450 lines
9.3 KiB
C
450 lines
9.3 KiB
C
#include "utils.h"
|
|
|
|
#include <ctype.h>
|
|
#include <math.h>
|
|
#include <openssl/bn.h>
|
|
#include <openssl/sha.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
static char to_hex_digit(unsigned int v) {
|
|
if (v < 10U) {
|
|
return (char)('0' + v);
|
|
}
|
|
return (char)('a' + (v - 10U));
|
|
}
|
|
|
|
void sb_init(StrBuf *sb) {
|
|
sb->data = NULL;
|
|
sb->len = 0;
|
|
sb->cap = 0;
|
|
}
|
|
|
|
void sb_free(StrBuf *sb) {
|
|
free(sb->data);
|
|
sb->data = NULL;
|
|
sb->len = 0;
|
|
sb->cap = 0;
|
|
}
|
|
|
|
int sb_reserve(StrBuf *sb, size_t extra) {
|
|
size_t need;
|
|
size_t new_cap;
|
|
char *p;
|
|
|
|
need = sb->len + extra + 1;
|
|
if (need <= sb->cap) {
|
|
return 1;
|
|
}
|
|
|
|
new_cap = (sb->cap == 0) ? 128 : sb->cap;
|
|
while (new_cap < need) {
|
|
new_cap *= 2;
|
|
}
|
|
|
|
p = (char *)realloc(sb->data, new_cap);
|
|
if (p == NULL) {
|
|
return 0;
|
|
}
|
|
|
|
sb->data = p;
|
|
sb->cap = new_cap;
|
|
|
|
if (sb->len == 0) {
|
|
sb->data[0] = '\0';
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
int sb_append(StrBuf *sb, const char *s) {
|
|
size_t n = strlen(s);
|
|
|
|
if (sb_reserve(sb, n) == 0) {
|
|
return 0;
|
|
}
|
|
|
|
memcpy(sb->data + sb->len, s, n + 1);
|
|
sb->len += n;
|
|
return 1;
|
|
}
|
|
|
|
int sb_append_n(StrBuf *sb, const char *s, size_t n) {
|
|
if (sb_reserve(sb, n) == 0) {
|
|
return 0;
|
|
}
|
|
|
|
memcpy(sb->data + sb->len, s, n);
|
|
sb->len += n;
|
|
sb->data[sb->len] = '\0';
|
|
return 1;
|
|
}
|
|
|
|
int sb_append_byte_hex(StrBuf *sb, uint8_t b) {
|
|
char tmp[3];
|
|
|
|
tmp[0] = to_hex_digit((unsigned int)(b >> 4));
|
|
tmp[1] = to_hex_digit((unsigned int)(b & 0x0F));
|
|
tmp[2] = '\0';
|
|
return sb_append(sb, tmp);
|
|
}
|
|
|
|
char *sb_take(StrBuf *sb) {
|
|
char *out = sb->data;
|
|
sb->data = NULL;
|
|
sb->len = 0;
|
|
sb->cap = 0;
|
|
return out;
|
|
}
|
|
|
|
int hex_char_to_val(char c) {
|
|
if (c >= '0' && c <= '9') {
|
|
return c - '0';
|
|
}
|
|
if (c >= 'a' && c <= 'f') {
|
|
return 10 + (c - 'a');
|
|
}
|
|
if (c >= 'A' && c <= 'F') {
|
|
return 10 + (c - 'A');
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
int hex_to_bytes(const char *hex, uint8_t **out, size_t *out_len) {
|
|
size_t n;
|
|
size_t i;
|
|
uint8_t *buf;
|
|
|
|
if (hex == NULL || out == NULL || out_len == NULL) {
|
|
return 0;
|
|
}
|
|
|
|
n = strlen(hex);
|
|
if ((n % 2) != 0) {
|
|
return 0;
|
|
}
|
|
|
|
buf = (uint8_t *)malloc(n / 2);
|
|
if (buf == NULL) {
|
|
return 0;
|
|
}
|
|
|
|
for (i = 0; i < n; i += 2) {
|
|
int hi = hex_char_to_val(hex[i]);
|
|
int lo = hex_char_to_val(hex[i + 1]);
|
|
if (hi < 0 || lo < 0) {
|
|
free(buf);
|
|
return 0;
|
|
}
|
|
buf[i / 2] = (uint8_t)((hi << 4) | lo);
|
|
}
|
|
|
|
*out = buf;
|
|
*out_len = n / 2;
|
|
return 1;
|
|
}
|
|
|
|
int hex_to_fixed_bytes(const char *hex, uint8_t *out, size_t out_len) {
|
|
size_t n;
|
|
size_t i;
|
|
|
|
if (hex == NULL || out == NULL) {
|
|
return 0;
|
|
}
|
|
|
|
n = strlen(hex);
|
|
if (n != out_len * 2) {
|
|
return 0;
|
|
}
|
|
|
|
for (i = 0; i < n; i += 2) {
|
|
int hi = hex_char_to_val(hex[i]);
|
|
int lo = hex_char_to_val(hex[i + 1]);
|
|
if (hi < 0 || lo < 0) {
|
|
return 0;
|
|
}
|
|
out[i / 2] = (uint8_t)((hi << 4) | lo);
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
char *bytes_to_hex(const uint8_t *data, size_t len) {
|
|
static const char tab[] = "0123456789abcdef";
|
|
char *out;
|
|
size_t i;
|
|
|
|
out = (char *)malloc(len * 2 + 1);
|
|
if (out == NULL) {
|
|
return NULL;
|
|
}
|
|
|
|
for (i = 0; i < len; ++i) {
|
|
out[2 * i] = tab[data[i] >> 4];
|
|
out[2 * i + 1] = tab[data[i] & 0x0F];
|
|
}
|
|
out[len * 2] = '\0';
|
|
|
|
return out;
|
|
}
|
|
|
|
void reverse_bytes(uint8_t *data, size_t n) {
|
|
size_t i;
|
|
|
|
for (i = 0; i < n / 2; ++i) {
|
|
uint8_t t = data[i];
|
|
data[i] = data[n - 1 - i];
|
|
data[n - 1 - i] = t;
|
|
}
|
|
}
|
|
|
|
void double_sha256(const uint8_t *data, size_t len, uint8_t out[32]) {
|
|
uint8_t tmp[SHA256_DIGEST_LENGTH];
|
|
|
|
SHA256(data, len, tmp);
|
|
SHA256(tmp, SHA256_DIGEST_LENGTH, out);
|
|
}
|
|
|
|
int encode_varint_hex(uint64_t value, StrBuf *sb) {
|
|
uint8_t bytes[9];
|
|
size_t n = 0;
|
|
size_t i;
|
|
|
|
if (value < 0xFD) {
|
|
bytes[n++] = (uint8_t)value;
|
|
} else if (value <= 0xFFFFULL) {
|
|
bytes[n++] = 0xFD;
|
|
bytes[n++] = (uint8_t)(value & 0xFF);
|
|
bytes[n++] = (uint8_t)((value >> 8) & 0xFF);
|
|
} else if (value <= 0xFFFFFFFFULL) {
|
|
bytes[n++] = 0xFE;
|
|
bytes[n++] = (uint8_t)(value & 0xFF);
|
|
bytes[n++] = (uint8_t)((value >> 8) & 0xFF);
|
|
bytes[n++] = (uint8_t)((value >> 16) & 0xFF);
|
|
bytes[n++] = (uint8_t)((value >> 24) & 0xFF);
|
|
} else {
|
|
bytes[n++] = 0xFF;
|
|
bytes[n++] = (uint8_t)(value & 0xFF);
|
|
bytes[n++] = (uint8_t)((value >> 8) & 0xFF);
|
|
bytes[n++] = (uint8_t)((value >> 16) & 0xFF);
|
|
bytes[n++] = (uint8_t)((value >> 24) & 0xFF);
|
|
bytes[n++] = (uint8_t)((value >> 32) & 0xFF);
|
|
bytes[n++] = (uint8_t)((value >> 40) & 0xFF);
|
|
bytes[n++] = (uint8_t)((value >> 48) & 0xFF);
|
|
bytes[n++] = (uint8_t)((value >> 56) & 0xFF);
|
|
}
|
|
|
|
for (i = 0; i < n; ++i) {
|
|
if (sb_append_byte_hex(sb, bytes[i]) == 0) {
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
static char *bn_to_fixed_hex64(const BIGNUM *bn) {
|
|
char *tmp;
|
|
char *out;
|
|
size_t n;
|
|
size_t i;
|
|
|
|
tmp = BN_bn2hex(bn);
|
|
if (tmp == NULL) {
|
|
return NULL;
|
|
}
|
|
|
|
n = strlen(tmp);
|
|
if (n > 64) {
|
|
OPENSSL_free(tmp);
|
|
return NULL;
|
|
}
|
|
|
|
out = (char *)malloc(65);
|
|
if (out == NULL) {
|
|
OPENSSL_free(tmp);
|
|
return NULL;
|
|
}
|
|
|
|
for (i = 0; i < 64; ++i) {
|
|
out[i] = '0';
|
|
}
|
|
out[64] = '\0';
|
|
|
|
for (i = 0; i < n; ++i) {
|
|
char c = tmp[i];
|
|
if (isupper((unsigned char)c)) {
|
|
c = (char)tolower((unsigned char)c);
|
|
}
|
|
out[64 - n + i] = c;
|
|
}
|
|
|
|
OPENSSL_free(tmp);
|
|
return out;
|
|
}
|
|
|
|
char *decode_nbits_hex(uint32_t nbits) {
|
|
BN_CTX *ctx;
|
|
BIGNUM *bn;
|
|
BIGNUM *sig;
|
|
char *out;
|
|
uint32_t exponent;
|
|
uint32_t significand;
|
|
|
|
exponent = (nbits >> 24) & 0xFF;
|
|
significand = nbits & 0x007FFFFF;
|
|
|
|
ctx = BN_CTX_new();
|
|
bn = BN_new();
|
|
sig = BN_new();
|
|
|
|
if (ctx == NULL || bn == NULL || sig == NULL) {
|
|
BN_CTX_free(ctx);
|
|
BN_free(bn);
|
|
BN_free(sig);
|
|
return NULL;
|
|
}
|
|
|
|
BN_set_word(sig, significand);
|
|
BN_copy(bn, sig);
|
|
|
|
if (exponent >= 3) {
|
|
BN_lshift(bn, bn, 8 * ((int)exponent - 3));
|
|
} else {
|
|
BN_rshift(bn, bn, 8 * (3 - (int)exponent));
|
|
}
|
|
|
|
out = bn_to_fixed_hex64(bn);
|
|
|
|
BN_CTX_free(ctx);
|
|
BN_free(bn);
|
|
BN_free(sig);
|
|
return out;
|
|
}
|
|
|
|
char *calculate_target_hex(const char *bits_hex, double difficulty_factor, const char *network) {
|
|
static const char *MAX_TARGET_HEX = "00000000ffff0000000000000000000000000000000000000000000000000000";
|
|
BIGNUM *max_bn;
|
|
BIGNUM *limit_bn;
|
|
BIGNUM *num_bn;
|
|
BIGNUM *den_bn;
|
|
BIGNUM *result_bn;
|
|
BN_CTX *ctx;
|
|
char *original;
|
|
char *out;
|
|
uint64_t scaled_factor;
|
|
const uint64_t SCALE = 1000000000ULL;
|
|
uint32_t nbits;
|
|
|
|
if (bits_hex == NULL || network == NULL) {
|
|
return NULL;
|
|
}
|
|
|
|
nbits = (uint32_t)strtoul(bits_hex, NULL, 16);
|
|
original = decode_nbits_hex(nbits);
|
|
if (original == NULL) {
|
|
return NULL;
|
|
}
|
|
|
|
if (strcmp(network, "regtest") == 0) {
|
|
if (difficulty_factor < 0.0) {
|
|
difficulty_factor = 0.1;
|
|
}
|
|
} else {
|
|
difficulty_factor = 1.0;
|
|
}
|
|
|
|
if (difficulty_factor == 0.0) {
|
|
return original;
|
|
}
|
|
|
|
scaled_factor = (uint64_t)llround(difficulty_factor * (double)SCALE);
|
|
if (scaled_factor == 0ULL) {
|
|
scaled_factor = 1ULL;
|
|
}
|
|
|
|
ctx = BN_CTX_new();
|
|
max_bn = BN_new();
|
|
limit_bn = BN_new();
|
|
num_bn = BN_new();
|
|
den_bn = BN_new();
|
|
result_bn = BN_new();
|
|
|
|
if (ctx == NULL || max_bn == NULL || limit_bn == NULL || num_bn == NULL || den_bn == NULL || result_bn == NULL) {
|
|
BN_CTX_free(ctx);
|
|
BN_free(max_bn);
|
|
BN_free(limit_bn);
|
|
BN_free(num_bn);
|
|
BN_free(den_bn);
|
|
BN_free(result_bn);
|
|
free(original);
|
|
return NULL;
|
|
}
|
|
|
|
BN_hex2bn(&max_bn, MAX_TARGET_HEX);
|
|
BN_hex2bn(&limit_bn, "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff");
|
|
|
|
BN_copy(num_bn, max_bn);
|
|
BN_mul_word(num_bn, (BN_ULONG)SCALE);
|
|
BN_set_word(den_bn, (BN_ULONG)scaled_factor);
|
|
BN_div(result_bn, NULL, num_bn, den_bn, ctx);
|
|
|
|
if (BN_cmp(result_bn, limit_bn) > 0) {
|
|
BN_copy(result_bn, limit_bn);
|
|
}
|
|
|
|
out = bn_to_fixed_hex64(result_bn);
|
|
|
|
BN_CTX_free(ctx);
|
|
BN_free(max_bn);
|
|
BN_free(limit_bn);
|
|
BN_free(num_bn);
|
|
BN_free(den_bn);
|
|
BN_free(result_bn);
|
|
free(original);
|
|
|
|
return out;
|
|
}
|
|
|
|
char *hex_add_width(const char *base_hex, int add_value) {
|
|
static const char *hex_digits = "0123456789abcdef";
|
|
char *out;
|
|
size_t n;
|
|
int carry;
|
|
size_t pos;
|
|
|
|
if (base_hex == NULL || add_value < 0) {
|
|
return NULL;
|
|
}
|
|
|
|
n = strlen(base_hex);
|
|
if (n == 0) {
|
|
return NULL;
|
|
}
|
|
|
|
out = strdup(base_hex);
|
|
if (out == NULL) {
|
|
return NULL;
|
|
}
|
|
|
|
carry = add_value;
|
|
pos = n;
|
|
while (pos > 0 && carry > 0) {
|
|
int digit = hex_char_to_val(out[pos - 1]);
|
|
int sum;
|
|
|
|
if (digit < 0) {
|
|
free(out);
|
|
return NULL;
|
|
}
|
|
|
|
sum = digit + carry;
|
|
out[pos - 1] = hex_digits[sum & 0x0F];
|
|
carry = sum >> 4;
|
|
--pos;
|
|
}
|
|
|
|
return out;
|
|
}
|