github.com/cloudflare/circl@v1.5.0/ecc/bls12381/hash_test.go (about) 1 package bls12381 2 3 import ( 4 "encoding/hex" 5 "encoding/json" 6 "io" 7 "os" 8 "path/filepath" 9 "strings" 10 "testing" 11 12 "github.com/cloudflare/circl/ecc/bls12381/ff" 13 "github.com/cloudflare/circl/internal/test" 14 ) 15 16 type vectorHash struct { 17 SuiteID string `json:"ciphersuite"` 18 CurveName string `json:"curve"` 19 DST string `json:"dst"` 20 IsRandomOracle bool `json:"randomOracle"` 21 Vectors []struct { 22 P point `json:"P"` 23 Msg string `json:"msg"` 24 } `json:"vectors"` 25 Field struct { 26 M string `json:"m"` 27 P string `json:"p"` 28 } `json:"field"` 29 } 30 31 type elm string 32 33 func (e elm) toBytes(t *testing.T) (out []byte) { 34 var buf [ff.FpSize]byte 35 for _, s := range strings.Split(string(e), ",") { 36 x, err := hex.DecodeString(s[2:]) 37 if err != nil { 38 t.Fatal(err) 39 } 40 copy(buf[ff.FpSize-len(x):ff.FpSize], x) 41 out = append(append([]byte{}, buf[:]...), out...) 42 } 43 return 44 } 45 46 type point struct { 47 X elm `json:"x"` 48 Y elm `json:"y"` 49 } 50 51 func (p point) toBytes(t *testing.T) []byte { return append(p.X.toBytes(t), p.Y.toBytes(t)...) } 52 53 type hasher interface { 54 Encode(_, _ []byte) 55 Hash(_, _ []byte) 56 SetBytes([]byte) error 57 IsEqualTo(_ hasher) bool 58 IsRTorsion() bool 59 } 60 61 type g1Hasher struct{ *G1 } 62 63 func (g g1Hasher) IsEqualTo(x hasher) bool { return g.IsEqual(x.(g1Hasher).G1) } 64 func (g g1Hasher) IsRTorsion() bool { return g.IsOnG1() } 65 66 type g2Hasher struct{ *G2 } 67 68 func (g g2Hasher) IsEqualTo(x hasher) bool { return g.IsEqual(x.(g2Hasher).G2) } 69 func (g g2Hasher) IsRTorsion() bool { return g.IsOnG2() } 70 71 func (v *vectorHash) test(t *testing.T) { 72 var got, want hasher 73 if v.Field.M == "0x1" { 74 got, want = g1Hasher{new(G1)}, g1Hasher{new(G1)} 75 } else if v.Field.M == "0x2" { 76 got, want = g2Hasher{new(G2)}, g2Hasher{new(G2)} 77 } 78 79 dst := []byte(v.DST) 80 81 doHash := got.Encode 82 if v.IsRandomOracle { 83 doHash = got.Hash 84 } 85 86 for i, vi := range v.Vectors { 87 input := []byte(vi.Msg) 88 doHash(input, dst) 89 90 err := want.SetBytes(vi.P.toBytes(t)) 91 test.CheckNoErr(t, err, "bad deserialization") 92 93 if !got.IsEqualTo(want) || !got.IsRTorsion() { 94 test.ReportError(t, got, want, v.SuiteID, i) 95 } 96 } 97 } 98 99 func readFile(t *testing.T, fileName string) *vectorHash { 100 jsonFile, err := os.Open(fileName) 101 if err != nil { 102 t.Fatalf("File %v can not be opened. Error: %v", fileName, err) 103 } 104 defer jsonFile.Close() 105 input, err := io.ReadAll(jsonFile) 106 if err != nil { 107 t.Fatalf("File %v can not be loaded. Error: %v", fileName, err) 108 } 109 v := new(vectorHash) 110 err = json.Unmarshal(input, v) 111 if err != nil { 112 t.Fatalf("File %v can not be parsed. Error: %v", fileName, err) 113 } 114 return v 115 } 116 117 func TestHashVectors(t *testing.T) { 118 // Test vectors from draft-irtf-cfrg-hash-to-curve: 119 // https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-hash-to-curve-11 120 // 121 // JSON files can be found at: 122 // https://github.com/cfrg/draft-irtf-cfrg-hash-to-curve/tree/draft-irtf-cfrg-hash-to-curve-10/poc/vectors 123 124 fileNames, err := filepath.Glob("./testdata/BLS12381*.json") 125 if err != nil { 126 t.Fatal(err) 127 } 128 129 for _, fileName := range fileNames { 130 v := readFile(t, fileName) 131 t.Run(v.SuiteID, v.test) 132 } 133 }