313 changes: 313 additions & 0 deletions ecc/javascript/bech32_ecc.js
@@ -0,0 +1,313 @@
var CHARSET = 'qpzry9x8gf2tvdw0s3jn54khce6mua7l';
var GENERATOR = [0x3b6a57b2, 0x26508e6d, 0x1ea119fa, 0x3d4233dd, 0x2a1462b3];

var GF1024_EXP = [
1, 303, 635, 446, 997, 640, 121, 142, 959, 420, 350, 438, 166, 39, 543,
335, 831, 691, 117, 632, 719, 97, 107, 374, 558, 797, 54, 150, 858, 877,
724, 1013, 294, 23, 354, 61, 164, 633, 992, 538, 469, 659, 174, 868, 184,
809, 766, 563, 866, 851, 257, 520, 45, 770, 535, 524, 408, 213, 436, 760,
472, 330, 933, 799, 616, 361, 15, 391, 756, 814, 58, 608, 554, 680, 993,
821, 942, 813, 843, 484, 193, 935, 321, 919, 572, 741, 423, 559, 562,
589, 296, 191, 493, 685, 891, 665, 435, 60, 395, 2, 606, 511, 853, 746,
32, 219, 284, 631, 840, 661, 837, 332, 78, 311, 670, 887, 111, 195, 505,
190, 194, 214, 709, 380, 819, 69, 261, 957, 1018, 161, 739, 588, 7, 708,
83, 328, 507, 736, 317, 899, 47, 348, 1000, 345, 882, 245, 367, 996, 943,
514, 304, 90, 804, 295, 312, 793, 387, 833, 249, 921, 660, 618, 823, 496,
722, 30, 782, 225, 892, 93, 480, 372, 112, 738, 867, 636, 890, 950, 968,
386, 622, 642, 551, 369, 234, 846, 382, 365, 442, 592, 343, 986, 122,
1023, 59, 847, 81, 790, 4, 437, 983, 931, 244, 64, 415, 529, 487, 944,
35, 938, 664, 156, 583, 53, 999, 222, 390, 987, 341, 388, 389, 170, 721,
879, 138, 522, 627, 765, 322, 230, 440, 14, 168, 143, 656, 991, 224, 595,
550, 94, 657, 752, 667, 1005, 451, 734, 744, 638, 292, 585, 157, 872,
590, 601, 827, 774, 930, 475, 571, 33, 500, 871, 969, 173, 21, 828, 450,
1009, 147, 960, 705, 201, 228, 998, 497, 1021, 613, 688, 772, 508, 36,
366, 715, 468, 956, 725, 730, 861, 425, 647, 701, 221, 759, 95, 958, 139,
805, 8, 835, 679, 614, 449, 128, 791, 299, 974, 617, 70, 628, 57, 273,
430, 67, 750, 405, 780, 703, 643, 776, 778, 340, 171, 1022, 276, 308,
495, 243, 644, 460, 857, 28, 336, 286, 41, 695, 448, 431, 364, 149, 43,
233, 63, 762, 902, 181, 240, 501, 584, 434, 275, 1008, 444, 443, 895,
812, 612, 927, 383, 66, 961, 1006, 690, 346, 3, 881, 900, 747, 271, 672,
162, 402, 456, 748, 971, 755, 490, 105, 808, 977, 72, 732, 182, 897, 625,
163, 189, 947, 850, 46, 115, 403, 231, 151, 629, 278, 874, 16, 934, 110,
492, 898, 256, 807, 598, 700, 498, 140, 481, 91, 523, 860, 134, 252, 771,
824, 119, 38, 816, 820, 641, 342, 757, 513, 577, 990, 463, 40, 920, 955,
17, 649, 533, 82, 103, 896, 862, 728, 259, 86, 466, 87, 253, 556, 323,
457, 963, 432, 845, 527, 745, 849, 863, 1015, 888, 488, 567, 727, 132,
674, 764, 109, 669, 6, 1003, 552, 246, 542, 96, 324, 781, 912, 248, 694,
239, 980, 210, 880, 683, 144, 177, 325, 546, 491, 326, 339, 623, 941, 92,
207, 783, 462, 263, 483, 517, 1012, 9, 620, 220, 984, 548, 512, 878, 421,
113, 973, 280, 962, 159, 310, 945, 268, 465, 806, 889, 199, 76, 873, 865,
34, 645, 227, 290, 418, 693, 926, 80, 569, 639, 11, 50, 291, 141, 206,
544, 949, 185, 518, 133, 909, 135, 467, 376, 646, 914, 678, 841, 954,
318, 242, 939, 951, 743, 1017, 976, 359, 167, 264, 100, 241, 218, 51, 12,
758, 368, 453, 309, 192, 648, 826, 553, 473, 101, 478, 673, 397, 1001,
118, 265, 331, 650, 356, 982, 652, 655, 510, 634, 145, 414, 830, 924,
526, 966, 298, 737, 18, 504, 401, 697, 360, 288, 1020, 842, 203, 698,
537, 676, 279, 581, 619, 536, 907, 876, 1019, 398, 152, 1010, 994, 68,
42, 454, 580, 836, 99, 565, 137, 379, 503, 22, 77, 582, 282, 412, 352,
611, 347, 300, 266, 570, 270, 911, 729, 44, 557, 108, 946, 637, 597, 461,
630, 615, 238, 763, 681, 718, 334, 528, 200, 459, 413, 79, 24, 229, 713,
906, 579, 384, 48, 893, 370, 923, 202, 917, 98, 794, 754, 197, 530, 662,
52, 712, 677, 56, 62, 981, 509, 267, 789, 885, 561, 316, 684, 596, 226,
13, 985, 779, 123, 720, 576, 753, 948, 406, 125, 315, 104, 519, 426, 502,
313, 566, 1016, 767, 796, 281, 749, 740, 136, 84, 908, 424, 936, 198,
355, 274, 735, 967, 5, 154, 428, 541, 785, 704, 486, 671, 600, 532, 381,
540, 574, 187, 88, 378, 216, 621, 499, 419, 922, 485, 494, 476, 255, 114,
188, 668, 297, 400, 918, 787, 158, 25, 458, 178, 564, 422, 768, 73, 1011,
717, 575, 404, 547, 196, 829, 237, 394, 301, 37, 65, 176, 106, 89, 85,
675, 979, 534, 803, 995, 363, 593, 120, 417, 452, 26, 699, 822, 223, 169,
416, 235, 609, 773, 211, 607, 208, 302, 852, 965, 603, 357, 761, 247,
817, 539, 250, 232, 272, 129, 568, 848, 624, 396, 710, 525, 183, 686, 10,
285, 856, 307, 811, 160, 972, 55, 441, 289, 723, 305, 373, 351, 153, 733,
409, 506, 975, 838, 573, 970, 988, 913, 471, 205, 337, 49, 594, 777, 549,
815, 277, 27, 916, 333, 353, 844, 800, 146, 751, 186, 375, 769, 358, 392,
883, 474, 788, 602, 74, 130, 329, 212, 155, 131, 102, 687, 293, 870, 742,
726, 427, 217, 834, 904, 29, 127, 869, 407, 338, 832, 470, 482, 810, 399,
439, 393, 604, 929, 682, 447, 714, 251, 455, 875, 319, 477, 464, 521,
258, 377, 937, 489, 792, 172, 314, 327, 124, 20, 531, 953, 591, 886, 320,
696, 71, 859, 578, 175, 587, 707, 663, 283, 179, 795, 989, 702, 940, 371,
692, 689, 555, 903, 410, 651, 75, 429, 818, 362, 894, 515, 31, 545, 666,
706, 952, 864, 269, 254, 349, 711, 802, 716, 784, 1007, 925, 801, 445,
148, 260, 658, 385, 287, 262, 204, 126, 586, 1004, 236, 165, 854, 411,
932, 560, 19, 215, 1002, 775, 653, 928, 901, 964, 884, 798, 839, 786,
433, 610, 116, 855, 180, 479, 910, 1014, 599, 915, 905, 306, 516, 731,
626, 978, 825, 344, 605, 654, 209
];

