package bn256 // 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 // where i²=-1. // For SM9, gfP2 = gfP[x]/(x²+2) = gfP(u) where u²=-2. type gfP2 struct { // sm9: xu+y x, y gfP } 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) Equal(other *gfP2) bool { return e.x.Equal(&other.x) && e.y.Equal(&other.y) } func (e *gfP2) Set(a *gfP2) *gfP2 { e.x.Set(&a.x) e.y.Set(&a.y) return e } func (e *gfP2) SetZero() *gfP2 { e.x = gfP{0} e.y = gfP{0} return e } func (e *gfP2) SetOne() *gfP2 { e.x = gfP{0} e.y = gfPOne return e } func (e *gfP2) IsZero() bool { return e.x == gfPZero && e.y == gfPZero } func (e *gfP2) IsOne() bool { return e.x == gfPZero && e.y == gfPOne } // Conjugate sets e = -xu+y if a = xu+y. Also note that conjugate equivalents to e = Frobenius(a) = a^p func (e *gfP2) Conjugate(a *gfP2) *gfP2 { e.y.Set(&a.y) gfpNeg(&e.x, &a.x) return e } func (e *gfP2) Neg(a *gfP2) *gfP2 { gfpNeg(&e.x, &a.x) gfpNeg(&e.y, &a.y) 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 } // See "Multiplication and Squaring in Pairing-Friendly Fields", // http://eprint.iacr.org/2006/471.pdf // (ax*u + ay) (bx*u + by) = (ay*by - 2ax*bx) + (ay*bx+ax*by)u func (e *gfP2) Mul(a, b *gfP2) *gfP2 { tx, t := &gfP{}, &gfP{} gfpMul(tx, &a.x, &b.y) gfpMul(t, &b.x, &a.y) gfpAdd(tx, tx, t) ty := &gfP{} gfpMul(ty, &a.y, &b.y) gfpMul(t, &a.x, &b.x) gfpAdd(t, t, t) gfpSub(ty, ty, t) e.x.Set(tx) e.y.Set(ty) return e } func (e *gfP2) MulScalar(a *gfP2, b *gfP) *gfP2 { gfpMul(&e.x, &a.x, b) gfpMul(&e.y, &a.y, b) return e } //MulXi sets e=ξa where ξ=i+3 and then returns e. //e = u*a = -2x + yu // sm9: e = a*u = yu - 2x func (e *gfP2) MulXi(a *gfP2) *gfP2 { // (xi+y)(i+3) = (3x+y)i+(3y-x) //e = u*a = -2x + yu ty := &gfP{} gfpAdd(ty, &a.x, &a.x) gfpNeg(ty, ty) tx := &gfP{} tx.Set(&a.y) e.x.Set(tx) e.y.Set(ty) return e } func (e *gfP2) Square(a *gfP2) *gfP2 { // Complex squaring algorithm: // (xi+y)² = (x+y)(y-x) + 2*i*x*y // sm9: (xu+y)² = y²-2x² + 2uxy tx, ty := &gfP{}, &gfP{} gfpMul(ty, &a.y, &a.y) gfpMul(tx, &a.x, &a.x) gfpAdd(tx, tx, tx) gfpSub(ty, ty, tx) gfpMul(tx, &a.x, &a.y) gfpAdd(tx, tx, tx) e.x.Set(tx) e.y.Set(ty) 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 := &gfP{}, &gfP{} gfpMul(t1, &a.x, &a.x) gfpAdd(t1, t1, t1) gfpMul(t2, &a.y, &a.y) gfpAdd(t1, t1, t2) inv := &gfP{} inv.Invert(t1) gfpNeg(t1, &a.x) gfpMul(&e.x, t1, inv) gfpMul(&e.y, &a.y, inv) return e } // Sqrt sets e = sqrt(e) and return true if e is a square. Otherwise returns false and e remain unchanged. // The algorithm is based on the beautiful identity: // $$ // \sqrt{a+bx} = \pm\left(\sqrt{ \frac{a \pm \sqrt{a^2 + nb^2}}{2} } + \frac{xb}{2\sqrt{ \frac{a \pm \sqrt{a^2 + nb^2}}{2} }}\right) // $$ func (e *gfP2) Sqrt(f *gfP2) bool { a := &gfP{} b := &gfP{} tmp := &gfP{} // e = a + bu gfpMul(a, &f.y, &f.y) gfpMul(b, &f.x, &f.x) gfpAdd(tmp, a, b) gfpAdd(tmp, tmp, b) //a = a^2 + nb^2 if legendre(tmp) != 1 { return false } tmp.Sqrt(tmp) gfpAdd(a, &f.y, tmp) a.half(a) if legendre(a) != 1 { gfpSub(a, &f.y, tmp) a.half(a) if legendre(a) != 1 { return false } } e.y.Sqrt(a) gfpAdd(a, &e.y, &e.y) a.Invert(a) gfpMul(&e.x, a, &f.x) return true }