Skip to content

Commit 2a8d115

Browse files
committed
One test for decaf, unmarshaling straight-line code, and check for errors.
1 parent 21c3483 commit 2a8d115

File tree

6 files changed

+89
-84
lines changed

6 files changed

+89
-84
lines changed

ecc/goldilocks/constants.go

+3-2
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,9 @@ const (
1515
DecafEncodingSize = fp.Size
1616
)
1717

18+
// All these values are in RFC-7748 (https://tools.ietf.org/html/rfc7748).
1819
var (
19-
// genX is the x-coordintate of the generator of Goldilocks curve.
20+
// genX is the x-coordinate of the generator of Goldilocks curve.
2021
genX = fp.Elt{
2122
0x5e, 0xc0, 0x0c, 0xc7, 0x2b, 0xa8, 0x26, 0x26,
2223
0x8e, 0x93, 0x00, 0x8b, 0xe1, 0x80, 0x3b, 0x43,
@@ -26,7 +27,7 @@ var (
2627
0xda, 0x36, 0xbf, 0x22, 0xa6, 0x15, 0x1d, 0x22,
2728
0xed, 0x0d, 0xed, 0x6b, 0xc6, 0x70, 0x19, 0x4f,
2829
}
29-
// genY is the y-coordintate of the generator of Goldilocks curve.
30+
// genY is the y-coordinate of the generator of Goldilocks curve.
3031
genY = fp.Elt{
3132
0x14, 0xfa, 0x30, 0xf2, 0x5b, 0x79, 0x08, 0x98,
3233
0xad, 0xc8, 0xd7, 0x4e, 0x2c, 0x13, 0xbd, 0xfd,

ecc/goldilocks/decaf.go

+33-35
Original file line numberDiff line numberDiff line change
@@ -54,53 +54,51 @@ func (e *Elt) IsEqual(a *Elt) bool {
5454
}
5555

5656
// UnmarshalBinary if succeeds returns a Decaf element by decoding the first
57-
// DecafEncodingSize bytes of b.
58-
func (e *Elt) UnmarshalBinary(b []byte) error {
59-
if len(b) < DecafEncodingSize {
57+
// DecafEncodingSize bytes of data.
58+
func (e *Elt) UnmarshalBinary(data []byte) error {
59+
if len(data) < DecafEncodingSize {
6060
return errInvalidDecoding
6161
}
6262

6363
s := &fp.Elt{}
64-
copy(s[:], b[:DecafEncodingSize])
65-
isNeg := fp.Parity(s)
66-
modulus := fp.P()
67-
if isNeg == 1 || !isLessThan(b[:DecafEncodingSize], modulus[:]) {
68-
return errInvalidDecoding
69-
}
64+
copy(s[:], data[:DecafEncodingSize])
65+
isPositiveS := fp.Parity(s) == 0
66+
p := fp.P()
67+
isLessThanP := isLessThan(s[:], p[:])
7068

71-
one, s2, den, num := &fp.Elt{}, &fp.Elt{}, &fp.Elt{}, &fp.Elt{}
69+
s2, den, num := &fp.Elt{}, &fp.Elt{}, &fp.Elt{}
7270
isr, altx := &fp.Elt{}, &fp.Elt{}
7371
t0, t1 := &fp.Elt{}, &fp.Elt{}
74-
fp.SetOne(one)
75-
fp.Sqr(s2, s) // s2 = s^2
76-
fp.Sub(den, one, s2) // den = 1 + a*s^2
77-
fp.Mul(t1, s2, &paramDTwist) // t1 = d*s^2
78-
fp.Add(t1, t1, t1) // t1 = 2*d*s^2
79-
fp.Add(t1, t1, t1) // t1 = 4*d*s^2
80-
fp.Sqr(t0, den) // num = (1 + a*s^2)^2
81-
fp.Sub(num, t0, t1) // num = (1 + a*s^2)^2 - 4*d*s^2
82-
fp.Mul(t0, t0, num) // t0 = num*den^2
83-
isQR := fp.InvSqrt(isr, one, t0) // v = 1/sqrt(num*den^2)
84-
if !isQR {
85-
return errInvalidDecoding
86-
}
72+
x, y := &fp.Elt{}, &fp.Elt{}
73+
one := fp.One()
74+
fp.Sqr(s2, s) // s2 = s^2
75+
fp.Sub(den, &one, s2) // den = 1 + a*s^2
76+
fp.Mul(t1, s2, &paramDTwist) // t1 = d*s^2
77+
fp.Add(t1, t1, t1) // t1 = 2*d*s^2
78+
fp.Add(t1, t1, t1) // t1 = 4*d*s^2
79+
fp.Sqr(t0, den) // num = (1 + a*s^2)^2
80+
fp.Sub(num, t0, t1) // num = (1 + a*s^2)^2 - 4*d*s^2
81+
fp.Mul(t0, t0, num) // t0 = num*den^2
82+
isQR := fp.InvSqrt(isr, &one, t0) // v = 1/sqrt(num*den^2)
8783
fp.Mul(t1, den, isr) // altx = isr*den
8884
fp.Mul(t1, t1, s) // altx = s*isr*den
8985
fp.Add(t1, t1, t1) // t1 = 2*s*isr*den
9086
fp.Mul(altx, t1, &sqrtAMinusDTwist) // altx = 2*s*isr*den*sqrt(A-D)
91-
isNeg = fp.Parity(altx) // isNeg = sgn(altx)
87+
isNegX := fp.Parity(altx) // isNeg = sgn(altx)
9288
fp.Neg(t0, isr) // t0 = -isr
93-
fp.Cmov(isr, t0, uint(isNeg)) // if altx is negative then isr = -isr
94-
fp.Sqr(&e.p.x, isr) // x = isr^2
95-
fp.Mul(&e.p.x, &e.p.x, den) // x = isr^2*den
96-
fp.Mul(&e.p.x, &e.p.x, num) // x = isr^2*den*num
97-
fp.Mul(&e.p.x, &e.p.x, s) // x = s*isr^2*den*num
98-
fp.Add(&e.p.x, &e.p.x, &e.p.x) // x = 2*s*isr^2*den*num
99-
fp.Mul(&e.p.y, isr, den) // y = isr*den
100-
fp.Add(t0, one, s2) // t0 = 1 - a*s^2
101-
fp.Mul(&e.p.y, &e.p.y, t0) // y = (1 - a*s^2)*isr*den
102-
e.p.ta, e.p.tb = e.p.x, e.p.y // T = Ta*Tb = x*y
103-
fp.SetOne(&e.p.z)
89+
fp.Cmov(isr, t0, uint(isNegX)) // if altx is negative then isr = -isr
90+
fp.Sqr(x, isr) // x = isr^2
91+
fp.Mul(x, x, den) // x = isr^2*den
92+
fp.Mul(x, x, num) // x = isr^2*den*num
93+
fp.Mul(x, x, s) // x = s*isr^2*den*num
94+
fp.Add(x, x, x) // x = 2*s*isr^2*den*num
95+
fp.Mul(y, isr, den) // y = isr*den
96+
fp.Add(t0, &one, s2) // t0 = 1 - a*s^2
97+
fp.Mul(y, y, t0) // y = (1 - a*s^2)*isr*den
98+
if !(isPositiveS && isLessThanP && isQR) {
99+
return errInvalidDecoding
100+
}
101+
e.p.x, e.p.y, e.p.ta, e.p.tb, e.p.z = *x, *y, *x, *y, one
104102
return nil
105103
}
106104

ecc/goldilocks/decaf_test.go

+19
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,25 @@ func TestDecafv1_1(t *testing.T) {
100100
}
101101
}
102102

103+
func TestDecafRandom(t *testing.T) {
104+
const testTimes = 1 << 10
105+
var e goldilocks.Elt
106+
var enc [goldilocks.DecafEncodingSize]byte
107+
108+
for i := 0; i < testTimes; i++ {
109+
for found := false; !found; {
110+
_, _ = rand.Read(enc[:])
111+
err := e.UnmarshalBinary(enc[:])
112+
found = err == nil
113+
}
114+
got, err := e.MarshalBinary()
115+
want := enc[:]
116+
if err != nil || !bytes.Equal(got, want) {
117+
test.ReportError(t, got, want, enc)
118+
}
119+
}
120+
}
121+
103122
func BenchmarkDecaf(b *testing.B) {
104123
var d goldilocks.Decaf
105124
var k, l goldilocks.Scalar

ecc/goldilocks/point.go

+26-33
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
package goldilocks
22

33
import (
4-
"errors"
54
"fmt"
65

76
fp "github.com/cloudflare/circl/math/fp448"
@@ -14,14 +13,14 @@ func (P *Point) String() string {
1413
return fmt.Sprintf("x: %v\ny: %v\nz: %v\nta: %v\ntb: %v", P.x, P.y, P.z, P.ta, P.tb)
1514
}
1615

17-
// FromAffine creates a point from affine coordinates.
18-
func FromAffine(x, y *fp.Elt) (*Point, error) {
19-
P := &Point{x: *x, y: *y, z: fp.One(), ta: *x, tb: *y}
20-
if !(Curve{}).IsOnCurve(P) {
21-
return nil, errors.New("point not on curve")
22-
}
23-
return P, nil
24-
}
16+
// // FromAffine creates a point from affine coordinates.
17+
// func FromAffine(x, y *fp.Elt) (*Point, error) {
18+
// P := &Point{x: *x, y: *y, z: fp.One(), ta: *x, tb: *y}
19+
// if !(Curve{}).IsOnCurve(P) {
20+
// return nil, errors.New("point not on curve")
21+
// }
22+
// return P, nil
23+
// }
2524

2625
// isLessThan returns true if 0 <= x < y, and assumes that slices are of the
2726
// same length and are interpreted in little-endian order.
@@ -108,38 +107,32 @@ func (P *Point) Add(Q *Point) {
108107
}
109108

110109
// UnmarshalBinary if succeeds constructs a point by decoding the first
111-
// CurveEncodingSize bytes of in.
112-
func (P *Point) UnmarshalBinary(in []byte) error {
113-
if len(in) < CurveEncodingSize {
110+
// CurveEncodingSize bytes of data.
111+
func (P *Point) UnmarshalBinary(data []byte) error {
112+
if len(data) < CurveEncodingSize {
114113
return errInvalidDecoding
115114
}
116-
signX := in[fp.Size] >> 7
117-
copy(P.y[:], in[:fp.Size])
115+
116+
x, y := &fp.Elt{}, &fp.Elt{}
117+
signX := data[fp.Size] >> 7
118+
copy(y[:], data[:fp.Size])
118119
p := fp.P()
119-
if !isLessThan(P.y[:], p[:]) {
120-
return errInvalidDecoding
121-
}
120+
isLessThanP := isLessThan(y[:], p[:])
122121

123122
u, v := &fp.Elt{}, &fp.Elt{}
124123
one := fp.One()
125-
fp.Sqr(u, &P.y) // u = y^2
126-
fp.Mul(v, u, &paramD) // v = dy^2
127-
fp.Sub(u, u, &one) // u = y^2-1
128-
fp.Sub(v, v, &one) // v = dy^2-1
129-
isQR := fp.InvSqrt(&P.x, u, v) // x = sqrt(u/v)
130-
if !isQR {
124+
fp.Sqr(u, y) // u = y^2
125+
fp.Mul(v, u, &paramD) // v = dy^2
126+
fp.Sub(u, u, &one) // u = y^2-a
127+
fp.Sub(v, v, &one) // v = dy^2-a
128+
isQR := fp.InvSqrt(x, u, v) // x = sqrt(u/v)
129+
isValidXSign := !(fp.IsZero(x) && signX == 1)
130+
fp.Neg(u, x) // u = -x
131+
fp.Cmov(x, u, uint(signX^(x[0]&1))) // if signX != x mod 2
132+
if !(isLessThanP && isQR && isValidXSign) {
131133
return errInvalidDecoding
132134
}
133-
fp.Modp(&P.x) // x = x mod p
134-
if fp.IsZero(&P.x) && signX == 1 {
135-
return errInvalidDecoding
136-
}
137-
if signX != (P.x[0] & 1) {
138-
fp.Neg(&P.x, &P.x)
139-
}
140-
P.ta = P.x
141-
P.tb = P.y
142-
P.z = fp.One()
135+
P.x, P.y, P.ta, P.tb, P.z = *x, *y, *x, *y, one
143136
return nil
144137
}
145138

ecc/goldilocks/point_test.go

-12
Original file line numberDiff line numberDiff line change
@@ -58,18 +58,6 @@ func TestPointNeg(t *testing.T) {
5858
}
5959
}
6060

61-
func TestPointAffine(t *testing.T) {
62-
const testTimes = 1 << 10
63-
for i := 0; i < testTimes; i++ {
64-
got := randomPoint()
65-
x, y := got.ToAffine()
66-
want, err := goldilocks.FromAffine(&x, &y)
67-
if !got.IsEqual(want) || err != nil {
68-
test.ReportError(t, got, want)
69-
}
70-
}
71-
}
72-
7361
func TestPointMarshal(t *testing.T) {
7462
const testTimes = 1 << 10
7563
var want error

sign/ed448/ed448.go

+8-2
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,10 @@ func NewKeyFromSeed(seed PrivateKey) *KeyPair {
9898
copy(pair.private[:], seed)
9999
P := &goldilocks.Point{}
100100
goldilocks.Curve{}.ScalarBaseMult(P, s)
101-
enc, _ := P.MarshalBinary()
101+
enc, err := P.MarshalBinary()
102+
if err != nil {
103+
panic(err)
104+
}
102105
copy(pair.public[:], enc)
103106
return pair
104107
}
@@ -194,7 +197,10 @@ func Verify(public PublicKey, message, context, signature []byte) bool {
194197
P.Neg()
195198
Q := &goldilocks.Point{}
196199
goldilocks.Curve{}.CombinedMult(Q, S, k, P)
197-
encR, _ := Q.MarshalBinary()
200+
encR, err := Q.MarshalBinary()
201+
if err != nil {
202+
return false
203+
}
198204
return bytes.Equal(R, encR)
199205
}
200206

0 commit comments

Comments
 (0)