internal/ed25519: remove single-model code

This commit is contained in:
Henry de Valence 2019-05-06 14:29:42 -07:00
parent bdc420be66
commit a360a6556f
2 changed files with 1 additions and 360 deletions

View File

@ -12,14 +12,13 @@
package edwards25519
import (
"math/big"
"github.com/gtank/ristretto255/internal/radix51"
)
// D is a constant in the curve equation.
var D = &radix51.FieldElement{929955233495203, 466365720129213,
1662059464998953, 2033849074728123, 1442794654840575}
var twoD = new(radix51.FieldElement).Add(D, D)
// Point types.
@ -275,328 +274,3 @@ func (v *ProjP3) Equal(u *ProjP3) int {
return t1.Equal(&t2) & t3.Equal(&t4)
}
// From EFD https://hyperelliptic.org/EFD/g1p/auto-twisted-extended-1.html
// An elliptic curve in twisted Edwards form has parameters a, d and coordinates
// x, y satisfying the following equations:
//
// a * x^2 + y^2 = 1 + d * x^2 * y^2
//
// Extended coordinates assume a = -1 and represent x, y as (X, Y, Z, T)
// satisfying the following equations:
//
// x = X / Z
// y = Y / Z
// x * y = T / Z
//
// This representation was introduced in the HisilWongCarterDawson paper "Twisted
// Edwards curves revisited" (Asiacrypt 2008).
type ExtendedGroupElement struct {
X, Y, Z, T radix51.FieldElement
}
func (v *ExtendedGroupElement) Set(u *ExtendedGroupElement) *ExtendedGroupElement {
*v = *u
return v
}
// Converts (x,y) to (X:Y:T:Z) extended coordinates, or "P3" in ref10. As
// described in "Twisted Edwards Curves Revisited", Hisil-Wong-Carter-Dawson
// 2008, Section 3.1 (https://eprint.iacr.org/2008/522.pdf)
// See also https://hyperelliptic.org/EFD/g1p/auto-twisted-extended-1.html#addition-add-2008-hwcd-3
func (v *ExtendedGroupElement) FromAffine(x, y *big.Int) *ExtendedGroupElement {
v.X.FromBig(x)
v.Y.FromBig(y)
v.T.Mul(&v.X, &v.Y)
v.Z.One()
return v
}
// Extended coordinates are XYZT with x = X/Z, y = Y/Z, or the "P3"
// representation in ref10. Extended->affine is the same operation as moving
// from projective to affine. Per HWCD, it is safe to move from extended to
// projective by simply ignoring T.
func (v *ExtendedGroupElement) ToAffine() (*big.Int, *big.Int) {
var x, y, zinv radix51.FieldElement
zinv.Invert(&v.Z)
x.Mul(&v.X, &zinv)
y.Mul(&v.Y, &zinv)
return x.ToBig(), y.ToBig()
}
// Per HWCD, it is safe to move from extended to projective by simply ignoring T.
func (v *ExtendedGroupElement) ToProjective(p *ProjectiveGroupElement) {
p.X.Set(&v.X)
p.Y.Set(&v.Y)
p.Z.Set(&v.Z)
}
func (v *ExtendedGroupElement) Zero() *ExtendedGroupElement {
v.X.Zero()
v.Y.One()
v.Z.One()
v.T.Zero()
return v
}
var twoD = new(radix51.FieldElement).Add(D, D)
// This is the same addition formula everyone uses, "add-2008-hwcd-3".
// https://hyperelliptic.org/EFD/g1p/auto-twisted-extended-1.html#addition-add-2008-hwcd-3
// TODO We know Z1=1 and Z2=1 here, so mmadd-2008-hwcd-3 (6M + 1S + 1*k + 9add) could apply
func (v *ExtendedGroupElement) Add(p1, p2 *ExtendedGroupElement) *ExtendedGroupElement {
var tmp1, tmp2, A, B, C, D, E, F, G, H radix51.FieldElement
tmp1.Sub(&p1.Y, &p1.X) // tmp1 <-- Y1-X1
tmp2.Sub(&p2.Y, &p2.X) // tmp2 <-- Y2-X2
A.Mul(&tmp1, &tmp2) // A <-- tmp1*tmp2 = (Y1-X1)*(Y2-X2)
tmp1.Add(&p1.Y, &p1.X) // tmp1 <-- Y1+X1
tmp2.Add(&p2.Y, &p2.X) // tmp2 <-- Y2+X2
B.Mul(&tmp1, &tmp2) // B <-- tmp1*tmp2 = (Y1+X1)*(Y2+X2)
tmp1.Mul(&p1.T, &p2.T) // tmp1 <-- T1*T2
C.Mul(&tmp1, twoD) // C <-- tmp1*2d = T1*2*d*T2
tmp1.Mul(&p1.Z, &p2.Z) // tmp1 <-- Z1*Z2
D.Add(&tmp1, &tmp1) // D <-- tmp1 + tmp1 = 2*Z1*Z2
E.Sub(&B, &A) // E <-- B-A
F.Sub(&D, &C) // F <-- D-C
G.Add(&D, &C) // G <-- D+C
H.Add(&B, &A) // H <-- B+A
v.X.Mul(&E, &F) // X3 <-- E*F
v.Y.Mul(&G, &H) // Y3 <-- G*H
v.T.Mul(&E, &H) // T3 <-- E*H
v.Z.Mul(&F, &G) // Z3 <-- F*G
return v
}
func (v *ExtendedGroupElement) Sub(p1, p2 *ExtendedGroupElement) *ExtendedGroupElement {
// This is the same function as above, but with X2, T2 negated to X2'=-X2, T2'=-T2
var tmp1, tmp2, A, B, C, D, E, F, G, H radix51.FieldElement
tmp1.Sub(&p1.Y, &p1.X) // tmp1 <-- Y1-X1
tmp2.Add(&p2.Y, &p2.X) // tmp2 <-- Y2+X2 = Y2-X2'
A.Mul(&tmp1, &tmp2) // A <-- tmp1*tmp2 = (Y1-X1)*(Y2-X2')
tmp1.Add(&p1.Y, &p1.X) // tmp1 <-- Y1+X1
tmp2.Sub(&p2.Y, &p2.X) // tmp2 <-- Y2-X2 = Y2+X2'
B.Mul(&tmp1, &tmp2) // B <-- tmp1*tmp2 = (Y1+X1)*(Y2+X2)
tmp1.Mul(&p1.T, &p2.T) // tmp1 <-- -T1*T2' = T1*T2
C.Mul(&tmp1, twoD) // C' <-- tmp1*2d = -T1*2*d*T2' = T1*2*d*T2
tmp1.Mul(&p1.Z, &p2.Z) // tmp1 <-- Z1*Z2
D.Add(&tmp1, &tmp1) // D <-- tmp1 + tmp1 = 2*Z1*Z2
E.Sub(&B, &A) // E <-- B-A
F.Add(&D, &C) // F <-- D+C' = D-C
G.Sub(&D, &C) // G <-- D-C' = D+C
H.Add(&B, &A) // H <-- B+A
v.X.Mul(&E, &F) // X3 <-- E*F
v.Y.Mul(&G, &H) // Y3 <-- G*H
v.T.Mul(&E, &H) // T3 <-- E*H
v.Z.Mul(&F, &G) // Z3 <-- F*G
return v
}
func (v *ExtendedGroupElement) Neg(p *ExtendedGroupElement) *ExtendedGroupElement {
v.X.Neg(&p.X)
v.Y.Set(&p.Y)
v.Z.Set(&p.Z)
v.T.Neg(&p.T)
return v
}
// by @ebfull
// https://github.com/dalek-cryptography/curve25519-dalek/pull/226/files
func (v *ExtendedGroupElement) Equal(u *ExtendedGroupElement) int {
var t1, t2, t3, t4 radix51.FieldElement
t1.Mul(&v.X, &u.Z)
t2.Mul(&u.X, &v.Z)
t3.Mul(&v.Y, &u.Z)
t4.Mul(&u.Y, &v.Z)
return t1.Equal(&t2) & t3.Equal(&t4)
}
// This implements the explicit formulas from HWCD Section 3.3, "Dedicated
// Doubling in [extended coordinates]".
//
// Explicit formula is as follows. Cost is 4M + 4S + 1D. For Ed25519, a = -1:
//
// A ← X1^2
// B ← Y1^2
// C ← 2*Z1^2
// D ← a*A
// E ← (X1+Y1)^2 A B
// G ← D+B
// F ← GC
// H ← DB
// X3 ← E*F
// Y3 ← G*H
// T3 ← E*H
// Z3 ← F*G
//
// In ref10/donna/dalek etc, this is instead handled by a faster
// mixed-coordinate doubling that results in a "Completed" group element
// instead of another point in extended coordinates. I have implemented it
// this way to see if more straightforward code is worth the (hopefully small)
// performance tradeoff.
func (v *ExtendedGroupElement) Double(u *ExtendedGroupElement) *ExtendedGroupElement {
// TODO: Convert to projective coordinates? Section 4.3 mixed doubling?
var A, B, C, D, E, F, G, H radix51.FieldElement
// A ← X1^2, B ← Y1^2
A.Square(&u.X)
B.Square(&u.Y)
// C ← 2*Z1^2
C.Square(&u.Z)
C.Add(&C, &C) // TODO should probably implement FeSquare2
// D ← -1*A
D.Neg(&A) // implemented as subtraction
// E ← (X1+Y1)^2 A B
var t0 radix51.FieldElement
t0.Add(&u.X, &u.Y)
t0.Square(&t0)
E.Sub(&t0, &A)
E.Sub(&E, &B)
G.Add(&D, &B) // G ← D+B
F.Sub(&G, &C) // F ← GC
H.Sub(&D, &B) // H ← DB
v.X.Mul(&E, &F) // X3 ← E*F
v.Y.Mul(&G, &H) // Y3 ← G*H
v.T.Mul(&E, &H) // T3 ← E*H
v.Z.Mul(&F, &G) // Z3 ← F*G
return v
}
// ScalarMult sets v = k*u where k is a reduced scalar field element in
// little-endian form. Note: this function is not constant-time.
func (v *ExtendedGroupElement) ScalarMult(u *ExtendedGroupElement, k *[32]byte) *ExtendedGroupElement {
// Montgomery ladder init:
// R_0 = O, R_1 = P
r1 := new(ExtendedGroupElement).Set(u)
r0 := v.Zero()
// Montgomery ladder step:
// R_{1-b} = R_{1-b} + R_{b}
// R_{b} = 2*R_{b}
for i := 255; i >= 0; i-- {
var b = int32((k[i/8] >> uint(i&7)) & 1)
if b == 0 {
r1.Add(r0, r1)
r0.Double(r0)
} else {
r0.Add(r0, r1)
r1.Double(r1)
}
}
return r0
}
// Projective coordinates are XYZ with x = X/Z, y = Y/Z, or the "P2"
// representation in ref10. This representation has a cheaper doubling formula
// than extended coordinates.
type ProjectiveGroupElement struct {
X, Y, Z radix51.FieldElement
}
func (v *ProjectiveGroupElement) FromAffine(x, y *big.Int) *ProjectiveGroupElement {
v.X.FromBig(x)
v.Y.FromBig(y)
v.Z.One()
return v
}
func (v *ProjectiveGroupElement) ToAffine() (*big.Int, *big.Int) {
var x, y, zinv radix51.FieldElement
zinv.Invert(&v.Z)
x.Mul(&v.X, &zinv)
y.Mul(&v.Y, &zinv)
return x.ToBig(), y.ToBig()
}
// HWCD Section 3: "Given (X : Y : Z) in [projective coordinates] passing to
// [extended coordinates, (X : Y : T : Z)] can be performed in 3M+1S by computing
// (XZ, YZ, XY, Z^2)"
func (v *ProjectiveGroupElement) ToExtended(r *ExtendedGroupElement) {
r.X.Mul(&v.X, &v.Z)
r.Y.Mul(&v.Y, &v.Z)
r.T.Mul(&v.X, &v.Y)
r.Z.Square(&v.Z)
}
func (v *ProjectiveGroupElement) Zero() *ProjectiveGroupElement {
v.X.Zero()
v.Y.One()
v.Z.One()
return v
}
// Because we are often converting from affine, we can use "mdbl-2008-bbjlp"
// which assumes Z1=1. We also assume a = -1.
//
// Assumptions: Z1 = 1.
// Cost: 2M + 4S + 1*a + 7add + 1*2.
// Source: 2008 BernsteinBirknerJoyeLangePeters
// http://eprint.iacr.org/2008/013, plus Z1=1, plus standard simplification.
// Explicit formulas:
//
// B = (X1+Y1)^2
// C = X1^2
// D = Y1^2
// E = a*C
// F = E+D
// X3 = (B-C-D)*(F-2)
// Y3 = F*(E-D)
// Z3 = F^2-2*F
//
// This assumption is one reason why this package is internal. For instance, it
// will not hold throughout a Montgomery ladder, when we convert to projective
// from possibly arbitrary extended coordinates.
func (v *ProjectiveGroupElement) DoubleZ1(u *ProjectiveGroupElement) *ProjectiveGroupElement {
var B, C, D, E, F radix51.FieldElement
if u.Z.Equal(radix51.One) != 1 {
panic("ed25519: DoubleZ1 called with Z != 1")
}
B.Square(B.Add(&u.X, &u.Y)) // B = (X1+Y1)^2
C.Square(&u.X) // C = X1^2
D.Square(&u.Y) // D = Y1^2
E.Neg(&C) // E = a*C where a = -1
F.Add(&E, &D) // F = E + D
// X3 = (B-C-D)*(F-2)
v.Y.Sub(v.Y.Sub(&B, &C), &D)
v.X.Mul(&v.Y, v.X.Sub(&F, radix51.Two))
// Y3 = F*(E-D)
v.Y.Mul(&F, v.Y.Sub(&E, &D))
// Z3 = F^2 - 2*F
v.Z.Square(&F)
v.Z.Sub(&v.Z, &F)
v.Z.Sub(&v.Z, &F)
return v
}
// IsOnCurve reports whether the given affine coordinate (x,y) lies on the curve
// by checking that -x^2 + y^2 - 1 - dx^2y^2 = 0 (mod p).
func IsOnCurve(x, y *radix51.FieldElement) bool {
var lh, y2, rh radix51.FieldElement
lh.Square(x) // x^2
y2.Square(y) // y^2
rh.Mul(&lh, &y2) // x^2*y^2
rh.Mul(&rh, D) // d*x^2*y^2
rh.Add(&rh, radix51.One) // 1 + d*x^2*y^2
lh.Neg(&lh) // -x^2
lh.Add(&lh, &y2) // -x^2 + y^2
lh.Sub(&lh, &rh) // -x^2 + y^2 - 1 - dx^2y^2
return lh.Equal(radix51.Zero) == 1
}

