From 476ef2229b86a6bb438feade02cb7a048490acea Mon Sep 17 00:00:00 2001 From: armfazh Date: Tue, 4 May 2021 18:03:29 -0700 Subject: [PATCH] Removes the h2c-go-ref dependency. --- go.mod | 5 +- go.sum | 20 ++------ group/hash.go | 57 +++++++++++----------- group/ristretto255.go | 16 ++---- group/short.go | 111 ++++++++++++++++++------------------------ 5 files changed, 85 insertions(+), 124 deletions(-) diff --git a/go.mod b/go.mod index 0353d082d..cb9981612 100644 --- a/go.mod +++ b/go.mod @@ -3,8 +3,7 @@ module github.com/cloudflare/circl go 1.12 require ( - github.com/armfazh/h2c-go-ref v0.0.0-20210215173008-07e12a6f8e0d github.com/bwesterb/go-ristretto v1.2.0 - golang.org/x/crypto v0.0.0-20210503195802-e9a32991a82e - golang.org/x/sys v0.0.0-20210503173754-0981d6026fa6 + golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e + golang.org/x/sys v0.0.0-20210616094352-59db8d763f22 ) diff --git a/go.sum b/go.sum index f3ebe0158..89efb2ee9 100644 --- a/go.sum +++ b/go.sum @@ -1,22 +1,12 @@ -github.com/armfazh/h2c-go-ref v0.0.0-20210215173008-07e12a6f8e0d h1:0YBiQ+rXap26i6apP7AldB+h50fAP7XSzpbio4ElXQo= -github.com/armfazh/h2c-go-ref v0.0.0-20210215173008-07e12a6f8e0d/go.mod h1:8fwPDRbWg9lh+s+iVv/7yAthCGHoGLTpeXnHf/J5EXs= -github.com/armfazh/tozan-ecc v0.1.3 h1:g3OKE0KR4L/GZaoQYzsOUdg97Ey5lZRl1i1fD/QkUUw= -github.com/armfazh/tozan-ecc v0.1.3/go.mod h1:u25eZC5Z8uJFQxJxGBz1Blfii/7m3DfmwX0vFnwtG9I= github.com/bwesterb/go-ristretto v1.2.0 h1:xxWOVbN5m8NNKiSDZXE1jtZvZnC6JSJ9cYFADiZcWtw= github.com/bwesterb/go-ristretto v1.2.0/go.mod h1:fUIoIZaG73pV5biE2Blr2xEzDoMj7NFEuV9ekS419A0= -golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20201124201722-c8d3bf9c5392/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= -golang.org/x/crypto v0.0.0-20210503195802-e9a32991a82e h1:8foAy0aoO5GkqCvAEJ4VC4P3zksTg4X4aJCDpZzmgQI= -golang.org/x/crypto v0.0.0-20210503195802-e9a32991a82e/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8= -golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e h1:gsTQYXdTw2Gq7RBsWvlQ91b+aEQ6bXFUngBGuR8sPpI= +golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210503173754-0981d6026fa6 h1:cdsMqa2nXzqlgs183pHxtvoVwU7CyzaCTAUOg94af4c= -golang.org/x/sys v0.0.0-20210503173754-0981d6026fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= +golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210616094352-59db8d763f22 h1:RqytpXGR1iVNX7psjB3ff8y7sNFinVFvkx1c8SjBkio= +golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= -golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= diff --git a/group/hash.go b/group/hash.go index e43977155..f0eab8d77 100644 --- a/group/hash.go +++ b/group/hash.go @@ -5,26 +5,38 @@ import ( "math/big" ) -// FieldHasher allows to hash byte strings producing one or more field elements. -type FieldHasher interface { - // HashToField generates a set of elements {u1,..., uN} = Hash(b). - HashToField(u []big.Int, b []byte) +// HashToField generates a set of elements {u1,..., uN} = Hash(b) where each +// u in GF(p) and L is the security parameter. +func HashToField(u []big.Int, b []byte, e Expander, p *big.Int, L uint) { + count := uint(len(u)) + bytes := e.Expand(b, count*L) + for i := range u { + j := uint(i) * L + u[i].Mod(u[i].SetBytes(bytes[j:j+L]), p) + } +} + +const maxDSTLength = 255 + +var longDSTPrefix = [17]byte{'H', '2', 'C', '-', 'O', 'V', 'E', 'R', 'S', 'I', 'Z', 'E', '-', 'D', 'S', 'T', '-'} + +type Expander interface { + // Expand generates a pseudo-random byte string of a determined length by + // expanding an input string. + Expand(in []byte, length uint) (pseudo []byte) } type expanderXMD struct { h crypto.Hash - p *big.Int - L uint dst []byte } // NewExpanderMD returns a hash function based on a Merkle-Damgård hash function. -func NewExpanderMD(h crypto.Hash, p *big.Int, L uint, dst []byte) FieldHasher { - const maxDSTLength = 255 +func NewExpanderMD(h crypto.Hash, dst []byte) Expander { var dstPrime []byte if l := len(dst); l > maxDSTLength { H := h.New() - _, _ = H.Write([]byte("H2C-OVERSIZE-DST-")) + _, _ = H.Write(longDSTPrefix[:]) _, _ = H.Write(dst) dstPrime = H.Sum(nil) } else { @@ -32,19 +44,10 @@ func NewExpanderMD(h crypto.Hash, p *big.Int, L uint, dst []byte) FieldHasher { copy(dstPrime, dst) } dstPrime = append(dstPrime, byte(len(dstPrime))) - return expanderXMD{h, p, L, dstPrime} + return expanderXMD{h, dstPrime} } -func (e expanderXMD) HashToField(u []big.Int, b []byte) { - count := uint(len(u)) - bytes := e.expand(b, count*e.L) - for i := range u { - j := uint(i) * e.L - u[i].Mod(u[i].SetBytes(bytes[j:j+e.L]), e.p) - } -} - -func (e expanderXMD) expand(msg []byte, n uint) []byte { +func (e expanderXMD) Expand(in []byte, n uint) []byte { H := e.h.New() bLen := uint(H.Size()) ell := (n + (bLen - 1)) / bLen @@ -59,7 +62,7 @@ func (e expanderXMD) expand(msg []byte, n uint) []byte { H.Reset() _, _ = H.Write(zPad) - _, _ = H.Write(msg) + _, _ = H.Write(in) _, _ = H.Write(libStr) _, _ = H.Write([]byte{0}) _, _ = H.Write(e.dst) @@ -73,7 +76,10 @@ func (e expanderXMD) expand(msg []byte, n uint) []byte { pseudo := append([]byte{}, bi...) for i := uint(2); i <= ell; i++ { H.Reset() - _, _ = H.Write(xor(bi, b0)) + for i := range b0 { + bi[i] ^= b0[i] + } + _, _ = H.Write(bi) _, _ = H.Write([]byte{byte(i)}) _, _ = H.Write(e.dst) bi = H.Sum(nil) @@ -81,10 +87,3 @@ func (e expanderXMD) expand(msg []byte, n uint) []byte { } return pseudo[0:n] } - -func xor(x, y []byte) []byte { - for i := range x { - x[i] ^= y[i] - } - return x -} diff --git a/group/ristretto255.go b/group/ristretto255.go index db51b3c93..61f8cc77a 100644 --- a/group/ristretto255.go +++ b/group/ristretto255.go @@ -2,10 +2,9 @@ package group import ( "crypto" + _ "crypto/sha512" // to link libraries "io" - h2c "github.com/armfazh/h2c-go-ref" - r255 "github.com/bwesterb/go-ristretto" ) @@ -84,18 +83,9 @@ func (g ristrettoGroup) RandomScalar(r io.Reader) Scalar { } func (g ristrettoGroup) HashToElement(msg, dst []byte) Element { + xmd := NewExpanderMD(crypto.SHA512, dst) + data := xmd.Expand(msg, 64) e := g.NewElement() - - expID := h2c.ExpanderDesc{ - Type: h2c.XMD, - ID: uint(crypto.SHA512), - } - exp, err := expID.Get(dst, 0) - if err != nil { - panic(err) - } - data := exp.Expand(msg, 64) - e.(*ristrettoElement).p.Derive(data) return e } diff --git a/group/short.go b/group/short.go index 603eb3d37..d0a60fe2d 100644 --- a/group/short.go +++ b/group/short.go @@ -31,35 +31,6 @@ func (g wG) RandomScalar(rd io.Reader) Scalar { _, _ = io.ReadFull(rd, b) return g.HashToScalar(b, nil) } -func (g wG) getHasher(dst []byte) wHash { - var Z, C2 big.Int - var h crypto.Hash - var L uint - switch g.c.Params().BitSize { - case 256: - Z.SetInt64(-10) - C2.SetString("0x78bc71a02d89ec07214623f6d0f955072c7cc05604a5a6e23ffbf67115fa5301", 0) - h = crypto.SHA256 - L = 48 - case 384: - Z.SetInt64(-12) - C2.SetString("0x19877cc1041b7555743c0ae2e3a3e61fb2aaa2e0e87ea557a563d8b598a0940d0a697a9e0b9e92cfaa314f583c9d066", 0) - h = crypto.SHA512 - L = 72 - case 521: - Z.SetInt64(-4) - C2.SetInt64(8) - h = crypto.SHA512 - L = 98 - default: - panic("curve not supported") - } - return wHash{ - sswu3mod4{g, &Z, &C2}, - NewExpanderMD(h, g.c.Params().P, L, dst), - NewExpanderMD(h, g.c.Params().N, L, dst), - } -} func (g wG) cvtElt(e Element) *wElt { ee, ok := e.(*wElt) if !ok || g.c.Params().BitSize != ee.c.Params().BitSize { @@ -82,6 +53,24 @@ func (g wG) Params() *Params { ScalarLength: fieldLen, } } +func (g wG) HashToElement(b, dst []byte) Element { + var u [2]big.Int + mapping, h, L := g.mapToCurveParams() + xmd := NewExpanderMD(h, dst) + HashToField(u[:], b, xmd, g.c.Params().P, L) + Q0 := mapping(&u[0]) + Q1 := mapping(&u[1]) + return Q0.Add(Q0, Q1) +} +func (g wG) HashToScalar(b, dst []byte) Scalar { + var u [1]big.Int + _, h, L := g.mapToCurveParams() + xmd := NewExpanderMD(h, dst) + HashToField(u[:], b, xmd, g.c.Params().N, L) + s := g.NewScalar().(*wScl) + s.fromBig(&u[0]) + return s +} type wElt struct { wG @@ -235,37 +224,31 @@ func (s *wScl) UnmarshalBinary(b []byte) error { return nil } -type wHash struct { - sswu3mod4 - elt FieldHasher - scl FieldHasher -} - -func (g wG) HashToElement(b, dst []byte) Element { - var u [2]big.Int - h := g.getHasher(dst) - h.elt.HashToField(u[:], b) - Q0 := h.Map(&u[0]) - Q1 := h.Map(&u[1]) - return Q0.Add(Q0, Q1) -} - -func (g wG) HashToScalar(b, dst []byte) Scalar { - var u [1]big.Int - h := g.getHasher(dst) - h.scl.HashToField(u[:], b) - s := g.NewScalar().(*wScl) - s.fromBig(&u[0]) - return s -} - -type sswu3mod4 struct { - wG - Z *big.Int - C2 *big.Int // c2 = sqrt(-Z^3) +func (g wG) mapToCurveParams() (mapping func(u *big.Int) *wElt, h crypto.Hash, L uint) { + var Z, C2 big.Int + switch g.c.Params().BitSize { + case 256: + Z.SetInt64(-10) + C2.SetString("0x78bc71a02d89ec07214623f6d0f955072c7cc05604a5a6e23ffbf67115fa5301", 0) + h = crypto.SHA256 + L = 48 + case 384: + Z.SetInt64(-12) + C2.SetString("0x19877cc1041b7555743c0ae2e3a3e61fb2aaa2e0e87ea557a563d8b598a0940d0a697a9e0b9e92cfaa314f583c9d066", 0) + h = crypto.SHA512 + L = 72 + case 521: + Z.SetInt64(-4) + C2.SetInt64(8) + h = crypto.SHA512 + L = 98 + default: + panic("curve not supported") + } + return func(u *big.Int) *wElt { return g.sswu3mod4Map(u, &Z, &C2) }, h, L } -func (s sswu3mod4) Map(u *big.Int) Element { +func (g wG) sswu3mod4Map(u *big.Int, Z, C2 *big.Int) *wElt { tv1 := new(big.Int) tv2 := new(big.Int) tv3 := new(big.Int) @@ -282,8 +265,8 @@ func (s sswu3mod4) Map(u *big.Int) Element { y := new(big.Int) A := big.NewInt(-3) - B := s.c.Params().B - p := s.c.Params().P + B := g.c.Params().B + p := g.c.Params().P c1 := new(big.Int) c1.Sub(p, big.NewInt(3)).Rsh(c1, 2) // 1. c1 = (q - 3) / 4 @@ -301,7 +284,7 @@ func (s sswu3mod4) Map(u *big.Int) Element { } sqr(tv1, u) // 1. tv1 = u^2 - mul(tv3, s.Z, tv1) // 2. tv3 = Z * tv1 + mul(tv3, Z, tv1) // 2. tv3 = Z * tv1 sqr(tv2, tv3) // 3. tv2 = tv3^2 add(xd, tv2, tv3) // 4. xd = tv2 + tv3 add(x1n, xd, big.NewInt(1)) // 5. x1n = xd + 1 @@ -309,7 +292,7 @@ func (s sswu3mod4) Map(u *big.Int) Element { tv4.Neg(A) // mul(xd, tv4, xd) // 7. xd = -A * xd e1 := xd.Sign() == 0 // 8. e1 = xd == 0 - mul(tv4, s.Z, A) // + mul(tv4, Z, A) // cmv(xd, xd, tv4, e1) // 9. xd = CMOV(xd, Z * A, e1) sqr(tv2, xd) // 10. tv2 = xd^2 mul(gxd, tv2, xd) // 11. gxd = tv2 * xd @@ -325,7 +308,7 @@ func (s sswu3mod4) Map(u *big.Int) Element { exp(y1, tv4, c1) // 21. y1 = tv4^c1 mul(y1, y1, tv2) // 22. y1 = y1 * tv2 mul(x2n, tv3, x1n) // 23. x2n = tv3 * x1n - mul(y2, y1, s.C2) // 24. y2 = y1 * c2 + mul(y2, y1, C2) // 24. y2 = y1 * c2 mul(y2, y2, tv1) // 25. y2 = y2 * tv1 mul(y2, y2, u) // 26. y2 = y2 * u sqr(tv2, y1) // 27. tv2 = y1^2 @@ -339,5 +322,5 @@ func (s sswu3mod4) Map(u *big.Int) Element { tv1.ModInverse(xd, p) // mul(x, xn, tv1) // 34. return (xn, xd, y, 1) y.Mod(y, p) - return &wElt{s.wG, x, y} + return &wElt{g, x, y} }