diff --git a/src/keystore.c b/src/keystore.c index 8d695fcc2..c4fad8f1e 100644 --- a/src/keystore.c +++ b/src/keystore.c @@ -1003,18 +1003,8 @@ bool keystore_secp256k1_schnorr_bip86_sign( bool keystore_secp256k1_get_private_key( const uint32_t* keypath, const size_t keypath_len, - bool tweak_bip86, uint8_t* key_out) { - if (tweak_bip86) { - secp256k1_keypair __attribute__((__cleanup__(_cleanup_keypair))) keypair = {0}; - secp256k1_xonly_pubkey pubkey = {0}; - if (!_schnorr_bip86_keypair(keypath, keypath_len, &keypair, &pubkey)) { - return false; - } - const secp256k1_context* ctx = wally_get_secp_context(); - return secp256k1_keypair_sec(ctx, key_out, &keypair) == 1; - } struct ext_key xprv __attribute__((__cleanup__(keystore_zero_xkey))) = {0}; if (!_get_xprv_twice(keypath, keypath_len, &xprv)) { return false; diff --git a/src/keystore.h b/src/keystore.h index c32287028..5e91c1ac2 100644 --- a/src/keystore.h +++ b/src/keystore.h @@ -308,13 +308,11 @@ USE_RESULT bool keystore_secp256k1_schnorr_bip86_sign( * * @param[in] keypath derivation keypath * @param[in] keypath_len number of elements in keypath - * @param[in] tweak_bip86 if true, the resulting private key is tweaked with the BIP-86 tweak. * @param[out] key_out resulting private key, must be 32 bytes. */ USE_RESULT bool keystore_secp256k1_get_private_key( const uint32_t* keypath, size_t keypath_len, - bool tweak_bip86, uint8_t* key_out); #ifdef TESTING diff --git a/src/rust/bitbox02-rust/src/hww/api/bitcoin/signtx.rs b/src/rust/bitbox02-rust/src/hww/api/bitcoin/signtx.rs index 3023c039a..af30e8b41 100644 --- a/src/rust/bitbox02-rust/src/hww/api/bitcoin/signtx.rs +++ b/src/rust/bitbox02-rust/src/hww/api/bitcoin/signtx.rs @@ -35,6 +35,7 @@ use pb::btc_sign_next_response::Type as NextType; use sha2::{Digest, Sha256}; use bitcoin::hashes::Hash; +use bitcoin::key::TapTweak; use streaming_silent_payments::SilentPayment; @@ -720,13 +721,22 @@ async fn _process(request: &pb::BtcSignInitRequest) -> Result { } if let Some(ref mut silent_payment) = silent_payment { - let private_key = bitcoin::secp256k1::SecretKey::from_slice( - &bitbox02::keystore::secp256k1_get_private_key( - &tx_input.keypath, - is_taproot(script_config_account), - )?, + let keypair = bitcoin::key::UntweakedKeypair::from_seckey_slice( + silent_payment.get_secp(), + &bitbox02::keystore::secp256k1_get_private_key(&tx_input.keypath)?, ) - .map_err(|_| Error::Generic)?; + .unwrap(); + // For Taproot, only key path spends are allowed in silent payments, and we need to + // provide the key path spend private key, which means the internal key plus the tap + // tweak. + let private_key = if is_taproot(script_config_account) { + keypair + .tap_tweak(silent_payment.get_secp(), None) + .to_inner() + .secret_key() + } else { + keypair.secret_key() + }; silent_payment .add_input( diff --git a/src/rust/bitbox02/src/keystore.rs b/src/rust/bitbox02/src/keystore.rs index bcabef8f1..1eac60394 100644 --- a/src/rust/bitbox02/src/keystore.rs +++ b/src/rust/bitbox02/src/keystore.rs @@ -224,16 +224,12 @@ pub fn encode_xpub_at_keypath(keypath: &[u32]) -> Result, ()> { } } -pub fn secp256k1_get_private_key( - keypath: &[u32], - tweak_bip86: bool, -) -> Result>, ()> { +pub fn secp256k1_get_private_key(keypath: &[u32]) -> Result>, ()> { let mut key = zeroize::Zeroizing::new(vec![0u8; 32]); match unsafe { bitbox02_sys::keystore_secp256k1_get_private_key( keypath.as_ptr(), keypath.len() as _, - tweak_bip86, key.as_mut_ptr(), ) } { @@ -558,7 +554,7 @@ mod tests { fn test_secp256k1_get_private_key() { lock(); let keypath = &[84 + HARDENED, 0 + HARDENED, 0 + HARDENED, 0, 0]; - assert!(secp256k1_get_private_key(keypath, false).is_err()); + assert!(secp256k1_get_private_key(keypath).is_err()); mock_unlocked_using_mnemonic( "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about", @@ -566,19 +562,8 @@ mod tests { ); assert_eq!( - hex::encode(secp256k1_get_private_key(keypath, false).unwrap()), + hex::encode(secp256k1_get_private_key(keypath).unwrap()), "4604b4b710fe91f584fff084e1a9159fe4f8408fff380596a604948474ce4fa3" ); - - // See first test vector in - // https://github.com/bitcoin/bips/blob/edffe529056f6dfd33d8f716fb871467c3c09263/bip-0086.mediawiki#test-vectors - // The below privte key's public key is: a60869f0dbcf1dc659c9cecbaf8050135ea9e8cdc487053f1dc6880949dc684c. - assert_eq!( - hex::encode( - secp256k1_get_private_key(&[86 + HARDENED, 0 + HARDENED, 0 + HARDENED, 0, 0], true) - .unwrap() - ), - "eaac016f36e8c18347fbacf05ab7966708fbfce7ce3bf1dc32a09dd0645db038", - ); } } diff --git a/src/rust/streaming-silent-payments/src/lib.rs b/src/rust/streaming-silent-payments/src/lib.rs index 4be2deb85..db712e1cd 100644 --- a/src/rust/streaming-silent-payments/src/lib.rs +++ b/src/rust/streaming-silent-payments/src/lib.rs @@ -169,6 +169,10 @@ impl SilentPayment { } } + pub fn get_secp(&self) -> &Secp256k1 { + &self.secp + } + /// This must be called for *every* input of the transaction. /// /// Important: if the input type cannot be represented by `InputType`, the transaction must be