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 50df20cf0..d243469ab 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 @@ -46,6 +46,8 @@ contract(WakuRlnContract): proc MAX_MESSAGE_LIMIT(): UInt256 {.view.} # this function returns the merkleProof for a given index proc merkleProofElements(index: Uint256): seq[Uint256] {.view.} + # this function returns the Merkle root + proc root(): Uint256 {.view.} type WakuRlnContractWithSender = Sender[WakuRlnContract] diff --git a/waku/waku_rln_relay/group_manager/on_chain_sync/group_manager.nim b/waku/waku_rln_relay/group_manager/on_chain_sync/group_manager.nim index 1d8469f97..4fa4969af 100644 --- a/waku/waku_rln_relay/group_manager/on_chain_sync/group_manager.nim +++ b/waku/waku_rln_relay/group_manager/on_chain_sync/group_manager.nim @@ -24,6 +24,11 @@ proc fetchMerkleProof*(g: OnchainSyncGroupManager) {.async.} = except CatchableError: error "Failed to fetch merkle proof: " & getCurrentExceptionMsg() +proc fetchMerkleRoot*(g: OnchainSyncGroupManager) {.async.} = + let merkleRootInvocation = g.wakuRlnContract.get().root() + let merkleRoot = await merkleRootInvocation.call() + return merkleRoot + method generateProof*( g: OnChainSyncGroupManager, data: seq[byte], @@ -50,14 +55,15 @@ method generateProof*( x: data, external_nullifier: poseidon_hash([epoch, rln_identifier]), ) - + let serializedWitness = serialize(witness) var inputBuffer = toBuffer(serializedWitness) # Generate the proof using the zerokit API var outputBuffer: Buffer - let success = - generate_proof_with_witness(g.rlnInstance, addr inputBuffer, addr outputBuffer) + let success = generate_proof_with_witness( + g.fetchMerkleRoot(), addr inputBuffer, addr outputBuffer + ) if not success: return err("Failed to generate proof") @@ -100,3 +106,37 @@ method generateProof*( nullifier: nullifier, ) return ok(output) + +method verifyProof*( + g: OnChainSyncGroupManager, input: openArray[byte], proof: RateLimitProof +): GroupManagerResult[bool] {.base, gcsafe, raises: [].} = + ## verifies the proof, returns an error if the proof verification fails + ## returns true if the proof is valid + var normalizedProof = proof + # when we do this, we ensure that we compute the proof for the derived value + # of the externalNullifier. The proof verification will fail if a malicious peer + # attaches invalid epoch+rlnidentifier pair + normalizedProof.externalNullifier = poseidon_hash([epoch, rln_identifier]).valueOr: + return err("could not construct the external nullifier") + + var + proofBytes = serialize(normalizedProof, data) + proofBuffer = proofBytes.toBuffer() + validProof: bool + rootsBytes = serialize(validRoots) + rootsBuffer = rootsBytes.toBuffer() + + trace "serialized proof", proof = byteutils.toHex(proofBytes) + + let verifyIsSuccessful = verify_with_roots( + g.fetchMerkleRoot(), addr proofBuffer, addr rootsBuffer, addr validProof + ) + if not verifyIsSuccessful: + # something went wrong in verification call + warn "could not verify validity of the proof", proof = proof + return err("could not verify the proof") + + if not validProof: + return ok(false) + else: + return ok(true) \ No newline at end of file