diff --git a/groth16/files/container.nim b/groth16/files/container.nim index 887a905..3d11348 100644 --- a/groth16/files/container.nim +++ b/groth16/files/container.nim @@ -94,3 +94,18 @@ proc parseContainer*[T] ( expectedMagic: string #------------------------------------------------------------------------------- +proc writeGlobalHeader*( stream: Stream, magic: string, version: int, nsections: int ) = + write[uint32]( stream , magicWord(magic) ) + write[uint32]( stream , version.uint32 ) + write[uint32]( stream , nsections.uint32 ) + +# WTF seriously... +proc writeBytes*( stream: Stream, data: seq[byte] ) = + stream.writeData( addr(data[0]), data.len ) + +proc writeSection*( stream: Stream, sectionId: int, sectionData: seq[byte] ) = + write[uint32]( stream , sectionId.uint32 ) + write[uint64]( stream , sectionData.len.uint64 ) + writeBytes( stream , sectionData ) + +#------------------------------------------------------------------------------- diff --git a/groth16/files/r1cs.nim b/groth16/files/r1cs.nim index 3f59a17..2adac89 100644 --- a/groth16/files/r1cs.nim +++ b/groth16/files/r1cs.nim @@ -19,11 +19,11 @@ # nPubIn : word32 = number of public inputs # nPrivIn : word32 = number of private inputs # nLabels : word64 = number of labels (variable names in the circom source code) +# nConstr : word32 = number of constraints # # 2: Constraints # -------------- -# nConstr : word32 = number of constraints -# then an array of constraints: +# An array of constraints: # A : LinComb # B : LinComb # C : LinComb @@ -190,3 +190,83 @@ proc parseR1CS* (fname: string): R1CS = return r1cs #------------------------------------------------------------------------------- +# writing R1CS files (required for reordering the rows) + +proc writeWitnessConfig(stream: Stream, cfg: WitnessConfig ) = + write[uint32]( stream , cfg.nWires.uint32 ) # total number of wires (or witness variables) + write[uint32]( stream , cfg.nPubOut.uint32 ) # number of public outputs + write[uint32]( stream , cfg.nPubIn.uint32 ) # number of public inputs + write[uint32]( stream , cfg.nPrivIn.uint32 ) # number of private inputs + write[uint64]( stream , cfg.nLabels.uint32 ) # number of labels + +proc writeR1CSHeader(stream: Stream, r1cs: R1CS ) = + write[uint32]( stream , 32 ) # n8r + write( stream , r1cs.r ) # the value of r + writeWitnessConfig( stream , r1cs.cfg ) # witness config + write[uint32]( stream , r1cs.nConstr.uint32 ) # number of constraints + +proc r1csHeaderSection*(r1cs: R1CS): seq[byte] = + var stream = newStringStream() + stream.writeR1CSHeader(r1cs) + stream.flush() + stream.setPosition(0) + let bytes = cast[seq[byte]](stream.readAll()) # WTF nim + stream.close() + return bytes + +proc r1csWireToLabelSection*(r1cs: R1CS): seq[byte] = + var stream = newStringStream() + for x in r1cs.wireToLabel: + write[uint64]( stream , x.uint64 ) + stream.flush() + stream.setPosition(0) + let bytes = cast[seq[byte]](stream.readAll()) # WTF nim + stream.close() + return bytes + +proc writeFr(stream: Stream, x: Fr[BN254_Snarks]) = + var big : BigInt[254] # fucking constantine + big = x.toBig() + stream.write(big) + +proc writeTerm(stream: Stream, term: Term ) = + write[uint32]( stream , term.wireIdx.uint32 ) + writeFr( stream , term.value ) + +proc writeLinComb(stream: Stream, lc: LinComb ) = + write[uint32]( stream , lc.len.uint32 ) + for term in lc: + writeTerm(stream, term) + +proc writeConstraint(stream: Stream, con: Constraint ) = + writeLinComb( stream, con.A ) + writeLinComb( stream, con.B ) + writeLinComb( stream, con.C ) + +proc r1csConstraintsSection*(r1cs: R1CS): seq[byte] = + var stream = newStringStream() + for c in r1cs.constraints: + writeConstraint( stream, c ) + stream.flush() + stream.setPosition(0) + let bytes = cast[seq[byte]](stream.readAll()) # WTF nim + stream.close() + return bytes + +proc exportR1CS*(fname: string, r1cs: R1CS) = + let section1 = r1csHeaderSection( r1cs) + let section2 = r1csConstraintsSection(r1cs) + let section3 = r1csWireToLabelSection(r1cs) + echo $section1.len + echo $section2.len + echo $section3.len + var stream = newFileStream(fname, fmWrite) + writeGlobalHeader( stream , "r1cs" , 1 , 3 ) + writeSection( stream , 2 , section2 ) + writeSection( stream , 1 , section1 ) + writeSection( stream , 3 , section3 ) + stream.flush() + stream.close() + echo "fuck" + +#------------------------------------------------------------------------------- diff --git a/groth16/math/ntt.nim b/groth16/math/ntt.nim index 7018f02..c3daac3 100644 --- a/groth16/math/ntt.nim +++ b/groth16/math/ntt.nim @@ -3,6 +3,8 @@ # Number-theoretic transform # (that is, FFT for polynomials over finite fields) # +# TODO: flip the order of arguments, so that the domain is first... +# #------------------------------------------------------------------------------- diff --git a/groth16/partial/README.md b/groth16/partial/README.md index ad0ef51..a787806 100644 --- a/groth16/partial/README.md +++ b/groth16/partial/README.md @@ -11,6 +11,6 @@ for more details. This is essentially free (the overhead is minimal, so already when doing 2 proofs with same shared part of the witness, it's worth do it). -A more advanced version, but also with a more heave trade-off, is developed in +A more advanced version, but one which also comes with a heavy trade-off, is developed in [`groth16/dynamic`](../dynamic/).