Skip to content

Commit

Permalink
Decaf decoding working. More tests needed.
Browse files Browse the repository at this point in the history
  • Loading branch information
armfazh committed Jul 24, 2020
1 parent daa36c1 commit 6173c83
Show file tree
Hide file tree
Showing 6 changed files with 147 additions and 81 deletions.
9 changes: 8 additions & 1 deletion ecc/goldilocks/constants.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
package goldilocks

import fp "github.com/cloudflare/circl/math/fp448"
import (
"errors"

fp "github.com/cloudflare/circl/math/fp448"
)

var (
// genX is the x-coordinate of the generator of Goldilocks curve.
Expand Down Expand Up @@ -35,6 +39,8 @@ var (
}
// aMinusD is paramA-paramD used for Decaf.
aMinusD = fp.Elt{0xaa, 0x98}
// aMinusD is paramA-paramD used for Decaf.
aMinusDTwist = fp.Elt{0xa9, 0x98}
// order is 2^446-0x8335dc163bb124b65129c96fde933d8d723a70aadc873d6d54a7bb0d,
// which is the number of points in the prime subgroup.
order = Scalar{
Expand Down Expand Up @@ -70,4 +76,5 @@ var (
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
}
errInvalidDecoding = errors.New("invalid decoding")
)
9 changes: 0 additions & 9 deletions ecc/goldilocks/curve_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -110,13 +110,4 @@ func BenchmarkCurve(b *testing.B) {
P = e.CombinedMult(&k, &l, P)
}
})

var d goldilocks.Decaf
a := d.Generator()

b.Run("Marshal", func(b *testing.B) {
for i := 0; i < b.N; i++ {
d.Marshal(a)
}
})
}
154 changes: 96 additions & 58 deletions ecc/goldilocks/decaf.go
Original file line number Diff line number Diff line change
@@ -1,74 +1,83 @@
package goldilocks

import (
fp "github.com/cloudflare/circl/math/fp448"
)
import fp "github.com/cloudflare/circl/math/fp448"

// Decaf provides a prime-order group quotient from goldilocks curve.
type Decaf struct{ c Curve }
// Decaf provides a prime-order group.
// Internally, the implementation uses the twist of goldilocks curve.
type Decaf struct{ c twistCurve }

// Elt is an element of decaf group.
type Elt struct{ p *Point }
// Elt is an element of the decaf group.
type Elt struct{ p twistPoint }

func (e Elt) String() string { return e.p.String() }

// IsValid is
func (d Decaf) IsValid(a *Elt) bool { return d.c.IsOnCurve(a.p) }
func (d Decaf) IsValid(a *Elt) bool { return false /*d.c.IsOnCurve(a.p) */ }

// IsIdentity is
func (d Decaf) IsIdentity(a *Elt) bool { return fp.IsZero(&a.p.x) }

// Identity is
func (d Decaf) Identity() *Elt { return &Elt{d.c.Identity()} }
func (d Decaf) Identity() *Elt { return &Elt{*d.c.Identity()} }

// Generator is
func (d Decaf) Generator() *Elt {
g := d.c.Generator()
// g.Double()
return &Elt{g}
}
func (d Decaf) Generator() *Elt { return &Elt{*d.c.pull(Curve{}.Generator())} }

// Order is
func (d Decaf) Order() Scalar { return d.c.Order() }
func (d Decaf) Order() Scalar { return order }

// Add is
func (d Decaf) Add(a, b *Elt) *Elt { return &Elt{d.c.Add(a.p, b.p)} }
func (d Decaf) Add(a, b *Elt) *Elt { R := a.p; R.Add(&b.p); return &Elt{R} }

// Neg is
func (d Decaf) Neg(a *Elt) *Elt { x := *a.p; x.Neg(); e := &Elt{&x}; return e }
func (d Decaf) Neg(a *Elt) *Elt { R := a.p; R.cneg(1); return &Elt{R} }

// Mul is
func (d Decaf) Mul(a *Elt, n *Scalar) *Elt { return &Elt{d.c.ScalarMult(n, a.p)} }
func (d Decaf) Mul(a *Elt, n *Scalar) *Elt { return &Elt{*d.c.ScalarMult(n, &a.p)} }

