constructor(arg) {
    if (Array.isArray(arg)) {
      // arg is an array of SHA256 hashes in hexadecimal encoding
      this.numEntries = arg.length
      this.numBitsPerEntry = BITS_PER_ENTRY
      this.numProbes = NUM_PROBES
      this.bits = new Uint8Array(
        Math.ceil((this.numEntries * this.numBitsPerEntry) / 8),
      )
      for (let hash of arg) this.addHash(hash)
    } else if (arg instanceof Uint8Array) {
      if (arg.byteLength === 0) {
        this.numEntries = 0
        this.numBitsPerEntry = 0
        this.numProbes = 0
        this.bits = arg
      } else {
        const decoder = new Decoder(arg)
        this.numEntries = decoder.readUint32()
        this.numBitsPerEntry = decoder.readUint32()
        this.numProbes = decoder.readUint32()
        this.bits = decoder.readRawBytes(
          Math.ceil((this.numEntries * this.numBitsPerEntry) / 8),
        )
      }
    } else {
      throw new TypeError("invalid argument")
    }
  }
A Bloom filter implementation that can be serialised to a byte array for transmission
over a network. The entries that are added are assumed to already be SHA-256 hashes,
so this implementation does not perform its own hashing.