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)
task.res.store(res)
proc asyncProve*[H](
self: CircomCompat, input: NormalizedProofInputs[H]
): Future[?!Proof] {.async.} =
proc prove*[H](
self: CircomCompat, input: ProofInputs[H]
): 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.slotProof.len <= self.datasetDepth,
@ -213,17 +217,6 @@ proc asyncProve*[H](
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.} =
defer:
task[].inputs[].releaseCircomInputs()
@ -232,59 +225,53 @@ proc circomVerifyTask(task: ptr VerifyTask) {.gcsafe.} =
let res = verify_circuit(task[].proof, task[].inputs, task[].vkp)
task.res.store(res)
proc asyncVerify*[H](
self: CircomCompat, proof: CircomProof, inputs: ProofInputs[H]
): Future[?!int32] {.async.} =
var
proofPtr = unsafeAddr proof
inputs = inputs.toCircomInputs()
without threadPtr =? ThreadSignalPtr.new().mapFailure, err:
trace "Failed to create thread signal", err = err.msg
return failure("Unable to create thread signal")
defer:
threadPtr.close().expect("closing once works")
inputs.releaseCircomInputs()
var task =
VerifyTask(proof: proofPtr, vkp: self.vkp, inputs: addr inputs, signal: threadPtr)
doAssert self.taskpool.numThreads > 1,
"Must have at least one separate thread or signal will never be fired"
self.taskpool.spawn circomVerifyTask(addr task)
let threadFut = threadPtr.wait()
if joinErr =? catch(await threadFut.join()).errorOption:
if err =? catch(await noCancel threadFut).errorOption:
trace "Failed to verify proof", err = err.msg
return failure(err)
if joinErr of CancelledError:
trace "Cancellation requested for verifying proof, re-raising"
raise joinErr
else:
return failure(joinErr)
success(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)
var
proofPtr = unsafeAddr proof
inputs = inputs.toCircomInputs()
without threadPtr =? ThreadSignalPtr.new().mapFailure, err:
trace "Failed to create thread signal", err = err.msg
return failure("Unable to create thread signal")
defer:
threadPtr.close().expect("closing once works")
inputs.releaseCircomInputs()
var task =
VerifyTask(proof: proofPtr, vkp: self.vkp, inputs: addr inputs, signal: threadPtr)
doAssert self.taskpool.numThreads > 1,
"Must have at least one separate thread or signal will never be fired"
self.taskpool.spawn circomVerifyTask(addr task)
let threadFut = threadPtr.wait()
if joinErr =? catch(await threadFut.join()).errorOption:
if err =? catch(await noCancel threadFut).errorOption:
trace "Error verifying proof", err = err.msg
return failure(err)
if joinErr of CancelledError:
trace "Cancellation requested for verifying proof, re-raising"
raise joinErr
else:
return failure(joinErr)
let res = task.res.load()
case res
of ERR_FAILED_TO_VERIFY_PROOF:
return failure("Failed to verify proof")
trace "Failed to verify proof", res
return success(false)
of ERR_OK:
return success(true)
else:
trace "Unknown error verifying proof", res
return failure("Unknown error")
except CancelledError as exc:
raise exc

View File

@ -17,47 +17,47 @@ import ./helpers
import ../helpers
import ../../helpers
suite "Test Circom Compat Backend - control inputs":
let
r1cs = "tests/circuits/fixtures/proof_main.r1cs"
wasm = "tests/circuits/fixtures/proof_main.wasm"
zkey = "tests/circuits/fixtures/proof_main.zkey"
# suite "Test Circom Compat Backend - control inputs":
# let
# r1cs = "tests/circuits/fixtures/proof_main.r1cs"
# wasm = "tests/circuits/fixtures/proof_main.wasm"
# zkey = "tests/circuits/fixtures/proof_main.zkey"
var
circom: CircomCompat
proofInputs: ProofInputs[Poseidon2Hash]
taskpool: Taskpool
# var
# circom: CircomCompat
# proofInputs: ProofInputs[Poseidon2Hash]
# taskpool: Taskpool
setup:
let
inputData = readFile("tests/circuits/fixtures/input.json")
inputJson = !JsonNode.parse(inputData)
# setup:
# let
# inputData = readFile("tests/circuits/fixtures/input.json")
# inputJson = !JsonNode.parse(inputData)
taskpool = Taskpool.new()
proofInputs = Poseidon2Hash.jsonToProofInput(inputJson)
circom = CircomCompat.init(r1cs, wasm, zkey, taskpool = taskpool)
# taskpool = Taskpool.new()
# proofInputs = Poseidon2Hash.jsonToProofInput(inputJson)
# circom = CircomCompat.init(r1cs, wasm, zkey, taskpool = taskpool)
teardown:
circom.release() # this comes from the rust FFI
taskpool.shutdown()
# teardown:
# circom.release() # this comes from the rust FFI
# taskpool.shutdown()
test "Should verify with correct inputs":
let proof = (await circom.prove(proofInputs)).tryGet
# test "Should verify with correct inputs":
# 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":
proofInputs.slotIndex = 1 # change slot index
# test "Should not verify with incorrect inputs":
# 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
ecK = 2
ecM = 2
@ -112,18 +112,35 @@ suite "Test Circom Compat Backend":
await metaTmp.destroyDb()
taskpool.shutdown()
test "Should verify with correct input":
var proof = (await circom.prove(proofInputs)).tryGet
# test "Should verify with correct input":
# 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":
proofInputs.slotIndex = 1 # change slot index
# test "Should not verify with incorrect input":
# 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
echo "Proof: ", proof
check:
(await prover.verify(proof, inputs)).tryGet == true
@ -134,13 +133,13 @@ suite "Test Prover":
let (inputs, proof) = (await prover.prove(1, verifiable, challenge)).tryGet
# call asyncProve and cancel the task
let proveFut = backend.asyncProve(backend.normalizeInput(inputs))
# call prover and cancel the task
let proveFut = backend.prove(inputs)
proveFut.cancel()
var cancelledProof: Proof
try:
cancelledProof = (await proveFut).tryGet
cancelledProof = (await proveFut).tryGet
except CatchableError as exc:
check exc of CancelledError
finally:
@ -148,15 +147,15 @@ suite "Test Prover":
check:
(await prover.verify(cancelledProof, inputs)).tryGet == true
# call asyncVerify and cancel the task
let verifyFut = backend.asyncVerify(proof, inputs)
# call verify and cancel the task
let verifyFut = backend.verify(proof, inputs)
verifyFut.cancel()
var verifyRes: int32
var verifyRes = false
try:
verifyRes = (await verifyFut).tryGet
verifyRes = (await verifyFut).tryGet
except CatchableError as exc:
check exc of CancelledError
finally:
# validate the verifyResponse
check verifyRes == ERR_OK
check verifyRes