var GF1024_LOG = [
-1, 0, 99, 363, 198, 726, 462, 132, 297, 495, 825, 528, 561, 693, 231,
66, 396, 429, 594, 990, 924, 264, 627, 33, 660, 759, 792, 858, 330, 891,
165, 957, 104, 259, 518, 208, 280, 776, 416, 13, 426, 333, 618, 339, 641,
52, 388, 140, 666, 852, 529, 560, 678, 213, 26, 832, 681, 309, 70, 194,
97, 35, 682, 341, 203, 777, 358, 312, 617, 125, 307, 931, 379, 765, 875,
951, 515, 628, 112, 659, 525, 196, 432, 134, 717, 781, 438, 440, 740,
780, 151, 408, 487, 169, 239, 293, 467, 21, 672, 622, 557, 571, 881, 433,
704, 376, 779, 22, 643, 460, 398, 116, 172, 503, 751, 389, 1004, 18, 576,
415, 789, 6, 192, 696, 923, 702, 981, 892, 302, 816, 876, 880, 457, 537,
411, 539, 716, 624, 224, 295, 406, 531, 7, 233, 478, 586, 864, 268, 974,
338, 27, 392, 614, 839, 727, 879, 211, 250, 758, 507, 830, 129, 369, 384,
36, 985, 12, 555, 232, 796, 221, 321, 920, 263, 42, 934, 778, 479, 761,
939, 1006, 344, 381, 823, 44, 535, 866, 739, 752, 385, 119, 91, 566, 80,
120, 117, 771, 675, 721, 514, 656, 271, 670, 602, 980, 850, 532, 488,
803, 1022, 475, 801, 878, 57, 121, 991, 742, 888, 559, 105, 497, 291,
215, 795, 236, 167, 692, 520, 272, 661, 229, 391, 814, 340, 184, 798,
984, 773, 650, 473, 345, 558, 548, 326, 202, 145, 465, 810, 471, 158,
813, 908, 412, 441, 964, 750, 401, 50, 915, 437, 975, 126, 979, 491, 556,
577, 636, 685, 510, 963, 638, 367, 815, 310, 723, 349, 323, 857, 394,
606, 505, 713, 630, 938, 106, 826, 332, 978, 599, 834, 521, 530, 248,
883, 32, 153, 90, 754, 592, 304, 635, 775, 804, 1, 150, 836, 1013, 828,
324, 565, 508, 113, 154, 708, 921, 703, 689, 138, 547, 911, 929, 82, 228,
443, 468, 480, 483, 922, 135, 877, 61, 578, 111, 860, 654, 15, 331, 851,
895, 484, 320, 218, 420, 190, 1019, 143, 362, 634, 141, 965, 10, 838,
632, 861, 34, 722, 580, 808, 869, 554, 598, 65, 954, 787, 337, 187, 281,
146, 563, 183, 668, 944, 171, 837, 23, 867, 541, 916, 741, 625, 123, 736,
186, 357, 665, 977, 179, 156, 219, 220, 216, 67, 870, 902, 774, 98, 820,
574, 613, 900, 755, 596, 370, 390, 769, 314, 701, 894, 56, 841, 949, 987,
631, 658, 587, 204, 797, 790, 522, 745, 9, 502, 763, 86, 719, 288, 706,
887, 728, 952, 311, 336, 446, 1002, 348, 96, 58, 199, 11, 901, 230, 833,
188, 352, 351, 973, 3, 906, 335, 301, 266, 244, 791, 564, 619, 909, 371,
444, 760, 657, 328, 647, 490, 425, 913, 511, 439, 540, 283, 40, 897, 849,
60, 570, 872, 257, 749, 912, 572, 1007, 170, 407, 898, 492, 79, 747, 732,
206, 454, 918, 375, 482, 399, 92, 748, 325, 163, 274, 405, 744, 260, 346,
707, 626, 595, 118, 842, 136, 279, 684, 584, 101, 500, 422, 149, 956,
1014, 493, 536, 705, 51, 914, 225, 409, 55, 822, 590, 448, 655, 205, 676,
925, 735, 431, 784, 54, 609, 604, 39, 812, 737, 729, 466, 14, 533, 958,
481, 770, 499, 855, 238, 182, 464, 569, 72, 947, 442, 642, 24, 87, 989,
688, 88, 47, 762, 623, 709, 455, 817, 526, 637, 258, 84, 845, 738, 768,
698, 423, 933, 664, 620, 607, 629, 212, 347, 249, 982, 935, 131, 89, 252,
927, 189, 788, 853, 237, 691, 646, 403, 1010, 734, 253, 874, 807, 903,
1020, 100, 802, 71, 799, 1003, 633, 355, 276, 300, 649, 64, 306, 161,
608, 496, 743, 180, 485, 819, 383, 1016, 226, 308, 393, 648, 107, 19, 37,
585, 2, 175, 645, 247, 527, 5, 419, 181, 317, 327, 519, 542, 289, 567,
430, 579, 950, 582, 994, 1021, 583, 234, 240, 976, 41, 160, 109, 677,
937, 210, 95, 959, 242, 753, 461, 114, 733, 368, 573, 458, 782, 605, 680,
544, 299, 73, 652, 905, 477, 690, 93, 824, 882, 277, 946, 361, 17, 945,
523, 472, 334, 930, 597, 603, 793, 404, 290, 942, 316, 731, 270, 960,
936, 133, 122, 821, 966, 679, 662, 907, 282, 968, 767, 653, 20, 697, 222,
164, 835, 30, 285, 886, 456, 436, 640, 286, 1015, 380, 840, 245, 724,
137, 593, 173, 130, 715, 85, 885, 551, 246, 449, 103, 366, 372, 714, 313,
865, 241, 699, 674, 374, 68, 421, 562, 292, 59, 809, 342, 651, 459, 227,
46, 711, 764, 868, 53, 413, 278, 800, 255, 993, 318, 854, 319, 695, 315,
469, 166, 489, 969, 730, 1001, 757, 873, 686, 197, 303, 919, 155, 673,
940, 712, 25, 999, 63, 863, 972, 967, 785, 152, 296, 512, 402, 377, 45,
899, 829, 354, 77, 69, 856, 417, 811, 953, 124, 418, 75, 794, 162, 414,
1018, 568, 254, 265, 772, 588, 16, 896, 157, 889, 298, 621, 110, 844,
1000, 108, 545, 601, 78, 862, 447, 185, 195, 818, 450, 387, 49, 805, 102,
986, 1005, 827, 329, 28, 932, 410, 287, 435, 451, 962, 517, 48, 174, 43,
893, 884, 261, 251, 516, 395, 910, 611, 29, 501, 223, 476, 364, 144, 871,
998, 687, 928, 115, 453, 513, 176, 94, 168, 667, 955, 353, 434, 382, 400,
139, 365, 996, 343, 948, 890, 1012, 663, 610, 718, 538, 1008, 639, 470,
848, 543, 1011, 859, 671, 756, 83, 427, 159, 746, 669, 589, 971, 524,
356, 995, 904, 256, 201, 988, 62, 397, 81, 720, 917, 209, 549, 943, 486,
76, 148, 207, 509, 644, 386, 700, 534, 177, 550, 961, 926, 546, 428, 284,
127, 294, 8, 269, 359, 506, 445, 997, 806, 591, 725, 178, 262, 846, 373,
831, 504, 305, 843, 553, 378, 1017, 783, 474, 683, 581, 200, 498, 694,
191, 217, 847, 941, 424, 235, 38, 74, 616, 786, 147, 4, 273, 214, 142,
575, 992, 463, 983, 243, 360, 970, 350, 267, 615, 766, 494, 31, 1009,
452, 710, 552, 128, 612, 600, 275, 322, 193
];

