packages feed

haskoin-core 0.14.1 → 0.15.0

raw patch · 61 files changed

+2951/−1192 lines, 61 filesdep +lensdep +lens-aesondep ~haskoin-coredep ~secp256k1-haskell

Dependencies added: lens, lens-aeson

Dependency ranges changed: haskoin-core, secp256k1-haskell

Files

CHANGELOG.md view
@@ -4,6 +4,18 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html). +## 0.15.0+### Added+- Add more test vectors++### Changed+- stringToAddr renamed to textToAddr+- Move ScriptOutput to Standard.hs+- Move WIF encoding/decoding to Keys.hs+- (breaking) rename `OP_NOP2` and `OP_NOP3` to `OP_CHECKLOCKTIMEVERIFY` and+  `OP_CHECKSEQUENCEVERIFY` resp.+- Update to latest secp256k1 bindings.+ ## 0.14.1 ### Fixed - Correct some Bitcoin Cash Testnet3 seeds.
+ data/key_io_invalid.json view
@@ -0,0 +1,182 @@+[+    [+        ""+    ],+    [+        "x"+    ],+    [+        "37qgekLpCCHrQuSjvX3fs496FWTGsHFHizjJAs6NPcR47aefnnCWECAhHV6E3g4YN7u7Yuwod5Y"+    ],+    [+        "dzb7VV1Ui55BARxv7ATxAtCUeJsANKovDGWFVgpTbhq9gvPqP3yv"+    ],+    [+        "MuNu7ZAEDFiHthiunm7dPjwKqrVNCM3mAz6rP9zFveQu14YA8CxExSJTHcVP9DErn6u84E6Ej7S"+    ],+    [+        "rPpQpYknyNQ5AEHuY6H8ijJJrYc2nDKKk9jjmKEXsWzyAQcFGpDLU2Zvsmoi8JLR7hAwoy3RQWf"+    ],+    [+        "4Uc3FmN6NQ6zLBK5QQBXRBUREaaHwCZYsGCueHauuDmJpZKn6jkEskMB2Zi2CNgtb5r6epWEFfUJq"+    ],+    [+        "7aQgR5DFQ25vyXmqZAWmnVCjL3PkBcdVkBUpjrjMTcghHx3E8wb"+    ],+    [+        "17QpPprjeg69fW1DV8DcYYCKvWjYhXvWkov6MJ1iTTvMFj6weAqW7wybZeH57WTNxXVCRH4veVs"+    ],+    [+        "KxuACDviz8Xvpn1xAh9MfopySZNuyajYMZWz16Dv2mHHryznWUp3"+    ],+    [+        "7nK3GSmqdXJQtdohvGfJ7KsSmn3TmGqExug49583bDAL91pVSGq5xS9SHoAYL3Wv3ijKTit65th"+    ],+    [+        "cTivdBmq7bay3RFGEBBuNfMh2P1pDCgRYN2Wbxmgwr4ki3jNUL2va"+    ],+    [+        "gjMV4vjNjyMrna4fsAr8bWxAbwtmMUBXJS3zL4NJt5qjozpbQLmAfK1uA3CquSqsZQMpoD1g2nk"+    ],+    [+        "emXm1naBMoVzPjbk7xpeTVMFy4oDEe25UmoyGgKEB1gGWsK8kRGs"+    ],+    [+        "7VThQnNRj1o3Zyvc7XHPRrjDf8j2oivPTeDXnRPYWeYGE4pXeRJDZgf28ppti5hsHWXS2GSobdqyo"+    ],+    [+        "1G9u6oCVCPh2o8m3t55ACiYvG1y5BHewUkDSdiQarDcYXXhFHYdzMdYfUAhfxn5vNZBwpgUNpso"+    ],+    [+        "31QQ7ZMLkScDiB4VyZjuptr7AEc9j1SjstF7pRoLhHTGkW4Q2y9XELobQmhhWxeRvqcukGd1XCq"+    ],+    [+        "DHqKSnpxa8ZdQyH8keAhvLTrfkyBMQxqngcQA5N8LQ9KVt25kmGN"+    ],+    [+        "2LUHcJPbwLCy9GLH1qXmfmAwvadWw4bp4PCpDfduLqV17s6iDcy1imUwhQJhAoNoN1XNmweiJP4i"+    ],+    [+        "7USRzBXAnmck8fX9HmW7RAb4qt92VFX6soCnts9s74wxm4gguVhtG5of8fZGbNPJA83irHVY6bCos"+    ],+    [+        "1DGezo7BfVebZxAbNT3XGujdeHyNNBF3vnficYoTSp4PfK2QaML9bHzAMxke3wdKdHYWmsMTJVu"+    ],+    [+        "2D12DqDZKwCxxkzs1ZATJWvgJGhQ4cFi3WrizQ5zLAyhN5HxuAJ1yMYaJp8GuYsTLLxTAz6otCfb"+    ],+    [+        "8AFJzuTujXjw1Z6M3fWhQ1ujDW7zsV4ePeVjVo7D1egERqSW9nZ"+    ],+    [+        "163Q17qLbTCue8YY3AvjpUhotuaodLm2uqMhpYirsKjVqnxJRWTEoywMVY3NbBAHuhAJ2cF9GAZ"+    ],+    [+        "2MnmgiRH4eGLyLc9eAqStzk7dFgBjFtUCtu"+    ],+    [+        "461QQ2sYWxU7H2PV4oBwJGNch8XVTYYbZxU"+    ],+    [+        "2UCtv53VttmQYkVU4VMtXB31REvQg4ABzs41AEKZ8UcB7DAfVzdkV9JDErwGwyj5AUHLkmgZeobs"+    ],+    [+        "cSNjAsnhgtiFMi6MtfvgscMB2Cbhn2v1FUYfviJ1CdjfidvmeW6mn"+    ],+    [+        "gmsow2Y6EWAFDFE1CE4Hd3Tpu2BvfmBfG1SXsuRARbnt1WjkZnFh1qGTiptWWbjsq2Q6qvpgJVj"+    ],+    [+        "nksUKSkzS76v8EsSgozXGMoQFiCoCHzCVajFKAXqzK5on9ZJYVHMD5CKwgmX3S3c7M1U3xabUny"+    ],+    [+        "L3favK1UzFGgdzYBF2oBT5tbayCo4vtVBLJhg2iYuMeePxWG8SQc"+    ],+    [+        "7VxLxGGtYT6N99GdEfi6xz56xdQ8nP2dG1CavuXx7Rf2PrvNMTBNevjkfgs9JmkcGm6EXpj8ipyPZ"+    ],+    [+        "2mbZwFXF6cxShaCo2czTRB62WTx9LxhTtpP"+    ],+    [+        "dB7cwYdcPSgiyAwKWL3JwCVwSk6epU2txw"+    ],+    [+        "HPhFUhUAh8ZQQisH8QQWafAxtQYju3SFTX"+    ],+    [+        "4ctAH6AkHzq5ioiM1m9T3E2hiYEev5mTsB"+    ],+    [+        "Hn1uFi4dNexWrqARpjMqgT6cX1UsNPuV3cHdGg9ExyXw8HTKadbktRDtdeVmY3M1BxJStiL4vjJ"+    ],+    [+        "Sq3fDbvutABmnAHHExJDgPLQn44KnNC7UsXuT7KZecpaYDMU9Txs"+    ],+    [+        "6TqWyrqdgUEYDQU1aChMuFMMEimHX44qHFzCUgGfqxGgZNMUVWJ"+    ],+    [+        "giqJo7oWqFxNKWyrgcBxAVHXnjJ1t6cGoEffce5Y1y7u649Noj5wJ4mmiUAKEVVrYAGg2KPB3Y4"+    ],+    [+        "cNzHY5e8vcmM3QVJUcjCyiKMYfeYvyueq5qCMV3kqcySoLyGLYUK"+    ],+    [+        "37uTe568EYc9WLoHEd9jXEvUiWbq5LFLscNyqvAzLU5vBArUJA6eydkLmnMwJDjkL5kXc2VK7ig"+    ],+    [+        "EsYbG4tWWWY45G31nox838qNdzksbPySWc"+    ],+    [+        "nbuzhfwMoNzA3PaFnyLcRxE9bTJPDkjZ6Rf6Y6o2ckXZfzZzXBT"+    ],+    [+        "cQN9PoxZeCWK1x56xnz6QYAsvR11XAce3Ehp3gMUdfSQ53Y2mPzx"+    ],+    [+        "1Gm3N3rkef6iMbx4voBzaxtXcmmiMTqZPhcuAepRzYUJQW4qRpEnHvMojzof42hjFRf8PE2jPde"+    ],+    [+        "2TAq2tuN6x6m233bpT7yqdYQPELdTDJn1eU"+    ],+    [+        "ntEtnnGhqPii4joABvBtSEJG6BxjT2tUZqE8PcVYgk3RHpgxgHDCQxNbLJf7ardf1dDk2oCQ7Cf"+    ],+    [+        "Ky1YjoZNgQ196HJV3HpdkecfhRBmRZdMJk89Hi5KGfpfPwS2bUbfd"+    ],+    [+        "2A1q1YsMZowabbvta7kTy2Fd6qN4r5ZCeG3qLpvZBMzCixMUdkN2Y4dHB1wPsZAeVXUGD83MfRED"+    ],+    [+        "tc1qw508d6qejxtdg4y5r3zarvary0c5xw7kg3g4ty"+    ],+    [+        "bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t5"+    ],+    [+        "BC13W508D6QEJXTDG4Y5R3ZARVARY0C5XW7KN40WF2"+    ],+    [+        "bc1rw5uspcuh"+    ],+    [+        "bc10w508d6qejxtdg4y5r3zarvary0c5xw7kw508d6qejxtdg4y5r3zarvary0c5xw7kw5rljs90"+    ],+    [+        "BC1QR508D6QEJXTDG4Y5R3ZARVARYV98GJ9P"+    ],+    [+        "tb1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3q0sL5k7"+    ],+    [+        "bc1zw508d6qejxtdg4y5r3zarvaryvqyzf3du"+    ],+    [+        "tb1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3pjxtptv"+    ],+    [+        "bc1gmk9yu"+    ]+]
+ data/key_io_valid.json view
@@ -0,0 +1,536 @@+[+    [+        "1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62i",+        "76a91465a16059864a2fdbc7c99a4723a8395bc6f188eb88ac",+        {+            "isPrivkey": false,+            "chain": "main"+        }+    ],+    [+        "3CMNFxN1oHBc4R1EpboAL5yzHGgE611Xou",+        "a91474f209f6ea907e2ea48f74fae05782ae8a66525787",+        {+            "isPrivkey": false,+            "chain": "main"+        }+    ],+    [+        "mo9ncXisMeAoXwqcV5EWuyncbmCcQN4rVs",+        "76a91453c0307d6851aa0ce7825ba883c6bd9ad242b48688ac",+        {+            "isPrivkey": false,+            "chain": "test"+        }+    ],+    [+        "mo9ncXisMeAoXwqcV5EWuyncbmCcQN4rVs",+        "76a91453c0307d6851aa0ce7825ba883c6bd9ad242b48688ac",+        {+            "isPrivkey": false,+            "chain": "regtest"+        }+    ],+    [+        "2N2JD6wb56AfK4tfmM6PwdVmoYk2dCKf4Br",+        "a9146349a418fc4578d10a372b54b45c280cc8c4382f87",+        {+            "isPrivkey": false,+            "chain": "test"+        }+    ],+    [+        "5Kd3NBUAdUnhyzenEwVLy9pBKxSwXvE9FMPyR4UKZvpe6E3AgLr",+        "eddbdc1168f1daeadbd3e44c1e3f8f5a284c2029f78ad26af98583a499de5b19",+        {+            "isCompressed": false,+            "isPrivkey": true,+            "chain": "main"+        }+    ],+    [+        "Kz6UJmQACJmLtaQj5A3JAge4kVTNQ8gbvXuwbmCj7bsaabudb3RD",+        "55c9bccb9ed68446d1b75273bbce89d7fe013a8acd1625514420fb2aca1a21c4",+        {+            "isCompressed": true,+            "isPrivkey": true,+            "chain": "main"+        }+    ],+    [+        "9213qJab2HNEpMpYNBa7wHGFKKbkDn24jpANDs2huN3yi4J11ko",+        "36cb93b9ab1bdabf7fb9f2c04f1b9cc879933530ae7842398eef5a63a56800c2",+        {+            "isCompressed": false,+            "isPrivkey": true,+            "chain": "test"+        }+    ],+    [+        "9213qJab2HNEpMpYNBa7wHGFKKbkDn24jpANDs2huN3yi4J11ko",+        "36cb93b9ab1bdabf7fb9f2c04f1b9cc879933530ae7842398eef5a63a56800c2",+        {+            "isCompressed": false,+            "isPrivkey": true,+            "chain": "regtest"+        }+    ],+    [+        "cTpB4YiyKiBcPxnefsDpbnDxFDffjqJob8wGCEDXxgQ7zQoMXJdH",+        "b9f4892c9e8282028fea1d2667c4dc5213564d41fc5783896a0d843fc15089f3",+        {+            "isCompressed": true,+            "isPrivkey": true,+            "chain": "test"+        }+    ],+    [+        "cTpB4YiyKiBcPxnefsDpbnDxFDffjqJob8wGCEDXxgQ7zQoMXJdH",+        "b9f4892c9e8282028fea1d2667c4dc5213564d41fc5783896a0d843fc15089f3",+        {+            "isCompressed": true,+            "isPrivkey": true,+            "chain": "regtest"+        }+    ],+    [+        "1Ax4gZtb7gAit2TivwejZHYtNNLT18PUXJ",+        "76a9146d23156cbbdcc82a5a47eee4c2c7c583c18b6bf488ac",+        {+            "isPrivkey": false,+            "chain": "main"+        }+    ],+    [+        "3QjYXhTkvuj8qPaXHTTWb5wjXhdsLAAWVy",+        "a914fcc5460dd6e2487c7d75b1963625da0e8f4c597587",+        {+            "isPrivkey": false,+            "chain": "main"+        }+    ],+    [+        "n3ZddxzLvAY9o7184TB4c6FJasAybsw4HZ",+        "76a914f1d470f9b02370fdec2e6b708b08ac431bf7a5f788ac",+        {+            "isPrivkey": false,+            "chain": "test"+        }+    ],+    [+        "2NBFNJTktNa7GZusGbDbGKRZTxdK9VVez3n",+        "a914c579342c2c4c9220205e2cdc285617040c924a0a87",+        {+            "isPrivkey": false,+            "chain": "test"+        }+    ],+    [+        "5K494XZwps2bGyeL71pWid4noiSNA2cfCibrvRWqcHSptoFn7rc",+        "a326b95ebae30164217d7a7f57d72ab2b54e3be64928a19da0210b9568d4015e",+        {+            "isCompressed": false,+            "isPrivkey": true,+            "chain": "main"+        }+    ],+    [+        "L1RrrnXkcKut5DEMwtDthjwRcTTwED36thyL1DebVrKuwvohjMNi",+        "7d998b45c219a1e38e99e7cbd312ef67f77a455a9b50c730c27f02c6f730dfb4",+        {+            "isCompressed": true,+            "isPrivkey": true,+            "chain": "main"+        }+    ],+    [+        "93DVKyFYwSN6wEo3E2fCrFPUp17FtrtNi2Lf7n4G3garFb16CRj",+        "d6bca256b5abc5602ec2e1c121a08b0da2556587430bcf7e1898af2224885203",+        {+            "isCompressed": false,+            "isPrivkey": true,+            "chain": "test"+        }+    ],+    [+        "cTDVKtMGVYWTHCb1AFjmVbEbWjvKpKqKgMaR3QJxToMSQAhmCeTN",+        "a81ca4e8f90181ec4b61b6a7eb998af17b2cb04de8a03b504b9e34c4c61db7d9",+        {+            "isCompressed": true,+            "isPrivkey": true,+            "chain": "test"+        }+    ],+    [+        "1C5bSj1iEGUgSTbziymG7Cn18ENQuT36vv",+        "76a9147987ccaa53d02c8873487ef919677cd3db7a691288ac",+        {+            "isPrivkey": false,+            "chain": "main"+        }+    ],+    [+        "3AnNxabYGoTxYiTEZwFEnerUoeFXK2Zoks",+        "a91463bcc565f9e68ee0189dd5cc67f1b0e5f02f45cb87",+        {+            "isPrivkey": false,+            "chain": "main"+        }+    ],+    [+        "n3LnJXCqbPjghuVs8ph9CYsAe4Sh4j97wk",+        "76a914ef66444b5b17f14e8fae6e7e19b045a78c54fd7988ac",+        {+            "isPrivkey": false,+            "chain": "test"+        }+    ],+    [+        "2NB72XtkjpnATMggui83aEtPawyyKvnbX2o",+        "a914c3e55fceceaa4391ed2a9677f4a4d34eacd021a087",+        {+            "isPrivkey": false,+            "chain": "test"+        }+    ],+    [+        "5KaBW9vNtWNhc3ZEDyNCiXLPdVPHCikRxSBWwV9NrpLLa4LsXi9",+        "e75d936d56377f432f404aabb406601f892fd49da90eb6ac558a733c93b47252",+        {+            "isCompressed": false,+            "isPrivkey": true,+            "chain": "main"+        }+    ],+    [+        "L1axzbSyynNYA8mCAhzxkipKkfHtAXYF4YQnhSKcLV8YXA874fgT",+        "8248bd0375f2f75d7e274ae544fb920f51784480866b102384190b1addfbaa5c",+        {+            "isCompressed": true,+            "isPrivkey": true,+            "chain": "main"+        }+    ],+    [+        "927CnUkUbasYtDwYwVn2j8GdTuACNnKkjZ1rpZd2yBB1CLcnXpo",+        "44c4f6a096eac5238291a94cc24c01e3b19b8d8cef72874a079e00a242237a52",+        {+            "isCompressed": false,+            "isPrivkey": true,+            "chain": "test"+        }+    ],+    [+        "cUcfCMRjiQf85YMzzQEk9d1s5A4K7xL5SmBCLrezqXFuTVefyhY7",+        "d1de707020a9059d6d3abaf85e17967c6555151143db13dbb06db78df0f15c69",+        {+            "isCompressed": true,+            "isPrivkey": true,+            "chain": "test"+        }+    ],+    [+        "1Gqk4Tv79P91Cc1STQtU3s1W6277M2CVWu",+        "76a914adc1cc2081a27206fae25792f28bbc55b831549d88ac",+        {+            "isPrivkey": false,+            "chain": "main"+        }+    ],+    [+        "33vt8ViH5jsr115AGkW6cEmEz9MpvJSwDk",+        "a914188f91a931947eddd7432d6e614387e32b24470987",+        {+            "isPrivkey": false,+            "chain": "main"+        }+    ],+    [+        "mhaMcBxNh5cqXm4aTQ6EcVbKtfL6LGyK2H",+        "76a9141694f5bc1a7295b600f40018a618a6ea48eeb49888ac",+        {+            "isPrivkey": false,+            "chain": "test"+        }+    ],+    [+        "2MxgPqX1iThW3oZVk9KoFcE5M4JpiETssVN",+        "a9143b9b3fd7a50d4f08d1a5b0f62f644fa7115ae2f387",+        {+            "isPrivkey": false,+            "chain": "test"+        }+    ],+    [+        "5HtH6GdcwCJA4ggWEL1B3jzBBUB8HPiBi9SBc5h9i4Wk4PSeApR",+        "091035445ef105fa1bb125eccfb1882f3fe69592265956ade751fd095033d8d0",+        {+            "isCompressed": false,+            "isPrivkey": true,+            "chain": "main"+        }+    ],+    [+        "L2xSYmMeVo3Zek3ZTsv9xUrXVAmrWxJ8Ua4cw8pkfbQhcEFhkXT8",+        "ab2b4bcdfc91d34dee0ae2a8c6b6668dadaeb3a88b9859743156f462325187af",+        {+            "isCompressed": true,+            "isPrivkey": true,+            "chain": "main"+        }+    ],+    [+        "92xFEve1Z9N8Z641KQQS7ByCSb8kGjsDzw6fAmjHN1LZGKQXyMq",+        "b4204389cef18bbe2b353623cbf93e8678fbc92a475b664ae98ed594e6cf0856",+        {+            "isCompressed": false,+            "isPrivkey": true,+            "chain": "test"+        }+    ],+    [+        "92xFEve1Z9N8Z641KQQS7ByCSb8kGjsDzw6fAmjHN1LZGKQXyMq",+        "b4204389cef18bbe2b353623cbf93e8678fbc92a475b664ae98ed594e6cf0856",+        {+            "isCompressed": false,+            "isPrivkey": true,+            "chain": "regtest"+        }+    ],+    [+        "cVM65tdYu1YK37tNoAyGoJTR13VBYFva1vg9FLuPAsJijGvG6NEA",+        "e7b230133f1b5489843260236b06edca25f66adb1be455fbd38d4010d48faeef",+        {+            "isCompressed": true,+            "isPrivkey": true,+            "chain": "test"+        }+    ],+    [+        "1JwMWBVLtiqtscbaRHai4pqHokhFCbtoB4",+        "76a914c4c1b72491ede1eedaca00618407ee0b772cad0d88ac",+        {+            "isPrivkey": false,+            "chain": "main"+        }+    ],+    [+        "3QCzvfL4ZRvmJFiWWBVwxfdaNBT8EtxB5y",+        "a914f6fe69bcb548a829cce4c57bf6fff8af3a5981f987",+        {+            "isPrivkey": false,+            "chain": "main"+        }+    ],+    [+        "mizXiucXRCsEriQCHUkCqef9ph9qtPbZZ6",+        "76a914261f83568a098a8638844bd7aeca039d5f2352c088ac",+        {+            "isPrivkey": false,+            "chain": "test"+        }+    ],+    [+        "2NEWDzHWwY5ZZp8CQWbB7ouNMLqCia6YRda",+        "a914e930e1834a4d234702773951d627cce82fbb5d2e87",+        {+            "isPrivkey": false,+            "chain": "test"+        }+    ],+    [+        "5KQmDryMNDcisTzRp3zEq9e4awRmJrEVU1j5vFRTKpRNYPqYrMg",+        "d1fab7ab7385ad26872237f1eb9789aa25cc986bacc695e07ac571d6cdac8bc0",+        {+            "isCompressed": false,+            "isPrivkey": true,+            "chain": "main"+        }+    ],+    [+        "L39Fy7AC2Hhj95gh3Yb2AU5YHh1mQSAHgpNixvm27poizcJyLtUi",+        "b0bbede33ef254e8376aceb1510253fc3550efd0fcf84dcd0c9998b288f166b3",+        {+            "isCompressed": true,+            "isPrivkey": true,+            "chain": "main"+        }+    ],+    [+        "91cTVUcgydqyZLgaANpf1fvL55FH53QMm4BsnCADVNYuWuqdVys",+        "037f4192c630f399d9271e26c575269b1d15be553ea1a7217f0cb8513cef41cb",+        {+            "isCompressed": false,+            "isPrivkey": true,+            "chain": "test"+        }+    ],+    [+        "cQspfSzsgLeiJGB2u8vrAiWpCU4MxUT6JseWo2SjXy4Qbzn2fwDw",+        "6251e205e8ad508bab5596bee086ef16cd4b239e0cc0c5d7c4e6035441e7d5de",+        {+            "isCompressed": true,+            "isPrivkey": true,+            "chain": "test"+        }+    ],+    [+        "19dcawoKcZdQz365WpXWMhX6QCUpR9SY4r",+        "76a9145eadaf9bb7121f0f192561a5a62f5e5f5421029288ac",+        {+            "isPrivkey": false,+            "chain": "main"+        }+    ],+    [+        "37Sp6Rv3y4kVd1nQ1JV5pfqXccHNyZm1x3",+        "a9143f210e7277c899c3a155cc1c90f4106cbddeec6e87",+        {+            "isPrivkey": false,+            "chain": "main"+        }+    ],+    [+        "myoqcgYiehufrsnnkqdqbp69dddVDMopJu",+        "76a914c8a3c2a09a298592c3e180f02487cd91ba3400b588ac",+        {+            "isPrivkey": false,+            "chain": "test"+        }+    ],+    [+        "2N7FuwuUuoTBrDFdrAZ9KxBmtqMLxce9i1C",+        "a91499b31df7c9068d1481b596578ddbb4d3bd90baeb87",+        {+            "isPrivkey": false,+            "chain": "test"+        }+    ],+    [+        "5KL6zEaMtPRXZKo1bbMq7JDjjo1bJuQcsgL33je3oY8uSJCR5b4",+        "c7666842503db6dc6ea061f092cfb9c388448629a6fe868d068c42a488b478ae",+        {+            "isCompressed": false,+            "isPrivkey": true,+            "chain": "main"+        }+    ],+    [+        "KwV9KAfwbwt51veZWNscRTeZs9CKpojyu1MsPnaKTF5kz69H1UN2",+        "07f0803fc5399e773555ab1e8939907e9badacc17ca129e67a2f5f2ff84351dd",+        {+            "isCompressed": true,+            "isPrivkey": true,+            "chain": "main"+        }+    ],+    [+        "93N87D6uxSBzwXvpokpzg8FFmfQPmvX4xHoWQe3pLdYpbiwT5YV",+        "ea577acfb5d1d14d3b7b195c321566f12f87d2b77ea3a53f68df7ebf8604a801",+        {+            "isCompressed": false,+            "isPrivkey": true,+            "chain": "test"+        }+    ],+    [+        "cMxXusSihaX58wpJ3tNuuUcZEQGt6DKJ1wEpxys88FFaQCYjku9h",+        "0b3b34f0958d8a268193a9814da92c3e8b58b4a4378a542863e34ac289cd830c",+        {+            "isCompressed": true,+            "isPrivkey": true,+            "chain": "test"+        }+    ],+    [+        "13p1ijLwsnrcuyqcTvJXkq2ASdXqcnEBLE",+        "76a9141ed467017f043e91ed4c44b4e8dd674db211c4e688ac",+        {+            "isPrivkey": false,+            "chain": "main"+        }+    ],+    [+        "3ALJH9Y951VCGcVZYAdpA3KchoP9McEj1G",+        "a9145ece0cadddc415b1980f001785947120acdb36fc87",+        {+            "isPrivkey": false,+            "chain": "main"+        }+    ],+    [+        "bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t4",+        "0014751e76e8199196d454941c45d1b3a323f1433bd6",+        {+            "isPrivkey": false,+            "chain": "main",+            "tryCaseFlip": true+        }+    ],+    [+        "bcrt1qw508d6qejxtdg4y5r3zarvary0c5xw7kygt080",+        "0014751e76e8199196d454941c45d1b3a323f1433bd6",+        {+            "isPrivkey": false,+            "chain": "regtest",+            "tryCaseFlip": true+        }+    ],+    [+        "tb1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3q0sl5k7",+        "00201863143c14c5166804bd19203356da136c985678cd4d27a1b8c6329604903262",+        {+            "isPrivkey": false,+            "chain": "test",+            "tryCaseFlip": true+        }+    ],+    [+        "bc1pw508d6qejxtdg4y5r3zarvary0c5xw7kw508d6qejxtdg4y5r3zarvary0c5xw7k7grplx",+        "5128751e76e8199196d454941c45d1b3a323f1433bd6751e76e8199196d454941c45d1b3a323f1433bd6",+        {+            "isPrivkey": false,+            "chain": "main",+            "tryCaseFlip": true,+            "disabled": true+        }+    ],+    [+        "bc1sw50qa3jx3s",+        "6002751e",+        {+            "isPrivkey": false,+            "chain": "main",+            "tryCaseFlip": true,+            "disabled": true+        }+    ],+    [+        "bc1zw508d6qejxtdg4y5r3zarvaryvg6kdaj",+        "5210751e76e8199196d454941c45d1b3a323",+        {+            "isPrivkey": false,+            "chain": "main",+            "tryCaseFlip": true,+            "disabled": true+        }+    ],+    [+        "tb1qqqqqp399et2xygdj5xreqhjjvcmzhxw4aywxecjdzew6hylgvsesrxh6hy",+        "0020000000c4a5cad46221b2a187905e5266362b99d5e91c6ce24d165dab93e86433",+        {+            "isPrivkey": false,+            "chain": "test",+            "tryCaseFlip": true+        }+    ],+    [+        "bcrt1qqqqqp399et2xygdj5xreqhjjvcmzhxw4aywxecjdzew6hylgvseswlauz7",+        "0020000000c4a5cad46221b2a187905e5266362b99d5e91c6ce24d165dab93e86433",+        {+            "isPrivkey": false,+            "chain": "regtest",+            "tryCaseFlip": true+        }+    ]+]
+ data/rfc6979DERabc.json view
@@ -0,0 +1,102 @@+[+    [+        "0000000000000000000000000000000000000000000000000000000000000001",+        "Absence makes the heart grow fonder.",+        "304402206c0db71422a66840f238b55635dc87d013a77caebb2057713e14928abe0d0ce602207f687dedcd60e4a8feb3ef31450ad8e42730d909dd19b5237a5eaa4bf50c0741"+    ],+    [+        "0000000000000000000000000000000000000000000000000000000000000002",+        "Actions speak louder than words.",+        "3045022100912705043b888d052c35a2d9736dde7f29c453cb6b2c355fa1b1a1328a1d23170220021ede2707be213c7d489720af88c43f6eb86c47835e7d6ff61cbe91ebec288a"+    ],+    [+        "0000000000000000000000000000000000000000000000000000000000000003",+        "All for one and one for all.",+        "3044022055bffc0d939ae7f8209dea0ae77f5b4905818201a4c2ca7f06a302ea56258186022079cfc2f2b5ce08e0a8f3f1082366f509783bceb2c4a05819a715724d68bbe7c0"+    ],+    [+        "0000000000000000000000000000000000000000000000000000000000000004",+        "All's fair in love and war.",+        "3045022100e1ea024069bd02f1332fafdbd12f50103e0438cbce1e32517c9932c1e043c902022078f4408e6851f25e8fdc91f82a920cf4ce400554f236d810c499886f97c9500b"+    ],+    [+        "0000000000000000000000000000000000000000000000000000000000000005",+        "All work and no play makes Jack a dull boy.",+        "3045022100824b35db88c1600747a3d9fe3d40d1400c6b8c3527c91d3bdb22b317bdf4dfd60220793025386e2de4289b3f0e135121f20088e1d0e0cb5bbf366561dffc9d17c0d4"+    ],+    [+        "0000000000000000000000000000000000000000000000000000000000000006",+        "All's well that ends well.",+        "3045022100f3a3f37b80880a5b1ac2a3fcde9a86aae7036e8576f1ce28ab2849155237de63022027ef8c5e61c42a86fe13953d57aea273f797828f22df686bbdbc5601a7cdf49a"+    ],+    [+        "0000000000000000000000000000000000000000000000000000000000000007",+        "An apple a day keeps the doctor away.",+        "3045022100e8f392a1657ec6fdf747ea8ff5a6dbeec7e932975c0c2f9430b9f6b7e3120018022064dd010aba1522d1ae16219e425225e9508c34a00d3e5d7327336391fc3e0cac"+    ],+    [+        "0000000000000000000000000000000000000000000000000000000000000008",+        "An apple never falls far from the tree.",+        "3045022100ba82ea8d785a951ce33dcf65379abfd1e3d1affa4557870c1d931bad119e3fde022070d86f0cdb023fd40c365d9caab1351900371166a72f55315e661486ed769753"+    ],+    [+        "0000000000000000000000000000000000000000000000000000000000000009",+        "An ounce of prevention is worth a pound of cure.",+        "30450221009d898ae395ed916e3b58f3f9e08019c65be8bcdc1634581891c30f7873de2570022048c7c244ceef3c3a6a6cd34119dc07ad54b8f8d50273629ac20fadd580241a92"+    ],+    [+        "000000000000000000000000000000000000000000000000000000000000000a",+        "Appearances can be deceiving.",+        "304402206a75d44757c6ae076d8dce8ea79dfde47765f02659e0ccb6e9e3f675c6d0013602200345ff627949d08d6d02ba1d43d07e89fd74c54d250f212b6d9e1e227887cce2"+    ],+    [+        "4bf5122f344554c53bde2ebb8cd2b7e3d1600ad631c385a5d7cce23c7785459a",+        "Absence makes the heart grow fonder.",+        "3044022001e95d38c5d65344800d9d87de5c2d4319674adf6d248bb59113d42d18bdb97502200d5afe847651e64a358e65ba16cca9d1e02eac371cfa8e1206cd3dceb438f9d1"+    ],+    [+        "dbc1b4c900ffe48d575b5da5c638040125f65db0fe3e24494b76ea986457d986",+        "Actions speak louder than words.",+        "30440220771a29e95d6e9e4c1b05b3cb7853ebc1057a9f68133fcc34190c4ba237e40b99022046067aff0918c18a3b3822c937921905ef22bf10c9f59d806ccfb23f7fcaa1ac"+    ],+    [+        "084fed08b978af4d7d196a7446a86b58009e636b611db16211b65a9aadff29c5",+        "All for one and one for all.",+        "3045022100822eb70daf001ed5b8a9ccd9e2fa849918148bdd5d2cdf3fb5797be0fa82fec0022060d43b32e6c86804d351dfe863135d8391f10442552dd59b75f2cbc3894f7277"+    ],+    [+        "e52d9c508c502347344d8c07ad91cbd6068afc75ff6292f062a09ca381c89e71",+        "All's fair in love and war.",+        "30440220264b1220e15eb1256bdac36512687aa37e059bb3b177bbf42f19a75cb95a9710022040928fcc170203596bb449f4d745b49f75b76d013a5c0d70af3f6eefa9af94d6"+    ],+    [+        "e77b9a9ae9e30b0dbdb6f510a264ef9de781501d7b6b92ae89eb059c5ab743db",+        "All work and no play makes Jack a dull boy.",+        "304402203b96a2ea837df2aba4e94be5167ce9bcb1f00c2a6c6698f4ff340b7a9379dd5f0220051222212a9a4d1886acfac0594ae8f98db354448c8aa626d34ee7d4abb83d4c"+    ],+    [+        "67586e98fad27da0b9968bc039a1ef34c939b9b8e523a8bef89d478608c5ecf6",+        "All's well that ends well.",+        "30450221009d6297db8a9446e376d45cc816ea9172d6a6db715680928dc0ead4f2f0fbbdfc02207df1a6c9e7a23c9baee9b2833d8dd18ea6ed33f7f7d653a1a29e75ead07ce143"+    ],+    [+        "ca358758f6d27e6cf45272937977a748fd88391db679ceda7dc7bf1f005ee879",+        "An apple a day keeps the doctor away.",+        "304402202e58d297a0d452ae6afc3cc8f3bfc4ff1a10c76c3f71ff1062564f196d4038f3022073f77ea431bd2b95a0e226eccb2fd4680b71a2ee6ba46a6b25d54db5a928f4ce"+    ],+    [+        "beead77994cf573341ec17b58bbf7eb34d2711c993c1d976b128b3188dc1829a",+        "An apple never falls far from the tree.",+        "304402204997ddbdb33574552d938e84378f29c3bb24a32e7a32e467315dd841fa278a040220198c27facdf3ac10b59cdc97ab269df337268d5a61527f41966f0ff876ac00df"+    ],+    [+        "2b4c342f5433ebe591a1da77e013d1b72475562d48578dca8b84bac6651c3cb9",+        "An ounce of prevention is worth a pound of cure.",+        "304402202803b367eacdff2a0ee8727108f43efc864519d0fc972e42a5e4f3f2221b6f880220632003636d7293672003650babc3a589e35be93b98dabf20dead8e70085fa8a8"+    ],+    [+        "01ba4719c80b6fe911b091a7c05124b64eeece964e09c058ef8f9805daca546b",+        "Appearances can be deceiving.",+        "30440220033aef6b3a2cea67a19d91130ee2736652588a21fdca9520ed778ca2d30e343d02206f0be9db4ebfc474470c4d164a67479e232f20e57f8659bc5b404520b665765d"+    ]+]
+ data/rfc6979DERcore.json view
@@ -0,0 +1,102 @@+[+    [+        "0000000000000000000000000000000000000000000000000000000000000001",+        "Absence makes the heart grow fonder.",+        "3045022100afff580595971b8c1700e77069d73602aef4c2a760dbd697881423dfff845de80220579adb6a1ac03acde461b5821a049ebd39a8a8ebf2506b841b15c27342d2e342"+    ],+    [+        "0000000000000000000000000000000000000000000000000000000000000002",+        "Actions speak louder than words.",+        "304502210085f28bbc90975b1907a51cbfe7bf0dc1ac74ade49318ee97498dbbde3894a31c0220241d24da8d263e7af7ff49bca6a7a850f0e087faf6fef44f85851b0283c3f026"+    ],+    [+        "0000000000000000000000000000000000000000000000000000000000000003",+        "All for one and one for all.",+        "30440220502c6ac38e1c68ce68f044f5ab680f2880a6c1cd34e70f2b4f945c6fd30abd03022018ef5c6c3392b9d67ad5109c85476a0e159425d7f6ace2cebeaa65f02f210bbb"+    ],+    [+        "0000000000000000000000000000000000000000000000000000000000000004",+        "All's fair in love and war.",+        "30440220452d4ab234891cf6e5432cd5472bdca1cfc6fb28563333885f068da02ee216d8022056c368d16a64d29cff92f17203d926e113064527af0480d3bcc1d3fadfde9364"+    ],+    [+        "0000000000000000000000000000000000000000000000000000000000000005",+        "All work and no play makes Jack a dull boy.",+        "3045022100995025b4880eeb1ecedba945fe8c9b2ddf2b07dbc293c2586c079d7b663ef38a022022fb54ab95014616d014277e05c97a7ed9e22596a0420bbd2d749ca9a2f876fe"+    ],+    [+        "0000000000000000000000000000000000000000000000000000000000000006",+        "All's well that ends well.",+        "3045022100a9c1593fa6459777b2eba6d7e2a206e3bb119e85b2163973cf28ffaf24ec381c02202f166f13230b3853b928efb649d30375ec6a4b1a64a8d56fbcc0a9d86a0943e9"+    ],+    [+        "0000000000000000000000000000000000000000000000000000000000000007",+        "An apple a day keeps the doctor away.",+        "304402202fc9c8b749621241c33fd51b57fc5140c1d7fc1594f91b073953e79da2f5e8f60220345e4ea7693b5069c0251771ea476cbe236586ed24b90aeeea7b7c2814edf477"+    ],+    [+        "0000000000000000000000000000000000000000000000000000000000000008",+        "An apple never falls far from the tree.",+        "3044022052b6e2c49a6f6adbe52fb6bbe744caa3f49364085db118eab8670bc766be160302207d96a42866637ca3d4caf36e597a460eb305adac0220b027410c821a7191a1c4"+    ],+    [+        "0000000000000000000000000000000000000000000000000000000000000009",+        "An ounce of prevention is worth a pound of cure.",+        "3045022100be53e7c00788e4417083d7511800f18c7c6f5f259de39bc6f8b1bebcd5056bd002201f389e13cfe7d1dbd8d2d1bff18138219f57de166673762009686a28fbc44df6"+    ],+    [+        "000000000000000000000000000000000000000000000000000000000000000a",+        "Appearances can be deceiving.",+        "304402202f2413a1673f642c30ea2e23fcae45776bc77a94f96920aea3c14303b1469428022053ac3e8ea0a488e9159d56e429a51f207bf04e462f8d4ba2c69b1b1635f30217"+    ],+    [+        "4bf5122f344554c53bde2ebb8cd2b7e3d1600ad631c385a5d7cce23c7785459a",+        "Absence makes the heart grow fonder.",+        "3045022100996d79fba54b24e9394fc5fab6bf94d173f3752645075de6e32574fe08625f770220345e638b373dcb0ce0c09e5799695ef64ffc5e01dd8367b9a205ce25f28870f6"+    ],+    [+        "dbc1b4c900ffe48d575b5da5c638040125f65db0fe3e24494b76ea986457d986",+        "Actions speak louder than words.",+        "304502210088164430985a4437471417c2386faa536e1fe8ec91bd0f1f642bc22a776891530220090dc83d6e3b54a1a54dc2e79c693144179a512d9c9e686a6c25e7641a2101a8"+    ],+    [+        "084fed08b978af4d7d196a7446a86b58009e636b611db16211b65a9aadff29c5",+        "All for one and one for all.",+        "30450221009f1073c9c09b664498d4b216983330b01c29a0fb55dd61aa145b4ebd0579905502204592fb6626f672d4f3ad4bb2d0a1ed6c2a161cc35c6bb77e6f0fd3b63feab36f"+    ],+    [+        "e52d9c508c502347344d8c07ad91cbd6068afc75ff6292f062a09ca381c89e71",+        "All's fair in love and war.",+        "304502210080eabf24117b492635043886e7229b9705b970cbb6828c4e03a39dae7ac34bda022070e8a32ca1df82add53facbd58b4f2d3984d0a17b6b13c44460238d9ff74e41f"+    ],+    [+        "e77b9a9ae9e30b0dbdb6f510a264ef9de781501d7b6b92ae89eb059c5ab743db",+        "All work and no play makes Jack a dull boy.",+        "3045022100a43ff5edea7ea0b9716d4359574e990a6859cdaeb9d7d6b4964afd40be11bd35022067f9d82e22fc447a122997335525f117f37b141c3efa9f8c6d77b586753f962f"+    ],+    [+        "67586e98fad27da0b9968bc039a1ef34c939b9b8e523a8bef89d478608c5ecf6",+        "All's well that ends well.",+        "3044022053ce16251f4fae7eb87e2ab040a6f334e08687fb445566256cd217ece389e0440220576506a168cbc9ee0dd485d6c418961e7a0861b0f05d22a93401812978d0b215"+    ],+    [+        "ca358758f6d27e6cf45272937977a748fd88391db679ceda7dc7bf1f005ee879",+        "An apple a day keeps the doctor away.",+        "3045022100df8744cc06a304b041e88149acfd84a68d8f4a2a4047056644e1ec8357e11ebe02204ba2d5499a26d072c797a86c7851533f287ceb8b818cae2c5d4483c37c62750c"+    ],+    [+        "beead77994cf573341ec17b58bbf7eb34d2711c993c1d976b128b3188dc1829a",+        "An apple never falls far from the tree.",+        "3045022100878372d211ed0dbde1273ae3dd85aec577c08a06a55960f2e274f97cc9f2f38f02203f992caa66f472a64f6ccdd8076c0a12202c674155a6a61b8cd23c1ded08aab7"+    ],+    [+        "2b4c342f5433ebe591a1da77e013d1b72475562d48578dca8b84bac6651c3cb9",+        "An ounce of prevention is worth a pound of cure.",+        "3045022100d5cb4e148c0a29ce37f1542be416e8ef575da522666b19b541960d726c99662b022045c951c1ca938c90dad6c3eede7c5df67fcf0d14f90faf201e8d215f215c5c18"+    ],+    [+        "01ba4719c80b6fe911b091a7c05124b64eeece964e09c058ef8f9805daca546b",+        "Appearances can be deceiving.",+        "304402203e2f0118062306e2239c873828a7275dd35545a143797e224148c5bbbd59dd08022073a8c9e17be75c66362913b5e05d81fd619b434edda766fae6c352e86987809d"+    ]+]
+ data/rfc6979abc.json view
@@ -0,0 +1,62 @@+[+    [+        "0000000000000000000000000000000000000000000000000000000000000001",+        "Satoshi Nakamoto",+        "cd7a225c6661e35a85f309a66ba9fbcd134487b80ae1d8a3c58d85015ac1f7ed046b573d040c8324ecf796d6b86732fdfd8938888fd8a28309e476732475a743"+    ],+    [+        "0000000000000000000000000000000000000000000000000000000000000001",+        "All those moments will be lost in time, like tears in rain. Time to die...",+        "fb073d886dda0444913a3f1fa32d5b2bc35d09420672b6e7e8e36c530422c98f114230b9362ba6985ccb0d87b86c752e597fa3ca46f1c0abe226a9496187588c"+    ],+    [+        "fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364140",+        "Satoshi Nakamoto",+        "20d0306cd55957786c6dedae03c2dc85cea8030de04ec6ba027cffe8b1be37d15f46f9282a7117c4179f54d00c944b4ce04b51e118cfddcdc73d72d5b5923933"+    ],+    [+        "f8b8af8ce3c7cca5e300d33939540c10d45ce001b8f252bfbc57ba0342904181",+        "Alan Turing",+        "b27049b4834f874e41a4b6c586ed6aa1d86dba5ef411bd2a149161e39287ab4247ad691e06358323d6bbb16589ac186c63393c694bf75914c4a29ee56675c740"+    ],+    [+        "e91671c46231f833a6406ccbea0e3e392c76c167bac1cb013f6f1013980455c2",+        "There is a computer disease that anybody who works with computers knows about. It's a very serious disease and it interferes completely with the work. The trouble with computers is that you 'play' with them!",+        "08438a0a59cb5c1f3de6a0c3c4852282472b9286ff6427f65dc8af31b6bdd41b300ad6ef64cf7d2f6ce7109d134d1c542c61430d4d3d1e404f4fd2634a0da0ad"+    ],+    [+        "0000000000000000000000000000000000000000000000000000000000000001",+        "Everything should be made as simple as possible, but not simpler.",+        "53452b2fbb94b30051ab0e7075c1e613685079cc5244c36aa7b9148521a04b87268579ff46388ff7ceb7d5a691fcc995cd62d596603fffff6013eaaef3ec1f65"+    ],+    [+        "fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364140",+        "Equations are more important to me, because politics is for the present, but an equation is something for eternity.",+        "fb904bd574f61510463e4e6593be29aa59de55f1dc31d3075920ac9ca7ef55997afa037dc9192877bf13ecf5458966bb92abd3328247b32425ab21d8b8a0d767"+    ],+    [+        "fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364140",+        "Not only is the Universe stranger than we think, it is stranger than we can think.",+        "402f863e862bdfabfa9444e1370f4163a8f61a5f3e16b56ce639d3c373d0ad551aea2bdfb410f1f327737f7fa28646338876f4097b86c1204952e8f1733989d7"+    ],+    [+        "0000000000000000000000000000000000000000000000000000000000000001",+        "How wonderful that we have met with a paradox. Now we have some hope of making progress.",+        "efdff52e87f77261f1aa07c7938e346547b712d3892a0ef6380cfff46198588b17efea735778bc04bae52cec6617b85537dc913f1423f21fd97860405ad78aee"+    ],+    [+        "69ec59eaa1f4f2e36b639716b7c30ca86d9a5375c7b38d8918bd9c0ebc80ba64",+        "Computer science is no more about computers than astronomy is about telescopes.",+        "d270a8604b11ec88a4e95cc1e4006f88452d5faf71dfd3f6d561d130a52903f93a6e9662a0fdf9f05ee5da5ba9fc437c97cf894a17844ccfb19d708942b72324"+    ],+    [+        "00000000000000000000000000007246174ab1e92e9149c6e446fe194d072637",+        "...if you aren't, at any given time, scandalized by code you wrote five or even three years ago, you're not learning anywhere near enough",+        "c0b51457714f4786e0f1d38219bfa124e06cbfff8b0c74c1a0ab11dff80b3a1b207aefdd3ac67158746b0ffad2be589a8f816296012b394302ab8a514aaeb120"+    ],+    [+        "000000000000000000000000000000000000000000056916d0f9b31dc9b637f3",+        "The question of whether computers can think is like the question of whether submarines can swim.",+        "fdcc51599f0b25a48f4b1f3701c153d840d49414b77d582b73bc0a93a3d2fe0c5770d55329857e5e1095545f911881447feccdde067faac1338c7f48a0355407"+    ]+]
+ data/rfc6979core.json view
@@ -0,0 +1,62 @@+[+    [+        "0000000000000000000000000000000000000000000000000000000000000001",+        "Satoshi Nakamoto",+        "934b1ea10a4b3c1757e2b0c017d0b6143ce3c9a7e6a4a49860d7a6ab210ee3d82442ce9d2b916064108014783e923ec36b49743e2ffa1c4496f01a512aafd9e5"+    ],+    [+        "0000000000000000000000000000000000000000000000000000000000000001",+        "All those moments will be lost in time, like tears in rain. Time to die...",+        "8600dbd41e348fe5c9465ab92d23e3db8b98b873beecd930736488696438cb6b547fe64427496db33bf66019dacbf0039c04199abb0122918601db38a72cfc21"+    ],+    [+        "fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364140",+        "Satoshi Nakamoto",+        "fd567d121db66e382991534ada77a6bd3106f0a1098c231e47993447cd6af2d06b39cd0eb1bc8603e159ef5c20a5c8ad685a45b06ce9bebed3f153d10d93bed5"+    ],+    [+        "f8b8af8ce3c7cca5e300d33939540c10d45ce001b8f252bfbc57ba0342904181",+        "Alan Turing",+        "7063ae83e7f62bbb171798131b4a0564b956930092b33b07b395615d9ec7e15c58dfcc1e00a35e1572f366ffe34ba0fc47db1e7189759b9fb233c5b05ab388ea"+    ],+    [+        "e91671c46231f833a6406ccbea0e3e392c76c167bac1cb013f6f1013980455c2",+        "There is a computer disease that anybody who works with computers knows about. It's a very serious disease and it interferes completely with the work. The trouble with computers is that you 'play' with them!",+        "b552edd27580141f3b2a5463048cb7cd3e047b97c9f98076c32dbdf85a68718b279fa72dd19bfae05577e06c7c0c1900c371fcd5893f7e1d56a37d30174671f6"+    ],+    [+        "0000000000000000000000000000000000000000000000000000000000000001",+        "Everything should be made as simple as possible, but not simpler.",+        "33a69cd2065432a30f3d1ce4eb0d59b8ab58c74f27c41a7fdb5696ad4e6108c96f807982866f785d3f6418d24163ddae117b7db4d5fdf0071de069fa54342262"+    ],+    [+        "fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364140",+        "Equations are more important to me, because politics is for the present, but an equation is something for eternity.",+        "54c4a33c6423d689378f160a7ff8b61330444abb58fb470f96ea16d99d4a2fed07082304410efa6b2943111b6a4e0aaa7b7db55a07e9861d1fb3cb1f421044a5"+    ],+    [+        "fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364140",+        "Not only is the Universe stranger than we think, it is stranger than we can think.",+        "ff466a9f1b7b273e2f4c3ffe032eb2e814121ed18ef84665d0f515360dab3dd06fc95f5132e5ecfdc8e5e6e616cc77151455d46ed48f5589b7db7771a332b283"+    ],+    [+        "0000000000000000000000000000000000000000000000000000000000000001",+        "How wonderful that we have met with a paradox. Now we have some hope of making progress.",+        "c0dafec8251f1d5010289d210232220b03202cba34ec11fec58b3e93a85b91d375afdc06b7d6322a590955bf264e7aaa155847f614d80078a90292fe205064d3"+    ],+    [+        "69ec59eaa1f4f2e36b639716b7c30ca86d9a5375c7b38d8918bd9c0ebc80ba64",+        "Computer science is no more about computers than astronomy is about telescopes.",+        "7186363571d65e084e7f02b0b77c3ec44fb1b257dee26274c38c928986fea45d0de0b38e06807e46bda1f1e293f4f6323e854c86d58abdd00c46c16441085df6"+    ],+    [+        "00000000000000000000000000007246174ab1e92e9149c6e446fe194d072637",+        "...if you aren't, at any given time, scandalized by code you wrote five or even three years ago, you're not learning anywhere near enough",+        "fbfe5076a15860ba8ed00e75e9bd22e05d230f02a936b653eb55b61c99dda4870e68880ebb0050fe4312b1b1eb0899e1b82da89baa5b895f612619edf34cbd37"+    ],+    [+        "000000000000000000000000000000000000000000056916d0f9b31dc9b637f3",+        "The question of whether computers can think is like the question of whether submarines can swim.",+        "cde1302d83f8dd835d89aef803c74a119f561fbaef3eb9129e45f30de86abbf906ce643f5049ee1f27890467b77a6a8e11ec4661cc38cd8badf90115fbd03cef"+    ]+]
haskoin-core.cabal view
@@ -4,10 +4,10 @@ -- -- see: https://github.com/sol/hpack ----- hash: 26dbdf73274ee98d645964af8eced9a7fa589a0e625153f6056626fc0d48a7cd+-- hash: da33a2de954861b59726562ecc494205eab150409d75381e7e3c867546e2d48f  name:           haskoin-core-version:        0.14.1+version:        0.15.0 synopsis:       Bitcoin & Bitcoin Cash library for Haskell description:    Please see the README on GitHub at <https://github.com/haskoin/haskoin-core#readme> category:       Bitcoin, Finance, Network@@ -23,6 +23,12 @@ extra-source-files:     data/forkid_script_tests.json     data/forkid_sighash.json+    data/key_io_invalid.json+    data/key_io_valid.json+    data/rfc6979abc.json+    data/rfc6979core.json+    data/rfc6979DERabc.json+    data/rfc6979DERcore.json     data/script_tests.json     data/sig_nonstrict.json     data/sig_strict.json@@ -65,6 +71,7 @@       Haskoin.Transaction.Builder       Haskoin.Transaction.Builder.Sign       Haskoin.Transaction.Common+      Haskoin.Transaction.Genesis       Haskoin.Transaction.Partial       Haskoin.Transaction.Segwit       Haskoin.Util@@ -103,7 +110,7 @@     , network >=3.1.1.1     , safe >=0.3.18     , scientific >=0.3.6.2-    , secp256k1-haskell >=0.3.0+    , secp256k1-haskell >=0.4.0     , split >=0.2.3.3     , string-conversions >=0.4.0.1     , text >=1.2.4.0@@ -123,7 +130,6 @@       Haskoin.BlockSpec       Haskoin.Crypto.HashSpec       Haskoin.Crypto.SignatureSpec-      Haskoin.CryptoSpec       Haskoin.Keys.ExtendedSpec       Haskoin.Keys.MnemonicSpec       Haskoin.KeysSpec@@ -150,15 +156,17 @@     , deepseq >=1.4.4.0     , entropy >=0.4.1.5     , hashable >=1.3.0.0-    , haskoin-core ==0.14.1+    , haskoin-core ==0.15.0     , hspec >=2.7.1+    , lens >=4.18.1+    , lens-aeson >=1.1     , memory >=0.15.0     , mtl >=2.2.2     , murmur3 >=1.0.3     , network >=3.1.1.1     , safe >=0.3.18     , scientific >=0.3.6.2-    , secp256k1-haskell >=0.3.0+    , secp256k1-haskell >=0.4.0     , split >=0.2.3.3     , string-conversions >=0.4.0.1     , text >=1.2.4.0
src/Haskoin.hs view
@@ -2,7 +2,7 @@ Module      : Haskoin Description : Bitcoin (BTC/BCH) Libraries for Haskell Copyright   : No rights reserved-License     : UNLICENSE+License     : MIT Maintainer  : jprupp@protonmail.ch Stability   : experimental Portability : POSIX
src/Haskoin/Address.hs view
@@ -2,11 +2,12 @@ {-# LANGUAGE DeriveGeneric     #-} {-# LANGUAGE FlexibleContexts  #-} {-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE LambdaCase        #-} {-# LANGUAGE OverloadedStrings #-} {-| Module      : Haskoin.Address Copyright   : No rights reserved-License     : UNLICENSE+License     : MIT Maintainer  : jprupp@protonmail.ch Stability   : experimental Portability : POSIX@@ -20,8 +21,11 @@     , isScriptAddress     , isWitnessPubKeyAddress     , isWitnessScriptAddress-    , addrToString-    , stringToAddr+    , addrToText+    , textToAddr+    , bech32ToAddr+    , cashToAddr+    , base58ToAddr     , addrToJSON     , addrToEncoding     , addrFromJSON@@ -42,15 +46,13 @@     , payToNestedScriptAddress     , scriptToAddress     , scriptToAddressBS-      -- ** Private Key Wallet Import Format (WIF)-    , fromWif-    , toWif     , module Haskoin.Address.Base58     , module Haskoin.Address.Bech32     , module Haskoin.Address.CashAddr     ) where  import           Control.Applicative+import           Control.Arrow            (second) import           Control.DeepSeq import           Control.Monad import           Data.Aeson               as A@@ -75,21 +77,25 @@ -- | Address format for Bitcoin and Bitcoin Cash. data Address     -- | pay to public key hash (regular)-    = PubKeyAddress { getAddrHash160 :: !Hash160-                      -- ^ RIPEMD160 hash of public key's SHA256 hash-                     }+    = PubKeyAddress+          { getAddrHash160 :: !Hash160+          -- ^ RIPEMD160 hash of public key's SHA256 hash+          }     -- | pay to script hash-    | ScriptAddress { getAddrHash160 :: !Hash160-                      -- ^ RIPEMD160 hash of script's SHA256 hash-                     }+    | ScriptAddress+          { getAddrHash160 :: !Hash160+          -- ^ RIPEMD160 hash of script's SHA256 hash+          }     -- | pay to witness public key hash-    | WitnessPubKeyAddress { getAddrHash160 :: !Hash160-                             -- ^ RIPEMD160 hash of public key's SHA256 hash-                            }+    | WitnessPubKeyAddress+          { getAddrHash160 :: !Hash160+          -- ^ RIPEMD160 hash of public key's SHA256 hash+          }     -- | pay to witness script hash-    | WitnessScriptAddress { getAddrHash256 :: !Hash256-                             -- ^ HASH256 hash of script-                            }+    | WitnessScriptAddress+          { getAddrHash256 :: !Hash256+          -- ^ HASH256 hash of script+          }     deriving (Eq, Ord, Generic, Show, Read, Serialize, Hashable, NFData)  -- | 'Address' pays to a public key hash.@@ -108,94 +114,91 @@ isWitnessPubKeyAddress WitnessPubKeyAddress {} = True isWitnessPubKeyAddress _                       = False --- | 'Address' pays to a witness script hash. Only valid for SegWit networks. isWitnessScriptAddress :: Address -> Bool isWitnessScriptAddress WitnessScriptAddress {} = True isWitnessScriptAddress _                       = False --- | Deserializer for binary 'Base58' addresses.-base58get :: Network -> Get Address-base58get net = do-    pfx <- getWord8-    addr <- S.get-    f pfx addr-  where-    f x a-        | x == getAddrPrefix net = return $ PubKeyAddress a-        | x == getScriptPrefix net = return $ ScriptAddress a-        | otherwise = fail "Does not recognize address prefix"---- | Binary serializer for 'Base58' addresses.-base58put :: Network -> Putter Address-base58put net (PubKeyAddress h) = do-        putWord8 (getAddrPrefix net)-        put h-base58put net (ScriptAddress h) = do-        putWord8 (getScriptPrefix net)-        put h-base58put _ _ = error "Cannot serialize this address as Base58"- addrToJSON :: Network -> Address -> Value-addrToJSON net a = toJSON (addrToString net a)+addrToJSON net a = toJSON (addrToText net a)  addrToEncoding :: Network -> Address -> Encoding-addrToEncoding net = maybe null_ text . addrToString net+addrToEncoding net = maybe null_ text . addrToText net  -- | JSON parsing for Bitcoin addresses. Works with 'Base58', 'CashAddr' and -- 'Bech32'. addrFromJSON :: Network -> Value -> Parser Address addrFromJSON net =     withText "address" $ \t ->-        case stringToAddr net t of+        case textToAddr net t of             Nothing -> fail "could not decode address"-            Just x -> return x+            Just x  -> return x  -- | Convert address to human-readable string. Uses 'Base58', 'Bech32', or -- 'CashAddr' depending on network.-addrToString :: Network -> Address -> Maybe Text-addrToString net a@PubKeyAddress {getAddrHash160 = h}+addrToText :: Network -> Address -> Maybe Text+addrToText net a@PubKeyAddress {getAddrHash160 = h}     | isNothing (getCashAddrPrefix net) =         Just . encodeBase58Check . runPut $ base58put net a     | otherwise = cashAddrEncode net 0 (S.encode h)-addrToString net a@ScriptAddress {getAddrHash160 = h}+addrToText net a@ScriptAddress {getAddrHash160 = h}     | isNothing (getCashAddrPrefix net) =         Just . encodeBase58Check . runPut $ base58put net a     | otherwise =         cashAddrEncode net 1 (S.encode h)-addrToString net WitnessPubKeyAddress {getAddrHash160 = h} = do+addrToText net WitnessPubKeyAddress {getAddrHash160 = h} = do     hrp <- getBech32Prefix net     segwitEncode hrp 0 (B.unpack (S.encode h))-addrToString net WitnessScriptAddress {getAddrHash256 = h} = do+addrToText net WitnessScriptAddress {getAddrHash256 = h} = do     hrp <- getBech32Prefix net     segwitEncode hrp 0 (B.unpack (S.encode h))  -- | Parse 'Base58', 'Bech32' or 'CashAddr' address, depending on network.-stringToAddr :: Network -> Text -> Maybe Address-stringToAddr net bs = cash <|> segwit <|> b58-  where-    b58 = eitherToMaybe . runGet (base58get net) =<< decodeBase58Check bs-    cash = cashAddrDecode net bs >>= \(ver, bs') -> case ver of-        0 -> do-            h <- eitherToMaybe (S.decode bs')-            return $ PubKeyAddress h-        1 -> do-            h <- eitherToMaybe (S.decode bs')-            return $ ScriptAddress h+textToAddr :: Network -> Text -> Maybe Address+textToAddr net txt =+    cashToAddr net txt <|> bech32ToAddr net txt <|> base58ToAddr net txt++cashToAddr :: Network -> Text -> Maybe Address+cashToAddr net txt = do+    (ver, bs) <- cashAddrDecode net txt+    case ver of+        0 -> PubKeyAddress <$> eitherToMaybe (S.decode bs)+        1 -> ScriptAddress <$> eitherToMaybe (S.decode bs)         _ -> Nothing-    segwit = do-        hrp <- getBech32Prefix net-        (ver, bs') <- segwitDecode hrp bs-        guard (ver == 0)-        let bs'' = B.pack bs'-        case B.length bs'' of-            20 -> do-                h <- eitherToMaybe (S.decode bs'')-                return $ WitnessPubKeyAddress h-            32 -> do-                h <- eitherToMaybe (S.decode bs'')-                return $ WitnessScriptAddress h-            _ -> Nothing +bech32ToAddr :: Network -> Text -> Maybe Address+bech32ToAddr net txt = do+    hrp <- getBech32Prefix net+    (ver, bs) <- second B.pack <$> segwitDecode hrp txt+    guard (ver == 0) -- We only support version 0 for now+    case B.length bs of+        20 -> WitnessPubKeyAddress <$> eitherToMaybe (S.decode bs)+        32 -> WitnessScriptAddress <$> eitherToMaybe (S.decode bs)+        _  -> Nothing++base58ToAddr :: Network -> Text -> Maybe Address+base58ToAddr net txt =+    eitherToMaybe . runGet (base58get net) =<< decodeBase58Check txt++base58get :: Network -> Get Address+base58get net = do+    pfx <- getWord8+    addr <- S.get+    f pfx addr+  where+    f x a+        | x == getAddrPrefix net = return $ PubKeyAddress a+        | x == getScriptPrefix net = return $ ScriptAddress a+        | otherwise = fail "Does not recognize address prefix"++base58put :: Network -> Putter Address+base58put net (PubKeyAddress h) = do+        putWord8 (getAddrPrefix net)+        put h+base58put net (ScriptAddress h) = do+        putWord8 (getScriptPrefix net)+        put h+base58put _ _ = error "Cannot serialize this address as Base58"+ -- | Obtain a standard pay-to-public-key-hash address from a public key. pubKeyAddr :: PubKeyI -> Address pubKeyAddr = PubKeyAddress . addressHash . S.encode@@ -245,10 +248,12 @@ -- | Encode an output script from an address. Will fail if using a -- pay-to-witness address on a non-SegWit network. addressToOutput :: Address -> ScriptOutput-addressToOutput (PubKeyAddress h)        = PayPKHash h-addressToOutput (ScriptAddress h)        = PayScriptHash h-addressToOutput (WitnessPubKeyAddress h) = PayWitnessPKHash h-addressToOutput (WitnessScriptAddress h) = PayWitnessScriptHash h+addressToOutput =+    \case+        (PubKeyAddress h) -> PayPKHash h+        (ScriptAddress h) -> PayScriptHash h+        (WitnessPubKeyAddress h) -> PayWitnessPKHash h+        (WitnessScriptAddress h) -> PayWitnessScriptHash h  -- | Get output script AST for an 'Address'. addressToScript :: Address -> Script@@ -270,39 +275,19 @@  -- | Get the 'Address' of a 'ScriptOutput'. outputAddress :: ScriptOutput -> Maybe Address-outputAddress (PayPKHash h)            = Just $ PubKeyAddress h-outputAddress (PayScriptHash h)        = Just $ ScriptAddress h-outputAddress (PayPK k)                = Just $ pubKeyAddr k-outputAddress (PayWitnessPKHash h)     = Just $ WitnessPubKeyAddress h-outputAddress (PayWitnessScriptHash h) = Just $ WitnessScriptAddress h-outputAddress _                        = Nothing+outputAddress =+    \case+        (PayPKHash h) -> Just $ PubKeyAddress h+        (PayScriptHash h) -> Just $ ScriptAddress h+        (PayPK k) -> Just $ pubKeyAddr k+        (PayWitnessPKHash h) -> Just $ WitnessPubKeyAddress h+        (PayWitnessScriptHash h) -> Just $ WitnessScriptAddress h+        _ -> Nothing  -- | Infer the 'Address' of a 'ScriptInput'. inputAddress :: ScriptInput -> Maybe Address-inputAddress (RegularInput (SpendPKHash _ key)) = Just $ pubKeyAddr key-inputAddress (ScriptHashInput _ rdm) = Just $ payToScriptAddress rdm-inputAddress _ = Nothing---- | Decode private key from WIF (wallet import format) string.-fromWif :: Network -> Base58 -> Maybe SecKeyI-fromWif net wif = do-    bs <- decodeBase58Check wif-    -- Check that this is a private key-    guard (B.head bs == getSecretPrefix net)-    case B.length bs of-        -- Uncompressed format-        33 -> wrapSecKey False <$> secKey (B.tail bs)-        -- Compressed format-        34 -> do-            guard $ B.last bs == 0x01-            wrapSecKey True <$> secKey (B.tail $ B.init bs)-        -- Bad length-        _  -> Nothing---- | Encode private key into a WIF string.-toWif :: Network -> SecKeyI -> Base58-toWif net (SecKeyI k c) =-    encodeBase58Check . B.cons (getSecretPrefix net) $-    if c-        then getSecKey k `B.snoc` 0x01-        else getSecKey k+inputAddress =+    \case+        (RegularInput (SpendPKHash _ key)) -> Just $ pubKeyAddr key+        (ScriptHashInput _ rdm) -> Just $ payToScriptAddress rdm+        _ -> Nothing
src/Haskoin/Address/Base58.hs view
@@ -2,7 +2,7 @@ {-| Module      : Haskoin.Address.Base58 Copyright   : No rights reserved-License     : UNLICENSE+License     : MIT Maintainer  : jprupp@protonmail.ch Stability   : experimental Portability : POSIX
src/Haskoin/Address/Bech32.hs view
@@ -2,7 +2,7 @@ {-| Module      : Haskoin.Address.Base58 Copyright   : No rights reserved-License     : UNLICENSE+License     : MIT Maintainer  : jprupp@protonmail.ch Stability   : experimental Portability : POSIX
src/Haskoin/Address/CashAddr.hs view
@@ -2,7 +2,7 @@ {-| Module      : Haskoin.Address.CashAddr Copyright   : No rights reserved-License     : UNLICENSE+License     : MIT Maintainer  : jprupp@protonmail.ch Stability   : experimental Portability : POSIX
src/Haskoin/Block.hs view
@@ -1,7 +1,7 @@ {-| Module      : Haskoin.Block Copyright   : No rights reserved-License     : UNLICENSE+License     : MIT Maintainer  : jprupp@protonmail.ch Stability   : experimental Portability : POSIX
src/Haskoin/Block/Common.hs view
@@ -4,7 +4,7 @@ {-| Module      : Haskoin.Block.Common Copyright   : No rights reserved-License     : UNLICENSE+License     : MIT Maintainer  : jprupp@protonmail.ch Stability   : experimental Portability : POSIX
src/Haskoin/Block/Headers.hs view
@@ -7,7 +7,7 @@ {-| Module      : Haskoin.Block.Headers Copyright   : No rights reserved-License     : UNLICENSE+License     : MIT Maintainer  : jprupp@protonmail.ch Stability   : experimental Portability : POSIX@@ -90,7 +90,7 @@ import           Haskoin.Block.Common import           Haskoin.Constants import           Haskoin.Crypto-import           Haskoin.Transaction.Common+import           Haskoin.Transaction.Genesis import           Haskoin.Util  -- | Short version of the block hash. Uses the good end of the hash (the part
src/Haskoin/Block/Merkle.hs view
@@ -3,7 +3,7 @@ {-| Module      : Haskoin.Block.Merkle Copyright   : No rights reserved-License     : UNLICENSE+License     : MIT Maintainer  : jprupp@protonmail.ch Stability   : experimental Portability : POSIX
src/Haskoin/Constants.hs view
@@ -5,7 +5,7 @@ {-| Module      : Haskoin.Constants Copyright   : No rights reserved-License     : UNLICENSE+License     : MIT Maintainer  : jprupp@protonmail.ch Stability   : experimental Portability : POSIX
src/Haskoin/Crypto.hs view
@@ -1,7 +1,7 @@ {-| Module      : Haskoin.Crypto Copyright   : No rights reserved-License     : UNLICENSE+License     : MIT Maintainer  : jprupp@protonmail.ch Stability   : experimental Portability : POSIX
src/Haskoin/Crypto/Hash.hs view
@@ -3,7 +3,7 @@ {-| Module      : Haskoin.Crypto.Hash Copyright   : No rights reserved-License     : UNLICENSE+License     : MIT Maintainer  : jprupp@protonmail.ch Stability   : experimental Portability : POSIX
src/Haskoin/Crypto/Signature.hs view
@@ -2,7 +2,7 @@ {-| Module      : Haskoin.Crypto.Signature Copyright   : No rights reserved-License     : UNLICENSE+License     : MIT Maintainer  : jprupp@protonmail.ch Stability   : experimental Portability : POSIX@@ -21,15 +21,14 @@     , exportSig     ) where -import           Control.Monad         (guard, unless, when)+import           Control.Monad       (guard, unless, when) import           Crypto.Secp256k1-import           Data.ByteString       (ByteString)-import qualified Data.ByteString       as BS-import           Data.ByteString.Short (toShort)-import           Data.Maybe            (fromMaybe)-import           Data.Serialize        as S+import           Data.ByteString     (ByteString)+import qualified Data.ByteString     as BS+import           Data.Maybe          (fromMaybe, isNothing)+import           Data.Serialize      as S import           Haskoin.Crypto.Hash-import           Numeric               (showHex)+import           Numeric             (showHex)  -- | Convert 256-bit hash into a 'Msg' for signing or verification. hashToMsg :: Hash256 -> Msg@@ -44,28 +43,28 @@  -- | Verify an ECDSA signature for a 256-bit hash. verifyHashSig :: Hash256 -> Sig -> PubKey -> Bool-verifyHashSig h s p =-    verifySig p g m+verifyHashSig h s p = verifySig p norm (hashToMsg h)   where-    (g, _) = normalizeSig s-    m = hashToMsg h+    norm = fromMaybe s (normalizeSig s)  -- | Deserialize an ECDSA signature as commonly encoded in Bitcoin. getSig :: Get Sig getSig = do-        l <- lookAhead $ do+    l <-+        lookAhead $ do             t <- getWord8             -- 0x30 is DER sequence type-            unless (t == 0x30) $ fail $+            unless (t == 0x30) $+                fail $                 "Bad DER identifier byte 0x" ++ showHex t ". Expecting 0x30"             l <- getWord8             when (l == 0x00) $ fail "Indeterminate form unsupported"             when (l >= 0x80) $ fail "Multi-octect length not supported"             return $ fromIntegral l-        bs <- getByteString $ l + 2-        case decodeStrictSig bs of-            Just s  -> return s-            Nothing -> fail "Invalid signature"+    bs <- getByteString $ l + 2+    case decodeStrictSig bs of+        Just s  -> return s+        Nothing -> fail "Invalid signature"  -- | Serialize an ECDSA signature for Bitcoin use. putSig :: Putter Sig@@ -73,18 +72,17 @@  -- | Is canonical half order. isCanonicalHalfOrder :: Sig -> Bool-isCanonicalHalfOrder = not . snd . normalizeSig+isCanonicalHalfOrder = isNothing . normalizeSig  -- | Decode signature strictly. decodeStrictSig :: ByteString -> Maybe Sig decodeStrictSig bs = do     g <- importSig bs-    let compact = exportCompactSig g     -- <http://www.secg.org/sec1-v2.pdf Section 4.1.4>     -- 4.1.4.1 (r and s can not be zero)-    guard $ getCompactSigR compact /= zero-    guard $ getCompactSigS compact /= zero+    let compact = exportCompactSig g+    let zero = BS.replicate 32 0+    guard $ BS.take 32 (getCompactSig compact) /= zero+    guard $ BS.take 32 (BS.drop 32 (getCompactSig compact)) /= zero     guard $ isCanonicalHalfOrder g     return g-  where-    zero = toShort $ BS.replicate 32 0
src/Haskoin/Keys.hs view
@@ -1,7 +1,7 @@ {-| Module      : Haskoin.Keys Copyright   : No rights reserved-License     : UNLICENSE+License     : MIT Maintainer  : jprupp@protonmail.ch Stability   : experimental Portability : POSIX
src/Haskoin/Keys/Common.hs view
@@ -7,7 +7,7 @@ {-| Module      : Haskoin.Keys.Common Copyright   : No rights reserved-License     : UNLICENSE+License     : MIT Maintainer  : jprupp@protonmail.ch Stability   : experimental Portability : POSIX@@ -28,6 +28,9 @@     , tweakSecKey     , getSecKey     , secKey+    -- ** Private Key Wallet Import Format (WIF)+    , fromWif+    , toWif     ) where  import           Control.Applicative     ((<|>))@@ -48,6 +51,8 @@ import           Data.String             (IsString, fromString) import           Data.String.Conversions (cs) import           GHC.Generics            (Generic)+import           Haskoin.Address.Base58+import           Haskoin.Constants import           Haskoin.Crypto.Hash import           Haskoin.Util @@ -107,16 +112,14 @@     , secKeyCompressed :: !Bool     } deriving (Eq, Show, Read, Generic, NFData) -instance Serialize SecKey where-    get = do-        bs <- getByteString 32-        maybe (fail "invalid private key") return (secKey bs)-    put = putByteString . getSecKey- -- | Wrap private key with corresponding public key compression flag. wrapSecKey :: Bool -> SecKey -> SecKeyI wrapSecKey c d = SecKeyI d c +-- | Tweak a private key.+tweakSecKey :: SecKey -> Hash256 -> Maybe SecKey+tweakSecKey key h = tweakAddSecKey key =<< tweak (encode h)+ -- | Decode Casascius mini private keys (22 or 30 characters). fromMiniKey :: ByteString -> Maybe SecKeyI fromMiniKey bs = do@@ -126,6 +129,26 @@     checkHash = encode $ sha256 $ bs `BS.append` "?"     checkShortKey = BS.length bs `elem` [22, 30] && BS.head checkHash == 0x00 --- | Tweak a private key.-tweakSecKey :: SecKey -> Hash256 -> Maybe SecKey-tweakSecKey key h = tweakAddSecKey key =<< tweak (encode h)+-- | Decode private key from WIF (wallet import format) string.+fromWif :: Network -> Base58 -> Maybe SecKeyI+fromWif net wif = do+    bs <- decodeBase58Check wif+    -- Check that this is a private key+    guard (BS.head bs == getSecretPrefix net)+    case BS.length bs of+        -- Uncompressed format+        33 -> wrapSecKey False <$> secKey (BS.tail bs)+        -- Compressed format+        34 -> do+            guard $ BS.last bs == 0x01+            wrapSecKey True <$> secKey (BS.tail $ BS.init bs)+        -- Bad length+        _  -> Nothing++-- | Encode private key into a WIF string.+toWif :: Network -> SecKeyI -> Base58+toWif net (SecKeyI k c) =+    encodeBase58Check . BS.cons (getSecretPrefix net) $+    if c+        then getSecKey k `BS.snoc` 0x01+        else getSecKey k
src/Haskoin/Keys/Extended.hs view
@@ -6,7 +6,7 @@ {-| Module      : Haskoin.Keys.Extended Copyright   : No rights reserved-License     : UNLICENSE+License     : MIT Maintainer  : jprupp@protonmail.ch Stability   : experimental Portability : POSIX@@ -251,10 +251,10 @@         XPubKey (xPubDepth xKey + 1) (xPubFP xKey) child c pK     | otherwise = error "Invalid child derivation index"   where-    m      = B.append (exportPubKey True (xPubKey xKey)) (encode child)+    m = B.append (exportPubKey True (xPubKey xKey)) (encode child)     (a, c) = split512 $ hmac512 (encode $ xPubChain xKey) m-    pK     = fromMaybe err $ tweakPubKey (xPubKey xKey) a-    err    = throw $ DerivationException "Invalid pubSubKey derivation"+    pK = fromMaybe err $ tweakPubKey (xPubKey xKey) a+    err = throw $ DerivationException "Invalid pubSubKey derivation"  -- | Compute a hard child key derivation. Hard derivations can only be computed -- for private keys. Hard derivations do not allow the parent public key to@@ -270,11 +270,11 @@         XPrvKey (xPrvDepth xkey + 1) (xPrvFP xkey) i c k     | otherwise = error "Invalid child derivation index"   where-    i      = setBit child 31-    m      = B.append (bsPadPrvKey $ xPrvKey xkey) (encode i)+    i = setBit child 31+    m = B.append (bsPadPrvKey $ xPrvKey xkey) (encode i)     (a, c) = split512 $ hmac512 (encode $ xPrvChain xkey) m-    k      = fromMaybe err $ tweakSecKey (xPrvKey xkey) a-    err    = throw $ DerivationException "Invalid hardSubKey derivation"+    k = fromMaybe err $ tweakSecKey (xPrvKey xkey) a+    err = throw $ DerivationException "Invalid hardSubKey derivation"  -- | Returns true if the extended private key was derived through a hard -- derivation.
src/Haskoin/Keys/Mnemonic.hs view
@@ -2,7 +2,7 @@ {-| Module      : Haskoin.Keys.Mnemonic Copyright   : No rights reserved-License     : UNLICENSE+License     : MIT Maintainer  : jprupp@protonmail.ch Stability   : experimental Portability : POSIX
src/Haskoin/Network.hs view
@@ -1,7 +1,7 @@ {-| Module      : Haskoin.Network Copyright   : No rights reserved-License     : UNLICENSE+License     : MIT Maintainer  : jprupp@protonmail.ch Stability   : experimental Portability : POSIX
src/Haskoin/Network/Bloom.hs view
@@ -3,7 +3,7 @@ {-| Module      : Haskoin.Network.Bloom Copyright   : No rights reserved-License     : UNLICENSE+License     : MIT Maintainer  : jprupp@protonmail.ch Stability   : experimental Portability : POSIX@@ -46,8 +46,9 @@ import           Data.Word import           GHC.Generics               (Generic) import           Haskoin.Network.Common-import           Haskoin.Script.Common+import           Haskoin.Script.Standard import           Haskoin.Transaction.Common+ -- | 20,000 items with fp rate < 0.1% or 10,000 items and <0.0001% maxBloomSize :: Int maxBloomSize = 36000@@ -212,35 +213,36 @@ bloomRelevantUpdate bfilter tx     | isBloomFull bfilter || isBloomEmpty bfilter = Nothing     | bloomFlags bfilter == BloomUpdateNone = Nothing-    | length matchOuts > 0 = Just $ foldl' (addRelevant) bfilter matchOuts+    | not (null matchOuts) = Just $ foldl' addRelevant bfilter matchOuts     | otherwise = Nothing-    where         -- TxHash if we end up inserting an outpoint-        h = txHash tx+  where+    h = txHash tx         -- Decode the scriptOutpus and add vOuts in case we make them outpoints-        decodedOutputScripts = traverse (decodeOutputBS . scriptOutput) $ txOut tx-        err = error $ "Error Decoding output script"-        idxOutputScripts = either (const err) (zip [0..]) decodedOutputScripts+    decodedOutputScripts = traverse (decodeOutputBS . scriptOutput) $ txOut tx+    err = error "Error Decoding output script"+    idxOutputScripts = either (const err) (zip [0 ..]) decodedOutputScripts         -- Check if any txOuts were contained in the bloom filter-        matchFilter = filter (\(_,op) -> bloomContains bfilter $ encodeScriptOut op)-        matchOuts = matchFilter idxOutputScripts--        addRelevant :: BloomFilter -> (Word32,ScriptOutput) -> BloomFilter-        addRelevant bfilter (id,scriptOut) = case (bloomFlags bfilter,scriptType) of+    matchFilter =+        filter (\(_, op) -> bloomContains bfilter $ encodeScriptOut op)+    matchOuts = matchFilter idxOutputScripts+    addRelevant :: BloomFilter -> (Word32, ScriptOutput) -> BloomFilter+    addRelevant bf (id', scriptOut) =+        case (bloomFlags bfilter, scriptType)             -- We filtered out BloomUpdateNone so we insert any PayPk or PayMulSig-            (_, True) -> bloomInsert bfilter outpoint-            (BloomUpdateAll, _ ) -> bloomInsert bfilter outpoint-            _ ->  error "Error Updating Bloom Filter with relevant outpoint"-            where-                outpoint = encode $ OutPoint{ outPointHash = h, outPointIndex = id}-                scriptType = (\s -> isPayPK s ||isPayMulSig s) scriptOut-+              of+            (_, True) -> bloomInsert bf outpoint+            (BloomUpdateAll, _) -> bloomInsert bf outpoint+            _ -> error "Error Updating Bloom Filter with relevant outpoint"+      where+        outpoint = encode $ OutPoint {outPointHash = h, outPointIndex = id'}+        scriptType = (\s -> isPayPK s || isPayMulSig s) scriptOut         -- Encodes a scriptOutput so it can be checked agains the Bloom Filter-        encodeScriptOut :: ScriptOutput -> ByteString-        encodeScriptOut (PayMulSig outputMuSig _) = encode outputMuSig-        encodeScriptOut (PayWitnessScriptHash scriptHash) = encode scriptHash-        encodeScriptOut (DataCarrier getOutputData) = encode getOutputData-        encodeScriptOut outputHash = (encode . getOutputHash) outputHash+    encodeScriptOut :: ScriptOutput -> ByteString+    encodeScriptOut (PayMulSig outputMuSig _) = encode outputMuSig+    encodeScriptOut (PayWitnessScriptHash scriptHash) = encode scriptHash+    encodeScriptOut (DataCarrier getOutputDat) = encode getOutputDat+    encodeScriptOut outputHash = (encode . getOutputHash) outputHash  -- | Returns True if the filter is empty (all bytes set to 0x00) isBloomEmpty :: BloomFilter -> Bool
src/Haskoin/Network/Common.hs view
@@ -1,11 +1,10 @@ {-# LANGUAGE DeriveAnyClass    #-} {-# LANGUAGE DeriveGeneric     #-}-{-# LANGUAGE LambdaCase        #-} {-# LANGUAGE OverloadedStrings #-} {-| Module      : Haskoin.Network.Common Copyright   : No rights reserved-License     : UNLICENSE+License     : MIT Maintainer  : jprupp@protonmail.ch Stability   : experimental Portability : POSIX
src/Haskoin/Network/Message.hs view
@@ -3,7 +3,7 @@ {-| Module      : Haskoin.Network.Message Copyright   : No rights reserved-License     : UNLICENSE+License     : MIT Maintainer  : jprupp@protonmail.ch Stability   : experimental Portability : POSIX
src/Haskoin/Script.hs view
@@ -1,7 +1,7 @@ {-| Module      : Haskoin.Script Copyright   : No rights reserved-License     : UNLICENSE+License     : MIT Maintainer  : jprupp@protonmail.ch Stability   : experimental Portability : POSIX
src/Haskoin/Script/Common.hs view
@@ -4,7 +4,7 @@ {-| Module      : Haskoin.Script.Common Copyright   : No rights reserved-License     : UNLICENSE+License     : MIT Maintainer  : jprupp@protonmail.ch Stability   : experimental Portability : POSIX@@ -16,20 +16,6 @@       ScriptOp(..)     , Script(..)     , PushDataType(..)-    , ScriptOutput(..)-    , isPayPK-    , isPayPKHash-    , isPayMulSig-    , isPayScriptHash-    , isPayWitnessPKHash-    , isPayWitnessScriptHash-    , isDataCarrier-    , encodeOutput-    , encodeOutputBS-    , decodeOutput-    , decodeOutputBS-    , toP2SH-    , toP2WSH     , isPushOp     , opPushData     , intToScriptOp@@ -38,17 +24,12 @@  import           Control.DeepSeq import           Control.Monad-import           Data.Aeson          as A-import           Data.Aeson.Encoding (text)-import           Data.ByteString     (ByteString)-import qualified Data.ByteString     as B+import           Data.ByteString (ByteString)+import qualified Data.ByteString as B import           Data.Hashable-import           Data.Serialize      as S-import           Data.Word           (Word8)-import           GHC.Generics        (Generic)-import           Haskoin.Crypto.Hash-import           Haskoin.Keys.Common-import           Haskoin.Util+import           Data.Serialize  as S+import           Data.Word       (Word8)+import           GHC.Generics    (Generic)  -- | Data type representing a transaction script. Scripts are defined as lists -- of script operators 'ScriptOp'. Scripts are used to:@@ -202,8 +183,8 @@     | OP_CHECKMULTISIGVERIFY       -- Expansion     | OP_NOP1-    | OP_NOP2-    | OP_NOP3+    | OP_CHECKLOCKTIMEVERIFY+    | OP_CHECKSEQUENCEVERIFY     | OP_NOP4     | OP_NOP5     | OP_NOP6@@ -355,8 +336,8 @@              -- More NOPs             | op == 0xb0 = return OP_NOP1-            | op == 0xb1 = return OP_NOP2-            | op == 0xb2 = return OP_NOP3+            | op == 0xb1 = return OP_CHECKLOCKTIMEVERIFY+            | op == 0xb2 = return OP_CHECKSEQUENCEVERIFY             | op == 0xb3 = return OP_NOP4             | op == 0xb4 = return OP_NOP5             | op == 0xb5 = return OP_NOP6@@ -512,31 +493,31 @@         OP_WITHIN            -> putWord8 0xa5          -- Crypto-        OP_RIPEMD160         -> putWord8 0xa6-        OP_SHA1              -> putWord8 0xa7-        OP_SHA256            -> putWord8 0xa8-        OP_HASH160           -> putWord8 0xa9-        OP_HASH256           -> putWord8 0xaa-        OP_CODESEPARATOR     -> putWord8 0xab-        OP_CHECKSIG          -> putWord8 0xac-        OP_CHECKSIGVERIFY    -> putWord8 0xad-        OP_CHECKMULTISIG     -> putWord8 0xae+        OP_RIPEMD160           -> putWord8 0xa6+        OP_SHA1                -> putWord8 0xa7+        OP_SHA256              -> putWord8 0xa8+        OP_HASH160             -> putWord8 0xa9+        OP_HASH256             -> putWord8 0xaa+        OP_CODESEPARATOR       -> putWord8 0xab+        OP_CHECKSIG            -> putWord8 0xac+        OP_CHECKSIGVERIFY      -> putWord8 0xad+        OP_CHECKMULTISIG       -> putWord8 0xae         OP_CHECKMULTISIGVERIFY -> putWord8 0xaf          -- More NOPs-        OP_NOP1              -> putWord8 0xb0-        OP_NOP2              -> putWord8 0xb1-        OP_NOP3              -> putWord8 0xb2-        OP_NOP4              -> putWord8 0xb3-        OP_NOP5              -> putWord8 0xb4-        OP_NOP6              -> putWord8 0xb5-        OP_NOP7              -> putWord8 0xb6-        OP_NOP8              -> putWord8 0xb7-        OP_NOP9              -> putWord8 0xb8-        OP_NOP10             -> putWord8 0xb9+        OP_NOP1                -> putWord8 0xb0+        OP_CHECKLOCKTIMEVERIFY -> putWord8 0xb1+        OP_CHECKSEQUENCEVERIFY -> putWord8 0xb2+        OP_NOP4                -> putWord8 0xb3+        OP_NOP5                -> putWord8 0xb4+        OP_NOP6                -> putWord8 0xb5+        OP_NOP7                -> putWord8 0xb6+        OP_NOP8                -> putWord8 0xb7+        OP_NOP9                -> putWord8 0xb8+        OP_NOP10               -> putWord8 0xb9          -- Bitcoin Cash Nov 2018 hard fork-        OP_CHECKDATASIG      -> putWord8 0xba+        OP_CHECKDATASIG       -> putWord8 0xba         OP_CHECKDATASIGVERIFY -> putWord8 0xbb          -- Bitcoin Cash May 2020 hard fork@@ -595,148 +576,3 @@     | otherwise          = Left $ "scriptOpToInt: invalid opcode " ++ show s   where     res = fromIntegral (B.head $ S.encode s) - 0x50---- | Data type describing standard transaction output scripts. Output scripts--- provide the conditions that must be fulfilled for someone to spend the funds--- in a transaction output.-data ScriptOutput-      -- | pay to public key-    = PayPK { getOutputPubKey :: !PubKeyI }-      -- | pay to public key hash-    | PayPKHash { getOutputHash :: !Hash160 }-      -- | multisig-    | PayMulSig { getOutputMulSigKeys     :: ![PubKeyI]-                , getOutputMulSigRequired :: !Int }-      -- | pay to a script hash-    | PayScriptHash { getOutputHash :: !Hash160 }-      -- | pay to witness public key hash-    | PayWitnessPKHash { getOutputHash :: !Hash160 }-      -- | pay to witness script hash-    | PayWitnessScriptHash { getScriptHash :: !Hash256 }-      -- | provably unspendable data carrier-    | DataCarrier { getOutputData :: !ByteString }-    deriving (Eq, Show, Read, Generic, Hashable, NFData)--instance FromJSON ScriptOutput where-    parseJSON =-        withText "scriptoutput" $ \t ->-            either fail return $-            maybeToEither "scriptoutput not hex" (decodeHex t) >>=-            decodeOutputBS--instance ToJSON ScriptOutput where-    toJSON = String . encodeHex . encodeOutputBS-    toEncoding = text . encodeHex . encodeOutputBS---- | Is script a pay-to-public-key output?-isPayPK :: ScriptOutput -> Bool-isPayPK (PayPK _) = True-isPayPK _         = False---- | Is script a pay-to-pub-key-hash output?-isPayPKHash :: ScriptOutput -> Bool-isPayPKHash (PayPKHash _) = True-isPayPKHash _             = False---- | Is script a pay-to-multi-sig output?-isPayMulSig :: ScriptOutput -> Bool-isPayMulSig (PayMulSig _ _) = True-isPayMulSig _               = False---- | Is script a pay-to-script-hash output?-isPayScriptHash :: ScriptOutput -> Bool-isPayScriptHash (PayScriptHash _) = True-isPayScriptHash _                 = False---- | Is script a pay-to-witness-pub-key-hash output?-isPayWitnessPKHash :: ScriptOutput -> Bool-isPayWitnessPKHash (PayWitnessPKHash _) = True-isPayWitnessPKHash _                    = False---- | Is script a pay-to-witness-script-hash output?-isPayWitnessScriptHash :: ScriptOutput -> Bool-isPayWitnessScriptHash (PayWitnessScriptHash _) = True-isPayWitnessScriptHash _                        = False---- | Is script a data carrier output?-isDataCarrier :: ScriptOutput -> Bool-isDataCarrier (DataCarrier _) = True-isDataCarrier _               = False---- | Tries to decode a 'ScriptOutput' from a 'Script'. This can fail if the--- script is not recognized as any of the standard output types.-decodeOutput :: Script -> Either String ScriptOutput-decodeOutput s = case scriptOps s of-    -- Pay to PubKey-    [OP_PUSHDATA bs _, OP_CHECKSIG] -> PayPK <$> S.decode bs-    -- Pay to PubKey Hash-    [OP_DUP, OP_HASH160, OP_PUSHDATA bs _, OP_EQUALVERIFY, OP_CHECKSIG] ->-        PayPKHash <$> S.decode bs-    -- Pay to Script Hash-    [OP_HASH160, OP_PUSHDATA bs _, OP_EQUAL] ->-        PayScriptHash <$> S.decode  bs-    -- Pay to Witness-    [OP_0, OP_PUSHDATA bs OPCODE]-      | B.length bs == 20 -> PayWitnessPKHash     <$> S.decode bs-      | B.length bs == 32 -> PayWitnessScriptHash <$> S.decode bs-    -- Provably unspendable data carrier output-    [OP_RETURN, OP_PUSHDATA bs _] -> Right $ DataCarrier bs-    -- Pay to MultiSig Keys-    _ -> matchPayMulSig s---- | Similar to 'decodeOutput' but decodes from a 'ByteString'.-decodeOutputBS :: ByteString -> Either String ScriptOutput-decodeOutputBS = decodeOutput <=< S.decode---- | Computes a 'Script' from a standard 'ScriptOutput'.-encodeOutput :: ScriptOutput -> Script-encodeOutput s = Script $ case s of-    -- Pay to PubKey-    (PayPK k) -> [opPushData $ S.encode k, OP_CHECKSIG]-    -- Pay to PubKey Hash Address-    (PayPKHash h) ->-        [ OP_DUP, OP_HASH160, opPushData $ S.encode h, OP_EQUALVERIFY, OP_CHECKSIG]-    -- Pay to MultiSig Keys-    (PayMulSig ps r)-      | r <= length ps ->-        let opM = intToScriptOp r-            opN = intToScriptOp $ length ps-            keys = map (opPushData . S.encode) ps-            in opM : keys ++ [opN, OP_CHECKMULTISIG]-      | otherwise -> error "encodeOutput: PayMulSig r must be <= than pkeys"-    -- Pay to Script Hash Address-    (PayScriptHash h) ->-        [ OP_HASH160, opPushData $ S.encode h, OP_EQUAL]-    -- Pay to Witness PubKey Hash Address-    (PayWitnessPKHash h) ->-        [ OP_0, opPushData $ S.encode h ]-    (PayWitnessScriptHash h) ->-        [ OP_0, opPushData $ S.encode h ]-    -- Provably unspendable output-    (DataCarrier d) -> [OP_RETURN, opPushData d]---- | Similar to 'encodeOutput' but encodes to a ByteString-encodeOutputBS :: ScriptOutput -> ByteString-encodeOutputBS = S.encode . encodeOutput---- | Encode script as pay-to-script-hash script-toP2SH :: Script -> ScriptOutput-toP2SH = PayScriptHash . addressHash . S.encode---- | Encode script as a pay-to-witness-script-hash script-toP2WSH :: Script -> ScriptOutput-toP2WSH = PayWitnessScriptHash . sha256 . S.encode---- | Match @[OP_N, PubKey1, ..., PubKeyM, OP_M, OP_CHECKMULTISIG]@-matchPayMulSig :: Script -> Either String ScriptOutput-matchPayMulSig (Script ops) = case splitAt (length ops - 2) ops of-    (m:xs,[n,OP_CHECKMULTISIG]) -> do-        (intM,intN) <- liftM2 (,) (scriptOpToInt m) (scriptOpToInt n)-        if intM <= intN && length xs == intN-            then liftM2 PayMulSig (go xs) (return intM)-            else Left "matchPayMulSig: Invalid M or N parameters"-    _ -> Left "matchPayMulSig: script did not match output template"-  where-    go (OP_PUSHDATA bs _:xs) = liftM2 (:) (S.decode bs) (go xs)-    go []                    = return []-    go  _                    = Left "matchPayMulSig: invalid multisig opcode"
src/Haskoin/Script/SigHash.hs view
@@ -4,7 +4,7 @@ {-| Module      : Haskoin.Script.SigHash Copyright   : No rights reserved-License     : UNLICENSE+License     : MIT Maintainer  : jprupp@protonmail.ch Stability   : experimental Portability : POSIX@@ -13,7 +13,7 @@ -} module Haskoin.Script.SigHash     ( -- * Script Signatures-      SigHash+      SigHash(..)     , SigHashFlag(..)     , sigHashAll     , sigHashNone@@ -38,10 +38,8 @@  import           Control.DeepSeq import           Control.Monad-import           Crypto.Secp256k1 import qualified Data.Aeson                 as J import           Data.Bits-import           Data.ByteString            (ByteString) import qualified Data.ByteString            as BS import           Data.Hashable import           Data.Maybe@@ -51,8 +49,8 @@ import           GHC.Generics               (Generic) import           Haskoin.Constants import           Haskoin.Crypto.Hash-import           Haskoin.Crypto.Signature-import           Haskoin.Network+import           Haskoin.Network.Common+import           Haskoin.Crypto import           Haskoin.Script.Common import           Haskoin.Transaction.Common import           Haskoin.Util@@ -291,22 +289,23 @@ -- is serialized as one byte at the end of an ECDSA 'Sig'. All signatures in -- transaction inputs are of type 'TxSignature'. data TxSignature-    = TxSignature { txSignature        :: !Sig-                  , txSignatureSigHash :: !SigHash-                  }+    = TxSignature+          { txSignature        :: !Sig+          , txSignatureSigHash :: !SigHash+          }     | TxSignatureEmpty     deriving (Eq, Show, Generic)  instance NFData TxSignature  -- | Serialize a 'TxSignature'.-encodeTxSig :: TxSignature -> ByteString+encodeTxSig :: TxSignature -> BS.ByteString encodeTxSig TxSignatureEmpty = error "Can not encode an empty signature" encodeTxSig (TxSignature sig (SigHash n)) =     runPut $ putSig sig >> putWord8 (fromIntegral n)  -- | Deserialize a 'TxSignature'.-decodeTxSig :: Network -> ByteString -> Either String TxSignature+decodeTxSig :: Network -> BS.ByteString -> Either String TxSignature decodeTxSig _   bs | BS.null bs = Left "Empty signature candidate" decodeTxSig net bs =     case decodeStrictSig $ BS.init bs of
src/Haskoin/Script/Standard.hs view
@@ -4,7 +4,7 @@ {-| Module      : Haskoin.Script.Standard Copyright   : No rights reserved-License     : UNLICENSE+License     : MIT Maintainer  : jprupp@protonmail.ch Stability   : experimental Portability : POSIX@@ -13,16 +13,30 @@ pay-to-script-hash, pay-to-multisig and corresponding SegWit variants. -} module Haskoin.Script.Standard-    ( -- * Standard Scripts-      ScriptInput(..)-    , SimpleInput(..)+    ( -- * Standard Script Outputs+      ScriptOutput(..)     , RedeemScript+    , isPayPK+    , isPayPKHash+    , isPayMulSig+    , isPayScriptHash+    , isPayWitnessPKHash+    , isPayWitnessScriptHash+    , isDataCarrier+    , encodeOutput+    , encodeOutputBS+    , decodeOutput+    , decodeOutputBS+    , toP2SH+    , toP2WSH+    , sortMulSig+    -- * Standard Script Inputs+    , ScriptInput(..)+    , SimpleInput(..)     , encodeInput     , encodeInputBS     , decodeInput     , decodeInputBS-    , sortMulSig-    , scriptOpToInt     , isSpendPK     , isSpendPKHash     , isSpendMulSig@@ -31,19 +45,175 @@  import           Control.Applicative    ((<|>)) import           Control.DeepSeq-import           Control.Monad          (guard, (<=<))+import           Control.Monad          (guard, liftM2, (<=<))+import qualified Data.Aeson             as A+import qualified Data.Aeson.Encoding    as A import           Data.ByteString        (ByteString)+import qualified Data.ByteString        as BS import           Data.Function          (on)+import           Data.Hashable import           Data.List              (sortBy)-import           Data.Serialize         (decode, encode)+import           Data.Serialize         as S import           GHC.Generics           (Generic) import           Haskoin.Constants+import           Haskoin.Crypto import           Haskoin.Keys.Common import           Haskoin.Script.Common import           Haskoin.Script.SigHash import           Haskoin.Util +-- | Data type describing standard transaction output scripts. Output scripts+-- provide the conditions that must be fulfilled for someone to spend the funds+-- in a transaction output.+data ScriptOutput+      -- | pay to public key+    = PayPK { getOutputPubKey :: !PubKeyI }+      -- | pay to public key hash+    | PayPKHash { getOutputHash :: !Hash160 }+      -- | multisig+    | PayMulSig { getOutputMulSigKeys     :: ![PubKeyI]+                , getOutputMulSigRequired :: !Int }+      -- | pay to a script hash+    | PayScriptHash { getOutputHash :: !Hash160 }+      -- | pay to witness public key hash+    | PayWitnessPKHash { getOutputHash :: !Hash160 }+      -- | pay to witness script hash+    | PayWitnessScriptHash { getScriptHash :: !Hash256 }+      -- | provably unspendable data carrier+    | DataCarrier { getOutputData :: !ByteString }+    deriving (Eq, Show, Read, Generic, Hashable, NFData) +instance A.FromJSON ScriptOutput where+    parseJSON =+        A.withText "scriptoutput" $ \t ->+            either fail return $+            maybeToEither "scriptoutput not hex" (decodeHex t) >>=+            decodeOutputBS++instance A.ToJSON ScriptOutput where+    toJSON = A.String . encodeHex . encodeOutputBS+    toEncoding = A.text . encodeHex . encodeOutputBS++-- | Is script a pay-to-public-key output?+isPayPK :: ScriptOutput -> Bool+isPayPK (PayPK _) = True+isPayPK _         = False++-- | Is script a pay-to-pub-key-hash output?+isPayPKHash :: ScriptOutput -> Bool+isPayPKHash (PayPKHash _) = True+isPayPKHash _             = False++-- | Is script a pay-to-multi-sig output?+isPayMulSig :: ScriptOutput -> Bool+isPayMulSig (PayMulSig _ _) = True+isPayMulSig _               = False++-- | Is script a pay-to-script-hash output?+isPayScriptHash :: ScriptOutput -> Bool+isPayScriptHash (PayScriptHash _) = True+isPayScriptHash _                 = False++-- | Is script a pay-to-witness-pub-key-hash output?+isPayWitnessPKHash :: ScriptOutput -> Bool+isPayWitnessPKHash (PayWitnessPKHash _) = True+isPayWitnessPKHash _                    = False++-- | Is script a pay-to-witness-script-hash output?+isPayWitnessScriptHash :: ScriptOutput -> Bool+isPayWitnessScriptHash (PayWitnessScriptHash _) = True+isPayWitnessScriptHash _                        = False++-- | Is script a data carrier output?+isDataCarrier :: ScriptOutput -> Bool+isDataCarrier (DataCarrier _) = True+isDataCarrier _               = False++-- | Tries to decode a 'ScriptOutput' from a 'Script'. This can fail if the+-- script is not recognized as any of the standard output types.+decodeOutput :: Script -> Either String ScriptOutput+decodeOutput s = case scriptOps s of+    -- Pay to PubKey+    [OP_PUSHDATA bs _, OP_CHECKSIG] -> PayPK <$> S.decode bs+    -- Pay to PubKey Hash+    [OP_DUP, OP_HASH160, OP_PUSHDATA bs _, OP_EQUALVERIFY, OP_CHECKSIG] ->+        PayPKHash <$> S.decode bs+    -- Pay to Script Hash+    [OP_HASH160, OP_PUSHDATA bs _, OP_EQUAL] ->+        PayScriptHash <$> S.decode  bs+    -- Pay to Witness+    [OP_0, OP_PUSHDATA bs OPCODE]+      | BS.length bs == 20 -> PayWitnessPKHash     <$> S.decode bs+      | BS.length bs == 32 -> PayWitnessScriptHash <$> S.decode bs+    -- Provably unspendable data carrier output+    [OP_RETURN, OP_PUSHDATA bs _] -> Right $ DataCarrier bs+    -- Pay to MultiSig Keys+    _ -> matchPayMulSig s++-- | Similar to 'decodeOutput' but decodes from a 'ByteString'.+decodeOutputBS :: ByteString -> Either String ScriptOutput+decodeOutputBS = decodeOutput <=< S.decode++-- | Computes a 'Script' from a standard 'ScriptOutput'.+encodeOutput :: ScriptOutput -> Script+encodeOutput s = Script $ case s of+    -- Pay to PubKey+    (PayPK k) -> [opPushData $ S.encode k, OP_CHECKSIG]+    -- Pay to PubKey Hash Address+    (PayPKHash h) ->+        [ OP_DUP, OP_HASH160, opPushData $ S.encode h, OP_EQUALVERIFY, OP_CHECKSIG]+    -- Pay to MultiSig Keys+    (PayMulSig ps r)+      | r <= length ps ->+        let opM = intToScriptOp r+            opN = intToScriptOp $ length ps+            keys = map (opPushData . S.encode) ps+            in opM : keys ++ [opN, OP_CHECKMULTISIG]+      | otherwise -> error "encodeOutput: PayMulSig r must be <= than pkeys"+    -- Pay to Script Hash Address+    (PayScriptHash h) ->+        [ OP_HASH160, opPushData $ S.encode h, OP_EQUAL]+    -- Pay to Witness PubKey Hash Address+    (PayWitnessPKHash h) ->+        [ OP_0, opPushData $ S.encode h ]+    (PayWitnessScriptHash h) ->+        [ OP_0, opPushData $ S.encode h ]+    -- Provably unspendable output+    (DataCarrier d) -> [OP_RETURN, opPushData d]++-- | Similar to 'encodeOutput' but encodes to a ByteString+encodeOutputBS :: ScriptOutput -> ByteString+encodeOutputBS = S.encode . encodeOutput++-- | Encode script as pay-to-script-hash script+toP2SH :: Script -> ScriptOutput+toP2SH = PayScriptHash . addressHash . S.encode++-- | Encode script as a pay-to-witness-script-hash script+toP2WSH :: Script -> ScriptOutput+toP2WSH = PayWitnessScriptHash . sha256 . S.encode++-- | Match @[OP_N, PubKey1, ..., PubKeyM, OP_M, OP_CHECKMULTISIG]@+matchPayMulSig :: Script -> Either String ScriptOutput+matchPayMulSig (Script ops) = case splitAt (length ops - 2) ops of+    (m:xs,[n,OP_CHECKMULTISIG]) -> do+        (intM,intN) <- liftM2 (,) (scriptOpToInt m) (scriptOpToInt n)+        if intM <= intN && length xs == intN+            then liftM2 PayMulSig (go xs) (return intM)+            else Left "matchPayMulSig: Invalid M or N parameters"+    _ -> Left "matchPayMulSig: script did not match output template"+  where+    go (OP_PUSHDATA bs _:xs) = liftM2 (:) (S.decode bs) (go xs)+    go []                    = return []+    go  _                    = Left "matchPayMulSig: invalid multisig opcode"++-- | Sort the public keys of a multisig output in ascending order by comparing+-- their compressed serialized representations. Refer to BIP-67.+sortMulSig :: ScriptOutput -> ScriptOutput+sortMulSig out = case out of+    PayMulSig keys r -> PayMulSig (sortBy (compare `on` encode) keys) r+    _ -> error "Can only call orderMulSig on PayMulSig scripts"+ -- | Data type describing standard transaction input scripts. Input scripts -- provide the signing data required to unlock the coins of the output they are -- trying to spend, except in pay-to-witness-public-key-hash and@@ -109,7 +279,7 @@     maybeToEither errMsg $ matchPK ops <|> matchPKHash ops <|> matchMulSig ops   where     matchPK [op] = SpendPK <$> f op-    matchPK _ = Nothing+    matchPK _    = Nothing     matchPKHash [op, OP_PUSHDATA pub _] =         SpendPKHash <$> f op <*> eitherToMaybe (decode pub)     matchPKHash _ = Nothing@@ -117,10 +287,10 @@         guard $ x == OP_0         SpendMulSig <$> mapM f xs     matchMulSig _ = Nothing-    f OP_0 = return TxSignatureEmpty+    f OP_0                    = return TxSignatureEmpty     f (OP_PUSHDATA "" OPCODE) = f OP_0-    f (OP_PUSHDATA bs _) = eitherToMaybe $ decodeTxSig net bs-    f _ = Nothing+    f (OP_PUSHDATA bs _)      = eitherToMaybe $ decodeTxSig net bs+    f _                       = Nothing     errMsg = "decodeInput: Could not decode script input"  -- | Heuristic to decode a 'ScriptInput' from a 'Script'. This function fails if@@ -169,9 +339,3 @@     f TxSignatureEmpty = OP_0     f ts               = opPushData $ encodeTxSig ts --- | Sort the public keys of a multisig output in ascending order by comparing--- their compressed serialized representations. Refer to BIP-67.-sortMulSig :: ScriptOutput -> ScriptOutput-sortMulSig out = case out of-    PayMulSig keys r -> PayMulSig (sortBy (compare `on` encode) keys) r-    _ -> error "Can only call orderMulSig on PayMulSig scripts"
src/Haskoin/Transaction.hs view
@@ -1,7 +1,7 @@ {-| Module      : Haskoin.Transaction Copyright   : No rights reserved-License     : UNLICENSE+License     : MIT Maintainer  : jprupp@protonmail.ch Stability   : experimental Portability : POSIX
src/Haskoin/Transaction/Builder.hs view
@@ -1,9 +1,10 @@+{-# LANGUAGE FlexibleContexts  #-} {-# LANGUAGE LambdaCase        #-} {-# LANGUAGE OverloadedStrings #-} {-| Module      : Haskoin.Transaction.Builder Copyright   : No rights reserved-License     : UNLICENSE+License     : MIT Maintainer  : jprupp@protonmail.ch Stability   : experimental Portability : POSIX@@ -247,25 +248,23 @@ -- | Build a transaction by providing a list of outpoints as inputs -- and a list of recipient addresses and amounts as outputs. buildAddrTx :: Network -> [OutPoint] -> [(Text, Word64)] -> Either String Tx-buildAddrTx net xs ys = buildTx xs =<< mapM f ys+buildAddrTx net ops rcps =+    buildTx ops <$> mapM f rcps   where-    f (s, v) =-        maybe (Left ("buildAddrTx: Invalid address " ++ cs s)) Right $ do-            a <- stringToAddr net s+    f (aTxt, v) =+        maybeToEither ("buildAddrTx: Invalid address " <> cs aTxt) $ do+            a <- textToAddr net aTxt             let o = addressToOutput a             return (o, v)  -- | Build a transaction by providing a list of outpoints as inputs -- and a list of 'ScriptOutput' and amounts as outputs.-buildTx :: [OutPoint] -> [(ScriptOutput, Word64)] -> Either String Tx-buildTx xs ys =-    mapM fo ys >>= \os -> return $ Tx 1 (map fi xs) os [] 0+buildTx :: [OutPoint] -> [(ScriptOutput, Word64)] -> Tx+buildTx ops rcpts =+    Tx 1 (toIn <$> ops) (toOut <$> rcpts) [] 0   where-    fi outPoint = TxIn outPoint B.empty maxBound-    fo (o, v)-        | v <= 2100000000000000 = return $ TxOut v $ encodeOutputBS o-        | otherwise =-            Left $ "buildTx: Invalid amount " ++ show v+    toIn op = TxIn op B.empty maxBound+    toOut (o, v) = TxOut v $ encodeOutputBS o  -- | Sign a transaction by providing the 'SigInput' signing parameters and a -- list of private keys. The signature is computed deterministically as defined@@ -346,9 +345,8 @@     -> Tx     -> ((ScriptOutput, Word64), Int)     -> Either String Tx-mergeTxInput net txs tx ((so, val), i)+mergeTxInput net txs tx ((so, val), i) = do     -- Ignore transactions with empty inputs- = do     let ins = map (scriptInput . (!! i) . txIn) txs     sigRes <- mapM extractSigs $ filter (not . B.null) ins     let rdm = snd $ head sigRes@@ -393,7 +391,7 @@   where     f (_, _, o) txin = o == prevOutput txin     go (Just (so, val, _), i) = verifyStdInput net tx i so val-    go _ = False+    go _                      = False  -- | Verify if a transaction input is valid and standard. verifyStdInput :: Network -> Tx -> Int -> ScriptOutput -> Word64 -> Bool@@ -468,7 +466,8 @@     -> [PubKey]     -> [TxSignature]     -> Int-countMulSig net tx out val i = countMulSig' h+countMulSig net tx out val i =+    countMulSig' h   where     h = txSigHash net tx out val i 
src/Haskoin/Transaction/Builder/Sign.hs view
@@ -5,7 +5,7 @@ {-| Module      : Haskoin.Transaction.Builder.Sign Copyright   : No rights reserved-License     : UNLICENSE+License     : MIT Maintainer  : jprupp@protonmail.ch Stability   : experimental Portability : POSIX@@ -36,26 +36,15 @@ import qualified Data.Serialize             as S import           Data.Word                  (Word64) import           GHC.Generics               (Generic)- import           Haskoin.Address            (getAddrHash160, pubKeyAddr) import           Haskoin.Constants          (Network) import           Haskoin.Crypto             (Hash256, SecKey) import           Haskoin.Crypto.Signature   (signHash, verifyHashSig) import           Haskoin.Keys.Common        (PubKeyI (..), SecKeyI (..),                                              derivePubKeyI, wrapSecKey)-import           Haskoin.Script.Common      (ScriptOutput (..), encodeOutput,-                                             encodeOutputBS, opPushData)-import           Haskoin.Script.SigHash     (SigHash, TxSignature (..),-                                             decodeTxSig, txSigHash,-                                             txSigHashForkId)-import           Haskoin.Script.Standard    (RedeemScript, ScriptInput (..),-                                             SimpleInput (..), decodeInputBS,-                                             encodeInputBS)-import           Haskoin.Transaction.Common (OutPoint, Tx (..), TxIn (..),-                                             WitnessData)-import           Haskoin.Transaction.Segwit (WitnessProgram (..),-                                             calcWitnessProgram, isSegwit,-                                             toWitnessStack)+import           Haskoin.Script+import           Haskoin.Transaction.Common+import           Haskoin.Transaction.Segwit import           Haskoin.Util               (matchTemplate, updateIndex)  -- | Data type used to specify the signing parameters of a transaction input.@@ -279,3 +268,4 @@         _                   -> fromMaybe so rdmM     h | isSegwit so = txSigHashForkId       | otherwise   = txSigHash+
src/Haskoin/Transaction/Common.hs view
@@ -4,7 +4,7 @@ {-| Module      : Haskoin.Transaction.Common Copyright   : No rights reserved-License     : UNLICENSE+License     : MIT Maintainer  : jprupp@protonmail.ch Stability   : experimental Portability : POSIX@@ -26,7 +26,6 @@     , txHashToHex     , nosigTxHash     , nullOutPoint-    , genesisTx     ) where  import           Control.Applicative     ((<|>))@@ -48,7 +47,6 @@ import           GHC.Generics            (Generic) import           Haskoin.Crypto.Hash import           Haskoin.Network.Common-import           Haskoin.Script.Common import           Haskoin.Util import           Text.Read               as R @@ -344,21 +342,3 @@           "0000000000000000000000000000000000000000000000000000000000000000"     , outPointIndex = maxBound     }---- | Transaction from Genesis block.-genesisTx :: Tx-genesisTx =-    Tx 1 [txin] [txout] [] locktime-  where-    txin = TxIn outpoint inputBS maxBound-    txout = TxOut 5000000000 (encodeOutputBS output)-    locktime = 0-    outpoint = OutPoint z maxBound-    Just inputBS = decodeHex $ fromString $-        "04ffff001d0104455468652054696d65732030332f4a616e2f323030392043686" ++-        "16e63656c6c6f72206f6e206272696e6b206f66207365636f6e64206261696c6f" ++-        "757420666f722062616e6b73"-    output = PayPK $ fromString $-        "04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb" ++-        "649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5f"-    z = "0000000000000000000000000000000000000000000000000000000000000000"
+ src/Haskoin/Transaction/Genesis.hs view
@@ -0,0 +1,37 @@+{-# LANGUAGE OverloadedStrings #-}+{-|+Module      : Haskoin.Transaction.Genesis+Copyright   : No rights reserved+License     : UNLICENSE+Maintainer  : jprupp@protonmail.ch+Stability   : experimental+Portability : POSIX++Code related to transactions parsing and serialization.+-}+module Haskoin.Transaction.Genesis+    ( genesisTx+    ) where++import           Data.String                (fromString)+import           Haskoin.Script.Standard+import           Haskoin.Transaction.Common+import           Haskoin.Util++-- | Transaction from Genesis block.+genesisTx :: Tx+genesisTx =+    Tx 1 [txin] [txout] [] locktime+  where+    txin = TxIn outpoint inputBS maxBound+    txout = TxOut 5000000000 (encodeOutputBS output)+    locktime = 0+    outpoint = OutPoint z maxBound+    Just inputBS = decodeHex $ fromString $+        "04ffff001d0104455468652054696d65732030332f4a616e2f323030392043686" +++        "16e63656c6c6f72206f6e206272696e6b206f66207365636f6e64206261696c6f" +++        "757420666f722062616e6b73"+    output = PayPK $ fromString $+        "04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb" +++        "649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5f"+    z = "0000000000000000000000000000000000000000000000000000000000000000"
src/Haskoin/Transaction/Partial.hs view
@@ -6,7 +6,7 @@ {-| Module      : Haskoin.Transaction.Partial Copyright   : No rights reserved-License     : UNLICENSE+License     : MIT Maintainer  : matt@bitnomial.com Stability   : experimental Portability : POSIX
src/Haskoin/Transaction/Segwit.hs view
@@ -4,7 +4,7 @@ {-| Module      : Haskoin.Transaction.Segwit Copyright   : No rights reserved-License     : UNLICENSE+License     : MIT Maintainer  : jprupp@protonmail.ch Stability   : experimental Portability : POSIX@@ -31,14 +31,10 @@  import           Data.ByteString            (ByteString) import qualified Data.Serialize             as S-import           Haskoin.Constants          (Network)-import           Haskoin.Keys.Common        (PubKeyI)-import           Haskoin.Script.Common      (Script (..), ScriptOutput (..),-                                             decodeOutput, encodeOutput)-import           Haskoin.Script.SigHash     (TxSignature (..), decodeTxSig,-                                             encodeTxSig)-import           Haskoin.Script.Standard    (ScriptInput (..), SimpleInput (..))-import           Haskoin.Transaction.Common (WitnessStack)+import           Haskoin.Constants+import           Haskoin.Keys.Common+import           Haskoin.Script+import           Haskoin.Transaction.Common  -- | Test if a 'ScriptOutput' is P2WPKH or P2WSH --
src/Haskoin/Util.hs view
@@ -2,7 +2,7 @@ {-| Module      : Haskoin.Util Copyright   : No rights reserved-License     : UNLICENSE+License     : MIT Maintainer  : jprupp@protonmail.ch Stability   : experimental Portability : POSIX
src/Haskoin/Util/Arbitrary.hs view
@@ -1,7 +1,7 @@ {-| Module      : Haskoin.Test Copyright   : No rights reserved-License     : UNLICENSE+License     : MIT Maintainer  : jprupp@protonmail.ch Stability   : experimental Portability : POSIX
src/Haskoin/Util/Arbitrary/Address.hs view
@@ -2,7 +2,7 @@ {-| Module      : Haskoin.Test.Address Copyright   : No rights reserved-License     : UNLICENSE+License     : MIT Maintainer  : jprupp@protonmail.ch Stability   : experimental Portability : POSIX
src/Haskoin/Util/Arbitrary/Block.hs view
@@ -1,7 +1,7 @@ {-| Module      : Haskoin.Test.Block Copyright   : No rights reserved-License     : UNLICENSE+License     : MIT Maintainer  : jprupp@protonmail.ch Stability   : experimental Portability : POSIX
src/Haskoin/Util/Arbitrary/Crypto.hs view
@@ -1,7 +1,7 @@ {-| Module      : Haskoin.Test.Crypto Copyright   : No rights reserved-License     : UNLICENSE+License     : MIT Maintainer  : jprupp@protonmail.ch Stability   : experimental Portability : POSIX
src/Haskoin/Util/Arbitrary/Keys.hs view
@@ -1,7 +1,7 @@ {-| Module      : Haskoin.Test.Keys Copyright   : No rights reserved-License     : UNLICENSE+License     : MIT Maintainer  : jprupp@protonmail.ch Stability   : experimental Portability : POSIX
src/Haskoin/Util/Arbitrary/Message.hs view
@@ -1,7 +1,7 @@ {-| Module      : Haskoin.Test.Message Copyright   : No rights reserved-License     : UNLICENSE+License     : MIT Maintainer  : jprupp@protonmail.ch Stability   : experimental Portability : POSIX
src/Haskoin/Util/Arbitrary/Network.hs view
@@ -1,7 +1,7 @@ {-| Module      : Haskoin.Test.Network Copyright   : No rights reserved-License     : UNLICENSE+License     : MIT Maintainer  : jprupp@protonmail.ch Stability   : experimental Portability : POSIX
src/Haskoin/Util/Arbitrary/Script.hs view
@@ -2,7 +2,7 @@ {-| Module      : Haskoin.Test.Script Copyright   : No rights reserved-License     : UNLICENSE+License     : MIT Maintainer  : jprupp@protonmail.ch Stability   : experimental Portability : POSIX@@ -140,8 +140,8 @@         , return OP_CHECKMULTISIGVERIFY         -- Expansion         , return OP_NOP1-        , return OP_NOP2-        , return OP_NOP3+        , return OP_CHECKLOCKTIMEVERIFY+        , return OP_CHECKSEQUENCEVERIFY         , return OP_NOP4         , return OP_NOP5         , return OP_NOP6
src/Haskoin/Util/Arbitrary/Transaction.hs view
@@ -1,7 +1,7 @@ {-| Module      : Haskoin.Test.Transaction Copyright   : No rights reserved-License     : UNLICENSE+License     : MIT Maintainer  : jprupp@protonmail.ch Stability   : experimental Portability : POSIX@@ -71,16 +71,8 @@ -- | Arbitrary witness or legacy transaction. arbitraryWLTx :: Network -> Bool -> Gen Tx arbitraryWLTx net wit = do-    ni <- choose (0, 5)-    no <--        if wit-            then choose (0, 5)-            else choose-                     ( if ni == 0-                           then 2-                           else 0-                     , 5 -- avoid witness case-                      )+    ni <- choose (1, 5)+    no <- choose (1, 5)     inps <- vectorOf ni (arbitraryTxIn net)     outs <- vectorOf no (arbitraryTxOut net)     let uniqueInps = nubBy (\a b -> prevOutput a == prevOutput b) inps@@ -95,8 +87,8 @@ -- Only compressed public keys are used. arbitraryAddrOnlyTx :: Network -> Gen Tx arbitraryAddrOnlyTx net = do-    ni <- choose (0, 5)-    no <- choose (0, 5)+    ni <- choose (1, 5)+    no <- choose (1, 5)     inps <- vectorOf ni (arbitraryAddrOnlyTxIn net)     outs <- vectorOf no (arbitraryAddrOnlyTxOut net)     Tx <$> arbitrary <*> pure inps <*> pure outs <*> pure [] <*> arbitrary@@ -104,8 +96,8 @@ -- | Like 'arbitraryAddrOnlyTx' without empty signatures in the inputs. arbitraryAddrOnlyTxFull :: Network -> Gen Tx arbitraryAddrOnlyTxFull net = do-    ni <- choose (0, 5)-    no <- choose (0, 5)+    ni <- choose (1, 5)+    no <- choose (1, 5)     inps <- vectorOf ni (arbitraryAddrOnlyTxInFull net)     outs <- vectorOf no (arbitraryAddrOnlyTxOut net)     Tx <$> arbitrary <*> pure inps <*> pure outs <*> pure [] <*> arbitrary
src/Haskoin/Util/Arbitrary/Util.hs view
@@ -3,7 +3,7 @@ {-| Module      : Haskoin.Test.Util Copyright   : No rights reserved-License     : UNLICENSE+License     : MIT Maintainer  : jprupp@protonmail.ch Stability   : experimental Portability : POSIX@@ -17,6 +17,7 @@ , arbitraryBSSn , arbitraryMaybe , arbitraryNetwork+, arbitraryUTCTime , SerialBox(..) , JsonBox(..) , NetBox(..)@@ -31,22 +32,23 @@ ) where -import           Control.Monad         (forM_, (<=<))-import qualified Data.Aeson            as A-import qualified Data.Aeson.Encoding   as A-import qualified Data.Aeson.Types      as A-import           Data.ByteString       (ByteString, pack)-import qualified Data.ByteString.Short as BSS-import qualified Data.Map.Strict       as Map+import           Control.Monad           (forM_, (<=<))+import qualified Data.Aeson              as A+import qualified Data.Aeson.Encoding     as A+import qualified Data.Aeson.Types        as A+import           Data.ByteString         (ByteString, pack)+import qualified Data.ByteString.Short   as BSS+import qualified Data.Map.Strict         as Map import           Data.Proxy-import qualified Data.Serialize        as S-import           Data.Time.Clock       (UTCTime (..))-import           Data.Time.Clock.POSIX (posixSecondsToUTCTime)-import qualified Data.Typeable         as T-import           Data.Word             (Word32)+import qualified Data.Serialize          as S+import           Data.Time.Clock         (UTCTime (..))+import           Data.Time.Clock.POSIX   (posixSecondsToUTCTime)+import qualified Data.Typeable           as T+import           Data.Word               (Word32) import           Haskoin.Constants-import           Test.Hspec            (Spec, describe, shouldBe, shouldSatisfy)-import           Test.Hspec.QuickCheck (prop)+import           Test.Hspec              (Spec, describe, shouldBe,+                                          shouldSatisfy)+import           Test.Hspec.QuickCheck   (prop) import           Test.QuickCheck  -- | Arbitrary strict 'ByteString'.@@ -125,9 +127,9 @@ -- | Generate Data.Serialize identity tests testSerial ::        (Eq a, Show a, T.Typeable a, S.Serialize a) => Gen a -> Spec-testSerial gen = do+testSerial gen =     prop ("Data.Serialize encoding/decoding identity for " <> name) $-        forAll gen $ \x -> (S.decode . S.encode) x `shouldBe` Right x+    forAll gen $ \x -> (S.decode . S.encode) x `shouldBe` Right x   where     name = show $ T.typeRep $ proxy gen     proxy :: Gen a -> Proxy a@@ -136,7 +138,7 @@ -- | Generate Read/Show identity tests testRead ::        (Eq a, Read a, Show a, T.Typeable a) => Gen a -> Spec-testRead gen = do+testRead gen =     prop ("read/show identity for " <> name) $         forAll gen $ \x -> (read . show) x `shouldBe` x   where
test/Haskoin/Address/CashAddrSpec.hs view
@@ -7,7 +7,6 @@ import           Data.String.Conversions import           Data.Text                (Text) import           Haskoin.Address-import           Haskoin.Address.CashAddr import           Haskoin.Constants import           Haskoin.Util import           Test.Hspec@@ -44,80 +43,80 @@     describe "cashaddr to base58 translation test vectors" $ do         it "1BpEi6DfDAUFd7GtittLSdBeYJvcoaVggu" $ do             let addr =-                    addrToString bch =<<-                    stringToAddr btc "1BpEi6DfDAUFd7GtittLSdBeYJvcoaVggu"+                    addrToText bch =<<+                    textToAddr btc "1BpEi6DfDAUFd7GtittLSdBeYJvcoaVggu"             addr `shouldBe`                 Just "bitcoincash:qpm2qsznhks23z7629mms6s4cwef74vcwvy22gdx6a"         it "1KXrWXciRDZUpQwQmuM1DbwsKDLYAYsVLR" $ do             let addr =-                    addrToString bch =<<-                    stringToAddr btc "1KXrWXciRDZUpQwQmuM1DbwsKDLYAYsVLR"+                    addrToText bch =<<+                    textToAddr btc "1KXrWXciRDZUpQwQmuM1DbwsKDLYAYsVLR"             addr `shouldBe`                 Just "bitcoincash:qr95sy3j9xwd2ap32xkykttr4cvcu7as4y0qverfuy"         it "16w1D5WRVKJuZUsSRzdLp9w3YGcgoxDXb" $ do             let addr =-                    addrToString bch =<<-                    stringToAddr btc "16w1D5WRVKJuZUsSRzdLp9w3YGcgoxDXb"+                    addrToText bch =<<+                    textToAddr btc "16w1D5WRVKJuZUsSRzdLp9w3YGcgoxDXb"             addr `shouldBe`                 Just "bitcoincash:qqq3728yw0y47sqn6l2na30mcw6zm78dzqre909m2r"         it "3CWFddi6m4ndiGyKqzYvsFYagqDLPVMTzC" $ do             let addr =-                    addrToString bch =<<-                    stringToAddr btc "3CWFddi6m4ndiGyKqzYvsFYagqDLPVMTzC"+                    addrToText bch =<<+                    textToAddr btc "3CWFddi6m4ndiGyKqzYvsFYagqDLPVMTzC"             addr `shouldBe`                 Just "bitcoincash:ppm2qsznhks23z7629mms6s4cwef74vcwvn0h829pq"         it "3LDsS579y7sruadqu11beEJoTjdFiFCdX4" $ do             let addr =-                    addrToString bch =<<-                    stringToAddr btc "3LDsS579y7sruadqu11beEJoTjdFiFCdX4"+                    addrToText bch =<<+                    textToAddr btc "3LDsS579y7sruadqu11beEJoTjdFiFCdX4"             addr `shouldBe`                 Just "bitcoincash:pr95sy3j9xwd2ap32xkykttr4cvcu7as4yc93ky28e"         it "31nwvkZwyPdgzjBJZXfDmSWsC4ZLKpYyUw" $ do             let addr =-                    addrToString bch =<<-                    stringToAddr btc "31nwvkZwyPdgzjBJZXfDmSWsC4ZLKpYyUw"+                    addrToText bch =<<+                    textToAddr btc "31nwvkZwyPdgzjBJZXfDmSWsC4ZLKpYyUw"             addr `shouldBe`                 Just "bitcoincash:pqq3728yw0y47sqn6l2na30mcw6zm78dzq5ucqzc37"     describe "base58 to cashaddr translation test vectors" $ do         it "bitcoincash:qpm2qsznhks23z7629mms6s4cwef74vcwvy22gdx6a" $ do             let addr =-                    addrToString btc =<<-                    stringToAddr+                    addrToText btc =<<+                    textToAddr                         bch                         "bitcoincash:qpm2qsznhks23z7629mms6s4cwef74vcwvy22gdx6a"             addr `shouldBe` Just "1BpEi6DfDAUFd7GtittLSdBeYJvcoaVggu"         it "bitcoincash:qr95sy3j9xwd2ap32xkykttr4cvcu7as4y0qverfuy" $ do             let addr =-                    addrToString btc =<<-                    stringToAddr+                    addrToText btc =<<+                    textToAddr                         bch                         "bitcoincash:qr95sy3j9xwd2ap32xkykttr4cvcu7as4y0qverfuy"             addr `shouldBe` Just "1KXrWXciRDZUpQwQmuM1DbwsKDLYAYsVLR"         it "bitcoincash:qqq3728yw0y47sqn6l2na30mcw6zm78dzqre909m2r" $ do             let addr =-                    addrToString btc =<<-                    stringToAddr+                    addrToText btc =<<+                    textToAddr                         bch                         "bitcoincash:qqq3728yw0y47sqn6l2na30mcw6zm78dzqre909m2r"             addr `shouldBe` Just "16w1D5WRVKJuZUsSRzdLp9w3YGcgoxDXb"         it "bitcoincash:ppm2qsznhks23z7629mms6s4cwef74vcwvn0h829pq" $ do             let addr =-                    addrToString btc =<<-                    stringToAddr+                    addrToText btc =<<+                    textToAddr                         bch                         "bitcoincash:ppm2qsznhks23z7629mms6s4cwef74vcwvn0h829pq"             addr `shouldBe` Just "3CWFddi6m4ndiGyKqzYvsFYagqDLPVMTzC"         it "bitcoincash:pr95sy3j9xwd2ap32xkykttr4cvcu7as4yc93ky28e" $ do             let addr =-                    addrToString btc =<<-                    stringToAddr+                    addrToText btc =<<+                    textToAddr                         bch                         "bitcoincash:pr95sy3j9xwd2ap32xkykttr4cvcu7as4yc93ky28e"             addr `shouldBe` Just "3LDsS579y7sruadqu11beEJoTjdFiFCdX4"         it "bitcoincash:pqq3728yw0y47sqn6l2na30mcw6zm78dzq5ucqzc37" $ do             let addr =-                    addrToString btc =<<-                    stringToAddr+                    addrToText btc =<<+                    textToAddr                         bch                         "bitcoincash:pqq3728yw0y47sqn6l2na30mcw6zm78dzq5ucqzc37"             addr `shouldBe` Just "31nwvkZwyPdgzjBJZXfDmSWsC4ZLKpYyUw"
test/Haskoin/AddressSpec.hs view
@@ -5,9 +5,11 @@ import qualified Data.ByteString        as BS (append, empty, pack) import           Data.Maybe             (fromJust, isJust) import           Data.Text              (Text)+import qualified Data.Text              as T import           Haskoin.Address import           Haskoin.Constants-import           Haskoin.Keys           (derivePubKeyI)+import           Haskoin.Keys+import           Haskoin.Util import           Haskoin.Util.Arbitrary import           Test.Hspec import           Test.Hspec.QuickCheck@@ -34,21 +36,26 @@         prop "encodes and decodes base58 bytestring with checksum" $             forAll arbitraryBS $ \bs ->                 decodeBase58Check (encodeBase58Check bs) == Just bs-        prop "encodes and decodes address" $+        prop "textToAddr . addrToText identity" $             forAll arbitraryNetAddress $ \(net, a) ->-                (stringToAddr net =<< addrToString net a) == Just a-    describe "Address vectors" . it "base58 btc address vectors" $-        mapM_ runVector vectors-    describe "Witness address vectors" . it "p2sh(pwpkh)" $-        mapM_ testCompatWitness compatWitnessVectors-    describe "WIF keys" $-        prop "encode and decode wif private keys" $-        forAll arbitraryNetwork $ \net ->-            forAll arbitraryKeyPair $ \(pk, _) ->-                fromWif net (toWif net pk) == Just pk+                (textToAddr net =<< addrToText net a) == Just a+        prop "outputAddress . addressToOutput identity" $+            forAll arbitraryAddress $ \a ->+                outputAddress (addressToOutput a) == Just a+    describe "Address vectors" $ do+        it "Passes Base58 vectors 1" $+            mapM_ testVector vectors+        it "Passes Base58 vectors 2" $+            mapM_ testBase58Vector base58Vectors+        it "Passes Base58 invalid decoding vectors" $+            mapM_ testBase58InvalidVector base58InvalidVectors+        it "Passes Base58Check invalid decoding vectors" $+            mapM_ testBase58ChkInvalidVector base58ChkInvalidVectors+        it "Passes addresses witness p2sh(pwpkh) vectors" $+            mapM_ testCompatWitnessVector compatWitnessVectors -runVector :: (ByteString, Text, Text) -> Assertion-runVector (bs, e, chk) = do+testVector :: (ByteString, Text, Text) -> Assertion+testVector (bs, e, chk) = do     assertEqual "encodeBase58" e b58     assertEqual "encodeBase58Check" chk b58Chk     assertEqual "decodeBase58" (Just bs) (decodeBase58 b58)@@ -59,29 +66,124 @@  vectors :: [(ByteString, Text, Text)] vectors =-    [ ( BS.empty, "", "3QJmnh" )-    , ( BS.pack [0], "1", "1Wh4bh" )-    , ( BS.pack [0,0,0,0], "1111", "11114bdQda" )-    , ( BS.pack [0,0,1,0,0], "11LUw", "113CUwsFVuo" )-    , ( BS.pack [255], "5Q", "VrZDWwe" )-    , ( BS.pack [0,0,0,0] `BS.append` BS.pack [1..255]-      , "1111cWB5HCBdLjAuqGGReWE3R3CguuwSjw6RHn39s2yuDRTS5NsBgNiFpWgAnEx6VQi8csexkgYw3mdYrMHr8x9i7aEwP8kZ7vccXWqKDvGv3u1GxFKPuAkn8JCPPGDMf3vMMnbzm6Nh9zh1gcNsMvH3ZNLmP5fSG6DGbbi2tuwMWPthr4boWwCxf7ewSgNQeacyozhKDDQQ1qL5fQFUW52QKUZDZ5fw3KXNQJMcNTcaB723LchjeKun7MuGW5qyCBZYzA1KjofN1gYBV3NqyhQJ3Ns746GNuf9N2pQPmHz4xpnSrrfCvy6TVVz5d4PdrjeshsWQwpZsZGzvbdAdN8MKV5QsBDY"-      , "111151KWPPBRzdWPr1ASeu172gVgLf1YfUp6VJyk6K9t4cLqYtFHcMa2iX8S3NJEprUcW7W5LvaPRpz7UG7puBj5STE3nKhCGt5eckYq7mMn5nT7oTTic2BAX6zDdqrmGCnkszQkzkz8e5QLGDjf7KeQgtEDm4UER6DMSdBjFQVa6cHrrJn9myVyyhUrsVnfUk2WmNFZvkWv3Tnvzo2cJ1xW62XDfUgYz1pd97eUGGPuXvDFfLsBVd1dfdUhPwxW7pMPgdWHTmg5uqKGFF6vE4xXpAqZTbTxRZjCDdTn68c2wrcxApm8hq3JX65Hix7VtcD13FF8b7BzBtwjXq1ze6NMjKgUcqpJTN9vt"-      )+    [ (BS.empty, "", "3QJmnh")+    , (BS.pack [0], "1", "1Wh4bh")+    , (BS.pack [0, 0, 0, 0], "1111", "11114bdQda")+    , (BS.pack [0, 0, 1, 0, 0], "11LUw", "113CUwsFVuo")+    , (BS.pack [255], "5Q", "VrZDWwe")+    , ( BS.pack [0, 0, 0, 0] `BS.append` BS.pack [1 .. 255]+      , "1111cWB5HCBdLjAuqGGReWE3R3CguuwSjw6RHn39s2yuDRTS5N\+        \sBgNiFpWgAnEx6VQi8csexkgYw3mdYrMHr8x9i7aEwP8kZ7vcc\+        \XWqKDvGv3u1GxFKPuAkn8JCPPGDMf3vMMnbzm6Nh9zh1gcNsMv\+        \H3ZNLmP5fSG6DGbbi2tuwMWPthr4boWwCxf7ewSgNQeacyozhK\+        \DDQQ1qL5fQFUW52QKUZDZ5fw3KXNQJMcNTcaB723LchjeKun7M\+        \uGW5qyCBZYzA1KjofN1gYBV3NqyhQJ3Ns746GNuf9N2pQPmHz4\+        \xpnSrrfCvy6TVVz5d4PdrjeshsWQwpZsZGzvbdAdN8MKV5QsBDY"+      , "111151KWPPBRzdWPr1ASeu172gVgLf1YfUp6VJyk6K9t4cLqYt\+        \FHcMa2iX8S3NJEprUcW7W5LvaPRpz7UG7puBj5STE3nKhCGt5e\+        \ckYq7mMn5nT7oTTic2BAX6zDdqrmGCnkszQkzkz8e5QLGDjf7K\+        \eQgtEDm4UER6DMSdBjFQVa6cHrrJn9myVyyhUrsVnfUk2WmNFZ\+        \vkWv3Tnvzo2cJ1xW62XDfUgYz1pd97eUGGPuXvDFfLsBVd1dfd\+        \UhPwxW7pMPgdWHTmg5uqKGFF6vE4xXpAqZTbTxRZjCDdTn68c2\+        \wrcxApm8hq3JX65Hix7VtcD13FF8b7BzBtwjXq1ze6NMjKgUcq\+        \pJTN9vt")     ] -compatWitnessVectors :: [(Network, Text, Text)]-compatWitnessVectors =-    [ ( btcTest-      , "cNUnpYpMsJXYCERYBciJnsWBpcYEFjdcbq6dxj4SskGhs7uHuJ7Q"-      , "2N6PDTueBHvXzW61B4oe5SW1D3v2Z3Vpbvw")+-- Test vectors from:+-- https://github.com/bitcoin/bitcoin/blob/master/src/test/data/base58_encode_decode.json++testBase58Vector :: (Text, Text) -> Assertion+testBase58Vector (a, b) = do+    assertEqual "encodeBase58 match" b (encodeBase58 bsA)+    assertEqual "decodeBase58 match" a (encodeHex bsB)+    assertEqual "bytestring match" bsA bsB+  where+    bsA = fromJust $ decodeHex a+    bsB = fromJust $ decodeBase58 b++base58Vectors :: [(Text, Text)]+base58Vectors =+    [ ("", "")+    , ("61", "2g")+    , ("626262", "a3gV")+    , ("636363", "aPEr")+    , ( "73696d706c792061206c6f6e6720737472696e67"+      , "2cFupjhnEsSn59qHXstmK2ffpLv2")+    , ( "00eb15231dfceb60925886b67d065299925915aeb172c06647"+      , "1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L")+    , ("516b6fcd0f", "ABnLTmg")+    , ("bf4f89001e670274dd", "3SEo3LWLoPntC")+    , ("572e4794", "3EFU7m")+    , ("ecac89cad93923c02321", "EJDM8drfXA6uyA")+    , ("10c8511e", "Rt5zm")+    , ("00000000000000000000", "1111111111")+    , ( "000111d38e5fc9071ffcd20b4a763cc9ae4f252bb4e48fd66a835e252a\+        \da93ff480d6dd43dc62a641155a5"+      , "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz")+    , ( "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c\+        \1d1e1f202122232425262728292a2b2c2d2e2f30313233343536373839\+        \3a3b3c3d3e3f404142434445464748494a4b4c4d4e4f50515253545556\+        \5758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f70717273\+        \7475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f90\+        \9192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacad\+        \aeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9ca\+        \cbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7\+        \e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff"+      , "1cWB5HCBdLjAuqGGReWE3R3CguuwSjw6RHn39s2yuDRTS5NsBgNiFpWgAn\+        \Ex6VQi8csexkgYw3mdYrMHr8x9i7aEwP8kZ7vccXWqKDvGv3u1GxFKPuAk\+        \n8JCPPGDMf3vMMnbzm6Nh9zh1gcNsMvH3ZNLmP5fSG6DGbbi2tuwMWPthr\+        \4boWwCxf7ewSgNQeacyozhKDDQQ1qL5fQFUW52QKUZDZ5fw3KXNQJMcNTc\+        \aB723LchjeKun7MuGW5qyCBZYzA1KjofN1gYBV3NqyhQJ3Ns746GNuf9N2\+        \pQPmHz4xpnSrrfCvy6TVVz5d4PdrjeshsWQwpZsZGzvbdAdN8MKV5QsBDY")     ] -testCompatWitness :: (Network, Text, Text) -> Assertion-testCompatWitness (net, seckey, addr) = do+-- Test vectors from:+-- https://github.com/bitcoin/bitcoin/blob/master/src/test/base58_tests.cpp++testBase58InvalidVector :: (Text, Maybe Text) -> Assertion+testBase58InvalidVector (a, resM) =+    assertEqual "decodeBase58 invalid match" resM (encodeHex <$> decodeBase58 a)++base58InvalidVectors :: [(Text, Maybe Text)]+base58InvalidVectors =+    [ ("invalid", Nothing)+    , ("\0invalid", Nothing)+    , ("good", Just "768320")+    , ("bad0IOl", Nothing)+    , ("goodbad0IOl", Nothing)+    , ("good\0bad0IOl", Nothing)+    --  Haskoin does not remove white spaces before decoding base58 strings+    -- , (" \t\n\v\f\r skip \r\f\v\n\t a", Nothing)+    -- , (" \t\n\v\f\r skip \r\f\v\n\t ", Just "971a55")+    ]++testBase58ChkInvalidVector :: (Text, Maybe Text) -> Assertion+testBase58ChkInvalidVector (a, resM) =+    assertEqual+        "decodeBase58Check invalid match"+        resM+        (encodeHex <$> decodeBase58Check a)++base58ChkInvalidVectors :: [(Text, Maybe Text)]+base58ChkInvalidVectors =+    [ ("3vQB7B6MrGQZaxCuFg4oh", Just "68656c6c6f20776f726c64")+    , ("3vQB7B6MrGQZaxCuFg4oi", Nothing) +    , ("3vQB7B6MrGQZaxCuFg4oh0IOl", Nothing)+    , ("3vQB7B6MrGQZaxCuFg4oh\00IOl", Nothing)+    ]++testCompatWitnessVector :: (Network, Text, Text) -> Assertion+testCompatWitnessVector (net, seckey, addr) = do     let seckeyM = fromWif net seckey     assertBool "decode seckey" (isJust seckeyM)     let pubkey = derivePubKeyI (fromJust seckeyM)-    let addrM = addrToString btcTest (pubKeyCompatWitnessAddr pubkey)+    let addrM = addrToText btcTest (pubKeyCompatWitnessAddr pubkey)     assertBool "address can be encoded" (isJust addrM)     assertEqual "witness address matches" addr (fromJust addrM)++compatWitnessVectors :: [(Network, Text, Text)]+compatWitnessVectors =+    [ ( btcTest+      , "cNUnpYpMsJXYCERYBciJnsWBpcYEFjdcbq6dxj4SskGhs7uHuJ7Q"+      , "2N6PDTueBHvXzW61B4oe5SW1D3v2Z3Vpbvw")+    ]
test/Haskoin/Crypto/HashSpec.hs view
@@ -1,19 +1,25 @@ {-# LANGUAGE OverloadedStrings #-} module Haskoin.Crypto.HashSpec (spec) where +import           Data.Bits import           Data.ByteString         (ByteString)-import           Data.Map.Strict         (singleton)+import           Data.ByteString.Builder+import qualified Data.ByteString.Char8   as C+import qualified Data.ByteString.Lazy    as BL+import qualified Data.ByteString.Short   as BSS import           Data.Maybe              (fromJust) import           Data.Serialize          as S import           Data.String             (fromString) import           Data.String.Conversions+import           Data.Text               (Text)+import           Data.Word import           Haskoin.Block import           Haskoin.Crypto import           Haskoin.Util import           Haskoin.Util.Arbitrary import           Test.Hspec import           Test.Hspec.QuickCheck-import           Test.HUnit              (Assertion, assertBool)+import           Test.HUnit import           Test.QuickCheck  serialVals :: [SerialBox]@@ -36,20 +42,34 @@  spec :: Spec spec =-    describe "hash" $ do+    describe "Hash" $ do         testIdentity serialVals readVals [] []-        prop "join512( split512(h) ) == h" $-            forAll arbitraryHash256 $ forAll arbitraryHash256 . joinSplit512-        prop "decodeCompact . encodeCompact i == i" decEncCompact-        prop "from string 64-byte hash" $-            forAll arbitraryHash512 $ \h ->-                fromString (cs $ encodeHex $ encode h) == h-        prop "from string 32-byte hash" $-            forAll arbitraryHash256 $ \h ->-                fromString (cs $ encodeHex $ encode h) == h-        prop "from string 20-byte hash" $-            forAll arbitraryHash160 $ \h ->-                fromString (cs $ encodeHex $ encode h) == h+        describe "Property Tests" $ do+            prop "join512( split512(h) ) == h" $+                forAll arbitraryHash256 $ forAll arbitraryHash256 . joinSplit512+            prop "decodeCompact . encodeCompact i == i" decEncCompact+            prop "from string Hash512" $+                forAll arbitraryHash512 $ \h ->+                    fromString (cs $ encodeHex $ encode h) == h+            prop "from string Hash256" $+                forAll arbitraryHash256 $ \h ->+                    fromString (cs $ encodeHex $ encode h) == h+            prop "from string Hash160" $+                forAll arbitraryHash160 $ \h ->+                    fromString (cs $ encodeHex $ encode h) == h+        describe "Test Vectors" $ do+            it "Passes RIPEMD160 test vectors" $+                mapM_ (testVector ripemd160 getHash160) ripemd160Vectors+            it "Passes SHA1 test vectors" $+                mapM_ (testVector sha1 getHash160) sha1Vectors+            it "Passes SHA256 test vectors" $+                mapM_ (testVector sha256 getHash256) sha256Vectors+            it "Passes SHA512 test vectors" $+                mapM_ (testVector sha512 getHash512) sha512Vectors+            it "Passes HMAC_SHA256 test vectors" $+                mapM_ (testHMACVector hmac256 getHash256) hmacSha256Vectors+            it "Passes HMAC_SHA512 test vectors" $+                mapM_ (testHMACVector hmac512 getHash512) hmacSha512Vectors  joinSplit512 :: Hash256 -> Hash256 -> Bool joinSplit512 a b = split512 (join512 (a, b)) == (a, b)@@ -64,3 +84,258 @@     -- be smaller than the original number     | i >= 0 = fst (decodeCompact (encodeCompact i)) < i     | otherwise = fst (decodeCompact (encodeCompact i)) > i++-- Test vectors from:+-- https://github.com/bitcoin/bitcoin/blob/master/src/test/crypto_tests.cpp++testVector ::+       (ByteString -> a)+    -> (a -> BSS.ShortByteString)+    -> (ByteString, Text)+    -> Assertion+testVector f1 f2 (i, res) =+    assertEqual "Hash matches" res (encodeHex (BSS.fromShort $ f2 $ f1 i))++testHMACVector ::+       (ByteString -> ByteString -> a)+    -> (a -> BSS.ShortByteString)+    -> (Text, Text, Text)+    -> Assertion+testHMACVector f1 f2 (k, m, res) =+    assertEqual "Hash matches" res (encodeHex (BSS.fromShort $ f2 $ f1 bsK bsM))+  where+    bsK = fromJust $ decodeHex k+    bsM = fromJust $ decodeHex m++longTestString :: ByteString+longTestString =+    BL.toStrict $! toLazyByteString $! go [0 .. 199999]+  where+    go :: [Word32] -> Builder+    go [] = mempty+    go (i:is) =+        let i1 = fromIntegral $! i+            i2 = fromIntegral $! i `shiftR` 4+            i3 = fromIntegral $! i `shiftR` 8+            i4 = fromIntegral $! i `shiftR` 12+            i5 = fromIntegral $! i `shiftR` 16+         in word8 i1 <> word8 i2 <> word8 i3 <> word8 i4 <> word8 i5 <> go is++ripemd160Vectors :: [(ByteString, Text)]+ripemd160Vectors =+    [ ("", "9c1185a5c5e9fc54612808977ee8f548b2258d31")+    , ("abc", "8eb208f7e05d987a9b044a8e98c6b087f15a0bfc")+    , ("message digest", "5d0689ef49d2fae572b881b123a85ffa21595f36")+    , ("secure hash algorithm", "20397528223b6a5f4cbc2808aba0464e645544f9")+    , ( "RIPEMD160 is considered to be safe"+      , "a7d78608c7af8a8e728778e81576870734122b66")+    , ( "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"+      , "12a053384a9c0c88e405a06c27dcf49ada62eb2b")+    , ( "For this sample, this 63-byte string will be used as input data"+      , "de90dbfee14b63fb5abf27c2ad4a82aaa5f27a11")+    , ( "This is exactly 64 bytes long, not counting the terminating byte"+      , "eda31d51d3a623b81e19eb02e24ff65d27d67b37")+    , (C.replicate 1000000 'a', "52783243c1697bdbe16d37f97f68f08325dc1528")+    , (longTestString, "464243587bd146ea835cdf57bdae582f25ec45f1")+    ]++sha1Vectors :: [(ByteString, Text)]+sha1Vectors =+    [ ("", "da39a3ee5e6b4b0d3255bfef95601890afd80709")+    , ("abc", "a9993e364706816aba3e25717850c26c9cd0d89d")+    , ("message digest", "c12252ceda8be8994d5fa0290a47231c1d16aae3")+    , ("secure hash algorithm", "d4d6d2f0ebe317513bbd8d967d89bac5819c2f60")+    , ( "SHA1 is considered to be safe"+      , "f2b6650569ad3a8720348dd6ea6c497dee3a842a")+    , ( "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"+      , "84983e441c3bd26ebaae4aa1f95129e5e54670f1")+    , ( "For this sample, this 63-byte string will be used as input data"+      , "4f0ea5cd0585a23d028abdc1a6684e5a8094dc49")+    , ( "This is exactly 64 bytes long, not counting the terminating byte"+      , "fb679f23e7d1ce053313e66e127ab1b444397057")+    , (C.replicate 1000000 'a', "34aa973cd4c4daa4f61eeb2bdbad27316534016f")+    , (longTestString, "b7755760681cbfd971451668f32af5774f4656b5")+    ]++sha256Vectors :: [(ByteString, Text)]+sha256Vectors =+    [ ("", "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855")+    , ( "abc"+      , "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad")+    , ( "message digest"+      , "f7846f55cf23e14eebeab5b4e1550cad5b509e3348fbc4efa3a1413d393cb650")+    , ( "secure hash algorithm"+      , "f30ceb2bb2829e79e4ca9753d35a8ecc00262d164cc077080295381cbd643f0d")+    , ( "SHA256 is considered to be safe"+      , "6819d915c73f4d1e77e4e1b52d1fa0f9cf9beaead3939f15874bd988e2a23630")+    , ( "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"+      , "248d6a61d20638b8e5c026930c3e6039a33ce45964ff2167f6ecedd419db06c1")+    , ( "For this sample, this 63-byte string will be used as input data"+      , "f08a78cbbaee082b052ae0708f32fa1e50c5c421aa772ba5dbb406a2ea6be342")+    , ( "This is exactly 64 bytes long, not counting the terminating byte"+      , "ab64eff7e88e2e46165e29f2bce41826bd4c7b3552f6b382a9e7d3af47c245f8")+    , ( "As Bitcoin relies on 80 byte header hashes, we want to have an example for that."+      , "7406e8de7d6e4fffc573daef05aefb8806e7790f55eab5576f31349743cca743")+    , ( C.replicate 1000000 'a'+      , "cdc76e5c9914fb9281a1c7e284d73e67f1809a48a497200e046d39ccc7112cd0")+    , ( longTestString+      , "a316d55510b49662420f49d145d42fb83f31ef8dc016aa4e32df049991a91e26")+    ]++sha512Vectors :: [(ByteString, Text)]+sha512Vectors =+    [ ( ""+      , "cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d1\+        \3c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e")+    , ( "abc"+      , "ddaf35a193617abacc417349ae20413112e6fa4e89a97ea20a9eeee64b55d39a219299\+        \2a274fc1a836ba3c23a3feebbd454d4423643ce80e2a9ac94fa54ca49f")+    , ( "message digest"+      , "107dbf389d9e9f71a3a95f6c055b9251bc5268c2be16d6c13492ea45b0199f3309e164\+        \55ab1e96118e8a905d5597b72038ddb372a89826046de66687bb420e7c")+    , ( "secure hash algorithm"+      , "7746d91f3de30c68cec0dd693120a7e8b04d8073cb699bdce1a3f64127bca7a3d5db50\+        \2e814bb63c063a7a5043b2df87c61133395f4ad1edca7fcf4b30c3236e")+    , ( "SHA512 is considered to be safe"+      , "099e6468d889e1c79092a89ae925a9499b5408e01b66cb5b0a3bd0dfa51a99646b4a39\+        \01caab1318189f74cd8cf2e941829012f2449df52067d3dd5b978456c2")+    , ( "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"+      , "204a8fc6dda82f0a0ced7beb8e08a41657c16ef468b228a8279be331a703c33596fd15\+        \c13b1b07f9aa1d3bea57789ca031ad85c7a71dd70354ec631238ca3445")+    , ( "For this sample, this 63-byte string will be used as input data"+      , "b3de4afbc516d2478fe9b518d063bda6c8dd65fc38402dd81d1eb7364e72fb6e6663cf\+        \6d2771c8f5a6da09601712fb3d2a36c6ffea3e28b0818b05b0a8660766")+    , ( "This is exactly 64 bytes long, not counting the terminating byte"+      , "70aefeaa0e7ac4f8fe17532d7185a289bee3b428d950c14fa8b713ca09814a387d2458\+        \70e007a80ad97c369d193e41701aa07f3221d15f0e65a1ff970cedf030")+    , ( "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmn\+        \opjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu"+      , "8e959b75dae313da8cf4f72814fc143f8f7779c6eb9f7fa17299aeadb6889018501d28\+        \9e4900f7e4331b99dec4b5433ac7d329eeb6dd26545e96e55b874be909")+    , ( C.replicate 1000000 'a'+      , "e718483d0ce769644e2e42c7bc15b4638e1f98b13b2044285632a803afa973ebde0ff2\+        \44877ea60a4cb0432ce577c31beb009c5c2c49aa2e4eadb217ad8cc09b")+    , ( longTestString+      , "40cac46c147e6131c5193dd5f34e9d8bb4951395f27b08c558c65ff4ba2de59437de8c\+        \3ef5459d76a52cedc02dc499a3c9ed9dedbfb3281afd9653b8a112fafc")+    ]++-- test cases 1, 2, 3, 4, 6 and 7 of RFC 4231+hmacSha256Vectors :: [(Text, Text, Text)]+hmacSha256Vectors =+    [ ( "0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b"+      , "4869205468657265"+      , "b0344c61d8db38535ca8afceaf0bf12b881dc200c9833da726e9376c2e32cff7")+    , ( "4a656665"+      , "7768617420646f2079612077616e7420666f72206e6f7468696e673f"+      , "5bdcc146bf60754e6a042426089575c75a003f089d2739839dec58b964ec3843")+    , ( "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"+      , "dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd\+        \dddddddddddddddddddddddddddddd"+      , "773ea91e36800e46854db8ebd09181a72959098b3ef8c122d9635514ced565fe")+    , ( "0102030405060708090a0b0c0d0e0f10111213141516171819"+      , "cdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd\+        \cdcdcdcdcdcdcdcdcdcdcdcdcdcdcd"+      , "82558a389a443c0ea4cc819899f2083a85f0faa3e578f8077a2e3ff46729665b")+    , ( "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\+        \aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\+        \aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\+        \aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"+      , "54657374205573696e67204c6172676572205468616e20426c6f636b2d53697a65204b\+        \6579202d2048617368204b6579204669727374"+      , "60e431591ee0b67f0d8a26aacbf5b77f8e0bc6213728c5140546040f0ee37f54")+    , ( "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\+        \aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\+        \aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\+        \aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"+      , "5468697320697320612074657374207573696e672061206c6172676572207468616e20\+        \626c6f636b2d73697a65206b657920616e642061206c6172676572207468616e20626c\+        \6f636b2d73697a6520646174612e20546865206b6579206e6565647320746f20626520\+        \686173686564206265666f7265206265696e6720757365642062792074686520484d41\+        \4320616c676f726974686d2e"+      , "9b09ffa71b942fcb27635fbcd5b0e944bfdc63644f0713938a7f51535c3a35e2")+      -- Test case with key length 63 bytes.+    , ( "4a6566654a6566654a6566654a6566654a6566654a6566654a6566654a6566654a6566\+        \654a6566654a6566654a6566654a6566654a6566654a6566654a6566"+      , "7768617420646f2079612077616e7420666f72206e6f7468696e673f"+      , "9de4b546756c83516720a4ad7fe7bdbeac4298c6fdd82b15f895a6d10b0769a6")+      -- Test case with key length 64 bytes.+    , ( "4a6566654a6566654a6566654a6566654a6566654a6566654a6566654a6566654a6566\+        \654a6566654a6566654a6566654a6566654a6566654a6566654a656665"+      , "7768617420646f2079612077616e7420666f72206e6f7468696e673f"+      , "528c609a4c9254c274585334946b7c2661bad8f1fc406b20f6892478d19163dd")+      -- Test case with key length 65 bytes.+    , ( "4a6566654a6566654a6566654a6566654a6566654a6566654a6566654a6566654a6566\+        \654a6566654a6566654a6566654a6566654a6566654a6566654a6566654a"+      , "7768617420646f2079612077616e7420666f72206e6f7468696e673f"+      , "d06af337f359a2330deffb8e3cbe4b5b7aa8ca1f208528cdbd245d5dc63c4483")+    ]++-- test cases 1, 2, 3, 4, 6 and 7 of RFC 4231+hmacSha512Vectors :: [(Text, Text, Text)]+hmacSha512Vectors =+    [ ( "0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b"+      , "4869205468657265"+      , "87aa7cdea5ef619d4ff0b4241a1d6cb02379f4e2ce4ec2787ad0b30545e17cde\+        \daa833b7d6b8a702038b274eaea3f4e4be9d914eeb61f1702e696c203a126854")+    , ( "4a656665"+      , "7768617420646f2079612077616e7420666f72206e6f7468696e673f"+      , "164b7a7bfcf819e2e395fbe73b56e0a387bd64222e831fd610270cd7ea250554\+        \9758bf75c05a994a6d034f65f8f0e6fdcaeab1a34d4a6b4b636e070a38bce737")+    , ( "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"+      , "dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd\+        \dddddddddddddddddddddddddddddddddddd"+      , "fa73b0089d56a284efb0f0756c890be9b1b5dbdd8ee81a3655f83e33b2279d39\+        \bf3e848279a722c806b485a47e67c807b946a337bee8942674278859e13292fb")+    , ( "0102030405060708090a0b0c0d0e0f10111213141516171819"+      , "cdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd\+        \cdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd"+      , "b0ba465637458c6990e5a8c5f61d4af7e576d97ff94b872de76f8050361ee3db\+        \a91ca5c11aa25eb4d679275cc5788063a5f19741120c4f2de2adebeb10a298dd")+    , ( "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\+        \aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\+        \aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\+        \aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\+        \aaaaaa"+      , "54657374205573696e67204c6172676572205468616e20426c6f636b2d53697a\+        \65204b6579202d2048617368204b6579204669727374"+      , "80b24263c7c1a3ebb71493c1dd7be8b49b46d1f41b4aeec1121b013783f8f352\+        \6b56d037e05f2598bd0fd2215d6a1e5295e64f73f63f0aec8b915a985d786598")+    , ( "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\+        \aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\+        \aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\+        \aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\+        \aaaaaa"+      , "5468697320697320612074657374207573696e672061206c6172676572207468\+        \616e20626c6f636b2d73697a65206b657920616e642061206c61726765722074\+        \68616e20626c6f636b2d73697a6520646174612e20546865206b6579206e6565\+        \647320746f20626520686173686564206265666f7265206265696e6720757365\+        \642062792074686520484d414320616c676f726974686d2e"+      , "e37b6a775dc87dbaa4dfa9f96e5e3ffddebd71f8867289865df5a32d20cdc944\+        \b6022cac3c4982b10d5eeb55c3e4de15134676fb6de0446065c97440fa8c6a58")+      -- Test case with key length 127 bytes.+    , ( "4a6566654a6566654a6566654a6566654a6566654a6566654a6566654a656665\+        \4a6566654a6566654a6566654a6566654a6566654a6566654a6566654a656665\+        \4a6566654a6566654a6566654a6566654a6566654a6566654a6566654a656665\+        \4a6566654a6566654a6566654a6566654a6566654a6566654a6566654a6566"+      , "7768617420646f2079612077616e7420666f72206e6f7468696e673f"+      , "267424dfb8eeb999f3e5ec39a4fe9fd14c923e6187e0897063e5c9e02b2e624a\+        \c04413e762977df71a9fb5d562b37f89dfdfb930fce2ed1fa783bbc2a203d80e")+      -- Test case with key length 128 bytes.+    , ( "4a6566654a6566654a6566654a6566654a6566654a6566654a6566654a656665\+        \4a6566654a6566654a6566654a6566654a6566654a6566654a6566654a656665\+        \4a6566654a6566654a6566654a6566654a6566654a6566654a6566654a656665\+        \4a6566654a6566654a6566654a6566654a6566654a6566654a6566654a656665"+      , "7768617420646f2079612077616e7420666f72206e6f7468696e673f"+      , "43aaac07bb1dd97c82c04df921f83b16a68d76815cd1a30d3455ad43a3d80484\+        \2bb35462be42cc2e4b5902de4d204c1c66d93b47d1383e3e13a3788687d61258")+      -- Test case with key length 129 bytes.+    , ( "4a6566654a6566654a6566654a6566654a6566654a6566654a6566654a656665\+        \4a6566654a6566654a6566654a6566654a6566654a6566654a6566654a656665\+        \4a6566654a6566654a6566654a6566654a6566654a6566654a6566654a656665\+        \4a6566654a6566654a6566654a6566654a6566654a6566654a6566654a656665\+        \4a"+      , "7768617420646f2079612077616e7420666f72206e6f7468696e673f"+      , "0b273325191cfc1b4b71d5075c8fcad67696309d292b1dad2cd23983a35feb8e\+        \fb29795e79f2ef27f68cb1e16d76178c307a67beaad9456fac5fdffeadb16e2c")+    ]
test/Haskoin/Crypto/SignatureSpec.hs view
@@ -1,66 +1,62 @@ {-# LANGUAGE OverloadedStrings #-} module Haskoin.Crypto.SignatureSpec (spec) where -import           Data.Bits              (testBit)-import           Data.ByteString        (ByteString)-import qualified Data.ByteString        as BS (index, length)-import           Data.Serialize         as S-import           Data.Text              (Text)-import           Haskoin.Crypto         (SecKey, Sig, decodeStrictSig,-                                         derivePubKey, exportSig,-                                         importCompactSig, isCanonicalHalfOrder,-                                         sha256, signHash, verifyHashSig)-import           Haskoin.Util           (decodeHex, eitherToMaybe, lst3)-import           Haskoin.Util.Arbitrary (arbitrarySignature)-import           Test.Hspec             (Spec, describe, it)-import           Test.Hspec.QuickCheck  (prop)-import           Test.HUnit             (Assertion, assertBool)-import           Test.QuickCheck        (forAll)+import           Control.Monad+import           Data.Bits               (testBit)+import           Data.ByteString         (ByteString)+import qualified Data.ByteString         as BS+import           Data.Map.Strict         (Map)+import qualified Data.Map.Strict         as Map+import           Data.Maybe+import           Data.Serialize          as S+import           Data.String.Conversions (cs)+import           Data.Text               (Text)+import           Haskoin.Address+import           Haskoin.Transaction+import           Haskoin.Keys+import           Haskoin.Crypto+import           Haskoin.Script+import           Haskoin.Constants+import           Haskoin.Util+import           Haskoin.Util.Arbitrary+import           Haskoin.UtilSpec        (readTestFile)+import           Test.Hspec+import           Test.Hspec.QuickCheck+import           Test.HUnit+import           Test.QuickCheck  spec :: Spec spec = do-    describe "signatures" $ do+    describe "Signature properties" $ do         prop "verify signature" $-            forAll arbitrarySignature $ \(msg, key, sig) ->-                verifyHashSig msg sig (derivePubKey key)+            forAll arbitrarySignature $ \(m, key', sig) ->+                verifyHashSig m sig (derivePubKey key')         prop "s component less than half order" $             forAll arbitrarySignature $ isCanonicalHalfOrder . lst3         prop "encoded signature is canonical" $             forAll arbitrarySignature $ testIsCanonical . lst3-        prop "encode signature and decode strictly" $+        prop "decodeStrictSig . exportSig identity" $             forAll arbitrarySignature $             (\s -> decodeStrictSig (exportSig s) == Just s) . lst3-        prop "encodes and decodes signature" $+        prop "importSig . exportSig identity" $             forAll arbitrarySignature $-            (\s -> decodeStrictSig (exportSig s) == Just s) . lst3-    describe "trezor rfc6979 test vectors" $ do-        it "rfc6979 test vector 1" (testSigning $ head detVec)-        it "rfc6979 test vector 2" (testSigning $ detVec !! 1)-        it "rfc6979 test vector 3" (testSigning $ detVec !! 2)-        it "rfc6979 test vector 4" (testSigning $ detVec !! 3)-        it "rfc6979 test vector 5" (testSigning $ detVec !! 4)-        it "rfc6979 test vector 6" (testSigning $ detVec !! 5)-        it "rfc6979 test vector 7" (testSigning $ detVec !! 6)-        it "rfc6979 test vector 8" (testSigning $ detVec !! 7)-        it "rfc6979 test vector 9" (testSigning $ detVec !! 8)-        it "rfc6979 test vector 10" (testSigning $ detVec !! 9)-        it "rfc6979 test vector 11" (testSigning $ detVec !! 10)-        it "rfc6979 test vector 12" (testSigning $ detVec !! 11)---- No longer validating that generated signature is exactly equal to provided--- one. Fedora includes libsecp256k1 from Bitcoin ABC that computes--- deterministic signatures using a slightly different nonce generation--- algorithm.-testSigning :: (SecKey, ByteString, Text) -> Assertion-testSigning (prv, msg, str) = do-    assertBool "my sig valid" $ verifyHashSig msg' g (derivePubKey prv)-    assertBool "valid sig" $ verifyHashSig msg' g' (derivePubKey prv)-  where-    Just g' = importCompactSig =<< eitherToMaybe . decode =<< decodeHex str-    g = signHash prv msg'-    msg' = sha256 msg--{- ECDSA Canonical -}+            (\s -> importSig (exportSig s) == Just s) . lst3+        prop "getSig . putSig identity" $+            forAll arbitrarySignature $+            (\s -> runGet getSig (runPut $ putSig s) == Right s) . lst3+    describe "Signature vectors" $+        checkDistSig $ \file1 file2 -> do+            vectors <- runIO (readTestFile file1 :: IO [(Text, Text, Text)])+            vectorsDER <- runIO (readTestFile file2 :: IO [(Text, Text, Text)])+            it "Passes the trezor rfc6979 test vectors" $+                mapM_ (testRFC6979Vector . toVector) vectors+            it "Passes the rfc6979 DER test vectors" $+                mapM_ (testRFC6979DERVector . toVector) vectorsDER+    describe "BIP143 signature vectors" $ do+        it "agrees with BIP143 p2wpkh example" testBip143p2wpkh+        it "agrees with BIP143 p2sh-p2wpkh example" testBip143p2shp2wpkh+        it "builds a p2wsh multisig transaction" testP2WSHMulsig+        it "agrees with BIP143 p2sh-p2wsh multisig example" testBip143p2shp2wpkhMulsig  -- github.com/bitcoin/bitcoin/blob/master/src/script.cpp -- from function IsCanonicalSignature@@ -80,6 +76,7 @@     (rlen + slen + 6 /= len) ||     -- Non-canonical signature: R value type mismatch     (BS.index s 2 /= 0x02) ||+     -- Non-canonical signature: R length is zero     (rlen == 0) ||     -- Non-canonical signature: R value negative@@ -106,58 +103,324 @@     rlen = BS.index s 3     slen = BS.index s (fromIntegral rlen + 5) +-- RFC6979 note: Different libraries of libsecp256k1 use different constants+-- to produce a nonce. Thus, their deterministric signatures will be different.+-- We still want to test against fixed signatures so we need a way to switch+-- between implementations. We check the output of signMsg 1 0++data ValidImpl+    = ImplCore+    | ImplABC++implSig :: Text+implSig =+    encodeHex $+    exportSig $+    signMsg+        "0000000000000000000000000000000000000000000000000000000000000001"+        "0000000000000000000000000000000000000000000000000000000000000000"++-- We have test vectors for these cases+validImplMap :: Map Text ValidImpl+validImplMap =+    Map.fromList+        [ ( "3045022100a0b37f8fba683cc68f6574cd43b39f0343a50008bf6ccea9d13231\+            \d9e7e2e1e4022011edc8d307254296264aebfc3dc76cd8b668373a072fd64665\+            \b50000e9fcce52"+          , ImplCore)+        , ( "304402200581361d23e645be9e3efe63a9a2ac2e8dd0c70ba3ac8554c9befe06\+            \0ad0b36202207d8172f1e259395834793d81b17e986f1e6131e4734969d2f4ae\+            \3a9c8bc42965"+          , ImplABC)+        ]++getImpl :: Maybe ValidImpl+getImpl = implSig `Map.lookup` validImplMap++rfc6979files :: ValidImpl -> (FilePath, FilePath)+rfc6979files ImplCore = ("rfc6979core.json", "rfc6979DERcore.json")+rfc6979files ImplABC = ("rfc6979abc.json", "rfc6979DERabc.json")++checkDistSig :: (FilePath -> FilePath -> Spec) -> Spec+checkDistSig go =+    case rfc6979files <$> getImpl of+        Just (file1, file2) -> go file1 file2+        _ ->+            it "Passes rfc6979 test vectors" $+            void $ assertFailure "Invalid rfc6979 signature"+ {- Trezor RFC 6979 Test Vectors -} -- github.com/trezor/python-ecdsa/blob/master/ecdsa/test_pyecdsa.py -detVec :: [(SecKey, ByteString, Text)]-detVec =-    [-      ( "0000000000000000000000000000000000000000000000000000000000000001"-      , "Satoshi Nakamoto"-      , "934b1ea10a4b3c1757e2b0c017d0b6143ce3c9a7e6a4a49860d7a6ab210ee3d82442ce9d2b916064108014783e923ec36b49743e2ffa1c4496f01a512aafd9e5"-      )-    , ( "0000000000000000000000000000000000000000000000000000000000000001"-      , "All those moments will be lost in time, like tears in rain. Time to die..."-      , "8600dbd41e348fe5c9465ab92d23e3db8b98b873beecd930736488696438cb6b547fe64427496db33bf66019dacbf0039c04199abb0122918601db38a72cfc21"-      )-    , ( "fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364140"-      , "Satoshi Nakamoto"-      , "fd567d121db66e382991534ada77a6bd3106f0a1098c231e47993447cd6af2d06b39cd0eb1bc8603e159ef5c20a5c8ad685a45b06ce9bebed3f153d10d93bed5"-      )-    , ( "f8b8af8ce3c7cca5e300d33939540c10d45ce001b8f252bfbc57ba0342904181"-      , "Alan Turing"-      , "7063ae83e7f62bbb171798131b4a0564b956930092b33b07b395615d9ec7e15c58dfcc1e00a35e1572f366ffe34ba0fc47db1e7189759b9fb233c5b05ab388ea"-      )-    , ( "e91671c46231f833a6406ccbea0e3e392c76c167bac1cb013f6f1013980455c2"-      , "There is a computer disease that anybody who works with computers knows about. It's a very serious disease and it interferes completely with the work. The trouble with computers is that you 'play' with them!"-      , "b552edd27580141f3b2a5463048cb7cd3e047b97c9f98076c32dbdf85a68718b279fa72dd19bfae05577e06c7c0c1900c371fcd5893f7e1d56a37d30174671f6"-      )-    , ( "0000000000000000000000000000000000000000000000000000000000000001"-      , "Everything should be made as simple as possible, but not simpler."-      , "33a69cd2065432a30f3d1ce4eb0d59b8ab58c74f27c41a7fdb5696ad4e6108c96f807982866f785d3f6418d24163ddae117b7db4d5fdf0071de069fa54342262"-      )-    , ( "fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364140"-      , "Equations are more important to me, because politics is for the present, but an equation is something for eternity."-      , "54c4a33c6423d689378f160a7ff8b61330444abb58fb470f96ea16d99d4a2fed07082304410efa6b2943111b6a4e0aaa7b7db55a07e9861d1fb3cb1f421044a5"-      )-    , ( "fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364140"-      , "Not only is the Universe stranger than we think, it is stranger than we can think."-      , "ff466a9f1b7b273e2f4c3ffe032eb2e814121ed18ef84665d0f515360dab3dd06fc95f5132e5ecfdc8e5e6e616cc77151455d46ed48f5589b7db7771a332b283"-      )-    , ( "0000000000000000000000000000000000000000000000000000000000000001"-      , "How wonderful that we have met with a paradox. Now we have some hope of making progress."-      , "c0dafec8251f1d5010289d210232220b03202cba34ec11fec58b3e93a85b91d375afdc06b7d6322a590955bf264e7aaa155847f614d80078a90292fe205064d3"-      )-    , ( "69ec59eaa1f4f2e36b639716b7c30ca86d9a5375c7b38d8918bd9c0ebc80ba64"-      , "Computer science is no more about computers than astronomy is about telescopes."-      , "7186363571d65e084e7f02b0b77c3ec44fb1b257dee26274c38c928986fea45d0de0b38e06807e46bda1f1e293f4f6323e854c86d58abdd00c46c16441085df6"-      )-    , ( "00000000000000000000000000007246174ab1e92e9149c6e446fe194d072637"-      , "...if you aren't, at any given time, scandalized by code you wrote five or even three years ago, you're not learning anywhere near enough"-      , "fbfe5076a15860ba8ed00e75e9bd22e05d230f02a936b653eb55b61c99dda4870e68880ebb0050fe4312b1b1eb0899e1b82da89baa5b895f612619edf34cbd37"-      )-    , ( "000000000000000000000000000000000000000000056916d0f9b31dc9b637f3"-      , "The question of whether computers can think is like the question of whether submarines can swim."-      , "cde1302d83f8dd835d89aef803c74a119f561fbaef3eb9129e45f30de86abbf906ce643f5049ee1f27890467b77a6a8e11ec4661cc38cd8badf90115fbd03cef"-      )-    ]+toVector :: (Text, Text, Text) -> (SecKey, ByteString, Text)+toVector (prv, m, res) = (fromJust $ (secKey <=< decodeHex) prv, cs m, res)++testRFC6979Vector :: (SecKey, ByteString, Text) -> Assertion+testRFC6979Vector (prv, m, res) = do+    assertEqual "RFC 6979 Vector" res (encodeHex $ encode $ exportCompactSig s)+    assertBool "Signature is valid" $ verifyHashSig h s (derivePubKey prv)+    assertBool "Signature is canonical" $ testIsCanonical s+    assertBool "Signature is normalized" $ isCanonicalHalfOrder s+  where+    h = sha256 m+    s = signHash prv h++-- Test vectors from:+-- https://crypto.stackexchange.com/questions/20838/request-for-data-to-test-deterministic-ecdsa-signature-algorithm-for-secp256k1++testRFC6979DERVector :: (SecKey, ByteString, Text) -> Assertion+testRFC6979DERVector (prv, m, res) = do+    assertEqual "RFC 6979 DER Vector" res (encodeHex $ exportSig s)+    assertBool "DER Signature is valid" $ verifyHashSig h s (derivePubKey prv)+    assertBool "DER Signature is canonical" $ testIsCanonical s+    assertBool "DER Signature is normalized" $ isCanonicalHalfOrder s+  where+    h = sha256 m+    s = signHash prv h++-- Reproduce the P2WPKH example from BIP 143+testBip143p2wpkh :: Assertion+testBip143p2wpkh =+    case getImpl of+        Just ImplCore ->+            assertEqual "BIP143 Core p2wpkh" (Right signedTxCore) generatedSignedTx+        Just ImplABC ->+            assertEqual "BIP143 ABC p2wpkh" (Right signedTxABC) generatedSignedTx+        Nothing -> assertFailure "Invalid secp256k1 library"+  where+    signedTxCore =+        "01000000000102fff7f7881a8099afa6940d42d1e7f6362bec38171ea3edf433\+        \541db4e4ad969f00000000494830450221008b9d1dc26ba6a9cb62127b02742f\+        \a9d754cd3bebf337f7a55d114c8e5cdd30be022040529b194ba3f9281a99f2b1\+        \c0a19c0489bc22ede944ccf4ecbab4cc618ef3ed01eeffffffef51e1b804cc89\+        \d182d279655c3aa89e815b1b309fe287d9b2b55d57b90ec68a0100000000ffff\+        \ffff02202cb206000000001976a9148280b37df378db99f66f85c95a783a76ac\+        \7a6d5988ac9093510d000000001976a9143bde42dbee7e4dbe6a21b2d50ce2f0\+        \167faa815988ac000247304402203609e17b84f6a7d30c80bfa610b5b4542f32\+        \a8a0d5447a12fb1366d7f01cc44a0220573a954c4518331561406f90300e8f33\+        \58f51928d43c212a8caed02de67eebee0121025476c2e83188368da1ff3e292e\+        \7acafcdb3566bb0ad253f62fc70f07aeee635711000000"+    signedTxABC =+        "01000000000102fff7f7881a8099afa6940d42d1e7f6362bec38171ea3edf433\+        \541db4e4ad969f000000004847304402200fbc9dad97500334e47c2dca50096a\+        \2117c01952c2870102e320823d21c36229022007cb36c2b141d11c08ef81d948\+        \f148332fc09fe8f6d226aaaf8ba6ae0d8a66ba01eeffffffef51e1b804cc89d1\+        \82d279655c3aa89e815b1b309fe287d9b2b55d57b90ec68a0100000000ffffff\+        \ff02202cb206000000001976a9148280b37df378db99f66f85c95a783a76ac7a\+        \6d5988ac9093510d000000001976a9143bde42dbee7e4dbe6a21b2d50ce2f016\+        \7faa815988ac0002473044022011cb891cee521eb1fc7aef681655a881288553\+        \fc024cff9cee5007bae5e6b8c602200b89d60ee2f98aa9a645dad59cd680b4b6\+        \25f343efcd3e7fb70852100ef601890121025476c2e83188368da1ff3e292e7a\+        \cafcdb3566bb0ad253f62fc70f07aeee635711000000"+    unsignedTx =+        "0100000002fff7f7881a8099afa6940d42d1e7f6362bec38171ea3edf433541d\+        \b4e4ad969f0000000000eeffffffef51e1b804cc89d182d279655c3aa89e815b\+        \1b309fe287d9b2b55d57b90ec68a0100000000ffffffff02202cb20600000000\+        \1976a9148280b37df378db99f66f85c95a783a76ac7a6d5988ac9093510d0000\+        \00001976a9143bde42dbee7e4dbe6a21b2d50ce2f0167faa815988ac11000000"+    Just key0 =+        secHexKey+            "bbc27228ddcb9209d7fd6f36b02f7dfa6252af40bb2f1cbc7a557da8027ff866"+    pubKey0 = toPubKey key0+    Just key1 =+        secHexKey+            "619c335025c7f4012e556c2a58b2506e30b8511b53ade95ea316fd8c3286feb9"+    [op0, op1] = prevOutput <$> txIn unsignedTx+    sigIn0 = SigInput (PayPK pubKey0) 625000000 op0 sigHashAll Nothing+    WitnessPubKeyAddress h = pubKeyWitnessAddr $ toPubKey key1+    sigIn1 = SigInput (PayWitnessPKHash h) 600000000 op1 sigHashAll Nothing+    generatedSignedTx = signTx btc unsignedTx [sigIn0, sigIn1] [key0, key1]++-- Reproduce the P2SH-P2WPKH example from BIP 143+testBip143p2shp2wpkh :: Assertion+testBip143p2shp2wpkh =+    case getImpl of+        Just ImplCore ->+            assertEqual "BIP143 Core p2sh-p2wpkh" (Right signedTxCore) generatedSignedTx+        Just ImplABC ->+            assertEqual "BIP143 ABC p2sh-p2wpkh" (Right signedTxABC) generatedSignedTx+        Nothing -> assertFailure "Invalid secp256k1 library"+  where+    signedTxCore =+        "01000000000101db6b1b20aa0fd7b23880be2ecbd4a98130974cf4748fb66092\+        \ac4d3ceb1a5477010000001716001479091972186c449eb1ded22b78e40d009b\+        \df0089feffffff02b8b4eb0b000000001976a914a457b684d7f0d539a46a45bb\+        \c043f35b59d0d96388ac0008af2f000000001976a914fd270b1ee6abcaea97fe\+        \a7ad0402e8bd8ad6d77c88ac02473044022047ac8e878352d3ebbde1c94ce3a1\+        \0d057c24175747116f8288e5d794d12d482f0220217f36a485cae903c713331d\+        \877c1f64677e3622ad4010726870540656fe9dcb012103ad1d8e89212f0b92c7\+        \4d23bb710c00662ad1470198ac48c43f7d6f93a2a2687392040000"+    signedTxABC =+        "01000000000101db6b1b20aa0fd7b23880be2ecbd4a98130974cf4748fb66092\+        \ac4d3ceb1a5477010000001716001479091972186c449eb1ded22b78e40d009b\+        \df0089feffffff02b8b4eb0b000000001976a914a457b684d7f0d539a46a45bb\+        \c043f35b59d0d96388ac0008af2f000000001976a914fd270b1ee6abcaea97fe\+        \a7ad0402e8bd8ad6d77c88ac024730440220091c78fd1e21535f6ddc45515e4c\+        \afca15cdf344765d72c1529fb82d3ada2d1802204a980d5e37d0b04f5e1185a0\+        \f97295c383764e9a4b08d8bd1161b33c6719139a012103ad1d8e89212f0b92c7\+        \4d23bb710c00662ad1470198ac48c43f7d6f93a2a2687392040000"+    unsignedTx =+        "0100000001db6b1b20aa0fd7b23880be2ecbd4a98130974cf4748fb66092ac4d\+        \3ceb1a54770100000000feffffff02b8b4eb0b000000001976a914a457b684d7\+        \f0d539a46a45bbc043f35b59d0d96388ac0008af2f000000001976a914fd270b\+        \1ee6abcaea97fea7ad0402e8bd8ad6d77c88ac92040000"+    Just key0 =+        secHexKey+            "eb696a065ef48a2192da5b28b694f87544b30fae8327c4510137a922f32c6dcf"+    op0 = prevOutput . head $ txIn unsignedTx+    WitnessPubKeyAddress h = pubKeyWitnessAddr $ toPubKey key0+    sigIn0 = SigInput (PayWitnessPKHash h) 1000000000 op0 sigHashAll Nothing+    generatedSignedTx = signNestedWitnessTx btc unsignedTx [sigIn0] [key0]++-- P2WSH multisig example (tested against bitcoin-core 0.19.0.1)+testP2WSHMulsig :: Assertion+testP2WSHMulsig =+    case getImpl of+        Just ImplCore ->+            assertEqual "Core p2wsh multisig" (Right signedTxCore) generatedSignedTx+        Just ImplABC ->+            assertEqual "ABC p2wsh multisig" (Right signedTxABC) generatedSignedTx+        Nothing -> assertFailure "Invalid secp256k1 library"+  where+    signedTxCore =+        "01000000000101d2e34df5d7ee565208eddd231548916b9b0e99f4f5071f8961\+        \34a448c5fb07bf0100000000ffffffff01f0b9f505000000001976a9143d5a35\+        \2cab583b12fbcb26d1269b4a2c951a33ad88ac0400483045022100fad4fedd2b\+        \b4c439c64637eb8e9150d9020a7212808b8dc0578d5ff5b4ad65fe0220714640\+        \f261b37eb3106310bf853f4b706e51436fb6b64c2ab00768814eb55b98014730\+        \44022100baff4e4ceea4022b9725a2e6f6d77997a554f858165b91ac8c16c983\+        \3008bee9021f5f70ebc3f8580dc0a5e96451e3697bdf1f1f5883944f0f33ab0c\+        \fb272354040169522102ba46d3bb8db74c77c6cf082db57fc0548058fcdea811\+        \549e186526e3d10caf6721038ac8aef2dd9cea5e7d66e2f6e23f177a6c21f69e\+        \a311fa0c85d81badb6b37ceb2103d96d2bfbbc040faaf93491d69e2bfe9695e2\+        \d8e007a7f26db96c2ee42db15dc953ae00000000"+    signedTxABC =+        "01000000000101d2e34df5d7ee565208eddd231548916b9b0e99f4f5071f8961\+        \34a448c5fb07bf0100000000ffffffff01f0b9f505000000001976a9143d5a35\+        \2cab583b12fbcb26d1269b4a2c951a33ad88ac0400483045022100b79bf3714a\+        \50f8f0e2f946034361ba4f6567b796d55910d89e98720d2e99f98c0220134879\+        \518002df23e80a058475fa8b10bc4182bedfecd5f85e446a00f211ea53014830\+        \45022100ce3c77480d664430a7544c1a962d1ae31151109a528a37e5bccc92ba\+        \2e460ad10220317bc9a71d0c3471058d16d4c3b1ea99616208db6b9b9040fb81\+        \0a7fa27f72b40169522102ba46d3bb8db74c77c6cf082db57fc0548058fcdea8\+        \11549e186526e3d10caf6721038ac8aef2dd9cea5e7d66e2f6e23f177a6c21f6\+        \9ea311fa0c85d81badb6b37ceb2103d96d2bfbbc040faaf93491d69e2bfe9695\+        \e2d8e007a7f26db96c2ee42db15dc953ae00000000"+    unsignedTx =+        "0100000001d2e34df5d7ee565208eddd231548916b9b0e99f4f5071f896134a4\+        \48c5fb07bf0100000000ffffffff01f0b9f505000000001976a9143d5a352cab\+        \583b12fbcb26d1269b4a2c951a33ad88ac00000000"+    op0 = head $ prevOutput <$> txIn unsignedTx+    Just keys =+        traverse+            secHexKey+            [ "3030303030303030303030303030303030303030303030303030303030303031"+            , "3030303030303030303030303030303030303030303030303030303030303032"+            , "3030303030303030303030303030303030303030303030303030303030303033"+            ]+    rdm = PayMulSig (toPubKey <$> keys) 2+    sigIn =+        SigInput+            (toP2WSH $ encodeOutput rdm)+            100000000+            op0+            sigHashAll+            (Just rdm)+    generatedSignedTx = signTx btc unsignedTx [sigIn] (take 2 keys)++-- Reproduce the P2SH-P2WSH multisig example from BIP 143+testBip143p2shp2wpkhMulsig :: Assertion+testBip143p2shp2wpkhMulsig =+    case getImpl of+        Just ImplCore ->+            assertEqual+                "BIP143 Core p2sh-p2wsh multisig"+                (Right signedTxCore)+                generatedSignedTx+        Just ImplABC ->+            assertEqual+                "BIP143 Core p2sh-p2wsh multisig"+                (Right signedTxABC)+                generatedSignedTx+        Nothing -> assertFailure "Invalid secp256k1 library"+  where+    signedTxCore =+        "0100000000010136641869ca081e70f394c6948e8af409e18b619df2ed74aa10\+        \6c1ca29787b96e0100000023220020a16b5755f7f6f96dbd65f5f0d6ab9418b8\+        \9af4b1f14a1bb8a09062c35f0dcb54ffffffff0200e9a435000000001976a914\+        \389ffce9cd9ae88dcc0631e88a821ffdbe9bfe2688acc0832f05000000001976\+        \a9147480a33f950689af511e6e84c138dbbd3c3ee41588ac080047304402206a\+        \c44d672dac41f9b00e28f4df20c52eeb087207e8d758d76d92c6fab3b73e2b02\+        \20367750dbbe19290069cba53d096f44530e4f98acaa594810388cf7409a1870\+        \ce01473044022068c7946a43232757cbdf9176f009a928e1cd9a1a8c212f15c1\+        \e11ac9f2925d9002205b75f937ff2f9f3c1246e547e54f62e027f64eefa26955\+        \78cc6432cdabce271502473044022059ebf56d98010a932cf8ecfec54c48e613\+        \9ed6adb0728c09cbe1e4fa0915302e022007cd986c8fa870ff5d2b3a89139c9f\+        \e7e499259875357e20fcbb15571c76795403483045022100fbefd94bd0a488d5\+        \0b79102b5dad4ab6ced30c4069f1eaa69a4b5a763414067e02203156c6a5c9cf\+        \88f91265f5a942e96213afae16d83321c8b31bb342142a14d163814830450221\+        \00a5263ea0553ba89221984bd7f0b13613db16e7a70c549a86de0cc0444141a4\+        \07022005c360ef0ae5a5d4f9f2f87a56c1546cc8268cab08c73501d6b3be2e1e\+        \1a8a08824730440220525406a1482936d5a21888260dc165497a90a15669636d\+        \8edca6b9fe490d309c022032af0c646a34a44d1f4576bf6a4a74b67940f8faa8\+        \4c7df9abe12a01a11e2b4783cf56210307b8ae49ac90a048e9b53357a2354b33\+        \34e9c8bee813ecb98e99a7e07e8c3ba32103b28f0c28bfab54554ae8c658ac5c\+        \3e0ce6e79ad336331f78c428dd43eea8449b21034b8113d703413d57761b8b97\+        \81957b8c0ac1dfe69f492580ca4195f50376ba4a21033400f6afecb833092a9a\+        \21cfdf1ed1376e58c5d1f47de74683123987e967a8f42103a6d48b1131e94ba0\+        \4d9737d61acdaa1322008af9602b3b14862c07a1789aac162102d8b661b0b330\+        \2ee2f162b09e07a55ad5dfbe673a9f01d9f0c19617681024306b56ae00000000"+    signedTxABC =+        "0100000000010136641869ca081e70f394c6948e8af409e18b619df2ed74aa10\+        \6c1ca29787b96e0100000023220020a16b5755f7f6f96dbd65f5f0d6ab9418b8\+        \9af4b1f14a1bb8a09062c35f0dcb54ffffffff0200e9a435000000001976a914\+        \389ffce9cd9ae88dcc0631e88a821ffdbe9bfe2688acc0832f05000000001976\+        \a9147480a33f950689af511e6e84c138dbbd3c3ee41588ac0800483045022100\+        \b70b684ef0d17b51adf71c0dae932beca5d447dd5eec03394328436bdba836e7\+        \0220208ebfd7408d21e41da11d8287655528385429d3fe300bee241f10944339\+        \5b580147304402204b5f9bc06c8f0a252b9842ea44785853beb1638002cec5f2\+        \489d73e5f6f5109302204f3b132b32638835d4b1a651e7d18dc93c10192db553\+        \999932af6a8e3d8a153202483045022100e0ed8d3a245a138c751d74e1359aee\+        \6a52476ddf33a3a9a5f0c2ad30147319650220581318187061ad0f48fc4f5c85\+        \1822e554d59977005b8de4b78bf2ce2fe8399703483045022100a0a40abc581e\+        \4b725775a3aa93bf0f0fd9a02ad3aa0f93483214784a47ba5387022069151c30\+        \f85a7e20c8671107c5af884ee4c5a82bd06398327fa68a993f7cc64b81473044\+        \022016d828460f6fab3cf89ae4b87c8f02c11c798cf739967f3b7406e7367c29\+        \ae8b022079e82b822eb6c37a66efabc3f0b40a2b98c52f848d36463f6623cbdc\+        \fe675812824730440220225a14ba7434858dbb5e6e0a0969ddf3b5455edaabf9\+        \9f5773d1f59e7816b918022047ed1ab87840a74f7e9489f3af051e5fd26b790f\+        \b308c79f4b0ed73c0422795d83cf56210307b8ae49ac90a048e9b53357a2354b\+        \3334e9c8bee813ecb98e99a7e07e8c3ba32103b28f0c28bfab54554ae8c658ac\+        \5c3e0ce6e79ad336331f78c428dd43eea8449b21034b8113d703413d57761b8b\+        \9781957b8c0ac1dfe69f492580ca4195f50376ba4a21033400f6afecb833092a\+        \9a21cfdf1ed1376e58c5d1f47de74683123987e967a8f42103a6d48b1131e94b\+        \a04d9737d61acdaa1322008af9602b3b14862c07a1789aac162102d8b661b0b3\+        \302ee2f162b09e07a55ad5dfbe673a9f01d9f0c19617681024306b56ae00000000"+    unsignedTx =+        "010000000136641869ca081e70f394c6948e8af409e18b619df2ed74aa106c1c\+        \a29787b96e0100000000ffffffff0200e9a435000000001976a914389ffce9cd\+        \9ae88dcc0631e88a821ffdbe9bfe2688acc0832f05000000001976a9147480a3\+        \3f950689af511e6e84c138dbbd3c3ee41588ac00000000"+    op0 = head $ prevOutput <$> txIn unsignedTx+    rawKeys =+        [ "730fff80e1413068a05b57d6a58261f07551163369787f349438ea38ca80fac6"+        , "11fa3d25a17cbc22b29c44a484ba552b5a53149d106d3d853e22fdd05a2d8bb3"+        , "77bf4141a87d55bdd7f3cd0bdccf6e9e642935fec45f2f30047be7b799120661"+        , "14af36970f5025ea3e8b5542c0f8ebe7763e674838d08808896b63c3351ffe49"+        , "fe9a95c19eef81dde2b95c1284ef39be497d128e2aa46916fb02d552485e0323"+        , "428a7aee9f0c2af0cd19af3cf1c78149951ea528726989b2e83e4778d2c3f890"+        ]+    Just keys = traverse secHexKey rawKeys+    rdm = PayMulSig (toPubKey <$> keys) 6+    sigIn sh = SigInput (toP2WSH $ encodeOutput rdm) 987654321 op0 sh (Just rdm)+    sigHashesA = [sigHashAll, sigHashNone, sigHashSingle]+    sigHashesB = setAnyoneCanPayFlag <$> sigHashesA+    sigIns = sigIn <$> (sigHashesA <> sigHashesB)+    generatedSignedTx = foldM addSig unsignedTx $ zip sigIns keys+    addSig tx (sigIn', key') = signNestedWitnessTx btc tx [sigIn'] [key']++secHexKey :: Text -> Maybe SecKey+secHexKey = decodeHex >=> secKey++toPubKey :: SecKey -> PubKeyI+toPubKey = derivePubKeyI . wrapSecKey True
− test/Haskoin/CryptoSpec.hs
@@ -1,165 +0,0 @@-{-# LANGUAGE OverloadedStrings #-}-module Haskoin.CryptoSpec (spec) where--import           Control.Monad-import           Data.ByteString       (ByteString)-import qualified Data.ByteString.Char8 as C (pack)-import           Data.Maybe            (fromMaybe, isJust, isNothing)-import           Data.Text             (Text)-import           Haskoin.Address-import           Haskoin.Constants-import           Haskoin.Crypto-import           Haskoin.Keys-import           Haskoin.Util-import           Test.Hspec-import           Test.HUnit            (Assertion, assertBool)---- Unit tests copied from bitcoind implementation--- https://github.com/bitcoin/bitcoin/blob/master/src/test/key_tests.cpp--strSecret1 :: Text-strSecret1  = "5HxWvvfubhXpYYpS3tJkw6fq9jE9j18THftkZjHHfmFiWtmAbrj"--strSecret2 :: Text-strSecret2  = "5KC4ejrDjv152FGwP386VD1i2NYc5KkfSMyv1nGy1VGDxGHqVY3"--strSecret1C :: Text-strSecret1C = "Kwr371tjA9u2rFSMZjTNun2PXXP3WPZu2afRHTcta6KxEUdm1vEw"--strSecret2C :: Text-strSecret2C = "L3Hq7a8FEQwJkW1M2GNKDW28546Vp5miewcCzSqUD9kCAXrJdS3g"--addr1 :: Text-addr1  = "1QFqqMUD55ZV3PJEJZtaKCsQmjLT6JkjvJ"--addr2 :: Text-addr2  = "1F5y5E5FMc5YzdJtB9hLaUe43GDxEKXENJ"--addr1C :: Text-addr1C = "1NoJrossxPBKfCHuJXT4HadJrXRE9Fxiqs"--addr2C :: Text-addr2C = "1CRj2HyM1CXWzHAXLQtiGLyggNT9WQqsDs"--strAddressBad :: Text-strAddressBad = "1HV9Lc3sNHZxwj4Zk6fB38tEmBryq2cBiF"--sigMsg :: [ByteString]-sigMsg =-    [ mconcat ["Very secret message ", C.pack (show (i :: Int)), ": 11"]-    | i <- [0..15]-    ]--sec1 :: SecKeyI-sec1 =-    fromMaybe (error "Could not decode WIF secret 1") (fromWif btc strSecret1)--sec2 :: SecKeyI-sec2 =-    fromMaybe (error "Could not decode WIF secret 2") (fromWif btc strSecret2)--sec1C :: SecKeyI-sec1C =-    fromMaybe-        (error "Could not decode WIF compressed secret 1")-        (fromWif btc strSecret1C)--sec2C :: SecKeyI-sec2C =-    fromMaybe-        (error "Could not decode WIF compressed secret 2")-        (fromWif btc strSecret2C)--pub1 :: PubKeyI-pub1  = derivePubKeyI sec1--pub2 :: PubKeyI-pub2  = derivePubKeyI sec2--pub1C :: PubKeyI-pub1C = derivePubKeyI sec1C--pub2C :: PubKeyI-pub2C = derivePubKeyI sec2C--spec :: Spec-spec =-    describe "bitcoind /src/test/key_tests.cpp" $ do-        it "decode valid wif" checkPrivkey-        it "decode invalid wif" checkInvalidKey-        it "decode minikey format" checkMiniKey-        it "check private key compression" checkPrvKeyCompressed-        it "check public key compression" checkKeyCompressed-        it "check matching address" checkMatchingAddress-        it "check various signatures" sigCheck--sigCheck :: Assertion-sigCheck = forM_ sigMsg $ checkSignatures . doubleSHA256--{- bitcoind /src/test/key_tests.cpp -}--checkPrivkey :: Assertion-checkPrivkey = do-    assertBool "Key 1"  $ isJust $ fromWif btc strSecret1-    assertBool "Key 2"  $ isJust $ fromWif btc strSecret2-    assertBool "Key 1C" $ isJust $ fromWif btc strSecret1C-    assertBool "Key 2C" $ isJust $ fromWif btc strSecret2C--checkInvalidKey :: Assertion-checkInvalidKey =-    assertBool "Bad key" $ isNothing $ fromWif btc strAddressBad--checkMiniKey :: Assertion-checkMiniKey =-    assertBool "Bad mini key" $-    isJust res && fromMiniKey "S6c56bnXQiBjk9mqSYE7ykVQ7NzrRy" == res-  where-    res = do-        bs <--            decodeHex-                "4C7A9640C72DC2099F23715D0C8A0D8A35F8906E3CAB61DD3F78B67BF887C9AB"-        wrapSecKey False <$> secKey bs--checkPrvKeyCompressed :: Assertion-checkPrvKeyCompressed = do-    assertBool "Key 1"  $ not $ secKeyCompressed sec1-    assertBool "Key 2"  $ not $ secKeyCompressed sec2-    assertBool "Key 1C" $ secKeyCompressed sec1C-    assertBool "Key 2C" $ secKeyCompressed sec2C--checkKeyCompressed :: Assertion-checkKeyCompressed = do-    assertBool "Key 1"  $ not $ pubKeyCompressed pub1-    assertBool "Key 2"  $ not $ pubKeyCompressed pub2-    assertBool "Key 1C" $ pubKeyCompressed pub1C-    assertBool "Key 2C" $ pubKeyCompressed pub2C--checkMatchingAddress :: Assertion-checkMatchingAddress = do-    assertBool "Key 1"  $ Just addr1  == addrToString btc (pubKeyAddr pub1)-    assertBool "Key 2"  $ Just addr2  == addrToString btc (pubKeyAddr pub2)-    assertBool "Key 1C" $ Just addr1C == addrToString btc (pubKeyAddr pub1C)-    assertBool "Key 2C" $ Just addr2C == addrToString btc (pubKeyAddr pub2C)--checkSignatures :: Hash256 -> Assertion-checkSignatures h = do-    let sign1  = signHash (secKeyData sec1) h-        sign2  = signHash (secKeyData sec2) h-        sign1C = signHash (secKeyData sec1C) h-        sign2C = signHash (secKeyData sec2C) h-    assertBool "Key 1, Sign1"   $ verifyHashSig h sign1 (pubKeyPoint pub1)-    assertBool "Key 1, Sign2"   $ not $ verifyHashSig h sign2 (pubKeyPoint pub1)-    assertBool "Key 1, Sign1C"  $ verifyHashSig h sign1C (pubKeyPoint pub1)-    assertBool "Key 1, Sign2C"  $ not $ verifyHashSig h sign2C (pubKeyPoint pub1)-    assertBool "Key 2, Sign1"   $ not $ verifyHashSig h sign1 (pubKeyPoint pub2)-    assertBool "Key 2, Sign2"   $ verifyHashSig h sign2 (pubKeyPoint pub2)-    assertBool "Key 2, Sign1C"  $ not $ verifyHashSig h sign1C (pubKeyPoint pub2)-    assertBool "Key 2, Sign2C"  $ verifyHashSig h sign2C (pubKeyPoint pub2)-    assertBool "Key 1C, Sign1"  $ verifyHashSig h sign1 (pubKeyPoint pub1C)-    assertBool "Key 1C, Sign2"  $ not $ verifyHashSig h sign2 (pubKeyPoint pub1C)-    assertBool "Key 1C, Sign1C" $ verifyHashSig h sign1C (pubKeyPoint pub1C)-    assertBool "Key 1C, Sign2C" $ not $ verifyHashSig h sign2C (pubKeyPoint pub1C)-    assertBool "Key 2C, Sign1"  $ not $ verifyHashSig h sign1 (pubKeyPoint pub2C)-    assertBool "Key 2C, Sign2"  $ verifyHashSig h sign2 (pubKeyPoint pub2C)-    assertBool "Key 2C, Sign1C" $ not $ verifyHashSig h sign1C (pubKeyPoint pub2C)-    assertBool "Key 2C, Sign2C" $ verifyHashSig h sign2C (pubKeyPoint pub2C)
test/Haskoin/Keys/ExtendedSpec.hs view
@@ -1,6 +1,8 @@+{-# LANGUAGE FlexibleContexts  #-} {-# LANGUAGE OverloadedStrings #-} module Haskoin.Keys.ExtendedSpec (spec) where +import           Control.Monad              (forM_) import           Data.Aeson                 as A import           Data.Bits                  ((.&.)) import qualified Data.ByteString.Lazy.Char8 as B8@@ -74,20 +76,9 @@             forAll arbitraryNetwork $ \net ->                 forAll arbitraryXPubKey $                 customCerealID (getXPubKey net) (putXPubKey net) . snd-    describe "bip32 derivation vector 1" $ do-        it "chain m" $ runXKeyVec (head xKeyVec)-        it "chain m/0'" $ runXKeyVec (xKeyVec !! 1)-        it "chain m/0'/1" $ runXKeyVec (xKeyVec !! 2)-        it "chain m/0'/1/2'" $ runXKeyVec (xKeyVec !! 3)-        it "chain m/0'/1/2'/2" $ runXKeyVec (xKeyVec !! 4)-        it "chain m/0'/1/2'/2/1000000000" $ runXKeyVec (xKeyVec !! 5)-    describe "bip32 subkey derivation vector 2" $ do-        it "chain m" $ runXKeyVec (head xKeyVec2)-        it "chain m/0" $ runXKeyVec (xKeyVec2 !! 1)-        it "chain m/0/2147483647'" $ runXKeyVec (xKeyVec2 !! 2)-        it "chain m/0/2147483647'/1" $ runXKeyVec (xKeyVec2 !! 3)-        it "chain m/0/2147483647'/1/2147483646'" $ runXKeyVec (xKeyVec2 !! 4)-        it "Chain m/0/2147483647'/1/2147483646'/2" $ runXKeyVec (xKeyVec2 !! 5)+    describe "bip32 subkey derivation vector 1" $ vectorSpec m1 vector1+    describe "bip32 subkey derivation vector 2" $ vectorSpec m2 vector2+    describe "bip32 subkey derivation vector 3" $ vectorSpec m3 vector3     describe "bip32 subkey derivation using string path" $ do         it "either derivations" testApplyPath         it "either derivations" testBadApplyPath@@ -113,17 +104,21 @@                 toSoft (listToPath $ pathToList p) == Just p     describe "Extended Keys" $ do         let net = btc-        it "computes pubkey of a subkey is subkey of the pubkey" $-            property $ forAll arbitraryXPrvKey pubKeyOfSubKeyIsSubKeyOfPubKey-        it "exports and imports extended private key" $-            property $+        prop "computes pubkey of a subkey is subkey of the pubkey" $+            forAll arbitraryXPrvKey pubKeyOfSubKeyIsSubKeyOfPubKey+        prop "exports and imports extended private key" $             forAll arbitraryXPrvKey $ \k ->                 xPrvImport net (xPrvExport net k) == Just k-        it "exports and imports extended public key" $-            property $+        prop "exports and imports extended public key" $             forAll arbitraryXPubKey $ \(_, k) ->                 xPubImport net (xPubExport net k) == Just k +pubKeyOfSubKeyIsSubKeyOfPubKey :: XPrvKey -> Word32 -> Bool+pubKeyOfSubKeyIsSubKeyOfPubKey k i =+    deriveXPubKey (prvSubKey k i') == pubSubKey (deriveXPubKey k) i'+  where+    i' = fromIntegral $ i .&. 0x7fffffff -- make it a public derivation+ testFromJsonPath :: Assertion testFromJsonPath =     sequence_ $ do@@ -301,59 +296,78 @@         \WzGmb8oageSRxBY8s4rjr9VXPVp2HQDbwPt4H31Gg4LpB"     xpub = deriveXPubKey xprv +-- BIP 0032 Test Vectors+-- https://en.bitcoin.it/wiki/BIP_0032_TestVectors -runXKeyVec :: ([Text], XPrvKey) -> Assertion-runXKeyVec (v, m) = do-    assertBool "xPrvID" $ encodeHex (S.encode $ xPrvID m) == head v+bip44Addr :: DerivPath+bip44Addr = Deriv :| 44 :| 0 :| 0 :/ 0 :/ 0++vectorSpec :: TestKey -> [TestVector] -> Spec+vectorSpec mTxt vecTxt =+    forM_ (parseVector mTxt vecTxt) $ \(d,m,v) ->+        it ("chain " <> cs d) $ runVector m v++runVector :: XPrvKey -> TestVector -> Assertion+runVector m v = do+    assertBool "xPrvID" $ encodeHex (S.encode $ xPrvID m) == v !! 0     assertBool "xPrvFP" $ encodeHex (S.encode $ xPrvFP m) == v !! 1     assertBool "xPrvAddr" $-        addrToString btc (xPubAddr $ deriveXPubKey m) == Just (v !! 2)-    assertBool "prvKey" $ encodeHex (getSecKey $ xPrvKey m) == v !! 3-    assertBool "xPrvWIF" $ xPrvWif btc m == v !! 4+        addrToText btc (xPubAddr $ deriveXPubKey m) == Just (v !! 2)+    assertBool "bip44Addr" $+        addrToText btc (xPubAddr $ deriveXPubKey $ derivePath bip44Addr m) ==+        Just (v !! 3)+    assertBool "prvKey" $ encodeHex (getSecKey $ xPrvKey m) == v !! 4+    assertBool "xPrvWIF" $ xPrvWif btc m == v !! 5     assertBool "pubKey" $-        encodeHex (exportPubKey True $ xPubKey $ deriveXPubKey m) == v !! 5-    assertBool "chain code" $ encodeHex (S.encode $ xPrvChain m) == v !! 6+        encodeHex (exportPubKey True $ xPubKey $ deriveXPubKey m) == v !! 6+    assertBool "chain code" $ encodeHex (S.encode $ xPrvChain m) == v !! 7     assertBool "Hex PubKey" $-        encodeHex (runPut $ putXPubKey btc $ deriveXPubKey m) == v !! 7-    assertBool "Hex PrvKey" $ encodeHex (runPut (putXPrvKey btc m)) == v !! 8-    assertBool "Base58 PubKey" $ xPubExport btc (deriveXPubKey m) == v !! 9-    assertBool "Base58 PrvKey" $ xPrvExport btc m == v !! 10+        encodeHex (runPut $ putXPubKey btc $ deriveXPubKey m) == v !! 8+    assertBool "Hex PrvKey" $ encodeHex (runPut (putXPrvKey btc m)) == v !! 9+    assertBool "Base58 PubKey" $ xPubExport btc (deriveXPubKey m) == v !! 10+    assertBool "Base58 PrvKey" $ xPrvExport btc m == v !! 11 --- BIP 0032 Test Vectors--- https://en.bitcoin.it/wiki/BIP_0032_TestVectors+-- This function was used to generate addition data for the test vectors+genVector :: XPrvKey -> [(Text, Text)]+genVector m =+    [ ("xPrvID", encodeHex (S.encode $ xPrvID m))+    , ("xPrvFP", encodeHex (S.encode $ xPrvFP m))+    , ("xPrvAddr", fromJust $ addrToText btc (xPubAddr $ deriveXPubKey m))+    , ( "bip44Addr"+      , fromJust $+        addrToText btc (xPubAddr $ deriveXPubKey $ derivePath bip44Addr m))+    , ("prvKey", encodeHex (getSecKey $ xPrvKey m))+    , ("xPrvWIF", xPrvWif btc m)+    , ("pubKey", encodeHex (exportPubKey True $ xPubKey $ deriveXPubKey m))+    , ("chain code", encodeHex (S.encode $ xPrvChain m))+    , ("Hex PubKey", encodeHex (runPut $ putXPubKey btc $ deriveXPubKey m))+    , ("Hex PrvKey", encodeHex (runPut (putXPrvKey btc m)))+    ] -xKeyVec :: [([Text], XPrvKey)]-xKeyVec = zip xKeyResVec $ foldl f [m] der-    where f acc d = acc ++ [d $ last acc]-          m   = makeXPrvKey $ fromJust $ decodeHex m0-          der = [ flip hardSubKey 0-                , flip prvSubKey 1-                , flip hardSubKey 2-                , flip prvSubKey 2-                , flip prvSubKey 1000000000-                ]+parseVector :: TestKey -> [TestVector] -> [(Text, XPrvKey, TestVector)]+parseVector mTxt vs =+    go <$> vs+  where+    mast = makeXPrvKey $ fromJust $ decodeHex mTxt+    go (d:vec) =+        let deriv = getParsedPath $ fromJust $ parsePath $ cs d+         in (d, derivePath deriv mast, vec)+    go _ = undefined -xKeyVec2 :: [([Text], XPrvKey)]-xKeyVec2 = zip xKeyResVec2 $ foldl f [m] der-    where f acc d = acc ++ [d $ last acc]-          m   = makeXPrvKey $ fromJust $ decodeHex m1-          der = [ flip prvSubKey 0-                , flip hardSubKey 2147483647-                , flip prvSubKey 1-                , flip hardSubKey 2147483646-                , flip prvSubKey 2-                ]+type TestVector = [Text]+type TestKey = Text -m0 :: Text-m0 = "000102030405060708090a0b0c0d0e0f"+m1 :: TestKey+m1 = "000102030405060708090a0b0c0d0e0f" -xKeyResVec :: [[Text]]-xKeyResVec =+vector1 :: [TestVector]+vector1 =     [-      -- m-      [ "3442193e1bb70916e914552172cd4e2dbc9df811"+      [ "m"+      , "3442193e1bb70916e914552172cd4e2dbc9df811"       , "3442193e"       , "15mKKb2eos1hWa6tisdPwwDC1a5J1y9nma"+      , "1NQpH6Nf8QtR2HphLRcvuVqfhXBXsiWn8r"       , "e8f32e723decf4051aefac8e2c93c9c5b214313817cdb01a1494b917c8436b35"       , "L52XzL2cMkHxqxBXRyEpnPQZGUs3uKiL3R11XbAdHigRzDozKZeW"       , "0339a36013301597daef41fbe593a02cc513d0b55527ec2df1050e2e8ff49c85c2"@@ -363,10 +377,11 @@       , "xpub661MyMwAqRbcFtXgS5sYJABqqG9YLmC4Q1Rdap9gSE8NqtwybGhePY2gZ29ESFjqJoCu1Rupje8YtGqsefD265TMg7usUDFdp6W1EGMcet8"       , "xprv9s21ZrQH143K3QTDL4LXw2F7HEK3wJUD2nW2nRk4stbPy6cq3jPPqjiChkVvvNKmPGJxWUtg6LnF5kejMRNNU3TGtRBeJgk33yuGBxrMPHi"       ]-      -- m/0'-    , [ "5c1bd648ed23aa5fd50ba52b2457c11e9e80a6a7"+    , [ "m/0'"+      , "5c1bd648ed23aa5fd50ba52b2457c11e9e80a6a7"       , "5c1bd648"       , "19Q2WoS5hSS6T8GjhK8KZLMgmWaq4neXrh"+      , "1DDVw6BRKUv9U8Hzg5rGsia13nDrgJQpBd"       , "edb2e14f9ee77d26dd93b4ecede8d16ed408ce149b6cd80b0715a2d911a0afea"       , "L5BmPijJjrKbiUfG4zbiFKNqkvuJ8usooJmzuD7Z8dkRoTThYnAT"       , "035a784662a4a20a65bf6aab9ae98a6c068a81c52e4b032c0fb5400c706cfccc56"@@ -376,10 +391,11 @@       , "xpub68Gmy5EdvgibQVfPdqkBBCHxA5htiqg55crXYuXoQRKfDBFA1WEjWgP6LHhwBZeNK1VTsfTFUHCdrfp1bgwQ9xv5ski8PX9rL2dZXvgGDnw"       , "xprv9uHRZZhk6KAJC1avXpDAp4MDc3sQKNxDiPvvkX8Br5ngLNv1TxvUxt4cV1rGL5hj6KCesnDYUhd7oWgT11eZG7XnxHrnYeSvkzY7d2bhkJ7"       ]-      -- m/0'/1-    , [ "bef5a2f9a56a94aab12459f72ad9cf8cf19c7bbe"+    , [ "m/0'/1"+      , "bef5a2f9a56a94aab12459f72ad9cf8cf19c7bbe"       , "bef5a2f9"       , "1JQheacLPdM5ySCkrZkV66G2ApAXe1mqLj"+      , "1KMg6dRggXSkpz9fFyU76ru83TUSwPePEZ"       , "3c6cb8d0f6a264c91ea8b5030fadaa8e538b020f0a387421a12de9319dc93368"       , "KyFAjQ5rgrKvhXvNMtFB5PCSKUYD1yyPEe3xr3T34TZSUHycXtMM"       , "03501e454bf00751f24b1b489aa925215d66af2234e3891c3b21a52bedb3cd711c"@@ -389,10 +405,11 @@       , "xpub6ASuArnXKPbfEwhqN6e3mwBcDTgzisQN1wXN9BJcM47sSikHjJf3UFHKkNAWbWMiGj7Wf5uMash7SyYq527Hqck2AxYysAA7xmALppuCkwQ"       , "xprv9wTYmMFdV23N2TdNG573QoEsfRrWKQgWeibmLntzniatZvR9BmLnvSxqu53Kw1UmYPxLgboyZQaXwTCg8MSY3H2EU4pWcQDnRnrVA1xe8fs"       ]-      -- m/0'/1/2'-    , [ "ee7ab90cde56a8c0e2bb086ac49748b8db9dce72"+    , [ "m/0'/1/2'"+      , "ee7ab90cde56a8c0e2bb086ac49748b8db9dce72"       , "ee7ab90c"       , "1NjxqbA9aZWnh17q1UW3rB4EPu79wDXj7x"+      , "1WykKhR25y7VDT21nZEwUUKSKDz9pENJh"       , "cbce0d719ecf7431d88e6a89fa1483e02e35092af60c042b1df2ff59fa424dca"       , "L43t3od1Gh7Lj55Bzjj1xDAgJDcL7YFo2nEcNaMGiyRZS1CidBVU"       , "0357bfe1e341d01c69fe5654309956cbea516822fba8a601743a012a7896ee8dc2"@@ -402,10 +419,11 @@       , "xpub6D4BDPcP2GT577Vvch3R8wDkScZWzQzMMUm3PWbmWvVJrZwQY4VUNgqFJPMM3No2dFDFGTsxxpG5uJh7n7epu4trkrX7x7DogT5Uv6fcLW5"       , "xprv9z4pot5VBttmtdRTWfWQmoH1taj2axGVzFqSb8C9xaxKymcFzXBDptWmT7FwuEzG3ryjH4ktypQSAewRiNMjANTtpgP4mLTj34bhnZX7UiM"       ]-      -- m/0'/1/2'/2-    , [ "d880d7d893848509a62d8fb74e32148dac68412f"+    , [ "m/0'/1/2'/2"+      , "d880d7d893848509a62d8fb74e32148dac68412f"       , "d880d7d8"       , "1LjmJcdPnDHhNTUgrWyhLGnRDKxQjoxAgt"+      , "1asQ3smHhv2nv5R6hPpiUfkEorJpsdwwx"       , "0f479245fb19a38a1954c5c7c0ebab2f9bdfd96a17563ef28a6a4b1a2a764ef4"       , "KwjQsVuMjbCP2Zmr3VaFaStav7NvevwjvvkqrWd5Qmh1XVnCteBR"       , "02e8445082a72f29b75ca48748a914df60622a609cacfce8ed0e35804560741d29"@@ -415,10 +433,11 @@       , "xpub6FHa3pjLCk84BayeJxFW2SP4XRrFd1JYnxeLeU8EqN3vDfZmbqBqaGJAyiLjTAwm6ZLRQUMv1ZACTj37sR62cfN7fe5JnJ7dh8zL4fiyLHV"       , "xprvA2JDeKCSNNZky6uBCviVfJSKyQ1mDYahRjijr5idH2WwLsEd4Hsb2Tyh8RfQMuPh7f7RtyzTtdrbdqqsunu5Mm3wDvUAKRHSC34sJ7in334"       ]-      -- m/0'/1/2'/2/1000000000-    , [ "d69aa102255fed74378278c7812701ea641fdf32"+    , [ "m/0'/1/2'/2/1000000000"+      , "d69aa102255fed74378278c7812701ea641fdf32"       , "d69aa102"       , "1LZiqrop2HGR4qrH1ULZPyBpU6AUP49Uam"+      , "1HXJog342VFdc68AB9Cb6LwVmCjvcLMiwm"       , "471b76e389e528d6de6d816857e012c5455051cad6660850e58372a6c3e6e7c8"       , "Kybw8izYevo5xMh1TK7aUr7jHFCxXS1zv8p3oqFz3o2zFbhRXHYs"       , "022a471424da5e657499d1ff51cb43c47481a03b1e77f951fe64cec9f5a48f7011"@@ -430,16 +449,17 @@       ]     ] -m1 :: Text-m1 = "fffcf9f6f3f0edeae7e4e1dedbd8d5d2cfccc9c6c3c0bdbab7b4b1aeaba8a5a29f9c999693908d8a8784817e7b7875726f6c696663605d5a5754514e4b484542"+m2 :: TestKey+m2 = "fffcf9f6f3f0edeae7e4e1dedbd8d5d2cfccc9c6c3c0bdbab7b4b1aeaba8a5a29f9c999693908d8a8784817e7b7875726f6c696663605d5a5754514e4b484542" -xKeyResVec2 :: [[Text]]-xKeyResVec2 =+vector2 :: [TestVector]+vector2 =     [-      -- m-      [ "bd16bee53961a47d6ad888e29545434a89bdfe95"+      [ "m"+      , "bd16bee53961a47d6ad888e29545434a89bdfe95"       , "bd16bee5"       , "1JEoxevbLLG8cVqeoGKQiAwoWbNYSUyYjg"+      , "148CGtv7bwcC933EHtcDfzDQVneur1R8Y1"       , "4b03d6fc340455b363f51020ad3ecca4f0850280cf436c70c727923f6db46c3e"       , "KyjXhyHF9wTphBkfpxjL8hkDXDUSbE3tKANT94kXSyh6vn6nKaoy"       , "03cbcaa9c98c877a26977d00825c956a238e8dddfbd322cce4f74b0b5bd6ace4a7"@@ -449,10 +469,11 @@       , "xpub661MyMwAqRbcFW31YEwpkMuc5THy2PSt5bDMsktWQcFF8syAmRUapSCGu8ED9W6oDMSgv6Zz8idoc4a6mr8BDzTJY47LJhkJ8UB7WEGuduB"       , "xprv9s21ZrQH143K31xYSDQpPDxsXRTUcvj2iNHm5NUtrGiGG5e2DtALGdso3pGz6ssrdK4PFmM8NSpSBHNqPqm55Qn3LqFtT2emdEXVYsCzC2U"       ]-      -- m/0-    , [ "5a61ff8eb7aaca3010db97ebda76121610b78096"+    , [ "m/0"+      , "5a61ff8eb7aaca3010db97ebda76121610b78096"       , "5a61ff8e"       , "19EuDJdgfRkwCmRzbzVBHZWQG9QNWhftbZ"+      , "1KVyTSpsBGYs7NdyZmArEpVTfWJQSgiDCx"       , "abe74a98f6c7eabee0428f53798f0ab8aa1bd37873999041703c742f15ac7e1e"       , "L2ysLrR6KMSAtx7uPqmYpoTeiRzydXBattRXjXz5GDFPrdfPzKbj"       , "02fc9e5af0ac8d9b3cecfe2a888e2117ba3d089d8585886c9c826b6b22a98d12ea"@@ -462,10 +483,11 @@       , "xpub69H7F5d8KSRgmmdJg2KhpAK8SR3DjMwAdkxj3ZuxV27CprR9LgpeyGmXUbC6wb7ERfvrnKZjXoUmmDznezpbZb7ap6r1D3tgFxHmwMkQTPH"       , "xprv9vHkqa6EV4sPZHYqZznhT2NPtPCjKuDKGY38FBWLvgaDx45zo9WQRUT3dKYnjwih2yJD9mkrocEZXo1ex8G81dwSM1fwqWpWkeS3v86pgKt"       ]-      -- m/0/2147483647'-    , [ "d8ab493736da02f11ed682f88339e720fb0379d1"+    , [ "m/0/2147483647'"+      , "d8ab493736da02f11ed682f88339e720fb0379d1"       , "d8ab4937"       , "1Lke9bXGhn5VPrBuXgN12uGUphrttUErmk"+      , "14MFLsfx1nc4RKiaH9khqDTNL9CRz3q347"       , "877c779ad9687164e9c2f4f0f4ff0340814392330693ce95a58fe18fd52e6e93"       , "L1m5VpbXmMp57P3knskwhoMTLdhAAaXiHvnGLMribbfwzVRpz2Sr"       , "03c01e7425647bdefa82b12d9bad5e3e6865bee0502694b94ca58b666abc0a5c3b"@@ -475,10 +497,11 @@       , "xpub6ASAVgeehLbnwdqV6UKMHVzgqAG8Gr6riv3Fxxpj8ksbH9ebxaEyBLZ85ySDhKiLDBrQSARLq1uNRts8RuJiHjaDMBU4Zn9h8LZNnBC5y4a"       , "xprv9wSp6B7kry3Vj9m1zSnLvN3xH8RdsPP1Mh7fAaR7aRLcQMKTR2vidYEeEg2mUCTAwCd6vnxVrcjfy2kRgVsFawNzmjuHc2YmYRmagcEPdU9"       ]-      -- m/0/2147483647'/1-    , [ "78412e3a2296a40de124307b6485bd19833e2e34"+    , [ "m/0/2147483647'/1"+      , "78412e3a2296a40de124307b6485bd19833e2e34"       , "78412e3a"       , "1BxrAr2pHpeBheusmd6fHDP2tSLAUa3qsW"+      , "19ou31MGyGW9VFx7woKBqwLe5JHhQBYaDD"       , "704addf544a06e5ee4bea37098463c23613da32020d604506da8c0518e1da4b7"       , "KzyzXnznxSv249b4KuNkBwowaN3akiNeEHy5FWoPCJpStZbEKXN2"       , "03a7d1d856deb74c508e05031f9895dab54626251b3806e16b4bd12e781a7df5b9"@@ -488,10 +511,11 @@       , "xpub6DF8uhdarytz3FWdA8TvFSvvAh8dP3283MY7p2V4SeE2wyWmG5mg5EwVvmdMVCQcoNJxGoWaU9DCWh89LojfZ537wTfunKau47EL2dhHKon"       , "xprv9zFnWC6h2cLgpmSA46vutJzBcfJ8yaJGg8cX1e5StJh45BBciYTRXSd25UEPVuesF9yog62tGAQtHjXajPPdbRCHuWS6T8XA2ECKADdw4Ef"       ]-      -- m/0/2147483647'/1/2147483646'-    , [ "31a507b815593dfc51ffc7245ae7e5aee304246e"+    , [  "m/0/2147483647'/1/2147483646'"+      , "31a507b815593dfc51ffc7245ae7e5aee304246e"       , "31a507b8"       , "15XVotxCAV7sRx1PSCkQNsGw3W9jT9A94R"+      , "18GYmRm4nyjk8ydvoVXFxMWQvxhksEFDZR"       , "f1c7c871a54a804afe328b4c83a1c33b8e5ff48f5087273f04efa83b247d6a2d"       , "L5KhaMvPYRW1ZoFmRjUtxxPypQ94m6BcDrPhqArhggdaTbbAFJEF"       , "02d2b36900396c9282fa14628566582f206a5dd0bcc8d5e892611806cafb0301f0"@@ -501,10 +525,11 @@       , "xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL"       , "xprvA1RpRA33e1JQ7ifknakTFpgNXPmW2YvmhqLQYMmrj4xJXXWYpDPS3xz7iAxn8L39njGVyuoseXzU6rcxFLJ8HFsTjSyQbLYnMpCqE2VbFWc"       ]-      -- m/0/2147483647'/1/2147483646'/2-    , [ "26132fdbe7bf89cbc64cf8dafa3f9f88b8666220"+    , [  "m/0/2147483647'/1/2147483646'/2"+      , "26132fdbe7bf89cbc64cf8dafa3f9f88b8666220"       , "26132fdb"       , "14UKfRV9ZPUp6ZC9PLhqbRtxdihW9em3xt"+      , "1758mgwNZhyzpRLe4u7FjqpJtqKpaGhXh7"       , "bb7d39bdb83ecf58f2fd82b6d918341cbef428661ef01ab97c28a4842125ac23"       , "L3WAYNAZPxx1fr7KCz7GN9nD5qMBnNiqEJNJMU1z9MMaannAt4aK"       , "024d902e1a2fc7a8755ab5b694c575fce742c48d9ff192e63df5193e4c7afe1f9c"@@ -516,8 +541,38 @@       ]     ] -pubKeyOfSubKeyIsSubKeyOfPubKey :: XPrvKey -> Word32 -> Bool-pubKeyOfSubKeyIsSubKeyOfPubKey k i =-    deriveXPubKey (prvSubKey k i') == pubSubKey (deriveXPubKey k) i'-  where-    i' = fromIntegral $ i .&. 0x7fffffff -- make it a public derivation+m3 :: TestKey+m3 = "4b381541583be4423346c643850da4b320e46a87ae3d2a4e6da11eba819cd4acba45d239319ac14f863b8d5ab5a0d0c64d2e8a1e7d1457df2e5a3c51c73235be"++vector3 :: [TestVector]+vector3 =+    [+      [ "m"+      , "41d63b50d8dd5e730cdf4c79a56fc929a757c548"+      , "41d63b50"+      , "1717ZYpXhZW5CqAbWSjDJbCey3FyKUmCSf"+      , "17rxURoF96VhmkcEGCj5LNQkmN9HVhWb7F"+      , "00ddb80b067e0d4993197fe10f2657a844a384589847602d56f0c629c81aae32"+      , "KwFPqAq9SKx1sPg15Qk56mqkHwrfGPuywtLUxoWPkiTSBoxCs8am"+      , "03683af1ba5743bdfc798cf814efeeab2735ec52d95eced528e692b8e34c4e5669"+      , "01d28a3e53cffa419ec122c968b3259e16b65076495494d97cae10bbfec3c36f"+      , "0488b21e00000000000000000001d28a3e53cffa419ec122c968b3259e16b65076495494d97cae10bbfec3c36f03683af1ba5743bdfc798cf814efeeab2735ec52d95eced528e692b8e34c4e5669"+      , "0488ade400000000000000000001d28a3e53cffa419ec122c968b3259e16b65076495494d97cae10bbfec3c36f0000ddb80b067e0d4993197fe10f2657a844a384589847602d56f0c629c81aae32"+      , "xpub661MyMwAqRbcEZVB4dScxMAdx6d4nFc9nvyvH3v4gJL378CSRZiYmhRoP7mBy6gSPSCYk6SzXPTf3ND1cZAceL7SfJ1Z3GC8vBgp2epUt13"+      , "xprv9s21ZrQH143K25QhxbucbDDuQ4naNntJRi4KUfWT7xo4EKsHt2QJDu7KXp1A3u7Bi1j8ph3EGsZ9Xvz9dGuVrtHHs7pXeTzjuxBrCmmhgC6"+      ]+    , [  "m/0'"+      , "c61368bb50e066acd95bd04a0b23d3837fb75698"+      , "c61368bb"+      , "1K4L3YxEwg8HkSEapM4iSiGuR6HeQ53KPX"+      , "13QeQVJNNakdUU55P1fc8xPMkkeYVzn4o6"+      , "491f7a2eebc7b57028e0d3faa0acda02e75c33b03c48fb288c41e2ea44e1daef"+      , "KyfrPaeirL5yYAoZvfzyoKXSdszeLqg5vb6dNy9ymvjzZrMZY8GW"+      , "026557fdda1d5d43d79611f784780471f086d58e8126b8c40acb82272a7712e7f2"+      , "e5fea12a97b927fc9dc3d2cb0d1ea1cf50aa5a1fdc1f933e8906bb38df3377bd"+      , "0488b21e0141d63b5080000000e5fea12a97b927fc9dc3d2cb0d1ea1cf50aa5a1fdc1f933e8906bb38df3377bd026557fdda1d5d43d79611f784780471f086d58e8126b8c40acb82272a7712e7f2"+      , "0488ade40141d63b5080000000e5fea12a97b927fc9dc3d2cb0d1ea1cf50aa5a1fdc1f933e8906bb38df3377bd00491f7a2eebc7b57028e0d3faa0acda02e75c33b03c48fb288c41e2ea44e1daef"+      , "xpub68NZiKmJWnxxS6aaHmn81bvJeTESw724CRDs6HbuccFQN9Ku14VQrADWgqbhhTHBaohPX4CjNLf9fq9MYo6oDaPPLPxSb7gwQN3ih19Zm4Y"+      , "xprv9uPDJpEQgRQfDcW7BkF7eTya6RPxXeJCqCJGHuCJ4GiRVLzkTXBAJMu2qaMWPrS7AANYqdq6vcBcBUdJCVVFceUvJFjaPdGZ2y9WACViL4L"+      ]+    ]
test/Haskoin/KeysSpec.hs view
@@ -1,18 +1,28 @@+{-# LANGUAGE OverloadedStrings #-} module Haskoin.KeysSpec (spec) where +import           Control.Lens+import           Control.Monad import           Data.Aeson              as A+import           Data.Aeson.Lens import qualified Data.ByteString         as BS-import           Data.Map.Strict         (singleton)+import qualified Data.ByteString.Char8   as C+import           Data.Maybe import           Data.Serialize          as S import           Data.String             (fromString) import           Data.String.Conversions (cs)+import           Data.Text               (Text) import           Haskoin.Address import           Haskoin.Constants import           Haskoin.Crypto import           Haskoin.Keys-import           Haskoin.Util.Arbitrary+import           Haskoin.Script import           Haskoin.Util+import           Haskoin.Util.Arbitrary+import           Haskoin.UtilSpec        (readTestFile) import           Test.Hspec+import           Test.Hspec.QuickCheck+import           Test.HUnit import           Test.QuickCheck  serialVals :: [SerialBox]@@ -34,15 +44,36 @@     ]  spec :: Spec-spec =-    describe "keys" $ do-        testIdentity serialVals readVals jsonVals []-        it "is public key canonical" $-            property $ forAll arbitraryKeyPair (isCanonicalPubKey . snd)-        it "from string public key" $-            property $+spec = do+    testIdentity serialVals readVals jsonVals []+    describe "PubKey properties" $ do+        prop "Public key is canonical" $+            forAll arbitraryKeyPair (isCanonicalPubKey . snd)+        prop "Public key fromString identity" $             forAll arbitraryKeyPair $ \(_, k) ->                 fromString (cs . encodeHex $ S.encode k) == k+    describe "SecKey properties" $+        prop "fromWif . toWif identity" $+        forAll arbitraryNetwork $ \net ->+            forAll arbitraryKeyPair $ \(pk, _) ->+                fromWif net (toWif net pk) == Just pk+    describe "Bitcoin core vectors /src/test/key_tests.cpp" $ do+        it "Passes WIF decoding tests" testPrivkey+        it "Passes SecKey compression tests" testPrvKeyCompressed+        it "Passes PubKey compression tests" testKeyCompressed+        it "Passes address matching tests" testMatchingAddress+        it "Passes signature verification" testSigs+        it "Passes deterministic signing tests" testDetSigning+    describe "MiniKey vectors" $+        it "Passes MiniKey decoding tests" testMiniKey+    describe "key_io_valid.json vectors" $ do+        vectors <- runIO (readTestFile "key_io_valid.json" :: IO [(Text, Text, A.Value)])+        it "Passes the key_io_valid.json vectors" $+            mapM_ testKeyIOValidVector vectors+    describe "key_io_invalid.json vectors" $ do+        vectors <- runIO (readTestFile "key_io_invalid.json" :: IO [[Text]])+        it "Passes the key_io_invalid.json vectors" $+            mapM_ testKeyIOInvalidVector vectors  -- github.com/bitcoin/bitcoin/blob/master/src/script.cpp -- from function IsCanonicalPubKey@@ -58,4 +89,169 @@     (BS.index bs 0 `notElem` [2,3,4])   where     bs = S.encode p++testMiniKey :: Assertion+testMiniKey =+    assertEqual "fromMiniKey" (Just res) (go "S6c56bnXQiBjk9mqSYE7ykVQ7NzrRy")+  where+    go = fmap (encodeHex . S.encode . secKeyData) . fromMiniKey+    res = "4c7a9640c72dc2099f23715d0c8a0d8a35f8906e3cab61dd3f78b67bf887c9ab"++-- Test vectors from:+-- https://github.com/bitcoin/bitcoin/blob/master/src/test/key_io_tests.cpp++testKeyIOValidVector :: (Text, Text, A.Value) -> Assertion+testKeyIOValidVector (a, payload, obj)+    | disabled = return () -- There are invalid version 1 bech32 addresses+    | isPrv = do+        -- Test from WIF to SecKey+        let isComp = obj ^?! key "isCompressed" . _Bool+            prvKeyM = fromWif net a+            prvKeyHexM = encodeHex . S.encode . secKeyData <$> prvKeyM+        assertBool "Valid PrvKey" $ isJust prvKeyM+        assertEqual "Valid compression" (Just isComp) (secKeyCompressed <$> prvKeyM)+        assertEqual "WIF matches payload" (Just payload) prvKeyHexM+        let prvAsPubM = (eitherToMaybe . decodeOutputBS <=< decodeHex) a+        assertBool "PrvKey is invalid ScriptOutput" $ isNothing prvAsPubM+        -- Test from SecKey to WIF+        let secM = eitherToMaybe . S.decode =<< decodeHex payload+            wifM = toWif net . wrapSecKey isComp <$> secM+        assertEqual "Payload matches WIF" (Just a) wifM+    | otherwise = do+        -- Test Addr to Script+        let addrM = textToAddr net a+            scriptM = encodeHex . encodeOutputBS . addressToOutput <$> addrM+        assertBool ("Valid Address " <> cs a) $ isJust addrM+        assertEqual "Address matches payload" (Just payload) scriptM+        let pubAsWifM = fromWif net a+            pubAsSecM = eitherToMaybe . S.decode =<< decodeHex a :: Maybe SecKey+        assertBool "Address is invalid Wif" $ isNothing pubAsWifM+        assertBool "Address is invalid PrvKey" $ isNothing pubAsSecM+        -- Test Script to Addr+        let outM = eitherToMaybe . decodeOutputBS =<< decodeHex payload+            resM = addrToText net =<< outputAddress =<< outM+        assertEqual "Payload matches address" (Just a) resM+  where+    isPrv = obj ^?! key "isPrivkey" . _Bool+    disabled = fromMaybe False $ obj ^? key "disabled" . _Bool+    chain = obj ^?! key "chain" . _String+    net =+        case chain of+            "main"    -> btc+            "test"    -> btcTest+            "regtest" -> btcRegTest+            _         -> error "Invalid chain key in key_io_valid.json"++testKeyIOInvalidVector :: [Text] -> Assertion+testKeyIOInvalidVector [a] = do+    let wifMs = (`fromWif` a) <$> allNets+        secKeyM = (eitherToMaybe . S.decode <=< decodeHex) a :: Maybe SecKey+        scriptM = (eitherToMaybe . decodeOutputBS <=< decodeHex) a :: Maybe ScriptOutput+    assertBool "Payload is invalid WIF" $ all isNothing wifMs+    assertBool "Payload is invalid SecKey" $ isNothing secKeyM+    assertBool "Payload is invalid Script" $ isNothing scriptM+testKeyIOInvalidVector _ = assertFailure "Invalid test vector"++-- Test vectors from:+-- https://github.com/bitcoin/bitcoin/blob/master/src/test/key_tests.cpp++testPrivkey :: Assertion+testPrivkey = do+    assertBool "Key 1"  $ isJust $ fromWif btc strSecret1+    assertBool "Key 2"  $ isJust $ fromWif btc strSecret2+    assertBool "Key 1C" $ isJust $ fromWif btc strSecret1C+    assertBool "Key 2C" $ isJust $ fromWif btc strSecret2C+    assertBool "Bad key" $ isNothing $ fromWif btc strAddressBad++testPrvKeyCompressed :: Assertion+testPrvKeyCompressed = do+    assertBool "Key 1" $ not $ secKeyCompressed sec1+    assertBool "Key 2" $ not $ secKeyCompressed sec2+    assertBool "Key 1C" $ secKeyCompressed sec1C+    assertBool "Key 2C" $ secKeyCompressed sec2C++testKeyCompressed :: Assertion+testKeyCompressed = do+    assertBool "Key 1" $ not $ pubKeyCompressed pub1+    assertBool "Key 2" $ not $ pubKeyCompressed pub2+    assertBool "Key 1C" $ pubKeyCompressed pub1C+    assertBool "Key 2C" $ pubKeyCompressed pub2C++testMatchingAddress :: Assertion+testMatchingAddress = do+    assertEqual "Key 1" (Just addr1) $ addrToText btc (pubKeyAddr pub1)+    assertEqual "Key 2" (Just addr2) $ addrToText btc (pubKeyAddr pub2)+    assertEqual "Key 1C" (Just addr1C) $ addrToText btc (pubKeyAddr pub1C)+    assertEqual "Key 2C" (Just addr2C) $ addrToText btc (pubKeyAddr pub2C)++testSigs :: Assertion+testSigs = forM_ sigMsg $ testSignature . doubleSHA256++sigMsg :: [BS.ByteString]+sigMsg =+    [ mconcat ["Very secret message ", C.pack (show (i :: Int)), ": 11"]+    | i <- [0..15]+    ]++testSignature :: Hash256 -> Assertion+testSignature h = do+    let sign1  = signHash (secKeyData sec1) h+        sign2  = signHash (secKeyData sec2) h+        sign1C = signHash (secKeyData sec1C) h+        sign2C = signHash (secKeyData sec2C) h+    assertBool "Key 1, Sign1"   $ verifyHashSig h sign1 (pubKeyPoint pub1)+    assertBool "Key 1, Sign2"   $ not $ verifyHashSig h sign2 (pubKeyPoint pub1)+    assertBool "Key 1, Sign1C"  $ verifyHashSig h sign1C (pubKeyPoint pub1)+    assertBool "Key 1, Sign2C"  $ not $ verifyHashSig h sign2C (pubKeyPoint pub1)+    assertBool "Key 2, Sign1"   $ not $ verifyHashSig h sign1 (pubKeyPoint pub2)+    assertBool "Key 2, Sign2"   $ verifyHashSig h sign2 (pubKeyPoint pub2)+    assertBool "Key 2, Sign1C"  $ not $ verifyHashSig h sign1C (pubKeyPoint pub2)+    assertBool "Key 2, Sign2C"  $ verifyHashSig h sign2C (pubKeyPoint pub2)+    assertBool "Key 1C, Sign1"  $ verifyHashSig h sign1 (pubKeyPoint pub1C)+    assertBool "Key 1C, Sign2"  $ not $ verifyHashSig h sign2 (pubKeyPoint pub1C)+    assertBool "Key 1C, Sign1C" $ verifyHashSig h sign1C (pubKeyPoint pub1C)+    assertBool "Key 1C, Sign2C" $ not $ verifyHashSig h sign2C (pubKeyPoint pub1C)+    assertBool "Key 2C, Sign1"  $ not $ verifyHashSig h sign1 (pubKeyPoint pub2C)+    assertBool "Key 2C, Sign2"  $ verifyHashSig h sign2 (pubKeyPoint pub2C)+    assertBool "Key 2C, Sign1C" $ not $ verifyHashSig h sign1C (pubKeyPoint pub2C)+    assertBool "Key 2C, Sign2C" $ verifyHashSig h sign2C (pubKeyPoint pub2C)++testDetSigning :: Assertion+testDetSigning = do+    let m = doubleSHA256 ("Very deterministic message" :: BS.ByteString)+    assertEqual+        "Det sig 1"+        (signHash (secKeyData sec1) m)+        (signHash (secKeyData sec1C) m)+    assertEqual+        "Det sig 2"+        (signHash (secKeyData sec2) m)+        (signHash (secKeyData sec2C) m)++strSecret1, strSecret2, strSecret1C, strSecret2C :: Text+strSecret1  = "5HxWvvfubhXpYYpS3tJkw6fq9jE9j18THftkZjHHfmFiWtmAbrj"+strSecret2  = "5KC4ejrDjv152FGwP386VD1i2NYc5KkfSMyv1nGy1VGDxGHqVY3"+strSecret1C = "Kwr371tjA9u2rFSMZjTNun2PXXP3WPZu2afRHTcta6KxEUdm1vEw"+strSecret2C = "L3Hq7a8FEQwJkW1M2GNKDW28546Vp5miewcCzSqUD9kCAXrJdS3g"++sec1, sec2, sec1C, sec2C :: SecKeyI+sec1 = fromJust $ fromWif btc strSecret1+sec2 = fromJust $ fromWif btc strSecret2+sec1C = fromJust $ fromWif btc strSecret1C+sec2C = fromJust $ fromWif btc strSecret2C++addr1, addr2, addr1C, addr2C :: Text+addr1  = "1QFqqMUD55ZV3PJEJZtaKCsQmjLT6JkjvJ"+addr2  = "1F5y5E5FMc5YzdJtB9hLaUe43GDxEKXENJ"+addr1C = "1NoJrossxPBKfCHuJXT4HadJrXRE9Fxiqs"+addr2C = "1CRj2HyM1CXWzHAXLQtiGLyggNT9WQqsDs"++strAddressBad :: Text+strAddressBad = "1HV9Lc3sNHZxwj4Zk6fB38tEmBryq2cBiF"++pub1, pub2, pub1C, pub2C :: PubKeyI+pub1  = derivePubKeyI sec1+pub2  = derivePubKeyI sec2+pub1C = derivePubKeyI sec1C+pub2C = derivePubKeyI sec2C 
test/Haskoin/ScriptSpec.hs view
@@ -5,7 +5,6 @@ import           Data.Aeson              as A import           Data.ByteString         (ByteString) import qualified Data.ByteString         as B-import qualified Data.ByteString.Lazy    as L import           Data.Either import           Data.List import           Data.Maybe@@ -21,6 +20,7 @@ import           Haskoin.Transaction import           Haskoin.Util import           Haskoin.Util.Arbitrary+import           Haskoin.UtilSpec        (readTestFile) import           Test.Hspec import           Test.Hspec.QuickCheck import           Test.HUnit              as HUnit@@ -63,6 +63,8 @@     describe "SigHashFlag fromEnum/toEnum" $         prop "fromEnum/toEnum" $         forAll arbitrarySigHashFlag $ \f -> toEnum (fromEnum f) `shouldBe` f+    describe "Script vectors" $+        it "Can encode script vectors" encodeScriptVector  props :: Network -> Spec props net = do@@ -89,7 +91,7 @@         forAll arbitraryMSOutput $ \out ->             map S.encode (getOutputMulSigKeys (sortMulSig out)) `shouldSatisfy` \xs ->                 xs == sort xs-    prop "can decode inputs with empty signatures" $ do+    it "can decode inputs with empty signatures" $ do         decodeInput net (Script [OP_0]) `shouldBe`             Right (RegularInput (SpendPK TxSignatureEmpty))         decodeInput net (Script [opPushData ""]) `shouldBe`@@ -108,7 +110,7 @@ scriptSpec net =     when (getNetworkName net == "btc") $     it "can verify standard scripts from script_tests.json file" $ do-        xs <- readTestFile "script_tests" :: IO [A.Value]+        xs <- readTestFile "script_tests.json" :: IO [A.Value]         let vectorsA =                 mapMaybe (A.decode . A.encode) xs :: [( String                                                       , String@@ -152,7 +154,7 @@ forkIdScriptSpec net =     when (isJust (getSigHashForkId net)) $     it "can verify scripts from forkid_script_tests.json file" $ do-        xs <- readTestFile "forkid_script_tests" :: IO [A.Value]+        xs <- readTestFile "forkid_script_tests.json" :: IO [A.Value]         let vectors =                 mapMaybe (A.decode . A.encode) xs :: [( [Word64]                                                       , String@@ -221,13 +223,13 @@ strictSigSpec net =     when (getNetworkName net == "btc") $ do         it "can decode strict signatures" $ do-            xs <- readTestFile "sig_strict"+            xs <- readTestFile "sig_strict.json"             let vectors = mapMaybe decodeHex xs             length vectors `shouldBe` 3             forM_ vectors $ \sig ->                 decodeTxSig net sig `shouldSatisfy` isRight         it "can detect non-strict signatures" $ do-            xs <- readTestFile "sig_nonstrict"+            xs <- readTestFile "sig_nonstrict.json"             let vectors = mapMaybe decodeHex xs             length vectors `shouldBe` 17             forM_ vectors $ \sig ->@@ -237,7 +239,7 @@ txSigHashSpec net =     when (getNetworkName net == "btc") $     it "can produce valid sighashes from sighash.json test vectors" $ do-        xs <- readTestFile "sighash" :: IO [A.Value]+        xs <- readTestFile "sighash.json" :: IO [A.Value]         let vectors =                 mapMaybe (A.decode . A.encode) xs :: [( String                                                       , String@@ -260,7 +262,7 @@ txSigHashForkIdSpec net =     when (getNetworkName net == "btc") $     it "can produce valid sighashes from forkid_sighash.json test vectors" $ do-        xs <- readTestFile "forkid_sighash" :: IO [A.Value]+        xs <- readTestFile "forkid_sighash.json" :: IO [A.Value]         let vectors =                 mapMaybe (A.decode . A.encode) xs :: [( String                                                       , String@@ -344,13 +346,6 @@             then setAnyoneCanPayFlag             else id -{-- Test Utilities --}--readTestFile :: A.FromJSON a => FilePath -> IO a-readTestFile fp = do-    bs <- L.readFile $ "data/" <> fp <> ".json"-    maybe (error $ "Could not read test file " <> fp) return $ A.decode bs- {- Parse tests from bitcoin-qt repository -}  mapMulSigVector :: ((Text, Text), Int) -> Spec@@ -368,7 +363,7 @@     b = do         o <- s         d <- eitherToMaybe $ decodeOutput o-        addrToString btc $ payToScriptAddress d+        addrToText btc $ payToScriptAddress d  sigDecodeMap :: Network -> (Text, Int) -> Spec sigDecodeMap net (_, i) =@@ -390,17 +385,55 @@ mulSigVectors :: [(Text, Text)] mulSigVectors =     [ ( "3QJmV3qfvL9SuYo34YihAf3sRCW3qSinyC"-      , "52410491bba2510912a5bd37da1fb5b1673010e43d2c6d812c514e91bfa9f2eb129e1c183329db55bd868e209aac2fbc02cb33d98fe74bf23f0c235d6126b1d8334f864104865c40293a680cb9c020e7b1e106d8c1916d3cef99aa431a56d253e69256dac09ef122b1a986818a7cb624532f062c1d1f8722084861c5c3291ccffef4ec687441048d2455d2403e08708fc1f556002f1b6cd83f992d085097f9974ab08a28838f07896fbab08f39495e15fa6fad6edbfb1e754e35fa1c7844c41f322a1863d4621353ae"+      , "52410491bba2510912a5bd37da1fb5b1673010e43d2c6d812c514e91bfa9f2eb\+        \129e1c183329db55bd868e209aac2fbc02cb33d98fe74bf23f0c235d6126b1d8\+        \334f864104865c40293a680cb9c020e7b1e106d8c1916d3cef99aa431a56d253\+        \e69256dac09ef122b1a986818a7cb624532f062c1d1f8722084861c5c3291ccf\+        \fef4ec687441048d2455d2403e08708fc1f556002f1b6cd83f992d085097f997\+        \4ab08a28838f07896fbab08f39495e15fa6fad6edbfb1e754e35fa1c7844c41f\+        \322a1863d4621353ae"       )     ]  scriptSigSignatures :: [Text] scriptSigSignatures =-     -- Signature in input of txid 1983a69265920c24f89aac81942b1a59f7eb30821a8b3fb258f88882b6336053-    [ "304402205ca6249f43538908151fe67b26d020306c0e59fa206cf9f3ccf641f33357119d02206c82f244d04ac0a48024fb9cc246b66e58598acf206139bdb7b75a2941a2b1e401"+     -- Signature in input of txid+     -- 1983a69265920c24f89aac81942b1a59f7eb30821a8b3fb258f88882b6336053+    [ "304402205ca6249f43538908151fe67b26d020306c0e59fa206cf9f3ccf641f333\+      \57119d02206c82f244d04ac0a48024fb9cc246b66e58598acf206139bdb7b75a29\+      \41a2b1e401"       -- Signature in input of txid       -- fb0a1d8d34fa5537e461ac384bac761125e1bfa7fec286fa72511240fa66864d.       -- Strange DER sizes, but in Blockchain. Now invalid as Haskoin can only       -- decode strict signatures.-      -- "3048022200002b83d59c1d23c08efd82ee0662fec23309c3adbcbd1f0b8695378db4b14e736602220000334a96676e58b1bb01784cb7c556dd8ce1c220171904da22e18fe1e7d1510db501"+      -- "3048022200002b83d59c1d23c08efd82ee0662fec23309c3adbcbd1f0b8695378d\+      -- \b4b14e736602220000334a96676e58b1bb01784cb7c556dd8ce1c220171904da22\+      -- \e18fe1e7d1510db501"     ]++encodeScriptVector :: Assertion+encodeScriptVector =+    assertEqual "Encode script" res (encodeHex $ S.encode s)+  where+    res =+        "514104cc71eb30d653c0c3163990c47b976f3fb3f37cccdcbedb169a1dfef58b\+        \bfbfaff7d8a473e7e2e6d317b87bafe8bde97e3cf8f065dec022b51d11fcdd0d\+        \348ac4410461cbdcc5409fb4b4d42b51d33381354d80e550078cb532a34bfa2f\+        \cfdeb7d76519aecc62770f5b0e4ef8551946d8a540911abe3e7854a26f39f58b\+        \25c15342af52ae"+    s =+        Script+            [ OP_1+            , opPushData $ d+              "04cc71eb30d653c0c3163990c47b976f3fb3f37cccdcbedb169a1dfef5\+              \8bbfbfaff7d8a473e7e2e6d317b87bafe8bde97e3cf8f065dec022b51d\+              \11fcdd0d348ac4"+            , opPushData $ d+              "0461cbdcc5409fb4b4d42b51d33381354d80e550078cb532a34bfa2fcf\+              \deb7d76519aecc62770f5b0e4ef8551946d8a540911abe3e7854a26f39\+              \f58b25c15342af"+            , OP_2+            , OP_CHECKMULTISIG+            ]+    d = fromJust . decodeHex+
test/Haskoin/TransactionSpec.hs view
@@ -15,13 +15,11 @@ import           Haskoin.Keys import           Haskoin.Script import           Haskoin.Transaction-import           Haskoin.Transaction.Segwit (isSegwit) import           Haskoin.Util import           Haskoin.Util.Arbitrary-import           Safe                       (readMay) import           Test.Hspec import           Test.Hspec.QuickCheck-import           Test.HUnit                 (Assertion, assertBool)+import           Test.HUnit import           Test.QuickCheck  serialVals :: [SerialBox]@@ -57,21 +55,7 @@ spec :: Spec spec = do     testIdentity serialVals readVals jsonVals []-    describe "transaction unit tests" $ do-        it "compute txid from tx" $ mapM_ runTxIDVec txIDVec-        it "build pkhash transaction (generated from bitcoind)" $-            mapM_ runPKHashVec pkHashVec-        it "encode satoshi core script pubkey" tEncodeSatoshiCoreScriptPubKey-        ---        -- These tests depend on signatures matching exactly those in the spec.-        -- Fedora includes a version of libsecp256k1 that computes signatures-        -- using a slighlty different deterministic nonce algorithm.-        ---        -- it "agrees with BIP143 p2wpkh example" testBip143p2wpkh-        -- it "agrees with BIP143 p2sh-p2wpkh example" testBip143p2shp2wpkh-        -- it "builds a p2wsh multisig transaction" testP2WSHMulsig-        -- it "agrees with BIP143 p2sh-p2wsh multisig example" testBip143p2shp2wpkhMulsig-    describe "btc transaction" $ do+    describe "Transaction properties" $ do         prop "decode and encode txid" $             forAll arbitraryTxHash $ \h -> hexToTxHash (txHashToHex h) == Just h         prop "from string transaction id" $@@ -99,191 +83,125 @@         prop "merge partially signed transactions" $             forAll arbitraryNetwork $ \net ->                 property $ forAll (arbitraryPartialTxs net) (testMergeTx net)+    describe "Transaction vectors" $ do+        it "compute txid from tx" $ mapM_ testTxidVector txidVectors+        it "build pkhash transaction (generated from bitcoind)" $+            mapM_ testPKHashVector pkHashVectors -runTxIDVec :: (Text, Text) -> Assertion-runTxIDVec (tid, tx) = assertBool "txid" $ txHashToHex (txHash txBS) == tid+-- Txid Vectors++testTxidVector :: (Text, Text) -> Assertion+testTxidVector (tid, tx) =+    assertEqual "txid" (Just tid) (txHashToHex . txHash <$> txM)   where-    txBS = fromJust $ either (const Nothing) return . S.decode =<< decodeHex tx+    txM = eitherToMaybe . S.decode =<< decodeHex tx -txIDVec :: [(Text, Text)]-txIDVec =+txidVectors :: [(Text, Text)]+txidVectors =     [ ( "23b397edccd3740a74adb603c9756370fafcde9bcc4483eb271ecad09a94dd63"-      , "0100000001b14bdcbc3e01bdaad36cc08e81e69c82e1060bc14e518db2b49aa43ad90ba26000000000490047304402203f16c6f40162ab686621ef3000b04e75418a0c0cb2d8aebeac894ae360ac1e780220ddc15ecdfc3507ac48e1681a33eb60996631bf6bf5bc0a0682c4db743ce7ca2b01ffffffff0140420f00000000001976a914660d4ef3a743e3e696ad990364e555c271ad504b88ac00000000"+      , "0100000001b14bdcbc3e01bdaad36cc08e81e69c82e1060bc14e518db2b49aa4\+        \3ad90ba26000000000490047304402203f16c6f40162ab686621ef3000b04e75\+        \418a0c0cb2d8aebeac894ae360ac1e780220ddc15ecdfc3507ac48e1681a33eb\+        \60996631bf6bf5bc0a0682c4db743ce7ca2b01ffffffff0140420f0000000000\+        \1976a914660d4ef3a743e3e696ad990364e555c271ad504b88ac00000000"       )     , ( "c99c49da4c38af669dea436d3e73780dfdb6c1ecf9958baa52960e8baee30e73"-      , "01000000010276b76b07f4935c70acf54fbf1f438a4c397a9fb7e633873c4dd3bc062b6b40000000008c493046022100d23459d03ed7e9511a47d13292d3430a04627de6235b6e51a40f9cd386f2abe3022100e7d25b080f0bb8d8d5f878bba7d54ad2fda650ea8d158a33ee3cbd11768191fd004104b0e2c879e4daf7b9ab68350228c159766676a14f5815084ba166432aab46198d4cca98fa3e9981d0a90b2effc514b76279476550ba3663fdcaff94c38420e9d5000000000100093d00000000001976a9149a7b0f3b80c6baaeedce0a0842553800f832ba1f88ac00000000"+      , "01000000010276b76b07f4935c70acf54fbf1f438a4c397a9fb7e633873c4dd3\+        \bc062b6b40000000008c493046022100d23459d03ed7e9511a47d13292d3430a\+        \04627de6235b6e51a40f9cd386f2abe3022100e7d25b080f0bb8d8d5f878bba7\+        \d54ad2fda650ea8d158a33ee3cbd11768191fd004104b0e2c879e4daf7b9ab68\+        \350228c159766676a14f5815084ba166432aab46198d4cca98fa3e9981d0a90b\+        \2effc514b76279476550ba3663fdcaff94c38420e9d5000000000100093d0000\+        \0000001976a9149a7b0f3b80c6baaeedce0a0842553800f832ba1f88ac000000\+        \00"       )     , ( "f7fdd091fa6d8f5e7a8c2458f5c38faffff2d3f1406b6e4fe2c99dcc0d2d1cbb"-      , "01000000023d6cf972d4dff9c519eff407ea800361dd0a121de1da8b6f4138a2f25de864b4000000008a4730440220ffda47bfc776bcd269da4832626ac332adfca6dd835e8ecd83cd1ebe7d709b0e022049cffa1cdc102a0b56e0e04913606c70af702a1149dc3b305ab9439288fee090014104266abb36d66eb4218a6dd31f09bb92cf3cfa803c7ea72c1fc80a50f919273e613f895b855fb7465ccbc8919ad1bd4a306c783f22cd3227327694c4fa4c1c439affffffff21ebc9ba20594737864352e95b727f1a565756f9d365083eb1a8596ec98c97b7010000008a4730440220503ff10e9f1e0de731407a4a245531c9ff17676eda461f8ceeb8c06049fa2c810220c008ac34694510298fa60b3f000df01caa244f165b727d4896eb84f81e46bcc4014104266abb36d66eb4218a6dd31f09bb92cf3cfa803c7ea72c1fc80a50f919273e613f895b855fb7465ccbc8919ad1bd4a306c783f22cd3227327694c4fa4c1c439affffffff01f0da5200000000001976a914857ccd42dded6df32949d4646dfa10a92458cfaa88ac00000000"+      , "01000000023d6cf972d4dff9c519eff407ea800361dd0a121de1da8b6f4138a2\+        \f25de864b4000000008a4730440220ffda47bfc776bcd269da4832626ac332ad\+        \fca6dd835e8ecd83cd1ebe7d709b0e022049cffa1cdc102a0b56e0e04913606c\+        \70af702a1149dc3b305ab9439288fee090014104266abb36d66eb4218a6dd31f\+        \09bb92cf3cfa803c7ea72c1fc80a50f919273e613f895b855fb7465ccbc8919a\+        \d1bd4a306c783f22cd3227327694c4fa4c1c439affffffff21ebc9ba20594737\+        \864352e95b727f1a565756f9d365083eb1a8596ec98c97b7010000008a473044\+        \0220503ff10e9f1e0de731407a4a245531c9ff17676eda461f8ceeb8c06049fa\+        \2c810220c008ac34694510298fa60b3f000df01caa244f165b727d4896eb84f8\+        \1e46bcc4014104266abb36d66eb4218a6dd31f09bb92cf3cfa803c7ea72c1fc8\+        \0a50f919273e613f895b855fb7465ccbc8919ad1bd4a306c783f22cd32273276\+        \94c4fa4c1c439affffffff01f0da5200000000001976a914857ccd42dded6df3\+        \2949d4646dfa10a92458cfaa88ac00000000"       )     , ( "afd9c17f8913577ec3509520bd6e5d63e9c0fd2a5f70c787993b097ba6ca9fae"-      , "010000000370ac0a1ae588aaf284c308d67ca92c69a39e2db81337e563bf40c59da0a5cf63000000006a4730440220360d20baff382059040ba9be98947fd678fb08aab2bb0c172efa996fd8ece9b702201b4fb0de67f015c90e7ac8a193aeab486a1f587e0f54d0fb9552ef7f5ce6caec032103579ca2e6d107522f012cd00b52b9a65fb46f0c57b9b8b6e377c48f526a44741affffffff7d815b6447e35fbea097e00e028fb7dfbad4f3f0987b4734676c84f3fcd0e804010000006b483045022100c714310be1e3a9ff1c5f7cacc65c2d8e781fc3a88ceb063c6153bf950650802102200b2d0979c76e12bb480da635f192cc8dc6f905380dd4ac1ff35a4f68f462fffd032103579ca2e6d107522f012cd00b52b9a65fb46f0c57b9b8b6e377c48f526a44741affffffff3f1f097333e4d46d51f5e77b53264db8f7f5d2e18217e1099957d0f5af7713ee010000006c493046022100b663499ef73273a3788dea342717c2640ac43c5a1cf862c9e09b206fcb3f6bb8022100b09972e75972d9148f2bdd462e5cb69b57c1214b88fc55ca638676c07cfc10d8032103579ca2e6d107522f012cd00b52b9a65fb46f0c57b9b8b6e377c48f526a44741affffffff0380841e00000000001976a914bfb282c70c4191f45b5a6665cad1682f2c9cfdfb88ac80841e00000000001976a9149857cc07bed33a5cf12b9c5e0500b675d500c81188ace0fd1c00000000001976a91443c52850606c872403c0601e69fa34b26f62db4a88ac00000000"+      , "010000000370ac0a1ae588aaf284c308d67ca92c69a39e2db81337e563bf40c5\+        \9da0a5cf63000000006a4730440220360d20baff382059040ba9be98947fd678\+        \fb08aab2bb0c172efa996fd8ece9b702201b4fb0de67f015c90e7ac8a193aeab\+        \486a1f587e0f54d0fb9552ef7f5ce6caec032103579ca2e6d107522f012cd00b\+        \52b9a65fb46f0c57b9b8b6e377c48f526a44741affffffff7d815b6447e35fbe\+        \a097e00e028fb7dfbad4f3f0987b4734676c84f3fcd0e804010000006b483045\+        \022100c714310be1e3a9ff1c5f7cacc65c2d8e781fc3a88ceb063c6153bf9506\+        \50802102200b2d0979c76e12bb480da635f192cc8dc6f905380dd4ac1ff35a4f\+        \68f462fffd032103579ca2e6d107522f012cd00b52b9a65fb46f0c57b9b8b6e3\+        \77c48f526a44741affffffff3f1f097333e4d46d51f5e77b53264db8f7f5d2e1\+        \8217e1099957d0f5af7713ee010000006c493046022100b663499ef73273a378\+        \8dea342717c2640ac43c5a1cf862c9e09b206fcb3f6bb8022100b09972e75972\+        \d9148f2bdd462e5cb69b57c1214b88fc55ca638676c07cfc10d8032103579ca2\+        \e6d107522f012cd00b52b9a65fb46f0c57b9b8b6e377c48f526a44741affffff\+        \ff0380841e00000000001976a914bfb282c70c4191f45b5a6665cad1682f2c9c\+        \fdfb88ac80841e00000000001976a9149857cc07bed33a5cf12b9c5e0500b675\+        \d500c81188ace0fd1c00000000001976a91443c52850606c872403c0601e69fa\+        \34b26f62db4a88ac00000000"       )     ] -runPKHashVec :: ([(Text, Word32)], [(Text, Word64)], Text) -> Assertion-runPKHashVec (xs, ys, res) =-    assertBool "Build PKHash Tx" $ encodeHex (S.encode tx) == res+-- Build address transactions vectors generated from bitcoin-core raw tx API++testPKHashVector :: ([(Text, Word32)], [(Text, Word64)], Text) -> Assertion+testPKHashVector (is, os, res) =+    assertEqual "Build PKHash Tx" (Right res) (encodeHex . S.encode <$> txE)   where-    tx =-        fromRight (error "Could not decode transaction") $-        buildAddrTx btc (map f xs) ys+    txE = buildAddrTx btc (map f is) os     f (tid, ix) = OutPoint (fromJust $ hexToTxHash tid) ix --- These test vectors have been generated from bitcoind raw transaction api--pkHashVec :: [([(Text, Word32)], [(Text, Word64)], Text)]-pkHashVec =-    [-      ( [("eb29eba154166f6541ebcc9cbdf5088756e026af051f123bcfb526df594549db",14)]-      , [("14LsRquZfURNFrzpcLVGdaHTfAPjjwiSPb",90000000)]-      , "0100000001db494559df26b5cf3b121f05af26e0568708f5bd9ccceb41656f1654a1eb29eb0e00000000ffffffff01804a5d05000000001976a91424aa604689cc582292b97668bedd91dd5bf9374c88ac00000000"-      )-    , ( [ ("eb29eba154166f6541ebcc9cbdf5088756e026af051f123bcfb526df594549db",0)-        , ("0001000000000000000000000000000000000000000000000000000000000000",2147483647)+pkHashVectors :: [([(Text, Word32)], [(Text, Word64)], Text)]+pkHashVectors =+    [ ( [ ( "eb29eba154166f6541ebcc9cbdf5088756e026af051f123bcfb526df594549db"+          , 14)         ]-      , [ ("14LsRquZfURNFrzpcLVGdaHTfAPjjwiSPb",1)-        , ("19VCgS642vzEA1sdByoSn6GsWBwraV8D4n",2100000000000000)+      , [("14LsRquZfURNFrzpcLVGdaHTfAPjjwiSPb", 90000000)]+      , "0100000001db494559df26b5cf3b121f05af26e0568708f5bd9ccceb41656f1654\+        \a1eb29eb0e00000000ffffffff01804a5d05000000001976a91424aa604689cc58\+        \2292b97668bedd91dd5bf9374c88ac00000000")+    , ( [ ( "eb29eba154166f6541ebcc9cbdf5088756e026af051f123bcfb526df594549db"+          , 0)+        , ( "0001000000000000000000000000000000000000000000000000000000000000"+          , 2147483647)         ]-      , "0100000002db494559df26b5cf3b121f05af26e0568708f5bd9ccceb41656f1654a1eb29eb0000000000ffffffff0000000000000000000000000000000000000000000000000000000000000100ffffff7f00ffffffff0201000000000000001976a91424aa604689cc582292b97668bedd91dd5bf9374c88ac0040075af07507001976a9145d16672f53981ff21c5f42b40d1954993cbca54f88ac00000000"-      )-    , ( [ ("eb29eba154166f6541ebcc9cbdf5088756e026af051f123bcfb526df594549db",0)-        , ("0001000000000000000000000000000000000000000000000000000000000000",2147483647)+      , [ ("14LsRquZfURNFrzpcLVGdaHTfAPjjwiSPb", 1)+        , ("19VCgS642vzEA1sdByoSn6GsWBwraV8D4n", 2100000000000000)         ]+      , "0100000002db494559df26b5cf3b121f05af26e0568708f5bd9ccceb41656f1654\+        \a1eb29eb0000000000ffffffff0000000000000000000000000000000000000000\+        \000000000000000000000100ffffff7f00ffffffff0201000000000000001976a9\+        \1424aa604689cc582292b97668bedd91dd5bf9374c88ac0040075af07507001976\+        \a9145d16672f53981ff21c5f42b40d1954993cbca54f88ac00000000")+    , ( [ ( "eb29eba154166f6541ebcc9cbdf5088756e026af051f123bcfb526df594549db"+          , 0)+        , ( "0001000000000000000000000000000000000000000000000000000000000000"+          , 2147483647)+        ]       , []-      , "0100000002db494559df26b5cf3b121f05af26e0568708f5bd9ccceb41656f1654a1eb29eb0000000000ffffffff0000000000000000000000000000000000000000000000000000000000000100ffffff7f00ffffffff0000000000"-      )+      , "0100000002db494559df26b5cf3b121f05af26e0568708f5bd9ccceb41656f1654a\+        \1eb29eb0000000000ffffffff000000000000000000000000000000000000000000\+        \0000000000000000000100ffffff7f00ffffffff0000000000")     , ( []-      , [ ("14LsRquZfURNFrzpcLVGdaHTfAPjjwiSPb",1)-        , ("19VCgS642vzEA1sdByoSn6GsWBwraV8D4n",2100000000000000)+      , [ ("14LsRquZfURNFrzpcLVGdaHTfAPjjwiSPb", 1)+        , ("19VCgS642vzEA1sdByoSn6GsWBwraV8D4n", 2100000000000000)         ]-      , "01000000000201000000000000001976a91424aa604689cc582292b97668bedd91dd5bf9374c88ac0040075af07507001976a9145d16672f53981ff21c5f42b40d1954993cbca54f88ac00000000"-      )+      , "01000000000201000000000000001976a91424aa604689cc582292b97668bedd91d\+        \d5bf9374c88ac0040075af07507001976a9145d16672f53981ff21c5f42b40d1954\+        \993cbca54f88ac00000000")     ] -tEncodeSatoshiCoreScriptPubKey :: Assertion-tEncodeSatoshiCoreScriptPubKey = assertBool "tEncodeSatoshiCoreScriptPubKey" $-  t1BsOutputScriptPubKey == encodeSatoshiCoreScriptPubKey t1SatoshiCoreJsonScriptPubKey-  where-    t1BsOutputScriptPubKey :: Text-    t1BsOutputScriptPubKey = "514104cc71eb30d653c0c3163990c47b976f3fb3f37cccdcbedb169a1dfef58bbfbfaff7d8a473e7e2e6d317b87bafe8bde97e3cf8f065dec022b51d11fcdd0d348ac4410461cbdcc5409fb4b4d42b51d33381354d80e550078cb532a34bfa2fcfdeb7d76519aecc62770f5b0e4ef8551946d8a540911abe3e7854a26f39f58b25c15342af52ae"-    t1SatoshiCoreJsonScriptPubKey :: String-    t1SatoshiCoreJsonScriptPubKey = "1 0x41 0x04cc71eb30d653c0c3163990c47b976f3fb3f37cccdcbedb169a1dfef58bbfbfaff7d8a473e7e2e6d317b87bafe8bde97e3cf8f065dec022b51d11fcdd0d348ac4 0x41 0x0461cbdcc5409fb4b4d42b51d33381354d80e550078cb532a34bfa2fcfdeb7d76519aecc62770f5b0e4ef8551946d8a540911abe3e7854a26f39f58b25c15342af 2 OP_CHECKMULTISIG"--encodeSatoshiCoreScriptPubKey :: String -> Text-encodeSatoshiCoreScriptPubKey =-  mconcat . map encodeSatoshiCoreScriptPiece . words-  where-    encodeSatoshiCoreScriptPiece :: String -> Text-    encodeSatoshiCoreScriptPiece s = case (readMay ("OP_" ++ s) :: Maybe ScriptOp) of-      Just op -> encodeHex . S.encode $ op-      Nothing -> case take 2 s of-          "OP" -> encodeHex . S.encode . (read :: String -> ScriptOp) $ s-          "0x" -> (fromString . drop 2 :: String -> Text) s-          _ -> case (readMay s :: Maybe Int) of -- can we get rid of this case now?-            Just i  -> encodeHex . S.encode . intToScriptOp $ i-            Nothing -> error $ "encodeSatoshiCoreScriptPubKey: " ++ s------- Following tests depend on specific secp256k1 deterministic nonce computation.--- Fedora distributes the Bitcoin ABC fork of this library, which computes nonces differently.------- -- Reproduce the P2WPKH example from BIP 143--- testBip143p2wpkh :: Assertion--- testBip143p2wpkh = assertEqual "BIP143 p2wpkh" (Right exampleSignedTx) generatedSignedTx---   where---     exampleSignedTx = "01000000000102fff7f7881a8099afa6940d42d1e7f6362bec38171ea3edf433541db4e4ad969f00000000494830450221008b9d1dc26ba6a9cb62127b02742fa9d754cd3bebf337f7a55d114c8e5cdd30be022040529b194ba3f9281a99f2b1c0a19c0489bc22ede944ccf4ecbab4cc618ef3ed01eeffffffef51e1b804cc89d182d279655c3aa89e815b1b309fe287d9b2b55d57b90ec68a0100000000ffffffff02202cb206000000001976a9148280b37df378db99f66f85c95a783a76ac7a6d5988ac9093510d000000001976a9143bde42dbee7e4dbe6a21b2d50ce2f0167faa815988ac000247304402203609e17b84f6a7d30c80bfa610b5b4542f32a8a0d5447a12fb1366d7f01cc44a0220573a954c4518331561406f90300e8f3358f51928d43c212a8caed02de67eebee0121025476c2e83188368da1ff3e292e7acafcdb3566bb0ad253f62fc70f07aeee635711000000"----     unsignedTx = "0100000002fff7f7881a8099afa6940d42d1e7f6362bec38171ea3edf433541db4e4ad969f0000000000eeffffffef51e1b804cc89d182d279655c3aa89e815b1b309fe287d9b2b55d57b90ec68a0100000000ffffffff02202cb206000000001976a9148280b37df378db99f66f85c95a783a76ac7a6d5988ac9093510d000000001976a9143bde42dbee7e4dbe6a21b2d50ce2f0167faa815988ac11000000"----     Just key0 = secHexKey "bbc27228ddcb9209d7fd6f36b02f7dfa6252af40bb2f1cbc7a557da8027ff866"---     pubKey0   = toPubKey key0----     Just key1 = secHexKey "619c335025c7f4012e556c2a58b2506e30b8511b53ade95ea316fd8c3286feb9"----     [op0, op1] = prevOutput <$> txIn unsignedTx----     sigIn0 = SigInput (PayPK pubKey0) 625000000 op0 sigHashAll Nothing----     WitnessPubKeyAddress h = pubKeyWitnessAddr $ toPubKey key1---     sigIn1                 = SigInput (PayWitnessPKHash h) 600000000 op1 sigHashAll Nothing----     generatedSignedTx = signTx btc unsignedTx [sigIn0, sigIn1] [key0, key1]---- -- Reproduce the P2SH-P2WPKH example from BIP 143--- testBip143p2shp2wpkh :: Assertion--- testBip143p2shp2wpkh = assertEqual "BIP143 p2sh-p2wpkh" (Right exampleSignedTx) generatedSignedTx---   where---     exampleSignedTx = "01000000000101db6b1b20aa0fd7b23880be2ecbd4a98130974cf4748fb66092ac4d3ceb1a5477010000001716001479091972186c449eb1ded22b78e40d009bdf0089feffffff02b8b4eb0b000000001976a914a457b684d7f0d539a46a45bbc043f35b59d0d96388ac0008af2f000000001976a914fd270b1ee6abcaea97fea7ad0402e8bd8ad6d77c88ac02473044022047ac8e878352d3ebbde1c94ce3a10d057c24175747116f8288e5d794d12d482f0220217f36a485cae903c713331d877c1f64677e3622ad4010726870540656fe9dcb012103ad1d8e89212f0b92c74d23bb710c00662ad1470198ac48c43f7d6f93a2a2687392040000"----     unsignedTx = "0100000001db6b1b20aa0fd7b23880be2ecbd4a98130974cf4748fb66092ac4d3ceb1a54770100000000feffffff02b8b4eb0b000000001976a914a457b684d7f0d539a46a45bbc043f35b59d0d96388ac0008af2f000000001976a914fd270b1ee6abcaea97fea7ad0402e8bd8ad6d77c88ac92040000"----     Just key0 = secHexKey "eb696a065ef48a2192da5b28b694f87544b30fae8327c4510137a922f32c6dcf"----     op0                    = prevOutput . head $ txIn unsignedTx---     WitnessPubKeyAddress h = pubKeyWitnessAddr $ toPubKey key0---     sigIn0                 = SigInput (PayWitnessPKHash h) 1000000000 op0 sigHashAll Nothing----     generatedSignedTx = signNestedWitnessTx btc unsignedTx [sigIn0] [key0]---- -- P2WSH multisig example (tested against bitcoin-core 0.19.0.1)--- testP2WSHMulsig :: Assertion--- testP2WSHMulsig = assertEqual "p2wsh multisig" (Right exampleSignedTx) generatedSignedTx---   where---     exampleSignedTx = "01000000000101d2e34df5d7ee565208eddd231548916b9b0e99f4f5071f896134a448c5fb07bf0100000000ffffffff01f0b9f505000000001976a9143d5a352cab583b12fbcb26d1269b4a2c951a33ad88ac0400483045022100fad4fedd2bb4c439c64637eb8e9150d9020a7212808b8dc0578d5ff5b4ad65fe0220714640f261b37eb3106310bf853f4b706e51436fb6b64c2ab00768814eb55b9801473044022100baff4e4ceea4022b9725a2e6f6d77997a554f858165b91ac8c16c9833008bee9021f5f70ebc3f8580dc0a5e96451e3697bdf1f1f5883944f0f33ab0cfb272354040169522102ba46d3bb8db74c77c6cf082db57fc0548058fcdea811549e186526e3d10caf6721038ac8aef2dd9cea5e7d66e2f6e23f177a6c21f69ea311fa0c85d81badb6b37ceb2103d96d2bfbbc040faaf93491d69e2bfe9695e2d8e007a7f26db96c2ee42db15dc953ae00000000"----     unsignedTx = "0100000001d2e34df5d7ee565208eddd231548916b9b0e99f4f5071f896134a448c5fb07bf0100000000ffffffff01f0b9f505000000001976a9143d5a352cab583b12fbcb26d1269b4a2c951a33ad88ac00000000"----     op0 = head $ prevOutput <$> txIn unsignedTx----     Just keys = traverse secHexKey [ "3030303030303030303030303030303030303030303030303030303030303031"---                                    , "3030303030303030303030303030303030303030303030303030303030303032"---                                    , "3030303030303030303030303030303030303030303030303030303030303033"---                                    ]----     rdm               = PayMulSig (toPubKey <$> keys) 2---     sigIn             = SigInput (toP2WSH $ encodeOutput rdm) 100000000 op0 sigHashAll (Just rdm)---     generatedSignedTx = signTx btc unsignedTx [sigIn] (take 2 keys)---- -- Reproduce the P2SH-P2WSH multisig example from BIP 143--- testBip143p2shp2wpkhMulsig :: Assertion--- testBip143p2shp2wpkhMulsig =---     assertEqual "BIP143 p2sh-p2wsh multisig" (Right exampleSignedTx) generatedSignedTx---   where---     exampleSignedTx = "0100000000010136641869ca081e70f394c6948e8af409e18b619df2ed74aa106c1ca29787b96e0100000023220020a16b5755f7f6f96dbd65f5f0d6ab9418b89af4b1f14a1bb8a09062c35f0dcb54ffffffff0200e9a435000000001976a914389ffce9cd9ae88dcc0631e88a821ffdbe9bfe2688acc0832f05000000001976a9147480a33f950689af511e6e84c138dbbd3c3ee41588ac080047304402206ac44d672dac41f9b00e28f4df20c52eeb087207e8d758d76d92c6fab3b73e2b0220367750dbbe19290069cba53d096f44530e4f98acaa594810388cf7409a1870ce01473044022068c7946a43232757cbdf9176f009a928e1cd9a1a8c212f15c1e11ac9f2925d9002205b75f937ff2f9f3c1246e547e54f62e027f64eefa2695578cc6432cdabce271502473044022059ebf56d98010a932cf8ecfec54c48e6139ed6adb0728c09cbe1e4fa0915302e022007cd986c8fa870ff5d2b3a89139c9fe7e499259875357e20fcbb15571c76795403483045022100fbefd94bd0a488d50b79102b5dad4ab6ced30c4069f1eaa69a4b5a763414067e02203156c6a5c9cf88f91265f5a942e96213afae16d83321c8b31bb342142a14d16381483045022100a5263ea0553ba89221984bd7f0b13613db16e7a70c549a86de0cc0444141a407022005c360ef0ae5a5d4f9f2f87a56c1546cc8268cab08c73501d6b3be2e1e1a8a08824730440220525406a1482936d5a21888260dc165497a90a15669636d8edca6b9fe490d309c022032af0c646a34a44d1f4576bf6a4a74b67940f8faa84c7df9abe12a01a11e2b4783cf56210307b8ae49ac90a048e9b53357a2354b3334e9c8bee813ecb98e99a7e07e8c3ba32103b28f0c28bfab54554ae8c658ac5c3e0ce6e79ad336331f78c428dd43eea8449b21034b8113d703413d57761b8b9781957b8c0ac1dfe69f492580ca4195f50376ba4a21033400f6afecb833092a9a21cfdf1ed1376e58c5d1f47de74683123987e967a8f42103a6d48b1131e94ba04d9737d61acdaa1322008af9602b3b14862c07a1789aac162102d8b661b0b3302ee2f162b09e07a55ad5dfbe673a9f01d9f0c19617681024306b56ae00000000"----     unsignedTx = "010000000136641869ca081e70f394c6948e8af409e18b619df2ed74aa106c1ca29787b96e0100000000ffffffff0200e9a435000000001976a914389ffce9cd9ae88dcc0631e88a821ffdbe9bfe2688acc0832f05000000001976a9147480a33f950689af511e6e84c138dbbd3c3ee41588ac00000000"----     op0 = head $ prevOutput <$> txIn unsignedTx----     rawKeys = [ "730fff80e1413068a05b57d6a58261f07551163369787f349438ea38ca80fac6"---               , "11fa3d25a17cbc22b29c44a484ba552b5a53149d106d3d853e22fdd05a2d8bb3"---               , "77bf4141a87d55bdd7f3cd0bdccf6e9e642935fec45f2f30047be7b799120661"---               , "14af36970f5025ea3e8b5542c0f8ebe7763e674838d08808896b63c3351ffe49"---               , "fe9a95c19eef81dde2b95c1284ef39be497d128e2aa46916fb02d552485e0323"---               , "428a7aee9f0c2af0cd19af3cf1c78149951ea528726989b2e83e4778d2c3f890"---               ]----     Just keys@[key0, key1, key2, key3, key4, key5] = traverse secHexKey rawKeys----     rdm      = PayMulSig (toPubKey <$> keys) 6---     sigIn sh = SigInput (toP2WSH $ encodeOutput rdm) 987654321 op0 sh (Just rdm)----     sigHashesA = [sigHashAll, sigHashNone, sigHashSingle]---     sigHashesB = setAnyoneCanPayFlag <$> sigHashesA---     sigIns     = sigIn <$> (sigHashesA <> sigHashesB)----     generatedSignedTx      = foldM addSig unsignedTx $ zip sigIns keys---     addSig tx (sigIn, key) = signNestedWitnessTx btc tx [sigIn] [key]---- secHexKey :: Text -> Maybe SecKey--- secHexKey = decodeHex >=> secKey---- toPubKey :: SecKey -> PubKeyI--- toPubKey = derivePubKeyI . wrapSecKey True--{- Building Transactions -}+-- Transaction Properties --  testBuildAddrTx :: Network -> Address -> TestCoin -> Bool testBuildAddrTx net a (TestCoin v)@@ -291,17 +209,17 @@     | isScriptAddress a = Right (PayScriptHash (getAddrHash160 a)) == out     | otherwise = undefined   where-    tx = buildAddrTx net [] [(fromJust (addrToString net a), v)]+    tx = buildAddrTx net [] [(fromJust (addrToText net a), v)]     out =         decodeOutputBS $         scriptOutput $         head $ txOut (fromRight (error "Could not build transaction") tx) +-- We compute an upper bound but it should be close enough to the real size+-- We give 2 bytes of slack on every signature (1 on r and 1 on s) testGuessSize :: Network -> Tx -> Bool-testGuessSize net tx-    -- We compute an upper bound but it should be close enough to the real size-    -- We give 2 bytes of slack on every signature (1 on r and 1 on s)- = guess >= len && guess <= len + 2 * delta+testGuessSize net tx =+    guess >= len && guess <= len + 2 * delta   where     delta = pki + sum (map fst msi)     guess = guessTxSize pki msi pkout msout@@ -313,7 +231,7 @@     pki = length $ filter isSpendPKHash ins     msi = concatMap shData ins     shData (ScriptHashInput _ (PayMulSig keys r)) = [(r, length keys)]-    shData _                                      = []+    shData _ = []     out =         map             (fromRight (error "Could not decode transaction output") .@@ -352,9 +270,10 @@ {- Signing Transactions -}  testDetSignTx :: Network -> (Tx, [SigInput], [SecKeyI]) -> Bool-testDetSignTx net  (tx, sigis, prv) =+testDetSignTx net (tx, sigis, prv) =     not (verifyStdTx net tx verData) &&-    not (verifyStdTx net txSigP verData) && verifyStdTx net txSigC verData+    not (verifyStdTx net txSigP verData) &&+    verifyStdTx net txSigC verData   where     txSigP =         fromRight (error "Could not decode transaction") $@@ -367,7 +286,8 @@ testDetSignNestedTx :: Network -> (Tx, [SigInput], [SecKeyI]) -> Bool testDetSignNestedTx net  (tx, sigis, prv) =     not (verifyStdTx net tx verData) &&-    not (verifyStdTx net txSigP verData) && verifyStdTx net txSigC verData+    not (verifyStdTx net txSigP verData) &&+    verifyStdTx net txSigC verData   where     txSigP =         fromRight (error "Could not decode transaction") $@@ -381,21 +301,26 @@         | otherwise  = (s, v, o)  testMergeTx :: Network -> ([Tx], [(ScriptOutput, Word64, OutPoint, Int, Int)]) -> Bool-testMergeTx net (txs, os) = and-    [ isRight mergeRes-    , length (txIn mergedTx) == length os-    , if enoughSigs then isValid else not isValid-    -- Signature count == min (length txs) (sum required signatures)-    , sum (map snd sigMap) == min (length txs) (sum (map fst sigMap))-    ]+testMergeTx net (txs, os) =+    and [ isRight mergeRes+        , length (txIn mergedTx) == length os+        , if enoughSigs+              then isValid+              else not isValid+        -- Signature count == min (length txs) (sum required signatures)+        , sum (map snd sigMap) == min (length txs) (sum (map fst sigMap))+        ]   where     outs = map (\(so, val, op, _, _) -> (so, val, op)) os     mergeRes = mergeTxs net txs outs     mergedTx = fromRight (error "Could not merge") mergeRes     isValid = verifyStdTx net mergedTx outs-    enoughSigs = all (\(m,c) -> c >= m) sigMap-    sigMap = map (\((_,_,_,m,_), inp) -> (m, sigCnt inp)) $ zip os $ txIn mergedTx-    sigCnt inp = case decodeInputBS net $ scriptInput inp of-        Right (RegularInput (SpendMulSig sigs)) -> length sigs-        Right (ScriptHashInput (SpendMulSig sigs) _) -> length sigs-        _ -> error "Invalid input script type"+    enoughSigs = all (\(m, c) -> c >= m) sigMap+    sigMap =+        map (\((_, _, _, m, _), inp) -> (m, sigCnt inp)) $+        zip os $ txIn mergedTx+    sigCnt inp =+        case decodeInputBS net $ scriptInput inp of+            Right (RegularInput (SpendMulSig sigs)) -> length sigs+            Right (ScriptHashInput (SpendMulSig sigs) _) -> length sigs+            _ -> error "Invalid input script type"
test/Haskoin/UtilSpec.hs view
@@ -1,6 +1,7 @@ module Haskoin.UtilSpec     ( spec     , customCerealID+    , readTestFile     ) where  import           Data.Aeson             (FromJSON, ToJSON)@@ -67,6 +68,13 @@ testMaybeToEither (Just v) str = maybeToEither str (Just v) == Right v testMaybeToEither m str = maybeToEither str m == Left str +{-- Test Utilities --}+ customCerealID :: Eq a => Get a -> Putter a -> a -> Bool customCerealID g p a = runGet g (runPut (p a)) == Right a++readTestFile :: A.FromJSON a => FilePath -> IO a+readTestFile fp = do+    fileM <- A.decodeFileStrict $ "data/" <> fp+    maybe (error $ "Could not read test file " <> fp) return fileM