Skip to content

Commit 21c3483

Browse files
committed
Updating interface for decaf and curve.
1 parent 0a3da6a commit 21c3483

13 files changed

+225
-258
lines changed

ecc/goldilocks/constants.go

+9
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,15 @@ import (
66
fp "github.com/cloudflare/circl/math/fp448"
77
)
88

9+
const (
10+
// ScalarSize is the size (in bytes) of scalars.
11+
ScalarSize = 56
12+
// CurveEncodingSize is the size (in bytes) of an encoded point on the Goldilocks curve.
13+
CurveEncodingSize = fp.Size + 1
14+
// DecafEncodingSize is the size (in bytes) of an encoded Decaf element.
15+
DecafEncodingSize = fp.Size
16+
)
17+
918
var (
1019
// genX is the x-coordintate of the generator of Goldilocks curve.
1120
genX = fp.Elt{

ecc/goldilocks/curve.go

+27-29
Original file line numberDiff line numberDiff line change
@@ -1,61 +1,59 @@
11
package goldilocks
22

3-
import fp "github.com/cloudflare/circl/math/fp448"
3+
import (
4+
fp "github.com/cloudflare/circl/math/fp448"
5+
)
46

57
// Curve provides operations on the Goldilocks curve.
68
// Curve is a zero-length datatype.
79
type Curve struct{}
810

911
// Identity returns the identity point.
10-
func (Curve) Identity() *Point {
11-
return &Point{
12-
y: fp.One(),
13-
z: fp.One(),
14-
}
15-
}
12+
func (Curve) Identity() *Point { return &Point{y: fp.One(), z: fp.One()} }
1613

1714
// Generator returns the generator point.
18-
func (Curve) Generator() *Point {
19-
return &Point{
20-
x: genX,
21-
y: genY,
22-
z: fp.One(),
23-
ta: genX,
24-
tb: genY,
25-
}
26-
}
15+
func (Curve) Generator() *Point { return &Point{x: genX, y: genY, z: fp.One(), ta: genX, tb: genY} }
2716

2817
// IsOnCurve returns true if the point lies on the curve.
2918
func (Curve) IsOnCurve(P *Point) bool { return isOnCurve(&P.x, &P.y, &P.ta, &P.tb, &P.z, false) }
3019

3120
// Order returns the number of points in the prime subgroup.
3221
func (Curve) Order() Scalar { return order }
3322

34-
// Double returns R = 2P.
35-
func (Curve) Double(R, P *Point) *Point { R := *P; R.Double(); return &R }
23+
// Double calculates R = 2P.
24+
func (Curve) Double(R, P *Point) { *R = *P; R.Double() }
3625

37-
// Add returns P+Q.
38-
func (Curve) Add(P, Q *Point) *Point { R := *P; R.Add(Q); return &R }
26+
// Add calculates R = P+Q.
27+
func (Curve) Add(R, P, Q *Point) { S := *P; S.Add(Q); *R = S }
3928

40-
// ScalarMult returns kP. This function runs in constant time.
41-
func (e Curve) ScalarMult(k *Scalar, P *Point) *Point {
29+
// ScalarMult calculates Q = kP. This function runs in constant time.
30+
func (Curve) ScalarMult(Q *Point, k *Scalar, P *Point) {
31+
var t twistCurve
4232
k4 := &Scalar{}
4333
k4.divBy4(k)
44-
return e.pull(twistCurve{}.ScalarMult(k4, e.push(P)))
34+
R := &twistPoint{}
35+
t.ScalarMult(R, k4, t.pull(P))
36+
*Q = *t.push(R)
4537
}
4638

47-
// ScalarBaseMult returns kG where G is the generator point. This function runs in constant time.
48-
func (e Curve) ScalarBaseMult(k *Scalar) *Point {
39+
// ScalarBaseMult calculates Q = kG, where G is the generator of the Goldilocks curve. This function runs in constant time.
40+
func (Curve) ScalarBaseMult(Q *Point, k *Scalar) {
41+
var t twistCurve
4942
k4 := &Scalar{}
5043
k4.divBy4(k)
51-
return e.pull(twistCurve{}.ScalarBaseMult(k4))
44+
R := &twistPoint{}
45+
t.ScalarBaseMult(R, k4)
46+
*Q = *t.push(R)
5247
}
5348

54-
// CombinedMult returns mG+nP, where G is the generator point. This function is non-constant time.
55-
func (e Curve) CombinedMult(m, n *Scalar, P *Point) *Point {
49+
// CombinedMult calculates Q = mG+nP, where G is the generator of the Goldilocks curve. This function does NOT run in constant time.
50+
func (Curve) CombinedMult(Q *Point, m, n *Scalar, P *Point) {
51+
var t twistCurve
5652
m4 := &Scalar{}
5753
n4 := &Scalar{}
5854
m4.divBy4(m)
5955
n4.divBy4(n)
60-
return e.pull(twistCurve{}.CombinedMult(m4, n4, twistCurve{}.pull(P)))
56+
R := &twistPoint{}
57+
t.CombinedMult(R, m4, n4, t.pull(P))
58+
*Q = *t.push(R)
6159
}

ecc/goldilocks/curve_test.go

+34-13
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,10 @@ func TestScalarMult(t *testing.T) {
1515
zero := &goldilocks.Scalar{}
1616

1717
t.Run("rG=0", func(t *testing.T) {
18+
got := &goldilocks.Point{}
1819
order := e.Order()
1920
for i := 0; i < testTimes; i++ {
20-
got := e.ScalarBaseMult(&order)
21+
e.ScalarBaseMult(got, &order)
2122
got.ToAffine()
2223
want := e.Identity()
2324

@@ -28,11 +29,12 @@ func TestScalarMult(t *testing.T) {
2829
}
2930
})
3031
t.Run("rP=0", func(t *testing.T) {
32+
got := &goldilocks.Point{}
3133
order := e.Order()
3234
for i := 0; i < testTimes; i++ {
3335
P := randomPoint()
3436

35-
got := e.ScalarMult(&order, P)
37+
e.ScalarMult(got, &order, P)
3638
got.ToAffine()
3739
want := e.Identity()
3840

@@ -43,43 +45,51 @@ func TestScalarMult(t *testing.T) {
4345
}
4446
})
4547
t.Run("kG", func(t *testing.T) {
48+
got := &goldilocks.Point{}
49+
want := &goldilocks.Point{}
4650
I := e.Identity()
4751
for i := 0; i < testTimes; i++ {
4852
_, _ = rand.Read(k[:])
4953

50-
got := e.ScalarBaseMult(k)
51-
want := e.CombinedMult(k, zero, I) // k*G + 0*I
54+
e.ScalarBaseMult(got, k)
55+
e.CombinedMult(want, k, zero, I) // k*G + 0*I
5256

5357
if !e.IsOnCurve(got) || !e.IsOnCurve(want) || !got.IsEqual(want) {
5458
test.ReportError(t, got, want, k)
5559
}
5660
}
5761
})
5862
t.Run("kP", func(t *testing.T) {
63+
got := &goldilocks.Point{}
64+
want := &goldilocks.Point{}
5965
for i := 0; i < testTimes; i++ {
6066
P := randomPoint()
6167
_, _ = rand.Read(k[:])
6268

63-
got := e.ScalarMult(k, P)
64-
want := e.CombinedMult(zero, k, P)
69+
e.ScalarMult(got, k, P)
70+
e.CombinedMult(want, zero, k, P)
6571

6672
if !e.IsOnCurve(got) || !e.IsOnCurve(want) || !got.IsEqual(want) {
6773
test.ReportError(t, got, want, P, k)
6874
}
6975
}
7076
})
7177
t.Run("kG+lP", func(t *testing.T) {
78+
got := &goldilocks.Point{}
79+
want := &goldilocks.Point{}
80+
kG := &goldilocks.Point{}
81+
lP := &goldilocks.Point{}
7282
G := e.Generator()
7383
l := &goldilocks.Scalar{}
7484
for i := 0; i < testTimes; i++ {
7585
P := randomPoint()
7686
_, _ = rand.Read(k[:])
7787
_, _ = rand.Read(l[:])
7888

79-
kG := e.ScalarMult(k, G)
80-
lP := e.ScalarMult(l, P)
81-
got := e.Add(kG, lP)
82-
want := e.CombinedMult(k, l, P)
89+
e.ScalarMult(kG, k, G)
90+
e.ScalarMult(lP, l, P)
91+
e.Add(got, kG, lP)
92+
e.CombinedMult(want, k, l, P)
8393

8494
if !e.IsOnCurve(got) || !e.IsOnCurve(want) || !got.IsEqual(want) {
8595
test.ReportError(t, got, want, P, k, l)
@@ -94,20 +104,31 @@ func BenchmarkCurve(b *testing.B) {
94104
_, _ = rand.Read(k[:])
95105
_, _ = rand.Read(l[:])
96106
P := randomPoint()
107+
Q := randomPoint()
97108

109+
b.Run("Add", func(b *testing.B) {
110+
for i := 0; i < b.N; i++ {
111+
P.Add(Q)
112+
}
113+
})
98114
b.Run("ScalarMult", func(b *testing.B) {
99115
for i := 0; i < b.N; i++ {
100-
P = e.ScalarMult(&k, P)
116+
e.ScalarMult(P, &k, P)
101117
}
102118
})
103119
b.Run("ScalarBaseMult", func(b *testing.B) {
104120
for i := 0; i < b.N; i++ {
105-
e.ScalarBaseMult(&k)
121+
e.ScalarBaseMult(P, &k)
106122
}
107123
})
108124
b.Run("CombinedMult", func(b *testing.B) {
109125
for i := 0; i < b.N; i++ {
110-
P = e.CombinedMult(&k, &l, P)
126+
e.CombinedMult(P, &k, &l, P)
127+
}
128+
})
129+
b.Run("ToAffine", func(b *testing.B) {
130+
for i := 0; i < b.N; i++ {
131+
P.ToAffine()
111132
}
112133
})
113134
}

ecc/goldilocks/decaf.go

+47-50
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,6 @@ package goldilocks
22

33
import fp "github.com/cloudflare/circl/math/fp448"
44

5-
// DecafEncodingSize is the size (in bytes) for storing a decaf element.
6-
const DecafEncodingSize = fp.Size
7-
85
// Decaf provides operations of a prime-order group from goldilocks curve.
96
// Its internal implementation uses the twist of the goldilocks curve.
107
// This uses version 1.1 of the encoding. Decaf is a zero-length datatype.
@@ -19,9 +16,6 @@ func (e Elt) String() string { return e.p.String() }
1916
// IsValid returns True if a is a valid element of the group.
2017
func (d Decaf) IsValid(a *Elt) bool { return d.c.IsOnCurve(&a.p) }
2118

22-
// IsIdentity returns True if a is the identity of the group.
23-
func (d Decaf) IsIdentity(a *Elt) bool { return fp.IsZero(&a.p.x) }
24-
2519
// Identity returns the identity element of the group.
2620
func (d Decaf) Identity() *Elt { return &Elt{*d.c.Identity()} }
2721

@@ -32,7 +26,7 @@ func (d Decaf) Generator() *Elt { return &Elt{*d.c.pull(Curve{}.Generator())} }
3226
func (d Decaf) Order() Scalar { return order }
3327

3428
// Add calculates c=a+b, where + is the group operation.
35-
func (d Decaf) Add(c, a, b *Elt) { c.p = a.p; c.p.Add(&b.p) }
29+
func (d Decaf) Add(c, a, b *Elt) { q := a.p; q.Add(&b.p); c.p = q }
3630

3731
// Double calculates c=a+a, where + is the group operation.
3832
func (d Decaf) Double(c, a *Elt) { c.p = a.p; c.p.Double() }
@@ -41,65 +35,36 @@ func (d Decaf) Double(c, a *Elt) { c.p = a.p; c.p.Double() }
4135
func (d Decaf) Neg(c, a *Elt) { c.p = a.p; c.p.cneg(1) }
4236

4337
// Mul calculates c=n*a, where * is scalar multiplication on the group.
44-
func (d Decaf) Mul(c *Elt, n *Scalar, a *Elt) { c.p = *d.c.ScalarMult(n, &a.p) }
38+
func (d Decaf) Mul(c *Elt, n *Scalar, a *Elt) { d.c.ScalarMult(&c.p, n, &a.p) }
4539

4640
// MulGen calculates c=n*g, where * is scalar multiplication on the group,
4741
// and g is the generator of the group.
48-
func (d Decaf) MulGen(c *Elt, n *Scalar) { c.p = *d.c.ScalarBaseMult(n) }
42+
func (d Decaf) MulGen(c *Elt, n *Scalar) { d.c.ScalarBaseMult(&c.p, n) }
4943

50-
// AreEqual returns True if a=b, where = is an equivalence relation.
51-
func (d Decaf) AreEqual(a, b *Elt) bool {
44+
// IsIdentity returns True if e is the identity of the group.
45+
func (e *Elt) IsIdentity() bool { return fp.IsZero(&e.p.x) }
46+
47+
// IsEqual returns True if e=a, where = is an equivalence relation.
48+
func (e *Elt) IsEqual(a *Elt) bool {
5249
l, r := &fp.Elt{}, &fp.Elt{}
53-
fp.Mul(l, &a.p.x, &b.p.y)
54-
fp.Mul(r, &b.p.x, &a.p.y)
50+
fp.Mul(l, &e.p.x, &a.p.y)
51+
fp.Mul(r, &a.p.x, &e.p.y)
5552
fp.Sub(l, l, r)
5653
return fp.IsZero(l)
5754
}
5855

59-
// Marshal returns a unique encoding of the element e.
60-
func (e *Elt) Marshal() []byte {
61-
x, ta, tb, z := e.p.x, e.p.ta, e.p.tb, e.p.z
62-
one, t, t2, s := &fp.Elt{}, &fp.Elt{}, &fp.Elt{}, &fp.Elt{}
63-
fp.SetOne(one)
64-
fp.Mul(t, &ta, &tb) // t = ta*tb
65-
t0, t1 := x, *t // (t0,t1) = (x,t)
66-
fp.Sqr(t2, &x) // t2 = x^2
67-
fp.AddSub(&t0, &t1) // (t0,t1) = (x+t,x-t)
68-
fp.Mul(&t1, &t0, &t1) // t1 = (x+t)*(x-t)
69-
fp.Mul(&t0, &t1, &aMinusDTwist) // t0 = (a-d)*(x+t)*(x-t)
70-
fp.Mul(&t0, &t0, t2) // t0 = x^2*(a-d)*(x+t)*(x-t)
71-
fp.InvSqrt(&t0, one, &t0) // t0 = 1/sqrt( x^2*(a-d)*(z+y)*(z-y) )
72-
fp.Mul(&t1, &t1, &t0) // t1 = (z+y)*(z-y)/sqrt( x^2*(a-d)*(z+y)*(z-y) )
73-
fp.Mul(t2, &t1, &sqrtAMinusDTwist) // t2 = sqrt( (z+y)*(z-y) )/z
74-
isNeg := fp.Parity(t2) // isNeg = sgn(t2)
75-
fp.Neg(t2, &t1) // t2 = -t1
76-
fp.Cmov(&t1, t2, uint(isNeg)) // if t2 is negative then t1 = -t1
77-
fp.Mul(s, &t1, &z) // s = t1*z
78-
fp.Sub(s, s, t) // s = t1*z - t
79-
fp.Mul(s, s, &x) // s = x*(t1*z - t)
80-
fp.Mul(s, s, &t0) // s = isr*x*(t1*z - t)
81-
fp.Mul(s, s, &aMinusDTwist) // s = (a-d)*isr*x*(t1*z - t)
82-
isNeg = fp.Parity(s) // isNeg = sgn(s)
83-
fp.Neg(&t0, s) // t0 = -s
84-
fp.Cmov(s, &t0, uint(isNeg)) // if s is negative then s = -s
85-
86-
var encS [fp.Size]byte
87-
_ = fp.ToBytes(encS[:], s)
88-
return encS[:]
89-
}
90-
91-
// Unmarshal if succeeds returns nil and constructs an element e from an
92-
// encoding stored in a slice b of DecafEncodingSize bytes.
93-
func (e *Elt) Unmarshal(b []byte) error {
56+
// UnmarshalBinary if succeeds returns a Decaf element by decoding the first
57+
// DecafEncodingSize bytes of b.
58+
func (e *Elt) UnmarshalBinary(b []byte) error {
9459
if len(b) < DecafEncodingSize {
9560
return errInvalidDecoding
9661
}
9762

9863
s := &fp.Elt{}
9964
copy(s[:], b[:DecafEncodingSize])
10065
isNeg := fp.Parity(s)
101-
p := fp.P()
102-
if isNeg == 1 || !isLessThan(b[:DecafEncodingSize], p[:]) {
66+
modulus := fp.P()
67+
if isNeg == 1 || !isLessThan(b[:DecafEncodingSize], modulus[:]) {
10368
return errInvalidDecoding
10469
}
10570

@@ -138,3 +103,35 @@ func (e *Elt) Unmarshal(b []byte) error {
138103
fp.SetOne(&e.p.z)
139104
return nil
140105
}
106+
107+
// MarshalBinary returns a unique encoding of the element e.
108+
func (e *Elt) MarshalBinary() ([]byte, error) {
109+
x, ta, tb, z := e.p.x, e.p.ta, e.p.tb, e.p.z
110+
one, t, t2, s := &fp.Elt{}, &fp.Elt{}, &fp.Elt{}, &fp.Elt{}
111+
fp.SetOne(one)
112+
fp.Mul(t, &ta, &tb) // t = ta*tb
113+
t0, t1 := x, *t // (t0,t1) = (x,t)
114+
fp.Sqr(t2, &x) // t2 = x^2
115+
fp.AddSub(&t0, &t1) // (t0,t1) = (x+t,x-t)
116+
fp.Mul(&t1, &t0, &t1) // t1 = (x+t)*(x-t)
117+
fp.Mul(&t0, &t1, &aMinusDTwist) // t0 = (a-d)*(x+t)*(x-t)
118+
fp.Mul(&t0, &t0, t2) // t0 = x^2*(a-d)*(x+t)*(x-t)
119+
fp.InvSqrt(&t0, one, &t0) // t0 = 1/sqrt( x^2*(a-d)*(z+y)*(z-y) )
120+
fp.Mul(&t1, &t1, &t0) // t1 = (z+y)*(z-y)/sqrt( x^2*(a-d)*(z+y)*(z-y) )
121+
fp.Mul(t2, &t1, &sqrtAMinusDTwist) // t2 = sqrt( (z+y)*(z-y) )/z
122+
isNeg := fp.Parity(t2) // isNeg = sgn(t2)
123+
fp.Neg(t2, &t1) // t2 = -t1
124+
fp.Cmov(&t1, t2, uint(isNeg)) // if t2 is negative then t1 = -t1
125+
fp.Mul(s, &t1, &z) // s = t1*z
126+
fp.Sub(s, s, t) // s = t1*z - t
127+
fp.Mul(s, s, &x) // s = x*(t1*z - t)
128+
fp.Mul(s, s, &t0) // s = isr*x*(t1*z - t)
129+
fp.Mul(s, s, &aMinusDTwist) // s = (a-d)*isr*x*(t1*z - t)
130+
isNeg = fp.Parity(s) // isNeg = sgn(s)
131+
fp.Neg(&t0, s) // t0 = -s
132+
fp.Cmov(s, &t0, uint(isNeg)) // if s is negative then s = -s
133+
134+
var encS [fp.Size]byte
135+
err := fp.ToBytes(encS[:], s)
136+
return encS[:], err
137+
}

0 commit comments

Comments
 (0)