void ep_mul_sim_gen(ep_t r, const bn_t k, const ep_t q, const bn_t m) { ep_t g; ep_null(g); if (bn_is_zero(k)) { ep_mul(r, q, m); return; } if (bn_is_zero(m) || ep_is_infty(q)) { ep_mul_gen(r, k); return; } TRY { ep_new(g); ep_curve_get_gen(g); #if defined(EP_ENDOM) #if EP_SIM == INTER && EP_FIX == LWNAF && defined(EP_PRECO) if (ep_curve_is_endom()) { ep_mul_sim_endom(r, g, k, q, m, ep_curve_get_tab()); } #else if (ep_curve_is_endom()) { ep_mul_sim(r, g, k, q, m); } #endif #endif #if defined(EP_PLAIN) || defined(EP_SUPER) #if EP_SIM == INTER && EP_FIX == LWNAF && defined(EP_PRECO) if (!ep_curve_is_endom()) { ep_mul_sim_plain(r, g, k, q, m, ep_curve_get_tab()); } #else if (!ep_curve_is_endom()) { ep_mul_sim(r, g, k, q, m); } #endif #endif } CATCH_ANY { THROW(ERR_CAUGHT); } FINALLY { ep_free(g); } }
void eb_mul_sim_gen(eb_t r, const bn_t k, const eb_t q, const bn_t m) { eb_t g; eb_null(g); if (bn_is_zero(k)) { eb_mul(r, q, m); return; } if (bn_is_zero(m) || eb_is_infty(q)) { eb_mul_gen(r, k); return; } TRY { eb_new(g); eb_curve_get_gen(g); #if defined(EB_KBLTZ) #if EB_SIM == INTER && EB_FIX == LWNAF && defined(EB_PRECO) if (eb_curve_is_kbltz()) { eb_mul_sim_kbltz(r, g, k, q, m, eb_curve_get_tab()); } #else if (eb_curve_is_kbltz()) { eb_mul_sim(r, g, k, q, m); } #endif #endif #if defined(EB_PLAIN) #if EB_SIM == INTER && EB_FIX == LWNAF && defined(EB_PRECO) if (!eb_curve_is_kbltz()) { eb_mul_sim_plain(r, g, k, q, m, eb_curve_get_tab()); } #else if (!eb_curve_is_kbltz()) { eb_mul_sim(r, g, k, q, m); } #endif #endif } CATCH_ANY { THROW(ERR_CAUGHT); } FINALLY { eb_free(g); } }
/** * Multiplies a binary elliptic curve point by an integer using the w-NAF * method. * * @param[out] r - the result. * @param[in] p - the point to multiply. * @param[in] k - the integer. */ static void ep2_mul_fix_ordin(ep2_t r, ep2_t *table, bn_t k) { int len, i, n; int8_t naf[2 * RLC_FP_BITS + 1], *t; if (bn_is_zero(k)) { ep2_set_infty(r); return; } /* Compute the w-TNAF representation of k. */ len = 2 * RLC_FP_BITS + 1; bn_rec_naf(naf, &len, k, EP_DEPTH); t = naf + len - 1; ep2_set_infty(r); for (i = len - 1; i >= 0; i--, t--) { ep2_dbl(r, r); n = *t; if (n > 0) { ep2_add(r, r, table[n / 2]); } if (n < 0) { ep2_sub(r, r, table[-n / 2]); } } /* Convert r to affine coordinates. */ ep2_norm(r, r); if (bn_sign(k) == RLC_NEG) { ep2_neg(r, r); } }
void fp_read_bin(fp_t a, const unsigned char *str, int len) { bn_t t; bn_null(t); TRY { bn_new(t); bn_read_bin(t, (unsigned char *) str, len); if (bn_is_zero(t)) { fp_zero(a); } else { if (t->used == 1) { fp_prime_conv_dig(a, t->dp[0]); } else { fp_prime_conv(a, t); } } } CATCH_ANY { THROW(ERR_CAUGHT); } FINALLY { bn_free(t); } }
void fp_read_str(fp_t a, const char *str, int len, int radix) { bn_t t; bn_null(t); TRY { bn_new(t); bn_read_str(t, str, len, radix); if (bn_is_zero(t)) { fp_zero(a); } else { if (t->used == 1) { fp_prime_conv_dig(a, t->dp[0]); } else { fp_prime_conv(a, t); } } } CATCH_ANY { THROW(ERR_CAUGHT); } FINALLY { bn_free(t); } }
status_t element_pow_zr(element_t c, element_t a, element_t b) { GroupType type = a->type; // c (type) = a (type) ^ b (ZR) LEAVE_IF( c->isInitialized != TRUE || a->isInitialized != TRUE, "uninitialized argument."); EXIT_IF_NOT_SAME(c, a); LEAVE_IF(a->isInitialized != TRUE, "invalid argument."); LEAVE_IF(b->isInitialized != TRUE || b->type != ZR, "invalid type."); if(type == ZR) { bn_mxp(c->bn, a->bn, b->bn, a->order); } else if(type == G1) { g1_mul(c->g1, a->g1, b->bn); } else if(type == G2) { g2_mul(c->g2, a->g2, b->bn); } else if(type == GT) { if(bn_is_zero(b->bn)) gt_set_unity(c->gt); // GT ^ 0 => identity element (not handled by gt_exp) else gt_exp(c->gt, a->gt, b->bn); } else { return ELEMENT_INVALID_TYPES; } return ELEMENT_OK; }
int cp_ecss_gen(bn_t d, ec_t q) { bn_t n; int result = STS_OK; bn_null(n); TRY { bn_new(n); ec_curve_get_ord(n); do { bn_rand(d, BN_POS, bn_bits(n)); bn_mod(d, d, n); } while (bn_is_zero(d)); ec_mul_gen(q, d); } CATCH_ANY { result = STS_ERR; } FINALLY { bn_free(n); } return result; }
void fp_read_bin(fp_t a, const uint8_t *bin, int len) { bn_t t; bn_null(t); if (len != RLC_FP_BYTES) { THROW(ERR_NO_BUFFER); } TRY { bn_new(t); bn_read_bin(t, bin, len); if (bn_is_zero(t)) { fp_zero(a); } else { if (t->used == 1) { fp_prime_conv_dig(a, t->dp[0]); } else { fp_prime_conv(a, t); } } } CATCH_ANY { THROW(ERR_CAUGHT); } FINALLY { bn_free(t); } }
// int appears on lhs (1 / [ZR, G1, G2, GT]) status_t element_int_div(element_t c, integer_t a, element_t b) { GroupType type = b->type; EXIT_IF_NOT_SAME(c, b); LEAVE_IF( c->isInitialized != TRUE || b->isInitialized != TRUE, "uninitialized arguments."); LEAVE_IF( c->type != type, "result initialized but invalid type."); if(type == ZR) { if(bn_is_zero(b->bn)) return ELEMENT_DIV_ZERO; element_invert(c, b); if(bn_is_one(a)) return ELEMENT_OK; integer_t s; bn_inits(s); bn_mul(s, a, c->bn); bn_div_rem(s, c->bn, s, c->order); // if(bn_sign(c->bn) == BN_NEG) bn_add(c->bn, c->bn, c->order); bn_free(s); // bn_div(c->bn, a, b->bn); // bn_mod(c->bn, c->bn, c->order); } else if(type == G1 || type == G2 || type == GT) { if(bn_is_one(a)) { element_invert(c, b); } // TODO: other cases: a > 1 (ZR)? } return ELEMENT_OK; }
int cp_ecss_sig(bn_t e, bn_t s, uint8_t *msg, int len, bn_t d) { bn_t n, k, x, r; ec_t p; uint8_t hash[MD_LEN]; uint8_t m[len + FC_BYTES]; int result = STS_OK; bn_null(n); bn_null(k); bn_null(x); bn_null(r); ec_null(p); TRY { bn_new(n); bn_new(k); bn_new(x); bn_new(r); ec_new(p); ec_curve_get_ord(n); do { bn_rand_mod(k, n); ec_mul_gen(p, k); ec_get_x(x, p); bn_mod(r, x, n); } while (bn_is_zero(r)); memcpy(m, msg, len); bn_write_bin(m + len, FC_BYTES, r); md_map(hash, m, len + FC_BYTES); if (8 * MD_LEN > bn_bits(n)) { len = CEIL(bn_bits(n), 8); bn_read_bin(e, hash, len); bn_rsh(e, e, 8 * MD_LEN - bn_bits(n)); } else { bn_read_bin(e, hash, MD_LEN); } bn_mod(e, e, n); bn_mul(s, d, e); bn_mod(s, s, n); bn_sub(s, n, s); bn_add(s, s, k); bn_mod(s, s, n); } CATCH_ANY { result = STS_ERR; } FINALLY { bn_free(n); bn_free(k); bn_free(x); bn_free(r); ec_free(p); } return result; }
void ed_mul_gen(ed_t r, const bn_t k) { if (bn_is_zero(k)) { ed_set_infty(r); return; } #ifdef ED_PRECO ed_mul_fix(r, ed_curve_get_tab(), k); #else ed_t g; ed_null(g); TRY { ed_new(g); ed_curve_get_gen(g); ed_mul(r, g, k); } CATCH_ANY { THROW(ERR_CAUGHT); } FINALLY { ed_free(g); } #endif }
void ed_mul_basic(ed_t r, const ed_t p, const bn_t k) { ed_t t; ed_null(t); if (bn_is_zero(k) || ed_is_infty(p)) { ed_set_infty(r); return; } TRY { ed_new(t); ed_copy(t, p); for (int i = bn_bits(k) - 2; i >= 0; i--) { ed_dbl(t, t); if (bn_get_bit(k, i)) { ed_add(t, t, p); } } ed_norm(r, t); if (bn_sign(k) == RLC_NEG) { ed_neg(r, r); } } CATCH_ANY { THROW(ERR_CAUGHT); } FINALLY { ed_free(t); } }
status_t element_pow_int(element_t c, element_t a, integer_t b) { GroupType type = a->type; // TODO: c (type) = a (type) ^ b (ZR) LEAVE_IF( c->isInitialized != TRUE || a->isInitialized != TRUE, "uninitialized argument."); EXIT_IF_NOT_SAME(c, a); LEAVE_IF(b == NULL, "uninitialized integer."); status_t result = ELEMENT_OK; LEAVE_IF( c->type != type, "result initialized but invalid type."); switch(type) { case ZR: bn_mxp(c->bn, a->bn, b, a->order); break; case G1: g1_mul(c->g1, a->g1, b); break; case G2: g2_mul(c->g2, a->g2, b); break; case GT: if(bn_is_zero(b)) gt_set_unity(c->gt); else gt_exp(c->gt, a->gt, b); break; default: result = ELEMENT_INVALID_TYPES; break; } return result; }
void ep2_mul_fix_combd(ep2_t r, ep2_t *t, bn_t k) { int i, j, d, e, w0, w1, n0, p0, p1; bn_t n; if (bn_is_zero(k)) { ep2_set_infty(r); return; } bn_null(n); TRY { bn_new(n); ep2_curve_get_ord(n); d = bn_bits(n); d = ((d % EP_DEPTH) == 0 ? (d / EP_DEPTH) : (d / EP_DEPTH) + 1); e = (d % 2 == 0 ? (d / 2) : (d / 2) + 1); ep2_set_infty(r); n0 = bn_bits(k); p1 = (e - 1) + (EP_DEPTH - 1) * d; for (i = e - 1; i >= 0; i--) { ep2_dbl(r, r); w0 = 0; p0 = p1; for (j = EP_DEPTH - 1; j >= 0; j--, p0 -= d) { w0 = w0 << 1; if (p0 < n0 && bn_get_bit(k, p0)) { w0 = w0 | 1; } } w1 = 0; p0 = p1-- + e; for (j = EP_DEPTH - 1; j >= 0; j--, p0 -= d) { w1 = w1 << 1; if (i + e < d && p0 < n0 && bn_get_bit(k, p0)) { w1 = w1 | 1; } } ep2_add(r, r, t[w0]); ep2_add(r, r, t[(1 << EP_DEPTH) + w1]); } ep2_norm(r, r); if (bn_sign(k) == RLC_NEG) { ep2_neg(r, r); } } CATCH_ANY { THROW(ERR_CAUGHT); } FINALLY { bn_free(n); } }
void ep2_mul_fix_combs(ep2_t r, ep2_t *t, bn_t k) { int i, j, l, w, n0, p0, p1; bn_t n; if (bn_is_zero(k)) { ep2_set_infty(r); return; } bn_null(n); TRY { bn_new(n); ep2_curve_get_ord(n); l = bn_bits(n); l = ((l % EP_DEPTH) == 0 ? (l / EP_DEPTH) : (l / EP_DEPTH) + 1); n0 = bn_bits(k); p0 = (EP_DEPTH) * l - 1; w = 0; p1 = p0--; for (j = EP_DEPTH - 1; j >= 0; j--, p1 -= l) { w = w << 1; if (p1 < n0 && bn_get_bit(k, p1)) { w = w | 1; } } ep2_copy(r, t[w]); for (i = l - 2; i >= 0; i--) { ep2_dbl(r, r); w = 0; p1 = p0--; for (j = EP_DEPTH - 1; j >= 0; j--, p1 -= l) { w = w << 1; if (p1 < n0 && bn_get_bit(k, p1)) { w = w | 1; } } if (w > 0) { ep2_add(r, r, t[w]); } } ep2_norm(r, r); if (bn_sign(k) == RLC_NEG) { ep2_neg(r, r); } } CATCH_ANY { THROW(ERR_CAUGHT); } FINALLY { bn_free(n); } }
void ed_mul_lwreg(ed_t r, const ed_t p, const bn_t k) { if (bn_is_zero(k) || ed_is_infty(p)) { ed_set_infty(r); return; } ed_mul_reg_imp(r, p, k); }
void bn_neg(bn_t c, const bn_t a) { if (c->dp != a->dp) { bn_copy(c, a); } if (!bn_is_zero(c)) { c->sign = a->sign ^ 1; } }
int bn_is_even(const bn_t a) { if (bn_is_zero(a)) { return 1; } if ((a->dp[0] & 0x01) == 0) { return 1; } return 0; }
int bn_size_str(const bn_t a, int radix) { int digits = 0; bn_t t; bn_null(t); /* Binary case requires the bits, a sign and the null terminator. */ if (radix == 2) { return bn_bits(a) + (a->sign == BN_NEG ? 1 : 0) + 1; } /* Check the radix. */ if (radix < 2 || radix > 64) { THROW(ERR_NO_VALID); } if (bn_is_zero(a)) { return 2; } if (a->sign == BN_NEG) { digits++; } TRY { bn_new(t); bn_copy(t, a); t->sign = BN_POS; while (!bn_is_zero(t)) { bn_div_dig(t, t, (dig_t)radix); digits++; } } CATCH_ANY { THROW(ERR_CAUGHT); } FINALLY { bn_free(t); } return digits + 1; }
void bn_mxp_basic(bn_t c, const bn_t a, const bn_t b, const bn_t m) { int i, l; bn_t t, u, r; if (bn_is_zero(b)) { bn_set_dig(c, 1); return; } bn_null(t); bn_null(u); bn_null(r); TRY { bn_new(t); bn_new(u); bn_new(r); bn_mod_pre(u, m); l = bn_bits(b); #if BN_MOD == MONTY bn_mod_monty_conv(t, a, m); #else bn_copy(t, a); #endif bn_copy(r, t); for (i = l - 2; i >= 0; i--) { bn_sqr(r, r); bn_mod(r, r, m, u); if (bn_get_bit(b, i)) { bn_mul(r, r, t); bn_mod(r, r, m, u); } } #if BN_MOD == MONTY bn_mod_monty_back(c, r, m); #else bn_copy(c, r); #endif } CATCH_ANY { THROW(ERR_CAUGHT); } FINALLY { bn_free(t); bn_free(u); bn_free(r); } }
/** * Applies or removes simple encryption padding. * * @param[out] m - the buffer to pad. * @param[out] p_len - the number of added pad bytes. * @param[in] m_len - the message length in bytes. * @param[in] k_len - the key length in bytes. * @param[in] operation - flag to indicate the operation type. * @return STS_ERR if errors occurred, STS_OK otherwise. */ static int pad_basic(bn_t m, int *p_len, int m_len, int k_len, int operation) { uint8_t pad = 0; int result = STS_OK; bn_t t; TRY { bn_null(t); bn_new(t); switch (operation) { case RSA_ENC: case RSA_SIG: case RSA_SIG_HASH: /* EB = 00 | FF | D. */ bn_zero(m); bn_lsh(m, m, 8); bn_add_dig(m, m, RSA_PAD); /* Make room for the real message. */ bn_lsh(m, m, m_len * 8); break; case RSA_DEC: case RSA_VER: case RSA_VER_HASH: /* EB = 00 | FF | D. */ m_len = k_len - 1; bn_rsh(t, m, 8 * m_len); if (!bn_is_zero(t)) { result = STS_ERR; } *p_len = 1; do { (*p_len)++; m_len--; bn_rsh(t, m, 8 * m_len); pad = (uint8_t)t->dp[0]; } while (pad == 0); if (pad != RSA_PAD) { result = STS_ERR; } bn_mod_2b(m, m, (k_len - *p_len) * 8); break; } } CATCH_ANY { result = STS_ERR; } FINALLY { bn_free(t); } return result; }
void eb_mul_sim_inter(eb_t r, const eb_t p, const bn_t k, const eb_t q, const bn_t m) { if (bn_is_zero(k) || eb_is_infty(p)) { eb_mul(r, q, m); return; } if (bn_is_zero(m) || eb_is_infty(q)) { eb_mul(r, p, k); return; } #if defined(EB_KBLTZ) if (eb_curve_is_kbltz()) { eb_mul_sim_kbltz(r, p, k, q, m, NULL); return; } #endif #if defined(EB_PLAIN) eb_mul_sim_plain(r, p, k, q, m, NULL); #endif }
void ep_mul_sim_inter(ep_t r, const ep_t p, const bn_t k, const ep_t q, const bn_t m) { if (bn_is_zero(k) || ep_is_infty(p)) { ep_mul(r, q, m); return; } if (bn_is_zero(m) || ep_is_infty(q)) { ep_mul(r, p, k); return; } #if defined(EP_ENDOM) if (ep_curve_is_endom()) { ep_mul_sim_endom(r, p, k, q, m, NULL); return; } #endif #if defined(EP_PLAIN) || defined(EP_SUPER) ep_mul_sim_plain(r, p, k, q, m, NULL); #endif }
void ed_mul_monty(ed_t r, const ed_t p, const bn_t k) { ed_t t[2]; ed_null(t[0]); ed_null(t[1]); if (bn_is_zero(k) || ed_is_infty(p)) { ed_set_infty(r); return; } TRY { ed_new(t[0]); ed_new(t[1]); ed_set_infty(t[0]); ed_copy(t[1], p); for (int i = bn_bits(k) - 1; i >= 0; i--) { int j = bn_get_bit(k, i); dv_swap_cond(t[0]->x, t[1]->x, RLC_FP_DIGS, j ^ 1); dv_swap_cond(t[0]->y, t[1]->y, RLC_FP_DIGS, j ^ 1); dv_swap_cond(t[0]->z, t[1]->z, RLC_FP_DIGS, j ^ 1); #if ED_ADD == EXTND dv_swap_cond(t[0]->t, t[1]->t, RLC_FP_DIGS, j ^ 1); #endif ed_add(t[0], t[0], t[1]); ed_dbl(t[1], t[1]); dv_swap_cond(t[0]->x, t[1]->x, RLC_FP_DIGS, j ^ 1); dv_swap_cond(t[0]->y, t[1]->y, RLC_FP_DIGS, j ^ 1); dv_swap_cond(t[0]->z, t[1]->z, RLC_FP_DIGS, j ^ 1); #if ED_ADD == EXTND dv_swap_cond(t[0]->t, t[1]->t, RLC_FP_DIGS, j ^ 1); #endif } ed_norm(r, t[0]); if (bn_sign(k) == RLC_NEG) { ed_neg(r, r); } } CATCH_ANY { THROW(ERR_CAUGHT); } FINALLY { ed_free(t[1]); ed_free(t[0]); } }
int hdnode_from_xprv(uint32_t depth, uint32_t fingerprint, uint32_t child_num, const uint8_t *chain_code, const uint8_t *private_key, HDNode *out) { bignum256 a; bn_read_be(private_key, &a); if (bn_is_zero(&a) || !bn_is_less(&a, &order256k1)) { // == 0 or >= order return 0; } out->depth = depth; out->fingerprint = fingerprint; out->child_num = child_num; memcpy(out->chain_code, chain_code, 32); memcpy(out->private_key, private_key, 32); hdnode_fill_public_key(out); return 1; }
int cp_bdpe_enc(uint8_t *out, int *out_len, dig_t in, bdpe_t pub) { bn_t m, u; int size, result = STS_OK; bn_null(m); bn_null(u); size = bn_size_bin(pub->n); if (in > pub->t) { return STS_ERR; } TRY { bn_new(m); bn_new(u); bn_set_dig(m, in); do { bn_rand(u, BN_POS, bn_bits(pub->n)); bn_mod(u, u, pub->n); } while (bn_is_zero(u)); bn_mxp(m, pub->y, m, pub->n); bn_mxp_dig(u, u, pub->t, pub->n); bn_mul(m, m, u); bn_mod(m, m, pub->n); if (size <= *out_len) { *out_len = size; memset(out, 0, *out_len); bn_write_bin(out, size, m); } else { result = STS_ERR; } } CATCH_ANY { result = STS_ERR; } FINALLY { bn_free(m); bn_free(u); } return result; }
status_t element_div(element_t c, element_t a, element_t b) { GroupType type = a->type; EXIT_IF_NOT_SAME(a, b); LEAVE_IF(a->isInitialized != TRUE || b->isInitialized != TRUE || c->isInitialized != TRUE, "uninitialized arguments."); LEAVE_IF( c->type != type, "result initialized but invalid type."); if(type == ZR) { if(bn_is_zero(b->bn)) return ELEMENT_DIV_ZERO; // c = (1 / b) mod order element_invert(c, b); if(bn_is_one(a->bn)) return ELEMENT_OK; // bn_div(c->bn, a->bn, b->bn); // bn_mod(c->bn, c->bn, c->order); // remainder of ((a * c) / order) integer_t s; bn_inits(s); // c = (a * c) / order (remainder only) bn_mul(s, a->bn, c->bn); bn_div_rem(s, c->bn, s, a->order); // if(bn_sign(c->bn) == BN_NEG) bn_add(c->bn, c->bn, a->order); bn_free(s); } else if(type == G1) { g1_sub(c->g1, a->g1, b->g1); g1_norm(c->g1, c->g1); } else if(type == G2) { g2_sub(c->g2, a->g2, b->g2); g2_norm(c->g2, c->g2); } else if(type == GT) { gt_t t; gt_inits(t); gt_inv(t, b->gt); gt_mul(c->gt, a->gt, t); gt_free(t); } else { return ELEMENT_INVALID_TYPES; } return ELEMENT_OK; }
int hdnode_private_ckd(HDNode *inout, uint32_t i) { uint8_t data[1 + 32 + 4]; uint8_t I[32 + 32]; uint8_t fingerprint[32]; bignum256 a, b; if (i & 0x80000000) { // private derivation data[0] = 0; memcpy(data + 1, inout->private_key, 32); } else { // public derivation memcpy(data, inout->public_key, 33); } write_be(data + 33, i); sha256_Raw(inout->public_key, 33, fingerprint); ripemd160(fingerprint, 32, fingerprint); inout->fingerprint = (fingerprint[0] << 24) + (fingerprint[1] << 16) + (fingerprint[2] << 8) + fingerprint[3]; bn_read_be(inout->private_key, &a); hmac_sha512(inout->chain_code, 32, data, sizeof(data), I); memcpy(inout->chain_code, I + 32, 32); memcpy(inout->private_key, I, 32); bn_read_be(inout->private_key, &b); if (!bn_is_less(&b, &order256k1)) { // >= order return 0; } bn_addmod(&a, &b, &order256k1); if (bn_is_zero(&a)) { return 0; } inout->depth++; inout->child_num = i; bn_write_be(&a, inout->private_key); hdnode_fill_public_key(inout); return 1; }
void bn_div_rem_dig(bn_t c, dig_t *d, const bn_t a, dig_t b) { bn_t q; dig_t r; bn_null(q); if (b == 0) { THROW(ERR_NO_VALID); } if (b == 1 || bn_is_zero(a) == 1) { if (d != NULL) { *d = 0; } if (c != NULL) { bn_copy(c, a); } return; } TRY { bn_new(q); int size = a->used; const dig_t *ap = a->dp; bn_div1_low(q->dp, &r, ap, size, b); if (c != NULL) { q->used = a->used; q->sign = a->sign; bn_trim(q); bn_copy(c, q); } if (d != NULL) { *d = r; } } CATCH_ANY { THROW(ERR_CAUGHT); } FINALLY { bn_free(q); } }
int hdnode_from_seed(const uint8_t *seed, int seed_len, HDNode *out) { uint8_t I[32 + 32]; memset(out, 0, sizeof(HDNode)); out->depth = 0; out->fingerprint = 0x00000000; out->child_num = 0; hmac_sha512((uint8_t *)"Bitcoin seed", 12, seed, seed_len, I); memcpy(out->private_key, I, 32); bignum256 a; bn_read_be(out->private_key, &a); if (bn_is_zero(&a) || !bn_is_less(&a, &order256k1)) { // == 0 or >= order return 0; } memcpy(out->chain_code, I + 32, 32); hdnode_fill_public_key(out); return 1; }