Move taproot keys to the keys module

We have a keys module, taproot keys should live in there.
This commit is contained in:
Tobin C. Harding 2023-02-01 09:32:04 +11:00
parent c5fe315a93
commit 7e4da3c0ab
No known key found for this signature in database
GPG Key ID: 40BF9E4C269D6607
8 changed files with 220 additions and 224 deletions

View File

@ -82,17 +82,16 @@ use bitcoin::bip32::{ChildNumber, DerivationPath, ExtendedPrivKey, ExtendedPubKe
use bitcoin::consensus::encode;
use bitcoin::constants::COIN_VALUE;
use bitcoin::hashes::Hash;
use bitcoin::key::XOnlyPublicKey;
use bitcoin::key::{TapTweak, XOnlyPublicKey};
use bitcoin::opcodes::all::{OP_CHECKSIG, OP_CLTV, OP_DROP};
use bitcoin::psbt::{self, Input, Output, Psbt, PsbtSighashType};
use bitcoin::schnorr::{self, TapTweak};
use bitcoin::secp256k1::{Message, Secp256k1};
use bitcoin::sighash::{self, SchnorrSighashType, SighashCache};
use bitcoin::taproot::{
LeafVersion, TapLeafHash, TapSighashHash, TaprootBuilder, TaprootSpendInfo,
};
use bitcoin::{
absolute, script, Address, Amount, Network, OutPoint, ScriptBuf, Transaction, TxIn, TxOut, Witness,
absolute, script, schnorr, Address, Amount, Network, OutPoint, ScriptBuf, Transaction, TxIn, TxOut, Witness,
};
fn main() -> Result<(), Box<dyn std::error::Error>> {

View File

@ -44,8 +44,7 @@ use crate::blockdata::constants::{
use crate::blockdata::opcodes;
use crate::blockdata::opcodes::all::*;
use crate::blockdata::script::{self, Instruction, Script, ScriptBuf, PushBytes, PushBytesBuf, PushBytesErrorReport};
use crate::crypto::key::PublicKey;
use crate::crypto::schnorr::{TapTweak, TweakedPublicKey, UntweakedPublicKey};
use crate::crypto::key::{PublicKey, TapTweak, TweakedPublicKey, UntweakedPublicKey};
use crate::error::ParseIntError;
use crate::hash_types::{PubkeyHash, ScriptHash};
use crate::hashes::{sha256, Hash, HashEngine};

View File

@ -17,10 +17,9 @@ use crate::blockdata::script::Error;
use crate::consensus::Encodable;
use crate::hash_types::{ScriptHash, WScriptHash};
use crate::hashes::Hash;
use crate::key::PublicKey;
use crate::key::{PublicKey, UntweakedPublicKey};
use crate::policy::DUST_RELAY_TX_FEE;
use crate::prelude::*;
use crate::schnorr::UntweakedPublicKey;
use crate::taproot::{LeafVersion, TapNodeHash, TapLeafHash};
/// Bitcoin script slice.

View File

@ -11,9 +11,8 @@ use crate::blockdata::opcodes::{self, all::*};
use crate::blockdata::script::{opcode_to_verify, Builder, Instruction, Script, PushBytes};
use crate::hashes::hex;
use crate::hash_types::{PubkeyHash, WPubkeyHash, ScriptHash, WScriptHash};
use crate::key::PublicKey;
use crate::key::{PublicKey, TapTweak, TweakedPublicKey, UntweakedPublicKey};
use crate::prelude::*;
use crate::schnorr::{TapTweak, TweakedPublicKey, UntweakedPublicKey};
use crate::taproot::TapNodeHash;
/// An owned, growable script.

View File

@ -12,12 +12,14 @@ use core::{ops, str::FromStr};
use core::fmt::{self, Write};
use bitcoin_internals::write_err;
pub use secp256k1::{self, Secp256k1, XOnlyPublicKey, KeyPair};
pub use secp256k1::{self, constants, Secp256k1, KeyPair, XOnlyPublicKey, Verification, Parity};
use crate::{base58, io};
use crate::network::constants::Network;
use crate::hashes::{Hash, hash160, hex, hex::FromHex};
use crate::hash_types::{PubkeyHash, WPubkeyHash};
use crate::taproot::{TapNodeHash, TapTweakHash};
/// A key-related error.
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
@ -546,6 +548,215 @@ impl<'de> serde::Deserialize<'de> for PublicKey {
}
}
/// Untweaked BIP-340 X-coord-only public key
pub type UntweakedPublicKey = XOnlyPublicKey;
/// Tweaked BIP-340 X-coord-only public key
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "serde", serde(crate = "actual_serde"))]
#[cfg_attr(feature = "serde", serde(transparent))]
pub struct TweakedPublicKey(XOnlyPublicKey);
impl fmt::LowerHex for TweakedPublicKey {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
fmt::LowerHex::fmt(&self.0, f)
}
}
impl fmt::Display for TweakedPublicKey {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
fmt::Display::fmt(&self.0, f)
}
}
/// Untweaked BIP-340 key pair
pub type UntweakedKeyPair = KeyPair;
/// Tweaked BIP-340 key pair
///
/// # Examples
/// ```
/// # #[cfg(feature = "rand-std")] {
/// # use bitcoin::crypto::key::{KeyPair, TweakedKeyPair, TweakedPublicKey};
/// # use bitcoin::secp256k1::{rand, Secp256k1};
/// # let secp = Secp256k1::new();
/// # let keypair = TweakedKeyPair::dangerous_assume_tweaked(KeyPair::new(&secp, &mut rand::thread_rng()));
/// // There are various conversion methods available to get a tweaked pubkey from a tweaked keypair.
/// let (_pk, _parity) = keypair.public_parts();
/// let _pk = TweakedPublicKey::from_keypair(keypair);
/// let _pk = TweakedPublicKey::from(keypair);
/// # }
/// ```
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "serde", serde(crate = "actual_serde"))]
#[cfg_attr(feature = "serde", serde(transparent))]
pub struct TweakedKeyPair(KeyPair);
/// A trait for tweaking BIP340 key types (x-only public keys and key pairs).
pub trait TapTweak {
/// Tweaked key type with optional auxiliary information
type TweakedAux;
/// Tweaked key type
type TweakedKey;
/// Tweaks an untweaked key with corresponding public key value and optional script tree merkle
/// root. For the [`KeyPair`] type this also tweaks the private key in the pair.
///
/// This is done by using the equation Q = P + H(P|c)G, where
/// * Q is the tweaked public key
/// * P is the internal public key
/// * H is the hash function
/// * c is the commitment data
/// * G is the generator point
///
/// # Returns
/// The tweaked key and its parity.
fn tap_tweak<C: Verification>(self, secp: &Secp256k1<C>, merkle_root: Option<TapNodeHash>) -> Self::TweakedAux;
/// Directly converts an [`UntweakedPublicKey`] to a [`TweakedPublicKey`]
///
/// This method is dangerous and can lead to loss of funds if used incorrectly.
/// Specifically, in multi-party protocols a peer can provide a value that allows them to steal.
fn dangerous_assume_tweaked(self) -> Self::TweakedKey;
}
impl TapTweak for UntweakedPublicKey {
type TweakedAux = (TweakedPublicKey, Parity);
type TweakedKey = TweakedPublicKey;
/// Tweaks an untweaked public key with corresponding public key value and optional script tree
/// merkle root.
///
/// This is done by using the equation Q = P + H(P|c)G, where
/// * Q is the tweaked public key
/// * P is the internal public key
/// * H is the hash function
/// * c is the commitment data
/// * G is the generator point
///
/// # Returns
/// The tweaked key and its parity.
fn tap_tweak<C: Verification>(self, secp: &Secp256k1<C>, merkle_root: Option<TapNodeHash>) -> (TweakedPublicKey, Parity) {
let tweak = TapTweakHash::from_key_and_tweak(self, merkle_root).to_scalar();
let (output_key, parity) = self.add_tweak(secp, &tweak).expect("Tap tweak failed");
debug_assert!(self.tweak_add_check(secp, &output_key, parity, tweak));
(TweakedPublicKey(output_key), parity)
}
fn dangerous_assume_tweaked(self) -> TweakedPublicKey {
TweakedPublicKey(self)
}
}
impl TapTweak for UntweakedKeyPair {
type TweakedAux = TweakedKeyPair;
type TweakedKey = TweakedKeyPair;
/// Tweaks private and public keys within an untweaked [`KeyPair`] with corresponding public key
/// value and optional script tree merkle root.
///
/// This is done by tweaking private key within the pair using the equation q = p + H(P|c), where
/// * q is the tweaked private key
/// * p is the internal private key
/// * H is the hash function
/// * c is the commitment data
/// The public key is generated from a private key by multiplying with generator point, Q = qG.
///
/// # Returns
/// The tweaked key and its parity.
fn tap_tweak<C: Verification>(self, secp: &Secp256k1<C>, merkle_root: Option<TapNodeHash>) -> TweakedKeyPair {
let (pubkey, _parity) = XOnlyPublicKey::from_keypair(&self);
let tweak = TapTweakHash::from_key_and_tweak(pubkey, merkle_root).to_scalar();
let tweaked = self.add_xonly_tweak(secp, &tweak).expect("Tap tweak failed");
TweakedKeyPair(tweaked)
}
fn dangerous_assume_tweaked(self) -> TweakedKeyPair {
TweakedKeyPair(self)
}
}
impl TweakedPublicKey {
/// Returns the [`TweakedPublicKey`] for `keypair`.
#[inline]
pub fn from_keypair(keypair: TweakedKeyPair) -> Self {
let (xonly, _parity) = keypair.0.x_only_public_key();
TweakedPublicKey(xonly)
}
/// Creates a new [`TweakedPublicKey`] from a [`XOnlyPublicKey`]. No tweak is applied, consider
/// calling `tap_tweak` on an [`UntweakedPublicKey`] instead of using this constructor.
///
/// This method is dangerous and can lead to loss of funds if used incorrectly.
/// Specifically, in multi-party protocols a peer can provide a value that allows them to steal.
#[inline]
pub fn dangerous_assume_tweaked(key: XOnlyPublicKey) -> TweakedPublicKey {
TweakedPublicKey(key)
}
/// Returns the underlying public key.
pub fn to_inner(self) -> XOnlyPublicKey {
self.0
}
/// Serialize the key as a byte-encoded pair of values. In compressed form
/// the y-coordinate is represented by only a single bit, as x determines
/// it up to one bit.
#[inline]
pub fn serialize(&self) -> [u8; constants::SCHNORR_PUBLIC_KEY_SIZE] {
self.0.serialize()
}
}
impl TweakedKeyPair {
/// Creates a new [`TweakedKeyPair`] from a [`KeyPair`]. No tweak is applied, consider
/// calling `tap_tweak` on an [`UntweakedKeyPair`] instead of using this constructor.
///
/// This method is dangerous and can lead to loss of funds if used incorrectly.
/// Specifically, in multi-party protocols a peer can provide a value that allows them to steal.
#[inline]
pub fn dangerous_assume_tweaked(pair: KeyPair) -> TweakedKeyPair {
TweakedKeyPair(pair)
}
/// Returns the underlying key pair.
#[inline]
pub fn to_inner(self) -> KeyPair {
self.0
}
/// Returns the [`TweakedPublicKey`] and its [`Parity`] for this [`TweakedKeyPair`].
#[inline]
pub fn public_parts(&self) -> (TweakedPublicKey, Parity) {
let (xonly, parity) = self.0.x_only_public_key();
(TweakedPublicKey(xonly), parity)
}
}
impl From<TweakedPublicKey> for XOnlyPublicKey {
#[inline]
fn from(pair: TweakedPublicKey) -> Self {
pair.0
}
}
impl From<TweakedKeyPair> for KeyPair {
#[inline]
fn from(pair: TweakedKeyPair) -> Self {
pair.0
}
}
impl From<TweakedKeyPair> for TweakedPublicKey {
#[inline]
fn from(pair: TweakedKeyPair) -> Self {
TweakedPublicKey::from_keypair(pair)
}
}
#[cfg(test)]
mod tests {
use super::*;

View File

@ -15,218 +15,8 @@ pub use secp256k1::{self, constants, Secp256k1, KeyPair, XOnlyPublicKey, Verific
use crate::prelude::*;
use crate::taproot::{TapNodeHash, TapTweakHash};
use crate::sighash::SchnorrSighashType;
/// Untweaked BIP-340 X-coord-only public key
pub type UntweakedPublicKey = XOnlyPublicKey;
/// Tweaked BIP-340 X-coord-only public key
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "serde", serde(crate = "actual_serde"))]
#[cfg_attr(feature = "serde", serde(transparent))]
pub struct TweakedPublicKey(XOnlyPublicKey);
impl fmt::LowerHex for TweakedPublicKey {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
fmt::LowerHex::fmt(&self.0, f)
}
}
impl fmt::Display for TweakedPublicKey {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
fmt::Display::fmt(&self.0, f)
}
}
/// Untweaked BIP-340 key pair
pub type UntweakedKeyPair = KeyPair;
/// Tweaked BIP-340 key pair
///
/// # Examples
/// ```
/// # #[cfg(feature = "rand-std")] {
/// # use bitcoin::schnorr::{KeyPair, TweakedKeyPair, TweakedPublicKey};
/// # use bitcoin::secp256k1::{rand, Secp256k1};
/// # let secp = Secp256k1::new();
/// # let keypair = TweakedKeyPair::dangerous_assume_tweaked(KeyPair::new(&secp, &mut rand::thread_rng()));
/// // There are various conversion methods available to get a tweaked pubkey from a tweaked keypair.
/// let (_pk, _parity) = keypair.public_parts();
/// let _pk = TweakedPublicKey::from_keypair(keypair);
/// let _pk = TweakedPublicKey::from(keypair);
/// # }
/// ```
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "serde", serde(crate = "actual_serde"))]
#[cfg_attr(feature = "serde", serde(transparent))]
pub struct TweakedKeyPair(KeyPair);
/// A trait for tweaking BIP340 key types (x-only public keys and key pairs).
pub trait TapTweak {
/// Tweaked key type with optional auxiliary information
type TweakedAux;
/// Tweaked key type
type TweakedKey;
/// Tweaks an untweaked key with corresponding public key value and optional script tree merkle
/// root. For the [`KeyPair`] type this also tweaks the private key in the pair.
///
/// This is done by using the equation Q = P + H(P|c)G, where
/// * Q is the tweaked public key
/// * P is the internal public key
/// * H is the hash function
/// * c is the commitment data
/// * G is the generator point
///
/// # Returns
/// The tweaked key and its parity.
fn tap_tweak<C: Verification>(self, secp: &Secp256k1<C>, merkle_root: Option<TapNodeHash>) -> Self::TweakedAux;
/// Directly converts an [`UntweakedPublicKey`] to a [`TweakedPublicKey`]
///
/// This method is dangerous and can lead to loss of funds if used incorrectly.
/// Specifically, in multi-party protocols a peer can provide a value that allows them to steal.
fn dangerous_assume_tweaked(self) -> Self::TweakedKey;
}
impl TapTweak for UntweakedPublicKey {
type TweakedAux = (TweakedPublicKey, Parity);
type TweakedKey = TweakedPublicKey;
/// Tweaks an untweaked public key with corresponding public key value and optional script tree
/// merkle root.
///
/// This is done by using the equation Q = P + H(P|c)G, where
/// * Q is the tweaked public key
/// * P is the internal public key
/// * H is the hash function
/// * c is the commitment data
/// * G is the generator point
///
/// # Returns
/// The tweaked key and its parity.
fn tap_tweak<C: Verification>(self, secp: &Secp256k1<C>, merkle_root: Option<TapNodeHash>) -> (TweakedPublicKey, Parity) {
let tweak = TapTweakHash::from_key_and_tweak(self, merkle_root).to_scalar();
let (output_key, parity) = self.add_tweak(secp, &tweak).expect("Tap tweak failed");
debug_assert!(self.tweak_add_check(secp, &output_key, parity, tweak));
(TweakedPublicKey(output_key), parity)
}
fn dangerous_assume_tweaked(self) -> TweakedPublicKey {
TweakedPublicKey(self)
}
}
impl TapTweak for UntweakedKeyPair {
type TweakedAux = TweakedKeyPair;
type TweakedKey = TweakedKeyPair;
/// Tweaks private and public keys within an untweaked [`KeyPair`] with corresponding public key
/// value and optional script tree merkle root.
///
/// This is done by tweaking private key within the pair using the equation q = p + H(P|c), where
/// * q is the tweaked private key
/// * p is the internal private key
/// * H is the hash function
/// * c is the commitment data
/// The public key is generated from a private key by multiplying with generator point, Q = qG.
///
/// # Returns
/// The tweaked key and its parity.
fn tap_tweak<C: Verification>(self, secp: &Secp256k1<C>, merkle_root: Option<TapNodeHash>) -> TweakedKeyPair {
let (pubkey, _parity) = XOnlyPublicKey::from_keypair(&self);
let tweak = TapTweakHash::from_key_and_tweak(pubkey, merkle_root).to_scalar();
let tweaked = self.add_xonly_tweak(secp, &tweak).expect("Tap tweak failed");
TweakedKeyPair(tweaked)
}
fn dangerous_assume_tweaked(self) -> TweakedKeyPair {
TweakedKeyPair(self)
}
}
impl TweakedPublicKey {
/// Returns the [`TweakedPublicKey`] for `keypair`.
#[inline]
pub fn from_keypair(keypair: TweakedKeyPair) -> Self {
let (xonly, _parity) = keypair.0.x_only_public_key();
TweakedPublicKey(xonly)
}
/// Creates a new [`TweakedPublicKey`] from a [`XOnlyPublicKey`]. No tweak is applied, consider
/// calling `tap_tweak` on an [`UntweakedPublicKey`] instead of using this constructor.
///
/// This method is dangerous and can lead to loss of funds if used incorrectly.
/// Specifically, in multi-party protocols a peer can provide a value that allows them to steal.
#[inline]
pub fn dangerous_assume_tweaked(key: XOnlyPublicKey) -> TweakedPublicKey {
TweakedPublicKey(key)
}
/// Returns the underlying public key.
pub fn to_inner(self) -> XOnlyPublicKey {
self.0
}
/// Serialize the key as a byte-encoded pair of values. In compressed form
/// the y-coordinate is represented by only a single bit, as x determines
/// it up to one bit.
#[inline]
pub fn serialize(&self) -> [u8; constants::SCHNORR_PUBLIC_KEY_SIZE] {
self.0.serialize()
}
}
impl TweakedKeyPair {
/// Creates a new [`TweakedKeyPair`] from a [`KeyPair`]. No tweak is applied, consider
/// calling `tap_tweak` on an [`UntweakedKeyPair`] instead of using this constructor.
///
/// This method is dangerous and can lead to loss of funds if used incorrectly.
/// Specifically, in multi-party protocols a peer can provide a value that allows them to steal.
#[inline]
pub fn dangerous_assume_tweaked(pair: KeyPair) -> TweakedKeyPair {
TweakedKeyPair(pair)
}
/// Returns the underlying key pair.
#[inline]
pub fn to_inner(self) -> KeyPair {
self.0
}
/// Returns the [`TweakedPublicKey`] and its [`Parity`] for this [`TweakedKeyPair`].
#[inline]
pub fn public_parts(&self) -> (TweakedPublicKey, Parity) {
let (xonly, parity) = self.0.x_only_public_key();
(TweakedPublicKey(xonly), parity)
}
}
impl From<TweakedPublicKey> for XOnlyPublicKey {
#[inline]
fn from(pair: TweakedPublicKey) -> Self {
pair.0
}
}
impl From<TweakedKeyPair> for KeyPair {
#[inline]
fn from(pair: TweakedKeyPair) -> Self {
pair.0
}
}
impl From<TweakedKeyPair> for TweakedPublicKey {
#[inline]
fn from(pair: TweakedKeyPair) -> Self {
TweakedPublicKey::from_keypair(pair)
}
}
/// A BIP340-341 serialized schnorr signature with the corresponding hash type.
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]