module.exports = {
check: check,
};

function syndrome (residue) {
var low = residue & 0x1f;
return low ^ (low << 10) ^ (low << 20) ^
((residue >> 5) & 1 ? 0x31edd3c4 : 0) ^
((residue >> 6) & 1 ? 0x335f86a8 : 0) ^
((residue >> 7) & 1 ? 0x363b8870 : 0) ^
((residue >> 8) & 1 ? 0x3e6390c9 : 0) ^
((residue >> 9) & 1 ? 0x2ec72192 : 0) ^
((residue >> 10) & 1 ? 0x1046f79d : 0) ^
((residue >> 11) & 1 ? 0x208d4e33 : 0) ^
((residue >> 12) & 1 ? 0x130ebd6f : 0) ^
((residue >> 13) & 1 ? 0x2499fade : 0) ^
((residue >> 14) & 1 ? 0x1b27d4b5 : 0) ^
((residue >> 15) & 1 ? 0x04be1eb4 : 0) ^
((residue >> 16) & 1 ? 0x0968b861 : 0) ^
((residue >> 17) & 1 ? 0x1055f0c2 : 0) ^
((residue >> 18) & 1 ? 0x20ab4584 : 0) ^
((residue >> 19) & 1 ? 0x1342af08 : 0) ^
((residue >> 20) & 1 ? 0x24f1f318 : 0) ^
((residue >> 21) & 1 ? 0x1be34739 : 0) ^
((residue >> 22) & 1 ? 0x35562f7b : 0) ^
((residue >> 23) & 1 ? 0x3a3c5bff : 0) ^
((residue >> 24) & 1 ? 0x266c96f7 : 0) ^
((residue >> 25) & 1 ? 0x25c78b65 : 0) ^
((residue >> 26) & 1 ? 0x1b1f13ea : 0) ^
((residue >> 27) & 1 ? 0x34baa2f4 : 0) ^
((residue >> 28) & 1 ? 0x3b61c0e1 : 0) ^
((residue >> 29) & 1 ? 0x265325c2 : 0);
}

function locate_errors (residue, length) {
if (residue == 0) {
return [];
}
var syn = syndrome(residue);
var s0 = syn & 0x3FF;
var s1 = (syn >> 10) & 0x3FF;
var s2 = syn >> 20;
var l_s0 = GF1024_LOG[s0];
var l_s1 = GF1024_LOG[s1];
var l_s2 = GF1024_LOG[s2];
if (l_s0 != -1 && l_s1 != -1 && l_s2 != -1 && (2 * l_s1 - l_s2 - l_s0 + 2046) % 1023 == 0) {
var p1 = (l_s1 - l_s0 + 1023) % 1023;
if (p1 >= length) return [];
var l_e1 = l_s0 + (1023 - 997) * p1;
if (l_e1 % 33) return [];
return [p1];
}
for (var p1 = 0; p1 < length; p1++) {
var s2_s1p1 = s2 ^ (s1 == 0 ? 0 : GF1024_EXP[(l_s1 + p1) % 1023]);
if (s2_s1p1 == 0) continue;
var s1_s0p1 = s1 ^ (s0 == 0 ? 0 : GF1024_EXP[(l_s0 + p1) % 1023]);
if (s1_s0p1 == 0) continue;
var l_s1_s0p1 = GF1024_LOG[s1_s0p1];
var p2 = (GF1024_LOG[s2_s1p1] - l_s1_s0p1 + 1023) % 1023;
if (p2 >= length || p1 == p2) continue;
var s1_s0p2 = s1 ^ (s0 == 0 ? 0 : GF1024_EXP[(l_s0 + p2) % 1023]);
if (s1_s0p2 == 0) continue;
var inv_p1_p2 = 1023 - GF1024_LOG[GF1024_EXP[p1] ^ GF1024_EXP[p2]];
var l_e2 = l_s1_s0p1 + inv_p1_p2 + (1023 - 997) * p2;
if (l_e2 % 33) continue;
var l_e1 = GF1024_LOG[s1_s0p2] + inv_p1_p2 + (1023 - 997) * p1;
if (l_e1 % 33) continue;
if (p1 < p2) {
return [p1, p2];
} else {
return [p2, p1];
}
}
return [];
}

function polymod (values) {
var chk = 1;
for (var p = 0; p < values.length; ++p) {
var top = chk >> 25;
chk = (chk & 0x1ffffff) << 5 ^ values[p];
for (var i = 0; i < 5; ++i) {
if ((top >> i) & 1) {
chk ^= GENERATOR[i];
}
}
}
return chk;
}

function hrpExpand (hrp) {
var ret = [];
var p;
for (p = 0; p < hrp.length; ++p) {
ret.push(hrp.charCodeAt(p) >> 5);
}
ret.push(0);
for (p = 0; p < hrp.length; ++p) {
ret.push(hrp.charCodeAt(p) & 31);
}
return ret;
}

function range (from, to) {
var ret = [];
for (var i = from; i < to; ++i) {
ret.push(i);
}
return ret;
}

function check (bechString, validHrp) {
if (bechString.length > 90) {
return {error:"Too long", pos:range(90, bechString.length)};
}
var p;
var has_lower = false;
var has_upper = false;
for (p = 0; p < bechString.length; ++p) {
if (bechString.charCodeAt(p) < 33 || bechString.charCodeAt(p) > 126) {
return {error:"Invalid character", pos:[p]};
}
if (bechString.charAt(p) >= 'a' && bechString.charAt(p) <= 'z') {
has_lower = true;
if (has_upper) return {error:"Mixed case", pos:[p]};
}
if (bechString.charAt(p) >= 'A' && bechString.charAt(p) <= 'Z') {
has_upper = true;
if (has_lower) return {error:"Mixed case", pos:[p]};
}
}
bechString = bechString.toLowerCase();
var pos = bechString.lastIndexOf('1');
if (pos == -1) {
return {error:"Missing separator '1'", pos:null};
}
if (pos < 1 || pos + 7 > bechString.length) {
return {error:"Separator '1' at invalid position", pos:[pos]};
}
var hrp = bechString.substring(0, pos);
var data = [];
for (p = pos + 1; p < bechString.length; ++p) {
var d = CHARSET.indexOf(bechString.charAt(p));
if (d === -1) {
return {error:"Invalid character", pos:[p]};
}
data.push(d);
}
if (validHrp.indexOf(hrp) == -1) {
return {error:"Unknown part before the separator '1'", pos:range(0, hrp.length)};
}
var residue = polymod(hrpExpand(hrp).concat(data)) ^ 1;
if (residue != 0) {
var epos = locate_errors(residue, bechString.length - 1);
if (epos.length == 0) {
return {error:"Invalid", pos:null};
}
for (var ep = 0; ep < epos.length; ++ep) {
epos[ep] = bechString.length - epos[ep] - (epos[ep] >= data.length ? 2 : 1);
}
return {error:"Invalid", pos:epos};
}
return {error:null, hrp:hrp, data:data.slice(0, -6)};
}
82 changes: 82 additions & 0 deletions ecc/javascript/segwit_addr_ecc.js
@@ -0,0 +1,82 @@
// Copyright (c) 2017 Pieter Wuille
//
// 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.

