internal: make all APIs chainable

This commit is contained in:
Filippo Valsorda 2019-01-26 21:05:03 -05:00 committed by George Tankersley
parent 6c2fda803c
commit 2925e841f7
7 changed files with 53 additions and 43 deletions

View File

@ -91,12 +91,9 @@ func (curve ed25519Curve) Add(x1, y1, x2, y2 *big.Int) (x, y *big.Int) {
// Double returns 2*(x,y). // Double returns 2*(x,y).
func (curve ed25519Curve) Double(x1, y1 *big.Int) (x, y *big.Int) { func (curve ed25519Curve) Double(x1, y1 *big.Int) (x, y *big.Int) {
var p group.ProjectiveGroupElement p := new(group.ProjectiveGroupElement).FromAffine(x1, y1)
p.FromAffine(x1, y1)
// Use the special-case DoubleZ1 here because we know Z will be 1. // Use the special-case DoubleZ1 here because we know Z will be 1.
return p.DoubleZ1().ToAffine() return p.DoubleZ1(p).ToAffine()
} }
// ScalarMult returns k*(Bx,By) where k is a number in big-endian form. // ScalarMult returns k*(Bx,By) where k is a number in big-endian form.
@ -125,10 +122,10 @@ func (curve ed25519Curve) ScalarMult(x1, y1 *big.Int, k []byte) (x, y *big.Int)
var b = int32((s[i/8] >> uint(i&7)) & 1) var b = int32((s[i/8] >> uint(i&7)) & 1)
if b == 0 { if b == 0 {
r1.Add(&r0, &r1) r1.Add(&r0, &r1)
r0.Double() r0.Double(&r0)
} else { } else {
r0.Add(&r0, &r1) r0.Add(&r0, &r1)
r1.Double() r1.Double(&r0)
} }
} }

View File

