Skip to content

Commit

Permalink
Updates internal packages of Ed448.
Browse files Browse the repository at this point in the history
  • Loading branch information
armfazh committed Jul 23, 2020
1 parent bc30f13 commit f120857
Show file tree
Hide file tree
Showing 3 changed files with 76 additions and 75 deletions.
42 changes: 28 additions & 14 deletions sign/ed448/ed448.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,9 @@ import (
"errors"
"fmt"
"io"
"strconv"

"github.com/cloudflare/circl/ecc/goldilocks"
sha3 "github.com/cloudflare/circl/internal/shake"
"github.com/cloudflare/circl/sign/ed448/internal/goldilocks"
)

const (
Expand Down Expand Up @@ -128,7 +127,12 @@ func NewKeyFromSeed(seed PrivateKey) *KeyPair {

pair := &KeyPair{}
copy(pair.private[:], seed)
_ = goldilocks.Curve{}.ScalarBaseMult(s).ToBytes(pair.public[:])
var P goldilocks.Point
P.ScalarBaseMult(s)
err := P.Encode(&pair.public)
if err != nil {
panic(err)
}
return pair
}

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

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

writeDom(&H, ctx, preHash)

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

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

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

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

P, err := goldilocks.FromBytes(public)
var encPublic [goldilocks.EncodingSize]byte
copy(encPublic[:], public)
P := &goldilocks.Point{}
err := P.Decode(&encPublic)
if err != nil {
return false
}
Expand Down Expand Up @@ -260,10 +269,15 @@ func verify(public PublicKey, message, signature, ctx []byte, preHash bool) bool
S := &goldilocks.Scalar{}
S.FromBytes(signature[paramB:])

encR := (&[paramB]byte{})[:]
P.Neg()
_ = goldilocks.Curve{}.CombinedMult(S, k, P).ToBytes(encR)
return bytes.Equal(R, encR)
var Q goldilocks.Point
Q.CombinedMult(S, k, P)
var encR [goldilocks.EncodingSize]byte
err = Q.Encode(&encR)
if err != nil {
return false
}
return bytes.Equal(R, encR[:])
}

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

