Skip to content

Commit f120857

Browse files
committed
Updates internal packages of Ed448.
1 parent bc30f13 commit f120857

File tree

3 files changed

+76
-75
lines changed

3 files changed

+76
-75
lines changed

sign/ed448/ed448.go

+28-14
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,9 @@ import (
1313
"errors"
1414
"fmt"
1515
"io"
16-
"strconv"
1716

18-
"github.com/cloudflare/circl/ecc/goldilocks"
1917
sha3 "github.com/cloudflare/circl/internal/shake"
18+
"github.com/cloudflare/circl/sign/ed448/internal/goldilocks"
2019
)
2120

2221
const (
@@ -128,7 +127,12 @@ func NewKeyFromSeed(seed PrivateKey) *KeyPair {
128127

129128
pair := &KeyPair{}
130129
copy(pair.private[:], seed)
131-
_ = goldilocks.Curve{}.ScalarBaseMult(s).ToBytes(pair.public[:])
130+
var P goldilocks.Point
131+
P.ScalarBaseMult(s)
132+
err := P.Encode(&pair.public)
133+
if err != nil {
134+
panic(err)
135+
}
132136
return pair
133137
}
134138

@@ -167,16 +171,18 @@ func sign(kp *KeyPair, message, ctx []byte, preHash bool) ([]byte, error) {
167171
// 3. Compute the point [r]B.
168172
r := &goldilocks.Scalar{}
169173
r.FromBytes(rPM[:])
170-
R := (&[paramB]byte{})[:]
171-
err := goldilocks.Curve{}.ScalarBaseMult(r).ToBytes(R)
174+
var R goldilocks.Point
175+
var encR [goldilocks.EncodingSize]byte
176+
R.ScalarBaseMult(r)
177+
err := R.Encode(&encR)
172178

173179
// 4. Compute SHAKE256(dom4(F, C) || R || A || PH(M), 114)
174180
var hRAM [hashSize]byte
175181
H.Reset()
176182

177183
writeDom(&H, ctx, preHash)
178184

179-
_, _ = H.Write(R)
185+
_, _ = H.Write(encR[:])
180186
_, _ = H.Write(kp.public[:])
181187
_, _ = H.Write(d)
182188
_, _ = H.Read(hRAM[:])
@@ -190,7 +196,7 @@ func sign(kp *KeyPair, message, ctx []byte, preHash bool) ([]byte, error) {
190196

191197
// 6. The signature is the concatenation of R and S.
192198
var signature [SignatureSize]byte
193-
copy(signature[:paramB], R[:])
199+
copy(signature[:paramB], encR[:])
194200
copy(signature[paramB:], S[:])
195201
return signature[:], err
196202
}
@@ -200,7 +206,7 @@ func sign(kp *KeyPair, message, ctx []byte, preHash bool) ([]byte, error) {
200206
// also known as the pure version of EdDSA.
201207
func (kp *KeyPair) SignPure(message []byte, ctx string) ([]byte, error) {
202208
if len(ctx) > ContextMaxSize {
203-
return nil, fmt.Errorf("ed448: bad context length: " + strconv.Itoa(len(ctx)))
209+
return nil, fmt.Errorf("ed448: bad context length: %v", len(ctx))
204210
}
205211

206212
return sign(kp, message, []byte(ctx), false)
@@ -213,7 +219,7 @@ func (kp *KeyPair) SignPure(message []byte, ctx string) ([]byte, error) {
213219
// 255. It can be empty.
214220
func (kp *KeyPair) SignPh(message []byte, ctx string) ([]byte, error) {
215221
if len(ctx) > ContextMaxSize {
216-
return nil, fmt.Errorf("ed448: bad context length: " + strconv.Itoa(len(ctx)))
222+
return nil, fmt.Errorf("ed448: bad context length: %v", len(ctx))
217223
}
218224

219225
return sign(kp, message, []byte(ctx), true)
@@ -227,7 +233,10 @@ func verify(public PublicKey, message, signature, ctx []byte, preHash bool) bool
227233
return false
228234
}
229235

230-
P, err := goldilocks.FromBytes(public)
236+
var encPublic [goldilocks.EncodingSize]byte
237+
copy(encPublic[:], public)
238+
P := &goldilocks.Point{}
239+
err := P.Decode(&encPublic)
231240
if err != nil {
232241
return false
233242
}
@@ -260,10 +269,15 @@ func verify(public PublicKey, message, signature, ctx []byte, preHash bool) bool
260269
S := &goldilocks.Scalar{}
261270
S.FromBytes(signature[paramB:])
262271

263-
encR := (&[paramB]byte{})[:]
264272
P.Neg()
265-
_ = goldilocks.Curve{}.CombinedMult(S, k, P).ToBytes(encR)
266-
return bytes.Equal(R, encR)
273+
var Q goldilocks.Point
274+
Q.CombinedMult(S, k, P)
275+
var encR [goldilocks.EncodingSize]byte
276+
err = Q.Encode(&encR)
277+
if err != nil {
278+
return false
279+
}
280+
return bytes.Equal(R, encR[:])
267281
}
268282

269283
// Verify returns true if the signature is valid. Failure cases are invalid
@@ -316,7 +330,7 @@ func deriveSecretScalar(s *goldilocks.Scalar, h []byte) {
316330

317331
// isLessThanOrder returns true if 0 <= x < order and if the last byte of x is zero.
318332
func isLessThanOrder(x []byte) bool {
319-
order := goldilocks.Curve{}.Order()
333+
order := goldilocks.Order()
320334
i := len(order) - 1
321335
for i > 0 && x[i] == order[i] {
322336
i--

sign/ed448/internal/goldilocks/goldilocks.go

+45-58
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
1-
// Package goldilocks provides goldilocks curve operations required by Ed448.
1+
// Package goldilocks provides arithmetic operations on the Goldilocks curve.
22
//
33
// Goldilocks Curve
44
//
5-
// The goldilocks curve is defined over GF(2^448-2^224-1) by the twisted Edwards
6-
// curve
5+
// The goldilocks curve is defined over GF(2^448-2^224-1) as
76
// Goldilocks: ax^2+y^2 = 1 + dx^2y^2, where a=1 and d=-39081.
87
// This curve was proposed by Hamburg (1) and is also known as edwards448
98
// after RFC-7748 (2).
@@ -36,8 +35,6 @@ const EncodingSize = fp.Size + 1
3635
// ErrInvalidDecoding alerts of an error during decoding a point.
3736
var ErrInvalidDecoding = errors.New("invalid decoding")
3837

39-
func (P *Point) Neg() { fp.Neg(&P.X, &P.X); fp.Neg(&P.Ta, &P.Ta) }
40-
4138
// Decode if succeeds constructs a point by decoding the first
4239
// EncodingSize bytes of data.
4340
func (P *Point) Decode(data *[EncodingSize]byte) error {
@@ -66,12 +63,10 @@ func (P *Point) Decode(data *[EncodingSize]byte) error {
6663
fp.Cmov(&P.Ta, x, b)
6764
fp.Cmov(&P.Tb, y, b)
6865
fp.Cmov(&P.Z, &one, b)
69-
70-
var err error
7166
if !isValid {
72-
err = ErrInvalidDecoding
67+
return ErrInvalidDecoding
7368
}
74-
return err
69+
return nil
7570
}
7671

7772
// Encode sets data with the unique encoding of the point P.
@@ -83,65 +78,60 @@ func (P *Point) Encode(data *[EncodingSize]byte) error {
8378
fp.Modp(x)
8479
fp.Modp(y)
8580
data[EncodingSize-1] = (x[0] & 1) << 7
86-
err := fp.ToBytes(data[:fp.Size], y)
87-
return err
81+
return fp.ToBytes(data[:fp.Size], y)
8882
}
8983

90-
// Order returns the number of points in the prime subgroup.
91-
func Order() Scalar { return ted448.Order() }
92-
93-
// ScalarBaseMult calculates Q = kG, where G is the generator of the Goldilocks curve. This function runs in constant time.
94-
func ScalarBaseMult(Q *Point, k *Scalar) {
84+
// ScalarBaseMult calculates P = kG, where G is the generator of the Goldilocks
85+
// curve. This function runs in constant time.
86+
func (P *Point) ScalarBaseMult(k *Scalar) {
9587
k4 := &Scalar{}
9688
divBy4(k4, k)
97-
R := &ted448.Point{}
98-
ted448.ScalarBaseMult(R, k4)
99-
push(Q, R)
89+
var Q ted448.Point
90+
ted448.ScalarBaseMult(&Q, k4)
91+
push(P, &Q)
10092
}
10193

102-
// CombinedMult calculates Q = mG+nP, where G is the generator of the Goldilocks curve. This function does NOT run in constant time.
103-
func CombinedMult(Q *Point, m, n *Scalar, P *Point) {
94+
// CombinedMult calculates P = mG+nQ, where G is the generator of the Goldilocks
95+
// curve. This function does NOT run in constant time as is only used for
96+
// signature verification.
97+
func (P *Point) CombinedMult(m, n *Scalar, Q *Point) {
10498
m4, n4 := &Scalar{}, &Scalar{}
10599
divBy4(m4, m)
106100
divBy4(n4, n)
107-
phiP := &ted448.Point{}
108-
R := &ted448.Point{}
109-
pull(phiP, P)
110-
ted448.CombinedMult(R, m4, n4, phiP)
111-
push(Q, R)
101+
var R, phiQ ted448.Point
102+
pull(&phiQ, Q)
103+
ted448.CombinedMult(&R, m4, n4, &phiQ)
104+
push(P, &R)
112105
}
113106

114-
// pull sends a point on the Goldilocks curve to a point on the twist curve.
115-
func pull(Q *ted448.Point, P *Point) {
116-
Px, Py, Pz := &P.X, &P.Y, &P.Z
117-
a, b, c, d, e, f, g, h := &Q.X, &Q.Y, &Q.Z, &fp.Elt{}, &Q.Ta, &Q.X, &Q.Y, &Q.Tb
118-
fp.Add(e, Px, Py) // x+y
119-
fp.Sqr(a, Px) // A = x^2
120-
fp.Sqr(b, Py) // B = y^2
121-
fp.Sqr(c, Pz) // z^2
122-
fp.Add(c, c, c) // C = 2*z^2
123-
*d = *a // D = A
124-
fp.Sqr(e, e) // (x+y)^2
125-
fp.Sub(e, e, a) // (x+y)^2-A
126-
fp.Sub(e, e, b) // E = (x+y)^2-A-B
127-
fp.Add(h, b, d) // H = B+D
128-
fp.Sub(g, b, d) // G = B-D
129-
fp.Sub(f, c, h) // F = C-H
130-
fp.Mul(&Q.Z, f, g) // Z = F * G
131-
fp.Mul(&Q.X, e, f) // X = E * F
132-
fp.Mul(&Q.Y, g, h) // Y = G * H, // T = E * H
133-
}
107+
func (P *Point) Neg() { fp.Neg(&P.X, &P.X); fp.Neg(&P.Ta, &P.Ta) }
108+
109+
// Order returns a scalar with the order of the group.
110+
func Order() Scalar { return ted448.Order() }
111+
112+
// divBy4 calculates z = x/4 mod order.
113+
func divBy4(z, x *Scalar) { z.Mul(x, &invFour) }
114+
115+
// pull calculates Q = Iso4(P), where P is a Goldilocks point and Q is a ted448 point.
116+
func pull(Q *ted448.Point, P *Point) { isogeny4(Q, (*ted448.Point)(P), true) }
134117

135-
// push sends a point on the twist curve to a point on the Goldilocks curve.
136-
func push(Q *Point, P *ted448.Point) {
118+
// push calculates Q = Iso4^-1(P), where P is a ted448 point and Q is a Goldilocks point.
119+
func push(Q *Point, P *ted448.Point) { isogeny4((*ted448.Point)(Q), P, false) }
120+
121+
// isogeny4 is a birational map between ted448 and Goldilocks curves.
122+
func isogeny4(Q, P *ted448.Point, isPull bool) {
137123
Px, Py, Pz := &P.X, &P.Y, &P.Z
138124
a, b, c, d, e, f, g, h := &Q.X, &Q.Y, &Q.Z, &fp.Elt{}, &Q.Ta, &Q.X, &Q.Y, &Q.Tb
139-
fp.Add(e, Px, Py) // x+y
140-
fp.Sqr(a, Px) // A = x^2
141-
fp.Sqr(b, Py) // B = y^2
142-
fp.Sqr(c, Pz) // z^2
143-
fp.Add(c, c, c) // C = 2*z^2
144-
fp.Neg(d, a) // D = -A
125+
fp.Add(e, Px, Py) // x+y
126+
fp.Sqr(a, Px) // A = x^2
127+
fp.Sqr(b, Py) // B = y^2
128+
fp.Sqr(c, Pz) // z^2
129+
fp.Add(c, c, c) // C = 2*z^2
130+
if isPull {
131+
*d = *a // D = A
132+
} else {
133+
fp.Neg(d, a) // D = -A
134+
}
145135
fp.Sqr(e, e) // (x+y)^2
146136
fp.Sub(e, e, a) // (x+y)^2-A
147137
fp.Sub(e, e, b) // E = (x+y)^2-A-B
@@ -153,9 +143,6 @@ func push(Q *Point, P *ted448.Point) {
153143
fp.Mul(&Q.Y, g, h) // Y = G * H, // T = E * H
154144
}
155145

156-
// divBy4 calculates z = x/4 mod order.
157-
func divBy4(z, x *Scalar) { z.Mul(x, &invFour) }
158-
159146
// isLessThan returns true if 0 <= x < y, and assumes that slices are of the
160147
// same length and are interpreted in little-endian order.
161148
func isLessThan(x, y []byte) bool {
@@ -177,7 +164,7 @@ var (
177164
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
178165
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0f,
179166
}
180-
// paramD is -39081 in Fp. This is the D parameter of the goldilocks curve.
167+
// paramD is the D parameter of the Goldilocks curve, D=-39081 in Fp.
181168
paramD = fp.Elt{
182169
0x56, 0x67, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
183170
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,

sign/ed448/internal/goldilocks/goldilocks_test.go

+3-3
Original file line numberDiff line numberDiff line change
@@ -47,8 +47,8 @@ func TestScalarMult(t *testing.T) {
4747
for i := 0; i < testTimes; i++ {
4848
_, _ = rand.Read(k[:])
4949

50-
ScalarBaseMult(&P, k)
51-
CombinedMult(&Q, k, zero, &I) // k*G + 0*I
50+
P.ScalarBaseMult(k)
51+
Q.CombinedMult(k, zero, &I) // k*G + 0*I
5252
err0 := P.Encode(&got)
5353
err1 := Q.Encode(&want)
5454
if err0 != nil || err1 != nil || got != want {
@@ -108,7 +108,7 @@ func BenchmarkEncoding(b *testing.B) {
108108
var k Scalar
109109
_, _ = rand.Read(k[:])
110110
var P Point
111-
ScalarBaseMult(&P, &k)
111+
P.ScalarBaseMult(&k)
112112
b.Run("Marshal", func(b *testing.B) {
113113
for i := 0; i < b.N; i++ {
114114
_ = P.Encode(&data)

0 commit comments

Comments
 (0)