var bech32_ecc = require('./bech32_ecc');

module.exports = {
check: check
};

function convertbits (data, frombits, tobits, pad) {
var acc = 0;
var bits = 0;
var ret = [];
var maxv = (1 << tobits) - 1;
for (var p = 0; p < data.length; ++p) {
var value = data[p];
if (value < 0 || (value >> frombits) !== 0) {
return null;
}
acc = (acc << frombits) | value;
bits += frombits;
while (bits >= tobits) {
bits -= tobits;
ret.push((acc >> bits) & maxv);
}
}
if (pad) {
if (bits > 0) {
ret.push((acc << (tobits - bits)) & maxv);
}
} else if (bits >= frombits || ((acc << (tobits - bits)) & maxv)) {
return null;
}
return ret;
}

function check (addr, validHrp) {
if (addr.length < 14) {
return {error:"Too short", pos:null};
}
if (addr.length > 74) {
return {error:"Too long", pos:null};
}
if ((addr.length % 8) == 0 || (addr.length % 8) == 3 || (addr.length % 8) == 5) {
return {error:"Invalid length", pos:null};
}
var dec = bech32_ecc.check(addr, validHrp);
if (dec.error !== null) {
return {error:dec.error, pos:dec.pos};
}
var res = convertbits(dec.data.slice(1), 5, 8, false);
if (res === null) {
return {error:"Padding error", pos:[addr.length - 6]};
}
if (res.length < 2 || res.length > 40) {
return {error:"Invalid witness program length", pos:null};
}
if (dec.data[0] > 16) {
return {error:"Invalid witness version", pos:[dec.hrp.length + 1]};
}
if (dec.data[0] === 0 && res.length !== 20 && res.length !== 32) {
return {error:"Invalid witness program length for v0", pos:null};
}
return {error:null, version:dec.data[0], program:res};
}
186 changes: 186 additions & 0 deletions ref/c/segwit_addr.c
@@ -0,0 +1,186 @@
/* Copyright (c) 2017 Pieter Wuille
*
* 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 <stdlib.h>
#include <stdint.h>
#include <string.h>

#include "segwit_addr.h"

uint32_t bech32_polymod_step(uint32_t pre) {
uint8_t b = pre >> 25;
return ((pre & 0x1FFFFFF) << 5) ^
(-((b >> 0) & 1) & 0x3b6a57b2UL) ^
(-((b >> 1) & 1) & 0x26508e6dUL) ^
(-((b >> 2) & 1) & 0x1ea119faUL) ^
(-((b >> 3) & 1) & 0x3d4233ddUL) ^
(-((b >> 4) & 1) & 0x2a1462b3UL);
}

static const char* charset = "qpzry9x8gf2tvdw0s3jn54khce6mua7l";

static const int8_t charset_rev[128] = {
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
15, -1, 10, 17, 21, 20, 26, 30, 7, 5, -1, -1, -1, -1, -1, -1,
-1, 29, -1, 24, 13, 25, 9, 8, 23, -1, 18, 22, 31, 27, 19, -1,
1, 0, 3, 16, 11, 28, 12, 14, 6, 4, 2, -1, -1, -1, -1, -1,
-1, 29, -1, 24, 13, 25, 9, 8, 23, -1, 18, 22, 31, 27, 19, -1,
1, 0, 3, 16, 11, 28, 12, 14, 6, 4, 2, -1, -1, -1, -1, -1
};

int bech32_encode(char *output, const char *hrp, const uint8_t *data, size_t data_len) {
uint32_t chk = 1;
size_t i = 0;
while (hrp[i] != 0) {
if (!(hrp[i] >> 5)) return 0;
chk = bech32_polymod_step(chk) ^ (hrp[i] >> 5);
++i;
}
if (i + 7 + data_len > 90) return 0;
chk = bech32_polymod_step(chk);
while (*hrp != 0) {
chk = bech32_polymod_step(chk) ^ (*hrp & 0x1f);
*(output++) = *(hrp++);
}
*(output++) = '1';
for (i = 0; i < data_len; ++i) {
if (*data >> 5) return 0;
chk = bech32_polymod_step(chk) ^ (*data);
*(output++) = charset[*(data++)];
}
for (i = 0; i < 6; ++i) {
chk = bech32_polymod_step(chk);
}
chk ^= 1;
for (i = 0; i < 6; ++i) {
*(output++) = charset[(chk >> ((5 - i) * 5)) & 0x1f];
}
*output = 0;
return 1;
}

int bech32_decode(char* hrp, uint8_t *data, size_t *data_len, const char *input) {
uint32_t chk = 1;
size_t i;
size_t input_len = strlen(input);
size_t hrp_len;
int have_lower = 0, have_upper = 0;
if (input_len < 8 || input_len > 90) {
return 0;
}
*data_len = 0;
while (*data_len < input_len && input[(input_len - 1) - *data_len] != '1') {
++(*data_len);
}
hrp_len = input_len - (1 + *data_len);
if (hrp_len < 1 || *data_len < 6) {
return 0;
}
*(data_len) -= 6;
for (i = 0; i < hrp_len; ++i) {
int ch = input[i];
if (ch < 33 || ch > 126) {
return 0;
}
if (ch >= 'a' && ch <= 'z') {
have_lower = 1;
} else if (ch >= 'A' && ch <= 'Z') {
have_upper = 1;
ch = (ch - 'A') + 'a';
}
hrp[i] = ch;
chk = bech32_polymod_step(chk) ^ (ch >> 5);
}
hrp[i] = 0;
chk = bech32_polymod_step(chk);
for (i = 0; i < hrp_len; ++i) {
chk = bech32_polymod_step(chk) ^ (input[i] & 0x1f);
}
++i;
while (i < input_len) {
int v = (input[i] & 0x80) ? -1 : charset_rev[(int)input[i]];
if (input[i] >= 'a' && input[i] <= 'z') have_lower = 1;
if (input[i] >= 'A' && input[i] <= 'Z') have_upper = 1;
if (v == -1) {
return 0;
}
chk = bech32_polymod_step(chk) ^ v;
if (i + 6 < input_len) {
data[i - (1 + hrp_len)] = v;
}
++i;
}
if (have_lower && have_upper) {
return 0;
}
return chk == 1;
}

static int convert_bits(uint8_t* out, size_t* outlen, int outbits, const uint8_t* in, size_t inlen, int inbits, int pad) {
uint32_t val = 0;
int bits = 0;
uint32_t maxv = (((uint32_t)1) << outbits) - 1;
while (inlen--) {
val = (val << inbits) | *(in++);
bits += inbits;
while (bits >= outbits) {
bits -= outbits;
out[(*outlen)++] = (val >> bits) & maxv;
}
}
if (pad) {
if (bits) {
out[(*outlen)++] = (val << (outbits - bits)) & maxv;
}
} else if (((val << (outbits - bits)) & maxv) || bits >= inbits) {
return 0;
}
return 1;
}

int segwit_addr_encode(char *output, const char *hrp, int witver, const uint8_t *witprog, size_t witprog_len) {
uint8_t data[65];
size_t datalen = 0;
if (witver > 16) return 0;
if (witver == 0 && witprog_len != 20 && witprog_len != 32) return 0;
if (witprog_len < 2 || witprog_len > 40) return 0;
data[0] = witver;
convert_bits(data + 1, &datalen, 5, witprog, witprog_len, 8, 1);
++datalen;
return bech32_encode(output, hrp, data, datalen);
}

int segwit_addr_decode(int* witver, uint8_t* witdata, size_t* witdata_len, const char* hrp, const char* addr) {
uint8_t data[84];
char hrp_actual[84];
size_t data_len;
if (!bech32_decode(hrp_actual, data, &data_len, addr)) return 0;
if (data_len == 0 || data_len > 65) return 0;
if (strncmp(hrp, hrp_actual, 84) != 0) return 0;
if (data[0] > 16) return 0;
*witdata_len = 0;
if (!convert_bits(witdata, witdata_len, 8, data + 1, data_len - 1, 5, 0)) return 0;
if (*witdata_len < 2 || *witdata_len > 40) return 0;
if (data[0] == 0 && *witdata_len != 20 && *witdata_len != 32) return 0;
*witver = data[0];
return 1;
}
101 changes: 101 additions & 0 deletions ref/c/segwit_addr.h
@@ -0,0 +1,101 @@
/* Copyright (c) 2017 Pieter Wuille
*
* 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 _SEGWIT_ADDR_H_
#define _SEGWIT_ADDR_H_ 1

#include <stdint.h>

/** Encode a SegWit address
*
* Out: output: Pointer to a buffer of size 73 + strlen(hrp) that will be
* updated to contain the null-terminated address.
* In: hrp: Pointer to the null-terminated human readable part to use
* (chain/network specific).
* ver: Version of the witness program (between 0 and 16 inclusive).
* prog: Data bytes for the witness program (between 2 and 40 bytes).
* prog_len: Number of data bytes in prog.
* Returns 1 if successful.
*/
int segwit_addr_encode(
char *output,
const char *hrp,
int ver,
const uint8_t *prog,
size_t prog_len
);

