|
package goldilocks
|
|
|
|
import (
|
|
"math/bits"
|
|
|
|
"github.com/consensys/gnark/frontend"
|
|
)
|
|
|
|
const W uint64 = 7
|
|
const DTH_ROOT uint64 = 18446744069414584320
|
|
|
|
type QuadraticExtensionVariable [2]GoldilocksVariable
|
|
|
|
func NewQuadraticExtensionVariable(x GoldilocksVariable, y GoldilocksVariable) QuadraticExtensionVariable {
|
|
return QuadraticExtensionVariable{x, y}
|
|
}
|
|
|
|
func (p GoldilocksVariable) ToQuadraticExtension() QuadraticExtensionVariable {
|
|
return NewQuadraticExtensionVariable(p, Zero())
|
|
}
|
|
|
|
func ZeroExtension() QuadraticExtensionVariable {
|
|
return Zero().ToQuadraticExtension()
|
|
}
|
|
|
|
func OneExtension() QuadraticExtensionVariable {
|
|
return One().ToQuadraticExtension()
|
|
}
|
|
|
|
// Adds two quadratic extension variables in the Goldilocks field.
|
|
func (p *GoldilocksApi) AddExtension(a, b QuadraticExtensionVariable) QuadraticExtensionVariable {
|
|
c0 := p.Add(a[0], b[0])
|
|
c1 := p.Add(a[1], b[1])
|
|
return NewQuadraticExtensionVariable(c0, c1)
|
|
}
|
|
|
|
// Adds two quadratic extension variables in the Goldilocks field without reducing.
|
|
func (p *GoldilocksApi) AddExtensionNoReduce(a, b QuadraticExtensionVariable) QuadraticExtensionVariable {
|
|
c0 := p.AddNoReduce(a[0], b[0])
|
|
c1 := p.AddNoReduce(a[1], b[1])
|
|
return NewQuadraticExtensionVariable(c0, c1)
|
|
}
|
|
|
|
// Subtracts two quadratic extension variables in the Goldilocks field.
|
|
func (p *GoldilocksApi) SubExtension(a, b QuadraticExtensionVariable) QuadraticExtensionVariable {
|
|
c0 := p.Sub(a[0], b[0])
|
|
c1 := p.Sub(a[1], b[1])
|
|
return NewQuadraticExtensionVariable(c0, c1)
|
|
}
|
|
|
|
// Subtracts two quadratic extension variables in the Goldilocks field without reducing.
|
|
func (p *GoldilocksApi) SubExtensionNoReduce(a, b QuadraticExtensionVariable) QuadraticExtensionVariable {
|
|
c0 := p.SubNoReduce(a[0], b[0])
|
|
c1 := p.SubNoReduce(a[1], b[1])
|
|
return NewQuadraticExtensionVariable(c0, c1)
|
|
}
|
|
|
|
// Multiplies quadratic extension variable in the Goldilocks field.
|
|
func (p *GoldilocksApi) MulExtension(a, b QuadraticExtensionVariable) QuadraticExtensionVariable {
|
|
product := p.MulExtensionNoReduce(a, b)
|
|
product[0] = p.Reduce(product[0])
|
|
product[1] = p.Reduce(product[1])
|
|
return product
|
|
}
|
|
|
|
// Multiplies quadratic extension variable in the Goldilocks field without reducing.
|
|
func (p *GoldilocksApi) MulExtensionNoReduce(a, b QuadraticExtensionVariable) QuadraticExtensionVariable {
|
|
c0o0 := p.MulNoReduce(a[0], b[0])
|
|
c0o1 := p.MulNoReduce(p.MulNoReduce(NewVariable(7), a[1]), b[1])
|
|
c0 := p.AddNoReduce(c0o0, c0o1)
|
|
c1 := p.AddNoReduce(p.MulNoReduce(a[0], b[1]), p.MulNoReduce(a[1], b[0]))
|
|
return NewQuadraticExtensionVariable(c0, c1)
|
|
}
|
|
|
|
// Multiplies two operands a and b and adds to c in the Goldilocks extension field. a * b + c must
|
|
// be less than RANGE_CHECK_NB_BITS bits.
|
|
func (p *GoldilocksApi) MulAddExtension(a, b, c QuadraticExtensionVariable) QuadraticExtensionVariable {
|
|
product := p.MulExtensionNoReduce(a, b)
|
|
sum := p.AddExtensionNoReduce(product, c)
|
|
sum[0] = p.Reduce(sum[0])
|
|
sum[1] = p.Reduce(sum[1])
|
|
return sum
|
|
}
|
|
|
|
func (p *GoldilocksApi) MulAddExtensionNoReduce(a, b, c QuadraticExtensionVariable) QuadraticExtensionVariable {
|
|
product := p.MulExtensionNoReduce(a, b)
|
|
sum := p.AddExtensionNoReduce(product, c)
|
|
return sum
|
|
}
|
|
|
|
// Multiplies two operands a and b and subtracts to c in the Goldilocks extension field. a * b - c must
|
|
// be less than RANGE_CHECK_NB_BITS bits.
|
|
func (p *GoldilocksApi) SubMulExtension(a, b, c QuadraticExtensionVariable) QuadraticExtensionVariable {
|
|
difference := p.SubExtensionNoReduce(a, b)
|
|
product := p.MulExtensionNoReduce(difference, c)
|
|
product[0] = p.Reduce(product[0])
|
|
product[1] = p.Reduce(product[1])
|
|
return product
|
|
}
|
|
|
|
// Multiplies quadratic extension variable in the Goldilocks field by a scalar.
|
|
func (p *GoldilocksApi) ScalarMulExtension(
|
|
a QuadraticExtensionVariable,
|
|
b GoldilocksVariable,
|
|
) QuadraticExtensionVariable {
|
|
return NewQuadraticExtensionVariable(
|
|
p.Mul(a[0], b),
|
|
p.Mul(a[1], b),
|
|
)
|
|
}
|
|
|
|
// Computes an inner product over quadratic extension variable vectors in the Goldilocks field.
|
|
func (p *GoldilocksApi) InnerProductExtension(
|
|
constant GoldilocksVariable,
|
|
startingAcc QuadraticExtensionVariable,
|
|
pairs [][2]QuadraticExtensionVariable,
|
|
) QuadraticExtensionVariable {
|
|
acc := startingAcc
|
|
for i := 0; i < len(pairs); i++ {
|
|
a := pairs[i][0]
|
|
b := pairs[i][1]
|
|
mul := p.ScalarMulExtension(a, constant)
|
|
acc = p.MulAddExtensionNoReduce(mul, b, acc)
|
|
}
|
|
return p.ReduceExtension(acc)
|
|
}
|
|
|
|
// Computes the inverse of a quadratic extension variable in the Goldilocks field.
|
|
func (p *GoldilocksApi) InverseExtension(a QuadraticExtensionVariable) QuadraticExtensionVariable {
|
|
a0IsZero := p.api.IsZero(a[0].Limb)
|
|
a1IsZero := p.api.IsZero(a[1].Limb)
|
|
p.api.AssertIsEqual(p.api.Mul(a0IsZero, a1IsZero), frontend.Variable(0))
|
|
aPowRMinus1 := QuadraticExtensionVariable{
|
|
a[0],
|
|
p.Mul(a[1], NewVariable(DTH_ROOT)),
|
|
}
|
|
aPowR := p.MulExtension(aPowRMinus1, a)
|
|
return p.ScalarMulExtension(aPowRMinus1, p.Inverse(aPowR[0]))
|
|
}
|
|
|
|
// Divides two quadratic extension variables in the Goldilocks field.
|
|
func (p *GoldilocksApi) DivExtension(a, b QuadraticExtensionVariable) QuadraticExtensionVariable {
|
|
return p.MulExtension(a, p.InverseExtension(b))
|
|
}
|
|
|
|
// Exponentiates a quadratic extension variable to some exponent in the Golidlocks field.
|
|
func (p *GoldilocksApi) ExpExtension(
|
|
a QuadraticExtensionVariable,
|
|
exponent uint64,
|
|
) QuadraticExtensionVariable {
|
|
switch exponent {
|
|
case 0:
|
|
return OneExtension()
|
|
case 1:
|
|
return a
|
|
case 2:
|
|
return p.MulExtension(a, a)
|
|
default:
|
|
}
|
|
|
|
current := a
|
|
product := OneExtension()
|
|
|
|
for i := 0; i < bits.Len64(exponent); i++ {
|
|
if i != 0 {
|
|
current = p.MulExtension(current, current)
|
|
}
|
|
if (exponent >> i & 1) != 0 {
|
|
product = p.MulExtension(product, current)
|
|
}
|
|
}
|
|
|
|
return product
|
|
}
|
|
|
|
func (p *GoldilocksApi) ReduceExtension(x QuadraticExtensionVariable) QuadraticExtensionVariable {
|
|
return NewQuadraticExtensionVariable(p.Reduce(x[0]), p.Reduce(x[1]))
|
|
}
|
|
|
|
// Reduces a list of extension field terms with a scalar power in the Goldilocks field.
|
|
func (p *GoldilocksApi) ReduceWithPowers(
|
|
terms []QuadraticExtensionVariable,
|
|
scalar QuadraticExtensionVariable,
|
|
) QuadraticExtensionVariable {
|
|
sum := ZeroExtension()
|
|
for i := len(terms) - 1; i >= 0; i-- {
|
|
sum = p.AddExtensionNoReduce(
|
|
p.MulExtensionNoReduce(
|
|
sum,
|
|
scalar,
|
|
),
|
|
terms[i],
|
|
)
|
|
sum = p.ReduceExtension(sum)
|
|
}
|
|
return sum
|
|
}
|
|
|
|
// Outputs whether the quadratic extension variable is zero.
|
|
func (p *GoldilocksApi) IsZero(x QuadraticExtensionVariable) frontend.Variable {
|
|
x0IsZero := p.api.IsZero(x[0].Limb)
|
|
x1IsZero := p.api.IsZero(x[1].Limb)
|
|
return p.api.Mul(x0IsZero, x1IsZero)
|
|
}
|
|
|
|
// Lookup is similar to select, but returns the first variable if the bit is zero and vice-versa.
|
|
func (p *GoldilocksApi) Lookup(
|
|
b frontend.Variable,
|
|
x, y QuadraticExtensionVariable,
|
|
) QuadraticExtensionVariable {
|
|
c0 := p.api.Select(b, y[0].Limb, x[0].Limb)
|
|
c1 := p.api.Select(b, y[1].Limb, x[1].Limb)
|
|
return NewQuadraticExtensionVariable(NewVariable(c0), NewVariable(c1))
|
|
}
|
|
|
|
// Lookup2 is similar to select2, but returns the first variable if the bit is zero and vice-versa.
|
|
func (p *GoldilocksApi) Lookup2(
|
|
b0 frontend.Variable,
|
|
b1 frontend.Variable,
|
|
qe0, qe1, qe2, qe3 QuadraticExtensionVariable,
|
|
) QuadraticExtensionVariable {
|
|
c0 := p.Lookup(b0, qe0, qe1)
|
|
c1 := p.Lookup(b0, qe2, qe3)
|
|
return p.Lookup(b1, c0, c1)
|
|
}
|
|
|
|
// Asserts that two quadratic extension variables are equal.
|
|
func (p *GoldilocksApi) AssertIsEqualExtension(
|
|
a QuadraticExtensionVariable,
|
|
b QuadraticExtensionVariable,
|
|
) {
|
|
p.AssertIsEqual(a[0], b[0])
|
|
p.AssertIsEqual(a[1], b[1])
|
|
}
|
|
|
|
func (p *GoldilocksApi) RangeCheckQE(a QuadraticExtensionVariable) {
|
|
p.RangeCheck(a[0])
|
|
p.RangeCheck(a[1])
|
|
}
|