You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

239 lines
7.3 KiB

package goldilocks
import (
"math/bits"
"github.com/consensys/gnark/frontend"
)
const W uint64 = 7
const DTH_ROOT uint64 = 18446744069414584320
type QuadraticExtensionVariable [2]Variable
func NewQuadraticExtensionVariable(x Variable, y Variable) QuadraticExtensionVariable {
return QuadraticExtensionVariable{x, y}
}
func (p Variable) 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 *Chip) 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 *Chip) 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 *Chip) 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 *Chip) 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 *Chip) 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 *Chip) 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 *Chip) 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 *Chip) 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 *Chip) 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 *Chip) ScalarMulExtension(
a QuadraticExtensionVariable,
b Variable,
) 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 *Chip) InnerProductExtension(
constant Variable,
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 *Chip) 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 *Chip) 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 *Chip) 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 *Chip) 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 *Chip) 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 *Chip) 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 *Chip) 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 *Chip) 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 *Chip) AssertIsEqualExtension(
a QuadraticExtensionVariable,
b QuadraticExtensionVariable,
) {
p.AssertIsEqual(a[0], b[0])
p.AssertIsEqual(a[1], b[1])
}
func (p *Chip) RangeCheckQE(a QuadraticExtensionVariable) {
p.RangeCheck(a[0])
p.RangeCheck(a[1])
}