/** Decode a SegWit address
*
* Out: ver: Pointer to an int that will be updated to contain the witness
* program version (between 0 and 16 inclusive).
* prog: Pointer to a buffer of size 40 that will be updated to
* contain the witness program bytes.
* prog_len: Pointer to a size_t that will be updated to contain the length
* of bytes in prog.
* hrp: Pointer to the null-terminated human readable part that is
* expected (chain/network specific).
* addr: Pointer to the null-terminated address.
* Returns 1 if successful.
*/
int segwit_addr_decode(
int* ver,
uint8_t* prog,
size_t* prog_len,
const char* hrp,
const char* addr
);

/** Encode a Bech32 string
*
* Out: output: Pointer to a buffer of size strlen(hrp) + data_len + 8 that
* will be updated to contain the null-terminated Bech32 string.
* In: hrp : Pointer to the null-terminated human readable part.
* data : Pointer to an array of 5-bit values.
* data_len: Length of the data array.
* Returns 1 if successful.
*/
int bech32_encode(
char *output,
const char *hrp,
const uint8_t *data,
size_t data_len
);

/** Decode a Bech32 string
*
* Out: hrp: Pointer to a buffer of size strlen(input) - 6. Will be
* updated to contain the null-terminated human readable part.
* data: Pointer to a buffer of size strlen(input) - 8 that will
* hold the encoded 5-bit data values.
* data_len: Pointer to a size_t that will be updated to be the number
* of entries in data.
* In: input: Pointer to a null-terminated Bech32 string.
* Returns 1 if succesful.
*/
int bech32_decode(
char *hrp,
uint8_t *data,
size_t *data_len,
const char *input
);

#endif
180 changes: 180 additions & 0 deletions ref/c/tests.c
@@ -0,0 +1,180 @@
#include <stdio.h>
#include <ctype.h>
#include <string.h>

#include "segwit_addr.h"

static const char* valid_checksum[] = {
"A12UEL5L",
"an83characterlonghumanreadablepartthatcontainsthenumber1andtheexcludedcharactersbio1tt5tgs",
"abcdef1qpzry9x8gf2tvdw0s3jn54khce6mua7lmqqqxw",
"11qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqc8247j",
"split1checkupstagehandshakeupstreamerranterredcaperred2y9e3w",
};

struct valid_address_data {
const char* address;
size_t scriptPubKeyLen;
const uint8_t scriptPubKey[42];
};

static struct valid_address_data valid_address[] = {
{
"BC1QW508D6QEJXTDG4Y5R3ZARVARY0C5XW7KV8F3T4",
22, {
0x00, 0x14, 0x75, 0x1e, 0x76, 0xe8, 0x19, 0x91, 0x96, 0xd4, 0x54,
0x94, 0x1c, 0x45, 0xd1, 0xb3, 0xa3, 0x23, 0xf1, 0x43, 0x3b, 0xd6
}
},
{
"tb1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3q0sl5k7",
34, {
0x00, 0x20, 0x18, 0x63, 0x14, 0x3c, 0x14, 0xc5, 0x16, 0x68, 0x04,
0xbd, 0x19, 0x20, 0x33, 0x56, 0xda, 0x13, 0x6c, 0x98, 0x56, 0x78,
0xcd, 0x4d, 0x27, 0xa1, 0xb8, 0xc6, 0x32, 0x96, 0x04, 0x90, 0x32,
0x62
}
},
{
"bc1pw508d6qejxtdg4y5r3zarvary0c5xw7kw508d6qejxtdg4y5r3zarvary0c5xw7k7grplx",
42, {
0x81, 0x28, 0x75, 0x1e, 0x76, 0xe8, 0x19, 0x91, 0x96, 0xd4, 0x54,
0x94, 0x1c, 0x45, 0xd1, 0xb3, 0xa3, 0x23, 0xf1, 0x43, 0x3b, 0xd6,
0x75, 0x1e, 0x76, 0xe8, 0x19, 0x91, 0x96, 0xd4, 0x54, 0x94, 0x1c,
0x45, 0xd1, 0xb3, 0xa3, 0x23, 0xf1, 0x43, 0x3b, 0xd6
}
},
{
"BC1SW50QA3JX3S",
4, {
0x90, 0x02, 0x75, 0x1e
}
},
{
"bc1zw508d6qejxtdg4y5r3zarvaryvg6kdaj",
18, {
0x82, 0x10, 0x75, 0x1e, 0x76, 0xe8, 0x19, 0x91, 0x96, 0xd4, 0x54,
0x94, 0x1c, 0x45, 0xd1, 0xb3, 0xa3, 0x23
}
},
{
"tb1qqqqqp399et2xygdj5xreqhjjvcmzhxw4aywxecjdzew6hylgvsesrxh6hy",
34, {
0x00, 0x20, 0x00, 0x00, 0x00, 0xc4, 0xa5, 0xca, 0xd4, 0x62, 0x21,
0xb2, 0xa1, 0x87, 0x90, 0x5e, 0x52, 0x66, 0x36, 0x2b, 0x99, 0xd5,
0xe9, 0x1c, 0x6c, 0xe2, 0x4d, 0x16, 0x5d, 0xab, 0x93, 0xe8, 0x64,
0x33
}
}
};

