arnaucube
arnaucube/gnark-plonky2-verifierPublic Self-hosted repository
gnark-plonky2-verifier/field/quadratic_extension.go
field/quadratic_extension.goRaw
  1package field
  2
  3import (
  4	"fmt"
  5	"math/bits"
  6
  7	"github.com/consensys/gnark-crypto/field/goldilocks"
  8	"github.com/consensys/gnark/frontend"
  9)
 10
 11type QuadraticExtensionAPI struct {
 12	fieldAPI frontend.API
 13
 14	W        F
 15	DTH_ROOT F
 16
 17	ONE_QE  QuadraticExtension
 18	ZERO_QE QuadraticExtension
 19
 20	ZERO_QE_ALGEBRA QEAlgebra
 21}
 22
 23func NewQuadraticExtensionAPI(fieldAPI frontend.API, degreeBits uint64) *QuadraticExtensionAPI {
 24	// TODO:  Should degreeBits be verified that it fits within the field and that degree is within uint64?
 25
 26	var ZERO_QE = QuadraticExtension{ZERO_F, ZERO_F}
 27
 28	var ZERO_QE_ALGEBRA QEAlgebra
 29
 30	for i := 0; i < D; i++ {
 31		ZERO_QE_ALGEBRA[i] = ZERO_QE
 32	}
 33
 34	return &QuadraticExtensionAPI{
 35		fieldAPI: fieldAPI,
 36
 37		W:        NewFieldElement(7),
 38		DTH_ROOT: NewFieldElement(18446744069414584320),
 39
 40		ONE_QE:  QuadraticExtension{ONE_F, ZERO_F},
 41		ZERO_QE: ZERO_QE,
 42
 43		ZERO_QE_ALGEBRA: ZERO_QE_ALGEBRA,
 44	}
 45}
 46
 47func (c *QuadraticExtensionAPI) SquareExtension(a QuadraticExtension) QuadraticExtension {
 48	return c.MulExtension(a, a)
 49}
 50
 51func (c *QuadraticExtensionAPI) MulExtension(a QuadraticExtension, b QuadraticExtension) QuadraticExtension {
 52	c_0 := c.fieldAPI.Add(c.fieldAPI.Mul(a[0], b[0]).(F), c.fieldAPI.Mul(c.W, a[1], b[1])).(F)
 53	c_1 := c.fieldAPI.Add(c.fieldAPI.Mul(a[0], b[1]).(F), c.fieldAPI.Mul(a[1], b[0])).(F)
 54	return QuadraticExtension{c_0, c_1}
 55}
 56
 57func (c *QuadraticExtensionAPI) AddExtension(a QuadraticExtension, b QuadraticExtension) QuadraticExtension {
 58	c_0 := c.fieldAPI.Add(a[0], b[0]).(F)
 59	c_1 := c.fieldAPI.Add(a[1], b[1]).(F)
 60	return QuadraticExtension{c_0, c_1}
 61}
 62
 63func (c *QuadraticExtensionAPI) SubExtension(a QuadraticExtension, b QuadraticExtension) QuadraticExtension {
 64	c_0 := c.fieldAPI.Sub(a[0], b[0]).(F)
 65	c_1 := c.fieldAPI.Sub(a[1], b[1]).(F)
 66	return QuadraticExtension{c_0, c_1}
 67}
 68
 69func (c *QuadraticExtensionAPI) DivExtension(a QuadraticExtension, b QuadraticExtension) QuadraticExtension {
 70	return c.MulExtension(a, c.InverseExtension(b))
 71}
 72
 73func (c *QuadraticExtensionAPI) IsZero(a QuadraticExtension) frontend.Variable {
 74	return c.fieldAPI.Mul(c.fieldAPI.IsZero(a[0]), c.fieldAPI.IsZero(a[1]))
 75}
 76
 77// TODO: Instead of calculating the inverse within the circuit, can witness the
 78// inverse and assert that a_inverse * a = 1.  Should reduce # of constraints.
 79func (c *QuadraticExtensionAPI) InverseExtension(a QuadraticExtension) QuadraticExtension {
 80	// First assert that a doesn't have 0 value coefficients
 81	a0_is_zero := c.fieldAPI.IsZero(a[0])
 82	a1_is_zero := c.fieldAPI.IsZero(a[1])
 83
 84	// assert that a0_is_zero OR a1_is_zero == false
 85	c.fieldAPI.AssertIsEqual(c.fieldAPI.Mul(a0_is_zero, a1_is_zero).(F), ZERO_F)
 86
 87	a_pow_r_minus_1 := QuadraticExtension{a[0], c.fieldAPI.Mul(a[1], c.DTH_ROOT).(F)}
 88	a_pow_r := c.MulExtension(a_pow_r_minus_1, a)
 89	return c.ScalarMulExtension(a_pow_r_minus_1, c.fieldAPI.Inverse(a_pow_r[0]).(F))
 90}
 91
 92func (c *QuadraticExtensionAPI) ScalarMulExtension(a QuadraticExtension, scalar F) QuadraticExtension {
 93	return QuadraticExtension{c.fieldAPI.Mul(a[0], scalar).(F), c.fieldAPI.Mul(a[1], scalar).(F)}
 94}
 95
 96func (c *QuadraticExtensionAPI) FieldToQE(a F) QuadraticExtension {
 97	return QuadraticExtension{a, ZERO_F}
 98}
 99
