diff --git a/bitcoin/psbt.c b/bitcoin/psbt.c index 3d2253736..b740ef163 100644 --- a/bitcoin/psbt.c +++ b/bitcoin/psbt.c @@ -1,7 +1,10 @@ #include #include +#include #include +#include #include +#include #include #include #include @@ -153,6 +156,66 @@ void psbt_rm_output(struct wally_psbt *psbt, REMOVE_ELEM(psbt->outputs, remove_at, psbt->num_outputs); psbt->num_outputs -= 1; } + +void psbt_input_add_pubkey(struct wally_psbt *psbt, size_t in, + const struct pubkey *pubkey) +{ + int wally_err; + u32 empty_path[1] = {0}; + unsigned char fingerprint[4]; + struct ripemd160 hash; + u8 pk_der[PUBKEY_CMPR_LEN]; + + assert(in < psbt->num_inputs); + + /* Find the key identifier fingerprint: + * the first 32 bits of the identifier, where the identifier + * is the hash160 of the ECDSA serialized public key + * https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki#key-identifiers + * */ + pubkey_to_hash160(pubkey, &hash); + memcpy(fingerprint, hash.u.u8, sizeof(fingerprint)); + + /* we serialize the compressed version of the key, wally likes this */ + pubkey_to_der(pk_der, pubkey); + + if (!psbt->inputs[in].keypaths) + if (wally_keypath_map_init_alloc(1, &psbt->inputs[in].keypaths) != WALLY_OK) + abort(); + + wally_err = wally_add_new_keypath(psbt->inputs[in].keypaths, + pk_der, sizeof(pk_der), + fingerprint, sizeof(fingerprint), + empty_path, ARRAY_SIZE(empty_path)); + + assert(wally_err == WALLY_OK); +} + +void psbt_input_set_partial_sig(struct wally_psbt *psbt, size_t in, + const struct pubkey *pubkey, + const struct bitcoin_signature *sig) +{ + int wally_err; + u8 pk_der[PUBKEY_CMPR_LEN]; + + assert(in < psbt->num_inputs); + if (!psbt->inputs[in].partial_sigs) + if (wally_partial_sigs_map_init_alloc(1, &psbt->inputs[in].partial_sigs) != WALLY_OK) + abort(); + + /* we serialize the compressed version of the key, wally likes this */ + pubkey_to_der(pk_der, pubkey); + wally_err = wally_add_new_partial_sig(psbt->inputs[in].partial_sigs, + pk_der, sizeof(pk_der), + cast_const(unsigned char *, sig->s.data), + sizeof(sig->s.data)); + assert(wally_err == WALLY_OK); + + wally_err = wally_psbt_input_set_sighash_type(&psbt->inputs[in], + sig->sighash_type); + assert(wally_err == WALLY_OK); +} + void psbt_input_set_prev_utxo(struct wally_psbt *psbt, size_t in, const u8 *scriptPubkey, struct amount_sat amt) { diff --git a/bitcoin/psbt.h b/bitcoin/psbt.h index 39d6805f1..43fcfbc57 100644 --- a/bitcoin/psbt.h +++ b/bitcoin/psbt.h @@ -11,6 +11,8 @@ struct wally_psbt; struct wally_psbt_input; struct wally_tx; struct amount_sat; +struct bitcoin_signature; +struct pubkey; int wally_psbt_clone(const struct wally_psbt *psbt, struct wally_psbt **output); @@ -33,6 +35,13 @@ struct wally_psbt_output *psbt_add_output(struct wally_psbt *psbt, void psbt_rm_output(struct wally_psbt *psbt, size_t remove_at); +void psbt_input_add_pubkey(struct wally_psbt *psbt, size_t in, + const struct pubkey *pubkey); + +void psbt_input_set_partial_sig(struct wally_psbt *psbt, size_t in, + const struct pubkey *pubkey, + const struct bitcoin_signature *sig); + void psbt_input_set_prev_utxo(struct wally_psbt *psbt, size_t in, const u8 *wscript, struct amount_sat amt); void psbt_input_set_prev_utxo_wscript(struct wally_psbt *psbt, size_t in, diff --git a/bitcoin/test/run-bitcoin_block_from_hex.c b/bitcoin/test/run-bitcoin_block_from_hex.c index 453bd825f..6cf84bc2f 100644 --- a/bitcoin/test/run-bitcoin_block_from_hex.c +++ b/bitcoin/test/run-bitcoin_block_from_hex.c @@ -58,6 +58,12 @@ bool is_p2wpkh(const u8 *script UNNEEDED, struct bitcoin_address *addr UNNEEDED) /* Generated stub for is_p2wsh */ bool is_p2wsh(const u8 *script UNNEEDED, struct sha256 *addr UNNEEDED) { fprintf(stderr, "is_p2wsh called!\n"); abort(); } +/* Generated stub for pubkey_to_der */ +void pubkey_to_der(u8 der[PUBKEY_CMPR_LEN] UNNEEDED, const struct pubkey *key UNNEEDED) +{ fprintf(stderr, "pubkey_to_der called!\n"); abort(); } +/* Generated stub for pubkey_to_hash160 */ +void pubkey_to_hash160(const struct pubkey *pk UNNEEDED, struct ripemd160 *hash UNNEEDED) +{ fprintf(stderr, "pubkey_to_hash160 called!\n"); abort(); } /* Generated stub for scriptpubkey_p2wsh */ u8 *scriptpubkey_p2wsh(const tal_t *ctx UNNEEDED, const u8 *witnessscript UNNEEDED) { fprintf(stderr, "scriptpubkey_p2wsh called!\n"); abort(); } diff --git a/bitcoin/test/run-tx-encode.c b/bitcoin/test/run-tx-encode.c index 1b5a10c09..6bc269a1d 100644 --- a/bitcoin/test/run-tx-encode.c +++ b/bitcoin/test/run-tx-encode.c @@ -59,6 +59,12 @@ bool is_p2wpkh(const u8 *script UNNEEDED, struct bitcoin_address *addr UNNEEDED) /* Generated stub for is_p2wsh */ bool is_p2wsh(const u8 *script UNNEEDED, struct sha256 *addr UNNEEDED) { fprintf(stderr, "is_p2wsh called!\n"); abort(); } +/* Generated stub for pubkey_to_der */ +void pubkey_to_der(u8 der[PUBKEY_CMPR_LEN] UNNEEDED, const struct pubkey *key UNNEEDED) +{ fprintf(stderr, "pubkey_to_der called!\n"); abort(); } +/* Generated stub for pubkey_to_hash160 */ +void pubkey_to_hash160(const struct pubkey *pk UNNEEDED, struct ripemd160 *hash UNNEEDED) +{ fprintf(stderr, "pubkey_to_hash160 called!\n"); abort(); } /* Generated stub for scriptpubkey_p2wsh */ u8 *scriptpubkey_p2wsh(const tal_t *ctx UNNEEDED, const u8 *witnessscript UNNEEDED) { fprintf(stderr, "scriptpubkey_p2wsh called!\n"); abort(); }