static const char* invalid_address[] = {
"tc1qw508d6qejxtdg4y5r3zarvary0c5xw7kg3g4ty",
"bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t5",
"BC13W508D6QEJXTDG4Y5R3ZARVARY0C5XW7KN40WF2",
"bc1rw5uspcuh",
"bc10w508d6qejxtdg4y5r3zarvary0c5xw7kw508d6qejxtdg4y5r3zarvary0c5xw7kw5rljs90",
"BC1QR508D6QEJXTDG4Y5R3ZARVARYV98GJ9P",
"tb1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3q0sL5k7",
"tb1pw508d6qejxtdg4y5r3zarqfsj6c3",
"tb1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3pjxtptv",
};

static void segwit_scriptpubkey(uint8_t* scriptpubkey, size_t* scriptpubkeylen, int witver, const uint8_t* witprog, size_t witprog_len) {
scriptpubkey[0] = witver ? (0x80 | witver) : 0;
scriptpubkey[1] = witprog_len;
memcpy(scriptpubkey + 2, witprog, witprog_len);
*scriptpubkeylen = witprog_len + 2;
}

int my_strncasecmp(const char *s1, const char *s2, size_t n) {
size_t i = 0;
while (i < n) {
char c1 = s1[i];
char c2 = s2[i];
if (c1 >= 'A' && c1 <= 'Z') c1 = (c1 - 'A') + 'a';
if (c2 >= 'A' && c2 <= 'Z') c2 = (c2 - 'A') + 'a';
if (c1 < c2) return -1;
if (c1 > c2) return 1;
if (c1 == 0) return 0;
++i;
}
return 0;
}

int main(void) {
size_t i;
int fail = 0;
for (i = 0; i < sizeof(valid_checksum) / sizeof(valid_checksum[0]); ++i) {
uint8_t data[82];
char rebuild[92];
char hrp[84];
size_t data_len;
int ok = 1;
if (!bech32_decode(hrp, data, &data_len, valid_checksum[i])) {
printf("bech32_decode fails: '%s'\n", valid_checksum[i]);
ok = 0;
}
if (ok) {
if (!bech32_encode(rebuild, hrp, data, data_len)) {
printf("bech32_encode fails: '%s'\n", valid_checksum[i]);
ok = 0;
}
}
if (ok && my_strncasecmp(rebuild, valid_checksum[i], 92)) {
printf("bech32_encode produces incorrect result: '%s'\n", valid_checksum[i]);
ok = 0;
}
fail += !ok;
}
for (i = 0; i < sizeof(valid_address) / sizeof(valid_address[0]); ++i) {
uint8_t witprog[40];
size_t witprog_len;
int witver;
const char* hrp = "bc";
int ok = 1;
uint8_t scriptpubkey[42];
size_t scriptpubkey_len;
char rebuild[93];
int ret = segwit_addr_decode(&witver, witprog, &witprog_len, hrp, valid_address[i].address);
if (!ret) {
hrp = "tb";
ret = segwit_addr_decode(&witver, witprog, &witprog_len, hrp, valid_address[i].address);
}
if (!ret) {
printf("segwit_addr_decode fails: '%s'\n", valid_address[i].address);
ok = 0;
}
if (ok) segwit_scriptpubkey(scriptpubkey, &scriptpubkey_len, witver, witprog, witprog_len);
if (ok && (scriptpubkey_len != valid_address[i].scriptPubKeyLen || memcmp(scriptpubkey, valid_address[i].scriptPubKey, scriptpubkey_len))) {
printf("segwit_addr_decode produces wrong result: '%s'\n", valid_address[i].address);
ok = 0;
}
if (ok && !segwit_addr_encode(rebuild, hrp, witver, witprog, witprog_len)) {
printf("segwit_addr_encode fails: '%s'\n", valid_address[i].address);
ok = 0;
}
if (ok && my_strncasecmp(valid_address[i].address, rebuild, 93)) {
printf("segwit_addr_encode produces wrong result: '%s'\n", valid_address[i].address);
ok = 0;
}
fail += !ok;
}
for (i = 0; i < sizeof(invalid_address) / sizeof(invalid_address[0]); ++i) {
uint8_t witprog[40];
size_t witprog_len;
int witver;
int ok = 1;
if (segwit_addr_decode(&witver, witprog, &witprog_len, "bc", invalid_address[i])) {
printf("segwit_addr_decode succeeds on invalid address '%s'\n", invalid_address[i]);
ok = 0;
}
if (segwit_addr_decode(&witver, witprog, &witprog_len, "tb", invalid_address[i])) {
printf("segwit_addr_decode succeeds on invalid address '%s'\n", invalid_address[i]);
ok = 0;
}
fail += !ok;
}
printf("%i failures\n", fail);
return fail != 0;
}
116 changes: 116 additions & 0 deletions ref/javascript/bech32.js
@@ -0,0 +1,116 @@
// Copyright (c) 2017 Pieter Wuille
//
// 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.

var CHARSET = 'qpzry9x8gf2tvdw0s3jn54khce6mua7l';
var GENERATOR = [0x3b6a57b2, 0x26508e6d, 0x1ea119fa, 0x3d4233dd, 0x2a1462b3];

module.exports = {
decode: decode,
encode: encode,
};


function polymod (values) {
var chk = 1;
for (var p = 0; p < values.length; ++p) {
var top = chk >> 25;
chk = (chk & 0x1ffffff) << 5 ^ values[p];
for (var i = 0; i < 5; ++i) {
if ((top >> i) & 1) {
chk ^= GENERATOR[i];
}
}
}
return chk;
}

function hrpExpand (hrp) {
var ret = [];
var p;
for (p = 0; p < hrp.length; ++p) {
ret.push(hrp.charCodeAt(p) >> 5);
}
ret.push(0);
for (p = 0; p < hrp.length; ++p) {
ret.push(hrp.charCodeAt(p) & 31);
}
return ret;
}

function verifyChecksum (hrp, data) {
return polymod(hrpExpand(hrp).concat(data)) === 1;
}

function createChecksum (hrp, data) {
var values = hrpExpand(hrp).concat(data).concat([0, 0, 0, 0, 0, 0]);
var mod = polymod(values) ^ 1;
var ret = [];
for (var p = 0; p < 6; ++p) {
ret.push((mod >> 5 * (5 - p)) & 31);
}
return ret;
}

function encode (hrp, data) {
var combined = data.concat(createChecksum(hrp, data));
var ret = hrp + '1';
for (var p = 0; p < combined.length; ++p) {
ret += CHARSET.charAt(combined[p]);
}
return ret;
}

function decode (bechString) {
var p;
var has_lower = false;
var has_upper = false;
for (p = 0; p < bechString.length; ++p) {
if (bechString.charCodeAt(p) < 33 || bechString.charCodeAt(p) > 126) {
return null;
}
if (bechString.charCodeAt(p) >= 97 && bechString.charCodeAt(p) <= 122) {
has_lower = true;
}
if (bechString.charCodeAt(p) >= 65 && bechString.charCodeAt(p) <= 90) {
has_upper = true;
}
}
if (has_lower && has_upper) {
return null;
}
bechString = bechString.toLowerCase();
var pos = bechString.lastIndexOf('1');
if (pos < 1 || pos + 7 > bechString.length || bechString.length > 90) {
return null;
}
var hrp = bechString.substring(0, pos);
var data = [];
for (p = pos + 1; p < bechString.length; ++p) {
var d = CHARSET.indexOf(bechString.charAt(p));
if (d === -1) {
return null;
}
data.push(d);
}
if (!verifyChecksum(hrp, data)) {
return null;
}
return {hrp: hrp, data: data.slice(0, data.length - 6)};
}
76 changes: 76 additions & 0 deletions ref/javascript/segwit_addr.js
@@ -0,0 +1,76 @@
// Copyright (c) 2017 Pieter Wuille
//
// 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.

