arnaucube
arnaucube/gnark-plonky2-verifierPublic Self-hosted repository
gnark-plonky2-verifier/goldilocks/quadratic_extension.go
goldilocks/quadratic_extension.goRaw
  1package goldilocks
  2
  3import (
  4	"math/bits"
  5
  6	"github.com/consensys/gnark/frontend"
  7)
  8
  9const W uint64 = 7
 10const DTH_ROOT uint64 = 18446744069414584320
 11
 12type QuadraticExtensionVariable [2]Variable
 13
 14func NewQuadraticExtensionVariable(x Variable, y Variable) QuadraticExtensionVariable {
 15	return QuadraticExtensionVariable{x, y}
 16}
 17
 18func (p Variable) ToQuadraticExtension() QuadraticExtensionVariable {
 19	return NewQuadraticExtensionVariable(p, Zero())
 20}
 21
 22func ZeroExtension() QuadraticExtensionVariable {
 23	return Zero().ToQuadraticExtension()
 24}
 25
 26func OneExtension() QuadraticExtensionVariable {
 27	return One().ToQuadraticExtension()
 28}
 29
 30// Adds two quadratic extension variables in the Goldilocks field.
 31func (p *Chip) AddExtension(a, b QuadraticExtensionVariable) QuadraticExtensionVariable {
 32	c0 := p.Add(a[0], b[0])
 33	c1 := p.Add(a[1], b[1])
 34	return NewQuadraticExtensionVariable(c0, c1)
 35}
 36
 37// Adds two quadratic extension variables in the Goldilocks field without reducing.
 38func (p *Chip) AddExtensionNoReduce(a, b QuadraticExtensionVariable) QuadraticExtensionVariable {
 39	c0 := p.AddNoReduce(a[0], b[0])
 40	c1 := p.AddNoReduce(a[1], b[1])
 41	return NewQuadraticExtensionVariable(c0, c1)
 42}
 43
 44// Subtracts two quadratic extension variables in the Goldilocks field.
 45func (p *Chip) SubExtension(a, b QuadraticExtensionVariable) QuadraticExtensionVariable {
 46	c0 := p.Sub(a[0], b[0])
 47	c1 := p.Sub(a[1], b[1])
 48	return NewQuadraticExtensionVariable(c0, c1)
 49}
 50
 51// Subtracts two quadratic extension variables in the Goldilocks field without reducing.
 52func (p *Chip) SubExtensionNoReduce(a, b QuadraticExtensionVariable) QuadraticExtensionVariable {
 53	c0 := p.SubNoReduce(a[0], b[0])
 54	c1 := p.SubNoReduce(a[1], b[1])
 55	return NewQuadraticExtensionVariable(c0, c1)
 56}
 57
 58// Multiplies quadratic extension variable in the Goldilocks field.
 59func (p *Chip) MulExtension(a, b QuadraticExtensionVariable) QuadraticExtensionVariable {
 60	product := p.MulExtensionNoReduce(a, b)
 61	return p.ReduceExtension(product)
 62}
 63
 64// Multiplies quadratic extension variable in the Goldilocks field without reducing.
 65func (p *Chip) MulExtensionNoReduce(a, b QuadraticExtensionVariable) QuadraticExtensionVariable {
 66	c0o0 := p.MulNoReduce(a[0], b[0])
 67	c0o1 := p.MulNoReduce(p.MulNoReduce(NewVariable(W), a[1]), b[1])
 68	c0 := p.AddNoReduce(c0o0, c0o1)
 69	c1 := p.AddNoReduce(p.MulNoReduce(a[0], b[1]), p.MulNoReduce(a[1], b[0]))
 70	return NewQuadraticExtensionVariable(c0, c1)
 71}
 72
 73// Multiplies two operands a and b and adds to c in the Goldilocks extension field. a * b + c must
 74// be less than RANGE_CHECK_NB_BITS bits.
 75func (p *Chip) MulAddExtension(a, b, c QuadraticExtensionVariable) QuadraticExtensionVariable {
 76	product := p.MulExtensionNoReduce(a, b)
 77	sum := p.AddExtensionNoReduce(product, c)
 78	return p.ReduceExtension(sum)
 79}
 80
 81func (p *Chip) MulAddExtensionNoReduce(a, b, c QuadraticExtensionVariable) QuadraticExtensionVariable {
 82	product := p.MulExtensionNoReduce(a, b)
 83	sum := p.AddExtensionNoReduce(product, c)
 84	return sum
 85}
 86
 87// Multiplies two operands a and b and subtracts to c in the Goldilocks extension field. a * b - c must
 88// be less than RANGE_CHECK_NB_BITS bits.
 89func (p *Chip) SubMulExtension(a, b, c QuadraticExtensionVariable) QuadraticExtensionVariable {
 90	difference := p.SubExtensionNoReduce(a, b)
 91	product := p.MulExtensionNoReduce(difference, c)
 92	return p.ReduceExtension(product)
 93}
 94
 95// Multiplies quadratic extension variable in the Goldilocks field by a scalar.
 96func (p *Chip) ScalarMulExtension(
 97	a QuadraticExtensionVariable,
 98	b Variable,
 99) QuadraticExtensionVariable {
100	return NewQuadraticExtensionVariable(
101		p.Mul(a[0], b),
102		p.Mul(a[1], b),
103	)
104}
105
106// Computes an inner product over quadratic extension variable vectors in the Goldilocks field.
107func (p *Chip) InnerProductExtension(
108	constant Variable,
109	startingAcc QuadraticExtensionVariable,
110	pairs [][2]QuadraticExtensionVariable,
111) QuadraticExtensionVariable {
112	acc := startingAcc
113	for i := 0; i < len(pairs); i++ {
114		a := pairs[i][0]
115		b := pairs[i][1]
116		mul := p.ScalarMulExtension(a, constant)
117		acc = p.MulAddExtensionNoReduce(mul, b, acc)
118	}
119	return p.ReduceExtension(acc)
120}
121
122// Computes the inverse of a quadratic extension variable in the Goldilocks field.
123func (p *Chip) InverseExtension(a QuadraticExtensionVariable) (QuadraticExtensionVariable, frontend.Variable) {
124	aIsZero := p.IsZero(a)
125	p.api.AssertIsEqual(aIsZero, frontend.Variable(0))
126	aPowRMinus1 := QuadraticExtensionVariable{
127		a[0],
128		p.Mul(a[1], NewVariable(DTH_ROOT)),
129	}
130	aPowR := p.MulExtension(aPowRMinus1, a)
131
132	aPowRInv, hasInv := p.Inverse(aPowR[0])
133	return p.ScalarMulExtension(aPowRMinus1, aPowRInv), hasInv
134}
135
136// Divides two quadratic extension variables in the Goldilocks field.
137func (p *Chip) DivExtension(a, b QuadraticExtensionVariable) (QuadraticExtensionVariable, frontend.Variable) {
138	bInv, hasInv := p.InverseExtension(b)
139	return p.MulExtension(a, bInv), hasInv
140}
141
142// Exponentiates a quadratic extension variable to some exponent in the Golidlocks field.
143func (p *Chip) ExpExtension(
144	a QuadraticExtensionVariable,
145	exponent uint64,
146) QuadraticExtensionVariable {
147	switch exponent {
148	case 0:
149		return OneExtension()
150	case 1:
151		return a
152	case 2:
153		return p.MulExtension(a, a)
154	default:
155	}
156
157	current := a
158	product := OneExtension()
159
160	for i := 0; i < bits.Len64(exponent); i++ {
161		if i != 0 {
162			current = p.MulExtension(current, current)
163		}
164		if (exponent >> i & 1) != 0 {
165			product = p.MulExtension(product, current)
166		}
167	}
168
169	return product
170}
171
172func (p *Chip) ReduceExtension(x QuadraticExtensionVariable) QuadraticExtensionVariable {
173	return NewQuadraticExtensionVariable(p.Reduce(x[0]), p.Reduce(x[1]))
174}
175
176// Reduces a list of extension field terms with a scalar power in the Goldilocks field.
177func (p *Chip) ReduceWithPowers(
178	terms []QuadraticExtensionVariable,
179	scalar QuadraticExtensionVariable,
180) QuadraticExtensionVariable {
181	sum := ZeroExtension()
182	for i := len(terms) - 1; i >= 0; i-- {
183		sum = p.AddExtensionNoReduce(
184			p.MulExtensionNoReduce(
185				sum,
186				scalar,
187			),
188			terms[i],
189		)
190		sum = p.ReduceExtension(sum)
191	}
192	return sum
193}
194
195// Outputs whether the quadratic extension variable is zero.
196func (p *Chip) IsZero(x QuadraticExtensionVariable) frontend.Variable {
197	x0IsZero := p.api.IsZero(x[0].Limb)
198	x1IsZero := p.api.IsZero(x[1].Limb)
199	return p.api.Mul(x0IsZero, x1IsZero)
200}
201
202// Lookup is similar to select, but returns the first variable if the bit is zero and vice-versa.
203func (p *Chip) Lookup(
204	b frontend.Variable,
205	x, y QuadraticExtensionVariable,
206) QuadraticExtensionVariable {
207	c0 := p.api.Select(b, y[0].Limb, x[0].Limb)
208	c1 := p.api.Select(b, y[1].Limb, x[1].Limb)
209	return NewQuadraticExtensionVariable(NewVariable(c0), NewVariable(c1))
210}
211
212// Lookup2 is similar to select2, but returns the first variable if the bit is zero and vice-versa.
213func (p *Chip) Lookup2(
214	b0 frontend.Variable,
215	b1 frontend.Variable,
216	qe0, qe1, qe2, qe3 QuadraticExtensionVariable,
217) QuadraticExtensionVariable {
218	c0 := p.Lookup(b0, qe0, qe1)
219	c1 := p.Lookup(b0, qe2, qe3)
220	return p.Lookup(b1, c0, c1)
221}
222
223// Asserts that two quadratic extension variables are equal.
224func (p *Chip) AssertIsEqualExtension(
225	a QuadraticExtensionVariable,
226	b QuadraticExtensionVariable,
227) {
228	p.AssertIsEqual(a[0], b[0])
229	p.AssertIsEqual(a[1], b[1])
230}
231
232func (p *Chip) RangeCheckQE(a QuadraticExtensionVariable) {
233	p.RangeCheck(a[0])
234	p.RangeCheck(a[1])
235}