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).
func (curve ed25519Curve) Double(x1, y1 *big.Int) (x, y *big.Int) {
var p group.ProjectiveGroupElement
p.FromAffine(x1, y1)
p := new(group.ProjectiveGroupElement).FromAffine(x1, y1)
// 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.
@ -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)
if b == 0 {
r1.Add(&r0, &r1)
r0.Double()
r0.Double(&r0)
} else {
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
// 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) {
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"
@ -130,20 +131,17 @@ func (v *ExtendedGroupElement) Add(p1, p2 *ExtendedGroupElement) *ExtendedGroupE
// 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() *ExtendedGroupElement {
func (v *ExtendedGroupElement) Double(u *ExtendedGroupElement) *ExtendedGroupElement {
// 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
// A ← X1^2, B ← Y1^2
A.Square(&v.X)
B.Square(&v.Y)
A.Square(&u.X)
B.Square(&u.Y)
// C ← 2*Z1^2
C.Square(&v.Z)
C.Square(&u.Z)
C.Add(&C, &C) // TODO should probably implement FeSquare2
// D ← -1*A
@ -151,7 +149,7 @@ func (v *ExtendedGroupElement) Double() *ExtendedGroupElement {
// E ← (X1+Y1)^2 A B
var t0 radix51.FieldElement
t0.Add(&v.X, &v.Y)
t0.Add(&u.X, &u.Y)
t0.Square(&t0)
E.Sub(&t0, &A)
E.Sub(&E, &B)
@ -174,10 +172,11 @@ type ProjectiveGroupElement struct {
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.Y.FromBig(y)
v.Z.Zero()
return v
}
func (v *ProjectiveGroupElement) ToAffine() (*big.Int, *big.Int) {

View File

@ -29,32 +29,35 @@ var (
Two = &FieldElement{2, 0, 0, 0, 0}
)
func (v *FieldElement) Zero() {
func (v *FieldElement) Zero() *FieldElement {
v[0] = 0
v[1] = 0
v[2] = 0
v[3] = 0
v[4] = 0
return v
}
func (v *FieldElement) One() {
func (v *FieldElement) One() *FieldElement {
v[0] = 1
v[1] = 0
v[2] = 0
v[3] = 0
v[4] = 0
return v
}
// 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[1] = 0
v[2] = 0
v[3] = 0
v[4] = 0
return v
}
func (v *FieldElement) Reduce(u *FieldElement) {
func (v *FieldElement) Reduce(u *FieldElement) *FieldElement {
v.Set(u)
// 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
// no additional carry
v[4] = v[4] & maskLow51Bits
return v
}
// Add sets v = a + b. Long sequences of additions without reduction that
// let coefficients grow larger than 54 bits would be a problem. Paper
// 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[1] = a[1] + b[1]
v[2] = a[2] + b[2]
v[3] = a[3] + b[3]
v[4] = a[4] + b[4]
return v
}
// Sub sets v = a - b.
func (v *FieldElement) Sub(a, b *FieldElement) {
func (v *FieldElement) Sub(a, b *FieldElement) *FieldElement {
t := *b
// 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[3] = (a[3] + 0xFFFFFFFFFFFFE) - t[3]
v[4] = (a[4] + 0xFFFFFFFFFFFFE) - t[4]
return v
}
// Neg sets v = -a.
func (v *FieldElement) Neg(a *FieldElement) {
v.Sub(&FieldElement{}, a)
func (v *FieldElement) Neg(a *FieldElement) *FieldElement {
return v.Sub(Zero, a)
}
// 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
// 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
@ -198,14 +206,15 @@ func (v *FieldElement) Invert(z *FieldElement) {
t.Square(&t) // 2^254 - 2^4
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
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[1]) << 8
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[30]) << 36
v[4] |= uint64(x[31]&127) << 44
return v
}
func (v *FieldElement) ToBytes(r *[32]byte) {
var t FieldElement
t.Reduce(v)
t := new(FieldElement).Reduce(v)
r[0] = byte(t[0] & 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))
}
func (v *FieldElement) FromBig(num *big.Int) {
func (v *FieldElement) FromBig(num *big.Int) *FieldElement {
var buf [32]byte
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 {
@ -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.
// 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
v[0] = (m & a[0]) | (^m & b[0])
v[1] = (m & a[1]) | (^m & b[1])
v[2] = (m & a[2]) | (^m & b[2])
v[3] = (m & a[3]) | (^m & b[3])
v[4] = (m & a[4]) | (^m & b[4])
return v
}
// CondNeg sets v to -u if cond == 1, and to u if cond == 0.
func (v *FieldElement) CondNeg(u *FieldElement, cond int) {
v.Neg(u)
v.Select(v, u, cond)
func (v *FieldElement) CondNeg(u *FieldElement, cond int) *FieldElement {
return v.Select(v.Neg(u), u, cond)
}
// 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.
func (v *FieldElement) Abs(u *FieldElement) {
v.CondNeg(u, u.IsNegative())
func (v *FieldElement) Abs(u *FieldElement) *FieldElement {
return v.CondNeg(u, u.IsNegative())
}

View File

@ -7,7 +7,7 @@
package radix51
// 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 y0, y1, y2, y3, y4 uint64
@ -123,4 +123,5 @@ func (v *FieldElement) Mul(x, y *FieldElement) {
v[2] = r20
v[3] = r30
v[4] = r40
return v
}

View File

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

View File

@ -7,7 +7,7 @@
package radix51
// 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;
// this is combined with multiplication by 19 where possible. The coefficient
// reduction after squaring is the same as for multiplication.
@ -95,4 +95,5 @@ func (v *FieldElement) Square(x *FieldElement) {
v[2] = r20
v[3] = r30
v[4] = r40
return v
}

View File

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