signed_data_test.go 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408
  1. // Copyright 2018 The go-ethereum Authors
  2. // This file is part of go-ethereum.
  3. //
  4. // go-ethereum is free software: you can redistribute it and/or modify
  5. // it under the terms of the GNU General Public License as published by
  6. // the Free Software Foundation, either version 3 of the License, or
  7. // (at your option) any later version.
  8. //
  9. // go-ethereum is distributed in the hope that it will be useful,
  10. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. // GNU General Public License for more details.
  13. //
  14. // You should have received a copy of the GNU General Public License
  15. // along with go-ethereum. If not, see <http://www.gnu.org/licenses/>.
  16. //
  17. package core_test
  18. import (
  19. "context"
  20. "encoding/json"
  21. "fmt"
  22. "io/ioutil"
  23. "path"
  24. "strings"
  25. "testing"
  26. "github.com/ethereum/go-ethereum/accounts/keystore"
  27. "github.com/ethereum/go-ethereum/common"
  28. "github.com/ethereum/go-ethereum/common/hexutil"
  29. "github.com/ethereum/go-ethereum/common/math"
  30. "github.com/ethereum/go-ethereum/crypto"
  31. "github.com/ethereum/go-ethereum/signer/core"
  32. )
  33. var typesStandard = core.Types{
  34. "EIP712Domain": {
  35. {
  36. Name: "name",
  37. Type: "string",
  38. },
  39. {
  40. Name: "version",
  41. Type: "string",
  42. },
  43. {
  44. Name: "chainId",
  45. Type: "uint256",
  46. },
  47. {
  48. Name: "verifyingContract",
  49. Type: "address",
  50. },
  51. },
  52. "Person": {
  53. {
  54. Name: "name",
  55. Type: "string",
  56. },
  57. {
  58. Name: "wallet",
  59. Type: "address",
  60. },
  61. },
  62. "Mail": {
  63. {
  64. Name: "from",
  65. Type: "Person",
  66. },
  67. {
  68. Name: "to",
  69. Type: "Person",
  70. },
  71. {
  72. Name: "contents",
  73. Type: "string",
  74. },
  75. },
  76. }
  77. var jsonTypedData = `
  78. {
  79. "types": {
  80. "EIP712Domain": [
  81. {
  82. "name": "name",
  83. "type": "string"
  84. },
  85. {
  86. "name": "version",
  87. "type": "string"
  88. },
  89. {
  90. "name": "chainId",
  91. "type": "uint256"
  92. },
  93. {
  94. "name": "verifyingContract",
  95. "type": "address"
  96. }
  97. ],
  98. "Person": [
  99. {
  100. "name": "name",
  101. "type": "string"
  102. },
  103. {
  104. "name": "test",
  105. "type": "uint8"
  106. },
  107. {
  108. "name": "wallet",
  109. "type": "address"
  110. }
  111. ],
  112. "Mail": [
  113. {
  114. "name": "from",
  115. "type": "Person"
  116. },
  117. {
  118. "name": "to",
  119. "type": "Person"
  120. },
  121. {
  122. "name": "contents",
  123. "type": "string"
  124. }
  125. ]
  126. },
  127. "primaryType": "Mail",
  128. "domain": {
  129. "name": "Ether Mail",
  130. "version": "1",
  131. "chainId": "1",
  132. "verifyingContract": "0xCCCcccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC"
  133. },
  134. "message": {
  135. "from": {
  136. "name": "Cow",
  137. "test": 3,
  138. "wallet": "0xcD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826"
  139. },
  140. "to": {
  141. "name": "Bob",
  142. "wallet": "0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB"
  143. },
  144. "contents": "Hello, Bob!"
  145. }
  146. }
  147. `
  148. const primaryType = "Mail"
  149. var domainStandard = core.TypedDataDomain{
  150. "Ether Mail",
  151. "1",
  152. math.NewHexOrDecimal256(1),
  153. "0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC",
  154. "",
  155. }
  156. var messageStandard = map[string]interface{}{
  157. "from": map[string]interface{}{
  158. "name": "Cow",
  159. "wallet": "0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826",
  160. },
  161. "to": map[string]interface{}{
  162. "name": "Bob",
  163. "wallet": "0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB",
  164. },
  165. "contents": "Hello, Bob!",
  166. }
  167. var typedData = core.TypedData{
  168. Types: typesStandard,
  169. PrimaryType: primaryType,
  170. Domain: domainStandard,
  171. Message: messageStandard,
  172. }
  173. func TestSignData(t *testing.T) {
  174. api, control := setup(t)
  175. //Create two accounts
  176. createAccount(control, api, t)
  177. createAccount(control, api, t)
  178. control.approveCh <- "1"
  179. list, err := api.List(context.Background())
  180. if err != nil {
  181. t.Fatal(err)
  182. }
  183. a := common.NewMixedcaseAddress(list[0])
  184. control.approveCh <- "Y"
  185. control.inputCh <- "wrongpassword"
  186. signature, err := api.SignData(context.Background(), core.TextPlain.Mime, a, hexutil.Encode([]byte("EHLO world")))
  187. if signature != nil {
  188. t.Errorf("Expected nil-data, got %x", signature)
  189. }
  190. if err != keystore.ErrDecrypt {
  191. t.Errorf("Expected ErrLocked! '%v'", err)
  192. }
  193. control.approveCh <- "No way"
  194. signature, err = api.SignData(context.Background(), core.TextPlain.Mime, a, hexutil.Encode([]byte("EHLO world")))
  195. if signature != nil {
  196. t.Errorf("Expected nil-data, got %x", signature)
  197. }
  198. if err != core.ErrRequestDenied {
  199. t.Errorf("Expected ErrRequestDenied! '%v'", err)
  200. }
  201. // text/plain
  202. control.approveCh <- "Y"
  203. control.inputCh <- "a_long_password"
  204. signature, err = api.SignData(context.Background(), core.TextPlain.Mime, a, hexutil.Encode([]byte("EHLO world")))
  205. if err != nil {
  206. t.Fatal(err)
  207. }
  208. if signature == nil || len(signature) != 65 {
  209. t.Errorf("Expected 65 byte signature (got %d bytes)", len(signature))
  210. }
  211. // data/typed
  212. control.approveCh <- "Y"
  213. control.inputCh <- "a_long_password"
  214. signature, err = api.SignTypedData(context.Background(), a, typedData)
  215. if err != nil {
  216. t.Fatal(err)
  217. }
  218. if signature == nil || len(signature) != 65 {
  219. t.Errorf("Expected 65 byte signature (got %d bytes)", len(signature))
  220. }
  221. }
  222. func TestDomainChainId(t *testing.T) {
  223. withoutChainID := core.TypedData{
  224. Types: core.Types{
  225. "EIP712Domain": []core.Type{
  226. {Name: "name", Type: "string"},
  227. },
  228. },
  229. Domain: core.TypedDataDomain{
  230. Name: "test",
  231. },
  232. }
  233. if _, ok := withoutChainID.Domain.Map()["chainId"]; ok {
  234. t.Errorf("Expected the chainId key to not be present in the domain map")
  235. }
  236. withChainID := core.TypedData{
  237. Types: core.Types{
  238. "EIP712Domain": []core.Type{
  239. {Name: "name", Type: "string"},
  240. {Name: "chainId", Type: "uint256"},
  241. },
  242. },
  243. Domain: core.TypedDataDomain{
  244. Name: "test",
  245. ChainId: math.NewHexOrDecimal256(1),
  246. },
  247. }
  248. if _, ok := withChainID.Domain.Map()["chainId"]; !ok {
  249. t.Errorf("Expected the chainId key be present in the domain map")
  250. }
  251. }
  252. func TestHashStruct(t *testing.T) {
  253. hash, err := typedData.HashStruct(typedData.PrimaryType, typedData.Message)
  254. if err != nil {
  255. t.Fatal(err)
  256. }
  257. mainHash := fmt.Sprintf("0x%s", common.Bytes2Hex(hash))
  258. if mainHash != "0xc52c0ee5d84264471806290a3f2c4cecfc5490626bf912d01f240d7a274b371e" {
  259. t.Errorf("Expected different hashStruct result (got %s)", mainHash)
  260. }
  261. hash, err = typedData.HashStruct("EIP712Domain", typedData.Domain.Map())
  262. if err != nil {
  263. t.Error(err)
  264. }
  265. domainHash := fmt.Sprintf("0x%s", common.Bytes2Hex(hash))
  266. if domainHash != "0xf2cee375fa42b42143804025fc449deafd50cc031ca257e0b194a650a912090f" {
  267. t.Errorf("Expected different domain hashStruct result (got %s)", domainHash)
  268. }
  269. }
  270. func TestEncodeType(t *testing.T) {
  271. domainTypeEncoding := string(typedData.EncodeType("EIP712Domain"))
  272. if domainTypeEncoding != "EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)" {
  273. t.Errorf("Expected different encodeType result (got %s)", domainTypeEncoding)
  274. }
  275. mailTypeEncoding := string(typedData.EncodeType(typedData.PrimaryType))
  276. if mailTypeEncoding != "Mail(Person from,Person to,string contents)Person(string name,address wallet)" {
  277. t.Errorf("Expected different encodeType result (got %s)", mailTypeEncoding)
  278. }
  279. }
  280. func TestTypeHash(t *testing.T) {
  281. mailTypeHash := fmt.Sprintf("0x%s", common.Bytes2Hex(typedData.TypeHash(typedData.PrimaryType)))
  282. if mailTypeHash != "0xa0cedeb2dc280ba39b857546d74f5549c3a1d7bdc2dd96bf881f76108e23dac2" {
  283. t.Errorf("Expected different typeHash result (got %s)", mailTypeHash)
  284. }
  285. }
  286. func TestEncodeData(t *testing.T) {
  287. hash, err := typedData.EncodeData(typedData.PrimaryType, typedData.Message, 0)
  288. if err != nil {
  289. t.Fatal(err)
  290. }
  291. dataEncoding := fmt.Sprintf("0x%s", common.Bytes2Hex(hash))
  292. if dataEncoding != "0xa0cedeb2dc280ba39b857546d74f5549c3a1d7bdc2dd96bf881f76108e23dac2fc71e5fa27ff56c350aa531bc129ebdf613b772b6604664f5d8dbe21b85eb0c8cd54f074a4af31b4411ff6a60c9719dbd559c221c8ac3492d9d872b041d703d1b5aadf3154a261abdd9086fc627b61efca26ae5702701d05cd2305f7c52a2fc8" {
  293. t.Errorf("Expected different encodeData result (got %s)", dataEncoding)
  294. }
  295. }
  296. func TestFormatter(t *testing.T) {
  297. var d core.TypedData
  298. err := json.Unmarshal([]byte(jsonTypedData), &d)
  299. if err != nil {
  300. t.Fatalf("unmarshalling failed '%v'", err)
  301. }
  302. formatted, _ := d.Format()
  303. for _, item := range formatted {
  304. fmt.Printf("'%v'\n", item.Pprint(0))
  305. }
  306. j, _ := json.Marshal(formatted)
  307. fmt.Printf("'%v'\n", string(j))
  308. }
  309. func sign(typedData core.TypedData) ([]byte, []byte, error) {
  310. domainSeparator, err := typedData.HashStruct("EIP712Domain", typedData.Domain.Map())
  311. if err != nil {
  312. return nil, nil, err
  313. }
  314. typedDataHash, err := typedData.HashStruct(typedData.PrimaryType, typedData.Message)
  315. if err != nil {
  316. return nil, nil, err
  317. }
  318. rawData := []byte(fmt.Sprintf("\x19\x01%s%s", string(domainSeparator), string(typedDataHash)))
  319. sighash := crypto.Keccak256(rawData)
  320. return typedDataHash, sighash, nil
  321. }
  322. func TestJsonFiles(t *testing.T) {
  323. testfiles, err := ioutil.ReadDir("testdata/")
  324. if err != nil {
  325. t.Fatalf("failed reading files: %v", err)
  326. }
  327. for i, fInfo := range testfiles {
  328. if !strings.HasSuffix(fInfo.Name(), "json") {
  329. continue
  330. }
  331. expectedFailure := strings.HasPrefix(fInfo.Name(), "expfail")
  332. data, err := ioutil.ReadFile(path.Join("testdata", fInfo.Name()))
  333. if err != nil {
  334. t.Errorf("Failed to read file %v: %v", fInfo.Name(), err)
  335. continue
  336. }
  337. var typedData core.TypedData
  338. err = json.Unmarshal([]byte(data), &typedData)
  339. if err != nil {
  340. t.Errorf("Test %d, file %v, json unmarshalling failed: %v", i, fInfo.Name(), err)
  341. continue
  342. }
  343. _, _, err = sign(typedData)
  344. fmt.Printf("Error %v\n", err)
  345. if err != nil && !expectedFailure {
  346. t.Errorf("Test %d failed, file %v: %v", i, fInfo.Name(), err)
  347. }
  348. if expectedFailure && err == nil {
  349. t.Errorf("Test %d succeeded (expected failure), file %v: %v", i, fInfo.Name(), err)
  350. }
  351. }
  352. }
  353. // TestFuzzerFiles tests some files that have been found by fuzzing to cause
  354. // crashes or hangs.
  355. func TestFuzzerFiles(t *testing.T) {
  356. corpusdir := path.Join("testdata", "fuzzing")
  357. testfiles, err := ioutil.ReadDir(corpusdir)
  358. if err != nil {
  359. t.Fatalf("failed reading files: %v", err)
  360. }
  361. verbose := false
  362. for i, fInfo := range testfiles {
  363. data, err := ioutil.ReadFile(path.Join(corpusdir, fInfo.Name()))
  364. if err != nil {
  365. t.Errorf("Failed to read file %v: %v", fInfo.Name(), err)
  366. continue
  367. }
  368. var typedData core.TypedData
  369. err = json.Unmarshal([]byte(data), &typedData)
  370. if err != nil {
  371. t.Errorf("Test %d, file %v, json unmarshalling failed: %v", i, fInfo.Name(), err)
  372. continue
  373. }
  374. _, err = typedData.EncodeData("EIP712Domain", typedData.Domain.Map(), 1)
  375. if verbose && err != nil {
  376. fmt.Printf("%d, EncodeData[1] err: %v\n", i, err)
  377. }
  378. _, err = typedData.EncodeData(typedData.PrimaryType, typedData.Message, 1)
  379. if verbose && err != nil {
  380. fmt.Printf("%d, EncodeData[2] err: %v\n", i, err)
  381. }
  382. typedData.Format()
  383. }
  384. }