github.com/consensys/gnark@v0.11.0/internal/generator/backend/template/zkpschemes/plonkfri/plonk.setup.go.tmpl (about)

     1  import (
     2  	"crypto/sha256"
     3  
     4  
     5  	{{- template "import_fri" . }}
     6  	{{- template "import_fr" . }}
     7  	{{- template "import_fft" . }}
     8  	{{- template "import_backend_cs" . }}
     9  )
    10  
    11  // ProvingKey stores the data needed to generate a proof:
    12  // * the commitment scheme
    13  // * ql, prepended with as many ones as they are public inputs
    14  // * qr, qm, qo prepended with as many zeroes as there are public inputs.
    15  // * qk, prepended with as many zeroes as public inputs, to be completed by the prover
    16  // with the list of public inputs.
    17  // * sigma_1, sigma_2, sigma_3 in both basis
    18  // * the copy constraint permutation
    19  type ProvingKey struct {
    20  
    21  	// Verifying Key is embedded into the proving key (needed by Prove)
    22  	Vk *VerifyingKey
    23  
    24  	// qr,ql,qm,qo and Qk incomplete (Ls=Lagrange basis big domain, L=Lagrange basis small domain, C=canonical basis)
    25  	EvaluationQlDomainBigBitReversed  []fr.Element
    26  	EvaluationQrDomainBigBitReversed  []fr.Element
    27  	EvaluationQmDomainBigBitReversed  []fr.Element
    28  	EvaluationQoDomainBigBitReversed  []fr.Element
    29  	LQkIncompleteDomainSmall          []fr.Element
    30  	CQl, CQr, CQm, CQo, CQkIncomplete []fr.Element
    31  
    32  	// Domains used for the FFTs
    33  	// 0 -> "small" domain, used for individual polynomials
    34  	// 1 -> "big" domain, used for the computation of the quotient
    35  	Domain [2]fft.Domain
    36  
    37  	// s1, s2, s3 (L=Lagrange basis small domain, C=canonical basis, Ls=Lagrange Shifted big domain)
    38  	LId                                                                    []fr.Element
    39  	EvaluationId1BigDomain, EvaluationId2BigDomain, EvaluationId3BigDomain []fr.Element
    40  	EvaluationS1BigDomain, EvaluationS2BigDomain, EvaluationS3BigDomain    []fr.Element
    41  
    42  	// position -> permuted position (position in [0,3*sizeSystem-1])
    43  	Permutation []int64
    44  }
    45  
    46  // VerifyingKey stores the data needed to verify a proof:
    47  // * The commitment scheme
    48  // * Commitments of ql prepended with as many ones as there are public inputs
    49  // * Commitments of qr, qm, qo, qk prepended with as many zeroes as there are public inputs
    50  // * Commitments to S1, S2, S3
    51  type VerifyingKey struct {
    52  
    53  	// Size circuit, that is the closest power of 2 bounding above
    54  	// number of constraints+number of public inputs
    55  	Size              uint64
    56  	SizeInv           fr.Element
    57  	Generator         fr.Element
    58  	NbPublicVariables uint64
    59  
    60  	// cosetShift generator of the coset on the small domain
    61  	CosetShift fr.Element
    62  
    63  	// S commitments to S1, S2, S3
    64  	SCanonical [3][]fr.Element
    65  	Spp        [3]fri.ProofOfProximity
    66  
    67  	// Id commitments to Id1, Id2, Id3
    68  	// Id   [3]Commitment
    69  	IdCanonical [3][]fr.Element
    70  	Idpp        [3]fri.ProofOfProximity
    71  
    72  	// Commitments to ql, qr, qm, qo prepended with as many zeroes (ones for l) as there are public inputs.
    73  	// In particular Qk is not complete.
    74  	Qpp [5]fri.ProofOfProximity // Ql, Qr, Qm, Qo, Qk
    75  
    76  	// Iopp scheme (currently one for each size of polynomial)
    77  	Iopp fri.Iopp
    78  
    79  	// generator of the group on which the Iopp works. If i is the opening position,
    80  	// the polynomials will be opened at genOpening^{i}.
    81  	GenOpening fr.Element
    82  }
    83  
    84  // Setup sets proving and verifying keys
    85  func Setup(spr *cs.SparseR1CS) (*ProvingKey, *VerifyingKey, error) {
    86  
    87  	var pk ProvingKey
    88  	var vk VerifyingKey
    89  
    90  	// The verifying key shares data with the proving key
    91  	pk.Vk = &vk
    92  
    93  	nbConstraints := spr.GetNbConstraints()
    94  
    95  	// fft domains
    96  	sizeSystem := uint64(nbConstraints + len(spr.Public)) // len(spr.Public) is for the placeholder constraints
    97  	pk.Domain[0] = *fft.NewDomain(sizeSystem)
    98  
    99  	// h, the quotient polynomial is of degree 3(n+1)+2, so it's in a 3(n+2) dim vector space,
   100  	// the domain is the next power of 2 superior to 3(n+2). 4*domainNum is enough in all cases
   101  	// except when n<6.
   102  	if sizeSystem < 6 {
   103  		pk.Domain[1] = *fft.NewDomain(8 * sizeSystem)
   104  	} else {
   105  		pk.Domain[1] = *fft.NewDomain(4 * sizeSystem)
   106  	}
   107  	pk.Vk.CosetShift.Set(&pk.Domain[0].FrMultiplicativeGen)
   108  
   109  	vk.Size = pk.Domain[0].Cardinality
   110  	vk.SizeInv.SetUint64(vk.Size).Inverse(&vk.SizeInv)
   111  	vk.Generator.Set(&pk.Domain[0].Generator)
   112  	vk.NbPublicVariables = uint64(len(spr.Public))
   113  
   114  	// IOP schemess
   115  	// The +2 is to handle the blinding.
   116  	sizeIopp := pk.Domain[0].Cardinality + 2
   117  	vk.Iopp = fri.RADIX_2_FRI.New(sizeIopp, sha256.New())
   118  	// only there to access the group used in FRI...
   119  	rho := uint64(fri.GetRho())
   120  	// we multiply by 2 because the IOP is created with size pk.Domain[0].Cardinality + 2 (because
   121  	// of the blinding), so the domain will be rho*size_domain where size_domain is the next power
   122  	// of 2 after pk.Domain[0].Cardinality + 2, which is 2*rho*pk.Domain[0].Cardinality
   123  	tmpDomain := fft.NewDomain(2 * rho * pk.Domain[0].Cardinality)
   124  	vk.GenOpening.Set(&tmpDomain.Generator)
   125  
   126  	// public polynomials corresponding to constraints: [ placholders | constraints | assertions ]
   127  	pk.EvaluationQlDomainBigBitReversed = make([]fr.Element, pk.Domain[1].Cardinality)
   128  	pk.EvaluationQrDomainBigBitReversed = make([]fr.Element, pk.Domain[1].Cardinality)
   129  	pk.EvaluationQmDomainBigBitReversed = make([]fr.Element, pk.Domain[1].Cardinality)
   130  	pk.EvaluationQoDomainBigBitReversed = make([]fr.Element, pk.Domain[1].Cardinality)
   131  	pk.LQkIncompleteDomainSmall = make([]fr.Element, pk.Domain[0].Cardinality)
   132  	pk.CQkIncomplete = make([]fr.Element, pk.Domain[0].Cardinality)
   133  
   134  	for i := 0; i < len(spr.Public); i++ { // placeholders (-PUB_INPUT_i + qk_i = 0) TODO should return error if size is inconsistent
   135  		pk.EvaluationQlDomainBigBitReversed[i].SetOne().Neg(&pk.EvaluationQlDomainBigBitReversed[i])
   136  		pk.EvaluationQrDomainBigBitReversed[i].SetZero()
   137  		pk.EvaluationQmDomainBigBitReversed[i].SetZero()
   138  		pk.EvaluationQoDomainBigBitReversed[i].SetZero()
   139  		pk.LQkIncompleteDomainSmall[i].SetZero()                 // --> to be completed by the prover
   140  		pk.CQkIncomplete[i].Set(&pk.LQkIncompleteDomainSmall[i]) // --> to be completed by the prover
   141  	}
   142  	offset := len(spr.Public)
   143  
   144  	j := 0
   145  	it := spr.GetSparseR1CIterator()
   146  	for c := it.Next(); c!=nil; c = it.Next() {
   147  		pk.EvaluationQlDomainBigBitReversed[offset+j].Set(&spr.Coefficients[c.QL])
   148  		pk.EvaluationQrDomainBigBitReversed[offset+j].Set(&spr.Coefficients[c.QR])
   149  		pk.EvaluationQmDomainBigBitReversed[offset+j].Set(&spr.Coefficients[c.QM])
   150  		pk.EvaluationQoDomainBigBitReversed[offset+j].Set(&spr.Coefficients[c.QO])
   151  		pk.LQkIncompleteDomainSmall[offset+j].Set(&spr.Coefficients[c.QC])
   152  		pk.CQkIncomplete[offset+j].Set(&pk.LQkIncompleteDomainSmall[offset+j])
   153  
   154  		j++
   155  	}
   156  
   157  
   158  	pk.Domain[0].FFTInverse(pk.EvaluationQlDomainBigBitReversed[:pk.Domain[0].Cardinality], fft.DIF)
   159  	pk.Domain[0].FFTInverse(pk.EvaluationQrDomainBigBitReversed[:pk.Domain[0].Cardinality], fft.DIF)
   160  	pk.Domain[0].FFTInverse(pk.EvaluationQmDomainBigBitReversed[:pk.Domain[0].Cardinality], fft.DIF)
   161  	pk.Domain[0].FFTInverse(pk.EvaluationQoDomainBigBitReversed[:pk.Domain[0].Cardinality], fft.DIF)
   162  	pk.Domain[0].FFTInverse(pk.CQkIncomplete, fft.DIF)
   163  	fft.BitReverse(pk.EvaluationQlDomainBigBitReversed[:pk.Domain[0].Cardinality])
   164  	fft.BitReverse(pk.EvaluationQrDomainBigBitReversed[:pk.Domain[0].Cardinality])
   165  	fft.BitReverse(pk.EvaluationQmDomainBigBitReversed[:pk.Domain[0].Cardinality])
   166  	fft.BitReverse(pk.EvaluationQoDomainBigBitReversed[:pk.Domain[0].Cardinality])
   167  	fft.BitReverse(pk.CQkIncomplete)
   168  
   169  	// Commit to the polynomials to set up the verifying key
   170  	pk.CQl = make([]fr.Element, pk.Domain[0].Cardinality)
   171  	pk.CQr = make([]fr.Element, pk.Domain[0].Cardinality)
   172  	pk.CQm = make([]fr.Element, pk.Domain[0].Cardinality)
   173  	pk.CQo = make([]fr.Element, pk.Domain[0].Cardinality)
   174  	copy(pk.CQl, pk.EvaluationQlDomainBigBitReversed)
   175  	copy(pk.CQr, pk.EvaluationQrDomainBigBitReversed)
   176  	copy(pk.CQm, pk.EvaluationQmDomainBigBitReversed)
   177  	copy(pk.CQo, pk.EvaluationQoDomainBigBitReversed)
   178  	var err error
   179  	vk.Qpp[0], err = vk.Iopp.BuildProofOfProximity(pk.CQl)
   180  	if err != nil {
   181  		return &pk, &vk, err
   182  	}
   183  	vk.Qpp[1], err = vk.Iopp.BuildProofOfProximity(pk.CQr)
   184  	if err != nil {
   185  		return &pk, &vk, err
   186  	}
   187  	vk.Qpp[2], err = vk.Iopp.BuildProofOfProximity(pk.CQm)
   188  	if err != nil {
   189  		return &pk, &vk, err
   190  	}
   191  	vk.Qpp[3], err = vk.Iopp.BuildProofOfProximity(pk.CQo)
   192  	if err != nil {
   193  		return &pk, &vk, err
   194  	}
   195  	vk.Qpp[4], err = vk.Iopp.BuildProofOfProximity(pk.CQkIncomplete)
   196  	if err != nil {
   197  		return &pk, &vk, err
   198  	}
   199  
   200  	pk.Domain[1].FFT(pk.EvaluationQlDomainBigBitReversed, fft.DIF, fft.OnCoset())
   201  	pk.Domain[1].FFT(pk.EvaluationQrDomainBigBitReversed, fft.DIF, fft.OnCoset())
   202  	pk.Domain[1].FFT(pk.EvaluationQmDomainBigBitReversed, fft.DIF, fft.OnCoset())
   203  	pk.Domain[1].FFT(pk.EvaluationQoDomainBigBitReversed, fft.DIF, fft.OnCoset())
   204  
   205  	// build permutation. Note: at this stage, the permutation takes in account the placeholders
   206  	buildPermutation(spr, &pk)
   207  
   208  	// set s1, s2, s3
   209  	err = computePermutationPolynomials(&pk, &vk)
   210  	if err != nil {
   211  		return &pk, &vk, err
   212  	}
   213  
   214  	return &pk, &vk, nil
   215  
   216  }
   217  
   218  // buildPermutation builds the Permutation associated with a circuit.
   219  //
   220  // The permutation s is composed of cycles of maximum length such that
   221  //
   222  // 			s. (l||r||o) = (l||r||o)
   223  //
   224  //, where l||r||o is the concatenation of the indices of l, r, o in
   225  // ql.l+qr.r+qm.l.r+qo.O+k = 0.
   226  //
   227  // The permutation is encoded as a slice s of size 3*size(l), where the
   228  // i-th entry of l||r||o is sent to the s[i]-th entry, so it acts on a tab
   229  // like this: for i in tab: tab[i] = tab[permutation[i]]
   230  func buildPermutation(spr *cs.SparseR1CS, pk *ProvingKey) {
   231  
   232  	nbVariables := spr.NbInternalVariables + len(spr.Public) + len(spr.Secret)
   233  	sizeSolution := int(pk.Domain[0].Cardinality)
   234  
   235  	// init permutation
   236  	pk.Permutation = make([]int64, 3*sizeSolution)
   237  	for i := 0; i < len(pk.Permutation); i++ {
   238  		pk.Permutation[i] = -1
   239  	}
   240  
   241  	// init LRO position -> variable_ID
   242  	lro := make([]int, 3*sizeSolution) // position -> variable_ID
   243  	for i := 0; i < len(spr.Public); i++ {
   244  		lro[i] = i // IDs of LRO associated to placeholders (only L needs to be taken care of)
   245  	}
   246  
   247  	offset := len(spr.Public)
   248  
   249  	j := 0
   250  	it := spr.GetSparseR1CIterator()
   251  	for c := it.Next(); c!=nil; c = it.Next() {
   252  		lro[offset+j] = int(c.XA)
   253  		lro[sizeSolution+offset+j] = int(c.XB)
   254  		lro[2*sizeSolution+offset+j] = int(c.XC)
   255  		j++
   256  	}
   257  
   258  	// init cycle:
   259  	// map ID -> last position the ID was seen
   260  	cycle := make([]int64, nbVariables)
   261  	for i := 0; i < len(cycle); i++ {
   262  		cycle[i] = -1
   263  	}
   264  
   265  	for i := 0; i < len(lro); i++ {
   266  		if cycle[lro[i]] != -1 {
   267  			// if != -1, it means we already encountered this value
   268  			// so we need to set the corresponding permutation index.
   269  			pk.Permutation[i] = cycle[lro[i]]
   270  		}
   271  		cycle[lro[i]] = int64(i)
   272  	}
   273  
   274  	// complete the Permutation by filling the first IDs encountered
   275  	for i := 0; i < len(pk.Permutation); i++ {
   276  		if pk.Permutation[i] == -1 {
   277  			pk.Permutation[i] = cycle[lro[i]]
   278  		}
   279  	}
   280  }
   281  
   282  // computePermutationPolynomials computes the LDE (Lagrange basis) of the permutations
   283  // s1, s2, s3.
   284  //
   285  // 0	1 	..	n-1		|	n	n+1	..	2*n-1		|	2n		2n+1	..		3n-1     |
   286  //  																					 |
   287  //        																				 | Permutation
   288  // s00  s01 ..   s0n-1	   s10 s11 	 ..		s1n-1 		s20 	s21 	..		s2n-1	 v
   289  // \---------------/       \--------------------/        \------------------------/
   290  // 		s1 (LDE)                s2 (LDE)                          s3 (LDE)
   291  func computePermutationPolynomials(pk *ProvingKey, vk *VerifyingKey) error {
   292  
   293  	nbElmt := int(pk.Domain[0].Cardinality)
   294  
   295  	// sID = [1,..,g^{n-1},s,..,s*g^{n-1},s^2,..,s^2*g^{n-1}]
   296  	pk.LId = getIDSmallDomain(&pk.Domain[0])
   297  
   298  	// canonical form of S1, S2, S3
   299  	pk.EvaluationS1BigDomain = make([]fr.Element, pk.Domain[1].Cardinality)
   300  	pk.EvaluationS2BigDomain = make([]fr.Element, pk.Domain[1].Cardinality)
   301  	pk.EvaluationS3BigDomain = make([]fr.Element, pk.Domain[1].Cardinality)
   302  	for i := 0; i < nbElmt; i++ {
   303  		pk.EvaluationS1BigDomain[i].Set(&pk.LId[pk.Permutation[i]])
   304  		pk.EvaluationS2BigDomain[i].Set(&pk.LId[pk.Permutation[nbElmt+i]])
   305  		pk.EvaluationS3BigDomain[i].Set(&pk.LId[pk.Permutation[2*nbElmt+i]])
   306  	}
   307  
   308  	// Evaluations of Sid1, Sid2, Sid3 on cosets of Domain[1]
   309  	pk.EvaluationId1BigDomain = make([]fr.Element, pk.Domain[1].Cardinality)
   310  	pk.EvaluationId2BigDomain = make([]fr.Element, pk.Domain[1].Cardinality)
   311  	pk.EvaluationId3BigDomain = make([]fr.Element, pk.Domain[1].Cardinality)
   312  	copy(pk.EvaluationId1BigDomain, pk.LId[:nbElmt])
   313  	copy(pk.EvaluationId2BigDomain, pk.LId[nbElmt:2*nbElmt])
   314  	copy(pk.EvaluationId3BigDomain, pk.LId[2*nbElmt:])
   315  	pk.Domain[0].FFTInverse(pk.EvaluationId1BigDomain[:pk.Domain[0].Cardinality], fft.DIF)
   316  	pk.Domain[0].FFTInverse(pk.EvaluationId2BigDomain[:pk.Domain[0].Cardinality], fft.DIF)
   317  	pk.Domain[0].FFTInverse(pk.EvaluationId3BigDomain[:pk.Domain[0].Cardinality], fft.DIF)
   318  	fft.BitReverse(pk.EvaluationId1BigDomain[:pk.Domain[0].Cardinality])
   319  	fft.BitReverse(pk.EvaluationId2BigDomain[:pk.Domain[0].Cardinality])
   320  	fft.BitReverse(pk.EvaluationId3BigDomain[:pk.Domain[0].Cardinality])
   321  	vk.IdCanonical[0] = make([]fr.Element, pk.Domain[0].Cardinality)
   322  	vk.IdCanonical[1] = make([]fr.Element, pk.Domain[0].Cardinality)
   323  	vk.IdCanonical[2] = make([]fr.Element, pk.Domain[0].Cardinality)
   324  	copy(vk.IdCanonical[0], pk.EvaluationId1BigDomain)
   325  	copy(vk.IdCanonical[1], pk.EvaluationId2BigDomain)
   326  	copy(vk.IdCanonical[2], pk.EvaluationId3BigDomain)
   327  
   328  	var err error
   329  	vk.Idpp[0], err = vk.Iopp.BuildProofOfProximity(pk.EvaluationId1BigDomain)
   330  	if err != nil {
   331  		return err
   332  	}
   333  	vk.Idpp[1], err = vk.Iopp.BuildProofOfProximity(pk.EvaluationId2BigDomain)
   334  	if err != nil {
   335  		return err
   336  	}
   337  	vk.Idpp[2], err = vk.Iopp.BuildProofOfProximity(pk.EvaluationId3BigDomain)
   338  	if err != nil {
   339  		return err
   340  	}
   341  	pk.Domain[1].FFT(pk.EvaluationId1BigDomain, fft.DIF, fft.OnCoset())
   342  	pk.Domain[1].FFT(pk.EvaluationId2BigDomain, fft.DIF, fft.OnCoset())
   343  	pk.Domain[1].FFT(pk.EvaluationId3BigDomain, fft.DIF, fft.OnCoset())
   344  
   345  	pk.Domain[0].FFTInverse(pk.EvaluationS1BigDomain[:pk.Domain[0].Cardinality], fft.DIF)
   346  	pk.Domain[0].FFTInverse(pk.EvaluationS2BigDomain[:pk.Domain[0].Cardinality], fft.DIF)
   347  	pk.Domain[0].FFTInverse(pk.EvaluationS3BigDomain[:pk.Domain[0].Cardinality], fft.DIF)
   348  	fft.BitReverse(pk.EvaluationS1BigDomain[:pk.Domain[0].Cardinality])
   349  	fft.BitReverse(pk.EvaluationS2BigDomain[:pk.Domain[0].Cardinality])
   350  	fft.BitReverse(pk.EvaluationS3BigDomain[:pk.Domain[0].Cardinality])
   351  
   352  	// commit S1, S2, S3
   353  	vk.SCanonical[0] = make([]fr.Element, pk.Domain[0].Cardinality)
   354  	vk.SCanonical[1] = make([]fr.Element, pk.Domain[0].Cardinality)
   355  	vk.SCanonical[2] = make([]fr.Element, pk.Domain[0].Cardinality)
   356  	copy(vk.SCanonical[0], pk.EvaluationS1BigDomain[:pk.Domain[0].Cardinality])
   357  	copy(vk.SCanonical[1], pk.EvaluationS2BigDomain[:pk.Domain[0].Cardinality])
   358  	copy(vk.SCanonical[2], pk.EvaluationS3BigDomain[:pk.Domain[0].Cardinality])
   359  	vk.Spp[0], err = vk.Iopp.BuildProofOfProximity(vk.SCanonical[0])
   360  	if err != nil {
   361  		return err
   362  	}
   363  	vk.Spp[1], err = vk.Iopp.BuildProofOfProximity(vk.SCanonical[1])
   364  	if err != nil {
   365  		return err
   366  	}
   367  	vk.Spp[2], err = vk.Iopp.BuildProofOfProximity(vk.SCanonical[2])
   368  	if err != nil {
   369  		return err
   370  	}
   371  	pk.Domain[1].FFT(pk.EvaluationS1BigDomain, fft.DIF, fft.OnCoset())
   372  	pk.Domain[1].FFT(pk.EvaluationS2BigDomain, fft.DIF, fft.OnCoset())
   373  	pk.Domain[1].FFT(pk.EvaluationS3BigDomain, fft.DIF, fft.OnCoset())
   374  
   375  	return nil
   376  
   377  }
   378  
   379  // getIDSmallDomain returns the Lagrange form of ID on the small domain
   380  func getIDSmallDomain(domain *fft.Domain) []fr.Element {
   381  
   382  	res := make([]fr.Element, 3*domain.Cardinality)
   383  
   384  	res[0].SetOne()
   385  	res[domain.Cardinality].Set(&domain.FrMultiplicativeGen)
   386  	res[2*domain.Cardinality].Square(&domain.FrMultiplicativeGen)
   387  
   388  	for i := uint64(1); i < domain.Cardinality; i++ {
   389  		res[i].Mul(&res[i-1], &domain.Generator)
   390  		res[domain.Cardinality+i].Mul(&res[domain.Cardinality+i-1], &domain.Generator)
   391  		res[2*domain.Cardinality+i].Mul(&res[2*domain.Cardinality+i-1], &domain.Generator)
   392  	}
   393  
   394  	return res
   395  }
   396  
   397  // NbPublicWitness returns the expected public witness size (number of field elements)
   398  func (vk *VerifyingKey) NbPublicWitness() int {
   399  	return int(vk.NbPublicVariables)
   400  }
   401  
   402  // VerifyingKey returns pk.Vk
   403  func (pk *ProvingKey) VerifyingKey() interface{} {
   404  	return pk.Vk
   405  }