convert some of the hack-ish "sanity checks" into regular tests

This commit is contained in:
Balazs Komuves 2026-06-13 15:48:35 +02:00
parent e6e0ba01b2
commit eff53fa4eb
No known key found for this signature in database
GPG Key ID: F63B7AEF18435562
7 changed files with 155 additions and 124 deletions

View File

@ -9,7 +9,7 @@
import sugar
import std/bitops
import std/sequtils
# import std/sequtils
import constantine/math/arithmetic
import constantine/math/io/io_fields
@ -43,6 +43,8 @@ const oneFp2* = mkFp2( oneFp , zeroFp )
const minusOneFp* = fromHex( Fp[BN254_Snarks], "0x30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd46" )
const minusOneFr* = fromHex( Fr[BN254_Snarks], "0x30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000000" )
const oneHalfFr* = fromHex( Fr[BN254_Snarks], "0x183227397098d014dc2822db40c0ac2e9419f4243cdcb848a1f0fac9f8000001" )
#-------------------------------------------------------------------------------
func intToB*(a: uint): B =
@ -152,7 +154,7 @@ func smallPowFr*(base: Fr, expo: int): Fr =
#-------------------------------------------------------------------------------
func deltaFr*[T](i, j: int) : Fr[T] =
func deltaFr*(i, j: int) : Fr[BN254_Snarks] =
return (if (i == j): oneFr else: zeroFr)
#-------------------------------------------------------------------------------
@ -171,17 +173,6 @@ func batchInverseFr*( xs: seq[Fr[BN254_Snarks]] ) : seq[Fr[BN254_Snarks]] =
for i in countdown(n-2,0): vs[i] = vs[i+1] * xs[i+1]
return collect( newSeq, (for i in 0..<n: us[i]*vs[i] ) )
proc sanityCheckBatchInverseFr*() =
let xs = map( toSeq(101..137) , intToFr )
let ys = batchInverseFr( xs )
let zs = collect( newSeq, (for x in xs: invFr(x)) )
let n = xs.len
# for i in 0..<n: echo(i," | batch = ",toDecimalFr(ys[i])," | ref = ",toDecimalFr(zs[i]) )
for i in 0..<n:
if not bool(ys[i] == zs[i]):
echo "batch inverse test FAILED!"
return
echo "batch iverse test OK."
#-------------------------------------------------------------------------------

View File

