nim-groth16/tests/groth16/testProver.nim

164 lines
5.3 KiB
Nim

{.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
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
#
const myWitnessCfg =
WitnessConfig( nWires: 8 # including the special variable "1"
, nPubOut: 1 # public output = input + a*b*c = 1022 + 7*11*13 = 2023
, nPubIn: 1 # public input = 1022
, nPrivIn: 3 # private inputs: 7, 11, 13
, nLabels: 0
)
# 2023 == 1022 + 7*3*11
const myEq1 : Constraint = ( @[] , @[] , @[ (1,minusOneFr) , (2,oneFr) , (7,oneFr) ] )
# 7*11 == 77
const myEq2 : Constraint = ( @[ (3,oneFr) ] , @[ (4,oneFr) ] , @[ (6,oneFr) ] )
# 77*13 == 1001
const myEq3 : Constraint = ( @[ (5,oneFr) ] , @[ (6,oneFr) ] , @[ (7,oneFr) ] )
const myConstraints : seq[Constraint] = @[ myEq1, myEq2, myEq3 ]
const myLabels : seq[int] = @[]
const myR1CS =
R1CS( r: primeR
, cfg: myWitnessCfg
, nConstr: myConstraints.len
, constraints: myConstraints
, wireToLabel: myLabels
)
# the equation we want prove is `7*11*13 + 1022 == 2023`
let myWitnessValues = map( @[ 1, 2023, 1022, 7, 11, 13, 7*11, 7*11*13 ] , intToFr )
# wire indices: ^^^^^^^ 0 1 2 3 4 5 6 7
let myWitness =
Witness( curve: "bn128"
, r: primeR
, nvars: 8
, values: myWitnessValues
)
#-------------------------------------------------------------------------------
proc testProof(zkey: ZKey, witness: Witness): bool =
var pool = Taskpool.new()
let proof = generateProof( zkey, witness, pool )
let vkey = extractVKey( zkey)
let ok = verifyProof( vkey, proof )
pool.shutdown()
return ok
suite "prover":
test "prove & verify simple multiplication circuit, `JensGroth` flavour":
let zkey = createFakeCircuitSetup( myR1cs, flavour=JensGroth )
check testProof( zkey, myWitness )
test "prove & verify simple multiplication circuit, `Snarkjs` flavour":
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()
#-------------------------------------------------------------------------------