@ -38,11 +38,12 @@ type ExtendedGroupElement struct {
// described in "Twisted Edwards Curves Revisited", Hisil-Wong-Carter-Dawson // described in "Twisted Edwards Curves Revisited", Hisil-Wong-Carter-Dawson
// 2008, Section 3.1 (https://eprint.iacr.org/2008/522.pdf) // 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 // 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) { func (v *ExtendedGroupElement) FromAffine(x, y *big.Int) *ExtendedGroupElement {
v.X.FromBig(x) v.X.FromBig(x)
v.Y.FromBig(y) v.Y.FromBig(y)
v.T.Mul(&v.X, &v.Y) v.T.Mul(&v.X, &v.Y)
v.Z.One() v.Z.One()
return v
} }
// Extended coordinates are XYZT with x = X/Z, y = Y/Z, or the "P3" // Extended coordinates are XYZT with x = X/Z, y = Y/Z, or the "P3"
@ -130,20 +131,17 @@ func (v *ExtendedGroupElement) Add(p1, p2 *ExtendedGroupElement) *ExtendedGroupE
// instead of another point in extended coordinates. I have implemented it // instead of another point in extended coordinates. I have implemented it
// this way to see if more straightforward code is worth the (hopefully small) // this way to see if more straightforward code is worth the (hopefully small)
// performance tradeoff. // performance tradeoff.
func (v *ExtendedGroupElement) Double() *ExtendedGroupElement { func (v *ExtendedGroupElement) Double(u *ExtendedGroupElement) *ExtendedGroupElement {
// TODO: Convert to projective coordinates? Section 4.3 mixed doubling? // TODO: Convert to projective coordinates? Section 4.3 mixed doubling?
// TODO: make a decision about how these APIs work wrt chaining/smashing
// *v = *(v.ToProjective().Double().ToExtended())
// return v
var A, B, C, D, E, F, G, H radix51.FieldElement var A, B, C, D, E, F, G, H radix51.FieldElement
// A ← X1^2, B ← Y1^2 // A ← X1^2, B ← Y1^2
A.Square(&v.X) A.Square(&u.X)
B.Square(&v.Y) B.Square(&u.Y)
// C ← 2*Z1^2 // C ← 2*Z1^2
C.Square(&v.Z) C.Square(&u.Z)
C.Add(&C, &C) // TODO should probably implement FeSquare2 C.Add(&C, &C) // TODO should probably implement FeSquare2
// D ← -1*A // D ← -1*A
@ -151,7 +149,7 @@ func (v *ExtendedGroupElement) Double() *ExtendedGroupElement {
// E ← (X1+Y1)^2 A B // E ← (X1+Y1)^2 A B
var t0 radix51.FieldElement var t0 radix51.FieldElement
t0.Add(&v.X, &v.Y) t0.Add(&u.X, &u.Y)
t0.Square(&t0) t0.Square(&t0)
E.Sub(&t0, &A) E.Sub(&t0, &A)
E.Sub(&E, &B) E.Sub(&E, &B)
@ -174,10 +172,11 @@ type ProjectiveGroupElement struct {
X, Y, Z radix51.FieldElement X, Y, Z radix51.FieldElement
} }
func (v *ProjectiveGroupElement) FromAffine(x, y *big.Int) { func (v *ProjectiveGroupElement) FromAffine(x, y *big.Int) *ProjectiveGroupElement {
v.X.FromBig(x) v.X.FromBig(x)
v.Y.FromBig(y) v.Y.FromBig(y)
v.Z.Zero() v.Z.Zero()
return v
} }
func (v *ProjectiveGroupElement) ToAffine() (*big.Int, *big.Int) { func (v *ProjectiveGroupElement) ToAffine() (*big.Int, *big.Int) {

View File

@ -29,32 +29,35 @@ var (
Two = &FieldElement{2, 0, 0, 0, 0} Two = &FieldElement{2, 0, 0, 0, 0}
) )
func (v *FieldElement) Zero() { func (v *FieldElement) Zero() *FieldElement {
v[0] = 0 v[0] = 0
v[1] = 0 v[1] = 0
v[2] = 0 v[2] = 0
v[3] = 0 v[3] = 0
v[4] = 0 v[4] = 0
return v
} }
func (v *FieldElement) One() { func (v *FieldElement) One() *FieldElement {
v[0] = 1 v[0] = 1
v[1] = 0 v[1] = 0
v[2] = 0 v[2] = 0
v[3] = 0 v[3] = 0
v[4] = 0 v[4] = 0
return v
} }
// SetInt sets the receiving FieldElement to the specified small integer. // SetInt sets the receiving FieldElement to the specified small integer.
func (v *FieldElement) SetInt(x uint64) { func (v *FieldElement) SetInt(x uint64) *FieldElement {
v[0] = x v[0] = x
v[1] = 0 v[1] = 0
v[2] = 0 v[2] = 0
v[3] = 0 v[3] = 0
v[4] = 0 v[4] = 0
return v
} }
func (v *FieldElement) Reduce(u *FieldElement) { func (v *FieldElement) Reduce(u *FieldElement) *FieldElement {
v.Set(u) v.Set(u)
// Lev v = v[0] + v[1]*2^51 + v[2]*2^102 + v[3]*2^153 + v[4]*2^204 // Lev v = v[0] + v[1]*2^51 + v[2]*2^102 + v[3]*2^153 + v[4]*2^204
@ -92,21 +95,24 @@ func (v *FieldElement) Reduce(u *FieldElement) {
v[3] = v[3] & maskLow51Bits v[3] = v[3] & maskLow51Bits
// no additional carry // no additional carry
v[4] = v[4] & maskLow51Bits v[4] = v[4] & maskLow51Bits
return v
} }
// Add sets v = a + b. Long sequences of additions without reduction that // Add sets v = a + b. Long sequences of additions without reduction that
// let coefficients grow larger than 54 bits would be a problem. Paper // let coefficients grow larger than 54 bits would be a problem. Paper
// cautions: "do not have such sequences of additions". // cautions: "do not have such sequences of additions".
func (v *FieldElement) Add(a, b *FieldElement) { func (v *FieldElement) Add(a, b *FieldElement) *FieldElement {
v[0] = a[0] + b[0] v[0] = a[0] + b[0]
v[1] = a[1] + b[1] v[1] = a[1] + b[1]
v[2] = a[2] + b[2] v[2] = a[2] + b[2]
v[3] = a[3] + b[3] v[3] = a[3] + b[3]
v[4] = a[4] + b[4] v[4] = a[4] + b[4]
return v
} }
// Sub sets v = a - b. // Sub sets v = a - b.
func (v *FieldElement) Sub(a, b *FieldElement) { func (v *FieldElement) Sub(a, b *FieldElement) *FieldElement {
t := *b t := *b
// Reduce each limb below 2^51, propagating carries. Ensures that results // Reduce each limb below 2^51, propagating carries. Ensures that results
@ -129,15 +135,17 @@ func (v *FieldElement) Sub(a, b *FieldElement) {
v[2] = (a[2] + 0xFFFFFFFFFFFFE) - t[2] v[2] = (a[2] + 0xFFFFFFFFFFFFE) - t[2]
v[3] = (a[3] + 0xFFFFFFFFFFFFE) - t[3] v[3] = (a[3] + 0xFFFFFFFFFFFFE) - t[3]
v[4] = (a[4] + 0xFFFFFFFFFFFFE) - t[4] v[4] = (a[4] + 0xFFFFFFFFFFFFE) - t[4]
return v
} }
// Neg sets v = -a. // Neg sets v = -a.
func (v *FieldElement) Neg(a *FieldElement) { func (v *FieldElement) Neg(a *FieldElement) *FieldElement {
v.Sub(&FieldElement{}, a) return v.Sub(Zero, a)
} }
// Invert sets v = 1/z mod p by calculating z^(p-2), p-2 = 2^255 - 21. // Invert sets v = 1/z mod p by calculating z^(p-2), p-2 = 2^255 - 21.
func (v *FieldElement) Invert(z *FieldElement) { func (v *FieldElement) Invert(z *FieldElement) *FieldElement {
// Inversion is implemented as exponentiation with exponent p 2. It uses the // Inversion is implemented as exponentiation with exponent p 2. It uses the
// same sequence of 255 squarings and 11 multiplications as [Curve25519]. // same sequence of 255 squarings and 11 multiplications as [Curve25519].
var z2, z9, z11, z2_5_0, z2_10_0, z2_20_0, z2_50_0, z2_100_0, t FieldElement var z2, z9, z11, z2_5_0, z2_10_0, z2_20_0, z2_50_0, z2_100_0, t FieldElement
@ -198,14 +206,15 @@ func (v *FieldElement) Invert(z *FieldElement) {
t.Square(&t) // 2^254 - 2^4 t.Square(&t) // 2^254 - 2^4
t.Square(&t) // 2^255 - 2^5 t.Square(&t) // 2^255 - 2^5
v.Mul(&t, &z11) // 2^255 - 21 return v.Mul(&t, &z11) // 2^255 - 21
} }
func (v *FieldElement) Set(a *FieldElement) { func (v *FieldElement) Set(a *FieldElement) *FieldElement {
*v = *a *v = *a
return v
} }
func (v *FieldElement) FromBytes(x *[32]byte) { func (v *FieldElement) FromBytes(x *[32]byte) *FieldElement {
v[0] = uint64(x[0]) v[0] = uint64(x[0])
v[0] |= uint64(x[1]) << 8 v[0] |= uint64(x[1]) << 8
v[0] |= uint64(x[2]) << 16 v[0] |= uint64(x[2]) << 16
@ -246,11 +255,12 @@ func (v *FieldElement) FromBytes(x *[32]byte) {
v[4] |= uint64(x[29]) << 28 v[4] |= uint64(x[29]) << 28
v[4] |= uint64(x[30]) << 36 v[4] |= uint64(x[30]) << 36
v[4] |= uint64(x[31]&127) << 44 v[4] |= uint64(x[31]&127) << 44
return v
} }
func (v *FieldElement) ToBytes(r *[32]byte) { func (v *FieldElement) ToBytes(r *[32]byte) {
var t FieldElement t := new(FieldElement).Reduce(v)
t.Reduce(v)
r[0] = byte(t[0] & 0xff) r[0] = byte(t[0] & 0xff)
r[1] = byte((t[0] >> 8) & 0xff) r[1] = byte((t[0] >> 8) & 0xff)
@ -294,7 +304,7 @@ func (v *FieldElement) ToBytes(r *[32]byte) {
r[31] = byte((t[4] >> 44)) r[31] = byte((t[4] >> 44))
} }
func (v *FieldElement) FromBig(num *big.Int) { func (v *FieldElement) FromBig(num *big.Int) *FieldElement {
var buf [32]byte var buf [32]byte
offset := 0 offset := 0
@ -312,7 +322,7 @@ func (v *FieldElement) FromBig(num *big.Int) {
} }
} }
v.FromBytes(&buf) return v.FromBytes(&buf)
} }
func (v *FieldElement) ToBig() *big.Int { func (v *FieldElement) ToBig() *big.Int {
@ -350,19 +360,19 @@ func (v *FieldElement) Equal(u *FieldElement) int {
// Select sets v to a if cond == 1, and to b if cond == 0. // Select sets v to a if cond == 1, and to b if cond == 0.
// v, a and b are allowed to overlap. // v, a and b are allowed to overlap.
func (v *FieldElement) Select(a, b *FieldElement, cond int) { func (v *FieldElement) Select(a, b *FieldElement, cond int) *FieldElement {
m := uint64(cond) * 0xffffffffffffffff m := uint64(cond) * 0xffffffffffffffff
v[0] = (m & a[0]) | (^m & b[0]) v[0] = (m & a[0]) | (^m & b[0])
v[1] = (m & a[1]) | (^m & b[1]) v[1] = (m & a[1]) | (^m & b[1])
v[2] = (m & a[2]) | (^m & b[2]) v[2] = (m & a[2]) | (^m & b[2])
v[3] = (m & a[3]) | (^m & b[3]) v[3] = (m & a[3]) | (^m & b[3])
v[4] = (m & a[4]) | (^m & b[4]) v[4] = (m & a[4]) | (^m & b[4])
return v
} }
// CondNeg sets v to -u if cond == 1, and to u if cond == 0. // CondNeg sets v to -u if cond == 1, and to u if cond == 0.
func (v *FieldElement) CondNeg(u *FieldElement, cond int) { func (v *FieldElement) CondNeg(u *FieldElement, cond int) *FieldElement {
v.Neg(u) return v.Select(v.Neg(u), u, cond)
v.Select(v, u, cond)
} }
// IsNegative returns 1 if v is negative, and 0 otherwise. // IsNegative returns 1 if v is negative, and 0 otherwise.
@ -373,6 +383,6 @@ func (v *FieldElement) IsNegative() int {
} }
// Abs sets v to |u|. v and u are allowed to overlap. // Abs sets v to |u|. v and u are allowed to overlap.
func (v *FieldElement) Abs(u *FieldElement) { func (v *FieldElement) Abs(u *FieldElement) *FieldElement {
v.CondNeg(u, u.IsNegative()) return v.CondNeg(u, u.IsNegative())
} }

View File

@ -7,7 +7,7 @@
package radix51 package radix51
// Mul sets out = x * y. // Mul sets out = x * y.
func (v *FieldElement) Mul(x, y *FieldElement) { func (v *FieldElement) Mul(x, y *FieldElement) *FieldElement {
var x0, x1, x2, x3, x4 uint64 var x0, x1, x2, x3, x4 uint64
var y0, y1, y2, y3, y4 uint64 var y0, y1, y2, y3, y4 uint64
@ -123,4 +123,5 @@ func (v *FieldElement) Mul(x, y *FieldElement) {
v[2] = r20 v[2] = r20
v[3] = r30 v[3] = r30
v[4] = r40 v[4] = r40
return v
} }

View File

@ -7,8 +7,9 @@
package radix51 package radix51
// Mul sets out = x * y. // Mul sets out = x * y.
func (v *FieldElement) Mul(x, y *FieldElement) { func (v *FieldElement) Mul(x, y *FieldElement) *FieldElement {
feMul(v, x, y) feMul(v, x, y)
return v
} }
// go:noescape // go:noescape

View File

@ -7,7 +7,7 @@
package radix51 package radix51
// Square sets v = x * x. // Square sets v = x * x.
func (v *FieldElement) Square(x *FieldElement) { func (v *FieldElement) Square(x *FieldElement) *FieldElement {
// Squaring needs only 15 mul instructions. Some inputs are multiplied by 2; // Squaring needs only 15 mul instructions. Some inputs are multiplied by 2;
// this is combined with multiplication by 19 where possible. The coefficient // this is combined with multiplication by 19 where possible. The coefficient
// reduction after squaring is the same as for multiplication. // reduction after squaring is the same as for multiplication.
@ -95,4 +95,5 @@ func (v *FieldElement) Square(x *FieldElement) {
v[2] = r20 v[2] = r20
v[3] = r30 v[3] = r30
v[4] = r40 v[4] = r40
return v
} }

View File

@ -7,8 +7,9 @@
package radix51 package radix51
// Square sets v = x * x. // Square sets v = x * x.
func (v *FieldElement) Square(x *FieldElement) { func (v *FieldElement) Square(x *FieldElement) *FieldElement {
feSquare(v, x) feSquare(v, x)
return v
} }
// go:noescape // go:noescape