var bech32 = require('./bech32');

module.exports = {
encode: encode,
decode: decode
};

function convertbits (data, frombits, tobits, pad) {
var acc = 0;
var bits = 0;
var ret = [];
var maxv = (1 << tobits) - 1;
for (var p = 0; p < data.length; ++p) {
var value = data[p];
if (value < 0 || (value >> frombits) !== 0) {
return null;
}
acc = (acc << frombits) | value;
bits += frombits;
while (bits >= tobits) {
bits -= tobits;
ret.push((acc >> bits) & maxv);
}
}
if (pad) {
if (bits > 0) {
ret.push((acc << (tobits - bits)) & maxv);
}
} else if (bits >= frombits || ((acc << (tobits - bits)) & maxv)) {
return null;
}
return ret;
}

function decode (hrp, addr) {
var dec = bech32.decode(addr);
if (dec === null || dec.hrp !== hrp || dec.data.length < 1 || dec.data[0] > 16) {
return null;
}
var res = convertbits(dec.data.slice(1), 5, 8, false);
if (res === null || res.length < 2 || res.length > 40) {
return null;
}
if (dec.data[0] === 0 && res.length !== 20 && res.length !== 32) {
return null;
}
return {version: dec.data[0], program: res};
}

function encode (hrp, version, program) {
var ret = bech32.encode(hrp, [version].concat(convertbits(program, 8, 5, true)));
if (decode(hrp, ret) === null) {
return null;
}
return ret;
}
143 changes: 143 additions & 0 deletions ref/javascript/tests.js
@@ -0,0 +1,143 @@
// Copyright (c) 2017 Pieter Wuille
//
// 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.

var segwit_addr = require('./segwit_addr.js');
var bech32 = require('./bech32');

function segwit_scriptpubkey(version, program) {
return [version ? version + 0x80 : 0, program.length].concat(program);
}

var VALID_CHECKSUM = [
"A12UEL5L",
"an83characterlonghumanreadablepartthatcontainsthenumber1andtheexcludedcharactersbio1tt5tgs",
"abcdef1qpzry9x8gf2tvdw0s3jn54khce6mua7lmqqqxw",
"11qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqc8247j",
"split1checkupstagehandshakeupstreamerranterredcaperred2y9e3w"
];

var VALID_ADDRESS = [
[
"BC1QW508D6QEJXTDG4Y5R3ZARVARY0C5XW7KV8F3T4",
[
0x00, 0x14, 0x75, 0x1e, 0x76, 0xe8, 0x19, 0x91, 0x96, 0xd4, 0x54,
0x94, 0x1c, 0x45, 0xd1, 0xb3, 0xa3, 0x23, 0xf1, 0x43, 0x3b, 0xd6
]
],
[
"tb1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3q0sl5k7",
[
0x00, 0x20, 0x18, 0x63, 0x14, 0x3c, 0x14, 0xc5, 0x16, 0x68, 0x04,
0xbd, 0x19, 0x20, 0x33, 0x56, 0xda, 0x13, 0x6c, 0x98, 0x56, 0x78,
0xcd, 0x4d, 0x27, 0xa1, 0xb8, 0xc6, 0x32, 0x96, 0x04, 0x90, 0x32,
0x62
]
],
[
"bc1pw508d6qejxtdg4y5r3zarvary0c5xw7kw508d6qejxtdg4y5r3zarvary0c5xw7k7grplx",
[
0x81, 0x28, 0x75, 0x1e, 0x76, 0xe8, 0x19, 0x91, 0x96, 0xd4, 0x54,
0x94, 0x1c, 0x45, 0xd1, 0xb3, 0xa3, 0x23, 0xf1, 0x43, 0x3b, 0xd6,
0x75, 0x1e, 0x76, 0xe8, 0x19, 0x91, 0x96, 0xd4, 0x54, 0x94, 0x1c,
0x45, 0xd1, 0xb3, 0xa3, 0x23, 0xf1, 0x43, 0x3b, 0xd6
]
],
[
"BC1SW50QA3JX3S",
[
0x90, 0x02, 0x75, 0x1e
]
],
[
"bc1zw508d6qejxtdg4y5r3zarvaryvg6kdaj",
[
0x82, 0x10, 0x75, 0x1e, 0x76, 0xe8, 0x19, 0x91, 0x96, 0xd4, 0x54,
0x94, 0x1c, 0x45, 0xd1, 0xb3, 0xa3, 0x23
]
],
[
"tb1qqqqqp399et2xygdj5xreqhjjvcmzhxw4aywxecjdzew6hylgvsesrxh6hy",
[
0x00, 0x20, 0x00, 0x00, 0x00, 0xc4, 0xa5, 0xca, 0xd4, 0x62, 0x21,
0xb2, 0xa1, 0x87, 0x90, 0x5e, 0x52, 0x66, 0x36, 0x2b, 0x99, 0xd5,
0xe9, 0x1c, 0x6c, 0xe2, 0x4d, 0x16, 0x5d, 0xab, 0x93, 0xe8, 0x64,
0x33
]
]
];

var INVALID_ADDRESS = [
"tc1qw508d6qejxtdg4y5r3zarvary0c5xw7kg3g4ty",
"bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t5",
"BC13W508D6QEJXTDG4Y5R3ZARVARY0C5XW7KN40WF2",
"bc1rw5uspcuh",
"bc10w508d6qejxtdg4y5r3zarvary0c5xw7kw508d6qejxtdg4y5r3zarvary0c5xw7kw5rljs90",
"BC1QR508D6QEJXTDG4Y5R3ZARVARYV98GJ9P",
"tb1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3q0sL5k7",
"tb1pw508d6qejxtdg4y5r3zarqfsj6c3",
"tb1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3pjxtptv",
];

var didPassTests = true;

for (var p = 0; p < VALID_CHECKSUM.length; ++p) {
var test = VALID_CHECKSUM[p];
var ret = bech32.decode(test);
didPassTests = didPassTests && !!ret;
console.log("Valid checksum for " + test + ": " + (ret === null ? "fail" : "ok"));
}

for (var p = 0; p < VALID_ADDRESS.length; ++p) {
var test = VALID_ADDRESS[p];
var address = test[0];
var scriptpubkey = test[1];
var hrp = "bc";
var ret = segwit_addr.decode(hrp, address);
if (ret === null) {
hrp = "tb";
ret = segwit_addr.decode(hrp, address);
}
var ok = ret !== null;
var output;
if (ok) {
output = segwit_scriptpubkey(ret.version, ret.program);
ok = ("" + output == "" +scriptpubkey);
}
if (ok) {
var recreate = segwit_addr.encode(hrp, ret.version, ret.program);
ok = (recreate === address.toLowerCase());
}
didPassTests = didPassTests && !!ok;
console.log("Valid address " + address + ": " + (ok ? "ok" : "FAIL"));
}

for (var p = 0; p < INVALID_ADDRESS.length; ++p) {
var test = INVALID_ADDRESS[p];
var ok = segwit_addr.decode("bc", test) === null && segwit_addr.decode("tb", test) === null;
didPassTests = didPassTests && !!ok;
console.log("Invalid address " + test + ": " + (ok ? "ok" : "FAIL"));
}

if (!didPassTests) {
console.error();
console.error('Failed tests');
console.error();
process.exit(1);
}
121 changes: 121 additions & 0 deletions ref/python/segwit_addr.py
@@ -0,0 +1,121 @@
# Copyright (c) 2017 Pieter Wuille
#
# 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.

