format: start using clang-format with style=Google

pull/25/head
Pavol Rusnak 5 years ago
parent 8434b2468c
commit 0c622d62e1
No known key found for this signature in database
GPG Key ID: 91F3B339B9A02A3D

@ -0,0 +1,2 @@
---
BasedOnStyle: Google

@ -24,66 +24,68 @@
#include "address.h"
#include "bignum.h"
size_t address_prefix_bytes_len(uint32_t address_type)
{
if (address_type <= 0xFF) return 1;
if (address_type <= 0xFFFF) return 2;
if (address_type <= 0xFFFFFF) return 3;
return 4;
size_t address_prefix_bytes_len(uint32_t address_type) {
if (address_type <= 0xFF) return 1;
if (address_type <= 0xFFFF) return 2;
if (address_type <= 0xFFFFFF) return 3;
return 4;
}
void address_write_prefix_bytes(uint32_t address_type, uint8_t *out)
{
if (address_type > 0xFFFFFF) *(out++) = address_type >> 24;
if (address_type > 0xFFFF) *(out++) = (address_type >> 16) & 0xFF;
if (address_type > 0xFF) *(out++) = (address_type >> 8) & 0xFF;
*(out++) = address_type & 0xFF;
void address_write_prefix_bytes(uint32_t address_type, uint8_t *out) {
if (address_type > 0xFFFFFF) *(out++) = address_type >> 24;
if (address_type > 0xFFFF) *(out++) = (address_type >> 16) & 0xFF;
if (address_type > 0xFF) *(out++) = (address_type >> 8) & 0xFF;
*(out++) = address_type & 0xFF;
}
bool address_check_prefix(const uint8_t *addr, uint32_t address_type)
{
if (address_type <= 0xFF) {
return address_type == (uint32_t)(addr[0]);
}
if (address_type <= 0xFFFF) {
return address_type == (((uint32_t) addr[0] << 8) | ((uint32_t) addr[1]));
}
if (address_type <= 0xFFFFFF) {
return address_type == (((uint32_t) addr[0] << 16) | ((uint32_t) addr[1] << 8) | ((uint32_t) addr[2]));
}
return address_type == (((uint32_t) addr[0] << 24) | ((uint32_t) addr[1] << 16) | ((uint32_t) addr[2] << 8) | ((uint32_t) addr[3]));
bool address_check_prefix(const uint8_t *addr, uint32_t address_type) {
if (address_type <= 0xFF) {
return address_type == (uint32_t)(addr[0]);
}
if (address_type <= 0xFFFF) {
return address_type == (((uint32_t)addr[0] << 8) | ((uint32_t)addr[1]));
}
if (address_type <= 0xFFFFFF) {
return address_type == (((uint32_t)addr[0] << 16) |
((uint32_t)addr[1] << 8) | ((uint32_t)addr[2]));
}
return address_type ==
(((uint32_t)addr[0] << 24) | ((uint32_t)addr[1] << 16) |
((uint32_t)addr[2] << 8) | ((uint32_t)addr[3]));
}
#if USE_ETHEREUM
#include "sha3.h"
void ethereum_address_checksum(const uint8_t *addr, char *address, bool rskip60, uint32_t chain_id)
{
const char *hex = "0123456789abcdef";
for (int i = 0; i < 20; i++) {
address[i * 2] = hex[(addr[i] >> 4) & 0xF];
address[i * 2 + 1] = hex[addr[i] & 0xF];
}
address[40] = 0;
void ethereum_address_checksum(const uint8_t *addr, char *address, bool rskip60,
uint32_t chain_id) {
const char *hex = "0123456789abcdef";
for (int i = 0; i < 20; i++) {
address[i * 2] = hex[(addr[i] >> 4) & 0xF];
address[i * 2 + 1] = hex[addr[i] & 0xF];
}
address[40] = 0;
SHA3_CTX ctx;
uint8_t hash[32];
keccak_256_Init(&ctx);
if (rskip60) {
char prefix[16];
int prefix_size = bn_format_uint64(chain_id, NULL, "0x", 0, 0, false, prefix, sizeof(prefix));
keccak_Update(&ctx, (const uint8_t *)prefix, prefix_size);
}
keccak_Update(&ctx, (const uint8_t *)address, 40);
keccak_Final(&ctx, hash);
SHA3_CTX ctx;
uint8_t hash[32];
keccak_256_Init(&ctx);
if (rskip60) {
char prefix[16];
int prefix_size = bn_format_uint64(chain_id, NULL, "0x", 0, 0, false,
prefix, sizeof(prefix));
keccak_Update(&ctx, (const uint8_t *)prefix, prefix_size);
}
keccak_Update(&ctx, (const uint8_t *)address, 40);
keccak_Final(&ctx, hash);
for (int i = 0; i < 20; i++) {
if (hash[i] & 0x80 && address[i * 2 ] >= 'a' && address[i * 2 ] <= 'f') {
address[i * 2] -= 0x20;
}
if (hash[i] & 0x08 && address[i * 2 + 1] >= 'a' && address[i * 2 + 1] <= 'f') {
address[i * 2 + 1] -= 0x20;
}
}
for (int i = 0; i < 20; i++) {
if (hash[i] & 0x80 && address[i * 2] >= 'a' && address[i * 2] <= 'f') {
address[i * 2] -= 0x20;
}
if (hash[i] & 0x08 && address[i * 2 + 1] >= 'a' &&
address[i * 2 + 1] <= 'f') {
address[i * 2 + 1] -= 0x20;
}
}
}
#endif

@ -24,16 +24,17 @@
#ifndef __ADDRESS_H__
#define __ADDRESS_H__
#include <stdint.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include "options.h"
size_t address_prefix_bytes_len(uint32_t address_type);
void address_write_prefix_bytes(uint32_t address_type, uint8_t *out);
bool address_check_prefix(const uint8_t *addr, uint32_t address_type);
#if USE_ETHEREUM
void ethereum_address_checksum(const uint8_t *addr, char *address, bool rskip60, uint32_t chain_id);
void ethereum_address_checksum(const uint8_t *addr, char *address, bool rskip60,
uint32_t chain_id);
#endif
#endif

@ -27,207 +27,214 @@
const char *BASE32_ALPHABET_RFC4648 = "ABCDEFGHIJKLMNOPQRSTUVWXYZ23456789";
static inline void base32_5to8(const uint8_t *in, uint8_t length, uint8_t *out);
static inline bool base32_8to5(const uint8_t *in, uint8_t length, uint8_t *out, const char *alphabet);
static inline void base32_8to5_raw(const uint8_t *in, uint8_t length, uint8_t *out);
static inline bool base32_8to5(const uint8_t *in, uint8_t length, uint8_t *out,
const char *alphabet);
static inline void base32_8to5_raw(const uint8_t *in, uint8_t length,
uint8_t *out);
static inline int base32_encode_character(uint8_t decoded, const char *alphabet);
static inline int base32_encode_character(uint8_t decoded,
const char *alphabet);
static inline int base32_decode_character(char encoded, const char *alphabet);
char *base32_encode(const uint8_t *in, size_t inlen, char *out, size_t outlen, const char *alphabet) {
size_t length = base32_encoded_length(inlen);
if (outlen <= length) {
return NULL;
}
char *base32_encode(const uint8_t *in, size_t inlen, char *out, size_t outlen,
const char *alphabet) {
size_t length = base32_encoded_length(inlen);
if (outlen <= length) {
return NULL;
}
base32_encode_unsafe(in, inlen, (uint8_t *) out);
base32_encode_unsafe(in, inlen, (uint8_t *)out);
for (size_t i = 0; i < length; i++) {
int ret = base32_encode_character(out[i], alphabet);
for (size_t i = 0; i < length; i++) {
int ret = base32_encode_character(out[i], alphabet);
if (ret == -1) {
return false;
} else {
out[i] = ret;
}
}
if (ret == -1) {
return false;
} else {
out[i] = ret;
}
}
out[length] = '\0';
return &out[length];
out[length] = '\0';
return &out[length];
}
uint8_t *base32_decode(const char *in, size_t inlen, uint8_t *out, size_t outlen, const char *alphabet) {
size_t length = base32_decoded_length(inlen);
if (outlen < length) {
return NULL;
}
uint8_t *base32_decode(const char *in, size_t inlen, uint8_t *out,
size_t outlen, const char *alphabet) {
size_t length = base32_decoded_length(inlen);
if (outlen < length) {
return NULL;
}
if (!base32_decode_unsafe((uint8_t *) in, inlen, (uint8_t *) out, alphabet)) {
return NULL;
}
if (!base32_decode_unsafe((uint8_t *)in, inlen, (uint8_t *)out, alphabet)) {
return NULL;
}
return &out[length];
return &out[length];
}
void base32_encode_unsafe(const uint8_t *in, size_t inlen, uint8_t *out) {
uint8_t remainder = inlen % 5;
size_t limit = inlen - remainder;
uint8_t remainder = inlen % 5;
size_t limit = inlen - remainder;
size_t i, j;
for (i = 0, j = 0; i < limit; i += 5, j += 8) {
base32_5to8(&in[i], 5, &out[j]);
}
size_t i, j;
for (i = 0, j = 0; i < limit; i += 5, j += 8) {
base32_5to8(&in[i], 5, &out[j]);
}
if (remainder) base32_5to8(&in[i], remainder, &out[j]);
if (remainder) base32_5to8(&in[i], remainder, &out[j]);
}
bool base32_decode_unsafe(const uint8_t *in, size_t inlen, uint8_t *out, const char *alphabet) {
uint8_t remainder = inlen % 8;
size_t limit = inlen - remainder;
bool base32_decode_unsafe(const uint8_t *in, size_t inlen, uint8_t *out,
const char *alphabet) {
uint8_t remainder = inlen % 8;
size_t limit = inlen - remainder;
size_t i, j;
for (i = 0, j = 0; i < limit; i += 8, j += 5) {
if (!base32_8to5(&in[i], 8, &out[j], alphabet)) {
return false;
}
}
size_t i, j;
for (i = 0, j = 0; i < limit; i += 8, j += 5) {
if (!base32_8to5(&in[i], 8, &out[j], alphabet)) {
return false;
}
}
if (remainder && !base32_8to5(&in[i], remainder, &out[j], alphabet)) {
return false;
}
if (remainder && !base32_8to5(&in[i], remainder, &out[j], alphabet)) {
return false;
}
return true;
return true;
}
size_t base32_encoded_length(size_t inlen) {
uint8_t remainder = inlen % 5;
uint8_t remainder = inlen % 5;
return (inlen / 5) * 8 + (remainder * 8 + 4) / 5;
return (inlen / 5) * 8 + (remainder * 8 + 4) / 5;
}
size_t base32_decoded_length(size_t inlen) {
uint8_t remainder = inlen % 8;
uint8_t remainder = inlen % 8;
return (inlen / 8) * 5 + (remainder * 5) / 8;
return (inlen / 8) * 5 + (remainder * 5) / 8;
}
void base32_5to8(const uint8_t *in, uint8_t length, uint8_t *out) {
if (length >= 1) {
out[0] = (in[0] >> 3);
out[1] = (in[0] & 7) << 2;
}
if (length >= 2) {
out[1] |= (in[1] >> 6);
out[2] = (in[1] >> 1) & 31;
out[3] = (in[1] & 1) << 4;
}
if (length >= 3) {
out[3] |= (in[2] >> 4);
out[4] = (in[2] & 15) << 1;
}
if (length >= 4) {
out[4] |= (in[3] >> 7);
out[5] = (in[3] >> 2) & 31;
out[6] = (in[3] & 3) << 3;
}
if (length >= 5) {
out[6] |= (in[4] >> 5);
out[7] = (in[4] & 31);
}
if (length >= 1) {
out[0] = (in[0] >> 3);
out[1] = (in[0] & 7) << 2;
}
if (length >= 2) {
out[1] |= (in[1] >> 6);
out[2] = (in[1] >> 1) & 31;
out[3] = (in[1] & 1) << 4;
}
if (length >= 3) {
out[3] |= (in[2] >> 4);
out[4] = (in[2] & 15) << 1;
}
if (length >= 4) {
out[4] |= (in[3] >> 7);
out[5] = (in[3] >> 2) & 31;
out[6] = (in[3] & 3) << 3;
}
if (length >= 5) {
out[6] |= (in[4] >> 5);
out[7] = (in[4] & 31);
}
}
bool base32_8to5(const uint8_t *in, uint8_t length, uint8_t *out, const char *alphabet) {
if (length == 1 || length == 3 || length == 6 || length > 8) {
return false;
}
bool base32_8to5(const uint8_t *in, uint8_t length, uint8_t *out,
const char *alphabet) {
if (length == 1 || length == 3 || length == 6 || length > 8) {
return false;
}
if (alphabet) {
uint8_t decoded[length];
if (alphabet) {
uint8_t decoded[length];
for (size_t i = 0; i < length; i++) {
int ret = base32_decode_character(in[i], alphabet);
for (size_t i = 0; i < length; i++) {
int ret = base32_decode_character(in[i], alphabet);
if (ret == -1) {
return false;
} else {
decoded[i] = ret;
}
}
if (ret == -1) {
return false;
} else {
decoded[i] = ret;
}
}
base32_8to5_raw(decoded, length, out);
} else {
base32_8to5_raw(in, length, out);
}
base32_8to5_raw(decoded, length, out);
} else {
base32_8to5_raw(in, length, out);
}
return true;
return true;
}
void base32_8to5_raw(const uint8_t *in, uint8_t length, uint8_t *out) {
if (length >= 2) {
out[0] = (in[0] << 3);
out[0] |= (in[1] >> 2);
}
if (length >= 4) {
out[1] = (in[1] & 3) << 6;
out[1] |= (in[2] << 1);
out[1] |= (in[3] >> 4);
}
if (length >= 5) {
out[2] = (in[3] & 15) << 4;
out[2] |= (in[4] >> 1);
}
if (length >= 7) {
out[3] = (in[4] & 1) << 7;
out[3] |= (in[5] << 2);
out[3] |= (in[6] >> 3);
}
if (length >= 8) {
out[4] = (in[6] & 7) << 5;
out[4] |= (in[7] & 31);
}
if (length >= 2) {
out[0] = (in[0] << 3);
out[0] |= (in[1] >> 2);
}
if (length >= 4) {
out[1] = (in[1] & 3) << 6;
out[1] |= (in[2] << 1);
out[1] |= (in[3] >> 4);
}
if (length >= 5) {
out[2] = (in[3] & 15) << 4;
out[2] |= (in[4] >> 1);
}
if (length >= 7) {
out[3] = (in[4] & 1) << 7;
out[3] |= (in[5] << 2);
out[3] |= (in[6] >> 3);
}
if (length >= 8) {
out[4] = (in[6] & 7) << 5;
out[4] |= (in[7] & 31);
}
}
int base32_encode_character(uint8_t decoded, const char *alphabet) {
if (decoded >> 5) {
return -1;
}
if (alphabet == BASE32_ALPHABET_RFC4648) {
if (decoded < 26) {
return 'A' + decoded;
} else {
return '2' - 26 + decoded;
}
}
return alphabet[decoded];
if (decoded >> 5) {
return -1;
}
if (alphabet == BASE32_ALPHABET_RFC4648) {
if (decoded < 26) {
return 'A' + decoded;
} else {
return '2' - 26 + decoded;
}
}
return alphabet[decoded];
}
int base32_decode_character(char encoded, const char *alphabet) {
if (alphabet == BASE32_ALPHABET_RFC4648) {
if (encoded >= 'A' && encoded <= 'Z') {
return encoded - 'A';
} else if (encoded >= 'a' && encoded <= 'z') {
return encoded - 'a';
} else if (encoded >= '2' && encoded <= '7') {
return encoded - '2' + 26;
} else {
return -1;
}
}
const char *occurrence = strchr(alphabet, encoded);
if (occurrence) {
return occurrence - alphabet;
} else {
return -1;
}
if (alphabet == BASE32_ALPHABET_RFC4648) {
if (encoded >= 'A' && encoded <= 'Z') {
return encoded - 'A';
} else if (encoded >= 'a' && encoded <= 'z') {
return encoded - 'a';
} else if (encoded >= '2' && encoded <= '7') {
return encoded - '2' + 26;
} else {
return -1;
}
}
const char *occurrence = strchr(alphabet, encoded);
if (occurrence) {
return occurrence - alphabet;
} else {
return -1;
}
}

@ -29,11 +29,14 @@
extern const char *BASE32_ALPHABET_RFC4648;
char *base32_encode(const uint8_t *in, size_t inlen, char *out, size_t outlen, const char *alphabet);
char *base32_encode(const uint8_t *in, size_t inlen, char *out, size_t outlen,
const char *alphabet);
void base32_encode_unsafe(const uint8_t *in, size_t inlen, uint8_t *out);
uint8_t *base32_decode(const char *in, size_t inlen, uint8_t *out, size_t outlen, const char *alphabet);
bool base32_decode_unsafe(const uint8_t *in, size_t inlen, uint8_t *out, const char *alphabet);
uint8_t *base32_decode(const char *in, size_t inlen, uint8_t *out,
size_t outlen, const char *alphabet);
bool base32_decode_unsafe(const uint8_t *in, size_t inlen, uint8_t *out,
const char *alphabet);
size_t base32_encoded_length(size_t inlen);
size_t base32_decoded_length(size_t inlen);

@ -21,265 +21,248 @@
* OTHER DEALINGS IN THE SOFTWARE.
*/
#include <string.h>
#include "base58.h"
#include <stdbool.h>
#include <string.h>
#include <sys/types.h>
#include "base58.h"
#include "sha2.h"
#include "ripemd160.h"
#include "memzero.h"
#include "ripemd160.h"
#include "sha2.h"
const char b58digits_ordered[] = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";
const char b58digits_ordered[] =
"123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";
const int8_t b58digits_map[] = {
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1, 0, 1, 2, 3, 4, 5, 6, 7, 8,-1,-1,-1,-1,-1,-1,
-1, 9,10,11,12,13,14,15,16,-1,17,18,19,20,21,-1,
22,23,24,25,26,27,28,29,30,31,32,-1,-1,-1,-1,-1,
-1,33,34,35,36,37,38,39,40,41,42,43,-1,44,45,46,
47,48,49,50,51,52,53,54,55,56,57,-1,-1,-1,-1,-1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, 1, 2, 3, 4, 5, 6, 7,
8, -1, -1, -1, -1, -1, -1, -1, 9, 10, 11, 12, 13, 14, 15, 16, -1, 17, 18,
19, 20, 21, -1, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, -1, -1, -1, -1,
-1, -1, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, -1, 44, 45, 46, 47, 48,
49, 50, 51, 52, 53, 54, 55, 56, 57, -1, -1, -1, -1, -1,
};
bool b58tobin(void *bin, size_t *binszp, const char *b58)
{
size_t binsz = *binszp;
bool b58tobin(void *bin, size_t *binszp, const char *b58) {
size_t binsz = *binszp;
if (binsz == 0) {
return false;
}
if (binsz == 0) {
return false;
}
const unsigned char *b58u = (const unsigned char*)b58;
unsigned char *binu = bin;
size_t outisz = (binsz + 3) / 4;
uint32_t outi[outisz];
uint64_t t;
uint32_t c;
size_t i, j;
uint8_t bytesleft = binsz % 4;
uint32_t zeromask = bytesleft ? (0xffffffff << (bytesleft * 8)) : 0;
unsigned zerocount = 0;
size_t b58sz;
const unsigned char *b58u = (const unsigned char *)b58;
unsigned char *binu = bin;
size_t outisz = (binsz + 3) / 4;
uint32_t outi[outisz];
uint64_t t;
uint32_t c;
size_t i, j;
uint8_t bytesleft = binsz % 4;
uint32_t zeromask = bytesleft ? (0xffffffff << (bytesleft * 8)) : 0;
unsigned zerocount = 0;
size_t b58sz;
b58sz = strlen(b58);
b58sz = strlen(b58);
memzero(outi, sizeof(outi));
memzero(outi, sizeof(outi));
// Leading zeros, just count
for (i = 0; i < b58sz && b58u[i] == '1'; ++i)
++zerocount;
// Leading zeros, just count
for (i = 0; i < b58sz && b58u[i] == '1'; ++i) ++zerocount;
for ( ; i < b58sz; ++i)
{
if (b58u[i] & 0x80)
// High-bit set on invalid digit
return false;
if (b58digits_map[b58u[i]] == -1)
// Invalid base58 digit
return false;
c = (unsigned)b58digits_map[b58u[i]];
for (j = outisz; j--; )
{
t = ((uint64_t)outi[j]) * 58 + c;
c = (t & 0x3f00000000) >> 32;
outi[j] = t & 0xffffffff;
}
if (c)
// Output number too big (carry to the next int32)
return false;
if (outi[0] & zeromask)
// Output number too big (last int32 filled too far)
return false;
}
for (; i < b58sz; ++i) {
if (b58u[i] & 0x80)
// High-bit set on invalid digit
return false;
if (b58digits_map[b58u[i]] == -1)
// Invalid base58 digit
return false;
c = (unsigned)b58digits_map[b58u[i]];
for (j = outisz; j--;) {
t = ((uint64_t)outi[j]) * 58 + c;
c = (t & 0x3f00000000) >> 32;
outi[j] = t & 0xffffffff;
}
if (c)
// Output number too big (carry to the next int32)
return false;
if (outi[0] & zeromask)
// Output number too big (last int32 filled too far)
return false;
}
j = 0;
switch (bytesleft) {
case 3:
*(binu++) = (outi[0] & 0xff0000) >> 16;
//-fallthrough
case 2:
*(binu++) = (outi[0] & 0xff00) >> 8;
//-fallthrough
case 1:
*(binu++) = (outi[0] & 0xff);
++j;
//-fallthrough
default:
break;
}
j = 0;
switch (bytesleft) {
case 3:
*(binu++) = (outi[0] & 0xff0000) >> 16;
//-fallthrough
case 2:
*(binu++) = (outi[0] & 0xff00) >> 8;
//-fallthrough
case 1:
*(binu++) = (outi[0] & 0xff);
++j;
//-fallthrough
default:
break;
}
for (; j < outisz; ++j)
{
*(binu++) = (outi[j] >> 0x18) & 0xff;
*(binu++) = (outi[j] >> 0x10) & 0xff;
*(binu++) = (outi[j] >> 8) & 0xff;
*(binu++) = (outi[j] >> 0) & 0xff;
}
for (; j < outisz; ++j) {
*(binu++) = (outi[j] >> 0x18) & 0xff;
*(binu++) = (outi[j] >> 0x10) & 0xff;
*(binu++) = (outi[j] >> 8) & 0xff;
*(binu++) = (outi[j] >> 0) & 0xff;
}
// Count canonical base58 byte count
binu = bin;
for (i = 0; i < binsz; ++i)
{
if (binu[i]) {
if (zerocount > i) {
/* result too large */
return false;
}
break;
}
--*binszp;
}
*binszp += zerocount;
// Count canonical base58 byte count
binu = bin;
for (i = 0; i < binsz; ++i) {
if (binu[i]) {
if (zerocount > i) {
/* result too large */
return false;
}
break;
}
--*binszp;
}
*binszp += zerocount;
return true;
return true;
}
int b58check(const void *bin, size_t binsz, HasherType hasher_type, const char *base58str)
{
unsigned char buf[32];
const uint8_t *binc = bin;
unsigned i;
if (binsz < 4)
return -4;
hasher_Raw(hasher_type, bin, binsz - 4, buf);
if (memcmp(&binc[binsz - 4], buf, 4))
return -1;
int b58check(const void *bin, size_t binsz, HasherType hasher_type,
const char *base58str) {
unsigned char buf[32];
const uint8_t *binc = bin;
unsigned i;
if (binsz < 4) return -4;
hasher_Raw(hasher_type, bin, binsz - 4, buf);
if (memcmp(&binc[binsz - 4], buf, 4)) return -1;
// Check number of zeros is correct AFTER verifying checksum (to avoid possibility of accessing base58str beyond the end)
for (i = 0; binc[i] == '\0' && base58str[i] == '1'; ++i)
{} // Just finding the end of zeros, nothing to do in loop
if (binc[i] == '\0' || base58str[i] == '1')
return -3;
// Check number of zeros is correct AFTER verifying checksum (to avoid
// possibility of accessing base58str beyond the end)
for (i = 0; binc[i] == '\0' && base58str[i] == '1'; ++i) {
} // Just finding the end of zeros, nothing to do in loop
if (binc[i] == '\0' || base58str[i] == '1') return -3;
return binc[0];
return binc[0];
}
bool b58enc(char *b58, size_t *b58sz, const void *data, size_t binsz)
{
const uint8_t *bin = data;
int carry;
ssize_t i, j, high, zcount = 0;
size_t size;
bool b58enc(char *b58, size_t *b58sz, const void *data, size_t binsz) {
const uint8_t *bin = data;
int carry;
ssize_t i, j, high, zcount = 0;
size_t size;
while (zcount < (ssize_t)binsz && !bin[zcount])
++zcount;
while (zcount < (ssize_t)binsz && !bin[zcount]) ++zcount;
size = (binsz - zcount) * 138 / 100 + 1;
uint8_t buf[size];
memzero(buf, size);
size = (binsz - zcount) * 138 / 100 + 1;
uint8_t buf[size];
memzero(buf, size);
for (i = zcount, high = size - 1; i < (ssize_t)binsz; ++i, high = j)
{
for (carry = bin[i], j = size - 1; (j > high) || carry; --j)
{
carry += 256 * buf[j];
buf[j] = carry % 58;
carry /= 58;
}
}
for (i = zcount, high = size - 1; i < (ssize_t)binsz; ++i, high = j) {
for (carry = bin[i], j = size - 1; (j > high) || carry; --j) {
carry += 256 * buf[j];
buf[j] = carry % 58;
carry /= 58;
}
}
for (j = 0; j < (ssize_t)size && !buf[j]; ++j);
for (j = 0; j < (ssize_t)size && !buf[j]; ++j)
;
if (*b58sz <= zcount + size - j)
{
*b58sz = zcount + size - j + 1;
return false;
}
if (*b58sz <= zcount + size - j) {
*b58sz = zcount + size - j + 1;
return false;
}
if (zcount)
memset(b58, '1', zcount);
for (i = zcount; j < (ssize_t)size; ++i, ++j)
b58[i] = b58digits_ordered[buf[j]];
b58[i] = '\0';
*b58sz = i + 1;
if (zcount) memset(b58, '1', zcount);
for (i = zcount; j < (ssize_t)size; ++i, ++j)
b58[i] = b58digits_ordered[buf[j]];
b58[i] = '\0';
*b58sz = i + 1;
return true;
return true;
}
int base58_encode_check(const uint8_t *data, int datalen, HasherType hasher_type, char *str, int strsize)
{
if (datalen > 128) {
return 0;
}
uint8_t buf[datalen + 32];
uint8_t *hash = buf + datalen;
memcpy(buf, data, datalen);
hasher_Raw(hasher_type, data, datalen, hash);
size_t res = strsize;
bool success = b58enc(str, &res, buf, datalen + 4);
memzero(buf, sizeof(buf));
return success ? res : 0;
int base58_encode_check(const uint8_t *data, int datalen,
HasherType hasher_type, char *str, int strsize) {
if (datalen > 128) {
return 0;
}
uint8_t buf[datalen + 32];
uint8_t *hash = buf + datalen;
memcpy(buf, data, datalen);
hasher_Raw(hasher_type, data, datalen, hash);
size_t res = strsize;
bool success = b58enc(str, &res, buf, datalen + 4);
memzero(buf, sizeof(buf));
return success ? res : 0;
}
int base58_decode_check(const char *str, HasherType hasher_type, uint8_t *data, int datalen)
{
if (datalen > 128) {
return 0;
}
uint8_t d[datalen + 4];
size_t res = datalen + 4;
if (b58tobin(d, &res, str) != true) {
return 0;
}
uint8_t *nd = d + datalen + 4 - res;
if (b58check(nd, res, hasher_type, str) < 0) {
return 0;
}
memcpy(data, nd, res - 4);
return res - 4;
int base58_decode_check(const char *str, HasherType hasher_type, uint8_t *data,
int datalen) {
if (datalen > 128) {
return 0;
}
uint8_t d[datalen + 4];
size_t res = datalen + 4;
if (b58tobin(d, &res, str) != true) {
return 0;
}
uint8_t *nd = d + datalen + 4 - res;
if (b58check(nd, res, hasher_type, str) < 0) {
return 0;
}
memcpy(data, nd, res - 4);
return res - 4;
}
#if USE_GRAPHENE
int b58gphcheck(const void *bin, size_t binsz, const char *base58str)
{
unsigned char buf[32];
const uint8_t *binc = bin;
unsigned i;
if (binsz < 4)
return -4;
ripemd160(bin, binsz - 4, buf); // No double SHA256, but a single RIPEMD160
if (memcmp(&binc[binsz - 4], buf, 4))
return -1;
int b58gphcheck(const void *bin, size_t binsz, const char *base58str) {
unsigned char buf[32];
const uint8_t *binc = bin;
unsigned i;
if (binsz < 4) return -4;
ripemd160(bin, binsz - 4, buf); // No double SHA256, but a single RIPEMD160
if (memcmp(&binc[binsz - 4], buf, 4)) return -1;
// Check number of zeros is correct AFTER verifying checksum (to avoid possibility of accessing base58str beyond the end)
for (i = 0; binc[i] == '\0' && base58str[i] == '1'; ++i)
{} // Just finding the end of zeros, nothing to do in loop
if (binc[i] == '\0' || base58str[i] == '1')
return -3;
// Check number of zeros is correct AFTER verifying checksum (to avoid
// possibility of accessing base58str beyond the end)
for (i = 0; binc[i] == '\0' && base58str[i] == '1'; ++i) {
} // Just finding the end of zeros, nothing to do in loop
if (binc[i] == '\0' || base58str[i] == '1') return -3;
return binc[0];
return binc[0];
}
int base58gph_encode_check(const uint8_t *data, int datalen, char *str, int strsize)
{
if (datalen > 128) {
return 0;
}
uint8_t buf[datalen + 32];
uint8_t *hash = buf + datalen;
memcpy(buf, data, datalen);
ripemd160(data, datalen, hash); // No double SHA256, but a single RIPEMD160
size_t res = strsize;
bool success = b58enc(str, &res, buf, datalen + 4);
memzero(buf, sizeof(buf));
return success ? res : 0;
int base58gph_encode_check(const uint8_t *data, int datalen, char *str,
int strsize) {
if (datalen > 128) {
return 0;
}
uint8_t buf[datalen + 32];
uint8_t *hash = buf + datalen;
memcpy(buf, data, datalen);
ripemd160(data, datalen, hash); // No double SHA256, but a single RIPEMD160
size_t res = strsize;
bool success = b58enc(str, &res, buf, datalen + 4);
memzero(buf, sizeof(buf));
return success ? res : 0;
}
int base58gph_decode_check(const char *str, uint8_t *data, int datalen)
{
if (datalen > 128) {
return 0;
}
uint8_t d[datalen + 4];
size_t res = datalen + 4;
if (b58tobin(d, &res, str) != true) {
return 0;
}
uint8_t *nd = d + datalen + 4 - res;
if (b58gphcheck(nd, res, str) < 0) {
return 0;
}
memcpy(data, nd, res - 4);
return res - 4;
int base58gph_decode_check(const char *str, uint8_t *data, int datalen) {
if (datalen > 128) {
return 0;
}
uint8_t d[datalen + 4];
size_t res = datalen + 4;
if (b58tobin(d, &res, str) != true) {
return 0;
}
uint8_t *nd = d + datalen + 4 - res;
if (b58gphcheck(nd, res, str) < 0) {
return 0;
}
memcpy(data, nd, res - 4);
return res - 4;
}
#endif

@ -24,24 +24,28 @@
#ifndef __BASE58_H__
#define __BASE58_H__
#include <stdint.h>
#include <stdbool.h>
#include <stdint.h>
#include "hasher.h"
#include "options.h"
extern const char b58digits_ordered[];
extern const int8_t b58digits_map[];
int base58_encode_check(const uint8_t *data, int len, HasherType hasher_type, char *str, int strsize);
int base58_decode_check(const char *str, HasherType hasher_type, uint8_t *data, int datalen);
int base58_encode_check(const uint8_t *data, int len, HasherType hasher_type,
char *str, int strsize);
int base58_decode_check(const char *str, HasherType hasher_type, uint8_t *data,
int datalen);
// Private
bool b58tobin(void *bin, size_t *binszp, const char *b58);
int b58check(const void *bin, size_t binsz, HasherType hasher_type, const char *base58str);
int b58check(const void *bin, size_t binsz, HasherType hasher_type,
const char *base58str);
bool b58enc(char *b58, size_t *b58sz, const void *data, size_t binsz);
#if USE_GRAPHENE
int base58gph_encode_check(const uint8_t *data, int datalen, char *str, int strsize);
int base58gph_encode_check(const uint8_t *data, int datalen, char *str,
int strsize);
int base58gph_decode_check(const char *str, uint8_t *data, int datalen);
int b58gphcheck(const void *bin, size_t binsz, const char *base58str);
#endif

1696
bignum.c

File diff suppressed because it is too large Load Diff

@ -33,7 +33,7 @@
// bignum256 are 256 bits stored as 8*30 bit + 1*16 bit
// val[0] are lowest 30 bits, val[8] highest 16 bits
typedef struct {
uint32_t val[9];
uint32_t val[9];
} bignum256;
// read 4 big endian bytes into uint32
@ -60,26 +60,22 @@ void bn_read_uint32(uint32_t in_number, bignum256 *out_number);
void bn_read_uint64(uint64_t in_number, bignum256 *out_number);
static inline uint32_t bn_write_uint32(const bignum256 *in_number)
{
return in_number->val[0] | (in_number->val[1] << 30);
static inline uint32_t bn_write_uint32(const bignum256 *in_number) {
return in_number->val[0] | (in_number->val[1] << 30);
}
static inline uint64_t bn_write_uint64(const bignum256 *in_number)
{
uint64_t tmp;
tmp = in_number->val[2];
tmp <<= 30;
tmp |= in_number->val[1];
tmp <<= 30;
tmp |= in_number->val[0];
return tmp;
static inline uint64_t bn_write_uint64(const bignum256 *in_number) {
uint64_t tmp;
tmp = in_number->val[2];
tmp <<= 30;
tmp |= in_number->val[1];
tmp <<= 30;
tmp |= in_number->val[0];
return tmp;
}
// copies number a to b
static inline void bn_copy(const bignum256 *a, bignum256 *b) {
*b = *a;
}
static inline void bn_copy(const bignum256 *a, bignum256 *b) { *b = *a; }
int bn_bitcount(const bignum256 *a);
@ -92,18 +88,17 @@ int bn_is_zero(const bignum256 *a);
void bn_one(bignum256 *a);
static inline int bn_is_even(const bignum256 *a) {
return (a->val[0] & 1) == 0;
return (a->val[0] & 1) == 0;
}
static inline int bn_is_odd(const bignum256 *a) {
return (a->val[0] & 1) == 1;
}
static inline int bn_is_odd(const bignum256 *a) { return (a->val[0] & 1) == 1; }
int bn_is_less(const bignum256 *a, const bignum256 *b);
int bn_is_equal(const bignum256 *a, const bignum256 *b);
void bn_cmov(bignum256 *res, int cond, const bignum256 *truecase, const bignum256 *falsecase);
void bn_cmov(bignum256 *res, int cond, const bignum256 *truecase,
const bignum256 *falsecase);
void bn_lshift(bignum256 *a);
@ -141,7 +136,8 @@ void bn_addi(bignum256 *a, uint32_t b);
void bn_subi(bignum256 *a, uint32_t b, const bignum256 *prime);
void bn_subtractmod(const bignum256 *a, const bignum256 *b, bignum256 *res, const bignum256 *prime);
void bn_subtractmod(const bignum256 *a, const bignum256 *b, bignum256 *res,
const bignum256 *prime);
void bn_subtract(const bignum256 *a, const bignum256 *b, bignum256 *res);
@ -149,14 +145,19 @@ void bn_divmod58(bignum256 *a, uint32_t *r);
void bn_divmod1000(bignum256 *a, uint32_t *r);
size_t bn_format(const bignum256 *amnt, const char *prefix, const char *suffix, unsigned int decimals, int exponent, bool trailing, char *out, size_t outlen);
size_t bn_format(const bignum256 *amnt, const char *prefix, const char *suffix,
unsigned int decimals, int exponent, bool trailing, char *out,
size_t outlen);
static inline size_t bn_format_uint64(uint64_t amount, const char *prefix, const char *suffix, unsigned int decimals, int exponent, bool trailing, char *out, size_t outlen)
{
bignum256 amnt;
bn_read_uint64(amount, &amnt);
static inline size_t bn_format_uint64(uint64_t amount, const char *prefix,
const char *suffix, unsigned int decimals,
int exponent, bool trailing, char *out,
size_t outlen) {
bignum256 amnt;
bn_read_uint64(amount, &amnt);
return bn_format(&amnt, prefix, suffix, decimals, exponent, trailing, out, outlen);
return bn_format(&amnt, prefix, suffix, decimals, exponent, trailing, out,
outlen);
}
#if USE_BN_PRINT

1378
bip32.c

File diff suppressed because it is too large Load Diff

@ -24,58 +24,73 @@
#ifndef __BIP32_H__
#define __BIP32_H__
#include <stdbool.h>
#include <stdint.h>
#include <stdlib.h>
#include <stdbool.h>
#include "ecdsa.h"
#include "ed25519-donna/ed25519.h"
#include "options.h"
typedef struct {
const char *bip32_name; // string for generating BIP32 xprv from seed
const ecdsa_curve *params; // ecdsa curve parameters, null for ed25519
const char *bip32_name; // string for generating BIP32 xprv from seed
const ecdsa_curve *params; // ecdsa curve parameters, null for ed25519
HasherType hasher_base58;
HasherType hasher_sign;
HasherType hasher_pubkey;
HasherType hasher_script;
HasherType hasher_base58;
HasherType hasher_sign;
HasherType hasher_pubkey;
HasherType hasher_script;
} curve_info;
typedef struct {
uint32_t depth;
uint32_t child_num;
uint8_t chain_code[32];
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 private_key[32];
uint8_t private_key_extension[32];
uint8_t public_key[33];
const curve_info *curve;
uint8_t public_key[33];
const curve_info *curve;
} HDNode;
int hdnode_from_xpub(uint32_t depth, uint32_t child_num, const uint8_t *chain_code, const uint8_t *public_key, const char *curve, HDNode *out);
int hdnode_from_xpub(uint32_t depth, uint32_t child_num,
const uint8_t *chain_code, const uint8_t *public_key,
const char *curve, HDNode *out);
int hdnode_from_xprv(uint32_t depth, uint32_t child_num, const uint8_t *chain_code, const uint8_t *private_key, const char *curve, HDNode *out);
int hdnode_from_xprv(uint32_t depth, uint32_t child_num,
const uint8_t *chain_code, const uint8_t *private_key,
const char *curve, HDNode *out);
int hdnode_from_seed(const uint8_t *seed, int seed_len, const char *curve, HDNode *out);
int hdnode_from_seed(const uint8_t *seed, int seed_len, const char *curve,
HDNode *out);
#define hdnode_private_ckd_prime(X, I) hdnode_private_ckd((X), ((I) | 0x80000000))
#define hdnode_private_ckd_prime(X, I) \
hdnode_private_ckd((X), ((I) | 0x80000000))
int hdnode_private_ckd(HDNode *inout, uint32_t i);
#if USE_CARDANO
int hdnode_private_ckd_cardano(HDNode *inout, uint32_t i);
int hdnode_from_seed_cardano(const uint8_t *pass, int pass_len, const uint8_t *seed, int seed_len, HDNode *out);
int hdnode_from_seed_cardano(const uint8_t *pass, int pass_len,
const 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);
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);
int hdnode_public_ckd(HDNode *inout, uint32_t i);
void hdnode_public_ckd_address_optimized(const curve_point *pub, const uint8_t *chain_code, uint32_t i, uint32_t version, HasherType hasher_pubkey, HasherType hasher_base58, char *addr, int addrsize, int addrformat);
void hdnode_public_ckd_address_optimized(const curve_point *pub,
const uint8_t *chain_code, uint32_t i,
uint32_t version,
HasherType hasher_pubkey,
HasherType hasher_base58, char *addr,
int addrsize, int addrformat);
#if USE_BIP32_CACHE
int hdnode_private_ckd_cached(HDNode *inout, const uint32_t *i, size_t i_count, uint32_t *fingerprint);
int hdnode_private_ckd_cached(HDNode *inout, const uint32_t *i, size_t i_count,
uint32_t *fingerprint);
#endif
uint32_t hdnode_fingerprint(HDNode *node);
@ -88,24 +103,41 @@ int hdnode_get_ethereum_pubkeyhash(const HDNode *node, uint8_t *pubkeyhash);
#if USE_NEM
int hdnode_get_nem_address(HDNode *node, uint8_t version, char *address);
int hdnode_get_nem_shared_key(const HDNode *node, const ed25519_public_key peer_public_key, const uint8_t *salt, ed25519_public_key mul, uint8_t *shared_key);
int hdnode_nem_encrypt(const HDNode *node, const ed25519_public_key public_key, const uint8_t *iv, const uint8_t *salt, const uint8_t *payload, size_t size, uint8_t *buffer);
int hdnode_nem_decrypt(const HDNode *node, const ed25519_public_key public_key, uint8_t *iv, const uint8_t *salt, const uint8_t *payload, size_t size, uint8_t *buffer);
int hdnode_get_nem_shared_key(const HDNode *node,
const ed25519_public_key peer_public_key,
const uint8_t *salt, ed25519_public_key mul,
uint8_t *shared_key);
int hdnode_nem_encrypt(const HDNode *node, const ed25519_public_key public_key,
const uint8_t *iv, const uint8_t *salt,
const uint8_t *payload, size_t size, uint8_t *buffer);
int hdnode_nem_decrypt(const HDNode *node, const ed25519_public_key public_key,
uint8_t *iv, const uint8_t *salt, const uint8_t *payload,
size_t size, uint8_t *buffer);
#endif
int hdnode_sign(HDNode *node, const uint8_t *msg, uint32_t msg_len, HasherType hasher_sign, uint8_t *sig, uint8_t *pby, int (*is_canonical)(uint8_t by, uint8_t sig[64]));
int hdnode_sign_digest(HDNode *node, const uint8_t *digest, uint8_t *sig, uint8_t *pby, int (*is_canonical)(uint8_t by, uint8_t sig[64]));
int hdnode_sign(HDNode *node, const uint8_t *msg, uint32_t msg_len,
HasherType hasher_sign, uint8_t *sig, uint8_t *pby,
int (*is_canonical)(uint8_t by, uint8_t sig[64]));
int hdnode_sign_digest(HDNode *node, const uint8_t *digest, uint8_t *sig,
uint8_t *pby,
int (*is_canonical)(uint8_t by, uint8_t sig[64]));
int hdnode_get_shared_key(const HDNode *node, const uint8_t *peer_public_key, uint8_t *session_key, int *result_size);
int hdnode_get_shared_key(const HDNode *node, const uint8_t *peer_public_key,
uint8_t *session_key, int *result_size);
int hdnode_serialize_public(const HDNode *node, uint32_t fingerprint, uint32_t version, char *str, int strsize);
int hdnode_serialize_public(const HDNode *node, uint32_t fingerprint,
uint32_t version, char *str, int strsize);
int hdnode_serialize_private(const HDNode *node, uint32_t fingerprint, uint32_t version, char *str, int strsize);
int hdnode_serialize_private(const HDNode *node, uint32_t fingerprint,
uint32_t version, char *str, int strsize);
int hdnode_deserialize(const char *str, uint32_t version_public, uint32_t version_private, const char *curve, HDNode *node, uint32_t *fingerprint);
int hdnode_deserialize(const char *str, uint32_t version_public,
uint32_t version_private, const char *curve,
HDNode *node, uint32_t *fingerprint);
void hdnode_get_address_raw(HDNode *node, uint32_t version, uint8_t *addr_raw);
void hdnode_get_address(HDNode *node, uint32_t version, char *addr, int addrsize);
void hdnode_get_address(HDNode *node, uint32_t version, char *addr,
int addrsize);
const curve_info *get_curve_by_name(const char *curve_name);

@ -21,216 +21,211 @@
* OTHER DEALINGS IN THE SOFTWARE.
*/
#include <string.h>
#include <stdbool.h>
#include <string.h>
#include "bip39.h"
#include "bip39_english.h"
#include "hmac.h"
#include "memzero.h"
#include "options.h"
#include "pbkdf2.h"
#include "rand.h"
#include "sha2.h"
#include "pbkdf2.h"
#include "bip39_english.h"
#include "options.h"
#include "memzero.h"
#if USE_BIP39_CACHE
static int bip39_cache_index = 0;
static CONFIDENTIAL struct {
bool set;
char mnemonic[256];
char passphrase[64];
uint8_t seed[512 / 8];
bool set;
char mnemonic[256];
char passphrase[64];
uint8_t seed[512 / 8];
} bip39_cache[BIP39_CACHE_SIZE];
#endif
const char *mnemonic_generate(int strength)
{
if (strength % 32 || strength < 128 || strength > 256) {
return 0;
}
uint8_t data[32];
random_buffer(data, 32);
const char *r = mnemonic_from_data(data, strength / 8);
memzero(data, sizeof(data));
return r;
const char *mnemonic_generate(int strength) {
if (strength % 32 || strength < 128 || strength > 256) {
return 0;
}
uint8_t data[32];
random_buffer(data, 32);
const char *r = mnemonic_from_data(data, strength / 8);
memzero(data, sizeof(data));
return r;
}
static CONFIDENTIAL char mnemo[24 * 10];
const char *mnemonic_from_data(const uint8_t *data, int len)
{
if (len % 4 || len < 16 || len > 32) {
return 0;
}
uint8_t bits[32 + 1];
sha256_Raw(data, len, bits);
// checksum
bits[len] = bits[0];
// data
memcpy(bits, data, len);
int mlen = len * 3 / 4;
int i, j, idx;
char *p = mnemo;
for (i = 0; i < mlen; i++) {
idx = 0;
for (j = 0; j < 11; j++) {
idx <<= 1;
idx += (bits[(i * 11 + j) / 8] & (1 << (7 - ((i * 11 + j) % 8)))) > 0;
}
strcpy(p, wordlist[idx]);
p += strlen(wordlist[idx]);
*p = (i < mlen - 1) ? ' ' : 0;
p++;
}
memzero(bits, sizeof(bits));
return mnemo;
const char *mnemonic_from_data(const uint8_t *data, int len) {
if (len % 4 || len < 16 || len > 32) {
return 0;
}
uint8_t bits[32 + 1];
sha256_Raw(data, len, bits);
// checksum
bits[len] = bits[0];
// data
memcpy(bits, data, len);
int mlen = len * 3 / 4;
int i, j, idx;
char *p = mnemo;
for (i = 0; i < mlen; i++) {
idx = 0;
for (j = 0; j < 11; j++) {
idx <<= 1;
idx += (bits[(i * 11 + j) / 8] & (1 << (7 - ((i * 11 + j) % 8)))) > 0;
}
strcpy(p, wordlist[idx]);
p += strlen(wordlist[idx]);
*p = (i < mlen - 1) ? ' ' : 0;
p++;
}
memzero(bits, sizeof(bits));
return mnemo;
}
void mnemonic_clear(void)
{
memzero(mnemo, sizeof(mnemo));
void mnemonic_clear(void) { memzero(mnemo, sizeof(mnemo)); }
int mnemonic_to_entropy(const char *mnemonic, uint8_t *entropy) {
if (!mnemonic) {
return 0;
}
uint32_t 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 = 0;
uint8_t bits[32 + 1];
memzero(bits, sizeof(bits));
i = 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_to_entropy(const char *mnemonic, uint8_t *entropy)
{
if (!mnemonic) {
return 0;
}
uint32_t 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 = 0;
uint8_t bits[32 + 1];
memzero(bits, sizeof(bits));
i = 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)
{
uint8_t bits[32 + 1];
int seed_len = mnemonic_to_entropy(mnemonic, bits);
if (seed_len != (12 * 11) && seed_len != (18 * 11) && seed_len != (24 * 11)) {
return 0;
}
int words = seed_len / 11;
uint8_t checksum = bits[words * 4 / 3];
sha256_Raw(bits, words * 4 / 3, bits);
if (words == 12) {
return (bits[0] & 0xF0) == (checksum & 0xF0); // compare first 4 bits
} else if (words == 18) {
return (bits[0] & 0xFC) == (checksum & 0xFC); // compare first 6 bits
} else if (words == 24) {
return bits[0] == checksum; // compare 8 bits
}
return 0;
int mnemonic_check(const char *mnemonic) {
uint8_t bits[32 + 1];
int seed_len = mnemonic_to_entropy(mnemonic, bits);
if (seed_len != (12 * 11) && seed_len != (18 * 11) && seed_len != (24 * 11)) {
return 0;
}
int words = seed_len / 11;
uint8_t checksum = bits[words * 4 / 3];
sha256_Raw(bits, words * 4 / 3, bits);
if (words == 12) {
return (bits[0] & 0xF0) == (checksum & 0xF0); // compare first 4 bits
} else if (words == 18) {
return (bits[0] & 0xFC) == (checksum & 0xFC); // compare first 6 bits
} else if (words == 24) {
return bits[0] == checksum; // compare 8 bits
}
return 0;
}
// passphrase must be at most 256 characters otherwise it would be truncated
void mnemonic_to_seed(const char *mnemonic, const char *passphrase, uint8_t seed[512 / 8], void (*progress_callback)(uint32_t current, uint32_t total))
{
int mnemoniclen = strlen(mnemonic);
int passphraselen = strnlen(passphrase, 256);
void mnemonic_to_seed(const char *mnemonic, const char *passphrase,
uint8_t seed[512 / 8],
void (*progress_callback)(uint32_t current,
uint32_t total)) {
int mnemoniclen = strlen(mnemonic);
int passphraselen = strnlen(passphrase, 256);
#if USE_BIP39_CACHE
// check cache
if (mnemoniclen < 256 && passphraselen < 64) {
for (int i = 0; i < BIP39_CACHE_SIZE; i++) {
if (!bip39_cache[i].set) continue;
if (strcmp(bip39_cache[i].mnemonic, mnemonic) != 0) continue;
if (strcmp(bip39_cache[i].passphrase, passphrase) != 0) continue;
// found the correct entry
memcpy(seed, bip39_cache[i].seed, 512 / 8);
return;
}
}
// check cache
if (mnemoniclen < 256 && passphraselen < 64) {
for (int i = 0; i < BIP39_CACHE_SIZE; i++) {
if (!bip39_cache[i].set) continue;
if (strcmp(bip39_cache[i].mnemonic, mnemonic) != 0) continue;
if (strcmp(bip39_cache[i].passphrase, passphrase) != 0) continue;
// found the correct entry
memcpy(seed, bip39_cache[i].seed, 512 / 8);
return;
}
}
#endif
uint8_t salt[8 + 256];
memcpy(salt, "mnemonic", 8);
memcpy(salt + 8, passphrase, passphraselen);
static CONFIDENTIAL PBKDF2_HMAC_SHA512_CTX pctx;
pbkdf2_hmac_sha512_Init(&pctx, (const uint8_t *)mnemonic, mnemoniclen, salt, passphraselen + 8, 1);
if (progress_callback) {
progress_callback(0, BIP39_PBKDF2_ROUNDS);
}
for (int i = 0; i < 16; i++) {
pbkdf2_hmac_sha512_Update(&pctx, BIP39_PBKDF2_ROUNDS / 16);
if (progress_callback) {
progress_callback((i + 1) * BIP39_PBKDF2_ROUNDS / 16, BIP39_PBKDF2_ROUNDS);
}
}
pbkdf2_hmac_sha512_Final(&pctx, seed);
memzero(salt, sizeof(salt));
uint8_t salt[8 + 256];
memcpy(salt, "mnemonic", 8);
memcpy(salt + 8, passphrase, passphraselen);
static CONFIDENTIAL PBKDF2_HMAC_SHA512_CTX pctx;
pbkdf2_hmac_sha512_Init(&pctx, (const uint8_t *)mnemonic, mnemoniclen, salt,
passphraselen + 8, 1);
if (progress_callback) {
progress_callback(0, BIP39_PBKDF2_ROUNDS);
}
for (int i = 0; i < 16; i++) {
pbkdf2_hmac_sha512_Update(&pctx, BIP39_PBKDF2_ROUNDS / 16);
if (progress_callback) {
progress_callback((i + 1) * BIP39_PBKDF2_ROUNDS / 16,
BIP39_PBKDF2_ROUNDS);
}
}
pbkdf2_hmac_sha512_Final(&pctx, seed);
memzero(salt, sizeof(salt));
#if USE_BIP39_CACHE
// store to cache
if (mnemoniclen < 256 && passphraselen < 64) {
bip39_cache[bip39_cache_index].set = true;
strcpy(bip39_cache[bip39_cache_index].mnemonic, mnemonic);
strcpy(bip39_cache[bip39_cache_index].passphrase, passphrase);
memcpy(bip39_cache[bip39_cache_index].seed, seed, 512 / 8);
bip39_cache_index = (bip39_cache_index + 1) % BIP39_CACHE_SIZE;
}
// store to cache
if (mnemoniclen < 256 && passphraselen < 64) {
bip39_cache[bip39_cache_index].set = true;
strcpy(bip39_cache[bip39_cache_index].mnemonic, mnemonic);
strcpy(bip39_cache[bip39_cache_index].passphrase, passphrase);
memcpy(bip39_cache[bip39_cache_index].seed, seed, 512 / 8);
bip39_cache_index = (bip39_cache_index + 1) % BIP39_CACHE_SIZE;
}
#endif
}
const char * const *mnemonic_wordlist(void)
{
return wordlist;
}
const char *const *mnemonic_wordlist(void) { return wordlist; }

@ -28,7 +28,7 @@
#define BIP39_PBKDF2_ROUNDS 2048
const char *mnemonic_generate(int strength); // strength in bits
const char *mnemonic_generate(int strength); // strength in bits
const char *mnemonic_from_data(const uint8_t *data, int len);
void mnemonic_clear(void);
@ -37,8 +37,11 @@ int mnemonic_check(const char *mnemonic);
int mnemonic_to_entropy(const char *mnemonic, uint8_t *entropy);
// passphrase must be at most 256 characters otherwise it would be truncated
void mnemonic_to_seed(const char *mnemonic, const char *passphrase, uint8_t seed[512 / 8], void (*progress_callback)(uint32_t current, uint32_t total));
void mnemonic_to_seed(const char *mnemonic, const char *passphrase,
uint8_t seed[512 / 8],
void (*progress_callback)(uint32_t current,
uint32_t total));
const char * const *mnemonic_wordlist(void);
const char *const *mnemonic_wordlist(void);
#endif

File diff suppressed because it is too large Load Diff

@ -1,39 +1,25 @@
static inline uint32_t load32( const void *src )
{
uint32_t w;
memcpy(&w, src, sizeof w);
return w;
static inline uint32_t load32(const void *src) {
uint32_t w;
memcpy(&w, src, sizeof w);
return w;
}
static inline uint64_t load64( const void *src )
{
static inline uint64_t load64(const void *src) {
uint64_t w;
memcpy(&w, src, sizeof w);
return w;
}
static inline void store16( void *dst, uint16_t w )
{
memcpy(dst, &w, sizeof w);
}
static inline void store16(void *dst, uint16_t w) { memcpy(dst, &w, sizeof w); }
static inline void store32( void *dst, uint32_t w )
{
memcpy(dst, &w, sizeof w);
}
static inline void store32(void *dst, uint32_t w) { memcpy(dst, &w, sizeof w); }
static inline void store64( void *dst, uint64_t w )
{
memcpy(dst, &w, sizeof w);
}
static inline void store64(void *dst, uint64_t w) { memcpy(dst, &w, sizeof w); }
static inline uint32_t rotr32( const uint32_t w, const unsigned c )
{
return ( w >> c ) | ( w << ( 32 - c ) );
static inline uint32_t rotr32(const uint32_t w, const unsigned c) {
return (w >> c) | (w << (32 - c));
}
static inline uint64_t rotr64( const uint64_t w, const unsigned c )
{
return ( w >> c ) | ( w << ( 64 - c ) );
static inline uint64_t rotr64(const uint64_t w, const unsigned c) {
return (w >> c) | (w << (64 - c));
}

@ -19,8 +19,8 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include <stdlib.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include "cash_addr.h"
@ -32,156 +32,158 @@
#define CHECKSUM_SIZE 8
uint64_t cashaddr_polymod_step(uint64_t pre) {
uint8_t b = pre >> 35;
return ((pre & 0x7FFFFFFFFULL) << 5) ^
(-((b >> 0) & 1) & 0x98f2bc8e61ULL) ^
(-((b >> 1) & 1) & 0x79b76d99e2ULL) ^
(-((b >> 2) & 1) & 0xf33e5fb3c4ULL) ^
(-((b >> 3) & 1) & 0xae2eabe2a8ULL) ^
(-((b >> 4) & 1) & 0x1e4f43e470ULL);
uint8_t b = pre >> 35;
return ((pre & 0x7FFFFFFFFULL) << 5) ^ (-((b >> 0) & 1) & 0x98f2bc8e61ULL) ^
(-((b >> 1) & 1) & 0x79b76d99e2ULL) ^
(-((b >> 2) & 1) & 0xf33e5fb3c4ULL) ^
(-((b >> 3) & 1) & 0xae2eabe2a8ULL) ^
(-((b >> 4) & 1) & 0x1e4f43e470ULL);
}
static const char* charset = "qpzry9x8gf2tvdw0s3jn54khce6mua7l";
static const int8_t charset_rev[128] = {
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
15, -1, 10, 17, 21, 20, 26, 30, 7, 5, -1, -1, -1, -1, -1, -1,
-1, 29, -1, 24, 13, 25, 9, 8, 23, -1, 18, 22, 31, 27, 19, -1,
1, 0, 3, 16, 11, 28, 12, 14, 6, 4, 2, -1, -1, -1, -1, -1,
-1, 29, -1, 24, 13, 25, 9, 8, 23, -1, 18, 22, 31, 27, 19, -1,
1, 0, 3, 16, 11, 28, 12, 14, 6, 4, 2, -1, -1, -1, -1, -1
};
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 15, -1, 10, 17, 21, 20, 26, 30, 7,
5, -1, -1, -1, -1, -1, -1, -1, 29, -1, 24, 13, 25, 9, 8, 23, -1, 18, 22,
31, 27, 19, -1, 1, 0, 3, 16, 11, 28, 12, 14, 6, 4, 2, -1, -1, -1, -1,
-1, -1, 29, -1, 24, 13, 25, 9, 8, 23, -1, 18, 22, 31, 27, 19, -1, 1, 0,
3, 16, 11, 28, 12, 14, 6, 4, 2, -1, -1, -1, -1, -1};
int cash_encode(char *output, const char *hrp, const uint8_t *data, size_t data_len) {
uint64_t chk = 1;
size_t i = 0;
while (hrp[i] != 0) {
int ch = hrp[i];
if (ch < 33 || ch > 126) {
return 0;
}
*(output++) = ch;
chk = cashaddr_polymod_step(chk) ^ (ch & 0x1f);
++i;
}
if (i + 1 + data_len + CHECKSUM_SIZE > MAX_CASHADDR_SIZE) {
return 0;
int cash_encode(char* output, const char* hrp, const uint8_t* data,
size_t data_len) {
uint64_t chk = 1;
size_t i = 0;
while (hrp[i] != 0) {
int ch = hrp[i];
if (ch < 33 || ch > 126) {
return 0;
}
*(output++) = ch;
chk = cashaddr_polymod_step(chk) ^ (ch & 0x1f);
++i;
}
if (i + 1 + data_len + CHECKSUM_SIZE > MAX_CASHADDR_SIZE) {
return 0;
}
chk = cashaddr_polymod_step(chk);
*(output++) = ':';
for (i = 0; i < data_len; ++i) {
if (*data >> 5) return 0;
chk = cashaddr_polymod_step(chk) ^ (*data);
*(output++) = charset[*(data++)];
}
for (i = 0; i < CHECKSUM_SIZE; ++i) {
chk = cashaddr_polymod_step(chk);
*(output++) = ':';
for (i = 0; i < data_len; ++i) {
if (*data >> 5) return 0;
chk = cashaddr_polymod_step(chk) ^ (*data);
*(output++) = charset[*(data++)];
}
for (i = 0; i < CHECKSUM_SIZE; ++i) {
chk = cashaddr_polymod_step(chk);
}
chk ^= 1;
for (i = 0; i < CHECKSUM_SIZE; ++i) {
*(output++) = charset[(chk >> ((CHECKSUM_SIZE - 1 - i) * 5)) & 0x1f];
}
*output = 0;
return 1;
}
chk ^= 1;
for (i = 0; i < CHECKSUM_SIZE; ++i) {
*(output++) = charset[(chk >> ((CHECKSUM_SIZE - 1 - i) * 5)) & 0x1f];
}
*output = 0;
return 1;
}
int cash_decode(char* hrp, uint8_t *data, size_t *data_len, const char *input) {
uint64_t chk = 1;
size_t i;
size_t input_len = strlen(input);
size_t hrp_len;
int have_lower = 0, have_upper = 0;
if (input_len < CHECKSUM_SIZE || input_len > MAX_CASHADDR_SIZE) {
return 0;
int cash_decode(char* hrp, uint8_t* data, size_t* data_len, const char* input) {
uint64_t chk = 1;
size_t i;
size_t input_len = strlen(input);
size_t hrp_len;
int have_lower = 0, have_upper = 0;
if (input_len < CHECKSUM_SIZE || input_len > MAX_CASHADDR_SIZE) {
return 0;
}
*data_len = 0;
while (*data_len < input_len && input[(input_len - 1) - *data_len] != ':') {
++(*data_len);
}
hrp_len = input_len - (1 + *data_len);
if (1 + *data_len >= input_len || hrp_len > MAX_HRP_SIZE ||
*data_len < CHECKSUM_SIZE ||
*data_len > CHECKSUM_SIZE + MAX_BASE32_SIZE) {
return 0;
}
// subtract checksum
*(data_len) -= CHECKSUM_SIZE;
for (i = 0; i < hrp_len; ++i) {
int ch = input[i];
if (ch < 33 || ch > 126) {
return 0;
}
*data_len = 0;
while (*data_len < input_len && input[(input_len - 1) - *data_len] != ':') {
++(*data_len);
if (ch >= 'a' && ch <= 'z') {
have_lower = 1;
} else if (ch >= 'A' && ch <= 'Z') {
have_upper = 1;
ch = (ch - 'A') + 'a';
}
hrp_len = input_len - (1 + *data_len);
if (1 + *data_len >= input_len || hrp_len > MAX_HRP_SIZE ||
*data_len < CHECKSUM_SIZE || *data_len > CHECKSUM_SIZE + MAX_BASE32_SIZE) {
return 0;
hrp[i] = ch;
chk = cashaddr_polymod_step(chk) ^ (ch & 0x1f);
}
hrp[i] = 0;
chk = cashaddr_polymod_step(chk);
++i;
while (i < input_len) {
int v = (input[i] & 0x80) ? -1 : charset_rev[(int)input[i]];
if (input[i] >= 'a' && input[i] <= 'z') have_lower = 1;
if (input[i] >= 'A' && input[i] <= 'Z') have_upper = 1;
if (v == -1) {
return 0;
}
// subtract checksum
*(data_len) -= CHECKSUM_SIZE;
for (i = 0; i < hrp_len; ++i) {
int ch = input[i];
if (ch < 33 || ch > 126) {
return 0;
}
if (ch >= 'a' && ch <= 'z') {
have_lower = 1;
} else if (ch >= 'A' && ch <= 'Z') {
have_upper = 1;
ch = (ch - 'A') + 'a';
}
hrp[i] = ch;
chk = cashaddr_polymod_step(chk) ^ (ch & 0x1f);
chk = cashaddr_polymod_step(chk) ^ v;
if (i + CHECKSUM_SIZE < input_len) {
data[i - (1 + hrp_len)] = v;
}
hrp[i] = 0;
chk = cashaddr_polymod_step(chk);
++i;
while (i < input_len) {
int v = (input[i] & 0x80) ? -1 : charset_rev[(int)input[i]];
if (input[i] >= 'a' && input[i] <= 'z') have_lower = 1;
if (input[i] >= 'A' && input[i] <= 'Z') have_upper = 1;
if (v == -1) {
return 0;
}
chk = cashaddr_polymod_step(chk) ^ v;
if (i + CHECKSUM_SIZE < input_len) {
data[i - (1 + hrp_len)] = v;
}
++i;
}
if (have_lower && have_upper) {
return 0;
}
return chk == 1;
}
if (have_lower && have_upper) {
return 0;
}
return chk == 1;
}
static int convert_bits(uint8_t* out, size_t* outlen, int outbits, const uint8_t* in, size_t inlen, int inbits, int pad) {
uint32_t val = 0;
int bits = 0;
uint32_t maxv = (((uint32_t)1) << outbits) - 1;
while (inlen--) {
val = (val << inbits) | *(in++);
bits += inbits;
while (bits >= outbits) {
bits -= outbits;
out[(*outlen)++] = (val >> bits) & maxv;
}
static int convert_bits(uint8_t* out, size_t* outlen, int outbits,
const uint8_t* in, size_t inlen, int inbits, int pad) {
uint32_t val = 0;
int bits = 0;
uint32_t maxv = (((uint32_t)1) << outbits) - 1;
while (inlen--) {
val = (val << inbits) | *(in++);
bits += inbits;
while (bits >= outbits) {
bits -= outbits;
out[(*outlen)++] = (val >> bits) & maxv;
}
if (pad) {
if (bits) {
out[(*outlen)++] = (val << (outbits - bits)) & maxv;
}
} else if (((val << (outbits - bits)) & maxv) || bits >= inbits) {
return 0;
}
if (pad) {
if (bits) {
out[(*outlen)++] = (val << (outbits - bits)) & maxv;
}
return 1;
} else if (((val << (outbits - bits)) & maxv) || bits >= inbits) {
return 0;
}
return 1;
}
int cash_addr_encode(char *output, const char *hrp, const uint8_t *data, size_t data_len) {
uint8_t base32[MAX_BASE32_SIZE];
size_t base32len = 0;
if (data_len < 2 || data_len > MAX_DATA_SIZE) return 0;
convert_bits(base32, &base32len, 5, data, data_len, 8, 1);
return cash_encode(output, hrp, base32, base32len);
int cash_addr_encode(char* output, const char* hrp, const uint8_t* data,
size_t data_len) {
uint8_t base32[MAX_BASE32_SIZE];
size_t base32len = 0;
if (data_len < 2 || data_len > MAX_DATA_SIZE) return 0;
convert_bits(base32, &base32len, 5, data, data_len, 8, 1);
return cash_encode(output, hrp, base32, base32len);
}
int cash_addr_decode(uint8_t* witdata, size_t* witdata_len, const char* hrp, const char* addr) {
uint8_t data[MAX_BASE32_SIZE];
char hrp_actual[MAX_HRP_SIZE+1];
size_t data_len;
if (!cash_decode(hrp_actual, data, &data_len, addr)) return 0;
if (data_len == 0 || data_len > MAX_BASE32_SIZE) return 0;
if (strncmp(hrp, hrp_actual, MAX_HRP_SIZE + 1) != 0) return 0;
*witdata_len = 0;
if (!convert_bits(witdata, witdata_len, 8, data, data_len, 5, 0)) return 0;
if (*witdata_len < 2 || *witdata_len > MAX_DATA_SIZE) return 0;
return 1;
int cash_addr_decode(uint8_t* witdata, size_t* witdata_len, const char* hrp,
const char* addr) {
uint8_t data[MAX_BASE32_SIZE];
char hrp_actual[MAX_HRP_SIZE + 1];
size_t data_len;
if (!cash_decode(hrp_actual, data, &data_len, addr)) return 0;
if (data_len == 0 || data_len > MAX_BASE32_SIZE) return 0;
if (strncmp(hrp, hrp_actual, MAX_HRP_SIZE + 1) != 0) return 0;
*witdata_len = 0;
if (!convert_bits(witdata, witdata_len, 8, data, data_len, 5, 0)) return 0;
if (*witdata_len < 2 || *witdata_len > MAX_DATA_SIZE) return 0;
return 1;
}

@ -34,30 +34,20 @@
* prog_len: Number of data bytes in prog.
* Returns 1 if successful.
*/
int cash_addr_encode(
char *output,
const char *hrp,
const uint8_t *prog,
size_t prog_len
);
int cash_addr_encode(char *output, const char *hrp, const uint8_t *prog,
size_t prog_len);
/** Decode a CashAddr address
*
* Out: prog: Pointer to a buffer of size 65 that will be updated to
* contain the witness program bytes.
* prog_len: Pointer to a size_t that will be updated to contain the length
* of bytes in prog.
* hrp: Pointer to the null-terminated human readable part that is
* expected (chain/network specific).
* addr: Pointer to the null-terminated address.
* Returns 1 if successful.
* prog_len: Pointer to a size_t that will be updated to contain the
* length of bytes in prog. hrp: Pointer to the null-terminated human
* readable part that is expected (chain/network specific). addr: Pointer to
* the null-terminated address. Returns 1 if successful.
*/
int cash_addr_decode(
uint8_t* prog,
size_t* prog_len,
const char* hrp,
const char* addr
);
int cash_addr_decode(uint8_t *prog, size_t *prog_len, const char *hrp,
const char *addr);
/** Encode a Cash string
*
@ -68,12 +58,8 @@ int cash_addr_decode(
* data_len: Length of the data array.
* Returns 1 if successful.
*/
int cash_encode(
char *output,
const char *hrp,
const uint8_t *data,
size_t data_len
);
int cash_encode(char *output, const char *hrp, const uint8_t *data,
size_t data_len);
/** Decode a Cash string
*
@ -86,11 +72,6 @@ int cash_encode(
* In: input: Pointer to a null-terminated Cash string.
* Returns 1 if succesful.
*/
int cash_decode(
char *hrp,
uint8_t *data,
size_t *data_len,
const char *input
);
int cash_decode(char *hrp, uint8_t *data, size_t *data_len, const char *input);
#endif

1968
ecdsa.c

File diff suppressed because it is too large Load Diff

@ -25,26 +25,25 @@
#define __ECDSA_H__
#include <stdint.h>
#include "options.h"
#include "bignum.h"
#include "hasher.h"
#include "options.h"
// curve point x and y
typedef struct {
bignum256 x, y;
bignum256 x, y;
} curve_point;
typedef struct {
bignum256 prime; // prime order of the finite field
curve_point G; // initial curve point
bignum256 order; // order of G
bignum256 order_half; // order of G divided by 2
int a; // coefficient 'a' of the elliptic curve
bignum256 b; // coefficient 'b' of the elliptic curve
bignum256 prime; // prime order of the finite field
curve_point G; // initial curve point
bignum256 order; // order of G
bignum256 order_half; // order of G divided by 2
int a; // coefficient 'a' of the elliptic curve
bignum256 b; // coefficient 'b' of the elliptic curve
#if USE_PRECOMPUTED_CP
const curve_point cp[64][8];
const curve_point cp[64][8];
#endif
} ecdsa_curve;
@ -63,35 +62,65 @@ typedef struct {
#define MAX_WIF_SIZE (57)
void point_copy(const curve_point *cp1, curve_point *cp2);
void point_add(const ecdsa_curve *curve, const curve_point *cp1, curve_point *cp2);
void point_add(const ecdsa_curve *curve, const curve_point *cp1,
curve_point *cp2);
void point_double(const ecdsa_curve *curve, curve_point *cp);
void point_multiply(const ecdsa_curve *curve, const bignum256 *k, const curve_point *p, curve_point *res);
void point_multiply(const ecdsa_curve *curve, const bignum256 *k,
const curve_point *p, curve_point *res);
void point_set_infinity(curve_point *p);
int point_is_infinity(const curve_point *p);
int point_is_equal(const curve_point *p, const curve_point *q);
int point_is_negative_of(const curve_point *p, const curve_point *q);
void scalar_multiply(const ecdsa_curve *curve, const bignum256 *k, curve_point *res);
int ecdh_multiply(const ecdsa_curve *curve, const uint8_t *priv_key, const uint8_t *pub_key, uint8_t *session_key);
void uncompress_coords(const ecdsa_curve *curve, uint8_t odd, const bignum256 *x, bignum256 *y);
int ecdsa_uncompress_pubkey(const ecdsa_curve *curve, const uint8_t *pub_key, uint8_t *uncompressed);
void scalar_multiply(const ecdsa_curve *curve, const bignum256 *k,
curve_point *res);
int ecdh_multiply(const ecdsa_curve *curve, const uint8_t *priv_key,
const uint8_t *pub_key, uint8_t *session_key);
void uncompress_coords(const ecdsa_curve *curve, uint8_t odd,
const bignum256 *x, bignum256 *y);
int ecdsa_uncompress_pubkey(const ecdsa_curve *curve, const uint8_t *pub_key,
uint8_t *uncompressed);
int ecdsa_sign(const ecdsa_curve *curve, HasherType hasher_sign, const uint8_t *priv_key, const uint8_t *msg, uint32_t msg_len, uint8_t *sig, uint8_t *pby, int (*is_canonical)(uint8_t by, uint8_t sig[64]));
int ecdsa_sign_digest(const ecdsa_curve *curve, const uint8_t *priv_key, const uint8_t *digest, uint8_t *sig, uint8_t *pby, int (*is_canonical)(uint8_t by, uint8_t sig[64]));
void ecdsa_get_public_key33(const ecdsa_curve *curve, const uint8_t *priv_key, uint8_t *pub_key);
void ecdsa_get_public_key65(const ecdsa_curve *curve, const uint8_t *priv_key, uint8_t *pub_key);
void ecdsa_get_pubkeyhash(const uint8_t *pub_key, HasherType hasher_pubkey, uint8_t *pubkeyhash);
void ecdsa_get_address_raw(const uint8_t *pub_key, uint32_t version, HasherType hasher_pubkey, uint8_t *addr_raw);
void ecdsa_get_address(const uint8_t *pub_key, uint32_t version, HasherType hasher_pubkey, HasherType hasher_base58, char *addr, int addrsize);
void ecdsa_get_address_segwit_p2sh_raw(const uint8_t *pub_key, uint32_t version, HasherType hasher_pubkey, uint8_t *addr_raw);
void ecdsa_get_address_segwit_p2sh(const uint8_t *pub_key, uint32_t version, HasherType hasher_pubkey, HasherType hasher_base58, char *addr, int addrsize);
void ecdsa_get_wif(const uint8_t *priv_key, uint32_t version, HasherType hasher_base58, char *wif, int wifsize);
int ecdsa_sign(const ecdsa_curve *curve, HasherType hasher_sign,
const uint8_t *priv_key, const uint8_t *msg, uint32_t msg_len,
uint8_t *sig, uint8_t *pby,
int (*is_canonical)(uint8_t by, uint8_t sig[64]));
int ecdsa_sign_digest(const ecdsa_curve *curve, const uint8_t *priv_key,
const uint8_t *digest, uint8_t *sig, uint8_t *pby,
int (*is_canonical)(uint8_t by, uint8_t sig[64]));
void ecdsa_get_public_key33(const ecdsa_curve *curve, const uint8_t *priv_key,
uint8_t *pub_key);
void ecdsa_get_public_key65(const ecdsa_curve *curve, const uint8_t *priv_key,
uint8_t *pub_key);
void ecdsa_get_pubkeyhash(const uint8_t *pub_key, HasherType hasher_pubkey,
uint8_t *pubkeyhash);
void ecdsa_get_address_raw(const uint8_t *pub_key, uint32_t version,
HasherType hasher_pubkey, uint8_t *addr_raw);
void ecdsa_get_address(const uint8_t *pub_key, uint32_t version,
HasherType hasher_pubkey, HasherType hasher_base58,
char *addr, int addrsize);
void ecdsa_get_address_segwit_p2sh_raw(const uint8_t *pub_key, uint32_t version,
HasherType hasher_pubkey,
uint8_t *addr_raw);
void ecdsa_get_address_segwit_p2sh(const uint8_t *pub_key, uint32_t version,
HasherType hasher_pubkey,
HasherType hasher_base58, char *addr,
int addrsize);
void ecdsa_get_wif(const uint8_t *priv_key, uint32_t version,
HasherType hasher_base58, char *wif, int wifsize);
int ecdsa_address_decode(const char *addr, uint32_t version, HasherType hasher_base58, uint8_t *out);
int ecdsa_read_pubkey(const ecdsa_curve *curve, const uint8_t *pub_key, curve_point *pub);
int ecdsa_address_decode(const char *addr, uint32_t version,
HasherType hasher_base58, uint8_t *out);
int ecdsa_read_pubkey(const ecdsa_curve *curve, const uint8_t *pub_key,
curve_point *pub);
int ecdsa_validate_pubkey(const ecdsa_curve *curve, const curve_point *pub);
int ecdsa_verify(const ecdsa_curve *curve, HasherType hasher_sign, const uint8_t *pub_key, const uint8_t *sig, const uint8_t *msg, uint32_t msg_len);
int ecdsa_verify_digest(const ecdsa_curve *curve, const uint8_t *pub_key, const uint8_t *sig, const uint8_t *digest);
int ecdsa_recover_pub_from_sig (const ecdsa_curve *curve, uint8_t *pub_key, const uint8_t *sig, const uint8_t *digest, int recid);
int ecdsa_verify(const ecdsa_curve *curve, HasherType hasher_sign,
const uint8_t *pub_key, const uint8_t *sig, const uint8_t *msg,
uint32_t msg_len);
int ecdsa_verify_digest(const ecdsa_curve *curve, const uint8_t *pub_key,
const uint8_t *sig, const uint8_t *digest);
int ecdsa_recover_pub_from_sig(const ecdsa_curve *curve, uint8_t *pub_key,
const uint8_t *sig, const uint8_t *digest,
int recid);
int ecdsa_sig_to_der(const uint8_t *sig, uint8_t *der);
#endif

@ -23,122 +23,125 @@
#include "hasher.h"
#include "ripemd160.h"
void hasher_InitParam(Hasher *hasher, HasherType type, const void *param, uint32_t param_size) {
hasher->type = type;
hasher->param = param;
hasher->param_size = param_size;
void hasher_InitParam(Hasher *hasher, HasherType type, const void *param,
uint32_t param_size) {
hasher->type = type;
hasher->param = param;
hasher->param_size = param_size;
switch (hasher->type) {
case HASHER_SHA2:
case HASHER_SHA2D:
case HASHER_SHA2_RIPEMD:
sha256_Init(&hasher->ctx.sha2);
break;
case HASHER_SHA3:
switch (hasher->type) {
case HASHER_SHA2:
case HASHER_SHA2D:
case HASHER_SHA2_RIPEMD:
sha256_Init(&hasher->ctx.sha2);
break;
case HASHER_SHA3:
#if USE_KECCAK
case HASHER_SHA3K:
case HASHER_SHA3K:
#endif
sha3_256_Init(&hasher->ctx.sha3);
break;
case HASHER_BLAKE:
case HASHER_BLAKED:
case HASHER_BLAKE_RIPEMD:
blake256_Init(&hasher->ctx.blake);
break;
case HASHER_GROESTLD_TRUNC:
groestl512_Init(&hasher->ctx.groestl);
break;
case HASHER_BLAKE2B:
blake2b_Init(&hasher->ctx.blake2b, 32);
break;
case HASHER_BLAKE2B_PERSONAL:
blake2b_InitPersonal(&hasher->ctx.blake2b, 32, hasher->param, hasher->param_size);
break;
}
sha3_256_Init(&hasher->ctx.sha3);
break;
case HASHER_BLAKE:
case HASHER_BLAKED:
case HASHER_BLAKE_RIPEMD:
blake256_Init(&hasher->ctx.blake);
break;
case HASHER_GROESTLD_TRUNC:
groestl512_Init(&hasher->ctx.groestl);
break;
case HASHER_BLAKE2B:
blake2b_Init(&hasher->ctx.blake2b, 32);
break;
case HASHER_BLAKE2B_PERSONAL:
blake2b_InitPersonal(&hasher->ctx.blake2b, 32, hasher->param,
hasher->param_size);
break;
}
}
void hasher_Init(Hasher *hasher, HasherType type) {
hasher_InitParam(hasher, type, NULL, 0);
hasher_InitParam(hasher, type, NULL, 0);
}
void hasher_Reset(Hasher *hasher) {
hasher_InitParam(hasher, hasher->type, hasher->param, hasher->param_size);
hasher_InitParam(hasher, hasher->type, hasher->param, hasher->param_size);
}
void hasher_Update(Hasher *hasher, const uint8_t *data, size_t length) {
switch (hasher->type) {
case HASHER_SHA2:
case HASHER_SHA2D:
case HASHER_SHA2_RIPEMD:
sha256_Update(&hasher->ctx.sha2, data, length);
break;
case HASHER_SHA3:
switch (hasher->type) {
case HASHER_SHA2:
case HASHER_SHA2D:
case HASHER_SHA2_RIPEMD:
sha256_Update(&hasher->ctx.sha2, data, length);
break;
case HASHER_SHA3:
#if USE_KECCAK
case HASHER_SHA3K:
case HASHER_SHA3K:
#endif
sha3_Update(&hasher->ctx.sha3, data, length);
break;
case HASHER_BLAKE:
case HASHER_BLAKED:
case HASHER_BLAKE_RIPEMD:
blake256_Update(&hasher->ctx.blake, data, length);
break;
case HASHER_GROESTLD_TRUNC:
groestl512_Update(&hasher->ctx.groestl, data, length);
break;
case HASHER_BLAKE2B:
case HASHER_BLAKE2B_PERSONAL:
blake2b_Update(&hasher->ctx.blake2b, data, length);
break;
}
sha3_Update(&hasher->ctx.sha3, data, length);
break;
case HASHER_BLAKE:
case HASHER_BLAKED:
case HASHER_BLAKE_RIPEMD:
blake256_Update(&hasher->ctx.blake, data, length);
break;
case HASHER_GROESTLD_TRUNC:
groestl512_Update(&hasher->ctx.groestl, data, length);
break;
case HASHER_BLAKE2B:
case HASHER_BLAKE2B_PERSONAL:
blake2b_Update(&hasher->ctx.blake2b, data, length);
break;
}
}
void hasher_Final(Hasher *hasher, uint8_t hash[HASHER_DIGEST_LENGTH]) {
switch (hasher->type) {
case HASHER_SHA2:
sha256_Final(&hasher->ctx.sha2, hash);
break;
case HASHER_SHA2D:
sha256_Final(&hasher->ctx.sha2, hash);
hasher_Raw(HASHER_SHA2, hash, HASHER_DIGEST_LENGTH, hash);
break;
case HASHER_SHA2_RIPEMD:
sha256_Final(&hasher->ctx.sha2, hash);
ripemd160(hash, HASHER_DIGEST_LENGTH, hash);
break;
case HASHER_SHA3:
sha3_Final(&hasher->ctx.sha3, hash);
break;
switch (hasher->type) {
case HASHER_SHA2:
sha256_Final(&hasher->ctx.sha2, hash);
break;
case HASHER_SHA2D:
sha256_Final(&hasher->ctx.sha2, hash);
hasher_Raw(HASHER_SHA2, hash, HASHER_DIGEST_LENGTH, hash);
break;
case HASHER_SHA2_RIPEMD:
sha256_Final(&hasher->ctx.sha2, hash);
ripemd160(hash, HASHER_DIGEST_LENGTH, hash);
break;
case HASHER_SHA3:
sha3_Final(&hasher->ctx.sha3, hash);
break;
#if USE_KECCAK
case HASHER_SHA3K:
keccak_Final(&hasher->ctx.sha3, hash);
break;
case HASHER_SHA3K:
keccak_Final(&hasher->ctx.sha3, hash);
break;
#endif
case HASHER_BLAKE:
blake256_Final(&hasher->ctx.blake, hash);
break;
case HASHER_BLAKED:
blake256_Final(&hasher->ctx.blake, hash);
hasher_Raw(HASHER_BLAKE, hash, HASHER_DIGEST_LENGTH, hash);
break;
case HASHER_BLAKE_RIPEMD:
blake256_Final(&hasher->ctx.blake, hash);
ripemd160(hash, HASHER_DIGEST_LENGTH, hash);
break;
case HASHER_GROESTLD_TRUNC:
groestl512_DoubleTrunc(&hasher->ctx.groestl, hash);
break;
case HASHER_BLAKE2B:
case HASHER_BLAKE2B_PERSONAL:
blake2b_Final(&hasher->ctx.blake2b, hash, 32);
break;
}
case HASHER_BLAKE:
blake256_Final(&hasher->ctx.blake, hash);
break;
case HASHER_BLAKED:
blake256_Final(&hasher->ctx.blake, hash);
hasher_Raw(HASHER_BLAKE, hash, HASHER_DIGEST_LENGTH, hash);
break;
case HASHER_BLAKE_RIPEMD:
blake256_Final(&hasher->ctx.blake, hash);
ripemd160(hash, HASHER_DIGEST_LENGTH, hash);
break;
case HASHER_GROESTLD_TRUNC:
groestl512_DoubleTrunc(&hasher->ctx.groestl, hash);
break;
case HASHER_BLAKE2B:
case HASHER_BLAKE2B_PERSONAL:
blake2b_Final(&hasher->ctx.blake2b, hash, 32);
break;
}
}
void hasher_Raw(HasherType type, const uint8_t *data, size_t length, uint8_t hash[HASHER_DIGEST_LENGTH]) {
Hasher hasher;
void hasher_Raw(HasherType type, const uint8_t *data, size_t length,
uint8_t hash[HASHER_DIGEST_LENGTH]) {
Hasher hasher;
hasher_Init(&hasher, type);
hasher_Update(&hasher, data, length);
hasher_Final(&hasher, hash);
hasher_Init(&hasher, type);
hasher_Update(&hasher, data, length);
hasher_Final(&hasher, hash);
}

@ -26,55 +26,57 @@
#include <stddef.h>
#include <stdint.h>
#include "sha2.h"
#include "sha3.h"
#include "blake256.h"
#include "groestl.h"
#include "blake2b.h"
#include "groestl.h"
#include "sha2.h"
#include "sha3.h"
#define HASHER_DIGEST_LENGTH 32
typedef enum {
HASHER_SHA2,
HASHER_SHA2D,
HASHER_SHA2_RIPEMD,
HASHER_SHA2,
HASHER_SHA2D,
HASHER_SHA2_RIPEMD,
HASHER_SHA3,
HASHER_SHA3,
#if USE_KECCAK
HASHER_SHA3K,
HASHER_SHA3K,
#endif
HASHER_BLAKE,
HASHER_BLAKED,
HASHER_BLAKE_RIPEMD,
HASHER_BLAKE,
HASHER_BLAKED,
HASHER_BLAKE_RIPEMD,
HASHER_GROESTLD_TRUNC, /* Double Groestl512 hasher truncated to 256 bits */
HASHER_GROESTLD_TRUNC, /* Double Groestl512 hasher truncated to 256 bits */
HASHER_BLAKE2B,
HASHER_BLAKE2B_PERSONAL,
HASHER_BLAKE2B,
HASHER_BLAKE2B_PERSONAL,
} HasherType;
typedef struct {
HasherType type;
HasherType type;
union {
SHA256_CTX sha2; // for HASHER_SHA2{,D}
SHA3_CTX sha3; // for HASHER_SHA3{,K}
BLAKE256_CTX blake; // for HASHER_BLAKE{,D}
GROESTL512_CTX groestl; // for HASHER_GROESTLD_TRUNC
BLAKE2B_CTX blake2b; // for HASHER_BLAKE2B{,_PERSONAL}
} ctx;
union {
SHA256_CTX sha2; // for HASHER_SHA2{,D}
SHA3_CTX sha3; // for HASHER_SHA3{,K}
BLAKE256_CTX blake; // for HASHER_BLAKE{,D}
GROESTL512_CTX groestl; // for HASHER_GROESTLD_TRUNC
BLAKE2B_CTX blake2b; // for HASHER_BLAKE2B{,_PERSONAL}
} ctx;
const void *param;
uint32_t param_size;
const void *param;
uint32_t param_size;
} Hasher;
void hasher_InitParam(Hasher *hasher, HasherType type, const void *param, uint32_t param_size);
void hasher_InitParam(Hasher *hasher, HasherType type, const void *param,
uint32_t param_size);
void hasher_Init(Hasher *hasher, HasherType type);
void hasher_Reset(Hasher *hasher);
void hasher_Update(Hasher *hasher, const uint8_t *data, size_t length);
void hasher_Final(Hasher *hasher, uint8_t hash[HASHER_DIGEST_LENGTH]);
void hasher_Raw(HasherType type, const uint8_t *data, size_t length, uint8_t hash[HASHER_DIGEST_LENGTH]);
void hasher_Raw(HasherType type, const uint8_t *data, size_t length,
uint8_t hash[HASHER_DIGEST_LENGTH]);
#endif

248
hmac.c

@ -24,155 +24,153 @@
#include <string.h>
#include "hmac.h"
#include "options.h"
#include "memzero.h"
#include "options.h"
void hmac_sha256_Init(HMAC_SHA256_CTX *hctx, const uint8_t *key, const uint32_t keylen)
{
static CONFIDENTIAL uint8_t i_key_pad[SHA256_BLOCK_LENGTH];
memzero(i_key_pad, SHA256_BLOCK_LENGTH);
if (keylen > SHA256_BLOCK_LENGTH) {
sha256_Raw(key, keylen, i_key_pad);
} else {
memcpy(i_key_pad, key, keylen);
}
for (int i = 0; i < SHA256_BLOCK_LENGTH; i++) {
hctx->o_key_pad[i] = i_key_pad[i] ^ 0x5c;
i_key_pad[i] ^= 0x36;
}
sha256_Init(&(hctx->ctx));
sha256_Update(&(hctx->ctx), i_key_pad, SHA256_BLOCK_LENGTH);
memzero(i_key_pad, sizeof(i_key_pad));
void hmac_sha256_Init(HMAC_SHA256_CTX *hctx, const uint8_t *key,
const uint32_t keylen) {
static CONFIDENTIAL uint8_t i_key_pad[SHA256_BLOCK_LENGTH];
memzero(i_key_pad, SHA256_BLOCK_LENGTH);
if (keylen > SHA256_BLOCK_LENGTH) {
sha256_Raw(key, keylen, i_key_pad);
} else {
memcpy(i_key_pad, key, keylen);
}
for (int i = 0; i < SHA256_BLOCK_LENGTH; i++) {
hctx->o_key_pad[i] = i_key_pad[i] ^ 0x5c;
i_key_pad[i] ^= 0x36;
}
sha256_Init(&(hctx->ctx));
sha256_Update(&(hctx->ctx), i_key_pad, SHA256_BLOCK_LENGTH);
memzero(i_key_pad, sizeof(i_key_pad));
}
void hmac_sha256_Update(HMAC_SHA256_CTX *hctx, const uint8_t *msg, const uint32_t msglen)
{
sha256_Update(&(hctx->ctx), msg, msglen);
void hmac_sha256_Update(HMAC_SHA256_CTX *hctx, const uint8_t *msg,
const uint32_t msglen) {
sha256_Update(&(hctx->ctx), msg, msglen);
}
void hmac_sha256_Final(HMAC_SHA256_CTX *hctx, uint8_t *hmac)
{
sha256_Final(&(hctx->ctx), hmac);
sha256_Init(&(hctx->ctx));
sha256_Update(&(hctx->ctx), hctx->o_key_pad, SHA256_BLOCK_LENGTH);
sha256_Update(&(hctx->ctx), hmac, SHA256_DIGEST_LENGTH);
sha256_Final(&(hctx->ctx), hmac);
memzero(hctx, sizeof(HMAC_SHA256_CTX));
void hmac_sha256_Final(HMAC_SHA256_CTX *hctx, uint8_t *hmac) {
sha256_Final(&(hctx->ctx), hmac);
sha256_Init(&(hctx->ctx));
sha256_Update(&(hctx->ctx), hctx->o_key_pad, SHA256_BLOCK_LENGTH);
sha256_Update(&(hctx->ctx), hmac, SHA256_DIGEST_LENGTH);
sha256_Final(&(hctx->ctx), hmac);
memzero(hctx, sizeof(HMAC_SHA256_CTX));
}
void hmac_sha256(const uint8_t *key, const uint32_t keylen, const uint8_t *msg, const uint32_t msglen, uint8_t *hmac)
{
static CONFIDENTIAL HMAC_SHA256_CTX hctx;
hmac_sha256_Init(&hctx, key, keylen);
hmac_sha256_Update(&hctx, msg, msglen);
hmac_sha256_Final(&hctx, hmac);
void hmac_sha256(const uint8_t *key, const uint32_t keylen, const uint8_t *msg,
const uint32_t msglen, uint8_t *hmac) {
static CONFIDENTIAL HMAC_SHA256_CTX hctx;
hmac_sha256_Init(&hctx, key, keylen);
hmac_sha256_Update(&hctx, msg, msglen);
hmac_sha256_Final(&hctx, hmac);
}
void hmac_sha256_prepare(const uint8_t *key, const uint32_t keylen, uint32_t *opad_digest, uint32_t *ipad_digest)
{
static CONFIDENTIAL uint32_t key_pad[SHA256_BLOCK_LENGTH/sizeof(uint32_t)];
memzero(key_pad, sizeof(key_pad));
if (keylen > SHA256_BLOCK_LENGTH) {
static CONFIDENTIAL SHA256_CTX context;
sha256_Init(&context);
sha256_Update(&context, key, keylen);
sha256_Final(&context, (uint8_t*)key_pad);
} else {
memcpy(key_pad, key, keylen);
}
/* compute o_key_pad and its digest */
for (int i = 0; i < SHA256_BLOCK_LENGTH/(int)sizeof(uint32_t); i++) {
uint32_t data;
void hmac_sha256_prepare(const uint8_t *key, const uint32_t keylen,
uint32_t *opad_digest, uint32_t *ipad_digest) {
static CONFIDENTIAL uint32_t key_pad[SHA256_BLOCK_LENGTH / sizeof(uint32_t)];
memzero(key_pad, sizeof(key_pad));
if (keylen > SHA256_BLOCK_LENGTH) {
static CONFIDENTIAL SHA256_CTX context;
sha256_Init(&context);
sha256_Update(&context, key, keylen);
sha256_Final(&context, (uint8_t *)key_pad);
} else {
memcpy(key_pad, key, keylen);
}
/* compute o_key_pad and its digest */
for (int i = 0; i < SHA256_BLOCK_LENGTH / (int)sizeof(uint32_t); i++) {
uint32_t data;
#if BYTE_ORDER == LITTLE_ENDIAN
REVERSE32(key_pad[i], data);
REVERSE32(key_pad[i], data);
#else
data = key_pad[i];
data = key_pad[i];
#endif
key_pad[i] = data ^ 0x5c5c5c5c;
}
sha256_Transform(sha256_initial_hash_value, key_pad, opad_digest);
/* convert o_key_pad to i_key_pad and compute its digest */
for (int i = 0; i < SHA256_BLOCK_LENGTH/(int)sizeof(uint32_t); i++) {
key_pad[i] = key_pad[i] ^ 0x5c5c5c5c ^ 0x36363636;
}
sha256_Transform(sha256_initial_hash_value, key_pad, ipad_digest);
memzero(key_pad, sizeof(key_pad));
key_pad[i] = data ^ 0x5c5c5c5c;
}
sha256_Transform(sha256_initial_hash_value, key_pad, opad_digest);
/* convert o_key_pad to i_key_pad and compute its digest */
for (int i = 0; i < SHA256_BLOCK_LENGTH / (int)sizeof(uint32_t); i++) {
key_pad[i] = key_pad[i] ^ 0x5c5c5c5c ^ 0x36363636;
}
sha256_Transform(sha256_initial_hash_value, key_pad, ipad_digest);
memzero(key_pad, sizeof(key_pad));
}
void hmac_sha512_Init(HMAC_SHA512_CTX *hctx, const uint8_t *key, const uint32_t keylen)
{
static CONFIDENTIAL uint8_t i_key_pad[SHA512_BLOCK_LENGTH];
memzero(i_key_pad, SHA512_BLOCK_LENGTH);
if (keylen > SHA512_BLOCK_LENGTH) {
sha512_Raw(key, keylen, i_key_pad);
} else {
memcpy(i_key_pad, key, keylen);
}
for (int i = 0; i < SHA512_BLOCK_LENGTH; i++) {
hctx->o_key_pad[i] = i_key_pad[i] ^ 0x5c;
i_key_pad[i] ^= 0x36;
}
sha512_Init(&(hctx->ctx));
sha512_Update(&(hctx->ctx), i_key_pad, SHA512_BLOCK_LENGTH);
memzero(i_key_pad, sizeof(i_key_pad));
void hmac_sha512_Init(HMAC_SHA512_CTX *hctx, const uint8_t *key,
const uint32_t keylen) {
static CONFIDENTIAL uint8_t i_key_pad[SHA512_BLOCK_LENGTH];
memzero(i_key_pad, SHA512_BLOCK_LENGTH);
if (keylen > SHA512_BLOCK_LENGTH) {
sha512_Raw(key, keylen, i_key_pad);
} else {
memcpy(i_key_pad, key, keylen);
}
for (int i = 0; i < SHA512_BLOCK_LENGTH; i++) {
hctx->o_key_pad[i] = i_key_pad[i] ^ 0x5c;
i_key_pad[i] ^= 0x36;
}
sha512_Init(&(hctx->ctx));
sha512_Update(&(hctx->ctx), i_key_pad, SHA512_BLOCK_LENGTH);
memzero(i_key_pad, sizeof(i_key_pad));
}
void hmac_sha512_Update(HMAC_SHA512_CTX *hctx, const uint8_t *msg, const uint32_t msglen)
{
sha512_Update(&(hctx->ctx), msg, msglen);
void hmac_sha512_Update(HMAC_SHA512_CTX *hctx, const uint8_t *msg,
const uint32_t msglen) {
sha512_Update(&(hctx->ctx), msg, msglen);
}
void hmac_sha512_Final(HMAC_SHA512_CTX *hctx, uint8_t *hmac)
{
sha512_Final(&(hctx->ctx), hmac);
sha512_Init(&(hctx->ctx));
sha512_Update(&(hctx->ctx), hctx->o_key_pad, SHA512_BLOCK_LENGTH);
sha512_Update(&(hctx->ctx), hmac, SHA512_DIGEST_LENGTH);
sha512_Final(&(hctx->ctx), hmac);
memzero(hctx, sizeof(HMAC_SHA512_CTX));
void hmac_sha512_Final(HMAC_SHA512_CTX *hctx, uint8_t *hmac) {
sha512_Final(&(hctx->ctx), hmac);
sha512_Init(&(hctx->ctx));
sha512_Update(&(hctx->ctx), hctx->o_key_pad, SHA512_BLOCK_LENGTH);
sha512_Update(&(hctx->ctx), hmac, SHA512_DIGEST_LENGTH);
sha512_Final(&(hctx->ctx), hmac);
memzero(hctx, sizeof(HMAC_SHA512_CTX));
}
void hmac_sha512(const uint8_t *key, const uint32_t keylen, const uint8_t *msg, const uint32_t msglen, uint8_t *hmac)
{
HMAC_SHA512_CTX hctx;
hmac_sha512_Init(&hctx, key, keylen);
hmac_sha512_Update(&hctx, msg, msglen);
hmac_sha512_Final(&hctx, hmac);
void hmac_sha512(const uint8_t *key, const uint32_t keylen, const uint8_t *msg,
const uint32_t msglen, uint8_t *hmac) {
HMAC_SHA512_CTX hctx;
hmac_sha512_Init(&hctx, key, keylen);
hmac_sha512_Update(&hctx, msg, msglen);
hmac_sha512_Final(&hctx, hmac);
}
void hmac_sha512_prepare(const uint8_t *key, const uint32_t keylen, uint64_t *opad_digest, uint64_t *ipad_digest)
{
static CONFIDENTIAL uint64_t key_pad[SHA512_BLOCK_LENGTH/sizeof(uint64_t)];
memzero(key_pad, sizeof(key_pad));
if (keylen > SHA512_BLOCK_LENGTH) {
static CONFIDENTIAL SHA512_CTX context;
sha512_Init(&context);
sha512_Update(&context, key, keylen);
sha512_Final(&context, (uint8_t*)key_pad);
} else {
memcpy(key_pad, key, keylen);
}
/* compute o_key_pad and its digest */
for (int i = 0; i < SHA512_BLOCK_LENGTH/(int)sizeof(uint64_t); i++) {
uint64_t data;
void hmac_sha512_prepare(const uint8_t *key, const uint32_t keylen,
uint64_t *opad_digest, uint64_t *ipad_digest) {
static CONFIDENTIAL uint64_t key_pad[SHA512_BLOCK_LENGTH / sizeof(uint64_t)];
memzero(key_pad, sizeof(key_pad));
if (keylen > SHA512_BLOCK_LENGTH) {
static CONFIDENTIAL SHA512_CTX context;
sha512_Init(&context);
sha512_Update(&context, key, keylen);
sha512_Final(&context, (uint8_t *)key_pad);
} else {
memcpy(key_pad, key, keylen);
}
/* compute o_key_pad and its digest */
for (int i = 0; i < SHA512_BLOCK_LENGTH / (int)sizeof(uint64_t); i++) {
uint64_t data;
#if BYTE_ORDER == LITTLE_ENDIAN
REVERSE64(key_pad[i], data);
REVERSE64(key_pad[i], data);
#else
data = key_pad[i];
data = key_pad[i];
#endif
key_pad[i] = data ^ 0x5c5c5c5c5c5c5c5c;
}
sha512_Transform(sha512_initial_hash_value, key_pad, opad_digest);
/* convert o_key_pad to i_key_pad and compute its digest */
for (int i = 0; i < SHA512_BLOCK_LENGTH/(int)sizeof(uint64_t); i++) {
key_pad[i] = key_pad[i] ^ 0x5c5c5c5c5c5c5c5c ^ 0x3636363636363636;
}
sha512_Transform(sha512_initial_hash_value, key_pad, ipad_digest);
memzero(key_pad, sizeof(key_pad));
key_pad[i] = data ^ 0x5c5c5c5c5c5c5c5c;
}
sha512_Transform(sha512_initial_hash_value, key_pad, opad_digest);
/* convert o_key_pad to i_key_pad and compute its digest */
for (int i = 0; i < SHA512_BLOCK_LENGTH / (int)sizeof(uint64_t); i++) {
key_pad[i] = key_pad[i] ^ 0x5c5c5c5c5c5c5c5c ^ 0x3636363636363636;
}
sha512_Transform(sha512_initial_hash_value, key_pad, ipad_digest);
memzero(key_pad, sizeof(key_pad));
}

@ -28,25 +28,33 @@
#include "sha2.h"
typedef struct _HMAC_SHA256_CTX {
uint8_t o_key_pad[SHA256_BLOCK_LENGTH];
SHA256_CTX ctx;
uint8_t o_key_pad[SHA256_BLOCK_LENGTH];
SHA256_CTX ctx;
} HMAC_SHA256_CTX;
typedef struct _HMAC_SHA512_CTX {
uint8_t o_key_pad[SHA512_BLOCK_LENGTH];
SHA512_CTX ctx;
uint8_t o_key_pad[SHA512_BLOCK_LENGTH];
SHA512_CTX ctx;
} HMAC_SHA512_CTX;
void hmac_sha256_Init(HMAC_SHA256_CTX *hctx, const uint8_t *key, const uint32_t keylen);
void hmac_sha256_Update(HMAC_SHA256_CTX *hctx, const uint8_t *msg, const uint32_t msglen);
void hmac_sha256_Init(HMAC_SHA256_CTX *hctx, const uint8_t *key,
const uint32_t keylen);
void hmac_sha256_Update(HMAC_SHA256_CTX *hctx, const uint8_t *msg,
const uint32_t msglen);
void hmac_sha256_Final(HMAC_SHA256_CTX *hctx, uint8_t *hmac);
void hmac_sha256(const uint8_t *key, const uint32_t keylen, const uint8_t *msg, const uint32_t msglen, uint8_t *hmac);
void hmac_sha256_prepare(const uint8_t *key, const uint32_t keylen, uint32_t *opad_digest, uint32_t *ipad_digest);
void hmac_sha256(const uint8_t *key, const uint32_t keylen, const uint8_t *msg,
const uint32_t msglen, uint8_t *hmac);
void hmac_sha256_prepare(const uint8_t *key, const uint32_t keylen,
uint32_t *opad_digest, uint32_t *ipad_digest);
void hmac_sha512_Init(HMAC_SHA512_CTX *hctx, const uint8_t *key, const uint32_t keylen);
void hmac_sha512_Update(HMAC_SHA512_CTX *hctx, const uint8_t *msg, const uint32_t msglen);
void hmac_sha512_Init(HMAC_SHA512_CTX *hctx, const uint8_t *key,
const uint32_t keylen);
void hmac_sha512_Update(HMAC_SHA512_CTX *hctx, const uint8_t *msg,
const uint32_t msglen);
void hmac_sha512_Final(HMAC_SHA512_CTX *hctx, uint8_t *hmac);
void hmac_sha512(const uint8_t *key, const uint32_t keylen, const uint8_t *msg, const uint32_t msglen, uint8_t *hmac);
void hmac_sha512_prepare(const uint8_t *key, const uint32_t keylen, uint64_t *opad_digest, uint64_t *ipad_digest);
void hmac_sha512(const uint8_t *key, const uint32_t keylen, const uint8_t *msg,
const uint32_t msglen, uint8_t *hmac);
void hmac_sha512_prepare(const uint8_t *key, const uint32_t keylen,
uint64_t *opad_digest, uint64_t *ipad_digest);
#endif

@ -1,5 +1,5 @@
#ifndef __STDC_WANT_LIB_EXT1__
#define __STDC_WANT_LIB_EXT1__ 1 // C11's bounds-checking interface.
#define __STDC_WANT_LIB_EXT1__ 1 // C11's bounds-checking interface.
#endif
#include <string.h>
@ -18,12 +18,13 @@
#endif
// GNU C Library version 2.25 or later.
#if defined(__GLIBC__) && (__GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 25))
#if defined(__GLIBC__) && \
(__GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 25))
#define HAVE_EXPLICIT_BZERO 1
#endif
// Newlib
#if defined( __NEWLIB__)
#if defined(__NEWLIB__)
#define HAVE_EXPLICIT_BZERO 1
#endif
@ -42,25 +43,24 @@
#define HAVE_EXPLICIT_MEMSET 1
#endif
// Adapted from https://github.com/jedisct1/libsodium/blob/1647f0d53ae0e370378a9195477e3df0a792408f/src/libsodium/sodium/utils.c#L102-L130
// Adapted from
// https://github.com/jedisct1/libsodium/blob/1647f0d53ae0e370378a9195477e3df0a792408f/src/libsodium/sodium/utils.c#L102-L130
void memzero(void *const pnt, const size_t len)
{
void memzero(void *const pnt, const size_t len) {
#ifdef _WIN32
SecureZeroMemory(pnt, len);
SecureZeroMemory(pnt, len);
#elif defined(HAVE_MEMSET_S)
memset_s(pnt, (rsize_t) len, 0, (rsize_t) len);
memset_s(pnt, (rsize_t)len, 0, (rsize_t)len);
#elif defined(HAVE_EXPLICIT_BZERO)
explicit_bzero(pnt, len);
explicit_bzero(pnt, len);
#elif defined(HAVE_EXPLICIT_MEMSET)
explicit_memset(pnt, 0, len);
explicit_memset(pnt, 0, len);
#else
volatile unsigned char *volatile pnt_ =
(volatile unsigned char *volatile) pnt;
size_t i = (size_t) 0U;
volatile unsigned char *volatile pnt_ = (volatile unsigned char *volatile)pnt;
size_t i = (size_t)0U;
while (i < len) {
pnt_[i++] = 0U;
}
while (i < len) {
pnt_[i++] = 0U;
}
#endif
}

@ -3,6 +3,6 @@
#include <stddef.h>
void memzero(void * const pnt, const size_t len);
void memzero(void* const pnt, const size_t len);
#endif

@ -14,8 +14,8 @@
#endif
#include "base58.h"
#include "range_proof.h"
#include "serialize.h"
#include "xmr.h"
#include "range_proof.h"
#endif //TREZOR_CRYPTO_MONERO_H
#endif // TREZOR_CRYPTO_MONERO_H

@ -4,112 +4,112 @@
#include "range_proof.h"
static void xmr_hash_ge25519_to_scalar(bignum256modm r, const ge25519 *p){
unsigned char buff[32];
ge25519_pack(buff, p);
xmr_hash_to_scalar(r, buff, sizeof(buff));
static void xmr_hash_ge25519_to_scalar(bignum256modm r, const ge25519 *p) {
unsigned char buff[32];
ge25519_pack(buff, p);
xmr_hash_to_scalar(r, buff, sizeof(buff));
}
void xmr_gen_range_sig(xmr_range_sig_t * sig, ge25519 * C, bignum256modm mask, xmr_amount amount, bignum256modm * last_mask){
bignum256modm ai[64];
bignum256modm alpha[64];
xmr_gen_range_sig_ex(sig, C, mask, amount, last_mask, ai, alpha);
void xmr_gen_range_sig(xmr_range_sig_t *sig, ge25519 *C, bignum256modm mask,
xmr_amount amount, bignum256modm *last_mask) {
bignum256modm ai[64];
bignum256modm alpha[64];
xmr_gen_range_sig_ex(sig, C, mask, amount, last_mask, ai, alpha);
}
void xmr_gen_range_sig_ex(xmr_range_sig_t * sig, ge25519 * C, bignum256modm mask, xmr_amount amount, bignum256modm * last_mask,
bignum256modm ai[64], bignum256modm alpha[64])
{
const unsigned n = XMR_ATOMS;
bignum256modm a={0};
bignum256modm si={0};
bignum256modm c={0};
bignum256modm ee={0};
unsigned char buff[32];
void xmr_gen_range_sig_ex(xmr_range_sig_t *sig, ge25519 *C, bignum256modm mask,
xmr_amount amount, bignum256modm *last_mask,
bignum256modm ai[64], bignum256modm alpha[64]) {
const unsigned n = XMR_ATOMS;
bignum256modm a = {0};
bignum256modm si = {0};
bignum256modm c = {0};
bignum256modm ee = {0};
unsigned char buff[32];
Hasher kck;
xmr_hasher_init(&kck);
Hasher kck;
xmr_hasher_init(&kck);
ge25519 C_acc;
ge25519 C_h;
ge25519 C_tmp;
ge25519 L;
ge25519 Zero;
ge25519 C_acc;
ge25519 C_h;
ge25519 C_tmp;
ge25519 L;
ge25519 Zero;
ge25519_set_neutral(&Zero);
ge25519_set_neutral(&C_acc);
ge25519_set_xmr_h(&C_h);
set256_modm(a, 0);
ge25519_set_neutral(&Zero);
ge25519_set_neutral(&C_acc);
ge25519_set_xmr_h(&C_h);
set256_modm(a, 0);
#define BB(i) ((amount>>(i)) & 1)
#define BB(i) ((amount >> (i)) & 1)
// First pass, generates: ai, alpha, Ci, ee, s1
for(unsigned ii=0; ii<n; ++ii){
xmr_random_scalar(ai[ii]);
if (last_mask != NULL && ii == n - 1){
sub256_modm(ai[ii], *last_mask, a);
}
// First pass, generates: ai, alpha, Ci, ee, s1
for (unsigned ii = 0; ii < n; ++ii) {
xmr_random_scalar(ai[ii]);
if (last_mask != NULL && ii == n - 1) {
sub256_modm(ai[ii], *last_mask, a);
}
add256_modm(a, a, ai[ii]); // creating the total mask since you have to pass this to receiver...
xmr_random_scalar(alpha[ii]);
add256_modm(a, a, ai[ii]); // creating the total mask since you have to
// pass this to receiver...
xmr_random_scalar(alpha[ii]);
ge25519_scalarmult_base_niels(&L, ge25519_niels_base_multiples, alpha[ii]);
ge25519_scalarmult_base_niels(&C_tmp, ge25519_niels_base_multiples, ai[ii]);
ge25519_scalarmult_base_niels(&L, ge25519_niels_base_multiples, alpha[ii]);
ge25519_scalarmult_base_niels(&C_tmp, ge25519_niels_base_multiples, ai[ii]);
// C_tmp += &Zero if BB(ii) == 0 else &C_h
ge25519_add(&C_tmp, &C_tmp, BB(ii) == 0 ? &Zero : &C_h, 0);
ge25519_add(&C_acc, &C_acc, &C_tmp, 0);
// C_tmp += &Zero if BB(ii) == 0 else &C_h
ge25519_add(&C_tmp, &C_tmp, BB(ii) == 0 ? &Zero : &C_h, 0);
ge25519_add(&C_acc, &C_acc, &C_tmp, 0);
// Set Ci[ii] to sigs
ge25519_pack(sig->Ci[ii], &C_tmp);
// Set Ci[ii] to sigs
ge25519_pack(sig->Ci[ii], &C_tmp);
if (BB(ii) == 0) {
xmr_random_scalar(si);
xmr_hash_ge25519_to_scalar(c, &L);
if (BB(ii) == 0) {
xmr_random_scalar(si);
xmr_hash_ge25519_to_scalar(c, &L);
ge25519_add(&C_tmp, &C_tmp, &C_h, 1); // Ci[ii] -= c_h
xmr_add_keys2_vartime(&L, si, c, &C_tmp);
ge25519_add(&C_tmp, &C_tmp, &C_h, 1); // Ci[ii] -= c_h
xmr_add_keys2_vartime(&L, si, c, &C_tmp);
// Set s1[ii] to sigs
contract256_modm(sig->asig.s1[ii], si);
}
// Set s1[ii] to sigs
contract256_modm(sig->asig.s1[ii], si);
}
ge25519_pack(buff, &L);
xmr_hasher_update(&kck, buff, sizeof(buff));
ge25519_pack(buff, &L);
xmr_hasher_update(&kck, buff, sizeof(buff));
ge25519_double(&C_h, &C_h); // c_H = crypto.scalarmult(c_H, 2)
}
ge25519_double(&C_h, &C_h); // c_H = crypto.scalarmult(c_H, 2)
}
// Compute ee
xmr_hasher_final(&kck, buff);
expand256_modm(ee, buff, sizeof(buff));
// Compute ee
xmr_hasher_final(&kck, buff);
expand256_modm(ee, buff, sizeof(buff));
ge25519_set_xmr_h(&C_h);
ge25519_set_xmr_h(&C_h);
// Second pass, s0, s1
for(unsigned ii=0; ii<n; ++ii){
if (BB(ii) == 0){
mulsub256_modm(si, ai[ii], ee, alpha[ii]);
contract256_modm(sig->asig.s0[ii], si);
// Second pass, s0, s1
for (unsigned ii = 0; ii < n; ++ii) {
if (BB(ii) == 0) {
mulsub256_modm(si, ai[ii], ee, alpha[ii]);
contract256_modm(sig->asig.s0[ii], si);
} else {
xmr_random_scalar(si);
contract256_modm(sig->asig.s0[ii], si);
} else {
xmr_random_scalar(si);
contract256_modm(sig->asig.s0[ii], si);
ge25519_unpack_vartime(&C_tmp, sig->Ci[ii]);
xmr_add_keys2_vartime(&L, si, ee, &C_tmp);
xmr_hash_ge25519_to_scalar(c, &L);
ge25519_unpack_vartime(&C_tmp, sig->Ci[ii]);
xmr_add_keys2_vartime(&L, si, ee, &C_tmp);
xmr_hash_ge25519_to_scalar(c, &L);
mulsub256_modm(si, ai[ii], c, alpha[ii]);
contract256_modm(sig->asig.s1[ii], si);
}
mulsub256_modm(si, ai[ii], c, alpha[ii]);
contract256_modm(sig->asig.s1[ii], si);
}
ge25519_double(&C_h, &C_h); // c_H = crypto.scalarmult(c_H, 2)
}
ge25519_double(&C_h, &C_h); // c_H = crypto.scalarmult(c_H, 2)
}
ge25519_copy(C, &C_acc);
copy256_modm(mask, a);
contract256_modm(sig->asig.ee, ee);
ge25519_copy(C, &C_acc);
copy256_modm(mask, a);
contract256_modm(sig->asig.ee, ee);
#undef BB
}

@ -12,19 +12,20 @@ typedef uint64_t xmr_amount;
typedef xmr_key_t xmr_key64_t[64];
typedef struct xmr_boro_sig {
xmr_key64_t s0;
xmr_key64_t s1;
xmr_key_t ee;
xmr_key64_t s0;
xmr_key64_t s1;
xmr_key_t ee;
} xmr_boro_sig_t;
typedef struct range_sig {
xmr_boro_sig_t asig;
xmr_key64_t Ci;
xmr_boro_sig_t asig;
xmr_key64_t Ci;
} xmr_range_sig_t;
void xmr_gen_range_sig(xmr_range_sig_t * sig, ge25519 * C, bignum256modm mask, xmr_amount amount, bignum256modm * last_mask);
void xmr_gen_range_sig_ex(xmr_range_sig_t * sig, ge25519 * C, bignum256modm mask, xmr_amount amount, bignum256modm * last_mask,
void xmr_gen_range_sig(xmr_range_sig_t* sig, ge25519* C, bignum256modm mask,
xmr_amount amount, bignum256modm* last_mask);
void xmr_gen_range_sig_ex(xmr_range_sig_t* sig, ge25519* C, bignum256modm mask,
xmr_amount amount, bignum256modm* last_mask,
bignum256modm ai[64], bignum256modm alpha[64]);
#endif //TREZOR_CRYPTO_RANGE_PROOF_H
#endif // TREZOR_CRYPTO_RANGE_PROOF_H

@ -4,51 +4,50 @@
#include "serialize.h"
int xmr_size_varint(uint64_t num){
int ctr = 1;
while (num >= 0x80) {
++ctr;
num >>= 7;
}
return ctr;
int xmr_size_varint(uint64_t num) {
int ctr = 1;
while (num >= 0x80) {
++ctr;
num >>= 7;
}
return ctr;
}
int xmr_write_varint(uint8_t * buff, size_t buff_size, uint64_t num){
unsigned ctr = 0;
while (num >= 0x80 && ctr < buff_size) {
*buff = (uint8_t) (((num) & 0x7f) | 0x80);
++buff;
++ctr;
num >>= 7;
}
/* writes the last one to dest */
if (ctr < buff_size) {
*buff = (uint8_t) num;
++ctr;
}
return ctr <= buff_size ? (int)ctr : -1;
int xmr_write_varint(uint8_t *buff, size_t buff_size, uint64_t num) {
unsigned ctr = 0;
while (num >= 0x80 && ctr < buff_size) {
*buff = (uint8_t)(((num)&0x7f) | 0x80);
++buff;
++ctr;
num >>= 7;
}
/* writes the last one to dest */
if (ctr < buff_size) {
*buff = (uint8_t)num;
++ctr;
}
return ctr <= buff_size ? (int)ctr : -1;
}
int xmr_read_varint(uint8_t * buff, size_t buff_size, uint64_t *val) {
unsigned read = 0;
int finished_ok = 0;
*val = 0;
for (int shift = 0; read < buff_size; shift += 7, ++read) {
uint8_t byte = buff[read];
if (byte == 0 && shift != 0) {
return -1;
}
*val |= (uint64_t)(byte & 0x7f) << shift;
/* If there is no next */
if ((byte & 0x80) == 0) {
finished_ok = 1;
break;
}
}
return finished_ok ? (int)read + 1 : -2;
int xmr_read_varint(uint8_t *buff, size_t buff_size, uint64_t *val) {
unsigned read = 0;
int finished_ok = 0;
*val = 0;
for (int shift = 0; read < buff_size; shift += 7, ++read) {
uint8_t byte = buff[read];
if (byte == 0 && shift != 0) {
return -1;
}
*val |= (uint64_t)(byte & 0x7f) << shift;
/* If there is no next */
if ((byte & 0x80) == 0) {
finished_ok = 1;
break;
}
}
return finished_ok ? (int)read + 1 : -2;
}

@ -9,7 +9,7 @@
#include <stdint.h>
int xmr_size_varint(uint64_t num);
int xmr_write_varint(uint8_t * buff, size_t buff_size, uint64_t num);
int xmr_read_varint(uint8_t * buff, size_t buff_size, uint64_t *val);
int xmr_write_varint(uint8_t *buff, size_t buff_size, uint64_t num);
int xmr_read_varint(uint8_t *buff, size_t buff_size, uint64_t *val);
#endif //TREZOR_XMR_SERIALIZE_H
#endif // TREZOR_XMR_SERIALIZE_H

@ -4,133 +4,140 @@
#include "xmr.h"
#include "int-util.h"
#include "serialize.h"
#include "rand.h"
#include "serialize.h"
const ge25519 ALIGN(16) xmr_h = {
{0x1861ec7, 0x1ceac77, 0x2f11626, 0x1f261d3, 0x346107c, 0x06d8c4a, 0x254201d, 0x1675c09, 0x1301c3f, 0x0211d73},
{0x326feb4, 0x12e30cc, 0x0cf54b4, 0x1117305, 0x318f5d5, 0x06cf754, 0x2e578a1, 0x1daf058, 0x34430a1, 0x04410e9},
{0x0fde4d2, 0x0774049, 0x22ca951, 0x05aec2b, 0x07a36a5, 0x1394f13, 0x3c5385c, 0x1adb924, 0x2b6c581, 0x0a55fa4},
{0x24517f7, 0x05ee936, 0x3acf5d9, 0x14b08aa, 0x3363738, 0x1051745, 0x360601e, 0x0f3f2c9, 0x1ead2cd, 0x1d3e3df}
};
{0x1861ec7, 0x1ceac77, 0x2f11626, 0x1f261d3, 0x346107c, 0x06d8c4a,
0x254201d, 0x1675c09, 0x1301c3f, 0x0211d73},
{0x326feb4, 0x12e30cc, 0x0cf54b4, 0x1117305, 0x318f5d5, 0x06cf754,
0x2e578a1, 0x1daf058, 0x34430a1, 0x04410e9},
{0x0fde4d2, 0x0774049, 0x22ca951, 0x05aec2b, 0x07a36a5, 0x1394f13,
0x3c5385c, 0x1adb924, 0x2b6c581, 0x0a55fa4},
{0x24517f7, 0x05ee936, 0x3acf5d9, 0x14b08aa, 0x3363738, 0x1051745,
0x360601e, 0x0f3f2c9, 0x1ead2cd, 0x1d3e3df}};
void ge25519_set_xmr_h(ge25519 *r) { ge25519_copy(r, &xmr_h); }
void ge25519_set_xmr_h(ge25519 *r){
ge25519_copy(r, &xmr_h);
void xmr_random_scalar(bignum256modm m) {
unsigned char buff[32] = {0};
random_buffer(buff, sizeof(buff));
expand256_modm(m, buff, sizeof(buff));
}
void xmr_random_scalar(bignum256modm m){
unsigned char buff[32]={0};
random_buffer(buff, sizeof(buff));
expand256_modm(m, buff, sizeof(buff));
void xmr_fast_hash(uint8_t *hash, const void *data, size_t length) {
hasher_Raw(HASHER_SHA3K, data, length, hash);
}
void xmr_fast_hash(uint8_t * hash, const void *data, size_t length){
hasher_Raw(HASHER_SHA3K, data, length, hash);
}
void xmr_hasher_init(Hasher * hasher){
hasher_Init(hasher, HASHER_SHA3K);
}
void xmr_hasher_init(Hasher *hasher) { hasher_Init(hasher, HASHER_SHA3K); }
void xmr_hasher_update(Hasher * hasher, const void *data, size_t length){
hasher_Update(hasher, data, length);
void xmr_hasher_update(Hasher *hasher, const void *data, size_t length) {
hasher_Update(hasher, data, length);
}
void xmr_hasher_final(Hasher * hasher, uint8_t * hash){
hasher_Final(hasher, hash);
void xmr_hasher_final(Hasher *hasher, uint8_t *hash) {
hasher_Final(hasher, hash);
}
void xmr_hasher_copy(Hasher * dst, const Hasher * src){
memcpy(dst, src, sizeof(Hasher));
void xmr_hasher_copy(Hasher *dst, const Hasher *src) {
memcpy(dst, src, sizeof(Hasher));
}
void xmr_hash_to_scalar(bignum256modm r, const void *data, size_t length){
uint8_t hash[HASHER_DIGEST_LENGTH];
hasher_Raw(HASHER_SHA3K, data, length, hash);
expand256_modm(r, hash, HASHER_DIGEST_LENGTH);
void xmr_hash_to_scalar(bignum256modm r, const void *data, size_t length) {
uint8_t hash[HASHER_DIGEST_LENGTH];
hasher_Raw(HASHER_SHA3K, data, length, hash);
expand256_modm(r, hash, HASHER_DIGEST_LENGTH);
}
void xmr_hash_to_ec(ge25519 *P, const void *data, size_t length){
ge25519 point2;
uint8_t hash[HASHER_DIGEST_LENGTH];
hasher_Raw(HASHER_SHA3K, data, length, hash);
void xmr_hash_to_ec(ge25519 *P, const void *data, size_t length) {
ge25519 point2;
uint8_t hash[HASHER_DIGEST_LENGTH];
hasher_Raw(HASHER_SHA3K, data, length, hash);
ge25519_fromfe_frombytes_vartime(&point2, hash);
ge25519_mul8(P, &point2);
ge25519_fromfe_frombytes_vartime(&point2, hash);
ge25519_mul8(P, &point2);
}
void xmr_derivation_to_scalar(bignum256modm s, const ge25519 * p, uint32_t output_index){
uint8_t buff[32 + 8];
ge25519_pack(buff, p);
int written = xmr_write_varint(buff + 32, 8, output_index);
xmr_hash_to_scalar(s, buff, 32u + written);
void xmr_derivation_to_scalar(bignum256modm s, const ge25519 *p,
uint32_t output_index) {
uint8_t buff[32 + 8];
ge25519_pack(buff, p);
int written = xmr_write_varint(buff + 32, 8, output_index);
xmr_hash_to_scalar(s, buff, 32u + written);
}
void xmr_generate_key_derivation(ge25519 * r, const ge25519 * A, const bignum256modm b){
ge25519 bA;
ge25519_scalarmult(&bA, A, b);
ge25519_mul8(r, &bA);
void xmr_generate_key_derivation(ge25519 *r, const ge25519 *A,
const bignum256modm b) {
ge25519 bA;
ge25519_scalarmult(&bA, A, b);
ge25519_mul8(r, &bA);
}
void xmr_derive_private_key(bignum256modm s, const ge25519 * deriv, uint32_t idx, const bignum256modm base){
xmr_derivation_to_scalar(s, deriv, idx);
add256_modm(s, s, base);
void xmr_derive_private_key(bignum256modm s, const ge25519 *deriv, uint32_t idx,
const bignum256modm base) {
xmr_derivation_to_scalar(s, deriv, idx);
add256_modm(s, s, base);
}
void xmr_derive_public_key(ge25519 * r, const ge25519 * deriv, uint32_t idx, const ge25519 * base){
bignum256modm s={0};
ge25519 p2;
void xmr_derive_public_key(ge25519 *r, const ge25519 *deriv, uint32_t idx,
const ge25519 *base) {
bignum256modm s = {0};
ge25519 p2;
xmr_derivation_to_scalar(s, deriv, idx);
ge25519_scalarmult_base_niels(&p2, ge25519_niels_base_multiples, s);
ge25519_add(r, base, &p2, 0);
xmr_derivation_to_scalar(s, deriv, idx);
ge25519_scalarmult_base_niels(&p2, ge25519_niels_base_multiples, s);
ge25519_add(r, base, &p2, 0);
}
void xmr_add_keys2(ge25519 * r, const bignum256modm a, const bignum256modm b, const ge25519 * B){
// aG + bB, G is basepoint
ge25519 aG, bB;
ge25519_scalarmult_base_niels(&aG, ge25519_niels_base_multiples, a);
ge25519_scalarmult(&bB, B, b);
ge25519_add(r, &aG, &bB, 0);
void xmr_add_keys2(ge25519 *r, const bignum256modm a, const bignum256modm b,
const ge25519 *B) {
// aG + bB, G is basepoint
ge25519 aG, bB;
ge25519_scalarmult_base_niels(&aG, ge25519_niels_base_multiples, a);
ge25519_scalarmult(&bB, B, b);
ge25519_add(r, &aG, &bB, 0);
}
void xmr_add_keys2_vartime(ge25519 * r, const bignum256modm a, const bignum256modm b, const ge25519 * B){
// aG + bB, G is basepoint
ge25519_double_scalarmult_vartime(r, B, b, a);
void xmr_add_keys2_vartime(ge25519 *r, const bignum256modm a,
const bignum256modm b, const ge25519 *B) {
// aG + bB, G is basepoint
ge25519_double_scalarmult_vartime(r, B, b, a);
}
void xmr_add_keys3(ge25519 * r, const bignum256modm a, const ge25519 * A, const bignum256modm b, const ge25519 * B){
// aA + bB
ge25519 aA, bB;
ge25519_scalarmult(&aA, A, a);
ge25519_scalarmult(&bB, B, b);
ge25519_add(r, &aA, &bB, 0);
void xmr_add_keys3(ge25519 *r, const bignum256modm a, const ge25519 *A,
const bignum256modm b, const ge25519 *B) {
// aA + bB
ge25519 aA, bB;
ge25519_scalarmult(&aA, A, a);
ge25519_scalarmult(&bB, B, b);
ge25519_add(r, &aA, &bB, 0);
}
void xmr_add_keys3_vartime(ge25519 * r, const bignum256modm a, const ge25519 * A, const bignum256modm b, const ge25519 * B){
// aA + bB
ge25519_double_scalarmult_vartime2(r, A, a, B, b);
void xmr_add_keys3_vartime(ge25519 *r, const bignum256modm a, const ge25519 *A,
const bignum256modm b, const ge25519 *B) {
// aA + bB
ge25519_double_scalarmult_vartime2(r, A, a, B, b);
}
void xmr_get_subaddress_secret_key(bignum256modm r, uint32_t major, uint32_t minor, const bignum256modm m){
const char prefix[] = "SubAddr";
unsigned char buff[32];
contract256_modm(buff, m);
void xmr_get_subaddress_secret_key(bignum256modm r, uint32_t major,
uint32_t minor, const bignum256modm m) {
const char prefix[] = "SubAddr";
unsigned char buff[32];
contract256_modm(buff, m);
char data[sizeof(prefix) + sizeof(buff) + 2 * sizeof(uint32_t)];
memcpy(data, prefix, sizeof(prefix));
memcpy(data + sizeof(prefix), buff, sizeof(buff));
memcpy(data + sizeof(prefix) + sizeof(buff), &major, sizeof(uint32_t));
memcpy(data + sizeof(prefix) + sizeof(buff) + sizeof(uint32_t), &minor, sizeof(uint32_t));
char data[sizeof(prefix) + sizeof(buff) + 2 * sizeof(uint32_t)];
memcpy(data, prefix, sizeof(prefix));
memcpy(data + sizeof(prefix), buff, sizeof(buff));
memcpy(data + sizeof(prefix) + sizeof(buff), &major, sizeof(uint32_t));
memcpy(data + sizeof(prefix) + sizeof(buff) + sizeof(uint32_t), &minor,
sizeof(uint32_t));
xmr_hash_to_scalar(r, data, sizeof(data));
xmr_hash_to_scalar(r, data, sizeof(data));
}
void xmr_gen_c(ge25519 * r, const bignum256modm a, uint64_t amount){
// C = aG + bH
bignum256modm b={0};
set256_modm(b, amount);
xmr_add_keys2(r, a, b, &xmr_h);
void xmr_gen_c(ge25519 *r, const bignum256modm a, uint64_t amount) {
// C = aG + bH
bignum256modm b = {0};
set256_modm(b, amount);
xmr_add_keys2(r, a, b, &xmr_h);
}

@ -24,13 +24,13 @@ void ge25519_set_xmr_h(ge25519 *r);
void xmr_random_scalar(bignum256modm m);
/* cn_fast_hash */
void xmr_fast_hash(uint8_t * hash, const void *data, size_t length);
void xmr_fast_hash(uint8_t *hash, const void *data, size_t length);
/* incremental hashing wrappers */
void xmr_hasher_init(Hasher * hasher);
void xmr_hasher_update(Hasher * hasher, const void *data, size_t length);
void xmr_hasher_final(Hasher * hasher, uint8_t * hash);
void xmr_hasher_copy(Hasher * dst, const Hasher * src);
void xmr_hasher_init(Hasher *hasher);
void xmr_hasher_update(Hasher *hasher, const void *data, size_t length);
void xmr_hasher_final(Hasher *hasher, uint8_t *hash);
void xmr_hasher_copy(Hasher *dst, const Hasher *src);
/* H_s(buffer) */
void xmr_hash_to_scalar(bignum256modm r, const void *data, size_t length);
@ -39,29 +39,38 @@ void xmr_hash_to_scalar(bignum256modm r, const void *data, size_t length);
void xmr_hash_to_ec(ge25519 *P, const void *data, size_t length);
/* derivation to scalar value */
void xmr_derivation_to_scalar(bignum256modm s, const ge25519 * p, uint32_t output_index);
void xmr_derivation_to_scalar(bignum256modm s, const ge25519 *p,
uint32_t output_index);
/* derivation */
void xmr_generate_key_derivation(ge25519 * r, const ge25519 * A, const bignum256modm b);
void xmr_generate_key_derivation(ge25519 *r, const ge25519 *A,
const bignum256modm b);
/* H_s(derivation || varint(output_index)) + base */
void xmr_derive_private_key(bignum256modm s, const ge25519 * deriv, uint32_t idx, const bignum256modm base);
void xmr_derive_private_key(bignum256modm s, const ge25519 *deriv, uint32_t idx,
const bignum256modm base);
/* H_s(derivation || varint(output_index))G + base */
void xmr_derive_public_key(ge25519 * r, const ge25519 * deriv, uint32_t idx, const ge25519 * base);
void xmr_derive_public_key(ge25519 *r, const ge25519 *deriv, uint32_t idx,
const ge25519 *base);
/* aG + bB, G is basepoint */
void xmr_add_keys2(ge25519 * r, const bignum256modm a, const bignum256modm b, const ge25519 * B);
void xmr_add_keys2_vartime(ge25519 * r, const bignum256modm a, const bignum256modm b, const ge25519 * B);
void xmr_add_keys2(ge25519 *r, const bignum256modm a, const bignum256modm b,
const ge25519 *B);
void xmr_add_keys2_vartime(ge25519 *r, const bignum256modm a,
const bignum256modm b, const ge25519 *B);
/* aA + bB */
void xmr_add_keys3(ge25519 * r, const bignum256modm a, const ge25519 * A, const bignum256modm b, const ge25519 * B);
void xmr_add_keys3_vartime(ge25519 * r, const bignum256modm a, const ge25519 * A, const bignum256modm b, const ge25519 * B);
void xmr_add_keys3(ge25519 *r, const bignum256modm a, const ge25519 *A,
const bignum256modm b, const ge25519 *B);
void xmr_add_keys3_vartime(ge25519 *r, const bignum256modm a, const ge25519 *A,
const bignum256modm b, const ge25519 *B);
/* subaddress secret */
void xmr_get_subaddress_secret_key(bignum256modm r, uint32_t major, uint32_t minor, const bignum256modm m);
void xmr_get_subaddress_secret_key(bignum256modm r, uint32_t major,
uint32_t minor, const bignum256modm m);
/* Generates Pedersen commitment C = aG + bH */
void xmr_gen_c(ge25519 * r, const bignum256modm a, uint64_t amount);
void xmr_gen_c(ge25519 *r, const bignum256modm a, uint64_t amount);
#endif //TREZOR_CRYPTO_XMR_H
#endif // TREZOR_CRYPTO_XMR_H

833
nem.c

@ -26,544 +26,483 @@
#include "base32.h"
#include "ed25519-donna/ed25519-keccak.h"
#include "memzero.h"
#include "ripemd160.h"
#include "sha3.h"
#include "memzero.h"
#define CAN_WRITE(NEEDED) ((ctx->offset + (NEEDED)) <= ctx->size)
#define SERIALIZE_U32(DATA) \
do { if (!nem_write_u32(ctx, (DATA))) return false; } while (0)
#define SERIALIZE_U64(DATA) \
do { if (!nem_write_u64(ctx, (DATA))) return false; } while (0)
#define SERIALIZE_TAGGED(DATA, LENGTH) \
do { if (!nem_write_tagged(ctx, (DATA), (LENGTH))) return false; } while (0)
#define SERIALIZE_U32(DATA) \
do { \
if (!nem_write_u32(ctx, (DATA))) return false; \
} while (0)
#define SERIALIZE_U64(DATA) \
do { \
if (!nem_write_u64(ctx, (DATA))) return false; \
} while (0)
#define SERIALIZE_TAGGED(DATA, LENGTH) \
do { \
if (!nem_write_tagged(ctx, (DATA), (LENGTH))) return false; \
} while (0)
const char *nem_network_name(uint8_t network) {
switch (network) {
case NEM_NETWORK_MAINNET:
return "NEM Mainnet";
case NEM_NETWORK_TESTNET:
return "NEM Testnet";
case NEM_NETWORK_MIJIN:
return "Mijin";
default:
return NULL;
}
switch (network) {
case NEM_NETWORK_MAINNET:
return "NEM Mainnet";
case NEM_NETWORK_TESTNET:
return "NEM Testnet";
case NEM_NETWORK_MIJIN:
return "Mijin";
default:
return NULL;
}
}
static inline bool nem_write_checked(nem_transaction_ctx *ctx, const uint8_t *data, uint32_t length) {
if (!CAN_WRITE(length)) {
return false;
}
static inline bool nem_write_checked(nem_transaction_ctx *ctx,
const uint8_t *data, uint32_t length) {
if (!CAN_WRITE(length)) {
return false;
}
memcpy(&ctx->buffer[ctx->offset], data, length);
ctx->offset += length;
return true;
memcpy(&ctx->buffer[ctx->offset], data, length);
ctx->offset += length;
return true;
}
static inline bool nem_write_u32(nem_transaction_ctx *ctx, uint32_t data) {
if (!CAN_WRITE(4)) {
return false;
}
if (!CAN_WRITE(4)) {
return false;
}
ctx->buffer[ctx->offset++] = (data >> 0) & 0xff;
ctx->buffer[ctx->offset++] = (data >> 8) & 0xff;
ctx->buffer[ctx->offset++] = (data >> 16) & 0xff;
ctx->buffer[ctx->offset++] = (data >> 24) & 0xff;
ctx->buffer[ctx->offset++] = (data >> 0) & 0xff;
ctx->buffer[ctx->offset++] = (data >> 8) & 0xff;
ctx->buffer[ctx->offset++] = (data >> 16) & 0xff;
ctx->buffer[ctx->offset++] = (data >> 24) & 0xff;
return true;
return true;
}
static inline bool nem_write_u64(nem_transaction_ctx *ctx, uint64_t data) {
SERIALIZE_U32((data >> 0) & 0xffffffff);
SERIALIZE_U32((data >> 32) & 0xffffffff);
SERIALIZE_U32((data >> 0) & 0xffffffff);
SERIALIZE_U32((data >> 32) & 0xffffffff);
return true;
return true;
}
static inline bool nem_write_tagged(nem_transaction_ctx *ctx, const uint8_t *data, uint32_t length) {
SERIALIZE_U32(length);
static inline bool nem_write_tagged(nem_transaction_ctx *ctx,
const uint8_t *data, uint32_t length) {
SERIALIZE_U32(length);
return nem_write_checked(ctx, data, length);
return nem_write_checked(ctx, data, length);
}
static inline bool nem_write_mosaic_str(nem_transaction_ctx *ctx, const char *name, const char *value) {
uint32_t name_length = strlen(name);
uint32_t value_length = strlen(value);
static inline bool nem_write_mosaic_str(nem_transaction_ctx *ctx,
const char *name, const char *value) {
uint32_t name_length = strlen(name);
uint32_t value_length = strlen(value);
SERIALIZE_U32(sizeof(uint32_t) + name_length + sizeof(uint32_t) + value_length);
SERIALIZE_TAGGED((const uint8_t *) name, name_length);
SERIALIZE_TAGGED((const uint8_t *) value, value_length);
SERIALIZE_U32(sizeof(uint32_t) + name_length + sizeof(uint32_t) +
value_length);
SERIALIZE_TAGGED((const uint8_t *)name, name_length);
SERIALIZE_TAGGED((const uint8_t *)value, value_length);
return true;
return true;
}
static inline bool nem_write_mosaic_bool(nem_transaction_ctx *ctx, const char *name, bool value) {
return nem_write_mosaic_str(ctx, name, value ? "true" : "false");
static inline bool nem_write_mosaic_bool(nem_transaction_ctx *ctx,
const char *name, bool value) {
return nem_write_mosaic_str(ctx, name, value ? "true" : "false");
}
static inline bool nem_write_mosaic_u64(nem_transaction_ctx *ctx, const char *name, uint64_t value) {
char buffer[21];
static inline bool nem_write_mosaic_u64(nem_transaction_ctx *ctx,
const char *name, uint64_t value) {
char buffer[21];
if (bn_format_uint64(value, NULL, NULL, 0, 0, false, buffer, sizeof(buffer)) == 0) {
return false;
}
if (bn_format_uint64(value, NULL, NULL, 0, 0, false, buffer,
sizeof(buffer)) == 0) {
return false;
}
return nem_write_mosaic_str(ctx, name, buffer);
return nem_write_mosaic_str(ctx, name, buffer);
}
void nem_get_address_raw(const ed25519_public_key public_key, uint8_t version, uint8_t *address) {
uint8_t hash[SHA3_256_DIGEST_LENGTH];
void nem_get_address_raw(const ed25519_public_key public_key, uint8_t version,
uint8_t *address) {
uint8_t hash[SHA3_256_DIGEST_LENGTH];
/* 1. Perform 256-bit Sha3 on the public key */
keccak_256(public_key, sizeof(ed25519_public_key), hash);
/* 1. Perform 256-bit Sha3 on the public key */
keccak_256(public_key, sizeof(ed25519_public_key), hash);
/* 2. Perform 160-bit Ripemd of hash resulting from step 1. */
ripemd160(hash, SHA3_256_DIGEST_LENGTH, &address[1]);
/* 2. Perform 160-bit Ripemd of hash resulting from step 1. */
ripemd160(hash, SHA3_256_DIGEST_LENGTH, &address[1]);
/* 3. Prepend version byte to Ripemd hash (either 0x68 or 0x98) */
address[0] = version;
/* 3. Prepend version byte to Ripemd hash (either 0x68 or 0x98) */
address[0] = version;
/* 4. Perform 256-bit Sha3 on the result, take the first four bytes as a checksum */
keccak_256(address, 1 + RIPEMD160_DIGEST_LENGTH, hash);
/* 4. Perform 256-bit Sha3 on the result, take the first four bytes as a
* checksum */
keccak_256(address, 1 + RIPEMD160_DIGEST_LENGTH, hash);
/* 5. Concatenate output of step 3 and the checksum from step 4 */
memcpy(&address[1 + RIPEMD160_DIGEST_LENGTH], hash, 4);
/* 5. Concatenate output of step 3 and the checksum from step 4 */
memcpy(&address[1 + RIPEMD160_DIGEST_LENGTH], hash, 4);
memzero(hash, sizeof(hash));
memzero(hash, sizeof(hash));
}
bool nem_get_address(const ed25519_public_key public_key, uint8_t version, char *address) {
uint8_t pubkeyhash[NEM_ADDRESS_SIZE_RAW];
bool nem_get_address(const ed25519_public_key public_key, uint8_t version,
char *address) {
uint8_t pubkeyhash[NEM_ADDRESS_SIZE_RAW];
nem_get_address_raw(public_key, version, pubkeyhash);
nem_get_address_raw(public_key, version, pubkeyhash);
char *ret = base32_encode(pubkeyhash, sizeof(pubkeyhash), address, NEM_ADDRESS_SIZE + 1, BASE32_ALPHABET_RFC4648);
char *ret = base32_encode(pubkeyhash, sizeof(pubkeyhash), address,
NEM_ADDRESS_SIZE + 1, BASE32_ALPHABET_RFC4648);
memzero(pubkeyhash, sizeof(pubkeyhash));
return (ret != NULL);
memzero(pubkeyhash, sizeof(pubkeyhash));
return (ret != NULL);
}
bool nem_validate_address_raw(const uint8_t *address, uint8_t network) {
if (!nem_network_name(network) || address[0] != network) {
return false;
}
if (!nem_network_name(network) || address[0] != network) {
return false;
}
uint8_t hash[SHA3_256_DIGEST_LENGTH];
uint8_t hash[SHA3_256_DIGEST_LENGTH];
keccak_256(address, 1 + RIPEMD160_DIGEST_LENGTH, hash);
bool valid = (memcmp(&address[1 + RIPEMD160_DIGEST_LENGTH], hash, 4) == 0);
keccak_256(address, 1 + RIPEMD160_DIGEST_LENGTH, hash);
bool valid = (memcmp(&address[1 + RIPEMD160_DIGEST_LENGTH], hash, 4) == 0);
memzero(hash, sizeof(hash));
return valid;
memzero(hash, sizeof(hash));
return valid;
}
bool nem_validate_address(const char *address, uint8_t network) {
uint8_t pubkeyhash[NEM_ADDRESS_SIZE_RAW];
uint8_t pubkeyhash[NEM_ADDRESS_SIZE_RAW];
if (strlen(address) != NEM_ADDRESS_SIZE) {
return false;
}
if (strlen(address) != NEM_ADDRESS_SIZE) {
return false;
}
uint8_t *ret = base32_decode(address, NEM_ADDRESS_SIZE, pubkeyhash, sizeof(pubkeyhash), BASE32_ALPHABET_RFC4648);
bool valid = (ret != NULL) && nem_validate_address_raw(pubkeyhash, network);
uint8_t *ret = base32_decode(address, NEM_ADDRESS_SIZE, pubkeyhash,
sizeof(pubkeyhash), BASE32_ALPHABET_RFC4648);
bool valid = (ret != NULL) && nem_validate_address_raw(pubkeyhash, network);
memzero(pubkeyhash, sizeof(pubkeyhash));
return valid;
memzero(pubkeyhash, sizeof(pubkeyhash));
return valid;
}
void nem_transaction_start(nem_transaction_ctx *ctx, const ed25519_public_key public_key, uint8_t *buffer, size_t size) {
memcpy(ctx->public_key, public_key, sizeof(ctx->public_key));
void nem_transaction_start(nem_transaction_ctx *ctx,
const ed25519_public_key public_key, uint8_t *buffer,
size_t size) {
memcpy(ctx->public_key, public_key, sizeof(ctx->public_key));
ctx->buffer = buffer;
ctx->offset = 0;
ctx->size = size;
ctx->buffer = buffer;
ctx->offset = 0;
ctx->size = size;
}
size_t nem_transaction_end(nem_transaction_ctx *ctx, const ed25519_secret_key private_key, ed25519_signature signature) {
if (private_key != NULL && signature != NULL) {
ed25519_sign_keccak(ctx->buffer, ctx->offset, private_key, ctx->public_key, signature);
}
size_t nem_transaction_end(nem_transaction_ctx *ctx,
const ed25519_secret_key private_key,
ed25519_signature signature) {
if (private_key != NULL && signature != NULL) {
ed25519_sign_keccak(ctx->buffer, ctx->offset, private_key, ctx->public_key,
signature);
}
return ctx->offset;
return ctx->offset;
}
bool nem_transaction_write_common(nem_transaction_ctx *ctx,
uint32_t type,
uint32_t version,
uint32_t timestamp,
const ed25519_public_key signer,
uint64_t fee,
uint32_t deadline) {
SERIALIZE_U32(type);
SERIALIZE_U32(version);
SERIALIZE_U32(timestamp);
SERIALIZE_TAGGED(signer, sizeof(ed25519_public_key));
SERIALIZE_U64(fee);
SERIALIZE_U32(deadline);
return true;
bool nem_transaction_write_common(nem_transaction_ctx *ctx, uint32_t type,
uint32_t version, uint32_t timestamp,
const ed25519_public_key signer, uint64_t fee,
uint32_t deadline) {
SERIALIZE_U32(type);
SERIALIZE_U32(version);
SERIALIZE_U32(timestamp);
SERIALIZE_TAGGED(signer, sizeof(ed25519_public_key));
SERIALIZE_U64(fee);
SERIALIZE_U32(deadline);
return true;
}
bool nem_transaction_create_transfer(nem_transaction_ctx *ctx,
uint8_t network,
uint32_t timestamp,
const ed25519_public_key signer,
uint64_t fee,
uint32_t deadline,
const char *recipient,
uint64_t amount,
const uint8_t *payload,
uint32_t length,
bool encrypted,
uint32_t mosaics) {
if (!signer) {
signer = ctx->public_key;
}
if (!payload) {
length = 0;
}
bool ret = nem_transaction_write_common(ctx,
NEM_TRANSACTION_TYPE_TRANSFER,
(uint32_t) network << 24 | (mosaics ? 2 : 1),
timestamp,
signer,
fee,
deadline);
if (!ret) return false;
SERIALIZE_TAGGED((const uint8_t *) recipient, NEM_ADDRESS_SIZE);
SERIALIZE_U64(amount);
if (length) {
SERIALIZE_U32(sizeof(uint32_t) + sizeof(uint32_t) + length);
SERIALIZE_U32(encrypted ? 0x02 : 0x01);
SERIALIZE_TAGGED(payload, length);
} else {
SERIALIZE_U32(0);
}
if (mosaics) {
SERIALIZE_U32(mosaics);
}
return true;
bool nem_transaction_create_transfer(nem_transaction_ctx *ctx, uint8_t network,
uint32_t timestamp,
const ed25519_public_key signer,
uint64_t fee, uint32_t deadline,
const char *recipient, uint64_t amount,
const uint8_t *payload, uint32_t length,
bool encrypted, uint32_t mosaics) {
if (!signer) {
signer = ctx->public_key;
}
if (!payload) {
length = 0;
}
bool ret =
nem_transaction_write_common(ctx, NEM_TRANSACTION_TYPE_TRANSFER,
(uint32_t)network << 24 | (mosaics ? 2 : 1),
timestamp, signer, fee, deadline);
if (!ret) return false;
SERIALIZE_TAGGED((const uint8_t *)recipient, NEM_ADDRESS_SIZE);
SERIALIZE_U64(amount);
if (length) {
SERIALIZE_U32(sizeof(uint32_t) + sizeof(uint32_t) + length);
SERIALIZE_U32(encrypted ? 0x02 : 0x01);
SERIALIZE_TAGGED(payload, length);
} else {
SERIALIZE_U32(0);
}
if (mosaics) {
SERIALIZE_U32(mosaics);
}
return true;
}
bool nem_transaction_write_mosaic(nem_transaction_ctx *ctx,
const char *namespace,
const char *mosaic,
uint64_t quantity) {
const char *namespace, const char *mosaic,
uint64_t quantity) {
size_t namespace_length = strlen(namespace);
size_t mosaic_length = strlen(mosaic);
size_t identifier_length =
sizeof(uint32_t) + namespace_length + sizeof(uint32_t) + mosaic_length;
SERIALIZE_U32(sizeof(uint32_t) + sizeof(uint64_t) + identifier_length);
SERIALIZE_U32(identifier_length);
SERIALIZE_TAGGED((const uint8_t *)namespace, namespace_length);
SERIALIZE_TAGGED((const uint8_t *)mosaic, mosaic_length);
SERIALIZE_U64(quantity);
return true;
}
size_t namespace_length = strlen(namespace);
size_t mosaic_length = strlen(mosaic);
size_t identifier_length = sizeof(uint32_t) + namespace_length + sizeof(uint32_t) + mosaic_length;
bool nem_transaction_create_multisig(nem_transaction_ctx *ctx, uint8_t network,
uint32_t timestamp,
const ed25519_public_key signer,
uint64_t fee, uint32_t deadline,
const nem_transaction_ctx *inner) {
if (!signer) {
signer = ctx->public_key;
}
SERIALIZE_U32(sizeof(uint32_t) + sizeof(uint64_t) + identifier_length);
SERIALIZE_U32(identifier_length);
SERIALIZE_TAGGED((const uint8_t *) namespace, namespace_length);
SERIALIZE_TAGGED((const uint8_t *) mosaic, mosaic_length);
SERIALIZE_U64(quantity);
bool ret = nem_transaction_write_common(ctx, NEM_TRANSACTION_TYPE_MULTISIG,
(uint32_t)network << 24 | 1,
timestamp, signer, fee, deadline);
if (!ret) return false;
return true;
}
SERIALIZE_TAGGED(inner->buffer, inner->offset);
bool nem_transaction_create_multisig(nem_transaction_ctx *ctx,
uint8_t network,
uint32_t timestamp,
const ed25519_public_key signer,
uint64_t fee,
uint32_t deadline,
const nem_transaction_ctx *inner) {
if (!signer) {
signer = ctx->public_key;
}
bool ret = nem_transaction_write_common(ctx,
NEM_TRANSACTION_TYPE_MULTISIG,
(uint32_t) network << 24 | 1,
timestamp,
signer,
fee,
deadline);
if (!ret) return false;
SERIALIZE_TAGGED(inner->buffer, inner->offset);
return true;
return true;
}
bool nem_transaction_create_multisig_signature(nem_transaction_ctx *ctx,
uint8_t network,
uint32_t timestamp,
const ed25519_public_key signer,
uint64_t fee,
uint32_t deadline,
const nem_transaction_ctx *inner) {
if (!signer) {
signer = ctx->public_key;
}
bool ret = nem_transaction_write_common(ctx,
NEM_TRANSACTION_TYPE_MULTISIG_SIGNATURE,
(uint32_t) network << 24 | 1,
timestamp,
signer,
fee,
deadline);
if (!ret) return false;
char address[NEM_ADDRESS_SIZE + 1];
nem_get_address(inner->public_key, network, address);
uint8_t hash[SHA3_256_DIGEST_LENGTH];
keccak_256(inner->buffer, inner->offset, hash);
SERIALIZE_U32(sizeof(uint32_t) + SHA3_256_DIGEST_LENGTH);
SERIALIZE_TAGGED(hash, SHA3_256_DIGEST_LENGTH);
SERIALIZE_TAGGED((const uint8_t *) address, NEM_ADDRESS_SIZE);
return true;
}
bool nem_transaction_create_multisig_signature(
nem_transaction_ctx *ctx, uint8_t network, uint32_t timestamp,
const ed25519_public_key signer, uint64_t fee, uint32_t deadline,
const nem_transaction_ctx *inner) {
if (!signer) {
signer = ctx->public_key;
}
bool nem_transaction_create_provision_namespace(nem_transaction_ctx *ctx,
uint8_t network,
uint32_t timestamp,
const ed25519_public_key signer,
uint64_t fee,
uint32_t deadline,
const char *namespace,
const char *parent,
const char *rental_sink,
uint64_t rental_fee) {
if (!signer) {
signer = ctx->public_key;
}
bool ret = nem_transaction_write_common(ctx,
NEM_TRANSACTION_TYPE_PROVISION_NAMESPACE,
(uint32_t) network << 24 | 1,
timestamp,
signer,
fee,
deadline);
if (!ret) return false;
if (parent) {
SERIALIZE_TAGGED((const uint8_t *) rental_sink, NEM_ADDRESS_SIZE);
SERIALIZE_U64(rental_fee);
SERIALIZE_TAGGED((const uint8_t *) namespace, strlen(namespace));
SERIALIZE_TAGGED((const uint8_t *) parent, strlen(parent));
} else {
SERIALIZE_TAGGED((const uint8_t *) rental_sink, NEM_ADDRESS_SIZE);
SERIALIZE_U64(rental_fee);
SERIALIZE_TAGGED((const uint8_t *) namespace, strlen(namespace));
SERIALIZE_U32(0xffffffff);
}
return true;
}
bool ret = nem_transaction_write_common(
ctx, NEM_TRANSACTION_TYPE_MULTISIG_SIGNATURE, (uint32_t)network << 24 | 1,
timestamp, signer, fee, deadline);
if (!ret) return false;
char address[NEM_ADDRESS_SIZE + 1];
nem_get_address(inner->public_key, network, address);
bool nem_transaction_create_mosaic_creation(nem_transaction_ctx *ctx,
uint8_t network,
uint32_t timestamp,
const ed25519_public_key signer,
uint64_t fee,
uint32_t deadline,
const char *namespace,
const char *mosaic,
const char *description,
uint32_t divisibility,
uint64_t supply,
bool mutable_supply,
bool transferable,
uint32_t levy_type,
uint64_t levy_fee,
const char *levy_address,
const char *levy_namespace,
const char *levy_mosaic,
const char *creation_sink,
uint64_t creation_fee) {
if (!signer) {
signer = ctx->public_key;
}
bool ret = nem_transaction_write_common(ctx,
NEM_TRANSACTION_TYPE_MOSAIC_CREATION,
(uint32_t) network << 24 | 1,
timestamp,
signer,
fee,
deadline);
if (!ret) return false;
size_t namespace_length = strlen(namespace);
size_t mosaic_length = strlen(mosaic);
size_t identifier_length = sizeof(uint32_t) + namespace_length + sizeof(uint32_t) + mosaic_length;
// This length will be rewritten later on
nem_transaction_ctx state;
memcpy(&state, ctx, sizeof(state));
SERIALIZE_U32(0);
SERIALIZE_TAGGED(signer, sizeof(ed25519_public_key));
SERIALIZE_U32(identifier_length);
SERIALIZE_TAGGED((const uint8_t *) namespace, namespace_length);
SERIALIZE_TAGGED((const uint8_t *) mosaic, mosaic_length);
SERIALIZE_TAGGED((const uint8_t *) description, strlen(description));
SERIALIZE_U32(4); // Number of properties
if (!nem_write_mosaic_u64(ctx, "divisibility", divisibility)) return false;
if (!nem_write_mosaic_u64(ctx, "initialSupply", supply)) return false;
if (!nem_write_mosaic_bool(ctx, "supplyMutable", mutable_supply)) return false;
if (!nem_write_mosaic_bool(ctx, "transferable", transferable)) return false;
if (levy_type) {
size_t levy_namespace_length = strlen(levy_namespace);
size_t levy_mosaic_length = strlen(levy_mosaic);
size_t levy_identifier_length = sizeof(uint32_t) + levy_namespace_length + sizeof(uint32_t) + levy_mosaic_length;
SERIALIZE_U32(sizeof(uint32_t) + sizeof(uint32_t) + NEM_ADDRESS_SIZE + sizeof(uint32_t) + levy_identifier_length + sizeof(uint64_t));
SERIALIZE_U32(levy_type);
SERIALIZE_TAGGED((const uint8_t *) levy_address, NEM_ADDRESS_SIZE);
SERIALIZE_U32(levy_identifier_length);
SERIALIZE_TAGGED((const uint8_t *) levy_namespace, levy_namespace_length);
SERIALIZE_TAGGED((const uint8_t *) levy_mosaic, levy_mosaic_length);
SERIALIZE_U64(levy_fee);
} else {
SERIALIZE_U32(0);
}
// Rewrite length
nem_write_u32(&state, ctx->offset - state.offset - sizeof(uint32_t));
SERIALIZE_TAGGED((const uint8_t *) creation_sink, NEM_ADDRESS_SIZE);
SERIALIZE_U64(creation_fee);
return true;
uint8_t hash[SHA3_256_DIGEST_LENGTH];
keccak_256(inner->buffer, inner->offset, hash);
SERIALIZE_U32(sizeof(uint32_t) + SHA3_256_DIGEST_LENGTH);
SERIALIZE_TAGGED(hash, SHA3_256_DIGEST_LENGTH);
SERIALIZE_TAGGED((const uint8_t *)address, NEM_ADDRESS_SIZE);
return true;
}
bool nem_transaction_create_mosaic_supply_change(nem_transaction_ctx *ctx,
uint8_t network,
uint32_t timestamp,
const ed25519_public_key signer,
uint64_t fee,
uint32_t deadline,
const char *namespace,
const char *mosaic,
uint32_t type,
uint64_t delta) {
if (!signer) {
signer = ctx->public_key;
}
bool ret = nem_transaction_write_common(ctx,
NEM_TRANSACTION_TYPE_MOSAIC_SUPPLY_CHANGE,
(uint32_t) network << 24 | 1,
timestamp,
signer,
fee,
deadline);
if (!ret) return false;
size_t namespace_length = strlen(namespace);
size_t mosaic_length = strlen(mosaic);
size_t identifier_length = sizeof(uint32_t) + namespace_length + sizeof(uint32_t) + mosaic_length;
SERIALIZE_U32(identifier_length);
SERIALIZE_TAGGED((const uint8_t *) namespace, namespace_length);
SERIALIZE_TAGGED((const uint8_t *) mosaic, mosaic_length);
SERIALIZE_U32(type);
SERIALIZE_U64(delta);
return true;
bool nem_transaction_create_provision_namespace(
nem_transaction_ctx *ctx, uint8_t network, uint32_t timestamp,
const ed25519_public_key signer, uint64_t fee, uint32_t deadline,
const char *namespace, const char *parent, const char *rental_sink,
uint64_t rental_fee) {
if (!signer) {
signer = ctx->public_key;
}
bool ret = nem_transaction_write_common(
ctx, NEM_TRANSACTION_TYPE_PROVISION_NAMESPACE,
(uint32_t)network << 24 | 1, timestamp, signer, fee, deadline);
if (!ret) return false;
if (parent) {
SERIALIZE_TAGGED((const uint8_t *)rental_sink, NEM_ADDRESS_SIZE);
SERIALIZE_U64(rental_fee);
SERIALIZE_TAGGED((const uint8_t *)namespace, strlen(namespace));
SERIALIZE_TAGGED((const uint8_t *)parent, strlen(parent));
} else {
SERIALIZE_TAGGED((const uint8_t *)rental_sink, NEM_ADDRESS_SIZE);
SERIALIZE_U64(rental_fee);
SERIALIZE_TAGGED((const uint8_t *)namespace, strlen(namespace));
SERIALIZE_U32(0xffffffff);
}
return true;
}
bool nem_transaction_create_aggregate_modification(nem_transaction_ctx *ctx,
uint8_t network,
uint32_t timestamp,
const ed25519_public_key signer,
uint64_t fee,
uint32_t deadline,
uint32_t modifications,
bool relative_change) {
if (!signer) {
signer = ctx->public_key;
}
bool ret = nem_transaction_write_common(ctx,
NEM_TRANSACTION_TYPE_AGGREGATE_MODIFICATION,
(uint32_t) network << 24 | (relative_change ? 2 : 1),
timestamp,
signer,
fee,
deadline);
if (!ret) return false;
SERIALIZE_U32(modifications);
return true;
bool nem_transaction_create_mosaic_creation(
nem_transaction_ctx *ctx, uint8_t network, uint32_t timestamp,
const ed25519_public_key signer, uint64_t fee, uint32_t deadline,
const char *namespace, const char *mosaic, const char *description,
uint32_t divisibility, uint64_t supply, bool mutable_supply,
bool transferable, uint32_t levy_type, uint64_t levy_fee,
const char *levy_address, const char *levy_namespace,
const char *levy_mosaic, const char *creation_sink, uint64_t creation_fee) {
if (!signer) {
signer = ctx->public_key;
}
bool ret = nem_transaction_write_common(
ctx, NEM_TRANSACTION_TYPE_MOSAIC_CREATION, (uint32_t)network << 24 | 1,
timestamp, signer, fee, deadline);
if (!ret) return false;
size_t namespace_length = strlen(namespace);
size_t mosaic_length = strlen(mosaic);
size_t identifier_length =
sizeof(uint32_t) + namespace_length + sizeof(uint32_t) + mosaic_length;
// This length will be rewritten later on
nem_transaction_ctx state;
memcpy(&state, ctx, sizeof(state));
SERIALIZE_U32(0);
SERIALIZE_TAGGED(signer, sizeof(ed25519_public_key));
SERIALIZE_U32(identifier_length);
SERIALIZE_TAGGED((const uint8_t *)namespace, namespace_length);
SERIALIZE_TAGGED((const uint8_t *)mosaic, mosaic_length);
SERIALIZE_TAGGED((const uint8_t *)description, strlen(description));
SERIALIZE_U32(4); // Number of properties
if (!nem_write_mosaic_u64(ctx, "divisibility", divisibility)) return false;
if (!nem_write_mosaic_u64(ctx, "initialSupply", supply)) return false;
if (!nem_write_mosaic_bool(ctx, "supplyMutable", mutable_supply))
return false;
if (!nem_write_mosaic_bool(ctx, "transferable", transferable)) return false;
if (levy_type) {
size_t levy_namespace_length = strlen(levy_namespace);
size_t levy_mosaic_length = strlen(levy_mosaic);
size_t levy_identifier_length = sizeof(uint32_t) + levy_namespace_length +
sizeof(uint32_t) + levy_mosaic_length;
SERIALIZE_U32(sizeof(uint32_t) + sizeof(uint32_t) + NEM_ADDRESS_SIZE +
sizeof(uint32_t) + levy_identifier_length + sizeof(uint64_t));
SERIALIZE_U32(levy_type);
SERIALIZE_TAGGED((const uint8_t *)levy_address, NEM_ADDRESS_SIZE);
SERIALIZE_U32(levy_identifier_length);
SERIALIZE_TAGGED((const uint8_t *)levy_namespace, levy_namespace_length);
SERIALIZE_TAGGED((const uint8_t *)levy_mosaic, levy_mosaic_length);
SERIALIZE_U64(levy_fee);
} else {
SERIALIZE_U32(0);
}
// Rewrite length
nem_write_u32(&state, ctx->offset - state.offset - sizeof(uint32_t));
SERIALIZE_TAGGED((const uint8_t *)creation_sink, NEM_ADDRESS_SIZE);
SERIALIZE_U64(creation_fee);
return true;
}
bool nem_transaction_write_cosignatory_modification(nem_transaction_ctx *ctx,
uint32_t type,
const ed25519_public_key cosignatory) {
bool nem_transaction_create_mosaic_supply_change(
nem_transaction_ctx *ctx, uint8_t network, uint32_t timestamp,
const ed25519_public_key signer, uint64_t fee, uint32_t deadline,
const char *namespace, const char *mosaic, uint32_t type, uint64_t delta) {
if (!signer) {
signer = ctx->public_key;
}
bool ret = nem_transaction_write_common(
ctx, NEM_TRANSACTION_TYPE_MOSAIC_SUPPLY_CHANGE,
(uint32_t)network << 24 | 1, timestamp, signer, fee, deadline);
if (!ret) return false;
size_t namespace_length = strlen(namespace);
size_t mosaic_length = strlen(mosaic);
size_t identifier_length =
sizeof(uint32_t) + namespace_length + sizeof(uint32_t) + mosaic_length;
SERIALIZE_U32(identifier_length);
SERIALIZE_TAGGED((const uint8_t *)namespace, namespace_length);
SERIALIZE_TAGGED((const uint8_t *)mosaic, mosaic_length);
SERIALIZE_U32(type);
SERIALIZE_U64(delta);
return true;
}
SERIALIZE_U32(sizeof(uint32_t) + sizeof(uint32_t) + sizeof(ed25519_public_key));
SERIALIZE_U32(type);
SERIALIZE_TAGGED(cosignatory, sizeof(ed25519_public_key));
bool nem_transaction_create_aggregate_modification(
nem_transaction_ctx *ctx, uint8_t network, uint32_t timestamp,
const ed25519_public_key signer, uint64_t fee, uint32_t deadline,
uint32_t modifications, bool relative_change) {
if (!signer) {
signer = ctx->public_key;
}
return true;
bool ret = nem_transaction_write_common(
ctx, NEM_TRANSACTION_TYPE_AGGREGATE_MODIFICATION,
(uint32_t)network << 24 | (relative_change ? 2 : 1), timestamp, signer,
fee, deadline);
if (!ret) return false;
SERIALIZE_U32(modifications);
return true;
}
bool nem_transaction_write_minimum_cosignatories(nem_transaction_ctx *ctx,
int32_t relative_change) {
bool nem_transaction_write_cosignatory_modification(
nem_transaction_ctx *ctx, uint32_t type,
const ed25519_public_key cosignatory) {
SERIALIZE_U32(sizeof(uint32_t) + sizeof(uint32_t) +
sizeof(ed25519_public_key));
SERIALIZE_U32(type);
SERIALIZE_TAGGED(cosignatory, sizeof(ed25519_public_key));
SERIALIZE_U32(sizeof(uint32_t));
SERIALIZE_U32((uint32_t) relative_change);
return true;
}
return true;
bool nem_transaction_write_minimum_cosignatories(nem_transaction_ctx *ctx,
int32_t relative_change) {
SERIALIZE_U32(sizeof(uint32_t));
SERIALIZE_U32((uint32_t)relative_change);
return true;
}
bool nem_transaction_create_importance_transfer(nem_transaction_ctx *ctx,
uint8_t network,
uint32_t timestamp,
const ed25519_public_key signer,
uint64_t fee,
uint32_t deadline,
uint32_t mode,
const ed25519_public_key remote) {
if (!signer) {
signer = ctx->public_key;
}
bool ret = nem_transaction_write_common(ctx,
NEM_TRANSACTION_TYPE_IMPORTANCE_TRANSFER,
(uint32_t) network << 24 | 1,
timestamp,
signer,
fee,
deadline);
if (!ret) return false;
SERIALIZE_U32(mode);
SERIALIZE_TAGGED(remote, sizeof(ed25519_public_key));
return true;
bool nem_transaction_create_importance_transfer(
nem_transaction_ctx *ctx, uint8_t network, uint32_t timestamp,
const ed25519_public_key signer, uint64_t fee, uint32_t deadline,
uint32_t mode, const ed25519_public_key remote) {
if (!signer) {
signer = ctx->public_key;
}
bool ret = nem_transaction_write_common(
ctx, NEM_TRANSACTION_TYPE_IMPORTANCE_TRANSFER,
(uint32_t)network << 24 | 1, timestamp, signer, fee, deadline);
if (!ret) return false;
SERIALIZE_U32(mode);
SERIALIZE_TAGGED(remote, sizeof(ed25519_public_key));
return true;
}

219
nem.h

@ -31,161 +31,126 @@
#include "ed25519-donna/ed25519.h"
#define NEM_LEVY_PERCENTILE_DIVISOR 4
#define NEM_MAX_DIVISIBILITY 6
#define NEM_MAX_SUPPLY 9000000000
#define NEM_MAX_DIVISIBILITY 6
#define NEM_MAX_SUPPLY 9000000000
#define NEM_NETWORK_MAINNET 0x68
#define NEM_NETWORK_TESTNET 0x98
#define NEM_NETWORK_MIJIN 0x60
#define NEM_NETWORK_MIJIN 0x60
#define NEM_ADDRESS_SIZE 40
#define NEM_ADDRESS_SIZE_RAW 25
#define NEM_TRANSACTION_TYPE_TRANSFER 0x0101
#define NEM_TRANSACTION_TYPE_IMPORTANCE_TRANSFER 0x0801
#define NEM_TRANSACTION_TYPE_AGGREGATE_MODIFICATION 0x1001
#define NEM_TRANSACTION_TYPE_MULTISIG_SIGNATURE 0x1002
#define NEM_TRANSACTION_TYPE_MULTISIG 0x1004
#define NEM_TRANSACTION_TYPE_PROVISION_NAMESPACE 0x2001
#define NEM_TRANSACTION_TYPE_MOSAIC_CREATION 0x4001
#define NEM_TRANSACTION_TYPE_MOSAIC_SUPPLY_CHANGE 0x4002
#define NEM_TRANSACTION_TYPE_TRANSFER 0x0101
#define NEM_TRANSACTION_TYPE_IMPORTANCE_TRANSFER 0x0801
#define NEM_TRANSACTION_TYPE_AGGREGATE_MODIFICATION 0x1001
#define NEM_TRANSACTION_TYPE_MULTISIG_SIGNATURE 0x1002
#define NEM_TRANSACTION_TYPE_MULTISIG 0x1004
#define NEM_TRANSACTION_TYPE_PROVISION_NAMESPACE 0x2001
#define NEM_TRANSACTION_TYPE_MOSAIC_CREATION 0x4001
#define NEM_TRANSACTION_TYPE_MOSAIC_SUPPLY_CHANGE 0x4002
#define NEM_SALT_SIZE sizeof(ed25519_public_key)
#define NEM_ENCRYPTED_SIZE(size) (((size) + AES_BLOCK_SIZE) / AES_BLOCK_SIZE * AES_BLOCK_SIZE)
#define NEM_ENCRYPTED_PAYLOAD_SIZE(size) (AES_BLOCK_SIZE + NEM_SALT_SIZE + NEM_ENCRYPTED_SIZE(size))
#define NEM_ENCRYPTED_SIZE(size) \
(((size) + AES_BLOCK_SIZE) / AES_BLOCK_SIZE * AES_BLOCK_SIZE)
#define NEM_ENCRYPTED_PAYLOAD_SIZE(size) \
(AES_BLOCK_SIZE + NEM_SALT_SIZE + NEM_ENCRYPTED_SIZE(size))
#define _NEM_PADDING_SIZE(buffer, size) ((buffer)[(size) - 1])
#define NEM_PADDING_SIZE(buffer, size) (_NEM_PADDING_SIZE(buffer, size) > (size) ? (size) : _NEM_PADDING_SIZE(buffer, size))
#define _NEM_PADDING_SIZE(buffer, size) ((buffer)[(size)-1])
#define NEM_PADDING_SIZE(buffer, size) \
(_NEM_PADDING_SIZE(buffer, size) > (size) ? (size) \
: _NEM_PADDING_SIZE(buffer, size))
#define NEM_DECRYPTED_SIZE(buffer, size) ((size) - NEM_PADDING_SIZE(buffer, size))
#define NEM_DECRYPTED_SIZE(buffer, size) ((size)-NEM_PADDING_SIZE(buffer, size))
typedef struct {
ed25519_public_key public_key;
uint8_t *buffer;
size_t offset;
size_t size;
ed25519_public_key public_key;
uint8_t *buffer;
size_t offset;
size_t size;
} nem_transaction_ctx;
const char *nem_network_name(uint8_t network);
void nem_get_address_raw(const ed25519_public_key public_key, uint8_t version, uint8_t *address);
bool nem_get_address(const ed25519_public_key public_key, uint8_t version, char *address);
void nem_get_address_raw(const ed25519_public_key public_key, uint8_t version,
uint8_t *address);
bool nem_get_address(const ed25519_public_key public_key, uint8_t version,
char *address);
bool nem_validate_address_raw(const uint8_t *address, uint8_t network);
bool nem_validate_address(const char *address, uint8_t network);
void nem_transaction_start(nem_transaction_ctx *ctx, const ed25519_public_key public_key, uint8_t *buffer, size_t size);
size_t nem_transaction_end(nem_transaction_ctx *ctx, const ed25519_secret_key private_key, ed25519_signature signature);
void nem_transaction_start(nem_transaction_ctx *ctx,
const ed25519_public_key public_key, uint8_t *buffer,
size_t size);
size_t nem_transaction_end(nem_transaction_ctx *ctx,
const ed25519_secret_key private_key,
ed25519_signature signature);
bool nem_transaction_write_common(nem_transaction_ctx *context,
uint32_t type,
uint32_t version,
uint32_t timestamp,
const ed25519_public_key signer,
uint64_t fee,
uint32_t deadline);
bool nem_transaction_write_common(nem_transaction_ctx *context, uint32_t type,
uint32_t version, uint32_t timestamp,
const ed25519_public_key signer, uint64_t fee,
uint32_t deadline);
bool nem_transaction_create_transfer(nem_transaction_ctx *context,
uint8_t network,
uint32_t timestamp,
const ed25519_public_key signer,
uint64_t fee,
uint32_t deadline,
const char *recipient,
uint64_t amount,
const uint8_t *payload,
uint32_t length,
bool encrypted,
uint32_t mosaics);
uint8_t network, uint32_t timestamp,
const ed25519_public_key signer,
uint64_t fee, uint32_t deadline,
const char *recipient, uint64_t amount,
const uint8_t *payload, uint32_t length,
bool encrypted, uint32_t mosaics);
bool nem_transaction_write_mosaic(nem_transaction_ctx *ctx,
const char *namespace,
const char *mosaic,
uint64_t quantity);
bool nem_transaction_create_multisig(nem_transaction_ctx *ctx,
uint8_t network,
uint32_t timestamp,
const ed25519_public_key signer,
uint64_t fee,
uint32_t deadline,
const nem_transaction_ctx *inner);
bool nem_transaction_create_multisig_signature(nem_transaction_ctx *ctx,
uint8_t network,
uint32_t timestamp,
const ed25519_public_key signer,
uint64_t fee,
uint32_t deadline,
const nem_transaction_ctx *inner);
bool nem_transaction_create_provision_namespace(nem_transaction_ctx *ctx,
uint8_t network,
uint32_t timestamp,
const ed25519_public_key signer,
uint64_t fee,
uint32_t deadline,
const char *namespace,
const char *parent,
const char *rental_sink,
uint64_t rental_fee);
bool nem_transaction_create_mosaic_creation(nem_transaction_ctx *ctx,
uint8_t network,
uint32_t timestamp,
const ed25519_public_key signer,
uint64_t fee,
uint32_t deadline,
const char *namespace,
const char *mosaic,
const char *description,
uint32_t divisibility,
uint64_t supply,
bool mutable_supply,
bool transferable,
uint32_t levy_type,
uint64_t levy_fee,
const char *levy_address,
const char *levy_namespace,
const char *levy_mosaic,
const char *creation_sink,
uint64_t creation_fee);
bool nem_transaction_create_mosaic_supply_change(nem_transaction_ctx *ctx,
uint8_t network,
uint32_t timestamp,
const ed25519_public_key signer,
uint64_t fee,
uint32_t deadline,
const char *namespace,
const char *mosaic,
uint32_t type,
uint64_t delta);
bool nem_transaction_create_aggregate_modification(nem_transaction_ctx *ctx,
uint8_t network,
uint32_t timestamp,
const ed25519_public_key signer,
uint64_t fee,
uint32_t deadline,
uint32_t modifications,
bool relative_change);
bool nem_transaction_write_cosignatory_modification(nem_transaction_ctx *ctx,
uint32_t type,
const ed25519_public_key cosignatory);
const char *namespace, const char *mosaic,
uint64_t quantity);
bool nem_transaction_create_multisig(nem_transaction_ctx *ctx, uint8_t network,
uint32_t timestamp,
const ed25519_public_key signer,
uint64_t fee, uint32_t deadline,
const nem_transaction_ctx *inner);
bool nem_transaction_create_multisig_signature(
nem_transaction_ctx *ctx, uint8_t network, uint32_t timestamp,
const ed25519_public_key signer, uint64_t fee, uint32_t deadline,
const nem_transaction_ctx *inner);
bool nem_transaction_create_provision_namespace(
nem_transaction_ctx *ctx, uint8_t network, uint32_t timestamp,
const ed25519_public_key signer, uint64_t fee, uint32_t deadline,
const char *namespace, const char *parent, const char *rental_sink,
uint64_t rental_fee);
bool nem_transaction_create_mosaic_creation(
nem_transaction_ctx *ctx, uint8_t network, uint32_t timestamp,
const ed25519_public_key signer, uint64_t fee, uint32_t deadline,
const char *namespace, const char *mosaic, const char *description,
uint32_t divisibility, uint64_t supply, bool mutable_supply,
bool transferable, uint32_t levy_type, uint64_t levy_fee,
const char *levy_address, const char *levy_namespace,
const char *levy_mosaic, const char *creation_sink, uint64_t creation_fee);
bool nem_transaction_create_mosaic_supply_change(
nem_transaction_ctx *ctx, uint8_t network, uint32_t timestamp,
const ed25519_public_key signer, uint64_t fee, uint32_t deadline,
const char *namespace, const char *mosaic, uint32_t type, uint64_t delta);
bool nem_transaction_create_aggregate_modification(
nem_transaction_ctx *ctx, uint8_t network, uint32_t timestamp,
const ed25519_public_key signer, uint64_t fee, uint32_t deadline,
uint32_t modifications, bool relative_change);
bool nem_transaction_write_cosignatory_modification(
nem_transaction_ctx *ctx, uint32_t type,
const ed25519_public_key cosignatory);
bool nem_transaction_write_minimum_cosignatories(nem_transaction_ctx *ctx,
int32_t relative_change);
bool nem_transaction_create_importance_transfer(nem_transaction_ctx *ctx,
uint8_t network,
uint32_t timestamp,
const ed25519_public_key signer,
uint64_t fee,
uint32_t deadline,
uint32_t mode,
const ed25519_public_key remote);
int32_t relative_change);
bool nem_transaction_create_importance_transfer(
nem_transaction_ctx *ctx, uint8_t network, uint32_t timestamp,
const ed25519_public_key signer, uint64_t fee, uint32_t deadline,
uint32_t mode, const ed25519_public_key remote);
#endif

@ -24,42 +24,45 @@
#include "nist256p1.h"
const ecdsa_curve nist256p1 = {
/* .prime */ {
/*.val =*/ {0x3fffffff, 0x3fffffff, 0x3fffffff, 0x3f, 0x0, 0x0, 0x1000, 0x3fffc000, 0xffff}
},
/* .prime */ {/*.val =*/{0x3fffffff, 0x3fffffff, 0x3fffffff, 0x3f, 0x0, 0x0,
0x1000, 0x3fffc000, 0xffff}},
/* G */ {
/*.x =*/{/*.val =*/{0x1898c296, 0x1284e517, 0x1eb33a0f, 0xdf604b, 0x2440f277, 0x339b958e, 0x4247f8b, 0x347cb84b, 0x6b17}},
/*.y =*/{/*.val =*/{0x37bf51f5, 0x2ed901a0, 0x3315ecec, 0x338cd5da, 0xf9e162b, 0x1fad29f0, 0x27f9b8ee, 0x10b8bf86, 0x4fe3}}
},
/* G */
{/*.x =*/{/*.val =*/{0x1898c296, 0x1284e517, 0x1eb33a0f, 0xdf604b,
0x2440f277, 0x339b958e, 0x4247f8b, 0x347cb84b,
0x6b17}},
/*.y =*/{/*.val =*/{0x37bf51f5, 0x2ed901a0, 0x3315ecec, 0x338cd5da,
0xf9e162b, 0x1fad29f0, 0x27f9b8ee, 0x10b8bf86,
0x4fe3}}},
/* order */ {
/*.val =*/{0x3c632551, 0xee72b0b, 0x3179e84f, 0x39beab69, 0x3fffffbc, 0x3fffffff, 0xfff, 0x3fffc000, 0xffff}
},
/* order */
{/*.val =*/{0x3c632551, 0xee72b0b, 0x3179e84f, 0x39beab69, 0x3fffffbc,
0x3fffffff, 0xfff, 0x3fffc000, 0xffff}},
/* order_half */ {
/*.val =*/{0x3e3192a8, 0x27739585, 0x38bcf427, 0x1cdf55b4, 0x3fffffde, 0x3fffffff, 0x7ff, 0x3fffe000, 0x7fff}
},
/* order_half */
{/*.val =*/{0x3e3192a8, 0x27739585, 0x38bcf427, 0x1cdf55b4, 0x3fffffde,
0x3fffffff, 0x7ff, 0x3fffe000, 0x7fff}},
/* a */ -3,
/* a */ -3,
/* b */ {
/*.val =*/{0x27d2604b, 0x2f38f0f8, 0x53b0f63, 0x741ac33, 0x1886bc65, 0x2ef555da, 0x293e7b3e, 0xd762a8e, 0x5ac6}
}
/* b */
{/*.val =*/{0x27d2604b, 0x2f38f0f8, 0x53b0f63, 0x741ac33, 0x1886bc65,
0x2ef555da, 0x293e7b3e, 0xd762a8e, 0x5ac6}}
#if USE_PRECOMPUTED_CP
,
/* cp */ {
,
/* cp */
{
#include "nist256p1.table"
}
}
#endif
};
const curve_info nist256p1_info = {
.bip32_name = "Nist256p1 seed",
.params = &nist256p1,
.hasher_base58 = HASHER_SHA2D,
.hasher_sign = HASHER_SHA2D,
.hasher_pubkey = HASHER_SHA2_RIPEMD,
.hasher_script = HASHER_SHA2,
.bip32_name = "Nist256p1 seed",
.params = &nist256p1,
.hasher_base58 = HASHER_SHA2D,
.hasher_sign = HASHER_SHA2D,
.hasher_pubkey = HASHER_SHA2_RIPEMD,
.hasher_script = HASHER_SHA2,
};

@ -26,8 +26,8 @@
#include <stdint.h>
#include "ecdsa.h"
#include "bip32.h"
#include "ecdsa.h"
extern const ecdsa_curve nist256p1;
extern const curve_info nist256p1_info;

@ -52,7 +52,7 @@
// support constructing BIP32 nodes from ed25519 and curve25519 curves.
#ifndef USE_BIP32_25519_CURVES
#define USE_BIP32_25519_CURVES 1
#define USE_BIP32_25519_CURVES 1
#endif
// implement BIP39 caching

@ -21,157 +21,159 @@
* OTHER DEALINGS IN THE SOFTWARE.
*/
#include <string.h>
#include "pbkdf2.h"
#include <string.h>
#include "hmac.h"
#include "sha2.h"
#include "memzero.h"
#include "sha2.h"
void pbkdf2_hmac_sha256_Init(PBKDF2_HMAC_SHA256_CTX *pctx, const uint8_t *pass, int passlen, const uint8_t *salt, int saltlen, uint32_t blocknr)
{
SHA256_CTX ctx;
void pbkdf2_hmac_sha256_Init(PBKDF2_HMAC_SHA256_CTX *pctx, const uint8_t *pass,
int passlen, const uint8_t *salt, int saltlen,
uint32_t blocknr) {
SHA256_CTX ctx;
#if BYTE_ORDER == LITTLE_ENDIAN
REVERSE32(blocknr, blocknr);
REVERSE32(blocknr, blocknr);
#endif
hmac_sha256_prepare(pass, passlen, pctx->odig, pctx->idig);
memzero(pctx->g, sizeof(pctx->g));
pctx->g[8] = 0x80000000;
pctx->g[15] = (SHA256_BLOCK_LENGTH + SHA256_DIGEST_LENGTH) * 8;
hmac_sha256_prepare(pass, passlen, pctx->odig, pctx->idig);
memzero(pctx->g, sizeof(pctx->g));
pctx->g[8] = 0x80000000;
pctx->g[15] = (SHA256_BLOCK_LENGTH + SHA256_DIGEST_LENGTH) * 8;
memcpy (ctx.state, pctx->idig, sizeof(pctx->idig));
ctx.bitcount = SHA256_BLOCK_LENGTH * 8;
sha256_Update(&ctx, salt, saltlen);
sha256_Update(&ctx, (uint8_t*)&blocknr, sizeof(blocknr));
sha256_Final(&ctx, (uint8_t*)pctx->g);
memcpy(ctx.state, pctx->idig, sizeof(pctx->idig));
ctx.bitcount = SHA256_BLOCK_LENGTH * 8;
sha256_Update(&ctx, salt, saltlen);
sha256_Update(&ctx, (uint8_t *)&blocknr, sizeof(blocknr));
sha256_Final(&ctx, (uint8_t *)pctx->g);
#if BYTE_ORDER == LITTLE_ENDIAN
for (uint32_t k = 0; k < SHA256_DIGEST_LENGTH / sizeof(uint32_t); k++) {
REVERSE32(pctx->g[k], pctx->g[k]);
}
for (uint32_t k = 0; k < SHA256_DIGEST_LENGTH / sizeof(uint32_t); k++) {
REVERSE32(pctx->g[k], pctx->g[k]);
}
#endif
sha256_Transform(pctx->odig, pctx->g, pctx->g);
memcpy(pctx->f, pctx->g, SHA256_DIGEST_LENGTH);
pctx->first = 1;
sha256_Transform(pctx->odig, pctx->g, pctx->g);
memcpy(pctx->f, pctx->g, SHA256_DIGEST_LENGTH);
pctx->first = 1;
}
void pbkdf2_hmac_sha256_Update(PBKDF2_HMAC_SHA256_CTX *pctx, uint32_t iterations)
{
for (uint32_t i = pctx->first; i < iterations; i++) {
sha256_Transform(pctx->idig, pctx->g, pctx->g);
sha256_Transform(pctx->odig, pctx->g, pctx->g);
for (uint32_t j = 0; j < SHA256_DIGEST_LENGTH/sizeof(uint32_t); j++) {
pctx->f[j] ^= pctx->g[j];
}
}
pctx->first = 0;
void pbkdf2_hmac_sha256_Update(PBKDF2_HMAC_SHA256_CTX *pctx,
uint32_t iterations) {
for (uint32_t i = pctx->first; i < iterations; i++) {
sha256_Transform(pctx->idig, pctx->g, pctx->g);
sha256_Transform(pctx->odig, pctx->g, pctx->g);
for (uint32_t j = 0; j < SHA256_DIGEST_LENGTH / sizeof(uint32_t); j++) {
pctx->f[j] ^= pctx->g[j];
}
}
pctx->first = 0;
}
void pbkdf2_hmac_sha256_Final(PBKDF2_HMAC_SHA256_CTX *pctx, uint8_t *key)
{
void pbkdf2_hmac_sha256_Final(PBKDF2_HMAC_SHA256_CTX *pctx, uint8_t *key) {
#if BYTE_ORDER == LITTLE_ENDIAN
for (uint32_t k = 0; k < SHA256_DIGEST_LENGTH/sizeof(uint32_t); k++) {
REVERSE32(pctx->f[k], pctx->f[k]);
}
for (uint32_t k = 0; k < SHA256_DIGEST_LENGTH / sizeof(uint32_t); k++) {
REVERSE32(pctx->f[k], pctx->f[k]);
}
#endif
memcpy(key, pctx->f, SHA256_DIGEST_LENGTH);
memzero(pctx, sizeof(PBKDF2_HMAC_SHA256_CTX));
memcpy(key, pctx->f, SHA256_DIGEST_LENGTH);
memzero(pctx, sizeof(PBKDF2_HMAC_SHA256_CTX));
}
void pbkdf2_hmac_sha256(const uint8_t *pass, int passlen, const uint8_t *salt, int saltlen, uint32_t iterations, uint8_t *key, int keylen)
{
uint32_t last_block_size = keylen % SHA256_DIGEST_LENGTH;
uint32_t blocks_count = keylen / SHA256_DIGEST_LENGTH;
if (last_block_size) {
blocks_count++;
} else {
last_block_size = SHA256_DIGEST_LENGTH;
}
for (uint32_t blocknr = 1; blocknr <= blocks_count; blocknr++) {
PBKDF2_HMAC_SHA256_CTX pctx;
pbkdf2_hmac_sha256_Init(&pctx, pass, passlen, salt, saltlen, blocknr);
pbkdf2_hmac_sha256_Update(&pctx, iterations);
uint8_t digest[SHA256_DIGEST_LENGTH];
pbkdf2_hmac_sha256_Final(&pctx, digest);
uint32_t key_offset = (blocknr - 1) * SHA256_DIGEST_LENGTH;
if (blocknr < blocks_count) {
memcpy(key + key_offset, digest, SHA256_DIGEST_LENGTH);
} else {
memcpy(key + key_offset, digest, last_block_size);
}
}
void pbkdf2_hmac_sha256(const uint8_t *pass, int passlen, const uint8_t *salt,
int saltlen, uint32_t iterations, uint8_t *key,
int keylen) {
uint32_t last_block_size = keylen % SHA256_DIGEST_LENGTH;
uint32_t blocks_count = keylen / SHA256_DIGEST_LENGTH;
if (last_block_size) {
blocks_count++;
} else {
last_block_size = SHA256_DIGEST_LENGTH;
}
for (uint32_t blocknr = 1; blocknr <= blocks_count; blocknr++) {
PBKDF2_HMAC_SHA256_CTX pctx;
pbkdf2_hmac_sha256_Init(&pctx, pass, passlen, salt, saltlen, blocknr);
pbkdf2_hmac_sha256_Update(&pctx, iterations);
uint8_t digest[SHA256_DIGEST_LENGTH];
pbkdf2_hmac_sha256_Final(&pctx, digest);
uint32_t key_offset = (blocknr - 1) * SHA256_DIGEST_LENGTH;
if (blocknr < blocks_count) {
memcpy(key + key_offset, digest, SHA256_DIGEST_LENGTH);
} else {
memcpy(key + key_offset, digest, last_block_size);
}
}
}
void pbkdf2_hmac_sha512_Init(PBKDF2_HMAC_SHA512_CTX *pctx, const uint8_t *pass, int passlen, const uint8_t *salt, int saltlen, uint32_t blocknr)
{
SHA512_CTX ctx;
void pbkdf2_hmac_sha512_Init(PBKDF2_HMAC_SHA512_CTX *pctx, const uint8_t *pass,
int passlen, const uint8_t *salt, int saltlen,
uint32_t blocknr) {
SHA512_CTX ctx;
#if BYTE_ORDER == LITTLE_ENDIAN
REVERSE32(blocknr, blocknr);
REVERSE32(blocknr, blocknr);
#endif
hmac_sha512_prepare(pass, passlen, pctx->odig, pctx->idig);
memzero(pctx->g, sizeof(pctx->g));
pctx->g[8] = 0x8000000000000000;
pctx->g[15] = (SHA512_BLOCK_LENGTH + SHA512_DIGEST_LENGTH) * 8;
hmac_sha512_prepare(pass, passlen, pctx->odig, pctx->idig);
memzero(pctx->g, sizeof(pctx->g));
pctx->g[8] = 0x8000000000000000;
pctx->g[15] = (SHA512_BLOCK_LENGTH + SHA512_DIGEST_LENGTH) * 8;
memcpy (ctx.state, pctx->idig, sizeof(pctx->idig));
ctx.bitcount[0] = SHA512_BLOCK_LENGTH * 8;
ctx.bitcount[1] = 0;
sha512_Update(&ctx, salt, saltlen);
sha512_Update(&ctx, (uint8_t*)&blocknr, sizeof(blocknr));
sha512_Final(&ctx, (uint8_t*)pctx->g);
memcpy(ctx.state, pctx->idig, sizeof(pctx->idig));
ctx.bitcount[0] = SHA512_BLOCK_LENGTH * 8;
ctx.bitcount[1] = 0;
sha512_Update(&ctx, salt, saltlen);
sha512_Update(&ctx, (uint8_t *)&blocknr, sizeof(blocknr));
sha512_Final(&ctx, (uint8_t *)pctx->g);
#if BYTE_ORDER == LITTLE_ENDIAN
for (uint32_t k = 0; k < SHA512_DIGEST_LENGTH / sizeof(uint64_t); k++) {
REVERSE64(pctx->g[k], pctx->g[k]);
}
for (uint32_t k = 0; k < SHA512_DIGEST_LENGTH / sizeof(uint64_t); k++) {
REVERSE64(pctx->g[k], pctx->g[k]);
}
#endif
sha512_Transform(pctx->odig, pctx->g, pctx->g);
memcpy(pctx->f, pctx->g, SHA512_DIGEST_LENGTH);
pctx->first = 1;
sha512_Transform(pctx->odig, pctx->g, pctx->g);
memcpy(pctx->f, pctx->g, SHA512_DIGEST_LENGTH);
pctx->first = 1;
}
void pbkdf2_hmac_sha512_Update(PBKDF2_HMAC_SHA512_CTX *pctx, uint32_t iterations)
{
for (uint32_t i = pctx->first; i < iterations; i++) {
sha512_Transform(pctx->idig, pctx->g, pctx->g);
sha512_Transform(pctx->odig, pctx->g, pctx->g);
for (uint32_t j = 0; j < SHA512_DIGEST_LENGTH / sizeof(uint64_t); j++) {
pctx->f[j] ^= pctx->g[j];
}
}
pctx->first = 0;
void pbkdf2_hmac_sha512_Update(PBKDF2_HMAC_SHA512_CTX *pctx,
uint32_t iterations) {
for (uint32_t i = pctx->first; i < iterations; i++) {
sha512_Transform(pctx->idig, pctx->g, pctx->g);
sha512_Transform(pctx->odig, pctx->g, pctx->g);
for (uint32_t j = 0; j < SHA512_DIGEST_LENGTH / sizeof(uint64_t); j++) {
pctx->f[j] ^= pctx->g[j];
}
}
pctx->first = 0;
}
void pbkdf2_hmac_sha512_Final(PBKDF2_HMAC_SHA512_CTX *pctx, uint8_t *key)
{
void pbkdf2_hmac_sha512_Final(PBKDF2_HMAC_SHA512_CTX *pctx, uint8_t *key) {
#if BYTE_ORDER == LITTLE_ENDIAN
for (uint32_t k = 0; k < SHA512_DIGEST_LENGTH/sizeof(uint64_t); k++) {
REVERSE64(pctx->f[k], pctx->f[k]);
}
for (uint32_t k = 0; k < SHA512_DIGEST_LENGTH / sizeof(uint64_t); k++) {
REVERSE64(pctx->f[k], pctx->f[k]);
}
#endif
memcpy(key, pctx->f, SHA512_DIGEST_LENGTH);
memzero(pctx, sizeof(PBKDF2_HMAC_SHA512_CTX));
memcpy(key, pctx->f, SHA512_DIGEST_LENGTH);
memzero(pctx, sizeof(PBKDF2_HMAC_SHA512_CTX));
}
void pbkdf2_hmac_sha512(const uint8_t *pass, int passlen, const uint8_t *salt, int saltlen, uint32_t iterations, uint8_t *key, int keylen)
{
uint32_t last_block_size = keylen % SHA512_DIGEST_LENGTH;
uint32_t blocks_count = keylen / SHA512_DIGEST_LENGTH;
if (last_block_size) {
blocks_count++;
} else {
last_block_size = SHA512_DIGEST_LENGTH;
}
for (uint32_t blocknr = 1; blocknr <= blocks_count; blocknr++) {
PBKDF2_HMAC_SHA512_CTX pctx;
pbkdf2_hmac_sha512_Init(&pctx, pass, passlen, salt, saltlen, blocknr);
pbkdf2_hmac_sha512_Update(&pctx, iterations);
uint8_t digest[SHA512_DIGEST_LENGTH];
pbkdf2_hmac_sha512_Final(&pctx, digest);
uint32_t key_offset = (blocknr - 1) * SHA512_DIGEST_LENGTH;
if (blocknr < blocks_count) {
memcpy(key + key_offset, digest, SHA512_DIGEST_LENGTH);
} else {
memcpy(key + key_offset, digest, last_block_size);
}
}
void pbkdf2_hmac_sha512(const uint8_t *pass, int passlen, const uint8_t *salt,
int saltlen, uint32_t iterations, uint8_t *key,
int keylen) {
uint32_t last_block_size = keylen % SHA512_DIGEST_LENGTH;
uint32_t blocks_count = keylen / SHA512_DIGEST_LENGTH;
if (last_block_size) {
blocks_count++;
} else {
last_block_size = SHA512_DIGEST_LENGTH;
}
for (uint32_t blocknr = 1; blocknr <= blocks_count; blocknr++) {
PBKDF2_HMAC_SHA512_CTX pctx;
pbkdf2_hmac_sha512_Init(&pctx, pass, passlen, salt, saltlen, blocknr);
pbkdf2_hmac_sha512_Update(&pctx, iterations);
uint8_t digest[SHA512_DIGEST_LENGTH];
pbkdf2_hmac_sha512_Final(&pctx, digest);
uint32_t key_offset = (blocknr - 1) * SHA512_DIGEST_LENGTH;
if (blocknr < blocks_count) {
memcpy(key + key_offset, digest, SHA512_DIGEST_LENGTH);
} else {
memcpy(key + key_offset, digest, last_block_size);
}
}
}

@ -28,29 +28,39 @@
#include "sha2.h"
typedef struct _PBKDF2_HMAC_SHA256_CTX {
uint32_t odig[SHA256_DIGEST_LENGTH / sizeof(uint32_t)];
uint32_t idig[SHA256_DIGEST_LENGTH / sizeof(uint32_t)];
uint32_t f[SHA256_DIGEST_LENGTH / sizeof(uint32_t)];
uint32_t g[SHA256_BLOCK_LENGTH / sizeof(uint32_t)];
char first;
uint32_t odig[SHA256_DIGEST_LENGTH / sizeof(uint32_t)];
uint32_t idig[SHA256_DIGEST_LENGTH / sizeof(uint32_t)];
uint32_t f[SHA256_DIGEST_LENGTH / sizeof(uint32_t)];
uint32_t g[SHA256_BLOCK_LENGTH / sizeof(uint32_t)];
char first;
} PBKDF2_HMAC_SHA256_CTX;
typedef struct _PBKDF2_HMAC_SHA512_CTX {
uint64_t odig[SHA512_DIGEST_LENGTH / sizeof(uint64_t)];
uint64_t idig[SHA512_DIGEST_LENGTH / sizeof(uint64_t)];
uint64_t f[SHA512_DIGEST_LENGTH / sizeof(uint64_t)];
uint64_t g[SHA512_BLOCK_LENGTH / sizeof(uint64_t)];
char first;
uint64_t odig[SHA512_DIGEST_LENGTH / sizeof(uint64_t)];
uint64_t idig[SHA512_DIGEST_LENGTH / sizeof(uint64_t)];
uint64_t f[SHA512_DIGEST_LENGTH / sizeof(uint64_t)];
uint64_t g[SHA512_BLOCK_LENGTH / sizeof(uint64_t)];
char first;
} PBKDF2_HMAC_SHA512_CTX;
void pbkdf2_hmac_sha256_Init(PBKDF2_HMAC_SHA256_CTX *pctx, const uint8_t *pass, int passlen, const uint8_t *salt, int saltlen, uint32_t blocknr);
void pbkdf2_hmac_sha256_Update(PBKDF2_HMAC_SHA256_CTX *pctx, uint32_t iterations);
void pbkdf2_hmac_sha256_Init(PBKDF2_HMAC_SHA256_CTX *pctx, const uint8_t *pass,
int passlen, const uint8_t *salt, int saltlen,
uint32_t blocknr);
void pbkdf2_hmac_sha256_Update(PBKDF2_HMAC_SHA256_CTX *pctx,
uint32_t iterations);
void pbkdf2_hmac_sha256_Final(PBKDF2_HMAC_SHA256_CTX *pctx, uint8_t *key);
void pbkdf2_hmac_sha256(const uint8_t *pass, int passlen, const uint8_t *salt, int saltlen, uint32_t iterations, uint8_t *key, int keylen);
void pbkdf2_hmac_sha256(const uint8_t *pass, int passlen, const uint8_t *salt,
int saltlen, uint32_t iterations, uint8_t *key,
int keylen);
void pbkdf2_hmac_sha512_Init(PBKDF2_HMAC_SHA512_CTX *pctx, const uint8_t *pass, int passlen, const uint8_t *salt, int saltlen, uint32_t blocknr);
void pbkdf2_hmac_sha512_Update(PBKDF2_HMAC_SHA512_CTX *pctx, uint32_t iterations);
void pbkdf2_hmac_sha512_Init(PBKDF2_HMAC_SHA512_CTX *pctx, const uint8_t *pass,
int passlen, const uint8_t *salt, int saltlen,
uint32_t blocknr);
void pbkdf2_hmac_sha512_Update(PBKDF2_HMAC_SHA512_CTX *pctx,
uint32_t iterations);
void pbkdf2_hmac_sha512_Final(PBKDF2_HMAC_SHA512_CTX *pctx, uint8_t *key);
void pbkdf2_hmac_sha512(const uint8_t *pass, int passlen, const uint8_t *salt, int saltlen, uint32_t iterations, uint8_t *key, int keylen);
void pbkdf2_hmac_sha512(const uint8_t *pass, int passlen, const uint8_t *salt,
int saltlen, uint32_t iterations, uint8_t *key,
int keylen);
#endif

@ -25,28 +25,27 @@
#ifndef RAND_PLATFORM_INDEPENDENT
#pragma message("NOT SUITABLE FOR PRODUCTION USE! Replace random32() function with your own secure code.")
#pragma message( \
"NOT SUITABLE FOR PRODUCTION USE! Replace random32() function with your own secure code.")
// The following code is not supposed to be used in a production environment.
// It's included only to make the library testable.
// The message above tries to prevent any accidental use outside of the test environment.
// The message above tries to prevent any accidental use outside of the test
// environment.
//
// You are supposed to replace the random8() and random32() function with your own secure code.
// There is also a possibility to replace the random_buffer() function as it is defined as a weak symbol.
// You are supposed to replace the random8() and random32() function with your
// own secure code. There is also a possibility to replace the random_buffer()
// function as it is defined as a weak symbol.
static uint32_t seed = 0;
void random_reseed(const uint32_t value)
{
seed = value;
}
void random_reseed(const uint32_t value) { seed = value; }
uint32_t random32(void)
{
// Linear congruential generator from Numerical Recipes
// https://en.wikipedia.org/wiki/Linear_congruential_generator
seed = 1664525 * seed + 1013904223;
return seed;
uint32_t random32(void) {
// Linear congruential generator from Numerical Recipes
// https://en.wikipedia.org/wiki/Linear_congruential_generator
seed = 1664525 * seed + 1013904223;
return seed;
}
#endif /* RAND_PLATFORM_INDEPENDENT */
@ -55,30 +54,28 @@ uint32_t random32(void)
// The following code is platform independent
//
void __attribute__((weak)) random_buffer(uint8_t *buf, size_t len)
{
uint32_t r = 0;
for (size_t i = 0; i < len; i++) {
if (i % 4 == 0) {
r = random32();
}
buf[i] = (r >> ((i % 4) * 8)) & 0xFF;
}
void __attribute__((weak)) random_buffer(uint8_t *buf, size_t len) {
uint32_t r = 0;
for (size_t i = 0; i < len; i++) {
if (i % 4 == 0) {
r = random32();
}
buf[i] = (r >> ((i % 4) * 8)) & 0xFF;
}
}
uint32_t random_uniform(uint32_t n)
{
uint32_t x, max = 0xFFFFFFFF - (0xFFFFFFFF % n);
while ((x = random32()) >= max);
return x / (max / n);
uint32_t random_uniform(uint32_t n) {
uint32_t x, max = 0xFFFFFFFF - (0xFFFFFFFF % n);
while ((x = random32()) >= max)
;
return x / (max / n);
}
void random_permute(char *str, size_t len)
{
for (int i = len - 1; i >= 1; i--) {
int j = random_uniform(i + 1);
char t = str[j];
str[j] = str[i];
str[i] = t;
}
void random_permute(char *str, size_t len) {
for (int i = len - 1; i >= 1; i--) {
int j = random_uniform(i + 1);
char t = str[j];
str[j] = str[i];
str[i] = t;
}
}

44
rc4.c

@ -23,34 +23,34 @@
#include "rc4.h"
static inline void rc4_swap(RC4_CTX *ctx, uint8_t i, uint8_t j) {
uint8_t temp = ctx->S[i];
ctx->S[i] = ctx->S[j];
ctx->S[j] = temp;
uint8_t temp = ctx->S[i];
ctx->S[i] = ctx->S[j];
ctx->S[j] = temp;
}
void rc4_init(RC4_CTX *ctx, const uint8_t *key, size_t length) {
ctx->i = 0;
ctx->j = 0;
for (size_t i = 0; i < 256; i++) {
ctx->S[i] = i;
}
uint8_t j = 0;
for (size_t i = 0; i < 256; i++) {
j += ctx->S[i] + key[i % length];
rc4_swap(ctx, i, j);
}
ctx->i = 0;
ctx->j = 0;
for (size_t i = 0; i < 256; i++) {
ctx->S[i] = i;
}
uint8_t j = 0;
for (size_t i = 0; i < 256; i++) {
j += ctx->S[i] + key[i % length];
rc4_swap(ctx, i, j);
}
}
void rc4_encrypt(RC4_CTX *ctx, uint8_t *buffer, size_t length) {
for (size_t idx = 0; idx < length; idx++) {
ctx->i++;
ctx->j += ctx->S[ctx->i];
for (size_t idx = 0; idx < length; idx++) {
ctx->i++;
ctx->j += ctx->S[ctx->i];
rc4_swap(ctx, ctx->i, ctx->j);
rc4_swap(ctx, ctx->i, ctx->j);
uint8_t K = ctx->S[(ctx->S[ctx->i] + ctx->S[ctx->j]) % 256];
buffer[idx] ^= K;
}
uint8_t K = ctx->S[(ctx->S[ctx->i] + ctx->S[ctx->j]) % 256];
buffer[idx] ^= K;
}
}

@ -23,12 +23,12 @@
#ifndef __RC4_H__
#define __RC4_H__
#include <stdint.h>
#include <stddef.h>
#include <stdint.h>
typedef struct {
uint8_t S[256];
uint8_t i, j;
uint8_t S[256];
uint8_t i, j;
} RC4_CTX;
void rc4_init(RC4_CTX *ctx, const uint8_t *key, size_t length);

@ -22,57 +22,56 @@
* OTHER DEALINGS IN THE SOFTWARE.
*/
#include <string.h>
#include "rfc6979.h"
#include <string.h>
#include "hmac.h"
#include "memzero.h"
void init_rfc6979(const uint8_t *priv_key, const uint8_t *hash, rfc6979_state *state) {
uint8_t bx[2*32];
uint8_t buf[32 + 1 + 2*32];
void init_rfc6979(const uint8_t *priv_key, const uint8_t *hash,
rfc6979_state *state) {
uint8_t bx[2 * 32];
uint8_t buf[32 + 1 + 2 * 32];
memcpy(bx, priv_key, 32);
memcpy(bx+32, hash, 32);
memcpy(bx, priv_key, 32);
memcpy(bx + 32, hash, 32);
memset(state->v, 1, sizeof(state->v));
memset(state->k, 0, sizeof(state->k));
memset(state->v, 1, sizeof(state->v));
memset(state->k, 0, sizeof(state->k));
memcpy(buf, state->v, sizeof(state->v));
buf[sizeof(state->v)] = 0x00;
memcpy(buf + sizeof(state->v) + 1, bx, 64);
hmac_sha256(state->k, sizeof(state->k), buf, sizeof(buf), state->k);
hmac_sha256(state->k, sizeof(state->k), state->v, sizeof(state->v), state->v);
memcpy(buf, state->v, sizeof(state->v));
buf[sizeof(state->v)] = 0x00;
memcpy(buf + sizeof(state->v) + 1, bx, 64);
hmac_sha256(state->k, sizeof(state->k), buf, sizeof(buf), state->k);
hmac_sha256(state->k, sizeof(state->k), state->v, sizeof(state->v), state->v);
memcpy(buf, state->v, sizeof(state->v));
buf[sizeof(state->v)] = 0x01;
memcpy(buf + sizeof(state->v) + 1, bx, 64);
hmac_sha256(state->k, sizeof(state->k), buf, sizeof(buf), state->k);
hmac_sha256(state->k, sizeof(state->k), state->v, sizeof(state->v), state->v);
memcpy(buf, state->v, sizeof(state->v));
buf[sizeof(state->v)] = 0x01;
memcpy(buf + sizeof(state->v) + 1, bx, 64);
hmac_sha256(state->k, sizeof(state->k), buf, sizeof(buf), state->k);
hmac_sha256(state->k, sizeof(state->k), state->v, sizeof(state->v), state->v);
memzero(bx, sizeof(bx));
memzero(buf, sizeof(buf));
memzero(bx, sizeof(bx));
memzero(buf, sizeof(buf));
}
// generate next number from deterministic random number generator
void generate_rfc6979(uint8_t rnd[32], rfc6979_state *state)
{
uint8_t buf[32 + 1];
void generate_rfc6979(uint8_t rnd[32], rfc6979_state *state) {
uint8_t buf[32 + 1];
hmac_sha256(state->k, sizeof(state->k), state->v, sizeof(state->v), state->v);
memcpy(buf, state->v, sizeof(state->v));
buf[sizeof(state->v)] = 0x00;
hmac_sha256(state->k, sizeof(state->k), buf, sizeof(state->v) + 1, state->k);
hmac_sha256(state->k, sizeof(state->k), state->v, sizeof(state->v), state->v);
memcpy(rnd, buf, 32);
memzero(buf, sizeof(buf));
hmac_sha256(state->k, sizeof(state->k), state->v, sizeof(state->v), state->v);
memcpy(buf, state->v, sizeof(state->v));
buf[sizeof(state->v)] = 0x00;
hmac_sha256(state->k, sizeof(state->k), buf, sizeof(state->v) + 1, state->k);
hmac_sha256(state->k, sizeof(state->k), state->v, sizeof(state->v), state->v);
memcpy(rnd, buf, 32);
memzero(buf, sizeof(buf));
}
// generate K in a deterministic way, according to RFC6979
// http://tools.ietf.org/html/rfc6979
void generate_k_rfc6979(bignum256 *k, rfc6979_state *state)
{
uint8_t buf[32];
generate_rfc6979(buf, state);
bn_read_be(buf, k);
memzero(buf, sizeof(buf));
void generate_k_rfc6979(bignum256 *k, rfc6979_state *state) {
uint8_t buf[32];
generate_rfc6979(buf, state);
bn_read_be(buf, k);
memzero(buf, sizeof(buf));
}

@ -30,10 +30,11 @@
// rfc6979 pseudo random number generator state
typedef struct {
uint8_t v[32], k[32];
uint8_t v[32], k[32];
} rfc6979_state;
void init_rfc6979(const uint8_t *priv_key, const uint8_t *hash, rfc6979_state *rng);
void init_rfc6979(const uint8_t *priv_key, const uint8_t *hash,
rfc6979_state *rng);
void generate_rfc6979(uint8_t rnd[32], rfc6979_state *rng);
void generate_k_rfc6979(bignum256 *k, rfc6979_state *rng);

@ -3,18 +3,20 @@
#include <stdint.h>
#define RIPEMD160_BLOCK_LENGTH 64
#define RIPEMD160_DIGEST_LENGTH 20
#define RIPEMD160_BLOCK_LENGTH 64
#define RIPEMD160_DIGEST_LENGTH 20
typedef struct _RIPEMD160_CTX {
uint32_t total[2]; /*!< number of bytes processed */
uint32_t state[5]; /*!< intermediate digest state */
uint8_t buffer[RIPEMD160_BLOCK_LENGTH]; /*!< data block being processed */
uint32_t total[2]; /*!< number of bytes processed */
uint32_t state[5]; /*!< intermediate digest state */
uint8_t buffer[RIPEMD160_BLOCK_LENGTH]; /*!< data block being processed */
} RIPEMD160_CTX;
void ripemd160_Init(RIPEMD160_CTX *ctx);
void ripemd160_Update(RIPEMD160_CTX *ctx, const uint8_t *input, uint32_t ilen);
void ripemd160_Final(RIPEMD160_CTX *ctx, uint8_t output[RIPEMD160_DIGEST_LENGTH]);
void ripemd160(const uint8_t *msg, uint32_t msg_len, uint8_t hash[RIPEMD160_DIGEST_LENGTH]);
void ripemd160_Final(RIPEMD160_CTX *ctx,
uint8_t output[RIPEMD160_DIGEST_LENGTH]);
void ripemd160(const uint8_t *msg, uint32_t msg_len,
uint8_t hash[RIPEMD160_DIGEST_LENGTH]);
#endif

@ -20,45 +20,47 @@
* OTHER DEALINGS IN THE SOFTWARE.
*/
#include "script.h"
#include <string.h>
#include "base58.h"
#include "script.h"
int script_output_to_address(const uint8_t *script, int scriptlen, char *addr, int addrsize)
{
uint8_t raw[35];
int script_output_to_address(const uint8_t *script, int scriptlen, char *addr,
int addrsize) {
uint8_t raw[35];
// P2PKH
if (scriptlen == 25 && script[0] == 0x76 && script[1] == 0xA9 && script[2] == 0x14 && script[23] == 0x88 && script[24] == 0xAC) {
raw[0] = 0x00;
memcpy(raw + 1, script + 3, 20);
return base58_encode_check(raw, 1 + 20, HASHER_SHA2D, addr, addrsize);
}
// P2PKH
if (scriptlen == 25 && script[0] == 0x76 && script[1] == 0xA9 &&
script[2] == 0x14 && script[23] == 0x88 && script[24] == 0xAC) {
raw[0] = 0x00;
memcpy(raw + 1, script + 3, 20);
return base58_encode_check(raw, 1 + 20, HASHER_SHA2D, addr, addrsize);
}
// P2SH
if (scriptlen == 23 && script[0] == 0xA9 && script[1] == 0x14 && script[22] == 0x87) {
raw[0] = 0x05;
memcpy(raw + 1, script + 2, 20);
return base58_encode_check(raw, 1 + 20, HASHER_SHA2D, addr, addrsize);
}
// P2SH
if (scriptlen == 23 && script[0] == 0xA9 && script[1] == 0x14 &&
script[22] == 0x87) {
raw[0] = 0x05;
memcpy(raw + 1, script + 2, 20);
return base58_encode_check(raw, 1 + 20, HASHER_SHA2D, addr, addrsize);
}
// P2WPKH
if (scriptlen == 22 && script[0] == 0x00 && script[1] == 0x14) {
raw[0] = 0x06;
raw[1] = 0x00;
raw[2] = 0x00;
memcpy(raw + 3, script + 2, 20);
return base58_encode_check(raw, 3 + 20, HASHER_SHA2D, addr, addrsize);
}
// P2WPKH
if (scriptlen == 22 && script[0] == 0x00 && script[1] == 0x14) {
raw[0] = 0x06;
raw[1] = 0x00;
raw[2] = 0x00;
memcpy(raw + 3, script + 2, 20);
return base58_encode_check(raw, 3 + 20, HASHER_SHA2D, addr, addrsize);
}
// P2WSH
if (scriptlen == 34 && script[0] == 0x00 && script[1] == 0x20) {
raw[0] = 0x0A;
raw[1] = 0x00;
raw[2] = 0x00;
memcpy(raw + 3, script + 2, 32);
return base58_encode_check(raw, 3 + 32, HASHER_SHA2D, addr, addrsize);
}
// P2WSH
if (scriptlen == 34 && script[0] == 0x00 && script[1] == 0x20) {
raw[0] = 0x0A;
raw[1] = 0x00;
raw[2] = 0x00;
memcpy(raw + 3, script + 2, 32);
return base58_encode_check(raw, 3 + 32, HASHER_SHA2D, addr, addrsize);
}
return 0;
return 0;
}

@ -25,6 +25,7 @@
#include <stdint.h>
int script_output_to_address(const uint8_t *script, int scriptlen, char *addr, int addrsize);
int script_output_to_address(const uint8_t *script, int scriptlen, char *addr,
int addrsize);
#endif

@ -24,69 +24,70 @@
#include "secp256k1.h"
const ecdsa_curve secp256k1 = {
/* .prime */ {
/*.val =*/ {0x3ffffc2f, 0x3ffffffb, 0x3fffffff, 0x3fffffff, 0x3fffffff, 0x3fffffff, 0x3fffffff, 0x3fffffff, 0xffff}
},
/* .prime */ {/*.val =*/{0x3ffffc2f, 0x3ffffffb, 0x3fffffff, 0x3fffffff,
0x3fffffff, 0x3fffffff, 0x3fffffff, 0x3fffffff,
0xffff}},
/* G */ {
/*.x =*/{/*.val =*/{0x16f81798, 0x27ca056c, 0x1ce28d95, 0x26ff36cb, 0x70b0702, 0x18a573a, 0xbbac55a, 0x199fbe77, 0x79be}},
/*.y =*/{/*.val =*/{0x3b10d4b8, 0x311f423f, 0x28554199, 0x5ed1229, 0x1108a8fd, 0x13eff038, 0x3c4655da, 0x369dc9a8, 0x483a}}
},
/* G */
{/*.x =*/{/*.val =*/{0x16f81798, 0x27ca056c, 0x1ce28d95, 0x26ff36cb,
0x70b0702, 0x18a573a, 0xbbac55a, 0x199fbe77, 0x79be}},
/*.y =*/{/*.val =*/{0x3b10d4b8, 0x311f423f, 0x28554199, 0x5ed1229,
0x1108a8fd, 0x13eff038, 0x3c4655da, 0x369dc9a8,
0x483a}}},
/* order */ {
/*.val =*/{0x10364141, 0x3f497a33, 0x348a03bb, 0x2bb739ab, 0x3ffffeba, 0x3fffffff, 0x3fffffff, 0x3fffffff, 0xffff}
},
/* order */
{/*.val =*/{0x10364141, 0x3f497a33, 0x348a03bb, 0x2bb739ab, 0x3ffffeba,
0x3fffffff, 0x3fffffff, 0x3fffffff, 0xffff}},
/* order_half */ {
/*.val =*/{0x281b20a0, 0x3fa4bd19, 0x3a4501dd, 0x15db9cd5, 0x3fffff5d, 0x3fffffff, 0x3fffffff, 0x3fffffff, 0x7fff}
},
/* order_half */
{/*.val =*/{0x281b20a0, 0x3fa4bd19, 0x3a4501dd, 0x15db9cd5, 0x3fffff5d,
0x3fffffff, 0x3fffffff, 0x3fffffff, 0x7fff}},
/* a */ 0,
/* a */ 0,
/* b */ {
/*.val =*/{7}
}
/* b */ {/*.val =*/{7}}
#if USE_PRECOMPUTED_CP
,
/* cp */ {
,
/* cp */
{
#include "secp256k1.table"
}
}
#endif
};
const curve_info secp256k1_info = {
.bip32_name = "Bitcoin seed",
.params = &secp256k1,
.hasher_base58 = HASHER_SHA2D,
.hasher_sign = HASHER_SHA2D,
.hasher_pubkey = HASHER_SHA2_RIPEMD,
.hasher_script = HASHER_SHA2,
.bip32_name = "Bitcoin seed",
.params = &secp256k1,
.hasher_base58 = HASHER_SHA2D,
.hasher_sign = HASHER_SHA2D,
.hasher_pubkey = HASHER_SHA2_RIPEMD,
.hasher_script = HASHER_SHA2,
};
const curve_info secp256k1_decred_info = {
.bip32_name = "Bitcoin seed",
.params = &secp256k1,
.hasher_base58 = HASHER_BLAKED,
.hasher_sign = HASHER_BLAKE,
.hasher_pubkey = HASHER_BLAKE_RIPEMD,
.hasher_script = HASHER_BLAKE,
.bip32_name = "Bitcoin seed",
.params = &secp256k1,
.hasher_base58 = HASHER_BLAKED,
.hasher_sign = HASHER_BLAKE,
.hasher_pubkey = HASHER_BLAKE_RIPEMD,
.hasher_script = HASHER_BLAKE,
};
const curve_info secp256k1_groestl_info = {
.bip32_name = "Bitcoin seed",
.params = &secp256k1,
.hasher_base58 = HASHER_GROESTLD_TRUNC,
.hasher_sign = HASHER_SHA2,
.hasher_pubkey = HASHER_SHA2_RIPEMD,
.hasher_script = HASHER_SHA2,
.bip32_name = "Bitcoin seed",
.params = &secp256k1,
.hasher_base58 = HASHER_GROESTLD_TRUNC,
.hasher_sign = HASHER_SHA2,
.hasher_pubkey = HASHER_SHA2_RIPEMD,
.hasher_script = HASHER_SHA2,
};
const curve_info secp256k1_smart_info = {
.bip32_name = "Bitcoin seed",
.params = &secp256k1,
.hasher_base58 = HASHER_SHA3K,
.hasher_sign = HASHER_SHA2,
.hasher_pubkey = HASHER_SHA2_RIPEMD,
.hasher_script = HASHER_SHA2,
.bip32_name = "Bitcoin seed",
.params = &secp256k1,
.hasher_base58 = HASHER_SHA3K,
.hasher_sign = HASHER_SHA2,
.hasher_pubkey = HASHER_SHA2_RIPEMD,
.hasher_script = HASHER_SHA2,
};

@ -26,8 +26,8 @@
#include <stdint.h>
#include "ecdsa.h"
#include "bip32.h"
#include "ecdsa.h"
extern const ecdsa_curve secp256k1;
extern const curve_info secp256k1_info;

@ -35,13 +35,8 @@
* prog_len: Number of data bytes in prog.
* Returns 1 if successful.
*/
int segwit_addr_encode(
char *output,
const char *hrp,
int ver,
const uint8_t *prog,
size_t prog_len
);
int segwit_addr_encode(char *output, const char *hrp, int ver,
const uint8_t *prog, size_t prog_len);
/** Decode a SegWit address
*
@ -49,20 +44,13 @@ int segwit_addr_encode(
* program version (between 0 and 16 inclusive).
* prog: Pointer to a buffer of size 40 that will be updated to
* contain the witness program bytes.
* prog_len: Pointer to a size_t that will be updated to contain the length
* of bytes in prog.
* hrp: Pointer to the null-terminated human readable part that is
* expected (chain/network specific).
* addr: Pointer to the null-terminated address.
* Returns 1 if successful.
* prog_len: Pointer to a size_t that will be updated to contain the
* length of bytes in prog. hrp: Pointer to the null-terminated human
* readable part that is expected (chain/network specific). addr: Pointer to
* the null-terminated address. Returns 1 if successful.
*/
int segwit_addr_decode(
int* ver,
uint8_t* prog,
size_t* prog_len,
const char* hrp,
const char* addr
);
int segwit_addr_decode(int *ver, uint8_t *prog, size_t *prog_len,
const char *hrp, const char *addr);
/** Encode a Bech32 string
*
@ -73,12 +61,8 @@ int segwit_addr_decode(
* data_len: Length of the data array.
* Returns 1 if successful.
*/
int bech32_encode(
char *output,
const char *hrp,
const uint8_t *data,
size_t data_len
);
int bech32_encode(char *output, const char *hrp, const uint8_t *data,
size_t data_len);
/** Decode a Bech32 string
*
@ -91,11 +75,7 @@ int bech32_encode(
* In: input: Pointer to a null-terminated Bech32 string.
* Returns 1 if succesful.
*/
int bech32_decode(
char *hrp,
uint8_t *data,
size_t *data_len,
const char *input
);
int bech32_decode(char *hrp, uint8_t *data, size_t *data_len,
const char *input);
#endif

@ -2,5 +2,5 @@ with import <nixpkgs> {};
stdenv.mkDerivation {
name = "trezor-crypto-dev";
buildInputs = [ gnumake gcc pkgconfig openssl check valgrind ];
buildInputs = [ gnumake gcc pkgconfig openssl check valgrind clang-tools ];
}

File diff suppressed because it is too large Load Diff

@ -1,215 +1,379 @@
// 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;
}
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[] =
{
"6065a956b1b34145c4416fdc3ba3276801850e91a77a31a7be782463288aea5"
"3", // private key
"60ba6e25b1a02157fb69c5d1d7b96c4619736e545447069a6a6f0ba90844bc8"
"e", // private key extension
"64b20fa082b3143d6b5eed42c6ef63f99599d0888afe060620abc1b319935fe"
"1", // public key
"45b1a75fe3119e13c6f60ab9ba674b42f946fdc558e07c83dfa0751c2eba69c7"
"9331bd8a4a975662b23628a438a0eba76367e44c12ca91b39ec59063f860f10"
"d", // signature
"e7d27516538403a53a8b041656a3f570909df641a0ab811fe7d87c9ba02a830"
"c", // private key
"794a2c54ad8b525b781773c87d38cbf4197636bc427a9d551368286fe4c294a"
"4", // private key extension
"95bb82ffd5707716bc65170ab4e8dafeed90fbe0ce9258713b7751e962d931d"
"f", // public key
"f2c9171782e7df7665126ac545ae53b05964b0160536efdb545e2460dbbec2b1"
"9ec6b338b8f1bf4dfee94360ed024b115e37b1d7e6f3f9ae4beb79539428560"
"f", // signature
"9b5a3d9a4c60bcd49bb64b72c082b164314d0f61d842f2575fd1d4fb30a28a0"
"c", // private key
"b093e376f41eb7bf80abcd0073a52455d25b5d21815bc758e5f6f81536aedeb"
"b", // private key extension
"79fc8154554b97e4c56ef2f9dbb4c1421ff19509688931a1e964bda5dec0f19"
"f", // public key
"2ba1439ae648a7e8da7c9ab1ee6da94fd4ebe37abd0978306e8fba2afa8f111a"
"88a993dbf008bedae9167f4f68409e4c9ddaf02cba12418447b1848907ad800"
"f", // signature
"52e0c98aa600cfdcd1ff28fcda5227ed87063f4a98547a78b771052cf102b40"
"c", // private key
"6c18d9f8075b1a6a1833540607479bd58b7beb8a83d2bb01ca7ae02452a2580"
"3", // private key extension
"dc907c7c06e6314eedd9e18c9f6c6f9cc4e205fb1c70da608234c319f1f7b0d"
"6", // public key
"0cd34f84e0d2fcb1800bdb0e869b9041349955ced66aedbe6bda187ebe8d36a6"
"2a05b39647e92fcc42aa7a7368174240afba08b8c81f981a22f942d6bd78160"
"2", // signature
"11fd6462a3a92b35c22703f6f1c124ddcf36b7c2b09cc2784f320e1cfa12ec0"
"4", // private key
"c2785803c61c46aeca192a1bb1b7b20a8c4cc7fa01db57fc5d1d8a547340235"
"2", // private key extension
"839775a41876e328986aa26168958bba1176e67819b357eea84afceab8b1db7"
"8", // public key
"e41f73db2f8d2896a687802b2be76b7cabb73dfbb4891494883a0cbd9bbb9e5f"
"9d3e14d2d0b06c6674333508496db660936737c0efd9511514147dac79fa490"
"5", // signature
"5b1e5cad02274ba461f4708d8598d3497faf8fe3e894a379573aa6ac3a03e50"
"5", // private key
"ba179d2e3c67aabb486c48d16002b51ad32eab434c738a1550962313b07098c"
"d", // private key extension
"75eb8d197ec8627c85af88e66aa1e49065dd8ac98ed8991db52ece01635dfb7"
"6", // public key
"631015357cee3051116b4c2ff4d1c5beb13b6e5023635aa1eeb0563cadf0d4fb"
"c10bd5e31b4a4220c67875558c41b5cc0328104ae39cc7ff20ff0c2bda59890"
"6", // signature
"624b47150f58dfa44284fbc63c9f99b9b79f808c4955a461f0e2be44eb0be50"
"d", // private key
"097aa006d694b165ef37cf23562e5967c96e49255d2f20faae478dee83aa5b0"
"2", // private key extension
"0588589cd9b51dfc028cf225674069cbe52e0e70deb02dc45b79b26ee3548b0"
"0", // public key
"1de1d275428ba9491a433cd473cd076c027f61e7a8b5391df9dea5cb4bc88d8a"
"57b095906a30b13e68259851a8dd3f57b6f0ffa37a5d3ffc171240f2d404f90"
"1", // 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
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);
ck_assert_int_eq(seed_len, 132);
hdnode_from_seed_cardano((const uint8_t *)"", 0, seed, seed_len / 8, &node);
ck_assert_mem_eq(node.chain_code, fromhex("affbc325d9027c0f2d9f925b1dcf6c12bf5c1dd08904474066a4f2c00db56173"), 32);
ck_assert_mem_eq(node.private_key, fromhex("08a14df748e477a69d21c97c56db151fc19e2521f31dd0ac5360f269e5b6ea46"), 32);
ck_assert_mem_eq(node.private_key_extension, fromhex("daeb991f2d2128e2525415c56a07f4366baa26c1e48572a5e073934b6de35fbc"), 32);
hdnode_fill_public_key(&node);
ck_assert_mem_eq(node.public_key + 1, fromhex("9a1d04808b4c0682816961cf666e82a7fd35949658aba5354c517eccf12aacb4"), 32);
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);
ck_assert_int_eq(seed_len, 132);
hdnode_from_seed_cardano((const uint8_t *)"", 0, seed, seed_len / 8, &node);
ck_assert_mem_eq(
node.chain_code,
fromhex(
"affbc325d9027c0f2d9f925b1dcf6c12bf5c1dd08904474066a4f2c00db56173"),
32);
ck_assert_mem_eq(
node.private_key,
fromhex(
"08a14df748e477a69d21c97c56db151fc19e2521f31dd0ac5360f269e5b6ea46"),
32);
ck_assert_mem_eq(
node.private_key_extension,
fromhex(
"daeb991f2d2128e2525415c56a07f4366baa26c1e48572a5e073934b6de35fbc"),
32);
hdnode_fill_public_key(&node);
ck_assert_mem_eq(
node.public_key + 1,
fromhex(
"9a1d04808b4c0682816961cf666e82a7fd35949658aba5354c517eccf12aacb4"),
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);
ck_assert_int_eq(seed_len, 132);
hdnode_from_seed_cardano((const uint8_t *)"", 0, seed, seed_len / 8, &node);
hdnode_private_ckd_cardano(&node, 0x80000000);
ck_assert_mem_eq(node.chain_code, fromhex("104c6a0736e501c9bfe2966ba3773f5320495b19c3f2ed222234850af2ccd5b1"), 32);
ck_assert_mem_eq(node.private_key, fromhex("6064bf06b2e981d7c9792b1482eeecd40ec3cfa12143f4a1f149d48ce8b6ea46"), 32);
ck_assert_mem_eq(node.private_key_extension, fromhex("64aa9a16331f14c981b769efcf96addcc4c6db44047fe7a7feae0be23d33bf54"), 32);
hdnode_fill_public_key(&node);
ck_assert_mem_eq(node.public_key + 1, fromhex("c651c14a13c2311fc30a7acf244add1fdac3683e7ba89b4571e4cbcab509b915"), 32);
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);
ck_assert_int_eq(seed_len, 132);
hdnode_from_seed_cardano((const uint8_t *)"", 0, seed, seed_len / 8, &node);
hdnode_private_ckd_cardano(&node, 0x80000000);
ck_assert_mem_eq(
node.chain_code,
fromhex(
"104c6a0736e501c9bfe2966ba3773f5320495b19c3f2ed222234850af2ccd5b1"),
32);
ck_assert_mem_eq(
node.private_key,
fromhex(
"6064bf06b2e981d7c9792b1482eeecd40ec3cfa12143f4a1f149d48ce8b6ea46"),
32);
ck_assert_mem_eq(
node.private_key_extension,
fromhex(
"64aa9a16331f14c981b769efcf96addcc4c6db44047fe7a7feae0be23d33bf54"),
32);
hdnode_fill_public_key(&node);
ck_assert_mem_eq(
node.public_key + 1,
fromhex(
"c651c14a13c2311fc30a7acf244add1fdac3683e7ba89b4571e4cbcab509b915"),
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);
ck_assert_int_eq(seed_len, 132);
hdnode_from_seed_cardano((const uint8_t *)"", 0, seed, seed_len / 8, &node);
hdnode_private_ckd_cardano(&node, 0x80000001);
ck_assert_mem_eq(node.chain_code, fromhex("da99870d7e69de2a76f255ba8c7ed22428c7e5b0a8df978753c707c95ec3d4ca"), 32);
ck_assert_mem_eq(node.private_key, fromhex("c85fa69f4a1891fd98d1d1fc5f0cf9b1d6e44b0e6906744ab23ea766edb6ea46"), 32);
ck_assert_mem_eq(node.private_key_extension, fromhex("b4fc241feffe840b8a54a26ab447f5a5caa31032db3a8091fca14f38b86ed539"), 32);
hdnode_fill_public_key(&node);
ck_assert_mem_eq(node.public_key + 1, fromhex("5a5b0c92530cd366f05cf072509c806f904262c259e79a0080bbd5ee35706bb1"), 32);
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);
ck_assert_int_eq(seed_len, 132);
hdnode_from_seed_cardano((const uint8_t *)"", 0, seed, seed_len / 8, &node);
hdnode_private_ckd_cardano(&node, 0x80000001);
ck_assert_mem_eq(
node.chain_code,
fromhex(
"da99870d7e69de2a76f255ba8c7ed22428c7e5b0a8df978753c707c95ec3d4ca"),
32);
ck_assert_mem_eq(
node.private_key,
fromhex(
"c85fa69f4a1891fd98d1d1fc5f0cf9b1d6e44b0e6906744ab23ea766edb6ea46"),
32);
ck_assert_mem_eq(
node.private_key_extension,
fromhex(
"b4fc241feffe840b8a54a26ab447f5a5caa31032db3a8091fca14f38b86ed539"),
32);
hdnode_fill_public_key(&node);
ck_assert_mem_eq(
node.public_key + 1,
fromhex(
"5a5b0c92530cd366f05cf072509c806f904262c259e79a0080bbd5ee35706bb1"),
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);
ck_assert_int_eq(seed_len, 132);
hdnode_from_seed_cardano((const uint8_t *)"", 0, 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("b40c44dfd9be08591b62be7f9991c85f812d8196927f3c824d9fcb17d275089e"), 32);
ck_assert_mem_eq(node.private_key, fromhex("d064dcf1449d9c3e47f5b422680343561989035bf2e4e23fc34cb61fedb6ea46"), 32);
ck_assert_mem_eq(node.private_key_extension, fromhex("a3071959013af95aaecf78a7a2e1b9838bbbc4864d6a8a2295243782078345cd"), 32);
hdnode_fill_public_key(&node);
ck_assert_mem_eq(node.public_key + 1, fromhex("aaaca5e7adc69a03ef1f5c017ed02879e8ca871df028461ed9bf19fb8fa15038"), 32);
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);
ck_assert_int_eq(seed_len, 132);
hdnode_from_seed_cardano((const uint8_t *)"", 0, 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(
"b40c44dfd9be08591b62be7f9991c85f812d8196927f3c824d9fcb17d275089e"),
32);
ck_assert_mem_eq(
node.private_key,
fromhex(
"d064dcf1449d9c3e47f5b422680343561989035bf2e4e23fc34cb61fedb6ea46"),
32);
ck_assert_mem_eq(
node.private_key_extension,
fromhex(
"a3071959013af95aaecf78a7a2e1b9838bbbc4864d6a8a2295243782078345cd"),
32);
hdnode_fill_public_key(&node);
ck_assert_mem_eq(
node.public_key + 1,
fromhex(
"aaaca5e7adc69a03ef1f5c017ed02879e8ca871df028461ed9bf19fb8fa15038"),
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);
ck_assert_int_eq(seed_len, 132);
hdnode_from_seed_cardano((const uint8_t *)"", 0, 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("2593896baf92f6ab2c0f253787ab16be0244ba95e0d48ba09da1a7fd3f926c72"), 32);
ck_assert_mem_eq(node.private_key, fromhex("0811b6d5d6f7120cb05d4ce5453d6ce42825c2a8e53b6d370a6b05ccf4b6ea46"), 32);
ck_assert_mem_eq(node.private_key_extension, fromhex("5bebf1eea68acd04932653d944b064b10baaf5886dd73c185cc285059bf93363"), 32);
hdnode_fill_public_key(&node);
ck_assert_mem_eq(node.public_key + 1, fromhex("1c87a32c5babad2fe33e0586bdc523574c6126f8368bc76598e17ea46201f980"), 32);
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);
ck_assert_int_eq(seed_len, 132);
hdnode_from_seed_cardano((const uint8_t *)"", 0, 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(
"2593896baf92f6ab2c0f253787ab16be0244ba95e0d48ba09da1a7fd3f926c72"),
32);
ck_assert_mem_eq(
node.private_key,
fromhex(
"0811b6d5d6f7120cb05d4ce5453d6ce42825c2a8e53b6d370a6b05ccf4b6ea46"),
32);
ck_assert_mem_eq(
node.private_key_extension,
fromhex(
"5bebf1eea68acd04932653d944b064b10baaf5886dd73c185cc285059bf93363"),
32);
hdnode_fill_public_key(&node);
ck_assert_mem_eq(
node.public_key + 1,
fromhex(
"1c87a32c5babad2fe33e0586bdc523574c6126f8368bc76598e17ea46201f980"),
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);
ck_assert_int_eq(seed_len, 132);
hdnode_from_seed_cardano((const uint8_t *)"", 0, 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("fe8c6c2ab1e30385513fcffb49dcfe3e7805260425ea76b3b72b9f5bbe3b3d40"), 32);
ck_assert_mem_eq(node.private_key, fromhex("6019b9f5ef6ca530b657bcdb500de5455db8d51afb951fa045b6fbb3f6b6ea46"), 32);
ck_assert_mem_eq(node.private_key_extension, fromhex("466332cb097934b43008701e7e27044aa56c7859019e4eba18d91a3bea23dff7"), 32);
hdnode_fill_public_key(&node);
ck_assert_mem_eq(node.public_key + 1, fromhex("0b8f04755481ced76b4e5795aaafdb3cbd757c10fe60e9c58f48cf29a7ec3575"), 32);
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);
ck_assert_int_eq(seed_len, 132);
hdnode_from_seed_cardano((const uint8_t *)"", 0, 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(
"fe8c6c2ab1e30385513fcffb49dcfe3e7805260425ea76b3b72b9f5bbe3b3d40"),
32);
ck_assert_mem_eq(
node.private_key,
fromhex(
"6019b9f5ef6ca530b657bcdb500de5455db8d51afb951fa045b6fbb3f6b6ea46"),
32);
ck_assert_mem_eq(
node.private_key_extension,
fromhex(
"466332cb097934b43008701e7e27044aa56c7859019e4eba18d91a3bea23dff7"),
32);
hdnode_fill_public_key(&node);
ck_assert_mem_eq(
node.public_key + 1,
fromhex(
"0b8f04755481ced76b4e5795aaafdb3cbd757c10fe60e9c58f48cf29a7ec3575"),
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);
ck_assert_int_eq(seed_len, 132);
hdnode_from_seed_cardano((const uint8_t *)"", 0, 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("ff77c08d37471c1d4cedd3fae2642c009324d9712492efc74dedab09c9bf973c"), 32);
ck_assert_mem_eq(node.private_key, fromhex("488f34840bba516f7920f91676b8681d0dd833b4ce14468e0810b255f9b6ea46"), 32);
ck_assert_mem_eq(node.private_key_extension, fromhex("01eccef768a79859f824a1d3c3e35e131184e2940c3fca9a4c9b307741f65363"), 32);
hdnode_fill_public_key(&node);
ck_assert_mem_eq(node.public_key + 1, fromhex("148605be54585773b44ba87e79265149ae444c4cc37cb1f8db8c08482fba293b"), 32);
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);
ck_assert_int_eq(seed_len, 132);
hdnode_from_seed_cardano((const uint8_t *)"", 0, 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(
"ff77c08d37471c1d4cedd3fae2642c009324d9712492efc74dedab09c9bf973c"),
32);
ck_assert_mem_eq(
node.private_key,
fromhex(
"488f34840bba516f7920f91676b8681d0dd833b4ce14468e0810b255f9b6ea46"),
32);
ck_assert_mem_eq(
node.private_key_extension,
fromhex(
"01eccef768a79859f824a1d3c3e35e131184e2940c3fca9a4c9b307741f65363"),
32);
hdnode_fill_public_key(&node);
ck_assert_mem_eq(
node.public_key + 1,
fromhex(
"148605be54585773b44ba87e79265149ae444c4cc37cb1f8db8c08482fba293b"),
32);
}
END_TEST

@ -1,76 +1,67 @@
#include "cash_addr.h"
static const char* valid_cashchecksum[] = {
"prefix:x64nx6hz",
"p:gpf8m4h7",
"bitcoincash:qpzry9x8gf2tvdw0s3jn54khce6mua7lcw20ayyn",
"bchtest:testnetaddress4d6njnut",
"bchreg:555555555555555555555555555555555555555555555udxmlmrz",
"prefix:x64nx6hz",
"p:gpf8m4h7",
"bitcoincash:qpzry9x8gf2tvdw0s3jn54khce6mua7lcw20ayyn",
"bchtest:testnetaddress4d6njnut",
"bchreg:555555555555555555555555555555555555555555555udxmlmrz",
};
struct valid_cashaddr_data {
const char* legacy;
const char* cashaddress;
const char* legacy;
const char* cashaddress;
};
static struct valid_cashaddr_data valid_cashaddr[] = {
{
"1BpEi6DfDAUFd7GtittLSdBeYJvcoaVggu",
"bitcoincash:qpm2qsznhks23z7629mms6s4cwef74vcwvy22gdx6a"
},
{
"1KXrWXciRDZUpQwQmuM1DbwsKDLYAYsVLR",
"bitcoincash:qr95sy3j9xwd2ap32xkykttr4cvcu7as4y0qverfuy"
},
{
"16w1D5WRVKJuZUsSRzdLp9w3YGcgoxDXb",
"bitcoincash:qqq3728yw0y47sqn6l2na30mcw6zm78dzqre909m2r"
},
{
"3CWFddi6m4ndiGyKqzYvsFYagqDLPVMTzC",
"bitcoincash:ppm2qsznhks23z7629mms6s4cwef74vcwvn0h829pq"
},
{
"3LDsS579y7sruadqu11beEJoTjdFiFCdX4",
"bitcoincash:pr95sy3j9xwd2ap32xkykttr4cvcu7as4yc93ky28e"
},
{
"31nwvkZwyPdgzjBJZXfDmSWsC4ZLKpYyUw",
"bitcoincash:pqq3728yw0y47sqn6l2na30mcw6zm78dzq5ucqzc37"
}
};
{"1BpEi6DfDAUFd7GtittLSdBeYJvcoaVggu",
"bitcoincash:qpm2qsznhks23z7629mms6s4cwef74vcwvy22gdx6a"},
{"1KXrWXciRDZUpQwQmuM1DbwsKDLYAYsVLR",
"bitcoincash:qr95sy3j9xwd2ap32xkykttr4cvcu7as4y0qverfuy"},
{"16w1D5WRVKJuZUsSRzdLp9w3YGcgoxDXb",
"bitcoincash:qqq3728yw0y47sqn6l2na30mcw6zm78dzqre909m2r"},
{"3CWFddi6m4ndiGyKqzYvsFYagqDLPVMTzC",
"bitcoincash:ppm2qsznhks23z7629mms6s4cwef74vcwvn0h829pq"},
{"3LDsS579y7sruadqu11beEJoTjdFiFCdX4",
"bitcoincash:pr95sy3j9xwd2ap32xkykttr4cvcu7as4yc93ky28e"},
{"31nwvkZwyPdgzjBJZXfDmSWsC4ZLKpYyUw",
"bitcoincash:pqq3728yw0y47sqn6l2na30mcw6zm78dzq5ucqzc37"}};
START_TEST(test_cashaddr)
{
size_t i;
for (i = 0; i < sizeof(valid_cashchecksum) / sizeof(valid_cashchecksum[0]); ++i) {
uint8_t data[82];
char rebuild[92];
char hrp[84];
size_t data_len;
int res = cash_decode(hrp, data, &data_len, valid_cashchecksum[i]);
ck_assert_int_eq(res, 1);
res = cash_encode(rebuild, hrp, data, data_len);
ck_assert_int_eq(res, 1);
ck_assert_int_eq(my_strncasecmp(rebuild, valid_cashchecksum[i], 92), 0);
}
for (i = 0; i < sizeof(valid_cashaddr) / sizeof(valid_cashaddr[0]); ++i) {
uint8_t prog[65];
size_t prog_len;
const char* hrp = "bitcoincash";
uint8_t rawdata[65];
size_t rawdata_len;
char rebuild[93];
int ret = cash_addr_decode(prog, &prog_len, hrp, valid_cashaddr[i].cashaddress);
ck_assert_int_eq(ret, 1);
ck_assert_int_eq(prog_len, 21);
rawdata_len = base58_decode_check(valid_cashaddr[i].legacy, HASHER_SHA2D, rawdata, sizeof(rawdata));
ck_assert_int_eq(rawdata_len, 21);
ck_assert_int_eq(prog[0], rawdata[0] == 0 ? 0x00 : rawdata[0] == 5 ? 0x08 : -1);
ck_assert_int_eq(memcmp(rawdata + 1, prog + 1, 20), 0);
ret = cash_addr_encode(rebuild, hrp, prog, 21);
ck_assert_int_eq(ret, 1);
ck_assert_int_eq(my_strncasecmp(rebuild, valid_cashaddr[i].cashaddress, 92), 0);
}
START_TEST(test_cashaddr) {
size_t i;
for (i = 0; i < sizeof(valid_cashchecksum) / sizeof(valid_cashchecksum[0]);
++i) {
uint8_t data[82];
char rebuild[92];
char hrp[84];
size_t data_len;
int res = cash_decode(hrp, data, &data_len, valid_cashchecksum[i]);
ck_assert_int_eq(res, 1);
res = cash_encode(rebuild, hrp, data, data_len);
ck_assert_int_eq(res, 1);
ck_assert_int_eq(my_strncasecmp(rebuild, valid_cashchecksum[i], 92), 0);
}
for (i = 0; i < sizeof(valid_cashaddr) / sizeof(valid_cashaddr[0]); ++i) {
uint8_t prog[65];
size_t prog_len;
const char* hrp = "bitcoincash";
uint8_t rawdata[65];
size_t rawdata_len;
char rebuild[93];
int ret =
cash_addr_decode(prog, &prog_len, hrp, valid_cashaddr[i].cashaddress);
ck_assert_int_eq(ret, 1);
ck_assert_int_eq(prog_len, 21);
rawdata_len = base58_decode_check(valid_cashaddr[i].legacy, HASHER_SHA2D,
rawdata, sizeof(rawdata));
ck_assert_int_eq(rawdata_len, 21);
ck_assert_int_eq(prog[0],
rawdata[0] == 0 ? 0x00 : rawdata[0] == 5 ? 0x08 : -1);
ck_assert_int_eq(memcmp(rawdata + 1, prog + 1, 20), 0);
ret = cash_addr_encode(rebuild, hrp, prog, 21);
ck_assert_int_eq(ret, 1);
ck_assert_int_eq(my_strncasecmp(rebuild, valid_cashaddr[i].cashaddress, 92),
0);
}
}
END_TEST

File diff suppressed because it is too large Load Diff

@ -1,184 +1,160 @@
#include "segwit_addr.h"
static const char* valid_checksum[] = {
"A12UEL5L",
"an83characterlonghumanreadablepartthatcontainsthenumber1andtheexcludedcharactersbio1tt5tgs",
"abcdef1qpzry9x8gf2tvdw0s3jn54khce6mua7lmqqqxw",
"11qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqc8247j",
"split1checkupstagehandshakeupstreamerranterredcaperred2y9e3w",
"A12UEL5L",
"an83characterlonghumanreadablepartthatcontainsthenumber1andtheexcludedchar"
"actersbio1tt5tgs",
"abcdef1qpzry9x8gf2tvdw0s3jn54khce6mua7lmqqqxw",
"11qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq"
"qqqqqqqqqqc8247j",
"split1checkupstagehandshakeupstreamerranterredcaperred2y9e3w",
};
static const char* invalid_checksum[] = {
" 1nwldj5",
"\x7f""1axkwrx",
"an84characterslonghumanreadablepartthatcontainsthenumber1andtheexcludedcharactersbio1569pvx",
"pzry9x0s0muk",
"1pzry9x0s0muk",
"x1b4n0q5v",
"li1dgmt3",
"de1lg7wt\xff",
" 1nwldj5",
"\x7f"
"1axkwrx",
"an84characterslonghumanreadablepartthatcontainsthenumber1andtheexcludedcha"
"ractersbio1569pvx",
"pzry9x0s0muk",
"1pzry9x0s0muk",
"x1b4n0q5v",
"li1dgmt3",
"de1lg7wt\xff",
};
struct valid_address_data {
const char* address;
size_t scriptPubKeyLen;
const uint8_t scriptPubKey[42];
const char* address;
size_t scriptPubKeyLen;
const uint8_t scriptPubKey[42];
};
struct invalid_address_data {
const char* hrp;
int version;
size_t program_length;
const char* hrp;
int version;
size_t program_length;
};
static struct valid_address_data valid_address[] = {
{
"BC1QW508D6QEJXTDG4Y5R3ZARVARY0C5XW7KV8F3T4",
22, {
0x00, 0x14, 0x75, 0x1e, 0x76, 0xe8, 0x19, 0x91, 0x96, 0xd4, 0x54,
0x94, 0x1c, 0x45, 0xd1, 0xb3, 0xa3, 0x23, 0xf1, 0x43, 0x3b, 0xd6
}
},
{
"tb1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3q0sl5k7",
34, {
0x00, 0x20, 0x18, 0x63, 0x14, 0x3c, 0x14, 0xc5, 0x16, 0x68, 0x04,
0xbd, 0x19, 0x20, 0x33, 0x56, 0xda, 0x13, 0x6c, 0x98, 0x56, 0x78,
0xcd, 0x4d, 0x27, 0xa1, 0xb8, 0xc6, 0x32, 0x96, 0x04, 0x90, 0x32,
0x62
}
},
{
"bc1pw508d6qejxtdg4y5r3zarvary0c5xw7kw508d6qejxtdg4y5r3zarvary0c5xw7k7grplx",
42, {
0x51, 0x28, 0x75, 0x1e, 0x76, 0xe8, 0x19, 0x91, 0x96, 0xd4, 0x54,
0x94, 0x1c, 0x45, 0xd1, 0xb3, 0xa3, 0x23, 0xf1, 0x43, 0x3b, 0xd6,
0x75, 0x1e, 0x76, 0xe8, 0x19, 0x91, 0x96, 0xd4, 0x54, 0x94, 0x1c,
0x45, 0xd1, 0xb3, 0xa3, 0x23, 0xf1, 0x43, 0x3b, 0xd6
}
},
{
"BC1SW50QA3JX3S",
4, {
0x60, 0x02, 0x75, 0x1e
}
},
{
"bc1zw508d6qejxtdg4y5r3zarvaryvg6kdaj",
18, {
0x52, 0x10, 0x75, 0x1e, 0x76, 0xe8, 0x19, 0x91, 0x96, 0xd4, 0x54,
0x94, 0x1c, 0x45, 0xd1, 0xb3, 0xa3, 0x23
}
},
{
"tb1qqqqqp399et2xygdj5xreqhjjvcmzhxw4aywxecjdzew6hylgvsesrxh6hy",
34, {
0x00, 0x20, 0x00, 0x00, 0x00, 0xc4, 0xa5, 0xca, 0xd4, 0x62, 0x21,
0xb2, 0xa1, 0x87, 0x90, 0x5e, 0x52, 0x66, 0x36, 0x2b, 0x99, 0xd5,
0xe9, 0x1c, 0x6c, 0xe2, 0x4d, 0x16, 0x5d, 0xab, 0x93, 0xe8, 0x64,
0x33
}
}
};
{"BC1QW508D6QEJXTDG4Y5R3ZARVARY0C5XW7KV8F3T4",
22,
{0x00, 0x14, 0x75, 0x1e, 0x76, 0xe8, 0x19, 0x91, 0x96, 0xd4, 0x54,
0x94, 0x1c, 0x45, 0xd1, 0xb3, 0xa3, 0x23, 0xf1, 0x43, 0x3b, 0xd6}},
{"tb1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3q0sl5k7",
34,
{0x00, 0x20, 0x18, 0x63, 0x14, 0x3c, 0x14, 0xc5, 0x16, 0x68, 0x04, 0xbd,
0x19, 0x20, 0x33, 0x56, 0xda, 0x13, 0x6c, 0x98, 0x56, 0x78, 0xcd, 0x4d,
0x27, 0xa1, 0xb8, 0xc6, 0x32, 0x96, 0x04, 0x90, 0x32, 0x62}},
{"bc1pw508d6qejxtdg4y5r3zarvary0c5xw7kw508d6qejxtdg4y5r3zarvary0c5xw7k7grpl"
"x",
42,
{0x51, 0x28, 0x75, 0x1e, 0x76, 0xe8, 0x19, 0x91, 0x96, 0xd4, 0x54,
0x94, 0x1c, 0x45, 0xd1, 0xb3, 0xa3, 0x23, 0xf1, 0x43, 0x3b, 0xd6,
0x75, 0x1e, 0x76, 0xe8, 0x19, 0x91, 0x96, 0xd4, 0x54, 0x94, 0x1c,
0x45, 0xd1, 0xb3, 0xa3, 0x23, 0xf1, 0x43, 0x3b, 0xd6}},
{"BC1SW50QA3JX3S", 4, {0x60, 0x02, 0x75, 0x1e}},
{"bc1zw508d6qejxtdg4y5r3zarvaryvg6kdaj",
18,
{0x52, 0x10, 0x75, 0x1e, 0x76, 0xe8, 0x19, 0x91, 0x96, 0xd4, 0x54, 0x94,
0x1c, 0x45, 0xd1, 0xb3, 0xa3, 0x23}},
{"tb1qqqqqp399et2xygdj5xreqhjjvcmzhxw4aywxecjdzew6hylgvsesrxh6hy",
34,
{0x00, 0x20, 0x00, 0x00, 0x00, 0xc4, 0xa5, 0xca, 0xd4, 0x62, 0x21, 0xb2,
0xa1, 0x87, 0x90, 0x5e, 0x52, 0x66, 0x36, 0x2b, 0x99, 0xd5, 0xe9, 0x1c,
0x6c, 0xe2, 0x4d, 0x16, 0x5d, 0xab, 0x93, 0xe8, 0x64, 0x33}}};
static const char* invalid_address[] = {
"tc1qw508d6qejxtdg4y5r3zarvary0c5xw7kg3g4ty",
"bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t5",
"BC13W508D6QEJXTDG4Y5R3ZARVARY0C5XW7KN40WF2",
"bc1rw5uspcuh",
"bc10w508d6qejxtdg4y5r3zarvary0c5xw7kw508d6qejxtdg4y5r3zarvary0c5xw7kw5rljs90",
"BC1QR508D6QEJXTDG4Y5R3ZARVARYV98GJ9P",
"tb1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3q0sL5k7",
"bc1zw508d6qejxtdg4y5r3zarvaryvqyzf3du",
"tb1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3pjxtptv",
"bc1gmk9yu",
"tc1qw508d6qejxtdg4y5r3zarvary0c5xw7kg3g4ty",
"bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t5",
"BC13W508D6QEJXTDG4Y5R3ZARVARY0C5XW7KN40WF2",
"bc1rw5uspcuh",
"bc10w508d6qejxtdg4y5r3zarvary0c5xw7kw508d6qejxtdg4y5r3zarvary0c5xw7kw5rljs"
"90",
"BC1QR508D6QEJXTDG4Y5R3ZARVARYV98GJ9P",
"tb1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3q0sL5k7",
"bc1zw508d6qejxtdg4y5r3zarvaryvqyzf3du",
"tb1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3pjxtptv",
"bc1gmk9yu",
};
static struct invalid_address_data invalid_address_enc[] = {
{"BC", 0, 20},
{"bc", 0, 21},
{"bc", 17, 32},
{"bc", 1, 1},
{"bc", 16, 41},
{"BC", 0, 20}, {"bc", 0, 21}, {"bc", 17, 32}, {"bc", 1, 1}, {"bc", 16, 41},
};
static void segwit_scriptpubkey(uint8_t* scriptpubkey, size_t* scriptpubkeylen, int witver, const uint8_t* witprog, size_t witprog_len) {
scriptpubkey[0] = witver ? (0x50 + witver) : 0;
scriptpubkey[1] = witprog_len;
memcpy(scriptpubkey + 2, witprog, witprog_len);
*scriptpubkeylen = witprog_len + 2;
}
int my_strncasecmp(const char *s1, const char *s2, size_t n) {
size_t i = 0;
while (i < n) {
char c1 = s1[i];
char c2 = s2[i];
if (c1 >= 'A' && c1 <= 'Z') c1 = (c1 - 'A') + 'a';
if (c2 >= 'A' && c2 <= 'Z') c2 = (c2 - 'A') + 'a';
if (c1 < c2) return -1;
if (c1 > c2) return 1;
if (c1 == 0) return 0;
++i;
}
return 0;
static void segwit_scriptpubkey(uint8_t* scriptpubkey, size_t* scriptpubkeylen,
int witver, const uint8_t* witprog,
size_t witprog_len) {
scriptpubkey[0] = witver ? (0x50 + witver) : 0;
scriptpubkey[1] = witprog_len;
memcpy(scriptpubkey + 2, witprog, witprog_len);
*scriptpubkeylen = witprog_len + 2;
}
START_TEST(test_segwit)
{
size_t i;
for (i = 0; i < sizeof(valid_checksum) / sizeof(valid_checksum[0]); ++i) {
uint8_t data[82];
char rebuild[92];
char hrp[84];
size_t data_len;
int res = bech32_decode(hrp, data, &data_len, valid_checksum[i]);
ck_assert_int_eq(res, 1);
res = bech32_encode(rebuild, hrp, data, data_len);
ck_assert_int_eq(res, 1);
ck_assert_int_eq(my_strncasecmp(rebuild, valid_checksum[i], 92), 0);
}
for (i = 0; i < sizeof(invalid_checksum) / sizeof(invalid_checksum[0]); ++i) {
uint8_t data[82];
char hrp[84];
size_t data_len;
int res = bech32_decode(hrp, data, &data_len, invalid_checksum[i]);
ck_assert_int_eq(res, 0);
}
for (i = 0; i < sizeof(valid_address) / sizeof(valid_address[0]); ++i) {
uint8_t witprog[40];
size_t witprog_len;
int witver;
const char* hrp = "bc";
uint8_t scriptpubkey[42];
size_t scriptpubkey_len;
char rebuild[93];
int ret = segwit_addr_decode(&witver, witprog, &witprog_len, hrp, valid_address[i].address);
if (!ret) {
hrp = "tb";
ret = segwit_addr_decode(&witver, witprog, &witprog_len, hrp, valid_address[i].address);
}
ck_assert_int_eq(ret, 1);
segwit_scriptpubkey(scriptpubkey, &scriptpubkey_len, witver, witprog, witprog_len);
ck_assert_int_eq(scriptpubkey_len, valid_address[i].scriptPubKeyLen);
ck_assert_int_eq(memcmp(scriptpubkey, valid_address[i].scriptPubKey, scriptpubkey_len), 0);
ck_assert_int_eq(segwit_addr_encode(rebuild, hrp, witver, witprog, witprog_len), 1);
ck_assert_int_eq(my_strncasecmp(valid_address[i].address, rebuild, 93), 0);
}
for (i = 0; i < sizeof(invalid_address) / sizeof(invalid_address[0]); ++i) {
uint8_t witprog[40];
size_t witprog_len;
int witver;
int ret = segwit_addr_decode(&witver, witprog, &witprog_len, "bc", invalid_address[i]);
ck_assert_int_eq(ret, 0);
ret = segwit_addr_decode(&witver, witprog, &witprog_len, "tb", invalid_address[i]);
ck_assert_int_eq(ret, 0);
}
for (i = 0; i < sizeof(invalid_address_enc) / sizeof(invalid_address_enc[0]); ++i) {
char rebuild[93];
static const uint8_t program[42] = {0};
int ret = segwit_addr_encode(rebuild, invalid_address_enc[i].hrp, invalid_address_enc[i].version, program, invalid_address_enc[i].program_length);
ck_assert_int_eq(ret, 0);
}
START_TEST(test_segwit) {
size_t i;
for (i = 0; i < sizeof(valid_checksum) / sizeof(valid_checksum[0]); ++i) {
uint8_t data[82];
char rebuild[92];
char hrp[84];
size_t data_len;
int res = bech32_decode(hrp, data, &data_len, valid_checksum[i]);
ck_assert_int_eq(res, 1);
res = bech32_encode(rebuild, hrp, data, data_len);
ck_assert_int_eq(res, 1);
ck_assert_int_eq(my_strncasecmp(rebuild, valid_checksum[i], 92), 0);
}
for (i = 0; i < sizeof(invalid_checksum) / sizeof(invalid_checksum[0]); ++i) {
uint8_t data[82];
char hrp[84];
size_t data_len;
int res = bech32_decode(hrp, data, &data_len, invalid_checksum[i]);
ck_assert_int_eq(res, 0);
}
for (i = 0; i < sizeof(valid_address) / sizeof(valid_address[0]); ++i) {
uint8_t witprog[40];
size_t witprog_len;
int witver;
const char* hrp = "bc";
uint8_t scriptpubkey[42];
size_t scriptpubkey_len;
char rebuild[93];
int ret = segwit_addr_decode(&witver, witprog, &witprog_len, hrp,
valid_address[i].address);
if (!ret) {
hrp = "tb";
ret = segwit_addr_decode(&witver, witprog, &witprog_len, hrp,
valid_address[i].address);
}
ck_assert_int_eq(ret, 1);
segwit_scriptpubkey(scriptpubkey, &scriptpubkey_len, witver, witprog,
witprog_len);
ck_assert_int_eq(scriptpubkey_len, valid_address[i].scriptPubKeyLen);
ck_assert_int_eq(
memcmp(scriptpubkey, valid_address[i].scriptPubKey, scriptpubkey_len),
0);
ck_assert_int_eq(
segwit_addr_encode(rebuild, hrp, witver, witprog, witprog_len), 1);
ck_assert_int_eq(my_strncasecmp(valid_address[i].address, rebuild, 93), 0);
}
for (i = 0; i < sizeof(invalid_address) / sizeof(invalid_address[0]); ++i) {
uint8_t witprog[40];
size_t witprog_len;
int witver;
int ret = segwit_addr_decode(&witver, witprog, &witprog_len, "bc",
invalid_address[i]);
ck_assert_int_eq(ret, 0);
ret = segwit_addr_decode(&witver, witprog, &witprog_len, "tb",
invalid_address[i]);
ck_assert_int_eq(ret, 0);
}
for (i = 0; i < sizeof(invalid_address_enc) / sizeof(invalid_address_enc[0]);
++i) {
char rebuild[93];
static const uint8_t program[42] = {0};
int ret = segwit_addr_encode(rebuild, invalid_address_enc[i].hrp,
invalid_address_enc[i].version, program,
invalid_address_enc[i].program_length);
ck_assert_int_eq(ret, 0);
}
}
END_TEST

@ -27,118 +27,117 @@
#include <openssl/bn.h>
#include <openssl/ecdsa.h>
#include <openssl/obj_mac.h>
#include <openssl/sha.h>
#include <openssl/opensslv.h>
#include <openssl/sha.h>
#undef SHA256_CTX
#undef SHA512_CTX
#include <stdio.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include "ecdsa.h"
#include "rand.h"
#include "hasher.h"
#include "rand.h"
#include "nist256p1.h"
#include "secp256k1.h"
#include "memzero.h"
void openssl_check(unsigned int iterations, int nid, const ecdsa_curve *curve)
{
uint8_t sig[64], pub_key33[33], pub_key65[65], priv_key[32], msg[256], hash[32];
struct SHA256state_st sha256;
EC_GROUP *ecgroup;
ecgroup = EC_GROUP_new_by_curve_name(nid);
for (unsigned int iter = 0; iter < iterations; iter++) {
// random message len between 1 and 256
int msg_len = (random32() & 0xFF) + 1;
// create random message
random_buffer(msg, msg_len);
// new ECDSA key
EC_KEY *eckey = EC_KEY_new();
EC_KEY_set_group(eckey, ecgroup);
// generate the key
EC_KEY_generate_key(eckey);
// copy key to buffer
const BIGNUM *K = EC_KEY_get0_private_key(eckey);
int bn_off = sizeof(priv_key) - BN_num_bytes(K);
memzero(priv_key, bn_off);
BN_bn2bin(K, priv_key + bn_off);
// use our ECDSA signer to sign the message with the key
if (ecdsa_sign(curve, HASHER_SHA2, priv_key, msg, msg_len, sig, NULL, NULL) != 0) {
printf("trezor-crypto signing failed\n");
return;
}
// generate public key from private key
ecdsa_get_public_key33(curve, priv_key, pub_key33);
ecdsa_get_public_key65(curve, priv_key, pub_key65);
// use our ECDSA verifier to verify the message signature
if (ecdsa_verify(curve, HASHER_SHA2, pub_key65, sig, msg, msg_len) != 0) {
printf("trezor-crypto verification failed (pub_key_len = 65)\n");
return;
}
if (ecdsa_verify(curve, HASHER_SHA2, pub_key33, sig, msg, msg_len) != 0) {
printf("trezor-crypto verification failed (pub_key_len = 33)\n");
return;
}
// copy signature to the OpenSSL struct
ECDSA_SIG *signature = ECDSA_SIG_new();
#if OPENSSL_VERSION_NUMBER < 0x10100000L
BN_bin2bn(sig, 32, signature->r);
BN_bin2bn(sig + 32, 32, signature->s);
void openssl_check(unsigned int iterations, int nid, const ecdsa_curve *curve) {
uint8_t sig[64], pub_key33[33], pub_key65[65], priv_key[32], msg[256],
hash[32];
struct SHA256state_st sha256;
EC_GROUP *ecgroup;
ecgroup = EC_GROUP_new_by_curve_name(nid);
for (unsigned int iter = 0; iter < iterations; iter++) {
// random message len between 1 and 256
int msg_len = (random32() & 0xFF) + 1;
// create random message
random_buffer(msg, msg_len);
// new ECDSA key
EC_KEY *eckey = EC_KEY_new();
EC_KEY_set_group(eckey, ecgroup);
// generate the key
EC_KEY_generate_key(eckey);
// copy key to buffer
const BIGNUM *K = EC_KEY_get0_private_key(eckey);
int bn_off = sizeof(priv_key) - BN_num_bytes(K);
memzero(priv_key, bn_off);
BN_bn2bin(K, priv_key + bn_off);
// use our ECDSA signer to sign the message with the key
if (ecdsa_sign(curve, HASHER_SHA2, priv_key, msg, msg_len, sig, NULL,
NULL) != 0) {
printf("trezor-crypto signing failed\n");
return;
}
// generate public key from private key
ecdsa_get_public_key33(curve, priv_key, pub_key33);
ecdsa_get_public_key65(curve, priv_key, pub_key65);
// use our ECDSA verifier to verify the message signature
if (ecdsa_verify(curve, HASHER_SHA2, pub_key65, sig, msg, msg_len) != 0) {
printf("trezor-crypto verification failed (pub_key_len = 65)\n");
return;
}
if (ecdsa_verify(curve, HASHER_SHA2, pub_key33, sig, msg, msg_len) != 0) {
printf("trezor-crypto verification failed (pub_key_len = 33)\n");
return;
}
// copy signature to the OpenSSL struct
ECDSA_SIG *signature = ECDSA_SIG_new();
#if OPENSSL_VERSION_NUMBER < 0x10100000L
BN_bin2bn(sig, 32, signature->r);
BN_bin2bn(sig + 32, 32, signature->s);
#else
BIGNUM *R = BN_bin2bn(sig, 32, NULL);
BIGNUM *S = BN_bin2bn(sig + 32, 32, NULL);
ECDSA_SIG_set0(signature, R, S);
BIGNUM *R = BN_bin2bn(sig, 32, NULL);
BIGNUM *S = BN_bin2bn(sig + 32, 32, NULL);
ECDSA_SIG_set0(signature, R, S);
#endif
// compute the digest of the message
// note: these are OpenSSL functions, not our own
SHA256_Init(&sha256);
SHA256_Update(&sha256, msg, msg_len);
SHA256_Final(hash, &sha256);
// verify all went well, i.e. we can decrypt our signature with OpenSSL
int v = ECDSA_do_verify(hash, 32, signature, eckey);
if (v != 1) {
printf("OpenSSL verification failed (%d)\n", v);
return;
}
ECDSA_SIG_free(signature);
EC_KEY_free(eckey);
if (((iter + 1) % 100) == 0) printf("Passed ... %d\n", iter + 1);
}
EC_GROUP_free(ecgroup);
printf("All OK\n");
// compute the digest of the message
// note: these are OpenSSL functions, not our own
SHA256_Init(&sha256);
SHA256_Update(&sha256, msg, msg_len);
SHA256_Final(hash, &sha256);
// verify all went well, i.e. we can decrypt our signature with OpenSSL
int v = ECDSA_do_verify(hash, 32, signature, eckey);
if (v != 1) {
printf("OpenSSL verification failed (%d)\n", v);
return;
}
ECDSA_SIG_free(signature);
EC_KEY_free(eckey);
if (((iter + 1) % 100) == 0) printf("Passed ... %d\n", iter + 1);
}
EC_GROUP_free(ecgroup);
printf("All OK\n");
}
int main(int argc, char *argv[])
{
if (argc != 2) {
printf("Usage: test_openssl iterations\n");
return 1;
}
int main(int argc, char *argv[]) {
if (argc != 2) {
printf("Usage: test_openssl iterations\n");
return 1;
}
unsigned int iterations;
sscanf(argv[1], "%u", &iterations);
unsigned int iterations;
sscanf(argv[1], "%u", &iterations);
printf("Testing secp256k1:\n");
openssl_check(iterations, NID_secp256k1, &secp256k1);
printf("Testing secp256k1:\n");
openssl_check(iterations, NID_secp256k1, &secp256k1);
printf("Testing nist256p1:\n");
openssl_check(iterations, NID_X9_62_prime256v1, &nist256p1);
printf("Testing nist256p1:\n");
openssl_check(iterations, NID_X9_62_prime256v1, &nist256p1);
return 0;
return 0;
}

@ -1,215 +1,233 @@
#include <stdio.h>
#include <assert.h>
#include <time.h>
#include <string.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <time.h>
#include "bip32.h"
#include "curves.h"
#include "ecdsa.h"
#include "bip32.h"
#include "secp256k1.h"
#include "nist256p1.h"
#include "ed25519-donna/ed25519.h"
#include "hasher.h"
#include "nist256p1.h"
#include "secp256k1.h"
static uint8_t msg[256];
void prepare_msg(void)
{
for (size_t i = 0; i < sizeof(msg); i++) {
msg[i] = i * 1103515245;
}
void prepare_msg(void) {
for (size_t i = 0; i < sizeof(msg); i++) {
msg[i] = i * 1103515245;
}
}
void bench_sign_secp256k1(int iterations)
{
uint8_t sig[64], priv[32], pby;
void bench_sign_secp256k1(int iterations) {
uint8_t sig[64], priv[32], pby;
const ecdsa_curve *curve = &secp256k1;
const ecdsa_curve *curve = &secp256k1;
memcpy(priv, "\xc5\x5e\xce\x85\x8b\x0d\xdd\x52\x63\xf9\x68\x10\xfe\x14\x43\x7c\xd3\xb5\xe1\xfb\xd7\xc6\xa2\xec\x1e\x03\x1f\x05\xe8\x6d\x8b\xd5", 32);
memcpy(priv,
"\xc5\x5e\xce\x85\x8b\x0d\xdd\x52\x63\xf9\x68\x10\xfe\x14\x43\x7c\xd3"
"\xb5\xe1\xfb\xd7\xc6\xa2\xec\x1e\x03\x1f\x05\xe8\x6d\x8b\xd5",
32);
for (int i = 0 ; i < iterations; i++) {
ecdsa_sign(curve, HASHER_SHA2, priv, msg, sizeof(msg), sig, &pby, NULL);
}
for (int i = 0; i < iterations; i++) {
ecdsa_sign(curve, HASHER_SHA2, priv, msg, sizeof(msg), sig, &pby, NULL);
}
}
void bench_sign_nist256p1(int iterations)
{
uint8_t sig[64], priv[32], pby;
void bench_sign_nist256p1(int iterations) {
uint8_t sig[64], priv[32], pby;
const ecdsa_curve *curve = &nist256p1;
const ecdsa_curve *curve = &nist256p1;
memcpy(priv, "\xc5\x5e\xce\x85\x8b\x0d\xdd\x52\x63\xf9\x68\x10\xfe\x14\x43\x7c\xd3\xb5\xe1\xfb\xd7\xc6\xa2\xec\x1e\x03\x1f\x05\xe8\x6d\x8b\xd5", 32);
memcpy(priv,
"\xc5\x5e\xce\x85\x8b\x0d\xdd\x52\x63\xf9\x68\x10\xfe\x14\x43\x7c\xd3"
"\xb5\xe1\xfb\xd7\xc6\xa2\xec\x1e\x03\x1f\x05\xe8\x6d\x8b\xd5",
32);
for (int i = 0 ; i < iterations; i++) {
ecdsa_sign(curve, HASHER_SHA2, priv, msg, sizeof(msg), sig, &pby, NULL);
}
for (int i = 0; i < iterations; i++) {
ecdsa_sign(curve, HASHER_SHA2, priv, msg, sizeof(msg), sig, &pby, NULL);
}
}
void bench_sign_ed25519(int iterations)
{
ed25519_public_key pk;
ed25519_secret_key sk;
ed25519_signature sig;
void bench_sign_ed25519(int iterations) {
ed25519_public_key pk;
ed25519_secret_key sk;
ed25519_signature sig;
memcpy(pk, "\xc5\x5e\xce\x85\x8b\x0d\xdd\x52\x63\xf9\x68\x10\xfe\x14\x43\x7c\xd3\xb5\xe1\xfb\xd7\xc6\xa2\xec\x1e\x03\x1f\x05\xe8\x6d\x8b\xd5", 32);
ed25519_publickey(sk, pk);
memcpy(pk,
"\xc5\x5e\xce\x85\x8b\x0d\xdd\x52\x63\xf9\x68\x10\xfe\x14\x43\x7c\xd3"
"\xb5\xe1\xfb\xd7\xc6\xa2\xec\x1e\x03\x1f\x05\xe8\x6d\x8b\xd5",
32);
ed25519_publickey(sk, pk);
for (int i = 0 ; i < iterations; i++) {
ed25519_sign(msg, sizeof(msg), sk, pk, sig);
}
for (int i = 0; i < iterations; i++) {
ed25519_sign(msg, sizeof(msg), sk, pk, sig);
}
}
void bench_verify_secp256k1_33(int iterations)
{
uint8_t sig[64], pub[33], priv[32], pby;
void bench_verify_secp256k1_33(int iterations) {
uint8_t sig[64], pub[33], priv[32], pby;
const ecdsa_curve *curve = &secp256k1;
const ecdsa_curve *curve = &secp256k1;
memcpy(priv, "\xc5\x5e\xce\x85\x8b\x0d\xdd\x52\x63\xf9\x68\x10\xfe\x14\x43\x7c\xd3\xb5\xe1\xfb\xd7\xc6\xa2\xec\x1e\x03\x1f\x05\xe8\x6d\x8b\xd5", 32);
ecdsa_get_public_key33(curve, priv, pub);
ecdsa_sign(curve, HASHER_SHA2, priv, msg, sizeof(msg), sig, &pby, NULL);
memcpy(priv,
"\xc5\x5e\xce\x85\x8b\x0d\xdd\x52\x63\xf9\x68\x10\xfe\x14\x43\x7c\xd3"
"\xb5\xe1\xfb\xd7\xc6\xa2\xec\x1e\x03\x1f\x05\xe8\x6d\x8b\xd5",
32);
ecdsa_get_public_key33(curve, priv, pub);
ecdsa_sign(curve, HASHER_SHA2, priv, msg, sizeof(msg), sig, &pby, NULL);
for (int i = 0 ; i < iterations; i++) {
ecdsa_verify(curve, HASHER_SHA2, pub, sig, msg, sizeof(msg));
}
for (int i = 0; i < iterations; i++) {
ecdsa_verify(curve, HASHER_SHA2, pub, sig, msg, sizeof(msg));
}
}
void bench_verify_secp256k1_65(int iterations)
{
uint8_t sig[64], pub[65], priv[32], pby;
void bench_verify_secp256k1_65(int iterations) {
uint8_t sig[64], pub[65], priv[32], pby;
const ecdsa_curve *curve = &secp256k1;
const ecdsa_curve *curve = &secp256k1;
memcpy(priv, "\xc5\x5e\xce\x85\x8b\x0d\xdd\x52\x63\xf9\x68\x10\xfe\x14\x43\x7c\xd3\xb5\xe1\xfb\xd7\xc6\xa2\xec\x1e\x03\x1f\x05\xe8\x6d\x8b\xd5", 32);
ecdsa_get_public_key65(curve, priv, pub);
ecdsa_sign(curve, HASHER_SHA2, priv, msg, sizeof(msg), sig, &pby, NULL);
memcpy(priv,
"\xc5\x5e\xce\x85\x8b\x0d\xdd\x52\x63\xf9\x68\x10\xfe\x14\x43\x7c\xd3"
"\xb5\xe1\xfb\xd7\xc6\xa2\xec\x1e\x03\x1f\x05\xe8\x6d\x8b\xd5",
32);
ecdsa_get_public_key65(curve, priv, pub);
ecdsa_sign(curve, HASHER_SHA2, priv, msg, sizeof(msg), sig, &pby, NULL);
for (int i = 0 ; i < iterations; i++) {
ecdsa_verify(curve, HASHER_SHA2, pub, sig, msg, sizeof(msg));
}
for (int i = 0; i < iterations; i++) {
ecdsa_verify(curve, HASHER_SHA2, pub, sig, msg, sizeof(msg));
}
}
void bench_verify_nist256p1_33(int iterations)
{
uint8_t sig[64], pub[33], priv[32], pby;
void bench_verify_nist256p1_33(int iterations) {
uint8_t sig[64], pub[33], priv[32], pby;
const ecdsa_curve *curve = &nist256p1;
const ecdsa_curve *curve = &nist256p1;
memcpy(priv, "\xc5\x5e\xce\x85\x8b\x0d\xdd\x52\x63\xf9\x68\x10\xfe\x14\x43\x7c\xd3\xb5\xe1\xfb\xd7\xc6\xa2\xec\x1e\x03\x1f\x05\xe8\x6d\x8b\xd5", 32);
ecdsa_get_public_key33(curve, priv, pub);
ecdsa_sign(curve, HASHER_SHA2, priv, msg, sizeof(msg), sig, &pby, NULL);
memcpy(priv,
"\xc5\x5e\xce\x85\x8b\x0d\xdd\x52\x63\xf9\x68\x10\xfe\x14\x43\x7c\xd3"
"\xb5\xe1\xfb\xd7\xc6\xa2\xec\x1e\x03\x1f\x05\xe8\x6d\x8b\xd5",
32);
ecdsa_get_public_key33(curve, priv, pub);
ecdsa_sign(curve, HASHER_SHA2, priv, msg, sizeof(msg), sig, &pby, NULL);
for (int i = 0 ; i < iterations; i++) {
ecdsa_verify(curve, HASHER_SHA2, pub, sig, msg, sizeof(msg));
}
for (int i = 0; i < iterations; i++) {
ecdsa_verify(curve, HASHER_SHA2, pub, sig, msg, sizeof(msg));
}
}
void bench_verify_nist256p1_65(int iterations)
{
uint8_t sig[64], pub[65], priv[32], pby;
void bench_verify_nist256p1_65(int iterations) {
uint8_t sig[64], pub[65], priv[32], pby;
const ecdsa_curve *curve = &nist256p1;
const ecdsa_curve *curve = &nist256p1;
memcpy(priv, "\xc5\x5e\xce\x85\x8b\x0d\xdd\x52\x63\xf9\x68\x10\xfe\x14\x43\x7c\xd3\xb5\xe1\xfb\xd7\xc6\xa2\xec\x1e\x03\x1f\x05\xe8\x6d\x8b\xd5", 32);
ecdsa_get_public_key65(curve, priv, pub);
ecdsa_sign(curve, HASHER_SHA2, priv, msg, sizeof(msg), sig, &pby, NULL);
memcpy(priv,
"\xc5\x5e\xce\x85\x8b\x0d\xdd\x52\x63\xf9\x68\x10\xfe\x14\x43\x7c\xd3"
"\xb5\xe1\xfb\xd7\xc6\xa2\xec\x1e\x03\x1f\x05\xe8\x6d\x8b\xd5",
32);
ecdsa_get_public_key65(curve, priv, pub);
ecdsa_sign(curve, HASHER_SHA2, priv, msg, sizeof(msg), sig, &pby, NULL);
for (int i = 0 ; i < iterations; i++) {
ecdsa_verify(curve, HASHER_SHA2, pub, sig, msg, sizeof(msg));
}
for (int i = 0; i < iterations; i++) {
ecdsa_verify(curve, HASHER_SHA2, pub, sig, msg, sizeof(msg));
}
}
void bench_verify_ed25519(int iterations)
{
ed25519_public_key pk;
ed25519_secret_key sk;
ed25519_signature sig;
memcpy(pk, "\xc5\x5e\xce\x85\x8b\x0d\xdd\x52\x63\xf9\x68\x10\xfe\x14\x43\x7c\xd3\xb5\xe1\xfb\xd7\xc6\xa2\xec\x1e\x03\x1f\x05\xe8\x6d\x8b\xd5", 32);
ed25519_publickey(sk, pk);
ed25519_sign(msg, sizeof(msg), sk, pk, sig);
for (int i = 0 ; i < iterations; i++) {
ed25519_sign_open(msg, sizeof(msg), pk, sig);
}
void bench_verify_ed25519(int iterations) {
ed25519_public_key pk;
ed25519_secret_key sk;
ed25519_signature sig;
memcpy(pk,
"\xc5\x5e\xce\x85\x8b\x0d\xdd\x52\x63\xf9\x68\x10\xfe\x14\x43\x7c\xd3"
"\xb5\xe1\xfb\xd7\xc6\xa2\xec\x1e\x03\x1f\x05\xe8\x6d\x8b\xd5",
32);
ed25519_publickey(sk, pk);
ed25519_sign(msg, sizeof(msg), sk, pk, sig);
for (int i = 0; i < iterations; i++) {
ed25519_sign_open(msg, sizeof(msg), pk, sig);
}
}
void bench_multiply_curve25519(int iterations)
{
uint8_t result[32];
uint8_t secret[32];
uint8_t basepoint[32];
memcpy(secret, "\xc5\x5e\xce\x85\x8b\x0d\xdd\x52\x63\xf9\x68\x10\xfe\x14\x43\x7c\xd3\xb5\xe1\xfb\xd7\xc6\xa2\xec\x1e\x03\x1f\x05\xe8\x6d\x8b\xd5", 32);
memcpy(basepoint, "\x96\x47\xda\xbe\x1e\xea\xaf\x25\x47\x1e\x68\x0b\x4d\x7c\x6f\xd1\x14\x38\x76\xbb\x77\x59\xd8\x3d\x0f\xf7\xa2\x49\x08\xfd\xda\xbc", 32);
for (int i = 0 ; i < iterations; i++) {
curve25519_scalarmult(result, secret, basepoint);
}
void bench_multiply_curve25519(int iterations) {
uint8_t result[32];
uint8_t secret[32];
uint8_t basepoint[32];
memcpy(secret,
"\xc5\x5e\xce\x85\x8b\x0d\xdd\x52\x63\xf9\x68\x10\xfe\x14\x43\x7c\xd3"
"\xb5\xe1\xfb\xd7\xc6\xa2\xec\x1e\x03\x1f\x05\xe8\x6d\x8b\xd5",
32);
memcpy(basepoint,
"\x96\x47\xda\xbe\x1e\xea\xaf\x25\x47\x1e\x68\x0b\x4d\x7c\x6f\xd1\x14"
"\x38\x76\xbb\x77\x59\xd8\x3d\x0f\xf7\xa2\x49\x08\xfd\xda\xbc",
32);
for (int i = 0; i < iterations; i++) {
curve25519_scalarmult(result, secret, basepoint);
}
}
static HDNode root;
void prepare_node(void)
{
hdnode_from_seed((uint8_t *)"NothingToSeeHere", 16, SECP256K1_NAME, &root);
hdnode_fill_public_key(&root);
void prepare_node(void) {
hdnode_from_seed((uint8_t *)"NothingToSeeHere", 16, SECP256K1_NAME, &root);
hdnode_fill_public_key(&root);
}
void bench_ckd_normal(int iterations)
{
char addr[MAX_ADDR_SIZE];
HDNode node;
for (int i = 0; i < iterations; i++) {
memcpy(&node, &root, sizeof(HDNode));
hdnode_public_ckd(&node, i);
hdnode_fill_public_key(&node);
ecdsa_get_address(node.public_key, HASHER_SHA2, HASHER_SHA2D, 0, addr, sizeof(addr));
}
void bench_ckd_normal(int iterations) {
char addr[MAX_ADDR_SIZE];
HDNode node;
for (int i = 0; i < iterations; i++) {
memcpy(&node, &root, sizeof(HDNode));
hdnode_public_ckd(&node, i);
hdnode_fill_public_key(&node);
ecdsa_get_address(node.public_key, HASHER_SHA2, HASHER_SHA2D, 0, addr,
sizeof(addr));
}
}
void bench_ckd_optimized(int iterations)
{
char addr[MAX_ADDR_SIZE];
curve_point pub;
ecdsa_read_pubkey(&secp256k1, root.public_key, &pub);
for (int i = 0; i < iterations; i++) {
hdnode_public_ckd_address_optimized(&pub, root.chain_code, i, 0, HASHER_SHA2, HASHER_SHA2D, addr, sizeof(addr), false);
}
void bench_ckd_optimized(int iterations) {
char addr[MAX_ADDR_SIZE];
curve_point pub;
ecdsa_read_pubkey(&secp256k1, root.public_key, &pub);
for (int i = 0; i < iterations; i++) {
hdnode_public_ckd_address_optimized(&pub, root.chain_code, i, 0,
HASHER_SHA2, HASHER_SHA2D, addr,
sizeof(addr), false);
}
}
void bench(void (*func)(int), const char *name, int iterations)
{
clock_t t = clock();
func(iterations);
float speed = iterations / ((float)(clock() - t) / CLOCKS_PER_SEC);
printf("%25s: %8.2f ops/s\n", name, speed);
void bench(void (*func)(int), const char *name, int iterations) {
clock_t t = clock();
func(iterations);
float speed = iterations / ((float)(clock() - t) / CLOCKS_PER_SEC);
printf("%25s: %8.2f ops/s\n", name, speed);
}
#define BENCH(FUNC, ITER) bench(FUNC, #FUNC, ITER)
int main(void) {
prepare_msg();
prepare_msg();
BENCH(bench_sign_secp256k1, 500);
BENCH(bench_verify_secp256k1_33, 500);
BENCH(bench_verify_secp256k1_65, 500);
BENCH(bench_sign_secp256k1, 500);
BENCH(bench_verify_secp256k1_33, 500);
BENCH(bench_verify_secp256k1_65, 500);
BENCH(bench_sign_nist256p1, 500);
BENCH(bench_verify_nist256p1_33, 500);
BENCH(bench_verify_nist256p1_65, 500);
BENCH(bench_sign_nist256p1, 500);
BENCH(bench_verify_nist256p1_33, 500);
BENCH(bench_verify_nist256p1_65, 500);
BENCH(bench_sign_ed25519, 4000);
BENCH(bench_verify_ed25519, 4000);
BENCH(bench_sign_ed25519, 4000);
BENCH(bench_verify_ed25519, 4000);
BENCH(bench_multiply_curve25519, 4000);
BENCH(bench_multiply_curve25519, 4000);
prepare_node();
prepare_node();
BENCH(bench_ckd_normal, 1000);
BENCH(bench_ckd_optimized, 1000);
BENCH(bench_ckd_normal, 1000);
BENCH(bench_ckd_optimized, 1000);
return 0;
return 0;
}

@ -1,10 +1,10 @@
#include <stdio.h>
#include <time.h>
#include <string.h>
#include "bip39.h"
#include <time.h>
#include "bip32.h"
#include "ecdsa.h"
#include "bip39.h"
#include "curves.h"
#include "ecdsa.h"
#include "secp256k1.h"
char iter[256];
@ -26,63 +26,64 @@ clock_t start;
// address: "1N3uJ5AU3FTYQ1ZQgTMtYmgSvMBmQiGVBS"
// passphrase: "testing"
int main(int argc, char **argv)
{
if (argc != 2 && argc != 3) {
fprintf(stderr, "Usage: bip39bruteforce address [mnemonic]\n");
return 1;
}
const char *address = argv[1];
const char *mnemonic, *item;
if (argc == 3) {
mnemonic = argv[2];
item = "passphrase";
} else {
mnemonic = NULL;
item = "mnemonic";
}
if (mnemonic && !mnemonic_check(mnemonic)) {
fprintf(stderr, "\"%s\" is not a valid mnemonic\n", mnemonic);
return 2;
}
if (!ecdsa_address_decode(address, 0, secp256k1_info.hasher_base58, addr)) {
fprintf(stderr, "\"%s\" is not a valid address\n", address);
return 3;
}
printf("Reading %ss from stdin ...\n", item);
start = clock();
for (;;) {
if (fgets(iter, 256, stdin) == NULL) break;
int len = strlen(iter);
if (len <= 0) {
continue;
}
count++;
iter[len - 1] = 0;
if (mnemonic) {
mnemonic_to_seed(mnemonic, iter, seed, NULL);
} else {
mnemonic_to_seed(iter, "", seed, NULL);
}
hdnode_from_seed(seed, 512 / 8, SECP256K1_NAME, &node);
hdnode_private_ckd_prime(&node, 44);
hdnode_private_ckd_prime(&node, 0);
hdnode_private_ckd_prime(&node, 0);
hdnode_private_ckd(&node, 0);
hdnode_private_ckd(&node, 0);
hdnode_fill_public_key(&node);
ecdsa_get_pubkeyhash(node.public_key, secp256k1_info.hasher_pubkey, pubkeyhash);
if (memcmp(addr + 1, pubkeyhash, 20) == 0) {
found = 1;
break;
}
}
float dur = (float)(clock() - start) / CLOCKS_PER_SEC;
printf("Tried %d %ss in %f seconds = %f tries/second\n", count, item, dur, (float)count/dur);
if (found) {
printf("Correct %s found! :-)\n\"%s\"\n", item, iter);
return 0;
}
printf("Correct %s not found. :-(\n", item);
return 4;
int main(int argc, char **argv) {
if (argc != 2 && argc != 3) {
fprintf(stderr, "Usage: bip39bruteforce address [mnemonic]\n");
return 1;
}
const char *address = argv[1];
const char *mnemonic, *item;
if (argc == 3) {
mnemonic = argv[2];
item = "passphrase";
} else {
mnemonic = NULL;
item = "mnemonic";
}
if (mnemonic && !mnemonic_check(mnemonic)) {
fprintf(stderr, "\"%s\" is not a valid mnemonic\n", mnemonic);
return 2;
}
if (!ecdsa_address_decode(address, 0, secp256k1_info.hasher_base58, addr)) {
fprintf(stderr, "\"%s\" is not a valid address\n", address);
return 3;
}
printf("Reading %ss from stdin ...\n", item);
start = clock();
for (;;) {
if (fgets(iter, 256, stdin) == NULL) break;
int len = strlen(iter);
if (len <= 0) {
continue;
}
count++;
iter[len - 1] = 0;
if (mnemonic) {
mnemonic_to_seed(mnemonic, iter, seed, NULL);
} else {
mnemonic_to_seed(iter, "", seed, NULL);
}
hdnode_from_seed(seed, 512 / 8, SECP256K1_NAME, &node);
hdnode_private_ckd_prime(&node, 44);
hdnode_private_ckd_prime(&node, 0);
hdnode_private_ckd_prime(&node, 0);
hdnode_private_ckd(&node, 0);
hdnode_private_ckd(&node, 0);
hdnode_fill_public_key(&node);
ecdsa_get_pubkeyhash(node.public_key, secp256k1_info.hasher_pubkey,
pubkeyhash);
if (memcmp(addr + 1, pubkeyhash, 20) == 0) {
found = 1;
break;
}
}
float dur = (float)(clock() - start) / CLOCKS_PER_SEC;
printf("Tried %d %ss in %f seconds = %f tries/second\n", count, item, dur,
(float)count / dur);
if (found) {
printf("Correct %s found! :-)\n\"%s\"\n", item, iter);
return 0;
}
printf("Correct %s not found. :-(\n", item);
return 4;
}

@ -1,8 +1,8 @@
#include <stdio.h>
#include <assert.h>
#include <stdio.h>
#include "bignum.h"
#include "ecdsa.h"
#include "bip32.h"
#include "ecdsa.h"
#include "rand.h"
/*
@ -11,58 +11,58 @@
* where G is the generator of the specified elliptic curve.
*/
int main(int argc, char **argv) {
int i,j,k;
if (argc != 2) {
printf("Usage: %s CURVE_NAME\n", argv[0]);
return 1;
}
const char *name = argv[1];
const curve_info *info = get_curve_by_name(name);
const ecdsa_curve *curve = info->params;
if (curve == 0) {
printf("Unknown curve '%s'\n", name);
return 1;
}
int i, j, k;
if (argc != 2) {
printf("Usage: %s CURVE_NAME\n", argv[0]);
return 1;
}
const char *name = argv[1];
const curve_info *info = get_curve_by_name(name);
const ecdsa_curve *curve = info->params;
if (curve == 0) {
printf("Unknown curve '%s'\n", name);
return 1;
}
curve_point ng = curve->G;
curve_point pow2ig = curve->G;
for (i = 0; i < 64; i++) {
// invariants:
// pow2ig = 16^i * G
// ng = pow2ig
printf("\t{\n");
for (j = 0; j < 8; j++) {
// invariants:
// pow2ig = 16^i * G
// ng = (2*j+1) * 16^i * G
curve_point ng = curve->G;
curve_point pow2ig = curve->G;
for (i = 0; i < 64; i++) {
// invariants:
// pow2ig = 16^i * G
// ng = pow2ig
printf("\t{\n");
for (j = 0; j < 8; j++) {
// invariants:
// pow2ig = 16^i * G
// ng = (2*j+1) * 16^i * G
#ifndef NDEBUG
curve_point checkresult;
bignum256 a;
bn_zero(&a);
a.val[(4*i) / 30] = ((uint32_t) 2*j+1) << ((4*i) % 30);
bn_normalize(&a);
point_multiply(curve, &a, &curve->G, &checkresult);
assert(point_is_equal(&checkresult, &ng));
curve_point checkresult;
bignum256 a;
bn_zero(&a);
a.val[(4 * i) / 30] = ((uint32_t)2 * j + 1) << ((4 * i) % 30);
bn_normalize(&a);
point_multiply(curve, &a, &curve->G, &checkresult);
assert(point_is_equal(&checkresult, &ng));
#endif
printf("\t\t/* %2d*16^%d*G: */\n\t\t{{{", 2*j + 1, i);
// print x coordinate
for (k = 0; k < 9; k++) {
printf((k < 8 ? "0x%08x, " : "0x%04x"), ng.x.val[k]);
}
printf("}},\n\t\t {{");
// print y coordinate
for (k = 0; k < 9; k++) {
printf((k < 8 ? "0x%08x, " : "0x%04x"), ng.y.val[k]);
}
if (j == 7) {
printf("}}}\n\t},\n");
} else {
printf("}}},\n");
point_add(curve, &pow2ig, &ng);
}
point_add(curve, &pow2ig, &ng);
}
pow2ig = ng;
}
return 0;
printf("\t\t/* %2d*16^%d*G: */\n\t\t{{{", 2 * j + 1, i);
// print x coordinate
for (k = 0; k < 9; k++) {
printf((k < 8 ? "0x%08x, " : "0x%04x"), ng.x.val[k]);
}
printf("}},\n\t\t {{");
// print y coordinate
for (k = 0; k < 9; k++) {
printf((k < 8 ? "0x%08x, " : "0x%04x"), ng.y.val[k]);
}
if (j == 7) {
printf("}}}\n\t},\n");
} else {
printf("}}},\n");
point_add(curve, &pow2ig, &ng);
}
point_add(curve, &pow2ig, &ng);
}
pow2ig = ng;
}
return 0;
}

@ -1,47 +1,49 @@
#include <inttypes.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <stdint.h>
#include <inttypes.h>
#include "bip32.h"
#include "curves.h"
#include "ecdsa.h"
#define VERSION_PUBLIC 0x0488b21e
#define VERSION_PUBLIC 0x0488b21e
#define VERSION_PRIVATE 0x0488ade4
void process_job(uint32_t jobid, const char *xpub, uint32_t change, uint32_t from, uint32_t to)
{
HDNode node, child;
if (change > 1 || to <= from || hdnode_deserialize(xpub, VERSION_PUBLIC, VERSION_PRIVATE, SECP256K1_NAME, &node, NULL) != 0) {
printf("%d error\n", jobid);
return;
}
hdnode_public_ckd(&node, change);
uint32_t i;
char address[36];
for (i = from; i < to; i++) {
memcpy(&child, &node, sizeof(HDNode));
hdnode_public_ckd(&child, i);
ecdsa_get_address(child.public_key, 0, HASHER_SHA2, HASHER_SHA2D, address, sizeof(address));
printf("%d %d %s\n", jobid, i, address);
}
void process_job(uint32_t jobid, const char *xpub, uint32_t change,
uint32_t from, uint32_t to) {
HDNode node, child;
if (change > 1 || to <= from ||
hdnode_deserialize(xpub, VERSION_PUBLIC, VERSION_PRIVATE, SECP256K1_NAME,
&node, NULL) != 0) {
printf("%d error\n", jobid);
return;
}
hdnode_public_ckd(&node, change);
uint32_t i;
char address[36];
for (i = from; i < to; i++) {
memcpy(&child, &node, sizeof(HDNode));
hdnode_public_ckd(&child, i);
ecdsa_get_address(child.public_key, 0, HASHER_SHA2, HASHER_SHA2D, address,
sizeof(address));
printf("%d %d %s\n", jobid, i, address);
}
}
int main(void)
{
char line[1024], xpub[1024];
uint32_t jobid, change, from, to;
int r;
for (;;) {
if (!fgets(line, sizeof(line), stdin)) break;
r = sscanf(line, "%u %s %u %u %u\n", &jobid, xpub, &change, &from, &to);
if (r < 1) {
printf("error\n");
} else if (r != 5) {
printf("%d error\n", jobid);
} else {
process_job(jobid, xpub, change, from, to);
}
}
return 0;
int main(void) {
char line[1024], xpub[1024];
uint32_t jobid, change, from, to;
int r;
for (;;) {
if (!fgets(line, sizeof(line), stdin)) break;
r = sscanf(line, "%u %s %u %u %u\n", &jobid, xpub, &change, &from, &to);
if (r < 1) {
printf("error\n");
} else if (r != 5) {
printf("%d error\n", jobid);
} else {
process_job(jobid, xpub, change, from, to);
}
}
return 0;
}

Loading…
Cancel
Save