github.com/consensys/gnark@v0.11.0/backend/plonk/bls24-317/setup.go (about)

     1  // Copyright 2020 ConsenSys Software Inc.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  // Code generated by gnark DO NOT EDIT
    16  
    17  package plonk
    18  
    19  import (
    20  	"fmt"
    21  	"github.com/consensys/gnark-crypto/ecc/bls24-317/fr"
    22  	"github.com/consensys/gnark-crypto/ecc/bls24-317/fr/fft"
    23  	"github.com/consensys/gnark-crypto/ecc/bls24-317/fr/iop"
    24  	"github.com/consensys/gnark-crypto/ecc/bls24-317/kzg"
    25  	"github.com/consensys/gnark/backend/plonk/internal"
    26  	"github.com/consensys/gnark/constraint"
    27  	cs "github.com/consensys/gnark/constraint/bls24-317"
    28  )
    29  
    30  // VerifyingKey stores the data needed to verify a proof:
    31  // * The commitment scheme
    32  // * Commitments of ql prepended with as many ones as there are public inputs
    33  // * Commitments of qr, qm, qo, qk prepended with as many zeroes as there are public inputs
    34  // * Commitments to S1, S2, S3
    35  type VerifyingKey struct {
    36  	// Size circuit
    37  	Size              uint64
    38  	SizeInv           fr.Element
    39  	Generator         fr.Element
    40  	NbPublicVariables uint64
    41  
    42  	// Commitment scheme that is used for an instantiation of PLONK
    43  	Kzg kzg.VerifyingKey
    44  
    45  	// cosetShift generator of the coset on the small domain
    46  	CosetShift fr.Element
    47  
    48  	// S commitments to S1, S2, S3
    49  	S [3]kzg.Digest
    50  
    51  	// Commitments to ql, qr, qm, qo, qcp prepended with as many zeroes (ones for l) as there are public inputs.
    52  	// In particular Qk is not complete.
    53  	Ql, Qr, Qm, Qo, Qk kzg.Digest
    54  	Qcp                []kzg.Digest
    55  
    56  	CommitmentConstraintIndexes []uint64
    57  }
    58  
    59  // Trace stores a plonk trace as columns
    60  type Trace struct {
    61  	// Constants describing a plonk circuit. The first entries
    62  	// of LQk (whose index correspond to the public inputs) are set to 0, and are to be
    63  	// completed by the prover. At those indices i (so from 0 to nb_public_variables), LQl[i]=-1
    64  	// so the first nb_public_variables constraints look like this:
    65  	// -1*Wire[i] + 0* + 0 . It is zero when the constant coefficient is replaced by Wire[i].
    66  	Ql, Qr, Qm, Qo, Qk *iop.Polynomial
    67  	Qcp                []*iop.Polynomial
    68  
    69  	// Polynomials representing the splitted permutation. The full permutation's support is 3*N where N=nb wires.
    70  	// The set of interpolation is <g> of size N, so to represent the permutation S we let S acts on the
    71  	// set A=(<g>, u*<g>, u^{2}*<g>) of size 3*N, where u is outside <g> (its use is to shift the set <g>).
    72  	// We obtain a permutation of A, A'. We split A' in 3 (A'_{1}, A'_{2}, A'_{3}), and S1, S2, S3 are
    73  	// respectively the interpolation of A'_{1}, A'_{2}, A'_{3} on <g>.
    74  	S1, S2, S3 *iop.Polynomial
    75  
    76  	// S full permutation, i -> S[i]
    77  	S []int64
    78  }
    79  
    80  // ProvingKey stores the data needed to generate a proof
    81  type ProvingKey struct {
    82  	Kzg, KzgLagrange kzg.ProvingKey
    83  
    84  	// Verifying Key is embedded into the proving key (needed by Prove)
    85  	Vk *VerifyingKey
    86  }
    87  
    88  func Setup(spr *cs.SparseR1CS, srs, srsLagrange kzg.SRS) (*ProvingKey, *VerifyingKey, error) {
    89  
    90  	var pk ProvingKey
    91  	var vk VerifyingKey
    92  	pk.Vk = &vk
    93  	vk.CommitmentConstraintIndexes = internal.IntSliceToUint64Slice(spr.CommitmentInfo.CommitmentIndexes())
    94  
    95  	// step 0: set the fft domains
    96  	domain := initFFTDomain(spr)
    97  	if domain.Cardinality < 2 {
    98  		return nil, nil, fmt.Errorf("circuit has only %d constraints; unsupported by the current implementation", len(spr.Public)+spr.GetNbConstraints())
    99  	}
   100  
   101  	// check the size of the kzg srs.
   102  	if len(srs.Pk.G1) < (int(domain.Cardinality) + 3) { // + 3 for the kzg.Open of blinded poly
   103  		return nil, nil, fmt.Errorf("kzg srs is too small: got %d, need %d", len(srs.Pk.G1), domain.Cardinality+3)
   104  	}
   105  
   106  	// same for the lagrange form
   107  	if len(srsLagrange.Pk.G1) != int(domain.Cardinality) {
   108  		return nil, nil, fmt.Errorf("kzg srs lagrange is too small: got %d, need %d", len(srsLagrange.Pk.G1), domain.Cardinality)
   109  	}
   110  
   111  	// step 1: set the verifying key
   112  	vk.CosetShift.Set(&domain.FrMultiplicativeGen)
   113  	vk.Size = domain.Cardinality
   114  	vk.SizeInv.SetUint64(vk.Size).Inverse(&vk.SizeInv)
   115  	vk.Generator.Set(&domain.Generator)
   116  	vk.NbPublicVariables = uint64(len(spr.Public))
   117  
   118  	pk.Kzg.G1 = srs.Pk.G1[:int(vk.Size)+3]
   119  	pk.KzgLagrange.G1 = srsLagrange.Pk.G1
   120  	vk.Kzg = srs.Vk
   121  
   122  	// step 2: ql, qr, qm, qo, qk, qcp in Lagrange Basis
   123  	// step 3: build the permutation and build the polynomials S1, S2, S3 to encode the permutation.
   124  	// Note: at this stage, the permutation takes in account the placeholders
   125  	trace := NewTrace(spr, domain)
   126  
   127  	// step 4: commit to s1, s2, s3, ql, qr, qm, qo, and (the incomplete version of) qk.
   128  	// All the above polynomials are expressed in canonical basis afterwards. This is why
   129  	// we save lqk before, because the prover needs to complete it in Lagrange form, and
   130  	// then express it on the Lagrange coset basis.
   131  	if err := vk.commitTrace(trace, domain, pk.KzgLagrange); err != nil {
   132  		return nil, nil, err
   133  	}
   134  
   135  	return &pk, &vk, nil
   136  }
   137  
   138  // NbPublicWitness returns the expected public witness size (number of field elements)
   139  func (vk *VerifyingKey) NbPublicWitness() int {
   140  	return int(vk.NbPublicVariables)
   141  }
   142  
   143  // VerifyingKey returns pk.Vk
   144  func (pk *ProvingKey) VerifyingKey() interface{} {
   145  	return pk.Vk
   146  }
   147  
   148  // NewTrace returns a new Trace object from the constraint system.
   149  // It fills the constant columns ql, qr, qm, qo, qk, and qcp with the
   150  // coefficients of the constraints.
   151  // Size is the size of the system that is next power of 2 (nb_constraints+nb_public_variables)
   152  // The permutation is also computed and stored in the Trace.
   153  func NewTrace(spr *cs.SparseR1CS, domain *fft.Domain) *Trace {
   154  	var trace Trace
   155  
   156  	size := int(domain.Cardinality)
   157  	commitmentInfo := spr.CommitmentInfo.(constraint.PlonkCommitments)
   158  
   159  	ql := make([]fr.Element, size)
   160  	qr := make([]fr.Element, size)
   161  	qm := make([]fr.Element, size)
   162  	qo := make([]fr.Element, size)
   163  	qk := make([]fr.Element, size)
   164  	qcp := make([][]fr.Element, len(commitmentInfo))
   165  
   166  	for i := 0; i < len(spr.Public); i++ { // placeholders (-PUB_INPUT_i + qk_i = 0) TODO should return error if size is inconsistent
   167  		ql[i].SetOne().Neg(&ql[i])
   168  		qr[i].SetZero()
   169  		qm[i].SetZero()
   170  		qo[i].SetZero()
   171  		qk[i].SetZero() // → to be completed by the prover
   172  	}
   173  	offset := len(spr.Public)
   174  
   175  	j := 0
   176  	it := spr.GetSparseR1CIterator()
   177  	for c := it.Next(); c != nil; c = it.Next() {
   178  		ql[offset+j].Set(&spr.Coefficients[c.QL])
   179  		qr[offset+j].Set(&spr.Coefficients[c.QR])
   180  		qm[offset+j].Set(&spr.Coefficients[c.QM])
   181  		qo[offset+j].Set(&spr.Coefficients[c.QO])
   182  		qk[offset+j].Set(&spr.Coefficients[c.QC])
   183  		j++
   184  	}
   185  
   186  	lagReg := iop.Form{Basis: iop.Lagrange, Layout: iop.Regular}
   187  
   188  	trace.Ql = iop.NewPolynomial(&ql, lagReg)
   189  	trace.Qr = iop.NewPolynomial(&qr, lagReg)
   190  	trace.Qm = iop.NewPolynomial(&qm, lagReg)
   191  	trace.Qo = iop.NewPolynomial(&qo, lagReg)
   192  	trace.Qk = iop.NewPolynomial(&qk, lagReg)
   193  	trace.Qcp = make([]*iop.Polynomial, len(qcp))
   194  
   195  	for i := range commitmentInfo {
   196  		qcp[i] = make([]fr.Element, size)
   197  		for _, committed := range commitmentInfo[i].Committed {
   198  			qcp[i][offset+committed].SetOne()
   199  		}
   200  		trace.Qcp[i] = iop.NewPolynomial(&qcp[i], lagReg)
   201  	}
   202  
   203  	// build the permutation and build the polynomials S1, S2, S3 to encode the permutation.
   204  	// Note: at this stage, the permutation takes in account the placeholders
   205  	nbVariables := spr.NbInternalVariables + len(spr.Public) + len(spr.Secret)
   206  	buildPermutation(spr, &trace, nbVariables)
   207  	s := computePermutationPolynomials(&trace, domain)
   208  	trace.S1 = s[0]
   209  	trace.S2 = s[1]
   210  	trace.S3 = s[2]
   211  
   212  	return &trace
   213  }
   214  
   215  // commitTrace commits to every polynomial in the trace, and put
   216  // the commitments int the verifying key.
   217  func (vk *VerifyingKey) commitTrace(trace *Trace, domain *fft.Domain, srsPk kzg.ProvingKey) error {
   218  
   219  	var err error
   220  	vk.Qcp = make([]kzg.Digest, len(trace.Qcp))
   221  	for i := range trace.Qcp {
   222  		if vk.Qcp[i], err = kzg.Commit(trace.Qcp[i].Coefficients(), srsPk); err != nil {
   223  			return err
   224  		}
   225  	}
   226  	if vk.Ql, err = kzg.Commit(trace.Ql.Coefficients(), srsPk); err != nil {
   227  		return err
   228  	}
   229  	if vk.Qr, err = kzg.Commit(trace.Qr.Coefficients(), srsPk); err != nil {
   230  		return err
   231  	}
   232  	if vk.Qm, err = kzg.Commit(trace.Qm.Coefficients(), srsPk); err != nil {
   233  		return err
   234  	}
   235  	if vk.Qo, err = kzg.Commit(trace.Qo.Coefficients(), srsPk); err != nil {
   236  		return err
   237  	}
   238  	if vk.Qk, err = kzg.Commit(trace.Qk.Coefficients(), srsPk); err != nil {
   239  		return err
   240  	}
   241  	if vk.S[0], err = kzg.Commit(trace.S1.Coefficients(), srsPk); err != nil {
   242  		return err
   243  	}
   244  	if vk.S[1], err = kzg.Commit(trace.S2.Coefficients(), srsPk); err != nil {
   245  		return err
   246  	}
   247  	if vk.S[2], err = kzg.Commit(trace.S3.Coefficients(), srsPk); err != nil {
   248  		return err
   249  	}
   250  	return nil
   251  }
   252  
   253  func initFFTDomain(spr *cs.SparseR1CS) *fft.Domain {
   254  	nbConstraints := spr.GetNbConstraints()
   255  	sizeSystem := uint64(nbConstraints + len(spr.Public)) // len(spr.Public) is for the placeholder constraints
   256  	return fft.NewDomain(sizeSystem, fft.WithoutPrecompute())
   257  }
   258  
   259  // buildPermutation builds the Permutation associated with a circuit.
   260  //
   261  // The permutation s is composed of cycles of maximum length such that
   262  //
   263  //	s. (l∥r∥o) = (l∥r∥o)
   264  //
   265  // , where l∥r∥o is the concatenation of the indices of l, r, o in
   266  // ql.l+qr.r+qm.l.r+qo.O+k = 0.
   267  //
   268  // The permutation is encoded as a slice s of size 3*size(l), where the
   269  // i-th entry of l∥r∥o is sent to the s[i]-th entry, so it acts on a tab
   270  // like this: for i in tab: tab[i] = tab[permutation[i]]
   271  func buildPermutation(spr *cs.SparseR1CS, trace *Trace, nbVariables int) {
   272  
   273  	// nbVariables := spr.NbInternalVariables + len(spr.Public) + len(spr.Secret)
   274  	sizeSolution := len(trace.Ql.Coefficients())
   275  	sizePermutation := 3 * sizeSolution
   276  
   277  	// init permutation
   278  	permutation := make([]int64, sizePermutation)
   279  	for i := 0; i < len(permutation); i++ {
   280  		permutation[i] = -1
   281  	}
   282  
   283  	// init LRO position -> variable_ID
   284  	lro := make([]int, sizePermutation) // position -> variable_ID
   285  	for i := 0; i < len(spr.Public); i++ {
   286  		lro[i] = i // IDs of LRO associated to placeholders (only L needs to be taken care of)
   287  	}
   288  
   289  	offset := len(spr.Public)
   290  
   291  	j := 0
   292  	it := spr.GetSparseR1CIterator()
   293  	for c := it.Next(); c != nil; c = it.Next() {
   294  		lro[offset+j] = int(c.XA)
   295  		lro[sizeSolution+offset+j] = int(c.XB)
   296  		lro[2*sizeSolution+offset+j] = int(c.XC)
   297  
   298  		j++
   299  	}
   300  
   301  	// init cycle:
   302  	// map ID -> last position the ID was seen
   303  	cycle := make([]int64, nbVariables)
   304  	for i := 0; i < len(cycle); i++ {
   305  		cycle[i] = -1
   306  	}
   307  
   308  	for i := 0; i < len(lro); i++ {
   309  		if cycle[lro[i]] != -1 {
   310  			// if != -1, it means we already encountered this value
   311  			// so we need to set the corresponding permutation index.
   312  			permutation[i] = cycle[lro[i]]
   313  		}
   314  		cycle[lro[i]] = int64(i)
   315  	}
   316  
   317  	// complete the Permutation by filling the first IDs encountered
   318  	for i := 0; i < sizePermutation; i++ {
   319  		if permutation[i] == -1 {
   320  			permutation[i] = cycle[lro[i]]
   321  		}
   322  	}
   323  
   324  	trace.S = permutation
   325  }
   326  
   327  // computePermutationPolynomials computes the LDE (Lagrange basis) of the permutation.
   328  // We let the permutation act on <g> || u<g> || u^{2}<g>, split the result in 3 parts,
   329  // and interpolate each of the 3 parts on <g>.
   330  func computePermutationPolynomials(trace *Trace, domain *fft.Domain) [3]*iop.Polynomial {
   331  
   332  	nbElmts := int(domain.Cardinality)
   333  
   334  	var res [3]*iop.Polynomial
   335  
   336  	// Lagrange form of ID
   337  	evaluationIDSmallDomain := getSupportPermutation(domain)
   338  
   339  	// Lagrange form of S1, S2, S3
   340  	s1Canonical := make([]fr.Element, nbElmts)
   341  	s2Canonical := make([]fr.Element, nbElmts)
   342  	s3Canonical := make([]fr.Element, nbElmts)
   343  	for i := 0; i < nbElmts; i++ {
   344  		s1Canonical[i].Set(&evaluationIDSmallDomain[trace.S[i]])
   345  		s2Canonical[i].Set(&evaluationIDSmallDomain[trace.S[nbElmts+i]])
   346  		s3Canonical[i].Set(&evaluationIDSmallDomain[trace.S[2*nbElmts+i]])
   347  	}
   348  
   349  	lagReg := iop.Form{Basis: iop.Lagrange, Layout: iop.Regular}
   350  	res[0] = iop.NewPolynomial(&s1Canonical, lagReg)
   351  	res[1] = iop.NewPolynomial(&s2Canonical, lagReg)
   352  	res[2] = iop.NewPolynomial(&s3Canonical, lagReg)
   353  
   354  	return res
   355  }
   356  
   357  // getSupportPermutation returns the support on which the permutation acts, it is
   358  // <g> || u<g> || u^{2}<g>
   359  func getSupportPermutation(domain *fft.Domain) []fr.Element {
   360  
   361  	res := make([]fr.Element, 3*domain.Cardinality)
   362  
   363  	res[0].SetOne()
   364  	res[domain.Cardinality].Set(&domain.FrMultiplicativeGen)
   365  	res[2*domain.Cardinality].Square(&domain.FrMultiplicativeGen)
   366  
   367  	for i := uint64(1); i < domain.Cardinality; i++ {
   368  		res[i].Mul(&res[i-1], &domain.Generator)
   369  		res[domain.Cardinality+i].Mul(&res[domain.Cardinality+i-1], &domain.Generator)
   370  		res[2*domain.Cardinality+i].Mul(&res[2*domain.Cardinality+i-1], &domain.Generator)
   371  	}
   372  
   373  	return res
   374  }