chore: improve debug and update verify proof

This commit is contained in:
darshankabariya 2025-04-23 15:09:31 +05:30
parent 8d699e32a5
commit 6a20ab8985

View File

@ -212,20 +212,20 @@ proc trackRootChanges*(g: OnchainGroupManager) {.async.} =
error "Failed to fetch Merkle proof", error = proofResult.error
g.merkleProofCache = proofResult.get()
debug "Roots and MerkleProof status",
roots = g.validRoots.toSeq(),
rootsCount = g.validRoots.len,
firstProofElement =
if g.merkleProofCache.len >= 32:
g.merkleProofCache[0 .. 31]
else:
@[],
lastProofElement =
if g.merkleProofCache.len >= 32:
g.merkleProofCache[^32 ..^ 1]
else:
@[],
proofLength = g.merkleProofCache.len
# debug "Roots and MerkleProof status",
# roots = g.validRoots.toSeq(),
# rootsCount = g.validRoots.len,
# firstProofElement =
# if g.merkleProofCache.len >= 32:
# g.merkleProofCache[0 .. 31]
# else:
# @[],
# lastProofElement =
# if g.merkleProofCache.len >= 32:
# g.merkleProofCache[^32 ..^ 1]
# else:
# @[],
# proofLength = g.merkleProofCache.len
await sleepAsync(rpcDelay)
method atomicBatch*(
@ -423,8 +423,10 @@ method generateProof*(
except CatchableError:
error "Failed to update roots", error = getCurrentExceptionMsg()
if contractRoot != generatedRoot:
return err("Root mismatch: contract=" & $contractRoot & " local=" & $generatedRoot)
debug "--- generatedRoot and contractRoots",
generatedRoot = generatedRoot, contractRoots = g.validRoots.toSeq()
# if contractRoot != generatedRoot:
# return err("Root mismatch: contract=" & $contractRoot & " local=" & $generatedRoot)
debug "--- pathElements ---",
before = g.merkleProofCache,
@ -436,19 +438,10 @@ method generateProof*(
before = g.membershipIndex.get(),
after = identity_path_index,
len = identity_path_index.len
# Convert seq[byte] to Buffer and get the hash
var
hash_input_buffer = toBuffer(data) # Convert input data to Buffer
hash_output_buffer: Buffer # Create output buffer for the hash
let hash_success = sha256(addr hash_input_buffer, addr hash_output_buffer)
if not hash_success:
return err("Failed to compute sha256 hash")
var hash_output_seq = newSeq[byte](hash_output_buffer.len)
copyMem(addr hash_output_seq[0], hash_output_buffer.ptr, hash_output_buffer.len)
# SHA256 digest is bigendian; convert to littleendian for Poseidon/BN254 field
hash_output_seq = hash_output_seq.reversed()
let x = seqToField(hash_output_seq)
# --- x = Keccak256(signal) ---
let keccakDigest = keccak.keccak256.digest(data) # 32byte BE array
let x = seqToField(keccakDigest.data.reversed()) # convert to LE for BN254
let extNullifierRes = poseidon(@[@(epoch), @(rlnIdentifier)])
if extNullifierRes.isErr():
@ -478,10 +471,9 @@ method generateProof*(
let witness_success = generate_proof_with_witness(
g.rlnInstance, addr input_witness_buffer, addr output_witness_buffer
)
if not witness_success:
return err("Failed to generate proof")
else:
debug "Proof generated successfully"
# Parse the proof into a RateLimitProof object
var proofValue = cast[ptr array[320, byte]](output_witness_buffer.`ptr`)
@ -521,45 +513,56 @@ method generateProof*(
shareY: shareY,
nullifier: nullifier,
)
debug "Proof generated successfully", Proof = output
waku_rln_remaining_proofs_per_epoch.dec()
waku_rln_total_generated_proofs.inc()
return ok(output)
method verifyProof*(
g: OnchainGroupManager, input: openArray[byte], proof: RateLimitProof
g: OnchainGroupManager, # verifier context
input: openArray[byte], # raw message data (signal)
proof: RateLimitProof, # proof received from the peer
): GroupManagerResult[bool] {.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
## -- Verifies an RLN rate-limit proof against the set of valid Merkle roots --
## Returns `ok(true)` → proof is valid
## `ok(false)` → proof is syntactically correct *but* fails verification
## `err(msg)` → internal failure (serialization, FFI, etc.)
normalizedProof.externalNullifier = poseidon(
@[@(proof.epoch), @(proof.rlnIdentifier)]
).valueOr:
return err("could not construct the external nullifier")
var
proofBytes = serialize(normalizedProof, input)
proofBuffer = proofBytes.toBuffer()
validProof: bool
rootsBytes = serialize(g.validRoots.items().toSeq())
rootsBuffer = rootsBytes.toBuffer()
# 1. Re-compute the external-nullifier so peers cant tamper with
# the `(epoch, rlnIdentifier)` public input.
var normalizedProof = proof # copy so we dont mutate callers value
let extNullRes = poseidon(@[@(proof.epoch), @(proof.rlnIdentifier)])
if extNullRes.isErr():
return err("could not construct external nullifier: " & extNullRes.error)
normalizedProof.externalNullifier = extNullRes.get()
trace "serialized proof", proof = byteutils.toHex(proofBytes)
# 2. Serialize `(proof, signal)` exactly the way Zerokit expects.
let proofBytes = serialize(normalizedProof, input)
let proofBuffer = proofBytes.toBuffer()
let verifyIsSuccessful = verify_with_roots(
g.rlnInstance, addr proofBuffer, addr rootsBuffer, addr validProof
# 3. Serialize the sliding window of Merkle roots we trust.
let rootsBytes = serialize(g.validRoots.items().toSeq())
let rootsBuffer = rootsBytes.toBuffer()
# 4. Hand everything to the RLN FFI verifier.
var validProof: bool # out-param
let ffiOk = verify_with_roots(
g.rlnInstance, # RLN context created at init()
addr proofBuffer, # (proof + signal)
addr rootsBuffer, # valid Merkle roots
addr validProof # will be set by the FFI call
,
)
if not verifyIsSuccessful:
# something went wrong in verification call
warn "could not verify validity of the proof", proof = proof
if not ffiOk:
warn "verify_with_roots() returned failure status", proof = proof
return err("could not verify the proof")
if not validProof:
return ok(false)
else:
return ok(true)
debug "Verification successfully", proof = proof
return ok(validProof)
method onRegister*(g: OnchainGroupManager, cb: OnRegisterCallback) {.gcsafe.} =
g.registerCb = some(cb)