Skip to content

Commit ed40f3d

Browse files
committed
Merge rust-bitcoin/rust-bitcoin#728: Use un/tweaked public key types
b5bf6d7 Improve rustdocs on schnorr module (Tobin Harding) a6d3514 Return parity when doing tap_tweak (Tobin Harding) 7af0999 Re-name TweakedPublicKey constructor (Tobin Harding) 3c3cf03 Remove use of unreachable in error branch (Tobin Harding) d8e42d1 Remove 'what' comments (Tobin Harding) b60db79 Use un/tweaked public key types (Tobin Harding) 402bd99 Add standard derives to TweakedPublickKey (Tobin Harding) 9c015d9 Add newline to end of file (Tobin Harding) Pull request description: We have two types for tweaked/untweaked schnorr public keys to help users of the taproot API not mix these two keys up. Currently the `taproot` module uses 'raw' `schnoor::PublicKey`s. Use the `schnoor` module's tweak/untweaked public key types for the `taproot` API. Fixes: #725 Please note, I saw this was labeled 'good-first-issue' but I ignored that and greedily implemented a solution because of two reasons 1. We want to get taproot stuff done post haste. 2. I'm struggling to follow what is going on with all the taproot work so this seemed like a way to get my hands dirty. ACKs for top commit: dr-orlovsky: utACK b5bf6d7 sanket1729: ACK b5bf6d7 Tree-SHA512: e3e0480e0d193877c33ac11d0e3a288b0393d9475b26056914e439cb3f19583c1936e70d048df8d2120a36a63b6b592d12e21ca3ab7e058dce6f8f873c3b598b
2 parents 9ae0f05 + b5bf6d7 commit ed40f3d

File tree

3 files changed

+37
-42
lines changed

3 files changed

+37
-42
lines changed

src/util/address.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -527,11 +527,12 @@ impl Address {
527527
merkle_root: Option<TapBranchHash>,
528528
network: Network
529529
) -> Address {
530+
let (output_key, _parity) = internal_key.tap_tweak(secp, merkle_root);
530531
Address {
531532
network: network,
532533
payload: Payload::WitnessProgram {
533534
version: WitnessVersion::V1,
534-
program: internal_key.tap_tweak(secp, merkle_root).into_inner().serialize().to_vec()
535+
program: output_key.into_inner().serialize().to_vec()
535536
}
536537
}
537538
}

src/util/schnorr.rs

Lines changed: 16 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ use util::taproot::{TapBranchHash, TapTweakHash};
2626
pub type UntweakedPublicKey = PublicKey;
2727

2828
/// Tweaked Schnorr public key
29+
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
2930
pub struct TweakedPublicKey(PublicKey);
3031

3132
/// A trait for tweaking Schnorr public keys
@@ -38,26 +39,26 @@ pub trait TapTweak {
3839
/// * H is the hash function
3940
/// * c is the commitment data
4041
/// * G is the generator point
41-
fn tap_tweak<C: Verification>(self, secp: &Secp256k1<C>, merkle_root: Option<TapBranchHash>) -> TweakedPublicKey;
42+
///
43+
/// # Returns
44+
/// The tweaked key and its parity.
45+
fn tap_tweak<C: Verification>(self, secp: &Secp256k1<C>, merkle_root: Option<TapBranchHash>) -> (TweakedPublicKey, bool);
4246

43-
/// Directly convert an UntweakedPublicKey to a TweakedPublicKey
47+
/// Directly converts an [`UntweakedPublicKey`] to a [`TweakedPublicKey`]
4448
///
4549
/// This method is dangerous and can lead to loss of funds if used incorrectly.
4650
/// Specifically, in multi-party protocols a peer can provide a value that allows them to steal.
4751
fn dangerous_assume_tweaked(self) -> TweakedPublicKey;
4852
}
4953

