From 33ba0bef688ad180d117046e2945bb0efe2097f2 Mon Sep 17 00:00:00 2001 From: Dr Maxim Orlovsky Date: Sun, 8 Oct 2023 22:54:09 +0200 Subject: [PATCH] consensus: add script convertors --- consensus/src/hashtypes.rs | 65 +++++++++++++++++++++++++++++++++++++- consensus/src/pubkeys.rs | 7 ++++ consensus/src/segwit.rs | 13 ++++++-- consensus/src/taproot.rs | 2 ++ 4 files changed, 84 insertions(+), 3 deletions(-) diff --git a/consensus/src/hashtypes.rs b/consensus/src/hashtypes.rs index f66f20f1..0153c80c 100644 --- a/consensus/src/hashtypes.rs +++ b/consensus/src/hashtypes.rs @@ -20,8 +20,11 @@ // limitations under the License. use amplify::{Bytes20, Bytes32, Wrapper}; +use commit_verify::{DigestExt, Ripemd160, Sha256}; -use crate::LIB_NAME_BITCOIN; +use crate::{ + CompressedPk, LegacyPk, RedeemScript, UncompressedPk, WitnessScript, LIB_NAME_BITCOIN, +}; #[derive(Wrapper, Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Debug, From)] #[wrapper(Index, RangeOps, AsSlice, BorrowSlice, Hex, Display, FromStr)] @@ -42,6 +45,36 @@ impl From for [u8; 20] { fn from(value: PubkeyHash) -> Self { value.0.into_inner() } } +impl From for PubkeyHash { + fn from(pk: CompressedPk) -> Self { + let mut engine = Sha256::default(); + engine.input_raw(&pk.to_byte_array()); + let mut engine2 = Ripemd160::default(); + engine2.input_raw(&engine.finish()); + Self(engine2.finish().into()) + } +} + +impl From for PubkeyHash { + fn from(pk: UncompressedPk) -> Self { + let mut engine = Sha256::default(); + engine.input_raw(&pk.to_byte_array()); + let mut engine2 = Ripemd160::default(); + engine2.input_raw(&engine.finish()); + Self(engine2.finish().into()) + } +} + +impl From for PubkeyHash { + fn from(pk: LegacyPk) -> Self { + let mut engine = Sha256::default(); + engine.input_raw(&pk.to_vec()); + let mut engine2 = Ripemd160::default(); + engine2.input_raw(&engine.finish()); + Self(engine2.finish().into()) + } +} + #[derive(Wrapper, Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Debug, From)] #[wrapper(Index, RangeOps, AsSlice, BorrowSlice, Hex, Display, FromStr)] #[derive(StrictType, StrictDumb, StrictEncode, StrictDecode)] @@ -61,6 +94,16 @@ impl From for [u8; 20] { fn from(value: ScriptHash) -> Self { value.0.into_inner() } } +impl From<&RedeemScript> for ScriptHash { + fn from(redeem_script: &RedeemScript) -> Self { + let mut engine = Sha256::default(); + engine.input_raw(redeem_script.as_slice()); + let mut engine2 = Ripemd160::default(); + engine2.input_raw(&engine.finish()); + Self(engine2.finish().into()) + } +} + #[derive(Wrapper, Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Debug, From)] #[wrapper(Index, RangeOps, AsSlice, BorrowSlice, Hex, Display, FromStr)] #[derive(StrictType, StrictDumb, StrictEncode, StrictDecode)] @@ -80,6 +123,16 @@ impl From for [u8; 20] { fn from(value: WPubkeyHash) -> Self { value.0.into_inner() } } +impl From for WPubkeyHash { + fn from(pk: CompressedPk) -> Self { + let mut engine = Sha256::default(); + engine.input_raw(&pk.to_byte_array()); + let mut engine2 = Ripemd160::default(); + engine2.input_raw(&engine.finish()); + Self(engine2.finish().into()) + } +} + #[derive(Wrapper, Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Debug, From)] #[wrapper(Index, RangeOps, AsSlice, BorrowSlice, Hex, Display, FromStr)] #[derive(StrictType, StrictDumb, StrictEncode, StrictDecode)] @@ -98,3 +151,13 @@ pub struct WScriptHash( impl From for [u8; 32] { fn from(value: WScriptHash) -> Self { value.0.into_inner() } } + +impl From<&WitnessScript> for WScriptHash { + fn from(witness_script: &WitnessScript) -> Self { + let mut engine = Sha256::default(); + engine.input_raw(witness_script.as_slice()); + let mut engine2 = Sha256::default(); + engine2.input_raw(&engine.finish()); + Self(engine2.finish().into()) + } +} diff --git a/consensus/src/pubkeys.rs b/consensus/src/pubkeys.rs index 7353cd3a..3b55b541 100644 --- a/consensus/src/pubkeys.rs +++ b/consensus/src/pubkeys.rs @@ -208,6 +208,13 @@ impl LegacyPk { _ => unreachable!(), }) } + + pub fn to_vec(&self) -> Vec { + match self.compressed { + true => self.pubkey.serialize().to_vec(), + false => self.pubkey.serialize_uncompressed().to_vec(), + } + } } impl StrictEncode for LegacyPk { diff --git a/consensus/src/segwit.rs b/consensus/src/segwit.rs index 9df0da17..2af2a3b7 100644 --- a/consensus/src/segwit.rs +++ b/consensus/src/segwit.rs @@ -22,10 +22,12 @@ use std::vec; use amplify::confinement::Confined; -use amplify::Bytes32StrRev; +use amplify::{Bytes32StrRev, Wrapper}; use crate::opcodes::*; -use crate::{OpCode, ScriptBytes, ScriptPubkey, VarIntArray, LIB_NAME_BITCOIN}; +use crate::{ + OpCode, RedeemScript, ScriptBytes, ScriptPubkey, VarIntArray, WScriptHash, LIB_NAME_BITCOIN, +}; #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug, Display, Error)] #[display(doc_comments)] @@ -328,6 +330,13 @@ impl WitnessScript { /// Adds a single opcode to the script. pub fn push_opcode(&mut self, op_code: OpCode) { self.0.push(op_code as u8); } + pub fn to_redeem_script(&self) -> RedeemScript { + let script = ScriptPubkey::p2wsh(WScriptHash::from(self)); + RedeemScript::from_inner(script.into_inner()) + } + + pub fn to_script_pubkey(&self) -> ScriptPubkey { ScriptPubkey::p2wsh(WScriptHash::from(self)) } + pub fn as_script_bytes(&self) -> &ScriptBytes { &self.0 } } diff --git a/consensus/src/taproot.rs b/consensus/src/taproot.rs index 779b49f0..08371d7e 100644 --- a/consensus/src/taproot.rs +++ b/consensus/src/taproot.rs @@ -247,6 +247,8 @@ impl OutputPk { XOnlyPk::from_bytes(bytes).map(Self) } + pub fn to_script_pubkey(&self) -> ScriptPubkey { ScriptPubkey::p2tr_tweaked(*self) } + #[inline] pub fn to_byte_array(&self) -> [u8; 32] { self.0.to_byte_array() } }