View File

@ -6,39 +6,6 @@ import (
)
func TestAddSubNegOnBasePoint(t *testing.T) {
basepoint := ExtendedGroupElement{
X: radix51.FieldElement([5]uint64{426475514619346, 2063872706840040, 14628272888959, 107677749330612, 288339085807592}),
Y: radix51.FieldElement([5]uint64{1934594822876571, 2049809580636559, 1991994783322914, 1758681962032007, 380046701118659}),
Z: radix51.FieldElement([5]uint64{1, 0, 0, 0, 0}),
T: radix51.FieldElement([5]uint64{410445769351754, 2235400917701188, 1495825632738689, 1351628537510093, 430502003771208}),
}
negBasepoint := ExtendedGroupElement{}
negBasepoint.Neg(&basepoint)
check1 := ExtendedGroupElement{}
check1.Zero()
check2 := ExtendedGroupElement{}
check2.Zero()
zero := ExtendedGroupElement{}
zero.Zero()
check1.Add(&basepoint, &negBasepoint)
check2.Sub(&basepoint, &basepoint)
if check1.Equal(&check2) != 1 {
t.Error("B + (-B) != B - B")
}
if check1.Equal(&zero) != 1 {
t.Error("B + (-B) != 0")
}
}
func TestAddSubNegOnBasePoint2(t *testing.T) {
var B, Bneg ProjP3
var tmpP2 ProjP2
var tmpP1xP1 ProjP1xP1