mirror of
https://github.com/logos-storage/nim-groth16.git
synced 2026-01-03 22:23:08 +00:00
minor improvements
This commit is contained in:
parent
0ba5af4754
commit
fc317298db
@ -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
|
||||
|
||||
@ -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!")
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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"
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user