Pavol Rusnak 11 years ago
parent 07d1c22730
commit afc9bcfe30

2
.gitignore vendored

@ -1,4 +1,6 @@
*.o
test-bip32
test-pubkey
test-rfc6979
test-speed
test-verify

@ -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

@ -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)

@ -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);

@ -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);
}

@ -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

@ -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

@ -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

@ -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;
}

@ -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…
Cancel
Save