@ -270,111 +270,3 @@ func polyInverseNTT*(ys: seq[Fr[BN254_Snarks]], D: Domain): Poly =
#-------------------------------------------------------------------------------
#[
proc sanityCheckOneHalf*() =
let two = oneFr + oneFr
let invTwo = oneHalfFr
echo(toDecimalFr(two))
echo(toDecimalFr(invTwo * two))
echo(toHex(invTwo))
#-------------------
proc sanityCheckVanishing*() =
var js : seq[int] = toSeq(101..112)
let cs : seq[Fr] = map( js, intToFr )
let P : Poly = Poly( coeffs:cs )
echo("degree of P = ",polyDegree(P))
debugPrintFrSeq("xs", P.coeffs)
let n : int = 5
let QR = polyQuotRemByVanishing(P, n)
let Q = QR.quot
let R = QR.rem
debugPrintFrSeq("Q", Q.coeffs)
debugPrintFrSeq("R", R.coeffs)
let Z : Poly = vanishingPoly(n)
let S : Poly = Q * Z + R
debugPrintFrSeq("zs", S.coeffs)
echo( polyIsEqual(P,S) )
#-------------------
proc sanityCheckNTT*() =
var js : seq[int] = toSeq(101..108)
let cs : seq[Fr] = map( js, intToFr )
let P : Poly = Poly( coeffs:cs )
let D : Domain = createDomain(8)
let xs : seq[Fr] = D.enumerateDomain()
let ys : seq[Fr] = collect( newSeq, (for x in xs: polyEvalAt(P,x)) )
let zs : seq[Fr] = polyForwardNTT(P ,D)
let Q : Poly = polyInverseNTT(zs,D)
debugPrintFrSeq("xs", xs)
debugPrintFrSeq("ys", ys)
debugPrintFrSeq("zs", zs)
debugPrintFrSeq("us", Q.coeffs)
#-------------------
proc sanityCheckMulFFT*() =
var js : seq[int] = toSeq(101..110)
let cs : seq[Fr] = map( js, intToFr )
let P : Poly = Poly( coeffs:cs )
var ks : seq[int] = toSeq(1001..1020)
let ds : seq[Fr] = map( ks, intToFr )
let Q : Poly = Poly( coeffs:ds )
let R1 : Poly = polyMulNaive( P , Q )
let R2 : Poly = polyMulFFT( P , Q )
# debugPrintFrSeq("naive coeffs", R1.coeffs)
# debugPrintFrSeq("fft coeffs", R2.coeffs)
echo( "multiply test = ", polyIsEqual(R1,R2) )
#-------------------
proc sanityCheckLagrangeBases*() =
let n = 8
let D = createDomain(n)
let L : seq[Poly] = collect( newSeq, (for k in 0..<n: lagrangePoly(D,k) ))
let xs = enumerateDomain(D)
let ys0 : seq[Fr] = collect( newSeq, (for x in xs: polyEvalAt(L[0],x) ))
let ys1 : seq[Fr] = collect( newSeq, (for x in xs: polyEvalAt(L[1],x) ))
let ys5 : seq[Fr] = collect( newSeq, (for x in xs: polyEvalAt(L[5],x) ))
let zs0 : seq[Fr] = collect( newSeq, (for i in 0..<n: deltaFr(0,i) ))
let zs1 : seq[Fr] = collect( newSeq, (for i in 0..<n: deltaFr(1,i) ))
let zs5 : seq[Fr] = collect( newSeq, (for i in 0..<n: deltaFr(5,i) ))
echo("==============")
for i in 0..<n: echo("i = ",i, " | y[i] = ",toDecimalFr(ys0[i]), " | z[i] = ",toDecimalFr(zs0[i]))
echo("--------------")
for i in 0..<n: echo("i = ",i, " | y[i] = ",toDecimalFr(ys1[i]), " | z[i] = ",toDecimalFr(zs1[i]))
echo("--------------")
for i in 0..<n: echo("i = ",i, " | y[i] = ",toDecimalFr(ys5[i]), " | z[i] = ",toDecimalFr(zs5[i]))
let zeta = intToFr(123457)
let us : seq[Fr] = collect( newSeq, (for i in 0..<n: polyEvalAt(L[i],zeta)) )
let vs : seq[Fr] = collect( newSeq, (for i in 0..<n: evalLagrangePolyAt(D,i,zeta)) )
echo("==============")
for i in 0..<n: echo("i = ",i, " | u[i] = ",toDecimalFr(us[i]), " | v[i] = ",toDecimalFr(vs[i]))
let prefix = "Lagrange basis sanity check = "
if ( ys0===zs0 and ys1===zs1 and ys5===zs5 and
us===vs ):
echo( prefix & "OK")
else:
echo( prefix & "FAILED")
]#
#-------------------------------------------------------------------------------

View File

@ -9,9 +9,9 @@ import constantine/named/properties_fields
import groth16/bn128/fields
import groth16/bn128/curves
import groth16/bn128/rnd
import groth16/bn128/debug
import groth16/bn128/arrays
# import groth16/bn128/rnd
# import groth16/bn128/debug
import groth16/math/domain
import groth16/math/ntt

View File

@ -0,0 +1,38 @@
{.used.}
import std/unittest
import std/sequtils
import std/sugar
import constantine/math/arithmetic
import constantine/named/properties_fields
import groth16/bn128/fields
# import groth16/bn128/rnd
# import groth16/bn128/debug
#-------------------------------------------------------------------------------
suite "field tests":
test "one-half in Fr":
let two = oneFr + oneFr
let invTwo = oneHalfFr
check (oneFr === invTwo * two)
test "sanity check for batch inverse over Fr":
let xs = map( toSeq(101..137) , intToFr )
let ys = batchInverseFr( xs )
let zs = collect( newSeq, (for x in xs: invFr(x)) )
let n = xs.len
# for i in 0..<n: echo(i," | batch = ",toDecimalFr(ys[i])," | ref = ",toDecimalFr(zs[i]) )
var ok: bool = true
for i in 0..<n:
ok = ok and bool(ys[i] == zs[i])
check ok
#-------------------------------------------------------------------------------

108
tests/groth16/testPoly.nim Normal file
View File

