...
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
119
120
121
122
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 }
134
View as plain text