Line data Source code
1 : /**
2 : * The MIT License (MIT)
3 : *
4 : * Copyright (c) 2021 RSK Labs Ltd
5 : *
6 : * Permission is hereby granted, free of charge, to any person obtaining a copy
7 : * of this software and associated documentation files (the "Software"), to
8 : * deal in the Software without restriction, including without limitation the
9 : * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
10 : * sell copies of the Software, and to permit persons to whom the Software is
11 : * furnished to do so, subject to the following conditions:
12 : *
13 : * The above copyright notice and this permission notice shall be included in
14 : * all copies or substantial portions of the Software.
15 : *
16 : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 : * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 : * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 : * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 : * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 : * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
22 : * IN THE SOFTWARE.
23 : */
24 :
25 : #include "bip32.h"
26 : #include "hal/constants.h"
27 : #include "hal/log.h"
28 : #include "hmac_sha512.h"
29 : #include "endian.h"
30 : #include "bigdigits.h"
31 : #include "bigdigits_helper.h"
32 : #include "random.h"
33 :
34 : #include <stdint.h>
35 : #include <stdlib.h>
36 : #include <stdbool.h>
37 : #include <string.h>
38 : #include <secp256k1.h>
39 :
40 : #define NODE_LENGTH 64
41 :
42 : #ifdef DEBUG_BIP32
43 : #define DEBUG_LOG(...) LOG(__VA_ARGS__)
44 : #else
45 : #define DEBUG_LOG(...)
46 : #endif
47 :
48 : static const uint8_t secp256k1_order[] = {
49 : 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
50 : 0xff, 0xff, 0xff, 0xff, 0xfe, 0xba, 0xae, 0xdc, 0xe6, 0xaf, 0x48,
51 : 0xa0, 0x3b, 0xbf, 0xd2, 0x5e, 0x8c, 0xd0, 0x36, 0x41, 0x41};
52 :
53 : static secp256k1_context* sp_ctx = NULL;
54 :
55 : /**
56 : * Following portion taken from
57 : * https://github.com/someone42/hardware-bitcoin-wallet @
58 : * 102c300d994712484c3c028b215f90a6f99d6155 and adapted for use with
59 : * the powHSM HAL by RootstockLabs. LICENSE transcribed below.
60 : */
61 :
62 : /*
63 : Copyright (c) 2011-2012 someone42
64 : All rights reserved.
65 :
66 : Redistribution and use in source and binary forms, with or without
67 : modification, are permitted provided that the following conditions are met:
68 :
69 : Redistributions of source code must retain the above copyright notice,
70 : this list of conditions and the following disclaimer.
71 :
72 : Redistributions in binary form must reproduce the above copyright notice,
73 : this list of conditions and the following disclaimer in the documentation
74 : and/or other materials provided with the distribution.
75 :
76 : THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
77 : AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
78 : IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
79 : ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
80 : LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
81 : CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
82 : SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
83 : INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
84 : CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
85 : ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
86 : POSSIBILITY OF SUCH DAMAGE.
87 : */
88 :
89 : #define PRIVATE_KEY_DIGITS (PRIVATE_KEY_LENGTH / sizeof(DIGIT_T))
90 : #define NODE_PART_LENGTH PRIVATE_KEY_LENGTH
91 :
92 21 : static bool seed_to_node(uint8_t* master_node,
93 : const size_t master_node_length,
94 : const uint8_t* seed,
95 : const unsigned int seed_length) {
96 21 : return hmac_sha512(master_node,
97 : master_node_length,
98 : (const uint8_t*)"Bitcoin seed",
99 : 12,
100 : seed,
101 : seed_length);
102 : }
103 :
104 22 : bool bip32_derive_private(uint8_t* out,
105 : const size_t out_size,
106 : const uint8_t* seed,
107 : const unsigned int seed_length,
108 : const uint32_t* path,
109 : const unsigned int path_length) {
110 : uint8_t current_node[NODE_LENGTH];
111 : uint8_t temp[NODE_LENGTH];
112 : DIGIT_T tempbig_a[PRIVATE_KEY_DIGITS + 1],
113 : tempbig_b[PRIVATE_KEY_DIGITS + 1];
114 : DIGIT_T tempbig_c[PRIVATE_KEY_DIGITS + 1],
115 : tempbig_d[PRIVATE_KEY_DIGITS + 1];
116 : uint8_t hmac_data[1 + NODE_PART_LENGTH + 4]; // prefix + private key + i
117 : secp256k1_pubkey pubkey;
118 : size_t pubkey_serialised_size;
119 :
120 : // Make sure private key fits in the output buffer
121 22 : if (out_size < PRIVATE_KEY_LENGTH) {
122 : DEBUG_LOG("Output buffer too small for private key\n");
123 1 : return false;
124 : }
125 :
126 : // Init the secp256k1 context and randomise it
127 21 : if (!sp_ctx) {
128 : unsigned char randomize[32];
129 1 : sp_ctx = secp256k1_context_create(SECP256K1_CONTEXT_NONE);
130 1 : if (!random_getrandom(randomize, sizeof(randomize))) {
131 : DEBUG_LOG("Error generating random seed for "
132 : "secp256k1 context randomisation\n");
133 0 : return false;
134 : }
135 1 : if (!secp256k1_context_randomize(sp_ctx, randomize)) {
136 : DEBUG_LOG("Error randomising secp256k1 context\n");
137 0 : return false;
138 : }
139 1 : explicit_bzero(randomize, sizeof(randomize));
140 : }
141 :
142 : // Compute the master node from the seed
143 21 : if (!seed_to_node(current_node, sizeof(current_node), seed, seed_length)) {
144 : DEBUG_LOG("Error deriving master node from seed\n");
145 0 : return false;
146 : }
147 :
148 81 : for (unsigned int i = 0; i < path_length; i++) {
149 60 : if (path[i] & 0x80000000) {
150 : // Hardened derivation.
151 32 : hmac_data[0] = 0x00;
152 32 : memcpy(&hmac_data[1], current_node, NODE_PART_LENGTH);
153 : } else {
154 : // Non-hardened derivation.
155 28 : if (!secp256k1_ec_pubkey_create(sp_ctx, &pubkey, current_node)) {
156 : DEBUG_LOG("Error deriving public key from private key\n");
157 0 : return false;
158 : }
159 :
160 28 : pubkey_serialised_size = PUBKEY_CMP_LENGTH;
161 28 : secp256k1_ec_pubkey_serialize(sp_ctx,
162 : hmac_data,
163 : &pubkey_serialised_size,
164 : &pubkey,
165 : SECP256K1_EC_COMPRESSED);
166 :
167 28 : if (pubkey_serialised_size != PUBKEY_CMP_LENGTH) {
168 : DEBUG_LOG("Unexpected serialised public key size\n");
169 0 : return false;
170 : }
171 : }
172 60 : write_uint32_be(&hmac_data[PUBKEY_CMP_LENGTH], path[i]);
173 :
174 : // Need to write to temp here (instead of current_node) because part of
175 : // current_node is used as the key.
176 60 : if (!hmac_sha512(temp,
177 : sizeof(temp),
178 : ¤t_node[NODE_PART_LENGTH],
179 : NODE_PART_LENGTH,
180 : hmac_data,
181 : sizeof(hmac_data))) {
182 : DEBUG_LOG("Error deriving private key from parent node\n");
183 0 : return false;
184 : }
185 :
186 : // First 32 bytes of temp = I_L. Compute k_i
187 60 : if (!secp256k1_ec_seckey_verify(sp_ctx, temp)) {
188 : DEBUG_LOG(
189 : "Overflow during derivation, use a different one (I_L)\n");
190 0 : return false;
191 : }
192 60 : parse_bigint_be(
193 : temp, NODE_PART_LENGTH, tempbig_a, PRIVATE_KEY_DIGITS + 1);
194 :
195 60 : if (!secp256k1_ec_seckey_verify(sp_ctx, current_node)) {
196 : DEBUG_LOG("Invalid key during derivation, use a different path "
197 : "(invalid k_par)\n");
198 0 : return false;
199 : }
200 60 : parse_bigint_be(
201 : current_node, NODE_PART_LENGTH, tempbig_b, PRIVATE_KEY_DIGITS + 1);
202 :
203 60 : mpAdd(tempbig_a, tempbig_a, tempbig_b, PRIVATE_KEY_DIGITS + 1);
204 60 : parse_bigint_be(secp256k1_order,
205 : PRIVATE_KEY_LENGTH,
206 : tempbig_b,
207 : PRIVATE_KEY_DIGITS + 1);
208 60 : mpDivide(tempbig_d,
209 : tempbig_c,
210 : tempbig_a,
211 : PRIVATE_KEY_DIGITS + 1,
212 : tempbig_b,
213 : PRIVATE_KEY_DIGITS + 1);
214 60 : dump_bigint_be(current_node, tempbig_c, PRIVATE_KEY_DIGITS);
215 60 : if (!secp256k1_ec_seckey_verify(sp_ctx, current_node)) {
216 : DEBUG_LOG(
217 : "Invalid derived key, use a different path (invalid k_i)\n");
218 0 : return false;
219 : }
220 :
221 : // Last 32 bytes = I_R = c_i
222 60 : memcpy(¤t_node[NODE_PART_LENGTH],
223 : &temp[NODE_PART_LENGTH],
224 : NODE_PART_LENGTH);
225 : }
226 21 : memcpy(out, current_node, PRIVATE_KEY_LENGTH);
227 21 : return true; // success
228 : }
|