From 46079a308f4e8303550454187ae7ec4f320614da Mon Sep 17 00:00:00 2001 From: Arya Tabaie Date: Tue, 20 Dec 2022 14:04:33 -0600 Subject: [PATCH 01/71] refactor: no non-mont on bls12-377 --- go.mod | 2 +- go.sum | 2 ++ internal/backend/bls12-377/groth16/prove.go | 16 ++++++------- internal/backend/bls12-377/groth16/setup.go | 24 ++++++++++---------- internal/backend/bls12-377/groth16/verify.go | 2 +- 5 files changed, 23 insertions(+), 23 deletions(-) diff --git a/go.mod b/go.mod index 218f6a1f41..fa0fe8e9b6 100644 --- a/go.mod +++ b/go.mod @@ -5,7 +5,7 @@ go 1.18 require ( github.com/blang/semver/v4 v4.0.0 github.com/consensys/bavard v0.1.13 - github.com/consensys/gnark-crypto v0.8.1-0.20221205155504-6b860ba21fbd + github.com/consensys/gnark-crypto v0.8.1-0.20221220191316-4b7364bddab8 github.com/fxamacker/cbor/v2 v2.2.0 github.com/google/go-cmp v0.5.8 github.com/google/pprof v0.0.0-20220729232143-a41b82acbcb1 diff --git a/go.sum b/go.sum index 477796b8ba..b5683a69d8 100644 --- a/go.sum +++ b/go.sum @@ -4,6 +4,8 @@ github.com/consensys/bavard v0.1.13 h1:oLhMLOFGTLdlda/kma4VOJazblc7IM5y5QPd2A/Yj github.com/consensys/bavard v0.1.13/go.mod h1:9ItSMtA/dXMAiL7BG6bqW2m3NdSEObYWoH223nGHukI= github.com/consensys/gnark-crypto v0.8.1-0.20221205155504-6b860ba21fbd h1:xpAhzOw3dZvRiQeTWmIO8KemBS5XdBsU+/jLfwibEmc= github.com/consensys/gnark-crypto v0.8.1-0.20221205155504-6b860ba21fbd/go.mod h1:CkbdF9hbRidRJYMRzmfX8TMOr95I2pYXRHF18MzRrvA= +github.com/consensys/gnark-crypto v0.8.1-0.20221220191316-4b7364bddab8 h1:Ij6UQpKx4/Ox6L6qFPk8NhEnTsYCEXlILnh+1Hi1grY= +github.com/consensys/gnark-crypto v0.8.1-0.20221220191316-4b7364bddab8/go.mod h1:CkbdF9hbRidRJYMRzmfX8TMOr95I2pYXRHF18MzRrvA= github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= diff --git a/internal/backend/bls12-377/groth16/prove.go b/internal/backend/bls12-377/groth16/prove.go index ac9a6ad2d6..0326cca28b 100644 --- a/internal/backend/bls12-377/groth16/prove.go +++ b/internal/backend/bls12-377/groth16/prove.go @@ -110,12 +110,13 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, witness bls12_377witness.Witness, opt } start := time.Now() + /*wireValuesRegular := make([][fr.Limbs]uint64, len(wireValues)) // set the wire values in regular form utils.Parallelize(len(wireValues), func(start, end int) { for i := start; i < end; i++ { - wireValues[i].FromMont() + wireValuesRegular[i] = wireValues[i].Bits() } - }) + })*/ // H (witness reduction / FFT part) var h []fr.Element @@ -167,11 +168,8 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, witness bls12_377witness.Witness, opt } _kr.Mul(&_r, &_s).Neg(&_kr) - _r.FromMont() - _s.FromMont() - _kr.FromMont() - _r.ToBigInt(&r) - _s.ToBigInt(&s) + _r.BigInt(&r) + _s.BigInt(&s) // computes r[δ], s[δ], kr[δ] deltas := curve.BatchScalarMultiplicationG1(&pk.G1.Delta, []fr.Element{_r, _s, _kr}) @@ -364,11 +362,11 @@ func computeH(a, b, c []fr.Element, domain *fft.Domain) []fr.Element { // ifft_coset domain.FFTInverse(a, fft.DIF, true) - utils.Parallelize(len(a), func(start, end int) { + /*utils.Parallelize(len(a), func(start, end int) { for i := start; i < end; i++ { a[i].FromMont() } - }) + })*/ return a } diff --git a/internal/backend/bls12-377/groth16/setup.go b/internal/backend/bls12-377/groth16/setup.go index c67feab458..e4b34b58ca 100644 --- a/internal/backend/bls12-377/groth16/setup.go +++ b/internal/backend/bls12-377/groth16/setup.go @@ -161,25 +161,25 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { computeK(i, &toxicWaste.gammaInv) if isCommittedPrivate { - ckK[cI] = t1.ToRegular() + ckK[cI] = t1 cI++ } else { - vkK[vI] = t1.ToRegular() + vkK[vI] = t1 vI++ } } else { computeK(i, &toxicWaste.deltaInv) - pkK[i-vI-cI] = t1.ToRegular() + pkK[i-vI-cI] = t1 } } // convert A and B to regular form - for i := 0; i < nbWires; i++ { + /*for i := 0; i < nbWires; i++ { A[i].FromMont() } for i := 0; i < nbWires; i++ { B[i].FromMont() - } + }*/ // Z part of the proving key (scalars) Z := make([]fr.Element, domain.Cardinality) @@ -191,7 +191,7 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { Mul(&zdt, &toxicWaste.deltaInv) // sets Zdt to Zdt/delta for i := 0; i < int(domain.Cardinality); i++ { - Z[i] = zdt.ToRegular() + Z[i] = zdt //.ToRegular() zdt.Mul(&zdt, &toxicWaste.t) } @@ -224,7 +224,7 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { // compute our batch scalar multiplication with g1 elements g1Scalars := make([]fr.Element, 0, (nbWires*3)+int(domain.Cardinality)+3) - g1Scalars = append(g1Scalars, toxicWaste.alphaReg, toxicWaste.betaReg, toxicWaste.deltaReg) + g1Scalars = append(g1Scalars, toxicWaste.alpha, toxicWaste.beta, toxicWaste.delta) g1Scalars = append(g1Scalars, A...) g1Scalars = append(g1Scalars, B...) g1Scalars = append(g1Scalars, Z...) @@ -281,7 +281,7 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { // len(B) == nbWires // compute our batch scalar multiplication with g2 elements - g2Scalars := append(B, toxicWaste.betaReg, toxicWaste.deltaReg, toxicWaste.gammaReg) + g2Scalars := append(B, toxicWaste.beta, toxicWaste.delta, toxicWaste.gamma) g2PointsAff := curve.BatchScalarMultiplicationG2(&g2, g2Scalars) @@ -403,7 +403,7 @@ type toxicWaste struct { gammaInv, deltaInv fr.Element // Non Montgomery form of params - alphaReg, betaReg, gammaReg, deltaReg fr.Element + //alphaReg, betaReg, gammaReg, deltaReg fr.Element } func sampleToxicWaste() (toxicWaste, error) { @@ -439,10 +439,10 @@ func sampleToxicWaste() (toxicWaste, error) { res.gammaInv.Inverse(&res.gamma) res.deltaInv.Inverse(&res.delta) - res.alphaReg = res.alpha.ToRegular() + /*res.alphaReg = res.alpha.ToRegular() res.betaReg = res.beta.ToRegular() res.gammaReg = res.gamma.ToRegular() - res.deltaReg = res.delta.ToRegular() + res.deltaReg = res.delta.ToRegular()*/ return res, nil } @@ -490,7 +490,7 @@ func DummySetup(r1cs *cs.R1CS, pk *ProvingKey) error { var r1Aff curve.G1Affine var b big.Int g1, g2, _, _ := curve.Generators() - r1Jac.ScalarMultiplication(&g1, toxicWaste.alphaReg.ToBigInt(&b)) + r1Jac.ScalarMultiplication(&g1, toxicWaste.alpha.BigInt(&b)) r1Aff.FromJacobian(&r1Jac) var r2Jac curve.G2Jac var r2Aff curve.G2Affine diff --git a/internal/backend/bls12-377/groth16/verify.go b/internal/backend/bls12-377/groth16/verify.go index 2407a6313b..1d452e5eeb 100644 --- a/internal/backend/bls12-377/groth16/verify.go +++ b/internal/backend/bls12-377/groth16/verify.go @@ -82,7 +82,7 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness bls12_377witness.Witne // compute e(Σx.[Kvk(t)]1, -[γ]2) var kSum curve.G1Jac - if _, err := kSum.MultiExp(vk.G1.K[1:], publicWitness, ecc.MultiExpConfig{ScalarsMont: true}); err != nil { + if _, err := kSum.MultiExp(vk.G1.K[1:], publicWitness, ecc.MultiExpConfig{}); err != nil { return err } kSum.AddMixed(&vk.G1.K[0]) From 0ff8bd5c37f77649d683fcc6be89efde163f6aff Mon Sep 17 00:00:00 2001 From: Arya Tabaie Date: Tue, 20 Dec 2022 14:15:20 -0600 Subject: [PATCH 02/71] refactor: groth16 backend tests pass --- internal/backend/bls12-377/groth16/prove.go | 14 --------- internal/backend/bls12-377/groth16/setup.go | 18 +---------- internal/backend/bls12-381/groth16/prove.go | 20 ++----------- internal/backend/bls12-381/groth16/setup.go | 30 +++++-------------- internal/backend/bls12-381/groth16/verify.go | 2 +- internal/backend/bls24-315/groth16/prove.go | 20 ++----------- internal/backend/bls24-315/groth16/setup.go | 30 +++++-------------- internal/backend/bls24-315/groth16/verify.go | 2 +- internal/backend/bls24-317/groth16/prove.go | 20 ++----------- internal/backend/bls24-317/groth16/setup.go | 30 +++++-------------- internal/backend/bls24-317/groth16/verify.go | 2 +- internal/backend/bn254/groth16/prove.go | 20 ++----------- internal/backend/bn254/groth16/setup.go | 30 +++++-------------- internal/backend/bn254/groth16/verify.go | 2 +- internal/backend/bw6-633/groth16/prove.go | 20 ++----------- internal/backend/bw6-633/groth16/setup.go | 30 +++++-------------- internal/backend/bw6-633/groth16/verify.go | 2 +- internal/backend/bw6-761/groth16/prove.go | 20 ++----------- internal/backend/bw6-761/groth16/setup.go | 30 +++++-------------- internal/backend/bw6-761/groth16/verify.go | 2 +- .../zkpschemes/groth16/groth16.prove.go.tmpl | 22 ++------------ .../zkpschemes/groth16/groth16.setup.go.tmpl | 30 +++++-------------- .../zkpschemes/groth16/groth16.verify.go.tmpl | 2 +- 23 files changed, 72 insertions(+), 326 deletions(-) diff --git a/internal/backend/bls12-377/groth16/prove.go b/internal/backend/bls12-377/groth16/prove.go index 0326cca28b..5d52bc5f4b 100644 --- a/internal/backend/bls12-377/groth16/prove.go +++ b/internal/backend/bls12-377/groth16/prove.go @@ -110,14 +110,6 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, witness bls12_377witness.Witness, opt } start := time.Now() - /*wireValuesRegular := make([][fr.Limbs]uint64, len(wireValues)) - // set the wire values in regular form - utils.Parallelize(len(wireValues), func(start, end int) { - for i := start; i < end; i++ { - wireValuesRegular[i] = wireValues[i].Bits() - } - })*/ - // H (witness reduction / FFT part) var h []fr.Element chHDone := make(chan struct{}, 1) @@ -362,11 +354,5 @@ func computeH(a, b, c []fr.Element, domain *fft.Domain) []fr.Element { // ifft_coset domain.FFTInverse(a, fft.DIF, true) - /*utils.Parallelize(len(a), func(start, end int) { - for i := start; i < end; i++ { - a[i].FromMont() - } - })*/ - return a } diff --git a/internal/backend/bls12-377/groth16/setup.go b/internal/backend/bls12-377/groth16/setup.go index e4b34b58ca..8b3beb485e 100644 --- a/internal/backend/bls12-377/groth16/setup.go +++ b/internal/backend/bls12-377/groth16/setup.go @@ -173,14 +173,6 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { } } - // convert A and B to regular form - /*for i := 0; i < nbWires; i++ { - A[i].FromMont() - } - for i := 0; i < nbWires; i++ { - B[i].FromMont() - }*/ - // Z part of the proving key (scalars) Z := make([]fr.Element, domain.Cardinality) one := fr.One() @@ -191,7 +183,7 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { Mul(&zdt, &toxicWaste.deltaInv) // sets Zdt to Zdt/delta for i := 0; i < int(domain.Cardinality); i++ { - Z[i] = zdt //.ToRegular() + Z[i] = zdt zdt.Mul(&zdt, &toxicWaste.t) } @@ -401,9 +393,6 @@ type toxicWaste struct { // Montgomery form of params t, alpha, beta, gamma, delta fr.Element gammaInv, deltaInv fr.Element - - // Non Montgomery form of params - //alphaReg, betaReg, gammaReg, deltaReg fr.Element } func sampleToxicWaste() (toxicWaste, error) { @@ -439,11 +428,6 @@ func sampleToxicWaste() (toxicWaste, error) { res.gammaInv.Inverse(&res.gamma) res.deltaInv.Inverse(&res.delta) - /*res.alphaReg = res.alpha.ToRegular() - res.betaReg = res.beta.ToRegular() - res.gammaReg = res.gamma.ToRegular() - res.deltaReg = res.delta.ToRegular()*/ - return res, nil } diff --git a/internal/backend/bls12-381/groth16/prove.go b/internal/backend/bls12-381/groth16/prove.go index 26b393b74f..1a321533cb 100644 --- a/internal/backend/bls12-381/groth16/prove.go +++ b/internal/backend/bls12-381/groth16/prove.go @@ -110,13 +110,6 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, witness bls12_381witness.Witness, opt } start := time.Now() - // set the wire values in regular form - utils.Parallelize(len(wireValues), func(start, end int) { - for i := start; i < end; i++ { - wireValues[i].FromMont() - } - }) - // H (witness reduction / FFT part) var h []fr.Element chHDone := make(chan struct{}, 1) @@ -167,11 +160,8 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, witness bls12_381witness.Witness, opt } _kr.Mul(&_r, &_s).Neg(&_kr) - _r.FromMont() - _s.FromMont() - _kr.FromMont() - _r.ToBigInt(&r) - _s.ToBigInt(&s) + _r.BigInt(&r) + _s.BigInt(&s) // computes r[δ], s[δ], kr[δ] deltas := curve.BatchScalarMultiplicationG1(&pk.G1.Delta, []fr.Element{_r, _s, _kr}) @@ -364,11 +354,5 @@ func computeH(a, b, c []fr.Element, domain *fft.Domain) []fr.Element { // ifft_coset domain.FFTInverse(a, fft.DIF, true) - utils.Parallelize(len(a), func(start, end int) { - for i := start; i < end; i++ { - a[i].FromMont() - } - }) - return a } diff --git a/internal/backend/bls12-381/groth16/setup.go b/internal/backend/bls12-381/groth16/setup.go index 9f41bb2f3a..f1b05f3cc8 100644 --- a/internal/backend/bls12-381/groth16/setup.go +++ b/internal/backend/bls12-381/groth16/setup.go @@ -161,26 +161,18 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { computeK(i, &toxicWaste.gammaInv) if isCommittedPrivate { - ckK[cI] = t1.ToRegular() + ckK[cI] = t1 cI++ } else { - vkK[vI] = t1.ToRegular() + vkK[vI] = t1 vI++ } } else { computeK(i, &toxicWaste.deltaInv) - pkK[i-vI-cI] = t1.ToRegular() + pkK[i-vI-cI] = t1 } } - // convert A and B to regular form - for i := 0; i < nbWires; i++ { - A[i].FromMont() - } - for i := 0; i < nbWires; i++ { - B[i].FromMont() - } - // Z part of the proving key (scalars) Z := make([]fr.Element, domain.Cardinality) one := fr.One() @@ -191,7 +183,7 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { Mul(&zdt, &toxicWaste.deltaInv) // sets Zdt to Zdt/delta for i := 0; i < int(domain.Cardinality); i++ { - Z[i] = zdt.ToRegular() + Z[i] = zdt zdt.Mul(&zdt, &toxicWaste.t) } @@ -224,7 +216,7 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { // compute our batch scalar multiplication with g1 elements g1Scalars := make([]fr.Element, 0, (nbWires*3)+int(domain.Cardinality)+3) - g1Scalars = append(g1Scalars, toxicWaste.alphaReg, toxicWaste.betaReg, toxicWaste.deltaReg) + g1Scalars = append(g1Scalars, toxicWaste.alpha, toxicWaste.beta, toxicWaste.delta) g1Scalars = append(g1Scalars, A...) g1Scalars = append(g1Scalars, B...) g1Scalars = append(g1Scalars, Z...) @@ -281,7 +273,7 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { // len(B) == nbWires // compute our batch scalar multiplication with g2 elements - g2Scalars := append(B, toxicWaste.betaReg, toxicWaste.deltaReg, toxicWaste.gammaReg) + g2Scalars := append(B, toxicWaste.beta, toxicWaste.delta, toxicWaste.gamma) g2PointsAff := curve.BatchScalarMultiplicationG2(&g2, g2Scalars) @@ -401,9 +393,6 @@ type toxicWaste struct { // Montgomery form of params t, alpha, beta, gamma, delta fr.Element gammaInv, deltaInv fr.Element - - // Non Montgomery form of params - alphaReg, betaReg, gammaReg, deltaReg fr.Element } func sampleToxicWaste() (toxicWaste, error) { @@ -439,11 +428,6 @@ func sampleToxicWaste() (toxicWaste, error) { res.gammaInv.Inverse(&res.gamma) res.deltaInv.Inverse(&res.delta) - res.alphaReg = res.alpha.ToRegular() - res.betaReg = res.beta.ToRegular() - res.gammaReg = res.gamma.ToRegular() - res.deltaReg = res.delta.ToRegular() - return res, nil } @@ -490,7 +474,7 @@ func DummySetup(r1cs *cs.R1CS, pk *ProvingKey) error { var r1Aff curve.G1Affine var b big.Int g1, g2, _, _ := curve.Generators() - r1Jac.ScalarMultiplication(&g1, toxicWaste.alphaReg.ToBigInt(&b)) + r1Jac.ScalarMultiplication(&g1, toxicWaste.alpha.BigInt(&b)) r1Aff.FromJacobian(&r1Jac) var r2Jac curve.G2Jac var r2Aff curve.G2Affine diff --git a/internal/backend/bls12-381/groth16/verify.go b/internal/backend/bls12-381/groth16/verify.go index 2672803d0e..6a7706543d 100644 --- a/internal/backend/bls12-381/groth16/verify.go +++ b/internal/backend/bls12-381/groth16/verify.go @@ -82,7 +82,7 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness bls12_381witness.Witne // compute e(Σx.[Kvk(t)]1, -[γ]2) var kSum curve.G1Jac - if _, err := kSum.MultiExp(vk.G1.K[1:], publicWitness, ecc.MultiExpConfig{ScalarsMont: true}); err != nil { + if _, err := kSum.MultiExp(vk.G1.K[1:], publicWitness, ecc.MultiExpConfig{}); err != nil { return err } kSum.AddMixed(&vk.G1.K[0]) diff --git a/internal/backend/bls24-315/groth16/prove.go b/internal/backend/bls24-315/groth16/prove.go index 2b1c54f6e9..45aacc1d0d 100644 --- a/internal/backend/bls24-315/groth16/prove.go +++ b/internal/backend/bls24-315/groth16/prove.go @@ -110,13 +110,6 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, witness bls24_315witness.Witness, opt } start := time.Now() - // set the wire values in regular form - utils.Parallelize(len(wireValues), func(start, end int) { - for i := start; i < end; i++ { - wireValues[i].FromMont() - } - }) - // H (witness reduction / FFT part) var h []fr.Element chHDone := make(chan struct{}, 1) @@ -167,11 +160,8 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, witness bls24_315witness.Witness, opt } _kr.Mul(&_r, &_s).Neg(&_kr) - _r.FromMont() - _s.FromMont() - _kr.FromMont() - _r.ToBigInt(&r) - _s.ToBigInt(&s) + _r.BigInt(&r) + _s.BigInt(&s) // computes r[δ], s[δ], kr[δ] deltas := curve.BatchScalarMultiplicationG1(&pk.G1.Delta, []fr.Element{_r, _s, _kr}) @@ -364,11 +354,5 @@ func computeH(a, b, c []fr.Element, domain *fft.Domain) []fr.Element { // ifft_coset domain.FFTInverse(a, fft.DIF, true) - utils.Parallelize(len(a), func(start, end int) { - for i := start; i < end; i++ { - a[i].FromMont() - } - }) - return a } diff --git a/internal/backend/bls24-315/groth16/setup.go b/internal/backend/bls24-315/groth16/setup.go index 6d89d9affb..8a80f7f023 100644 --- a/internal/backend/bls24-315/groth16/setup.go +++ b/internal/backend/bls24-315/groth16/setup.go @@ -161,26 +161,18 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { computeK(i, &toxicWaste.gammaInv) if isCommittedPrivate { - ckK[cI] = t1.ToRegular() + ckK[cI] = t1 cI++ } else { - vkK[vI] = t1.ToRegular() + vkK[vI] = t1 vI++ } } else { computeK(i, &toxicWaste.deltaInv) - pkK[i-vI-cI] = t1.ToRegular() + pkK[i-vI-cI] = t1 } } - // convert A and B to regular form - for i := 0; i < nbWires; i++ { - A[i].FromMont() - } - for i := 0; i < nbWires; i++ { - B[i].FromMont() - } - // Z part of the proving key (scalars) Z := make([]fr.Element, domain.Cardinality) one := fr.One() @@ -191,7 +183,7 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { Mul(&zdt, &toxicWaste.deltaInv) // sets Zdt to Zdt/delta for i := 0; i < int(domain.Cardinality); i++ { - Z[i] = zdt.ToRegular() + Z[i] = zdt zdt.Mul(&zdt, &toxicWaste.t) } @@ -224,7 +216,7 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { // compute our batch scalar multiplication with g1 elements g1Scalars := make([]fr.Element, 0, (nbWires*3)+int(domain.Cardinality)+3) - g1Scalars = append(g1Scalars, toxicWaste.alphaReg, toxicWaste.betaReg, toxicWaste.deltaReg) + g1Scalars = append(g1Scalars, toxicWaste.alpha, toxicWaste.beta, toxicWaste.delta) g1Scalars = append(g1Scalars, A...) g1Scalars = append(g1Scalars, B...) g1Scalars = append(g1Scalars, Z...) @@ -281,7 +273,7 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { // len(B) == nbWires // compute our batch scalar multiplication with g2 elements - g2Scalars := append(B, toxicWaste.betaReg, toxicWaste.deltaReg, toxicWaste.gammaReg) + g2Scalars := append(B, toxicWaste.beta, toxicWaste.delta, toxicWaste.gamma) g2PointsAff := curve.BatchScalarMultiplicationG2(&g2, g2Scalars) @@ -401,9 +393,6 @@ type toxicWaste struct { // Montgomery form of params t, alpha, beta, gamma, delta fr.Element gammaInv, deltaInv fr.Element - - // Non Montgomery form of params - alphaReg, betaReg, gammaReg, deltaReg fr.Element } func sampleToxicWaste() (toxicWaste, error) { @@ -439,11 +428,6 @@ func sampleToxicWaste() (toxicWaste, error) { res.gammaInv.Inverse(&res.gamma) res.deltaInv.Inverse(&res.delta) - res.alphaReg = res.alpha.ToRegular() - res.betaReg = res.beta.ToRegular() - res.gammaReg = res.gamma.ToRegular() - res.deltaReg = res.delta.ToRegular() - return res, nil } @@ -490,7 +474,7 @@ func DummySetup(r1cs *cs.R1CS, pk *ProvingKey) error { var r1Aff curve.G1Affine var b big.Int g1, g2, _, _ := curve.Generators() - r1Jac.ScalarMultiplication(&g1, toxicWaste.alphaReg.ToBigInt(&b)) + r1Jac.ScalarMultiplication(&g1, toxicWaste.alpha.BigInt(&b)) r1Aff.FromJacobian(&r1Jac) var r2Jac curve.G2Jac var r2Aff curve.G2Affine diff --git a/internal/backend/bls24-315/groth16/verify.go b/internal/backend/bls24-315/groth16/verify.go index a199b02a84..cf6a91a30e 100644 --- a/internal/backend/bls24-315/groth16/verify.go +++ b/internal/backend/bls24-315/groth16/verify.go @@ -82,7 +82,7 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness bls24_315witness.Witne // compute e(Σx.[Kvk(t)]1, -[γ]2) var kSum curve.G1Jac - if _, err := kSum.MultiExp(vk.G1.K[1:], publicWitness, ecc.MultiExpConfig{ScalarsMont: true}); err != nil { + if _, err := kSum.MultiExp(vk.G1.K[1:], publicWitness, ecc.MultiExpConfig{}); err != nil { return err } kSum.AddMixed(&vk.G1.K[0]) diff --git a/internal/backend/bls24-317/groth16/prove.go b/internal/backend/bls24-317/groth16/prove.go index 3c665a16c5..78f9e7727c 100644 --- a/internal/backend/bls24-317/groth16/prove.go +++ b/internal/backend/bls24-317/groth16/prove.go @@ -110,13 +110,6 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, witness bls24_317witness.Witness, opt } start := time.Now() - // set the wire values in regular form - utils.Parallelize(len(wireValues), func(start, end int) { - for i := start; i < end; i++ { - wireValues[i].FromMont() - } - }) - // H (witness reduction / FFT part) var h []fr.Element chHDone := make(chan struct{}, 1) @@ -167,11 +160,8 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, witness bls24_317witness.Witness, opt } _kr.Mul(&_r, &_s).Neg(&_kr) - _r.FromMont() - _s.FromMont() - _kr.FromMont() - _r.ToBigInt(&r) - _s.ToBigInt(&s) + _r.BigInt(&r) + _s.BigInt(&s) // computes r[δ], s[δ], kr[δ] deltas := curve.BatchScalarMultiplicationG1(&pk.G1.Delta, []fr.Element{_r, _s, _kr}) @@ -364,11 +354,5 @@ func computeH(a, b, c []fr.Element, domain *fft.Domain) []fr.Element { // ifft_coset domain.FFTInverse(a, fft.DIF, true) - utils.Parallelize(len(a), func(start, end int) { - for i := start; i < end; i++ { - a[i].FromMont() - } - }) - return a } diff --git a/internal/backend/bls24-317/groth16/setup.go b/internal/backend/bls24-317/groth16/setup.go index db5559dc39..c49e1718ea 100644 --- a/internal/backend/bls24-317/groth16/setup.go +++ b/internal/backend/bls24-317/groth16/setup.go @@ -161,26 +161,18 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { computeK(i, &toxicWaste.gammaInv) if isCommittedPrivate { - ckK[cI] = t1.ToRegular() + ckK[cI] = t1 cI++ } else { - vkK[vI] = t1.ToRegular() + vkK[vI] = t1 vI++ } } else { computeK(i, &toxicWaste.deltaInv) - pkK[i-vI-cI] = t1.ToRegular() + pkK[i-vI-cI] = t1 } } - // convert A and B to regular form - for i := 0; i < nbWires; i++ { - A[i].FromMont() - } - for i := 0; i < nbWires; i++ { - B[i].FromMont() - } - // Z part of the proving key (scalars) Z := make([]fr.Element, domain.Cardinality) one := fr.One() @@ -191,7 +183,7 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { Mul(&zdt, &toxicWaste.deltaInv) // sets Zdt to Zdt/delta for i := 0; i < int(domain.Cardinality); i++ { - Z[i] = zdt.ToRegular() + Z[i] = zdt zdt.Mul(&zdt, &toxicWaste.t) } @@ -224,7 +216,7 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { // compute our batch scalar multiplication with g1 elements g1Scalars := make([]fr.Element, 0, (nbWires*3)+int(domain.Cardinality)+3) - g1Scalars = append(g1Scalars, toxicWaste.alphaReg, toxicWaste.betaReg, toxicWaste.deltaReg) + g1Scalars = append(g1Scalars, toxicWaste.alpha, toxicWaste.beta, toxicWaste.delta) g1Scalars = append(g1Scalars, A...) g1Scalars = append(g1Scalars, B...) g1Scalars = append(g1Scalars, Z...) @@ -281,7 +273,7 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { // len(B) == nbWires // compute our batch scalar multiplication with g2 elements - g2Scalars := append(B, toxicWaste.betaReg, toxicWaste.deltaReg, toxicWaste.gammaReg) + g2Scalars := append(B, toxicWaste.beta, toxicWaste.delta, toxicWaste.gamma) g2PointsAff := curve.BatchScalarMultiplicationG2(&g2, g2Scalars) @@ -401,9 +393,6 @@ type toxicWaste struct { // Montgomery form of params t, alpha, beta, gamma, delta fr.Element gammaInv, deltaInv fr.Element - - // Non Montgomery form of params - alphaReg, betaReg, gammaReg, deltaReg fr.Element } func sampleToxicWaste() (toxicWaste, error) { @@ -439,11 +428,6 @@ func sampleToxicWaste() (toxicWaste, error) { res.gammaInv.Inverse(&res.gamma) res.deltaInv.Inverse(&res.delta) - res.alphaReg = res.alpha.ToRegular() - res.betaReg = res.beta.ToRegular() - res.gammaReg = res.gamma.ToRegular() - res.deltaReg = res.delta.ToRegular() - return res, nil } @@ -490,7 +474,7 @@ func DummySetup(r1cs *cs.R1CS, pk *ProvingKey) error { var r1Aff curve.G1Affine var b big.Int g1, g2, _, _ := curve.Generators() - r1Jac.ScalarMultiplication(&g1, toxicWaste.alphaReg.ToBigInt(&b)) + r1Jac.ScalarMultiplication(&g1, toxicWaste.alpha.BigInt(&b)) r1Aff.FromJacobian(&r1Jac) var r2Jac curve.G2Jac var r2Aff curve.G2Affine diff --git a/internal/backend/bls24-317/groth16/verify.go b/internal/backend/bls24-317/groth16/verify.go index f742834a29..4a20f54647 100644 --- a/internal/backend/bls24-317/groth16/verify.go +++ b/internal/backend/bls24-317/groth16/verify.go @@ -82,7 +82,7 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness bls24_317witness.Witne // compute e(Σx.[Kvk(t)]1, -[γ]2) var kSum curve.G1Jac - if _, err := kSum.MultiExp(vk.G1.K[1:], publicWitness, ecc.MultiExpConfig{ScalarsMont: true}); err != nil { + if _, err := kSum.MultiExp(vk.G1.K[1:], publicWitness, ecc.MultiExpConfig{}); err != nil { return err } kSum.AddMixed(&vk.G1.K[0]) diff --git a/internal/backend/bn254/groth16/prove.go b/internal/backend/bn254/groth16/prove.go index 42032df8c8..f36022eaa7 100644 --- a/internal/backend/bn254/groth16/prove.go +++ b/internal/backend/bn254/groth16/prove.go @@ -110,13 +110,6 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, witness bn254witness.Witness, opt back } start := time.Now() - // set the wire values in regular form - utils.Parallelize(len(wireValues), func(start, end int) { - for i := start; i < end; i++ { - wireValues[i].FromMont() - } - }) - // H (witness reduction / FFT part) var h []fr.Element chHDone := make(chan struct{}, 1) @@ -167,11 +160,8 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, witness bn254witness.Witness, opt back } _kr.Mul(&_r, &_s).Neg(&_kr) - _r.FromMont() - _s.FromMont() - _kr.FromMont() - _r.ToBigInt(&r) - _s.ToBigInt(&s) + _r.BigInt(&r) + _s.BigInt(&s) // computes r[δ], s[δ], kr[δ] deltas := curve.BatchScalarMultiplicationG1(&pk.G1.Delta, []fr.Element{_r, _s, _kr}) @@ -364,11 +354,5 @@ func computeH(a, b, c []fr.Element, domain *fft.Domain) []fr.Element { // ifft_coset domain.FFTInverse(a, fft.DIF, true) - utils.Parallelize(len(a), func(start, end int) { - for i := start; i < end; i++ { - a[i].FromMont() - } - }) - return a } diff --git a/internal/backend/bn254/groth16/setup.go b/internal/backend/bn254/groth16/setup.go index 97f128f102..e13869bbcb 100644 --- a/internal/backend/bn254/groth16/setup.go +++ b/internal/backend/bn254/groth16/setup.go @@ -161,26 +161,18 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { computeK(i, &toxicWaste.gammaInv) if isCommittedPrivate { - ckK[cI] = t1.ToRegular() + ckK[cI] = t1 cI++ } else { - vkK[vI] = t1.ToRegular() + vkK[vI] = t1 vI++ } } else { computeK(i, &toxicWaste.deltaInv) - pkK[i-vI-cI] = t1.ToRegular() + pkK[i-vI-cI] = t1 } } - // convert A and B to regular form - for i := 0; i < nbWires; i++ { - A[i].FromMont() - } - for i := 0; i < nbWires; i++ { - B[i].FromMont() - } - // Z part of the proving key (scalars) Z := make([]fr.Element, domain.Cardinality) one := fr.One() @@ -191,7 +183,7 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { Mul(&zdt, &toxicWaste.deltaInv) // sets Zdt to Zdt/delta for i := 0; i < int(domain.Cardinality); i++ { - Z[i] = zdt.ToRegular() + Z[i] = zdt zdt.Mul(&zdt, &toxicWaste.t) } @@ -224,7 +216,7 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { // compute our batch scalar multiplication with g1 elements g1Scalars := make([]fr.Element, 0, (nbWires*3)+int(domain.Cardinality)+3) - g1Scalars = append(g1Scalars, toxicWaste.alphaReg, toxicWaste.betaReg, toxicWaste.deltaReg) + g1Scalars = append(g1Scalars, toxicWaste.alpha, toxicWaste.beta, toxicWaste.delta) g1Scalars = append(g1Scalars, A...) g1Scalars = append(g1Scalars, B...) g1Scalars = append(g1Scalars, Z...) @@ -281,7 +273,7 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { // len(B) == nbWires // compute our batch scalar multiplication with g2 elements - g2Scalars := append(B, toxicWaste.betaReg, toxicWaste.deltaReg, toxicWaste.gammaReg) + g2Scalars := append(B, toxicWaste.beta, toxicWaste.delta, toxicWaste.gamma) g2PointsAff := curve.BatchScalarMultiplicationG2(&g2, g2Scalars) @@ -401,9 +393,6 @@ type toxicWaste struct { // Montgomery form of params t, alpha, beta, gamma, delta fr.Element gammaInv, deltaInv fr.Element - - // Non Montgomery form of params - alphaReg, betaReg, gammaReg, deltaReg fr.Element } func sampleToxicWaste() (toxicWaste, error) { @@ -439,11 +428,6 @@ func sampleToxicWaste() (toxicWaste, error) { res.gammaInv.Inverse(&res.gamma) res.deltaInv.Inverse(&res.delta) - res.alphaReg = res.alpha.ToRegular() - res.betaReg = res.beta.ToRegular() - res.gammaReg = res.gamma.ToRegular() - res.deltaReg = res.delta.ToRegular() - return res, nil } @@ -490,7 +474,7 @@ func DummySetup(r1cs *cs.R1CS, pk *ProvingKey) error { var r1Aff curve.G1Affine var b big.Int g1, g2, _, _ := curve.Generators() - r1Jac.ScalarMultiplication(&g1, toxicWaste.alphaReg.ToBigInt(&b)) + r1Jac.ScalarMultiplication(&g1, toxicWaste.alpha.BigInt(&b)) r1Aff.FromJacobian(&r1Jac) var r2Jac curve.G2Jac var r2Aff curve.G2Affine diff --git a/internal/backend/bn254/groth16/verify.go b/internal/backend/bn254/groth16/verify.go index 6018d45ac5..1f9328caf0 100644 --- a/internal/backend/bn254/groth16/verify.go +++ b/internal/backend/bn254/groth16/verify.go @@ -83,7 +83,7 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness bn254witness.Witness) // compute e(Σx.[Kvk(t)]1, -[γ]2) var kSum curve.G1Jac - if _, err := kSum.MultiExp(vk.G1.K[1:], publicWitness, ecc.MultiExpConfig{ScalarsMont: true}); err != nil { + if _, err := kSum.MultiExp(vk.G1.K[1:], publicWitness, ecc.MultiExpConfig{}); err != nil { return err } kSum.AddMixed(&vk.G1.K[0]) diff --git a/internal/backend/bw6-633/groth16/prove.go b/internal/backend/bw6-633/groth16/prove.go index caecec7243..a20240c03d 100644 --- a/internal/backend/bw6-633/groth16/prove.go +++ b/internal/backend/bw6-633/groth16/prove.go @@ -110,13 +110,6 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, witness bw6_633witness.Witness, opt ba } start := time.Now() - // set the wire values in regular form - utils.Parallelize(len(wireValues), func(start, end int) { - for i := start; i < end; i++ { - wireValues[i].FromMont() - } - }) - // H (witness reduction / FFT part) var h []fr.Element chHDone := make(chan struct{}, 1) @@ -167,11 +160,8 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, witness bw6_633witness.Witness, opt ba } _kr.Mul(&_r, &_s).Neg(&_kr) - _r.FromMont() - _s.FromMont() - _kr.FromMont() - _r.ToBigInt(&r) - _s.ToBigInt(&s) + _r.BigInt(&r) + _s.BigInt(&s) // computes r[δ], s[δ], kr[δ] deltas := curve.BatchScalarMultiplicationG1(&pk.G1.Delta, []fr.Element{_r, _s, _kr}) @@ -364,11 +354,5 @@ func computeH(a, b, c []fr.Element, domain *fft.Domain) []fr.Element { // ifft_coset domain.FFTInverse(a, fft.DIF, true) - utils.Parallelize(len(a), func(start, end int) { - for i := start; i < end; i++ { - a[i].FromMont() - } - }) - return a } diff --git a/internal/backend/bw6-633/groth16/setup.go b/internal/backend/bw6-633/groth16/setup.go index 4debf9e355..d6777090eb 100644 --- a/internal/backend/bw6-633/groth16/setup.go +++ b/internal/backend/bw6-633/groth16/setup.go @@ -161,26 +161,18 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { computeK(i, &toxicWaste.gammaInv) if isCommittedPrivate { - ckK[cI] = t1.ToRegular() + ckK[cI] = t1 cI++ } else { - vkK[vI] = t1.ToRegular() + vkK[vI] = t1 vI++ } } else { computeK(i, &toxicWaste.deltaInv) - pkK[i-vI-cI] = t1.ToRegular() + pkK[i-vI-cI] = t1 } } - // convert A and B to regular form - for i := 0; i < nbWires; i++ { - A[i].FromMont() - } - for i := 0; i < nbWires; i++ { - B[i].FromMont() - } - // Z part of the proving key (scalars) Z := make([]fr.Element, domain.Cardinality) one := fr.One() @@ -191,7 +183,7 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { Mul(&zdt, &toxicWaste.deltaInv) // sets Zdt to Zdt/delta for i := 0; i < int(domain.Cardinality); i++ { - Z[i] = zdt.ToRegular() + Z[i] = zdt zdt.Mul(&zdt, &toxicWaste.t) } @@ -224,7 +216,7 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { // compute our batch scalar multiplication with g1 elements g1Scalars := make([]fr.Element, 0, (nbWires*3)+int(domain.Cardinality)+3) - g1Scalars = append(g1Scalars, toxicWaste.alphaReg, toxicWaste.betaReg, toxicWaste.deltaReg) + g1Scalars = append(g1Scalars, toxicWaste.alpha, toxicWaste.beta, toxicWaste.delta) g1Scalars = append(g1Scalars, A...) g1Scalars = append(g1Scalars, B...) g1Scalars = append(g1Scalars, Z...) @@ -281,7 +273,7 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { // len(B) == nbWires // compute our batch scalar multiplication with g2 elements - g2Scalars := append(B, toxicWaste.betaReg, toxicWaste.deltaReg, toxicWaste.gammaReg) + g2Scalars := append(B, toxicWaste.beta, toxicWaste.delta, toxicWaste.gamma) g2PointsAff := curve.BatchScalarMultiplicationG2(&g2, g2Scalars) @@ -401,9 +393,6 @@ type toxicWaste struct { // Montgomery form of params t, alpha, beta, gamma, delta fr.Element gammaInv, deltaInv fr.Element - - // Non Montgomery form of params - alphaReg, betaReg, gammaReg, deltaReg fr.Element } func sampleToxicWaste() (toxicWaste, error) { @@ -439,11 +428,6 @@ func sampleToxicWaste() (toxicWaste, error) { res.gammaInv.Inverse(&res.gamma) res.deltaInv.Inverse(&res.delta) - res.alphaReg = res.alpha.ToRegular() - res.betaReg = res.beta.ToRegular() - res.gammaReg = res.gamma.ToRegular() - res.deltaReg = res.delta.ToRegular() - return res, nil } @@ -490,7 +474,7 @@ func DummySetup(r1cs *cs.R1CS, pk *ProvingKey) error { var r1Aff curve.G1Affine var b big.Int g1, g2, _, _ := curve.Generators() - r1Jac.ScalarMultiplication(&g1, toxicWaste.alphaReg.ToBigInt(&b)) + r1Jac.ScalarMultiplication(&g1, toxicWaste.alpha.BigInt(&b)) r1Aff.FromJacobian(&r1Jac) var r2Jac curve.G2Jac var r2Aff curve.G2Affine diff --git a/internal/backend/bw6-633/groth16/verify.go b/internal/backend/bw6-633/groth16/verify.go index 460cf1736d..d8200d6981 100644 --- a/internal/backend/bw6-633/groth16/verify.go +++ b/internal/backend/bw6-633/groth16/verify.go @@ -82,7 +82,7 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness bw6_633witness.Witness // compute e(Σx.[Kvk(t)]1, -[γ]2) var kSum curve.G1Jac - if _, err := kSum.MultiExp(vk.G1.K[1:], publicWitness, ecc.MultiExpConfig{ScalarsMont: true}); err != nil { + if _, err := kSum.MultiExp(vk.G1.K[1:], publicWitness, ecc.MultiExpConfig{}); err != nil { return err } kSum.AddMixed(&vk.G1.K[0]) diff --git a/internal/backend/bw6-761/groth16/prove.go b/internal/backend/bw6-761/groth16/prove.go index f1943122dc..bb00b69ca4 100644 --- a/internal/backend/bw6-761/groth16/prove.go +++ b/internal/backend/bw6-761/groth16/prove.go @@ -110,13 +110,6 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, witness bw6_761witness.Witness, opt ba } start := time.Now() - // set the wire values in regular form - utils.Parallelize(len(wireValues), func(start, end int) { - for i := start; i < end; i++ { - wireValues[i].FromMont() - } - }) - // H (witness reduction / FFT part) var h []fr.Element chHDone := make(chan struct{}, 1) @@ -167,11 +160,8 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, witness bw6_761witness.Witness, opt ba } _kr.Mul(&_r, &_s).Neg(&_kr) - _r.FromMont() - _s.FromMont() - _kr.FromMont() - _r.ToBigInt(&r) - _s.ToBigInt(&s) + _r.BigInt(&r) + _s.BigInt(&s) // computes r[δ], s[δ], kr[δ] deltas := curve.BatchScalarMultiplicationG1(&pk.G1.Delta, []fr.Element{_r, _s, _kr}) @@ -364,11 +354,5 @@ func computeH(a, b, c []fr.Element, domain *fft.Domain) []fr.Element { // ifft_coset domain.FFTInverse(a, fft.DIF, true) - utils.Parallelize(len(a), func(start, end int) { - for i := start; i < end; i++ { - a[i].FromMont() - } - }) - return a } diff --git a/internal/backend/bw6-761/groth16/setup.go b/internal/backend/bw6-761/groth16/setup.go index 89b3044f54..c0616ff53a 100644 --- a/internal/backend/bw6-761/groth16/setup.go +++ b/internal/backend/bw6-761/groth16/setup.go @@ -161,26 +161,18 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { computeK(i, &toxicWaste.gammaInv) if isCommittedPrivate { - ckK[cI] = t1.ToRegular() + ckK[cI] = t1 cI++ } else { - vkK[vI] = t1.ToRegular() + vkK[vI] = t1 vI++ } } else { computeK(i, &toxicWaste.deltaInv) - pkK[i-vI-cI] = t1.ToRegular() + pkK[i-vI-cI] = t1 } } - // convert A and B to regular form - for i := 0; i < nbWires; i++ { - A[i].FromMont() - } - for i := 0; i < nbWires; i++ { - B[i].FromMont() - } - // Z part of the proving key (scalars) Z := make([]fr.Element, domain.Cardinality) one := fr.One() @@ -191,7 +183,7 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { Mul(&zdt, &toxicWaste.deltaInv) // sets Zdt to Zdt/delta for i := 0; i < int(domain.Cardinality); i++ { - Z[i] = zdt.ToRegular() + Z[i] = zdt zdt.Mul(&zdt, &toxicWaste.t) } @@ -224,7 +216,7 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { // compute our batch scalar multiplication with g1 elements g1Scalars := make([]fr.Element, 0, (nbWires*3)+int(domain.Cardinality)+3) - g1Scalars = append(g1Scalars, toxicWaste.alphaReg, toxicWaste.betaReg, toxicWaste.deltaReg) + g1Scalars = append(g1Scalars, toxicWaste.alpha, toxicWaste.beta, toxicWaste.delta) g1Scalars = append(g1Scalars, A...) g1Scalars = append(g1Scalars, B...) g1Scalars = append(g1Scalars, Z...) @@ -281,7 +273,7 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { // len(B) == nbWires // compute our batch scalar multiplication with g2 elements - g2Scalars := append(B, toxicWaste.betaReg, toxicWaste.deltaReg, toxicWaste.gammaReg) + g2Scalars := append(B, toxicWaste.beta, toxicWaste.delta, toxicWaste.gamma) g2PointsAff := curve.BatchScalarMultiplicationG2(&g2, g2Scalars) @@ -401,9 +393,6 @@ type toxicWaste struct { // Montgomery form of params t, alpha, beta, gamma, delta fr.Element gammaInv, deltaInv fr.Element - - // Non Montgomery form of params - alphaReg, betaReg, gammaReg, deltaReg fr.Element } func sampleToxicWaste() (toxicWaste, error) { @@ -439,11 +428,6 @@ func sampleToxicWaste() (toxicWaste, error) { res.gammaInv.Inverse(&res.gamma) res.deltaInv.Inverse(&res.delta) - res.alphaReg = res.alpha.ToRegular() - res.betaReg = res.beta.ToRegular() - res.gammaReg = res.gamma.ToRegular() - res.deltaReg = res.delta.ToRegular() - return res, nil } @@ -490,7 +474,7 @@ func DummySetup(r1cs *cs.R1CS, pk *ProvingKey) error { var r1Aff curve.G1Affine var b big.Int g1, g2, _, _ := curve.Generators() - r1Jac.ScalarMultiplication(&g1, toxicWaste.alphaReg.ToBigInt(&b)) + r1Jac.ScalarMultiplication(&g1, toxicWaste.alpha.BigInt(&b)) r1Aff.FromJacobian(&r1Jac) var r2Jac curve.G2Jac var r2Aff curve.G2Affine diff --git a/internal/backend/bw6-761/groth16/verify.go b/internal/backend/bw6-761/groth16/verify.go index 821b9167fa..c2c100b4dc 100644 --- a/internal/backend/bw6-761/groth16/verify.go +++ b/internal/backend/bw6-761/groth16/verify.go @@ -82,7 +82,7 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness bw6_761witness.Witness // compute e(Σx.[Kvk(t)]1, -[γ]2) var kSum curve.G1Jac - if _, err := kSum.MultiExp(vk.G1.K[1:], publicWitness, ecc.MultiExpConfig{ScalarsMont: true}); err != nil { + if _, err := kSum.MultiExp(vk.G1.K[1:], publicWitness, ecc.MultiExpConfig{}); err != nil { return err } kSum.AddMixed(&vk.G1.K[0]) diff --git a/internal/generator/backend/template/zkpschemes/groth16/groth16.prove.go.tmpl b/internal/generator/backend/template/zkpschemes/groth16/groth16.prove.go.tmpl index 61f466a2cc..5ec88fc1c4 100644 --- a/internal/generator/backend/template/zkpschemes/groth16/groth16.prove.go.tmpl +++ b/internal/generator/backend/template/zkpschemes/groth16/groth16.prove.go.tmpl @@ -91,14 +91,7 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, witness {{ toLower .CurveID }}witness. } } } - start := time.Now() - - // set the wire values in regular form - utils.Parallelize(len(wireValues), func(start, end int) { - for i := start; i < end; i++ { - wireValues[i].FromMont() - } - }) + start := time.Now() // H (witness reduction / FFT part) var h []fr.Element @@ -150,11 +143,8 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, witness {{ toLower .CurveID }}witness. } _kr.Mul(&_r, &_s).Neg(&_kr) - _r.FromMont() - _s.FromMont() - _kr.FromMont() - _r.ToBigInt(&r) - _s.ToBigInt(&s) + _r.BigInt(&r) + _s.BigInt(&s) // computes r[δ], s[δ], kr[δ] deltas := curve.BatchScalarMultiplicationG1(&pk.G1.Delta, []fr.Element{_r, _s, _kr}) @@ -347,11 +337,5 @@ func computeH(a, b, c []fr.Element, domain *fft.Domain) []fr.Element { // ifft_coset domain.FFTInverse(a, fft.DIF, true) - utils.Parallelize(len(a), func(start, end int) { - for i := start; i < end; i++ { - a[i].FromMont() - } - }) - return a } \ No newline at end of file diff --git a/internal/generator/backend/template/zkpschemes/groth16/groth16.setup.go.tmpl b/internal/generator/backend/template/zkpschemes/groth16/groth16.setup.go.tmpl index d106ec0df4..1c7ca7dbbb 100644 --- a/internal/generator/backend/template/zkpschemes/groth16/groth16.setup.go.tmpl +++ b/internal/generator/backend/template/zkpschemes/groth16/groth16.setup.go.tmpl @@ -143,26 +143,18 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { computeK(i, &toxicWaste.gammaInv) if isCommittedPrivate { - ckK[cI] = t1.ToRegular() + ckK[cI] = t1 cI++ } else { - vkK[vI] = t1.ToRegular() + vkK[vI] = t1 vI++ } } else { computeK(i, &toxicWaste.deltaInv) - pkK[i-vI-cI] = t1.ToRegular() + pkK[i-vI-cI] = t1 } } - // convert A and B to regular form - for i := 0; i < nbWires; i++ { - A[i].FromMont() - } - for i := 0; i < nbWires; i++ { - B[i].FromMont() - } - // Z part of the proving key (scalars) Z := make([]fr.Element, domain.Cardinality) one := fr.One() @@ -173,7 +165,7 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { Mul(&zdt, &toxicWaste.deltaInv) // sets Zdt to Zdt/delta for i := 0; i < int(domain.Cardinality); i++ { - Z[i] = zdt.ToRegular() + Z[i] = zdt zdt.Mul(&zdt, &toxicWaste.t) } @@ -206,7 +198,7 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { // compute our batch scalar multiplication with g1 elements g1Scalars := make([]fr.Element, 0, (nbWires*3)+int(domain.Cardinality)+3) - g1Scalars = append(g1Scalars, toxicWaste.alphaReg, toxicWaste.betaReg, toxicWaste.deltaReg) + g1Scalars = append(g1Scalars, toxicWaste.alpha, toxicWaste.beta, toxicWaste.delta) g1Scalars = append(g1Scalars, A...) g1Scalars = append(g1Scalars, B...) g1Scalars = append(g1Scalars, Z...) @@ -263,7 +255,7 @@ func Setup(r1cs *cs.R1CS, pk *ProvingKey, vk *VerifyingKey) error { // len(B) == nbWires // compute our batch scalar multiplication with g2 elements - g2Scalars := append(B, toxicWaste.betaReg, toxicWaste.deltaReg, toxicWaste.gammaReg) + g2Scalars := append(B, toxicWaste.beta, toxicWaste.delta, toxicWaste.gamma) g2PointsAff := curve.BatchScalarMultiplicationG2(&g2, g2Scalars) @@ -383,9 +375,6 @@ type toxicWaste struct { // Montgomery form of params t, alpha, beta, gamma, delta fr.Element gammaInv, deltaInv fr.Element - - // Non Montgomery form of params - alphaReg, betaReg, gammaReg, deltaReg fr.Element } func sampleToxicWaste() (toxicWaste, error) { @@ -421,11 +410,6 @@ func sampleToxicWaste() (toxicWaste, error) { res.gammaInv.Inverse(&res.gamma) res.deltaInv.Inverse(&res.delta) - res.alphaReg = res.alpha.ToRegular() - res.betaReg = res.beta.ToRegular() - res.gammaReg = res.gamma.ToRegular() - res.deltaReg = res.delta.ToRegular() - return res, nil } @@ -472,7 +456,7 @@ func DummySetup(r1cs *cs.R1CS, pk *ProvingKey) error { var r1Aff curve.G1Affine var b big.Int g1, g2, _, _ := curve.Generators() - r1Jac.ScalarMultiplication(&g1, toxicWaste.alphaReg.ToBigInt(&b)) + r1Jac.ScalarMultiplication(&g1, toxicWaste.alpha.BigInt(&b)) r1Aff.FromJacobian(&r1Jac) var r2Jac curve.G2Jac var r2Aff curve.G2Affine diff --git a/internal/generator/backend/template/zkpschemes/groth16/groth16.verify.go.tmpl b/internal/generator/backend/template/zkpschemes/groth16/groth16.verify.go.tmpl index 378e22e792..ce8d718bc1 100644 --- a/internal/generator/backend/template/zkpschemes/groth16/groth16.verify.go.tmpl +++ b/internal/generator/backend/template/zkpschemes/groth16/groth16.verify.go.tmpl @@ -67,7 +67,7 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness {{ toLower .CurveID}}w // compute e(Σx.[Kvk(t)]1, -[γ]2) var kSum curve.G1Jac - if _, err := kSum.MultiExp(vk.G1.K[1:], publicWitness, ecc.MultiExpConfig{ScalarsMont:true}); err != nil { + if _, err := kSum.MultiExp(vk.G1.K[1:], publicWitness, ecc.MultiExpConfig{}); err != nil { return err } kSum.AddMixed(&vk.G1.K[0]) From f515c8cbce21814d26b07571b578735315a3336d Mon Sep 17 00:00:00 2001 From: Arya Tabaie Date: Tue, 20 Dec 2022 14:43:27 -0600 Subject: [PATCH 03/71] refactor: MSM takes Montgomery only - Plonk --- internal/backend/bls12-377/plonk/verify.go | 2 +- internal/backend/bls12-381/plonk/verify.go | 2 +- internal/backend/bls24-315/plonk/verify.go | 2 +- internal/backend/bls24-317/plonk/verify.go | 2 +- internal/backend/bn254/plonk/verify.go | 2 +- internal/backend/bw6-633/plonk/verify.go | 2 +- internal/backend/bw6-761/plonk/verify.go | 2 +- .../backend/template/zkpschemes/plonk/plonk.verify.go.tmpl | 2 +- 8 files changed, 8 insertions(+), 8 deletions(-) diff --git a/internal/backend/bls12-377/plonk/verify.go b/internal/backend/bls12-377/plonk/verify.go index 36719cc1f2..404a635da9 100644 --- a/internal/backend/bls12-377/plonk/verify.go +++ b/internal/backend/bls12-377/plonk/verify.go @@ -202,7 +202,7 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness bls12_377witness.Witne l, r, rl, o, one, // first part _s1, _s2, // second & third part } - if _, err := linearizedPolynomialDigest.MultiExp(points, scalars, ecc.MultiExpConfig{ScalarsMont: true}); err != nil { + if _, err := linearizedPolynomialDigest.MultiExp(points, scalars, ecc.MultiExpConfig{}); err != nil { return err } diff --git a/internal/backend/bls12-381/plonk/verify.go b/internal/backend/bls12-381/plonk/verify.go index a1289d5caa..9c1da50193 100644 --- a/internal/backend/bls12-381/plonk/verify.go +++ b/internal/backend/bls12-381/plonk/verify.go @@ -202,7 +202,7 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness bls12_381witness.Witne l, r, rl, o, one, // first part _s1, _s2, // second & third part } - if _, err := linearizedPolynomialDigest.MultiExp(points, scalars, ecc.MultiExpConfig{ScalarsMont: true}); err != nil { + if _, err := linearizedPolynomialDigest.MultiExp(points, scalars, ecc.MultiExpConfig{}); err != nil { return err } diff --git a/internal/backend/bls24-315/plonk/verify.go b/internal/backend/bls24-315/plonk/verify.go index b182368f93..621010dd4e 100644 --- a/internal/backend/bls24-315/plonk/verify.go +++ b/internal/backend/bls24-315/plonk/verify.go @@ -202,7 +202,7 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness bls24_315witness.Witne l, r, rl, o, one, // first part _s1, _s2, // second & third part } - if _, err := linearizedPolynomialDigest.MultiExp(points, scalars, ecc.MultiExpConfig{ScalarsMont: true}); err != nil { + if _, err := linearizedPolynomialDigest.MultiExp(points, scalars, ecc.MultiExpConfig{}); err != nil { return err } diff --git a/internal/backend/bls24-317/plonk/verify.go b/internal/backend/bls24-317/plonk/verify.go index 24faf644e1..ad619939a3 100644 --- a/internal/backend/bls24-317/plonk/verify.go +++ b/internal/backend/bls24-317/plonk/verify.go @@ -202,7 +202,7 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness bls24_317witness.Witne l, r, rl, o, one, // first part _s1, _s2, // second & third part } - if _, err := linearizedPolynomialDigest.MultiExp(points, scalars, ecc.MultiExpConfig{ScalarsMont: true}); err != nil { + if _, err := linearizedPolynomialDigest.MultiExp(points, scalars, ecc.MultiExpConfig{}); err != nil { return err } diff --git a/internal/backend/bn254/plonk/verify.go b/internal/backend/bn254/plonk/verify.go index ca3a2fba03..103e1f30ec 100644 --- a/internal/backend/bn254/plonk/verify.go +++ b/internal/backend/bn254/plonk/verify.go @@ -204,7 +204,7 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness bn254witness.Witness) l, r, rl, o, one, // first part _s1, _s2, // second & third part } - if _, err := linearizedPolynomialDigest.MultiExp(points, scalars, ecc.MultiExpConfig{ScalarsMont: true}); err != nil { + if _, err := linearizedPolynomialDigest.MultiExp(points, scalars, ecc.MultiExpConfig{}); err != nil { return err } diff --git a/internal/backend/bw6-633/plonk/verify.go b/internal/backend/bw6-633/plonk/verify.go index 42c339db32..127c0506df 100644 --- a/internal/backend/bw6-633/plonk/verify.go +++ b/internal/backend/bw6-633/plonk/verify.go @@ -202,7 +202,7 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness bw6_633witness.Witness l, r, rl, o, one, // first part _s1, _s2, // second & third part } - if _, err := linearizedPolynomialDigest.MultiExp(points, scalars, ecc.MultiExpConfig{ScalarsMont: true}); err != nil { + if _, err := linearizedPolynomialDigest.MultiExp(points, scalars, ecc.MultiExpConfig{}); err != nil { return err } diff --git a/internal/backend/bw6-761/plonk/verify.go b/internal/backend/bw6-761/plonk/verify.go index ae74c7f2fd..eca3443894 100644 --- a/internal/backend/bw6-761/plonk/verify.go +++ b/internal/backend/bw6-761/plonk/verify.go @@ -202,7 +202,7 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness bw6_761witness.Witness l, r, rl, o, one, // first part _s1, _s2, // second & third part } - if _, err := linearizedPolynomialDigest.MultiExp(points, scalars, ecc.MultiExpConfig{ScalarsMont: true}); err != nil { + if _, err := linearizedPolynomialDigest.MultiExp(points, scalars, ecc.MultiExpConfig{}); err != nil { return err } diff --git a/internal/generator/backend/template/zkpschemes/plonk/plonk.verify.go.tmpl b/internal/generator/backend/template/zkpschemes/plonk/plonk.verify.go.tmpl index d57f5c0977..25452331de 100644 --- a/internal/generator/backend/template/zkpschemes/plonk/plonk.verify.go.tmpl +++ b/internal/generator/backend/template/zkpschemes/plonk/plonk.verify.go.tmpl @@ -182,7 +182,7 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness {{ toLower .CurveID }} l, r, rl, o, one, // first part _s1, _s2, // second & third part } - if _, err := linearizedPolynomialDigest.MultiExp(points, scalars, ecc.MultiExpConfig{ScalarsMont: true}); err != nil { + if _, err := linearizedPolynomialDigest.MultiExp(points, scalars, ecc.MultiExpConfig{}); err != nil { return err } From 401993c181b5c825d8f02eaa71251a739a9a8a8d Mon Sep 17 00:00:00 2001 From: Arya Tabaie Date: Tue, 20 Dec 2022 14:59:33 -0600 Subject: [PATCH 04/71] fix:`ToBigIntRegular` => `BigInt` --- .../template/representations/coeff.go.tmpl | 2 +- .../template/representations/solution.go.tmpl | 2 +- .../zkpschemes/groth16/groth16.prove.go.tmpl | 2 +- .../zkpschemes/groth16/groth16.verify.go.tmpl | 2 +- .../zkpschemes/plonk/plonk.prove.go.tmpl | 2 +- .../zkpschemes/plonk/plonk.verify.go.tmpl | 2 +- std/algebra/sw_bls12377/pairing_test.go | 4 +- std/algebra/sw_bls24315/g1_test.go | 8 +- std/algebra/sw_bls24315/pairing_test.go | 4 +- std/algebra/twistededwards/twistededwards.go | 80 +++++++++---------- 10 files changed, 54 insertions(+), 54 deletions(-) diff --git a/internal/generator/backend/template/representations/coeff.go.tmpl b/internal/generator/backend/template/representations/coeff.go.tmpl index 56ddffccc7..ca3e47dfca 100644 --- a/internal/generator/backend/template/representations/coeff.go.tmpl +++ b/internal/generator/backend/template/representations/coeff.go.tmpl @@ -93,7 +93,7 @@ func (engine *arithEngine) FromInterface(i interface{}) constraint.Coeff { func (engine *arithEngine) ToBigInt(c *constraint.Coeff) *big.Int { e := (*fr.Element)(c[:]) r := new(big.Int) - e.ToBigIntRegular(r) + e.BigInt(r) return r } diff --git a/internal/generator/backend/template/representations/solution.go.tmpl b/internal/generator/backend/template/representations/solution.go.tmpl index 1d262cc214..ff4ef0842d 100644 --- a/internal/generator/backend/template/representations/solution.go.tmpl +++ b/internal/generator/backend/template/representations/solution.go.tmpl @@ -172,7 +172,7 @@ func (s *solution) solveWithHint(vID int, h *constraint.Hint) error { } s.accumulateInto(term, &v) } - v.ToBigIntRegular(inputs[i]) + v.BigInt(inputs[i]) } diff --git a/internal/generator/backend/template/zkpschemes/groth16/groth16.prove.go.tmpl b/internal/generator/backend/template/zkpschemes/groth16/groth16.prove.go.tmpl index 5ec88fc1c4..b6915ed590 100644 --- a/internal/generator/backend/template/zkpschemes/groth16/groth16.prove.go.tmpl +++ b/internal/generator/backend/template/zkpschemes/groth16/groth16.prove.go.tmpl @@ -71,7 +71,7 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, witness {{ toLower .CurveID }}witness. var res fr.Element res, err = solveCommitmentWire(&r1cs.CommitmentInfo, &proof.Commitment, in[:r1cs.CommitmentInfo.NbPublicCommitted()]) - res.ToBigIntRegular(out[0]) //Perf-TODO: Regular (non-mont) hashToField to obviate this conversion? + res.BigInt(out[0]) //Perf-TODO: Regular (non-mont) hashToField to obviate this conversion? return err } } diff --git a/internal/generator/backend/template/zkpschemes/groth16/groth16.verify.go.tmpl b/internal/generator/backend/template/zkpschemes/groth16/groth16.verify.go.tmpl index ce8d718bc1..e2b5ae6f34 100644 --- a/internal/generator/backend/template/zkpschemes/groth16/groth16.verify.go.tmpl +++ b/internal/generator/backend/template/zkpschemes/groth16/groth16.verify.go.tmpl @@ -56,7 +56,7 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness {{ toLower .CurveID}}w publicCommitted := make([]*big.Int, vk.CommitmentInfo.NbPublicCommitted()) for i := range publicCommitted { var b big.Int - publicWitness[vk.CommitmentInfo.Committed[i]-1].ToBigIntRegular(&b) + publicWitness[vk.CommitmentInfo.Committed[i]-1].BigInt(&b) publicCommitted[i] = &b } diff --git a/internal/generator/backend/template/zkpschemes/plonk/plonk.prove.go.tmpl b/internal/generator/backend/template/zkpschemes/plonk/plonk.prove.go.tmpl index a153f943bc..3dd97520db 100644 --- a/internal/generator/backend/template/zkpschemes/plonk/plonk.prove.go.tmpl +++ b/internal/generator/backend/template/zkpschemes/plonk/plonk.prove.go.tmpl @@ -300,7 +300,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness {{ toLower .CurveID } bSize.SetUint64(pk.Domain[0].Cardinality + 2) // +2 because of the masking (h of degree 3(n+2)-1) var zetaPowerm fr.Element zetaPowerm.Exp(zeta, &bSize) - zetaPowerm.ToBigIntRegular(&bZetaPowerm) + zetaPowerm.BigInt(&bZetaPowerm) foldedHDigest := proof.H[2] foldedHDigest.ScalarMultiplication(&foldedHDigest, &bZetaPowerm) foldedHDigest.Add(&foldedHDigest, &proof.H[1]) // ζᵐ⁺²*Comm(h3) diff --git a/internal/generator/backend/template/zkpschemes/plonk/plonk.verify.go.tmpl b/internal/generator/backend/template/zkpschemes/plonk/plonk.verify.go.tmpl index 25452331de..9b96e671c3 100644 --- a/internal/generator/backend/template/zkpschemes/plonk/plonk.verify.go.tmpl +++ b/internal/generator/backend/template/zkpschemes/plonk/plonk.verify.go.tmpl @@ -138,7 +138,7 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness {{ toLower .CurveID }} var zetaMPlusTwo fr.Element zetaMPlusTwo.Exp(zeta, mPlusTwo) var zetaMPlusTwoBigInt big.Int - zetaMPlusTwo.ToBigIntRegular(&zetaMPlusTwoBigInt) + zetaMPlusTwo.BigInt(&zetaMPlusTwoBigInt) foldedH := proof.H[2] foldedH.ScalarMultiplication(&foldedH, &zetaMPlusTwoBigInt) foldedH.Add(&foldedH, &proof.H[1]) diff --git a/std/algebra/sw_bls12377/pairing_test.go b/std/algebra/sw_bls12377/pairing_test.go index b16e3617b3..bf09b6efad 100644 --- a/std/algebra/sw_bls12377/pairing_test.go +++ b/std/algebra/sw_bls12377/pairing_test.go @@ -141,8 +141,8 @@ func triplePairingData() (P [3]bls12377.G1Affine, Q [3]bls12377.G2Affine, pairin for i := 1; i < 3; i++ { _, _ = u.SetRandom() _, _ = v.SetRandom() - u.ToBigIntRegular(&_u) - v.ToBigIntRegular(&_v) + u.BigInt(&_u) + v.BigInt(&_v) P[i].ScalarMultiplication(&P[0], &_u) Q[i].ScalarMultiplication(&Q[0], &_v) } diff --git a/std/algebra/sw_bls24315/g1_test.go b/std/algebra/sw_bls24315/g1_test.go index 82d385e59d..86feeeb571 100644 --- a/std/algebra/sw_bls24315/g1_test.go +++ b/std/algebra/sw_bls24315/g1_test.go @@ -281,7 +281,7 @@ func TestConstantScalarMulG1(t *testing.T) { witness.A.Assign(&a) // compute the result br := new(big.Int) - r.ToBigIntRegular(br) + r.BigInt(br) // br is a circuit parameter circuit.R = br _a.ScalarMultiplication(&_a, br) @@ -321,7 +321,7 @@ func TestVarScalarMulG1(t *testing.T) { witness.A.Assign(&a) // compute the result var br big.Int - _a.ScalarMultiplication(&_a, r.ToBigIntRegular(&br)) + _a.ScalarMultiplication(&_a, r.BigInt(&br)) c.FromJacobian(&_a) witness.C.Assign(&c) @@ -361,7 +361,7 @@ func TestScalarMulG1(t *testing.T) { witness.A.Assign(&a) // compute the result var br big.Int - _a.ScalarMultiplication(&_a, r.ToBigIntRegular(&br)) + _a.ScalarMultiplication(&_a, r.BigInt(&br)) c.FromJacobian(&_a) witness.C.Assign(&c) @@ -376,7 +376,7 @@ func randomPointG1() bls24315.G1Jac { var r1 fr.Element var b big.Int _, _ = r1.SetRandom() - p1.ScalarMultiplication(&p1, r1.ToBigIntRegular(&b)) + p1.ScalarMultiplication(&p1, r1.BigInt(&b)) return p1 } diff --git a/std/algebra/sw_bls24315/pairing_test.go b/std/algebra/sw_bls24315/pairing_test.go index f8d78b2384..c7bb53b4a5 100644 --- a/std/algebra/sw_bls24315/pairing_test.go +++ b/std/algebra/sw_bls24315/pairing_test.go @@ -142,8 +142,8 @@ func triplePairingData() (P [3]bls24315.G1Affine, Q [3]bls24315.G2Affine, pairin for i := 1; i < 3; i++ { _, _ = u.SetRandom() _, _ = v.SetRandom() - u.ToBigIntRegular(&_u) - v.ToBigIntRegular(&_v) + u.BigInt(&_u) + v.BigInt(&_v) P[i].ScalarMultiplication(&P[0], &_u) Q[i].ScalarMultiplication(&Q[0], &_v) } diff --git a/std/algebra/twistededwards/twistededwards.go b/std/algebra/twistededwards/twistededwards.go index 9f93e53bfa..20c0de3aba 100644 --- a/std/algebra/twistededwards/twistededwards.go +++ b/std/algebra/twistededwards/twistededwards.go @@ -158,12 +158,12 @@ func newEdBN254() *CurveParams { edcurve := edbn254.GetEdwardsCurve() r := newCurveParams() - edcurve.A.ToBigIntRegular(r.A) - edcurve.D.ToBigIntRegular(r.D) - edcurve.Cofactor.ToBigIntRegular(r.Cofactor) + edcurve.A.BigInt(r.A) + edcurve.D.BigInt(r.D) + edcurve.Cofactor.BigInt(r.Cofactor) r.Order.Set(&edcurve.Order) - edcurve.Base.X.ToBigIntRegular(r.Base[0]) - edcurve.Base.Y.ToBigIntRegular(r.Base[1]) + edcurve.Base.X.BigInt(r.Base[0]) + edcurve.Base.Y.BigInt(r.Base[1]) return r } @@ -173,12 +173,12 @@ func newEdBLS12_381() *CurveParams { edcurve := edbls12381.GetEdwardsCurve() r := newCurveParams() - edcurve.A.ToBigIntRegular(r.A) - edcurve.D.ToBigIntRegular(r.D) - edcurve.Cofactor.ToBigIntRegular(r.Cofactor) + edcurve.A.BigInt(r.A) + edcurve.D.BigInt(r.D) + edcurve.Cofactor.BigInt(r.Cofactor) r.Order.Set(&edcurve.Order) - edcurve.Base.X.ToBigIntRegular(r.Base[0]) - edcurve.Base.Y.ToBigIntRegular(r.Base[1]) + edcurve.Base.X.BigInt(r.Base[0]) + edcurve.Base.Y.BigInt(r.Base[1]) return r } @@ -188,12 +188,12 @@ func newEdBLS12_381_BANDERSNATCH() *CurveParams { edcurve := edbls12381_bandersnatch.GetEdwardsCurve() r := newCurveParams() - edcurve.A.ToBigIntRegular(r.A) - edcurve.D.ToBigIntRegular(r.D) - edcurve.Cofactor.ToBigIntRegular(r.Cofactor) + edcurve.A.BigInt(r.A) + edcurve.D.BigInt(r.D) + edcurve.Cofactor.BigInt(r.Cofactor) r.Order.Set(&edcurve.Order) - edcurve.Base.X.ToBigIntRegular(r.Base[0]) - edcurve.Base.Y.ToBigIntRegular(r.Base[1]) + edcurve.Base.X.BigInt(r.Base[0]) + edcurve.Base.Y.BigInt(r.Base[1]) return r } @@ -203,12 +203,12 @@ func newEdBLS12_377() *CurveParams { edcurve := edbls12377.GetEdwardsCurve() r := newCurveParams() - edcurve.A.ToBigIntRegular(r.A) - edcurve.D.ToBigIntRegular(r.D) - edcurve.Cofactor.ToBigIntRegular(r.Cofactor) + edcurve.A.BigInt(r.A) + edcurve.D.BigInt(r.D) + edcurve.Cofactor.BigInt(r.Cofactor) r.Order.Set(&edcurve.Order) - edcurve.Base.X.ToBigIntRegular(r.Base[0]) - edcurve.Base.Y.ToBigIntRegular(r.Base[1]) + edcurve.Base.X.BigInt(r.Base[0]) + edcurve.Base.Y.BigInt(r.Base[1]) return r } @@ -218,12 +218,12 @@ func newEdBW6_633() *CurveParams { edcurve := edbw6633.GetEdwardsCurve() r := newCurveParams() - edcurve.A.ToBigIntRegular(r.A) - edcurve.D.ToBigIntRegular(r.D) - edcurve.Cofactor.ToBigIntRegular(r.Cofactor) + edcurve.A.BigInt(r.A) + edcurve.D.BigInt(r.D) + edcurve.Cofactor.BigInt(r.Cofactor) r.Order.Set(&edcurve.Order) - edcurve.Base.X.ToBigIntRegular(r.Base[0]) - edcurve.Base.Y.ToBigIntRegular(r.Base[1]) + edcurve.Base.X.BigInt(r.Base[0]) + edcurve.Base.Y.BigInt(r.Base[1]) return r } @@ -233,12 +233,12 @@ func newEdBW6_761() *CurveParams { edcurve := edbw6761.GetEdwardsCurve() r := newCurveParams() - edcurve.A.ToBigIntRegular(r.A) - edcurve.D.ToBigIntRegular(r.D) - edcurve.Cofactor.ToBigIntRegular(r.Cofactor) + edcurve.A.BigInt(r.A) + edcurve.D.BigInt(r.D) + edcurve.Cofactor.BigInt(r.Cofactor) r.Order.Set(&edcurve.Order) - edcurve.Base.X.ToBigIntRegular(r.Base[0]) - edcurve.Base.Y.ToBigIntRegular(r.Base[1]) + edcurve.Base.X.BigInt(r.Base[0]) + edcurve.Base.Y.BigInt(r.Base[1]) return r } @@ -248,12 +248,12 @@ func newEdBLS24_317() *CurveParams { edcurve := edbls24317.GetEdwardsCurve() r := newCurveParams() - edcurve.A.ToBigIntRegular(r.A) - edcurve.D.ToBigIntRegular(r.D) - edcurve.Cofactor.ToBigIntRegular(r.Cofactor) + edcurve.A.BigInt(r.A) + edcurve.D.BigInt(r.D) + edcurve.Cofactor.BigInt(r.Cofactor) r.Order.Set(&edcurve.Order) - edcurve.Base.X.ToBigIntRegular(r.Base[0]) - edcurve.Base.Y.ToBigIntRegular(r.Base[1]) + edcurve.Base.X.BigInt(r.Base[0]) + edcurve.Base.Y.BigInt(r.Base[1]) return r } @@ -263,12 +263,12 @@ func newEdBLS24_315() *CurveParams { edcurve := edbls24315.GetEdwardsCurve() r := newCurveParams() - edcurve.A.ToBigIntRegular(r.A) - edcurve.D.ToBigIntRegular(r.D) - edcurve.Cofactor.ToBigIntRegular(r.Cofactor) + edcurve.A.BigInt(r.A) + edcurve.D.BigInt(r.D) + edcurve.Cofactor.BigInt(r.Cofactor) r.Order.Set(&edcurve.Order) - edcurve.Base.X.ToBigIntRegular(r.Base[0]) - edcurve.Base.Y.ToBigIntRegular(r.Base[1]) + edcurve.Base.X.BigInt(r.Base[0]) + edcurve.Base.Y.BigInt(r.Base[1]) return r } From 5d56b7ad262114ba120e4e923ae0fb76ecc39059 Mon Sep 17 00:00:00 2001 From: Arya Tabaie Date: Tue, 20 Dec 2022 15:03:35 -0600 Subject: [PATCH 05/71] fix: more `ToBigIntRegular` => `BigInt` --- constraint/bls12-377/coeff.go | 2 +- constraint/bls12-377/solution.go | 2 +- constraint/bls12-381/coeff.go | 2 +- constraint/bls12-381/solution.go | 2 +- constraint/bls24-315/coeff.go | 2 +- constraint/bls24-315/solution.go | 2 +- constraint/bls24-317/coeff.go | 2 +- constraint/bls24-317/solution.go | 2 +- constraint/bn254/coeff.go | 2 +- constraint/bn254/solution.go | 2 +- constraint/bw6-633/coeff.go | 2 +- constraint/bw6-633/solution.go | 2 +- constraint/bw6-761/coeff.go | 2 +- constraint/bw6-761/solution.go | 2 +- constraint/tinyfield/coeff.go | 2 +- constraint/tinyfield/solution.go | 2 +- examples/rollup/operator.go | 4 +- internal/backend/bls12-377/groth16/prove.go | 2 +- internal/backend/bls12-377/groth16/verify.go | 2 +- internal/backend/bls12-377/plonk/prove.go | 2 +- internal/backend/bls12-377/plonk/verify.go | 2 +- internal/backend/bls12-381/groth16/prove.go | 2 +- internal/backend/bls12-381/groth16/verify.go | 2 +- internal/backend/bls12-381/plonk/prove.go | 2 +- internal/backend/bls12-381/plonk/verify.go | 2 +- internal/backend/bls24-315/groth16/prove.go | 2 +- internal/backend/bls24-315/groth16/verify.go | 2 +- internal/backend/bls24-315/plonk/prove.go | 2 +- internal/backend/bls24-315/plonk/verify.go | 2 +- internal/backend/bls24-317/groth16/prove.go | 2 +- internal/backend/bls24-317/groth16/verify.go | 2 +- internal/backend/bls24-317/plonk/prove.go | 2 +- internal/backend/bls24-317/plonk/verify.go | 2 +- internal/backend/bn254/groth16/prove.go | 2 +- internal/backend/bn254/groth16/verify.go | 2 +- internal/backend/bn254/plonk/prove.go | 2 +- internal/backend/bn254/plonk/verify.go | 2 +- internal/backend/bw6-633/groth16/prove.go | 2 +- internal/backend/bw6-633/groth16/verify.go | 2 +- internal/backend/bw6-633/plonk/prove.go | 2 +- internal/backend/bw6-633/plonk/verify.go | 2 +- internal/backend/bw6-761/groth16/prove.go | 2 +- internal/backend/bw6-761/groth16/verify.go | 2 +- internal/backend/bw6-761/plonk/prove.go | 2 +- internal/backend/bw6-761/plonk/verify.go | 2 +- internal/tinyfield/element.go | 4 +- internal/tinyfield/element_test.go | 42 ++++----- std/algebra/fields_bls12377/e12.go | 50 +++++----- std/algebra/fields_bls12377/e2.go | 8 +- std/algebra/fields_bls12377/e6.go | 24 ++--- std/algebra/fields_bls24315/e12.go | 48 +++++----- std/algebra/fields_bls24315/e2.go | 8 +- std/algebra/fields_bls24315/e24.go | 98 ++++++++++---------- std/algebra/fields_bls24315/e4.go | 16 ++-- std/algebra/sw_bls12377/g1_test.go | 8 +- std/algebra/sw_bls12377/g2_test.go | 8 +- std/algebra/sw_bls24315/g2_test.go | 8 +- 57 files changed, 207 insertions(+), 207 deletions(-) diff --git a/constraint/bls12-377/coeff.go b/constraint/bls12-377/coeff.go index facfe7b96f..f602e1845a 100644 --- a/constraint/bls12-377/coeff.go +++ b/constraint/bls12-377/coeff.go @@ -108,7 +108,7 @@ func (engine *arithEngine) FromInterface(i interface{}) constraint.Coeff { func (engine *arithEngine) ToBigInt(c *constraint.Coeff) *big.Int { e := (*fr.Element)(c[:]) r := new(big.Int) - e.ToBigIntRegular(r) + e.BigInt(r) return r } diff --git a/constraint/bls12-377/solution.go b/constraint/bls12-377/solution.go index 08fd188b34..1ff8f07fb4 100644 --- a/constraint/bls12-377/solution.go +++ b/constraint/bls12-377/solution.go @@ -191,7 +191,7 @@ func (s *solution) solveWithHint(vID int, h *constraint.Hint) error { } s.accumulateInto(term, &v) } - v.ToBigIntRegular(inputs[i]) + v.BigInt(inputs[i]) } err := f(q, inputs, outputs) diff --git a/constraint/bls12-381/coeff.go b/constraint/bls12-381/coeff.go index 683e6fd869..762d1e5b00 100644 --- a/constraint/bls12-381/coeff.go +++ b/constraint/bls12-381/coeff.go @@ -108,7 +108,7 @@ func (engine *arithEngine) FromInterface(i interface{}) constraint.Coeff { func (engine *arithEngine) ToBigInt(c *constraint.Coeff) *big.Int { e := (*fr.Element)(c[:]) r := new(big.Int) - e.ToBigIntRegular(r) + e.BigInt(r) return r } diff --git a/constraint/bls12-381/solution.go b/constraint/bls12-381/solution.go index 9dc5ca7450..2924e1b28d 100644 --- a/constraint/bls12-381/solution.go +++ b/constraint/bls12-381/solution.go @@ -191,7 +191,7 @@ func (s *solution) solveWithHint(vID int, h *constraint.Hint) error { } s.accumulateInto(term, &v) } - v.ToBigIntRegular(inputs[i]) + v.BigInt(inputs[i]) } err := f(q, inputs, outputs) diff --git a/constraint/bls24-315/coeff.go b/constraint/bls24-315/coeff.go index c2bbf9898b..0c0242c9ef 100644 --- a/constraint/bls24-315/coeff.go +++ b/constraint/bls24-315/coeff.go @@ -108,7 +108,7 @@ func (engine *arithEngine) FromInterface(i interface{}) constraint.Coeff { func (engine *arithEngine) ToBigInt(c *constraint.Coeff) *big.Int { e := (*fr.Element)(c[:]) r := new(big.Int) - e.ToBigIntRegular(r) + e.BigInt(r) return r } diff --git a/constraint/bls24-315/solution.go b/constraint/bls24-315/solution.go index 0cab97252f..b19b3d0211 100644 --- a/constraint/bls24-315/solution.go +++ b/constraint/bls24-315/solution.go @@ -191,7 +191,7 @@ func (s *solution) solveWithHint(vID int, h *constraint.Hint) error { } s.accumulateInto(term, &v) } - v.ToBigIntRegular(inputs[i]) + v.BigInt(inputs[i]) } err := f(q, inputs, outputs) diff --git a/constraint/bls24-317/coeff.go b/constraint/bls24-317/coeff.go index 1e380539ed..1fbe8c9f47 100644 --- a/constraint/bls24-317/coeff.go +++ b/constraint/bls24-317/coeff.go @@ -108,7 +108,7 @@ func (engine *arithEngine) FromInterface(i interface{}) constraint.Coeff { func (engine *arithEngine) ToBigInt(c *constraint.Coeff) *big.Int { e := (*fr.Element)(c[:]) r := new(big.Int) - e.ToBigIntRegular(r) + e.BigInt(r) return r } diff --git a/constraint/bls24-317/solution.go b/constraint/bls24-317/solution.go index 6dfd404832..1f00341ae8 100644 --- a/constraint/bls24-317/solution.go +++ b/constraint/bls24-317/solution.go @@ -191,7 +191,7 @@ func (s *solution) solveWithHint(vID int, h *constraint.Hint) error { } s.accumulateInto(term, &v) } - v.ToBigIntRegular(inputs[i]) + v.BigInt(inputs[i]) } err := f(q, inputs, outputs) diff --git a/constraint/bn254/coeff.go b/constraint/bn254/coeff.go index 8327df511a..9ac0f66610 100644 --- a/constraint/bn254/coeff.go +++ b/constraint/bn254/coeff.go @@ -108,7 +108,7 @@ func (engine *arithEngine) FromInterface(i interface{}) constraint.Coeff { func (engine *arithEngine) ToBigInt(c *constraint.Coeff) *big.Int { e := (*fr.Element)(c[:]) r := new(big.Int) - e.ToBigIntRegular(r) + e.BigInt(r) return r } diff --git a/constraint/bn254/solution.go b/constraint/bn254/solution.go index 316a386f12..e9c69b49c3 100644 --- a/constraint/bn254/solution.go +++ b/constraint/bn254/solution.go @@ -191,7 +191,7 @@ func (s *solution) solveWithHint(vID int, h *constraint.Hint) error { } s.accumulateInto(term, &v) } - v.ToBigIntRegular(inputs[i]) + v.BigInt(inputs[i]) } err := f(q, inputs, outputs) diff --git a/constraint/bw6-633/coeff.go b/constraint/bw6-633/coeff.go index 42c94edc65..1020168cab 100644 --- a/constraint/bw6-633/coeff.go +++ b/constraint/bw6-633/coeff.go @@ -108,7 +108,7 @@ func (engine *arithEngine) FromInterface(i interface{}) constraint.Coeff { func (engine *arithEngine) ToBigInt(c *constraint.Coeff) *big.Int { e := (*fr.Element)(c[:]) r := new(big.Int) - e.ToBigIntRegular(r) + e.BigInt(r) return r } diff --git a/constraint/bw6-633/solution.go b/constraint/bw6-633/solution.go index 8c02849824..88218a9136 100644 --- a/constraint/bw6-633/solution.go +++ b/constraint/bw6-633/solution.go @@ -191,7 +191,7 @@ func (s *solution) solveWithHint(vID int, h *constraint.Hint) error { } s.accumulateInto(term, &v) } - v.ToBigIntRegular(inputs[i]) + v.BigInt(inputs[i]) } err := f(q, inputs, outputs) diff --git a/constraint/bw6-761/coeff.go b/constraint/bw6-761/coeff.go index 093bc5cdc2..92643d2d79 100644 --- a/constraint/bw6-761/coeff.go +++ b/constraint/bw6-761/coeff.go @@ -108,7 +108,7 @@ func (engine *arithEngine) FromInterface(i interface{}) constraint.Coeff { func (engine *arithEngine) ToBigInt(c *constraint.Coeff) *big.Int { e := (*fr.Element)(c[:]) r := new(big.Int) - e.ToBigIntRegular(r) + e.BigInt(r) return r } diff --git a/constraint/bw6-761/solution.go b/constraint/bw6-761/solution.go index 5bf53da194..7410ca3056 100644 --- a/constraint/bw6-761/solution.go +++ b/constraint/bw6-761/solution.go @@ -191,7 +191,7 @@ func (s *solution) solveWithHint(vID int, h *constraint.Hint) error { } s.accumulateInto(term, &v) } - v.ToBigIntRegular(inputs[i]) + v.BigInt(inputs[i]) } err := f(q, inputs, outputs) diff --git a/constraint/tinyfield/coeff.go b/constraint/tinyfield/coeff.go index 7324e01794..175611602b 100644 --- a/constraint/tinyfield/coeff.go +++ b/constraint/tinyfield/coeff.go @@ -108,7 +108,7 @@ func (engine *arithEngine) FromInterface(i interface{}) constraint.Coeff { func (engine *arithEngine) ToBigInt(c *constraint.Coeff) *big.Int { e := (*fr.Element)(c[:]) r := new(big.Int) - e.ToBigIntRegular(r) + e.BigInt(r) return r } diff --git a/constraint/tinyfield/solution.go b/constraint/tinyfield/solution.go index cf1b5d215a..c7c2a38470 100644 --- a/constraint/tinyfield/solution.go +++ b/constraint/tinyfield/solution.go @@ -191,7 +191,7 @@ func (s *solution) solveWithHint(vID int, h *constraint.Hint) error { } s.accumulateInto(term, &v) } - v.ToBigIntRegular(inputs[i]) + v.BigInt(inputs[i]) } err := f(q, inputs, outputs) diff --git a/examples/rollup/operator.go b/examples/rollup/operator.go index daba40c7dc..b3a73aef91 100644 --- a/examples/rollup/operator.go +++ b/examples/rollup/operator.go @@ -197,8 +197,8 @@ func (o *Operator) updateState(t Transfer, numTransfer int) error { // checks if the amount is correct var bAmount, bBalance big.Int - receiverAccount.balance.ToBigIntRegular(&bBalance) - t.amount.ToBigIntRegular(&bAmount) + receiverAccount.balance.BigInt(&bBalance) + t.amount.BigInt(&bAmount) if bAmount.Cmp(&bBalance) == 1 { return ErrAmountTooHigh } diff --git a/internal/backend/bls12-377/groth16/prove.go b/internal/backend/bls12-377/groth16/prove.go index 5d52bc5f4b..37888c2cd5 100644 --- a/internal/backend/bls12-377/groth16/prove.go +++ b/internal/backend/bls12-377/groth16/prove.go @@ -88,7 +88,7 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, witness bls12_377witness.Witness, opt var res fr.Element res, err = solveCommitmentWire(&r1cs.CommitmentInfo, &proof.Commitment, in[:r1cs.CommitmentInfo.NbPublicCommitted()]) - res.ToBigIntRegular(out[0]) //Perf-TODO: Regular (non-mont) hashToField to obviate this conversion? + res.BigInt(out[0]) //Perf-TODO: Regular (non-mont) hashToField to obviate this conversion? return err } } diff --git a/internal/backend/bls12-377/groth16/verify.go b/internal/backend/bls12-377/groth16/verify.go index 1d452e5eeb..242705a35a 100644 --- a/internal/backend/bls12-377/groth16/verify.go +++ b/internal/backend/bls12-377/groth16/verify.go @@ -71,7 +71,7 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness bls12_377witness.Witne publicCommitted := make([]*big.Int, vk.CommitmentInfo.NbPublicCommitted()) for i := range publicCommitted { var b big.Int - publicWitness[vk.CommitmentInfo.Committed[i]-1].ToBigIntRegular(&b) + publicWitness[vk.CommitmentInfo.Committed[i]-1].BigInt(&b) publicCommitted[i] = &b } diff --git a/internal/backend/bls12-377/plonk/prove.go b/internal/backend/bls12-377/plonk/prove.go index 880467371f..3796066585 100644 --- a/internal/backend/bls12-377/plonk/prove.go +++ b/internal/backend/bls12-377/plonk/prove.go @@ -323,7 +323,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness bls12_377witness.Witn bSize.SetUint64(pk.Domain[0].Cardinality + 2) // +2 because of the masking (h of degree 3(n+2)-1) var zetaPowerm fr.Element zetaPowerm.Exp(zeta, &bSize) - zetaPowerm.ToBigIntRegular(&bZetaPowerm) + zetaPowerm.BigInt(&bZetaPowerm) foldedHDigest := proof.H[2] foldedHDigest.ScalarMultiplication(&foldedHDigest, &bZetaPowerm) foldedHDigest.Add(&foldedHDigest, &proof.H[1]) // ζᵐ⁺²*Comm(h3) diff --git a/internal/backend/bls12-377/plonk/verify.go b/internal/backend/bls12-377/plonk/verify.go index 404a635da9..74c3b02849 100644 --- a/internal/backend/bls12-377/plonk/verify.go +++ b/internal/backend/bls12-377/plonk/verify.go @@ -158,7 +158,7 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness bls12_377witness.Witne var zetaMPlusTwo fr.Element zetaMPlusTwo.Exp(zeta, mPlusTwo) var zetaMPlusTwoBigInt big.Int - zetaMPlusTwo.ToBigIntRegular(&zetaMPlusTwoBigInt) + zetaMPlusTwo.BigInt(&zetaMPlusTwoBigInt) foldedH := proof.H[2] foldedH.ScalarMultiplication(&foldedH, &zetaMPlusTwoBigInt) foldedH.Add(&foldedH, &proof.H[1]) diff --git a/internal/backend/bls12-381/groth16/prove.go b/internal/backend/bls12-381/groth16/prove.go index 1a321533cb..44ed5f6ef5 100644 --- a/internal/backend/bls12-381/groth16/prove.go +++ b/internal/backend/bls12-381/groth16/prove.go @@ -88,7 +88,7 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, witness bls12_381witness.Witness, opt var res fr.Element res, err = solveCommitmentWire(&r1cs.CommitmentInfo, &proof.Commitment, in[:r1cs.CommitmentInfo.NbPublicCommitted()]) - res.ToBigIntRegular(out[0]) //Perf-TODO: Regular (non-mont) hashToField to obviate this conversion? + res.BigInt(out[0]) //Perf-TODO: Regular (non-mont) hashToField to obviate this conversion? return err } } diff --git a/internal/backend/bls12-381/groth16/verify.go b/internal/backend/bls12-381/groth16/verify.go index 6a7706543d..5ee3e1c349 100644 --- a/internal/backend/bls12-381/groth16/verify.go +++ b/internal/backend/bls12-381/groth16/verify.go @@ -71,7 +71,7 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness bls12_381witness.Witne publicCommitted := make([]*big.Int, vk.CommitmentInfo.NbPublicCommitted()) for i := range publicCommitted { var b big.Int - publicWitness[vk.CommitmentInfo.Committed[i]-1].ToBigIntRegular(&b) + publicWitness[vk.CommitmentInfo.Committed[i]-1].BigInt(&b) publicCommitted[i] = &b } diff --git a/internal/backend/bls12-381/plonk/prove.go b/internal/backend/bls12-381/plonk/prove.go index 6bd637e609..e1d44cd47f 100644 --- a/internal/backend/bls12-381/plonk/prove.go +++ b/internal/backend/bls12-381/plonk/prove.go @@ -323,7 +323,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness bls12_381witness.Witn bSize.SetUint64(pk.Domain[0].Cardinality + 2) // +2 because of the masking (h of degree 3(n+2)-1) var zetaPowerm fr.Element zetaPowerm.Exp(zeta, &bSize) - zetaPowerm.ToBigIntRegular(&bZetaPowerm) + zetaPowerm.BigInt(&bZetaPowerm) foldedHDigest := proof.H[2] foldedHDigest.ScalarMultiplication(&foldedHDigest, &bZetaPowerm) foldedHDigest.Add(&foldedHDigest, &proof.H[1]) // ζᵐ⁺²*Comm(h3) diff --git a/internal/backend/bls12-381/plonk/verify.go b/internal/backend/bls12-381/plonk/verify.go index 9c1da50193..47ee78494d 100644 --- a/internal/backend/bls12-381/plonk/verify.go +++ b/internal/backend/bls12-381/plonk/verify.go @@ -158,7 +158,7 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness bls12_381witness.Witne var zetaMPlusTwo fr.Element zetaMPlusTwo.Exp(zeta, mPlusTwo) var zetaMPlusTwoBigInt big.Int - zetaMPlusTwo.ToBigIntRegular(&zetaMPlusTwoBigInt) + zetaMPlusTwo.BigInt(&zetaMPlusTwoBigInt) foldedH := proof.H[2] foldedH.ScalarMultiplication(&foldedH, &zetaMPlusTwoBigInt) foldedH.Add(&foldedH, &proof.H[1]) diff --git a/internal/backend/bls24-315/groth16/prove.go b/internal/backend/bls24-315/groth16/prove.go index 45aacc1d0d..136f249a34 100644 --- a/internal/backend/bls24-315/groth16/prove.go +++ b/internal/backend/bls24-315/groth16/prove.go @@ -88,7 +88,7 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, witness bls24_315witness.Witness, opt var res fr.Element res, err = solveCommitmentWire(&r1cs.CommitmentInfo, &proof.Commitment, in[:r1cs.CommitmentInfo.NbPublicCommitted()]) - res.ToBigIntRegular(out[0]) //Perf-TODO: Regular (non-mont) hashToField to obviate this conversion? + res.BigInt(out[0]) //Perf-TODO: Regular (non-mont) hashToField to obviate this conversion? return err } } diff --git a/internal/backend/bls24-315/groth16/verify.go b/internal/backend/bls24-315/groth16/verify.go index cf6a91a30e..26ba626c1f 100644 --- a/internal/backend/bls24-315/groth16/verify.go +++ b/internal/backend/bls24-315/groth16/verify.go @@ -71,7 +71,7 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness bls24_315witness.Witne publicCommitted := make([]*big.Int, vk.CommitmentInfo.NbPublicCommitted()) for i := range publicCommitted { var b big.Int - publicWitness[vk.CommitmentInfo.Committed[i]-1].ToBigIntRegular(&b) + publicWitness[vk.CommitmentInfo.Committed[i]-1].BigInt(&b) publicCommitted[i] = &b } diff --git a/internal/backend/bls24-315/plonk/prove.go b/internal/backend/bls24-315/plonk/prove.go index 71acb960aa..6ba044e124 100644 --- a/internal/backend/bls24-315/plonk/prove.go +++ b/internal/backend/bls24-315/plonk/prove.go @@ -323,7 +323,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness bls24_315witness.Witn bSize.SetUint64(pk.Domain[0].Cardinality + 2) // +2 because of the masking (h of degree 3(n+2)-1) var zetaPowerm fr.Element zetaPowerm.Exp(zeta, &bSize) - zetaPowerm.ToBigIntRegular(&bZetaPowerm) + zetaPowerm.BigInt(&bZetaPowerm) foldedHDigest := proof.H[2] foldedHDigest.ScalarMultiplication(&foldedHDigest, &bZetaPowerm) foldedHDigest.Add(&foldedHDigest, &proof.H[1]) // ζᵐ⁺²*Comm(h3) diff --git a/internal/backend/bls24-315/plonk/verify.go b/internal/backend/bls24-315/plonk/verify.go index 621010dd4e..c8a25c60fa 100644 --- a/internal/backend/bls24-315/plonk/verify.go +++ b/internal/backend/bls24-315/plonk/verify.go @@ -158,7 +158,7 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness bls24_315witness.Witne var zetaMPlusTwo fr.Element zetaMPlusTwo.Exp(zeta, mPlusTwo) var zetaMPlusTwoBigInt big.Int - zetaMPlusTwo.ToBigIntRegular(&zetaMPlusTwoBigInt) + zetaMPlusTwo.BigInt(&zetaMPlusTwoBigInt) foldedH := proof.H[2] foldedH.ScalarMultiplication(&foldedH, &zetaMPlusTwoBigInt) foldedH.Add(&foldedH, &proof.H[1]) diff --git a/internal/backend/bls24-317/groth16/prove.go b/internal/backend/bls24-317/groth16/prove.go index 78f9e7727c..16e4bd68db 100644 --- a/internal/backend/bls24-317/groth16/prove.go +++ b/internal/backend/bls24-317/groth16/prove.go @@ -88,7 +88,7 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, witness bls24_317witness.Witness, opt var res fr.Element res, err = solveCommitmentWire(&r1cs.CommitmentInfo, &proof.Commitment, in[:r1cs.CommitmentInfo.NbPublicCommitted()]) - res.ToBigIntRegular(out[0]) //Perf-TODO: Regular (non-mont) hashToField to obviate this conversion? + res.BigInt(out[0]) //Perf-TODO: Regular (non-mont) hashToField to obviate this conversion? return err } } diff --git a/internal/backend/bls24-317/groth16/verify.go b/internal/backend/bls24-317/groth16/verify.go index 4a20f54647..95fb0c993f 100644 --- a/internal/backend/bls24-317/groth16/verify.go +++ b/internal/backend/bls24-317/groth16/verify.go @@ -71,7 +71,7 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness bls24_317witness.Witne publicCommitted := make([]*big.Int, vk.CommitmentInfo.NbPublicCommitted()) for i := range publicCommitted { var b big.Int - publicWitness[vk.CommitmentInfo.Committed[i]-1].ToBigIntRegular(&b) + publicWitness[vk.CommitmentInfo.Committed[i]-1].BigInt(&b) publicCommitted[i] = &b } diff --git a/internal/backend/bls24-317/plonk/prove.go b/internal/backend/bls24-317/plonk/prove.go index 1ec854f108..a24b602f18 100644 --- a/internal/backend/bls24-317/plonk/prove.go +++ b/internal/backend/bls24-317/plonk/prove.go @@ -323,7 +323,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness bls24_317witness.Witn bSize.SetUint64(pk.Domain[0].Cardinality + 2) // +2 because of the masking (h of degree 3(n+2)-1) var zetaPowerm fr.Element zetaPowerm.Exp(zeta, &bSize) - zetaPowerm.ToBigIntRegular(&bZetaPowerm) + zetaPowerm.BigInt(&bZetaPowerm) foldedHDigest := proof.H[2] foldedHDigest.ScalarMultiplication(&foldedHDigest, &bZetaPowerm) foldedHDigest.Add(&foldedHDigest, &proof.H[1]) // ζᵐ⁺²*Comm(h3) diff --git a/internal/backend/bls24-317/plonk/verify.go b/internal/backend/bls24-317/plonk/verify.go index ad619939a3..808d123729 100644 --- a/internal/backend/bls24-317/plonk/verify.go +++ b/internal/backend/bls24-317/plonk/verify.go @@ -158,7 +158,7 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness bls24_317witness.Witne var zetaMPlusTwo fr.Element zetaMPlusTwo.Exp(zeta, mPlusTwo) var zetaMPlusTwoBigInt big.Int - zetaMPlusTwo.ToBigIntRegular(&zetaMPlusTwoBigInt) + zetaMPlusTwo.BigInt(&zetaMPlusTwoBigInt) foldedH := proof.H[2] foldedH.ScalarMultiplication(&foldedH, &zetaMPlusTwoBigInt) foldedH.Add(&foldedH, &proof.H[1]) diff --git a/internal/backend/bn254/groth16/prove.go b/internal/backend/bn254/groth16/prove.go index f36022eaa7..153d42562b 100644 --- a/internal/backend/bn254/groth16/prove.go +++ b/internal/backend/bn254/groth16/prove.go @@ -88,7 +88,7 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, witness bn254witness.Witness, opt back var res fr.Element res, err = solveCommitmentWire(&r1cs.CommitmentInfo, &proof.Commitment, in[:r1cs.CommitmentInfo.NbPublicCommitted()]) - res.ToBigIntRegular(out[0]) //Perf-TODO: Regular (non-mont) hashToField to obviate this conversion? + res.BigInt(out[0]) //Perf-TODO: Regular (non-mont) hashToField to obviate this conversion? return err } } diff --git a/internal/backend/bn254/groth16/verify.go b/internal/backend/bn254/groth16/verify.go index 1f9328caf0..ed8a9cc0b3 100644 --- a/internal/backend/bn254/groth16/verify.go +++ b/internal/backend/bn254/groth16/verify.go @@ -72,7 +72,7 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness bn254witness.Witness) publicCommitted := make([]*big.Int, vk.CommitmentInfo.NbPublicCommitted()) for i := range publicCommitted { var b big.Int - publicWitness[vk.CommitmentInfo.Committed[i]-1].ToBigIntRegular(&b) + publicWitness[vk.CommitmentInfo.Committed[i]-1].BigInt(&b) publicCommitted[i] = &b } diff --git a/internal/backend/bn254/plonk/prove.go b/internal/backend/bn254/plonk/prove.go index 1a43704666..1050e08ad5 100644 --- a/internal/backend/bn254/plonk/prove.go +++ b/internal/backend/bn254/plonk/prove.go @@ -323,7 +323,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness bn254witness.Witness, bSize.SetUint64(pk.Domain[0].Cardinality + 2) // +2 because of the masking (h of degree 3(n+2)-1) var zetaPowerm fr.Element zetaPowerm.Exp(zeta, &bSize) - zetaPowerm.ToBigIntRegular(&bZetaPowerm) + zetaPowerm.BigInt(&bZetaPowerm) foldedHDigest := proof.H[2] foldedHDigest.ScalarMultiplication(&foldedHDigest, &bZetaPowerm) foldedHDigest.Add(&foldedHDigest, &proof.H[1]) // ζᵐ⁺²*Comm(h3) diff --git a/internal/backend/bn254/plonk/verify.go b/internal/backend/bn254/plonk/verify.go index 103e1f30ec..b7e562abf8 100644 --- a/internal/backend/bn254/plonk/verify.go +++ b/internal/backend/bn254/plonk/verify.go @@ -160,7 +160,7 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness bn254witness.Witness) var zetaMPlusTwo fr.Element zetaMPlusTwo.Exp(zeta, mPlusTwo) var zetaMPlusTwoBigInt big.Int - zetaMPlusTwo.ToBigIntRegular(&zetaMPlusTwoBigInt) + zetaMPlusTwo.BigInt(&zetaMPlusTwoBigInt) foldedH := proof.H[2] foldedH.ScalarMultiplication(&foldedH, &zetaMPlusTwoBigInt) foldedH.Add(&foldedH, &proof.H[1]) diff --git a/internal/backend/bw6-633/groth16/prove.go b/internal/backend/bw6-633/groth16/prove.go index a20240c03d..a815f5de04 100644 --- a/internal/backend/bw6-633/groth16/prove.go +++ b/internal/backend/bw6-633/groth16/prove.go @@ -88,7 +88,7 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, witness bw6_633witness.Witness, opt ba var res fr.Element res, err = solveCommitmentWire(&r1cs.CommitmentInfo, &proof.Commitment, in[:r1cs.CommitmentInfo.NbPublicCommitted()]) - res.ToBigIntRegular(out[0]) //Perf-TODO: Regular (non-mont) hashToField to obviate this conversion? + res.BigInt(out[0]) //Perf-TODO: Regular (non-mont) hashToField to obviate this conversion? return err } } diff --git a/internal/backend/bw6-633/groth16/verify.go b/internal/backend/bw6-633/groth16/verify.go index d8200d6981..ddc6e62223 100644 --- a/internal/backend/bw6-633/groth16/verify.go +++ b/internal/backend/bw6-633/groth16/verify.go @@ -71,7 +71,7 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness bw6_633witness.Witness publicCommitted := make([]*big.Int, vk.CommitmentInfo.NbPublicCommitted()) for i := range publicCommitted { var b big.Int - publicWitness[vk.CommitmentInfo.Committed[i]-1].ToBigIntRegular(&b) + publicWitness[vk.CommitmentInfo.Committed[i]-1].BigInt(&b) publicCommitted[i] = &b } diff --git a/internal/backend/bw6-633/plonk/prove.go b/internal/backend/bw6-633/plonk/prove.go index 4e8657bcf3..aea57b48f5 100644 --- a/internal/backend/bw6-633/plonk/prove.go +++ b/internal/backend/bw6-633/plonk/prove.go @@ -323,7 +323,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness bw6_633witness.Witnes bSize.SetUint64(pk.Domain[0].Cardinality + 2) // +2 because of the masking (h of degree 3(n+2)-1) var zetaPowerm fr.Element zetaPowerm.Exp(zeta, &bSize) - zetaPowerm.ToBigIntRegular(&bZetaPowerm) + zetaPowerm.BigInt(&bZetaPowerm) foldedHDigest := proof.H[2] foldedHDigest.ScalarMultiplication(&foldedHDigest, &bZetaPowerm) foldedHDigest.Add(&foldedHDigest, &proof.H[1]) // ζᵐ⁺²*Comm(h3) diff --git a/internal/backend/bw6-633/plonk/verify.go b/internal/backend/bw6-633/plonk/verify.go index 127c0506df..3807f8faba 100644 --- a/internal/backend/bw6-633/plonk/verify.go +++ b/internal/backend/bw6-633/plonk/verify.go @@ -158,7 +158,7 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness bw6_633witness.Witness var zetaMPlusTwo fr.Element zetaMPlusTwo.Exp(zeta, mPlusTwo) var zetaMPlusTwoBigInt big.Int - zetaMPlusTwo.ToBigIntRegular(&zetaMPlusTwoBigInt) + zetaMPlusTwo.BigInt(&zetaMPlusTwoBigInt) foldedH := proof.H[2] foldedH.ScalarMultiplication(&foldedH, &zetaMPlusTwoBigInt) foldedH.Add(&foldedH, &proof.H[1]) diff --git a/internal/backend/bw6-761/groth16/prove.go b/internal/backend/bw6-761/groth16/prove.go index bb00b69ca4..0026d7e65b 100644 --- a/internal/backend/bw6-761/groth16/prove.go +++ b/internal/backend/bw6-761/groth16/prove.go @@ -88,7 +88,7 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, witness bw6_761witness.Witness, opt ba var res fr.Element res, err = solveCommitmentWire(&r1cs.CommitmentInfo, &proof.Commitment, in[:r1cs.CommitmentInfo.NbPublicCommitted()]) - res.ToBigIntRegular(out[0]) //Perf-TODO: Regular (non-mont) hashToField to obviate this conversion? + res.BigInt(out[0]) //Perf-TODO: Regular (non-mont) hashToField to obviate this conversion? return err } } diff --git a/internal/backend/bw6-761/groth16/verify.go b/internal/backend/bw6-761/groth16/verify.go index c2c100b4dc..6d1db17677 100644 --- a/internal/backend/bw6-761/groth16/verify.go +++ b/internal/backend/bw6-761/groth16/verify.go @@ -71,7 +71,7 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness bw6_761witness.Witness publicCommitted := make([]*big.Int, vk.CommitmentInfo.NbPublicCommitted()) for i := range publicCommitted { var b big.Int - publicWitness[vk.CommitmentInfo.Committed[i]-1].ToBigIntRegular(&b) + publicWitness[vk.CommitmentInfo.Committed[i]-1].BigInt(&b) publicCommitted[i] = &b } diff --git a/internal/backend/bw6-761/plonk/prove.go b/internal/backend/bw6-761/plonk/prove.go index fe51467b47..5101cfb90c 100644 --- a/internal/backend/bw6-761/plonk/prove.go +++ b/internal/backend/bw6-761/plonk/prove.go @@ -323,7 +323,7 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness bw6_761witness.Witnes bSize.SetUint64(pk.Domain[0].Cardinality + 2) // +2 because of the masking (h of degree 3(n+2)-1) var zetaPowerm fr.Element zetaPowerm.Exp(zeta, &bSize) - zetaPowerm.ToBigIntRegular(&bZetaPowerm) + zetaPowerm.BigInt(&bZetaPowerm) foldedHDigest := proof.H[2] foldedHDigest.ScalarMultiplication(&foldedHDigest, &bZetaPowerm) foldedHDigest.Add(&foldedHDigest, &proof.H[1]) // ζᵐ⁺²*Comm(h3) diff --git a/internal/backend/bw6-761/plonk/verify.go b/internal/backend/bw6-761/plonk/verify.go index eca3443894..e951e0811e 100644 --- a/internal/backend/bw6-761/plonk/verify.go +++ b/internal/backend/bw6-761/plonk/verify.go @@ -158,7 +158,7 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness bw6_761witness.Witness var zetaMPlusTwo fr.Element zetaMPlusTwo.Exp(zeta, mPlusTwo) var zetaMPlusTwoBigInt big.Int - zetaMPlusTwo.ToBigIntRegular(&zetaMPlusTwoBigInt) + zetaMPlusTwo.BigInt(&zetaMPlusTwoBigInt) foldedH := proof.H[2] foldedH.ScalarMultiplication(&foldedH, &zetaMPlusTwoBigInt) foldedH.Add(&foldedH, &proof.H[1]) diff --git a/internal/tinyfield/element.go b/internal/tinyfield/element.go index 18b05910f3..18e496c364 100644 --- a/internal/tinyfield/element.go +++ b/internal/tinyfield/element.go @@ -681,8 +681,8 @@ func (z *Element) ToBigInt(res *big.Int) *big.Int { return res.SetBytes(b[:]) } -// ToBigIntRegular returns z as a big.Int in regular form -func (z Element) ToBigIntRegular(res *big.Int) *big.Int { +// BigInt returns z as a big.Int in regular form +func (z Element) BigInt(res *big.Int) *big.Int { z.FromMont() return z.ToBigInt(res) } diff --git a/internal/tinyfield/element_test.go b/internal/tinyfield/element_test.go index e8fb7e4c94..5328795aa1 100644 --- a/internal/tinyfield/element_test.go +++ b/internal/tinyfield/element_test.go @@ -710,7 +710,7 @@ func TestElementAdd(t *testing.T) { for _, r := range testValues { var d, e, rb big.Int - r.ToBigIntRegular(&rb) + r.BigInt(&rb) var c Element c.Add(&a.element, &r) @@ -745,11 +745,11 @@ func TestElementAdd(t *testing.T) { for _, a := range testValues { var aBig big.Int - a.ToBigIntRegular(&aBig) + a.BigInt(&aBig) for _, b := range testValues { var bBig, d, e big.Int - b.ToBigIntRegular(&bBig) + b.BigInt(&bBig) var c Element c.Add(&a, &b) @@ -819,7 +819,7 @@ func TestElementSub(t *testing.T) { for _, r := range testValues { var d, e, rb big.Int - r.ToBigIntRegular(&rb) + r.BigInt(&rb) var c Element c.Sub(&a.element, &r) @@ -854,11 +854,11 @@ func TestElementSub(t *testing.T) { for _, a := range testValues { var aBig big.Int - a.ToBigIntRegular(&aBig) + a.BigInt(&aBig) for _, b := range testValues { var bBig, d, e big.Int - b.ToBigIntRegular(&bBig) + b.BigInt(&bBig) var c Element c.Sub(&a, &b) @@ -928,7 +928,7 @@ func TestElementMul(t *testing.T) { for _, r := range testValues { var d, e, rb big.Int - r.ToBigIntRegular(&rb) + r.BigInt(&rb) var c Element c.Mul(&a.element, &r) @@ -982,11 +982,11 @@ func TestElementMul(t *testing.T) { for _, a := range testValues { var aBig big.Int - a.ToBigIntRegular(&aBig) + a.BigInt(&aBig) for _, b := range testValues { var bBig, d, e big.Int - b.ToBigIntRegular(&bBig) + b.BigInt(&bBig) var c Element c.Mul(&a, &b) @@ -1064,7 +1064,7 @@ func TestElementDiv(t *testing.T) { for _, r := range testValues { var d, e, rb big.Int - r.ToBigIntRegular(&rb) + r.BigInt(&rb) var c Element c.Div(&a.element, &r) @@ -1100,11 +1100,11 @@ func TestElementDiv(t *testing.T) { for _, a := range testValues { var aBig big.Int - a.ToBigIntRegular(&aBig) + a.BigInt(&aBig) for _, b := range testValues { var bBig, d, e big.Int - b.ToBigIntRegular(&bBig) + b.BigInt(&bBig) var c Element c.Div(&a, &b) @@ -1175,7 +1175,7 @@ func TestElementExp(t *testing.T) { for _, r := range testValues { var d, e, rb big.Int - r.ToBigIntRegular(&rb) + r.BigInt(&rb) var c Element c.Exp(a.element, &rb) @@ -1210,11 +1210,11 @@ func TestElementExp(t *testing.T) { for _, a := range testValues { var aBig big.Int - a.ToBigIntRegular(&aBig) + a.BigInt(&aBig) for _, b := range testValues { var bBig, d, e big.Int - b.ToBigIntRegular(&bBig) + b.BigInt(&bBig) var c Element c.Exp(a, &bBig) @@ -1286,7 +1286,7 @@ func TestElementSquare(t *testing.T) { for _, a := range testValues { var aBig big.Int - a.ToBigIntRegular(&aBig) + a.BigInt(&aBig) var c Element c.Square(&a) @@ -1358,7 +1358,7 @@ func TestElementInverse(t *testing.T) { for _, a := range testValues { var aBig big.Int - a.ToBigIntRegular(&aBig) + a.BigInt(&aBig) var c Element c.Inverse(&a) @@ -1430,7 +1430,7 @@ func TestElementSqrt(t *testing.T) { for _, a := range testValues { var aBig big.Int - a.ToBigIntRegular(&aBig) + a.BigInt(&aBig) var c Element c.Sqrt(&a) @@ -1502,7 +1502,7 @@ func TestElementDouble(t *testing.T) { for _, a := range testValues { var aBig big.Int - a.ToBigIntRegular(&aBig) + a.BigInt(&aBig) var c Element c.Double(&a) @@ -1574,7 +1574,7 @@ func TestElementNeg(t *testing.T) { for _, a := range testValues { var aBig big.Int - a.ToBigIntRegular(&aBig) + a.BigInt(&aBig) var c Element c.Neg(&a) @@ -2150,7 +2150,7 @@ func gen() gopter.Gen { } } - g.element.ToBigIntRegular(&g.bigint) + g.element.BigInt(&g.bigint) genResult := gopter.NewGenResult(g, gopter.NoShrinker) return genResult } diff --git a/std/algebra/fields_bls12377/e12.go b/std/algebra/fields_bls12377/e12.go index 5fe7e6b55e..64ed8fc024 100644 --- a/std/algebra/fields_bls12377/e12.go +++ b/std/algebra/fields_bls12377/e12.go @@ -272,7 +272,7 @@ func (e *E12) Decompress(api frontend.API, x E12) *E12 { t[1].Sub(api, t[0], x.C0.B2). Double(api, t[1]). Add(api, t[1], t[0]) - // t0 = E * g5² + t1 + // t0 = E * g5² + t1 t[2].Square(api, x.C1.B2) t[0].MulByNonResidue(api, t[2]). Add(api, t[0], t[1]) @@ -447,18 +447,18 @@ var InverseE12Hint = func(_ *big.Int, inputs []*big.Int, res []*big.Int) error { c.Inverse(&a) - c.C0.B0.A0.ToBigIntRegular(res[0]) - c.C0.B0.A1.ToBigIntRegular(res[1]) - c.C0.B1.A0.ToBigIntRegular(res[2]) - c.C0.B1.A1.ToBigIntRegular(res[3]) - c.C0.B2.A0.ToBigIntRegular(res[4]) - c.C0.B2.A1.ToBigIntRegular(res[5]) - c.C1.B0.A0.ToBigIntRegular(res[6]) - c.C1.B0.A1.ToBigIntRegular(res[7]) - c.C1.B1.A0.ToBigIntRegular(res[8]) - c.C1.B1.A1.ToBigIntRegular(res[9]) - c.C1.B2.A0.ToBigIntRegular(res[10]) - c.C1.B2.A1.ToBigIntRegular(res[11]) + c.C0.B0.A0.BigInt(res[0]) + c.C0.B0.A1.BigInt(res[1]) + c.C0.B1.A0.BigInt(res[2]) + c.C0.B1.A1.BigInt(res[3]) + c.C0.B2.A0.BigInt(res[4]) + c.C0.B2.A1.BigInt(res[5]) + c.C1.B0.A0.BigInt(res[6]) + c.C1.B0.A1.BigInt(res[7]) + c.C1.B1.A0.BigInt(res[8]) + c.C1.B1.A1.BigInt(res[9]) + c.C1.B2.A0.BigInt(res[10]) + c.C1.B2.A1.BigInt(res[11]) return nil } @@ -520,18 +520,18 @@ var DivE12Hint = func(_ *big.Int, inputs []*big.Int, res []*big.Int) error { c.Inverse(&b).Mul(&c, &a) - c.C0.B0.A0.ToBigIntRegular(res[0]) - c.C0.B0.A1.ToBigIntRegular(res[1]) - c.C0.B1.A0.ToBigIntRegular(res[2]) - c.C0.B1.A1.ToBigIntRegular(res[3]) - c.C0.B2.A0.ToBigIntRegular(res[4]) - c.C0.B2.A1.ToBigIntRegular(res[5]) - c.C1.B0.A0.ToBigIntRegular(res[6]) - c.C1.B0.A1.ToBigIntRegular(res[7]) - c.C1.B1.A0.ToBigIntRegular(res[8]) - c.C1.B1.A1.ToBigIntRegular(res[9]) - c.C1.B2.A0.ToBigIntRegular(res[10]) - c.C1.B2.A1.ToBigIntRegular(res[11]) + c.C0.B0.A0.BigInt(res[0]) + c.C0.B0.A1.BigInt(res[1]) + c.C0.B1.A0.BigInt(res[2]) + c.C0.B1.A1.BigInt(res[3]) + c.C0.B2.A0.BigInt(res[4]) + c.C0.B2.A1.BigInt(res[5]) + c.C1.B0.A0.BigInt(res[6]) + c.C1.B0.A1.BigInt(res[7]) + c.C1.B1.A0.BigInt(res[8]) + c.C1.B1.A1.BigInt(res[9]) + c.C1.B2.A0.BigInt(res[10]) + c.C1.B2.A1.BigInt(res[11]) return nil } diff --git a/std/algebra/fields_bls12377/e2.go b/std/algebra/fields_bls12377/e2.go index 27a17e32ef..067e8242c4 100644 --- a/std/algebra/fields_bls12377/e2.go +++ b/std/algebra/fields_bls12377/e2.go @@ -147,8 +147,8 @@ var InverseE2Hint = func(_ *big.Int, inputs []*big.Int, res []*big.Int) error { c.Inverse(&a) - c.A0.ToBigIntRegular(res[0]) - c.A1.ToBigIntRegular(res[1]) + c.A0.BigInt(res[0]) + c.A1.BigInt(res[1]) return nil } @@ -189,8 +189,8 @@ var DivE2Hint = func(_ *big.Int, inputs []*big.Int, res []*big.Int) error { c.Inverse(&b).Mul(&c, &a) - c.A0.ToBigIntRegular(res[0]) - c.A1.ToBigIntRegular(res[1]) + c.A0.BigInt(res[0]) + c.A1.BigInt(res[1]) return nil } diff --git a/std/algebra/fields_bls12377/e6.go b/std/algebra/fields_bls12377/e6.go index f3091da62b..b8d15605e8 100644 --- a/std/algebra/fields_bls12377/e6.go +++ b/std/algebra/fields_bls12377/e6.go @@ -187,12 +187,12 @@ var DivE6Hint = func(_ *big.Int, inputs []*big.Int, res []*big.Int) error { c.Inverse(&b).Mul(&c, &a) - c.B0.A0.ToBigIntRegular(res[0]) - c.B0.A1.ToBigIntRegular(res[1]) - c.B1.A0.ToBigIntRegular(res[2]) - c.B1.A1.ToBigIntRegular(res[3]) - c.B2.A0.ToBigIntRegular(res[4]) - c.B2.A1.ToBigIntRegular(res[5]) + c.B0.A0.BigInt(res[0]) + c.B0.A1.BigInt(res[1]) + c.B1.A0.BigInt(res[2]) + c.B1.A1.BigInt(res[3]) + c.B2.A0.BigInt(res[4]) + c.B2.A1.BigInt(res[5]) return nil } @@ -235,12 +235,12 @@ var InverseE6Hint = func(_ *big.Int, inputs []*big.Int, res []*big.Int) error { c.Inverse(&a) - c.B0.A0.ToBigIntRegular(res[0]) - c.B0.A1.ToBigIntRegular(res[1]) - c.B1.A0.ToBigIntRegular(res[2]) - c.B1.A1.ToBigIntRegular(res[3]) - c.B2.A0.ToBigIntRegular(res[4]) - c.B2.A1.ToBigIntRegular(res[5]) + c.B0.A0.BigInt(res[0]) + c.B0.A1.BigInt(res[1]) + c.B1.A0.BigInt(res[2]) + c.B1.A1.BigInt(res[3]) + c.B2.A0.BigInt(res[4]) + c.B2.A1.BigInt(res[5]) return nil } diff --git a/std/algebra/fields_bls24315/e12.go b/std/algebra/fields_bls24315/e12.go index 87c5e0aad2..2a8583f3f8 100644 --- a/std/algebra/fields_bls24315/e12.go +++ b/std/algebra/fields_bls24315/e12.go @@ -192,18 +192,18 @@ var InverseE12Hint = func(_ *big.Int, inputs []*big.Int, res []*big.Int) error { c.Inverse(&a) - c.C0.B0.A0.ToBigIntRegular(res[0]) - c.C0.B0.A1.ToBigIntRegular(res[1]) - c.C0.B1.A0.ToBigIntRegular(res[2]) - c.C0.B1.A1.ToBigIntRegular(res[3]) - c.C1.B0.A0.ToBigIntRegular(res[4]) - c.C1.B0.A1.ToBigIntRegular(res[5]) - c.C1.B1.A0.ToBigIntRegular(res[6]) - c.C1.B1.A1.ToBigIntRegular(res[7]) - c.C2.B0.A0.ToBigIntRegular(res[8]) - c.C2.B0.A1.ToBigIntRegular(res[9]) - c.C2.B1.A0.ToBigIntRegular(res[10]) - c.C2.B1.A1.ToBigIntRegular(res[11]) + c.C0.B0.A0.BigInt(res[0]) + c.C0.B0.A1.BigInt(res[1]) + c.C0.B1.A0.BigInt(res[2]) + c.C0.B1.A1.BigInt(res[3]) + c.C1.B0.A0.BigInt(res[4]) + c.C1.B0.A1.BigInt(res[5]) + c.C1.B1.A0.BigInt(res[6]) + c.C1.B1.A1.BigInt(res[7]) + c.C2.B0.A0.BigInt(res[8]) + c.C2.B0.A1.BigInt(res[9]) + c.C2.B1.A0.BigInt(res[10]) + c.C2.B1.A1.BigInt(res[11]) return nil } @@ -265,18 +265,18 @@ var DivE12Hint = func(_ *big.Int, inputs []*big.Int, res []*big.Int) error { c.Inverse(&b).Mul(&c, &a) - c.C0.B0.A0.ToBigIntRegular(res[0]) - c.C0.B0.A1.ToBigIntRegular(res[1]) - c.C0.B1.A0.ToBigIntRegular(res[2]) - c.C0.B1.A1.ToBigIntRegular(res[3]) - c.C1.B0.A0.ToBigIntRegular(res[4]) - c.C1.B0.A1.ToBigIntRegular(res[5]) - c.C1.B1.A0.ToBigIntRegular(res[6]) - c.C1.B1.A1.ToBigIntRegular(res[7]) - c.C2.B0.A0.ToBigIntRegular(res[8]) - c.C2.B0.A1.ToBigIntRegular(res[9]) - c.C2.B1.A0.ToBigIntRegular(res[10]) - c.C2.B1.A1.ToBigIntRegular(res[11]) + c.C0.B0.A0.BigInt(res[0]) + c.C0.B0.A1.BigInt(res[1]) + c.C0.B1.A0.BigInt(res[2]) + c.C0.B1.A1.BigInt(res[3]) + c.C1.B0.A0.BigInt(res[4]) + c.C1.B0.A1.BigInt(res[5]) + c.C1.B1.A0.BigInt(res[6]) + c.C1.B1.A1.BigInt(res[7]) + c.C2.B0.A0.BigInt(res[8]) + c.C2.B0.A1.BigInt(res[9]) + c.C2.B1.A0.BigInt(res[10]) + c.C2.B1.A1.BigInt(res[11]) return nil } diff --git a/std/algebra/fields_bls24315/e2.go b/std/algebra/fields_bls24315/e2.go index d04df41c02..b850ef025b 100644 --- a/std/algebra/fields_bls24315/e2.go +++ b/std/algebra/fields_bls24315/e2.go @@ -153,8 +153,8 @@ var DivE2Hint = func(_ *big.Int, inputs []*big.Int, res []*big.Int) error { c.Inverse(&b).Mul(&c, &a) - c.A0.ToBigIntRegular(res[0]) - c.A1.ToBigIntRegular(res[1]) + c.A0.BigInt(res[0]) + c.A1.BigInt(res[1]) return nil } @@ -192,8 +192,8 @@ var InverseE2Hint = func(_ *big.Int, inputs []*big.Int, res []*big.Int) error { c.Inverse(&a) - c.A0.ToBigIntRegular(res[0]) - c.A1.ToBigIntRegular(res[1]) + c.A0.BigInt(res[0]) + c.A1.BigInt(res[1]) return nil } diff --git a/std/algebra/fields_bls24315/e24.go b/std/algebra/fields_bls24315/e24.go index b21c8004e3..d70722cb70 100644 --- a/std/algebra/fields_bls24315/e24.go +++ b/std/algebra/fields_bls24315/e24.go @@ -270,7 +270,7 @@ func (e *E24) Decompress(api frontend.API, x E24) *E24 { t[1].Sub(api, t[0], x.D0.C2). Double(api, t[1]). Add(api, t[1], t[0]) - // t0 = E * g5² + t1 + // t0 = E * g5² + t1 t[2].Square(api, x.D1.C2) t[0].MulByNonResidue(api, t[2]). Add(api, t[0], t[1]) @@ -418,30 +418,30 @@ var InverseE24Hint = func(_ *big.Int, inputs []*big.Int, res []*big.Int) error { c.Inverse(&a) - c.D0.C0.B0.A0.ToBigIntRegular(res[0]) - c.D0.C0.B0.A1.ToBigIntRegular(res[1]) - c.D0.C0.B1.A0.ToBigIntRegular(res[2]) - c.D0.C0.B1.A1.ToBigIntRegular(res[3]) - c.D0.C1.B0.A0.ToBigIntRegular(res[4]) - c.D0.C1.B0.A1.ToBigIntRegular(res[5]) - c.D0.C1.B1.A0.ToBigIntRegular(res[6]) - c.D0.C1.B1.A1.ToBigIntRegular(res[7]) - c.D0.C2.B0.A0.ToBigIntRegular(res[8]) - c.D0.C2.B0.A1.ToBigIntRegular(res[9]) - c.D0.C2.B1.A0.ToBigIntRegular(res[10]) - c.D0.C2.B1.A1.ToBigIntRegular(res[11]) - c.D1.C0.B0.A0.ToBigIntRegular(res[12]) - c.D1.C0.B0.A1.ToBigIntRegular(res[13]) - c.D1.C0.B1.A0.ToBigIntRegular(res[14]) - c.D1.C0.B1.A1.ToBigIntRegular(res[15]) - c.D1.C1.B0.A0.ToBigIntRegular(res[16]) - c.D1.C1.B0.A1.ToBigIntRegular(res[17]) - c.D1.C1.B1.A0.ToBigIntRegular(res[18]) - c.D1.C1.B1.A1.ToBigIntRegular(res[19]) - c.D1.C2.B0.A0.ToBigIntRegular(res[20]) - c.D1.C2.B0.A1.ToBigIntRegular(res[21]) - c.D1.C2.B1.A0.ToBigIntRegular(res[22]) - c.D1.C2.B1.A1.ToBigIntRegular(res[23]) + c.D0.C0.B0.A0.BigInt(res[0]) + c.D0.C0.B0.A1.BigInt(res[1]) + c.D0.C0.B1.A0.BigInt(res[2]) + c.D0.C0.B1.A1.BigInt(res[3]) + c.D0.C1.B0.A0.BigInt(res[4]) + c.D0.C1.B0.A1.BigInt(res[5]) + c.D0.C1.B1.A0.BigInt(res[6]) + c.D0.C1.B1.A1.BigInt(res[7]) + c.D0.C2.B0.A0.BigInt(res[8]) + c.D0.C2.B0.A1.BigInt(res[9]) + c.D0.C2.B1.A0.BigInt(res[10]) + c.D0.C2.B1.A1.BigInt(res[11]) + c.D1.C0.B0.A0.BigInt(res[12]) + c.D1.C0.B0.A1.BigInt(res[13]) + c.D1.C0.B1.A0.BigInt(res[14]) + c.D1.C0.B1.A1.BigInt(res[15]) + c.D1.C1.B0.A0.BigInt(res[16]) + c.D1.C1.B0.A1.BigInt(res[17]) + c.D1.C1.B1.A0.BigInt(res[18]) + c.D1.C1.B1.A1.BigInt(res[19]) + c.D1.C2.B0.A0.BigInt(res[20]) + c.D1.C2.B0.A1.BigInt(res[21]) + c.D1.C2.B1.A0.BigInt(res[22]) + c.D1.C2.B1.A1.BigInt(res[23]) return nil } @@ -528,30 +528,30 @@ var DivE24Hint = func(_ *big.Int, inputs []*big.Int, res []*big.Int) error { c.Inverse(&b).Mul(&c, &a) - c.D0.C0.B0.A0.ToBigIntRegular(res[0]) - c.D0.C0.B0.A1.ToBigIntRegular(res[1]) - c.D0.C0.B1.A0.ToBigIntRegular(res[2]) - c.D0.C0.B1.A1.ToBigIntRegular(res[3]) - c.D0.C1.B0.A0.ToBigIntRegular(res[4]) - c.D0.C1.B0.A1.ToBigIntRegular(res[5]) - c.D0.C1.B1.A0.ToBigIntRegular(res[6]) - c.D0.C1.B1.A1.ToBigIntRegular(res[7]) - c.D0.C2.B0.A0.ToBigIntRegular(res[8]) - c.D0.C2.B0.A1.ToBigIntRegular(res[9]) - c.D0.C2.B1.A0.ToBigIntRegular(res[10]) - c.D0.C2.B1.A1.ToBigIntRegular(res[11]) - c.D1.C0.B0.A0.ToBigIntRegular(res[12]) - c.D1.C0.B0.A1.ToBigIntRegular(res[13]) - c.D1.C0.B1.A0.ToBigIntRegular(res[14]) - c.D1.C0.B1.A1.ToBigIntRegular(res[15]) - c.D1.C1.B0.A0.ToBigIntRegular(res[16]) - c.D1.C1.B0.A1.ToBigIntRegular(res[17]) - c.D1.C1.B1.A0.ToBigIntRegular(res[18]) - c.D1.C1.B1.A1.ToBigIntRegular(res[19]) - c.D1.C2.B0.A0.ToBigIntRegular(res[20]) - c.D1.C2.B0.A1.ToBigIntRegular(res[21]) - c.D1.C2.B1.A0.ToBigIntRegular(res[22]) - c.D1.C2.B1.A1.ToBigIntRegular(res[23]) + c.D0.C0.B0.A0.BigInt(res[0]) + c.D0.C0.B0.A1.BigInt(res[1]) + c.D0.C0.B1.A0.BigInt(res[2]) + c.D0.C0.B1.A1.BigInt(res[3]) + c.D0.C1.B0.A0.BigInt(res[4]) + c.D0.C1.B0.A1.BigInt(res[5]) + c.D0.C1.B1.A0.BigInt(res[6]) + c.D0.C1.B1.A1.BigInt(res[7]) + c.D0.C2.B0.A0.BigInt(res[8]) + c.D0.C2.B0.A1.BigInt(res[9]) + c.D0.C2.B1.A0.BigInt(res[10]) + c.D0.C2.B1.A1.BigInt(res[11]) + c.D1.C0.B0.A0.BigInt(res[12]) + c.D1.C0.B0.A1.BigInt(res[13]) + c.D1.C0.B1.A0.BigInt(res[14]) + c.D1.C0.B1.A1.BigInt(res[15]) + c.D1.C1.B0.A0.BigInt(res[16]) + c.D1.C1.B0.A1.BigInt(res[17]) + c.D1.C1.B1.A0.BigInt(res[18]) + c.D1.C1.B1.A1.BigInt(res[19]) + c.D1.C2.B0.A0.BigInt(res[20]) + c.D1.C2.B0.A1.BigInt(res[21]) + c.D1.C2.B1.A0.BigInt(res[22]) + c.D1.C2.B1.A1.BigInt(res[23]) return nil } diff --git a/std/algebra/fields_bls24315/e4.go b/std/algebra/fields_bls24315/e4.go index bb800abea7..57abb6ccf8 100644 --- a/std/algebra/fields_bls24315/e4.go +++ b/std/algebra/fields_bls24315/e4.go @@ -156,10 +156,10 @@ var DivE4Hint = func(_ *big.Int, inputs []*big.Int, res []*big.Int) error { c.Inverse(&b).Mul(&c, &a) - c.B0.A0.ToBigIntRegular(res[0]) - c.B0.A1.ToBigIntRegular(res[1]) - c.B1.A0.ToBigIntRegular(res[2]) - c.B1.A1.ToBigIntRegular(res[3]) + c.B0.A0.BigInt(res[0]) + c.B0.A1.BigInt(res[1]) + c.B1.A0.BigInt(res[2]) + c.B1.A1.BigInt(res[3]) return nil } @@ -199,10 +199,10 @@ var InverseE4Hint = func(_ *big.Int, inputs []*big.Int, res []*big.Int) error { c.Inverse(&a) - c.B0.A0.ToBigIntRegular(res[0]) - c.B0.A1.ToBigIntRegular(res[1]) - c.B1.A0.ToBigIntRegular(res[2]) - c.B1.A1.ToBigIntRegular(res[3]) + c.B0.A0.BigInt(res[0]) + c.B0.A1.BigInt(res[1]) + c.B1.A0.BigInt(res[2]) + c.B1.A1.BigInt(res[3]) return nil } diff --git a/std/algebra/sw_bls12377/g1_test.go b/std/algebra/sw_bls12377/g1_test.go index 8e921803a9..2a0a83a1a5 100644 --- a/std/algebra/sw_bls12377/g1_test.go +++ b/std/algebra/sw_bls12377/g1_test.go @@ -281,7 +281,7 @@ func TestConstantScalarMulG1(t *testing.T) { witness.A.Assign(&a) // compute the result br := new(big.Int) - r.ToBigIntRegular(br) + r.BigInt(br) // br is a circuit parameter circuit.R = br _a.ScalarMultiplication(&_a, br) @@ -321,7 +321,7 @@ func TestVarScalarMulG1(t *testing.T) { witness.A.Assign(&a) // compute the result var br big.Int - _a.ScalarMultiplication(&_a, r.ToBigIntRegular(&br)) + _a.ScalarMultiplication(&_a, r.BigInt(&br)) c.FromJacobian(&_a) witness.C.Assign(&c) @@ -361,7 +361,7 @@ func TestScalarMulG1(t *testing.T) { witness.A.Assign(&a) // compute the result var br big.Int - _a.ScalarMultiplication(&_a, r.ToBigIntRegular(&br)) + _a.ScalarMultiplication(&_a, r.BigInt(&br)) c.FromJacobian(&_a) witness.C.Assign(&c) @@ -376,7 +376,7 @@ func randomPointG1() bls12377.G1Jac { var r1 fr.Element var b big.Int _, _ = r1.SetRandom() - p1.ScalarMultiplication(&p1, r1.ToBigIntRegular(&b)) + p1.ScalarMultiplication(&p1, r1.BigInt(&b)) return p1 } diff --git a/std/algebra/sw_bls12377/g2_test.go b/std/algebra/sw_bls12377/g2_test.go index e647c96ac0..534a58b54c 100644 --- a/std/algebra/sw_bls12377/g2_test.go +++ b/std/algebra/sw_bls12377/g2_test.go @@ -287,7 +287,7 @@ func TestConstantScalarMulG2(t *testing.T) { witness.A.Assign(&a) // compute the result br := new(big.Int) - r.ToBigIntRegular(br) + r.BigInt(br) // br is a circuit parameter circuit.R = br _a.ScalarMultiplication(&_a, br) @@ -327,7 +327,7 @@ func TestVarScalarMulG2(t *testing.T) { witness.A.Assign(&a) // compute the result var br big.Int - _a.ScalarMultiplication(&_a, r.ToBigIntRegular(&br)) + _a.ScalarMultiplication(&_a, r.BigInt(&br)) c.FromJacobian(&_a) witness.C.Assign(&c) @@ -367,7 +367,7 @@ func TestScalarMulG2(t *testing.T) { witness.A.Assign(&a) // compute the result var br big.Int - _a.ScalarMultiplication(&_a, r.ToBigIntRegular(&br)) + _a.ScalarMultiplication(&_a, r.BigInt(&br)) c.FromJacobian(&_a) witness.C.Assign(&c) @@ -380,7 +380,7 @@ func randomPointG2() bls12377.G2Jac { var r1 fr.Element var b big.Int _, _ = r1.SetRandom() - p2.ScalarMultiplication(&p2, r1.ToBigIntRegular(&b)) + p2.ScalarMultiplication(&p2, r1.BigInt(&b)) return p2 } diff --git a/std/algebra/sw_bls24315/g2_test.go b/std/algebra/sw_bls24315/g2_test.go index 478be13146..0c8fb3ad20 100644 --- a/std/algebra/sw_bls24315/g2_test.go +++ b/std/algebra/sw_bls24315/g2_test.go @@ -287,7 +287,7 @@ func TestConstantScalarMulG2(t *testing.T) { witness.A.Assign(&a) // compute the result br := new(big.Int) - r.ToBigIntRegular(br) + r.BigInt(br) // br is a circuit parameter circuit.R = br _a.ScalarMultiplication(&_a, br) @@ -327,7 +327,7 @@ func TestVarScalarMulG2(t *testing.T) { witness.A.Assign(&a) // compute the result var br big.Int - _a.ScalarMultiplication(&_a, r.ToBigIntRegular(&br)) + _a.ScalarMultiplication(&_a, r.BigInt(&br)) c.FromJacobian(&_a) witness.C.Assign(&c) @@ -367,7 +367,7 @@ func TestScalarMulG2(t *testing.T) { witness.A.Assign(&a) // compute the result var br big.Int - _a.ScalarMultiplication(&_a, r.ToBigIntRegular(&br)) + _a.ScalarMultiplication(&_a, r.BigInt(&br)) c.FromJacobian(&_a) witness.C.Assign(&c) @@ -380,7 +380,7 @@ func randomPointG2() bls24315.G2Jac { var r1 fr.Element var b big.Int _, _ = r1.SetRandom() - p2.ScalarMultiplication(&p2, r1.ToBigIntRegular(&b)) + p2.ScalarMultiplication(&p2, r1.BigInt(&b)) return p2 } From 3da7cf738b951a45024cff7e213b282eb08a7db8 Mon Sep 17 00:00:00 2001 From: Arya Tabaie Date: Tue, 20 Dec 2022 15:15:33 -0600 Subject: [PATCH 06/71] feat: experiments with solving --- internal/gkr/bn254/circuit.go | 207 +++++++++++++++++++++++++++++++++ internal/gkr/bn254/prove.go | 1 + internal/gkr/bn254/solve.go | 91 +++++++++++++++ std/gkr/api.go | 127 ++++++++++++++++++++ std/gkr/api_test.go | 48 ++++++++ std/gkr/compile.go | 213 ++++++++++++++++++++++++++++++++++ std/gkr/gkr.go | 6 +- std/gkr/gkr_test.go | 6 +- std/gkr/prove_hint.go | 1 + std/gkr/solve_hint.go | 1 + 10 files changed, 695 insertions(+), 6 deletions(-) create mode 100644 internal/gkr/bn254/circuit.go create mode 100644 internal/gkr/bn254/prove.go create mode 100644 internal/gkr/bn254/solve.go create mode 100644 std/gkr/api.go create mode 100644 std/gkr/api_test.go create mode 100644 std/gkr/compile.go create mode 100644 std/gkr/prove_hint.go create mode 100644 std/gkr/solve_hint.go diff --git a/internal/gkr/bn254/circuit.go b/internal/gkr/bn254/circuit.go new file mode 100644 index 0000000000..e1be1b30ad --- /dev/null +++ b/internal/gkr/bn254/circuit.go @@ -0,0 +1,207 @@ +package bn254 + +import ( + "github.com/consensys/gnark-crypto/ecc/bn254/fr" + "github.com/consensys/gnark-crypto/ecc/bn254/fr/gkr" + "github.com/consensys/gnark/backend/hint" + "github.com/consensys/gnark/frontend" + genericGkr "github.com/consensys/gnark/std/gkr" + "math/big" +) + +func ConvertGate(gate genericGkr.Gate) gkr.Gate { + return gateConverter{gate: gate} +} + +func Map[T, S any](in []T, f func(T) S) []S { + out := make([]S, len(in)) + for i, t := range in { + out[i] = f(t) + } + return out +} + +func ConvertCircuit(d genericGkr.CircuitData) gkr.Circuit { + resCircuit := make(gkr.Circuit, len(d.Sorted)) + for i := range d.Sorted { + resCircuit[i].Gate = ConvertGate(d.Sorted[i].Gate) + resCircuit[i].Inputs = Map(d.CircuitInputsIndex[i], func(index int) *gkr.Wire { + return &resCircuit[i] + }) + } + return resCircuit +} + +type gateConverter struct { + gate genericGkr.Gate + api gateConversionApi +} + +func (c gateConverter) Degree() int { + return c.gate.Degree() +} + +func newGateConverter(gate genericGkr.Gate) gateConverter { + return gateConverter{ + gate: gate, + api: gateConversionApi{}, + } +} + +func elementSliceToVariableSlice(e []fr.Element) []frontend.Variable { + res := make([]frontend.Variable, len(e)) + for i := range res { + res[i] = e[i] + } + return res +} + +func (c gateConverter) Evaluate(ins ...fr.Element) fr.Element { + return c.gate.Evaluate(&c.api, elementSliceToVariableSlice(ins)...).(fr.Element) +} + +type gateConversionApi struct{} + +/*func forceElemPtr(elems []fr.Element, i1, i2 frontend.Variable, in ...frontend.Variable) []*fr.Element { + res := make([]*fr.Element, 2+len(in)) + res[0] = &elems[i1.(int)] + res[1] = &elems[i2.(int)] + for i := range in { + res[2+i] = &elems[in[i].(int)] + } +}*/ + +func varsToElems(i1, i2 frontend.Variable, in ...frontend.Variable) []fr.Element { + res := make([]fr.Element, 2+len(in)) + res[0] = i1.(fr.Element) + res[1] = i2.(fr.Element) + for i := range in { + res[2+i] = in[i].(fr.Element) + } + return res +} + +func (c *gateConversionApi) Add(i1, i2 frontend.Variable, in ...frontend.Variable) frontend.Variable { + //TODO implement me + panic("implement me") +} + +func (c *gateConversionApi) Neg(i1 frontend.Variable) frontend.Variable { + //TODO implement me + panic("implement me") +} + +func (c *gateConversionApi) Sub(i1, i2 frontend.Variable, in ...frontend.Variable) frontend.Variable { + //TODO implement me + panic("implement me") +} + +func (c *gateConversionApi) Mul(i1, i2 frontend.Variable, in ...frontend.Variable) frontend.Variable { + elems := varsToElems(i1, i2, in...) + var res fr.Element + res.Mul(&elems[0], &elems[1]) + for i := range in { + res.Mul(&res, &elems[i+2]) + } + return res +} + +func (c *gateConversionApi) DivUnchecked(i1, i2 frontend.Variable) frontend.Variable { + //TODO implement me + panic("implement me") +} + +func (c *gateConversionApi) Div(i1, i2 frontend.Variable) frontend.Variable { + //TODO implement me + panic("implement me") +} + +func (c *gateConversionApi) Inverse(i1 frontend.Variable) frontend.Variable { + //TODO implement me + panic("implement me") +} + +func (c *gateConversionApi) ToBinary(i1 frontend.Variable, n ...int) []frontend.Variable { + //TODO implement me + panic("implement me") +} + +func (c *gateConversionApi) FromBinary(b ...frontend.Variable) frontend.Variable { + //TODO implement me + panic("implement me") +} + +func (c *gateConversionApi) Xor(a, b frontend.Variable) frontend.Variable { + //TODO implement me + panic("implement me") +} + +func (c *gateConversionApi) Or(a, b frontend.Variable) frontend.Variable { + //TODO implement me + panic("implement me") +} + +func (c *gateConversionApi) And(a, b frontend.Variable) frontend.Variable { + //TODO implement me + panic("implement me") +} + +func (c *gateConversionApi) Select(b frontend.Variable, i1, i2 frontend.Variable) frontend.Variable { + //TODO implement me + panic("implement me") +} + +func (c *gateConversionApi) Lookup2(b0, b1 frontend.Variable, i0, i1, i2, i3 frontend.Variable) frontend.Variable { + //TODO implement me + panic("implement me") +} + +func (c *gateConversionApi) IsZero(i1 frontend.Variable) frontend.Variable { + //TODO implement me + panic("implement me") +} + +func (c *gateConversionApi) Cmp(i1, i2 frontend.Variable) frontend.Variable { + //TODO implement me + panic("implement me") +} + +func (c *gateConversionApi) AssertIsEqual(i1, i2 frontend.Variable) { + //TODO implement me + panic("implement me") +} + +func (c *gateConversionApi) AssertIsDifferent(i1, i2 frontend.Variable) { + //TODO implement me + panic("implement me") +} + +func (c *gateConversionApi) AssertIsBoolean(i1 frontend.Variable) { + //TODO implement me + panic("implement me") +} + +func (c *gateConversionApi) AssertIsLessOrEqual(v frontend.Variable, bound frontend.Variable) { + //TODO implement me + panic("implement me") +} + +func (c *gateConversionApi) Println(a ...frontend.Variable) { + //TODO implement me + panic("implement me") +} + +func (c *gateConversionApi) Compiler() frontend.Compiler { + //TODO implement me + panic("implement me") +} + +func (c *gateConversionApi) NewHint(f hint.Function, nbOutputs int, inputs ...frontend.Variable) ([]frontend.Variable, error) { + //TODO implement me + panic("implement me") +} + +func (c *gateConversionApi) ConstantValue(v frontend.Variable) (*big.Int, bool) { + //TODO implement me + panic("implement me") +} diff --git a/internal/gkr/bn254/prove.go b/internal/gkr/bn254/prove.go new file mode 100644 index 0000000000..32b83bb541 --- /dev/null +++ b/internal/gkr/bn254/prove.go @@ -0,0 +1 @@ +package bn254 diff --git a/internal/gkr/bn254/solve.go b/internal/gkr/bn254/solve.go new file mode 100644 index 0000000000..701a5a7e31 --- /dev/null +++ b/internal/gkr/bn254/solve.go @@ -0,0 +1,91 @@ +package bn254 + +import ( + "github.com/consensys/gnark-crypto/ecc/bn254/fr" + "github.com/consensys/gnark-crypto/ecc/bn254/fr/gkr" + "github.com/consensys/gnark-crypto/ecc/bn254/fr/polynomial" + genericGkr "github.com/consensys/gnark/std/gkr" +) + +type solvingStatus byte + +const ( + unsolved solvingStatus = 0 + beingSolved = 1 + solved = 2 +) + +type solver struct { + assignment [][]fr.Element //wire first, instance second + d genericGkr.CircuitData + circuit gkr.Circuit + status []solvingStatus + offsets []int // per wire + pool polynomial.Pool +} + +// solve the i'th instance +func (s solver) solve(i int) { + if s.status[i] == solved { + return + } + if s.status[i] == beingSolved { + panic("circular dependency among instances") + } + inputI := 0 + for j, J := range s.d.InputIndexes { + offset := s.offsets[inputI] + dependencyWireIndex := s.d.InputDependencies[i][j].OutputWireIndex + + if dependencyWireIndex == -1 { // no dependency + s.assignment[J][i].SetBigInt(s.d.AssignmentVector[offset+i]) + inputI++ + } else { + dependencyInstance := s.d.InputDependencies[i][j].OutputInstance + s.solve(dependencyInstance) + s.assignment[J][i] = s.assignment[dependencyWireIndex][dependencyInstance] + } + } + s.complete(i) //TODO: This duplicates some of gkr.Complete in gnark-crypto + s.status[i] = solved +} + +// complete computes the assignments of an instance given input assignments +func (s solver) complete(i int) { + circuit := s.d.CircuitInputsIndex + ins := s.pool.Make(s.d.MaxGateDegree) + for j := range circuit { + n := len(circuit[j]) + for k := 0; k < n; k++ { + ins[k] = s.assignment[circuit[j][k]][i] + } + + s.assignment[j][i] = s.circuit[j].Gate.Evaluate(ins[:n]...) + } + s.pool.Dump(ins) +} + +func Solve(circuitData genericGkr.CircuitData, circuit gkr.Circuit) gkr.WireAssignment { + solver := solver{ + assignment: make([][]fr.Element, len(circuit)), + d: circuitData, + circuit: circuit, + status: make([]solvingStatus, circuitData.NbInstances), + offsets: make([]int, len(circuit)), + } + + solver.offsets[0] = 0 + for j := 0; j+1 < len(circuit); j++ { + solver.offsets[j+1] = solver.offsets[j] + circuitData.NbInstances - circuitData.InputDependencies.NbDependencies(j) + } + + for i := 0; i < circuitData.NbInstances; i++ { + solver.solve(i) + } + + res := make(gkr.WireAssignment, len(circuit)) + for i := range circuit { + res[&circuit[i]] = solver.assignment[i] + } + return res +} diff --git a/std/gkr/api.go b/std/gkr/api.go new file mode 100644 index 0000000000..948e51ac96 --- /dev/null +++ b/std/gkr/api.go @@ -0,0 +1,127 @@ +package gkr + +import ( + "github.com/consensys/gnark/backend/hint" + "github.com/consensys/gnark/frontend" + "math/big" +) + +func (i *API) Add(i1, i2 frontend.Variable, in ...frontend.Variable) frontend.Variable { + //TODO implement me + panic("implement me") +} + +func (i *API) Neg(i1 frontend.Variable) frontend.Variable { + //TODO implement me + panic("implement me") +} + +func (i *API) Sub(i1, i2 frontend.Variable, in ...frontend.Variable) frontend.Variable { + //TODO implement me + panic("implement me") +} + +func (i *API) Mul(i1, i2 frontend.Variable, in ...frontend.Variable) frontend.Variable { + //TODO implement me + panic("implement me") +} + +func (i *API) DivUnchecked(i1, i2 frontend.Variable) frontend.Variable { + //TODO implement me + panic("implement me") +} + +func (i *API) Div(i1, i2 frontend.Variable) frontend.Variable { + //TODO implement me + panic("implement me") +} + +func (i *API) Inverse(i1 frontend.Variable) frontend.Variable { + //TODO implement me + panic("implement me") +} + +func (i *API) ToBinary(i1 frontend.Variable, n ...int) []frontend.Variable { + //TODO implement me + panic("implement me") +} + +func (i *API) FromBinary(b ...frontend.Variable) frontend.Variable { + //TODO implement me + panic("implement me") +} + +func (i *API) Xor(a, b frontend.Variable) frontend.Variable { + //TODO implement me + panic("implement me") +} + +func (i *API) Or(a, b frontend.Variable) frontend.Variable { + //TODO implement me + panic("implement me") +} + +func (i *API) And(a, b frontend.Variable) frontend.Variable { + //TODO implement me + panic("implement me") +} + +func (i *API) Select(b frontend.Variable, i1, i2 frontend.Variable) frontend.Variable { + //TODO implement me + panic("implement me") +} + +func (i *API) Lookup2(b0, b1 frontend.Variable, i0, i1, i2, i3 frontend.Variable) frontend.Variable { + //TODO implement me + panic("implement me") +} + +func (i *API) IsZero(i1 frontend.Variable) frontend.Variable { + //TODO implement me + panic("implement me") +} + +func (i *API) Cmp(i1, i2 frontend.Variable) frontend.Variable { + //TODO implement me + panic("implement me") +} + +func (i *API) AssertIsEqual(i1, i2 frontend.Variable) { + //TODO implement me + panic("implement me") +} + +func (i *API) AssertIsDifferent(i1, i2 frontend.Variable) { + //TODO implement me + panic("implement me") +} + +func (i *API) AssertIsBoolean(i1 frontend.Variable) { + //TODO implement me + panic("implement me") +} + +func (i *API) AssertIsLessOrEqual(v frontend.Variable, bound frontend.Variable) { + //TODO implement me + panic("implement me") +} + +func (i *API) Println(a ...frontend.Variable) { + //TODO implement me + panic("implement me") +} + +func (i *API) Compiler() frontend.Compiler { + //TODO implement me + panic("implement me") +} + +func (i *API) NewHint(f hint.Function, nbOutputs int, inputs ...frontend.Variable) ([]frontend.Variable, error) { + //TODO implement me + panic("implement me") +} + +func (i *API) ConstantValue(v frontend.Variable) (*big.Int, bool) { + //TODO implement me + panic("implement me") +} diff --git a/std/gkr/api_test.go b/std/gkr/api_test.go new file mode 100644 index 0000000000..08c57c5d6f --- /dev/null +++ b/std/gkr/api_test.go @@ -0,0 +1,48 @@ +package gkr + +import ( + "github.com/consensys/gnark-crypto/ecc" + "github.com/consensys/gnark/backend" + "github.com/consensys/gnark/frontend" + "github.com/consensys/gnark/test" + "testing" +) + +type mulNoDependencyCircuit struct { + X, Y []frontend.Variable +} + +func (c *mulNoDependencyCircuit) Define(api frontend.API) error { + gkr := NewApi() + var x, y frontend.Variable + var err error + if x, err = gkr.Import(c.X); err != nil { + return err + } + if y, err = gkr.Import(c.Y); err != nil { + return err + } + gkr.Mul(x, y) + var gkrOuts [][]frontend.Variable + if gkrOuts, err = gkr.Compile(api); err != nil { + return err + } + Z := gkrOuts[0] + + for i := range c.X { + api.AssertIsEqual(Z[i], api.Mul(c.X[i], c.Y[i])) + } + return nil +} + +func TestSolveMulNoDependency(t *testing.T) { + assignment := mulNoDependencyCircuit{ + X: []frontend.Variable{1, 2}, + Y: []frontend.Variable{2, 3}, + } + circuit := mulNoDependencyCircuit{ + X: make([]frontend.Variable, 2), + Y: make([]frontend.Variable, 2), + } + test.NewAssert(t).SolvingSucceeded(&circuit, &assignment, test.WithBackends(backend.GROTH16), test.WithCurves(ecc.BN254)) +} diff --git a/std/gkr/compile.go b/std/gkr/compile.go new file mode 100644 index 0000000000..c4890a2929 --- /dev/null +++ b/std/gkr/compile.go @@ -0,0 +1,213 @@ +package gkr + +import ( + "fmt" + "github.com/consensys/gnark/frontend" + "math/big" + "math/bits" +) + +type API struct { + compiled bool + logNbInstances int + circuitData CircuitData + circuit Circuit + assignments map[Variable][]frontend.Variable +} + +type CircuitData struct { + Sorted []*Wire + CircuitInputsIndex [][]int + NbInstances int + AssignmentVector []*big.Int + InputDependencies inputDependencies // InputDependencies indexes first by instance then input wire + InputIndexes []int + MaxGateDegree int +} + +type Variable *Wire + +type InputDependency struct { + Output Variable + OutputInstance int +} + +type IndexedInputDependency struct { + OutputInstance int + OutputWireIndex int +} + +func (i *API) NbInstances() int { + return 1 << i.logNbInstances +} + +func NewApi() *API { + return &API{circuit: make(Circuit, 0), assignments: make(map[Variable][]frontend.Variable)} + /*var res API + res.inOutEqualities = make([][2]int, len(inOutEqualities)) + copy(res.inOutEqualities, inOutEqualities) + sort.Slice(res.inOutEqualities, func(i int, j int) bool { + if res.inOutEqualities[i][0] < res.inOutEqualities[j][0] { + return true + } + return res.inOutEqualities[i][1] < res.inOutEqualities[j][1] + }) + + + if len(inOutEqualities) == 0 { + res.nbOutputBoundIns = 0 + } else { + res.nbOutputBoundIns = 1 + for i := 1; i < len(res.inOutEqualities); i++ { + if res.inOutEqualities[i][0] != res.inOutEqualities[i][1] { + + } + } + } + res.inOutEqualities = inOutEqualities + res.circuit = make(Circuit, 0, len(inOutEqualities)) + + return res*/ +} + +func logNbInstances(nbInstances uint) int { + if bits.OnesCount(nbInstances) != 1 { + return -1 + } + return bits.LeadingZeros(nbInstances) +} + +func (i *API) Series(input, output Variable, inputInstance, outputInstance int) *API { + i.assignments[input][inputInstance] = InputDependency{ + Output: output, + OutputInstance: outputInstance, + } + return i +} + +func (i *API) Import(assignment []frontend.Variable) (Variable, error) { + if i.compiled { + return nil, fmt.Errorf("cannot import variables into compiled circuit") + } + nbInstances := uint(len(assignment)) + logNbInstances := logNbInstances(nbInstances) + if logNbInstances == -1 { + return nil, fmt.Errorf("number of assignments must be a power of 2") + } + if logNbInstances != i.logNbInstances { + return nil, fmt.Errorf("number of assignments must be consistent across all variables") + } + i.circuit = append(i.circuit, Wire{ + Gate: nil, + Inputs: []*Wire{}, + }) + return &i.circuit[len(i.circuit)-1], nil +} + +func (i *API) nbInputValueAssignments(variable Variable) int { + res := 0 + for j := range i.assignments[variable] { + if _, ok := i.assignments[variable][j].(InputDependency); !ok { + res++ + } + } + return res +} + +// Compile finalizes the GKR circuit and returns the output variables in the order created +func (i *API) Compile(parentApi frontend.API) ([][]frontend.Variable, error) { + if i.compiled { + return nil, fmt.Errorf("already compiled") + } + i.compiled = true + + i.circuitData.Sorted = TopologicalSort(i.circuit) + i.circuitData.NbInstances = 1 << i.logNbInstances + indexes := circuitIndexMap(i.circuitData.Sorted) + i.circuitData.CircuitInputsIndex, i.circuitData.InputIndexes = + circuitInputsIndex(i.circuitData.Sorted, indexes) + + solveHintNIn := 0 + //solveHintNOut := ProofSize(i.circuit, i.logNbInstances) + solveHintNOut := 0 + for j := range i.circuit { + v := &i.circuit[j] + if v.IsInput() { + solveHintNIn += i.nbInputValueAssignments(v) + } else if v.IsOutput() { + solveHintNOut += i.circuitData.NbInstances + } + } + + ins := make([]frontend.Variable, 0, solveHintNIn) + for j := range i.circuit { + if i.circuit[j].IsInput() { + assignment := i.assignments[&i.circuit[j]] + for k := range assignment { + if _, ok := assignment[k].(InputDependency); !ok { + ins = append(ins, assignment[k]) + } + } + } + } + + solveHint := func(mod *big.Int, ins []*big.Int, outs []*big.Int) error { + return fmt.Errorf("not implemented") + } + + outsSerialized, err := parentApi.Compiler().NewHint(solveHint, solveHintNOut, ins...) + if err != nil { + return nil, err + } + + outs := make([][]frontend.Variable, len(outsSerialized)/i.circuitData.NbInstances) + + offset := 0 + for j := range outs { + outs[j] = outsSerialized[offset : offset+i.circuitData.NbInstances] + offset += i.circuitData.NbInstances + } + + return outs, nil +} + +// Verify produces a subcircuit guaranteeing the correctness of the solved values +func (i *API) Verify(statement []frontend.Variable) error { + return fmt.Errorf("not implemented") +} + +func circuitIndexMap(sorted []*Wire) map[*Wire]int { + indexes := make(map[*Wire]int, len(sorted)) + for i := range sorted { + indexes[sorted[i]] = i + } + return indexes +} + +func circuitInputsIndex(sorted []*Wire, indexes map[*Wire]int) ([][]int, []int) { + res := make([][]int, len(sorted)) + inputIndexes := make([]int, 0) + for i, w := range sorted { + if w.IsInput() { + inputIndexes = append(inputIndexes, i) + } + res[i] = make([]int, len(w.Inputs)) + for j, v := range w.Inputs { + res[i][j] = indexes[v] + } + } + + return res, inputIndexes +} + +type inputDependencies [][]IndexedInputDependency + +func (d inputDependencies) NbDependencies(inputIndex int) int { + count := 0 + for _, instance := range d { + if instance[inputIndex].OutputWireIndex != -1 { + count++ + } + } + return count +} diff --git a/std/gkr/gkr.go b/std/gkr/gkr.go index 1e9640314f..38468e5cec 100644 --- a/std/gkr/gkr.go +++ b/std/gkr/gkr.go @@ -194,7 +194,7 @@ func setup(api frontend.API, c Circuit, assignment WireAssignment, transcriptSet } if o.sorted == nil { - o.sorted = topologicalSort(c) + o.sorted = TopologicalSort(c) } if transcriptSettings.Transcript == nil { @@ -425,12 +425,12 @@ func statusList(c Circuit) []int { return res } -// topologicalSort sorts the wires in order of dependence. Such that for any wire, any one it depends on +// TopologicalSort sorts the wires in order of dependence. Such that for any wire, any one it depends on // occurs before it. It tries to stick to the input order as much as possible. An already sorted list will remain unchanged. // It also sets the nbOutput flags, and a dummy IdentityGate for input wires. // Worst-case inefficient O(n^2), but that probably won't matter since the circuits are small. // Furthermore, it is efficient with already-close-to-sorted lists, which are the expected input -func topologicalSort(c Circuit) []*Wire { +func TopologicalSort(c Circuit) []*Wire { var data topSortData data.index = indexMap(c) data.outputs = outputsList(c, data.index) diff --git a/std/gkr/gkr_test.go b/std/gkr/gkr_test.go index 5e68171452..be56cdbb30 100644 --- a/std/gkr/gkr_test.go +++ b/std/gkr/gkr_test.go @@ -104,7 +104,7 @@ func (c *GkrVerifierCircuit) Define(api frontend.API) error { if testCase, err = getTestCase(c.TestCaseName); err != nil { return err } - sorted := topologicalSort(testCase.Circuit) + sorted := TopologicalSort(testCase.Circuit) if proof, err = DeserializeProof(sorted, c.SerializedProof); err != nil { return err @@ -120,7 +120,7 @@ func (c *GkrVerifierCircuit) Define(api frontend.API) error { } func makeInOutAssignment(c Circuit, inputValues [][]frontend.Variable, outputValues [][]frontend.Variable) WireAssignment { - sorted := topologicalSort(c) + sorted := TopologicalSort(c) res := make(WireAssignment, len(inputValues)+len(outputValues)) inI, outI := 0, 0 for _, w := range sorted { @@ -335,7 +335,7 @@ func TestLogNbInstances(t *testing.T) { return func(t *testing.T) { testCase, err := getTestCase(path) assert.NoError(t, err) - wires := topologicalSort(testCase.Circuit) + wires := TopologicalSort(testCase.Circuit) serializedProof := testCase.Proof.Serialize() logNbInstances := computeLogNbInstances(wires, len(serializedProof)) assert.Equal(t, 1, logNbInstances) diff --git a/std/gkr/prove_hint.go b/std/gkr/prove_hint.go new file mode 100644 index 0000000000..10cd5e6a54 --- /dev/null +++ b/std/gkr/prove_hint.go @@ -0,0 +1 @@ +package gkr diff --git a/std/gkr/solve_hint.go b/std/gkr/solve_hint.go new file mode 100644 index 0000000000..10cd5e6a54 --- /dev/null +++ b/std/gkr/solve_hint.go @@ -0,0 +1 @@ +package gkr From 986f62a50ebb2ffa585ed2b2531220a8ed8e4b1d Mon Sep 17 00:00:00 2001 From: Arya Tabaie Date: Wed, 4 Jan 2023 13:36:30 -0500 Subject: [PATCH 07/71] chore: some efforts from before christmas break --- go.mod | 4 ++- internal/gkr/bn254/circuit.go | 7 ++--- internal/gkr/bn254/solve.go | 28 +++++++++++++++++--- internal/gkr/gkr.go | 20 ++++++++++++++ internal/gkr/utils/utils.go | 1 + std/gkr/api.go | 30 +++++++++++++++++++-- std/gkr/api_test.go | 2 +- std/gkr/compile.go | 49 ++++++++++++++++++----------------- std/gkr/gkr.go | 19 +++++++++++--- std/gkr/gkr_test.go | 21 +++------------ 10 files changed, 127 insertions(+), 54 deletions(-) create mode 100644 internal/gkr/gkr.go create mode 100644 internal/gkr/utils/utils.go diff --git a/go.mod b/go.mod index 63c2801da6..4251dce434 100644 --- a/go.mod +++ b/go.mod @@ -26,4 +26,6 @@ require ( gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect gopkg.in/yaml.v3 v3.0.1 // indirect rsc.io/tmplfunc v0.0.3 // indirect -) \ No newline at end of file +) + +replace "github.com/consensys/gnark-crypto" => "/Users/arya/gnark-crypto" \ No newline at end of file diff --git a/internal/gkr/bn254/circuit.go b/internal/gkr/bn254/circuit.go index e1be1b30ad..7308136d76 100644 --- a/internal/gkr/bn254/circuit.go +++ b/internal/gkr/bn254/circuit.go @@ -6,10 +6,11 @@ import ( "github.com/consensys/gnark/backend/hint" "github.com/consensys/gnark/frontend" genericGkr "github.com/consensys/gnark/std/gkr" + "github.com/consensys/gnark/std/gkr/api" "math/big" ) -func ConvertGate(gate genericGkr.Gate) gkr.Gate { +func convertGate(gate genericGkr.Gate) gkr.Gate { return gateConverter{gate: gate} } @@ -21,10 +22,10 @@ func Map[T, S any](in []T, f func(T) S) []S { return out } -func ConvertCircuit(d genericGkr.CircuitData) gkr.Circuit { +func convertCircuit(d *api.CircuitData) gkr.Circuit { resCircuit := make(gkr.Circuit, len(d.Sorted)) for i := range d.Sorted { - resCircuit[i].Gate = ConvertGate(d.Sorted[i].Gate) + resCircuit[i].Gate = convertGate(d.Sorted[i].Gate) resCircuit[i].Inputs = Map(d.CircuitInputsIndex[i], func(index int) *gkr.Wire { return &resCircuit[i] }) diff --git a/internal/gkr/bn254/solve.go b/internal/gkr/bn254/solve.go index 701a5a7e31..6ea9fd3ed8 100644 --- a/internal/gkr/bn254/solve.go +++ b/internal/gkr/bn254/solve.go @@ -4,7 +4,8 @@ import ( "github.com/consensys/gnark-crypto/ecc/bn254/fr" "github.com/consensys/gnark-crypto/ecc/bn254/fr/gkr" "github.com/consensys/gnark-crypto/ecc/bn254/fr/polynomial" - genericGkr "github.com/consensys/gnark/std/gkr" + //stdGkr "github.com/consensys/gnark/std/gkr" + "math/big" ) type solvingStatus byte @@ -17,7 +18,7 @@ const ( type solver struct { assignment [][]fr.Element //wire first, instance second - d genericGkr.CircuitData + d *stdGkr.CircuitData circuit gkr.Circuit status []solvingStatus offsets []int // per wire @@ -65,7 +66,7 @@ func (s solver) complete(i int) { s.pool.Dump(ins) } -func Solve(circuitData genericGkr.CircuitData, circuit gkr.Circuit) gkr.WireAssignment { +func Solve(circuitData *stdGkr.CircuitData, circuit gkr.Circuit) gkr.WireAssignment { solver := solver{ assignment: make([][]fr.Element, len(circuit)), d: circuitData, @@ -89,3 +90,24 @@ func Solve(circuitData genericGkr.CircuitData, circuit gkr.Circuit) gkr.WireAssi } return res } + +func SolveHint(data interface{}, ins []*big.Int, outs []*big.Int) error { + circuitData := data.(*stdGkr.CircuitData) + circuit := convertCircuit(circuitData) + circuitData.TypedCircuit = circuit + circuitData.AssignmentVector = ins + assignments := Solve(circuitData, circuit) + circuitData.TypedAssignment = assignments + + outI := 0 + for i, w := range circuitData.Sorted { + if w.IsOutput() { + assignmentW := assignments[&circuit[i]] + for j := range assignmentW { + assignmentW[outI].BigInt(outs[outI+j]) + } + } + } + + return nil +} diff --git a/internal/gkr/gkr.go b/internal/gkr/gkr.go new file mode 100644 index 0000000000..ec7cea2612 --- /dev/null +++ b/internal/gkr/gkr.go @@ -0,0 +1,20 @@ +package gkr + +import ( + "fmt" + bn254Fr "github.com/consensys/gnark-crypto/ecc/bn254/fr" + "github.com/consensys/gnark/internal/gkr/bn254" + "math/big" +) + +// hack to avoid import cycles. find out how to avoid + +func SolveHint(data interface{}) func(*big.Int, []*big.Int, []*big.Int) error { + return func(mod *big.Int, ins []*big.Int, outs []*big.Int) error { + switch mod { + case bn254Fr.Modulus(): + return bn254.SolveHint(data, ins, outs) + } + return fmt.Errorf("unknow modulus") + } +} diff --git a/internal/gkr/utils/utils.go b/internal/gkr/utils/utils.go new file mode 100644 index 0000000000..d4b585bf78 --- /dev/null +++ b/internal/gkr/utils/utils.go @@ -0,0 +1 @@ +package utils diff --git a/std/gkr/api.go b/std/gkr/api.go index 948e51ac96..e2acb520e4 100644 --- a/std/gkr/api.go +++ b/std/gkr/api.go @@ -6,6 +6,33 @@ import ( "math/big" ) +func Map[T, S any](in []T, f func(T) S) []S { + out := make([]S, len(in)) + for i, t := range in { + out[i] = f(t) + } + return out +} + +func frontendVarToPtr(a frontend.Variable) *Wire { + return a.(Variable) +} + +func (i *API) newVar(gate Gate, in []frontend.Variable) Variable { + i.circuit = append(i.circuit, Wire{Gate: gate, Inputs: Map(in, frontendVarToPtr)}) + return &i.circuit[len(i.circuit)-1] +} + +func (i *API) newVar2PlusIn(gate Gate, in1, in2 frontend.Variable, in ...frontend.Variable) Variable { + inCombined := make([]frontend.Variable, 2+len(in)) + inCombined[0] = in1 + inCombined[1] = in2 + for i := range in { + inCombined[i+2] = in[i] + } + return i.newVar(gate, inCombined) +} + func (i *API) Add(i1, i2 frontend.Variable, in ...frontend.Variable) frontend.Variable { //TODO implement me panic("implement me") @@ -22,8 +49,7 @@ func (i *API) Sub(i1, i2 frontend.Variable, in ...frontend.Variable) frontend.Va } func (i *API) Mul(i1, i2 frontend.Variable, in ...frontend.Variable) frontend.Variable { - //TODO implement me - panic("implement me") + return i.newVar2PlusIn(MulGate{}, i1, i2, in...) } func (i *API) DivUnchecked(i1, i2 frontend.Variable) frontend.Variable { diff --git a/std/gkr/api_test.go b/std/gkr/api_test.go index 08c57c5d6f..68b464e3c8 100644 --- a/std/gkr/api_test.go +++ b/std/gkr/api_test.go @@ -13,7 +13,7 @@ type mulNoDependencyCircuit struct { } func (c *mulNoDependencyCircuit) Define(api frontend.API) error { - gkr := NewApi() + gkr := NewGkrApi() var x, y frontend.Variable var err error if x, err = gkr.Import(c.X); err != nil { diff --git a/std/gkr/compile.go b/std/gkr/compile.go index c4890a2929..91dd06da74 100644 --- a/std/gkr/compile.go +++ b/std/gkr/compile.go @@ -3,7 +3,7 @@ package gkr import ( "fmt" "github.com/consensys/gnark/frontend" - "math/big" + "github.com/consensys/gnark/internal/gkr" "math/bits" ) @@ -17,32 +17,19 @@ type API struct { type CircuitData struct { Sorted []*Wire - CircuitInputsIndex [][]int NbInstances int - AssignmentVector []*big.Int - InputDependencies inputDependencies // InputDependencies indexes first by instance then input wire + CircuitInputsIndex [][]int InputIndexes []int - MaxGateDegree int } type Variable *Wire -type InputDependency struct { - Output Variable - OutputInstance int -} - -type IndexedInputDependency struct { - OutputInstance int - OutputWireIndex int -} - func (i *API) NbInstances() int { return 1 << i.logNbInstances } -func NewApi() *API { - return &API{circuit: make(Circuit, 0), assignments: make(map[Variable][]frontend.Variable)} +func NewGkrApi() *API { + return &API{circuit: make(Circuit, 0), assignments: make(map[Variable][]frontend.Variable), logNbInstances: -1} /*var res API res.inOutEqualities = make([][2]int, len(inOutEqualities)) copy(res.inOutEqualities, inOutEqualities) @@ -74,7 +61,7 @@ func logNbInstances(nbInstances uint) int { if bits.OnesCount(nbInstances) != 1 { return -1 } - return bits.LeadingZeros(nbInstances) + return bits.TrailingZeros(nbInstances) } func (i *API) Series(input, output Variable, inputInstance, outputInstance int) *API { @@ -94,7 +81,9 @@ func (i *API) Import(assignment []frontend.Variable) (Variable, error) { if logNbInstances == -1 { return nil, fmt.Errorf("number of assignments must be a power of 2") } - if logNbInstances != i.logNbInstances { + if i.logNbInstances == -1 { + i.logNbInstances = logNbInstances + } else if logNbInstances != i.logNbInstances { return nil, fmt.Errorf("number of assignments must be consistent across all variables") } i.circuit = append(i.circuit, Wire{ @@ -121,7 +110,7 @@ func (i *API) Compile(parentApi frontend.API) ([][]frontend.Variable, error) { } i.compiled = true - i.circuitData.Sorted = TopologicalSort(i.circuit) + i.circuitData.Sorted = topologicalSort(i.circuit) i.circuitData.NbInstances = 1 << i.logNbInstances indexes := circuitIndexMap(i.circuitData.Sorted) i.circuitData.CircuitInputsIndex, i.circuitData.InputIndexes = @@ -151,9 +140,11 @@ func (i *API) Compile(parentApi frontend.API) ([][]frontend.Variable, error) { } } - solveHint := func(mod *big.Int, ins []*big.Int, outs []*big.Int) error { - return fmt.Errorf("not implemented") - } + i.circuitData.Sorted = topologicalSort(i.circuit) + indexMap := circuitIndexMap(i.circuitData.Sorted) + i.circuitData.CircuitInputsIndex, i.circuitData.InputIndexes = circuitInputsIndex(i.circuitData.Sorted, indexMap) + + solveHint := gkr.SolveHint(&i.circuitData) outsSerialized, err := parentApi.Compiler().NewHint(solveHint, solveHintNOut, ins...) if err != nil { @@ -200,7 +191,17 @@ func circuitInputsIndex(sorted []*Wire, indexes map[*Wire]int) ([][]int, []int) return res, inputIndexes } -type inputDependencies [][]IndexedInputDependency +type InputDependency struct { + Output *Wire + OutputInstance int +} + +type IndexedInputDependency struct { + OutputInstance int + OutputWireIndex int +} + +type inputDependencies [][]IndexedInputDependency // instance first, then wire func (d inputDependencies) NbDependencies(inputIndex int) int { count := 0 diff --git a/std/gkr/gkr.go b/std/gkr/gkr.go index 38468e5cec..0cf65a7e93 100644 --- a/std/gkr/gkr.go +++ b/std/gkr/gkr.go @@ -194,7 +194,7 @@ func setup(api frontend.API, c Circuit, assignment WireAssignment, transcriptSet } if o.sorted == nil { - o.sorted = TopologicalSort(c) + o.sorted = topologicalSort(c) } if transcriptSettings.Transcript == nil { @@ -425,12 +425,12 @@ func statusList(c Circuit) []int { return res } -// TopologicalSort sorts the wires in order of dependence. Such that for any wire, any one it depends on +// topologicalSort sorts the wires in order of dependence. Such that for any wire, any one it depends on // occurs before it. It tries to stick to the input order as much as possible. An already sorted list will remain unchanged. // It also sets the nbOutput flags, and a dummy IdentityGate for input wires. // Worst-case inefficient O(n^2), but that probably won't matter since the circuits are small. // Furthermore, it is efficient with already-close-to-sorted lists, which are the expected input -func TopologicalSort(c Circuit) []*Wire { +func topologicalSort(c Circuit) []*Wire { var data topSortData data.index = indexMap(c) data.outputs = outputsList(c, data.index) @@ -526,3 +526,16 @@ func DeserializeProof(sorted []*Wire, serializedProof []frontend.Variable) (Proo } return proof, nil } + +type MulGate struct{} + +func (g MulGate) Evaluate(api frontend.API, x ...frontend.Variable) frontend.Variable { + if len(x) != 2 { + panic("mul has fan-in 2") + } + return api.Mul(x[0], x[1]) +} + +func (g MulGate) Degree() int { + return 2 +} diff --git a/std/gkr/gkr_test.go b/std/gkr/gkr_test.go index be56cdbb30..f436737f61 100644 --- a/std/gkr/gkr_test.go +++ b/std/gkr/gkr_test.go @@ -104,7 +104,7 @@ func (c *GkrVerifierCircuit) Define(api frontend.API) error { if testCase, err = getTestCase(c.TestCaseName); err != nil { return err } - sorted := TopologicalSort(testCase.Circuit) + sorted := topologicalSort(testCase.Circuit) if proof, err = DeserializeProof(sorted, c.SerializedProof); err != nil { return err @@ -120,7 +120,7 @@ func (c *GkrVerifierCircuit) Define(api frontend.API) error { } func makeInOutAssignment(c Circuit, inputValues [][]frontend.Variable, outputValues [][]frontend.Variable) WireAssignment { - sorted := TopologicalSort(c) + sorted := topologicalSort(c) res := make(WireAssignment, len(inputValues)+len(outputValues)) inI, outI := 0, 0 for _, w := range sorted { @@ -254,24 +254,11 @@ var gates map[string]Gate func init() { gates = make(map[string]Gate) gates["identity"] = IdentityGate{} - gates["mul"] = mulGate{} + gates["mul"] = MulGate{} gates["mimc"] = mimcCipherGate{ark: 0} //TODO: Add ark gates["select-input-3"] = _select(2) } -type mulGate struct{} - -func (g mulGate) Evaluate(api frontend.API, x ...frontend.Variable) frontend.Variable { - if len(x) != 2 { - panic("mul has fan-in 2") - } - return api.Mul(x[0], x[1]) -} - -func (g mulGate) Degree() int { - return 2 -} - type mimcCipherGate struct { ark frontend.Variable } @@ -335,7 +322,7 @@ func TestLogNbInstances(t *testing.T) { return func(t *testing.T) { testCase, err := getTestCase(path) assert.NoError(t, err) - wires := TopologicalSort(testCase.Circuit) + wires := topologicalSort(testCase.Circuit) serializedProof := testCase.Proof.Serialize() logNbInstances := computeLogNbInstances(wires, len(serializedProof)) assert.Equal(t, 1, logNbInstances) From 62df360143667307825f8007594b8266f1b7dc6c Mon Sep 17 00:00:00 2001 From: Arya Tabaie Date: Wed, 4 Jan 2023 16:17:58 -0500 Subject: [PATCH 08/71] refactor: all in one package --- internal/gkr/bn254/prove.go | 1 - internal/gkr/bn254/solve.go | 113 ------------ internal/gkr/gkr.go | 20 --- internal/gkr/utils/utils.go | 1 - std/gkr/api.go | 8 - .../circuit.go => std/gkr/bn254_circuit.go | 30 ++-- std/gkr/bn254_solve.go | 112 ++++++++++++ std/gkr/compile.go | 165 +++++++++++------- std/gkr/utils.go | 9 + 9 files changed, 231 insertions(+), 228 deletions(-) delete mode 100644 internal/gkr/bn254/prove.go delete mode 100644 internal/gkr/bn254/solve.go delete mode 100644 internal/gkr/gkr.go delete mode 100644 internal/gkr/utils/utils.go rename internal/gkr/bn254/circuit.go => std/gkr/bn254_circuit.go (86%) create mode 100644 std/gkr/bn254_solve.go create mode 100644 std/gkr/utils.go diff --git a/internal/gkr/bn254/prove.go b/internal/gkr/bn254/prove.go deleted file mode 100644 index 32b83bb541..0000000000 --- a/internal/gkr/bn254/prove.go +++ /dev/null @@ -1 +0,0 @@ -package bn254 diff --git a/internal/gkr/bn254/solve.go b/internal/gkr/bn254/solve.go deleted file mode 100644 index 6ea9fd3ed8..0000000000 --- a/internal/gkr/bn254/solve.go +++ /dev/null @@ -1,113 +0,0 @@ -package bn254 - -import ( - "github.com/consensys/gnark-crypto/ecc/bn254/fr" - "github.com/consensys/gnark-crypto/ecc/bn254/fr/gkr" - "github.com/consensys/gnark-crypto/ecc/bn254/fr/polynomial" - //stdGkr "github.com/consensys/gnark/std/gkr" - "math/big" -) - -type solvingStatus byte - -const ( - unsolved solvingStatus = 0 - beingSolved = 1 - solved = 2 -) - -type solver struct { - assignment [][]fr.Element //wire first, instance second - d *stdGkr.CircuitData - circuit gkr.Circuit - status []solvingStatus - offsets []int // per wire - pool polynomial.Pool -} - -// solve the i'th instance -func (s solver) solve(i int) { - if s.status[i] == solved { - return - } - if s.status[i] == beingSolved { - panic("circular dependency among instances") - } - inputI := 0 - for j, J := range s.d.InputIndexes { - offset := s.offsets[inputI] - dependencyWireIndex := s.d.InputDependencies[i][j].OutputWireIndex - - if dependencyWireIndex == -1 { // no dependency - s.assignment[J][i].SetBigInt(s.d.AssignmentVector[offset+i]) - inputI++ - } else { - dependencyInstance := s.d.InputDependencies[i][j].OutputInstance - s.solve(dependencyInstance) - s.assignment[J][i] = s.assignment[dependencyWireIndex][dependencyInstance] - } - } - s.complete(i) //TODO: This duplicates some of gkr.Complete in gnark-crypto - s.status[i] = solved -} - -// complete computes the assignments of an instance given input assignments -func (s solver) complete(i int) { - circuit := s.d.CircuitInputsIndex - ins := s.pool.Make(s.d.MaxGateDegree) - for j := range circuit { - n := len(circuit[j]) - for k := 0; k < n; k++ { - ins[k] = s.assignment[circuit[j][k]][i] - } - - s.assignment[j][i] = s.circuit[j].Gate.Evaluate(ins[:n]...) - } - s.pool.Dump(ins) -} - -func Solve(circuitData *stdGkr.CircuitData, circuit gkr.Circuit) gkr.WireAssignment { - solver := solver{ - assignment: make([][]fr.Element, len(circuit)), - d: circuitData, - circuit: circuit, - status: make([]solvingStatus, circuitData.NbInstances), - offsets: make([]int, len(circuit)), - } - - solver.offsets[0] = 0 - for j := 0; j+1 < len(circuit); j++ { - solver.offsets[j+1] = solver.offsets[j] + circuitData.NbInstances - circuitData.InputDependencies.NbDependencies(j) - } - - for i := 0; i < circuitData.NbInstances; i++ { - solver.solve(i) - } - - res := make(gkr.WireAssignment, len(circuit)) - for i := range circuit { - res[&circuit[i]] = solver.assignment[i] - } - return res -} - -func SolveHint(data interface{}, ins []*big.Int, outs []*big.Int) error { - circuitData := data.(*stdGkr.CircuitData) - circuit := convertCircuit(circuitData) - circuitData.TypedCircuit = circuit - circuitData.AssignmentVector = ins - assignments := Solve(circuitData, circuit) - circuitData.TypedAssignment = assignments - - outI := 0 - for i, w := range circuitData.Sorted { - if w.IsOutput() { - assignmentW := assignments[&circuit[i]] - for j := range assignmentW { - assignmentW[outI].BigInt(outs[outI+j]) - } - } - } - - return nil -} diff --git a/internal/gkr/gkr.go b/internal/gkr/gkr.go deleted file mode 100644 index ec7cea2612..0000000000 --- a/internal/gkr/gkr.go +++ /dev/null @@ -1,20 +0,0 @@ -package gkr - -import ( - "fmt" - bn254Fr "github.com/consensys/gnark-crypto/ecc/bn254/fr" - "github.com/consensys/gnark/internal/gkr/bn254" - "math/big" -) - -// hack to avoid import cycles. find out how to avoid - -func SolveHint(data interface{}) func(*big.Int, []*big.Int, []*big.Int) error { - return func(mod *big.Int, ins []*big.Int, outs []*big.Int) error { - switch mod { - case bn254Fr.Modulus(): - return bn254.SolveHint(data, ins, outs) - } - return fmt.Errorf("unknow modulus") - } -} diff --git a/internal/gkr/utils/utils.go b/internal/gkr/utils/utils.go deleted file mode 100644 index d4b585bf78..0000000000 --- a/internal/gkr/utils/utils.go +++ /dev/null @@ -1 +0,0 @@ -package utils diff --git a/std/gkr/api.go b/std/gkr/api.go index e2acb520e4..a0d3634ae9 100644 --- a/std/gkr/api.go +++ b/std/gkr/api.go @@ -6,14 +6,6 @@ import ( "math/big" ) -func Map[T, S any](in []T, f func(T) S) []S { - out := make([]S, len(in)) - for i, t := range in { - out[i] = f(t) - } - return out -} - func frontendVarToPtr(a frontend.Variable) *Wire { return a.(Variable) } diff --git a/internal/gkr/bn254/circuit.go b/std/gkr/bn254_circuit.go similarity index 86% rename from internal/gkr/bn254/circuit.go rename to std/gkr/bn254_circuit.go index 7308136d76..6861661fa2 100644 --- a/internal/gkr/bn254/circuit.go +++ b/std/gkr/bn254_circuit.go @@ -1,32 +1,22 @@ -package bn254 +package gkr import ( "github.com/consensys/gnark-crypto/ecc/bn254/fr" - "github.com/consensys/gnark-crypto/ecc/bn254/fr/gkr" + curveGkr "github.com/consensys/gnark-crypto/ecc/bn254/fr/gkr" "github.com/consensys/gnark/backend/hint" "github.com/consensys/gnark/frontend" - genericGkr "github.com/consensys/gnark/std/gkr" - "github.com/consensys/gnark/std/gkr/api" "math/big" ) -func convertGate(gate genericGkr.Gate) gkr.Gate { +func convertGate(gate Gate) curveGkr.Gate { return gateConverter{gate: gate} } -func Map[T, S any](in []T, f func(T) S) []S { - out := make([]S, len(in)) - for i, t := range in { - out[i] = f(t) - } - return out -} - -func convertCircuit(d *api.CircuitData) gkr.Circuit { - resCircuit := make(gkr.Circuit, len(d.Sorted)) - for i := range d.Sorted { - resCircuit[i].Gate = convertGate(d.Sorted[i].Gate) - resCircuit[i].Inputs = Map(d.CircuitInputsIndex[i], func(index int) *gkr.Wire { +func convertCircuit(d *circuitData) curveGkr.Circuit { + resCircuit := make(curveGkr.Circuit, len(d.sorted)) + for i := range d.sorted { + resCircuit[i].Gate = convertGate(d.sorted[i].Gate) + resCircuit[i].Inputs = Map(d.circuitInputsIndex[i], func(index int) *curveGkr.Wire { return &resCircuit[i] }) } @@ -34,7 +24,7 @@ func convertCircuit(d *api.CircuitData) gkr.Circuit { } type gateConverter struct { - gate genericGkr.Gate + gate Gate api gateConversionApi } @@ -42,7 +32,7 @@ func (c gateConverter) Degree() int { return c.gate.Degree() } -func newGateConverter(gate genericGkr.Gate) gateConverter { +func newGateConverter(gate Gate) gateConverter { return gateConverter{ gate: gate, api: gateConversionApi{}, diff --git a/std/gkr/bn254_solve.go b/std/gkr/bn254_solve.go new file mode 100644 index 0000000000..a8f4d41988 --- /dev/null +++ b/std/gkr/bn254_solve.go @@ -0,0 +1,112 @@ +package gkr + +import ( + "github.com/consensys/gnark-crypto/ecc/bn254/fr" + curveGkr "github.com/consensys/gnark-crypto/ecc/bn254/fr/gkr" + "github.com/consensys/gnark-crypto/ecc/bn254/fr/polynomial" + "math/big" +) + +type solvingStatus byte + +const ( + unsolved solvingStatus = 0 + beingSolved = 1 + solved = 2 +) + +type bn254Solver struct { + assignment [][]fr.Element //wire first, instance second + assignmentVector []*big.Int + d *circuitData + circuit curveGkr.Circuit + status []solvingStatus + offsets []int // the index of an input wire's first given input in the AssignmentVector + pool polynomial.Pool +} + +// solve the i'th instance +func (s bn254Solver) solve(instance int) { + if s.status[instance] == solved { + return + } + if s.status[instance] == beingSolved { + panic("circular dependency among instances") + } + //inputI := 0 + for j, J := range s.d.inputIndexes { + offset := s.offsets[j] //[inputI] + dependency := s.d.inputDependencies.get(j, instance) + + if dependency.OutputWireIndex == -1 { // no dependency + s.assignment[J][instance].SetBigInt(s.assignmentVector[offset+instance]) + //inputI++ + } else { + s.solve(dependency.OutputInstance) + s.assignment[J][instance] = s.assignment[dependency.OutputWireIndex][dependency.OutputInstance] + } + } + s.complete(instance) //TODO: This duplicates some of curveGkr.Complete + s.status[instance] = solved +} + +// complete computes the assignments of an instance given input assignments +func (s bn254Solver) complete(i int) { + circuit := s.d.circuitInputsIndex + ins := s.pool.Make(s.d.maxGateDegree) // TODO: Check + for j := range circuit { + n := len(circuit[j]) + for k := 0; k < n; k++ { + ins[k] = s.assignment[circuit[j][k]][i] + } + + s.assignment[j][i] = s.circuit[j].Gate.Evaluate(ins[:n]...) + } + s.pool.Dump(ins) +} + +func bn254Solve(circuitData *circuitData, circuit curveGkr.Circuit, assignmentVector []*big.Int) curveGkr.WireAssignment { + solver := bn254Solver{ + assignment: make([][]fr.Element, len(circuit)), + d: circuitData, + circuit: circuit, + status: make([]solvingStatus, circuitData.nbInstances), + offsets: make([]int, len(circuit)), + assignmentVector: assignmentVector, + } + + solver.offsets[0] = 0 + for j := 0; j+1 < len(circuit); j++ { + solver.offsets[j+1] = solver.offsets[j] + circuitData.nbInstances - circuitData.inputDependencies.nbDependencies(j) + } + + for i := 0; i < circuitData.nbInstances; i++ { + solver.solve(i) + } + + res := make(curveGkr.WireAssignment, len(circuit)) + for i := range circuit { + res[&circuit[i]] = solver.assignment[i] + } + return res +} + +func bn254SolveHint(data *circuitData, ins []*big.Int, outs []*big.Int) error { + circuit := convertCircuit(data) + assignments := bn254Solve(data, circuit, ins) + + outI := 0 + for i, w := range data.sorted { + if w.IsOutput() { + assignmentW := assignments[&circuit[i]] + for j := range assignmentW { + assignmentW[outI].BigInt(outs[outI+j]) + } + outI++ + } + } + + data.assignments = assignments + + return nil +} diff --git a/std/gkr/compile.go b/std/gkr/compile.go index 91dd06da74..a795ee1f43 100644 --- a/std/gkr/compile.go +++ b/std/gkr/compile.go @@ -2,24 +2,30 @@ package gkr import ( "fmt" + bn254Fr "github.com/consensys/gnark-crypto/ecc/bn254/fr" "github.com/consensys/gnark/frontend" - "github.com/consensys/gnark/internal/gkr" + fiatshamir "github.com/consensys/gnark/std/fiat-shamir" + "github.com/consensys/gnark/std/hash/mimc" + "math/big" "math/bits" ) type API struct { compiled bool logNbInstances int - circuitData CircuitData + circuitData circuitData circuit Circuit - assignments map[Variable][]frontend.Variable + assignments WireAssignment } -type CircuitData struct { - Sorted []*Wire - NbInstances int - CircuitInputsIndex [][]int - InputIndexes []int +type circuitData struct { + sorted []*Wire + nbInstances int + circuitInputsIndex [][]int // circuitInputsIndex is the circuit structure, but with indexes instead of pointers + inputIndexes []int + inputDependencies inputDependencies + maxGateDegree int + assignments interface{} // curve-dependent type. for communication between solver and prover } type Variable *Wire @@ -29,34 +35,10 @@ func (i *API) NbInstances() int { } func NewGkrApi() *API { - return &API{circuit: make(Circuit, 0), assignments: make(map[Variable][]frontend.Variable), logNbInstances: -1} - /*var res API - res.inOutEqualities = make([][2]int, len(inOutEqualities)) - copy(res.inOutEqualities, inOutEqualities) - sort.Slice(res.inOutEqualities, func(i int, j int) bool { - if res.inOutEqualities[i][0] < res.inOutEqualities[j][0] { - return true - } - return res.inOutEqualities[i][1] < res.inOutEqualities[j][1] - }) - - - if len(inOutEqualities) == 0 { - res.nbOutputBoundIns = 0 - } else { - res.nbOutputBoundIns = 1 - for i := 1; i < len(res.inOutEqualities); i++ { - if res.inOutEqualities[i][0] != res.inOutEqualities[i][1] { - - } - } - } - res.inOutEqualities = inOutEqualities - res.circuit = make(Circuit, 0, len(inOutEqualities)) - - return res*/ + return &API{circuit: make(Circuit, 0), assignments: make(WireAssignment), logNbInstances: -1} } +// logNbInstances returns -1 if nbInstances is not a power of 2 func logNbInstances(nbInstances uint) int { if bits.OnesCount(nbInstances) != 1 { return -1 @@ -65,7 +47,7 @@ func logNbInstances(nbInstances uint) int { } func (i *API) Series(input, output Variable, inputInstance, outputInstance int) *API { - i.assignments[input][inputInstance] = InputDependency{ + i.assignments[input][inputInstance] = inputDependency{ Output: output, OutputInstance: outputInstance, } @@ -96,7 +78,7 @@ func (i *API) Import(assignment []frontend.Variable) (Variable, error) { func (i *API) nbInputValueAssignments(variable Variable) int { res := 0 for j := range i.assignments[variable] { - if _, ok := i.assignments[variable][j].(InputDependency); !ok { + if _, ok := i.assignments[variable][j].(inputDependency); !ok { res++ } } @@ -110,21 +92,20 @@ func (i *API) Compile(parentApi frontend.API) ([][]frontend.Variable, error) { } i.compiled = true - i.circuitData.Sorted = topologicalSort(i.circuit) - i.circuitData.NbInstances = 1 << i.logNbInstances - indexes := circuitIndexMap(i.circuitData.Sorted) - i.circuitData.CircuitInputsIndex, i.circuitData.InputIndexes = - circuitInputsIndex(i.circuitData.Sorted, indexes) + i.circuitData.sorted = topologicalSort(i.circuit) // unnecessary(?) but harmless + i.circuitData.nbInstances = 1 << i.logNbInstances + indexMap := circuitIndexMap(i.circuitData.sorted) + i.circuitData.circuitInputsIndex, i.circuitData.inputIndexes = + circuitInputsIndex(i.circuitData.sorted, indexMap) solveHintNIn := 0 - //solveHintNOut := ProofSize(i.circuit, i.logNbInstances) solveHintNOut := 0 for j := range i.circuit { v := &i.circuit[j] if v.IsInput() { solveHintNIn += i.nbInputValueAssignments(v) } else if v.IsOutput() { - solveHintNOut += i.circuitData.NbInstances + solveHintNOut += i.circuitData.nbInstances } } @@ -133,40 +114,69 @@ func (i *API) Compile(parentApi frontend.API) ([][]frontend.Variable, error) { if i.circuit[j].IsInput() { assignment := i.assignments[&i.circuit[j]] for k := range assignment { - if _, ok := assignment[k].(InputDependency); !ok { + if _, ok := assignment[k].(inputDependency); !ok { ins = append(ins, assignment[k]) } } + } else { + i.circuitData.maxGateDegree = max(i.circuitData.maxGateDegree, i.circuit[j].Gate.Degree()) } } - i.circuitData.Sorted = topologicalSort(i.circuit) - indexMap := circuitIndexMap(i.circuitData.Sorted) - i.circuitData.CircuitInputsIndex, i.circuitData.InputIndexes = circuitInputsIndex(i.circuitData.Sorted, indexMap) + i.circuitData.circuitInputsIndex, i.circuitData.inputIndexes = circuitInputsIndex(i.circuitData.sorted, indexMap) - solveHint := gkr.SolveHint(&i.circuitData) - - outsSerialized, err := parentApi.Compiler().NewHint(solveHint, solveHintNOut, ins...) + outsSerialized, err := parentApi.Compiler().NewHint(solveHint(&i.circuitData), solveHintNOut, ins...) if err != nil { return nil, err } - outs := make([][]frontend.Variable, len(outsSerialized)/i.circuitData.NbInstances) + outs := make([][]frontend.Variable, len(outsSerialized)/i.circuitData.nbInstances) - offset := 0 for j := range outs { - outs[j] = outsSerialized[offset : offset+i.circuitData.NbInstances] - offset += i.circuitData.NbInstances + outs[j] = outsSerialized[:i.circuitData.nbInstances] + outsSerialized = outsSerialized[i.circuitData.nbInstances:] + } + + var ( + proofSerialized []frontend.Variable + proof Proof + _mimc mimc.MiMC + ) + if proofSerialized, err = parentApi.Compiler().NewHint(proveHint(&i.circuitData), ProofSize(i.circuit, i.logNbInstances)); // , outsSerialized[0] <- do this as a hack if order of execution got messed up + err != nil { + return nil, err + } + if proof, err = DeserializeProof(i.circuitData.sorted, proofSerialized); err != nil { + return nil, err + } + if _mimc, err = mimc.NewMiMC(parentApi); err != nil { + return nil, err + } + + i.addOutAssignments(outs) + if err = Verify(parentApi, i.circuit, i.assignments, proof, fiatshamir.WithHash(&_mimc), WithSortedCircuit(i.circuitData.sorted)); err != nil { // TODO: Security critical: do a proper transcriptSetting + } return outs, nil } -// Verify produces a subcircuit guaranteeing the correctness of the solved values -func (i *API) Verify(statement []frontend.Variable) error { - return fmt.Errorf("not implemented") +func (i *API) addOutAssignments(outs [][]frontend.Variable) { + // TODO: Increase map size here, since we already know how many we're adding? + outI := 0 + for _, w := range i.circuitData.sorted { + if w.IsOutput() { + i.assignments[w] = outs[outI] + outI++ + } + } } +// Verify produces a subcircuit guaranteeing the correctness of the solved values +//func (i *API) Verify(statement []frontend.Variable) error { +// return fmt.Errorf("not implemented") +//} + func circuitIndexMap(sorted []*Wire) map[*Wire]int { indexes := make(map[*Wire]int, len(sorted)) for i := range sorted { @@ -175,6 +185,7 @@ func circuitIndexMap(sorted []*Wire) map[*Wire]int { return indexes } +// circuitInputsIndex returns a description of the circuit, with indexes instead of pointers. It also returns the indexes of the input wires func circuitInputsIndex(sorted []*Wire, indexes map[*Wire]int) ([][]int, []int) { res := make([][]int, len(sorted)) inputIndexes := make([]int, 0) @@ -182,28 +193,32 @@ func circuitInputsIndex(sorted []*Wire, indexes map[*Wire]int) ([][]int, []int) if w.IsInput() { inputIndexes = append(inputIndexes, i) } - res[i] = make([]int, len(w.Inputs)) - for j, v := range w.Inputs { - res[i][j] = indexes[v] - } + res[i] = Map(w.Inputs, func(v *Wire) int { + return indexes[v] // is it possible to pass a reference to a particular map object's [] operator? + }) } return res, inputIndexes } -type InputDependency struct { +type inputDependency struct { Output *Wire OutputInstance int } -type IndexedInputDependency struct { +type indexedInputDependency struct { OutputInstance int OutputWireIndex int } -type inputDependencies [][]IndexedInputDependency // instance first, then wire +type inputDependencies [][]indexedInputDependency // instance first, then wire + +// inputIndex denotes the index of an input wire AMONG INPUT wires, so that if the intended wire is say, #2 but wire #1 is not an input wire, the inputIndex would be at most 1 +func (d inputDependencies) get(inputIndex, instance int) indexedInputDependency { + return d[instance][inputIndex] +} -func (d inputDependencies) NbDependencies(inputIndex int) int { +func (d inputDependencies) nbDependencies(inputIndex int) int { count := 0 for _, instance := range d { if instance[inputIndex].OutputWireIndex != -1 { @@ -212,3 +227,23 @@ func (d inputDependencies) NbDependencies(inputIndex int) int { } return count } + +// solveHint the hint returns the outputs, indexed by output (ordered by SORTED circuit) first and instance second +func solveHint(data *circuitData) func(*big.Int, []*big.Int, []*big.Int) error { + return func(mod *big.Int, ins []*big.Int, outs []*big.Int) error { + switch mod { + case bn254Fr.Modulus(): + return bn254SolveHint(data, ins, outs) + } + return fmt.Errorf("unknow modulus") + } +} + +func proveHint(data *circuitData) func(*big.Int, []*big.Int, []*big.Int) error { + return func(mod *big.Int, ins []*big.Int, outs []*big.Int) error { + if data.assignments == nil { + return fmt.Errorf("attempting to run the prove hint before the solve hint is done. find a way to create a dependence between them (perhaps an output of the solver to be input to the prover as a hack)") + } + return fmt.Errorf("not implemented") + } +} diff --git a/std/gkr/utils.go b/std/gkr/utils.go new file mode 100644 index 0000000000..e9ed3e810f --- /dev/null +++ b/std/gkr/utils.go @@ -0,0 +1,9 @@ +package gkr + +func Map[T, S any](in []T, f func(T) S) []S { + out := make([]S, len(in)) + for i, t := range in { + out[i] = f(t) + } + return out +} From be5842643e19940ff08a66cd41cf3b393a2d81cc Mon Sep 17 00:00:00 2001 From: Arya Tabaie Date: Wed, 4 Jan 2023 17:13:33 -0500 Subject: [PATCH 09/71] feat: development done for bn254. to test and generify --- std/gkr/bn254_circuit.go | 17 +++++++++++----- std/gkr/bn254_prove.go | 43 ++++++++++++++++++++++++++++++++++++++++ std/gkr/bn254_solve.go | 41 +++++++++++++++++++------------------- std/gkr/compile.go | 29 +-------------------------- std/gkr/prove_hint.go | 1 - std/gkr/solve_hint.go | 1 - std/gkr/switch_cases.go | 31 +++++++++++++++++++++++++++++ 7 files changed, 108 insertions(+), 55 deletions(-) create mode 100644 std/gkr/bn254_prove.go delete mode 100644 std/gkr/prove_hint.go delete mode 100644 std/gkr/solve_hint.go create mode 100644 std/gkr/switch_cases.go diff --git a/std/gkr/bn254_circuit.go b/std/gkr/bn254_circuit.go index 6861661fa2..ba7975ca2a 100644 --- a/std/gkr/bn254_circuit.go +++ b/std/gkr/bn254_circuit.go @@ -2,21 +2,28 @@ package gkr import ( "github.com/consensys/gnark-crypto/ecc/bn254/fr" - curveGkr "github.com/consensys/gnark-crypto/ecc/bn254/fr/gkr" + "github.com/consensys/gnark-crypto/ecc/bn254/fr/gkr" + "github.com/consensys/gnark-crypto/ecc/bn254/fr/polynomial" "github.com/consensys/gnark/backend/hint" "github.com/consensys/gnark/frontend" "math/big" ) -func convertGate(gate Gate) curveGkr.Gate { +type bn254CircuitData struct { + assignments gkr.WireAssignment + circuit gkr.Circuit + memoryPool polynomial.Pool +} + +func convertGate(gate Gate) gkr.Gate { return gateConverter{gate: gate} } -func convertCircuit(d *circuitData) curveGkr.Circuit { - resCircuit := make(curveGkr.Circuit, len(d.sorted)) +func convertCircuit(d *circuitData) gkr.Circuit { + resCircuit := make(gkr.Circuit, len(d.sorted)) for i := range d.sorted { resCircuit[i].Gate = convertGate(d.sorted[i].Gate) - resCircuit[i].Inputs = Map(d.circuitInputsIndex[i], func(index int) *curveGkr.Wire { + resCircuit[i].Inputs = Map(d.circuitInputsIndex[i], func(index int) *gkr.Wire { return &resCircuit[i] }) } diff --git a/std/gkr/bn254_prove.go b/std/gkr/bn254_prove.go new file mode 100644 index 0000000000..fad18a7dd9 --- /dev/null +++ b/std/gkr/bn254_prove.go @@ -0,0 +1,43 @@ +package gkr + +import ( + "fmt" + "github.com/consensys/gnark-crypto/ecc/bn254/fr" + "github.com/consensys/gnark-crypto/ecc/bn254/fr/gkr" + "github.com/consensys/gnark-crypto/ecc/bn254/fr/mimc" + fiatshamir "github.com/consensys/gnark-crypto/fiat-shamir" + "math/big" +) + +func bn254FrToBigInts(dst []*big.Int, src []fr.Element) { + for i := range src { + src[i].BigInt(dst[i]) + } +} + +func bn254ProveHint(data *circuitData, ins []*big.Int, outs []*big.Int) error { + if len(ins) != 0 { + return fmt.Errorf("the prove hint takes no input") + } + typed := data.typed.(bn254CircuitData) + + proof, err := gkr.Prove(typed.circuit, typed.assignments, fiatshamir.WithHash(mimc.NewMiMC()), gkr.WithPool(&typed.memoryPool)) // TODO: Do transcriptSettings properly + if err != nil { + return err + } + + // serialize proof: TODO: In gnark-crypto? + offset := 0 + for i := range proof { + for _, poly := range proof[i].PartialSumPolys { + bn254FrToBigInts(outs[offset:], poly) + offset += len(poly) + } + if proof[i].FinalEvalProof != nil { + finalEvalProof := proof[i].FinalEvalProof.([]fr.Element) + bn254FrToBigInts(outs[offset:], finalEvalProof) + offset += len(finalEvalProof) + } + } + return nil +} diff --git a/std/gkr/bn254_solve.go b/std/gkr/bn254_solve.go index a8f4d41988..f4d238b2ad 100644 --- a/std/gkr/bn254_solve.go +++ b/std/gkr/bn254_solve.go @@ -2,7 +2,7 @@ package gkr import ( "github.com/consensys/gnark-crypto/ecc/bn254/fr" - curveGkr "github.com/consensys/gnark-crypto/ecc/bn254/fr/gkr" + "github.com/consensys/gnark-crypto/ecc/bn254/fr/gkr" "github.com/consensys/gnark-crypto/ecc/bn254/fr/polynomial" "math/big" ) @@ -19,10 +19,9 @@ type bn254Solver struct { assignment [][]fr.Element //wire first, instance second assignmentVector []*big.Int d *circuitData - circuit curveGkr.Circuit + typed *bn254CircuitData status []solvingStatus offsets []int // the index of an input wire's first given input in the AssignmentVector - pool polynomial.Pool } // solve the i'th instance @@ -46,37 +45,37 @@ func (s bn254Solver) solve(instance int) { s.assignment[J][instance] = s.assignment[dependency.OutputWireIndex][dependency.OutputInstance] } } - s.complete(instance) //TODO: This duplicates some of curveGkr.Complete + s.complete(instance) //TODO: This duplicates some of gkr.Complete s.status[instance] = solved } // complete computes the assignments of an instance given input assignments func (s bn254Solver) complete(i int) { circuit := s.d.circuitInputsIndex - ins := s.pool.Make(s.d.maxGateDegree) // TODO: Check + ins := s.typed.memoryPool.Make(s.d.maxGateDegree) // TODO: Check for j := range circuit { n := len(circuit[j]) for k := 0; k < n; k++ { ins[k] = s.assignment[circuit[j][k]][i] } - s.assignment[j][i] = s.circuit[j].Gate.Evaluate(ins[:n]...) + s.assignment[j][i] = s.typed.circuit[j].Gate.Evaluate(ins[:n]...) } - s.pool.Dump(ins) + s.typed.memoryPool.Dump(ins) } -func bn254Solve(circuitData *circuitData, circuit curveGkr.Circuit, assignmentVector []*big.Int) curveGkr.WireAssignment { +func bn254Solve(circuitData *circuitData, typed *bn254CircuitData, assignmentVector []*big.Int) { solver := bn254Solver{ - assignment: make([][]fr.Element, len(circuit)), + assignment: make([][]fr.Element, len(typed.circuit)), d: circuitData, - circuit: circuit, + typed: typed, status: make([]solvingStatus, circuitData.nbInstances), - offsets: make([]int, len(circuit)), + offsets: make([]int, len(typed.circuit)), assignmentVector: assignmentVector, } solver.offsets[0] = 0 - for j := 0; j+1 < len(circuit); j++ { + for j := 0; j+1 < len(typed.circuit); j++ { solver.offsets[j+1] = solver.offsets[j] + circuitData.nbInstances - circuitData.inputDependencies.nbDependencies(j) } @@ -84,21 +83,25 @@ func bn254Solve(circuitData *circuitData, circuit curveGkr.Circuit, assignmentVe solver.solve(i) } - res := make(curveGkr.WireAssignment, len(circuit)) - for i := range circuit { - res[&circuit[i]] = solver.assignment[i] + typed.assignments = make(gkr.WireAssignment, len(typed.circuit)) + for i := range typed.circuit { + typed.assignments[&typed.circuit[i]] = solver.assignment[i] } - return res } func bn254SolveHint(data *circuitData, ins []*big.Int, outs []*big.Int) error { circuit := convertCircuit(data) - assignments := bn254Solve(data, circuit, ins) + typed := bn254CircuitData{ + memoryPool: polynomial.NewPool(256, 1<<11), // TODO: Get clever with limits + } + data.typed = typed + + bn254Solve(data, &typed, ins) outI := 0 for i, w := range data.sorted { if w.IsOutput() { - assignmentW := assignments[&circuit[i]] + assignmentW := typed.assignments[&circuit[i]] for j := range assignmentW { assignmentW[outI].BigInt(outs[outI+j]) } @@ -106,7 +109,5 @@ func bn254SolveHint(data *circuitData, ins []*big.Int, outs []*big.Int) error { } } - data.assignments = assignments - return nil } diff --git a/std/gkr/compile.go b/std/gkr/compile.go index a795ee1f43..a4beccf667 100644 --- a/std/gkr/compile.go +++ b/std/gkr/compile.go @@ -2,11 +2,9 @@ package gkr import ( "fmt" - bn254Fr "github.com/consensys/gnark-crypto/ecc/bn254/fr" "github.com/consensys/gnark/frontend" fiatshamir "github.com/consensys/gnark/std/fiat-shamir" "github.com/consensys/gnark/std/hash/mimc" - "math/big" "math/bits" ) @@ -25,7 +23,7 @@ type circuitData struct { inputIndexes []int inputDependencies inputDependencies maxGateDegree int - assignments interface{} // curve-dependent type. for communication between solver and prover + typed interface{} // curve-dependent data. for communication between solver and prover } type Variable *Wire @@ -172,11 +170,6 @@ func (i *API) addOutAssignments(outs [][]frontend.Variable) { } } -// Verify produces a subcircuit guaranteeing the correctness of the solved values -//func (i *API) Verify(statement []frontend.Variable) error { -// return fmt.Errorf("not implemented") -//} - func circuitIndexMap(sorted []*Wire) map[*Wire]int { indexes := make(map[*Wire]int, len(sorted)) for i := range sorted { @@ -227,23 +220,3 @@ func (d inputDependencies) nbDependencies(inputIndex int) int { } return count } - -// solveHint the hint returns the outputs, indexed by output (ordered by SORTED circuit) first and instance second -func solveHint(data *circuitData) func(*big.Int, []*big.Int, []*big.Int) error { - return func(mod *big.Int, ins []*big.Int, outs []*big.Int) error { - switch mod { - case bn254Fr.Modulus(): - return bn254SolveHint(data, ins, outs) - } - return fmt.Errorf("unknow modulus") - } -} - -func proveHint(data *circuitData) func(*big.Int, []*big.Int, []*big.Int) error { - return func(mod *big.Int, ins []*big.Int, outs []*big.Int) error { - if data.assignments == nil { - return fmt.Errorf("attempting to run the prove hint before the solve hint is done. find a way to create a dependence between them (perhaps an output of the solver to be input to the prover as a hack)") - } - return fmt.Errorf("not implemented") - } -} diff --git a/std/gkr/prove_hint.go b/std/gkr/prove_hint.go deleted file mode 100644 index 10cd5e6a54..0000000000 --- a/std/gkr/prove_hint.go +++ /dev/null @@ -1 +0,0 @@ -package gkr diff --git a/std/gkr/solve_hint.go b/std/gkr/solve_hint.go deleted file mode 100644 index 10cd5e6a54..0000000000 --- a/std/gkr/solve_hint.go +++ /dev/null @@ -1 +0,0 @@ -package gkr diff --git a/std/gkr/switch_cases.go b/std/gkr/switch_cases.go new file mode 100644 index 0000000000..9fd2685650 --- /dev/null +++ b/std/gkr/switch_cases.go @@ -0,0 +1,31 @@ +package gkr + +import ( + "fmt" + bn254 "github.com/consensys/gnark-crypto/ecc/bn254/fr" + "math/big" +) + +// solveHint the hint returns the outputs, indexed by output (ordered by SORTED circuit) first and instance second +func solveHint(data *circuitData) func(*big.Int, []*big.Int, []*big.Int) error { + return func(mod *big.Int, ins []*big.Int, outs []*big.Int) error { + switch mod { + case bn254.Modulus(): + return bn254SolveHint(data, ins, outs) + } + return fmt.Errorf("unknow modulus") + } +} + +func proveHint(data *circuitData) func(*big.Int, []*big.Int, []*big.Int) error { + return func(mod *big.Int, ins []*big.Int, outs []*big.Int) error { + if data.typed == nil { + return fmt.Errorf("attempting to run the prove hint before the solve hint is done. find a way to create a dependence between them (perhaps an output of the solver to be input to the prover as a hack)") + } + switch mod { + case bn254.Modulus(): + return bn254ProveHint(data, ins, outs) + } + return fmt.Errorf("unknow modulus") + } +} From b95229e0ab0b60f15abc875b75b3420e5b0b75cb Mon Sep 17 00:00:00 2001 From: Arya Tabaie Date: Thu, 5 Jan 2023 14:40:56 -0500 Subject: [PATCH 10/71] test: fails. pointer issue --- std/gkr/api_test.go | 31 +++++++++++++- std/gkr/compile.go | 4 +- std/gkr/gkr_test.go | 48 ++++++++++++++++++++++ std/test_vector_utils/test_vector_utils.go | 21 ++++++++++ 4 files changed, 101 insertions(+), 3 deletions(-) diff --git a/std/gkr/api_test.go b/std/gkr/api_test.go index 68b464e3c8..a3b70c3396 100644 --- a/std/gkr/api_test.go +++ b/std/gkr/api_test.go @@ -4,7 +4,9 @@ import ( "github.com/consensys/gnark-crypto/ecc" "github.com/consensys/gnark/backend" "github.com/consensys/gnark/frontend" + "github.com/consensys/gnark/std/test_vector_utils" "github.com/consensys/gnark/test" + "github.com/stretchr/testify/assert" "testing" ) @@ -13,7 +15,7 @@ type mulNoDependencyCircuit struct { } func (c *mulNoDependencyCircuit) Define(api frontend.API) error { - gkr := NewGkrApi() + gkr := NewApi() var x, y frontend.Variable var err error if x, err = gkr.Import(c.X); err != nil { @@ -46,3 +48,30 @@ func TestSolveMulNoDependency(t *testing.T) { } test.NewAssert(t).SolvingSucceeded(&circuit, &assignment, test.WithBackends(backend.GROTH16), test.WithCurves(ecc.BN254)) } + +func TestApiMul(t *testing.T) { + var ( + x *Wire + y *Wire + z *Wire + err error + ) + api := NewApi() + x, err = api.Import([]frontend.Variable{nil, nil}) + assert.NoError(t, err) + y, err = api.Import([]frontend.Variable{nil, nil}) + assert.NoError(t, err) + z = api.Mul(Variable(x), Variable(y)).(Variable) + test_vector_utils.AssertSliceEqual(t, z.Inputs, []*Wire{x, y}) // TODO: Find out why assert.Equal gives false positives ( []*Wire{x,x} as second argument passes when it shouldn't ) + + unsorted := []*Wire{&api.circuit[0], &api.circuit[1], &api.circuit[2]} + test_vector_utils.AssertSliceEqual(t, []*Wire{x, y, z}, unsorted) + + //sorted := topologicalSort(api.circuit) + + //test_vector_utils.AssertSliceEqual(t, sorted, []*Wire{x, y, z}) + + /*assert.Equal(t, x.nbUniqueOutputs, 1) + assert.Equal(t, y.nbUniqueOutputs, 1) + assert.Equal(t, z.nbUniqueOutputs, 0)*/ +} diff --git a/std/gkr/compile.go b/std/gkr/compile.go index a4beccf667..9b0ebab729 100644 --- a/std/gkr/compile.go +++ b/std/gkr/compile.go @@ -26,13 +26,13 @@ type circuitData struct { typed interface{} // curve-dependent data. for communication between solver and prover } -type Variable *Wire +type Variable *Wire // Just an alias to hide implementation details. May be more trouble than worth func (i *API) NbInstances() int { return 1 << i.logNbInstances } -func NewGkrApi() *API { +func NewApi() *API { return &API{circuit: make(Circuit, 0), assignments: make(WireAssignment), logNbInstances: -1} } diff --git a/std/gkr/gkr_test.go b/std/gkr/gkr_test.go index f436737f61..e7e6fb7212 100644 --- a/std/gkr/gkr_test.go +++ b/std/gkr/gkr_test.go @@ -344,3 +344,51 @@ func TestLoadCircuit(t *testing.T) { assert.Equal(t, []*Wire{&c[1]}, c[2].Inputs) } + +func TestTopSortTrivial(t *testing.T) { + c := make(Circuit, 2) + c[0].Inputs = []*Wire{&c[1]} + sorted := topologicalSort(c) + assert.Equal(t, []*Wire{&c[1], &c[0]}, sorted) +} + +func TestTopSortSingleGate(t *testing.T) { + c := make(Circuit, 3) + c[0].Inputs = []*Wire{&c[1], &c[2]} + sorted := topologicalSort(c) + expected := []*Wire{&c[1], &c[2], &c[0]} + assert.True(t, test_vector_utils.SliceEqual(sorted, expected)) //TODO: Remove + test_vector_utils.AssertSliceEqual(t, sorted, expected) + assert.Equal(t, c[0].nbUniqueOutputs, 0) + assert.Equal(t, c[1].nbUniqueOutputs, 1) + assert.Equal(t, c[2].nbUniqueOutputs, 1) +} + +func TestTopSortDeep(t *testing.T) { + c := make(Circuit, 4) + c[0].Inputs = []*Wire{&c[2]} + c[1].Inputs = []*Wire{&c[3]} + c[2].Inputs = []*Wire{} + c[3].Inputs = []*Wire{&c[0]} + sorted := topologicalSort(c) + assert.Equal(t, []*Wire{&c[2], &c[0], &c[3], &c[1]}, sorted) +} + +func TestTopSortWide(t *testing.T) { + c := make(Circuit, 10) + c[0].Inputs = []*Wire{&c[3], &c[8]} + c[1].Inputs = []*Wire{&c[6]} + c[2].Inputs = []*Wire{&c[4]} + c[3].Inputs = []*Wire{} + c[4].Inputs = []*Wire{} + c[5].Inputs = []*Wire{&c[9]} + c[6].Inputs = []*Wire{&c[9]} + c[7].Inputs = []*Wire{&c[9], &c[5], &c[2]} + c[8].Inputs = []*Wire{&c[4], &c[3]} + c[9].Inputs = []*Wire{} + + sorted := topologicalSort(c) + sortedExpected := []*Wire{&c[3], &c[4], &c[2], &c[8], &c[0], &c[9], &c[5], &c[6], &c[1], &c[7]} + + assert.Equal(t, sortedExpected, sorted) +} diff --git a/std/test_vector_utils/test_vector_utils.go b/std/test_vector_utils/test_vector_utils.go index 1e1b6a11cd..2f5dbc4a38 100644 --- a/std/test_vector_utils/test_vector_utils.go +++ b/std/test_vector_utils/test_vector_utils.go @@ -3,10 +3,12 @@ package test_vector_utils import ( "encoding/json" "github.com/consensys/gnark/frontend" + "github.com/stretchr/testify/assert" "os" "path/filepath" "strconv" "strings" + "testing" ) // These data structures fail to equate different representations of the same number. i.e. 5 = -10/-2 @@ -237,3 +239,22 @@ func (m *MapHash) write(x frontend.Variable) { } m.stateValid = true } + +func AssertSliceEqual[T comparable](t *testing.T, expected, seen []T) { + assert.Equal(t, len(expected), len(seen)) + for i := range seen { + assert.True(t, expected[i] == seen[i], "@%d: %v != %v", i, expected[i], seen[i]) // assert.Equal is not strict enough when comparing pointers, i.e. it compares what they refer to + } +} + +func SliceEqual[T comparable](expected, seen []T) bool { + if len(expected) != len(seen) { + return false + } + for i := range seen { + if expected[i] != seen[i] { + return false + } + } + return true +} From d72713e6c0d19114d56567e5e11f263c9d548e36 Mon Sep 17 00:00:00 2001 From: Arya Tabaie Date: Thu, 5 Jan 2023 17:39:42 -0500 Subject: [PATCH 11/71] feat: "generic" top sort --- std/gkr/api_test.go | 2 +- std/gkr/compile.go | 112 ++++++++++++------ std/gkr/gkr_test.go | 2 +- std/gkr/utils.go | 9 -- std/utils/algo_utils/algo_utils.go | 110 +++++++++++++++++ std/utils/algo_utils/algo_utils_test.go | 58 +++++++++ .../test_vectors_utils}/test_vector_utils.go | 0 .../test_vector_utils_test.go | 0 8 files changed, 248 insertions(+), 45 deletions(-) delete mode 100644 std/gkr/utils.go create mode 100644 std/utils/algo_utils/algo_utils.go create mode 100644 std/utils/algo_utils/algo_utils_test.go rename std/{test_vector_utils => utils/test_vectors_utils}/test_vector_utils.go (100%) rename std/{test_vector_utils => utils/test_vectors_utils}/test_vector_utils_test.go (100%) diff --git a/std/gkr/api_test.go b/std/gkr/api_test.go index a3b70c3396..ea6d89fab1 100644 --- a/std/gkr/api_test.go +++ b/std/gkr/api_test.go @@ -4,7 +4,7 @@ import ( "github.com/consensys/gnark-crypto/ecc" "github.com/consensys/gnark/backend" "github.com/consensys/gnark/frontend" - "github.com/consensys/gnark/std/test_vector_utils" + "github.com/consensys/gnark/std/utils/test_vectors_utils" "github.com/consensys/gnark/test" "github.com/stretchr/testify/assert" "testing" diff --git a/std/gkr/compile.go b/std/gkr/compile.go index 9b0ebab729..930e55f660 100644 --- a/std/gkr/compile.go +++ b/std/gkr/compile.go @@ -5,18 +5,27 @@ import ( "github.com/consensys/gnark/frontend" fiatshamir "github.com/consensys/gnark/std/fiat-shamir" "github.com/consensys/gnark/std/hash/mimc" + "github.com/consensys/gnark/std/utils/algo_utils" "math/bits" ) +type incompleteCircuitWire struct { + assignments []frontend.Variable + gate Gate + inputs []int +} + +type incompleteCircuit []incompleteCircuitWire + type API struct { - compiled bool logNbInstances int - circuitData circuitData - circuit Circuit - assignments WireAssignment + compiled circuitData + incomplete incompleteCircuit } type circuitData struct { + circuit Circuit + assignments WireAssignment sorted []*Wire nbInstances int circuitInputsIndex [][]int // circuitInputsIndex is the circuit structure, but with indexes instead of pointers @@ -26,14 +35,51 @@ type circuitData struct { typed interface{} // curve-dependent data. for communication between solver and prover } -type Variable *Wire // Just an alias to hide implementation details. May be more trouble than worth +type Variable int // Just an alias to hide implementation details. May be more trouble than worth + +func sliceAt[T any](slice []T) func(int) T { + return func(i int) T { + return slice[i] + } +} + +func mapAt[K comparable, V any](mp map[K]V) func(K) V { + return func(k K) V { + return mp[k] + } +} func (i *API) NbInstances() int { return 1 << i.logNbInstances } +func (c *incompleteCircuit) compile() (circuit Circuit, assignment WireAssignment) { + circuit = make(Circuit, len(*c)) + assignment = make(WireAssignment, len(*c)) + + at := func(i int) *Wire { + return &circuit[i] + } + for i := range circuit { + cI := (*c)[i] + circuit[i].Inputs = algo_utils.Map(cI.inputs, at) + assignment[&circuit[i]] = cI.assignments + } + return +} + +func (c *incompleteCircuit) newVariable(assignment []frontend.Variable) Variable { + i := len(*c) + *c = append(*c, incompleteCircuitWire{assignments: assignment}) + return Variable(i) +} + +func (i *API) isCompiled() bool { + return i.incomplete == nil +} + func NewApi() *API { - return &API{circuit: make(Circuit, 0), assignments: make(WireAssignment), logNbInstances: -1} + return &API{incomplete: make(incompleteCircuit, 0), logNbInstances: -1} } // logNbInstances returns -1 if nbInstances is not a power of 2 @@ -44,8 +90,9 @@ func logNbInstances(nbInstances uint) int { return bits.TrailingZeros(nbInstances) } +// Series like in an electric circuit, binds an input of an instance to an output of another func (i *API) Series(input, output Variable, inputInstance, outputInstance int) *API { - i.assignments[input][inputInstance] = inputDependency{ + i.incomplete[input].assignments[inputInstance] = inputDependency{ Output: output, OutputInstance: outputInstance, } @@ -53,24 +100,21 @@ func (i *API) Series(input, output Variable, inputInstance, outputInstance int) } func (i *API) Import(assignment []frontend.Variable) (Variable, error) { - if i.compiled { - return nil, fmt.Errorf("cannot import variables into compiled circuit") + if i.isCompiled() { + return -1, fmt.Errorf("cannot import variables into compiled circuit") } nbInstances := uint(len(assignment)) logNbInstances := logNbInstances(nbInstances) if logNbInstances == -1 { - return nil, fmt.Errorf("number of assignments must be a power of 2") + return -1, fmt.Errorf("number of assignments must be a power of 2") } if i.logNbInstances == -1 { i.logNbInstances = logNbInstances } else if logNbInstances != i.logNbInstances { - return nil, fmt.Errorf("number of assignments must be consistent across all variables") + return -1, fmt.Errorf("number of assignments must be consistent across all variables") } - i.circuit = append(i.circuit, Wire{ - Gate: nil, - Inputs: []*Wire{}, - }) - return &i.circuit[len(i.circuit)-1], nil + + return i.incomplete.newVariable(assignment), nil } func (i *API) nbInputValueAssignments(variable Variable) int { @@ -85,16 +129,16 @@ func (i *API) nbInputValueAssignments(variable Variable) int { // Compile finalizes the GKR circuit and returns the output variables in the order created func (i *API) Compile(parentApi frontend.API) ([][]frontend.Variable, error) { - if i.compiled { + if i.isCompiled { return nil, fmt.Errorf("already compiled") } - i.compiled = true + i.isCompiled = true - i.circuitData.sorted = topologicalSort(i.circuit) // unnecessary(?) but harmless - i.circuitData.nbInstances = 1 << i.logNbInstances - indexMap := circuitIndexMap(i.circuitData.sorted) - i.circuitData.circuitInputsIndex, i.circuitData.inputIndexes = - circuitInputsIndex(i.circuitData.sorted, indexMap) + i.compiled.sorted = topologicalSort(i.circuit) // unnecessary(?) but harmless + i.compiled.nbInstances = 1 << i.logNbInstances + indexMap := circuitIndexMap(i.compiled.sorted) + i.compiled.circuitInputsIndex, i.compiled.inputIndexes = + circuitInputsIndex(i.compiled.sorted, indexMap) solveHintNIn := 0 solveHintNOut := 0 @@ -103,7 +147,7 @@ func (i *API) Compile(parentApi frontend.API) ([][]frontend.Variable, error) { if v.IsInput() { solveHintNIn += i.nbInputValueAssignments(v) } else if v.IsOutput() { - solveHintNOut += i.circuitData.nbInstances + solveHintNOut += i.compiled.nbInstances } } @@ -117,22 +161,22 @@ func (i *API) Compile(parentApi frontend.API) ([][]frontend.Variable, error) { } } } else { - i.circuitData.maxGateDegree = max(i.circuitData.maxGateDegree, i.circuit[j].Gate.Degree()) + i.compiled.maxGateDegree = max(i.compiled.maxGateDegree, i.circuit[j].Gate.Degree()) } } - i.circuitData.circuitInputsIndex, i.circuitData.inputIndexes = circuitInputsIndex(i.circuitData.sorted, indexMap) + i.compiled.circuitInputsIndex, i.compiled.inputIndexes = circuitInputsIndex(i.compiled.sorted, indexMap) - outsSerialized, err := parentApi.Compiler().NewHint(solveHint(&i.circuitData), solveHintNOut, ins...) + outsSerialized, err := parentApi.Compiler().NewHint(solveHint(&i.compiled), solveHintNOut, ins...) if err != nil { return nil, err } - outs := make([][]frontend.Variable, len(outsSerialized)/i.circuitData.nbInstances) + outs := make([][]frontend.Variable, len(outsSerialized)/i.compiled.nbInstances) for j := range outs { - outs[j] = outsSerialized[:i.circuitData.nbInstances] - outsSerialized = outsSerialized[i.circuitData.nbInstances:] + outs[j] = outsSerialized[:i.compiled.nbInstances] + outsSerialized = outsSerialized[i.compiled.nbInstances:] } var ( @@ -140,11 +184,11 @@ func (i *API) Compile(parentApi frontend.API) ([][]frontend.Variable, error) { proof Proof _mimc mimc.MiMC ) - if proofSerialized, err = parentApi.Compiler().NewHint(proveHint(&i.circuitData), ProofSize(i.circuit, i.logNbInstances)); // , outsSerialized[0] <- do this as a hack if order of execution got messed up + if proofSerialized, err = parentApi.Compiler().NewHint(proveHint(&i.compiled), ProofSize(i.circuit, i.logNbInstances)); // , outsSerialized[0] <- do this as a hack if order of execution got messed up err != nil { return nil, err } - if proof, err = DeserializeProof(i.circuitData.sorted, proofSerialized); err != nil { + if proof, err = DeserializeProof(i.compiled.sorted, proofSerialized); err != nil { return nil, err } if _mimc, err = mimc.NewMiMC(parentApi); err != nil { @@ -152,7 +196,7 @@ func (i *API) Compile(parentApi frontend.API) ([][]frontend.Variable, error) { } i.addOutAssignments(outs) - if err = Verify(parentApi, i.circuit, i.assignments, proof, fiatshamir.WithHash(&_mimc), WithSortedCircuit(i.circuitData.sorted)); err != nil { // TODO: Security critical: do a proper transcriptSetting + if err = Verify(parentApi, i.circuit, i.assignments, proof, fiatshamir.WithHash(&_mimc), WithSortedCircuit(i.compiled.sorted)); err != nil { // TODO: Security critical: do a proper transcriptSetting } @@ -162,7 +206,7 @@ func (i *API) Compile(parentApi frontend.API) ([][]frontend.Variable, error) { func (i *API) addOutAssignments(outs [][]frontend.Variable) { // TODO: Increase map size here, since we already know how many we're adding? outI := 0 - for _, w := range i.circuitData.sorted { + for _, w := range i.compiled.sorted { if w.IsOutput() { i.assignments[w] = outs[outI] outI++ diff --git a/std/gkr/gkr_test.go b/std/gkr/gkr_test.go index e7e6fb7212..4ddc4cd0fc 100644 --- a/std/gkr/gkr_test.go +++ b/std/gkr/gkr_test.go @@ -7,7 +7,7 @@ import ( "github.com/consensys/gnark/frontend" fiatshamir "github.com/consensys/gnark/std/fiat-shamir" "github.com/consensys/gnark/std/polynomial" - "github.com/consensys/gnark/std/test_vector_utils" + "github.com/consensys/gnark/std/utils/test_vectors_utils" "github.com/consensys/gnark/test" "github.com/stretchr/testify/assert" "os" diff --git a/std/gkr/utils.go b/std/gkr/utils.go deleted file mode 100644 index e9ed3e810f..0000000000 --- a/std/gkr/utils.go +++ /dev/null @@ -1,9 +0,0 @@ -package gkr - -func Map[T, S any](in []T, f func(T) S) []S { - out := make([]S, len(in)) - for i, t := range in { - out[i] = f(t) - } - return out -} diff --git a/std/utils/algo_utils/algo_utils.go b/std/utils/algo_utils/algo_utils.go new file mode 100644 index 0000000000..1e53cbea8f --- /dev/null +++ b/std/utils/algo_utils/algo_utils.go @@ -0,0 +1,110 @@ +package algo_utils + +func Map[T, S any](in []T, f func(T) S) []S { + out := make([]S, len(in)) + for i, t := range in { + out[i] = f(t) + } + return out +} + +// TODO: Move this to gnark-crypto and use it for gkr there as well + +// TopologicalSort sorts the wires in order of dependence. Such that for any wire, any one it depends on +// occurs before it. It tries to stick to the input order as much as possible. An already sorted list will remain unchanged. +// It also sets the nbOutput flags, and a dummy IdentityGate for input wires. +// Worst-case inefficient O(n^2), but that probably won't matter since the circuits are small. +// Furthermore, it is efficient with already-close-to-sorted lists, which are the expected input +func TopologicalSort(inputs [][]int) (sorted []int, uniqueOutputs [][]int) { + data := newTopSortData(inputs) + sorted = make([]int, len(inputs)) + + for i := range inputs { + sorted[i] = data.leastReady + data.markDone(data.leastReady) + } + + return sorted, data.uniqueOutputs +} + +type topSortData struct { + uniqueOutputs [][]int + inputs [][]int + status []int // status > 0 indicates number of unique inputs left to be ready. status = 0 means ready. status = -1 means done + leastReady int +} + +func newTopSortData(inputs [][]int) topSortData { + size := len(inputs) + res := topSortData{ + uniqueOutputs: make([][]int, size), + inputs: inputs, + status: make([]int, size), + leastReady: 0, + } + for i := range res.uniqueOutputs { + res.uniqueOutputs[i] = make([]int, 0) + } + inputsISet := newIntSet(size) //if size is large, a map to struct{} might serve better + for i := range res.uniqueOutputs { + if i != 0 { + inputsISet.clear() + } + for _, in := range inputs[i] { + if !inputsISet.put(in) { + res.uniqueOutputs[in] = append(res.uniqueOutputs[in], i) + } + } + res.status[i] = inputsISet.len() + } + + for res.status[res.leastReady] != 0 { + res.leastReady++ + } + + return res +} + +func (d *topSortData) markDone(i int) { + + d.status[i] = -1 + + for _, outI := range d.uniqueOutputs[i] { + d.status[outI]-- + if d.status[outI] == 0 && outI < d.leastReady { + d.leastReady = outI + } + } + + for d.leastReady < len(d.status) && d.status[d.leastReady] != 0 { + d.leastReady++ + } +} + +type intSet struct { + contains []bool + length int +} + +func newIntSet(capacity int) intSet { //if capacity is large, a map to struct{} might serve better + return intSet{contains: make([]bool, capacity)} +} + +func (s *intSet) clear() { + for i := range s.contains { + s.contains[i] = false + } + s.length = 0 +} + +func (s *intSet) put(i int) (alreadyContains bool) { + if alreadyContains = s.contains[i]; !alreadyContains { + s.length++ + } + s.contains[i] = true + return +} + +func (s *intSet) len() int { + return s.length +} diff --git a/std/utils/algo_utils/algo_utils_test.go b/std/utils/algo_utils/algo_utils_test.go new file mode 100644 index 0000000000..f55055aa26 --- /dev/null +++ b/std/utils/algo_utils/algo_utils_test.go @@ -0,0 +1,58 @@ +package algo_utils + +import ( + "github.com/stretchr/testify/assert" + "testing" +) + +func SliceLen[T any](slice []T) int { + return len(slice) +} + +func testTopSort(t *testing.T, inputs [][]int, expectedSorted, expectedNbUniqueOuts []int) { + sorted, uniqueOuts := TopologicalSort(inputs) + nbUniqueOut := Map(uniqueOuts, SliceLen[int]) + assert.Equal(t, expectedSorted, sorted) + assert.Equal(t, expectedNbUniqueOuts, nbUniqueOut) +} + +func TestTopSortTrivial(t *testing.T) { + testTopSort(t, [][]int{ + {1}, + {}, + }, []int{1, 0}, []int{0, 1}) +} + +func TestTopSortSingleGate(t *testing.T) { + inputs := [][]int{{1, 2}, {}, {}} + expectedSorted := []int{1, 2, 0} + expectedNbUniqueOuts := []int{0, 1, 1} + testTopSort(t, inputs, expectedSorted, expectedNbUniqueOuts) +} + +func TestTopSortDeep(t *testing.T) { + inputs := [][]int{{2}, {3}, {}, {0}} + expectedSorted := []int{2, 0, 3, 1} + expectedNbUniqueOuts := []int{1, 0, 1, 1} + + testTopSort(t, inputs, expectedSorted, expectedNbUniqueOuts) +} + +func TestTopSortWide(t *testing.T) { + inputs := [][]int{ + {3, 8}, + {6}, + {4}, + {}, + {}, + {9}, + {9}, + {9, 5, 2, 2}, + {4, 3}, + {}, + } + expectedSorted := []int{3, 4, 2, 8, 0, 9, 5, 6, 1, 7} + expectedNbUniqueOut := []int{0, 0, 1, 2, 2, 1, 1, 0, 1, 3} + + testTopSort(t, inputs, expectedSorted, expectedNbUniqueOut) +} diff --git a/std/test_vector_utils/test_vector_utils.go b/std/utils/test_vectors_utils/test_vector_utils.go similarity index 100% rename from std/test_vector_utils/test_vector_utils.go rename to std/utils/test_vectors_utils/test_vector_utils.go diff --git a/std/test_vector_utils/test_vector_utils_test.go b/std/utils/test_vectors_utils/test_vector_utils_test.go similarity index 100% rename from std/test_vector_utils/test_vector_utils_test.go rename to std/utils/test_vectors_utils/test_vector_utils_test.go From 8bdbca751a9d78ee57e9f15bbe4e3b73070eff3d Mon Sep 17 00:00:00 2001 From: Arya Tabaie Date: Fri, 6 Jan 2023 15:49:57 -0500 Subject: [PATCH 12/71] refactor: improved, simplified solver; compiler to match --- std/gkr/bn254_circuit.go | 15 +-- std/gkr/bn254_prove.go | 6 +- std/gkr/bn254_solve.go | 141 ++++++++++++----------------- std/gkr/compile.go | 133 +++++++++++++++------------ std/gkr/gkr.go | 4 +- std/utils/algo_utils/algo_utils.go | 22 ++++- 6 files changed, 165 insertions(+), 156 deletions(-) diff --git a/std/gkr/bn254_circuit.go b/std/gkr/bn254_circuit.go index ba7975ca2a..b203eeedeb 100644 --- a/std/gkr/bn254_circuit.go +++ b/std/gkr/bn254_circuit.go @@ -6,6 +6,7 @@ import ( "github.com/consensys/gnark-crypto/ecc/bn254/fr/polynomial" "github.com/consensys/gnark/backend/hint" "github.com/consensys/gnark/frontend" + "github.com/consensys/gnark/std/utils/algo_utils" "math/big" ) @@ -19,13 +20,13 @@ func convertGate(gate Gate) gkr.Gate { return gateConverter{gate: gate} } -func convertCircuit(d *circuitData) gkr.Circuit { - resCircuit := make(gkr.Circuit, len(d.sorted)) - for i := range d.sorted { - resCircuit[i].Gate = convertGate(d.sorted[i].Gate) - resCircuit[i].Inputs = Map(d.circuitInputsIndex[i], func(index int) *gkr.Wire { - return &resCircuit[i] - }) +func convertCircuit(d circuitData) gkr.Circuit { + + noPtr := d.noPtr.circuit + resCircuit := make(gkr.Circuit, len(noPtr)) + for i := range noPtr { + resCircuit[i].Gate = convertGate(d.forSnark.circuit[i].Gate) + resCircuit[i].Inputs = algo_utils.Map(noPtr[i].inputs, slicePtrAt(resCircuit)) } return resCircuit } diff --git a/std/gkr/bn254_prove.go b/std/gkr/bn254_prove.go index fad18a7dd9..3e22713871 100644 --- a/std/gkr/bn254_prove.go +++ b/std/gkr/bn254_prove.go @@ -15,13 +15,13 @@ func bn254FrToBigInts(dst []*big.Int, src []fr.Element) { } } -func bn254ProveHint(data *circuitData, ins []*big.Int, outs []*big.Int) error { +func bn254ProveHint(typed interface{}, ins []*big.Int, outs []*big.Int) error { if len(ins) != 0 { return fmt.Errorf("the prove hint takes no input") } - typed := data.typed.(bn254CircuitData) + data := typed.(bn254CircuitData) - proof, err := gkr.Prove(typed.circuit, typed.assignments, fiatshamir.WithHash(mimc.NewMiMC()), gkr.WithPool(&typed.memoryPool)) // TODO: Do transcriptSettings properly + proof, err := gkr.Prove(data.circuit, data.assignments, fiatshamir.WithHash(mimc.NewMiMC()), gkr.WithPool(&data.memoryPool)) // TODO: Do transcriptSettings properly if err != nil { return err } diff --git a/std/gkr/bn254_solve.go b/std/gkr/bn254_solve.go index f4d238b2ad..4b9c48a05e 100644 --- a/std/gkr/bn254_solve.go +++ b/std/gkr/bn254_solve.go @@ -7,107 +7,82 @@ import ( "math/big" ) -type solvingStatus byte - -const ( - unsolved solvingStatus = 0 - beingSolved = 1 - solved = 2 -) - -type bn254Solver struct { - assignment [][]fr.Element //wire first, instance second - assignmentVector []*big.Int - d *circuitData - typed *bn254CircuitData - status []solvingStatus - offsets []int // the index of an input wire's first given input in the AssignmentVector -} - -// solve the i'th instance -func (s bn254Solver) solve(instance int) { - if s.status[instance] == solved { - return - } - if s.status[instance] == beingSolved { - panic("circular dependency among instances") - } - //inputI := 0 - for j, J := range s.d.inputIndexes { - offset := s.offsets[j] //[inputI] - dependency := s.d.inputDependencies.get(j, instance) - - if dependency.OutputWireIndex == -1 { // no dependency - s.assignment[J][instance].SetBigInt(s.assignmentVector[offset+instance]) - //inputI++ - } else { - s.solve(dependency.OutputInstance) - s.assignment[J][instance] = s.assignment[dependency.OutputWireIndex][dependency.OutputInstance] +func bn254CreateAssignments(noPtr circuitDataNoPtr, assignmentVector []*big.Int) [][]fr.Element { + circuit := noPtr.circuit + nbInstances := noPtr.nbInstances() + assignments := make([][]fr.Element, len(circuit)) + for wireI := range circuit { + assignments[wireI] = make([]fr.Element, nbInstances) + if circuit[wireI].isInput() { + dependencies := circuit[wireI].dependencies + dependencyI := 0 + for instanceI := range assignments[wireI] { + if dependencyI < len(dependencies) && dependencies[dependencyI].inputInstance == instanceI { + dependencyI++ + } else { + assignments[wireI][instanceI].SetBigInt(assignmentVector[instanceI-dependencyI]) + } + } } } - s.complete(instance) //TODO: This duplicates some of gkr.Complete - s.status[instance] = solved + return assignments } -// complete computes the assignments of an instance given input assignments -func (s bn254Solver) complete(i int) { - circuit := s.d.circuitInputsIndex - ins := s.typed.memoryPool.Make(s.d.maxGateDegree) // TODO: Check - for j := range circuit { - n := len(circuit[j]) - for k := 0; k < n; k++ { - ins[k] = s.assignment[circuit[j][k]][i] +func bn254Solve(noPtr circuitDataNoPtr, typed bn254CircuitData, assignments [][]fr.Element) { + + inputs := make([]fr.Element, noPtr.maxNIns) + for _, instanceI := range noPtr.sortedInstances { + dependencyI := 0 + for wireI := range typed.circuit { + dependencies := noPtr.circuit[wireI].dependencies + if dependencyI < len(dependencies) && dependencies[dependencyI].inputInstance == instanceI { + assignments[instanceI][wireI].Set(&assignments[dependencies[dependencyI].outputWire][dependencies[dependencyI].outputInstance]) + dependencyI++ + } else { + // assemble the inputs + inputIndexes := noPtr.circuit[wireI].inputs + for i, inputI := range inputIndexes { + inputs[i].Set(&assignments[inputI][instanceI]) + } + gate := typed.circuit[wireI].Gate + assignments[instanceI][wireI] = gate.Evaluate(inputs[:len(inputIndexes)]...) + } } - - s.assignment[j][i] = s.typed.circuit[j].Gate.Evaluate(ins[:n]...) } - s.typed.memoryPool.Dump(ins) } -func bn254Solve(circuitData *circuitData, typed *bn254CircuitData, assignmentVector []*big.Int) { - solver := bn254Solver{ - assignment: make([][]fr.Element, len(typed.circuit)), - d: circuitData, - typed: typed, - status: make([]solvingStatus, circuitData.nbInstances), - offsets: make([]int, len(typed.circuit)), - assignmentVector: assignmentVector, - } - - solver.offsets[0] = 0 - for j := 0; j+1 < len(typed.circuit); j++ { - solver.offsets[j+1] = solver.offsets[j] + circuitData.nbInstances - circuitData.inputDependencies.nbDependencies(j) - } - - for i := 0; i < circuitData.nbInstances; i++ { - solver.solve(i) +func toBn254MapAssignment(circuit gkr.Circuit, assignment [][]fr.Element) gkr.WireAssignment { + res := make(gkr.WireAssignment, len(circuit)) + for i := range circuit { + res[&circuit[i]] = assignment[i] } + return res +} - typed.assignments = make(gkr.WireAssignment, len(typed.circuit)) - for i := range typed.circuit { - typed.assignments[&typed.circuit[i]] = solver.assignment[i] +func bn254SetOutputValues(circuit []wireNoPtr, assignments [][]fr.Element, outs []*big.Int) { + outsI := 0 + for i := range circuit { + if circuit[i].isOutput { + for j := range assignments[i] { + assignments[i][j].BigInt(outs[outsI]) + } + outsI++ + } } + // Check if outsI == len(outs)? } -func bn254SolveHint(data *circuitData, ins []*big.Int, outs []*big.Int) error { - circuit := convertCircuit(data) +func bn254SolveHint(data circuitData, ins []*big.Int, outs []*big.Int) error { typed := bn254CircuitData{ + circuit: convertCircuit(data), memoryPool: polynomial.NewPool(256, 1<<11), // TODO: Get clever with limits } data.typed = typed - bn254Solve(data, &typed, ins) - - outI := 0 - for i, w := range data.sorted { - if w.IsOutput() { - assignmentW := typed.assignments[&circuit[i]] - for j := range assignmentW { - assignmentW[outI].BigInt(outs[outI+j]) - } - outI++ - } - } + assignments := bn254CreateAssignments(data.noPtr, ins) + bn254Solve(data.noPtr, typed, assignments) + typed.assignments = toBn254MapAssignment(typed.circuit, assignments) + bn254SetOutputValues(data.noPtr.circuit, assignments, outs) return nil } diff --git a/std/gkr/compile.go b/std/gkr/compile.go index 930e55f660..a50eb5fef7 100644 --- a/std/gkr/compile.go +++ b/std/gkr/compile.go @@ -9,77 +9,107 @@ import ( "math/bits" ) -type incompleteCircuitWire struct { - assignments []frontend.Variable - gate Gate - inputs []int +type wireNoPtr struct { + assignments []frontend.Variable + gate Gate + inputs []int + dependencies []inputDependency // nil for input wires + isOutput bool } -type incompleteCircuit []incompleteCircuitWire +func (w wireNoPtr) isInput() bool { + return len(w.inputs) == 0 +} -type API struct { - logNbInstances int - compiled circuitData - incomplete incompleteCircuit +type circuitDataNoPtr struct { + circuit []wireNoPtr + maxNIns int + sortedInstances []int +} + +type circuitDataForSnark struct { + circuit Circuit + assignments [][]frontend.Variable } type circuitData struct { - circuit Circuit - assignments WireAssignment - sorted []*Wire - nbInstances int - circuitInputsIndex [][]int // circuitInputsIndex is the circuit structure, but with indexes instead of pointers - inputIndexes []int - inputDependencies inputDependencies - maxGateDegree int - typed interface{} // curve-dependent data. for communication between solver and prover + noPtr circuitDataNoPtr + forSnark circuitDataForSnark + typed interface{} // curve-dependent data. for communication between solver and prover +} + +type API struct { + circuitData } type Variable int // Just an alias to hide implementation details. May be more trouble than worth -func sliceAt[T any](slice []T) func(int) T { - return func(i int) T { - return slice[i] +func (d *circuitDataNoPtr) nbInstances() int { + for i := range d.circuit { + if lenI := len(d.circuit[i].inputs); lenI != 0 { + return lenI + } } + return -1 } -func mapAt[K comparable, V any](mp map[K]V) func(K) V { - return func(k K) V { - return mp[k] - } +func (i *API) nbInstances() int { + return i.noPtr.nbInstances() } -func (i *API) NbInstances() int { - return 1 << i.logNbInstances +func (i *API) logNbInstances() int { + return logNbInstances(uint(i.nbInstances())) } -func (c *incompleteCircuit) compile() (circuit Circuit, assignment WireAssignment) { - circuit = make(Circuit, len(*c)) - assignment = make(WireAssignment, len(*c)) +func (d *circuitDataNoPtr) compile() (circuit Circuit, assignment WireAssignment) { + + inputs := algo_utils.Map(d.circuit, func(w wireNoPtr) []int { + return w.inputs + }) + + sorted, uniqueNbOuts := algo_utils.TopologicalSort(inputs) + + circuitInputsIndex = make([][]int, len(inputs)) + for i := range circuitInputsIndex { + circuitInputsIndex[i] = algo_utils.Map(inputs[i], algo_utils.SliceAt(sorted)) + } + + circuit = make(Circuit, len(*d)) + circuitPtrAt := slicePtrAt(circuit) + for i := range circuit { + circuit[i] = Wire{ + Gate: (*d)[sorted[i]].gate, + Inputs: algo_utils.Map(circuitInputsIndex[i], circuitPtrAt), + nbUniqueOutputs: len(uniqueNbOuts[i]), + } + } + + circuit = make(Circuit, len(*d)) + assignment = make(WireAssignment, len(*d)) at := func(i int) *Wire { return &circuit[i] } for i := range circuit { - cI := (*c)[i] + cI := (*d)[i] circuit[i].Inputs = algo_utils.Map(cI.inputs, at) assignment[&circuit[i]] = cI.assignments } return } -func (c *incompleteCircuit) newVariable(assignment []frontend.Variable) Variable { - i := len(*c) - *c = append(*c, incompleteCircuitWire{assignments: assignment}) +func (d *circuitDataNoPtr) newVariable(assignment []frontend.Variable) Variable { + i := len(*d) + *d = append(*d, wireNoPtr{assignments: assignment}) return Variable(i) } func (i *API) isCompiled() bool { - return i.incomplete == nil + return i.dataNoPtr == nil } func NewApi() *API { - return &API{incomplete: make(incompleteCircuit, 0), logNbInstances: -1} + return &API{dataNoPtr: make(circuitDataNoPtr, 0), logNbInstances: -1} } // logNbInstances returns -1 if nbInstances is not a power of 2 @@ -92,7 +122,7 @@ func logNbInstances(nbInstances uint) int { // Series like in an electric circuit, binds an input of an instance to an output of another func (i *API) Series(input, output Variable, inputInstance, outputInstance int) *API { - i.incomplete[input].assignments[inputInstance] = inputDependency{ + i.dataNoPtr[input].assignments[inputInstance] = inputDependency{ Output: output, OutputInstance: outputInstance, } @@ -114,7 +144,7 @@ func (i *API) Import(assignment []frontend.Variable) (Variable, error) { return -1, fmt.Errorf("number of assignments must be consistent across all variables") } - return i.incomplete.newVariable(assignment), nil + return i.dataNoPtr.newVariable(assignment), nil } func (i *API) nbInputValueAssignments(variable Variable) int { @@ -239,28 +269,13 @@ func circuitInputsIndex(sorted []*Wire, indexes map[*Wire]int) ([][]int, []int) } type inputDependency struct { - Output *Wire - OutputInstance int + outputWire int + outputInstance int + inputInstance int } -type indexedInputDependency struct { - OutputInstance int - OutputWireIndex int -} - -type inputDependencies [][]indexedInputDependency // instance first, then wire - -// inputIndex denotes the index of an input wire AMONG INPUT wires, so that if the intended wire is say, #2 but wire #1 is not an input wire, the inputIndex would be at most 1 -func (d inputDependencies) get(inputIndex, instance int) indexedInputDependency { - return d[instance][inputIndex] -} - -func (d inputDependencies) nbDependencies(inputIndex int) int { - count := 0 - for _, instance := range d { - if instance[inputIndex].OutputWireIndex != -1 { - count++ - } +func slicePtrAt[T any](slice []T) func(int) *T { + return func(i int) *T { + return &slice[i] } - return count } diff --git a/std/gkr/gkr.go b/std/gkr/gkr.go index 0cf65a7e93..ed45c5aabf 100644 --- a/std/gkr/gkr.go +++ b/std/gkr/gkr.go @@ -425,6 +425,8 @@ func statusList(c Circuit) []int { return res } +// TODO: Have this use algo_utils.TopologicalSort underneath + // topologicalSort sorts the wires in order of dependence. Such that for any wire, any one it depends on // occurs before it. It tries to stick to the input order as much as possible. An already sorted list will remain unchanged. // It also sets the nbOutput flags, and a dummy IdentityGate for input wires. @@ -452,7 +454,7 @@ func (a WireAssignment) NumInstances() int { for _, aW := range a { return len(aW) } - panic("empty assignment") + panic("empty assignments") } func (a WireAssignment) NumVars() int { diff --git a/std/utils/algo_utils/algo_utils.go b/std/utils/algo_utils/algo_utils.go index 1e53cbea8f..fbf4a13db4 100644 --- a/std/utils/algo_utils/algo_utils.go +++ b/std/utils/algo_utils/algo_utils.go @@ -1,5 +1,7 @@ package algo_utils +// this package provides some generic (in both senses of the word) algorithmic conveniences. + func Map[T, S any](in []T, f func(T) S) []S { out := make([]S, len(in)) for i, t := range in { @@ -8,13 +10,27 @@ func Map[T, S any](in []T, f func(T) S) []S { return out } +func SliceAt[T any](slice []T) func(int) T { + return func(i int) T { + return slice[i] + } +} + +func MapAt[K comparable, V any](mp map[K]V) func(K) V { + return func(k K) V { + return mp[k] + } +} + // TODO: Move this to gnark-crypto and use it for gkr there as well -// TopologicalSort sorts the wires in order of dependence. Such that for any wire, any one it depends on +// TopologicalSort takes a list of lists of dependencies and proposes a sorting of the lists in order of dependence. Such that for any wire, any one it depends on // occurs before it. It tries to stick to the input order as much as possible. An already sorted list will remain unchanged. -// It also sets the nbOutput flags, and a dummy IdentityGate for input wires. +// As a bonus, it returns for each list its "unique" outputs. That is, a list of its outputs with no duplicates. // Worst-case inefficient O(n^2), but that probably won't matter since the circuits are small. -// Furthermore, it is efficient with already-close-to-sorted lists, which are the expected input +// Furthermore, it is efficient with already-close-to-sorted lists, which are the expected input. +// If performance was bad, consider using a heap for finding the value "leastReady". +// WARNING: Due to the current implementation of intSet, it is ALWAYS O(n^2). func TopologicalSort(inputs [][]int) (sorted []int, uniqueOutputs [][]int) { data := newTopSortData(inputs) sorted = make([]int, len(inputs)) From 41cb30d005f11cc7bd3517dc8272a06f6282cd68 Mon Sep 17 00:00:00 2001 From: Arya Tabaie Date: Mon, 9 Jan 2023 16:12:50 -0500 Subject: [PATCH 13/71] refactor: use mostly no-ptr data. better information silos --- std/gkr/api_test.go | 2 +- std/gkr/bn254_circuit.go | 6 +- std/gkr/bn254_prove.go | 3 +- std/gkr/bn254_solve.go | 18 +- std/gkr/compile.go | 290 ++++++++++++++++++----------- std/gkr/switch_cases.go | 13 +- std/utils/algo_utils/algo_utils.go | 17 ++ 7 files changed, 223 insertions(+), 126 deletions(-) diff --git a/std/gkr/api_test.go b/std/gkr/api_test.go index ea6d89fab1..2d4562a657 100644 --- a/std/gkr/api_test.go +++ b/std/gkr/api_test.go @@ -51,7 +51,7 @@ func TestSolveMulNoDependency(t *testing.T) { func TestApiMul(t *testing.T) { var ( - x *Wire + x Variable y *Wire z *Wire err error diff --git a/std/gkr/bn254_circuit.go b/std/gkr/bn254_circuit.go index b203eeedeb..90720b969a 100644 --- a/std/gkr/bn254_circuit.go +++ b/std/gkr/bn254_circuit.go @@ -20,12 +20,10 @@ func convertGate(gate Gate) gkr.Gate { return gateConverter{gate: gate} } -func convertCircuit(d circuitData) gkr.Circuit { - - noPtr := d.noPtr.circuit +func convertCircuit(noPtr circuitNoPtr) gkr.Circuit { resCircuit := make(gkr.Circuit, len(noPtr)) for i := range noPtr { - resCircuit[i].Gate = convertGate(d.forSnark.circuit[i].Gate) + resCircuit[i].Gate = convertGate(noPtr[i].gate) resCircuit[i].Inputs = algo_utils.Map(noPtr[i].inputs, slicePtrAt(resCircuit)) } return resCircuit diff --git a/std/gkr/bn254_prove.go b/std/gkr/bn254_prove.go index 3e22713871..46071a4b2d 100644 --- a/std/gkr/bn254_prove.go +++ b/std/gkr/bn254_prove.go @@ -15,11 +15,10 @@ func bn254FrToBigInts(dst []*big.Int, src []fr.Element) { } } -func bn254ProveHint(typed interface{}, ins []*big.Int, outs []*big.Int) error { +func bn254ProveHint(data bn254CircuitData, ins []*big.Int, outs []*big.Int) error { if len(ins) != 0 { return fmt.Errorf("the prove hint takes no input") } - data := typed.(bn254CircuitData) proof, err := gkr.Prove(data.circuit, data.assignments, fiatshamir.WithHash(mimc.NewMiMC()), gkr.WithPool(&data.memoryPool)) // TODO: Do transcriptSettings properly if err != nil { diff --git a/std/gkr/bn254_solve.go b/std/gkr/bn254_solve.go index 4b9c48a05e..99d000ed5a 100644 --- a/std/gkr/bn254_solve.go +++ b/std/gkr/bn254_solve.go @@ -72,17 +72,17 @@ func bn254SetOutputValues(circuit []wireNoPtr, assignments [][]fr.Element, outs // Check if outsI == len(outs)? } -func bn254SolveHint(data circuitData, ins []*big.Int, outs []*big.Int) error { - typed := bn254CircuitData{ - circuit: convertCircuit(data), +func bn254SolveHint(data circuitDataNoPtr, ins []*big.Int, outs []*big.Int) (bn254CircuitData, error) { + + res := bn254CircuitData{ + circuit: convertCircuit(data.circuit), memoryPool: polynomial.NewPool(256, 1<<11), // TODO: Get clever with limits } - data.typed = typed - assignments := bn254CreateAssignments(data.noPtr, ins) - bn254Solve(data.noPtr, typed, assignments) - typed.assignments = toBn254MapAssignment(typed.circuit, assignments) - bn254SetOutputValues(data.noPtr.circuit, assignments, outs) + assignments := bn254CreateAssignments(data, ins) + bn254Solve(data, res, assignments) + res.assignments = toBn254MapAssignment(res.circuit, assignments) + bn254SetOutputValues(data.circuit, assignments, outs) - return nil + return res, nil } diff --git a/std/gkr/compile.go b/std/gkr/compile.go index a50eb5fef7..774edca834 100644 --- a/std/gkr/compile.go +++ b/std/gkr/compile.go @@ -7,29 +7,36 @@ import ( "github.com/consensys/gnark/std/hash/mimc" "github.com/consensys/gnark/std/utils/algo_utils" "math/bits" + "sort" ) type wireNoPtr struct { - assignments []frontend.Variable - gate Gate - inputs []int - dependencies []inputDependency // nil for input wires - isOutput bool + assignments []frontend.Variable + gate Gate + inputs []int + dependencies []inputDependency // nil for input wires + nbUniqueOutputs int } +type circuitNoPtr []wireNoPtr + func (w wireNoPtr) isInput() bool { return len(w.inputs) == 0 } +func (w wireNoPtr) isOutput() bool { + return w.nbUniqueOutputs == 0 +} + type circuitDataNoPtr struct { - circuit []wireNoPtr + circuit circuitNoPtr maxNIns int sortedInstances []int } type circuitDataForSnark struct { circuit Circuit - assignments [][]frontend.Variable + assignments WireAssignment } type circuitData struct { @@ -61,55 +68,111 @@ func (i *API) logNbInstances() int { return logNbInstances(uint(i.nbInstances())) } -func (d *circuitDataNoPtr) compile() (circuit Circuit, assignment WireAssignment) { +// compile sorts the circuit wires, their dependencies and the instances +func (d *circuitDataNoPtr) compile() error { // (circuit Circuit, assignment WireAssignment) { + + // this whole circuit sorting is a bit of a charade. if things are built using an api, there's no way it could NOT already be topologically sorted + // worth keeping for future-proofing? inputs := algo_utils.Map(d.circuit, func(w wireNoPtr) []int { return w.inputs }) - sorted, uniqueNbOuts := algo_utils.TopologicalSort(inputs) + permutation, uniqueOuts := algo_utils.TopologicalSort(inputs) + permutationInv := algo_utils.InvertPermutation(permutation) + permutationInvAt := algo_utils.SliceAt(permutationInv) + sorted := make([]wireNoPtr, len(d.circuit)) + for newI, oldI := range permutation { + oldW := d.circuit[oldI] - circuitInputsIndex = make([][]int, len(inputs)) - for i := range circuitInputsIndex { - circuitInputsIndex[i] = algo_utils.Map(inputs[i], algo_utils.SliceAt(sorted)) - } + sort.Slice(oldW.dependencies, func(i, j int) bool { + return oldW.dependencies[i].inputInstance < oldW.dependencies[j].inputInstance + }) + for i := 1; i < len(oldW.dependencies); i++ { + if oldW.dependencies[i].inputInstance == oldW.dependencies[i-1].inputInstance { + return fmt.Errorf("an input wire can only have one dependency per instance") + } + } // TODO: Check that dependencies and explicit assignments cover all instances - circuit = make(Circuit, len(*d)) - circuitPtrAt := slicePtrAt(circuit) - for i := range circuit { - circuit[i] = Wire{ - Gate: (*d)[sorted[i]].gate, - Inputs: algo_utils.Map(circuitInputsIndex[i], circuitPtrAt), - nbUniqueOutputs: len(uniqueNbOuts[i]), + if !oldW.isInput() { + d.maxNIns = max(d.maxNIns, len(oldW.inputs)) } - } - circuit = make(Circuit, len(*d)) - assignment = make(WireAssignment, len(*d)) + for j := range oldW.dependencies { + oldW.dependencies[j].outputWire = permutationInv[oldW.dependencies[j].outputWire] + } - at := func(i int) *Wire { - return &circuit[i] + sorted[newI] = wireNoPtr{ + assignments: oldW.assignments, + gate: oldW.gate, + inputs: algo_utils.Map(oldW.inputs, permutationInvAt), + dependencies: oldW.dependencies, + nbUniqueOutputs: len(uniqueOuts[oldI]), + } } - for i := range circuit { - cI := (*d)[i] - circuit[i].Inputs = algo_utils.Map(cI.inputs, at) - assignment[&circuit[i]] = cI.assignments + + d.circuit = sorted + + // sort the instances to decide the order in which they are to be solved + instanceDeps := make([][]int, d.nbInstances()) + for i := range d.circuit { + for _, dep := range d.circuit[i].dependencies { + instanceDeps[dep.inputInstance] = append(instanceDeps[dep.inputInstance], dep.outputInstance) + } } - return + + d.sortedInstances, _ = algo_utils.TopologicalSort(instanceDeps) + + return nil + /* circuitInputsIndex := make([][]int, len(inputs)) + for i := range circuitInputsIndex { + circuitInputsIndex[i] = algo_utils.Map(inputs[i], algo_utils.SliceAt(sorted)) + + for j := range + } + + circuit = make(Circuit, len(*d)) + circuitPtrAt := slicePtrAt(circuit) + for i := range circuit { + circuit[i] = Wire{ + Gate: (*d)[sorted[i]].gate, + Inputs: algo_utils.Map(circuitInputsIndex[i], circuitPtrAt), + nbUniqueOutputs: len(uniqueNbOuts[i]), + } + } + + circuit = make(Circuit, len(*d)) + assignment = make(WireAssignment, len(*d)) + + at := func(i int) *Wire { + return &circuit[i] + } + for i := range circuit { + cI := (*d)[i] + circuit[i].Inputs = algo_utils.Map(cI.inputs, at) + assignment[&circuit[i]] = cI.assignments + } + return*/ } func (d *circuitDataNoPtr) newVariable(assignment []frontend.Variable) Variable { - i := len(*d) - *d = append(*d, wireNoPtr{assignments: assignment}) + i := len(d.circuit) + d.circuit = append(d.circuit, wireNoPtr{assignments: assignment}) return Variable(i) } func (i *API) isCompiled() bool { - return i.dataNoPtr == nil + return i.forSnark.circuit != nil } func NewApi() *API { - return &API{dataNoPtr: make(circuitDataNoPtr, 0), logNbInstances: -1} + return &API{circuitData{ + noPtr: circuitDataNoPtr{ + circuit: make(circuitNoPtr, 0), + maxNIns: 0, + sortedInstances: make([]int, 0), + }, + }} } // logNbInstances returns -1 if nbInstances is not a power of 2 @@ -122,10 +185,15 @@ func logNbInstances(nbInstances uint) int { // Series like in an electric circuit, binds an input of an instance to an output of another func (i *API) Series(input, output Variable, inputInstance, outputInstance int) *API { - i.dataNoPtr[input].assignments[inputInstance] = inputDependency{ - Output: output, - OutputInstance: outputInstance, + if i.noPtr.circuit[input].assignments[inputInstance] != nil { + panic("dependency attempting to override explicit value assignment") } + i.noPtr.circuit[input].dependencies = + append(i.noPtr.circuit[input].dependencies, inputDependency{ + outputWire: int(output), + outputInstance: outputInstance, + inputInstance: inputInstance, + }) return i } @@ -133,21 +201,20 @@ func (i *API) Import(assignment []frontend.Variable) (Variable, error) { if i.isCompiled() { return -1, fmt.Errorf("cannot import variables into compiled circuit") } - nbInstances := uint(len(assignment)) - logNbInstances := logNbInstances(nbInstances) + nbInstances := len(assignment) + logNbInstances := logNbInstances(uint(nbInstances)) if logNbInstances == -1 { return -1, fmt.Errorf("number of assignments must be a power of 2") } - if i.logNbInstances == -1 { - i.logNbInstances = logNbInstances - } else if logNbInstances != i.logNbInstances { + + if currentNbInstances := i.nbInstances(); currentNbInstances != -1 && currentNbInstances != nbInstances { return -1, fmt.Errorf("number of assignments must be consistent across all variables") } - return i.dataNoPtr.newVariable(assignment), nil + return i.noPtr.newVariable(assignment), nil } -func (i *API) nbInputValueAssignments(variable Variable) int { +/*func (i *API) nbInputValueAssignments(variable Variable) int { res := 0 for j := range i.assignments[variable] { if _, ok := i.assignments[variable][j].(inputDependency); !ok { @@ -155,117 +222,108 @@ func (i *API) nbInputValueAssignments(variable Variable) int { } } return res +}*/ + +func appendNonNil[T any](dst *[]T, src []T) { + for i := range src { + if src[i] != nil { + *dst = append(*dst, src[i]) + } + } } // Compile finalizes the GKR circuit and returns the output variables in the order created func (i *API) Compile(parentApi frontend.API) ([][]frontend.Variable, error) { - if i.isCompiled { + if i.isCompiled() { return nil, fmt.Errorf("already compiled") } - i.isCompiled = true - i.compiled.sorted = topologicalSort(i.circuit) // unnecessary(?) but harmless - i.compiled.nbInstances = 1 << i.logNbInstances - indexMap := circuitIndexMap(i.compiled.sorted) - i.compiled.circuitInputsIndex, i.compiled.inputIndexes = - circuitInputsIndex(i.compiled.sorted, indexMap) + if err := i.noPtr.compile(); err != nil { + return nil, err + } + nbInstances := i.nbInstances() + circuit := i.noPtr.circuit solveHintNIn := 0 solveHintNOut := 0 - for j := range i.circuit { - v := &i.circuit[j] - if v.IsInput() { - solveHintNIn += i.nbInputValueAssignments(v) - } else if v.IsOutput() { - solveHintNOut += i.compiled.nbInstances + + for j := range circuit { + v := &circuit[j] + if v.isInput() { + solveHintNIn += nbInstances - len(v.dependencies) + } else if v.isOutput() { + solveHintNOut += nbInstances } } ins := make([]frontend.Variable, 0, solveHintNIn) - for j := range i.circuit { - if i.circuit[j].IsInput() { - assignment := i.assignments[&i.circuit[j]] - for k := range assignment { - if _, ok := assignment[k].(inputDependency); !ok { - ins = append(ins, assignment[k]) - } - } - } else { - i.compiled.maxGateDegree = max(i.compiled.maxGateDegree, i.circuit[j].Gate.Degree()) + for j := range circuit { + if circuit[j].isInput() { + appendNonNil(&ins, circuit[j].assignments) } } - i.compiled.circuitInputsIndex, i.compiled.inputIndexes = circuitInputsIndex(i.compiled.sorted, indexMap) - - outsSerialized, err := parentApi.Compiler().NewHint(solveHint(&i.compiled), solveHintNOut, ins...) + outsSerialized, err := parentApi.Compiler().NewHint(solveHint(&i.circuitData), solveHintNOut, ins...) if err != nil { return nil, err } - outs := make([][]frontend.Variable, len(outsSerialized)/i.compiled.nbInstances) + outs := make([][]frontend.Variable, len(outsSerialized)/nbInstances) for j := range outs { - outs[j] = outsSerialized[:i.compiled.nbInstances] - outsSerialized = outsSerialized[i.compiled.nbInstances:] + outs[j] = outsSerialized[:nbInstances] + outsSerialized = outsSerialized[nbInstances:] } + i.noPtr.circuit.addOutputAssignments(outs) + var ( proofSerialized []frontend.Variable proof Proof _mimc mimc.MiMC ) - if proofSerialized, err = parentApi.Compiler().NewHint(proveHint(&i.compiled), ProofSize(i.circuit, i.logNbInstances)); // , outsSerialized[0] <- do this as a hack if order of execution got messed up + + i.forSnark = i.noPtr.forSnark() + + if proofSerialized, err = parentApi.Compiler().NewHint( + proveHint(i.typed), ProofSize(i.forSnark.circuit, logNbInstances(uint(nbInstances)))); // , outsSerialized[0] <- do this as a hack if order of execution got messed up err != nil { return nil, err } - if proof, err = DeserializeProof(i.compiled.sorted, proofSerialized); err != nil { + + forSnarkSorted := algo_utils.MapRange(0, len(circuit), slicePtrAt(i.forSnark.circuit)) + + if proof, err = DeserializeProof(forSnarkSorted, proofSerialized); err != nil { return nil, err } if _mimc, err = mimc.NewMiMC(parentApi); err != nil { return nil, err } - i.addOutAssignments(outs) - if err = Verify(parentApi, i.circuit, i.assignments, proof, fiatshamir.WithHash(&_mimc), WithSortedCircuit(i.compiled.sorted)); err != nil { // TODO: Security critical: do a proper transcriptSetting - + if err = Verify(parentApi, i.forSnark.circuit, i.forSnark.assignments, proof, fiatshamir.WithHash(&_mimc), WithSortedCircuit(forSnarkSorted)); err != nil { // TODO: Security critical: do a proper transcriptSetting + return nil, err } return outs, nil } -func (i *API) addOutAssignments(outs [][]frontend.Variable) { - // TODO: Increase map size here, since we already know how many we're adding? +// completeAssignments creates assignment fields for the output vars and input instances that depend on them +func (c circuitNoPtr) addOutputAssignments(outs [][]frontend.Variable) { outI := 0 - for _, w := range i.compiled.sorted { - if w.IsOutput() { - i.assignments[w] = outs[outI] + for i := range c { + if c[i].isOutput() { + c[i].assignments = outs[outI] outI++ } } -} - -func circuitIndexMap(sorted []*Wire) map[*Wire]int { - indexes := make(map[*Wire]int, len(sorted)) - for i := range sorted { - indexes[sorted[i]] = i - } - return indexes -} - -// circuitInputsIndex returns a description of the circuit, with indexes instead of pointers. It also returns the indexes of the input wires -func circuitInputsIndex(sorted []*Wire, indexes map[*Wire]int) ([][]int, []int) { - res := make([][]int, len(sorted)) - inputIndexes := make([]int, 0) - for i, w := range sorted { - if w.IsInput() { - inputIndexes = append(inputIndexes, i) + for i := range c { + if c[i].dependencies != nil && !c[i].isInput() { // TODO: Remove + panic("data structure poorly maintained") + } + for _, dep := range c[i].dependencies { + c[i].assignments[dep.inputInstance] = c[dep.outputWire].assignments[dep.outputInstance] } - res[i] = Map(w.Inputs, func(v *Wire) int { - return indexes[v] // is it possible to pass a reference to a particular map object's [] operator? - }) } - - return res, inputIndexes } type inputDependency struct { @@ -279,3 +337,25 @@ func slicePtrAt[T any](slice []T) func(int) *T { return &slice[i] } } + +func (d *circuitDataNoPtr) forSnark() circuitDataForSnark { + circuit := make(Circuit, len(d.circuit)) + assignment := make(WireAssignment, len(d.circuit)) + circuitAt := slicePtrAt(circuit) + for i := range circuit { + w := d.circuit[i] + circuit[i] = Wire{ + Gate: w.gate, + Inputs: algo_utils.Map(w.inputs, circuitAt), + nbUniqueOutputs: w.nbUniqueOutputs, + } + if !w.isInput() && !w.isOutput() && w.assignments != nil { // TODO: Remove + panic("unexpected!!") + } + assignment[&circuit[i]] = w.assignments + } + return circuitDataForSnark{ + circuit: circuit, + assignments: assignment, + } +} diff --git a/std/gkr/switch_cases.go b/std/gkr/switch_cases.go index 9fd2685650..820acf7a9d 100644 --- a/std/gkr/switch_cases.go +++ b/std/gkr/switch_cases.go @@ -9,22 +9,25 @@ import ( // solveHint the hint returns the outputs, indexed by output (ordered by SORTED circuit) first and instance second func solveHint(data *circuitData) func(*big.Int, []*big.Int, []*big.Int) error { return func(mod *big.Int, ins []*big.Int, outs []*big.Int) error { + var err error switch mod { case bn254.Modulus(): - return bn254SolveHint(data, ins, outs) + data.typed, err = bn254SolveHint(data.noPtr, ins, outs) + default: + err = fmt.Errorf("unknow modulus") } - return fmt.Errorf("unknow modulus") + return err } } -func proveHint(data *circuitData) func(*big.Int, []*big.Int, []*big.Int) error { +func proveHint(data interface{}) func(*big.Int, []*big.Int, []*big.Int) error { return func(mod *big.Int, ins []*big.Int, outs []*big.Int) error { - if data.typed == nil { + if data == nil { return fmt.Errorf("attempting to run the prove hint before the solve hint is done. find a way to create a dependence between them (perhaps an output of the solver to be input to the prover as a hack)") } switch mod { case bn254.Modulus(): - return bn254ProveHint(data, ins, outs) + return bn254ProveHint(data.(bn254CircuitData), ins, outs) } return fmt.Errorf("unknow modulus") } diff --git a/std/utils/algo_utils/algo_utils.go b/std/utils/algo_utils/algo_utils.go index fbf4a13db4..70037efc21 100644 --- a/std/utils/algo_utils/algo_utils.go +++ b/std/utils/algo_utils/algo_utils.go @@ -10,6 +10,14 @@ func Map[T, S any](in []T, f func(T) S) []S { return out } +func MapRange[S any](begin, end int, f func(int) S) []S { + out := make([]S, end-begin) + for i := begin; i < end; i++ { + out[i] = f(i) + } + return out +} + func SliceAt[T any](slice []T) func(int) T { return func(i int) T { return slice[i] @@ -22,6 +30,15 @@ func MapAt[K comparable, V any](mp map[K]V) func(K) V { } } +// InvertPermutation input permutation must contain exactly 0, ..., len(permutation)-1 +func InvertPermutation(permutation []int) []int { + res := make([]int, len(permutation)) + for i := range permutation { + res[permutation[i]] = i + } + return res +} + // TODO: Move this to gnark-crypto and use it for gkr there as well // TopologicalSort takes a list of lists of dependencies and proposes a sorting of the lists in order of dependence. Such that for any wire, any one it depends on From 743633b8aa5f002077a33c87ec9079274d20823b Mon Sep 17 00:00:00 2001 From: Arya Tabaie Date: Tue, 10 Jan 2023 14:20:10 -0500 Subject: [PATCH 14/71] fix: inconsistencies re assignments alignment --- std/gkr/api.go | 16 ++++++---- std/gkr/api_test.go | 12 ++++---- std/gkr/bn254_circuit.go | 6 ++-- std/gkr/bn254_solve.go | 66 +++++++++++++++++++++++++++------------- std/gkr/compile.go | 6 ++-- std/gkr/compile_test.go | 30 ++++++++++++++++++ std/gkr/switch_cases.go | 5 ++- 7 files changed, 99 insertions(+), 42 deletions(-) create mode 100644 std/gkr/compile_test.go diff --git a/std/gkr/api.go b/std/gkr/api.go index a0d3634ae9..2199ecf1e0 100644 --- a/std/gkr/api.go +++ b/std/gkr/api.go @@ -3,16 +3,20 @@ package gkr import ( "github.com/consensys/gnark/backend/hint" "github.com/consensys/gnark/frontend" + "github.com/consensys/gnark/std/utils/algo_utils" "math/big" ) -func frontendVarToPtr(a frontend.Variable) *Wire { - return a.(Variable) +func frontendVarToInt(a frontend.Variable) int { + return int(a.(Variable)) } -func (i *API) newVar(gate Gate, in []frontend.Variable) Variable { - i.circuit = append(i.circuit, Wire{Gate: gate, Inputs: Map(in, frontendVarToPtr)}) - return &i.circuit[len(i.circuit)-1] +func (i *API) newNonInputVariable(gate Gate, in []frontend.Variable) Variable { + i.noPtr.circuit = append(i.noPtr.circuit, wireNoPtr{ + gate: gate, + inputs: algo_utils.Map(in, frontendVarToInt), + }) + return Variable(len(i.noPtr.circuit) - 1) } func (i *API) newVar2PlusIn(gate Gate, in1, in2 frontend.Variable, in ...frontend.Variable) Variable { @@ -22,7 +26,7 @@ func (i *API) newVar2PlusIn(gate Gate, in1, in2 frontend.Variable, in ...fronten for i := range in { inCombined[i+2] = in[i] } - return i.newVar(gate, inCombined) + return i.newNonInputVariable(gate, inCombined) } func (i *API) Add(i1, i2 frontend.Variable, in ...frontend.Variable) frontend.Variable { diff --git a/std/gkr/api_test.go b/std/gkr/api_test.go index 2d4562a657..39317ee983 100644 --- a/std/gkr/api_test.go +++ b/std/gkr/api_test.go @@ -52,8 +52,8 @@ func TestSolveMulNoDependency(t *testing.T) { func TestApiMul(t *testing.T) { var ( x Variable - y *Wire - z *Wire + y Variable + z Variable err error ) api := NewApi() @@ -61,11 +61,11 @@ func TestApiMul(t *testing.T) { assert.NoError(t, err) y, err = api.Import([]frontend.Variable{nil, nil}) assert.NoError(t, err) - z = api.Mul(Variable(x), Variable(y)).(Variable) - test_vector_utils.AssertSliceEqual(t, z.Inputs, []*Wire{x, y}) // TODO: Find out why assert.Equal gives false positives ( []*Wire{x,x} as second argument passes when it shouldn't ) + z = api.Mul(x, y).(Variable) + test_vector_utils.AssertSliceEqual(t, api.noPtr.circuit[z].inputs, []int{int(x), int(y)}) // TODO: Find out why assert.Equal gives false positives ( []*Wire{x,x} as second argument passes when it shouldn't ) - unsorted := []*Wire{&api.circuit[0], &api.circuit[1], &api.circuit[2]} - test_vector_utils.AssertSliceEqual(t, []*Wire{x, y, z}, unsorted) + //unsorted := []*Wire{&api.noPtr.circuit[0], &api.noPtr.circuit[1], &api.noPtr.circuit[2]} + //test_vector_utils.AssertSliceEqual(t, []*Wire{x, y, z}, unsorted) //sorted := topologicalSort(api.circuit) diff --git a/std/gkr/bn254_circuit.go b/std/gkr/bn254_circuit.go index 90720b969a..f8f7423d59 100644 --- a/std/gkr/bn254_circuit.go +++ b/std/gkr/bn254_circuit.go @@ -16,14 +16,14 @@ type bn254CircuitData struct { memoryPool polynomial.Pool } -func convertGate(gate Gate) gkr.Gate { +func bn254ConvertGate(gate Gate) gkr.Gate { return gateConverter{gate: gate} } -func convertCircuit(noPtr circuitNoPtr) gkr.Circuit { +func bn254ConvertCircuit(noPtr circuitNoPtr) gkr.Circuit { resCircuit := make(gkr.Circuit, len(noPtr)) for i := range noPtr { - resCircuit[i].Gate = convertGate(noPtr[i].gate) + resCircuit[i].Gate = bn254ConvertGate(noPtr[i].gate) resCircuit[i].Inputs = algo_utils.Map(noPtr[i].inputs, slicePtrAt(resCircuit)) } return resCircuit diff --git a/std/gkr/bn254_solve.go b/std/gkr/bn254_solve.go index 99d000ed5a..7f35755937 100644 --- a/std/gkr/bn254_solve.go +++ b/std/gkr/bn254_solve.go @@ -4,23 +4,38 @@ import ( "github.com/consensys/gnark-crypto/ecc/bn254/fr" "github.com/consensys/gnark-crypto/ecc/bn254/fr/gkr" "github.com/consensys/gnark-crypto/ecc/bn254/fr/polynomial" + "golang.org/x/exp/slices" "math/big" ) -func bn254CreateAssignments(noPtr circuitDataNoPtr, assignmentVector []*big.Int) [][]fr.Element { +type bn254AssignmentNoPtr [][]fr.Element //bn254AssignmentNoPtr is indexed instance first, wire second + +func bn254CreateAssignments(noPtr circuitDataNoPtr, assignmentVector []*big.Int) bn254AssignmentNoPtr { circuit := noPtr.circuit nbInstances := noPtr.nbInstances() - assignments := make([][]fr.Element, len(circuit)) - for wireI := range circuit { - assignments[wireI] = make([]fr.Element, nbInstances) - if circuit[wireI].isInput() { - dependencies := circuit[wireI].dependencies - dependencyI := 0 - for instanceI := range assignments[wireI] { + + /*offsets := make([]int, len(circuit)+1) // offsets shows where the assignments for each wire begin + for i := range circuit { + nbAssignments := 0 + if circuit[i].isInput() { + nbAssignments = nbInstances - len(circuit[i].dependencies) + } + offsets[i+1] = offsets[i] + nbAssignments + }*/ + dependenciesI := make([]int, len(circuit)) + assignments := make([][]fr.Element, nbInstances) // Many short arrays are probably less efficient than a few long arrays. A point against the current instance-first indexing + + for instanceI := 0; instanceI < nbInstances; instanceI++ { + assignments[instanceI] = make([]fr.Element, len(circuit)) + for wireI := range circuit { + if circuit[wireI].isInput() { + dependencies := circuit[wireI].dependencies + dependencyI := dependenciesI[wireI] if dependencyI < len(dependencies) && dependencies[dependencyI].inputInstance == instanceI { - dependencyI++ + dependenciesI[wireI]++ } else { - assignments[wireI][instanceI].SetBigInt(assignmentVector[instanceI-dependencyI]) + assignments[instanceI][wireI].SetBigInt(assignmentVector[0]) + assignmentVector = assignmentVector[1:] } } } @@ -28,21 +43,30 @@ func bn254CreateAssignments(noPtr circuitDataNoPtr, assignmentVector []*big.Int) return assignments } -func bn254Solve(noPtr circuitDataNoPtr, typed bn254CircuitData, assignments [][]fr.Element) { +func bn254Solve(noPtr circuitDataNoPtr, typed bn254CircuitData, assignments bn254AssignmentNoPtr) { inputs := make([]fr.Element, noPtr.maxNIns) for _, instanceI := range noPtr.sortedInstances { - dependencyI := 0 for wireI := range typed.circuit { - dependencies := noPtr.circuit[wireI].dependencies - if dependencyI < len(dependencies) && dependencies[dependencyI].inputInstance == instanceI { - assignments[instanceI][wireI].Set(&assignments[dependencies[dependencyI].outputWire][dependencies[dependencyI].outputInstance]) - dependencyI++ + if noPtr.circuit[wireI].isInput() { + dependencies := noPtr.circuit[wireI].dependencies + dependencyI, dependent := slices.BinarySearchFunc(dependencies, inputDependency{inputInstance: instanceI}, + func(a, b inputDependency) int { + if a.inputInstance > b.inputInstance { + return 1 + } else if a.inputInstance == b.inputInstance { + return 0 + } + return -1 + }) + if dependent { + assignments[instanceI][wireI].Set(&assignments[dependencies[dependencyI].outputInstance][dependencies[dependencyI].outputWire]) + } } else { // assemble the inputs inputIndexes := noPtr.circuit[wireI].inputs for i, inputI := range inputIndexes { - inputs[i].Set(&assignments[inputI][instanceI]) + inputs[i].Set(&assignments[instanceI][inputI]) } gate := typed.circuit[wireI].Gate assignments[instanceI][wireI] = gate.Evaluate(inputs[:len(inputIndexes)]...) @@ -51,7 +75,7 @@ func bn254Solve(noPtr circuitDataNoPtr, typed bn254CircuitData, assignments [][] } } -func toBn254MapAssignment(circuit gkr.Circuit, assignment [][]fr.Element) gkr.WireAssignment { +func toBn254MapAssignment(circuit gkr.Circuit, assignment bn254AssignmentNoPtr) gkr.WireAssignment { res := make(gkr.WireAssignment, len(circuit)) for i := range circuit { res[&circuit[i]] = assignment[i] @@ -59,10 +83,10 @@ func toBn254MapAssignment(circuit gkr.Circuit, assignment [][]fr.Element) gkr.Wi return res } -func bn254SetOutputValues(circuit []wireNoPtr, assignments [][]fr.Element, outs []*big.Int) { +func bn254SetOutputValues(circuit []wireNoPtr, assignments bn254AssignmentNoPtr, outs []*big.Int) { outsI := 0 for i := range circuit { - if circuit[i].isOutput { + if circuit[i].isOutput() { for j := range assignments[i] { assignments[i][j].BigInt(outs[outsI]) } @@ -75,7 +99,7 @@ func bn254SetOutputValues(circuit []wireNoPtr, assignments [][]fr.Element, outs func bn254SolveHint(data circuitDataNoPtr, ins []*big.Int, outs []*big.Int) (bn254CircuitData, error) { res := bn254CircuitData{ - circuit: convertCircuit(data.circuit), + circuit: bn254ConvertCircuit(data.circuit), memoryPool: polynomial.NewPool(256, 1<<11), // TODO: Get clever with limits } diff --git a/std/gkr/compile.go b/std/gkr/compile.go index 774edca834..b73ad24b04 100644 --- a/std/gkr/compile.go +++ b/std/gkr/compile.go @@ -155,7 +155,7 @@ func (d *circuitDataNoPtr) compile() error { // (circuit Circuit, assignment Wir return*/ } -func (d *circuitDataNoPtr) newVariable(assignment []frontend.Variable) Variable { +func (d *circuitDataNoPtr) newInputVariable(assignment []frontend.Variable) Variable { i := len(d.circuit) d.circuit = append(d.circuit, wireNoPtr{assignments: assignment}) return Variable(i) @@ -211,7 +211,7 @@ func (i *API) Import(assignment []frontend.Variable) (Variable, error) { return -1, fmt.Errorf("number of assignments must be consistent across all variables") } - return i.noPtr.newVariable(assignment), nil + return i.noPtr.newInputVariable(assignment), nil } /*func (i *API) nbInputValueAssignments(variable Variable) int { @@ -224,7 +224,7 @@ func (i *API) Import(assignment []frontend.Variable) (Variable, error) { return res }*/ -func appendNonNil[T any](dst *[]T, src []T) { +func appendNonNil(dst *[]frontend.Variable, src []frontend.Variable) { for i := range src { if src[i] != nil { *dst = append(*dst, src[i]) diff --git a/std/gkr/compile_test.go b/std/gkr/compile_test.go new file mode 100644 index 0000000000..6d589c219b --- /dev/null +++ b/std/gkr/compile_test.go @@ -0,0 +1,30 @@ +package gkr + +import ( + "github.com/consensys/gnark/frontend" + "github.com/stretchr/testify/assert" + "testing" +) + +func TestConvertCircuit(t *testing.T) { + circuitNoPtr := circuitNoPtr{ + { + assignments: []frontend.Variable{1, 2}, + inputs: []int{}, + nbUniqueOutputs: 1, + }, + { + assignments: []frontend.Variable{2, 3}, + inputs: []int{}, + nbUniqueOutputs: 1, + }, + { + gate: MulGate{}, + inputs: []int{0, 1}, + dependencies: nil, + nbUniqueOutputs: 0, + }, + } + circuit := bn254ConvertCircuit(circuitNoPtr) + assert.Equal(t, 3, len(circuit)) +} diff --git a/std/gkr/switch_cases.go b/std/gkr/switch_cases.go index 820acf7a9d..0c4c72e665 100644 --- a/std/gkr/switch_cases.go +++ b/std/gkr/switch_cases.go @@ -10,10 +10,9 @@ import ( func solveHint(data *circuitData) func(*big.Int, []*big.Int, []*big.Int) error { return func(mod *big.Int, ins []*big.Int, outs []*big.Int) error { var err error - switch mod { - case bn254.Modulus(): + if mod.Cmp(bn254.Modulus()) == 0 { // TODO: Switch case? data.typed, err = bn254SolveHint(data.noPtr, ins, outs) - default: + } else { err = fmt.Errorf("unknow modulus") } return err From 3938c2cff463bde9648e8b49ed1d2f6dbb3e7c8e Mon Sep 17 00:00:00 2001 From: Arya Tabaie Date: Tue, 10 Jan 2023 17:29:08 -0500 Subject: [PATCH 15/71] feat: simple compilation test passes --- std/gkr/bn254_solve.go | 72 +++++--------- std/gkr/compile.go | 121 ++++++++++++------------ std/gkr/compile_test.go | 48 ++++++++++ std/utils/algo_utils/algo_utils.go | 20 ++++ std/utils/algo_utils/algo_utils_test.go | 11 +++ 5 files changed, 160 insertions(+), 112 deletions(-) diff --git a/std/gkr/bn254_solve.go b/std/gkr/bn254_solve.go index 7f35755937..ffb25753fa 100644 --- a/std/gkr/bn254_solve.go +++ b/std/gkr/bn254_solve.go @@ -4,63 +4,35 @@ import ( "github.com/consensys/gnark-crypto/ecc/bn254/fr" "github.com/consensys/gnark-crypto/ecc/bn254/fr/gkr" "github.com/consensys/gnark-crypto/ecc/bn254/fr/polynomial" - "golang.org/x/exp/slices" "math/big" ) -type bn254AssignmentNoPtr [][]fr.Element //bn254AssignmentNoPtr is indexed instance first, wire second +// this module assumes that wire and instance indexes respect dependencies -func bn254CreateAssignments(noPtr circuitDataNoPtr, assignmentVector []*big.Int) bn254AssignmentNoPtr { +type bn254AssignmentNoPtr [][]fr.Element //bn254AssignmentNoPtr is indexed wire first, instance second + +// assumes assignmentVector is arranged wire first, instance second in order of solution +func bn254Solve(noPtr circuitDataNoPtr, typed bn254CircuitData, assignmentVector []*big.Int) bn254AssignmentNoPtr { circuit := noPtr.circuit - nbInstances := noPtr.nbInstances() + nbInstances := circuit.nbInstances() + offsets := circuit.assignmentOffsets() + nbDepsResolved := make([]int, len(circuit)) + inputs := make([]fr.Element, noPtr.maxNIns) - /*offsets := make([]int, len(circuit)+1) // offsets shows where the assignments for each wire begin - for i := range circuit { - nbAssignments := 0 - if circuit[i].isInput() { - nbAssignments = nbInstances - len(circuit[i].dependencies) - } - offsets[i+1] = offsets[i] + nbAssignments - }*/ - dependenciesI := make([]int, len(circuit)) - assignments := make([][]fr.Element, nbInstances) // Many short arrays are probably less efficient than a few long arrays. A point against the current instance-first indexing + assignments := make(bn254AssignmentNoPtr, len(circuit)) + for i := range assignments { + assignments[i] = make([]fr.Element, nbInstances) + } for instanceI := 0; instanceI < nbInstances; instanceI++ { - assignments[instanceI] = make([]fr.Element, len(circuit)) - for wireI := range circuit { - if circuit[wireI].isInput() { - dependencies := circuit[wireI].dependencies - dependencyI := dependenciesI[wireI] - if dependencyI < len(dependencies) && dependencies[dependencyI].inputInstance == instanceI { - dependenciesI[wireI]++ + for wireI, wire := range circuit { + if wire.isInput() { + if nbDepsResolved[wireI] < len(wire.dependencies) && instanceI == wire.dependencies[nbDepsResolved[wireI]].inputInstance { + dep := wire.dependencies[nbDepsResolved[wireI]] + assignments[wireI][instanceI].Set(&assignments[dep.outputWire][dep.outputInstance]) + nbDepsResolved[wireI]++ } else { - assignments[instanceI][wireI].SetBigInt(assignmentVector[0]) - assignmentVector = assignmentVector[1:] - } - } - } - } - return assignments -} - -func bn254Solve(noPtr circuitDataNoPtr, typed bn254CircuitData, assignments bn254AssignmentNoPtr) { - - inputs := make([]fr.Element, noPtr.maxNIns) - for _, instanceI := range noPtr.sortedInstances { - for wireI := range typed.circuit { - if noPtr.circuit[wireI].isInput() { - dependencies := noPtr.circuit[wireI].dependencies - dependencyI, dependent := slices.BinarySearchFunc(dependencies, inputDependency{inputInstance: instanceI}, - func(a, b inputDependency) int { - if a.inputInstance > b.inputInstance { - return 1 - } else if a.inputInstance == b.inputInstance { - return 0 - } - return -1 - }) - if dependent { - assignments[instanceI][wireI].Set(&assignments[dependencies[dependencyI].outputInstance][dependencies[dependencyI].outputWire]) + assignments[wireI][instanceI].SetBigInt(assignmentVector[offsets[wireI]+instanceI-nbDepsResolved[wireI]]) } } else { // assemble the inputs @@ -73,6 +45,7 @@ func bn254Solve(noPtr circuitDataNoPtr, typed bn254CircuitData, assignments bn25 } } } + return assignments } func toBn254MapAssignment(circuit gkr.Circuit, assignment bn254AssignmentNoPtr) gkr.WireAssignment { @@ -103,8 +76,7 @@ func bn254SolveHint(data circuitDataNoPtr, ins []*big.Int, outs []*big.Int) (bn2 memoryPool: polynomial.NewPool(256, 1<<11), // TODO: Get clever with limits } - assignments := bn254CreateAssignments(data, ins) - bn254Solve(data, res, assignments) + assignments := bn254Solve(data, res, ins) res.assignments = toBn254MapAssignment(res.circuit, assignments) bn254SetOutputValues(data.circuit, assignments, outs) diff --git a/std/gkr/compile.go b/std/gkr/compile.go index b73ad24b04..ef42601cdc 100644 --- a/std/gkr/compile.go +++ b/std/gkr/compile.go @@ -32,6 +32,7 @@ type circuitDataNoPtr struct { circuit circuitNoPtr maxNIns int sortedInstances []int + sortedWires []int } type circuitDataForSnark struct { @@ -51,9 +52,9 @@ type API struct { type Variable int // Just an alias to hide implementation details. May be more trouble than worth -func (d *circuitDataNoPtr) nbInstances() int { - for i := range d.circuit { - if lenI := len(d.circuit[i].inputs); lenI != 0 { +func (c circuitNoPtr) nbInstances() int { + for i := range c { + if lenI := len(c[i].assignments); lenI != 0 { return lenI } } @@ -61,7 +62,7 @@ func (d *circuitDataNoPtr) nbInstances() int { } func (i *API) nbInstances() int { - return i.noPtr.nbInstances() + return i.noPtr.circuit.nbInstances() } func (i *API) logNbInstances() int { @@ -71,6 +72,19 @@ func (i *API) logNbInstances() int { // compile sorts the circuit wires, their dependencies and the instances func (d *circuitDataNoPtr) compile() error { // (circuit Circuit, assignment WireAssignment) { + nbInstances := d.circuit.nbInstances() + // sort the instances to decide the order in which they are to be solved + instanceDeps := make([][]int, nbInstances) + for i := range d.circuit { + for _, dep := range d.circuit[i].dependencies { + instanceDeps[dep.inputInstance] = append(instanceDeps[dep.inputInstance], dep.outputInstance) + } + } + + d.sortedInstances, _ = algo_utils.TopologicalSort(instanceDeps) + instancePermutationInv := algo_utils.InvertPermutation(d.sortedInstances) + //instancePermutationInvAt := algo_utils.SliceAt(instancePermutationInv) + // this whole circuit sorting is a bit of a charade. if things are built using an api, there's no way it could NOT already be topologically sorted // worth keeping for future-proofing? @@ -78,16 +92,14 @@ func (d *circuitDataNoPtr) compile() error { // (circuit Circuit, assignment Wir return w.inputs }) - permutation, uniqueOuts := algo_utils.TopologicalSort(inputs) - permutationInv := algo_utils.InvertPermutation(permutation) - permutationInvAt := algo_utils.SliceAt(permutationInv) + var uniqueOuts [][]int + d.sortedWires, uniqueOuts = algo_utils.TopologicalSort(inputs) + wirePermutationInv := algo_utils.InvertPermutation(d.sortedWires) + wirePermutationInvAt := algo_utils.SliceAt(wirePermutationInv) sorted := make([]wireNoPtr, len(d.circuit)) - for newI, oldI := range permutation { + for newI, oldI := range d.sortedWires { oldW := d.circuit[oldI] - sort.Slice(oldW.dependencies, func(i, j int) bool { - return oldW.dependencies[i].inputInstance < oldW.dependencies[j].inputInstance - }) for i := 1; i < len(oldW.dependencies); i++ { if oldW.dependencies[i].inputInstance == oldW.dependencies[i-1].inputInstance { return fmt.Errorf("an input wire can only have one dependency per instance") @@ -99,60 +111,31 @@ func (d *circuitDataNoPtr) compile() error { // (circuit Circuit, assignment Wir } for j := range oldW.dependencies { - oldW.dependencies[j].outputWire = permutationInv[oldW.dependencies[j].outputWire] + dep := &oldW.dependencies[j] + dep.outputWire = wirePermutationInv[dep.outputWire] + dep.inputInstance = instancePermutationInv[dep.inputInstance] + dep.outputInstance = instancePermutationInv[dep.outputInstance] } + sort.Slice(oldW.dependencies, func(i, j int) bool { + return oldW.dependencies[i].inputInstance < oldW.dependencies[j].inputInstance + }) + + algo_utils.Permute(oldW.assignments, instancePermutationInv) + sorted[newI] = wireNoPtr{ assignments: oldW.assignments, gate: oldW.gate, - inputs: algo_utils.Map(oldW.inputs, permutationInvAt), + inputs: algo_utils.Map(oldW.inputs, wirePermutationInvAt), dependencies: oldW.dependencies, nbUniqueOutputs: len(uniqueOuts[oldI]), } - } - d.circuit = sorted - - // sort the instances to decide the order in which they are to be solved - instanceDeps := make([][]int, d.nbInstances()) - for i := range d.circuit { - for _, dep := range d.circuit[i].dependencies { - instanceDeps[dep.inputInstance] = append(instanceDeps[dep.inputInstance], dep.outputInstance) - } } - d.sortedInstances, _ = algo_utils.TopologicalSort(instanceDeps) + d.circuit = sorted return nil - /* circuitInputsIndex := make([][]int, len(inputs)) - for i := range circuitInputsIndex { - circuitInputsIndex[i] = algo_utils.Map(inputs[i], algo_utils.SliceAt(sorted)) - - for j := range - } - - circuit = make(Circuit, len(*d)) - circuitPtrAt := slicePtrAt(circuit) - for i := range circuit { - circuit[i] = Wire{ - Gate: (*d)[sorted[i]].gate, - Inputs: algo_utils.Map(circuitInputsIndex[i], circuitPtrAt), - nbUniqueOutputs: len(uniqueNbOuts[i]), - } - } - - circuit = make(Circuit, len(*d)) - assignment = make(WireAssignment, len(*d)) - - at := func(i int) *Wire { - return &circuit[i] - } - for i := range circuit { - cI := (*d)[i] - circuit[i].Inputs = algo_utils.Map(cI.inputs, at) - assignment[&circuit[i]] = cI.assignments - } - return*/ } func (d *circuitDataNoPtr) newInputVariable(assignment []frontend.Variable) Variable { @@ -214,16 +197,6 @@ func (i *API) Import(assignment []frontend.Variable) (Variable, error) { return i.noPtr.newInputVariable(assignment), nil } -/*func (i *API) nbInputValueAssignments(variable Variable) int { - res := 0 - for j := range i.assignments[variable] { - if _, ok := i.assignments[variable][j].(inputDependency); !ok { - res++ - } - } - return res -}*/ - func appendNonNil(dst *[]frontend.Variable, src []frontend.Variable) { for i := range src { if src[i] != nil { @@ -256,6 +229,7 @@ func (i *API) Compile(parentApi frontend.API) ([][]frontend.Variable, error) { } } + // arrange inputs wire first, then in the order solved ins := make([]frontend.Variable, 0, solveHintNIn) for j := range circuit { if circuit[j].isInput() { @@ -304,6 +278,8 @@ func (i *API) Compile(parentApi frontend.API) ([][]frontend.Variable, error) { return nil, err } + i.noPtr.toVirtualOrder(outs) + return outs, nil } @@ -359,3 +335,24 @@ func (d *circuitDataNoPtr) forSnark() circuitDataForSnark { assignments: assignment, } } + +func (d *circuitDataNoPtr) toVirtualOrder(outs [][]frontend.Variable) { + for j := range d.circuit { + algo_utils.Permute(outs[j], d.sortedInstances) + } + algo_utils.Permute(outs, d.sortedWires) +} + +// assignmentOffsets returns the index of the first value assigned to a wire TODO: Explain clearly +func (c circuitNoPtr) assignmentOffsets() []int { + res := make([]int, len(c)+1) + nbInstances := c.nbInstances() + for i := range c { + nbExplicitAssignments := 0 + if c[i].isInput() { + nbExplicitAssignments = nbInstances - len(c[i].dependencies) + } + res[i+1] = res[i] + nbExplicitAssignments + } + return res +} diff --git a/std/gkr/compile_test.go b/std/gkr/compile_test.go index 6d589c219b..fd7a0eaf2d 100644 --- a/std/gkr/compile_test.go +++ b/std/gkr/compile_test.go @@ -28,3 +28,51 @@ func TestConvertCircuit(t *testing.T) { circuit := bn254ConvertCircuit(circuitNoPtr) assert.Equal(t, 3, len(circuit)) } + +func TestNoPtrCompile(t *testing.T) { + var d = circuitDataNoPtr{ + circuit: circuitNoPtr{ + { + assignments: []frontend.Variable{2, 1}, + inputs: []int{1}, + dependencies: nil, + }, + { + assignments: []frontend.Variable{nil, 0}, + inputs: []int{}, + dependencies: []inputDependency{ + { + outputWire: 0, + outputInstance: 1, + inputInstance: 0, + }, + }, + }, + }, + } + expectedCompiled := circuitDataNoPtr{ + circuit: circuitNoPtr{ + { + assignments: []frontend.Variable{0, nil}, + inputs: []int{}, + dependencies: []inputDependency{{ + outputWire: 1, + outputInstance: 0, + inputInstance: 1, + }}, + + nbUniqueOutputs: 1, + }, + { + assignments: []frontend.Variable{1, 2}, + inputs: []int{0}, + dependencies: nil, + }}, + maxNIns: 1, + sortedInstances: []int{1, 0}, + sortedWires: []int{1, 0}, + } + + assert.NoError(t, d.compile()) + assert.Equal(t, expectedCompiled, d) +} diff --git a/std/utils/algo_utils/algo_utils.go b/std/utils/algo_utils/algo_utils.go index 70037efc21..95b335a81b 100644 --- a/std/utils/algo_utils/algo_utils.go +++ b/std/utils/algo_utils/algo_utils.go @@ -2,6 +2,26 @@ package algo_utils // this package provides some generic (in both senses of the word) algorithmic conveniences. +// Permute operates in-place but is not thread-safe; it uses the permutation for scratching +// permutation[i] signifies which index slice[i] is going to +func Permute[T any](slice []T, permutation []int) { + var cached T + for next := 0; next < len(permutation); next++ { + + cached = slice[next] + j := permutation[next] + permutation[next] = ^j + for j >= 0 { + cached, slice[j] = slice[j], cached + j, permutation[j] = permutation[j], ^permutation[j] + } + permutation[next] = ^permutation[next] + } + for i := range permutation { + permutation[i] = ^permutation[i] + } +} + func Map[T, S any](in []T, f func(T) S) []S { out := make([]S, len(in)) for i, t := range in { diff --git a/std/utils/algo_utils/algo_utils_test.go b/std/utils/algo_utils/algo_utils_test.go index f55055aa26..cf8bf4a81d 100644 --- a/std/utils/algo_utils/algo_utils_test.go +++ b/std/utils/algo_utils/algo_utils_test.go @@ -56,3 +56,14 @@ func TestTopSortWide(t *testing.T) { testTopSort(t, inputs, expectedSorted, expectedNbUniqueOut) } + +func TestPermute(t *testing.T) { + list := []int{34, 65, 23, 2, 5} + permutation := []int{2, 0, 1, 4, 3} + permutationCopy := make([]int, len(permutation)) + copy(permutationCopy, permutation) + + Permute(list, permutation) + assert.Equal(t, []int{65, 23, 34, 5, 2}, list) + assert.Equal(t, permutationCopy, permutation) +} \ No newline at end of file From cae4b076c54a265bc18043e85c032067761c0e18 Mon Sep 17 00:00:00 2001 From: Arya Tabaie Date: Tue, 10 Jan 2023 20:08:16 -0500 Subject: [PATCH 16/71] test: solver error found --- std/gkr/api_test.go | 1 + std/gkr/bn254_solve.go | 4 ++-- std/gkr/compile.go | 22 ++++++++++------------ std/gkr/gkr.go | 1 + std/gkr/switch_cases.go | 8 +++++--- 5 files changed, 19 insertions(+), 17 deletions(-) diff --git a/std/gkr/api_test.go b/std/gkr/api_test.go index 39317ee983..800f4d42ee 100644 --- a/std/gkr/api_test.go +++ b/std/gkr/api_test.go @@ -32,6 +32,7 @@ func (c *mulNoDependencyCircuit) Define(api frontend.API) error { Z := gkrOuts[0] for i := range c.X { + api.Println("z@", i, " = ", Z[i]) api.AssertIsEqual(Z[i], api.Mul(c.X[i], c.Y[i])) } return nil diff --git a/std/gkr/bn254_solve.go b/std/gkr/bn254_solve.go index ffb25753fa..706df19754 100644 --- a/std/gkr/bn254_solve.go +++ b/std/gkr/bn254_solve.go @@ -38,10 +38,10 @@ func bn254Solve(noPtr circuitDataNoPtr, typed bn254CircuitData, assignmentVector // assemble the inputs inputIndexes := noPtr.circuit[wireI].inputs for i, inputI := range inputIndexes { - inputs[i].Set(&assignments[instanceI][inputI]) + inputs[i].Set(&assignments[inputI][instanceI]) } gate := typed.circuit[wireI].Gate - assignments[instanceI][wireI] = gate.Evaluate(inputs[:len(inputIndexes)]...) + assignments[wireI][instanceI] = gate.Evaluate(inputs[:len(inputIndexes)]...) } } } diff --git a/std/gkr/compile.go b/std/gkr/compile.go index ef42601cdc..1c744f3853 100644 --- a/std/gkr/compile.go +++ b/std/gkr/compile.go @@ -3,8 +3,6 @@ package gkr import ( "fmt" "github.com/consensys/gnark/frontend" - fiatshamir "github.com/consensys/gnark/std/fiat-shamir" - "github.com/consensys/gnark/std/hash/mimc" "github.com/consensys/gnark/std/utils/algo_utils" "math/bits" "sort" @@ -106,7 +104,9 @@ func (d *circuitDataNoPtr) compile() error { // (circuit Circuit, assignment Wir } } // TODO: Check that dependencies and explicit assignments cover all instances - if !oldW.isInput() { + if oldW.isInput() { + algo_utils.Permute(oldW.assignments, instancePermutationInv) + } else { d.maxNIns = max(d.maxNIns, len(oldW.inputs)) } @@ -121,8 +121,6 @@ func (d *circuitDataNoPtr) compile() error { // (circuit Circuit, assignment Wir return oldW.dependencies[i].inputInstance < oldW.dependencies[j].inputInstance }) - algo_utils.Permute(oldW.assignments, instancePermutationInv) - sorted[newI] = wireNoPtr{ assignments: oldW.assignments, gate: oldW.gate, @@ -250,18 +248,17 @@ func (i *API) Compile(parentApi frontend.API) ([][]frontend.Variable, error) { } i.noPtr.circuit.addOutputAssignments(outs) + i.forSnark = i.noPtr.forSnark() - var ( + /*var ( proofSerialized []frontend.Variable proof Proof _mimc mimc.MiMC ) - i.forSnark = i.noPtr.forSnark() - if proofSerialized, err = parentApi.Compiler().NewHint( proveHint(i.typed), ProofSize(i.forSnark.circuit, logNbInstances(uint(nbInstances)))); // , outsSerialized[0] <- do this as a hack if order of execution got messed up - err != nil { + err != nil { return nil, err } @@ -276,7 +273,7 @@ func (i *API) Compile(parentApi frontend.API) ([][]frontend.Variable, error) { if err = Verify(parentApi, i.forSnark.circuit, i.forSnark.assignments, proof, fiatshamir.WithHash(&_mimc), WithSortedCircuit(forSnarkSorted)); err != nil { // TODO: Security critical: do a proper transcriptSetting return nil, err - } + }*/ i.noPtr.toVirtualOrder(outs) @@ -337,10 +334,11 @@ func (d *circuitDataNoPtr) forSnark() circuitDataForSnark { } func (d *circuitDataNoPtr) toVirtualOrder(outs [][]frontend.Variable) { - for j := range d.circuit { + for j := range outs { algo_utils.Permute(outs[j], d.sortedInstances) } - algo_utils.Permute(outs, d.sortedWires) + // as long as topologicalSort sticks to the current order "as much as possible", the relative orders of the output wires will + // not have been disrupted so there is no need to reorder the out wires. TODO: Do it anyway } // assignmentOffsets returns the index of the first value assigned to a wire TODO: Explain clearly diff --git a/std/gkr/gkr.go b/std/gkr/gkr.go index ed45c5aabf..5ad0b08746 100644 --- a/std/gkr/gkr.go +++ b/std/gkr/gkr.go @@ -538,6 +538,7 @@ func (g MulGate) Evaluate(api frontend.API, x ...frontend.Variable) frontend.Var return api.Mul(x[0], x[1]) } +// TODO: Degree must take nbInputs as an argument and return degree = nbInputs func (g MulGate) Degree() int { return 2 } diff --git a/std/gkr/switch_cases.go b/std/gkr/switch_cases.go index 0c4c72e665..34a7342251 100644 --- a/std/gkr/switch_cases.go +++ b/std/gkr/switch_cases.go @@ -24,10 +24,12 @@ func proveHint(data interface{}) func(*big.Int, []*big.Int, []*big.Int) error { if data == nil { return fmt.Errorf("attempting to run the prove hint before the solve hint is done. find a way to create a dependence between them (perhaps an output of the solver to be input to the prover as a hack)") } - switch mod { - case bn254.Modulus(): + var err error + if mod.Cmp(bn254.Modulus()) == 0 { // TODO: Switch case? return bn254ProveHint(data.(bn254CircuitData), ins, outs) + } else { + err = fmt.Errorf("unknow modulus") } - return fmt.Errorf("unknow modulus") + return err } } From 0fbf16328166aefc052cc2460a4ecc8839bc0559 Mon Sep 17 00:00:00 2001 From: Arya Tabaie Date: Wed, 11 Jan 2023 11:47:46 -0500 Subject: [PATCH 17/71] fix: solving works on the simplest example --- std/gkr/api_test.go | 3 ++- std/gkr/bn254_solve.go | 52 +++++++++++++++++++++++++++++++++++++++--- 2 files changed, 51 insertions(+), 4 deletions(-) diff --git a/std/gkr/api_test.go b/std/gkr/api_test.go index 800f4d42ee..0c59b24358 100644 --- a/std/gkr/api_test.go +++ b/std/gkr/api_test.go @@ -33,6 +33,7 @@ func (c *mulNoDependencyCircuit) Define(api frontend.API) error { for i := range c.X { api.Println("z@", i, " = ", Z[i]) + api.Println("x.y = ", api.Mul(c.X[i], c.Y[i])) api.AssertIsEqual(Z[i], api.Mul(c.X[i], c.Y[i])) } return nil @@ -41,7 +42,7 @@ func (c *mulNoDependencyCircuit) Define(api frontend.API) error { func TestSolveMulNoDependency(t *testing.T) { assignment := mulNoDependencyCircuit{ X: []frontend.Variable{1, 2}, - Y: []frontend.Variable{2, 3}, + Y: []frontend.Variable{0, 3}, } circuit := mulNoDependencyCircuit{ X: make([]frontend.Variable, 2), diff --git a/std/gkr/bn254_solve.go b/std/gkr/bn254_solve.go index 706df19754..e34c9156a8 100644 --- a/std/gkr/bn254_solve.go +++ b/std/gkr/bn254_solve.go @@ -1,9 +1,13 @@ package gkr import ( + "encoding/json" + "fmt" "github.com/consensys/gnark-crypto/ecc/bn254/fr" "github.com/consensys/gnark-crypto/ecc/bn254/fr/gkr" "github.com/consensys/gnark-crypto/ecc/bn254/fr/polynomial" + "github.com/consensys/gnark-crypto/ecc/bn254/fr/test_vector_utils" + "github.com/consensys/gnark/std/utils/algo_utils" "math/big" ) @@ -25,16 +29,22 @@ func bn254Solve(noPtr circuitDataNoPtr, typed bn254CircuitData, assignmentVector } for instanceI := 0; instanceI < nbInstances; instanceI++ { + fmt.Println("instance", instanceI) for wireI, wire := range circuit { + fmt.Print("\twire ", wireI, ": ") if wire.isInput() { + fmt.Print("input.") if nbDepsResolved[wireI] < len(wire.dependencies) && instanceI == wire.dependencies[nbDepsResolved[wireI]].inputInstance { + fmt.Print(" copying value from dependency") dep := wire.dependencies[nbDepsResolved[wireI]] assignments[wireI][instanceI].Set(&assignments[dep.outputWire][dep.outputInstance]) nbDepsResolved[wireI]++ } else { + fmt.Print(" taking value from input") assignments[wireI][instanceI].SetBigInt(assignmentVector[offsets[wireI]+instanceI-nbDepsResolved[wireI]]) } } else { + fmt.Print("gated.") // assemble the inputs inputIndexes := noPtr.circuit[wireI].inputs for i, inputI := range inputIndexes { @@ -43,6 +53,7 @@ func bn254Solve(noPtr circuitDataNoPtr, typed bn254CircuitData, assignmentVector gate := typed.circuit[wireI].Gate assignments[wireI][instanceI] = gate.Evaluate(inputs[:len(inputIndexes)]...) } + fmt.Println("\n\t\tresult: ", assignments[wireI][instanceI].Text(10)) } } return assignments @@ -62,8 +73,8 @@ func bn254SetOutputValues(circuit []wireNoPtr, assignments bn254AssignmentNoPtr, if circuit[i].isOutput() { for j := range assignments[i] { assignments[i][j].BigInt(outs[outsI]) + outsI++ } - outsI++ } } // Check if outsI == len(outs)? @@ -72,13 +83,48 @@ func bn254SetOutputValues(circuit []wireNoPtr, assignments bn254AssignmentNoPtr, func bn254SolveHint(data circuitDataNoPtr, ins []*big.Int, outs []*big.Int) (bn254CircuitData, error) { res := bn254CircuitData{ - circuit: bn254ConvertCircuit(data.circuit), - memoryPool: polynomial.NewPool(256, 1<<11), // TODO: Get clever with limits + circuit: bn254ConvertCircuit(data.circuit), // TODO: Take this out of here into the proving module + memoryPool: polynomial.NewPool(256, 1<<11), // TODO: Get clever with limits } assignments := bn254Solve(data, res, ins) res.assignments = toBn254MapAssignment(res.circuit, assignments) bn254SetOutputValues(data.circuit, assignments, outs) + fmt.Println("assignment ", sliceSliceToString(assignments)) + fmt.Println("returning ", bigIntPtrSliceToString(outs)) + return res, nil } + +func bigIntPtrSliceToString(slice []*big.Int) []int64 { + return algo_utils.Map(slice, func(e *big.Int) int64 { + if !e.IsInt64() { + panic("int too big") + } + return e.Int64() + }) +} + +func sliceSliceToString(slice [][]fr.Element) string { + printable := make([]interface{}, len(slice)) + for i, s := range slice { + printable[i] = test_vector_utils.ElementSliceToInterfaceSlice(s) + } + res, err := json.Marshal(printable) + if err != nil { + panic(err.Error()) + } + return string(res) +} + +/* +func sliceToString(slice []fr.Element) string { + printable := test_vector_utils.ElementSliceToInterfaceSlice(slice) + res, err := json.Marshal(printable) + if err != nil { + panic(err.Error()) + } + return string(res) +} +*/ From 4087f5f50ab7979a4e63dee1411b1be64a6b1284 Mon Sep 17 00:00:00 2001 From: Arya Tabaie Date: Wed, 11 Jan 2023 12:26:41 -0500 Subject: [PATCH 18/71] test: with dependency. err: inputs are modified --- std/gkr/api.go | 60 ++++++++++++++++++++-------------------- std/gkr/api_test.go | 54 +++++++++++++++++++++++++++++++++++- std/gkr/bn254_circuit.go | 9 ------ std/gkr/compile.go | 58 +++++++++++++++++++------------------- test/engine.go | 38 +++++++++++++++++-------- 5 files changed, 139 insertions(+), 80 deletions(-) diff --git a/std/gkr/api.go b/std/gkr/api.go index 2199ecf1e0..5f86b9dbc5 100644 --- a/std/gkr/api.go +++ b/std/gkr/api.go @@ -11,139 +11,139 @@ func frontendVarToInt(a frontend.Variable) int { return int(a.(Variable)) } -func (i *API) newNonInputVariable(gate Gate, in []frontend.Variable) Variable { - i.noPtr.circuit = append(i.noPtr.circuit, wireNoPtr{ +func (api *API) newNonInputVariable(gate Gate, in []frontend.Variable) Variable { + api.noPtr.circuit = append(api.noPtr.circuit, wireNoPtr{ gate: gate, inputs: algo_utils.Map(in, frontendVarToInt), }) - return Variable(len(i.noPtr.circuit) - 1) + return Variable(len(api.noPtr.circuit) - 1) } -func (i *API) newVar2PlusIn(gate Gate, in1, in2 frontend.Variable, in ...frontend.Variable) Variable { +func (api *API) newVar2PlusIn(gate Gate, in1, in2 frontend.Variable, in ...frontend.Variable) Variable { inCombined := make([]frontend.Variable, 2+len(in)) inCombined[0] = in1 inCombined[1] = in2 for i := range in { inCombined[i+2] = in[i] } - return i.newNonInputVariable(gate, inCombined) + return api.newNonInputVariable(gate, inCombined) } -func (i *API) Add(i1, i2 frontend.Variable, in ...frontend.Variable) frontend.Variable { +func (api *API) Add(i1, i2 frontend.Variable, in ...frontend.Variable) frontend.Variable { //TODO implement me panic("implement me") } -func (i *API) Neg(i1 frontend.Variable) frontend.Variable { +func (api *API) Neg(i1 frontend.Variable) frontend.Variable { //TODO implement me panic("implement me") } -func (i *API) Sub(i1, i2 frontend.Variable, in ...frontend.Variable) frontend.Variable { +func (api *API) Sub(i1, i2 frontend.Variable, in ...frontend.Variable) frontend.Variable { //TODO implement me panic("implement me") } -func (i *API) Mul(i1, i2 frontend.Variable, in ...frontend.Variable) frontend.Variable { - return i.newVar2PlusIn(MulGate{}, i1, i2, in...) +func (api *API) Mul(i1, i2 frontend.Variable, in ...frontend.Variable) frontend.Variable { + return api.newVar2PlusIn(MulGate{}, i1, i2, in...) } -func (i *API) DivUnchecked(i1, i2 frontend.Variable) frontend.Variable { +func (api *API) DivUnchecked(i1, i2 frontend.Variable) frontend.Variable { //TODO implement me panic("implement me") } -func (i *API) Div(i1, i2 frontend.Variable) frontend.Variable { +func (api *API) Div(i1, i2 frontend.Variable) frontend.Variable { //TODO implement me panic("implement me") } -func (i *API) Inverse(i1 frontend.Variable) frontend.Variable { +func (api *API) Inverse(i1 frontend.Variable) frontend.Variable { //TODO implement me panic("implement me") } -func (i *API) ToBinary(i1 frontend.Variable, n ...int) []frontend.Variable { +func (api *API) ToBinary(i1 frontend.Variable, n ...int) []frontend.Variable { //TODO implement me panic("implement me") } -func (i *API) FromBinary(b ...frontend.Variable) frontend.Variable { +func (api *API) FromBinary(b ...frontend.Variable) frontend.Variable { //TODO implement me panic("implement me") } -func (i *API) Xor(a, b frontend.Variable) frontend.Variable { +func (api *API) Xor(a, b frontend.Variable) frontend.Variable { //TODO implement me panic("implement me") } -func (i *API) Or(a, b frontend.Variable) frontend.Variable { +func (api *API) Or(a, b frontend.Variable) frontend.Variable { //TODO implement me panic("implement me") } -func (i *API) And(a, b frontend.Variable) frontend.Variable { +func (api *API) And(a, b frontend.Variable) frontend.Variable { //TODO implement me panic("implement me") } -func (i *API) Select(b frontend.Variable, i1, i2 frontend.Variable) frontend.Variable { +func (api *API) Select(b frontend.Variable, i1, i2 frontend.Variable) frontend.Variable { //TODO implement me panic("implement me") } -func (i *API) Lookup2(b0, b1 frontend.Variable, i0, i1, i2, i3 frontend.Variable) frontend.Variable { +func (api *API) Lookup2(b0, b1 frontend.Variable, i0, i1, i2, i3 frontend.Variable) frontend.Variable { //TODO implement me panic("implement me") } -func (i *API) IsZero(i1 frontend.Variable) frontend.Variable { +func (api *API) IsZero(i1 frontend.Variable) frontend.Variable { //TODO implement me panic("implement me") } -func (i *API) Cmp(i1, i2 frontend.Variable) frontend.Variable { +func (api *API) Cmp(i1, i2 frontend.Variable) frontend.Variable { //TODO implement me panic("implement me") } -func (i *API) AssertIsEqual(i1, i2 frontend.Variable) { +func (api *API) AssertIsEqual(i1, i2 frontend.Variable) { //TODO implement me panic("implement me") } -func (i *API) AssertIsDifferent(i1, i2 frontend.Variable) { +func (api *API) AssertIsDifferent(i1, i2 frontend.Variable) { //TODO implement me panic("implement me") } -func (i *API) AssertIsBoolean(i1 frontend.Variable) { +func (api *API) AssertIsBoolean(i1 frontend.Variable) { //TODO implement me panic("implement me") } -func (i *API) AssertIsLessOrEqual(v frontend.Variable, bound frontend.Variable) { +func (api *API) AssertIsLessOrEqual(v frontend.Variable, bound frontend.Variable) { //TODO implement me panic("implement me") } -func (i *API) Println(a ...frontend.Variable) { +func (api *API) Println(a ...frontend.Variable) { //TODO implement me panic("implement me") } -func (i *API) Compiler() frontend.Compiler { +func (api *API) Compiler() frontend.Compiler { //TODO implement me panic("implement me") } -func (i *API) NewHint(f hint.Function, nbOutputs int, inputs ...frontend.Variable) ([]frontend.Variable, error) { +func (api *API) NewHint(f hint.Function, nbOutputs int, inputs ...frontend.Variable) ([]frontend.Variable, error) { //TODO implement me panic("implement me") } -func (i *API) ConstantValue(v frontend.Variable) (*big.Int, bool) { +func (api *API) ConstantValue(v frontend.Variable) (*big.Int, bool) { //TODO implement me panic("implement me") } diff --git a/std/gkr/api_test.go b/std/gkr/api_test.go index 0c59b24358..0aa5a585f9 100644 --- a/std/gkr/api_test.go +++ b/std/gkr/api_test.go @@ -39,7 +39,7 @@ func (c *mulNoDependencyCircuit) Define(api frontend.API) error { return nil } -func TestSolveMulNoDependency(t *testing.T) { +func TestMulNoDependency(t *testing.T) { assignment := mulNoDependencyCircuit{ X: []frontend.Variable{1, 2}, Y: []frontend.Variable{0, 3}, @@ -51,6 +51,58 @@ func TestSolveMulNoDependency(t *testing.T) { test.NewAssert(t).SolvingSucceeded(&circuit, &assignment, test.WithBackends(backend.GROTH16), test.WithCurves(ecc.BN254)) } +type mulWithDependencyCircuit struct { + XLast frontend.Variable + Y []frontend.Variable +} + +func (c *mulWithDependencyCircuit) Define(api frontend.API) error { + gkr := NewApi() + var x, y frontend.Variable + var err error + + X := make([]frontend.Variable, len(c.Y)) + X[len(c.Y)-1] = c.XLast + if x, err = gkr.Import(X); err != nil { + return err + } + if y, err = gkr.Import(c.Y); err != nil { + return err + } + z := gkr.Mul(x, y) + + for i := len(X) - 1; i > 0; i-- { + gkr.Series(x, z, i-1, i) + } + + var gkrOuts [][]frontend.Variable + if gkrOuts, err = gkr.Compile(api); err != nil { + return err + } + Z := gkrOuts[0] + + api.Println("after solving, z=", Z, ", x=", X, ", y=", c.Y) + + for i := len(X) - 1; i >= 0; i-- { + api.AssertIsEqual(Z[i], api.Mul(X[i], c.Y[i])) + if i > 0 { + api.AssertIsEqual(Z[i], X[i-1]) + } + } + return nil +} + +func TestSolveMulWithDependency(t *testing.T) { + + assignment := mulWithDependencyCircuit{ + XLast: 1, + Y: []frontend.Variable{3, 2}, + } + circuit := mulWithDependencyCircuit{Y: make([]frontend.Variable, len(assignment.Y))} + + test.NewAssert(t).SolvingSucceeded(&circuit, &assignment, test.WithBackends(backend.GROTH16), test.WithCurves(ecc.BN254)) +} + func TestApiMul(t *testing.T) { var ( x Variable diff --git a/std/gkr/bn254_circuit.go b/std/gkr/bn254_circuit.go index f8f7423d59..955daa1c3b 100644 --- a/std/gkr/bn254_circuit.go +++ b/std/gkr/bn254_circuit.go @@ -59,15 +59,6 @@ func (c gateConverter) Evaluate(ins ...fr.Element) fr.Element { type gateConversionApi struct{} -/*func forceElemPtr(elems []fr.Element, i1, i2 frontend.Variable, in ...frontend.Variable) []*fr.Element { - res := make([]*fr.Element, 2+len(in)) - res[0] = &elems[i1.(int)] - res[1] = &elems[i2.(int)] - for i := range in { - res[2+i] = &elems[in[i].(int)] - } -}*/ - func varsToElems(i1, i2 frontend.Variable, in ...frontend.Variable) []fr.Element { res := make([]fr.Element, 2+len(in)) res[0] = i1.(fr.Element) diff --git a/std/gkr/compile.go b/std/gkr/compile.go index 1c744f3853..4126b2ef6b 100644 --- a/std/gkr/compile.go +++ b/std/gkr/compile.go @@ -59,12 +59,12 @@ func (c circuitNoPtr) nbInstances() int { return -1 } -func (i *API) nbInstances() int { - return i.noPtr.circuit.nbInstances() +func (api *API) nbInstances() int { + return api.noPtr.circuit.nbInstances() } -func (i *API) logNbInstances() int { - return logNbInstances(uint(i.nbInstances())) +func (api *API) logNbInstances() int { + return logNbInstances(uint(api.nbInstances())) } // compile sorts the circuit wires, their dependencies and the instances @@ -142,8 +142,8 @@ func (d *circuitDataNoPtr) newInputVariable(assignment []frontend.Variable) Vari return Variable(i) } -func (i *API) isCompiled() bool { - return i.forSnark.circuit != nil +func (api *API) isCompiled() bool { + return api.forSnark.circuit != nil } func NewApi() *API { @@ -165,21 +165,23 @@ func logNbInstances(nbInstances uint) int { } // Series like in an electric circuit, binds an input of an instance to an output of another -func (i *API) Series(input, output Variable, inputInstance, outputInstance int) *API { - if i.noPtr.circuit[input].assignments[inputInstance] != nil { +func (api *API) Series(input, output frontend.Variable, inputInstance, outputInstance int) *API { + i := input.(Variable) + o := output.(Variable) + if api.noPtr.circuit[i].assignments[inputInstance] != nil { panic("dependency attempting to override explicit value assignment") } - i.noPtr.circuit[input].dependencies = - append(i.noPtr.circuit[input].dependencies, inputDependency{ - outputWire: int(output), + api.noPtr.circuit[i].dependencies = + append(api.noPtr.circuit[i].dependencies, inputDependency{ + outputWire: int(o), outputInstance: outputInstance, inputInstance: inputInstance, }) - return i + return api } -func (i *API) Import(assignment []frontend.Variable) (Variable, error) { - if i.isCompiled() { +func (api *API) Import(assignment []frontend.Variable) (Variable, error) { + if api.isCompiled() { return -1, fmt.Errorf("cannot import variables into compiled circuit") } nbInstances := len(assignment) @@ -188,11 +190,11 @@ func (i *API) Import(assignment []frontend.Variable) (Variable, error) { return -1, fmt.Errorf("number of assignments must be a power of 2") } - if currentNbInstances := i.nbInstances(); currentNbInstances != -1 && currentNbInstances != nbInstances { + if currentNbInstances := api.nbInstances(); currentNbInstances != -1 && currentNbInstances != nbInstances { return -1, fmt.Errorf("number of assignments must be consistent across all variables") } - return i.noPtr.newInputVariable(assignment), nil + return api.noPtr.newInputVariable(assignment), nil } func appendNonNil(dst *[]frontend.Variable, src []frontend.Variable) { @@ -204,16 +206,16 @@ func appendNonNil(dst *[]frontend.Variable, src []frontend.Variable) { } // Compile finalizes the GKR circuit and returns the output variables in the order created -func (i *API) Compile(parentApi frontend.API) ([][]frontend.Variable, error) { - if i.isCompiled() { +func (api *API) Compile(parentApi frontend.API) ([][]frontend.Variable, error) { + if api.isCompiled() { return nil, fmt.Errorf("already compiled") } - if err := i.noPtr.compile(); err != nil { + if err := api.noPtr.compile(); err != nil { return nil, err } - nbInstances := i.nbInstances() - circuit := i.noPtr.circuit + nbInstances := api.nbInstances() + circuit := api.noPtr.circuit solveHintNIn := 0 solveHintNOut := 0 @@ -235,7 +237,7 @@ func (i *API) Compile(parentApi frontend.API) ([][]frontend.Variable, error) { } } - outsSerialized, err := parentApi.Compiler().NewHint(solveHint(&i.circuitData), solveHintNOut, ins...) + outsSerialized, err := parentApi.Compiler().NewHint(solveHint(&api.circuitData), solveHintNOut, ins...) if err != nil { return nil, err } @@ -247,8 +249,8 @@ func (i *API) Compile(parentApi frontend.API) ([][]frontend.Variable, error) { outsSerialized = outsSerialized[nbInstances:] } - i.noPtr.circuit.addOutputAssignments(outs) - i.forSnark = i.noPtr.forSnark() + api.noPtr.circuit.addOutputAssignments(outs) + api.forSnark = api.noPtr.forSnark() /*var ( proofSerialized []frontend.Variable @@ -257,12 +259,12 @@ func (i *API) Compile(parentApi frontend.API) ([][]frontend.Variable, error) { ) if proofSerialized, err = parentApi.Compiler().NewHint( - proveHint(i.typed), ProofSize(i.forSnark.circuit, logNbInstances(uint(nbInstances)))); // , outsSerialized[0] <- do this as a hack if order of execution got messed up + proveHint(api.typed), ProofSize(api.forSnark.circuit, logNbInstances(uint(nbInstances)))); // , outsSerialized[0] <- do this as a hack if order of execution got messed up err != nil { return nil, err } - forSnarkSorted := algo_utils.MapRange(0, len(circuit), slicePtrAt(i.forSnark.circuit)) + forSnarkSorted := algo_utils.MapRange(0, len(circuit), slicePtrAt(api.forSnark.circuit)) if proof, err = DeserializeProof(forSnarkSorted, proofSerialized); err != nil { return nil, err @@ -271,11 +273,11 @@ func (i *API) Compile(parentApi frontend.API) ([][]frontend.Variable, error) { return nil, err } - if err = Verify(parentApi, i.forSnark.circuit, i.forSnark.assignments, proof, fiatshamir.WithHash(&_mimc), WithSortedCircuit(forSnarkSorted)); err != nil { // TODO: Security critical: do a proper transcriptSetting + if err = Verify(parentApi, api.forSnark.circuit, api.forSnark.assignments, proof, fiatshamir.WithHash(&_mimc), WithSortedCircuit(forSnarkSorted)); err != nil { // TODO: Security critical: do a proper transcriptSetting return nil, err }*/ - i.noPtr.toVirtualOrder(outs) + api.noPtr.toVirtualOrder(outs) return outs, nil } diff --git a/test/engine.go b/test/engine.go index b092641196..84ffc79b63 100644 --- a/test/engine.go +++ b/test/engine.go @@ -405,23 +405,37 @@ func (e *engine) Println(a ...frontend.Variable) { } for i := 0; i < len(a); i++ { - if s, ok := a[i].(string); ok { - sbb.WriteString(s) - } else { - v := e.toBigInt(a[i]) - var vAsNeg big.Int - vAsNeg.Sub(v, e.q) - if vAsNeg.IsInt64() { - sbb.WriteString(strconv.FormatInt(vAsNeg.Int64(), 10)) - } else { - sbb.WriteString(v.String()) - } - } + e.print(&sbb, a[i]) sbb.WriteByte(' ') } fmt.Println(sbb.String()) } +func (e *engine) print(sbb *strings.Builder, x interface{}) { + switch v := x.(type) { + case string: + sbb.WriteString(v) + case []frontend.Variable: + sbb.WriteRune('[') + for i := range v { + e.print(sbb, v[i]) + if i+1 != len(v) { + sbb.WriteRune(',') + } + } + sbb.WriteRune(']') + default: + i := e.toBigInt(v) + var iAsNeg big.Int + iAsNeg.Sub(i, e.q) + if iAsNeg.IsInt64() { + sbb.WriteString(strconv.FormatInt(iAsNeg.Int64(), 10)) + } else { + sbb.WriteString(i.String()) + } + } +} + func (e *engine) NewHint(f hint.Function, nbOutputs int, inputs ...frontend.Variable) ([]frontend.Variable, error) { if nbOutputs <= 0 { From defabf652dda351a1e3bbf387b57c3d646d223bf Mon Sep 17 00:00:00 2001 From: Arya Tabaie Date: Thu, 12 Jan 2023 12:11:56 -0500 Subject: [PATCH 19/71] fix: solver works. prover doesn't. possibly deeper gkr issue --- std/fiat-shamir/transcript.go | 10 ++ std/gkr/api.go | 3 +- std/gkr/api_test.go | 140 +++++++++++++++-- std/gkr/bn254_circuit.go | 9 +- std/gkr/bn254_prove.go | 11 +- std/gkr/bn254_solve.go | 11 -- std/gkr/compile.go | 146 ++++++++---------- std/gkr/gkr.go | 14 ++ std/gkr/switch_cases.go | 13 +- std/hash/hash.go | 7 +- std/hash/mimc/mimc.go | 11 ++ std/sumcheck/sumcheck.go | 2 + .../test_vectors_utils/test_vector_utils.go | 5 + 13 files changed, 263 insertions(+), 119 deletions(-) diff --git a/std/fiat-shamir/transcript.go b/std/fiat-shamir/transcript.go index 97a35ca62a..bbea588e68 100644 --- a/std/fiat-shamir/transcript.go +++ b/std/fiat-shamir/transcript.go @@ -73,6 +73,10 @@ func NewTranscript(api frontend.API, h hash.Hash, challengesID ...string) Transc // binded to other values. func (t *Transcript) Bind(challengeID string, values []frontend.Variable) error { + toPrint := []frontend.Variable{"snark binding to ", challengeID, ":"} + toPrint = append(toPrint, values...) + t.api.Println(toPrint...) + challenge, ok := t.challenges[challengeID] if !ok { @@ -120,6 +124,10 @@ func (t *Transcript) ComputeChallenge(challengeID string) (frontend.Variable, er t.h.Write(t.previous.value) } + toPrint := []frontend.Variable{"snark bindings:"} + toPrint = append(toPrint, challenge.bindings...) + t.api.Println(toPrint...) + // write the binded values in the order they were added t.h.Write(challenge.bindings...) @@ -132,6 +140,8 @@ func (t *Transcript) ComputeChallenge(challengeID string) (frontend.Variable, er t.h.Reset() + t.api.Println("snark challenge \"", challengeID, "\" <- ", challenge.value) + return challenge.value, nil } diff --git a/std/gkr/api.go b/std/gkr/api.go index 5f86b9dbc5..fce1dc5c35 100644 --- a/std/gkr/api.go +++ b/std/gkr/api.go @@ -30,8 +30,7 @@ func (api *API) newVar2PlusIn(gate Gate, in1, in2 frontend.Variable, in ...front } func (api *API) Add(i1, i2 frontend.Variable, in ...frontend.Variable) frontend.Variable { - //TODO implement me - panic("implement me") + return api.newVar2PlusIn(AddGate{}, i1, i2, in...) } func (api *API) Neg(i1 frontend.Variable) frontend.Variable { diff --git a/std/gkr/api_test.go b/std/gkr/api_test.go index 0aa5a585f9..a9164244ad 100644 --- a/std/gkr/api_test.go +++ b/std/gkr/api_test.go @@ -1,15 +1,94 @@ package gkr import ( + "fmt" "github.com/consensys/gnark-crypto/ecc" + bn254TestVectorUtils "github.com/consensys/gnark-crypto/ecc/bn254/fr/test_vector_utils" "github.com/consensys/gnark/backend" "github.com/consensys/gnark/frontend" + "github.com/consensys/gnark/std/hash/mimc" "github.com/consensys/gnark/std/utils/test_vectors_utils" "github.com/consensys/gnark/test" "github.com/stretchr/testify/assert" + "hash" "testing" ) +type doubleNoDependencyCircuit struct { + X []frontend.Variable +} + +func (c *doubleNoDependencyCircuit) Define(api frontend.API) error { + gkr := NewApi() + var x frontend.Variable + var err error + if x, err = gkr.Import(c.X); err != nil { + return err + } + z := gkr.Add(x, x) + var solution Solution + if solution, err = gkr.Solve(api); err != nil { + return err + } + Z := solution.Export(z) + + for i := range Z { + api.AssertIsEqual(Z[i], api.Mul(2, c.X[i])) + } + + var hsh mimc.MiMC + if hsh, err = mimc.NewMiMC(api); err != nil { + return err + } + //hsh := messageCounter{startState: 0, step: 1} + return solution.Verify(&hsh) +} + +func TestDoubleNoDependencyCircuit(t *testing.T) { + assignment := doubleNoDependencyCircuit{X: []frontend.Variable{1, 1}} + circuit := doubleNoDependencyCircuit{X: make([]frontend.Variable, 2)} + + test.NewAssert(t).SolvingSucceeded(&circuit, &assignment, test.WithBackends(backend.GROTH16), test.WithCurves(ecc.BN254)) +} + +type sqNoDependencyCircuit struct { + X []frontend.Variable +} + +func (c *sqNoDependencyCircuit) Define(api frontend.API) error { + gkr := NewApi() + var x frontend.Variable + var err error + if x, err = gkr.Import(c.X); err != nil { + return err + } + z := gkr.Mul(x, x) + var solution Solution + if solution, err = gkr.Solve(api); err != nil { + return err + } + Z := solution.Export(z) + + for i := range Z { + api.AssertIsEqual(Z[i], api.Mul(c.X[i], c.X[i])) + } + + var hsh mimc.MiMC + if hsh, err = mimc.NewMiMC(api); err != nil { + return err + } + //var hsh hash.Hash = &literalSum{initialState: 0} + //hsh := messageCounter{startState: 0, step: 1} + return solution.Verify(&hsh) +} + +func TestSqNoDependencyCircuit(t *testing.T) { + assignment := sqNoDependencyCircuit{X: []frontend.Variable{1, 1}} + circuit := sqNoDependencyCircuit{X: make([]frontend.Variable, 2)} + + test.NewAssert(t).SolvingSucceeded(&circuit, &assignment, test.WithBackends(backend.GROTH16), test.WithCurves(ecc.BN254)) +} + type mulNoDependencyCircuit struct { X, Y []frontend.Variable } @@ -24,19 +103,28 @@ func (c *mulNoDependencyCircuit) Define(api frontend.API) error { if y, err = gkr.Import(c.Y); err != nil { return err } - gkr.Mul(x, y) - var gkrOuts [][]frontend.Variable - if gkrOuts, err = gkr.Compile(api); err != nil { + z := gkr.Mul(x, y) + var solution Solution + if solution, err = gkr.Solve(api); err != nil { return err } - Z := gkrOuts[0] + X := solution.Export(x) + Y := solution.Export(y) + Z := solution.Export(z) + api.Println("after solving, z=", Z, ", x=", X, ", y=", Y) for i := range c.X { api.Println("z@", i, " = ", Z[i]) api.Println("x.y = ", api.Mul(c.X[i], c.Y[i])) api.AssertIsEqual(Z[i], api.Mul(c.X[i], c.Y[i])) } - return nil + + var hsh mimc.MiMC + if hsh, err = mimc.NewMiMC(api); err != nil { + return err + } + //hsh := messageCounter{startState: 0, step: 1} + return solution.Verify(&hsh) } func TestMulNoDependency(t *testing.T) { @@ -75,19 +163,20 @@ func (c *mulWithDependencyCircuit) Define(api frontend.API) error { gkr.Series(x, z, i-1, i) } - var gkrOuts [][]frontend.Variable - if gkrOuts, err = gkr.Compile(api); err != nil { + var solution Solution + if solution, err = gkr.Solve(api); err != nil { return err } - Z := gkrOuts[0] + X = solution.Export(x) + Y := solution.Export(y) + Z := solution.Export(z) - api.Println("after solving, z=", Z, ", x=", X, ", y=", c.Y) + api.Println("after solving, z=", Z, ", x=", X, ", y=", Y) - for i := len(X) - 1; i >= 0; i-- { - api.AssertIsEqual(Z[i], api.Mul(X[i], c.Y[i])) - if i > 0 { - api.AssertIsEqual(Z[i], X[i-1]) - } + lastI := len(X) - 1 + api.AssertIsEqual(Z[lastI], api.Mul(c.XLast, Y[lastI])) + for i := 0; i < lastI; i++ { + api.AssertIsEqual(Z[i], api.Mul(Z[i+1], Y[i])) } return nil } @@ -129,3 +218,26 @@ func TestApiMul(t *testing.T) { assert.Equal(t, y.nbUniqueOutputs, 1) assert.Equal(t, z.nbUniqueOutputs, 0)*/ } + +type messageCounter struct { + startState int + step int + state int +} + +func (c *messageCounter) Sum() frontend.Variable { + fmt.Println("snarkHash returning", c.state) + return c.state +} + +func (c *messageCounter) Write(data ...frontend.Variable) { + c.state += len(data) * c.step +} + +func (c *messageCounter) Reset() { + c.state = c.startState +} + +func (c *messageCounter) ToStandard() hash.Hash { + return bn254TestVectorUtils.NewMessageCounter(c.startState, c.step) +} diff --git a/std/gkr/bn254_circuit.go b/std/gkr/bn254_circuit.go index 955daa1c3b..f297e61b80 100644 --- a/std/gkr/bn254_circuit.go +++ b/std/gkr/bn254_circuit.go @@ -70,8 +70,13 @@ func varsToElems(i1, i2 frontend.Variable, in ...frontend.Variable) []fr.Element } func (c *gateConversionApi) Add(i1, i2 frontend.Variable, in ...frontend.Variable) frontend.Variable { - //TODO implement me - panic("implement me") + elems := varsToElems(i1, i2, in...) + var res fr.Element + res.Add(&elems[0], &elems[1]) + for i := range in { + res.Add(&res, &elems[i+2]) + } + return res } func (c *gateConversionApi) Neg(i1 frontend.Variable) frontend.Variable { diff --git a/std/gkr/bn254_prove.go b/std/gkr/bn254_prove.go index 46071a4b2d..fddeb2634b 100644 --- a/std/gkr/bn254_prove.go +++ b/std/gkr/bn254_prove.go @@ -1,11 +1,9 @@ package gkr import ( - "fmt" "github.com/consensys/gnark-crypto/ecc/bn254/fr" "github.com/consensys/gnark-crypto/ecc/bn254/fr/gkr" - "github.com/consensys/gnark-crypto/ecc/bn254/fr/mimc" - fiatshamir "github.com/consensys/gnark-crypto/fiat-shamir" + curveFS "github.com/consensys/gnark-crypto/fiat-shamir" "math/big" ) @@ -15,12 +13,9 @@ func bn254FrToBigInts(dst []*big.Int, src []fr.Element) { } } -func bn254ProveHint(data bn254CircuitData, ins []*big.Int, outs []*big.Int) error { - if len(ins) != 0 { - return fmt.Errorf("the prove hint takes no input") - } +func bn254ProveHint(data bn254CircuitData, transcriptSettings curveFS.Settings, outs []*big.Int) error { - proof, err := gkr.Prove(data.circuit, data.assignments, fiatshamir.WithHash(mimc.NewMiMC()), gkr.WithPool(&data.memoryPool)) // TODO: Do transcriptSettings properly + proof, err := gkr.Prove(data.circuit, data.assignments, transcriptSettings, gkr.WithPool(&data.memoryPool)) // TODO: Do transcriptSettings properly if err != nil { return err } diff --git a/std/gkr/bn254_solve.go b/std/gkr/bn254_solve.go index e34c9156a8..7561495877 100644 --- a/std/gkr/bn254_solve.go +++ b/std/gkr/bn254_solve.go @@ -117,14 +117,3 @@ func sliceSliceToString(slice [][]fr.Element) string { } return string(res) } - -/* -func sliceToString(slice []fr.Element) string { - printable := test_vector_utils.ElementSliceToInterfaceSlice(slice) - res, err := json.Marshal(printable) - if err != nil { - panic(err.Error()) - } - return string(res) -} -*/ diff --git a/std/gkr/compile.go b/std/gkr/compile.go index 4126b2ef6b..d312896084 100644 --- a/std/gkr/compile.go +++ b/std/gkr/compile.go @@ -3,6 +3,8 @@ package gkr import ( "fmt" "github.com/consensys/gnark/frontend" + fiatshamir "github.com/consensys/gnark/std/fiat-shamir" + "github.com/consensys/gnark/std/hash" "github.com/consensys/gnark/std/utils/algo_utils" "math/bits" "sort" @@ -39,15 +41,19 @@ type circuitDataForSnark struct { } type circuitData struct { - noPtr circuitDataNoPtr - forSnark circuitDataForSnark - typed interface{} // curve-dependent data. for communication between solver and prover + noPtr circuitDataNoPtr + typed interface{} // curve-dependent data. for communication between solver and prover } type API struct { circuitData } +type Solution struct { + circuitData + parentApi frontend.API +} + type Variable int // Just an alias to hide implementation details. May be more trouble than worth func (c circuitNoPtr) nbInstances() int { @@ -64,7 +70,7 @@ func (api *API) nbInstances() int { } func (api *API) logNbInstances() int { - return logNbInstances(uint(api.nbInstances())) + return log2(uint(api.nbInstances())) } // compile sorts the circuit wires, their dependencies and the instances @@ -81,7 +87,6 @@ func (d *circuitDataNoPtr) compile() error { // (circuit Circuit, assignment Wir d.sortedInstances, _ = algo_utils.TopologicalSort(instanceDeps) instancePermutationInv := algo_utils.InvertPermutation(d.sortedInstances) - //instancePermutationInvAt := algo_utils.SliceAt(instancePermutationInv) // this whole circuit sorting is a bit of a charade. if things are built using an api, there's no way it could NOT already be topologically sorted // worth keeping for future-proofing? @@ -106,6 +111,7 @@ func (d *circuitDataNoPtr) compile() error { // (circuit Circuit, assignment Wir if oldW.isInput() { algo_utils.Permute(oldW.assignments, instancePermutationInv) + //oldW.assignments = algo_utils.Map(d.sortedInstances, algo_utils.SliceAt(oldW.assignments)) TODO: This if decided not to modify the user-given assignments } else { d.maxNIns = max(d.maxNIns, len(oldW.inputs)) } @@ -142,10 +148,6 @@ func (d *circuitDataNoPtr) newInputVariable(assignment []frontend.Variable) Vari return Variable(i) } -func (api *API) isCompiled() bool { - return api.forSnark.circuit != nil -} - func NewApi() *API { return &API{circuitData{ noPtr: circuitDataNoPtr{ @@ -156,12 +158,12 @@ func NewApi() *API { }} } -// logNbInstances returns -1 if nbInstances is not a power of 2 -func logNbInstances(nbInstances uint) int { - if bits.OnesCount(nbInstances) != 1 { +// log2 returns -1 if x is not a power of 2 +func log2(x uint) int { + if bits.OnesCount(x) != 1 { return -1 } - return bits.TrailingZeros(nbInstances) + return bits.TrailingZeros(x) } // Series like in an electric circuit, binds an input of an instance to an output of another @@ -181,11 +183,8 @@ func (api *API) Series(input, output frontend.Variable, inputInstance, outputIns } func (api *API) Import(assignment []frontend.Variable) (Variable, error) { - if api.isCompiled() { - return -1, fmt.Errorf("cannot import variables into compiled circuit") - } nbInstances := len(assignment) - logNbInstances := logNbInstances(uint(nbInstances)) + logNbInstances := log2(uint(nbInstances)) if logNbInstances == -1 { return -1, fmt.Errorf("number of assignments must be a power of 2") } @@ -205,23 +204,21 @@ func appendNonNil(dst *[]frontend.Variable, src []frontend.Variable) { } } -// Compile finalizes the GKR circuit and returns the output variables in the order created -func (api *API) Compile(parentApi frontend.API) ([][]frontend.Variable, error) { - if api.isCompiled() { - return nil, fmt.Errorf("already compiled") - } +// Solve finalizes the GKR circuit and returns the output variables in the order created +func (api *API) Solve(parentApi frontend.API) (Solution, error) { if err := api.noPtr.compile(); err != nil { - return nil, err + return Solution{}, err } + nbInstances := api.nbInstances() circuit := api.noPtr.circuit solveHintNIn := 0 solveHintNOut := 0 - for j := range circuit { - v := &circuit[j] + for i := range circuit { + v := &circuit[i] if v.isInput() { solveHintNIn += nbInstances - len(v.dependencies) } else if v.isOutput() { @@ -231,74 +228,73 @@ func (api *API) Compile(parentApi frontend.API) ([][]frontend.Variable, error) { // arrange inputs wire first, then in the order solved ins := make([]frontend.Variable, 0, solveHintNIn) - for j := range circuit { - if circuit[j].isInput() { - appendNonNil(&ins, circuit[j].assignments) + for i := range circuit { + if circuit[i].isInput() { + appendNonNil(&ins, circuit[i].assignments) } } outsSerialized, err := parentApi.Compiler().NewHint(solveHint(&api.circuitData), solveHintNOut, ins...) if err != nil { - return nil, err + return Solution{}, err } - outs := make([][]frontend.Variable, len(outsSerialized)/nbInstances) + for i := range circuit { + w := &circuit[i] + if w.isOutput() { + w.assignments = outsSerialized[:nbInstances] + outsSerialized = outsSerialized[nbInstances:] + } + } - for j := range outs { - outs[j] = outsSerialized[:nbInstances] - outsSerialized = outsSerialized[nbInstances:] + for i := range circuit { + for _, dep := range circuit[i].dependencies { + circuit[i].assignments[dep.inputInstance] = circuit[dep.outputWire].assignments[dep.outputInstance] + } } - api.noPtr.circuit.addOutputAssignments(outs) - api.forSnark = api.noPtr.forSnark() + return Solution{ + circuitData: api.circuitData, + parentApi: parentApi, + }, nil +} + +func (s Solution) Export(v frontend.Variable) []frontend.Variable { + return algo_utils.Map(s.noPtr.sortedInstances, algo_utils.SliceAt(s.noPtr.circuit[v.(Variable)].assignments)) +} - /*var ( +func (s Solution) Verify(hash hash.Hash, initialChallenges ...frontend.Variable) error { + // TODO: Translate transcriptSettings from snark to field ugh + var ( + err error proofSerialized []frontend.Variable proof Proof - _mimc mimc.MiMC ) - if proofSerialized, err = parentApi.Compiler().NewHint( - proveHint(api.typed), ProofSize(api.forSnark.circuit, logNbInstances(uint(nbInstances)))); // , outsSerialized[0] <- do this as a hack if order of execution got messed up - err != nil { - return nil, err - } + forSnark := s.noPtr.forSnark() + logNbInstances := log2(uint(s.noPtr.circuit.nbInstances())) - forSnarkSorted := algo_utils.MapRange(0, len(circuit), slicePtrAt(api.forSnark.circuit)) + // TODO: Find out if this hack is necessary + /*for i := range s.noPtr.circuit { + if s.noPtr.circuit[i].isOutput() { + initialChallenges = append(initialChallenges, s.noPtr.circuit[i].assignments[0]) + break + } + }*/ - if proof, err = DeserializeProof(forSnarkSorted, proofSerialized); err != nil { - return nil, err - } - if _mimc, err = mimc.NewMiMC(parentApi); err != nil { - return nil, err + if proofSerialized, err = s.parentApi.Compiler().NewHint( + proveHint(s.typed, hash), ProofSize(forSnark.circuit, logNbInstances), initialChallenges...); err != nil { + return err } - if err = Verify(parentApi, api.forSnark.circuit, api.forSnark.assignments, proof, fiatshamir.WithHash(&_mimc), WithSortedCircuit(forSnarkSorted)); err != nil { // TODO: Security critical: do a proper transcriptSetting - return nil, err - }*/ + forSnarkSorted := algo_utils.MapRange(0, len(s.noPtr.circuit), slicePtrAt(forSnark.circuit)) - api.noPtr.toVirtualOrder(outs) + if proof, err = DeserializeProof(forSnarkSorted, proofSerialized); err != nil { + return err + } - return outs, nil -} + return Verify(s.parentApi, forSnark.circuit, forSnark.assignments, proof, fiatshamir.WithHash(hash, initialChallenges...), WithSortedCircuit(forSnarkSorted)) // TODO: Security critical: do a proper transcriptSetting -// completeAssignments creates assignment fields for the output vars and input instances that depend on them -func (c circuitNoPtr) addOutputAssignments(outs [][]frontend.Variable) { - outI := 0 - for i := range c { - if c[i].isOutput() { - c[i].assignments = outs[outI] - outI++ - } - } - for i := range c { - if c[i].dependencies != nil && !c[i].isInput() { // TODO: Remove - panic("data structure poorly maintained") - } - for _, dep := range c[i].dependencies { - c[i].assignments[dep.inputInstance] = c[dep.outputWire].assignments[dep.outputInstance] - } - } } type inputDependency struct { @@ -335,14 +331,6 @@ func (d *circuitDataNoPtr) forSnark() circuitDataForSnark { } } -func (d *circuitDataNoPtr) toVirtualOrder(outs [][]frontend.Variable) { - for j := range outs { - algo_utils.Permute(outs[j], d.sortedInstances) - } - // as long as topologicalSort sticks to the current order "as much as possible", the relative orders of the output wires will - // not have been disrupted so there is no need to reorder the out wires. TODO: Do it anyway -} - // assignmentOffsets returns the index of the first value assigned to a wire TODO: Explain clearly func (c circuitNoPtr) assignmentOffsets() []int { res := make([]int, len(c)+1) diff --git a/std/gkr/gkr.go b/std/gkr/gkr.go index 5ad0b08746..8de80f5a28 100644 --- a/std/gkr/gkr.go +++ b/std/gkr/gkr.go @@ -542,3 +542,17 @@ func (g MulGate) Evaluate(api frontend.API, x ...frontend.Variable) frontend.Var func (g MulGate) Degree() int { return 2 } + +type AddGate struct{} + +func (a AddGate) Evaluate(api frontend.API, v ...frontend.Variable) frontend.Variable { + var rest []frontend.Variable + if len(v) >= 2 { + rest = v[2:] + } + return api.Add(v[0], v[1], rest...) +} + +func (a AddGate) Degree() int { + return 1 +} diff --git a/std/gkr/switch_cases.go b/std/gkr/switch_cases.go index 34a7342251..e920bb80fe 100644 --- a/std/gkr/switch_cases.go +++ b/std/gkr/switch_cases.go @@ -3,6 +3,9 @@ package gkr import ( "fmt" bn254 "github.com/consensys/gnark-crypto/ecc/bn254/fr" + fiatshamir "github.com/consensys/gnark-crypto/fiat-shamir" + gnarkHash "github.com/consensys/gnark/std/hash" + "github.com/consensys/gnark/std/utils/algo_utils" "math/big" ) @@ -19,14 +22,20 @@ func solveHint(data *circuitData) func(*big.Int, []*big.Int, []*big.Int) error { } } -func proveHint(data interface{}) func(*big.Int, []*big.Int, []*big.Int) error { +func proveHint(data interface{}, hash gnarkHash.Hash) func(*big.Int, []*big.Int, []*big.Int) error { + hsh := hash.ToStandard() return func(mod *big.Int, ins []*big.Int, outs []*big.Int) error { if data == nil { return fmt.Errorf("attempting to run the prove hint before the solve hint is done. find a way to create a dependence between them (perhaps an output of the solver to be input to the prover as a hack)") } + + insAsBytes := algo_utils.Map(ins, func(i *big.Int) []byte { + return i.Bytes() + }) + var err error if mod.Cmp(bn254.Modulus()) == 0 { // TODO: Switch case? - return bn254ProveHint(data.(bn254CircuitData), ins, outs) + return bn254ProveHint(data.(bn254CircuitData), fiatshamir.WithHash(hsh, insAsBytes...), outs) } else { err = fmt.Errorf("unknow modulus") } diff --git a/std/hash/hash.go b/std/hash/hash.go index 55e8791084..e405806102 100644 --- a/std/hash/hash.go +++ b/std/hash/hash.go @@ -17,7 +17,10 @@ limitations under the License. // Package hash provides an interface that hash functions (as gadget) should implement. package hash -import "github.com/consensys/gnark/frontend" +import ( + "github.com/consensys/gnark/frontend" + "hash" +) type Hash interface { @@ -29,4 +32,6 @@ type Hash interface { // Reset empty the internal state and put the intermediate state to zero. Reset() + + ToStandard() hash.Hash } diff --git a/std/hash/mimc/mimc.go b/std/hash/mimc/mimc.go index 1a1dcc44db..d70e22a414 100644 --- a/std/hash/mimc/mimc.go +++ b/std/hash/mimc/mimc.go @@ -19,6 +19,8 @@ package mimc import ( "errors" + bn254 "github.com/consensys/gnark-crypto/ecc/bn254/fr/mimc" + "hash" "math/big" "github.com/consensys/gnark-crypto/ecc" @@ -72,3 +74,12 @@ func (h *MiMC) Sum() frontend.Variable { return h.h } + +func (h *MiMC) ToStandard() hash.Hash { + switch h.id { + // TODO: Take the parameters into account? + case ecc.BN254: + return bn254.NewMiMC() + } + panic("not implemented") +} diff --git a/std/sumcheck/sumcheck.go b/std/sumcheck/sumcheck.go index c3fb993d7e..768f044784 100644 --- a/std/sumcheck/sumcheck.go +++ b/std/sumcheck/sumcheck.go @@ -46,6 +46,7 @@ func setupTranscript(api frontend.API, claimsNum int, varsNum int, settings *fia func next(transcript *fiatshamir.Transcript, bindings []frontend.Variable, remainingChallengeNames *[]string) (frontend.Variable, error) { challengeName := (*remainingChallengeNames)[0] + if err := transcript.Bind(challengeName, bindings); err != nil { return nil, err } @@ -56,6 +57,7 @@ func next(transcript *fiatshamir.Transcript, bindings []frontend.Variable, remai } func Verify(api frontend.API, claims LazyClaims, proof Proof, transcriptSettings fiatshamir.Settings) error { + remainingChallengeNames, err := setupTranscript(api, claims.ClaimsNum(), claims.VarsNum(), &transcriptSettings) transcript := transcriptSettings.Transcript if err != nil { diff --git a/std/utils/test_vectors_utils/test_vector_utils.go b/std/utils/test_vectors_utils/test_vector_utils.go index 2f5dbc4a38..3c5a0013dc 100644 --- a/std/utils/test_vectors_utils/test_vector_utils.go +++ b/std/utils/test_vectors_utils/test_vector_utils.go @@ -4,6 +4,7 @@ import ( "encoding/json" "github.com/consensys/gnark/frontend" "github.com/stretchr/testify/assert" + "hash" "os" "path/filepath" "strconv" @@ -217,6 +218,10 @@ type MapHash struct { stateValid bool } +func (m *MapHash) ToStandard() hash.Hash { + panic("not implemented") +} + func (m *MapHash) Sum() frontend.Variable { return m.state } From 6097684177b9a6632d95d8c8a33cceb33e33a538 Mon Sep 17 00:00:00 2001 From: Arya Tabaie Date: Thu, 12 Jan 2023 17:18:38 -0500 Subject: [PATCH 20/71] bench: merkle tree --- std/gkr/api_test.go | 100 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 100 insertions(+) diff --git a/std/gkr/api_test.go b/std/gkr/api_test.go index a9164244ad..de6332aaa2 100644 --- a/std/gkr/api_test.go +++ b/std/gkr/api_test.go @@ -5,7 +5,9 @@ import ( "github.com/consensys/gnark-crypto/ecc" bn254TestVectorUtils "github.com/consensys/gnark-crypto/ecc/bn254/fr/test_vector_utils" "github.com/consensys/gnark/backend" + "github.com/consensys/gnark/backend/groth16" "github.com/consensys/gnark/frontend" + "github.com/consensys/gnark/frontend/cs/r1cs" "github.com/consensys/gnark/std/hash/mimc" "github.com/consensys/gnark/std/utils/test_vectors_utils" "github.com/consensys/gnark/test" @@ -241,3 +243,101 @@ func (c *messageCounter) Reset() { func (c *messageCounter) ToStandard() hash.Hash { return bn254TestVectorUtils.NewMessageCounter(c.startState, c.step) } + +func BenchmarkMiMCMerkleTree(b *testing.B) { + depth := 3 + bottom := make([]frontend.Variable, 1<= 0; d-- { + for i := 0; i < 1< Date: Wed, 18 Jan 2023 10:16:13 -0500 Subject: [PATCH 21/71] refactor: hint-lite, has import cycle --- backend/hint/registry.go | 2 +- constraint/bn254/gkr.go | 242 ++++++++++++++++++++++++++ constraint/bn254/r1cs.go | 4 +- constraint/bn254/solution.go | 2 +- constraint/gkr.go | 138 +++++++++++++++ constraint/system.go | 1 + frontend/circuit.go | 2 +- go.mod | 6 +- go.sum | 8 + std/gkr/api.go | 19 ++- std/gkr/api_test.go | 21 +-- std/gkr/bn254_circuit.go | 200 ---------------------- std/gkr/bn254_prove.go | 37 ---- std/gkr/bn254_solve.go | 119 ------------- std/gkr/compile.go | 264 ++++++++++------------------- std/gkr/compile_test.go | 89 +++++----- std/gkr/gkr_test.go | 30 +--- std/gkr/registry.go | 29 ++++ std/gkr/switch_cases.go | 44 ----- std/utils/algo_utils/algo_utils.go | 6 + test/engine_test.go | 25 +++ 21 files changed, 617 insertions(+), 671 deletions(-) create mode 100644 constraint/bn254/gkr.go create mode 100644 constraint/gkr.go delete mode 100644 std/gkr/bn254_circuit.go delete mode 100644 std/gkr/bn254_prove.go delete mode 100644 std/gkr/bn254_solve.go create mode 100644 std/gkr/registry.go delete mode 100644 std/gkr/switch_cases.go diff --git a/backend/hint/registry.go b/backend/hint/registry.go index 619c3a1715..dfd5a66b8d 100644 --- a/backend/hint/registry.go +++ b/backend/hint/registry.go @@ -9,7 +9,7 @@ import ( var registry = make(map[ID]Function) var registryM sync.RWMutex -// Register registers an hint function in the global registry. +// Register registers a hint function in the global registry. func Register(hintFns ...Function) { registryM.Lock() defer registryM.Unlock() diff --git a/constraint/bn254/gkr.go b/constraint/bn254/gkr.go new file mode 100644 index 0000000000..76e12988b5 --- /dev/null +++ b/constraint/bn254/gkr.go @@ -0,0 +1,242 @@ +package cs + +import ( + "encoding/json" + "fmt" + "github.com/consensys/gnark-crypto/ecc/bn254/fr" + "github.com/consensys/gnark-crypto/ecc/bn254/fr/gkr" + "github.com/consensys/gnark-crypto/ecc/bn254/fr/mimc" + "github.com/consensys/gnark-crypto/ecc/bn254/fr/polynomial" + "github.com/consensys/gnark-crypto/ecc/bn254/fr/test_vector_utils" + fiatshamir "github.com/consensys/gnark-crypto/fiat-shamir" + "github.com/consensys/gnark/backend/hint" + "github.com/consensys/gnark/constraint" + stdGkr "github.com/consensys/gnark/std/gkr" + "github.com/consensys/gnark/std/utils/algo_utils" + "math/big" +) + +type gkrSolvingData struct { + assignments gkr.WireAssignment + circuit gkr.Circuit + memoryPool polynomial.Pool +} + +var gateRegistry = make(map[string]gkr.Gate) // TODO: Migrate to gnark-crypto + +func init() { + gateRegistry["mul"] = mulGate(2) // in-built input count is problematic TODO fix + gateRegistry["add"] = addGate{} + //gateRegistry["mimc"] +} + +type mulGate int + +func (g mulGate) Evaluate(x ...fr.Element) (res fr.Element) { + if len(x) != int(g) { + panic("wrong input count") + } + switch len(x) { + case 0: + res.SetOne() + case 1: + res.Set(&x[0]) + default: + res.Mul(&x[0], &x[1]) + for i := 2; i < len(x); i++ { + res.Mul(&res, &x[2]) + } + } + return +} + +func (g mulGate) Degree() int { + return int(g) +} + +type addGate struct{} + +func (g addGate) Evaluate(x ...fr.Element) (res fr.Element) { + switch len(x) { + case 0: + // set zero + case 1: + res.Set(&x[0]) + case 2: + res.Add(&x[0], &x[1]) + for i := 2; i < len(x); i++ { + res.Add(&res, &x[2]) + } + } + return +} + +func (g addGate) Degree() int { + return 1 +} + +func convertCircuit(noPtr constraint.GkrCircuit) gkr.Circuit { + resCircuit := make(gkr.Circuit, len(noPtr)) + for i := range noPtr { + resCircuit[i].Gate = gateRegistry[noPtr[i].Gate] + resCircuit[i].Inputs = algo_utils.Map(noPtr[i].Inputs, algo_utils.SlicePtrAt(resCircuit)) + } + return resCircuit +} + +// this module assumes that wire and instance indexes respect dependencies + +type gkrAssignment [][]fr.Element //gkrAssignment is indexed wire first, instance second + +// assumes assignmentVector is arranged wire first, instance second in order of solution +func gkrSolve(info constraint.GkrInfo, solvingData gkrSolvingData, assignmentVector []*big.Int) gkrAssignment { + circuit := info.Circuit + nbInstances := info.NbInstances + offsets := info.AssignmentOffsets() + nbDepsResolved := make([]int, len(circuit)) + inputs := make([]fr.Element, info.MaxNIns) + + assignments := make(gkrAssignment, len(circuit)) + for i := range assignments { + assignments[i] = make([]fr.Element, nbInstances) + } + + for instanceI := 0; instanceI < nbInstances; instanceI++ { + fmt.Println("instance", instanceI) + for wireI, wire := range circuit { + fmt.Print("\twire ", wireI, ": ") + if wire.IsInput() { + fmt.Print("input.") + if nbDepsResolved[wireI] < len(wire.Dependencies) && instanceI == wire.Dependencies[nbDepsResolved[wireI]].InputInstance { + fmt.Print(" copying value from dependency") + dep := wire.Dependencies[nbDepsResolved[wireI]] + assignments[wireI][instanceI].Set(&assignments[dep.OutputWire][dep.OutputInstance]) + nbDepsResolved[wireI]++ + } else { + fmt.Print(" taking value from input") + assignments[wireI][instanceI].SetBigInt(assignmentVector[offsets[wireI]+instanceI-nbDepsResolved[wireI]]) + } + } else { + fmt.Print("gated.") + // assemble the inputs + inputIndexes := info.Circuit[wireI].Inputs + for i, inputI := range inputIndexes { + inputs[i].Set(&assignments[inputI][instanceI]) + } + gate := solvingData.circuit[wireI].Gate + assignments[wireI][instanceI] = gate.Evaluate(inputs[:len(inputIndexes)]...) + } + fmt.Println("\n\t\tresult: ", assignments[wireI][instanceI].Text(10)) + } + } + return assignments +} + +func toMapAssignment(circuit gkr.Circuit, assignment gkrAssignment) gkr.WireAssignment { + res := make(gkr.WireAssignment, len(circuit)) + for i := range circuit { + res[&circuit[i]] = assignment[i] + } + return res +} + +func gkrSetOutputValues(circuit []constraint.GkrWire, assignments gkrAssignment, outs []*big.Int) { + outsI := 0 + for i := range circuit { + if circuit[i].IsOutput() { + for j := range assignments[i] { + assignments[i][j].BigInt(outs[outsI]) + outsI++ + } + } + } + // Check if outsI == len(outs)? +} + +func gkrSolveHint(data constraint.GkrInfo, res *gkrSolvingData) hint.Function { + return func(_ *big.Int, ins, outs []*big.Int) error { + + res.circuit = convertCircuit(data.Circuit) // TODO: Take this out of here into the proving module + res.memoryPool = polynomial.NewPool(256, 1<<11) // TODO: Get clever with limits + + assignments := gkrSolve(data, *res, ins) + res.assignments = toMapAssignment(res.circuit, assignments) + gkrSetOutputValues(data.Circuit, assignments, outs) + + fmt.Println("assignment ", sliceSliceToString(assignments)) + fmt.Println("returning ", bigIntPtrSliceToString(outs)) + + return nil + } +} + +func bigIntPtrSliceToString(slice []*big.Int) []int64 { + return algo_utils.Map(slice, func(e *big.Int) int64 { + if !e.IsInt64() { + panic("int too big") + } + return e.Int64() + }) +} + +func sliceSliceToString(slice [][]fr.Element) string { + printable := make([]interface{}, len(slice)) + for i, s := range slice { + printable[i] = test_vector_utils.ElementSliceToInterfaceSlice(s) + } + res, err := json.Marshal(printable) + if err != nil { + panic(err.Error()) + } + return string(res) +} + +func frToBigInts(dst []*big.Int, src []fr.Element) { + for i := range src { + src[i].BigInt(dst[i]) + } +} + +func gkrProveHint(hashName string, data *gkrSolvingData) hint.Function { + + return func(_ *big.Int, ins, outs []*big.Int) error { + insBytes := algo_utils.Map(ins, func(i *big.Int) []byte { + b := i.Bytes() + return b[:] + }) + + hsh := mimc.NewMiMC() // TODO: Use hashName + + proof, err := gkr.Prove(data.circuit, data.assignments, fiatshamir.WithHash(hsh, insBytes...), gkr.WithPool(&data.memoryPool)) // TODO: Do transcriptSettings properly + if err != nil { + return err + } + + // serialize proof: TODO: In gnark-crypto? + offset := 0 + for i := range proof { + for _, poly := range proof[i].PartialSumPolys { + frToBigInts(outs[offset:], poly) + offset += len(poly) + } + if proof[i].FinalEvalProof != nil { + finalEvalProof := proof[i].FinalEvalProof.([]fr.Element) + frToBigInts(outs[offset:], finalEvalProof) + offset += len(finalEvalProof) + } + } + return nil + + } +} + +func defineGkrHints(info constraint.GkrInfo, hintFunctions map[hint.ID]hint.Function) map[hint.ID]hint.Function { + res := make(map[hint.ID]hint.Function, len(hintFunctions)+2) + for k, v := range hintFunctions { + res[k] = v + } + var gkrData gkrSolvingData + res[hint.UUID(stdGkr.SolveHintPlaceholder)] = gkrSolveHint(info, &gkrData) + res[hint.UUID(stdGkr.ProveHintPlaceholder)] = gkrProveHint(info.HashName, &gkrData) + return res +} diff --git a/constraint/bn254/r1cs.go b/constraint/bn254/r1cs.go index dd4a534e02..5e29b3300c 100644 --- a/constraint/bn254/r1cs.go +++ b/constraint/bn254/r1cs.go @@ -80,7 +80,9 @@ func (cs *R1CS) Solve(witness, a, b, c []fr.Element, opt backend.ProverConfig) ( log := logger.Logger().With().Int("nbConstraints", len(cs.Constraints)).Str("backend", "groth16").Logger() nbWires := len(cs.Public) + len(cs.Secret) + cs.NbInternalVariables - solution, err := newSolution(nbWires, opt.HintFunctions, cs.MHintsDependencies, cs.MHints, cs.Coefficients) + hintFunctions := defineGkrHints(cs.GkrInfo, opt.HintFunctions) + + solution, err := newSolution(nbWires, hintFunctions, cs.MHintsDependencies, cs.MHints, cs.Coefficients) if err != nil { return make([]fr.Element, nbWires), err } diff --git a/constraint/bn254/solution.go b/constraint/bn254/solution.go index e9c69b49c3..5ad3690e98 100644 --- a/constraint/bn254/solution.go +++ b/constraint/bn254/solution.go @@ -52,7 +52,7 @@ func newSolution(nbWires int, hintFunctions map[hint.ID]hint.Function, hintsDepe // hintsDependencies is from compile time; it contains the list of hints the solver **needs** var missing []string for hintUUID, hintID := range hintsDependencies { - if _, ok := s.mHintsFunctions[hintUUID]; !ok { + if _, ok := hintFunctions[hintUUID]; !ok { missing = append(missing, hintID) } } diff --git a/constraint/gkr.go b/constraint/gkr.go new file mode 100644 index 0000000000..5255dca8ab --- /dev/null +++ b/constraint/gkr.go @@ -0,0 +1,138 @@ +package constraint + +import ( + "fmt" + "github.com/consensys/gnark/std/utils/algo_utils" + "sort" +) + +type GkrVariable int // Just an alias to hide implementation details. May be more trouble than worth + +type InputDependency struct { + OutputWire int + OutputInstance int + InputInstance int +} + +type GkrWire struct { + Gate string // TODO: Change to description + Inputs []int + Dependencies []InputDependency // nil for input wires + NbUniqueOutputs int +} + +type GkrCircuit []GkrWire + +type GkrInfo struct { + Circuit GkrCircuit + MaxNIns int + NbInstances int + HashName string +} + +type GkrPermutations struct { + SortedInstances []int + SortedWires []int + InstancesPermutation []int + WiresPermutation []int +} + +func (w GkrWire) IsInput() bool { + return len(w.Inputs) == 0 +} + +func (w GkrWire) IsOutput() bool { + return w.NbUniqueOutputs == 0 +} + +// AssignmentOffsets returns the index of the first value assigned to a wire TODO: Explain clearly +func (d *GkrInfo) AssignmentOffsets() []int { + c := d.Circuit + res := make([]int, len(c)+1) + for i := range c { + nbExplicitAssignments := 0 + if c[i].IsInput() { + nbExplicitAssignments = d.NbInstances - len(c[i].Dependencies) + } + res[i+1] = res[i] + nbExplicitAssignments + } + return res +} + +func (d *GkrInfo) NewInputVariable() GkrVariable { + i := len(d.Circuit) + d.Circuit = append(d.Circuit) + return GkrVariable(i) +} + +// Compile sorts the circuit wires, their dependencies and the instances +func (d *GkrInfo) Compile(nbInstances int) (GkrPermutations, error) { + + var p GkrPermutations + d.NbInstances = nbInstances + // sort the instances to decide the order in which they are to be solved + instanceDeps := make([][]int, nbInstances) + for i := range d.Circuit { + for _, dep := range d.Circuit[i].Dependencies { + instanceDeps[dep.InputInstance] = append(instanceDeps[dep.InputInstance], dep.OutputInstance) + } + } + + p.SortedInstances, _ = algo_utils.TopologicalSort(instanceDeps) + p.InstancesPermutation = algo_utils.InvertPermutation(p.SortedInstances) + + // this whole circuit sorting is a bit of a charade. if things are built using an api, there's no way it could NOT already be topologically sorted + // worth keeping for future-proofing? + + inputs := algo_utils.Map(d.Circuit, func(w GkrWire) []int { + return w.Inputs + }) + + var uniqueOuts [][]int + p.SortedWires, uniqueOuts = algo_utils.TopologicalSort(inputs) + p.WiresPermutation = algo_utils.InvertPermutation(p.SortedWires) + wirePermutationAt := algo_utils.SliceAt(p.WiresPermutation) + sorted := make([]GkrWire, len(d.Circuit)) + for newI, oldI := range p.SortedWires { + oldW := d.Circuit[oldI] + + for i := 1; i < len(oldW.Dependencies); i++ { + if oldW.Dependencies[i].InputInstance == oldW.Dependencies[i-1].InputInstance { + return p, fmt.Errorf("an input wire can only have one dependency per instance") + } + } // TODO: Check that dependencies and explicit assignments cover all instances + + if !oldW.IsInput() { + d.MaxNIns = max(d.MaxNIns, len(oldW.Inputs)) + } + + for j := range oldW.Dependencies { + dep := &oldW.Dependencies[j] + dep.OutputWire = p.WiresPermutation[dep.OutputWire] + dep.InputInstance = p.InstancesPermutation[dep.InputInstance] + dep.OutputInstance = p.InstancesPermutation[dep.OutputInstance] + } + + sort.Slice(oldW.Dependencies, func(i, j int) bool { + return oldW.Dependencies[i].InputInstance < oldW.Dependencies[j].InputInstance + }) + + sorted[newI] = GkrWire{ + Gate: oldW.Gate, + Inputs: algo_utils.Map(oldW.Inputs, wirePermutationAt), + Dependencies: oldW.Dependencies, + NbUniqueOutputs: len(uniqueOuts[oldI]), + } + + } + d.Circuit = sorted + + return p, nil +} + +func max(a, b int) int { + if a > b { + return a + } + return b +} diff --git a/constraint/system.go b/constraint/system.go index c18030fe3d..fbbd28bc9b 100644 --- a/constraint/system.go +++ b/constraint/system.go @@ -145,6 +145,7 @@ type System struct { lbOutputs []uint32 `cbor:"-"` // wire outputs for current constraint. CommitmentInfo Commitment + GkrInfo GkrInfo } // NewSystem initialize the common structure among constraint system diff --git a/frontend/circuit.go b/frontend/circuit.go index f561011b0a..a0ae6eed51 100644 --- a/frontend/circuit.go +++ b/frontend/circuit.go @@ -17,7 +17,7 @@ limitations under the License. package frontend // Circuit must be implemented by user-defined circuit. The best way to define a -// circuit is define a type which contains all the witness elements as fields +// circuit is to define a type which contains all the witness elements as fields // and declare `Define` method on the type. // // For example, the following is a minimal valid circuit: diff --git a/go.mod b/go.mod index 4251dce434..915658b56d 100644 --- a/go.mod +++ b/go.mod @@ -20,12 +20,16 @@ require ( github.com/kr/pretty v0.3.0 // indirect github.com/mmcloughlin/addchain v0.4.0 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect + github.com/samlitowitz/goimportcycle v1.0.4 // indirect github.com/x448/float16 v0.8.4 // indirect golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa // indirect + golang.org/x/mod v0.7.0 // indirect golang.org/x/sys v0.2.0 // indirect + golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect + gonum.org/v1/gonum v0.12.0 // indirect gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect gopkg.in/yaml.v3 v3.0.1 // indirect rsc.io/tmplfunc v0.0.3 // indirect ) -replace "github.com/consensys/gnark-crypto" => "/Users/arya/gnark-crypto" \ No newline at end of file +replace github.com/consensys/gnark-crypto => /Users/arya/gnark-crypto diff --git a/go.sum b/go.sum index b5683a69d8..adfb20ba7d 100644 --- a/go.sum +++ b/go.sum @@ -40,6 +40,8 @@ github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTE github.com/rs/xid v1.3.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg= github.com/rs/zerolog v1.26.1 h1:/ihwxqH+4z8UxyI70wM1z9yCvkWcfz/a3mj48k/Zngc= github.com/rs/zerolog v1.26.1/go.mod h1:/wSSJWX7lVrsOwlbyTRSOJvqRlc+WjWlfes+CiJ+tmc= +github.com/samlitowitz/goimportcycle v1.0.4 h1:GE1sl60DsmcMH+tgx6suF0jmSvChb7EY8zwC8/OP04g= +github.com/samlitowitz/goimportcycle v1.0.4/go.mod h1:Wbq8jmeCIFyP/A3deG1wzVHs5O4g0mQiMhQnYNq1p2A= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= @@ -56,6 +58,8 @@ golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0 golang.org/x/exp v0.0.0-20220713135740-79cabaa25d75 h1:x03zeu7B2B11ySp+daztnwM5oBJ/8wGUSqrwcw9L0RA= golang.org/x/exp v0.0.0-20220713135740-79cabaa25d75/go.mod h1:Kr81I6Kryrl9sr8s2FK3vxD90NdsKWRuOIl2O4CvYbA= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.7.0 h1:LapD9S96VoQRhi/GrNTqeBJFrUjs5UHCAtTlgwA5oZA= +golang.org/x/mod v0.7.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= @@ -79,6 +83,10 @@ golang.org/x/tools v0.1.7/go.mod h1:LGqMHiF4EqQNHR1JncWGqT5BVaXmza+X+BDGol+dOxo= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 h1:H2TDz8ibqkAF6YGhCdN3jS9O0/s90v0rJh3X/OLHEUk= +golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= +gonum.org/v1/gonum v0.12.0 h1:xKuo6hzt+gMav00meVPUlXwSdoEJP46BR+wdxQEFK2o= +gonum.org/v1/gonum v0.12.0/go.mod h1:73TDxJfAAHeA8Mk9mf8NlIppyhQNo5GLTcYeqgo2lvY= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= diff --git a/std/gkr/api.go b/std/gkr/api.go index fce1dc5c35..a214135a42 100644 --- a/std/gkr/api.go +++ b/std/gkr/api.go @@ -2,24 +2,25 @@ package gkr import ( "github.com/consensys/gnark/backend/hint" + "github.com/consensys/gnark/constraint" "github.com/consensys/gnark/frontend" "github.com/consensys/gnark/std/utils/algo_utils" "math/big" ) func frontendVarToInt(a frontend.Variable) int { - return int(a.(Variable)) + return int(a.(constraint.GkrVariable)) } -func (api *API) newNonInputVariable(gate Gate, in []frontend.Variable) Variable { - api.noPtr.circuit = append(api.noPtr.circuit, wireNoPtr{ - gate: gate, - inputs: algo_utils.Map(in, frontendVarToInt), +func (api *API) newNonInputVariable(gate string, in []frontend.Variable) constraint.GkrVariable { + api.toStore.Circuit = append(api.toStore.Circuit, constraint.GkrWire{ + Gate: gate, + Inputs: algo_utils.Map(in, frontendVarToInt), }) - return Variable(len(api.noPtr.circuit) - 1) + return constraint.GkrVariable(len(api.toStore.Circuit) - 1) } -func (api *API) newVar2PlusIn(gate Gate, in1, in2 frontend.Variable, in ...frontend.Variable) Variable { +func (api *API) newVar2PlusIn(gate string, in1, in2 frontend.Variable, in ...frontend.Variable) constraint.GkrVariable { inCombined := make([]frontend.Variable, 2+len(in)) inCombined[0] = in1 inCombined[1] = in2 @@ -30,7 +31,7 @@ func (api *API) newVar2PlusIn(gate Gate, in1, in2 frontend.Variable, in ...front } func (api *API) Add(i1, i2 frontend.Variable, in ...frontend.Variable) frontend.Variable { - return api.newVar2PlusIn(AddGate{}, i1, i2, in...) + return api.newVar2PlusIn("add", i1, i2, in...) } func (api *API) Neg(i1 frontend.Variable) frontend.Variable { @@ -44,7 +45,7 @@ func (api *API) Sub(i1, i2 frontend.Variable, in ...frontend.Variable) frontend. } func (api *API) Mul(i1, i2 frontend.Variable, in ...frontend.Variable) frontend.Variable { - return api.newVar2PlusIn(MulGate{}, i1, i2, in...) + return api.newVar2PlusIn("mul", i1, i2, in...) } func (api *API) DivUnchecked(i1, i2 frontend.Variable) frontend.Variable { diff --git a/std/gkr/api_test.go b/std/gkr/api_test.go index de6332aaa2..9e0133719c 100644 --- a/std/gkr/api_test.go +++ b/std/gkr/api_test.go @@ -6,6 +6,7 @@ import ( bn254TestVectorUtils "github.com/consensys/gnark-crypto/ecc/bn254/fr/test_vector_utils" "github.com/consensys/gnark/backend" "github.com/consensys/gnark/backend/groth16" + "github.com/consensys/gnark/constraint" "github.com/consensys/gnark/frontend" "github.com/consensys/gnark/frontend/cs/r1cs" "github.com/consensys/gnark/std/hash/mimc" @@ -196,9 +197,9 @@ func TestSolveMulWithDependency(t *testing.T) { func TestApiMul(t *testing.T) { var ( - x Variable - y Variable - z Variable + x constraint.GkrVariable + y constraint.GkrVariable + z constraint.GkrVariable err error ) api := NewApi() @@ -206,10 +207,10 @@ func TestApiMul(t *testing.T) { assert.NoError(t, err) y, err = api.Import([]frontend.Variable{nil, nil}) assert.NoError(t, err) - z = api.Mul(x, y).(Variable) - test_vector_utils.AssertSliceEqual(t, api.noPtr.circuit[z].inputs, []int{int(x), int(y)}) // TODO: Find out why assert.Equal gives false positives ( []*Wire{x,x} as second argument passes when it shouldn't ) + z = api.Mul(x, y).(constraint.GkrVariable) + test_vector_utils.AssertSliceEqual(t, api.toStore.Circuit[z].Inputs, []int{int(x), int(y)}) // TODO: Find out why assert.Equal gives false positives ( []*Wire{x,x} as second argument passes when it shouldn't ) - //unsorted := []*Wire{&api.noPtr.circuit[0], &api.noPtr.circuit[1], &api.noPtr.circuit[2]} + //unsorted := []*Wire{&api.toStore.circuit[0], &api.toStore.circuit[1], &api.toStore.circuit[2]} //test_vector_utils.AssertSliceEqual(t, []*Wire{x, y, z}, unsorted) //sorted := topologicalSort(api.circuit) @@ -307,11 +308,11 @@ func (c *benchMiMCMerkleTreeCircuit) Define(api frontend.API) error { } // cheat{ - gkr.circuitData.noPtr.circuit = append(gkr.circuitData.noPtr.circuit, wireNoPtr{ - gate: mimcCipherGate{1}, - inputs: []int{int(x.(Variable)), int(y.(Variable))}, + gkr.circuitData.toStore.Circuit = append(gkr.circuitData.toStore.Circuit, constraint.GkrWire{ + Gate: "mimc", + Inputs: []int{int(x.(constraint.GkrVariable)), int(y.(constraint.GkrVariable))}, }) - z := frontend.Variable(Variable(2)) + z := frontend.Variable(constraint.GkrVariable(2)) // } offset := 1 << (c.depth - 1) diff --git a/std/gkr/bn254_circuit.go b/std/gkr/bn254_circuit.go deleted file mode 100644 index f297e61b80..0000000000 --- a/std/gkr/bn254_circuit.go +++ /dev/null @@ -1,200 +0,0 @@ -package gkr - -import ( - "github.com/consensys/gnark-crypto/ecc/bn254/fr" - "github.com/consensys/gnark-crypto/ecc/bn254/fr/gkr" - "github.com/consensys/gnark-crypto/ecc/bn254/fr/polynomial" - "github.com/consensys/gnark/backend/hint" - "github.com/consensys/gnark/frontend" - "github.com/consensys/gnark/std/utils/algo_utils" - "math/big" -) - -type bn254CircuitData struct { - assignments gkr.WireAssignment - circuit gkr.Circuit - memoryPool polynomial.Pool -} - -func bn254ConvertGate(gate Gate) gkr.Gate { - return gateConverter{gate: gate} -} - -func bn254ConvertCircuit(noPtr circuitNoPtr) gkr.Circuit { - resCircuit := make(gkr.Circuit, len(noPtr)) - for i := range noPtr { - resCircuit[i].Gate = bn254ConvertGate(noPtr[i].gate) - resCircuit[i].Inputs = algo_utils.Map(noPtr[i].inputs, slicePtrAt(resCircuit)) - } - return resCircuit -} - -type gateConverter struct { - gate Gate - api gateConversionApi -} - -func (c gateConverter) Degree() int { - return c.gate.Degree() -} - -func newGateConverter(gate Gate) gateConverter { - return gateConverter{ - gate: gate, - api: gateConversionApi{}, - } -} - -func elementSliceToVariableSlice(e []fr.Element) []frontend.Variable { - res := make([]frontend.Variable, len(e)) - for i := range res { - res[i] = e[i] - } - return res -} - -func (c gateConverter) Evaluate(ins ...fr.Element) fr.Element { - return c.gate.Evaluate(&c.api, elementSliceToVariableSlice(ins)...).(fr.Element) -} - -type gateConversionApi struct{} - -func varsToElems(i1, i2 frontend.Variable, in ...frontend.Variable) []fr.Element { - res := make([]fr.Element, 2+len(in)) - res[0] = i1.(fr.Element) - res[1] = i2.(fr.Element) - for i := range in { - res[2+i] = in[i].(fr.Element) - } - return res -} - -func (c *gateConversionApi) Add(i1, i2 frontend.Variable, in ...frontend.Variable) frontend.Variable { - elems := varsToElems(i1, i2, in...) - var res fr.Element - res.Add(&elems[0], &elems[1]) - for i := range in { - res.Add(&res, &elems[i+2]) - } - return res -} - -func (c *gateConversionApi) Neg(i1 frontend.Variable) frontend.Variable { - //TODO implement me - panic("implement me") -} - -func (c *gateConversionApi) Sub(i1, i2 frontend.Variable, in ...frontend.Variable) frontend.Variable { - //TODO implement me - panic("implement me") -} - -func (c *gateConversionApi) Mul(i1, i2 frontend.Variable, in ...frontend.Variable) frontend.Variable { - elems := varsToElems(i1, i2, in...) - var res fr.Element - res.Mul(&elems[0], &elems[1]) - for i := range in { - res.Mul(&res, &elems[i+2]) - } - return res -} - -func (c *gateConversionApi) DivUnchecked(i1, i2 frontend.Variable) frontend.Variable { - //TODO implement me - panic("implement me") -} - -func (c *gateConversionApi) Div(i1, i2 frontend.Variable) frontend.Variable { - //TODO implement me - panic("implement me") -} - -func (c *gateConversionApi) Inverse(i1 frontend.Variable) frontend.Variable { - //TODO implement me - panic("implement me") -} - -func (c *gateConversionApi) ToBinary(i1 frontend.Variable, n ...int) []frontend.Variable { - //TODO implement me - panic("implement me") -} - -func (c *gateConversionApi) FromBinary(b ...frontend.Variable) frontend.Variable { - //TODO implement me - panic("implement me") -} - -func (c *gateConversionApi) Xor(a, b frontend.Variable) frontend.Variable { - //TODO implement me - panic("implement me") -} - -func (c *gateConversionApi) Or(a, b frontend.Variable) frontend.Variable { - //TODO implement me - panic("implement me") -} - -func (c *gateConversionApi) And(a, b frontend.Variable) frontend.Variable { - //TODO implement me - panic("implement me") -} - -func (c *gateConversionApi) Select(b frontend.Variable, i1, i2 frontend.Variable) frontend.Variable { - //TODO implement me - panic("implement me") -} - -func (c *gateConversionApi) Lookup2(b0, b1 frontend.Variable, i0, i1, i2, i3 frontend.Variable) frontend.Variable { - //TODO implement me - panic("implement me") -} - -func (c *gateConversionApi) IsZero(i1 frontend.Variable) frontend.Variable { - //TODO implement me - panic("implement me") -} - -func (c *gateConversionApi) Cmp(i1, i2 frontend.Variable) frontend.Variable { - //TODO implement me - panic("implement me") -} - -func (c *gateConversionApi) AssertIsEqual(i1, i2 frontend.Variable) { - //TODO implement me - panic("implement me") -} - -func (c *gateConversionApi) AssertIsDifferent(i1, i2 frontend.Variable) { - //TODO implement me - panic("implement me") -} - -func (c *gateConversionApi) AssertIsBoolean(i1 frontend.Variable) { - //TODO implement me - panic("implement me") -} - -func (c *gateConversionApi) AssertIsLessOrEqual(v frontend.Variable, bound frontend.Variable) { - //TODO implement me - panic("implement me") -} - -func (c *gateConversionApi) Println(a ...frontend.Variable) { - //TODO implement me - panic("implement me") -} - -func (c *gateConversionApi) Compiler() frontend.Compiler { - //TODO implement me - panic("implement me") -} - -func (c *gateConversionApi) NewHint(f hint.Function, nbOutputs int, inputs ...frontend.Variable) ([]frontend.Variable, error) { - //TODO implement me - panic("implement me") -} - -func (c *gateConversionApi) ConstantValue(v frontend.Variable) (*big.Int, bool) { - //TODO implement me - panic("implement me") -} diff --git a/std/gkr/bn254_prove.go b/std/gkr/bn254_prove.go deleted file mode 100644 index fddeb2634b..0000000000 --- a/std/gkr/bn254_prove.go +++ /dev/null @@ -1,37 +0,0 @@ -package gkr - -import ( - "github.com/consensys/gnark-crypto/ecc/bn254/fr" - "github.com/consensys/gnark-crypto/ecc/bn254/fr/gkr" - curveFS "github.com/consensys/gnark-crypto/fiat-shamir" - "math/big" -) - -func bn254FrToBigInts(dst []*big.Int, src []fr.Element) { - for i := range src { - src[i].BigInt(dst[i]) - } -} - -func bn254ProveHint(data bn254CircuitData, transcriptSettings curveFS.Settings, outs []*big.Int) error { - - proof, err := gkr.Prove(data.circuit, data.assignments, transcriptSettings, gkr.WithPool(&data.memoryPool)) // TODO: Do transcriptSettings properly - if err != nil { - return err - } - - // serialize proof: TODO: In gnark-crypto? - offset := 0 - for i := range proof { - for _, poly := range proof[i].PartialSumPolys { - bn254FrToBigInts(outs[offset:], poly) - offset += len(poly) - } - if proof[i].FinalEvalProof != nil { - finalEvalProof := proof[i].FinalEvalProof.([]fr.Element) - bn254FrToBigInts(outs[offset:], finalEvalProof) - offset += len(finalEvalProof) - } - } - return nil -} diff --git a/std/gkr/bn254_solve.go b/std/gkr/bn254_solve.go deleted file mode 100644 index 7561495877..0000000000 --- a/std/gkr/bn254_solve.go +++ /dev/null @@ -1,119 +0,0 @@ -package gkr - -import ( - "encoding/json" - "fmt" - "github.com/consensys/gnark-crypto/ecc/bn254/fr" - "github.com/consensys/gnark-crypto/ecc/bn254/fr/gkr" - "github.com/consensys/gnark-crypto/ecc/bn254/fr/polynomial" - "github.com/consensys/gnark-crypto/ecc/bn254/fr/test_vector_utils" - "github.com/consensys/gnark/std/utils/algo_utils" - "math/big" -) - -// this module assumes that wire and instance indexes respect dependencies - -type bn254AssignmentNoPtr [][]fr.Element //bn254AssignmentNoPtr is indexed wire first, instance second - -// assumes assignmentVector is arranged wire first, instance second in order of solution -func bn254Solve(noPtr circuitDataNoPtr, typed bn254CircuitData, assignmentVector []*big.Int) bn254AssignmentNoPtr { - circuit := noPtr.circuit - nbInstances := circuit.nbInstances() - offsets := circuit.assignmentOffsets() - nbDepsResolved := make([]int, len(circuit)) - inputs := make([]fr.Element, noPtr.maxNIns) - - assignments := make(bn254AssignmentNoPtr, len(circuit)) - for i := range assignments { - assignments[i] = make([]fr.Element, nbInstances) - } - - for instanceI := 0; instanceI < nbInstances; instanceI++ { - fmt.Println("instance", instanceI) - for wireI, wire := range circuit { - fmt.Print("\twire ", wireI, ": ") - if wire.isInput() { - fmt.Print("input.") - if nbDepsResolved[wireI] < len(wire.dependencies) && instanceI == wire.dependencies[nbDepsResolved[wireI]].inputInstance { - fmt.Print(" copying value from dependency") - dep := wire.dependencies[nbDepsResolved[wireI]] - assignments[wireI][instanceI].Set(&assignments[dep.outputWire][dep.outputInstance]) - nbDepsResolved[wireI]++ - } else { - fmt.Print(" taking value from input") - assignments[wireI][instanceI].SetBigInt(assignmentVector[offsets[wireI]+instanceI-nbDepsResolved[wireI]]) - } - } else { - fmt.Print("gated.") - // assemble the inputs - inputIndexes := noPtr.circuit[wireI].inputs - for i, inputI := range inputIndexes { - inputs[i].Set(&assignments[inputI][instanceI]) - } - gate := typed.circuit[wireI].Gate - assignments[wireI][instanceI] = gate.Evaluate(inputs[:len(inputIndexes)]...) - } - fmt.Println("\n\t\tresult: ", assignments[wireI][instanceI].Text(10)) - } - } - return assignments -} - -func toBn254MapAssignment(circuit gkr.Circuit, assignment bn254AssignmentNoPtr) gkr.WireAssignment { - res := make(gkr.WireAssignment, len(circuit)) - for i := range circuit { - res[&circuit[i]] = assignment[i] - } - return res -} - -func bn254SetOutputValues(circuit []wireNoPtr, assignments bn254AssignmentNoPtr, outs []*big.Int) { - outsI := 0 - for i := range circuit { - if circuit[i].isOutput() { - for j := range assignments[i] { - assignments[i][j].BigInt(outs[outsI]) - outsI++ - } - } - } - // Check if outsI == len(outs)? -} - -func bn254SolveHint(data circuitDataNoPtr, ins []*big.Int, outs []*big.Int) (bn254CircuitData, error) { - - res := bn254CircuitData{ - circuit: bn254ConvertCircuit(data.circuit), // TODO: Take this out of here into the proving module - memoryPool: polynomial.NewPool(256, 1<<11), // TODO: Get clever with limits - } - - assignments := bn254Solve(data, res, ins) - res.assignments = toBn254MapAssignment(res.circuit, assignments) - bn254SetOutputValues(data.circuit, assignments, outs) - - fmt.Println("assignment ", sliceSliceToString(assignments)) - fmt.Println("returning ", bigIntPtrSliceToString(outs)) - - return res, nil -} - -func bigIntPtrSliceToString(slice []*big.Int) []int64 { - return algo_utils.Map(slice, func(e *big.Int) int64 { - if !e.IsInt64() { - panic("int too big") - } - return e.Int64() - }) -} - -func sliceSliceToString(slice [][]fr.Element) string { - printable := make([]interface{}, len(slice)) - for i, s := range slice { - printable[i] = test_vector_utils.ElementSliceToInterfaceSlice(s) - } - res, err := json.Marshal(printable) - if err != nil { - panic(err.Error()) - } - return string(res) -} diff --git a/std/gkr/compile.go b/std/gkr/compile.go index d312896084..ef5b8eac6d 100644 --- a/std/gkr/compile.go +++ b/std/gkr/compile.go @@ -2,47 +2,23 @@ package gkr import ( "fmt" + "github.com/consensys/gnark/constraint" "github.com/consensys/gnark/frontend" fiatshamir "github.com/consensys/gnark/std/fiat-shamir" "github.com/consensys/gnark/std/hash" "github.com/consensys/gnark/std/utils/algo_utils" + "math/big" "math/bits" - "sort" ) -type wireNoPtr struct { - assignments []frontend.Variable - gate Gate - inputs []int - dependencies []inputDependency // nil for input wires - nbUniqueOutputs int -} - -type circuitNoPtr []wireNoPtr - -func (w wireNoPtr) isInput() bool { - return len(w.inputs) == 0 -} - -func (w wireNoPtr) isOutput() bool { - return w.nbUniqueOutputs == 0 -} - -type circuitDataNoPtr struct { - circuit circuitNoPtr - maxNIns int - sortedInstances []int - sortedWires []int -} - type circuitDataForSnark struct { circuit Circuit assignments WireAssignment } type circuitData struct { - noPtr circuitDataNoPtr - typed interface{} // curve-dependent data. for communication between solver and prover + toStore constraint.GkrInfo + assignments GkrAssignment } type API struct { @@ -51,109 +27,23 @@ type API struct { type Solution struct { circuitData - parentApi frontend.API -} - -type Variable int // Just an alias to hide implementation details. May be more trouble than worth - -func (c circuitNoPtr) nbInstances() int { - for i := range c { - if lenI := len(c[i].assignments); lenI != 0 { - return lenI - } - } - return -1 + parentApi frontend.API + permutations constraint.GkrPermutations } func (api *API) nbInstances() int { - return api.noPtr.circuit.nbInstances() + return api.assignments.NbInstances() } func (api *API) logNbInstances() int { return log2(uint(api.nbInstances())) } -// compile sorts the circuit wires, their dependencies and the instances -func (d *circuitDataNoPtr) compile() error { // (circuit Circuit, assignment WireAssignment) { - - nbInstances := d.circuit.nbInstances() - // sort the instances to decide the order in which they are to be solved - instanceDeps := make([][]int, nbInstances) - for i := range d.circuit { - for _, dep := range d.circuit[i].dependencies { - instanceDeps[dep.inputInstance] = append(instanceDeps[dep.inputInstance], dep.outputInstance) - } - } - - d.sortedInstances, _ = algo_utils.TopologicalSort(instanceDeps) - instancePermutationInv := algo_utils.InvertPermutation(d.sortedInstances) - - // this whole circuit sorting is a bit of a charade. if things are built using an api, there's no way it could NOT already be topologically sorted - // worth keeping for future-proofing? - - inputs := algo_utils.Map(d.circuit, func(w wireNoPtr) []int { - return w.inputs - }) - - var uniqueOuts [][]int - d.sortedWires, uniqueOuts = algo_utils.TopologicalSort(inputs) - wirePermutationInv := algo_utils.InvertPermutation(d.sortedWires) - wirePermutationInvAt := algo_utils.SliceAt(wirePermutationInv) - sorted := make([]wireNoPtr, len(d.circuit)) - for newI, oldI := range d.sortedWires { - oldW := d.circuit[oldI] - - for i := 1; i < len(oldW.dependencies); i++ { - if oldW.dependencies[i].inputInstance == oldW.dependencies[i-1].inputInstance { - return fmt.Errorf("an input wire can only have one dependency per instance") - } - } // TODO: Check that dependencies and explicit assignments cover all instances - - if oldW.isInput() { - algo_utils.Permute(oldW.assignments, instancePermutationInv) - //oldW.assignments = algo_utils.Map(d.sortedInstances, algo_utils.SliceAt(oldW.assignments)) TODO: This if decided not to modify the user-given assignments - } else { - d.maxNIns = max(d.maxNIns, len(oldW.inputs)) - } - - for j := range oldW.dependencies { - dep := &oldW.dependencies[j] - dep.outputWire = wirePermutationInv[dep.outputWire] - dep.inputInstance = instancePermutationInv[dep.inputInstance] - dep.outputInstance = instancePermutationInv[dep.outputInstance] - } - - sort.Slice(oldW.dependencies, func(i, j int) bool { - return oldW.dependencies[i].inputInstance < oldW.dependencies[j].inputInstance - }) - - sorted[newI] = wireNoPtr{ - assignments: oldW.assignments, - gate: oldW.gate, - inputs: algo_utils.Map(oldW.inputs, wirePermutationInvAt), - dependencies: oldW.dependencies, - nbUniqueOutputs: len(uniqueOuts[oldI]), - } - - } - - d.circuit = sorted - - return nil -} - -func (d *circuitDataNoPtr) newInputVariable(assignment []frontend.Variable) Variable { - i := len(d.circuit) - d.circuit = append(d.circuit, wireNoPtr{assignments: assignment}) - return Variable(i) -} - func NewApi() *API { return &API{circuitData{ - noPtr: circuitDataNoPtr{ - circuit: make(circuitNoPtr, 0), - maxNIns: 0, - sortedInstances: make([]int, 0), + toStore: constraint.GkrInfo{ + Circuit: make(constraint.GkrCircuit, 0), + MaxNIns: 0, }, }} } @@ -168,21 +58,21 @@ func log2(x uint) int { // Series like in an electric circuit, binds an input of an instance to an output of another func (api *API) Series(input, output frontend.Variable, inputInstance, outputInstance int) *API { - i := input.(Variable) - o := output.(Variable) - if api.noPtr.circuit[i].assignments[inputInstance] != nil { + i := input.(constraint.GkrVariable) + o := output.(constraint.GkrVariable) + if api.assignments[i][inputInstance] != nil { panic("dependency attempting to override explicit value assignment") } - api.noPtr.circuit[i].dependencies = - append(api.noPtr.circuit[i].dependencies, inputDependency{ - outputWire: int(o), - outputInstance: outputInstance, - inputInstance: inputInstance, + api.toStore.Circuit[i].Dependencies = + append(api.toStore.Circuit[i].Dependencies, constraint.InputDependency{ + OutputWire: int(o), + OutputInstance: outputInstance, + InputInstance: inputInstance, }) return api } -func (api *API) Import(assignment []frontend.Variable) (Variable, error) { +func (api *API) Import(assignment []frontend.Variable) (constraint.GkrVariable, error) { nbInstances := len(assignment) logNbInstances := log2(uint(nbInstances)) if logNbInstances == -1 { @@ -193,7 +83,7 @@ func (api *API) Import(assignment []frontend.Variable) (Variable, error) { return -1, fmt.Errorf("number of assignments must be consistent across all variables") } - return api.noPtr.newInputVariable(assignment), nil + return api.toStore.NewInputVariable(), nil } func appendNonNil(dst *[]frontend.Variable, src []frontend.Variable) { @@ -207,21 +97,24 @@ func appendNonNil(dst *[]frontend.Variable, src []frontend.Variable) { // Solve finalizes the GKR circuit and returns the output variables in the order created func (api *API) Solve(parentApi frontend.API) (Solution, error) { - if err := api.noPtr.compile(); err != nil { + var p constraint.GkrPermutations + var err error + if p, err = api.toStore.Compile(api.assignments.NbInstances()); err != nil { return Solution{}, err } + api.assignments.Permute(p) - nbInstances := api.nbInstances() - circuit := api.noPtr.circuit + nbInstances := api.toStore.NbInstances + circuit := api.toStore.Circuit solveHintNIn := 0 solveHintNOut := 0 for i := range circuit { v := &circuit[i] - if v.isInput() { - solveHintNIn += nbInstances - len(v.dependencies) - } else if v.isOutput() { + if v.IsInput() { + solveHintNIn += nbInstances - len(v.Dependencies) + } else if v.IsOutput() { solveHintNOut += nbInstances } } @@ -229,38 +122,47 @@ func (api *API) Solve(parentApi frontend.API) (Solution, error) { // arrange inputs wire first, then in the order solved ins := make([]frontend.Variable, 0, solveHintNIn) for i := range circuit { - if circuit[i].isInput() { - appendNonNil(&ins, circuit[i].assignments) + if circuit[i].IsInput() { + appendNonNil(&ins, api.assignments[i]) } } - outsSerialized, err := parentApi.Compiler().NewHint(solveHint(&api.circuitData), solveHintNOut, ins...) + outsSerialized, err := parentApi.Compiler().NewHint(SolveHintPlaceholder, solveHintNOut, ins...) if err != nil { return Solution{}, err } for i := range circuit { - w := &circuit[i] - if w.isOutput() { - w.assignments = outsSerialized[:nbInstances] + if circuit[i].IsOutput() { + api.assignments[i] = outsSerialized[:nbInstances] outsSerialized = outsSerialized[nbInstances:] } } for i := range circuit { - for _, dep := range circuit[i].dependencies { - circuit[i].assignments[dep.inputInstance] = circuit[dep.outputWire].assignments[dep.outputInstance] + for _, dep := range circuit[i].Dependencies { + api.assignments[i][dep.InputInstance] = api.assignments[dep.OutputWire][dep.OutputInstance] } } + setGkrInfo(parentApi, api.toStore) + return Solution{ - circuitData: api.circuitData, - parentApi: parentApi, + circuitData: api.circuitData, + parentApi: parentApi, + permutations: p, }, nil } +func setGkrInfo(api frontend.API, toStore constraint.GkrInfo) { + switch sys := api.(type) { + default: + panic(fmt.Sprintf("unrecognized type %T", sys)) + } +} + func (s Solution) Export(v frontend.Variable) []frontend.Variable { - return algo_utils.Map(s.noPtr.sortedInstances, algo_utils.SliceAt(s.noPtr.circuit[v.(Variable)].assignments)) + return algo_utils.Map(s.permutations.SortedInstances, algo_utils.SliceAt(s.assignments[v.(constraint.GkrVariable)])) } func (s Solution) Verify(hash hash.Hash, initialChallenges ...frontend.Variable) error { @@ -271,23 +173,23 @@ func (s Solution) Verify(hash hash.Hash, initialChallenges ...frontend.Variable) proof Proof ) - forSnark := s.noPtr.forSnark() - logNbInstances := log2(uint(s.noPtr.circuit.nbInstances())) + forSnark := newCircuitDataForSnark(s.toStore, s.assignments) + logNbInstances := log2(uint(s.assignments.NbInstances())) // TODO: Find out if this hack is necessary - /*for i := range s.noPtr.circuit { - if s.noPtr.circuit[i].isOutput() { - initialChallenges = append(initialChallenges, s.noPtr.circuit[i].assignments[0]) + /*for i := range s.toStore.circuit { + if s.toStore.circuit[i].isOutput() { + initialChallenges = append(initialChallenges, s.toStore.circuit[i].assignments[0]) break } }*/ if proofSerialized, err = s.parentApi.Compiler().NewHint( - proveHint(s.typed, hash), ProofSize(forSnark.circuit, logNbInstances), initialChallenges...); err != nil { + ProveHintPlaceholder, ProofSize(forSnark.circuit, logNbInstances), initialChallenges...); err != nil { return err } - forSnarkSorted := algo_utils.MapRange(0, len(s.noPtr.circuit), slicePtrAt(forSnark.circuit)) + forSnarkSorted := algo_utils.MapRange(0, len(s.toStore.Circuit), slicePtrAt(forSnark.circuit)) if proof, err = DeserializeProof(forSnarkSorted, proofSerialized); err != nil { return err @@ -297,10 +199,12 @@ func (s Solution) Verify(hash hash.Hash, initialChallenges ...frontend.Variable) } -type inputDependency struct { - outputWire int - outputInstance int - inputInstance int +func SolveHintPlaceholder(*big.Int, []*big.Int, []*big.Int) error { + return fmt.Errorf("placeholder - not meant to be called") +} + +func ProveHintPlaceholder(*big.Int, []*big.Int, []*big.Int) error { + return fmt.Errorf("placeholder - not meant to be called") } func slicePtrAt[T any](slice []T) func(int) *T { @@ -309,38 +213,42 @@ func slicePtrAt[T any](slice []T) func(int) *T { } } -func (d *circuitDataNoPtr) forSnark() circuitDataForSnark { - circuit := make(Circuit, len(d.circuit)) - assignment := make(WireAssignment, len(d.circuit)) +func newCircuitDataForSnark(info constraint.GkrInfo, assignment GkrAssignment) circuitDataForSnark { + circuit := make(Circuit, len(info.Circuit)) + snarkAssignment := make(WireAssignment, len(info.Circuit)) circuitAt := slicePtrAt(circuit) for i := range circuit { - w := d.circuit[i] + w := info.Circuit[i] circuit[i] = Wire{ - Gate: w.gate, - Inputs: algo_utils.Map(w.inputs, circuitAt), - nbUniqueOutputs: w.nbUniqueOutputs, + Gate: RegisteredGates[w.Gate], + Inputs: algo_utils.Map(w.Inputs, circuitAt), + nbUniqueOutputs: w.NbUniqueOutputs, } - if !w.isInput() && !w.isOutput() && w.assignments != nil { // TODO: Remove + if !w.IsInput() && !w.IsOutput() && assignment[i] != nil { // TODO: Remove panic("unexpected!!") } - assignment[&circuit[i]] = w.assignments + snarkAssignment[&circuit[i]] = assignment[i] } return circuitDataForSnark{ circuit: circuit, - assignments: assignment, + assignments: snarkAssignment, } } -// assignmentOffsets returns the index of the first value assigned to a wire TODO: Explain clearly -func (c circuitNoPtr) assignmentOffsets() []int { - res := make([]int, len(c)+1) - nbInstances := c.nbInstances() - for i := range c { - nbExplicitAssignments := 0 - if c[i].isInput() { - nbExplicitAssignments = nbInstances - len(c[i].dependencies) +type GkrAssignment [][]frontend.Variable + +func (a GkrAssignment) NbInstances() int { + for i := range a { + if lenI := len(a[i]); lenI != 0 { + return lenI } - res[i+1] = res[i] + nbExplicitAssignments } - return res + return -1 +} + +func (a GkrAssignment) Permute(p constraint.GkrPermutations) { + algo_utils.Permute(a, p.WiresPermutation) + for i := range a { + algo_utils.Permute(a[i], p.InstancesPermutation) + } } diff --git a/std/gkr/compile_test.go b/std/gkr/compile_test.go index fd7a0eaf2d..f28450f2c4 100644 --- a/std/gkr/compile_test.go +++ b/std/gkr/compile_test.go @@ -1,78 +1,83 @@ package gkr import ( - "github.com/consensys/gnark/frontend" + "github.com/consensys/gnark/constraint" "github.com/stretchr/testify/assert" "testing" ) -func TestConvertCircuit(t *testing.T) { - circuitNoPtr := circuitNoPtr{ +/*func TestConvertCircuit(t *testing.T) { TODO: Move to cs package + circuitNoPtr := frontend.GkrCircuit{ { - assignments: []frontend.Variable{1, 2}, - inputs: []int{}, - nbUniqueOutputs: 1, + Assignments: []frontend.Variable{1, 2}, + Inputs: []int{}, + NbUniqueOutputs: 1, }, { - assignments: []frontend.Variable{2, 3}, - inputs: []int{}, - nbUniqueOutputs: 1, + Assignments: []frontend.Variable{2, 3}, + Inputs: []int{}, + NbUniqueOutputs: 1, }, { - gate: MulGate{}, - inputs: []int{0, 1}, - dependencies: nil, - nbUniqueOutputs: 0, + Gate: "mul", + Inputs: []int{0, 1}, + Dependencies: nil, + NbUniqueOutputs: 0, }, } - circuit := bn254ConvertCircuit(circuitNoPtr) + circuit := cs.bn254ConvertCircuit(circuitNoPtr) assert.Equal(t, 3, len(circuit)) -} +}*/ func TestNoPtrCompile(t *testing.T) { - var d = circuitDataNoPtr{ - circuit: circuitNoPtr{ + var d = constraint.GkrInfo{ + Circuit: constraint.GkrCircuit{ { - assignments: []frontend.Variable{2, 1}, - inputs: []int{1}, - dependencies: nil, + Inputs: []int{1}, + Dependencies: nil, }, { - assignments: []frontend.Variable{nil, 0}, - inputs: []int{}, - dependencies: []inputDependency{ + Inputs: []int{}, + Dependencies: []constraint.InputDependency{ { - outputWire: 0, - outputInstance: 1, - inputInstance: 0, + OutputWire: 0, + OutputInstance: 1, + InputInstance: 0, }, }, }, }, } - expectedCompiled := circuitDataNoPtr{ - circuit: circuitNoPtr{ + assignment := GkrAssignment{ + {2, 1}, + {nil, 0}, + } + + expectedCompiled := constraint.GkrInfo{ + Circuit: constraint.GkrCircuit{ { - assignments: []frontend.Variable{0, nil}, - inputs: []int{}, - dependencies: []inputDependency{{ - outputWire: 1, - outputInstance: 0, - inputInstance: 1, + Inputs: []int{}, + Dependencies: []constraint.InputDependency{{ + OutputWire: 1, + OutputInstance: 0, + InputInstance: 1, }}, - nbUniqueOutputs: 1, + NbUniqueOutputs: 1, }, { - assignments: []frontend.Variable{1, 2}, - inputs: []int{0}, - dependencies: nil, + Inputs: []int{0}, + Dependencies: nil, }}, - maxNIns: 1, - sortedInstances: []int{1, 0}, - sortedWires: []int{1, 0}, + MaxNIns: 1, + } + expectedAssignment := GkrAssignment{ + {0, nil}, + {1, 2}, } - assert.NoError(t, d.compile()) + _, err := d.Compile(assignment.NbInstances()) // TODO: Test the permutation too + assert.NoError(t, err) assert.Equal(t, expectedCompiled, d) + assert.Equal(t, expectedAssignment, assignment) } diff --git a/std/gkr/gkr_test.go b/std/gkr/gkr_test.go index 4ddc4cd0fc..2faee91fbf 100644 --- a/std/gkr/gkr_test.go +++ b/std/gkr/gkr_test.go @@ -241,7 +241,7 @@ func (c CircuitInfo) toCircuit() (circuit Circuit, err error) { } var found bool - if circuit[i].Gate, found = gates[wireInfo.Gate]; !found && wireInfo.Gate != "" { + if circuit[i].Gate, found = RegisteredGates[wireInfo.Gate]; !found && wireInfo.Gate != "" { err = fmt.Errorf("undefined gate \"%s\"", wireInfo.Gate) } } @@ -249,36 +249,12 @@ func (c CircuitInfo) toCircuit() (circuit Circuit, err error) { return } -var gates map[string]Gate +type _select int func init() { - gates = make(map[string]Gate) - gates["identity"] = IdentityGate{} - gates["mul"] = MulGate{} - gates["mimc"] = mimcCipherGate{ark: 0} //TODO: Add ark - gates["select-input-3"] = _select(2) -} - -type mimcCipherGate struct { - ark frontend.Variable + RegisteredGates["select-input-3"] = _select(2) } -func (m mimcCipherGate) Evaluate(api frontend.API, input ...frontend.Variable) frontend.Variable { - if len(input) != 2 { - panic("mimc has fan-in 2") - } - sum := api.Add(input[0], input[1], m.ark) - - sumCubed := api.Mul(sum, sum, sum) // sum^3 - return api.Mul(sumCubed, sumCubed, sum) -} - -func (m mimcCipherGate) Degree() int { - return 7 -} - -type _select int - func (g _select) Evaluate(_ frontend.API, in ...frontend.Variable) frontend.Variable { return in[g] } diff --git a/std/gkr/registry.go b/std/gkr/registry.go new file mode 100644 index 0000000000..a42370d193 --- /dev/null +++ b/std/gkr/registry.go @@ -0,0 +1,29 @@ +package gkr + +import "github.com/consensys/gnark/frontend" + +var RegisteredGates = make(map[string]Gate) + +func init() { + RegisteredGates["identity"] = IdentityGate{} + RegisteredGates["mul"] = MulGate{} + RegisteredGates["mimc"] = MiMCCipherGate{Ark: 0} //TODO: Add ark +} + +type MiMCCipherGate struct { + Ark frontend.Variable +} + +func (m MiMCCipherGate) Evaluate(api frontend.API, input ...frontend.Variable) frontend.Variable { + if len(input) != 2 { + panic("mimc has fan-in 2") + } + sum := api.Add(input[0], input[1], m.Ark) + + sumCubed := api.Mul(sum, sum, sum) // sum^3 + return api.Mul(sumCubed, sumCubed, sum) +} + +func (m MiMCCipherGate) Degree() int { + return 7 +} diff --git a/std/gkr/switch_cases.go b/std/gkr/switch_cases.go deleted file mode 100644 index e920bb80fe..0000000000 --- a/std/gkr/switch_cases.go +++ /dev/null @@ -1,44 +0,0 @@ -package gkr - -import ( - "fmt" - bn254 "github.com/consensys/gnark-crypto/ecc/bn254/fr" - fiatshamir "github.com/consensys/gnark-crypto/fiat-shamir" - gnarkHash "github.com/consensys/gnark/std/hash" - "github.com/consensys/gnark/std/utils/algo_utils" - "math/big" -) - -// solveHint the hint returns the outputs, indexed by output (ordered by SORTED circuit) first and instance second -func solveHint(data *circuitData) func(*big.Int, []*big.Int, []*big.Int) error { - return func(mod *big.Int, ins []*big.Int, outs []*big.Int) error { - var err error - if mod.Cmp(bn254.Modulus()) == 0 { // TODO: Switch case? - data.typed, err = bn254SolveHint(data.noPtr, ins, outs) - } else { - err = fmt.Errorf("unknow modulus") - } - return err - } -} - -func proveHint(data interface{}, hash gnarkHash.Hash) func(*big.Int, []*big.Int, []*big.Int) error { - hsh := hash.ToStandard() - return func(mod *big.Int, ins []*big.Int, outs []*big.Int) error { - if data == nil { - return fmt.Errorf("attempting to run the prove hint before the solve hint is done. find a way to create a dependence between them (perhaps an output of the solver to be input to the prover as a hack)") - } - - insAsBytes := algo_utils.Map(ins, func(i *big.Int) []byte { - return i.Bytes() - }) - - var err error - if mod.Cmp(bn254.Modulus()) == 0 { // TODO: Switch case? - return bn254ProveHint(data.(bn254CircuitData), fiatshamir.WithHash(hsh, insAsBytes...), outs) - } else { - err = fmt.Errorf("unknow modulus") - } - return err - } -} diff --git a/std/utils/algo_utils/algo_utils.go b/std/utils/algo_utils/algo_utils.go index 95b335a81b..5d7df927ad 100644 --- a/std/utils/algo_utils/algo_utils.go +++ b/std/utils/algo_utils/algo_utils.go @@ -44,6 +44,12 @@ func SliceAt[T any](slice []T) func(int) T { } } +func SlicePtrAt[T any](slice []T) func(int) *T { + return func(i int) *T { + return &slice[i] + } +} + func MapAt[K comparable, V any](mp map[K]V) func(K) V { return func(k K) V { return mp[k] diff --git a/test/engine_test.go b/test/engine_test.go index 26b232b46e..8a77af4e80 100644 --- a/test/engine_test.go +++ b/test/engine_test.go @@ -69,3 +69,28 @@ func TestBuiltinHints(t *testing.T) { } } + +type inlineHintCircuit struct { + X frontend.Variable +} + +func (c *inlineHintCircuit) Define(api frontend.API) error { + zeroMaker := func(q *big.Int, ins, outs []*big.Int) error { + outs[0].SetUint64(0) + return nil + } + hint.Register(zeroMaker) + zero, err := api.Compiler().NewHint(zeroMaker, 1, c.X) + if err != nil { + return err + } + api.AssertIsEqual(c.X, zero[0]) + return nil +} + +func TestInlineHint(t *testing.T) { + assignment := inlineHintCircuit{X: 0} + circuit := inlineHintCircuit{} + + NewAssert(t).SolvingSucceeded(&circuit, &assignment) +} From d4b924b0e5ac26f1244afbc97f93a6e7c5c913f4 Mon Sep 17 00:00:00 2001 From: Arya Tabaie Date: Wed, 18 Jan 2023 11:08:49 -0500 Subject: [PATCH 22/71] fix: import cycle --- constraint/bn254/gkr.go | 18 +++++++++++++----- constraint/gkr.go | 3 +++ 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/constraint/bn254/gkr.go b/constraint/bn254/gkr.go index 76e12988b5..ae70c60f7c 100644 --- a/constraint/bn254/gkr.go +++ b/constraint/bn254/gkr.go @@ -11,7 +11,9 @@ import ( fiatshamir "github.com/consensys/gnark-crypto/fiat-shamir" "github.com/consensys/gnark/backend/hint" "github.com/consensys/gnark/constraint" - stdGkr "github.com/consensys/gnark/std/gkr" + "sync" + + //stdGkr "github.com/consensys/gnark/std/gkr" "github.com/consensys/gnark/std/utils/algo_utils" "math/big" ) @@ -153,7 +155,7 @@ func gkrSetOutputValues(circuit []constraint.GkrWire, assignments gkrAssignment, // Check if outsI == len(outs)? } -func gkrSolveHint(data constraint.GkrInfo, res *gkrSolvingData) hint.Function { +func gkrSolveHint(data constraint.GkrInfo, res *gkrSolvingData, solvingDone *sync.Mutex) hint.Function { return func(_ *big.Int, ins, outs []*big.Int) error { res.circuit = convertCircuit(data.Circuit) // TODO: Take this out of here into the proving module @@ -166,6 +168,8 @@ func gkrSolveHint(data constraint.GkrInfo, res *gkrSolvingData) hint.Function { fmt.Println("assignment ", sliceSliceToString(assignments)) fmt.Println("returning ", bigIntPtrSliceToString(outs)) + solvingDone.Unlock() + return nil } } @@ -197,7 +201,7 @@ func frToBigInts(dst []*big.Int, src []fr.Element) { } } -func gkrProveHint(hashName string, data *gkrSolvingData) hint.Function { +func gkrProveHint(hashName string, data *gkrSolvingData, solvingDone *sync.Mutex) hint.Function { return func(_ *big.Int, ins, outs []*big.Int) error { insBytes := algo_utils.Map(ins, func(i *big.Int) []byte { @@ -207,6 +211,8 @@ func gkrProveHint(hashName string, data *gkrSolvingData) hint.Function { hsh := mimc.NewMiMC() // TODO: Use hashName + solvingDone.Lock() + proof, err := gkr.Prove(data.circuit, data.assignments, fiatshamir.WithHash(hsh, insBytes...), gkr.WithPool(&data.memoryPool)) // TODO: Do transcriptSettings properly if err != nil { return err @@ -236,7 +242,9 @@ func defineGkrHints(info constraint.GkrInfo, hintFunctions map[hint.ID]hint.Func res[k] = v } var gkrData gkrSolvingData - res[hint.UUID(stdGkr.SolveHintPlaceholder)] = gkrSolveHint(info, &gkrData) - res[hint.UUID(stdGkr.ProveHintPlaceholder)] = gkrProveHint(info.HashName, &gkrData) + var solvingDone sync.Mutex // if the user manages challenges correctly, the solver will see the "prove" function as dependent on the "solve" function, but better not take chances + solvingDone.Lock() + res[info.SolveHintID] = gkrSolveHint(info, &gkrData, &solvingDone) + res[info.ProveHintID] = gkrProveHint(info.HashName, &gkrData, &solvingDone) return res } diff --git a/constraint/gkr.go b/constraint/gkr.go index 5255dca8ab..ed304e62b4 100644 --- a/constraint/gkr.go +++ b/constraint/gkr.go @@ -2,6 +2,7 @@ package constraint import ( "fmt" + "github.com/consensys/gnark/backend/hint" "github.com/consensys/gnark/std/utils/algo_utils" "sort" ) @@ -28,6 +29,8 @@ type GkrInfo struct { MaxNIns int NbInstances int HashName string + SolveHintID hint.ID + ProveHintID hint.ID } type GkrPermutations struct { From 4d29684ad76b85754d5bd83d4028849c866efcb9 Mon Sep 17 00:00:00 2001 From: Arya Tabaie Date: Wed, 18 Jan 2023 12:11:12 -0500 Subject: [PATCH 23/71] test: basic permutation tests passing --- constraint/bn254/gkr.go | 3 ++ constraint/gkr.go | 15 +++---- std/gkr/compile_test.go | 95 ++++++++++++++++++++++++++++++++++++++--- 3 files changed, 97 insertions(+), 16 deletions(-) diff --git a/constraint/bn254/gkr.go b/constraint/bn254/gkr.go index ae70c60f7c..1490867c4d 100644 --- a/constraint/bn254/gkr.go +++ b/constraint/bn254/gkr.go @@ -209,6 +209,9 @@ func gkrProveHint(hashName string, data *gkrSolvingData, solvingDone *sync.Mutex return b[:] }) + if hashName != "mimc" { + return fmt.Errorf("currently only mimc supported") + } hsh := mimc.NewMiMC() // TODO: Use hashName solvingDone.Lock() diff --git a/constraint/gkr.go b/constraint/gkr.go index ed304e62b4..b062f1d811 100644 --- a/constraint/gkr.go +++ b/constraint/gkr.go @@ -95,16 +95,10 @@ func (d *GkrInfo) Compile(nbInstances int) (GkrPermutations, error) { p.SortedWires, uniqueOuts = algo_utils.TopologicalSort(inputs) p.WiresPermutation = algo_utils.InvertPermutation(p.SortedWires) wirePermutationAt := algo_utils.SliceAt(p.WiresPermutation) - sorted := make([]GkrWire, len(d.Circuit)) + sorted := make([]GkrWire, len(d.Circuit)) // TODO: Directly manipulate d.Circuit instead for newI, oldI := range p.SortedWires { oldW := d.Circuit[oldI] - for i := 1; i < len(oldW.Dependencies); i++ { - if oldW.Dependencies[i].InputInstance == oldW.Dependencies[i-1].InputInstance { - return p, fmt.Errorf("an input wire can only have one dependency per instance") - } - } // TODO: Check that dependencies and explicit assignments cover all instances - if !oldW.IsInput() { d.MaxNIns = max(d.MaxNIns, len(oldW.Inputs)) } @@ -115,10 +109,14 @@ func (d *GkrInfo) Compile(nbInstances int) (GkrPermutations, error) { dep.InputInstance = p.InstancesPermutation[dep.InputInstance] dep.OutputInstance = p.InstancesPermutation[dep.OutputInstance] } - sort.Slice(oldW.Dependencies, func(i, j int) bool { return oldW.Dependencies[i].InputInstance < oldW.Dependencies[j].InputInstance }) + for i := 1; i < len(oldW.Dependencies); i++ { + if oldW.Dependencies[i].InputInstance == oldW.Dependencies[i-1].InputInstance { + return p, fmt.Errorf("an input wire can only have one dependency per instance") + } + } // TODO: Check that dependencies and explicit assignments cover all instances sorted[newI] = GkrWire{ Gate: oldW.Gate, @@ -126,7 +124,6 @@ func (d *GkrInfo) Compile(nbInstances int) (GkrPermutations, error) { Dependencies: oldW.Dependencies, NbUniqueOutputs: len(uniqueOuts[oldI]), } - } d.Circuit = sorted diff --git a/std/gkr/compile_test.go b/std/gkr/compile_test.go index f28450f2c4..646af17286 100644 --- a/std/gkr/compile_test.go +++ b/std/gkr/compile_test.go @@ -29,7 +29,7 @@ import ( assert.Equal(t, 3, len(circuit)) }*/ -func TestNoPtrCompile(t *testing.T) { +func TestCompile2Cycles(t *testing.T) { var d = constraint.GkrInfo{ Circuit: constraint.GkrCircuit{ { @@ -48,10 +48,10 @@ func TestNoPtrCompile(t *testing.T) { }, }, } - assignment := GkrAssignment{ + /*assignment := GkrAssignment{ {2, 1}, {nil, 0}, - } + }*/ expectedCompiled := constraint.GkrInfo{ Circuit: constraint.GkrCircuit{ @@ -69,15 +69,96 @@ func TestNoPtrCompile(t *testing.T) { Inputs: []int{0}, Dependencies: nil, }}, - MaxNIns: 1, + MaxNIns: 1, + NbInstances: 2, } - expectedAssignment := GkrAssignment{ + /*expectedAssignment := GkrAssignment{ {0, nil}, {1, 2}, + }*/ + + expectedPermutations := constraint.GkrPermutations{ + SortedInstances: []int{1, 0}, + SortedWires: []int{1, 0}, + InstancesPermutation: []int{1, 0}, + WiresPermutation: []int{1, 0}, + } + + p, err := d.Compile(2) + assert.NoError(t, err) + assert.Equal(t, expectedPermutations, p) + assert.Equal(t, expectedCompiled, d) + //assert.Equal(t, expectedAssignment, assignment) +} + +func TestCompile3Cycles(t *testing.T) { + var d = constraint.GkrInfo{ + Circuit: constraint.GkrCircuit{ + { + Inputs: []int{2}, + Dependencies: nil, + }, + { + Inputs: []int{}, + Dependencies: []constraint.InputDependency{ + { + OutputWire: 0, + OutputInstance: 2, + InputInstance: 0, + }, + { + OutputWire: 0, + OutputInstance: 1, + InputInstance: 2, + }, + }, + }, + { + Inputs: []int{1}, + Dependencies: nil, + }, + }, + } + + expectedCompiled := constraint.GkrInfo{ + Circuit: constraint.GkrCircuit{ + { + Inputs: []int{}, + Dependencies: []constraint.InputDependency{{ + OutputWire: 2, + OutputInstance: 0, + InputInstance: 1, + }, { + OutputWire: 2, + OutputInstance: 1, + InputInstance: 2, + }}, + NbUniqueOutputs: 1, + }, + { + Inputs: []int{0}, + Dependencies: nil, + NbUniqueOutputs: 1, + }, + { + Inputs: []int{1}, + Dependencies: nil, + NbUniqueOutputs: 0, + }, + }, + MaxNIns: 1, + NbInstances: 3, // not allowed if we were actually performing gkr + } + + expectedPermutations := constraint.GkrPermutations{ + SortedInstances: []int{1, 2, 0}, + SortedWires: []int{1, 2, 0}, + InstancesPermutation: []int{2, 0, 1}, + WiresPermutation: []int{2, 0, 1}, } - _, err := d.Compile(assignment.NbInstances()) // TODO: Test the permutation too + p, err := d.Compile(3) assert.NoError(t, err) + assert.Equal(t, expectedPermutations, p) assert.Equal(t, expectedCompiled, d) - assert.Equal(t, expectedAssignment, assignment) } From 41a1615a7c4b674e88b0222a3ab839bfee0d1539 Mon Sep 17 00:00:00 2001 From: Arya Tabaie Date: Wed, 18 Jan 2023 14:04:05 -0500 Subject: [PATCH 24/71] test: end-to-end: can't use test engine (for now) --- constraint/gkr.go | 2 +- frontend/builder.go | 1 + frontend/cs/r1cs/builder.go | 17 +++++++--- frontend/cs/scs/builder.go | 5 +++ std/gkr/api.go | 1 + std/gkr/api_test.go | 53 +++++++++++++++--------------- std/gkr/compile.go | 64 ++++++++++++++++++------------------- std/gkr/registry.go | 11 +++---- test/engine.go | 8 ++++- 9 files changed, 91 insertions(+), 71 deletions(-) diff --git a/constraint/gkr.go b/constraint/gkr.go index b062f1d811..f1bffb871a 100644 --- a/constraint/gkr.go +++ b/constraint/gkr.go @@ -64,7 +64,7 @@ func (d *GkrInfo) AssignmentOffsets() []int { func (d *GkrInfo) NewInputVariable() GkrVariable { i := len(d.Circuit) - d.Circuit = append(d.Circuit) + d.Circuit = append(d.Circuit, GkrWire{}) return GkrVariable(i) } diff --git a/frontend/builder.go b/frontend/builder.go index 1446077c59..e73c0ce4eb 100644 --- a/frontend/builder.go +++ b/frontend/builder.go @@ -56,6 +56,7 @@ type Compiler interface { // This API is experimental // TENTATIVE: Functions regarding fiat-shamir-ed proofs over enormous statements TODO finalize Commit(...Variable) (Variable, error) + SetGkrInfo(constraint.GkrInfo) *constraint.GkrInfo } // Builder represents a constraint system builder diff --git a/frontend/cs/r1cs/builder.go b/frontend/cs/r1cs/builder.go index fdaf0e268c..d23c7733cc 100644 --- a/frontend/cs/r1cs/builder.go +++ b/frontend/cs/r1cs/builder.go @@ -56,9 +56,18 @@ type builder struct { // map for recording boolean constrained variables (to not constrain them twice) mtBooleans map[uint64][]expr.LinearExpression - q *big.Int - tOne constraint.Coeff - heap minHeap // helps merge k sorted linear expressions + q *big.Int + tOne constraint.Coeff + heap minHeap // helps merge k sorted linear expressions + gkrInfo constraint.GkrInfo +} + +func (builder *builder) SetGkrInfo(info constraint.GkrInfo) *constraint.GkrInfo { + if builder.gkrInfo.Circuit != nil { + panic("currently only one gkr sub-circuit per snark is allowed") + } + builder.gkrInfo = info + return &builder.gkrInfo } // initialCapacity has quite some impact on frontend performance, especially on large circuits size @@ -158,7 +167,7 @@ func (builder *builder) FieldBitLen() int { return builder.cs.FieldBitLen() } -// newR1C clones the linear expression associated with the Variables (to avoid offseting the ID multiple time) +// newR1C clones the linear expression associated with the Variables (to avoid offsetting the ID multiple time) // and return a R1C func (builder *builder) newR1C(_l, _r, _o frontend.Variable) constraint.R1C { l := _l.(expr.LinearExpression) diff --git a/frontend/cs/scs/builder.go b/frontend/cs/scs/builder.go index fee010f01f..3a2c2c8673 100644 --- a/frontend/cs/scs/builder.go +++ b/frontend/cs/scs/builder.go @@ -58,6 +58,11 @@ type scs struct { q *big.Int } +func (builder *scs) SetGkrInfo(info constraint.GkrInfo) *constraint.GkrInfo { + panic("not implemented") + return nil +} + // initialCapacity has quite some impact on frontend performance, especially on large circuits size // we may want to add build tags to tune that // TODO @gbotrel restore capacity option! diff --git a/std/gkr/api.go b/std/gkr/api.go index a214135a42..eb9a224ad2 100644 --- a/std/gkr/api.go +++ b/std/gkr/api.go @@ -17,6 +17,7 @@ func (api *API) newNonInputVariable(gate string, in []frontend.Variable) constra Gate: gate, Inputs: algo_utils.Map(in, frontendVarToInt), }) + api.assignments = append(api.assignments, nil) return constraint.GkrVariable(len(api.toStore.Circuit) - 1) } diff --git a/std/gkr/api_test.go b/std/gkr/api_test.go index 9e0133719c..82e678e619 100644 --- a/std/gkr/api_test.go +++ b/std/gkr/api_test.go @@ -6,10 +6,10 @@ import ( bn254TestVectorUtils "github.com/consensys/gnark-crypto/ecc/bn254/fr/test_vector_utils" "github.com/consensys/gnark/backend" "github.com/consensys/gnark/backend/groth16" + "github.com/consensys/gnark/backend/witness" "github.com/consensys/gnark/constraint" "github.com/consensys/gnark/frontend" "github.com/consensys/gnark/frontend/cs/r1cs" - "github.com/consensys/gnark/std/hash/mimc" "github.com/consensys/gnark/std/utils/test_vectors_utils" "github.com/consensys/gnark/test" "github.com/stretchr/testify/assert" @@ -39,12 +39,7 @@ func (c *doubleNoDependencyCircuit) Define(api frontend.API) error { api.AssertIsEqual(Z[i], api.Mul(2, c.X[i])) } - var hsh mimc.MiMC - if hsh, err = mimc.NewMiMC(api); err != nil { - return err - } - //hsh := messageCounter{startState: 0, step: 1} - return solution.Verify(&hsh) + return solution.Verify("mimc") } func TestDoubleNoDependencyCircuit(t *testing.T) { @@ -76,13 +71,7 @@ func (c *sqNoDependencyCircuit) Define(api frontend.API) error { api.AssertIsEqual(Z[i], api.Mul(c.X[i], c.X[i])) } - var hsh mimc.MiMC - if hsh, err = mimc.NewMiMC(api); err != nil { - return err - } - //var hsh hash.Hash = &literalSum{initialState: 0} - //hsh := messageCounter{startState: 0, step: 1} - return solution.Verify(&hsh) + return solution.Verify("mimc") } func TestSqNoDependencyCircuit(t *testing.T) { @@ -122,12 +111,7 @@ func (c *mulNoDependencyCircuit) Define(api frontend.API) error { api.AssertIsEqual(Z[i], api.Mul(c.X[i], c.Y[i])) } - var hsh mimc.MiMC - if hsh, err = mimc.NewMiMC(api); err != nil { - return err - } - //hsh := messageCounter{startState: 0, step: 1} - return solution.Verify(&hsh) + return solution.Verify("mimc") } func TestMulNoDependency(t *testing.T) { @@ -308,7 +292,7 @@ func (c *benchMiMCMerkleTreeCircuit) Define(api frontend.API) error { } // cheat{ - gkr.circuitData.toStore.Circuit = append(gkr.circuitData.toStore.Circuit, constraint.GkrWire{ + gkr.toStore.Circuit = append(gkr.toStore.Circuit, constraint.GkrWire{ Gate: "mimc", Inputs: []int{int(x.(constraint.GkrVariable)), int(y.(constraint.GkrVariable))}, }) @@ -335,10 +319,27 @@ func (c *benchMiMCMerkleTreeCircuit) Define(api frontend.API) error { return err } - hsh, err := mimc.NewMiMC(api) - if err != nil { - return err - } + return solution.Verify("mimc", challenge) +} - return solution.Verify(&hsh, challenge) +func solve(t *testing.T, circuit, assignment frontend.Circuit) { + cs, err := frontend.Compile(ecc.BN254.ScalarField(), r1cs.NewBuilder, circuit) + assert.NoError(t, err) + var ( + fullWitness *witness.Witness + publicWitness *witness.Witness + pk groth16.ProvingKey + vk groth16.VerifyingKey + proof groth16.Proof + ) + fullWitness, err = frontend.NewWitness(assignment, ecc.BN254.ScalarField()) + assert.NoError(t, err) + publicWitness, err = fullWitness.Public() + assert.NoError(t, err) + pk, vk, err = groth16.Setup(cs) + assert.NoError(t, err) + proof, err = groth16.Prove(cs, pk, fullWitness) + assert.NoError(t, err) + err = groth16.Verify(proof, vk, publicWitness) + assert.NoError(t, err) } diff --git a/std/gkr/compile.go b/std/gkr/compile.go index ef5b8eac6d..23b5a3704f 100644 --- a/std/gkr/compile.go +++ b/std/gkr/compile.go @@ -2,10 +2,12 @@ package gkr import ( "fmt" + "github.com/consensys/gnark/backend/hint" "github.com/consensys/gnark/constraint" "github.com/consensys/gnark/frontend" fiatshamir "github.com/consensys/gnark/std/fiat-shamir" "github.com/consensys/gnark/std/hash" + "github.com/consensys/gnark/std/hash/mimc" "github.com/consensys/gnark/std/utils/algo_utils" "math/big" "math/bits" @@ -16,17 +18,14 @@ type circuitDataForSnark struct { assignments WireAssignment } -type circuitData struct { +type API struct { toStore constraint.GkrInfo assignments GkrAssignment } -type API struct { - circuitData -} - type Solution struct { - circuitData + toStore *constraint.GkrInfo + assignments GkrAssignment parentApi frontend.API permutations constraint.GkrPermutations } @@ -40,12 +39,12 @@ func (api *API) logNbInstances() int { } func NewApi() *API { - return &API{circuitData{ + return &API{ toStore: constraint.GkrInfo{ Circuit: make(constraint.GkrCircuit, 0), MaxNIns: 0, }, - }} + } } // log2 returns -1 if x is not a power of 2 @@ -82,8 +81,9 @@ func (api *API) Import(assignment []frontend.Variable) (constraint.GkrVariable, if currentNbInstances := api.nbInstances(); currentNbInstances != -1 && currentNbInstances != nbInstances { return -1, fmt.Errorf("number of assignments must be consistent across all variables") } - - return api.toStore.NewInputVariable(), nil + newVar := api.toStore.NewInputVariable() + api.assignments = append(api.assignments, assignment) + return newVar, nil } func appendNonNil(dst *[]frontend.Variable, src []frontend.Variable) { @@ -128,6 +128,7 @@ func (api *API) Solve(parentApi frontend.API) (Solution, error) { } outsSerialized, err := parentApi.Compiler().NewHint(SolveHintPlaceholder, solveHintNOut, ins...) + api.toStore.SolveHintID = hint.UUID(SolveHintPlaceholder) if err != nil { return Solution{}, err } @@ -145,49 +146,33 @@ func (api *API) Solve(parentApi frontend.API) (Solution, error) { } } - setGkrInfo(parentApi, api.toStore) - return Solution{ - circuitData: api.circuitData, + toStore: parentApi.Compiler().SetGkrInfo(api.toStore), + assignments: api.assignments, parentApi: parentApi, permutations: p, }, nil } -func setGkrInfo(api frontend.API, toStore constraint.GkrInfo) { - switch sys := api.(type) { - default: - panic(fmt.Sprintf("unrecognized type %T", sys)) - } -} - func (s Solution) Export(v frontend.Variable) []frontend.Variable { return algo_utils.Map(s.permutations.SortedInstances, algo_utils.SliceAt(s.assignments[v.(constraint.GkrVariable)])) } -func (s Solution) Verify(hash hash.Hash, initialChallenges ...frontend.Variable) error { - // TODO: Translate transcriptSettings from snark to field ugh +func (s Solution) Verify(hashName string, initialChallenges ...frontend.Variable) error { var ( err error proofSerialized []frontend.Variable proof Proof ) - forSnark := newCircuitDataForSnark(s.toStore, s.assignments) + forSnark := newCircuitDataForSnark(*s.toStore, s.assignments) logNbInstances := log2(uint(s.assignments.NbInstances())) - // TODO: Find out if this hack is necessary - /*for i := range s.toStore.circuit { - if s.toStore.circuit[i].isOutput() { - initialChallenges = append(initialChallenges, s.toStore.circuit[i].assignments[0]) - break - } - }*/ - if proofSerialized, err = s.parentApi.Compiler().NewHint( ProveHintPlaceholder, ProofSize(forSnark.circuit, logNbInstances), initialChallenges...); err != nil { return err } + s.toStore.ProveHintID = hint.UUID(ProveHintPlaceholder) forSnarkSorted := algo_utils.MapRange(0, len(s.toStore.Circuit), slicePtrAt(forSnark.circuit)) @@ -195,7 +180,18 @@ func (s Solution) Verify(hash hash.Hash, initialChallenges ...frontend.Variable) return err } - return Verify(s.parentApi, forSnark.circuit, forSnark.assignments, proof, fiatshamir.WithHash(hash, initialChallenges...), WithSortedCircuit(forSnarkSorted)) // TODO: Security critical: do a proper transcriptSetting + var hsh hash.Hash + if hashName == "mimc" { + if _mimc, err := mimc.NewMiMC(s.parentApi); err == nil { + hsh = &_mimc + } else { + return err + } + } else { + return fmt.Errorf("unsupported hash \"%s\"", hashName) // TODO: A hash registry + } + + return Verify(s.parentApi, forSnark.circuit, forSnark.assignments, proof, fiatshamir.WithHash(hsh, initialChallenges...), WithSortedCircuit(forSnarkSorted)) // TODO: Security critical: do a proper transcriptSetting } @@ -249,6 +245,8 @@ func (a GkrAssignment) NbInstances() int { func (a GkrAssignment) Permute(p constraint.GkrPermutations) { algo_utils.Permute(a, p.WiresPermutation) for i := range a { - algo_utils.Permute(a[i], p.InstancesPermutation) + if a[i] != nil { + algo_utils.Permute(a[i], p.InstancesPermutation) + } } } diff --git a/std/gkr/registry.go b/std/gkr/registry.go index a42370d193..72c26e358c 100644 --- a/std/gkr/registry.go +++ b/std/gkr/registry.go @@ -2,12 +2,11 @@ package gkr import "github.com/consensys/gnark/frontend" -var RegisteredGates = make(map[string]Gate) - -func init() { - RegisteredGates["identity"] = IdentityGate{} - RegisteredGates["mul"] = MulGate{} - RegisteredGates["mimc"] = MiMCCipherGate{Ark: 0} //TODO: Add ark +var RegisteredGates = map[string]Gate{ + "identity": IdentityGate{}, + "add": AddGate{}, + "mul": MulGate{}, + "mimc": MiMCCipherGate{Ark: 0}, //TODO: Add ark } type MiMCCipherGate struct { diff --git a/test/engine.go b/test/engine.go index 84ffc79b63..1a287f9bf0 100644 --- a/test/engine.go +++ b/test/engine.go @@ -18,6 +18,7 @@ package test import ( "fmt" + "github.com/consensys/gnark/constraint" "math/big" "path/filepath" "reflect" @@ -578,6 +579,11 @@ func (e *engine) Compiler() frontend.Compiler { } func (e *engine) Commit(v ...frontend.Variable) (frontend.Variable, error) { + panic("not implemented") +} + +func (e *engine) SetGkrInfo(info constraint.GkrInfo) *constraint.GkrInfo { //TODO implement me - panic("implement me") + panic("not implemented") + return nil } From 6d041eac037fc5e2af746e00b3e716b4a14356ee Mon Sep 17 00:00:00 2001 From: Arya Tabaie Date: Wed, 18 Jan 2023 15:17:48 -0500 Subject: [PATCH 25/71] fix: propagating gkrInfo --- constraint/gkr.go | 4 ++++ constraint/system.go | 10 ++++++++++ frontend/builder.go | 2 +- frontend/cs/r1cs/api.go | 4 ++++ frontend/cs/r1cs/builder.go | 15 +++------------ frontend/cs/scs/builder.go | 13 ++++++------- std/gkr/api_test.go | 3 ++- std/gkr/compile.go | 13 +++++++++---- test/engine.go | 6 ++---- 9 files changed, 41 insertions(+), 29 deletions(-) diff --git a/constraint/gkr.go b/constraint/gkr.go index f1bffb871a..486f9eadbc 100644 --- a/constraint/gkr.go +++ b/constraint/gkr.go @@ -130,6 +130,10 @@ func (d *GkrInfo) Compile(nbInstances int) (GkrPermutations, error) { return p, nil } +func (d *GkrInfo) Is() bool { + return d.Circuit != nil +} + func max(a, b int) int { if a > b { return a diff --git a/constraint/system.go b/constraint/system.go index fbbd28bc9b..2f723cbb19 100644 --- a/constraint/system.go +++ b/constraint/system.go @@ -57,6 +57,7 @@ type ConstraintSystem interface { AddSolverHint(f hint.Function, input []LinearExpression, nbOutput int) (internalVariables []int, err error) AddCommitment(c Commitment) error + AddGkr(gkr GkrInfo) error AddLog(l LogEntry) @@ -308,6 +309,15 @@ func (system *System) AddSolverHint(f hint.Function, input []LinearExpression, n return } +func (system *System) AddGkr(gkr GkrInfo) error { + if system.GkrInfo.Is() { + return fmt.Errorf("currently only one GKR sub-circuit per SNARK is supported") + } + + system.GkrInfo = gkr + return nil +} + func (system *System) AddCommitment(c Commitment) error { if system.CommitmentInfo.Is() { return fmt.Errorf("currently only one commitment per circuit is supported") diff --git a/frontend/builder.go b/frontend/builder.go index e73c0ce4eb..85f83073c1 100644 --- a/frontend/builder.go +++ b/frontend/builder.go @@ -56,7 +56,7 @@ type Compiler interface { // This API is experimental // TENTATIVE: Functions regarding fiat-shamir-ed proofs over enormous statements TODO finalize Commit(...Variable) (Variable, error) - SetGkrInfo(constraint.GkrInfo) *constraint.GkrInfo + SetGkrInfo(constraint.GkrInfo) error } // Builder represents a constraint system builder diff --git a/frontend/cs/r1cs/api.go b/frontend/cs/r1cs/api.go index 8003c7cfac..383c085f5a 100644 --- a/frontend/cs/r1cs/api.go +++ b/frontend/cs/r1cs/api.go @@ -703,6 +703,10 @@ func (builder *builder) getCommittedVariables(i *constraint.Commitment) []fronte return res } +func (builder *builder) SetGkrInfo(info constraint.GkrInfo) error { + return builder.cs.AddGkr(info) +} + func bsb22CommitmentComputePlaceholder(*big.Int, []*big.Int, []*big.Int) error { return fmt.Errorf("placeholder function: to be replaced by commitment computation") } diff --git a/frontend/cs/r1cs/builder.go b/frontend/cs/r1cs/builder.go index d23c7733cc..5326415355 100644 --- a/frontend/cs/r1cs/builder.go +++ b/frontend/cs/r1cs/builder.go @@ -56,18 +56,9 @@ type builder struct { // map for recording boolean constrained variables (to not constrain them twice) mtBooleans map[uint64][]expr.LinearExpression - q *big.Int - tOne constraint.Coeff - heap minHeap // helps merge k sorted linear expressions - gkrInfo constraint.GkrInfo -} - -func (builder *builder) SetGkrInfo(info constraint.GkrInfo) *constraint.GkrInfo { - if builder.gkrInfo.Circuit != nil { - panic("currently only one gkr sub-circuit per snark is allowed") - } - builder.gkrInfo = info - return &builder.gkrInfo + q *big.Int + tOne constraint.Coeff + heap minHeap // helps merge k sorted linear expressions } // initialCapacity has quite some impact on frontend performance, especially on large circuits size diff --git a/frontend/cs/scs/builder.go b/frontend/cs/scs/builder.go index 3a2c2c8673..7438e473cf 100644 --- a/frontend/cs/scs/builder.go +++ b/frontend/cs/scs/builder.go @@ -17,6 +17,7 @@ limitations under the License. package scs import ( + "fmt" "math/big" "reflect" "sort" @@ -58,11 +59,6 @@ type scs struct { q *big.Int } -func (builder *scs) SetGkrInfo(info constraint.GkrInfo) *constraint.GkrInfo { - panic("not implemented") - return nil -} - // initialCapacity has quite some impact on frontend performance, especially on large circuits size // we may want to add build tags to tune that // TODO @gbotrel restore capacity option! @@ -366,8 +362,11 @@ func (builder *scs) splitProd(acc expr.TermToRefactor, r expr.LinearExpressionTo } func (builder *scs) Commit(v ...frontend.Variable) (frontend.Variable, error) { - //TODO implement me - panic("not implemented") + return nil, fmt.Errorf("not implemented") +} + +func (builder *scs) SetGkrInfo(info constraint.GkrInfo) error { + return fmt.Errorf("not implemented") } // newDebugInfo this is temporary to restore debug logs diff --git a/std/gkr/api_test.go b/std/gkr/api_test.go index 82e678e619..a0236a191d 100644 --- a/std/gkr/api_test.go +++ b/std/gkr/api_test.go @@ -46,7 +46,8 @@ func TestDoubleNoDependencyCircuit(t *testing.T) { assignment := doubleNoDependencyCircuit{X: []frontend.Variable{1, 1}} circuit := doubleNoDependencyCircuit{X: make([]frontend.Variable, 2)} - test.NewAssert(t).SolvingSucceeded(&circuit, &assignment, test.WithBackends(backend.GROTH16), test.WithCurves(ecc.BN254)) + solve(t, &circuit, &assignment) + //test.NewAssert(t).SolvingSucceeded(&circuit, &assignment, test.WithBackends(backend.GROTH16), test.WithCurves(ecc.BN254)) } type sqNoDependencyCircuit struct { diff --git a/std/gkr/compile.go b/std/gkr/compile.go index 23b5a3704f..cc18e25471 100644 --- a/std/gkr/compile.go +++ b/std/gkr/compile.go @@ -24,7 +24,7 @@ type API struct { } type Solution struct { - toStore *constraint.GkrInfo + toStore constraint.GkrInfo assignments GkrAssignment parentApi frontend.API permutations constraint.GkrPermutations @@ -147,7 +147,7 @@ func (api *API) Solve(parentApi frontend.API) (Solution, error) { } return Solution{ - toStore: parentApi.Compiler().SetGkrInfo(api.toStore), + toStore: api.toStore, assignments: api.assignments, parentApi: parentApi, permutations: p, @@ -165,7 +165,7 @@ func (s Solution) Verify(hashName string, initialChallenges ...frontend.Variable proof Proof ) - forSnark := newCircuitDataForSnark(*s.toStore, s.assignments) + forSnark := newCircuitDataForSnark(s.toStore, s.assignments) logNbInstances := log2(uint(s.assignments.NbInstances())) if proofSerialized, err = s.parentApi.Compiler().NewHint( @@ -190,9 +190,14 @@ func (s Solution) Verify(hashName string, initialChallenges ...frontend.Variable } else { return fmt.Errorf("unsupported hash \"%s\"", hashName) // TODO: A hash registry } + s.toStore.HashName = hashName - return Verify(s.parentApi, forSnark.circuit, forSnark.assignments, proof, fiatshamir.WithHash(hsh, initialChallenges...), WithSortedCircuit(forSnarkSorted)) // TODO: Security critical: do a proper transcriptSetting + err = Verify(s.parentApi, forSnark.circuit, forSnark.assignments, proof, fiatshamir.WithHash(hsh, initialChallenges...), WithSortedCircuit(forSnarkSorted)) // TODO: Security critical: do a proper transcriptSetting + if err != nil { + return err + } + return s.parentApi.Compiler().SetGkrInfo(s.toStore) } func SolveHintPlaceholder(*big.Int, []*big.Int, []*big.Int) error { diff --git a/test/engine.go b/test/engine.go index 1a287f9bf0..1b26cb291b 100644 --- a/test/engine.go +++ b/test/engine.go @@ -582,8 +582,6 @@ func (e *engine) Commit(v ...frontend.Variable) (frontend.Variable, error) { panic("not implemented") } -func (e *engine) SetGkrInfo(info constraint.GkrInfo) *constraint.GkrInfo { - //TODO implement me - panic("not implemented") - return nil +func (e *engine) SetGkrInfo(info constraint.GkrInfo) error { + return fmt.Errorf("not implemented") } From fc82d973b376b83860448c51d7f644db02340232 Mon Sep 17 00:00:00 2001 From: Arya Tabaie Date: Wed, 18 Jan 2023 19:18:37 -0500 Subject: [PATCH 26/71] test: "doubling" circuit passes --- constraint/bn254/gkr.go | 15 ++-- std/fiat-shamir/transcript.go | 8 +- std/gkr/api_test.go | 161 ++++++++++++++++++++++++++++++---- std/gkr/compile.go | 23 ++--- std/gkr/compile_test.go | 4 +- std/hash/hash.go | 5 +- 6 files changed, 165 insertions(+), 51 deletions(-) diff --git a/constraint/bn254/gkr.go b/constraint/bn254/gkr.go index 1490867c4d..bd44ed4f99 100644 --- a/constraint/bn254/gkr.go +++ b/constraint/bn254/gkr.go @@ -5,17 +5,15 @@ import ( "fmt" "github.com/consensys/gnark-crypto/ecc/bn254/fr" "github.com/consensys/gnark-crypto/ecc/bn254/fr/gkr" - "github.com/consensys/gnark-crypto/ecc/bn254/fr/mimc" "github.com/consensys/gnark-crypto/ecc/bn254/fr/polynomial" "github.com/consensys/gnark-crypto/ecc/bn254/fr/test_vector_utils" fiatshamir "github.com/consensys/gnark-crypto/fiat-shamir" "github.com/consensys/gnark/backend/hint" "github.com/consensys/gnark/constraint" - "sync" - - //stdGkr "github.com/consensys/gnark/std/gkr" "github.com/consensys/gnark/std/utils/algo_utils" + "hash" "math/big" + "sync" ) type gkrSolvingData struct { @@ -209,13 +207,9 @@ func gkrProveHint(hashName string, data *gkrSolvingData, solvingDone *sync.Mutex return b[:] }) - if hashName != "mimc" { - return fmt.Errorf("currently only mimc supported") - } - hsh := mimc.NewMiMC() // TODO: Use hashName + hsh := HashBuilderRegistry[hashName]() solvingDone.Lock() - proof, err := gkr.Prove(data.circuit, data.assignments, fiatshamir.WithHash(hsh, insBytes...), gkr.WithPool(&data.memoryPool)) // TODO: Do transcriptSettings properly if err != nil { return err @@ -251,3 +245,6 @@ func defineGkrHints(info constraint.GkrInfo, hintFunctions map[hint.ID]hint.Func res[info.ProveHintID] = gkrProveHint(info.HashName, &gkrData, &solvingDone) return res } + +// TODO: Move to gnark-crypto +var HashBuilderRegistry = make(map[string]func() hash.Hash) diff --git a/std/fiat-shamir/transcript.go b/std/fiat-shamir/transcript.go index bbea588e68..c4447fde4a 100644 --- a/std/fiat-shamir/transcript.go +++ b/std/fiat-shamir/transcript.go @@ -18,6 +18,7 @@ package fiatshamir import ( "errors" + "fmt" "github.com/consensys/gnark/frontend" "github.com/consensys/gnark/std/hash" @@ -140,8 +141,11 @@ func (t *Transcript) ComputeChallenge(challengeID string) (frontend.Variable, er t.h.Reset() - t.api.Println("snark challenge \"", challengeID, "\" <- ", challenge.value) - + if valueInt, ok := challenge.value.(int); ok { + fmt.Printf("snark challenge \"%s\" <- %d\n", challengeID, valueInt) + } else { + t.api.Println("snark challenge \"", challengeID, "\" <- ", challenge.value) + } return challenge.value, nil } diff --git a/std/gkr/api_test.go b/std/gkr/api_test.go index a0236a191d..858781cff3 100644 --- a/std/gkr/api_test.go +++ b/std/gkr/api_test.go @@ -3,22 +3,31 @@ package gkr import ( "fmt" "github.com/consensys/gnark-crypto/ecc" - bn254TestVectorUtils "github.com/consensys/gnark-crypto/ecc/bn254/fr/test_vector_utils" + "github.com/consensys/gnark-crypto/ecc/bn254/fr" + bn254MiMC "github.com/consensys/gnark-crypto/ecc/bn254/fr/mimc" "github.com/consensys/gnark/backend" "github.com/consensys/gnark/backend/groth16" "github.com/consensys/gnark/backend/witness" "github.com/consensys/gnark/constraint" + bn254r1cs "github.com/consensys/gnark/constraint/bn254" "github.com/consensys/gnark/frontend" "github.com/consensys/gnark/frontend/cs/r1cs" + stdHash "github.com/consensys/gnark/std/hash" + "github.com/consensys/gnark/std/hash/mimc" "github.com/consensys/gnark/std/utils/test_vectors_utils" "github.com/consensys/gnark/test" "github.com/stretchr/testify/assert" "hash" + "strconv" "testing" ) +//const msgCounterTemplate = "messageCounter{startState:%d, step:%d}" +//var msgCounterParams = messageCounter{} + type doubleNoDependencyCircuit struct { - X []frontend.Variable + X []frontend.Variable + hashName string } func (c *doubleNoDependencyCircuit) Define(api frontend.API) error { @@ -39,19 +48,31 @@ func (c *doubleNoDependencyCircuit) Define(api frontend.API) error { api.AssertIsEqual(Z[i], api.Mul(2, c.X[i])) } - return solution.Verify("mimc") + return solution.Verify(c.hashName) } func TestDoubleNoDependencyCircuit(t *testing.T) { - assignment := doubleNoDependencyCircuit{X: []frontend.Variable{1, 1}} - circuit := doubleNoDependencyCircuit{X: make([]frontend.Variable, 2)} - solve(t, &circuit, &assignment) - //test.NewAssert(t).SolvingSucceeded(&circuit, &assignment, test.WithBackends(backend.GROTH16), test.WithCurves(ecc.BN254)) + xValuess := [][]frontend.Variable{ + {1, 1}, + {1, 2}, + } + + hashes := []string{"-1", "-20"} + + for _, xValues := range xValuess { + for _, hashName := range hashes { + assignment := doubleNoDependencyCircuit{X: xValues} + circuit := doubleNoDependencyCircuit{X: make([]frontend.Variable, len(xValues)), hashName: hashName} + + solve(t, &circuit, &assignment) + } + } } type sqNoDependencyCircuit struct { - X []frontend.Variable + X []frontend.Variable + hashName string } func (c *sqNoDependencyCircuit) Define(api frontend.API) error { @@ -72,7 +93,7 @@ func (c *sqNoDependencyCircuit) Define(api frontend.API) error { api.AssertIsEqual(Z[i], api.Mul(c.X[i], c.X[i])) } - return solution.Verify("mimc") + return solution.Verify(c.hashName) } func TestSqNoDependencyCircuit(t *testing.T) { @@ -83,7 +104,8 @@ func TestSqNoDependencyCircuit(t *testing.T) { } type mulNoDependencyCircuit struct { - X, Y []frontend.Variable + X, Y []frontend.Variable + hashName string } func (c *mulNoDependencyCircuit) Define(api frontend.API) error { @@ -112,7 +134,7 @@ func (c *mulNoDependencyCircuit) Define(api frontend.API) error { api.AssertIsEqual(Z[i], api.Mul(c.X[i], c.Y[i])) } - return solution.Verify("mimc") + return solution.Verify(c.hashName) } func TestMulNoDependency(t *testing.T) { @@ -177,7 +199,7 @@ func TestSolveMulWithDependency(t *testing.T) { } circuit := mulWithDependencyCircuit{Y: make([]frontend.Variable, len(assignment.Y))} - test.NewAssert(t).SolvingSucceeded(&circuit, &assignment, test.WithBackends(backend.GROTH16), test.WithCurves(ecc.BN254)) + solve(t, &circuit, &assignment) } func TestApiMul(t *testing.T) { @@ -226,10 +248,6 @@ func (c *messageCounter) Reset() { c.state = c.startState } -func (c *messageCounter) ToStandard() hash.Hash { - return bn254TestVectorUtils.NewMessageCounter(c.startState, c.step) -} - func BenchmarkMiMCMerkleTree(b *testing.B) { depth := 3 bottom := make([]frontend.Variable, 1< Date: Thu, 19 Jan 2023 09:54:19 -0500 Subject: [PATCH 27/71] fix: race condition --- constraint/bn254/gkr.go | 16 +++++----------- std/gkr/api_test.go | 19 +++++++++++++++---- std/gkr/compile.go | 11 ++++++++++- 3 files changed, 30 insertions(+), 16 deletions(-) diff --git a/constraint/bn254/gkr.go b/constraint/bn254/gkr.go index bd44ed4f99..3b94a288d4 100644 --- a/constraint/bn254/gkr.go +++ b/constraint/bn254/gkr.go @@ -13,7 +13,6 @@ import ( "github.com/consensys/gnark/std/utils/algo_utils" "hash" "math/big" - "sync" ) type gkrSolvingData struct { @@ -153,7 +152,7 @@ func gkrSetOutputValues(circuit []constraint.GkrWire, assignments gkrAssignment, // Check if outsI == len(outs)? } -func gkrSolveHint(data constraint.GkrInfo, res *gkrSolvingData, solvingDone *sync.Mutex) hint.Function { +func gkrSolveHint(data constraint.GkrInfo, res *gkrSolvingData) hint.Function { return func(_ *big.Int, ins, outs []*big.Int) error { res.circuit = convertCircuit(data.Circuit) // TODO: Take this out of here into the proving module @@ -166,8 +165,6 @@ func gkrSolveHint(data constraint.GkrInfo, res *gkrSolvingData, solvingDone *syn fmt.Println("assignment ", sliceSliceToString(assignments)) fmt.Println("returning ", bigIntPtrSliceToString(outs)) - solvingDone.Unlock() - return nil } } @@ -199,17 +196,16 @@ func frToBigInts(dst []*big.Int, src []fr.Element) { } } -func gkrProveHint(hashName string, data *gkrSolvingData, solvingDone *sync.Mutex) hint.Function { +func gkrProveHint(hashName string, data *gkrSolvingData) hint.Function { return func(_ *big.Int, ins, outs []*big.Int) error { - insBytes := algo_utils.Map(ins, func(i *big.Int) []byte { + insBytes := algo_utils.Map(ins[1:], func(i *big.Int) []byte { // the first input is dummy, just to ensure the solver's work is done before the prover is called b := i.Bytes() return b[:] }) hsh := HashBuilderRegistry[hashName]() - solvingDone.Lock() proof, err := gkr.Prove(data.circuit, data.assignments, fiatshamir.WithHash(hsh, insBytes...), gkr.WithPool(&data.memoryPool)) // TODO: Do transcriptSettings properly if err != nil { return err @@ -239,10 +235,8 @@ func defineGkrHints(info constraint.GkrInfo, hintFunctions map[hint.ID]hint.Func res[k] = v } var gkrData gkrSolvingData - var solvingDone sync.Mutex // if the user manages challenges correctly, the solver will see the "prove" function as dependent on the "solve" function, but better not take chances - solvingDone.Lock() - res[info.SolveHintID] = gkrSolveHint(info, &gkrData, &solvingDone) - res[info.ProveHintID] = gkrProveHint(info.HashName, &gkrData, &solvingDone) + res[info.SolveHintID] = gkrSolveHint(info, &gkrData) + res[info.ProveHintID] = gkrProveHint(info.HashName, &gkrData) return res } diff --git a/std/gkr/api_test.go b/std/gkr/api_test.go index 858781cff3..55a7746aa7 100644 --- a/std/gkr/api_test.go +++ b/std/gkr/api_test.go @@ -97,10 +97,21 @@ func (c *sqNoDependencyCircuit) Define(api frontend.API) error { } func TestSqNoDependencyCircuit(t *testing.T) { - assignment := sqNoDependencyCircuit{X: []frontend.Variable{1, 1}} - circuit := sqNoDependencyCircuit{X: make([]frontend.Variable, 2)} - test.NewAssert(t).SolvingSucceeded(&circuit, &assignment, test.WithBackends(backend.GROTH16), test.WithCurves(ecc.BN254)) + xValuess := [][]frontend.Variable{ + {1, 1}, + {1, 2}, + } + + hashes := []string{"-1", "-20"} + + for _, xValues := range xValuess { + for _, hashName := range hashes { + assignment := sqNoDependencyCircuit{X: xValues} + circuit := sqNoDependencyCircuit{X: make([]frontend.Variable, len(xValues)), hashName: hashName} + solve(t, &circuit, &assignment) + } + } } type mulNoDependencyCircuit struct { @@ -404,7 +415,7 @@ func init() { //registerMessageCounter(0, 1) } -type constHashBn254 int +type constHashBn254 int // TODO @Tabaie move to gnark-crypto func (c constHashBn254) Write(p []byte) (int, error) { return len(p), nil diff --git a/std/gkr/compile.go b/std/gkr/compile.go index 74da70b789..0c3517042e 100644 --- a/std/gkr/compile.go +++ b/std/gkr/compile.go @@ -167,8 +167,17 @@ func (s Solution) Verify(hashName string, initialChallenges ...frontend.Variable forSnark := newCircuitDataForSnark(s.toStore, s.assignments) logNbInstances := log2(uint(s.assignments.NbInstances())) + hintIns := make([]frontend.Variable, len(initialChallenges)+1) // hack: adding one of the outputs of the solve hint to ensure "prove" is called after "solve" + for i, w := range s.toStore.Circuit { + if w.IsOutput() { + hintIns[0] = s.assignments[i][0] + break + } + } + copy(hintIns[1:], initialChallenges) + if proofSerialized, err = s.parentApi.Compiler().NewHint( - ProveHintPlaceholder, ProofSize(forSnark.circuit, logNbInstances), initialChallenges...); err != nil { + ProveHintPlaceholder, ProofSize(forSnark.circuit, logNbInstances), hintIns...); err != nil { return err } s.toStore.ProveHintID = hint.UUID(ProveHintPlaceholder) From e8ed9570d776396ce35420e15ef5c11293cf1ded Mon Sep 17 00:00:00 2001 From: Arya Tabaie Date: Thu, 19 Jan 2023 10:41:45 -0500 Subject: [PATCH 28/71] test: with dependency --- std/gkr/api_test.go | 41 ++++++++++++++++++++++++++++------------- 1 file changed, 28 insertions(+), 13 deletions(-) diff --git a/std/gkr/api_test.go b/std/gkr/api_test.go index 55a7746aa7..bf4916d06d 100644 --- a/std/gkr/api_test.go +++ b/std/gkr/api_test.go @@ -5,7 +5,6 @@ import ( "github.com/consensys/gnark-crypto/ecc" "github.com/consensys/gnark-crypto/ecc/bn254/fr" bn254MiMC "github.com/consensys/gnark-crypto/ecc/bn254/fr/mimc" - "github.com/consensys/gnark/backend" "github.com/consensys/gnark/backend/groth16" "github.com/consensys/gnark/backend/witness" "github.com/consensys/gnark/constraint" @@ -15,7 +14,6 @@ import ( stdHash "github.com/consensys/gnark/std/hash" "github.com/consensys/gnark/std/hash/mimc" "github.com/consensys/gnark/std/utils/test_vectors_utils" - "github.com/consensys/gnark/test" "github.com/stretchr/testify/assert" "hash" "strconv" @@ -149,20 +147,37 @@ func (c *mulNoDependencyCircuit) Define(api frontend.API) error { } func TestMulNoDependency(t *testing.T) { - assignment := mulNoDependencyCircuit{ - X: []frontend.Variable{1, 2}, - Y: []frontend.Variable{0, 3}, + xValuess := [][]frontend.Variable{ + {1, 2}, } - circuit := mulNoDependencyCircuit{ - X: make([]frontend.Variable, 2), - Y: make([]frontend.Variable, 2), + yValuess := [][]frontend.Variable{ + {0, 3}, + } + + hashes := []string{"-1", "-20"} + + for i := range xValuess { + for _, hashName := range hashes { + + assignment := mulNoDependencyCircuit{ + X: xValuess[i], + Y: yValuess[i], + } + circuit := mulNoDependencyCircuit{ + X: make([]frontend.Variable, len(xValuess[i])), + Y: make([]frontend.Variable, len(yValuess[i])), + hashName: hashName, + } + + solve(t, &circuit, &assignment) + } } - test.NewAssert(t).SolvingSucceeded(&circuit, &assignment, test.WithBackends(backend.GROTH16), test.WithCurves(ecc.BN254)) } type mulWithDependencyCircuit struct { - XLast frontend.Variable - Y []frontend.Variable + XLast frontend.Variable + Y []frontend.Variable + hashName string } func (c *mulWithDependencyCircuit) Define(api frontend.API) error { @@ -199,7 +214,7 @@ func (c *mulWithDependencyCircuit) Define(api frontend.API) error { for i := 0; i < lastI; i++ { api.AssertIsEqual(Z[i], api.Mul(Z[i+1], Y[i])) } - return nil + return solution.Verify(c.hashName) } func TestSolveMulWithDependency(t *testing.T) { @@ -208,7 +223,7 @@ func TestSolveMulWithDependency(t *testing.T) { XLast: 1, Y: []frontend.Variable{3, 2}, } - circuit := mulWithDependencyCircuit{Y: make([]frontend.Variable, len(assignment.Y))} + circuit := mulWithDependencyCircuit{Y: make([]frontend.Variable, len(assignment.Y)), hashName: "-20"} solve(t, &circuit, &assignment) } From 1fe140a39b7a103d6362afc25a263eac50896f68 Mon Sep 17 00:00:00 2001 From: Arya Tabaie Date: Thu, 19 Jan 2023 13:08:57 -0500 Subject: [PATCH 29/71] fix: small mimc test --- constraint/bn254/gkr.go | 20 ++++---- std/gkr/api_test.go | 101 +++++++++++----------------------------- 2 files changed, 36 insertions(+), 85 deletions(-) diff --git a/constraint/bn254/gkr.go b/constraint/bn254/gkr.go index 3b94a288d4..13d980efb3 100644 --- a/constraint/bn254/gkr.go +++ b/constraint/bn254/gkr.go @@ -21,12 +21,11 @@ type gkrSolvingData struct { memoryPool polynomial.Pool } -var gateRegistry = make(map[string]gkr.Gate) // TODO: Migrate to gnark-crypto +var GkrGateRegistry = make(map[string]gkr.Gate) // TODO: Migrate to gnark-crypto func init() { - gateRegistry["mul"] = mulGate(2) // in-built input count is problematic TODO fix - gateRegistry["add"] = addGate{} - //gateRegistry["mimc"] + GkrGateRegistry["mul"] = mulGate(2) // in-built input count is problematic TODO fix + GkrGateRegistry["add"] = addGate{} } type mulGate int @@ -77,7 +76,7 @@ func (g addGate) Degree() int { func convertCircuit(noPtr constraint.GkrCircuit) gkr.Circuit { resCircuit := make(gkr.Circuit, len(noPtr)) for i := range noPtr { - resCircuit[i].Gate = gateRegistry[noPtr[i].Gate] + resCircuit[i].Gate = GkrGateRegistry[noPtr[i].Gate] resCircuit[i].Inputs = algo_utils.Map(noPtr[i].Inputs, algo_utils.SlicePtrAt(resCircuit)) } return resCircuit @@ -169,12 +168,13 @@ func gkrSolveHint(data constraint.GkrInfo, res *gkrSolvingData) hint.Function { } } -func bigIntPtrSliceToString(slice []*big.Int) []int64 { - return algo_utils.Map(slice, func(e *big.Int) int64 { - if !e.IsInt64() { - panic("int too big") +func bigIntPtrSliceToString(slice []*big.Int) []interface{} { + return algo_utils.Map(slice, func(e *big.Int) interface{} { + if e.IsInt64() { + return e.Int64() + } else { + return e.Text(10) } - return e.Int64() }) } diff --git a/std/gkr/api_test.go b/std/gkr/api_test.go index bf4916d06d..95dcc38eb5 100644 --- a/std/gkr/api_test.go +++ b/std/gkr/api_test.go @@ -1,7 +1,6 @@ package gkr import ( - "fmt" "github.com/consensys/gnark-crypto/ecc" "github.com/consensys/gnark-crypto/ecc/bn254/fr" bn254MiMC "github.com/consensys/gnark-crypto/ecc/bn254/fr/mimc" @@ -20,9 +19,6 @@ import ( "testing" ) -//const msgCounterTemplate = "messageCounter{startState:%d, step:%d}" -//var msgCounterParams = messageCounter{} - type doubleNoDependencyCircuit struct { X []frontend.Variable hashName string @@ -242,40 +238,10 @@ func TestApiMul(t *testing.T) { assert.NoError(t, err) z = api.Mul(x, y).(constraint.GkrVariable) test_vector_utils.AssertSliceEqual(t, api.toStore.Circuit[z].Inputs, []int{int(x), int(y)}) // TODO: Find out why assert.Equal gives false positives ( []*Wire{x,x} as second argument passes when it shouldn't ) - - //unsorted := []*Wire{&api.toStore.circuit[0], &api.toStore.circuit[1], &api.toStore.circuit[2]} - //test_vector_utils.AssertSliceEqual(t, []*Wire{x, y, z}, unsorted) - - //sorted := topologicalSort(api.circuit) - - //test_vector_utils.AssertSliceEqual(t, sorted, []*Wire{x, y, z}) - - /*assert.Equal(t, x.nbUniqueOutputs, 1) - assert.Equal(t, y.nbUniqueOutputs, 1) - assert.Equal(t, z.nbUniqueOutputs, 0)*/ -} - -type messageCounter struct { - startState int - step int - state int -} - -func (c *messageCounter) Sum() frontend.Variable { - fmt.Println("snarkHash returning", c.state) - return c.state -} - -func (c *messageCounter) Write(data ...frontend.Variable) { - c.state += len(data) * c.step -} - -func (c *messageCounter) Reset() { - c.state = c.startState } func BenchmarkMiMCMerkleTree(b *testing.B) { - depth := 3 + depth := 2 bottom := make([]frontend.Variable, 1< Date: Thu, 19 Jan 2023 16:56:35 -0500 Subject: [PATCH 30/71] bench: gkr inefficient --- constraint/bn254/gkr.go | 23 +++--- std/fiat-shamir/transcript.go | 22 +++--- std/gkr/api_test.go | 144 +++++++++++++++++++++++++++++----- std/gkr/gkr_test.go | 18 +---- std/gkr/registry.go | 4 + 5 files changed, 152 insertions(+), 59 deletions(-) diff --git a/constraint/bn254/gkr.go b/constraint/bn254/gkr.go index 13d980efb3..e44df4e459 100644 --- a/constraint/bn254/gkr.go +++ b/constraint/bn254/gkr.go @@ -2,7 +2,6 @@ package cs import ( "encoding/json" - "fmt" "github.com/consensys/gnark-crypto/ecc/bn254/fr" "github.com/consensys/gnark-crypto/ecc/bn254/fr/gkr" "github.com/consensys/gnark-crypto/ecc/bn254/fr/polynomial" @@ -100,22 +99,22 @@ func gkrSolve(info constraint.GkrInfo, solvingData gkrSolvingData, assignmentVec } for instanceI := 0; instanceI < nbInstances; instanceI++ { - fmt.Println("instance", instanceI) + //fmt.Println("instance", instanceI) for wireI, wire := range circuit { - fmt.Print("\twire ", wireI, ": ") + //fmt.Print("\twire ", wireI, ": ") if wire.IsInput() { - fmt.Print("input.") + //fmt.Print("input.") if nbDepsResolved[wireI] < len(wire.Dependencies) && instanceI == wire.Dependencies[nbDepsResolved[wireI]].InputInstance { - fmt.Print(" copying value from dependency") + //fmt.Print(" copying value from dependency") dep := wire.Dependencies[nbDepsResolved[wireI]] assignments[wireI][instanceI].Set(&assignments[dep.OutputWire][dep.OutputInstance]) nbDepsResolved[wireI]++ } else { - fmt.Print(" taking value from input") + //fmt.Print(" taking value from input") assignments[wireI][instanceI].SetBigInt(assignmentVector[offsets[wireI]+instanceI-nbDepsResolved[wireI]]) } } else { - fmt.Print("gated.") + //fmt.Print("gated.") // assemble the inputs inputIndexes := info.Circuit[wireI].Inputs for i, inputI := range inputIndexes { @@ -124,7 +123,7 @@ func gkrSolve(info constraint.GkrInfo, solvingData gkrSolvingData, assignmentVec gate := solvingData.circuit[wireI].Gate assignments[wireI][instanceI] = gate.Evaluate(inputs[:len(inputIndexes)]...) } - fmt.Println("\n\t\tresult: ", assignments[wireI][instanceI].Text(10)) + //fmt.Println("\n\t\tresult: ", assignments[wireI][instanceI].Text(10)) } } return assignments @@ -154,15 +153,15 @@ func gkrSetOutputValues(circuit []constraint.GkrWire, assignments gkrAssignment, func gkrSolveHint(data constraint.GkrInfo, res *gkrSolvingData) hint.Function { return func(_ *big.Int, ins, outs []*big.Int) error { - res.circuit = convertCircuit(data.Circuit) // TODO: Take this out of here into the proving module - res.memoryPool = polynomial.NewPool(256, 1<<11) // TODO: Get clever with limits + res.circuit = convertCircuit(data.Circuit) // TODO: Take this out of here into the proving module + res.memoryPool = polynomial.NewPool(256, data.NbInstances) assignments := gkrSolve(data, *res, ins) res.assignments = toMapAssignment(res.circuit, assignments) gkrSetOutputValues(data.Circuit, assignments, outs) - fmt.Println("assignment ", sliceSliceToString(assignments)) - fmt.Println("returning ", bigIntPtrSliceToString(outs)) + //fmt.Println("assignment ", sliceSliceToString(assignments)) + //fmt.Println("returning ", bigIntPtrSliceToString(outs)) return nil } diff --git a/std/fiat-shamir/transcript.go b/std/fiat-shamir/transcript.go index c4447fde4a..ecdb295568 100644 --- a/std/fiat-shamir/transcript.go +++ b/std/fiat-shamir/transcript.go @@ -18,8 +18,6 @@ package fiatshamir import ( "errors" - "fmt" - "github.com/consensys/gnark/frontend" "github.com/consensys/gnark/std/hash" ) @@ -74,9 +72,9 @@ func NewTranscript(api frontend.API, h hash.Hash, challengesID ...string) Transc // binded to other values. func (t *Transcript) Bind(challengeID string, values []frontend.Variable) error { - toPrint := []frontend.Variable{"snark binding to ", challengeID, ":"} + /*toPrint := []frontend.Variable{"snark binding to ", challengeID, ":"} toPrint = append(toPrint, values...) - t.api.Println(toPrint...) + t.api.Println(toPrint...)*/ challenge, ok := t.challenges[challengeID] @@ -125,9 +123,9 @@ func (t *Transcript) ComputeChallenge(challengeID string) (frontend.Variable, er t.h.Write(t.previous.value) } - toPrint := []frontend.Variable{"snark bindings:"} + /*toPrint := []frontend.Variable{"snark bindings:"} toPrint = append(toPrint, challenge.bindings...) - t.api.Println(toPrint...) + t.api.Println(toPrint...)*/ // write the binded values in the order they were added t.h.Write(challenge.bindings...) @@ -140,12 +138,12 @@ func (t *Transcript) ComputeChallenge(challengeID string) (frontend.Variable, er t.challenges[challengeID] = challenge t.h.Reset() - - if valueInt, ok := challenge.value.(int); ok { - fmt.Printf("snark challenge \"%s\" <- %d\n", challengeID, valueInt) - } else { - t.api.Println("snark challenge \"", challengeID, "\" <- ", challenge.value) - } + /* + if valueInt, ok := challenge.value.(int); ok { + fmt.Printf("snark challenge \"%s\" <- %d\n", challengeID, valueInt) + } else { + t.api.Println("snark challenge \"", challengeID, "\" <- ", challenge.value) + }*/ return challenge.value, nil } diff --git a/std/gkr/api_test.go b/std/gkr/api_test.go index 95dcc38eb5..404c0f6f97 100644 --- a/std/gkr/api_test.go +++ b/std/gkr/api_test.go @@ -1,6 +1,7 @@ package gkr import ( + "fmt" "github.com/consensys/gnark-crypto/ecc" "github.com/consensys/gnark-crypto/ecc/bn254/fr" bn254MiMC "github.com/consensys/gnark-crypto/ecc/bn254/fr/mimc" @@ -240,37 +241,45 @@ func TestApiMul(t *testing.T) { test_vector_utils.AssertSliceEqual(t, api.toStore.Circuit[z].Inputs, []int{int(x), int(y)}) // TODO: Find out why assert.Equal gives false positives ( []*Wire{x,x} as second argument passes when it shouldn't ) } -func BenchmarkMiMCMerkleTree(b *testing.B) { - depth := 2 - bottom := make([]frontend.Variable, 1< Date: Fri, 20 Jan 2023 13:38:47 -0500 Subject: [PATCH 31/71] feat: support more operations --- constraint/bn254/gkr.go | 129 ++++++++++++++++++++++++---------------- std/gkr/api.go | 69 ++++++++------------- 2 files changed, 102 insertions(+), 96 deletions(-) diff --git a/constraint/bn254/gkr.go b/constraint/bn254/gkr.go index e44df4e459..7a88703397 100644 --- a/constraint/bn254/gkr.go +++ b/constraint/bn254/gkr.go @@ -20,58 +20,6 @@ type gkrSolvingData struct { memoryPool polynomial.Pool } -var GkrGateRegistry = make(map[string]gkr.Gate) // TODO: Migrate to gnark-crypto - -func init() { - GkrGateRegistry["mul"] = mulGate(2) // in-built input count is problematic TODO fix - GkrGateRegistry["add"] = addGate{} -} - -type mulGate int - -func (g mulGate) Evaluate(x ...fr.Element) (res fr.Element) { - if len(x) != int(g) { - panic("wrong input count") - } - switch len(x) { - case 0: - res.SetOne() - case 1: - res.Set(&x[0]) - default: - res.Mul(&x[0], &x[1]) - for i := 2; i < len(x); i++ { - res.Mul(&res, &x[2]) - } - } - return -} - -func (g mulGate) Degree() int { - return int(g) -} - -type addGate struct{} - -func (g addGate) Evaluate(x ...fr.Element) (res fr.Element) { - switch len(x) { - case 0: - // set zero - case 1: - res.Set(&x[0]) - case 2: - res.Add(&x[0], &x[1]) - for i := 2; i < len(x); i++ { - res.Add(&res, &x[2]) - } - } - return -} - -func (g addGate) Degree() int { - return 1 -} - func convertCircuit(noPtr constraint.GkrCircuit) gkr.Circuit { resCircuit := make(gkr.Circuit, len(noPtr)) for i := range noPtr { @@ -239,5 +187,82 @@ func defineGkrHints(info constraint.GkrInfo, hintFunctions map[hint.ID]hint.Func return res } +var GkrGateRegistry = map[string]gkr.Gate{ // TODO: Migrate to gnark-crypto + "mul": mulGate(2), + "add": addGate{}, + "sub": subGate{}, + "neg": negGate{}, +} + // TODO: Move to gnark-crypto var HashBuilderRegistry = make(map[string]func() hash.Hash) + +type mulGate int +type addGate struct{} +type subGate struct{} +type negGate struct{} + +func (g mulGate) Evaluate(x ...fr.Element) (res fr.Element) { + if len(x) != int(g) { + panic("wrong input count") + } + switch len(x) { + case 0: + res.SetOne() + case 1: + res.Set(&x[0]) + default: + res.Mul(&x[0], &x[1]) + for i := 2; i < len(x); i++ { + res.Mul(&res, &x[2]) + } + } + return +} + +func (g mulGate) Degree() int { + return int(g) +} + +func (g addGate) Evaluate(x ...fr.Element) (res fr.Element) { + switch len(x) { + case 0: + // set zero + case 1: + res.Set(&x[0]) + case 2: + res.Add(&x[0], &x[1]) + for i := 2; i < len(x); i++ { + res.Add(&res, &x[2]) + } + } + return +} + +func (g addGate) Degree() int { + return 1 +} + +func (g *subGate) Evaluate(element ...fr.Element) (diff fr.Element) { + if len(element) > 2 { + panic("not implemented") //TODO + } + diff.Sub(&element[0], &element[1]) + return +} + +func (g *subGate) Degree() int { + return 1 +} + +func (g *negGate) Evaluate(element ...fr.Element) (neg fr.Element) { + if len(element) != 1 { + panic("univariate gate") + } + neg.Neg(&element[0]) + return +} + +func (g *negGate) Degree() int { + return 1 +} diff --git a/std/gkr/api.go b/std/gkr/api.go index eb9a224ad2..2bb88bc5fc 100644 --- a/std/gkr/api.go +++ b/std/gkr/api.go @@ -36,13 +36,11 @@ func (api *API) Add(i1, i2 frontend.Variable, in ...frontend.Variable) frontend. } func (api *API) Neg(i1 frontend.Variable) frontend.Variable { - //TODO implement me - panic("implement me") + return api.newNonInputVariable("neg", []frontend.Variable{i1}) } func (api *API) Sub(i1, i2 frontend.Variable, in ...frontend.Variable) frontend.Variable { - //TODO implement me - panic("implement me") + return api.newVar2PlusIn("sub", i1, i2, in...) } func (api *API) Mul(i1, i2 frontend.Variable, in ...frontend.Variable) frontend.Variable { @@ -50,101 +48,84 @@ func (api *API) Mul(i1, i2 frontend.Variable, in ...frontend.Variable) frontend. } func (api *API) DivUnchecked(i1, i2 frontend.Variable) frontend.Variable { - //TODO implement me - panic("implement me") + panic("not implemented") } func (api *API) Div(i1, i2 frontend.Variable) frontend.Variable { - //TODO implement me - panic("implement me") + panic("not implemented") } +// TODO: This will require some sophistication. The resulting variable will be considered input by the prover but not by the solver func (api *API) Inverse(i1 frontend.Variable) frontend.Variable { - //TODO implement me - panic("implement me") + panic("not implemented") } func (api *API) ToBinary(i1 frontend.Variable, n ...int) []frontend.Variable { - //TODO implement me - panic("implement me") + panic("not implemented") } func (api *API) FromBinary(b ...frontend.Variable) frontend.Variable { - //TODO implement me - panic("implement me") + panic("not implemented") } func (api *API) Xor(a, b frontend.Variable) frontend.Variable { - //TODO implement me - panic("implement me") + panic("not implemented") } func (api *API) Or(a, b frontend.Variable) frontend.Variable { - //TODO implement me - panic("implement me") + panic("not implemented") } func (api *API) And(a, b frontend.Variable) frontend.Variable { - //TODO implement me - panic("implement me") + panic("not implemented") } func (api *API) Select(b frontend.Variable, i1, i2 frontend.Variable) frontend.Variable { - //TODO implement me - panic("implement me") + panic("not implemented") } func (api *API) Lookup2(b0, b1 frontend.Variable, i0, i1, i2, i3 frontend.Variable) frontend.Variable { - //TODO implement me - panic("implement me") + panic("not implemented") } func (api *API) IsZero(i1 frontend.Variable) frontend.Variable { - //TODO implement me - panic("implement me") + panic("not implemented") } func (api *API) Cmp(i1, i2 frontend.Variable) frontend.Variable { - //TODO implement me - panic("implement me") + panic("not implemented") } func (api *API) AssertIsEqual(i1, i2 frontend.Variable) { - //TODO implement me - panic("implement me") + panic("not implemented") } func (api *API) AssertIsDifferent(i1, i2 frontend.Variable) { - //TODO implement me - panic("implement me") + panic("not implemented") } func (api *API) AssertIsBoolean(i1 frontend.Variable) { - //TODO implement me - panic("implement me") + panic("not implemented") } func (api *API) AssertIsLessOrEqual(v frontend.Variable, bound frontend.Variable) { - //TODO implement me - panic("implement me") + panic("not implemented") } +// TODO: This can be important. func (api *API) Println(a ...frontend.Variable) { - //TODO implement me - panic("implement me") + panic("not implemented") } +// This is definitely out of scope. TODO: A CircuitBuilder API that doesn't have to implement this and can be passed on to gadgets func (api *API) Compiler() frontend.Compiler { - //TODO implement me - panic("implement me") + panic("not implemented") } func (api *API) NewHint(f hint.Function, nbOutputs int, inputs ...frontend.Variable) ([]frontend.Variable, error) { - //TODO implement me - panic("implement me") + panic("not implemented") } func (api *API) ConstantValue(v frontend.Variable) (*big.Int, bool) { - //TODO implement me - panic("implement me") + panic("not implemented") } From 7f494a2178e1c3f9aed268eda7447329d9ed41d7 Mon Sep 17 00:00:00 2001 From: Arya Tabaie Date: Fri, 20 Jan 2023 13:54:34 -0500 Subject: [PATCH 32/71] fix: minor stuff, some code generation --- constraint/bn254/gkr.go | 8 ++++---- .../backend/template/representations/r1cs.go.tmpl | 6 ++++-- std/hash/hash.go | 4 +--- std/hash/mimc/mimc.go | 11 ----------- std/sumcheck/sumcheck.go | 1 - std/utils/test_vectors_utils/test_vector_utils.go | 5 ----- 6 files changed, 9 insertions(+), 26 deletions(-) diff --git a/constraint/bn254/gkr.go b/constraint/bn254/gkr.go index 7a88703397..a1fde9c363 100644 --- a/constraint/bn254/gkr.go +++ b/constraint/bn254/gkr.go @@ -243,7 +243,7 @@ func (g addGate) Degree() int { return 1 } -func (g *subGate) Evaluate(element ...fr.Element) (diff fr.Element) { +func (g subGate) Evaluate(element ...fr.Element) (diff fr.Element) { if len(element) > 2 { panic("not implemented") //TODO } @@ -251,11 +251,11 @@ func (g *subGate) Evaluate(element ...fr.Element) (diff fr.Element) { return } -func (g *subGate) Degree() int { +func (g subGate) Degree() int { return 1 } -func (g *negGate) Evaluate(element ...fr.Element) (neg fr.Element) { +func (g negGate) Evaluate(element ...fr.Element) (neg fr.Element) { if len(element) != 1 { panic("univariate gate") } @@ -263,6 +263,6 @@ func (g *negGate) Evaluate(element ...fr.Element) (neg fr.Element) { return } -func (g *negGate) Degree() int { +func (g negGate) Degree() int { return 1 } diff --git a/internal/generator/backend/template/representations/r1cs.go.tmpl b/internal/generator/backend/template/representations/r1cs.go.tmpl index 33c9a23a6b..8d2a854f72 100644 --- a/internal/generator/backend/template/representations/r1cs.go.tmpl +++ b/internal/generator/backend/template/representations/r1cs.go.tmpl @@ -63,9 +63,11 @@ func (cs *R1CS) AddConstraint(r1c constraint.R1C, debugInfo ...constraint.DebugI func (cs *R1CS) Solve(witness, a, b, c []fr.Element, opt backend.ProverConfig) ([]fr.Element, error) { log := logger.Logger().With().Int("nbConstraints", len(cs.Constraints)).Str("backend", "groth16").Logger() - nbWires := len(cs.Public) + len(cs.Secret) + cs.NbInternalVariables - solution, err := newSolution(nbWires, opt.HintFunctions, cs.MHintsDependencies, cs.MHints, cs.Coefficients) + + hintFunctions := defineGkrHints(cs.GkrInfo, opt.HintFunctions) + solution, err := newSolution(nbWires, hintFunctions, cs.MHintsDependencies, cs.MHints, cs.Coefficients) + if err != nil { return make([]fr.Element, nbWires), err } diff --git a/std/hash/hash.go b/std/hash/hash.go index da81cadd86..141d0fcf18 100644 --- a/std/hash/hash.go +++ b/std/hash/hash.go @@ -17,9 +17,7 @@ limitations under the License. // Package hash provides an interface that hash functions (as gadget) should implement. package hash -import ( - "github.com/consensys/gnark/frontend" -) +import "github.com/consensys/gnark/frontend" type Hash interface { diff --git a/std/hash/mimc/mimc.go b/std/hash/mimc/mimc.go index d70e22a414..1a1dcc44db 100644 --- a/std/hash/mimc/mimc.go +++ b/std/hash/mimc/mimc.go @@ -19,8 +19,6 @@ package mimc import ( "errors" - bn254 "github.com/consensys/gnark-crypto/ecc/bn254/fr/mimc" - "hash" "math/big" "github.com/consensys/gnark-crypto/ecc" @@ -74,12 +72,3 @@ func (h *MiMC) Sum() frontend.Variable { return h.h } - -func (h *MiMC) ToStandard() hash.Hash { - switch h.id { - // TODO: Take the parameters into account? - case ecc.BN254: - return bn254.NewMiMC() - } - panic("not implemented") -} diff --git a/std/sumcheck/sumcheck.go b/std/sumcheck/sumcheck.go index 768f044784..e002dfc489 100644 --- a/std/sumcheck/sumcheck.go +++ b/std/sumcheck/sumcheck.go @@ -46,7 +46,6 @@ func setupTranscript(api frontend.API, claimsNum int, varsNum int, settings *fia func next(transcript *fiatshamir.Transcript, bindings []frontend.Variable, remainingChallengeNames *[]string) (frontend.Variable, error) { challengeName := (*remainingChallengeNames)[0] - if err := transcript.Bind(challengeName, bindings); err != nil { return nil, err } diff --git a/std/utils/test_vectors_utils/test_vector_utils.go b/std/utils/test_vectors_utils/test_vector_utils.go index 3c5a0013dc..2f5dbc4a38 100644 --- a/std/utils/test_vectors_utils/test_vector_utils.go +++ b/std/utils/test_vectors_utils/test_vector_utils.go @@ -4,7 +4,6 @@ import ( "encoding/json" "github.com/consensys/gnark/frontend" "github.com/stretchr/testify/assert" - "hash" "os" "path/filepath" "strconv" @@ -218,10 +217,6 @@ type MapHash struct { stateValid bool } -func (m *MapHash) ToStandard() hash.Hash { - panic("not implemented") -} - func (m *MapHash) Sum() frontend.Variable { return m.state } From 0792b1efe47b8c75f67eb2a1833bf7400ff6785e Mon Sep 17 00:00:00 2001 From: Arya Tabaie Date: Fri, 20 Jan 2023 14:08:03 -0500 Subject: [PATCH 33/71] feat: codegen --- constraint/bls12-377/r1cs.go | 5 +- constraint/bls12-381/r1cs.go | 5 +- constraint/bls24-315/r1cs.go | 5 +- constraint/bls24-317/r1cs.go | 5 +- constraint/bn254/r1cs.go | 3 +- constraint/bn254/solution.go | 2 +- constraint/bw6-633/r1cs.go | 5 +- constraint/bw6-761/r1cs.go | 5 +- constraint/tinyfield/r1cs.go | 5 +- internal/generator/backend/main.go | 1 + .../backend/template/imports.go.tmpl | 4 + .../template/representations/gkr.go.tmpl | 268 ++++++++++++++++++ std/utils/algo_utils/algo_utils_test.go | 2 +- 13 files changed, 305 insertions(+), 10 deletions(-) create mode 100644 internal/generator/backend/template/representations/gkr.go.tmpl diff --git a/constraint/bls12-377/r1cs.go b/constraint/bls12-377/r1cs.go index 3357975725..728a5f68fb 100644 --- a/constraint/bls12-377/r1cs.go +++ b/constraint/bls12-377/r1cs.go @@ -80,7 +80,10 @@ func (cs *R1CS) Solve(witness, a, b, c []fr.Element, opt backend.ProverConfig) ( log := logger.Logger().With().Int("nbConstraints", len(cs.Constraints)).Str("backend", "groth16").Logger() nbWires := len(cs.Public) + len(cs.Secret) + cs.NbInternalVariables - solution, err := newSolution(nbWires, opt.HintFunctions, cs.MHintsDependencies, cs.MHints, cs.Coefficients) + + hintFunctions := defineGkrHints(cs.GkrInfo, opt.HintFunctions) + solution, err := newSolution(nbWires, hintFunctions, cs.MHintsDependencies, cs.MHints, cs.Coefficients) + if err != nil { return make([]fr.Element, nbWires), err } diff --git a/constraint/bls12-381/r1cs.go b/constraint/bls12-381/r1cs.go index 17493f798a..2b161cba62 100644 --- a/constraint/bls12-381/r1cs.go +++ b/constraint/bls12-381/r1cs.go @@ -80,7 +80,10 @@ func (cs *R1CS) Solve(witness, a, b, c []fr.Element, opt backend.ProverConfig) ( log := logger.Logger().With().Int("nbConstraints", len(cs.Constraints)).Str("backend", "groth16").Logger() nbWires := len(cs.Public) + len(cs.Secret) + cs.NbInternalVariables - solution, err := newSolution(nbWires, opt.HintFunctions, cs.MHintsDependencies, cs.MHints, cs.Coefficients) + + hintFunctions := defineGkrHints(cs.GkrInfo, opt.HintFunctions) + solution, err := newSolution(nbWires, hintFunctions, cs.MHintsDependencies, cs.MHints, cs.Coefficients) + if err != nil { return make([]fr.Element, nbWires), err } diff --git a/constraint/bls24-315/r1cs.go b/constraint/bls24-315/r1cs.go index 93de6f9fde..a3b7a7a57c 100644 --- a/constraint/bls24-315/r1cs.go +++ b/constraint/bls24-315/r1cs.go @@ -80,7 +80,10 @@ func (cs *R1CS) Solve(witness, a, b, c []fr.Element, opt backend.ProverConfig) ( log := logger.Logger().With().Int("nbConstraints", len(cs.Constraints)).Str("backend", "groth16").Logger() nbWires := len(cs.Public) + len(cs.Secret) + cs.NbInternalVariables - solution, err := newSolution(nbWires, opt.HintFunctions, cs.MHintsDependencies, cs.MHints, cs.Coefficients) + + hintFunctions := defineGkrHints(cs.GkrInfo, opt.HintFunctions) + solution, err := newSolution(nbWires, hintFunctions, cs.MHintsDependencies, cs.MHints, cs.Coefficients) + if err != nil { return make([]fr.Element, nbWires), err } diff --git a/constraint/bls24-317/r1cs.go b/constraint/bls24-317/r1cs.go index 8286c96219..6768e6a4da 100644 --- a/constraint/bls24-317/r1cs.go +++ b/constraint/bls24-317/r1cs.go @@ -80,7 +80,10 @@ func (cs *R1CS) Solve(witness, a, b, c []fr.Element, opt backend.ProverConfig) ( log := logger.Logger().With().Int("nbConstraints", len(cs.Constraints)).Str("backend", "groth16").Logger() nbWires := len(cs.Public) + len(cs.Secret) + cs.NbInternalVariables - solution, err := newSolution(nbWires, opt.HintFunctions, cs.MHintsDependencies, cs.MHints, cs.Coefficients) + + hintFunctions := defineGkrHints(cs.GkrInfo, opt.HintFunctions) + solution, err := newSolution(nbWires, hintFunctions, cs.MHintsDependencies, cs.MHints, cs.Coefficients) + if err != nil { return make([]fr.Element, nbWires), err } diff --git a/constraint/bn254/r1cs.go b/constraint/bn254/r1cs.go index 5e29b3300c..eddf1cf349 100644 --- a/constraint/bn254/r1cs.go +++ b/constraint/bn254/r1cs.go @@ -80,9 +80,10 @@ func (cs *R1CS) Solve(witness, a, b, c []fr.Element, opt backend.ProverConfig) ( log := logger.Logger().With().Int("nbConstraints", len(cs.Constraints)).Str("backend", "groth16").Logger() nbWires := len(cs.Public) + len(cs.Secret) + cs.NbInternalVariables - hintFunctions := defineGkrHints(cs.GkrInfo, opt.HintFunctions) + hintFunctions := defineGkrHints(cs.GkrInfo, opt.HintFunctions) solution, err := newSolution(nbWires, hintFunctions, cs.MHintsDependencies, cs.MHints, cs.Coefficients) + if err != nil { return make([]fr.Element, nbWires), err } diff --git a/constraint/bn254/solution.go b/constraint/bn254/solution.go index 5ad3690e98..e9c69b49c3 100644 --- a/constraint/bn254/solution.go +++ b/constraint/bn254/solution.go @@ -52,7 +52,7 @@ func newSolution(nbWires int, hintFunctions map[hint.ID]hint.Function, hintsDepe // hintsDependencies is from compile time; it contains the list of hints the solver **needs** var missing []string for hintUUID, hintID := range hintsDependencies { - if _, ok := hintFunctions[hintUUID]; !ok { + if _, ok := s.mHintsFunctions[hintUUID]; !ok { missing = append(missing, hintID) } } diff --git a/constraint/bw6-633/r1cs.go b/constraint/bw6-633/r1cs.go index df72f55d0d..b6e7ca0e77 100644 --- a/constraint/bw6-633/r1cs.go +++ b/constraint/bw6-633/r1cs.go @@ -80,7 +80,10 @@ func (cs *R1CS) Solve(witness, a, b, c []fr.Element, opt backend.ProverConfig) ( log := logger.Logger().With().Int("nbConstraints", len(cs.Constraints)).Str("backend", "groth16").Logger() nbWires := len(cs.Public) + len(cs.Secret) + cs.NbInternalVariables - solution, err := newSolution(nbWires, opt.HintFunctions, cs.MHintsDependencies, cs.MHints, cs.Coefficients) + + hintFunctions := defineGkrHints(cs.GkrInfo, opt.HintFunctions) + solution, err := newSolution(nbWires, hintFunctions, cs.MHintsDependencies, cs.MHints, cs.Coefficients) + if err != nil { return make([]fr.Element, nbWires), err } diff --git a/constraint/bw6-761/r1cs.go b/constraint/bw6-761/r1cs.go index d190f1c87c..e8b03a24f5 100644 --- a/constraint/bw6-761/r1cs.go +++ b/constraint/bw6-761/r1cs.go @@ -80,7 +80,10 @@ func (cs *R1CS) Solve(witness, a, b, c []fr.Element, opt backend.ProverConfig) ( log := logger.Logger().With().Int("nbConstraints", len(cs.Constraints)).Str("backend", "groth16").Logger() nbWires := len(cs.Public) + len(cs.Secret) + cs.NbInternalVariables - solution, err := newSolution(nbWires, opt.HintFunctions, cs.MHintsDependencies, cs.MHints, cs.Coefficients) + + hintFunctions := defineGkrHints(cs.GkrInfo, opt.HintFunctions) + solution, err := newSolution(nbWires, hintFunctions, cs.MHintsDependencies, cs.MHints, cs.Coefficients) + if err != nil { return make([]fr.Element, nbWires), err } diff --git a/constraint/tinyfield/r1cs.go b/constraint/tinyfield/r1cs.go index 708c277d7f..221c01f8a2 100644 --- a/constraint/tinyfield/r1cs.go +++ b/constraint/tinyfield/r1cs.go @@ -80,7 +80,10 @@ func (cs *R1CS) Solve(witness, a, b, c []fr.Element, opt backend.ProverConfig) ( log := logger.Logger().With().Int("nbConstraints", len(cs.Constraints)).Str("backend", "groth16").Logger() nbWires := len(cs.Public) + len(cs.Secret) + cs.NbInternalVariables - solution, err := newSolution(nbWires, opt.HintFunctions, cs.MHintsDependencies, cs.MHints, cs.Coefficients) + + hintFunctions := defineGkrHints(cs.GkrInfo, opt.HintFunctions) + solution, err := newSolution(nbWires, hintFunctions, cs.MHintsDependencies, cs.MHints, cs.Coefficients) + if err != nil { return make([]fr.Element, nbWires), err } diff --git a/internal/generator/backend/main.go b/internal/generator/backend/main.go index 66bee4544c..64224cea5b 100644 --- a/internal/generator/backend/main.go +++ b/internal/generator/backend/main.go @@ -108,6 +108,7 @@ func main() { {File: filepath.Join(csDir, "coeff.go"), Templates: []string{"coeff.go.tmpl", importCurve}}, {File: filepath.Join(csDir, "r1cs_sparse.go"), Templates: []string{"r1cs.sparse.go.tmpl", importCurve}}, {File: filepath.Join(csDir, "solution.go"), Templates: []string{"solution.go.tmpl", importCurve}}, + {File: filepath.Join(csDir, "gkr.go"), Templates: []string{"gkr.go.tmpl", importCurve}}, } if err := bgen.Generate(d, "cs", "./template/representations/", entries...); err != nil { panic(err) diff --git a/internal/generator/backend/template/imports.go.tmpl b/internal/generator/backend/template/imports.go.tmpl index 09352cb941..56639bdfb2 100644 --- a/internal/generator/backend/template/imports.go.tmpl +++ b/internal/generator/backend/template/imports.go.tmpl @@ -56,4 +56,8 @@ {{- define "import_pedersen"}} "github.com/consensys/gnark-crypto/ecc/{{ toLower .Curve }}/fr/pedersen" +{{- end}} + +{{- define "import_gkr"}} + "github.com/consensys/gnark-crypto/ecc/{{ toLower .Curve }}/fr/gkr" {{- end}} \ No newline at end of file diff --git a/internal/generator/backend/template/representations/gkr.go.tmpl b/internal/generator/backend/template/representations/gkr.go.tmpl new file mode 100644 index 0000000000..258ae615bc --- /dev/null +++ b/internal/generator/backend/template/representations/gkr.go.tmpl @@ -0,0 +1,268 @@ +package cs + +import ( + "encoding/json" + {{template "import_fr" .}} + {{template "import_gkr" .}} + {{template "import_polynomial" .}} + "github.com/consensys/gnark-crypto/ecc/{{ toLower .Curve }}/fr/test_vector_utils" // TODO: Seems a bit dubious to use this here. Decide if okay + fiatshamir "github.com/consensys/gnark-crypto/fiat-shamir" + "github.com/consensys/gnark/backend/hint" + "github.com/consensys/gnark/constraint" + "github.com/consensys/gnark/std/utils/algo_utils" + "hash" + "math/big" +) + +type gkrSolvingData struct { + assignments gkr.WireAssignment + circuit gkr.Circuit + memoryPool polynomial.Pool +} + +func convertCircuit(noPtr constraint.GkrCircuit) gkr.Circuit { + resCircuit := make(gkr.Circuit, len(noPtr)) + for i := range noPtr { + resCircuit[i].Gate = GkrGateRegistry[noPtr[i].Gate] + resCircuit[i].Inputs = algo_utils.Map(noPtr[i].Inputs, algo_utils.SlicePtrAt(resCircuit)) + } + return resCircuit +} + +// this module assumes that wire and instance indexes respect dependencies + +type gkrAssignment [][]fr.Element //gkrAssignment is indexed wire first, instance second + +// assumes assignmentVector is arranged wire first, instance second in order of solution +func gkrSolve(info constraint.GkrInfo, solvingData gkrSolvingData, assignmentVector []*big.Int) gkrAssignment { + circuit := info.Circuit + nbInstances := info.NbInstances + offsets := info.AssignmentOffsets() + nbDepsResolved := make([]int, len(circuit)) + inputs := make([]fr.Element, info.MaxNIns) + + assignments := make(gkrAssignment, len(circuit)) + for i := range assignments { + assignments[i] = make([]fr.Element, nbInstances) + } + + for instanceI := 0; instanceI < nbInstances; instanceI++ { + //fmt.Println("instance", instanceI) + for wireI, wire := range circuit { + //fmt.Print("\twire ", wireI, ": ") + if wire.IsInput() { + //fmt.Print("input.") + if nbDepsResolved[wireI] < len(wire.Dependencies) && instanceI == wire.Dependencies[nbDepsResolved[wireI]].InputInstance { + //fmt.Print(" copying value from dependency") + dep := wire.Dependencies[nbDepsResolved[wireI]] + assignments[wireI][instanceI].Set(&assignments[dep.OutputWire][dep.OutputInstance]) + nbDepsResolved[wireI]++ + } else { + //fmt.Print(" taking value from input") + assignments[wireI][instanceI].SetBigInt(assignmentVector[offsets[wireI]+instanceI-nbDepsResolved[wireI]]) + } + } else { + //fmt.Print("gated.") + // assemble the inputs + inputIndexes := info.Circuit[wireI].Inputs + for i, inputI := range inputIndexes { + inputs[i].Set(&assignments[inputI][instanceI]) + } + gate := solvingData.circuit[wireI].Gate + assignments[wireI][instanceI] = gate.Evaluate(inputs[:len(inputIndexes)]...) + } + //fmt.Println("\n\t\tresult: ", assignments[wireI][instanceI].Text(10)) + } + } + return assignments +} + +func toMapAssignment(circuit gkr.Circuit, assignment gkrAssignment) gkr.WireAssignment { + res := make(gkr.WireAssignment, len(circuit)) + for i := range circuit { + res[&circuit[i]] = assignment[i] + } + return res +} + +func gkrSetOutputValues(circuit []constraint.GkrWire, assignments gkrAssignment, outs []*big.Int) { + outsI := 0 + for i := range circuit { + if circuit[i].IsOutput() { + for j := range assignments[i] { + assignments[i][j].BigInt(outs[outsI]) + outsI++ + } + } + } + // Check if outsI == len(outs)? +} + +func gkrSolveHint(data constraint.GkrInfo, res *gkrSolvingData) hint.Function { + return func(_ *big.Int, ins, outs []*big.Int) error { + + res.circuit = convertCircuit(data.Circuit) // TODO: Take this out of here into the proving module + res.memoryPool = polynomial.NewPool(256, data.NbInstances) + + assignments := gkrSolve(data, *res, ins) + res.assignments = toMapAssignment(res.circuit, assignments) + gkrSetOutputValues(data.Circuit, assignments, outs) + + //fmt.Println("assignment ", sliceSliceToString(assignments)) + //fmt.Println("returning ", bigIntPtrSliceToString(outs)) + + return nil + } +} + +func bigIntPtrSliceToString(slice []*big.Int) []interface{} { + return algo_utils.Map(slice, func(e *big.Int) interface{} { + if e.IsInt64() { + return e.Int64() + } else { + return e.Text(10) + } + }) +} + +func sliceSliceToString(slice [][]fr.Element) string { + printable := make([]interface{}, len(slice)) + for i, s := range slice { + printable[i] = test_vector_utils.ElementSliceToInterfaceSlice(s) + } + res, err := json.Marshal(printable) + if err != nil { + panic(err.Error()) + } + return string(res) +} + +func frToBigInts(dst []*big.Int, src []fr.Element) { + for i := range src { + src[i].BigInt(dst[i]) + } +} + +func gkrProveHint(hashName string, data *gkrSolvingData) hint.Function { + + return func(_ *big.Int, ins, outs []*big.Int) error { + insBytes := algo_utils.Map(ins[1:], func(i *big.Int) []byte { // the first input is dummy, just to ensure the solver's work is done before the prover is called + b := i.Bytes() + return b[:] + }) + + hsh := HashBuilderRegistry[hashName]() + + proof, err := gkr.Prove(data.circuit, data.assignments, fiatshamir.WithHash(hsh, insBytes...), gkr.WithPool(&data.memoryPool)) // TODO: Do transcriptSettings properly + if err != nil { + return err + } + + // serialize proof: TODO: In gnark-crypto? + offset := 0 + for i := range proof { + for _, poly := range proof[i].PartialSumPolys { + frToBigInts(outs[offset:], poly) + offset += len(poly) + } + if proof[i].FinalEvalProof != nil { + finalEvalProof := proof[i].FinalEvalProof.([]fr.Element) + frToBigInts(outs[offset:], finalEvalProof) + offset += len(finalEvalProof) + } + } + return nil + + } +} + +func defineGkrHints(info constraint.GkrInfo, hintFunctions map[hint.ID]hint.Function) map[hint.ID]hint.Function { + res := make(map[hint.ID]hint.Function, len(hintFunctions)+2) + for k, v := range hintFunctions { + res[k] = v + } + var gkrData gkrSolvingData + res[info.SolveHintID] = gkrSolveHint(info, &gkrData) + res[info.ProveHintID] = gkrProveHint(info.HashName, &gkrData) + return res +} + +var GkrGateRegistry = map[string]gkr.Gate{ // TODO: Migrate to gnark-crypto + "mul": mulGate(2), + "add": addGate{}, + "sub": subGate{}, + "neg": negGate{}, +} + +// TODO: Move to gnark-crypto +var HashBuilderRegistry = make(map[string]func() hash.Hash) + +type mulGate int +type addGate struct{} +type subGate struct{} +type negGate struct{} + +func (g mulGate) Evaluate(x ...fr.Element) (res fr.Element) { + if len(x) != int(g) { + panic("wrong input count") + } + switch len(x) { + case 0: + res.SetOne() + case 1: + res.Set(&x[0]) + default: + res.Mul(&x[0], &x[1]) + for i := 2; i < len(x); i++ { + res.Mul(&res, &x[2]) + } + } + return +} + +func (g mulGate) Degree() int { + return int(g) +} + +func (g addGate) Evaluate(x ...fr.Element) (res fr.Element) { + switch len(x) { + case 0: + // set zero + case 1: + res.Set(&x[0]) + case 2: + res.Add(&x[0], &x[1]) + for i := 2; i < len(x); i++ { + res.Add(&res, &x[2]) + } + } + return +} + +func (g addGate) Degree() int { + return 1 +} + +func (g subGate) Evaluate(element ...fr.Element) (diff fr.Element) { + if len(element) > 2 { + panic("not implemented") //TODO + } + diff.Sub(&element[0], &element[1]) + return +} + +func (g subGate) Degree() int { + return 1 +} + +func (g negGate) Evaluate(element ...fr.Element) (neg fr.Element) { + if len(element) != 1 { + panic("univariate gate") + } + neg.Neg(&element[0]) + return +} + +func (g negGate) Degree() int { + return 1 +} diff --git a/std/utils/algo_utils/algo_utils_test.go b/std/utils/algo_utils/algo_utils_test.go index cf8bf4a81d..85ab4bf294 100644 --- a/std/utils/algo_utils/algo_utils_test.go +++ b/std/utils/algo_utils/algo_utils_test.go @@ -66,4 +66,4 @@ func TestPermute(t *testing.T) { Permute(list, permutation) assert.Equal(t, []int{65, 23, 34, 5, 2}, list) assert.Equal(t, permutationCopy, permutation) -} \ No newline at end of file +} From 7f995aeda5f49377335c6acb91eb433d34d59f93 Mon Sep 17 00:00:00 2001 From: Arya Tabaie Date: Fri, 20 Jan 2023 14:09:31 -0500 Subject: [PATCH 34/71] feat: yet more codegen --- constraint/bls12-377/gkr.go | 284 ++++++++++++++++++ constraint/bls12-381/gkr.go | 284 ++++++++++++++++++ constraint/bls24-315/gkr.go | 284 ++++++++++++++++++ constraint/bls24-317/gkr.go | 284 ++++++++++++++++++ constraint/bn254/gkr.go | 18 +- constraint/bw6-633/gkr.go | 284 ++++++++++++++++++ constraint/bw6-761/gkr.go | 284 ++++++++++++++++++ constraint/tinyfield/gkr.go | 284 ++++++++++++++++++ .../template/representations/gkr.go.tmpl | 8 +- 9 files changed, 2008 insertions(+), 6 deletions(-) create mode 100644 constraint/bls12-377/gkr.go create mode 100644 constraint/bls12-381/gkr.go create mode 100644 constraint/bls24-315/gkr.go create mode 100644 constraint/bls24-317/gkr.go create mode 100644 constraint/bw6-633/gkr.go create mode 100644 constraint/bw6-761/gkr.go create mode 100644 constraint/tinyfield/gkr.go diff --git a/constraint/bls12-377/gkr.go b/constraint/bls12-377/gkr.go new file mode 100644 index 0000000000..fb2a29e41b --- /dev/null +++ b/constraint/bls12-377/gkr.go @@ -0,0 +1,284 @@ +// Copyright 2020 ConsenSys Software Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Code generated by gnark DO NOT EDIT + +package cs + +import ( + "encoding/json" + "github.com/consensys/gnark-crypto/ecc/bls12-377/fr" + "github.com/consensys/gnark-crypto/ecc/bls12-377/fr/gkr" + "github.com/consensys/gnark-crypto/ecc/bls12-377/fr/polynomial" + "github.com/consensys/gnark-crypto/ecc/bls12-377/fr/test_vector_utils" // TODO: Seems a bit dubious to use this here. Decide if okay + fiatshamir "github.com/consensys/gnark-crypto/fiat-shamir" + "github.com/consensys/gnark/backend/hint" + "github.com/consensys/gnark/constraint" + "github.com/consensys/gnark/std/utils/algo_utils" + "hash" + "math/big" +) + +type gkrSolvingData struct { + assignments gkr.WireAssignment + circuit gkr.Circuit + memoryPool polynomial.Pool +} + +func convertCircuit(noPtr constraint.GkrCircuit) gkr.Circuit { + resCircuit := make(gkr.Circuit, len(noPtr)) + for i := range noPtr { + resCircuit[i].Gate = GkrGateRegistry[noPtr[i].Gate] + resCircuit[i].Inputs = algo_utils.Map(noPtr[i].Inputs, algo_utils.SlicePtrAt(resCircuit)) + } + return resCircuit +} + +// this module assumes that wire and instance indexes respect dependencies + +type gkrAssignment [][]fr.Element //gkrAssignment is indexed wire first, instance second + +// assumes assignmentVector is arranged wire first, instance second in order of solution +func gkrSolve(info constraint.GkrInfo, solvingData gkrSolvingData, assignmentVector []*big.Int) gkrAssignment { + circuit := info.Circuit + nbInstances := info.NbInstances + offsets := info.AssignmentOffsets() + nbDepsResolved := make([]int, len(circuit)) + inputs := make([]fr.Element, info.MaxNIns) + + assignments := make(gkrAssignment, len(circuit)) + for i := range assignments { + assignments[i] = make([]fr.Element, nbInstances) + } + + for instanceI := 0; instanceI < nbInstances; instanceI++ { + //fmt.Println("instance", instanceI) + for wireI, wire := range circuit { + //fmt.Print("\twire ", wireI, ": ") + if wire.IsInput() { + //fmt.Print("input.") + if nbDepsResolved[wireI] < len(wire.Dependencies) && instanceI == wire.Dependencies[nbDepsResolved[wireI]].InputInstance { + //fmt.Print(" copying value from dependency") + dep := wire.Dependencies[nbDepsResolved[wireI]] + assignments[wireI][instanceI].Set(&assignments[dep.OutputWire][dep.OutputInstance]) + nbDepsResolved[wireI]++ + } else { + //fmt.Print(" taking value from input") + assignments[wireI][instanceI].SetBigInt(assignmentVector[offsets[wireI]+instanceI-nbDepsResolved[wireI]]) + } + } else { + //fmt.Print("gated.") + // assemble the inputs + inputIndexes := info.Circuit[wireI].Inputs + for i, inputI := range inputIndexes { + inputs[i].Set(&assignments[inputI][instanceI]) + } + gate := solvingData.circuit[wireI].Gate + assignments[wireI][instanceI] = gate.Evaluate(inputs[:len(inputIndexes)]...) + } + //fmt.Println("\n\t\tresult: ", assignments[wireI][instanceI].Text(10)) + } + } + return assignments +} + +func toMapAssignment(circuit gkr.Circuit, assignment gkrAssignment) gkr.WireAssignment { + res := make(gkr.WireAssignment, len(circuit)) + for i := range circuit { + res[&circuit[i]] = assignment[i] + } + return res +} + +func gkrSetOutputValues(circuit []constraint.GkrWire, assignments gkrAssignment, outs []*big.Int) { + outsI := 0 + for i := range circuit { + if circuit[i].IsOutput() { + for j := range assignments[i] { + assignments[i][j].BigInt(outs[outsI]) + outsI++ + } + } + } + // Check if outsI == len(outs)? +} + +func gkrSolveHint(data constraint.GkrInfo, res *gkrSolvingData) hint.Function { + return func(_ *big.Int, ins, outs []*big.Int) error { + + res.circuit = convertCircuit(data.Circuit) // TODO: Take this out of here into the proving module + res.memoryPool = polynomial.NewPool(256, data.NbInstances) + + assignments := gkrSolve(data, *res, ins) + res.assignments = toMapAssignment(res.circuit, assignments) + gkrSetOutputValues(data.Circuit, assignments, outs) + + //fmt.Println("assignment ", sliceSliceToString(assignments)) + //fmt.Println("returning ", bigIntPtrSliceToString(outs)) + + return nil + } +} + +func bigIntPtrSliceToString(slice []*big.Int) []interface{} { + return algo_utils.Map(slice, func(e *big.Int) interface{} { + if e.IsInt64() { + return e.Int64() + } else { + return e.Text(10) + } + }) +} + +func sliceSliceToString(slice [][]fr.Element) string { + printable := make([]interface{}, len(slice)) + for i, s := range slice { + printable[i] = test_vector_utils.ElementSliceToInterfaceSlice(s) + } + res, err := json.Marshal(printable) + if err != nil { + panic(err.Error()) + } + return string(res) +} + +func frToBigInts(dst []*big.Int, src []fr.Element) { + for i := range src { + src[i].BigInt(dst[i]) + } +} + +func gkrProveHint(hashName string, data *gkrSolvingData) hint.Function { + + return func(_ *big.Int, ins, outs []*big.Int) error { + insBytes := algo_utils.Map(ins[1:], func(i *big.Int) []byte { // the first input is dummy, just to ensure the solver's work is done before the prover is called + b := i.Bytes() + return b[:] + }) + + hsh := HashBuilderRegistry[hashName]() + + proof, err := gkr.Prove(data.circuit, data.assignments, fiatshamir.WithHash(hsh, insBytes...), gkr.WithPool(&data.memoryPool)) // TODO: Do transcriptSettings properly + if err != nil { + return err + } + + // serialize proof: TODO: In gnark-crypto? + offset := 0 + for i := range proof { + for _, poly := range proof[i].PartialSumPolys { + frToBigInts(outs[offset:], poly) + offset += len(poly) + } + if proof[i].FinalEvalProof != nil { + finalEvalProof := proof[i].FinalEvalProof.([]fr.Element) + frToBigInts(outs[offset:], finalEvalProof) + offset += len(finalEvalProof) + } + } + return nil + + } +} + +func defineGkrHints(info constraint.GkrInfo, hintFunctions map[hint.ID]hint.Function) map[hint.ID]hint.Function { + res := make(map[hint.ID]hint.Function, len(hintFunctions)+2) + for k, v := range hintFunctions { + res[k] = v + } + var gkrData gkrSolvingData + res[info.SolveHintID] = gkrSolveHint(info, &gkrData) + res[info.ProveHintID] = gkrProveHint(info.HashName, &gkrData) + return res +} + +var GkrGateRegistry = map[string]gkr.Gate{ // TODO: Migrate to gnark-crypto + "mul": mulGate(2), + "add": addGate{}, + "sub": subGate{}, + "neg": negGate{}, +} + +// TODO: Move to gnark-crypto +var HashBuilderRegistry = make(map[string]func() hash.Hash) + +type mulGate int +type addGate struct{} +type subGate struct{} +type negGate struct{} + +func (g mulGate) Evaluate(x ...fr.Element) (res fr.Element) { + if len(x) != int(g) { + panic("wrong input count") + } + switch len(x) { + case 0: + res.SetOne() + case 1: + res.Set(&x[0]) + default: + res.Mul(&x[0], &x[1]) + for i := 2; i < len(x); i++ { + res.Mul(&res, &x[2]) + } + } + return +} + +func (g mulGate) Degree() int { + return int(g) +} + +func (g addGate) Evaluate(x ...fr.Element) (res fr.Element) { + switch len(x) { + case 0: + // set zero + case 1: + res.Set(&x[0]) + case 2: + res.Add(&x[0], &x[1]) + for i := 2; i < len(x); i++ { + res.Add(&res, &x[2]) + } + } + return +} + +func (g addGate) Degree() int { + return 1 +} + +func (g subGate) Evaluate(element ...fr.Element) (diff fr.Element) { + if len(element) > 2 { + panic("not implemented") //TODO + } + diff.Sub(&element[0], &element[1]) + return +} + +func (g subGate) Degree() int { + return 1 +} + +func (g negGate) Evaluate(element ...fr.Element) (neg fr.Element) { + if len(element) != 1 { + panic("univariate gate") + } + neg.Neg(&element[0]) + return +} + +func (g negGate) Degree() int { + return 1 +} diff --git a/constraint/bls12-381/gkr.go b/constraint/bls12-381/gkr.go new file mode 100644 index 0000000000..814d344872 --- /dev/null +++ b/constraint/bls12-381/gkr.go @@ -0,0 +1,284 @@ +// Copyright 2020 ConsenSys Software Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Code generated by gnark DO NOT EDIT + +package cs + +import ( + "encoding/json" + "github.com/consensys/gnark-crypto/ecc/bls12-381/fr" + "github.com/consensys/gnark-crypto/ecc/bls12-381/fr/gkr" + "github.com/consensys/gnark-crypto/ecc/bls12-381/fr/polynomial" + "github.com/consensys/gnark-crypto/ecc/bls12-381/fr/test_vector_utils" // TODO: Seems a bit dubious to use this here. Decide if okay + fiatshamir "github.com/consensys/gnark-crypto/fiat-shamir" + "github.com/consensys/gnark/backend/hint" + "github.com/consensys/gnark/constraint" + "github.com/consensys/gnark/std/utils/algo_utils" + "hash" + "math/big" +) + +type gkrSolvingData struct { + assignments gkr.WireAssignment + circuit gkr.Circuit + memoryPool polynomial.Pool +} + +func convertCircuit(noPtr constraint.GkrCircuit) gkr.Circuit { + resCircuit := make(gkr.Circuit, len(noPtr)) + for i := range noPtr { + resCircuit[i].Gate = GkrGateRegistry[noPtr[i].Gate] + resCircuit[i].Inputs = algo_utils.Map(noPtr[i].Inputs, algo_utils.SlicePtrAt(resCircuit)) + } + return resCircuit +} + +// this module assumes that wire and instance indexes respect dependencies + +type gkrAssignment [][]fr.Element //gkrAssignment is indexed wire first, instance second + +// assumes assignmentVector is arranged wire first, instance second in order of solution +func gkrSolve(info constraint.GkrInfo, solvingData gkrSolvingData, assignmentVector []*big.Int) gkrAssignment { + circuit := info.Circuit + nbInstances := info.NbInstances + offsets := info.AssignmentOffsets() + nbDepsResolved := make([]int, len(circuit)) + inputs := make([]fr.Element, info.MaxNIns) + + assignments := make(gkrAssignment, len(circuit)) + for i := range assignments { + assignments[i] = make([]fr.Element, nbInstances) + } + + for instanceI := 0; instanceI < nbInstances; instanceI++ { + //fmt.Println("instance", instanceI) + for wireI, wire := range circuit { + //fmt.Print("\twire ", wireI, ": ") + if wire.IsInput() { + //fmt.Print("input.") + if nbDepsResolved[wireI] < len(wire.Dependencies) && instanceI == wire.Dependencies[nbDepsResolved[wireI]].InputInstance { + //fmt.Print(" copying value from dependency") + dep := wire.Dependencies[nbDepsResolved[wireI]] + assignments[wireI][instanceI].Set(&assignments[dep.OutputWire][dep.OutputInstance]) + nbDepsResolved[wireI]++ + } else { + //fmt.Print(" taking value from input") + assignments[wireI][instanceI].SetBigInt(assignmentVector[offsets[wireI]+instanceI-nbDepsResolved[wireI]]) + } + } else { + //fmt.Print("gated.") + // assemble the inputs + inputIndexes := info.Circuit[wireI].Inputs + for i, inputI := range inputIndexes { + inputs[i].Set(&assignments[inputI][instanceI]) + } + gate := solvingData.circuit[wireI].Gate + assignments[wireI][instanceI] = gate.Evaluate(inputs[:len(inputIndexes)]...) + } + //fmt.Println("\n\t\tresult: ", assignments[wireI][instanceI].Text(10)) + } + } + return assignments +} + +func toMapAssignment(circuit gkr.Circuit, assignment gkrAssignment) gkr.WireAssignment { + res := make(gkr.WireAssignment, len(circuit)) + for i := range circuit { + res[&circuit[i]] = assignment[i] + } + return res +} + +func gkrSetOutputValues(circuit []constraint.GkrWire, assignments gkrAssignment, outs []*big.Int) { + outsI := 0 + for i := range circuit { + if circuit[i].IsOutput() { + for j := range assignments[i] { + assignments[i][j].BigInt(outs[outsI]) + outsI++ + } + } + } + // Check if outsI == len(outs)? +} + +func gkrSolveHint(data constraint.GkrInfo, res *gkrSolvingData) hint.Function { + return func(_ *big.Int, ins, outs []*big.Int) error { + + res.circuit = convertCircuit(data.Circuit) // TODO: Take this out of here into the proving module + res.memoryPool = polynomial.NewPool(256, data.NbInstances) + + assignments := gkrSolve(data, *res, ins) + res.assignments = toMapAssignment(res.circuit, assignments) + gkrSetOutputValues(data.Circuit, assignments, outs) + + //fmt.Println("assignment ", sliceSliceToString(assignments)) + //fmt.Println("returning ", bigIntPtrSliceToString(outs)) + + return nil + } +} + +func bigIntPtrSliceToString(slice []*big.Int) []interface{} { + return algo_utils.Map(slice, func(e *big.Int) interface{} { + if e.IsInt64() { + return e.Int64() + } else { + return e.Text(10) + } + }) +} + +func sliceSliceToString(slice [][]fr.Element) string { + printable := make([]interface{}, len(slice)) + for i, s := range slice { + printable[i] = test_vector_utils.ElementSliceToInterfaceSlice(s) + } + res, err := json.Marshal(printable) + if err != nil { + panic(err.Error()) + } + return string(res) +} + +func frToBigInts(dst []*big.Int, src []fr.Element) { + for i := range src { + src[i].BigInt(dst[i]) + } +} + +func gkrProveHint(hashName string, data *gkrSolvingData) hint.Function { + + return func(_ *big.Int, ins, outs []*big.Int) error { + insBytes := algo_utils.Map(ins[1:], func(i *big.Int) []byte { // the first input is dummy, just to ensure the solver's work is done before the prover is called + b := i.Bytes() + return b[:] + }) + + hsh := HashBuilderRegistry[hashName]() + + proof, err := gkr.Prove(data.circuit, data.assignments, fiatshamir.WithHash(hsh, insBytes...), gkr.WithPool(&data.memoryPool)) // TODO: Do transcriptSettings properly + if err != nil { + return err + } + + // serialize proof: TODO: In gnark-crypto? + offset := 0 + for i := range proof { + for _, poly := range proof[i].PartialSumPolys { + frToBigInts(outs[offset:], poly) + offset += len(poly) + } + if proof[i].FinalEvalProof != nil { + finalEvalProof := proof[i].FinalEvalProof.([]fr.Element) + frToBigInts(outs[offset:], finalEvalProof) + offset += len(finalEvalProof) + } + } + return nil + + } +} + +func defineGkrHints(info constraint.GkrInfo, hintFunctions map[hint.ID]hint.Function) map[hint.ID]hint.Function { + res := make(map[hint.ID]hint.Function, len(hintFunctions)+2) + for k, v := range hintFunctions { + res[k] = v + } + var gkrData gkrSolvingData + res[info.SolveHintID] = gkrSolveHint(info, &gkrData) + res[info.ProveHintID] = gkrProveHint(info.HashName, &gkrData) + return res +} + +var GkrGateRegistry = map[string]gkr.Gate{ // TODO: Migrate to gnark-crypto + "mul": mulGate(2), + "add": addGate{}, + "sub": subGate{}, + "neg": negGate{}, +} + +// TODO: Move to gnark-crypto +var HashBuilderRegistry = make(map[string]func() hash.Hash) + +type mulGate int +type addGate struct{} +type subGate struct{} +type negGate struct{} + +func (g mulGate) Evaluate(x ...fr.Element) (res fr.Element) { + if len(x) != int(g) { + panic("wrong input count") + } + switch len(x) { + case 0: + res.SetOne() + case 1: + res.Set(&x[0]) + default: + res.Mul(&x[0], &x[1]) + for i := 2; i < len(x); i++ { + res.Mul(&res, &x[2]) + } + } + return +} + +func (g mulGate) Degree() int { + return int(g) +} + +func (g addGate) Evaluate(x ...fr.Element) (res fr.Element) { + switch len(x) { + case 0: + // set zero + case 1: + res.Set(&x[0]) + case 2: + res.Add(&x[0], &x[1]) + for i := 2; i < len(x); i++ { + res.Add(&res, &x[2]) + } + } + return +} + +func (g addGate) Degree() int { + return 1 +} + +func (g subGate) Evaluate(element ...fr.Element) (diff fr.Element) { + if len(element) > 2 { + panic("not implemented") //TODO + } + diff.Sub(&element[0], &element[1]) + return +} + +func (g subGate) Degree() int { + return 1 +} + +func (g negGate) Evaluate(element ...fr.Element) (neg fr.Element) { + if len(element) != 1 { + panic("univariate gate") + } + neg.Neg(&element[0]) + return +} + +func (g negGate) Degree() int { + return 1 +} diff --git a/constraint/bls24-315/gkr.go b/constraint/bls24-315/gkr.go new file mode 100644 index 0000000000..260caa790a --- /dev/null +++ b/constraint/bls24-315/gkr.go @@ -0,0 +1,284 @@ +// Copyright 2020 ConsenSys Software Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Code generated by gnark DO NOT EDIT + +package cs + +import ( + "encoding/json" + "github.com/consensys/gnark-crypto/ecc/bls24-315/fr" + "github.com/consensys/gnark-crypto/ecc/bls24-315/fr/gkr" + "github.com/consensys/gnark-crypto/ecc/bls24-315/fr/polynomial" + "github.com/consensys/gnark-crypto/ecc/bls24-315/fr/test_vector_utils" // TODO: Seems a bit dubious to use this here. Decide if okay + fiatshamir "github.com/consensys/gnark-crypto/fiat-shamir" + "github.com/consensys/gnark/backend/hint" + "github.com/consensys/gnark/constraint" + "github.com/consensys/gnark/std/utils/algo_utils" + "hash" + "math/big" +) + +type gkrSolvingData struct { + assignments gkr.WireAssignment + circuit gkr.Circuit + memoryPool polynomial.Pool +} + +func convertCircuit(noPtr constraint.GkrCircuit) gkr.Circuit { + resCircuit := make(gkr.Circuit, len(noPtr)) + for i := range noPtr { + resCircuit[i].Gate = GkrGateRegistry[noPtr[i].Gate] + resCircuit[i].Inputs = algo_utils.Map(noPtr[i].Inputs, algo_utils.SlicePtrAt(resCircuit)) + } + return resCircuit +} + +// this module assumes that wire and instance indexes respect dependencies + +type gkrAssignment [][]fr.Element //gkrAssignment is indexed wire first, instance second + +// assumes assignmentVector is arranged wire first, instance second in order of solution +func gkrSolve(info constraint.GkrInfo, solvingData gkrSolvingData, assignmentVector []*big.Int) gkrAssignment { + circuit := info.Circuit + nbInstances := info.NbInstances + offsets := info.AssignmentOffsets() + nbDepsResolved := make([]int, len(circuit)) + inputs := make([]fr.Element, info.MaxNIns) + + assignments := make(gkrAssignment, len(circuit)) + for i := range assignments { + assignments[i] = make([]fr.Element, nbInstances) + } + + for instanceI := 0; instanceI < nbInstances; instanceI++ { + //fmt.Println("instance", instanceI) + for wireI, wire := range circuit { + //fmt.Print("\twire ", wireI, ": ") + if wire.IsInput() { + //fmt.Print("input.") + if nbDepsResolved[wireI] < len(wire.Dependencies) && instanceI == wire.Dependencies[nbDepsResolved[wireI]].InputInstance { + //fmt.Print(" copying value from dependency") + dep := wire.Dependencies[nbDepsResolved[wireI]] + assignments[wireI][instanceI].Set(&assignments[dep.OutputWire][dep.OutputInstance]) + nbDepsResolved[wireI]++ + } else { + //fmt.Print(" taking value from input") + assignments[wireI][instanceI].SetBigInt(assignmentVector[offsets[wireI]+instanceI-nbDepsResolved[wireI]]) + } + } else { + //fmt.Print("gated.") + // assemble the inputs + inputIndexes := info.Circuit[wireI].Inputs + for i, inputI := range inputIndexes { + inputs[i].Set(&assignments[inputI][instanceI]) + } + gate := solvingData.circuit[wireI].Gate + assignments[wireI][instanceI] = gate.Evaluate(inputs[:len(inputIndexes)]...) + } + //fmt.Println("\n\t\tresult: ", assignments[wireI][instanceI].Text(10)) + } + } + return assignments +} + +func toMapAssignment(circuit gkr.Circuit, assignment gkrAssignment) gkr.WireAssignment { + res := make(gkr.WireAssignment, len(circuit)) + for i := range circuit { + res[&circuit[i]] = assignment[i] + } + return res +} + +func gkrSetOutputValues(circuit []constraint.GkrWire, assignments gkrAssignment, outs []*big.Int) { + outsI := 0 + for i := range circuit { + if circuit[i].IsOutput() { + for j := range assignments[i] { + assignments[i][j].BigInt(outs[outsI]) + outsI++ + } + } + } + // Check if outsI == len(outs)? +} + +func gkrSolveHint(data constraint.GkrInfo, res *gkrSolvingData) hint.Function { + return func(_ *big.Int, ins, outs []*big.Int) error { + + res.circuit = convertCircuit(data.Circuit) // TODO: Take this out of here into the proving module + res.memoryPool = polynomial.NewPool(256, data.NbInstances) + + assignments := gkrSolve(data, *res, ins) + res.assignments = toMapAssignment(res.circuit, assignments) + gkrSetOutputValues(data.Circuit, assignments, outs) + + //fmt.Println("assignment ", sliceSliceToString(assignments)) + //fmt.Println("returning ", bigIntPtrSliceToString(outs)) + + return nil + } +} + +func bigIntPtrSliceToString(slice []*big.Int) []interface{} { + return algo_utils.Map(slice, func(e *big.Int) interface{} { + if e.IsInt64() { + return e.Int64() + } else { + return e.Text(10) + } + }) +} + +func sliceSliceToString(slice [][]fr.Element) string { + printable := make([]interface{}, len(slice)) + for i, s := range slice { + printable[i] = test_vector_utils.ElementSliceToInterfaceSlice(s) + } + res, err := json.Marshal(printable) + if err != nil { + panic(err.Error()) + } + return string(res) +} + +func frToBigInts(dst []*big.Int, src []fr.Element) { + for i := range src { + src[i].BigInt(dst[i]) + } +} + +func gkrProveHint(hashName string, data *gkrSolvingData) hint.Function { + + return func(_ *big.Int, ins, outs []*big.Int) error { + insBytes := algo_utils.Map(ins[1:], func(i *big.Int) []byte { // the first input is dummy, just to ensure the solver's work is done before the prover is called + b := i.Bytes() + return b[:] + }) + + hsh := HashBuilderRegistry[hashName]() + + proof, err := gkr.Prove(data.circuit, data.assignments, fiatshamir.WithHash(hsh, insBytes...), gkr.WithPool(&data.memoryPool)) // TODO: Do transcriptSettings properly + if err != nil { + return err + } + + // serialize proof: TODO: In gnark-crypto? + offset := 0 + for i := range proof { + for _, poly := range proof[i].PartialSumPolys { + frToBigInts(outs[offset:], poly) + offset += len(poly) + } + if proof[i].FinalEvalProof != nil { + finalEvalProof := proof[i].FinalEvalProof.([]fr.Element) + frToBigInts(outs[offset:], finalEvalProof) + offset += len(finalEvalProof) + } + } + return nil + + } +} + +func defineGkrHints(info constraint.GkrInfo, hintFunctions map[hint.ID]hint.Function) map[hint.ID]hint.Function { + res := make(map[hint.ID]hint.Function, len(hintFunctions)+2) + for k, v := range hintFunctions { + res[k] = v + } + var gkrData gkrSolvingData + res[info.SolveHintID] = gkrSolveHint(info, &gkrData) + res[info.ProveHintID] = gkrProveHint(info.HashName, &gkrData) + return res +} + +var GkrGateRegistry = map[string]gkr.Gate{ // TODO: Migrate to gnark-crypto + "mul": mulGate(2), + "add": addGate{}, + "sub": subGate{}, + "neg": negGate{}, +} + +// TODO: Move to gnark-crypto +var HashBuilderRegistry = make(map[string]func() hash.Hash) + +type mulGate int +type addGate struct{} +type subGate struct{} +type negGate struct{} + +func (g mulGate) Evaluate(x ...fr.Element) (res fr.Element) { + if len(x) != int(g) { + panic("wrong input count") + } + switch len(x) { + case 0: + res.SetOne() + case 1: + res.Set(&x[0]) + default: + res.Mul(&x[0], &x[1]) + for i := 2; i < len(x); i++ { + res.Mul(&res, &x[2]) + } + } + return +} + +func (g mulGate) Degree() int { + return int(g) +} + +func (g addGate) Evaluate(x ...fr.Element) (res fr.Element) { + switch len(x) { + case 0: + // set zero + case 1: + res.Set(&x[0]) + case 2: + res.Add(&x[0], &x[1]) + for i := 2; i < len(x); i++ { + res.Add(&res, &x[2]) + } + } + return +} + +func (g addGate) Degree() int { + return 1 +} + +func (g subGate) Evaluate(element ...fr.Element) (diff fr.Element) { + if len(element) > 2 { + panic("not implemented") //TODO + } + diff.Sub(&element[0], &element[1]) + return +} + +func (g subGate) Degree() int { + return 1 +} + +func (g negGate) Evaluate(element ...fr.Element) (neg fr.Element) { + if len(element) != 1 { + panic("univariate gate") + } + neg.Neg(&element[0]) + return +} + +func (g negGate) Degree() int { + return 1 +} diff --git a/constraint/bls24-317/gkr.go b/constraint/bls24-317/gkr.go new file mode 100644 index 0000000000..42b85ab61f --- /dev/null +++ b/constraint/bls24-317/gkr.go @@ -0,0 +1,284 @@ +// Copyright 2020 ConsenSys Software Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Code generated by gnark DO NOT EDIT + +package cs + +import ( + "encoding/json" + "github.com/consensys/gnark-crypto/ecc/bls24-317/fr" + "github.com/consensys/gnark-crypto/ecc/bls24-317/fr/gkr" + "github.com/consensys/gnark-crypto/ecc/bls24-317/fr/polynomial" + "github.com/consensys/gnark-crypto/ecc/bls24-317/fr/test_vector_utils" // TODO: Seems a bit dubious to use this here. Decide if okay + fiatshamir "github.com/consensys/gnark-crypto/fiat-shamir" + "github.com/consensys/gnark/backend/hint" + "github.com/consensys/gnark/constraint" + "github.com/consensys/gnark/std/utils/algo_utils" + "hash" + "math/big" +) + +type gkrSolvingData struct { + assignments gkr.WireAssignment + circuit gkr.Circuit + memoryPool polynomial.Pool +} + +func convertCircuit(noPtr constraint.GkrCircuit) gkr.Circuit { + resCircuit := make(gkr.Circuit, len(noPtr)) + for i := range noPtr { + resCircuit[i].Gate = GkrGateRegistry[noPtr[i].Gate] + resCircuit[i].Inputs = algo_utils.Map(noPtr[i].Inputs, algo_utils.SlicePtrAt(resCircuit)) + } + return resCircuit +} + +// this module assumes that wire and instance indexes respect dependencies + +type gkrAssignment [][]fr.Element //gkrAssignment is indexed wire first, instance second + +// assumes assignmentVector is arranged wire first, instance second in order of solution +func gkrSolve(info constraint.GkrInfo, solvingData gkrSolvingData, assignmentVector []*big.Int) gkrAssignment { + circuit := info.Circuit + nbInstances := info.NbInstances + offsets := info.AssignmentOffsets() + nbDepsResolved := make([]int, len(circuit)) + inputs := make([]fr.Element, info.MaxNIns) + + assignments := make(gkrAssignment, len(circuit)) + for i := range assignments { + assignments[i] = make([]fr.Element, nbInstances) + } + + for instanceI := 0; instanceI < nbInstances; instanceI++ { + //fmt.Println("instance", instanceI) + for wireI, wire := range circuit { + //fmt.Print("\twire ", wireI, ": ") + if wire.IsInput() { + //fmt.Print("input.") + if nbDepsResolved[wireI] < len(wire.Dependencies) && instanceI == wire.Dependencies[nbDepsResolved[wireI]].InputInstance { + //fmt.Print(" copying value from dependency") + dep := wire.Dependencies[nbDepsResolved[wireI]] + assignments[wireI][instanceI].Set(&assignments[dep.OutputWire][dep.OutputInstance]) + nbDepsResolved[wireI]++ + } else { + //fmt.Print(" taking value from input") + assignments[wireI][instanceI].SetBigInt(assignmentVector[offsets[wireI]+instanceI-nbDepsResolved[wireI]]) + } + } else { + //fmt.Print("gated.") + // assemble the inputs + inputIndexes := info.Circuit[wireI].Inputs + for i, inputI := range inputIndexes { + inputs[i].Set(&assignments[inputI][instanceI]) + } + gate := solvingData.circuit[wireI].Gate + assignments[wireI][instanceI] = gate.Evaluate(inputs[:len(inputIndexes)]...) + } + //fmt.Println("\n\t\tresult: ", assignments[wireI][instanceI].Text(10)) + } + } + return assignments +} + +func toMapAssignment(circuit gkr.Circuit, assignment gkrAssignment) gkr.WireAssignment { + res := make(gkr.WireAssignment, len(circuit)) + for i := range circuit { + res[&circuit[i]] = assignment[i] + } + return res +} + +func gkrSetOutputValues(circuit []constraint.GkrWire, assignments gkrAssignment, outs []*big.Int) { + outsI := 0 + for i := range circuit { + if circuit[i].IsOutput() { + for j := range assignments[i] { + assignments[i][j].BigInt(outs[outsI]) + outsI++ + } + } + } + // Check if outsI == len(outs)? +} + +func gkrSolveHint(data constraint.GkrInfo, res *gkrSolvingData) hint.Function { + return func(_ *big.Int, ins, outs []*big.Int) error { + + res.circuit = convertCircuit(data.Circuit) // TODO: Take this out of here into the proving module + res.memoryPool = polynomial.NewPool(256, data.NbInstances) + + assignments := gkrSolve(data, *res, ins) + res.assignments = toMapAssignment(res.circuit, assignments) + gkrSetOutputValues(data.Circuit, assignments, outs) + + //fmt.Println("assignment ", sliceSliceToString(assignments)) + //fmt.Println("returning ", bigIntPtrSliceToString(outs)) + + return nil + } +} + +func bigIntPtrSliceToString(slice []*big.Int) []interface{} { + return algo_utils.Map(slice, func(e *big.Int) interface{} { + if e.IsInt64() { + return e.Int64() + } else { + return e.Text(10) + } + }) +} + +func sliceSliceToString(slice [][]fr.Element) string { + printable := make([]interface{}, len(slice)) + for i, s := range slice { + printable[i] = test_vector_utils.ElementSliceToInterfaceSlice(s) + } + res, err := json.Marshal(printable) + if err != nil { + panic(err.Error()) + } + return string(res) +} + +func frToBigInts(dst []*big.Int, src []fr.Element) { + for i := range src { + src[i].BigInt(dst[i]) + } +} + +func gkrProveHint(hashName string, data *gkrSolvingData) hint.Function { + + return func(_ *big.Int, ins, outs []*big.Int) error { + insBytes := algo_utils.Map(ins[1:], func(i *big.Int) []byte { // the first input is dummy, just to ensure the solver's work is done before the prover is called + b := i.Bytes() + return b[:] + }) + + hsh := HashBuilderRegistry[hashName]() + + proof, err := gkr.Prove(data.circuit, data.assignments, fiatshamir.WithHash(hsh, insBytes...), gkr.WithPool(&data.memoryPool)) // TODO: Do transcriptSettings properly + if err != nil { + return err + } + + // serialize proof: TODO: In gnark-crypto? + offset := 0 + for i := range proof { + for _, poly := range proof[i].PartialSumPolys { + frToBigInts(outs[offset:], poly) + offset += len(poly) + } + if proof[i].FinalEvalProof != nil { + finalEvalProof := proof[i].FinalEvalProof.([]fr.Element) + frToBigInts(outs[offset:], finalEvalProof) + offset += len(finalEvalProof) + } + } + return nil + + } +} + +func defineGkrHints(info constraint.GkrInfo, hintFunctions map[hint.ID]hint.Function) map[hint.ID]hint.Function { + res := make(map[hint.ID]hint.Function, len(hintFunctions)+2) + for k, v := range hintFunctions { + res[k] = v + } + var gkrData gkrSolvingData + res[info.SolveHintID] = gkrSolveHint(info, &gkrData) + res[info.ProveHintID] = gkrProveHint(info.HashName, &gkrData) + return res +} + +var GkrGateRegistry = map[string]gkr.Gate{ // TODO: Migrate to gnark-crypto + "mul": mulGate(2), + "add": addGate{}, + "sub": subGate{}, + "neg": negGate{}, +} + +// TODO: Move to gnark-crypto +var HashBuilderRegistry = make(map[string]func() hash.Hash) + +type mulGate int +type addGate struct{} +type subGate struct{} +type negGate struct{} + +func (g mulGate) Evaluate(x ...fr.Element) (res fr.Element) { + if len(x) != int(g) { + panic("wrong input count") + } + switch len(x) { + case 0: + res.SetOne() + case 1: + res.Set(&x[0]) + default: + res.Mul(&x[0], &x[1]) + for i := 2; i < len(x); i++ { + res.Mul(&res, &x[2]) + } + } + return +} + +func (g mulGate) Degree() int { + return int(g) +} + +func (g addGate) Evaluate(x ...fr.Element) (res fr.Element) { + switch len(x) { + case 0: + // set zero + case 1: + res.Set(&x[0]) + case 2: + res.Add(&x[0], &x[1]) + for i := 2; i < len(x); i++ { + res.Add(&res, &x[2]) + } + } + return +} + +func (g addGate) Degree() int { + return 1 +} + +func (g subGate) Evaluate(element ...fr.Element) (diff fr.Element) { + if len(element) > 2 { + panic("not implemented") //TODO + } + diff.Sub(&element[0], &element[1]) + return +} + +func (g subGate) Degree() int { + return 1 +} + +func (g negGate) Evaluate(element ...fr.Element) (neg fr.Element) { + if len(element) != 1 { + panic("univariate gate") + } + neg.Neg(&element[0]) + return +} + +func (g negGate) Degree() int { + return 1 +} diff --git a/constraint/bn254/gkr.go b/constraint/bn254/gkr.go index a1fde9c363..e257f7b946 100644 --- a/constraint/bn254/gkr.go +++ b/constraint/bn254/gkr.go @@ -1,3 +1,19 @@ +// Copyright 2020 ConsenSys Software Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Code generated by gnark DO NOT EDIT + package cs import ( @@ -5,7 +21,7 @@ import ( "github.com/consensys/gnark-crypto/ecc/bn254/fr" "github.com/consensys/gnark-crypto/ecc/bn254/fr/gkr" "github.com/consensys/gnark-crypto/ecc/bn254/fr/polynomial" - "github.com/consensys/gnark-crypto/ecc/bn254/fr/test_vector_utils" + "github.com/consensys/gnark-crypto/ecc/bn254/fr/test_vector_utils" // TODO: Seems a bit dubious to use this here. Decide if okay fiatshamir "github.com/consensys/gnark-crypto/fiat-shamir" "github.com/consensys/gnark/backend/hint" "github.com/consensys/gnark/constraint" diff --git a/constraint/bw6-633/gkr.go b/constraint/bw6-633/gkr.go new file mode 100644 index 0000000000..392c06d5ea --- /dev/null +++ b/constraint/bw6-633/gkr.go @@ -0,0 +1,284 @@ +// Copyright 2020 ConsenSys Software Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Code generated by gnark DO NOT EDIT + +package cs + +import ( + "encoding/json" + "github.com/consensys/gnark-crypto/ecc/bw6-633/fr" + "github.com/consensys/gnark-crypto/ecc/bw6-633/fr/gkr" + "github.com/consensys/gnark-crypto/ecc/bw6-633/fr/polynomial" + "github.com/consensys/gnark-crypto/ecc/bw6-633/fr/test_vector_utils" // TODO: Seems a bit dubious to use this here. Decide if okay + fiatshamir "github.com/consensys/gnark-crypto/fiat-shamir" + "github.com/consensys/gnark/backend/hint" + "github.com/consensys/gnark/constraint" + "github.com/consensys/gnark/std/utils/algo_utils" + "hash" + "math/big" +) + +type gkrSolvingData struct { + assignments gkr.WireAssignment + circuit gkr.Circuit + memoryPool polynomial.Pool +} + +func convertCircuit(noPtr constraint.GkrCircuit) gkr.Circuit { + resCircuit := make(gkr.Circuit, len(noPtr)) + for i := range noPtr { + resCircuit[i].Gate = GkrGateRegistry[noPtr[i].Gate] + resCircuit[i].Inputs = algo_utils.Map(noPtr[i].Inputs, algo_utils.SlicePtrAt(resCircuit)) + } + return resCircuit +} + +// this module assumes that wire and instance indexes respect dependencies + +type gkrAssignment [][]fr.Element //gkrAssignment is indexed wire first, instance second + +// assumes assignmentVector is arranged wire first, instance second in order of solution +func gkrSolve(info constraint.GkrInfo, solvingData gkrSolvingData, assignmentVector []*big.Int) gkrAssignment { + circuit := info.Circuit + nbInstances := info.NbInstances + offsets := info.AssignmentOffsets() + nbDepsResolved := make([]int, len(circuit)) + inputs := make([]fr.Element, info.MaxNIns) + + assignments := make(gkrAssignment, len(circuit)) + for i := range assignments { + assignments[i] = make([]fr.Element, nbInstances) + } + + for instanceI := 0; instanceI < nbInstances; instanceI++ { + //fmt.Println("instance", instanceI) + for wireI, wire := range circuit { + //fmt.Print("\twire ", wireI, ": ") + if wire.IsInput() { + //fmt.Print("input.") + if nbDepsResolved[wireI] < len(wire.Dependencies) && instanceI == wire.Dependencies[nbDepsResolved[wireI]].InputInstance { + //fmt.Print(" copying value from dependency") + dep := wire.Dependencies[nbDepsResolved[wireI]] + assignments[wireI][instanceI].Set(&assignments[dep.OutputWire][dep.OutputInstance]) + nbDepsResolved[wireI]++ + } else { + //fmt.Print(" taking value from input") + assignments[wireI][instanceI].SetBigInt(assignmentVector[offsets[wireI]+instanceI-nbDepsResolved[wireI]]) + } + } else { + //fmt.Print("gated.") + // assemble the inputs + inputIndexes := info.Circuit[wireI].Inputs + for i, inputI := range inputIndexes { + inputs[i].Set(&assignments[inputI][instanceI]) + } + gate := solvingData.circuit[wireI].Gate + assignments[wireI][instanceI] = gate.Evaluate(inputs[:len(inputIndexes)]...) + } + //fmt.Println("\n\t\tresult: ", assignments[wireI][instanceI].Text(10)) + } + } + return assignments +} + +func toMapAssignment(circuit gkr.Circuit, assignment gkrAssignment) gkr.WireAssignment { + res := make(gkr.WireAssignment, len(circuit)) + for i := range circuit { + res[&circuit[i]] = assignment[i] + } + return res +} + +func gkrSetOutputValues(circuit []constraint.GkrWire, assignments gkrAssignment, outs []*big.Int) { + outsI := 0 + for i := range circuit { + if circuit[i].IsOutput() { + for j := range assignments[i] { + assignments[i][j].BigInt(outs[outsI]) + outsI++ + } + } + } + // Check if outsI == len(outs)? +} + +func gkrSolveHint(data constraint.GkrInfo, res *gkrSolvingData) hint.Function { + return func(_ *big.Int, ins, outs []*big.Int) error { + + res.circuit = convertCircuit(data.Circuit) // TODO: Take this out of here into the proving module + res.memoryPool = polynomial.NewPool(256, data.NbInstances) + + assignments := gkrSolve(data, *res, ins) + res.assignments = toMapAssignment(res.circuit, assignments) + gkrSetOutputValues(data.Circuit, assignments, outs) + + //fmt.Println("assignment ", sliceSliceToString(assignments)) + //fmt.Println("returning ", bigIntPtrSliceToString(outs)) + + return nil + } +} + +func bigIntPtrSliceToString(slice []*big.Int) []interface{} { + return algo_utils.Map(slice, func(e *big.Int) interface{} { + if e.IsInt64() { + return e.Int64() + } else { + return e.Text(10) + } + }) +} + +func sliceSliceToString(slice [][]fr.Element) string { + printable := make([]interface{}, len(slice)) + for i, s := range slice { + printable[i] = test_vector_utils.ElementSliceToInterfaceSlice(s) + } + res, err := json.Marshal(printable) + if err != nil { + panic(err.Error()) + } + return string(res) +} + +func frToBigInts(dst []*big.Int, src []fr.Element) { + for i := range src { + src[i].BigInt(dst[i]) + } +} + +func gkrProveHint(hashName string, data *gkrSolvingData) hint.Function { + + return func(_ *big.Int, ins, outs []*big.Int) error { + insBytes := algo_utils.Map(ins[1:], func(i *big.Int) []byte { // the first input is dummy, just to ensure the solver's work is done before the prover is called + b := i.Bytes() + return b[:] + }) + + hsh := HashBuilderRegistry[hashName]() + + proof, err := gkr.Prove(data.circuit, data.assignments, fiatshamir.WithHash(hsh, insBytes...), gkr.WithPool(&data.memoryPool)) // TODO: Do transcriptSettings properly + if err != nil { + return err + } + + // serialize proof: TODO: In gnark-crypto? + offset := 0 + for i := range proof { + for _, poly := range proof[i].PartialSumPolys { + frToBigInts(outs[offset:], poly) + offset += len(poly) + } + if proof[i].FinalEvalProof != nil { + finalEvalProof := proof[i].FinalEvalProof.([]fr.Element) + frToBigInts(outs[offset:], finalEvalProof) + offset += len(finalEvalProof) + } + } + return nil + + } +} + +func defineGkrHints(info constraint.GkrInfo, hintFunctions map[hint.ID]hint.Function) map[hint.ID]hint.Function { + res := make(map[hint.ID]hint.Function, len(hintFunctions)+2) + for k, v := range hintFunctions { + res[k] = v + } + var gkrData gkrSolvingData + res[info.SolveHintID] = gkrSolveHint(info, &gkrData) + res[info.ProveHintID] = gkrProveHint(info.HashName, &gkrData) + return res +} + +var GkrGateRegistry = map[string]gkr.Gate{ // TODO: Migrate to gnark-crypto + "mul": mulGate(2), + "add": addGate{}, + "sub": subGate{}, + "neg": negGate{}, +} + +// TODO: Move to gnark-crypto +var HashBuilderRegistry = make(map[string]func() hash.Hash) + +type mulGate int +type addGate struct{} +type subGate struct{} +type negGate struct{} + +func (g mulGate) Evaluate(x ...fr.Element) (res fr.Element) { + if len(x) != int(g) { + panic("wrong input count") + } + switch len(x) { + case 0: + res.SetOne() + case 1: + res.Set(&x[0]) + default: + res.Mul(&x[0], &x[1]) + for i := 2; i < len(x); i++ { + res.Mul(&res, &x[2]) + } + } + return +} + +func (g mulGate) Degree() int { + return int(g) +} + +func (g addGate) Evaluate(x ...fr.Element) (res fr.Element) { + switch len(x) { + case 0: + // set zero + case 1: + res.Set(&x[0]) + case 2: + res.Add(&x[0], &x[1]) + for i := 2; i < len(x); i++ { + res.Add(&res, &x[2]) + } + } + return +} + +func (g addGate) Degree() int { + return 1 +} + +func (g subGate) Evaluate(element ...fr.Element) (diff fr.Element) { + if len(element) > 2 { + panic("not implemented") //TODO + } + diff.Sub(&element[0], &element[1]) + return +} + +func (g subGate) Degree() int { + return 1 +} + +func (g negGate) Evaluate(element ...fr.Element) (neg fr.Element) { + if len(element) != 1 { + panic("univariate gate") + } + neg.Neg(&element[0]) + return +} + +func (g negGate) Degree() int { + return 1 +} diff --git a/constraint/bw6-761/gkr.go b/constraint/bw6-761/gkr.go new file mode 100644 index 0000000000..21a07c4344 --- /dev/null +++ b/constraint/bw6-761/gkr.go @@ -0,0 +1,284 @@ +// Copyright 2020 ConsenSys Software Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Code generated by gnark DO NOT EDIT + +package cs + +import ( + "encoding/json" + "github.com/consensys/gnark-crypto/ecc/bw6-761/fr" + "github.com/consensys/gnark-crypto/ecc/bw6-761/fr/gkr" + "github.com/consensys/gnark-crypto/ecc/bw6-761/fr/polynomial" + "github.com/consensys/gnark-crypto/ecc/bw6-761/fr/test_vector_utils" // TODO: Seems a bit dubious to use this here. Decide if okay + fiatshamir "github.com/consensys/gnark-crypto/fiat-shamir" + "github.com/consensys/gnark/backend/hint" + "github.com/consensys/gnark/constraint" + "github.com/consensys/gnark/std/utils/algo_utils" + "hash" + "math/big" +) + +type gkrSolvingData struct { + assignments gkr.WireAssignment + circuit gkr.Circuit + memoryPool polynomial.Pool +} + +func convertCircuit(noPtr constraint.GkrCircuit) gkr.Circuit { + resCircuit := make(gkr.Circuit, len(noPtr)) + for i := range noPtr { + resCircuit[i].Gate = GkrGateRegistry[noPtr[i].Gate] + resCircuit[i].Inputs = algo_utils.Map(noPtr[i].Inputs, algo_utils.SlicePtrAt(resCircuit)) + } + return resCircuit +} + +// this module assumes that wire and instance indexes respect dependencies + +type gkrAssignment [][]fr.Element //gkrAssignment is indexed wire first, instance second + +// assumes assignmentVector is arranged wire first, instance second in order of solution +func gkrSolve(info constraint.GkrInfo, solvingData gkrSolvingData, assignmentVector []*big.Int) gkrAssignment { + circuit := info.Circuit + nbInstances := info.NbInstances + offsets := info.AssignmentOffsets() + nbDepsResolved := make([]int, len(circuit)) + inputs := make([]fr.Element, info.MaxNIns) + + assignments := make(gkrAssignment, len(circuit)) + for i := range assignments { + assignments[i] = make([]fr.Element, nbInstances) + } + + for instanceI := 0; instanceI < nbInstances; instanceI++ { + //fmt.Println("instance", instanceI) + for wireI, wire := range circuit { + //fmt.Print("\twire ", wireI, ": ") + if wire.IsInput() { + //fmt.Print("input.") + if nbDepsResolved[wireI] < len(wire.Dependencies) && instanceI == wire.Dependencies[nbDepsResolved[wireI]].InputInstance { + //fmt.Print(" copying value from dependency") + dep := wire.Dependencies[nbDepsResolved[wireI]] + assignments[wireI][instanceI].Set(&assignments[dep.OutputWire][dep.OutputInstance]) + nbDepsResolved[wireI]++ + } else { + //fmt.Print(" taking value from input") + assignments[wireI][instanceI].SetBigInt(assignmentVector[offsets[wireI]+instanceI-nbDepsResolved[wireI]]) + } + } else { + //fmt.Print("gated.") + // assemble the inputs + inputIndexes := info.Circuit[wireI].Inputs + for i, inputI := range inputIndexes { + inputs[i].Set(&assignments[inputI][instanceI]) + } + gate := solvingData.circuit[wireI].Gate + assignments[wireI][instanceI] = gate.Evaluate(inputs[:len(inputIndexes)]...) + } + //fmt.Println("\n\t\tresult: ", assignments[wireI][instanceI].Text(10)) + } + } + return assignments +} + +func toMapAssignment(circuit gkr.Circuit, assignment gkrAssignment) gkr.WireAssignment { + res := make(gkr.WireAssignment, len(circuit)) + for i := range circuit { + res[&circuit[i]] = assignment[i] + } + return res +} + +func gkrSetOutputValues(circuit []constraint.GkrWire, assignments gkrAssignment, outs []*big.Int) { + outsI := 0 + for i := range circuit { + if circuit[i].IsOutput() { + for j := range assignments[i] { + assignments[i][j].BigInt(outs[outsI]) + outsI++ + } + } + } + // Check if outsI == len(outs)? +} + +func gkrSolveHint(data constraint.GkrInfo, res *gkrSolvingData) hint.Function { + return func(_ *big.Int, ins, outs []*big.Int) error { + + res.circuit = convertCircuit(data.Circuit) // TODO: Take this out of here into the proving module + res.memoryPool = polynomial.NewPool(256, data.NbInstances) + + assignments := gkrSolve(data, *res, ins) + res.assignments = toMapAssignment(res.circuit, assignments) + gkrSetOutputValues(data.Circuit, assignments, outs) + + //fmt.Println("assignment ", sliceSliceToString(assignments)) + //fmt.Println("returning ", bigIntPtrSliceToString(outs)) + + return nil + } +} + +func bigIntPtrSliceToString(slice []*big.Int) []interface{} { + return algo_utils.Map(slice, func(e *big.Int) interface{} { + if e.IsInt64() { + return e.Int64() + } else { + return e.Text(10) + } + }) +} + +func sliceSliceToString(slice [][]fr.Element) string { + printable := make([]interface{}, len(slice)) + for i, s := range slice { + printable[i] = test_vector_utils.ElementSliceToInterfaceSlice(s) + } + res, err := json.Marshal(printable) + if err != nil { + panic(err.Error()) + } + return string(res) +} + +func frToBigInts(dst []*big.Int, src []fr.Element) { + for i := range src { + src[i].BigInt(dst[i]) + } +} + +func gkrProveHint(hashName string, data *gkrSolvingData) hint.Function { + + return func(_ *big.Int, ins, outs []*big.Int) error { + insBytes := algo_utils.Map(ins[1:], func(i *big.Int) []byte { // the first input is dummy, just to ensure the solver's work is done before the prover is called + b := i.Bytes() + return b[:] + }) + + hsh := HashBuilderRegistry[hashName]() + + proof, err := gkr.Prove(data.circuit, data.assignments, fiatshamir.WithHash(hsh, insBytes...), gkr.WithPool(&data.memoryPool)) // TODO: Do transcriptSettings properly + if err != nil { + return err + } + + // serialize proof: TODO: In gnark-crypto? + offset := 0 + for i := range proof { + for _, poly := range proof[i].PartialSumPolys { + frToBigInts(outs[offset:], poly) + offset += len(poly) + } + if proof[i].FinalEvalProof != nil { + finalEvalProof := proof[i].FinalEvalProof.([]fr.Element) + frToBigInts(outs[offset:], finalEvalProof) + offset += len(finalEvalProof) + } + } + return nil + + } +} + +func defineGkrHints(info constraint.GkrInfo, hintFunctions map[hint.ID]hint.Function) map[hint.ID]hint.Function { + res := make(map[hint.ID]hint.Function, len(hintFunctions)+2) + for k, v := range hintFunctions { + res[k] = v + } + var gkrData gkrSolvingData + res[info.SolveHintID] = gkrSolveHint(info, &gkrData) + res[info.ProveHintID] = gkrProveHint(info.HashName, &gkrData) + return res +} + +var GkrGateRegistry = map[string]gkr.Gate{ // TODO: Migrate to gnark-crypto + "mul": mulGate(2), + "add": addGate{}, + "sub": subGate{}, + "neg": negGate{}, +} + +// TODO: Move to gnark-crypto +var HashBuilderRegistry = make(map[string]func() hash.Hash) + +type mulGate int +type addGate struct{} +type subGate struct{} +type negGate struct{} + +func (g mulGate) Evaluate(x ...fr.Element) (res fr.Element) { + if len(x) != int(g) { + panic("wrong input count") + } + switch len(x) { + case 0: + res.SetOne() + case 1: + res.Set(&x[0]) + default: + res.Mul(&x[0], &x[1]) + for i := 2; i < len(x); i++ { + res.Mul(&res, &x[2]) + } + } + return +} + +func (g mulGate) Degree() int { + return int(g) +} + +func (g addGate) Evaluate(x ...fr.Element) (res fr.Element) { + switch len(x) { + case 0: + // set zero + case 1: + res.Set(&x[0]) + case 2: + res.Add(&x[0], &x[1]) + for i := 2; i < len(x); i++ { + res.Add(&res, &x[2]) + } + } + return +} + +func (g addGate) Degree() int { + return 1 +} + +func (g subGate) Evaluate(element ...fr.Element) (diff fr.Element) { + if len(element) > 2 { + panic("not implemented") //TODO + } + diff.Sub(&element[0], &element[1]) + return +} + +func (g subGate) Degree() int { + return 1 +} + +func (g negGate) Evaluate(element ...fr.Element) (neg fr.Element) { + if len(element) != 1 { + panic("univariate gate") + } + neg.Neg(&element[0]) + return +} + +func (g negGate) Degree() int { + return 1 +} diff --git a/constraint/tinyfield/gkr.go b/constraint/tinyfield/gkr.go new file mode 100644 index 0000000000..d911a9930c --- /dev/null +++ b/constraint/tinyfield/gkr.go @@ -0,0 +1,284 @@ +// Copyright 2020 ConsenSys Software Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Code generated by gnark DO NOT EDIT + +package cs + +import ( + "encoding/json" + "github.com/consensys/gnark-crypto/ecc/tinyfield/fr/gkr" + "github.com/consensys/gnark-crypto/ecc/tinyfield/fr/polynomial" + "github.com/consensys/gnark-crypto/ecc/tinyfield/fr/test_vector_utils" // TODO: Seems a bit dubious to use this here. Decide if okay + fiatshamir "github.com/consensys/gnark-crypto/fiat-shamir" + "github.com/consensys/gnark/backend/hint" + "github.com/consensys/gnark/constraint" + fr "github.com/consensys/gnark/internal/tinyfield" + "github.com/consensys/gnark/std/utils/algo_utils" + "hash" + "math/big" +) + +type gkrSolvingData struct { + assignments gkr.WireAssignment + circuit gkr.Circuit + memoryPool polynomial.Pool +} + +func convertCircuit(noPtr constraint.GkrCircuit) gkr.Circuit { + resCircuit := make(gkr.Circuit, len(noPtr)) + for i := range noPtr { + resCircuit[i].Gate = GkrGateRegistry[noPtr[i].Gate] + resCircuit[i].Inputs = algo_utils.Map(noPtr[i].Inputs, algo_utils.SlicePtrAt(resCircuit)) + } + return resCircuit +} + +// this module assumes that wire and instance indexes respect dependencies + +type gkrAssignment [][]fr.Element //gkrAssignment is indexed wire first, instance second + +// assumes assignmentVector is arranged wire first, instance second in order of solution +func gkrSolve(info constraint.GkrInfo, solvingData gkrSolvingData, assignmentVector []*big.Int) gkrAssignment { + circuit := info.Circuit + nbInstances := info.NbInstances + offsets := info.AssignmentOffsets() + nbDepsResolved := make([]int, len(circuit)) + inputs := make([]fr.Element, info.MaxNIns) + + assignments := make(gkrAssignment, len(circuit)) + for i := range assignments { + assignments[i] = make([]fr.Element, nbInstances) + } + + for instanceI := 0; instanceI < nbInstances; instanceI++ { + //fmt.Println("instance", instanceI) + for wireI, wire := range circuit { + //fmt.Print("\twire ", wireI, ": ") + if wire.IsInput() { + //fmt.Print("input.") + if nbDepsResolved[wireI] < len(wire.Dependencies) && instanceI == wire.Dependencies[nbDepsResolved[wireI]].InputInstance { + //fmt.Print(" copying value from dependency") + dep := wire.Dependencies[nbDepsResolved[wireI]] + assignments[wireI][instanceI].Set(&assignments[dep.OutputWire][dep.OutputInstance]) + nbDepsResolved[wireI]++ + } else { + //fmt.Print(" taking value from input") + assignments[wireI][instanceI].SetBigInt(assignmentVector[offsets[wireI]+instanceI-nbDepsResolved[wireI]]) + } + } else { + //fmt.Print("gated.") + // assemble the inputs + inputIndexes := info.Circuit[wireI].Inputs + for i, inputI := range inputIndexes { + inputs[i].Set(&assignments[inputI][instanceI]) + } + gate := solvingData.circuit[wireI].Gate + assignments[wireI][instanceI] = gate.Evaluate(inputs[:len(inputIndexes)]...) + } + //fmt.Println("\n\t\tresult: ", assignments[wireI][instanceI].Text(10)) + } + } + return assignments +} + +func toMapAssignment(circuit gkr.Circuit, assignment gkrAssignment) gkr.WireAssignment { + res := make(gkr.WireAssignment, len(circuit)) + for i := range circuit { + res[&circuit[i]] = assignment[i] + } + return res +} + +func gkrSetOutputValues(circuit []constraint.GkrWire, assignments gkrAssignment, outs []*big.Int) { + outsI := 0 + for i := range circuit { + if circuit[i].IsOutput() { + for j := range assignments[i] { + assignments[i][j].BigInt(outs[outsI]) + outsI++ + } + } + } + // Check if outsI == len(outs)? +} + +func gkrSolveHint(data constraint.GkrInfo, res *gkrSolvingData) hint.Function { + return func(_ *big.Int, ins, outs []*big.Int) error { + + res.circuit = convertCircuit(data.Circuit) // TODO: Take this out of here into the proving module + res.memoryPool = polynomial.NewPool(256, data.NbInstances) + + assignments := gkrSolve(data, *res, ins) + res.assignments = toMapAssignment(res.circuit, assignments) + gkrSetOutputValues(data.Circuit, assignments, outs) + + //fmt.Println("assignment ", sliceSliceToString(assignments)) + //fmt.Println("returning ", bigIntPtrSliceToString(outs)) + + return nil + } +} + +func bigIntPtrSliceToString(slice []*big.Int) []interface{} { + return algo_utils.Map(slice, func(e *big.Int) interface{} { + if e.IsInt64() { + return e.Int64() + } else { + return e.Text(10) + } + }) +} + +func sliceSliceToString(slice [][]fr.Element) string { + printable := make([]interface{}, len(slice)) + for i, s := range slice { + printable[i] = test_vector_utils.ElementSliceToInterfaceSlice(s) + } + res, err := json.Marshal(printable) + if err != nil { + panic(err.Error()) + } + return string(res) +} + +func frToBigInts(dst []*big.Int, src []fr.Element) { + for i := range src { + src[i].BigInt(dst[i]) + } +} + +func gkrProveHint(hashName string, data *gkrSolvingData) hint.Function { + + return func(_ *big.Int, ins, outs []*big.Int) error { + insBytes := algo_utils.Map(ins[1:], func(i *big.Int) []byte { // the first input is dummy, just to ensure the solver's work is done before the prover is called + b := i.Bytes() + return b[:] + }) + + hsh := HashBuilderRegistry[hashName]() + + proof, err := gkr.Prove(data.circuit, data.assignments, fiatshamir.WithHash(hsh, insBytes...), gkr.WithPool(&data.memoryPool)) // TODO: Do transcriptSettings properly + if err != nil { + return err + } + + // serialize proof: TODO: In gnark-crypto? + offset := 0 + for i := range proof { + for _, poly := range proof[i].PartialSumPolys { + frToBigInts(outs[offset:], poly) + offset += len(poly) + } + if proof[i].FinalEvalProof != nil { + finalEvalProof := proof[i].FinalEvalProof.([]fr.Element) + frToBigInts(outs[offset:], finalEvalProof) + offset += len(finalEvalProof) + } + } + return nil + + } +} + +func defineGkrHints(info constraint.GkrInfo, hintFunctions map[hint.ID]hint.Function) map[hint.ID]hint.Function { + res := make(map[hint.ID]hint.Function, len(hintFunctions)+2) + for k, v := range hintFunctions { + res[k] = v + } + var gkrData gkrSolvingData + res[info.SolveHintID] = gkrSolveHint(info, &gkrData) + res[info.ProveHintID] = gkrProveHint(info.HashName, &gkrData) + return res +} + +var GkrGateRegistry = map[string]gkr.Gate{ // TODO: Migrate to gnark-crypto + "mul": mulGate(2), + "add": addGate{}, + "sub": subGate{}, + "neg": negGate{}, +} + +// TODO: Move to gnark-crypto +var HashBuilderRegistry = make(map[string]func() hash.Hash) + +type mulGate int +type addGate struct{} +type subGate struct{} +type negGate struct{} + +func (g mulGate) Evaluate(x ...fr.Element) (res fr.Element) { + if len(x) != int(g) { + panic("wrong input count") + } + switch len(x) { + case 0: + res.SetOne() + case 1: + res.Set(&x[0]) + default: + res.Mul(&x[0], &x[1]) + for i := 2; i < len(x); i++ { + res.Mul(&res, &x[2]) + } + } + return +} + +func (g mulGate) Degree() int { + return int(g) +} + +func (g addGate) Evaluate(x ...fr.Element) (res fr.Element) { + switch len(x) { + case 0: + // set zero + case 1: + res.Set(&x[0]) + case 2: + res.Add(&x[0], &x[1]) + for i := 2; i < len(x); i++ { + res.Add(&res, &x[2]) + } + } + return +} + +func (g addGate) Degree() int { + return 1 +} + +func (g subGate) Evaluate(element ...fr.Element) (diff fr.Element) { + if len(element) > 2 { + panic("not implemented") //TODO + } + diff.Sub(&element[0], &element[1]) + return +} + +func (g subGate) Degree() int { + return 1 +} + +func (g negGate) Evaluate(element ...fr.Element) (neg fr.Element) { + if len(element) != 1 { + panic("univariate gate") + } + neg.Neg(&element[0]) + return +} + +func (g negGate) Degree() int { + return 1 +} diff --git a/internal/generator/backend/template/representations/gkr.go.tmpl b/internal/generator/backend/template/representations/gkr.go.tmpl index 258ae615bc..abf5f7a64b 100644 --- a/internal/generator/backend/template/representations/gkr.go.tmpl +++ b/internal/generator/backend/template/representations/gkr.go.tmpl @@ -1,10 +1,8 @@ -package cs - import ( "encoding/json" - {{template "import_fr" .}} - {{template "import_gkr" .}} - {{template "import_polynomial" .}} + {{- template "import_fr" .}} + {{- template "import_gkr" .}} + {{- template "import_polynomial" .}} "github.com/consensys/gnark-crypto/ecc/{{ toLower .Curve }}/fr/test_vector_utils" // TODO: Seems a bit dubious to use this here. Decide if okay fiatshamir "github.com/consensys/gnark-crypto/fiat-shamir" "github.com/consensys/gnark/backend/hint" From 0470d225396aef371d70d3bb7a2106537b2e811c Mon Sep 17 00:00:00 2001 From: Arya Tabaie Date: Fri, 20 Jan 2023 14:26:18 -0500 Subject: [PATCH 35/71] fix: no gkr for tinyfield --- constraint/tinyfield/gkr.go | 284 ----------------------------- internal/generator/backend/main.go | 9 +- std/fiat-shamir/transcript.go | 15 +- std/gkr/api_test.go | 80 ++++---- std/gkr/compile.go | 5 +- std/gkr/compile_test.go | 32 ---- std/gkr/gkr.go | 2 +- std/gkr/gkr_test.go | 18 +- test/engine_test.go | 25 --- 9 files changed, 65 insertions(+), 405 deletions(-) delete mode 100644 constraint/tinyfield/gkr.go diff --git a/constraint/tinyfield/gkr.go b/constraint/tinyfield/gkr.go deleted file mode 100644 index d911a9930c..0000000000 --- a/constraint/tinyfield/gkr.go +++ /dev/null @@ -1,284 +0,0 @@ -// Copyright 2020 ConsenSys Software Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -// Code generated by gnark DO NOT EDIT - -package cs - -import ( - "encoding/json" - "github.com/consensys/gnark-crypto/ecc/tinyfield/fr/gkr" - "github.com/consensys/gnark-crypto/ecc/tinyfield/fr/polynomial" - "github.com/consensys/gnark-crypto/ecc/tinyfield/fr/test_vector_utils" // TODO: Seems a bit dubious to use this here. Decide if okay - fiatshamir "github.com/consensys/gnark-crypto/fiat-shamir" - "github.com/consensys/gnark/backend/hint" - "github.com/consensys/gnark/constraint" - fr "github.com/consensys/gnark/internal/tinyfield" - "github.com/consensys/gnark/std/utils/algo_utils" - "hash" - "math/big" -) - -type gkrSolvingData struct { - assignments gkr.WireAssignment - circuit gkr.Circuit - memoryPool polynomial.Pool -} - -func convertCircuit(noPtr constraint.GkrCircuit) gkr.Circuit { - resCircuit := make(gkr.Circuit, len(noPtr)) - for i := range noPtr { - resCircuit[i].Gate = GkrGateRegistry[noPtr[i].Gate] - resCircuit[i].Inputs = algo_utils.Map(noPtr[i].Inputs, algo_utils.SlicePtrAt(resCircuit)) - } - return resCircuit -} - -// this module assumes that wire and instance indexes respect dependencies - -type gkrAssignment [][]fr.Element //gkrAssignment is indexed wire first, instance second - -// assumes assignmentVector is arranged wire first, instance second in order of solution -func gkrSolve(info constraint.GkrInfo, solvingData gkrSolvingData, assignmentVector []*big.Int) gkrAssignment { - circuit := info.Circuit - nbInstances := info.NbInstances - offsets := info.AssignmentOffsets() - nbDepsResolved := make([]int, len(circuit)) - inputs := make([]fr.Element, info.MaxNIns) - - assignments := make(gkrAssignment, len(circuit)) - for i := range assignments { - assignments[i] = make([]fr.Element, nbInstances) - } - - for instanceI := 0; instanceI < nbInstances; instanceI++ { - //fmt.Println("instance", instanceI) - for wireI, wire := range circuit { - //fmt.Print("\twire ", wireI, ": ") - if wire.IsInput() { - //fmt.Print("input.") - if nbDepsResolved[wireI] < len(wire.Dependencies) && instanceI == wire.Dependencies[nbDepsResolved[wireI]].InputInstance { - //fmt.Print(" copying value from dependency") - dep := wire.Dependencies[nbDepsResolved[wireI]] - assignments[wireI][instanceI].Set(&assignments[dep.OutputWire][dep.OutputInstance]) - nbDepsResolved[wireI]++ - } else { - //fmt.Print(" taking value from input") - assignments[wireI][instanceI].SetBigInt(assignmentVector[offsets[wireI]+instanceI-nbDepsResolved[wireI]]) - } - } else { - //fmt.Print("gated.") - // assemble the inputs - inputIndexes := info.Circuit[wireI].Inputs - for i, inputI := range inputIndexes { - inputs[i].Set(&assignments[inputI][instanceI]) - } - gate := solvingData.circuit[wireI].Gate - assignments[wireI][instanceI] = gate.Evaluate(inputs[:len(inputIndexes)]...) - } - //fmt.Println("\n\t\tresult: ", assignments[wireI][instanceI].Text(10)) - } - } - return assignments -} - -func toMapAssignment(circuit gkr.Circuit, assignment gkrAssignment) gkr.WireAssignment { - res := make(gkr.WireAssignment, len(circuit)) - for i := range circuit { - res[&circuit[i]] = assignment[i] - } - return res -} - -func gkrSetOutputValues(circuit []constraint.GkrWire, assignments gkrAssignment, outs []*big.Int) { - outsI := 0 - for i := range circuit { - if circuit[i].IsOutput() { - for j := range assignments[i] { - assignments[i][j].BigInt(outs[outsI]) - outsI++ - } - } - } - // Check if outsI == len(outs)? -} - -func gkrSolveHint(data constraint.GkrInfo, res *gkrSolvingData) hint.Function { - return func(_ *big.Int, ins, outs []*big.Int) error { - - res.circuit = convertCircuit(data.Circuit) // TODO: Take this out of here into the proving module - res.memoryPool = polynomial.NewPool(256, data.NbInstances) - - assignments := gkrSolve(data, *res, ins) - res.assignments = toMapAssignment(res.circuit, assignments) - gkrSetOutputValues(data.Circuit, assignments, outs) - - //fmt.Println("assignment ", sliceSliceToString(assignments)) - //fmt.Println("returning ", bigIntPtrSliceToString(outs)) - - return nil - } -} - -func bigIntPtrSliceToString(slice []*big.Int) []interface{} { - return algo_utils.Map(slice, func(e *big.Int) interface{} { - if e.IsInt64() { - return e.Int64() - } else { - return e.Text(10) - } - }) -} - -func sliceSliceToString(slice [][]fr.Element) string { - printable := make([]interface{}, len(slice)) - for i, s := range slice { - printable[i] = test_vector_utils.ElementSliceToInterfaceSlice(s) - } - res, err := json.Marshal(printable) - if err != nil { - panic(err.Error()) - } - return string(res) -} - -func frToBigInts(dst []*big.Int, src []fr.Element) { - for i := range src { - src[i].BigInt(dst[i]) - } -} - -func gkrProveHint(hashName string, data *gkrSolvingData) hint.Function { - - return func(_ *big.Int, ins, outs []*big.Int) error { - insBytes := algo_utils.Map(ins[1:], func(i *big.Int) []byte { // the first input is dummy, just to ensure the solver's work is done before the prover is called - b := i.Bytes() - return b[:] - }) - - hsh := HashBuilderRegistry[hashName]() - - proof, err := gkr.Prove(data.circuit, data.assignments, fiatshamir.WithHash(hsh, insBytes...), gkr.WithPool(&data.memoryPool)) // TODO: Do transcriptSettings properly - if err != nil { - return err - } - - // serialize proof: TODO: In gnark-crypto? - offset := 0 - for i := range proof { - for _, poly := range proof[i].PartialSumPolys { - frToBigInts(outs[offset:], poly) - offset += len(poly) - } - if proof[i].FinalEvalProof != nil { - finalEvalProof := proof[i].FinalEvalProof.([]fr.Element) - frToBigInts(outs[offset:], finalEvalProof) - offset += len(finalEvalProof) - } - } - return nil - - } -} - -func defineGkrHints(info constraint.GkrInfo, hintFunctions map[hint.ID]hint.Function) map[hint.ID]hint.Function { - res := make(map[hint.ID]hint.Function, len(hintFunctions)+2) - for k, v := range hintFunctions { - res[k] = v - } - var gkrData gkrSolvingData - res[info.SolveHintID] = gkrSolveHint(info, &gkrData) - res[info.ProveHintID] = gkrProveHint(info.HashName, &gkrData) - return res -} - -var GkrGateRegistry = map[string]gkr.Gate{ // TODO: Migrate to gnark-crypto - "mul": mulGate(2), - "add": addGate{}, - "sub": subGate{}, - "neg": negGate{}, -} - -// TODO: Move to gnark-crypto -var HashBuilderRegistry = make(map[string]func() hash.Hash) - -type mulGate int -type addGate struct{} -type subGate struct{} -type negGate struct{} - -func (g mulGate) Evaluate(x ...fr.Element) (res fr.Element) { - if len(x) != int(g) { - panic("wrong input count") - } - switch len(x) { - case 0: - res.SetOne() - case 1: - res.Set(&x[0]) - default: - res.Mul(&x[0], &x[1]) - for i := 2; i < len(x); i++ { - res.Mul(&res, &x[2]) - } - } - return -} - -func (g mulGate) Degree() int { - return int(g) -} - -func (g addGate) Evaluate(x ...fr.Element) (res fr.Element) { - switch len(x) { - case 0: - // set zero - case 1: - res.Set(&x[0]) - case 2: - res.Add(&x[0], &x[1]) - for i := 2; i < len(x); i++ { - res.Add(&res, &x[2]) - } - } - return -} - -func (g addGate) Degree() int { - return 1 -} - -func (g subGate) Evaluate(element ...fr.Element) (diff fr.Element) { - if len(element) > 2 { - panic("not implemented") //TODO - } - diff.Sub(&element[0], &element[1]) - return -} - -func (g subGate) Degree() int { - return 1 -} - -func (g negGate) Evaluate(element ...fr.Element) (neg fr.Element) { - if len(element) != 1 { - panic("univariate gate") - } - neg.Neg(&element[0]) - return -} - -func (g negGate) Degree() int { - return 1 -} diff --git a/internal/generator/backend/main.go b/internal/generator/backend/main.go index 64224cea5b..58f07ca4d4 100644 --- a/internal/generator/backend/main.go +++ b/internal/generator/backend/main.go @@ -108,12 +108,19 @@ func main() { {File: filepath.Join(csDir, "coeff.go"), Templates: []string{"coeff.go.tmpl", importCurve}}, {File: filepath.Join(csDir, "r1cs_sparse.go"), Templates: []string{"r1cs.sparse.go.tmpl", importCurve}}, {File: filepath.Join(csDir, "solution.go"), Templates: []string{"solution.go.tmpl", importCurve}}, - {File: filepath.Join(csDir, "gkr.go"), Templates: []string{"gkr.go.tmpl", importCurve}}, } if err := bgen.Generate(d, "cs", "./template/representations/", entries...); err != nil { panic(err) } + // gkr backend + if d.Curve != "tinyfield" { + entries = []bavard.Entry{{File: filepath.Join(csDir, "gkr.go"), Templates: []string{"gkr.go.tmpl", importCurve}}} + if err := bgen.Generate(d, "cs", "./template/representations/", entries...); err != nil { + panic(err) + } + } + entries = []bavard.Entry{ {File: filepath.Join(csDir, "r1cs_test.go"), Templates: []string{"tests/r1cs.go.tmpl", importCurve}}, } diff --git a/std/fiat-shamir/transcript.go b/std/fiat-shamir/transcript.go index ecdb295568..e8921422e1 100644 --- a/std/fiat-shamir/transcript.go +++ b/std/fiat-shamir/transcript.go @@ -72,10 +72,6 @@ func NewTranscript(api frontend.API, h hash.Hash, challengesID ...string) Transc // binded to other values. func (t *Transcript) Bind(challengeID string, values []frontend.Variable) error { - /*toPrint := []frontend.Variable{"snark binding to ", challengeID, ":"} - toPrint = append(toPrint, values...) - t.api.Println(toPrint...)*/ - challenge, ok := t.challenges[challengeID] if !ok { @@ -123,10 +119,6 @@ func (t *Transcript) ComputeChallenge(challengeID string) (frontend.Variable, er t.h.Write(t.previous.value) } - /*toPrint := []frontend.Variable{"snark bindings:"} - toPrint = append(toPrint, challenge.bindings...) - t.api.Println(toPrint...)*/ - // write the binded values in the order they were added t.h.Write(challenge.bindings...) @@ -138,12 +130,7 @@ func (t *Transcript) ComputeChallenge(challengeID string) (frontend.Variable, er t.challenges[challengeID] = challenge t.h.Reset() - /* - if valueInt, ok := challenge.value.(int); ok { - fmt.Printf("snark challenge \"%s\" <- %d\n", challengeID, valueInt) - } else { - t.api.Println("snark challenge \"", challengeID, "\" <- ", challenge.value) - }*/ + return challenge.value, nil } diff --git a/std/gkr/api_test.go b/std/gkr/api_test.go index 404c0f6f97..d4c082c155 100644 --- a/std/gkr/api_test.go +++ b/std/gkr/api_test.go @@ -241,31 +241,30 @@ func TestApiMul(t *testing.T) { test_vector_utils.AssertSliceEqual(t, api.toStore.Circuit[z].Inputs, []int{int(x), int(y)}) // TODO: Find out why assert.Equal gives false positives ( []*Wire{x,x} as second argument passes when it shouldn't ) } -/* - func BenchmarkMiMCMerkleTree(b *testing.B) { - depth := 14 - //fmt.Println("start") - bottom := make([]frontend.Variable, 1< Date: Fri, 20 Jan 2023 14:43:26 -0500 Subject: [PATCH 36/71] fix: no defineGkrHints for tinyfield and more --- constraint/bls12-377/gkr.go | 27 ------------------- constraint/bls12-377/r1cs.go | 1 - constraint/bls12-377/solution.go | 2 +- constraint/bls12-381/gkr.go | 27 ------------------- constraint/bls12-381/r1cs.go | 1 - constraint/bls12-381/solution.go | 2 +- constraint/bls24-315/gkr.go | 27 ------------------- constraint/bls24-315/r1cs.go | 1 - constraint/bls24-315/solution.go | 2 +- constraint/bls24-317/gkr.go | 27 ------------------- constraint/bls24-317/r1cs.go | 1 - constraint/bls24-317/solution.go | 2 +- constraint/bn254/gkr.go | 27 ------------------- constraint/bn254/r1cs.go | 1 - constraint/bn254/solution.go | 2 +- constraint/bw6-633/gkr.go | 27 ------------------- constraint/bw6-633/r1cs.go | 1 - constraint/bw6-633/solution.go | 2 +- constraint/bw6-761/gkr.go | 27 ------------------- constraint/bw6-761/r1cs.go | 1 - constraint/bw6-761/solution.go | 2 +- constraint/tinyfield/r1cs.go | 4 +-- constraint/tinyfield/solution.go | 2 +- .../template/representations/gkr.go.tmpl | 27 ------------------- .../template/representations/r1cs.go.tmpl | 6 ++++- .../template/representations/solution.go.tmpl | 2 +- internal/tinyfield/element.go | 1 - std/gkr/compile.go | 8 +++--- std/math/emulated/wrapped_api.go | 5 ++++ 29 files changed, 23 insertions(+), 242 deletions(-) diff --git a/constraint/bls12-377/gkr.go b/constraint/bls12-377/gkr.go index fb2a29e41b..1219b1da33 100644 --- a/constraint/bls12-377/gkr.go +++ b/constraint/bls12-377/gkr.go @@ -17,11 +17,9 @@ package cs import ( - "encoding/json" "github.com/consensys/gnark-crypto/ecc/bls12-377/fr" "github.com/consensys/gnark-crypto/ecc/bls12-377/fr/gkr" "github.com/consensys/gnark-crypto/ecc/bls12-377/fr/polynomial" - "github.com/consensys/gnark-crypto/ecc/bls12-377/fr/test_vector_utils" // TODO: Seems a bit dubious to use this here. Decide if okay fiatshamir "github.com/consensys/gnark-crypto/fiat-shamir" "github.com/consensys/gnark/backend/hint" "github.com/consensys/gnark/constraint" @@ -124,35 +122,10 @@ func gkrSolveHint(data constraint.GkrInfo, res *gkrSolvingData) hint.Function { res.assignments = toMapAssignment(res.circuit, assignments) gkrSetOutputValues(data.Circuit, assignments, outs) - //fmt.Println("assignment ", sliceSliceToString(assignments)) - //fmt.Println("returning ", bigIntPtrSliceToString(outs)) - return nil } } -func bigIntPtrSliceToString(slice []*big.Int) []interface{} { - return algo_utils.Map(slice, func(e *big.Int) interface{} { - if e.IsInt64() { - return e.Int64() - } else { - return e.Text(10) - } - }) -} - -func sliceSliceToString(slice [][]fr.Element) string { - printable := make([]interface{}, len(slice)) - for i, s := range slice { - printable[i] = test_vector_utils.ElementSliceToInterfaceSlice(s) - } - res, err := json.Marshal(printable) - if err != nil { - panic(err.Error()) - } - return string(res) -} - func frToBigInts(dst []*big.Int, src []fr.Element) { for i := range src { src[i].BigInt(dst[i]) diff --git a/constraint/bls12-377/r1cs.go b/constraint/bls12-377/r1cs.go index b9c52122d5..81f8250df1 100644 --- a/constraint/bls12-377/r1cs.go +++ b/constraint/bls12-377/r1cs.go @@ -85,7 +85,6 @@ func (cs *R1CS) Solve(witness, a, b, c []fr.Element, opt backend.ProverConfig) ( log := logger.Logger().With().Int("nbConstraints", len(cs.Constraints)).Str("backend", "groth16").Logger() nbWires := len(cs.Public) + len(cs.Secret) + cs.NbInternalVariables - hintFunctions := defineGkrHints(cs.GkrInfo, opt.HintFunctions) solution, err := newSolution(nbWires, hintFunctions, cs.MHintsDependencies, cs.MHints, cs.Coefficients, &cs.System.SymbolTable) diff --git a/constraint/bls12-377/solution.go b/constraint/bls12-377/solution.go index a34c2e2a87..8849a30acb 100644 --- a/constraint/bls12-377/solution.go +++ b/constraint/bls12-377/solution.go @@ -82,7 +82,7 @@ func (s *solution) isValid() bool { return int(s.nbSolved) == len(s.values) } -// computeTerm computes coef*variable +// computeTerm computes coeff*variable func (s *solution) computeTerm(t constraint.Term) fr.Element { cID, vID := t.CoeffID(), t.WireID() if cID != 0 && !s.solved[vID] { diff --git a/constraint/bls12-381/gkr.go b/constraint/bls12-381/gkr.go index 814d344872..8cc1f0382d 100644 --- a/constraint/bls12-381/gkr.go +++ b/constraint/bls12-381/gkr.go @@ -17,11 +17,9 @@ package cs import ( - "encoding/json" "github.com/consensys/gnark-crypto/ecc/bls12-381/fr" "github.com/consensys/gnark-crypto/ecc/bls12-381/fr/gkr" "github.com/consensys/gnark-crypto/ecc/bls12-381/fr/polynomial" - "github.com/consensys/gnark-crypto/ecc/bls12-381/fr/test_vector_utils" // TODO: Seems a bit dubious to use this here. Decide if okay fiatshamir "github.com/consensys/gnark-crypto/fiat-shamir" "github.com/consensys/gnark/backend/hint" "github.com/consensys/gnark/constraint" @@ -124,35 +122,10 @@ func gkrSolveHint(data constraint.GkrInfo, res *gkrSolvingData) hint.Function { res.assignments = toMapAssignment(res.circuit, assignments) gkrSetOutputValues(data.Circuit, assignments, outs) - //fmt.Println("assignment ", sliceSliceToString(assignments)) - //fmt.Println("returning ", bigIntPtrSliceToString(outs)) - return nil } } -func bigIntPtrSliceToString(slice []*big.Int) []interface{} { - return algo_utils.Map(slice, func(e *big.Int) interface{} { - if e.IsInt64() { - return e.Int64() - } else { - return e.Text(10) - } - }) -} - -func sliceSliceToString(slice [][]fr.Element) string { - printable := make([]interface{}, len(slice)) - for i, s := range slice { - printable[i] = test_vector_utils.ElementSliceToInterfaceSlice(s) - } - res, err := json.Marshal(printable) - if err != nil { - panic(err.Error()) - } - return string(res) -} - func frToBigInts(dst []*big.Int, src []fr.Element) { for i := range src { src[i].BigInt(dst[i]) diff --git a/constraint/bls12-381/r1cs.go b/constraint/bls12-381/r1cs.go index 2a9ff526f7..5fc71ba40e 100644 --- a/constraint/bls12-381/r1cs.go +++ b/constraint/bls12-381/r1cs.go @@ -85,7 +85,6 @@ func (cs *R1CS) Solve(witness, a, b, c []fr.Element, opt backend.ProverConfig) ( log := logger.Logger().With().Int("nbConstraints", len(cs.Constraints)).Str("backend", "groth16").Logger() nbWires := len(cs.Public) + len(cs.Secret) + cs.NbInternalVariables - hintFunctions := defineGkrHints(cs.GkrInfo, opt.HintFunctions) solution, err := newSolution(nbWires, hintFunctions, cs.MHintsDependencies, cs.MHints, cs.Coefficients, &cs.System.SymbolTable) diff --git a/constraint/bls12-381/solution.go b/constraint/bls12-381/solution.go index 74f60c23d2..dbf96fadc4 100644 --- a/constraint/bls12-381/solution.go +++ b/constraint/bls12-381/solution.go @@ -82,7 +82,7 @@ func (s *solution) isValid() bool { return int(s.nbSolved) == len(s.values) } -// computeTerm computes coef*variable +// computeTerm computes coeff*variable func (s *solution) computeTerm(t constraint.Term) fr.Element { cID, vID := t.CoeffID(), t.WireID() if cID != 0 && !s.solved[vID] { diff --git a/constraint/bls24-315/gkr.go b/constraint/bls24-315/gkr.go index 260caa790a..6853538d1d 100644 --- a/constraint/bls24-315/gkr.go +++ b/constraint/bls24-315/gkr.go @@ -17,11 +17,9 @@ package cs import ( - "encoding/json" "github.com/consensys/gnark-crypto/ecc/bls24-315/fr" "github.com/consensys/gnark-crypto/ecc/bls24-315/fr/gkr" "github.com/consensys/gnark-crypto/ecc/bls24-315/fr/polynomial" - "github.com/consensys/gnark-crypto/ecc/bls24-315/fr/test_vector_utils" // TODO: Seems a bit dubious to use this here. Decide if okay fiatshamir "github.com/consensys/gnark-crypto/fiat-shamir" "github.com/consensys/gnark/backend/hint" "github.com/consensys/gnark/constraint" @@ -124,35 +122,10 @@ func gkrSolveHint(data constraint.GkrInfo, res *gkrSolvingData) hint.Function { res.assignments = toMapAssignment(res.circuit, assignments) gkrSetOutputValues(data.Circuit, assignments, outs) - //fmt.Println("assignment ", sliceSliceToString(assignments)) - //fmt.Println("returning ", bigIntPtrSliceToString(outs)) - return nil } } -func bigIntPtrSliceToString(slice []*big.Int) []interface{} { - return algo_utils.Map(slice, func(e *big.Int) interface{} { - if e.IsInt64() { - return e.Int64() - } else { - return e.Text(10) - } - }) -} - -func sliceSliceToString(slice [][]fr.Element) string { - printable := make([]interface{}, len(slice)) - for i, s := range slice { - printable[i] = test_vector_utils.ElementSliceToInterfaceSlice(s) - } - res, err := json.Marshal(printable) - if err != nil { - panic(err.Error()) - } - return string(res) -} - func frToBigInts(dst []*big.Int, src []fr.Element) { for i := range src { src[i].BigInt(dst[i]) diff --git a/constraint/bls24-315/r1cs.go b/constraint/bls24-315/r1cs.go index 77fb42a20b..b5f3916d85 100644 --- a/constraint/bls24-315/r1cs.go +++ b/constraint/bls24-315/r1cs.go @@ -85,7 +85,6 @@ func (cs *R1CS) Solve(witness, a, b, c []fr.Element, opt backend.ProverConfig) ( log := logger.Logger().With().Int("nbConstraints", len(cs.Constraints)).Str("backend", "groth16").Logger() nbWires := len(cs.Public) + len(cs.Secret) + cs.NbInternalVariables - hintFunctions := defineGkrHints(cs.GkrInfo, opt.HintFunctions) solution, err := newSolution(nbWires, hintFunctions, cs.MHintsDependencies, cs.MHints, cs.Coefficients, &cs.System.SymbolTable) diff --git a/constraint/bls24-315/solution.go b/constraint/bls24-315/solution.go index 5f018c69b8..f65a2821b1 100644 --- a/constraint/bls24-315/solution.go +++ b/constraint/bls24-315/solution.go @@ -82,7 +82,7 @@ func (s *solution) isValid() bool { return int(s.nbSolved) == len(s.values) } -// computeTerm computes coef*variable +// computeTerm computes coeff*variable func (s *solution) computeTerm(t constraint.Term) fr.Element { cID, vID := t.CoeffID(), t.WireID() if cID != 0 && !s.solved[vID] { diff --git a/constraint/bls24-317/gkr.go b/constraint/bls24-317/gkr.go index 42b85ab61f..515f64bcda 100644 --- a/constraint/bls24-317/gkr.go +++ b/constraint/bls24-317/gkr.go @@ -17,11 +17,9 @@ package cs import ( - "encoding/json" "github.com/consensys/gnark-crypto/ecc/bls24-317/fr" "github.com/consensys/gnark-crypto/ecc/bls24-317/fr/gkr" "github.com/consensys/gnark-crypto/ecc/bls24-317/fr/polynomial" - "github.com/consensys/gnark-crypto/ecc/bls24-317/fr/test_vector_utils" // TODO: Seems a bit dubious to use this here. Decide if okay fiatshamir "github.com/consensys/gnark-crypto/fiat-shamir" "github.com/consensys/gnark/backend/hint" "github.com/consensys/gnark/constraint" @@ -124,35 +122,10 @@ func gkrSolveHint(data constraint.GkrInfo, res *gkrSolvingData) hint.Function { res.assignments = toMapAssignment(res.circuit, assignments) gkrSetOutputValues(data.Circuit, assignments, outs) - //fmt.Println("assignment ", sliceSliceToString(assignments)) - //fmt.Println("returning ", bigIntPtrSliceToString(outs)) - return nil } } -func bigIntPtrSliceToString(slice []*big.Int) []interface{} { - return algo_utils.Map(slice, func(e *big.Int) interface{} { - if e.IsInt64() { - return e.Int64() - } else { - return e.Text(10) - } - }) -} - -func sliceSliceToString(slice [][]fr.Element) string { - printable := make([]interface{}, len(slice)) - for i, s := range slice { - printable[i] = test_vector_utils.ElementSliceToInterfaceSlice(s) - } - res, err := json.Marshal(printable) - if err != nil { - panic(err.Error()) - } - return string(res) -} - func frToBigInts(dst []*big.Int, src []fr.Element) { for i := range src { src[i].BigInt(dst[i]) diff --git a/constraint/bls24-317/r1cs.go b/constraint/bls24-317/r1cs.go index 3c7fa4246a..a2bdc12b74 100644 --- a/constraint/bls24-317/r1cs.go +++ b/constraint/bls24-317/r1cs.go @@ -85,7 +85,6 @@ func (cs *R1CS) Solve(witness, a, b, c []fr.Element, opt backend.ProverConfig) ( log := logger.Logger().With().Int("nbConstraints", len(cs.Constraints)).Str("backend", "groth16").Logger() nbWires := len(cs.Public) + len(cs.Secret) + cs.NbInternalVariables - hintFunctions := defineGkrHints(cs.GkrInfo, opt.HintFunctions) solution, err := newSolution(nbWires, hintFunctions, cs.MHintsDependencies, cs.MHints, cs.Coefficients, &cs.System.SymbolTable) diff --git a/constraint/bls24-317/solution.go b/constraint/bls24-317/solution.go index ef035c4826..d26c56f931 100644 --- a/constraint/bls24-317/solution.go +++ b/constraint/bls24-317/solution.go @@ -82,7 +82,7 @@ func (s *solution) isValid() bool { return int(s.nbSolved) == len(s.values) } -// computeTerm computes coef*variable +// computeTerm computes coeff*variable func (s *solution) computeTerm(t constraint.Term) fr.Element { cID, vID := t.CoeffID(), t.WireID() if cID != 0 && !s.solved[vID] { diff --git a/constraint/bn254/gkr.go b/constraint/bn254/gkr.go index e257f7b946..28396cb456 100644 --- a/constraint/bn254/gkr.go +++ b/constraint/bn254/gkr.go @@ -17,11 +17,9 @@ package cs import ( - "encoding/json" "github.com/consensys/gnark-crypto/ecc/bn254/fr" "github.com/consensys/gnark-crypto/ecc/bn254/fr/gkr" "github.com/consensys/gnark-crypto/ecc/bn254/fr/polynomial" - "github.com/consensys/gnark-crypto/ecc/bn254/fr/test_vector_utils" // TODO: Seems a bit dubious to use this here. Decide if okay fiatshamir "github.com/consensys/gnark-crypto/fiat-shamir" "github.com/consensys/gnark/backend/hint" "github.com/consensys/gnark/constraint" @@ -124,35 +122,10 @@ func gkrSolveHint(data constraint.GkrInfo, res *gkrSolvingData) hint.Function { res.assignments = toMapAssignment(res.circuit, assignments) gkrSetOutputValues(data.Circuit, assignments, outs) - //fmt.Println("assignment ", sliceSliceToString(assignments)) - //fmt.Println("returning ", bigIntPtrSliceToString(outs)) - return nil } } -func bigIntPtrSliceToString(slice []*big.Int) []interface{} { - return algo_utils.Map(slice, func(e *big.Int) interface{} { - if e.IsInt64() { - return e.Int64() - } else { - return e.Text(10) - } - }) -} - -func sliceSliceToString(slice [][]fr.Element) string { - printable := make([]interface{}, len(slice)) - for i, s := range slice { - printable[i] = test_vector_utils.ElementSliceToInterfaceSlice(s) - } - res, err := json.Marshal(printable) - if err != nil { - panic(err.Error()) - } - return string(res) -} - func frToBigInts(dst []*big.Int, src []fr.Element) { for i := range src { src[i].BigInt(dst[i]) diff --git a/constraint/bn254/r1cs.go b/constraint/bn254/r1cs.go index fc620bbcb9..a6e942077c 100644 --- a/constraint/bn254/r1cs.go +++ b/constraint/bn254/r1cs.go @@ -85,7 +85,6 @@ func (cs *R1CS) Solve(witness, a, b, c []fr.Element, opt backend.ProverConfig) ( log := logger.Logger().With().Int("nbConstraints", len(cs.Constraints)).Str("backend", "groth16").Logger() nbWires := len(cs.Public) + len(cs.Secret) + cs.NbInternalVariables - hintFunctions := defineGkrHints(cs.GkrInfo, opt.HintFunctions) solution, err := newSolution(nbWires, hintFunctions, cs.MHintsDependencies, cs.MHints, cs.Coefficients, &cs.System.SymbolTable) diff --git a/constraint/bn254/solution.go b/constraint/bn254/solution.go index 690ffc879f..3346fc9f1c 100644 --- a/constraint/bn254/solution.go +++ b/constraint/bn254/solution.go @@ -82,7 +82,7 @@ func (s *solution) isValid() bool { return int(s.nbSolved) == len(s.values) } -// computeTerm computes coef*variable +// computeTerm computes coeff*variable func (s *solution) computeTerm(t constraint.Term) fr.Element { cID, vID := t.CoeffID(), t.WireID() if cID != 0 && !s.solved[vID] { diff --git a/constraint/bw6-633/gkr.go b/constraint/bw6-633/gkr.go index 392c06d5ea..7657a64543 100644 --- a/constraint/bw6-633/gkr.go +++ b/constraint/bw6-633/gkr.go @@ -17,11 +17,9 @@ package cs import ( - "encoding/json" "github.com/consensys/gnark-crypto/ecc/bw6-633/fr" "github.com/consensys/gnark-crypto/ecc/bw6-633/fr/gkr" "github.com/consensys/gnark-crypto/ecc/bw6-633/fr/polynomial" - "github.com/consensys/gnark-crypto/ecc/bw6-633/fr/test_vector_utils" // TODO: Seems a bit dubious to use this here. Decide if okay fiatshamir "github.com/consensys/gnark-crypto/fiat-shamir" "github.com/consensys/gnark/backend/hint" "github.com/consensys/gnark/constraint" @@ -124,35 +122,10 @@ func gkrSolveHint(data constraint.GkrInfo, res *gkrSolvingData) hint.Function { res.assignments = toMapAssignment(res.circuit, assignments) gkrSetOutputValues(data.Circuit, assignments, outs) - //fmt.Println("assignment ", sliceSliceToString(assignments)) - //fmt.Println("returning ", bigIntPtrSliceToString(outs)) - return nil } } -func bigIntPtrSliceToString(slice []*big.Int) []interface{} { - return algo_utils.Map(slice, func(e *big.Int) interface{} { - if e.IsInt64() { - return e.Int64() - } else { - return e.Text(10) - } - }) -} - -func sliceSliceToString(slice [][]fr.Element) string { - printable := make([]interface{}, len(slice)) - for i, s := range slice { - printable[i] = test_vector_utils.ElementSliceToInterfaceSlice(s) - } - res, err := json.Marshal(printable) - if err != nil { - panic(err.Error()) - } - return string(res) -} - func frToBigInts(dst []*big.Int, src []fr.Element) { for i := range src { src[i].BigInt(dst[i]) diff --git a/constraint/bw6-633/r1cs.go b/constraint/bw6-633/r1cs.go index 83ed427e5c..7ad1ba3c10 100644 --- a/constraint/bw6-633/r1cs.go +++ b/constraint/bw6-633/r1cs.go @@ -85,7 +85,6 @@ func (cs *R1CS) Solve(witness, a, b, c []fr.Element, opt backend.ProverConfig) ( log := logger.Logger().With().Int("nbConstraints", len(cs.Constraints)).Str("backend", "groth16").Logger() nbWires := len(cs.Public) + len(cs.Secret) + cs.NbInternalVariables - hintFunctions := defineGkrHints(cs.GkrInfo, opt.HintFunctions) solution, err := newSolution(nbWires, hintFunctions, cs.MHintsDependencies, cs.MHints, cs.Coefficients, &cs.System.SymbolTable) diff --git a/constraint/bw6-633/solution.go b/constraint/bw6-633/solution.go index aba13f6d22..aea0b28a49 100644 --- a/constraint/bw6-633/solution.go +++ b/constraint/bw6-633/solution.go @@ -82,7 +82,7 @@ func (s *solution) isValid() bool { return int(s.nbSolved) == len(s.values) } -// computeTerm computes coef*variable +// computeTerm computes coeff*variable func (s *solution) computeTerm(t constraint.Term) fr.Element { cID, vID := t.CoeffID(), t.WireID() if cID != 0 && !s.solved[vID] { diff --git a/constraint/bw6-761/gkr.go b/constraint/bw6-761/gkr.go index 21a07c4344..40ea107700 100644 --- a/constraint/bw6-761/gkr.go +++ b/constraint/bw6-761/gkr.go @@ -17,11 +17,9 @@ package cs import ( - "encoding/json" "github.com/consensys/gnark-crypto/ecc/bw6-761/fr" "github.com/consensys/gnark-crypto/ecc/bw6-761/fr/gkr" "github.com/consensys/gnark-crypto/ecc/bw6-761/fr/polynomial" - "github.com/consensys/gnark-crypto/ecc/bw6-761/fr/test_vector_utils" // TODO: Seems a bit dubious to use this here. Decide if okay fiatshamir "github.com/consensys/gnark-crypto/fiat-shamir" "github.com/consensys/gnark/backend/hint" "github.com/consensys/gnark/constraint" @@ -124,35 +122,10 @@ func gkrSolveHint(data constraint.GkrInfo, res *gkrSolvingData) hint.Function { res.assignments = toMapAssignment(res.circuit, assignments) gkrSetOutputValues(data.Circuit, assignments, outs) - //fmt.Println("assignment ", sliceSliceToString(assignments)) - //fmt.Println("returning ", bigIntPtrSliceToString(outs)) - return nil } } -func bigIntPtrSliceToString(slice []*big.Int) []interface{} { - return algo_utils.Map(slice, func(e *big.Int) interface{} { - if e.IsInt64() { - return e.Int64() - } else { - return e.Text(10) - } - }) -} - -func sliceSliceToString(slice [][]fr.Element) string { - printable := make([]interface{}, len(slice)) - for i, s := range slice { - printable[i] = test_vector_utils.ElementSliceToInterfaceSlice(s) - } - res, err := json.Marshal(printable) - if err != nil { - panic(err.Error()) - } - return string(res) -} - func frToBigInts(dst []*big.Int, src []fr.Element) { for i := range src { src[i].BigInt(dst[i]) diff --git a/constraint/bw6-761/r1cs.go b/constraint/bw6-761/r1cs.go index a4ddc703a7..dc46dc0a0e 100644 --- a/constraint/bw6-761/r1cs.go +++ b/constraint/bw6-761/r1cs.go @@ -85,7 +85,6 @@ func (cs *R1CS) Solve(witness, a, b, c []fr.Element, opt backend.ProverConfig) ( log := logger.Logger().With().Int("nbConstraints", len(cs.Constraints)).Str("backend", "groth16").Logger() nbWires := len(cs.Public) + len(cs.Secret) + cs.NbInternalVariables - hintFunctions := defineGkrHints(cs.GkrInfo, opt.HintFunctions) solution, err := newSolution(nbWires, hintFunctions, cs.MHintsDependencies, cs.MHints, cs.Coefficients, &cs.System.SymbolTable) diff --git a/constraint/bw6-761/solution.go b/constraint/bw6-761/solution.go index f82b98e0c9..54e9eee0bb 100644 --- a/constraint/bw6-761/solution.go +++ b/constraint/bw6-761/solution.go @@ -82,7 +82,7 @@ func (s *solution) isValid() bool { return int(s.nbSolved) == len(s.values) } -// computeTerm computes coef*variable +// computeTerm computes coeff*variable func (s *solution) computeTerm(t constraint.Term) fr.Element { cID, vID := t.CoeffID(), t.WireID() if cID != 0 && !s.solved[vID] { diff --git a/constraint/tinyfield/r1cs.go b/constraint/tinyfield/r1cs.go index 7b84b8c628..308d3e162b 100644 --- a/constraint/tinyfield/r1cs.go +++ b/constraint/tinyfield/r1cs.go @@ -85,9 +85,7 @@ func (cs *R1CS) Solve(witness, a, b, c []fr.Element, opt backend.ProverConfig) ( log := logger.Logger().With().Int("nbConstraints", len(cs.Constraints)).Str("backend", "groth16").Logger() nbWires := len(cs.Public) + len(cs.Secret) + cs.NbInternalVariables - - hintFunctions := defineGkrHints(cs.GkrInfo, opt.HintFunctions) - solution, err := newSolution(nbWires, hintFunctions, cs.MHintsDependencies, cs.MHints, cs.Coefficients, &cs.System.SymbolTable) + solution, err := newSolution(nbWires, opt.HintFunctions, cs.MHintsDependencies, cs.MHints, cs.Coefficients, &cs.System.SymbolTable) if err != nil { return make([]fr.Element, nbWires), err diff --git a/constraint/tinyfield/solution.go b/constraint/tinyfield/solution.go index 7fd9dbc8f8..2f5eb4caec 100644 --- a/constraint/tinyfield/solution.go +++ b/constraint/tinyfield/solution.go @@ -82,7 +82,7 @@ func (s *solution) isValid() bool { return int(s.nbSolved) == len(s.values) } -// computeTerm computes coef*variable +// computeTerm computes coeff*variable func (s *solution) computeTerm(t constraint.Term) fr.Element { cID, vID := t.CoeffID(), t.WireID() if cID != 0 && !s.solved[vID] { diff --git a/internal/generator/backend/template/representations/gkr.go.tmpl b/internal/generator/backend/template/representations/gkr.go.tmpl index abf5f7a64b..c0c92e6c85 100644 --- a/internal/generator/backend/template/representations/gkr.go.tmpl +++ b/internal/generator/backend/template/representations/gkr.go.tmpl @@ -1,9 +1,7 @@ import ( - "encoding/json" {{- template "import_fr" .}} {{- template "import_gkr" .}} {{- template "import_polynomial" .}} - "github.com/consensys/gnark-crypto/ecc/{{ toLower .Curve }}/fr/test_vector_utils" // TODO: Seems a bit dubious to use this here. Decide if okay fiatshamir "github.com/consensys/gnark-crypto/fiat-shamir" "github.com/consensys/gnark/backend/hint" "github.com/consensys/gnark/constraint" @@ -106,35 +104,10 @@ func gkrSolveHint(data constraint.GkrInfo, res *gkrSolvingData) hint.Function { res.assignments = toMapAssignment(res.circuit, assignments) gkrSetOutputValues(data.Circuit, assignments, outs) - //fmt.Println("assignment ", sliceSliceToString(assignments)) - //fmt.Println("returning ", bigIntPtrSliceToString(outs)) - return nil } } -func bigIntPtrSliceToString(slice []*big.Int) []interface{} { - return algo_utils.Map(slice, func(e *big.Int) interface{} { - if e.IsInt64() { - return e.Int64() - } else { - return e.Text(10) - } - }) -} - -func sliceSliceToString(slice [][]fr.Element) string { - printable := make([]interface{}, len(slice)) - for i, s := range slice { - printable[i] = test_vector_utils.ElementSliceToInterfaceSlice(s) - } - res, err := json.Marshal(printable) - if err != nil { - panic(err.Error()) - } - return string(res) -} - func frToBigInts(dst []*big.Int, src []fr.Element) { for i := range src { src[i].BigInt(dst[i]) diff --git a/internal/generator/backend/template/representations/r1cs.go.tmpl b/internal/generator/backend/template/representations/r1cs.go.tmpl index 5462dd1061..a61b829942 100644 --- a/internal/generator/backend/template/representations/r1cs.go.tmpl +++ b/internal/generator/backend/template/representations/r1cs.go.tmpl @@ -70,8 +70,12 @@ func (cs *R1CS) Solve(witness, a, b, c []fr.Element, opt backend.ProverConfig) ( nbWires := len(cs.Public) + len(cs.Secret) + cs.NbInternalVariables + {{- $hintFunctions := "opt.HintFunctions"}} + {{- if ne .Curve "tinyfield"}} hintFunctions := defineGkrHints(cs.GkrInfo, opt.HintFunctions) - solution, err := newSolution(nbWires, hintFunctions, cs.MHintsDependencies, cs.MHints, cs.Coefficients, &cs.System.SymbolTable) + {{- $hintFunctions = "hintFunctions"}} + {{- end}} + solution, err := newSolution(nbWires, {{$hintFunctions}}, cs.MHintsDependencies, cs.MHints, cs.Coefficients, &cs.System.SymbolTable) if err != nil { return make([]fr.Element, nbWires), err diff --git a/internal/generator/backend/template/representations/solution.go.tmpl b/internal/generator/backend/template/representations/solution.go.tmpl index cf2ef77192..e323a614f5 100644 --- a/internal/generator/backend/template/representations/solution.go.tmpl +++ b/internal/generator/backend/template/representations/solution.go.tmpl @@ -63,7 +63,7 @@ func (s *solution) isValid() bool { return int(s.nbSolved) == len(s.values) } -// computeTerm computes coef*variable +// computeTerm computes coeff*variable func (s *solution) computeTerm(t constraint.Term) fr.Element { cID, vID := t.CoeffID(), t.WireID() if cID != 0 && !s.solved[vID] { diff --git a/internal/tinyfield/element.go b/internal/tinyfield/element.go index f9d1e70862..c30cc10254 100644 --- a/internal/tinyfield/element.go +++ b/internal/tinyfield/element.go @@ -755,7 +755,6 @@ func (z *Element) SetBigInt(v *big.Int) *Element { vv := field.BigIntPool.Get() // copy input + modular reduction - vv.Set(v) vv.Mod(v, &_modulus) // set big int byte value diff --git a/std/gkr/compile.go b/std/gkr/compile.go index 53ad8198fe..0fda7f779e 100644 --- a/std/gkr/compile.go +++ b/std/gkr/compile.go @@ -33,10 +33,6 @@ func (api *API) nbInstances() int { return api.assignments.NbInstances() } -func (api *API) logNbInstances() int { - return log2(uint(api.nbInstances())) -} - func NewApi() *API { return &API{ toStore: constraint.GkrInfo{ @@ -189,7 +185,9 @@ func (s Solution) Verify(hashName string, initialChallenges ...frontend.Variable } var hsh hash.Hash - hsh, err = hash.BuilderRegistry[hashName](s.parentApi) + if hsh, err = hash.BuilderRegistry[hashName](s.parentApi); err != nil { + return err + } s.toStore.HashName = hashName err = Verify(s.parentApi, forSnark.circuit, forSnark.assignments, proof, fiatshamir.WithHash(hsh, initialChallenges...), WithSortedCircuit(forSnarkSorted)) diff --git a/std/math/emulated/wrapped_api.go b/std/math/emulated/wrapped_api.go index aa433d249d..9ebe2c43c2 100644 --- a/std/math/emulated/wrapped_api.go +++ b/std/math/emulated/wrapped_api.go @@ -3,6 +3,7 @@ package emulated import ( "errors" "fmt" + "github.com/consensys/gnark/constraint" "math/big" "github.com/consensys/gnark/backend/hint" @@ -411,6 +412,10 @@ func (w *FieldAPI[T]) MarkBoolean(v frontend.Variable) { } } +func (w *FieldAPI[T]) SetGkrInfo(constraint.GkrInfo) error { + return fmt.Errorf("not implemented") +} + // --- non-API methods func (w *FieldAPI[T]) Reduce(i1 frontend.Variable) frontend.Variable { From 37d5aaa0fab5dcfb93fb5ecd95f74fd5e92a04d9 Mon Sep 17 00:00:00 2001 From: Arya Tabaie Date: Fri, 20 Jan 2023 19:59:49 -0500 Subject: [PATCH 37/71] fix: mod tidy --- go.mod | 6 +----- go.sum | 10 ---------- 2 files changed, 1 insertion(+), 15 deletions(-) diff --git a/go.mod b/go.mod index 75c4d2b8f0..c17c804140 100644 --- a/go.mod +++ b/go.mod @@ -5,7 +5,7 @@ go 1.18 require ( github.com/blang/semver/v4 v4.0.0 github.com/consensys/bavard v0.1.13 - github.com/consensys/gnark-crypto v0.8.1-0.20221220191316-4b7364bddab8 + github.com/consensys/gnark-crypto v0.9.0 github.com/ethereum/go-ethereum v1.10.26 github.com/fxamacker/cbor/v2 v2.2.0 github.com/google/go-cmp v0.5.8 @@ -23,13 +23,9 @@ require ( github.com/kr/pretty v0.3.0 // indirect github.com/mmcloughlin/addchain v0.4.0 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect - github.com/samlitowitz/goimportcycle v1.0.4 // indirect github.com/x448/float16 v0.8.4 // indirect golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa // indirect - golang.org/x/mod v0.7.0 // indirect golang.org/x/sys v0.2.0 // indirect - golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect - gonum.org/v1/gonum v0.12.0 // indirect gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect gopkg.in/yaml.v3 v3.0.1 // indirect rsc.io/tmplfunc v0.0.3 // indirect diff --git a/go.sum b/go.sum index 7a03941bfa..6073552fbd 100644 --- a/go.sum +++ b/go.sum @@ -5,8 +5,6 @@ github.com/btcsuite/btcd/btcec/v2 v2.2.0/go.mod h1:U7MHm051Al6XmscBQ0BoNydpOTsFA github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1 h1:q0rUy8C/TYNBQS1+CGKw68tLOFYSNEs0TFnxxnS9+4U= github.com/consensys/bavard v0.1.13 h1:oLhMLOFGTLdlda/kma4VOJazblc7IM5y5QPd2A/YjhQ= github.com/consensys/bavard v0.1.13/go.mod h1:9ItSMtA/dXMAiL7BG6bqW2m3NdSEObYWoH223nGHukI= -github.com/consensys/gnark-crypto v0.8.1-0.20221220191316-4b7364bddab8 h1:Ij6UQpKx4/Ox6L6qFPk8NhEnTsYCEXlILnh+1Hi1grY= -github.com/consensys/gnark-crypto v0.8.1-0.20221220191316-4b7364bddab8/go.mod h1:CkbdF9hbRidRJYMRzmfX8TMOr95I2pYXRHF18MzRrvA= github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -47,8 +45,6 @@ github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTE github.com/rs/xid v1.3.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg= github.com/rs/zerolog v1.26.1 h1:/ihwxqH+4z8UxyI70wM1z9yCvkWcfz/a3mj48k/Zngc= github.com/rs/zerolog v1.26.1/go.mod h1:/wSSJWX7lVrsOwlbyTRSOJvqRlc+WjWlfes+CiJ+tmc= -github.com/samlitowitz/goimportcycle v1.0.4 h1:GE1sl60DsmcMH+tgx6suF0jmSvChb7EY8zwC8/OP04g= -github.com/samlitowitz/goimportcycle v1.0.4/go.mod h1:Wbq8jmeCIFyP/A3deG1wzVHs5O4g0mQiMhQnYNq1p2A= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= @@ -65,8 +61,6 @@ golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0 golang.org/x/exp v0.0.0-20220713135740-79cabaa25d75 h1:x03zeu7B2B11ySp+daztnwM5oBJ/8wGUSqrwcw9L0RA= golang.org/x/exp v0.0.0-20220713135740-79cabaa25d75/go.mod h1:Kr81I6Kryrl9sr8s2FK3vxD90NdsKWRuOIl2O4CvYbA= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.7.0 h1:LapD9S96VoQRhi/GrNTqeBJFrUjs5UHCAtTlgwA5oZA= -golang.org/x/mod v0.7.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= @@ -90,10 +84,6 @@ golang.org/x/tools v0.1.7/go.mod h1:LGqMHiF4EqQNHR1JncWGqT5BVaXmza+X+BDGol+dOxo= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 h1:H2TDz8ibqkAF6YGhCdN3jS9O0/s90v0rJh3X/OLHEUk= -golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= -gonum.org/v1/gonum v0.12.0 h1:xKuo6hzt+gMav00meVPUlXwSdoEJP46BR+wdxQEFK2o= -gonum.org/v1/gonum v0.12.0/go.mod h1:73TDxJfAAHeA8Mk9mf8NlIppyhQNo5GLTcYeqgo2lvY= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= From 6f885a9b3e9b65321e94945a4fbfa7b432aed96c Mon Sep 17 00:00:00 2001 From: Arya Tabaie Date: Mon, 23 Jan 2023 09:44:44 -0500 Subject: [PATCH 38/71] fix: go mod tidy --- go.sum | 2 ++ 1 file changed, 2 insertions(+) diff --git a/go.sum b/go.sum index 6073552fbd..c20e7bc42d 100644 --- a/go.sum +++ b/go.sum @@ -5,6 +5,8 @@ github.com/btcsuite/btcd/btcec/v2 v2.2.0/go.mod h1:U7MHm051Al6XmscBQ0BoNydpOTsFA github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1 h1:q0rUy8C/TYNBQS1+CGKw68tLOFYSNEs0TFnxxnS9+4U= github.com/consensys/bavard v0.1.13 h1:oLhMLOFGTLdlda/kma4VOJazblc7IM5y5QPd2A/YjhQ= github.com/consensys/bavard v0.1.13/go.mod h1:9ItSMtA/dXMAiL7BG6bqW2m3NdSEObYWoH223nGHukI= +github.com/consensys/gnark-crypto v0.9.0 h1:xspjHTygkgHmX4Behn00VJUTfEGvs+e6lFlfERfA28E= +github.com/consensys/gnark-crypto v0.9.0/go.mod h1:CkbdF9hbRidRJYMRzmfX8TMOr95I2pYXRHF18MzRrvA= github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= From 6466829fc5d569dbe2ea40eabfbe31365f2592fe Mon Sep 17 00:00:00 2001 From: Arya Tabaie Date: Mon, 23 Jan 2023 13:43:45 -0500 Subject: [PATCH 39/71] refactor: some cleanup - bn254 only --- constraint/bn254/gkr.go | 121 ++++++++++++++++++++-------------------- std/gkr/api_test.go | 10 ++-- 2 files changed, 67 insertions(+), 64 deletions(-) diff --git a/constraint/bn254/gkr.go b/constraint/bn254/gkr.go index 28396cb456..ce44301dd8 100644 --- a/constraint/bn254/gkr.go +++ b/constraint/bn254/gkr.go @@ -43,68 +43,36 @@ func convertCircuit(noPtr constraint.GkrCircuit) gkr.Circuit { return resCircuit } -// this module assumes that wire and instance indexes respect dependencies - -type gkrAssignment [][]fr.Element //gkrAssignment is indexed wire first, instance second - -// assumes assignmentVector is arranged wire first, instance second in order of solution -func gkrSolve(info constraint.GkrInfo, solvingData gkrSolvingData, assignmentVector []*big.Int) gkrAssignment { - circuit := info.Circuit - nbInstances := info.NbInstances - offsets := info.AssignmentOffsets() - nbDepsResolved := make([]int, len(circuit)) - inputs := make([]fr.Element, info.MaxNIns) - - assignments := make(gkrAssignment, len(circuit)) - for i := range assignments { - assignments[i] = make([]fr.Element, nbInstances) +func (d *gkrSolvingData) init(info constraint.GkrInfo) gkrAssignment { + d.memoryPool = polynomial.NewPool(256, info.NbInstances) + d.circuit = convertCircuit(info.Circuit) + + assignmentsSequential := make(gkrAssignment, len(d.circuit)) + d.assignments = make(gkr.WireAssignment, len(d.circuit)) + for i := range assignmentsSequential { + assignmentsSequential[i] = d.memoryPool.Make(info.NbInstances) + d.assignments[&d.circuit[i]] = assignmentsSequential[i] } - for instanceI := 0; instanceI < nbInstances; instanceI++ { - //fmt.Println("instance", instanceI) - for wireI, wire := range circuit { - //fmt.Print("\twire ", wireI, ": ") - if wire.IsInput() { - //fmt.Print("input.") - if nbDepsResolved[wireI] < len(wire.Dependencies) && instanceI == wire.Dependencies[nbDepsResolved[wireI]].InputInstance { - //fmt.Print(" copying value from dependency") - dep := wire.Dependencies[nbDepsResolved[wireI]] - assignments[wireI][instanceI].Set(&assignments[dep.OutputWire][dep.OutputInstance]) - nbDepsResolved[wireI]++ - } else { - //fmt.Print(" taking value from input") - assignments[wireI][instanceI].SetBigInt(assignmentVector[offsets[wireI]+instanceI-nbDepsResolved[wireI]]) - } - } else { - //fmt.Print("gated.") - // assemble the inputs - inputIndexes := info.Circuit[wireI].Inputs - for i, inputI := range inputIndexes { - inputs[i].Set(&assignments[inputI][instanceI]) - } - gate := solvingData.circuit[wireI].Gate - assignments[wireI][instanceI] = gate.Evaluate(inputs[:len(inputIndexes)]...) - } - //fmt.Println("\n\t\tresult: ", assignments[wireI][instanceI].Text(10)) - } - } - return assignments + return assignmentsSequential } -func toMapAssignment(circuit gkr.Circuit, assignment gkrAssignment) gkr.WireAssignment { - res := make(gkr.WireAssignment, len(circuit)) - for i := range circuit { - res[&circuit[i]] = assignment[i] +func (d *gkrSolvingData) dumpAssignments() { + for _, p := range d.assignments { + d.memoryPool.Dump(p) } - return res } -func gkrSetOutputValues(circuit []constraint.GkrWire, assignments gkrAssignment, outs []*big.Int) { +// this module assumes that wire and instance indexes respect dependencies + +type gkrAssignment [][]fr.Element //gkrAssignment is indexed wire first, instance second + +func (a gkrAssignment) setOuts(circuit constraint.GkrCircuit, outs []*big.Int) { outsI := 0 for i := range circuit { if circuit[i].IsOutput() { - for j := range assignments[i] { - assignments[i][j].BigInt(outs[outsI]) + for j := range a[i] { + a[i][j].BigInt(outs[outsI]) outsI++ } } @@ -112,16 +80,47 @@ func gkrSetOutputValues(circuit []constraint.GkrWire, assignments gkrAssignment, // Check if outsI == len(outs)? } -func gkrSolveHint(data constraint.GkrInfo, res *gkrSolvingData) hint.Function { +func gkrSolveHint(info constraint.GkrInfo, solvingData *gkrSolvingData) hint.Function { return func(_ *big.Int, ins, outs []*big.Int) error { - res.circuit = convertCircuit(data.Circuit) // TODO: Take this out of here into the proving module - res.memoryPool = polynomial.NewPool(256, data.NbInstances) - - assignments := gkrSolve(data, *res, ins) - res.assignments = toMapAssignment(res.circuit, assignments) - gkrSetOutputValues(data.Circuit, assignments, outs) + // assumes assignmentVector is arranged wire first, instance second in order of solution + circuit := info.Circuit + nbInstances := info.NbInstances + offsets := info.AssignmentOffsets() + nbDepsResolved := make([]int, len(circuit)) + inputs := make([]fr.Element, info.MaxNIns) + assignment := solvingData.init(info) + + for instanceI := 0; instanceI < nbInstances; instanceI++ { + //fmt.Println("instance", instanceI) TODO Remove prints + for wireI, wire := range circuit { + //fmt.Print("\twire ", wireI, ": ") + if wire.IsInput() { + //fmt.Print("input.") + if nbDepsResolved[wireI] < len(wire.Dependencies) && instanceI == wire.Dependencies[nbDepsResolved[wireI]].InputInstance { + //fmt.Print(" copying value from dependency") + dep := wire.Dependencies[nbDepsResolved[wireI]] + assignment[wireI][instanceI].Set(&assignment[dep.OutputWire][dep.OutputInstance]) + nbDepsResolved[wireI]++ + } else { + //fmt.Print(" taking value from input") + assignment[wireI][instanceI].SetBigInt(ins[offsets[wireI]+instanceI-nbDepsResolved[wireI]]) + } + } else { + //fmt.Print("gated.") + // assemble the inputs + inputIndexes := info.Circuit[wireI].Inputs + for i, inputI := range inputIndexes { + inputs[i].Set(&assignment[inputI][instanceI]) + } + gate := solvingData.circuit[wireI].Gate + assignment[wireI][instanceI] = gate.Evaluate(inputs[:len(inputIndexes)]...) + } + //fmt.Println("\n\t\tresult: ", assignment[wireI][instanceI].Text(10)) + } + } + assignment.setOuts(info.Circuit, outs) return nil } } @@ -160,6 +159,9 @@ func gkrProveHint(hashName string, data *gkrSolvingData) hint.Function { offset += len(finalEvalProof) } } + + data.dumpAssignments() + return nil } @@ -170,6 +172,7 @@ func defineGkrHints(info constraint.GkrInfo, hintFunctions map[hint.ID]hint.Func for k, v := range hintFunctions { res[k] = v } + var gkrData gkrSolvingData res[info.SolveHintID] = gkrSolveHint(info, &gkrData) res[info.ProveHintID] = gkrProveHint(info.HashName, &gkrData) diff --git a/std/gkr/api_test.go b/std/gkr/api_test.go index d4c082c155..3f6584e30f 100644 --- a/std/gkr/api_test.go +++ b/std/gkr/api_test.go @@ -274,7 +274,7 @@ func solveB(b *testing.B, circuit, assignment frontend.Circuit) { pk, _, err := groth16.Setup(cs) assert.NoError(b, err) - //b.ResetTimer() + b.ResetTimer() _, err = groth16.Prove(cs, pk, fullWitness) assert.NoError(b, err) //fmt.Println("done") @@ -540,9 +540,9 @@ func BenchmarkMiMCNoDep(b *testing.B) { X: make([]frontend.Variable, nbInstances), Y: make([]frontend.Variable, nbInstances), } - b.ResetTimer() - for i := 0; i < b.N; i++ { - solveB(b, &circuit, &assignment) - } + //fmt.Println(b.N) + //for i := 0; i < b.N; i++ { + solveB(b, &circuit, &assignment) + //} } From 095ce409f03b1aec664ec36f59755553de0dc1b9 Mon Sep 17 00:00:00 2001 From: Arya Tabaie Date: Tue, 24 Jan 2023 13:44:50 -0500 Subject: [PATCH 40/71] fix: a small bug and some new benchmarks --- std/gkr/api_test.go | 153 ++++++++++++++++++++++++++++++++------------ std/gkr/compile.go | 9 ++- std/gkr/gkr.go | 9 ++- 3 files changed, 127 insertions(+), 44 deletions(-) diff --git a/std/gkr/api_test.go b/std/gkr/api_test.go index 3f6584e30f..b436ee254e 100644 --- a/std/gkr/api_test.go +++ b/std/gkr/api_test.go @@ -16,8 +16,10 @@ import ( "github.com/consensys/gnark/std/utils/test_vectors_utils" "github.com/stretchr/testify/assert" "hash" + "math/rand" "strconv" "testing" + "time" ) type doubleNoDependencyCircuit struct { @@ -60,7 +62,7 @@ func TestDoubleNoDependencyCircuit(t *testing.T) { assignment := doubleNoDependencyCircuit{X: xValues} circuit := doubleNoDependencyCircuit{X: make([]frontend.Variable, len(xValues)), hashName: hashName} - solve(t, &circuit, &assignment) + testE2E(t, &circuit, &assignment) } } } @@ -104,7 +106,7 @@ func TestSqNoDependencyCircuit(t *testing.T) { for _, hashName := range hashes { assignment := sqNoDependencyCircuit{X: xValues} circuit := sqNoDependencyCircuit{X: make([]frontend.Variable, len(xValues)), hashName: hashName} - solve(t, &circuit, &assignment) + testE2E(t, &circuit, &assignment) } } } @@ -166,7 +168,7 @@ func TestMulNoDependency(t *testing.T) { hashName: hashName, } - solve(t, &circuit, &assignment) + testE2E(t, &circuit, &assignment) } } } @@ -215,14 +217,13 @@ func (c *mulWithDependencyCircuit) Define(api frontend.API) error { } func TestSolveMulWithDependency(t *testing.T) { - assignment := mulWithDependencyCircuit{ XLast: 1, Y: []frontend.Variable{3, 2}, } circuit := mulWithDependencyCircuit{Y: make([]frontend.Variable, len(assignment.Y)), hashName: "-20"} - solve(t, &circuit, &assignment) + testE2E(t, &circuit, &assignment) } func TestApiMul(t *testing.T) { @@ -262,23 +263,43 @@ func BenchmarkMiMCMerkleTree(b *testing.B) { YBottom: make([]frontend.Variable, len(assignment.YBottom)), } - solveB(b, &circuit, &assignment) + benchProof(b, &circuit, &assignment) +} + +func benchCompile(b *testing.B, circuit frontend.Circuit) { + b.ResetTimer() + for i := 0; i < b.N; i++ { + _, err := frontend.Compile(ecc.BN254.ScalarField(), r1cs.NewBuilder, circuit) + assert.NoError(b, err) + } } -func solveB(b *testing.B, circuit, assignment frontend.Circuit) { +func benchProof(b *testing.B, circuit, assignment frontend.Circuit) { + fmt.Println("compiling...") + start := time.Now().UnixMicro() cs, err := frontend.Compile(ecc.BN254.ScalarField(), r1cs.NewBuilder, circuit) assert.NoError(b, err) + fmt.Println("compiled in", time.Now().UnixMicro()-start, "μs") fullWitness, err := frontend.NewWitness(assignment, ecc.BN254.ScalarField()) assert.NoError(b, err) //publicWitness := fullWitness.Public() + fmt.Println("setting up...") pk, _, err := groth16.Setup(cs) assert.NoError(b, err) + fmt.Println("solving and proving...") b.ResetTimer() - _, err = groth16.Prove(cs, pk, fullWitness) - assert.NoError(b, err) - //fmt.Println("done") - fmt.Println("mimc total calls: fr=", mimcFrTotalCalls, ", snark=", mimcSnarkTotalCalls) + + for i := 0; i < b.N; i++ { + id := rand.Uint32() % 256 + start = time.Now().UnixMicro() + fmt.Println("groth16 proving", id) + _, err = groth16.Prove(cs, pk, fullWitness) + assert.NoError(b, err) + fmt.Println("groth16 proved", id, "in", time.Now().UnixMicro()-start, "μs") + + fmt.Println("mimc total calls: fr=", mimcFrTotalCalls, ", snark=", mimcSnarkTotalCalls) + } } type benchMiMCMerkleTreeCircuit struct { @@ -342,7 +363,7 @@ func (c *benchMiMCMerkleTreeCircuit) Define(api frontend.API) error { return solution.Verify("-20", challenge) } -func solve(t *testing.T, circuit, assignment frontend.Circuit) { +func testE2E(t *testing.T, circuit, assignment frontend.Circuit) { cs, err := frontend.Compile(ecc.BN254.ScalarField(), r1cs.NewBuilder, circuit) assert.NoError(t, err) var ( @@ -454,44 +475,50 @@ func (m mimcCipherGate) Degree() int { return 7 } -type mimcNoGkrNoDepCircuit struct { - X []frontend.Variable - Y []frontend.Variable +type mimcNoGkrCircuit struct { + X []frontend.Variable + Y []frontend.Variable + mimcDepth int } -func (c *mimcNoGkrNoDepCircuit) Define(api frontend.API) error { +func (c *mimcNoGkrCircuit) Define(api frontend.API) error { Z := make([]frontend.Variable, len(c.X)) zSum := frontend.Variable(0) for i := range Z { - Z[i] = MiMCCipherGate{Ark: 0}.Evaluate(api, c.X[i], c.Y[i]) + Z[i] = c.Y[i] + for j := 0; j < c.mimcDepth; j++ { + Z[i] = MiMCCipherGate{Ark: 0}.Evaluate(api, c.X[i], Z[i]) + } zSum = api.Add(zSum, Z[i]) } api.AssertIsDifferent(zSum, 0) return nil } -func BenchmarkMiMCNoGkrNoDep(b *testing.B) { - nbInstances := 1 << 14 +func BenchmarkMiMCMerkleTreeNoGkrNoDep(b *testing.B) { + nbInstances := 1 << 18 X := make([]frontend.Variable, nbInstances) Y := make([]frontend.Variable, nbInstances) for i := range X { X[i] = i Y[i] = -2*i + 1 } - assignment := mimcNoGkrNoDepCircuit{ + assignment := mimcNoGkrCircuit{ X: X, Y: Y, } - circuit := mimcNoGkrNoDepCircuit{ + circuit := mimcNoGkrCircuit{ X: make([]frontend.Variable, nbInstances), Y: make([]frontend.Variable, nbInstances), } - solveB(b, &circuit, &assignment) + + benchProof(b, &circuit, &assignment) } type mimcNoDepCircuit struct { - X []frontend.Variable - Y []frontend.Variable + X []frontend.Variable + Y []frontend.Variable + mimcDepth int } func (c *mimcNoDepCircuit) Define(api frontend.API) error { @@ -509,12 +536,15 @@ func (c *mimcNoDepCircuit) Define(api frontend.API) error { } // cheat{ - _gkr.toStore.Circuit = append(_gkr.toStore.Circuit, constraint.GkrWire{ - Gate: "mimc", - Inputs: []int{int(x), int(y)}, - }) - _gkr.assignments = append(_gkr.assignments, nil) - z = constraint.GkrVariable(2) + z = y + for i := 0; i < c.mimcDepth; i++ { + _gkr.toStore.Circuit = append(_gkr.toStore.Circuit, constraint.GkrWire{ + Gate: "mimc", + Inputs: []int{int(x), int(z)}, + }) + _gkr.assignments = append(_gkr.assignments, nil) + z = constraint.GkrVariable(len(_gkr.toStore.Circuit) - 1) + } // } if solution, err = _gkr.Solve(api); err != nil { @@ -524,25 +554,68 @@ func (c *mimcNoDepCircuit) Define(api frontend.API) error { return solution.Verify("-20", Z...) } -func BenchmarkMiMCNoDep(b *testing.B) { - nbInstances := 1 << 14 +func mimcNoDepCircuits(mimcDepth, nbInstances int) (circuit, assignment frontend.Circuit) { X := make([]frontend.Variable, nbInstances) Y := make([]frontend.Variable, nbInstances) for i := range X { X[i] = i Y[i] = -2*i + 1 } - assignment := mimcNoDepCircuit{ + assignment = &mimcNoDepCircuit{ X: X, Y: Y, } - circuit := mimcNoDepCircuit{ - X: make([]frontend.Variable, nbInstances), - Y: make([]frontend.Variable, nbInstances), + circuit = &mimcNoDepCircuit{ + X: make([]frontend.Variable, nbInstances), + Y: make([]frontend.Variable, nbInstances), + mimcDepth: mimcDepth, + } + return +} + +func BenchmarkMiMCNoDepSolve(b *testing.B) { + //defer profile.Start().Stop() + circuit, assignment := mimcNoDepCircuits(1, 1<<9) + benchProof(b, circuit, assignment) +} + +func BenchmarkMiMCFullDepthNoDepSolve(b *testing.B) { + circuit, assignment := mimcNoDepCircuits(91, 1<<14) + benchProof(b, circuit, assignment) +} + +func BenchmarkMiMCFullDepthNoDepCompile(b *testing.B) { + circuit, _ := mimcNoDepCircuits(91, 1<<17) + benchCompile(b, circuit) +} + +func BenchmarkMiMCNoGkrFullDepthSolve(b *testing.B) { + circuit, assignment := mimcNoGkrCircuits(91, 1<<14) + benchProof(b, circuit, assignment) +} + +func TestMiMCFullDepthNoDepSolve(t *testing.T) { + for i := 0; i < 100; i++ { + circuit, assignment := mimcNoDepCircuits(5, 1<<2) + testE2E(t, circuit, assignment) } +} - //fmt.Println(b.N) - //for i := 0; i < b.N; i++ { - solveB(b, &circuit, &assignment) - //} +func mimcNoGkrCircuits(mimcDepth, nbInstances int) (circuit, assignment frontend.Circuit) { + X := make([]frontend.Variable, nbInstances) + Y := make([]frontend.Variable, nbInstances) + for i := range X { + X[i] = i + Y[i] = -2*i + 1 + } + assignment = &mimcNoGkrCircuit{ + X: X, + Y: Y, + } + circuit = &mimcNoGkrCircuit{ + X: make([]frontend.Variable, nbInstances), + Y: make([]frontend.Variable, nbInstances), + mimcDepth: mimcDepth, + } + return } diff --git a/std/gkr/compile.go b/std/gkr/compile.go index 0fda7f779e..4b7a719dd9 100644 --- a/std/gkr/compile.go +++ b/std/gkr/compile.go @@ -212,6 +212,13 @@ func slicePtrAt[T any](slice []T) func(int) *T { } } +func ite[T any](condition bool, ifNot, IfSo T) T { + if condition { + return IfSo + } + return ifNot +} + func newCircuitDataForSnark(info constraint.GkrInfo, assignment assignment) circuitDataForSnark { circuit := make(Circuit, len(info.Circuit)) snarkAssignment := make(WireAssignment, len(info.Circuit)) @@ -219,7 +226,7 @@ func newCircuitDataForSnark(info constraint.GkrInfo, assignment assignment) circ for i := range circuit { w := info.Circuit[i] circuit[i] = Wire{ - Gate: RegisteredGates[w.Gate], + Gate: ite(w.IsInput(), RegisteredGates[w.Gate], Gate(IdentityGate{})), Inputs: algo_utils.Map(w.Inputs, circuitAt), nbUniqueOutputs: w.NbUniqueOutputs, } diff --git a/std/gkr/gkr.go b/std/gkr/gkr.go index 489127660c..e10e0c98b5 100644 --- a/std/gkr/gkr.go +++ b/std/gkr/gkr.go @@ -23,7 +23,6 @@ type Wire struct { Gate Gate Inputs []*Wire // if there are no Inputs, the wire is assumed an input wire nbUniqueOutputs int // number of other wires using it as input, not counting duplicates (i.e. providing two inputs to the same gate counts as one) - //nbUniqueInputs int // number of inputs, not counting duplicates } type Circuit []Wire @@ -452,14 +451,18 @@ func topologicalSort(c Circuit) []*Wire { func (a WireAssignment) NumInstances() int { for _, aW := range a { - return len(aW) + if aW != nil { + return len(aW) + } } panic("empty assignment") } func (a WireAssignment) NumVars() int { for _, aW := range a { - return aW.NumVars() + if aW != nil { + return aW.NumVars() + } } panic("empty assignment") } From cd98156e7b0f3d0d0b1175ea23d07a44349c81ba Mon Sep 17 00:00:00 2001 From: Gautam Botrel Date: Tue, 24 Jan 2023 14:59:05 -0600 Subject: [PATCH 41/71] perf: replace Add(Mul) by MulAdd --- std/polynomial/polynomial.go | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/std/polynomial/polynomial.go b/std/polynomial/polynomial.go index f5a9155d2e..7086a7e130 100644 --- a/std/polynomial/polynomial.go +++ b/std/polynomial/polynomial.go @@ -1,8 +1,9 @@ package polynomial import ( - "github.com/consensys/gnark/frontend" "math/bits" + + "github.com/consensys/gnark/frontend" ) type Polynomial []frontend.Variable @@ -24,10 +25,7 @@ func (m MultiLin) Evaluate(api frontend.API, at []frontend.Variable) frontend.Va evaluation := frontend.Variable(0) for j := range m { - evaluation = api.Add( - evaluation, - api.Mul(eqs[j], m[j]), - ) + evaluation = api.MulAcc(evaluation, eqs[j], m[j]) } return evaluation } From f5d3e0b8477f7a75437b698ec25a5ab2fb06339b Mon Sep 17 00:00:00 2001 From: Gautam Botrel Date: Tue, 24 Jan 2023 15:01:47 -0600 Subject: [PATCH 42/71] perf: add frontend.WithCompressThreshold in compile test opts --- std/gkr/api_test.go | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/std/gkr/api_test.go b/std/gkr/api_test.go index b436ee254e..56cab8ab18 100644 --- a/std/gkr/api_test.go +++ b/std/gkr/api_test.go @@ -2,6 +2,12 @@ package gkr import ( "fmt" + "hash" + "math/rand" + "strconv" + "testing" + "time" + "github.com/consensys/gnark-crypto/ecc" "github.com/consensys/gnark-crypto/ecc/bn254/fr" bn254MiMC "github.com/consensys/gnark-crypto/ecc/bn254/fr/mimc" @@ -13,15 +19,15 @@ import ( "github.com/consensys/gnark/frontend/cs/r1cs" stdHash "github.com/consensys/gnark/std/hash" "github.com/consensys/gnark/std/hash/mimc" - "github.com/consensys/gnark/std/utils/test_vectors_utils" + test_vector_utils "github.com/consensys/gnark/std/utils/test_vectors_utils" "github.com/stretchr/testify/assert" - "hash" - "math/rand" - "strconv" - "testing" - "time" ) +// compressThreshold --> if linear expressions are larger than this, the frontend will introduce +// intermediate constraints. The lower this number is, the faster compile time should be (to a point) +// but resulting circuit will have more constraints (slower proving time). +const compressThreshold = 1000 + type doubleNoDependencyCircuit struct { X []frontend.Variable hashName string @@ -269,7 +275,7 @@ func BenchmarkMiMCMerkleTree(b *testing.B) { func benchCompile(b *testing.B, circuit frontend.Circuit) { b.ResetTimer() for i := 0; i < b.N; i++ { - _, err := frontend.Compile(ecc.BN254.ScalarField(), r1cs.NewBuilder, circuit) + _, err := frontend.Compile(ecc.BN254.ScalarField(), r1cs.NewBuilder, circuit, frontend.WithCompressThreshold(compressThreshold)) assert.NoError(b, err) } } @@ -277,7 +283,7 @@ func benchCompile(b *testing.B, circuit frontend.Circuit) { func benchProof(b *testing.B, circuit, assignment frontend.Circuit) { fmt.Println("compiling...") start := time.Now().UnixMicro() - cs, err := frontend.Compile(ecc.BN254.ScalarField(), r1cs.NewBuilder, circuit) + cs, err := frontend.Compile(ecc.BN254.ScalarField(), r1cs.NewBuilder, circuit, frontend.WithCompressThreshold(compressThreshold)) assert.NoError(b, err) fmt.Println("compiled in", time.Now().UnixMicro()-start, "μs") fullWitness, err := frontend.NewWitness(assignment, ecc.BN254.ScalarField()) @@ -364,7 +370,7 @@ func (c *benchMiMCMerkleTreeCircuit) Define(api frontend.API) error { } func testE2E(t *testing.T, circuit, assignment frontend.Circuit) { - cs, err := frontend.Compile(ecc.BN254.ScalarField(), r1cs.NewBuilder, circuit) + cs, err := frontend.Compile(ecc.BN254.ScalarField(), r1cs.NewBuilder, circuit, frontend.WithCompressThreshold(compressThreshold)) assert.NoError(t, err) var ( fullWitness *witness.Witness From 9dd1f2bc00f05c96c334a0dbe6a1d3a1eccf321f Mon Sep 17 00:00:00 2001 From: Gautam Botrel Date: Tue, 24 Jan 2023 15:22:33 -0600 Subject: [PATCH 43/71] perf: replace intSet by bitset --- go.mod | 1 + go.sum | 2 ++ std/utils/algo_utils/algo_utils.go | 40 ++++++------------------------ 3 files changed, 11 insertions(+), 32 deletions(-) diff --git a/go.mod b/go.mod index 0106258f35..455d136232 100644 --- a/go.mod +++ b/go.mod @@ -17,6 +17,7 @@ require ( ) require ( + github.com/bits-and-blooms/bitset v1.5.0 // indirect github.com/btcsuite/btcd/btcec/v2 v2.2.0 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1 // indirect diff --git a/go.sum b/go.sum index c20e7bc42d..b98459742f 100644 --- a/go.sum +++ b/go.sum @@ -1,3 +1,5 @@ +github.com/bits-and-blooms/bitset v1.5.0 h1:NpE8frKRLGHIcEzkR+gZhiioW1+WbYV6fKwD6ZIpQT8= +github.com/bits-and-blooms/bitset v1.5.0/go.mod h1:gIdJ4wp64HaoK2YrL1Q5/N7Y16edYb8uY+O0FJTyyDA= github.com/blang/semver/v4 v4.0.0 h1:1PFHFE6yCCTv8C1TeyNNarDzntLi7wMI5i/pzqYIsAM= github.com/blang/semver/v4 v4.0.0/go.mod h1:IbckMUScFkM3pff0VJDNKRiT6TG/YpiHIM2yvyW5YoQ= github.com/btcsuite/btcd/btcec/v2 v2.2.0 h1:fzn1qaOt32TuLjFlkzYSsBC35Q3KUjT1SwPxiMSCF5k= diff --git a/std/utils/algo_utils/algo_utils.go b/std/utils/algo_utils/algo_utils.go index 5d7df927ad..9beab1ab97 100644 --- a/std/utils/algo_utils/algo_utils.go +++ b/std/utils/algo_utils/algo_utils.go @@ -1,5 +1,7 @@ package algo_utils +import "github.com/bits-and-blooms/bitset" + // this package provides some generic (in both senses of the word) algorithmic conveniences. // Permute operates in-place but is not thread-safe; it uses the permutation for scratching @@ -104,17 +106,19 @@ func newTopSortData(inputs [][]int) topSortData { for i := range res.uniqueOutputs { res.uniqueOutputs[i] = make([]int, 0) } - inputsISet := newIntSet(size) //if size is large, a map to struct{} might serve better + + inputsISet := bitset.New(uint(size)) for i := range res.uniqueOutputs { if i != 0 { - inputsISet.clear() + inputsISet.ClearAll() } for _, in := range inputs[i] { - if !inputsISet.put(in) { + if !inputsISet.Test(uint(in)) { + inputsISet.Set(uint(in)) res.uniqueOutputs[in] = append(res.uniqueOutputs[in], i) } } - res.status[i] = inputsISet.len() + res.status[i] = int(inputsISet.Count()) } for res.status[res.leastReady] != 0 { @@ -139,31 +143,3 @@ func (d *topSortData) markDone(i int) { d.leastReady++ } } - -type intSet struct { - contains []bool - length int -} - -func newIntSet(capacity int) intSet { //if capacity is large, a map to struct{} might serve better - return intSet{contains: make([]bool, capacity)} -} - -func (s *intSet) clear() { - for i := range s.contains { - s.contains[i] = false - } - s.length = 0 -} - -func (s *intSet) put(i int) (alreadyContains bool) { - if alreadyContains = s.contains[i]; !alreadyContains { - s.length++ - } - s.contains[i] = true - return -} - -func (s *intSet) len() int { - return s.length -} From 85cf4f7e2baaf8c388c3dc3067087137f7d7387d Mon Sep 17 00:00:00 2001 From: Gautam Botrel Date: Tue, 24 Jan 2023 15:28:39 -0600 Subject: [PATCH 44/71] perf: use cpt in topo sort --- std/utils/algo_utils/algo_utils.go | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/std/utils/algo_utils/algo_utils.go b/std/utils/algo_utils/algo_utils.go index 9beab1ab97..f94bb8eda5 100644 --- a/std/utils/algo_utils/algo_utils.go +++ b/std/utils/algo_utils/algo_utils.go @@ -103,22 +103,21 @@ func newTopSortData(inputs [][]int) topSortData { status: make([]int, size), leastReady: 0, } - for i := range res.uniqueOutputs { - res.uniqueOutputs[i] = make([]int, 0) - } inputsISet := bitset.New(uint(size)) for i := range res.uniqueOutputs { if i != 0 { inputsISet.ClearAll() } + cpt := 0 for _, in := range inputs[i] { if !inputsISet.Test(uint(in)) { inputsISet.Set(uint(in)) + cpt++ res.uniqueOutputs[in] = append(res.uniqueOutputs[in], i) } } - res.status[i] = int(inputsISet.Count()) + res.status[i] = cpt } for res.status[res.leastReady] != 0 { From a4fe824f1e5cf014da708462486d0185dc8a66de Mon Sep 17 00:00:00 2001 From: Gautam Botrel Date: Tue, 24 Jan 2023 15:30:22 -0600 Subject: [PATCH 45/71] build: make linter happy --- std/gkr/api_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/std/gkr/api_test.go b/std/gkr/api_test.go index 56cab8ab18..3fc5a93dff 100644 --- a/std/gkr/api_test.go +++ b/std/gkr/api_test.go @@ -297,7 +297,7 @@ func benchProof(b *testing.B, circuit, assignment frontend.Circuit) { b.ResetTimer() for i := 0; i < b.N; i++ { - id := rand.Uint32() % 256 + id := rand.Uint32() % 256 //#nosec G404 -- This is a false positive start = time.Now().UnixMicro() fmt.Println("groth16 proving", id) _, err = groth16.Prove(cs, pk, fullWitness) From c3a7f27ba3c66301370992276aafa87bc3222f22 Mon Sep 17 00:00:00 2001 From: Gautam Botrel Date: Tue, 24 Jan 2023 15:37:38 -0600 Subject: [PATCH 46/71] build: reran go generate --- constraint/bn254/gkr.go | 121 ++++++++++++++++++++-------------------- go.mod | 2 +- 2 files changed, 60 insertions(+), 63 deletions(-) diff --git a/constraint/bn254/gkr.go b/constraint/bn254/gkr.go index ce44301dd8..28396cb456 100644 --- a/constraint/bn254/gkr.go +++ b/constraint/bn254/gkr.go @@ -43,36 +43,68 @@ func convertCircuit(noPtr constraint.GkrCircuit) gkr.Circuit { return resCircuit } -func (d *gkrSolvingData) init(info constraint.GkrInfo) gkrAssignment { - d.memoryPool = polynomial.NewPool(256, info.NbInstances) - d.circuit = convertCircuit(info.Circuit) - - assignmentsSequential := make(gkrAssignment, len(d.circuit)) - d.assignments = make(gkr.WireAssignment, len(d.circuit)) - for i := range assignmentsSequential { - assignmentsSequential[i] = d.memoryPool.Make(info.NbInstances) - d.assignments[&d.circuit[i]] = assignmentsSequential[i] +// this module assumes that wire and instance indexes respect dependencies + +type gkrAssignment [][]fr.Element //gkrAssignment is indexed wire first, instance second + +// assumes assignmentVector is arranged wire first, instance second in order of solution +func gkrSolve(info constraint.GkrInfo, solvingData gkrSolvingData, assignmentVector []*big.Int) gkrAssignment { + circuit := info.Circuit + nbInstances := info.NbInstances + offsets := info.AssignmentOffsets() + nbDepsResolved := make([]int, len(circuit)) + inputs := make([]fr.Element, info.MaxNIns) + + assignments := make(gkrAssignment, len(circuit)) + for i := range assignments { + assignments[i] = make([]fr.Element, nbInstances) } - return assignmentsSequential + for instanceI := 0; instanceI < nbInstances; instanceI++ { + //fmt.Println("instance", instanceI) + for wireI, wire := range circuit { + //fmt.Print("\twire ", wireI, ": ") + if wire.IsInput() { + //fmt.Print("input.") + if nbDepsResolved[wireI] < len(wire.Dependencies) && instanceI == wire.Dependencies[nbDepsResolved[wireI]].InputInstance { + //fmt.Print(" copying value from dependency") + dep := wire.Dependencies[nbDepsResolved[wireI]] + assignments[wireI][instanceI].Set(&assignments[dep.OutputWire][dep.OutputInstance]) + nbDepsResolved[wireI]++ + } else { + //fmt.Print(" taking value from input") + assignments[wireI][instanceI].SetBigInt(assignmentVector[offsets[wireI]+instanceI-nbDepsResolved[wireI]]) + } + } else { + //fmt.Print("gated.") + // assemble the inputs + inputIndexes := info.Circuit[wireI].Inputs + for i, inputI := range inputIndexes { + inputs[i].Set(&assignments[inputI][instanceI]) + } + gate := solvingData.circuit[wireI].Gate + assignments[wireI][instanceI] = gate.Evaluate(inputs[:len(inputIndexes)]...) + } + //fmt.Println("\n\t\tresult: ", assignments[wireI][instanceI].Text(10)) + } + } + return assignments } -func (d *gkrSolvingData) dumpAssignments() { - for _, p := range d.assignments { - d.memoryPool.Dump(p) +func toMapAssignment(circuit gkr.Circuit, assignment gkrAssignment) gkr.WireAssignment { + res := make(gkr.WireAssignment, len(circuit)) + for i := range circuit { + res[&circuit[i]] = assignment[i] } + return res } -// this module assumes that wire and instance indexes respect dependencies - -type gkrAssignment [][]fr.Element //gkrAssignment is indexed wire first, instance second - -func (a gkrAssignment) setOuts(circuit constraint.GkrCircuit, outs []*big.Int) { +func gkrSetOutputValues(circuit []constraint.GkrWire, assignments gkrAssignment, outs []*big.Int) { outsI := 0 for i := range circuit { if circuit[i].IsOutput() { - for j := range a[i] { - a[i][j].BigInt(outs[outsI]) + for j := range assignments[i] { + assignments[i][j].BigInt(outs[outsI]) outsI++ } } @@ -80,47 +112,16 @@ func (a gkrAssignment) setOuts(circuit constraint.GkrCircuit, outs []*big.Int) { // Check if outsI == len(outs)? } -func gkrSolveHint(info constraint.GkrInfo, solvingData *gkrSolvingData) hint.Function { +func gkrSolveHint(data constraint.GkrInfo, res *gkrSolvingData) hint.Function { return func(_ *big.Int, ins, outs []*big.Int) error { - // assumes assignmentVector is arranged wire first, instance second in order of solution - circuit := info.Circuit - nbInstances := info.NbInstances - offsets := info.AssignmentOffsets() - nbDepsResolved := make([]int, len(circuit)) - inputs := make([]fr.Element, info.MaxNIns) - assignment := solvingData.init(info) - - for instanceI := 0; instanceI < nbInstances; instanceI++ { - //fmt.Println("instance", instanceI) TODO Remove prints - for wireI, wire := range circuit { - //fmt.Print("\twire ", wireI, ": ") - if wire.IsInput() { - //fmt.Print("input.") - if nbDepsResolved[wireI] < len(wire.Dependencies) && instanceI == wire.Dependencies[nbDepsResolved[wireI]].InputInstance { - //fmt.Print(" copying value from dependency") - dep := wire.Dependencies[nbDepsResolved[wireI]] - assignment[wireI][instanceI].Set(&assignment[dep.OutputWire][dep.OutputInstance]) - nbDepsResolved[wireI]++ - } else { - //fmt.Print(" taking value from input") - assignment[wireI][instanceI].SetBigInt(ins[offsets[wireI]+instanceI-nbDepsResolved[wireI]]) - } - } else { - //fmt.Print("gated.") - // assemble the inputs - inputIndexes := info.Circuit[wireI].Inputs - for i, inputI := range inputIndexes { - inputs[i].Set(&assignment[inputI][instanceI]) - } - gate := solvingData.circuit[wireI].Gate - assignment[wireI][instanceI] = gate.Evaluate(inputs[:len(inputIndexes)]...) - } - //fmt.Println("\n\t\tresult: ", assignment[wireI][instanceI].Text(10)) - } - } + res.circuit = convertCircuit(data.Circuit) // TODO: Take this out of here into the proving module + res.memoryPool = polynomial.NewPool(256, data.NbInstances) + + assignments := gkrSolve(data, *res, ins) + res.assignments = toMapAssignment(res.circuit, assignments) + gkrSetOutputValues(data.Circuit, assignments, outs) - assignment.setOuts(info.Circuit, outs) return nil } } @@ -159,9 +160,6 @@ func gkrProveHint(hashName string, data *gkrSolvingData) hint.Function { offset += len(finalEvalProof) } } - - data.dumpAssignments() - return nil } @@ -172,7 +170,6 @@ func defineGkrHints(info constraint.GkrInfo, hintFunctions map[hint.ID]hint.Func for k, v := range hintFunctions { res[k] = v } - var gkrData gkrSolvingData res[info.SolveHintID] = gkrSolveHint(info, &gkrData) res[info.ProveHintID] = gkrProveHint(info.HashName, &gkrData) diff --git a/go.mod b/go.mod index 455d136232..6dd3fe466e 100644 --- a/go.mod +++ b/go.mod @@ -3,6 +3,7 @@ module github.com/consensys/gnark go 1.18 require ( + github.com/bits-and-blooms/bitset v1.5.0 github.com/blang/semver/v4 v4.0.0 github.com/consensys/bavard v0.1.13 github.com/consensys/gnark-crypto v0.9.0 @@ -17,7 +18,6 @@ require ( ) require ( - github.com/bits-and-blooms/bitset v1.5.0 // indirect github.com/btcsuite/btcd/btcec/v2 v2.2.0 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1 // indirect From 2f02f7287d7bf6c9f834256e57f310c8f5d0d7c8 Mon Sep 17 00:00:00 2001 From: Gautam Botrel Date: Tue, 24 Jan 2023 15:49:02 -0600 Subject: [PATCH 47/71] perf: factorize MultiLin.Evaluate hot loop --- std/polynomial/polynomial.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/std/polynomial/polynomial.go b/std/polynomial/polynomial.go index 7086a7e130..72cc329f9f 100644 --- a/std/polynomial/polynomial.go +++ b/std/polynomial/polynomial.go @@ -16,10 +16,9 @@ func (m MultiLin) Evaluate(api frontend.API, at []frontend.Variable) frontend.Va eqs[0] = 1 for i, rI := range at { prevSize := 1 << i - oneMinusRI := api.Sub(1, rI) for j := prevSize - 1; j >= 0; j-- { eqs[2*j+1] = api.Mul(rI, eqs[j]) - eqs[2*j] = api.Mul(oneMinusRI, eqs[j]) + eqs[2*j] = api.Sub(eqs[j], eqs[2*j+1]) // eq[2j] == (1 - rI) * eq[j] } } From 788d6cf297b394fdd32e8978e1e9e665f941788c Mon Sep 17 00:00:00 2001 From: Arya Tabaie Date: Tue, 24 Jan 2023 17:27:29 -0500 Subject: [PATCH 48/71] revert: bn254/gkr changes --- constraint/bn254/gkr.go | 121 ++++++++++++++++++++-------------------- 1 file changed, 62 insertions(+), 59 deletions(-) diff --git a/constraint/bn254/gkr.go b/constraint/bn254/gkr.go index 28396cb456..ce44301dd8 100644 --- a/constraint/bn254/gkr.go +++ b/constraint/bn254/gkr.go @@ -43,68 +43,36 @@ func convertCircuit(noPtr constraint.GkrCircuit) gkr.Circuit { return resCircuit } -// this module assumes that wire and instance indexes respect dependencies - -type gkrAssignment [][]fr.Element //gkrAssignment is indexed wire first, instance second - -// assumes assignmentVector is arranged wire first, instance second in order of solution -func gkrSolve(info constraint.GkrInfo, solvingData gkrSolvingData, assignmentVector []*big.Int) gkrAssignment { - circuit := info.Circuit - nbInstances := info.NbInstances - offsets := info.AssignmentOffsets() - nbDepsResolved := make([]int, len(circuit)) - inputs := make([]fr.Element, info.MaxNIns) - - assignments := make(gkrAssignment, len(circuit)) - for i := range assignments { - assignments[i] = make([]fr.Element, nbInstances) +func (d *gkrSolvingData) init(info constraint.GkrInfo) gkrAssignment { + d.memoryPool = polynomial.NewPool(256, info.NbInstances) + d.circuit = convertCircuit(info.Circuit) + + assignmentsSequential := make(gkrAssignment, len(d.circuit)) + d.assignments = make(gkr.WireAssignment, len(d.circuit)) + for i := range assignmentsSequential { + assignmentsSequential[i] = d.memoryPool.Make(info.NbInstances) + d.assignments[&d.circuit[i]] = assignmentsSequential[i] } - for instanceI := 0; instanceI < nbInstances; instanceI++ { - //fmt.Println("instance", instanceI) - for wireI, wire := range circuit { - //fmt.Print("\twire ", wireI, ": ") - if wire.IsInput() { - //fmt.Print("input.") - if nbDepsResolved[wireI] < len(wire.Dependencies) && instanceI == wire.Dependencies[nbDepsResolved[wireI]].InputInstance { - //fmt.Print(" copying value from dependency") - dep := wire.Dependencies[nbDepsResolved[wireI]] - assignments[wireI][instanceI].Set(&assignments[dep.OutputWire][dep.OutputInstance]) - nbDepsResolved[wireI]++ - } else { - //fmt.Print(" taking value from input") - assignments[wireI][instanceI].SetBigInt(assignmentVector[offsets[wireI]+instanceI-nbDepsResolved[wireI]]) - } - } else { - //fmt.Print("gated.") - // assemble the inputs - inputIndexes := info.Circuit[wireI].Inputs - for i, inputI := range inputIndexes { - inputs[i].Set(&assignments[inputI][instanceI]) - } - gate := solvingData.circuit[wireI].Gate - assignments[wireI][instanceI] = gate.Evaluate(inputs[:len(inputIndexes)]...) - } - //fmt.Println("\n\t\tresult: ", assignments[wireI][instanceI].Text(10)) - } - } - return assignments + return assignmentsSequential } -func toMapAssignment(circuit gkr.Circuit, assignment gkrAssignment) gkr.WireAssignment { - res := make(gkr.WireAssignment, len(circuit)) - for i := range circuit { - res[&circuit[i]] = assignment[i] +func (d *gkrSolvingData) dumpAssignments() { + for _, p := range d.assignments { + d.memoryPool.Dump(p) } - return res } -func gkrSetOutputValues(circuit []constraint.GkrWire, assignments gkrAssignment, outs []*big.Int) { +// this module assumes that wire and instance indexes respect dependencies + +type gkrAssignment [][]fr.Element //gkrAssignment is indexed wire first, instance second + +func (a gkrAssignment) setOuts(circuit constraint.GkrCircuit, outs []*big.Int) { outsI := 0 for i := range circuit { if circuit[i].IsOutput() { - for j := range assignments[i] { - assignments[i][j].BigInt(outs[outsI]) + for j := range a[i] { + a[i][j].BigInt(outs[outsI]) outsI++ } } @@ -112,16 +80,47 @@ func gkrSetOutputValues(circuit []constraint.GkrWire, assignments gkrAssignment, // Check if outsI == len(outs)? } -func gkrSolveHint(data constraint.GkrInfo, res *gkrSolvingData) hint.Function { +func gkrSolveHint(info constraint.GkrInfo, solvingData *gkrSolvingData) hint.Function { return func(_ *big.Int, ins, outs []*big.Int) error { - res.circuit = convertCircuit(data.Circuit) // TODO: Take this out of here into the proving module - res.memoryPool = polynomial.NewPool(256, data.NbInstances) - - assignments := gkrSolve(data, *res, ins) - res.assignments = toMapAssignment(res.circuit, assignments) - gkrSetOutputValues(data.Circuit, assignments, outs) + // assumes assignmentVector is arranged wire first, instance second in order of solution + circuit := info.Circuit + nbInstances := info.NbInstances + offsets := info.AssignmentOffsets() + nbDepsResolved := make([]int, len(circuit)) + inputs := make([]fr.Element, info.MaxNIns) + assignment := solvingData.init(info) + + for instanceI := 0; instanceI < nbInstances; instanceI++ { + //fmt.Println("instance", instanceI) TODO Remove prints + for wireI, wire := range circuit { + //fmt.Print("\twire ", wireI, ": ") + if wire.IsInput() { + //fmt.Print("input.") + if nbDepsResolved[wireI] < len(wire.Dependencies) && instanceI == wire.Dependencies[nbDepsResolved[wireI]].InputInstance { + //fmt.Print(" copying value from dependency") + dep := wire.Dependencies[nbDepsResolved[wireI]] + assignment[wireI][instanceI].Set(&assignment[dep.OutputWire][dep.OutputInstance]) + nbDepsResolved[wireI]++ + } else { + //fmt.Print(" taking value from input") + assignment[wireI][instanceI].SetBigInt(ins[offsets[wireI]+instanceI-nbDepsResolved[wireI]]) + } + } else { + //fmt.Print("gated.") + // assemble the inputs + inputIndexes := info.Circuit[wireI].Inputs + for i, inputI := range inputIndexes { + inputs[i].Set(&assignment[inputI][instanceI]) + } + gate := solvingData.circuit[wireI].Gate + assignment[wireI][instanceI] = gate.Evaluate(inputs[:len(inputIndexes)]...) + } + //fmt.Println("\n\t\tresult: ", assignment[wireI][instanceI].Text(10)) + } + } + assignment.setOuts(info.Circuit, outs) return nil } } @@ -160,6 +159,9 @@ func gkrProveHint(hashName string, data *gkrSolvingData) hint.Function { offset += len(finalEvalProof) } } + + data.dumpAssignments() + return nil } @@ -170,6 +172,7 @@ func defineGkrHints(info constraint.GkrInfo, hintFunctions map[hint.ID]hint.Func for k, v := range hintFunctions { res[k] = v } + var gkrData gkrSolvingData res[info.SolveHintID] = gkrSolveHint(info, &gkrData) res[info.ProveHintID] = gkrProveHint(info.HashName, &gkrData) From 9b79c6255bee9db575cf3bcee201a0b8e877b649 Mon Sep 17 00:00:00 2001 From: Arya Tabaie Date: Tue, 24 Jan 2023 17:30:58 -0500 Subject: [PATCH 49/71] build: generify bn254/gkr changes --- constraint/bls12-377/gkr.go | 114 +++++++++-------- constraint/bls12-381/gkr.go | 114 +++++++++-------- constraint/bls24-315/gkr.go | 114 +++++++++-------- constraint/bls24-317/gkr.go | 114 +++++++++-------- constraint/bn254/gkr.go | 7 -- constraint/bw6-633/gkr.go | 114 +++++++++-------- constraint/bw6-761/gkr.go | 114 +++++++++-------- .../template/representations/gkr.go.tmpl | 116 +++++++++--------- 8 files changed, 386 insertions(+), 421 deletions(-) diff --git a/constraint/bls12-377/gkr.go b/constraint/bls12-377/gkr.go index 1219b1da33..209a155763 100644 --- a/constraint/bls12-377/gkr.go +++ b/constraint/bls12-377/gkr.go @@ -43,68 +43,36 @@ func convertCircuit(noPtr constraint.GkrCircuit) gkr.Circuit { return resCircuit } -// this module assumes that wire and instance indexes respect dependencies - -type gkrAssignment [][]fr.Element //gkrAssignment is indexed wire first, instance second - -// assumes assignmentVector is arranged wire first, instance second in order of solution -func gkrSolve(info constraint.GkrInfo, solvingData gkrSolvingData, assignmentVector []*big.Int) gkrAssignment { - circuit := info.Circuit - nbInstances := info.NbInstances - offsets := info.AssignmentOffsets() - nbDepsResolved := make([]int, len(circuit)) - inputs := make([]fr.Element, info.MaxNIns) - - assignments := make(gkrAssignment, len(circuit)) - for i := range assignments { - assignments[i] = make([]fr.Element, nbInstances) +func (d *gkrSolvingData) init(info constraint.GkrInfo) gkrAssignment { + d.memoryPool = polynomial.NewPool(256, info.NbInstances) + d.circuit = convertCircuit(info.Circuit) + + assignmentsSequential := make(gkrAssignment, len(d.circuit)) + d.assignments = make(gkr.WireAssignment, len(d.circuit)) + for i := range assignmentsSequential { + assignmentsSequential[i] = d.memoryPool.Make(info.NbInstances) + d.assignments[&d.circuit[i]] = assignmentsSequential[i] } - for instanceI := 0; instanceI < nbInstances; instanceI++ { - //fmt.Println("instance", instanceI) - for wireI, wire := range circuit { - //fmt.Print("\twire ", wireI, ": ") - if wire.IsInput() { - //fmt.Print("input.") - if nbDepsResolved[wireI] < len(wire.Dependencies) && instanceI == wire.Dependencies[nbDepsResolved[wireI]].InputInstance { - //fmt.Print(" copying value from dependency") - dep := wire.Dependencies[nbDepsResolved[wireI]] - assignments[wireI][instanceI].Set(&assignments[dep.OutputWire][dep.OutputInstance]) - nbDepsResolved[wireI]++ - } else { - //fmt.Print(" taking value from input") - assignments[wireI][instanceI].SetBigInt(assignmentVector[offsets[wireI]+instanceI-nbDepsResolved[wireI]]) - } - } else { - //fmt.Print("gated.") - // assemble the inputs - inputIndexes := info.Circuit[wireI].Inputs - for i, inputI := range inputIndexes { - inputs[i].Set(&assignments[inputI][instanceI]) - } - gate := solvingData.circuit[wireI].Gate - assignments[wireI][instanceI] = gate.Evaluate(inputs[:len(inputIndexes)]...) - } - //fmt.Println("\n\t\tresult: ", assignments[wireI][instanceI].Text(10)) - } - } - return assignments + return assignmentsSequential } -func toMapAssignment(circuit gkr.Circuit, assignment gkrAssignment) gkr.WireAssignment { - res := make(gkr.WireAssignment, len(circuit)) - for i := range circuit { - res[&circuit[i]] = assignment[i] +func (d *gkrSolvingData) dumpAssignments() { + for _, p := range d.assignments { + d.memoryPool.Dump(p) } - return res } -func gkrSetOutputValues(circuit []constraint.GkrWire, assignments gkrAssignment, outs []*big.Int) { +// this module assumes that wire and instance indexes respect dependencies + +type gkrAssignment [][]fr.Element //gkrAssignment is indexed wire first, instance second + +func (a gkrAssignment) setOuts(circuit constraint.GkrCircuit, outs []*big.Int) { outsI := 0 for i := range circuit { if circuit[i].IsOutput() { - for j := range assignments[i] { - assignments[i][j].BigInt(outs[outsI]) + for j := range a[i] { + a[i][j].BigInt(outs[outsI]) outsI++ } } @@ -112,16 +80,40 @@ func gkrSetOutputValues(circuit []constraint.GkrWire, assignments gkrAssignment, // Check if outsI == len(outs)? } -func gkrSolveHint(data constraint.GkrInfo, res *gkrSolvingData) hint.Function { +func gkrSolveHint(info constraint.GkrInfo, solvingData *gkrSolvingData) hint.Function { return func(_ *big.Int, ins, outs []*big.Int) error { - res.circuit = convertCircuit(data.Circuit) // TODO: Take this out of here into the proving module - res.memoryPool = polynomial.NewPool(256, data.NbInstances) - - assignments := gkrSolve(data, *res, ins) - res.assignments = toMapAssignment(res.circuit, assignments) - gkrSetOutputValues(data.Circuit, assignments, outs) + // assumes assignmentVector is arranged wire first, instance second in order of solution + circuit := info.Circuit + nbInstances := info.NbInstances + offsets := info.AssignmentOffsets() + nbDepsResolved := make([]int, len(circuit)) + inputs := make([]fr.Element, info.MaxNIns) + assignment := solvingData.init(info) + + for instanceI := 0; instanceI < nbInstances; instanceI++ { + for wireI, wire := range circuit { + if wire.IsInput() { + if nbDepsResolved[wireI] < len(wire.Dependencies) && instanceI == wire.Dependencies[nbDepsResolved[wireI]].InputInstance { + dep := wire.Dependencies[nbDepsResolved[wireI]] + assignment[wireI][instanceI].Set(&assignment[dep.OutputWire][dep.OutputInstance]) + nbDepsResolved[wireI]++ + } else { + assignment[wireI][instanceI].SetBigInt(ins[offsets[wireI]+instanceI-nbDepsResolved[wireI]]) + } + } else { + // assemble the inputs + inputIndexes := info.Circuit[wireI].Inputs + for i, inputI := range inputIndexes { + inputs[i].Set(&assignment[inputI][instanceI]) + } + gate := solvingData.circuit[wireI].Gate + assignment[wireI][instanceI] = gate.Evaluate(inputs[:len(inputIndexes)]...) + } + } + } + assignment.setOuts(info.Circuit, outs) return nil } } @@ -160,6 +152,9 @@ func gkrProveHint(hashName string, data *gkrSolvingData) hint.Function { offset += len(finalEvalProof) } } + + data.dumpAssignments() + return nil } @@ -170,6 +165,7 @@ func defineGkrHints(info constraint.GkrInfo, hintFunctions map[hint.ID]hint.Func for k, v := range hintFunctions { res[k] = v } + var gkrData gkrSolvingData res[info.SolveHintID] = gkrSolveHint(info, &gkrData) res[info.ProveHintID] = gkrProveHint(info.HashName, &gkrData) diff --git a/constraint/bls12-381/gkr.go b/constraint/bls12-381/gkr.go index 8cc1f0382d..c70cd89fd8 100644 --- a/constraint/bls12-381/gkr.go +++ b/constraint/bls12-381/gkr.go @@ -43,68 +43,36 @@ func convertCircuit(noPtr constraint.GkrCircuit) gkr.Circuit { return resCircuit } -// this module assumes that wire and instance indexes respect dependencies - -type gkrAssignment [][]fr.Element //gkrAssignment is indexed wire first, instance second - -// assumes assignmentVector is arranged wire first, instance second in order of solution -func gkrSolve(info constraint.GkrInfo, solvingData gkrSolvingData, assignmentVector []*big.Int) gkrAssignment { - circuit := info.Circuit - nbInstances := info.NbInstances - offsets := info.AssignmentOffsets() - nbDepsResolved := make([]int, len(circuit)) - inputs := make([]fr.Element, info.MaxNIns) - - assignments := make(gkrAssignment, len(circuit)) - for i := range assignments { - assignments[i] = make([]fr.Element, nbInstances) +func (d *gkrSolvingData) init(info constraint.GkrInfo) gkrAssignment { + d.memoryPool = polynomial.NewPool(256, info.NbInstances) + d.circuit = convertCircuit(info.Circuit) + + assignmentsSequential := make(gkrAssignment, len(d.circuit)) + d.assignments = make(gkr.WireAssignment, len(d.circuit)) + for i := range assignmentsSequential { + assignmentsSequential[i] = d.memoryPool.Make(info.NbInstances) + d.assignments[&d.circuit[i]] = assignmentsSequential[i] } - for instanceI := 0; instanceI < nbInstances; instanceI++ { - //fmt.Println("instance", instanceI) - for wireI, wire := range circuit { - //fmt.Print("\twire ", wireI, ": ") - if wire.IsInput() { - //fmt.Print("input.") - if nbDepsResolved[wireI] < len(wire.Dependencies) && instanceI == wire.Dependencies[nbDepsResolved[wireI]].InputInstance { - //fmt.Print(" copying value from dependency") - dep := wire.Dependencies[nbDepsResolved[wireI]] - assignments[wireI][instanceI].Set(&assignments[dep.OutputWire][dep.OutputInstance]) - nbDepsResolved[wireI]++ - } else { - //fmt.Print(" taking value from input") - assignments[wireI][instanceI].SetBigInt(assignmentVector[offsets[wireI]+instanceI-nbDepsResolved[wireI]]) - } - } else { - //fmt.Print("gated.") - // assemble the inputs - inputIndexes := info.Circuit[wireI].Inputs - for i, inputI := range inputIndexes { - inputs[i].Set(&assignments[inputI][instanceI]) - } - gate := solvingData.circuit[wireI].Gate - assignments[wireI][instanceI] = gate.Evaluate(inputs[:len(inputIndexes)]...) - } - //fmt.Println("\n\t\tresult: ", assignments[wireI][instanceI].Text(10)) - } - } - return assignments + return assignmentsSequential } -func toMapAssignment(circuit gkr.Circuit, assignment gkrAssignment) gkr.WireAssignment { - res := make(gkr.WireAssignment, len(circuit)) - for i := range circuit { - res[&circuit[i]] = assignment[i] +func (d *gkrSolvingData) dumpAssignments() { + for _, p := range d.assignments { + d.memoryPool.Dump(p) } - return res } -func gkrSetOutputValues(circuit []constraint.GkrWire, assignments gkrAssignment, outs []*big.Int) { +// this module assumes that wire and instance indexes respect dependencies + +type gkrAssignment [][]fr.Element //gkrAssignment is indexed wire first, instance second + +func (a gkrAssignment) setOuts(circuit constraint.GkrCircuit, outs []*big.Int) { outsI := 0 for i := range circuit { if circuit[i].IsOutput() { - for j := range assignments[i] { - assignments[i][j].BigInt(outs[outsI]) + for j := range a[i] { + a[i][j].BigInt(outs[outsI]) outsI++ } } @@ -112,16 +80,40 @@ func gkrSetOutputValues(circuit []constraint.GkrWire, assignments gkrAssignment, // Check if outsI == len(outs)? } -func gkrSolveHint(data constraint.GkrInfo, res *gkrSolvingData) hint.Function { +func gkrSolveHint(info constraint.GkrInfo, solvingData *gkrSolvingData) hint.Function { return func(_ *big.Int, ins, outs []*big.Int) error { - res.circuit = convertCircuit(data.Circuit) // TODO: Take this out of here into the proving module - res.memoryPool = polynomial.NewPool(256, data.NbInstances) - - assignments := gkrSolve(data, *res, ins) - res.assignments = toMapAssignment(res.circuit, assignments) - gkrSetOutputValues(data.Circuit, assignments, outs) + // assumes assignmentVector is arranged wire first, instance second in order of solution + circuit := info.Circuit + nbInstances := info.NbInstances + offsets := info.AssignmentOffsets() + nbDepsResolved := make([]int, len(circuit)) + inputs := make([]fr.Element, info.MaxNIns) + assignment := solvingData.init(info) + + for instanceI := 0; instanceI < nbInstances; instanceI++ { + for wireI, wire := range circuit { + if wire.IsInput() { + if nbDepsResolved[wireI] < len(wire.Dependencies) && instanceI == wire.Dependencies[nbDepsResolved[wireI]].InputInstance { + dep := wire.Dependencies[nbDepsResolved[wireI]] + assignment[wireI][instanceI].Set(&assignment[dep.OutputWire][dep.OutputInstance]) + nbDepsResolved[wireI]++ + } else { + assignment[wireI][instanceI].SetBigInt(ins[offsets[wireI]+instanceI-nbDepsResolved[wireI]]) + } + } else { + // assemble the inputs + inputIndexes := info.Circuit[wireI].Inputs + for i, inputI := range inputIndexes { + inputs[i].Set(&assignment[inputI][instanceI]) + } + gate := solvingData.circuit[wireI].Gate + assignment[wireI][instanceI] = gate.Evaluate(inputs[:len(inputIndexes)]...) + } + } + } + assignment.setOuts(info.Circuit, outs) return nil } } @@ -160,6 +152,9 @@ func gkrProveHint(hashName string, data *gkrSolvingData) hint.Function { offset += len(finalEvalProof) } } + + data.dumpAssignments() + return nil } @@ -170,6 +165,7 @@ func defineGkrHints(info constraint.GkrInfo, hintFunctions map[hint.ID]hint.Func for k, v := range hintFunctions { res[k] = v } + var gkrData gkrSolvingData res[info.SolveHintID] = gkrSolveHint(info, &gkrData) res[info.ProveHintID] = gkrProveHint(info.HashName, &gkrData) diff --git a/constraint/bls24-315/gkr.go b/constraint/bls24-315/gkr.go index 6853538d1d..5dabba1acd 100644 --- a/constraint/bls24-315/gkr.go +++ b/constraint/bls24-315/gkr.go @@ -43,68 +43,36 @@ func convertCircuit(noPtr constraint.GkrCircuit) gkr.Circuit { return resCircuit } -// this module assumes that wire and instance indexes respect dependencies - -type gkrAssignment [][]fr.Element //gkrAssignment is indexed wire first, instance second - -// assumes assignmentVector is arranged wire first, instance second in order of solution -func gkrSolve(info constraint.GkrInfo, solvingData gkrSolvingData, assignmentVector []*big.Int) gkrAssignment { - circuit := info.Circuit - nbInstances := info.NbInstances - offsets := info.AssignmentOffsets() - nbDepsResolved := make([]int, len(circuit)) - inputs := make([]fr.Element, info.MaxNIns) - - assignments := make(gkrAssignment, len(circuit)) - for i := range assignments { - assignments[i] = make([]fr.Element, nbInstances) +func (d *gkrSolvingData) init(info constraint.GkrInfo) gkrAssignment { + d.memoryPool = polynomial.NewPool(256, info.NbInstances) + d.circuit = convertCircuit(info.Circuit) + + assignmentsSequential := make(gkrAssignment, len(d.circuit)) + d.assignments = make(gkr.WireAssignment, len(d.circuit)) + for i := range assignmentsSequential { + assignmentsSequential[i] = d.memoryPool.Make(info.NbInstances) + d.assignments[&d.circuit[i]] = assignmentsSequential[i] } - for instanceI := 0; instanceI < nbInstances; instanceI++ { - //fmt.Println("instance", instanceI) - for wireI, wire := range circuit { - //fmt.Print("\twire ", wireI, ": ") - if wire.IsInput() { - //fmt.Print("input.") - if nbDepsResolved[wireI] < len(wire.Dependencies) && instanceI == wire.Dependencies[nbDepsResolved[wireI]].InputInstance { - //fmt.Print(" copying value from dependency") - dep := wire.Dependencies[nbDepsResolved[wireI]] - assignments[wireI][instanceI].Set(&assignments[dep.OutputWire][dep.OutputInstance]) - nbDepsResolved[wireI]++ - } else { - //fmt.Print(" taking value from input") - assignments[wireI][instanceI].SetBigInt(assignmentVector[offsets[wireI]+instanceI-nbDepsResolved[wireI]]) - } - } else { - //fmt.Print("gated.") - // assemble the inputs - inputIndexes := info.Circuit[wireI].Inputs - for i, inputI := range inputIndexes { - inputs[i].Set(&assignments[inputI][instanceI]) - } - gate := solvingData.circuit[wireI].Gate - assignments[wireI][instanceI] = gate.Evaluate(inputs[:len(inputIndexes)]...) - } - //fmt.Println("\n\t\tresult: ", assignments[wireI][instanceI].Text(10)) - } - } - return assignments + return assignmentsSequential } -func toMapAssignment(circuit gkr.Circuit, assignment gkrAssignment) gkr.WireAssignment { - res := make(gkr.WireAssignment, len(circuit)) - for i := range circuit { - res[&circuit[i]] = assignment[i] +func (d *gkrSolvingData) dumpAssignments() { + for _, p := range d.assignments { + d.memoryPool.Dump(p) } - return res } -func gkrSetOutputValues(circuit []constraint.GkrWire, assignments gkrAssignment, outs []*big.Int) { +// this module assumes that wire and instance indexes respect dependencies + +type gkrAssignment [][]fr.Element //gkrAssignment is indexed wire first, instance second + +func (a gkrAssignment) setOuts(circuit constraint.GkrCircuit, outs []*big.Int) { outsI := 0 for i := range circuit { if circuit[i].IsOutput() { - for j := range assignments[i] { - assignments[i][j].BigInt(outs[outsI]) + for j := range a[i] { + a[i][j].BigInt(outs[outsI]) outsI++ } } @@ -112,16 +80,40 @@ func gkrSetOutputValues(circuit []constraint.GkrWire, assignments gkrAssignment, // Check if outsI == len(outs)? } -func gkrSolveHint(data constraint.GkrInfo, res *gkrSolvingData) hint.Function { +func gkrSolveHint(info constraint.GkrInfo, solvingData *gkrSolvingData) hint.Function { return func(_ *big.Int, ins, outs []*big.Int) error { - res.circuit = convertCircuit(data.Circuit) // TODO: Take this out of here into the proving module - res.memoryPool = polynomial.NewPool(256, data.NbInstances) - - assignments := gkrSolve(data, *res, ins) - res.assignments = toMapAssignment(res.circuit, assignments) - gkrSetOutputValues(data.Circuit, assignments, outs) + // assumes assignmentVector is arranged wire first, instance second in order of solution + circuit := info.Circuit + nbInstances := info.NbInstances + offsets := info.AssignmentOffsets() + nbDepsResolved := make([]int, len(circuit)) + inputs := make([]fr.Element, info.MaxNIns) + assignment := solvingData.init(info) + + for instanceI := 0; instanceI < nbInstances; instanceI++ { + for wireI, wire := range circuit { + if wire.IsInput() { + if nbDepsResolved[wireI] < len(wire.Dependencies) && instanceI == wire.Dependencies[nbDepsResolved[wireI]].InputInstance { + dep := wire.Dependencies[nbDepsResolved[wireI]] + assignment[wireI][instanceI].Set(&assignment[dep.OutputWire][dep.OutputInstance]) + nbDepsResolved[wireI]++ + } else { + assignment[wireI][instanceI].SetBigInt(ins[offsets[wireI]+instanceI-nbDepsResolved[wireI]]) + } + } else { + // assemble the inputs + inputIndexes := info.Circuit[wireI].Inputs + for i, inputI := range inputIndexes { + inputs[i].Set(&assignment[inputI][instanceI]) + } + gate := solvingData.circuit[wireI].Gate + assignment[wireI][instanceI] = gate.Evaluate(inputs[:len(inputIndexes)]...) + } + } + } + assignment.setOuts(info.Circuit, outs) return nil } } @@ -160,6 +152,9 @@ func gkrProveHint(hashName string, data *gkrSolvingData) hint.Function { offset += len(finalEvalProof) } } + + data.dumpAssignments() + return nil } @@ -170,6 +165,7 @@ func defineGkrHints(info constraint.GkrInfo, hintFunctions map[hint.ID]hint.Func for k, v := range hintFunctions { res[k] = v } + var gkrData gkrSolvingData res[info.SolveHintID] = gkrSolveHint(info, &gkrData) res[info.ProveHintID] = gkrProveHint(info.HashName, &gkrData) diff --git a/constraint/bls24-317/gkr.go b/constraint/bls24-317/gkr.go index 515f64bcda..5fbf12080b 100644 --- a/constraint/bls24-317/gkr.go +++ b/constraint/bls24-317/gkr.go @@ -43,68 +43,36 @@ func convertCircuit(noPtr constraint.GkrCircuit) gkr.Circuit { return resCircuit } -// this module assumes that wire and instance indexes respect dependencies - -type gkrAssignment [][]fr.Element //gkrAssignment is indexed wire first, instance second - -// assumes assignmentVector is arranged wire first, instance second in order of solution -func gkrSolve(info constraint.GkrInfo, solvingData gkrSolvingData, assignmentVector []*big.Int) gkrAssignment { - circuit := info.Circuit - nbInstances := info.NbInstances - offsets := info.AssignmentOffsets() - nbDepsResolved := make([]int, len(circuit)) - inputs := make([]fr.Element, info.MaxNIns) - - assignments := make(gkrAssignment, len(circuit)) - for i := range assignments { - assignments[i] = make([]fr.Element, nbInstances) +func (d *gkrSolvingData) init(info constraint.GkrInfo) gkrAssignment { + d.memoryPool = polynomial.NewPool(256, info.NbInstances) + d.circuit = convertCircuit(info.Circuit) + + assignmentsSequential := make(gkrAssignment, len(d.circuit)) + d.assignments = make(gkr.WireAssignment, len(d.circuit)) + for i := range assignmentsSequential { + assignmentsSequential[i] = d.memoryPool.Make(info.NbInstances) + d.assignments[&d.circuit[i]] = assignmentsSequential[i] } - for instanceI := 0; instanceI < nbInstances; instanceI++ { - //fmt.Println("instance", instanceI) - for wireI, wire := range circuit { - //fmt.Print("\twire ", wireI, ": ") - if wire.IsInput() { - //fmt.Print("input.") - if nbDepsResolved[wireI] < len(wire.Dependencies) && instanceI == wire.Dependencies[nbDepsResolved[wireI]].InputInstance { - //fmt.Print(" copying value from dependency") - dep := wire.Dependencies[nbDepsResolved[wireI]] - assignments[wireI][instanceI].Set(&assignments[dep.OutputWire][dep.OutputInstance]) - nbDepsResolved[wireI]++ - } else { - //fmt.Print(" taking value from input") - assignments[wireI][instanceI].SetBigInt(assignmentVector[offsets[wireI]+instanceI-nbDepsResolved[wireI]]) - } - } else { - //fmt.Print("gated.") - // assemble the inputs - inputIndexes := info.Circuit[wireI].Inputs - for i, inputI := range inputIndexes { - inputs[i].Set(&assignments[inputI][instanceI]) - } - gate := solvingData.circuit[wireI].Gate - assignments[wireI][instanceI] = gate.Evaluate(inputs[:len(inputIndexes)]...) - } - //fmt.Println("\n\t\tresult: ", assignments[wireI][instanceI].Text(10)) - } - } - return assignments + return assignmentsSequential } -func toMapAssignment(circuit gkr.Circuit, assignment gkrAssignment) gkr.WireAssignment { - res := make(gkr.WireAssignment, len(circuit)) - for i := range circuit { - res[&circuit[i]] = assignment[i] +func (d *gkrSolvingData) dumpAssignments() { + for _, p := range d.assignments { + d.memoryPool.Dump(p) } - return res } -func gkrSetOutputValues(circuit []constraint.GkrWire, assignments gkrAssignment, outs []*big.Int) { +// this module assumes that wire and instance indexes respect dependencies + +type gkrAssignment [][]fr.Element //gkrAssignment is indexed wire first, instance second + +func (a gkrAssignment) setOuts(circuit constraint.GkrCircuit, outs []*big.Int) { outsI := 0 for i := range circuit { if circuit[i].IsOutput() { - for j := range assignments[i] { - assignments[i][j].BigInt(outs[outsI]) + for j := range a[i] { + a[i][j].BigInt(outs[outsI]) outsI++ } } @@ -112,16 +80,40 @@ func gkrSetOutputValues(circuit []constraint.GkrWire, assignments gkrAssignment, // Check if outsI == len(outs)? } -func gkrSolveHint(data constraint.GkrInfo, res *gkrSolvingData) hint.Function { +func gkrSolveHint(info constraint.GkrInfo, solvingData *gkrSolvingData) hint.Function { return func(_ *big.Int, ins, outs []*big.Int) error { - res.circuit = convertCircuit(data.Circuit) // TODO: Take this out of here into the proving module - res.memoryPool = polynomial.NewPool(256, data.NbInstances) - - assignments := gkrSolve(data, *res, ins) - res.assignments = toMapAssignment(res.circuit, assignments) - gkrSetOutputValues(data.Circuit, assignments, outs) + // assumes assignmentVector is arranged wire first, instance second in order of solution + circuit := info.Circuit + nbInstances := info.NbInstances + offsets := info.AssignmentOffsets() + nbDepsResolved := make([]int, len(circuit)) + inputs := make([]fr.Element, info.MaxNIns) + assignment := solvingData.init(info) + + for instanceI := 0; instanceI < nbInstances; instanceI++ { + for wireI, wire := range circuit { + if wire.IsInput() { + if nbDepsResolved[wireI] < len(wire.Dependencies) && instanceI == wire.Dependencies[nbDepsResolved[wireI]].InputInstance { + dep := wire.Dependencies[nbDepsResolved[wireI]] + assignment[wireI][instanceI].Set(&assignment[dep.OutputWire][dep.OutputInstance]) + nbDepsResolved[wireI]++ + } else { + assignment[wireI][instanceI].SetBigInt(ins[offsets[wireI]+instanceI-nbDepsResolved[wireI]]) + } + } else { + // assemble the inputs + inputIndexes := info.Circuit[wireI].Inputs + for i, inputI := range inputIndexes { + inputs[i].Set(&assignment[inputI][instanceI]) + } + gate := solvingData.circuit[wireI].Gate + assignment[wireI][instanceI] = gate.Evaluate(inputs[:len(inputIndexes)]...) + } + } + } + assignment.setOuts(info.Circuit, outs) return nil } } @@ -160,6 +152,9 @@ func gkrProveHint(hashName string, data *gkrSolvingData) hint.Function { offset += len(finalEvalProof) } } + + data.dumpAssignments() + return nil } @@ -170,6 +165,7 @@ func defineGkrHints(info constraint.GkrInfo, hintFunctions map[hint.ID]hint.Func for k, v := range hintFunctions { res[k] = v } + var gkrData gkrSolvingData res[info.SolveHintID] = gkrSolveHint(info, &gkrData) res[info.ProveHintID] = gkrProveHint(info.HashName, &gkrData) diff --git a/constraint/bn254/gkr.go b/constraint/bn254/gkr.go index ce44301dd8..2551af9ae8 100644 --- a/constraint/bn254/gkr.go +++ b/constraint/bn254/gkr.go @@ -92,22 +92,16 @@ func gkrSolveHint(info constraint.GkrInfo, solvingData *gkrSolvingData) hint.Fun assignment := solvingData.init(info) for instanceI := 0; instanceI < nbInstances; instanceI++ { - //fmt.Println("instance", instanceI) TODO Remove prints for wireI, wire := range circuit { - //fmt.Print("\twire ", wireI, ": ") if wire.IsInput() { - //fmt.Print("input.") if nbDepsResolved[wireI] < len(wire.Dependencies) && instanceI == wire.Dependencies[nbDepsResolved[wireI]].InputInstance { - //fmt.Print(" copying value from dependency") dep := wire.Dependencies[nbDepsResolved[wireI]] assignment[wireI][instanceI].Set(&assignment[dep.OutputWire][dep.OutputInstance]) nbDepsResolved[wireI]++ } else { - //fmt.Print(" taking value from input") assignment[wireI][instanceI].SetBigInt(ins[offsets[wireI]+instanceI-nbDepsResolved[wireI]]) } } else { - //fmt.Print("gated.") // assemble the inputs inputIndexes := info.Circuit[wireI].Inputs for i, inputI := range inputIndexes { @@ -116,7 +110,6 @@ func gkrSolveHint(info constraint.GkrInfo, solvingData *gkrSolvingData) hint.Fun gate := solvingData.circuit[wireI].Gate assignment[wireI][instanceI] = gate.Evaluate(inputs[:len(inputIndexes)]...) } - //fmt.Println("\n\t\tresult: ", assignment[wireI][instanceI].Text(10)) } } diff --git a/constraint/bw6-633/gkr.go b/constraint/bw6-633/gkr.go index 7657a64543..db88f06200 100644 --- a/constraint/bw6-633/gkr.go +++ b/constraint/bw6-633/gkr.go @@ -43,68 +43,36 @@ func convertCircuit(noPtr constraint.GkrCircuit) gkr.Circuit { return resCircuit } -// this module assumes that wire and instance indexes respect dependencies - -type gkrAssignment [][]fr.Element //gkrAssignment is indexed wire first, instance second - -// assumes assignmentVector is arranged wire first, instance second in order of solution -func gkrSolve(info constraint.GkrInfo, solvingData gkrSolvingData, assignmentVector []*big.Int) gkrAssignment { - circuit := info.Circuit - nbInstances := info.NbInstances - offsets := info.AssignmentOffsets() - nbDepsResolved := make([]int, len(circuit)) - inputs := make([]fr.Element, info.MaxNIns) - - assignments := make(gkrAssignment, len(circuit)) - for i := range assignments { - assignments[i] = make([]fr.Element, nbInstances) +func (d *gkrSolvingData) init(info constraint.GkrInfo) gkrAssignment { + d.memoryPool = polynomial.NewPool(256, info.NbInstances) + d.circuit = convertCircuit(info.Circuit) + + assignmentsSequential := make(gkrAssignment, len(d.circuit)) + d.assignments = make(gkr.WireAssignment, len(d.circuit)) + for i := range assignmentsSequential { + assignmentsSequential[i] = d.memoryPool.Make(info.NbInstances) + d.assignments[&d.circuit[i]] = assignmentsSequential[i] } - for instanceI := 0; instanceI < nbInstances; instanceI++ { - //fmt.Println("instance", instanceI) - for wireI, wire := range circuit { - //fmt.Print("\twire ", wireI, ": ") - if wire.IsInput() { - //fmt.Print("input.") - if nbDepsResolved[wireI] < len(wire.Dependencies) && instanceI == wire.Dependencies[nbDepsResolved[wireI]].InputInstance { - //fmt.Print(" copying value from dependency") - dep := wire.Dependencies[nbDepsResolved[wireI]] - assignments[wireI][instanceI].Set(&assignments[dep.OutputWire][dep.OutputInstance]) - nbDepsResolved[wireI]++ - } else { - //fmt.Print(" taking value from input") - assignments[wireI][instanceI].SetBigInt(assignmentVector[offsets[wireI]+instanceI-nbDepsResolved[wireI]]) - } - } else { - //fmt.Print("gated.") - // assemble the inputs - inputIndexes := info.Circuit[wireI].Inputs - for i, inputI := range inputIndexes { - inputs[i].Set(&assignments[inputI][instanceI]) - } - gate := solvingData.circuit[wireI].Gate - assignments[wireI][instanceI] = gate.Evaluate(inputs[:len(inputIndexes)]...) - } - //fmt.Println("\n\t\tresult: ", assignments[wireI][instanceI].Text(10)) - } - } - return assignments + return assignmentsSequential } -func toMapAssignment(circuit gkr.Circuit, assignment gkrAssignment) gkr.WireAssignment { - res := make(gkr.WireAssignment, len(circuit)) - for i := range circuit { - res[&circuit[i]] = assignment[i] +func (d *gkrSolvingData) dumpAssignments() { + for _, p := range d.assignments { + d.memoryPool.Dump(p) } - return res } -func gkrSetOutputValues(circuit []constraint.GkrWire, assignments gkrAssignment, outs []*big.Int) { +// this module assumes that wire and instance indexes respect dependencies + +type gkrAssignment [][]fr.Element //gkrAssignment is indexed wire first, instance second + +func (a gkrAssignment) setOuts(circuit constraint.GkrCircuit, outs []*big.Int) { outsI := 0 for i := range circuit { if circuit[i].IsOutput() { - for j := range assignments[i] { - assignments[i][j].BigInt(outs[outsI]) + for j := range a[i] { + a[i][j].BigInt(outs[outsI]) outsI++ } } @@ -112,16 +80,40 @@ func gkrSetOutputValues(circuit []constraint.GkrWire, assignments gkrAssignment, // Check if outsI == len(outs)? } -func gkrSolveHint(data constraint.GkrInfo, res *gkrSolvingData) hint.Function { +func gkrSolveHint(info constraint.GkrInfo, solvingData *gkrSolvingData) hint.Function { return func(_ *big.Int, ins, outs []*big.Int) error { - res.circuit = convertCircuit(data.Circuit) // TODO: Take this out of here into the proving module - res.memoryPool = polynomial.NewPool(256, data.NbInstances) - - assignments := gkrSolve(data, *res, ins) - res.assignments = toMapAssignment(res.circuit, assignments) - gkrSetOutputValues(data.Circuit, assignments, outs) + // assumes assignmentVector is arranged wire first, instance second in order of solution + circuit := info.Circuit + nbInstances := info.NbInstances + offsets := info.AssignmentOffsets() + nbDepsResolved := make([]int, len(circuit)) + inputs := make([]fr.Element, info.MaxNIns) + assignment := solvingData.init(info) + + for instanceI := 0; instanceI < nbInstances; instanceI++ { + for wireI, wire := range circuit { + if wire.IsInput() { + if nbDepsResolved[wireI] < len(wire.Dependencies) && instanceI == wire.Dependencies[nbDepsResolved[wireI]].InputInstance { + dep := wire.Dependencies[nbDepsResolved[wireI]] + assignment[wireI][instanceI].Set(&assignment[dep.OutputWire][dep.OutputInstance]) + nbDepsResolved[wireI]++ + } else { + assignment[wireI][instanceI].SetBigInt(ins[offsets[wireI]+instanceI-nbDepsResolved[wireI]]) + } + } else { + // assemble the inputs + inputIndexes := info.Circuit[wireI].Inputs + for i, inputI := range inputIndexes { + inputs[i].Set(&assignment[inputI][instanceI]) + } + gate := solvingData.circuit[wireI].Gate + assignment[wireI][instanceI] = gate.Evaluate(inputs[:len(inputIndexes)]...) + } + } + } + assignment.setOuts(info.Circuit, outs) return nil } } @@ -160,6 +152,9 @@ func gkrProveHint(hashName string, data *gkrSolvingData) hint.Function { offset += len(finalEvalProof) } } + + data.dumpAssignments() + return nil } @@ -170,6 +165,7 @@ func defineGkrHints(info constraint.GkrInfo, hintFunctions map[hint.ID]hint.Func for k, v := range hintFunctions { res[k] = v } + var gkrData gkrSolvingData res[info.SolveHintID] = gkrSolveHint(info, &gkrData) res[info.ProveHintID] = gkrProveHint(info.HashName, &gkrData) diff --git a/constraint/bw6-761/gkr.go b/constraint/bw6-761/gkr.go index 40ea107700..70392089a9 100644 --- a/constraint/bw6-761/gkr.go +++ b/constraint/bw6-761/gkr.go @@ -43,68 +43,36 @@ func convertCircuit(noPtr constraint.GkrCircuit) gkr.Circuit { return resCircuit } -// this module assumes that wire and instance indexes respect dependencies - -type gkrAssignment [][]fr.Element //gkrAssignment is indexed wire first, instance second - -// assumes assignmentVector is arranged wire first, instance second in order of solution -func gkrSolve(info constraint.GkrInfo, solvingData gkrSolvingData, assignmentVector []*big.Int) gkrAssignment { - circuit := info.Circuit - nbInstances := info.NbInstances - offsets := info.AssignmentOffsets() - nbDepsResolved := make([]int, len(circuit)) - inputs := make([]fr.Element, info.MaxNIns) - - assignments := make(gkrAssignment, len(circuit)) - for i := range assignments { - assignments[i] = make([]fr.Element, nbInstances) +func (d *gkrSolvingData) init(info constraint.GkrInfo) gkrAssignment { + d.memoryPool = polynomial.NewPool(256, info.NbInstances) + d.circuit = convertCircuit(info.Circuit) + + assignmentsSequential := make(gkrAssignment, len(d.circuit)) + d.assignments = make(gkr.WireAssignment, len(d.circuit)) + for i := range assignmentsSequential { + assignmentsSequential[i] = d.memoryPool.Make(info.NbInstances) + d.assignments[&d.circuit[i]] = assignmentsSequential[i] } - for instanceI := 0; instanceI < nbInstances; instanceI++ { - //fmt.Println("instance", instanceI) - for wireI, wire := range circuit { - //fmt.Print("\twire ", wireI, ": ") - if wire.IsInput() { - //fmt.Print("input.") - if nbDepsResolved[wireI] < len(wire.Dependencies) && instanceI == wire.Dependencies[nbDepsResolved[wireI]].InputInstance { - //fmt.Print(" copying value from dependency") - dep := wire.Dependencies[nbDepsResolved[wireI]] - assignments[wireI][instanceI].Set(&assignments[dep.OutputWire][dep.OutputInstance]) - nbDepsResolved[wireI]++ - } else { - //fmt.Print(" taking value from input") - assignments[wireI][instanceI].SetBigInt(assignmentVector[offsets[wireI]+instanceI-nbDepsResolved[wireI]]) - } - } else { - //fmt.Print("gated.") - // assemble the inputs - inputIndexes := info.Circuit[wireI].Inputs - for i, inputI := range inputIndexes { - inputs[i].Set(&assignments[inputI][instanceI]) - } - gate := solvingData.circuit[wireI].Gate - assignments[wireI][instanceI] = gate.Evaluate(inputs[:len(inputIndexes)]...) - } - //fmt.Println("\n\t\tresult: ", assignments[wireI][instanceI].Text(10)) - } - } - return assignments + return assignmentsSequential } -func toMapAssignment(circuit gkr.Circuit, assignment gkrAssignment) gkr.WireAssignment { - res := make(gkr.WireAssignment, len(circuit)) - for i := range circuit { - res[&circuit[i]] = assignment[i] +func (d *gkrSolvingData) dumpAssignments() { + for _, p := range d.assignments { + d.memoryPool.Dump(p) } - return res } -func gkrSetOutputValues(circuit []constraint.GkrWire, assignments gkrAssignment, outs []*big.Int) { +// this module assumes that wire and instance indexes respect dependencies + +type gkrAssignment [][]fr.Element //gkrAssignment is indexed wire first, instance second + +func (a gkrAssignment) setOuts(circuit constraint.GkrCircuit, outs []*big.Int) { outsI := 0 for i := range circuit { if circuit[i].IsOutput() { - for j := range assignments[i] { - assignments[i][j].BigInt(outs[outsI]) + for j := range a[i] { + a[i][j].BigInt(outs[outsI]) outsI++ } } @@ -112,16 +80,40 @@ func gkrSetOutputValues(circuit []constraint.GkrWire, assignments gkrAssignment, // Check if outsI == len(outs)? } -func gkrSolveHint(data constraint.GkrInfo, res *gkrSolvingData) hint.Function { +func gkrSolveHint(info constraint.GkrInfo, solvingData *gkrSolvingData) hint.Function { return func(_ *big.Int, ins, outs []*big.Int) error { - res.circuit = convertCircuit(data.Circuit) // TODO: Take this out of here into the proving module - res.memoryPool = polynomial.NewPool(256, data.NbInstances) - - assignments := gkrSolve(data, *res, ins) - res.assignments = toMapAssignment(res.circuit, assignments) - gkrSetOutputValues(data.Circuit, assignments, outs) + // assumes assignmentVector is arranged wire first, instance second in order of solution + circuit := info.Circuit + nbInstances := info.NbInstances + offsets := info.AssignmentOffsets() + nbDepsResolved := make([]int, len(circuit)) + inputs := make([]fr.Element, info.MaxNIns) + assignment := solvingData.init(info) + + for instanceI := 0; instanceI < nbInstances; instanceI++ { + for wireI, wire := range circuit { + if wire.IsInput() { + if nbDepsResolved[wireI] < len(wire.Dependencies) && instanceI == wire.Dependencies[nbDepsResolved[wireI]].InputInstance { + dep := wire.Dependencies[nbDepsResolved[wireI]] + assignment[wireI][instanceI].Set(&assignment[dep.OutputWire][dep.OutputInstance]) + nbDepsResolved[wireI]++ + } else { + assignment[wireI][instanceI].SetBigInt(ins[offsets[wireI]+instanceI-nbDepsResolved[wireI]]) + } + } else { + // assemble the inputs + inputIndexes := info.Circuit[wireI].Inputs + for i, inputI := range inputIndexes { + inputs[i].Set(&assignment[inputI][instanceI]) + } + gate := solvingData.circuit[wireI].Gate + assignment[wireI][instanceI] = gate.Evaluate(inputs[:len(inputIndexes)]...) + } + } + } + assignment.setOuts(info.Circuit, outs) return nil } } @@ -160,6 +152,9 @@ func gkrProveHint(hashName string, data *gkrSolvingData) hint.Function { offset += len(finalEvalProof) } } + + data.dumpAssignments() + return nil } @@ -170,6 +165,7 @@ func defineGkrHints(info constraint.GkrInfo, hintFunctions map[hint.ID]hint.Func for k, v := range hintFunctions { res[k] = v } + var gkrData gkrSolvingData res[info.SolveHintID] = gkrSolveHint(info, &gkrData) res[info.ProveHintID] = gkrProveHint(info.HashName, &gkrData) diff --git a/internal/generator/backend/template/representations/gkr.go.tmpl b/internal/generator/backend/template/representations/gkr.go.tmpl index c0c92e6c85..47143ea70c 100644 --- a/internal/generator/backend/template/representations/gkr.go.tmpl +++ b/internal/generator/backend/template/representations/gkr.go.tmpl @@ -25,68 +25,36 @@ func convertCircuit(noPtr constraint.GkrCircuit) gkr.Circuit { return resCircuit } -// this module assumes that wire and instance indexes respect dependencies - -type gkrAssignment [][]fr.Element //gkrAssignment is indexed wire first, instance second - -// assumes assignmentVector is arranged wire first, instance second in order of solution -func gkrSolve(info constraint.GkrInfo, solvingData gkrSolvingData, assignmentVector []*big.Int) gkrAssignment { - circuit := info.Circuit - nbInstances := info.NbInstances - offsets := info.AssignmentOffsets() - nbDepsResolved := make([]int, len(circuit)) - inputs := make([]fr.Element, info.MaxNIns) - - assignments := make(gkrAssignment, len(circuit)) - for i := range assignments { - assignments[i] = make([]fr.Element, nbInstances) +func (d *gkrSolvingData) init(info constraint.GkrInfo) gkrAssignment { + d.memoryPool = polynomial.NewPool(256, info.NbInstances) + d.circuit = convertCircuit(info.Circuit) + + assignmentsSequential := make(gkrAssignment, len(d.circuit)) + d.assignments = make(gkr.WireAssignment, len(d.circuit)) + for i := range assignmentsSequential { + assignmentsSequential[i] = d.memoryPool.Make(info.NbInstances) + d.assignments[&d.circuit[i]] = assignmentsSequential[i] } - for instanceI := 0; instanceI < nbInstances; instanceI++ { - //fmt.Println("instance", instanceI) - for wireI, wire := range circuit { - //fmt.Print("\twire ", wireI, ": ") - if wire.IsInput() { - //fmt.Print("input.") - if nbDepsResolved[wireI] < len(wire.Dependencies) && instanceI == wire.Dependencies[nbDepsResolved[wireI]].InputInstance { - //fmt.Print(" copying value from dependency") - dep := wire.Dependencies[nbDepsResolved[wireI]] - assignments[wireI][instanceI].Set(&assignments[dep.OutputWire][dep.OutputInstance]) - nbDepsResolved[wireI]++ - } else { - //fmt.Print(" taking value from input") - assignments[wireI][instanceI].SetBigInt(assignmentVector[offsets[wireI]+instanceI-nbDepsResolved[wireI]]) - } - } else { - //fmt.Print("gated.") - // assemble the inputs - inputIndexes := info.Circuit[wireI].Inputs - for i, inputI := range inputIndexes { - inputs[i].Set(&assignments[inputI][instanceI]) - } - gate := solvingData.circuit[wireI].Gate - assignments[wireI][instanceI] = gate.Evaluate(inputs[:len(inputIndexes)]...) - } - //fmt.Println("\n\t\tresult: ", assignments[wireI][instanceI].Text(10)) - } - } - return assignments + return assignmentsSequential } -func toMapAssignment(circuit gkr.Circuit, assignment gkrAssignment) gkr.WireAssignment { - res := make(gkr.WireAssignment, len(circuit)) - for i := range circuit { - res[&circuit[i]] = assignment[i] +func (d *gkrSolvingData) dumpAssignments() { + for _, p := range d.assignments { + d.memoryPool.Dump(p) } - return res } -func gkrSetOutputValues(circuit []constraint.GkrWire, assignments gkrAssignment, outs []*big.Int) { +// this module assumes that wire and instance indexes respect dependencies + +type gkrAssignment [][]fr.Element //gkrAssignment is indexed wire first, instance second + +func (a gkrAssignment) setOuts(circuit constraint.GkrCircuit, outs []*big.Int) { outsI := 0 for i := range circuit { if circuit[i].IsOutput() { - for j := range assignments[i] { - assignments[i][j].BigInt(outs[outsI]) + for j := range a[i] { + a[i][j].BigInt(outs[outsI]) outsI++ } } @@ -94,16 +62,40 @@ func gkrSetOutputValues(circuit []constraint.GkrWire, assignments gkrAssignment, // Check if outsI == len(outs)? } -func gkrSolveHint(data constraint.GkrInfo, res *gkrSolvingData) hint.Function { +func gkrSolveHint(info constraint.GkrInfo, solvingData *gkrSolvingData) hint.Function { return func(_ *big.Int, ins, outs []*big.Int) error { - res.circuit = convertCircuit(data.Circuit) // TODO: Take this out of here into the proving module - res.memoryPool = polynomial.NewPool(256, data.NbInstances) - - assignments := gkrSolve(data, *res, ins) - res.assignments = toMapAssignment(res.circuit, assignments) - gkrSetOutputValues(data.Circuit, assignments, outs) + // assumes assignmentVector is arranged wire first, instance second in order of solution + circuit := info.Circuit + nbInstances := info.NbInstances + offsets := info.AssignmentOffsets() + nbDepsResolved := make([]int, len(circuit)) + inputs := make([]fr.Element, info.MaxNIns) + assignment := solvingData.init(info) + + for instanceI := 0; instanceI < nbInstances; instanceI++ { + for wireI, wire := range circuit { + if wire.IsInput() { + if nbDepsResolved[wireI] < len(wire.Dependencies) && instanceI == wire.Dependencies[nbDepsResolved[wireI]].InputInstance { + dep := wire.Dependencies[nbDepsResolved[wireI]] + assignment[wireI][instanceI].Set(&assignment[dep.OutputWire][dep.OutputInstance]) + nbDepsResolved[wireI]++ + } else { + assignment[wireI][instanceI].SetBigInt(ins[offsets[wireI]+instanceI-nbDepsResolved[wireI]]) + } + } else { + // assemble the inputs + inputIndexes := info.Circuit[wireI].Inputs + for i, inputI := range inputIndexes { + inputs[i].Set(&assignment[inputI][instanceI]) + } + gate := solvingData.circuit[wireI].Gate + assignment[wireI][instanceI] = gate.Evaluate(inputs[:len(inputIndexes)]...) + } + } + } + assignment.setOuts(info.Circuit, outs) return nil } } @@ -142,6 +134,9 @@ func gkrProveHint(hashName string, data *gkrSolvingData) hint.Function { offset += len(finalEvalProof) } } + + data.dumpAssignments() + return nil } @@ -152,6 +147,7 @@ func defineGkrHints(info constraint.GkrInfo, hintFunctions map[hint.ID]hint.Func for k, v := range hintFunctions { res[k] = v } + var gkrData gkrSolvingData res[info.SolveHintID] = gkrSolveHint(info, &gkrData) res[info.ProveHintID] = gkrProveHint(info.HashName, &gkrData) @@ -236,4 +232,4 @@ func (g negGate) Evaluate(element ...fr.Element) (neg fr.Element) { func (g negGate) Degree() int { return 1 -} +} \ No newline at end of file From 25fc396854c9fefc9a5caf2098acff1e655e4df9 Mon Sep 17 00:00:00 2001 From: Arya Tabaie Date: Wed, 25 Jan 2023 12:45:44 -0500 Subject: [PATCH 50/71] test: more instances --- std/gkr/api_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/std/gkr/api_test.go b/std/gkr/api_test.go index 3fc5a93dff..deaa65a5ed 100644 --- a/std/gkr/api_test.go +++ b/std/gkr/api_test.go @@ -586,7 +586,7 @@ func BenchmarkMiMCNoDepSolve(b *testing.B) { } func BenchmarkMiMCFullDepthNoDepSolve(b *testing.B) { - circuit, assignment := mimcNoDepCircuits(91, 1<<14) + circuit, assignment := mimcNoDepCircuits(91, 1<<19) benchProof(b, circuit, assignment) } @@ -596,7 +596,7 @@ func BenchmarkMiMCFullDepthNoDepCompile(b *testing.B) { } func BenchmarkMiMCNoGkrFullDepthSolve(b *testing.B) { - circuit, assignment := mimcNoGkrCircuits(91, 1<<14) + circuit, assignment := mimcNoGkrCircuits(91, 1<<19) benchProof(b, circuit, assignment) } From 0f45f166f5b5a7640072224a3e99db2d8f35ded6 Mon Sep 17 00:00:00 2001 From: Arya Tabaie Date: Sat, 28 Jan 2023 14:55:48 -0500 Subject: [PATCH 51/71] perf: reflect new gc gkr opts and parallelize solving --- constraint/bn254/gkr.go | 68 +++++++++++++++++++++++++++++------------ constraint/gkr.go | 26 +++++++++++++--- go.mod | 2 +- go.sum | 4 +-- 4 files changed, 73 insertions(+), 27 deletions(-) diff --git a/constraint/bn254/gkr.go b/constraint/bn254/gkr.go index 2551af9ae8..3c2652f3ca 100644 --- a/constraint/bn254/gkr.go +++ b/constraint/bn254/gkr.go @@ -17,21 +17,25 @@ package cs import ( + "fmt" "github.com/consensys/gnark-crypto/ecc/bn254/fr" "github.com/consensys/gnark-crypto/ecc/bn254/fr/gkr" "github.com/consensys/gnark-crypto/ecc/bn254/fr/polynomial" fiatshamir "github.com/consensys/gnark-crypto/fiat-shamir" + "github.com/consensys/gnark-crypto/utils" "github.com/consensys/gnark/backend/hint" "github.com/consensys/gnark/constraint" "github.com/consensys/gnark/std/utils/algo_utils" "hash" "math/big" + "time" ) type gkrSolvingData struct { assignments gkr.WireAssignment circuit gkr.Circuit memoryPool polynomial.Pool + workers utils.WorkerPool } func convertCircuit(noPtr constraint.GkrCircuit) gkr.Circuit { @@ -46,6 +50,7 @@ func convertCircuit(noPtr constraint.GkrCircuit) gkr.Circuit { func (d *gkrSolvingData) init(info constraint.GkrInfo) gkrAssignment { d.memoryPool = polynomial.NewPool(256, info.NbInstances) d.circuit = convertCircuit(info.Circuit) + d.workers = utils.NewWorkerPool() assignmentsSequential := make(gkrAssignment, len(d.circuit)) d.assignments = make(gkr.WireAssignment, len(d.circuit)) @@ -83,6 +88,8 @@ func (a gkrAssignment) setOuts(circuit constraint.GkrCircuit, outs []*big.Int) { func gkrSolveHint(info constraint.GkrInfo, solvingData *gkrSolvingData) hint.Function { return func(_ *big.Int, ins, outs []*big.Int) error { + startTime := time.Now().UnixMicro() + // assumes assignmentVector is arranged wire first, instance second in order of solution circuit := info.Circuit nbInstances := info.NbInstances @@ -90,30 +97,47 @@ func gkrSolveHint(info constraint.GkrInfo, solvingData *gkrSolvingData) hint.Fun nbDepsResolved := make([]int, len(circuit)) inputs := make([]fr.Element, info.MaxNIns) assignment := solvingData.init(info) - - for instanceI := 0; instanceI < nbInstances; instanceI++ { - for wireI, wire := range circuit { - if wire.IsInput() { - if nbDepsResolved[wireI] < len(wire.Dependencies) && instanceI == wire.Dependencies[nbDepsResolved[wireI]].InputInstance { - dep := wire.Dependencies[nbDepsResolved[wireI]] - assignment[wireI][instanceI].Set(&assignment[dep.OutputWire][dep.OutputInstance]) - nbDepsResolved[wireI]++ - } else { - assignment[wireI][instanceI].SetBigInt(ins[offsets[wireI]+instanceI-nbDepsResolved[wireI]]) - } - } else { - // assemble the inputs - inputIndexes := info.Circuit[wireI].Inputs - for i, inputI := range inputIndexes { - inputs[i].Set(&assignment[inputI][instanceI]) + chunks := circuit.Chunks(nbInstances) + + solveTask := func(chunkOffset int) utils.Task { + return func(startInChunk, endInChunk int) { + start := startInChunk + chunkOffset + end := endInChunk + chunkOffset + for instanceI := start; instanceI < end; instanceI++ { + for wireI, wire := range circuit { + if wire.IsInput() { + if nbDepsResolved[wireI] < len(wire.Dependencies) && instanceI == wire.Dependencies[nbDepsResolved[wireI]].InputInstance { + dep := wire.Dependencies[nbDepsResolved[wireI]] + assignment[wireI][instanceI].Set(&assignment[dep.OutputWire][dep.OutputInstance]) + nbDepsResolved[wireI]++ + } else { + assignment[wireI][instanceI].SetBigInt(ins[offsets[wireI]+instanceI-nbDepsResolved[wireI]]) + } + } else { + // assemble the inputs + inputIndexes := info.Circuit[wireI].Inputs + for i, inputI := range inputIndexes { + inputs[i].Set(&assignment[inputI][instanceI]) + } + gate := solvingData.circuit[wireI].Gate + assignment[wireI][instanceI] = gate.Evaluate(inputs[:len(inputIndexes)]...) + } } - gate := solvingData.circuit[wireI].Gate - assignment[wireI][instanceI] = gate.Evaluate(inputs[:len(inputIndexes)]...) } } } + start := 0 + for _, end := range chunks { + solvingData.workers.Dispatch(end-start, 1024, solveTask(start)).Wait() + start = end + } + assignment.setOuts(info.Circuit, outs) + + endTime := time.Now().UnixMicro() + fmt.Println("gkr solved in", endTime-startTime, "μs") + return nil } } @@ -127,6 +151,9 @@ func frToBigInts(dst []*big.Int, src []fr.Element) { func gkrProveHint(hashName string, data *gkrSolvingData) hint.Function { return func(_ *big.Int, ins, outs []*big.Int) error { + + startTime := time.Now().UnixMicro() + insBytes := algo_utils.Map(ins[1:], func(i *big.Int) []byte { // the first input is dummy, just to ensure the solver's work is done before the prover is called b := i.Bytes() return b[:] @@ -134,7 +161,7 @@ func gkrProveHint(hashName string, data *gkrSolvingData) hint.Function { hsh := HashBuilderRegistry[hashName]() - proof, err := gkr.Prove(data.circuit, data.assignments, fiatshamir.WithHash(hsh, insBytes...), gkr.WithPool(&data.memoryPool)) // TODO: Do transcriptSettings properly + proof, err := gkr.Prove(data.circuit, data.assignments, fiatshamir.WithHash(hsh, insBytes...), gkr.WithPool(&data.memoryPool), gkr.WithWorkers(&data.workers)) if err != nil { return err } @@ -155,6 +182,9 @@ func gkrProveHint(hashName string, data *gkrSolvingData) hint.Function { data.dumpAssignments() + endTime := time.Now().UnixMicro() + fmt.Println("gkr proved in", endTime-startTime, "μs") + return nil } diff --git a/constraint/gkr.go b/constraint/gkr.go index 486f9eadbc..7c40c35937 100644 --- a/constraint/gkr.go +++ b/constraint/gkr.go @@ -2,6 +2,7 @@ package constraint import ( "fmt" + "github.com/consensys/gnark-crypto/utils" "github.com/consensys/gnark/backend/hint" "github.com/consensys/gnark/std/utils/algo_utils" "sort" @@ -100,7 +101,7 @@ func (d *GkrInfo) Compile(nbInstances int) (GkrPermutations, error) { oldW := d.Circuit[oldI] if !oldW.IsInput() { - d.MaxNIns = max(d.MaxNIns, len(oldW.Inputs)) + d.MaxNIns = utils.Max(d.MaxNIns, len(oldW.Inputs)) } for j := range oldW.Dependencies { @@ -134,9 +135,24 @@ func (d *GkrInfo) Is() bool { return d.Circuit != nil } -func max(a, b int) int { - if a > b { - return a +// Chunks returns intervals of instances that are independent of each other and can be solved in parallel +func (c GkrCircuit) Chunks(nbInstances int) []int { + res := make([]int, 0, 1) + lastSeenDependencyI := make([]int, len(c)) + + for start, end := 0, 0; start != nbInstances; start = end { + end = nbInstances + endWireI := -1 + for wI, w := range c { + if wDepI := lastSeenDependencyI[wI]; wDepI < len(w.Dependencies) && w.Dependencies[wDepI].InputInstance < end { + end = w.Dependencies[wDepI].InputInstance + endWireI = wI + } + } + if endWireI != -1 { + lastSeenDependencyI[endWireI]++ + } + res = append(res, end) } - return b + return res } diff --git a/go.mod b/go.mod index 6dd3fe466e..aa1a998a3c 100644 --- a/go.mod +++ b/go.mod @@ -6,7 +6,7 @@ require ( github.com/bits-and-blooms/bitset v1.5.0 github.com/blang/semver/v4 v4.0.0 github.com/consensys/bavard v0.1.13 - github.com/consensys/gnark-crypto v0.9.0 + github.com/consensys/gnark-crypto v0.8.1-0.20230128191838-25572a87d2f0 github.com/ethereum/go-ethereum v1.10.26 github.com/fxamacker/cbor/v2 v2.2.0 github.com/google/go-cmp v0.5.8 diff --git a/go.sum b/go.sum index b98459742f..819cd9fee5 100644 --- a/go.sum +++ b/go.sum @@ -7,8 +7,8 @@ github.com/btcsuite/btcd/btcec/v2 v2.2.0/go.mod h1:U7MHm051Al6XmscBQ0BoNydpOTsFA github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1 h1:q0rUy8C/TYNBQS1+CGKw68tLOFYSNEs0TFnxxnS9+4U= github.com/consensys/bavard v0.1.13 h1:oLhMLOFGTLdlda/kma4VOJazblc7IM5y5QPd2A/YjhQ= github.com/consensys/bavard v0.1.13/go.mod h1:9ItSMtA/dXMAiL7BG6bqW2m3NdSEObYWoH223nGHukI= -github.com/consensys/gnark-crypto v0.9.0 h1:xspjHTygkgHmX4Behn00VJUTfEGvs+e6lFlfERfA28E= -github.com/consensys/gnark-crypto v0.9.0/go.mod h1:CkbdF9hbRidRJYMRzmfX8TMOr95I2pYXRHF18MzRrvA= +github.com/consensys/gnark-crypto v0.8.1-0.20230128191838-25572a87d2f0 h1:ZNavbFXuuJj/UvaYMFhu3Lxpk9Y0m2xO1Zp9nG11Ir4= +github.com/consensys/gnark-crypto v0.8.1-0.20230128191838-25572a87d2f0/go.mod h1:CkbdF9hbRidRJYMRzmfX8TMOr95I2pYXRHF18MzRrvA= github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= From 9e91467f3bbf6c196255060a9e74de8d55296cc4 Mon Sep 17 00:00:00 2001 From: Arya Tabaie Date: Sat, 28 Jan 2023 15:13:34 -0500 Subject: [PATCH 52/71] fix: bn254 mem pool --- constraint/bn254/gkr.go | 2 +- go.mod | 2 +- go.sum | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/constraint/bn254/gkr.go b/constraint/bn254/gkr.go index 3c2652f3ca..59b05af498 100644 --- a/constraint/bn254/gkr.go +++ b/constraint/bn254/gkr.go @@ -48,8 +48,8 @@ func convertCircuit(noPtr constraint.GkrCircuit) gkr.Circuit { } func (d *gkrSolvingData) init(info constraint.GkrInfo) gkrAssignment { - d.memoryPool = polynomial.NewPool(256, info.NbInstances) d.circuit = convertCircuit(info.Circuit) + d.memoryPool = polynomial.NewPool(d.circuit.MemoryRequirements(info.NbInstances)...) d.workers = utils.NewWorkerPool() assignmentsSequential := make(gkrAssignment, len(d.circuit)) diff --git a/go.mod b/go.mod index aa1a998a3c..8f09e0750b 100644 --- a/go.mod +++ b/go.mod @@ -6,7 +6,7 @@ require ( github.com/bits-and-blooms/bitset v1.5.0 github.com/blang/semver/v4 v4.0.0 github.com/consensys/bavard v0.1.13 - github.com/consensys/gnark-crypto v0.8.1-0.20230128191838-25572a87d2f0 + github.com/consensys/gnark-crypto v0.8.1-0.20230128201059-6a5cd08eaa0b github.com/ethereum/go-ethereum v1.10.26 github.com/fxamacker/cbor/v2 v2.2.0 github.com/google/go-cmp v0.5.8 diff --git a/go.sum b/go.sum index 819cd9fee5..5544b62366 100644 --- a/go.sum +++ b/go.sum @@ -7,8 +7,8 @@ github.com/btcsuite/btcd/btcec/v2 v2.2.0/go.mod h1:U7MHm051Al6XmscBQ0BoNydpOTsFA github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1 h1:q0rUy8C/TYNBQS1+CGKw68tLOFYSNEs0TFnxxnS9+4U= github.com/consensys/bavard v0.1.13 h1:oLhMLOFGTLdlda/kma4VOJazblc7IM5y5QPd2A/YjhQ= github.com/consensys/bavard v0.1.13/go.mod h1:9ItSMtA/dXMAiL7BG6bqW2m3NdSEObYWoH223nGHukI= -github.com/consensys/gnark-crypto v0.8.1-0.20230128191838-25572a87d2f0 h1:ZNavbFXuuJj/UvaYMFhu3Lxpk9Y0m2xO1Zp9nG11Ir4= -github.com/consensys/gnark-crypto v0.8.1-0.20230128191838-25572a87d2f0/go.mod h1:CkbdF9hbRidRJYMRzmfX8TMOr95I2pYXRHF18MzRrvA= +github.com/consensys/gnark-crypto v0.8.1-0.20230128201059-6a5cd08eaa0b h1:nfyx6D6TjnZII1Yta/UP7+cHeIbcmWZ3AaLnjwAjWqE= +github.com/consensys/gnark-crypto v0.8.1-0.20230128201059-6a5cd08eaa0b/go.mod h1:CkbdF9hbRidRJYMRzmfX8TMOr95I2pYXRHF18MzRrvA= github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= From 844ddffd7f04dc56db2af75704fd0ee0fbedec7a Mon Sep 17 00:00:00 2001 From: Arya Tabaie Date: Sat, 28 Jan 2023 16:06:35 -0500 Subject: [PATCH 53/71] test: only the gkr solver --- std/gkr/api_test.go | 32 +++++++++++++++++++++++++++++--- 1 file changed, 29 insertions(+), 3 deletions(-) diff --git a/std/gkr/api_test.go b/std/gkr/api_test.go index deaa65a5ed..474434a5a6 100644 --- a/std/gkr/api_test.go +++ b/std/gkr/api_test.go @@ -522,9 +522,10 @@ func BenchmarkMiMCMerkleTreeNoGkrNoDep(b *testing.B) { } type mimcNoDepCircuit struct { - X []frontend.Variable - Y []frontend.Variable - mimcDepth int + X []frontend.Variable + Y []frontend.Variable + mimcDepth int + solverOnly bool } func (c *mimcNoDepCircuit) Define(api frontend.API) error { @@ -557,9 +558,28 @@ func (c *mimcNoDepCircuit) Define(api frontend.API) error { return err } Z := solution.Export(z) + if c.solverOnly { + zCorrect := ToyMiMC(api, c.mimcDepth, c.X, c.Y) + for i := range zCorrect { + api.AssertIsEqual(zCorrect[i], Z[i]) + } + return nil + } return solution.Verify("-20", Z...) } +func ToyMiMC(api frontend.API, mimcDepth int, X, Y []frontend.Variable) []frontend.Variable { + Z := make([]frontend.Variable, len(X)) + gate := RegisteredGates["mimc"] + for i := range Z { + Z[i] = Y[i] + for n := 0; n < mimcDepth; n++ { + Z[i] = gate.Evaluate(api, X[i], Z[i]) + } + } + return Z +} + func mimcNoDepCircuits(mimcDepth, nbInstances int) (circuit, assignment frontend.Circuit) { X := make([]frontend.Variable, nbInstances) Y := make([]frontend.Variable, nbInstances) @@ -585,6 +605,12 @@ func BenchmarkMiMCNoDepSolve(b *testing.B) { benchProof(b, circuit, assignment) } +func TestMiMCFullDepthNoDepSolver(t *testing.T) { + circuit, assignment := mimcNoDepCircuits(91, 1<<19) + circuit.(*mimcNoDepCircuit).solverOnly = true + testE2E(t, circuit, assignment) +} + func BenchmarkMiMCFullDepthNoDepSolve(b *testing.B) { circuit, assignment := mimcNoDepCircuits(91, 1<<19) benchProof(b, circuit, assignment) From 1eeb1dcd1cef3549b4e11e2c6a9bae02995cf7ba Mon Sep 17 00:00:00 2001 From: Arya Tabaie Date: Sun, 29 Jan 2023 19:07:39 -0500 Subject: [PATCH 54/71] fix: solving bug - bn254 --- constraint/bn254/gkr.go | 20 +++++++++++++------ std/gkr/api_test.go | 2 +- std/utils/algo_utils/algo_utils.go | 31 ++++++++++++++++++++++++++++++ 3 files changed, 46 insertions(+), 7 deletions(-) diff --git a/constraint/bn254/gkr.go b/constraint/bn254/gkr.go index 59b05af498..7f31ffb057 100644 --- a/constraint/bn254/gkr.go +++ b/constraint/bn254/gkr.go @@ -94,8 +94,6 @@ func gkrSolveHint(info constraint.GkrInfo, solvingData *gkrSolvingData) hint.Fun circuit := info.Circuit nbInstances := info.NbInstances offsets := info.AssignmentOffsets() - nbDepsResolved := make([]int, len(circuit)) - inputs := make([]fr.Element, info.MaxNIns) assignment := solvingData.init(info) chunks := circuit.Chunks(nbInstances) @@ -103,15 +101,23 @@ func gkrSolveHint(info constraint.GkrInfo, solvingData *gkrSolvingData) hint.Fun return func(startInChunk, endInChunk int) { start := startInChunk + chunkOffset end := endInChunk + chunkOffset + inputs := solvingData.memoryPool.Make(info.MaxNIns) + dependencyHeads := make([]int, len(circuit)) + for wI, w := range circuit { + dependencyHeads[wI] = algo_utils.BinarySearchFunc(func(i int) int { + return w.Dependencies[i].InputInstance + }, len(w.Dependencies), start) + } + for instanceI := start; instanceI < end; instanceI++ { for wireI, wire := range circuit { if wire.IsInput() { - if nbDepsResolved[wireI] < len(wire.Dependencies) && instanceI == wire.Dependencies[nbDepsResolved[wireI]].InputInstance { - dep := wire.Dependencies[nbDepsResolved[wireI]] + if dependencyHeads[wireI] < len(wire.Dependencies) && instanceI == wire.Dependencies[dependencyHeads[wireI]].InputInstance { + dep := wire.Dependencies[dependencyHeads[wireI]] assignment[wireI][instanceI].Set(&assignment[dep.OutputWire][dep.OutputInstance]) - nbDepsResolved[wireI]++ + dependencyHeads[wireI]++ } else { - assignment[wireI][instanceI].SetBigInt(ins[offsets[wireI]+instanceI-nbDepsResolved[wireI]]) + assignment[wireI][instanceI].SetBigInt(ins[offsets[wireI]+instanceI-dependencyHeads[wireI]]) } } else { // assemble the inputs @@ -124,6 +130,8 @@ func gkrSolveHint(info constraint.GkrInfo, solvingData *gkrSolvingData) hint.Fun } } } + + solvingData.memoryPool.Dump(inputs) } } diff --git a/std/gkr/api_test.go b/std/gkr/api_test.go index 474434a5a6..f0aaf5414b 100644 --- a/std/gkr/api_test.go +++ b/std/gkr/api_test.go @@ -606,7 +606,7 @@ func BenchmarkMiMCNoDepSolve(b *testing.B) { } func TestMiMCFullDepthNoDepSolver(t *testing.T) { - circuit, assignment := mimcNoDepCircuits(91, 1<<19) + circuit, assignment := mimcNoDepCircuits(91, 1<<11) circuit.(*mimcNoDepCircuit).solverOnly = true testE2E(t, circuit, assignment) } diff --git a/std/utils/algo_utils/algo_utils.go b/std/utils/algo_utils/algo_utils.go index f94bb8eda5..37dbc8c464 100644 --- a/std/utils/algo_utils/algo_utils.go +++ b/std/utils/algo_utils/algo_utils.go @@ -142,3 +142,34 @@ func (d *topSortData) markDone(i int) { d.leastReady++ } } + +// BinarySearch looks for toFind in a sorted slice, and returns the index at which it either is or would be were it to be inserted. +func BinarySearch(slice []int, toFind int) int { + var start int + for end := len(slice); start != end; { + mid := (start + end) / 2 + if toFind >= slice[mid] { + start = mid + } + if toFind <= slice[mid] { + end = mid + } + } + return start +} + +// BinarySearchFunc looks for toFind in an increasing function of domain 0 ... (end-1), and returns the index at which it either is or would be were it to be inserted. +func BinarySearchFunc(eval func(int) int, end int, toFind int) int { + var start int + for start != end { + mid := (start + end) / 2 + val := eval(mid) + if toFind >= val { + start = mid + } + if toFind <= val { + end = mid + } + } + return start +} From 43623507eae9bbfca39b7a1d4ed345e3f85a4357 Mon Sep 17 00:00:00 2001 From: Arya Tabaie Date: Mon, 30 Jan 2023 00:09:04 -0500 Subject: [PATCH 55/71] build: generify --- constraint/bls12-377/gkr.go | 83 ++++++++++++++----- constraint/bls12-381/gkr.go | 83 ++++++++++++++----- constraint/bls24-315/gkr.go | 83 ++++++++++++++----- constraint/bls24-317/gkr.go | 83 ++++++++++++++----- constraint/bn254/gkr.go | 13 +-- constraint/bw6-633/gkr.go | 83 ++++++++++++++----- constraint/bw6-761/gkr.go | 83 ++++++++++++++----- go.mod | 2 +- go.sum | 4 +- .../template/representations/gkr.go.tmpl | 83 ++++++++++++++----- internal/tinyfield/element.go | 1 + 11 files changed, 446 insertions(+), 155 deletions(-) diff --git a/constraint/bls12-377/gkr.go b/constraint/bls12-377/gkr.go index 209a155763..5c1dbb3393 100644 --- a/constraint/bls12-377/gkr.go +++ b/constraint/bls12-377/gkr.go @@ -17,21 +17,25 @@ package cs import ( + "fmt" "github.com/consensys/gnark-crypto/ecc/bls12-377/fr" "github.com/consensys/gnark-crypto/ecc/bls12-377/fr/gkr" "github.com/consensys/gnark-crypto/ecc/bls12-377/fr/polynomial" fiatshamir "github.com/consensys/gnark-crypto/fiat-shamir" + "github.com/consensys/gnark-crypto/utils" "github.com/consensys/gnark/backend/hint" "github.com/consensys/gnark/constraint" "github.com/consensys/gnark/std/utils/algo_utils" "hash" "math/big" + "time" ) type gkrSolvingData struct { assignments gkr.WireAssignment circuit gkr.Circuit memoryPool polynomial.Pool + workers utils.WorkerPool } func convertCircuit(noPtr constraint.GkrCircuit) gkr.Circuit { @@ -44,8 +48,9 @@ func convertCircuit(noPtr constraint.GkrCircuit) gkr.Circuit { } func (d *gkrSolvingData) init(info constraint.GkrInfo) gkrAssignment { - d.memoryPool = polynomial.NewPool(256, info.NbInstances) d.circuit = convertCircuit(info.Circuit) + d.memoryPool = polynomial.NewPool(d.circuit.MemoryRequirements(info.NbInstances)...) + d.workers = utils.NewWorkerPool() assignmentsSequential := make(gkrAssignment, len(d.circuit)) d.assignments = make(gkr.WireAssignment, len(d.circuit)) @@ -80,40 +85,70 @@ func (a gkrAssignment) setOuts(circuit constraint.GkrCircuit, outs []*big.Int) { // Check if outsI == len(outs)? } +const log = true + func gkrSolveHint(info constraint.GkrInfo, solvingData *gkrSolvingData) hint.Function { return func(_ *big.Int, ins, outs []*big.Int) error { + startTime := time.Now().UnixMicro() + // assumes assignmentVector is arranged wire first, instance second in order of solution circuit := info.Circuit nbInstances := info.NbInstances offsets := info.AssignmentOffsets() - nbDepsResolved := make([]int, len(circuit)) - inputs := make([]fr.Element, info.MaxNIns) assignment := solvingData.init(info) + chunks := circuit.Chunks(nbInstances) + + solveTask := func(chunkOffset int) utils.Task { + return func(startInChunk, endInChunk int) { + start := startInChunk + chunkOffset + end := endInChunk + chunkOffset + inputs := solvingData.memoryPool.Make(info.MaxNIns) + dependencyHeads := make([]int, len(circuit)) + for wI, w := range circuit { + dependencyHeads[wI] = algo_utils.BinarySearchFunc(func(i int) int { + return w.Dependencies[i].InputInstance + }, len(w.Dependencies), start) + } - for instanceI := 0; instanceI < nbInstances; instanceI++ { - for wireI, wire := range circuit { - if wire.IsInput() { - if nbDepsResolved[wireI] < len(wire.Dependencies) && instanceI == wire.Dependencies[nbDepsResolved[wireI]].InputInstance { - dep := wire.Dependencies[nbDepsResolved[wireI]] - assignment[wireI][instanceI].Set(&assignment[dep.OutputWire][dep.OutputInstance]) - nbDepsResolved[wireI]++ - } else { - assignment[wireI][instanceI].SetBigInt(ins[offsets[wireI]+instanceI-nbDepsResolved[wireI]]) + for instanceI := start; instanceI < end; instanceI++ { + for wireI, wire := range circuit { + if wire.IsInput() { + if dependencyHeads[wireI] < len(wire.Dependencies) && instanceI == wire.Dependencies[dependencyHeads[wireI]].InputInstance { + dep := wire.Dependencies[dependencyHeads[wireI]] + assignment[wireI][instanceI].Set(&assignment[dep.OutputWire][dep.OutputInstance]) + dependencyHeads[wireI]++ + } else { + assignment[wireI][instanceI].SetBigInt(ins[offsets[wireI]+instanceI-dependencyHeads[wireI]]) + } + } else { + // assemble the inputs + inputIndexes := info.Circuit[wireI].Inputs + for i, inputI := range inputIndexes { + inputs[i].Set(&assignment[inputI][instanceI]) + } + gate := solvingData.circuit[wireI].Gate + assignment[wireI][instanceI] = gate.Evaluate(inputs[:len(inputIndexes)]...) + } } - } else { - // assemble the inputs - inputIndexes := info.Circuit[wireI].Inputs - for i, inputI := range inputIndexes { - inputs[i].Set(&assignment[inputI][instanceI]) - } - gate := solvingData.circuit[wireI].Gate - assignment[wireI][instanceI] = gate.Evaluate(inputs[:len(inputIndexes)]...) + solvingData.memoryPool.Dump(inputs) } } } + start := 0 + for _, end := range chunks { + solvingData.workers.Dispatch(end-start, 1024, solveTask(start)).Wait() + start = end + } + assignment.setOuts(info.Circuit, outs) + + if log { + endTime := time.Now().UnixMicro() + fmt.Println("gkr proved in", endTime-startTime, "μs") + } + return nil } } @@ -127,6 +162,9 @@ func frToBigInts(dst []*big.Int, src []fr.Element) { func gkrProveHint(hashName string, data *gkrSolvingData) hint.Function { return func(_ *big.Int, ins, outs []*big.Int) error { + + startTime := time.Now().UnixMicro() + insBytes := algo_utils.Map(ins[1:], func(i *big.Int) []byte { // the first input is dummy, just to ensure the solver's work is done before the prover is called b := i.Bytes() return b[:] @@ -134,7 +172,7 @@ func gkrProveHint(hashName string, data *gkrSolvingData) hint.Function { hsh := HashBuilderRegistry[hashName]() - proof, err := gkr.Prove(data.circuit, data.assignments, fiatshamir.WithHash(hsh, insBytes...), gkr.WithPool(&data.memoryPool)) // TODO: Do transcriptSettings properly + proof, err := gkr.Prove(data.circuit, data.assignments, fiatshamir.WithHash(hsh, insBytes...), gkr.WithPool(&data.memoryPool), gkr.WithWorkers(&data.workers)) if err != nil { return err } @@ -155,6 +193,9 @@ func gkrProveHint(hashName string, data *gkrSolvingData) hint.Function { data.dumpAssignments() + endTime := time.Now().UnixMicro() + fmt.Println("gkr solved in", endTime-startTime, "μs") + return nil } diff --git a/constraint/bls12-381/gkr.go b/constraint/bls12-381/gkr.go index c70cd89fd8..bc93c9d946 100644 --- a/constraint/bls12-381/gkr.go +++ b/constraint/bls12-381/gkr.go @@ -17,21 +17,25 @@ package cs import ( + "fmt" "github.com/consensys/gnark-crypto/ecc/bls12-381/fr" "github.com/consensys/gnark-crypto/ecc/bls12-381/fr/gkr" "github.com/consensys/gnark-crypto/ecc/bls12-381/fr/polynomial" fiatshamir "github.com/consensys/gnark-crypto/fiat-shamir" + "github.com/consensys/gnark-crypto/utils" "github.com/consensys/gnark/backend/hint" "github.com/consensys/gnark/constraint" "github.com/consensys/gnark/std/utils/algo_utils" "hash" "math/big" + "time" ) type gkrSolvingData struct { assignments gkr.WireAssignment circuit gkr.Circuit memoryPool polynomial.Pool + workers utils.WorkerPool } func convertCircuit(noPtr constraint.GkrCircuit) gkr.Circuit { @@ -44,8 +48,9 @@ func convertCircuit(noPtr constraint.GkrCircuit) gkr.Circuit { } func (d *gkrSolvingData) init(info constraint.GkrInfo) gkrAssignment { - d.memoryPool = polynomial.NewPool(256, info.NbInstances) d.circuit = convertCircuit(info.Circuit) + d.memoryPool = polynomial.NewPool(d.circuit.MemoryRequirements(info.NbInstances)...) + d.workers = utils.NewWorkerPool() assignmentsSequential := make(gkrAssignment, len(d.circuit)) d.assignments = make(gkr.WireAssignment, len(d.circuit)) @@ -80,40 +85,70 @@ func (a gkrAssignment) setOuts(circuit constraint.GkrCircuit, outs []*big.Int) { // Check if outsI == len(outs)? } +const log = true + func gkrSolveHint(info constraint.GkrInfo, solvingData *gkrSolvingData) hint.Function { return func(_ *big.Int, ins, outs []*big.Int) error { + startTime := time.Now().UnixMicro() + // assumes assignmentVector is arranged wire first, instance second in order of solution circuit := info.Circuit nbInstances := info.NbInstances offsets := info.AssignmentOffsets() - nbDepsResolved := make([]int, len(circuit)) - inputs := make([]fr.Element, info.MaxNIns) assignment := solvingData.init(info) + chunks := circuit.Chunks(nbInstances) + + solveTask := func(chunkOffset int) utils.Task { + return func(startInChunk, endInChunk int) { + start := startInChunk + chunkOffset + end := endInChunk + chunkOffset + inputs := solvingData.memoryPool.Make(info.MaxNIns) + dependencyHeads := make([]int, len(circuit)) + for wI, w := range circuit { + dependencyHeads[wI] = algo_utils.BinarySearchFunc(func(i int) int { + return w.Dependencies[i].InputInstance + }, len(w.Dependencies), start) + } - for instanceI := 0; instanceI < nbInstances; instanceI++ { - for wireI, wire := range circuit { - if wire.IsInput() { - if nbDepsResolved[wireI] < len(wire.Dependencies) && instanceI == wire.Dependencies[nbDepsResolved[wireI]].InputInstance { - dep := wire.Dependencies[nbDepsResolved[wireI]] - assignment[wireI][instanceI].Set(&assignment[dep.OutputWire][dep.OutputInstance]) - nbDepsResolved[wireI]++ - } else { - assignment[wireI][instanceI].SetBigInt(ins[offsets[wireI]+instanceI-nbDepsResolved[wireI]]) + for instanceI := start; instanceI < end; instanceI++ { + for wireI, wire := range circuit { + if wire.IsInput() { + if dependencyHeads[wireI] < len(wire.Dependencies) && instanceI == wire.Dependencies[dependencyHeads[wireI]].InputInstance { + dep := wire.Dependencies[dependencyHeads[wireI]] + assignment[wireI][instanceI].Set(&assignment[dep.OutputWire][dep.OutputInstance]) + dependencyHeads[wireI]++ + } else { + assignment[wireI][instanceI].SetBigInt(ins[offsets[wireI]+instanceI-dependencyHeads[wireI]]) + } + } else { + // assemble the inputs + inputIndexes := info.Circuit[wireI].Inputs + for i, inputI := range inputIndexes { + inputs[i].Set(&assignment[inputI][instanceI]) + } + gate := solvingData.circuit[wireI].Gate + assignment[wireI][instanceI] = gate.Evaluate(inputs[:len(inputIndexes)]...) + } } - } else { - // assemble the inputs - inputIndexes := info.Circuit[wireI].Inputs - for i, inputI := range inputIndexes { - inputs[i].Set(&assignment[inputI][instanceI]) - } - gate := solvingData.circuit[wireI].Gate - assignment[wireI][instanceI] = gate.Evaluate(inputs[:len(inputIndexes)]...) + solvingData.memoryPool.Dump(inputs) } } } + start := 0 + for _, end := range chunks { + solvingData.workers.Dispatch(end-start, 1024, solveTask(start)).Wait() + start = end + } + assignment.setOuts(info.Circuit, outs) + + if log { + endTime := time.Now().UnixMicro() + fmt.Println("gkr proved in", endTime-startTime, "μs") + } + return nil } } @@ -127,6 +162,9 @@ func frToBigInts(dst []*big.Int, src []fr.Element) { func gkrProveHint(hashName string, data *gkrSolvingData) hint.Function { return func(_ *big.Int, ins, outs []*big.Int) error { + + startTime := time.Now().UnixMicro() + insBytes := algo_utils.Map(ins[1:], func(i *big.Int) []byte { // the first input is dummy, just to ensure the solver's work is done before the prover is called b := i.Bytes() return b[:] @@ -134,7 +172,7 @@ func gkrProveHint(hashName string, data *gkrSolvingData) hint.Function { hsh := HashBuilderRegistry[hashName]() - proof, err := gkr.Prove(data.circuit, data.assignments, fiatshamir.WithHash(hsh, insBytes...), gkr.WithPool(&data.memoryPool)) // TODO: Do transcriptSettings properly + proof, err := gkr.Prove(data.circuit, data.assignments, fiatshamir.WithHash(hsh, insBytes...), gkr.WithPool(&data.memoryPool), gkr.WithWorkers(&data.workers)) if err != nil { return err } @@ -155,6 +193,9 @@ func gkrProveHint(hashName string, data *gkrSolvingData) hint.Function { data.dumpAssignments() + endTime := time.Now().UnixMicro() + fmt.Println("gkr solved in", endTime-startTime, "μs") + return nil } diff --git a/constraint/bls24-315/gkr.go b/constraint/bls24-315/gkr.go index 5dabba1acd..0b7055170f 100644 --- a/constraint/bls24-315/gkr.go +++ b/constraint/bls24-315/gkr.go @@ -17,21 +17,25 @@ package cs import ( + "fmt" "github.com/consensys/gnark-crypto/ecc/bls24-315/fr" "github.com/consensys/gnark-crypto/ecc/bls24-315/fr/gkr" "github.com/consensys/gnark-crypto/ecc/bls24-315/fr/polynomial" fiatshamir "github.com/consensys/gnark-crypto/fiat-shamir" + "github.com/consensys/gnark-crypto/utils" "github.com/consensys/gnark/backend/hint" "github.com/consensys/gnark/constraint" "github.com/consensys/gnark/std/utils/algo_utils" "hash" "math/big" + "time" ) type gkrSolvingData struct { assignments gkr.WireAssignment circuit gkr.Circuit memoryPool polynomial.Pool + workers utils.WorkerPool } func convertCircuit(noPtr constraint.GkrCircuit) gkr.Circuit { @@ -44,8 +48,9 @@ func convertCircuit(noPtr constraint.GkrCircuit) gkr.Circuit { } func (d *gkrSolvingData) init(info constraint.GkrInfo) gkrAssignment { - d.memoryPool = polynomial.NewPool(256, info.NbInstances) d.circuit = convertCircuit(info.Circuit) + d.memoryPool = polynomial.NewPool(d.circuit.MemoryRequirements(info.NbInstances)...) + d.workers = utils.NewWorkerPool() assignmentsSequential := make(gkrAssignment, len(d.circuit)) d.assignments = make(gkr.WireAssignment, len(d.circuit)) @@ -80,40 +85,70 @@ func (a gkrAssignment) setOuts(circuit constraint.GkrCircuit, outs []*big.Int) { // Check if outsI == len(outs)? } +const log = true + func gkrSolveHint(info constraint.GkrInfo, solvingData *gkrSolvingData) hint.Function { return func(_ *big.Int, ins, outs []*big.Int) error { + startTime := time.Now().UnixMicro() + // assumes assignmentVector is arranged wire first, instance second in order of solution circuit := info.Circuit nbInstances := info.NbInstances offsets := info.AssignmentOffsets() - nbDepsResolved := make([]int, len(circuit)) - inputs := make([]fr.Element, info.MaxNIns) assignment := solvingData.init(info) + chunks := circuit.Chunks(nbInstances) + + solveTask := func(chunkOffset int) utils.Task { + return func(startInChunk, endInChunk int) { + start := startInChunk + chunkOffset + end := endInChunk + chunkOffset + inputs := solvingData.memoryPool.Make(info.MaxNIns) + dependencyHeads := make([]int, len(circuit)) + for wI, w := range circuit { + dependencyHeads[wI] = algo_utils.BinarySearchFunc(func(i int) int { + return w.Dependencies[i].InputInstance + }, len(w.Dependencies), start) + } - for instanceI := 0; instanceI < nbInstances; instanceI++ { - for wireI, wire := range circuit { - if wire.IsInput() { - if nbDepsResolved[wireI] < len(wire.Dependencies) && instanceI == wire.Dependencies[nbDepsResolved[wireI]].InputInstance { - dep := wire.Dependencies[nbDepsResolved[wireI]] - assignment[wireI][instanceI].Set(&assignment[dep.OutputWire][dep.OutputInstance]) - nbDepsResolved[wireI]++ - } else { - assignment[wireI][instanceI].SetBigInt(ins[offsets[wireI]+instanceI-nbDepsResolved[wireI]]) + for instanceI := start; instanceI < end; instanceI++ { + for wireI, wire := range circuit { + if wire.IsInput() { + if dependencyHeads[wireI] < len(wire.Dependencies) && instanceI == wire.Dependencies[dependencyHeads[wireI]].InputInstance { + dep := wire.Dependencies[dependencyHeads[wireI]] + assignment[wireI][instanceI].Set(&assignment[dep.OutputWire][dep.OutputInstance]) + dependencyHeads[wireI]++ + } else { + assignment[wireI][instanceI].SetBigInt(ins[offsets[wireI]+instanceI-dependencyHeads[wireI]]) + } + } else { + // assemble the inputs + inputIndexes := info.Circuit[wireI].Inputs + for i, inputI := range inputIndexes { + inputs[i].Set(&assignment[inputI][instanceI]) + } + gate := solvingData.circuit[wireI].Gate + assignment[wireI][instanceI] = gate.Evaluate(inputs[:len(inputIndexes)]...) + } } - } else { - // assemble the inputs - inputIndexes := info.Circuit[wireI].Inputs - for i, inputI := range inputIndexes { - inputs[i].Set(&assignment[inputI][instanceI]) - } - gate := solvingData.circuit[wireI].Gate - assignment[wireI][instanceI] = gate.Evaluate(inputs[:len(inputIndexes)]...) + solvingData.memoryPool.Dump(inputs) } } } + start := 0 + for _, end := range chunks { + solvingData.workers.Dispatch(end-start, 1024, solveTask(start)).Wait() + start = end + } + assignment.setOuts(info.Circuit, outs) + + if log { + endTime := time.Now().UnixMicro() + fmt.Println("gkr proved in", endTime-startTime, "μs") + } + return nil } } @@ -127,6 +162,9 @@ func frToBigInts(dst []*big.Int, src []fr.Element) { func gkrProveHint(hashName string, data *gkrSolvingData) hint.Function { return func(_ *big.Int, ins, outs []*big.Int) error { + + startTime := time.Now().UnixMicro() + insBytes := algo_utils.Map(ins[1:], func(i *big.Int) []byte { // the first input is dummy, just to ensure the solver's work is done before the prover is called b := i.Bytes() return b[:] @@ -134,7 +172,7 @@ func gkrProveHint(hashName string, data *gkrSolvingData) hint.Function { hsh := HashBuilderRegistry[hashName]() - proof, err := gkr.Prove(data.circuit, data.assignments, fiatshamir.WithHash(hsh, insBytes...), gkr.WithPool(&data.memoryPool)) // TODO: Do transcriptSettings properly + proof, err := gkr.Prove(data.circuit, data.assignments, fiatshamir.WithHash(hsh, insBytes...), gkr.WithPool(&data.memoryPool), gkr.WithWorkers(&data.workers)) if err != nil { return err } @@ -155,6 +193,9 @@ func gkrProveHint(hashName string, data *gkrSolvingData) hint.Function { data.dumpAssignments() + endTime := time.Now().UnixMicro() + fmt.Println("gkr solved in", endTime-startTime, "μs") + return nil } diff --git a/constraint/bls24-317/gkr.go b/constraint/bls24-317/gkr.go index 5fbf12080b..2791d30e74 100644 --- a/constraint/bls24-317/gkr.go +++ b/constraint/bls24-317/gkr.go @@ -17,21 +17,25 @@ package cs import ( + "fmt" "github.com/consensys/gnark-crypto/ecc/bls24-317/fr" "github.com/consensys/gnark-crypto/ecc/bls24-317/fr/gkr" "github.com/consensys/gnark-crypto/ecc/bls24-317/fr/polynomial" fiatshamir "github.com/consensys/gnark-crypto/fiat-shamir" + "github.com/consensys/gnark-crypto/utils" "github.com/consensys/gnark/backend/hint" "github.com/consensys/gnark/constraint" "github.com/consensys/gnark/std/utils/algo_utils" "hash" "math/big" + "time" ) type gkrSolvingData struct { assignments gkr.WireAssignment circuit gkr.Circuit memoryPool polynomial.Pool + workers utils.WorkerPool } func convertCircuit(noPtr constraint.GkrCircuit) gkr.Circuit { @@ -44,8 +48,9 @@ func convertCircuit(noPtr constraint.GkrCircuit) gkr.Circuit { } func (d *gkrSolvingData) init(info constraint.GkrInfo) gkrAssignment { - d.memoryPool = polynomial.NewPool(256, info.NbInstances) d.circuit = convertCircuit(info.Circuit) + d.memoryPool = polynomial.NewPool(d.circuit.MemoryRequirements(info.NbInstances)...) + d.workers = utils.NewWorkerPool() assignmentsSequential := make(gkrAssignment, len(d.circuit)) d.assignments = make(gkr.WireAssignment, len(d.circuit)) @@ -80,40 +85,70 @@ func (a gkrAssignment) setOuts(circuit constraint.GkrCircuit, outs []*big.Int) { // Check if outsI == len(outs)? } +const log = true + func gkrSolveHint(info constraint.GkrInfo, solvingData *gkrSolvingData) hint.Function { return func(_ *big.Int, ins, outs []*big.Int) error { + startTime := time.Now().UnixMicro() + // assumes assignmentVector is arranged wire first, instance second in order of solution circuit := info.Circuit nbInstances := info.NbInstances offsets := info.AssignmentOffsets() - nbDepsResolved := make([]int, len(circuit)) - inputs := make([]fr.Element, info.MaxNIns) assignment := solvingData.init(info) + chunks := circuit.Chunks(nbInstances) + + solveTask := func(chunkOffset int) utils.Task { + return func(startInChunk, endInChunk int) { + start := startInChunk + chunkOffset + end := endInChunk + chunkOffset + inputs := solvingData.memoryPool.Make(info.MaxNIns) + dependencyHeads := make([]int, len(circuit)) + for wI, w := range circuit { + dependencyHeads[wI] = algo_utils.BinarySearchFunc(func(i int) int { + return w.Dependencies[i].InputInstance + }, len(w.Dependencies), start) + } - for instanceI := 0; instanceI < nbInstances; instanceI++ { - for wireI, wire := range circuit { - if wire.IsInput() { - if nbDepsResolved[wireI] < len(wire.Dependencies) && instanceI == wire.Dependencies[nbDepsResolved[wireI]].InputInstance { - dep := wire.Dependencies[nbDepsResolved[wireI]] - assignment[wireI][instanceI].Set(&assignment[dep.OutputWire][dep.OutputInstance]) - nbDepsResolved[wireI]++ - } else { - assignment[wireI][instanceI].SetBigInt(ins[offsets[wireI]+instanceI-nbDepsResolved[wireI]]) + for instanceI := start; instanceI < end; instanceI++ { + for wireI, wire := range circuit { + if wire.IsInput() { + if dependencyHeads[wireI] < len(wire.Dependencies) && instanceI == wire.Dependencies[dependencyHeads[wireI]].InputInstance { + dep := wire.Dependencies[dependencyHeads[wireI]] + assignment[wireI][instanceI].Set(&assignment[dep.OutputWire][dep.OutputInstance]) + dependencyHeads[wireI]++ + } else { + assignment[wireI][instanceI].SetBigInt(ins[offsets[wireI]+instanceI-dependencyHeads[wireI]]) + } + } else { + // assemble the inputs + inputIndexes := info.Circuit[wireI].Inputs + for i, inputI := range inputIndexes { + inputs[i].Set(&assignment[inputI][instanceI]) + } + gate := solvingData.circuit[wireI].Gate + assignment[wireI][instanceI] = gate.Evaluate(inputs[:len(inputIndexes)]...) + } } - } else { - // assemble the inputs - inputIndexes := info.Circuit[wireI].Inputs - for i, inputI := range inputIndexes { - inputs[i].Set(&assignment[inputI][instanceI]) - } - gate := solvingData.circuit[wireI].Gate - assignment[wireI][instanceI] = gate.Evaluate(inputs[:len(inputIndexes)]...) + solvingData.memoryPool.Dump(inputs) } } } + start := 0 + for _, end := range chunks { + solvingData.workers.Dispatch(end-start, 1024, solveTask(start)).Wait() + start = end + } + assignment.setOuts(info.Circuit, outs) + + if log { + endTime := time.Now().UnixMicro() + fmt.Println("gkr proved in", endTime-startTime, "μs") + } + return nil } } @@ -127,6 +162,9 @@ func frToBigInts(dst []*big.Int, src []fr.Element) { func gkrProveHint(hashName string, data *gkrSolvingData) hint.Function { return func(_ *big.Int, ins, outs []*big.Int) error { + + startTime := time.Now().UnixMicro() + insBytes := algo_utils.Map(ins[1:], func(i *big.Int) []byte { // the first input is dummy, just to ensure the solver's work is done before the prover is called b := i.Bytes() return b[:] @@ -134,7 +172,7 @@ func gkrProveHint(hashName string, data *gkrSolvingData) hint.Function { hsh := HashBuilderRegistry[hashName]() - proof, err := gkr.Prove(data.circuit, data.assignments, fiatshamir.WithHash(hsh, insBytes...), gkr.WithPool(&data.memoryPool)) // TODO: Do transcriptSettings properly + proof, err := gkr.Prove(data.circuit, data.assignments, fiatshamir.WithHash(hsh, insBytes...), gkr.WithPool(&data.memoryPool), gkr.WithWorkers(&data.workers)) if err != nil { return err } @@ -155,6 +193,9 @@ func gkrProveHint(hashName string, data *gkrSolvingData) hint.Function { data.dumpAssignments() + endTime := time.Now().UnixMicro() + fmt.Println("gkr solved in", endTime-startTime, "μs") + return nil } diff --git a/constraint/bn254/gkr.go b/constraint/bn254/gkr.go index 7f31ffb057..5d7627b400 100644 --- a/constraint/bn254/gkr.go +++ b/constraint/bn254/gkr.go @@ -85,6 +85,8 @@ func (a gkrAssignment) setOuts(circuit constraint.GkrCircuit, outs []*big.Int) { // Check if outsI == len(outs)? } +const log = true + func gkrSolveHint(info constraint.GkrInfo, solvingData *gkrSolvingData) hint.Function { return func(_ *big.Int, ins, outs []*big.Int) error { @@ -129,9 +131,8 @@ func gkrSolveHint(info constraint.GkrInfo, solvingData *gkrSolvingData) hint.Fun assignment[wireI][instanceI] = gate.Evaluate(inputs[:len(inputIndexes)]...) } } + solvingData.memoryPool.Dump(inputs) } - - solvingData.memoryPool.Dump(inputs) } } @@ -143,8 +144,10 @@ func gkrSolveHint(info constraint.GkrInfo, solvingData *gkrSolvingData) hint.Fun assignment.setOuts(info.Circuit, outs) - endTime := time.Now().UnixMicro() - fmt.Println("gkr solved in", endTime-startTime, "μs") + if log { + endTime := time.Now().UnixMicro() + fmt.Println("gkr proved in", endTime-startTime, "μs") + } return nil } @@ -191,7 +194,7 @@ func gkrProveHint(hashName string, data *gkrSolvingData) hint.Function { data.dumpAssignments() endTime := time.Now().UnixMicro() - fmt.Println("gkr proved in", endTime-startTime, "μs") + fmt.Println("gkr solved in", endTime-startTime, "μs") return nil diff --git a/constraint/bw6-633/gkr.go b/constraint/bw6-633/gkr.go index db88f06200..f963cd325e 100644 --- a/constraint/bw6-633/gkr.go +++ b/constraint/bw6-633/gkr.go @@ -17,21 +17,25 @@ package cs import ( + "fmt" "github.com/consensys/gnark-crypto/ecc/bw6-633/fr" "github.com/consensys/gnark-crypto/ecc/bw6-633/fr/gkr" "github.com/consensys/gnark-crypto/ecc/bw6-633/fr/polynomial" fiatshamir "github.com/consensys/gnark-crypto/fiat-shamir" + "github.com/consensys/gnark-crypto/utils" "github.com/consensys/gnark/backend/hint" "github.com/consensys/gnark/constraint" "github.com/consensys/gnark/std/utils/algo_utils" "hash" "math/big" + "time" ) type gkrSolvingData struct { assignments gkr.WireAssignment circuit gkr.Circuit memoryPool polynomial.Pool + workers utils.WorkerPool } func convertCircuit(noPtr constraint.GkrCircuit) gkr.Circuit { @@ -44,8 +48,9 @@ func convertCircuit(noPtr constraint.GkrCircuit) gkr.Circuit { } func (d *gkrSolvingData) init(info constraint.GkrInfo) gkrAssignment { - d.memoryPool = polynomial.NewPool(256, info.NbInstances) d.circuit = convertCircuit(info.Circuit) + d.memoryPool = polynomial.NewPool(d.circuit.MemoryRequirements(info.NbInstances)...) + d.workers = utils.NewWorkerPool() assignmentsSequential := make(gkrAssignment, len(d.circuit)) d.assignments = make(gkr.WireAssignment, len(d.circuit)) @@ -80,40 +85,70 @@ func (a gkrAssignment) setOuts(circuit constraint.GkrCircuit, outs []*big.Int) { // Check if outsI == len(outs)? } +const log = true + func gkrSolveHint(info constraint.GkrInfo, solvingData *gkrSolvingData) hint.Function { return func(_ *big.Int, ins, outs []*big.Int) error { + startTime := time.Now().UnixMicro() + // assumes assignmentVector is arranged wire first, instance second in order of solution circuit := info.Circuit nbInstances := info.NbInstances offsets := info.AssignmentOffsets() - nbDepsResolved := make([]int, len(circuit)) - inputs := make([]fr.Element, info.MaxNIns) assignment := solvingData.init(info) + chunks := circuit.Chunks(nbInstances) + + solveTask := func(chunkOffset int) utils.Task { + return func(startInChunk, endInChunk int) { + start := startInChunk + chunkOffset + end := endInChunk + chunkOffset + inputs := solvingData.memoryPool.Make(info.MaxNIns) + dependencyHeads := make([]int, len(circuit)) + for wI, w := range circuit { + dependencyHeads[wI] = algo_utils.BinarySearchFunc(func(i int) int { + return w.Dependencies[i].InputInstance + }, len(w.Dependencies), start) + } - for instanceI := 0; instanceI < nbInstances; instanceI++ { - for wireI, wire := range circuit { - if wire.IsInput() { - if nbDepsResolved[wireI] < len(wire.Dependencies) && instanceI == wire.Dependencies[nbDepsResolved[wireI]].InputInstance { - dep := wire.Dependencies[nbDepsResolved[wireI]] - assignment[wireI][instanceI].Set(&assignment[dep.OutputWire][dep.OutputInstance]) - nbDepsResolved[wireI]++ - } else { - assignment[wireI][instanceI].SetBigInt(ins[offsets[wireI]+instanceI-nbDepsResolved[wireI]]) + for instanceI := start; instanceI < end; instanceI++ { + for wireI, wire := range circuit { + if wire.IsInput() { + if dependencyHeads[wireI] < len(wire.Dependencies) && instanceI == wire.Dependencies[dependencyHeads[wireI]].InputInstance { + dep := wire.Dependencies[dependencyHeads[wireI]] + assignment[wireI][instanceI].Set(&assignment[dep.OutputWire][dep.OutputInstance]) + dependencyHeads[wireI]++ + } else { + assignment[wireI][instanceI].SetBigInt(ins[offsets[wireI]+instanceI-dependencyHeads[wireI]]) + } + } else { + // assemble the inputs + inputIndexes := info.Circuit[wireI].Inputs + for i, inputI := range inputIndexes { + inputs[i].Set(&assignment[inputI][instanceI]) + } + gate := solvingData.circuit[wireI].Gate + assignment[wireI][instanceI] = gate.Evaluate(inputs[:len(inputIndexes)]...) + } } - } else { - // assemble the inputs - inputIndexes := info.Circuit[wireI].Inputs - for i, inputI := range inputIndexes { - inputs[i].Set(&assignment[inputI][instanceI]) - } - gate := solvingData.circuit[wireI].Gate - assignment[wireI][instanceI] = gate.Evaluate(inputs[:len(inputIndexes)]...) + solvingData.memoryPool.Dump(inputs) } } } + start := 0 + for _, end := range chunks { + solvingData.workers.Dispatch(end-start, 1024, solveTask(start)).Wait() + start = end + } + assignment.setOuts(info.Circuit, outs) + + if log { + endTime := time.Now().UnixMicro() + fmt.Println("gkr proved in", endTime-startTime, "μs") + } + return nil } } @@ -127,6 +162,9 @@ func frToBigInts(dst []*big.Int, src []fr.Element) { func gkrProveHint(hashName string, data *gkrSolvingData) hint.Function { return func(_ *big.Int, ins, outs []*big.Int) error { + + startTime := time.Now().UnixMicro() + insBytes := algo_utils.Map(ins[1:], func(i *big.Int) []byte { // the first input is dummy, just to ensure the solver's work is done before the prover is called b := i.Bytes() return b[:] @@ -134,7 +172,7 @@ func gkrProveHint(hashName string, data *gkrSolvingData) hint.Function { hsh := HashBuilderRegistry[hashName]() - proof, err := gkr.Prove(data.circuit, data.assignments, fiatshamir.WithHash(hsh, insBytes...), gkr.WithPool(&data.memoryPool)) // TODO: Do transcriptSettings properly + proof, err := gkr.Prove(data.circuit, data.assignments, fiatshamir.WithHash(hsh, insBytes...), gkr.WithPool(&data.memoryPool), gkr.WithWorkers(&data.workers)) if err != nil { return err } @@ -155,6 +193,9 @@ func gkrProveHint(hashName string, data *gkrSolvingData) hint.Function { data.dumpAssignments() + endTime := time.Now().UnixMicro() + fmt.Println("gkr solved in", endTime-startTime, "μs") + return nil } diff --git a/constraint/bw6-761/gkr.go b/constraint/bw6-761/gkr.go index 70392089a9..39e78232c7 100644 --- a/constraint/bw6-761/gkr.go +++ b/constraint/bw6-761/gkr.go @@ -17,21 +17,25 @@ package cs import ( + "fmt" "github.com/consensys/gnark-crypto/ecc/bw6-761/fr" "github.com/consensys/gnark-crypto/ecc/bw6-761/fr/gkr" "github.com/consensys/gnark-crypto/ecc/bw6-761/fr/polynomial" fiatshamir "github.com/consensys/gnark-crypto/fiat-shamir" + "github.com/consensys/gnark-crypto/utils" "github.com/consensys/gnark/backend/hint" "github.com/consensys/gnark/constraint" "github.com/consensys/gnark/std/utils/algo_utils" "hash" "math/big" + "time" ) type gkrSolvingData struct { assignments gkr.WireAssignment circuit gkr.Circuit memoryPool polynomial.Pool + workers utils.WorkerPool } func convertCircuit(noPtr constraint.GkrCircuit) gkr.Circuit { @@ -44,8 +48,9 @@ func convertCircuit(noPtr constraint.GkrCircuit) gkr.Circuit { } func (d *gkrSolvingData) init(info constraint.GkrInfo) gkrAssignment { - d.memoryPool = polynomial.NewPool(256, info.NbInstances) d.circuit = convertCircuit(info.Circuit) + d.memoryPool = polynomial.NewPool(d.circuit.MemoryRequirements(info.NbInstances)...) + d.workers = utils.NewWorkerPool() assignmentsSequential := make(gkrAssignment, len(d.circuit)) d.assignments = make(gkr.WireAssignment, len(d.circuit)) @@ -80,40 +85,70 @@ func (a gkrAssignment) setOuts(circuit constraint.GkrCircuit, outs []*big.Int) { // Check if outsI == len(outs)? } +const log = true + func gkrSolveHint(info constraint.GkrInfo, solvingData *gkrSolvingData) hint.Function { return func(_ *big.Int, ins, outs []*big.Int) error { + startTime := time.Now().UnixMicro() + // assumes assignmentVector is arranged wire first, instance second in order of solution circuit := info.Circuit nbInstances := info.NbInstances offsets := info.AssignmentOffsets() - nbDepsResolved := make([]int, len(circuit)) - inputs := make([]fr.Element, info.MaxNIns) assignment := solvingData.init(info) + chunks := circuit.Chunks(nbInstances) + + solveTask := func(chunkOffset int) utils.Task { + return func(startInChunk, endInChunk int) { + start := startInChunk + chunkOffset + end := endInChunk + chunkOffset + inputs := solvingData.memoryPool.Make(info.MaxNIns) + dependencyHeads := make([]int, len(circuit)) + for wI, w := range circuit { + dependencyHeads[wI] = algo_utils.BinarySearchFunc(func(i int) int { + return w.Dependencies[i].InputInstance + }, len(w.Dependencies), start) + } - for instanceI := 0; instanceI < nbInstances; instanceI++ { - for wireI, wire := range circuit { - if wire.IsInput() { - if nbDepsResolved[wireI] < len(wire.Dependencies) && instanceI == wire.Dependencies[nbDepsResolved[wireI]].InputInstance { - dep := wire.Dependencies[nbDepsResolved[wireI]] - assignment[wireI][instanceI].Set(&assignment[dep.OutputWire][dep.OutputInstance]) - nbDepsResolved[wireI]++ - } else { - assignment[wireI][instanceI].SetBigInt(ins[offsets[wireI]+instanceI-nbDepsResolved[wireI]]) + for instanceI := start; instanceI < end; instanceI++ { + for wireI, wire := range circuit { + if wire.IsInput() { + if dependencyHeads[wireI] < len(wire.Dependencies) && instanceI == wire.Dependencies[dependencyHeads[wireI]].InputInstance { + dep := wire.Dependencies[dependencyHeads[wireI]] + assignment[wireI][instanceI].Set(&assignment[dep.OutputWire][dep.OutputInstance]) + dependencyHeads[wireI]++ + } else { + assignment[wireI][instanceI].SetBigInt(ins[offsets[wireI]+instanceI-dependencyHeads[wireI]]) + } + } else { + // assemble the inputs + inputIndexes := info.Circuit[wireI].Inputs + for i, inputI := range inputIndexes { + inputs[i].Set(&assignment[inputI][instanceI]) + } + gate := solvingData.circuit[wireI].Gate + assignment[wireI][instanceI] = gate.Evaluate(inputs[:len(inputIndexes)]...) + } } - } else { - // assemble the inputs - inputIndexes := info.Circuit[wireI].Inputs - for i, inputI := range inputIndexes { - inputs[i].Set(&assignment[inputI][instanceI]) - } - gate := solvingData.circuit[wireI].Gate - assignment[wireI][instanceI] = gate.Evaluate(inputs[:len(inputIndexes)]...) + solvingData.memoryPool.Dump(inputs) } } } + start := 0 + for _, end := range chunks { + solvingData.workers.Dispatch(end-start, 1024, solveTask(start)).Wait() + start = end + } + assignment.setOuts(info.Circuit, outs) + + if log { + endTime := time.Now().UnixMicro() + fmt.Println("gkr proved in", endTime-startTime, "μs") + } + return nil } } @@ -127,6 +162,9 @@ func frToBigInts(dst []*big.Int, src []fr.Element) { func gkrProveHint(hashName string, data *gkrSolvingData) hint.Function { return func(_ *big.Int, ins, outs []*big.Int) error { + + startTime := time.Now().UnixMicro() + insBytes := algo_utils.Map(ins[1:], func(i *big.Int) []byte { // the first input is dummy, just to ensure the solver's work is done before the prover is called b := i.Bytes() return b[:] @@ -134,7 +172,7 @@ func gkrProveHint(hashName string, data *gkrSolvingData) hint.Function { hsh := HashBuilderRegistry[hashName]() - proof, err := gkr.Prove(data.circuit, data.assignments, fiatshamir.WithHash(hsh, insBytes...), gkr.WithPool(&data.memoryPool)) // TODO: Do transcriptSettings properly + proof, err := gkr.Prove(data.circuit, data.assignments, fiatshamir.WithHash(hsh, insBytes...), gkr.WithPool(&data.memoryPool), gkr.WithWorkers(&data.workers)) if err != nil { return err } @@ -155,6 +193,9 @@ func gkrProveHint(hashName string, data *gkrSolvingData) hint.Function { data.dumpAssignments() + endTime := time.Now().UnixMicro() + fmt.Println("gkr solved in", endTime-startTime, "μs") + return nil } diff --git a/go.mod b/go.mod index 8f09e0750b..ef67a9afd8 100644 --- a/go.mod +++ b/go.mod @@ -6,7 +6,7 @@ require ( github.com/bits-and-blooms/bitset v1.5.0 github.com/blang/semver/v4 v4.0.0 github.com/consensys/bavard v0.1.13 - github.com/consensys/gnark-crypto v0.8.1-0.20230128201059-6a5cd08eaa0b + github.com/consensys/gnark-crypto v0.8.1-0.20230130045319-9d9a6a9f3978 github.com/ethereum/go-ethereum v1.10.26 github.com/fxamacker/cbor/v2 v2.2.0 github.com/google/go-cmp v0.5.8 diff --git a/go.sum b/go.sum index 5544b62366..90ec705fb2 100644 --- a/go.sum +++ b/go.sum @@ -7,8 +7,8 @@ github.com/btcsuite/btcd/btcec/v2 v2.2.0/go.mod h1:U7MHm051Al6XmscBQ0BoNydpOTsFA github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1 h1:q0rUy8C/TYNBQS1+CGKw68tLOFYSNEs0TFnxxnS9+4U= github.com/consensys/bavard v0.1.13 h1:oLhMLOFGTLdlda/kma4VOJazblc7IM5y5QPd2A/YjhQ= github.com/consensys/bavard v0.1.13/go.mod h1:9ItSMtA/dXMAiL7BG6bqW2m3NdSEObYWoH223nGHukI= -github.com/consensys/gnark-crypto v0.8.1-0.20230128201059-6a5cd08eaa0b h1:nfyx6D6TjnZII1Yta/UP7+cHeIbcmWZ3AaLnjwAjWqE= -github.com/consensys/gnark-crypto v0.8.1-0.20230128201059-6a5cd08eaa0b/go.mod h1:CkbdF9hbRidRJYMRzmfX8TMOr95I2pYXRHF18MzRrvA= +github.com/consensys/gnark-crypto v0.8.1-0.20230130045319-9d9a6a9f3978 h1:wSzIfUOIF16DVPtTlSu1TV864nF+t11kQAx2Oy6ThAo= +github.com/consensys/gnark-crypto v0.8.1-0.20230130045319-9d9a6a9f3978/go.mod h1:CkbdF9hbRidRJYMRzmfX8TMOr95I2pYXRHF18MzRrvA= github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= diff --git a/internal/generator/backend/template/representations/gkr.go.tmpl b/internal/generator/backend/template/representations/gkr.go.tmpl index 47143ea70c..5341834503 100644 --- a/internal/generator/backend/template/representations/gkr.go.tmpl +++ b/internal/generator/backend/template/representations/gkr.go.tmpl @@ -1,19 +1,23 @@ import ( + "fmt" {{- template "import_fr" .}} {{- template "import_gkr" .}} {{- template "import_polynomial" .}} fiatshamir "github.com/consensys/gnark-crypto/fiat-shamir" + "github.com/consensys/gnark-crypto/utils" "github.com/consensys/gnark/backend/hint" "github.com/consensys/gnark/constraint" "github.com/consensys/gnark/std/utils/algo_utils" "hash" "math/big" + "time" ) type gkrSolvingData struct { assignments gkr.WireAssignment circuit gkr.Circuit memoryPool polynomial.Pool + workers utils.WorkerPool } func convertCircuit(noPtr constraint.GkrCircuit) gkr.Circuit { @@ -26,8 +30,9 @@ func convertCircuit(noPtr constraint.GkrCircuit) gkr.Circuit { } func (d *gkrSolvingData) init(info constraint.GkrInfo) gkrAssignment { - d.memoryPool = polynomial.NewPool(256, info.NbInstances) d.circuit = convertCircuit(info.Circuit) + d.memoryPool = polynomial.NewPool(d.circuit.MemoryRequirements(info.NbInstances)...) + d.workers = utils.NewWorkerPool() assignmentsSequential := make(gkrAssignment, len(d.circuit)) d.assignments = make(gkr.WireAssignment, len(d.circuit)) @@ -62,40 +67,70 @@ func (a gkrAssignment) setOuts(circuit constraint.GkrCircuit, outs []*big.Int) { // Check if outsI == len(outs)? } +const log = true + func gkrSolveHint(info constraint.GkrInfo, solvingData *gkrSolvingData) hint.Function { return func(_ *big.Int, ins, outs []*big.Int) error { + startTime := time.Now().UnixMicro() + // assumes assignmentVector is arranged wire first, instance second in order of solution circuit := info.Circuit nbInstances := info.NbInstances offsets := info.AssignmentOffsets() - nbDepsResolved := make([]int, len(circuit)) - inputs := make([]fr.Element, info.MaxNIns) assignment := solvingData.init(info) + chunks := circuit.Chunks(nbInstances) + + solveTask := func(chunkOffset int) utils.Task { + return func(startInChunk, endInChunk int) { + start := startInChunk + chunkOffset + end := endInChunk + chunkOffset + inputs := solvingData.memoryPool.Make(info.MaxNIns) + dependencyHeads := make([]int, len(circuit)) + for wI, w := range circuit { + dependencyHeads[wI] = algo_utils.BinarySearchFunc(func(i int) int { + return w.Dependencies[i].InputInstance + }, len(w.Dependencies), start) + } - for instanceI := 0; instanceI < nbInstances; instanceI++ { - for wireI, wire := range circuit { - if wire.IsInput() { - if nbDepsResolved[wireI] < len(wire.Dependencies) && instanceI == wire.Dependencies[nbDepsResolved[wireI]].InputInstance { - dep := wire.Dependencies[nbDepsResolved[wireI]] - assignment[wireI][instanceI].Set(&assignment[dep.OutputWire][dep.OutputInstance]) - nbDepsResolved[wireI]++ - } else { - assignment[wireI][instanceI].SetBigInt(ins[offsets[wireI]+instanceI-nbDepsResolved[wireI]]) + for instanceI := start; instanceI < end; instanceI++ { + for wireI, wire := range circuit { + if wire.IsInput() { + if dependencyHeads[wireI] < len(wire.Dependencies) && instanceI == wire.Dependencies[dependencyHeads[wireI]].InputInstance { + dep := wire.Dependencies[dependencyHeads[wireI]] + assignment[wireI][instanceI].Set(&assignment[dep.OutputWire][dep.OutputInstance]) + dependencyHeads[wireI]++ + } else { + assignment[wireI][instanceI].SetBigInt(ins[offsets[wireI]+instanceI-dependencyHeads[wireI]]) + } + } else { + // assemble the inputs + inputIndexes := info.Circuit[wireI].Inputs + for i, inputI := range inputIndexes { + inputs[i].Set(&assignment[inputI][instanceI]) + } + gate := solvingData.circuit[wireI].Gate + assignment[wireI][instanceI] = gate.Evaluate(inputs[:len(inputIndexes)]...) + } } - } else { - // assemble the inputs - inputIndexes := info.Circuit[wireI].Inputs - for i, inputI := range inputIndexes { - inputs[i].Set(&assignment[inputI][instanceI]) - } - gate := solvingData.circuit[wireI].Gate - assignment[wireI][instanceI] = gate.Evaluate(inputs[:len(inputIndexes)]...) + solvingData.memoryPool.Dump(inputs) } } } + start := 0 + for _, end := range chunks { + solvingData.workers.Dispatch(end-start, 1024, solveTask(start)).Wait() + start = end + } + assignment.setOuts(info.Circuit, outs) + + if log { + endTime := time.Now().UnixMicro() + fmt.Println("gkr proved in", endTime-startTime, "μs") + } + return nil } } @@ -109,6 +144,9 @@ func frToBigInts(dst []*big.Int, src []fr.Element) { func gkrProveHint(hashName string, data *gkrSolvingData) hint.Function { return func(_ *big.Int, ins, outs []*big.Int) error { + + startTime := time.Now().UnixMicro() + insBytes := algo_utils.Map(ins[1:], func(i *big.Int) []byte { // the first input is dummy, just to ensure the solver's work is done before the prover is called b := i.Bytes() return b[:] @@ -116,7 +154,7 @@ func gkrProveHint(hashName string, data *gkrSolvingData) hint.Function { hsh := HashBuilderRegistry[hashName]() - proof, err := gkr.Prove(data.circuit, data.assignments, fiatshamir.WithHash(hsh, insBytes...), gkr.WithPool(&data.memoryPool)) // TODO: Do transcriptSettings properly + proof, err := gkr.Prove(data.circuit, data.assignments, fiatshamir.WithHash(hsh, insBytes...), gkr.WithPool(&data.memoryPool), gkr.WithWorkers(&data.workers)) if err != nil { return err } @@ -137,6 +175,9 @@ func gkrProveHint(hashName string, data *gkrSolvingData) hint.Function { data.dumpAssignments() + endTime := time.Now().UnixMicro() + fmt.Println("gkr solved in", endTime-startTime, "μs") + return nil } diff --git a/internal/tinyfield/element.go b/internal/tinyfield/element.go index c30cc10254..f9d1e70862 100644 --- a/internal/tinyfield/element.go +++ b/internal/tinyfield/element.go @@ -755,6 +755,7 @@ func (z *Element) SetBigInt(v *big.Int) *Element { vv := field.BigIntPool.Get() // copy input + modular reduction + vv.Set(v) vv.Mod(v, &_modulus) // set big int byte value From 9863c26ba04cecc1073214b056b75169f3d5f8f0 Mon Sep 17 00:00:00 2001 From: Arya Tabaie Date: Mon, 30 Jan 2023 00:23:45 -0500 Subject: [PATCH 56/71] fix: dumping error and solver test --- constraint/bls12-377/gkr.go | 2 +- constraint/bls12-381/gkr.go | 2 +- constraint/bls24-315/gkr.go | 2 +- constraint/bls24-317/gkr.go | 2 +- constraint/bn254/gkr.go | 2 +- constraint/bw6-633/gkr.go | 2 +- constraint/bw6-761/gkr.go | 2 +- .../template/representations/gkr.go.tmpl | 2 +- std/gkr/api_test.go | 32 ++----------------- 9 files changed, 11 insertions(+), 37 deletions(-) diff --git a/constraint/bls12-377/gkr.go b/constraint/bls12-377/gkr.go index 5c1dbb3393..52a8610ab3 100644 --- a/constraint/bls12-377/gkr.go +++ b/constraint/bls12-377/gkr.go @@ -131,8 +131,8 @@ func gkrSolveHint(info constraint.GkrInfo, solvingData *gkrSolvingData) hint.Fun assignment[wireI][instanceI] = gate.Evaluate(inputs[:len(inputIndexes)]...) } } - solvingData.memoryPool.Dump(inputs) } + solvingData.memoryPool.Dump(inputs) } } diff --git a/constraint/bls12-381/gkr.go b/constraint/bls12-381/gkr.go index bc93c9d946..33c977a3e0 100644 --- a/constraint/bls12-381/gkr.go +++ b/constraint/bls12-381/gkr.go @@ -131,8 +131,8 @@ func gkrSolveHint(info constraint.GkrInfo, solvingData *gkrSolvingData) hint.Fun assignment[wireI][instanceI] = gate.Evaluate(inputs[:len(inputIndexes)]...) } } - solvingData.memoryPool.Dump(inputs) } + solvingData.memoryPool.Dump(inputs) } } diff --git a/constraint/bls24-315/gkr.go b/constraint/bls24-315/gkr.go index 0b7055170f..eeafe6af2e 100644 --- a/constraint/bls24-315/gkr.go +++ b/constraint/bls24-315/gkr.go @@ -131,8 +131,8 @@ func gkrSolveHint(info constraint.GkrInfo, solvingData *gkrSolvingData) hint.Fun assignment[wireI][instanceI] = gate.Evaluate(inputs[:len(inputIndexes)]...) } } - solvingData.memoryPool.Dump(inputs) } + solvingData.memoryPool.Dump(inputs) } } diff --git a/constraint/bls24-317/gkr.go b/constraint/bls24-317/gkr.go index 2791d30e74..bf1d8b068a 100644 --- a/constraint/bls24-317/gkr.go +++ b/constraint/bls24-317/gkr.go @@ -131,8 +131,8 @@ func gkrSolveHint(info constraint.GkrInfo, solvingData *gkrSolvingData) hint.Fun assignment[wireI][instanceI] = gate.Evaluate(inputs[:len(inputIndexes)]...) } } - solvingData.memoryPool.Dump(inputs) } + solvingData.memoryPool.Dump(inputs) } } diff --git a/constraint/bn254/gkr.go b/constraint/bn254/gkr.go index 5d7627b400..d8b8d2e799 100644 --- a/constraint/bn254/gkr.go +++ b/constraint/bn254/gkr.go @@ -131,8 +131,8 @@ func gkrSolveHint(info constraint.GkrInfo, solvingData *gkrSolvingData) hint.Fun assignment[wireI][instanceI] = gate.Evaluate(inputs[:len(inputIndexes)]...) } } - solvingData.memoryPool.Dump(inputs) } + solvingData.memoryPool.Dump(inputs) } } diff --git a/constraint/bw6-633/gkr.go b/constraint/bw6-633/gkr.go index f963cd325e..350d55e80b 100644 --- a/constraint/bw6-633/gkr.go +++ b/constraint/bw6-633/gkr.go @@ -131,8 +131,8 @@ func gkrSolveHint(info constraint.GkrInfo, solvingData *gkrSolvingData) hint.Fun assignment[wireI][instanceI] = gate.Evaluate(inputs[:len(inputIndexes)]...) } } - solvingData.memoryPool.Dump(inputs) } + solvingData.memoryPool.Dump(inputs) } } diff --git a/constraint/bw6-761/gkr.go b/constraint/bw6-761/gkr.go index 39e78232c7..d8f7bf14f6 100644 --- a/constraint/bw6-761/gkr.go +++ b/constraint/bw6-761/gkr.go @@ -131,8 +131,8 @@ func gkrSolveHint(info constraint.GkrInfo, solvingData *gkrSolvingData) hint.Fun assignment[wireI][instanceI] = gate.Evaluate(inputs[:len(inputIndexes)]...) } } - solvingData.memoryPool.Dump(inputs) } + solvingData.memoryPool.Dump(inputs) } } diff --git a/internal/generator/backend/template/representations/gkr.go.tmpl b/internal/generator/backend/template/representations/gkr.go.tmpl index 5341834503..ee0a0acda2 100644 --- a/internal/generator/backend/template/representations/gkr.go.tmpl +++ b/internal/generator/backend/template/representations/gkr.go.tmpl @@ -113,8 +113,8 @@ func gkrSolveHint(info constraint.GkrInfo, solvingData *gkrSolvingData) hint.Fun assignment[wireI][instanceI] = gate.Evaluate(inputs[:len(inputIndexes)]...) } } - solvingData.memoryPool.Dump(inputs) } + solvingData.memoryPool.Dump(inputs) } } diff --git a/std/gkr/api_test.go b/std/gkr/api_test.go index f0aaf5414b..deaa65a5ed 100644 --- a/std/gkr/api_test.go +++ b/std/gkr/api_test.go @@ -522,10 +522,9 @@ func BenchmarkMiMCMerkleTreeNoGkrNoDep(b *testing.B) { } type mimcNoDepCircuit struct { - X []frontend.Variable - Y []frontend.Variable - mimcDepth int - solverOnly bool + X []frontend.Variable + Y []frontend.Variable + mimcDepth int } func (c *mimcNoDepCircuit) Define(api frontend.API) error { @@ -558,28 +557,9 @@ func (c *mimcNoDepCircuit) Define(api frontend.API) error { return err } Z := solution.Export(z) - if c.solverOnly { - zCorrect := ToyMiMC(api, c.mimcDepth, c.X, c.Y) - for i := range zCorrect { - api.AssertIsEqual(zCorrect[i], Z[i]) - } - return nil - } return solution.Verify("-20", Z...) } -func ToyMiMC(api frontend.API, mimcDepth int, X, Y []frontend.Variable) []frontend.Variable { - Z := make([]frontend.Variable, len(X)) - gate := RegisteredGates["mimc"] - for i := range Z { - Z[i] = Y[i] - for n := 0; n < mimcDepth; n++ { - Z[i] = gate.Evaluate(api, X[i], Z[i]) - } - } - return Z -} - func mimcNoDepCircuits(mimcDepth, nbInstances int) (circuit, assignment frontend.Circuit) { X := make([]frontend.Variable, nbInstances) Y := make([]frontend.Variable, nbInstances) @@ -605,12 +585,6 @@ func BenchmarkMiMCNoDepSolve(b *testing.B) { benchProof(b, circuit, assignment) } -func TestMiMCFullDepthNoDepSolver(t *testing.T) { - circuit, assignment := mimcNoDepCircuits(91, 1<<11) - circuit.(*mimcNoDepCircuit).solverOnly = true - testE2E(t, circuit, assignment) -} - func BenchmarkMiMCFullDepthNoDepSolve(b *testing.B) { circuit, assignment := mimcNoDepCircuits(91, 1<<19) benchProof(b, circuit, assignment) From 4a91d8314e03f0368a5a6a76817920cd538b3a49 Mon Sep 17 00:00:00 2001 From: Arya Tabaie Date: Mon, 30 Jan 2023 00:26:18 -0500 Subject: [PATCH 57/71] fix: avoid overlogging --- constraint/bls12-377/gkr.go | 6 ++++-- constraint/bls12-381/gkr.go | 6 ++++-- constraint/bls24-315/gkr.go | 6 ++++-- constraint/bls24-317/gkr.go | 6 ++++-- constraint/bn254/gkr.go | 6 ++++-- constraint/bw6-633/gkr.go | 6 ++++-- constraint/bw6-761/gkr.go | 6 ++++-- .../generator/backend/template/representations/gkr.go.tmpl | 6 ++++-- 8 files changed, 32 insertions(+), 16 deletions(-) diff --git a/constraint/bls12-377/gkr.go b/constraint/bls12-377/gkr.go index 52a8610ab3..5f259ab75b 100644 --- a/constraint/bls12-377/gkr.go +++ b/constraint/bls12-377/gkr.go @@ -193,8 +193,10 @@ func gkrProveHint(hashName string, data *gkrSolvingData) hint.Function { data.dumpAssignments() - endTime := time.Now().UnixMicro() - fmt.Println("gkr solved in", endTime-startTime, "μs") + if log { + endTime := time.Now().UnixMicro() + fmt.Println("gkr proved in", endTime-startTime, "μs") + } return nil diff --git a/constraint/bls12-381/gkr.go b/constraint/bls12-381/gkr.go index 33c977a3e0..4dc8f262bd 100644 --- a/constraint/bls12-381/gkr.go +++ b/constraint/bls12-381/gkr.go @@ -193,8 +193,10 @@ func gkrProveHint(hashName string, data *gkrSolvingData) hint.Function { data.dumpAssignments() - endTime := time.Now().UnixMicro() - fmt.Println("gkr solved in", endTime-startTime, "μs") + if log { + endTime := time.Now().UnixMicro() + fmt.Println("gkr proved in", endTime-startTime, "μs") + } return nil diff --git a/constraint/bls24-315/gkr.go b/constraint/bls24-315/gkr.go index eeafe6af2e..cb9321c9c5 100644 --- a/constraint/bls24-315/gkr.go +++ b/constraint/bls24-315/gkr.go @@ -193,8 +193,10 @@ func gkrProveHint(hashName string, data *gkrSolvingData) hint.Function { data.dumpAssignments() - endTime := time.Now().UnixMicro() - fmt.Println("gkr solved in", endTime-startTime, "μs") + if log { + endTime := time.Now().UnixMicro() + fmt.Println("gkr proved in", endTime-startTime, "μs") + } return nil diff --git a/constraint/bls24-317/gkr.go b/constraint/bls24-317/gkr.go index bf1d8b068a..1e7692d6f3 100644 --- a/constraint/bls24-317/gkr.go +++ b/constraint/bls24-317/gkr.go @@ -193,8 +193,10 @@ func gkrProveHint(hashName string, data *gkrSolvingData) hint.Function { data.dumpAssignments() - endTime := time.Now().UnixMicro() - fmt.Println("gkr solved in", endTime-startTime, "μs") + if log { + endTime := time.Now().UnixMicro() + fmt.Println("gkr proved in", endTime-startTime, "μs") + } return nil diff --git a/constraint/bn254/gkr.go b/constraint/bn254/gkr.go index d8b8d2e799..13a119c56a 100644 --- a/constraint/bn254/gkr.go +++ b/constraint/bn254/gkr.go @@ -193,8 +193,10 @@ func gkrProveHint(hashName string, data *gkrSolvingData) hint.Function { data.dumpAssignments() - endTime := time.Now().UnixMicro() - fmt.Println("gkr solved in", endTime-startTime, "μs") + if log { + endTime := time.Now().UnixMicro() + fmt.Println("gkr proved in", endTime-startTime, "μs") + } return nil diff --git a/constraint/bw6-633/gkr.go b/constraint/bw6-633/gkr.go index 350d55e80b..e88c236fb0 100644 --- a/constraint/bw6-633/gkr.go +++ b/constraint/bw6-633/gkr.go @@ -193,8 +193,10 @@ func gkrProveHint(hashName string, data *gkrSolvingData) hint.Function { data.dumpAssignments() - endTime := time.Now().UnixMicro() - fmt.Println("gkr solved in", endTime-startTime, "μs") + if log { + endTime := time.Now().UnixMicro() + fmt.Println("gkr proved in", endTime-startTime, "μs") + } return nil diff --git a/constraint/bw6-761/gkr.go b/constraint/bw6-761/gkr.go index d8f7bf14f6..d0d080a2c8 100644 --- a/constraint/bw6-761/gkr.go +++ b/constraint/bw6-761/gkr.go @@ -193,8 +193,10 @@ func gkrProveHint(hashName string, data *gkrSolvingData) hint.Function { data.dumpAssignments() - endTime := time.Now().UnixMicro() - fmt.Println("gkr solved in", endTime-startTime, "μs") + if log { + endTime := time.Now().UnixMicro() + fmt.Println("gkr proved in", endTime-startTime, "μs") + } return nil diff --git a/internal/generator/backend/template/representations/gkr.go.tmpl b/internal/generator/backend/template/representations/gkr.go.tmpl index ee0a0acda2..b9759d30b5 100644 --- a/internal/generator/backend/template/representations/gkr.go.tmpl +++ b/internal/generator/backend/template/representations/gkr.go.tmpl @@ -175,8 +175,10 @@ func gkrProveHint(hashName string, data *gkrSolvingData) hint.Function { data.dumpAssignments() - endTime := time.Now().UnixMicro() - fmt.Println("gkr solved in", endTime-startTime, "μs") + if log { + endTime := time.Now().UnixMicro() + fmt.Println("gkr proved in", endTime-startTime, "μs") + } return nil From 966797dd8b02a8d887e227c23f110bdcf110cfd8 Mon Sep 17 00:00:00 2001 From: Arya Tabaie Date: Mon, 30 Jan 2023 00:29:46 -0500 Subject: [PATCH 58/71] fix: log correction --- internal/generator/backend/template/representations/gkr.go.tmpl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/generator/backend/template/representations/gkr.go.tmpl b/internal/generator/backend/template/representations/gkr.go.tmpl index b9759d30b5..be5c2a0acd 100644 --- a/internal/generator/backend/template/representations/gkr.go.tmpl +++ b/internal/generator/backend/template/representations/gkr.go.tmpl @@ -128,7 +128,7 @@ func gkrSolveHint(info constraint.GkrInfo, solvingData *gkrSolvingData) hint.Fun if log { endTime := time.Now().UnixMicro() - fmt.Println("gkr proved in", endTime-startTime, "μs") + fmt.Println("gkr solved in", endTime-startTime, "μs") } return nil From e9cf2397ad72c45093ef4a176564b2ba9b6f2ee0 Mon Sep 17 00:00:00 2001 From: Arya Tabaie Date: Fri, 10 Feb 2023 15:14:47 -0500 Subject: [PATCH 59/71] build: gnark-crypto@develop --- go.mod | 2 +- go.sum | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/go.mod b/go.mod index 33e4a1f8ed..b85d9197af 100644 --- a/go.mod +++ b/go.mod @@ -6,7 +6,7 @@ require ( github.com/bits-and-blooms/bitset v1.5.0 github.com/blang/semver/v4 v4.0.0 github.com/consensys/bavard v0.1.13 - github.com/consensys/gnark-crypto v0.9.1-0.20230209152347-632763cd3e3c + github.com/consensys/gnark-crypto v0.9.1-0.20230210193008-6f591e7c0ebd github.com/fxamacker/cbor/v2 v2.2.0 github.com/google/go-cmp v0.5.8 github.com/google/pprof v0.0.0-20220729232143-a41b82acbcb1 diff --git a/go.sum b/go.sum index 1d51f2ba1a..0b79c1f478 100644 --- a/go.sum +++ b/go.sum @@ -8,6 +8,8 @@ github.com/consensys/gnark-crypto v0.9.1-0.20230209152151-ec280f158fc8 h1:nx43IG github.com/consensys/gnark-crypto v0.9.1-0.20230209152151-ec280f158fc8/go.mod h1:CkbdF9hbRidRJYMRzmfX8TMOr95I2pYXRHF18MzRrvA= github.com/consensys/gnark-crypto v0.9.1-0.20230209152347-632763cd3e3c h1:15LTi7eD7N/L0EN4lSbyyfO/tTqiEhpRtJjEfdMOEQ8= github.com/consensys/gnark-crypto v0.9.1-0.20230209152347-632763cd3e3c/go.mod h1:CkbdF9hbRidRJYMRzmfX8TMOr95I2pYXRHF18MzRrvA= +github.com/consensys/gnark-crypto v0.9.1-0.20230210193008-6f591e7c0ebd h1:cC1msj4C66UP8gdI0R2JwwMb6eth7CWA7WoYiyLiZ0I= +github.com/consensys/gnark-crypto v0.9.1-0.20230210193008-6f591e7c0ebd/go.mod h1:CkbdF9hbRidRJYMRzmfX8TMOr95I2pYXRHF18MzRrvA= github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= From 2aef7ea7a03aac78838fc8434f6d2e99df3687f6 Mon Sep 17 00:00:00 2001 From: Arya Tabaie Date: Fri, 10 Feb 2023 15:27:55 -0500 Subject: [PATCH 60/71] fix: reflect gkr changes in gnark-crypto --- constraint/bls12-377/gkr.go | 8 ++++---- constraint/bls12-381/gkr.go | 8 ++++---- constraint/bls24-315/gkr.go | 8 ++++---- constraint/bls24-317/gkr.go | 8 ++++---- constraint/bn254/gkr.go | 8 ++++---- constraint/bw6-633/gkr.go | 8 ++++---- constraint/bw6-761/gkr.go | 8 ++++---- .../backend/template/representations/gkr.go.tmpl | 6 +++--- 8 files changed, 31 insertions(+), 31 deletions(-) diff --git a/constraint/bls12-377/gkr.go b/constraint/bls12-377/gkr.go index 5f259ab75b..0fa1535e44 100644 --- a/constraint/bls12-377/gkr.go +++ b/constraint/bls12-377/gkr.go @@ -35,7 +35,7 @@ type gkrSolvingData struct { assignments gkr.WireAssignment circuit gkr.Circuit memoryPool polynomial.Pool - workers utils.WorkerPool + workers *utils.WorkerPool } func convertCircuit(noPtr constraint.GkrCircuit) gkr.Circuit { @@ -138,7 +138,7 @@ func gkrSolveHint(info constraint.GkrInfo, solvingData *gkrSolvingData) hint.Fun start := 0 for _, end := range chunks { - solvingData.workers.Dispatch(end-start, 1024, solveTask(start)).Wait() + solvingData.workers.Submit(end-start, solveTask(start), 1024).Wait() start = end } @@ -146,7 +146,7 @@ func gkrSolveHint(info constraint.GkrInfo, solvingData *gkrSolvingData) hint.Fun if log { endTime := time.Now().UnixMicro() - fmt.Println("gkr proved in", endTime-startTime, "μs") + fmt.Println("gkr solved in", endTime-startTime, "μs") } return nil @@ -172,7 +172,7 @@ func gkrProveHint(hashName string, data *gkrSolvingData) hint.Function { hsh := HashBuilderRegistry[hashName]() - proof, err := gkr.Prove(data.circuit, data.assignments, fiatshamir.WithHash(hsh, insBytes...), gkr.WithPool(&data.memoryPool), gkr.WithWorkers(&data.workers)) + proof, err := gkr.Prove(data.circuit, data.assignments, fiatshamir.WithHash(hsh, insBytes...), gkr.WithPool(&data.memoryPool), gkr.WithWorkers(data.workers)) if err != nil { return err } diff --git a/constraint/bls12-381/gkr.go b/constraint/bls12-381/gkr.go index 4dc8f262bd..733ab78d8c 100644 --- a/constraint/bls12-381/gkr.go +++ b/constraint/bls12-381/gkr.go @@ -35,7 +35,7 @@ type gkrSolvingData struct { assignments gkr.WireAssignment circuit gkr.Circuit memoryPool polynomial.Pool - workers utils.WorkerPool + workers *utils.WorkerPool } func convertCircuit(noPtr constraint.GkrCircuit) gkr.Circuit { @@ -138,7 +138,7 @@ func gkrSolveHint(info constraint.GkrInfo, solvingData *gkrSolvingData) hint.Fun start := 0 for _, end := range chunks { - solvingData.workers.Dispatch(end-start, 1024, solveTask(start)).Wait() + solvingData.workers.Submit(end-start, solveTask(start), 1024).Wait() start = end } @@ -146,7 +146,7 @@ func gkrSolveHint(info constraint.GkrInfo, solvingData *gkrSolvingData) hint.Fun if log { endTime := time.Now().UnixMicro() - fmt.Println("gkr proved in", endTime-startTime, "μs") + fmt.Println("gkr solved in", endTime-startTime, "μs") } return nil @@ -172,7 +172,7 @@ func gkrProveHint(hashName string, data *gkrSolvingData) hint.Function { hsh := HashBuilderRegistry[hashName]() - proof, err := gkr.Prove(data.circuit, data.assignments, fiatshamir.WithHash(hsh, insBytes...), gkr.WithPool(&data.memoryPool), gkr.WithWorkers(&data.workers)) + proof, err := gkr.Prove(data.circuit, data.assignments, fiatshamir.WithHash(hsh, insBytes...), gkr.WithPool(&data.memoryPool), gkr.WithWorkers(data.workers)) if err != nil { return err } diff --git a/constraint/bls24-315/gkr.go b/constraint/bls24-315/gkr.go index cb9321c9c5..a999e0509a 100644 --- a/constraint/bls24-315/gkr.go +++ b/constraint/bls24-315/gkr.go @@ -35,7 +35,7 @@ type gkrSolvingData struct { assignments gkr.WireAssignment circuit gkr.Circuit memoryPool polynomial.Pool - workers utils.WorkerPool + workers *utils.WorkerPool } func convertCircuit(noPtr constraint.GkrCircuit) gkr.Circuit { @@ -138,7 +138,7 @@ func gkrSolveHint(info constraint.GkrInfo, solvingData *gkrSolvingData) hint.Fun start := 0 for _, end := range chunks { - solvingData.workers.Dispatch(end-start, 1024, solveTask(start)).Wait() + solvingData.workers.Submit(end-start, solveTask(start), 1024).Wait() start = end } @@ -146,7 +146,7 @@ func gkrSolveHint(info constraint.GkrInfo, solvingData *gkrSolvingData) hint.Fun if log { endTime := time.Now().UnixMicro() - fmt.Println("gkr proved in", endTime-startTime, "μs") + fmt.Println("gkr solved in", endTime-startTime, "μs") } return nil @@ -172,7 +172,7 @@ func gkrProveHint(hashName string, data *gkrSolvingData) hint.Function { hsh := HashBuilderRegistry[hashName]() - proof, err := gkr.Prove(data.circuit, data.assignments, fiatshamir.WithHash(hsh, insBytes...), gkr.WithPool(&data.memoryPool), gkr.WithWorkers(&data.workers)) + proof, err := gkr.Prove(data.circuit, data.assignments, fiatshamir.WithHash(hsh, insBytes...), gkr.WithPool(&data.memoryPool), gkr.WithWorkers(data.workers)) if err != nil { return err } diff --git a/constraint/bls24-317/gkr.go b/constraint/bls24-317/gkr.go index 1e7692d6f3..620f17eac0 100644 --- a/constraint/bls24-317/gkr.go +++ b/constraint/bls24-317/gkr.go @@ -35,7 +35,7 @@ type gkrSolvingData struct { assignments gkr.WireAssignment circuit gkr.Circuit memoryPool polynomial.Pool - workers utils.WorkerPool + workers *utils.WorkerPool } func convertCircuit(noPtr constraint.GkrCircuit) gkr.Circuit { @@ -138,7 +138,7 @@ func gkrSolveHint(info constraint.GkrInfo, solvingData *gkrSolvingData) hint.Fun start := 0 for _, end := range chunks { - solvingData.workers.Dispatch(end-start, 1024, solveTask(start)).Wait() + solvingData.workers.Submit(end-start, solveTask(start), 1024).Wait() start = end } @@ -146,7 +146,7 @@ func gkrSolveHint(info constraint.GkrInfo, solvingData *gkrSolvingData) hint.Fun if log { endTime := time.Now().UnixMicro() - fmt.Println("gkr proved in", endTime-startTime, "μs") + fmt.Println("gkr solved in", endTime-startTime, "μs") } return nil @@ -172,7 +172,7 @@ func gkrProveHint(hashName string, data *gkrSolvingData) hint.Function { hsh := HashBuilderRegistry[hashName]() - proof, err := gkr.Prove(data.circuit, data.assignments, fiatshamir.WithHash(hsh, insBytes...), gkr.WithPool(&data.memoryPool), gkr.WithWorkers(&data.workers)) + proof, err := gkr.Prove(data.circuit, data.assignments, fiatshamir.WithHash(hsh, insBytes...), gkr.WithPool(&data.memoryPool), gkr.WithWorkers(data.workers)) if err != nil { return err } diff --git a/constraint/bn254/gkr.go b/constraint/bn254/gkr.go index 13a119c56a..a16f7b711e 100644 --- a/constraint/bn254/gkr.go +++ b/constraint/bn254/gkr.go @@ -35,7 +35,7 @@ type gkrSolvingData struct { assignments gkr.WireAssignment circuit gkr.Circuit memoryPool polynomial.Pool - workers utils.WorkerPool + workers *utils.WorkerPool } func convertCircuit(noPtr constraint.GkrCircuit) gkr.Circuit { @@ -138,7 +138,7 @@ func gkrSolveHint(info constraint.GkrInfo, solvingData *gkrSolvingData) hint.Fun start := 0 for _, end := range chunks { - solvingData.workers.Dispatch(end-start, 1024, solveTask(start)).Wait() + solvingData.workers.Submit(end-start, solveTask(start), 1024).Wait() start = end } @@ -146,7 +146,7 @@ func gkrSolveHint(info constraint.GkrInfo, solvingData *gkrSolvingData) hint.Fun if log { endTime := time.Now().UnixMicro() - fmt.Println("gkr proved in", endTime-startTime, "μs") + fmt.Println("gkr solved in", endTime-startTime, "μs") } return nil @@ -172,7 +172,7 @@ func gkrProveHint(hashName string, data *gkrSolvingData) hint.Function { hsh := HashBuilderRegistry[hashName]() - proof, err := gkr.Prove(data.circuit, data.assignments, fiatshamir.WithHash(hsh, insBytes...), gkr.WithPool(&data.memoryPool), gkr.WithWorkers(&data.workers)) + proof, err := gkr.Prove(data.circuit, data.assignments, fiatshamir.WithHash(hsh, insBytes...), gkr.WithPool(&data.memoryPool), gkr.WithWorkers(data.workers)) if err != nil { return err } diff --git a/constraint/bw6-633/gkr.go b/constraint/bw6-633/gkr.go index e88c236fb0..eb8dc3a9bf 100644 --- a/constraint/bw6-633/gkr.go +++ b/constraint/bw6-633/gkr.go @@ -35,7 +35,7 @@ type gkrSolvingData struct { assignments gkr.WireAssignment circuit gkr.Circuit memoryPool polynomial.Pool - workers utils.WorkerPool + workers *utils.WorkerPool } func convertCircuit(noPtr constraint.GkrCircuit) gkr.Circuit { @@ -138,7 +138,7 @@ func gkrSolveHint(info constraint.GkrInfo, solvingData *gkrSolvingData) hint.Fun start := 0 for _, end := range chunks { - solvingData.workers.Dispatch(end-start, 1024, solveTask(start)).Wait() + solvingData.workers.Submit(end-start, solveTask(start), 1024).Wait() start = end } @@ -146,7 +146,7 @@ func gkrSolveHint(info constraint.GkrInfo, solvingData *gkrSolvingData) hint.Fun if log { endTime := time.Now().UnixMicro() - fmt.Println("gkr proved in", endTime-startTime, "μs") + fmt.Println("gkr solved in", endTime-startTime, "μs") } return nil @@ -172,7 +172,7 @@ func gkrProveHint(hashName string, data *gkrSolvingData) hint.Function { hsh := HashBuilderRegistry[hashName]() - proof, err := gkr.Prove(data.circuit, data.assignments, fiatshamir.WithHash(hsh, insBytes...), gkr.WithPool(&data.memoryPool), gkr.WithWorkers(&data.workers)) + proof, err := gkr.Prove(data.circuit, data.assignments, fiatshamir.WithHash(hsh, insBytes...), gkr.WithPool(&data.memoryPool), gkr.WithWorkers(data.workers)) if err != nil { return err } diff --git a/constraint/bw6-761/gkr.go b/constraint/bw6-761/gkr.go index d0d080a2c8..dd7c9aba93 100644 --- a/constraint/bw6-761/gkr.go +++ b/constraint/bw6-761/gkr.go @@ -35,7 +35,7 @@ type gkrSolvingData struct { assignments gkr.WireAssignment circuit gkr.Circuit memoryPool polynomial.Pool - workers utils.WorkerPool + workers *utils.WorkerPool } func convertCircuit(noPtr constraint.GkrCircuit) gkr.Circuit { @@ -138,7 +138,7 @@ func gkrSolveHint(info constraint.GkrInfo, solvingData *gkrSolvingData) hint.Fun start := 0 for _, end := range chunks { - solvingData.workers.Dispatch(end-start, 1024, solveTask(start)).Wait() + solvingData.workers.Submit(end-start, solveTask(start), 1024).Wait() start = end } @@ -146,7 +146,7 @@ func gkrSolveHint(info constraint.GkrInfo, solvingData *gkrSolvingData) hint.Fun if log { endTime := time.Now().UnixMicro() - fmt.Println("gkr proved in", endTime-startTime, "μs") + fmt.Println("gkr solved in", endTime-startTime, "μs") } return nil @@ -172,7 +172,7 @@ func gkrProveHint(hashName string, data *gkrSolvingData) hint.Function { hsh := HashBuilderRegistry[hashName]() - proof, err := gkr.Prove(data.circuit, data.assignments, fiatshamir.WithHash(hsh, insBytes...), gkr.WithPool(&data.memoryPool), gkr.WithWorkers(&data.workers)) + proof, err := gkr.Prove(data.circuit, data.assignments, fiatshamir.WithHash(hsh, insBytes...), gkr.WithPool(&data.memoryPool), gkr.WithWorkers(data.workers)) if err != nil { return err } diff --git a/internal/generator/backend/template/representations/gkr.go.tmpl b/internal/generator/backend/template/representations/gkr.go.tmpl index be5c2a0acd..f33cac90bf 100644 --- a/internal/generator/backend/template/representations/gkr.go.tmpl +++ b/internal/generator/backend/template/representations/gkr.go.tmpl @@ -17,7 +17,7 @@ type gkrSolvingData struct { assignments gkr.WireAssignment circuit gkr.Circuit memoryPool polynomial.Pool - workers utils.WorkerPool + workers *utils.WorkerPool } func convertCircuit(noPtr constraint.GkrCircuit) gkr.Circuit { @@ -120,7 +120,7 @@ func gkrSolveHint(info constraint.GkrInfo, solvingData *gkrSolvingData) hint.Fun start := 0 for _, end := range chunks { - solvingData.workers.Dispatch(end-start, 1024, solveTask(start)).Wait() + solvingData.workers.Submit(end-start, solveTask(start), 1024).Wait() start = end } @@ -154,7 +154,7 @@ func gkrProveHint(hashName string, data *gkrSolvingData) hint.Function { hsh := HashBuilderRegistry[hashName]() - proof, err := gkr.Prove(data.circuit, data.assignments, fiatshamir.WithHash(hsh, insBytes...), gkr.WithPool(&data.memoryPool), gkr.WithWorkers(&data.workers)) + proof, err := gkr.Prove(data.circuit, data.assignments, fiatshamir.WithHash(hsh, insBytes...), gkr.WithPool(&data.memoryPool), gkr.WithWorkers(data.workers)) if err != nil { return err } From af7cbb538dfd3726993e40a7df9931ff9734f263 Mon Sep 17 00:00:00 2001 From: Arya Tabaie Date: Fri, 10 Feb 2023 15:31:44 -0500 Subject: [PATCH 61/71] fix: witness-related functions no longer return ptrs --- std/gkr/api_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/std/gkr/api_test.go b/std/gkr/api_test.go index deaa65a5ed..1325be3288 100644 --- a/std/gkr/api_test.go +++ b/std/gkr/api_test.go @@ -373,8 +373,8 @@ func testE2E(t *testing.T, circuit, assignment frontend.Circuit) { cs, err := frontend.Compile(ecc.BN254.ScalarField(), r1cs.NewBuilder, circuit, frontend.WithCompressThreshold(compressThreshold)) assert.NoError(t, err) var ( - fullWitness *witness.Witness - publicWitness *witness.Witness + fullWitness witness.Witness + publicWitness witness.Witness pk groth16.ProvingKey vk groth16.VerifyingKey proof groth16.Proof From 6a20a0b6b55f1f7035360c406d4bc90ac9304d36 Mon Sep 17 00:00:00 2001 From: Arya Tabaie Date: Fri, 10 Feb 2023 16:10:27 -0500 Subject: [PATCH 62/71] fix: remove printfs --- constraint/bls12-377/gkr.go | 20 ------------------- constraint/bls12-381/gkr.go | 20 ------------------- constraint/bls24-315/gkr.go | 20 ------------------- constraint/bls24-317/gkr.go | 20 ------------------- constraint/bn254/gkr.go | 20 ------------------- constraint/bw6-633/gkr.go | 20 ------------------- constraint/bw6-761/gkr.go | 20 ------------------- .../template/representations/gkr.go.tmpl | 20 ------------------- 8 files changed, 160 deletions(-) diff --git a/constraint/bls12-377/gkr.go b/constraint/bls12-377/gkr.go index 0fa1535e44..d1b0a840b8 100644 --- a/constraint/bls12-377/gkr.go +++ b/constraint/bls12-377/gkr.go @@ -17,7 +17,6 @@ package cs import ( - "fmt" "github.com/consensys/gnark-crypto/ecc/bls12-377/fr" "github.com/consensys/gnark-crypto/ecc/bls12-377/fr/gkr" "github.com/consensys/gnark-crypto/ecc/bls12-377/fr/polynomial" @@ -28,7 +27,6 @@ import ( "github.com/consensys/gnark/std/utils/algo_utils" "hash" "math/big" - "time" ) type gkrSolvingData struct { @@ -85,13 +83,8 @@ func (a gkrAssignment) setOuts(circuit constraint.GkrCircuit, outs []*big.Int) { // Check if outsI == len(outs)? } -const log = true - func gkrSolveHint(info constraint.GkrInfo, solvingData *gkrSolvingData) hint.Function { return func(_ *big.Int, ins, outs []*big.Int) error { - - startTime := time.Now().UnixMicro() - // assumes assignmentVector is arranged wire first, instance second in order of solution circuit := info.Circuit nbInstances := info.NbInstances @@ -144,11 +137,6 @@ func gkrSolveHint(info constraint.GkrInfo, solvingData *gkrSolvingData) hint.Fun assignment.setOuts(info.Circuit, outs) - if log { - endTime := time.Now().UnixMicro() - fmt.Println("gkr solved in", endTime-startTime, "μs") - } - return nil } } @@ -162,9 +150,6 @@ func frToBigInts(dst []*big.Int, src []fr.Element) { func gkrProveHint(hashName string, data *gkrSolvingData) hint.Function { return func(_ *big.Int, ins, outs []*big.Int) error { - - startTime := time.Now().UnixMicro() - insBytes := algo_utils.Map(ins[1:], func(i *big.Int) []byte { // the first input is dummy, just to ensure the solver's work is done before the prover is called b := i.Bytes() return b[:] @@ -193,11 +178,6 @@ func gkrProveHint(hashName string, data *gkrSolvingData) hint.Function { data.dumpAssignments() - if log { - endTime := time.Now().UnixMicro() - fmt.Println("gkr proved in", endTime-startTime, "μs") - } - return nil } diff --git a/constraint/bls12-381/gkr.go b/constraint/bls12-381/gkr.go index 733ab78d8c..838df92eb5 100644 --- a/constraint/bls12-381/gkr.go +++ b/constraint/bls12-381/gkr.go @@ -17,7 +17,6 @@ package cs import ( - "fmt" "github.com/consensys/gnark-crypto/ecc/bls12-381/fr" "github.com/consensys/gnark-crypto/ecc/bls12-381/fr/gkr" "github.com/consensys/gnark-crypto/ecc/bls12-381/fr/polynomial" @@ -28,7 +27,6 @@ import ( "github.com/consensys/gnark/std/utils/algo_utils" "hash" "math/big" - "time" ) type gkrSolvingData struct { @@ -85,13 +83,8 @@ func (a gkrAssignment) setOuts(circuit constraint.GkrCircuit, outs []*big.Int) { // Check if outsI == len(outs)? } -const log = true - func gkrSolveHint(info constraint.GkrInfo, solvingData *gkrSolvingData) hint.Function { return func(_ *big.Int, ins, outs []*big.Int) error { - - startTime := time.Now().UnixMicro() - // assumes assignmentVector is arranged wire first, instance second in order of solution circuit := info.Circuit nbInstances := info.NbInstances @@ -144,11 +137,6 @@ func gkrSolveHint(info constraint.GkrInfo, solvingData *gkrSolvingData) hint.Fun assignment.setOuts(info.Circuit, outs) - if log { - endTime := time.Now().UnixMicro() - fmt.Println("gkr solved in", endTime-startTime, "μs") - } - return nil } } @@ -162,9 +150,6 @@ func frToBigInts(dst []*big.Int, src []fr.Element) { func gkrProveHint(hashName string, data *gkrSolvingData) hint.Function { return func(_ *big.Int, ins, outs []*big.Int) error { - - startTime := time.Now().UnixMicro() - insBytes := algo_utils.Map(ins[1:], func(i *big.Int) []byte { // the first input is dummy, just to ensure the solver's work is done before the prover is called b := i.Bytes() return b[:] @@ -193,11 +178,6 @@ func gkrProveHint(hashName string, data *gkrSolvingData) hint.Function { data.dumpAssignments() - if log { - endTime := time.Now().UnixMicro() - fmt.Println("gkr proved in", endTime-startTime, "μs") - } - return nil } diff --git a/constraint/bls24-315/gkr.go b/constraint/bls24-315/gkr.go index a999e0509a..4e66b4da8a 100644 --- a/constraint/bls24-315/gkr.go +++ b/constraint/bls24-315/gkr.go @@ -17,7 +17,6 @@ package cs import ( - "fmt" "github.com/consensys/gnark-crypto/ecc/bls24-315/fr" "github.com/consensys/gnark-crypto/ecc/bls24-315/fr/gkr" "github.com/consensys/gnark-crypto/ecc/bls24-315/fr/polynomial" @@ -28,7 +27,6 @@ import ( "github.com/consensys/gnark/std/utils/algo_utils" "hash" "math/big" - "time" ) type gkrSolvingData struct { @@ -85,13 +83,8 @@ func (a gkrAssignment) setOuts(circuit constraint.GkrCircuit, outs []*big.Int) { // Check if outsI == len(outs)? } -const log = true - func gkrSolveHint(info constraint.GkrInfo, solvingData *gkrSolvingData) hint.Function { return func(_ *big.Int, ins, outs []*big.Int) error { - - startTime := time.Now().UnixMicro() - // assumes assignmentVector is arranged wire first, instance second in order of solution circuit := info.Circuit nbInstances := info.NbInstances @@ -144,11 +137,6 @@ func gkrSolveHint(info constraint.GkrInfo, solvingData *gkrSolvingData) hint.Fun assignment.setOuts(info.Circuit, outs) - if log { - endTime := time.Now().UnixMicro() - fmt.Println("gkr solved in", endTime-startTime, "μs") - } - return nil } } @@ -162,9 +150,6 @@ func frToBigInts(dst []*big.Int, src []fr.Element) { func gkrProveHint(hashName string, data *gkrSolvingData) hint.Function { return func(_ *big.Int, ins, outs []*big.Int) error { - - startTime := time.Now().UnixMicro() - insBytes := algo_utils.Map(ins[1:], func(i *big.Int) []byte { // the first input is dummy, just to ensure the solver's work is done before the prover is called b := i.Bytes() return b[:] @@ -193,11 +178,6 @@ func gkrProveHint(hashName string, data *gkrSolvingData) hint.Function { data.dumpAssignments() - if log { - endTime := time.Now().UnixMicro() - fmt.Println("gkr proved in", endTime-startTime, "μs") - } - return nil } diff --git a/constraint/bls24-317/gkr.go b/constraint/bls24-317/gkr.go index 620f17eac0..cc8a6bac62 100644 --- a/constraint/bls24-317/gkr.go +++ b/constraint/bls24-317/gkr.go @@ -17,7 +17,6 @@ package cs import ( - "fmt" "github.com/consensys/gnark-crypto/ecc/bls24-317/fr" "github.com/consensys/gnark-crypto/ecc/bls24-317/fr/gkr" "github.com/consensys/gnark-crypto/ecc/bls24-317/fr/polynomial" @@ -28,7 +27,6 @@ import ( "github.com/consensys/gnark/std/utils/algo_utils" "hash" "math/big" - "time" ) type gkrSolvingData struct { @@ -85,13 +83,8 @@ func (a gkrAssignment) setOuts(circuit constraint.GkrCircuit, outs []*big.Int) { // Check if outsI == len(outs)? } -const log = true - func gkrSolveHint(info constraint.GkrInfo, solvingData *gkrSolvingData) hint.Function { return func(_ *big.Int, ins, outs []*big.Int) error { - - startTime := time.Now().UnixMicro() - // assumes assignmentVector is arranged wire first, instance second in order of solution circuit := info.Circuit nbInstances := info.NbInstances @@ -144,11 +137,6 @@ func gkrSolveHint(info constraint.GkrInfo, solvingData *gkrSolvingData) hint.Fun assignment.setOuts(info.Circuit, outs) - if log { - endTime := time.Now().UnixMicro() - fmt.Println("gkr solved in", endTime-startTime, "μs") - } - return nil } } @@ -162,9 +150,6 @@ func frToBigInts(dst []*big.Int, src []fr.Element) { func gkrProveHint(hashName string, data *gkrSolvingData) hint.Function { return func(_ *big.Int, ins, outs []*big.Int) error { - - startTime := time.Now().UnixMicro() - insBytes := algo_utils.Map(ins[1:], func(i *big.Int) []byte { // the first input is dummy, just to ensure the solver's work is done before the prover is called b := i.Bytes() return b[:] @@ -193,11 +178,6 @@ func gkrProveHint(hashName string, data *gkrSolvingData) hint.Function { data.dumpAssignments() - if log { - endTime := time.Now().UnixMicro() - fmt.Println("gkr proved in", endTime-startTime, "μs") - } - return nil } diff --git a/constraint/bn254/gkr.go b/constraint/bn254/gkr.go index a16f7b711e..6b00893e0f 100644 --- a/constraint/bn254/gkr.go +++ b/constraint/bn254/gkr.go @@ -17,7 +17,6 @@ package cs import ( - "fmt" "github.com/consensys/gnark-crypto/ecc/bn254/fr" "github.com/consensys/gnark-crypto/ecc/bn254/fr/gkr" "github.com/consensys/gnark-crypto/ecc/bn254/fr/polynomial" @@ -28,7 +27,6 @@ import ( "github.com/consensys/gnark/std/utils/algo_utils" "hash" "math/big" - "time" ) type gkrSolvingData struct { @@ -85,13 +83,8 @@ func (a gkrAssignment) setOuts(circuit constraint.GkrCircuit, outs []*big.Int) { // Check if outsI == len(outs)? } -const log = true - func gkrSolveHint(info constraint.GkrInfo, solvingData *gkrSolvingData) hint.Function { return func(_ *big.Int, ins, outs []*big.Int) error { - - startTime := time.Now().UnixMicro() - // assumes assignmentVector is arranged wire first, instance second in order of solution circuit := info.Circuit nbInstances := info.NbInstances @@ -144,11 +137,6 @@ func gkrSolveHint(info constraint.GkrInfo, solvingData *gkrSolvingData) hint.Fun assignment.setOuts(info.Circuit, outs) - if log { - endTime := time.Now().UnixMicro() - fmt.Println("gkr solved in", endTime-startTime, "μs") - } - return nil } } @@ -162,9 +150,6 @@ func frToBigInts(dst []*big.Int, src []fr.Element) { func gkrProveHint(hashName string, data *gkrSolvingData) hint.Function { return func(_ *big.Int, ins, outs []*big.Int) error { - - startTime := time.Now().UnixMicro() - insBytes := algo_utils.Map(ins[1:], func(i *big.Int) []byte { // the first input is dummy, just to ensure the solver's work is done before the prover is called b := i.Bytes() return b[:] @@ -193,11 +178,6 @@ func gkrProveHint(hashName string, data *gkrSolvingData) hint.Function { data.dumpAssignments() - if log { - endTime := time.Now().UnixMicro() - fmt.Println("gkr proved in", endTime-startTime, "μs") - } - return nil } diff --git a/constraint/bw6-633/gkr.go b/constraint/bw6-633/gkr.go index eb8dc3a9bf..5a5de0b7fd 100644 --- a/constraint/bw6-633/gkr.go +++ b/constraint/bw6-633/gkr.go @@ -17,7 +17,6 @@ package cs import ( - "fmt" "github.com/consensys/gnark-crypto/ecc/bw6-633/fr" "github.com/consensys/gnark-crypto/ecc/bw6-633/fr/gkr" "github.com/consensys/gnark-crypto/ecc/bw6-633/fr/polynomial" @@ -28,7 +27,6 @@ import ( "github.com/consensys/gnark/std/utils/algo_utils" "hash" "math/big" - "time" ) type gkrSolvingData struct { @@ -85,13 +83,8 @@ func (a gkrAssignment) setOuts(circuit constraint.GkrCircuit, outs []*big.Int) { // Check if outsI == len(outs)? } -const log = true - func gkrSolveHint(info constraint.GkrInfo, solvingData *gkrSolvingData) hint.Function { return func(_ *big.Int, ins, outs []*big.Int) error { - - startTime := time.Now().UnixMicro() - // assumes assignmentVector is arranged wire first, instance second in order of solution circuit := info.Circuit nbInstances := info.NbInstances @@ -144,11 +137,6 @@ func gkrSolveHint(info constraint.GkrInfo, solvingData *gkrSolvingData) hint.Fun assignment.setOuts(info.Circuit, outs) - if log { - endTime := time.Now().UnixMicro() - fmt.Println("gkr solved in", endTime-startTime, "μs") - } - return nil } } @@ -162,9 +150,6 @@ func frToBigInts(dst []*big.Int, src []fr.Element) { func gkrProveHint(hashName string, data *gkrSolvingData) hint.Function { return func(_ *big.Int, ins, outs []*big.Int) error { - - startTime := time.Now().UnixMicro() - insBytes := algo_utils.Map(ins[1:], func(i *big.Int) []byte { // the first input is dummy, just to ensure the solver's work is done before the prover is called b := i.Bytes() return b[:] @@ -193,11 +178,6 @@ func gkrProveHint(hashName string, data *gkrSolvingData) hint.Function { data.dumpAssignments() - if log { - endTime := time.Now().UnixMicro() - fmt.Println("gkr proved in", endTime-startTime, "μs") - } - return nil } diff --git a/constraint/bw6-761/gkr.go b/constraint/bw6-761/gkr.go index dd7c9aba93..fe85e72dd1 100644 --- a/constraint/bw6-761/gkr.go +++ b/constraint/bw6-761/gkr.go @@ -17,7 +17,6 @@ package cs import ( - "fmt" "github.com/consensys/gnark-crypto/ecc/bw6-761/fr" "github.com/consensys/gnark-crypto/ecc/bw6-761/fr/gkr" "github.com/consensys/gnark-crypto/ecc/bw6-761/fr/polynomial" @@ -28,7 +27,6 @@ import ( "github.com/consensys/gnark/std/utils/algo_utils" "hash" "math/big" - "time" ) type gkrSolvingData struct { @@ -85,13 +83,8 @@ func (a gkrAssignment) setOuts(circuit constraint.GkrCircuit, outs []*big.Int) { // Check if outsI == len(outs)? } -const log = true - func gkrSolveHint(info constraint.GkrInfo, solvingData *gkrSolvingData) hint.Function { return func(_ *big.Int, ins, outs []*big.Int) error { - - startTime := time.Now().UnixMicro() - // assumes assignmentVector is arranged wire first, instance second in order of solution circuit := info.Circuit nbInstances := info.NbInstances @@ -144,11 +137,6 @@ func gkrSolveHint(info constraint.GkrInfo, solvingData *gkrSolvingData) hint.Fun assignment.setOuts(info.Circuit, outs) - if log { - endTime := time.Now().UnixMicro() - fmt.Println("gkr solved in", endTime-startTime, "μs") - } - return nil } } @@ -162,9 +150,6 @@ func frToBigInts(dst []*big.Int, src []fr.Element) { func gkrProveHint(hashName string, data *gkrSolvingData) hint.Function { return func(_ *big.Int, ins, outs []*big.Int) error { - - startTime := time.Now().UnixMicro() - insBytes := algo_utils.Map(ins[1:], func(i *big.Int) []byte { // the first input is dummy, just to ensure the solver's work is done before the prover is called b := i.Bytes() return b[:] @@ -193,11 +178,6 @@ func gkrProveHint(hashName string, data *gkrSolvingData) hint.Function { data.dumpAssignments() - if log { - endTime := time.Now().UnixMicro() - fmt.Println("gkr proved in", endTime-startTime, "μs") - } - return nil } diff --git a/internal/generator/backend/template/representations/gkr.go.tmpl b/internal/generator/backend/template/representations/gkr.go.tmpl index f33cac90bf..1d6df8406a 100644 --- a/internal/generator/backend/template/representations/gkr.go.tmpl +++ b/internal/generator/backend/template/representations/gkr.go.tmpl @@ -1,5 +1,4 @@ import ( - "fmt" {{- template "import_fr" .}} {{- template "import_gkr" .}} {{- template "import_polynomial" .}} @@ -10,7 +9,6 @@ import ( "github.com/consensys/gnark/std/utils/algo_utils" "hash" "math/big" - "time" ) type gkrSolvingData struct { @@ -67,13 +65,8 @@ func (a gkrAssignment) setOuts(circuit constraint.GkrCircuit, outs []*big.Int) { // Check if outsI == len(outs)? } -const log = true - func gkrSolveHint(info constraint.GkrInfo, solvingData *gkrSolvingData) hint.Function { return func(_ *big.Int, ins, outs []*big.Int) error { - - startTime := time.Now().UnixMicro() - // assumes assignmentVector is arranged wire first, instance second in order of solution circuit := info.Circuit nbInstances := info.NbInstances @@ -126,11 +119,6 @@ func gkrSolveHint(info constraint.GkrInfo, solvingData *gkrSolvingData) hint.Fun assignment.setOuts(info.Circuit, outs) - if log { - endTime := time.Now().UnixMicro() - fmt.Println("gkr solved in", endTime-startTime, "μs") - } - return nil } } @@ -144,9 +132,6 @@ func frToBigInts(dst []*big.Int, src []fr.Element) { func gkrProveHint(hashName string, data *gkrSolvingData) hint.Function { return func(_ *big.Int, ins, outs []*big.Int) error { - - startTime := time.Now().UnixMicro() - insBytes := algo_utils.Map(ins[1:], func(i *big.Int) []byte { // the first input is dummy, just to ensure the solver's work is done before the prover is called b := i.Bytes() return b[:] @@ -175,11 +160,6 @@ func gkrProveHint(hashName string, data *gkrSolvingData) hint.Function { data.dumpAssignments() - if log { - endTime := time.Now().UnixMicro() - fmt.Println("gkr proved in", endTime-startTime, "μs") - } - return nil } From 2753ae60ed8f6de4fc793d4ec3cbcb9291d52236 Mon Sep 17 00:00:00 2001 From: Gautam Botrel Date: Tue, 14 Feb 2023 14:33:34 -0600 Subject: [PATCH 63/71] feat: update gnark version to v0.8.0 --- doc.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc.go b/doc.go index 84ae2e9545..697944b7d7 100644 --- a/doc.go +++ b/doc.go @@ -22,7 +22,7 @@ import ( "github.com/consensys/gnark-crypto/ecc" ) -var Version = semver.MustParse("0.8.0-alpha") +var Version = semver.MustParse("0.8.0") // Curves return the curves supported by gnark func Curves() []ecc.ID { From 3fad3c8d8d4492d64f5d48594641740e62ced704 Mon Sep 17 00:00:00 2001 From: Arya Tabaie Date: Tue, 27 Jun 2023 11:53:43 -0500 Subject: [PATCH 64/71] chore: merge changes --- constraint/gkr.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/constraint/gkr.go b/constraint/gkr.go index 7c40c35937..4d84a5466d 100644 --- a/constraint/gkr.go +++ b/constraint/gkr.go @@ -3,7 +3,7 @@ package constraint import ( "fmt" "github.com/consensys/gnark-crypto/utils" - "github.com/consensys/gnark/backend/hint" + "github.com/consensys/gnark/constraint/solver" "github.com/consensys/gnark/std/utils/algo_utils" "sort" ) @@ -30,8 +30,8 @@ type GkrInfo struct { MaxNIns int NbInstances int HashName string - SolveHintID hint.ID - ProveHintID hint.ID + SolveHintID solver.HintID + ProveHintID solver.HintID } type GkrPermutations struct { From 1243f3c4a9a7d30a8f23fa35938d7850aff319aa Mon Sep 17 00:00:00 2001 From: Arya Tabaie Date: Tue, 27 Jun 2023 14:09:19 -0500 Subject: [PATCH 65/71] chore: make staticcheck happy --- constraint/bls12-377/gkr.go | 10 +++++----- constraint/bls12-381/gkr.go | 10 +++++----- constraint/bls24-315/gkr.go | 10 +++++----- constraint/bls24-317/gkr.go | 10 +++++----- constraint/blueprint.go | 6 +++--- constraint/bn254/gkr.go | 10 +++++----- constraint/bn254/system.go | 4 ++++ constraint/bw6-633/gkr.go | 10 +++++----- constraint/bw6-761/gkr.go | 10 +++++----- constraint/core.go | 10 ++++++++++ constraint/system.go | 3 ++- constraint/term.go | 2 +- frontend/builder.go | 4 +++- frontend/cs/r1cs/api.go | 4 ++++ frontend/cs/scs/api.go | 4 ++++ .../backend/template/representations/gkr.go.tmpl | 10 +++++----- std/gkr/api.go | 4 ++-- std/gkr/api_test.go | 6 +++--- std/gkr/compile.go | 8 ++++---- std/hash/hash.go | 2 +- 20 files changed, 81 insertions(+), 56 deletions(-) diff --git a/constraint/bls12-377/gkr.go b/constraint/bls12-377/gkr.go index d1b0a840b8..1e1becb91b 100644 --- a/constraint/bls12-377/gkr.go +++ b/constraint/bls12-377/gkr.go @@ -22,8 +22,8 @@ import ( "github.com/consensys/gnark-crypto/ecc/bls12-377/fr/polynomial" fiatshamir "github.com/consensys/gnark-crypto/fiat-shamir" "github.com/consensys/gnark-crypto/utils" - "github.com/consensys/gnark/backend/hint" "github.com/consensys/gnark/constraint" + hint "github.com/consensys/gnark/constraint/solver" "github.com/consensys/gnark/std/utils/algo_utils" "hash" "math/big" @@ -83,7 +83,7 @@ func (a gkrAssignment) setOuts(circuit constraint.GkrCircuit, outs []*big.Int) { // Check if outsI == len(outs)? } -func gkrSolveHint(info constraint.GkrInfo, solvingData *gkrSolvingData) hint.Function { +func gkrSolveHint(info constraint.GkrInfo, solvingData *gkrSolvingData) hint.Hint { return func(_ *big.Int, ins, outs []*big.Int) error { // assumes assignmentVector is arranged wire first, instance second in order of solution circuit := info.Circuit @@ -147,7 +147,7 @@ func frToBigInts(dst []*big.Int, src []fr.Element) { } } -func gkrProveHint(hashName string, data *gkrSolvingData) hint.Function { +func gkrProveHint(hashName string, data *gkrSolvingData) hint.Hint { return func(_ *big.Int, ins, outs []*big.Int) error { insBytes := algo_utils.Map(ins[1:], func(i *big.Int) []byte { // the first input is dummy, just to ensure the solver's work is done before the prover is called @@ -183,8 +183,8 @@ func gkrProveHint(hashName string, data *gkrSolvingData) hint.Function { } } -func defineGkrHints(info constraint.GkrInfo, hintFunctions map[hint.ID]hint.Function) map[hint.ID]hint.Function { - res := make(map[hint.ID]hint.Function, len(hintFunctions)+2) +func defineGkrHints(info constraint.GkrInfo, hintFunctions map[hint.HintID]hint.Hint) map[hint.HintID]hint.Hint { + res := make(map[hint.HintID]hint.Hint, len(hintFunctions)+2) for k, v := range hintFunctions { res[k] = v } diff --git a/constraint/bls12-381/gkr.go b/constraint/bls12-381/gkr.go index 838df92eb5..ffff99484d 100644 --- a/constraint/bls12-381/gkr.go +++ b/constraint/bls12-381/gkr.go @@ -22,8 +22,8 @@ import ( "github.com/consensys/gnark-crypto/ecc/bls12-381/fr/polynomial" fiatshamir "github.com/consensys/gnark-crypto/fiat-shamir" "github.com/consensys/gnark-crypto/utils" - "github.com/consensys/gnark/backend/hint" "github.com/consensys/gnark/constraint" + hint "github.com/consensys/gnark/constraint/solver" "github.com/consensys/gnark/std/utils/algo_utils" "hash" "math/big" @@ -83,7 +83,7 @@ func (a gkrAssignment) setOuts(circuit constraint.GkrCircuit, outs []*big.Int) { // Check if outsI == len(outs)? } -func gkrSolveHint(info constraint.GkrInfo, solvingData *gkrSolvingData) hint.Function { +func gkrSolveHint(info constraint.GkrInfo, solvingData *gkrSolvingData) hint.Hint { return func(_ *big.Int, ins, outs []*big.Int) error { // assumes assignmentVector is arranged wire first, instance second in order of solution circuit := info.Circuit @@ -147,7 +147,7 @@ func frToBigInts(dst []*big.Int, src []fr.Element) { } } -func gkrProveHint(hashName string, data *gkrSolvingData) hint.Function { +func gkrProveHint(hashName string, data *gkrSolvingData) hint.Hint { return func(_ *big.Int, ins, outs []*big.Int) error { insBytes := algo_utils.Map(ins[1:], func(i *big.Int) []byte { // the first input is dummy, just to ensure the solver's work is done before the prover is called @@ -183,8 +183,8 @@ func gkrProveHint(hashName string, data *gkrSolvingData) hint.Function { } } -func defineGkrHints(info constraint.GkrInfo, hintFunctions map[hint.ID]hint.Function) map[hint.ID]hint.Function { - res := make(map[hint.ID]hint.Function, len(hintFunctions)+2) +func defineGkrHints(info constraint.GkrInfo, hintFunctions map[hint.HintID]hint.Hint) map[hint.HintID]hint.Hint { + res := make(map[hint.HintID]hint.Hint, len(hintFunctions)+2) for k, v := range hintFunctions { res[k] = v } diff --git a/constraint/bls24-315/gkr.go b/constraint/bls24-315/gkr.go index 4e66b4da8a..bca5ee8c0c 100644 --- a/constraint/bls24-315/gkr.go +++ b/constraint/bls24-315/gkr.go @@ -22,8 +22,8 @@ import ( "github.com/consensys/gnark-crypto/ecc/bls24-315/fr/polynomial" fiatshamir "github.com/consensys/gnark-crypto/fiat-shamir" "github.com/consensys/gnark-crypto/utils" - "github.com/consensys/gnark/backend/hint" "github.com/consensys/gnark/constraint" + hint "github.com/consensys/gnark/constraint/solver" "github.com/consensys/gnark/std/utils/algo_utils" "hash" "math/big" @@ -83,7 +83,7 @@ func (a gkrAssignment) setOuts(circuit constraint.GkrCircuit, outs []*big.Int) { // Check if outsI == len(outs)? } -func gkrSolveHint(info constraint.GkrInfo, solvingData *gkrSolvingData) hint.Function { +func gkrSolveHint(info constraint.GkrInfo, solvingData *gkrSolvingData) hint.Hint { return func(_ *big.Int, ins, outs []*big.Int) error { // assumes assignmentVector is arranged wire first, instance second in order of solution circuit := info.Circuit @@ -147,7 +147,7 @@ func frToBigInts(dst []*big.Int, src []fr.Element) { } } -func gkrProveHint(hashName string, data *gkrSolvingData) hint.Function { +func gkrProveHint(hashName string, data *gkrSolvingData) hint.Hint { return func(_ *big.Int, ins, outs []*big.Int) error { insBytes := algo_utils.Map(ins[1:], func(i *big.Int) []byte { // the first input is dummy, just to ensure the solver's work is done before the prover is called @@ -183,8 +183,8 @@ func gkrProveHint(hashName string, data *gkrSolvingData) hint.Function { } } -func defineGkrHints(info constraint.GkrInfo, hintFunctions map[hint.ID]hint.Function) map[hint.ID]hint.Function { - res := make(map[hint.ID]hint.Function, len(hintFunctions)+2) +func defineGkrHints(info constraint.GkrInfo, hintFunctions map[hint.HintID]hint.Hint) map[hint.HintID]hint.Hint { + res := make(map[hint.HintID]hint.Hint, len(hintFunctions)+2) for k, v := range hintFunctions { res[k] = v } diff --git a/constraint/bls24-317/gkr.go b/constraint/bls24-317/gkr.go index cc8a6bac62..5707c20c54 100644 --- a/constraint/bls24-317/gkr.go +++ b/constraint/bls24-317/gkr.go @@ -22,8 +22,8 @@ import ( "github.com/consensys/gnark-crypto/ecc/bls24-317/fr/polynomial" fiatshamir "github.com/consensys/gnark-crypto/fiat-shamir" "github.com/consensys/gnark-crypto/utils" - "github.com/consensys/gnark/backend/hint" "github.com/consensys/gnark/constraint" + hint "github.com/consensys/gnark/constraint/solver" "github.com/consensys/gnark/std/utils/algo_utils" "hash" "math/big" @@ -83,7 +83,7 @@ func (a gkrAssignment) setOuts(circuit constraint.GkrCircuit, outs []*big.Int) { // Check if outsI == len(outs)? } -func gkrSolveHint(info constraint.GkrInfo, solvingData *gkrSolvingData) hint.Function { +func gkrSolveHint(info constraint.GkrInfo, solvingData *gkrSolvingData) hint.Hint { return func(_ *big.Int, ins, outs []*big.Int) error { // assumes assignmentVector is arranged wire first, instance second in order of solution circuit := info.Circuit @@ -147,7 +147,7 @@ func frToBigInts(dst []*big.Int, src []fr.Element) { } } -func gkrProveHint(hashName string, data *gkrSolvingData) hint.Function { +func gkrProveHint(hashName string, data *gkrSolvingData) hint.Hint { return func(_ *big.Int, ins, outs []*big.Int) error { insBytes := algo_utils.Map(ins[1:], func(i *big.Int) []byte { // the first input is dummy, just to ensure the solver's work is done before the prover is called @@ -183,8 +183,8 @@ func gkrProveHint(hashName string, data *gkrSolvingData) hint.Function { } } -func defineGkrHints(info constraint.GkrInfo, hintFunctions map[hint.ID]hint.Function) map[hint.ID]hint.Function { - res := make(map[hint.ID]hint.Function, len(hintFunctions)+2) +func defineGkrHints(info constraint.GkrInfo, hintFunctions map[hint.HintID]hint.Hint) map[hint.HintID]hint.Hint { + res := make(map[hint.HintID]hint.Hint, len(hintFunctions)+2) for k, v := range hintFunctions { res[k] = v } diff --git a/constraint/blueprint.go b/constraint/blueprint.go index 1471d9d3e9..2949f0665f 100644 --- a/constraint/blueprint.go +++ b/constraint/blueprint.go @@ -2,7 +2,7 @@ package constraint type BlueprintID uint32 -// Blueprint enable representing heterogenous constraints or instructions in a constraint system +// Blueprint enable representing heterogeneous constraints or instructions in a constraint system // in a memory efficient way. Blueprints essentially help the frontend/ to "compress" // constraints or instructions, and specify for the solving (or zksnark setup) part how to // "decompress" and optionally "solve" the associated wires. @@ -66,8 +66,8 @@ type BlueprintHint interface { DecompressHint(h *HintMapping, instruction Instruction) } -// Compressable represent an object that knows how to encode itself as a []uint32. -type Compressable interface { +// Compressible represent an object that knows how to encode itself as a []uint32. +type Compressible interface { // Compress interprets the objects as a LinearExpression and encodes it as a []uint32. Compress(to *[]uint32) } diff --git a/constraint/bn254/gkr.go b/constraint/bn254/gkr.go index 6b00893e0f..f47207613a 100644 --- a/constraint/bn254/gkr.go +++ b/constraint/bn254/gkr.go @@ -22,8 +22,8 @@ import ( "github.com/consensys/gnark-crypto/ecc/bn254/fr/polynomial" fiatshamir "github.com/consensys/gnark-crypto/fiat-shamir" "github.com/consensys/gnark-crypto/utils" - "github.com/consensys/gnark/backend/hint" "github.com/consensys/gnark/constraint" + hint "github.com/consensys/gnark/constraint/solver" "github.com/consensys/gnark/std/utils/algo_utils" "hash" "math/big" @@ -83,7 +83,7 @@ func (a gkrAssignment) setOuts(circuit constraint.GkrCircuit, outs []*big.Int) { // Check if outsI == len(outs)? } -func gkrSolveHint(info constraint.GkrInfo, solvingData *gkrSolvingData) hint.Function { +func gkrSolveHint(info constraint.GkrInfo, solvingData *gkrSolvingData) hint.Hint { return func(_ *big.Int, ins, outs []*big.Int) error { // assumes assignmentVector is arranged wire first, instance second in order of solution circuit := info.Circuit @@ -147,7 +147,7 @@ func frToBigInts(dst []*big.Int, src []fr.Element) { } } -func gkrProveHint(hashName string, data *gkrSolvingData) hint.Function { +func gkrProveHint(hashName string, data *gkrSolvingData) hint.Hint { return func(_ *big.Int, ins, outs []*big.Int) error { insBytes := algo_utils.Map(ins[1:], func(i *big.Int) []byte { // the first input is dummy, just to ensure the solver's work is done before the prover is called @@ -183,8 +183,8 @@ func gkrProveHint(hashName string, data *gkrSolvingData) hint.Function { } } -func defineGkrHints(info constraint.GkrInfo, hintFunctions map[hint.ID]hint.Function) map[hint.ID]hint.Function { - res := make(map[hint.ID]hint.Function, len(hintFunctions)+2) +func defineGkrHints(info constraint.GkrInfo, hintFunctions map[hint.HintID]hint.Hint) map[hint.HintID]hint.Hint { + res := make(map[hint.HintID]hint.Hint, len(hintFunctions)+2) for k, v := range hintFunctions { res[k] = v } diff --git a/constraint/bn254/system.go b/constraint/bn254/system.go index 949e532dbe..a96fe5d5a2 100644 --- a/constraint/bn254/system.go +++ b/constraint/bn254/system.go @@ -372,3 +372,7 @@ func getTagSet() cbor.TagSet { return ts } + +func (s *system) AddGkr(gkr constraint.GkrInfo) error { + return s.System.AddGkr(gkr) +} diff --git a/constraint/bw6-633/gkr.go b/constraint/bw6-633/gkr.go index 5a5de0b7fd..de49f3e8a4 100644 --- a/constraint/bw6-633/gkr.go +++ b/constraint/bw6-633/gkr.go @@ -22,8 +22,8 @@ import ( "github.com/consensys/gnark-crypto/ecc/bw6-633/fr/polynomial" fiatshamir "github.com/consensys/gnark-crypto/fiat-shamir" "github.com/consensys/gnark-crypto/utils" - "github.com/consensys/gnark/backend/hint" "github.com/consensys/gnark/constraint" + hint "github.com/consensys/gnark/constraint/solver" "github.com/consensys/gnark/std/utils/algo_utils" "hash" "math/big" @@ -83,7 +83,7 @@ func (a gkrAssignment) setOuts(circuit constraint.GkrCircuit, outs []*big.Int) { // Check if outsI == len(outs)? } -func gkrSolveHint(info constraint.GkrInfo, solvingData *gkrSolvingData) hint.Function { +func gkrSolveHint(info constraint.GkrInfo, solvingData *gkrSolvingData) hint.Hint { return func(_ *big.Int, ins, outs []*big.Int) error { // assumes assignmentVector is arranged wire first, instance second in order of solution circuit := info.Circuit @@ -147,7 +147,7 @@ func frToBigInts(dst []*big.Int, src []fr.Element) { } } -func gkrProveHint(hashName string, data *gkrSolvingData) hint.Function { +func gkrProveHint(hashName string, data *gkrSolvingData) hint.Hint { return func(_ *big.Int, ins, outs []*big.Int) error { insBytes := algo_utils.Map(ins[1:], func(i *big.Int) []byte { // the first input is dummy, just to ensure the solver's work is done before the prover is called @@ -183,8 +183,8 @@ func gkrProveHint(hashName string, data *gkrSolvingData) hint.Function { } } -func defineGkrHints(info constraint.GkrInfo, hintFunctions map[hint.ID]hint.Function) map[hint.ID]hint.Function { - res := make(map[hint.ID]hint.Function, len(hintFunctions)+2) +func defineGkrHints(info constraint.GkrInfo, hintFunctions map[hint.HintID]hint.Hint) map[hint.HintID]hint.Hint { + res := make(map[hint.HintID]hint.Hint, len(hintFunctions)+2) for k, v := range hintFunctions { res[k] = v } diff --git a/constraint/bw6-761/gkr.go b/constraint/bw6-761/gkr.go index fe85e72dd1..12958a20f4 100644 --- a/constraint/bw6-761/gkr.go +++ b/constraint/bw6-761/gkr.go @@ -22,8 +22,8 @@ import ( "github.com/consensys/gnark-crypto/ecc/bw6-761/fr/polynomial" fiatshamir "github.com/consensys/gnark-crypto/fiat-shamir" "github.com/consensys/gnark-crypto/utils" - "github.com/consensys/gnark/backend/hint" "github.com/consensys/gnark/constraint" + hint "github.com/consensys/gnark/constraint/solver" "github.com/consensys/gnark/std/utils/algo_utils" "hash" "math/big" @@ -83,7 +83,7 @@ func (a gkrAssignment) setOuts(circuit constraint.GkrCircuit, outs []*big.Int) { // Check if outsI == len(outs)? } -func gkrSolveHint(info constraint.GkrInfo, solvingData *gkrSolvingData) hint.Function { +func gkrSolveHint(info constraint.GkrInfo, solvingData *gkrSolvingData) hint.Hint { return func(_ *big.Int, ins, outs []*big.Int) error { // assumes assignmentVector is arranged wire first, instance second in order of solution circuit := info.Circuit @@ -147,7 +147,7 @@ func frToBigInts(dst []*big.Int, src []fr.Element) { } } -func gkrProveHint(hashName string, data *gkrSolvingData) hint.Function { +func gkrProveHint(hashName string, data *gkrSolvingData) hint.Hint { return func(_ *big.Int, ins, outs []*big.Int) error { insBytes := algo_utils.Map(ins[1:], func(i *big.Int) []byte { // the first input is dummy, just to ensure the solver's work is done before the prover is called @@ -183,8 +183,8 @@ func gkrProveHint(hashName string, data *gkrSolvingData) hint.Function { } } -func defineGkrHints(info constraint.GkrInfo, hintFunctions map[hint.ID]hint.Function) map[hint.ID]hint.Function { - res := make(map[hint.ID]hint.Function, len(hintFunctions)+2) +func defineGkrHints(info constraint.GkrInfo, hintFunctions map[hint.HintID]hint.Hint) map[hint.HintID]hint.Hint { + res := make(map[hint.HintID]hint.Hint, len(hintFunctions)+2) for k, v := range hintFunctions { res[k] = v } diff --git a/constraint/core.go b/constraint/core.go index e54fab3149..12aac144cb 100644 --- a/constraint/core.go +++ b/constraint/core.go @@ -125,6 +125,7 @@ type System struct { lbOutputs []uint32 `cbor:"-"` // wire outputs for current constraint. CommitmentInfo Commitments + GkrInfo GkrInfo genericHint BlueprintID } @@ -457,3 +458,12 @@ func putBuffer(buf *[]uint32) { } bufPool.Put(buf) } + +func (system *System) AddGkr(gkr GkrInfo) error { + if system.GkrInfo.Is() { + return fmt.Errorf("currently only one GKR sub-circuit per SNARK is supported") + } + + system.GkrInfo = gkr + return nil +} diff --git a/constraint/system.go b/constraint/system.go index 19f8167f32..e03586af4e 100644 --- a/constraint/system.go +++ b/constraint/system.go @@ -20,7 +20,7 @@ type ConstraintSystem interface { // Deprecated: use _, err := Solve(...) instead IsSolved(witness witness.Witness, opts ...solver.Option) error - // Solve attempts to solves the constraint system using provided witness. + // Solve attempts to solve the constraint system using provided witness. // Returns an error if the witness does not allow all the constraints to be satisfied. // Returns a typed solution (R1CSSolution or SparseR1CSSolution) and nil otherwise. Solve(witness witness.Witness, opts ...solver.Option) (any, error) @@ -52,6 +52,7 @@ type ConstraintSystem interface { AddCommitment(c Commitment) error GetCommitments() Commitments + AddGkr(gkr GkrInfo) error AddLog(l LogEntry) diff --git a/constraint/term.go b/constraint/term.go index 857edd0da0..799fb4f7a3 100644 --- a/constraint/term.go +++ b/constraint/term.go @@ -54,7 +54,7 @@ func (t Term) String(r Resolver) string { return sbb.String() } -// implements constraint.Compressable +// implements constraint.Compressible // Compress compresses the term into a slice of uint32 words. // For compatibility with test engine and LinearExpression, the term is encoded as: diff --git a/frontend/builder.go b/frontend/builder.go index 680a789b7a..717dbfca7a 100644 --- a/frontend/builder.go +++ b/frontend/builder.go @@ -64,6 +64,8 @@ type Compiler interface { // ToCanonicalVariable converts a frontend.Variable to a constraint system specific Variable // ! Experimental: use in conjunction with constraint.CustomizableSystem ToCanonicalVariable(Variable) CanonicalVariable + + SetGkrInfo(constraint.GkrInfo) error } // Builder represents a constraint system builder @@ -104,5 +106,5 @@ type Rangechecker interface { // a PLONK builder --> constraint.Term // and the test/Engine --> ~*big.Int. type CanonicalVariable interface { - constraint.Compressable + constraint.Compressible } diff --git a/frontend/cs/r1cs/api.go b/frontend/cs/r1cs/api.go index 7bb01fa76c..797bba0854 100644 --- a/frontend/cs/r1cs/api.go +++ b/frontend/cs/r1cs/api.go @@ -815,3 +815,7 @@ func (builder *builder) wireIDsToVars(wireIDs ...[]int) []frontend.Variable { } return res } + +func (builder *builder) SetGkrInfo(info constraint.GkrInfo) error { + return builder.cs.AddGkr(info) +} diff --git a/frontend/cs/scs/api.go b/frontend/cs/scs/api.go index 12eff1e730..75764878d3 100644 --- a/frontend/cs/scs/api.go +++ b/frontend/cs/scs/api.go @@ -619,3 +619,7 @@ func filterConstants(v []frontend.Variable) []frontend.Variable { func (*builder) FrontendType() frontendtype.Type { return frontendtype.SCS } + +func (builder *builder) SetGkrInfo(info constraint.GkrInfo) error { + return builder.cs.AddGkr(info) +} diff --git a/internal/generator/backend/template/representations/gkr.go.tmpl b/internal/generator/backend/template/representations/gkr.go.tmpl index 1d6df8406a..d405ea501c 100644 --- a/internal/generator/backend/template/representations/gkr.go.tmpl +++ b/internal/generator/backend/template/representations/gkr.go.tmpl @@ -4,8 +4,8 @@ import ( {{- template "import_polynomial" .}} fiatshamir "github.com/consensys/gnark-crypto/fiat-shamir" "github.com/consensys/gnark-crypto/utils" - "github.com/consensys/gnark/backend/hint" "github.com/consensys/gnark/constraint" + hint "github.com/consensys/gnark/constraint/solver" "github.com/consensys/gnark/std/utils/algo_utils" "hash" "math/big" @@ -65,7 +65,7 @@ func (a gkrAssignment) setOuts(circuit constraint.GkrCircuit, outs []*big.Int) { // Check if outsI == len(outs)? } -func gkrSolveHint(info constraint.GkrInfo, solvingData *gkrSolvingData) hint.Function { +func gkrSolveHint(info constraint.GkrInfo, solvingData *gkrSolvingData) hint.Hint { return func(_ *big.Int, ins, outs []*big.Int) error { // assumes assignmentVector is arranged wire first, instance second in order of solution circuit := info.Circuit @@ -129,7 +129,7 @@ func frToBigInts(dst []*big.Int, src []fr.Element) { } } -func gkrProveHint(hashName string, data *gkrSolvingData) hint.Function { +func gkrProveHint(hashName string, data *gkrSolvingData) hint.Hint { return func(_ *big.Int, ins, outs []*big.Int) error { insBytes := algo_utils.Map(ins[1:], func(i *big.Int) []byte { // the first input is dummy, just to ensure the solver's work is done before the prover is called @@ -165,8 +165,8 @@ func gkrProveHint(hashName string, data *gkrSolvingData) hint.Function { } } -func defineGkrHints(info constraint.GkrInfo, hintFunctions map[hint.ID]hint.Function) map[hint.ID]hint.Function { - res := make(map[hint.ID]hint.Function, len(hintFunctions)+2) +func defineGkrHints(info constraint.GkrInfo, hintFunctions map[hint.HintID]hint.Hint) map[hint.HintID]hint.Hint { + res := make(map[hint.HintID]hint.Hint, len(hintFunctions)+2) for k, v := range hintFunctions { res[k] = v } diff --git a/std/gkr/api.go b/std/gkr/api.go index 2bb88bc5fc..7515e93163 100644 --- a/std/gkr/api.go +++ b/std/gkr/api.go @@ -1,8 +1,8 @@ package gkr import ( - "github.com/consensys/gnark/backend/hint" "github.com/consensys/gnark/constraint" + "github.com/consensys/gnark/constraint/solver" "github.com/consensys/gnark/frontend" "github.com/consensys/gnark/std/utils/algo_utils" "math/big" @@ -122,7 +122,7 @@ func (api *API) Compiler() frontend.Compiler { panic("not implemented") } -func (api *API) NewHint(f hint.Function, nbOutputs int, inputs ...frontend.Variable) ([]frontend.Variable, error) { +func (api *API) NewHint(f solver.Hint, nbOutputs int, inputs ...frontend.Variable) ([]frontend.Variable, error) { panic("not implemented") } diff --git a/std/gkr/api_test.go b/std/gkr/api_test.go index 1325be3288..3dd889c7e6 100644 --- a/std/gkr/api_test.go +++ b/std/gkr/api_test.go @@ -361,7 +361,7 @@ func (c *benchMiMCMerkleTreeCircuit) Define(api frontend.API) error { } Z := solution.Export(z) - challenge, err := api.Compiler().Commit(Z...) + challenge, err := api.Compiler().(frontend.Committer).Commit(Z...) if err != nil { return err } @@ -393,7 +393,7 @@ func testE2E(t *testing.T, circuit, assignment frontend.Circuit) { func registerMiMC() { bn254r1cs.HashBuilderRegistry["mimc"] = bn254MiMC.NewMiMC - stdHash.BuilderRegistry["mimc"] = func(api frontend.API) (stdHash.Hash, error) { + stdHash.BuilderRegistry["mimc"] = func(api frontend.API) (stdHash.FieldHasher, error) { m, err := mimc.NewMiMC(api) return &m, err } @@ -404,7 +404,7 @@ func registerConstant(c int) { bn254r1cs.HashBuilderRegistry[name] = func() hash.Hash { return constHashBn254(c) } - stdHash.BuilderRegistry[name] = func(frontend.API) (stdHash.Hash, error) { + stdHash.BuilderRegistry[name] = func(frontend.API) (stdHash.FieldHasher, error) { return constHash(c), nil } } diff --git a/std/gkr/compile.go b/std/gkr/compile.go index 4b7a719dd9..8d1042ad74 100644 --- a/std/gkr/compile.go +++ b/std/gkr/compile.go @@ -2,8 +2,8 @@ package gkr import ( "fmt" - "github.com/consensys/gnark/backend/hint" "github.com/consensys/gnark/constraint" + "github.com/consensys/gnark/constraint/solver" "github.com/consensys/gnark/frontend" fiatshamir "github.com/consensys/gnark/std/fiat-shamir" "github.com/consensys/gnark/std/hash" @@ -123,7 +123,7 @@ func (api *API) Solve(parentApi frontend.API) (Solution, error) { } outsSerialized, err := parentApi.Compiler().NewHint(SolveHintPlaceholder, solveHintNOut, ins...) - api.toStore.SolveHintID = hint.UUID(SolveHintPlaceholder) + api.toStore.SolveHintID = solver.GetHintID(SolveHintPlaceholder) if err != nil { return Solution{}, err } @@ -176,7 +176,7 @@ func (s Solution) Verify(hashName string, initialChallenges ...frontend.Variable ProveHintPlaceholder, ProofSize(forSnark.circuit, logNbInstances), hintIns...); err != nil { return err } - s.toStore.ProveHintID = hint.UUID(ProveHintPlaceholder) + s.toStore.ProveHintID = solver.GetHintID(ProveHintPlaceholder) forSnarkSorted := algo_utils.MapRange(0, len(s.toStore.Circuit), slicePtrAt(forSnark.circuit)) @@ -184,7 +184,7 @@ func (s Solution) Verify(hashName string, initialChallenges ...frontend.Variable return err } - var hsh hash.Hash + var hsh hash.FieldHasher if hsh, err = hash.BuilderRegistry[hashName](s.parentApi); err != nil { return err } diff --git a/std/hash/hash.go b/std/hash/hash.go index 307a7fc4b5..67e0d91ce1 100644 --- a/std/hash/hash.go +++ b/std/hash/hash.go @@ -37,7 +37,7 @@ type FieldHasher interface { Reset() } -var BuilderRegistry = make(map[string]func(api frontend.API) (Hash, error)) +var BuilderRegistry = make(map[string]func(api frontend.API) (FieldHasher, error)) // BinaryHasher hashes inputs into a short digest. It takes as inputs bytes and // outputs byte array whose length depends on the underlying hash function. For From 96b415461c4a53e1c53da5574de3202b979ec65f Mon Sep 17 00:00:00 2001 From: Arya Tabaie Date: Tue, 27 Jun 2023 14:16:21 -0500 Subject: [PATCH 66/71] build go generate --- constraint/bls12-377/system.go | 4 ++++ constraint/bls12-381/system.go | 4 ++++ constraint/bls24-315/system.go | 4 ++++ constraint/bls24-317/system.go | 4 ++++ constraint/bw6-633/system.go | 4 ++++ constraint/bw6-761/system.go | 4 ++++ constraint/tinyfield/system.go | 4 ++++ .../generator/backend/template/representations/system.go.tmpl | 4 ++++ 8 files changed, 32 insertions(+) diff --git a/constraint/bls12-377/system.go b/constraint/bls12-377/system.go index 5a35f10a00..49ba1525ef 100644 --- a/constraint/bls12-377/system.go +++ b/constraint/bls12-377/system.go @@ -372,3 +372,7 @@ func getTagSet() cbor.TagSet { return ts } + +func (s *system) AddGkr(gkr constraint.GkrInfo) error { + return s.System.AddGkr(gkr) +} diff --git a/constraint/bls12-381/system.go b/constraint/bls12-381/system.go index ff3c074f67..5bcb7d44ee 100644 --- a/constraint/bls12-381/system.go +++ b/constraint/bls12-381/system.go @@ -372,3 +372,7 @@ func getTagSet() cbor.TagSet { return ts } + +func (s *system) AddGkr(gkr constraint.GkrInfo) error { + return s.System.AddGkr(gkr) +} diff --git a/constraint/bls24-315/system.go b/constraint/bls24-315/system.go index de1f206275..01ea069cb3 100644 --- a/constraint/bls24-315/system.go +++ b/constraint/bls24-315/system.go @@ -372,3 +372,7 @@ func getTagSet() cbor.TagSet { return ts } + +func (s *system) AddGkr(gkr constraint.GkrInfo) error { + return s.System.AddGkr(gkr) +} diff --git a/constraint/bls24-317/system.go b/constraint/bls24-317/system.go index f8ac490de2..06633648ce 100644 --- a/constraint/bls24-317/system.go +++ b/constraint/bls24-317/system.go @@ -372,3 +372,7 @@ func getTagSet() cbor.TagSet { return ts } + +func (s *system) AddGkr(gkr constraint.GkrInfo) error { + return s.System.AddGkr(gkr) +} diff --git a/constraint/bw6-633/system.go b/constraint/bw6-633/system.go index f102b47290..7cd6843fc5 100644 --- a/constraint/bw6-633/system.go +++ b/constraint/bw6-633/system.go @@ -372,3 +372,7 @@ func getTagSet() cbor.TagSet { return ts } + +func (s *system) AddGkr(gkr constraint.GkrInfo) error { + return s.System.AddGkr(gkr) +} diff --git a/constraint/bw6-761/system.go b/constraint/bw6-761/system.go index 10e7990dfa..75252436e8 100644 --- a/constraint/bw6-761/system.go +++ b/constraint/bw6-761/system.go @@ -372,3 +372,7 @@ func getTagSet() cbor.TagSet { return ts } + +func (s *system) AddGkr(gkr constraint.GkrInfo) error { + return s.System.AddGkr(gkr) +} diff --git a/constraint/tinyfield/system.go b/constraint/tinyfield/system.go index d75471e445..bcb551272b 100644 --- a/constraint/tinyfield/system.go +++ b/constraint/tinyfield/system.go @@ -372,3 +372,7 @@ func getTagSet() cbor.TagSet { return ts } + +func (s *system) AddGkr(gkr constraint.GkrInfo) error { + return s.System.AddGkr(gkr) +} diff --git a/internal/generator/backend/template/representations/system.go.tmpl b/internal/generator/backend/template/representations/system.go.tmpl index 7288fdb546..dc5b4a98d3 100644 --- a/internal/generator/backend/template/representations/system.go.tmpl +++ b/internal/generator/backend/template/representations/system.go.tmpl @@ -369,3 +369,7 @@ func getTagSet() cbor.TagSet { return ts } + +func (s *system) AddGkr(gkr constraint.GkrInfo) error { + return s.System.AddGkr(gkr) +} \ No newline at end of file From bbe066b998792f910d8741173c5ba1ab0168004c Mon Sep 17 00:00:00 2001 From: Arya Tabaie Date: Tue, 27 Jun 2023 14:29:54 -0500 Subject: [PATCH 67/71] docs: GKR API --- std/gkr/compile.go | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/std/gkr/compile.go b/std/gkr/compile.go index 8d1042ad74..724916e42a 100644 --- a/std/gkr/compile.go +++ b/std/gkr/compile.go @@ -33,6 +33,7 @@ func (api *API) nbInstances() int { return api.assignments.NbInstances() } +// NewApi creates a new GKR API func NewApi() *API { return &API{ toStore: constraint.GkrInfo{ @@ -66,6 +67,8 @@ func (api *API) Series(input, output frontend.Variable, inputInstance, outputIns return api } +// Import creates a new input variable, whose values across all instances are given by assignment. +// If the value in an instance depends on an output of another instance, leave the corresponding index in assigment nil and use Series to specify the dependency. func (api *API) Import(assignment []frontend.Variable) (constraint.GkrVariable, error) { nbInstances := len(assignment) logNbInstances := log2(uint(nbInstances)) @@ -149,10 +152,12 @@ func (api *API) Solve(parentApi frontend.API) (Solution, error) { }, nil } +// Export returns the values of an output variable across all instances func (s Solution) Export(v frontend.Variable) []frontend.Variable { return algo_utils.Map(s.permutations.SortedInstances, algo_utils.SliceAt(s.assignments[v.(constraint.GkrVariable)])) } +// Verify encodes the verification circuitry for the GKR circuit func (s Solution) Verify(hashName string, initialChallenges ...frontend.Variable) error { var ( err error From 9c2f87f950730488c9d7e253e57663c33a24dc6c Mon Sep 17 00:00:00 2001 From: Arya Tabaie Date: Tue, 27 Jun 2023 15:23:31 -0500 Subject: [PATCH 68/71] fix: replace hints bn254 --- backend/groth16/bn254/prove.go | 9 ++++++++- constraint/bn254/gkr.go | 22 +++++----------------- 2 files changed, 13 insertions(+), 18 deletions(-) diff --git a/backend/groth16/bn254/prove.go b/backend/groth16/bn254/prove.go index 75eb17e895..42ec4de8b9 100644 --- a/backend/groth16/bn254/prove.go +++ b/backend/groth16/bn254/prove.go @@ -26,7 +26,7 @@ import ( "github.com/consensys/gnark/backend/groth16/internal" "github.com/consensys/gnark/backend/witness" "github.com/consensys/gnark/constraint" - "github.com/consensys/gnark/constraint/bn254" + cs "github.com/consensys/gnark/constraint/bn254" "github.com/consensys/gnark/constraint/solver" "github.com/consensys/gnark/internal/utils" "github.com/consensys/gnark/logger" @@ -94,6 +94,13 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b }(i))) } + if r1cs.GkrInfo.Is() { + var gkrData cs.GkrSolvingData + solverOpts = append(solverOpts, + solver.OverrideHint(r1cs.GkrInfo.SolveHintID, cs.GkrSolveHint(r1cs.GkrInfo, &gkrData)), + solver.OverrideHint(r1cs.GkrInfo.ProveHintID, cs.GkrProveHint(r1cs.GkrInfo.HashName, &gkrData))) + } + _solution, err := r1cs.Solve(fullWitness, solverOpts...) if err != nil { return nil, err diff --git a/constraint/bn254/gkr.go b/constraint/bn254/gkr.go index f47207613a..d834f7caca 100644 --- a/constraint/bn254/gkr.go +++ b/constraint/bn254/gkr.go @@ -29,7 +29,7 @@ import ( "math/big" ) -type gkrSolvingData struct { +type GkrSolvingData struct { assignments gkr.WireAssignment circuit gkr.Circuit memoryPool polynomial.Pool @@ -45,7 +45,7 @@ func convertCircuit(noPtr constraint.GkrCircuit) gkr.Circuit { return resCircuit } -func (d *gkrSolvingData) init(info constraint.GkrInfo) gkrAssignment { +func (d *GkrSolvingData) init(info constraint.GkrInfo) gkrAssignment { d.circuit = convertCircuit(info.Circuit) d.memoryPool = polynomial.NewPool(d.circuit.MemoryRequirements(info.NbInstances)...) d.workers = utils.NewWorkerPool() @@ -60,7 +60,7 @@ func (d *gkrSolvingData) init(info constraint.GkrInfo) gkrAssignment { return assignmentsSequential } -func (d *gkrSolvingData) dumpAssignments() { +func (d *GkrSolvingData) dumpAssignments() { for _, p := range d.assignments { d.memoryPool.Dump(p) } @@ -83,7 +83,7 @@ func (a gkrAssignment) setOuts(circuit constraint.GkrCircuit, outs []*big.Int) { // Check if outsI == len(outs)? } -func gkrSolveHint(info constraint.GkrInfo, solvingData *gkrSolvingData) hint.Hint { +func GkrSolveHint(info constraint.GkrInfo, solvingData *GkrSolvingData) hint.Hint { return func(_ *big.Int, ins, outs []*big.Int) error { // assumes assignmentVector is arranged wire first, instance second in order of solution circuit := info.Circuit @@ -147,7 +147,7 @@ func frToBigInts(dst []*big.Int, src []fr.Element) { } } -func gkrProveHint(hashName string, data *gkrSolvingData) hint.Hint { +func GkrProveHint(hashName string, data *GkrSolvingData) hint.Hint { return func(_ *big.Int, ins, outs []*big.Int) error { insBytes := algo_utils.Map(ins[1:], func(i *big.Int) []byte { // the first input is dummy, just to ensure the solver's work is done before the prover is called @@ -183,18 +183,6 @@ func gkrProveHint(hashName string, data *gkrSolvingData) hint.Hint { } } -func defineGkrHints(info constraint.GkrInfo, hintFunctions map[hint.HintID]hint.Hint) map[hint.HintID]hint.Hint { - res := make(map[hint.HintID]hint.Hint, len(hintFunctions)+2) - for k, v := range hintFunctions { - res[k] = v - } - - var gkrData gkrSolvingData - res[info.SolveHintID] = gkrSolveHint(info, &gkrData) - res[info.ProveHintID] = gkrProveHint(info.HashName, &gkrData) - return res -} - var GkrGateRegistry = map[string]gkr.Gate{ // TODO: Migrate to gnark-crypto "mul": mulGate(2), "add": addGate{}, From 82949fd50110b25f607e16cd56f646fbd364dc7e Mon Sep 17 00:00:00 2001 From: Arya Tabaie Date: Tue, 27 Jun 2023 15:28:48 -0500 Subject: [PATCH 69/71] build replace hints generify --- .../bls12-377/mpcsetup/marshal_test.go | 2 +- backend/groth16/bls12-377/mpcsetup/phase2.go | 2 +- .../groth16/bls12-377/mpcsetup/setup_test.go | 2 +- backend/groth16/bls12-377/prove.go | 9 +++++++- backend/groth16/bls12-377/setup.go | 2 +- .../bls12-381/mpcsetup/marshal_test.go | 2 +- backend/groth16/bls12-381/mpcsetup/phase2.go | 2 +- .../groth16/bls12-381/mpcsetup/setup_test.go | 2 +- backend/groth16/bls12-381/prove.go | 9 +++++++- backend/groth16/bls12-381/setup.go | 2 +- .../bls24-315/mpcsetup/marshal_test.go | 2 +- backend/groth16/bls24-315/mpcsetup/phase2.go | 2 +- .../groth16/bls24-315/mpcsetup/setup_test.go | 2 +- backend/groth16/bls24-315/prove.go | 9 +++++++- backend/groth16/bls24-315/setup.go | 2 +- .../bls24-317/mpcsetup/marshal_test.go | 2 +- backend/groth16/bls24-317/mpcsetup/phase2.go | 2 +- .../groth16/bls24-317/mpcsetup/setup_test.go | 2 +- backend/groth16/bls24-317/prove.go | 9 +++++++- backend/groth16/bls24-317/setup.go | 2 +- .../groth16/bn254/mpcsetup/marshal_test.go | 2 +- backend/groth16/bn254/mpcsetup/phase2.go | 2 +- backend/groth16/bn254/mpcsetup/setup_test.go | 2 +- backend/groth16/bn254/setup.go | 2 +- .../groth16/bw6-633/mpcsetup/marshal_test.go | 2 +- backend/groth16/bw6-633/mpcsetup/phase2.go | 2 +- .../groth16/bw6-633/mpcsetup/setup_test.go | 2 +- backend/groth16/bw6-633/prove.go | 9 +++++++- backend/groth16/bw6-633/setup.go | 2 +- .../groth16/bw6-761/mpcsetup/marshal_test.go | 2 +- backend/groth16/bw6-761/mpcsetup/phase2.go | 2 +- .../groth16/bw6-761/mpcsetup/setup_test.go | 2 +- backend/groth16/bw6-761/prove.go | 9 +++++++- backend/groth16/bw6-761/setup.go | 2 +- backend/plonk/bls12-377/prove.go | 2 +- backend/plonk/bls12-377/setup.go | 2 +- backend/plonk/bls12-381/prove.go | 2 +- backend/plonk/bls12-381/setup.go | 2 +- backend/plonk/bls24-315/prove.go | 2 +- backend/plonk/bls24-315/setup.go | 2 +- backend/plonk/bls24-317/prove.go | 2 +- backend/plonk/bls24-317/setup.go | 2 +- backend/plonk/bn254/prove.go | 2 +- backend/plonk/bn254/setup.go | 2 +- backend/plonk/bw6-633/prove.go | 2 +- backend/plonk/bw6-633/setup.go | 2 +- backend/plonk/bw6-761/prove.go | 2 +- backend/plonk/bw6-761/setup.go | 2 +- backend/plonkfri/bls12-377/prove.go | 2 +- backend/plonkfri/bls12-377/setup.go | 2 +- backend/plonkfri/bls12-381/prove.go | 2 +- backend/plonkfri/bls12-381/setup.go | 2 +- backend/plonkfri/bls24-315/prove.go | 2 +- backend/plonkfri/bls24-315/setup.go | 2 +- backend/plonkfri/bls24-317/prove.go | 2 +- backend/plonkfri/bls24-317/setup.go | 2 +- backend/plonkfri/bn254/prove.go | 2 +- backend/plonkfri/bn254/setup.go | 2 +- backend/plonkfri/bw6-633/prove.go | 2 +- backend/plonkfri/bw6-633/setup.go | 2 +- backend/plonkfri/bw6-761/prove.go | 2 +- backend/plonkfri/bw6-761/setup.go | 2 +- constraint/bls12-377/gkr.go | 22 +++++-------------- constraint/bls12-377/r1cs_test.go | 2 +- constraint/bls12-381/gkr.go | 22 +++++-------------- constraint/bls12-381/r1cs_test.go | 2 +- constraint/bls24-315/gkr.go | 22 +++++-------------- constraint/bls24-315/r1cs_test.go | 2 +- constraint/bls24-317/gkr.go | 22 +++++-------------- constraint/bls24-317/r1cs_test.go | 2 +- constraint/bn254/r1cs_test.go | 2 +- constraint/bw6-633/gkr.go | 22 +++++-------------- constraint/bw6-633/r1cs_test.go | 2 +- constraint/bw6-761/gkr.go | 22 +++++-------------- constraint/bw6-761/r1cs_test.go | 2 +- .../backend/template/imports.go.tmpl | 2 +- .../template/representations/gkr.go.tmpl | 22 +++++-------------- .../zkpschemes/groth16/groth16.prove.go.tmpl | 7 ++++++ 78 files changed, 154 insertions(+), 189 deletions(-) diff --git a/backend/groth16/bls12-377/mpcsetup/marshal_test.go b/backend/groth16/bls12-377/mpcsetup/marshal_test.go index fafeac27ca..ab7e6956cc 100644 --- a/backend/groth16/bls12-377/mpcsetup/marshal_test.go +++ b/backend/groth16/bls12-377/mpcsetup/marshal_test.go @@ -19,7 +19,7 @@ package mpcsetup import ( "bytes" curve "github.com/consensys/gnark-crypto/ecc/bls12-377" - "github.com/consensys/gnark/constraint/bls12-377" + cs "github.com/consensys/gnark/constraint/bls12-377" "github.com/consensys/gnark/frontend" "github.com/consensys/gnark/frontend/cs/r1cs" "github.com/stretchr/testify/require" diff --git a/backend/groth16/bls12-377/mpcsetup/phase2.go b/backend/groth16/bls12-377/mpcsetup/phase2.go index 3460138d12..e3816d65ca 100644 --- a/backend/groth16/bls12-377/mpcsetup/phase2.go +++ b/backend/groth16/bls12-377/mpcsetup/phase2.go @@ -24,7 +24,7 @@ import ( curve "github.com/consensys/gnark-crypto/ecc/bls12-377" "github.com/consensys/gnark-crypto/ecc/bls12-377/fr" "github.com/consensys/gnark/constraint" - "github.com/consensys/gnark/constraint/bls12-377" + cs "github.com/consensys/gnark/constraint/bls12-377" ) type Phase2Evaluations struct { diff --git a/backend/groth16/bls12-377/mpcsetup/setup_test.go b/backend/groth16/bls12-377/mpcsetup/setup_test.go index 6cfb710888..ca8cca346f 100644 --- a/backend/groth16/bls12-377/mpcsetup/setup_test.go +++ b/backend/groth16/bls12-377/mpcsetup/setup_test.go @@ -19,7 +19,7 @@ package mpcsetup import ( curve "github.com/consensys/gnark-crypto/ecc/bls12-377" "github.com/consensys/gnark-crypto/ecc/bls12-377/fr" - "github.com/consensys/gnark/constraint/bls12-377" + cs "github.com/consensys/gnark/constraint/bls12-377" "testing" "github.com/consensys/gnark/backend/groth16" diff --git a/backend/groth16/bls12-377/prove.go b/backend/groth16/bls12-377/prove.go index 7f52932504..ed7124a557 100644 --- a/backend/groth16/bls12-377/prove.go +++ b/backend/groth16/bls12-377/prove.go @@ -26,7 +26,7 @@ import ( "github.com/consensys/gnark/backend/groth16/internal" "github.com/consensys/gnark/backend/witness" "github.com/consensys/gnark/constraint" - "github.com/consensys/gnark/constraint/bls12-377" + cs "github.com/consensys/gnark/constraint/bls12-377" "github.com/consensys/gnark/constraint/solver" "github.com/consensys/gnark/internal/utils" "github.com/consensys/gnark/logger" @@ -94,6 +94,13 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b }(i))) } + if r1cs.GkrInfo.Is() { + var gkrData cs.GkrSolvingData + solverOpts = append(solverOpts, + solver.OverrideHint(r1cs.GkrInfo.SolveHintID, cs.GkrSolveHint(r1cs.GkrInfo, &gkrData)), + solver.OverrideHint(r1cs.GkrInfo.ProveHintID, cs.GkrProveHint(r1cs.GkrInfo.HashName, &gkrData))) + } + _solution, err := r1cs.Solve(fullWitness, solverOpts...) if err != nil { return nil, err diff --git a/backend/groth16/bls12-377/setup.go b/backend/groth16/bls12-377/setup.go index 1cd302a9a9..393d6a802e 100644 --- a/backend/groth16/bls12-377/setup.go +++ b/backend/groth16/bls12-377/setup.go @@ -25,7 +25,7 @@ import ( "github.com/consensys/gnark-crypto/ecc/bls12-377/fr/pedersen" "github.com/consensys/gnark/backend/groth16/internal" "github.com/consensys/gnark/constraint" - "github.com/consensys/gnark/constraint/bls12-377" + cs "github.com/consensys/gnark/constraint/bls12-377" "math/big" "math/bits" ) diff --git a/backend/groth16/bls12-381/mpcsetup/marshal_test.go b/backend/groth16/bls12-381/mpcsetup/marshal_test.go index 9432d50a6a..bbcaa65d36 100644 --- a/backend/groth16/bls12-381/mpcsetup/marshal_test.go +++ b/backend/groth16/bls12-381/mpcsetup/marshal_test.go @@ -19,7 +19,7 @@ package mpcsetup import ( "bytes" curve "github.com/consensys/gnark-crypto/ecc/bls12-381" - "github.com/consensys/gnark/constraint/bls12-381" + cs "github.com/consensys/gnark/constraint/bls12-381" "github.com/consensys/gnark/frontend" "github.com/consensys/gnark/frontend/cs/r1cs" "github.com/stretchr/testify/require" diff --git a/backend/groth16/bls12-381/mpcsetup/phase2.go b/backend/groth16/bls12-381/mpcsetup/phase2.go index f2cd98bd77..ed42a69f9c 100644 --- a/backend/groth16/bls12-381/mpcsetup/phase2.go +++ b/backend/groth16/bls12-381/mpcsetup/phase2.go @@ -24,7 +24,7 @@ import ( curve "github.com/consensys/gnark-crypto/ecc/bls12-381" "github.com/consensys/gnark-crypto/ecc/bls12-381/fr" "github.com/consensys/gnark/constraint" - "github.com/consensys/gnark/constraint/bls12-381" + cs "github.com/consensys/gnark/constraint/bls12-381" ) type Phase2Evaluations struct { diff --git a/backend/groth16/bls12-381/mpcsetup/setup_test.go b/backend/groth16/bls12-381/mpcsetup/setup_test.go index e801821bea..0e9880b010 100644 --- a/backend/groth16/bls12-381/mpcsetup/setup_test.go +++ b/backend/groth16/bls12-381/mpcsetup/setup_test.go @@ -19,7 +19,7 @@ package mpcsetup import ( curve "github.com/consensys/gnark-crypto/ecc/bls12-381" "github.com/consensys/gnark-crypto/ecc/bls12-381/fr" - "github.com/consensys/gnark/constraint/bls12-381" + cs "github.com/consensys/gnark/constraint/bls12-381" "testing" "github.com/consensys/gnark/backend/groth16" diff --git a/backend/groth16/bls12-381/prove.go b/backend/groth16/bls12-381/prove.go index 23ab3529dc..6e4c0a5227 100644 --- a/backend/groth16/bls12-381/prove.go +++ b/backend/groth16/bls12-381/prove.go @@ -26,7 +26,7 @@ import ( "github.com/consensys/gnark/backend/groth16/internal" "github.com/consensys/gnark/backend/witness" "github.com/consensys/gnark/constraint" - "github.com/consensys/gnark/constraint/bls12-381" + cs "github.com/consensys/gnark/constraint/bls12-381" "github.com/consensys/gnark/constraint/solver" "github.com/consensys/gnark/internal/utils" "github.com/consensys/gnark/logger" @@ -94,6 +94,13 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b }(i))) } + if r1cs.GkrInfo.Is() { + var gkrData cs.GkrSolvingData + solverOpts = append(solverOpts, + solver.OverrideHint(r1cs.GkrInfo.SolveHintID, cs.GkrSolveHint(r1cs.GkrInfo, &gkrData)), + solver.OverrideHint(r1cs.GkrInfo.ProveHintID, cs.GkrProveHint(r1cs.GkrInfo.HashName, &gkrData))) + } + _solution, err := r1cs.Solve(fullWitness, solverOpts...) if err != nil { return nil, err diff --git a/backend/groth16/bls12-381/setup.go b/backend/groth16/bls12-381/setup.go index d1ca2e9b2d..b5333ba374 100644 --- a/backend/groth16/bls12-381/setup.go +++ b/backend/groth16/bls12-381/setup.go @@ -25,7 +25,7 @@ import ( "github.com/consensys/gnark-crypto/ecc/bls12-381/fr/pedersen" "github.com/consensys/gnark/backend/groth16/internal" "github.com/consensys/gnark/constraint" - "github.com/consensys/gnark/constraint/bls12-381" + cs "github.com/consensys/gnark/constraint/bls12-381" "math/big" "math/bits" ) diff --git a/backend/groth16/bls24-315/mpcsetup/marshal_test.go b/backend/groth16/bls24-315/mpcsetup/marshal_test.go index 9ca32105de..02d61df6a9 100644 --- a/backend/groth16/bls24-315/mpcsetup/marshal_test.go +++ b/backend/groth16/bls24-315/mpcsetup/marshal_test.go @@ -19,7 +19,7 @@ package mpcsetup import ( "bytes" curve "github.com/consensys/gnark-crypto/ecc/bls24-315" - "github.com/consensys/gnark/constraint/bls24-315" + cs "github.com/consensys/gnark/constraint/bls24-315" "github.com/consensys/gnark/frontend" "github.com/consensys/gnark/frontend/cs/r1cs" "github.com/stretchr/testify/require" diff --git a/backend/groth16/bls24-315/mpcsetup/phase2.go b/backend/groth16/bls24-315/mpcsetup/phase2.go index b85efd3856..48939131d3 100644 --- a/backend/groth16/bls24-315/mpcsetup/phase2.go +++ b/backend/groth16/bls24-315/mpcsetup/phase2.go @@ -24,7 +24,7 @@ import ( curve "github.com/consensys/gnark-crypto/ecc/bls24-315" "github.com/consensys/gnark-crypto/ecc/bls24-315/fr" "github.com/consensys/gnark/constraint" - "github.com/consensys/gnark/constraint/bls24-315" + cs "github.com/consensys/gnark/constraint/bls24-315" ) type Phase2Evaluations struct { diff --git a/backend/groth16/bls24-315/mpcsetup/setup_test.go b/backend/groth16/bls24-315/mpcsetup/setup_test.go index c640467623..25c8affc68 100644 --- a/backend/groth16/bls24-315/mpcsetup/setup_test.go +++ b/backend/groth16/bls24-315/mpcsetup/setup_test.go @@ -19,7 +19,7 @@ package mpcsetup import ( curve "github.com/consensys/gnark-crypto/ecc/bls24-315" "github.com/consensys/gnark-crypto/ecc/bls24-315/fr" - "github.com/consensys/gnark/constraint/bls24-315" + cs "github.com/consensys/gnark/constraint/bls24-315" "testing" "github.com/consensys/gnark/backend/groth16" diff --git a/backend/groth16/bls24-315/prove.go b/backend/groth16/bls24-315/prove.go index 0b0774af00..c464544ad0 100644 --- a/backend/groth16/bls24-315/prove.go +++ b/backend/groth16/bls24-315/prove.go @@ -26,7 +26,7 @@ import ( "github.com/consensys/gnark/backend/groth16/internal" "github.com/consensys/gnark/backend/witness" "github.com/consensys/gnark/constraint" - "github.com/consensys/gnark/constraint/bls24-315" + cs "github.com/consensys/gnark/constraint/bls24-315" "github.com/consensys/gnark/constraint/solver" "github.com/consensys/gnark/internal/utils" "github.com/consensys/gnark/logger" @@ -94,6 +94,13 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b }(i))) } + if r1cs.GkrInfo.Is() { + var gkrData cs.GkrSolvingData + solverOpts = append(solverOpts, + solver.OverrideHint(r1cs.GkrInfo.SolveHintID, cs.GkrSolveHint(r1cs.GkrInfo, &gkrData)), + solver.OverrideHint(r1cs.GkrInfo.ProveHintID, cs.GkrProveHint(r1cs.GkrInfo.HashName, &gkrData))) + } + _solution, err := r1cs.Solve(fullWitness, solverOpts...) if err != nil { return nil, err diff --git a/backend/groth16/bls24-315/setup.go b/backend/groth16/bls24-315/setup.go index a37ce828cd..6a8c8e60d2 100644 --- a/backend/groth16/bls24-315/setup.go +++ b/backend/groth16/bls24-315/setup.go @@ -25,7 +25,7 @@ import ( "github.com/consensys/gnark-crypto/ecc/bls24-315/fr/pedersen" "github.com/consensys/gnark/backend/groth16/internal" "github.com/consensys/gnark/constraint" - "github.com/consensys/gnark/constraint/bls24-315" + cs "github.com/consensys/gnark/constraint/bls24-315" "math/big" "math/bits" ) diff --git a/backend/groth16/bls24-317/mpcsetup/marshal_test.go b/backend/groth16/bls24-317/mpcsetup/marshal_test.go index 6fc34b923c..ddc7229489 100644 --- a/backend/groth16/bls24-317/mpcsetup/marshal_test.go +++ b/backend/groth16/bls24-317/mpcsetup/marshal_test.go @@ -19,7 +19,7 @@ package mpcsetup import ( "bytes" curve "github.com/consensys/gnark-crypto/ecc/bls24-317" - "github.com/consensys/gnark/constraint/bls24-317" + cs "github.com/consensys/gnark/constraint/bls24-317" "github.com/consensys/gnark/frontend" "github.com/consensys/gnark/frontend/cs/r1cs" "github.com/stretchr/testify/require" diff --git a/backend/groth16/bls24-317/mpcsetup/phase2.go b/backend/groth16/bls24-317/mpcsetup/phase2.go index cac7bc08eb..d3037cc3d3 100644 --- a/backend/groth16/bls24-317/mpcsetup/phase2.go +++ b/backend/groth16/bls24-317/mpcsetup/phase2.go @@ -24,7 +24,7 @@ import ( curve "github.com/consensys/gnark-crypto/ecc/bls24-317" "github.com/consensys/gnark-crypto/ecc/bls24-317/fr" "github.com/consensys/gnark/constraint" - "github.com/consensys/gnark/constraint/bls24-317" + cs "github.com/consensys/gnark/constraint/bls24-317" ) type Phase2Evaluations struct { diff --git a/backend/groth16/bls24-317/mpcsetup/setup_test.go b/backend/groth16/bls24-317/mpcsetup/setup_test.go index 8332441b27..750ab1e0cf 100644 --- a/backend/groth16/bls24-317/mpcsetup/setup_test.go +++ b/backend/groth16/bls24-317/mpcsetup/setup_test.go @@ -19,7 +19,7 @@ package mpcsetup import ( curve "github.com/consensys/gnark-crypto/ecc/bls24-317" "github.com/consensys/gnark-crypto/ecc/bls24-317/fr" - "github.com/consensys/gnark/constraint/bls24-317" + cs "github.com/consensys/gnark/constraint/bls24-317" "testing" "github.com/consensys/gnark/backend/groth16" diff --git a/backend/groth16/bls24-317/prove.go b/backend/groth16/bls24-317/prove.go index 72f08ac910..10f38c5f77 100644 --- a/backend/groth16/bls24-317/prove.go +++ b/backend/groth16/bls24-317/prove.go @@ -26,7 +26,7 @@ import ( "github.com/consensys/gnark/backend/groth16/internal" "github.com/consensys/gnark/backend/witness" "github.com/consensys/gnark/constraint" - "github.com/consensys/gnark/constraint/bls24-317" + cs "github.com/consensys/gnark/constraint/bls24-317" "github.com/consensys/gnark/constraint/solver" "github.com/consensys/gnark/internal/utils" "github.com/consensys/gnark/logger" @@ -94,6 +94,13 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b }(i))) } + if r1cs.GkrInfo.Is() { + var gkrData cs.GkrSolvingData + solverOpts = append(solverOpts, + solver.OverrideHint(r1cs.GkrInfo.SolveHintID, cs.GkrSolveHint(r1cs.GkrInfo, &gkrData)), + solver.OverrideHint(r1cs.GkrInfo.ProveHintID, cs.GkrProveHint(r1cs.GkrInfo.HashName, &gkrData))) + } + _solution, err := r1cs.Solve(fullWitness, solverOpts...) if err != nil { return nil, err diff --git a/backend/groth16/bls24-317/setup.go b/backend/groth16/bls24-317/setup.go index 04156ae8bd..68ee5c8922 100644 --- a/backend/groth16/bls24-317/setup.go +++ b/backend/groth16/bls24-317/setup.go @@ -25,7 +25,7 @@ import ( "github.com/consensys/gnark-crypto/ecc/bls24-317/fr/pedersen" "github.com/consensys/gnark/backend/groth16/internal" "github.com/consensys/gnark/constraint" - "github.com/consensys/gnark/constraint/bls24-317" + cs "github.com/consensys/gnark/constraint/bls24-317" "math/big" "math/bits" ) diff --git a/backend/groth16/bn254/mpcsetup/marshal_test.go b/backend/groth16/bn254/mpcsetup/marshal_test.go index b56e2bfdce..ce03c11bd4 100644 --- a/backend/groth16/bn254/mpcsetup/marshal_test.go +++ b/backend/groth16/bn254/mpcsetup/marshal_test.go @@ -19,7 +19,7 @@ package mpcsetup import ( "bytes" curve "github.com/consensys/gnark-crypto/ecc/bn254" - "github.com/consensys/gnark/constraint/bn254" + cs "github.com/consensys/gnark/constraint/bn254" "github.com/consensys/gnark/frontend" "github.com/consensys/gnark/frontend/cs/r1cs" "github.com/stretchr/testify/require" diff --git a/backend/groth16/bn254/mpcsetup/phase2.go b/backend/groth16/bn254/mpcsetup/phase2.go index c14e14b509..3fcafb30da 100644 --- a/backend/groth16/bn254/mpcsetup/phase2.go +++ b/backend/groth16/bn254/mpcsetup/phase2.go @@ -24,7 +24,7 @@ import ( curve "github.com/consensys/gnark-crypto/ecc/bn254" "github.com/consensys/gnark-crypto/ecc/bn254/fr" "github.com/consensys/gnark/constraint" - "github.com/consensys/gnark/constraint/bn254" + cs "github.com/consensys/gnark/constraint/bn254" ) type Phase2Evaluations struct { diff --git a/backend/groth16/bn254/mpcsetup/setup_test.go b/backend/groth16/bn254/mpcsetup/setup_test.go index e6644c664d..63b717cac4 100644 --- a/backend/groth16/bn254/mpcsetup/setup_test.go +++ b/backend/groth16/bn254/mpcsetup/setup_test.go @@ -19,7 +19,7 @@ package mpcsetup import ( curve "github.com/consensys/gnark-crypto/ecc/bn254" "github.com/consensys/gnark-crypto/ecc/bn254/fr" - "github.com/consensys/gnark/constraint/bn254" + cs "github.com/consensys/gnark/constraint/bn254" "testing" "github.com/consensys/gnark/backend/groth16" diff --git a/backend/groth16/bn254/setup.go b/backend/groth16/bn254/setup.go index d6eaf37793..372c723da0 100644 --- a/backend/groth16/bn254/setup.go +++ b/backend/groth16/bn254/setup.go @@ -25,7 +25,7 @@ import ( "github.com/consensys/gnark-crypto/ecc/bn254/fr/pedersen" "github.com/consensys/gnark/backend/groth16/internal" "github.com/consensys/gnark/constraint" - "github.com/consensys/gnark/constraint/bn254" + cs "github.com/consensys/gnark/constraint/bn254" "math/big" "math/bits" ) diff --git a/backend/groth16/bw6-633/mpcsetup/marshal_test.go b/backend/groth16/bw6-633/mpcsetup/marshal_test.go index 0c04d15934..b9d346f3bd 100644 --- a/backend/groth16/bw6-633/mpcsetup/marshal_test.go +++ b/backend/groth16/bw6-633/mpcsetup/marshal_test.go @@ -19,7 +19,7 @@ package mpcsetup import ( "bytes" curve "github.com/consensys/gnark-crypto/ecc/bw6-633" - "github.com/consensys/gnark/constraint/bw6-633" + cs "github.com/consensys/gnark/constraint/bw6-633" "github.com/consensys/gnark/frontend" "github.com/consensys/gnark/frontend/cs/r1cs" "github.com/stretchr/testify/require" diff --git a/backend/groth16/bw6-633/mpcsetup/phase2.go b/backend/groth16/bw6-633/mpcsetup/phase2.go index e966fd021a..cdf0bb7578 100644 --- a/backend/groth16/bw6-633/mpcsetup/phase2.go +++ b/backend/groth16/bw6-633/mpcsetup/phase2.go @@ -24,7 +24,7 @@ import ( curve "github.com/consensys/gnark-crypto/ecc/bw6-633" "github.com/consensys/gnark-crypto/ecc/bw6-633/fr" "github.com/consensys/gnark/constraint" - "github.com/consensys/gnark/constraint/bw6-633" + cs "github.com/consensys/gnark/constraint/bw6-633" ) type Phase2Evaluations struct { diff --git a/backend/groth16/bw6-633/mpcsetup/setup_test.go b/backend/groth16/bw6-633/mpcsetup/setup_test.go index 6933f11050..fa51d16fe2 100644 --- a/backend/groth16/bw6-633/mpcsetup/setup_test.go +++ b/backend/groth16/bw6-633/mpcsetup/setup_test.go @@ -19,7 +19,7 @@ package mpcsetup import ( curve "github.com/consensys/gnark-crypto/ecc/bw6-633" "github.com/consensys/gnark-crypto/ecc/bw6-633/fr" - "github.com/consensys/gnark/constraint/bw6-633" + cs "github.com/consensys/gnark/constraint/bw6-633" "testing" "github.com/consensys/gnark/backend/groth16" diff --git a/backend/groth16/bw6-633/prove.go b/backend/groth16/bw6-633/prove.go index 41002c3f48..b92dbb6943 100644 --- a/backend/groth16/bw6-633/prove.go +++ b/backend/groth16/bw6-633/prove.go @@ -26,7 +26,7 @@ import ( "github.com/consensys/gnark/backend/groth16/internal" "github.com/consensys/gnark/backend/witness" "github.com/consensys/gnark/constraint" - "github.com/consensys/gnark/constraint/bw6-633" + cs "github.com/consensys/gnark/constraint/bw6-633" "github.com/consensys/gnark/constraint/solver" "github.com/consensys/gnark/internal/utils" "github.com/consensys/gnark/logger" @@ -94,6 +94,13 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b }(i))) } + if r1cs.GkrInfo.Is() { + var gkrData cs.GkrSolvingData + solverOpts = append(solverOpts, + solver.OverrideHint(r1cs.GkrInfo.SolveHintID, cs.GkrSolveHint(r1cs.GkrInfo, &gkrData)), + solver.OverrideHint(r1cs.GkrInfo.ProveHintID, cs.GkrProveHint(r1cs.GkrInfo.HashName, &gkrData))) + } + _solution, err := r1cs.Solve(fullWitness, solverOpts...) if err != nil { return nil, err diff --git a/backend/groth16/bw6-633/setup.go b/backend/groth16/bw6-633/setup.go index 92c73871b7..f168993476 100644 --- a/backend/groth16/bw6-633/setup.go +++ b/backend/groth16/bw6-633/setup.go @@ -25,7 +25,7 @@ import ( "github.com/consensys/gnark-crypto/ecc/bw6-633/fr/pedersen" "github.com/consensys/gnark/backend/groth16/internal" "github.com/consensys/gnark/constraint" - "github.com/consensys/gnark/constraint/bw6-633" + cs "github.com/consensys/gnark/constraint/bw6-633" "math/big" "math/bits" ) diff --git a/backend/groth16/bw6-761/mpcsetup/marshal_test.go b/backend/groth16/bw6-761/mpcsetup/marshal_test.go index 46913c86b5..cdb362ab70 100644 --- a/backend/groth16/bw6-761/mpcsetup/marshal_test.go +++ b/backend/groth16/bw6-761/mpcsetup/marshal_test.go @@ -19,7 +19,7 @@ package mpcsetup import ( "bytes" curve "github.com/consensys/gnark-crypto/ecc/bw6-761" - "github.com/consensys/gnark/constraint/bw6-761" + cs "github.com/consensys/gnark/constraint/bw6-761" "github.com/consensys/gnark/frontend" "github.com/consensys/gnark/frontend/cs/r1cs" "github.com/stretchr/testify/require" diff --git a/backend/groth16/bw6-761/mpcsetup/phase2.go b/backend/groth16/bw6-761/mpcsetup/phase2.go index df2d2d5be9..cb0c6f9768 100644 --- a/backend/groth16/bw6-761/mpcsetup/phase2.go +++ b/backend/groth16/bw6-761/mpcsetup/phase2.go @@ -24,7 +24,7 @@ import ( curve "github.com/consensys/gnark-crypto/ecc/bw6-761" "github.com/consensys/gnark-crypto/ecc/bw6-761/fr" "github.com/consensys/gnark/constraint" - "github.com/consensys/gnark/constraint/bw6-761" + cs "github.com/consensys/gnark/constraint/bw6-761" ) type Phase2Evaluations struct { diff --git a/backend/groth16/bw6-761/mpcsetup/setup_test.go b/backend/groth16/bw6-761/mpcsetup/setup_test.go index 28e4c7a768..83994ca73d 100644 --- a/backend/groth16/bw6-761/mpcsetup/setup_test.go +++ b/backend/groth16/bw6-761/mpcsetup/setup_test.go @@ -19,7 +19,7 @@ package mpcsetup import ( curve "github.com/consensys/gnark-crypto/ecc/bw6-761" "github.com/consensys/gnark-crypto/ecc/bw6-761/fr" - "github.com/consensys/gnark/constraint/bw6-761" + cs "github.com/consensys/gnark/constraint/bw6-761" "testing" "github.com/consensys/gnark/backend/groth16" diff --git a/backend/groth16/bw6-761/prove.go b/backend/groth16/bw6-761/prove.go index 7234bf7d15..3ee6b9ad0f 100644 --- a/backend/groth16/bw6-761/prove.go +++ b/backend/groth16/bw6-761/prove.go @@ -26,7 +26,7 @@ import ( "github.com/consensys/gnark/backend/groth16/internal" "github.com/consensys/gnark/backend/witness" "github.com/consensys/gnark/constraint" - "github.com/consensys/gnark/constraint/bw6-761" + cs "github.com/consensys/gnark/constraint/bw6-761" "github.com/consensys/gnark/constraint/solver" "github.com/consensys/gnark/internal/utils" "github.com/consensys/gnark/logger" @@ -94,6 +94,13 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b }(i))) } + if r1cs.GkrInfo.Is() { + var gkrData cs.GkrSolvingData + solverOpts = append(solverOpts, + solver.OverrideHint(r1cs.GkrInfo.SolveHintID, cs.GkrSolveHint(r1cs.GkrInfo, &gkrData)), + solver.OverrideHint(r1cs.GkrInfo.ProveHintID, cs.GkrProveHint(r1cs.GkrInfo.HashName, &gkrData))) + } + _solution, err := r1cs.Solve(fullWitness, solverOpts...) if err != nil { return nil, err diff --git a/backend/groth16/bw6-761/setup.go b/backend/groth16/bw6-761/setup.go index 5a69e9799a..b0fa2811e6 100644 --- a/backend/groth16/bw6-761/setup.go +++ b/backend/groth16/bw6-761/setup.go @@ -25,7 +25,7 @@ import ( "github.com/consensys/gnark-crypto/ecc/bw6-761/fr/pedersen" "github.com/consensys/gnark/backend/groth16/internal" "github.com/consensys/gnark/constraint" - "github.com/consensys/gnark/constraint/bw6-761" + cs "github.com/consensys/gnark/constraint/bw6-761" "math/big" "math/bits" ) diff --git a/backend/plonk/bls12-377/prove.go b/backend/plonk/bls12-377/prove.go index 43e999fd87..b2d3804587 100644 --- a/backend/plonk/bls12-377/prove.go +++ b/backend/plonk/bls12-377/prove.go @@ -34,7 +34,7 @@ import ( "github.com/consensys/gnark-crypto/ecc/bls12-377/fr/fft" "github.com/consensys/gnark-crypto/ecc/bls12-377/fr/iop" - "github.com/consensys/gnark/constraint/bls12-377" + cs "github.com/consensys/gnark/constraint/bls12-377" "github.com/consensys/gnark-crypto/fiat-shamir" "github.com/consensys/gnark/backend" diff --git a/backend/plonk/bls12-377/setup.go b/backend/plonk/bls12-377/setup.go index 20d21a0d29..273fbd2239 100644 --- a/backend/plonk/bls12-377/setup.go +++ b/backend/plonk/bls12-377/setup.go @@ -25,7 +25,7 @@ import ( "github.com/consensys/gnark-crypto/ecc/bls12-377/fr/kzg" "github.com/consensys/gnark/backend/plonk/internal" "github.com/consensys/gnark/constraint" - "github.com/consensys/gnark/constraint/bls12-377" + cs "github.com/consensys/gnark/constraint/bls12-377" ) // Trace stores a plonk trace as columns diff --git a/backend/plonk/bls12-381/prove.go b/backend/plonk/bls12-381/prove.go index 4397656393..04af58ed95 100644 --- a/backend/plonk/bls12-381/prove.go +++ b/backend/plonk/bls12-381/prove.go @@ -34,7 +34,7 @@ import ( "github.com/consensys/gnark-crypto/ecc/bls12-381/fr/fft" "github.com/consensys/gnark-crypto/ecc/bls12-381/fr/iop" - "github.com/consensys/gnark/constraint/bls12-381" + cs "github.com/consensys/gnark/constraint/bls12-381" "github.com/consensys/gnark-crypto/fiat-shamir" "github.com/consensys/gnark/backend" diff --git a/backend/plonk/bls12-381/setup.go b/backend/plonk/bls12-381/setup.go index b3f00a335b..bc5a5efe22 100644 --- a/backend/plonk/bls12-381/setup.go +++ b/backend/plonk/bls12-381/setup.go @@ -25,7 +25,7 @@ import ( "github.com/consensys/gnark-crypto/ecc/bls12-381/fr/kzg" "github.com/consensys/gnark/backend/plonk/internal" "github.com/consensys/gnark/constraint" - "github.com/consensys/gnark/constraint/bls12-381" + cs "github.com/consensys/gnark/constraint/bls12-381" ) // Trace stores a plonk trace as columns diff --git a/backend/plonk/bls24-315/prove.go b/backend/plonk/bls24-315/prove.go index 777bd2b8e1..650e71714c 100644 --- a/backend/plonk/bls24-315/prove.go +++ b/backend/plonk/bls24-315/prove.go @@ -34,7 +34,7 @@ import ( "github.com/consensys/gnark-crypto/ecc/bls24-315/fr/fft" "github.com/consensys/gnark-crypto/ecc/bls24-315/fr/iop" - "github.com/consensys/gnark/constraint/bls24-315" + cs "github.com/consensys/gnark/constraint/bls24-315" "github.com/consensys/gnark-crypto/fiat-shamir" "github.com/consensys/gnark/backend" diff --git a/backend/plonk/bls24-315/setup.go b/backend/plonk/bls24-315/setup.go index 41fd1ee0a3..f7d674ed66 100644 --- a/backend/plonk/bls24-315/setup.go +++ b/backend/plonk/bls24-315/setup.go @@ -25,7 +25,7 @@ import ( "github.com/consensys/gnark-crypto/ecc/bls24-315/fr/kzg" "github.com/consensys/gnark/backend/plonk/internal" "github.com/consensys/gnark/constraint" - "github.com/consensys/gnark/constraint/bls24-315" + cs "github.com/consensys/gnark/constraint/bls24-315" ) // Trace stores a plonk trace as columns diff --git a/backend/plonk/bls24-317/prove.go b/backend/plonk/bls24-317/prove.go index ae3d6a28dd..01eebfb5d6 100644 --- a/backend/plonk/bls24-317/prove.go +++ b/backend/plonk/bls24-317/prove.go @@ -34,7 +34,7 @@ import ( "github.com/consensys/gnark-crypto/ecc/bls24-317/fr/fft" "github.com/consensys/gnark-crypto/ecc/bls24-317/fr/iop" - "github.com/consensys/gnark/constraint/bls24-317" + cs "github.com/consensys/gnark/constraint/bls24-317" "github.com/consensys/gnark-crypto/fiat-shamir" "github.com/consensys/gnark/backend" diff --git a/backend/plonk/bls24-317/setup.go b/backend/plonk/bls24-317/setup.go index de56d191cd..77b2e5ac05 100644 --- a/backend/plonk/bls24-317/setup.go +++ b/backend/plonk/bls24-317/setup.go @@ -25,7 +25,7 @@ import ( "github.com/consensys/gnark-crypto/ecc/bls24-317/fr/kzg" "github.com/consensys/gnark/backend/plonk/internal" "github.com/consensys/gnark/constraint" - "github.com/consensys/gnark/constraint/bls24-317" + cs "github.com/consensys/gnark/constraint/bls24-317" ) // Trace stores a plonk trace as columns diff --git a/backend/plonk/bn254/prove.go b/backend/plonk/bn254/prove.go index 70baf95687..6058692704 100644 --- a/backend/plonk/bn254/prove.go +++ b/backend/plonk/bn254/prove.go @@ -34,7 +34,7 @@ import ( "github.com/consensys/gnark-crypto/ecc/bn254/fr/fft" "github.com/consensys/gnark-crypto/ecc/bn254/fr/iop" - "github.com/consensys/gnark/constraint/bn254" + cs "github.com/consensys/gnark/constraint/bn254" "github.com/consensys/gnark-crypto/fiat-shamir" "github.com/consensys/gnark/backend" diff --git a/backend/plonk/bn254/setup.go b/backend/plonk/bn254/setup.go index a4e65bce21..66b387dc80 100644 --- a/backend/plonk/bn254/setup.go +++ b/backend/plonk/bn254/setup.go @@ -25,7 +25,7 @@ import ( "github.com/consensys/gnark-crypto/ecc/bn254/fr/kzg" "github.com/consensys/gnark/backend/plonk/internal" "github.com/consensys/gnark/constraint" - "github.com/consensys/gnark/constraint/bn254" + cs "github.com/consensys/gnark/constraint/bn254" ) // Trace stores a plonk trace as columns diff --git a/backend/plonk/bw6-633/prove.go b/backend/plonk/bw6-633/prove.go index f5ffbaba57..abfc80c1ad 100644 --- a/backend/plonk/bw6-633/prove.go +++ b/backend/plonk/bw6-633/prove.go @@ -34,7 +34,7 @@ import ( "github.com/consensys/gnark-crypto/ecc/bw6-633/fr/fft" "github.com/consensys/gnark-crypto/ecc/bw6-633/fr/iop" - "github.com/consensys/gnark/constraint/bw6-633" + cs "github.com/consensys/gnark/constraint/bw6-633" "github.com/consensys/gnark-crypto/fiat-shamir" "github.com/consensys/gnark/backend" diff --git a/backend/plonk/bw6-633/setup.go b/backend/plonk/bw6-633/setup.go index 9848de6fa7..4d68ed0018 100644 --- a/backend/plonk/bw6-633/setup.go +++ b/backend/plonk/bw6-633/setup.go @@ -25,7 +25,7 @@ import ( "github.com/consensys/gnark-crypto/ecc/bw6-633/fr/kzg" "github.com/consensys/gnark/backend/plonk/internal" "github.com/consensys/gnark/constraint" - "github.com/consensys/gnark/constraint/bw6-633" + cs "github.com/consensys/gnark/constraint/bw6-633" ) // Trace stores a plonk trace as columns diff --git a/backend/plonk/bw6-761/prove.go b/backend/plonk/bw6-761/prove.go index 54a179a33b..1aba64a32e 100644 --- a/backend/plonk/bw6-761/prove.go +++ b/backend/plonk/bw6-761/prove.go @@ -34,7 +34,7 @@ import ( "github.com/consensys/gnark-crypto/ecc/bw6-761/fr/fft" "github.com/consensys/gnark-crypto/ecc/bw6-761/fr/iop" - "github.com/consensys/gnark/constraint/bw6-761" + cs "github.com/consensys/gnark/constraint/bw6-761" "github.com/consensys/gnark-crypto/fiat-shamir" "github.com/consensys/gnark/backend" diff --git a/backend/plonk/bw6-761/setup.go b/backend/plonk/bw6-761/setup.go index f15643bf7b..75751f7929 100644 --- a/backend/plonk/bw6-761/setup.go +++ b/backend/plonk/bw6-761/setup.go @@ -25,7 +25,7 @@ import ( "github.com/consensys/gnark-crypto/ecc/bw6-761/fr/kzg" "github.com/consensys/gnark/backend/plonk/internal" "github.com/consensys/gnark/constraint" - "github.com/consensys/gnark/constraint/bw6-761" + cs "github.com/consensys/gnark/constraint/bw6-761" ) // Trace stores a plonk trace as columns diff --git a/backend/plonkfri/bls12-377/prove.go b/backend/plonkfri/bls12-377/prove.go index a525c90cb5..97d6c0301e 100644 --- a/backend/plonkfri/bls12-377/prove.go +++ b/backend/plonkfri/bls12-377/prove.go @@ -28,7 +28,7 @@ import ( "github.com/consensys/gnark-crypto/ecc/bls12-377/fr/fft" - "github.com/consensys/gnark/constraint/bls12-377" + cs "github.com/consensys/gnark/constraint/bls12-377" "github.com/consensys/gnark-crypto/ecc/bls12-377/fr/fri" diff --git a/backend/plonkfri/bls12-377/setup.go b/backend/plonkfri/bls12-377/setup.go index 2168bbeeab..f4e5ad6daf 100644 --- a/backend/plonkfri/bls12-377/setup.go +++ b/backend/plonkfri/bls12-377/setup.go @@ -21,7 +21,7 @@ import ( "github.com/consensys/gnark-crypto/ecc/bls12-377/fr" "github.com/consensys/gnark-crypto/ecc/bls12-377/fr/fft" "github.com/consensys/gnark-crypto/ecc/bls12-377/fr/fri" - "github.com/consensys/gnark/constraint/bls12-377" + cs "github.com/consensys/gnark/constraint/bls12-377" ) // ProvingKey stores the data needed to generate a proof: diff --git a/backend/plonkfri/bls12-381/prove.go b/backend/plonkfri/bls12-381/prove.go index 3823ed3b26..d121b59a37 100644 --- a/backend/plonkfri/bls12-381/prove.go +++ b/backend/plonkfri/bls12-381/prove.go @@ -28,7 +28,7 @@ import ( "github.com/consensys/gnark-crypto/ecc/bls12-381/fr/fft" - "github.com/consensys/gnark/constraint/bls12-381" + cs "github.com/consensys/gnark/constraint/bls12-381" "github.com/consensys/gnark-crypto/ecc/bls12-381/fr/fri" diff --git a/backend/plonkfri/bls12-381/setup.go b/backend/plonkfri/bls12-381/setup.go index 4f2b6e1b20..11f574f5f2 100644 --- a/backend/plonkfri/bls12-381/setup.go +++ b/backend/plonkfri/bls12-381/setup.go @@ -21,7 +21,7 @@ import ( "github.com/consensys/gnark-crypto/ecc/bls12-381/fr" "github.com/consensys/gnark-crypto/ecc/bls12-381/fr/fft" "github.com/consensys/gnark-crypto/ecc/bls12-381/fr/fri" - "github.com/consensys/gnark/constraint/bls12-381" + cs "github.com/consensys/gnark/constraint/bls12-381" ) // ProvingKey stores the data needed to generate a proof: diff --git a/backend/plonkfri/bls24-315/prove.go b/backend/plonkfri/bls24-315/prove.go index 5d7f385ea1..cb1f43fcee 100644 --- a/backend/plonkfri/bls24-315/prove.go +++ b/backend/plonkfri/bls24-315/prove.go @@ -28,7 +28,7 @@ import ( "github.com/consensys/gnark-crypto/ecc/bls24-315/fr/fft" - "github.com/consensys/gnark/constraint/bls24-315" + cs "github.com/consensys/gnark/constraint/bls24-315" "github.com/consensys/gnark-crypto/ecc/bls24-315/fr/fri" diff --git a/backend/plonkfri/bls24-315/setup.go b/backend/plonkfri/bls24-315/setup.go index 9063dc95d9..c3c0837f90 100644 --- a/backend/plonkfri/bls24-315/setup.go +++ b/backend/plonkfri/bls24-315/setup.go @@ -21,7 +21,7 @@ import ( "github.com/consensys/gnark-crypto/ecc/bls24-315/fr" "github.com/consensys/gnark-crypto/ecc/bls24-315/fr/fft" "github.com/consensys/gnark-crypto/ecc/bls24-315/fr/fri" - "github.com/consensys/gnark/constraint/bls24-315" + cs "github.com/consensys/gnark/constraint/bls24-315" ) // ProvingKey stores the data needed to generate a proof: diff --git a/backend/plonkfri/bls24-317/prove.go b/backend/plonkfri/bls24-317/prove.go index 409d66b34e..5fc6cbf713 100644 --- a/backend/plonkfri/bls24-317/prove.go +++ b/backend/plonkfri/bls24-317/prove.go @@ -28,7 +28,7 @@ import ( "github.com/consensys/gnark-crypto/ecc/bls24-317/fr/fft" - "github.com/consensys/gnark/constraint/bls24-317" + cs "github.com/consensys/gnark/constraint/bls24-317" "github.com/consensys/gnark-crypto/ecc/bls24-317/fr/fri" diff --git a/backend/plonkfri/bls24-317/setup.go b/backend/plonkfri/bls24-317/setup.go index c2ab7ee5be..54668b98f8 100644 --- a/backend/plonkfri/bls24-317/setup.go +++ b/backend/plonkfri/bls24-317/setup.go @@ -21,7 +21,7 @@ import ( "github.com/consensys/gnark-crypto/ecc/bls24-317/fr" "github.com/consensys/gnark-crypto/ecc/bls24-317/fr/fft" "github.com/consensys/gnark-crypto/ecc/bls24-317/fr/fri" - "github.com/consensys/gnark/constraint/bls24-317" + cs "github.com/consensys/gnark/constraint/bls24-317" ) // ProvingKey stores the data needed to generate a proof: diff --git a/backend/plonkfri/bn254/prove.go b/backend/plonkfri/bn254/prove.go index 1cb0e6fbc6..161ad667f4 100644 --- a/backend/plonkfri/bn254/prove.go +++ b/backend/plonkfri/bn254/prove.go @@ -28,7 +28,7 @@ import ( "github.com/consensys/gnark-crypto/ecc/bn254/fr/fft" - "github.com/consensys/gnark/constraint/bn254" + cs "github.com/consensys/gnark/constraint/bn254" "github.com/consensys/gnark-crypto/ecc/bn254/fr/fri" diff --git a/backend/plonkfri/bn254/setup.go b/backend/plonkfri/bn254/setup.go index 6b37f37600..9f69648ed1 100644 --- a/backend/plonkfri/bn254/setup.go +++ b/backend/plonkfri/bn254/setup.go @@ -21,7 +21,7 @@ import ( "github.com/consensys/gnark-crypto/ecc/bn254/fr" "github.com/consensys/gnark-crypto/ecc/bn254/fr/fft" "github.com/consensys/gnark-crypto/ecc/bn254/fr/fri" - "github.com/consensys/gnark/constraint/bn254" + cs "github.com/consensys/gnark/constraint/bn254" ) // ProvingKey stores the data needed to generate a proof: diff --git a/backend/plonkfri/bw6-633/prove.go b/backend/plonkfri/bw6-633/prove.go index 3e9d8e8ef4..e71df6e7aa 100644 --- a/backend/plonkfri/bw6-633/prove.go +++ b/backend/plonkfri/bw6-633/prove.go @@ -28,7 +28,7 @@ import ( "github.com/consensys/gnark-crypto/ecc/bw6-633/fr/fft" - "github.com/consensys/gnark/constraint/bw6-633" + cs "github.com/consensys/gnark/constraint/bw6-633" "github.com/consensys/gnark-crypto/ecc/bw6-633/fr/fri" diff --git a/backend/plonkfri/bw6-633/setup.go b/backend/plonkfri/bw6-633/setup.go index dff84dbee9..1384eed0bd 100644 --- a/backend/plonkfri/bw6-633/setup.go +++ b/backend/plonkfri/bw6-633/setup.go @@ -21,7 +21,7 @@ import ( "github.com/consensys/gnark-crypto/ecc/bw6-633/fr" "github.com/consensys/gnark-crypto/ecc/bw6-633/fr/fft" "github.com/consensys/gnark-crypto/ecc/bw6-633/fr/fri" - "github.com/consensys/gnark/constraint/bw6-633" + cs "github.com/consensys/gnark/constraint/bw6-633" ) // ProvingKey stores the data needed to generate a proof: diff --git a/backend/plonkfri/bw6-761/prove.go b/backend/plonkfri/bw6-761/prove.go index f57bc4f6d3..9092580485 100644 --- a/backend/plonkfri/bw6-761/prove.go +++ b/backend/plonkfri/bw6-761/prove.go @@ -28,7 +28,7 @@ import ( "github.com/consensys/gnark-crypto/ecc/bw6-761/fr/fft" - "github.com/consensys/gnark/constraint/bw6-761" + cs "github.com/consensys/gnark/constraint/bw6-761" "github.com/consensys/gnark-crypto/ecc/bw6-761/fr/fri" diff --git a/backend/plonkfri/bw6-761/setup.go b/backend/plonkfri/bw6-761/setup.go index ee278a5eda..a08a528d80 100644 --- a/backend/plonkfri/bw6-761/setup.go +++ b/backend/plonkfri/bw6-761/setup.go @@ -21,7 +21,7 @@ import ( "github.com/consensys/gnark-crypto/ecc/bw6-761/fr" "github.com/consensys/gnark-crypto/ecc/bw6-761/fr/fft" "github.com/consensys/gnark-crypto/ecc/bw6-761/fr/fri" - "github.com/consensys/gnark/constraint/bw6-761" + cs "github.com/consensys/gnark/constraint/bw6-761" ) // ProvingKey stores the data needed to generate a proof: diff --git a/constraint/bls12-377/gkr.go b/constraint/bls12-377/gkr.go index 1e1becb91b..31dc279700 100644 --- a/constraint/bls12-377/gkr.go +++ b/constraint/bls12-377/gkr.go @@ -29,7 +29,7 @@ import ( "math/big" ) -type gkrSolvingData struct { +type GkrSolvingData struct { assignments gkr.WireAssignment circuit gkr.Circuit memoryPool polynomial.Pool @@ -45,7 +45,7 @@ func convertCircuit(noPtr constraint.GkrCircuit) gkr.Circuit { return resCircuit } -func (d *gkrSolvingData) init(info constraint.GkrInfo) gkrAssignment { +func (d *GkrSolvingData) init(info constraint.GkrInfo) gkrAssignment { d.circuit = convertCircuit(info.Circuit) d.memoryPool = polynomial.NewPool(d.circuit.MemoryRequirements(info.NbInstances)...) d.workers = utils.NewWorkerPool() @@ -60,7 +60,7 @@ func (d *gkrSolvingData) init(info constraint.GkrInfo) gkrAssignment { return assignmentsSequential } -func (d *gkrSolvingData) dumpAssignments() { +func (d *GkrSolvingData) dumpAssignments() { for _, p := range d.assignments { d.memoryPool.Dump(p) } @@ -83,7 +83,7 @@ func (a gkrAssignment) setOuts(circuit constraint.GkrCircuit, outs []*big.Int) { // Check if outsI == len(outs)? } -func gkrSolveHint(info constraint.GkrInfo, solvingData *gkrSolvingData) hint.Hint { +func GkrSolveHint(info constraint.GkrInfo, solvingData *GkrSolvingData) hint.Hint { return func(_ *big.Int, ins, outs []*big.Int) error { // assumes assignmentVector is arranged wire first, instance second in order of solution circuit := info.Circuit @@ -147,7 +147,7 @@ func frToBigInts(dst []*big.Int, src []fr.Element) { } } -func gkrProveHint(hashName string, data *gkrSolvingData) hint.Hint { +func GkrProveHint(hashName string, data *GkrSolvingData) hint.Hint { return func(_ *big.Int, ins, outs []*big.Int) error { insBytes := algo_utils.Map(ins[1:], func(i *big.Int) []byte { // the first input is dummy, just to ensure the solver's work is done before the prover is called @@ -183,18 +183,6 @@ func gkrProveHint(hashName string, data *gkrSolvingData) hint.Hint { } } -func defineGkrHints(info constraint.GkrInfo, hintFunctions map[hint.HintID]hint.Hint) map[hint.HintID]hint.Hint { - res := make(map[hint.HintID]hint.Hint, len(hintFunctions)+2) - for k, v := range hintFunctions { - res[k] = v - } - - var gkrData gkrSolvingData - res[info.SolveHintID] = gkrSolveHint(info, &gkrData) - res[info.ProveHintID] = gkrProveHint(info.HashName, &gkrData) - return res -} - var GkrGateRegistry = map[string]gkr.Gate{ // TODO: Migrate to gnark-crypto "mul": mulGate(2), "add": addGate{}, diff --git a/constraint/bls12-377/r1cs_test.go b/constraint/bls12-377/r1cs_test.go index b3eb222420..044c55d31a 100644 --- a/constraint/bls12-377/r1cs_test.go +++ b/constraint/bls12-377/r1cs_test.go @@ -28,7 +28,7 @@ import ( "github.com/google/go-cmp/cmp" "github.com/google/go-cmp/cmp/cmpopts" - "github.com/consensys/gnark/constraint/bls12-377" + cs "github.com/consensys/gnark/constraint/bls12-377" "github.com/consensys/gnark-crypto/ecc/bls12-377/fr" ) diff --git a/constraint/bls12-381/gkr.go b/constraint/bls12-381/gkr.go index ffff99484d..5adfe3ec50 100644 --- a/constraint/bls12-381/gkr.go +++ b/constraint/bls12-381/gkr.go @@ -29,7 +29,7 @@ import ( "math/big" ) -type gkrSolvingData struct { +type GkrSolvingData struct { assignments gkr.WireAssignment circuit gkr.Circuit memoryPool polynomial.Pool @@ -45,7 +45,7 @@ func convertCircuit(noPtr constraint.GkrCircuit) gkr.Circuit { return resCircuit } -func (d *gkrSolvingData) init(info constraint.GkrInfo) gkrAssignment { +func (d *GkrSolvingData) init(info constraint.GkrInfo) gkrAssignment { d.circuit = convertCircuit(info.Circuit) d.memoryPool = polynomial.NewPool(d.circuit.MemoryRequirements(info.NbInstances)...) d.workers = utils.NewWorkerPool() @@ -60,7 +60,7 @@ func (d *gkrSolvingData) init(info constraint.GkrInfo) gkrAssignment { return assignmentsSequential } -func (d *gkrSolvingData) dumpAssignments() { +func (d *GkrSolvingData) dumpAssignments() { for _, p := range d.assignments { d.memoryPool.Dump(p) } @@ -83,7 +83,7 @@ func (a gkrAssignment) setOuts(circuit constraint.GkrCircuit, outs []*big.Int) { // Check if outsI == len(outs)? } -func gkrSolveHint(info constraint.GkrInfo, solvingData *gkrSolvingData) hint.Hint { +func GkrSolveHint(info constraint.GkrInfo, solvingData *GkrSolvingData) hint.Hint { return func(_ *big.Int, ins, outs []*big.Int) error { // assumes assignmentVector is arranged wire first, instance second in order of solution circuit := info.Circuit @@ -147,7 +147,7 @@ func frToBigInts(dst []*big.Int, src []fr.Element) { } } -func gkrProveHint(hashName string, data *gkrSolvingData) hint.Hint { +func GkrProveHint(hashName string, data *GkrSolvingData) hint.Hint { return func(_ *big.Int, ins, outs []*big.Int) error { insBytes := algo_utils.Map(ins[1:], func(i *big.Int) []byte { // the first input is dummy, just to ensure the solver's work is done before the prover is called @@ -183,18 +183,6 @@ func gkrProveHint(hashName string, data *gkrSolvingData) hint.Hint { } } -func defineGkrHints(info constraint.GkrInfo, hintFunctions map[hint.HintID]hint.Hint) map[hint.HintID]hint.Hint { - res := make(map[hint.HintID]hint.Hint, len(hintFunctions)+2) - for k, v := range hintFunctions { - res[k] = v - } - - var gkrData gkrSolvingData - res[info.SolveHintID] = gkrSolveHint(info, &gkrData) - res[info.ProveHintID] = gkrProveHint(info.HashName, &gkrData) - return res -} - var GkrGateRegistry = map[string]gkr.Gate{ // TODO: Migrate to gnark-crypto "mul": mulGate(2), "add": addGate{}, diff --git a/constraint/bls12-381/r1cs_test.go b/constraint/bls12-381/r1cs_test.go index c7b0fa6156..28f77b956b 100644 --- a/constraint/bls12-381/r1cs_test.go +++ b/constraint/bls12-381/r1cs_test.go @@ -28,7 +28,7 @@ import ( "github.com/google/go-cmp/cmp" "github.com/google/go-cmp/cmp/cmpopts" - "github.com/consensys/gnark/constraint/bls12-381" + cs "github.com/consensys/gnark/constraint/bls12-381" "github.com/consensys/gnark-crypto/ecc/bls12-381/fr" ) diff --git a/constraint/bls24-315/gkr.go b/constraint/bls24-315/gkr.go index bca5ee8c0c..048f8fa911 100644 --- a/constraint/bls24-315/gkr.go +++ b/constraint/bls24-315/gkr.go @@ -29,7 +29,7 @@ import ( "math/big" ) -type gkrSolvingData struct { +type GkrSolvingData struct { assignments gkr.WireAssignment circuit gkr.Circuit memoryPool polynomial.Pool @@ -45,7 +45,7 @@ func convertCircuit(noPtr constraint.GkrCircuit) gkr.Circuit { return resCircuit } -func (d *gkrSolvingData) init(info constraint.GkrInfo) gkrAssignment { +func (d *GkrSolvingData) init(info constraint.GkrInfo) gkrAssignment { d.circuit = convertCircuit(info.Circuit) d.memoryPool = polynomial.NewPool(d.circuit.MemoryRequirements(info.NbInstances)...) d.workers = utils.NewWorkerPool() @@ -60,7 +60,7 @@ func (d *gkrSolvingData) init(info constraint.GkrInfo) gkrAssignment { return assignmentsSequential } -func (d *gkrSolvingData) dumpAssignments() { +func (d *GkrSolvingData) dumpAssignments() { for _, p := range d.assignments { d.memoryPool.Dump(p) } @@ -83,7 +83,7 @@ func (a gkrAssignment) setOuts(circuit constraint.GkrCircuit, outs []*big.Int) { // Check if outsI == len(outs)? } -func gkrSolveHint(info constraint.GkrInfo, solvingData *gkrSolvingData) hint.Hint { +func GkrSolveHint(info constraint.GkrInfo, solvingData *GkrSolvingData) hint.Hint { return func(_ *big.Int, ins, outs []*big.Int) error { // assumes assignmentVector is arranged wire first, instance second in order of solution circuit := info.Circuit @@ -147,7 +147,7 @@ func frToBigInts(dst []*big.Int, src []fr.Element) { } } -func gkrProveHint(hashName string, data *gkrSolvingData) hint.Hint { +func GkrProveHint(hashName string, data *GkrSolvingData) hint.Hint { return func(_ *big.Int, ins, outs []*big.Int) error { insBytes := algo_utils.Map(ins[1:], func(i *big.Int) []byte { // the first input is dummy, just to ensure the solver's work is done before the prover is called @@ -183,18 +183,6 @@ func gkrProveHint(hashName string, data *gkrSolvingData) hint.Hint { } } -func defineGkrHints(info constraint.GkrInfo, hintFunctions map[hint.HintID]hint.Hint) map[hint.HintID]hint.Hint { - res := make(map[hint.HintID]hint.Hint, len(hintFunctions)+2) - for k, v := range hintFunctions { - res[k] = v - } - - var gkrData gkrSolvingData - res[info.SolveHintID] = gkrSolveHint(info, &gkrData) - res[info.ProveHintID] = gkrProveHint(info.HashName, &gkrData) - return res -} - var GkrGateRegistry = map[string]gkr.Gate{ // TODO: Migrate to gnark-crypto "mul": mulGate(2), "add": addGate{}, diff --git a/constraint/bls24-315/r1cs_test.go b/constraint/bls24-315/r1cs_test.go index 3885c438b5..4c42f78ee5 100644 --- a/constraint/bls24-315/r1cs_test.go +++ b/constraint/bls24-315/r1cs_test.go @@ -28,7 +28,7 @@ import ( "github.com/google/go-cmp/cmp" "github.com/google/go-cmp/cmp/cmpopts" - "github.com/consensys/gnark/constraint/bls24-315" + cs "github.com/consensys/gnark/constraint/bls24-315" "github.com/consensys/gnark-crypto/ecc/bls24-315/fr" ) diff --git a/constraint/bls24-317/gkr.go b/constraint/bls24-317/gkr.go index 5707c20c54..f81157a0cf 100644 --- a/constraint/bls24-317/gkr.go +++ b/constraint/bls24-317/gkr.go @@ -29,7 +29,7 @@ import ( "math/big" ) -type gkrSolvingData struct { +type GkrSolvingData struct { assignments gkr.WireAssignment circuit gkr.Circuit memoryPool polynomial.Pool @@ -45,7 +45,7 @@ func convertCircuit(noPtr constraint.GkrCircuit) gkr.Circuit { return resCircuit } -func (d *gkrSolvingData) init(info constraint.GkrInfo) gkrAssignment { +func (d *GkrSolvingData) init(info constraint.GkrInfo) gkrAssignment { d.circuit = convertCircuit(info.Circuit) d.memoryPool = polynomial.NewPool(d.circuit.MemoryRequirements(info.NbInstances)...) d.workers = utils.NewWorkerPool() @@ -60,7 +60,7 @@ func (d *gkrSolvingData) init(info constraint.GkrInfo) gkrAssignment { return assignmentsSequential } -func (d *gkrSolvingData) dumpAssignments() { +func (d *GkrSolvingData) dumpAssignments() { for _, p := range d.assignments { d.memoryPool.Dump(p) } @@ -83,7 +83,7 @@ func (a gkrAssignment) setOuts(circuit constraint.GkrCircuit, outs []*big.Int) { // Check if outsI == len(outs)? } -func gkrSolveHint(info constraint.GkrInfo, solvingData *gkrSolvingData) hint.Hint { +func GkrSolveHint(info constraint.GkrInfo, solvingData *GkrSolvingData) hint.Hint { return func(_ *big.Int, ins, outs []*big.Int) error { // assumes assignmentVector is arranged wire first, instance second in order of solution circuit := info.Circuit @@ -147,7 +147,7 @@ func frToBigInts(dst []*big.Int, src []fr.Element) { } } -func gkrProveHint(hashName string, data *gkrSolvingData) hint.Hint { +func GkrProveHint(hashName string, data *GkrSolvingData) hint.Hint { return func(_ *big.Int, ins, outs []*big.Int) error { insBytes := algo_utils.Map(ins[1:], func(i *big.Int) []byte { // the first input is dummy, just to ensure the solver's work is done before the prover is called @@ -183,18 +183,6 @@ func gkrProveHint(hashName string, data *gkrSolvingData) hint.Hint { } } -func defineGkrHints(info constraint.GkrInfo, hintFunctions map[hint.HintID]hint.Hint) map[hint.HintID]hint.Hint { - res := make(map[hint.HintID]hint.Hint, len(hintFunctions)+2) - for k, v := range hintFunctions { - res[k] = v - } - - var gkrData gkrSolvingData - res[info.SolveHintID] = gkrSolveHint(info, &gkrData) - res[info.ProveHintID] = gkrProveHint(info.HashName, &gkrData) - return res -} - var GkrGateRegistry = map[string]gkr.Gate{ // TODO: Migrate to gnark-crypto "mul": mulGate(2), "add": addGate{}, diff --git a/constraint/bls24-317/r1cs_test.go b/constraint/bls24-317/r1cs_test.go index 9ad8d2f586..40bb573a0b 100644 --- a/constraint/bls24-317/r1cs_test.go +++ b/constraint/bls24-317/r1cs_test.go @@ -28,7 +28,7 @@ import ( "github.com/google/go-cmp/cmp" "github.com/google/go-cmp/cmp/cmpopts" - "github.com/consensys/gnark/constraint/bls24-317" + cs "github.com/consensys/gnark/constraint/bls24-317" "github.com/consensys/gnark-crypto/ecc/bls24-317/fr" ) diff --git a/constraint/bn254/r1cs_test.go b/constraint/bn254/r1cs_test.go index 8c8ba5da95..d295603ebf 100644 --- a/constraint/bn254/r1cs_test.go +++ b/constraint/bn254/r1cs_test.go @@ -28,7 +28,7 @@ import ( "github.com/google/go-cmp/cmp" "github.com/google/go-cmp/cmp/cmpopts" - "github.com/consensys/gnark/constraint/bn254" + cs "github.com/consensys/gnark/constraint/bn254" "github.com/consensys/gnark-crypto/ecc/bn254/fr" ) diff --git a/constraint/bw6-633/gkr.go b/constraint/bw6-633/gkr.go index de49f3e8a4..fd3feedb08 100644 --- a/constraint/bw6-633/gkr.go +++ b/constraint/bw6-633/gkr.go @@ -29,7 +29,7 @@ import ( "math/big" ) -type gkrSolvingData struct { +type GkrSolvingData struct { assignments gkr.WireAssignment circuit gkr.Circuit memoryPool polynomial.Pool @@ -45,7 +45,7 @@ func convertCircuit(noPtr constraint.GkrCircuit) gkr.Circuit { return resCircuit } -func (d *gkrSolvingData) init(info constraint.GkrInfo) gkrAssignment { +func (d *GkrSolvingData) init(info constraint.GkrInfo) gkrAssignment { d.circuit = convertCircuit(info.Circuit) d.memoryPool = polynomial.NewPool(d.circuit.MemoryRequirements(info.NbInstances)...) d.workers = utils.NewWorkerPool() @@ -60,7 +60,7 @@ func (d *gkrSolvingData) init(info constraint.GkrInfo) gkrAssignment { return assignmentsSequential } -func (d *gkrSolvingData) dumpAssignments() { +func (d *GkrSolvingData) dumpAssignments() { for _, p := range d.assignments { d.memoryPool.Dump(p) } @@ -83,7 +83,7 @@ func (a gkrAssignment) setOuts(circuit constraint.GkrCircuit, outs []*big.Int) { // Check if outsI == len(outs)? } -func gkrSolveHint(info constraint.GkrInfo, solvingData *gkrSolvingData) hint.Hint { +func GkrSolveHint(info constraint.GkrInfo, solvingData *GkrSolvingData) hint.Hint { return func(_ *big.Int, ins, outs []*big.Int) error { // assumes assignmentVector is arranged wire first, instance second in order of solution circuit := info.Circuit @@ -147,7 +147,7 @@ func frToBigInts(dst []*big.Int, src []fr.Element) { } } -func gkrProveHint(hashName string, data *gkrSolvingData) hint.Hint { +func GkrProveHint(hashName string, data *GkrSolvingData) hint.Hint { return func(_ *big.Int, ins, outs []*big.Int) error { insBytes := algo_utils.Map(ins[1:], func(i *big.Int) []byte { // the first input is dummy, just to ensure the solver's work is done before the prover is called @@ -183,18 +183,6 @@ func gkrProveHint(hashName string, data *gkrSolvingData) hint.Hint { } } -func defineGkrHints(info constraint.GkrInfo, hintFunctions map[hint.HintID]hint.Hint) map[hint.HintID]hint.Hint { - res := make(map[hint.HintID]hint.Hint, len(hintFunctions)+2) - for k, v := range hintFunctions { - res[k] = v - } - - var gkrData gkrSolvingData - res[info.SolveHintID] = gkrSolveHint(info, &gkrData) - res[info.ProveHintID] = gkrProveHint(info.HashName, &gkrData) - return res -} - var GkrGateRegistry = map[string]gkr.Gate{ // TODO: Migrate to gnark-crypto "mul": mulGate(2), "add": addGate{}, diff --git a/constraint/bw6-633/r1cs_test.go b/constraint/bw6-633/r1cs_test.go index 9f9d6a0d6f..7111c25c77 100644 --- a/constraint/bw6-633/r1cs_test.go +++ b/constraint/bw6-633/r1cs_test.go @@ -28,7 +28,7 @@ import ( "github.com/google/go-cmp/cmp" "github.com/google/go-cmp/cmp/cmpopts" - "github.com/consensys/gnark/constraint/bw6-633" + cs "github.com/consensys/gnark/constraint/bw6-633" "github.com/consensys/gnark-crypto/ecc/bw6-633/fr" ) diff --git a/constraint/bw6-761/gkr.go b/constraint/bw6-761/gkr.go index 12958a20f4..5d3edc00cf 100644 --- a/constraint/bw6-761/gkr.go +++ b/constraint/bw6-761/gkr.go @@ -29,7 +29,7 @@ import ( "math/big" ) -type gkrSolvingData struct { +type GkrSolvingData struct { assignments gkr.WireAssignment circuit gkr.Circuit memoryPool polynomial.Pool @@ -45,7 +45,7 @@ func convertCircuit(noPtr constraint.GkrCircuit) gkr.Circuit { return resCircuit } -func (d *gkrSolvingData) init(info constraint.GkrInfo) gkrAssignment { +func (d *GkrSolvingData) init(info constraint.GkrInfo) gkrAssignment { d.circuit = convertCircuit(info.Circuit) d.memoryPool = polynomial.NewPool(d.circuit.MemoryRequirements(info.NbInstances)...) d.workers = utils.NewWorkerPool() @@ -60,7 +60,7 @@ func (d *gkrSolvingData) init(info constraint.GkrInfo) gkrAssignment { return assignmentsSequential } -func (d *gkrSolvingData) dumpAssignments() { +func (d *GkrSolvingData) dumpAssignments() { for _, p := range d.assignments { d.memoryPool.Dump(p) } @@ -83,7 +83,7 @@ func (a gkrAssignment) setOuts(circuit constraint.GkrCircuit, outs []*big.Int) { // Check if outsI == len(outs)? } -func gkrSolveHint(info constraint.GkrInfo, solvingData *gkrSolvingData) hint.Hint { +func GkrSolveHint(info constraint.GkrInfo, solvingData *GkrSolvingData) hint.Hint { return func(_ *big.Int, ins, outs []*big.Int) error { // assumes assignmentVector is arranged wire first, instance second in order of solution circuit := info.Circuit @@ -147,7 +147,7 @@ func frToBigInts(dst []*big.Int, src []fr.Element) { } } -func gkrProveHint(hashName string, data *gkrSolvingData) hint.Hint { +func GkrProveHint(hashName string, data *GkrSolvingData) hint.Hint { return func(_ *big.Int, ins, outs []*big.Int) error { insBytes := algo_utils.Map(ins[1:], func(i *big.Int) []byte { // the first input is dummy, just to ensure the solver's work is done before the prover is called @@ -183,18 +183,6 @@ func gkrProveHint(hashName string, data *gkrSolvingData) hint.Hint { } } -func defineGkrHints(info constraint.GkrInfo, hintFunctions map[hint.HintID]hint.Hint) map[hint.HintID]hint.Hint { - res := make(map[hint.HintID]hint.Hint, len(hintFunctions)+2) - for k, v := range hintFunctions { - res[k] = v - } - - var gkrData gkrSolvingData - res[info.SolveHintID] = gkrSolveHint(info, &gkrData) - res[info.ProveHintID] = gkrProveHint(info.HashName, &gkrData) - return res -} - var GkrGateRegistry = map[string]gkr.Gate{ // TODO: Migrate to gnark-crypto "mul": mulGate(2), "add": addGate{}, diff --git a/constraint/bw6-761/r1cs_test.go b/constraint/bw6-761/r1cs_test.go index b6eae1220c..d8f3b48039 100644 --- a/constraint/bw6-761/r1cs_test.go +++ b/constraint/bw6-761/r1cs_test.go @@ -28,7 +28,7 @@ import ( "github.com/google/go-cmp/cmp" "github.com/google/go-cmp/cmp/cmpopts" - "github.com/consensys/gnark/constraint/bw6-761" + cs "github.com/consensys/gnark/constraint/bw6-761" "github.com/consensys/gnark-crypto/ecc/bw6-761/fr" ) diff --git a/internal/generator/backend/template/imports.go.tmpl b/internal/generator/backend/template/imports.go.tmpl index 56639bdfb2..949969f9d7 100644 --- a/internal/generator/backend/template/imports.go.tmpl +++ b/internal/generator/backend/template/imports.go.tmpl @@ -22,7 +22,7 @@ {{- if eq .Curve "tinyfield"}} "github.com/consensys/gnark/constraint/tinyfield" {{- else}} - "github.com/consensys/gnark/constraint/{{toLower .Curve}}" + cs "github.com/consensys/gnark/constraint/{{toLower .Curve}}" {{- end}} {{- end }} diff --git a/internal/generator/backend/template/representations/gkr.go.tmpl b/internal/generator/backend/template/representations/gkr.go.tmpl index d405ea501c..9c66dd8cf0 100644 --- a/internal/generator/backend/template/representations/gkr.go.tmpl +++ b/internal/generator/backend/template/representations/gkr.go.tmpl @@ -11,7 +11,7 @@ import ( "math/big" ) -type gkrSolvingData struct { +type GkrSolvingData struct { assignments gkr.WireAssignment circuit gkr.Circuit memoryPool polynomial.Pool @@ -27,7 +27,7 @@ func convertCircuit(noPtr constraint.GkrCircuit) gkr.Circuit { return resCircuit } -func (d *gkrSolvingData) init(info constraint.GkrInfo) gkrAssignment { +func (d *GkrSolvingData) init(info constraint.GkrInfo) gkrAssignment { d.circuit = convertCircuit(info.Circuit) d.memoryPool = polynomial.NewPool(d.circuit.MemoryRequirements(info.NbInstances)...) d.workers = utils.NewWorkerPool() @@ -42,7 +42,7 @@ func (d *gkrSolvingData) init(info constraint.GkrInfo) gkrAssignment { return assignmentsSequential } -func (d *gkrSolvingData) dumpAssignments() { +func (d *GkrSolvingData) dumpAssignments() { for _, p := range d.assignments { d.memoryPool.Dump(p) } @@ -65,7 +65,7 @@ func (a gkrAssignment) setOuts(circuit constraint.GkrCircuit, outs []*big.Int) { // Check if outsI == len(outs)? } -func gkrSolveHint(info constraint.GkrInfo, solvingData *gkrSolvingData) hint.Hint { +func GkrSolveHint(info constraint.GkrInfo, solvingData *GkrSolvingData) hint.Hint { return func(_ *big.Int, ins, outs []*big.Int) error { // assumes assignmentVector is arranged wire first, instance second in order of solution circuit := info.Circuit @@ -129,7 +129,7 @@ func frToBigInts(dst []*big.Int, src []fr.Element) { } } -func gkrProveHint(hashName string, data *gkrSolvingData) hint.Hint { +func GkrProveHint(hashName string, data *GkrSolvingData) hint.Hint { return func(_ *big.Int, ins, outs []*big.Int) error { insBytes := algo_utils.Map(ins[1:], func(i *big.Int) []byte { // the first input is dummy, just to ensure the solver's work is done before the prover is called @@ -165,18 +165,6 @@ func gkrProveHint(hashName string, data *gkrSolvingData) hint.Hint { } } -func defineGkrHints(info constraint.GkrInfo, hintFunctions map[hint.HintID]hint.Hint) map[hint.HintID]hint.Hint { - res := make(map[hint.HintID]hint.Hint, len(hintFunctions)+2) - for k, v := range hintFunctions { - res[k] = v - } - - var gkrData gkrSolvingData - res[info.SolveHintID] = gkrSolveHint(info, &gkrData) - res[info.ProveHintID] = gkrProveHint(info.HashName, &gkrData) - return res -} - var GkrGateRegistry = map[string]gkr.Gate{ // TODO: Migrate to gnark-crypto "mul": mulGate(2), "add": addGate{}, diff --git a/internal/generator/backend/template/zkpschemes/groth16/groth16.prove.go.tmpl b/internal/generator/backend/template/zkpschemes/groth16/groth16.prove.go.tmpl index 760cf22d24..fa72568220 100644 --- a/internal/generator/backend/template/zkpschemes/groth16/groth16.prove.go.tmpl +++ b/internal/generator/backend/template/zkpschemes/groth16/groth16.prove.go.tmpl @@ -77,6 +77,13 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b }(i))) } + if r1cs.GkrInfo.Is() { + var gkrData cs.GkrSolvingData + solverOpts = append(solverOpts, + solver.OverrideHint(r1cs.GkrInfo.SolveHintID, cs.GkrSolveHint(r1cs.GkrInfo, &gkrData)), + solver.OverrideHint(r1cs.GkrInfo.ProveHintID, cs.GkrProveHint(r1cs.GkrInfo.HashName, &gkrData))) + } + _solution, err := r1cs.Solve(fullWitness, solverOpts...) if err != nil { return nil, err From 4bc9e042fc0de1d52f1de37e82865d5d4efad5a6 Mon Sep 17 00:00:00 2001 From: Arya Tabaie Date: Tue, 27 Jun 2023 15:47:00 -0500 Subject: [PATCH 70/71] feat: gkr-api for plonk --- backend/plonk/bls12-377/prove.go | 7 ++ backend/plonk/bls12-381/prove.go | 7 ++ backend/plonk/bls24-315/prove.go | 7 ++ backend/plonk/bls24-317/prove.go | 7 ++ backend/plonk/bn254/prove.go | 7 ++ backend/plonk/bw6-633/prove.go | 7 ++ backend/plonk/bw6-761/prove.go | 7 ++ .../zkpschemes/plonk/plonk.prove.go.tmpl | 7 ++ std/gkr/api_test.go | 74 ++++++++++++++----- 9 files changed, 110 insertions(+), 20 deletions(-) diff --git a/backend/plonk/bls12-377/prove.go b/backend/plonk/bls12-377/prove.go index b2d3804587..3f767215ba 100644 --- a/backend/plonk/bls12-377/prove.go +++ b/backend/plonk/bls12-377/prove.go @@ -127,6 +127,13 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts bsb22ComputeCommitmentHint(spr, pk, proof, cCommitments, &commitmentVal[i], i))) } + if spr.GkrInfo.Is() { + var gkrData cs.GkrSolvingData + opt.SolverOpts = append(opt.SolverOpts, + solver.OverrideHint(spr.GkrInfo.SolveHintID, cs.GkrSolveHint(spr.GkrInfo, &gkrData)), + solver.OverrideHint(spr.GkrInfo.ProveHintID, cs.GkrProveHint(spr.GkrInfo.HashName, &gkrData))) + } + // query l, r, o in Lagrange basis, not blinded _solution, err := spr.Solve(fullWitness, opt.SolverOpts...) if err != nil { diff --git a/backend/plonk/bls12-381/prove.go b/backend/plonk/bls12-381/prove.go index 04af58ed95..17627cd176 100644 --- a/backend/plonk/bls12-381/prove.go +++ b/backend/plonk/bls12-381/prove.go @@ -127,6 +127,13 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts bsb22ComputeCommitmentHint(spr, pk, proof, cCommitments, &commitmentVal[i], i))) } + if spr.GkrInfo.Is() { + var gkrData cs.GkrSolvingData + opt.SolverOpts = append(opt.SolverOpts, + solver.OverrideHint(spr.GkrInfo.SolveHintID, cs.GkrSolveHint(spr.GkrInfo, &gkrData)), + solver.OverrideHint(spr.GkrInfo.ProveHintID, cs.GkrProveHint(spr.GkrInfo.HashName, &gkrData))) + } + // query l, r, o in Lagrange basis, not blinded _solution, err := spr.Solve(fullWitness, opt.SolverOpts...) if err != nil { diff --git a/backend/plonk/bls24-315/prove.go b/backend/plonk/bls24-315/prove.go index 650e71714c..7ed6145ebb 100644 --- a/backend/plonk/bls24-315/prove.go +++ b/backend/plonk/bls24-315/prove.go @@ -127,6 +127,13 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts bsb22ComputeCommitmentHint(spr, pk, proof, cCommitments, &commitmentVal[i], i))) } + if spr.GkrInfo.Is() { + var gkrData cs.GkrSolvingData + opt.SolverOpts = append(opt.SolverOpts, + solver.OverrideHint(spr.GkrInfo.SolveHintID, cs.GkrSolveHint(spr.GkrInfo, &gkrData)), + solver.OverrideHint(spr.GkrInfo.ProveHintID, cs.GkrProveHint(spr.GkrInfo.HashName, &gkrData))) + } + // query l, r, o in Lagrange basis, not blinded _solution, err := spr.Solve(fullWitness, opt.SolverOpts...) if err != nil { diff --git a/backend/plonk/bls24-317/prove.go b/backend/plonk/bls24-317/prove.go index 01eebfb5d6..0cdc878d8d 100644 --- a/backend/plonk/bls24-317/prove.go +++ b/backend/plonk/bls24-317/prove.go @@ -127,6 +127,13 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts bsb22ComputeCommitmentHint(spr, pk, proof, cCommitments, &commitmentVal[i], i))) } + if spr.GkrInfo.Is() { + var gkrData cs.GkrSolvingData + opt.SolverOpts = append(opt.SolverOpts, + solver.OverrideHint(spr.GkrInfo.SolveHintID, cs.GkrSolveHint(spr.GkrInfo, &gkrData)), + solver.OverrideHint(spr.GkrInfo.ProveHintID, cs.GkrProveHint(spr.GkrInfo.HashName, &gkrData))) + } + // query l, r, o in Lagrange basis, not blinded _solution, err := spr.Solve(fullWitness, opt.SolverOpts...) if err != nil { diff --git a/backend/plonk/bn254/prove.go b/backend/plonk/bn254/prove.go index 6058692704..40b120a21f 100644 --- a/backend/plonk/bn254/prove.go +++ b/backend/plonk/bn254/prove.go @@ -127,6 +127,13 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts bsb22ComputeCommitmentHint(spr, pk, proof, cCommitments, &commitmentVal[i], i))) } + if spr.GkrInfo.Is() { + var gkrData cs.GkrSolvingData + opt.SolverOpts = append(opt.SolverOpts, + solver.OverrideHint(spr.GkrInfo.SolveHintID, cs.GkrSolveHint(spr.GkrInfo, &gkrData)), + solver.OverrideHint(spr.GkrInfo.ProveHintID, cs.GkrProveHint(spr.GkrInfo.HashName, &gkrData))) + } + // query l, r, o in Lagrange basis, not blinded _solution, err := spr.Solve(fullWitness, opt.SolverOpts...) if err != nil { diff --git a/backend/plonk/bw6-633/prove.go b/backend/plonk/bw6-633/prove.go index abfc80c1ad..1ea6ccf02d 100644 --- a/backend/plonk/bw6-633/prove.go +++ b/backend/plonk/bw6-633/prove.go @@ -127,6 +127,13 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts bsb22ComputeCommitmentHint(spr, pk, proof, cCommitments, &commitmentVal[i], i))) } + if spr.GkrInfo.Is() { + var gkrData cs.GkrSolvingData + opt.SolverOpts = append(opt.SolverOpts, + solver.OverrideHint(spr.GkrInfo.SolveHintID, cs.GkrSolveHint(spr.GkrInfo, &gkrData)), + solver.OverrideHint(spr.GkrInfo.ProveHintID, cs.GkrProveHint(spr.GkrInfo.HashName, &gkrData))) + } + // query l, r, o in Lagrange basis, not blinded _solution, err := spr.Solve(fullWitness, opt.SolverOpts...) if err != nil { diff --git a/backend/plonk/bw6-761/prove.go b/backend/plonk/bw6-761/prove.go index 1aba64a32e..603a95cf31 100644 --- a/backend/plonk/bw6-761/prove.go +++ b/backend/plonk/bw6-761/prove.go @@ -127,6 +127,13 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts bsb22ComputeCommitmentHint(spr, pk, proof, cCommitments, &commitmentVal[i], i))) } + if spr.GkrInfo.Is() { + var gkrData cs.GkrSolvingData + opt.SolverOpts = append(opt.SolverOpts, + solver.OverrideHint(spr.GkrInfo.SolveHintID, cs.GkrSolveHint(spr.GkrInfo, &gkrData)), + solver.OverrideHint(spr.GkrInfo.ProveHintID, cs.GkrProveHint(spr.GkrInfo.HashName, &gkrData))) + } + // query l, r, o in Lagrange basis, not blinded _solution, err := spr.Solve(fullWitness, opt.SolverOpts...) if err != nil { diff --git a/internal/generator/backend/template/zkpschemes/plonk/plonk.prove.go.tmpl b/internal/generator/backend/template/zkpschemes/plonk/plonk.prove.go.tmpl index a869528cf9..def44c21ec 100644 --- a/internal/generator/backend/template/zkpschemes/plonk/plonk.prove.go.tmpl +++ b/internal/generator/backend/template/zkpschemes/plonk/plonk.prove.go.tmpl @@ -105,6 +105,13 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts bsb22ComputeCommitmentHint(spr, pk, proof, cCommitments, &commitmentVal[i], i))) } + if spr.GkrInfo.Is() { + var gkrData cs.GkrSolvingData + opt.SolverOpts = append(opt.SolverOpts, + solver.OverrideHint(spr.GkrInfo.SolveHintID, cs.GkrSolveHint(spr.GkrInfo, &gkrData)), + solver.OverrideHint(spr.GkrInfo.ProveHintID, cs.GkrProveHint(spr.GkrInfo.HashName, &gkrData))) + } + // query l, r, o in Lagrange basis, not blinded _solution, err := spr.Solve(fullWitness, opt.SolverOpts...) if err != nil { diff --git a/std/gkr/api_test.go b/std/gkr/api_test.go index 3dd889c7e6..59d903c1af 100644 --- a/std/gkr/api_test.go +++ b/std/gkr/api_test.go @@ -2,6 +2,10 @@ package gkr import ( "fmt" + "github.com/consensys/gnark-crypto/kzg" + "github.com/consensys/gnark/backend/plonk" + "github.com/consensys/gnark/test" + "github.com/stretchr/testify/require" "hash" "math/rand" "strconv" @@ -17,10 +21,10 @@ import ( bn254r1cs "github.com/consensys/gnark/constraint/bn254" "github.com/consensys/gnark/frontend" "github.com/consensys/gnark/frontend/cs/r1cs" + "github.com/consensys/gnark/frontend/cs/scs" stdHash "github.com/consensys/gnark/std/hash" "github.com/consensys/gnark/std/hash/mimc" test_vector_utils "github.com/consensys/gnark/std/utils/test_vectors_utils" - "github.com/stretchr/testify/assert" ) // compressThreshold --> if linear expressions are larger than this, the frontend will introduce @@ -68,7 +72,8 @@ func TestDoubleNoDependencyCircuit(t *testing.T) { assignment := doubleNoDependencyCircuit{X: xValues} circuit := doubleNoDependencyCircuit{X: make([]frontend.Variable, len(xValues)), hashName: hashName} - testE2E(t, &circuit, &assignment) + testGroth16(t, &circuit, &assignment) + testPlonk(t, &circuit, &assignment) } } } @@ -112,7 +117,8 @@ func TestSqNoDependencyCircuit(t *testing.T) { for _, hashName := range hashes { assignment := sqNoDependencyCircuit{X: xValues} circuit := sqNoDependencyCircuit{X: make([]frontend.Variable, len(xValues)), hashName: hashName} - testE2E(t, &circuit, &assignment) + testGroth16(t, &circuit, &assignment) + testPlonk(t, &circuit, &assignment) } } } @@ -174,7 +180,8 @@ func TestMulNoDependency(t *testing.T) { hashName: hashName, } - testE2E(t, &circuit, &assignment) + testGroth16(t, &circuit, &assignment) + testPlonk(t, &circuit, &assignment) } } } @@ -229,7 +236,8 @@ func TestSolveMulWithDependency(t *testing.T) { } circuit := mulWithDependencyCircuit{Y: make([]frontend.Variable, len(assignment.Y)), hashName: "-20"} - testE2E(t, &circuit, &assignment) + testGroth16(t, &circuit, &assignment) + testPlonk(t, &circuit, &assignment) } func TestApiMul(t *testing.T) { @@ -241,9 +249,9 @@ func TestApiMul(t *testing.T) { ) api := NewApi() x, err = api.Import([]frontend.Variable{nil, nil}) - assert.NoError(t, err) + require.NoError(t, err) y, err = api.Import([]frontend.Variable{nil, nil}) - assert.NoError(t, err) + require.NoError(t, err) z = api.Mul(x, y).(constraint.GkrVariable) test_vector_utils.AssertSliceEqual(t, api.toStore.Circuit[z].Inputs, []int{int(x), int(y)}) // TODO: Find out why assert.Equal gives false positives ( []*Wire{x,x} as second argument passes when it shouldn't ) } @@ -276,7 +284,7 @@ func benchCompile(b *testing.B, circuit frontend.Circuit) { b.ResetTimer() for i := 0; i < b.N; i++ { _, err := frontend.Compile(ecc.BN254.ScalarField(), r1cs.NewBuilder, circuit, frontend.WithCompressThreshold(compressThreshold)) - assert.NoError(b, err) + require.NoError(b, err) } } @@ -284,14 +292,14 @@ func benchProof(b *testing.B, circuit, assignment frontend.Circuit) { fmt.Println("compiling...") start := time.Now().UnixMicro() cs, err := frontend.Compile(ecc.BN254.ScalarField(), r1cs.NewBuilder, circuit, frontend.WithCompressThreshold(compressThreshold)) - assert.NoError(b, err) + require.NoError(b, err) fmt.Println("compiled in", time.Now().UnixMicro()-start, "μs") fullWitness, err := frontend.NewWitness(assignment, ecc.BN254.ScalarField()) - assert.NoError(b, err) + require.NoError(b, err) //publicWitness := fullWitness.Public() fmt.Println("setting up...") pk, _, err := groth16.Setup(cs) - assert.NoError(b, err) + require.NoError(b, err) fmt.Println("solving and proving...") b.ResetTimer() @@ -301,7 +309,7 @@ func benchProof(b *testing.B, circuit, assignment frontend.Circuit) { start = time.Now().UnixMicro() fmt.Println("groth16 proving", id) _, err = groth16.Prove(cs, pk, fullWitness) - assert.NoError(b, err) + require.NoError(b, err) fmt.Println("groth16 proved", id, "in", time.Now().UnixMicro()-start, "μs") fmt.Println("mimc total calls: fr=", mimcFrTotalCalls, ", snark=", mimcSnarkTotalCalls) @@ -369,9 +377,9 @@ func (c *benchMiMCMerkleTreeCircuit) Define(api frontend.API) error { return solution.Verify("-20", challenge) } -func testE2E(t *testing.T, circuit, assignment frontend.Circuit) { +func testGroth16(t *testing.T, circuit, assignment frontend.Circuit) { cs, err := frontend.Compile(ecc.BN254.ScalarField(), r1cs.NewBuilder, circuit, frontend.WithCompressThreshold(compressThreshold)) - assert.NoError(t, err) + require.NoError(t, err) var ( fullWitness witness.Witness publicWitness witness.Witness @@ -380,15 +388,40 @@ func testE2E(t *testing.T, circuit, assignment frontend.Circuit) { proof groth16.Proof ) fullWitness, err = frontend.NewWitness(assignment, ecc.BN254.ScalarField()) - assert.NoError(t, err) + require.NoError(t, err) publicWitness, err = fullWitness.Public() - assert.NoError(t, err) + require.NoError(t, err) pk, vk, err = groth16.Setup(cs) - assert.NoError(t, err) + require.NoError(t, err) proof, err = groth16.Prove(cs, pk, fullWitness) - assert.NoError(t, err) + require.NoError(t, err) err = groth16.Verify(proof, vk, publicWitness) - assert.NoError(t, err) + require.NoError(t, err) +} + +func testPlonk(t *testing.T, circuit, assignment frontend.Circuit) { + cs, err := frontend.Compile(ecc.BN254.ScalarField(), scs.NewBuilder, circuit, frontend.WithCompressThreshold(compressThreshold)) + require.NoError(t, err) + var ( + fullWitness witness.Witness + publicWitness witness.Witness + pk plonk.ProvingKey + vk plonk.VerifyingKey + proof plonk.Proof + kzgSrs kzg.SRS + ) + fullWitness, err = frontend.NewWitness(assignment, ecc.BN254.ScalarField()) + require.NoError(t, err) + publicWitness, err = fullWitness.Public() + require.NoError(t, err) + kzgSrs, err = test.NewKZGSRS(cs) + require.NoError(t, err) + pk, vk, err = plonk.Setup(cs, kzgSrs) + require.NoError(t, err) + proof, err = plonk.Prove(cs, pk, fullWitness) + require.NoError(t, err) + err = plonk.Verify(proof, vk, publicWitness) + require.NoError(t, err) } func registerMiMC() { @@ -603,7 +636,8 @@ func BenchmarkMiMCNoGkrFullDepthSolve(b *testing.B) { func TestMiMCFullDepthNoDepSolve(t *testing.T) { for i := 0; i < 100; i++ { circuit, assignment := mimcNoDepCircuits(5, 1<<2) - testE2E(t, circuit, assignment) + testGroth16(t, circuit, assignment) + testPlonk(t, circuit, assignment) } } From 92cdb5d468a82cb6b8b5f7358c4f01b7067a265c Mon Sep 17 00:00:00 2001 From: Arya Tabaie Date: Tue, 27 Jun 2023 16:22:51 -0500 Subject: [PATCH 71/71] refactor: gkrAPI is no longer a frontend.API --- std/gkr/api.go | 105 +++++--------------------------------------- std/gkr/api_test.go | 16 +++---- std/gkr/compile.go | 16 +++---- 3 files changed, 27 insertions(+), 110 deletions(-) diff --git a/std/gkr/api.go b/std/gkr/api.go index 7515e93163..ad67fb6fcb 100644 --- a/std/gkr/api.go +++ b/std/gkr/api.go @@ -2,17 +2,14 @@ package gkr import ( "github.com/consensys/gnark/constraint" - "github.com/consensys/gnark/constraint/solver" - "github.com/consensys/gnark/frontend" "github.com/consensys/gnark/std/utils/algo_utils" - "math/big" ) -func frontendVarToInt(a frontend.Variable) int { - return int(a.(constraint.GkrVariable)) +func frontendVarToInt(a constraint.GkrVariable) int { + return int(a) } -func (api *API) newNonInputVariable(gate string, in []frontend.Variable) constraint.GkrVariable { +func (api *API) newNonInputVariable(gate string, in []constraint.GkrVariable) constraint.GkrVariable { api.toStore.Circuit = append(api.toStore.Circuit, constraint.GkrWire{ Gate: gate, Inputs: algo_utils.Map(in, frontendVarToInt), @@ -21,8 +18,8 @@ func (api *API) newNonInputVariable(gate string, in []frontend.Variable) constra return constraint.GkrVariable(len(api.toStore.Circuit) - 1) } -func (api *API) newVar2PlusIn(gate string, in1, in2 frontend.Variable, in ...frontend.Variable) constraint.GkrVariable { - inCombined := make([]frontend.Variable, 2+len(in)) +func (api *API) newVar2PlusIn(gate string, in1, in2 constraint.GkrVariable, in ...constraint.GkrVariable) constraint.GkrVariable { + inCombined := make([]constraint.GkrVariable, 2+len(in)) inCombined[0] = in1 inCombined[1] = in2 for i := range in { @@ -31,101 +28,23 @@ func (api *API) newVar2PlusIn(gate string, in1, in2 frontend.Variable, in ...fro return api.newNonInputVariable(gate, inCombined) } -func (api *API) Add(i1, i2 frontend.Variable, in ...frontend.Variable) frontend.Variable { +func (api *API) Add(i1, i2 constraint.GkrVariable, in ...constraint.GkrVariable) constraint.GkrVariable { return api.newVar2PlusIn("add", i1, i2, in...) } -func (api *API) Neg(i1 frontend.Variable) frontend.Variable { - return api.newNonInputVariable("neg", []frontend.Variable{i1}) +func (api *API) Neg(i1 constraint.GkrVariable) constraint.GkrVariable { + return api.newNonInputVariable("neg", []constraint.GkrVariable{i1}) } -func (api *API) Sub(i1, i2 frontend.Variable, in ...frontend.Variable) frontend.Variable { +func (api *API) Sub(i1, i2 constraint.GkrVariable, in ...constraint.GkrVariable) constraint.GkrVariable { return api.newVar2PlusIn("sub", i1, i2, in...) } -func (api *API) Mul(i1, i2 frontend.Variable, in ...frontend.Variable) frontend.Variable { +func (api *API) Mul(i1, i2 constraint.GkrVariable, in ...constraint.GkrVariable) constraint.GkrVariable { return api.newVar2PlusIn("mul", i1, i2, in...) } -func (api *API) DivUnchecked(i1, i2 frontend.Variable) frontend.Variable { - panic("not implemented") -} - -func (api *API) Div(i1, i2 frontend.Variable) frontend.Variable { - panic("not implemented") -} - -// TODO: This will require some sophistication. The resulting variable will be considered input by the prover but not by the solver -func (api *API) Inverse(i1 frontend.Variable) frontend.Variable { - panic("not implemented") -} - -func (api *API) ToBinary(i1 frontend.Variable, n ...int) []frontend.Variable { - panic("not implemented") -} - -func (api *API) FromBinary(b ...frontend.Variable) frontend.Variable { - panic("not implemented") -} - -func (api *API) Xor(a, b frontend.Variable) frontend.Variable { - panic("not implemented") -} - -func (api *API) Or(a, b frontend.Variable) frontend.Variable { - panic("not implemented") -} - -func (api *API) And(a, b frontend.Variable) frontend.Variable { - panic("not implemented") -} - -func (api *API) Select(b frontend.Variable, i1, i2 frontend.Variable) frontend.Variable { - panic("not implemented") -} - -func (api *API) Lookup2(b0, b1 frontend.Variable, i0, i1, i2, i3 frontend.Variable) frontend.Variable { - panic("not implemented") -} - -func (api *API) IsZero(i1 frontend.Variable) frontend.Variable { - panic("not implemented") -} - -func (api *API) Cmp(i1, i2 frontend.Variable) frontend.Variable { - panic("not implemented") -} - -func (api *API) AssertIsEqual(i1, i2 frontend.Variable) { - panic("not implemented") -} - -func (api *API) AssertIsDifferent(i1, i2 frontend.Variable) { - panic("not implemented") -} - -func (api *API) AssertIsBoolean(i1 frontend.Variable) { - panic("not implemented") -} - -func (api *API) AssertIsLessOrEqual(v frontend.Variable, bound frontend.Variable) { - panic("not implemented") -} - -// TODO: This can be important. -func (api *API) Println(a ...frontend.Variable) { - panic("not implemented") -} - -// This is definitely out of scope. TODO: A CircuitBuilder API that doesn't have to implement this and can be passed on to gadgets -func (api *API) Compiler() frontend.Compiler { - panic("not implemented") -} - -func (api *API) NewHint(f solver.Hint, nbOutputs int, inputs ...frontend.Variable) ([]frontend.Variable, error) { - panic("not implemented") -} - -func (api *API) ConstantValue(v frontend.Variable) (*big.Int, bool) { +// TODO @Tabaie This can be useful +func (api *API) Println(a ...constraint.GkrVariable) { panic("not implemented") } diff --git a/std/gkr/api_test.go b/std/gkr/api_test.go index 59d903c1af..a41670be0e 100644 --- a/std/gkr/api_test.go +++ b/std/gkr/api_test.go @@ -39,7 +39,7 @@ type doubleNoDependencyCircuit struct { func (c *doubleNoDependencyCircuit) Define(api frontend.API) error { gkr := NewApi() - var x frontend.Variable + var x constraint.GkrVariable var err error if x, err = gkr.Import(c.X); err != nil { return err @@ -85,7 +85,7 @@ type sqNoDependencyCircuit struct { func (c *sqNoDependencyCircuit) Define(api frontend.API) error { gkr := NewApi() - var x frontend.Variable + var x constraint.GkrVariable var err error if x, err = gkr.Import(c.X); err != nil { return err @@ -130,7 +130,7 @@ type mulNoDependencyCircuit struct { func (c *mulNoDependencyCircuit) Define(api frontend.API) error { gkr := NewApi() - var x, y frontend.Variable + var x, y constraint.GkrVariable var err error if x, err = gkr.Import(c.X); err != nil { return err @@ -194,7 +194,7 @@ type mulWithDependencyCircuit struct { func (c *mulWithDependencyCircuit) Define(api frontend.API) error { gkr := NewApi() - var x, y frontend.Variable + var x, y constraint.GkrVariable var err error X := make([]frontend.Variable, len(c.Y)) @@ -252,7 +252,7 @@ func TestApiMul(t *testing.T) { require.NoError(t, err) y, err = api.Import([]frontend.Variable{nil, nil}) require.NoError(t, err) - z = api.Mul(x, y).(constraint.GkrVariable) + z = api.Mul(x, y) test_vector_utils.AssertSliceEqual(t, api.toStore.Circuit[z].Inputs, []int{int(x), int(y)}) // TODO: Find out why assert.Equal gives false positives ( []*Wire{x,x} as second argument passes when it shouldn't ) } @@ -334,7 +334,7 @@ func (c *benchMiMCMerkleTreeCircuit) Define(api frontend.API) error { X[len(X)-1] = 0 Y[len(X)-1] = 0 - var x, y frontend.Variable + var x, y constraint.GkrVariable var err error gkr := NewApi() @@ -348,10 +348,10 @@ func (c *benchMiMCMerkleTreeCircuit) Define(api frontend.API) error { // cheat{ gkr.toStore.Circuit = append(gkr.toStore.Circuit, constraint.GkrWire{ Gate: "mimc", - Inputs: []int{int(x.(constraint.GkrVariable)), int(y.(constraint.GkrVariable))}, + Inputs: []int{int(x), int(y)}, }) gkr.assignments = append(gkr.assignments, nil) - z := frontend.Variable(constraint.GkrVariable(2)) + z := constraint.GkrVariable(2) // } offset := 1 << (c.depth - 1) diff --git a/std/gkr/compile.go b/std/gkr/compile.go index 724916e42a..0b1199787c 100644 --- a/std/gkr/compile.go +++ b/std/gkr/compile.go @@ -52,15 +52,13 @@ func log2(x uint) int { } // Series like in an electric circuit, binds an input of an instance to an output of another -func (api *API) Series(input, output frontend.Variable, inputInstance, outputInstance int) *API { - i := input.(constraint.GkrVariable) - o := output.(constraint.GkrVariable) - if api.assignments[i][inputInstance] != nil { +func (api *API) Series(input, output constraint.GkrVariable, inputInstance, outputInstance int) *API { + if api.assignments[input][inputInstance] != nil { panic("dependency attempting to override explicit value assignment") } - api.toStore.Circuit[i].Dependencies = - append(api.toStore.Circuit[i].Dependencies, constraint.InputDependency{ - OutputWire: int(o), + api.toStore.Circuit[input].Dependencies = + append(api.toStore.Circuit[input].Dependencies, constraint.InputDependency{ + OutputWire: int(output), OutputInstance: outputInstance, InputInstance: inputInstance, }) @@ -203,11 +201,11 @@ func (s Solution) Verify(hashName string, initialChallenges ...frontend.Variable return s.parentApi.Compiler().SetGkrInfo(s.toStore) } -func SolveHintPlaceholder(*big.Int, []*big.Int, []*big.Int) error { +func SolveHintPlaceholder(*big.Int, []*big.Int, []*big.Int) error { // TODO @Tabaie Add implementation for testing return fmt.Errorf("placeholder - not meant to be called") } -func ProveHintPlaceholder(*big.Int, []*big.Int, []*big.Int) error { +func ProveHintPlaceholder(*big.Int, []*big.Int, []*big.Int) error { // TODO @Tabaie Add implementation for testing return fmt.Errorf("placeholder - not meant to be called") }