// isLessThanOrder returns true if 0 <= x < order and if the last byte of x is zero.
func isLessThanOrder(x []byte) bool {
order := goldilocks.Curve{}.Order()
order := goldilocks.Order()
i := len(order) - 1
for i > 0 && x[i] == order[i] {
i--
Expand Down
103 changes: 45 additions & 58 deletions sign/ed448/internal/goldilocks/goldilocks.go
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
// Package goldilocks provides goldilocks curve operations required by Ed448.
// Package goldilocks provides arithmetic operations on the Goldilocks curve.
//
// Goldilocks Curve
//
// The goldilocks curve is defined over GF(2^448-2^224-1) by the twisted Edwards
// curve
// The goldilocks curve is defined over GF(2^448-2^224-1) as
// Goldilocks: ax^2+y^2 = 1 + dx^2y^2, where a=1 and d=-39081.
// This curve was proposed by Hamburg (1) and is also known as edwards448
// after RFC-7748 (2).
Expand Down Expand Up @@ -36,8 +35,6 @@ const EncodingSize = fp.Size + 1
// ErrInvalidDecoding alerts of an error during decoding a point.
var ErrInvalidDecoding = errors.New("invalid decoding")

func (P *Point) Neg() { fp.Neg(&P.X, &P.X); fp.Neg(&P.Ta, &P.Ta) }

// Decode if succeeds constructs a point by decoding the first
// EncodingSize bytes of data.
func (P *Point) Decode(data *[EncodingSize]byte) error {
Expand Down Expand Up @@ -66,12 +63,10 @@ func (P *Point) Decode(data *[EncodingSize]byte) error {
fp.Cmov(&P.Ta, x, b)
fp.Cmov(&P.Tb, y, b)
fp.Cmov(&P.Z, &one, b)

var err error
if !isValid {
err = ErrInvalidDecoding
return ErrInvalidDecoding
}
return err
return nil
}

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

// Order returns the number of points in the prime subgroup.
func Order() Scalar { return ted448.Order() }

// ScalarBaseMult calculates Q = kG, where G is the generator of the Goldilocks curve. This function runs in constant time.
func ScalarBaseMult(Q *Point, k *Scalar) {
// ScalarBaseMult calculates P = kG, where G is the generator of the Goldilocks
// curve. This function runs in constant time.
func (P *Point) ScalarBaseMult(k *Scalar) {
k4 := &Scalar{}
divBy4(k4, k)
R := &ted448.Point{}
ted448.ScalarBaseMult(R, k4)
push(Q, R)
var Q ted448.Point
ted448.ScalarBaseMult(&Q, k4)
push(P, &Q)
}

// CombinedMult calculates Q = mG+nP, where G is the generator of the Goldilocks curve. This function does NOT run in constant time.
func CombinedMult(Q *Point, m, n *Scalar, P *Point) {
// CombinedMult calculates P = mG+nQ, where G is the generator of the Goldilocks
// curve. This function does NOT run in constant time as is only used for
// signature verification.
func (P *Point) CombinedMult(m, n *Scalar, Q *Point) {
m4, n4 := &Scalar{}, &Scalar{}
divBy4(m4, m)
divBy4(n4, n)
phiP := &ted448.Point{}
R := &ted448.Point{}
pull(phiP, P)
ted448.CombinedMult(R, m4, n4, phiP)
push(Q, R)
var R, phiQ ted448.Point
pull(&phiQ, Q)
ted448.CombinedMult(&R, m4, n4, &phiQ)
push(P, &R)
}

// pull sends a point on the Goldilocks curve to a point on the twist curve.
func pull(Q *ted448.Point, P *Point) {
Px, Py, Pz := &P.X, &P.Y, &P.Z
a, b, c, d, e, f, g, h := &Q.X, &Q.Y, &Q.Z, &fp.Elt{}, &Q.Ta, &Q.X, &Q.Y, &Q.Tb
fp.Add(e, Px, Py) // x+y
fp.Sqr(a, Px) // A = x^2
fp.Sqr(b, Py) // B = y^2
fp.Sqr(c, Pz) // z^2
fp.Add(c, c, c) // C = 2*z^2
*d = *a // D = A
fp.Sqr(e, e) // (x+y)^2
fp.Sub(e, e, a) // (x+y)^2-A
fp.Sub(e, e, b) // E = (x+y)^2-A-B
fp.Add(h, b, d) // H = B+D
fp.Sub(g, b, d) // G = B-D
fp.Sub(f, c, h) // F = C-H
fp.Mul(&Q.Z, f, g) // Z = F * G
fp.Mul(&Q.X, e, f) // X = E * F
fp.Mul(&Q.Y, g, h) // Y = G * H, // T = E * H
}
func (P *Point) Neg() { fp.Neg(&P.X, &P.X); fp.Neg(&P.Ta, &P.Ta) }

// Order returns a scalar with the order of the group.
func Order() Scalar { return ted448.Order() }

// divBy4 calculates z = x/4 mod order.
func divBy4(z, x *Scalar) { z.Mul(x, &invFour) }

// pull calculates Q = Iso4(P), where P is a Goldilocks point and Q is a ted448 point.
func pull(Q *ted448.Point, P *Point) { isogeny4(Q, (*ted448.Point)(P), true) }

// push sends a point on the twist curve to a point on the Goldilocks curve.
func push(Q *Point, P *ted448.Point) {
// push calculates Q = Iso4^-1(P), where P is a ted448 point and Q is a Goldilocks point.
func push(Q *Point, P *ted448.Point) { isogeny4((*ted448.Point)(Q), P, false) }

// isogeny4 is a birational map between ted448 and Goldilocks curves.
func isogeny4(Q, P *ted448.Point, isPull bool) {
Px, Py, Pz := &P.X, &P.Y, &P.Z
a, b, c, d, e, f, g, h := &Q.X, &Q.Y, &Q.Z, &fp.Elt{}, &Q.Ta, &Q.X, &Q.Y, &Q.Tb
fp.Add(e, Px, Py) // x+y
fp.Sqr(a, Px) // A = x^2
fp.Sqr(b, Py) // B = y^2
fp.Sqr(c, Pz) // z^2
fp.Add(c, c, c) // C = 2*z^2
fp.Neg(d, a) // D = -A
fp.Add(e, Px, Py) // x+y
fp.Sqr(a, Px) // A = x^2
fp.Sqr(b, Py) // B = y^2
fp.Sqr(c, Pz) // z^2
fp.Add(c, c, c) // C = 2*z^2
if isPull {
*d = *a // D = A
} else {
fp.Neg(d, a) // D = -A
}
fp.Sqr(e, e) // (x+y)^2
fp.Sub(e, e, a) // (x+y)^2-A
fp.Sub(e, e, b) // E = (x+y)^2-A-B
Expand All @@ -153,9 +143,6 @@ func push(Q *Point, P *ted448.Point) {
fp.Mul(&Q.Y, g, h) // Y = G * H, // T = E * H
}

// divBy4 calculates z = x/4 mod order.
func divBy4(z, x *Scalar) { z.Mul(x, &invFour) }

// isLessThan returns true if 0 <= x < y, and assumes that slices are of the
// same length and are interpreted in little-endian order.
func isLessThan(x, y []byte) bool {
Expand All @@ -177,7 +164,7 @@ var (
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0f,
}
// paramD is -39081 in Fp. This is the D parameter of the goldilocks curve.
// paramD is the D parameter of the Goldilocks curve, D=-39081 in Fp.
paramD = fp.Elt{
0x56, 0x67, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
Expand Down
6 changes: 3 additions & 3 deletions sign/ed448/internal/goldilocks/goldilocks_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,8 @@ func TestScalarMult(t *testing.T) {
for i := 0; i < testTimes; i++ {
_, _ = rand.Read(k[:])

ScalarBaseMult(&P, k)
CombinedMult(&Q, k, zero, &I) // k*G + 0*I
P.ScalarBaseMult(k)
Q.CombinedMult(k, zero, &I) // k*G + 0*I
err0 := P.Encode(&got)
err1 := Q.Encode(&want)
if err0 != nil || err1 != nil || got != want {
Expand Down Expand Up @@ -108,7 +108,7 @@ func BenchmarkEncoding(b *testing.B) {
var k Scalar
_, _ = rand.Read(k[:])
var P Point
ScalarBaseMult(&P, &k)
P.ScalarBaseMult(&k)
b.Run("Marshal", func(b *testing.B) {
for i := 0; i < b.N; i++ {
_ = P.Encode(&data)
Expand Down

0 comments on commit f120857

Please sign in to comment.