mirror of https://github.com/gtank/ristretto255
Implement ScalarMult using Montgomery pattern and dedicated
extended-coordinates doubling. This will be slow.
This commit is contained in:
parent
ce27eaf07c
commit
0ba575b405
|
@ -6,6 +6,7 @@ package ed25519
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"crypto/rand"
|
"crypto/rand"
|
||||||
|
"io"
|
||||||
"math/big"
|
"math/big"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
@ -101,6 +102,37 @@ func BenchmarkDouble(b *testing.B) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestScalarMult(t *testing.T) {
|
||||||
|
ed := Ed25519()
|
||||||
|
x, y := ed.Params().Gx, ed.Params().Gy
|
||||||
|
|
||||||
|
twoX, twoY := ed.ScalarMult(x, y, big.NewInt(2).Bytes())
|
||||||
|
xPlusX, yPlusY := ed.Add(x, y, x, y)
|
||||||
|
|
||||||
|
if !ed.IsOnCurve(twoX, twoY) {
|
||||||
|
t.Error("2*B is not on the curve")
|
||||||
|
}
|
||||||
|
|
||||||
|
if twoX.Cmp(xPlusX) != 0 || twoY.Cmp(yPlusY) != 0 {
|
||||||
|
t.Errorf("2*B != B+B")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkScalarMult(b *testing.B) {
|
||||||
|
ed := Ed25519()
|
||||||
|
Bx, By := ed.Params().Gx, ed.Params().Gy
|
||||||
|
|
||||||
|
var k [32]byte
|
||||||
|
_, err := io.ReadFull(rand.Reader, k[:])
|
||||||
|
if err != nil {
|
||||||
|
b.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
_, _ = ed.ScalarMult(Bx, By, k[:])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// // Test vector generated by instrumenting x/crypto/ed25519 GenerateKey
|
// // Test vector generated by instrumenting x/crypto/ed25519 GenerateKey
|
||||||
// // seed: c240344fcc6615dda52da98149377ad2b13fdba2bc39a50ba9f3afb2cbd4abaa
|
// // seed: c240344fcc6615dda52da98149377ad2b13fdba2bc39a50ba9f3afb2cbd4abaa
|
||||||
// // expanded: f04154b9d80963bb4c76214ece8a1049bdd16fbfc5003aff9835a59643ace276
|
// // expanded: f04154b9d80963bb4c76214ece8a1049bdd16fbfc5003aff9835a59643ace276
|
||||||
|
@ -339,24 +371,6 @@ func BenchmarkDouble(b *testing.B) {
|
||||||
// }
|
// }
|
||||||
// }
|
// }
|
||||||
|
|
||||||
// func BenchmarkScalarMult(b *testing.B) {
|
|
||||||
// ed := Ed25519()
|
|
||||||
// Bx, By := ed.Params().Gx, ed.Params().Gy
|
|
||||||
|
|
||||||
// var k [32]byte
|
|
||||||
// _, err := io.ReadFull(rand.Reader, k[:])
|
|
||||||
// if err != nil {
|
|
||||||
// b.Fatal(err)
|
|
||||||
// }
|
|
||||||
// k[0] &= 248
|
|
||||||
// k[31] &= 127
|
|
||||||
// k[31] |= 64
|
|
||||||
|
|
||||||
// for i := 0; i < b.N; i++ {
|
|
||||||
// _, _ = ed.ScalarMult(Bx, By, k[:])
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
var radix51A = field.FieldElement{
|
var radix51A = field.FieldElement{
|
||||||
486662, 0, 0, 0, 0,
|
486662, 0, 0, 0, 0,
|
||||||
}
|
}
|
||||||
|
|
|
@ -97,9 +97,71 @@ func (v *ExtendedGroupElement) Add(p1, p2 *ExtendedGroupElement) *ExtendedGroupE
|
||||||
return v
|
return v
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 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 ← G−C
|
||||||
|
// H ← D−B
|
||||||
|
// 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() *ExtendedGroupElement {
|
func (v *ExtendedGroupElement) Double() *ExtendedGroupElement {
|
||||||
// return v.ToProjective().Double().ToExtended()
|
// TODO: Convert to projective coordinates? Section 4.3 mixed doubling?
|
||||||
panic("not yet implemented")
|
// 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 field.FieldElement
|
||||||
|
|
||||||
|
// A ← X1^2, B ← Y1^2
|
||||||
|
field.FeSquare(&A, &v.X)
|
||||||
|
field.FeSquare(&B, &v.Y)
|
||||||
|
|
||||||
|
// C ← 2*Z1^2
|
||||||
|
field.FeSquare(&C, &v.Z)
|
||||||
|
field.FeAdd(&C, &C, &C) // TODO should probably implement FeSquare2
|
||||||
|
|
||||||
|
// D ← -1*A
|
||||||
|
field.FeNeg(&D, &A) // implemented as substraction
|
||||||
|
|
||||||
|
// E ← (X1+Y1)^2 − A − B
|
||||||
|
var t0 field.FieldElement
|
||||||
|
field.FeAdd(&t0, &v.X, &v.Y)
|
||||||
|
field.FeSquare(&t0, &t0)
|
||||||
|
field.FeSub(&E, &t0, &A)
|
||||||
|
field.FeSub(&E, &E, &B)
|
||||||
|
|
||||||
|
// G ← D+B
|
||||||
|
field.FeAdd(&G, &D, &B)
|
||||||
|
// F ← G−C
|
||||||
|
field.FeSub(&F, &G, &C)
|
||||||
|
// H ← D−B
|
||||||
|
field.FeSub(&H, &D, &B)
|
||||||
|
// X3 ← E*F
|
||||||
|
field.FeMul(&v.X, &E, &F)
|
||||||
|
// Y3 ← G*H
|
||||||
|
field.FeMul(&v.Y, &G, &H)
|
||||||
|
// T3 ← E*H
|
||||||
|
field.FeMul(&v.T, &E, &H)
|
||||||
|
// Z3 ← F*G
|
||||||
|
field.FeMul(&v.Z, &F, &G)
|
||||||
|
|
||||||
|
return v
|
||||||
}
|
}
|
||||||
|
|
||||||
// Projective coordinates are XYZ with x = X/Z, y = Y/Z, or the "P2"
|
// Projective coordinates are XYZ with x = X/Z, y = Y/Z, or the "P2"
|
||||||
|
@ -165,9 +227,13 @@ func (v *ProjectiveGroupElement) Zero() *ProjectiveGroupElement {
|
||||||
// Z3 = F^2-2*F
|
// Z3 = F^2-2*F
|
||||||
//
|
//
|
||||||
// This assumption is one reason why this package is internal. For instance, it
|
// This assumption is one reason why this package is internal. For instance, it
|
||||||
// will not hold throughout a Montgomery ladder using extended coordinates.
|
// will not hold throughout a Montgomery ladder, when we convert to projective
|
||||||
// TODO: Check or switch entirely to dbl-2008-bbjlp like everyone else.
|
// from possibly arbitrary extended coordinates.
|
||||||
func (v *ProjectiveGroupElement) DoubleZ1() *ProjectiveGroupElement {
|
func (v *ProjectiveGroupElement) DoubleZ1() *ProjectiveGroupElement {
|
||||||
|
// TODO This function is inconsistent with the other ones in that it
|
||||||
|
// returns a copy rather than smashing the receiver. It doesn't matter
|
||||||
|
// because it is always called on ephemeral intermediate values, but should
|
||||||
|
// fix.
|
||||||
var p, q ProjectiveGroupElement
|
var p, q ProjectiveGroupElement
|
||||||
var t0, t1 field.FieldElement
|
var t0, t1 field.FieldElement
|
||||||
|
|
||||||
|
@ -176,12 +242,10 @@ func (v *ProjectiveGroupElement) DoubleZ1() *ProjectiveGroupElement {
|
||||||
// C = X1^2, D = Y1^2
|
// C = X1^2, D = Y1^2
|
||||||
field.FeSquare(&t0, &p.X)
|
field.FeSquare(&t0, &p.X)
|
||||||
field.FeSquare(&t1, &p.Y)
|
field.FeSquare(&t1, &p.Y)
|
||||||
field.FeMul(&p.Z, &p.X, &p.Y)
|
|
||||||
|
|
||||||
// B = (X1+Y1)^2 = X1^2 + Y1^2 + 2*(X*Y)
|
// B = (X1+Y1)^2
|
||||||
field.FeAdd(&q.X, &t0, &t1)
|
field.FeAdd(&p.Z, &p.X, &p.Y) // Z is irrelevant but already allocated
|
||||||
field.FeAdd(&q.X, &q.X, &p.Z)
|
field.FeSquare(&q.X, &p.Z)
|
||||||
field.FeAdd(&q.X, &q.X, &p.Z)
|
|
||||||
|
|
||||||
// E = a*C where a = -1
|
// E = a*C where a = -1
|
||||||
field.FeNeg(&q.Z, &t0)
|
field.FeNeg(&q.Z, &t0)
|
||||||
|
|
Loading…
Reference in New Issue