minor improvements

This commit is contained in:
Balazs Komuves 2024-01-25 13:00:26 +01:00
parent 0ba5af4754
commit fc317298db
No known key found for this signature in database
GPG Key ID: F63B7AEF18435562
4 changed files with 65 additions and 34 deletions

View File

@ -19,12 +19,13 @@ at your choice.
### TODO
- [ ] find and fix the _second_ totally surreal bug
- [ ] clean up the code
- [ ] make it compatible with the latest constantine and also Nim 2.0.x
- [x] make it a nimble package
- [/] refactor `bn128.nim` into smaller files
- [/] proper MSM implementation (at first I couldn't make constantine's one to work)
- [x] compare `.r1cs` to the "coeffs" section of `.zkey`
- [ ] compare `.r1cs` to the "coeffs" section of `.zkey`
- [x] generate fake circuit-specific setup ourselves
- [x] make a CLI interface
- [ ] multithreading support (MSM, and possibly also FFT)
- [ ] add Groth16 notes
- [ ] document the `snarkjs` circuit-specific setup `H` points convention

View File

@ -4,7 +4,7 @@ import std/strutils
import std/sequtils
import std/os
import std/parseopt
import std/[times,os]
import std/times
import std/options
import strformat
@ -26,6 +26,7 @@ proc printHelp() =
echo "available options:"
echo " -h, --help : print this help"
echo " -v, --verbose : verbose output"
echo " -d, --debug : debug output"
echo " -t, --time : print time measurements"
echo " -p, --prove : create a proof"
echo " -y, --verify : verify a proof"
@ -45,6 +46,7 @@ type Config = object
output_file: string
io_file: string
verbose: bool
debug: bool
measure_time: bool
do_prove: bool
do_verify: bool
@ -95,6 +97,7 @@ proc parseCliOptions(): Config =
of "h", "help" : printHelp()
of "v", "verbose" : cfg.verbose = true
of "d", "debug" : cfg.debug = true
of "t", "time" : cfg.measure_time = true
of "p", "prove" : cfg.do_prove = true
of "y", "verify" : cfg.do_verify = true
@ -190,6 +193,10 @@ proc cliMain(cfg: Config) =
let elapsed = cpuTime() - start
if cfg.measure_time: echo("fake setup took ",seconds(elapsed))
if cfg.debug:
printGrothHeader(zkey.header)
# debugPrintCoeffs(zkey.coeffs)
if cfg.do_prove:
if (cfg.wtns_file=="") or (cfg.zkey_file=="" and cfg.do_setup==false):
echo("cannot prove: missing witness and/or zkey file!")

View File

