diff --git a/ecc/bls12-377/fr/fri/fri.go b/ecc/bls12-377/fr/fri/fri.go index 91cc031ee..9a4a8bee1 100644 --- a/ecc/bls12-377/fr/fri/fri.go +++ b/ecc/bls12-377/fr/fri/fri.go @@ -365,18 +365,6 @@ func foldPolynomialLagrangeBasis(pSorted []fr.Element, gInv, x fr.Element) []fr. return res } -// paddNaming takes s = 0xA1.... and turns -// it into s' = 0xA1.. || 0..0 of size frSize bytes. -// Using this, when writing the domain separator in FiatShamir, it takes -// the same size as a snark variable (=number of byte in the block of a snark compliant -// hash function like mimc), so it is compliant with snark circuit. -func paddNaming(s string, size int) string { - a := make([]byte, size) - b := []byte(s) - copy(a, b) - return string(a) -} - // buildProofOfProximitySingleRound generates a proof that a function, given as an oracle from // the verifier point of view, is in fact δ-close to a polynomial. // * salt is a variable for multi rounds, it allows to generate different challenges using Fiat Shamir @@ -395,9 +383,9 @@ func (s radixTwoFri) buildProofOfProximitySingleRound(salt fr.Element, p []fr.El // by replacing x by xᵢ. xis := make([]string, s.nbSteps+1) for i := 0; i < s.nbSteps; i++ { - xis[i] = paddNaming(fmt.Sprintf("x%d", i), fr.Bytes) + xis[i] = fmt.Sprintf("x%d", i) } - xis[s.nbSteps] = paddNaming("s0", fr.Bytes) + xis[s.nbSteps] = "s0" fs := fiatshamir.NewTranscript(s.h, xis...) // the salt is binded to the first challenge, to ensure the challenges @@ -549,9 +537,9 @@ func (s radixTwoFri) verifyProofOfProximitySingleRound(salt fr.Element, proof Ro // Fiat Shamir transcript to derive the challenges xis := make([]string, s.nbSteps+1) for i := 0; i < s.nbSteps; i++ { - xis[i] = paddNaming(fmt.Sprintf("x%d", i), fr.Bytes) + xis[i] = fmt.Sprintf("x%d", i) } - xis[s.nbSteps] = paddNaming("s0", fr.Bytes) + xis[s.nbSteps] = "s0" fs := fiatshamir.NewTranscript(s.h, xis...) xi := make([]fr.Element, s.nbSteps) diff --git a/ecc/bls12-377/fr/gkr/gkr.go b/ecc/bls12-377/fr/gkr/gkr.go index 2d579924a..19f4e9bb2 100644 --- a/ecc/bls12-377/fr/gkr/gkr.go +++ b/ecc/bls12-377/fr/gkr/gkr.go @@ -490,9 +490,7 @@ func setup(c Circuit, assignment WireAssignment, transcriptSettings fiatshamir.S if transcriptSettings.Transcript == nil { challengeNames := ChallengeNames(o.sorted, o.nbVars, transcriptSettings.Prefix) - transcript := fiatshamir.NewTranscript( - transcriptSettings.Hash, challengeNames...) - o.transcript = &transcript + o.transcript = fiatshamir.NewTranscript(transcriptSettings.Hash, challengeNames...) for i := range transcriptSettings.BaseChallenges { if err = o.transcript.Bind(challengeNames[0], transcriptSettings.BaseChallenges[i]); err != nil { return o, err diff --git a/ecc/bls12-377/fr/mimc/mimc.go b/ecc/bls12-377/fr/mimc/mimc.go index 58ed4f649..d393f0d74 100644 --- a/ecc/bls12-377/fr/mimc/mimc.go +++ b/ecc/bls12-377/fr/mimc/mimc.go @@ -100,6 +100,14 @@ func (d *digest) BlockSize() int { // // To hash arbitrary data ([]byte not representing canonical field elements) use fr.Hash first func (d *digest) Write(p []byte) (int, error) { + // we usually expect multiple of block size. But sometimes we hash short + // values (FS transcript). Instead of forcing to hash to field, we left-pad the + // input here. + if len(p) > 0 && len(p) < BlockSize { + pp := make([]byte, BlockSize) + copy(pp[len(pp)-len(p):], p) + p = pp + } var start int for start = 0; start < len(p); start += BlockSize { @@ -185,10 +193,11 @@ func initConstants() { } // WriteString writes a string that doesn't necessarily consist of field elements -func (d *digest) WriteString(rawBytes []byte) { +func (d *digest) WriteString(rawBytes []byte) error { if elems, err := fr.Hash(rawBytes, []byte("string:"), 1); err != nil { - panic(err) + return err } else { d.data = append(d.data, elems[0]) } + return nil } diff --git a/ecc/bls12-377/fr/permutation/permutation.go b/ecc/bls12-377/fr/permutation/permutation.go index 3cf4c56a9..e5c2770df 100644 --- a/ecc/bls12-377/fr/permutation/permutation.go +++ b/ecc/bls12-377/fr/permutation/permutation.go @@ -177,7 +177,7 @@ func Prove(pk kzg.ProvingKey, t1, t2 []fr.Element) (Proof, error) { } // derive challenge for z - epsilon, err := deriveRandomness(&fs, "epsilon", &proof.t1, &proof.t2) + epsilon, err := deriveRandomness(fs, "epsilon", &proof.t1, &proof.t2) if err != nil { return proof, err } @@ -206,7 +206,7 @@ func Prove(pk kzg.ProvingKey, t1, t2 []fr.Element) (Proof, error) { lsNum := evaluateSecondPartNumReverse(lz, d) // derive challenge used for the folding - omega, err := deriveRandomness(&fs, "omega", &proof.z) + omega, err := deriveRandomness(fs, "omega", &proof.z) if err != nil { return proof, err } @@ -229,7 +229,7 @@ func Prove(pk kzg.ProvingKey, t1, t2 []fr.Element) (Proof, error) { } // derive the evaluation challenge - eta, err := deriveRandomness(&fs, "eta", &proof.q) + eta, err := deriveRandomness(fs, "eta", &proof.q) if err != nil { return proof, err } @@ -282,17 +282,17 @@ func Verify(vk kzg.VerifyingKey, proof Proof) error { fs := fiatshamir.NewTranscript(hFunc, "epsilon", "omega", "eta") // derive the challenges - epsilon, err := deriveRandomness(&fs, "epsilon", &proof.t1, &proof.t2) + epsilon, err := deriveRandomness(fs, "epsilon", &proof.t1, &proof.t2) if err != nil { return err } - omega, err := deriveRandomness(&fs, "omega", &proof.z) + omega, err := deriveRandomness(fs, "omega", &proof.z) if err != nil { return err } - eta, err := deriveRandomness(&fs, "eta", &proof.q) + eta, err := deriveRandomness(fs, "eta", &proof.q) if err != nil { return err } diff --git a/ecc/bls12-377/fr/plookup/table.go b/ecc/bls12-377/fr/plookup/table.go index 650e73be2..4a299138a 100644 --- a/ecc/bls12-377/fr/plookup/table.go +++ b/ecc/bls12-377/fr/plookup/table.go @@ -145,7 +145,7 @@ func ProveLookupTables(pk kzg.ProvingKey, f, t []fr.Vector) (ProofLookupTables, comms[nbRows+i] = new(kzg.Digest) comms[nbRows+i].Set(&proof.ts[i]) } - lambda, err := deriveRandomness(&fs, "lambda", comms...) + lambda, err := deriveRandomness(fs, "lambda", comms...) if err != nil { return proof, err } @@ -197,7 +197,7 @@ func VerifyLookupTables(vk kzg.VerifyingKey, proof ProofLookupTables) error { comms[i] = &proof.fs[i] comms[i+nbRows] = &proof.ts[i] } - lambda, err := deriveRandomness(&fs, "lambda", comms...) + lambda, err := deriveRandomness(fs, "lambda", comms...) if err != nil { return err } diff --git a/ecc/bls12-377/fr/plookup/vector.go b/ecc/bls12-377/fr/plookup/vector.go index dd91fb108..98583fded 100644 --- a/ecc/bls12-377/fr/plookup/vector.go +++ b/ecc/bls12-377/fr/plookup/vector.go @@ -441,11 +441,11 @@ func ProveLookupVector(pk kzg.ProvingKey, f, t fr.Vector) (ProofLookupVector, er } // derive beta, gamma - beta, err := deriveRandomness(&fs, "beta", &proof.t, &proof.f, &proof.h1, &proof.h2) + beta, err := deriveRandomness(fs, "beta", &proof.t, &proof.f, &proof.h1, &proof.h2) if err != nil { return proof, err } - gamma, err := deriveRandomness(&fs, "gamma") + gamma, err := deriveRandomness(fs, "gamma") if err != nil { return proof, err } @@ -495,7 +495,7 @@ func ProveLookupVector(pk kzg.ProvingKey, f, t fr.Vector) (ProofLookupVector, er lh1h2 := evaluateOverlapH1h2BitReversed(_lh1, _lh2, domainBig) // compute the quotient - alpha, err := deriveRandomness(&fs, "alpha", &proof.z) + alpha, err := deriveRandomness(fs, "alpha", &proof.z) if err != nil { return proof, err } @@ -506,7 +506,7 @@ func ProveLookupVector(pk kzg.ProvingKey, f, t fr.Vector) (ProofLookupVector, er } // build the opening proofs - nu, err := deriveRandomness(&fs, "nu", &proof.h) + nu, err := deriveRandomness(fs, "nu", &proof.h) if err != nil { return proof, err } @@ -570,22 +570,22 @@ func VerifyLookupVector(vk kzg.VerifyingKey, proof ProofLookupVector) error { fs := fiatshamir.NewTranscript(hFunc, "beta", "gamma", "alpha", "nu") // derive the various challenges - beta, err := deriveRandomness(&fs, "beta", &proof.t, &proof.f, &proof.h1, &proof.h2) + beta, err := deriveRandomness(fs, "beta", &proof.t, &proof.f, &proof.h1, &proof.h2) if err != nil { return err } - gamma, err := deriveRandomness(&fs, "gamma") + gamma, err := deriveRandomness(fs, "gamma") if err != nil { return err } - alpha, err := deriveRandomness(&fs, "alpha", &proof.z) + alpha, err := deriveRandomness(fs, "alpha", &proof.z) if err != nil { return err } - nu, err := deriveRandomness(&fs, "nu", &proof.h) + nu, err := deriveRandomness(fs, "nu", &proof.h) if err != nil { return err } diff --git a/ecc/bls12-377/fr/sumcheck/sumcheck.go b/ecc/bls12-377/fr/sumcheck/sumcheck.go index 09640b7bc..cdea58ba8 100644 --- a/ecc/bls12-377/fr/sumcheck/sumcheck.go +++ b/ecc/bls12-377/fr/sumcheck/sumcheck.go @@ -67,7 +67,7 @@ func setupTranscript(claimsNum int, varsNum int, settings *fiatshamir.Settings) } if settings.Transcript == nil { transcript := fiatshamir.NewTranscript(settings.Hash, challengeNames...) - settings.Transcript = &transcript + settings.Transcript = transcript } for i := range settings.BaseChallenges { diff --git a/ecc/bls12-378/fr/fri/fri.go b/ecc/bls12-378/fr/fri/fri.go index 145e2defd..fe392d533 100644 --- a/ecc/bls12-378/fr/fri/fri.go +++ b/ecc/bls12-378/fr/fri/fri.go @@ -365,18 +365,6 @@ func foldPolynomialLagrangeBasis(pSorted []fr.Element, gInv, x fr.Element) []fr. return res } -// paddNaming takes s = 0xA1.... and turns -// it into s' = 0xA1.. || 0..0 of size frSize bytes. -// Using this, when writing the domain separator in FiatShamir, it takes -// the same size as a snark variable (=number of byte in the block of a snark compliant -// hash function like mimc), so it is compliant with snark circuit. -func paddNaming(s string, size int) string { - a := make([]byte, size) - b := []byte(s) - copy(a, b) - return string(a) -} - // buildProofOfProximitySingleRound generates a proof that a function, given as an oracle from // the verifier point of view, is in fact δ-close to a polynomial. // * salt is a variable for multi rounds, it allows to generate different challenges using Fiat Shamir @@ -395,9 +383,9 @@ func (s radixTwoFri) buildProofOfProximitySingleRound(salt fr.Element, p []fr.El // by replacing x by xᵢ. xis := make([]string, s.nbSteps+1) for i := 0; i < s.nbSteps; i++ { - xis[i] = paddNaming(fmt.Sprintf("x%d", i), fr.Bytes) + xis[i] = fmt.Sprintf("x%d", i) } - xis[s.nbSteps] = paddNaming("s0", fr.Bytes) + xis[s.nbSteps] = "s0" fs := fiatshamir.NewTranscript(s.h, xis...) // the salt is binded to the first challenge, to ensure the challenges @@ -549,9 +537,9 @@ func (s radixTwoFri) verifyProofOfProximitySingleRound(salt fr.Element, proof Ro // Fiat Shamir transcript to derive the challenges xis := make([]string, s.nbSteps+1) for i := 0; i < s.nbSteps; i++ { - xis[i] = paddNaming(fmt.Sprintf("x%d", i), fr.Bytes) + xis[i] = fmt.Sprintf("x%d", i) } - xis[s.nbSteps] = paddNaming("s0", fr.Bytes) + xis[s.nbSteps] = "s0" fs := fiatshamir.NewTranscript(s.h, xis...) xi := make([]fr.Element, s.nbSteps) diff --git a/ecc/bls12-378/fr/gkr/gkr.go b/ecc/bls12-378/fr/gkr/gkr.go index 1c6c96774..c576d7aca 100644 --- a/ecc/bls12-378/fr/gkr/gkr.go +++ b/ecc/bls12-378/fr/gkr/gkr.go @@ -490,9 +490,7 @@ func setup(c Circuit, assignment WireAssignment, transcriptSettings fiatshamir.S if transcriptSettings.Transcript == nil { challengeNames := ChallengeNames(o.sorted, o.nbVars, transcriptSettings.Prefix) - transcript := fiatshamir.NewTranscript( - transcriptSettings.Hash, challengeNames...) - o.transcript = &transcript + o.transcript = fiatshamir.NewTranscript(transcriptSettings.Hash, challengeNames...) for i := range transcriptSettings.BaseChallenges { if err = o.transcript.Bind(challengeNames[0], transcriptSettings.BaseChallenges[i]); err != nil { return o, err diff --git a/ecc/bls12-378/fr/mimc/mimc.go b/ecc/bls12-378/fr/mimc/mimc.go index e28d965a4..38cde3905 100644 --- a/ecc/bls12-378/fr/mimc/mimc.go +++ b/ecc/bls12-378/fr/mimc/mimc.go @@ -100,6 +100,14 @@ func (d *digest) BlockSize() int { // // To hash arbitrary data ([]byte not representing canonical field elements) use fr.Hash first func (d *digest) Write(p []byte) (int, error) { + // we usually expect multiple of block size. But sometimes we hash short + // values (FS transcript). Instead of forcing to hash to field, we left-pad the + // input here. + if len(p) > 0 && len(p) < BlockSize { + pp := make([]byte, BlockSize) + copy(pp[len(pp)-len(p):], p) + p = pp + } var start int for start = 0; start < len(p); start += BlockSize { @@ -183,10 +191,11 @@ func initConstants() { } // WriteString writes a string that doesn't necessarily consist of field elements -func (d *digest) WriteString(rawBytes []byte) { +func (d *digest) WriteString(rawBytes []byte) error { if elems, err := fr.Hash(rawBytes, []byte("string:"), 1); err != nil { - panic(err) + return err } else { d.data = append(d.data, elems[0]) } + return nil } diff --git a/ecc/bls12-378/fr/permutation/permutation.go b/ecc/bls12-378/fr/permutation/permutation.go index 7e21ef345..0f7b60f1b 100644 --- a/ecc/bls12-378/fr/permutation/permutation.go +++ b/ecc/bls12-378/fr/permutation/permutation.go @@ -177,7 +177,7 @@ func Prove(pk kzg.ProvingKey, t1, t2 []fr.Element) (Proof, error) { } // derive challenge for z - epsilon, err := deriveRandomness(&fs, "epsilon", &proof.t1, &proof.t2) + epsilon, err := deriveRandomness(fs, "epsilon", &proof.t1, &proof.t2) if err != nil { return proof, err } @@ -206,7 +206,7 @@ func Prove(pk kzg.ProvingKey, t1, t2 []fr.Element) (Proof, error) { lsNum := evaluateSecondPartNumReverse(lz, d) // derive challenge used for the folding - omega, err := deriveRandomness(&fs, "omega", &proof.z) + omega, err := deriveRandomness(fs, "omega", &proof.z) if err != nil { return proof, err } @@ -229,7 +229,7 @@ func Prove(pk kzg.ProvingKey, t1, t2 []fr.Element) (Proof, error) { } // derive the evaluation challenge - eta, err := deriveRandomness(&fs, "eta", &proof.q) + eta, err := deriveRandomness(fs, "eta", &proof.q) if err != nil { return proof, err } @@ -282,17 +282,17 @@ func Verify(vk kzg.VerifyingKey, proof Proof) error { fs := fiatshamir.NewTranscript(hFunc, "epsilon", "omega", "eta") // derive the challenges - epsilon, err := deriveRandomness(&fs, "epsilon", &proof.t1, &proof.t2) + epsilon, err := deriveRandomness(fs, "epsilon", &proof.t1, &proof.t2) if err != nil { return err } - omega, err := deriveRandomness(&fs, "omega", &proof.z) + omega, err := deriveRandomness(fs, "omega", &proof.z) if err != nil { return err } - eta, err := deriveRandomness(&fs, "eta", &proof.q) + eta, err := deriveRandomness(fs, "eta", &proof.q) if err != nil { return err } diff --git a/ecc/bls12-378/fr/plookup/table.go b/ecc/bls12-378/fr/plookup/table.go index e4a9ea604..cff6a8cf6 100644 --- a/ecc/bls12-378/fr/plookup/table.go +++ b/ecc/bls12-378/fr/plookup/table.go @@ -145,7 +145,7 @@ func ProveLookupTables(pk kzg.ProvingKey, f, t []fr.Vector) (ProofLookupTables, comms[nbRows+i] = new(kzg.Digest) comms[nbRows+i].Set(&proof.ts[i]) } - lambda, err := deriveRandomness(&fs, "lambda", comms...) + lambda, err := deriveRandomness(fs, "lambda", comms...) if err != nil { return proof, err } @@ -197,7 +197,7 @@ func VerifyLookupTables(vk kzg.VerifyingKey, proof ProofLookupTables) error { comms[i] = &proof.fs[i] comms[i+nbRows] = &proof.ts[i] } - lambda, err := deriveRandomness(&fs, "lambda", comms...) + lambda, err := deriveRandomness(fs, "lambda", comms...) if err != nil { return err } diff --git a/ecc/bls12-378/fr/plookup/vector.go b/ecc/bls12-378/fr/plookup/vector.go index 6415607e4..59d37e7e1 100644 --- a/ecc/bls12-378/fr/plookup/vector.go +++ b/ecc/bls12-378/fr/plookup/vector.go @@ -441,11 +441,11 @@ func ProveLookupVector(pk kzg.ProvingKey, f, t fr.Vector) (ProofLookupVector, er } // derive beta, gamma - beta, err := deriveRandomness(&fs, "beta", &proof.t, &proof.f, &proof.h1, &proof.h2) + beta, err := deriveRandomness(fs, "beta", &proof.t, &proof.f, &proof.h1, &proof.h2) if err != nil { return proof, err } - gamma, err := deriveRandomness(&fs, "gamma") + gamma, err := deriveRandomness(fs, "gamma") if err != nil { return proof, err } @@ -495,7 +495,7 @@ func ProveLookupVector(pk kzg.ProvingKey, f, t fr.Vector) (ProofLookupVector, er lh1h2 := evaluateOverlapH1h2BitReversed(_lh1, _lh2, domainBig) // compute the quotient - alpha, err := deriveRandomness(&fs, "alpha", &proof.z) + alpha, err := deriveRandomness(fs, "alpha", &proof.z) if err != nil { return proof, err } @@ -506,7 +506,7 @@ func ProveLookupVector(pk kzg.ProvingKey, f, t fr.Vector) (ProofLookupVector, er } // build the opening proofs - nu, err := deriveRandomness(&fs, "nu", &proof.h) + nu, err := deriveRandomness(fs, "nu", &proof.h) if err != nil { return proof, err } @@ -570,22 +570,22 @@ func VerifyLookupVector(vk kzg.VerifyingKey, proof ProofLookupVector) error { fs := fiatshamir.NewTranscript(hFunc, "beta", "gamma", "alpha", "nu") // derive the various challenges - beta, err := deriveRandomness(&fs, "beta", &proof.t, &proof.f, &proof.h1, &proof.h2) + beta, err := deriveRandomness(fs, "beta", &proof.t, &proof.f, &proof.h1, &proof.h2) if err != nil { return err } - gamma, err := deriveRandomness(&fs, "gamma") + gamma, err := deriveRandomness(fs, "gamma") if err != nil { return err } - alpha, err := deriveRandomness(&fs, "alpha", &proof.z) + alpha, err := deriveRandomness(fs, "alpha", &proof.z) if err != nil { return err } - nu, err := deriveRandomness(&fs, "nu", &proof.h) + nu, err := deriveRandomness(fs, "nu", &proof.h) if err != nil { return err } diff --git a/ecc/bls12-378/fr/sumcheck/sumcheck.go b/ecc/bls12-378/fr/sumcheck/sumcheck.go index 2ae2f56aa..88c1ed861 100644 --- a/ecc/bls12-378/fr/sumcheck/sumcheck.go +++ b/ecc/bls12-378/fr/sumcheck/sumcheck.go @@ -67,7 +67,7 @@ func setupTranscript(claimsNum int, varsNum int, settings *fiatshamir.Settings) } if settings.Transcript == nil { transcript := fiatshamir.NewTranscript(settings.Hash, challengeNames...) - settings.Transcript = &transcript + settings.Transcript = transcript } for i := range settings.BaseChallenges { diff --git a/ecc/bls12-381/fr/fri/fri.go b/ecc/bls12-381/fr/fri/fri.go index 52bf2091e..c206e7c5b 100644 --- a/ecc/bls12-381/fr/fri/fri.go +++ b/ecc/bls12-381/fr/fri/fri.go @@ -365,18 +365,6 @@ func foldPolynomialLagrangeBasis(pSorted []fr.Element, gInv, x fr.Element) []fr. return res } -// paddNaming takes s = 0xA1.... and turns -// it into s' = 0xA1.. || 0..0 of size frSize bytes. -// Using this, when writing the domain separator in FiatShamir, it takes -// the same size as a snark variable (=number of byte in the block of a snark compliant -// hash function like mimc), so it is compliant with snark circuit. -func paddNaming(s string, size int) string { - a := make([]byte, size) - b := []byte(s) - copy(a, b) - return string(a) -} - // buildProofOfProximitySingleRound generates a proof that a function, given as an oracle from // the verifier point of view, is in fact δ-close to a polynomial. // * salt is a variable for multi rounds, it allows to generate different challenges using Fiat Shamir @@ -395,9 +383,9 @@ func (s radixTwoFri) buildProofOfProximitySingleRound(salt fr.Element, p []fr.El // by replacing x by xᵢ. xis := make([]string, s.nbSteps+1) for i := 0; i < s.nbSteps; i++ { - xis[i] = paddNaming(fmt.Sprintf("x%d", i), fr.Bytes) + xis[i] = fmt.Sprintf("x%d", i) } - xis[s.nbSteps] = paddNaming("s0", fr.Bytes) + xis[s.nbSteps] = "s0" fs := fiatshamir.NewTranscript(s.h, xis...) // the salt is binded to the first challenge, to ensure the challenges @@ -549,9 +537,9 @@ func (s radixTwoFri) verifyProofOfProximitySingleRound(salt fr.Element, proof Ro // Fiat Shamir transcript to derive the challenges xis := make([]string, s.nbSteps+1) for i := 0; i < s.nbSteps; i++ { - xis[i] = paddNaming(fmt.Sprintf("x%d", i), fr.Bytes) + xis[i] = fmt.Sprintf("x%d", i) } - xis[s.nbSteps] = paddNaming("s0", fr.Bytes) + xis[s.nbSteps] = "s0" fs := fiatshamir.NewTranscript(s.h, xis...) xi := make([]fr.Element, s.nbSteps) diff --git a/ecc/bls12-381/fr/gkr/gkr.go b/ecc/bls12-381/fr/gkr/gkr.go index 7de6aa7df..64b48da06 100644 --- a/ecc/bls12-381/fr/gkr/gkr.go +++ b/ecc/bls12-381/fr/gkr/gkr.go @@ -490,9 +490,7 @@ func setup(c Circuit, assignment WireAssignment, transcriptSettings fiatshamir.S if transcriptSettings.Transcript == nil { challengeNames := ChallengeNames(o.sorted, o.nbVars, transcriptSettings.Prefix) - transcript := fiatshamir.NewTranscript( - transcriptSettings.Hash, challengeNames...) - o.transcript = &transcript + o.transcript = fiatshamir.NewTranscript(transcriptSettings.Hash, challengeNames...) for i := range transcriptSettings.BaseChallenges { if err = o.transcript.Bind(challengeNames[0], transcriptSettings.BaseChallenges[i]); err != nil { return o, err diff --git a/ecc/bls12-381/fr/mimc/mimc.go b/ecc/bls12-381/fr/mimc/mimc.go index 577768363..716a655b4 100644 --- a/ecc/bls12-381/fr/mimc/mimc.go +++ b/ecc/bls12-381/fr/mimc/mimc.go @@ -100,6 +100,14 @@ func (d *digest) BlockSize() int { // // To hash arbitrary data ([]byte not representing canonical field elements) use fr.Hash first func (d *digest) Write(p []byte) (int, error) { + // we usually expect multiple of block size. But sometimes we hash short + // values (FS transcript). Instead of forcing to hash to field, we left-pad the + // input here. + if len(p) > 0 && len(p) < BlockSize { + pp := make([]byte, BlockSize) + copy(pp[len(pp)-len(p):], p) + p = pp + } var start int for start = 0; start < len(p); start += BlockSize { @@ -183,10 +191,11 @@ func initConstants() { } // WriteString writes a string that doesn't necessarily consist of field elements -func (d *digest) WriteString(rawBytes []byte) { +func (d *digest) WriteString(rawBytes []byte) error { if elems, err := fr.Hash(rawBytes, []byte("string:"), 1); err != nil { - panic(err) + return err } else { d.data = append(d.data, elems[0]) } + return nil } diff --git a/ecc/bls12-381/fr/permutation/permutation.go b/ecc/bls12-381/fr/permutation/permutation.go index 778f4ea48..00c0cebfd 100644 --- a/ecc/bls12-381/fr/permutation/permutation.go +++ b/ecc/bls12-381/fr/permutation/permutation.go @@ -177,7 +177,7 @@ func Prove(pk kzg.ProvingKey, t1, t2 []fr.Element) (Proof, error) { } // derive challenge for z - epsilon, err := deriveRandomness(&fs, "epsilon", &proof.t1, &proof.t2) + epsilon, err := deriveRandomness(fs, "epsilon", &proof.t1, &proof.t2) if err != nil { return proof, err } @@ -206,7 +206,7 @@ func Prove(pk kzg.ProvingKey, t1, t2 []fr.Element) (Proof, error) { lsNum := evaluateSecondPartNumReverse(lz, d) // derive challenge used for the folding - omega, err := deriveRandomness(&fs, "omega", &proof.z) + omega, err := deriveRandomness(fs, "omega", &proof.z) if err != nil { return proof, err } @@ -229,7 +229,7 @@ func Prove(pk kzg.ProvingKey, t1, t2 []fr.Element) (Proof, error) { } // derive the evaluation challenge - eta, err := deriveRandomness(&fs, "eta", &proof.q) + eta, err := deriveRandomness(fs, "eta", &proof.q) if err != nil { return proof, err } @@ -282,17 +282,17 @@ func Verify(vk kzg.VerifyingKey, proof Proof) error { fs := fiatshamir.NewTranscript(hFunc, "epsilon", "omega", "eta") // derive the challenges - epsilon, err := deriveRandomness(&fs, "epsilon", &proof.t1, &proof.t2) + epsilon, err := deriveRandomness(fs, "epsilon", &proof.t1, &proof.t2) if err != nil { return err } - omega, err := deriveRandomness(&fs, "omega", &proof.z) + omega, err := deriveRandomness(fs, "omega", &proof.z) if err != nil { return err } - eta, err := deriveRandomness(&fs, "eta", &proof.q) + eta, err := deriveRandomness(fs, "eta", &proof.q) if err != nil { return err } diff --git a/ecc/bls12-381/fr/plookup/table.go b/ecc/bls12-381/fr/plookup/table.go index cf11e8965..c191752da 100644 --- a/ecc/bls12-381/fr/plookup/table.go +++ b/ecc/bls12-381/fr/plookup/table.go @@ -145,7 +145,7 @@ func ProveLookupTables(pk kzg.ProvingKey, f, t []fr.Vector) (ProofLookupTables, comms[nbRows+i] = new(kzg.Digest) comms[nbRows+i].Set(&proof.ts[i]) } - lambda, err := deriveRandomness(&fs, "lambda", comms...) + lambda, err := deriveRandomness(fs, "lambda", comms...) if err != nil { return proof, err } @@ -197,7 +197,7 @@ func VerifyLookupTables(vk kzg.VerifyingKey, proof ProofLookupTables) error { comms[i] = &proof.fs[i] comms[i+nbRows] = &proof.ts[i] } - lambda, err := deriveRandomness(&fs, "lambda", comms...) + lambda, err := deriveRandomness(fs, "lambda", comms...) if err != nil { return err } diff --git a/ecc/bls12-381/fr/plookup/vector.go b/ecc/bls12-381/fr/plookup/vector.go index 044835c32..4ed22fb16 100644 --- a/ecc/bls12-381/fr/plookup/vector.go +++ b/ecc/bls12-381/fr/plookup/vector.go @@ -441,11 +441,11 @@ func ProveLookupVector(pk kzg.ProvingKey, f, t fr.Vector) (ProofLookupVector, er } // derive beta, gamma - beta, err := deriveRandomness(&fs, "beta", &proof.t, &proof.f, &proof.h1, &proof.h2) + beta, err := deriveRandomness(fs, "beta", &proof.t, &proof.f, &proof.h1, &proof.h2) if err != nil { return proof, err } - gamma, err := deriveRandomness(&fs, "gamma") + gamma, err := deriveRandomness(fs, "gamma") if err != nil { return proof, err } @@ -495,7 +495,7 @@ func ProveLookupVector(pk kzg.ProvingKey, f, t fr.Vector) (ProofLookupVector, er lh1h2 := evaluateOverlapH1h2BitReversed(_lh1, _lh2, domainBig) // compute the quotient - alpha, err := deriveRandomness(&fs, "alpha", &proof.z) + alpha, err := deriveRandomness(fs, "alpha", &proof.z) if err != nil { return proof, err } @@ -506,7 +506,7 @@ func ProveLookupVector(pk kzg.ProvingKey, f, t fr.Vector) (ProofLookupVector, er } // build the opening proofs - nu, err := deriveRandomness(&fs, "nu", &proof.h) + nu, err := deriveRandomness(fs, "nu", &proof.h) if err != nil { return proof, err } @@ -570,22 +570,22 @@ func VerifyLookupVector(vk kzg.VerifyingKey, proof ProofLookupVector) error { fs := fiatshamir.NewTranscript(hFunc, "beta", "gamma", "alpha", "nu") // derive the various challenges - beta, err := deriveRandomness(&fs, "beta", &proof.t, &proof.f, &proof.h1, &proof.h2) + beta, err := deriveRandomness(fs, "beta", &proof.t, &proof.f, &proof.h1, &proof.h2) if err != nil { return err } - gamma, err := deriveRandomness(&fs, "gamma") + gamma, err := deriveRandomness(fs, "gamma") if err != nil { return err } - alpha, err := deriveRandomness(&fs, "alpha", &proof.z) + alpha, err := deriveRandomness(fs, "alpha", &proof.z) if err != nil { return err } - nu, err := deriveRandomness(&fs, "nu", &proof.h) + nu, err := deriveRandomness(fs, "nu", &proof.h) if err != nil { return err } diff --git a/ecc/bls12-381/fr/sumcheck/sumcheck.go b/ecc/bls12-381/fr/sumcheck/sumcheck.go index ee3675773..7f7d605ef 100644 --- a/ecc/bls12-381/fr/sumcheck/sumcheck.go +++ b/ecc/bls12-381/fr/sumcheck/sumcheck.go @@ -67,7 +67,7 @@ func setupTranscript(claimsNum int, varsNum int, settings *fiatshamir.Settings) } if settings.Transcript == nil { transcript := fiatshamir.NewTranscript(settings.Hash, challengeNames...) - settings.Transcript = &transcript + settings.Transcript = transcript } for i := range settings.BaseChallenges { diff --git a/ecc/bls24-315/fr/fri/fri.go b/ecc/bls24-315/fr/fri/fri.go index b117c0235..10156d62f 100644 --- a/ecc/bls24-315/fr/fri/fri.go +++ b/ecc/bls24-315/fr/fri/fri.go @@ -365,18 +365,6 @@ func foldPolynomialLagrangeBasis(pSorted []fr.Element, gInv, x fr.Element) []fr. return res } -// paddNaming takes s = 0xA1.... and turns -// it into s' = 0xA1.. || 0..0 of size frSize bytes. -// Using this, when writing the domain separator in FiatShamir, it takes -// the same size as a snark variable (=number of byte in the block of a snark compliant -// hash function like mimc), so it is compliant with snark circuit. -func paddNaming(s string, size int) string { - a := make([]byte, size) - b := []byte(s) - copy(a, b) - return string(a) -} - // buildProofOfProximitySingleRound generates a proof that a function, given as an oracle from // the verifier point of view, is in fact δ-close to a polynomial. // * salt is a variable for multi rounds, it allows to generate different challenges using Fiat Shamir @@ -395,9 +383,9 @@ func (s radixTwoFri) buildProofOfProximitySingleRound(salt fr.Element, p []fr.El // by replacing x by xᵢ. xis := make([]string, s.nbSteps+1) for i := 0; i < s.nbSteps; i++ { - xis[i] = paddNaming(fmt.Sprintf("x%d", i), fr.Bytes) + xis[i] = fmt.Sprintf("x%d", i) } - xis[s.nbSteps] = paddNaming("s0", fr.Bytes) + xis[s.nbSteps] = "s0" fs := fiatshamir.NewTranscript(s.h, xis...) // the salt is binded to the first challenge, to ensure the challenges @@ -549,9 +537,9 @@ func (s radixTwoFri) verifyProofOfProximitySingleRound(salt fr.Element, proof Ro // Fiat Shamir transcript to derive the challenges xis := make([]string, s.nbSteps+1) for i := 0; i < s.nbSteps; i++ { - xis[i] = paddNaming(fmt.Sprintf("x%d", i), fr.Bytes) + xis[i] = fmt.Sprintf("x%d", i) } - xis[s.nbSteps] = paddNaming("s0", fr.Bytes) + xis[s.nbSteps] = "s0" fs := fiatshamir.NewTranscript(s.h, xis...) xi := make([]fr.Element, s.nbSteps) diff --git a/ecc/bls24-315/fr/gkr/gkr.go b/ecc/bls24-315/fr/gkr/gkr.go index 968acb37d..ca1f4c833 100644 --- a/ecc/bls24-315/fr/gkr/gkr.go +++ b/ecc/bls24-315/fr/gkr/gkr.go @@ -490,9 +490,7 @@ func setup(c Circuit, assignment WireAssignment, transcriptSettings fiatshamir.S if transcriptSettings.Transcript == nil { challengeNames := ChallengeNames(o.sorted, o.nbVars, transcriptSettings.Prefix) - transcript := fiatshamir.NewTranscript( - transcriptSettings.Hash, challengeNames...) - o.transcript = &transcript + o.transcript = fiatshamir.NewTranscript(transcriptSettings.Hash, challengeNames...) for i := range transcriptSettings.BaseChallenges { if err = o.transcript.Bind(challengeNames[0], transcriptSettings.BaseChallenges[i]); err != nil { return o, err diff --git a/ecc/bls24-315/fr/mimc/mimc.go b/ecc/bls24-315/fr/mimc/mimc.go index 61137054e..1912d66df 100644 --- a/ecc/bls24-315/fr/mimc/mimc.go +++ b/ecc/bls24-315/fr/mimc/mimc.go @@ -100,6 +100,14 @@ func (d *digest) BlockSize() int { // // To hash arbitrary data ([]byte not representing canonical field elements) use fr.Hash first func (d *digest) Write(p []byte) (int, error) { + // we usually expect multiple of block size. But sometimes we hash short + // values (FS transcript). Instead of forcing to hash to field, we left-pad the + // input here. + if len(p) > 0 && len(p) < BlockSize { + pp := make([]byte, BlockSize) + copy(pp[len(pp)-len(p):], p) + p = pp + } var start int for start = 0; start < len(p); start += BlockSize { @@ -183,10 +191,11 @@ func initConstants() { } // WriteString writes a string that doesn't necessarily consist of field elements -func (d *digest) WriteString(rawBytes []byte) { +func (d *digest) WriteString(rawBytes []byte) error { if elems, err := fr.Hash(rawBytes, []byte("string:"), 1); err != nil { - panic(err) + return err } else { d.data = append(d.data, elems[0]) } + return nil } diff --git a/ecc/bls24-315/fr/permutation/permutation.go b/ecc/bls24-315/fr/permutation/permutation.go index b45676c52..6a87a7c92 100644 --- a/ecc/bls24-315/fr/permutation/permutation.go +++ b/ecc/bls24-315/fr/permutation/permutation.go @@ -177,7 +177,7 @@ func Prove(pk kzg.ProvingKey, t1, t2 []fr.Element) (Proof, error) { } // derive challenge for z - epsilon, err := deriveRandomness(&fs, "epsilon", &proof.t1, &proof.t2) + epsilon, err := deriveRandomness(fs, "epsilon", &proof.t1, &proof.t2) if err != nil { return proof, err } @@ -206,7 +206,7 @@ func Prove(pk kzg.ProvingKey, t1, t2 []fr.Element) (Proof, error) { lsNum := evaluateSecondPartNumReverse(lz, d) // derive challenge used for the folding - omega, err := deriveRandomness(&fs, "omega", &proof.z) + omega, err := deriveRandomness(fs, "omega", &proof.z) if err != nil { return proof, err } @@ -229,7 +229,7 @@ func Prove(pk kzg.ProvingKey, t1, t2 []fr.Element) (Proof, error) { } // derive the evaluation challenge - eta, err := deriveRandomness(&fs, "eta", &proof.q) + eta, err := deriveRandomness(fs, "eta", &proof.q) if err != nil { return proof, err } @@ -282,17 +282,17 @@ func Verify(vk kzg.VerifyingKey, proof Proof) error { fs := fiatshamir.NewTranscript(hFunc, "epsilon", "omega", "eta") // derive the challenges - epsilon, err := deriveRandomness(&fs, "epsilon", &proof.t1, &proof.t2) + epsilon, err := deriveRandomness(fs, "epsilon", &proof.t1, &proof.t2) if err != nil { return err } - omega, err := deriveRandomness(&fs, "omega", &proof.z) + omega, err := deriveRandomness(fs, "omega", &proof.z) if err != nil { return err } - eta, err := deriveRandomness(&fs, "eta", &proof.q) + eta, err := deriveRandomness(fs, "eta", &proof.q) if err != nil { return err } diff --git a/ecc/bls24-315/fr/plookup/table.go b/ecc/bls24-315/fr/plookup/table.go index 51c8858c2..b710796f2 100644 --- a/ecc/bls24-315/fr/plookup/table.go +++ b/ecc/bls24-315/fr/plookup/table.go @@ -145,7 +145,7 @@ func ProveLookupTables(pk kzg.ProvingKey, f, t []fr.Vector) (ProofLookupTables, comms[nbRows+i] = new(kzg.Digest) comms[nbRows+i].Set(&proof.ts[i]) } - lambda, err := deriveRandomness(&fs, "lambda", comms...) + lambda, err := deriveRandomness(fs, "lambda", comms...) if err != nil { return proof, err } @@ -197,7 +197,7 @@ func VerifyLookupTables(vk kzg.VerifyingKey, proof ProofLookupTables) error { comms[i] = &proof.fs[i] comms[i+nbRows] = &proof.ts[i] } - lambda, err := deriveRandomness(&fs, "lambda", comms...) + lambda, err := deriveRandomness(fs, "lambda", comms...) if err != nil { return err } diff --git a/ecc/bls24-315/fr/plookup/vector.go b/ecc/bls24-315/fr/plookup/vector.go index a446e2e25..6fefe36ac 100644 --- a/ecc/bls24-315/fr/plookup/vector.go +++ b/ecc/bls24-315/fr/plookup/vector.go @@ -441,11 +441,11 @@ func ProveLookupVector(pk kzg.ProvingKey, f, t fr.Vector) (ProofLookupVector, er } // derive beta, gamma - beta, err := deriveRandomness(&fs, "beta", &proof.t, &proof.f, &proof.h1, &proof.h2) + beta, err := deriveRandomness(fs, "beta", &proof.t, &proof.f, &proof.h1, &proof.h2) if err != nil { return proof, err } - gamma, err := deriveRandomness(&fs, "gamma") + gamma, err := deriveRandomness(fs, "gamma") if err != nil { return proof, err } @@ -495,7 +495,7 @@ func ProveLookupVector(pk kzg.ProvingKey, f, t fr.Vector) (ProofLookupVector, er lh1h2 := evaluateOverlapH1h2BitReversed(_lh1, _lh2, domainBig) // compute the quotient - alpha, err := deriveRandomness(&fs, "alpha", &proof.z) + alpha, err := deriveRandomness(fs, "alpha", &proof.z) if err != nil { return proof, err } @@ -506,7 +506,7 @@ func ProveLookupVector(pk kzg.ProvingKey, f, t fr.Vector) (ProofLookupVector, er } // build the opening proofs - nu, err := deriveRandomness(&fs, "nu", &proof.h) + nu, err := deriveRandomness(fs, "nu", &proof.h) if err != nil { return proof, err } @@ -570,22 +570,22 @@ func VerifyLookupVector(vk kzg.VerifyingKey, proof ProofLookupVector) error { fs := fiatshamir.NewTranscript(hFunc, "beta", "gamma", "alpha", "nu") // derive the various challenges - beta, err := deriveRandomness(&fs, "beta", &proof.t, &proof.f, &proof.h1, &proof.h2) + beta, err := deriveRandomness(fs, "beta", &proof.t, &proof.f, &proof.h1, &proof.h2) if err != nil { return err } - gamma, err := deriveRandomness(&fs, "gamma") + gamma, err := deriveRandomness(fs, "gamma") if err != nil { return err } - alpha, err := deriveRandomness(&fs, "alpha", &proof.z) + alpha, err := deriveRandomness(fs, "alpha", &proof.z) if err != nil { return err } - nu, err := deriveRandomness(&fs, "nu", &proof.h) + nu, err := deriveRandomness(fs, "nu", &proof.h) if err != nil { return err } diff --git a/ecc/bls24-315/fr/sumcheck/sumcheck.go b/ecc/bls24-315/fr/sumcheck/sumcheck.go index ba4f2c1eb..3c7412347 100644 --- a/ecc/bls24-315/fr/sumcheck/sumcheck.go +++ b/ecc/bls24-315/fr/sumcheck/sumcheck.go @@ -67,7 +67,7 @@ func setupTranscript(claimsNum int, varsNum int, settings *fiatshamir.Settings) } if settings.Transcript == nil { transcript := fiatshamir.NewTranscript(settings.Hash, challengeNames...) - settings.Transcript = &transcript + settings.Transcript = transcript } for i := range settings.BaseChallenges { diff --git a/ecc/bls24-317/fr/fri/fri.go b/ecc/bls24-317/fr/fri/fri.go index 135cfb127..cbac4e378 100644 --- a/ecc/bls24-317/fr/fri/fri.go +++ b/ecc/bls24-317/fr/fri/fri.go @@ -365,18 +365,6 @@ func foldPolynomialLagrangeBasis(pSorted []fr.Element, gInv, x fr.Element) []fr. return res } -// paddNaming takes s = 0xA1.... and turns -// it into s' = 0xA1.. || 0..0 of size frSize bytes. -// Using this, when writing the domain separator in FiatShamir, it takes -// the same size as a snark variable (=number of byte in the block of a snark compliant -// hash function like mimc), so it is compliant with snark circuit. -func paddNaming(s string, size int) string { - a := make([]byte, size) - b := []byte(s) - copy(a, b) - return string(a) -} - // buildProofOfProximitySingleRound generates a proof that a function, given as an oracle from // the verifier point of view, is in fact δ-close to a polynomial. // * salt is a variable for multi rounds, it allows to generate different challenges using Fiat Shamir @@ -395,9 +383,9 @@ func (s radixTwoFri) buildProofOfProximitySingleRound(salt fr.Element, p []fr.El // by replacing x by xᵢ. xis := make([]string, s.nbSteps+1) for i := 0; i < s.nbSteps; i++ { - xis[i] = paddNaming(fmt.Sprintf("x%d", i), fr.Bytes) + xis[i] = fmt.Sprintf("x%d", i) } - xis[s.nbSteps] = paddNaming("s0", fr.Bytes) + xis[s.nbSteps] = "s0" fs := fiatshamir.NewTranscript(s.h, xis...) // the salt is binded to the first challenge, to ensure the challenges @@ -549,9 +537,9 @@ func (s radixTwoFri) verifyProofOfProximitySingleRound(salt fr.Element, proof Ro // Fiat Shamir transcript to derive the challenges xis := make([]string, s.nbSteps+1) for i := 0; i < s.nbSteps; i++ { - xis[i] = paddNaming(fmt.Sprintf("x%d", i), fr.Bytes) + xis[i] = fmt.Sprintf("x%d", i) } - xis[s.nbSteps] = paddNaming("s0", fr.Bytes) + xis[s.nbSteps] = "s0" fs := fiatshamir.NewTranscript(s.h, xis...) xi := make([]fr.Element, s.nbSteps) diff --git a/ecc/bls24-317/fr/gkr/gkr.go b/ecc/bls24-317/fr/gkr/gkr.go index a9c4f9670..0dc5b4883 100644 --- a/ecc/bls24-317/fr/gkr/gkr.go +++ b/ecc/bls24-317/fr/gkr/gkr.go @@ -490,9 +490,7 @@ func setup(c Circuit, assignment WireAssignment, transcriptSettings fiatshamir.S if transcriptSettings.Transcript == nil { challengeNames := ChallengeNames(o.sorted, o.nbVars, transcriptSettings.Prefix) - transcript := fiatshamir.NewTranscript( - transcriptSettings.Hash, challengeNames...) - o.transcript = &transcript + o.transcript = fiatshamir.NewTranscript(transcriptSettings.Hash, challengeNames...) for i := range transcriptSettings.BaseChallenges { if err = o.transcript.Bind(challengeNames[0], transcriptSettings.BaseChallenges[i]); err != nil { return o, err diff --git a/ecc/bls24-317/fr/mimc/mimc.go b/ecc/bls24-317/fr/mimc/mimc.go index 15b07da35..c0050e056 100644 --- a/ecc/bls24-317/fr/mimc/mimc.go +++ b/ecc/bls24-317/fr/mimc/mimc.go @@ -100,6 +100,14 @@ func (d *digest) BlockSize() int { // // To hash arbitrary data ([]byte not representing canonical field elements) use fr.Hash first func (d *digest) Write(p []byte) (int, error) { + // we usually expect multiple of block size. But sometimes we hash short + // values (FS transcript). Instead of forcing to hash to field, we left-pad the + // input here. + if len(p) > 0 && len(p) < BlockSize { + pp := make([]byte, BlockSize) + copy(pp[len(pp)-len(p):], p) + p = pp + } var start int for start = 0; start < len(p); start += BlockSize { @@ -185,10 +193,11 @@ func initConstants() { } // WriteString writes a string that doesn't necessarily consist of field elements -func (d *digest) WriteString(rawBytes []byte) { +func (d *digest) WriteString(rawBytes []byte) error { if elems, err := fr.Hash(rawBytes, []byte("string:"), 1); err != nil { - panic(err) + return err } else { d.data = append(d.data, elems[0]) } + return nil } diff --git a/ecc/bls24-317/fr/permutation/permutation.go b/ecc/bls24-317/fr/permutation/permutation.go index 8aa2bb92f..ef7b7d2e3 100644 --- a/ecc/bls24-317/fr/permutation/permutation.go +++ b/ecc/bls24-317/fr/permutation/permutation.go @@ -177,7 +177,7 @@ func Prove(pk kzg.ProvingKey, t1, t2 []fr.Element) (Proof, error) { } // derive challenge for z - epsilon, err := deriveRandomness(&fs, "epsilon", &proof.t1, &proof.t2) + epsilon, err := deriveRandomness(fs, "epsilon", &proof.t1, &proof.t2) if err != nil { return proof, err } @@ -206,7 +206,7 @@ func Prove(pk kzg.ProvingKey, t1, t2 []fr.Element) (Proof, error) { lsNum := evaluateSecondPartNumReverse(lz, d) // derive challenge used for the folding - omega, err := deriveRandomness(&fs, "omega", &proof.z) + omega, err := deriveRandomness(fs, "omega", &proof.z) if err != nil { return proof, err } @@ -229,7 +229,7 @@ func Prove(pk kzg.ProvingKey, t1, t2 []fr.Element) (Proof, error) { } // derive the evaluation challenge - eta, err := deriveRandomness(&fs, "eta", &proof.q) + eta, err := deriveRandomness(fs, "eta", &proof.q) if err != nil { return proof, err } @@ -282,17 +282,17 @@ func Verify(vk kzg.VerifyingKey, proof Proof) error { fs := fiatshamir.NewTranscript(hFunc, "epsilon", "omega", "eta") // derive the challenges - epsilon, err := deriveRandomness(&fs, "epsilon", &proof.t1, &proof.t2) + epsilon, err := deriveRandomness(fs, "epsilon", &proof.t1, &proof.t2) if err != nil { return err } - omega, err := deriveRandomness(&fs, "omega", &proof.z) + omega, err := deriveRandomness(fs, "omega", &proof.z) if err != nil { return err } - eta, err := deriveRandomness(&fs, "eta", &proof.q) + eta, err := deriveRandomness(fs, "eta", &proof.q) if err != nil { return err } diff --git a/ecc/bls24-317/fr/plookup/table.go b/ecc/bls24-317/fr/plookup/table.go index 9720f3d37..5c1607cdb 100644 --- a/ecc/bls24-317/fr/plookup/table.go +++ b/ecc/bls24-317/fr/plookup/table.go @@ -145,7 +145,7 @@ func ProveLookupTables(pk kzg.ProvingKey, f, t []fr.Vector) (ProofLookupTables, comms[nbRows+i] = new(kzg.Digest) comms[nbRows+i].Set(&proof.ts[i]) } - lambda, err := deriveRandomness(&fs, "lambda", comms...) + lambda, err := deriveRandomness(fs, "lambda", comms...) if err != nil { return proof, err } @@ -197,7 +197,7 @@ func VerifyLookupTables(vk kzg.VerifyingKey, proof ProofLookupTables) error { comms[i] = &proof.fs[i] comms[i+nbRows] = &proof.ts[i] } - lambda, err := deriveRandomness(&fs, "lambda", comms...) + lambda, err := deriveRandomness(fs, "lambda", comms...) if err != nil { return err } diff --git a/ecc/bls24-317/fr/plookup/vector.go b/ecc/bls24-317/fr/plookup/vector.go index 3d618ff40..05f916788 100644 --- a/ecc/bls24-317/fr/plookup/vector.go +++ b/ecc/bls24-317/fr/plookup/vector.go @@ -441,11 +441,11 @@ func ProveLookupVector(pk kzg.ProvingKey, f, t fr.Vector) (ProofLookupVector, er } // derive beta, gamma - beta, err := deriveRandomness(&fs, "beta", &proof.t, &proof.f, &proof.h1, &proof.h2) + beta, err := deriveRandomness(fs, "beta", &proof.t, &proof.f, &proof.h1, &proof.h2) if err != nil { return proof, err } - gamma, err := deriveRandomness(&fs, "gamma") + gamma, err := deriveRandomness(fs, "gamma") if err != nil { return proof, err } @@ -495,7 +495,7 @@ func ProveLookupVector(pk kzg.ProvingKey, f, t fr.Vector) (ProofLookupVector, er lh1h2 := evaluateOverlapH1h2BitReversed(_lh1, _lh2, domainBig) // compute the quotient - alpha, err := deriveRandomness(&fs, "alpha", &proof.z) + alpha, err := deriveRandomness(fs, "alpha", &proof.z) if err != nil { return proof, err } @@ -506,7 +506,7 @@ func ProveLookupVector(pk kzg.ProvingKey, f, t fr.Vector) (ProofLookupVector, er } // build the opening proofs - nu, err := deriveRandomness(&fs, "nu", &proof.h) + nu, err := deriveRandomness(fs, "nu", &proof.h) if err != nil { return proof, err } @@ -570,22 +570,22 @@ func VerifyLookupVector(vk kzg.VerifyingKey, proof ProofLookupVector) error { fs := fiatshamir.NewTranscript(hFunc, "beta", "gamma", "alpha", "nu") // derive the various challenges - beta, err := deriveRandomness(&fs, "beta", &proof.t, &proof.f, &proof.h1, &proof.h2) + beta, err := deriveRandomness(fs, "beta", &proof.t, &proof.f, &proof.h1, &proof.h2) if err != nil { return err } - gamma, err := deriveRandomness(&fs, "gamma") + gamma, err := deriveRandomness(fs, "gamma") if err != nil { return err } - alpha, err := deriveRandomness(&fs, "alpha", &proof.z) + alpha, err := deriveRandomness(fs, "alpha", &proof.z) if err != nil { return err } - nu, err := deriveRandomness(&fs, "nu", &proof.h) + nu, err := deriveRandomness(fs, "nu", &proof.h) if err != nil { return err } diff --git a/ecc/bls24-317/fr/sumcheck/sumcheck.go b/ecc/bls24-317/fr/sumcheck/sumcheck.go index 5d294c205..81ff2e5f2 100644 --- a/ecc/bls24-317/fr/sumcheck/sumcheck.go +++ b/ecc/bls24-317/fr/sumcheck/sumcheck.go @@ -67,7 +67,7 @@ func setupTranscript(claimsNum int, varsNum int, settings *fiatshamir.Settings) } if settings.Transcript == nil { transcript := fiatshamir.NewTranscript(settings.Hash, challengeNames...) - settings.Transcript = &transcript + settings.Transcript = transcript } for i := range settings.BaseChallenges { diff --git a/ecc/bn254/fr/fri/fri.go b/ecc/bn254/fr/fri/fri.go index 6559829ec..0bec8575d 100644 --- a/ecc/bn254/fr/fri/fri.go +++ b/ecc/bn254/fr/fri/fri.go @@ -365,18 +365,6 @@ func foldPolynomialLagrangeBasis(pSorted []fr.Element, gInv, x fr.Element) []fr. return res } -// paddNaming takes s = 0xA1.... and turns -// it into s' = 0xA1.. || 0..0 of size frSize bytes. -// Using this, when writing the domain separator in FiatShamir, it takes -// the same size as a snark variable (=number of byte in the block of a snark compliant -// hash function like mimc), so it is compliant with snark circuit. -func paddNaming(s string, size int) string { - a := make([]byte, size) - b := []byte(s) - copy(a, b) - return string(a) -} - // buildProofOfProximitySingleRound generates a proof that a function, given as an oracle from // the verifier point of view, is in fact δ-close to a polynomial. // * salt is a variable for multi rounds, it allows to generate different challenges using Fiat Shamir @@ -395,9 +383,9 @@ func (s radixTwoFri) buildProofOfProximitySingleRound(salt fr.Element, p []fr.El // by replacing x by xᵢ. xis := make([]string, s.nbSteps+1) for i := 0; i < s.nbSteps; i++ { - xis[i] = paddNaming(fmt.Sprintf("x%d", i), fr.Bytes) + xis[i] = fmt.Sprintf("x%d", i) } - xis[s.nbSteps] = paddNaming("s0", fr.Bytes) + xis[s.nbSteps] = "s0" fs := fiatshamir.NewTranscript(s.h, xis...) // the salt is binded to the first challenge, to ensure the challenges @@ -549,9 +537,9 @@ func (s radixTwoFri) verifyProofOfProximitySingleRound(salt fr.Element, proof Ro // Fiat Shamir transcript to derive the challenges xis := make([]string, s.nbSteps+1) for i := 0; i < s.nbSteps; i++ { - xis[i] = paddNaming(fmt.Sprintf("x%d", i), fr.Bytes) + xis[i] = fmt.Sprintf("x%d", i) } - xis[s.nbSteps] = paddNaming("s0", fr.Bytes) + xis[s.nbSteps] = "s0" fs := fiatshamir.NewTranscript(s.h, xis...) xi := make([]fr.Element, s.nbSteps) diff --git a/ecc/bn254/fr/gkr/gkr.go b/ecc/bn254/fr/gkr/gkr.go index a96fb9110..df189b19d 100644 --- a/ecc/bn254/fr/gkr/gkr.go +++ b/ecc/bn254/fr/gkr/gkr.go @@ -490,9 +490,7 @@ func setup(c Circuit, assignment WireAssignment, transcriptSettings fiatshamir.S if transcriptSettings.Transcript == nil { challengeNames := ChallengeNames(o.sorted, o.nbVars, transcriptSettings.Prefix) - transcript := fiatshamir.NewTranscript( - transcriptSettings.Hash, challengeNames...) - o.transcript = &transcript + o.transcript = fiatshamir.NewTranscript(transcriptSettings.Hash, challengeNames...) for i := range transcriptSettings.BaseChallenges { if err = o.transcript.Bind(challengeNames[0], transcriptSettings.BaseChallenges[i]); err != nil { return o, err diff --git a/ecc/bn254/fr/mimc/mimc.go b/ecc/bn254/fr/mimc/mimc.go index 254ef43bd..719ed4e8a 100644 --- a/ecc/bn254/fr/mimc/mimc.go +++ b/ecc/bn254/fr/mimc/mimc.go @@ -100,6 +100,14 @@ func (d *digest) BlockSize() int { // // To hash arbitrary data ([]byte not representing canonical field elements) use fr.Hash first func (d *digest) Write(p []byte) (int, error) { + // we usually expect multiple of block size. But sometimes we hash short + // values (FS transcript). Instead of forcing to hash to field, we left-pad the + // input here. + if len(p) > 0 && len(p) < BlockSize { + pp := make([]byte, BlockSize) + copy(pp[len(pp)-len(p):], p) + p = pp + } var start int for start = 0; start < len(p); start += BlockSize { @@ -183,10 +191,11 @@ func initConstants() { } // WriteString writes a string that doesn't necessarily consist of field elements -func (d *digest) WriteString(rawBytes []byte) { +func (d *digest) WriteString(rawBytes []byte) error { if elems, err := fr.Hash(rawBytes, []byte("string:"), 1); err != nil { - panic(err) + return err } else { d.data = append(d.data, elems[0]) } + return nil } diff --git a/ecc/bn254/fr/mimc/mimc_test.go b/ecc/bn254/fr/mimc/mimc_test.go index 11c693852..dbd9740ad 100644 --- a/ecc/bn254/fr/mimc/mimc_test.go +++ b/ecc/bn254/fr/mimc/mimc_test.go @@ -1,10 +1,11 @@ package mimc_test import ( + "testing" + "github.com/consensys/gnark-crypto/ecc/bn254/fr/mimc" fiatshamir "github.com/consensys/gnark-crypto/fiat-shamir" "github.com/stretchr/testify/assert" - "testing" ) func TestMiMCFiatShamir(t *testing.T) { diff --git a/ecc/bn254/fr/permutation/permutation.go b/ecc/bn254/fr/permutation/permutation.go index b59ab3aaa..83abd07c2 100644 --- a/ecc/bn254/fr/permutation/permutation.go +++ b/ecc/bn254/fr/permutation/permutation.go @@ -177,7 +177,7 @@ func Prove(pk kzg.ProvingKey, t1, t2 []fr.Element) (Proof, error) { } // derive challenge for z - epsilon, err := deriveRandomness(&fs, "epsilon", &proof.t1, &proof.t2) + epsilon, err := deriveRandomness(fs, "epsilon", &proof.t1, &proof.t2) if err != nil { return proof, err } @@ -206,7 +206,7 @@ func Prove(pk kzg.ProvingKey, t1, t2 []fr.Element) (Proof, error) { lsNum := evaluateSecondPartNumReverse(lz, d) // derive challenge used for the folding - omega, err := deriveRandomness(&fs, "omega", &proof.z) + omega, err := deriveRandomness(fs, "omega", &proof.z) if err != nil { return proof, err } @@ -229,7 +229,7 @@ func Prove(pk kzg.ProvingKey, t1, t2 []fr.Element) (Proof, error) { } // derive the evaluation challenge - eta, err := deriveRandomness(&fs, "eta", &proof.q) + eta, err := deriveRandomness(fs, "eta", &proof.q) if err != nil { return proof, err } @@ -282,17 +282,17 @@ func Verify(vk kzg.VerifyingKey, proof Proof) error { fs := fiatshamir.NewTranscript(hFunc, "epsilon", "omega", "eta") // derive the challenges - epsilon, err := deriveRandomness(&fs, "epsilon", &proof.t1, &proof.t2) + epsilon, err := deriveRandomness(fs, "epsilon", &proof.t1, &proof.t2) if err != nil { return err } - omega, err := deriveRandomness(&fs, "omega", &proof.z) + omega, err := deriveRandomness(fs, "omega", &proof.z) if err != nil { return err } - eta, err := deriveRandomness(&fs, "eta", &proof.q) + eta, err := deriveRandomness(fs, "eta", &proof.q) if err != nil { return err } diff --git a/ecc/bn254/fr/plookup/table.go b/ecc/bn254/fr/plookup/table.go index 7851831e7..fe37c0d1b 100644 --- a/ecc/bn254/fr/plookup/table.go +++ b/ecc/bn254/fr/plookup/table.go @@ -145,7 +145,7 @@ func ProveLookupTables(pk kzg.ProvingKey, f, t []fr.Vector) (ProofLookupTables, comms[nbRows+i] = new(kzg.Digest) comms[nbRows+i].Set(&proof.ts[i]) } - lambda, err := deriveRandomness(&fs, "lambda", comms...) + lambda, err := deriveRandomness(fs, "lambda", comms...) if err != nil { return proof, err } @@ -197,7 +197,7 @@ func VerifyLookupTables(vk kzg.VerifyingKey, proof ProofLookupTables) error { comms[i] = &proof.fs[i] comms[i+nbRows] = &proof.ts[i] } - lambda, err := deriveRandomness(&fs, "lambda", comms...) + lambda, err := deriveRandomness(fs, "lambda", comms...) if err != nil { return err } diff --git a/ecc/bn254/fr/plookup/vector.go b/ecc/bn254/fr/plookup/vector.go index 93816fdab..f6adf0bde 100644 --- a/ecc/bn254/fr/plookup/vector.go +++ b/ecc/bn254/fr/plookup/vector.go @@ -441,11 +441,11 @@ func ProveLookupVector(pk kzg.ProvingKey, f, t fr.Vector) (ProofLookupVector, er } // derive beta, gamma - beta, err := deriveRandomness(&fs, "beta", &proof.t, &proof.f, &proof.h1, &proof.h2) + beta, err := deriveRandomness(fs, "beta", &proof.t, &proof.f, &proof.h1, &proof.h2) if err != nil { return proof, err } - gamma, err := deriveRandomness(&fs, "gamma") + gamma, err := deriveRandomness(fs, "gamma") if err != nil { return proof, err } @@ -495,7 +495,7 @@ func ProveLookupVector(pk kzg.ProvingKey, f, t fr.Vector) (ProofLookupVector, er lh1h2 := evaluateOverlapH1h2BitReversed(_lh1, _lh2, domainBig) // compute the quotient - alpha, err := deriveRandomness(&fs, "alpha", &proof.z) + alpha, err := deriveRandomness(fs, "alpha", &proof.z) if err != nil { return proof, err } @@ -506,7 +506,7 @@ func ProveLookupVector(pk kzg.ProvingKey, f, t fr.Vector) (ProofLookupVector, er } // build the opening proofs - nu, err := deriveRandomness(&fs, "nu", &proof.h) + nu, err := deriveRandomness(fs, "nu", &proof.h) if err != nil { return proof, err } @@ -570,22 +570,22 @@ func VerifyLookupVector(vk kzg.VerifyingKey, proof ProofLookupVector) error { fs := fiatshamir.NewTranscript(hFunc, "beta", "gamma", "alpha", "nu") // derive the various challenges - beta, err := deriveRandomness(&fs, "beta", &proof.t, &proof.f, &proof.h1, &proof.h2) + beta, err := deriveRandomness(fs, "beta", &proof.t, &proof.f, &proof.h1, &proof.h2) if err != nil { return err } - gamma, err := deriveRandomness(&fs, "gamma") + gamma, err := deriveRandomness(fs, "gamma") if err != nil { return err } - alpha, err := deriveRandomness(&fs, "alpha", &proof.z) + alpha, err := deriveRandomness(fs, "alpha", &proof.z) if err != nil { return err } - nu, err := deriveRandomness(&fs, "nu", &proof.h) + nu, err := deriveRandomness(fs, "nu", &proof.h) if err != nil { return err } diff --git a/ecc/bn254/fr/sumcheck/sumcheck.go b/ecc/bn254/fr/sumcheck/sumcheck.go index 104a52e7e..473066bb5 100644 --- a/ecc/bn254/fr/sumcheck/sumcheck.go +++ b/ecc/bn254/fr/sumcheck/sumcheck.go @@ -67,7 +67,7 @@ func setupTranscript(claimsNum int, varsNum int, settings *fiatshamir.Settings) } if settings.Transcript == nil { transcript := fiatshamir.NewTranscript(settings.Hash, challengeNames...) - settings.Transcript = &transcript + settings.Transcript = transcript } for i := range settings.BaseChallenges { diff --git a/ecc/bn254/fr/test_vector_utils/test_vector_utils_test.go b/ecc/bn254/fr/test_vector_utils/test_vector_utils_test.go index dc14edf51..261b27686 100644 --- a/ecc/bn254/fr/test_vector_utils/test_vector_utils_test.go +++ b/ecc/bn254/fr/test_vector_utils/test_vector_utils_test.go @@ -1,10 +1,11 @@ package test_vector_utils import ( + "testing" + fiatshamir "github.com/consensys/gnark-crypto/fiat-shamir" "github.com/consensys/gnark-crypto/internal/generator/test_vector_utils/small_rational/test_vector_utils" "github.com/stretchr/testify/assert" - "testing" ) func TestCounterTranscriptInequality(t *testing.T) { diff --git a/ecc/bw6-633/fr/fri/fri.go b/ecc/bw6-633/fr/fri/fri.go index 70e927600..b90dbc75f 100644 --- a/ecc/bw6-633/fr/fri/fri.go +++ b/ecc/bw6-633/fr/fri/fri.go @@ -365,18 +365,6 @@ func foldPolynomialLagrangeBasis(pSorted []fr.Element, gInv, x fr.Element) []fr. return res } -// paddNaming takes s = 0xA1.... and turns -// it into s' = 0xA1.. || 0..0 of size frSize bytes. -// Using this, when writing the domain separator in FiatShamir, it takes -// the same size as a snark variable (=number of byte in the block of a snark compliant -// hash function like mimc), so it is compliant with snark circuit. -func paddNaming(s string, size int) string { - a := make([]byte, size) - b := []byte(s) - copy(a, b) - return string(a) -} - // buildProofOfProximitySingleRound generates a proof that a function, given as an oracle from // the verifier point of view, is in fact δ-close to a polynomial. // * salt is a variable for multi rounds, it allows to generate different challenges using Fiat Shamir @@ -395,9 +383,9 @@ func (s radixTwoFri) buildProofOfProximitySingleRound(salt fr.Element, p []fr.El // by replacing x by xᵢ. xis := make([]string, s.nbSteps+1) for i := 0; i < s.nbSteps; i++ { - xis[i] = paddNaming(fmt.Sprintf("x%d", i), fr.Bytes) + xis[i] = fmt.Sprintf("x%d", i) } - xis[s.nbSteps] = paddNaming("s0", fr.Bytes) + xis[s.nbSteps] = "s0" fs := fiatshamir.NewTranscript(s.h, xis...) // the salt is binded to the first challenge, to ensure the challenges @@ -549,9 +537,9 @@ func (s radixTwoFri) verifyProofOfProximitySingleRound(salt fr.Element, proof Ro // Fiat Shamir transcript to derive the challenges xis := make([]string, s.nbSteps+1) for i := 0; i < s.nbSteps; i++ { - xis[i] = paddNaming(fmt.Sprintf("x%d", i), fr.Bytes) + xis[i] = fmt.Sprintf("x%d", i) } - xis[s.nbSteps] = paddNaming("s0", fr.Bytes) + xis[s.nbSteps] = "s0" fs := fiatshamir.NewTranscript(s.h, xis...) xi := make([]fr.Element, s.nbSteps) diff --git a/ecc/bw6-633/fr/gkr/gkr.go b/ecc/bw6-633/fr/gkr/gkr.go index b9c27df17..888c2c3c5 100644 --- a/ecc/bw6-633/fr/gkr/gkr.go +++ b/ecc/bw6-633/fr/gkr/gkr.go @@ -490,9 +490,7 @@ func setup(c Circuit, assignment WireAssignment, transcriptSettings fiatshamir.S if transcriptSettings.Transcript == nil { challengeNames := ChallengeNames(o.sorted, o.nbVars, transcriptSettings.Prefix) - transcript := fiatshamir.NewTranscript( - transcriptSettings.Hash, challengeNames...) - o.transcript = &transcript + o.transcript = fiatshamir.NewTranscript(transcriptSettings.Hash, challengeNames...) for i := range transcriptSettings.BaseChallenges { if err = o.transcript.Bind(challengeNames[0], transcriptSettings.BaseChallenges[i]); err != nil { return o, err diff --git a/ecc/bw6-633/fr/mimc/mimc.go b/ecc/bw6-633/fr/mimc/mimc.go index 4ee249897..9cce55e36 100644 --- a/ecc/bw6-633/fr/mimc/mimc.go +++ b/ecc/bw6-633/fr/mimc/mimc.go @@ -100,6 +100,14 @@ func (d *digest) BlockSize() int { // // To hash arbitrary data ([]byte not representing canonical field elements) use fr.Hash first func (d *digest) Write(p []byte) (int, error) { + // we usually expect multiple of block size. But sometimes we hash short + // values (FS transcript). Instead of forcing to hash to field, we left-pad the + // input here. + if len(p) > 0 && len(p) < BlockSize { + pp := make([]byte, BlockSize) + copy(pp[len(pp)-len(p):], p) + p = pp + } var start int for start = 0; start < len(p); start += BlockSize { @@ -183,10 +191,11 @@ func initConstants() { } // WriteString writes a string that doesn't necessarily consist of field elements -func (d *digest) WriteString(rawBytes []byte) { +func (d *digest) WriteString(rawBytes []byte) error { if elems, err := fr.Hash(rawBytes, []byte("string:"), 1); err != nil { - panic(err) + return err } else { d.data = append(d.data, elems[0]) } + return nil } diff --git a/ecc/bw6-633/fr/permutation/permutation.go b/ecc/bw6-633/fr/permutation/permutation.go index 8f3cfd52d..7ec0969dd 100644 --- a/ecc/bw6-633/fr/permutation/permutation.go +++ b/ecc/bw6-633/fr/permutation/permutation.go @@ -177,7 +177,7 @@ func Prove(pk kzg.ProvingKey, t1, t2 []fr.Element) (Proof, error) { } // derive challenge for z - epsilon, err := deriveRandomness(&fs, "epsilon", &proof.t1, &proof.t2) + epsilon, err := deriveRandomness(fs, "epsilon", &proof.t1, &proof.t2) if err != nil { return proof, err } @@ -206,7 +206,7 @@ func Prove(pk kzg.ProvingKey, t1, t2 []fr.Element) (Proof, error) { lsNum := evaluateSecondPartNumReverse(lz, d) // derive challenge used for the folding - omega, err := deriveRandomness(&fs, "omega", &proof.z) + omega, err := deriveRandomness(fs, "omega", &proof.z) if err != nil { return proof, err } @@ -229,7 +229,7 @@ func Prove(pk kzg.ProvingKey, t1, t2 []fr.Element) (Proof, error) { } // derive the evaluation challenge - eta, err := deriveRandomness(&fs, "eta", &proof.q) + eta, err := deriveRandomness(fs, "eta", &proof.q) if err != nil { return proof, err } @@ -282,17 +282,17 @@ func Verify(vk kzg.VerifyingKey, proof Proof) error { fs := fiatshamir.NewTranscript(hFunc, "epsilon", "omega", "eta") // derive the challenges - epsilon, err := deriveRandomness(&fs, "epsilon", &proof.t1, &proof.t2) + epsilon, err := deriveRandomness(fs, "epsilon", &proof.t1, &proof.t2) if err != nil { return err } - omega, err := deriveRandomness(&fs, "omega", &proof.z) + omega, err := deriveRandomness(fs, "omega", &proof.z) if err != nil { return err } - eta, err := deriveRandomness(&fs, "eta", &proof.q) + eta, err := deriveRandomness(fs, "eta", &proof.q) if err != nil { return err } diff --git a/ecc/bw6-633/fr/plookup/table.go b/ecc/bw6-633/fr/plookup/table.go index dcfe721d9..eb80ef8c6 100644 --- a/ecc/bw6-633/fr/plookup/table.go +++ b/ecc/bw6-633/fr/plookup/table.go @@ -145,7 +145,7 @@ func ProveLookupTables(pk kzg.ProvingKey, f, t []fr.Vector) (ProofLookupTables, comms[nbRows+i] = new(kzg.Digest) comms[nbRows+i].Set(&proof.ts[i]) } - lambda, err := deriveRandomness(&fs, "lambda", comms...) + lambda, err := deriveRandomness(fs, "lambda", comms...) if err != nil { return proof, err } @@ -197,7 +197,7 @@ func VerifyLookupTables(vk kzg.VerifyingKey, proof ProofLookupTables) error { comms[i] = &proof.fs[i] comms[i+nbRows] = &proof.ts[i] } - lambda, err := deriveRandomness(&fs, "lambda", comms...) + lambda, err := deriveRandomness(fs, "lambda", comms...) if err != nil { return err } diff --git a/ecc/bw6-633/fr/plookup/vector.go b/ecc/bw6-633/fr/plookup/vector.go index 13a821b2b..a50eb0001 100644 --- a/ecc/bw6-633/fr/plookup/vector.go +++ b/ecc/bw6-633/fr/plookup/vector.go @@ -441,11 +441,11 @@ func ProveLookupVector(pk kzg.ProvingKey, f, t fr.Vector) (ProofLookupVector, er } // derive beta, gamma - beta, err := deriveRandomness(&fs, "beta", &proof.t, &proof.f, &proof.h1, &proof.h2) + beta, err := deriveRandomness(fs, "beta", &proof.t, &proof.f, &proof.h1, &proof.h2) if err != nil { return proof, err } - gamma, err := deriveRandomness(&fs, "gamma") + gamma, err := deriveRandomness(fs, "gamma") if err != nil { return proof, err } @@ -495,7 +495,7 @@ func ProveLookupVector(pk kzg.ProvingKey, f, t fr.Vector) (ProofLookupVector, er lh1h2 := evaluateOverlapH1h2BitReversed(_lh1, _lh2, domainBig) // compute the quotient - alpha, err := deriveRandomness(&fs, "alpha", &proof.z) + alpha, err := deriveRandomness(fs, "alpha", &proof.z) if err != nil { return proof, err } @@ -506,7 +506,7 @@ func ProveLookupVector(pk kzg.ProvingKey, f, t fr.Vector) (ProofLookupVector, er } // build the opening proofs - nu, err := deriveRandomness(&fs, "nu", &proof.h) + nu, err := deriveRandomness(fs, "nu", &proof.h) if err != nil { return proof, err } @@ -570,22 +570,22 @@ func VerifyLookupVector(vk kzg.VerifyingKey, proof ProofLookupVector) error { fs := fiatshamir.NewTranscript(hFunc, "beta", "gamma", "alpha", "nu") // derive the various challenges - beta, err := deriveRandomness(&fs, "beta", &proof.t, &proof.f, &proof.h1, &proof.h2) + beta, err := deriveRandomness(fs, "beta", &proof.t, &proof.f, &proof.h1, &proof.h2) if err != nil { return err } - gamma, err := deriveRandomness(&fs, "gamma") + gamma, err := deriveRandomness(fs, "gamma") if err != nil { return err } - alpha, err := deriveRandomness(&fs, "alpha", &proof.z) + alpha, err := deriveRandomness(fs, "alpha", &proof.z) if err != nil { return err } - nu, err := deriveRandomness(&fs, "nu", &proof.h) + nu, err := deriveRandomness(fs, "nu", &proof.h) if err != nil { return err } diff --git a/ecc/bw6-633/fr/sumcheck/sumcheck.go b/ecc/bw6-633/fr/sumcheck/sumcheck.go index 3e401b771..db7abdacc 100644 --- a/ecc/bw6-633/fr/sumcheck/sumcheck.go +++ b/ecc/bw6-633/fr/sumcheck/sumcheck.go @@ -67,7 +67,7 @@ func setupTranscript(claimsNum int, varsNum int, settings *fiatshamir.Settings) } if settings.Transcript == nil { transcript := fiatshamir.NewTranscript(settings.Hash, challengeNames...) - settings.Transcript = &transcript + settings.Transcript = transcript } for i := range settings.BaseChallenges { diff --git a/ecc/bw6-756/fr/fri/fri.go b/ecc/bw6-756/fr/fri/fri.go index 29d74e962..6ff1ee539 100644 --- a/ecc/bw6-756/fr/fri/fri.go +++ b/ecc/bw6-756/fr/fri/fri.go @@ -365,18 +365,6 @@ func foldPolynomialLagrangeBasis(pSorted []fr.Element, gInv, x fr.Element) []fr. return res } -// paddNaming takes s = 0xA1.... and turns -// it into s' = 0xA1.. || 0..0 of size frSize bytes. -// Using this, when writing the domain separator in FiatShamir, it takes -// the same size as a snark variable (=number of byte in the block of a snark compliant -// hash function like mimc), so it is compliant with snark circuit. -func paddNaming(s string, size int) string { - a := make([]byte, size) - b := []byte(s) - copy(a, b) - return string(a) -} - // buildProofOfProximitySingleRound generates a proof that a function, given as an oracle from // the verifier point of view, is in fact δ-close to a polynomial. // * salt is a variable for multi rounds, it allows to generate different challenges using Fiat Shamir @@ -395,9 +383,9 @@ func (s radixTwoFri) buildProofOfProximitySingleRound(salt fr.Element, p []fr.El // by replacing x by xᵢ. xis := make([]string, s.nbSteps+1) for i := 0; i < s.nbSteps; i++ { - xis[i] = paddNaming(fmt.Sprintf("x%d", i), fr.Bytes) + xis[i] = fmt.Sprintf("x%d", i) } - xis[s.nbSteps] = paddNaming("s0", fr.Bytes) + xis[s.nbSteps] = "s0" fs := fiatshamir.NewTranscript(s.h, xis...) // the salt is binded to the first challenge, to ensure the challenges @@ -549,9 +537,9 @@ func (s radixTwoFri) verifyProofOfProximitySingleRound(salt fr.Element, proof Ro // Fiat Shamir transcript to derive the challenges xis := make([]string, s.nbSteps+1) for i := 0; i < s.nbSteps; i++ { - xis[i] = paddNaming(fmt.Sprintf("x%d", i), fr.Bytes) + xis[i] = fmt.Sprintf("x%d", i) } - xis[s.nbSteps] = paddNaming("s0", fr.Bytes) + xis[s.nbSteps] = "s0" fs := fiatshamir.NewTranscript(s.h, xis...) xi := make([]fr.Element, s.nbSteps) diff --git a/ecc/bw6-756/fr/gkr/gkr.go b/ecc/bw6-756/fr/gkr/gkr.go index 650170be4..5fe30d6d2 100644 --- a/ecc/bw6-756/fr/gkr/gkr.go +++ b/ecc/bw6-756/fr/gkr/gkr.go @@ -490,9 +490,7 @@ func setup(c Circuit, assignment WireAssignment, transcriptSettings fiatshamir.S if transcriptSettings.Transcript == nil { challengeNames := ChallengeNames(o.sorted, o.nbVars, transcriptSettings.Prefix) - transcript := fiatshamir.NewTranscript( - transcriptSettings.Hash, challengeNames...) - o.transcript = &transcript + o.transcript = fiatshamir.NewTranscript(transcriptSettings.Hash, challengeNames...) for i := range transcriptSettings.BaseChallenges { if err = o.transcript.Bind(challengeNames[0], transcriptSettings.BaseChallenges[i]); err != nil { return o, err diff --git a/ecc/bw6-756/fr/mimc/mimc.go b/ecc/bw6-756/fr/mimc/mimc.go index c9a2992b0..8078aa6c3 100644 --- a/ecc/bw6-756/fr/mimc/mimc.go +++ b/ecc/bw6-756/fr/mimc/mimc.go @@ -100,6 +100,14 @@ func (d *digest) BlockSize() int { // // To hash arbitrary data ([]byte not representing canonical field elements) use fr.Hash first func (d *digest) Write(p []byte) (int, error) { + // we usually expect multiple of block size. But sometimes we hash short + // values (FS transcript). Instead of forcing to hash to field, we left-pad the + // input here. + if len(p) > 0 && len(p) < BlockSize { + pp := make([]byte, BlockSize) + copy(pp[len(pp)-len(p):], p) + p = pp + } var start int for start = 0; start < len(p); start += BlockSize { @@ -183,10 +191,11 @@ func initConstants() { } // WriteString writes a string that doesn't necessarily consist of field elements -func (d *digest) WriteString(rawBytes []byte) { +func (d *digest) WriteString(rawBytes []byte) error { if elems, err := fr.Hash(rawBytes, []byte("string:"), 1); err != nil { - panic(err) + return err } else { d.data = append(d.data, elems[0]) } + return nil } diff --git a/ecc/bw6-756/fr/permutation/permutation.go b/ecc/bw6-756/fr/permutation/permutation.go index 5a80f995e..416a3742b 100644 --- a/ecc/bw6-756/fr/permutation/permutation.go +++ b/ecc/bw6-756/fr/permutation/permutation.go @@ -177,7 +177,7 @@ func Prove(pk kzg.ProvingKey, t1, t2 []fr.Element) (Proof, error) { } // derive challenge for z - epsilon, err := deriveRandomness(&fs, "epsilon", &proof.t1, &proof.t2) + epsilon, err := deriveRandomness(fs, "epsilon", &proof.t1, &proof.t2) if err != nil { return proof, err } @@ -206,7 +206,7 @@ func Prove(pk kzg.ProvingKey, t1, t2 []fr.Element) (Proof, error) { lsNum := evaluateSecondPartNumReverse(lz, d) // derive challenge used for the folding - omega, err := deriveRandomness(&fs, "omega", &proof.z) + omega, err := deriveRandomness(fs, "omega", &proof.z) if err != nil { return proof, err } @@ -229,7 +229,7 @@ func Prove(pk kzg.ProvingKey, t1, t2 []fr.Element) (Proof, error) { } // derive the evaluation challenge - eta, err := deriveRandomness(&fs, "eta", &proof.q) + eta, err := deriveRandomness(fs, "eta", &proof.q) if err != nil { return proof, err } @@ -282,17 +282,17 @@ func Verify(vk kzg.VerifyingKey, proof Proof) error { fs := fiatshamir.NewTranscript(hFunc, "epsilon", "omega", "eta") // derive the challenges - epsilon, err := deriveRandomness(&fs, "epsilon", &proof.t1, &proof.t2) + epsilon, err := deriveRandomness(fs, "epsilon", &proof.t1, &proof.t2) if err != nil { return err } - omega, err := deriveRandomness(&fs, "omega", &proof.z) + omega, err := deriveRandomness(fs, "omega", &proof.z) if err != nil { return err } - eta, err := deriveRandomness(&fs, "eta", &proof.q) + eta, err := deriveRandomness(fs, "eta", &proof.q) if err != nil { return err } diff --git a/ecc/bw6-756/fr/plookup/table.go b/ecc/bw6-756/fr/plookup/table.go index bb8d418d4..e2f04587d 100644 --- a/ecc/bw6-756/fr/plookup/table.go +++ b/ecc/bw6-756/fr/plookup/table.go @@ -145,7 +145,7 @@ func ProveLookupTables(pk kzg.ProvingKey, f, t []fr.Vector) (ProofLookupTables, comms[nbRows+i] = new(kzg.Digest) comms[nbRows+i].Set(&proof.ts[i]) } - lambda, err := deriveRandomness(&fs, "lambda", comms...) + lambda, err := deriveRandomness(fs, "lambda", comms...) if err != nil { return proof, err } @@ -197,7 +197,7 @@ func VerifyLookupTables(vk kzg.VerifyingKey, proof ProofLookupTables) error { comms[i] = &proof.fs[i] comms[i+nbRows] = &proof.ts[i] } - lambda, err := deriveRandomness(&fs, "lambda", comms...) + lambda, err := deriveRandomness(fs, "lambda", comms...) if err != nil { return err } diff --git a/ecc/bw6-756/fr/plookup/vector.go b/ecc/bw6-756/fr/plookup/vector.go index beba8c4d3..fd1b5ff61 100644 --- a/ecc/bw6-756/fr/plookup/vector.go +++ b/ecc/bw6-756/fr/plookup/vector.go @@ -441,11 +441,11 @@ func ProveLookupVector(pk kzg.ProvingKey, f, t fr.Vector) (ProofLookupVector, er } // derive beta, gamma - beta, err := deriveRandomness(&fs, "beta", &proof.t, &proof.f, &proof.h1, &proof.h2) + beta, err := deriveRandomness(fs, "beta", &proof.t, &proof.f, &proof.h1, &proof.h2) if err != nil { return proof, err } - gamma, err := deriveRandomness(&fs, "gamma") + gamma, err := deriveRandomness(fs, "gamma") if err != nil { return proof, err } @@ -495,7 +495,7 @@ func ProveLookupVector(pk kzg.ProvingKey, f, t fr.Vector) (ProofLookupVector, er lh1h2 := evaluateOverlapH1h2BitReversed(_lh1, _lh2, domainBig) // compute the quotient - alpha, err := deriveRandomness(&fs, "alpha", &proof.z) + alpha, err := deriveRandomness(fs, "alpha", &proof.z) if err != nil { return proof, err } @@ -506,7 +506,7 @@ func ProveLookupVector(pk kzg.ProvingKey, f, t fr.Vector) (ProofLookupVector, er } // build the opening proofs - nu, err := deriveRandomness(&fs, "nu", &proof.h) + nu, err := deriveRandomness(fs, "nu", &proof.h) if err != nil { return proof, err } @@ -570,22 +570,22 @@ func VerifyLookupVector(vk kzg.VerifyingKey, proof ProofLookupVector) error { fs := fiatshamir.NewTranscript(hFunc, "beta", "gamma", "alpha", "nu") // derive the various challenges - beta, err := deriveRandomness(&fs, "beta", &proof.t, &proof.f, &proof.h1, &proof.h2) + beta, err := deriveRandomness(fs, "beta", &proof.t, &proof.f, &proof.h1, &proof.h2) if err != nil { return err } - gamma, err := deriveRandomness(&fs, "gamma") + gamma, err := deriveRandomness(fs, "gamma") if err != nil { return err } - alpha, err := deriveRandomness(&fs, "alpha", &proof.z) + alpha, err := deriveRandomness(fs, "alpha", &proof.z) if err != nil { return err } - nu, err := deriveRandomness(&fs, "nu", &proof.h) + nu, err := deriveRandomness(fs, "nu", &proof.h) if err != nil { return err } diff --git a/ecc/bw6-756/fr/sumcheck/sumcheck.go b/ecc/bw6-756/fr/sumcheck/sumcheck.go index 0cbce7fa7..0a42bdb25 100644 --- a/ecc/bw6-756/fr/sumcheck/sumcheck.go +++ b/ecc/bw6-756/fr/sumcheck/sumcheck.go @@ -67,7 +67,7 @@ func setupTranscript(claimsNum int, varsNum int, settings *fiatshamir.Settings) } if settings.Transcript == nil { transcript := fiatshamir.NewTranscript(settings.Hash, challengeNames...) - settings.Transcript = &transcript + settings.Transcript = transcript } for i := range settings.BaseChallenges { diff --git a/ecc/bw6-761/fr/fri/fri.go b/ecc/bw6-761/fr/fri/fri.go index 6c8cb0bce..0ebeec095 100644 --- a/ecc/bw6-761/fr/fri/fri.go +++ b/ecc/bw6-761/fr/fri/fri.go @@ -365,18 +365,6 @@ func foldPolynomialLagrangeBasis(pSorted []fr.Element, gInv, x fr.Element) []fr. return res } -// paddNaming takes s = 0xA1.... and turns -// it into s' = 0xA1.. || 0..0 of size frSize bytes. -// Using this, when writing the domain separator in FiatShamir, it takes -// the same size as a snark variable (=number of byte in the block of a snark compliant -// hash function like mimc), so it is compliant with snark circuit. -func paddNaming(s string, size int) string { - a := make([]byte, size) - b := []byte(s) - copy(a, b) - return string(a) -} - // buildProofOfProximitySingleRound generates a proof that a function, given as an oracle from // the verifier point of view, is in fact δ-close to a polynomial. // * salt is a variable for multi rounds, it allows to generate different challenges using Fiat Shamir @@ -395,9 +383,9 @@ func (s radixTwoFri) buildProofOfProximitySingleRound(salt fr.Element, p []fr.El // by replacing x by xᵢ. xis := make([]string, s.nbSteps+1) for i := 0; i < s.nbSteps; i++ { - xis[i] = paddNaming(fmt.Sprintf("x%d", i), fr.Bytes) + xis[i] = fmt.Sprintf("x%d", i) } - xis[s.nbSteps] = paddNaming("s0", fr.Bytes) + xis[s.nbSteps] = "s0" fs := fiatshamir.NewTranscript(s.h, xis...) // the salt is binded to the first challenge, to ensure the challenges @@ -549,9 +537,9 @@ func (s radixTwoFri) verifyProofOfProximitySingleRound(salt fr.Element, proof Ro // Fiat Shamir transcript to derive the challenges xis := make([]string, s.nbSteps+1) for i := 0; i < s.nbSteps; i++ { - xis[i] = paddNaming(fmt.Sprintf("x%d", i), fr.Bytes) + xis[i] = fmt.Sprintf("x%d", i) } - xis[s.nbSteps] = paddNaming("s0", fr.Bytes) + xis[s.nbSteps] = "s0" fs := fiatshamir.NewTranscript(s.h, xis...) xi := make([]fr.Element, s.nbSteps) diff --git a/ecc/bw6-761/fr/gkr/gkr.go b/ecc/bw6-761/fr/gkr/gkr.go index a50b7617b..c98a8ab05 100644 --- a/ecc/bw6-761/fr/gkr/gkr.go +++ b/ecc/bw6-761/fr/gkr/gkr.go @@ -490,9 +490,7 @@ func setup(c Circuit, assignment WireAssignment, transcriptSettings fiatshamir.S if transcriptSettings.Transcript == nil { challengeNames := ChallengeNames(o.sorted, o.nbVars, transcriptSettings.Prefix) - transcript := fiatshamir.NewTranscript( - transcriptSettings.Hash, challengeNames...) - o.transcript = &transcript + o.transcript = fiatshamir.NewTranscript(transcriptSettings.Hash, challengeNames...) for i := range transcriptSettings.BaseChallenges { if err = o.transcript.Bind(challengeNames[0], transcriptSettings.BaseChallenges[i]); err != nil { return o, err diff --git a/ecc/bw6-761/fr/mimc/mimc.go b/ecc/bw6-761/fr/mimc/mimc.go index d575a63d9..d93fe32f2 100644 --- a/ecc/bw6-761/fr/mimc/mimc.go +++ b/ecc/bw6-761/fr/mimc/mimc.go @@ -100,6 +100,14 @@ func (d *digest) BlockSize() int { // // To hash arbitrary data ([]byte not representing canonical field elements) use fr.Hash first func (d *digest) Write(p []byte) (int, error) { + // we usually expect multiple of block size. But sometimes we hash short + // values (FS transcript). Instead of forcing to hash to field, we left-pad the + // input here. + if len(p) > 0 && len(p) < BlockSize { + pp := make([]byte, BlockSize) + copy(pp[len(pp)-len(p):], p) + p = pp + } var start int for start = 0; start < len(p); start += BlockSize { @@ -183,10 +191,11 @@ func initConstants() { } // WriteString writes a string that doesn't necessarily consist of field elements -func (d *digest) WriteString(rawBytes []byte) { +func (d *digest) WriteString(rawBytes []byte) error { if elems, err := fr.Hash(rawBytes, []byte("string:"), 1); err != nil { - panic(err) + return err } else { d.data = append(d.data, elems[0]) } + return nil } diff --git a/ecc/bw6-761/fr/permutation/permutation.go b/ecc/bw6-761/fr/permutation/permutation.go index 30b3a5e00..d06ec57e0 100644 --- a/ecc/bw6-761/fr/permutation/permutation.go +++ b/ecc/bw6-761/fr/permutation/permutation.go @@ -177,7 +177,7 @@ func Prove(pk kzg.ProvingKey, t1, t2 []fr.Element) (Proof, error) { } // derive challenge for z - epsilon, err := deriveRandomness(&fs, "epsilon", &proof.t1, &proof.t2) + epsilon, err := deriveRandomness(fs, "epsilon", &proof.t1, &proof.t2) if err != nil { return proof, err } @@ -206,7 +206,7 @@ func Prove(pk kzg.ProvingKey, t1, t2 []fr.Element) (Proof, error) { lsNum := evaluateSecondPartNumReverse(lz, d) // derive challenge used for the folding - omega, err := deriveRandomness(&fs, "omega", &proof.z) + omega, err := deriveRandomness(fs, "omega", &proof.z) if err != nil { return proof, err } @@ -229,7 +229,7 @@ func Prove(pk kzg.ProvingKey, t1, t2 []fr.Element) (Proof, error) { } // derive the evaluation challenge - eta, err := deriveRandomness(&fs, "eta", &proof.q) + eta, err := deriveRandomness(fs, "eta", &proof.q) if err != nil { return proof, err } @@ -282,17 +282,17 @@ func Verify(vk kzg.VerifyingKey, proof Proof) error { fs := fiatshamir.NewTranscript(hFunc, "epsilon", "omega", "eta") // derive the challenges - epsilon, err := deriveRandomness(&fs, "epsilon", &proof.t1, &proof.t2) + epsilon, err := deriveRandomness(fs, "epsilon", &proof.t1, &proof.t2) if err != nil { return err } - omega, err := deriveRandomness(&fs, "omega", &proof.z) + omega, err := deriveRandomness(fs, "omega", &proof.z) if err != nil { return err } - eta, err := deriveRandomness(&fs, "eta", &proof.q) + eta, err := deriveRandomness(fs, "eta", &proof.q) if err != nil { return err } diff --git a/ecc/bw6-761/fr/plookup/table.go b/ecc/bw6-761/fr/plookup/table.go index bfbfc7cbf..cd90fb6ee 100644 --- a/ecc/bw6-761/fr/plookup/table.go +++ b/ecc/bw6-761/fr/plookup/table.go @@ -145,7 +145,7 @@ func ProveLookupTables(pk kzg.ProvingKey, f, t []fr.Vector) (ProofLookupTables, comms[nbRows+i] = new(kzg.Digest) comms[nbRows+i].Set(&proof.ts[i]) } - lambda, err := deriveRandomness(&fs, "lambda", comms...) + lambda, err := deriveRandomness(fs, "lambda", comms...) if err != nil { return proof, err } @@ -197,7 +197,7 @@ func VerifyLookupTables(vk kzg.VerifyingKey, proof ProofLookupTables) error { comms[i] = &proof.fs[i] comms[i+nbRows] = &proof.ts[i] } - lambda, err := deriveRandomness(&fs, "lambda", comms...) + lambda, err := deriveRandomness(fs, "lambda", comms...) if err != nil { return err } diff --git a/ecc/bw6-761/fr/plookup/vector.go b/ecc/bw6-761/fr/plookup/vector.go index 3883123fc..508ceb539 100644 --- a/ecc/bw6-761/fr/plookup/vector.go +++ b/ecc/bw6-761/fr/plookup/vector.go @@ -441,11 +441,11 @@ func ProveLookupVector(pk kzg.ProvingKey, f, t fr.Vector) (ProofLookupVector, er } // derive beta, gamma - beta, err := deriveRandomness(&fs, "beta", &proof.t, &proof.f, &proof.h1, &proof.h2) + beta, err := deriveRandomness(fs, "beta", &proof.t, &proof.f, &proof.h1, &proof.h2) if err != nil { return proof, err } - gamma, err := deriveRandomness(&fs, "gamma") + gamma, err := deriveRandomness(fs, "gamma") if err != nil { return proof, err } @@ -495,7 +495,7 @@ func ProveLookupVector(pk kzg.ProvingKey, f, t fr.Vector) (ProofLookupVector, er lh1h2 := evaluateOverlapH1h2BitReversed(_lh1, _lh2, domainBig) // compute the quotient - alpha, err := deriveRandomness(&fs, "alpha", &proof.z) + alpha, err := deriveRandomness(fs, "alpha", &proof.z) if err != nil { return proof, err } @@ -506,7 +506,7 @@ func ProveLookupVector(pk kzg.ProvingKey, f, t fr.Vector) (ProofLookupVector, er } // build the opening proofs - nu, err := deriveRandomness(&fs, "nu", &proof.h) + nu, err := deriveRandomness(fs, "nu", &proof.h) if err != nil { return proof, err } @@ -570,22 +570,22 @@ func VerifyLookupVector(vk kzg.VerifyingKey, proof ProofLookupVector) error { fs := fiatshamir.NewTranscript(hFunc, "beta", "gamma", "alpha", "nu") // derive the various challenges - beta, err := deriveRandomness(&fs, "beta", &proof.t, &proof.f, &proof.h1, &proof.h2) + beta, err := deriveRandomness(fs, "beta", &proof.t, &proof.f, &proof.h1, &proof.h2) if err != nil { return err } - gamma, err := deriveRandomness(&fs, "gamma") + gamma, err := deriveRandomness(fs, "gamma") if err != nil { return err } - alpha, err := deriveRandomness(&fs, "alpha", &proof.z) + alpha, err := deriveRandomness(fs, "alpha", &proof.z) if err != nil { return err } - nu, err := deriveRandomness(&fs, "nu", &proof.h) + nu, err := deriveRandomness(fs, "nu", &proof.h) if err != nil { return err } diff --git a/ecc/bw6-761/fr/sumcheck/sumcheck.go b/ecc/bw6-761/fr/sumcheck/sumcheck.go index 1c6afa936..6a8554c20 100644 --- a/ecc/bw6-761/fr/sumcheck/sumcheck.go +++ b/ecc/bw6-761/fr/sumcheck/sumcheck.go @@ -67,7 +67,7 @@ func setupTranscript(claimsNum int, varsNum int, settings *fiatshamir.Settings) } if settings.Transcript == nil { transcript := fiatshamir.NewTranscript(settings.Hash, challengeNames...) - settings.Transcript = &transcript + settings.Transcript = transcript } for i := range settings.BaseChallenges { diff --git a/fiat-shamir/transcript.go b/fiat-shamir/transcript.go index 110d8aed5..a50f1ba65 100644 --- a/fiat-shamir/transcript.go +++ b/fiat-shamir/transcript.go @@ -16,6 +16,7 @@ package fiatshamir import ( "errors" + "fmt" "hash" ) @@ -45,17 +46,15 @@ type challenge struct { // NewTranscript returns a new transcript. // h is the hash function that is used to compute the challenges. // challenges are the name of the challenges. The order of the challenges IDs matters. -func NewTranscript(h hash.Hash, challengesID ...string) Transcript { - n := len(challengesID) - t := Transcript{ - challenges: make(map[string]challenge, n), - h: h, +func NewTranscript(h hash.Hash, challengesID ...string) *Transcript { + challenges := make(map[string]challenge) + for i := range challengesID { + challenges[challengesID[i]] = challenge{position: i} } - - for i := 0; i < n; i++ { - t.challenges[challengesID[i]] = challenge{position: i} + t := &Transcript{ + challenges: challenges, + h: h, } - return t } @@ -65,19 +64,19 @@ func NewTranscript(h hash.Hash, challengesID ...string) Transcript { // binded to other values. func (t *Transcript) Bind(challengeID string, bValue []byte) error { - challenge, ok := t.challenges[challengeID] + currentChallenge, ok := t.challenges[challengeID] if !ok { return errChallengeNotFound } - if challenge.isComputed { + if currentChallenge.isComputed { return errChallengeAlreadyComputed } bCopy := make([]byte, len(bValue)) copy(bCopy, bValue) - challenge.bindings = append(challenge.bindings, bCopy) - t.challenges[challengeID] = challenge + currentChallenge.bindings = append(currentChallenge.bindings, bCopy) + t.challenges[challengeID] = currentChallenge return nil @@ -103,15 +102,8 @@ func (t *Transcript) ComputeChallenge(challengeID string) ([]byte, error) { t.h.Reset() defer t.h.Reset() - // write the challenge name, the purpose is to have a domain separator - if hashToField, ok := t.h.(interface { - WriteString(rawBytes []byte) - }); ok { - hashToField.WriteString([]byte(challengeID)) // TODO: Replace with a function returning field identifier, whence we can find the correct hash to field function. Better than confusingly embedding hash to field into another hash - } else { - if _, err := t.h.Write([]byte(challengeID)); err != nil { - return nil, err - } + if _, err := t.h.Write([]byte(challengeID)); err != nil { + return nil, fmt.Errorf("write: %w", err) } // write the previous challenge if it's not the first challenge diff --git a/fiat-shamir/transcript_test.go b/fiat-shamir/transcript_test.go index 8b929f57d..8451aae32 100644 --- a/fiat-shamir/transcript_test.go +++ b/fiat-shamir/transcript_test.go @@ -20,7 +20,7 @@ import ( "testing" ) -func initTranscript() Transcript { +func initTranscript() *Transcript { fs := NewTranscript(sha256.New(), "alpha", "beta", "gamma") diff --git a/internal/generator/crypto/hash/mimc/template/mimc.go.tmpl b/internal/generator/crypto/hash/mimc/template/mimc.go.tmpl index f396c8644..a752a3bcc 100644 --- a/internal/generator/crypto/hash/mimc/template/mimc.go.tmpl +++ b/internal/generator/crypto/hash/mimc/template/mimc.go.tmpl @@ -100,6 +100,14 @@ func (d *digest) BlockSize() int { // // To hash arbitrary data ([]byte not representing canonical field elements) use fr.Hash first func (d *digest) Write(p []byte) (int, error) { + // we usually expect multiple of block size. But sometimes we hash short + // values (FS transcript). Instead of forcing to hash to field, we left-pad the + // input here. + if len(p) > 0 && len(p) < BlockSize { + pp := make([]byte,BlockSize) + copy(pp[len(pp)-len(p):], p) + p = pp + } var start int for start = 0; start < len(p); start += BlockSize { @@ -227,10 +235,11 @@ func initConstants() { } // WriteString writes a string that doesn't necessarily consist of field elements -func (d *digest) WriteString(rawBytes []byte) { +func (d *digest) WriteString(rawBytes []byte) error { if elems, err := fr.Hash(rawBytes, []byte("string:"), 1); err != nil { - panic(err) + return err } else { d.data = append(d.data, elems[0]) } + return nil } diff --git a/internal/generator/fri/template/fri.go.tmpl b/internal/generator/fri/template/fri.go.tmpl index f226f87a4..5870c1cd0 100644 --- a/internal/generator/fri/template/fri.go.tmpl +++ b/internal/generator/fri/template/fri.go.tmpl @@ -348,18 +348,6 @@ func foldPolynomialLagrangeBasis(pSorted []fr.Element, gInv, x fr.Element) []fr. return res } -// paddNaming takes s = 0xA1.... and turns -// it into s' = 0xA1.. || 0..0 of size frSize bytes. -// Using this, when writing the domain separator in FiatShamir, it takes -// the same size as a snark variable (=number of byte in the block of a snark compliant -// hash function like mimc), so it is compliant with snark circuit. -func paddNaming(s string, size int) string { - a := make([]byte, size) - b := []byte(s) - copy(a, b) - return string(a) -} - // buildProofOfProximitySingleRound generates a proof that a function, given as an oracle from // the verifier point of view, is in fact δ-close to a polynomial. // * salt is a variable for multi rounds, it allows to generate different challenges using Fiat Shamir @@ -378,9 +366,9 @@ func (s radixTwoFri) buildProofOfProximitySingleRound(salt fr.Element, p []fr.El // by replacing x by xᵢ. xis := make([]string, s.nbSteps+1) for i := 0; i < s.nbSteps; i++ { - xis[i] = paddNaming(fmt.Sprintf("x%d", i), fr.Bytes) + xis[i] = fmt.Sprintf("x%d", i) } - xis[s.nbSteps] = paddNaming("s0", fr.Bytes) + xis[s.nbSteps] = "s0" fs := fiatshamir.NewTranscript(s.h, xis...) // the salt is binded to the first challenge, to ensure the challenges @@ -532,9 +520,9 @@ func (s radixTwoFri) verifyProofOfProximitySingleRound(salt fr.Element, proof Ro // Fiat Shamir transcript to derive the challenges xis := make([]string, s.nbSteps+1) for i := 0; i < s.nbSteps; i++ { - xis[i] = paddNaming(fmt.Sprintf("x%d", i), fr.Bytes) + xis[i] = fmt.Sprintf("x%d", i) } - xis[s.nbSteps] = paddNaming("s0", fr.Bytes) + xis[s.nbSteps] = "s0" fs := fiatshamir.NewTranscript(s.h, xis...) xi := make([]fr.Element, s.nbSteps) diff --git a/internal/generator/gkr/template/gkr.go.tmpl b/internal/generator/gkr/template/gkr.go.tmpl index 6a09ac332..049702508 100644 --- a/internal/generator/gkr/template/gkr.go.tmpl +++ b/internal/generator/gkr/template/gkr.go.tmpl @@ -475,9 +475,7 @@ func setup(c Circuit, assignment WireAssignment, transcriptSettings fiatshamir.S if transcriptSettings.Transcript == nil { challengeNames := ChallengeNames(o.sorted, o.nbVars, transcriptSettings.Prefix) - transcript := fiatshamir.NewTranscript( - transcriptSettings.Hash, challengeNames...) - o.transcript = &transcript + o.transcript = fiatshamir.NewTranscript(transcriptSettings.Hash, challengeNames...) for i := range transcriptSettings.BaseChallenges { if err = o.transcript.Bind(challengeNames[0], transcriptSettings.BaseChallenges[i]); err != nil { return o, err diff --git a/internal/generator/permutation/template/permutation.go.tmpl b/internal/generator/permutation/template/permutation.go.tmpl index 9ef791a63..c90343e4f 100644 --- a/internal/generator/permutation/template/permutation.go.tmpl +++ b/internal/generator/permutation/template/permutation.go.tmpl @@ -159,7 +159,7 @@ func Prove(pk kzg.ProvingKey, t1, t2 []fr.Element) (Proof, error) { } // derive challenge for z - epsilon, err := deriveRandomness(&fs, "epsilon", &proof.t1, &proof.t2) + epsilon, err := deriveRandomness(fs, "epsilon", &proof.t1, &proof.t2) if err != nil { return proof, err } @@ -188,7 +188,7 @@ func Prove(pk kzg.ProvingKey, t1, t2 []fr.Element) (Proof, error) { lsNum := evaluateSecondPartNumReverse(lz, d) // derive challenge used for the folding - omega, err := deriveRandomness(&fs, "omega", &proof.z) + omega, err := deriveRandomness(fs, "omega", &proof.z) if err != nil { return proof, err } @@ -211,7 +211,7 @@ func Prove(pk kzg.ProvingKey, t1, t2 []fr.Element) (Proof, error) { } // derive the evaluation challenge - eta, err := deriveRandomness(&fs, "eta", &proof.q) + eta, err := deriveRandomness(fs, "eta", &proof.q) if err != nil { return proof, err } @@ -264,17 +264,17 @@ func Verify(vk kzg.VerifyingKey, proof Proof) error { fs := fiatshamir.NewTranscript(hFunc, "epsilon", "omega", "eta") // derive the challenges - epsilon, err := deriveRandomness(&fs, "epsilon", &proof.t1, &proof.t2) + epsilon, err := deriveRandomness(fs, "epsilon", &proof.t1, &proof.t2) if err != nil { return err } - omega, err := deriveRandomness(&fs, "omega", &proof.z) + omega, err := deriveRandomness(fs, "omega", &proof.z) if err != nil { return err } - eta, err := deriveRandomness(&fs, "eta", &proof.q) + eta, err := deriveRandomness(fs, "eta", &proof.q) if err != nil { return err } diff --git a/internal/generator/plookup/template/table.go.tmpl b/internal/generator/plookup/template/table.go.tmpl index 29f0339bf..fcdec07f8 100644 --- a/internal/generator/plookup/template/table.go.tmpl +++ b/internal/generator/plookup/template/table.go.tmpl @@ -127,7 +127,7 @@ func ProveLookupTables(pk kzg.ProvingKey, f, t []fr.Vector) (ProofLookupTables, comms[nbRows+i] = new(kzg.Digest) comms[nbRows+i].Set(&proof.ts[i]) } - lambda, err := deriveRandomness(&fs, "lambda", comms...) + lambda, err := deriveRandomness(fs, "lambda", comms...) if err != nil { return proof, err } @@ -179,7 +179,7 @@ func VerifyLookupTables(vk kzg.VerifyingKey, proof ProofLookupTables) error { comms[i] = &proof.fs[i] comms[i+nbRows] = &proof.ts[i] } - lambda, err := deriveRandomness(&fs, "lambda", comms...) + lambda, err := deriveRandomness(fs, "lambda", comms...) if err != nil { return err } diff --git a/internal/generator/plookup/template/vector.go.tmpl b/internal/generator/plookup/template/vector.go.tmpl index 1970b864f..c9f654336 100644 --- a/internal/generator/plookup/template/vector.go.tmpl +++ b/internal/generator/plookup/template/vector.go.tmpl @@ -424,11 +424,11 @@ func ProveLookupVector(pk kzg.ProvingKey, f, t fr.Vector) (ProofLookupVector, er } // derive beta, gamma - beta, err := deriveRandomness(&fs, "beta", &proof.t, &proof.f, &proof.h1, &proof.h2) + beta, err := deriveRandomness(fs, "beta", &proof.t, &proof.f, &proof.h1, &proof.h2) if err != nil { return proof, err } - gamma, err := deriveRandomness(&fs, "gamma") + gamma, err := deriveRandomness(fs, "gamma") if err != nil { return proof, err } @@ -478,7 +478,7 @@ func ProveLookupVector(pk kzg.ProvingKey, f, t fr.Vector) (ProofLookupVector, er lh1h2 := evaluateOverlapH1h2BitReversed(_lh1, _lh2, domainBig) // compute the quotient - alpha, err := deriveRandomness(&fs, "alpha", &proof.z) + alpha, err := deriveRandomness(fs, "alpha", &proof.z) if err != nil { return proof, err } @@ -489,7 +489,7 @@ func ProveLookupVector(pk kzg.ProvingKey, f, t fr.Vector) (ProofLookupVector, er } // build the opening proofs - nu, err := deriveRandomness(&fs, "nu", &proof.h) + nu, err := deriveRandomness(fs, "nu", &proof.h) if err != nil { return proof, err } @@ -553,22 +553,22 @@ func VerifyLookupVector(vk kzg.VerifyingKey, proof ProofLookupVector) error { fs := fiatshamir.NewTranscript(hFunc, "beta", "gamma", "alpha", "nu") // derive the various challenges - beta, err := deriveRandomness(&fs, "beta", &proof.t, &proof.f, &proof.h1, &proof.h2) + beta, err := deriveRandomness(fs, "beta", &proof.t, &proof.f, &proof.h1, &proof.h2) if err != nil { return err } - gamma, err := deriveRandomness(&fs, "gamma") + gamma, err := deriveRandomness(fs, "gamma") if err != nil { return err } - alpha, err := deriveRandomness(&fs, "alpha", &proof.z) + alpha, err := deriveRandomness(fs, "alpha", &proof.z) if err != nil { return err } - nu, err := deriveRandomness(&fs, "nu", &proof.h) + nu, err := deriveRandomness(fs, "nu", &proof.h) if err != nil { return err } diff --git a/internal/generator/sumcheck/template/sumcheck.go.tmpl b/internal/generator/sumcheck/template/sumcheck.go.tmpl index 80881bdcc..a4e17da82 100644 --- a/internal/generator/sumcheck/template/sumcheck.go.tmpl +++ b/internal/generator/sumcheck/template/sumcheck.go.tmpl @@ -49,7 +49,7 @@ func setupTranscript(claimsNum int, varsNum int, settings *fiatshamir.Settings) } if settings.Transcript == nil { transcript := fiatshamir.NewTranscript(settings.Hash, challengeNames...) - settings.Transcript = &transcript + settings.Transcript = transcript } for i := range settings.BaseChallenges { diff --git a/internal/generator/test_vector_utils/small_rational/gkr/gkr.go b/internal/generator/test_vector_utils/small_rational/gkr/gkr.go index ae7261e52..a2bef7d1e 100644 --- a/internal/generator/test_vector_utils/small_rational/gkr/gkr.go +++ b/internal/generator/test_vector_utils/small_rational/gkr/gkr.go @@ -490,9 +490,7 @@ func setup(c Circuit, assignment WireAssignment, transcriptSettings fiatshamir.S if transcriptSettings.Transcript == nil { challengeNames := ChallengeNames(o.sorted, o.nbVars, transcriptSettings.Prefix) - transcript := fiatshamir.NewTranscript( - transcriptSettings.Hash, challengeNames...) - o.transcript = &transcript + o.transcript = fiatshamir.NewTranscript(transcriptSettings.Hash, challengeNames...) for i := range transcriptSettings.BaseChallenges { if err = o.transcript.Bind(challengeNames[0], transcriptSettings.BaseChallenges[i]); err != nil { return o, err diff --git a/internal/generator/test_vector_utils/small_rational/sumcheck/sumcheck.go b/internal/generator/test_vector_utils/small_rational/sumcheck/sumcheck.go index 4f33c8017..cb86eb419 100644 --- a/internal/generator/test_vector_utils/small_rational/sumcheck/sumcheck.go +++ b/internal/generator/test_vector_utils/small_rational/sumcheck/sumcheck.go @@ -67,7 +67,7 @@ func setupTranscript(claimsNum int, varsNum int, settings *fiatshamir.Settings) } if settings.Transcript == nil { transcript := fiatshamir.NewTranscript(settings.Hash, challengeNames...) - settings.Transcript = &transcript + settings.Transcript = transcript } for i := range settings.BaseChallenges {