mirror of
https://github.com/logos-storage/nim-groth16.git
synced 2026-04-05 03:43:30 +00:00
Merge 2ae270a8079081cf7c924852f8f93ec918b93217 into 73b5ae2734050d64157afbc29d364345ff0ec211
This commit is contained in:
commit
a5919e93a9
146
tests/groth16/testFakeSetup.nim
Normal file
146
tests/groth16/testFakeSetup.nim
Normal file
@ -0,0 +1,146 @@
|
||||
|
||||
import std/unittest
|
||||
|
||||
import groth16/bn128/fields
|
||||
import groth16/fake_setup
|
||||
import groth16/zkey_types
|
||||
import groth16/files/r1cs
|
||||
|
||||
suite "fake setup":
|
||||
|
||||
const testWitnessCfg =
|
||||
WitnessConfig( nWires: 5
|
||||
, nPubOut: 1
|
||||
, nPubIn: 1
|
||||
, nPrivIn: 2
|
||||
, nLabels: 0
|
||||
)
|
||||
|
||||
const testConstraint1: Constraint = (
|
||||
@[ (wireIdx: 0, value: oneFr) ] ,
|
||||
@[ (wireIdx: 1, value: oneFr) ] ,
|
||||
@[ (wireIdx: 2, value: oneFr) ]
|
||||
)
|
||||
|
||||
const testConstraints: seq[Constraint] = @[ testConstraint1 ]
|
||||
const testLabels: seq[int] = @[]
|
||||
|
||||
const testR1CS =
|
||||
R1CS( r: primeR
|
||||
, cfg: testWitnessCfg
|
||||
, nConstr: testConstraints.len
|
||||
, constraints: testConstraints
|
||||
, wireToLabel: testLabels
|
||||
)
|
||||
|
||||
test "create fake circuit setup - JensGroth":
|
||||
let zkey = createFakeCircuitSetup( testR1CS, flavour=JensGroth )
|
||||
|
||||
check zkey.header.curve == "bn128"
|
||||
check zkey.header.flavour == JensGroth
|
||||
check zkey.header.nvars == testWitnessCfg.nWires
|
||||
check zkey.header.npubs == testWitnessCfg.nPubOut + testWitnessCfg.nPubIn
|
||||
|
||||
test "create fake circuit setup - Snarkjs":
|
||||
let zkey = createFakeCircuitSetup( testR1CS, flavour=Snarkjs )
|
||||
|
||||
check zkey.header.curve == "bn128"
|
||||
check zkey.header.flavour == Snarkjs
|
||||
check zkey.header.nvars == testWitnessCfg.nWires
|
||||
check zkey.header.npubs == testWitnessCfg.nPubOut + testWitnessCfg.nPubIn
|
||||
|
||||
test "fake setup header consistency":
|
||||
let zkey = createFakeCircuitSetup( testR1CS, flavour=Snarkjs )
|
||||
let header = zkey.header
|
||||
|
||||
check header.domainSize == (1 shl header.logDomainSize)
|
||||
check header.domainSize >= testR1CS.nConstr + header.npubs + 1
|
||||
|
||||
test "fake setup spec points":
|
||||
let zkey = createFakeCircuitSetup( testR1CS, flavour=Snarkjs )
|
||||
let spec = zkey.specPoints
|
||||
|
||||
check true
|
||||
check true
|
||||
|
||||
test "fake setup verifier points":
|
||||
let zkey = createFakeCircuitSetup( testR1CS, flavour=Snarkjs )
|
||||
let vPoints = zkey.vPoints
|
||||
|
||||
let expectedLen = testWitnessCfg.nPubOut + testWitnessCfg.nPubIn + 1
|
||||
check vPoints.pointsIC.len == expectedLen
|
||||
|
||||
test "fake setup prover points":
|
||||
let zkey = createFakeCircuitSetup( testR1CS, flavour=Snarkjs )
|
||||
let pPoints = zkey.pPoints
|
||||
|
||||
check pPoints.pointsA1.len == testWitnessCfg.nWires
|
||||
check pPoints.pointsB1.len == testWitnessCfg.nWires
|
||||
check pPoints.pointsB2.len == testWitnessCfg.nWires
|
||||
check pPoints.pointsC1.len == testWitnessCfg.nWires - (testWitnessCfg.nPubOut + testWitnessCfg.nPubIn + 1)
|
||||
check pPoints.pointsH1.len > 0
|
||||
|
||||
test "fake setup coefficients":
|
||||
let zkey = createFakeCircuitSetup( testR1CS, flavour=Snarkjs )
|
||||
|
||||
check zkey.coeffs.len > 0
|
||||
|
||||
for coeff in zkey.coeffs:
|
||||
check coeff.row >= 0
|
||||
check coeff.col >= 0
|
||||
check coeff.col < testWitnessCfg.nWires
|
||||
|
||||
test "random toxic waste":
|
||||
let toxic1 = randomToxicWaste()
|
||||
let toxic2 = randomToxicWaste()
|
||||
|
||||
check not isEqualFr(toxic1.alpha, toxic2.alpha) or
|
||||
not isEqualFr(toxic1.beta, toxic2.beta) or
|
||||
not isEqualFr(toxic1.gamma, toxic2.gamma) or
|
||||
not isEqualFr(toxic1.delta, toxic2.delta) or
|
||||
not isEqualFr(toxic1.tau, toxic2.tau)
|
||||
|
||||
test "R1CS to coefficients conversion":
|
||||
let coeffs = r1csToCoeffs( testR1CS )
|
||||
|
||||
check coeffs.len > 0
|
||||
|
||||
var hasA = false
|
||||
var hasB = false
|
||||
for coeff in coeffs:
|
||||
if coeff.matrix == MatrixA:
|
||||
hasA = true
|
||||
if coeff.matrix == MatrixB:
|
||||
hasB = true
|
||||
|
||||
check hasA or hasB
|
||||
|
||||
test "R1CS to sparse matrices":
|
||||
let matrices = r1csToSparseMatrices( testR1CS )
|
||||
|
||||
check matrices.A.len == testWitnessCfg.nWires
|
||||
check matrices.B.len == testWitnessCfg.nWires
|
||||
check matrices.C.len == testWitnessCfg.nWires
|
||||
|
||||
test "fake setup with different flavours produces different H points":
|
||||
let zkey1 = createFakeCircuitSetup( testR1CS, flavour=JensGroth )
|
||||
let zkey2 = createFakeCircuitSetup( testR1CS, flavour=Snarkjs )
|
||||
|
||||
check zkey1.pPoints.pointsH1.len == zkey2.pPoints.pointsH1.len
|
||||
|
||||
test "fake setup domain size":
|
||||
let zkey = createFakeCircuitSetup( testR1CS, flavour=Snarkjs )
|
||||
|
||||
let domainSize = zkey.header.domainSize
|
||||
check (domainSize and (domainSize - 1)) == 0
|
||||
|
||||
check domainSize >= testR1CS.nConstr + zkey.header.npubs + 1
|
||||
|
||||
test "fake setup consistency":
|
||||
let zkey1 = createFakeCircuitSetup( testR1CS, flavour=Snarkjs )
|
||||
let zkey2 = createFakeCircuitSetup( testR1CS, flavour=Snarkjs )
|
||||
|
||||
check zkey1.header.nvars == zkey2.header.nvars
|
||||
check zkey1.header.npubs == zkey2.header.npubs
|
||||
check zkey1.header.domainSize == zkey2.header.domainSize
|
||||
check zkey1.pPoints.pointsA1.len == zkey2.pPoints.pointsA1.len
|
||||
117
tests/groth16/testProverVerifier.nim
Normal file
117
tests/groth16/testProverVerifier.nim
Normal file
@ -0,0 +1,117 @@
|
||||
|
||||
import std/unittest
|
||||
import std/sequtils
|
||||
|
||||
import taskpools
|
||||
|
||||
import groth16/bn128/fields
|
||||
import groth16/prover
|
||||
import groth16/verifier
|
||||
import groth16/fake_setup
|
||||
import groth16/zkey_types
|
||||
import groth16/files/r1cs
|
||||
import groth16/files/witness
|
||||
|
||||
suite "prover and verifier":
|
||||
|
||||
const simpleWitnessCfg =
|
||||
WitnessConfig( nWires: 8
|
||||
, nPubOut: 1
|
||||
, nPubIn: 1
|
||||
, nPrivIn: 3
|
||||
, nLabels: 0
|
||||
)
|
||||
|
||||
const simpleEq1: Constraint = ( @[] , @[] , @[ (1,minusOneFr) , (2,oneFr) , (7,oneFr) ] )
|
||||
const simpleEq2: Constraint = ( @[ (3,oneFr) ] , @[ (4,oneFr) ] , @[ (6,oneFr) ] )
|
||||
const simpleEq3: Constraint = ( @[ (5,oneFr) ] , @[ (6,oneFr) ] , @[ (7,oneFr) ] )
|
||||
|
||||
const simpleConstraints: seq[Constraint] = @[ simpleEq1, simpleEq2, simpleEq3 ]
|
||||
const simpleLabels: seq[int] = @[]
|
||||
|
||||
const simpleR1CS =
|
||||
R1CS( r: primeR
|
||||
, cfg: simpleWitnessCfg
|
||||
, nConstr: simpleConstraints.len
|
||||
, constraints: simpleConstraints
|
||||
, wireToLabel: simpleLabels
|
||||
)
|
||||
|
||||
let simpleWitnessValues = map( @[ 1, 2023, 1022, 7, 11, 13, 7*11, 7*11*13 ] , intToFr )
|
||||
|
||||
let simpleWitness =
|
||||
Witness( curve: "bn128"
|
||||
, r: primeR
|
||||
, nvars: 8
|
||||
, values: simpleWitnessValues
|
||||
)
|
||||
|
||||
test "prove and verify - JensGroth flavour":
|
||||
let zkey = createFakeCircuitSetup( simpleR1CS, flavour=JensGroth )
|
||||
var pool = Taskpool.new()
|
||||
let proof = generateProof( zkey, simpleWitness, pool )
|
||||
let vkey = extractVKey( zkey )
|
||||
let ok = verifyProof( vkey, proof )
|
||||
pool.shutdown()
|
||||
check ok
|
||||
|
||||
test "prove and verify - Snarkjs flavour":
|
||||
let zkey = createFakeCircuitSetup( simpleR1CS, flavour=Snarkjs )
|
||||
var pool = Taskpool.new()
|
||||
let proof = generateProof( zkey, simpleWitness, pool )
|
||||
let vkey = extractVKey( zkey )
|
||||
let ok = verifyProof( vkey, proof )
|
||||
pool.shutdown()
|
||||
check ok
|
||||
|
||||
test "proof structure":
|
||||
let zkey = createFakeCircuitSetup( simpleR1CS, flavour=Snarkjs )
|
||||
var pool = Taskpool.new()
|
||||
let proof = generateProof( zkey, simpleWitness, pool )
|
||||
pool.shutdown()
|
||||
|
||||
check proof.curve == "bn128"
|
||||
check proof.publicIO.len == simpleWitnessCfg.nPubOut + simpleWitnessCfg.nPubIn + 1
|
||||
check true
|
||||
|
||||
test "verification key extraction":
|
||||
let zkey = createFakeCircuitSetup( simpleR1CS, flavour=Snarkjs )
|
||||
let vkey = extractVKey( zkey )
|
||||
|
||||
check vkey.curve == "bn128"
|
||||
check vkey.vpoints.pointsIC.len == simpleWitnessCfg.nPubOut + simpleWitnessCfg.nPubIn + 1
|
||||
|
||||
test "proof structure consistency":
|
||||
let zkey = createFakeCircuitSetup( simpleR1CS, flavour=Snarkjs )
|
||||
var pool = Taskpool.new()
|
||||
let proof1 = generateProof( zkey, simpleWitness, pool )
|
||||
let proof2 = generateProof( zkey, simpleWitness, pool )
|
||||
pool.shutdown()
|
||||
|
||||
check proof1.publicIO.len == proof2.publicIO.len
|
||||
check proof1.curve == proof2.curve
|
||||
check proof1.curve == "bn128"
|
||||
|
||||
test "multiple proofs with same setup":
|
||||
let zkey = createFakeCircuitSetup( simpleR1CS, flavour=Snarkjs )
|
||||
let vkey = extractVKey( zkey )
|
||||
var pool = Taskpool.new()
|
||||
|
||||
for i in 1..5:
|
||||
let proof = generateProof( zkey, simpleWitness, pool )
|
||||
let ok = verifyProof( vkey, proof )
|
||||
check ok
|
||||
|
||||
pool.shutdown()
|
||||
|
||||
test "proof with different witness but same public IO":
|
||||
let altWitnessValues = map( @[ 1, 2023, 1022, 7, 11, 13, 7*11, 7*11*13 ] , intToFr )
|
||||
let altWitness = Witness( curve: "bn128", r: primeR, nvars: 8, values: altWitnessValues )
|
||||
|
||||
let zkey = createFakeCircuitSetup( simpleR1CS, flavour=Snarkjs )
|
||||
var pool = Taskpool.new()
|
||||
let proof = generateProof( zkey, altWitness, pool )
|
||||
let vkey = extractVKey( zkey )
|
||||
let ok = verifyProof( vkey, proof )
|
||||
pool.shutdown()
|
||||
check ok
|
||||
140
tests/groth16/testR1CS.nim
Normal file
140
tests/groth16/testR1CS.nim
Normal file
@ -0,0 +1,140 @@
|
||||
|
||||
import std/unittest
|
||||
|
||||
import groth16/bn128/fields
|
||||
import groth16/files/r1cs
|
||||
|
||||
suite "R1CS operations":
|
||||
|
||||
test "R1CS creation":
|
||||
let cfg = WitnessConfig(
|
||||
nWires: 8,
|
||||
nPubOut: 1,
|
||||
nPubIn: 1,
|
||||
nPrivIn: 3,
|
||||
nLabels: 0
|
||||
)
|
||||
|
||||
let constraint1: Constraint = (
|
||||
A: @[(wireIdx: 1, value: minusOneFr), (wireIdx: 2, value: oneFr), (wireIdx: 7, value: oneFr)],
|
||||
B: @[],
|
||||
C: @[]
|
||||
)
|
||||
|
||||
let constraint2: Constraint = (
|
||||
A: @[(wireIdx: 3, value: oneFr)],
|
||||
B: @[(wireIdx: 4, value: oneFr)],
|
||||
C: @[(wireIdx: 6, value: oneFr)]
|
||||
)
|
||||
|
||||
let constraints = @[constraint1, constraint2]
|
||||
|
||||
let r1cs = R1CS(
|
||||
r: primeR,
|
||||
cfg: cfg,
|
||||
nConstr: constraints.len,
|
||||
constraints: constraints,
|
||||
wireToLabel: @[]
|
||||
)
|
||||
|
||||
check r1cs.cfg.nWires == 8
|
||||
check r1cs.nConstr == 2
|
||||
check r1cs.constraints.len == 2
|
||||
|
||||
test "R1CS constraint structure":
|
||||
let constraint: Constraint = (
|
||||
A: @[(wireIdx: 0, value: oneFr), (wireIdx: 1, value: intToFr(2))],
|
||||
B: @[(wireIdx: 2, value: intToFr(3))],
|
||||
C: @[(wireIdx: 3, value: intToFr(4))]
|
||||
)
|
||||
|
||||
check constraint.A.len == 2
|
||||
check constraint.B.len == 1
|
||||
check constraint.C.len == 1
|
||||
check isEqualFr(constraint.A[0].value, oneFr)
|
||||
check isEqualFr(constraint.A[1].value, intToFr(2))
|
||||
|
||||
test "R1CS witness config":
|
||||
let cfg = WitnessConfig(
|
||||
nWires: 10,
|
||||
nPubOut: 2,
|
||||
nPubIn: 3,
|
||||
nPrivIn: 4,
|
||||
nLabels: 1
|
||||
)
|
||||
|
||||
check cfg.nWires == 10
|
||||
check cfg.nPubOut == 2
|
||||
check cfg.nPubIn == 3
|
||||
check cfg.nPrivIn == 4
|
||||
check cfg.nLabels == 1
|
||||
|
||||
test "R1CS term creation":
|
||||
let term1: Term = (wireIdx: 5, value: intToFr(42))
|
||||
let term2: Term = (wireIdx: 3, value: minusOneFr)
|
||||
|
||||
check term1.wireIdx == 5
|
||||
check isEqualFr(term1.value, intToFr(42))
|
||||
check term2.wireIdx == 3
|
||||
check isEqualFr(term2.value, minusOneFr)
|
||||
|
||||
test "R1CS linear combination":
|
||||
let linComb: LinComb = @[
|
||||
(wireIdx: 0, value: oneFr),
|
||||
(wireIdx: 1, value: intToFr(2)),
|
||||
(wireIdx: 2, value: intToFr(3))
|
||||
]
|
||||
|
||||
check linComb.len == 3
|
||||
check linComb[0].wireIdx == 0
|
||||
check isEqualFr(linComb[1].value, intToFr(2))
|
||||
|
||||
test "R1CS constraint evaluation":
|
||||
let x = intToFr(5)
|
||||
let y = intToFr(7)
|
||||
let expected = x * y
|
||||
|
||||
let constraint: Constraint = (
|
||||
A: @[(wireIdx: 0, value: x)],
|
||||
B: @[(wireIdx: 1, value: y)],
|
||||
C: @[(wireIdx: 2, value: expected)]
|
||||
)
|
||||
|
||||
let product = constraint.A[0].value * constraint.B[0].value
|
||||
check isEqualFr(product, constraint.C[0].value)
|
||||
|
||||
test "R1CS empty constraint":
|
||||
let emptyConstraint: Constraint = (
|
||||
A: @[],
|
||||
B: @[],
|
||||
C: @[]
|
||||
)
|
||||
|
||||
check emptyConstraint.A.len == 0
|
||||
check emptyConstraint.B.len == 0
|
||||
check emptyConstraint.C.len == 0
|
||||
|
||||
test "R1CS multiple constraints":
|
||||
let constraints = @[
|
||||
(A: @[(wireIdx: 0, value: oneFr)], B: @[(wireIdx: 1, value: oneFr)], C: @[(wireIdx: 2, value: oneFr)]),
|
||||
(A: @[(wireIdx: 2, value: oneFr)], B: @[(wireIdx: 3, value: oneFr)], C: @[(wireIdx: 4, value: oneFr)]),
|
||||
(A: @[(wireIdx: 4, value: oneFr)], B: @[(wireIdx: 5, value: oneFr)], C: @[(wireIdx: 6, value: oneFr)])
|
||||
]
|
||||
|
||||
check constraints.len == 3
|
||||
for i, constraint in constraints:
|
||||
check constraint.A.len > 0 or constraint.B.len > 0 or constraint.C.len > 0
|
||||
|
||||
test "R1CS wire to label mapping":
|
||||
let wireToLabel = @[0, 1, 2, 3, 4]
|
||||
let r1cs = R1CS(
|
||||
r: primeR,
|
||||
cfg: WitnessConfig(nWires: 5, nPubOut: 0, nPubIn: 0, nPrivIn: 0, nLabels: 0),
|
||||
nConstr: 0,
|
||||
constraints: @[],
|
||||
wireToLabel: wireToLabel
|
||||
)
|
||||
|
||||
check r1cs.wireToLabel.len == 5
|
||||
check r1cs.wireToLabel[0] == 0
|
||||
check r1cs.wireToLabel[4] == 4
|
||||
203
tests/groth16/testRegression.nim
Normal file
203
tests/groth16/testRegression.nim
Normal file
@ -0,0 +1,203 @@
|
||||
|
||||
import std/unittest
|
||||
|
||||
import taskpools
|
||||
|
||||
import groth16/bn128
|
||||
import groth16/prover
|
||||
import groth16/verifier
|
||||
import groth16/fake_setup
|
||||
import groth16/zkey_types
|
||||
import groth16/files/r1cs
|
||||
import groth16/files/witness
|
||||
import groth16/math/poly
|
||||
import groth16/math/domain
|
||||
import groth16/math/ntt
|
||||
|
||||
suite "regression tests":
|
||||
|
||||
test "edge case - single constraint circuit":
|
||||
const cfg = WitnessConfig( nWires: 3, nPubOut: 0, nPubIn: 1, nPrivIn: 1, nLabels: 0 )
|
||||
const constraint: Constraint = (
|
||||
@[ (wireIdx: 0, value: oneFr) ] ,
|
||||
@[ (wireIdx: 1, value: oneFr) ] ,
|
||||
@[ (wireIdx: 2, value: oneFr) ]
|
||||
)
|
||||
const r1cs = R1CS( r: primeR, cfg: cfg, nConstr: 1, constraints: @[constraint], wireToLabel: @[] )
|
||||
let witness = Witness( curve: "bn128", r: primeR, nvars: 3, values: @[oneFr, intToFr(2), intToFr(2)] )
|
||||
|
||||
let zkey = createFakeCircuitSetup( r1cs, flavour=Snarkjs )
|
||||
var pool = Taskpool.new()
|
||||
let proof = generateProof( zkey, witness, pool )
|
||||
let vkey = extractVKey( zkey )
|
||||
let ok = verifyProof( vkey, proof )
|
||||
pool.shutdown()
|
||||
check ok
|
||||
|
||||
test "edge case - empty public inputs":
|
||||
const cfg = WitnessConfig( nWires: 4, nPubOut: 0, nPubIn: 0, nPrivIn: 2, nLabels: 0 )
|
||||
const constraint: Constraint = (
|
||||
@[ (wireIdx: 1, value: oneFr) ] ,
|
||||
@[ (wireIdx: 2, value: oneFr) ] ,
|
||||
@[ (wireIdx: 3, value: oneFr) ]
|
||||
)
|
||||
const r1cs = R1CS( r: primeR, cfg: cfg, nConstr: 1, constraints: @[constraint], wireToLabel: @[] )
|
||||
let witness = Witness( curve: "bn128", r: primeR, nvars: 4, values: @[oneFr, intToFr(2), intToFr(2), intToFr(4)] )
|
||||
|
||||
let zkey = createFakeCircuitSetup( r1cs, flavour=Snarkjs )
|
||||
var pool = Taskpool.new()
|
||||
let proof = generateProof( zkey, witness, pool )
|
||||
let vkey = extractVKey( zkey )
|
||||
let ok = verifyProof( vkey, proof )
|
||||
pool.shutdown()
|
||||
check ok
|
||||
|
||||
test "edge case - large number of constraints":
|
||||
let cfg = WitnessConfig( nWires: 10, nPubOut: 1, nPubIn: 1, nPrivIn: 7, nLabels: 0 )
|
||||
var constraints: seq[Constraint] = @[]
|
||||
|
||||
for i in 0..<20:
|
||||
constraints.add((
|
||||
@[ (wireIdx: i mod 10, value: oneFr) ],
|
||||
@[ (wireIdx: (i+1) mod 10, value: oneFr) ],
|
||||
@[ (wireIdx: (i+2) mod 10, value: oneFr) ]
|
||||
))
|
||||
|
||||
let witnessValues = @[oneFr, oneFr, oneFr, oneFr, oneFr, oneFr, oneFr, oneFr, oneFr, oneFr]
|
||||
let r1cs = R1CS( r: primeR, cfg: cfg, nConstr: constraints.len, constraints: constraints, wireToLabel: @[] )
|
||||
let witness = Witness( curve: "bn128", r: primeR, nvars: 10, values: witnessValues )
|
||||
|
||||
let zkey = createFakeCircuitSetup( r1cs, flavour=Snarkjs )
|
||||
var pool = Taskpool.new()
|
||||
let proof = generateProof( zkey, witness, pool )
|
||||
let vkey = extractVKey( zkey )
|
||||
let ok = verifyProof( vkey, proof )
|
||||
pool.shutdown()
|
||||
check ok
|
||||
|
||||
test "edge case - polynomial with leading zeros":
|
||||
let P = Poly(coeffs: @[intToFr(1), intToFr(2), zeroFr, zeroFr])
|
||||
check polyDegree(P) == 1
|
||||
check not polyIsZero(P)
|
||||
|
||||
test "edge case - domain size 2":
|
||||
let D = createDomain(2)
|
||||
check D.domainSize == 2
|
||||
check D.logDomainSize == 1
|
||||
|
||||
let points = enumerateDomain(D)
|
||||
check points.len == 2
|
||||
check isEqualFr(points[0], oneFr)
|
||||
check isEqualFr(points[1], D.domainGen)
|
||||
|
||||
test "edge case - very large domain":
|
||||
let D = createDomain(1024)
|
||||
check D.domainSize == 1024
|
||||
check D.logDomainSize == 10
|
||||
|
||||
let points = enumerateDomain(D)
|
||||
check points.len == 1024
|
||||
let wrapAround = points[1023] * D.domainGen
|
||||
check isEqualFr(wrapAround, oneFr)
|
||||
|
||||
test "edge case - field element at prime boundary":
|
||||
let minusOne = minusOneFr
|
||||
let one = oneFr
|
||||
let sum = minusOne + one
|
||||
check isZeroFr(sum)
|
||||
|
||||
test "edge case - batch inversion with single element":
|
||||
let xs = @[intToFr(5)]
|
||||
let ys = batchInverseFr(xs)
|
||||
check ys.len == 1
|
||||
check isEqualFr(xs[0] * ys[0], oneFr)
|
||||
|
||||
test "edge case - batch inversion with zero element":
|
||||
let xs = @[intToFr(1), intToFr(2), intToFr(3)]
|
||||
let ys = batchInverseFr(xs)
|
||||
for i in 0..<xs.len:
|
||||
check isEqualFr(xs[i] * ys[i], oneFr)
|
||||
|
||||
test "regression - polynomial multiplication identity":
|
||||
let P = Poly(coeffs: @[intToFr(1), intToFr(2), intToFr(3)])
|
||||
let onePoly = Poly(coeffs: @[oneFr])
|
||||
let result = P * onePoly
|
||||
check polyIsEqual(result, P)
|
||||
|
||||
test "regression - polynomial addition zero":
|
||||
let P = Poly(coeffs: @[intToFr(1), intToFr(2)])
|
||||
let zeroPoly = Poly(coeffs: @[zeroFr])
|
||||
let result = P + zeroPoly
|
||||
check polyIsEqual(result, P)
|
||||
|
||||
test "regression - NTT round trip with two elements":
|
||||
let D = createDomain(2)
|
||||
let input = @[intToFr(1), intToFr(2)]
|
||||
let forward = forwardNTT(input, D)
|
||||
let inverse = inverseNTT(forward, D)
|
||||
check input.len == inverse.len
|
||||
check isEqualFr(input[0], inverse[0])
|
||||
check isEqualFr(input[1], inverse[1])
|
||||
|
||||
test "regression - vanishing polynomial at domain points":
|
||||
let N = 8
|
||||
let Z = vanishingPoly(N)
|
||||
let D = createDomain(N)
|
||||
let points = enumerateDomain(D)
|
||||
|
||||
for point in points:
|
||||
let eval = polyEvalAt(Z, point)
|
||||
check isZeroFr(eval)
|
||||
|
||||
test "regression - Lagrange basis at domain points":
|
||||
let N = 4
|
||||
let D = createDomain(N)
|
||||
let points = enumerateDomain(D)
|
||||
|
||||
for k in 0..<N:
|
||||
let Lk = lagrangePoly(D, k)
|
||||
for i in 0..<N:
|
||||
let eval = polyEvalAt(Lk, points[i])
|
||||
if i == k:
|
||||
check isEqualFr(eval, oneFr)
|
||||
else:
|
||||
check isZeroFr(eval)
|
||||
|
||||
test "regression - proof generation with minimal circuit":
|
||||
const cfg = WitnessConfig( nWires: 2, nPubOut: 0, nPubIn: 0, nPrivIn: 1, nLabels: 0 )
|
||||
const constraint: Constraint = (
|
||||
@[ (wireIdx: 0, value: oneFr) ] ,
|
||||
@[ (wireIdx: 1, value: oneFr) ] ,
|
||||
@[ (wireIdx: 1, value: oneFr) ]
|
||||
)
|
||||
const r1cs = R1CS( r: primeR, cfg: cfg, nConstr: 1, constraints: @[constraint], wireToLabel: @[] )
|
||||
let witness = Witness( curve: "bn128", r: primeR, nvars: 2, values: @[oneFr, oneFr] )
|
||||
|
||||
let zkey = createFakeCircuitSetup( r1cs, flavour=Snarkjs )
|
||||
var pool = Taskpool.new()
|
||||
let proof = generateProof( zkey, witness, pool )
|
||||
let vkey = extractVKey( zkey )
|
||||
let ok = verifyProof( vkey, proof )
|
||||
pool.shutdown()
|
||||
check ok
|
||||
|
||||
test "regression - multiple proof generations don't interfere":
|
||||
const cfg = WitnessConfig( nWires: 3, nPubOut: 0, nPubIn: 1, nPrivIn: 1, nLabels: 0 )
|
||||
const constraint: Constraint = (
|
||||
@[ (wireIdx: 0, value: oneFr) ] ,
|
||||
@[ (wireIdx: 1, value: oneFr) ] ,
|
||||
@[ (wireIdx: 2, value: oneFr) ]
|
||||
)
|
||||
const r1cs = R1CS( r: primeR, cfg: cfg, nConstr: 1, constraints: @[constraint], wireToLabel: @[] )
|
||||
let witness = Witness( curve: "bn128", r: primeR, nvars: 3, values: @[oneFr, intToFr(2), intToFr(2)] )
|
||||
|
||||
let zkey = createFakeCircuitSetup( r1cs, flavour=Snarkjs )
|
||||
let vkey = extractVKey( zkey )
|
||||
var pool = Taskpool.new()
|
||||
|
||||
for i in 1..10:
|
||||
let proof = generateProof( zkey, witness, pool )
|
||||
let ok = verifyProof( vkey, proof )
|
||||
check ok
|
||||
|
||||
pool.shutdown()
|
||||
87
tests/groth16/testWitness.nim
Normal file
87
tests/groth16/testWitness.nim
Normal file
@ -0,0 +1,87 @@
|
||||
|
||||
import std/unittest
|
||||
import std/sequtils
|
||||
|
||||
import constantine/named/properties_fields
|
||||
|
||||
import groth16/bn128
|
||||
import groth16/bn128/fields
|
||||
import groth16/files/witness
|
||||
|
||||
suite "witness operations":
|
||||
|
||||
test "witness creation":
|
||||
let values = @[oneFr, intToFr(2), intToFr(3), intToFr(4)]
|
||||
let witness = makeWitnessBN254(values)
|
||||
|
||||
check witness.curve == "bn128"
|
||||
check witness.nvars == 4
|
||||
check witness.values.len == 4
|
||||
check isEqualFr(witness.values[0], oneFr)
|
||||
check isEqualFr(witness.values[1], intToFr(2))
|
||||
|
||||
test "witness structure":
|
||||
let values = map(toSeq(1..10), intToFr)
|
||||
let witness = makeWitnessBN254(values)
|
||||
|
||||
check witness.nvars == 10
|
||||
check witness.values.len == 10
|
||||
check true
|
||||
|
||||
test "witness with zero values":
|
||||
let values = @[zeroFr, zeroFr, zeroFr]
|
||||
let witness = makeWitnessBN254(values)
|
||||
|
||||
check witness.nvars == 3
|
||||
check witness.values.len == 3
|
||||
check isZeroFr(witness.values[0])
|
||||
check isZeroFr(witness.values[1])
|
||||
check isZeroFr(witness.values[2])
|
||||
|
||||
test "witness with large values":
|
||||
let values = @[intToFr(1000000), intToFr(999999), intToFr(123456)]
|
||||
let witness = makeWitnessBN254(values)
|
||||
|
||||
check witness.nvars == 3
|
||||
check isEqualFr(witness.values[0], intToFr(1000000))
|
||||
|
||||
test "witness single value":
|
||||
let values = @[oneFr]
|
||||
let witness = makeWitnessBN254(values)
|
||||
|
||||
check witness.nvars == 1
|
||||
check witness.values.len == 1
|
||||
check isEqualFr(witness.values[0], oneFr)
|
||||
|
||||
test "witness empty (should fail or handle gracefully)":
|
||||
let values: seq[Fr[BN254_Snarks]] = @[]
|
||||
let witness = makeWitnessBN254(values)
|
||||
|
||||
check witness.nvars == 0
|
||||
check witness.values.len == 0
|
||||
|
||||
test "witness field consistency":
|
||||
let values = @[oneFr, intToFr(5), intToFr(10)]
|
||||
let witness = makeWitnessBN254(values)
|
||||
|
||||
# All values should be valid field elements
|
||||
check witness.values.len == 3
|
||||
check isEqualFr(witness.values[0], oneFr)
|
||||
check isEqualFr(witness.values[1], intToFr(5))
|
||||
check isEqualFr(witness.values[2], intToFr(10))
|
||||
|
||||
test "witness ordering":
|
||||
let publicOut = intToFr(100)
|
||||
let publicIn = intToFr(200)
|
||||
let privateIn = intToFr(300)
|
||||
let secret = intToFr(400)
|
||||
|
||||
let values = @[oneFr, publicOut, publicIn, privateIn, secret]
|
||||
let witness = makeWitnessBN254(values)
|
||||
|
||||
check witness.nvars == 5
|
||||
check isEqualFr(witness.values[0], oneFr)
|
||||
check isEqualFr(witness.values[1], publicOut)
|
||||
check isEqualFr(witness.values[2], publicIn)
|
||||
check isEqualFr(witness.values[3], privateIn)
|
||||
check isEqualFr(witness.values[4], secret)
|
||||
@ -1,3 +1,8 @@
|
||||
|
||||
import ./groth16/testProver
|
||||
import ./groth16/testR1CS
|
||||
import ./groth16/testWitness
|
||||
import ./groth16/testProverVerifier
|
||||
import ./groth16/testFakeSetup
|
||||
import ./groth16/testRegression
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user