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

     1  import (
     2  	"fmt"
     3  	"errors"
     4  	"math/big"
     5  
     6  	{{- template "import_fri" . }}
     7  	{{- template "import_fr" . }}
     8  	"github.com/consensys/gnark/backend"
     9      fiatshamir "github.com/consensys/gnark-crypto/fiat-shamir"
    10  )
    11  
    12  var ErrInvalidAlgebraicRelation = errors.New("algebraic relation does not hold")
    13  
    14  func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector, opts ...backend.VerifierOption) error {
    15  	cfg, err := backend.NewVerifierConfig(opts...)
    16  	if err != nil {
    17  		return fmt.Errorf("create backend config: %w", err)
    18  	}
    19  
    20  	// 0 - derive the challenges with Fiat Shamir
    21  	fs := fiatshamir.NewTranscript(cfg.ChallengeHash, "gamma", "beta", "alpha", "zeta")
    22  
    23  	dataFiatShamir := make([][fr.Bytes]byte, len(publicWitness)+3)
    24  	for i := 0; i < len(publicWitness); i++ {
    25  		copy(dataFiatShamir[i][:], publicWitness[i].Marshal())
    26  	}
    27  	copy(dataFiatShamir[len(publicWitness)][:], proof.LROpp[0].ID)
    28  	copy(dataFiatShamir[len(publicWitness)+1][:], proof.LROpp[1].ID)
    29  	copy(dataFiatShamir[len(publicWitness)+2][:], proof.LROpp[2].ID)
    30  
    31  	beta, err := deriveRandomnessFixedSize(fs, "gamma", dataFiatShamir...)
    32  	if err != nil {
    33  		return err
    34  	}
    35  
    36  	gamma, err := deriveRandomness(fs, "beta", nil)
    37  	if err != nil {
    38  		return err
    39  	}
    40  
    41  	alpha, err := deriveRandomness(fs, "alpha", proof.Zpp.ID)
    42  	if err != nil {
    43  		return err
    44  	}
    45  
    46  	// compute the size of the domain of evaluation of the committed polynomial,
    47  	// the opening position. The challenge zeta will be g^{i} where i is the opening
    48  	// position, and g is the generator of the fri domain.
    49  	rho := uint64(fri.GetRho())
    50  	friSize := 2 * rho * vk.Size
    51  	var bFriSize big.Int
    52  	bFriSize.SetInt64(int64(friSize))
    53  	frOpeningPosition, err := deriveRandomness(fs, "zeta", proof.Hpp[0].ID, proof.Hpp[1].ID, proof.Hpp[2].ID)
    54  	if err != nil {
    55  		return err
    56  	}
    57  	var bOpeningPosition big.Int
    58  	bOpeningPosition.SetBytes(frOpeningPosition.Marshal()).Mod(&bOpeningPosition, &bFriSize)
    59  	openingPosition := bOpeningPosition.Uint64()
    60  
    61  	shiftedOpeningPosition := (openingPosition + uint64(2*rho)) % friSize
    62  	err = vk.Iopp.VerifyOpening(shiftedOpeningPosition, proof.OpeningsZmp[1], proof.Zpp)
    63  	if err != nil {
    64  		return err
    65  	}
    66  
    67  	// 1 - verify that the commitments are low degree polynomials
    68  
    69  	// ql, qr, qm, qo, qkIncomplete
    70  	err = vk.Iopp.VerifyProofOfProximity(vk.Qpp[0])
    71  	if err != nil {
    72  		return err
    73  	}
    74  	err = vk.Iopp.VerifyProofOfProximity(vk.Qpp[1])
    75  	if err != nil {
    76  		return err
    77  	}
    78  	err = vk.Iopp.VerifyProofOfProximity(vk.Qpp[2])
    79  	if err != nil {
    80  		return err
    81  	}
    82  	err = vk.Iopp.VerifyProofOfProximity(vk.Qpp[3])
    83  	if err != nil {
    84  		return err
    85  	}
    86  	err = vk.Iopp.VerifyProofOfProximity(vk.Qpp[4])
    87  	if err != nil {
    88  		return err
    89  	}
    90  
    91  	// l, r, o
    92  	err = vk.Iopp.VerifyProofOfProximity(proof.LROpp[0])
    93  	if err != nil {
    94  		return err
    95  	}
    96  	err = vk.Iopp.VerifyProofOfProximity(proof.LROpp[1])
    97  	if err != nil {
    98  		return err
    99  	}
   100  	err = vk.Iopp.VerifyProofOfProximity(proof.LROpp[2])
   101  	if err != nil {
   102  		return err
   103  	}
   104  	err = vk.Iopp.VerifyProofOfProximity(proof.Zpp)
   105  	if err != nil {
   106  		return err
   107  	}
   108  
   109  	// h0, h1, h2
   110  	err = vk.Iopp.VerifyProofOfProximity(proof.Hpp[0])
   111  	if err != nil {
   112  		return err
   113  	}
   114  	err = vk.Iopp.VerifyProofOfProximity(proof.Hpp[1])
   115  	if err != nil {
   116  		return err
   117  	}
   118  	err = vk.Iopp.VerifyProofOfProximity(proof.Hpp[2])
   119  	if err != nil {
   120  		return err
   121  	}
   122  
   123  	// s1, s2, s3
   124  	err = vk.Iopp.VerifyProofOfProximity(vk.Spp[0])
   125  	if err != nil {
   126  		return err
   127  	}
   128  	err = vk.Iopp.VerifyProofOfProximity(vk.Spp[1])
   129  	if err != nil {
   130  		return err
   131  	}
   132  	err = vk.Iopp.VerifyProofOfProximity(vk.Spp[2])
   133  	if err != nil {
   134  		return err
   135  	}
   136  
   137  	// id1, id2, id3
   138  	err = vk.Iopp.VerifyProofOfProximity(vk.Idpp[0])
   139  	if err != nil {
   140  		return err
   141  	}
   142  	err = vk.Iopp.VerifyProofOfProximity(vk.Idpp[1])
   143  	if err != nil {
   144  		return err
   145  	}
   146  	err = vk.Iopp.VerifyProofOfProximity(vk.Idpp[2])
   147  	if err != nil {
   148  		return err
   149  	}
   150  
   151  	// Z
   152  	err = vk.Iopp.VerifyProofOfProximity(proof.Zpp)
   153  	if err != nil {
   154  		return err
   155  	}
   156  
   157  	// 2 - verify the openings
   158  
   159  	// ql, qr, qm, qo, qkIncomplete
   160  	// openingPosition := uint64(2)
   161  	err = vk.Iopp.VerifyOpening(openingPosition, proof.OpeningsQlQrQmQoQkincompletemp[0], vk.Qpp[0])
   162  	if err != nil {
   163  		return err
   164  	}
   165  	err = vk.Iopp.VerifyOpening(openingPosition, proof.OpeningsQlQrQmQoQkincompletemp[1], vk.Qpp[1])
   166  	if err != nil {
   167  		return err
   168  	}
   169  	err = vk.Iopp.VerifyOpening(openingPosition, proof.OpeningsQlQrQmQoQkincompletemp[2], vk.Qpp[2])
   170  	if err != nil {
   171  		return err
   172  	}
   173  	err = vk.Iopp.VerifyOpening(openingPosition, proof.OpeningsQlQrQmQoQkincompletemp[3], vk.Qpp[3])
   174  	if err != nil {
   175  		return err
   176  	}
   177  	err = vk.Iopp.VerifyOpening(openingPosition, proof.OpeningsQlQrQmQoQkincompletemp[4], vk.Qpp[4])
   178  	if err != nil {
   179  		return err
   180  	}
   181  
   182  	// l, r, o
   183  	err = vk.Iopp.VerifyOpening(openingPosition, proof.OpeningsLROmp[0], proof.LROpp[0])
   184  	if err != nil {
   185  		return err
   186  	}
   187  	err = vk.Iopp.VerifyOpening(openingPosition, proof.OpeningsLROmp[1], proof.LROpp[1])
   188  	if err != nil {
   189  		return err
   190  	}
   191  	err = vk.Iopp.VerifyOpening(openingPosition, proof.OpeningsLROmp[2], proof.LROpp[2])
   192  	if err != nil {
   193  		return err
   194  	}
   195  
   196  	// h0, h1, h2
   197  	err = vk.Iopp.VerifyOpening(openingPosition, proof.OpeningsHmp[0], proof.Hpp[0])
   198  	if err != nil {
   199  		return err
   200  	}
   201  	err = vk.Iopp.VerifyOpening(openingPosition, proof.OpeningsHmp[1], proof.Hpp[1])
   202  	if err != nil {
   203  		return err
   204  	}
   205  	err = vk.Iopp.VerifyOpening(openingPosition, proof.OpeningsHmp[2], proof.Hpp[2])
   206  	if err != nil {
   207  		return err
   208  	}
   209  
   210  	// s0, s1, s2
   211  	err = vk.Iopp.VerifyOpening(openingPosition, proof.OpeningsS1S2S3mp[0], vk.Spp[0])
   212  	if err != nil {
   213  		return err
   214  	}
   215  	err = vk.Iopp.VerifyOpening(openingPosition, proof.OpeningsS1S2S3mp[1], vk.Spp[1])
   216  	if err != nil {
   217  		return err
   218  	}
   219  	err = vk.Iopp.VerifyOpening(openingPosition, proof.OpeningsS1S2S3mp[2], vk.Spp[2])
   220  	if err != nil {
   221  		return err
   222  	}
   223  
   224  	// id0, id1, id2
   225  	err = vk.Iopp.VerifyOpening(openingPosition, proof.OpeningsId1Id2Id3mp[0], vk.Idpp[0])
   226  	if err != nil {
   227  		return err
   228  	}
   229  	err = vk.Iopp.VerifyOpening(openingPosition, proof.OpeningsId1Id2Id3mp[1], vk.Idpp[1])
   230  	if err != nil {
   231  		return err
   232  	}
   233  	err = vk.Iopp.VerifyOpening(openingPosition, proof.OpeningsId1Id2Id3mp[2], vk.Idpp[2])
   234  	if err != nil {
   235  		return err
   236  	}
   237  
   238  	// Z, Zshift
   239  	err = vk.Iopp.VerifyOpening(openingPosition, proof.OpeningsZmp[0], proof.Zpp)
   240  	if err != nil {
   241  		return err
   242  	}
   243  
   244  	// verification of the algebraic relation
   245  	var ql, qr, qm, qo, qk fr.Element
   246  	ql.Set(&proof.OpeningsQlQrQmQoQkincompletemp[0].ClaimedValue)
   247  	qr.Set(&proof.OpeningsQlQrQmQoQkincompletemp[1].ClaimedValue)
   248  	qm.Set(&proof.OpeningsQlQrQmQoQkincompletemp[2].ClaimedValue)
   249  	qo.Set(&proof.OpeningsQlQrQmQoQkincompletemp[3].ClaimedValue)
   250  	qk.Set(&proof.OpeningsQlQrQmQoQkincompletemp[4].ClaimedValue) // -> to be completed
   251  
   252  	var l, r, o fr.Element
   253  	l.Set(&proof.OpeningsLROmp[0].ClaimedValue)
   254  	r.Set(&proof.OpeningsLROmp[1].ClaimedValue)
   255  	o.Set(&proof.OpeningsLROmp[2].ClaimedValue)
   256  
   257  	var h1, h2, h3 fr.Element
   258  	h1.Set(&proof.OpeningsHmp[0].ClaimedValue)
   259  	h2.Set(&proof.OpeningsHmp[1].ClaimedValue)
   260  	h3.Set(&proof.OpeningsHmp[2].ClaimedValue)
   261  
   262  	var s1, s2, s3 fr.Element
   263  	s1.Set(&proof.OpeningsS1S2S3mp[0].ClaimedValue)
   264  	s2.Set(&proof.OpeningsS1S2S3mp[1].ClaimedValue)
   265  	s3.Set(&proof.OpeningsS1S2S3mp[2].ClaimedValue)
   266  
   267  	var id1, id2, id3 fr.Element
   268  	id1.Set(&proof.OpeningsId1Id2Id3mp[0].ClaimedValue)
   269  	id2.Set(&proof.OpeningsId1Id2Id3mp[1].ClaimedValue)
   270  	id3.Set(&proof.OpeningsId1Id2Id3mp[2].ClaimedValue)
   271  
   272  	var z, zshift fr.Element
   273  	z.Set(&proof.OpeningsZmp[0].ClaimedValue)
   274  	zshift.Set(&proof.OpeningsZmp[1].ClaimedValue)
   275  
   276  	// 2 - compute the LHS: (ql*l+..+qk)+ α*(z(μx)*(l+β*s₁+γ)*..-z*(l+β*id1+γ))+α²*z*(l1-1)
   277  	var zeta fr.Element
   278  	zeta.Exp(vk.GenOpening, &bOpeningPosition)
   279  
   280  	var lhs, t1, t2, t3, tmp, tmp2 fr.Element
   281  	// 2.1 (ql*l+..+qk)
   282  	t1.Mul(&l, &ql)
   283  	tmp.Mul(&r, &qr)
   284  	t1.Add(&t1, &tmp)
   285  	tmp.Mul(&qm, &l).Mul(&tmp, &r)
   286  	t1.Add(&t1, &tmp)
   287  	tmp.Mul(&o, &qo)
   288  	t1.Add(&tmp, &t1)
   289  	tmp = completeQk(publicWitness, vk, zeta)
   290  	tmp.Add(&qk, &tmp)
   291  	t1.Add(&tmp, &t1)
   292  
   293  	// 2.2 (z(ux)*(l+β*s1+γ)*..-z*(l+β*id1+γ))
   294  	t2.Mul(&beta, &s1).Add(&t2, &l).Add(&t2, &gamma)
   295  	tmp.Mul(&beta, &s2).Add(&tmp, &r).Add(&tmp, &gamma)
   296  	t2.Mul(&tmp, &t2)
   297  	tmp.Mul(&beta, &s3).Add(&tmp, &o).Add(&tmp, &gamma)
   298  	t2.Mul(&tmp, &t2).Mul(&t2, &zshift)
   299  
   300  	tmp.Mul(&beta, &id1).Add(&tmp, &l).Add(&tmp, &gamma)
   301  	tmp2.Mul(&beta, &id2).Add(&tmp2, &r).Add(&tmp2, &gamma)
   302  	tmp.Mul(&tmp, &tmp2)
   303  	tmp2.Mul(&beta, &id3).Add(&tmp2, &o).Add(&tmp2, &gamma)
   304  	tmp.Mul(&tmp2, &tmp).Mul(&tmp, &z)
   305  
   306  	t2.Sub(&t2, &tmp)
   307  
   308  	// 2.3 (z-1)*l1
   309  	var one fr.Element
   310  	one.SetOne()
   311  	t3.Exp(zeta, big.NewInt(int64(vk.Size))).Sub(&t3, &one)
   312  	tmp.Sub(&zeta, &one).Inverse(&tmp).Mul(&tmp, &vk.SizeInv)
   313  	t3.Mul(&tmp, &t3)
   314  	tmp.Sub(&z, &one)
   315  	t3.Mul(&tmp, &t3)
   316  
   317  	// 2.4 (ql*l+s+qk) + α*(z(ux)*(l+β*s1+γ)*...-z*(l+β*id1+γ)..)+ α²*z*(l1-1)
   318  	lhs.Set(&t3).Mul(&lhs, &alpha).Add(&lhs, &t2).Mul(&lhs, &alpha).Add(&lhs, &t1)
   319  
   320  	// 3 - compute the RHS
   321  	var rhs fr.Element
   322  	tmp.Exp(zeta, big.NewInt(int64(vk.Size+2)))
   323  	rhs.Mul(&h3, &tmp).
   324  		Add(&rhs, &h2).
   325  		Mul(&rhs, &tmp).
   326  		Add(&rhs, &h1)
   327  
   328  	tmp.Exp(zeta, big.NewInt(int64(vk.Size))).Sub(&tmp, &one)
   329  	rhs.Mul(&rhs, &tmp)
   330  
   331  	// 4 - verify the relation LHS==RHS
   332  	if !rhs.Equal(&lhs) {
   333  		return ErrInvalidAlgebraicRelation
   334  	}
   335  
   336  	return nil
   337  
   338  }
   339  
   340  // completeQk returns ∑_{i<nb_public_inputs}w_i*L_i
   341  func completeQk(publicWitness []fr.Element, vk *VerifyingKey, zeta fr.Element) fr.Element {
   342  
   343  	var res fr.Element
   344  
   345  	// compute l1(zeta). Exceptional case: if zeta=1, then l1(zeta)=1,
   346  	// we need to manually initialise l to this value otherwise there
   347  	// is a denominator equal to zero in the formula.
   348  	var l, tmp, acc, one fr.Element
   349  	one.SetOne()
   350  	acc.SetOne()
   351  	l.Sub(&zeta, &one)
   352  	if l.IsZero() {
   353  		l.SetOne()
   354  	} else {
   355  		l.Inverse(&l).Mul(&l, &vk.SizeInv)
   356  		tmp.Exp(zeta, big.NewInt(int64(vk.Size))).Sub(&tmp, &one)
   357  		l.Mul(&l, &tmp)
   358  	}
   359  
   360  	// use L_i+1 = w*Li*(X-z**i)/(X-z**i+1)
   361  	for i := 0; i < len(publicWitness); i++ {
   362  
   363  		tmp.Mul(&l, &publicWitness[i])
   364  		res.Add(&res, &tmp)
   365  
   366  		tmp.Sub(&zeta, &acc)
   367  		l.Mul(&l, &tmp).Mul(&l, &vk.Generator)
   368  		acc.Mul(&acc, &vk.Generator)
   369  		tmp.Sub(&zeta, &acc)
   370  		// if tmp==0, then zeta=vk.Generator**i, so l_i(zeta)=1. We need
   371  		// to manually set the value to 1, exacty as in the case l_0 before
   372  		// the loop, otherwise the generic formula leads to a division by zero.
   373  		if tmp.IsZero() {
   374  			l.SetOne()
   375  		} else {
   376  			l.Div(&l, &tmp)
   377  		}
   378  	}
   379  
   380  	return res
   381  }