Add Cardano currency support

pull/25/head
jmuravsky 6 years ago committed by Pavol Rusnak
parent 3e8974ff88
commit 18b109e2bd

@ -28,6 +28,7 @@ CFLAGS += -DUSE_ETHEREUM=1
CFLAGS += -DUSE_GRAPHENE=1
CFLAGS += -DUSE_NEM=1
CFLAGS += -DUSE_MONERO=1
CFLAGS += -DUSE_CARDANO=1
CFLAGS += $(shell pkg-config --cflags openssl)
# disable certain optimizations and features when small footprint is required

@ -46,6 +46,11 @@
#if USE_NEM
#include "nem.h"
#endif
#if USE_CARDANO
#include "ed25519-donna/modm-donna-32bit.h"
#include "blake2b.h"
#include "bip39.h"
#endif
#include "memzero.h"
const curve_info ed25519_info = {
@ -57,6 +62,15 @@ const curve_info ed25519_info = {
.hasher_pubkey = HASHER_SHA2,
};
const curve_info ed25519_cardano_info = {
.bip32_name = "ed25519 cardano seed",
.params = NULL,
.hasher_bip32 = HASHER_SHA2,
.hasher_base58 = HASHER_SHA2D,
.hasher_sign = HASHER_SHA2D,
.hasher_pubkey = HASHER_SHA2,
};
const curve_info ed25519_sha3_info = {
.bip32_name = "ed25519-sha3 seed",
.params = NULL,
@ -100,6 +114,7 @@ int hdnode_from_xpub(uint32_t depth, uint32_t child_num, const uint8_t *chain_co
out->child_num = child_num;
memcpy(out->chain_code, chain_code, 32);
memzero(out->private_key, 32);
memzero(out->private_key_extension,32);
memcpy(out->public_key, public_key, 33);
return 1;
}
@ -133,6 +148,7 @@ int hdnode_from_xprv(uint32_t depth, uint32_t child_num, const uint8_t *chain_co
memcpy(out->chain_code, chain_code, 32);
memcpy(out->private_key, private_key, 32);
memzero(out->public_key, sizeof(out->public_key));
memzero(out->private_key_extension, sizeof(out->private_key_extension));
return 1;
}
@ -252,6 +268,195 @@ int hdnode_private_ckd(HDNode *inout, uint32_t i)
return 1;
}
#ifdef USE_CARDANO
static void multiply8(uint8_t *dst, uint8_t *src, int bytes)
{
int i;
uint8_t prev_acc = 0;
for (i = 0; i < bytes; i++) {
dst[i] = (src[i] << 3) + (prev_acc & 0x8);
prev_acc = src[i] >> 5;
}
}
static void add_256bits(uint8_t *dst, uint8_t *src1, uint8_t *src2)
{
int i;
for (i = 0; i < 32; i++) {
uint8_t a = src1[i];
uint8_t b = src2[i];
uint16_t r = a + b;
dst[i] = r & 0xff;
}
}
int ed25519_scalar_add(const uint8_t *sk1, const uint8_t *sk2, uint8_t *res)
{
bignum256modm s1, s2;
expand256_modm(s1, sk1, 32);
expand256_modm(s2, sk2, 32);
add256_modm(s1, s1, s2);
contract256_modm(res, s1);
return 0;
}
int hdnode_private_ckd_cardano(HDNode *inout, uint32_t i)
{
//checks for hardened/non-hardened derivation, keysize 32 means we are dealing with public key and thus non-h, keysize 64 is for private key
int keysize = 32;
if(i & 0x80000000){
keysize = 64;
}
static CONFIDENTIAL uint8_t data[1 + 64 + 4];
static CONFIDENTIAL uint8_t I[32 + 32];
static CONFIDENTIAL bignum256 a, b;
static CONFIDENTIAL uint8_t priv_key[64];
static CONFIDENTIAL uint8_t res_key[64];
memcpy(priv_key, inout->private_key, 32);
memcpy(priv_key + 32, inout->private_key_extension, 32);
if (keysize == 64) { // private derivation
data[0] = 0;
memcpy(data + 1, inout->private_key, 32);
memcpy(data + 1 + 32, inout->private_key_extension, 32);
} else { // public derivation
hdnode_fill_public_key(inout);
data[0] = 2;
memcpy(data + 1, inout->public_key + 1, 32);
}
write_be(data + keysize + 1, i);
bn_read_be(priv_key, &a);
static CONFIDENTIAL HMAC_SHA512_CTX ctx;
hmac_sha512_Init(&ctx, inout->chain_code, 32);
hmac_sha512_Update(&ctx, data, 1 + keysize + 4);
hmac_sha512_Final(&ctx, I);
static CONFIDENTIAL uint8_t zl8[32];
multiply8(zl8,I,32);
ed25519_scalar_add(zl8,priv_key,res_key);
add_256bits(res_key+32,I+32,priv_key+32);
memcpy(inout->private_key, res_key, 32);
memcpy(inout->private_key_extension, res_key + 32, 32);
if(keysize == 64){
data[0]=1;
}else{
data[0]=3;
}
hmac_sha512_Init(&ctx, inout->chain_code, 32);
hmac_sha512_Update(&ctx, data, 1 + keysize + 4);
hmac_sha512_Final(&ctx, I);
memcpy(inout->chain_code, I + 32, 32);
inout->depth++;
inout->child_num = i;
memzero(inout->public_key, sizeof(inout->public_key));
// making sure to wipe our memory
memzero(&a, sizeof(a));
memzero(&b, sizeof(b));
memzero(I, sizeof(I));
memzero(data, sizeof(data));
memzero(priv_key, sizeof(priv_key));
memzero(res_key, sizeof(res_key));
return 1;
}
void decitoa(int val, char * out){
static char buf[32] = {0};
int i = 30;
for(; val && i ; --i, val /= 10){
buf[i] = "0123456789"[val % 10];
}
memcpy(out,&buf[i+1],strlen(&buf[i+1])+1);
}
int hdnode_from_seed_cardano(uint8_t *seed, int seed_len, HDNode *out){
uint8_t hash[32];
uint8_t cbor[32+2];
if(seed_len < 24){
// cbor encodes length directly into first byte if its smaller than 24
seed[1] = 64 | seed_len;
blake2b(seed + 1, seed_len + 1, hash, 32);
}else{
seed[0] = 88;
seed[1] = seed_len;
blake2b(seed, seed_len + 2, hash, 32);
}
cbor[0] = 88; // 64 means its byte array, 24 means its length has 8 bits
cbor[1] = 32; // length of the byte array
memcpy(cbor + 2, hash, 32);
char salt[21];
memcpy(salt, "Root Seed Chain xyzw", 16);
char c[21];
uint8_t hmac[64];
uint8_t secret[64];
uint8_t public[32];
uint8_t chain_code[32];
int failed = 1;
memset(out, 0, sizeof(HDNode));
out->depth = 0;
out->child_num = 0;
out->curve = get_curve_by_name(ED25519_CARDANO_NAME);
static CONFIDENTIAL HMAC_SHA512_CTX ctx;
for(int i = 1; i <= 1000; i++){
hmac_sha512_Init(&ctx, cbor, 34);
decitoa(i, c);
memcpy(salt + 16, c, strlen(c) + 1);
hmac_sha512_Update(&ctx, (unsigned char *)salt, strlen(salt));
hmac_sha512_Final(&ctx, hmac);
ed25519_publickey(hmac, public);
sha512_Raw(hmac, 32, secret);
secret[0] &= 248;
secret[31] &= 127;
secret[31] |= 64;
if (secret[31] & 0x20) {
continue;
}
memcpy(chain_code, hmac + 32, 32);
failed = 0;
break;
}
memzero(hash, 32);
memzero(cbor, 34);
memzero(salt, strlen(salt) + 1);
memzero(c, strlen(c) + 1);
if(failed){
memzero(seed, sizeof(seed));
memzero(secret, sizeof(secret));
memzero(chain_code, sizeof(chain_code));
memzero(hmac, sizeof(hmac));
return 0;
}
memcpy(out->private_key, secret, 32);
memcpy(out->private_key_extension, secret + 32, 32);
memcpy(out->chain_code, chain_code, 32);
out->public_key[0] = 1;
memcpy(out->public_key + 1, public, 32);
memzero(seed, sizeof(seed));
memzero(secret, sizeof(secret));
memzero(chain_code, sizeof(chain_code));
memzero(hmac, sizeof(hmac));
return 1;
}
#endif
int hdnode_public_ckd_cp(const ecdsa_curve *curve, const curve_point *parent, const uint8_t *parent_chain_code, uint32_t i, curve_point *child, uint8_t *child_chain_code) {
uint8_t data[1 + 32 + 4];
uint8_t I[32 + 32];
@ -270,7 +475,7 @@ int hdnode_public_ckd_cp(const ecdsa_curve *curve, const curve_point *parent, co
bn_read_be(I, &c);
if (bn_is_less(&c, &curve->order)) { // < order
scalar_multiply(curve, &c, child); // b = c * G
point_add(curve, parent, child); // b = a + b
point_add(curve, parent, child); // b = a + b
if (!point_is_infinity(child)) {
if (child_chain_code) {
memcpy(child_chain_code, I + 32, 32);
@ -371,8 +576,8 @@ int hdnode_private_ckd_cached(HDNode *inout, const uint32_t *i, size_t i_count,
int j;
for (j = 0; j < BIP32_CACHE_SIZE; j++) {
if (private_ckd_cache[j].set &&
private_ckd_cache[j].depth == i_count - 1 &&
memcmp(private_ckd_cache[j].i, i, (i_count - 1) * sizeof(uint32_t)) == 0 &&
private_ckd_cache[j].depth == i_count - 1 &&
memcmp(private_ckd_cache[j].i, i, (i_count - 1) * sizeof(uint32_t)) == 0 &&
private_ckd_cache[j].node.curve == inout->curve) {
memcpy(inout, &(private_ckd_cache[j].node), sizeof(HDNode));
found = true;
@ -437,11 +642,15 @@ void hdnode_fill_public_key(HDNode *node)
#endif
} else if (node->curve == &curve25519_info) {
curve25519_scalarmult_basepoint(node->public_key + 1, node->private_key);
#ifdef USE_CARDANO
} else if (node->curve == &ed25519_cardano_info){
ed25519_publickey_ext(node->private_key, node->private_key_extension, node->public_key + 1);
#endif
}
}
#else
ecdsa_get_public_key33(node->curve->params, node->private_key, node->public_key);
ecdsa_get_public_key33(node->curve->params, node->private_key, node->public_key);
#endif
}
@ -696,6 +905,9 @@ const curve_info *get_curve_by_name(const char *curve_name) {
if (strcmp(curve_name, ED25519_NAME) == 0) {
return &ed25519_info;
}
if (strcmp(curve_name, ED25519_CARDANO_NAME) == 0) {
return &ed25519_cardano_info;
}
if (strcmp(curve_name, ED25519_SHA3_NAME) == 0) {
return &ed25519_sha3_info;
}

@ -45,7 +45,10 @@ typedef struct {
uint32_t depth;
uint32_t child_num;
uint8_t chain_code[32];
uint8_t private_key[32];
uint8_t private_key_extension[32];
uint8_t public_key[33];
const curve_info *curve;
} HDNode;
@ -59,6 +62,10 @@ int hdnode_from_seed(const uint8_t *seed, int seed_len, const char *curve, HDNod
#define hdnode_private_ckd_prime(X, I) hdnode_private_ckd((X), ((I) | 0x80000000))
int hdnode_private_ckd(HDNode *inout, uint32_t i);
#ifdef USE_CARDANO
int hdnode_private_ckd_cardano(HDNode *inout, uint32_t i);
int hdnode_from_seed_cardano(uint8_t *seed, int seed_len, HDNode *out);
#endif
int hdnode_public_ckd_cp(const ecdsa_curve *curve, const curve_point *parent, const uint8_t *parent_chain_code, uint32_t i, curve_point *child, uint8_t *child_chain_code);

@ -136,6 +136,67 @@ const uint16_t *mnemonic_from_data_indexes(const uint8_t *data, int len)
return mnemo;
}
int mnemonic_to_entropy(const char *mnemonic, uint8_t *entropy){
if (!mnemonic) {
return 0;
}
uint32_t i, n;
i = 0; n = 0;
while (mnemonic[i]) {
if (mnemonic[i] == ' ') {
n++;
}
i++;
}
n++;
// check number of words
if (n != 12 && n != 18 && n != 24) {
return 0;
}
char current_word[10];
uint32_t j, k, ki, bi;
uint8_t bits[32 + 1];
memzero(bits, sizeof(bits));
i = 0; bi = 0;
while (mnemonic[i]) {
j = 0;
while (mnemonic[i] != ' ' && mnemonic[i] != 0) {
if (j >= sizeof(current_word) - 1) {
return 0;
}
current_word[j] = mnemonic[i];
i++; j++;
}
current_word[j] = 0;
if (mnemonic[i] != 0) i++;
k = 0;
for (;;) {
if (!wordlist[k]) { // word not found
return 0;
}
if (strcmp(current_word, wordlist[k]) == 0) { // word found on index k
for (ki = 0; ki < 11; ki++) {
if (k & (1 << (10 - ki))) {
bits[bi / 8] |= 1 << (7 - (bi % 8));
}
bi++;
}
break;
}
k++;
}
}
if (bi != n * 11) {
return 0;
}
memcpy(entropy,bits,sizeof(bits));
return (n*11);
}
int mnemonic_check(const char *mnemonic)
{
if (!mnemonic) {

@ -36,6 +36,8 @@ const uint16_t *mnemonic_from_data_indexes(const uint8_t *data, int len);
int mnemonic_check(const char *mnemonic);
int mnemonic_to_entropy(const char *mnemonic, uint8_t *entropy);
// passphrase must be at most 256 characters or code may crash
void mnemonic_to_seed(const char *mnemonic, const char *passphrase, uint8_t seed[512 / 8], void (*progress_callback)(uint32_t current, uint32_t total));

@ -27,6 +27,7 @@ const char SECP256K1_DECRED_NAME[] = "secp256k1-decred";
const char SECP256K1_GROESTL_NAME[] = "secp256k1-groestl";
const char NIST256P1_NAME[] = "nist256p1";
const char ED25519_NAME[] = "ed25519";
const char ED25519_CARDANO_NAME[] = "ed25519 cardano seed";
const char ED25519_SHA3_NAME[] = "ed25519-sha3";
#if USE_KECCAK
const char ED25519_KECCAK_NAME[] = "ed25519-keccak";

@ -30,6 +30,7 @@ extern const char SECP256K1_DECRED_NAME[];
extern const char SECP256K1_GROESTL_NAME[];
extern const char NIST256P1_NAME[];
extern const char ED25519_NAME[];
extern const char ED25519_CARDANO_NAME[];
extern const char ED25519_SHA3_NAME[];
#if USE_KECCAK
extern const char ED25519_KECCAK_NAME[];

@ -48,11 +48,29 @@ ED25519_FN(ed25519_publickey) (const ed25519_secret_key sk, ed25519_public_key p
/* A = aB */
ed25519_extsk(extsk, sk);
expand256_modm(a, extsk, 32);
ge25519_scalarmult_base_niels(&A, ge25519_niels_base_multiples, a);
ge25519_pack(pk, &A);
}
#ifdef USE_CARDANO
void
ED25519_FN(ed25519_publickey_ext) (const ed25519_secret_key sk, const ed25519_secret_key skext, ed25519_public_key pk) {
bignum256modm a;
ge25519 ALIGN(16) A;
hash_512bits extsk;
/* we don't stretch the key through hashing first since its already 64 bytes */
memcpy(extsk, sk, 32);
memcpy(extsk+32, skext, 32);
expand256_modm(a, extsk, 32);
ge25519_scalarmult_base_niels(&A, ge25519_niels_base_multiples, a);
ge25519_pack(pk, &A);
}
#endif
void
ED25519_FN(ed25519_cosi_sign) (const unsigned char *m, size_t mlen, const ed25519_secret_key sk, const ed25519_secret_key nonce, const ed25519_public_key R, const ed25519_public_key pk, ed25519_cosi_signature sig) {
bignum256modm r, S, a;
@ -88,6 +106,7 @@ ED25519_FN(ed25519_sign) (const unsigned char *m, size_t mlen, const ed25519_sec
ed25519_extsk(extsk, sk);
/* r = H(aExt[32..64], m) */
ed25519_hash_init(&ctx);
ed25519_hash_update(&ctx, extsk + 32, 32);
@ -114,6 +133,47 @@ ED25519_FN(ed25519_sign) (const unsigned char *m, size_t mlen, const ed25519_sec
contract256_modm(RS + 32, S);
}
#ifdef USE_CARDANO
void
ED25519_FN(ed25519_sign_ext) (const unsigned char *m, size_t mlen, const ed25519_secret_key sk, const ed25519_secret_key skext, const ed25519_public_key pk, ed25519_signature RS) {
ed25519_hash_context ctx;
bignum256modm r, S, a;
ge25519 ALIGN(16) R;
hash_512bits extsk, hashr, hram;
/* we don't stretch the key through hashing first since its already 64 bytes */
memcpy(extsk, sk, 32);
memcpy(extsk+32, skext, 32);
/* r = H(aExt[32..64], m) */
ed25519_hash_init(&ctx);
ed25519_hash_update(&ctx, extsk + 32, 32);
ed25519_hash_update(&ctx, m, mlen);
ed25519_hash_final(&ctx, hashr);
expand256_modm(r, hashr, 64);
/* R = rB */
ge25519_scalarmult_base_niels(&R, ge25519_niels_base_multiples, r);
ge25519_pack(RS, &R);
/* S = H(R,A,m).. */
ed25519_hram(hram, RS, pk, m, mlen);
expand256_modm(S, hram, 64);
/* S = H(R,A,m)a */
expand256_modm(a, extsk, 32);
mul256_modm(S, S, a);
/* S = (r + H(R,A,m)a) */
add256_modm(S, S, r);
/* S = (r + H(R,A,m)a) mod L */
contract256_modm(RS + 32, S);
}
#endif
int
ED25519_FN(ed25519_sign_open) (const unsigned char *m, size_t mlen, const ed25519_public_key pk, const ed25519_signature RS) {
ge25519 ALIGN(16) R, A;

@ -14,9 +14,15 @@ typedef unsigned char curve25519_key[32];
typedef unsigned char ed25519_cosi_signature[32];
void ed25519_publickey(const ed25519_secret_key sk, ed25519_public_key pk);
#ifdef USE_CARDANO
void ed25519_publickey_ext(const ed25519_secret_key sk, const ed25519_secret_key skext, ed25519_public_key pk);
#endif
int ed25519_sign_open(const unsigned char *m, size_t mlen, const ed25519_public_key pk, const ed25519_signature RS);
void ed25519_sign(const unsigned char *m, size_t mlen, const ed25519_secret_key sk, const ed25519_public_key pk, ed25519_signature RS);
#ifdef USE_CARDANO
void ed25519_sign_ext(const unsigned char *m, size_t mlen, const ed25519_secret_key sk, const ed25519_secret_key skext, const ed25519_public_key pk, ed25519_signature RS);
#endif
int ed25519_scalarmult(ed25519_public_key res, const ed25519_secret_key sk, const ed25519_public_key pk);

@ -1872,6 +1872,141 @@ START_TEST(test_bip32_decred_vector_2)
}
END_TEST
// https://github.com/input-output-hk/cardano-crypto/blob/master/tests/goldens/cardano/crypto/wallet/BIP39-128
START_TEST(test_bip32_cardano_hdnode_vector_1)
{
HDNode node;
uint8_t seed[66];
int seed_len = mnemonic_to_entropy("ring crime symptom enough erupt lady behave ramp apart settle citizen junk", seed + 2);
hdnode_from_seed_cardano(seed, seed_len / 8, &node);
ck_assert_mem_eq(node.chain_code, fromhex("739f4b3caca4c9ad4fcd4bdc2ef42c8601af8d6946999ef85ef6ae84f66e72eb"), 32);
ck_assert_mem_eq(node.private_key, fromhex("6065a956b1b34145c4416fdc3ba3276801850e91a77a31a7be782463288aea53"), 32);
ck_assert_mem_eq(node.private_key_extension, fromhex("60ba6e25b1a02157fb69c5d1d7b96c4619736e545447069a6a6f0ba90844bc8e"), 32);
hdnode_fill_public_key(&node);
ck_assert_mem_eq(node.public_key + 1, fromhex("64b20fa082b3143d6b5eed42c6ef63f99599d0888afe060620abc1b319935fe1"), 32);
}
END_TEST
START_TEST(test_bip32_cardano_hdnode_vector_2)
{
HDNode node;
uint8_t seed[66];
int seed_len = mnemonic_to_entropy("ring crime symptom enough erupt lady behave ramp apart settle citizen junk", seed + 2);
hdnode_from_seed_cardano(seed, seed_len / 8, &node);
hdnode_private_ckd_cardano(&node, 0x80000000);
ck_assert_mem_eq(node.chain_code, fromhex("6755cb82e892d6614c007a5efbceb21d95a5244e269d0e206b48b9a495390b03"), 32);
ck_assert_mem_eq(node.private_key, fromhex("e7d27516538403a53a8b041656a3f570909df641a0ab811fe7d87c9ba02a830c"), 32);
ck_assert_mem_eq(node.private_key_extension, fromhex("794a2c54ad8b525b781773c87d38cbf4197636bc427a9d551368286fe4c294a4"), 32);
hdnode_fill_public_key(&node);
ck_assert_mem_eq(node.public_key + 1, fromhex("95bb82ffd5707716bc65170ab4e8dafeed90fbe0ce9258713b7751e962d931df"), 32);
}
END_TEST
START_TEST(test_bip32_cardano_hdnode_vector_3)
{
HDNode node;
uint8_t seed[66];
int seed_len = mnemonic_to_entropy("ring crime symptom enough erupt lady behave ramp apart settle citizen junk", seed + 2);
hdnode_from_seed_cardano(seed, seed_len / 8, &node);
hdnode_private_ckd_cardano(&node, 0x80000001);
ck_assert_mem_eq(node.chain_code, fromhex("47a242713bd18608231147c066b6083bfc1e9066fec9f621844c84fed6228a34"), 32);
ck_assert_mem_eq(node.private_key, fromhex("9b5a3d9a4c60bcd49bb64b72c082b164314d0f61d842f2575fd1d4fb30a28a0c"), 32);
ck_assert_mem_eq(node.private_key_extension, fromhex("b093e376f41eb7bf80abcd0073a52455d25b5d21815bc758e5f6f81536aedebb"), 32);
hdnode_fill_public_key(&node);
ck_assert_mem_eq(node.public_key + 1, fromhex("79fc8154554b97e4c56ef2f9dbb4c1421ff19509688931a1e964bda5dec0f19f"), 32);
}
END_TEST
START_TEST(test_bip32_cardano_hdnode_vector_4)
{
HDNode node;
uint8_t seed[66];
int seed_len = mnemonic_to_entropy("ring crime symptom enough erupt lady behave ramp apart settle citizen junk", seed + 2);
hdnode_from_seed_cardano(seed, seed_len / 8, &node);
hdnode_private_ckd_cardano(&node, 0x80000000);
hdnode_private_ckd_cardano(&node, 0x80000001);
ck_assert_mem_eq(node.chain_code, fromhex("d6798491b9fa4612370ae5ef3c623a0b6872f3ad8f26970885fa67c83bdc425e"), 32);
ck_assert_mem_eq(node.private_key, fromhex("52e0c98aa600cfdcd1ff28fcda5227ed87063f4a98547a78b771052cf102b40c"), 32);
ck_assert_mem_eq(node.private_key_extension, fromhex("6c18d9f8075b1a6a1833540607479bd58b7beb8a83d2bb01ca7ae02452a25803"), 32);
hdnode_fill_public_key(&node);
ck_assert_mem_eq(node.public_key + 1, fromhex("dc907c7c06e6314eedd9e18c9f6c6f9cc4e205fb1c70da608234c319f1f7b0d6"), 32);
}
END_TEST
START_TEST(test_bip32_cardano_hdnode_vector_5)
{
HDNode node;
uint8_t seed[66];
int seed_len = mnemonic_to_entropy("ring crime symptom enough erupt lady behave ramp apart settle citizen junk", seed + 2);
hdnode_from_seed_cardano(seed, seed_len / 8, &node);
hdnode_private_ckd_cardano(&node, 0x80000000);
hdnode_private_ckd_cardano(&node, 0x80000001);
hdnode_private_ckd_cardano(&node, 0x80000002);
ck_assert_mem_eq(node.chain_code, fromhex("4169a2a32e3618a903e930bd1a713033a38f92389093408394e29ac37a1752ea"), 32);
ck_assert_mem_eq(node.private_key, fromhex("11fd6462a3a92b35c22703f6f1c124ddcf36b7c2b09cc2784f320e1cfa12ec04"), 32);
ck_assert_mem_eq(node.private_key_extension, fromhex("c2785803c61c46aeca192a1bb1b7b20a8c4cc7fa01db57fc5d1d8a5473402352"), 32);
hdnode_fill_public_key(&node);
ck_assert_mem_eq(node.public_key + 1, fromhex("839775a41876e328986aa26168958bba1176e67819b357eea84afceab8b1db78"), 32);
}
END_TEST
START_TEST(test_bip32_cardano_hdnode_vector_6)
{
HDNode node;
uint8_t seed[66];
int seed_len = mnemonic_to_entropy("ring crime symptom enough erupt lady behave ramp apart settle citizen junk", seed + 2);
hdnode_from_seed_cardano(seed, seed_len / 8, &node);
hdnode_private_ckd_cardano(&node, 0x80000000);
hdnode_private_ckd_cardano(&node, 0x80000001);
hdnode_private_ckd_cardano(&node, 0x80000002);
hdnode_private_ckd_cardano(&node, 0x80000002);
ck_assert_mem_eq(node.chain_code, fromhex("3ae9c99a5925cba2dcf121baf3a0254f3dea23c129f9eb70a8a7e8897c5199ba"), 32);
ck_assert_mem_eq(node.private_key, fromhex("5b1e5cad02274ba461f4708d8598d3497faf8fe3e894a379573aa6ac3a03e505"), 32);
ck_assert_mem_eq(node.private_key_extension, fromhex("ba179d2e3c67aabb486c48d16002b51ad32eab434c738a1550962313b07098cd"), 32);
hdnode_fill_public_key(&node);
ck_assert_mem_eq(node.public_key + 1, fromhex("75eb8d197ec8627c85af88e66aa1e49065dd8ac98ed8991db52ece01635dfb76"), 32);
}
END_TEST
START_TEST(test_bip32_cardano_hdnode_vector_7)
{
HDNode node;
uint8_t seed[66];
int seed_len = mnemonic_to_entropy("ring crime symptom enough erupt lady behave ramp apart settle citizen junk", seed + 2);
hdnode_from_seed_cardano(seed, seed_len / 8, &node);
hdnode_private_ckd_cardano(&node, 0x80000000);
hdnode_private_ckd_cardano(&node, 0x80000001);
hdnode_private_ckd_cardano(&node, 0x80000002);
hdnode_private_ckd_cardano(&node, 0x80000002);
hdnode_private_ckd_cardano(&node, 0xBB9ACA00);
ck_assert_mem_eq(node.chain_code, fromhex("15c450b86dd7dd83b31951d9ee03eb1a7925161d817bd517c69cf09e3671f1ca"), 32);
ck_assert_mem_eq(node.private_key, fromhex("624b47150f58dfa44284fbc63c9f99b9b79f808c4955a461f0e2be44eb0be50d"), 32);
ck_assert_mem_eq(node.private_key_extension, fromhex("097aa006d694b165ef37cf23562e5967c96e49255d2f20faae478dee83aa5b02"), 32);
hdnode_fill_public_key(&node);
ck_assert_mem_eq(node.public_key + 1, fromhex("0588589cd9b51dfc028cf225674069cbe52e0e70deb02dc45b79b26ee3548b00"), 32);
}
END_TEST
START_TEST(test_ecdsa_signature)
{
int res;
@ -2772,6 +2907,74 @@ START_TEST(test_mnemonic_check)
}
END_TEST
START_TEST(test_mnemonic_to_entropy)
{
static const char *vectors[] = {
"00000000000000000000000000000000",
"abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about",
"7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f",
"legal winner thank year wave sausage worth useful legal winner thank yellow",
"80808080808080808080808080808080",
"letter advice cage absurd amount doctor acoustic avoid letter advice cage above",
"ffffffffffffffffffffffffffffffff",
"zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo wrong",
"000000000000000000000000000000000000000000000000",
"abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon agent",
"7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f",
"legal winner thank year wave sausage worth useful legal winner thank year wave sausage worth useful legal will",
"808080808080808080808080808080808080808080808080",
"letter advice cage absurd amount doctor acoustic avoid letter advice cage absurd amount doctor acoustic avoid letter always",
"ffffffffffffffffffffffffffffffffffffffffffffffff",
"zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo when",
"0000000000000000000000000000000000000000000000000000000000000000",
"abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon art",
"7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f",
"legal winner thank year wave sausage worth useful legal winner thank year wave sausage worth useful legal winner thank year wave sausage worth title",
"8080808080808080808080808080808080808080808080808080808080808080",
"letter advice cage absurd amount doctor acoustic avoid letter advice cage absurd amount doctor acoustic avoid letter advice cage absurd amount doctor acoustic bless",
"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
"zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo vote",
"77c2b00716cec7213839159e404db50d",
"jelly better achieve collect unaware mountain thought cargo oxygen act hood bridge",
"b63a9c59a6e641f288ebc103017f1da9f8290b3da6bdef7b",
"renew stay biology evidence goat welcome casual join adapt armor shuffle fault little machine walk stumble urge swap",
"3e141609b97933b66a060dcddc71fad1d91677db872031e85f4c015c5e7e8982",
"dignity pass list indicate nasty swamp pool script soccer toe leaf photo multiply desk host tomato cradle drill spread actor shine dismiss champion exotic",
"0460ef47585604c5660618db2e6a7e7f",
"afford alter spike radar gate glance object seek swamp infant panel yellow",
"72f60ebac5dd8add8d2a25a797102c3ce21bc029c200076f",
"indicate race push merry suffer human cruise dwarf pole review arch keep canvas theme poem divorce alter left",
"2c85efc7f24ee4573d2b81a6ec66cee209b2dcbd09d8eddc51e0215b0b68e416",
"clutch control vehicle tonight unusual clog visa ice plunge glimpse recipe series open hour vintage deposit universe tip job dress radar refuse motion taste",
"eaebabb2383351fd31d703840b32e9e2",
"turtle front uncle idea crush write shrug there lottery flower risk shell",
"7ac45cfe7722ee6c7ba84fbc2d5bd61b45cb2fe5eb65aa78",
"kiss carry display unusual confirm curtain upgrade antique rotate hello void custom frequent obey nut hole price segment",
"4fa1a8bc3e6d80ee1316050e862c1812031493212b7ec3f3bb1b08f168cabeef",
"exile ask congress lamp submit jacket era scheme attend cousin alcohol catch course end lucky hurt sentence oven short ball bird grab wing top",
"18ab19a9f54a9274f03e5209a2ac8a91",
"board flee heavy tunnel powder denial science ski answer betray cargo cat",
"18a2e1d81b8ecfb2a333adcb0c17a5b9eb76cc5d05db91a4",
"board blade invite damage undo sun mimic interest slam gaze truly inherit resist great inject rocket museum chief",
"15da872c95a13dd738fbf50e427583ad61f18fd99f628c417a61cf8343c90419",
"beyond stage sleep clip because twist token leaf atom beauty genius food business side grid unable middle armed observe pair crouch tonight away coconut",
0,
0,
};
const char **a, **b;
uint8_t entropy[64];
a = vectors;
b = vectors + 1;
while (*a && *b) {
mnemonic_to_entropy(*b,entropy);
ck_assert_mem_eq(entropy, fromhex(*a), strlen(*a) / 2);
a += 2; b += 2;
}
}
END_TEST
START_TEST(test_address)
{
char address[36];
@ -3607,6 +3810,81 @@ START_TEST(test_ge25519_double_scalarmult_vartime2)
}
END_TEST
// https://github.com/input-output-hk/cardano-crypto/blob/master/tests/goldens/cardano/crypto/wallet/BIP39-128
START_TEST(test_ed25519_cardano_sign_vectors)
{
ed25519_public_key public_key;
ed25519_secret_key secret_key;
ed25519_secret_key secret_key_extension;
ed25519_signature signature;
static const char *vectors[] = {
"6065a956b1b34145c4416fdc3ba3276801850e91a77a31a7be782463288aea53", // private key
"60ba6e25b1a02157fb69c5d1d7b96c4619736e545447069a6a6f0ba90844bc8e", // private key extension
"64b20fa082b3143d6b5eed42c6ef63f99599d0888afe060620abc1b319935fe1", // public key
"45b1a75fe3119e13c6f60ab9ba674b42f946fdc558e07c83dfa0751c2eba69c79331bd8a4a975662b23628a438a0eba76367e44c12ca91b39ec59063f860f10d", // signature
"e7d27516538403a53a8b041656a3f570909df641a0ab811fe7d87c9ba02a830c", // private key
"794a2c54ad8b525b781773c87d38cbf4197636bc427a9d551368286fe4c294a4", // private key extension
"95bb82ffd5707716bc65170ab4e8dafeed90fbe0ce9258713b7751e962d931df", // public key
"f2c9171782e7df7665126ac545ae53b05964b0160536efdb545e2460dbbec2b19ec6b338b8f1bf4dfee94360ed024b115e37b1d7e6f3f9ae4beb79539428560f", // signature
"9b5a3d9a4c60bcd49bb64b72c082b164314d0f61d842f2575fd1d4fb30a28a0c", // private key
"b093e376f41eb7bf80abcd0073a52455d25b5d21815bc758e5f6f81536aedebb", // private key extension
"79fc8154554b97e4c56ef2f9dbb4c1421ff19509688931a1e964bda5dec0f19f", // public key
"2ba1439ae648a7e8da7c9ab1ee6da94fd4ebe37abd0978306e8fba2afa8f111a88a993dbf008bedae9167f4f68409e4c9ddaf02cba12418447b1848907ad800f", // signature
"52e0c98aa600cfdcd1ff28fcda5227ed87063f4a98547a78b771052cf102b40c", // private key
"6c18d9f8075b1a6a1833540607479bd58b7beb8a83d2bb01ca7ae02452a25803", // private key extension
"dc907c7c06e6314eedd9e18c9f6c6f9cc4e205fb1c70da608234c319f1f7b0d6", // public key
"0cd34f84e0d2fcb1800bdb0e869b9041349955ced66aedbe6bda187ebe8d36a62a05b39647e92fcc42aa7a7368174240afba08b8c81f981a22f942d6bd781602", // signature
"11fd6462a3a92b35c22703f6f1c124ddcf36b7c2b09cc2784f320e1cfa12ec04", // private key
"c2785803c61c46aeca192a1bb1b7b20a8c4cc7fa01db57fc5d1d8a5473402352", // private key extension
"839775a41876e328986aa26168958bba1176e67819b357eea84afceab8b1db78", // public key
"e41f73db2f8d2896a687802b2be76b7cabb73dfbb4891494883a0cbd9bbb9e5f9d3e14d2d0b06c6674333508496db660936737c0efd9511514147dac79fa4905", // signature
"5b1e5cad02274ba461f4708d8598d3497faf8fe3e894a379573aa6ac3a03e505", // private key
"ba179d2e3c67aabb486c48d16002b51ad32eab434c738a1550962313b07098cd", // private key extension
"75eb8d197ec8627c85af88e66aa1e49065dd8ac98ed8991db52ece01635dfb76", // public key
"631015357cee3051116b4c2ff4d1c5beb13b6e5023635aa1eeb0563cadf0d4fbc10bd5e31b4a4220c67875558c41b5cc0328104ae39cc7ff20ff0c2bda598906", // signature
"624b47150f58dfa44284fbc63c9f99b9b79f808c4955a461f0e2be44eb0be50d", // private key
"097aa006d694b165ef37cf23562e5967c96e49255d2f20faae478dee83aa5b02", // private key extension
"0588589cd9b51dfc028cf225674069cbe52e0e70deb02dc45b79b26ee3548b00", // public key
"1de1d275428ba9491a433cd473cd076c027f61e7a8b5391df9dea5cb4bc88d8a57b095906a30b13e68259851a8dd3f57b6f0ffa37a5d3ffc171240f2d404f901", // signature
0, 0,
};
const char **test_data;
test_data = vectors;
while (*test_data) {
memcpy(secret_key, fromhex(*test_data), 32);
MARK_SECRET_DATA(secret_key, sizeof(secret_key));
memcpy(secret_key_extension, fromhex(*(test_data + 1)), 32);
MARK_SECRET_DATA(secret_key_extension, sizeof(secret_key_extension));
ed25519_publickey_ext(secret_key, secret_key_extension, public_key);
UNMARK_SECRET_DATA(public_key, sizeof(public_key));
ck_assert_mem_eq(public_key, fromhex(*(test_data + 2)), 32);
const uint8_t * message = (const uint8_t *) "Hello World";
ed25519_sign_ext(message, 11, secret_key, secret_key_extension, public_key, signature);
UNMARK_SECRET_DATA(signature, sizeof(signature));
ck_assert_mem_eq(signature, fromhex(*(test_data + 3)), 64);
UNMARK_SECRET_DATA(secret_key, sizeof(secret_key));
UNMARK_SECRET_DATA(secret_key_extension, sizeof(secret_key_extension));
test_data += 4;
}
}
END_TEST
static void test_bip32_ecdh_init_node(HDNode *node, const char *seed_str, const char *curve_name) {
hdnode_from_seed((const uint8_t *)seed_str, strlen(seed_str), curve_name, node);
hdnode_fill_public_key(node);
@ -4762,6 +5040,16 @@ Suite *test_suite(void)
tcase_add_test(tc, test_bip32_decred_vector_2);
suite_add_tcase(s, tc);
tc = tcase_create("bip32-cardano");
tcase_add_test(tc, test_bip32_cardano_hdnode_vector_1);
tcase_add_test(tc, test_bip32_cardano_hdnode_vector_2);
tcase_add_test(tc, test_bip32_cardano_hdnode_vector_3);
tcase_add_test(tc, test_bip32_cardano_hdnode_vector_4);
tcase_add_test(tc, test_bip32_cardano_hdnode_vector_5);
tcase_add_test(tc, test_bip32_cardano_hdnode_vector_6);
tcase_add_test(tc, test_bip32_cardano_hdnode_vector_7);
suite_add_tcase(s,tc);
tc = tcase_create("ecdsa");
tcase_add_test(tc, test_ecdsa_signature);
suite_add_tcase(s, tc);
@ -4829,6 +5117,10 @@ Suite *test_suite(void)
tcase_add_test(tc, test_mnemonic_check);
suite_add_tcase(s, tc);
tc = tcase_create("bip39-cardano");
tcase_add_test(tc, test_mnemonic_to_entropy);
suite_add_tcase(s,tc);
tc = tcase_create("pubkey_validity");
tcase_add_test(tc, test_pubkey_validity);
suite_add_tcase(s, tc);
@ -4884,6 +5176,10 @@ Suite *test_suite(void)
tcase_add_test(tc, test_ge25519_double_scalarmult_vartime2);
suite_add_tcase(s, tc);
tc = tcase_create("ed25519-cardano");
tcase_add_test(tc, test_ed25519_cardano_sign_vectors);
suite_add_tcase(s,tc);
tc = tcase_create("script");
tcase_add_test(tc, test_output_script);
suite_add_tcase(s, tc);

Loading…
Cancel
Save