100// / Exponentiate `base` to the power of a known `exponent`.
101func (c *QuadraticExtensionAPI) ExpU64Extension(a QuadraticExtension, exponent uint64) QuadraticExtension {
102	switch exponent {
103	case 0:
104		return c.ONE_QE
105	case 1:
106		return a
107	case 2:
108		return c.SquareExtension(a)
109	default:
110	}
111
112	current := a
113	product := c.ONE_QE
114
115	for i := 0; i < bits.Len64(exponent); i++ {
116		if i != 0 {
117			current = c.SquareExtension(current)
118		}
119
120		if (exponent >> i & 1) != 0 {
121			product = c.MulExtension(product, current)
122		}
123	}
124
125	return product
126}
127
128func (c *QuadraticExtensionAPI) ReduceWithPowers(terms []QuadraticExtension, scalar QuadraticExtension) QuadraticExtension {
129	sum := c.ZERO_QE
130
131	for i := len(terms) - 1; i >= 0; i-- {
132		sum = c.AddExtension(
133			c.MulExtension(
134				sum,
135				scalar,
136			),
137			terms[i],
138		)
139	}
140
141	return sum
142}
143
144func (c *QuadraticExtensionAPI) Select(b frontend.Variable, qe0, qe1 QuadraticExtension) QuadraticExtension {
145	var retQE QuadraticExtension
146
147	for i := 0; i < 2; i++ {
148		retQE[i] = c.fieldAPI.Select(b, qe0[i], qe1[i]).(F)
149	}
150
151	return retQE
152}
153
154func (c *QuadraticExtensionAPI) Lookup2(b0 frontend.Variable, b1 frontend.Variable, qe0, qe1, qe2, qe3 QuadraticExtension) QuadraticExtension {
155	var retQE QuadraticExtension
156
157	for i := 0; i < 2; i++ {
158		retQE[i] = c.fieldAPI.Lookup2(b0, b1, qe0[i], qe1[i], qe2[i], qe3[i]).(F)
159	}
160
161	return retQE
162}
163
164func (c *QuadraticExtensionAPI) AssertIsEqual(a, b QuadraticExtension) {
165	for i := 0; i < 2; i++ {
166		c.fieldAPI.AssertIsEqual(a[i], b[i])
167	}
168}
169
170func (c *QuadraticExtensionAPI) InnerProductExtension(constant F, startingAcc QuadraticExtension, pairs [][2]QuadraticExtension) QuadraticExtension {
171	acc := startingAcc
172
173	for i := 0; i < len(pairs); i++ {
174		a := pairs[i][0]
175		b := pairs[i][1]
176		mul := c.ScalarMulExtension(a, constant)
177		mul = c.MulExtension(mul, b)
178		acc = c.AddExtension(acc, mul)
179	}
180
181	return acc
182}
183
184func (c *QuadraticExtensionAPI) Println(a QuadraticExtension) {
185	fmt.Print("Degree 0 coefficient")
186	c.fieldAPI.Println(a[0])
187
188	fmt.Print("Degree 1 coefficient")
189	c.fieldAPI.Println(a[1])
190}
191
192func (c *QuadraticExtensionAPI) MulExtensionAlgebra(a, b QEAlgebra) QEAlgebra {
193	var inner [D][][2]QuadraticExtension
194	var inner_w [D][][2]QuadraticExtension
195	for i := 0; i < D; i++ {
196		for j := 0; j < D-i; j++ {
197			idx := (i + j) % D
198			inner[idx] = append(inner[idx], [2]QuadraticExtension{a[i], b[j]})
199		}
200		for j := D - i; j < D; j++ {
201			idx := (i + j) % D
202			inner_w[idx] = append(inner_w[idx], [2]QuadraticExtension{a[i], b[j]})
203		}
204	}
205
206	var product QEAlgebra
207	for i := 0; i < D; i++ {
208		acc := c.InnerProductExtension(NewFieldElement(7), c.ZERO_QE, inner_w[i])
209		product[i] = c.InnerProductExtension(ONE_F, acc, inner[i])
210	}
211
212	return product
213}
214
215func (c *QuadraticExtensionAPI) ScalarMulExtensionAlgebra(a QuadraticExtension, b QEAlgebra) QEAlgebra {
216	var product QEAlgebra
217	for i := 0; i < D; i++ {
218		product[i] = c.MulExtension(a, b[i])
219	}
220
221	return product
222}
223
224func (c *QuadraticExtensionAPI) AddExtensionAlgebra(a, b QEAlgebra) QEAlgebra {
225	var sum QEAlgebra
226	for i := 0; i < D; i++ {
227		sum[i] = c.AddExtension(a[i], b[i])
228	}
229
230	return sum
231}
232
233func (c *QuadraticExtensionAPI) SubExtensionAlgebra(a, b QEAlgebra) QEAlgebra {
234	var diff QEAlgebra
235	for i := 0; i < D; i++ {
236		diff[i] = c.SubExtension(a[i], b[i])
237	}
238
239	return diff
240}
241
242func (c *QuadraticExtensionAPI) PartialInterpolateExtAlgebra(
243	domain []goldilocks.Element,
244	values []QEAlgebra,
245	barycentricWeights []goldilocks.Element,
246	point QEAlgebra,
247	initialEval QEAlgebra,
248	initialPartialProd QEAlgebra,
249) (QEAlgebra, QEAlgebra) {
250	n := len(values)
251	if n == 0 {
252		panic("Cannot interpolate with no values")
253	}
254	if n != len(domain) {
255		panic("Domain and values must have the same length")
256	}
257	if n != len(barycentricWeights) {
258		panic("Domain and barycentric weights must have the same length")
259	}
260
261	newEval := initialEval
262	newPartialProd := initialPartialProd
263	for i := 0; i < n; i++ {
264		val := values[i]
265		x := domain[i]
266		xField := NewFieldElement(x.Uint64())
267		xQE := QuadraticExtension{xField, ZERO_F}
268		xQEAlgebra := QEAlgebra{xQE, c.ZERO_QE}
269		weight := QuadraticExtension{NewFieldElement(barycentricWeights[i].Uint64()), ZERO_F}
270		term := c.SubExtensionAlgebra(point, xQEAlgebra)
271		weightedVal := c.ScalarMulExtensionAlgebra(weight, val)
272		newEval = c.MulExtensionAlgebra(newEval, term)
273		tmp := c.MulExtensionAlgebra(weightedVal, newPartialProd)
274		newEval = c.AddExtensionAlgebra(newEval, tmp)
275		newPartialProd = c.MulExtensionAlgebra(newPartialProd, term)
276	}
277
278	return newEval, newPartialProd
279}