upleb.uk

Public git repos — served from a NIP-34 GRASP relay at git.upleb.uk

summaryrefslogtreecommitdiff
path: root/src/test_bip32.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/test_bip32.cpp')
-rw-r--r--src/test_bip32.cpp130
1 files changed, 130 insertions, 0 deletions
diff --git a/src/test_bip32.cpp b/src/test_bip32.cpp
new file mode 100644
index 0000000..610a651
--- /dev/null
+++ b/src/test_bip32.cpp
@@ -0,0 +1,130 @@
1// Standalone tests for BIP39/BIP32 primitives.
2//
3// Build:
4// g++ -std=gnu++14 test_bip32.cpp bip32.cpp -lssl -lcrypto -o test_bip32
5
6#include "bip32.h"
7
8#include <cstdio>
9#include <cstring>
10#include <string>
11#include <vector>
12
13using namespace bitflash;
14
15static int g_fail = 0;
16
17#define CHECK(cond, name) do { \
18 if (cond) { printf(" ok %s\n", name); } \
19 else { printf(" FAIL %s\n", name); g_fail++; } \
20} while (0)
21
22static int HexDigit(char c)
23{
24 if (c >= '0' && c <= '9') return c - '0';
25 if (c >= 'a' && c <= 'f') return c - 'a' + 10;
26 if (c >= 'A' && c <= 'F') return c - 'A' + 10;
27 return -1;
28}
29
30static std::vector<unsigned char> FromHex(const std::string& s)
31{
32 std::vector<unsigned char> out;
33 if (s.size() % 2 != 0)
34 return out;
35 out.reserve(s.size() / 2);
36 for (size_t i = 0; i < s.size(); i += 2)
37 {
38 int hi = HexDigit(s[i]);
39 int lo = HexDigit(s[i + 1]);
40 if (hi < 0 || lo < 0)
41 return std::vector<unsigned char>();
42 out.push_back((unsigned char)((hi << 4) | lo));
43 }
44 return out;
45}
46
47static std::string ToHex(const std::vector<unsigned char>& v)
48{
49 static const char* hex = "0123456789abcdef";
50 std::string out;
51 out.reserve(v.size() * 2);
52 for (unsigned char c : v)
53 {
54 out.push_back(hex[c >> 4]);
55 out.push_back(hex[c & 0x0f]);
56 }
57 return out;
58}
59
60int main()
61{
62 std::string err;
63
64 printf("bip39_entropy_to_mnemonic\n");
65 {
66 std::vector<unsigned char> entropy(16, 0);
67 std::string mnemonic;
68 CHECK(BIP39EntropyToMnemonic(entropy, mnemonic, err), "zero entropy encodes");
69 CHECK(mnemonic ==
70 "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about",
71 "matches BIP39 vector");
72 }
73
74 printf("bip39_validation\n");
75 {
76 std::string normalized;
77 CHECK(BIP39ValidateMnemonic(
78 " Abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about ",
79 normalized, err),
80 "valid phrase normalizes");
81 CHECK(normalized ==
82 "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about",
83 "normalized text matches");
84 CHECK(!BIP39ValidateMnemonic(
85 "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon",
86 normalized, err),
87 "bad checksum rejected");
88 }
89
90 printf("bip39_seed\n");
91 {
92 std::vector<unsigned char> seed;
93 const std::string mnemonic =
94 "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about";
95 CHECK(BIP39MnemonicToSeed(mnemonic, "TREZOR", seed, err), "mnemonic derives seed");
96 CHECK(ToHex(seed) ==
97 "c55257c360c07c72029aebc1b53c05ed0362ada38ead3e3e9efa3708e5349553"
98 "1f09a6987599d18264c1e1c92f2cf141630c7a3c4ab7c81b2f001698e7463b04",
99 "matches BIP39 seed vector");
100 }
101
102 printf("bip32_master\n");
103 {
104 std::vector<unsigned char> seed = FromHex("000102030405060708090a0b0c0d0e0f");
105 BIP32PrivateNode master;
106 CHECK(BIP32MasterFromSeed(seed, master, err), "master key derives");
107 CHECK(ToHex(master.privateKey) ==
108 "e8f32e723decf4051aefac8e2c93c9c5b214313817cdb01a1494b917c8436b35",
109 "matches BIP32 master private key");
110 CHECK(ToHex(master.chainCode) ==
111 "873dff81c02f525623fd1fe5167eac3a55a049de3d314bb42ee227ffed37d508",
112 "matches BIP32 master chain code");
113
114 BIP32PrivateNode childA, childB;
115 CHECK(BIP32DeriveHardenedChild(master, 0, childA, err), "hardened child derives");
116 CHECK(BIP32DeriveHardenedChild(master, 0, childB, err), "hardened child re-derives");
117 CHECK(childA.privateKey == childB.privateKey &&
118 childA.chainCode == childB.chainCode,
119 "same child path is deterministic");
120 CHECK(childA.privateKey != master.privateKey &&
121 childA.chainCode != master.chainCode,
122 "child differs from parent");
123 CHECK(!BIP32DeriveHardenedChild(master, 0x80000000U, childA, err),
124 "pre-hardened index rejected");
125 }
126
127 printf("\n%s (%d failures)\n",
128 g_fail == 0 ? "ALL TESTS PASSED" : "TESTS FAILED", g_fail);
129 return g_fail == 0 ? 0 : 1;
130}