@@ -20,7 +20,14 @@ import (
2020 "crypto/ecdsa"
2121 "crypto/elliptic"
2222 "crypto/rand"
23+ "crypto/sha256"
24+ "encoding/asn1"
25+ "encoding/hex"
26+ "encoding/json"
27+ "fmt"
28+ "math/big"
2329 "slices"
30+ "strings"
2431 "testing"
2532
2633 "github.com/holiman/uint256"
@@ -33,6 +40,8 @@ import (
3340 "github.com/ava-labs/libevm/libevm/ethtest"
3441 "github.com/ava-labs/libevm/libevm/hookstest"
3542 "github.com/ava-labs/libevm/params"
43+
44+ _ "embed"
3645)
3746
3847// ulerdoganTestCase is the test case from
@@ -41,15 +50,18 @@ import (
4150// information.
4251const ulerdoganTestCase = `4cee90eb86eaa050036147a12d49004b6b9c72bd725d39d4785011fe190f0b4da73bd4903f0ce3b639bbbf6e8e80d16931ff4bcf5993d58468e8fb19086e8cac36dbcd03009df8c59286b162af3bd7fcc0450c9aa81be5d10d312af6c66b1d604aebd3099c618202fcfe16ae7770b0c49ab5eadf74b754204a3bb6060e44eff37618b065f9832de4ca6ca971a7a1adc826d0f7c00181a5fb2ddf79ae00b4e10e`
4352
53+ //go:embed testdata/ecdsa_secp256r1_sha256_test.json
54+ var wycheproofECDSASHA256 []byte
55+
56+ type testCase struct {
57+ name string
58+ in []byte
59+ wantSuccess bool
60+ }
61+
4462func TestPrecompile (t * testing.T ) {
4563 assert .Equal (t , params .P256VerifyGas , Precompile {}.RequiredGas (nil ), "RequiredGas()" )
4664
47- type testCase struct {
48- name string
49- in []byte
50- wantSuccess bool
51- }
52-
5365 tests := []testCase {
5466 {
5567 name : "empty_input" ,
@@ -102,6 +114,11 @@ func TestPrecompile(t *testing.T) {
102114 }
103115 }
104116
117+ tests = append (tests , wycheproofTestCases (t )... )
118+ if t .Failed () {
119+ return
120+ }
121+
105122 for _ , tt := range tests {
106123 t .Run (tt .name , func (t * testing.T ) {
107124 got , err := Precompile {}.Run (tt .in )
@@ -116,6 +133,100 @@ func TestPrecompile(t *testing.T) {
116133 }
117134}
118135
136+ type jsonHex []byte
137+
138+ var _ json.Unmarshaler = (* jsonHex )(nil )
139+
140+ func (j * jsonHex ) UnmarshalJSON (data []byte ) error {
141+ var s string
142+ if err := json .Unmarshal (data , & s ); err != nil {
143+ return err
144+ }
145+ b , err := hex .DecodeString (s )
146+ if err != nil {
147+ return err
148+ }
149+ * j = b
150+ return nil
151+ }
152+
153+ func wycheproofTestCases (t * testing.T ) []testCase {
154+ t .Helper ()
155+
156+ var raw struct {
157+ Groups []struct {
158+ Key struct {
159+ X jsonHex `json:"wx"`
160+ Y jsonHex `json:"wy"`
161+ }
162+ Tests []struct {
163+ ID int `json:"tcId"`
164+ Comment string
165+ Preimage jsonHex `json:"msg"`
166+ ASNSig jsonHex `json:"sig"`
167+ Result string
168+ } `json:"tests"`
169+ } `json:"testGroups"`
170+ }
171+ require .NoError (t , json .Unmarshal (wycheproofECDSASHA256 , & raw ))
172+
173+ var cases []testCase
174+ for _ , group := range raw .Groups {
175+ key := & ecdsa.PublicKey {
176+ Curve : elliptic .P256 (),
177+ X : new (big.Int ).SetBytes (group .Key .X ),
178+ Y : new (big.Int ).SetBytes (group .Key .Y ),
179+ }
180+
181+ for _ , test := range group .Tests {
182+ t .Run (fmt .Sprintf ("parse_test_%d" , test .ID ), func (t * testing.T ) {
183+ // Many of the invalid cases are due to ASN1-specific problems,
184+ // which aren't of concern to us.
185+ include := test .Result == "valid" ||
186+ strings .Contains (test .Comment , "r or s" ) ||
187+ strings .Contains (test .Comment , "r and s" ) ||
188+ slices .Contains (
189+ []int {
190+ // Special cases of r and/or s.
191+ 286 , 294 , 295 , 303 , 304 , 340 , 341 ,
192+ 342 , 343 , 356 , 357 , 358 , 359 ,
193+ },
194+ test .ID ,
195+ )
196+
197+ include = include && ! slices .Contains (
198+ // These cases have negative r or s value(s) with the same
199+ // absolute value(s) as valid signatures. Packing and then
200+ // unpacking via [big.Int.Bytes] therefore converts them to
201+ // the valid, positive values that pass verification and
202+ // raise false-positive test errors.
203+ []int {133 , 139 , 140 },
204+ test .ID ,
205+ )
206+ if ! include {
207+ return
208+ }
209+
210+ var rs [2 ]* big.Int
211+ rest , err := asn1 .Unmarshal (test .ASNSig , & rs )
212+ if err != nil || len (rest ) > 0 {
213+ return
214+ }
215+ if rs [0 ].BitLen () > 256 || rs [1 ].BitLen () > 256 {
216+ return
217+ }
218+ cases = append (cases , testCase {
219+ name : fmt .Sprintf ("wycheproof_ecdsa_secp256r1_sha256_%d" , test .ID ),
220+ in : Pack (sha256 .Sum256 (test .Preimage ), rs [0 ], rs [1 ], key ),
221+ wantSuccess : test .Result == "valid" ,
222+ })
223+ })
224+ }
225+ }
226+ t .Logf ("%d Wycheproof cases" , len (cases ))
227+ return cases
228+ }
229+
119230func BenchmarkPrecompile (b * testing.B ) {
120231 in := common .Hex2Bytes (ulerdoganTestCase )
121232 var p Precompile
0 commit comments