@@ -4422,47 +4422,63 @@ int wally_psbt_get_input_scriptcode(const struct wally_psbt *psbt, size_t index,
44224422 return ret ;
44234423}
44244424
4425- /* Get the input scripts and values for taproot signing.
4426- * Creates a non-value-owning map, avoiding allocating/copying the scripts.
4425+ static void append_signing_data (struct wally_map * m , size_t index ,
4426+ unsigned char * bytes , size_t len )
4427+ {
4428+ if (bytes && len ) {
4429+ m -> items [m -> num_items ].key = NULL ;
4430+ m -> items [m -> num_items ].key_len = index ;
4431+ m -> items [m -> num_items ].value = bytes ;
4432+ m -> items [m -> num_items ].value_len = len ;
4433+ ++ m -> num_items ;
4434+ }
4435+ }
4436+
4437+ /* Get input scripts, assets (if applicable) and values for tx signing.
4438+ * Creates non-owning maps, avoiding allocations/copying.
44274439 */
4428- static int get_scripts_and_values (const struct wally_psbt * psbt ,
4429- struct wally_map * scripts ,
4430- uint64_t * * values )
4440+ static int get_signing_data (const struct wally_psbt * psbt ,
4441+ struct wally_map * scripts ,
4442+ struct wally_map * assets ,
4443+ struct wally_map * values )
44314444{
4432- size_t num_inputs = psbt -> num_inputs , i ;
4433- int ret = WALLY_OK ;
4445+ int ret ;
44344446
4435- wally_clear (scripts , sizeof (scripts ));
4447+ memset (scripts , 0 , sizeof (* scripts ));
4448+ memset (values , 0 , sizeof (* values ));
4449+ if (assets )
4450+ memset (assets , 0 , sizeof (* assets ));
44364451
4437- if (!(* values = wally_malloc (num_inputs * sizeof (uint64_t ))))
4438- return WALLY_ENOMEM ;
4439- if (!(scripts -> items = wally_calloc (num_inputs * sizeof (struct wally_map_item )))) {
4440- ret = WALLY_ENOMEM ;
4441- goto fail ;
4442- }
4443- scripts -> items_allocation_len = num_inputs ;
4452+ ret = wally_map_init (psbt -> num_inputs , NULL , scripts );
4453+ if (ret == WALLY_OK )
4454+ ret = wally_map_init (psbt -> num_inputs , NULL , values );
4455+ if (ret == WALLY_OK && assets )
4456+ ret = wally_map_init (psbt -> num_inputs , NULL , assets );
44444457
4445- for (i = 0 ; i < num_inputs && ret == WALLY_OK ; ++ i ) {
4458+ /* We add all the data we have and let the signing code
4459+ * validate that it is sufficient, since the required data
4460+ * depends on things like the sighash type being signed with.
4461+ */
4462+ for (size_t i = 0 ; i < psbt -> num_inputs && ret == WALLY_OK ; ++ i ) {
44464463 const struct wally_psbt_input * p = psbt -> inputs + i ;
44474464 const struct wally_tx_output * utxo = utxo_from_input (psbt , p );
4448- if (!utxo || !utxo -> script )
4449- ret = WALLY_EINVAL ;
4450- else {
4451- (* values )[i ] = utxo -> satoshi ; /* FIXME: Support for Elements */
4452- /* Add the script to the map without allocating/copying */
4453- scripts -> items [i ].key_len = i ;
4454- scripts -> items [i ].value = utxo -> script ;
4455- scripts -> items [i ].value_len = utxo -> script_len ;
4465+ if (utxo ) {
4466+ /* Add items to maps without allocating/copying */
4467+ append_signing_data (scripts , i , utxo -> script , utxo -> script_len );
4468+ if (assets ) {
4469+ append_signing_data (assets , i , utxo -> asset , utxo -> asset_len );
4470+ append_signing_data (values , i , utxo -> value , utxo -> value_len );
4471+ } else {
4472+ append_signing_data (values , i , (unsigned char * )& utxo -> satoshi ,
4473+ sizeof (utxo -> satoshi ));
4474+ }
44564475 }
44574476 }
4458- if (ret == WALLY_OK )
4459- scripts -> num_items = num_inputs ;
4460- else {
4477+ if (ret != WALLY_OK ) {
44614478 wally_free (scripts -> items ); /* No need to clear the value pointers */
4462- wally_clear (scripts , sizeof (scripts ));
4463- fail :
4464- wally_free (* values );
4465- * values = NULL ;
4479+ wally_free (values -> items );
4480+ if (assets )
4481+ wally_free (assets -> items );
44664482 }
44674483 return ret ;
44684484}
@@ -4473,61 +4489,67 @@ int wally_psbt_get_input_signature_hash(struct wally_psbt *psbt, size_t index,
44734489 uint32_t flags ,
44744490 unsigned char * bytes_out , size_t len )
44754491{
4476- struct wally_map scripts ;
44774492 const struct wally_psbt_input * inp = psbt_get_input (psbt , index );
4478- const bool is_taproot = is_taproot_input (psbt , inp );
4479- uint64_t satoshi , * values = NULL ;
4480- uint32_t sighash , sig_flags ;
4493+ const struct wally_tx_output * utxo = utxo_from_input (psbt , inp );
44814494 size_t is_pset ;
4495+ uint32_t sighash , sig_flags ;
4496+ const bool is_taproot = is_taproot_input (psbt , inp );
44824497 int ret ;
44834498
4484- if (!inp || !tx || flags )
4499+ if (!tx || ! inp || !utxo || flags )
44854500 return WALLY_EINVAL ;
44864501
44874502 if ((ret = wally_psbt_is_elements (psbt , & is_pset )) != WALLY_OK )
44884503 return ret ;
4504+ #ifndef BUILD_ELEMENTS
4505+ if (is_pset )
4506+ return WALLY_EINVAL ; /* Unsupported */
4507+ #endif
44894508
44904509 sighash = inp -> sighash ;
44914510 if (!sighash )
44924511 sighash = is_taproot ? WALLY_SIGHASH_DEFAULT : WALLY_SIGHASH_ALL ;
44934512 else if (sighash & 0xffffff00 )
44944513 return WALLY_EINVAL ;
44954514
4515+ if (is_taproot ) {
4516+ struct wally_map scripts , assets , values ;
4517+ struct wally_map * assets_p = is_pset ? & assets : NULL ;
4518+
4519+ #ifdef BUILD_ELEMENTS
4520+ if (is_pset && mem_is_zero (psbt -> genesis_blockhash , sizeof (psbt -> genesis_blockhash )))
4521+ return WALLY_EINVAL ; /* Genesis blockhash is required for taproot */
4522+ #endif
4523+ ret = get_signing_data (psbt , & scripts , assets_p , & values );
4524+ if (ret == WALLY_OK )
4525+ ret = wally_tx_get_input_signature_hash (tx , index ,
4526+ & scripts , assets_p , & values ,
4527+ NULL , 0 , 0 , WALLY_NO_CODESEPARATOR ,
4528+ NULL , 0 ,
4529+ psbt -> genesis_blockhash , sizeof (psbt -> genesis_blockhash ),
4530+ sighash , WALLY_SIGTYPE_SW_V1 ,
4531+ NULL , bytes_out , len );
4532+
4533+ wally_free (scripts .items ); /* No need to clear the value pointers */
4534+ wally_free (values .items );
4535+ if (assets_p )
4536+ wally_free (assets_p -> items );
4537+ return ret ;
4538+ }
4539+
44964540 sig_flags = inp -> witness_utxo ? WALLY_TX_FLAG_USE_WITNESS : 0 ;
44974541
4498- if (is_pset ) {
4499- const struct wally_tx_output * utxo = utxo_from_input (psbt , inp );
4500- if (!utxo )
4501- return WALLY_EINVAL ; /* Prevout is required */
45024542#ifdef BUILD_ELEMENTS
4543+ if (is_pset )
45034544 return wally_tx_get_elements_signature_hash (tx , index ,
45044545 script , script_len ,
45054546 utxo -> value , utxo -> value_len ,
45064547 sighash , sig_flags , bytes_out ,
45074548 len );
4508- #else
4509- return WALLY_EINVAL ; /* Unsupported */
4510- #endif /* BUILD_ELEMENTS */
4511- }
4512-
4513- if (!is_taproot ) {
4514- satoshi = inp -> witness_utxo ? inp -> witness_utxo -> satoshi : 0 ;
4515- return wally_tx_get_btc_signature_hash (tx , index , script , script_len ,
4516- satoshi , sighash , sig_flags ,
4517- bytes_out , len );
4518- }
4519-
4520- /* Taproot */
4521- if ((ret = get_scripts_and_values (psbt , & scripts , & values )) == WALLY_OK ) {
4522- ret = wally_tx_get_btc_taproot_signature_hash (tx , index , & scripts ,
4523- values , psbt -> num_inputs ,
4524- NULL , 0 , 0 , 0xFFFFFFFF ,
4525- NULL , 0 , sighash , 0 ,
4526- bytes_out , len );
4527- wally_free (values );
4528- wally_free (scripts .items ); /* No need to clear the value pointers */
4529- }
4530- return ret ;
4549+ #endif
4550+ return wally_tx_get_btc_signature_hash (tx , index , script , script_len ,
4551+ utxo -> satoshi , sighash , sig_flags ,
4552+ bytes_out , len );
45314553}
45324554
45334555int wally_psbt_sign_input_bip32 (struct wally_psbt * psbt ,
@@ -4545,7 +4567,7 @@ int wally_psbt_sign_input_bip32(struct wally_psbt *psbt,
45454567 int ret ;
45464568
45474569 if (!inp || !hdkey || hdkey -> priv_key [0 ] != BIP32_FLAG_KEY_PRIVATE ||
4548- (flags & ~EC_FLAGS_ALL ))
4570+ (flags & ~( EC_FLAG_GRIND_R | EC_FLAG_ELEMENTS ) ))
45494571 return WALLY_EINVAL ;
45504572
45514573 /* Find the public key this signature is for */
@@ -4561,24 +4583,25 @@ int wally_psbt_sign_input_bip32(struct wally_psbt *psbt,
45614583 if (ret != WALLY_OK || !pubkey_idx )
45624584 return WALLY_EINVAL ; /* Signing pubkey key not found */
45634585
4564- /* Copy signing key so we can tweak it if needed */
4565- memcpy (signing_key , hdkey -> priv_key + 1 , EC_PRIVATE_KEY_LEN );
4566-
4567- if (is_taproot ) {
4586+ if (!is_taproot ) {
4587+ /* ECDSA: Use untweaked private key. Only grinding flag is relevant */
4588+ memcpy (signing_key , hdkey -> priv_key + 1 , EC_PRIVATE_KEY_LEN );
4589+ flags = EC_FLAG_ECDSA | (flags & EC_FLAG_GRIND_R );
4590+ } else {
45684591 /* Schnorr BIP340: Tweak the private key */
45694592 const struct wally_map_item * p = wally_map_get_integer (& inp -> psbt_fields ,
45704593 PSBT_IN_TAP_MERKLE_ROOT );
45714594 const unsigned char * merkle_root = p ? p -> value : NULL ;
45724595 const size_t merkle_root_len = p ? p -> value_len : 0 ;
4573- ret = wally_ec_private_key_bip341_tweak (signing_key , sizeof (signing_key ),
4596+
4597+ ret = wally_ec_private_key_bip341_tweak (hdkey -> priv_key + 1 , EC_PRIVATE_KEY_LEN ,
45744598 merkle_root , merkle_root_len ,
4575- 0 , signing_key , sizeof (signing_key ));
4599+ flags & EC_FLAG_ELEMENTS ,
4600+ signing_key , sizeof (signing_key ));
45764601 if (ret != WALLY_OK )
45774602 goto done ;
4578- flags = EC_FLAG_SCHNORR ;
4579- } else {
4580- /* ECDSA: Only grinding flag is relevant */
4581- flags = EC_FLAG_ECDSA | (flags & EC_FLAG_GRIND_R );
4603+ /* Only Elements flag is relevant */
4604+ flags = EC_FLAG_SCHNORR | (flags & EC_FLAG_ELEMENTS );
45824605 }
45834606
45844607 sighash = inp -> sighash ;
@@ -4626,12 +4649,18 @@ int wally_psbt_sign_bip32(struct wally_psbt *psbt,
46264649 struct wally_tx * tx ;
46274650
46284651 if (!hdkey || hdkey -> priv_key [0 ] != BIP32_FLAG_KEY_PRIVATE ||
4629- (flags & ~EC_FLAGS_ALL ))
4652+ (flags & ~EC_FLAG_GRIND_R ))
46304653 return WALLY_EINVAL ;
46314654
46324655 if ((ret = psbt_build_tx (psbt , & tx , & is_pset , false)) != WALLY_OK )
46334656 return ret ;
46344657
4658+ #ifdef BUILD_ELEMENTS
4659+ if (is_pset ) {
4660+ flags |= EC_FLAG_ELEMENTS ;
4661+ }
4662+ #endif
4663+
46354664 /* Go through each of the inputs */
46364665 for (i = 0 ; ret == WALLY_OK && i < psbt -> num_inputs ; ++ i ) {
46374666 unsigned char txhash [WALLY_TXHASH_LEN ];
0 commit comments