diff --git a/BRBech32.c b/BRBech32.c new file mode 100644 index 000000000..7773895c5 --- /dev/null +++ b/BRBech32.c @@ -0,0 +1,144 @@ +// +// BRBech32.c +// +// Created by Aaron Voisine on 1/20/18. +// Copyright (c) 2018 breadwallet LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#include "BRBech32.h" +#include "BRAddress.h" +#include "BRCrypto.h" +#include +#include +#include +#include +#include + +// bech32 address format: https://github.com/bitcoin/bips/blob/master/bip-0173.mediawiki + +#define polymod(x) ((((x) & 0x1ffffff) << 5) ^ (-(((x) >> 25) & 1) & 0x3b6a57b2) ^\ + (-(((x) >> 26) & 1) & 0x26508e6d) ^ (-(((x) >> 27) & 1) & 0x1ea119fa) ^\ + (-(((x) >> 28) & 1) & 0x3d4233dd) ^ (-(((x) >> 29) & 1) & 0x2a1462b3)) + +// returns the number of bytes written to data42 (maximum of 42) +size_t BRBech32Decode(char *hrp84, uint8_t *data42, const char *addr) +{ + size_t i, j, bufLen, addrLen, sep; + uint32_t x, chk = 1; + uint8_t c, ver = 0xff, buf[52], upper = 0, lower = 0; + + assert(hrp84 != NULL); + assert(data42 != NULL); + assert(addr != NULL); + + for (i = 0; addr && addr[i]; i++) { + if (addr[i] < 33 || addr[i] > 126) return 0; + if (islower(addr[i])) lower = 1; + if (isupper(addr[i])) upper = 1; + } + + addrLen = sep = i; + while (sep > 0 && addr[sep] != '1') sep--; + if (addrLen < 8 || addrLen > 90 || sep < 1 || sep + 2 + 6 > addrLen || (upper && lower)) return 0; + for (i = 0; i < sep; i++) chk = polymod(chk) ^ (tolower(addr[i]) >> 5); + chk = polymod(chk); + for (i = 0; i < sep; i++) chk = polymod(chk) ^ (addr[i] & 0x1f); + memset(buf, 0, sizeof(buf)); + + for (i = sep + 1, j = -1; i < addrLen; i++, j++) { + switch (tolower(addr[i])) { + case 'q': c = 0; break; case 'p': c = 1; break; case 'z': c = 2; break; case 'r': c = 3; break; + case 'y': c = 4; break; case '9': c = 5; break; case 'x': c = 6; break; case '8': c = 7; break; + case 'g': c = 8; break; case 'f': c = 9; break; case '2': c = 10; break; case 't': c = 11; break; + case 'v': c = 12; break; case 'd': c = 13; break; case 'w': c = 14; break; case '0': c = 15; break; + case 's': c = 16; break; case '3': c = 17; break; case 'j': c = 18; break; case 'n': c = 19; break; + case '5': c = 20; break; case '4': c = 21; break; case 'k': c = 22; break; case 'h': c = 23; break; + case 'c': c = 24; break; case 'e': c = 25; break; case '6': c = 26; break; case 'm': c = 27; break; + case 'u': c = 28; break; case 'a': c = 29; break; case '7': c = 30; break; case 'l': c = 31; break; + default: return 0; // invalid bech32 digit + } + + chk = polymod(chk) ^ c; + if (j == -1) ver = c; + if (j == -1 || i + 6 >= addrLen) continue; + x = (j % 8)*5 - ((j % 8)*5/8)*8; + buf[(j/8)*5 + (j % 8)*5/8] |= (c << 3) >> x; + if (x > 3) buf[(j/8)*5 + (j % 8)*5/8 + 1] |= c << (11 - x); + } + + bufLen = (addrLen - (sep + 2 + 6))*5/8; + if (hrp84 == NULL || data42 == NULL || chk != 1 || ver > 16 || bufLen < 2 || bufLen > 40) return 0; + assert(sep < 84); + for (i = 0; i < sep; i++) hrp84[i] = tolower(addr[i]); + hrp84[sep] = '\0'; + data42[0] = (ver == 0) ? OP_0 : ver + OP_1 - 1; + data42[1] = bufLen; + assert(bufLen <= 40); + memcpy(&data42[2], buf, bufLen); + return 2 + bufLen; +} + +// data must contain a valid BIP141 witness program +// returns the number of bytes written to addr91 (maximum of 91) +size_t BRBech32Encode(char *addr91, const char *hrp, const uint8_t data[]) +{ + static const char chars[] = "qpzry9x8gf2tvdw0s3jn54khce6mua7l"; + char addr[91]; + uint32_t x, chk = 1; + uint8_t ver, a, b = 0, c = 0; + size_t i, j, len; + + assert(addr91 != NULL); + assert(hrp != NULL); + assert(data != NULL); + + for (i = 0; hrp && hrp[i]; i++) { + if (i > 83 || hrp[i] < 33 || hrp[i] > 126 || isupper(hrp[i])) return 0; + chk = polymod(chk) ^ (hrp[i] >> 5); + addr[i] = hrp[i]; + } + + chk = polymod(chk); + for (j = 0; j < i; j++) chk = polymod(chk) ^ (hrp[j] & 0x1f); + addr[i++] = '1'; + if (i < 1 || data == NULL || (data[0] > OP_0 && data[0] < OP_1)) return 0; + ver = (data[0] >= OP_1) ? data[0] + 1 - OP_1 : 0; + len = data[1]; + if (ver > 16 || len < 2 || len > 40 || i + 1 + len + 6 >= 91) return 0; + chk = polymod(chk) ^ ver; + addr[i++] = chars[ver]; + + for (j = 0; j <= len; j++) { + a = b, b = (j < len) ? data[2 + j] : 0; + x = (j % 5)*8 - ((j % 5)*8/5)*5; + c = ((a << (5 - x)) | (b >> (3 + x))) & 0x1f; + if (j < len || j % 5 > 0) chk = polymod(chk) ^ c, addr[i++] = chars[c]; + if (x >= 2) c = (b >> (x - 2)) & 0x1f; + if (x >= 2 && j < len) chk = polymod(chk) ^ c, addr[i++] = chars[c]; + } + + for (j = 0; j < 6; j++) chk = polymod(chk); + chk ^= 1; + for (j = 0; j < 6; ++j) addr[i++] = chars[(chk >> ((5 - j)*5)) & 0x1f]; + addr[i++] = '\0'; + memcpy(addr91, addr, i); + return i; +} + diff --git a/BRBech32.h b/BRBech32.h new file mode 100644 index 000000000..e9b9ca445 --- /dev/null +++ b/BRBech32.h @@ -0,0 +1,48 @@ +// +// BRBech32.h +// +// Created by Aaron Voisine on 1/20/18. +// Copyright (c) 2018 breadwallet LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#ifndef BRBech32_h +#define BRBech32_h + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +// bech32 address format: https://github.com/bitcoin/bips/blob/master/bip-0173.mediawiki + +// returns the number of bytes written to data42 (maximum of 42) +size_t BRBech32Decode(char *hrp84, uint8_t *data42, const char *addr); + +// data must contain a valid BIP141 witness program +// returns the number of bytes written to addr91 (maximum of 91) +size_t BRBech32Encode(char *addr91, const char *hrp, const uint8_t data[]); + +#ifdef __cplusplus +} +#endif + +#endif // BRBech32_h diff --git a/BRChainParams.h b/BRChainParams.h new file mode 100644 index 000000000..af16e6bc3 --- /dev/null +++ b/BRChainParams.h @@ -0,0 +1,136 @@ +// +// BRChainParams.h +// +// Created by Aaron Voisine on 1/10/18. +// Copyright (c) 2019 breadwallet LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#ifndef BRChainParams_h +#define BRChainParams_h + +#include "BRMerkleBlock.h" +#include "BRSet.h" +#include + +typedef struct { + uint32_t height; + UInt256 hash; + uint32_t timestamp; + uint32_t target; +} BRCheckPoint; + +typedef struct { + const char * const *dnsSeeds; // NULL terminated array of dns seeds + uint16_t standardPort; + uint32_t magicNumber; + uint64_t services; + int (*verifyDifficulty)(const BRMerkleBlock *block, const BRSet *blockSet); // blockSet must have last 2016 blocks + const BRCheckPoint *checkpoints; + size_t checkpointsCount; +} BRChainParams; + +static const char *BRMainNetDNSSeeds[] = { + "dnsseed.litecoinpool.org.", "seed-a.litecoin.loshan.co.uk.", "dnsseed.thrasher.io.", + "dnsseed.koin-project.com.", "dnsseed.litecointools.com.", NULL}; + +static const char *BRTestNetDNSSeeds[] = { + "testnet-seed.ltc.xurious.com.", "seed-b.litecoin.loshan.co.uk.", "dnsseed-testnet.thrasher.io.", NULL +}; + +// blockchain checkpoints - these are also used as starting points for partial chain downloads, so they must be at +// difficulty transition boundaries in order to verify the block difficulty at the immediately following transition +static const BRCheckPoint BRMainNetCheckpoints[] = { + { 0, uint256("12a765e31ffd4059bada1e25190f6e98c99d9714d334efa41a195a7e7e04bfe2"), 1317972665, 0x1e0ffff0 }, + { 20160, uint256("633036c8df655531c2449b2d09b264cc0b49d945a89be23fd3c1a97361ca198c"), 1319798300, 0x1d055262 }, + { 40320, uint256("d148cdd2cf44069cef4b63f0feaf30a8d291ca9ea9ba7e83f226b9738c1d5e9c"), 1322522019, 0x1d018053 }, + { 60480, uint256("3250f0a560d55f039c34bfaee1b71297aa5104ac6641778f9a87d73232d12c6c"), 1325540574, 0x1d00e848 }, + { 80640, uint256("bedc0a090b740b1902d870aeb6caa89040a24e7d670d46f8ef035fd9d2e9ce80"), 1328779944, 0x1d00ab92 }, + { 100800, uint256("7b0b620d15f781faaaa73b43607a49d5becb2b803ef19b4010014646cc177a61"), 1331873688, 0x1d00ae9f }, + { 120960, uint256("dbd6249f30e5690890bc03dabcc0a526c46adcde572be06af4075b6ea28aa251"), 1334881566, 0x1d009e48 }, + { 141120, uint256("5d5e15a45cecf2b9528e36e63c407167423a2f9963a96bbce3b67b75fd10be2a"), 1338009318, 0x1d00d6a6 }, + { 161280, uint256("f595c754d0abcfe3616573bfabee01b230ec0ea6b2f2894c40214ea23d772b6c"), 1340918301, 0x1d008881 }, + { 181440, uint256("d7fa3152959f3c25e33edf825f7cbef75ee651d5f9183cc4ed8d19d57b8f35a4"), 1343534530, 0x1c1cd430 }, + { 201600, uint256("d481df8e8ce144fca9ae6b3157cc706e903c6ea161a13d2c421270354a02d6d0"), 1346567025, 0x1c1c89e8 }, + { 282240, uint256("8932095fba44bd6860fd71745c0dca908769221a47166ab1fb442b6cefcd53fb"), 1358801720, 0x1c0ced21 }, + { 342720, uint256("33f62e026a202be550e8a9df37d638d38991553544e279cb264123378bf46042"), 1367113967, 0x1c0095a5 }, + { 383040, uint256("5c0a443361c1356796a7db472c69433b6ce6108d61e4403fd9a9d91e01009ce3"), 1372971948, 0x1b481262 }, + { 443520, uint256("37d668803ed1efc24ffab4a2a90da9ac92679acf68370d7570f042c2bd6d651b"), 1382034998, 0x1b3f864f }, + { 504000, uint256("97db0624d3d5137bc085f0d731607314972bb4124b85b73420ef9aa5fc10d640"), 1390892377, 0x1b1aa868 }, + { 564480, uint256("c876276bf12754c2b265787d9e7ab83d429e59761dc63057f728529018db7834"), 1399724592, 0x1b099dce }, + { 624960, uint256("ccac71fafe98107b81ac3e0eed41190e4d47600962c93c49db8843b53f760bda"), 1408389228, 0x1b02552d }, + { 685440, uint256("29d2328990dda4c4870846d4e3d573785452bed68e6013930a83fc8d5fe89b09"), 1417289378, 0x1b01473b }, + { 745920, uint256("04809a35ff6e5054e21d14582072605b812b7d4ae11d3450e7c03a7237e1d35d"), 1426441593, 0x1b019b8c }, + { 806400, uint256("e2363e8b3e8f237b9b1bfc1c72ede80fef2c7bd1aabcd78afed82065a194b960"), 1435516150, 0x1b019268 }, + { 846720, uint256("6f5d94d7cfd01f1dbf4aa631b987f8e2ec9d0c57720604787b816bafe34192a8"), 1441561050, 0x1b0187a3 }, + { 901152, uint256("cfccdf8e3830ae4879e910051ac3dc583b4fb45b83be3a38019e5d9326dfa223"), 1449698771, 0x1b015b0e }, + { 953568, uint256("e46e01cf1239cffa69408ac162d517bac5a4899972e0328fd0ba4d93e8ad3764"), 1457542869, 0x1b013c91 }, + { 1058400, uint256("76ce37c66d449a4ffbfc35674cf932da701066a001dc223754f9250dd2bdbc62"), 1473296285, 0x1b013ca7 }, + { 1260000, uint256("85a22b528d805bf7a641d1d7c6d96ef5054beda3dcab6be7b83f2e3df24b33a8"), 1502976600, 0x1a25a0d3 }, + { 1411200, uint256("92c85b76f3d4bffca76b23717e4eb1b667c77c96fd52d4dd5dd843bbee64cd73"), 1524838967, 0x1a0203a7 } +}; + +static const BRCheckPoint BRTestNetCheckpoints[] = { + { 0, uint256("4966625a4b2851d9fdee139e56211a0d88575f59ed816ff5e6a63deb4e3e29a0"), 1486949366, 0x1e0ffff0 } +}; + +static int BRMainNetVerifyDifficulty(const BRMerkleBlock *block, const BRSet *blockSet) +{ + // const BRMerkleBlock *previous, *b = NULL; + // uint32_t i; + + // assert(block != NULL); + // assert(blockSet != NULL); + + // // check if we hit a difficulty transition, and find previous transition block + // if ((block->height % BLOCK_DIFFICULTY_INTERVAL) == 0) { + // for (i = 0, b = block; b && i < BLOCK_DIFFICULTY_INTERVAL; i++) { + // b = BRSetGet(blockSet, &b->prevBlock); + // } + // } + + // previous = BRSetGet(blockSet, &block->prevBlock); + // return BRMerkleBlockVerifyDifficulty(block, previous, (b) ? b->timestamp : 0); + return 1; +} + +static int BRTestNetVerifyDifficulty(const BRMerkleBlock *block, const BRSet *blockSet) +{ + return 1; // XXX skip testnet difficulty check for now +} + +static const BRChainParams BRMainNetParams = { + BRMainNetDNSSeeds, + 9333, // standardPort + 0xdbb6c0fb, // magicNumber + 0, // services + BRMainNetVerifyDifficulty, + BRMainNetCheckpoints, + sizeof(BRMainNetCheckpoints) / sizeof(*BRMainNetCheckpoints)}; + +static const BRChainParams BRTestNetParams = { + BRTestNetDNSSeeds, + 19335, // standardPort + 0xf1c8d2fd, // magicNumber + 0, // services + BRTestNetVerifyDifficulty, + BRTestNetCheckpoints, + sizeof(BRTestNetCheckpoints) / sizeof(*BRTestNetCheckpoints)}; + +#endif // BRChainParams_h