mirror of
https://github.com/emmansun/gmsm.git
synced 2025-04-26 12:16:20 +08:00
Merge branch 'main' of https://github.com/emmansun/gmsm
# Conflicts: # sm9/bn256/gfp12_b6.go
This commit is contained in:
commit
e769cefbd8
@ -2298,14 +2298,12 @@ internalMulBMI2:
|
||||
|
||||
MULXQ t1, mul0, acc2
|
||||
ADDQ mul0, acc1
|
||||
ADCQ $0, acc2
|
||||
|
||||
MULXQ t2, mul0, acc3
|
||||
ADDQ mul0, acc2
|
||||
ADCQ $0, acc3
|
||||
ADCQ mul0, acc2
|
||||
|
||||
MULXQ t3, mul0, acc4
|
||||
ADDQ mul0, acc3
|
||||
ADCQ mul0, acc3
|
||||
ADCQ $0, acc4
|
||||
|
||||
MOVQ acc5, mul1
|
||||
|
@ -4,23 +4,23 @@ package bn256
|
||||
func lineFunctionAdd(r, p, rOut *twistPoint, q *curvePoint, r2, a, b, c *gfP2) {
|
||||
// See the mixed addition algorithm from "Faster Computation of the
|
||||
// Tate Pairing", http://arxiv.org/pdf/0904.0854v3.pdf
|
||||
B := (&gfP2{}).MulNC(&p.x, &r.t) // B = Xp * Zr^2
|
||||
B := (&gfP2{}).Mul(&p.x, &r.t) // B = Xp * Zr^2
|
||||
|
||||
D := (&gfP2{}).Add(&p.y, &r.z) // D = Yp + Zr
|
||||
D.Square(D).Sub(D, r2).Sub(D, &r.t).Mul(D, &r.t) // D = ((Yp + Zr)^2 - Zr^2 - Yp^2)*Zr^2 = 2Yp*Zr^3
|
||||
|
||||
H := (&gfP2{}).Sub(B, &r.x) // H = Xp * Zr^2 - Xr
|
||||
I := (&gfP2{}).SquareNC(H) // I = (Xp * Zr^2 - Xr)^2 = Xp^2*Zr^4 + Xr^2 - 2Xr*Xp*Zr^2
|
||||
I := (&gfP2{}).Square(H) // I = (Xp * Zr^2 - Xr)^2 = Xp^2*Zr^4 + Xr^2 - 2Xr*Xp*Zr^2
|
||||
|
||||
E := (&gfP2{}).Double(I) // E = 2*(Xp * Zr^2 - Xr)^2
|
||||
E.Double(E) // E = 4*(Xp * Zr^2 - Xr)^2
|
||||
|
||||
J := (&gfP2{}).MulNC(H, E) // J = 4*(Xp * Zr^2 - Xr)^3
|
||||
J := (&gfP2{}).Mul(H, E) // J = 4*(Xp * Zr^2 - Xr)^3
|
||||
|
||||
L1 := (&gfP2{}).Sub(D, &r.y) // L1 = 2Yp*Zr^3 - Yr
|
||||
L1.Sub(L1, &r.y) // L1 = 2Yp*Zr^3 - 2*Yr
|
||||
|
||||
V := (&gfP2{}).MulNC(&r.x, E) // V = 4 * Xr * (Xp * Zr^2 - Xr)^2
|
||||
V := (&gfP2{}).Mul(&r.x, E) // V = 4 * Xr * (Xp * Zr^2 - Xr)^2
|
||||
|
||||
rOut.x.Square(L1).Sub(&rOut.x, J).Sub(&rOut.x, V).Sub(&rOut.x, V) // rOut.x = L1^2 - J - 2V
|
||||
|
||||
@ -28,11 +28,11 @@ func lineFunctionAdd(r, p, rOut *twistPoint, q *curvePoint, r2, a, b, c *gfP2) {
|
||||
|
||||
t := (&gfP2{}).Sub(V, &rOut.x) // t = V - rOut.x
|
||||
t.Mul(t, L1) // t = L1*(V-rOut.x)
|
||||
t2 := (&gfP2{}).MulNC(&r.y, J)
|
||||
t2 := (&gfP2{}).Mul(&r.y, J)
|
||||
t2.Double(t2) // t2 = 2Yr * J
|
||||
rOut.y.Sub(t, t2) // rOut.y = L1*(V-rOut.x) - 2Yr*J
|
||||
|
||||
rOut.t.SquareNC(&rOut.z)
|
||||
rOut.t.Square(&rOut.z)
|
||||
|
||||
// t = (Yp + rOut.Z)^2 - Yp^2 - rOut.Z^2 = 2Yp*rOut.Z
|
||||
t.Add(&p.y, &rOut.z).Square(t).Sub(t, r2).Sub(t, &rOut.t)
|
||||
@ -51,9 +51,9 @@ func lineFunctionAdd(r, p, rOut *twistPoint, q *curvePoint, r2, a, b, c *gfP2) {
|
||||
func lineFunctionDouble(r, rOut *twistPoint, q *curvePoint, a, b, c *gfP2) {
|
||||
// See the doubling algorithm for a=0 from "Faster Computation of the
|
||||
// Tate Pairing", http://arxiv.org/pdf/0904.0854v3.pdf
|
||||
A := (&gfP2{}).SquareNC(&r.x)
|
||||
B := (&gfP2{}).SquareNC(&r.y)
|
||||
C := (&gfP2{}).SquareNC(B) // C = Yr ^ 4
|
||||
A := (&gfP2{}).Square(&r.x)
|
||||
B := (&gfP2{}).Square(&r.y)
|
||||
C := (&gfP2{}).Square(B) // C = Yr ^ 4
|
||||
|
||||
D := (&gfP2{}).Add(&r.x, B)
|
||||
D.Square(D).Sub(D, A).Sub(D, C).Double(D)
|
||||
@ -61,7 +61,7 @@ func lineFunctionDouble(r, rOut *twistPoint, q *curvePoint, a, b, c *gfP2) {
|
||||
E := (&gfP2{}).Double(A) //
|
||||
E.Add(E, A) // E = 3 * Xr ^ 2
|
||||
|
||||
G := (&gfP2{}).SquareNC(E) // G = 9 * Xr^4
|
||||
G := (&gfP2{}).Square(E) // G = 9 * Xr^4
|
||||
|
||||
rOut.x.Sub(G, D).Sub(&rOut.x, D)
|
||||
|
||||
@ -72,7 +72,7 @@ func lineFunctionDouble(r, rOut *twistPoint, q *curvePoint, a, b, c *gfP2) {
|
||||
t.Double(t).Double(t) // t = 8 * Yr ^ 4
|
||||
rOut.y.Sub(&rOut.y, t)
|
||||
|
||||
rOut.t.SquareNC(&rOut.z)
|
||||
rOut.t.Square(&rOut.z)
|
||||
|
||||
t.Mul(E, &r.t).Double(t) // t = 2(E * Tr)
|
||||
b.Neg(t) // b = -2(E * Tr)
|
||||
@ -127,7 +127,7 @@ func miller(q *twistPoint, p *curvePoint) *gfP12 {
|
||||
r := &twistPoint{}
|
||||
r.Set(aAffine)
|
||||
|
||||
r2 := (&gfP2{}).SquareNC(&aAffine.y)
|
||||
r2 := (&gfP2{}).Square(&aAffine.y)
|
||||
|
||||
a, b, c := &gfP2{}, &gfP2{}, &gfP2{}
|
||||
newR := &twistPoint{}
|
||||
@ -218,10 +218,9 @@ func finalExponentiation(in *gfP12) *gfP12 {
|
||||
y0.MulNC(fp, fp2).Mul(y0, fp3) // y0 = (t1^p) * (t1^(p^2)) * (t1^(p^3))
|
||||
|
||||
// reuse fp, fp2, fp3 local variables
|
||||
// [gfP12ExpU] is most time consuming operation
|
||||
fu := fp.gfP12ExpU(t1)
|
||||
fu2 := fp2.gfP12ExpU(fu)
|
||||
fu3 := fp3.gfP12ExpU(fu2)
|
||||
fu := fp.Cyclo6PowToU(t1)
|
||||
fu2 := fp2.Cyclo6PowToU(fu)
|
||||
fu3 := fp3.Cyclo6PowToU(fu2)
|
||||
|
||||
fu2p := (&gfP12{}).Frobenius(fu2)
|
||||
fu3p := (&gfP12{}).Frobenius(fu3)
|
||||
@ -237,14 +236,14 @@ func finalExponentiation(in *gfP12) *gfP12 {
|
||||
y6.Conjugate(y6) // y6 = 1 / (t1^(u^3) * (t1^(u^3))^p)
|
||||
|
||||
// https://eprint.iacr.org/2008/490.pdf
|
||||
t0 := (&gfP12{}).SpecialSquareNC(y6)
|
||||
t0 := (&gfP12{}).Cyclo6SquareNC(y6)
|
||||
t0.Mul(t0, y4).Mul(t0, y5)
|
||||
t1.Mul(y3, y5).Mul(t1, t0)
|
||||
t0.Mul(t0, y2)
|
||||
t1.SpecialSquare(t1).Mul(t1, t0).SpecialSquare(t1)
|
||||
t1.Cyclo6Square(t1).Mul(t1, t0).Cyclo6Square(t1)
|
||||
t0.Mul(t1, y1)
|
||||
t1.Mul(t1, y0)
|
||||
t0.SpecialSquare(t0).Mul(t0, t1)
|
||||
t0.Cyclo6Square(t0).Mul(t0, t1)
|
||||
|
||||
return t0
|
||||
}
|
||||
|
@ -50,7 +50,7 @@ func millerB6(q *twistPoint, p *curvePoint) *gfP12b6 {
|
||||
r := &twistPoint{}
|
||||
r.Set(aAffine)
|
||||
|
||||
r2 := (&gfP2{}).SquareNC(&aAffine.y)
|
||||
r2 := (&gfP2{}).Square(&aAffine.y)
|
||||
|
||||
a, b, c := &gfP2{}, &gfP2{}, &gfP2{}
|
||||
newR := &twistPoint{}
|
||||
@ -155,10 +155,9 @@ func finalExponentiationB6(in *gfP12b6) *gfP12b6 {
|
||||
y0.MulNC(fp, fp2).Mul(y0, fp3)
|
||||
|
||||
// reuse fp, fp2, fp3 local variables
|
||||
// [gfP12ExpU] is most time consuming operation
|
||||
fu := fp.gfP12ExpU(t1)
|
||||
fu2 := fp2.gfP12ExpU(fu)
|
||||
fu3 := fp3.gfP12ExpU(fu2)
|
||||
fu := fp.Cyclo6PowToU(t1)
|
||||
fu2 := fp2.Cyclo6PowToU(fu)
|
||||
fu3 := fp3.Cyclo6PowToU(fu2)
|
||||
|
||||
y3 := (&gfP12b6{}).Frobenius(fu)
|
||||
fu2p := (&gfP12b6{}).Frobenius(fu2)
|
||||
@ -174,14 +173,14 @@ func finalExponentiationB6(in *gfP12b6) *gfP12b6 {
|
||||
y6 := (&gfP12b6{}).MulNC(fu3, fu3p)
|
||||
y6.Conjugate(y6)
|
||||
|
||||
t0 := (&gfP12b6{}).SpecialSquareNC(y6)
|
||||
t0 := (&gfP12b6{}).Cyclo6SquareNC(y6)
|
||||
t0.Mul(t0, y4).Mul(t0, y5)
|
||||
t1.Mul(y3, y5).Mul(t1, t0)
|
||||
t0.Mul(t0, y2)
|
||||
t1.SpecialSquare(t1).Mul(t1, t0).SpecialSquare(t1)
|
||||
t1.Cyclo6Square(t1).Mul(t1, t0).Cyclo6Square(t1)
|
||||
t0.Mul(t1, y1)
|
||||
t1.Mul(t1, y0)
|
||||
t0.SpecialSquare(t0).Mul(t0, t1)
|
||||
t0.Cyclo6Square(t0).Mul(t0, t1)
|
||||
|
||||
return t0
|
||||
}
|
||||
|
@ -12,6 +12,7 @@ type curvePoint struct {
|
||||
}
|
||||
|
||||
var curveB = newGFp(5)
|
||||
var threeCurveB = newGFp(3 * 5)
|
||||
|
||||
// curveGen is the generator of G₁.
|
||||
var curveGen = &curvePoint{
|
||||
@ -82,125 +83,6 @@ func (c *curvePoint) IsInfinity() bool {
|
||||
return c.z.Equal(zero) == 1
|
||||
}
|
||||
|
||||
func (c *curvePoint) Add(a, b *curvePoint) {
|
||||
if a.IsInfinity() {
|
||||
c.Set(b)
|
||||
return
|
||||
}
|
||||
if b.IsInfinity() {
|
||||
c.Set(a)
|
||||
return
|
||||
}
|
||||
|
||||
// See http://hyperelliptic.org/EFD/g1p/auto-code/shortw/jacobian-0/addition/add-2007-bl.op3
|
||||
|
||||
// Normalize the points by replacing a = [x1:y1:z1] and b = [x2:y2:z2]
|
||||
// by [u1:s1:z1·z2] and [u2:s2:z1·z2]
|
||||
// where u1 = x1·z2², s1 = y1·z2³ and u1 = x2·z1², s2 = y2·z1³
|
||||
z12, z22 := &gfP{}, &gfP{}
|
||||
gfpSqr(z12, &a.z, 1)
|
||||
gfpSqr(z22, &b.z, 1)
|
||||
|
||||
u1, u2 := &gfP{}, &gfP{}
|
||||
gfpMul(u1, &a.x, z22)
|
||||
gfpMul(u2, &b.x, z12)
|
||||
|
||||
t, s1 := &gfP{}, &gfP{}
|
||||
gfpMul(t, &b.z, z22)
|
||||
gfpMul(s1, &a.y, t)
|
||||
|
||||
s2 := &gfP{}
|
||||
gfpMul(t, &a.z, z12)
|
||||
gfpMul(s2, &b.y, t)
|
||||
|
||||
// Compute x = (2h)²(s²-u1-u2)
|
||||
// where s = (s2-s1)/(u2-u1) is the slope of the line through
|
||||
// (u1,s1) and (u2,s2). The extra factor 2h = 2(u2-u1) comes from the value of z below.
|
||||
// This is also:
|
||||
// 4(s2-s1)² - 4h²(u1+u2) = 4(s2-s1)² - 4h³ - 4h²(2u1)
|
||||
// = r² - j - 2v
|
||||
// with the notations below.
|
||||
h := &gfP{}
|
||||
gfpSub(h, u2, u1)
|
||||
|
||||
gfpDouble(t, h)
|
||||
// i = 4h²
|
||||
i := &gfP{}
|
||||
gfpSqr(i, t, 1)
|
||||
// j = 4h³
|
||||
j := &gfP{}
|
||||
gfpMul(j, h, i)
|
||||
|
||||
gfpSub(t, s2, s1)
|
||||
|
||||
if h.Equal(zero) == 1 && t.Equal(one) == 1 {
|
||||
c.Double(a)
|
||||
return
|
||||
}
|
||||
r := &gfP{}
|
||||
gfpDouble(r, t)
|
||||
|
||||
v := &gfP{}
|
||||
gfpMul(v, u1, i)
|
||||
|
||||
// t4 = 4(s2-s1)²
|
||||
t4, t6 := &gfP{}, &gfP{}
|
||||
gfpSqr(t4, r, 1)
|
||||
gfpDouble(t, v)
|
||||
gfpSub(t6, t4, j)
|
||||
|
||||
gfpSub(&c.x, t6, t)
|
||||
|
||||
// Set y = -(2h)³(s1 + s*(x/4h²-u1))
|
||||
// This is also
|
||||
// y = - 2·s1·j - (s2-s1)(2x - 2i·u1) = r(v-x) - 2·s1·j
|
||||
gfpSub(t, v, &c.x) // t7
|
||||
gfpMul(t4, s1, j) // t8
|
||||
gfpDouble(t6, t4) // t9
|
||||
gfpMul(t4, r, t) // t10
|
||||
gfpSub(&c.y, t4, t6)
|
||||
|
||||
// Set z = 2(u2-u1)·z1·z2 = 2h·z1·z2
|
||||
gfpAdd(t, &a.z, &b.z) // t11
|
||||
gfpSqr(t4, t, 1) // t12
|
||||
gfpSub(t, t4, z12) // t13
|
||||
gfpSub(t4, t, z22) // t14
|
||||
gfpMul(&c.z, t4, h)
|
||||
}
|
||||
|
||||
func (c *curvePoint) Double(a *curvePoint) {
|
||||
// See http://hyperelliptic.org/EFD/g1p/auto-code/shortw/jacobian-0/doubling/dbl-2009-l.op3
|
||||
A, B, C := &gfP{}, &gfP{}, &gfP{}
|
||||
gfpSqr(A, &a.x, 1)
|
||||
gfpSqr(B, &a.y, 1)
|
||||
gfpSqr(C, B, 1)
|
||||
|
||||
t, t2 := &gfP{}, &gfP{}
|
||||
gfpAdd(t, &a.x, B)
|
||||
gfpSqr(t2, t, 1)
|
||||
gfpSub(t, t2, A)
|
||||
gfpSub(t2, t, C)
|
||||
|
||||
d, e, f := &gfP{}, &gfP{}, &gfP{}
|
||||
gfpAdd(d, t2, t2)
|
||||
gfpDouble(t, A)
|
||||
gfpAdd(e, t, A)
|
||||
gfpSqr(f, e, 1)
|
||||
|
||||
gfpDouble(t, d)
|
||||
gfpSub(&c.x, f, t)
|
||||
|
||||
gfpMul(&c.z, &a.y, &a.z)
|
||||
gfpDouble(&c.z, &c.z)
|
||||
|
||||
gfpDouble(t, C)
|
||||
gfpDouble(t2, t)
|
||||
gfpDouble(t, t2)
|
||||
gfpSub(&c.y, d, &c.x)
|
||||
gfpMul(t2, e, &c.y)
|
||||
gfpSub(&c.y, t2, t)
|
||||
}
|
||||
|
||||
func (c *curvePoint) Mul(a *curvePoint, scalar *big.Int) {
|
||||
sum, t := &curvePoint{}, &curvePoint{}
|
||||
sum.SetInfinity()
|
||||
@ -217,7 +99,10 @@ func (c *curvePoint) Mul(a *curvePoint, scalar *big.Int) {
|
||||
c.Set(sum)
|
||||
}
|
||||
|
||||
func (c *curvePoint) MakeAffine() {
|
||||
// MakeAffine reverses the Jacobian transform.
|
||||
// the Jacobian coordinates are (x1, y1, z1)
|
||||
// where x = x1/z1² and y = y1/z1³.
|
||||
func (c *curvePoint) AffineFromJacobian() {
|
||||
if c.z.Equal(one) == 1 {
|
||||
return
|
||||
} else if c.z.Equal(zero) == 1 {
|
||||
@ -231,11 +116,11 @@ func (c *curvePoint) MakeAffine() {
|
||||
zInv.Invert(&c.z)
|
||||
|
||||
t, zInv2 := &gfP{}, &gfP{}
|
||||
gfpMul(t, &c.y, zInv)
|
||||
gfpMul(t, &c.y, zInv) // t = y/z
|
||||
gfpSqr(zInv2, zInv, 1)
|
||||
|
||||
gfpMul(&c.x, &c.x, zInv2)
|
||||
gfpMul(&c.y, t, zInv2)
|
||||
gfpMul(&c.x, &c.x, zInv2) // x = x / z^2
|
||||
gfpMul(&c.y, t, zInv2) // y = y / z^3
|
||||
|
||||
c.z.Set(one)
|
||||
c.t.Set(one)
|
||||
@ -265,3 +150,123 @@ func (table *curvePointTable) Select(p *curvePoint, n uint8) {
|
||||
curvePointMovCond(p, f, p, cond)
|
||||
}
|
||||
}
|
||||
|
||||
// Equal compare e and other
|
||||
func (e *curvePoint) Equal(other *curvePoint) bool {
|
||||
return e.x.Equal(&other.x) == 1 &&
|
||||
e.y.Equal(&other.y) == 1 &&
|
||||
e.z.Equal(&other.z) == 1 &&
|
||||
e.t.Equal(&other.t) == 1
|
||||
}
|
||||
|
||||
// Below methods are POC yet, the line add/double functions are still based on
|
||||
// Jacobian coordination.
|
||||
func (c *curvePoint) Add(p1, p2 *curvePoint) {
|
||||
// Complete addition formula for a = 0 from "Complete addition formulas for
|
||||
// prime order elliptic curves" (https://eprint.iacr.org/2015/1060), §3.2.
|
||||
// Algorithm 7: Complete, projective point addition for prime order j-invariant 0 short Weierstrass curves.
|
||||
|
||||
t0, t1, t2, t3, t4 := new(gfP), new(gfP), new(gfP), new(gfP), new(gfP)
|
||||
x3, y3, z3 := new(gfP), new(gfP), new(gfP)
|
||||
gfpMul(t0, &p1.x, &p2.x) // t0 := X1X2
|
||||
gfpMul(t1, &p1.y, &p2.y) // t1 := Y1Y2
|
||||
gfpMul(t2, &p1.z, &p2.z) // t2 := Z1Z2
|
||||
gfpAdd(t3, &p1.x, &p1.y) // t3 := X1 + Y1
|
||||
gfpAdd(t4, &p2.x, &p2.y) // t4 := X2 + Y2
|
||||
gfpMul(t3, t3, t4) // t3 := t3 * t4 = (X1 + Y1) * (X2 + Y2)
|
||||
gfpAdd(t4, t0, t1) // t4 := t0 + t1
|
||||
gfpSub(t3, t3, t4) // t3 := t3 - t4 = X1Y2 + X2Y1
|
||||
gfpAdd(t4, &p1.y, &p1.z) // t4 := Y1 + Z1
|
||||
gfpAdd(x3, &p2.y, &p2.z) // X3 := Y2 + Z2
|
||||
gfpMul(t4, t4, x3) // t4 := t4 * X3 = (Y1 + Z1)(Y2 + Z2)
|
||||
gfpAdd(x3, t1, t2) // X3 := t1 + t2
|
||||
gfpSub(t4, t4, x3) // t4 := t4 - X3 = Y1Z2 + Y2Z1
|
||||
gfpAdd(x3, &p1.x, &p1.z) // X3 := X1 + Z1
|
||||
gfpAdd(y3, &p2.x, &p2.z) // Y3 := X2 + Z2
|
||||
gfpMul(x3, x3, y3) // X3 := X3 * Y3
|
||||
gfpAdd(y3, t0, t2) // Y3 := t0 + t2
|
||||
gfpSub(y3, x3, y3) // Y3 := X3 - Y3 = X1Z2 + X2Z1
|
||||
gfpTriple(t0, t0) // t0 := t0 + t0 + t0 = 3X1X2
|
||||
gfpMul(t2, threeCurveB, t2) // t2 := 3b * t2 = 3bZ1Z2
|
||||
gfpAdd(z3, t1, t2) // Z3 := t1 + t2 = Y1Y2 + 3bZ1Z2
|
||||
gfpSub(t1, t1, t2) // t1 := t1 - t2 = Y1Y2 - 3bZ1Z2
|
||||
gfpMul(y3, threeCurveB, y3) // Y3 = 3b * Y3 = 3b(X1Z2 + X2Z1)
|
||||
gfpMul(x3, t4, y3) // X3 := t4 * Y3 = 3b(X1Z2 + X2Z1)(Y1Z2 + Y2Z1)
|
||||
gfpMul(t2, t3, t1) // t2 := t3 * t1 = (X1Y2 + X2Y1)(Y1Y2 - 3bZ1Z2)
|
||||
gfpSub(x3, t2, x3) // X3 := t2 - X3 = (X1Y2 + X2Y1)(Y1Y2 - 3bZ1Z2) - 3b(Y1Z2 + Y2Z1)(X1Z2 + X2Z1)
|
||||
gfpMul(y3, y3, t0) // Y3 := Y3 * t0 = 9bX1X2(X1Z2 + X2Z1)
|
||||
gfpMul(t1, t1, z3) // t1 := t1 * Z3 = (Y1Y2 + 3bZ1Z2)(Y1Y2 - 3bZ1Z2)
|
||||
gfpAdd(y3, t1, y3) // Y3 := t1 + Y3 = (Y1Y2 + 3bZ1Z2)(Y1Y2 - 3bZ1Z2) + 9bX1X2(X1Z2 + X2Z1)
|
||||
gfpMul(t0, t0, t3) // t0 := t0 * t3 = 3X1X2(X1Y2 + X2Y1)
|
||||
gfpMul(z3, z3, t4) // Z3 := Z3 * t4 = (Y1Z2 + Y2Z1)(Y1Y2 + 3bZ1Z2)
|
||||
gfpAdd(z3, z3, t0) // Z3 := Z3 + t0 = (Y1Z2 + Y2Z1)(Y1Y2 + 3bZ1Z2) + 3X1X2(X1Y2 + X2Y1)
|
||||
|
||||
c.x.Set(x3)
|
||||
c.y.Set(y3)
|
||||
c.z.Set(z3)
|
||||
}
|
||||
|
||||
func (c *curvePoint) AddComplete(p1, p2 *curvePoint) {
|
||||
c.Add(p1, p2)
|
||||
}
|
||||
|
||||
func (c *curvePoint) Double(p *curvePoint) {
|
||||
// Complete addition formula for a = 0 from "Complete addition formulas for
|
||||
// prime order elliptic curves" (https://eprint.iacr.org/2015/1060), §3.2.
|
||||
// Algorithm 9: Exception-free point doubling for prime order j-invariant 0 short Weierstrass curves.
|
||||
t0, t1, t2 := new(gfP), new(gfP), new(gfP)
|
||||
x3, y3, z3 := new(gfP), new(gfP), new(gfP)
|
||||
|
||||
gfpSqr(t0, &p.y, 1) // t0 := Y^2
|
||||
gfpDouble(z3, t0) // Z3 := t0 + t0
|
||||
gfpDouble(z3, z3) // Z3 := Z3 + Z3
|
||||
gfpDouble(z3, z3) // Z3 := Z3 + Z3
|
||||
gfpMul(t1, &p.y, &p.z) // t1 := YZ
|
||||
gfpSqr(t2, &p.z, 1) // t0 := Z^2
|
||||
gfpMul(t2, threeCurveB, t2) // t2 := 3b * t2 = 3bZ^2
|
||||
gfpMul(x3, t2, z3) // X3 := t2 * Z3
|
||||
gfpAdd(y3, t0, t2) // Y3 := t0 + t2
|
||||
gfpMul(z3, t1, z3) // Z3 := t1 * Z3
|
||||
gfpTriple(t2, t2) // t2 := t2 + t2 + t2
|
||||
gfpSub(t0, t0, t2) // t0 := t0 - t2
|
||||
gfpMul(y3, t0, y3) // t0 := t0 * Y3
|
||||
gfpAdd(y3, x3, y3) // Y3 := X3 + Y3
|
||||
gfpMul(t1, &p.x, &p.y) // t1 := XY
|
||||
gfpMul(x3, t0, t1) // X3 := t0 * t1
|
||||
gfpDouble(x3, x3) // X3 := X3 + X3
|
||||
|
||||
c.x.Set(x3)
|
||||
c.y.Set(y3)
|
||||
c.z.Set(z3)
|
||||
}
|
||||
|
||||
func (c *curvePoint) DoubleComplete(p *curvePoint) {
|
||||
c.Double(p)
|
||||
}
|
||||
|
||||
// MakeAffine reverses the Projective transform.
|
||||
// A = 1/Z1
|
||||
// X3 = A*X1
|
||||
// Y3 = A*Y1
|
||||
// Z3 = 1
|
||||
func (c *curvePoint) MakeAffine() {
|
||||
// TODO: do we need to change it to constant-time implementation?
|
||||
if c.z.Equal(one) == 1 {
|
||||
return
|
||||
} else if c.z.Equal(zero) == 1 {
|
||||
c.x.Set(zero)
|
||||
c.y.Set(one)
|
||||
c.t.Set(zero)
|
||||
return
|
||||
}
|
||||
zInv := &gfP{}
|
||||
zInv.Invert(&c.z)
|
||||
gfpMul(&c.x, &c.x, zInv)
|
||||
gfpMul(&c.y, &c.y, zInv)
|
||||
c.z.Set(one)
|
||||
c.t.Set(one)
|
||||
}
|
||||
|
||||
func (c *curvePoint) AffineFromProjective() {
|
||||
c.MakeAffine()
|
||||
}
|
||||
|
@ -368,10 +368,7 @@ func (e *G1) Equal(other *G1) bool {
|
||||
if e.p == nil && other.p == nil {
|
||||
return true
|
||||
}
|
||||
return e.p.x.Equal(&other.p.x) == 1 &&
|
||||
e.p.y.Equal(&other.p.y) == 1 &&
|
||||
e.p.z.Equal(&other.p.z) == 1 &&
|
||||
e.p.t.Equal(&other.p.t) == 1
|
||||
return e.p.Equal(other.p)
|
||||
}
|
||||
|
||||
// IsOnCurve returns true if e is on the curve.
|
||||
|
@ -3,6 +3,7 @@ package bn256
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/rand"
|
||||
"fmt"
|
||||
"io"
|
||||
"math/big"
|
||||
"testing"
|
||||
@ -24,6 +25,24 @@ func TestG1AddNeg(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestG1AddSame(t *testing.T) {
|
||||
g1, g2 := &G1{}, &G1{}
|
||||
g1.Add(Gen1, Gen1)
|
||||
g2.Double(Gen1)
|
||||
|
||||
if !g1.Equal(g2) {
|
||||
t.Fail()
|
||||
}
|
||||
}
|
||||
|
||||
func TestCurvePointDouble(t *testing.T) {
|
||||
p := &curvePoint{}
|
||||
p.Double(p)
|
||||
if !p.IsInfinity() {
|
||||
t.Fail()
|
||||
}
|
||||
}
|
||||
|
||||
type g1BaseMultTest struct {
|
||||
k string
|
||||
}
|
||||
@ -157,35 +176,84 @@ func TestG1BaseMult(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestG1ScaleMult(t *testing.T) {
|
||||
k, e, err := RandomG1(rand.Reader)
|
||||
func TestG1ScalarMult(t *testing.T) {
|
||||
checkScalar := func(t *testing.T, scalar []byte) {
|
||||
p1, err := (&G1{}).ScalarBaseMult(scalar)
|
||||
fatalIfErr(t, err)
|
||||
p2, err := (&G1{}).ScalarMult(Gen1, scalar)
|
||||
fatalIfErr(t, err)
|
||||
p1.p.MakeAffine()
|
||||
p2.p.MakeAffine()
|
||||
if !p1.Equal(p2) {
|
||||
t.Error("[k]G != ScalarBaseMult(k)")
|
||||
}
|
||||
|
||||
d := new(big.Int).SetBytes(scalar)
|
||||
d.Sub(Order, d)
|
||||
d.Mod(d, Order)
|
||||
g1, err := (&G1{}).ScalarBaseMult(d.FillBytes(make([]byte, len(scalar))))
|
||||
fatalIfErr(t, err)
|
||||
g1.Add(g1, p1)
|
||||
g1.p.MakeAffine()
|
||||
if !g1.p.IsInfinity() {
|
||||
t.Error("[N - k]G + [k]G != ∞")
|
||||
}
|
||||
}
|
||||
|
||||
byteLen := len(Order.Bytes())
|
||||
bitLen := Order.BitLen()
|
||||
t.Run("0", func(t *testing.T) { checkScalar(t, make([]byte, byteLen)) })
|
||||
t.Run("1", func(t *testing.T) {
|
||||
checkScalar(t, big.NewInt(1).FillBytes(make([]byte, byteLen)))
|
||||
})
|
||||
t.Run("N-6", func(t *testing.T) {
|
||||
checkScalar(t, new(big.Int).Sub(Order, big.NewInt(6)).Bytes())
|
||||
})
|
||||
t.Run("N-1", func(t *testing.T) {
|
||||
checkScalar(t, new(big.Int).Sub(Order, big.NewInt(1)).Bytes())
|
||||
})
|
||||
t.Run("N", func(t *testing.T) { checkScalar(t, Order.Bytes()) })
|
||||
t.Run("N+1", func(t *testing.T) {
|
||||
checkScalar(t, new(big.Int).Add(Order, big.NewInt(1)).Bytes())
|
||||
})
|
||||
t.Run("N+22", func(t *testing.T) {
|
||||
checkScalar(t, new(big.Int).Add(Order, big.NewInt(22)).Bytes())
|
||||
})
|
||||
t.Run("all1s", func(t *testing.T) {
|
||||
s := new(big.Int).Lsh(big.NewInt(1), uint(bitLen))
|
||||
s.Sub(s, big.NewInt(1))
|
||||
checkScalar(t, s.Bytes())
|
||||
})
|
||||
if testing.Short() {
|
||||
return
|
||||
}
|
||||
for i := 0; i < bitLen; i++ {
|
||||
t.Run(fmt.Sprintf("1<<%d", i), func(t *testing.T) {
|
||||
s := new(big.Int).Lsh(big.NewInt(1), uint(i))
|
||||
checkScalar(t, s.FillBytes(make([]byte, byteLen)))
|
||||
})
|
||||
}
|
||||
for i := 0; i <= 64; i++ {
|
||||
t.Run(fmt.Sprintf("%d", i), func(t *testing.T) {
|
||||
checkScalar(t, big.NewInt(int64(i)).FillBytes(make([]byte, byteLen)))
|
||||
})
|
||||
}
|
||||
|
||||
// Test N-64...N+64 since they risk overlapping with precomputed table values
|
||||
// in the final additions.
|
||||
for i := int64(-64); i <= 64; i++ {
|
||||
t.Run(fmt.Sprintf("N%+d", i), func(t *testing.T) {
|
||||
checkScalar(t, new(big.Int).Add(Order, big.NewInt(i)).Bytes())
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func fatalIfErr(t *testing.T, err error) {
|
||||
t.Helper()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
e.p.MakeAffine()
|
||||
|
||||
e2, e3 := &G1{}, &G1{}
|
||||
|
||||
if e2.p == nil {
|
||||
e2.p = &curvePoint{}
|
||||
}
|
||||
|
||||
e2.p.Mul(curveGen, k)
|
||||
e2.p.MakeAffine()
|
||||
|
||||
if !e.Equal(e2) {
|
||||
t.Errorf("not same")
|
||||
}
|
||||
|
||||
_, err = e3.ScalarMult(Gen1, NormalizeScalar(k.Bytes()))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
e3.p.MakeAffine()
|
||||
|
||||
if !e.Equal(e3) {
|
||||
t.Errorf("not same")
|
||||
}
|
||||
}
|
||||
|
||||
func TestFuzz(t *testing.T) {
|
||||
@ -542,3 +610,131 @@ func BenchmarkMarshalUnmarshal(b *testing.B) {
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
func TestCurvePointAddComplete(t *testing.T) {
|
||||
t.Run("normal case", func(t *testing.T) {
|
||||
p1 := &curvePoint{}
|
||||
curvePointDouble(p1, curveGen)
|
||||
p1.AffineFromJacobian()
|
||||
|
||||
p2 := &curvePoint{}
|
||||
p2.AddComplete(p1, curveGen)
|
||||
p2.AffineFromProjective()
|
||||
|
||||
p3 := &curvePoint{}
|
||||
curvePointAdd(p3, curveGen, p1)
|
||||
p3.AffineFromJacobian()
|
||||
|
||||
if !p2.Equal(p3) {
|
||||
t.Errorf("Got %v, expected %v", p2, p3)
|
||||
}
|
||||
})
|
||||
t.Run("exception case: double", func(t *testing.T) {
|
||||
p2 := &curvePoint{}
|
||||
p2.AddComplete(curveGen, curveGen)
|
||||
p2.AffineFromProjective()
|
||||
|
||||
p3 := &curvePoint{}
|
||||
curvePointDouble(p3, curveGen)
|
||||
p3.AffineFromJacobian()
|
||||
if !p2.Equal(p3) {
|
||||
t.Errorf("Got %v, expected %v", p2, p3)
|
||||
}
|
||||
})
|
||||
t.Run("exception case: neg", func(t *testing.T) {
|
||||
p1 := &curvePoint{}
|
||||
p1.Neg(curveGen)
|
||||
p2 := &curvePoint{}
|
||||
p2.AddComplete(curveGen, p1)
|
||||
p2.AffineFromProjective()
|
||||
if !p2.IsInfinity() {
|
||||
t.Fatal("should be infinity")
|
||||
}
|
||||
})
|
||||
t.Run("exception case: IsInfinity", func(t *testing.T) {
|
||||
p1 := &curvePoint{}
|
||||
p1.SetInfinity()
|
||||
p2 := &curvePoint{}
|
||||
p2.AddComplete(curveGen, p1)
|
||||
p2.AffineFromProjective()
|
||||
if !p2.Equal(curveGen) {
|
||||
t.Fatal("should be curveGen")
|
||||
}
|
||||
p2.AddComplete(p1, curveGen)
|
||||
p2.AffineFromProjective()
|
||||
if !p2.Equal(curveGen) {
|
||||
t.Fatal("should be curveGen")
|
||||
}
|
||||
p2.AddComplete(p1, p1)
|
||||
p2.AffineFromProjective()
|
||||
if !p2.IsInfinity() {
|
||||
t.Fatal("should be infinity")
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func BenchmarkAddPoint(b *testing.B) {
|
||||
p1 := &curvePoint{}
|
||||
curvePointDouble(p1, curveGen)
|
||||
p1.AffineFromJacobian()
|
||||
p2 := &curvePoint{}
|
||||
|
||||
b.Run("Add complete", func(b *testing.B) {
|
||||
b.ReportAllocs()
|
||||
for i := 0; i < b.N; i++ {
|
||||
p2.AddComplete(curveGen, p1)
|
||||
}
|
||||
})
|
||||
|
||||
b.Run("Add traditional", func(b *testing.B) {
|
||||
b.ReportAllocs()
|
||||
for i := 0; i < b.N; i++ {
|
||||
curvePointAdd(p2, curveGen, p1)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func TestCurvePointDobuleComplete(t *testing.T) {
|
||||
t.Run("normal case", func(t *testing.T) {
|
||||
p2 := &curvePoint{}
|
||||
p2.DoubleComplete(curveGen)
|
||||
p2.AffineFromProjective()
|
||||
|
||||
p3 := &curvePoint{}
|
||||
curvePointDouble(p3, curveGen)
|
||||
p3.AffineFromJacobian()
|
||||
|
||||
if !p2.Equal(p3) {
|
||||
t.Errorf("Got %v, expected %v", p2, p3)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("exception case: IsInfinity", func(t *testing.T) {
|
||||
p1 := &curvePoint{}
|
||||
p1.SetInfinity()
|
||||
p2 := &curvePoint{}
|
||||
p2.DoubleComplete(p1)
|
||||
p2.AffineFromProjective()
|
||||
if !p2.IsInfinity() {
|
||||
t.Fatal("should be infinity")
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func BenchmarkDoublePoint(b *testing.B) {
|
||||
p2 := &curvePoint{}
|
||||
|
||||
b.Run("Double complete", func(b *testing.B) {
|
||||
b.ReportAllocs()
|
||||
for i := 0; i < b.N; i++ {
|
||||
p2.DoubleComplete(curveGen)
|
||||
}
|
||||
})
|
||||
|
||||
b.Run("Double traditional", func(b *testing.B) {
|
||||
b.ReportAllocs()
|
||||
for i := 0; i < b.N; i++ {
|
||||
curvePointDouble(p2, curveGen)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
@ -226,13 +226,19 @@ func (e *gfP12) SquareNC(a *gfP12) *gfP12 {
|
||||
return e
|
||||
}
|
||||
|
||||
// Special squaring for use on elements in T_6(fp2) (after the
|
||||
// easy part of the final exponentiation. Used in the hard part
|
||||
// of the final exponentiation. Function uses formulas in
|
||||
// Cyclo6Square is used in final exponentiation after easy part(a ^ ((p^2 + 1)(p^6-1))).
|
||||
// Note that after the easy part of the final exponentiation,
|
||||
// the resulting element lies in cyclotomic subgroup.
|
||||
// "New software speed records for cryptographic pairings"
|
||||
// Section 3.3, Final exponentiation
|
||||
// https://cryptojedi.org/papers/dclxvi-20100714.pdf
|
||||
// The fomula reference:
|
||||
// Granger/Scott (PKC2010).
|
||||
func (e *gfP12) SpecialSquare(a *gfP12) *gfP12 {
|
||||
// Section 3.2
|
||||
// https://eprint.iacr.org/2009/565.pdf
|
||||
func (e *gfP12) Cyclo6Square(a *gfP12) *gfP12 {
|
||||
tmp := &gfP12{}
|
||||
tmp.SpecialSquareNC(a)
|
||||
tmp.Cyclo6SquareNC(a)
|
||||
gfp12Copy(e, tmp)
|
||||
return e
|
||||
}
|
||||
@ -241,7 +247,7 @@ func (e *gfP12) SpecialSquare(a *gfP12) *gfP12 {
|
||||
// easy part of the final exponentiation. Used in the hard part
|
||||
// of the final exponentiation. Function uses formulas in
|
||||
// Granger/Scott (PKC2010).
|
||||
func (e *gfP12) SpecialSquares(a *gfP12, n int) *gfP12 {
|
||||
func (e *gfP12) Cyclo6Squares(a *gfP12, n int) *gfP12 {
|
||||
// Square first round
|
||||
in := &gfP12{}
|
||||
tx, ty, tz := &gfP4{}, &gfP4{}, &gfP4{}
|
||||
@ -306,7 +312,7 @@ func (e *gfP12) SpecialSquares(a *gfP12, n int) *gfP12 {
|
||||
}
|
||||
|
||||
// Special Square without value copy, will use e directly, so e can't be same as a.
|
||||
func (e *gfP12) SpecialSquareNC(a *gfP12) *gfP12 {
|
||||
func (e *gfP12) Cyclo6SquareNC(a *gfP12) *gfP12 {
|
||||
tx, ty, tz := &gfP4{}, &gfP4{}, &gfP4{}
|
||||
|
||||
v0 := &e.x
|
||||
|
@ -201,20 +201,26 @@ func (e *gfP12b6) SquareNC(a *gfP12b6) *gfP12b6 {
|
||||
return e
|
||||
}
|
||||
|
||||
// Special squaring for use on elements in T_6(fp2) (after the
|
||||
// easy part of the final exponentiation. Used in the hard part
|
||||
// of the final exponentiation. Function uses formulas in
|
||||
// Cyclo6Square is used in final exponentiation after easy part(a ^ ((p^2 + 1)(p^6-1))).
|
||||
// Note that after the easy part of the final exponentiation,
|
||||
// the resulting element lies in cyclotomic subgroup.
|
||||
// "New software speed records for cryptographic pairings"
|
||||
// Section 3.3, Final exponentiation
|
||||
// https://cryptojedi.org/papers/dclxvi-20100714.pdf
|
||||
// The fomula reference:
|
||||
// Granger/Scott (PKC2010).
|
||||
func (e *gfP12b6) SpecialSquare(a *gfP12b6) *gfP12b6 {
|
||||
// Section 3.2
|
||||
// https://eprint.iacr.org/2009/565.pdf
|
||||
func (e *gfP12b6) Cyclo6Square(a *gfP12b6) *gfP12b6 {
|
||||
tmp := &gfP12b6{}
|
||||
tmp.SpecialSquareNC(a)
|
||||
tmp.Cyclo6SquareNC(a)
|
||||
e.x.Set(&tmp.x)
|
||||
e.y.Set(&tmp.y)
|
||||
return e
|
||||
}
|
||||
|
||||
// Special Square without value copy, will use e directly, so e can't be same as a.
|
||||
func (e *gfP12b6) SpecialSquareNC(a *gfP12b6) *gfP12b6 {
|
||||
func (e *gfP12b6) Cyclo6SquareNC(a *gfP12b6) *gfP12b6 {
|
||||
f02 := &e.y.x
|
||||
f01 := &e.y.y
|
||||
f00 := &e.y.z
|
||||
@ -232,28 +238,28 @@ func (e *gfP12b6) SpecialSquareNC(a *gfP12b6) *gfP12b6 {
|
||||
t02.Set(t10)
|
||||
t10.Set(f00)
|
||||
|
||||
f00.Double(t00)
|
||||
f00.Add(t00, t00)
|
||||
t00.Add(f00, t00)
|
||||
f00.Double(t01)
|
||||
f00.Add(t01, t01)
|
||||
t01.Add(f00, t01)
|
||||
f00.Double(t02)
|
||||
f00.Add(t02, t02)
|
||||
t02.Add(f00, t02)
|
||||
f00.Double(t10)
|
||||
f00.Add(t10, t10)
|
||||
t10.Add(f00, t10)
|
||||
f00.Double(t11)
|
||||
f00.Add(t11, t11)
|
||||
t11.Add(f00, t11)
|
||||
f00.Double(t12)
|
||||
f00.Add(t12, t12)
|
||||
t12.Add(f00, t12)
|
||||
|
||||
f00.Double(&a.y.z)
|
||||
f00.Add(&a.y.z, &a.y.z)
|
||||
f00.Neg(f00)
|
||||
f01.Double(&a.y.y)
|
||||
f01.Add(&a.y.y, &a.y.y)
|
||||
f01.Neg(f01)
|
||||
f02.Double(&a.y.x)
|
||||
f02.Add(&a.y.x, &a.y.x)
|
||||
f02.Neg(f02)
|
||||
f10.Double(&a.x.z)
|
||||
f11.Double(&a.x.y)
|
||||
f12.Double(&a.x.x)
|
||||
f10.Add(&a.x.z, &a.x.z)
|
||||
f11.Add(&a.x.y, &a.x.y)
|
||||
f12.Add(&a.x.x, &a.x.x)
|
||||
|
||||
f00.Add(f00, t00)
|
||||
f01.Add(f01, t01)
|
||||
@ -265,7 +271,7 @@ func (e *gfP12b6) SpecialSquareNC(a *gfP12b6) *gfP12b6 {
|
||||
return e
|
||||
}
|
||||
|
||||
func (e *gfP12b6) SpecialSquares(a *gfP12b6, n int) *gfP12b6 {
|
||||
func (e *gfP12b6) Cyclo6Squares(a *gfP12b6, n int) *gfP12b6 {
|
||||
// Square first round
|
||||
in := &gfP12b6{}
|
||||
f02 := &in.y.x
|
||||
@ -284,28 +290,28 @@ func (e *gfP12b6) SpecialSquares(a *gfP12b6, n int) *gfP12b6 {
|
||||
t02.Set(t10)
|
||||
t10.Set(f00)
|
||||
|
||||
f00.Double(t00)
|
||||
f00.Add(t00, t00)
|
||||
t00.Add(f00, t00)
|
||||
f00.Double(t01)
|
||||
f00.Add(t01, t01)
|
||||
t01.Add(f00, t01)
|
||||
f00.Double(t02)
|
||||
f00.Add(t02, t02)
|
||||
t02.Add(f00, t02)
|
||||
f00.Double(t10)
|
||||
f00.Add(t10, t10)
|
||||
t10.Add(f00, t10)
|
||||
f00.Double(t11)
|
||||
f00.Add(t11, t11)
|
||||
t11.Add(f00, t11)
|
||||
f00.Double(t12)
|
||||
f00.Add(t12, t12)
|
||||
t12.Add(f00, t12)
|
||||
|
||||
f00.Double(&a.y.z)
|
||||
f00.Add(&a.y.z, &a.y.z)
|
||||
f00.Neg(f00)
|
||||
f01.Double(&a.y.y)
|
||||
f01.Add(&a.y.y, &a.y.y)
|
||||
f01.Neg(f01)
|
||||
f02.Double(&a.y.x)
|
||||
f02.Add(&a.y.x, &a.y.x)
|
||||
f02.Neg(f02)
|
||||
f10.Double(&a.x.z)
|
||||
f11.Double(&a.x.y)
|
||||
f12.Double(&a.x.x)
|
||||
f10.Add(&a.x.z, &a.x.z)
|
||||
f11.Add(&a.x.y, &a.x.y)
|
||||
f12.Add(&a.x.x, &a.x.x)
|
||||
|
||||
f00.Add(f00, t00)
|
||||
f01.Add(f01, t01)
|
||||
@ -333,28 +339,28 @@ func (e *gfP12b6) SpecialSquares(a *gfP12b6, n int) *gfP12b6 {
|
||||
t02.Set(t10)
|
||||
t10.Set(f00)
|
||||
|
||||
f00.Double(t00)
|
||||
f00.Add(t00, t00)
|
||||
t00.Add(f00, t00)
|
||||
f00.Double(t01)
|
||||
f00.Add(t01, t01)
|
||||
t01.Add(f00, t01)
|
||||
f00.Double(t02)
|
||||
f00.Add(t02, t02)
|
||||
t02.Add(f00, t02)
|
||||
f00.Double(t10)
|
||||
f00.Add(t10, t10)
|
||||
t10.Add(f00, t10)
|
||||
f00.Double(t11)
|
||||
f00.Add(t11, t11)
|
||||
t11.Add(f00, t11)
|
||||
f00.Double(t12)
|
||||
f00.Add(t12, t12)
|
||||
t12.Add(f00, t12)
|
||||
|
||||
f00.Double(&in.y.z)
|
||||
f00.Add(&in.y.z, &in.y.z)
|
||||
f00.Neg(f00)
|
||||
f01.Double(&in.y.y)
|
||||
f01.Add(&in.y.y, &in.y.y)
|
||||
f01.Neg(f01)
|
||||
f02.Double(&in.y.x)
|
||||
f02.Add(&in.y.x, &in.y.x)
|
||||
f02.Neg(f02)
|
||||
f10.Double(&in.x.z)
|
||||
f11.Double(&in.x.y)
|
||||
f12.Double(&in.x.x)
|
||||
f10.Add(&in.x.z, &in.x.z)
|
||||
f11.Add(&in.x.y, &in.x.y)
|
||||
f12.Add(&in.x.x, &in.x.x)
|
||||
|
||||
f00.Add(f00, t00)
|
||||
f01.Add(f01, t01)
|
||||
@ -374,12 +380,12 @@ func (e *gfP12b6) SpecialSquares(a *gfP12b6, n int) *gfP12b6 {
|
||||
}
|
||||
|
||||
func gfP4Square(retX, retY, x, y *gfP2) {
|
||||
retX.SquareUNC(x)
|
||||
retY.SquareNC(y)
|
||||
retX.SquareU(x)
|
||||
retY.Square(y)
|
||||
retY.Add(retX, retY)
|
||||
|
||||
retX.MulNC(x, y)
|
||||
retX.Double(retX)
|
||||
retX.Mul(x, y)
|
||||
retX.Add(retX, retX)
|
||||
}
|
||||
|
||||
func (c *gfP12b6) Exp(a *gfP12b6, power *big.Int) *gfP12b6 {
|
||||
|
@ -330,7 +330,7 @@ func TestGfP12b6SpecialSquare(t *testing.T) {
|
||||
|
||||
got := &gfP12b6{}
|
||||
expected := &gfP12b6{}
|
||||
got.SpecialSquare(t1)
|
||||
got.Cyclo6Square(t1)
|
||||
expected.Square(t1)
|
||||
if *got != *expected {
|
||||
t.Errorf("not same got=%v, expected=%v", got, expected)
|
||||
|
@ -1,7 +1,7 @@
|
||||
package bn256
|
||||
|
||||
// Use special square
|
||||
func (e *gfP12) gfP12ExpU(x *gfP12) *gfP12 {
|
||||
func (e *gfP12) Cyclo6PowToU(x *gfP12) *gfP12 {
|
||||
// The sequence of 10 multiplications and 61 squarings is derived from the
|
||||
// following addition chain generated with github.com/mmcloughlin/addchain v0.4.0.
|
||||
//
|
||||
@ -21,23 +21,23 @@ func (e *gfP12) gfP12ExpU(x *gfP12) *gfP12 {
|
||||
var t2 = new(gfP12)
|
||||
var t3 = new(gfP12)
|
||||
|
||||
t2.SpecialSquareNC(x)
|
||||
t1.SpecialSquareNC(t2)
|
||||
t2.Cyclo6SquareNC(x)
|
||||
t1.Cyclo6SquareNC(t2)
|
||||
z.MulNC(x, t1)
|
||||
t0.MulNC(t1, z)
|
||||
t2.Mul(t2, t0)
|
||||
t3.MulNC(x, t2)
|
||||
t3.SpecialSquares(t3, 40)
|
||||
t3.Cyclo6Squares(t3, 40)
|
||||
t3.Mul(t2, t3)
|
||||
t3.SpecialSquares(t3, 7)
|
||||
t3.Cyclo6Squares(t3, 7)
|
||||
t2.Mul(t2, t3)
|
||||
t1.Mul(t1, t2)
|
||||
t1.SpecialSquares(t1, 4)
|
||||
t1.Cyclo6Squares(t1, 4)
|
||||
t0.Mul(t0, t1)
|
||||
t0.SpecialSquare(t0)
|
||||
t0.Cyclo6Square(t0)
|
||||
t0.Mul(x, t0)
|
||||
t0.SpecialSquares(t0, 6)
|
||||
t0.Cyclo6Squares(t0, 6)
|
||||
z.Mul(z, t0)
|
||||
z.SpecialSquare(z)
|
||||
z.Cyclo6Square(z)
|
||||
return e
|
||||
}
|
||||
|
@ -35,7 +35,7 @@ func Test_gfP12Square(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestSpecialSquare(t *testing.T) {
|
||||
func TestCyclo6Square(t *testing.T) {
|
||||
in := &gfP12{
|
||||
testdataP4,
|
||||
testdataP4,
|
||||
@ -51,9 +51,18 @@ func TestSpecialSquare(t *testing.T) {
|
||||
t2 := inv.FrobeniusP2(t1) // reuse inv
|
||||
t1.Mul(t1, t2) // t1 = in ^ ((p^6 - 1) * (p^2 + 1)), the first two parts of the exponentiation
|
||||
|
||||
one := (&gfP12{}).SetOne()
|
||||
t3 := (&gfP12{}).FrobeniusP2(t1)
|
||||
t4 := (&gfP12{}).FrobeniusP2(t3)
|
||||
t5 := (&gfP12{}).Invert(t3)
|
||||
t5.Mul(t4, t5).Mul(t1, t5)
|
||||
if *t5 != *one {
|
||||
t.Errorf("t1 should be in Cyclotomic Subgroup")
|
||||
}
|
||||
|
||||
got := &gfP12{}
|
||||
expected := &gfP12{}
|
||||
got.SpecialSquare(t1)
|
||||
got.Cyclo6Square(t1)
|
||||
expected.Square(t1)
|
||||
if *got != *expected {
|
||||
t.Errorf("not same got=%v, expected=%v", got, expected)
|
||||
@ -74,7 +83,7 @@ func BenchmarkGfP12Square(b *testing.B) {
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkGfP12SpecialSquare(b *testing.B) {
|
||||
func BenchmarkGfP12Cyclo6Square(b *testing.B) {
|
||||
in := &gfP12{
|
||||
testdataP4,
|
||||
testdataP4,
|
||||
@ -93,7 +102,7 @@ func BenchmarkGfP12SpecialSquare(b *testing.B) {
|
||||
b.ReportAllocs()
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
x2.SpecialSquare(t1)
|
||||
x2.Cyclo6Square(t1)
|
||||
}
|
||||
}
|
||||
|
||||
@ -116,7 +125,7 @@ func BenchmarkGfP12SpecialSqures(b *testing.B) {
|
||||
b.ReportAllocs()
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
got.SpecialSquares(in, 61)
|
||||
got.Cyclo6Squares(in, 61)
|
||||
}
|
||||
}
|
||||
|
||||
@ -433,13 +442,22 @@ func BenchmarkGfP12ExpU(b *testing.B) {
|
||||
testdataP4,
|
||||
testdataP4,
|
||||
}
|
||||
// This is the p^6-Frobenius
|
||||
t1 := (&gfP12{}).FrobeniusP6(x)
|
||||
|
||||
inv := (&gfP12{}).Invert(x)
|
||||
t1.Mul(t1, inv)
|
||||
|
||||
t2 := inv.FrobeniusP2(t1) // reuse inv
|
||||
t1.Mul(t1, t2) // t1 = in ^ ((p^6 - 1) * (p^2 + 1)), the first two parts of the exponentiation
|
||||
|
||||
got := &gfP12{}
|
||||
b.ReportAllocs()
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
got.gfP12ExpU(x)
|
||||
got.gfP12ExpU(x)
|
||||
got.gfP12ExpU(x)
|
||||
got.Cyclo6PowToU(t1)
|
||||
got.Cyclo6PowToU(t1)
|
||||
got.Cyclo6PowToU(t1)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
package bn256
|
||||
|
||||
// Use special square
|
||||
func (e *gfP12b6) gfP12ExpU(x *gfP12b6) *gfP12b6 {
|
||||
func (e *gfP12b6) Cyclo6PowToU(x *gfP12b6) *gfP12b6 {
|
||||
// The sequence of 10 multiplications and 61 squarings is derived from the
|
||||
// following addition chain generated with github.com/mmcloughlin/addchain v0.4.0.
|
||||
//
|
||||
@ -21,23 +21,23 @@ func (e *gfP12b6) gfP12ExpU(x *gfP12b6) *gfP12b6 {
|
||||
var t2 = new(gfP12b6)
|
||||
var t3 = new(gfP12b6)
|
||||
|
||||
t2.SpecialSquareNC(x)
|
||||
t1.SpecialSquareNC(t2)
|
||||
t2.Cyclo6SquareNC(x)
|
||||
t1.Cyclo6SquareNC(t2)
|
||||
z.MulNC(x, t1)
|
||||
t0.MulNC(t1, z)
|
||||
t2.Mul(t2, t0)
|
||||
t3.MulNC(x, t2)
|
||||
t3.SpecialSquares(t3, 40)
|
||||
t3.Cyclo6Squares(t3, 40)
|
||||
t3.Mul(t2, t3)
|
||||
t3.SpecialSquares(t3, 7)
|
||||
t3.Cyclo6Squares(t3, 7)
|
||||
t2.Mul(t2, t3)
|
||||
t1.Mul(t1, t2)
|
||||
t1.SpecialSquares(t1, 4)
|
||||
t1.Cyclo6Squares(t1, 4)
|
||||
t0.Mul(t0, t1)
|
||||
t0.SpecialSquare(t0)
|
||||
t0.Cyclo6Square(t0)
|
||||
t0.Mul(x, t0)
|
||||
t0.SpecialSquares(t0, 6)
|
||||
t0.Cyclo6Squares(t0, 6)
|
||||
z.Mul(z, t0)
|
||||
z.SpecialSquare(z)
|
||||
z.Cyclo6Square(z)
|
||||
return e
|
||||
}
|
||||
|
@ -116,37 +116,7 @@ func (e *gfP2) Triple(a *gfP2) *gfP2 {
|
||||
// c0 = a0*b0 - 2a1*b1
|
||||
// c1 = (a0 + a1)(b0 + b1) - a0*b0 - a1*b1 = a0*b1 + a1*b0
|
||||
func (e *gfP2) Mul(a, b *gfP2) *gfP2 {
|
||||
tmp := &gfP2{}
|
||||
tmp.MulNC(a, b)
|
||||
gfp2Copy(e, tmp)
|
||||
return e
|
||||
}
|
||||
|
||||
// Mul without value copy, will use e directly, so e can't be same as a and b.
|
||||
func (e *gfP2) MulNC(a, b *gfP2) *gfP2 {
|
||||
tx := &e.x
|
||||
ty := &e.y
|
||||
v0, v1 := &gfP{}, &gfP{}
|
||||
|
||||
gfpMul(v0, &a.y, &b.y)
|
||||
gfpMul(v1, &a.x, &b.x)
|
||||
|
||||
gfpAdd(tx, &a.x, &a.y)
|
||||
gfpAdd(ty, &b.x, &b.y)
|
||||
gfpMul(tx, tx, ty)
|
||||
gfpSub(tx, tx, v0)
|
||||
gfpSub(tx, tx, v1)
|
||||
|
||||
gfpSub(ty, v0, v1)
|
||||
gfpSub(ty, ty, v1)
|
||||
|
||||
return e
|
||||
}
|
||||
|
||||
func (e *gfP2) MulU(a, b *gfP2) *gfP2 {
|
||||
tmp := &gfP2{}
|
||||
tmp.MulUNC(a, b)
|
||||
gfp2Copy(e, tmp)
|
||||
gfp2Mul(e, a, b)
|
||||
return e
|
||||
}
|
||||
|
||||
@ -155,26 +125,8 @@ func (e *gfP2) MulU(a, b *gfP2) *gfP2 {
|
||||
// (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)
|
||||
func (e *gfP2) MulUNC(a, b *gfP2) *gfP2 {
|
||||
tx := &e.x
|
||||
ty := &e.y
|
||||
v0, v1 := &gfP{}, &gfP{}
|
||||
|
||||
gfpMul(v0, &a.y, &b.y)
|
||||
gfpMul(v1, &a.x, &b.x)
|
||||
|
||||
gfpAdd(tx, &a.x, &a.y)
|
||||
gfpAdd(ty, &b.x, &b.y)
|
||||
|
||||
gfpMul(ty, tx, ty)
|
||||
gfpSub(ty, ty, v0)
|
||||
gfpSub(ty, ty, v1)
|
||||
gfpDouble(ty, ty)
|
||||
gfpNeg(ty, ty)
|
||||
|
||||
gfpSub(tx, v0, v1)
|
||||
gfpSub(tx, tx, v1)
|
||||
|
||||
func (e *gfP2) MulU(a, b *gfP2) *gfP2 {
|
||||
gfp2MulU(e, a, b)
|
||||
return e
|
||||
}
|
||||
|
||||
@ -195,57 +147,14 @@ func (e *gfP2) MulU1(a *gfP2) *gfP2 {
|
||||
func (e *gfP2) Square(a *gfP2) *gfP2 {
|
||||
// Complex squaring algorithm:
|
||||
// (xu+y)² = y^2-2*x^2 + 2*u*x*y
|
||||
tmp := &gfP2{}
|
||||
tmp.SquareNC(a)
|
||||
gfp2Copy(e, tmp)
|
||||
return e
|
||||
}
|
||||
|
||||
// Square without value copy, will use e directly, so e can't be same as a.
|
||||
func (e *gfP2) SquareNC(a *gfP2) *gfP2 {
|
||||
// Complex squaring algorithm:
|
||||
// (xu+y)² = y^2-2*x^2 + 2*u*x*y
|
||||
tx := &e.x
|
||||
ty := &e.y
|
||||
|
||||
gfpAdd(ty, &a.x, &a.y)
|
||||
gfpDouble(tx, &a.x)
|
||||
gfpSub(tx, &a.y, tx)
|
||||
gfpMul(ty, tx, ty)
|
||||
gfpMul(tx, &a.x, &a.y)
|
||||
gfpAdd(ty, tx, ty)
|
||||
gfpDouble(tx, tx)
|
||||
|
||||
gfp2Square(e, a)
|
||||
return e
|
||||
}
|
||||
|
||||
func (e *gfP2) SquareU(a *gfP2) *gfP2 {
|
||||
// Complex squaring algorithm:
|
||||
// (xu+y)²*u = (y^2-2*x^2)u - 4*x*y
|
||||
|
||||
tmp := &gfP2{}
|
||||
tmp.SquareUNC(a)
|
||||
gfp2Copy(e, tmp)
|
||||
return e
|
||||
}
|
||||
|
||||
// SquareU without value copy, will use e directly, so e can't be same as a.
|
||||
func (e *gfP2) SquareUNC(a *gfP2) *gfP2 {
|
||||
// Complex squaring algorithm:
|
||||
// (xu+y)²*u = (y^2-2*x^2)u - 4*x*y
|
||||
tx := &e.x
|
||||
ty := &e.y
|
||||
|
||||
gfpAdd(tx, &a.x, &a.y)
|
||||
gfpDouble(ty, &a.x)
|
||||
gfpSub(ty, &a.y, ty)
|
||||
gfpMul(tx, tx, ty)
|
||||
gfpMul(ty, &a.x, &a.y)
|
||||
gfpAdd(tx, tx, ty)
|
||||
gfpDouble(ty, ty)
|
||||
gfpDouble(ty, ty)
|
||||
gfpNeg(ty, ty)
|
||||
|
||||
gfp2SquareU(e, a)
|
||||
return e
|
||||
}
|
||||
|
||||
|
1653
sm9/bn256/gfp2_g1_amd64.s
Normal file
1653
sm9/bn256/gfp2_g1_amd64.s
Normal file
File diff suppressed because it is too large
Load Diff
36
sm9/bn256/gfp2_g1_decl.go
Normal file
36
sm9/bn256/gfp2_g1_decl.go
Normal file
@ -0,0 +1,36 @@
|
||||
//go:build amd64 && !purego
|
||||
// +build amd64,!purego
|
||||
|
||||
package bn256
|
||||
|
||||
// gfP2 multiplication.
|
||||
//
|
||||
//go:noescape
|
||||
func gfp2Mul(c, a, b *gfP2)
|
||||
|
||||
// gfP2 multiplication. c = a*b*u
|
||||
//
|
||||
//go:noescape
|
||||
func gfp2MulU(c, a, b *gfP2)
|
||||
|
||||
// gfP2 square.
|
||||
//
|
||||
//go:noescape
|
||||
func gfp2Square(c, a *gfP2)
|
||||
|
||||
// gfP2 square and mult u.
|
||||
//
|
||||
//go:noescape
|
||||
func gfp2SquareU(c, a *gfP2)
|
||||
|
||||
// Point doubling. Sets res = in + in. in can be the point at infinity.
|
||||
//
|
||||
//go:noescape
|
||||
func curvePointDouble(c, a *curvePoint)
|
||||
|
||||
// Point addition. Sets res = in1 + in2. Returns one if the two input points
|
||||
// were equal and zero otherwise. If in1 or in2 are the point at infinity, res
|
||||
// and the return value are undefined.
|
||||
//
|
||||
//go:noescape
|
||||
func curvePointAdd(c, a, b *curvePoint) int
|
193
sm9/bn256/gfp2_g1_generic.go
Normal file
193
sm9/bn256/gfp2_g1_generic.go
Normal file
@ -0,0 +1,193 @@
|
||||
//go:build (!amd64) || purego
|
||||
// +build !amd64 purego
|
||||
|
||||
package bn256
|
||||
|
||||
func gfp2Mul(c, a, b *gfP2) {
|
||||
tmp := &gfP2{}
|
||||
tx := &tmp.x
|
||||
ty := &tmp.y
|
||||
v0, v1 := &gfP{}, &gfP{}
|
||||
|
||||
gfpMul(v0, &a.y, &b.y)
|
||||
gfpMul(v1, &a.x, &b.x)
|
||||
|
||||
gfpAdd(tx, &a.x, &a.y)
|
||||
gfpAdd(ty, &b.x, &b.y)
|
||||
gfpMul(tx, tx, ty)
|
||||
gfpSub(tx, tx, v0)
|
||||
gfpSub(tx, tx, v1)
|
||||
|
||||
gfpSub(ty, v0, v1)
|
||||
gfpSub(ty, ty, v1)
|
||||
|
||||
gfp2Copy(c, tmp)
|
||||
}
|
||||
|
||||
func gfp2MulU(c, a, b *gfP2) {
|
||||
tmp := &gfP2{}
|
||||
tx := &tmp.x
|
||||
ty := &tmp.y
|
||||
v0, v1 := &gfP{}, &gfP{}
|
||||
|
||||
gfpMul(v0, &a.y, &b.y)
|
||||
gfpMul(v1, &a.x, &b.x)
|
||||
|
||||
gfpAdd(tx, &a.x, &a.y)
|
||||
gfpAdd(ty, &b.x, &b.y)
|
||||
|
||||
gfpMul(ty, tx, ty)
|
||||
gfpSub(ty, ty, v0)
|
||||
gfpSub(ty, ty, v1)
|
||||
gfpDouble(ty, ty)
|
||||
gfpNeg(ty, ty)
|
||||
|
||||
gfpSub(tx, v0, v1)
|
||||
gfpSub(tx, tx, v1)
|
||||
|
||||
gfp2Copy(c, tmp)
|
||||
}
|
||||
|
||||
func gfp2Square(c, a *gfP2) {
|
||||
tmp := &gfP2{}
|
||||
tx := &tmp.x
|
||||
ty := &tmp.y
|
||||
|
||||
gfpAdd(ty, &a.x, &a.y)
|
||||
gfpDouble(tx, &a.x)
|
||||
gfpSub(tx, &a.y, tx)
|
||||
gfpMul(ty, tx, ty)
|
||||
gfpMul(tx, &a.x, &a.y)
|
||||
gfpAdd(ty, tx, ty)
|
||||
gfpDouble(tx, tx)
|
||||
|
||||
gfp2Copy(c, tmp)
|
||||
}
|
||||
|
||||
func gfp2SquareU(c, a *gfP2) {
|
||||
tmp := &gfP2{}
|
||||
tx := &tmp.x
|
||||
ty := &tmp.y
|
||||
|
||||
gfpAdd(tx, &a.x, &a.y)
|
||||
gfpDouble(ty, &a.x)
|
||||
gfpSub(ty, &a.y, ty)
|
||||
gfpMul(tx, tx, ty)
|
||||
gfpMul(ty, &a.x, &a.y)
|
||||
gfpAdd(tx, tx, ty)
|
||||
gfpDouble(ty, ty)
|
||||
gfpDouble(ty, ty)
|
||||
gfpNeg(ty, ty)
|
||||
|
||||
gfp2Copy(c, tmp)
|
||||
}
|
||||
|
||||
func curvePointDouble(c, a *curvePoint) {
|
||||
// See http://hyperelliptic.org/EFD/g1p/auto-code/shortw/jacobian-0/doubling/dbl-2009-l.op3
|
||||
A, B, C := &gfP{}, &gfP{}, &gfP{}
|
||||
gfpSqr(A, &a.x, 1)
|
||||
gfpSqr(B, &a.y, 1)
|
||||
gfpSqr(C, B, 1)
|
||||
|
||||
t := &gfP{}
|
||||
gfpAdd(B, &a.x, B)
|
||||
gfpSqr(t, B, 1)
|
||||
gfpSub(B, t, A)
|
||||
gfpSub(t, B, C)
|
||||
|
||||
d, e := &gfP{}, &gfP{}
|
||||
gfpDouble(d, t)
|
||||
gfpDouble(B, A)
|
||||
gfpAdd(e, B, A)
|
||||
gfpSqr(A, e, 1)
|
||||
|
||||
gfpDouble(B, d)
|
||||
gfpSub(&c.x, A, B)
|
||||
|
||||
gfpMul(&c.z, &a.y, &a.z)
|
||||
gfpDouble(&c.z, &c.z)
|
||||
|
||||
gfpDouble(B, C)
|
||||
gfpDouble(t, B)
|
||||
gfpDouble(B, t)
|
||||
gfpSub(&c.y, d, &c.x)
|
||||
gfpMul(t, e, &c.y)
|
||||
gfpSub(&c.y, t, B)
|
||||
}
|
||||
|
||||
func curvePointAdd(c, a, b *curvePoint) int {
|
||||
// See http://hyperelliptic.org/EFD/g1p/auto-code/shortw/jacobian-0/addition/add-2007-bl.op3
|
||||
var pointEq int
|
||||
// Normalize the points by replacing a = [x1:y1:z1] and b = [x2:y2:z2]
|
||||
// by [u1:s1:z1·z2] and [u2:s2:z1·z2]
|
||||
// where u1 = x1·z2², s1 = y1·z2³ and u1 = x2·z1², s2 = y2·z1³
|
||||
z12, z22 := &gfP{}, &gfP{}
|
||||
gfpSqr(z12, &a.z, 1)
|
||||
gfpSqr(z22, &b.z, 1)
|
||||
|
||||
u1, u2 := &gfP{}, &gfP{}
|
||||
gfpMul(u1, &a.x, z22)
|
||||
gfpMul(u2, &b.x, z12)
|
||||
|
||||
t, s1 := &gfP{}, &gfP{}
|
||||
gfpMul(t, &b.z, z22)
|
||||
gfpMul(s1, &a.y, t)
|
||||
|
||||
s2 := &gfP{}
|
||||
gfpMul(t, &a.z, z12)
|
||||
gfpMul(s2, &b.y, t)
|
||||
|
||||
// Compute x = (2h)²(s²-u1-u2)
|
||||
// where s = (s2-s1)/(u2-u1) is the slope of the line through
|
||||
// (u1,s1) and (u2,s2). The extra factor 2h = 2(u2-u1) comes from the value of z below.
|
||||
// This is also:
|
||||
// 4(s2-s1)² - 4h²(u1+u2) = 4(s2-s1)² - 4h³ - 4h²(2u1)
|
||||
// = r² - j - 2v
|
||||
// with the notations below.
|
||||
h := &gfP{}
|
||||
gfpSub(h, u2, u1)
|
||||
|
||||
gfpDouble(t, h)
|
||||
// i = 4h²
|
||||
i := &gfP{}
|
||||
gfpSqr(i, t, 1)
|
||||
// j = 4h³
|
||||
j := &gfP{}
|
||||
gfpMul(j, h, i)
|
||||
|
||||
gfpSub(t, s2, s1)
|
||||
|
||||
pointEq = h.Equal(zero) & t.Equal(zero)
|
||||
|
||||
r := &gfP{}
|
||||
gfpDouble(r, t)
|
||||
|
||||
v := &gfP{}
|
||||
gfpMul(v, u1, i)
|
||||
|
||||
// t4 = 4(s2-s1)²
|
||||
t4, t6 := &gfP{}, &gfP{}
|
||||
gfpSqr(t4, r, 1)
|
||||
gfpDouble(t, v)
|
||||
gfpSub(t6, t4, j)
|
||||
|
||||
gfpSub(&c.x, t6, t)
|
||||
|
||||
// Set y = -(2h)³(s1 + s*(x/4h²-u1))
|
||||
// This is also
|
||||
// y = - 2·s1·j - (s2-s1)(2x - 2i·u1) = r(v-x) - 2·s1·j
|
||||
gfpSub(t, v, &c.x) // t7
|
||||
gfpMul(t4, s1, j) // t8
|
||||
gfpDouble(t6, t4) // t9
|
||||
gfpMul(t4, r, t) // t10
|
||||
gfpSub(&c.y, t4, t6)
|
||||
|
||||
// Set z = 2(u2-u1)·z1·z2 = 2h·z1·z2
|
||||
gfpAdd(t, &a.z, &b.z) // t11
|
||||
gfpSqr(t4, t, 1) // t12
|
||||
gfpSub(t, t4, z12) // t13
|
||||
gfpSub(t4, t, z22) // t14
|
||||
gfpMul(&c.z, t4, h)
|
||||
|
||||
return pointEq
|
||||
}
|
@ -135,10 +135,10 @@ func BenchmarkGfP2Mul(b *testing.B) {
|
||||
*fromBigInt(bigFromHex("17509B092E845C1266BA0D262CBEE6ED0736A96FA347C8BD856DC76B84EBEB96")),
|
||||
*fromBigInt(bigFromHex("A7CF28D519BE3DA65F3170153D278FF247EFBA98A71A08116215BBA5C999A7C7")),
|
||||
}
|
||||
t := &gfP2{}
|
||||
b.ReportAllocs()
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
t := &gfP2{}
|
||||
t.Mul(x, y)
|
||||
}
|
||||
}
|
||||
|
@ -121,8 +121,8 @@ func (e *gfP4) MulNC(a, b *gfP4) *gfP4 {
|
||||
tx := &e.x
|
||||
ty := &e.y
|
||||
v0, v1 := &gfP2{}, &gfP2{}
|
||||
v0.MulNC(&a.y, &b.y)
|
||||
v1.MulNC(&a.x, &b.x)
|
||||
v0.Mul(&a.y, &b.y)
|
||||
v1.Mul(&a.x, &b.x)
|
||||
|
||||
tx.Add(&a.x, &a.y)
|
||||
ty.Add(&b.x, &b.y)
|
||||
@ -148,8 +148,8 @@ func (e *gfP4) MulNC2(a *gfP4, x, y *gfP2) *gfP4 {
|
||||
tx := &e.x
|
||||
ty := &e.y
|
||||
v0, v1 := &gfP2{}, &gfP2{}
|
||||
v0.MulNC(&a.y, y)
|
||||
v1.MulNC(&a.x, x)
|
||||
v0.Mul(&a.y, y)
|
||||
v1.Mul(&a.x, x)
|
||||
|
||||
tx.Add(&a.x, &a.y)
|
||||
ty.Add(x, y)
|
||||
@ -181,8 +181,8 @@ func (e *gfP4) MulVNC(a, b *gfP4) *gfP4 {
|
||||
tx := &e.x
|
||||
ty := &e.y
|
||||
v0, v1 := &gfP2{}, &gfP2{}
|
||||
v0.MulNC(&a.y, &b.y)
|
||||
v1.MulNC(&a.x, &b.x)
|
||||
v0.Mul(&a.y, &b.y)
|
||||
v1.Mul(&a.x, &b.x)
|
||||
|
||||
tx.Add(&a.x, &a.y)
|
||||
ty.Add(&b.x, &b.y)
|
||||
@ -227,11 +227,11 @@ func (e *gfP4) SquareNC(a *gfP4) *gfP4 {
|
||||
tx := &e.x
|
||||
ty := &e.y
|
||||
|
||||
tx.SquareUNC(&a.x)
|
||||
ty.SquareNC(&a.y)
|
||||
tx.SquareU(&a.x)
|
||||
ty.Square(&a.y)
|
||||
ty.Add(tx, ty)
|
||||
|
||||
tx.MulNC(&a.x, &a.y)
|
||||
tx.Mul(&a.x, &a.y)
|
||||
tx.Add(tx, tx)
|
||||
|
||||
return e
|
||||
@ -250,8 +250,8 @@ func (e *gfP4) SquareV(a *gfP4) *gfP4 {
|
||||
func (e *gfP4) SquareVNC(a *gfP4) *gfP4 {
|
||||
tx := &e.x
|
||||
ty := &e.y
|
||||
tx.SquareUNC(&a.x)
|
||||
ty.SquareNC(&a.y)
|
||||
tx.SquareU(&a.x)
|
||||
ty.Square(&a.y)
|
||||
tx.Add(tx, ty)
|
||||
|
||||
ty.MulU(&a.x, &a.y)
|
||||
@ -269,15 +269,15 @@ func (e *gfP4) Invert(a *gfP4) *gfP4 {
|
||||
|
||||
t3 := &gfP2{}
|
||||
|
||||
t3.SquareUNC(&a.x)
|
||||
t1.SquareNC(&a.y)
|
||||
t3.SquareU(&a.x)
|
||||
t1.Square(&a.y)
|
||||
t3.Sub(t3, t1)
|
||||
t3.Invert(t3)
|
||||
|
||||
t1.Mul(&a.y, t3)
|
||||
t1.Neg(t1)
|
||||
|
||||
t2.MulNC(&a.x, t3)
|
||||
t2.Mul(&a.x, t3)
|
||||
|
||||
gfp4Copy(e, tmp)
|
||||
return e
|
||||
|
@ -119,9 +119,9 @@ func (e *gfP6) MulNC(a, b *gfP6) *gfP6 {
|
||||
ty := &e.y
|
||||
tz := &e.z
|
||||
t, v0, v1, v2 := &gfP2{}, &gfP2{}, &gfP2{}, &gfP2{}
|
||||
v0.MulNC(&a.z, &b.z)
|
||||
v1.MulNC(&a.y, &b.y)
|
||||
v2.MulNC(&a.x, &b.x)
|
||||
v0.Mul(&a.z, &b.z)
|
||||
v1.Mul(&a.y, &b.y)
|
||||
v2.Mul(&a.x, &b.x)
|
||||
|
||||
t.Add(&a.y, &a.x)
|
||||
tz.Add(&b.y, &b.x)
|
||||
@ -185,26 +185,26 @@ func (e *gfP6) SquareNC(a *gfP6) *gfP6 {
|
||||
tz := &e.z
|
||||
t, v0, v1, v2 := &gfP2{}, &gfP2{}, &gfP2{}, &gfP2{}
|
||||
|
||||
v0.SquareNC(&a.z)
|
||||
v1.SquareNC(&a.y)
|
||||
v2.SquareNC(&a.x)
|
||||
v0.Square(&a.z)
|
||||
v1.Square(&a.y)
|
||||
v2.Square(&a.x)
|
||||
|
||||
t.Add(&a.y, &a.x)
|
||||
tz.SquareNC(t)
|
||||
tz.Square(t)
|
||||
tz.Sub(tz, v1)
|
||||
tz.Sub(tz, v2)
|
||||
tz.MulU1(tz)
|
||||
tz.Add(tz, v0)
|
||||
|
||||
t.Add(&a.z, &a.y)
|
||||
ty.SquareNC(t)
|
||||
ty.Square(t)
|
||||
ty.Sub(ty, v0)
|
||||
ty.Sub(ty, v1)
|
||||
t.MulU1(v2)
|
||||
ty.Add(ty, t)
|
||||
|
||||
t.Add(&a.z, &a.x)
|
||||
tx.SquareNC(t)
|
||||
tx.Square(t)
|
||||
tx.Sub(tx, v0)
|
||||
tx.Add(tx, v1)
|
||||
tx.Sub(tx, v2)
|
||||
@ -233,19 +233,19 @@ func (e *gfP6) Invert(a *gfP6) *gfP6 {
|
||||
// See "Implementing cryptographic pairings", M. Scott, section 3.2.
|
||||
// ftp://136.206.11.249/pub/crypto/pairings.pdf
|
||||
|
||||
t1 := (&gfP2{}).MulUNC(&a.x, &a.y)
|
||||
A := (&gfP2{}).SquareNC(&a.z)
|
||||
t1 := (&gfP2{}).MulU(&a.x, &a.y)
|
||||
A := (&gfP2{}).Square(&a.z)
|
||||
A.Sub(A, t1)
|
||||
|
||||
B := (&gfP2{}).SquareUNC(&a.x)
|
||||
B := (&gfP2{}).SquareU(&a.x)
|
||||
t1.Mul(&a.y, &a.z)
|
||||
B.Sub(B, t1)
|
||||
|
||||
C := (&gfP2{}).SquareNC(&a.y)
|
||||
C := (&gfP2{}).Square(&a.y)
|
||||
t1.Mul(&a.x, &a.z)
|
||||
C.Sub(C, t1)
|
||||
|
||||
F := (&gfP2{}).MulUNC(C, &a.y)
|
||||
F := (&gfP2{}).MulU(C, &a.y)
|
||||
t1.Mul(A, &a.z)
|
||||
F.Add(F, t1)
|
||||
t1.MulU(B, &a.x)
|
||||
|
@ -67,7 +67,7 @@
|
||||
CMOVQCC b2, a2 \
|
||||
CMOVQCC b3, a3
|
||||
|
||||
TEXT ·gfpNeg(SB),0,$0-16
|
||||
TEXT ·gfpNeg(SB),NOSPLIT,$0-16
|
||||
MOVQ ·p2+0(SB), R8
|
||||
MOVQ ·p2+8(SB), R9
|
||||
MOVQ ·p2+16(SB), R10
|
||||
@ -85,7 +85,7 @@ TEXT ·gfpNeg(SB),0,$0-16
|
||||
storeBlock(R8,R9,R10,R11, 0(DI))
|
||||
RET
|
||||
|
||||
TEXT ·gfpAdd(SB),0,$0-24
|
||||
TEXT ·gfpAdd(SB),NOSPLIT,$0-24
|
||||
MOVQ a+8(FP), DI
|
||||
MOVQ b+16(FP), SI
|
||||
|
||||
@ -104,7 +104,7 @@ TEXT ·gfpAdd(SB),0,$0-24
|
||||
storeBlock(R8,R9,R10,R11, 0(DI))
|
||||
RET
|
||||
|
||||
TEXT ·gfpDouble(SB),0,$0-16
|
||||
TEXT ·gfpDouble(SB),NOSPLIT,$0-16
|
||||
MOVQ a+0(FP), DI
|
||||
MOVQ b+8(FP), SI
|
||||
|
||||
@ -122,7 +122,7 @@ TEXT ·gfpDouble(SB),0,$0-16
|
||||
storeBlock(R8,R9,R10,R11, 0(DI))
|
||||
RET
|
||||
|
||||
TEXT ·gfpTriple(SB),0,$0-16
|
||||
TEXT ·gfpTriple(SB),NOSPLIT,$0-16
|
||||
MOVQ a+0(FP), DI
|
||||
MOVQ b+8(FP), SI
|
||||
|
||||
@ -149,7 +149,7 @@ TEXT ·gfpTriple(SB),0,$0-16
|
||||
storeBlock(R8,R9,R10,R11, 0(DI))
|
||||
RET
|
||||
|
||||
TEXT ·gfpSub(SB),0,$0-24
|
||||
TEXT ·gfpSub(SB),NOSPLIT,$0-24
|
||||
MOVQ a+8(FP), DI
|
||||
MOVQ b+16(FP), SI
|
||||
|
||||
@ -180,7 +180,7 @@ TEXT ·gfpSub(SB),0,$0-24
|
||||
storeBlock(R8,R9,R10,R11, 0(DI))
|
||||
RET
|
||||
|
||||
TEXT ·gfpMul(SB),0,$0-24
|
||||
TEXT ·gfpMul(SB),NOSPLIT,$0-24
|
||||
MOVQ in1+8(FP), x_ptr
|
||||
MOVQ in2+16(FP), y_ptr
|
||||
|
||||
|
@ -56,7 +56,8 @@ func Test_gfpSqr(t *testing.T) {
|
||||
gfpSqr(ret, x, 1)
|
||||
pMinusOne.Mul(pMinusOne, pMinusOne)
|
||||
pMinusOne.Mod(pMinusOne, p)
|
||||
if *ret != *fromBigInt(pMinusOne) {
|
||||
expected := fromBigInt(pMinusOne)
|
||||
if *ret != *expected {
|
||||
t.Errorf("bad sqr")
|
||||
}
|
||||
// p + 1
|
||||
|
@ -17,6 +17,11 @@ var twistB = &gfP2{
|
||||
*zero,
|
||||
}
|
||||
|
||||
var threeTwistB = &gfP2{
|
||||
*newGFp(3 * 5),
|
||||
*zero,
|
||||
}
|
||||
|
||||
// twistGen is the generator of group G₂.
|
||||
var twistGen = &twistPoint{
|
||||
gfP2{
|
||||
@ -58,7 +63,7 @@ func NewTwistGenerator() *twistPoint {
|
||||
|
||||
func (c *twistPoint) polynomial(x *gfP2) *gfP2 {
|
||||
x3 := &gfP2{}
|
||||
x3.SquareNC(x).Mul(x3, x).Add(x3, twistB)
|
||||
x3.Square(x).Mul(x3, x).Add(x3, twistB)
|
||||
return x3
|
||||
}
|
||||
|
||||
@ -70,7 +75,7 @@ func (c *twistPoint) IsOnCurve() bool {
|
||||
}
|
||||
|
||||
y2 := &gfP2{}
|
||||
y2.SquareNC(&c.y)
|
||||
y2.Square(&c.y)
|
||||
x3 := c.polynomial(&c.x)
|
||||
|
||||
return y2.Equal(x3) == 1
|
||||
@ -87,92 +92,79 @@ func (c *twistPoint) IsInfinity() bool {
|
||||
return c.z.IsZero()
|
||||
}
|
||||
|
||||
func (c *twistPoint) Add(a, b *twistPoint) {
|
||||
// For additional comments, see the same function in curve.go.
|
||||
func (c *twistPoint) Add(p1, p2 *twistPoint) {
|
||||
// Complete addition formula for a = 0 from "Complete addition formulas for
|
||||
// prime order elliptic curves" (https://eprint.iacr.org/2015/1060), §3.2.
|
||||
// Algorithm 7: Complete, projective point addition for prime order j-invariant 0 short Weierstrass curves.
|
||||
|
||||
if a.IsInfinity() {
|
||||
c.Set(b)
|
||||
return
|
||||
}
|
||||
if b.IsInfinity() {
|
||||
c.Set(a)
|
||||
return
|
||||
}
|
||||
t0, t1, t2, t3, t4 := new(gfP2), new(gfP2), new(gfP2), new(gfP2), new(gfP2)
|
||||
x3, y3, z3 := new(gfP2), new(gfP2), new(gfP2)
|
||||
t0.Mul(&p1.x, &p2.x) // t0 := X1X2
|
||||
t1.Mul(&p1.y, &p2.y) // t1 := Y1Y2
|
||||
t2.Mul(&p1.z, &p2.z) // t2 := Z1Z2
|
||||
t3.Add(&p1.x, &p1.y) // t3 := X1 + Y1
|
||||
t4.Add(&p2.x, &p2.y) // t4 := X2 + Y2
|
||||
t3.Mul(t3, t4) // t3 := t3 * t4 = (X1 + Y1) * (X2 + Y2)
|
||||
t4.Add(t0, t1) // t4 := t0 + t1
|
||||
t3.Sub(t3, t4) // t3 := t3 - t4 = X1Y2 + X2Y1
|
||||
t4.Add(&p1.y, &p1.z) // t4 := Y1 + Z1
|
||||
x3.Add(&p2.y, &p2.z) // X3 := Y2 + Z2
|
||||
t4.Mul(t4, x3) // t4 := t4 * X3 = (Y1 + Z1)(Y2 + Z2)
|
||||
x3.Add(t1, t2) // X3 := t1 + t2
|
||||
t4.Sub(t4, x3) // t4 := t4 - X3 = Y1Z2 + Y2Z1
|
||||
x3.Add(&p1.x, &p1.z) // X3 := X1 + Z1
|
||||
y3.Add(&p2.x, &p2.z) // Y3 := X2 + Z2
|
||||
x3.Mul(x3, y3) // X3 := X3 * Y3
|
||||
y3.Add(t0, t2) // Y3 := t0 + t2
|
||||
y3.Sub(x3, y3) // Y3 := X3 - Y3 = X1Z2 + X2Z1
|
||||
t0.Triple(t0) // t0 := t0 + t0 + t0 = 3X1X2
|
||||
t2.Mul(threeTwistB, t2) // t2 := 3b * t2 = 3bZ1Z2
|
||||
z3.Add(t1, t2) // Z3 := t1 + t2 = Y1Y2 + 3bZ1Z2
|
||||
t1.Sub(t1, t2) // t1 := t1 - t2 = Y1Y2 - 3bZ1Z2
|
||||
y3.Mul(threeTwistB, y3) // Y3 = 3b * Y3 = 3b(X1Z2 + X2Z1)
|
||||
x3.Mul(t4, y3) // X3 := t4 * Y3 = 3b(X1Z2 + X2Z1)(Y1Z2 + Y2Z1)
|
||||
t2.Mul(t3, t1) // t2 := t3 * t1 = (X1Y2 + X2Y1)(Y1Y2 - 3bZ1Z2)
|
||||
x3.Sub(t2, x3) // X3 := t2 - X3 = (X1Y2 + X2Y1)(Y1Y2 - 3bZ1Z2) - 3b(Y1Z2 + Y2Z1)(X1Z2 + X2Z1)
|
||||
y3.Mul(y3, t0) // Y3 := Y3 * t0 = 9bX1X2(X1Z2 + X2Z1)
|
||||
t1.Mul(t1, z3) // t1 := t1 * Z3 = (Y1Y2 + 3bZ1Z2)(Y1Y2 - 3bZ1Z2)
|
||||
y3.Add(t1, y3) // Y3 := t1 + Y3 = (Y1Y2 + 3bZ1Z2)(Y1Y2 - 3bZ1Z2) + 9bX1X2(X1Z2 + X2Z1)
|
||||
t0.Mul(t0, t3) // t0 := t0 * t3 = 3X1X2(X1Y2 + X2Y1)
|
||||
z3.Mul(z3, t4) // Z3 := Z3 * t4 = (Y1Z2 + Y2Z1)(Y1Y2 + 3bZ1Z2)
|
||||
z3.Add(z3, t0) // Z3 := Z3 + t0 = (Y1Z2 + Y2Z1)(Y1Y2 + 3bZ1Z2) + 3X1X2(X1Y2 + X2Y1)
|
||||
|
||||
// See http://hyperelliptic.org/EFD/g1p/auto-code/shortw/jacobian-0/addition/add-2007-bl.op3
|
||||
z12 := (&gfP2{}).SquareNC(&a.z)
|
||||
z22 := (&gfP2{}).SquareNC(&b.z)
|
||||
u1 := (&gfP2{}).MulNC(&a.x, z22)
|
||||
u2 := (&gfP2{}).MulNC(&b.x, z12)
|
||||
|
||||
t := (&gfP2{}).MulNC(&b.z, z22)
|
||||
s1 := (&gfP2{}).MulNC(&a.y, t)
|
||||
|
||||
t.Mul(&a.z, z12)
|
||||
s2 := (&gfP2{}).MulNC(&b.y, t)
|
||||
|
||||
h := (&gfP2{}).Sub(u2, u1)
|
||||
xEqual := h.IsZero()
|
||||
|
||||
t.Double(h)
|
||||
i := (&gfP2{}).SquareNC(t)
|
||||
j := (&gfP2{}).MulNC(h, i)
|
||||
|
||||
t.Sub(s2, s1)
|
||||
yEqual := t.IsZero()
|
||||
if xEqual && yEqual {
|
||||
c.Double(a)
|
||||
return
|
||||
}
|
||||
r := (&gfP2{}).Double(t)
|
||||
|
||||
v := (&gfP2{}).MulNC(u1, i)
|
||||
|
||||
t4 := (&gfP2{}).SquareNC(r)
|
||||
t.Double(v)
|
||||
t6 := (&gfP2{}).Sub(t4, j)
|
||||
c.x.Sub(t6, t)
|
||||
|
||||
t.Sub(v, &c.x) // t7
|
||||
t4.Mul(s1, j) // t8
|
||||
t6.Double(t4) // t9
|
||||
t4.Mul(r, t) // t10
|
||||
c.y.Sub(t4, t6)
|
||||
|
||||
t.Add(&a.z, &b.z) // t11
|
||||
t4.Square(t) // t12
|
||||
t.Sub(t4, z12) // t13
|
||||
t4.Sub(t, z22) // t14
|
||||
c.z.Mul(t4, h)
|
||||
c.x.Set(x3)
|
||||
c.y.Set(y3)
|
||||
c.z.Set(z3)
|
||||
}
|
||||
|
||||
func (c *twistPoint) Double(a *twistPoint) {
|
||||
// See http://hyperelliptic.org/EFD/g1p/auto-code/shortw/jacobian-0/doubling/dbl-2009-l.op3
|
||||
A := (&gfP2{}).SquareNC(&a.x)
|
||||
B := (&gfP2{}).SquareNC(&a.y)
|
||||
C := (&gfP2{}).SquareNC(B)
|
||||
func (c *twistPoint) Double(p *twistPoint) {
|
||||
// Complete addition formula for a = 0 from "Complete addition formulas for
|
||||
// prime order elliptic curves" (https://eprint.iacr.org/2015/1060), §3.2.
|
||||
// Algorithm 9: Exception-free point doubling for prime order j-invariant 0 short Weierstrass curves.
|
||||
t0, t1, t2 := new(gfP2), new(gfP2), new(gfP2)
|
||||
x3, y3, z3 := new(gfP2), new(gfP2), new(gfP2)
|
||||
|
||||
t := (&gfP2{}).Add(&a.x, B)
|
||||
t2 := (&gfP2{}).SquareNC(t)
|
||||
t.Sub(t2, A)
|
||||
t2.Sub(t, C)
|
||||
d := (&gfP2{}).Double(t2)
|
||||
t.Double(A)
|
||||
e := (&gfP2{}).Add(t, A)
|
||||
f := (&gfP2{}).SquareNC(e)
|
||||
t0.Square(&p.y) // t0 := Y^2
|
||||
z3.Double(t0) // Z3 := t0 + t0
|
||||
z3.Double(z3) // Z3 := Z3 + Z3
|
||||
z3.Double(z3) // Z3 := Z3 + Z3
|
||||
t1.Mul(&p.y, &p.z) // t1 := YZ
|
||||
t2.Square(&p.z) // t0 := Z^2
|
||||
t2.Mul(threeTwistB, t2) // t2 := 3b * t2 = 3bZ^2
|
||||
x3.Mul(t2, z3) // X3 := t2 * Z3
|
||||
y3.Add(t0, t2) // Y3 := t0 + t2
|
||||
z3.Mul(t1, z3) // Z3 := t1 * Z3
|
||||
t2.Triple(t2) // t2 := t2 + t2 + t2
|
||||
t0.Sub(t0, t2) // t0 := t0 - t2
|
||||
y3.Mul(t0, y3) // t0 := t0 * Y3
|
||||
y3.Add(x3, y3) // Y3 := X3 + Y3
|
||||
t1.Mul(&p.x, &p.y) // t1 := XY
|
||||
x3.Mul(t0, t1) // X3 := t0 * t1
|
||||
x3.Double(x3) // X3 := X3 + X3
|
||||
|
||||
t.Double(d)
|
||||
c.x.Sub(f, t)
|
||||
|
||||
c.z.Mul(&a.y, &a.z)
|
||||
c.z.Double(&c.z)
|
||||
|
||||
t.Double(C)
|
||||
t2.Double(t)
|
||||
t.Double(t2)
|
||||
c.y.Sub(d, &c.x)
|
||||
t2.Mul(e, &c.y)
|
||||
c.y.Sub(t2, t)
|
||||
c.x.Set(x3)
|
||||
c.y.Set(y3)
|
||||
c.z.Set(z3)
|
||||
}
|
||||
|
||||
func (c *twistPoint) Mul(a *twistPoint, scalar *big.Int) {
|
||||
@ -190,7 +182,36 @@ func (c *twistPoint) Mul(a *twistPoint, scalar *big.Int) {
|
||||
c.Set(sum)
|
||||
}
|
||||
|
||||
// MakeAffine reverses the Projective transform.
|
||||
// A = 1/Z1
|
||||
// X3 = A*X1
|
||||
// Y3 = A*Y1
|
||||
// Z3 = 1
|
||||
func (c *twistPoint) MakeAffine() {
|
||||
// TODO: do we need to change it to constant-time implementation?
|
||||
if c.z.IsOne() {
|
||||
return
|
||||
} else if c.z.IsZero() {
|
||||
c.x.SetZero()
|
||||
c.y.SetOne()
|
||||
c.t.SetZero()
|
||||
return
|
||||
}
|
||||
|
||||
zInv := &gfP2{}
|
||||
zInv.Invert(&c.z)
|
||||
|
||||
c.x.Mul(&c.x, zInv)
|
||||
c.y.Mul(&c.y, zInv)
|
||||
|
||||
c.z.SetOne()
|
||||
c.t.SetOne()
|
||||
}
|
||||
|
||||
// MakeAffine reverses the Jacobian transform.
|
||||
// the Jacobian coordinates are (x1, y1, z1)
|
||||
// where x = x1/z1² and y = y1/z1³.
|
||||
func (c *twistPoint) AffineFromJacobian() {
|
||||
if c.z.IsOne() {
|
||||
return
|
||||
} else if c.z.IsZero() {
|
||||
@ -201,8 +222,8 @@ func (c *twistPoint) MakeAffine() {
|
||||
}
|
||||
|
||||
zInv := (&gfP2{}).Invert(&c.z)
|
||||
t := (&gfP2{}).MulNC(&c.y, zInv)
|
||||
zInv2 := (&gfP2{}).SquareNC(zInv)
|
||||
t := (&gfP2{}).Mul(&c.y, zInv)
|
||||
zInv2 := (&gfP2{}).Square(zInv)
|
||||
c.y.Mul(t, zInv2)
|
||||
t.Mul(&c.x, zInv2)
|
||||
c.x.Set(t)
|
||||
|
@ -28,7 +28,7 @@ func TestAddNeg(t *testing.T) {
|
||||
func Test_TwistFrobeniusP(t *testing.T) {
|
||||
ret1, ret2 := &twistPoint{}, &twistPoint{}
|
||||
ret1.Frobenius(twistGen)
|
||||
ret1.MakeAffine()
|
||||
ret1.AffineFromJacobian()
|
||||
|
||||
ret2.x.Conjugate(&twistGen.x)
|
||||
ret2.x.MulScalar(&ret2.x, betaToNegPPlus1Over3)
|
||||
@ -49,12 +49,15 @@ func Test_TwistFrobeniusP(t *testing.T) {
|
||||
func Test_TwistFrobeniusP2(t *testing.T) {
|
||||
ret1, ret2 := &twistPoint{}, &twistPoint{}
|
||||
ret1.Frobenius(twistGen)
|
||||
ret1.AffineFromJacobian()
|
||||
ret1.Frobenius(ret1)
|
||||
ret1.AffineFromJacobian()
|
||||
if !ret1.IsOnCurve() {
|
||||
t.Errorf("point should be on curve")
|
||||
}
|
||||
|
||||
ret2.FrobeniusP2(twistGen)
|
||||
ret2.AffineFromJacobian()
|
||||
if !ret2.IsOnCurve() {
|
||||
t.Errorf("point should be on curve")
|
||||
}
|
||||
@ -77,7 +80,7 @@ func Test_TwistFrobeniusP2_Case2(t *testing.T) {
|
||||
}
|
||||
|
||||
ret2.FrobeniusP2(twistGen)
|
||||
ret2.MakeAffine()
|
||||
ret2.AffineFromJacobian()
|
||||
if !ret2.IsOnCurve() {
|
||||
t.Errorf("point should be on curve")
|
||||
}
|
||||
@ -100,7 +103,7 @@ func Test_TwistNegFrobeniusP2_Case2(t *testing.T) {
|
||||
}
|
||||
|
||||
ret2.NegFrobeniusP2(twistGen)
|
||||
ret2.MakeAffine()
|
||||
ret2.AffineFromJacobian()
|
||||
if !ret2.IsOnCurve() {
|
||||
t.Errorf("point should be on curve")
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user