"""Reference implementation for Bech32 and segwit addresses."""


CHARSET = "qpzry9x8gf2tvdw0s3jn54khce6mua7l"


def bech32_polymod(values):
"""Internal function that computes the Bech32 checksum."""
generator = [0x3b6a57b2, 0x26508e6d, 0x1ea119fa, 0x3d4233dd, 0x2a1462b3]
chk = 1
for value in values:
top = chk >> 25
chk = (chk & 0x1ffffff) << 5 ^ value
for i in range(5):
chk ^= generator[i] if ((top >> i) & 1) else 0
return chk


def bech32_hrp_expand(hrp):
"""Expand the HRP into values for checksum computation."""
return [ord(x) >> 5 for x in hrp] + [0] + [ord(x) & 31 for x in hrp]


def bech32_verify_checksum(hrp, data):
"""Verify a checksum given HRP and converted data characters."""
return bech32_polymod(bech32_hrp_expand(hrp) + data) == 1


def bech32_create_checksum(hrp, data):
"""Compute the checksum values given HRP and data."""
values = bech32_hrp_expand(hrp) + data
polymod = bech32_polymod(values + [0, 0, 0, 0, 0, 0]) ^ 1
return [(polymod >> 5 * (5 - i)) & 31 for i in range(6)]


def bech32_encode(hrp, data):
"""Compute a Bech32 string given HRP and data values."""
combined = data + bech32_create_checksum(hrp, data)
return hrp + '1' + ''.join([CHARSET[d] for d in combined])


def bech32_decode(bech):
"""Validate a Bech32 string, and determine HRP and data."""
if ((any(ord(x) < 33 or ord(x) > 126 for x in bech)) or
(bech.lower() != bech and bech.upper() != bech)):
return (None, None)
bech = bech.lower()
pos = bech.rfind('1')
if pos < 1 or pos + 7 > len(bech) or len(bech) > 90:
return (None, None)
if not all(x in CHARSET for x in bech[pos+1:]):
return (None, None)
hrp = bech[:pos]
data = [CHARSET.find(x) for x in bech[pos+1:]]
if not bech32_verify_checksum(hrp, data):
return (None, None)
return (hrp, data[:-6])


def convertbits(data, frombits, tobits, pad=True):
"""General power-of-2 base conversion."""
acc = 0
bits = 0
ret = []
maxv = (1 << tobits) - 1
for value in data:
if value < 0 or (value >> frombits):
return None
acc = (acc << frombits) | value
bits += frombits
while bits >= tobits:
bits -= tobits
ret.append((acc >> bits) & maxv)
if pad:
if bits:
ret.append((acc << (tobits - bits)) & maxv)
elif bits >= frombits or ((acc << (tobits - bits)) & maxv):
return None
return ret


def decode(hrp, addr):
"""Decode a segwit address."""
hrpgot, data = bech32_decode(addr)
if hrpgot != hrp:
return (None, None)
decoded = convertbits(data[1:], 5, 8, False)
if decoded is None or len(decoded) < 2 or len(decoded) > 40:
return (None, None)
if data[0] > 16:
return (None, None)
if data[0] == 0 and len(decoded) != 20 and len(decoded) != 32:
return (None, None)
return (data[0], decoded)


def encode(hrp, witver, witprog):
"""Encode a segwit address."""
ret = bech32_encode(hrp, [witver] + convertbits(witprog, 8, 5))
assert decode(hrp, ret) is not (None, None)
return ret
102 changes: 102 additions & 0 deletions ref/python/tests.py
@@ -0,0 +1,102 @@
#!/usr/bin/python3

# Copyright (c) 2017 Pieter Wuille
#
# 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.


"""Reference tests for segwit adresses"""

import binascii
import unittest
import segwit_addr

def segwit_scriptpubkey(witver, witprog):
"""Construct a Segwit scriptPubKey for a given witness program."""
return bytes([witver + 0x80 if witver else 0, len(witprog)] + witprog)

VALID_CHECKSUM = [
"A12UEL5L",
"an83characterlonghumanreadablepartthatcontainsthenumber1andtheexcludedcharactersbio1tt5tgs",
"abcdef1qpzry9x8gf2tvdw0s3jn54khce6mua7lmqqqxw",
"11qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqc8247j",
"split1checkupstagehandshakeupstreamerranterredcaperred2y9e3w",
]

VALID_ADDRESS = [
["BC1QW508D6QEJXTDG4Y5R3ZARVARY0C5XW7KV8F3T4", "0014751e76e8199196d454941c45d1b3a323f1433bd6"],
["tb1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3q0sl5k7",
"00201863143c14c5166804bd19203356da136c985678cd4d27a1b8c6329604903262"],
["bc1pw508d6qejxtdg4y5r3zarvary0c5xw7kw508d6qejxtdg4y5r3zarvary0c5xw7k7grplx",
"8128751e76e8199196d454941c45d1b3a323f1433bd6751e76e8199196d454941c45d1b3a323f1433bd6"],
["BC1SW50QA3JX3S", "9002751e"],
["bc1zw508d6qejxtdg4y5r3zarvaryvg6kdaj", "8210751e76e8199196d454941c45d1b3a323"],
["tb1qqqqqp399et2xygdj5xreqhjjvcmzhxw4aywxecjdzew6hylgvsesrxh6hy",
"0020000000c4a5cad46221b2a187905e5266362b99d5e91c6ce24d165dab93e86433"],
]

INVALID_ADDRESS = [
"tc1qw508d6qejxtdg4y5r3zarvary0c5xw7kg3g4ty",
"bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t5",
"BC13W508D6QEJXTDG4Y5R3ZARVARY0C5XW7KN40WF2",
"bc1rw5uspcuh",
"bc10w508d6qejxtdg4y5r3zarvary0c5xw7kw508d6qejxtdg4y5r3zarvary0c5xw7kw5rljs90",
"BC1QR508D6QEJXTDG4Y5R3ZARVARYV98GJ9P",
"tb1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3q0sL5k7",
"tb1pw508d6qejxtdg4y5r3zarqfsj6c3",
"tb1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3pjxtptv",
]

class TestSegwitAddress(unittest.TestCase):
"""Unit test class for segwit addressess."""

def test_checksum(self):
"""Test checksum creation and validation."""
for test in VALID_CHECKSUM:
hrp, _ = segwit_addr.bech32_decode(test)
self.assertIsNotNone(hrp)
pos = test.rfind('1')
test = test[:pos+1] + chr(ord(test[pos + 1]) ^ 1) + test[pos+2:]
hrp, _ = segwit_addr.bech32_decode(test)
self.assertIsNone(hrp)

def test_valid_address(self):
"""Test whether valid addresses decode to the correct output."""
for (address, hexscript) in VALID_ADDRESS:
hrp = "bc"
witver, witprog = segwit_addr.decode(hrp, address)
if witver is None:
hrp = "tb"
witver, witprog = segwit_addr.decode(hrp, address)
self.assertIsNotNone(witver)
scriptpubkey = segwit_scriptpubkey(witver, witprog)
self.assertEqual(scriptpubkey, binascii.unhexlify(hexscript))
addr = segwit_addr.encode(hrp, witver, witprog)
self.assertEqual(address.lower(), addr)

def test_invalid_address(self):
"""Test whether invalid addresses fail to decode."""
for test in INVALID_ADDRESS:
witver, _ = segwit_addr.decode("bc", test)
self.assertIsNone(witver)
witver, _ = segwit_addr.decode("tb", test)
self.assertIsNone(witver)

if __name__ == "__main__":
unittest.main()