diff --git a/waku/waku_rln_relay/conversion_utils.nim b/waku/waku_rln_relay/conversion_utils.nim index a9e7f1f11..f49faca3c 100644 --- a/waku/waku_rln_relay/conversion_utils.nim +++ b/waku/waku_rln_relay/conversion_utils.nim @@ -78,6 +78,21 @@ proc serialize*( ) return output +proc serialize*(witness: RLNWitnessInput): seq[byte] = + ## Serializes the witness into a byte array according to the RLN protocol format + var buffer: seq[byte] + buffer.add(@(witness.identity_secret)) + buffer.add(@(witness.user_message_limit)) + buffer.add(@(witness.message_id)) + buffer.add(toBytes(uint64(witness.path_elements.len / 32), Endianness.littleEndian)) + for element in witness.path_elements: + buffer.add(element) + buffer.add(toBytes(uint64(witness.path_elements.len / 32), Endianness.littleEndian)) + buffer.add(witness.identity_path_index) + buffer.add(@(witness.x)) + buffer.add(@(witness.external_nullifier)) + return buffer + proc serialize*(proof: RateLimitProof, data: openArray[byte]): seq[byte] = ## a private proc to convert RateLimitProof and data to a byte seq ## this conversion is used in the proof verification proc @@ -116,21 +131,6 @@ proc serialize*(memIndices: seq[MembershipIndex]): seq[byte] = return memIndicesBytes -proc serialize*(witness: RLNWitnessInput): seq[byte] = - ## Serializes the witness into a byte array according to the RLN protocol format - var buffer: seq[byte] - buffer.add(@(witness.identity_secret)) - buffer.add(@(witness.user_message_limit)) - buffer.add(@(witness.message_id)) - buffer.add(toBytes(uint64(witness.path_elements.len), Endianness.littleEndian)) - for element in witness.path_elements: - buffer.add(@element) - buffer.add(toBytes(uint64(witness.path_elements.len), Endianness.littleEndian)) - buffer.add(witness.identity_path_index) - buffer.add(@(witness.x)) - buffer.add(@(witness.external_nullifier)) - return buffer - proc toEpoch*(t: uint64): Epoch = ## converts `t` to `Epoch` in little-endian order let bytes = toBytes(t, Endianness.littleEndian) diff --git a/waku/waku_rln_relay/group_manager/on_chain/group_manager.nim b/waku/waku_rln_relay/group_manager/on_chain/group_manager.nim index 82eaf4cfd..295384b80 100644 --- a/waku/waku_rln_relay/group_manager/on_chain/group_manager.nim +++ b/waku/waku_rln_relay/group_manager/on_chain/group_manager.nim @@ -49,9 +49,9 @@ contract(WakuRlnContract): # this constant describes max message limit of rln contract proc MAX_MESSAGE_LIMIT(): UInt256 {.view.} # this function returns the merkleProof for a given index - proc merkleProofElements(index: EthereumUInt40): seq[array[32, byte]] {.view.} + proc merkleProofElements(index: EthereumUInt40): seq[byte] {.view.} # this function returns the merkle root - proc root(): Uint256 {.view.} + proc root(): UInt256 {.view.} type WakuRlnContractWithSender = Sender[WakuRlnContract] @@ -67,7 +67,7 @@ type keystorePassword*: Option[string] registrationHandler*: Option[RegistrationHandler] latestProcessedBlock*: BlockNumber - merkleProofCache*: seq[array[32, byte]] + merkleProofCache*: seq[byte] proc setMetadata*( g: OnchainGroupManager, lastProcessedBlock = none(BlockNumber) @@ -92,63 +92,27 @@ proc setMetadata*( return err("failed to persist rln metadata: " & getCurrentExceptionMsg()) return ok() -proc toArray32LE*(x: UInt256): array[32, byte] {.inline.} = - ## Convert UInt256 to byte array without endianness conversion - when nimvm: - for i in 0 ..< 32: - result[i] = byte((x shr (i * 8)).truncate(uint8) and 0xff) - else: - copyMem(addr result, unsafeAddr x, 32) +proc uint64ToField*(n: uint64): array[32, byte] = + ## Converts uint64 to 32-byte little-endian array with zero padding + var bytes = toBytes(n, Endianness.littleEndian) + result[0 ..< bytes.len] = bytes -proc toArray32LE*(x: array[32, byte]): array[32, byte] = - for i in 0 ..< 32: - result[i] = x[31 - i] - return result +proc UInt256ToField*(v: UInt256): array[32, byte] = + var bytes: array[32, byte] + let vBytes = v.toBytesBE() + for i in 0 .. 31: + bytes[i] = vBytes[31 - i] + return bytes -proc toArray32LE*(s: seq[byte]): array[32, byte] = - var output: array[32, byte] - for i in 0 ..< 32: - output[i] = 0 +proc seqToField*(s: seq[byte]): array[32, byte] = + result = default(array[32, byte]) let len = min(s.len, 32) for i in 0 ..< len: - output[i] = s[31 - i] - return output - -proc toArray32*(s: seq[byte]): array[32, byte] = - var output: array[32, byte] - for i in 0 ..< 32: - output[i] = 0 - let len = min(s.len, 32) - for i in 0 ..< len: - output[i] = s[i] - return output - -proc toArray32LE*(v: uint64): array[32, byte] = - let bytes = toBytes(v, Endianness.littleEndian) - var output: array[32, byte] - discard output.copyFrom(bytes) - return output - -proc toArray32*(v: uint64): array[32, byte] = - let bytes = toBytes(v) - var output: array[32, byte] - discard output.copyFrom(bytes) - return output - -# Hashes arbitrary signal to the underlying prime field. -proc hash_to_field*(signal: seq[byte]): array[32, byte] = - var ctx: keccak256 - ctx.init() - ctx.update(signal) - var hash_result = ctx.finish() - - var hash: array[32, byte] - copyMem(hash[0].addr, hash_result.data[0].addr, 32) - toArray32LE(hash) + result[i] = s[i] proc fetchMerkleProofElements*( g: OnchainGroupManager -): Future[Result[seq[array[32, byte]], string]] {.async.} = +): Future[Result[seq[byte], string]] {.async.} = try: let membershipIndex = g.membershipIndex.get() let index40 = stuint(membershipIndex, 40) @@ -173,19 +137,7 @@ proc fetchMerkleProofElements*( let responseBytes = await g.ethRpc.get().provider.eth_call(tx, "latest") - var i = 0 - var merkleProof = newSeq[array[32, byte]]() - while (i * 32) + 31 < responseBytes.len: - var element: array[32, byte] - let startIndex = i * 32 - let endIndex = startIndex + 31 - element = responseBytes.toOpenArray(startIndex, endIndex) - merkleProof.add(element) - i += 1 - - debug "merkleProof", responseBytes = responseBytes, merkleProof = merkleProof - - return ok(merkleProof) + return ok(responseBytes) except CatchableError: error "Failed to fetch Merkle proof elements", errMsg = getCurrentExceptionMsg(), index = g.membershipIndex.get() @@ -193,7 +145,7 @@ proc fetchMerkleProofElements*( proc fetchMerkleRoot*( g: OnchainGroupManager -): Future[Result[Uint256, string]] {.async.} = +): Future[Result[UInt256, string]] {.async.} = try: let merkleRootInvocation = g.wakuRlnContract.get().root() let merkleRoot = await merkleRootInvocation.call() @@ -228,13 +180,11 @@ proc updateRoots*(g: OnchainGroupManager): Future[bool] {.async.} = if rootRes.isErr(): return false - let merkleRoot = toArray32LE(rootRes.get()) + let merkleRoot = UInt256ToField(rootRes.get()) if g.validRoots.len == 0: g.validRoots.addLast(merkleRoot) return true - debug "--- validRoots ---", rootRes = rootRes.get(), validRoots = merkleRoot - if g.validRoots[g.validRoots.len - 1] != merkleRoot: var overflow = g.validRoots.len - AcceptableRootWindowSize + 1 while overflow > 0: @@ -260,11 +210,6 @@ proc trackRootChanges*(g: OnchainGroupManager) {.async.} = error "Failed to fetch Merkle proof", error = proofResult.error g.merkleProofCache = proofResult.get() - # debug "--- track update ---", - # len = g.validRoots.len, - # validRoots = g.validRoots, - # merkleProof = g.merkleProofCache - await sleepAsync(rpcDelay) method atomicBatch*( @@ -365,92 +310,6 @@ method withdrawBatch*( ): Future[void] {.async: (raises: [Exception]).} = initializedGuard(g) -proc indexToPath*(membershipIndex: UInt256, tree_depth: int): seq[byte] = - result = newSeq[byte](tree_depth) - var idx = membershipIndex - - for i in 0 ..< tree_depth: - let bit = (idx shr (tree_depth - 1 - i)) and 1 - result[i] = byte(bit.truncate(uint8)) - - debug "indexToPath", index = membershipIndex, path = result - -proc identitySecretToField*(secret: seq[byte]): array[32, byte] = - let str = cast[string](secret) - var field : StUint[256] - try: - field = parse(str, StUint[256]) - except CatchableError: - error "Failed to parse identity secret", error = getCurrentExceptionMsg() - return field.toBytesLE() - -proc uint64ToField*(n: uint64): array[32, byte] = - ## Converts uint64 to 32-byte little-endian array with zero padding - var bytes = toBytes(n, Endianness.littleEndian) - result[0.. | root<32> | external_nullifier<32> | share_x<32> | share_y<32> | nullifier<32> ] diff --git a/waku/waku_rln_relay/protocol_types.nim b/waku/waku_rln_relay/protocol_types.nim index ec85de05f..41372bef3 100644 --- a/waku/waku_rln_relay/protocol_types.nim +++ b/waku/waku_rln_relay/protocol_types.nim @@ -59,7 +59,7 @@ type identity_secret*: Fr user_message_limit*: Fr message_id*: Fr - path_elements*: seq[Fr] + path_elements*: seq[byte] identity_path_index*: seq[byte] x*: Fr external_nullifier*: Fr