Skip to content

Commit 90dedea

Browse files
authored
signer: EIP 712, parse bytes and bytesX as hex strings + correct padding (#21307)
* Handle hex strings for bytesX types * Add tests for parseBytes * Improve tests * Return nil bytes if error is non-nil * Right-pad instead of left-pad bytes * More tests
1 parent c0c0161 commit 90dedea

File tree

2 files changed

+118
-3
lines changed

2 files changed

+118
-3
lines changed

signer/core/signed_data.go

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -481,6 +481,24 @@ func (typedData *TypedData) EncodeData(primaryType string, data map[string]inter
481481
return buffer.Bytes(), nil
482482
}
483483

484+
// Attempt to parse bytes in different formats: byte array, hex string, hexutil.Bytes.
485+
func parseBytes(encType interface{}) ([]byte, bool) {
486+
switch v := encType.(type) {
487+
case []byte:
488+
return v, true
489+
case hexutil.Bytes:
490+
return []byte(v), true
491+
case string:
492+
bytes, err := hexutil.Decode(v)
493+
if err != nil {
494+
return nil, false
495+
}
496+
return bytes, true
497+
default:
498+
return nil, false
499+
}
500+
}
501+
484502
func parseInteger(encType string, encValue interface{}) (*big.Int, error) {
485503
var (
486504
length int
@@ -560,7 +578,7 @@ func (typedData *TypedData) EncodePrimitiveValue(encType string, encValue interf
560578
}
561579
return crypto.Keccak256([]byte(strVal)), nil
562580
case "bytes":
563-
bytesValue, ok := encValue.([]byte)
581+
bytesValue, ok := parseBytes(encValue)
564582
if !ok {
565583
return nil, dataMismatchError(encType, encValue)
566584
}
@@ -575,10 +593,13 @@ func (typedData *TypedData) EncodePrimitiveValue(encType string, encValue interf
575593
if length < 0 || length > 32 {
576594
return nil, fmt.Errorf("invalid size on bytes: %d", length)
577595
}
578-
if byteValue, ok := encValue.(hexutil.Bytes); !ok {
596+
if byteValue, ok := parseBytes(encValue); !ok || len(byteValue) != length {
579597
return nil, dataMismatchError(encType, encValue)
580598
} else {
581-
return math.PaddedBigBytes(new(big.Int).SetBytes(byteValue), 32), nil
599+
// Right-pad the bits
600+
dst := make([]byte, 32)
601+
copy(dst, byteValue)
602+
return dst, nil
582603
}
583604
}
584605
if strings.HasPrefix(encType, "int") || strings.HasPrefix(encType, "uint") {

signer/core/signed_data_internal_test.go

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,104 @@
1717
package core
1818

1919
import (
20+
"bytes"
2021
"math/big"
2122
"testing"
23+
24+
"github.com/ethereum/go-ethereum/common/hexutil"
2225
)
2326

27+
func TestBytesPadding(t *testing.T) {
28+
tests := []struct {
29+
Type string
30+
Input []byte
31+
Output []byte // nil => error
32+
}{
33+
{
34+
// Fail on wrong length
35+
Type: "bytes20",
36+
Input: []byte{},
37+
Output: nil,
38+
},
39+
{
40+
Type: "bytes1",
41+
Input: []byte{1},
42+
Output: []byte{1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
43+
},
44+
{
45+
Type: "bytes1",
46+
Input: []byte{1, 2},
47+
Output: nil,
48+
},
49+
{
50+
Type: "bytes7",
51+
Input: []byte{1, 2, 3, 4, 5, 6, 7},
52+
Output: []byte{1, 2, 3, 4, 5, 6, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
53+
},
54+
{
55+
Type: "bytes32",
56+
Input: []byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32},
57+
Output: []byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32},
58+
},
59+
{
60+
Type: "bytes32",
61+
Input: []byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33},
62+
Output: nil,
63+
},
64+
}
65+
66+
d := TypedData{}
67+
for i, test := range tests {
68+
val, err := d.EncodePrimitiveValue(test.Type, test.Input, 1)
69+
if test.Output == nil {
70+
if err == nil {
71+
t.Errorf("test %d: expected error, got no error (result %x)", i, val)
72+
}
73+
} else {
74+
if err != nil {
75+
t.Errorf("test %d: expected no error, got %v", i, err)
76+
}
77+
if len(val) != 32 {
78+
t.Errorf("test %d: expected len 32, got %d", i, len(val))
79+
}
80+
if !bytes.Equal(val, test.Output) {
81+
t.Errorf("test %d: expected %x, got %x", i, test.Output, val)
82+
}
83+
}
84+
}
85+
}
86+
87+
func TestParseBytes(t *testing.T) {
88+
for i, tt := range []struct {
89+
v interface{}
90+
exp []byte
91+
}{
92+
{"0x", []byte{}},
93+
{"0x1234", []byte{0x12, 0x34}},
94+
{[]byte{12, 34}, []byte{12, 34}},
95+
{hexutil.Bytes([]byte{12, 34}), []byte{12, 34}},
96+
{"1234", nil}, // not a proper hex-string
97+
{"0x01233", nil}, // nibbles should be rejected
98+
{"not a hex string", nil},
99+
{15, nil},
100+
{nil, nil},
101+
} {
102+
out, ok := parseBytes(tt.v)
103+
if tt.exp == nil {
104+
if ok || out != nil {
105+
t.Errorf("test %d: expected !ok, got ok = %v with out = %x", i, ok, out)
106+
}
107+
continue
108+
}
109+
if !ok {
110+
t.Errorf("test %d: expected ok got !ok", i)
111+
}
112+
if !bytes.Equal(out, tt.exp) {
113+
t.Errorf("test %d: expected %x got %x", i, tt.exp, out)
114+
}
115+
}
116+
}
117+
24118
func TestParseInteger(t *testing.T) {
25119
for i, tt := range []struct {
26120
t string

0 commit comments

Comments
 (0)