View File

@ -13,7 +13,7 @@ use bitcoin_internals::write_err;
use secp256k1::{self, Scalar, Secp256k1};
use crate::consensus::Encodable;
use crate::crypto::schnorr::{TapTweak, TweakedPublicKey, UntweakedPublicKey, XOnlyPublicKey};
use crate::crypto::key::{TapTweak, TweakedPublicKey, UntweakedPublicKey, XOnlyPublicKey};
use crate::hashes::{sha256t_hash_newtype, Hash, HashEngine};
use crate::prelude::*;
use crate::{io, Script, ScriptBuf};
@ -1145,7 +1145,6 @@ mod test {
use secp256k1::{VerifyOnly, XOnlyPublicKey};
use super::*;
use crate::crypto::schnorr::TapTweak;
use crate::hashes::hex::FromHex;
use crate::hashes::sha256t::Tag;
use crate::hashes::{sha256, Hash, HashEngine};

View File

@ -30,15 +30,15 @@ use bitcoin::bip32::{ChildNumber, ExtendedPrivKey, ExtendedPubKey, KeySource};
use bitcoin::blockdata::locktime::{absolute, relative};
use bitcoin::blockdata::witness::Witness;
use bitcoin::consensus::encode::deserialize;
use bitcoin::crypto::key::UntweakedPublicKey;
use bitcoin::hashes::hex::FromHex;
use bitcoin::hashes::{hash160, ripemd160, sha256, sha256d, Hash};
use bitcoin::psbt::raw::{self, Key, Pair, ProprietaryKey};
use bitcoin::psbt::{Input, Output, Psbt, PsbtSighashType};
use bitcoin::schnorr::{self, UntweakedPublicKey};
use bitcoin::sighash::{EcdsaSighashType, SchnorrSighashType};
use bitcoin::taproot::{ControlBlock, LeafVersion, TaprootBuilder, TaprootSpendInfo};
use bitcoin::{
ecdsa, Address, Block, Network, OutPoint, PrivateKey, PublicKey, ScriptBuf, Sequence, Target,
ecdsa, schnorr, Address, Block, Network, OutPoint, PrivateKey, PublicKey, ScriptBuf, Sequence, Target,
Transaction, TxIn, TxOut, Txid, Work,
};
use secp256k1::Secp256k1;