// MulGen is
func (d Decaf) MulGen(n *Scalar) *Elt { return &Elt{d.c.ScalarBaseMult(n)} }
func (d Decaf) MulGen(n *Scalar) *Elt { return &Elt{*d.c.ScalarBaseMult(n)} }

// AreEqual is
func (d Decaf) AreEqual(a, b *Elt) bool {
l, r := &fp.Elt{}, &fp.Elt{}
fp.Mul(l, &a.p.x, &b.p.y)
fp.Mul(r, &b.p.x, &a.p.y)
fp.Sub(l, l, r)
return fp.IsZero(l)
}

// Marshal is
func (d Decaf) Marshal(a *Elt) []byte {
func (e *Elt) Marshal() []byte {
r, u := &fp.Elt{}, &fp.Elt{}
one, s := &fp.Elt{}, &fp.Elt{}
x, y, ta, tb, z := a.p.x, a.p.y, a.p.ta, a.p.tb, a.p.z
x, y, ta, tb, z := e.p.x, e.p.y, e.p.ta, e.p.tb, e.p.z
t0, t1 := z, y
fp.SetOne(one)
fp.AddSub(&t0, &t1) // (t0,t1) = (z+y,z-y)
fp.Mul(&t0, &t0, &t1) // t0 = (z+y)*(z-y)
fp.Mul(&t0, &t0, &aMinusD) // t0 = (a-d)*(z+y)*(z-y)
fp.InvSqrt(r, one, &t0) // r = 1/sqrt( (a-d)*(z+y)*(z-y) )
fp.Mul(u, r, &aMinusD) // u = (a-d)*r
fp.Mul(&t0, u, &z) // t0 = u*Z
fp.Add(&t0, &t0, &t0) // t0 = 2*u*Z
fp.Neg(&t0, &t0) // t0 = -2*u*Z
isNeg := fp.Parity(&t0) // isNeg = sgn(t0)
fp.Neg(&t1, r) // t1 = -r
fp.Cmov(r, &t1, uint(isNeg)) // if -2*u*Z is negative then r = -r
fp.Mul(&t1, &ta, &tb) // t1 = Ta*Tb = T
fp.Mul(&t1, &t1, &y) // t1 = Y*T
fp.Mul(&t1, &t1, &paramD) // t1 = d*Y*T
fp.Mul(&t0, &z, &x) // t0 = a*Z*X
fp.Sub(&t0, &t0, &t1) // t0 = a*Z*X - d*Y*T
fp.Mul(&t0, &t0, r) // t0 = r*(a*Z*X - d*Y*T)
fp.Add(&t0, &t0, &y) // t0 = r*(a*Z*X - d*Y*T) + Y
fp.Mul(s, &t0, u) // s = (u/a)*(r*(a*Z*X - d*Y*T) + Y)
isNeg = fp.Parity(s) // isNeg = sgn(s)
fp.Neg(&t1, s) // t1 = -s
fp.Cmov(s, &t1, uint(isNeg)) // if s is negative then s = -s
fp.AddSub(&t0, &t1) // (t0,t1) = (z+y,z-y)
fp.Mul(&t0, &t0, &t1) // t0 = (z+y)*(z-y)
fp.Mul(&t0, &t0, &aMinusDTwist) // t0 = (a-d)*(z+y)*(z-y)
fp.InvSqrt(r, one, &t0) // r = 1/sqrt( (a-d)*(z+y)*(z-y) )
fp.Mul(u, r, &aMinusDTwist) // u = (a-d)*r
fp.Mul(&t0, u, &z) // t0 = u*Z
fp.Add(&t0, &t0, &t0) // t0 = 2*u*Z
fp.Neg(&t0, &t0) // t0 = -2*u*Z
isNeg := fp.Parity(&t0) // isNeg = sgn(t0)
fp.Neg(&t1, r) // t1 = -r
fp.Cmov(r, &t1, uint(isNeg)) // if -2*u*Z is negative then r = -r
fp.Mul(&t1, &ta, &tb) // t1 = Ta*Tb = T
fp.Mul(&t1, &t1, &y) // t1 = Y*T
fp.Mul(&t1, &t1, &paramDTwist) // t1 = d*Y*T
fp.Mul(&t0, &z, &x) // t0 = Z*X
fp.Neg(&t0, &t0) // t0 = a*Z*X
fp.Sub(&t0, &t0, &t1) // t0 = a*Z*X - d*Y*T
fp.Mul(&t0, &t0, r) // t0 = r*(a*Z*X - d*Y*T)
fp.Add(&t0, &t0, &y) // t0 = r*(a*Z*X - d*Y*T) + Y
fp.Mul(s, &t0, u) // s = (u)*(r*(a*Z*X - d*Y*T) + Y)
fp.Neg(s, s) // s = (u/a)*(r*(a*Z*X - d*Y*T) + Y)
isNeg = fp.Parity(s) // isNeg = sgn(s)
fp.Neg(&t1, s) // t1 = -s
fp.Cmov(s, &t1, uint(isNeg)) // if s is negative then s = -s

var encS [fp.Size]byte
_ = fp.ToBytes(encS[:], s)
Expand All @@ -77,19 +86,48 @@ func (d Decaf) Marshal(a *Elt) []byte {

// Unmarshal is
func (d Decaf) Unmarshal(b []byte) (*Elt, error) {

return nil, nil

}

// IsIdentity is
func (d Decaf) IsIdentity(a *Elt) bool { return fp.IsZero(&a.p.x) }

// AreEqual is
func (d Decaf) AreEqual(a, b *Elt) bool {
l, r := &fp.Elt{}, &fp.Elt{}
fp.Mul(l, &a.p.x, &b.p.y)
fp.Mul(r, &b.p.x, &a.p.y)
fp.Sub(l, l, r)
return fp.IsZero(l)
if len(b) < fp.Size {
return nil, errInvalidDecoding
}

s := &fp.Elt{}
copy(s[:], b[:fp.Size])
isNeg := fp.Parity(s)
p := fp.P()
if isNeg == 1 || !isLessThan(b[:fp.Size], p[:]) {
return nil, errInvalidDecoding
}

one, u, v, w := &fp.Elt{}, &fp.Elt{}, &fp.Elt{}, &fp.Elt{}
t0, t1 := &fp.Elt{}, &fp.Elt{}
e := &Elt{}
fp.SetOne(one)
fp.Add(&e.p.x, s, s) // X = 2*s
fp.Sqr(t0, s) // t0 = s^2
fp.Sub(&e.p.z, one, t0) // Z = 1 + a*s^2
fp.Mul(t1, t0, &paramDTwist) // t1 = d*s^2
fp.Add(t1, t1, t1) // t1 = 2*d*s^2
fp.Add(t1, t1, t1) // t1 = 4*d*s^2
fp.Sqr(u, &e.p.z) // u = Z^2
fp.Sub(u, u, t1) // u = Z^2 - 4*d*s^2
fp.Mul(t0, t0, u) // t0 = u*s^2
isQR := fp.InvSqrt(v, one, t0) // v = 1/sqrt(u*s^2)
var isZero byte
if !isQR {
if !fp.IsZero(t0) {
return nil, errInvalidDecoding
}
isZero = 1
}
fp.Mul(t0, u, v) // t0 = u*v
isNeg = fp.Parity(t0) // isNeg = sgn(u*v)
fp.Neg(t1, v) // t1 = -v
fp.Cmov(v, t1, uint(isNeg)) // if u*v is negative then v = -v
fp.Sub(w, &fp.Elt{2}, &e.p.z) // w = 2-Z
fp.Mul(w, w, s) // w = s*(2-Z)
fp.Mul(w, w, v) // w = v*s*(2-Z)
fp.Add(w, w, &fp.Elt{isZero}) // if s=0 then w = w+1
fp.Mul(&e.p.y, &e.p.z, w) // Y = w*Z
e.p.ta, e.p.tb = e.p.x, *w // T = Ta*Tb = w*X
return e, nil
}
29 changes: 20 additions & 9 deletions ecc/goldilocks/decaf_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,30 @@ import (
"encoding/hex"
"fmt"
"testing"

"github.com/cloudflare/circl/internal/test"
)

func TestDecafDevel(t *testing.T) {

// var c Curve
var d Decaf
GE := d.Generator()
fmt.Printf("GE: %v\n%v\n\n", GE, hex.EncodeToString(d.Marshal(GE)))
G := d.Generator()
fmt.Printf("G: %v\n%v\n\n", G, hex.EncodeToString(G.Marshal()))

Q := d.Identity()
for i := 0; i < 100; i++ {
fmt.Printf("%v\n", hex.EncodeToString(d.Marshal(Q)))
Q = d.Add(Q, GE)
for i := 0; i < 18; i++ {
enc := Q.Marshal()
decP, err := d.Unmarshal(enc)
if err != nil {
t.Fatalf("dd")
}
got := d.AreEqual(Q, decP)
want := true
if got != want {
fmt.Printf("%v\n", Q)
fmt.Printf("%v\n", decP)
test.ReportError(t, got, want, i)
}
Q = d.Add(Q, G)
}
// fmt.Printf("2GE: %v\n%v\n\n", GE, enc(GE))

Expand All @@ -38,10 +49,10 @@ func TestDecafDevel(t *testing.T) {
func BenchmarkDecaf(b *testing.B) {
var d Decaf
G := d.Generator()
enc := d.Marshal(G)
enc := G.Marshal()
b.Run("Marshal", func(b *testing.B) {
for i := 0; i < b.N; i++ {
d.Marshal(G)
G.Marshal()
}
})
b.Run("Unmarshal", func(b *testing.B) {
Expand Down
7 changes: 3 additions & 4 deletions ecc/goldilocks/point.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,13 +44,12 @@ func FromBytes(in []byte) (*Point, error) {
if len(in) < fp.Size+1 {
return nil, errors.New("wrong input length")
}
var err = errors.New("invalid decoding")
P := &Point{}
signX := in[fp.Size] >> 7
copy(P.y[:], in[:fp.Size])
p := fp.P()
if !isLessThan(P.y[:], p[:]) {
return nil, err
return nil, errInvalidDecoding
}

u, v := &fp.Elt{}, &fp.Elt{}
Expand All @@ -61,11 +60,11 @@ func FromBytes(in []byte) (*Point, error) {
fp.Sub(v, v, &one) // v = dy^2-1
isQR := fp.InvSqrt(&P.x, u, v) // x = sqrt(u/v)
if !isQR {
return nil, err
return nil, errInvalidDecoding
}
fp.Modp(&P.x) // x = x mod p
if fp.IsZero(&P.x) && signX == 1 {
return nil, err
return nil, errInvalidDecoding
}
if signX != (P.x[0] & 1) {
fp.Neg(&P.x, &P.x)
Expand Down
20 changes: 20 additions & 0 deletions ecc/goldilocks/twistPoint.go
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,13 @@ func (P *twistPoint) mixAdd(Q *preTwistPointProy) {
P.coreAddition(&Q.preTwistPointAffine)
}

// Add calculates P = P+Q.
func (P *twistPoint) Add(Q *twistPoint) {
preB := &preTwistPointProy{}
preB.FromTwistPoint(Q)
P.mixAdd(preB)
}

// oddMultiples calculates T[i] = (2*i-1)P for 0 < i < len(T).
func (P *twistPoint) oddMultiples(T []preTwistPointProy) {
if n := len(T); n > 0 {
Expand Down Expand Up @@ -133,3 +140,16 @@ func (P *preTwistPointProy) FromTwistPoint(Q *twistPoint) {
fp.Add(&P.dt2, &P.dt2, &P.dt2) // dt2 = 2*D*T
fp.Add(&P.z2, &Q.z, &Q.z) // z2 = 2*Z
}

// ToAffine returns the x,y affine coordinates of P. TODO: remove this method
func (P *twistPoint) ToAffine() (x, y fp.Elt) {
fp.Inv(&P.z, &P.z) // 1/z
fp.Mul(&P.x, &P.x, &P.z) // x/z
fp.Mul(&P.y, &P.y, &P.z) // y/z
fp.Modp(&P.x)
fp.Modp(&P.y)
fp.SetOne(&P.z)
P.ta = P.x
P.tb = P.y
return P.x, P.y
}

0 comments on commit 6173c83

Please sign in to comment.