2022-07-15 16:42:39 +08:00
|
|
|
|
package bn256
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
"math/big"
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
// For details of the algorithms used, see "Multiplication and Squaring on
|
|
|
|
|
// Pairing-Friendly Fields, Devegili et al.
|
|
|
|
|
// http://eprint.iacr.org/2006/471.pdf.
|
|
|
|
|
|
|
|
|
|
// gfP2 implements a field of size p² as a quadratic extension of the base field
|
2023-04-28 11:25:09 +08:00
|
|
|
|
// where u²=-2, beta=-2.
|
2022-07-15 16:42:39 +08:00
|
|
|
|
type gfP2 struct {
|
2023-04-28 11:25:09 +08:00
|
|
|
|
x, y gfP // value is xu+y.
|
2022-07-15 16:42:39 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func gfP2Decode(in *gfP2) *gfP2 {
|
|
|
|
|
out := &gfP2{}
|
|
|
|
|
montDecode(&out.x, &in.x)
|
|
|
|
|
montDecode(&out.y, &in.y)
|
|
|
|
|
return out
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (e *gfP2) String() string {
|
|
|
|
|
return "(" + e.x.String() + ", " + e.y.String() + ")"
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (e *gfP2) Set(a *gfP2) *gfP2 {
|
2023-06-30 17:51:35 +08:00
|
|
|
|
gfp2Copy(e, a)
|
2022-07-15 16:42:39 +08:00
|
|
|
|
return e
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (e *gfP2) SetZero() *gfP2 {
|
2023-07-07 18:09:49 +08:00
|
|
|
|
e.x.Set(zero)
|
|
|
|
|
e.y.Set(zero)
|
2022-07-15 16:42:39 +08:00
|
|
|
|
return e
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (e *gfP2) SetOne() *gfP2 {
|
2023-07-07 18:09:49 +08:00
|
|
|
|
e.x.Set(zero)
|
|
|
|
|
e.y.Set(one)
|
2022-07-15 16:42:39 +08:00
|
|
|
|
return e
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (e *gfP2) SetU() *gfP2 {
|
2023-07-07 18:09:49 +08:00
|
|
|
|
e.x.Set(one)
|
|
|
|
|
e.y.Set(zero)
|
2022-07-15 16:42:39 +08:00
|
|
|
|
return e
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (e *gfP2) SetFrobConstant() *gfP2 {
|
2023-07-07 18:09:49 +08:00
|
|
|
|
e.x.Set(zero)
|
|
|
|
|
e.y.Set(frobConstant)
|
2022-07-15 16:42:39 +08:00
|
|
|
|
return e
|
|
|
|
|
}
|
|
|
|
|
|
2023-07-07 18:09:49 +08:00
|
|
|
|
func (e *gfP2) Equal(t *gfP2) int {
|
|
|
|
|
var acc uint64
|
|
|
|
|
for i := range e.x {
|
|
|
|
|
acc |= e.x[i] ^ t.x[i]
|
|
|
|
|
}
|
|
|
|
|
for i := range e.y {
|
|
|
|
|
acc |= e.y[i] ^ t.y[i]
|
|
|
|
|
}
|
|
|
|
|
return uint64IsZero(acc)
|
|
|
|
|
}
|
|
|
|
|
|
2022-07-15 16:42:39 +08:00
|
|
|
|
func (e *gfP2) IsZero() bool {
|
2023-07-07 18:09:49 +08:00
|
|
|
|
return (e.x.Equal(zero) == 1) && (e.y.Equal(zero) == 1)
|
2022-07-15 16:42:39 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (e *gfP2) IsOne() bool {
|
2023-07-07 18:09:49 +08:00
|
|
|
|
return (e.x.Equal(zero) == 1) && (e.y.Equal(one) == 1)
|
2022-07-15 16:42:39 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (e *gfP2) Conjugate(a *gfP2) *gfP2 {
|
|
|
|
|
e.y.Set(&a.y)
|
2023-07-11 17:30:48 +08:00
|
|
|
|
gfpNeg(&e.x, &a.x)
|
2022-07-15 16:42:39 +08:00
|
|
|
|
return e
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (e *gfP2) Neg(a *gfP2) *gfP2 {
|
2023-07-11 17:30:48 +08:00
|
|
|
|
gfpNeg(&e.x, &a.x)
|
|
|
|
|
gfpNeg(&e.y, &a.y)
|
2022-07-15 16:42:39 +08:00
|
|
|
|
return e
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (e *gfP2) Add(a, b *gfP2) *gfP2 {
|
|
|
|
|
gfpAdd(&e.x, &a.x, &b.x)
|
|
|
|
|
gfpAdd(&e.y, &a.y, &b.y)
|
|
|
|
|
return e
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (e *gfP2) Sub(a, b *gfP2) *gfP2 {
|
|
|
|
|
gfpSub(&e.x, &a.x, &b.x)
|
|
|
|
|
gfpSub(&e.y, &a.y, &b.y)
|
|
|
|
|
return e
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (e *gfP2) Double(a *gfP2) *gfP2 {
|
2023-07-11 17:30:48 +08:00
|
|
|
|
gfpDouble(&e.x, &a.x)
|
|
|
|
|
gfpDouble(&e.y, &a.y)
|
2022-07-15 16:42:39 +08:00
|
|
|
|
return e
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (e *gfP2) Triple(a *gfP2) *gfP2 {
|
2023-07-11 17:30:48 +08:00
|
|
|
|
gfpTriple(&e.x, &a.x)
|
|
|
|
|
gfpTriple(&e.y, &a.y)
|
2022-07-15 16:42:39 +08:00
|
|
|
|
return e
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// See "Multiplication and Squaring in Pairing-Friendly Fields",
|
|
|
|
|
// http://eprint.iacr.org/2006/471.pdf
|
|
|
|
|
// The Karatsuba method
|
2023-06-30 17:51:35 +08:00
|
|
|
|
// (a0+a1*u)(b0+b1*u)=c0+c1*u, where
|
|
|
|
|
// c0 = a0*b0 - 2a1*b1
|
|
|
|
|
// c1 = (a0 + a1)(b0 + b1) - a0*b0 - a1*b1 = a0*b1 + a1*b0
|
2022-07-15 16:42:39 +08:00
|
|
|
|
func (e *gfP2) Mul(a, b *gfP2) *gfP2 {
|
2023-07-21 17:39:06 +08:00
|
|
|
|
gfp2Mul(e, a, b)
|
2023-07-06 17:36:34 +08:00
|
|
|
|
return e
|
|
|
|
|
}
|
|
|
|
|
|
2023-07-07 18:09:49 +08:00
|
|
|
|
// MulU without value copy, will use e directly, so e can't be same as a and b.
|
2023-04-28 11:25:09 +08:00
|
|
|
|
// MulU: a * b * u
|
2023-06-30 17:51:35 +08:00
|
|
|
|
// (a0+a1*u)(b0+b1*u)*u=c0+c1*u, where
|
|
|
|
|
// c1 = (a0*b0 - 2a1*b1)u
|
|
|
|
|
// c0 = -2 * ((a0 + a1)(b0 + b1) - a0*b0 - a1*b1) = -2 * (a0*b1 + a1*b0)
|
2023-07-21 17:39:06 +08:00
|
|
|
|
func (e *gfP2) MulU(a, b *gfP2) *gfP2 {
|
|
|
|
|
gfp2MulU(e, a, b)
|
2022-07-15 16:42:39 +08:00
|
|
|
|
return e
|
|
|
|
|
}
|
|
|
|
|
|
2023-04-28 15:31:59 +08:00
|
|
|
|
// MulU1: a * u
|
2023-06-30 17:51:35 +08:00
|
|
|
|
// (a0+a1*u)u=c0+c1*u, where
|
|
|
|
|
// c1 = a0
|
|
|
|
|
// c0 = -2a1
|
2023-04-28 15:31:59 +08:00
|
|
|
|
func (e *gfP2) MulU1(a *gfP2) *gfP2 {
|
|
|
|
|
t := &gfP{}
|
2023-07-11 17:30:48 +08:00
|
|
|
|
gfpDouble(t, &a.x)
|
|
|
|
|
gfpNeg(t, t)
|
2023-04-28 15:31:59 +08:00
|
|
|
|
|
2023-06-30 17:51:35 +08:00
|
|
|
|
gfpCopy(&e.x, &a.y)
|
|
|
|
|
gfpCopy(&e.y, t)
|
2023-04-28 15:31:59 +08:00
|
|
|
|
return e
|
|
|
|
|
}
|
|
|
|
|
|
2022-07-15 16:42:39 +08:00
|
|
|
|
func (e *gfP2) Square(a *gfP2) *gfP2 {
|
|
|
|
|
// Complex squaring algorithm:
|
2023-04-28 11:25:09 +08:00
|
|
|
|
// (xu+y)² = y^2-2*x^2 + 2*u*x*y
|
2023-07-21 17:39:06 +08:00
|
|
|
|
gfp2Square(e, a)
|
2023-07-02 11:23:36 +08:00
|
|
|
|
return e
|
|
|
|
|
}
|
|
|
|
|
|
2022-07-15 16:42:39 +08:00
|
|
|
|
func (e *gfP2) SquareU(a *gfP2) *gfP2 {
|
|
|
|
|
// Complex squaring algorithm:
|
2023-04-28 11:25:09 +08:00
|
|
|
|
// (xu+y)²*u = (y^2-2*x^2)u - 4*x*y
|
2023-07-21 17:39:06 +08:00
|
|
|
|
gfp2SquareU(e, a)
|
2023-07-02 11:23:36 +08:00
|
|
|
|
return e
|
|
|
|
|
}
|
|
|
|
|
|
2022-07-15 16:42:39 +08:00
|
|
|
|
func (e *gfP2) MulScalar(a *gfP2, b *gfP) *gfP2 {
|
|
|
|
|
gfpMul(&e.x, &a.x, b)
|
|
|
|
|
gfpMul(&e.y, &a.y, b)
|
|
|
|
|
return e
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (e *gfP2) Invert(a *gfP2) *gfP2 {
|
|
|
|
|
// See "Implementing cryptographic pairings", M. Scott, section 3.2.
|
|
|
|
|
// ftp://136.206.11.249/pub/crypto/pairings.pdf
|
|
|
|
|
t1, t2, t3 := &gfP{}, &gfP{}, &gfP{}
|
2023-06-24 09:38:45 +08:00
|
|
|
|
gfpSqr(t1, &a.x, 1)
|
2023-07-11 17:30:48 +08:00
|
|
|
|
gfpDouble(t3, t1)
|
2023-06-24 09:38:45 +08:00
|
|
|
|
gfpSqr(t2, &a.y, 1)
|
2022-07-15 16:42:39 +08:00
|
|
|
|
gfpAdd(t3, t3, t2)
|
|
|
|
|
|
|
|
|
|
inv := &gfP{}
|
|
|
|
|
inv.Invert(t3) // inv = (2 * a.x ^ 2 + a.y ^ 2) ^ (-1)
|
|
|
|
|
|
2023-07-11 17:30:48 +08:00
|
|
|
|
gfpNeg(t1, &a.x)
|
2022-07-15 16:42:39 +08:00
|
|
|
|
|
|
|
|
|
gfpMul(&e.x, t1, inv) // x = - a.x * inv
|
|
|
|
|
gfpMul(&e.y, &a.y, inv) // y = a.y * inv
|
|
|
|
|
return e
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (e *gfP2) Exp(f *gfP2, power *big.Int) *gfP2 {
|
|
|
|
|
sum := (&gfP2{}).SetOne()
|
|
|
|
|
t := &gfP2{}
|
|
|
|
|
|
|
|
|
|
for i := power.BitLen() - 1; i >= 0; i-- {
|
|
|
|
|
t.Square(sum)
|
|
|
|
|
if power.Bit(i) != 0 {
|
|
|
|
|
sum.Mul(t, f)
|
|
|
|
|
} else {
|
|
|
|
|
sum.Set(t)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
e.Set(sum)
|
|
|
|
|
return e
|
|
|
|
|
}
|
|
|
|
|
|
2023-04-28 11:25:09 +08:00
|
|
|
|
// (xu+y)^p = x * u^p + y
|
2023-06-30 17:51:35 +08:00
|
|
|
|
//
|
|
|
|
|
// = x * u * u^(p-1) + y
|
|
|
|
|
// = (-x)*u + y
|
|
|
|
|
//
|
2023-04-28 11:25:09 +08:00
|
|
|
|
// here u^(p-1) = -1
|
2022-07-15 16:42:39 +08:00
|
|
|
|
func (e *gfP2) Frobenius(a *gfP2) *gfP2 {
|
|
|
|
|
e.Conjugate(a)
|
|
|
|
|
return e
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Sqrt method is only required when we implement compressed format
|
2023-04-29 13:33:44 +08:00
|
|
|
|
// TODO: use addchain to improve performance for 3 exp operations.
|
2022-07-15 16:42:39 +08:00
|
|
|
|
func (ret *gfP2) Sqrt(a *gfP2) *gfP2 {
|
|
|
|
|
// Algorithm 10 https://eprint.iacr.org/2012/685.pdf
|
|
|
|
|
// TODO
|
|
|
|
|
ret.SetZero()
|
|
|
|
|
c := &twistGen.x
|
|
|
|
|
b, b2, bq := &gfP2{}, &gfP2{}, &gfP2{}
|
2023-04-29 13:33:44 +08:00
|
|
|
|
b = b.expPMinus1Over4(a)
|
2022-07-15 16:42:39 +08:00
|
|
|
|
b2.Mul(b, b)
|
2023-04-29 13:33:44 +08:00
|
|
|
|
bq = bq.expP(b)
|
2022-07-15 16:42:39 +08:00
|
|
|
|
|
|
|
|
|
t := &gfP2{}
|
|
|
|
|
x0 := &gfP{}
|
|
|
|
|
/* ignore sqrt existing check
|
|
|
|
|
a0 := &gfP2{}
|
|
|
|
|
a0.Exp(b2, p)
|
|
|
|
|
a0.Mul(a0, b2)
|
|
|
|
|
a0 = gfP2Decode(a0)
|
|
|
|
|
*/
|
|
|
|
|
t.Mul(bq, b)
|
2023-07-07 18:09:49 +08:00
|
|
|
|
if t.x.Equal(zero) == 1 && t.y.Equal(one) == 1 {
|
2022-07-15 16:42:39 +08:00
|
|
|
|
t.Mul(b2, a)
|
|
|
|
|
x0.Sqrt(&t.y)
|
|
|
|
|
t.MulScalar(bq, x0)
|
|
|
|
|
ret.Set(t)
|
|
|
|
|
} else {
|
|
|
|
|
d, e, f := &gfP2{}, &gfP2{}, &gfP2{}
|
2023-04-29 13:33:44 +08:00
|
|
|
|
d = d.expPMinus1Over2(c)
|
2022-07-15 16:42:39 +08:00
|
|
|
|
e.Mul(d, c)
|
|
|
|
|
f.Square(e)
|
|
|
|
|
e.Invert(e)
|
|
|
|
|
t.Mul(b2, a)
|
|
|
|
|
t.Mul(t, f)
|
|
|
|
|
x0.Sqrt(&t.y)
|
|
|
|
|
t.MulScalar(bq, x0)
|
|
|
|
|
t.Mul(t, e)
|
|
|
|
|
ret.Set(t)
|
|
|
|
|
}
|
|
|
|
|
return ret
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Select sets e to p1 if cond == 1, and to p2 if cond == 0.
|
|
|
|
|
func (e *gfP2) Select(p1, p2 *gfP2, cond int) *gfP2 {
|
|
|
|
|
e.x.Select(&p1.x, &p2.x, cond)
|
|
|
|
|
e.y.Select(&p1.y, &p2.y, cond)
|
|
|
|
|
return e
|
|
|
|
|
}
|