refactor(signer): Remove trait ComputeSighash
This commit is contained in:
parent
6dab68d35b
commit
f2a2dae84c
@ -99,7 +99,7 @@ use miniscript::descriptor::{
|
|||||||
Descriptor, DescriptorMultiXKey, DescriptorPublicKey, DescriptorSecretKey, DescriptorXKey,
|
Descriptor, DescriptorMultiXKey, DescriptorPublicKey, DescriptorSecretKey, DescriptorXKey,
|
||||||
InnerXKey, KeyMap, SinglePriv, SinglePubKey,
|
InnerXKey, KeyMap, SinglePriv, SinglePubKey,
|
||||||
};
|
};
|
||||||
use miniscript::{Legacy, Segwitv0, SigType, Tap, ToPublicKey};
|
use miniscript::{SigType, ToPublicKey};
|
||||||
|
|
||||||
use super::utils::SecpCtx;
|
use super::utils::SecpCtx;
|
||||||
use crate::descriptor::{DescriptorMeta, XKeyUtils};
|
use crate::descriptor::{DescriptorMeta, XKeyUtils};
|
||||||
@ -481,7 +481,7 @@ impl InputSigner for SignerWrapper<PrivateKey> {
|
|||||||
&& sign_options.sign_with_tap_internal_key
|
&& sign_options.sign_with_tap_internal_key
|
||||||
&& x_only_pubkey == psbt_internal_key
|
&& x_only_pubkey == psbt_internal_key
|
||||||
{
|
{
|
||||||
let (hash, hash_ty) = Tap::sighash(psbt, input_index, None)?;
|
let (hash, hash_ty) = compute_tap_sighash(psbt, input_index, None)?;
|
||||||
sign_psbt_schnorr(
|
sign_psbt_schnorr(
|
||||||
&self.inner,
|
&self.inner,
|
||||||
x_only_pubkey,
|
x_only_pubkey,
|
||||||
@ -516,7 +516,7 @@ impl InputSigner for SignerWrapper<PrivateKey> {
|
|||||||
.cloned()
|
.cloned()
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
for lh in leaf_hashes {
|
for lh in leaf_hashes {
|
||||||
let (hash, hash_ty) = Tap::sighash(psbt, input_index, Some(lh))?;
|
let (hash, hash_ty) = compute_tap_sighash(psbt, input_index, Some(lh))?;
|
||||||
sign_psbt_schnorr(
|
sign_psbt_schnorr(
|
||||||
&self.inner,
|
&self.inner,
|
||||||
x_only_pubkey,
|
x_only_pubkey,
|
||||||
@ -538,12 +538,12 @@ impl InputSigner for SignerWrapper<PrivateKey> {
|
|||||||
|
|
||||||
let (hash, hash_ty) = match self.ctx {
|
let (hash, hash_ty) = match self.ctx {
|
||||||
SignerContext::Segwitv0 => {
|
SignerContext::Segwitv0 => {
|
||||||
let (h, t) = Segwitv0::sighash(psbt, input_index, ())?;
|
let (h, t) = compute_segwitv0_sighash(psbt, input_index)?;
|
||||||
let h = h.to_raw_hash();
|
let h = h.to_raw_hash();
|
||||||
(h, t)
|
(h, t)
|
||||||
}
|
}
|
||||||
SignerContext::Legacy => {
|
SignerContext::Legacy => {
|
||||||
let (h, t) = Legacy::sighash(psbt, input_index, ())?;
|
let (h, t) = compute_legacy_sighash(psbt, input_index)?;
|
||||||
let h = h.to_raw_hash();
|
let h = h.to_raw_hash();
|
||||||
(h, t)
|
(h, t)
|
||||||
}
|
}
|
||||||
@ -853,198 +853,165 @@ impl Default for SignOptions {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) trait ComputeSighash {
|
/// Computes the legacy sighash.
|
||||||
type Extra;
|
fn compute_legacy_sighash(
|
||||||
type Sighash;
|
psbt: &Psbt,
|
||||||
type SighashType;
|
input_index: usize,
|
||||||
|
) -> Result<(sighash::LegacySighash, EcdsaSighashType), SignerError> {
|
||||||
fn sighash(
|
if input_index >= psbt.inputs.len() || input_index >= psbt.unsigned_tx.input.len() {
|
||||||
psbt: &Psbt,
|
return Err(SignerError::InputIndexOutOfRange);
|
||||||
input_index: usize,
|
|
||||||
extra: Self::Extra,
|
|
||||||
) -> Result<(Self::Sighash, Self::SighashType), SignerError>;
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ComputeSighash for Legacy {
|
|
||||||
type Extra = ();
|
|
||||||
type Sighash = sighash::LegacySighash;
|
|
||||||
type SighashType = EcdsaSighashType;
|
|
||||||
|
|
||||||
fn sighash(
|
|
||||||
psbt: &Psbt,
|
|
||||||
input_index: usize,
|
|
||||||
_extra: (),
|
|
||||||
) -> Result<(Self::Sighash, Self::SighashType), SignerError> {
|
|
||||||
if input_index >= psbt.inputs.len() || input_index >= psbt.unsigned_tx.input.len() {
|
|
||||||
return Err(SignerError::InputIndexOutOfRange);
|
|
||||||
}
|
|
||||||
|
|
||||||
let psbt_input = &psbt.inputs[input_index];
|
|
||||||
let tx_input = &psbt.unsigned_tx.input[input_index];
|
|
||||||
|
|
||||||
let sighash = psbt_input
|
|
||||||
.sighash_type
|
|
||||||
.unwrap_or_else(|| EcdsaSighashType::All.into())
|
|
||||||
.ecdsa_hash_ty()
|
|
||||||
.map_err(|_| SignerError::InvalidSighash)?;
|
|
||||||
let script = match psbt_input.redeem_script {
|
|
||||||
Some(ref redeem_script) => redeem_script.clone(),
|
|
||||||
None => {
|
|
||||||
let non_witness_utxo = psbt_input
|
|
||||||
.non_witness_utxo
|
|
||||||
.as_ref()
|
|
||||||
.ok_or(SignerError::MissingNonWitnessUtxo)?;
|
|
||||||
let prev_out = non_witness_utxo
|
|
||||||
.output
|
|
||||||
.get(tx_input.previous_output.vout as usize)
|
|
||||||
.ok_or(SignerError::InvalidNonWitnessUtxo)?;
|
|
||||||
|
|
||||||
prev_out.script_pubkey.clone()
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
Ok((
|
|
||||||
sighash::SighashCache::new(&psbt.unsigned_tx).legacy_signature_hash(
|
|
||||||
input_index,
|
|
||||||
&script,
|
|
||||||
sighash.to_u32(),
|
|
||||||
)?,
|
|
||||||
sighash,
|
|
||||||
))
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
impl ComputeSighash for Segwitv0 {
|
let psbt_input = &psbt.inputs[input_index];
|
||||||
type Extra = ();
|
let tx_input = &psbt.unsigned_tx.input[input_index];
|
||||||
type Sighash = sighash::SegwitV0Sighash;
|
|
||||||
type SighashType = EcdsaSighashType;
|
|
||||||
|
|
||||||
fn sighash(
|
let sighash_type = psbt_input
|
||||||
psbt: &Psbt,
|
.sighash_type
|
||||||
input_index: usize,
|
.unwrap_or_else(|| EcdsaSighashType::All.into())
|
||||||
_extra: (),
|
.ecdsa_hash_ty()
|
||||||
) -> Result<(Self::Sighash, Self::SighashType), SignerError> {
|
.map_err(|_| SignerError::InvalidSighash)?;
|
||||||
if input_index >= psbt.inputs.len() || input_index >= psbt.unsigned_tx.input.len() {
|
|
||||||
return Err(SignerError::InputIndexOutOfRange);
|
|
||||||
}
|
|
||||||
|
|
||||||
let psbt_input = &psbt.inputs[input_index];
|
let script = match psbt_input.redeem_script {
|
||||||
let tx_input = &psbt.unsigned_tx.input[input_index];
|
Some(ref redeem_script) => redeem_script.clone(),
|
||||||
|
None => {
|
||||||
let sighash_type = psbt_input
|
let non_witness_utxo = psbt_input
|
||||||
.sighash_type
|
.non_witness_utxo
|
||||||
.unwrap_or_else(|| EcdsaSighashType::All.into())
|
.as_ref()
|
||||||
.ecdsa_hash_ty()
|
.ok_or(SignerError::MissingNonWitnessUtxo)?;
|
||||||
.map_err(|_| SignerError::InvalidSighash)?;
|
let prev_out = non_witness_utxo
|
||||||
|
|
||||||
// Always try first with the non-witness utxo
|
|
||||||
let utxo = if let Some(prev_tx) = &psbt_input.non_witness_utxo {
|
|
||||||
// Check the provided prev-tx
|
|
||||||
if prev_tx.compute_txid() != tx_input.previous_output.txid {
|
|
||||||
return Err(SignerError::InvalidNonWitnessUtxo);
|
|
||||||
}
|
|
||||||
|
|
||||||
// The output should be present, if it's missing the `non_witness_utxo` is invalid
|
|
||||||
prev_tx
|
|
||||||
.output
|
.output
|
||||||
.get(tx_input.previous_output.vout as usize)
|
.get(tx_input.previous_output.vout as usize)
|
||||||
.ok_or(SignerError::InvalidNonWitnessUtxo)?
|
.ok_or(SignerError::InvalidNonWitnessUtxo)?;
|
||||||
} else if let Some(witness_utxo) = &psbt_input.witness_utxo {
|
|
||||||
// Fallback to the witness_utxo. If we aren't allowed to use it, signing should fail
|
|
||||||
// before we get to this point
|
|
||||||
witness_utxo
|
|
||||||
} else {
|
|
||||||
// Nothing has been provided
|
|
||||||
return Err(SignerError::MissingNonWitnessUtxo);
|
|
||||||
};
|
|
||||||
let value = utxo.value;
|
|
||||||
|
|
||||||
let mut sighasher = sighash::SighashCache::new(&psbt.unsigned_tx);
|
prev_out.script_pubkey.clone()
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
let sighash = match psbt_input.witness_script {
|
Ok((
|
||||||
Some(ref witness_script) => {
|
sighash::SighashCache::new(&psbt.unsigned_tx).legacy_signature_hash(
|
||||||
sighasher.p2wsh_signature_hash(input_index, witness_script, value, sighash_type)?
|
input_index,
|
||||||
}
|
&script,
|
||||||
None => {
|
sighash_type.to_u32(),
|
||||||
if utxo.script_pubkey.is_p2wpkh() {
|
)?,
|
||||||
sighasher.p2wpkh_signature_hash(
|
sighash_type,
|
||||||
input_index,
|
))
|
||||||
&utxo.script_pubkey,
|
|
||||||
value,
|
|
||||||
sighash_type,
|
|
||||||
)?
|
|
||||||
} else if psbt_input
|
|
||||||
.redeem_script
|
|
||||||
.as_ref()
|
|
||||||
.map(|s| s.is_p2wpkh())
|
|
||||||
.unwrap_or(false)
|
|
||||||
{
|
|
||||||
let script_pubkey = psbt_input.redeem_script.as_ref().unwrap();
|
|
||||||
sighasher.p2wpkh_signature_hash(
|
|
||||||
input_index,
|
|
||||||
script_pubkey,
|
|
||||||
value,
|
|
||||||
sighash_type,
|
|
||||||
)?
|
|
||||||
} else {
|
|
||||||
return Err(SignerError::MissingWitnessScript);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
Ok((sighash, sighash_type))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ComputeSighash for Tap {
|
/// Computes the segwitv0 sighash.
|
||||||
type Extra = Option<taproot::TapLeafHash>;
|
fn compute_segwitv0_sighash(
|
||||||
type Sighash = TapSighash;
|
psbt: &Psbt,
|
||||||
type SighashType = TapSighashType;
|
input_index: usize,
|
||||||
|
) -> Result<(sighash::SegwitV0Sighash, EcdsaSighashType), SignerError> {
|
||||||
|
if input_index >= psbt.inputs.len() || input_index >= psbt.unsigned_tx.input.len() {
|
||||||
|
return Err(SignerError::InputIndexOutOfRange);
|
||||||
|
}
|
||||||
|
|
||||||
fn sighash(
|
let psbt_input = &psbt.inputs[input_index];
|
||||||
psbt: &Psbt,
|
let tx_input = &psbt.unsigned_tx.input[input_index];
|
||||||
input_index: usize,
|
|
||||||
extra: Self::Extra,
|
let sighash_type = psbt_input
|
||||||
) -> Result<(Self::Sighash, TapSighashType), SignerError> {
|
.sighash_type
|
||||||
if input_index >= psbt.inputs.len() || input_index >= psbt.unsigned_tx.input.len() {
|
.unwrap_or_else(|| EcdsaSighashType::All.into())
|
||||||
return Err(SignerError::InputIndexOutOfRange);
|
.ecdsa_hash_ty()
|
||||||
|
.map_err(|_| SignerError::InvalidSighash)?;
|
||||||
|
|
||||||
|
// Always try first with the non-witness utxo
|
||||||
|
let utxo = if let Some(prev_tx) = &psbt_input.non_witness_utxo {
|
||||||
|
// Check the provided prev-tx
|
||||||
|
if prev_tx.compute_txid() != tx_input.previous_output.txid {
|
||||||
|
return Err(SignerError::InvalidNonWitnessUtxo);
|
||||||
}
|
}
|
||||||
|
|
||||||
let psbt_input = &psbt.inputs[input_index];
|
// The output should be present, if it's missing the `non_witness_utxo` is invalid
|
||||||
|
prev_tx
|
||||||
|
.output
|
||||||
|
.get(tx_input.previous_output.vout as usize)
|
||||||
|
.ok_or(SignerError::InvalidNonWitnessUtxo)?
|
||||||
|
} else if let Some(witness_utxo) = &psbt_input.witness_utxo {
|
||||||
|
// Fallback to the witness_utxo. If we aren't allowed to use it, signing should fail
|
||||||
|
// before we get to this point
|
||||||
|
witness_utxo
|
||||||
|
} else {
|
||||||
|
// Nothing has been provided
|
||||||
|
return Err(SignerError::MissingNonWitnessUtxo);
|
||||||
|
};
|
||||||
|
let value = utxo.value;
|
||||||
|
|
||||||
let sighash_type = psbt_input
|
let mut sighasher = sighash::SighashCache::new(&psbt.unsigned_tx);
|
||||||
.sighash_type
|
|
||||||
.unwrap_or_else(|| TapSighashType::Default.into())
|
|
||||||
.taproot_hash_ty()
|
|
||||||
.map_err(|_| SignerError::InvalidSighash)?;
|
|
||||||
let witness_utxos = (0..psbt.inputs.len())
|
|
||||||
.map(|i| psbt.get_utxo_for(i))
|
|
||||||
.collect::<Vec<_>>();
|
|
||||||
let mut all_witness_utxos = vec![];
|
|
||||||
|
|
||||||
let mut cache = sighash::SighashCache::new(&psbt.unsigned_tx);
|
let sighash = match psbt_input.witness_script {
|
||||||
let is_anyone_can_pay = psbt::PsbtSighashType::from(sighash_type).to_u32() & 0x80 != 0;
|
Some(ref witness_script) => {
|
||||||
let prevouts = if is_anyone_can_pay {
|
sighasher.p2wsh_signature_hash(input_index, witness_script, value, sighash_type)?
|
||||||
sighash::Prevouts::One(
|
}
|
||||||
input_index,
|
None => {
|
||||||
witness_utxos[input_index]
|
if utxo.script_pubkey.is_p2wpkh() {
|
||||||
.as_ref()
|
sighasher.p2wpkh_signature_hash(
|
||||||
.ok_or(SignerError::MissingWitnessUtxo)?,
|
input_index,
|
||||||
)
|
&utxo.script_pubkey,
|
||||||
} else if witness_utxos.iter().all(Option::is_some) {
|
value,
|
||||||
all_witness_utxos.extend(witness_utxos.iter().filter_map(|x| x.as_ref()));
|
sighash_type,
|
||||||
sighash::Prevouts::All(&all_witness_utxos)
|
)?
|
||||||
} else {
|
} else if psbt_input
|
||||||
return Err(SignerError::MissingWitnessUtxo);
|
.redeem_script
|
||||||
};
|
.as_ref()
|
||||||
|
.map(|s| s.is_p2wpkh())
|
||||||
|
.unwrap_or(false)
|
||||||
|
{
|
||||||
|
let script_pubkey = psbt_input.redeem_script.as_ref().unwrap();
|
||||||
|
sighasher.p2wpkh_signature_hash(input_index, script_pubkey, value, sighash_type)?
|
||||||
|
} else {
|
||||||
|
return Err(SignerError::MissingWitnessScript);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
Ok((sighash, sighash_type))
|
||||||
|
}
|
||||||
|
|
||||||
// Assume no OP_CODESEPARATOR
|
/// Computes the taproot sighash.
|
||||||
let extra = extra.map(|leaf_hash| (leaf_hash, 0xFFFFFFFF));
|
fn compute_tap_sighash(
|
||||||
|
psbt: &Psbt,
|
||||||
Ok((
|
input_index: usize,
|
||||||
cache.taproot_signature_hash(input_index, &prevouts, None, extra, sighash_type)?,
|
extra: Option<taproot::TapLeafHash>,
|
||||||
sighash_type,
|
) -> Result<(sighash::TapSighash, TapSighashType), SignerError> {
|
||||||
))
|
if input_index >= psbt.inputs.len() || input_index >= psbt.unsigned_tx.input.len() {
|
||||||
|
return Err(SignerError::InputIndexOutOfRange);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let psbt_input = &psbt.inputs[input_index];
|
||||||
|
|
||||||
|
let sighash_type = psbt_input
|
||||||
|
.sighash_type
|
||||||
|
.unwrap_or_else(|| TapSighashType::Default.into())
|
||||||
|
.taproot_hash_ty()
|
||||||
|
.map_err(|_| SignerError::InvalidSighash)?;
|
||||||
|
let witness_utxos = (0..psbt.inputs.len())
|
||||||
|
.map(|i| psbt.get_utxo_for(i))
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
let mut all_witness_utxos = vec![];
|
||||||
|
|
||||||
|
let mut cache = sighash::SighashCache::new(&psbt.unsigned_tx);
|
||||||
|
let is_anyone_can_pay = psbt::PsbtSighashType::from(sighash_type).to_u32() & 0x80 != 0;
|
||||||
|
let prevouts = if is_anyone_can_pay {
|
||||||
|
sighash::Prevouts::One(
|
||||||
|
input_index,
|
||||||
|
witness_utxos[input_index]
|
||||||
|
.as_ref()
|
||||||
|
.ok_or(SignerError::MissingWitnessUtxo)?,
|
||||||
|
)
|
||||||
|
} else if witness_utxos.iter().all(Option::is_some) {
|
||||||
|
all_witness_utxos.extend(witness_utxos.iter().filter_map(|x| x.as_ref()));
|
||||||
|
sighash::Prevouts::All(&all_witness_utxos)
|
||||||
|
} else {
|
||||||
|
return Err(SignerError::MissingWitnessUtxo);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Assume no OP_CODESEPARATOR
|
||||||
|
let extra = extra.map(|leaf_hash| (leaf_hash, 0xFFFFFFFF));
|
||||||
|
|
||||||
|
Ok((
|
||||||
|
cache.taproot_signature_hash(input_index, &prevouts, None, extra, sighash_type)?,
|
||||||
|
sighash_type,
|
||||||
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PartialOrd for SignersContainerKey {
|
impl PartialOrd for SignersContainerKey {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user