Skip to content

Commit

Permalink
feat(RLN): Add verify against multiple roots (#1250)
Browse files Browse the repository at this point in the history
* update zerokit submodule

* fix(rln): allow Buffer creation on empty arrays

* feat(rln): use verify_with_root

* fix(rln): update test to work with verify_with_root
  • Loading branch information
s1fr0 authored Oct 7, 2022
1 parent 8a8c745 commit 3e1e7cc
Show file tree
Hide file tree
Showing 5 changed files with 32 additions and 8 deletions.
5 changes: 3 additions & 2 deletions tests/v2/test_waku_rln_relay.nim
Original file line number Diff line number Diff line change
Expand Up @@ -633,9 +633,10 @@ suite "Waku rln relay":
proofRes.isOk()
let proof = proofRes.value

# verify the proof (should not be verified)
# verify the proof (should not be verified) against the internal RLN tree root
let verified = rln.proofVerify(data = messageBytes,
proof = proof)
proof = proof,
validRoots = @[rln.getMerkleRoot().value()])

require:
verified.isOk()
Expand Down
5 changes: 3 additions & 2 deletions tests/v2/test_wakunode_rln_relay.nim
Original file line number Diff line number Diff line change
Expand Up @@ -194,9 +194,10 @@ procSuite "WakuNode - RLN relay":
let
contentTopicBytes = contentTopic.toBytes
input = concat(payload, contentTopicBytes)
rateLimitProofRes = node1.wakuRlnRelay.rlnInstance.proofGen(data = input,
extraBytes: seq[byte] = @[byte(1),2,3]
rateLimitProofRes = node1.wakuRlnRelay.rlnInstance.proofGen(data = concat(input, extraBytes), # we add extra bytes to invalidate proof verification against original payload
memKeys = node1.wakuRlnRelay.membershipKeyPair,
memIndex = MembershipIndex(4),
memIndex = MembershipIndex(1),
epoch = epoch)
doAssert(rateLimitProofRes.isOk())
let rateLimitProof = rateLimitProofRes.value
Expand Down
2 changes: 1 addition & 1 deletion vendor/zerokit
9 changes: 9 additions & 0 deletions waku/v2/protocol/waku_rln_relay/rln.nim
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,15 @@ when defined(rlnzerokit):
## the return bool value indicates the success or failure of the call to the verify function
## the verification of the zk proof is available in proof_is_valid_ptr, where a value of true indicates success and false a failure

proc verify_with_roots*(ctx: ptr RLN,
proof_buffer: ptr Buffer,
roots_buffer: ptr Buffer,
proof_is_valid_ptr: ptr bool): bool {.importc: "verify_with_roots".}
## proof_buffer has to be serialized as [ proof<128> | root<32> | epoch<32> | share_x<32> | share_y<32> | nullifier<32> | rln_identifier<32> | signal_len<8> | signal<var> ]
## roots_buffer contains the concatenation of 32 bytes long serializations in little endian of root values
## the return bool value indicates the success or failure of the call to the verify function
## the verification of the zk proof is available in proof_is_valid_ptr, where a value of true indicates success and false a failure

proc zk_prove*(ctx: ptr RLN,
input_buffer: ptr Buffer,
output_buffer: ptr Buffer): bool {.importc: "prove".}
Expand Down
19 changes: 16 additions & 3 deletions waku/v2/protocol/waku_rln_relay/waku_rln_relay_utils.nim
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,8 @@ proc toBuffer*(x: openArray[byte]): Buffer =
## converts the input to a Buffer object
## the Buffer object is used to communicate data with the rln lib
var temp = @x
let output = Buffer(`ptr`: addr(temp[0]), len: uint(temp.len))
let baseAddr = cast[pointer](x)
let output = Buffer(`ptr`: cast[ptr uint8](baseAddr), len: uint(temp.len))
return output

when defined(rln) or (not defined(rln) and not defined(rlnzerokit)):
Expand Down Expand Up @@ -507,14 +508,26 @@ when defined(rlnzerokit):

return proofBytes

proc proofVerify*(rlnInstance: ptr RLN, data: openArray[byte], proof: RateLimitProof): RlnRelayResult[bool] =
# Serializes a sequence of MerkleNodes
proc serialize(roots: seq[MerkleNode]): seq[byte] =
var rootsBytes: seq[byte] = @[]
for root in roots:
rootsBytes = concat(rootsBytes, @root)
return rootsBytes

# validRoots should contain a sequence of roots in the acceptable windows.
# As default, it is set to an empty sequence of roots. This implies that the validity check for the proof's root is skipped
proc proofVerify*(rlnInstance: ptr RLN, data: openArray[byte], proof: RateLimitProof, validRoots: seq[MerkleNode] = @[]): RlnRelayResult[bool] =
var
proofBytes = serialize(proof, data)
proofBuffer = proofBytes.toBuffer()
validProof: bool
rootsBytes = serialize(validRoots)
rootsBuffer = rootsBytes.toBuffer()

trace "serialized proof", proof = proofBytes.toHex()

let verifyIsSuccessful = verify(rlnInstance, addr proofBuffer, addr validProof)
let verifyIsSuccessful = verify_with_roots(rlnInstance, 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
Expand Down

0 comments on commit 3e1e7cc

Please sign in to comment.