Skip to content
This repository has been archived by the owner on Dec 27, 2023. It is now read-only.

Update to accommodate DST longer than 255 #15

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 8 additions & 7 deletions g1.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package bls12381

import (
"errors"
"hash"
"math"
"math/big"
)
Expand Down Expand Up @@ -496,7 +497,7 @@ func (g *G1) MultiExp(r *PointG1, points []*PointG1, powers []*big.Int) (*PointG

// MapToCurve given a byte slice returns a valid G1 point.
// This mapping function implements the Simplified Shallue-van de Woestijne-Ulas method.
// https://tools.ietf.org/html/draft-irtf-cfrg-hash-to-curve-06
// https://tools.ietf.org/html/draft-irtf-cfrg-hash-to-curve-08
// Input byte slice should be a valid field element, otherwise an error is returned.
func (g *G1) MapToCurve(in []byte) (*PointG1, error) {
u, err := fromBytes(in)
Expand All @@ -514,9 +515,9 @@ func (g *G1) MapToCurve(in []byte) (*PointG1, error) {
// EncodeToCurve given a message and domain seperator tag returns the hash result
// which is a valid curve point.
// Implementation follows BLS12381G1_XMD:SHA-256_SSWU_NU_ suite at
// https://tools.ietf.org/html/draft-irtf-cfrg-hash-to-curve-06
func (g *G1) EncodeToCurve(msg, domain []byte) (*PointG1, error) {
hashRes, err := hashToFpXMDSHA256(msg, domain, 1)
// https://tools.ietf.org/html/draft-irtf-cfrg-hash-to-curve-08
func (g *G1) EncodeToCurve(f func() hash.Hash, msg, domain []byte) (*PointG1, error) {
hashRes, err := hashToFpXMD(f, msg, domain, 1)
if err != nil {
return nil, err
}
Expand All @@ -532,9 +533,9 @@ func (g *G1) EncodeToCurve(msg, domain []byte) (*PointG1, error) {
// HashToCurve given a message and domain seperator tag returns the hash result
// which is a valid curve point.
// Implementation follows BLS12381G1_XMD:SHA-256_SSWU_RO_ suite at
// https://tools.ietf.org/html/draft-irtf-cfrg-hash-to-curve-06
func (g *G1) HashToCurve(msg, domain []byte) (*PointG1, error) {
hashRes, err := hashToFpXMDSHA256(msg, domain, 2)
// https://tools.ietf.org/html/draft-irtf-cfrg-hash-to-curve-08
func (g *G1) HashToCurve(f func() hash.Hash, msg, domain []byte) (*PointG1, error) {
hashRes, err := hashToFpXMD(f, msg, domain, 2)
if err != nil {
return nil, err
}
Expand Down
46 changes: 44 additions & 2 deletions g1_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ package bls12381
import (
"bytes"
"crypto/rand"
"crypto/sha256"
"encoding/hex"
"io/ioutil"
"math/big"
"testing"
Expand Down Expand Up @@ -377,7 +379,7 @@ func TestG1EncodeToCurve(t *testing.T) {
},
} {
g := NewG1()
p0, err := g.EncodeToCurve(v.msg, domain)
p0, err := g.EncodeToCurve(sha256.New, v.msg, domain)
if err != nil {
t.Fatal("encode to point fails", i, err)
}
Expand Down Expand Up @@ -423,14 +425,54 @@ func TestG1HashToCurve(t *testing.T) {
},
} {
g := NewG1()
p0, err := g.HashToCurve(v.msg, domain)
p0, err := g.HashToCurve(sha256.New, v.msg, domain)
if err != nil {
t.Fatal("hash to point fails", i, err)
}
if !bytes.Equal(g.ToBytes(p0), v.expected) {
t.Fatal("hash to point fails", i)
}
}

domain = []byte("QUUX-V01-CS02-with-expander")
for i, v := range []struct {
msg []byte
expected []byte
}{
{
msg: []byte(""),
expected: fromHex(-1,
"140c7a6dbfff5ece70b651e951964551296f70efd3a72d64bd2c145f4469ba54840a4495f8ca4ee7a86dc25b83a54fde13871e80c7eaeb5af63ecf7e95ffa24b326ddab44cf1837ac3ba00bd7772c2b88e2f7d61271abdf84cd30deae9c0c798",
),
},
{
msg: []byte("abc"),
expected: fromHex(-1,
"10122323a3260d856bde2fc1662dc0fa863fda1abcd081fd932fb8cd01ff24b21af3900bd32d4e34558289b4c5d0cfc5129d3715ac3bb90229ec09e7649d2442f2991082d137072adfc664e185d879763f5c490cb261f8484c23872857bd16ce",
),
},
{
msg: []byte("abcdef0123456789"),
expected: fromHex(-1,
"00d6baa7c082c3bb02531bc329cfc6c00e04d32a0225faad568e081e5b761c1c9bc080020f88775e4eef90494f7f6b1719a8098791b3a8fa318a309bf84984bc32d435161df73c184c98a32351d39eb4c3a7236ad51ad28ef0151bcfcad66911",
),
},
{
msg: []byte("a512_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"),
expected: fromHex(-1,
"1386c705ca91cefd5feb2cacb337c6beaaa2161937ebfbb2bf1838adfaac0c4922d674f0ed394f247c0d1b9befc8964d08fa7f130bd73137226438335797a20ebcf6d3699ac520aa0db1f9268865db330f36108fed71e6cf2c2f3651acb3e48a",
),
},
} {
g := NewG1()
p0, err := g.HashToCurve(sha256.New, v.msg, domain)
if err != nil {
t.Fatal("hash to point fails", i, err)
}
if !bytes.Equal(g.ToBytes(p0), v.expected) {
t.Fatalf("hash to point fails %d: expected: %v, got: %v", i, hex.EncodeToString(v.expected), hex.EncodeToString(g.ToBytes(p0)))
}
}
}

func BenchmarkG1Add(t *testing.B) {
Expand Down
13 changes: 7 additions & 6 deletions g2.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package bls12381

import (
"errors"
"hash"
"math"
"math/big"
)
Expand Down Expand Up @@ -564,9 +565,9 @@ func (g *G2) MapToCurve(in []byte) (*PointG2, error) {
// EncodeToCurve given a message and domain seperator tag returns the hash result
// which is a valid curve point.
// Implementation follows BLS12381G1_XMD:SHA-256_SSWU_NU_ suite at
// https://tools.ietf.org/html/draft-irtf-cfrg-hash-to-curve-06
func (g *G2) EncodeToCurve(msg, domain []byte) (*PointG2, error) {
hashRes, err := hashToFpXMDSHA256(msg, domain, 2)
// https://tools.ietf.org/html/draft-irtf-cfrg-hash-to-curve-08
func (g *G2) EncodeToCurve(f func() hash.Hash, msg, domain []byte) (*PointG2, error) {
hashRes, err := hashToFpXMD(f, msg, domain, 2)
if err != nil {
return nil, err
}
Expand All @@ -583,9 +584,9 @@ func (g *G2) EncodeToCurve(msg, domain []byte) (*PointG2, error) {
// HashToCurve given a message and domain seperator tag returns the hash result
// which is a valid curve point.
// Implementation follows BLS12381G1_XMD:SHA-256_SSWU_RO_ suite at
// https://tools.ietf.org/html/draft-irtf-cfrg-hash-to-curve-06
func (g *G2) HashToCurve(msg, domain []byte) (*PointG2, error) {
hashRes, err := hashToFpXMDSHA256(msg, domain, 4)
// https://tools.ietf.org/html/draft-irtf-cfrg-hash-to-curve-08
func (g *G2) HashToCurve(f func() hash.Hash, msg, domain []byte) (*PointG2, error) {
hashRes, err := hashToFpXMD(f, msg, domain, 4)
if err != nil {
return nil, err
}
Expand Down
45 changes: 43 additions & 2 deletions g2_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ package bls12381
import (
"bytes"
"crypto/rand"
"crypto/sha256"
"encoding/hex"
"io/ioutil"
"math/big"
"testing"
Expand Down Expand Up @@ -493,7 +495,7 @@ func TestG2EncodeToCurve(t *testing.T) {
},
} {
g := NewG2()
p0, err := g.EncodeToCurve(v.msg, domain)
p0, err := g.EncodeToCurve(sha256.New, v.msg, domain)
if err != nil {
t.Fatal("encode to point fails", i, err)
}
Expand Down Expand Up @@ -547,14 +549,53 @@ func TestG2HashToCurve(t *testing.T) {
},
} {
g := NewG2()
p0, err := g.HashToCurve(v.msg, domain)
p0, err := g.HashToCurve(sha256.New, v.msg, domain)
if err != nil {
t.Fatal("encode to point fails", i, err)
}
if !bytes.Equal(g.ToBytes(p0), v.expected) {
t.Fatal("encode to point fails x", i)
}
}
domain = []byte("QUUX-V01-CS02-with-expander")

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks like a 27 bytes = 216 bit DST, so this does not test the code path about the DST being longer than 255, does it?

for i, v := range []struct {
msg []byte
expected []byte
}{
{
msg: []byte(""),
expected: fromHex(-1,
"11476980d59511379345dddd759c97c2a799bf21ee991e977439d73ff24dfedb468e5b8a1fd99e1e79eb80b5b17e32f900d83d21bd763b2b783e2e420de8813998556464624a9f328d9f5993efcacfd35b5ebc2bbdcd50a9f82393ae769a165c1250d29a557c960255447cd524b24f48f158048383f8e956562a54564c468d3c40e77b434f7382a6c67078c59800ac7b0048f91e5ec8bbaa5cdb8993243a8bb255fcf2d6aaabf785e9129bff0ebfff8ac9e2cdb5919ccdf8e4a05b940c281b42",
),
},
{
msg: []byte("abc"),
expected: fromHex(-1,
"158715ddabfc01a58b21bf7590b36aeaf0af7b7f336d4b9a18ec2952801be51ff81e092f8d465ebe8433576acaf1970e0c5b94d02b027927c94ca7520ebc5e0b8ada1b778df99c2390f0a485b2939aa8c4aefd4100a81b4071a218689b890d230fc5edda32abcf705239d2ba7a67c08ec90de872765cab945b02449e44a3d8e933fb2982cdb286cd3e38e688ee736ce10f1b39c3fec1de32245b6bdba9848f9d3a93adbf1c69280f4e20c961885251227e798445947eff1038f8dfe93a713bf0",
),
},
{
msg: []byte("abcdef0123456789"),
expected: fromHex(-1,
"0b78c6db53a98aa4c600524cc8c24cabaf3f695645fd3f3c58e5a7c105737cf8dbccf4ef14517210bb200bda2f82374b029dfd5cfa8735a372aa5f5edd1449be549c76f611c859b7fbbbbb85c821be209685caae39c4f80c8fd10b6140309795146c6ffc2ee10da5379c237ef43e4c24f71e32ffc3d3949a0f07c6b177406ee90fef3059cd3a860bc74cc945bf3335360a7e5f4221f2e0f29589feab7d7ac6f7a17a50324881071a14a49556f2a8de47d164b317d480fb47ec0f082d44b7b641",
),
},
{
msg: []byte("a512_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"),
expected: fromHex(-1,
"164da56a56881558025526ddba71c1a25a5650ae44ff47ce78d784c03c1c523b85acd73fecca9beb7142df1852ecaccf0222289d1ebdac5c2cf336f6f5bb9880ee58efbeac543dcb5317222224052d3d1ada9aa26c74ccda6c90a7a0484080ed16b9cf44913ea3a924f762fdfa8061ca88cff73aa6f40e01eeb7eed75b7d45cc3163644ee8d00c9a00a750f56f6d492e0d39e2c0234380e8bf1503d754c3998e54460a4b9dc135f7f9b08b6a6d86dcc2bc1de0ec601b09970646ddf1c9f9c71c",
),
},
} {
g := NewG2()
p0, err := g.HashToCurve(sha256.New, v.msg, domain)
if err != nil {
t.Fatal("hash to point fails", i, err)
}
if !bytes.Equal(g.ToBytes(p0), v.expected) {
t.Fatalf("hash to point fails %d: expected: %v, got: %v", i, hex.EncodeToString(v.expected), hex.EncodeToString(g.ToBytes(p0)))
}
}
}

func BenchmarkG2Add(t *testing.B) {
Expand Down
4 changes: 2 additions & 2 deletions go.mod
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
module github.com/kilic/bls12-381
module github.cbhq.net/security/bls12-381

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems like it was committed by mistake.


go 1.12
go 1.14

require golang.org/x/sys v0.0.0-20191025090151-53bf42e6b339
32 changes: 20 additions & 12 deletions hash_to_field.go
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
package bls12381

import (
"crypto/sha256"
"errors"
"hash"
)

func hashToFpXMDSHA256(msg []byte, domain []byte, count int) ([]*fe, error) {
randBytes, err := expandMsgSHA256XMD(msg, domain, count*64)
if err != nil {
return nil, err
}
func hashToFpXMD(f func() hash.Hash, msg []byte, domain []byte, count int) ([]*fe, error) {
h := f()
lenPerElm := h.Size() * 2
lenInBytes := count * lenPerElm
randBytes := expandMsgXMD(f, msg, domain, lenInBytes)
els := make([]*fe, count)
var err error
for i := 0; i < count; i++ {
els[i], err = from64Bytes(randBytes[i*64 : (i+1)*64])
if err != nil {
Expand All @@ -20,11 +20,17 @@ func hashToFpXMDSHA256(msg []byte, domain []byte, count int) ([]*fe, error) {
return els, nil
}

func expandMsgSHA256XMD(msg []byte, domain []byte, outLen int) ([]byte, error) {
h := sha256.New()
func expandMsgXMD(f func() hash.Hash, msg []byte, domain []byte, outLen int) []byte {
h := f()
domainLen := uint8(len(domain))
if domainLen > 255 {
return nil, errors.New("invalid domain length")
if len(domain) > 255 {
// See https://datatracker.ietf.org/doc/draft-irtf-cfrg-hash-to-curve/?include_text=1
// Section 5.3.3
h.Write([]byte("H2C-OVERSIZE-DST-"))
h.Write(domain)
domain = h.Sum(nil)
h.Reset()
domainLen = uint8(len(domain))
}
// DST_prime = DST || I2OSP(len(DST), 1)
// b_0 = H(Z_pad || msg || l_i_b_str || I2OSP(0, 1) || DST_prime)
Expand Down Expand Up @@ -66,5 +72,7 @@ func expandMsgSHA256XMD(msg []byte, domain []byte, outLen int) ([]byte, error) {
}
// b_ell
copy(out[(ell-1)*h.Size():], bi[:])
return out[:outLen], nil
return out[:outLen]

}

4 changes: 2 additions & 2 deletions isogeny.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ package bls12381

// isogenyMapG1 applies 11-isogeny map for BLS12-381 G1 defined at draft-irtf-cfrg-hash-to-curve-06.
func isogenyMapG1(x, y *fe) {
// https://tools.ietf.org/html/draft-irtf-cfrg-hash-to-curve-06#appendix-C.2
// https://tools.ietf.org/html/draft-irtf-cfrg-hash-to-curve-08#appendix-C.2
params := isogenyConstansG1
degree := 15
xNum, xDen, yNum, yDen := new(fe), new(fe), new(fe), new(fe)
Expand Down Expand Up @@ -34,7 +34,7 @@ func isogenyMapG2(e *fp2, x, y *fe2) {
if e == nil {
e = newFp2()
}
// https://tools.ietf.org/html/draft-irtf-cfrg-hash-to-curve-06#appendix-C.2
// https://tools.ietf.org/html/draft-irtf-cfrg-hash-to-curve-08#appendix-C.2
params := isogenyConstantsG2
degree := 3
xNum := new(fe2).set(params[0][degree])
Expand Down