@ -0,0 +1,108 @@
{.used.}
import std/unittest
import std/sequtils
import std/sugar
import constantine/math/arithmetic
import constantine/named/properties_fields
import groth16/bn128/fields
import groth16/bn128/arrays
# import groth16/bn128/rnd
import groth16/math/domain
import groth16/math/poly
# import groth16/math/ntt
#-------------------------------------------------------------------------------
type F = Fr[BN254_Snarks]
suite "polynomial tests":
test "sanity check for (division by) vanishing polynomial":
var js : seq[int] = toSeq(101..112)
let cs : seq[F] = map( js, intToFr )
let P : Poly = Poly( coeffs:cs )
let ok1 = polyDegree(P) == 11
let n : int = 5
let QR = polyQuotRemByVanishing(P, n)
let Q = QR.quot
let R = QR.rem
let ok2 = (polyDegree(R) < 5) and (polyDegree(Q) == 11-5)
let Z : Poly = vanishingPoly(n)
let S : Poly = Q * Z + R
let ok3 = polyIsEqual(P,S)
check (ok1 and ok2 and ok3)
#-----------------------------------------------------------------------------
test "sanity check for NTT":
var js : seq[int] = toSeq(101..116)
let cs : seq[F] = map( js, intToFr )
let P : Poly = Poly( coeffs:cs )
let D : Domain = createDomain(16)
let xs : seq[F] = D.enumerateDomain()
let ys : seq[F] = collect( newSeq, (for x in xs: polyEvalAt(P,x)) )
let zs : seq[F] = polyForwardNTT(P ,D)
let Q : Poly = polyInverseNTT(zs,D)
let ok1 = isEqualFrSeq( ys , zs ) # naive evaluations = NTT
let ok2 = isEqualFrSeq( Q.coeffs , cs) # inverse NTT = starting
check (ok1 and ok2)
#-----------------------------------------------------------------------------
test "sanity check for FFT polynomial multiplication":
var js : seq[int] = toSeq(101..110)
let cs : seq[F] = map( js, intToFr )
let P : Poly = Poly( coeffs:cs )
var ks : seq[int] = toSeq(1001..1020)
let ds : seq[F] = map( ks, intToFr )
let Q : Poly = Poly( coeffs:ds )
let R1 : Poly = polyMulNaive( P , Q )
let R2 : Poly = polyMulFFT( P , Q )
# debugPrintFrSeq("naive coeffs", R1.coeffs)
# debugPrintFrSeq("fft coeffs", R2.coeffs)
check polyIsEqual(R1,R2)
#-----------------------------------------------------------------------------
test "sanity check for Lagrange bases":
let n = 8
let D = createDomain(n)
let L : seq[Poly] = collect( newSeq, (for k in 0..<n: lagrangePoly(D,k) ))
let xs = enumerateDomain(D)
let ys0 : seq[F] = collect( newSeq, (for x in xs: polyEvalAt(L[0],x) ))
let ys1 : seq[F] = collect( newSeq, (for x in xs: polyEvalAt(L[1],x) ))
let ys5 : seq[F] = collect( newSeq, (for x in xs: polyEvalAt(L[5],x) ))
let zs0 : seq[F] = collect( newSeq, (for i in 0..<n: deltaFr(0,i) ))
let zs1 : seq[F] = collect( newSeq, (for i in 0..<n: deltaFr(1,i) ))
let zs5 : seq[F] = collect( newSeq, (for i in 0..<n: deltaFr(5,i) ))
let zeta = intToFr(123457)
let us : seq[F] = collect( newSeq, (for i in 0..<n: polyEvalAt(L[i],zeta)) )
let vs : seq[F] = collect( newSeq, (for i in 0..<n: evalLagrangePolyAt(D,i,zeta)) )
check ( ys0===zs0 and ys1===zs1 and ys5===zs5 and us===vs )
#-------------------------------------------------------------------------------

View File

@ -12,7 +12,7 @@ import groth16/bn128/fields
import groth16/bn128/curves
import groth16/bn128/rnd
import groth16/bn128/debug
# import groth16/bn128/debug
#-------------------------------------------------------------------------------
# compression test cases generated by arkworks

View File

@ -1,4 +1,6 @@
import ./groth16/testField
import ./groth16/testPoly
import ./groth16/testFFT
import ./groth16/testPtCompression
import ./groth16/testCurve