Merge pull request #13 from logos-storage/fix/input-validations

fix: avoid assert for input validations
This commit is contained in:
Balazs Komuves 2026-06-09 10:08:42 +02:00 committed by GitHub
commit beb56c2cd3
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 104 additions and 18 deletions

View File

@ -31,24 +31,26 @@ import groth16/prover/shared
# the prover
#
proc generateProofWithMask*( zkey: ZKey, wtns: Witness, mask: Mask, pool: Taskpool, printTimings: bool): Proof =
proc generateProofWithMask*( zkey: ZKey, wtns: Witness, mask: Mask, pool: Taskpool, printTimings: bool): Proof {.raises: [ValueError].} =
# if (zkey.header.curve != wtns.curve):
# echo( "zkey.header.curve = " & ($zkey.header.curve) )
# echo( "wtns.curve = " & ($wtns.curve ) )
assert( zkey.header.curve == wtns.curve )
if zkey.header.curve != wtns.curve:
raise newException(ValueError,
"curve mismatch: zkey.header.curve=" & $zkey.header.curve &
" wtns.curve=" & $wtns.curve)
let witness = wtns.values
let hdr : GrothHeader = zkey.header
let spec : SpecPoints = zkey.specPoints
let pts : ProverPoints = zkey.pPoints
let pts : ProverPoints = zkey.pPoints
let nvars = hdr.nvars
let npubs = hdr.npubs
assert( nvars == witness.len , "wrong witness length" )
if nvars != witness.len:
raise newException(ValueError,
"wrong witness length: expected " & $nvars &
" (zkey.header.nvars), got " & $witness.len)
# remark: with the special variable "1" we actuall have (npub+1) public IO variables
var pubIO = newSeq[Fr[BN254_Snarks]]( npubs + 1)
@ -118,11 +120,11 @@ proc generateProofWithMask*( zkey: ZKey, wtns: Witness, mask: Mask, pool: Taskpo
#-------------------------------------------------------------------------------
proc generateProofWithTrivialMask*( zkey: ZKey, wtns: Witness, pool: Taskpool, printTimings: bool ): Proof =
proc generateProofWithTrivialMask*( zkey: ZKey, wtns: Witness, pool: Taskpool, printTimings: bool ): Proof {.raises: [ValueError].} =
let mask = Mask( r: zeroFr , s: zeroFr )
return generateProofWithMask( zkey, wtns, mask, pool, printTimings )
proc generateProof*( zkey: ZKey, wtns: Witness, pool: Taskpool, printTimings = false ): Proof =
proc generateProof*( zkey: ZKey, wtns: Witness, pool: Taskpool, printTimings = false ): Proof {.raises: [ValueError].} =
let mask = randomMask()
return generateProofWithMask( zkey, wtns, mask, pool, printTimings )

View File

@ -29,13 +29,15 @@ from groth16/prover import Proof
# the verifier
#
proc verifyProof* (vkey: VKey, prf: Proof): bool =
proc verifyProof* (vkey: VKey, prf: Proof): bool {.raises: [ValueError].} =
assert( prf.curve == "bn128" )
if prf.curve != "bn128":
raise newException(ValueError,
"unsupported curve: expected \"bn128\", got \"" & prf.curve & "\"")
assert( isInSubgroupG1(prf.pi_a) , "pi_a is not in G1" )
assert( isInSubgroupG2(prf.pi_b) , "pi_b is not in G2" )
assert( isInSubgroupG1(prf.pi_c) , "pi_c is not in G1" )
if not isInSubgroupG1(prf.pi_a): return false
if not isInSubgroupG2(prf.pi_b): return false
if not isInSubgroupG1(prf.pi_c): return false
var pubG1 : G1 = msmG1( prf.publicIO , vkey.vpoints.pointsIC )

View File

@ -1,11 +1,14 @@
{.used.}
{.used.}
import std/unittest
import std/sequtils
import taskpools
import constantine/math/io/io_fields
import constantine/named/properties_fields
import groth16/prover
import groth16/verifier
import groth16/fake_setup
@ -13,6 +16,7 @@ import groth16/zkey_types
import groth16/files/witness
import groth16/files/r1cs
import groth16/bn128/fields
import groth16/bn128/curves
#-------------------------------------------------------------------------------
# simple hand-crafted arithmetic circuit
@ -71,11 +75,89 @@ proc testProof(zkey: ZKey, witness: Witness): bool =
suite "prover":
test "prove & verify simple multiplication circuit, `JensGroth` flavour":
let zkey = createFakeCircuitSetup( myR1cs, flavour=JensGroth )
let zkey = createFakeCircuitSetup( myR1cs, flavour=JensGroth )
check testProof( zkey, myWitness )
test "prove & verify simple multiplication circuit, `Snarkjs` flavour":
let zkey = createFakeCircuitSetup( myR1cs, flavour=Snarkjs )
let zkey = createFakeCircuitSetup( myR1cs, flavour=Snarkjs )
check testProof( zkey, myWitness )
#-------------------------------------------------------------------------------
# malformed-input handling: verifyProof must return `false`, never crash.
# An on-curve but out-of-subgroup G2 point (same construction as in testCurve.nim).
const badPt2_x1 = fromHex(Fp[BN254_Snarks], "0x2")
const badPt2_xu = fromHex(Fp[BN254_Snarks], "0x0")
const badPt2_y1 = fromHex(Fp[BN254_Snarks], "0x181604d0560080401c08b557815482553e278257d98100d193a011c42782474d")
const badPt2_yu = fromHex(Fp[BN254_Snarks], "0x04f21f9d99cc25f694cf22ff70dc0ac4692e7a721b725dc454a217f04bd03e33")
let badPt2_x = mkFp2(badPt2_x1, badPt2_xu)
let badPt2_y = mkFp2(badPt2_y1, badPt2_yu)
let outOfSubgroupG2 = unsafeMkG2(badPt2_x, badPt2_y)
# A G1 value with coordinates (1,1), which does NOT satisfy y^2 = x^3 + 3.
let bogusG1 = unsafeMkG1(oneFp, oneFp)
proc buildGoodProof(): (VKey, Proof) =
var pool = Taskpool.new()
let zkey = createFakeCircuitSetup(myR1cs, flavour=Snarkjs)
let proof = generateProof(zkey, myWitness, pool)
let vkey = extractVKey(zkey)
pool.shutdown()
return (vkey, proof)
suite "verifier input validation":
test "wrong curve string raises ValueError":
let (vkey, proof) = buildGoodProof()
var bad = proof
bad.curve = "bls12-381"
expect ValueError:
discard verifyProof(vkey, bad)
test "out-of-subgroup G2 pi_b returns false":
let (vkey, proof) = buildGoodProof()
var bad = proof
bad.pi_b = outOfSubgroupG2
check (not verifyProof(vkey, bad))
test "off-curve G1 pi_a returns false":
let (vkey, proof) = buildGoodProof()
var bad = proof
bad.pi_a = bogusG1
check (not verifyProof(vkey, bad))
test "off-curve G1 pi_c returns false":
let (vkey, proof) = buildGoodProof()
var bad = proof
bad.pi_c = bogusG1
check (not verifyProof(vkey, bad))
test "known-good proof still verifies":
let (vkey, proof) = buildGoodProof()
check verifyProof(vkey, proof)
#-------------------------------------------------------------------------------
# prover input-validation: generateProof must raise ValueError (catchable in
# both --panics modes) for malformed inputs, not AssertionDefect.
suite "prover input validation":
test "curve mismatch between zkey and witness raises ValueError":
let zkey = createFakeCircuitSetup(myR1cs, flavour=Snarkjs)
var badWtns = myWitness
badWtns.curve = "bls12-381"
var pool = Taskpool.new()
expect ValueError:
discard generateProof(zkey, badWtns, pool)
pool.shutdown()
test "wrong witness length raises ValueError":
let zkey = createFakeCircuitSetup(myR1cs, flavour=Snarkjs)
var badWtns = myWitness
badWtns.values = badWtns.values[0 ..< badWtns.values.len - 1] # drop one wire
var pool = Taskpool.new()
expect ValueError:
discard generateProof(zkey, badWtns, pool)
pool.shutdown()
#-------------------------------------------------------------------------------