bool bp_key_secret_set(struct bp_key *key, const void *privkey_, size_t pk_len) { bp_key_free(key); if (!privkey_ || pk_len != 32) return false; const unsigned char *privkey = privkey_; BIGNUM *bn = BN_bin2bn(privkey, 32, BN_new()); if (!bn) return false; key->k = EC_KEY_new_by_curve_name(NID_secp256k1); if (!key->k) goto err_out; if (!EC_KEY_regenerate_key(key->k, bn)) goto err_out; if (!EC_KEY_check_key(key->k)) return false; EC_KEY_set_conv_form(key->k, POINT_CONVERSION_COMPRESSED); BN_clear_free(bn); return true; err_out: bp_key_free(key); BN_clear_free(bn); return false; }
static bool bp_checksig(const struct buffer *vchSigIn, const struct buffer *vchPubKey, const cstring *scriptCode, const struct bp_tx *txTo, unsigned int nIn) { if (!vchSigIn || !vchPubKey || !scriptCode || !txTo || !vchSigIn->len || !vchPubKey->len || !scriptCode->len) return false; // Hash type is one byte tacked on to the end of the signature unsigned char *vch_back = vchSigIn->p + (vchSigIn->len - 1); int nHashType = *vch_back; struct buffer vchSig = { vchSigIn->p, vchSigIn->len - 1 }; /* calculate signature hash of transaction */ bu256_t sighash; bp_tx_sighash(&sighash, scriptCode, txTo, nIn, nHashType); /* verify signature hash */ struct bp_key pubkey; bp_key_init(&pubkey); bool rc = false; if (!bp_pubkey_set(&pubkey, vchPubKey->p, vchPubKey->len)) goto out; if (!bp_verify(&pubkey, &sighash, sizeof(sighash), vchSig.p, vchSig.len)) goto out; rc = true; out: bp_key_free(&pubkey); return rc; }
static void g_bp_key_free(gpointer data) { struct bp_key *key = data; if (!key) return; bp_key_free(key); free(key); }
static void keytest() { { struct bp_key k; bp_key_init(&k); bp_key_free(&k); } // Signature { const uint8_t test_secret[32] = { 0x1 }; const uint8_t test_data[] = { 1, 2, 3, 4, 5, 6, 7, 8 }; bu256_t hash; SHA256(test_data, sizeof(test_data), (uint8_t *)&hash); void *pub = NULL; size_t publen = 0; void *sig = NULL; size_t siglen = 0; struct bp_key k; bp_key_init(&k); assert(bp_key_secret_set(&k, test_secret, sizeof(test_secret))); assert(bp_pubkey_get(&k, &pub, &publen)); assert(NULL != pub); assert(0 != publen); assert(bp_sign(&k, (uint8_t *)&hash, sizeof(hash), &sig, &siglen)); assert(NULL != sig); assert(0 != siglen); bp_key_free(&k); struct bp_key pubk; bp_key_init(&k); assert(bp_pubkey_set(&pubk, pub, publen)); assert(bp_verify(&pubk, (uint8_t *)&hash, sizeof(hash), sig, siglen)); bp_key_free(&k); free(pub); free(sig); } }
static void wallet_free_key(void *p) { struct bp_key *key = p; if (!key) return; bp_key_free(key); memset(key, 0, sizeof(*key)); free(key); }
static bool bp_checksig(const struct buffer *vchSigHT, const struct buffer *vchPubKey, const GString *scriptCode, const struct bp_tx *txTo, unsigned int nIn, int nHashType) { if (!vchSigHT || !vchPubKey || !scriptCode || !txTo || !vchSigHT->len || !vchPubKey->len || !scriptCode->len) return false; /* examine hashtype at end of string, then remove it */ unsigned char *vch_back = vchSigHT->p + (vchSigHT->len - 1); if (nHashType == 0) nHashType = *vch_back; else if (nHashType != *vch_back) return false; struct buffer vchSig = { vchSigHT->p, vchSigHT->len - 1 }; /* calculate signature hash of transaction */ bu256_t sighash; bp_tx_sighash(&sighash, scriptCode, txTo, nIn, nHashType); /* verify signature hash */ struct bp_key key; bp_key_init(&key); bool rc = false; if (!bp_pubkey_set(&key, vchPubKey->p, vchPubKey->len)) goto out; if (!bp_verify(&key, &sighash, sizeof(sighash), vchSig.p, vchSig.len)) goto out; rc = true; out: bp_key_free(&key); return rc; }
static bool sign1(const bu160_t *key_id, struct bp_keystore *ks, const bu256_t *hash, int nHashType, cstring *scriptSig) { struct bp_key key; bool rc = false; bp_key_init(&key); /* find private key in keystore */ if (!bkeys_key_get(ks, key_id, &key)) goto out; void *sig = NULL; size_t siglen = 0; /* sign hash with private key */ if (!bp_sign(&key, hash, sizeof(*hash), &sig, &siglen)) goto out; /* append nHashType to signature */ unsigned char ch = (unsigned char) nHashType; sig = realloc(sig, siglen + 1); memcpy(sig + siglen, &ch, 1); siglen++; /* append signature to scriptSig */ bsp_push_data(scriptSig, sig, siglen); free(sig); rc = true; out: bp_key_free(&key); return rc; }
static void runtest(const char *json_base_fn, const char *ser_in_fn, const char *block_in_hash, const char *tx_in_hash) { /* read wallet data */ char *json_fn = test_filename(json_base_fn); json_t *wallet = read_json(json_fn); assert(wallet != NULL); /* read block data containing incoming payment */ char *fn = test_filename(ser_in_fn); void *data; size_t data_len; assert(bu_read_file(fn, &data, &data_len, 1 * 1024 * 1024) == true); struct bp_block block_in; bp_block_init(&block_in); struct const_buffer buf = { data, data_len }; assert(deser_bp_block(&block_in, &buf) == true); bp_block_calc_sha256(&block_in); /* verify block-in data matches expected block-in hash */ bu256_t check_hash; assert(hex_bu256(&check_hash, block_in_hash) == true); assert(bu256_equal(&block_in.sha256, &check_hash) == true); /* load key that has received an incoming payment */ struct bp_key key; assert(bp_key_init(&key) == true); load_json_key(wallet, &key); /* load key into keyset */ struct bp_keyset ks; bpks_init(&ks); assert(bpks_add(&ks, &key) == true); /* find key matches in block */ parr *matches; matches = bp_block_match(&block_in, &ks); assert(matches != NULL); assert(matches->len == 1); struct bp_block_match *match = parr_idx(matches, 0); assert(match->n == 1); /* match 2nd tx, index 1 */ /* get matching transaction */ struct bp_tx *tx = parr_idx(block_in.vtx, match->n); bp_tx_calc_sha256(tx); /* verify txid matches expected */ char tx_hexstr[BU256_STRSZ]; bu256_hex(tx_hexstr, &tx->sha256); assert(strcmp(tx_hexstr, tx_in_hash) == 0); /* verify mask matches 2nd txout (1 << 1) */ BIGNUM tmp_mask; BN_init(&tmp_mask); BN_one(&tmp_mask); BN_lshift(&tmp_mask, &tmp_mask, 1); assert(BN_cmp(&tmp_mask, &match->mask) == 0); /* build merkle tree, tx's branch */ parr *mtree = bp_block_merkle_tree(&block_in); assert(mtree != NULL); parr *mbranch = bp_block_merkle_branch(&block_in, mtree, match->n); assert(mbranch != NULL); /* verify merkle branch for tx matches expected */ bu256_t mrk_check; bp_check_merkle_branch(&mrk_check, &tx->sha256, mbranch, match->n); assert(bu256_equal(&mrk_check, &block_in.hashMerkleRoot) == true); /* release resources */ parr_free(mtree, true); parr_free(mbranch, true); BN_clear_free(&tmp_mask); parr_free(matches, true); bpks_free(&ks); bp_key_free(&key); bp_block_free(&block_in); json_decref(wallet); free(data); free(fn); free(json_fn); }
static void runtest(void) { unsigned int i; struct bp_key keys[4]; /* generate keys */ for (i = 0; i < ARRAY_SIZE(keys); i++) { struct bp_key *key = &keys[i]; assert(bp_key_init(key) == true); assert(bp_key_generate(key) == true); } struct bp_keyset ks; bpks_init(&ks); /* add all but one to keyset */ for (i = 0; i < (ARRAY_SIZE(keys) - 1); i++) assert(bpks_add(&ks, &keys[i]) == true); /* verify all-but-one are in keyset */ for (i = 0; i < (ARRAY_SIZE(keys) - 1); i++) { unsigned char md160[RIPEMD160_DIGEST_LENGTH]; void *pubkey; size_t pklen; assert(bp_pubkey_get(&keys[i], &pubkey, &pklen) == true); bu_Hash160(md160, pubkey, pklen); assert(bpks_lookup(&ks, pubkey, pklen, true) == false); assert(bpks_lookup(&ks, pubkey, pklen, false) == true); assert(bpks_lookup(&ks, md160, sizeof(md160), true) == true); assert(bpks_lookup(&ks, md160, sizeof(md160), false) == false); free(pubkey); } /* verify last key not in keyset */ { unsigned char md160[RIPEMD160_DIGEST_LENGTH]; void *pubkey; size_t pklen; struct bp_key *key = &keys[ARRAY_SIZE(keys) - 1]; assert(bp_pubkey_get(key, &pubkey, &pklen) == true); bu_Hash160(md160, pubkey, pklen); assert(bpks_lookup(&ks, pubkey, pklen, true) == false); assert(bpks_lookup(&ks, pubkey, pklen, false) == false); assert(bpks_lookup(&ks, md160, sizeof(md160), true) == false); assert(bpks_lookup(&ks, md160, sizeof(md160), false) == false); free(pubkey); } bpks_free(&ks); for (i = 0; i < ARRAY_SIZE(keys); i++) { struct bp_key *key = &keys[i]; bp_key_free(key); } }