mirror of
https://github.com/trezor/trezor-firmware.git
synced 2024-11-25 00:48:19 +00:00
implement bip32 - https://en.bitcoin.it/wiki/BIP_0032
This commit is contained in:
parent
07d1c22730
commit
afc9bcfe30
2
.gitignore
vendored
2
.gitignore
vendored
@ -1,4 +1,6 @@
|
||||
*.o
|
||||
test-bip32
|
||||
test-pubkey
|
||||
test-rfc6979
|
||||
test-speed
|
||||
test-verify
|
||||
|
12
Makefile
12
Makefile
@ -1,12 +1,18 @@
|
||||
CC = gcc
|
||||
CFLAGS = -Wall -Os
|
||||
OBJS = bignum.o ecdsa.o secp256k1.o sha2.o rand.o hmac.o
|
||||
OBJS = bignum.o ecdsa.o secp256k1.o sha2.o rand.o hmac.o bip32.o
|
||||
|
||||
all: test-rfc6979 test-speed test-verify
|
||||
all: test-bip32 test-pubkey test-rfc6979 test-speed test-verify
|
||||
|
||||
%.o: %.c
|
||||
$(CC) $(CFLAGS) -o $@ -c $<
|
||||
|
||||
test-bip32: test-bip32.o $(OBJS)
|
||||
gcc test-bip32.o $(OBJS) -o test-bip32
|
||||
|
||||
test-pubkey: test-pubkey.o $(OBJS)
|
||||
gcc test-pubkey.o $(OBJS) -o test-pubkey
|
||||
|
||||
test-rfc6979: test-rfc6979.o $(OBJS)
|
||||
gcc test-rfc6979.o $(OBJS) -o test-rfc6979
|
||||
|
||||
@ -17,4 +23,4 @@ test-verify: test-verify.o $(OBJS)
|
||||
gcc test-verify.o $(OBJS) -o test-verify -lcrypto
|
||||
|
||||
clean:
|
||||
rm -f $(OBJS) test-rfc6979 test-speed test-verify
|
||||
rm -f *.o test-bip32 test-pubkey test-rfc6979 test-speed test-verify
|
||||
|
30
bignum.c
30
bignum.c
@ -83,8 +83,8 @@ int bn_is_less(const bignum256 *a, const bignum256 *b)
|
||||
return 0;
|
||||
}
|
||||
|
||||
// assumes x < 2*prime
|
||||
void bn_mod(bignum256 *x, bignum256 const *prime)
|
||||
// assumes x < 2*prime, result < prime
|
||||
void bn_mod(bignum256 *x, const bignum256 *prime)
|
||||
{
|
||||
int i = 8;
|
||||
uint32_t temp;
|
||||
@ -113,7 +113,7 @@ void bn_mod(bignum256 *x, bignum256 const *prime)
|
||||
|
||||
// x = k * x
|
||||
// both inputs and result may be bigger than prime but not bigger than 2 * prime
|
||||
void bn_multiply(const bignum256 *k, bignum256 *x, bignum256 const *prime)
|
||||
void bn_multiply(const bignum256 *k, bignum256 *x, const bignum256 *prime)
|
||||
{
|
||||
int i, j;
|
||||
uint64_t temp = 0;
|
||||
@ -157,7 +157,8 @@ void bn_multiply(const bignum256 *k, bignum256 *x, bignum256 const *prime)
|
||||
}
|
||||
}
|
||||
|
||||
void bn_fast_mod(bignum256 *x, bignum256 const *prime)
|
||||
// result is smaller than 2*prime
|
||||
void bn_fast_mod(bignum256 *x, const bignum256 *prime)
|
||||
{
|
||||
int j;
|
||||
uint32_t coef;
|
||||
@ -182,7 +183,7 @@ void bn_fast_mod(bignum256 *x, bignum256 const *prime)
|
||||
#endif
|
||||
|
||||
// in field G_prime, small but slow
|
||||
void bn_inverse(bignum256 *x, bignum256 const *prime)
|
||||
void bn_inverse(bignum256 *x, const bignum256 *prime)
|
||||
{
|
||||
uint32_t i, j, limb;
|
||||
bignum256 res;
|
||||
@ -210,7 +211,7 @@ void bn_inverse(bignum256 *x, bignum256 const *prime)
|
||||
#else
|
||||
|
||||
// in field G_prime, big but fast
|
||||
void bn_inverse(bignum256 *x, bignum256 const *prime)
|
||||
void bn_inverse(bignum256 *x, const bignum256 *prime)
|
||||
{
|
||||
int i, j, k, len1, len2, mask;
|
||||
uint32_t u[9], v[9], s[10], r[10], temp, temp2;
|
||||
@ -382,6 +383,23 @@ void bn_inverse(bignum256 *x, bignum256 const *prime)
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
void bn_addmod(bignum256 *a, const bignum256 *b, const bignum256 *prime)
|
||||
{
|
||||
int i;
|
||||
uint32_t carry = 0;
|
||||
for (i = 0; i < 9; i++) {
|
||||
a->val[i] += b->val[i] + carry;
|
||||
if (a->val[i] > 0x3FFFFFFF) {
|
||||
carry = a->val[i] >> 30;
|
||||
a->val[i] &= 0x3FFFFFFF;
|
||||
} else {
|
||||
carry = 0;
|
||||
}
|
||||
}
|
||||
bn_mod(a, prime);
|
||||
}
|
||||
|
||||
// res = a - b
|
||||
// b < 2*prime; result not normalized
|
||||
void bn_substract(const bignum256 *a, const bignum256 *b, bignum256 *res)
|
||||
|
10
bignum.h
10
bignum.h
@ -54,13 +54,15 @@ int bn_is_zero(const bignum256 *a);
|
||||
|
||||
int bn_is_less(const bignum256 *a, const bignum256 *b);
|
||||
|
||||
void bn_mod(bignum256 *x, bignum256 const *prime);
|
||||
void bn_mod(bignum256 *x, const bignum256 *prime);
|
||||
|
||||
void bn_multiply(const bignum256 *k, bignum256 *x, bignum256 const *prime);
|
||||
void bn_multiply(const bignum256 *k, bignum256 *x, const bignum256 *prime);
|
||||
|
||||
void bn_fast_mod(bignum256 *x, bignum256 const *prime);
|
||||
void bn_fast_mod(bignum256 *x, const bignum256 *prime);
|
||||
|
||||
void bn_inverse(bignum256 *x, bignum256 const *prime);
|
||||
void bn_inverse(bignum256 *x, const bignum256 *prime);
|
||||
|
||||
void bn_addmod(bignum256 *a, const bignum256 *b, const bignum256 *prime);
|
||||
|
||||
void bn_substract(const bignum256 *a, const bignum256 *b, bignum256 *res);
|
||||
|
||||
|
47
bip32.c
Normal file
47
bip32.c
Normal file
@ -0,0 +1,47 @@
|
||||
#include <string.h>
|
||||
|
||||
#include "bignum.h"
|
||||
#include "hmac.h"
|
||||
#include "ecdsa.h"
|
||||
#include "bip32.h"
|
||||
|
||||
void xprv_from_seed(uint8_t *seed, int seed_len, xprv *out)
|
||||
{
|
||||
out->version = 0x0488ADE4; // main-net
|
||||
out->depth = 0;
|
||||
out->fingerprint = 0x00000000;
|
||||
out->child_num = 0;
|
||||
// this can be done because private_key[32] and chain_code[32]
|
||||
// form a continuous 64 byte block in the memory
|
||||
hmac_sha512((uint8_t *)"Bitcoin seed", 12, seed, seed_len, out->private_key);
|
||||
ecdsa_get_public_key_compressed(out->private_key, out->public_key);
|
||||
}
|
||||
|
||||
void xprv_descent(xprv *inout, uint32_t i)
|
||||
{
|
||||
uint8_t data[1 + 32 + 4];
|
||||
bignum256 a, b;
|
||||
|
||||
if (i & 0x80000000) {
|
||||
data[0] = 0;
|
||||
memcpy(data + 1, inout->private_key, 32);
|
||||
} else {
|
||||
ecdsa_get_public_key_compressed(inout->private_key, data);
|
||||
}
|
||||
write_be(data + 33, i);
|
||||
|
||||
bn_read_be(inout->private_key, &a);
|
||||
|
||||
// this can be done because private_key[32] and chain_code[32]
|
||||
// form a continuous 64 byte block in the memory
|
||||
hmac_sha512(inout->chain_code, 32, data, sizeof(data), inout->private_key);
|
||||
|
||||
bn_read_be(inout->private_key, &b);
|
||||
bn_addmod(&a, &b, &order256k1);
|
||||
|
||||
inout->depth++;
|
||||
inout->child_num = i;
|
||||
bn_write_be(&a, inout->private_key);
|
||||
|
||||
ecdsa_get_public_key_compressed(inout->private_key, inout->public_key);
|
||||
}
|
22
bip32.h
Normal file
22
bip32.h
Normal file
@ -0,0 +1,22 @@
|
||||
#ifndef __BIP32_H__
|
||||
#define __BIP32_H__
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
typedef struct {
|
||||
uint32_t version;
|
||||
uint32_t depth;
|
||||
uint32_t fingerprint;
|
||||
uint32_t child_num;
|
||||
uint8_t private_key[32]; // private_key + chain_code have to
|
||||
uint8_t chain_code[32]; // form a continuous 64 byte block
|
||||
uint8_t public_key[33];
|
||||
} xprv;
|
||||
|
||||
void xprv_from_seed(uint8_t *seed, int seed_len, xprv *out);
|
||||
|
||||
#define xprv_descent_prime(X, I) xprv_descent((X), ((I) | 0x80000000))
|
||||
|
||||
void xprv_descent(xprv *inout, uint32_t i);
|
||||
|
||||
#endif
|
16
ecdsa.c
16
ecdsa.c
@ -306,7 +306,7 @@ void ecdsa_sign(const uint8_t *priv_key, const uint8_t *msg, uint32_t msg_len, u
|
||||
// uses secp256k1 curve
|
||||
// priv_key is a 32 byte big endian stored number
|
||||
// pub_key is at least 70 bytes long array for the public key
|
||||
void ecdsa_get_public_key(const uint8_t *priv_key, uint8_t *pub_key, uint32_t *pub_key_len)
|
||||
void ecdsa_get_public_key_der(const uint8_t *priv_key, uint8_t *pub_key, uint32_t *pub_key_len)
|
||||
{
|
||||
uint32_t i;
|
||||
curve_point R;
|
||||
@ -324,6 +324,20 @@ void ecdsa_get_public_key(const uint8_t *priv_key, uint8_t *pub_key, uint32_t *p
|
||||
*pub_key_len = i + 2;
|
||||
}
|
||||
|
||||
|
||||
// pub_key is always 33 bytes long
|
||||
void ecdsa_get_public_key_compressed(const uint8_t *priv_key, uint8_t *pub_key)
|
||||
{
|
||||
curve_point R;
|
||||
bignum256 k;
|
||||
|
||||
bn_read_be(priv_key, &k);
|
||||
// compute k*G
|
||||
scalar_multiply(&k, &R);
|
||||
pub_key[0] = 0x02 | (R.y.val[0] & 0x01);
|
||||
bn_write_be(&R.x, pub_key + 1);
|
||||
}
|
||||
|
||||
// uses secp256k1 curve
|
||||
// pub_key and signature are DER encoded
|
||||
// msg is a data that was signed
|
||||
|
3
ecdsa.h
3
ecdsa.h
@ -30,7 +30,8 @@
|
||||
|
||||
// all functions use secp256k1 curve
|
||||
void ecdsa_sign(const uint8_t *priv_key, const uint8_t *msg, uint32_t msg_len, uint8_t *sig, uint32_t *sig_len);
|
||||
void ecdsa_get_public_key(const uint8_t *priv_key, uint8_t *pub_key, uint32_t *pub_key_len);
|
||||
void ecdsa_get_public_key_der(const uint8_t *priv_key, uint8_t *pub_key, uint32_t *pub_key_len);
|
||||
void ecdsa_get_public_key_compressed(const uint8_t *priv_key, uint8_t *pub_key);
|
||||
int ecdsa_verify(const uint8_t *pub_key, const uint8_t *signature, const uint8_t *msg, uint32_t msg_len);
|
||||
|
||||
#endif
|
||||
|
74
test-bip32.c
Normal file
74
test-bip32.c
Normal file
@ -0,0 +1,74 @@
|
||||
/**
|
||||
* Copyright (c) 2013 Pavol Rusnak
|
||||
*
|
||||
* 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 <stdio.h>
|
||||
|
||||
#include "bip32.h"
|
||||
|
||||
// test vectors from https://en.bitcoin.it/wiki/BIP_0032_TestVectors
|
||||
|
||||
void xprv_print(xprv *in)
|
||||
{
|
||||
int i;
|
||||
|
||||
printf("chain : "); for (i = 0; i < 32; i++) printf("%02x", in->chain_code[i]); printf("\n");
|
||||
printf("priv : "); for (i = 0; i < 32; i++) printf("%02x", in->private_key[i]); printf("\n");
|
||||
printf("pub : "); for (i = 0; i < 33; i++) printf("%02x", in->public_key[i]); printf("\n");
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
xprv node;
|
||||
|
||||
xprv_from_seed((uint8_t *)"\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f", 16, &node);
|
||||
|
||||
printf("[Chain m] got\n");
|
||||
xprv_print(&node);
|
||||
printf("[Chain m] expected\n");
|
||||
printf("chain : 873dff81c02f525623fd1fe5167eac3a55a049de3d314bb42ee227ffed37d508\n");
|
||||
printf("priv : e8f32e723decf4051aefac8e2c93c9c5b214313817cdb01a1494b917c8436b35\n");
|
||||
printf("pub : 0339a36013301597daef41fbe593a02cc513d0b55527ec2df1050e2e8ff49c85c2\n");
|
||||
printf("\n");
|
||||
|
||||
xprv_descent_prime(&node, 0);
|
||||
|
||||
printf("[Chain m/0'] got\n");
|
||||
xprv_print(&node);
|
||||
printf("[Chain m/0'] expected\n");
|
||||
printf("chain : 47fdacbd0f1097043b78c63c20c34ef4ed9a111d980047ad16282c7ae6236141\n");
|
||||
printf("priv : edb2e14f9ee77d26dd93b4ecede8d16ed408ce149b6cd80b0715a2d911a0afea\n");
|
||||
printf("pub : 035a784662a4a20a65bf6aab9ae98a6c068a81c52e4b032c0fb5400c706cfccc56\n");
|
||||
printf("\n");
|
||||
|
||||
xprv_descent(&node, 1);
|
||||
|
||||
printf("[Chain m/0'/1] got\n");
|
||||
xprv_print(&node);
|
||||
printf("[Chain m/0'/1] expected\n");
|
||||
printf("chain : 2a7857631386ba23dacac34180dd1983734e444fdbf774041578e9b6adb37c19\n");
|
||||
printf("priv : 3c6cb8d0f6a264c91ea8b5030fadaa8e538b020f0a387421a12de9319dc93368\n");
|
||||
printf("pub : 03501e454bf00751f24b1b489aa925215d66af2234e3891c3b21a52bedb3cd711c\n");
|
||||
printf("\n");
|
||||
|
||||
return 0;
|
||||
}
|
58
test-pubkey.c
Normal file
58
test-pubkey.c
Normal file
@ -0,0 +1,58 @@
|
||||
/**
|
||||
* Copyright (c) 2013 Pavol Rusnak
|
||||
*
|
||||
* 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 <stdio.h>
|
||||
#include "ecdsa.h"
|
||||
|
||||
// vectors from https://en.bitcoin.it/wiki/BIP_0032_TestVectors
|
||||
|
||||
const char *privs[] = {
|
||||
"\xe8\xf3\x2e\x72\x3d\xec\xf4\x05\x1a\xef\xac\x8e\x2c\x93\xc9\xc5\xb2\x14\x31\x38\x17\xcd\xb0\x1a\x14\x94\xb9\x17\xc8\x43\x6b\x35",
|
||||
"\xed\xb2\xe1\x4f\x9e\xe7\x7d\x26\xdd\x93\xb4\xec\xed\xe8\xd1\x6e\xd4\x08\xce\x14\x9b\x6c\xd8\x0b\x07\x15\xa2\xd9\x11\xa0\xaf\xea",
|
||||
"\x3c\x6c\xb8\xd0\xf6\xa2\x64\xc9\x1e\xa8\xb5\x03\x0f\xad\xaa\x8e\x53\x8b\x02\x0f\x0a\x38\x74\x21\xa1\x2d\xe9\x31\x9d\xc9\x33\x68",
|
||||
"\xcb\xce\x0d\x71\x9e\xcf\x74\x31\xd8\x8e\x6a\x89\xfa\x14\x83\xe0\x2e\x35\x09\x2a\xf6\x0c\x04\x2b\x1d\xf2\xff\x59\xfa\x42\x4d\xca",
|
||||
"\x0f\x47\x92\x45\xfb\x19\xa3\x8a\x19\x54\xc5\xc7\xc0\xeb\xab\x2f\x9b\xdf\xd9\x6a\x17\x56\x3e\xf2\x8a\x6a\x4b\x1a\x2a\x76\x4e\xf4",
|
||||
"\x47\x1b\x76\xe3\x89\xe5\x28\xd6\xde\x6d\x81\x68\x57\xe0\x12\xc5\x45\x50\x51\xca\xd6\x66\x08\x50\xe5\x83\x72\xa6\xc3\xe6\xe7\xc8",
|
||||
};
|
||||
|
||||
const char *pubs[] = {
|
||||
"0339a36013301597daef41fbe593a02cc513d0b55527ec2df1050e2e8ff49c85c2",
|
||||
"035a784662a4a20a65bf6aab9ae98a6c068a81c52e4b032c0fb5400c706cfccc56",
|
||||
"03501e454bf00751f24b1b489aa925215d66af2234e3891c3b21a52bedb3cd711c",
|
||||
"0357bfe1e341d01c69fe5654309956cbea516822fba8a601743a012a7896ee8dc2",
|
||||
"02e8445082a72f29b75ca48748a914df60622a609cacfce8ed0e35804560741d29",
|
||||
"022a471424da5e657499d1ff51cb43c47481a03b1e77f951fe64cec9f5a48f7011",
|
||||
};
|
||||
|
||||
int main()
|
||||
{
|
||||
int i, k;
|
||||
uint8_t pub[33];
|
||||
|
||||
for (k = 0; k < 6; k++) {
|
||||
ecdsa_get_public_key_compressed((uint8_t *)privs[k], pub);
|
||||
printf("got : "); for (i = 0; i < 33; i++) printf("%02x", pub[i]); printf("\n");
|
||||
printf("expected : %s\n", pubs[k]);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
@ -78,7 +78,7 @@ int main()
|
||||
ecdsa_sign(priv_key, msg, msg_len, sig, &sig_len);
|
||||
|
||||
// generate public key from private key
|
||||
ecdsa_get_public_key(priv_key, pub_key, &pub_key_len);
|
||||
ecdsa_get_public_key_der(priv_key, pub_key, &pub_key_len);
|
||||
|
||||
// use our ECDSA verifier to verify the message signature
|
||||
if (ecdsa_verify(pub_key, sig, msg, msg_len) != 0) {
|
||||
|
Loading…
Reference in New Issue
Block a user