@ -36,32 +36,34 @@ type
curve* : string
#-------------------------------------------------------------------------------
# A, B, C column vectors
# Az, Bz, Cz column vectors
#
type
ABC = object
valuesA : seq[Fr]
valuesB : seq[Fr]
valuesC : seq[Fr]
valuesAz : seq[Fr]
valuesBz : seq[Fr]
valuesCz : seq[Fr]
# computes the vectors A*z, B*z, C*z where z is the witness
func buildABC( zkey: ZKey, witness: seq[Fr] ): ABC =
let hdr: GrothHeader = zkey.header
let domSize = hdr.domainSize
var valuesA : seq[Fr] = newSeq[Fr](domSize)
var valuesB : seq[Fr] = newSeq[Fr](domSize)
var valuesAz : seq[Fr] = newSeq[Fr](domSize)
var valuesBz : seq[Fr] = newSeq[Fr](domSize)
for entry in zkey.coeffs:
case entry.matrix
of MatrixA: valuesA[entry.row] += entry.coeff * witness[entry.col]
of MatrixB: valuesB[entry.row] += entry.coeff * witness[entry.col]
of MatrixA: valuesAz[entry.row] += entry.coeff * witness[entry.col]
of MatrixB: valuesBz[entry.row] += entry.coeff * witness[entry.col]
else: raise newException(AssertionDefect, "fatal error")
var valuesC : seq[Fr] = newSeq[Fr](domSize)
var valuesCz : seq[Fr] = newSeq[Fr](domSize)
for i in 0..<domSize:
valuesC[i] = valuesA[i] * valuesB[i]
valuesCz[i] = valuesAz[i] * valuesBz[i]
return ABC( valuesA:valuesA, valuesB:valuesB, valuesC:valuesC )
return ABC( valuesAz:valuesAz, valuesBz:valuesBz, valuesCz:valuesCz )
#-------------------------------------------------------------------------------
# quotient poly
@ -69,13 +71,13 @@ func buildABC( zkey: ZKey, witness: seq[Fr] ): ABC =
# interpolates A,B,C, and computes the quotient polynomial Q = (A*B - C) / Z
func computeQuotientNaive( abc: ABC ): Poly=
let n = abc.valuesA.len
assert( abc.valuesB.len == n )
assert( abc.valuesC.len == n )
let n = abc.valuesAz.len
assert( abc.valuesBz.len == n )
assert( abc.valuesCz.len == n )
let D = createDomain(n)
let polyA : Poly = polyInverseNTT( abc.valuesA , D )
let polyB : Poly = polyInverseNTT( abc.valuesB , D )
let polyC : Poly = polyInverseNTT( abc.valuesC , D )
let polyA : Poly = polyInverseNTT( abc.valuesAz , D )
let polyB : Poly = polyInverseNTT( abc.valuesBz , D )
let polyC : Poly = polyInverseNTT( abc.valuesCz , D )
let polyBig = polyMulFFT( polyA , polyB ) - polyC
var polyQ = polyDivideByVanishing(polyBig, D.domainSize)
polyQ.coeffs.add( zeroFr ) # make it a power of two
@ -107,9 +109,9 @@ func shiftEvalDomain( values: seq[Fr], D: Domain, eta: Fr ): seq[Fr] =
# by computing the values on a shifted domain, and interpolating the result
# remark: Q has degree `n-2`, so it's enough to use a domain of size n
func computeQuotientPointwise( abc: ABC ): Poly =
let n = abc.valuesA.len
assert( abc.valuesB.len == n )
assert( abc.valuesC.len == n )
let n = abc.valuesAz.len
assert( abc.valuesBz.len == n )
assert( abc.valuesCz.len == n )
let D = createDomain(n)
@ -118,9 +120,9 @@ func computeQuotientPointwise( abc: ABC ): Poly =
let eta = createDomain(2*n).domainGen
let invZ1 = invFr( smallPowFr(eta,n) - oneFr )
let A1 = shiftEvalDomain( abc.valuesA, D, eta )
let B1 = shiftEvalDomain( abc.valuesB, D, eta )
let C1 = shiftEvalDomain( abc.valuesC, D, eta )
let A1 = shiftEvalDomain( abc.valuesAz, D, eta )
let B1 = shiftEvalDomain( abc.valuesBz, D, eta )
let C1 = shiftEvalDomain( abc.valuesCz, D, eta )
var ys : seq[Fr] = newSeq[Fr]( n )
for j in 0..<n: ys[j] = ( A1[j]*B1[j] - C1[j] ) * invZ1
@ -138,14 +140,14 @@ func computeQuotientPointwise( abc: ABC ): Poly =
# see <https://geometry.xyz/notebook/the-hidden-little-secret-in-snarkjs>
#
func computeSnarkjsScalarCoeffs( abc: ABC ): seq[Fr] =
let n = abc.valuesA.len
assert( abc.valuesB.len == n )
assert( abc.valuesC.len == n )
let n = abc.valuesAz.len
assert( abc.valuesBz.len == n )
assert( abc.valuesCz.len == n )
let D = createDomain(n)
let eta = createDomain(2*n).domainGen
let A1 = shiftEvalDomain( abc.valuesA, D, eta )
let B1 = shiftEvalDomain( abc.valuesB, D, eta )
let C1 = shiftEvalDomain( abc.valuesC, D, eta )
let A1 = shiftEvalDomain( abc.valuesAz, D, eta )
let B1 = shiftEvalDomain( abc.valuesBz, D, eta )
let C1 = shiftEvalDomain( abc.valuesCz, D, eta )
var ys : seq[Fr] = newSeq[Fr]( n )
for j in 0..<n: ys[j] = ( A1[j]*B1[j] - C1[j] )
return ys
@ -178,8 +180,9 @@ proc generateProofWithMask*( zkey: ZKey, wtns: Witness, mask: Mask ): Proof =
assert( nvars == witness.len , "wrong witness length" )
# remark: with the special variable "1" we actuall have (npub+1) public IO variables
var pubIO : seq[Fr] = newSeq[Fr]( npubs + 1)
for i in 0..npubs: pubIO[i] = witness[i]
for i in 0..npubs: pubIO[i] = witness[i]
var abc : ABC = buildABC( zkey, witness )
@ -204,6 +207,14 @@ proc generateProofWithMask*( zkey: ZKey, wtns: Witness, mask: Mask ): Proof =
let r = mask.r
let s = mask.s
assert( witness.len == pts.pointsA1.len )
assert( witness.len == pts.pointsB1.len )
assert( witness.len == pts.pointsB2.len )
assert( hdr.domainSize == qs.len )
assert( hdr.domainSize == pts.pointsH1.len )
assert( nvars - npubs - 1 == zs.len )
assert( nvars - npubs - 1 == pts.pointsC1.len )
var pi_a : G1
pi_a = spec.alpha1
pi_a += r ** spec.delta1

View File

@ -74,6 +74,18 @@ func extractVKey*(zkey: Zkey): VKey =
#-------------------------------------------------------------------------------
proc printGrothHeader*(hdr: GrothHeader) =
echo("curve = " & ($hdr.curve ) )
echo("flavour = " & ($hdr.flavour ) )
echo("|Fp| = " & (toDecimalBig(hdr.p)) )
echo("|Fr| = " & (toDecimalBig(hdr.r)) )
echo("nvars = " & ($hdr.nvars ) )
echo("npubs = " & ($hdr.npubs ) )
echo("domainSize = " & ($hdr.domainSize ) )
echo("logDomainSize= " & ($hdr.logDomainSize) )
#-------------------------------------------------------------------------------
func matrixSelToString(sel: MatrixSel): string =
case sel
of MatrixA: return "A"