From e7885c38533bd388fc613d28ea3034cfbb5c46e5 Mon Sep 17 00:00:00 2001 From: Gautam Botrel Date: Fri, 8 Mar 2024 09:42:44 -0600 Subject: [PATCH] refactor: kill backend.PLONK_FRI --- backend/backend.go | 5 +- backend/plonkfri/bls12-377/prove.go | 701 --------------------------- backend/plonkfri/bls12-377/setup.go | 423 ---------------- backend/plonkfri/bls12-377/verify.go | 398 --------------- backend/plonkfri/bls12-381/prove.go | 701 --------------------------- backend/plonkfri/bls12-381/setup.go | 423 ---------------- backend/plonkfri/bls12-381/verify.go | 398 --------------- backend/plonkfri/bls24-315/prove.go | 701 --------------------------- backend/plonkfri/bls24-315/setup.go | 423 ---------------- backend/plonkfri/bls24-315/verify.go | 398 --------------- backend/plonkfri/bls24-317/prove.go | 701 --------------------------- backend/plonkfri/bls24-317/setup.go | 423 ---------------- backend/plonkfri/bls24-317/verify.go | 398 --------------- backend/plonkfri/bn254/prove.go | 701 --------------------------- backend/plonkfri/bn254/setup.go | 423 ---------------- backend/plonkfri/bn254/verify.go | 398 --------------- backend/plonkfri/bw6-633/prove.go | 701 --------------------------- backend/plonkfri/bw6-633/setup.go | 423 ---------------- backend/plonkfri/bw6-633/verify.go | 398 --------------- backend/plonkfri/bw6-761/prove.go | 701 --------------------------- backend/plonkfri/bw6-761/setup.go | 423 ---------------- backend/plonkfri/bw6-761/verify.go | 398 --------------- backend/plonkfri/plonkfri.go | 191 -------- integration_test.go | 5 - internal/generator/backend/main.go | 14 - internal/stats/stats.go | 6 +- test/assert.go | 2 - test/assert_checkcircuit.go | 19 - 28 files changed, 4 insertions(+), 10892 deletions(-) delete mode 100644 backend/plonkfri/bls12-377/prove.go delete mode 100644 backend/plonkfri/bls12-377/setup.go delete mode 100644 backend/plonkfri/bls12-377/verify.go delete mode 100644 backend/plonkfri/bls12-381/prove.go delete mode 100644 backend/plonkfri/bls12-381/setup.go delete mode 100644 backend/plonkfri/bls12-381/verify.go delete mode 100644 backend/plonkfri/bls24-315/prove.go delete mode 100644 backend/plonkfri/bls24-315/setup.go delete mode 100644 backend/plonkfri/bls24-315/verify.go delete mode 100644 backend/plonkfri/bls24-317/prove.go delete mode 100644 backend/plonkfri/bls24-317/setup.go delete mode 100644 backend/plonkfri/bls24-317/verify.go delete mode 100644 backend/plonkfri/bn254/prove.go delete mode 100644 backend/plonkfri/bn254/setup.go delete mode 100644 backend/plonkfri/bn254/verify.go delete mode 100644 backend/plonkfri/bw6-633/prove.go delete mode 100644 backend/plonkfri/bw6-633/setup.go delete mode 100644 backend/plonkfri/bw6-633/verify.go delete mode 100644 backend/plonkfri/bw6-761/prove.go delete mode 100644 backend/plonkfri/bw6-761/setup.go delete mode 100644 backend/plonkfri/bw6-761/verify.go delete mode 100644 backend/plonkfri/plonkfri.go diff --git a/backend/backend.go b/backend/backend.go index 50f0ab15e5..7ee17d6793 100644 --- a/backend/backend.go +++ b/backend/backend.go @@ -29,12 +29,11 @@ const ( UNKNOWN ID = iota GROTH16 PLONK - PLONKFRI ) // Implemented return the list of proof systems implemented in gnark func Implemented() []ID { - return []ID{GROTH16, PLONK, PLONKFRI} + return []ID{GROTH16, PLONK} } // String returns the string representation of a proof system @@ -44,8 +43,6 @@ func (id ID) String() string { return "groth16" case PLONK: return "plonk" - case PLONKFRI: - return "plonkFRI" default: return "unknown" } diff --git a/backend/plonkfri/bls12-377/prove.go b/backend/plonkfri/bls12-377/prove.go deleted file mode 100644 index 82144641b2..0000000000 --- a/backend/plonkfri/bls12-377/prove.go +++ /dev/null @@ -1,701 +0,0 @@ -// Copyright 2020 ConsenSys Software Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -// Code generated by gnark DO NOT EDIT - -package plonkfri - -import ( - "math/big" - "math/bits" - "runtime" - - "github.com/consensys/gnark/backend/witness" - - "github.com/consensys/gnark-crypto/ecc/bls12-377/fr" - - "github.com/consensys/gnark-crypto/ecc/bls12-377/fr/fft" - - cs "github.com/consensys/gnark/constraint/bls12-377" - - "github.com/consensys/gnark-crypto/ecc/bls12-377/fr/fri" - - fiatshamir "github.com/consensys/gnark-crypto/fiat-shamir" - "github.com/consensys/gnark/backend" - "github.com/consensys/gnark/internal/utils" -) - -type Proof struct { - // commitments to the solution vectors - LROpp [3]fri.ProofOfProximity - - // commitment to Z (permutation polynomial) - // Z Commitment - Zpp fri.ProofOfProximity - - // commitment to h1,h2,h3 such that h = h1 + X**n*h2 + X**2nh3 the quotient polynomial - Hpp [3]fri.ProofOfProximity - - // opening proofs for L, R, O - OpeningsLROmp [3]fri.OpeningProof - - // opening proofs for Z, Zu - OpeningsZmp [2]fri.OpeningProof - - // opening proof for H - OpeningsHmp [3]fri.OpeningProof - - // opening proofs for ql, qr, qm, qo, qk - OpeningsQlQrQmQoQkincompletemp [5]fri.OpeningProof - - // openings of S1, S2, S3 - // OpeningsS1S2S3 [3]OpeningProof - OpeningsS1S2S3mp [3]fri.OpeningProof - - // openings of Id1, Id2, Id3 - OpeningsId1Id2Id3mp [3]fri.OpeningProof -} - -func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...backend.ProverOption) (*Proof, error) { - opt, err := backend.NewProverConfig(opts...) - if err != nil { - return nil, err - } - - var proof Proof - - // 0 - Fiat Shamir - fs := fiatshamir.NewTranscript(opt.ChallengeHash, "gamma", "beta", "alpha", "zeta") - - // 1 - solve the system - _solution, err := spr.Solve(fullWitness, opt.SolverOpts...) - if err != nil { - return nil, err - } - - solution := _solution.(*cs.SparseR1CSSolution) - evaluationLDomainSmall := []fr.Element(solution.L) - evaluationRDomainSmall := []fr.Element(solution.R) - evaluationODomainSmall := []fr.Element(solution.O) - - // 2 - commit to lro - blindedLCanonical, blindedRCanonical, blindedOCanonical, err := computeBlindedLROCanonical( - evaluationLDomainSmall, - evaluationRDomainSmall, - evaluationODomainSmall, - &pk.Domain[0]) - if err != nil { - return nil, err - } - proof.LROpp[0], err = pk.Vk.Iopp.BuildProofOfProximity(blindedLCanonical) - if err != nil { - return nil, err - } - proof.LROpp[1], err = pk.Vk.Iopp.BuildProofOfProximity(blindedRCanonical) - if err != nil { - return nil, err - } - proof.LROpp[2], err = pk.Vk.Iopp.BuildProofOfProximity(blindedOCanonical) - if err != nil { - return nil, err - } - - // 3 - compute Z, challenges are derived using L, R, O + public inputs - fw, ok := fullWitness.Vector().(fr.Vector) - if !ok { - return nil, witness.ErrInvalidWitness - } - dataFiatShamir := make([][fr.Bytes]byte, len(spr.Public)+3) - for i := 0; i < len(spr.Public); i++ { - copy(dataFiatShamir[i][:], fw[i].Marshal()) - } - copy(dataFiatShamir[len(spr.Public)][:], proof.LROpp[0].ID) - copy(dataFiatShamir[len(spr.Public)+1][:], proof.LROpp[1].ID) - copy(dataFiatShamir[len(spr.Public)+2][:], proof.LROpp[2].ID) - - beta, err := deriveRandomnessFixedSize(fs, "gamma", dataFiatShamir...) - if err != nil { - return nil, err - } - - gamma, err := deriveRandomness(fs, "beta", nil) - if err != nil { - return nil, err - } - - //var beta, gamma fr.Element - //beta.SetUint64(9) - // gamma.SetString("10") - blindedZCanonical, err := computeBlindedZCanonical( - evaluationLDomainSmall, - evaluationRDomainSmall, - evaluationODomainSmall, - pk, beta, gamma) - if err != nil { - return nil, err - } - - // 4 - commit Z - proof.Zpp, err = pk.Vk.Iopp.BuildProofOfProximity(blindedZCanonical) - if err != nil { - return nil, err - } - - // 5 - compute H - // var alpha fr.Element - alpha, err := deriveRandomness(fs, "alpha", proof.Zpp.ID) - if err != nil { - return nil, err - } - // alpha.SetUint64(11) - - evaluationQkCompleteDomainBigBitReversed := make([]fr.Element, pk.Domain[1].Cardinality) - copy(evaluationQkCompleteDomainBigBitReversed, fw[:len(spr.Public)]) - copy(evaluationQkCompleteDomainBigBitReversed[len(spr.Public):], pk.LQkIncompleteDomainSmall[len(spr.Public):]) - pk.Domain[0].FFTInverse(evaluationQkCompleteDomainBigBitReversed[:pk.Domain[0].Cardinality], fft.DIF) - fft.BitReverse(evaluationQkCompleteDomainBigBitReversed[:pk.Domain[0].Cardinality]) - - evaluationQkCompleteDomainBigBitReversed = fftBigCosetWOBitReverse(evaluationQkCompleteDomainBigBitReversed, &pk.Domain[1]) - - evaluationBlindedLDomainBigBitReversed := fftBigCosetWOBitReverse(blindedLCanonical, &pk.Domain[1]) - evaluationBlindedRDomainBigBitReversed := fftBigCosetWOBitReverse(blindedRCanonical, &pk.Domain[1]) - evaluationBlindedODomainBigBitReversed := fftBigCosetWOBitReverse(blindedOCanonical, &pk.Domain[1]) - - evaluationConstraintsDomainBigBitReversed := evalConstraintsInd( - pk, - evaluationBlindedLDomainBigBitReversed, - evaluationBlindedRDomainBigBitReversed, - evaluationBlindedODomainBigBitReversed, - evaluationQkCompleteDomainBigBitReversed) - - evaluationBlindedZDomainBigBitReversed := fftBigCosetWOBitReverse(blindedZCanonical, &pk.Domain[1]) - - evaluationOrderingDomainBigBitReversed := evaluateOrderingDomainBigBitReversed( - pk, - evaluationBlindedZDomainBigBitReversed, - evaluationBlindedLDomainBigBitReversed, - evaluationBlindedRDomainBigBitReversed, - evaluationBlindedODomainBigBitReversed, - beta, gamma) - - h1Canonical, h2Canonical, h3Canonical := computeQuotientCanonical( - pk, - evaluationConstraintsDomainBigBitReversed, - evaluationOrderingDomainBigBitReversed, - evaluationBlindedZDomainBigBitReversed, - alpha) - - // 6 - commit to H - proof.Hpp[0], err = pk.Vk.Iopp.BuildProofOfProximity(h1Canonical) - if err != nil { - return nil, err - } - proof.Hpp[1], err = pk.Vk.Iopp.BuildProofOfProximity(h2Canonical) - if err != nil { - return nil, err - } - proof.Hpp[2], err = pk.Vk.Iopp.BuildProofOfProximity(h3Canonical) - if err != nil { - return nil, err - } - - // 7 - build the opening proofs - // compute the size of the domain of evaluation of the committed polynomial, - // the opening position. The challenge zeta will be g^{i} where i is the opening - // position, and g is the generator of the fri domain. - rho := uint64(fri.GetRho()) - friSize := 2 * rho * pk.Vk.Size - var bFriSize big.Int - bFriSize.SetInt64(int64(friSize)) - frOpeningPosition, err := deriveRandomness(fs, "zeta", proof.Hpp[0].ID, proof.Hpp[1].ID, proof.Hpp[2].ID) - if err != nil { - return nil, err - } - var bOpeningPosition big.Int - bOpeningPosition.SetBytes(frOpeningPosition.Marshal()).Mod(&bOpeningPosition, &bFriSize) - openingPosition := bOpeningPosition.Uint64() - - // ql, qr, qm, qo, qkIncomplete - proof.OpeningsQlQrQmQoQkincompletemp[0], err = pk.Vk.Iopp.Open(pk.CQl, openingPosition) - if err != nil { - return &proof, err - } - proof.OpeningsQlQrQmQoQkincompletemp[1], err = pk.Vk.Iopp.Open(pk.CQr, openingPosition) - if err != nil { - return &proof, err - } - proof.OpeningsQlQrQmQoQkincompletemp[2], err = pk.Vk.Iopp.Open(pk.CQm, openingPosition) - if err != nil { - return &proof, err - } - proof.OpeningsQlQrQmQoQkincompletemp[3], err = pk.Vk.Iopp.Open(pk.CQo, openingPosition) - if err != nil { - return &proof, err - } - proof.OpeningsQlQrQmQoQkincompletemp[4], err = pk.Vk.Iopp.Open(pk.CQkIncomplete, openingPosition) - if err != nil { - return &proof, err - } - - // l, r, o - proof.OpeningsLROmp[0], err = pk.Vk.Iopp.Open(blindedLCanonical, openingPosition) - if err != nil { - return &proof, err - } - proof.OpeningsLROmp[1], err = pk.Vk.Iopp.Open(blindedRCanonical, openingPosition) - if err != nil { - return &proof, err - } - proof.OpeningsLROmp[2], err = pk.Vk.Iopp.Open(blindedOCanonical, openingPosition) - if err != nil { - return &proof, err - } - - // h0, h1, h2 - proof.OpeningsHmp[0], err = pk.Vk.Iopp.Open(h1Canonical, openingPosition) - if err != nil { - return &proof, err - } - proof.OpeningsHmp[1], err = pk.Vk.Iopp.Open(h2Canonical, openingPosition) - if err != nil { - return &proof, err - } - proof.OpeningsHmp[2], err = pk.Vk.Iopp.Open(h3Canonical, openingPosition) - if err != nil { - return &proof, err - } - - // s0, s1, s2 - proof.OpeningsS1S2S3mp[0], err = pk.Vk.Iopp.Open(pk.Vk.SCanonical[0], openingPosition) - if err != nil { - return &proof, err - } - proof.OpeningsS1S2S3mp[1], err = pk.Vk.Iopp.Open(pk.Vk.SCanonical[1], openingPosition) - if err != nil { - return &proof, err - } - proof.OpeningsS1S2S3mp[2], err = pk.Vk.Iopp.Open(pk.Vk.SCanonical[2], openingPosition) - if err != nil { - return &proof, err - } - - // id0, id1, id2 - proof.OpeningsId1Id2Id3mp[0], err = pk.Vk.Iopp.Open(pk.Vk.IdCanonical[0], openingPosition) - if err != nil { - return &proof, err - } - proof.OpeningsId1Id2Id3mp[1], err = pk.Vk.Iopp.Open(pk.Vk.IdCanonical[1], openingPosition) - if err != nil { - return &proof, err - } - proof.OpeningsId1Id2Id3mp[2], err = pk.Vk.Iopp.Open(pk.Vk.IdCanonical[2], openingPosition) - if err != nil { - return &proof, err - } - - // zeta is shifted by g, the generator of Z/nZ where n is the number of constraints. We need - // to query the "rho" factor from FRI to know by what should be shifted the opening position. - // We multiply by 2 because FRI is instantiated with pk.Domain[0].Cardinality+2, which makes - // the iop's domain of size rho*(2*pk.Domain[0].Cardinality). - shiftedOpeningPosition := (openingPosition + uint64(2*rho)) % friSize - proof.OpeningsZmp[0], err = pk.Vk.Iopp.Open(blindedZCanonical, openingPosition) - if err != nil { - return &proof, err - } - proof.OpeningsZmp[1], err = pk.Vk.Iopp.Open(blindedZCanonical, shiftedOpeningPosition) - if err != nil { - return &proof, err - } - - return &proof, nil -} - -// evaluateOrderingDomainBigBitReversed computes the evaluation of Z(uX)g1g2g3-Z(X)f1f2f3 on the odd -// cosets of the big domain. -// -// * z evaluation of the blinded permutation accumulator polynomial on odd cosets -// * l, r, o evaluation of the blinded solution vectors on odd cosets -// * gamma randomization -func evaluateOrderingDomainBigBitReversed(pk *ProvingKey, z, l, r, o []fr.Element, beta, gamma fr.Element) []fr.Element { - - nbElmts := int(pk.Domain[1].Cardinality) - - // computes z_(uX)*(l(X)+s₁(X)*β+γ)*(r(X))+s₂(gⁱ)*β+γ)*(o(X))+s₃(X)*β+γ) - z(X)*(l(X)+X*β+γ)*(r(X)+u*X*β+γ)*(o(X)+u²*X*β+γ) - // on the big domain (coset). - res := make([]fr.Element, pk.Domain[1].Cardinality) // re use allocated memory for EvaluationS1BigDomain - - // utils variables useful for using bit reversed indices - nn := uint64(64 - bits.TrailingZeros64(uint64(nbElmts))) - - // needed to shift LsZ - toShift := int(pk.Domain[1].Cardinality / pk.Domain[0].Cardinality) - - var cosetShift, cosetShiftSquare fr.Element - cosetShift.Set(&pk.Vk.CosetShift) - cosetShiftSquare.Square(&pk.Vk.CosetShift) - - utils.Parallelize(int(pk.Domain[1].Cardinality), func(start, end int) { - - var evaluationIDBigDomain fr.Element - evaluationIDBigDomain.Exp(pk.Domain[1].Generator, big.NewInt(int64(start))). - Mul(&evaluationIDBigDomain, &pk.Domain[1].FrMultiplicativeGen) - - var f [3]fr.Element - var g [3]fr.Element - - for i := start; i < end; i++ { - - _i := bits.Reverse64(uint64(i)) >> nn - _is := bits.Reverse64(uint64((i+toShift)%nbElmts)) >> nn - - // in what follows gⁱ is understood as the generator of the chosen coset of domainBig - f[0].Mul(&evaluationIDBigDomain, &beta).Add(&f[0], &l[_i]).Add(&f[0], &gamma) //l(gⁱ)+gⁱ*β+γ - f[1].Mul(&evaluationIDBigDomain, &cosetShift).Mul(&f[1], &beta).Add(&f[1], &r[_i]).Add(&f[1], &gamma) //r(gⁱ)+u*gⁱ*β+γ - f[2].Mul(&evaluationIDBigDomain, &cosetShiftSquare).Mul(&f[2], &beta).Add(&f[2], &o[_i]).Add(&f[2], &gamma) //o(gⁱ)+u²*gⁱ*β+γ - - g[0].Mul(&pk.EvaluationS1BigDomain[_i], &beta).Add(&g[0], &l[_i]).Add(&g[0], &gamma) //l(gⁱ))+s1(gⁱ)*β+γ - g[1].Mul(&pk.EvaluationS2BigDomain[_i], &beta).Add(&g[1], &r[_i]).Add(&g[1], &gamma) //r(gⁱ))+s2(gⁱ)*β+γ - g[2].Mul(&pk.EvaluationS3BigDomain[_i], &beta).Add(&g[2], &o[_i]).Add(&g[2], &gamma) //o(gⁱ))+s3(gⁱ)*β+γ - - f[0].Mul(&f[0], &f[1]).Mul(&f[0], &f[2]).Mul(&f[0], &z[_i]) // z(gⁱ)*(l(gⁱ)+g^i*β+γ)*(r(g^i)+u*g^i*β+γ)*(o(g^i)+u²*g^i*β+γ) - g[0].Mul(&g[0], &g[1]).Mul(&g[0], &g[2]).Mul(&g[0], &z[_is]) // z_(ugⁱ)*(l(gⁱ))+s₁(gⁱ)*β+γ)*(r(gⁱ))+s₂(gⁱ)*β+γ)*(o(gⁱ))+s₃(gⁱ)*β+γ) - - res[_i].Sub(&g[0], &f[0]) // z_(ugⁱ)*(l(gⁱ))+s₁(gⁱ)*β+γ)*(r(gⁱ))+s₂(gⁱ)*β+γ)*(o(gⁱ))+s₃(gⁱ)*β+γ) - z(gⁱ)*(l(gⁱ)+g^i*β+γ)*(r(g^i)+u*g^i*β+γ)*(o(g^i)+u²*g^i*β+γ) - - evaluationIDBigDomain.Mul(&evaluationIDBigDomain, &pk.Domain[1].Generator) // gⁱ*g - } - }) - - return res -} - -// evalConstraintsInd computes the evaluation of lL+qrR+qqmL.R+qoO+k on -// the odd coset of (Z/8mZ)/(Z/4mZ), where m=nbConstraints+nbAssertions. -// -// * lsL, lsR, lsO are the evaluation of the blinded solution vectors on odd cosets -// * lsQk is the completed version of qk, in canonical version -// -// lsL, lsR, lsO are in bit reversed order, lsQk is in the correct order. -func evalConstraintsInd(pk *ProvingKey, lsL, lsR, lsO, lsQk []fr.Element) []fr.Element { - - res := make([]fr.Element, pk.Domain[1].Cardinality) - // nn := uint64(64 - bits.TrailingZeros64(pk.Domain[1].Cardinality)) - - utils.Parallelize(len(res), func(start, end int) { - - var t0, t1 fr.Element - - for i := start; i < end; i++ { - - // irev := bits.Reverse64(uint64(i)) >> nn - - t1.Mul(&pk.EvaluationQmDomainBigBitReversed[i], &lsR[i]) // qm.r - t1.Add(&t1, &pk.EvaluationQlDomainBigBitReversed[i]) // qm.r + ql - t1.Mul(&t1, &lsL[i]) // qm.l.r + ql.l - - t0.Mul(&pk.EvaluationQrDomainBigBitReversed[i], &lsR[i]) - t0.Add(&t0, &t1) // qm.l.r + ql.l + qr.r - - t1.Mul(&pk.EvaluationQoDomainBigBitReversed[i], &lsO[i]) - t0.Add(&t0, &t1) // ql.l + qr.r + qm.l.r + qo.o - res[i].Add(&t0, &lsQk[i]) // ql.l + qr.r + qm.l.r + qo.o + k - - } - }) - - return res -} - -// fftBigCosetWOBitReverse evaluates poly (canonical form) of degree m> nn - - t.Sub(&evaluationBlindedZDomainBigBitReversed[_i], &one) // evaluates L₁(X)*(Z(X)-1) on a coset of the big domain - h[_i].Mul(&startsAtOne[_i], &t).Mul(&h[_i], &alpha). - Add(&h[_i], &evaluationConstraintOrderingBitReversed[_i]). - Mul(&h[_i], &alpha). - Add(&h[_i], &evaluationConstraintsIndBitReversed[_i]). - Mul(&h[_i], &evaluationXnMinusOneInverse[i%ratio]) - } - }) - - // put h in canonical form. h is of degree 3*(n+1)+2. - // using fft.DIT put h revert bit reverse - pk.Domain[1].FFTInverse(h, fft.DIT, fft.OnCoset()) - - // degree of hi is n+2 because of the blinding - h1 := h[:pk.Domain[0].Cardinality+2] - h2 := h[pk.Domain[0].Cardinality+2 : 2*(pk.Domain[0].Cardinality+2)] - h3 := h[2*(pk.Domain[0].Cardinality+2) : 3*(pk.Domain[0].Cardinality+2)] - - return h1, h2, h3 - -} - -// computeZ computes Z, in canonical basis, where: -// -// - Z of degree n (domainNum.Cardinality) -// -// - Z(1)=1 -// (l_i+z**i+gamma)*(r_i+u*z**i+gamma)*(o_i+u**2z**i+gamma) -// -// - for i>0: Z(u**i) = Pi_{k "small" domain, used for individual polynomials - // 1 -> "big" domain, used for the computation of the quotient - Domain [2]fft.Domain - - // s1, s2, s3 (L=Lagrange basis small domain, C=canonical basis, Ls=Lagrange Shifted big domain) - LId []fr.Element - EvaluationId1BigDomain, EvaluationId2BigDomain, EvaluationId3BigDomain []fr.Element - EvaluationS1BigDomain, EvaluationS2BigDomain, EvaluationS3BigDomain []fr.Element - - // position -> permuted position (position in [0,3*sizeSystem-1]) - Permutation []int64 -} - -// VerifyingKey stores the data needed to verify a proof: -// * The commitment scheme -// * Commitments of ql prepended with as many ones as there are public inputs -// * Commitments of qr, qm, qo, qk prepended with as many zeroes as there are public inputs -// * Commitments to S1, S2, S3 -type VerifyingKey struct { - - // Size circuit, that is the closest power of 2 bounding above - // number of constraints+number of public inputs - Size uint64 - SizeInv fr.Element - Generator fr.Element - NbPublicVariables uint64 - - // cosetShift generator of the coset on the small domain - CosetShift fr.Element - - // S commitments to S1, S2, S3 - SCanonical [3][]fr.Element - Spp [3]fri.ProofOfProximity - - // Id commitments to Id1, Id2, Id3 - // Id [3]Commitment - IdCanonical [3][]fr.Element - Idpp [3]fri.ProofOfProximity - - // Commitments to ql, qr, qm, qo prepended with as many zeroes (ones for l) as there are public inputs. - // In particular Qk is not complete. - Qpp [5]fri.ProofOfProximity // Ql, Qr, Qm, Qo, Qk - - // Iopp scheme (currently one for each size of polynomial) - Iopp fri.Iopp - - // generator of the group on which the Iopp works. If i is the opening position, - // the polynomials will be opened at genOpening^{i}. - GenOpening fr.Element -} - -// Setup sets proving and verifying keys -func Setup(spr *cs.SparseR1CS) (*ProvingKey, *VerifyingKey, error) { - - var pk ProvingKey - var vk VerifyingKey - - // The verifying key shares data with the proving key - pk.Vk = &vk - - nbConstraints := spr.GetNbConstraints() - - // fft domains - sizeSystem := uint64(nbConstraints + len(spr.Public)) // len(spr.Public) is for the placeholder constraints - pk.Domain[0] = *fft.NewDomain(sizeSystem) - - // h, the quotient polynomial is of degree 3(n+1)+2, so it's in a 3(n+2) dim vector space, - // the domain is the next power of 2 superior to 3(n+2). 4*domainNum is enough in all cases - // except when n<6. - if sizeSystem < 6 { - pk.Domain[1] = *fft.NewDomain(8 * sizeSystem) - } else { - pk.Domain[1] = *fft.NewDomain(4 * sizeSystem) - } - pk.Vk.CosetShift.Set(&pk.Domain[0].FrMultiplicativeGen) - - vk.Size = pk.Domain[0].Cardinality - vk.SizeInv.SetUint64(vk.Size).Inverse(&vk.SizeInv) - vk.Generator.Set(&pk.Domain[0].Generator) - vk.NbPublicVariables = uint64(len(spr.Public)) - - // IOP schemess - // The +2 is to handle the blinding. - sizeIopp := pk.Domain[0].Cardinality + 2 - vk.Iopp = fri.RADIX_2_FRI.New(sizeIopp, sha256.New()) - // only there to access the group used in FRI... - rho := uint64(fri.GetRho()) - // we multiply by 2 because the IOP is created with size pk.Domain[0].Cardinality + 2 (because - // of the blinding), so the domain will be rho*size_domain where size_domain is the next power - // of 2 after pk.Domain[0].Cardinality + 2, which is 2*rho*pk.Domain[0].Cardinality - tmpDomain := fft.NewDomain(2 * rho * pk.Domain[0].Cardinality) - vk.GenOpening.Set(&tmpDomain.Generator) - - // public polynomials corresponding to constraints: [ placholders | constraints | assertions ] - pk.EvaluationQlDomainBigBitReversed = make([]fr.Element, pk.Domain[1].Cardinality) - pk.EvaluationQrDomainBigBitReversed = make([]fr.Element, pk.Domain[1].Cardinality) - pk.EvaluationQmDomainBigBitReversed = make([]fr.Element, pk.Domain[1].Cardinality) - pk.EvaluationQoDomainBigBitReversed = make([]fr.Element, pk.Domain[1].Cardinality) - pk.LQkIncompleteDomainSmall = make([]fr.Element, pk.Domain[0].Cardinality) - pk.CQkIncomplete = make([]fr.Element, pk.Domain[0].Cardinality) - - for i := 0; i < len(spr.Public); i++ { // placeholders (-PUB_INPUT_i + qk_i = 0) TODO should return error if size is inconsistent - pk.EvaluationQlDomainBigBitReversed[i].SetOne().Neg(&pk.EvaluationQlDomainBigBitReversed[i]) - pk.EvaluationQrDomainBigBitReversed[i].SetZero() - pk.EvaluationQmDomainBigBitReversed[i].SetZero() - pk.EvaluationQoDomainBigBitReversed[i].SetZero() - pk.LQkIncompleteDomainSmall[i].SetZero() // --> to be completed by the prover - pk.CQkIncomplete[i].Set(&pk.LQkIncompleteDomainSmall[i]) // --> to be completed by the prover - } - offset := len(spr.Public) - - j := 0 - it := spr.GetSparseR1CIterator() - for c := it.Next(); c != nil; c = it.Next() { - pk.EvaluationQlDomainBigBitReversed[offset+j].Set(&spr.Coefficients[c.QL]) - pk.EvaluationQrDomainBigBitReversed[offset+j].Set(&spr.Coefficients[c.QR]) - pk.EvaluationQmDomainBigBitReversed[offset+j].Set(&spr.Coefficients[c.QM]) - pk.EvaluationQoDomainBigBitReversed[offset+j].Set(&spr.Coefficients[c.QO]) - pk.LQkIncompleteDomainSmall[offset+j].Set(&spr.Coefficients[c.QC]) - pk.CQkIncomplete[offset+j].Set(&pk.LQkIncompleteDomainSmall[offset+j]) - - j++ - } - - pk.Domain[0].FFTInverse(pk.EvaluationQlDomainBigBitReversed[:pk.Domain[0].Cardinality], fft.DIF) - pk.Domain[0].FFTInverse(pk.EvaluationQrDomainBigBitReversed[:pk.Domain[0].Cardinality], fft.DIF) - pk.Domain[0].FFTInverse(pk.EvaluationQmDomainBigBitReversed[:pk.Domain[0].Cardinality], fft.DIF) - pk.Domain[0].FFTInverse(pk.EvaluationQoDomainBigBitReversed[:pk.Domain[0].Cardinality], fft.DIF) - pk.Domain[0].FFTInverse(pk.CQkIncomplete, fft.DIF) - fft.BitReverse(pk.EvaluationQlDomainBigBitReversed[:pk.Domain[0].Cardinality]) - fft.BitReverse(pk.EvaluationQrDomainBigBitReversed[:pk.Domain[0].Cardinality]) - fft.BitReverse(pk.EvaluationQmDomainBigBitReversed[:pk.Domain[0].Cardinality]) - fft.BitReverse(pk.EvaluationQoDomainBigBitReversed[:pk.Domain[0].Cardinality]) - fft.BitReverse(pk.CQkIncomplete) - - // Commit to the polynomials to set up the verifying key - pk.CQl = make([]fr.Element, pk.Domain[0].Cardinality) - pk.CQr = make([]fr.Element, pk.Domain[0].Cardinality) - pk.CQm = make([]fr.Element, pk.Domain[0].Cardinality) - pk.CQo = make([]fr.Element, pk.Domain[0].Cardinality) - copy(pk.CQl, pk.EvaluationQlDomainBigBitReversed) - copy(pk.CQr, pk.EvaluationQrDomainBigBitReversed) - copy(pk.CQm, pk.EvaluationQmDomainBigBitReversed) - copy(pk.CQo, pk.EvaluationQoDomainBigBitReversed) - var err error - vk.Qpp[0], err = vk.Iopp.BuildProofOfProximity(pk.CQl) - if err != nil { - return &pk, &vk, err - } - vk.Qpp[1], err = vk.Iopp.BuildProofOfProximity(pk.CQr) - if err != nil { - return &pk, &vk, err - } - vk.Qpp[2], err = vk.Iopp.BuildProofOfProximity(pk.CQm) - if err != nil { - return &pk, &vk, err - } - vk.Qpp[3], err = vk.Iopp.BuildProofOfProximity(pk.CQo) - if err != nil { - return &pk, &vk, err - } - vk.Qpp[4], err = vk.Iopp.BuildProofOfProximity(pk.CQkIncomplete) - if err != nil { - return &pk, &vk, err - } - - pk.Domain[1].FFT(pk.EvaluationQlDomainBigBitReversed, fft.DIF, fft.OnCoset()) - pk.Domain[1].FFT(pk.EvaluationQrDomainBigBitReversed, fft.DIF, fft.OnCoset()) - pk.Domain[1].FFT(pk.EvaluationQmDomainBigBitReversed, fft.DIF, fft.OnCoset()) - pk.Domain[1].FFT(pk.EvaluationQoDomainBigBitReversed, fft.DIF, fft.OnCoset()) - - // build permutation. Note: at this stage, the permutation takes in account the placeholders - buildPermutation(spr, &pk) - - // set s1, s2, s3 - err = computePermutationPolynomials(&pk, &vk) - if err != nil { - return &pk, &vk, err - } - - return &pk, &vk, nil - -} - -// buildPermutation builds the Permutation associated with a circuit. -// -// The permutation s is composed of cycles of maximum length such that -// -// s. (l||r||o) = (l||r||o) -// -// , where l||r||o is the concatenation of the indices of l, r, o in -// ql.l+qr.r+qm.l.r+qo.O+k = 0. -// -// The permutation is encoded as a slice s of size 3*size(l), where the -// i-th entry of l||r||o is sent to the s[i]-th entry, so it acts on a tab -// like this: for i in tab: tab[i] = tab[permutation[i]] -func buildPermutation(spr *cs.SparseR1CS, pk *ProvingKey) { - - nbVariables := spr.NbInternalVariables + len(spr.Public) + len(spr.Secret) - sizeSolution := int(pk.Domain[0].Cardinality) - - // init permutation - pk.Permutation = make([]int64, 3*sizeSolution) - for i := 0; i < len(pk.Permutation); i++ { - pk.Permutation[i] = -1 - } - - // init LRO position -> variable_ID - lro := make([]int, 3*sizeSolution) // position -> variable_ID - for i := 0; i < len(spr.Public); i++ { - lro[i] = i // IDs of LRO associated to placeholders (only L needs to be taken care of) - } - - offset := len(spr.Public) - - j := 0 - it := spr.GetSparseR1CIterator() - for c := it.Next(); c != nil; c = it.Next() { - lro[offset+j] = int(c.XA) - lro[sizeSolution+offset+j] = int(c.XB) - lro[2*sizeSolution+offset+j] = int(c.XC) - j++ - } - - // init cycle: - // map ID -> last position the ID was seen - cycle := make([]int64, nbVariables) - for i := 0; i < len(cycle); i++ { - cycle[i] = -1 - } - - for i := 0; i < len(lro); i++ { - if cycle[lro[i]] != -1 { - // if != -1, it means we already encountered this value - // so we need to set the corresponding permutation index. - pk.Permutation[i] = cycle[lro[i]] - } - cycle[lro[i]] = int64(i) - } - - // complete the Permutation by filling the first IDs encountered - for i := 0; i < len(pk.Permutation); i++ { - if pk.Permutation[i] == -1 { - pk.Permutation[i] = cycle[lro[i]] - } - } -} - -// computePermutationPolynomials computes the LDE (Lagrange basis) of the permutations -// s1, s2, s3. -// -// 0 1 .. n-1 | n n+1 .. 2*n-1 | 2n 2n+1 .. 3n-1 | -// -// | -// | Permutation -// -// s00 s01 .. s0n-1 s10 s11 .. s1n-1 s20 s21 .. s2n-1 v -// \---------------/ \--------------------/ \------------------------/ -// -// s1 (LDE) s2 (LDE) s3 (LDE) -func computePermutationPolynomials(pk *ProvingKey, vk *VerifyingKey) error { - - nbElmt := int(pk.Domain[0].Cardinality) - - // sID = [1,..,g^{n-1},s,..,s*g^{n-1},s^2,..,s^2*g^{n-1}] - pk.LId = getIDSmallDomain(&pk.Domain[0]) - - // canonical form of S1, S2, S3 - pk.EvaluationS1BigDomain = make([]fr.Element, pk.Domain[1].Cardinality) - pk.EvaluationS2BigDomain = make([]fr.Element, pk.Domain[1].Cardinality) - pk.EvaluationS3BigDomain = make([]fr.Element, pk.Domain[1].Cardinality) - for i := 0; i < nbElmt; i++ { - pk.EvaluationS1BigDomain[i].Set(&pk.LId[pk.Permutation[i]]) - pk.EvaluationS2BigDomain[i].Set(&pk.LId[pk.Permutation[nbElmt+i]]) - pk.EvaluationS3BigDomain[i].Set(&pk.LId[pk.Permutation[2*nbElmt+i]]) - } - - // Evaluations of Sid1, Sid2, Sid3 on cosets of Domain[1] - pk.EvaluationId1BigDomain = make([]fr.Element, pk.Domain[1].Cardinality) - pk.EvaluationId2BigDomain = make([]fr.Element, pk.Domain[1].Cardinality) - pk.EvaluationId3BigDomain = make([]fr.Element, pk.Domain[1].Cardinality) - copy(pk.EvaluationId1BigDomain, pk.LId[:nbElmt]) - copy(pk.EvaluationId2BigDomain, pk.LId[nbElmt:2*nbElmt]) - copy(pk.EvaluationId3BigDomain, pk.LId[2*nbElmt:]) - pk.Domain[0].FFTInverse(pk.EvaluationId1BigDomain[:pk.Domain[0].Cardinality], fft.DIF) - pk.Domain[0].FFTInverse(pk.EvaluationId2BigDomain[:pk.Domain[0].Cardinality], fft.DIF) - pk.Domain[0].FFTInverse(pk.EvaluationId3BigDomain[:pk.Domain[0].Cardinality], fft.DIF) - fft.BitReverse(pk.EvaluationId1BigDomain[:pk.Domain[0].Cardinality]) - fft.BitReverse(pk.EvaluationId2BigDomain[:pk.Domain[0].Cardinality]) - fft.BitReverse(pk.EvaluationId3BigDomain[:pk.Domain[0].Cardinality]) - vk.IdCanonical[0] = make([]fr.Element, pk.Domain[0].Cardinality) - vk.IdCanonical[1] = make([]fr.Element, pk.Domain[0].Cardinality) - vk.IdCanonical[2] = make([]fr.Element, pk.Domain[0].Cardinality) - copy(vk.IdCanonical[0], pk.EvaluationId1BigDomain) - copy(vk.IdCanonical[1], pk.EvaluationId2BigDomain) - copy(vk.IdCanonical[2], pk.EvaluationId3BigDomain) - - var err error - vk.Idpp[0], err = vk.Iopp.BuildProofOfProximity(pk.EvaluationId1BigDomain) - if err != nil { - return err - } - vk.Idpp[1], err = vk.Iopp.BuildProofOfProximity(pk.EvaluationId2BigDomain) - if err != nil { - return err - } - vk.Idpp[2], err = vk.Iopp.BuildProofOfProximity(pk.EvaluationId3BigDomain) - if err != nil { - return err - } - pk.Domain[1].FFT(pk.EvaluationId1BigDomain, fft.DIF, fft.OnCoset()) - pk.Domain[1].FFT(pk.EvaluationId2BigDomain, fft.DIF, fft.OnCoset()) - pk.Domain[1].FFT(pk.EvaluationId3BigDomain, fft.DIF, fft.OnCoset()) - - pk.Domain[0].FFTInverse(pk.EvaluationS1BigDomain[:pk.Domain[0].Cardinality], fft.DIF) - pk.Domain[0].FFTInverse(pk.EvaluationS2BigDomain[:pk.Domain[0].Cardinality], fft.DIF) - pk.Domain[0].FFTInverse(pk.EvaluationS3BigDomain[:pk.Domain[0].Cardinality], fft.DIF) - fft.BitReverse(pk.EvaluationS1BigDomain[:pk.Domain[0].Cardinality]) - fft.BitReverse(pk.EvaluationS2BigDomain[:pk.Domain[0].Cardinality]) - fft.BitReverse(pk.EvaluationS3BigDomain[:pk.Domain[0].Cardinality]) - - // commit S1, S2, S3 - vk.SCanonical[0] = make([]fr.Element, pk.Domain[0].Cardinality) - vk.SCanonical[1] = make([]fr.Element, pk.Domain[0].Cardinality) - vk.SCanonical[2] = make([]fr.Element, pk.Domain[0].Cardinality) - copy(vk.SCanonical[0], pk.EvaluationS1BigDomain[:pk.Domain[0].Cardinality]) - copy(vk.SCanonical[1], pk.EvaluationS2BigDomain[:pk.Domain[0].Cardinality]) - copy(vk.SCanonical[2], pk.EvaluationS3BigDomain[:pk.Domain[0].Cardinality]) - vk.Spp[0], err = vk.Iopp.BuildProofOfProximity(vk.SCanonical[0]) - if err != nil { - return err - } - vk.Spp[1], err = vk.Iopp.BuildProofOfProximity(vk.SCanonical[1]) - if err != nil { - return err - } - vk.Spp[2], err = vk.Iopp.BuildProofOfProximity(vk.SCanonical[2]) - if err != nil { - return err - } - pk.Domain[1].FFT(pk.EvaluationS1BigDomain, fft.DIF, fft.OnCoset()) - pk.Domain[1].FFT(pk.EvaluationS2BigDomain, fft.DIF, fft.OnCoset()) - pk.Domain[1].FFT(pk.EvaluationS3BigDomain, fft.DIF, fft.OnCoset()) - - return nil - -} - -// getIDSmallDomain returns the Lagrange form of ID on the small domain -func getIDSmallDomain(domain *fft.Domain) []fr.Element { - - res := make([]fr.Element, 3*domain.Cardinality) - - res[0].SetOne() - res[domain.Cardinality].Set(&domain.FrMultiplicativeGen) - res[2*domain.Cardinality].Square(&domain.FrMultiplicativeGen) - - for i := uint64(1); i < domain.Cardinality; i++ { - res[i].Mul(&res[i-1], &domain.Generator) - res[domain.Cardinality+i].Mul(&res[domain.Cardinality+i-1], &domain.Generator) - res[2*domain.Cardinality+i].Mul(&res[2*domain.Cardinality+i-1], &domain.Generator) - } - - return res -} - -// NbPublicWitness returns the expected public witness size (number of field elements) -func (vk *VerifyingKey) NbPublicWitness() int { - return int(vk.NbPublicVariables) -} - -// VerifyingKey returns pk.Vk -func (pk *ProvingKey) VerifyingKey() interface{} { - return pk.Vk -} diff --git a/backend/plonkfri/bls12-377/verify.go b/backend/plonkfri/bls12-377/verify.go deleted file mode 100644 index 88034fe0bb..0000000000 --- a/backend/plonkfri/bls12-377/verify.go +++ /dev/null @@ -1,398 +0,0 @@ -// Copyright 2020 ConsenSys Software Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -// Code generated by gnark DO NOT EDIT - -package plonkfri - -import ( - "errors" - "fmt" - "github.com/consensys/gnark-crypto/ecc/bls12-377/fr" - "github.com/consensys/gnark-crypto/ecc/bls12-377/fr/fri" - fiatshamir "github.com/consensys/gnark-crypto/fiat-shamir" - "github.com/consensys/gnark/backend" - "math/big" -) - -var ErrInvalidAlgebraicRelation = errors.New("algebraic relation does not hold") - -func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector, opts ...backend.VerifierOption) error { - cfg, err := backend.NewVerifierConfig(opts...) - if err != nil { - return fmt.Errorf("create backend config: %w", err) - } - - // 0 - derive the challenges with Fiat Shamir - fs := fiatshamir.NewTranscript(cfg.ChallengeHash, "gamma", "beta", "alpha", "zeta") - - dataFiatShamir := make([][fr.Bytes]byte, len(publicWitness)+3) - for i := 0; i < len(publicWitness); i++ { - copy(dataFiatShamir[i][:], publicWitness[i].Marshal()) - } - copy(dataFiatShamir[len(publicWitness)][:], proof.LROpp[0].ID) - copy(dataFiatShamir[len(publicWitness)+1][:], proof.LROpp[1].ID) - copy(dataFiatShamir[len(publicWitness)+2][:], proof.LROpp[2].ID) - - beta, err := deriveRandomnessFixedSize(fs, "gamma", dataFiatShamir...) - if err != nil { - return err - } - - gamma, err := deriveRandomness(fs, "beta", nil) - if err != nil { - return err - } - - alpha, err := deriveRandomness(fs, "alpha", proof.Zpp.ID) - if err != nil { - return err - } - - // compute the size of the domain of evaluation of the committed polynomial, - // the opening position. The challenge zeta will be g^{i} where i is the opening - // position, and g is the generator of the fri domain. - rho := uint64(fri.GetRho()) - friSize := 2 * rho * vk.Size - var bFriSize big.Int - bFriSize.SetInt64(int64(friSize)) - frOpeningPosition, err := deriveRandomness(fs, "zeta", proof.Hpp[0].ID, proof.Hpp[1].ID, proof.Hpp[2].ID) - if err != nil { - return err - } - var bOpeningPosition big.Int - bOpeningPosition.SetBytes(frOpeningPosition.Marshal()).Mod(&bOpeningPosition, &bFriSize) - openingPosition := bOpeningPosition.Uint64() - - shiftedOpeningPosition := (openingPosition + uint64(2*rho)) % friSize - err = vk.Iopp.VerifyOpening(shiftedOpeningPosition, proof.OpeningsZmp[1], proof.Zpp) - if err != nil { - return err - } - - // 1 - verify that the commitments are low degree polynomials - - // ql, qr, qm, qo, qkIncomplete - err = vk.Iopp.VerifyProofOfProximity(vk.Qpp[0]) - if err != nil { - return err - } - err = vk.Iopp.VerifyProofOfProximity(vk.Qpp[1]) - if err != nil { - return err - } - err = vk.Iopp.VerifyProofOfProximity(vk.Qpp[2]) - if err != nil { - return err - } - err = vk.Iopp.VerifyProofOfProximity(vk.Qpp[3]) - if err != nil { - return err - } - err = vk.Iopp.VerifyProofOfProximity(vk.Qpp[4]) - if err != nil { - return err - } - - // l, r, o - err = vk.Iopp.VerifyProofOfProximity(proof.LROpp[0]) - if err != nil { - return err - } - err = vk.Iopp.VerifyProofOfProximity(proof.LROpp[1]) - if err != nil { - return err - } - err = vk.Iopp.VerifyProofOfProximity(proof.LROpp[2]) - if err != nil { - return err - } - err = vk.Iopp.VerifyProofOfProximity(proof.Zpp) - if err != nil { - return err - } - - // h0, h1, h2 - err = vk.Iopp.VerifyProofOfProximity(proof.Hpp[0]) - if err != nil { - return err - } - err = vk.Iopp.VerifyProofOfProximity(proof.Hpp[1]) - if err != nil { - return err - } - err = vk.Iopp.VerifyProofOfProximity(proof.Hpp[2]) - if err != nil { - return err - } - - // s1, s2, s3 - err = vk.Iopp.VerifyProofOfProximity(vk.Spp[0]) - if err != nil { - return err - } - err = vk.Iopp.VerifyProofOfProximity(vk.Spp[1]) - if err != nil { - return err - } - err = vk.Iopp.VerifyProofOfProximity(vk.Spp[2]) - if err != nil { - return err - } - - // id1, id2, id3 - err = vk.Iopp.VerifyProofOfProximity(vk.Idpp[0]) - if err != nil { - return err - } - err = vk.Iopp.VerifyProofOfProximity(vk.Idpp[1]) - if err != nil { - return err - } - err = vk.Iopp.VerifyProofOfProximity(vk.Idpp[2]) - if err != nil { - return err - } - - // Z - err = vk.Iopp.VerifyProofOfProximity(proof.Zpp) - if err != nil { - return err - } - - // 2 - verify the openings - - // ql, qr, qm, qo, qkIncomplete - // openingPosition := uint64(2) - err = vk.Iopp.VerifyOpening(openingPosition, proof.OpeningsQlQrQmQoQkincompletemp[0], vk.Qpp[0]) - if err != nil { - return err - } - err = vk.Iopp.VerifyOpening(openingPosition, proof.OpeningsQlQrQmQoQkincompletemp[1], vk.Qpp[1]) - if err != nil { - return err - } - err = vk.Iopp.VerifyOpening(openingPosition, proof.OpeningsQlQrQmQoQkincompletemp[2], vk.Qpp[2]) - if err != nil { - return err - } - err = vk.Iopp.VerifyOpening(openingPosition, proof.OpeningsQlQrQmQoQkincompletemp[3], vk.Qpp[3]) - if err != nil { - return err - } - err = vk.Iopp.VerifyOpening(openingPosition, proof.OpeningsQlQrQmQoQkincompletemp[4], vk.Qpp[4]) - if err != nil { - return err - } - - // l, r, o - err = vk.Iopp.VerifyOpening(openingPosition, proof.OpeningsLROmp[0], proof.LROpp[0]) - if err != nil { - return err - } - err = vk.Iopp.VerifyOpening(openingPosition, proof.OpeningsLROmp[1], proof.LROpp[1]) - if err != nil { - return err - } - err = vk.Iopp.VerifyOpening(openingPosition, proof.OpeningsLROmp[2], proof.LROpp[2]) - if err != nil { - return err - } - - // h0, h1, h2 - err = vk.Iopp.VerifyOpening(openingPosition, proof.OpeningsHmp[0], proof.Hpp[0]) - if err != nil { - return err - } - err = vk.Iopp.VerifyOpening(openingPosition, proof.OpeningsHmp[1], proof.Hpp[1]) - if err != nil { - return err - } - err = vk.Iopp.VerifyOpening(openingPosition, proof.OpeningsHmp[2], proof.Hpp[2]) - if err != nil { - return err - } - - // s0, s1, s2 - err = vk.Iopp.VerifyOpening(openingPosition, proof.OpeningsS1S2S3mp[0], vk.Spp[0]) - if err != nil { - return err - } - err = vk.Iopp.VerifyOpening(openingPosition, proof.OpeningsS1S2S3mp[1], vk.Spp[1]) - if err != nil { - return err - } - err = vk.Iopp.VerifyOpening(openingPosition, proof.OpeningsS1S2S3mp[2], vk.Spp[2]) - if err != nil { - return err - } - - // id0, id1, id2 - err = vk.Iopp.VerifyOpening(openingPosition, proof.OpeningsId1Id2Id3mp[0], vk.Idpp[0]) - if err != nil { - return err - } - err = vk.Iopp.VerifyOpening(openingPosition, proof.OpeningsId1Id2Id3mp[1], vk.Idpp[1]) - if err != nil { - return err - } - err = vk.Iopp.VerifyOpening(openingPosition, proof.OpeningsId1Id2Id3mp[2], vk.Idpp[2]) - if err != nil { - return err - } - - // Z, Zshift - err = vk.Iopp.VerifyOpening(openingPosition, proof.OpeningsZmp[0], proof.Zpp) - if err != nil { - return err - } - - // verification of the algebraic relation - var ql, qr, qm, qo, qk fr.Element - ql.Set(&proof.OpeningsQlQrQmQoQkincompletemp[0].ClaimedValue) - qr.Set(&proof.OpeningsQlQrQmQoQkincompletemp[1].ClaimedValue) - qm.Set(&proof.OpeningsQlQrQmQoQkincompletemp[2].ClaimedValue) - qo.Set(&proof.OpeningsQlQrQmQoQkincompletemp[3].ClaimedValue) - qk.Set(&proof.OpeningsQlQrQmQoQkincompletemp[4].ClaimedValue) // -> to be completed - - var l, r, o fr.Element - l.Set(&proof.OpeningsLROmp[0].ClaimedValue) - r.Set(&proof.OpeningsLROmp[1].ClaimedValue) - o.Set(&proof.OpeningsLROmp[2].ClaimedValue) - - var h1, h2, h3 fr.Element - h1.Set(&proof.OpeningsHmp[0].ClaimedValue) - h2.Set(&proof.OpeningsHmp[1].ClaimedValue) - h3.Set(&proof.OpeningsHmp[2].ClaimedValue) - - var s1, s2, s3 fr.Element - s1.Set(&proof.OpeningsS1S2S3mp[0].ClaimedValue) - s2.Set(&proof.OpeningsS1S2S3mp[1].ClaimedValue) - s3.Set(&proof.OpeningsS1S2S3mp[2].ClaimedValue) - - var id1, id2, id3 fr.Element - id1.Set(&proof.OpeningsId1Id2Id3mp[0].ClaimedValue) - id2.Set(&proof.OpeningsId1Id2Id3mp[1].ClaimedValue) - id3.Set(&proof.OpeningsId1Id2Id3mp[2].ClaimedValue) - - var z, zshift fr.Element - z.Set(&proof.OpeningsZmp[0].ClaimedValue) - zshift.Set(&proof.OpeningsZmp[1].ClaimedValue) - - // 2 - compute the LHS: (ql*l+..+qk)+ α*(z(μx)*(l+β*s₁+γ)*..-z*(l+β*id1+γ))+α²*z*(l1-1) - var zeta fr.Element - zeta.Exp(vk.GenOpening, &bOpeningPosition) - - var lhs, t1, t2, t3, tmp, tmp2 fr.Element - // 2.1 (ql*l+..+qk) - t1.Mul(&l, &ql) - tmp.Mul(&r, &qr) - t1.Add(&t1, &tmp) - tmp.Mul(&qm, &l).Mul(&tmp, &r) - t1.Add(&t1, &tmp) - tmp.Mul(&o, &qo) - t1.Add(&tmp, &t1) - tmp = completeQk(publicWitness, vk, zeta) - tmp.Add(&qk, &tmp) - t1.Add(&tmp, &t1) - - // 2.2 (z(ux)*(l+β*s1+γ)*..-z*(l+β*id1+γ)) - t2.Mul(&beta, &s1).Add(&t2, &l).Add(&t2, &gamma) - tmp.Mul(&beta, &s2).Add(&tmp, &r).Add(&tmp, &gamma) - t2.Mul(&tmp, &t2) - tmp.Mul(&beta, &s3).Add(&tmp, &o).Add(&tmp, &gamma) - t2.Mul(&tmp, &t2).Mul(&t2, &zshift) - - tmp.Mul(&beta, &id1).Add(&tmp, &l).Add(&tmp, &gamma) - tmp2.Mul(&beta, &id2).Add(&tmp2, &r).Add(&tmp2, &gamma) - tmp.Mul(&tmp, &tmp2) - tmp2.Mul(&beta, &id3).Add(&tmp2, &o).Add(&tmp2, &gamma) - tmp.Mul(&tmp2, &tmp).Mul(&tmp, &z) - - t2.Sub(&t2, &tmp) - - // 2.3 (z-1)*l1 - var one fr.Element - one.SetOne() - t3.Exp(zeta, big.NewInt(int64(vk.Size))).Sub(&t3, &one) - tmp.Sub(&zeta, &one).Inverse(&tmp).Mul(&tmp, &vk.SizeInv) - t3.Mul(&tmp, &t3) - tmp.Sub(&z, &one) - t3.Mul(&tmp, &t3) - - // 2.4 (ql*l+s+qk) + α*(z(ux)*(l+β*s1+γ)*...-z*(l+β*id1+γ)..)+ α²*z*(l1-1) - lhs.Set(&t3).Mul(&lhs, &alpha).Add(&lhs, &t2).Mul(&lhs, &alpha).Add(&lhs, &t1) - - // 3 - compute the RHS - var rhs fr.Element - tmp.Exp(zeta, big.NewInt(int64(vk.Size+2))) - rhs.Mul(&h3, &tmp). - Add(&rhs, &h2). - Mul(&rhs, &tmp). - Add(&rhs, &h1) - - tmp.Exp(zeta, big.NewInt(int64(vk.Size))).Sub(&tmp, &one) - rhs.Mul(&rhs, &tmp) - - // 4 - verify the relation LHS==RHS - if !rhs.Equal(&lhs) { - return ErrInvalidAlgebraicRelation - } - - return nil - -} - -// completeQk returns ∑_{i> nn - _is := bits.Reverse64(uint64((i+toShift)%nbElmts)) >> nn - - // in what follows gⁱ is understood as the generator of the chosen coset of domainBig - f[0].Mul(&evaluationIDBigDomain, &beta).Add(&f[0], &l[_i]).Add(&f[0], &gamma) //l(gⁱ)+gⁱ*β+γ - f[1].Mul(&evaluationIDBigDomain, &cosetShift).Mul(&f[1], &beta).Add(&f[1], &r[_i]).Add(&f[1], &gamma) //r(gⁱ)+u*gⁱ*β+γ - f[2].Mul(&evaluationIDBigDomain, &cosetShiftSquare).Mul(&f[2], &beta).Add(&f[2], &o[_i]).Add(&f[2], &gamma) //o(gⁱ)+u²*gⁱ*β+γ - - g[0].Mul(&pk.EvaluationS1BigDomain[_i], &beta).Add(&g[0], &l[_i]).Add(&g[0], &gamma) //l(gⁱ))+s1(gⁱ)*β+γ - g[1].Mul(&pk.EvaluationS2BigDomain[_i], &beta).Add(&g[1], &r[_i]).Add(&g[1], &gamma) //r(gⁱ))+s2(gⁱ)*β+γ - g[2].Mul(&pk.EvaluationS3BigDomain[_i], &beta).Add(&g[2], &o[_i]).Add(&g[2], &gamma) //o(gⁱ))+s3(gⁱ)*β+γ - - f[0].Mul(&f[0], &f[1]).Mul(&f[0], &f[2]).Mul(&f[0], &z[_i]) // z(gⁱ)*(l(gⁱ)+g^i*β+γ)*(r(g^i)+u*g^i*β+γ)*(o(g^i)+u²*g^i*β+γ) - g[0].Mul(&g[0], &g[1]).Mul(&g[0], &g[2]).Mul(&g[0], &z[_is]) // z_(ugⁱ)*(l(gⁱ))+s₁(gⁱ)*β+γ)*(r(gⁱ))+s₂(gⁱ)*β+γ)*(o(gⁱ))+s₃(gⁱ)*β+γ) - - res[_i].Sub(&g[0], &f[0]) // z_(ugⁱ)*(l(gⁱ))+s₁(gⁱ)*β+γ)*(r(gⁱ))+s₂(gⁱ)*β+γ)*(o(gⁱ))+s₃(gⁱ)*β+γ) - z(gⁱ)*(l(gⁱ)+g^i*β+γ)*(r(g^i)+u*g^i*β+γ)*(o(g^i)+u²*g^i*β+γ) - - evaluationIDBigDomain.Mul(&evaluationIDBigDomain, &pk.Domain[1].Generator) // gⁱ*g - } - }) - - return res -} - -// evalConstraintsInd computes the evaluation of lL+qrR+qqmL.R+qoO+k on -// the odd coset of (Z/8mZ)/(Z/4mZ), where m=nbConstraints+nbAssertions. -// -// * lsL, lsR, lsO are the evaluation of the blinded solution vectors on odd cosets -// * lsQk is the completed version of qk, in canonical version -// -// lsL, lsR, lsO are in bit reversed order, lsQk is in the correct order. -func evalConstraintsInd(pk *ProvingKey, lsL, lsR, lsO, lsQk []fr.Element) []fr.Element { - - res := make([]fr.Element, pk.Domain[1].Cardinality) - // nn := uint64(64 - bits.TrailingZeros64(pk.Domain[1].Cardinality)) - - utils.Parallelize(len(res), func(start, end int) { - - var t0, t1 fr.Element - - for i := start; i < end; i++ { - - // irev := bits.Reverse64(uint64(i)) >> nn - - t1.Mul(&pk.EvaluationQmDomainBigBitReversed[i], &lsR[i]) // qm.r - t1.Add(&t1, &pk.EvaluationQlDomainBigBitReversed[i]) // qm.r + ql - t1.Mul(&t1, &lsL[i]) // qm.l.r + ql.l - - t0.Mul(&pk.EvaluationQrDomainBigBitReversed[i], &lsR[i]) - t0.Add(&t0, &t1) // qm.l.r + ql.l + qr.r - - t1.Mul(&pk.EvaluationQoDomainBigBitReversed[i], &lsO[i]) - t0.Add(&t0, &t1) // ql.l + qr.r + qm.l.r + qo.o - res[i].Add(&t0, &lsQk[i]) // ql.l + qr.r + qm.l.r + qo.o + k - - } - }) - - return res -} - -// fftBigCosetWOBitReverse evaluates poly (canonical form) of degree m> nn - - t.Sub(&evaluationBlindedZDomainBigBitReversed[_i], &one) // evaluates L₁(X)*(Z(X)-1) on a coset of the big domain - h[_i].Mul(&startsAtOne[_i], &t).Mul(&h[_i], &alpha). - Add(&h[_i], &evaluationConstraintOrderingBitReversed[_i]). - Mul(&h[_i], &alpha). - Add(&h[_i], &evaluationConstraintsIndBitReversed[_i]). - Mul(&h[_i], &evaluationXnMinusOneInverse[i%ratio]) - } - }) - - // put h in canonical form. h is of degree 3*(n+1)+2. - // using fft.DIT put h revert bit reverse - pk.Domain[1].FFTInverse(h, fft.DIT, fft.OnCoset()) - - // degree of hi is n+2 because of the blinding - h1 := h[:pk.Domain[0].Cardinality+2] - h2 := h[pk.Domain[0].Cardinality+2 : 2*(pk.Domain[0].Cardinality+2)] - h3 := h[2*(pk.Domain[0].Cardinality+2) : 3*(pk.Domain[0].Cardinality+2)] - - return h1, h2, h3 - -} - -// computeZ computes Z, in canonical basis, where: -// -// - Z of degree n (domainNum.Cardinality) -// -// - Z(1)=1 -// (l_i+z**i+gamma)*(r_i+u*z**i+gamma)*(o_i+u**2z**i+gamma) -// -// - for i>0: Z(u**i) = Pi_{k "small" domain, used for individual polynomials - // 1 -> "big" domain, used for the computation of the quotient - Domain [2]fft.Domain - - // s1, s2, s3 (L=Lagrange basis small domain, C=canonical basis, Ls=Lagrange Shifted big domain) - LId []fr.Element - EvaluationId1BigDomain, EvaluationId2BigDomain, EvaluationId3BigDomain []fr.Element - EvaluationS1BigDomain, EvaluationS2BigDomain, EvaluationS3BigDomain []fr.Element - - // position -> permuted position (position in [0,3*sizeSystem-1]) - Permutation []int64 -} - -// VerifyingKey stores the data needed to verify a proof: -// * The commitment scheme -// * Commitments of ql prepended with as many ones as there are public inputs -// * Commitments of qr, qm, qo, qk prepended with as many zeroes as there are public inputs -// * Commitments to S1, S2, S3 -type VerifyingKey struct { - - // Size circuit, that is the closest power of 2 bounding above - // number of constraints+number of public inputs - Size uint64 - SizeInv fr.Element - Generator fr.Element - NbPublicVariables uint64 - - // cosetShift generator of the coset on the small domain - CosetShift fr.Element - - // S commitments to S1, S2, S3 - SCanonical [3][]fr.Element - Spp [3]fri.ProofOfProximity - - // Id commitments to Id1, Id2, Id3 - // Id [3]Commitment - IdCanonical [3][]fr.Element - Idpp [3]fri.ProofOfProximity - - // Commitments to ql, qr, qm, qo prepended with as many zeroes (ones for l) as there are public inputs. - // In particular Qk is not complete. - Qpp [5]fri.ProofOfProximity // Ql, Qr, Qm, Qo, Qk - - // Iopp scheme (currently one for each size of polynomial) - Iopp fri.Iopp - - // generator of the group on which the Iopp works. If i is the opening position, - // the polynomials will be opened at genOpening^{i}. - GenOpening fr.Element -} - -// Setup sets proving and verifying keys -func Setup(spr *cs.SparseR1CS) (*ProvingKey, *VerifyingKey, error) { - - var pk ProvingKey - var vk VerifyingKey - - // The verifying key shares data with the proving key - pk.Vk = &vk - - nbConstraints := spr.GetNbConstraints() - - // fft domains - sizeSystem := uint64(nbConstraints + len(spr.Public)) // len(spr.Public) is for the placeholder constraints - pk.Domain[0] = *fft.NewDomain(sizeSystem) - - // h, the quotient polynomial is of degree 3(n+1)+2, so it's in a 3(n+2) dim vector space, - // the domain is the next power of 2 superior to 3(n+2). 4*domainNum is enough in all cases - // except when n<6. - if sizeSystem < 6 { - pk.Domain[1] = *fft.NewDomain(8 * sizeSystem) - } else { - pk.Domain[1] = *fft.NewDomain(4 * sizeSystem) - } - pk.Vk.CosetShift.Set(&pk.Domain[0].FrMultiplicativeGen) - - vk.Size = pk.Domain[0].Cardinality - vk.SizeInv.SetUint64(vk.Size).Inverse(&vk.SizeInv) - vk.Generator.Set(&pk.Domain[0].Generator) - vk.NbPublicVariables = uint64(len(spr.Public)) - - // IOP schemess - // The +2 is to handle the blinding. - sizeIopp := pk.Domain[0].Cardinality + 2 - vk.Iopp = fri.RADIX_2_FRI.New(sizeIopp, sha256.New()) - // only there to access the group used in FRI... - rho := uint64(fri.GetRho()) - // we multiply by 2 because the IOP is created with size pk.Domain[0].Cardinality + 2 (because - // of the blinding), so the domain will be rho*size_domain where size_domain is the next power - // of 2 after pk.Domain[0].Cardinality + 2, which is 2*rho*pk.Domain[0].Cardinality - tmpDomain := fft.NewDomain(2 * rho * pk.Domain[0].Cardinality) - vk.GenOpening.Set(&tmpDomain.Generator) - - // public polynomials corresponding to constraints: [ placholders | constraints | assertions ] - pk.EvaluationQlDomainBigBitReversed = make([]fr.Element, pk.Domain[1].Cardinality) - pk.EvaluationQrDomainBigBitReversed = make([]fr.Element, pk.Domain[1].Cardinality) - pk.EvaluationQmDomainBigBitReversed = make([]fr.Element, pk.Domain[1].Cardinality) - pk.EvaluationQoDomainBigBitReversed = make([]fr.Element, pk.Domain[1].Cardinality) - pk.LQkIncompleteDomainSmall = make([]fr.Element, pk.Domain[0].Cardinality) - pk.CQkIncomplete = make([]fr.Element, pk.Domain[0].Cardinality) - - for i := 0; i < len(spr.Public); i++ { // placeholders (-PUB_INPUT_i + qk_i = 0) TODO should return error if size is inconsistent - pk.EvaluationQlDomainBigBitReversed[i].SetOne().Neg(&pk.EvaluationQlDomainBigBitReversed[i]) - pk.EvaluationQrDomainBigBitReversed[i].SetZero() - pk.EvaluationQmDomainBigBitReversed[i].SetZero() - pk.EvaluationQoDomainBigBitReversed[i].SetZero() - pk.LQkIncompleteDomainSmall[i].SetZero() // --> to be completed by the prover - pk.CQkIncomplete[i].Set(&pk.LQkIncompleteDomainSmall[i]) // --> to be completed by the prover - } - offset := len(spr.Public) - - j := 0 - it := spr.GetSparseR1CIterator() - for c := it.Next(); c != nil; c = it.Next() { - pk.EvaluationQlDomainBigBitReversed[offset+j].Set(&spr.Coefficients[c.QL]) - pk.EvaluationQrDomainBigBitReversed[offset+j].Set(&spr.Coefficients[c.QR]) - pk.EvaluationQmDomainBigBitReversed[offset+j].Set(&spr.Coefficients[c.QM]) - pk.EvaluationQoDomainBigBitReversed[offset+j].Set(&spr.Coefficients[c.QO]) - pk.LQkIncompleteDomainSmall[offset+j].Set(&spr.Coefficients[c.QC]) - pk.CQkIncomplete[offset+j].Set(&pk.LQkIncompleteDomainSmall[offset+j]) - - j++ - } - - pk.Domain[0].FFTInverse(pk.EvaluationQlDomainBigBitReversed[:pk.Domain[0].Cardinality], fft.DIF) - pk.Domain[0].FFTInverse(pk.EvaluationQrDomainBigBitReversed[:pk.Domain[0].Cardinality], fft.DIF) - pk.Domain[0].FFTInverse(pk.EvaluationQmDomainBigBitReversed[:pk.Domain[0].Cardinality], fft.DIF) - pk.Domain[0].FFTInverse(pk.EvaluationQoDomainBigBitReversed[:pk.Domain[0].Cardinality], fft.DIF) - pk.Domain[0].FFTInverse(pk.CQkIncomplete, fft.DIF) - fft.BitReverse(pk.EvaluationQlDomainBigBitReversed[:pk.Domain[0].Cardinality]) - fft.BitReverse(pk.EvaluationQrDomainBigBitReversed[:pk.Domain[0].Cardinality]) - fft.BitReverse(pk.EvaluationQmDomainBigBitReversed[:pk.Domain[0].Cardinality]) - fft.BitReverse(pk.EvaluationQoDomainBigBitReversed[:pk.Domain[0].Cardinality]) - fft.BitReverse(pk.CQkIncomplete) - - // Commit to the polynomials to set up the verifying key - pk.CQl = make([]fr.Element, pk.Domain[0].Cardinality) - pk.CQr = make([]fr.Element, pk.Domain[0].Cardinality) - pk.CQm = make([]fr.Element, pk.Domain[0].Cardinality) - pk.CQo = make([]fr.Element, pk.Domain[0].Cardinality) - copy(pk.CQl, pk.EvaluationQlDomainBigBitReversed) - copy(pk.CQr, pk.EvaluationQrDomainBigBitReversed) - copy(pk.CQm, pk.EvaluationQmDomainBigBitReversed) - copy(pk.CQo, pk.EvaluationQoDomainBigBitReversed) - var err error - vk.Qpp[0], err = vk.Iopp.BuildProofOfProximity(pk.CQl) - if err != nil { - return &pk, &vk, err - } - vk.Qpp[1], err = vk.Iopp.BuildProofOfProximity(pk.CQr) - if err != nil { - return &pk, &vk, err - } - vk.Qpp[2], err = vk.Iopp.BuildProofOfProximity(pk.CQm) - if err != nil { - return &pk, &vk, err - } - vk.Qpp[3], err = vk.Iopp.BuildProofOfProximity(pk.CQo) - if err != nil { - return &pk, &vk, err - } - vk.Qpp[4], err = vk.Iopp.BuildProofOfProximity(pk.CQkIncomplete) - if err != nil { - return &pk, &vk, err - } - - pk.Domain[1].FFT(pk.EvaluationQlDomainBigBitReversed, fft.DIF, fft.OnCoset()) - pk.Domain[1].FFT(pk.EvaluationQrDomainBigBitReversed, fft.DIF, fft.OnCoset()) - pk.Domain[1].FFT(pk.EvaluationQmDomainBigBitReversed, fft.DIF, fft.OnCoset()) - pk.Domain[1].FFT(pk.EvaluationQoDomainBigBitReversed, fft.DIF, fft.OnCoset()) - - // build permutation. Note: at this stage, the permutation takes in account the placeholders - buildPermutation(spr, &pk) - - // set s1, s2, s3 - err = computePermutationPolynomials(&pk, &vk) - if err != nil { - return &pk, &vk, err - } - - return &pk, &vk, nil - -} - -// buildPermutation builds the Permutation associated with a circuit. -// -// The permutation s is composed of cycles of maximum length such that -// -// s. (l||r||o) = (l||r||o) -// -// , where l||r||o is the concatenation of the indices of l, r, o in -// ql.l+qr.r+qm.l.r+qo.O+k = 0. -// -// The permutation is encoded as a slice s of size 3*size(l), where the -// i-th entry of l||r||o is sent to the s[i]-th entry, so it acts on a tab -// like this: for i in tab: tab[i] = tab[permutation[i]] -func buildPermutation(spr *cs.SparseR1CS, pk *ProvingKey) { - - nbVariables := spr.NbInternalVariables + len(spr.Public) + len(spr.Secret) - sizeSolution := int(pk.Domain[0].Cardinality) - - // init permutation - pk.Permutation = make([]int64, 3*sizeSolution) - for i := 0; i < len(pk.Permutation); i++ { - pk.Permutation[i] = -1 - } - - // init LRO position -> variable_ID - lro := make([]int, 3*sizeSolution) // position -> variable_ID - for i := 0; i < len(spr.Public); i++ { - lro[i] = i // IDs of LRO associated to placeholders (only L needs to be taken care of) - } - - offset := len(spr.Public) - - j := 0 - it := spr.GetSparseR1CIterator() - for c := it.Next(); c != nil; c = it.Next() { - lro[offset+j] = int(c.XA) - lro[sizeSolution+offset+j] = int(c.XB) - lro[2*sizeSolution+offset+j] = int(c.XC) - j++ - } - - // init cycle: - // map ID -> last position the ID was seen - cycle := make([]int64, nbVariables) - for i := 0; i < len(cycle); i++ { - cycle[i] = -1 - } - - for i := 0; i < len(lro); i++ { - if cycle[lro[i]] != -1 { - // if != -1, it means we already encountered this value - // so we need to set the corresponding permutation index. - pk.Permutation[i] = cycle[lro[i]] - } - cycle[lro[i]] = int64(i) - } - - // complete the Permutation by filling the first IDs encountered - for i := 0; i < len(pk.Permutation); i++ { - if pk.Permutation[i] == -1 { - pk.Permutation[i] = cycle[lro[i]] - } - } -} - -// computePermutationPolynomials computes the LDE (Lagrange basis) of the permutations -// s1, s2, s3. -// -// 0 1 .. n-1 | n n+1 .. 2*n-1 | 2n 2n+1 .. 3n-1 | -// -// | -// | Permutation -// -// s00 s01 .. s0n-1 s10 s11 .. s1n-1 s20 s21 .. s2n-1 v -// \---------------/ \--------------------/ \------------------------/ -// -// s1 (LDE) s2 (LDE) s3 (LDE) -func computePermutationPolynomials(pk *ProvingKey, vk *VerifyingKey) error { - - nbElmt := int(pk.Domain[0].Cardinality) - - // sID = [1,..,g^{n-1},s,..,s*g^{n-1},s^2,..,s^2*g^{n-1}] - pk.LId = getIDSmallDomain(&pk.Domain[0]) - - // canonical form of S1, S2, S3 - pk.EvaluationS1BigDomain = make([]fr.Element, pk.Domain[1].Cardinality) - pk.EvaluationS2BigDomain = make([]fr.Element, pk.Domain[1].Cardinality) - pk.EvaluationS3BigDomain = make([]fr.Element, pk.Domain[1].Cardinality) - for i := 0; i < nbElmt; i++ { - pk.EvaluationS1BigDomain[i].Set(&pk.LId[pk.Permutation[i]]) - pk.EvaluationS2BigDomain[i].Set(&pk.LId[pk.Permutation[nbElmt+i]]) - pk.EvaluationS3BigDomain[i].Set(&pk.LId[pk.Permutation[2*nbElmt+i]]) - } - - // Evaluations of Sid1, Sid2, Sid3 on cosets of Domain[1] - pk.EvaluationId1BigDomain = make([]fr.Element, pk.Domain[1].Cardinality) - pk.EvaluationId2BigDomain = make([]fr.Element, pk.Domain[1].Cardinality) - pk.EvaluationId3BigDomain = make([]fr.Element, pk.Domain[1].Cardinality) - copy(pk.EvaluationId1BigDomain, pk.LId[:nbElmt]) - copy(pk.EvaluationId2BigDomain, pk.LId[nbElmt:2*nbElmt]) - copy(pk.EvaluationId3BigDomain, pk.LId[2*nbElmt:]) - pk.Domain[0].FFTInverse(pk.EvaluationId1BigDomain[:pk.Domain[0].Cardinality], fft.DIF) - pk.Domain[0].FFTInverse(pk.EvaluationId2BigDomain[:pk.Domain[0].Cardinality], fft.DIF) - pk.Domain[0].FFTInverse(pk.EvaluationId3BigDomain[:pk.Domain[0].Cardinality], fft.DIF) - fft.BitReverse(pk.EvaluationId1BigDomain[:pk.Domain[0].Cardinality]) - fft.BitReverse(pk.EvaluationId2BigDomain[:pk.Domain[0].Cardinality]) - fft.BitReverse(pk.EvaluationId3BigDomain[:pk.Domain[0].Cardinality]) - vk.IdCanonical[0] = make([]fr.Element, pk.Domain[0].Cardinality) - vk.IdCanonical[1] = make([]fr.Element, pk.Domain[0].Cardinality) - vk.IdCanonical[2] = make([]fr.Element, pk.Domain[0].Cardinality) - copy(vk.IdCanonical[0], pk.EvaluationId1BigDomain) - copy(vk.IdCanonical[1], pk.EvaluationId2BigDomain) - copy(vk.IdCanonical[2], pk.EvaluationId3BigDomain) - - var err error - vk.Idpp[0], err = vk.Iopp.BuildProofOfProximity(pk.EvaluationId1BigDomain) - if err != nil { - return err - } - vk.Idpp[1], err = vk.Iopp.BuildProofOfProximity(pk.EvaluationId2BigDomain) - if err != nil { - return err - } - vk.Idpp[2], err = vk.Iopp.BuildProofOfProximity(pk.EvaluationId3BigDomain) - if err != nil { - return err - } - pk.Domain[1].FFT(pk.EvaluationId1BigDomain, fft.DIF, fft.OnCoset()) - pk.Domain[1].FFT(pk.EvaluationId2BigDomain, fft.DIF, fft.OnCoset()) - pk.Domain[1].FFT(pk.EvaluationId3BigDomain, fft.DIF, fft.OnCoset()) - - pk.Domain[0].FFTInverse(pk.EvaluationS1BigDomain[:pk.Domain[0].Cardinality], fft.DIF) - pk.Domain[0].FFTInverse(pk.EvaluationS2BigDomain[:pk.Domain[0].Cardinality], fft.DIF) - pk.Domain[0].FFTInverse(pk.EvaluationS3BigDomain[:pk.Domain[0].Cardinality], fft.DIF) - fft.BitReverse(pk.EvaluationS1BigDomain[:pk.Domain[0].Cardinality]) - fft.BitReverse(pk.EvaluationS2BigDomain[:pk.Domain[0].Cardinality]) - fft.BitReverse(pk.EvaluationS3BigDomain[:pk.Domain[0].Cardinality]) - - // commit S1, S2, S3 - vk.SCanonical[0] = make([]fr.Element, pk.Domain[0].Cardinality) - vk.SCanonical[1] = make([]fr.Element, pk.Domain[0].Cardinality) - vk.SCanonical[2] = make([]fr.Element, pk.Domain[0].Cardinality) - copy(vk.SCanonical[0], pk.EvaluationS1BigDomain[:pk.Domain[0].Cardinality]) - copy(vk.SCanonical[1], pk.EvaluationS2BigDomain[:pk.Domain[0].Cardinality]) - copy(vk.SCanonical[2], pk.EvaluationS3BigDomain[:pk.Domain[0].Cardinality]) - vk.Spp[0], err = vk.Iopp.BuildProofOfProximity(vk.SCanonical[0]) - if err != nil { - return err - } - vk.Spp[1], err = vk.Iopp.BuildProofOfProximity(vk.SCanonical[1]) - if err != nil { - return err - } - vk.Spp[2], err = vk.Iopp.BuildProofOfProximity(vk.SCanonical[2]) - if err != nil { - return err - } - pk.Domain[1].FFT(pk.EvaluationS1BigDomain, fft.DIF, fft.OnCoset()) - pk.Domain[1].FFT(pk.EvaluationS2BigDomain, fft.DIF, fft.OnCoset()) - pk.Domain[1].FFT(pk.EvaluationS3BigDomain, fft.DIF, fft.OnCoset()) - - return nil - -} - -// getIDSmallDomain returns the Lagrange form of ID on the small domain -func getIDSmallDomain(domain *fft.Domain) []fr.Element { - - res := make([]fr.Element, 3*domain.Cardinality) - - res[0].SetOne() - res[domain.Cardinality].Set(&domain.FrMultiplicativeGen) - res[2*domain.Cardinality].Square(&domain.FrMultiplicativeGen) - - for i := uint64(1); i < domain.Cardinality; i++ { - res[i].Mul(&res[i-1], &domain.Generator) - res[domain.Cardinality+i].Mul(&res[domain.Cardinality+i-1], &domain.Generator) - res[2*domain.Cardinality+i].Mul(&res[2*domain.Cardinality+i-1], &domain.Generator) - } - - return res -} - -// NbPublicWitness returns the expected public witness size (number of field elements) -func (vk *VerifyingKey) NbPublicWitness() int { - return int(vk.NbPublicVariables) -} - -// VerifyingKey returns pk.Vk -func (pk *ProvingKey) VerifyingKey() interface{} { - return pk.Vk -} diff --git a/backend/plonkfri/bls12-381/verify.go b/backend/plonkfri/bls12-381/verify.go deleted file mode 100644 index 1ee33e1eee..0000000000 --- a/backend/plonkfri/bls12-381/verify.go +++ /dev/null @@ -1,398 +0,0 @@ -// Copyright 2020 ConsenSys Software Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -// Code generated by gnark DO NOT EDIT - -package plonkfri - -import ( - "errors" - "fmt" - "github.com/consensys/gnark-crypto/ecc/bls12-381/fr" - "github.com/consensys/gnark-crypto/ecc/bls12-381/fr/fri" - fiatshamir "github.com/consensys/gnark-crypto/fiat-shamir" - "github.com/consensys/gnark/backend" - "math/big" -) - -var ErrInvalidAlgebraicRelation = errors.New("algebraic relation does not hold") - -func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector, opts ...backend.VerifierOption) error { - cfg, err := backend.NewVerifierConfig(opts...) - if err != nil { - return fmt.Errorf("create backend config: %w", err) - } - - // 0 - derive the challenges with Fiat Shamir - fs := fiatshamir.NewTranscript(cfg.ChallengeHash, "gamma", "beta", "alpha", "zeta") - - dataFiatShamir := make([][fr.Bytes]byte, len(publicWitness)+3) - for i := 0; i < len(publicWitness); i++ { - copy(dataFiatShamir[i][:], publicWitness[i].Marshal()) - } - copy(dataFiatShamir[len(publicWitness)][:], proof.LROpp[0].ID) - copy(dataFiatShamir[len(publicWitness)+1][:], proof.LROpp[1].ID) - copy(dataFiatShamir[len(publicWitness)+2][:], proof.LROpp[2].ID) - - beta, err := deriveRandomnessFixedSize(fs, "gamma", dataFiatShamir...) - if err != nil { - return err - } - - gamma, err := deriveRandomness(fs, "beta", nil) - if err != nil { - return err - } - - alpha, err := deriveRandomness(fs, "alpha", proof.Zpp.ID) - if err != nil { - return err - } - - // compute the size of the domain of evaluation of the committed polynomial, - // the opening position. The challenge zeta will be g^{i} where i is the opening - // position, and g is the generator of the fri domain. - rho := uint64(fri.GetRho()) - friSize := 2 * rho * vk.Size - var bFriSize big.Int - bFriSize.SetInt64(int64(friSize)) - frOpeningPosition, err := deriveRandomness(fs, "zeta", proof.Hpp[0].ID, proof.Hpp[1].ID, proof.Hpp[2].ID) - if err != nil { - return err - } - var bOpeningPosition big.Int - bOpeningPosition.SetBytes(frOpeningPosition.Marshal()).Mod(&bOpeningPosition, &bFriSize) - openingPosition := bOpeningPosition.Uint64() - - shiftedOpeningPosition := (openingPosition + uint64(2*rho)) % friSize - err = vk.Iopp.VerifyOpening(shiftedOpeningPosition, proof.OpeningsZmp[1], proof.Zpp) - if err != nil { - return err - } - - // 1 - verify that the commitments are low degree polynomials - - // ql, qr, qm, qo, qkIncomplete - err = vk.Iopp.VerifyProofOfProximity(vk.Qpp[0]) - if err != nil { - return err - } - err = vk.Iopp.VerifyProofOfProximity(vk.Qpp[1]) - if err != nil { - return err - } - err = vk.Iopp.VerifyProofOfProximity(vk.Qpp[2]) - if err != nil { - return err - } - err = vk.Iopp.VerifyProofOfProximity(vk.Qpp[3]) - if err != nil { - return err - } - err = vk.Iopp.VerifyProofOfProximity(vk.Qpp[4]) - if err != nil { - return err - } - - // l, r, o - err = vk.Iopp.VerifyProofOfProximity(proof.LROpp[0]) - if err != nil { - return err - } - err = vk.Iopp.VerifyProofOfProximity(proof.LROpp[1]) - if err != nil { - return err - } - err = vk.Iopp.VerifyProofOfProximity(proof.LROpp[2]) - if err != nil { - return err - } - err = vk.Iopp.VerifyProofOfProximity(proof.Zpp) - if err != nil { - return err - } - - // h0, h1, h2 - err = vk.Iopp.VerifyProofOfProximity(proof.Hpp[0]) - if err != nil { - return err - } - err = vk.Iopp.VerifyProofOfProximity(proof.Hpp[1]) - if err != nil { - return err - } - err = vk.Iopp.VerifyProofOfProximity(proof.Hpp[2]) - if err != nil { - return err - } - - // s1, s2, s3 - err = vk.Iopp.VerifyProofOfProximity(vk.Spp[0]) - if err != nil { - return err - } - err = vk.Iopp.VerifyProofOfProximity(vk.Spp[1]) - if err != nil { - return err - } - err = vk.Iopp.VerifyProofOfProximity(vk.Spp[2]) - if err != nil { - return err - } - - // id1, id2, id3 - err = vk.Iopp.VerifyProofOfProximity(vk.Idpp[0]) - if err != nil { - return err - } - err = vk.Iopp.VerifyProofOfProximity(vk.Idpp[1]) - if err != nil { - return err - } - err = vk.Iopp.VerifyProofOfProximity(vk.Idpp[2]) - if err != nil { - return err - } - - // Z - err = vk.Iopp.VerifyProofOfProximity(proof.Zpp) - if err != nil { - return err - } - - // 2 - verify the openings - - // ql, qr, qm, qo, qkIncomplete - // openingPosition := uint64(2) - err = vk.Iopp.VerifyOpening(openingPosition, proof.OpeningsQlQrQmQoQkincompletemp[0], vk.Qpp[0]) - if err != nil { - return err - } - err = vk.Iopp.VerifyOpening(openingPosition, proof.OpeningsQlQrQmQoQkincompletemp[1], vk.Qpp[1]) - if err != nil { - return err - } - err = vk.Iopp.VerifyOpening(openingPosition, proof.OpeningsQlQrQmQoQkincompletemp[2], vk.Qpp[2]) - if err != nil { - return err - } - err = vk.Iopp.VerifyOpening(openingPosition, proof.OpeningsQlQrQmQoQkincompletemp[3], vk.Qpp[3]) - if err != nil { - return err - } - err = vk.Iopp.VerifyOpening(openingPosition, proof.OpeningsQlQrQmQoQkincompletemp[4], vk.Qpp[4]) - if err != nil { - return err - } - - // l, r, o - err = vk.Iopp.VerifyOpening(openingPosition, proof.OpeningsLROmp[0], proof.LROpp[0]) - if err != nil { - return err - } - err = vk.Iopp.VerifyOpening(openingPosition, proof.OpeningsLROmp[1], proof.LROpp[1]) - if err != nil { - return err - } - err = vk.Iopp.VerifyOpening(openingPosition, proof.OpeningsLROmp[2], proof.LROpp[2]) - if err != nil { - return err - } - - // h0, h1, h2 - err = vk.Iopp.VerifyOpening(openingPosition, proof.OpeningsHmp[0], proof.Hpp[0]) - if err != nil { - return err - } - err = vk.Iopp.VerifyOpening(openingPosition, proof.OpeningsHmp[1], proof.Hpp[1]) - if err != nil { - return err - } - err = vk.Iopp.VerifyOpening(openingPosition, proof.OpeningsHmp[2], proof.Hpp[2]) - if err != nil { - return err - } - - // s0, s1, s2 - err = vk.Iopp.VerifyOpening(openingPosition, proof.OpeningsS1S2S3mp[0], vk.Spp[0]) - if err != nil { - return err - } - err = vk.Iopp.VerifyOpening(openingPosition, proof.OpeningsS1S2S3mp[1], vk.Spp[1]) - if err != nil { - return err - } - err = vk.Iopp.VerifyOpening(openingPosition, proof.OpeningsS1S2S3mp[2], vk.Spp[2]) - if err != nil { - return err - } - - // id0, id1, id2 - err = vk.Iopp.VerifyOpening(openingPosition, proof.OpeningsId1Id2Id3mp[0], vk.Idpp[0]) - if err != nil { - return err - } - err = vk.Iopp.VerifyOpening(openingPosition, proof.OpeningsId1Id2Id3mp[1], vk.Idpp[1]) - if err != nil { - return err - } - err = vk.Iopp.VerifyOpening(openingPosition, proof.OpeningsId1Id2Id3mp[2], vk.Idpp[2]) - if err != nil { - return err - } - - // Z, Zshift - err = vk.Iopp.VerifyOpening(openingPosition, proof.OpeningsZmp[0], proof.Zpp) - if err != nil { - return err - } - - // verification of the algebraic relation - var ql, qr, qm, qo, qk fr.Element - ql.Set(&proof.OpeningsQlQrQmQoQkincompletemp[0].ClaimedValue) - qr.Set(&proof.OpeningsQlQrQmQoQkincompletemp[1].ClaimedValue) - qm.Set(&proof.OpeningsQlQrQmQoQkincompletemp[2].ClaimedValue) - qo.Set(&proof.OpeningsQlQrQmQoQkincompletemp[3].ClaimedValue) - qk.Set(&proof.OpeningsQlQrQmQoQkincompletemp[4].ClaimedValue) // -> to be completed - - var l, r, o fr.Element - l.Set(&proof.OpeningsLROmp[0].ClaimedValue) - r.Set(&proof.OpeningsLROmp[1].ClaimedValue) - o.Set(&proof.OpeningsLROmp[2].ClaimedValue) - - var h1, h2, h3 fr.Element - h1.Set(&proof.OpeningsHmp[0].ClaimedValue) - h2.Set(&proof.OpeningsHmp[1].ClaimedValue) - h3.Set(&proof.OpeningsHmp[2].ClaimedValue) - - var s1, s2, s3 fr.Element - s1.Set(&proof.OpeningsS1S2S3mp[0].ClaimedValue) - s2.Set(&proof.OpeningsS1S2S3mp[1].ClaimedValue) - s3.Set(&proof.OpeningsS1S2S3mp[2].ClaimedValue) - - var id1, id2, id3 fr.Element - id1.Set(&proof.OpeningsId1Id2Id3mp[0].ClaimedValue) - id2.Set(&proof.OpeningsId1Id2Id3mp[1].ClaimedValue) - id3.Set(&proof.OpeningsId1Id2Id3mp[2].ClaimedValue) - - var z, zshift fr.Element - z.Set(&proof.OpeningsZmp[0].ClaimedValue) - zshift.Set(&proof.OpeningsZmp[1].ClaimedValue) - - // 2 - compute the LHS: (ql*l+..+qk)+ α*(z(μx)*(l+β*s₁+γ)*..-z*(l+β*id1+γ))+α²*z*(l1-1) - var zeta fr.Element - zeta.Exp(vk.GenOpening, &bOpeningPosition) - - var lhs, t1, t2, t3, tmp, tmp2 fr.Element - // 2.1 (ql*l+..+qk) - t1.Mul(&l, &ql) - tmp.Mul(&r, &qr) - t1.Add(&t1, &tmp) - tmp.Mul(&qm, &l).Mul(&tmp, &r) - t1.Add(&t1, &tmp) - tmp.Mul(&o, &qo) - t1.Add(&tmp, &t1) - tmp = completeQk(publicWitness, vk, zeta) - tmp.Add(&qk, &tmp) - t1.Add(&tmp, &t1) - - // 2.2 (z(ux)*(l+β*s1+γ)*..-z*(l+β*id1+γ)) - t2.Mul(&beta, &s1).Add(&t2, &l).Add(&t2, &gamma) - tmp.Mul(&beta, &s2).Add(&tmp, &r).Add(&tmp, &gamma) - t2.Mul(&tmp, &t2) - tmp.Mul(&beta, &s3).Add(&tmp, &o).Add(&tmp, &gamma) - t2.Mul(&tmp, &t2).Mul(&t2, &zshift) - - tmp.Mul(&beta, &id1).Add(&tmp, &l).Add(&tmp, &gamma) - tmp2.Mul(&beta, &id2).Add(&tmp2, &r).Add(&tmp2, &gamma) - tmp.Mul(&tmp, &tmp2) - tmp2.Mul(&beta, &id3).Add(&tmp2, &o).Add(&tmp2, &gamma) - tmp.Mul(&tmp2, &tmp).Mul(&tmp, &z) - - t2.Sub(&t2, &tmp) - - // 2.3 (z-1)*l1 - var one fr.Element - one.SetOne() - t3.Exp(zeta, big.NewInt(int64(vk.Size))).Sub(&t3, &one) - tmp.Sub(&zeta, &one).Inverse(&tmp).Mul(&tmp, &vk.SizeInv) - t3.Mul(&tmp, &t3) - tmp.Sub(&z, &one) - t3.Mul(&tmp, &t3) - - // 2.4 (ql*l+s+qk) + α*(z(ux)*(l+β*s1+γ)*...-z*(l+β*id1+γ)..)+ α²*z*(l1-1) - lhs.Set(&t3).Mul(&lhs, &alpha).Add(&lhs, &t2).Mul(&lhs, &alpha).Add(&lhs, &t1) - - // 3 - compute the RHS - var rhs fr.Element - tmp.Exp(zeta, big.NewInt(int64(vk.Size+2))) - rhs.Mul(&h3, &tmp). - Add(&rhs, &h2). - Mul(&rhs, &tmp). - Add(&rhs, &h1) - - tmp.Exp(zeta, big.NewInt(int64(vk.Size))).Sub(&tmp, &one) - rhs.Mul(&rhs, &tmp) - - // 4 - verify the relation LHS==RHS - if !rhs.Equal(&lhs) { - return ErrInvalidAlgebraicRelation - } - - return nil - -} - -// completeQk returns ∑_{i> nn - _is := bits.Reverse64(uint64((i+toShift)%nbElmts)) >> nn - - // in what follows gⁱ is understood as the generator of the chosen coset of domainBig - f[0].Mul(&evaluationIDBigDomain, &beta).Add(&f[0], &l[_i]).Add(&f[0], &gamma) //l(gⁱ)+gⁱ*β+γ - f[1].Mul(&evaluationIDBigDomain, &cosetShift).Mul(&f[1], &beta).Add(&f[1], &r[_i]).Add(&f[1], &gamma) //r(gⁱ)+u*gⁱ*β+γ - f[2].Mul(&evaluationIDBigDomain, &cosetShiftSquare).Mul(&f[2], &beta).Add(&f[2], &o[_i]).Add(&f[2], &gamma) //o(gⁱ)+u²*gⁱ*β+γ - - g[0].Mul(&pk.EvaluationS1BigDomain[_i], &beta).Add(&g[0], &l[_i]).Add(&g[0], &gamma) //l(gⁱ))+s1(gⁱ)*β+γ - g[1].Mul(&pk.EvaluationS2BigDomain[_i], &beta).Add(&g[1], &r[_i]).Add(&g[1], &gamma) //r(gⁱ))+s2(gⁱ)*β+γ - g[2].Mul(&pk.EvaluationS3BigDomain[_i], &beta).Add(&g[2], &o[_i]).Add(&g[2], &gamma) //o(gⁱ))+s3(gⁱ)*β+γ - - f[0].Mul(&f[0], &f[1]).Mul(&f[0], &f[2]).Mul(&f[0], &z[_i]) // z(gⁱ)*(l(gⁱ)+g^i*β+γ)*(r(g^i)+u*g^i*β+γ)*(o(g^i)+u²*g^i*β+γ) - g[0].Mul(&g[0], &g[1]).Mul(&g[0], &g[2]).Mul(&g[0], &z[_is]) // z_(ugⁱ)*(l(gⁱ))+s₁(gⁱ)*β+γ)*(r(gⁱ))+s₂(gⁱ)*β+γ)*(o(gⁱ))+s₃(gⁱ)*β+γ) - - res[_i].Sub(&g[0], &f[0]) // z_(ugⁱ)*(l(gⁱ))+s₁(gⁱ)*β+γ)*(r(gⁱ))+s₂(gⁱ)*β+γ)*(o(gⁱ))+s₃(gⁱ)*β+γ) - z(gⁱ)*(l(gⁱ)+g^i*β+γ)*(r(g^i)+u*g^i*β+γ)*(o(g^i)+u²*g^i*β+γ) - - evaluationIDBigDomain.Mul(&evaluationIDBigDomain, &pk.Domain[1].Generator) // gⁱ*g - } - }) - - return res -} - -// evalConstraintsInd computes the evaluation of lL+qrR+qqmL.R+qoO+k on -// the odd coset of (Z/8mZ)/(Z/4mZ), where m=nbConstraints+nbAssertions. -// -// * lsL, lsR, lsO are the evaluation of the blinded solution vectors on odd cosets -// * lsQk is the completed version of qk, in canonical version -// -// lsL, lsR, lsO are in bit reversed order, lsQk is in the correct order. -func evalConstraintsInd(pk *ProvingKey, lsL, lsR, lsO, lsQk []fr.Element) []fr.Element { - - res := make([]fr.Element, pk.Domain[1].Cardinality) - // nn := uint64(64 - bits.TrailingZeros64(pk.Domain[1].Cardinality)) - - utils.Parallelize(len(res), func(start, end int) { - - var t0, t1 fr.Element - - for i := start; i < end; i++ { - - // irev := bits.Reverse64(uint64(i)) >> nn - - t1.Mul(&pk.EvaluationQmDomainBigBitReversed[i], &lsR[i]) // qm.r - t1.Add(&t1, &pk.EvaluationQlDomainBigBitReversed[i]) // qm.r + ql - t1.Mul(&t1, &lsL[i]) // qm.l.r + ql.l - - t0.Mul(&pk.EvaluationQrDomainBigBitReversed[i], &lsR[i]) - t0.Add(&t0, &t1) // qm.l.r + ql.l + qr.r - - t1.Mul(&pk.EvaluationQoDomainBigBitReversed[i], &lsO[i]) - t0.Add(&t0, &t1) // ql.l + qr.r + qm.l.r + qo.o - res[i].Add(&t0, &lsQk[i]) // ql.l + qr.r + qm.l.r + qo.o + k - - } - }) - - return res -} - -// fftBigCosetWOBitReverse evaluates poly (canonical form) of degree m> nn - - t.Sub(&evaluationBlindedZDomainBigBitReversed[_i], &one) // evaluates L₁(X)*(Z(X)-1) on a coset of the big domain - h[_i].Mul(&startsAtOne[_i], &t).Mul(&h[_i], &alpha). - Add(&h[_i], &evaluationConstraintOrderingBitReversed[_i]). - Mul(&h[_i], &alpha). - Add(&h[_i], &evaluationConstraintsIndBitReversed[_i]). - Mul(&h[_i], &evaluationXnMinusOneInverse[i%ratio]) - } - }) - - // put h in canonical form. h is of degree 3*(n+1)+2. - // using fft.DIT put h revert bit reverse - pk.Domain[1].FFTInverse(h, fft.DIT, fft.OnCoset()) - - // degree of hi is n+2 because of the blinding - h1 := h[:pk.Domain[0].Cardinality+2] - h2 := h[pk.Domain[0].Cardinality+2 : 2*(pk.Domain[0].Cardinality+2)] - h3 := h[2*(pk.Domain[0].Cardinality+2) : 3*(pk.Domain[0].Cardinality+2)] - - return h1, h2, h3 - -} - -// computeZ computes Z, in canonical basis, where: -// -// - Z of degree n (domainNum.Cardinality) -// -// - Z(1)=1 -// (l_i+z**i+gamma)*(r_i+u*z**i+gamma)*(o_i+u**2z**i+gamma) -// -// - for i>0: Z(u**i) = Pi_{k "small" domain, used for individual polynomials - // 1 -> "big" domain, used for the computation of the quotient - Domain [2]fft.Domain - - // s1, s2, s3 (L=Lagrange basis small domain, C=canonical basis, Ls=Lagrange Shifted big domain) - LId []fr.Element - EvaluationId1BigDomain, EvaluationId2BigDomain, EvaluationId3BigDomain []fr.Element - EvaluationS1BigDomain, EvaluationS2BigDomain, EvaluationS3BigDomain []fr.Element - - // position -> permuted position (position in [0,3*sizeSystem-1]) - Permutation []int64 -} - -// VerifyingKey stores the data needed to verify a proof: -// * The commitment scheme -// * Commitments of ql prepended with as many ones as there are public inputs -// * Commitments of qr, qm, qo, qk prepended with as many zeroes as there are public inputs -// * Commitments to S1, S2, S3 -type VerifyingKey struct { - - // Size circuit, that is the closest power of 2 bounding above - // number of constraints+number of public inputs - Size uint64 - SizeInv fr.Element - Generator fr.Element - NbPublicVariables uint64 - - // cosetShift generator of the coset on the small domain - CosetShift fr.Element - - // S commitments to S1, S2, S3 - SCanonical [3][]fr.Element - Spp [3]fri.ProofOfProximity - - // Id commitments to Id1, Id2, Id3 - // Id [3]Commitment - IdCanonical [3][]fr.Element - Idpp [3]fri.ProofOfProximity - - // Commitments to ql, qr, qm, qo prepended with as many zeroes (ones for l) as there are public inputs. - // In particular Qk is not complete. - Qpp [5]fri.ProofOfProximity // Ql, Qr, Qm, Qo, Qk - - // Iopp scheme (currently one for each size of polynomial) - Iopp fri.Iopp - - // generator of the group on which the Iopp works. If i is the opening position, - // the polynomials will be opened at genOpening^{i}. - GenOpening fr.Element -} - -// Setup sets proving and verifying keys -func Setup(spr *cs.SparseR1CS) (*ProvingKey, *VerifyingKey, error) { - - var pk ProvingKey - var vk VerifyingKey - - // The verifying key shares data with the proving key - pk.Vk = &vk - - nbConstraints := spr.GetNbConstraints() - - // fft domains - sizeSystem := uint64(nbConstraints + len(spr.Public)) // len(spr.Public) is for the placeholder constraints - pk.Domain[0] = *fft.NewDomain(sizeSystem) - - // h, the quotient polynomial is of degree 3(n+1)+2, so it's in a 3(n+2) dim vector space, - // the domain is the next power of 2 superior to 3(n+2). 4*domainNum is enough in all cases - // except when n<6. - if sizeSystem < 6 { - pk.Domain[1] = *fft.NewDomain(8 * sizeSystem) - } else { - pk.Domain[1] = *fft.NewDomain(4 * sizeSystem) - } - pk.Vk.CosetShift.Set(&pk.Domain[0].FrMultiplicativeGen) - - vk.Size = pk.Domain[0].Cardinality - vk.SizeInv.SetUint64(vk.Size).Inverse(&vk.SizeInv) - vk.Generator.Set(&pk.Domain[0].Generator) - vk.NbPublicVariables = uint64(len(spr.Public)) - - // IOP schemess - // The +2 is to handle the blinding. - sizeIopp := pk.Domain[0].Cardinality + 2 - vk.Iopp = fri.RADIX_2_FRI.New(sizeIopp, sha256.New()) - // only there to access the group used in FRI... - rho := uint64(fri.GetRho()) - // we multiply by 2 because the IOP is created with size pk.Domain[0].Cardinality + 2 (because - // of the blinding), so the domain will be rho*size_domain where size_domain is the next power - // of 2 after pk.Domain[0].Cardinality + 2, which is 2*rho*pk.Domain[0].Cardinality - tmpDomain := fft.NewDomain(2 * rho * pk.Domain[0].Cardinality) - vk.GenOpening.Set(&tmpDomain.Generator) - - // public polynomials corresponding to constraints: [ placholders | constraints | assertions ] - pk.EvaluationQlDomainBigBitReversed = make([]fr.Element, pk.Domain[1].Cardinality) - pk.EvaluationQrDomainBigBitReversed = make([]fr.Element, pk.Domain[1].Cardinality) - pk.EvaluationQmDomainBigBitReversed = make([]fr.Element, pk.Domain[1].Cardinality) - pk.EvaluationQoDomainBigBitReversed = make([]fr.Element, pk.Domain[1].Cardinality) - pk.LQkIncompleteDomainSmall = make([]fr.Element, pk.Domain[0].Cardinality) - pk.CQkIncomplete = make([]fr.Element, pk.Domain[0].Cardinality) - - for i := 0; i < len(spr.Public); i++ { // placeholders (-PUB_INPUT_i + qk_i = 0) TODO should return error if size is inconsistent - pk.EvaluationQlDomainBigBitReversed[i].SetOne().Neg(&pk.EvaluationQlDomainBigBitReversed[i]) - pk.EvaluationQrDomainBigBitReversed[i].SetZero() - pk.EvaluationQmDomainBigBitReversed[i].SetZero() - pk.EvaluationQoDomainBigBitReversed[i].SetZero() - pk.LQkIncompleteDomainSmall[i].SetZero() // --> to be completed by the prover - pk.CQkIncomplete[i].Set(&pk.LQkIncompleteDomainSmall[i]) // --> to be completed by the prover - } - offset := len(spr.Public) - - j := 0 - it := spr.GetSparseR1CIterator() - for c := it.Next(); c != nil; c = it.Next() { - pk.EvaluationQlDomainBigBitReversed[offset+j].Set(&spr.Coefficients[c.QL]) - pk.EvaluationQrDomainBigBitReversed[offset+j].Set(&spr.Coefficients[c.QR]) - pk.EvaluationQmDomainBigBitReversed[offset+j].Set(&spr.Coefficients[c.QM]) - pk.EvaluationQoDomainBigBitReversed[offset+j].Set(&spr.Coefficients[c.QO]) - pk.LQkIncompleteDomainSmall[offset+j].Set(&spr.Coefficients[c.QC]) - pk.CQkIncomplete[offset+j].Set(&pk.LQkIncompleteDomainSmall[offset+j]) - - j++ - } - - pk.Domain[0].FFTInverse(pk.EvaluationQlDomainBigBitReversed[:pk.Domain[0].Cardinality], fft.DIF) - pk.Domain[0].FFTInverse(pk.EvaluationQrDomainBigBitReversed[:pk.Domain[0].Cardinality], fft.DIF) - pk.Domain[0].FFTInverse(pk.EvaluationQmDomainBigBitReversed[:pk.Domain[0].Cardinality], fft.DIF) - pk.Domain[0].FFTInverse(pk.EvaluationQoDomainBigBitReversed[:pk.Domain[0].Cardinality], fft.DIF) - pk.Domain[0].FFTInverse(pk.CQkIncomplete, fft.DIF) - fft.BitReverse(pk.EvaluationQlDomainBigBitReversed[:pk.Domain[0].Cardinality]) - fft.BitReverse(pk.EvaluationQrDomainBigBitReversed[:pk.Domain[0].Cardinality]) - fft.BitReverse(pk.EvaluationQmDomainBigBitReversed[:pk.Domain[0].Cardinality]) - fft.BitReverse(pk.EvaluationQoDomainBigBitReversed[:pk.Domain[0].Cardinality]) - fft.BitReverse(pk.CQkIncomplete) - - // Commit to the polynomials to set up the verifying key - pk.CQl = make([]fr.Element, pk.Domain[0].Cardinality) - pk.CQr = make([]fr.Element, pk.Domain[0].Cardinality) - pk.CQm = make([]fr.Element, pk.Domain[0].Cardinality) - pk.CQo = make([]fr.Element, pk.Domain[0].Cardinality) - copy(pk.CQl, pk.EvaluationQlDomainBigBitReversed) - copy(pk.CQr, pk.EvaluationQrDomainBigBitReversed) - copy(pk.CQm, pk.EvaluationQmDomainBigBitReversed) - copy(pk.CQo, pk.EvaluationQoDomainBigBitReversed) - var err error - vk.Qpp[0], err = vk.Iopp.BuildProofOfProximity(pk.CQl) - if err != nil { - return &pk, &vk, err - } - vk.Qpp[1], err = vk.Iopp.BuildProofOfProximity(pk.CQr) - if err != nil { - return &pk, &vk, err - } - vk.Qpp[2], err = vk.Iopp.BuildProofOfProximity(pk.CQm) - if err != nil { - return &pk, &vk, err - } - vk.Qpp[3], err = vk.Iopp.BuildProofOfProximity(pk.CQo) - if err != nil { - return &pk, &vk, err - } - vk.Qpp[4], err = vk.Iopp.BuildProofOfProximity(pk.CQkIncomplete) - if err != nil { - return &pk, &vk, err - } - - pk.Domain[1].FFT(pk.EvaluationQlDomainBigBitReversed, fft.DIF, fft.OnCoset()) - pk.Domain[1].FFT(pk.EvaluationQrDomainBigBitReversed, fft.DIF, fft.OnCoset()) - pk.Domain[1].FFT(pk.EvaluationQmDomainBigBitReversed, fft.DIF, fft.OnCoset()) - pk.Domain[1].FFT(pk.EvaluationQoDomainBigBitReversed, fft.DIF, fft.OnCoset()) - - // build permutation. Note: at this stage, the permutation takes in account the placeholders - buildPermutation(spr, &pk) - - // set s1, s2, s3 - err = computePermutationPolynomials(&pk, &vk) - if err != nil { - return &pk, &vk, err - } - - return &pk, &vk, nil - -} - -// buildPermutation builds the Permutation associated with a circuit. -// -// The permutation s is composed of cycles of maximum length such that -// -// s. (l||r||o) = (l||r||o) -// -// , where l||r||o is the concatenation of the indices of l, r, o in -// ql.l+qr.r+qm.l.r+qo.O+k = 0. -// -// The permutation is encoded as a slice s of size 3*size(l), where the -// i-th entry of l||r||o is sent to the s[i]-th entry, so it acts on a tab -// like this: for i in tab: tab[i] = tab[permutation[i]] -func buildPermutation(spr *cs.SparseR1CS, pk *ProvingKey) { - - nbVariables := spr.NbInternalVariables + len(spr.Public) + len(spr.Secret) - sizeSolution := int(pk.Domain[0].Cardinality) - - // init permutation - pk.Permutation = make([]int64, 3*sizeSolution) - for i := 0; i < len(pk.Permutation); i++ { - pk.Permutation[i] = -1 - } - - // init LRO position -> variable_ID - lro := make([]int, 3*sizeSolution) // position -> variable_ID - for i := 0; i < len(spr.Public); i++ { - lro[i] = i // IDs of LRO associated to placeholders (only L needs to be taken care of) - } - - offset := len(spr.Public) - - j := 0 - it := spr.GetSparseR1CIterator() - for c := it.Next(); c != nil; c = it.Next() { - lro[offset+j] = int(c.XA) - lro[sizeSolution+offset+j] = int(c.XB) - lro[2*sizeSolution+offset+j] = int(c.XC) - j++ - } - - // init cycle: - // map ID -> last position the ID was seen - cycle := make([]int64, nbVariables) - for i := 0; i < len(cycle); i++ { - cycle[i] = -1 - } - - for i := 0; i < len(lro); i++ { - if cycle[lro[i]] != -1 { - // if != -1, it means we already encountered this value - // so we need to set the corresponding permutation index. - pk.Permutation[i] = cycle[lro[i]] - } - cycle[lro[i]] = int64(i) - } - - // complete the Permutation by filling the first IDs encountered - for i := 0; i < len(pk.Permutation); i++ { - if pk.Permutation[i] == -1 { - pk.Permutation[i] = cycle[lro[i]] - } - } -} - -// computePermutationPolynomials computes the LDE (Lagrange basis) of the permutations -// s1, s2, s3. -// -// 0 1 .. n-1 | n n+1 .. 2*n-1 | 2n 2n+1 .. 3n-1 | -// -// | -// | Permutation -// -// s00 s01 .. s0n-1 s10 s11 .. s1n-1 s20 s21 .. s2n-1 v -// \---------------/ \--------------------/ \------------------------/ -// -// s1 (LDE) s2 (LDE) s3 (LDE) -func computePermutationPolynomials(pk *ProvingKey, vk *VerifyingKey) error { - - nbElmt := int(pk.Domain[0].Cardinality) - - // sID = [1,..,g^{n-1},s,..,s*g^{n-1},s^2,..,s^2*g^{n-1}] - pk.LId = getIDSmallDomain(&pk.Domain[0]) - - // canonical form of S1, S2, S3 - pk.EvaluationS1BigDomain = make([]fr.Element, pk.Domain[1].Cardinality) - pk.EvaluationS2BigDomain = make([]fr.Element, pk.Domain[1].Cardinality) - pk.EvaluationS3BigDomain = make([]fr.Element, pk.Domain[1].Cardinality) - for i := 0; i < nbElmt; i++ { - pk.EvaluationS1BigDomain[i].Set(&pk.LId[pk.Permutation[i]]) - pk.EvaluationS2BigDomain[i].Set(&pk.LId[pk.Permutation[nbElmt+i]]) - pk.EvaluationS3BigDomain[i].Set(&pk.LId[pk.Permutation[2*nbElmt+i]]) - } - - // Evaluations of Sid1, Sid2, Sid3 on cosets of Domain[1] - pk.EvaluationId1BigDomain = make([]fr.Element, pk.Domain[1].Cardinality) - pk.EvaluationId2BigDomain = make([]fr.Element, pk.Domain[1].Cardinality) - pk.EvaluationId3BigDomain = make([]fr.Element, pk.Domain[1].Cardinality) - copy(pk.EvaluationId1BigDomain, pk.LId[:nbElmt]) - copy(pk.EvaluationId2BigDomain, pk.LId[nbElmt:2*nbElmt]) - copy(pk.EvaluationId3BigDomain, pk.LId[2*nbElmt:]) - pk.Domain[0].FFTInverse(pk.EvaluationId1BigDomain[:pk.Domain[0].Cardinality], fft.DIF) - pk.Domain[0].FFTInverse(pk.EvaluationId2BigDomain[:pk.Domain[0].Cardinality], fft.DIF) - pk.Domain[0].FFTInverse(pk.EvaluationId3BigDomain[:pk.Domain[0].Cardinality], fft.DIF) - fft.BitReverse(pk.EvaluationId1BigDomain[:pk.Domain[0].Cardinality]) - fft.BitReverse(pk.EvaluationId2BigDomain[:pk.Domain[0].Cardinality]) - fft.BitReverse(pk.EvaluationId3BigDomain[:pk.Domain[0].Cardinality]) - vk.IdCanonical[0] = make([]fr.Element, pk.Domain[0].Cardinality) - vk.IdCanonical[1] = make([]fr.Element, pk.Domain[0].Cardinality) - vk.IdCanonical[2] = make([]fr.Element, pk.Domain[0].Cardinality) - copy(vk.IdCanonical[0], pk.EvaluationId1BigDomain) - copy(vk.IdCanonical[1], pk.EvaluationId2BigDomain) - copy(vk.IdCanonical[2], pk.EvaluationId3BigDomain) - - var err error - vk.Idpp[0], err = vk.Iopp.BuildProofOfProximity(pk.EvaluationId1BigDomain) - if err != nil { - return err - } - vk.Idpp[1], err = vk.Iopp.BuildProofOfProximity(pk.EvaluationId2BigDomain) - if err != nil { - return err - } - vk.Idpp[2], err = vk.Iopp.BuildProofOfProximity(pk.EvaluationId3BigDomain) - if err != nil { - return err - } - pk.Domain[1].FFT(pk.EvaluationId1BigDomain, fft.DIF, fft.OnCoset()) - pk.Domain[1].FFT(pk.EvaluationId2BigDomain, fft.DIF, fft.OnCoset()) - pk.Domain[1].FFT(pk.EvaluationId3BigDomain, fft.DIF, fft.OnCoset()) - - pk.Domain[0].FFTInverse(pk.EvaluationS1BigDomain[:pk.Domain[0].Cardinality], fft.DIF) - pk.Domain[0].FFTInverse(pk.EvaluationS2BigDomain[:pk.Domain[0].Cardinality], fft.DIF) - pk.Domain[0].FFTInverse(pk.EvaluationS3BigDomain[:pk.Domain[0].Cardinality], fft.DIF) - fft.BitReverse(pk.EvaluationS1BigDomain[:pk.Domain[0].Cardinality]) - fft.BitReverse(pk.EvaluationS2BigDomain[:pk.Domain[0].Cardinality]) - fft.BitReverse(pk.EvaluationS3BigDomain[:pk.Domain[0].Cardinality]) - - // commit S1, S2, S3 - vk.SCanonical[0] = make([]fr.Element, pk.Domain[0].Cardinality) - vk.SCanonical[1] = make([]fr.Element, pk.Domain[0].Cardinality) - vk.SCanonical[2] = make([]fr.Element, pk.Domain[0].Cardinality) - copy(vk.SCanonical[0], pk.EvaluationS1BigDomain[:pk.Domain[0].Cardinality]) - copy(vk.SCanonical[1], pk.EvaluationS2BigDomain[:pk.Domain[0].Cardinality]) - copy(vk.SCanonical[2], pk.EvaluationS3BigDomain[:pk.Domain[0].Cardinality]) - vk.Spp[0], err = vk.Iopp.BuildProofOfProximity(vk.SCanonical[0]) - if err != nil { - return err - } - vk.Spp[1], err = vk.Iopp.BuildProofOfProximity(vk.SCanonical[1]) - if err != nil { - return err - } - vk.Spp[2], err = vk.Iopp.BuildProofOfProximity(vk.SCanonical[2]) - if err != nil { - return err - } - pk.Domain[1].FFT(pk.EvaluationS1BigDomain, fft.DIF, fft.OnCoset()) - pk.Domain[1].FFT(pk.EvaluationS2BigDomain, fft.DIF, fft.OnCoset()) - pk.Domain[1].FFT(pk.EvaluationS3BigDomain, fft.DIF, fft.OnCoset()) - - return nil - -} - -// getIDSmallDomain returns the Lagrange form of ID on the small domain -func getIDSmallDomain(domain *fft.Domain) []fr.Element { - - res := make([]fr.Element, 3*domain.Cardinality) - - res[0].SetOne() - res[domain.Cardinality].Set(&domain.FrMultiplicativeGen) - res[2*domain.Cardinality].Square(&domain.FrMultiplicativeGen) - - for i := uint64(1); i < domain.Cardinality; i++ { - res[i].Mul(&res[i-1], &domain.Generator) - res[domain.Cardinality+i].Mul(&res[domain.Cardinality+i-1], &domain.Generator) - res[2*domain.Cardinality+i].Mul(&res[2*domain.Cardinality+i-1], &domain.Generator) - } - - return res -} - -// NbPublicWitness returns the expected public witness size (number of field elements) -func (vk *VerifyingKey) NbPublicWitness() int { - return int(vk.NbPublicVariables) -} - -// VerifyingKey returns pk.Vk -func (pk *ProvingKey) VerifyingKey() interface{} { - return pk.Vk -} diff --git a/backend/plonkfri/bls24-315/verify.go b/backend/plonkfri/bls24-315/verify.go deleted file mode 100644 index c5b58259cf..0000000000 --- a/backend/plonkfri/bls24-315/verify.go +++ /dev/null @@ -1,398 +0,0 @@ -// Copyright 2020 ConsenSys Software Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -// Code generated by gnark DO NOT EDIT - -package plonkfri - -import ( - "errors" - "fmt" - "github.com/consensys/gnark-crypto/ecc/bls24-315/fr" - "github.com/consensys/gnark-crypto/ecc/bls24-315/fr/fri" - fiatshamir "github.com/consensys/gnark-crypto/fiat-shamir" - "github.com/consensys/gnark/backend" - "math/big" -) - -var ErrInvalidAlgebraicRelation = errors.New("algebraic relation does not hold") - -func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector, opts ...backend.VerifierOption) error { - cfg, err := backend.NewVerifierConfig(opts...) - if err != nil { - return fmt.Errorf("create backend config: %w", err) - } - - // 0 - derive the challenges with Fiat Shamir - fs := fiatshamir.NewTranscript(cfg.ChallengeHash, "gamma", "beta", "alpha", "zeta") - - dataFiatShamir := make([][fr.Bytes]byte, len(publicWitness)+3) - for i := 0; i < len(publicWitness); i++ { - copy(dataFiatShamir[i][:], publicWitness[i].Marshal()) - } - copy(dataFiatShamir[len(publicWitness)][:], proof.LROpp[0].ID) - copy(dataFiatShamir[len(publicWitness)+1][:], proof.LROpp[1].ID) - copy(dataFiatShamir[len(publicWitness)+2][:], proof.LROpp[2].ID) - - beta, err := deriveRandomnessFixedSize(fs, "gamma", dataFiatShamir...) - if err != nil { - return err - } - - gamma, err := deriveRandomness(fs, "beta", nil) - if err != nil { - return err - } - - alpha, err := deriveRandomness(fs, "alpha", proof.Zpp.ID) - if err != nil { - return err - } - - // compute the size of the domain of evaluation of the committed polynomial, - // the opening position. The challenge zeta will be g^{i} where i is the opening - // position, and g is the generator of the fri domain. - rho := uint64(fri.GetRho()) - friSize := 2 * rho * vk.Size - var bFriSize big.Int - bFriSize.SetInt64(int64(friSize)) - frOpeningPosition, err := deriveRandomness(fs, "zeta", proof.Hpp[0].ID, proof.Hpp[1].ID, proof.Hpp[2].ID) - if err != nil { - return err - } - var bOpeningPosition big.Int - bOpeningPosition.SetBytes(frOpeningPosition.Marshal()).Mod(&bOpeningPosition, &bFriSize) - openingPosition := bOpeningPosition.Uint64() - - shiftedOpeningPosition := (openingPosition + uint64(2*rho)) % friSize - err = vk.Iopp.VerifyOpening(shiftedOpeningPosition, proof.OpeningsZmp[1], proof.Zpp) - if err != nil { - return err - } - - // 1 - verify that the commitments are low degree polynomials - - // ql, qr, qm, qo, qkIncomplete - err = vk.Iopp.VerifyProofOfProximity(vk.Qpp[0]) - if err != nil { - return err - } - err = vk.Iopp.VerifyProofOfProximity(vk.Qpp[1]) - if err != nil { - return err - } - err = vk.Iopp.VerifyProofOfProximity(vk.Qpp[2]) - if err != nil { - return err - } - err = vk.Iopp.VerifyProofOfProximity(vk.Qpp[3]) - if err != nil { - return err - } - err = vk.Iopp.VerifyProofOfProximity(vk.Qpp[4]) - if err != nil { - return err - } - - // l, r, o - err = vk.Iopp.VerifyProofOfProximity(proof.LROpp[0]) - if err != nil { - return err - } - err = vk.Iopp.VerifyProofOfProximity(proof.LROpp[1]) - if err != nil { - return err - } - err = vk.Iopp.VerifyProofOfProximity(proof.LROpp[2]) - if err != nil { - return err - } - err = vk.Iopp.VerifyProofOfProximity(proof.Zpp) - if err != nil { - return err - } - - // h0, h1, h2 - err = vk.Iopp.VerifyProofOfProximity(proof.Hpp[0]) - if err != nil { - return err - } - err = vk.Iopp.VerifyProofOfProximity(proof.Hpp[1]) - if err != nil { - return err - } - err = vk.Iopp.VerifyProofOfProximity(proof.Hpp[2]) - if err != nil { - return err - } - - // s1, s2, s3 - err = vk.Iopp.VerifyProofOfProximity(vk.Spp[0]) - if err != nil { - return err - } - err = vk.Iopp.VerifyProofOfProximity(vk.Spp[1]) - if err != nil { - return err - } - err = vk.Iopp.VerifyProofOfProximity(vk.Spp[2]) - if err != nil { - return err - } - - // id1, id2, id3 - err = vk.Iopp.VerifyProofOfProximity(vk.Idpp[0]) - if err != nil { - return err - } - err = vk.Iopp.VerifyProofOfProximity(vk.Idpp[1]) - if err != nil { - return err - } - err = vk.Iopp.VerifyProofOfProximity(vk.Idpp[2]) - if err != nil { - return err - } - - // Z - err = vk.Iopp.VerifyProofOfProximity(proof.Zpp) - if err != nil { - return err - } - - // 2 - verify the openings - - // ql, qr, qm, qo, qkIncomplete - // openingPosition := uint64(2) - err = vk.Iopp.VerifyOpening(openingPosition, proof.OpeningsQlQrQmQoQkincompletemp[0], vk.Qpp[0]) - if err != nil { - return err - } - err = vk.Iopp.VerifyOpening(openingPosition, proof.OpeningsQlQrQmQoQkincompletemp[1], vk.Qpp[1]) - if err != nil { - return err - } - err = vk.Iopp.VerifyOpening(openingPosition, proof.OpeningsQlQrQmQoQkincompletemp[2], vk.Qpp[2]) - if err != nil { - return err - } - err = vk.Iopp.VerifyOpening(openingPosition, proof.OpeningsQlQrQmQoQkincompletemp[3], vk.Qpp[3]) - if err != nil { - return err - } - err = vk.Iopp.VerifyOpening(openingPosition, proof.OpeningsQlQrQmQoQkincompletemp[4], vk.Qpp[4]) - if err != nil { - return err - } - - // l, r, o - err = vk.Iopp.VerifyOpening(openingPosition, proof.OpeningsLROmp[0], proof.LROpp[0]) - if err != nil { - return err - } - err = vk.Iopp.VerifyOpening(openingPosition, proof.OpeningsLROmp[1], proof.LROpp[1]) - if err != nil { - return err - } - err = vk.Iopp.VerifyOpening(openingPosition, proof.OpeningsLROmp[2], proof.LROpp[2]) - if err != nil { - return err - } - - // h0, h1, h2 - err = vk.Iopp.VerifyOpening(openingPosition, proof.OpeningsHmp[0], proof.Hpp[0]) - if err != nil { - return err - } - err = vk.Iopp.VerifyOpening(openingPosition, proof.OpeningsHmp[1], proof.Hpp[1]) - if err != nil { - return err - } - err = vk.Iopp.VerifyOpening(openingPosition, proof.OpeningsHmp[2], proof.Hpp[2]) - if err != nil { - return err - } - - // s0, s1, s2 - err = vk.Iopp.VerifyOpening(openingPosition, proof.OpeningsS1S2S3mp[0], vk.Spp[0]) - if err != nil { - return err - } - err = vk.Iopp.VerifyOpening(openingPosition, proof.OpeningsS1S2S3mp[1], vk.Spp[1]) - if err != nil { - return err - } - err = vk.Iopp.VerifyOpening(openingPosition, proof.OpeningsS1S2S3mp[2], vk.Spp[2]) - if err != nil { - return err - } - - // id0, id1, id2 - err = vk.Iopp.VerifyOpening(openingPosition, proof.OpeningsId1Id2Id3mp[0], vk.Idpp[0]) - if err != nil { - return err - } - err = vk.Iopp.VerifyOpening(openingPosition, proof.OpeningsId1Id2Id3mp[1], vk.Idpp[1]) - if err != nil { - return err - } - err = vk.Iopp.VerifyOpening(openingPosition, proof.OpeningsId1Id2Id3mp[2], vk.Idpp[2]) - if err != nil { - return err - } - - // Z, Zshift - err = vk.Iopp.VerifyOpening(openingPosition, proof.OpeningsZmp[0], proof.Zpp) - if err != nil { - return err - } - - // verification of the algebraic relation - var ql, qr, qm, qo, qk fr.Element - ql.Set(&proof.OpeningsQlQrQmQoQkincompletemp[0].ClaimedValue) - qr.Set(&proof.OpeningsQlQrQmQoQkincompletemp[1].ClaimedValue) - qm.Set(&proof.OpeningsQlQrQmQoQkincompletemp[2].ClaimedValue) - qo.Set(&proof.OpeningsQlQrQmQoQkincompletemp[3].ClaimedValue) - qk.Set(&proof.OpeningsQlQrQmQoQkincompletemp[4].ClaimedValue) // -> to be completed - - var l, r, o fr.Element - l.Set(&proof.OpeningsLROmp[0].ClaimedValue) - r.Set(&proof.OpeningsLROmp[1].ClaimedValue) - o.Set(&proof.OpeningsLROmp[2].ClaimedValue) - - var h1, h2, h3 fr.Element - h1.Set(&proof.OpeningsHmp[0].ClaimedValue) - h2.Set(&proof.OpeningsHmp[1].ClaimedValue) - h3.Set(&proof.OpeningsHmp[2].ClaimedValue) - - var s1, s2, s3 fr.Element - s1.Set(&proof.OpeningsS1S2S3mp[0].ClaimedValue) - s2.Set(&proof.OpeningsS1S2S3mp[1].ClaimedValue) - s3.Set(&proof.OpeningsS1S2S3mp[2].ClaimedValue) - - var id1, id2, id3 fr.Element - id1.Set(&proof.OpeningsId1Id2Id3mp[0].ClaimedValue) - id2.Set(&proof.OpeningsId1Id2Id3mp[1].ClaimedValue) - id3.Set(&proof.OpeningsId1Id2Id3mp[2].ClaimedValue) - - var z, zshift fr.Element - z.Set(&proof.OpeningsZmp[0].ClaimedValue) - zshift.Set(&proof.OpeningsZmp[1].ClaimedValue) - - // 2 - compute the LHS: (ql*l+..+qk)+ α*(z(μx)*(l+β*s₁+γ)*..-z*(l+β*id1+γ))+α²*z*(l1-1) - var zeta fr.Element - zeta.Exp(vk.GenOpening, &bOpeningPosition) - - var lhs, t1, t2, t3, tmp, tmp2 fr.Element - // 2.1 (ql*l+..+qk) - t1.Mul(&l, &ql) - tmp.Mul(&r, &qr) - t1.Add(&t1, &tmp) - tmp.Mul(&qm, &l).Mul(&tmp, &r) - t1.Add(&t1, &tmp) - tmp.Mul(&o, &qo) - t1.Add(&tmp, &t1) - tmp = completeQk(publicWitness, vk, zeta) - tmp.Add(&qk, &tmp) - t1.Add(&tmp, &t1) - - // 2.2 (z(ux)*(l+β*s1+γ)*..-z*(l+β*id1+γ)) - t2.Mul(&beta, &s1).Add(&t2, &l).Add(&t2, &gamma) - tmp.Mul(&beta, &s2).Add(&tmp, &r).Add(&tmp, &gamma) - t2.Mul(&tmp, &t2) - tmp.Mul(&beta, &s3).Add(&tmp, &o).Add(&tmp, &gamma) - t2.Mul(&tmp, &t2).Mul(&t2, &zshift) - - tmp.Mul(&beta, &id1).Add(&tmp, &l).Add(&tmp, &gamma) - tmp2.Mul(&beta, &id2).Add(&tmp2, &r).Add(&tmp2, &gamma) - tmp.Mul(&tmp, &tmp2) - tmp2.Mul(&beta, &id3).Add(&tmp2, &o).Add(&tmp2, &gamma) - tmp.Mul(&tmp2, &tmp).Mul(&tmp, &z) - - t2.Sub(&t2, &tmp) - - // 2.3 (z-1)*l1 - var one fr.Element - one.SetOne() - t3.Exp(zeta, big.NewInt(int64(vk.Size))).Sub(&t3, &one) - tmp.Sub(&zeta, &one).Inverse(&tmp).Mul(&tmp, &vk.SizeInv) - t3.Mul(&tmp, &t3) - tmp.Sub(&z, &one) - t3.Mul(&tmp, &t3) - - // 2.4 (ql*l+s+qk) + α*(z(ux)*(l+β*s1+γ)*...-z*(l+β*id1+γ)..)+ α²*z*(l1-1) - lhs.Set(&t3).Mul(&lhs, &alpha).Add(&lhs, &t2).Mul(&lhs, &alpha).Add(&lhs, &t1) - - // 3 - compute the RHS - var rhs fr.Element - tmp.Exp(zeta, big.NewInt(int64(vk.Size+2))) - rhs.Mul(&h3, &tmp). - Add(&rhs, &h2). - Mul(&rhs, &tmp). - Add(&rhs, &h1) - - tmp.Exp(zeta, big.NewInt(int64(vk.Size))).Sub(&tmp, &one) - rhs.Mul(&rhs, &tmp) - - // 4 - verify the relation LHS==RHS - if !rhs.Equal(&lhs) { - return ErrInvalidAlgebraicRelation - } - - return nil - -} - -// completeQk returns ∑_{i> nn - _is := bits.Reverse64(uint64((i+toShift)%nbElmts)) >> nn - - // in what follows gⁱ is understood as the generator of the chosen coset of domainBig - f[0].Mul(&evaluationIDBigDomain, &beta).Add(&f[0], &l[_i]).Add(&f[0], &gamma) //l(gⁱ)+gⁱ*β+γ - f[1].Mul(&evaluationIDBigDomain, &cosetShift).Mul(&f[1], &beta).Add(&f[1], &r[_i]).Add(&f[1], &gamma) //r(gⁱ)+u*gⁱ*β+γ - f[2].Mul(&evaluationIDBigDomain, &cosetShiftSquare).Mul(&f[2], &beta).Add(&f[2], &o[_i]).Add(&f[2], &gamma) //o(gⁱ)+u²*gⁱ*β+γ - - g[0].Mul(&pk.EvaluationS1BigDomain[_i], &beta).Add(&g[0], &l[_i]).Add(&g[0], &gamma) //l(gⁱ))+s1(gⁱ)*β+γ - g[1].Mul(&pk.EvaluationS2BigDomain[_i], &beta).Add(&g[1], &r[_i]).Add(&g[1], &gamma) //r(gⁱ))+s2(gⁱ)*β+γ - g[2].Mul(&pk.EvaluationS3BigDomain[_i], &beta).Add(&g[2], &o[_i]).Add(&g[2], &gamma) //o(gⁱ))+s3(gⁱ)*β+γ - - f[0].Mul(&f[0], &f[1]).Mul(&f[0], &f[2]).Mul(&f[0], &z[_i]) // z(gⁱ)*(l(gⁱ)+g^i*β+γ)*(r(g^i)+u*g^i*β+γ)*(o(g^i)+u²*g^i*β+γ) - g[0].Mul(&g[0], &g[1]).Mul(&g[0], &g[2]).Mul(&g[0], &z[_is]) // z_(ugⁱ)*(l(gⁱ))+s₁(gⁱ)*β+γ)*(r(gⁱ))+s₂(gⁱ)*β+γ)*(o(gⁱ))+s₃(gⁱ)*β+γ) - - res[_i].Sub(&g[0], &f[0]) // z_(ugⁱ)*(l(gⁱ))+s₁(gⁱ)*β+γ)*(r(gⁱ))+s₂(gⁱ)*β+γ)*(o(gⁱ))+s₃(gⁱ)*β+γ) - z(gⁱ)*(l(gⁱ)+g^i*β+γ)*(r(g^i)+u*g^i*β+γ)*(o(g^i)+u²*g^i*β+γ) - - evaluationIDBigDomain.Mul(&evaluationIDBigDomain, &pk.Domain[1].Generator) // gⁱ*g - } - }) - - return res -} - -// evalConstraintsInd computes the evaluation of lL+qrR+qqmL.R+qoO+k on -// the odd coset of (Z/8mZ)/(Z/4mZ), where m=nbConstraints+nbAssertions. -// -// * lsL, lsR, lsO are the evaluation of the blinded solution vectors on odd cosets -// * lsQk is the completed version of qk, in canonical version -// -// lsL, lsR, lsO are in bit reversed order, lsQk is in the correct order. -func evalConstraintsInd(pk *ProvingKey, lsL, lsR, lsO, lsQk []fr.Element) []fr.Element { - - res := make([]fr.Element, pk.Domain[1].Cardinality) - // nn := uint64(64 - bits.TrailingZeros64(pk.Domain[1].Cardinality)) - - utils.Parallelize(len(res), func(start, end int) { - - var t0, t1 fr.Element - - for i := start; i < end; i++ { - - // irev := bits.Reverse64(uint64(i)) >> nn - - t1.Mul(&pk.EvaluationQmDomainBigBitReversed[i], &lsR[i]) // qm.r - t1.Add(&t1, &pk.EvaluationQlDomainBigBitReversed[i]) // qm.r + ql - t1.Mul(&t1, &lsL[i]) // qm.l.r + ql.l - - t0.Mul(&pk.EvaluationQrDomainBigBitReversed[i], &lsR[i]) - t0.Add(&t0, &t1) // qm.l.r + ql.l + qr.r - - t1.Mul(&pk.EvaluationQoDomainBigBitReversed[i], &lsO[i]) - t0.Add(&t0, &t1) // ql.l + qr.r + qm.l.r + qo.o - res[i].Add(&t0, &lsQk[i]) // ql.l + qr.r + qm.l.r + qo.o + k - - } - }) - - return res -} - -// fftBigCosetWOBitReverse evaluates poly (canonical form) of degree m> nn - - t.Sub(&evaluationBlindedZDomainBigBitReversed[_i], &one) // evaluates L₁(X)*(Z(X)-1) on a coset of the big domain - h[_i].Mul(&startsAtOne[_i], &t).Mul(&h[_i], &alpha). - Add(&h[_i], &evaluationConstraintOrderingBitReversed[_i]). - Mul(&h[_i], &alpha). - Add(&h[_i], &evaluationConstraintsIndBitReversed[_i]). - Mul(&h[_i], &evaluationXnMinusOneInverse[i%ratio]) - } - }) - - // put h in canonical form. h is of degree 3*(n+1)+2. - // using fft.DIT put h revert bit reverse - pk.Domain[1].FFTInverse(h, fft.DIT, fft.OnCoset()) - - // degree of hi is n+2 because of the blinding - h1 := h[:pk.Domain[0].Cardinality+2] - h2 := h[pk.Domain[0].Cardinality+2 : 2*(pk.Domain[0].Cardinality+2)] - h3 := h[2*(pk.Domain[0].Cardinality+2) : 3*(pk.Domain[0].Cardinality+2)] - - return h1, h2, h3 - -} - -// computeZ computes Z, in canonical basis, where: -// -// - Z of degree n (domainNum.Cardinality) -// -// - Z(1)=1 -// (l_i+z**i+gamma)*(r_i+u*z**i+gamma)*(o_i+u**2z**i+gamma) -// -// - for i>0: Z(u**i) = Pi_{k "small" domain, used for individual polynomials - // 1 -> "big" domain, used for the computation of the quotient - Domain [2]fft.Domain - - // s1, s2, s3 (L=Lagrange basis small domain, C=canonical basis, Ls=Lagrange Shifted big domain) - LId []fr.Element - EvaluationId1BigDomain, EvaluationId2BigDomain, EvaluationId3BigDomain []fr.Element - EvaluationS1BigDomain, EvaluationS2BigDomain, EvaluationS3BigDomain []fr.Element - - // position -> permuted position (position in [0,3*sizeSystem-1]) - Permutation []int64 -} - -// VerifyingKey stores the data needed to verify a proof: -// * The commitment scheme -// * Commitments of ql prepended with as many ones as there are public inputs -// * Commitments of qr, qm, qo, qk prepended with as many zeroes as there are public inputs -// * Commitments to S1, S2, S3 -type VerifyingKey struct { - - // Size circuit, that is the closest power of 2 bounding above - // number of constraints+number of public inputs - Size uint64 - SizeInv fr.Element - Generator fr.Element - NbPublicVariables uint64 - - // cosetShift generator of the coset on the small domain - CosetShift fr.Element - - // S commitments to S1, S2, S3 - SCanonical [3][]fr.Element - Spp [3]fri.ProofOfProximity - - // Id commitments to Id1, Id2, Id3 - // Id [3]Commitment - IdCanonical [3][]fr.Element - Idpp [3]fri.ProofOfProximity - - // Commitments to ql, qr, qm, qo prepended with as many zeroes (ones for l) as there are public inputs. - // In particular Qk is not complete. - Qpp [5]fri.ProofOfProximity // Ql, Qr, Qm, Qo, Qk - - // Iopp scheme (currently one for each size of polynomial) - Iopp fri.Iopp - - // generator of the group on which the Iopp works. If i is the opening position, - // the polynomials will be opened at genOpening^{i}. - GenOpening fr.Element -} - -// Setup sets proving and verifying keys -func Setup(spr *cs.SparseR1CS) (*ProvingKey, *VerifyingKey, error) { - - var pk ProvingKey - var vk VerifyingKey - - // The verifying key shares data with the proving key - pk.Vk = &vk - - nbConstraints := spr.GetNbConstraints() - - // fft domains - sizeSystem := uint64(nbConstraints + len(spr.Public)) // len(spr.Public) is for the placeholder constraints - pk.Domain[0] = *fft.NewDomain(sizeSystem) - - // h, the quotient polynomial is of degree 3(n+1)+2, so it's in a 3(n+2) dim vector space, - // the domain is the next power of 2 superior to 3(n+2). 4*domainNum is enough in all cases - // except when n<6. - if sizeSystem < 6 { - pk.Domain[1] = *fft.NewDomain(8 * sizeSystem) - } else { - pk.Domain[1] = *fft.NewDomain(4 * sizeSystem) - } - pk.Vk.CosetShift.Set(&pk.Domain[0].FrMultiplicativeGen) - - vk.Size = pk.Domain[0].Cardinality - vk.SizeInv.SetUint64(vk.Size).Inverse(&vk.SizeInv) - vk.Generator.Set(&pk.Domain[0].Generator) - vk.NbPublicVariables = uint64(len(spr.Public)) - - // IOP schemess - // The +2 is to handle the blinding. - sizeIopp := pk.Domain[0].Cardinality + 2 - vk.Iopp = fri.RADIX_2_FRI.New(sizeIopp, sha256.New()) - // only there to access the group used in FRI... - rho := uint64(fri.GetRho()) - // we multiply by 2 because the IOP is created with size pk.Domain[0].Cardinality + 2 (because - // of the blinding), so the domain will be rho*size_domain where size_domain is the next power - // of 2 after pk.Domain[0].Cardinality + 2, which is 2*rho*pk.Domain[0].Cardinality - tmpDomain := fft.NewDomain(2 * rho * pk.Domain[0].Cardinality) - vk.GenOpening.Set(&tmpDomain.Generator) - - // public polynomials corresponding to constraints: [ placholders | constraints | assertions ] - pk.EvaluationQlDomainBigBitReversed = make([]fr.Element, pk.Domain[1].Cardinality) - pk.EvaluationQrDomainBigBitReversed = make([]fr.Element, pk.Domain[1].Cardinality) - pk.EvaluationQmDomainBigBitReversed = make([]fr.Element, pk.Domain[1].Cardinality) - pk.EvaluationQoDomainBigBitReversed = make([]fr.Element, pk.Domain[1].Cardinality) - pk.LQkIncompleteDomainSmall = make([]fr.Element, pk.Domain[0].Cardinality) - pk.CQkIncomplete = make([]fr.Element, pk.Domain[0].Cardinality) - - for i := 0; i < len(spr.Public); i++ { // placeholders (-PUB_INPUT_i + qk_i = 0) TODO should return error if size is inconsistent - pk.EvaluationQlDomainBigBitReversed[i].SetOne().Neg(&pk.EvaluationQlDomainBigBitReversed[i]) - pk.EvaluationQrDomainBigBitReversed[i].SetZero() - pk.EvaluationQmDomainBigBitReversed[i].SetZero() - pk.EvaluationQoDomainBigBitReversed[i].SetZero() - pk.LQkIncompleteDomainSmall[i].SetZero() // --> to be completed by the prover - pk.CQkIncomplete[i].Set(&pk.LQkIncompleteDomainSmall[i]) // --> to be completed by the prover - } - offset := len(spr.Public) - - j := 0 - it := spr.GetSparseR1CIterator() - for c := it.Next(); c != nil; c = it.Next() { - pk.EvaluationQlDomainBigBitReversed[offset+j].Set(&spr.Coefficients[c.QL]) - pk.EvaluationQrDomainBigBitReversed[offset+j].Set(&spr.Coefficients[c.QR]) - pk.EvaluationQmDomainBigBitReversed[offset+j].Set(&spr.Coefficients[c.QM]) - pk.EvaluationQoDomainBigBitReversed[offset+j].Set(&spr.Coefficients[c.QO]) - pk.LQkIncompleteDomainSmall[offset+j].Set(&spr.Coefficients[c.QC]) - pk.CQkIncomplete[offset+j].Set(&pk.LQkIncompleteDomainSmall[offset+j]) - - j++ - } - - pk.Domain[0].FFTInverse(pk.EvaluationQlDomainBigBitReversed[:pk.Domain[0].Cardinality], fft.DIF) - pk.Domain[0].FFTInverse(pk.EvaluationQrDomainBigBitReversed[:pk.Domain[0].Cardinality], fft.DIF) - pk.Domain[0].FFTInverse(pk.EvaluationQmDomainBigBitReversed[:pk.Domain[0].Cardinality], fft.DIF) - pk.Domain[0].FFTInverse(pk.EvaluationQoDomainBigBitReversed[:pk.Domain[0].Cardinality], fft.DIF) - pk.Domain[0].FFTInverse(pk.CQkIncomplete, fft.DIF) - fft.BitReverse(pk.EvaluationQlDomainBigBitReversed[:pk.Domain[0].Cardinality]) - fft.BitReverse(pk.EvaluationQrDomainBigBitReversed[:pk.Domain[0].Cardinality]) - fft.BitReverse(pk.EvaluationQmDomainBigBitReversed[:pk.Domain[0].Cardinality]) - fft.BitReverse(pk.EvaluationQoDomainBigBitReversed[:pk.Domain[0].Cardinality]) - fft.BitReverse(pk.CQkIncomplete) - - // Commit to the polynomials to set up the verifying key - pk.CQl = make([]fr.Element, pk.Domain[0].Cardinality) - pk.CQr = make([]fr.Element, pk.Domain[0].Cardinality) - pk.CQm = make([]fr.Element, pk.Domain[0].Cardinality) - pk.CQo = make([]fr.Element, pk.Domain[0].Cardinality) - copy(pk.CQl, pk.EvaluationQlDomainBigBitReversed) - copy(pk.CQr, pk.EvaluationQrDomainBigBitReversed) - copy(pk.CQm, pk.EvaluationQmDomainBigBitReversed) - copy(pk.CQo, pk.EvaluationQoDomainBigBitReversed) - var err error - vk.Qpp[0], err = vk.Iopp.BuildProofOfProximity(pk.CQl) - if err != nil { - return &pk, &vk, err - } - vk.Qpp[1], err = vk.Iopp.BuildProofOfProximity(pk.CQr) - if err != nil { - return &pk, &vk, err - } - vk.Qpp[2], err = vk.Iopp.BuildProofOfProximity(pk.CQm) - if err != nil { - return &pk, &vk, err - } - vk.Qpp[3], err = vk.Iopp.BuildProofOfProximity(pk.CQo) - if err != nil { - return &pk, &vk, err - } - vk.Qpp[4], err = vk.Iopp.BuildProofOfProximity(pk.CQkIncomplete) - if err != nil { - return &pk, &vk, err - } - - pk.Domain[1].FFT(pk.EvaluationQlDomainBigBitReversed, fft.DIF, fft.OnCoset()) - pk.Domain[1].FFT(pk.EvaluationQrDomainBigBitReversed, fft.DIF, fft.OnCoset()) - pk.Domain[1].FFT(pk.EvaluationQmDomainBigBitReversed, fft.DIF, fft.OnCoset()) - pk.Domain[1].FFT(pk.EvaluationQoDomainBigBitReversed, fft.DIF, fft.OnCoset()) - - // build permutation. Note: at this stage, the permutation takes in account the placeholders - buildPermutation(spr, &pk) - - // set s1, s2, s3 - err = computePermutationPolynomials(&pk, &vk) - if err != nil { - return &pk, &vk, err - } - - return &pk, &vk, nil - -} - -// buildPermutation builds the Permutation associated with a circuit. -// -// The permutation s is composed of cycles of maximum length such that -// -// s. (l||r||o) = (l||r||o) -// -// , where l||r||o is the concatenation of the indices of l, r, o in -// ql.l+qr.r+qm.l.r+qo.O+k = 0. -// -// The permutation is encoded as a slice s of size 3*size(l), where the -// i-th entry of l||r||o is sent to the s[i]-th entry, so it acts on a tab -// like this: for i in tab: tab[i] = tab[permutation[i]] -func buildPermutation(spr *cs.SparseR1CS, pk *ProvingKey) { - - nbVariables := spr.NbInternalVariables + len(spr.Public) + len(spr.Secret) - sizeSolution := int(pk.Domain[0].Cardinality) - - // init permutation - pk.Permutation = make([]int64, 3*sizeSolution) - for i := 0; i < len(pk.Permutation); i++ { - pk.Permutation[i] = -1 - } - - // init LRO position -> variable_ID - lro := make([]int, 3*sizeSolution) // position -> variable_ID - for i := 0; i < len(spr.Public); i++ { - lro[i] = i // IDs of LRO associated to placeholders (only L needs to be taken care of) - } - - offset := len(spr.Public) - - j := 0 - it := spr.GetSparseR1CIterator() - for c := it.Next(); c != nil; c = it.Next() { - lro[offset+j] = int(c.XA) - lro[sizeSolution+offset+j] = int(c.XB) - lro[2*sizeSolution+offset+j] = int(c.XC) - j++ - } - - // init cycle: - // map ID -> last position the ID was seen - cycle := make([]int64, nbVariables) - for i := 0; i < len(cycle); i++ { - cycle[i] = -1 - } - - for i := 0; i < len(lro); i++ { - if cycle[lro[i]] != -1 { - // if != -1, it means we already encountered this value - // so we need to set the corresponding permutation index. - pk.Permutation[i] = cycle[lro[i]] - } - cycle[lro[i]] = int64(i) - } - - // complete the Permutation by filling the first IDs encountered - for i := 0; i < len(pk.Permutation); i++ { - if pk.Permutation[i] == -1 { - pk.Permutation[i] = cycle[lro[i]] - } - } -} - -// computePermutationPolynomials computes the LDE (Lagrange basis) of the permutations -// s1, s2, s3. -// -// 0 1 .. n-1 | n n+1 .. 2*n-1 | 2n 2n+1 .. 3n-1 | -// -// | -// | Permutation -// -// s00 s01 .. s0n-1 s10 s11 .. s1n-1 s20 s21 .. s2n-1 v -// \---------------/ \--------------------/ \------------------------/ -// -// s1 (LDE) s2 (LDE) s3 (LDE) -func computePermutationPolynomials(pk *ProvingKey, vk *VerifyingKey) error { - - nbElmt := int(pk.Domain[0].Cardinality) - - // sID = [1,..,g^{n-1},s,..,s*g^{n-1},s^2,..,s^2*g^{n-1}] - pk.LId = getIDSmallDomain(&pk.Domain[0]) - - // canonical form of S1, S2, S3 - pk.EvaluationS1BigDomain = make([]fr.Element, pk.Domain[1].Cardinality) - pk.EvaluationS2BigDomain = make([]fr.Element, pk.Domain[1].Cardinality) - pk.EvaluationS3BigDomain = make([]fr.Element, pk.Domain[1].Cardinality) - for i := 0; i < nbElmt; i++ { - pk.EvaluationS1BigDomain[i].Set(&pk.LId[pk.Permutation[i]]) - pk.EvaluationS2BigDomain[i].Set(&pk.LId[pk.Permutation[nbElmt+i]]) - pk.EvaluationS3BigDomain[i].Set(&pk.LId[pk.Permutation[2*nbElmt+i]]) - } - - // Evaluations of Sid1, Sid2, Sid3 on cosets of Domain[1] - pk.EvaluationId1BigDomain = make([]fr.Element, pk.Domain[1].Cardinality) - pk.EvaluationId2BigDomain = make([]fr.Element, pk.Domain[1].Cardinality) - pk.EvaluationId3BigDomain = make([]fr.Element, pk.Domain[1].Cardinality) - copy(pk.EvaluationId1BigDomain, pk.LId[:nbElmt]) - copy(pk.EvaluationId2BigDomain, pk.LId[nbElmt:2*nbElmt]) - copy(pk.EvaluationId3BigDomain, pk.LId[2*nbElmt:]) - pk.Domain[0].FFTInverse(pk.EvaluationId1BigDomain[:pk.Domain[0].Cardinality], fft.DIF) - pk.Domain[0].FFTInverse(pk.EvaluationId2BigDomain[:pk.Domain[0].Cardinality], fft.DIF) - pk.Domain[0].FFTInverse(pk.EvaluationId3BigDomain[:pk.Domain[0].Cardinality], fft.DIF) - fft.BitReverse(pk.EvaluationId1BigDomain[:pk.Domain[0].Cardinality]) - fft.BitReverse(pk.EvaluationId2BigDomain[:pk.Domain[0].Cardinality]) - fft.BitReverse(pk.EvaluationId3BigDomain[:pk.Domain[0].Cardinality]) - vk.IdCanonical[0] = make([]fr.Element, pk.Domain[0].Cardinality) - vk.IdCanonical[1] = make([]fr.Element, pk.Domain[0].Cardinality) - vk.IdCanonical[2] = make([]fr.Element, pk.Domain[0].Cardinality) - copy(vk.IdCanonical[0], pk.EvaluationId1BigDomain) - copy(vk.IdCanonical[1], pk.EvaluationId2BigDomain) - copy(vk.IdCanonical[2], pk.EvaluationId3BigDomain) - - var err error - vk.Idpp[0], err = vk.Iopp.BuildProofOfProximity(pk.EvaluationId1BigDomain) - if err != nil { - return err - } - vk.Idpp[1], err = vk.Iopp.BuildProofOfProximity(pk.EvaluationId2BigDomain) - if err != nil { - return err - } - vk.Idpp[2], err = vk.Iopp.BuildProofOfProximity(pk.EvaluationId3BigDomain) - if err != nil { - return err - } - pk.Domain[1].FFT(pk.EvaluationId1BigDomain, fft.DIF, fft.OnCoset()) - pk.Domain[1].FFT(pk.EvaluationId2BigDomain, fft.DIF, fft.OnCoset()) - pk.Domain[1].FFT(pk.EvaluationId3BigDomain, fft.DIF, fft.OnCoset()) - - pk.Domain[0].FFTInverse(pk.EvaluationS1BigDomain[:pk.Domain[0].Cardinality], fft.DIF) - pk.Domain[0].FFTInverse(pk.EvaluationS2BigDomain[:pk.Domain[0].Cardinality], fft.DIF) - pk.Domain[0].FFTInverse(pk.EvaluationS3BigDomain[:pk.Domain[0].Cardinality], fft.DIF) - fft.BitReverse(pk.EvaluationS1BigDomain[:pk.Domain[0].Cardinality]) - fft.BitReverse(pk.EvaluationS2BigDomain[:pk.Domain[0].Cardinality]) - fft.BitReverse(pk.EvaluationS3BigDomain[:pk.Domain[0].Cardinality]) - - // commit S1, S2, S3 - vk.SCanonical[0] = make([]fr.Element, pk.Domain[0].Cardinality) - vk.SCanonical[1] = make([]fr.Element, pk.Domain[0].Cardinality) - vk.SCanonical[2] = make([]fr.Element, pk.Domain[0].Cardinality) - copy(vk.SCanonical[0], pk.EvaluationS1BigDomain[:pk.Domain[0].Cardinality]) - copy(vk.SCanonical[1], pk.EvaluationS2BigDomain[:pk.Domain[0].Cardinality]) - copy(vk.SCanonical[2], pk.EvaluationS3BigDomain[:pk.Domain[0].Cardinality]) - vk.Spp[0], err = vk.Iopp.BuildProofOfProximity(vk.SCanonical[0]) - if err != nil { - return err - } - vk.Spp[1], err = vk.Iopp.BuildProofOfProximity(vk.SCanonical[1]) - if err != nil { - return err - } - vk.Spp[2], err = vk.Iopp.BuildProofOfProximity(vk.SCanonical[2]) - if err != nil { - return err - } - pk.Domain[1].FFT(pk.EvaluationS1BigDomain, fft.DIF, fft.OnCoset()) - pk.Domain[1].FFT(pk.EvaluationS2BigDomain, fft.DIF, fft.OnCoset()) - pk.Domain[1].FFT(pk.EvaluationS3BigDomain, fft.DIF, fft.OnCoset()) - - return nil - -} - -// getIDSmallDomain returns the Lagrange form of ID on the small domain -func getIDSmallDomain(domain *fft.Domain) []fr.Element { - - res := make([]fr.Element, 3*domain.Cardinality) - - res[0].SetOne() - res[domain.Cardinality].Set(&domain.FrMultiplicativeGen) - res[2*domain.Cardinality].Square(&domain.FrMultiplicativeGen) - - for i := uint64(1); i < domain.Cardinality; i++ { - res[i].Mul(&res[i-1], &domain.Generator) - res[domain.Cardinality+i].Mul(&res[domain.Cardinality+i-1], &domain.Generator) - res[2*domain.Cardinality+i].Mul(&res[2*domain.Cardinality+i-1], &domain.Generator) - } - - return res -} - -// NbPublicWitness returns the expected public witness size (number of field elements) -func (vk *VerifyingKey) NbPublicWitness() int { - return int(vk.NbPublicVariables) -} - -// VerifyingKey returns pk.Vk -func (pk *ProvingKey) VerifyingKey() interface{} { - return pk.Vk -} diff --git a/backend/plonkfri/bls24-317/verify.go b/backend/plonkfri/bls24-317/verify.go deleted file mode 100644 index 758398865f..0000000000 --- a/backend/plonkfri/bls24-317/verify.go +++ /dev/null @@ -1,398 +0,0 @@ -// Copyright 2020 ConsenSys Software Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -// Code generated by gnark DO NOT EDIT - -package plonkfri - -import ( - "errors" - "fmt" - "github.com/consensys/gnark-crypto/ecc/bls24-317/fr" - "github.com/consensys/gnark-crypto/ecc/bls24-317/fr/fri" - fiatshamir "github.com/consensys/gnark-crypto/fiat-shamir" - "github.com/consensys/gnark/backend" - "math/big" -) - -var ErrInvalidAlgebraicRelation = errors.New("algebraic relation does not hold") - -func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector, opts ...backend.VerifierOption) error { - cfg, err := backend.NewVerifierConfig(opts...) - if err != nil { - return fmt.Errorf("create backend config: %w", err) - } - - // 0 - derive the challenges with Fiat Shamir - fs := fiatshamir.NewTranscript(cfg.ChallengeHash, "gamma", "beta", "alpha", "zeta") - - dataFiatShamir := make([][fr.Bytes]byte, len(publicWitness)+3) - for i := 0; i < len(publicWitness); i++ { - copy(dataFiatShamir[i][:], publicWitness[i].Marshal()) - } - copy(dataFiatShamir[len(publicWitness)][:], proof.LROpp[0].ID) - copy(dataFiatShamir[len(publicWitness)+1][:], proof.LROpp[1].ID) - copy(dataFiatShamir[len(publicWitness)+2][:], proof.LROpp[2].ID) - - beta, err := deriveRandomnessFixedSize(fs, "gamma", dataFiatShamir...) - if err != nil { - return err - } - - gamma, err := deriveRandomness(fs, "beta", nil) - if err != nil { - return err - } - - alpha, err := deriveRandomness(fs, "alpha", proof.Zpp.ID) - if err != nil { - return err - } - - // compute the size of the domain of evaluation of the committed polynomial, - // the opening position. The challenge zeta will be g^{i} where i is the opening - // position, and g is the generator of the fri domain. - rho := uint64(fri.GetRho()) - friSize := 2 * rho * vk.Size - var bFriSize big.Int - bFriSize.SetInt64(int64(friSize)) - frOpeningPosition, err := deriveRandomness(fs, "zeta", proof.Hpp[0].ID, proof.Hpp[1].ID, proof.Hpp[2].ID) - if err != nil { - return err - } - var bOpeningPosition big.Int - bOpeningPosition.SetBytes(frOpeningPosition.Marshal()).Mod(&bOpeningPosition, &bFriSize) - openingPosition := bOpeningPosition.Uint64() - - shiftedOpeningPosition := (openingPosition + uint64(2*rho)) % friSize - err = vk.Iopp.VerifyOpening(shiftedOpeningPosition, proof.OpeningsZmp[1], proof.Zpp) - if err != nil { - return err - } - - // 1 - verify that the commitments are low degree polynomials - - // ql, qr, qm, qo, qkIncomplete - err = vk.Iopp.VerifyProofOfProximity(vk.Qpp[0]) - if err != nil { - return err - } - err = vk.Iopp.VerifyProofOfProximity(vk.Qpp[1]) - if err != nil { - return err - } - err = vk.Iopp.VerifyProofOfProximity(vk.Qpp[2]) - if err != nil { - return err - } - err = vk.Iopp.VerifyProofOfProximity(vk.Qpp[3]) - if err != nil { - return err - } - err = vk.Iopp.VerifyProofOfProximity(vk.Qpp[4]) - if err != nil { - return err - } - - // l, r, o - err = vk.Iopp.VerifyProofOfProximity(proof.LROpp[0]) - if err != nil { - return err - } - err = vk.Iopp.VerifyProofOfProximity(proof.LROpp[1]) - if err != nil { - return err - } - err = vk.Iopp.VerifyProofOfProximity(proof.LROpp[2]) - if err != nil { - return err - } - err = vk.Iopp.VerifyProofOfProximity(proof.Zpp) - if err != nil { - return err - } - - // h0, h1, h2 - err = vk.Iopp.VerifyProofOfProximity(proof.Hpp[0]) - if err != nil { - return err - } - err = vk.Iopp.VerifyProofOfProximity(proof.Hpp[1]) - if err != nil { - return err - } - err = vk.Iopp.VerifyProofOfProximity(proof.Hpp[2]) - if err != nil { - return err - } - - // s1, s2, s3 - err = vk.Iopp.VerifyProofOfProximity(vk.Spp[0]) - if err != nil { - return err - } - err = vk.Iopp.VerifyProofOfProximity(vk.Spp[1]) - if err != nil { - return err - } - err = vk.Iopp.VerifyProofOfProximity(vk.Spp[2]) - if err != nil { - return err - } - - // id1, id2, id3 - err = vk.Iopp.VerifyProofOfProximity(vk.Idpp[0]) - if err != nil { - return err - } - err = vk.Iopp.VerifyProofOfProximity(vk.Idpp[1]) - if err != nil { - return err - } - err = vk.Iopp.VerifyProofOfProximity(vk.Idpp[2]) - if err != nil { - return err - } - - // Z - err = vk.Iopp.VerifyProofOfProximity(proof.Zpp) - if err != nil { - return err - } - - // 2 - verify the openings - - // ql, qr, qm, qo, qkIncomplete - // openingPosition := uint64(2) - err = vk.Iopp.VerifyOpening(openingPosition, proof.OpeningsQlQrQmQoQkincompletemp[0], vk.Qpp[0]) - if err != nil { - return err - } - err = vk.Iopp.VerifyOpening(openingPosition, proof.OpeningsQlQrQmQoQkincompletemp[1], vk.Qpp[1]) - if err != nil { - return err - } - err = vk.Iopp.VerifyOpening(openingPosition, proof.OpeningsQlQrQmQoQkincompletemp[2], vk.Qpp[2]) - if err != nil { - return err - } - err = vk.Iopp.VerifyOpening(openingPosition, proof.OpeningsQlQrQmQoQkincompletemp[3], vk.Qpp[3]) - if err != nil { - return err - } - err = vk.Iopp.VerifyOpening(openingPosition, proof.OpeningsQlQrQmQoQkincompletemp[4], vk.Qpp[4]) - if err != nil { - return err - } - - // l, r, o - err = vk.Iopp.VerifyOpening(openingPosition, proof.OpeningsLROmp[0], proof.LROpp[0]) - if err != nil { - return err - } - err = vk.Iopp.VerifyOpening(openingPosition, proof.OpeningsLROmp[1], proof.LROpp[1]) - if err != nil { - return err - } - err = vk.Iopp.VerifyOpening(openingPosition, proof.OpeningsLROmp[2], proof.LROpp[2]) - if err != nil { - return err - } - - // h0, h1, h2 - err = vk.Iopp.VerifyOpening(openingPosition, proof.OpeningsHmp[0], proof.Hpp[0]) - if err != nil { - return err - } - err = vk.Iopp.VerifyOpening(openingPosition, proof.OpeningsHmp[1], proof.Hpp[1]) - if err != nil { - return err - } - err = vk.Iopp.VerifyOpening(openingPosition, proof.OpeningsHmp[2], proof.Hpp[2]) - if err != nil { - return err - } - - // s0, s1, s2 - err = vk.Iopp.VerifyOpening(openingPosition, proof.OpeningsS1S2S3mp[0], vk.Spp[0]) - if err != nil { - return err - } - err = vk.Iopp.VerifyOpening(openingPosition, proof.OpeningsS1S2S3mp[1], vk.Spp[1]) - if err != nil { - return err - } - err = vk.Iopp.VerifyOpening(openingPosition, proof.OpeningsS1S2S3mp[2], vk.Spp[2]) - if err != nil { - return err - } - - // id0, id1, id2 - err = vk.Iopp.VerifyOpening(openingPosition, proof.OpeningsId1Id2Id3mp[0], vk.Idpp[0]) - if err != nil { - return err - } - err = vk.Iopp.VerifyOpening(openingPosition, proof.OpeningsId1Id2Id3mp[1], vk.Idpp[1]) - if err != nil { - return err - } - err = vk.Iopp.VerifyOpening(openingPosition, proof.OpeningsId1Id2Id3mp[2], vk.Idpp[2]) - if err != nil { - return err - } - - // Z, Zshift - err = vk.Iopp.VerifyOpening(openingPosition, proof.OpeningsZmp[0], proof.Zpp) - if err != nil { - return err - } - - // verification of the algebraic relation - var ql, qr, qm, qo, qk fr.Element - ql.Set(&proof.OpeningsQlQrQmQoQkincompletemp[0].ClaimedValue) - qr.Set(&proof.OpeningsQlQrQmQoQkincompletemp[1].ClaimedValue) - qm.Set(&proof.OpeningsQlQrQmQoQkincompletemp[2].ClaimedValue) - qo.Set(&proof.OpeningsQlQrQmQoQkincompletemp[3].ClaimedValue) - qk.Set(&proof.OpeningsQlQrQmQoQkincompletemp[4].ClaimedValue) // -> to be completed - - var l, r, o fr.Element - l.Set(&proof.OpeningsLROmp[0].ClaimedValue) - r.Set(&proof.OpeningsLROmp[1].ClaimedValue) - o.Set(&proof.OpeningsLROmp[2].ClaimedValue) - - var h1, h2, h3 fr.Element - h1.Set(&proof.OpeningsHmp[0].ClaimedValue) - h2.Set(&proof.OpeningsHmp[1].ClaimedValue) - h3.Set(&proof.OpeningsHmp[2].ClaimedValue) - - var s1, s2, s3 fr.Element - s1.Set(&proof.OpeningsS1S2S3mp[0].ClaimedValue) - s2.Set(&proof.OpeningsS1S2S3mp[1].ClaimedValue) - s3.Set(&proof.OpeningsS1S2S3mp[2].ClaimedValue) - - var id1, id2, id3 fr.Element - id1.Set(&proof.OpeningsId1Id2Id3mp[0].ClaimedValue) - id2.Set(&proof.OpeningsId1Id2Id3mp[1].ClaimedValue) - id3.Set(&proof.OpeningsId1Id2Id3mp[2].ClaimedValue) - - var z, zshift fr.Element - z.Set(&proof.OpeningsZmp[0].ClaimedValue) - zshift.Set(&proof.OpeningsZmp[1].ClaimedValue) - - // 2 - compute the LHS: (ql*l+..+qk)+ α*(z(μx)*(l+β*s₁+γ)*..-z*(l+β*id1+γ))+α²*z*(l1-1) - var zeta fr.Element - zeta.Exp(vk.GenOpening, &bOpeningPosition) - - var lhs, t1, t2, t3, tmp, tmp2 fr.Element - // 2.1 (ql*l+..+qk) - t1.Mul(&l, &ql) - tmp.Mul(&r, &qr) - t1.Add(&t1, &tmp) - tmp.Mul(&qm, &l).Mul(&tmp, &r) - t1.Add(&t1, &tmp) - tmp.Mul(&o, &qo) - t1.Add(&tmp, &t1) - tmp = completeQk(publicWitness, vk, zeta) - tmp.Add(&qk, &tmp) - t1.Add(&tmp, &t1) - - // 2.2 (z(ux)*(l+β*s1+γ)*..-z*(l+β*id1+γ)) - t2.Mul(&beta, &s1).Add(&t2, &l).Add(&t2, &gamma) - tmp.Mul(&beta, &s2).Add(&tmp, &r).Add(&tmp, &gamma) - t2.Mul(&tmp, &t2) - tmp.Mul(&beta, &s3).Add(&tmp, &o).Add(&tmp, &gamma) - t2.Mul(&tmp, &t2).Mul(&t2, &zshift) - - tmp.Mul(&beta, &id1).Add(&tmp, &l).Add(&tmp, &gamma) - tmp2.Mul(&beta, &id2).Add(&tmp2, &r).Add(&tmp2, &gamma) - tmp.Mul(&tmp, &tmp2) - tmp2.Mul(&beta, &id3).Add(&tmp2, &o).Add(&tmp2, &gamma) - tmp.Mul(&tmp2, &tmp).Mul(&tmp, &z) - - t2.Sub(&t2, &tmp) - - // 2.3 (z-1)*l1 - var one fr.Element - one.SetOne() - t3.Exp(zeta, big.NewInt(int64(vk.Size))).Sub(&t3, &one) - tmp.Sub(&zeta, &one).Inverse(&tmp).Mul(&tmp, &vk.SizeInv) - t3.Mul(&tmp, &t3) - tmp.Sub(&z, &one) - t3.Mul(&tmp, &t3) - - // 2.4 (ql*l+s+qk) + α*(z(ux)*(l+β*s1+γ)*...-z*(l+β*id1+γ)..)+ α²*z*(l1-1) - lhs.Set(&t3).Mul(&lhs, &alpha).Add(&lhs, &t2).Mul(&lhs, &alpha).Add(&lhs, &t1) - - // 3 - compute the RHS - var rhs fr.Element - tmp.Exp(zeta, big.NewInt(int64(vk.Size+2))) - rhs.Mul(&h3, &tmp). - Add(&rhs, &h2). - Mul(&rhs, &tmp). - Add(&rhs, &h1) - - tmp.Exp(zeta, big.NewInt(int64(vk.Size))).Sub(&tmp, &one) - rhs.Mul(&rhs, &tmp) - - // 4 - verify the relation LHS==RHS - if !rhs.Equal(&lhs) { - return ErrInvalidAlgebraicRelation - } - - return nil - -} - -// completeQk returns ∑_{i> nn - _is := bits.Reverse64(uint64((i+toShift)%nbElmts)) >> nn - - // in what follows gⁱ is understood as the generator of the chosen coset of domainBig - f[0].Mul(&evaluationIDBigDomain, &beta).Add(&f[0], &l[_i]).Add(&f[0], &gamma) //l(gⁱ)+gⁱ*β+γ - f[1].Mul(&evaluationIDBigDomain, &cosetShift).Mul(&f[1], &beta).Add(&f[1], &r[_i]).Add(&f[1], &gamma) //r(gⁱ)+u*gⁱ*β+γ - f[2].Mul(&evaluationIDBigDomain, &cosetShiftSquare).Mul(&f[2], &beta).Add(&f[2], &o[_i]).Add(&f[2], &gamma) //o(gⁱ)+u²*gⁱ*β+γ - - g[0].Mul(&pk.EvaluationS1BigDomain[_i], &beta).Add(&g[0], &l[_i]).Add(&g[0], &gamma) //l(gⁱ))+s1(gⁱ)*β+γ - g[1].Mul(&pk.EvaluationS2BigDomain[_i], &beta).Add(&g[1], &r[_i]).Add(&g[1], &gamma) //r(gⁱ))+s2(gⁱ)*β+γ - g[2].Mul(&pk.EvaluationS3BigDomain[_i], &beta).Add(&g[2], &o[_i]).Add(&g[2], &gamma) //o(gⁱ))+s3(gⁱ)*β+γ - - f[0].Mul(&f[0], &f[1]).Mul(&f[0], &f[2]).Mul(&f[0], &z[_i]) // z(gⁱ)*(l(gⁱ)+g^i*β+γ)*(r(g^i)+u*g^i*β+γ)*(o(g^i)+u²*g^i*β+γ) - g[0].Mul(&g[0], &g[1]).Mul(&g[0], &g[2]).Mul(&g[0], &z[_is]) // z_(ugⁱ)*(l(gⁱ))+s₁(gⁱ)*β+γ)*(r(gⁱ))+s₂(gⁱ)*β+γ)*(o(gⁱ))+s₃(gⁱ)*β+γ) - - res[_i].Sub(&g[0], &f[0]) // z_(ugⁱ)*(l(gⁱ))+s₁(gⁱ)*β+γ)*(r(gⁱ))+s₂(gⁱ)*β+γ)*(o(gⁱ))+s₃(gⁱ)*β+γ) - z(gⁱ)*(l(gⁱ)+g^i*β+γ)*(r(g^i)+u*g^i*β+γ)*(o(g^i)+u²*g^i*β+γ) - - evaluationIDBigDomain.Mul(&evaluationIDBigDomain, &pk.Domain[1].Generator) // gⁱ*g - } - }) - - return res -} - -// evalConstraintsInd computes the evaluation of lL+qrR+qqmL.R+qoO+k on -// the odd coset of (Z/8mZ)/(Z/4mZ), where m=nbConstraints+nbAssertions. -// -// * lsL, lsR, lsO are the evaluation of the blinded solution vectors on odd cosets -// * lsQk is the completed version of qk, in canonical version -// -// lsL, lsR, lsO are in bit reversed order, lsQk is in the correct order. -func evalConstraintsInd(pk *ProvingKey, lsL, lsR, lsO, lsQk []fr.Element) []fr.Element { - - res := make([]fr.Element, pk.Domain[1].Cardinality) - // nn := uint64(64 - bits.TrailingZeros64(pk.Domain[1].Cardinality)) - - utils.Parallelize(len(res), func(start, end int) { - - var t0, t1 fr.Element - - for i := start; i < end; i++ { - - // irev := bits.Reverse64(uint64(i)) >> nn - - t1.Mul(&pk.EvaluationQmDomainBigBitReversed[i], &lsR[i]) // qm.r - t1.Add(&t1, &pk.EvaluationQlDomainBigBitReversed[i]) // qm.r + ql - t1.Mul(&t1, &lsL[i]) // qm.l.r + ql.l - - t0.Mul(&pk.EvaluationQrDomainBigBitReversed[i], &lsR[i]) - t0.Add(&t0, &t1) // qm.l.r + ql.l + qr.r - - t1.Mul(&pk.EvaluationQoDomainBigBitReversed[i], &lsO[i]) - t0.Add(&t0, &t1) // ql.l + qr.r + qm.l.r + qo.o - res[i].Add(&t0, &lsQk[i]) // ql.l + qr.r + qm.l.r + qo.o + k - - } - }) - - return res -} - -// fftBigCosetWOBitReverse evaluates poly (canonical form) of degree m> nn - - t.Sub(&evaluationBlindedZDomainBigBitReversed[_i], &one) // evaluates L₁(X)*(Z(X)-1) on a coset of the big domain - h[_i].Mul(&startsAtOne[_i], &t).Mul(&h[_i], &alpha). - Add(&h[_i], &evaluationConstraintOrderingBitReversed[_i]). - Mul(&h[_i], &alpha). - Add(&h[_i], &evaluationConstraintsIndBitReversed[_i]). - Mul(&h[_i], &evaluationXnMinusOneInverse[i%ratio]) - } - }) - - // put h in canonical form. h is of degree 3*(n+1)+2. - // using fft.DIT put h revert bit reverse - pk.Domain[1].FFTInverse(h, fft.DIT, fft.OnCoset()) - - // degree of hi is n+2 because of the blinding - h1 := h[:pk.Domain[0].Cardinality+2] - h2 := h[pk.Domain[0].Cardinality+2 : 2*(pk.Domain[0].Cardinality+2)] - h3 := h[2*(pk.Domain[0].Cardinality+2) : 3*(pk.Domain[0].Cardinality+2)] - - return h1, h2, h3 - -} - -// computeZ computes Z, in canonical basis, where: -// -// - Z of degree n (domainNum.Cardinality) -// -// - Z(1)=1 -// (l_i+z**i+gamma)*(r_i+u*z**i+gamma)*(o_i+u**2z**i+gamma) -// -// - for i>0: Z(u**i) = Pi_{k "small" domain, used for individual polynomials - // 1 -> "big" domain, used for the computation of the quotient - Domain [2]fft.Domain - - // s1, s2, s3 (L=Lagrange basis small domain, C=canonical basis, Ls=Lagrange Shifted big domain) - LId []fr.Element - EvaluationId1BigDomain, EvaluationId2BigDomain, EvaluationId3BigDomain []fr.Element - EvaluationS1BigDomain, EvaluationS2BigDomain, EvaluationS3BigDomain []fr.Element - - // position -> permuted position (position in [0,3*sizeSystem-1]) - Permutation []int64 -} - -// VerifyingKey stores the data needed to verify a proof: -// * The commitment scheme -// * Commitments of ql prepended with as many ones as there are public inputs -// * Commitments of qr, qm, qo, qk prepended with as many zeroes as there are public inputs -// * Commitments to S1, S2, S3 -type VerifyingKey struct { - - // Size circuit, that is the closest power of 2 bounding above - // number of constraints+number of public inputs - Size uint64 - SizeInv fr.Element - Generator fr.Element - NbPublicVariables uint64 - - // cosetShift generator of the coset on the small domain - CosetShift fr.Element - - // S commitments to S1, S2, S3 - SCanonical [3][]fr.Element - Spp [3]fri.ProofOfProximity - - // Id commitments to Id1, Id2, Id3 - // Id [3]Commitment - IdCanonical [3][]fr.Element - Idpp [3]fri.ProofOfProximity - - // Commitments to ql, qr, qm, qo prepended with as many zeroes (ones for l) as there are public inputs. - // In particular Qk is not complete. - Qpp [5]fri.ProofOfProximity // Ql, Qr, Qm, Qo, Qk - - // Iopp scheme (currently one for each size of polynomial) - Iopp fri.Iopp - - // generator of the group on which the Iopp works. If i is the opening position, - // the polynomials will be opened at genOpening^{i}. - GenOpening fr.Element -} - -// Setup sets proving and verifying keys -func Setup(spr *cs.SparseR1CS) (*ProvingKey, *VerifyingKey, error) { - - var pk ProvingKey - var vk VerifyingKey - - // The verifying key shares data with the proving key - pk.Vk = &vk - - nbConstraints := spr.GetNbConstraints() - - // fft domains - sizeSystem := uint64(nbConstraints + len(spr.Public)) // len(spr.Public) is for the placeholder constraints - pk.Domain[0] = *fft.NewDomain(sizeSystem) - - // h, the quotient polynomial is of degree 3(n+1)+2, so it's in a 3(n+2) dim vector space, - // the domain is the next power of 2 superior to 3(n+2). 4*domainNum is enough in all cases - // except when n<6. - if sizeSystem < 6 { - pk.Domain[1] = *fft.NewDomain(8 * sizeSystem) - } else { - pk.Domain[1] = *fft.NewDomain(4 * sizeSystem) - } - pk.Vk.CosetShift.Set(&pk.Domain[0].FrMultiplicativeGen) - - vk.Size = pk.Domain[0].Cardinality - vk.SizeInv.SetUint64(vk.Size).Inverse(&vk.SizeInv) - vk.Generator.Set(&pk.Domain[0].Generator) - vk.NbPublicVariables = uint64(len(spr.Public)) - - // IOP schemess - // The +2 is to handle the blinding. - sizeIopp := pk.Domain[0].Cardinality + 2 - vk.Iopp = fri.RADIX_2_FRI.New(sizeIopp, sha256.New()) - // only there to access the group used in FRI... - rho := uint64(fri.GetRho()) - // we multiply by 2 because the IOP is created with size pk.Domain[0].Cardinality + 2 (because - // of the blinding), so the domain will be rho*size_domain where size_domain is the next power - // of 2 after pk.Domain[0].Cardinality + 2, which is 2*rho*pk.Domain[0].Cardinality - tmpDomain := fft.NewDomain(2 * rho * pk.Domain[0].Cardinality) - vk.GenOpening.Set(&tmpDomain.Generator) - - // public polynomials corresponding to constraints: [ placholders | constraints | assertions ] - pk.EvaluationQlDomainBigBitReversed = make([]fr.Element, pk.Domain[1].Cardinality) - pk.EvaluationQrDomainBigBitReversed = make([]fr.Element, pk.Domain[1].Cardinality) - pk.EvaluationQmDomainBigBitReversed = make([]fr.Element, pk.Domain[1].Cardinality) - pk.EvaluationQoDomainBigBitReversed = make([]fr.Element, pk.Domain[1].Cardinality) - pk.LQkIncompleteDomainSmall = make([]fr.Element, pk.Domain[0].Cardinality) - pk.CQkIncomplete = make([]fr.Element, pk.Domain[0].Cardinality) - - for i := 0; i < len(spr.Public); i++ { // placeholders (-PUB_INPUT_i + qk_i = 0) TODO should return error if size is inconsistent - pk.EvaluationQlDomainBigBitReversed[i].SetOne().Neg(&pk.EvaluationQlDomainBigBitReversed[i]) - pk.EvaluationQrDomainBigBitReversed[i].SetZero() - pk.EvaluationQmDomainBigBitReversed[i].SetZero() - pk.EvaluationQoDomainBigBitReversed[i].SetZero() - pk.LQkIncompleteDomainSmall[i].SetZero() // --> to be completed by the prover - pk.CQkIncomplete[i].Set(&pk.LQkIncompleteDomainSmall[i]) // --> to be completed by the prover - } - offset := len(spr.Public) - - j := 0 - it := spr.GetSparseR1CIterator() - for c := it.Next(); c != nil; c = it.Next() { - pk.EvaluationQlDomainBigBitReversed[offset+j].Set(&spr.Coefficients[c.QL]) - pk.EvaluationQrDomainBigBitReversed[offset+j].Set(&spr.Coefficients[c.QR]) - pk.EvaluationQmDomainBigBitReversed[offset+j].Set(&spr.Coefficients[c.QM]) - pk.EvaluationQoDomainBigBitReversed[offset+j].Set(&spr.Coefficients[c.QO]) - pk.LQkIncompleteDomainSmall[offset+j].Set(&spr.Coefficients[c.QC]) - pk.CQkIncomplete[offset+j].Set(&pk.LQkIncompleteDomainSmall[offset+j]) - - j++ - } - - pk.Domain[0].FFTInverse(pk.EvaluationQlDomainBigBitReversed[:pk.Domain[0].Cardinality], fft.DIF) - pk.Domain[0].FFTInverse(pk.EvaluationQrDomainBigBitReversed[:pk.Domain[0].Cardinality], fft.DIF) - pk.Domain[0].FFTInverse(pk.EvaluationQmDomainBigBitReversed[:pk.Domain[0].Cardinality], fft.DIF) - pk.Domain[0].FFTInverse(pk.EvaluationQoDomainBigBitReversed[:pk.Domain[0].Cardinality], fft.DIF) - pk.Domain[0].FFTInverse(pk.CQkIncomplete, fft.DIF) - fft.BitReverse(pk.EvaluationQlDomainBigBitReversed[:pk.Domain[0].Cardinality]) - fft.BitReverse(pk.EvaluationQrDomainBigBitReversed[:pk.Domain[0].Cardinality]) - fft.BitReverse(pk.EvaluationQmDomainBigBitReversed[:pk.Domain[0].Cardinality]) - fft.BitReverse(pk.EvaluationQoDomainBigBitReversed[:pk.Domain[0].Cardinality]) - fft.BitReverse(pk.CQkIncomplete) - - // Commit to the polynomials to set up the verifying key - pk.CQl = make([]fr.Element, pk.Domain[0].Cardinality) - pk.CQr = make([]fr.Element, pk.Domain[0].Cardinality) - pk.CQm = make([]fr.Element, pk.Domain[0].Cardinality) - pk.CQo = make([]fr.Element, pk.Domain[0].Cardinality) - copy(pk.CQl, pk.EvaluationQlDomainBigBitReversed) - copy(pk.CQr, pk.EvaluationQrDomainBigBitReversed) - copy(pk.CQm, pk.EvaluationQmDomainBigBitReversed) - copy(pk.CQo, pk.EvaluationQoDomainBigBitReversed) - var err error - vk.Qpp[0], err = vk.Iopp.BuildProofOfProximity(pk.CQl) - if err != nil { - return &pk, &vk, err - } - vk.Qpp[1], err = vk.Iopp.BuildProofOfProximity(pk.CQr) - if err != nil { - return &pk, &vk, err - } - vk.Qpp[2], err = vk.Iopp.BuildProofOfProximity(pk.CQm) - if err != nil { - return &pk, &vk, err - } - vk.Qpp[3], err = vk.Iopp.BuildProofOfProximity(pk.CQo) - if err != nil { - return &pk, &vk, err - } - vk.Qpp[4], err = vk.Iopp.BuildProofOfProximity(pk.CQkIncomplete) - if err != nil { - return &pk, &vk, err - } - - pk.Domain[1].FFT(pk.EvaluationQlDomainBigBitReversed, fft.DIF, fft.OnCoset()) - pk.Domain[1].FFT(pk.EvaluationQrDomainBigBitReversed, fft.DIF, fft.OnCoset()) - pk.Domain[1].FFT(pk.EvaluationQmDomainBigBitReversed, fft.DIF, fft.OnCoset()) - pk.Domain[1].FFT(pk.EvaluationQoDomainBigBitReversed, fft.DIF, fft.OnCoset()) - - // build permutation. Note: at this stage, the permutation takes in account the placeholders - buildPermutation(spr, &pk) - - // set s1, s2, s3 - err = computePermutationPolynomials(&pk, &vk) - if err != nil { - return &pk, &vk, err - } - - return &pk, &vk, nil - -} - -// buildPermutation builds the Permutation associated with a circuit. -// -// The permutation s is composed of cycles of maximum length such that -// -// s. (l||r||o) = (l||r||o) -// -// , where l||r||o is the concatenation of the indices of l, r, o in -// ql.l+qr.r+qm.l.r+qo.O+k = 0. -// -// The permutation is encoded as a slice s of size 3*size(l), where the -// i-th entry of l||r||o is sent to the s[i]-th entry, so it acts on a tab -// like this: for i in tab: tab[i] = tab[permutation[i]] -func buildPermutation(spr *cs.SparseR1CS, pk *ProvingKey) { - - nbVariables := spr.NbInternalVariables + len(spr.Public) + len(spr.Secret) - sizeSolution := int(pk.Domain[0].Cardinality) - - // init permutation - pk.Permutation = make([]int64, 3*sizeSolution) - for i := 0; i < len(pk.Permutation); i++ { - pk.Permutation[i] = -1 - } - - // init LRO position -> variable_ID - lro := make([]int, 3*sizeSolution) // position -> variable_ID - for i := 0; i < len(spr.Public); i++ { - lro[i] = i // IDs of LRO associated to placeholders (only L needs to be taken care of) - } - - offset := len(spr.Public) - - j := 0 - it := spr.GetSparseR1CIterator() - for c := it.Next(); c != nil; c = it.Next() { - lro[offset+j] = int(c.XA) - lro[sizeSolution+offset+j] = int(c.XB) - lro[2*sizeSolution+offset+j] = int(c.XC) - j++ - } - - // init cycle: - // map ID -> last position the ID was seen - cycle := make([]int64, nbVariables) - for i := 0; i < len(cycle); i++ { - cycle[i] = -1 - } - - for i := 0; i < len(lro); i++ { - if cycle[lro[i]] != -1 { - // if != -1, it means we already encountered this value - // so we need to set the corresponding permutation index. - pk.Permutation[i] = cycle[lro[i]] - } - cycle[lro[i]] = int64(i) - } - - // complete the Permutation by filling the first IDs encountered - for i := 0; i < len(pk.Permutation); i++ { - if pk.Permutation[i] == -1 { - pk.Permutation[i] = cycle[lro[i]] - } - } -} - -// computePermutationPolynomials computes the LDE (Lagrange basis) of the permutations -// s1, s2, s3. -// -// 0 1 .. n-1 | n n+1 .. 2*n-1 | 2n 2n+1 .. 3n-1 | -// -// | -// | Permutation -// -// s00 s01 .. s0n-1 s10 s11 .. s1n-1 s20 s21 .. s2n-1 v -// \---------------/ \--------------------/ \------------------------/ -// -// s1 (LDE) s2 (LDE) s3 (LDE) -func computePermutationPolynomials(pk *ProvingKey, vk *VerifyingKey) error { - - nbElmt := int(pk.Domain[0].Cardinality) - - // sID = [1,..,g^{n-1},s,..,s*g^{n-1},s^2,..,s^2*g^{n-1}] - pk.LId = getIDSmallDomain(&pk.Domain[0]) - - // canonical form of S1, S2, S3 - pk.EvaluationS1BigDomain = make([]fr.Element, pk.Domain[1].Cardinality) - pk.EvaluationS2BigDomain = make([]fr.Element, pk.Domain[1].Cardinality) - pk.EvaluationS3BigDomain = make([]fr.Element, pk.Domain[1].Cardinality) - for i := 0; i < nbElmt; i++ { - pk.EvaluationS1BigDomain[i].Set(&pk.LId[pk.Permutation[i]]) - pk.EvaluationS2BigDomain[i].Set(&pk.LId[pk.Permutation[nbElmt+i]]) - pk.EvaluationS3BigDomain[i].Set(&pk.LId[pk.Permutation[2*nbElmt+i]]) - } - - // Evaluations of Sid1, Sid2, Sid3 on cosets of Domain[1] - pk.EvaluationId1BigDomain = make([]fr.Element, pk.Domain[1].Cardinality) - pk.EvaluationId2BigDomain = make([]fr.Element, pk.Domain[1].Cardinality) - pk.EvaluationId3BigDomain = make([]fr.Element, pk.Domain[1].Cardinality) - copy(pk.EvaluationId1BigDomain, pk.LId[:nbElmt]) - copy(pk.EvaluationId2BigDomain, pk.LId[nbElmt:2*nbElmt]) - copy(pk.EvaluationId3BigDomain, pk.LId[2*nbElmt:]) - pk.Domain[0].FFTInverse(pk.EvaluationId1BigDomain[:pk.Domain[0].Cardinality], fft.DIF) - pk.Domain[0].FFTInverse(pk.EvaluationId2BigDomain[:pk.Domain[0].Cardinality], fft.DIF) - pk.Domain[0].FFTInverse(pk.EvaluationId3BigDomain[:pk.Domain[0].Cardinality], fft.DIF) - fft.BitReverse(pk.EvaluationId1BigDomain[:pk.Domain[0].Cardinality]) - fft.BitReverse(pk.EvaluationId2BigDomain[:pk.Domain[0].Cardinality]) - fft.BitReverse(pk.EvaluationId3BigDomain[:pk.Domain[0].Cardinality]) - vk.IdCanonical[0] = make([]fr.Element, pk.Domain[0].Cardinality) - vk.IdCanonical[1] = make([]fr.Element, pk.Domain[0].Cardinality) - vk.IdCanonical[2] = make([]fr.Element, pk.Domain[0].Cardinality) - copy(vk.IdCanonical[0], pk.EvaluationId1BigDomain) - copy(vk.IdCanonical[1], pk.EvaluationId2BigDomain) - copy(vk.IdCanonical[2], pk.EvaluationId3BigDomain) - - var err error - vk.Idpp[0], err = vk.Iopp.BuildProofOfProximity(pk.EvaluationId1BigDomain) - if err != nil { - return err - } - vk.Idpp[1], err = vk.Iopp.BuildProofOfProximity(pk.EvaluationId2BigDomain) - if err != nil { - return err - } - vk.Idpp[2], err = vk.Iopp.BuildProofOfProximity(pk.EvaluationId3BigDomain) - if err != nil { - return err - } - pk.Domain[1].FFT(pk.EvaluationId1BigDomain, fft.DIF, fft.OnCoset()) - pk.Domain[1].FFT(pk.EvaluationId2BigDomain, fft.DIF, fft.OnCoset()) - pk.Domain[1].FFT(pk.EvaluationId3BigDomain, fft.DIF, fft.OnCoset()) - - pk.Domain[0].FFTInverse(pk.EvaluationS1BigDomain[:pk.Domain[0].Cardinality], fft.DIF) - pk.Domain[0].FFTInverse(pk.EvaluationS2BigDomain[:pk.Domain[0].Cardinality], fft.DIF) - pk.Domain[0].FFTInverse(pk.EvaluationS3BigDomain[:pk.Domain[0].Cardinality], fft.DIF) - fft.BitReverse(pk.EvaluationS1BigDomain[:pk.Domain[0].Cardinality]) - fft.BitReverse(pk.EvaluationS2BigDomain[:pk.Domain[0].Cardinality]) - fft.BitReverse(pk.EvaluationS3BigDomain[:pk.Domain[0].Cardinality]) - - // commit S1, S2, S3 - vk.SCanonical[0] = make([]fr.Element, pk.Domain[0].Cardinality) - vk.SCanonical[1] = make([]fr.Element, pk.Domain[0].Cardinality) - vk.SCanonical[2] = make([]fr.Element, pk.Domain[0].Cardinality) - copy(vk.SCanonical[0], pk.EvaluationS1BigDomain[:pk.Domain[0].Cardinality]) - copy(vk.SCanonical[1], pk.EvaluationS2BigDomain[:pk.Domain[0].Cardinality]) - copy(vk.SCanonical[2], pk.EvaluationS3BigDomain[:pk.Domain[0].Cardinality]) - vk.Spp[0], err = vk.Iopp.BuildProofOfProximity(vk.SCanonical[0]) - if err != nil { - return err - } - vk.Spp[1], err = vk.Iopp.BuildProofOfProximity(vk.SCanonical[1]) - if err != nil { - return err - } - vk.Spp[2], err = vk.Iopp.BuildProofOfProximity(vk.SCanonical[2]) - if err != nil { - return err - } - pk.Domain[1].FFT(pk.EvaluationS1BigDomain, fft.DIF, fft.OnCoset()) - pk.Domain[1].FFT(pk.EvaluationS2BigDomain, fft.DIF, fft.OnCoset()) - pk.Domain[1].FFT(pk.EvaluationS3BigDomain, fft.DIF, fft.OnCoset()) - - return nil - -} - -// getIDSmallDomain returns the Lagrange form of ID on the small domain -func getIDSmallDomain(domain *fft.Domain) []fr.Element { - - res := make([]fr.Element, 3*domain.Cardinality) - - res[0].SetOne() - res[domain.Cardinality].Set(&domain.FrMultiplicativeGen) - res[2*domain.Cardinality].Square(&domain.FrMultiplicativeGen) - - for i := uint64(1); i < domain.Cardinality; i++ { - res[i].Mul(&res[i-1], &domain.Generator) - res[domain.Cardinality+i].Mul(&res[domain.Cardinality+i-1], &domain.Generator) - res[2*domain.Cardinality+i].Mul(&res[2*domain.Cardinality+i-1], &domain.Generator) - } - - return res -} - -// NbPublicWitness returns the expected public witness size (number of field elements) -func (vk *VerifyingKey) NbPublicWitness() int { - return int(vk.NbPublicVariables) -} - -// VerifyingKey returns pk.Vk -func (pk *ProvingKey) VerifyingKey() interface{} { - return pk.Vk -} diff --git a/backend/plonkfri/bn254/verify.go b/backend/plonkfri/bn254/verify.go deleted file mode 100644 index 517d79b536..0000000000 --- a/backend/plonkfri/bn254/verify.go +++ /dev/null @@ -1,398 +0,0 @@ -// Copyright 2020 ConsenSys Software Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -// Code generated by gnark DO NOT EDIT - -package plonkfri - -import ( - "errors" - "fmt" - "github.com/consensys/gnark-crypto/ecc/bn254/fr" - "github.com/consensys/gnark-crypto/ecc/bn254/fr/fri" - fiatshamir "github.com/consensys/gnark-crypto/fiat-shamir" - "github.com/consensys/gnark/backend" - "math/big" -) - -var ErrInvalidAlgebraicRelation = errors.New("algebraic relation does not hold") - -func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector, opts ...backend.VerifierOption) error { - cfg, err := backend.NewVerifierConfig(opts...) - if err != nil { - return fmt.Errorf("create backend config: %w", err) - } - - // 0 - derive the challenges with Fiat Shamir - fs := fiatshamir.NewTranscript(cfg.ChallengeHash, "gamma", "beta", "alpha", "zeta") - - dataFiatShamir := make([][fr.Bytes]byte, len(publicWitness)+3) - for i := 0; i < len(publicWitness); i++ { - copy(dataFiatShamir[i][:], publicWitness[i].Marshal()) - } - copy(dataFiatShamir[len(publicWitness)][:], proof.LROpp[0].ID) - copy(dataFiatShamir[len(publicWitness)+1][:], proof.LROpp[1].ID) - copy(dataFiatShamir[len(publicWitness)+2][:], proof.LROpp[2].ID) - - beta, err := deriveRandomnessFixedSize(fs, "gamma", dataFiatShamir...) - if err != nil { - return err - } - - gamma, err := deriveRandomness(fs, "beta", nil) - if err != nil { - return err - } - - alpha, err := deriveRandomness(fs, "alpha", proof.Zpp.ID) - if err != nil { - return err - } - - // compute the size of the domain of evaluation of the committed polynomial, - // the opening position. The challenge zeta will be g^{i} where i is the opening - // position, and g is the generator of the fri domain. - rho := uint64(fri.GetRho()) - friSize := 2 * rho * vk.Size - var bFriSize big.Int - bFriSize.SetInt64(int64(friSize)) - frOpeningPosition, err := deriveRandomness(fs, "zeta", proof.Hpp[0].ID, proof.Hpp[1].ID, proof.Hpp[2].ID) - if err != nil { - return err - } - var bOpeningPosition big.Int - bOpeningPosition.SetBytes(frOpeningPosition.Marshal()).Mod(&bOpeningPosition, &bFriSize) - openingPosition := bOpeningPosition.Uint64() - - shiftedOpeningPosition := (openingPosition + uint64(2*rho)) % friSize - err = vk.Iopp.VerifyOpening(shiftedOpeningPosition, proof.OpeningsZmp[1], proof.Zpp) - if err != nil { - return err - } - - // 1 - verify that the commitments are low degree polynomials - - // ql, qr, qm, qo, qkIncomplete - err = vk.Iopp.VerifyProofOfProximity(vk.Qpp[0]) - if err != nil { - return err - } - err = vk.Iopp.VerifyProofOfProximity(vk.Qpp[1]) - if err != nil { - return err - } - err = vk.Iopp.VerifyProofOfProximity(vk.Qpp[2]) - if err != nil { - return err - } - err = vk.Iopp.VerifyProofOfProximity(vk.Qpp[3]) - if err != nil { - return err - } - err = vk.Iopp.VerifyProofOfProximity(vk.Qpp[4]) - if err != nil { - return err - } - - // l, r, o - err = vk.Iopp.VerifyProofOfProximity(proof.LROpp[0]) - if err != nil { - return err - } - err = vk.Iopp.VerifyProofOfProximity(proof.LROpp[1]) - if err != nil { - return err - } - err = vk.Iopp.VerifyProofOfProximity(proof.LROpp[2]) - if err != nil { - return err - } - err = vk.Iopp.VerifyProofOfProximity(proof.Zpp) - if err != nil { - return err - } - - // h0, h1, h2 - err = vk.Iopp.VerifyProofOfProximity(proof.Hpp[0]) - if err != nil { - return err - } - err = vk.Iopp.VerifyProofOfProximity(proof.Hpp[1]) - if err != nil { - return err - } - err = vk.Iopp.VerifyProofOfProximity(proof.Hpp[2]) - if err != nil { - return err - } - - // s1, s2, s3 - err = vk.Iopp.VerifyProofOfProximity(vk.Spp[0]) - if err != nil { - return err - } - err = vk.Iopp.VerifyProofOfProximity(vk.Spp[1]) - if err != nil { - return err - } - err = vk.Iopp.VerifyProofOfProximity(vk.Spp[2]) - if err != nil { - return err - } - - // id1, id2, id3 - err = vk.Iopp.VerifyProofOfProximity(vk.Idpp[0]) - if err != nil { - return err - } - err = vk.Iopp.VerifyProofOfProximity(vk.Idpp[1]) - if err != nil { - return err - } - err = vk.Iopp.VerifyProofOfProximity(vk.Idpp[2]) - if err != nil { - return err - } - - // Z - err = vk.Iopp.VerifyProofOfProximity(proof.Zpp) - if err != nil { - return err - } - - // 2 - verify the openings - - // ql, qr, qm, qo, qkIncomplete - // openingPosition := uint64(2) - err = vk.Iopp.VerifyOpening(openingPosition, proof.OpeningsQlQrQmQoQkincompletemp[0], vk.Qpp[0]) - if err != nil { - return err - } - err = vk.Iopp.VerifyOpening(openingPosition, proof.OpeningsQlQrQmQoQkincompletemp[1], vk.Qpp[1]) - if err != nil { - return err - } - err = vk.Iopp.VerifyOpening(openingPosition, proof.OpeningsQlQrQmQoQkincompletemp[2], vk.Qpp[2]) - if err != nil { - return err - } - err = vk.Iopp.VerifyOpening(openingPosition, proof.OpeningsQlQrQmQoQkincompletemp[3], vk.Qpp[3]) - if err != nil { - return err - } - err = vk.Iopp.VerifyOpening(openingPosition, proof.OpeningsQlQrQmQoQkincompletemp[4], vk.Qpp[4]) - if err != nil { - return err - } - - // l, r, o - err = vk.Iopp.VerifyOpening(openingPosition, proof.OpeningsLROmp[0], proof.LROpp[0]) - if err != nil { - return err - } - err = vk.Iopp.VerifyOpening(openingPosition, proof.OpeningsLROmp[1], proof.LROpp[1]) - if err != nil { - return err - } - err = vk.Iopp.VerifyOpening(openingPosition, proof.OpeningsLROmp[2], proof.LROpp[2]) - if err != nil { - return err - } - - // h0, h1, h2 - err = vk.Iopp.VerifyOpening(openingPosition, proof.OpeningsHmp[0], proof.Hpp[0]) - if err != nil { - return err - } - err = vk.Iopp.VerifyOpening(openingPosition, proof.OpeningsHmp[1], proof.Hpp[1]) - if err != nil { - return err - } - err = vk.Iopp.VerifyOpening(openingPosition, proof.OpeningsHmp[2], proof.Hpp[2]) - if err != nil { - return err - } - - // s0, s1, s2 - err = vk.Iopp.VerifyOpening(openingPosition, proof.OpeningsS1S2S3mp[0], vk.Spp[0]) - if err != nil { - return err - } - err = vk.Iopp.VerifyOpening(openingPosition, proof.OpeningsS1S2S3mp[1], vk.Spp[1]) - if err != nil { - return err - } - err = vk.Iopp.VerifyOpening(openingPosition, proof.OpeningsS1S2S3mp[2], vk.Spp[2]) - if err != nil { - return err - } - - // id0, id1, id2 - err = vk.Iopp.VerifyOpening(openingPosition, proof.OpeningsId1Id2Id3mp[0], vk.Idpp[0]) - if err != nil { - return err - } - err = vk.Iopp.VerifyOpening(openingPosition, proof.OpeningsId1Id2Id3mp[1], vk.Idpp[1]) - if err != nil { - return err - } - err = vk.Iopp.VerifyOpening(openingPosition, proof.OpeningsId1Id2Id3mp[2], vk.Idpp[2]) - if err != nil { - return err - } - - // Z, Zshift - err = vk.Iopp.VerifyOpening(openingPosition, proof.OpeningsZmp[0], proof.Zpp) - if err != nil { - return err - } - - // verification of the algebraic relation - var ql, qr, qm, qo, qk fr.Element - ql.Set(&proof.OpeningsQlQrQmQoQkincompletemp[0].ClaimedValue) - qr.Set(&proof.OpeningsQlQrQmQoQkincompletemp[1].ClaimedValue) - qm.Set(&proof.OpeningsQlQrQmQoQkincompletemp[2].ClaimedValue) - qo.Set(&proof.OpeningsQlQrQmQoQkincompletemp[3].ClaimedValue) - qk.Set(&proof.OpeningsQlQrQmQoQkincompletemp[4].ClaimedValue) // -> to be completed - - var l, r, o fr.Element - l.Set(&proof.OpeningsLROmp[0].ClaimedValue) - r.Set(&proof.OpeningsLROmp[1].ClaimedValue) - o.Set(&proof.OpeningsLROmp[2].ClaimedValue) - - var h1, h2, h3 fr.Element - h1.Set(&proof.OpeningsHmp[0].ClaimedValue) - h2.Set(&proof.OpeningsHmp[1].ClaimedValue) - h3.Set(&proof.OpeningsHmp[2].ClaimedValue) - - var s1, s2, s3 fr.Element - s1.Set(&proof.OpeningsS1S2S3mp[0].ClaimedValue) - s2.Set(&proof.OpeningsS1S2S3mp[1].ClaimedValue) - s3.Set(&proof.OpeningsS1S2S3mp[2].ClaimedValue) - - var id1, id2, id3 fr.Element - id1.Set(&proof.OpeningsId1Id2Id3mp[0].ClaimedValue) - id2.Set(&proof.OpeningsId1Id2Id3mp[1].ClaimedValue) - id3.Set(&proof.OpeningsId1Id2Id3mp[2].ClaimedValue) - - var z, zshift fr.Element - z.Set(&proof.OpeningsZmp[0].ClaimedValue) - zshift.Set(&proof.OpeningsZmp[1].ClaimedValue) - - // 2 - compute the LHS: (ql*l+..+qk)+ α*(z(μx)*(l+β*s₁+γ)*..-z*(l+β*id1+γ))+α²*z*(l1-1) - var zeta fr.Element - zeta.Exp(vk.GenOpening, &bOpeningPosition) - - var lhs, t1, t2, t3, tmp, tmp2 fr.Element - // 2.1 (ql*l+..+qk) - t1.Mul(&l, &ql) - tmp.Mul(&r, &qr) - t1.Add(&t1, &tmp) - tmp.Mul(&qm, &l).Mul(&tmp, &r) - t1.Add(&t1, &tmp) - tmp.Mul(&o, &qo) - t1.Add(&tmp, &t1) - tmp = completeQk(publicWitness, vk, zeta) - tmp.Add(&qk, &tmp) - t1.Add(&tmp, &t1) - - // 2.2 (z(ux)*(l+β*s1+γ)*..-z*(l+β*id1+γ)) - t2.Mul(&beta, &s1).Add(&t2, &l).Add(&t2, &gamma) - tmp.Mul(&beta, &s2).Add(&tmp, &r).Add(&tmp, &gamma) - t2.Mul(&tmp, &t2) - tmp.Mul(&beta, &s3).Add(&tmp, &o).Add(&tmp, &gamma) - t2.Mul(&tmp, &t2).Mul(&t2, &zshift) - - tmp.Mul(&beta, &id1).Add(&tmp, &l).Add(&tmp, &gamma) - tmp2.Mul(&beta, &id2).Add(&tmp2, &r).Add(&tmp2, &gamma) - tmp.Mul(&tmp, &tmp2) - tmp2.Mul(&beta, &id3).Add(&tmp2, &o).Add(&tmp2, &gamma) - tmp.Mul(&tmp2, &tmp).Mul(&tmp, &z) - - t2.Sub(&t2, &tmp) - - // 2.3 (z-1)*l1 - var one fr.Element - one.SetOne() - t3.Exp(zeta, big.NewInt(int64(vk.Size))).Sub(&t3, &one) - tmp.Sub(&zeta, &one).Inverse(&tmp).Mul(&tmp, &vk.SizeInv) - t3.Mul(&tmp, &t3) - tmp.Sub(&z, &one) - t3.Mul(&tmp, &t3) - - // 2.4 (ql*l+s+qk) + α*(z(ux)*(l+β*s1+γ)*...-z*(l+β*id1+γ)..)+ α²*z*(l1-1) - lhs.Set(&t3).Mul(&lhs, &alpha).Add(&lhs, &t2).Mul(&lhs, &alpha).Add(&lhs, &t1) - - // 3 - compute the RHS - var rhs fr.Element - tmp.Exp(zeta, big.NewInt(int64(vk.Size+2))) - rhs.Mul(&h3, &tmp). - Add(&rhs, &h2). - Mul(&rhs, &tmp). - Add(&rhs, &h1) - - tmp.Exp(zeta, big.NewInt(int64(vk.Size))).Sub(&tmp, &one) - rhs.Mul(&rhs, &tmp) - - // 4 - verify the relation LHS==RHS - if !rhs.Equal(&lhs) { - return ErrInvalidAlgebraicRelation - } - - return nil - -} - -// completeQk returns ∑_{i> nn - _is := bits.Reverse64(uint64((i+toShift)%nbElmts)) >> nn - - // in what follows gⁱ is understood as the generator of the chosen coset of domainBig - f[0].Mul(&evaluationIDBigDomain, &beta).Add(&f[0], &l[_i]).Add(&f[0], &gamma) //l(gⁱ)+gⁱ*β+γ - f[1].Mul(&evaluationIDBigDomain, &cosetShift).Mul(&f[1], &beta).Add(&f[1], &r[_i]).Add(&f[1], &gamma) //r(gⁱ)+u*gⁱ*β+γ - f[2].Mul(&evaluationIDBigDomain, &cosetShiftSquare).Mul(&f[2], &beta).Add(&f[2], &o[_i]).Add(&f[2], &gamma) //o(gⁱ)+u²*gⁱ*β+γ - - g[0].Mul(&pk.EvaluationS1BigDomain[_i], &beta).Add(&g[0], &l[_i]).Add(&g[0], &gamma) //l(gⁱ))+s1(gⁱ)*β+γ - g[1].Mul(&pk.EvaluationS2BigDomain[_i], &beta).Add(&g[1], &r[_i]).Add(&g[1], &gamma) //r(gⁱ))+s2(gⁱ)*β+γ - g[2].Mul(&pk.EvaluationS3BigDomain[_i], &beta).Add(&g[2], &o[_i]).Add(&g[2], &gamma) //o(gⁱ))+s3(gⁱ)*β+γ - - f[0].Mul(&f[0], &f[1]).Mul(&f[0], &f[2]).Mul(&f[0], &z[_i]) // z(gⁱ)*(l(gⁱ)+g^i*β+γ)*(r(g^i)+u*g^i*β+γ)*(o(g^i)+u²*g^i*β+γ) - g[0].Mul(&g[0], &g[1]).Mul(&g[0], &g[2]).Mul(&g[0], &z[_is]) // z_(ugⁱ)*(l(gⁱ))+s₁(gⁱ)*β+γ)*(r(gⁱ))+s₂(gⁱ)*β+γ)*(o(gⁱ))+s₃(gⁱ)*β+γ) - - res[_i].Sub(&g[0], &f[0]) // z_(ugⁱ)*(l(gⁱ))+s₁(gⁱ)*β+γ)*(r(gⁱ))+s₂(gⁱ)*β+γ)*(o(gⁱ))+s₃(gⁱ)*β+γ) - z(gⁱ)*(l(gⁱ)+g^i*β+γ)*(r(g^i)+u*g^i*β+γ)*(o(g^i)+u²*g^i*β+γ) - - evaluationIDBigDomain.Mul(&evaluationIDBigDomain, &pk.Domain[1].Generator) // gⁱ*g - } - }) - - return res -} - -// evalConstraintsInd computes the evaluation of lL+qrR+qqmL.R+qoO+k on -// the odd coset of (Z/8mZ)/(Z/4mZ), where m=nbConstraints+nbAssertions. -// -// * lsL, lsR, lsO are the evaluation of the blinded solution vectors on odd cosets -// * lsQk is the completed version of qk, in canonical version -// -// lsL, lsR, lsO are in bit reversed order, lsQk is in the correct order. -func evalConstraintsInd(pk *ProvingKey, lsL, lsR, lsO, lsQk []fr.Element) []fr.Element { - - res := make([]fr.Element, pk.Domain[1].Cardinality) - // nn := uint64(64 - bits.TrailingZeros64(pk.Domain[1].Cardinality)) - - utils.Parallelize(len(res), func(start, end int) { - - var t0, t1 fr.Element - - for i := start; i < end; i++ { - - // irev := bits.Reverse64(uint64(i)) >> nn - - t1.Mul(&pk.EvaluationQmDomainBigBitReversed[i], &lsR[i]) // qm.r - t1.Add(&t1, &pk.EvaluationQlDomainBigBitReversed[i]) // qm.r + ql - t1.Mul(&t1, &lsL[i]) // qm.l.r + ql.l - - t0.Mul(&pk.EvaluationQrDomainBigBitReversed[i], &lsR[i]) - t0.Add(&t0, &t1) // qm.l.r + ql.l + qr.r - - t1.Mul(&pk.EvaluationQoDomainBigBitReversed[i], &lsO[i]) - t0.Add(&t0, &t1) // ql.l + qr.r + qm.l.r + qo.o - res[i].Add(&t0, &lsQk[i]) // ql.l + qr.r + qm.l.r + qo.o + k - - } - }) - - return res -} - -// fftBigCosetWOBitReverse evaluates poly (canonical form) of degree m> nn - - t.Sub(&evaluationBlindedZDomainBigBitReversed[_i], &one) // evaluates L₁(X)*(Z(X)-1) on a coset of the big domain - h[_i].Mul(&startsAtOne[_i], &t).Mul(&h[_i], &alpha). - Add(&h[_i], &evaluationConstraintOrderingBitReversed[_i]). - Mul(&h[_i], &alpha). - Add(&h[_i], &evaluationConstraintsIndBitReversed[_i]). - Mul(&h[_i], &evaluationXnMinusOneInverse[i%ratio]) - } - }) - - // put h in canonical form. h is of degree 3*(n+1)+2. - // using fft.DIT put h revert bit reverse - pk.Domain[1].FFTInverse(h, fft.DIT, fft.OnCoset()) - - // degree of hi is n+2 because of the blinding - h1 := h[:pk.Domain[0].Cardinality+2] - h2 := h[pk.Domain[0].Cardinality+2 : 2*(pk.Domain[0].Cardinality+2)] - h3 := h[2*(pk.Domain[0].Cardinality+2) : 3*(pk.Domain[0].Cardinality+2)] - - return h1, h2, h3 - -} - -// computeZ computes Z, in canonical basis, where: -// -// - Z of degree n (domainNum.Cardinality) -// -// - Z(1)=1 -// (l_i+z**i+gamma)*(r_i+u*z**i+gamma)*(o_i+u**2z**i+gamma) -// -// - for i>0: Z(u**i) = Pi_{k "small" domain, used for individual polynomials - // 1 -> "big" domain, used for the computation of the quotient - Domain [2]fft.Domain - - // s1, s2, s3 (L=Lagrange basis small domain, C=canonical basis, Ls=Lagrange Shifted big domain) - LId []fr.Element - EvaluationId1BigDomain, EvaluationId2BigDomain, EvaluationId3BigDomain []fr.Element - EvaluationS1BigDomain, EvaluationS2BigDomain, EvaluationS3BigDomain []fr.Element - - // position -> permuted position (position in [0,3*sizeSystem-1]) - Permutation []int64 -} - -// VerifyingKey stores the data needed to verify a proof: -// * The commitment scheme -// * Commitments of ql prepended with as many ones as there are public inputs -// * Commitments of qr, qm, qo, qk prepended with as many zeroes as there are public inputs -// * Commitments to S1, S2, S3 -type VerifyingKey struct { - - // Size circuit, that is the closest power of 2 bounding above - // number of constraints+number of public inputs - Size uint64 - SizeInv fr.Element - Generator fr.Element - NbPublicVariables uint64 - - // cosetShift generator of the coset on the small domain - CosetShift fr.Element - - // S commitments to S1, S2, S3 - SCanonical [3][]fr.Element - Spp [3]fri.ProofOfProximity - - // Id commitments to Id1, Id2, Id3 - // Id [3]Commitment - IdCanonical [3][]fr.Element - Idpp [3]fri.ProofOfProximity - - // Commitments to ql, qr, qm, qo prepended with as many zeroes (ones for l) as there are public inputs. - // In particular Qk is not complete. - Qpp [5]fri.ProofOfProximity // Ql, Qr, Qm, Qo, Qk - - // Iopp scheme (currently one for each size of polynomial) - Iopp fri.Iopp - - // generator of the group on which the Iopp works. If i is the opening position, - // the polynomials will be opened at genOpening^{i}. - GenOpening fr.Element -} - -// Setup sets proving and verifying keys -func Setup(spr *cs.SparseR1CS) (*ProvingKey, *VerifyingKey, error) { - - var pk ProvingKey - var vk VerifyingKey - - // The verifying key shares data with the proving key - pk.Vk = &vk - - nbConstraints := spr.GetNbConstraints() - - // fft domains - sizeSystem := uint64(nbConstraints + len(spr.Public)) // len(spr.Public) is for the placeholder constraints - pk.Domain[0] = *fft.NewDomain(sizeSystem) - - // h, the quotient polynomial is of degree 3(n+1)+2, so it's in a 3(n+2) dim vector space, - // the domain is the next power of 2 superior to 3(n+2). 4*domainNum is enough in all cases - // except when n<6. - if sizeSystem < 6 { - pk.Domain[1] = *fft.NewDomain(8 * sizeSystem) - } else { - pk.Domain[1] = *fft.NewDomain(4 * sizeSystem) - } - pk.Vk.CosetShift.Set(&pk.Domain[0].FrMultiplicativeGen) - - vk.Size = pk.Domain[0].Cardinality - vk.SizeInv.SetUint64(vk.Size).Inverse(&vk.SizeInv) - vk.Generator.Set(&pk.Domain[0].Generator) - vk.NbPublicVariables = uint64(len(spr.Public)) - - // IOP schemess - // The +2 is to handle the blinding. - sizeIopp := pk.Domain[0].Cardinality + 2 - vk.Iopp = fri.RADIX_2_FRI.New(sizeIopp, sha256.New()) - // only there to access the group used in FRI... - rho := uint64(fri.GetRho()) - // we multiply by 2 because the IOP is created with size pk.Domain[0].Cardinality + 2 (because - // of the blinding), so the domain will be rho*size_domain where size_domain is the next power - // of 2 after pk.Domain[0].Cardinality + 2, which is 2*rho*pk.Domain[0].Cardinality - tmpDomain := fft.NewDomain(2 * rho * pk.Domain[0].Cardinality) - vk.GenOpening.Set(&tmpDomain.Generator) - - // public polynomials corresponding to constraints: [ placholders | constraints | assertions ] - pk.EvaluationQlDomainBigBitReversed = make([]fr.Element, pk.Domain[1].Cardinality) - pk.EvaluationQrDomainBigBitReversed = make([]fr.Element, pk.Domain[1].Cardinality) - pk.EvaluationQmDomainBigBitReversed = make([]fr.Element, pk.Domain[1].Cardinality) - pk.EvaluationQoDomainBigBitReversed = make([]fr.Element, pk.Domain[1].Cardinality) - pk.LQkIncompleteDomainSmall = make([]fr.Element, pk.Domain[0].Cardinality) - pk.CQkIncomplete = make([]fr.Element, pk.Domain[0].Cardinality) - - for i := 0; i < len(spr.Public); i++ { // placeholders (-PUB_INPUT_i + qk_i = 0) TODO should return error if size is inconsistent - pk.EvaluationQlDomainBigBitReversed[i].SetOne().Neg(&pk.EvaluationQlDomainBigBitReversed[i]) - pk.EvaluationQrDomainBigBitReversed[i].SetZero() - pk.EvaluationQmDomainBigBitReversed[i].SetZero() - pk.EvaluationQoDomainBigBitReversed[i].SetZero() - pk.LQkIncompleteDomainSmall[i].SetZero() // --> to be completed by the prover - pk.CQkIncomplete[i].Set(&pk.LQkIncompleteDomainSmall[i]) // --> to be completed by the prover - } - offset := len(spr.Public) - - j := 0 - it := spr.GetSparseR1CIterator() - for c := it.Next(); c != nil; c = it.Next() { - pk.EvaluationQlDomainBigBitReversed[offset+j].Set(&spr.Coefficients[c.QL]) - pk.EvaluationQrDomainBigBitReversed[offset+j].Set(&spr.Coefficients[c.QR]) - pk.EvaluationQmDomainBigBitReversed[offset+j].Set(&spr.Coefficients[c.QM]) - pk.EvaluationQoDomainBigBitReversed[offset+j].Set(&spr.Coefficients[c.QO]) - pk.LQkIncompleteDomainSmall[offset+j].Set(&spr.Coefficients[c.QC]) - pk.CQkIncomplete[offset+j].Set(&pk.LQkIncompleteDomainSmall[offset+j]) - - j++ - } - - pk.Domain[0].FFTInverse(pk.EvaluationQlDomainBigBitReversed[:pk.Domain[0].Cardinality], fft.DIF) - pk.Domain[0].FFTInverse(pk.EvaluationQrDomainBigBitReversed[:pk.Domain[0].Cardinality], fft.DIF) - pk.Domain[0].FFTInverse(pk.EvaluationQmDomainBigBitReversed[:pk.Domain[0].Cardinality], fft.DIF) - pk.Domain[0].FFTInverse(pk.EvaluationQoDomainBigBitReversed[:pk.Domain[0].Cardinality], fft.DIF) - pk.Domain[0].FFTInverse(pk.CQkIncomplete, fft.DIF) - fft.BitReverse(pk.EvaluationQlDomainBigBitReversed[:pk.Domain[0].Cardinality]) - fft.BitReverse(pk.EvaluationQrDomainBigBitReversed[:pk.Domain[0].Cardinality]) - fft.BitReverse(pk.EvaluationQmDomainBigBitReversed[:pk.Domain[0].Cardinality]) - fft.BitReverse(pk.EvaluationQoDomainBigBitReversed[:pk.Domain[0].Cardinality]) - fft.BitReverse(pk.CQkIncomplete) - - // Commit to the polynomials to set up the verifying key - pk.CQl = make([]fr.Element, pk.Domain[0].Cardinality) - pk.CQr = make([]fr.Element, pk.Domain[0].Cardinality) - pk.CQm = make([]fr.Element, pk.Domain[0].Cardinality) - pk.CQo = make([]fr.Element, pk.Domain[0].Cardinality) - copy(pk.CQl, pk.EvaluationQlDomainBigBitReversed) - copy(pk.CQr, pk.EvaluationQrDomainBigBitReversed) - copy(pk.CQm, pk.EvaluationQmDomainBigBitReversed) - copy(pk.CQo, pk.EvaluationQoDomainBigBitReversed) - var err error - vk.Qpp[0], err = vk.Iopp.BuildProofOfProximity(pk.CQl) - if err != nil { - return &pk, &vk, err - } - vk.Qpp[1], err = vk.Iopp.BuildProofOfProximity(pk.CQr) - if err != nil { - return &pk, &vk, err - } - vk.Qpp[2], err = vk.Iopp.BuildProofOfProximity(pk.CQm) - if err != nil { - return &pk, &vk, err - } - vk.Qpp[3], err = vk.Iopp.BuildProofOfProximity(pk.CQo) - if err != nil { - return &pk, &vk, err - } - vk.Qpp[4], err = vk.Iopp.BuildProofOfProximity(pk.CQkIncomplete) - if err != nil { - return &pk, &vk, err - } - - pk.Domain[1].FFT(pk.EvaluationQlDomainBigBitReversed, fft.DIF, fft.OnCoset()) - pk.Domain[1].FFT(pk.EvaluationQrDomainBigBitReversed, fft.DIF, fft.OnCoset()) - pk.Domain[1].FFT(pk.EvaluationQmDomainBigBitReversed, fft.DIF, fft.OnCoset()) - pk.Domain[1].FFT(pk.EvaluationQoDomainBigBitReversed, fft.DIF, fft.OnCoset()) - - // build permutation. Note: at this stage, the permutation takes in account the placeholders - buildPermutation(spr, &pk) - - // set s1, s2, s3 - err = computePermutationPolynomials(&pk, &vk) - if err != nil { - return &pk, &vk, err - } - - return &pk, &vk, nil - -} - -// buildPermutation builds the Permutation associated with a circuit. -// -// The permutation s is composed of cycles of maximum length such that -// -// s. (l||r||o) = (l||r||o) -// -// , where l||r||o is the concatenation of the indices of l, r, o in -// ql.l+qr.r+qm.l.r+qo.O+k = 0. -// -// The permutation is encoded as a slice s of size 3*size(l), where the -// i-th entry of l||r||o is sent to the s[i]-th entry, so it acts on a tab -// like this: for i in tab: tab[i] = tab[permutation[i]] -func buildPermutation(spr *cs.SparseR1CS, pk *ProvingKey) { - - nbVariables := spr.NbInternalVariables + len(spr.Public) + len(spr.Secret) - sizeSolution := int(pk.Domain[0].Cardinality) - - // init permutation - pk.Permutation = make([]int64, 3*sizeSolution) - for i := 0; i < len(pk.Permutation); i++ { - pk.Permutation[i] = -1 - } - - // init LRO position -> variable_ID - lro := make([]int, 3*sizeSolution) // position -> variable_ID - for i := 0; i < len(spr.Public); i++ { - lro[i] = i // IDs of LRO associated to placeholders (only L needs to be taken care of) - } - - offset := len(spr.Public) - - j := 0 - it := spr.GetSparseR1CIterator() - for c := it.Next(); c != nil; c = it.Next() { - lro[offset+j] = int(c.XA) - lro[sizeSolution+offset+j] = int(c.XB) - lro[2*sizeSolution+offset+j] = int(c.XC) - j++ - } - - // init cycle: - // map ID -> last position the ID was seen - cycle := make([]int64, nbVariables) - for i := 0; i < len(cycle); i++ { - cycle[i] = -1 - } - - for i := 0; i < len(lro); i++ { - if cycle[lro[i]] != -1 { - // if != -1, it means we already encountered this value - // so we need to set the corresponding permutation index. - pk.Permutation[i] = cycle[lro[i]] - } - cycle[lro[i]] = int64(i) - } - - // complete the Permutation by filling the first IDs encountered - for i := 0; i < len(pk.Permutation); i++ { - if pk.Permutation[i] == -1 { - pk.Permutation[i] = cycle[lro[i]] - } - } -} - -// computePermutationPolynomials computes the LDE (Lagrange basis) of the permutations -// s1, s2, s3. -// -// 0 1 .. n-1 | n n+1 .. 2*n-1 | 2n 2n+1 .. 3n-1 | -// -// | -// | Permutation -// -// s00 s01 .. s0n-1 s10 s11 .. s1n-1 s20 s21 .. s2n-1 v -// \---------------/ \--------------------/ \------------------------/ -// -// s1 (LDE) s2 (LDE) s3 (LDE) -func computePermutationPolynomials(pk *ProvingKey, vk *VerifyingKey) error { - - nbElmt := int(pk.Domain[0].Cardinality) - - // sID = [1,..,g^{n-1},s,..,s*g^{n-1},s^2,..,s^2*g^{n-1}] - pk.LId = getIDSmallDomain(&pk.Domain[0]) - - // canonical form of S1, S2, S3 - pk.EvaluationS1BigDomain = make([]fr.Element, pk.Domain[1].Cardinality) - pk.EvaluationS2BigDomain = make([]fr.Element, pk.Domain[1].Cardinality) - pk.EvaluationS3BigDomain = make([]fr.Element, pk.Domain[1].Cardinality) - for i := 0; i < nbElmt; i++ { - pk.EvaluationS1BigDomain[i].Set(&pk.LId[pk.Permutation[i]]) - pk.EvaluationS2BigDomain[i].Set(&pk.LId[pk.Permutation[nbElmt+i]]) - pk.EvaluationS3BigDomain[i].Set(&pk.LId[pk.Permutation[2*nbElmt+i]]) - } - - // Evaluations of Sid1, Sid2, Sid3 on cosets of Domain[1] - pk.EvaluationId1BigDomain = make([]fr.Element, pk.Domain[1].Cardinality) - pk.EvaluationId2BigDomain = make([]fr.Element, pk.Domain[1].Cardinality) - pk.EvaluationId3BigDomain = make([]fr.Element, pk.Domain[1].Cardinality) - copy(pk.EvaluationId1BigDomain, pk.LId[:nbElmt]) - copy(pk.EvaluationId2BigDomain, pk.LId[nbElmt:2*nbElmt]) - copy(pk.EvaluationId3BigDomain, pk.LId[2*nbElmt:]) - pk.Domain[0].FFTInverse(pk.EvaluationId1BigDomain[:pk.Domain[0].Cardinality], fft.DIF) - pk.Domain[0].FFTInverse(pk.EvaluationId2BigDomain[:pk.Domain[0].Cardinality], fft.DIF) - pk.Domain[0].FFTInverse(pk.EvaluationId3BigDomain[:pk.Domain[0].Cardinality], fft.DIF) - fft.BitReverse(pk.EvaluationId1BigDomain[:pk.Domain[0].Cardinality]) - fft.BitReverse(pk.EvaluationId2BigDomain[:pk.Domain[0].Cardinality]) - fft.BitReverse(pk.EvaluationId3BigDomain[:pk.Domain[0].Cardinality]) - vk.IdCanonical[0] = make([]fr.Element, pk.Domain[0].Cardinality) - vk.IdCanonical[1] = make([]fr.Element, pk.Domain[0].Cardinality) - vk.IdCanonical[2] = make([]fr.Element, pk.Domain[0].Cardinality) - copy(vk.IdCanonical[0], pk.EvaluationId1BigDomain) - copy(vk.IdCanonical[1], pk.EvaluationId2BigDomain) - copy(vk.IdCanonical[2], pk.EvaluationId3BigDomain) - - var err error - vk.Idpp[0], err = vk.Iopp.BuildProofOfProximity(pk.EvaluationId1BigDomain) - if err != nil { - return err - } - vk.Idpp[1], err = vk.Iopp.BuildProofOfProximity(pk.EvaluationId2BigDomain) - if err != nil { - return err - } - vk.Idpp[2], err = vk.Iopp.BuildProofOfProximity(pk.EvaluationId3BigDomain) - if err != nil { - return err - } - pk.Domain[1].FFT(pk.EvaluationId1BigDomain, fft.DIF, fft.OnCoset()) - pk.Domain[1].FFT(pk.EvaluationId2BigDomain, fft.DIF, fft.OnCoset()) - pk.Domain[1].FFT(pk.EvaluationId3BigDomain, fft.DIF, fft.OnCoset()) - - pk.Domain[0].FFTInverse(pk.EvaluationS1BigDomain[:pk.Domain[0].Cardinality], fft.DIF) - pk.Domain[0].FFTInverse(pk.EvaluationS2BigDomain[:pk.Domain[0].Cardinality], fft.DIF) - pk.Domain[0].FFTInverse(pk.EvaluationS3BigDomain[:pk.Domain[0].Cardinality], fft.DIF) - fft.BitReverse(pk.EvaluationS1BigDomain[:pk.Domain[0].Cardinality]) - fft.BitReverse(pk.EvaluationS2BigDomain[:pk.Domain[0].Cardinality]) - fft.BitReverse(pk.EvaluationS3BigDomain[:pk.Domain[0].Cardinality]) - - // commit S1, S2, S3 - vk.SCanonical[0] = make([]fr.Element, pk.Domain[0].Cardinality) - vk.SCanonical[1] = make([]fr.Element, pk.Domain[0].Cardinality) - vk.SCanonical[2] = make([]fr.Element, pk.Domain[0].Cardinality) - copy(vk.SCanonical[0], pk.EvaluationS1BigDomain[:pk.Domain[0].Cardinality]) - copy(vk.SCanonical[1], pk.EvaluationS2BigDomain[:pk.Domain[0].Cardinality]) - copy(vk.SCanonical[2], pk.EvaluationS3BigDomain[:pk.Domain[0].Cardinality]) - vk.Spp[0], err = vk.Iopp.BuildProofOfProximity(vk.SCanonical[0]) - if err != nil { - return err - } - vk.Spp[1], err = vk.Iopp.BuildProofOfProximity(vk.SCanonical[1]) - if err != nil { - return err - } - vk.Spp[2], err = vk.Iopp.BuildProofOfProximity(vk.SCanonical[2]) - if err != nil { - return err - } - pk.Domain[1].FFT(pk.EvaluationS1BigDomain, fft.DIF, fft.OnCoset()) - pk.Domain[1].FFT(pk.EvaluationS2BigDomain, fft.DIF, fft.OnCoset()) - pk.Domain[1].FFT(pk.EvaluationS3BigDomain, fft.DIF, fft.OnCoset()) - - return nil - -} - -// getIDSmallDomain returns the Lagrange form of ID on the small domain -func getIDSmallDomain(domain *fft.Domain) []fr.Element { - - res := make([]fr.Element, 3*domain.Cardinality) - - res[0].SetOne() - res[domain.Cardinality].Set(&domain.FrMultiplicativeGen) - res[2*domain.Cardinality].Square(&domain.FrMultiplicativeGen) - - for i := uint64(1); i < domain.Cardinality; i++ { - res[i].Mul(&res[i-1], &domain.Generator) - res[domain.Cardinality+i].Mul(&res[domain.Cardinality+i-1], &domain.Generator) - res[2*domain.Cardinality+i].Mul(&res[2*domain.Cardinality+i-1], &domain.Generator) - } - - return res -} - -// NbPublicWitness returns the expected public witness size (number of field elements) -func (vk *VerifyingKey) NbPublicWitness() int { - return int(vk.NbPublicVariables) -} - -// VerifyingKey returns pk.Vk -func (pk *ProvingKey) VerifyingKey() interface{} { - return pk.Vk -} diff --git a/backend/plonkfri/bw6-633/verify.go b/backend/plonkfri/bw6-633/verify.go deleted file mode 100644 index 1cf213e2cc..0000000000 --- a/backend/plonkfri/bw6-633/verify.go +++ /dev/null @@ -1,398 +0,0 @@ -// Copyright 2020 ConsenSys Software Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -// Code generated by gnark DO NOT EDIT - -package plonkfri - -import ( - "errors" - "fmt" - "github.com/consensys/gnark-crypto/ecc/bw6-633/fr" - "github.com/consensys/gnark-crypto/ecc/bw6-633/fr/fri" - fiatshamir "github.com/consensys/gnark-crypto/fiat-shamir" - "github.com/consensys/gnark/backend" - "math/big" -) - -var ErrInvalidAlgebraicRelation = errors.New("algebraic relation does not hold") - -func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector, opts ...backend.VerifierOption) error { - cfg, err := backend.NewVerifierConfig(opts...) - if err != nil { - return fmt.Errorf("create backend config: %w", err) - } - - // 0 - derive the challenges with Fiat Shamir - fs := fiatshamir.NewTranscript(cfg.ChallengeHash, "gamma", "beta", "alpha", "zeta") - - dataFiatShamir := make([][fr.Bytes]byte, len(publicWitness)+3) - for i := 0; i < len(publicWitness); i++ { - copy(dataFiatShamir[i][:], publicWitness[i].Marshal()) - } - copy(dataFiatShamir[len(publicWitness)][:], proof.LROpp[0].ID) - copy(dataFiatShamir[len(publicWitness)+1][:], proof.LROpp[1].ID) - copy(dataFiatShamir[len(publicWitness)+2][:], proof.LROpp[2].ID) - - beta, err := deriveRandomnessFixedSize(fs, "gamma", dataFiatShamir...) - if err != nil { - return err - } - - gamma, err := deriveRandomness(fs, "beta", nil) - if err != nil { - return err - } - - alpha, err := deriveRandomness(fs, "alpha", proof.Zpp.ID) - if err != nil { - return err - } - - // compute the size of the domain of evaluation of the committed polynomial, - // the opening position. The challenge zeta will be g^{i} where i is the opening - // position, and g is the generator of the fri domain. - rho := uint64(fri.GetRho()) - friSize := 2 * rho * vk.Size - var bFriSize big.Int - bFriSize.SetInt64(int64(friSize)) - frOpeningPosition, err := deriveRandomness(fs, "zeta", proof.Hpp[0].ID, proof.Hpp[1].ID, proof.Hpp[2].ID) - if err != nil { - return err - } - var bOpeningPosition big.Int - bOpeningPosition.SetBytes(frOpeningPosition.Marshal()).Mod(&bOpeningPosition, &bFriSize) - openingPosition := bOpeningPosition.Uint64() - - shiftedOpeningPosition := (openingPosition + uint64(2*rho)) % friSize - err = vk.Iopp.VerifyOpening(shiftedOpeningPosition, proof.OpeningsZmp[1], proof.Zpp) - if err != nil { - return err - } - - // 1 - verify that the commitments are low degree polynomials - - // ql, qr, qm, qo, qkIncomplete - err = vk.Iopp.VerifyProofOfProximity(vk.Qpp[0]) - if err != nil { - return err - } - err = vk.Iopp.VerifyProofOfProximity(vk.Qpp[1]) - if err != nil { - return err - } - err = vk.Iopp.VerifyProofOfProximity(vk.Qpp[2]) - if err != nil { - return err - } - err = vk.Iopp.VerifyProofOfProximity(vk.Qpp[3]) - if err != nil { - return err - } - err = vk.Iopp.VerifyProofOfProximity(vk.Qpp[4]) - if err != nil { - return err - } - - // l, r, o - err = vk.Iopp.VerifyProofOfProximity(proof.LROpp[0]) - if err != nil { - return err - } - err = vk.Iopp.VerifyProofOfProximity(proof.LROpp[1]) - if err != nil { - return err - } - err = vk.Iopp.VerifyProofOfProximity(proof.LROpp[2]) - if err != nil { - return err - } - err = vk.Iopp.VerifyProofOfProximity(proof.Zpp) - if err != nil { - return err - } - - // h0, h1, h2 - err = vk.Iopp.VerifyProofOfProximity(proof.Hpp[0]) - if err != nil { - return err - } - err = vk.Iopp.VerifyProofOfProximity(proof.Hpp[1]) - if err != nil { - return err - } - err = vk.Iopp.VerifyProofOfProximity(proof.Hpp[2]) - if err != nil { - return err - } - - // s1, s2, s3 - err = vk.Iopp.VerifyProofOfProximity(vk.Spp[0]) - if err != nil { - return err - } - err = vk.Iopp.VerifyProofOfProximity(vk.Spp[1]) - if err != nil { - return err - } - err = vk.Iopp.VerifyProofOfProximity(vk.Spp[2]) - if err != nil { - return err - } - - // id1, id2, id3 - err = vk.Iopp.VerifyProofOfProximity(vk.Idpp[0]) - if err != nil { - return err - } - err = vk.Iopp.VerifyProofOfProximity(vk.Idpp[1]) - if err != nil { - return err - } - err = vk.Iopp.VerifyProofOfProximity(vk.Idpp[2]) - if err != nil { - return err - } - - // Z - err = vk.Iopp.VerifyProofOfProximity(proof.Zpp) - if err != nil { - return err - } - - // 2 - verify the openings - - // ql, qr, qm, qo, qkIncomplete - // openingPosition := uint64(2) - err = vk.Iopp.VerifyOpening(openingPosition, proof.OpeningsQlQrQmQoQkincompletemp[0], vk.Qpp[0]) - if err != nil { - return err - } - err = vk.Iopp.VerifyOpening(openingPosition, proof.OpeningsQlQrQmQoQkincompletemp[1], vk.Qpp[1]) - if err != nil { - return err - } - err = vk.Iopp.VerifyOpening(openingPosition, proof.OpeningsQlQrQmQoQkincompletemp[2], vk.Qpp[2]) - if err != nil { - return err - } - err = vk.Iopp.VerifyOpening(openingPosition, proof.OpeningsQlQrQmQoQkincompletemp[3], vk.Qpp[3]) - if err != nil { - return err - } - err = vk.Iopp.VerifyOpening(openingPosition, proof.OpeningsQlQrQmQoQkincompletemp[4], vk.Qpp[4]) - if err != nil { - return err - } - - // l, r, o - err = vk.Iopp.VerifyOpening(openingPosition, proof.OpeningsLROmp[0], proof.LROpp[0]) - if err != nil { - return err - } - err = vk.Iopp.VerifyOpening(openingPosition, proof.OpeningsLROmp[1], proof.LROpp[1]) - if err != nil { - return err - } - err = vk.Iopp.VerifyOpening(openingPosition, proof.OpeningsLROmp[2], proof.LROpp[2]) - if err != nil { - return err - } - - // h0, h1, h2 - err = vk.Iopp.VerifyOpening(openingPosition, proof.OpeningsHmp[0], proof.Hpp[0]) - if err != nil { - return err - } - err = vk.Iopp.VerifyOpening(openingPosition, proof.OpeningsHmp[1], proof.Hpp[1]) - if err != nil { - return err - } - err = vk.Iopp.VerifyOpening(openingPosition, proof.OpeningsHmp[2], proof.Hpp[2]) - if err != nil { - return err - } - - // s0, s1, s2 - err = vk.Iopp.VerifyOpening(openingPosition, proof.OpeningsS1S2S3mp[0], vk.Spp[0]) - if err != nil { - return err - } - err = vk.Iopp.VerifyOpening(openingPosition, proof.OpeningsS1S2S3mp[1], vk.Spp[1]) - if err != nil { - return err - } - err = vk.Iopp.VerifyOpening(openingPosition, proof.OpeningsS1S2S3mp[2], vk.Spp[2]) - if err != nil { - return err - } - - // id0, id1, id2 - err = vk.Iopp.VerifyOpening(openingPosition, proof.OpeningsId1Id2Id3mp[0], vk.Idpp[0]) - if err != nil { - return err - } - err = vk.Iopp.VerifyOpening(openingPosition, proof.OpeningsId1Id2Id3mp[1], vk.Idpp[1]) - if err != nil { - return err - } - err = vk.Iopp.VerifyOpening(openingPosition, proof.OpeningsId1Id2Id3mp[2], vk.Idpp[2]) - if err != nil { - return err - } - - // Z, Zshift - err = vk.Iopp.VerifyOpening(openingPosition, proof.OpeningsZmp[0], proof.Zpp) - if err != nil { - return err - } - - // verification of the algebraic relation - var ql, qr, qm, qo, qk fr.Element - ql.Set(&proof.OpeningsQlQrQmQoQkincompletemp[0].ClaimedValue) - qr.Set(&proof.OpeningsQlQrQmQoQkincompletemp[1].ClaimedValue) - qm.Set(&proof.OpeningsQlQrQmQoQkincompletemp[2].ClaimedValue) - qo.Set(&proof.OpeningsQlQrQmQoQkincompletemp[3].ClaimedValue) - qk.Set(&proof.OpeningsQlQrQmQoQkincompletemp[4].ClaimedValue) // -> to be completed - - var l, r, o fr.Element - l.Set(&proof.OpeningsLROmp[0].ClaimedValue) - r.Set(&proof.OpeningsLROmp[1].ClaimedValue) - o.Set(&proof.OpeningsLROmp[2].ClaimedValue) - - var h1, h2, h3 fr.Element - h1.Set(&proof.OpeningsHmp[0].ClaimedValue) - h2.Set(&proof.OpeningsHmp[1].ClaimedValue) - h3.Set(&proof.OpeningsHmp[2].ClaimedValue) - - var s1, s2, s3 fr.Element - s1.Set(&proof.OpeningsS1S2S3mp[0].ClaimedValue) - s2.Set(&proof.OpeningsS1S2S3mp[1].ClaimedValue) - s3.Set(&proof.OpeningsS1S2S3mp[2].ClaimedValue) - - var id1, id2, id3 fr.Element - id1.Set(&proof.OpeningsId1Id2Id3mp[0].ClaimedValue) - id2.Set(&proof.OpeningsId1Id2Id3mp[1].ClaimedValue) - id3.Set(&proof.OpeningsId1Id2Id3mp[2].ClaimedValue) - - var z, zshift fr.Element - z.Set(&proof.OpeningsZmp[0].ClaimedValue) - zshift.Set(&proof.OpeningsZmp[1].ClaimedValue) - - // 2 - compute the LHS: (ql*l+..+qk)+ α*(z(μx)*(l+β*s₁+γ)*..-z*(l+β*id1+γ))+α²*z*(l1-1) - var zeta fr.Element - zeta.Exp(vk.GenOpening, &bOpeningPosition) - - var lhs, t1, t2, t3, tmp, tmp2 fr.Element - // 2.1 (ql*l+..+qk) - t1.Mul(&l, &ql) - tmp.Mul(&r, &qr) - t1.Add(&t1, &tmp) - tmp.Mul(&qm, &l).Mul(&tmp, &r) - t1.Add(&t1, &tmp) - tmp.Mul(&o, &qo) - t1.Add(&tmp, &t1) - tmp = completeQk(publicWitness, vk, zeta) - tmp.Add(&qk, &tmp) - t1.Add(&tmp, &t1) - - // 2.2 (z(ux)*(l+β*s1+γ)*..-z*(l+β*id1+γ)) - t2.Mul(&beta, &s1).Add(&t2, &l).Add(&t2, &gamma) - tmp.Mul(&beta, &s2).Add(&tmp, &r).Add(&tmp, &gamma) - t2.Mul(&tmp, &t2) - tmp.Mul(&beta, &s3).Add(&tmp, &o).Add(&tmp, &gamma) - t2.Mul(&tmp, &t2).Mul(&t2, &zshift) - - tmp.Mul(&beta, &id1).Add(&tmp, &l).Add(&tmp, &gamma) - tmp2.Mul(&beta, &id2).Add(&tmp2, &r).Add(&tmp2, &gamma) - tmp.Mul(&tmp, &tmp2) - tmp2.Mul(&beta, &id3).Add(&tmp2, &o).Add(&tmp2, &gamma) - tmp.Mul(&tmp2, &tmp).Mul(&tmp, &z) - - t2.Sub(&t2, &tmp) - - // 2.3 (z-1)*l1 - var one fr.Element - one.SetOne() - t3.Exp(zeta, big.NewInt(int64(vk.Size))).Sub(&t3, &one) - tmp.Sub(&zeta, &one).Inverse(&tmp).Mul(&tmp, &vk.SizeInv) - t3.Mul(&tmp, &t3) - tmp.Sub(&z, &one) - t3.Mul(&tmp, &t3) - - // 2.4 (ql*l+s+qk) + α*(z(ux)*(l+β*s1+γ)*...-z*(l+β*id1+γ)..)+ α²*z*(l1-1) - lhs.Set(&t3).Mul(&lhs, &alpha).Add(&lhs, &t2).Mul(&lhs, &alpha).Add(&lhs, &t1) - - // 3 - compute the RHS - var rhs fr.Element - tmp.Exp(zeta, big.NewInt(int64(vk.Size+2))) - rhs.Mul(&h3, &tmp). - Add(&rhs, &h2). - Mul(&rhs, &tmp). - Add(&rhs, &h1) - - tmp.Exp(zeta, big.NewInt(int64(vk.Size))).Sub(&tmp, &one) - rhs.Mul(&rhs, &tmp) - - // 4 - verify the relation LHS==RHS - if !rhs.Equal(&lhs) { - return ErrInvalidAlgebraicRelation - } - - return nil - -} - -// completeQk returns ∑_{i> nn - _is := bits.Reverse64(uint64((i+toShift)%nbElmts)) >> nn - - // in what follows gⁱ is understood as the generator of the chosen coset of domainBig - f[0].Mul(&evaluationIDBigDomain, &beta).Add(&f[0], &l[_i]).Add(&f[0], &gamma) //l(gⁱ)+gⁱ*β+γ - f[1].Mul(&evaluationIDBigDomain, &cosetShift).Mul(&f[1], &beta).Add(&f[1], &r[_i]).Add(&f[1], &gamma) //r(gⁱ)+u*gⁱ*β+γ - f[2].Mul(&evaluationIDBigDomain, &cosetShiftSquare).Mul(&f[2], &beta).Add(&f[2], &o[_i]).Add(&f[2], &gamma) //o(gⁱ)+u²*gⁱ*β+γ - - g[0].Mul(&pk.EvaluationS1BigDomain[_i], &beta).Add(&g[0], &l[_i]).Add(&g[0], &gamma) //l(gⁱ))+s1(gⁱ)*β+γ - g[1].Mul(&pk.EvaluationS2BigDomain[_i], &beta).Add(&g[1], &r[_i]).Add(&g[1], &gamma) //r(gⁱ))+s2(gⁱ)*β+γ - g[2].Mul(&pk.EvaluationS3BigDomain[_i], &beta).Add(&g[2], &o[_i]).Add(&g[2], &gamma) //o(gⁱ))+s3(gⁱ)*β+γ - - f[0].Mul(&f[0], &f[1]).Mul(&f[0], &f[2]).Mul(&f[0], &z[_i]) // z(gⁱ)*(l(gⁱ)+g^i*β+γ)*(r(g^i)+u*g^i*β+γ)*(o(g^i)+u²*g^i*β+γ) - g[0].Mul(&g[0], &g[1]).Mul(&g[0], &g[2]).Mul(&g[0], &z[_is]) // z_(ugⁱ)*(l(gⁱ))+s₁(gⁱ)*β+γ)*(r(gⁱ))+s₂(gⁱ)*β+γ)*(o(gⁱ))+s₃(gⁱ)*β+γ) - - res[_i].Sub(&g[0], &f[0]) // z_(ugⁱ)*(l(gⁱ))+s₁(gⁱ)*β+γ)*(r(gⁱ))+s₂(gⁱ)*β+γ)*(o(gⁱ))+s₃(gⁱ)*β+γ) - z(gⁱ)*(l(gⁱ)+g^i*β+γ)*(r(g^i)+u*g^i*β+γ)*(o(g^i)+u²*g^i*β+γ) - - evaluationIDBigDomain.Mul(&evaluationIDBigDomain, &pk.Domain[1].Generator) // gⁱ*g - } - }) - - return res -} - -// evalConstraintsInd computes the evaluation of lL+qrR+qqmL.R+qoO+k on -// the odd coset of (Z/8mZ)/(Z/4mZ), where m=nbConstraints+nbAssertions. -// -// * lsL, lsR, lsO are the evaluation of the blinded solution vectors on odd cosets -// * lsQk is the completed version of qk, in canonical version -// -// lsL, lsR, lsO are in bit reversed order, lsQk is in the correct order. -func evalConstraintsInd(pk *ProvingKey, lsL, lsR, lsO, lsQk []fr.Element) []fr.Element { - - res := make([]fr.Element, pk.Domain[1].Cardinality) - // nn := uint64(64 - bits.TrailingZeros64(pk.Domain[1].Cardinality)) - - utils.Parallelize(len(res), func(start, end int) { - - var t0, t1 fr.Element - - for i := start; i < end; i++ { - - // irev := bits.Reverse64(uint64(i)) >> nn - - t1.Mul(&pk.EvaluationQmDomainBigBitReversed[i], &lsR[i]) // qm.r - t1.Add(&t1, &pk.EvaluationQlDomainBigBitReversed[i]) // qm.r + ql - t1.Mul(&t1, &lsL[i]) // qm.l.r + ql.l - - t0.Mul(&pk.EvaluationQrDomainBigBitReversed[i], &lsR[i]) - t0.Add(&t0, &t1) // qm.l.r + ql.l + qr.r - - t1.Mul(&pk.EvaluationQoDomainBigBitReversed[i], &lsO[i]) - t0.Add(&t0, &t1) // ql.l + qr.r + qm.l.r + qo.o - res[i].Add(&t0, &lsQk[i]) // ql.l + qr.r + qm.l.r + qo.o + k - - } - }) - - return res -} - -// fftBigCosetWOBitReverse evaluates poly (canonical form) of degree m> nn - - t.Sub(&evaluationBlindedZDomainBigBitReversed[_i], &one) // evaluates L₁(X)*(Z(X)-1) on a coset of the big domain - h[_i].Mul(&startsAtOne[_i], &t).Mul(&h[_i], &alpha). - Add(&h[_i], &evaluationConstraintOrderingBitReversed[_i]). - Mul(&h[_i], &alpha). - Add(&h[_i], &evaluationConstraintsIndBitReversed[_i]). - Mul(&h[_i], &evaluationXnMinusOneInverse[i%ratio]) - } - }) - - // put h in canonical form. h is of degree 3*(n+1)+2. - // using fft.DIT put h revert bit reverse - pk.Domain[1].FFTInverse(h, fft.DIT, fft.OnCoset()) - - // degree of hi is n+2 because of the blinding - h1 := h[:pk.Domain[0].Cardinality+2] - h2 := h[pk.Domain[0].Cardinality+2 : 2*(pk.Domain[0].Cardinality+2)] - h3 := h[2*(pk.Domain[0].Cardinality+2) : 3*(pk.Domain[0].Cardinality+2)] - - return h1, h2, h3 - -} - -// computeZ computes Z, in canonical basis, where: -// -// - Z of degree n (domainNum.Cardinality) -// -// - Z(1)=1 -// (l_i+z**i+gamma)*(r_i+u*z**i+gamma)*(o_i+u**2z**i+gamma) -// -// - for i>0: Z(u**i) = Pi_{k "small" domain, used for individual polynomials - // 1 -> "big" domain, used for the computation of the quotient - Domain [2]fft.Domain - - // s1, s2, s3 (L=Lagrange basis small domain, C=canonical basis, Ls=Lagrange Shifted big domain) - LId []fr.Element - EvaluationId1BigDomain, EvaluationId2BigDomain, EvaluationId3BigDomain []fr.Element - EvaluationS1BigDomain, EvaluationS2BigDomain, EvaluationS3BigDomain []fr.Element - - // position -> permuted position (position in [0,3*sizeSystem-1]) - Permutation []int64 -} - -// VerifyingKey stores the data needed to verify a proof: -// * The commitment scheme -// * Commitments of ql prepended with as many ones as there are public inputs -// * Commitments of qr, qm, qo, qk prepended with as many zeroes as there are public inputs -// * Commitments to S1, S2, S3 -type VerifyingKey struct { - - // Size circuit, that is the closest power of 2 bounding above - // number of constraints+number of public inputs - Size uint64 - SizeInv fr.Element - Generator fr.Element - NbPublicVariables uint64 - - // cosetShift generator of the coset on the small domain - CosetShift fr.Element - - // S commitments to S1, S2, S3 - SCanonical [3][]fr.Element - Spp [3]fri.ProofOfProximity - - // Id commitments to Id1, Id2, Id3 - // Id [3]Commitment - IdCanonical [3][]fr.Element - Idpp [3]fri.ProofOfProximity - - // Commitments to ql, qr, qm, qo prepended with as many zeroes (ones for l) as there are public inputs. - // In particular Qk is not complete. - Qpp [5]fri.ProofOfProximity // Ql, Qr, Qm, Qo, Qk - - // Iopp scheme (currently one for each size of polynomial) - Iopp fri.Iopp - - // generator of the group on which the Iopp works. If i is the opening position, - // the polynomials will be opened at genOpening^{i}. - GenOpening fr.Element -} - -// Setup sets proving and verifying keys -func Setup(spr *cs.SparseR1CS) (*ProvingKey, *VerifyingKey, error) { - - var pk ProvingKey - var vk VerifyingKey - - // The verifying key shares data with the proving key - pk.Vk = &vk - - nbConstraints := spr.GetNbConstraints() - - // fft domains - sizeSystem := uint64(nbConstraints + len(spr.Public)) // len(spr.Public) is for the placeholder constraints - pk.Domain[0] = *fft.NewDomain(sizeSystem) - - // h, the quotient polynomial is of degree 3(n+1)+2, so it's in a 3(n+2) dim vector space, - // the domain is the next power of 2 superior to 3(n+2). 4*domainNum is enough in all cases - // except when n<6. - if sizeSystem < 6 { - pk.Domain[1] = *fft.NewDomain(8 * sizeSystem) - } else { - pk.Domain[1] = *fft.NewDomain(4 * sizeSystem) - } - pk.Vk.CosetShift.Set(&pk.Domain[0].FrMultiplicativeGen) - - vk.Size = pk.Domain[0].Cardinality - vk.SizeInv.SetUint64(vk.Size).Inverse(&vk.SizeInv) - vk.Generator.Set(&pk.Domain[0].Generator) - vk.NbPublicVariables = uint64(len(spr.Public)) - - // IOP schemess - // The +2 is to handle the blinding. - sizeIopp := pk.Domain[0].Cardinality + 2 - vk.Iopp = fri.RADIX_2_FRI.New(sizeIopp, sha256.New()) - // only there to access the group used in FRI... - rho := uint64(fri.GetRho()) - // we multiply by 2 because the IOP is created with size pk.Domain[0].Cardinality + 2 (because - // of the blinding), so the domain will be rho*size_domain where size_domain is the next power - // of 2 after pk.Domain[0].Cardinality + 2, which is 2*rho*pk.Domain[0].Cardinality - tmpDomain := fft.NewDomain(2 * rho * pk.Domain[0].Cardinality) - vk.GenOpening.Set(&tmpDomain.Generator) - - // public polynomials corresponding to constraints: [ placholders | constraints | assertions ] - pk.EvaluationQlDomainBigBitReversed = make([]fr.Element, pk.Domain[1].Cardinality) - pk.EvaluationQrDomainBigBitReversed = make([]fr.Element, pk.Domain[1].Cardinality) - pk.EvaluationQmDomainBigBitReversed = make([]fr.Element, pk.Domain[1].Cardinality) - pk.EvaluationQoDomainBigBitReversed = make([]fr.Element, pk.Domain[1].Cardinality) - pk.LQkIncompleteDomainSmall = make([]fr.Element, pk.Domain[0].Cardinality) - pk.CQkIncomplete = make([]fr.Element, pk.Domain[0].Cardinality) - - for i := 0; i < len(spr.Public); i++ { // placeholders (-PUB_INPUT_i + qk_i = 0) TODO should return error if size is inconsistent - pk.EvaluationQlDomainBigBitReversed[i].SetOne().Neg(&pk.EvaluationQlDomainBigBitReversed[i]) - pk.EvaluationQrDomainBigBitReversed[i].SetZero() - pk.EvaluationQmDomainBigBitReversed[i].SetZero() - pk.EvaluationQoDomainBigBitReversed[i].SetZero() - pk.LQkIncompleteDomainSmall[i].SetZero() // --> to be completed by the prover - pk.CQkIncomplete[i].Set(&pk.LQkIncompleteDomainSmall[i]) // --> to be completed by the prover - } - offset := len(spr.Public) - - j := 0 - it := spr.GetSparseR1CIterator() - for c := it.Next(); c != nil; c = it.Next() { - pk.EvaluationQlDomainBigBitReversed[offset+j].Set(&spr.Coefficients[c.QL]) - pk.EvaluationQrDomainBigBitReversed[offset+j].Set(&spr.Coefficients[c.QR]) - pk.EvaluationQmDomainBigBitReversed[offset+j].Set(&spr.Coefficients[c.QM]) - pk.EvaluationQoDomainBigBitReversed[offset+j].Set(&spr.Coefficients[c.QO]) - pk.LQkIncompleteDomainSmall[offset+j].Set(&spr.Coefficients[c.QC]) - pk.CQkIncomplete[offset+j].Set(&pk.LQkIncompleteDomainSmall[offset+j]) - - j++ - } - - pk.Domain[0].FFTInverse(pk.EvaluationQlDomainBigBitReversed[:pk.Domain[0].Cardinality], fft.DIF) - pk.Domain[0].FFTInverse(pk.EvaluationQrDomainBigBitReversed[:pk.Domain[0].Cardinality], fft.DIF) - pk.Domain[0].FFTInverse(pk.EvaluationQmDomainBigBitReversed[:pk.Domain[0].Cardinality], fft.DIF) - pk.Domain[0].FFTInverse(pk.EvaluationQoDomainBigBitReversed[:pk.Domain[0].Cardinality], fft.DIF) - pk.Domain[0].FFTInverse(pk.CQkIncomplete, fft.DIF) - fft.BitReverse(pk.EvaluationQlDomainBigBitReversed[:pk.Domain[0].Cardinality]) - fft.BitReverse(pk.EvaluationQrDomainBigBitReversed[:pk.Domain[0].Cardinality]) - fft.BitReverse(pk.EvaluationQmDomainBigBitReversed[:pk.Domain[0].Cardinality]) - fft.BitReverse(pk.EvaluationQoDomainBigBitReversed[:pk.Domain[0].Cardinality]) - fft.BitReverse(pk.CQkIncomplete) - - // Commit to the polynomials to set up the verifying key - pk.CQl = make([]fr.Element, pk.Domain[0].Cardinality) - pk.CQr = make([]fr.Element, pk.Domain[0].Cardinality) - pk.CQm = make([]fr.Element, pk.Domain[0].Cardinality) - pk.CQo = make([]fr.Element, pk.Domain[0].Cardinality) - copy(pk.CQl, pk.EvaluationQlDomainBigBitReversed) - copy(pk.CQr, pk.EvaluationQrDomainBigBitReversed) - copy(pk.CQm, pk.EvaluationQmDomainBigBitReversed) - copy(pk.CQo, pk.EvaluationQoDomainBigBitReversed) - var err error - vk.Qpp[0], err = vk.Iopp.BuildProofOfProximity(pk.CQl) - if err != nil { - return &pk, &vk, err - } - vk.Qpp[1], err = vk.Iopp.BuildProofOfProximity(pk.CQr) - if err != nil { - return &pk, &vk, err - } - vk.Qpp[2], err = vk.Iopp.BuildProofOfProximity(pk.CQm) - if err != nil { - return &pk, &vk, err - } - vk.Qpp[3], err = vk.Iopp.BuildProofOfProximity(pk.CQo) - if err != nil { - return &pk, &vk, err - } - vk.Qpp[4], err = vk.Iopp.BuildProofOfProximity(pk.CQkIncomplete) - if err != nil { - return &pk, &vk, err - } - - pk.Domain[1].FFT(pk.EvaluationQlDomainBigBitReversed, fft.DIF, fft.OnCoset()) - pk.Domain[1].FFT(pk.EvaluationQrDomainBigBitReversed, fft.DIF, fft.OnCoset()) - pk.Domain[1].FFT(pk.EvaluationQmDomainBigBitReversed, fft.DIF, fft.OnCoset()) - pk.Domain[1].FFT(pk.EvaluationQoDomainBigBitReversed, fft.DIF, fft.OnCoset()) - - // build permutation. Note: at this stage, the permutation takes in account the placeholders - buildPermutation(spr, &pk) - - // set s1, s2, s3 - err = computePermutationPolynomials(&pk, &vk) - if err != nil { - return &pk, &vk, err - } - - return &pk, &vk, nil - -} - -// buildPermutation builds the Permutation associated with a circuit. -// -// The permutation s is composed of cycles of maximum length such that -// -// s. (l||r||o) = (l||r||o) -// -// , where l||r||o is the concatenation of the indices of l, r, o in -// ql.l+qr.r+qm.l.r+qo.O+k = 0. -// -// The permutation is encoded as a slice s of size 3*size(l), where the -// i-th entry of l||r||o is sent to the s[i]-th entry, so it acts on a tab -// like this: for i in tab: tab[i] = tab[permutation[i]] -func buildPermutation(spr *cs.SparseR1CS, pk *ProvingKey) { - - nbVariables := spr.NbInternalVariables + len(spr.Public) + len(spr.Secret) - sizeSolution := int(pk.Domain[0].Cardinality) - - // init permutation - pk.Permutation = make([]int64, 3*sizeSolution) - for i := 0; i < len(pk.Permutation); i++ { - pk.Permutation[i] = -1 - } - - // init LRO position -> variable_ID - lro := make([]int, 3*sizeSolution) // position -> variable_ID - for i := 0; i < len(spr.Public); i++ { - lro[i] = i // IDs of LRO associated to placeholders (only L needs to be taken care of) - } - - offset := len(spr.Public) - - j := 0 - it := spr.GetSparseR1CIterator() - for c := it.Next(); c != nil; c = it.Next() { - lro[offset+j] = int(c.XA) - lro[sizeSolution+offset+j] = int(c.XB) - lro[2*sizeSolution+offset+j] = int(c.XC) - j++ - } - - // init cycle: - // map ID -> last position the ID was seen - cycle := make([]int64, nbVariables) - for i := 0; i < len(cycle); i++ { - cycle[i] = -1 - } - - for i := 0; i < len(lro); i++ { - if cycle[lro[i]] != -1 { - // if != -1, it means we already encountered this value - // so we need to set the corresponding permutation index. - pk.Permutation[i] = cycle[lro[i]] - } - cycle[lro[i]] = int64(i) - } - - // complete the Permutation by filling the first IDs encountered - for i := 0; i < len(pk.Permutation); i++ { - if pk.Permutation[i] == -1 { - pk.Permutation[i] = cycle[lro[i]] - } - } -} - -// computePermutationPolynomials computes the LDE (Lagrange basis) of the permutations -// s1, s2, s3. -// -// 0 1 .. n-1 | n n+1 .. 2*n-1 | 2n 2n+1 .. 3n-1 | -// -// | -// | Permutation -// -// s00 s01 .. s0n-1 s10 s11 .. s1n-1 s20 s21 .. s2n-1 v -// \---------------/ \--------------------/ \------------------------/ -// -// s1 (LDE) s2 (LDE) s3 (LDE) -func computePermutationPolynomials(pk *ProvingKey, vk *VerifyingKey) error { - - nbElmt := int(pk.Domain[0].Cardinality) - - // sID = [1,..,g^{n-1},s,..,s*g^{n-1},s^2,..,s^2*g^{n-1}] - pk.LId = getIDSmallDomain(&pk.Domain[0]) - - // canonical form of S1, S2, S3 - pk.EvaluationS1BigDomain = make([]fr.Element, pk.Domain[1].Cardinality) - pk.EvaluationS2BigDomain = make([]fr.Element, pk.Domain[1].Cardinality) - pk.EvaluationS3BigDomain = make([]fr.Element, pk.Domain[1].Cardinality) - for i := 0; i < nbElmt; i++ { - pk.EvaluationS1BigDomain[i].Set(&pk.LId[pk.Permutation[i]]) - pk.EvaluationS2BigDomain[i].Set(&pk.LId[pk.Permutation[nbElmt+i]]) - pk.EvaluationS3BigDomain[i].Set(&pk.LId[pk.Permutation[2*nbElmt+i]]) - } - - // Evaluations of Sid1, Sid2, Sid3 on cosets of Domain[1] - pk.EvaluationId1BigDomain = make([]fr.Element, pk.Domain[1].Cardinality) - pk.EvaluationId2BigDomain = make([]fr.Element, pk.Domain[1].Cardinality) - pk.EvaluationId3BigDomain = make([]fr.Element, pk.Domain[1].Cardinality) - copy(pk.EvaluationId1BigDomain, pk.LId[:nbElmt]) - copy(pk.EvaluationId2BigDomain, pk.LId[nbElmt:2*nbElmt]) - copy(pk.EvaluationId3BigDomain, pk.LId[2*nbElmt:]) - pk.Domain[0].FFTInverse(pk.EvaluationId1BigDomain[:pk.Domain[0].Cardinality], fft.DIF) - pk.Domain[0].FFTInverse(pk.EvaluationId2BigDomain[:pk.Domain[0].Cardinality], fft.DIF) - pk.Domain[0].FFTInverse(pk.EvaluationId3BigDomain[:pk.Domain[0].Cardinality], fft.DIF) - fft.BitReverse(pk.EvaluationId1BigDomain[:pk.Domain[0].Cardinality]) - fft.BitReverse(pk.EvaluationId2BigDomain[:pk.Domain[0].Cardinality]) - fft.BitReverse(pk.EvaluationId3BigDomain[:pk.Domain[0].Cardinality]) - vk.IdCanonical[0] = make([]fr.Element, pk.Domain[0].Cardinality) - vk.IdCanonical[1] = make([]fr.Element, pk.Domain[0].Cardinality) - vk.IdCanonical[2] = make([]fr.Element, pk.Domain[0].Cardinality) - copy(vk.IdCanonical[0], pk.EvaluationId1BigDomain) - copy(vk.IdCanonical[1], pk.EvaluationId2BigDomain) - copy(vk.IdCanonical[2], pk.EvaluationId3BigDomain) - - var err error - vk.Idpp[0], err = vk.Iopp.BuildProofOfProximity(pk.EvaluationId1BigDomain) - if err != nil { - return err - } - vk.Idpp[1], err = vk.Iopp.BuildProofOfProximity(pk.EvaluationId2BigDomain) - if err != nil { - return err - } - vk.Idpp[2], err = vk.Iopp.BuildProofOfProximity(pk.EvaluationId3BigDomain) - if err != nil { - return err - } - pk.Domain[1].FFT(pk.EvaluationId1BigDomain, fft.DIF, fft.OnCoset()) - pk.Domain[1].FFT(pk.EvaluationId2BigDomain, fft.DIF, fft.OnCoset()) - pk.Domain[1].FFT(pk.EvaluationId3BigDomain, fft.DIF, fft.OnCoset()) - - pk.Domain[0].FFTInverse(pk.EvaluationS1BigDomain[:pk.Domain[0].Cardinality], fft.DIF) - pk.Domain[0].FFTInverse(pk.EvaluationS2BigDomain[:pk.Domain[0].Cardinality], fft.DIF) - pk.Domain[0].FFTInverse(pk.EvaluationS3BigDomain[:pk.Domain[0].Cardinality], fft.DIF) - fft.BitReverse(pk.EvaluationS1BigDomain[:pk.Domain[0].Cardinality]) - fft.BitReverse(pk.EvaluationS2BigDomain[:pk.Domain[0].Cardinality]) - fft.BitReverse(pk.EvaluationS3BigDomain[:pk.Domain[0].Cardinality]) - - // commit S1, S2, S3 - vk.SCanonical[0] = make([]fr.Element, pk.Domain[0].Cardinality) - vk.SCanonical[1] = make([]fr.Element, pk.Domain[0].Cardinality) - vk.SCanonical[2] = make([]fr.Element, pk.Domain[0].Cardinality) - copy(vk.SCanonical[0], pk.EvaluationS1BigDomain[:pk.Domain[0].Cardinality]) - copy(vk.SCanonical[1], pk.EvaluationS2BigDomain[:pk.Domain[0].Cardinality]) - copy(vk.SCanonical[2], pk.EvaluationS3BigDomain[:pk.Domain[0].Cardinality]) - vk.Spp[0], err = vk.Iopp.BuildProofOfProximity(vk.SCanonical[0]) - if err != nil { - return err - } - vk.Spp[1], err = vk.Iopp.BuildProofOfProximity(vk.SCanonical[1]) - if err != nil { - return err - } - vk.Spp[2], err = vk.Iopp.BuildProofOfProximity(vk.SCanonical[2]) - if err != nil { - return err - } - pk.Domain[1].FFT(pk.EvaluationS1BigDomain, fft.DIF, fft.OnCoset()) - pk.Domain[1].FFT(pk.EvaluationS2BigDomain, fft.DIF, fft.OnCoset()) - pk.Domain[1].FFT(pk.EvaluationS3BigDomain, fft.DIF, fft.OnCoset()) - - return nil - -} - -// getIDSmallDomain returns the Lagrange form of ID on the small domain -func getIDSmallDomain(domain *fft.Domain) []fr.Element { - - res := make([]fr.Element, 3*domain.Cardinality) - - res[0].SetOne() - res[domain.Cardinality].Set(&domain.FrMultiplicativeGen) - res[2*domain.Cardinality].Square(&domain.FrMultiplicativeGen) - - for i := uint64(1); i < domain.Cardinality; i++ { - res[i].Mul(&res[i-1], &domain.Generator) - res[domain.Cardinality+i].Mul(&res[domain.Cardinality+i-1], &domain.Generator) - res[2*domain.Cardinality+i].Mul(&res[2*domain.Cardinality+i-1], &domain.Generator) - } - - return res -} - -// NbPublicWitness returns the expected public witness size (number of field elements) -func (vk *VerifyingKey) NbPublicWitness() int { - return int(vk.NbPublicVariables) -} - -// VerifyingKey returns pk.Vk -func (pk *ProvingKey) VerifyingKey() interface{} { - return pk.Vk -} diff --git a/backend/plonkfri/bw6-761/verify.go b/backend/plonkfri/bw6-761/verify.go deleted file mode 100644 index fe74c9d864..0000000000 --- a/backend/plonkfri/bw6-761/verify.go +++ /dev/null @@ -1,398 +0,0 @@ -// Copyright 2020 ConsenSys Software Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -// Code generated by gnark DO NOT EDIT - -package plonkfri - -import ( - "errors" - "fmt" - "github.com/consensys/gnark-crypto/ecc/bw6-761/fr" - "github.com/consensys/gnark-crypto/ecc/bw6-761/fr/fri" - fiatshamir "github.com/consensys/gnark-crypto/fiat-shamir" - "github.com/consensys/gnark/backend" - "math/big" -) - -var ErrInvalidAlgebraicRelation = errors.New("algebraic relation does not hold") - -func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector, opts ...backend.VerifierOption) error { - cfg, err := backend.NewVerifierConfig(opts...) - if err != nil { - return fmt.Errorf("create backend config: %w", err) - } - - // 0 - derive the challenges with Fiat Shamir - fs := fiatshamir.NewTranscript(cfg.ChallengeHash, "gamma", "beta", "alpha", "zeta") - - dataFiatShamir := make([][fr.Bytes]byte, len(publicWitness)+3) - for i := 0; i < len(publicWitness); i++ { - copy(dataFiatShamir[i][:], publicWitness[i].Marshal()) - } - copy(dataFiatShamir[len(publicWitness)][:], proof.LROpp[0].ID) - copy(dataFiatShamir[len(publicWitness)+1][:], proof.LROpp[1].ID) - copy(dataFiatShamir[len(publicWitness)+2][:], proof.LROpp[2].ID) - - beta, err := deriveRandomnessFixedSize(fs, "gamma", dataFiatShamir...) - if err != nil { - return err - } - - gamma, err := deriveRandomness(fs, "beta", nil) - if err != nil { - return err - } - - alpha, err := deriveRandomness(fs, "alpha", proof.Zpp.ID) - if err != nil { - return err - } - - // compute the size of the domain of evaluation of the committed polynomial, - // the opening position. The challenge zeta will be g^{i} where i is the opening - // position, and g is the generator of the fri domain. - rho := uint64(fri.GetRho()) - friSize := 2 * rho * vk.Size - var bFriSize big.Int - bFriSize.SetInt64(int64(friSize)) - frOpeningPosition, err := deriveRandomness(fs, "zeta", proof.Hpp[0].ID, proof.Hpp[1].ID, proof.Hpp[2].ID) - if err != nil { - return err - } - var bOpeningPosition big.Int - bOpeningPosition.SetBytes(frOpeningPosition.Marshal()).Mod(&bOpeningPosition, &bFriSize) - openingPosition := bOpeningPosition.Uint64() - - shiftedOpeningPosition := (openingPosition + uint64(2*rho)) % friSize - err = vk.Iopp.VerifyOpening(shiftedOpeningPosition, proof.OpeningsZmp[1], proof.Zpp) - if err != nil { - return err - } - - // 1 - verify that the commitments are low degree polynomials - - // ql, qr, qm, qo, qkIncomplete - err = vk.Iopp.VerifyProofOfProximity(vk.Qpp[0]) - if err != nil { - return err - } - err = vk.Iopp.VerifyProofOfProximity(vk.Qpp[1]) - if err != nil { - return err - } - err = vk.Iopp.VerifyProofOfProximity(vk.Qpp[2]) - if err != nil { - return err - } - err = vk.Iopp.VerifyProofOfProximity(vk.Qpp[3]) - if err != nil { - return err - } - err = vk.Iopp.VerifyProofOfProximity(vk.Qpp[4]) - if err != nil { - return err - } - - // l, r, o - err = vk.Iopp.VerifyProofOfProximity(proof.LROpp[0]) - if err != nil { - return err - } - err = vk.Iopp.VerifyProofOfProximity(proof.LROpp[1]) - if err != nil { - return err - } - err = vk.Iopp.VerifyProofOfProximity(proof.LROpp[2]) - if err != nil { - return err - } - err = vk.Iopp.VerifyProofOfProximity(proof.Zpp) - if err != nil { - return err - } - - // h0, h1, h2 - err = vk.Iopp.VerifyProofOfProximity(proof.Hpp[0]) - if err != nil { - return err - } - err = vk.Iopp.VerifyProofOfProximity(proof.Hpp[1]) - if err != nil { - return err - } - err = vk.Iopp.VerifyProofOfProximity(proof.Hpp[2]) - if err != nil { - return err - } - - // s1, s2, s3 - err = vk.Iopp.VerifyProofOfProximity(vk.Spp[0]) - if err != nil { - return err - } - err = vk.Iopp.VerifyProofOfProximity(vk.Spp[1]) - if err != nil { - return err - } - err = vk.Iopp.VerifyProofOfProximity(vk.Spp[2]) - if err != nil { - return err - } - - // id1, id2, id3 - err = vk.Iopp.VerifyProofOfProximity(vk.Idpp[0]) - if err != nil { - return err - } - err = vk.Iopp.VerifyProofOfProximity(vk.Idpp[1]) - if err != nil { - return err - } - err = vk.Iopp.VerifyProofOfProximity(vk.Idpp[2]) - if err != nil { - return err - } - - // Z - err = vk.Iopp.VerifyProofOfProximity(proof.Zpp) - if err != nil { - return err - } - - // 2 - verify the openings - - // ql, qr, qm, qo, qkIncomplete - // openingPosition := uint64(2) - err = vk.Iopp.VerifyOpening(openingPosition, proof.OpeningsQlQrQmQoQkincompletemp[0], vk.Qpp[0]) - if err != nil { - return err - } - err = vk.Iopp.VerifyOpening(openingPosition, proof.OpeningsQlQrQmQoQkincompletemp[1], vk.Qpp[1]) - if err != nil { - return err - } - err = vk.Iopp.VerifyOpening(openingPosition, proof.OpeningsQlQrQmQoQkincompletemp[2], vk.Qpp[2]) - if err != nil { - return err - } - err = vk.Iopp.VerifyOpening(openingPosition, proof.OpeningsQlQrQmQoQkincompletemp[3], vk.Qpp[3]) - if err != nil { - return err - } - err = vk.Iopp.VerifyOpening(openingPosition, proof.OpeningsQlQrQmQoQkincompletemp[4], vk.Qpp[4]) - if err != nil { - return err - } - - // l, r, o - err = vk.Iopp.VerifyOpening(openingPosition, proof.OpeningsLROmp[0], proof.LROpp[0]) - if err != nil { - return err - } - err = vk.Iopp.VerifyOpening(openingPosition, proof.OpeningsLROmp[1], proof.LROpp[1]) - if err != nil { - return err - } - err = vk.Iopp.VerifyOpening(openingPosition, proof.OpeningsLROmp[2], proof.LROpp[2]) - if err != nil { - return err - } - - // h0, h1, h2 - err = vk.Iopp.VerifyOpening(openingPosition, proof.OpeningsHmp[0], proof.Hpp[0]) - if err != nil { - return err - } - err = vk.Iopp.VerifyOpening(openingPosition, proof.OpeningsHmp[1], proof.Hpp[1]) - if err != nil { - return err - } - err = vk.Iopp.VerifyOpening(openingPosition, proof.OpeningsHmp[2], proof.Hpp[2]) - if err != nil { - return err - } - - // s0, s1, s2 - err = vk.Iopp.VerifyOpening(openingPosition, proof.OpeningsS1S2S3mp[0], vk.Spp[0]) - if err != nil { - return err - } - err = vk.Iopp.VerifyOpening(openingPosition, proof.OpeningsS1S2S3mp[1], vk.Spp[1]) - if err != nil { - return err - } - err = vk.Iopp.VerifyOpening(openingPosition, proof.OpeningsS1S2S3mp[2], vk.Spp[2]) - if err != nil { - return err - } - - // id0, id1, id2 - err = vk.Iopp.VerifyOpening(openingPosition, proof.OpeningsId1Id2Id3mp[0], vk.Idpp[0]) - if err != nil { - return err - } - err = vk.Iopp.VerifyOpening(openingPosition, proof.OpeningsId1Id2Id3mp[1], vk.Idpp[1]) - if err != nil { - return err - } - err = vk.Iopp.VerifyOpening(openingPosition, proof.OpeningsId1Id2Id3mp[2], vk.Idpp[2]) - if err != nil { - return err - } - - // Z, Zshift - err = vk.Iopp.VerifyOpening(openingPosition, proof.OpeningsZmp[0], proof.Zpp) - if err != nil { - return err - } - - // verification of the algebraic relation - var ql, qr, qm, qo, qk fr.Element - ql.Set(&proof.OpeningsQlQrQmQoQkincompletemp[0].ClaimedValue) - qr.Set(&proof.OpeningsQlQrQmQoQkincompletemp[1].ClaimedValue) - qm.Set(&proof.OpeningsQlQrQmQoQkincompletemp[2].ClaimedValue) - qo.Set(&proof.OpeningsQlQrQmQoQkincompletemp[3].ClaimedValue) - qk.Set(&proof.OpeningsQlQrQmQoQkincompletemp[4].ClaimedValue) // -> to be completed - - var l, r, o fr.Element - l.Set(&proof.OpeningsLROmp[0].ClaimedValue) - r.Set(&proof.OpeningsLROmp[1].ClaimedValue) - o.Set(&proof.OpeningsLROmp[2].ClaimedValue) - - var h1, h2, h3 fr.Element - h1.Set(&proof.OpeningsHmp[0].ClaimedValue) - h2.Set(&proof.OpeningsHmp[1].ClaimedValue) - h3.Set(&proof.OpeningsHmp[2].ClaimedValue) - - var s1, s2, s3 fr.Element - s1.Set(&proof.OpeningsS1S2S3mp[0].ClaimedValue) - s2.Set(&proof.OpeningsS1S2S3mp[1].ClaimedValue) - s3.Set(&proof.OpeningsS1S2S3mp[2].ClaimedValue) - - var id1, id2, id3 fr.Element - id1.Set(&proof.OpeningsId1Id2Id3mp[0].ClaimedValue) - id2.Set(&proof.OpeningsId1Id2Id3mp[1].ClaimedValue) - id3.Set(&proof.OpeningsId1Id2Id3mp[2].ClaimedValue) - - var z, zshift fr.Element - z.Set(&proof.OpeningsZmp[0].ClaimedValue) - zshift.Set(&proof.OpeningsZmp[1].ClaimedValue) - - // 2 - compute the LHS: (ql*l+..+qk)+ α*(z(μx)*(l+β*s₁+γ)*..-z*(l+β*id1+γ))+α²*z*(l1-1) - var zeta fr.Element - zeta.Exp(vk.GenOpening, &bOpeningPosition) - - var lhs, t1, t2, t3, tmp, tmp2 fr.Element - // 2.1 (ql*l+..+qk) - t1.Mul(&l, &ql) - tmp.Mul(&r, &qr) - t1.Add(&t1, &tmp) - tmp.Mul(&qm, &l).Mul(&tmp, &r) - t1.Add(&t1, &tmp) - tmp.Mul(&o, &qo) - t1.Add(&tmp, &t1) - tmp = completeQk(publicWitness, vk, zeta) - tmp.Add(&qk, &tmp) - t1.Add(&tmp, &t1) - - // 2.2 (z(ux)*(l+β*s1+γ)*..-z*(l+β*id1+γ)) - t2.Mul(&beta, &s1).Add(&t2, &l).Add(&t2, &gamma) - tmp.Mul(&beta, &s2).Add(&tmp, &r).Add(&tmp, &gamma) - t2.Mul(&tmp, &t2) - tmp.Mul(&beta, &s3).Add(&tmp, &o).Add(&tmp, &gamma) - t2.Mul(&tmp, &t2).Mul(&t2, &zshift) - - tmp.Mul(&beta, &id1).Add(&tmp, &l).Add(&tmp, &gamma) - tmp2.Mul(&beta, &id2).Add(&tmp2, &r).Add(&tmp2, &gamma) - tmp.Mul(&tmp, &tmp2) - tmp2.Mul(&beta, &id3).Add(&tmp2, &o).Add(&tmp2, &gamma) - tmp.Mul(&tmp2, &tmp).Mul(&tmp, &z) - - t2.Sub(&t2, &tmp) - - // 2.3 (z-1)*l1 - var one fr.Element - one.SetOne() - t3.Exp(zeta, big.NewInt(int64(vk.Size))).Sub(&t3, &one) - tmp.Sub(&zeta, &one).Inverse(&tmp).Mul(&tmp, &vk.SizeInv) - t3.Mul(&tmp, &t3) - tmp.Sub(&z, &one) - t3.Mul(&tmp, &t3) - - // 2.4 (ql*l+s+qk) + α*(z(ux)*(l+β*s1+γ)*...-z*(l+β*id1+γ)..)+ α²*z*(l1-1) - lhs.Set(&t3).Mul(&lhs, &alpha).Add(&lhs, &t2).Mul(&lhs, &alpha).Add(&lhs, &t1) - - // 3 - compute the RHS - var rhs fr.Element - tmp.Exp(zeta, big.NewInt(int64(vk.Size+2))) - rhs.Mul(&h3, &tmp). - Add(&rhs, &h2). - Mul(&rhs, &tmp). - Add(&rhs, &h1) - - tmp.Exp(zeta, big.NewInt(int64(vk.Size))).Sub(&tmp, &one) - rhs.Mul(&rhs, &tmp) - - // 4 - verify the relation LHS==RHS - if !rhs.Equal(&lhs) { - return ErrInvalidAlgebraicRelation - } - - return nil - -} - -// completeQk returns ∑_{i