5054
impl TapTweak for UntweakedPublicKey {
51-
fn tap_tweak<C: Verification>(self, secp: &Secp256k1<C>, merkle_root: Option<TapBranchHash>) -> TweakedPublicKey {
52-
// Compute the tweak
55+
fn tap_tweak<C: Verification>(self, secp: &Secp256k1<C>, merkle_root: Option<TapBranchHash>) -> (TweakedPublicKey, bool) {
5356
let tweak_value = TapTweakHash::from_key_and_tweak(self, merkle_root).into_inner();
54-
55-
//Tweak the internal key by the tweak value
5657
let mut output_key = self.clone();
5758
let parity = output_key.tweak_add_assign(&secp, &tweak_value).expect("Tap tweak failed");
58-
if self.tweak_add_check(&secp, &output_key, parity, tweak_value) {
59-
return TweakedPublicKey(output_key);
60-
} else { unreachable!("Tap tweak failed") }
59+
60+
debug_assert!(self.tweak_add_check(&secp, &output_key, parity, tweak_value));
61+
(TweakedPublicKey(output_key), parity)
6162
}
6263

6364
fn dangerous_assume_tweaked(self) -> TweakedPublicKey {
@@ -67,19 +68,20 @@ impl TapTweak for UntweakedPublicKey {
6768

6869

6970
impl TweakedPublicKey {
70-
/// Create a new [TweakedPublicKey] from a [PublicKey]. No tweak is applied.
71-
pub fn new(key: PublicKey) -> TweakedPublicKey {
71+
/// Creates a new [`TweakedPublicKey`] from a [`PublicKey`]. No tweak is applied, consider
72+
/// calling `tap_tweak` on an [`UntweakedPublicKey`] instead of using this constructor.
73+
pub fn dangerous_assume_tweaked(key: PublicKey) -> TweakedPublicKey {
7274
TweakedPublicKey(key)
7375
}
7476

75-
/// Returns the underlying public key
77+
/// Returns the underlying public key.
7678
pub fn into_inner(self) -> PublicKey {
7779
self.0
7880
}
7981

80-
/// Returns a reference to underlying public key
82+
/// Returns a reference to underlying public key.
8183
pub fn as_inner(&self) -> &PublicKey {
8284
&self.0
8385
}
8486

85-
}
87+
}

src/util/taproot.rs

Lines changed: 19 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ use core::cmp::Reverse;
2525
use std::error;
2626

2727
use hashes::{sha256, sha256t, Hash, HashEngine};
28-
use schnorr;
28+
use schnorr::{TweakedPublicKey, UntweakedPublicKey, TapTweak};
2929
use Script;
3030

3131
use consensus::Encodable;
@@ -101,7 +101,7 @@ impl TapTweakHash {
101101
/// Create a new BIP341 [`TapTweakHash`] from key and tweak
102102
/// Produces H_taptweak(P||R) where P is internal key and R is the merkle root
103103
pub fn from_key_and_tweak(
104-
internal_key: schnorr::PublicKey,
104+
internal_key: UntweakedPublicKey,
105105
merkle_root: Option<TapBranchHash>,
106106
) -> TapTweakHash {
107107
let mut eng = TapTweakHash::engine();
@@ -171,13 +171,13 @@ type ScriptMerkleProofMap = BTreeMap<(Script, LeafVersion), BTreeSet<TaprootMerk
171171
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
172172
pub struct TaprootSpendInfo {
173173
/// The BIP341 internal key.
174-
internal_key: schnorr::PublicKey,
174+
internal_key: UntweakedPublicKey,
175175
/// The Merkle root of the script tree (None if there are no scripts)
176176
merkle_root: Option<TapBranchHash>,
177177
/// The sign final output pubkey as per BIP 341
178178
output_key_parity: bool,
179179
/// The tweaked output key
180-
output_key: schnorr::PublicKey,
180+
output_key: TweakedPublicKey,
181181
/// Map from (script, leaf_version) to (sets of) [`TaprootMerkleBranch`].
182182
/// More than one control block for a given script is only possible if it
183183
/// appears in multiple branches of the tree. In all cases, keeping one should
@@ -207,7 +207,7 @@ impl TaprootSpendInfo {
207207
/// 2^32.
208208
pub fn with_huffman_tree<C, I>(
209209
secp: &Secp256k1<C>,
210-
internal_key: schnorr::PublicKey,
210+
internal_key: UntweakedPublicKey,
211211
script_weights: I,
212212
) -> Result<Self, TaprootBuilderError>
213213
where
@@ -253,20 +253,10 @@ impl TaprootSpendInfo {
253253
///
254254
pub fn new_key_spend<C: secp256k1::Verification>(
255255
secp: &Secp256k1<C>,
256-
internal_key: schnorr::PublicKey,
256+
internal_key: UntweakedPublicKey,
257257
merkle_root: Option<TapBranchHash>,
258258
) -> Self {
259-
let tweak = TapTweakHash::from_key_and_tweak(internal_key, merkle_root);
260-
let mut output_key = internal_key;
261-
// # Panics:
262-
//
263-
// This would return Err if the merkle root hash is the negation of the secret
264-
// key corresponding to the internal key.
265-
// Because the tweak is derived as specified in BIP341 (hash output of a function),
266-
// this is unlikely to occur (1/2^128) in real life usage, it is safe to unwrap this
267-
let parity = output_key
268-
.tweak_add_assign(&secp, &tweak)
269-
.expect("TapTweakHash::from_key_and_tweak is broken");
259+
let (output_key, parity) = internal_key.tap_tweak(secp, merkle_root);
270260
Self {
271261
internal_key: internal_key,
272262
merkle_root: merkle_root,
@@ -282,7 +272,7 @@ impl TaprootSpendInfo {
282272
}
283273

284274
/// Obtain the internal key
285-
pub fn internal_key(&self) -> schnorr::PublicKey {
275+
pub fn internal_key(&self) -> UntweakedPublicKey {
286276
self.internal_key
287277
}
288278

@@ -293,7 +283,7 @@ impl TaprootSpendInfo {
293283

294284
/// Output key(the key used in script pubkey) from Spend data. See also
295285
/// [`TaprootSpendInfo::output_key_parity`]
296-
pub fn output_key(&self) -> schnorr::PublicKey {
286+
pub fn output_key(&self) -> TweakedPublicKey {
297287
self.output_key
298288
}
299289

@@ -305,7 +295,7 @@ impl TaprootSpendInfo {
305295
// Internal function to compute [`TaprootSpendInfo`] from NodeInfo
306296
fn from_node_info<C: secp256k1::Verification>(
307297
secp: &Secp256k1<C>,
308-
internal_key: schnorr::PublicKey,
298+
internal_key: UntweakedPublicKey,
309299
node: NodeInfo,
310300
) -> TaprootSpendInfo {
311301
// Create as if it is a key spend path with the given merkle root
@@ -433,7 +423,7 @@ impl TaprootBuilder {
433423
pub fn finalize<C: secp256k1::Verification>(
434424
mut self,
435425
secp: &Secp256k1<C>,
436-
internal_key: schnorr::PublicKey,
426+
internal_key: UntweakedPublicKey,
437427
) -> Result<TaprootSpendInfo, TaprootBuilderError> {
438428
if self.branch.len() > 1 {
439429
return Err(TaprootBuilderError::IncompleteTree);
@@ -655,7 +645,7 @@ pub struct ControlBlock {
655645
/// The parity of the output key (NOT THE INTERNAL KEY WHICH IS ALWAYS XONLY)
656646
pub output_key_parity: bool,
657647
/// The internal key
658-
pub internal_key: schnorr::PublicKey,
648+
pub internal_key: UntweakedPublicKey,
659649
/// The merkle proof of a script associated with this leaf
660650
pub merkle_branch: TaprootMerkleBranch,
661651
}
@@ -677,7 +667,7 @@ impl ControlBlock {
677667
}
678668
let output_key_parity = (sl[0] & 1) == 1;
679669
let leaf_version = LeafVersion::from_u8(sl[0] & TAPROOT_LEAF_MASK)?;
680-
let internal_key = schnorr::PublicKey::from_slice(&sl[1..TAPROOT_CONTROL_BASE_SIZE])
670+
let internal_key = UntweakedPublicKey::from_slice(&sl[1..TAPROOT_CONTROL_BASE_SIZE])
681671
.map_err(TaprootError::InvalidInternalKey)?;
682672
let merkle_branch = TaprootMerkleBranch::from_slice(&sl[TAPROOT_CONTROL_BASE_SIZE..])?;
683673
Ok(ControlBlock {
@@ -722,7 +712,7 @@ impl ControlBlock {
722712
pub fn verify_taproot_commitment<C: secp256k1::Verification>(
723713
&self,
724714
secp: &Secp256k1<C>,
725-
output_key: &schnorr::PublicKey,
715+
output_key: &TweakedPublicKey,
726716
script: &Script,
727717
) -> bool {
728718
// compute the script hash
@@ -746,7 +736,7 @@ impl ControlBlock {
746736
let tweak = TapTweakHash::from_key_and_tweak(self.internal_key, Some(curr_hash));
747737
self.internal_key.tweak_add_check(
748738
secp,
749-
output_key,
739+
output_key.as_inner(),
750740
self.output_key_parity,
751741
tweak.into_inner(),
752742
)
@@ -903,6 +893,7 @@ mod test {
903893
use hashes::{sha256, Hash, HashEngine};
904894
use secp256k1::VerifyOnly;
905895
use core::str::FromStr;
896+
use schnorr;
906897

907898
fn tag_engine(tag_name: &str) -> sha256::HashEngine {
908899
let mut engine = sha256::Hash::engine();
@@ -987,6 +978,7 @@ mod test {
987978

988979
fn _verify_tap_commitments(secp: &Secp256k1<VerifyOnly>, out_spk_hex: &str, script_hex : &str, control_block_hex: &str) {
989980
let out_pk = schnorr::PublicKey::from_str(&out_spk_hex[4..]).unwrap();
981+
let out_pk = TweakedPublicKey::dangerous_assume_tweaked(out_pk);
990982
let script = Script::from_hex(script_hex).unwrap();
991983
let control_block = ControlBlock::from_slice(&Vec::<u8>::from_hex(control_block_hex).unwrap()).unwrap();
992984
assert_eq!(control_block_hex, control_block.serialize().to_hex());
@@ -1028,7 +1020,7 @@ mod test {
10281020
#[test]
10291021
fn build_huffman_tree() {
10301022
let secp = Secp256k1::verification_only();
1031-
let internal_key = schnorr::PublicKey::from_str("93c7378d96518a75448821c4f7c8f4bae7ce60f804d03d1f0628dd5dd0f5de51").unwrap();
1023+
let internal_key = UntweakedPublicKey::from_str("93c7378d96518a75448821c4f7c8f4bae7ce60f804d03d1f0628dd5dd0f5de51").unwrap();
10321024

10331025
let script_weights = vec![
10341026
(10, Script::from_hex("51").unwrap()), // semantics of script don't matter for this test
@@ -1078,7 +1070,7 @@ mod test {
10781070
#[test]
10791071
fn taptree_builder() {
10801072
let secp = Secp256k1::verification_only();
1081-
let internal_key = schnorr::PublicKey::from_str("93c7378d96518a75448821c4f7c8f4bae7ce60f804d03d1f0628dd5dd0f5de51").unwrap();
1073+
let internal_key = UntweakedPublicKey::from_str("93c7378d96518a75448821c4f7c8f4bae7ce60f804d03d1f0628dd5dd0f5de51").unwrap();
10821074

10831075
let builder = TaprootBuilder::new();
10841076
// Create a tree as shown below

0 commit comments

Comments
 (0)