This commit is contained in:
Dmitriy Ryajov 2025-03-05 10:25:26 -06:00
parent 294a1f7105
commit e25a4e7e1b
No known key found for this signature in database
GPG Key ID: DA8C680CE7C657A4
3 changed files with 105 additions and 102 deletions

View File

@ -104,9 +104,13 @@ proc circomProveTask(task: ptr ProveTask) {.gcsafe.} =
let res = task.circom.backendCfg.prove_circuit(task[].ctx, task[].proofPtr.addr) let res = task.circom.backendCfg.prove_circuit(task[].ctx, task[].proofPtr.addr)
task.res.store(res) task.res.store(res)
proc asyncProve*[H]( proc prove*[H](
self: CircomCompat, input: NormalizedProofInputs[H] self: CircomCompat, input: ProofInputs[H]
): Future[?!Proof] {.async.} = ): Future[?!CircomProof] {.async, raises: [CancelledError].} =
## Prove a circuit using a ctx
##
var input = self.normalizeInput(input)
doAssert input.samples.len == self.numSamples, "Number of samples does not match" doAssert input.samples.len == self.numSamples, "Number of samples does not match"
doAssert input.slotProof.len <= self.datasetDepth, doAssert input.slotProof.len <= self.datasetDepth,
@ -213,17 +217,6 @@ proc asyncProve*[H](
success(task.proofPtr[]) success(task.proofPtr[])
proc prove*[H](
self: CircomCompat, input: ProofInputs[H]
): Future[?!CircomProof] {.async, raises: [CancelledError].} =
try:
without proof =? (await self.asyncProve(self.normalizeInput(input))), err:
trace "Failed to prove circuit", err = err.msg
return failure(err)
return success(proof)
except CancelledError as exc:
raise exc
proc circomVerifyTask(task: ptr VerifyTask) {.gcsafe.} = proc circomVerifyTask(task: ptr VerifyTask) {.gcsafe.} =
defer: defer:
task[].inputs[].releaseCircomInputs() task[].inputs[].releaseCircomInputs()
@ -232,9 +225,12 @@ proc circomVerifyTask(task: ptr VerifyTask) {.gcsafe.} =
let res = verify_circuit(task[].proof, task[].inputs, task[].vkp) let res = verify_circuit(task[].proof, task[].inputs, task[].vkp)
task.res.store(res) task.res.store(res)
proc asyncVerify*[H]( proc verify*[H](
self: CircomCompat, proof: CircomProof, inputs: ProofInputs[H] self: CircomCompat, proof: CircomProof, inputs: ProofInputs[H]
): Future[?!int32] {.async.} = ): Future[?!bool] {.async, raises: [CancelledError].} =
## Verify a proof using a ctx
##
try:
var var
proofPtr = unsafeAddr proof proofPtr = unsafeAddr proof
inputs = inputs.toCircomInputs() inputs = inputs.toCircomInputs()
@ -259,7 +255,7 @@ proc asyncVerify*[H](
if joinErr =? catch(await threadFut.join()).errorOption: if joinErr =? catch(await threadFut.join()).errorOption:
if err =? catch(await noCancel threadFut).errorOption: if err =? catch(await noCancel threadFut).errorOption:
trace "Failed to verify proof", err = err.msg trace "Error verifying proof", err = err.msg
return failure(err) return failure(err)
if joinErr of CancelledError: if joinErr of CancelledError:
trace "Cancellation requested for verifying proof, re-raising" trace "Cancellation requested for verifying proof, re-raising"
@ -267,24 +263,15 @@ proc asyncVerify*[H](
else: else:
return failure(joinErr) return failure(joinErr)
success(task.res.load()) let res = task.res.load()
proc verify*[H](
self: CircomCompat, proof: CircomProof, inputs: ProofInputs[H]
): Future[?!bool] {.async, raises: [CancelledError].} =
## Verify a proof using a ctx
##
try:
without res =? (await self.asyncVerify(proof, inputs)), err:
trace "Failed to verify proof", err = err.msg
return failure(err)
case res case res
of ERR_FAILED_TO_VERIFY_PROOF: of ERR_FAILED_TO_VERIFY_PROOF:
return failure("Failed to verify proof") trace "Failed to verify proof", res
return success(false)
of ERR_OK: of ERR_OK:
return success(true) return success(true)
else: else:
trace "Unknown error verifying proof", res
return failure("Unknown error") return failure("Unknown error")
except CancelledError as exc: except CancelledError as exc:
raise exc raise exc

View File

@ -17,47 +17,47 @@ import ./helpers
import ../helpers import ../helpers
import ../../helpers import ../../helpers
suite "Test Circom Compat Backend - control inputs": # suite "Test Circom Compat Backend - control inputs":
let # let
r1cs = "tests/circuits/fixtures/proof_main.r1cs" # r1cs = "tests/circuits/fixtures/proof_main.r1cs"
wasm = "tests/circuits/fixtures/proof_main.wasm" # wasm = "tests/circuits/fixtures/proof_main.wasm"
zkey = "tests/circuits/fixtures/proof_main.zkey" # zkey = "tests/circuits/fixtures/proof_main.zkey"
var # var
circom: CircomCompat # circom: CircomCompat
proofInputs: ProofInputs[Poseidon2Hash] # proofInputs: ProofInputs[Poseidon2Hash]
taskpool: Taskpool # taskpool: Taskpool
setup: # setup:
let # let
inputData = readFile("tests/circuits/fixtures/input.json") # inputData = readFile("tests/circuits/fixtures/input.json")
inputJson = !JsonNode.parse(inputData) # inputJson = !JsonNode.parse(inputData)
taskpool = Taskpool.new() # taskpool = Taskpool.new()
proofInputs = Poseidon2Hash.jsonToProofInput(inputJson) # proofInputs = Poseidon2Hash.jsonToProofInput(inputJson)
circom = CircomCompat.init(r1cs, wasm, zkey, taskpool = taskpool) # circom = CircomCompat.init(r1cs, wasm, zkey, taskpool = taskpool)
teardown: # teardown:
circom.release() # this comes from the rust FFI # circom.release() # this comes from the rust FFI
taskpool.shutdown() # taskpool.shutdown()
test "Should verify with correct inputs": # test "Should verify with correct inputs":
let proof = (await circom.prove(proofInputs)).tryGet # let proof = (await circom.prove(proofInputs)).tryGet
var resp = (await circom.verify(proof, proofInputs)).tryGet # var resp = (await circom.verify(proof, proofInputs)).tryGet
check resp # check resp
test "Should not verify with incorrect inputs": # test "Should not verify with incorrect inputs":
proofInputs.slotIndex = 1 # change slot index # proofInputs.slotIndex = 1 # change slot index
let proof = (await circom.prove(proofInputs)).tryGet # let proof = (await circom.prove(proofInputs)).tryGet
var resp = (await circom.verify(proof, proofInputs)).tryGet # var resp = (await circom.verify(proof, proofInputs)).tryGet
check resp == false # check resp == false
suite "Test Circom Compat Backend": suite "Test Circom Compat Backend - full flow":
let let
ecK = 2 ecK = 2
ecM = 2 ecM = 2
@ -112,18 +112,35 @@ suite "Test Circom Compat Backend":
await metaTmp.destroyDb() await metaTmp.destroyDb()
taskpool.shutdown() taskpool.shutdown()
test "Should verify with correct input": # test "Should verify with correct input":
var proof = (await circom.prove(proofInputs)).tryGet # var proof = (await circom.prove(proofInputs)).tryGet
var resp = (await circom.verify(proof, proofInputs)).tryGet # var resp = (await circom.verify(proof, proofInputs)).tryGet
check resp == true # check resp == true
test "Should not verify with incorrect input": # test "Should not verify with incorrect input":
proofInputs.slotIndex = 1 # change slot index # proofInputs.slotIndex = 1 # change slot index
let proof = (await circom.prove(proofInputs)).tryGet # let proof = (await circom.prove(proofInputs)).tryGet
var resp = (await circom.verify(proof, proofInputs)).tryGet # var resp = (await circom.verify(proof, proofInputs)).tryGet
check resp == false # check resp == false
test "Should concurrently prove/verify":
var proveTasks = newSeq[Future[?!CircomProof]]()
var verifyTasks = newSeq[Future[?!bool]]()
for i in 0 ..< 5:
proveTasks.add(circom.prove(proofInputs))
let proveResults = await allFinished(proveTasks)
for i in 0 ..< 5:
var proof = proveTasks[i].read().tryGet()
verifyTasks.add(circom.verify(proof, proofInputs))
let verifyResults = await allFinished(verifyTasks)
for i in 0 ..< 5:
check:
verifyResults[i].read().tryGet() == true

View File

@ -69,7 +69,6 @@ suite "Test Prover":
let (inputs, proof) = (await prover.prove(1, verifiable, challenge)).tryGet let (inputs, proof) = (await prover.prove(1, verifiable, challenge)).tryGet
echo "Proof: ", proof
check: check:
(await prover.verify(proof, inputs)).tryGet == true (await prover.verify(proof, inputs)).tryGet == true
@ -134,8 +133,8 @@ suite "Test Prover":
let (inputs, proof) = (await prover.prove(1, verifiable, challenge)).tryGet let (inputs, proof) = (await prover.prove(1, verifiable, challenge)).tryGet
# call asyncProve and cancel the task # call prover and cancel the task
let proveFut = backend.asyncProve(backend.normalizeInput(inputs)) let proveFut = backend.prove(inputs)
proveFut.cancel() proveFut.cancel()
var cancelledProof: Proof var cancelledProof: Proof
@ -148,15 +147,15 @@ suite "Test Prover":
check: check:
(await prover.verify(cancelledProof, inputs)).tryGet == true (await prover.verify(cancelledProof, inputs)).tryGet == true
# call asyncVerify and cancel the task # call verify and cancel the task
let verifyFut = backend.asyncVerify(proof, inputs) let verifyFut = backend.verify(proof, inputs)
verifyFut.cancel() verifyFut.cancel()
var verifyRes: int32 var verifyRes = false
try: try:
verifyRes = (await verifyFut).tryGet verifyRes = (await verifyFut).tryGet
except CatchableError as exc: except CatchableError as exc:
check exc of CancelledError check exc of CancelledError
finally: finally:
# validate the verifyResponse # validate the verifyResponse
check verifyRes == ERR_OK check verifyRes