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 :
33 : #include <stdint.h>
34 : #include <stdlib.h>
35 : #include <stdbool.h>
36 : #include <string.h>
37 : #include <secp256k1.h>
38 :
39 : #define NODE_LENGTH 64
40 :
41 : #ifdef DEBUG_BIP32
42 : #define DEBUG_LOG(...) LOG(__VA_ARGS__)
43 : #else
44 : #define DEBUG_LOG(...)
45 : #endif
46 :
47 : static const uint8_t secp256k1_order[] = {
48 : 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
49 : 0xff, 0xff, 0xff, 0xff, 0xfe, 0xba, 0xae, 0xdc, 0xe6, 0xaf, 0x48,
50 : 0xa0, 0x3b, 0xbf, 0xd2, 0x5e, 0x8c, 0xd0, 0x36, 0x41, 0x41};
51 :
52 : static secp256k1_context* sp_ctx = NULL;
53 :
54 : /**
55 : * Following portion taken from
56 : * https://github.com/someone42/hardware-bitcoin-wallet @
57 : * 102c300d994712484c3c028b215f90a6f99d6155 and adapted for use with
58 : * the powHSM HAL by RootstockLabs. LICENSE transcribed below.
59 : */
60 :
61 : /*
62 : Copyright (c) 2011-2012 someone42
63 : All rights reserved.
64 :
65 : Redistribution and use in source and binary forms, with or without
66 : modification, are permitted provided that the following conditions are met:
67 :
68 : Redistributions of source code must retain the above copyright notice,
69 : this list of conditions and the following disclaimer.
70 :
71 : Redistributions in binary form must reproduce the above copyright notice,
72 : this list of conditions and the following disclaimer in the documentation
73 : and/or other materials provided with the distribution.
74 :
75 : THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
76 : AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
77 : IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
78 : ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
79 : LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
80 : CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
81 : SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
82 : INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
83 : CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
84 : ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
85 : POSSIBILITY OF SUCH DAMAGE.
86 : */
87 :
88 : #define PRIVATE_KEY_DIGITS (PRIVATE_KEY_LENGTH / sizeof(DIGIT_T))
89 : #define NODE_PART_LENGTH PRIVATE_KEY_LENGTH
90 :
91 19 : static bool seed_to_node(uint8_t* master_node,
92 : const uint8_t* seed,
93 : const unsigned int seed_length) {
94 19 : return hmac_sha512(
95 : master_node, (const uint8_t*)"Bitcoin seed", 12, seed, seed_length);
96 : }
97 :
98 20 : bool bip32_derive_private(uint8_t* out,
99 : const size_t out_size,
100 : const uint8_t* seed,
101 : const unsigned int seed_length,
102 : const uint32_t* path,
103 : const unsigned int path_length) {
104 : uint8_t current_node[NODE_LENGTH];
105 : uint8_t temp[NODE_LENGTH];
106 : DIGIT_T tempbig_a[PRIVATE_KEY_DIGITS + 1],
107 : tempbig_b[PRIVATE_KEY_DIGITS + 1];
108 : DIGIT_T tempbig_c[PRIVATE_KEY_DIGITS + 1],
109 : tempbig_d[PRIVATE_KEY_DIGITS + 1];
110 : uint8_t hmac_data[1 + NODE_PART_LENGTH + 4]; // prefix + private key + i
111 : secp256k1_pubkey pubkey;
112 : size_t pubkey_serialised_size;
113 :
114 : // Make sure private key fits in the output buffer
115 20 : if (out_size < PRIVATE_KEY_LENGTH) {
116 : DEBUG_LOG("Output buffer too small for private key\n");
117 1 : return false;
118 : }
119 :
120 : // Init the secp256k1 context
121 19 : if (!sp_ctx)
122 1 : sp_ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN);
123 :
124 : // Compute the master node from the seed
125 19 : if (!seed_to_node(current_node, seed, seed_length)) {
126 : DEBUG_LOG("Error deriving master node from seed\n");
127 0 : return false;
128 : }
129 :
130 79 : for (unsigned int i = 0; i < path_length; i++) {
131 60 : if (path[i] & 0x80000000) {
132 : // Hardened derivation.
133 32 : hmac_data[0] = 0x00;
134 32 : memcpy(&hmac_data[1], current_node, NODE_PART_LENGTH);
135 : } else {
136 : // Non-hardened derivation.
137 28 : if (!secp256k1_ec_pubkey_create(sp_ctx, &pubkey, current_node)) {
138 : DEBUG_LOG("Error deriving public key from private key\n");
139 0 : return false;
140 : }
141 :
142 28 : pubkey_serialised_size = PUBKEY_CMP_LENGTH;
143 28 : secp256k1_ec_pubkey_serialize(sp_ctx,
144 : hmac_data,
145 : &pubkey_serialised_size,
146 : &pubkey,
147 : SECP256K1_EC_COMPRESSED);
148 :
149 28 : if (pubkey_serialised_size != PUBKEY_CMP_LENGTH) {
150 : DEBUG_LOG("Unexpected serialised public key size\n");
151 0 : return false;
152 : }
153 : }
154 60 : write_uint32_be(&hmac_data[PUBKEY_CMP_LENGTH], path[i]);
155 :
156 : // Need to write to temp here (instead of current_node) because part of
157 : // current_node is used as the key.
158 60 : if (!hmac_sha512(temp,
159 : ¤t_node[NODE_PART_LENGTH],
160 : NODE_PART_LENGTH,
161 : hmac_data,
162 : sizeof(hmac_data))) {
163 : DEBUG_LOG("Error deriving private key from parent node\n");
164 0 : return false;
165 : }
166 :
167 : // First 32 bytes of temp = I_L. Compute k_i
168 60 : if (!secp256k1_ec_seckey_verify(sp_ctx, temp)) {
169 : DEBUG_LOG(
170 : "Overflow during derivation, use a different one (I_L)\n");
171 0 : return false;
172 : }
173 60 : parse_bigint_be(
174 : temp, NODE_PART_LENGTH, tempbig_a, PRIVATE_KEY_DIGITS + 1);
175 :
176 60 : if (!secp256k1_ec_seckey_verify(sp_ctx, current_node)) {
177 : DEBUG_LOG("Invalid key during derivation, use a different path "
178 : "(invalid k_par)\n");
179 0 : return false;
180 : }
181 60 : parse_bigint_be(
182 : current_node, NODE_PART_LENGTH, tempbig_b, PRIVATE_KEY_DIGITS + 1);
183 :
184 60 : mpAdd(tempbig_a, tempbig_a, tempbig_b, PRIVATE_KEY_DIGITS + 1);
185 60 : parse_bigint_be(secp256k1_order,
186 : PRIVATE_KEY_LENGTH,
187 : tempbig_b,
188 : PRIVATE_KEY_DIGITS + 1);
189 60 : mpDivide(tempbig_d,
190 : tempbig_c,
191 : tempbig_a,
192 : PRIVATE_KEY_DIGITS + 1,
193 : tempbig_b,
194 : PRIVATE_KEY_DIGITS + 1);
195 60 : dump_bigint_be(current_node, tempbig_c, PRIVATE_KEY_DIGITS);
196 60 : if (!secp256k1_ec_seckey_verify(sp_ctx, current_node)) {
197 : DEBUG_LOG(
198 : "Invalid derived key, use a different path (invalid k_i)\n");
199 0 : return false;
200 : }
201 :
202 : // Last 32 bytes = I_R = c_i
203 60 : memcpy(¤t_node[NODE_PART_LENGTH],
204 : &temp[NODE_PART_LENGTH],
205 : NODE_PART_LENGTH);
206 : }
207 19 : memcpy(out, current_node, PRIVATE_KEY_LENGTH);
208 19 : return true; // success
209 : }
|