github.com/ethersphere/bee/v2@v2.2.0/pkg/crypto/clef/clef_test.go (about) 1 // Copyright 2020 The Swarm Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package clef_test 6 7 import ( 8 "bytes" 9 "crypto/ecdsa" 10 "errors" 11 "math/big" 12 "testing" 13 14 "github.com/ethereum/go-ethereum/accounts" 15 "github.com/ethereum/go-ethereum/common" 16 "github.com/ethereum/go-ethereum/common/hexutil" 17 "github.com/ethereum/go-ethereum/core/types" 18 "github.com/ethersphere/bee/v2/pkg/crypto" 19 "github.com/ethersphere/bee/v2/pkg/crypto/clef" 20 "github.com/ethersphere/bee/v2/pkg/crypto/eip712" 21 ) 22 23 type mockClef struct { 24 accounts []accounts.Account 25 signature []byte 26 27 signedMimeType string 28 signedData []byte 29 signedAccount accounts.Account 30 } 31 32 func (m *mockClef) SignData(account accounts.Account, mimeType string, data []byte) ([]byte, error) { 33 m.signedAccount = account 34 m.signedMimeType = mimeType 35 m.signedData = data 36 return m.signature, nil 37 } 38 39 func (m *mockClef) Accounts() []accounts.Account { 40 return m.accounts 41 } 42 43 func (m *mockClef) SignTx(account accounts.Account, transaction *types.Transaction, chainId *big.Int) (*types.Transaction, error) { 44 return nil, nil 45 } 46 47 func TestNewClefSigner(t *testing.T) { 48 t.Parallel() 49 50 ethAddress := common.HexToAddress("0x31415b599f636129AD03c196cef9f8f8b184D5C7") 51 testSignature := make([]byte, 65) 52 53 key, err := crypto.GenerateSecp256k1Key() 54 if err != nil { 55 t.Fatal(err) 56 } 57 publicKey := &key.PublicKey 58 59 mock := &mockClef{ 60 accounts: []accounts.Account{ 61 { 62 Address: ethAddress, 63 }, 64 { 65 Address: common.Address{}, 66 }, 67 }, 68 signature: testSignature, 69 } 70 71 signer, err := clef.NewSigner(mock, nil, func(signature, data []byte) (*ecdsa.PublicKey, error) { 72 if !bytes.Equal(testSignature, signature) { 73 t.Fatalf("wrong data used for recover. expected %v got %v", testSignature, signature) 74 } 75 76 if !bytes.Equal(clef.ClefRecoveryMessage, data) { 77 t.Fatalf("wrong data used for recover. expected %v got %v", clef.ClefRecoveryMessage, data) 78 } 79 return publicKey, nil 80 }, nil) 81 if err != nil { 82 t.Fatal(err) 83 } 84 85 if mock.signedAccount.Address != ethAddress { 86 t.Fatalf("wrong account used for signing. expected %v got %v", ethAddress, mock.signedAccount.Address) 87 } 88 89 if mock.signedMimeType != accounts.MimetypeTextPlain { 90 t.Fatalf("wrong mime type used for signing. expected %v got %v", accounts.MimetypeTextPlain, mock.signedMimeType) 91 } 92 93 if !bytes.Equal(mock.signedData, clef.ClefRecoveryMessage) { 94 t.Fatalf("wrong data used for signing. expected %v got %v", clef.ClefRecoveryMessage, mock.signedData) 95 } 96 97 signerPublicKey, err := signer.PublicKey() 98 if err != nil { 99 t.Fatal(err) 100 } 101 102 if signerPublicKey != publicKey { 103 t.Fatalf("wrong public key. expected %v got %v", publicKey, signerPublicKey) 104 } 105 } 106 107 func TestNewClefSignerSpecificAccount(t *testing.T) { 108 t.Parallel() 109 110 ethAddress := common.HexToAddress("0x31415b599f636129AD03c196cef9f8f8b184D5C7") 111 wantedAddress := common.HexToAddress("0x41415b599f636129AD03c196cef9f8f8b184D5C7") 112 testSignature := make([]byte, 65) 113 114 key, err := crypto.GenerateSecp256k1Key() 115 if err != nil { 116 t.Fatal(err) 117 } 118 publicKey := &key.PublicKey 119 120 mock := &mockClef{ 121 accounts: []accounts.Account{ 122 { 123 Address: ethAddress, 124 }, 125 { 126 Address: wantedAddress, 127 }, 128 }, 129 signature: testSignature, 130 } 131 132 signer, err := clef.NewSigner(mock, nil, func(signature, data []byte) (*ecdsa.PublicKey, error) { 133 if !bytes.Equal(testSignature, signature) { 134 t.Fatalf("wrong data used for recover. expected %v got %v", testSignature, signature) 135 } 136 137 if !bytes.Equal(clef.ClefRecoveryMessage, data) { 138 t.Fatalf("wrong data used for recover. expected %v got %v", clef.ClefRecoveryMessage, data) 139 } 140 return publicKey, nil 141 }, &wantedAddress) 142 if err != nil { 143 t.Fatal(err) 144 } 145 146 if mock.signedAccount.Address != wantedAddress { 147 t.Fatalf("wrong account used for signing. expected %v got %v", wantedAddress, mock.signedAccount.Address) 148 } 149 150 if mock.signedMimeType != accounts.MimetypeTextPlain { 151 t.Fatalf("wrong mime type used for signing. expected %v got %v", accounts.MimetypeTextPlain, mock.signedMimeType) 152 } 153 154 if !bytes.Equal(mock.signedData, clef.ClefRecoveryMessage) { 155 t.Fatalf("wrong data used for signing. expected %v got %v", clef.ClefRecoveryMessage, mock.signedData) 156 } 157 158 signerPublicKey, err := signer.PublicKey() 159 if err != nil { 160 t.Fatal(err) 161 } 162 163 if signerPublicKey != publicKey { 164 t.Fatalf("wrong public key. expected %v got %v", publicKey, signerPublicKey) 165 } 166 } 167 168 func TestNewClefSignerAccountUnavailable(t *testing.T) { 169 t.Parallel() 170 171 ethAddress := common.HexToAddress("0x31415b599f636129AD03c196cef9f8f8b184D5C7") 172 wantedAddress := common.HexToAddress("0x41415b599f636129AD03c196cef9f8f8b184D5C7") 173 174 mock := &mockClef{ 175 accounts: []accounts.Account{ 176 { 177 Address: ethAddress, 178 }, 179 }, 180 } 181 182 _, err := clef.NewSigner(mock, nil, func(signature, data []byte) (*ecdsa.PublicKey, error) { 183 return nil, errors.New("called sign") 184 }, &wantedAddress) 185 if !errors.Is(err, clef.ErrAccountNotAvailable) { 186 t.Fatalf("expected account to be not available. got error %v", err) 187 } 188 } 189 190 func TestClefNoAccounts(t *testing.T) { 191 t.Parallel() 192 193 mock := &mockClef{ 194 accounts: []accounts.Account{}, 195 } 196 197 _, err := clef.NewSigner(mock, nil, nil, nil) 198 if err == nil { 199 t.Fatal("expected ErrNoAccounts error if no accounts") 200 } 201 if !errors.Is(err, clef.ErrNoAccounts) { 202 t.Fatalf("expected ErrNoAccounts error but got %v", err) 203 } 204 } 205 206 type mockRpc struct { 207 call func(result interface{}, method string, args ...interface{}) error 208 } 209 210 func (m *mockRpc) Call(result interface{}, method string, args ...interface{}) error { 211 return m.call(result, method, args...) 212 } 213 214 func TestClefTypedData(t *testing.T) { 215 t.Parallel() 216 217 key, err := crypto.GenerateSecp256k1Key() 218 if err != nil { 219 t.Fatal(err) 220 } 221 publicKey := &key.PublicKey 222 signature := common.FromHex("0xabcdef") 223 224 account := common.HexToAddress("21b26864067deb88e2d5cdca512167815f2910d3") 225 226 typedData := &eip712.TypedData{ 227 PrimaryType: "MyType", 228 } 229 230 signer, err := clef.NewSigner(&mockClef{ 231 accounts: []accounts.Account{ 232 { 233 Address: account, 234 }, 235 }, 236 signature: make([]byte, 65), 237 }, &mockRpc{ 238 call: func(result interface{}, method string, args ...interface{}) error { 239 if method != "account_signTypedData" { 240 t.Fatalf("called wrong method. was %s", method) 241 } 242 if args[0].(common.Address) != account { 243 t.Fatalf("called with wrong account. was %x, wanted %x", args[0].(common.Address), account) 244 } 245 if args[1].(*eip712.TypedData) != typedData { 246 t.Fatal("called with wrong data") 247 } 248 *result.(*hexutil.Bytes) = signature 249 return nil 250 }, 251 }, func(signature, data []byte) (*ecdsa.PublicKey, error) { 252 return publicKey, nil 253 }, nil) 254 if err != nil { 255 t.Fatal(err) 256 } 257 258 s, err := signer.SignTypedData(typedData) 259 if err != nil { 260 t.Fatal(err) 261 } 262 263 if !bytes.Equal(s, signature) { 264 t.Fatalf("wrong signature. wanted %x, got %x", signature, s) 265 } 266 }