From 3b5825a42c0a16cd10be2014a1fa56a2dee2c394 Mon Sep 17 00:00:00 2001 From: Dr Maxim Orlovsky Date: Thu, 5 Oct 2023 23:03:04 +0200 Subject: [PATCH 01/31] primitives: move sighashes module from PSBT crate --- primitives/src/lib.rs | 4 + primitives/src/sigtypes.rs | 297 +++++++++++++++++++++++++++++++++++++ 2 files changed, 301 insertions(+) create mode 100644 primitives/src/sigtypes.rs diff --git a/primitives/src/lib.rs b/primitives/src/lib.rs index a5c3af32..ef1219e8 100644 --- a/primitives/src/lib.rs +++ b/primitives/src/lib.rs @@ -51,6 +51,7 @@ mod script; mod segwit; mod taproot; mod tx; +mod sigtypes; mod util; mod weights; #[cfg(feature = "stl")] @@ -64,6 +65,9 @@ pub use consensus::{ }; pub use script::{OpCode, ScriptBytes, ScriptPubkey, SigScript}; pub use segwit::*; +pub use sigtypes::{ + Bip340Sig, LegacySig, NonStandardSighashType, SigError, SighashFlag, SighashType, +}; pub use taproot::*; pub use tx::{ LockTime, Outpoint, OutpointParseError, Sats, SeqNo, Tx, TxIn, TxOut, TxParseError, TxVer, diff --git a/primitives/src/sigtypes.rs b/primitives/src/sigtypes.rs new file mode 100644 index 00000000..1177fdbf --- /dev/null +++ b/primitives/src/sigtypes.rs @@ -0,0 +1,297 @@ +// Bitcoin protocol primitives library. +// +// SPDX-License-Identifier: Apache-2.0 +// +// Written in 2019-2023 by +// Dr Maxim Orlovsky +// +// Copyright (C) 2019-2023 LNP/BP Standards Association. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use std::iter; + +use secp256k1::{ecdsa, schnorr}; + +/// This type is consensus valid but an input including it would prevent the +/// transaction from being relayed on today's Bitcoin network. +#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Display, Error)] +#[display("non-standard SIGHASH_TYPE value {0:#X}")] +pub struct NonStandardSighashType(pub u32); + +#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)] +#[cfg_attr( + feature = "serde", + derive(Serialize, Deserialize), + serde(crate = "serde_crate", rename_all = "camelCase") +)] +#[repr(u8)] +pub enum SighashFlag { + /// 0x1: Sign all outputs. + All = 0x01, + /// 0x2: Sign no outputs --- anyone can choose the destination. + None = 0x02, + /// 0x3: Sign the output whose index matches this input's index. If none + /// exists, sign the hash + /// `0000000000000000000000000000000000000000000000000000000000000001`. + /// (This rule is probably an unintentional C++ism, but it's consensus so we + /// have to follow it.) + Single = 0x03, +} + +#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)] +#[cfg_attr( + feature = "serde", + derive(Serialize, Deserialize), + serde(crate = "serde_crate", rename_all = "camelCase") +)] +pub struct SighashType { + pub flag: SighashFlag, + pub anyone_can_pay: bool, +} + +impl SighashType { + pub const fn all() -> Self { + SighashType { + flag: SighashFlag::All, + anyone_can_pay: false, + } + } + pub const fn none() -> Self { + SighashType { + flag: SighashFlag::None, + anyone_can_pay: false, + } + } + pub const fn single() -> Self { + SighashType { + flag: SighashFlag::Single, + anyone_can_pay: false, + } + } + + pub const fn all_anyone_can_pay() -> Self { + SighashType { + flag: SighashFlag::All, + anyone_can_pay: true, + } + } + pub const fn none_anyone_can_pay() -> Self { + SighashType { + flag: SighashFlag::None, + anyone_can_pay: true, + } + } + pub const fn single_anyone_can_pay() -> Self { + SighashType { + flag: SighashFlag::Single, + anyone_can_pay: true, + } + } + + /// Creates a [`SighashType`] from a raw `u32`. + /// + /// **Note**: this replicates consensus behaviour, for current standardness + /// rules correctness you probably want [`Self::from_standard_u32`]. + /// + /// This might cause unexpected behavior because it does not roundtrip. That + /// is, `LegacySighashType::from_consensus(n) as u32 != n` for + /// non-standard values of `n`. While verifying signatures, the user + /// should retain the `n` and use it compute the signature hash message. + pub fn from_consensus_u32(n: u32) -> SighashType { + // In Bitcoin Core, the SignatureHash function will mask the (int32) value with + // 0x1f to (apparently) deactivate ACP when checking for SINGLE and NONE bits. + // We however want to be matching also against on ACP-masked ALL, SINGLE, and + // NONE. So here we re-activate ACP. + let mask = 0x1f | 0x80; + let (flag, anyone_can_pay) = match n & mask { + // "real" sighashes + 0x01 => (SighashFlag::All, false), + 0x02 => (SighashFlag::None, false), + 0x03 => (SighashFlag::Single, false), + 0x81 => (SighashFlag::All, true), + 0x82 => (SighashFlag::None, true), + 0x83 => (SighashFlag::Single, true), + // catchalls + x if x & 0x80 == 0x80 => (SighashFlag::All, true), + _ => (SighashFlag::All, false), + }; + SighashType { + flag, + anyone_can_pay, + } + } + + /// Creates a [`SighashType`] from a raw `u32`. + /// + /// # Errors + /// + /// If `n` is a non-standard sighash value. + pub fn from_standard_u32(n: u32) -> Result { + let (flag, anyone_can_pay) = match n { + // Standard sighashes, see https://github.com/bitcoin/bitcoin/blob/b805dbb0b9c90dadef0424e5b3bf86ac308e103e/src/script/interpreter.cpp#L189-L198 + 0x01 => (SighashFlag::All, false), + 0x02 => (SighashFlag::None, false), + 0x03 => (SighashFlag::Single, false), + 0x81 => (SighashFlag::All, true), + 0x82 => (SighashFlag::None, true), + 0x83 => (SighashFlag::Single, true), + non_standard => return Err(NonStandardSighashType(non_standard)), + }; + Ok(SighashType { + flag, + anyone_can_pay, + }) + } + + /// Converts [`SighashType`] to a `u32` sighash flag. + /// + /// The returned value is guaranteed to be a valid according to standardness + /// rules. + #[inline] + pub const fn into_consensus_u32(self) -> u32 { self.into_consensus_u8() as u32 } + + /// Converts [`SighashType`] to a `u32` sighash flag. + /// + /// The returned value is guaranteed to be a valid according to standardness + /// rules. + #[inline] + pub const fn to_consensus_u32(&self) -> u32 { self.into_consensus_u32() } + + pub const fn into_consensus_u8(self) -> u8 { + let flag = self.flag as u8; + let mask = (self.anyone_can_pay as u8) << 7; + flag | mask + } + + pub const fn to_consensus_u8(self) -> u8 { + let flag = self.flag as u8; + let mask = (self.anyone_can_pay as u8) << 7; + flag | mask + } +} + +/// An ECDSA signature-related error. +#[derive(Clone, PartialEq, Eq, Debug, Display, Error, From)] +#[display(doc_comments)] +pub enum SigError { + /// Non-standard sighash type. + #[display(inner)] + #[from] + SighashType(NonStandardSighashType), + + /// empty signature. + EmptySignature, + + /// invalid signature DER encoding. + DerEncoding, + + /// invalid BIP340 signature length ({0}). + Bip340Encoding(usize), + + /// invalid BIP340 signature. + InvalidSignature, +} + +#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)] +#[cfg_attr( + feature = "serde", + derive(Serialize, Deserialize), + serde(crate = "serde_crate", rename_all = "camelCase") +)] +pub struct LegacySig { + /// The underlying ECDSA Signature + pub sig: ecdsa::Signature, + /// The corresponding hash type + pub sighash_type: SighashType, +} + +impl LegacySig { + /// Constructs an ECDSA bitcoin signature for [`SighashType::All`]. + pub fn sighash_all(sig: ecdsa::Signature) -> LegacySig { + LegacySig { + sig, + sighash_type: SighashType::all(), + } + } + + /// Deserializes from slice following the standardness rules for + /// [`SighashType`]. + pub fn from_bytes(bytes: &[u8]) -> Result { + let (hash_ty, sig) = bytes.split_last().ok_or(SigError::EmptySignature)?; + let sighash_type = SighashType::from_standard_u32(*hash_ty as u32)?; + let sig = ecdsa::Signature::from_der(sig).map_err(|_| SigError::DerEncoding)?; + Ok(LegacySig { sig, sighash_type }) + } + + /// Serializes an Legacy signature (inner secp256k1 signature in DER format) + /// into `Vec`. + // TODO: add support to serialize to a writer to SerializedSig + pub fn to_vec(self) -> Vec { + self.sig + .serialize_der() + .iter() + .copied() + .chain(iter::once(self.sighash_type.into_consensus_u8())) + .collect() + } +} + +#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)] +#[cfg_attr( + feature = "serde", + derive(Serialize, Deserialize), + serde(crate = "serde_crate", rename_all = "camelCase") +)] +pub struct Bip340Sig { + /// The underlying ECDSA Signature + pub sig: schnorr::Signature, + /// The corresponding hash type + pub sighash_type: Option, +} + +impl Bip340Sig { + /// Constructs an ECDSA bitcoin signature for [`SighashType::All`]. + pub fn sighash_default(sig: schnorr::Signature) -> Self { + Bip340Sig { + sig, + sighash_type: None, + } + } + + /// Deserializes from slice following the standardness rules for + /// [`SighashType`]. + pub fn from_bytes(bytes: &[u8]) -> Result { + let (hash_ty, sig) = match bytes.len() { + 0 => return Err(SigError::EmptySignature), + 64 => (None, bytes), + 65 => (Some(bytes[64] as u32), &bytes[..64]), + invalid => return Err(SigError::Bip340Encoding(invalid)), + }; + let sighash_type = hash_ty.map(SighashType::from_standard_u32).transpose()?; + let sig = schnorr::Signature::from_slice(sig).map_err(|_| SigError::InvalidSignature)?; + Ok(Bip340Sig { sig, sighash_type }) + } + + /// Serializes an ECDSA signature (inner secp256k1 signature in DER format) + /// into `Vec`. + // TODO: add support to serialize to a writer to SerializedSig + pub fn to_vec(self) -> Vec { + let mut ser = Vec::::with_capacity(65); + ser.extend_from_slice(&self.sig[..]); + if let Some(sighash_type) = self.sighash_type { + ser.push(sighash_type.into_consensus_u8()) + } + ser + } +} From f6bf5716c8ed3b7301f9cb34903fab76997e6ebb Mon Sep 17 00:00:00 2001 From: Dr Maxim Orlovsky Date: Thu, 5 Oct 2023 23:06:26 +0200 Subject: [PATCH 02/31] primitives: move WitnessScript and RedeemScript from PSBT crate --- primitives/src/lib.rs | 2 +- primitives/src/script.rs | 92 +++++++++++++++++++++++++++++++++++----- 2 files changed, 83 insertions(+), 11 deletions(-) diff --git a/primitives/src/lib.rs b/primitives/src/lib.rs index ef1219e8..02e07919 100644 --- a/primitives/src/lib.rs +++ b/primitives/src/lib.rs @@ -63,7 +63,7 @@ pub use consensus::{ ConsensusDataError, ConsensusDecode, ConsensusDecodeError, ConsensusEncode, VarIntArray, VarIntSize, }; -pub use script::{OpCode, ScriptBytes, ScriptPubkey, SigScript}; +pub use script::{OpCode, RedeemScript, ScriptBytes, ScriptPubkey, SigScript, WitnessScript}; pub use segwit::*; pub use sigtypes::{ Bip340Sig, LegacySig, NonStandardSighashType, SigError, SighashFlag, SighashType, diff --git a/primitives/src/script.rs b/primitives/src/script.rs index b7d25f6f..5b630c08 100644 --- a/primitives/src/script.rs +++ b/primitives/src/script.rs @@ -22,7 +22,7 @@ use std::fmt::{Formatter, LowerHex, UpperHex}; use amplify::confinement::Confined; -use amplify::hex::{Error, FromHex, ToHex}; +use amplify::hex::{self, FromHex, ToHex}; use crate::opcodes::*; use crate::{VarIntArray, LIB_NAME_BITCOIN}; @@ -125,10 +125,10 @@ pub struct SigScript( ); impl FromHex for SigScript { - fn from_hex(s: &str) -> Result { ScriptBytes::from_hex(s).map(Self) } + fn from_hex(s: &str) -> Result { ScriptBytes::from_hex(s).map(Self) } - fn from_byte_iter(_: I) -> Result - where I: Iterator> + ExactSizeIterator + DoubleEndedIterator { + fn from_byte_iter(_: I) -> Result + where I: Iterator> + ExactSizeIterator + DoubleEndedIterator { unreachable!() } } @@ -215,10 +215,82 @@ impl ScriptPubkey { } impl FromHex for ScriptPubkey { - fn from_hex(s: &str) -> Result { ScriptBytes::from_hex(s).map(Self) } + fn from_hex(s: &str) -> Result { ScriptBytes::from_hex(s).map(Self) } - fn from_byte_iter(_: I) -> Result - where I: Iterator> + ExactSizeIterator + DoubleEndedIterator { + fn from_byte_iter(_: I) -> Result + where I: Iterator> + ExactSizeIterator + DoubleEndedIterator { + unreachable!() + } +} + +#[derive(Wrapper, WrapperMut, Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Debug, From, Default)] +#[wrapper(Deref, Index, RangeOps, BorrowSlice, LowerHex, UpperHex)] +#[wrapper_mut(DerefMut, IndexMut, RangeMut, BorrowSliceMut)] +#[cfg_attr( + feature = "serde", + derive(Serialize, Deserialize), + serde(crate = "serde_crate", transparent) +)] +pub struct WitnessScript( + #[from] + #[from(Vec)] + ScriptBytes, +); + +impl WitnessScript { + pub fn new() -> Self { Self::default() } + + pub fn with_capacity(capacity: usize) -> Self { + Self(ScriptBytes::from(Confined::with_capacity(capacity))) + } + + /// 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 as_script_bytes(&self) -> &ScriptBytes { &self.0 } +} + +impl FromHex for WitnessScript { + fn from_hex(s: &str) -> Result { ScriptBytes::from_hex(s).map(Self) } + + fn from_byte_iter(_: I) -> Result + where I: Iterator> + ExactSizeIterator + DoubleEndedIterator { + unreachable!() + } +} + +#[derive(Wrapper, WrapperMut, Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Debug, From, Default)] +#[wrapper(Deref, Index, RangeOps, BorrowSlice, LowerHex, UpperHex)] +#[wrapper_mut(DerefMut, IndexMut, RangeMut, BorrowSliceMut)] +#[cfg_attr( + feature = "serde", + derive(Serialize, Deserialize), + serde(crate = "serde_crate", transparent) +)] +pub struct RedeemScript( + #[from] + #[from(Vec)] + ScriptBytes, +); + +impl RedeemScript { + pub fn new() -> Self { Self::default() } + + pub fn with_capacity(capacity: usize) -> Self { + Self(ScriptBytes::from(Confined::with_capacity(capacity))) + } + + /// 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 as_script_bytes(&self) -> &ScriptBytes { &self.0 } +} + +impl FromHex for RedeemScript { + fn from_hex(s: &str) -> Result { ScriptBytes::from_hex(s).map(Self) } + + fn from_byte_iter(_: I) -> Result + where I: Iterator> + ExactSizeIterator + DoubleEndedIterator { unreachable!() } } @@ -247,9 +319,9 @@ impl UpperHex for ScriptBytes { } impl FromHex for ScriptBytes { - fn from_hex(s: &str) -> Result { Vec::::from_hex(s).map(Self::from) } - fn from_byte_iter(_: I) -> Result - where I: Iterator> + ExactSizeIterator + DoubleEndedIterator { + fn from_hex(s: &str) -> Result { Vec::::from_hex(s).map(Self::from) } + fn from_byte_iter(_: I) -> Result + where I: Iterator> + ExactSizeIterator + DoubleEndedIterator { unreachable!() } } From da864130f6ef6efd898cc3bb494df785785531ff Mon Sep 17 00:00:00 2001 From: Dr Maxim Orlovsky Date: Thu, 5 Oct 2023 23:11:04 +0200 Subject: [PATCH 03/31] primitives: move Witness, Wtxid & WitnessScript into segwit module --- primitives/src/lib.rs | 6 +- primitives/src/script.rs | 40 +----------- primitives/src/segwit.rs | 129 +++++++++++++++++++++++++++++++++++++- primitives/src/taproot.rs | 4 +- primitives/src/tx.rs | 89 +------------------------- 5 files changed, 135 insertions(+), 133 deletions(-) diff --git a/primitives/src/lib.rs b/primitives/src/lib.rs index 02e07919..569e48ea 100644 --- a/primitives/src/lib.rs +++ b/primitives/src/lib.rs @@ -63,15 +63,15 @@ pub use consensus::{ ConsensusDataError, ConsensusDecode, ConsensusDecodeError, ConsensusEncode, VarIntArray, VarIntSize, }; -pub use script::{OpCode, RedeemScript, ScriptBytes, ScriptPubkey, SigScript, WitnessScript}; -pub use segwit::*; +pub use script::{OpCode, RedeemScript, ScriptBytes, ScriptPubkey, SigScript}; +pub use segwit::{SegwitError, Witness, WitnessProgram, WitnessScript, WitnessVer, Wtxid}; pub use sigtypes::{ Bip340Sig, LegacySig, NonStandardSighashType, SigError, SighashFlag, SighashType, }; pub use taproot::*; pub use tx::{ LockTime, Outpoint, OutpointParseError, Sats, SeqNo, Tx, TxIn, TxOut, TxParseError, TxVer, - Txid, Vout, Witness, Wtxid, LOCKTIME_THRESHOLD, + Txid, Vout, LOCKTIME_THRESHOLD, }; pub use util::{Chain, ChainParseError, NonStandardValue, VarInt}; pub use weights::{VBytes, Weight, WeightUnits}; diff --git a/primitives/src/script.rs b/primitives/src/script.rs index 5b630c08..d3bceb4f 100644 --- a/primitives/src/script.rs +++ b/primitives/src/script.rs @@ -223,42 +223,6 @@ impl FromHex for ScriptPubkey { } } -#[derive(Wrapper, WrapperMut, Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Debug, From, Default)] -#[wrapper(Deref, Index, RangeOps, BorrowSlice, LowerHex, UpperHex)] -#[wrapper_mut(DerefMut, IndexMut, RangeMut, BorrowSliceMut)] -#[cfg_attr( - feature = "serde", - derive(Serialize, Deserialize), - serde(crate = "serde_crate", transparent) -)] -pub struct WitnessScript( - #[from] - #[from(Vec)] - ScriptBytes, -); - -impl WitnessScript { - pub fn new() -> Self { Self::default() } - - pub fn with_capacity(capacity: usize) -> Self { - Self(ScriptBytes::from(Confined::with_capacity(capacity))) - } - - /// 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 as_script_bytes(&self) -> &ScriptBytes { &self.0 } -} - -impl FromHex for WitnessScript { - fn from_hex(s: &str) -> Result { ScriptBytes::from_hex(s).map(Self) } - - fn from_byte_iter(_: I) -> Result - where I: Iterator> + ExactSizeIterator + DoubleEndedIterator { - unreachable!() - } -} - #[derive(Wrapper, WrapperMut, Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Debug, From, Default)] #[wrapper(Deref, Index, RangeOps, BorrowSlice, LowerHex, UpperHex)] #[wrapper_mut(DerefMut, IndexMut, RangeMut, BorrowSliceMut)] @@ -362,10 +326,10 @@ impl ScriptBytes { } #[inline] - fn push(&mut self, data: u8) { self.0.push(data).expect("script exceeds 4GB") } + pub(crate) fn push(&mut self, data: u8) { self.0.push(data).expect("script exceeds 4GB") } #[inline] - fn extend(&mut self, data: &[u8]) { + pub(crate) fn extend(&mut self, data: &[u8]) { self.0 .extend(data.iter().copied()) .expect("script exceeds 4GB") diff --git a/primitives/src/segwit.rs b/primitives/src/segwit.rs index 464e3b6c..f3c438ca 100644 --- a/primitives/src/segwit.rs +++ b/primitives/src/segwit.rs @@ -19,8 +19,14 @@ // See the License for the specific language governing permissions and // limitations under the License. +use std::vec; + +use amplify::confinement::Confined; +use amplify::hex::{self, FromHex}; +use amplify::Bytes32StrRev; + use crate::opcodes::*; -use crate::{OpCode, ScriptBytes, ScriptPubkey}; +use crate::{OpCode, ScriptBytes, ScriptPubkey, VarIntArray, LIB_NAME_BITCOIN}; #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug, Display, Error)] #[display(doc_comments)] @@ -289,3 +295,124 @@ impl ScriptPubkey { && script_len - 2 == push_opbyte as usize } } + +#[derive(Wrapper, WrapperMut, Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Debug, From, Default)] +#[wrapper(Deref, Index, RangeOps, BorrowSlice, LowerHex, UpperHex)] +#[wrapper_mut(DerefMut, IndexMut, RangeMut, BorrowSliceMut)] +#[cfg_attr( + feature = "serde", + derive(Serialize, Deserialize), + serde(crate = "serde_crate", transparent) +)] +pub struct WitnessScript( + #[from] + #[from(Vec)] + ScriptBytes, +); + +impl WitnessScript { + pub fn new() -> Self { Self::default() } + + pub fn with_capacity(capacity: usize) -> Self { + Self(ScriptBytes::from(Confined::with_capacity(capacity))) + } + + /// 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 as_script_bytes(&self) -> &ScriptBytes { &self.0 } +} + +impl FromHex for WitnessScript { + fn from_hex(s: &str) -> Result { ScriptBytes::from_hex(s).map(Self) } + + fn from_byte_iter(_: I) -> Result + where I: Iterator> + ExactSizeIterator + DoubleEndedIterator { + unreachable!() + } +} + +#[derive(Wrapper, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, From)] +#[derive(StrictType, StrictDumb, StrictEncode, StrictDecode)] +#[strict_type(lib = LIB_NAME_BITCOIN)] +#[derive(CommitEncode)] +#[commit_encode(strategy = strict)] +#[cfg_attr( + feature = "serde", + derive(Serialize, Deserialize), + serde(crate = "serde_crate", transparent) +)] +#[wrapper(BorrowSlice, Index, RangeOps, Debug, LowerHex, UpperHex, Display, FromStr)] +pub struct Wtxid( + #[from] + #[from([u8; 32])] + Bytes32StrRev, +); + +impl FromHex for Wtxid { + fn from_byte_iter(iter: I) -> Result + where I: Iterator> + ExactSizeIterator + DoubleEndedIterator { + Bytes32StrRev::from_byte_iter(iter).map(Self) + } +} + +#[derive(Wrapper, Clone, Eq, PartialEq, Hash, Debug, From, Default)] +#[wrapper(Deref, Index, RangeOps)] +#[derive(StrictType, StrictEncode, StrictDecode)] +#[strict_type(lib = LIB_NAME_BITCOIN)] +pub struct Witness(VarIntArray>); + +impl IntoIterator for Witness { + type Item = VarIntArray; + type IntoIter = vec::IntoIter>; + + fn into_iter(self) -> Self::IntoIter { self.0.into_iter() } +} + +impl Witness { + pub fn new() -> Self { default!() } + + pub fn elements(&self) -> impl Iterator { + self.0.iter().map(|el| el.as_slice()) + } + + pub fn from_consensus_stack(witness: impl IntoIterator>) -> Witness { + let iter = witness.into_iter().map(|vec| { + VarIntArray::try_from(vec).expect("witness stack element length exceeds 2^64 bytes") + }); + let stack = + VarIntArray::try_from_iter(iter).expect("witness stack size exceeds 2^64 bytes"); + Witness(stack) + } + + pub(crate) fn as_var_int_array(&self) -> &VarIntArray> { &self.0 } +} + +#[cfg(feature = "serde")] +mod _serde { + use serde::{Deserialize, Serialize}; + use serde_crate::ser::SerializeSeq; + use serde_crate::{Deserializer, Serializer}; + + use super::*; + use crate::ScriptBytes; + + impl Serialize for Witness { + fn serialize(&self, serializer: S) -> Result + where S: Serializer { + let mut ser = serializer.serialize_seq(Some(self.len()))?; + for el in &self.0 { + ser.serialize_element(&ScriptBytes::from(el.to_inner()))?; + } + ser.end() + } + } + + impl<'de> Deserialize<'de> for Witness { + fn deserialize(deserializer: D) -> Result + where D: Deserializer<'de> { + let data = Vec::::deserialize(deserializer)?; + Ok(Witness::from_consensus_stack(data.into_iter().map(ScriptBytes::into_vec))) + } + } +} diff --git a/primitives/src/taproot.rs b/primitives/src/taproot.rs index b4dfc785..563bb15d 100644 --- a/primitives/src/taproot.rs +++ b/primitives/src/taproot.rs @@ -421,9 +421,7 @@ impl TapScript { } /// Adds a single opcode to the script. - pub fn push_opcode(&mut self, op_code: TapCode) { - self.0.push(op_code as u8).expect("script exceeds 4GB"); - } + pub fn push_opcode(&mut self, op_code: TapCode) { self.0.push(op_code as u8); } } impl ScriptPubkey { diff --git a/primitives/src/tx.rs b/primitives/src/tx.rs index dc457ff4..93224319 100644 --- a/primitives/src/tx.rs +++ b/primitives/src/tx.rs @@ -25,16 +25,14 @@ use std::fmt::{self, Debug, Display, Formatter, LowerHex}; use std::iter::Sum; use std::num::ParseIntError; use std::str::FromStr; -use std::vec; use amplify::hex::{self, FromHex, ToHex}; use amplify::{Bytes32StrRev, RawArray, Wrapper}; use commit_verify::{DigestExt, Sha256}; -use super::{VarIntArray, LIB_NAME_BITCOIN}; use crate::{ ConsensusDecode, ConsensusDecodeError, ConsensusEncode, NonStandardValue, ScriptPubkey, - SigScript, + SigScript, VarIntArray, Witness, Wtxid, LIB_NAME_BITCOIN, }; #[derive(Wrapper, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, From)] @@ -69,30 +67,6 @@ impl FromHex for Txid { } } -#[derive(Wrapper, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, From)] -#[derive(StrictType, StrictDumb, StrictEncode, StrictDecode)] -#[strict_type(lib = LIB_NAME_BITCOIN)] -#[derive(CommitEncode)] -#[commit_encode(strategy = strict)] -#[cfg_attr( - feature = "serde", - derive(Serialize, Deserialize), - serde(crate = "serde_crate", transparent) -)] -#[wrapper(BorrowSlice, Index, RangeOps, Debug, LowerHex, UpperHex, Display, FromStr)] -pub struct Wtxid( - #[from] - #[from([u8; 32])] - Bytes32StrRev, -); - -impl FromHex for Wtxid { - fn from_byte_iter(iter: I) -> Result - where I: Iterator> + ExactSizeIterator + DoubleEndedIterator { - Bytes32StrRev::from_byte_iter(iter).map(Self) - } -} - #[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug, Display, From)] #[derive(StrictType, StrictDumb, StrictEncode, StrictDecode)] #[strict_type(lib = LIB_NAME_BITCOIN)] @@ -206,67 +180,6 @@ impl SeqNo { pub const fn to_consensus_u32(&self) -> u32 { self.0 } } -#[derive(Wrapper, Clone, Eq, PartialEq, Hash, Debug, From, Default)] -#[wrapper(Deref, Index, RangeOps)] -#[derive(StrictType, StrictEncode, StrictDecode)] -#[strict_type(lib = LIB_NAME_BITCOIN)] -pub struct Witness(VarIntArray>); - -impl IntoIterator for Witness { - type Item = VarIntArray; - type IntoIter = vec::IntoIter>; - - fn into_iter(self) -> Self::IntoIter { self.0.into_iter() } -} - -impl Witness { - pub fn new() -> Self { default!() } - - pub fn elements(&self) -> impl Iterator { - self.0.iter().map(|el| el.as_slice()) - } - - pub fn from_consensus_stack(witness: impl IntoIterator>) -> Witness { - let iter = witness.into_iter().map(|vec| { - VarIntArray::try_from(vec).expect("witness stack element length exceeds 2^64 bytes") - }); - let stack = - VarIntArray::try_from_iter(iter).expect("witness stack size exceeds 2^64 bytes"); - Witness(stack) - } - - pub(crate) fn as_var_int_array(&self) -> &VarIntArray> { &self.0 } -} - -#[cfg(feature = "serde")] -mod _serde { - use serde::{Deserialize, Serialize}; - use serde_crate::ser::SerializeSeq; - use serde_crate::{Deserializer, Serializer}; - - use super::*; - use crate::ScriptBytes; - - impl Serialize for Witness { - fn serialize(&self, serializer: S) -> Result - where S: Serializer { - let mut ser = serializer.serialize_seq(Some(self.len()))?; - for el in &self.0 { - ser.serialize_element(&ScriptBytes::from(el.to_inner()))?; - } - ser.end() - } - } - - impl<'de> Deserialize<'de> for Witness { - fn deserialize(deserializer: D) -> Result - where D: Deserializer<'de> { - let data = Vec::::deserialize(deserializer)?; - Ok(Witness::from_consensus_stack(data.into_iter().map(ScriptBytes::into_vec))) - } - } -} - #[derive(Clone, Eq, PartialEq, Hash, Debug)] #[derive(StrictType, StrictDumb, StrictEncode, StrictDecode)] #[strict_type(lib = LIB_NAME_BITCOIN)] From aff9ff183768ff0fabb0b53d02aa2bdfdc4b9491 Mon Sep 17 00:00:00 2001 From: Dr Maxim Orlovsky Date: Thu, 5 Oct 2023 23:14:40 +0200 Subject: [PATCH 04/31] primitives: rename consensus into coding module --- primitives/src/{consensus.rs => coding.rs} | 0 primitives/src/lib.rs | 4 ++-- 2 files changed, 2 insertions(+), 2 deletions(-) rename primitives/src/{consensus.rs => coding.rs} (100%) diff --git a/primitives/src/consensus.rs b/primitives/src/coding.rs similarity index 100% rename from primitives/src/consensus.rs rename to primitives/src/coding.rs diff --git a/primitives/src/lib.rs b/primitives/src/lib.rs index 569e48ea..cb8fa90e 100644 --- a/primitives/src/lib.rs +++ b/primitives/src/lib.rs @@ -56,10 +56,10 @@ mod util; mod weights; #[cfg(feature = "stl")] pub mod stl; -mod consensus; +mod coding; pub use block::{BlockHash, BlockHeader}; -pub use consensus::{ +pub use coding::{ ConsensusDataError, ConsensusDecode, ConsensusDecodeError, ConsensusEncode, VarIntArray, VarIntSize, }; From 5039b71c02a065f947140a472b7e490cb2f3f640 Mon Sep 17 00:00:00 2001 From: Dr Maxim Orlovsky Date: Thu, 5 Oct 2023 23:19:57 +0200 Subject: [PATCH 05/31] stl: rename Bitcoin into BP Tx library --- primitives/src/stl.rs | 19 +++++++++++++++---- src/bin/bpcore-stl.rs | 4 ++-- src/stl.rs | 2 +- stl/Bitcoin@0.1.0.sty | 2 +- 4 files changed, 19 insertions(+), 8 deletions(-) diff --git a/primitives/src/stl.rs b/primitives/src/stl.rs index addee42b..6345f6fc 100644 --- a/primitives/src/stl.rs +++ b/primitives/src/stl.rs @@ -24,16 +24,27 @@ use strict_types::{CompileError, LibBuilder, TypeLib}; use crate::{Tx, LIB_NAME_BITCOIN}; +#[deprecated(since = "0.10.8", note = "use LIB_ID_BP_TX instead")] pub const LIB_ID_BITCOIN: &str = "urn:ubideco:stl:6GgF7biXPVNcus2FfQj2pQuRzau11rXApMQLfCZhojgi#money-pardon-parody"; +pub const LIB_ID_BP_TX: &str = + "urn:ubideco:stl:6GgF7biXPVNcus2FfQj2pQuRzau11rXApMQLfCZhojgi#money-pardon-parody"; + +#[deprecated(since = "0.10.8", note = "use _bp_tx_stl instead")] +fn _bitcoin_stl() -> Result { _bp_tx_stl() } -fn _bitcoin_stl() -> Result { +fn _bp_tx_stl() -> Result { LibBuilder::new(libname!(LIB_NAME_BITCOIN), None) .transpile::() .compile() } -pub fn bitcoin_stl() -> TypeLib { _bitcoin_stl().expect("invalid strict type Bitcoin library") } +#[deprecated(since = "0.10.8", note = "use bp_tx_stl instead")] +pub fn bitcoin_stl() -> TypeLib { bp_tx_stl() } + +pub fn bp_tx_stl() -> TypeLib { + _bp_tx_stl().expect("invalid strict type Bitcoin transaction library") +} #[cfg(test)] mod test { @@ -41,7 +52,7 @@ mod test { #[test] fn lib_id() { - let lib = bitcoin_stl(); - assert_eq!(lib.id().to_string(), LIB_ID_BITCOIN); + let lib = bp_tx_stl(); + assert_eq!(lib.id().to_string(), LIB_ID_BP_TX); } } diff --git a/src/bin/bpcore-stl.rs b/src/bin/bpcore-stl.rs index 6340bca1..dfa8a2cc 100644 --- a/src/bin/bpcore-stl.rs +++ b/src/bin/bpcore-stl.rs @@ -24,14 +24,14 @@ use strict_types::parse_args; fn main() { let (format, dir) = parse_args(); - bc::stl::bitcoin_stl() + bc::stl::bp_tx_stl() .serialize( format, dir.as_ref(), "0.1.0", Some( " - Description: Consensus layer for bitcoin protocol + Description: Consensus transaction library for bitcoin protocol Author: Dr Maxim Orlovsky Copyright (C) 2023 LNP/BP Standards Association. All rights reserved. License: Apache-2.0", diff --git a/src/stl.rs b/src/stl.rs index ddafba9e..005f26b9 100644 --- a/src/stl.rs +++ b/src/stl.rs @@ -35,7 +35,7 @@ pub const LIB_ID_BPCORE: &str = fn _bp_core_stl() -> Result { LibBuilder::new(libname!(LIB_NAME_BPCORE), tiny_bset! { strict_types::stl::std_stl().to_dependency(), - bc::stl::bitcoin_stl().to_dependency(), + bc::stl::bp_tx_stl().to_dependency(), commit_verify::stl::commit_verify_stl().to_dependency() }) .transpile::() diff --git a/stl/Bitcoin@0.1.0.sty b/stl/Bitcoin@0.1.0.sty index deed2a6e..047270e4 100644 --- a/stl/Bitcoin@0.1.0.sty +++ b/stl/Bitcoin@0.1.0.sty @@ -2,7 +2,7 @@ Id: urn:ubideco:stl:6GgF7biXPVNcus2FfQj2pQuRzau11rXApMQLfCZhojgi#money-pardon-parody Name: Bitcoin Version: 0.1.0 - Description: Consensus layer for bitcoin protocol + Description: Consensus transaction library for bitcoin protocol Author: Dr Maxim Orlovsky Copyright (C) 2023 LNP/BP Standards Association. All rights reserved. License: Apache-2.0 From 4d8a411ae17a59573a1c9defd3909b66c6007df5 Mon Sep 17 00:00:00 2001 From: Dr Maxim Orlovsky Date: Fri, 6 Oct 2023 00:14:36 +0200 Subject: [PATCH 06/31] primitives: add explicit taproot module exports --- primitives/src/lib.rs | 6 +++++- primitives/src/taproot.rs | 9 +++++---- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/primitives/src/lib.rs b/primitives/src/lib.rs index cb8fa90e..c7b6c696 100644 --- a/primitives/src/lib.rs +++ b/primitives/src/lib.rs @@ -68,7 +68,11 @@ pub use segwit::{SegwitError, Witness, WitnessProgram, WitnessScript, WitnessVer pub use sigtypes::{ Bip340Sig, LegacySig, NonStandardSighashType, SigError, SighashFlag, SighashType, }; -pub use taproot::*; +pub use taproot::{ + FutureLeafVer, InternalPk, IntoTapHash, InvalidLeafVer, LeafScript, LeafVer, TapBranchHash, + TapCode, TapLeafHash, TapMerklePath, TapNodeHash, TapScript, TAPROOT_ANNEX_PREFIX, + TAPROOT_LEAF_MASK, TAPROOT_LEAF_TAPSCRIPT, +}; pub use tx::{ LockTime, Outpoint, OutpointParseError, Sats, SeqNo, Tx, TxIn, TxOut, TxParseError, TxVer, Txid, Vout, LOCKTIME_THRESHOLD, diff --git a/primitives/src/taproot.rs b/primitives/src/taproot.rs index 563bb15d..071321cc 100644 --- a/primitives/src/taproot.rs +++ b/primitives/src/taproot.rs @@ -38,19 +38,20 @@ use crate::opcodes::*; use crate::{ScriptBytes, ScriptPubkey, WitnessVer, LIB_NAME_BITCOIN}; /// The SHA-256 midstate value for the TapLeaf hash. -pub const MIDSTATE_TAPLEAF: [u8; 7] = *b"TapLeaf"; +const MIDSTATE_TAPLEAF: [u8; 7] = *b"TapLeaf"; // 9ce0e4e67c116c3938b3caf2c30f5089d3f3936c47636e607db33eeaddc6f0c9 /// The SHA-256 midstate value for the TapBranch hash. -pub const MIDSTATE_TAPBRANCH: [u8; 9] = *b"TapBranch"; +const MIDSTATE_TAPBRANCH: [u8; 9] = *b"TapBranch"; // 23a865a9b8a40da7977c1e04c49e246fb5be13769d24c9b7b583b5d4a8d226d2 /// The SHA-256 midstate value for the TapTweak hash. -pub const MIDSTATE_TAPTWEAK: [u8; 8] = *b"TapTweak"; +const MIDSTATE_TAPTWEAK: [u8; 8] = *b"TapTweak"; // d129a2f3701c655d6583b6c3b941972795f4e23294fd54f4a2ae8d8547ca590b /// The SHA-256 midstate value for the TapSig hash. -pub const MIDSTATE_TAPSIGHASH: [u8; 10] = *b"TapSighash"; +#[warn(dead_code)] +const MIDSTATE_TAPSIGHASH: [u8; 10] = *b"TapSighash"; // f504a425d7f8783b1363868ae3e556586eee945dbc7888dd02a6e2c31873fe9f #[derive(Copy, Clone, Eq, PartialEq, Debug, Display, Error)] From 250f1195e1731a978e604f268f4ed0f91a2f046d Mon Sep 17 00:00:00 2001 From: Dr Maxim Orlovsky Date: Fri, 6 Oct 2023 00:15:37 +0200 Subject: [PATCH 07/31] stl: rename Bitcoin into Tx library --- src/bin/bpcore-stl.rs | 18 +++++++++++++++- stl/Tx@0.1.0.sta | 26 ++++++++++++++++++++++ stl/Tx@0.1.0.stl | Bin 0 -> 816 bytes stl/Tx@0.1.0.sty | 49 ++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 92 insertions(+), 1 deletion(-) create mode 100644 stl/Tx@0.1.0.sta create mode 100644 stl/Tx@0.1.0.stl create mode 100644 stl/Tx@0.1.0.sty diff --git a/src/bin/bpcore-stl.rs b/src/bin/bpcore-stl.rs index dfa8a2cc..cab5a37d 100644 --- a/src/bin/bpcore-stl.rs +++ b/src/bin/bpcore-stl.rs @@ -19,12 +19,28 @@ // See the License for the specific language governing permissions and // limitations under the License. +use strict_encoding::libname; use strict_types::parse_args; fn main() { let (format, dir) = parse_args(); - bc::stl::bp_tx_stl() + let mut lib = bc::stl::bp_tx_stl(); + lib.name = libname!("Tx"); + lib.serialize( + format, + dir.as_ref(), + "0.1.0", + Some( + " + Description: Bitcoin transaction library + Author: Dr Maxim Orlovsky + Copyright (C) 2023 LNP/BP Standards Association. All rights reserved. + License: Apache-2.0", + ), + ) + .expect("unable to write to the file"); + .serialize( format, dir.as_ref(), diff --git a/stl/Tx@0.1.0.sta b/stl/Tx@0.1.0.sta new file mode 100644 index 00000000..167f7b48 --- /dev/null +++ b/stl/Tx@0.1.0.sta @@ -0,0 +1,26 @@ +-----BEGIN STRICT TYPE LIB----- +Id: urn:ubideco:stl:5PUqZnqASPU3zKASh2pTHYmfcV4pZfvt4UU8FxPsRt6S +Name: Tx +Dependencies: ~ + +AlR4AAAOAAhMb2NrVGltZQUBAAAECE91dHBvaW50BgIEdHhpZAGjgkLzy9fR0KES +2o3hYC9W1PhvDsTEdsXAaFlMSwRlVgR2b3V0ASHjPkPFqlzyKSdTozjBZ+07Y5xN +2c69qY80aRe6yUN1BFNhdHMFAQAACAtTY3JpcHRCeXRlcwUBAAgAAEAAAAAAAAAA +AP////8AAAAADFNjcmlwdFB1YmtleQUBASWr9bkSFBe6oznUX3sVdadxS+F6dRhd +0DE1etTJLemGBVNlcU5vBQEAAAQJU2lnU2NyaXB0BQEBJav1uRIUF7qjOdRfexV1 +p3FL4Xp1GF3QMTV61Mkt6YYCVHgGBAd2ZXJzaW9uAah8xnlkZ+VX10TlyWI64AzL +ldkaDS8D33TAdRJPvseeBmlucHV0cwAIARlHLRfYYgenDyExqVihaKVuKtZTP5xm +TBl32lz5/mKGAAAAAAAAAAD/////AAAAAAdvdXRwdXRzAAgBkDtkcHmEjxsmUyrk +zsamiUSgU1i48IHLJrO7+C2eO/MAAAAAAAAAAP////8AAAAACGxvY2tUaW1lATXa +HRU5IG673dykwz2HMerym6fadN89yIIgHE4WtbkcBFR4SW4GBApwcmV2T3V0cHV0 +AehqQM1cJfm94oT/aaURMqdBKyFVvQ5WEsG/44SVYMUGCXNpZ1NjcmlwdAE4dQSx +S3wORm1HnhdHfSR0JH/4A2TsPUuq9zog90F0awhzZXF1ZW5jZQEBGW2FKcj22kRN +FU6NnIy9ng+NiQJaO7CRIcY9UrAehwd3aXRuZXNzAXN3Q3A2kyBJzSiVCKpxfOOC +nbJFLlXoTtT8LjzNLgCdBVR4T3V0BgIFdmFsdWUBl/XXBkKuKjOSJTuoTh3OxJPj +vz7TcbGHc4Y1TsyIgmsMc2NyaXB0UHVia2V5Ab78HvxmpRn9ZFJqOhOHQOfxEC0L +vv86wUZO8/dAdnRcBVR4VmVyBQEAAEQEVHhpZAUBAAcAAEAgAARWb3V0BQEAAAQH +V2l0bmVzcwUBAAgACAAAQAAAAAAAAAAA/////wAAAAAAAAAAAAAAAP////8AAAAA + + +-----END STRICT TYPE LIB----- + diff --git a/stl/Tx@0.1.0.stl b/stl/Tx@0.1.0.stl new file mode 100644 index 0000000000000000000000000000000000000000..79ac39a82350f5777d6094707d7631f10be3ff8b GIT binary patch literal 816 zcmZPysbFB>W8m<~PtFd>%uQuwWME+7@GmVX$j{6xVPj$`smM%WT-@aJ`SkUR7ZwWL z>V24?A9m$OKHrfeWk(NWMEZEMq=vDS<(HN)Dn7PzKDsLAlcsv`VvB?6Z>^K(_})CX zcV)jxrueRt&ZR8Di6zA#3pluglZ!G7N}MW7Qb7V73=9qoQ1BlJKujKpl7P~r?9@tD zMn=`uUv~b`7a4Nfie%LhB3GdMFHqMHbP zOd%C)EbL{eMa7xQ*TP~>NDRjIZ!I(zwh`ww#>YO z(vo5Z4n|3LUGW=9?92HT4Od1i%vhSIbuHL_PMVKo`K_3r|B~9!{lg9nA*j{~)+q&* zE&bAJ!CFtw9b4AvvLHBO$A`w#YMXce(4A-f8C@$!4m5HYO>fDHS}Nr2zI$iMVcT}Y zSD$7tzg2SI_C%9{jGx%noiZ#T6`px)EL;Uesb!!z1V+k>EQhl(sz3KWYWbhJRM2R- zqqbt`UcNA)gZm%1Oieh-##sytEJlk`mW|#ud~Uh!^Tge2RZ3Lqe=w)KvGrc{-AduR zV@WngacW^{YF=_GBco()tLBMsw_JQh{d(v0?48Ho+sPDVyY$t7=kE?>B{4w5!%~YtNx}sfFqtVp7CSJdDKM~v0V4yPRM^8I O4h3>JuqH$FxBviZI5tH9 literal 0 HcmV?d00001 diff --git a/stl/Tx@0.1.0.sty b/stl/Tx@0.1.0.sty new file mode 100644 index 00000000..b519eb01 --- /dev/null +++ b/stl/Tx@0.1.0.sty @@ -0,0 +1,49 @@ +{- + Id: urn:ubideco:stl:5PUqZnqASPU3zKASh2pTHYmfcV4pZfvt4UU8FxPsRt6S#winter-horizon-binary + Name: Tx + Version: 0.1.0 + Description: Consensus transaction library for bitcoin protocol + Author: Dr Maxim Orlovsky + Copyright (C) 2023 LNP/BP Standards Association. All rights reserved. + License: Apache-2.0 +-} + +typelib Tx + +-- no dependencies + +-- urn:ubideco:semid:4dDWWU4afiPN3q4AgCMuFRFhL4UDta2u5SrqrBzPvjby#tokyo-inch-program +data LockTime :: U32 +-- urn:ubideco:semid:FWt2MSo8A4nsYgYbuBqMRNLiKgtzvLBgUn774iKzTcuf#pocket-pegasus-frank +data Outpoint :: txid Txid, vout Vout +-- urn:ubideco:semid:BEBz6h7AGjYSDRCxVHnjYkkkxzBsjN3EvyNiD4ZrzmRL#pyramid-spray-star +data Sats :: U64 +-- urn:ubideco:semid:3Y4AgjkFbDusgo3YqRDWv9BznDeAJEUDEPeEq1mpSkAR#maestro-source-jackson +data ScriptBytes :: [Byte ^ ..0xffffffff] +-- urn:ubideco:semid:2ZAYpWKB2BQxeXXjpQDpYGZ7eXFM9qQxN9TcdTiQqeB8#bingo-maestro-silk +data ScriptPubkey :: ScriptBytes +-- urn:ubideco:semid:5HtymNhYBhjqPkLLw9QVWZ62cLm57cZxgQTDUBBXtmL#rhino-time-rodent +data SeqNo :: U32 +-- urn:ubideco:semid:2gTMqAC393rBSGtBhDn8sJq3F3HtDosbqKDQTw9bHFyT#prelude-analyze-think +data SigScript :: ScriptBytes +-- urn:ubideco:semid:DynChojW1sfr8VjSoZbmReHhZoU8u9KCiuwijgEGdToe#milk-gloria-prize +data Tx :: version TxVer + , inputs [TxIn ^ ..0xffffffff] + , outputs [TxOut ^ ..0xffffffff] + , lockTime LockTime +-- urn:ubideco:semid:9Nf4Vvt3im8tFQSGzPWKfjfhsrkB8bf2XsLWfzywiFSv#antenna-crater-planet +data TxIn :: prevOutput Outpoint + , sigScript SigScript + , sequence SeqNo + , witness Witness +-- urn:ubideco:semid:HutVbeKmYYrNun96Pi4T7YfYww7SeWxRFPZGDiZwoGZV#design-jacket-spirit +data TxOut :: value Sats, scriptPubkey ScriptPubkey +-- urn:ubideco:semid:CLhr1zatQBSkCz9SiVrNoKB5igCZfF3hqRizfrviM6NR#english-natasha-virus +data TxVer :: I32 +-- urn:ubideco:semid:C1GfCrG7AXu2sFhRBspd7KpJK2YgyTkVy6pty5rZynRs#cowboy-diego-betty +data Txid :: [Byte ^ 32] +-- urn:ubideco:semid:3HHRtSJW5fnGkdVW1EVDH7B97Y79WhwvKyyfsaBkuQkk#chrome-robin-gallop +data Vout :: U32 +-- urn:ubideco:semid:8mjN2CZj3Nhn2HjnKqTmEcN5vmyb3UJK8HSFW1uE3W2p#warning-saddle-period +data Witness :: [[Byte ^ ..0xffffffff] ^ ..0xffffffff] + From d4d1979503e5ae93064373fea8323025a6de2850 Mon Sep 17 00:00:00 2001 From: Dr Maxim Orlovsky Date: Fri, 6 Oct 2023 00:16:19 +0200 Subject: [PATCH 08/31] primitives: enforce witness program length at type level --- primitives/src/segwit.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/primitives/src/segwit.rs b/primitives/src/segwit.rs index f3c438ca..ad34fbeb 100644 --- a/primitives/src/segwit.rs +++ b/primitives/src/segwit.rs @@ -214,15 +214,15 @@ pub struct WitnessProgram { /// The witness program version. version: WitnessVer, /// The witness program. (Between 2 and 40 bytes) - program: Vec, + program: Confined, 2, 40>, } impl WitnessProgram { /// Creates a new witness program. pub fn new(version: WitnessVer, program: Vec) -> Result { - if program.len() < 2 || program.len() > 40 { - return Err(SegwitError::InvalidWitnessProgramLength(program.len())); - } + let len = program.len(); + let program = Confined::try_from(program) + .map_err(|_| SegwitError::InvalidWitnessProgramLength(len))?; // Specific segwit v0 check. These addresses can never spend funds sent // to them. From a1850fc1714b7e311a5430f389882a23cea67b85 Mon Sep 17 00:00:00 2001 From: Dr Maxim Orlovsky Date: Fri, 6 Oct 2023 00:16:32 +0200 Subject: [PATCH 09/31] stl: add Bitcoin Consensus library --- primitives/src/block.rs | 2 + primitives/src/script.rs | 2 + primitives/src/segwit.rs | 7 +++ primitives/src/sigtypes.rs | 103 ++++++++++++++++++++++++++++++++++++- primitives/src/stl.rs | 52 ++++++++++++++++++- primitives/src/taproot.rs | 8 ++- primitives/src/util.rs | 4 +- primitives/src/weights.rs | 6 ++- src/bin/bpcore-stl.rs | 3 +- stl/Bitcoin@0.1.0.sta | 72 +++++++++++++++++++------- stl/Bitcoin@0.1.0.stl | Bin 821 -> 2328 bytes stl/Bitcoin@0.1.0.sty | 79 +++++++++++++++++++++++++++- 12 files changed, 308 insertions(+), 30 deletions(-) diff --git a/primitives/src/block.rs b/primitives/src/block.rs index a8375cf0..7529eb58 100644 --- a/primitives/src/block.rs +++ b/primitives/src/block.rs @@ -47,6 +47,8 @@ impl FromHex for BlockHash { } #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] +#[derive(StrictType, StrictEncode, StrictDecode, StrictDumb)] +#[strict_type(lib = LIB_NAME_BITCOIN)] #[cfg_attr( feature = "serde", derive(Serialize, Deserialize), diff --git a/primitives/src/script.rs b/primitives/src/script.rs index d3bceb4f..adbb1448 100644 --- a/primitives/src/script.rs +++ b/primitives/src/script.rs @@ -226,6 +226,8 @@ impl FromHex for ScriptPubkey { #[derive(Wrapper, WrapperMut, Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Debug, From, Default)] #[wrapper(Deref, Index, RangeOps, BorrowSlice, LowerHex, UpperHex)] #[wrapper_mut(DerefMut, IndexMut, RangeMut, BorrowSliceMut)] +#[derive(StrictType, StrictEncode, StrictDecode)] +#[strict_type(lib = LIB_NAME_BITCOIN)] #[cfg_attr( feature = "serde", derive(Serialize, Deserialize), diff --git a/primitives/src/segwit.rs b/primitives/src/segwit.rs index ad34fbeb..8b462a1f 100644 --- a/primitives/src/segwit.rs +++ b/primitives/src/segwit.rs @@ -49,9 +49,12 @@ pub enum SegwitError { /// First byte of `scriptPubkey` in transaction output for transactions starting /// with 0 and 0x51-0x60 (inclusive). #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Display)] +#[derive(StrictType, StrictEncode, StrictDecode, StrictDumb)] +#[strict_type(lib = LIB_NAME_BITCOIN, tags = repr, into_u8, try_from_u8)] #[repr(u8)] pub enum WitnessVer { /// Initial version of witness program. Used for P2WPKH and P2WPK outputs + #[strict_type(dumb)] #[display("segwit0")] V0 = OP_PUSHBYTES_0, @@ -210,6 +213,8 @@ impl WitnessVer { /// Witness program as defined in BIP141. #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] +#[derive(StrictType, StrictEncode, StrictDecode, StrictDumb)] +#[strict_type(lib = LIB_NAME_BITCOIN, dumb = {Self::new(strict_dumb!(), vec![0; 32]).unwrap()})] pub struct WitnessProgram { /// The witness program version. version: WitnessVer, @@ -299,6 +304,8 @@ impl ScriptPubkey { #[derive(Wrapper, WrapperMut, Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Debug, From, Default)] #[wrapper(Deref, Index, RangeOps, BorrowSlice, LowerHex, UpperHex)] #[wrapper_mut(DerefMut, IndexMut, RangeMut, BorrowSliceMut)] +#[derive(StrictType, StrictEncode, StrictDecode)] +#[strict_type(lib = LIB_NAME_BITCOIN)] #[cfg_attr( feature = "serde", derive(Serialize, Deserialize), diff --git a/primitives/src/sigtypes.rs b/primitives/src/sigtypes.rs index 1177fdbf..7a070705 100644 --- a/primitives/src/sigtypes.rs +++ b/primitives/src/sigtypes.rs @@ -23,13 +23,17 @@ use std::iter; use secp256k1::{ecdsa, schnorr}; +use crate::LIB_NAME_BITCOIN; + /// This type is consensus valid but an input including it would prevent the /// transaction from being relayed on today's Bitcoin network. #[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Display, Error)] #[display("non-standard SIGHASH_TYPE value {0:#X}")] pub struct NonStandardSighashType(pub u32); -#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)] +#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash, Default)] +#[derive(StrictType, StrictEncode, StrictDecode)] +#[strict_type(lib = LIB_NAME_BITCOIN, tags = repr, into_u8, try_from_u8)] #[cfg_attr( feature = "serde", derive(Serialize, Deserialize), @@ -38,6 +42,7 @@ pub struct NonStandardSighashType(pub u32); #[repr(u8)] pub enum SighashFlag { /// 0x1: Sign all outputs. + #[default] All = 0x01, /// 0x2: Sign no outputs --- anyone can choose the destination. None = 0x02, @@ -49,7 +54,9 @@ pub enum SighashFlag { Single = 0x03, } -#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)] +#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash, Default)] +#[derive(StrictType, StrictEncode, StrictDecode)] +#[strict_type(lib = LIB_NAME_BITCOIN)] #[cfg_attr( feature = "serde", derive(Serialize, Deserialize), @@ -204,6 +211,8 @@ pub enum SigError { } #[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)] +#[derive(StrictType)] +#[strict_type(lib = LIB_NAME_BITCOIN)] #[cfg_attr( feature = "serde", derive(Serialize, Deserialize), @@ -248,6 +257,8 @@ impl LegacySig { } #[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)] +#[derive(StrictType)] +#[strict_type(lib = LIB_NAME_BITCOIN)] #[cfg_attr( feature = "serde", derive(Serialize, Deserialize), @@ -295,3 +306,91 @@ impl Bip340Sig { ser } } + +mod _strict_encode { + use std::io; + + use amplify::confinement::TinyBlob; + use amplify::hex::FromHex; + use amplify::Bytes64; + use strict_encoding::{ + DecodeError, ReadStruct, StrictDecode, StrictDumb, StrictEncode, TypedRead, TypedWrite, + WriteStruct, + }; + + use super::*; + + impl StrictDumb for LegacySig { + fn strict_dumb() -> Self { + Self { + sig: ecdsa::Signature::from_der(&Vec::::from_hex( + "304402206fa6c164fb89906e2e1d291cc5461ceadf0f115c6b71e58f87482c94d512c3630220\ + 0ab641f3ece1d77f13ad2d8910cb7abd5a9b85f0f9036317dbb1470f22e7714c").unwrap() + ).expect("hardcoded signature"), + sighash_type: default!(), + } + } + } + + impl StrictEncode for LegacySig { + fn strict_encode(&self, writer: W) -> io::Result { + writer.write_struct::(|w| { + Ok(w.write_field( + fname!("sig"), + &TinyBlob::try_from(self.sig.serialize_der().to_vec()) + .expect("invalid signature"), + )? + .write_field(fname!("sighash_type"), &self.sighash_type)? + .complete()) + }) + } + } + + impl StrictDecode for LegacySig { + fn strict_decode(reader: &mut impl TypedRead) -> Result { + reader.read_struct(|r| { + let bytes: TinyBlob = r.read_field(fname!("sig"))?; + let sig = ecdsa::Signature::from_der(bytes.as_slice()).map_err(|_| { + DecodeError::DataIntegrityError(s!("invalid signature DER encoding")) + })?; + let sighash_type = r.read_field(fname!("sighash_type"))?; + Ok(Self { sig, sighash_type }) + }) + } + } + + impl StrictDumb for Bip340Sig { + fn strict_dumb() -> Self { + Bip340Sig::from_bytes(&Vec::::from_hex( + "a12b3f4c224619d7834f0bad0a598b79111ba08146ae1205f3e6220a132aef0ed8290379624db643\ + e6b861d8dcd37b406a11f91a51bf5a6cdf9b3c9b772f67c301" + ).unwrap()) + .expect("hardcoded signature") + } + } + + impl StrictEncode for Bip340Sig { + fn strict_encode(&self, writer: W) -> io::Result { + writer.write_struct::(|w| { + Ok(w.write_field(fname!("sig"), &Bytes64::from(*self.sig.as_ref()))? + .write_field(fname!("sighash_type"), &self.sighash_type)? + .complete()) + }) + } + } + + impl StrictDecode for Bip340Sig { + fn strict_decode(reader: &mut impl TypedRead) -> Result { + reader.read_struct(|r| { + let bytes: Bytes64 = r.read_field(fname!("sig"))?; + let sig = schnorr::Signature::from_slice(bytes.as_slice()).map_err(|_| { + DecodeError::DataIntegrityError(format!( + "invalid signature BIP340 encoding '{bytes:x}'" + )) + })?; + let sighash_type = r.read_field(fname!("sighash_type"))?; + Ok(Self { sig, sighash_type }) + }) + } + } +} diff --git a/primitives/src/stl.rs b/primitives/src/stl.rs index 6345f6fc..272a444d 100644 --- a/primitives/src/stl.rs +++ b/primitives/src/stl.rs @@ -22,13 +22,20 @@ use strict_types::{CompileError, LibBuilder, TypeLib}; -use crate::{Tx, LIB_NAME_BITCOIN}; +use crate::{ + Bip340Sig, BlockHeader, Chain, FutureLeafVer, InternalPk, LeafScript, LeafVer, LegacySig, + OpCode, RedeemScript, TapBranchHash, TapCode, TapLeafHash, TapMerklePath, TapNodeHash, + TapScript, Tx, VBytes, VarInt, WeightUnits, WitnessProgram, WitnessScript, WitnessVer, Wtxid, + LIB_NAME_BITCOIN, +}; #[deprecated(since = "0.10.8", note = "use LIB_ID_BP_TX instead")] pub const LIB_ID_BITCOIN: &str = "urn:ubideco:stl:6GgF7biXPVNcus2FfQj2pQuRzau11rXApMQLfCZhojgi#money-pardon-parody"; pub const LIB_ID_BP_TX: &str = "urn:ubideco:stl:6GgF7biXPVNcus2FfQj2pQuRzau11rXApMQLfCZhojgi#money-pardon-parody"; +pub const LIB_ID_BP_CONSENSUS: &str = + "urn:ubideco:stl:HeTuSir1NWBfMe11Zf3dfw9uCrmfsSNdCaCaaLJQpQ91#apropos-milk-order"; #[deprecated(since = "0.10.8", note = "use _bp_tx_stl instead")] fn _bitcoin_stl() -> Result { _bp_tx_stl() } @@ -39,6 +46,37 @@ fn _bp_tx_stl() -> Result { .compile() } +fn _bp_consensus_stl() -> Result { + LibBuilder::new(libname!(LIB_NAME_BITCOIN), tiny_bset! { + strict_types::stl::std_stl().to_dependency(), + }) + .transpile::() + .transpile::() + .transpile::() + .transpile::() + .transpile::() + .transpile::() + .transpile::() + .transpile::() + .transpile::() + .transpile::() + .transpile::() + .transpile::() + .transpile::() + .transpile::() + .transpile::() + .transpile::() + .transpile::() + .transpile::() + .transpile::() + .transpile::() + .transpile::() + .transpile::() + .transpile::() + .transpile::() + .compile() +} + #[deprecated(since = "0.10.8", note = "use bp_tx_stl instead")] pub fn bitcoin_stl() -> TypeLib { bp_tx_stl() } @@ -46,13 +84,23 @@ pub fn bp_tx_stl() -> TypeLib { _bp_tx_stl().expect("invalid strict type Bitcoin transaction library") } +pub fn bp_consensus_stl() -> TypeLib { + _bp_consensus_stl().expect("invalid strict type Bitcoin consensus library") +} + #[cfg(test)] mod test { use super::*; #[test] - fn lib_id() { + fn lib_id_tx() { let lib = bp_tx_stl(); assert_eq!(lib.id().to_string(), LIB_ID_BP_TX); } + + #[test] + fn lib_id_consensus() { + let lib = bp_consensus_stl(); + assert_eq!(lib.id().to_string(), LIB_ID_BP_CONSENSUS); + } } diff --git a/primitives/src/taproot.rs b/primitives/src/taproot.rs index 071321cc..0f6da74f 100644 --- a/primitives/src/taproot.rs +++ b/primitives/src/taproot.rs @@ -130,6 +130,8 @@ pub trait IntoTapHash { #[derive(Wrapper, Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Debug, From)] #[wrapper(Index, RangeOps, BorrowSlice, Hex, Display, FromStr)] +#[derive(StrictType, StrictEncode, StrictDecode, StrictDumb)] +#[strict_type(lib = LIB_NAME_BITCOIN)] #[cfg_attr( feature = "serde", derive(Serialize, Deserialize), @@ -163,6 +165,8 @@ impl IntoTapHash for TapLeafHash { #[derive(Wrapper, Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Debug, From)] #[wrapper(Index, RangeOps, BorrowSlice, Hex, Display, FromStr)] +#[derive(StrictType, StrictEncode, StrictDecode, StrictDumb)] +#[strict_type(lib = LIB_NAME_BITCOIN)] #[cfg_attr( feature = "serde", derive(Serialize, Deserialize), @@ -208,8 +212,10 @@ impl IntoTapHash for TapNodeHash { fn into_tap_hash(self) -> TapNodeHash { self } } -#[derive(Wrapper, Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Debug, From)] +#[derive(Wrapper, Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Debug, From, Default)] #[wrapper(Deref)] +#[derive(StrictType, StrictEncode, StrictDecode)] +#[strict_type(lib = LIB_NAME_BITCOIN)] #[cfg_attr( feature = "serde", derive(Serialize, Deserialize), diff --git a/primitives/src/util.rs b/primitives/src/util.rs index cef8139c..37fb198d 100644 --- a/primitives/src/util.rs +++ b/primitives/src/util.rs @@ -94,7 +94,9 @@ impl Chain { } /// A variable-length unsigned integer. -#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug)] +#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Default)] +#[derive(StrictType, StrictEncode, StrictDecode)] +#[strict_type(lib = LIB_NAME_BITCOIN)] pub struct VarInt(pub u64); #[allow(clippy::len_without_is_empty)] // VarInt has no concept of 'is_empty'. diff --git a/primitives/src/weights.rs b/primitives/src/weights.rs index e9436e78..5147642f 100644 --- a/primitives/src/weights.rs +++ b/primitives/src/weights.rs @@ -22,9 +22,11 @@ use std::iter::Sum; use std::ops::{Add, AddAssign}; -use crate::{ScriptPubkey, SigScript, Tx, TxIn, TxOut, VarIntSize, Witness}; +use crate::{ScriptPubkey, SigScript, Tx, TxIn, TxOut, VarIntSize, Witness, LIB_NAME_BITCOIN}; #[derive(Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Debug, Display)] +#[derive(StrictType, StrictEncode, StrictDecode, StrictDumb)] +#[strict_type(lib = LIB_NAME_BITCOIN)] #[display("{0} vbytes")] pub struct VBytes(u32); @@ -47,6 +49,8 @@ impl VBytes { } #[derive(Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Debug, Display)] +#[derive(StrictType, StrictEncode, StrictDecode, StrictDumb)] +#[strict_type(lib = LIB_NAME_BITCOIN)] #[display("{0} WU")] pub struct WeightUnits(u32); diff --git a/src/bin/bpcore-stl.rs b/src/bin/bpcore-stl.rs index cab5a37d..483c26d1 100644 --- a/src/bin/bpcore-stl.rs +++ b/src/bin/bpcore-stl.rs @@ -41,13 +41,14 @@ fn main() { ) .expect("unable to write to the file"); + bc::stl::bp_consensus_stl() .serialize( format, dir.as_ref(), "0.1.0", Some( " - Description: Consensus transaction library for bitcoin protocol + Description: Consensus library for bitcoin protocol Author: Dr Maxim Orlovsky Copyright (C) 2023 LNP/BP Standards Association. All rights reserved. License: Apache-2.0", diff --git a/stl/Bitcoin@0.1.0.sta b/stl/Bitcoin@0.1.0.sta index c49fed3f..a96ca784 100644 --- a/stl/Bitcoin@0.1.0.sta +++ b/stl/Bitcoin@0.1.0.sta @@ -1,26 +1,58 @@ -----BEGIN STRICT TYPE LIB----- -Id: urn:ubideco:stl:6GgF7biXPVNcus2FfQj2pQuRzau11rXApMQLfCZhojgi +Id: urn:ubideco:stl:HeTuSir1NWBfMe11Zf3dfw9uCrmfsSNdCaCaaLJQpQ91 Name: Bitcoin -Dependencies: ~ +Dependencies: + urn:ubideco:stl:9KALDYR8Nyjq4FdMW6kYoL7vdkWnqPqNuFnmE9qHpNjZ -B0JpdGNvaW4AAA4ACExvY2tUaW1lBQEAAAQIT3V0cG9pbnQGAgR0eGlkAaOCQvPL -19HQoRLajeFgL1bU+G8OxMR2xcBoWUxLBGVWBHZvdXQBIeM+Q8WqXPIpJ1OjOMFn -7TtjnE3Zzr2pjzRpF7rJQ3UEU2F0cwUBAAAIC1NjcmlwdEJ5dGVzBQEACAAAQAAA -AAAAAAAA/////wAAAAAMU2NyaXB0UHVia2V5BQEBJav1uRIUF7qjOdRfexV1p3FL -4Xp1GF3QMTV61Mkt6YYFU2VxTm8FAQAABAlTaWdTY3JpcHQFAQElq/W5EhQXuqM5 -1F97FXWncUvhenUYXdAxNXrUyS3phgJUeAYEB3ZlcnNpb24BqHzGeWRn5VfXROXJ -YjrgDMuV2RoNLwPfdMB1Ek++x54GaW5wdXRzAAgBGUctF9hiB6cPITGpWKFopW4q -1lM/nGZMGXfaXPn+YoYAAAAAAAAAAP////8AAAAAB291dHB1dHMACAGQO2RweYSP -GyZTKuTOxqaJRKBTWLjwgcsms7v4LZ478wAAAAAAAAAA/////wAAAAAIbG9ja1Rp -bWUBNdodFTkgbrvd3KTDPYcx6vKbp9p03z3IgiAcTha1uRwEVHhJbgYECnByZXZP -dXRwdXQB6GpAzVwl+b3ihP9ppREyp0ErIVW9DlYSwb/jhJVgxQYJc2lnU2NyaXB0 -ATh1BLFLfA5GbUeeF0d9JHQkf/gDZOw9S6r3OiD3QXRrCHNlcXVlbmNlAQEZbYUp -yPbaRE0VTo2cjL2eD42JAlo7sJEhxj1SsB6HB3dpdG5lc3MBc3dDcDaTIEnNKJUI -qnF844KdskUuVehO1PwuPM0uAJ0FVHhPdXQGAgV2YWx1ZQGX9dcGQq4qM5IlO6hO -Hc7Ek+O/PtNxsYdzhjVOzIiCawxzY3JpcHRQdWJrZXkBvvwe/GalGf1kUmo6E4dA -5/EQLQu+/zrBRk7z90B2dFwFVHhWZXIFAQAARARUeGlkBQEABwAAQCAABFZvdXQF -AQAABAdXaXRuZXNzBQEACAAIAABAAAAAAAAAAAD/////AAAAAAAAAAAAAAAA//// -/wAAAAA= +B0JpdGNvaW4Be4SAPJ764hElp3wsObxw0v3o+UOuDf2c9OaC7cdmynADU3RkAQNT +dGQBAGGGItF7rvBmAt/ndcmA4LNrbrroCQ2AdfdRO+xLk/ZNBEJvb2woAAlCaXAz +NDBTaWcGAgNzaWcABwAAQEAADHNpZ2hhc2hfdHlwZQAEAgAEbm9uZQAAAAEEc29t +ZQAFAQHbF2Q+dwkTJ+gEmSSB1dxgFSMIlVM55Yszn9RMT3JIKglCbG9ja0hhc2gF +AQAHAABAIAALQmxvY2tIZWFkZXIGBgd2ZXJzaW9uAABEDXByZXZCbG9ja0hhc2gB +136XKN8Qx+HJT3+gvLwHRRJSZMs+SsX4k0LE/8jKtLcKbWVya2xlUm9vdAAHAABA +IAAEdGltZQAABARiaXRzAAAEBW5vbmNlAAAEBUNoYWluAwQHYml0Y29pbgAHcmVn +dGVzdIAIdGVzdG5ldDODBnNpZ25ldIQNRnV0dXJlTGVhZlZlcgUBAAABCkludGVy +bmFsUGsFAQAHAABAIAAKTGVhZlNjcmlwdAYCB3ZlcnNpb24BtjMJqRi/tpINbshY +pCSHI0ZaaT9yQwe//x3XOnOBTskGc2NyaXB0ASWr9bkSFBe6oznUX3sVdadxS+F6 +dRhd0DE1etTJLemGB0xlYWZWZXIFAQAAAQlMZWdhY3lTaWcGAgNzaWcACAAAQAAA +AAAAAAAA/wAAAAAAAAAMc2lnaGFzaF90eXBlAdsXZD53CRMn6ASZJIHV3GAVIwiV +UznlizOf1ExPckgqCExvY2tUaW1lBQEAAAQGT3BDb2RlAxIKcHVzaEJ5dGVzMAAL +cHVzaEJ5dGVzMzIgCXB1c2hEYXRhMUwJcHVzaERhdGEyTQlwdXNoRGF0YTROCHJl +c2VydmVkUAhwdXNoTnVtMVEGcmV0dXJuagNkdXB2BWVxdWFshwtlcXVhbFZlcmlm +eYgJcmlwZW1kMTYwpgRzaGExpwZzaGEyNTaoB2hhc2gxNjCpB2hhc2gyNTaqCGNo +ZWNrU2lnrA5jaGVja1NpZ1Zlcmlmea0IT3V0cG9pbnQGAgR0eGlkAaOCQvPL19HQ +oRLajeFgL1bU+G8OxMR2xcBoWUxLBGVWBHZvdXQBIeM+Q8WqXPIpJ1OjOMFn7Ttj +nE3Zzr2pjzRpF7rJQ3UMUmVkZWVtU2NyaXB0BQEBJav1uRIUF7qjOdRfexV1p3FL +4Xp1GF3QMTV61Mkt6YYEU2F0cwUBAAAIC1NjcmlwdEJ5dGVzBQEACAAAQAAAAAAA +AAAA/////wAAAAAMU2NyaXB0UHVia2V5BQEBJav1uRIUF7qjOdRfexV1p3FL4Xp1 +GF3QMTV61Mkt6YYFU2VxTm8FAQAABAlTaWdTY3JpcHQFAQElq/W5EhQXuqM51F97 +FXWncUvhenUYXdAxNXrUyS3phgtTaWdoYXNoRmxhZwMDA2FsbAEEbm9uZQIGc2lu +Z2xlAwtTaWdoYXNoVHlwZQYCBGZsYWcB/z5qf8jHhUNO/I7ndLMAsZvsmHGimh7x +AIvvEOso1TQMYW55b25lQ2FuUGF5AnuEgDye+uIRJad8LDm8cNL96PlDrg39nPTm +gu3HZspwYYYi0Xuu8GYC3+d1yYDgs2tuuugJDYB191E77EuT9k0NVGFwQnJhbmNo +SGFzaAUBAAcAAEAgAAdUYXBDb2RlAwYLcHVzaEJ5dGVzMzIgCXB1c2hEYXRhMUwJ +cHVzaERhdGEyTQlwdXNoRGF0YTROCHJlc2VydmVkUAZyZXR1cm5qC1RhcExlYWZI +YXNoBQEABwAAQCAADVRhcE1lcmtsZVBhdGgFAQAIAa/rxZ3Y/VBHHZhdwkEoLqup +jEiK8mRjwXZ+UQYiwpLYAAAAAAAAAAD/AAAAAAAAAAtUYXBOb2RlSGFzaAUBAAcA +AEAgAAlUYXBTY3JpcHQFAQElq/W5EhQXuqM51F97FXWncUvhenUYXdAxNXrUyS3p +hgJUeAYEB3ZlcnNpb24BqHzGeWRn5VfXROXJYjrgDMuV2RoNLwPfdMB1Ek++x54G +aW5wdXRzAAgBGUctF9hiB6cPITGpWKFopW4q1lM/nGZMGXfaXPn+YoYAAAAAAAAA +AP////8AAAAAB291dHB1dHMACAGQO2RweYSPGyZTKuTOxqaJRKBTWLjwgcsms7v4 +LZ478wAAAAAAAAAA/////wAAAAAIbG9ja1RpbWUBNdodFTkgbrvd3KTDPYcx6vKb +p9p03z3IgiAcTha1uRwEVHhJbgYECnByZXZPdXRwdXQB6GpAzVwl+b3ihP9ppREy +p0ErIVW9DlYSwb/jhJVgxQYJc2lnU2NyaXB0ATh1BLFLfA5GbUeeF0d9JHQkf/gD +ZOw9S6r3OiD3QXRrCHNlcXVlbmNlAQEZbYUpyPbaRE0VTo2cjL2eD42JAlo7sJEh +xj1SsB6HB3dpdG5lc3MBc3dDcDaTIEnNKJUIqnF844KdskUuVehO1PwuPM0uAJ0F +VHhPdXQGAgV2YWx1ZQGX9dcGQq4qM5IlO6hOHc7Ek+O/PtNxsYdzhjVOzIiCawxz +Y3JpcHRQdWJrZXkBvvwe/GalGf1kUmo6E4dA5/EQLQu+/zrBRk7z90B2dFwFVHhW +ZXIFAQAARARUeGlkBQEABwAAQCAABlZCeXRlcwUBAAAEBlZhckludAUBAAAIBFZv +dXQFAQAABAtXZWlnaHRVbml0cwUBAAAEB1dpdG5lc3MFAQAIAAgAAEAAAAAAAAAA +AP////8AAAAAAAAAAAAAAAD/////AAAAAA5XaXRuZXNzUHJvZ3JhbQYCB3ZlcnNp +b24B0ezadmfkQu1NEmmmZwM25f70N69ezitprroMRlbE+q0HcHJvZ3JhbQAIAABA +AgAAAAAAAAAoAAAAAAAAAA1XaXRuZXNzU2NyaXB0BQEBJav1uRIUF7qjOdRfexV1 +p3FL4Xp1GF3QMTV61Mkt6YYKV2l0bmVzc1ZlcgMRAnYwAAJ2MVECdjJSAnYzUwJ2 +NFQCdjVVAnY2VgJ2N1cCdjhYAnY5WQN2MTBaA3YxMVsDdjEyXAN2MTNdA3YxNF4D +djE1XwN2MTZgBVd0eGlkBQEABwAAQCAA -----END STRICT TYPE LIB----- diff --git a/stl/Bitcoin@0.1.0.stl b/stl/Bitcoin@0.1.0.stl index c6c7e8d62f3b2aba67a1b1a91ee6e931fc4459d3..2d152ba7117f8cf320bfae24abf7156245a28570 100644 GIT binary patch delta 1431 zcmbVMeQXnD7=Q1hcl}ri%n*$UW&+0gMf$bk)J$w~4(+;b9WA0TUVCrbqwU@8?t0o_ zxS=RUjLBGt^V=8$PTdGWF(FHc1hNei6O07nM^NKr2_t@l_(7cYxwf0^A4$AFp7*)u zp8MVV{+{3OKH`QNO+GB@X<3x0Z9Dt#dE@f;OK#f#wbfw=7*@-~eN5CfSZ%Q1v{kT0a#)lYmWKxxiHKK8RwtU?Z?~dE^uW^`92b(E?zWO%Qc0BH zOp>UuZA3ZONim(M5-!B^^XG6{9f`CmDmq8c9fLX?a138}^za_HG_m2GmAh87Z4~cS zBmB|IvNLySJ7SZZR()e&MbR-x=6p20(T7s?^s76S*q)_9#%_1B_T_ zV7X2uA`66RbSfn+7cT22(Y(l2zad({-{i1v)?yv|qVuW0V?GVW>?+ZSY7ilAw_0PR zqOXfn3D6~NWrUJq*hpUq7k0U-3$Q0<%Fj7~AyO24A@4p`%VFPs4x+y~bjQ2Ar7oxs zR}(0`XHVxyIu9g#uxKu;p^OY%pW++3i9kqk;G0_p`u3VGXtMy?3OLI!3@#L?sy=BL zq?9cXX0D+JsE7O{FzAXuNTkjhtR=SXNLOTe&vQ=(C(iWU+|m`Hejg? z8joNpj?46aSM*$f%Ri@@HQHSOW$9=EzV+FTsyX6V zx149E4qQ0#`q|m|1Ivas9lOu7>iyvt+MoYbNPl8%@8Xsp+jF+AFf=DM3pWOOS%B++ zVomWj>fqE;dKH%hArY-6uq0O3NxGHW*`!>mW~?hkU`+aY2^=|Cp+mikQX=?G)8eX} zRdMkO>ztbT(#ZZ0zSz+y?#nWvslP9+KCt<-+r-f$4QK!zVvEJ0vqVm6ef!fn~BdbNJ+W%u_dCWc|X($`Y1e KS~B@FyBPqTi4aTx diff --git a/stl/Bitcoin@0.1.0.sty b/stl/Bitcoin@0.1.0.sty index 047270e4..03a47d71 100644 --- a/stl/Bitcoin@0.1.0.sty +++ b/stl/Bitcoin@0.1.0.sty @@ -1,5 +1,5 @@ {- - Id: urn:ubideco:stl:6GgF7biXPVNcus2FfQj2pQuRzau11rXApMQLfCZhojgi#money-pardon-parody + Id: urn:ubideco:stl:HeTuSir1NWBfMe11Zf3dfw9uCrmfsSNdCaCaaLJQpQ91#apropos-milk-order Name: Bitcoin Version: 0.1.0 Description: Consensus transaction library for bitcoin protocol @@ -10,12 +10,49 @@ typelib Bitcoin --- no dependencies +import urn:ubideco:stl:9KALDYR8Nyjq4FdMW6kYoL7vdkWnqPqNuFnmE9qHpNjZ#justice-rocket-type as Std +-- Imports: +-- Bool := urn:ubideco:semid:7ZhBHGSJm9ixmm8Z9vCX7i5Ga7j5xrW8t11nsb1Cgpnx#laser-madam-maxwell + + +-- urn:ubideco:semid:8NDnad1DezNcQSjq85QMxnDhsBbLwxLCFUfMHEJpnFnH#politic-cactus-salon +data Bip340Sig :: sig [Byte ^ 64], sighash_type SighashType? +-- urn:ubideco:semid:FWCcWgBQCGQw8FX5Z4P3etje6e92qWpVPgXBonNrTM7C#canada-sharp-traffic +data BlockHash :: [Byte ^ 32] +-- urn:ubideco:semid:HHzmwexZQY4G1YKWB6mWwk7rJW8KKb1CaeuRw8xHV1tm#rose-apropos-join +data BlockHeader :: version I32 + , prevBlockHash BlockHash + , merkleRoot [Byte ^ 32] + , time U32 + , bits U32 + , nonce U32 +-- urn:ubideco:semid:6aRP3odHaTGySvSWHjreC8HsbX5ss9LxkQqwcjaoxhpv#aspirin-brown-alpine +data Chain :: bitcoin:0 | regtest:128 | testnet3:131 | signet:132 + +-- urn:ubideco:semid:CvDS9EgqtBkWLvADynNeR7VGwVAy14EXViKnLaBkqtac#student-formula-circus +data FutureLeafVer :: U8 +-- urn:ubideco:semid:G5HFVaWwWNYSzqk548JgGZ8WKy6dQ2ftVgkJvHjgRudZ#horse-major-vienna +data InternalPk :: [Byte ^ 32] +-- urn:ubideco:semid:Birr99aCTGqzwnuBou79KNhyLLBTNQvoTAkTbMu7C4y5#anvil-arctic-cloud +data LeafScript :: version LeafVer, script ScriptBytes +-- urn:ubideco:semid:DGELfUvcU62GNQRo7HaMbKDzYQwdYRMW3b91JHd4d3WY#tunnel-lagoon-cowboy +data LeafVer :: U8 +-- urn:ubideco:semid:89ux18kFuT9nT6LEWnvkpFBiWR9GJwBYVVBqFUPvrTuj#gondola-middle-style +data LegacySig :: sig [Byte ^ ..0xff], sighash_type SighashType -- urn:ubideco:semid:4dDWWU4afiPN3q4AgCMuFRFhL4UDta2u5SrqrBzPvjby#tokyo-inch-program data LockTime :: U32 +-- urn:ubideco:semid:F8WJfUNUgyVDSX6zXjrdi2pWBa54zLWorawtahJf33Hw#shampoo-rufus-tobacco +data OpCode :: pushBytes0:0 | pushBytes32:32 | pushData1:76 | pushData2:77 + | pushData4:78 | reserved:80 | pushNum1:81 | return:106 + | dup:118 | equal:135 | equalVerify:136 | ripemd160:166 + | sha1:167 | sha256:168 | hash160:169 | hash256:170 + | checkSig:172 | checkSigVerify:173 + -- urn:ubideco:semid:FWt2MSo8A4nsYgYbuBqMRNLiKgtzvLBgUn774iKzTcuf#pocket-pegasus-frank data Outpoint :: txid Txid, vout Vout +-- urn:ubideco:semid:85m9Qv56neQKaqiPSZ8G8NPWz5DDeJeeXhBwnUpcZGug#delta-jumbo-clone +data RedeemScript :: ScriptBytes -- urn:ubideco:semid:BEBz6h7AGjYSDRCxVHnjYkkkxzBsjN3EvyNiD4ZrzmRL#pyramid-spray-star data Sats :: U64 -- urn:ubideco:semid:3Y4AgjkFbDusgo3YqRDWv9BznDeAJEUDEPeEq1mpSkAR#maestro-source-jackson @@ -26,6 +63,25 @@ data ScriptPubkey :: ScriptBytes data SeqNo :: U32 -- urn:ubideco:semid:2gTMqAC393rBSGtBhDn8sJq3F3HtDosbqKDQTw9bHFyT#prelude-analyze-think data SigScript :: ScriptBytes +-- urn:ubideco:semid:JBNAWau3wDWa66fxnSyRJLkcUXSovZLxQJxERoUMNCbD#prefix-pioneer-remark +data SighashFlag :: all:1 | none:2 | single:3 + +-- urn:ubideco:semid:6mjKj9hdk5HzS8XR6SwsyAvzzaEfXmuXqmLuWq2EfayQ#balsa-equator-ground +data SighashType :: flag SighashFlag, anyoneCanPay Std.Bool {- urn:ubideco:semid:7ZhBHGSJm9ixmm8Z9vCX7i5Ga7j5xrW8t11nsb1Cgpnx#laser-madam-maxwell -} +-- urn:ubideco:semid:CqisAtFLQku77z3HbB1rBe9EjuctxLqcojV8p4THe3Uj#europe-welcome-phone +data TapBranchHash :: [Byte ^ 32] +-- urn:ubideco:semid:5WjBwSuKQwoTq6eXRtXwFrAmcPP1vLpBJ94AWpUgEsPe#weekend-boris-import +data TapCode :: pushBytes32:32 | pushData1:76 | pushData2:77 | pushData4:78 + | reserved:80 | return:106 + +-- urn:ubideco:semid:FHWiTycy1JvN5CvVJ3ibyAhtXfr21t3BDNuLFnqYPQ2j#middle-jazz-basket +data TapLeafHash :: [Byte ^ 32] +-- urn:ubideco:semid:5YrqoQi4fLCLqzBE1ZKb623WC311FGRgjcivLPXadnEN#gossip-protein-orion +data TapMerklePath :: [TapBranchHash ^ ..0xff] +-- urn:ubideco:semid:4M8xyvABKKKJseN6Pme5eKrAuusMNMXoY5s6ifsEcreC#crash-culture-jamaica +data TapNodeHash :: [Byte ^ 32] +-- urn:ubideco:semid:71AxyLFsoRG6hJ1c11gxad65nEbWfzkQBjWCPPrgCyjX#telecom-quest-helium +data TapScript :: ScriptBytes -- urn:ubideco:semid:DynChojW1sfr8VjSoZbmReHhZoU8u9KCiuwijgEGdToe#milk-gloria-prize data Tx :: version TxVer , inputs [TxIn ^ ..0xffffffff] @@ -42,8 +98,27 @@ data TxOut :: value Sats, scriptPubkey ScriptPubkey data TxVer :: I32 -- urn:ubideco:semid:C1GfCrG7AXu2sFhRBspd7KpJK2YgyTkVy6pty5rZynRs#cowboy-diego-betty data Txid :: [Byte ^ 32] +-- urn:ubideco:semid:8ALgmuRBL8YRNWmcFoPdBFCsZwCvDjupXgdq9DjFVnkV#waiter-salad-casino +data VBytes :: U32 +-- urn:ubideco:semid:AZqcQMyFBmixEkiDtAqGxB4nM8i9hmxV3mk4vUgNAkWT#conan-avalon-food +data VarInt :: U64 -- urn:ubideco:semid:3HHRtSJW5fnGkdVW1EVDH7B97Y79WhwvKyyfsaBkuQkk#chrome-robin-gallop data Vout :: U32 +-- urn:ubideco:semid:EcY6NU6BVRVkgCFwfWmSkbVKpLmWWVfDwBRRiSr6FJUC#bridge-version-voyage +data WeightUnits :: U32 -- urn:ubideco:semid:8mjN2CZj3Nhn2HjnKqTmEcN5vmyb3UJK8HSFW1uE3W2p#warning-saddle-period data Witness :: [[Byte ^ ..0xffffffff] ^ ..0xffffffff] +-- urn:ubideco:semid:FK7h8D8X6BTAuh8q4NdkdAGgF9vwAZRyYcUpFzR3fcDG#scholar-juice-titanic +data WitnessProgram :: version WitnessVer, program [Byte ^ 2..0x28] +-- urn:ubideco:semid:Bd2bXQc2D6YmMFpupKnFGvjBiZNcGKrhaxS9omUUedcS#boris-harbor-equal +data WitnessScript :: ScriptBytes +-- urn:ubideco:semid:F8Tgd8G4vQdBtiF8nnC46tANuaBcp9jnkaSeYxjREwEU#richard-average-unit +data WitnessVer :: v0:0 | v1:81 | v2:82 | v3:83 + | v4:84 | v5:85 | v6:86 | v7:87 + | v8:88 | v9:89 | v10:90 | v11:91 + | v12:92 | v13:93 | v14:94 | v15:95 + | v16:96 + +-- urn:ubideco:semid:HZbMnxQ1p2duNgYuYrQn9xtHBwSom63zWtRwy6pmBGfU#sushi-polygon-circus +data Wtxid :: [Byte ^ 32] From 99c21f39beea57209496e99d63a1b8ec0824211d Mon Sep 17 00:00:00 2001 From: Dr Maxim Orlovsky Date: Fri, 6 Oct 2023 00:22:48 +0200 Subject: [PATCH 10/31] primitives: move VarInt into coding module --- primitives/src/coding.rs | 40 +++++++++++++++++++++++++++++++++++++++- primitives/src/lib.rs | 6 +++--- primitives/src/util.rs | 38 -------------------------------------- 3 files changed, 42 insertions(+), 42 deletions(-) diff --git a/primitives/src/coding.rs b/primitives/src/coding.rs index 9052cf5f..dff020f0 100644 --- a/primitives/src/coding.rs +++ b/primitives/src/coding.rs @@ -26,11 +26,49 @@ use amplify::{confinement, IoError, RawArray, Wrapper}; use crate::{ LockTime, Outpoint, Sats, ScriptBytes, ScriptPubkey, SeqNo, SigScript, Tx, TxIn, TxOut, TxVer, - Txid, VarInt, Vout, Witness, + Txid, Vout, Witness, LIB_NAME_BITCOIN, }; pub type VarIntArray = Confined, 0, U32>; +/// A variable-length unsigned integer. +#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Default)] +#[derive(StrictType, StrictEncode, StrictDecode)] +#[strict_type(lib = LIB_NAME_BITCOIN)] +pub struct VarInt(pub u64); + +#[allow(clippy::len_without_is_empty)] // VarInt has no concept of 'is_empty'. +impl VarInt { + pub const fn new(u: u64) -> Self { VarInt(u) } + + pub fn with(u: impl Into) -> Self { VarInt(u.into() as u64) } + + /// Gets the length of this VarInt when encoded. + /// + /// Returns 1 for 0..=0xFC, 3 for 0xFD..=(2^16-1), 5 for 0x10000..=(2^32-1), + /// and 9 otherwise. + #[inline] + pub const fn len(&self) -> usize { + match self.0 { + 0..=0xFC => 1, + 0xFD..=0xFFFF => 3, + 0x10000..=0xFFFFFFFF => 5, + _ => 9, + } + } + + pub const fn to_u64(&self) -> u64 { self.0 } + pub const fn into_u64(self) -> u64 { self.0 } + pub fn to_usize(&self) -> usize { + usize::try_from(self.0).expect("transaction too large for a non-64 bit platform") + } + pub fn into_usize(self) -> usize { self.to_usize() } +} + +impl + Copy> PartialEq for VarInt { + fn eq(&self, other: &U) -> bool { self.0.eq(&(*other).into()) } +} + pub trait VarIntSize { fn var_int_size(&self) -> VarInt; } diff --git a/primitives/src/lib.rs b/primitives/src/lib.rs index c7b6c696..1452b367 100644 --- a/primitives/src/lib.rs +++ b/primitives/src/lib.rs @@ -60,8 +60,8 @@ mod coding; pub use block::{BlockHash, BlockHeader}; pub use coding::{ - ConsensusDataError, ConsensusDecode, ConsensusDecodeError, ConsensusEncode, VarIntArray, - VarIntSize, + ConsensusDataError, ConsensusDecode, ConsensusDecodeError, ConsensusEncode, VarInt, + VarIntArray, VarIntSize, }; pub use script::{OpCode, RedeemScript, ScriptBytes, ScriptPubkey, SigScript}; pub use segwit::{SegwitError, Witness, WitnessProgram, WitnessScript, WitnessVer, Wtxid}; @@ -77,7 +77,7 @@ pub use tx::{ LockTime, Outpoint, OutpointParseError, Sats, SeqNo, Tx, TxIn, TxOut, TxParseError, TxVer, Txid, Vout, LOCKTIME_THRESHOLD, }; -pub use util::{Chain, ChainParseError, NonStandardValue, VarInt}; +pub use util::{Chain, ChainParseError, NonStandardValue}; pub use weights::{VBytes, Weight, WeightUnits}; pub const LIB_NAME_BITCOIN: &str = "Bitcoin"; diff --git a/primitives/src/util.rs b/primitives/src/util.rs index 37fb198d..d7c70642 100644 --- a/primitives/src/util.rs +++ b/primitives/src/util.rs @@ -92,41 +92,3 @@ impl Chain { } } } - -/// A variable-length unsigned integer. -#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Default)] -#[derive(StrictType, StrictEncode, StrictDecode)] -#[strict_type(lib = LIB_NAME_BITCOIN)] -pub struct VarInt(pub u64); - -#[allow(clippy::len_without_is_empty)] // VarInt has no concept of 'is_empty'. -impl VarInt { - pub const fn new(u: u64) -> Self { VarInt(u) } - - pub fn with(u: impl Into) -> Self { VarInt(u.into() as u64) } - - /// Gets the length of this VarInt when encoded. - /// - /// Returns 1 for 0..=0xFC, 3 for 0xFD..=(2^16-1), 5 for 0x10000..=(2^32-1), - /// and 9 otherwise. - #[inline] - pub const fn len(&self) -> usize { - match self.0 { - 0..=0xFC => 1, - 0xFD..=0xFFFF => 3, - 0x10000..=0xFFFFFFFF => 5, - _ => 9, - } - } - - pub const fn to_u64(&self) -> u64 { self.0 } - pub const fn into_u64(self) -> u64 { self.0 } - pub fn to_usize(&self) -> usize { - usize::try_from(self.0).expect("transaction too large for a non-64 bit platform") - } - pub fn into_usize(self) -> usize { self.to_usize() } -} - -impl + Copy> PartialEq for VarInt { - fn eq(&self, other: &U) -> bool { self.0.eq(&(*other).into()) } -} From afa8e4ee38a4460a8416d7a92ca93988db0b02ed Mon Sep 17 00:00:00 2001 From: Dr Maxim Orlovsky Date: Fri, 6 Oct 2023 00:23:02 +0200 Subject: [PATCH 11/31] primitives: add todo list --- primitives/src/lib.rs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/primitives/src/lib.rs b/primitives/src/lib.rs index 1452b367..0491affa 100644 --- a/primitives/src/lib.rs +++ b/primitives/src/lib.rs @@ -19,6 +19,15 @@ // See the License for the specific language governing permissions and // limitations under the License. +// TODO: Ensure all serde uses both string and binary version +// TODO: Complete taproot consensus structure implementation (ControlBlock) +// TODO: Complete block data type implementation +// TODO: Add VarBytes data type +// TODO: Use NonStandardValue instead of NonStandardSighashType +// TODO: Do a no-std feature +// TODO: Complete OpCode structure implementation +// TODO: Move consensus-level timelocks and sequence locks from other libraries + // Coding conventions #![deny( non_upper_case_globals, @@ -33,6 +42,7 @@ #[macro_use] extern crate amplify; +// TODO: Make strict encoding optional dependency #[macro_use] extern crate strict_encoding; #[macro_use] From 978350527ce68cd2085b907c0364f47a4c12fbf7 Mon Sep 17 00:00:00 2001 From: Dr Maxim Orlovsky Date: Fri, 6 Oct 2023 00:27:16 +0200 Subject: [PATCH 12/31] primitives: use NonStandardValue instead of NonStandardSighashType --- primitives/src/lib.rs | 5 +---- primitives/src/sigtypes.rs | 14 ++++---------- 2 files changed, 5 insertions(+), 14 deletions(-) diff --git a/primitives/src/lib.rs b/primitives/src/lib.rs index 0491affa..59c5d6fd 100644 --- a/primitives/src/lib.rs +++ b/primitives/src/lib.rs @@ -23,7 +23,6 @@ // TODO: Complete taproot consensus structure implementation (ControlBlock) // TODO: Complete block data type implementation // TODO: Add VarBytes data type -// TODO: Use NonStandardValue instead of NonStandardSighashType // TODO: Do a no-std feature // TODO: Complete OpCode structure implementation // TODO: Move consensus-level timelocks and sequence locks from other libraries @@ -75,9 +74,7 @@ pub use coding::{ }; pub use script::{OpCode, RedeemScript, ScriptBytes, ScriptPubkey, SigScript}; pub use segwit::{SegwitError, Witness, WitnessProgram, WitnessScript, WitnessVer, Wtxid}; -pub use sigtypes::{ - Bip340Sig, LegacySig, NonStandardSighashType, SigError, SighashFlag, SighashType, -}; +pub use sigtypes::{Bip340Sig, LegacySig, SigError, SighashFlag, SighashType}; pub use taproot::{ FutureLeafVer, InternalPk, IntoTapHash, InvalidLeafVer, LeafScript, LeafVer, TapBranchHash, TapCode, TapLeafHash, TapMerklePath, TapNodeHash, TapScript, TAPROOT_ANNEX_PREFIX, diff --git a/primitives/src/sigtypes.rs b/primitives/src/sigtypes.rs index 7a070705..21d09726 100644 --- a/primitives/src/sigtypes.rs +++ b/primitives/src/sigtypes.rs @@ -23,13 +23,7 @@ use std::iter; use secp256k1::{ecdsa, schnorr}; -use crate::LIB_NAME_BITCOIN; - -/// This type is consensus valid but an input including it would prevent the -/// transaction from being relayed on today's Bitcoin network. -#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Display, Error)] -#[display("non-standard SIGHASH_TYPE value {0:#X}")] -pub struct NonStandardSighashType(pub u32); +use crate::{NonStandardValue, LIB_NAME_BITCOIN}; #[derive(Copy, Clone, PartialEq, Eq, Debug, Hash, Default)] #[derive(StrictType, StrictEncode, StrictDecode)] @@ -144,7 +138,7 @@ impl SighashType { /// # Errors /// /// If `n` is a non-standard sighash value. - pub fn from_standard_u32(n: u32) -> Result { + pub fn from_standard_u32(n: u32) -> Result> { let (flag, anyone_can_pay) = match n { // Standard sighashes, see https://github.com/bitcoin/bitcoin/blob/b805dbb0b9c90dadef0424e5b3bf86ac308e103e/src/script/interpreter.cpp#L189-L198 0x01 => (SighashFlag::All, false), @@ -153,7 +147,7 @@ impl SighashType { 0x81 => (SighashFlag::All, true), 0x82 => (SighashFlag::None, true), 0x83 => (SighashFlag::Single, true), - non_standard => return Err(NonStandardSighashType(non_standard)), + non_standard => return Err(NonStandardValue::with(non_standard, "SighashType")), }; Ok(SighashType { flag, @@ -195,7 +189,7 @@ pub enum SigError { /// Non-standard sighash type. #[display(inner)] #[from] - SighashType(NonStandardSighashType), + SighashType(NonStandardValue), /// empty signature. EmptySignature, From 2bf569efc4a1119f9e054b640e89dee4372ad58b Mon Sep 17 00:00:00 2001 From: Dr Maxim Orlovsky Date: Fri, 6 Oct 2023 00:37:53 +0200 Subject: [PATCH 13/31] primitives: add ByteStr type --- primitives/src/coding.rs | 49 +++++++++++++++++--- primitives/src/lib.rs | 11 ++--- primitives/src/script.rs | 4 +- primitives/src/stl.rs | 11 ++--- primitives/src/weights.rs | 14 +++--- stl/Bitcoin@0.1.0.sta | 91 +++++++++++++++++++------------------- stl/Bitcoin@0.1.0.stl | Bin 2328 -> 2359 bytes stl/Bitcoin@0.1.0.sty | 6 ++- stl/Tx@0.1.0.sty | 2 +- 9 files changed, 117 insertions(+), 71 deletions(-) diff --git a/primitives/src/coding.rs b/primitives/src/coding.rs index dff020f0..dc4550a1 100644 --- a/primitives/src/coding.rs +++ b/primitives/src/coding.rs @@ -19,9 +19,11 @@ // See the License for the specific language governing permissions and // limitations under the License. +use std::fmt::{Formatter, LowerHex, UpperHex}; use std::io::{self, Cursor, Read, Write}; use amplify::confinement::{Confined, U32}; +use amplify::hex::{self, FromHex, ToHex}; use amplify::{confinement, IoError, RawArray, Wrapper}; use crate::{ @@ -69,12 +71,49 @@ impl + Copy> PartialEq for VarInt { fn eq(&self, other: &U) -> bool { self.0.eq(&(*other).into()) } } -pub trait VarIntSize { - fn var_int_size(&self) -> VarInt; +pub trait LenVarInt { + fn len_var_int(&self) -> VarInt; } -impl VarIntSize for VarIntArray { - fn var_int_size(&self) -> VarInt { VarInt::with(self.len()) } +impl LenVarInt for VarIntArray { + fn len_var_int(&self) -> VarInt { VarInt::with(self.len()) } +} + +#[derive(Wrapper, WrapperMut, Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Default, Debug, From)] +#[derive(StrictType, StrictEncode, StrictDecode)] +#[strict_type(lib = LIB_NAME_BITCOIN)] +#[wrapper(Deref, Index, RangeOps, BorrowSlice)] +#[wrapper_mut(DerefMut, IndexMut, RangeMut, BorrowSliceMut)] +pub struct ByteStr(VarIntArray); + +impl From> for ByteStr { + fn from(value: Vec) -> Self { Self(Confined::try_from(value).expect("u64 >= usize")) } +} + +impl LowerHex for ByteStr { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + f.write_str(&self.0.as_inner().to_hex()) + } +} + +impl UpperHex for ByteStr { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + f.write_str(&self.0.as_inner().to_hex().to_uppercase()) + } +} + +impl FromHex for ByteStr { + fn from_hex(s: &str) -> Result { Vec::::from_hex(s).map(Self::from) } + fn from_byte_iter(_: I) -> Result + where I: Iterator> + ExactSizeIterator + DoubleEndedIterator { + unreachable!() + } +} + +impl ByteStr { + pub fn len_var_int(&self) -> VarInt { VarInt(self.len() as u64) } + + pub fn into_vec(self) -> Vec { self.0.into_inner() } } #[derive(Clone, PartialEq, Eq, Debug, Display, Error, From)] @@ -429,7 +468,7 @@ impl ConsensusDecode for VarInt { impl ConsensusEncode for VarIntArray { fn consensus_encode(&self, writer: &mut impl Write) -> Result { - let mut counter = self.var_int_size().consensus_encode(writer)?; + let mut counter = self.len_var_int().consensus_encode(writer)?; for item in self { counter += item.consensus_encode(writer)?; } diff --git a/primitives/src/lib.rs b/primitives/src/lib.rs index 59c5d6fd..434dc329 100644 --- a/primitives/src/lib.rs +++ b/primitives/src/lib.rs @@ -19,13 +19,14 @@ // See the License for the specific language governing permissions and // limitations under the License. +// Version 0.10.10: // TODO: Ensure all serde uses both string and binary version // TODO: Complete taproot consensus structure implementation (ControlBlock) // TODO: Complete block data type implementation -// TODO: Add VarBytes data type -// TODO: Do a no-std feature -// TODO: Complete OpCode structure implementation // TODO: Move consensus-level timelocks and sequence locks from other libraries +// Version 1.0: +// TODO: Complete OpCode structure implementation +// TODO: Do a no-std feature // Coding conventions #![deny( @@ -69,8 +70,8 @@ mod coding; pub use block::{BlockHash, BlockHeader}; pub use coding::{ - ConsensusDataError, ConsensusDecode, ConsensusDecodeError, ConsensusEncode, VarInt, - VarIntArray, VarIntSize, + ByteStr, ConsensusDataError, ConsensusDecode, ConsensusDecodeError, ConsensusEncode, LenVarInt, + VarInt, VarIntArray, }; pub use script::{OpCode, RedeemScript, ScriptBytes, ScriptPubkey, SigScript}; pub use segwit::{SegwitError, Witness, WitnessProgram, WitnessScript, WitnessVer, Wtxid}; diff --git a/primitives/src/script.rs b/primitives/src/script.rs index adbb1448..091c12c4 100644 --- a/primitives/src/script.rs +++ b/primitives/src/script.rs @@ -25,7 +25,7 @@ use amplify::confinement::Confined; use amplify::hex::{self, FromHex, ToHex}; use crate::opcodes::*; -use crate::{VarIntArray, LIB_NAME_BITCOIN}; +use crate::{VarInt, VarIntArray, LIB_NAME_BITCOIN}; #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug, Display)] #[derive(StrictType, StrictDumb, StrictEncode, StrictDecode)] @@ -349,6 +349,8 @@ impl ScriptBytes { } } + pub fn len_var_int(&self) -> VarInt { VarInt(self.len() as u64) } + pub fn into_vec(self) -> Vec { self.0.into_inner() } pub(crate) fn as_var_int_array(&self) -> &VarIntArray { &self.0 } diff --git a/primitives/src/stl.rs b/primitives/src/stl.rs index 272a444d..d0344b6c 100644 --- a/primitives/src/stl.rs +++ b/primitives/src/stl.rs @@ -23,10 +23,10 @@ use strict_types::{CompileError, LibBuilder, TypeLib}; use crate::{ - Bip340Sig, BlockHeader, Chain, FutureLeafVer, InternalPk, LeafScript, LeafVer, LegacySig, - OpCode, RedeemScript, TapBranchHash, TapCode, TapLeafHash, TapMerklePath, TapNodeHash, - TapScript, Tx, VBytes, VarInt, WeightUnits, WitnessProgram, WitnessScript, WitnessVer, Wtxid, - LIB_NAME_BITCOIN, + Bip340Sig, BlockHeader, ByteStr, Chain, FutureLeafVer, InternalPk, LeafScript, LeafVer, + LegacySig, OpCode, RedeemScript, TapBranchHash, TapCode, TapLeafHash, TapMerklePath, + TapNodeHash, TapScript, Tx, VBytes, VarInt, WeightUnits, WitnessProgram, WitnessScript, + WitnessVer, Wtxid, LIB_NAME_BITCOIN, }; #[deprecated(since = "0.10.8", note = "use LIB_ID_BP_TX instead")] @@ -35,7 +35,7 @@ pub const LIB_ID_BITCOIN: &str = pub const LIB_ID_BP_TX: &str = "urn:ubideco:stl:6GgF7biXPVNcus2FfQj2pQuRzau11rXApMQLfCZhojgi#money-pardon-parody"; pub const LIB_ID_BP_CONSENSUS: &str = - "urn:ubideco:stl:HeTuSir1NWBfMe11Zf3dfw9uCrmfsSNdCaCaaLJQpQ91#apropos-milk-order"; + "urn:ubideco:stl:DrkRxZuxVjPSc5CtPmXhxQ14wyfVDz787WEfdrgqgffB#gray-prepare-proton"; #[deprecated(since = "0.10.8", note = "use _bp_tx_stl instead")] fn _bitcoin_stl() -> Result { _bp_tx_stl() } @@ -71,6 +71,7 @@ fn _bp_consensus_stl() -> Result { .transpile::() .transpile::() .transpile::() + .transpile::() .transpile::() .transpile::() .transpile::() diff --git a/primitives/src/weights.rs b/primitives/src/weights.rs index 5147642f..2a45f8d1 100644 --- a/primitives/src/weights.rs +++ b/primitives/src/weights.rs @@ -22,7 +22,7 @@ use std::iter::Sum; use std::ops::{Add, AddAssign}; -use crate::{ScriptPubkey, SigScript, Tx, TxIn, TxOut, VarIntSize, Witness, LIB_NAME_BITCOIN}; +use crate::{LenVarInt, ScriptPubkey, SigScript, Tx, TxIn, TxOut, Witness, LIB_NAME_BITCOIN}; #[derive(Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Debug, Display)] #[derive(StrictType, StrictEncode, StrictDecode, StrictDumb)] @@ -88,8 +88,8 @@ pub trait Weight { impl Weight for Tx { fn weight_units(&self) -> WeightUnits { let bytes = 4 // version - + self.inputs.var_int_size().len() - + self.outputs.var_int_size().len() + + self.inputs.len_var_int().len() + + self.outputs.len_var_int().len() + 4; // lock time let mut weight = WeightUnits::no_discount(bytes) + @@ -126,22 +126,22 @@ impl Weight for TxOut { impl Weight for ScriptPubkey { fn weight_units(&self) -> WeightUnits { - WeightUnits::no_discount(self.var_int_size().len() + self.len()) + WeightUnits::no_discount(self.len_var_int().len() + self.len()) } } impl Weight for SigScript { fn weight_units(&self) -> WeightUnits { - WeightUnits::no_discount(self.var_int_size().len() + self.len()) + WeightUnits::no_discount(self.len_var_int().len() + self.len()) } } impl Weight for Witness { fn weight_units(&self) -> WeightUnits { WeightUnits::witness_discount( - self.var_int_size().len() + + self.len_var_int().len() + self.iter() - .map(|item| item.var_int_size().len() + item.len()) + .map(|item| item.len_var_int().len() + item.len()) .sum::(), ) } diff --git a/stl/Bitcoin@0.1.0.sta b/stl/Bitcoin@0.1.0.sta index a96ca784..42e33e3b 100644 --- a/stl/Bitcoin@0.1.0.sta +++ b/stl/Bitcoin@0.1.0.sta @@ -1,58 +1,59 @@ -----BEGIN STRICT TYPE LIB----- -Id: urn:ubideco:stl:HeTuSir1NWBfMe11Zf3dfw9uCrmfsSNdCaCaaLJQpQ91 +Id: urn:ubideco:stl:DrkRxZuxVjPSc5CtPmXhxQ14wyfVDz787WEfdrgqgffB Name: Bitcoin Dependencies: urn:ubideco:stl:9KALDYR8Nyjq4FdMW6kYoL7vdkWnqPqNuFnmE9qHpNjZ B0JpdGNvaW4Be4SAPJ764hElp3wsObxw0v3o+UOuDf2c9OaC7cdmynADU3RkAQNT -dGQBAGGGItF7rvBmAt/ndcmA4LNrbrroCQ2AdfdRO+xLk/ZNBEJvb2woAAlCaXAz +dGQBAGGGItF7rvBmAt/ndcmA4LNrbrroCQ2AdfdRO+xLk/ZNBEJvb2wpAAlCaXAz NDBTaWcGAgNzaWcABwAAQEAADHNpZ2hhc2hfdHlwZQAEAgAEbm9uZQAAAAEEc29t ZQAFAQHbF2Q+dwkTJ+gEmSSB1dxgFSMIlVM55Yszn9RMT3JIKglCbG9ja0hhc2gF AQAHAABAIAALQmxvY2tIZWFkZXIGBgd2ZXJzaW9uAABEDXByZXZCbG9ja0hhc2gB 136XKN8Qx+HJT3+gvLwHRRJSZMs+SsX4k0LE/8jKtLcKbWVya2xlUm9vdAAHAABA -IAAEdGltZQAABARiaXRzAAAEBW5vbmNlAAAEBUNoYWluAwQHYml0Y29pbgAHcmVn -dGVzdIAIdGVzdG5ldDODBnNpZ25ldIQNRnV0dXJlTGVhZlZlcgUBAAABCkludGVy -bmFsUGsFAQAHAABAIAAKTGVhZlNjcmlwdAYCB3ZlcnNpb24BtjMJqRi/tpINbshY -pCSHI0ZaaT9yQwe//x3XOnOBTskGc2NyaXB0ASWr9bkSFBe6oznUX3sVdadxS+F6 -dRhd0DE1etTJLemGB0xlYWZWZXIFAQAAAQlMZWdhY3lTaWcGAgNzaWcACAAAQAAA -AAAAAAAA/wAAAAAAAAAMc2lnaGFzaF90eXBlAdsXZD53CRMn6ASZJIHV3GAVIwiV -UznlizOf1ExPckgqCExvY2tUaW1lBQEAAAQGT3BDb2RlAxIKcHVzaEJ5dGVzMAAL -cHVzaEJ5dGVzMzIgCXB1c2hEYXRhMUwJcHVzaERhdGEyTQlwdXNoRGF0YTROCHJl -c2VydmVkUAhwdXNoTnVtMVEGcmV0dXJuagNkdXB2BWVxdWFshwtlcXVhbFZlcmlm -eYgJcmlwZW1kMTYwpgRzaGExpwZzaGEyNTaoB2hhc2gxNjCpB2hhc2gyNTaqCGNo -ZWNrU2lnrA5jaGVja1NpZ1Zlcmlmea0IT3V0cG9pbnQGAgR0eGlkAaOCQvPL19HQ -oRLajeFgL1bU+G8OxMR2xcBoWUxLBGVWBHZvdXQBIeM+Q8WqXPIpJ1OjOMFn7Ttj -nE3Zzr2pjzRpF7rJQ3UMUmVkZWVtU2NyaXB0BQEBJav1uRIUF7qjOdRfexV1p3FL -4Xp1GF3QMTV61Mkt6YYEU2F0cwUBAAAIC1NjcmlwdEJ5dGVzBQEACAAAQAAAAAAA -AAAA/////wAAAAAMU2NyaXB0UHVia2V5BQEBJav1uRIUF7qjOdRfexV1p3FL4Xp1 -GF3QMTV61Mkt6YYFU2VxTm8FAQAABAlTaWdTY3JpcHQFAQElq/W5EhQXuqM51F97 -FXWncUvhenUYXdAxNXrUyS3phgtTaWdoYXNoRmxhZwMDA2FsbAEEbm9uZQIGc2lu -Z2xlAwtTaWdoYXNoVHlwZQYCBGZsYWcB/z5qf8jHhUNO/I7ndLMAsZvsmHGimh7x -AIvvEOso1TQMYW55b25lQ2FuUGF5AnuEgDye+uIRJad8LDm8cNL96PlDrg39nPTm -gu3HZspwYYYi0Xuu8GYC3+d1yYDgs2tuuugJDYB191E77EuT9k0NVGFwQnJhbmNo -SGFzaAUBAAcAAEAgAAdUYXBDb2RlAwYLcHVzaEJ5dGVzMzIgCXB1c2hEYXRhMUwJ -cHVzaERhdGEyTQlwdXNoRGF0YTROCHJlc2VydmVkUAZyZXR1cm5qC1RhcExlYWZI -YXNoBQEABwAAQCAADVRhcE1lcmtsZVBhdGgFAQAIAa/rxZ3Y/VBHHZhdwkEoLqup -jEiK8mRjwXZ+UQYiwpLYAAAAAAAAAAD/AAAAAAAAAAtUYXBOb2RlSGFzaAUBAAcA -AEAgAAlUYXBTY3JpcHQFAQElq/W5EhQXuqM51F97FXWncUvhenUYXdAxNXrUyS3p -hgJUeAYEB3ZlcnNpb24BqHzGeWRn5VfXROXJYjrgDMuV2RoNLwPfdMB1Ek++x54G -aW5wdXRzAAgBGUctF9hiB6cPITGpWKFopW4q1lM/nGZMGXfaXPn+YoYAAAAAAAAA -AP////8AAAAAB291dHB1dHMACAGQO2RweYSPGyZTKuTOxqaJRKBTWLjwgcsms7v4 -LZ478wAAAAAAAAAA/////wAAAAAIbG9ja1RpbWUBNdodFTkgbrvd3KTDPYcx6vKb -p9p03z3IgiAcTha1uRwEVHhJbgYECnByZXZPdXRwdXQB6GpAzVwl+b3ihP9ppREy -p0ErIVW9DlYSwb/jhJVgxQYJc2lnU2NyaXB0ATh1BLFLfA5GbUeeF0d9JHQkf/gD -ZOw9S6r3OiD3QXRrCHNlcXVlbmNlAQEZbYUpyPbaRE0VTo2cjL2eD42JAlo7sJEh -xj1SsB6HB3dpdG5lc3MBc3dDcDaTIEnNKJUIqnF844KdskUuVehO1PwuPM0uAJ0F -VHhPdXQGAgV2YWx1ZQGX9dcGQq4qM5IlO6hOHc7Ek+O/PtNxsYdzhjVOzIiCawxz -Y3JpcHRQdWJrZXkBvvwe/GalGf1kUmo6E4dA5/EQLQu+/zrBRk7z90B2dFwFVHhW -ZXIFAQAARARUeGlkBQEABwAAQCAABlZCeXRlcwUBAAAEBlZhckludAUBAAAIBFZv -dXQFAQAABAtXZWlnaHRVbml0cwUBAAAEB1dpdG5lc3MFAQAIAAgAAEAAAAAAAAAA -AP////8AAAAAAAAAAAAAAAD/////AAAAAA5XaXRuZXNzUHJvZ3JhbQYCB3ZlcnNp -b24B0ezadmfkQu1NEmmmZwM25f70N69ezitprroMRlbE+q0HcHJvZ3JhbQAIAABA -AgAAAAAAAAAoAAAAAAAAAA1XaXRuZXNzU2NyaXB0BQEBJav1uRIUF7qjOdRfexV1 -p3FL4Xp1GF3QMTV61Mkt6YYKV2l0bmVzc1ZlcgMRAnYwAAJ2MVECdjJSAnYzUwJ2 -NFQCdjVVAnY2VgJ2N1cCdjhYAnY5WQN2MTBaA3YxMVsDdjEyXAN2MTNdA3YxNF4D -djE1XwN2MTZgBVd0eGlkBQEABwAAQCAA +IAAEdGltZQAABARiaXRzAAAEBW5vbmNlAAAEB0J5dGVTdHIFAQAIAABAAAAAAAAA +AAD/////AAAAAAVDaGFpbgMEB2JpdGNvaW4AB3JlZ3Rlc3SACHRlc3RuZXQzgwZz +aWduZXSEDUZ1dHVyZUxlYWZWZXIFAQAAAQpJbnRlcm5hbFBrBQEABwAAQCAACkxl +YWZTY3JpcHQGAgd2ZXJzaW9uAbYzCakYv7aSDW7IWKQkhyNGWmk/ckMHv/8d1zpz +gU7JBnNjcmlwdAElq/W5EhQXuqM51F97FXWncUvhenUYXdAxNXrUyS3phgdMZWFm +VmVyBQEAAAEJTGVnYWN5U2lnBgIDc2lnAAgAAEAAAAAAAAAAAP8AAAAAAAAADHNp +Z2hhc2hfdHlwZQHbF2Q+dwkTJ+gEmSSB1dxgFSMIlVM55Yszn9RMT3JIKghMb2Nr +VGltZQUBAAAEBk9wQ29kZQMSCnB1c2hCeXRlczAAC3B1c2hCeXRlczMyIAlwdXNo +RGF0YTFMCXB1c2hEYXRhMk0JcHVzaERhdGE0TghyZXNlcnZlZFAIcHVzaE51bTFR +BnJldHVybmoDZHVwdgVlcXVhbIcLZXF1YWxWZXJpZnmICXJpcGVtZDE2MKYEc2hh +MacGc2hhMjU2qAdoYXNoMTYwqQdoYXNoMjU2qghjaGVja1NpZ6wOY2hlY2tTaWdW +ZXJpZnmtCE91dHBvaW50BgIEdHhpZAGjgkLzy9fR0KES2o3hYC9W1PhvDsTEdsXA +aFlMSwRlVgR2b3V0ASHjPkPFqlzyKSdTozjBZ+07Y5xN2c69qY80aRe6yUN1DFJl +ZGVlbVNjcmlwdAUBASWr9bkSFBe6oznUX3sVdadxS+F6dRhd0DE1etTJLemGBFNh +dHMFAQAACAtTY3JpcHRCeXRlcwUBAAgAAEAAAAAAAAAAAP////8AAAAADFNjcmlw +dFB1YmtleQUBASWr9bkSFBe6oznUX3sVdadxS+F6dRhd0DE1etTJLemGBVNlcU5v +BQEAAAQJU2lnU2NyaXB0BQEBJav1uRIUF7qjOdRfexV1p3FL4Xp1GF3QMTV61Mkt +6YYLU2lnaGFzaEZsYWcDAwNhbGwBBG5vbmUCBnNpbmdsZQMLU2lnaGFzaFR5cGUG +AgRmbGFnAf8+an/Ix4VDTvyO53SzALGb7Jhxopoe8QCL7xDrKNU0DGFueW9uZUNh +blBheQJ7hIA8nvriESWnfCw5vHDS/ej5Q64N/Zz05oLtx2bKcGGGItF7rvBmAt/n +dcmA4LNrbrroCQ2AdfdRO+xLk/ZNDVRhcEJyYW5jaEhhc2gFAQAHAABAIAAHVGFw +Q29kZQMGC3B1c2hCeXRlczMyIAlwdXNoRGF0YTFMCXB1c2hEYXRhMk0JcHVzaERh +dGE0TghyZXNlcnZlZFAGcmV0dXJuagtUYXBMZWFmSGFzaAUBAAcAAEAgAA1UYXBN +ZXJrbGVQYXRoBQEACAGv68Wd2P1QRx2YXcJBKC6rqYxIivJkY8F2flEGIsKS2AAA +AAAAAAAA/wAAAAAAAAALVGFwTm9kZUhhc2gFAQAHAABAIAAJVGFwU2NyaXB0BQEB +Jav1uRIUF7qjOdRfexV1p3FL4Xp1GF3QMTV61Mkt6YYCVHgGBAd2ZXJzaW9uAah8 +xnlkZ+VX10TlyWI64AzLldkaDS8D33TAdRJPvseeBmlucHV0cwAIARlHLRfYYgen +DyExqVihaKVuKtZTP5xmTBl32lz5/mKGAAAAAAAAAAD/////AAAAAAdvdXRwdXRz +AAgBkDtkcHmEjxsmUyrkzsamiUSgU1i48IHLJrO7+C2eO/MAAAAAAAAAAP////8A +AAAACGxvY2tUaW1lATXaHRU5IG673dykwz2HMerym6fadN89yIIgHE4WtbkcBFR4 +SW4GBApwcmV2T3V0cHV0AehqQM1cJfm94oT/aaURMqdBKyFVvQ5WEsG/44SVYMUG +CXNpZ1NjcmlwdAE4dQSxS3wORm1HnhdHfSR0JH/4A2TsPUuq9zog90F0awhzZXF1 +ZW5jZQEBGW2FKcj22kRNFU6NnIy9ng+NiQJaO7CRIcY9UrAehwd3aXRuZXNzAXN3 +Q3A2kyBJzSiVCKpxfOOCnbJFLlXoTtT8LjzNLgCdBVR4T3V0BgIFdmFsdWUBl/XX +BkKuKjOSJTuoTh3OxJPjvz7TcbGHc4Y1TsyIgmsMc2NyaXB0UHVia2V5Ab78Hvxm +pRn9ZFJqOhOHQOfxEC0Lvv86wUZO8/dAdnRcBVR4VmVyBQEAAEQEVHhpZAUBAAcA +AEAgAAZWQnl0ZXMFAQAABAZWYXJJbnQFAQAACARWb3V0BQEAAAQLV2VpZ2h0VW5p +dHMFAQAABAdXaXRuZXNzBQEACAAIAABAAAAAAAAAAAD/////AAAAAAAAAAAAAAAA +/////wAAAAAOV2l0bmVzc1Byb2dyYW0GAgd2ZXJzaW9uAdHs2nZn5ELtTRJppmcD +NuX+9DevXs4raa66DEZWxPqtB3Byb2dyYW0ACAAAQAIAAAAAAAAAKAAAAAAAAAAN +V2l0bmVzc1NjcmlwdAUBASWr9bkSFBe6oznUX3sVdadxS+F6dRhd0DE1etTJLemG +CldpdG5lc3NWZXIDEQJ2MAACdjFRAnYyUgJ2M1MCdjRUAnY1VQJ2NlYCdjdXAnY4 +WAJ2OVkDdjEwWgN2MTFbA3YxMlwDdjEzXQN2MTReA3YxNV8DdjE2YAVXdHhpZAUB +AAcAAEAgAA== -----END STRICT TYPE LIB----- diff --git a/stl/Bitcoin@0.1.0.stl b/stl/Bitcoin@0.1.0.stl index 2d152ba7117f8cf320bfae24abf7156245a28570..ff8596f5164f3712c867248bdd4cc6d705f0f420 100644 GIT binary patch delta 48 ucmbOsv|VUIB%|iUsE6|GPL(C8!6ikkj0_wM3=RxX@E-_3%+1z}ci90^?G0l9 delta 16 YcmdlkG(%`YB%{W}sE3=Q81J$J05rS?L;wH) diff --git a/stl/Bitcoin@0.1.0.sty b/stl/Bitcoin@0.1.0.sty index 03a47d71..025d91e1 100644 --- a/stl/Bitcoin@0.1.0.sty +++ b/stl/Bitcoin@0.1.0.sty @@ -1,8 +1,8 @@ {- - Id: urn:ubideco:stl:HeTuSir1NWBfMe11Zf3dfw9uCrmfsSNdCaCaaLJQpQ91#apropos-milk-order + Id: urn:ubideco:stl:DrkRxZuxVjPSc5CtPmXhxQ14wyfVDz787WEfdrgqgffB#gray-prepare-proton Name: Bitcoin Version: 0.1.0 - Description: Consensus transaction library for bitcoin protocol + Description: Consensus library for bitcoin protocol Author: Dr Maxim Orlovsky Copyright (C) 2023 LNP/BP Standards Association. All rights reserved. License: Apache-2.0 @@ -27,6 +27,8 @@ data BlockHeader :: version I32 , time U32 , bits U32 , nonce U32 +-- urn:ubideco:semid:EDr6wurh4X1tMNGqA7mRkyrAY6ngPGyRSEufTGSUtySJ#kinetic-avenue-escort +data ByteStr :: [Byte ^ ..0xffffffff] -- urn:ubideco:semid:6aRP3odHaTGySvSWHjreC8HsbX5ss9LxkQqwcjaoxhpv#aspirin-brown-alpine data Chain :: bitcoin:0 | regtest:128 | testnet3:131 | signet:132 diff --git a/stl/Tx@0.1.0.sty b/stl/Tx@0.1.0.sty index b519eb01..b5859e11 100644 --- a/stl/Tx@0.1.0.sty +++ b/stl/Tx@0.1.0.sty @@ -2,7 +2,7 @@ Id: urn:ubideco:stl:5PUqZnqASPU3zKASh2pTHYmfcV4pZfvt4UU8FxPsRt6S#winter-horizon-binary Name: Tx Version: 0.1.0 - Description: Consensus transaction library for bitcoin protocol + Description: Bitcoin transaction library Author: Dr Maxim Orlovsky Copyright (C) 2023 LNP/BP Standards Association. All rights reserved. License: Apache-2.0 From 64a77f36a896184cd476c1f632f48c2d6cfddc12 Mon Sep 17 00:00:00 2001 From: Dr Maxim Orlovsky Date: Fri, 6 Oct 2023 01:03:11 +0200 Subject: [PATCH 14/31] primitives: make TapMerklePath max size match consensus rule --- primitives/src/taproot.rs | 4 ++-- stl/Bitcoin@0.1.0.sta | 2 +- stl/Bitcoin@0.1.0.sty | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/primitives/src/taproot.rs b/primitives/src/taproot.rs index 0f6da74f..d7847195 100644 --- a/primitives/src/taproot.rs +++ b/primitives/src/taproot.rs @@ -25,7 +25,7 @@ use std::borrow::Borrow; use std::fmt::{self, Formatter, LowerHex, UpperHex}; use std::{cmp, io}; -use amplify::confinement::{Confined, TinyVec, U32}; +use amplify::confinement::{Confined, U32}; use amplify::{Bytes32, Wrapper}; use commit_verify::{DigestExt, Sha256}; use secp256k1::{Scalar, XOnlyPublicKey}; @@ -221,7 +221,7 @@ impl IntoTapHash for TapNodeHash { derive(Serialize, Deserialize), serde(crate = "serde_crate", transparent) )] -pub struct TapMerklePath(TinyVec); +pub struct TapMerklePath(Confined, 0, 128>); /// Taproot annex prefix. pub const TAPROOT_ANNEX_PREFIX: u8 = 0x50; diff --git a/stl/Bitcoin@0.1.0.sta b/stl/Bitcoin@0.1.0.sta index 42e33e3b..820cd249 100644 --- a/stl/Bitcoin@0.1.0.sta +++ b/stl/Bitcoin@0.1.0.sta @@ -5,7 +5,7 @@ Dependencies: urn:ubideco:stl:9KALDYR8Nyjq4FdMW6kYoL7vdkWnqPqNuFnmE9qHpNjZ B0JpdGNvaW4Be4SAPJ764hElp3wsObxw0v3o+UOuDf2c9OaC7cdmynADU3RkAQNT -dGQBAGGGItF7rvBmAt/ndcmA4LNrbrroCQ2AdfdRO+xLk/ZNBEJvb2wpAAlCaXAz +dGQBAGGGItF7rvBmAt/ndcmA4LNrbrroCQ2AdfdRO+xLk/ZNBEJvb2wrAAlCaXAz NDBTaWcGAgNzaWcABwAAQEAADHNpZ2hhc2hfdHlwZQAEAgAEbm9uZQAAAAEEc29t ZQAFAQHbF2Q+dwkTJ+gEmSSB1dxgFSMIlVM55Yszn9RMT3JIKglCbG9ja0hhc2gF AQAHAABAIAALQmxvY2tIZWFkZXIGBgd2ZXJzaW9uAABEDXByZXZCbG9ja0hhc2gB diff --git a/stl/Bitcoin@0.1.0.sty b/stl/Bitcoin@0.1.0.sty index 025d91e1..bf30d710 100644 --- a/stl/Bitcoin@0.1.0.sty +++ b/stl/Bitcoin@0.1.0.sty @@ -78,8 +78,8 @@ data TapCode :: pushBytes32:32 | pushData1:76 | pushData2:77 | pushData -- urn:ubideco:semid:FHWiTycy1JvN5CvVJ3ibyAhtXfr21t3BDNuLFnqYPQ2j#middle-jazz-basket data TapLeafHash :: [Byte ^ 32] --- urn:ubideco:semid:5YrqoQi4fLCLqzBE1ZKb623WC311FGRgjcivLPXadnEN#gossip-protein-orion -data TapMerklePath :: [TapBranchHash ^ ..0xff] +-- urn:ubideco:semid:2Cy61crHEVHKfCSix5WhmS9ms6J4FFE9wCC6pLsyondh#dublin-chemist-version +data TapMerklePath :: [TapBranchHash ^ ..0x80] -- urn:ubideco:semid:4M8xyvABKKKJseN6Pme5eKrAuusMNMXoY5s6ifsEcreC#crash-culture-jamaica data TapNodeHash :: [Byte ^ 32] -- urn:ubideco:semid:71AxyLFsoRG6hJ1c11gxad65nEbWfzkQBjWCPPrgCyjX#telecom-quest-helium From 873ebc804ea717872918a438ab5adbbd2558341c Mon Sep 17 00:00:00 2001 From: Dr Maxim Orlovsky Date: Fri, 6 Oct 2023 01:03:25 +0200 Subject: [PATCH 15/31] primitives: add taproot ControlBlock and Parity structures --- primitives/src/lib.rs | 8 ++-- primitives/src/stl.rs | 14 +++--- primitives/src/taproot.rs | 79 +++++++++++++++++++++++++++++++++ stl/Bitcoin@0.1.0.sta | 90 ++++++++++++++++++++------------------ stl/Bitcoin@0.1.0.stl | Bin 2359 -> 2579 bytes stl/Bitcoin@0.1.0.sty | 10 ++++- 6 files changed, 144 insertions(+), 57 deletions(-) diff --git a/primitives/src/lib.rs b/primitives/src/lib.rs index 434dc329..93b65077 100644 --- a/primitives/src/lib.rs +++ b/primitives/src/lib.rs @@ -21,7 +21,7 @@ // Version 0.10.10: // TODO: Ensure all serde uses both string and binary version -// TODO: Complete taproot consensus structure implementation (ControlBlock) +// TODO: Complete consensus encoding for taproot data // TODO: Complete block data type implementation // TODO: Move consensus-level timelocks and sequence locks from other libraries // Version 1.0: @@ -77,9 +77,9 @@ pub use script::{OpCode, RedeemScript, ScriptBytes, ScriptPubkey, SigScript}; pub use segwit::{SegwitError, Witness, WitnessProgram, WitnessScript, WitnessVer, Wtxid}; pub use sigtypes::{Bip340Sig, LegacySig, SigError, SighashFlag, SighashType}; pub use taproot::{ - FutureLeafVer, InternalPk, IntoTapHash, InvalidLeafVer, LeafScript, LeafVer, TapBranchHash, - TapCode, TapLeafHash, TapMerklePath, TapNodeHash, TapScript, TAPROOT_ANNEX_PREFIX, - TAPROOT_LEAF_MASK, TAPROOT_LEAF_TAPSCRIPT, + ControlBlock, FutureLeafVer, InternalPk, IntoTapHash, InvalidLeafVer, LeafScript, LeafVer, + Parity, TapBranchHash, TapCode, TapLeafHash, TapMerklePath, TapNodeHash, TapScript, + TAPROOT_ANNEX_PREFIX, TAPROOT_LEAF_MASK, TAPROOT_LEAF_TAPSCRIPT, }; pub use tx::{ LockTime, Outpoint, OutpointParseError, Sats, SeqNo, Tx, TxIn, TxOut, TxParseError, TxVer, diff --git a/primitives/src/stl.rs b/primitives/src/stl.rs index d0344b6c..81134e9b 100644 --- a/primitives/src/stl.rs +++ b/primitives/src/stl.rs @@ -23,10 +23,9 @@ use strict_types::{CompileError, LibBuilder, TypeLib}; use crate::{ - Bip340Sig, BlockHeader, ByteStr, Chain, FutureLeafVer, InternalPk, LeafScript, LeafVer, - LegacySig, OpCode, RedeemScript, TapBranchHash, TapCode, TapLeafHash, TapMerklePath, - TapNodeHash, TapScript, Tx, VBytes, VarInt, WeightUnits, WitnessProgram, WitnessScript, - WitnessVer, Wtxid, LIB_NAME_BITCOIN, + Bip340Sig, BlockHeader, ByteStr, Chain, ControlBlock, FutureLeafVer, LeafScript, LegacySig, + OpCode, RedeemScript, TapCode, TapLeafHash, TapNodeHash, TapScript, Tx, VBytes, VarInt, + WeightUnits, WitnessProgram, WitnessScript, WitnessVer, Wtxid, LIB_NAME_BITCOIN, }; #[deprecated(since = "0.10.8", note = "use LIB_ID_BP_TX instead")] @@ -35,7 +34,7 @@ pub const LIB_ID_BITCOIN: &str = pub const LIB_ID_BP_TX: &str = "urn:ubideco:stl:6GgF7biXPVNcus2FfQj2pQuRzau11rXApMQLfCZhojgi#money-pardon-parody"; pub const LIB_ID_BP_CONSENSUS: &str = - "urn:ubideco:stl:DrkRxZuxVjPSc5CtPmXhxQ14wyfVDz787WEfdrgqgffB#gray-prepare-proton"; + "urn:ubideco:stl:A6tfQFthqmb39wR5sWvrfgf3oiAyazm8rh7ff35ruioi#russian-emerald-extra"; #[deprecated(since = "0.10.8", note = "use _bp_tx_stl instead")] fn _bitcoin_stl() -> Result { _bp_tx_stl() } @@ -59,15 +58,12 @@ fn _bp_consensus_stl() -> Result { .transpile::() .transpile::() .transpile::() - .transpile::() .transpile::() - .transpile::() - .transpile::() - .transpile::() .transpile::() .transpile::() .transpile::() .transpile::() + .transpile::() .transpile::() .transpile::() .transpile::() diff --git a/primitives/src/taproot.rs b/primitives/src/taproot.rs index d7847195..3b0aaeaf 100644 --- a/primitives/src/taproot.rs +++ b/primitives/src/taproot.rs @@ -23,6 +23,7 @@ use std::borrow::Borrow; use std::fmt::{self, Formatter, LowerHex, UpperHex}; +use std::ops::BitXor; use std::{cmp, io}; use amplify::confinement::{Confined, U32}; @@ -457,3 +458,81 @@ impl ScriptPubkey { self.len() == 34 && self[0] == WitnessVer::V1.op_code() as u8 && self[1] == OP_PUSHBYTES_32 } } + +/// invalid parity value {0} - must be 0 or 1 +#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug, Display, Error)] +#[display(doc_comments)] +pub struct InvalidParityValue(pub u8); + +/// Represents the parity passed between FFI function calls. +#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Display)] +#[display(lowercase)] +#[derive(StrictType, StrictEncode, StrictDecode, StrictDumb)] +#[strict_type(lib = LIB_NAME_BITCOIN, tags = repr, into_u8, try_from_u8)] +#[cfg_attr( + feature = "serde", + derive(Serialize, Deserialize), + serde(crate = "serde_crate", rename_all = "camelCase") +)] +#[repr(u8)] +pub enum Parity { + /// Even parity. + #[strict_type(dumb)] + Even = 0, + /// Odd parity. + Odd = 1, +} + +impl Parity { + /// Converts parity into an integer (byte) value. + /// + /// This returns `0` for even parity and `1` for odd parity. + pub fn to_consensus_u8(self) -> u8 { self as u8 } + + /// Constructs a [`Parity`] from a byte. + /// + /// The only allowed values are `0` meaning even parity and `1` meaning odd. + /// Other values result in error being returned. + pub fn from_consensus_u8(parity: u8) -> Result { + match parity { + 0 => Ok(Parity::Even), + 1 => Ok(Parity::Odd), + invalid => Err(InvalidParityValue(invalid)), + } + } +} + +/// Returns even parity if the operands are equal, odd otherwise. +impl BitXor for Parity { + type Output = Parity; + + fn bitxor(self, rhs: Parity) -> Self::Output { + // This works because Parity has only two values (i.e. only 1 bit of + // information). + if self == rhs { + Parity::Even // 1^1==0 and 0^0==0 + } else { + Parity::Odd // 1^0==1 and 0^1==1 + } + } +} + +#[derive(Clone, Eq, PartialEq, Hash, Debug)] +#[derive(StrictType, StrictEncode, StrictDecode, StrictDumb)] +#[strict_type(lib = LIB_NAME_BITCOIN)] +#[cfg_attr( + feature = "serde", + derive(Serialize, Deserialize), + serde(crate = "serde_crate", rename_all = "camelCase") +)] +pub struct ControlBlock { + /// The tapleaf version. + pub leaf_version: LeafVer, + /// The parity of the output key (NOT THE INTERNAL KEY WHICH IS ALWAYS + /// XONLY). + pub output_key_parity: Parity, + /// The internal key. + pub internal_key: InternalPk, + /// The merkle proof of a script associated with this leaf. + pub merkle_branch: TapMerklePath, +} diff --git a/stl/Bitcoin@0.1.0.sta b/stl/Bitcoin@0.1.0.sta index 820cd249..c37e080a 100644 --- a/stl/Bitcoin@0.1.0.sta +++ b/stl/Bitcoin@0.1.0.sta @@ -1,5 +1,5 @@ -----BEGIN STRICT TYPE LIB----- -Id: urn:ubideco:stl:DrkRxZuxVjPSc5CtPmXhxQ14wyfVDz787WEfdrgqgffB +Id: urn:ubideco:stl:A6tfQFthqmb39wR5sWvrfgf3oiAyazm8rh7ff35ruioi Name: Bitcoin Dependencies: urn:ubideco:stl:9KALDYR8Nyjq4FdMW6kYoL7vdkWnqPqNuFnmE9qHpNjZ @@ -12,48 +12,52 @@ AQAHAABAIAALQmxvY2tIZWFkZXIGBgd2ZXJzaW9uAABEDXByZXZCbG9ja0hhc2gB 136XKN8Qx+HJT3+gvLwHRRJSZMs+SsX4k0LE/8jKtLcKbWVya2xlUm9vdAAHAABA IAAEdGltZQAABARiaXRzAAAEBW5vbmNlAAAEB0J5dGVTdHIFAQAIAABAAAAAAAAA AAD/////AAAAAAVDaGFpbgMEB2JpdGNvaW4AB3JlZ3Rlc3SACHRlc3RuZXQzgwZz -aWduZXSEDUZ1dHVyZUxlYWZWZXIFAQAAAQpJbnRlcm5hbFBrBQEABwAAQCAACkxl -YWZTY3JpcHQGAgd2ZXJzaW9uAbYzCakYv7aSDW7IWKQkhyNGWmk/ckMHv/8d1zpz -gU7JBnNjcmlwdAElq/W5EhQXuqM51F97FXWncUvhenUYXdAxNXrUyS3phgdMZWFm -VmVyBQEAAAEJTGVnYWN5U2lnBgIDc2lnAAgAAEAAAAAAAAAAAP8AAAAAAAAADHNp -Z2hhc2hfdHlwZQHbF2Q+dwkTJ+gEmSSB1dxgFSMIlVM55Yszn9RMT3JIKghMb2Nr -VGltZQUBAAAEBk9wQ29kZQMSCnB1c2hCeXRlczAAC3B1c2hCeXRlczMyIAlwdXNo -RGF0YTFMCXB1c2hEYXRhMk0JcHVzaERhdGE0TghyZXNlcnZlZFAIcHVzaE51bTFR -BnJldHVybmoDZHVwdgVlcXVhbIcLZXF1YWxWZXJpZnmICXJpcGVtZDE2MKYEc2hh -MacGc2hhMjU2qAdoYXNoMTYwqQdoYXNoMjU2qghjaGVja1NpZ6wOY2hlY2tTaWdW -ZXJpZnmtCE91dHBvaW50BgIEdHhpZAGjgkLzy9fR0KES2o3hYC9W1PhvDsTEdsXA -aFlMSwRlVgR2b3V0ASHjPkPFqlzyKSdTozjBZ+07Y5xN2c69qY80aRe6yUN1DFJl -ZGVlbVNjcmlwdAUBASWr9bkSFBe6oznUX3sVdadxS+F6dRhd0DE1etTJLemGBFNh -dHMFAQAACAtTY3JpcHRCeXRlcwUBAAgAAEAAAAAAAAAAAP////8AAAAADFNjcmlw -dFB1YmtleQUBASWr9bkSFBe6oznUX3sVdadxS+F6dRhd0DE1etTJLemGBVNlcU5v -BQEAAAQJU2lnU2NyaXB0BQEBJav1uRIUF7qjOdRfexV1p3FL4Xp1GF3QMTV61Mkt -6YYLU2lnaGFzaEZsYWcDAwNhbGwBBG5vbmUCBnNpbmdsZQMLU2lnaGFzaFR5cGUG -AgRmbGFnAf8+an/Ix4VDTvyO53SzALGb7Jhxopoe8QCL7xDrKNU0DGFueW9uZUNh -blBheQJ7hIA8nvriESWnfCw5vHDS/ej5Q64N/Zz05oLtx2bKcGGGItF7rvBmAt/n -dcmA4LNrbrroCQ2AdfdRO+xLk/ZNDVRhcEJyYW5jaEhhc2gFAQAHAABAIAAHVGFw -Q29kZQMGC3B1c2hCeXRlczMyIAlwdXNoRGF0YTFMCXB1c2hEYXRhMk0JcHVzaERh -dGE0TghyZXNlcnZlZFAGcmV0dXJuagtUYXBMZWFmSGFzaAUBAAcAAEAgAA1UYXBN -ZXJrbGVQYXRoBQEACAGv68Wd2P1QRx2YXcJBKC6rqYxIivJkY8F2flEGIsKS2AAA -AAAAAAAA/wAAAAAAAAALVGFwTm9kZUhhc2gFAQAHAABAIAAJVGFwU2NyaXB0BQEB -Jav1uRIUF7qjOdRfexV1p3FL4Xp1GF3QMTV61Mkt6YYCVHgGBAd2ZXJzaW9uAah8 -xnlkZ+VX10TlyWI64AzLldkaDS8D33TAdRJPvseeBmlucHV0cwAIARlHLRfYYgen -DyExqVihaKVuKtZTP5xmTBl32lz5/mKGAAAAAAAAAAD/////AAAAAAdvdXRwdXRz -AAgBkDtkcHmEjxsmUyrkzsamiUSgU1i48IHLJrO7+C2eO/MAAAAAAAAAAP////8A -AAAACGxvY2tUaW1lATXaHRU5IG673dykwz2HMerym6fadN89yIIgHE4WtbkcBFR4 -SW4GBApwcmV2T3V0cHV0AehqQM1cJfm94oT/aaURMqdBKyFVvQ5WEsG/44SVYMUG -CXNpZ1NjcmlwdAE4dQSxS3wORm1HnhdHfSR0JH/4A2TsPUuq9zog90F0awhzZXF1 -ZW5jZQEBGW2FKcj22kRNFU6NnIy9ng+NiQJaO7CRIcY9UrAehwd3aXRuZXNzAXN3 -Q3A2kyBJzSiVCKpxfOOCnbJFLlXoTtT8LjzNLgCdBVR4T3V0BgIFdmFsdWUBl/XX -BkKuKjOSJTuoTh3OxJPjvz7TcbGHc4Y1TsyIgmsMc2NyaXB0UHVia2V5Ab78Hvxm -pRn9ZFJqOhOHQOfxEC0Lvv86wUZO8/dAdnRcBVR4VmVyBQEAAEQEVHhpZAUBAAcA -AEAgAAZWQnl0ZXMFAQAABAZWYXJJbnQFAQAACARWb3V0BQEAAAQLV2VpZ2h0VW5p -dHMFAQAABAdXaXRuZXNzBQEACAAIAABAAAAAAAAAAAD/////AAAAAAAAAAAAAAAA -/////wAAAAAOV2l0bmVzc1Byb2dyYW0GAgd2ZXJzaW9uAdHs2nZn5ELtTRJppmcD -NuX+9DevXs4raa66DEZWxPqtB3Byb2dyYW0ACAAAQAIAAAAAAAAAKAAAAAAAAAAN -V2l0bmVzc1NjcmlwdAUBASWr9bkSFBe6oznUX3sVdadxS+F6dRhd0DE1etTJLemG -CldpdG5lc3NWZXIDEQJ2MAACdjFRAnYyUgJ2M1MCdjRUAnY1VQJ2NlYCdjdXAnY4 -WAJ2OVkDdjEwWgN2MTFbA3YxMlwDdjEzXQN2MTReA3YxNV8DdjE2YAVXdHhpZAUB -AAcAAEAgAA== +aWduZXSEDENvbnRyb2xCbG9jawYEC2xlYWZWZXJzaW9uAbYzCakYv7aSDW7IWKQk +hyNGWmk/ckMHv/8d1zpzgU7JD291dHB1dEtleVBhcml0eQGPyiYjolVEI5WPpnqn +bUNqFd5k6xCz9PmZFCIvlRFmiAtpbnRlcm5hbEtleQHf+AA8gf5H/FQjsdLG4g8N +36pmvczzfXQTyR9l2gA8iAxtZXJrbGVCcmFuY2gB7gMeZlFQaLZ0GVxRd/QKg8QA +UlvBpDAUGABpT73wc6QNRnV0dXJlTGVhZlZlcgUBAAABCkludGVybmFsUGsFAQAH +AABAIAAKTGVhZlNjcmlwdAYCB3ZlcnNpb24BtjMJqRi/tpINbshYpCSHI0ZaaT9y +Qwe//x3XOnOBTskGc2NyaXB0ASWr9bkSFBe6oznUX3sVdadxS+F6dRhd0DE1etTJ +LemGB0xlYWZWZXIFAQAAAQlMZWdhY3lTaWcGAgNzaWcACAAAQAAAAAAAAAAA/wAA +AAAAAAAMc2lnaGFzaF90eXBlAdsXZD53CRMn6ASZJIHV3GAVIwiVUznlizOf1ExP +ckgqCExvY2tUaW1lBQEAAAQGT3BDb2RlAxIKcHVzaEJ5dGVzMAALcHVzaEJ5dGVz +MzIgCXB1c2hEYXRhMUwJcHVzaERhdGEyTQlwdXNoRGF0YTROCHJlc2VydmVkUAhw +dXNoTnVtMVEGcmV0dXJuagNkdXB2BWVxdWFshwtlcXVhbFZlcmlmeYgJcmlwZW1k +MTYwpgRzaGExpwZzaGEyNTaoB2hhc2gxNjCpB2hhc2gyNTaqCGNoZWNrU2lnrA5j +aGVja1NpZ1Zlcmlmea0IT3V0cG9pbnQGAgR0eGlkAaOCQvPL19HQoRLajeFgL1bU ++G8OxMR2xcBoWUxLBGVWBHZvdXQBIeM+Q8WqXPIpJ1OjOMFn7TtjnE3Zzr2pjzRp +F7rJQ3UGUGFyaXR5AwIEZXZlbgADb2RkAQxSZWRlZW1TY3JpcHQFAQElq/W5EhQX +uqM51F97FXWncUvhenUYXdAxNXrUyS3phgRTYXRzBQEAAAgLU2NyaXB0Qnl0ZXMF +AQAIAABAAAAAAAAAAAD/////AAAAAAxTY3JpcHRQdWJrZXkFAQElq/W5EhQXuqM5 +1F97FXWncUvhenUYXdAxNXrUyS3phgVTZXFObwUBAAAECVNpZ1NjcmlwdAUBASWr +9bkSFBe6oznUX3sVdadxS+F6dRhd0DE1etTJLemGC1NpZ2hhc2hGbGFnAwMDYWxs +AQRub25lAgZzaW5nbGUDC1NpZ2hhc2hUeXBlBgIEZmxhZwH/Pmp/yMeFQ078jud0 +swCxm+yYcaKaHvEAi+8Q6yjVNAxhbnlvbmVDYW5QYXkCe4SAPJ764hElp3wsObxw +0v3o+UOuDf2c9OaC7cdmynBhhiLRe67wZgLf53XJgOCza2666AkNgHX3UTvsS5P2 +TQ1UYXBCcmFuY2hIYXNoBQEABwAAQCAAB1RhcENvZGUDBgtwdXNoQnl0ZXMzMiAJ +cHVzaERhdGExTAlwdXNoRGF0YTJNCXB1c2hEYXRhNE4IcmVzZXJ2ZWRQBnJldHVy +bmoLVGFwTGVhZkhhc2gFAQAHAABAIAANVGFwTWVya2xlUGF0aAUBAAgBr+vFndj9 +UEcdmF3CQSguq6mMSIryZGPBdn5RBiLCktgAAAAAAAAAAIAAAAAAAAAAC1RhcE5v +ZGVIYXNoBQEABwAAQCAACVRhcFNjcmlwdAUBASWr9bkSFBe6oznUX3sVdadxS+F6 +dRhd0DE1etTJLemGAlR4BgQHdmVyc2lvbgGofMZ5ZGflV9dE5cliOuAMy5XZGg0v +A990wHUST77HngZpbnB1dHMACAEZRy0X2GIHpw8hMalYoWilbirWUz+cZkwZd9pc ++f5ihgAAAAAAAAAA/////wAAAAAHb3V0cHV0cwAIAZA7ZHB5hI8bJlMq5M7GpolE +oFNYuPCByyazu/gtnjvzAAAAAAAAAAD/////AAAAAAhsb2NrVGltZQE12h0VOSBu +u93cpMM9hzHq8pun2nTfPciCIBxOFrW5HARUeEluBgQKcHJldk91dHB1dAHoakDN +XCX5veKE/2mlETKnQSshVb0OVhLBv+OElWDFBglzaWdTY3JpcHQBOHUEsUt8DkZt +R54XR30kdCR/+ANk7D1Lqvc6IPdBdGsIc2VxdWVuY2UBARlthSnI9tpETRVOjZyM +vZ4PjYkCWjuwkSHGPVKwHocHd2l0bmVzcwFzd0NwNpMgSc0olQiqcXzjgp2yRS5V +6E7U/C48zS4AnQVUeE91dAYCBXZhbHVlAZf11wZCriozkiU7qE4dzsST478+03Gx +h3OGNU7MiIJrDHNjcmlwdFB1YmtleQG+/B78ZqUZ/WRSajoTh0Dn8RAtC77/OsFG +TvP3QHZ0XAVUeFZlcgUBAABEBFR4aWQFAQAHAABAIAAGVkJ5dGVzBQEAAAQGVmFy +SW50BQEAAAgEVm91dAUBAAAEC1dlaWdodFVuaXRzBQEAAAQHV2l0bmVzcwUBAAgA +CAAAQAAAAAAAAAAA/////wAAAAAAAAAAAAAAAP////8AAAAADldpdG5lc3NQcm9n +cmFtBgIHdmVyc2lvbgHR7Np2Z+RC7U0SaaZnAzbl/vQ3r17OK2muugxGVsT6rQdw +cm9ncmFtAAgAAEACAAAAAAAAACgAAAAAAAAADVdpdG5lc3NTY3JpcHQFAQElq/W5 +EhQXuqM51F97FXWncUvhenUYXdAxNXrUyS3phgpXaXRuZXNzVmVyAxECdjAAAnYx +UQJ2MlICdjNTAnY0VAJ2NVUCdjZWAnY3VwJ2OFgCdjlZA3YxMFoDdjExWwN2MTJc +A3YxM10DdjE0XgN2MTVfA3YxNmAFV3R4aWQFAQAHAABAIAA= -----END STRICT TYPE LIB----- diff --git a/stl/Bitcoin@0.1.0.stl b/stl/Bitcoin@0.1.0.stl index ff8596f5164f3712c867248bdd4cc6d705f0f420..75bdc339309f5d806661fd0dcee73eb22fd7dd8e 100644 GIT binary patch delta 218 zcmdlkG+AUqB%}7mC>=&o9_ReLlA`<^r=0xcY&I6|oYcg$u*rKE)$955OG^q$OT1Gn z0}_ieODY-rPpK&{3UyJQ+P|!7d9HJo=)IKJ0-L}5oGGHDKUFZTgF7>?B(*3nF$buH z@%|46o5p|ce?pWuUOM)OpZET%w7q9O*OmyMluy0IVAH{qn_85elj>BIn3tTv_>NgF zEifQsTZv>$VEGrW<|7P2ywL}j7>GzPWcu&@P`qSw8zVcD2phyD%uFn)WvO`#%=sxP SjGKFzC7Bo-HZNzLzzhI)ty81` delta 29 lcmbO%vR!CGB%|iWC>_SleoX94n=@G?nHc|XZf2Xn3;>542+{xm diff --git a/stl/Bitcoin@0.1.0.sty b/stl/Bitcoin@0.1.0.sty index bf30d710..113c8d71 100644 --- a/stl/Bitcoin@0.1.0.sty +++ b/stl/Bitcoin@0.1.0.sty @@ -1,5 +1,5 @@ {- - Id: urn:ubideco:stl:DrkRxZuxVjPSc5CtPmXhxQ14wyfVDz787WEfdrgqgffB#gray-prepare-proton + Id: urn:ubideco:stl:A6tfQFthqmb39wR5sWvrfgf3oiAyazm8rh7ff35ruioi#russian-emerald-extra Name: Bitcoin Version: 0.1.0 Description: Consensus library for bitcoin protocol @@ -32,6 +32,11 @@ data ByteStr :: [Byte ^ ..0xffffffff] -- urn:ubideco:semid:6aRP3odHaTGySvSWHjreC8HsbX5ss9LxkQqwcjaoxhpv#aspirin-brown-alpine data Chain :: bitcoin:0 | regtest:128 | testnet3:131 | signet:132 +-- urn:ubideco:semid:C7rC7icVsoUF43k8QpzxWSx6BAbT8uyY2PWGjsQuf2kd#mega-optic-type +data ControlBlock :: leafVersion LeafVer + , outputKeyParity Parity + , internalKey InternalPk + , merkleBranch TapMerklePath -- urn:ubideco:semid:CvDS9EgqtBkWLvADynNeR7VGwVAy14EXViKnLaBkqtac#student-formula-circus data FutureLeafVer :: U8 -- urn:ubideco:semid:G5HFVaWwWNYSzqk548JgGZ8WKy6dQ2ftVgkJvHjgRudZ#horse-major-vienna @@ -53,6 +58,9 @@ data OpCode :: pushBytes0:0 | pushBytes32:32 | pushData1:76 | pushData -- urn:ubideco:semid:FWt2MSo8A4nsYgYbuBqMRNLiKgtzvLBgUn774iKzTcuf#pocket-pegasus-frank data Outpoint :: txid Txid, vout Vout +-- urn:ubideco:semid:AgJ5n58hrH761B4MV7giZ1FhMipaDrUmnFYCLno74HDy#method-editor-echo +data Parity :: even:0 | odd:1 + -- urn:ubideco:semid:85m9Qv56neQKaqiPSZ8G8NPWz5DDeJeeXhBwnUpcZGug#delta-jumbo-clone data RedeemScript :: ScriptBytes -- urn:ubideco:semid:BEBz6h7AGjYSDRCxVHnjYkkkxzBsjN3EvyNiD4ZrzmRL#pyramid-spray-star From 1c0095fd2fcd7f981b01a3a5ac3b48b1febdf920 Mon Sep 17 00:00:00 2001 From: Dr Maxim Orlovsky Date: Fri, 6 Oct 2023 01:22:46 +0200 Subject: [PATCH 16/31] primitives: implement IntoIterator for TapMerklePath --- primitives/src/taproot.rs | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/primitives/src/taproot.rs b/primitives/src/taproot.rs index 3b0aaeaf..1d00785d 100644 --- a/primitives/src/taproot.rs +++ b/primitives/src/taproot.rs @@ -24,7 +24,7 @@ use std::borrow::Borrow; use std::fmt::{self, Formatter, LowerHex, UpperHex}; use std::ops::BitXor; -use std::{cmp, io}; +use std::{cmp, io, slice, vec}; use amplify::confinement::{Confined, U32}; use amplify::{Bytes32, Wrapper}; @@ -224,6 +224,20 @@ impl IntoTapHash for TapNodeHash { )] pub struct TapMerklePath(Confined, 0, 128>); +impl IntoIterator for TapMerklePath { + type Item = TapBranchHash; + type IntoIter = vec::IntoIter; + + fn into_iter(self) -> Self::IntoIter { self.0.into_iter() } +} + +impl<'a> IntoIterator for &'a TapMerklePath { + type Item = &'a TapBranchHash; + type IntoIter = slice::Iter<'a, TapBranchHash>; + + fn into_iter(self) -> Self::IntoIter { self.0.iter() } +} + /// Taproot annex prefix. pub const TAPROOT_ANNEX_PREFIX: u8 = 0x50; From 7d87b3b5407218580dc8a6f06918ef18d0b10971 Mon Sep 17 00:00:00 2001 From: Dr Maxim Orlovsky Date: Fri, 6 Oct 2023 01:23:24 +0200 Subject: [PATCH 17/31] primitives: refactor LeafVer convertors to match conventions --- primitives/src/taproot.rs | 24 +++++++++++++++++------- 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/primitives/src/taproot.rs b/primitives/src/taproot.rs index 1d00785d..39749d92 100644 --- a/primitives/src/taproot.rs +++ b/primitives/src/taproot.rs @@ -147,7 +147,7 @@ pub struct TapLeafHash( impl TapLeafHash { pub fn with_leaf_script(leaf_script: &LeafScript) -> Self { let mut engine = Sha256::from_tag(MIDSTATE_TAPLEAF); - engine.input_raw(&[leaf_script.version.to_consensus()]); + engine.input_raw(&[leaf_script.version.to_consensus_u8()]); engine.input_with_len::(leaf_script.script.as_slice()); Self(engine.finish().into()) } @@ -280,27 +280,33 @@ impl StrictTuple for LeafVer { } impl StrictEncode for LeafVer { fn strict_encode(&self, writer: W) -> std::io::Result { - writer.write_tuple::(|w| Ok(w.write_field(&self.to_consensus())?.complete())) + writer.write_tuple::(|w| Ok(w.write_field(&self.to_consensus_u8())?.complete())) } } impl StrictDecode for LeafVer { fn strict_decode(reader: &mut impl TypedRead) -> Result { reader.read_tuple(|r| { let version = r.read_field()?; - Self::from_consensus(version) + Self::from_consensus_u8(version) .map_err(|err| DecodeError::DataIntegrityError(err.to_string())) }) } } impl LeafVer { + #[doc(hidden)] + #[deprecated(since = "0.10.9", note = "use from_consensus_u8")] + pub fn from_consensus(version: u8) -> Result { + Self::from_consensus_u8(version) + } + /// Creates a [`LeafVer`] from consensus byte representation. /// /// # Errors /// /// - If the last bit of the `version` is odd. /// - If the `version` is 0x50 ([`TAPROOT_ANNEX_PREFIX`]). - pub fn from_consensus(version: u8) -> Result { + pub fn from_consensus_u8(version: u8) -> Result { match version { TAPROOT_LEAF_TAPSCRIPT => Ok(LeafVer::TapScript), TAPROOT_ANNEX_PREFIX => Err(InvalidLeafVer(TAPROOT_ANNEX_PREFIX)), @@ -308,8 +314,12 @@ impl LeafVer { } } + #[doc(hidden)] + #[deprecated(since = "0.10.9", note = "use to_consensus_u8")] + pub fn to_consensus(self) -> u8 { self.to_consensus_u8() } + /// Returns the consensus representation of this [`LeafVer`]. - pub fn to_consensus(self) -> u8 { + pub fn to_consensus_u8(self) -> u8 { match self { LeafVer::TapScript => TAPROOT_LEAF_TAPSCRIPT, LeafVer::Future(version) => version.to_consensus(), @@ -318,11 +328,11 @@ impl LeafVer { } impl LowerHex for LeafVer { - fn fmt(&self, f: &mut Formatter) -> fmt::Result { LowerHex::fmt(&self.to_consensus(), f) } + fn fmt(&self, f: &mut Formatter) -> fmt::Result { LowerHex::fmt(&self.to_consensus_u8(), f) } } impl UpperHex for LeafVer { - fn fmt(&self, f: &mut Formatter) -> fmt::Result { UpperHex::fmt(&self.to_consensus(), f) } + fn fmt(&self, f: &mut Formatter) -> fmt::Result { UpperHex::fmt(&self.to_consensus_u8(), f) } } /// Inner type representing future (non-tapscript) leaf versions. See From 6c82fe6c412b46bd7bba099c9103ee2558b20693 Mon Sep 17 00:00:00 2001 From: Dr Maxim Orlovsky Date: Fri, 6 Oct 2023 01:23:43 +0200 Subject: [PATCH 18/31] primitives: add TapScript::as_script_bytes method --- primitives/src/taproot.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/primitives/src/taproot.rs b/primitives/src/taproot.rs index 39749d92..156cb540 100644 --- a/primitives/src/taproot.rs +++ b/primitives/src/taproot.rs @@ -454,6 +454,8 @@ impl TapScript { /// Adds a single opcode to the script. pub fn push_opcode(&mut self, op_code: TapCode) { self.0.push(op_code as u8); } + + pub fn as_script_bytes(&self) -> &ScriptBytes { &self.0 } } impl ScriptPubkey { From e2823eb5bac6e47a43ba3af998324207b8383ad7 Mon Sep 17 00:00:00 2001 From: Dr Maxim Orlovsky Date: Fri, 6 Oct 2023 01:24:08 +0200 Subject: [PATCH 19/31] primitives: implement consensus encoding for taproot data --- primitives/src/coding.rs | 106 +++++++++++++++++++++++++++++++++++++-- primitives/src/lib.rs | 5 +- 2 files changed, 105 insertions(+), 6 deletions(-) diff --git a/primitives/src/coding.rs b/primitives/src/coding.rs index dc4550a1..9ab60026 100644 --- a/primitives/src/coding.rs +++ b/primitives/src/coding.rs @@ -24,11 +24,12 @@ use std::io::{self, Cursor, Read, Write}; use amplify::confinement::{Confined, U32}; use amplify::hex::{self, FromHex, ToHex}; -use amplify::{confinement, IoError, RawArray, Wrapper}; +use amplify::{confinement, Bytes32, IoError, RawArray, Wrapper}; use crate::{ - LockTime, Outpoint, Sats, ScriptBytes, ScriptPubkey, SeqNo, SigScript, Tx, TxIn, TxOut, TxVer, - Txid, Vout, Witness, LIB_NAME_BITCOIN, + ControlBlock, InternalPk, LockTime, Outpoint, RedeemScript, Sats, ScriptBytes, ScriptPubkey, + SeqNo, SigScript, TapBranchHash, TapScript, Tx, TxIn, TxOut, TxVer, Txid, Vout, Witness, + WitnessScript, LIB_NAME_BITCOIN, }; pub type VarIntArray = Confined, 0, U32>; @@ -137,6 +138,9 @@ pub enum ConsensusDataError { /// not a minimally-encoded variable integer. NonMinimalVarInt, + /// invalid BIP340 (x-only) pubkey data. + InvalidXonlyPubkey(Bytes32), + #[from] #[display(inner)] Confined(confinement::Error), @@ -371,6 +375,42 @@ impl ConsensusDecode for ScriptPubkey { } } +impl ConsensusEncode for WitnessScript { + fn consensus_encode(&self, writer: &mut impl Write) -> Result { + self.as_script_bytes().consensus_encode(writer) + } +} + +impl ConsensusDecode for WitnessScript { + fn consensus_decode(reader: &mut impl Read) -> Result { + ScriptBytes::consensus_decode(reader).map(Self::from_inner) + } +} + +impl ConsensusEncode for RedeemScript { + fn consensus_encode(&self, writer: &mut impl Write) -> Result { + self.as_script_bytes().consensus_encode(writer) + } +} + +impl ConsensusDecode for RedeemScript { + fn consensus_decode(reader: &mut impl Read) -> Result { + ScriptBytes::consensus_decode(reader).map(Self::from_inner) + } +} + +impl ConsensusEncode for TapScript { + fn consensus_encode(&self, writer: &mut impl Write) -> Result { + self.as_script_bytes().consensus_encode(writer) + } +} + +impl ConsensusDecode for TapScript { + fn consensus_decode(reader: &mut impl Read) -> Result { + ScriptBytes::consensus_decode(reader).map(Self::from_inner) + } +} + impl ConsensusEncode for SigScript { fn consensus_encode(&self, writer: &mut impl Write) -> Result { self.as_script_bytes().consensus_encode(writer) @@ -395,6 +435,54 @@ impl ConsensusDecode for Witness { } } +impl ConsensusEncode for InternalPk { + fn consensus_encode(&self, writer: &mut impl Write) -> Result { + writer.write_all(&self.to_byte_array())?; + Ok(32) + } +} + +impl ConsensusEncode for TapBranchHash { + fn consensus_encode(&self, writer: &mut impl Write) -> Result { + writer.write_all(&self.to_raw_array())?; + Ok(32) + } +} + +impl ConsensusDecode for TapBranchHash { + fn consensus_decode(reader: &mut impl Read) -> Result { + let mut buf = [0u8; 32]; + reader.read_exact(&mut buf)?; + Ok(TapBranchHash::from_raw_array(buf)) + } +} + +impl ConsensusDecode for InternalPk { + fn consensus_decode(reader: &mut impl Read) -> Result { + let mut buf = [0u8; 32]; + reader.read_exact(&mut buf)?; + InternalPk::from_byte_array(buf) + .map_err(|_| ConsensusDataError::InvalidXonlyPubkey(buf.into()).into()) + } +} + +impl ConsensusEncode for ControlBlock { + fn consensus_encode(&self, writer: &mut impl Write) -> Result { + let mut counter = 0; + + let first_byte = + self.leaf_version.to_consensus_u8() & self.output_key_parity.to_consensus_u8(); + first_byte.consensus_encode(writer)?; + + counter += self.internal_key.consensus_encode(writer)?; + for step in &self.merkle_branch { + counter += step.consensus_encode(writer)?; + } + + Ok(counter) + } +} + impl ConsensusEncode for Sats { fn consensus_encode(&self, writer: &mut impl Write) -> Result { self.0.consensus_encode(writer) @@ -466,6 +554,18 @@ impl ConsensusDecode for VarInt { } } +impl ConsensusEncode for ByteStr { + fn consensus_encode(&self, writer: &mut impl Write) -> Result { + self.0.consensus_encode(writer) + } +} + +impl ConsensusDecode for ByteStr { + fn consensus_decode(reader: &mut impl Read) -> Result { + VarIntArray::consensus_decode(reader).map(Self::from_inner) + } +} + impl ConsensusEncode for VarIntArray { fn consensus_encode(&self, writer: &mut impl Write) -> Result { let mut counter = self.len_var_int().consensus_encode(writer)?; diff --git a/primitives/src/lib.rs b/primitives/src/lib.rs index 93b65077..939f07d4 100644 --- a/primitives/src/lib.rs +++ b/primitives/src/lib.rs @@ -21,11 +21,10 @@ // Version 0.10.10: // TODO: Ensure all serde uses both string and binary version -// TODO: Complete consensus encoding for taproot data -// TODO: Complete block data type implementation // TODO: Move consensus-level timelocks and sequence locks from other libraries // Version 1.0: -// TODO: Complete OpCode structure implementation +// TODO: Complete block data type implementation +// TODO: Complete OpCode enumeration // TODO: Do a no-std feature // Coding conventions From 9baa1e83586f89f1cd653347569fa9c2cc113f18 Mon Sep 17 00:00:00 2001 From: Dr Maxim Orlovsky Date: Fri, 6 Oct 2023 01:26:44 +0200 Subject: [PATCH 20/31] primitives: fix taproot error export --- primitives/src/lib.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/primitives/src/lib.rs b/primitives/src/lib.rs index 939f07d4..e568ec51 100644 --- a/primitives/src/lib.rs +++ b/primitives/src/lib.rs @@ -76,9 +76,9 @@ pub use script::{OpCode, RedeemScript, ScriptBytes, ScriptPubkey, SigScript}; pub use segwit::{SegwitError, Witness, WitnessProgram, WitnessScript, WitnessVer, Wtxid}; pub use sigtypes::{Bip340Sig, LegacySig, SigError, SighashFlag, SighashType}; pub use taproot::{ - ControlBlock, FutureLeafVer, InternalPk, IntoTapHash, InvalidLeafVer, LeafScript, LeafVer, - Parity, TapBranchHash, TapCode, TapLeafHash, TapMerklePath, TapNodeHash, TapScript, - TAPROOT_ANNEX_PREFIX, TAPROOT_LEAF_MASK, TAPROOT_LEAF_TAPSCRIPT, + ControlBlock, FutureLeafVer, InternalPk, IntoTapHash, InvalidLeafVer, InvalidParityValue, + InvalidPubkey, LeafScript, LeafVer, Parity, TapBranchHash, TapCode, TapLeafHash, TapMerklePath, + TapNodeHash, TapScript, TAPROOT_ANNEX_PREFIX, TAPROOT_LEAF_MASK, TAPROOT_LEAF_TAPSCRIPT, }; pub use tx::{ LockTime, Outpoint, OutpointParseError, Sats, SeqNo, Tx, TxIn, TxOut, TxParseError, TxVer, From f1cdb38ce022264324dc59ca49521f31fda5477b Mon Sep 17 00:00:00 2001 From: Dr Maxim Orlovsky Date: Fri, 6 Oct 2023 01:34:45 +0200 Subject: [PATCH 21/31] primitives: implement AsRef and serde for ByteStr --- primitives/src/coding.rs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/primitives/src/coding.rs b/primitives/src/coding.rs index 9ab60026..676a61e6 100644 --- a/primitives/src/coding.rs +++ b/primitives/src/coding.rs @@ -85,8 +85,17 @@ impl LenVarInt for VarIntArray { #[strict_type(lib = LIB_NAME_BITCOIN)] #[wrapper(Deref, Index, RangeOps, BorrowSlice)] #[wrapper_mut(DerefMut, IndexMut, RangeMut, BorrowSliceMut)] +#[cfg_attr( + feature = "serde", + derive(Serialize, Deserialize), + serde(crate = "serde_crate", transparent) +)] pub struct ByteStr(VarIntArray); +impl AsRef<[u8]> for ByteStr { + fn as_ref(&self) -> &[u8] { self.0.as_slice() } +} + impl From> for ByteStr { fn from(value: Vec) -> Self { Self(Confined::try_from(value).expect("u64 >= usize")) } } From a23d9e7d31057e2e202dc6bbd7d1d5c34fff3322 Mon Sep 17 00:00:00 2001 From: Dr Maxim Orlovsky Date: Fri, 6 Oct 2023 10:03:06 +0200 Subject: [PATCH 22/31] chore: update to new amplify ByteArray APIs --- Cargo.lock | 4 ++-- Cargo.toml | 2 +- dbc/src/tapret/tapscript.rs | 4 ++-- primitives/src/coding.rs | 8 ++++---- primitives/src/tx.rs | 10 +++++----- 5 files changed, 14 insertions(+), 14 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 8377f1c4..8727111e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4,9 +4,9 @@ version = 3 [[package]] name = "amplify" -version = "4.1.1" +version = "4.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3f58ae011435caa061fb64894c7b05d615321011d35dd07b53b2843a4b61933" +checksum = "add3e79c9c3e33209e1676562e0fda882bc20701f52870ba162d9f046b7d8b0b" dependencies = [ "amplify_apfloat", "amplify_derive 3.0.1", diff --git a/Cargo.toml b/Cargo.toml index 11fedf1e..7c6fc667 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -21,7 +21,7 @@ edition = "2021" license = "Apache-2.0" [workspace.dependencies] -amplify = "4.0.2" +amplify = "4.2.0" strict_encoding = "2.5.0" commit_verify = "0.10.5" single_use_seals = "0.10.0" diff --git a/dbc/src/tapret/tapscript.rs b/dbc/src/tapret/tapscript.rs index 97fd526a..00d68836 100644 --- a/dbc/src/tapret/tapscript.rs +++ b/dbc/src/tapret/tapscript.rs @@ -118,7 +118,7 @@ impl CommitVerify for TapScript { #[cfg(test)] mod test { - use amplify::RawArray; + use amplify::ByteArray; use commit_verify::{Digest, Sha256}; use super::*; @@ -126,7 +126,7 @@ mod test { pub fn commitment() -> TapretCommitment { let msg = Sha256::digest("test data"); TapretCommitment { - mpc: mpc::Commitment::from_raw_array(msg), + mpc: mpc::Commitment::from_byte_array(msg), nonce: 8, } } diff --git a/primitives/src/coding.rs b/primitives/src/coding.rs index 676a61e6..eb2d0ff4 100644 --- a/primitives/src/coding.rs +++ b/primitives/src/coding.rs @@ -24,7 +24,7 @@ use std::io::{self, Cursor, Read, Write}; use amplify::confinement::{Confined, U32}; use amplify::hex::{self, FromHex, ToHex}; -use amplify::{confinement, Bytes32, IoError, RawArray, Wrapper}; +use amplify::{confinement, ByteArray, Bytes32, IoError, Wrapper}; use crate::{ ControlBlock, InternalPk, LockTime, Outpoint, RedeemScript, Sats, ScriptBytes, ScriptPubkey, @@ -313,7 +313,7 @@ impl ConsensusDecode for Outpoint { impl ConsensusEncode for Txid { fn consensus_encode(&self, writer: &mut impl Write) -> Result { - writer.write_all(&self.to_raw_array())?; + writer.write_all(&self.to_byte_array())?; Ok(32) } } @@ -453,7 +453,7 @@ impl ConsensusEncode for InternalPk { impl ConsensusEncode for TapBranchHash { fn consensus_encode(&self, writer: &mut impl Write) -> Result { - writer.write_all(&self.to_raw_array())?; + writer.write_all(&self.to_byte_array())?; Ok(32) } } @@ -462,7 +462,7 @@ impl ConsensusDecode for TapBranchHash { fn consensus_decode(reader: &mut impl Read) -> Result { let mut buf = [0u8; 32]; reader.read_exact(&mut buf)?; - Ok(TapBranchHash::from_raw_array(buf)) + Ok(TapBranchHash::from_byte_array(buf)) } } diff --git a/primitives/src/tx.rs b/primitives/src/tx.rs index 93224319..c550cc38 100644 --- a/primitives/src/tx.rs +++ b/primitives/src/tx.rs @@ -27,7 +27,7 @@ use std::num::ParseIntError; use std::str::FromStr; use amplify::hex::{self, FromHex, ToHex}; -use amplify::{Bytes32StrRev, RawArray, Wrapper}; +use amplify::{ByteArray, Bytes32StrRev, Wrapper}; use commit_verify::{DigestExt, Sha256}; use crate::{ @@ -57,7 +57,7 @@ impl Txid { #[inline] pub const fn coinbase() -> Self { Self(Bytes32StrRev::zero()) } #[inline] - pub fn is_coinbase(&self) -> bool { self.to_raw_array() == [0u8; 32] } + pub fn is_coinbase(&self) -> bool { self.to_byte_array() == [0u8; 32] } } impl FromHex for Txid { @@ -529,7 +529,7 @@ impl Tx { /// /// This gives a way to identify a transaction that is "the same" as /// another in the sense of having same inputs and outputs. - pub fn ntxid(&self) -> [u8; 32] { self.to_unsigned_tx().txid().to_raw_array() } + pub fn ntxid(&self) -> [u8; 32] { self.to_unsigned_tx().txid().to_byte_array() } /// Computes the [`Txid`]. /// @@ -553,7 +553,7 @@ impl Tx { .expect("engines don't error"); let mut double = Sha256::default(); double.input_raw(&enc.finish()); - Txid::from_raw_array(double.finish()) + Txid::from_byte_array(double.finish()) } /// Computes the segwit version of the transaction id. @@ -568,7 +568,7 @@ impl Tx { .expect("engines don't error"); let mut double = Sha256::default(); double.input_raw(&enc.finish()); - Wtxid::from_raw_array(double.finish()) + Wtxid::from_byte_array(double.finish()) } } From 8efffe91a13bb4ffa3a134cc00a2f3d06c634fc5 Mon Sep 17 00:00:00 2001 From: Dr Maxim Orlovsky Date: Fri, 6 Oct 2023 10:03:31 +0200 Subject: [PATCH 23/31] primitives: implement consensus decoding for ControlBlock --- primitives/src/coding.rs | 46 ++++++++++++++++++++++++++++++++++++--- primitives/src/taproot.rs | 23 +++++++++++++++++++- 2 files changed, 65 insertions(+), 4 deletions(-) diff --git a/primitives/src/coding.rs b/primitives/src/coding.rs index eb2d0ff4..44ffc84e 100644 --- a/primitives/src/coding.rs +++ b/primitives/src/coding.rs @@ -27,9 +27,9 @@ use amplify::hex::{self, FromHex, ToHex}; use amplify::{confinement, ByteArray, Bytes32, IoError, Wrapper}; use crate::{ - ControlBlock, InternalPk, LockTime, Outpoint, RedeemScript, Sats, ScriptBytes, ScriptPubkey, - SeqNo, SigScript, TapBranchHash, TapScript, Tx, TxIn, TxOut, TxVer, Txid, Vout, Witness, - WitnessScript, LIB_NAME_BITCOIN, + ControlBlock, InternalPk, InvalidLeafVer, LeafVer, LockTime, Outpoint, Parity, RedeemScript, + Sats, ScriptBytes, ScriptPubkey, SeqNo, SigScript, TapBranchHash, TapMerklePath, TapScript, Tx, + TxIn, TxOut, TxVer, Txid, Vout, Witness, WitnessScript, LIB_NAME_BITCOIN, }; pub type VarIntArray = Confined, 0, U32>; @@ -133,7 +133,9 @@ pub enum ConsensusDecodeError { #[from(io::Error)] Io(IoError), + #[display(inner)] #[from] + #[from(InvalidLeafVer)] #[from(confinement::Error)] Data(ConsensusDataError), } @@ -150,6 +152,17 @@ pub enum ConsensusDataError { /// invalid BIP340 (x-only) pubkey data. InvalidXonlyPubkey(Bytes32), + /// taproot Merkle path length exceeds BIP-341 consensus limit of 128 + /// elements. + LongTapMerklePath, + + /// Merkle path in the `PSBT_IN_TAP_TREE` is not encoded correctly. + InvalidTapMerklePath, + + #[from] + #[display(inner)] + InvalidLeafVer(InvalidLeafVer), + #[from] #[display(inner)] Confined(confinement::Error), @@ -492,6 +505,33 @@ impl ConsensusEncode for ControlBlock { } } +impl ConsensusDecode for ControlBlock { + fn consensus_decode(reader: &mut impl Read) -> Result { + let first_byte = u8::consensus_decode(reader)?; + let leaf_version = LeafVer::from_consensus_u8(first_byte & 0xFE)?; + let output_key_parity = Parity::from_consensus_u8(first_byte & 0x01).expect("binary value"); + + let internal_key = InternalPk::consensus_decode(reader)?; + + let mut buf = vec![]; + reader.read_to_end(&mut buf)?; + let mut iter = buf.chunks_exact(32); + let merkle_branch = iter.by_ref().map(TapBranchHash::from_slice_unsafe); + let merkle_branch = TapMerklePath::try_from_iter(merkle_branch) + .map_err(|_| ConsensusDataError::LongTapMerklePath)?; + if !iter.remainder().is_empty() { + return Err(ConsensusDataError::InvalidTapMerklePath.into()); + } + + Ok(ControlBlock { + leaf_version, + output_key_parity, + internal_key, + merkle_branch, + }) + } +} + impl ConsensusEncode for Sats { fn consensus_encode(&self, writer: &mut impl Write) -> Result { self.0.consensus_encode(writer) diff --git a/primitives/src/taproot.rs b/primitives/src/taproot.rs index 156cb540..2fc4b5a0 100644 --- a/primitives/src/taproot.rs +++ b/primitives/src/taproot.rs @@ -27,7 +27,7 @@ use std::ops::BitXor; use std::{cmp, io, slice, vec}; use amplify::confinement::{Confined, U32}; -use amplify::{Bytes32, Wrapper}; +use amplify::{confinement, Bytes32, Wrapper}; use commit_verify::{DigestExt, Sha256}; use secp256k1::{Scalar, XOnlyPublicKey}; use strict_encoding::{ @@ -238,6 +238,27 @@ impl<'a> IntoIterator for &'a TapMerklePath { fn into_iter(self) -> Self::IntoIter { self.0.iter() } } +impl TapMerklePath { + /// Tries to construct a confinement over a collection. Fails if the number + /// of items in the collection exceeds one of the confinement bounds. + // We can't use `impl TryFrom` due to the conflict with core library blanked + // implementation + #[inline] + pub fn try_from(path: Vec) -> Result { + Confined::try_from(path).map(Self::from_inner) + } + + /// Tries to construct a confinement with a collection of elements taken + /// from an iterator. Fails if the number of items in the collection + /// exceeds one of the confinement bounds. + #[inline] + pub fn try_from_iter>( + iter: I, + ) -> Result { + Confined::try_from_iter(iter).map(Self::from_inner) + } +} + /// Taproot annex prefix. pub const TAPROOT_ANNEX_PREFIX: u8 = 0x50; From b757924d7c7b1a94ddc886fd54462af9755a9dcc Mon Sep 17 00:00:00 2001 From: Dr Maxim Orlovsky Date: Fri, 6 Oct 2023 13:17:25 +0200 Subject: [PATCH 24/31] primitives: add LeafScript constructors --- primitives/src/taproot.rs | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/primitives/src/taproot.rs b/primitives/src/taproot.rs index 2fc4b5a0..7ab9eeda 100644 --- a/primitives/src/taproot.rs +++ b/primitives/src/taproot.rs @@ -417,7 +417,18 @@ impl From for LeafScript { } impl LeafScript { + #[inline] + pub fn new(version: LeafVer, script: ScriptBytes) -> Self { LeafScript { version, script } } + #[inline] + pub fn with_bytes(version: LeafVer, script: Vec) -> Result { + Ok(LeafScript { + version, + script: ScriptBytes::from(script), + }) + } + #[inline] pub fn from_tap_script(tap_script: TapScript) -> Self { Self::from(tap_script) } + #[inline] pub fn tap_leaf_hash(&self) -> TapLeafHash { TapLeafHash::with_leaf_script(self) } } From 808a86e4329a196b139adfd274a25c1be481f73a Mon Sep 17 00:00:00 2001 From: Dr Maxim Orlovsky Date: Fri, 6 Oct 2023 17:21:00 +0200 Subject: [PATCH 25/31] primitives: move TaprootPk and OutputPk from bp-std --- dbc/src/tapret/xonlypk.rs | 9 ++-- primitives/src/lib.rs | 5 +- primitives/src/stl.rs | 11 +++-- primitives/src/taproot.rs | 96 ++++++++++++++++++++++++++++++--------- src/stl.rs | 2 +- 5 files changed, 89 insertions(+), 34 deletions(-) diff --git a/dbc/src/tapret/xonlypk.rs b/dbc/src/tapret/xonlypk.rs index 5ac25b69..8c12e285 100644 --- a/dbc/src/tapret/xonlypk.rs +++ b/dbc/src/tapret/xonlypk.rs @@ -19,9 +19,8 @@ // See the License for the specific language governing permissions and // limitations under the License. -use bc::{InternalPk, TapBranchHash, TapLeafHash, TapNodeHash, TapScript}; +use bc::{InternalPk, OutputPk, TapBranchHash, TapLeafHash, TapNodeHash, TapScript}; use commit_verify::{mpc, CommitVerify, ConvolveCommit, ConvolveCommitProof}; -use secp256k1::XOnlyPublicKey; use super::{Lnpbp12, TapretNodePartner, TapretPathProof, TapretProof}; use crate::tapret::tapscript::TapretCommitment; @@ -46,20 +45,20 @@ pub enum TapretKeyError { impl ConvolveCommitProof for TapretProof { type Suppl = TapretPathProof; - fn restore_original(&self, _: &XOnlyPublicKey) -> InternalPk { self.internal_pk } + fn restore_original(&self, _: &OutputPk) -> InternalPk { self.internal_pk } fn extract_supplement(&self) -> &Self::Suppl { &self.path_proof } } impl ConvolveCommit for InternalPk { - type Commitment = XOnlyPublicKey; + type Commitment = OutputPk; type CommitError = TapretKeyError; fn convolve_commit( &self, supplement: &TapretPathProof, msg: &mpc::Commitment, - ) -> Result<(XOnlyPublicKey, TapretProof), Self::CommitError> { + ) -> Result<(OutputPk, TapretProof), Self::CommitError> { let tapret_commitment = TapretCommitment::with(*msg, supplement.nonce); let script_commitment = TapScript::commit(&tapret_commitment); diff --git a/primitives/src/lib.rs b/primitives/src/lib.rs index e568ec51..9bb67a66 100644 --- a/primitives/src/lib.rs +++ b/primitives/src/lib.rs @@ -77,8 +77,9 @@ pub use segwit::{SegwitError, Witness, WitnessProgram, WitnessScript, WitnessVer pub use sigtypes::{Bip340Sig, LegacySig, SigError, SighashFlag, SighashType}; pub use taproot::{ ControlBlock, FutureLeafVer, InternalPk, IntoTapHash, InvalidLeafVer, InvalidParityValue, - InvalidPubkey, LeafScript, LeafVer, Parity, TapBranchHash, TapCode, TapLeafHash, TapMerklePath, - TapNodeHash, TapScript, TAPROOT_ANNEX_PREFIX, TAPROOT_LEAF_MASK, TAPROOT_LEAF_TAPSCRIPT, + InvalidPubkey, LeafScript, LeafVer, OutputPk, Parity, TapBranchHash, TapCode, TapLeafHash, + TapMerklePath, TapNodeHash, TapScript, TaprootPk, TAPROOT_ANNEX_PREFIX, TAPROOT_LEAF_MASK, + TAPROOT_LEAF_TAPSCRIPT, }; pub use tx::{ LockTime, Outpoint, OutpointParseError, Sats, SeqNo, Tx, TxIn, TxOut, TxParseError, TxVer, diff --git a/primitives/src/stl.rs b/primitives/src/stl.rs index 81134e9b..17a6c76a 100644 --- a/primitives/src/stl.rs +++ b/primitives/src/stl.rs @@ -23,9 +23,10 @@ use strict_types::{CompileError, LibBuilder, TypeLib}; use crate::{ - Bip340Sig, BlockHeader, ByteStr, Chain, ControlBlock, FutureLeafVer, LeafScript, LegacySig, - OpCode, RedeemScript, TapCode, TapLeafHash, TapNodeHash, TapScript, Tx, VBytes, VarInt, - WeightUnits, WitnessProgram, WitnessScript, WitnessVer, Wtxid, LIB_NAME_BITCOIN, + Bip340Sig, BlockHeader, ByteStr, Chain, ControlBlock, FutureLeafVer, InternalPk, LeafScript, + LegacySig, OpCode, OutputPk, RedeemScript, TapCode, TapLeafHash, TapNodeHash, TapScript, Tx, + VBytes, VarInt, WeightUnits, WitnessProgram, WitnessScript, WitnessVer, Wtxid, + LIB_NAME_BITCOIN, }; #[deprecated(since = "0.10.8", note = "use LIB_ID_BP_TX instead")] @@ -34,7 +35,7 @@ pub const LIB_ID_BITCOIN: &str = pub const LIB_ID_BP_TX: &str = "urn:ubideco:stl:6GgF7biXPVNcus2FfQj2pQuRzau11rXApMQLfCZhojgi#money-pardon-parody"; pub const LIB_ID_BP_CONSENSUS: &str = - "urn:ubideco:stl:A6tfQFthqmb39wR5sWvrfgf3oiAyazm8rh7ff35ruioi#russian-emerald-extra"; + "urn:ubideco:stl:A9EKnosv2TJAJvQvRgCDLUpajnfSjS7oRiuogFs1S8Nq#chapter-henry-unit"; #[deprecated(since = "0.10.8", note = "use _bp_tx_stl instead")] fn _bitcoin_stl() -> Result { _bp_tx_stl() } @@ -57,6 +58,8 @@ fn _bp_consensus_stl() -> Result { .transpile::() .transpile::() .transpile::() + .transpile::() + .transpile::() .transpile::() .transpile::() .transpile::() diff --git a/primitives/src/taproot.rs b/primitives/src/taproot.rs index 7ab9eeda..ad2eb300 100644 --- a/primitives/src/taproot.rs +++ b/primitives/src/taproot.rs @@ -69,9 +69,9 @@ pub struct InvalidPubkey; derive(Serialize, Deserialize), serde(crate = "serde_crate", transparent) )] -pub struct InternalPk(XOnlyPublicKey); +pub struct TaprootPk(XOnlyPublicKey); -impl InternalPk { +impl TaprootPk { pub fn from_byte_array(data: [u8; 32]) -> Result { XOnlyPublicKey::from_slice(data.as_ref()) .map(Self) @@ -79,8 +79,54 @@ impl InternalPk { } pub fn to_byte_array(&self) -> [u8; 32] { self.0.serialize() } +} + +impl From for [u8; 32] { + fn from(pk: TaprootPk) -> [u8; 32] { pk.to_byte_array() } +} + +impl StrictEncode for TaprootPk { + fn strict_encode(&self, writer: W) -> io::Result { + let bytes = Bytes32::from(self.0.serialize()); + writer.write_newtype::(&bytes) + } +} + +impl StrictDecode for TaprootPk { + fn strict_decode(reader: &mut impl TypedRead) -> Result { + reader.read_tuple(|r| { + let bytes: Bytes32 = r.read_field()?; + XOnlyPublicKey::from_slice(bytes.as_slice()) + .map(Self) + .map_err(|_| { + DecodeError::DataIntegrityError(format!( + "invalid x-only public key value '{bytes:x}'" + )) + }) + }) + } +} + +#[derive(Wrapper, WrapperMut, Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Debug, From)] +#[wrapper(Deref, LowerHex, Display, FromStr)] +#[wrapper_mut(DerefMut)] +#[derive(StrictType, StrictEncode, StrictDecode, StrictDumb)] +#[strict_type(lib = LIB_NAME_BITCOIN, dumb = Self(strict_dumb!()))] +#[cfg_attr( + feature = "serde", + derive(Serialize, Deserialize), + serde(crate = "serde_crate", transparent) +)] +pub struct InternalPk(TaprootPk); - pub fn to_output_key(&self, merkle_root: Option) -> XOnlyPublicKey { +impl InternalPk { + pub fn from_byte_array(data: [u8; 32]) -> Result { + TaprootPk::from_byte_array(data).map(Self) + } + + pub fn to_byte_array(&self) -> [u8; 32] { self.0.to_byte_array() } + + pub fn to_output_key(&self, merkle_root: Option) -> OutputPk { let mut engine = Sha256::from_tag(MIDSTATE_TAPTWEAK); // always hash the key engine.input_raw(&self.0.serialize()); @@ -99,30 +145,36 @@ impl InternalPk { tweaked_parity, tweak )); - output_key + OutputPk(TaprootPk(output_key)) } } -impl StrictEncode for InternalPk { - fn strict_encode(&self, writer: W) -> io::Result { - let bytes = Bytes32::from(self.0.serialize()); - writer.write_newtype::(&bytes) - } +impl From for [u8; 32] { + fn from(pk: InternalPk) -> [u8; 32] { pk.to_byte_array() } } -impl StrictDecode for InternalPk { - fn strict_decode(reader: &mut impl TypedRead) -> Result { - reader.read_tuple(|r| { - let bytes: Bytes32 = r.read_field()?; - XOnlyPublicKey::from_slice(bytes.as_slice()) - .map(Self) - .map_err(|_| { - DecodeError::DataIntegrityError(format!( - "invalid x-only public key value '{bytes:x}'" - )) - }) - }) +#[derive(Wrapper, WrapperMut, Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Debug, From)] +#[wrapper(Deref, LowerHex, Display, FromStr)] +#[wrapper_mut(DerefMut)] +#[derive(StrictType, StrictEncode, StrictDecode, StrictDumb)] +#[strict_type(lib = LIB_NAME_BITCOIN, dumb = Self(strict_dumb!()))] +#[cfg_attr( + feature = "serde", + derive(Serialize, Deserialize), + serde(crate = "serde_crate", transparent) +)] +pub struct OutputPk(TaprootPk); + +impl OutputPk { + pub fn from_byte_array(data: [u8; 32]) -> Result { + TaprootPk::from_byte_array(data).map(Self) } + + pub fn to_byte_array(&self) -> [u8; 32] { self.0.to_byte_array() } +} + +impl From for [u8; 32] { + fn from(pk: OutputPk) -> [u8; 32] { pk.to_byte_array() } } pub trait IntoTapHash { @@ -506,7 +558,7 @@ impl ScriptPubkey { Self::p2tr_tweaked(output_key) } - pub fn p2tr_tweaked(output_key: XOnlyPublicKey) -> Self { + pub fn p2tr_tweaked(output_key: OutputPk) -> Self { // output key is 32 bytes long, so it's safe to use // `new_witness_program_unchecked` (Segwitv1) Self::with_witness_program_unchecked(WitnessVer::V1, &output_key.serialize()) diff --git a/src/stl.rs b/src/stl.rs index 005f26b9..9745480b 100644 --- a/src/stl.rs +++ b/src/stl.rs @@ -30,7 +30,7 @@ use strict_types::{CompileError, LibBuilder, TypeLib}; /// Strict types id for the library providing data types from [`dbc`] and /// [`seals`] crates. pub const LIB_ID_BPCORE: &str = - "urn:ubideco:stl:2YsxMW6xygK2FxFSbbBLqmzaUSytmLHHNF9DRio5zNr2#sultan-data-copy"; + "urn:ubideco:stl:5cbnbTwuKKKpRqh9WJejEKXcWahnHc3jgwBeJCNr48cL#gyro-minute-maestro"; fn _bp_core_stl() -> Result { LibBuilder::new(libname!(LIB_NAME_BPCORE), tiny_bset! { From 7c10f61996623b8fecb9e5bca744d92186016d69 Mon Sep 17 00:00:00 2001 From: Dr Maxim Orlovsky Date: Fri, 6 Oct 2023 17:28:50 +0200 Subject: [PATCH 26/31] primitives: return output key parity --- dbc/src/tapret/xonlypk.rs | 4 ++-- primitives/src/taproot.rs | 25 ++++++++++++++++++++----- 2 files changed, 22 insertions(+), 7 deletions(-) diff --git a/dbc/src/tapret/xonlypk.rs b/dbc/src/tapret/xonlypk.rs index 8c12e285..65cc05ae 100644 --- a/dbc/src/tapret/xonlypk.rs +++ b/dbc/src/tapret/xonlypk.rs @@ -79,7 +79,7 @@ impl ConvolveCommit for InternalPk { TapLeafHash::with_tap_script(&script_commitment).into() }; - let output_key = self.to_output_key(Some(merkle_root)); + let (output_key, _) = self.to_output_pk(Some(merkle_root)); let proof = TapretProof { path_proof: supplement.clone(), @@ -116,7 +116,7 @@ mod test { let tapret_commitment = TapretCommitment::with(msg, path_proof.nonce); let script_commitment = TapScript::commit(&tapret_commitment); let script_leaf = TapLeafHash::with_tap_script(&script_commitment); - let real_key = internal_pk.to_output_key(Some(script_leaf)); + let (real_key, _) = internal_pk.to_output_pk(Some(script_leaf)); assert_eq!(outer_key, real_key); diff --git a/primitives/src/taproot.rs b/primitives/src/taproot.rs index ad2eb300..18d01caf 100644 --- a/primitives/src/taproot.rs +++ b/primitives/src/taproot.rs @@ -126,7 +126,13 @@ impl InternalPk { pub fn to_byte_array(&self) -> [u8; 32] { self.0.to_byte_array() } - pub fn to_output_key(&self, merkle_root: Option) -> OutputPk { + #[deprecated(since = "0.10.9", note = "use to_output_pk")] + pub fn to_output_key(&self, merkle_root: Option) -> XOnlyPublicKey { + let (pk, _) = self.to_output_pk(merkle_root); + pk.0.0 + } + + pub fn to_output_pk(&self, merkle_root: Option) -> (OutputPk, Parity) { let mut engine = Sha256::from_tag(MIDSTATE_TAPTWEAK); // always hash the key engine.input_raw(&self.0.serialize()); @@ -145,7 +151,7 @@ impl InternalPk { tweaked_parity, tweak )); - OutputPk(TaprootPk(output_key)) + (OutputPk(TaprootPk(output_key)), tweaked_parity.into()) } } @@ -544,17 +550,17 @@ impl TapScript { impl ScriptPubkey { pub fn p2tr(internal_key: InternalPk, merkle_root: Option) -> Self { - let output_key = internal_key.to_output_key(merkle_root); + let (output_key, _) = internal_key.to_output_pk(merkle_root); Self::p2tr_tweaked(output_key) } pub fn p2tr_key_only(internal_key: InternalPk) -> Self { - let output_key = internal_key.to_output_key(None::); + let (output_key, _) = internal_key.to_output_pk(None::); Self::p2tr_tweaked(output_key) } pub fn p2tr_scripted(internal_key: InternalPk, merkle_root: impl IntoTapHash) -> Self { - let output_key = internal_key.to_output_key(Some(merkle_root)); + let (output_key, _) = internal_key.to_output_pk(Some(merkle_root)); Self::p2tr_tweaked(output_key) } @@ -593,6 +599,15 @@ pub enum Parity { Odd = 1, } +impl From for Parity { + fn from(parity: secp256k1::Parity) -> Self { + match parity { + secp256k1::Parity::Even => Parity::Even, + secp256k1::Parity::Odd => Parity::Odd, + } + } +} + impl Parity { /// Converts parity into an integer (byte) value. /// From fc16f588234d9281264ddfc7f5aa5af6bed4aa4d Mon Sep 17 00:00:00 2001 From: Dr Maxim Orlovsky Date: Fri, 6 Oct 2023 17:33:26 +0200 Subject: [PATCH 27/31] primitives: add TaprootPk::from(PublicKey) --- primitives/src/taproot.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/primitives/src/taproot.rs b/primitives/src/taproot.rs index 18d01caf..383e7d44 100644 --- a/primitives/src/taproot.rs +++ b/primitives/src/taproot.rs @@ -29,7 +29,7 @@ use std::{cmp, io, slice, vec}; use amplify::confinement::{Confined, U32}; use amplify::{confinement, Bytes32, Wrapper}; use commit_verify::{DigestExt, Sha256}; -use secp256k1::{Scalar, XOnlyPublicKey}; +use secp256k1::{PublicKey, Scalar, XOnlyPublicKey}; use strict_encoding::{ DecodeError, ReadTuple, StrictDecode, StrictEncode, StrictProduct, StrictTuple, StrictType, TypeName, TypedRead, TypedWrite, WriteTuple, @@ -81,6 +81,10 @@ impl TaprootPk { pub fn to_byte_array(&self) -> [u8; 32] { self.0.serialize() } } +impl From for TaprootPk { + fn from(pubkey: PublicKey) -> Self { TaprootPk(pubkey.x_only_public_key().0) } +} + impl From for [u8; 32] { fn from(pk: TaprootPk) -> [u8; 32] { pk.to_byte_array() } } From a2115740cd8847618361f34e0596e29b8dcedb28 Mon Sep 17 00:00:00 2001 From: Dr Maxim Orlovsky Date: Fri, 6 Oct 2023 17:37:38 +0200 Subject: [PATCH 28/31] primitives: add ControlBlock constructor --- primitives/src/coding.rs | 4 +- primitives/src/stl.rs | 2 +- primitives/src/taproot.rs | 19 ++++++- stl/BPCore@0.1.0.sta | 116 +++++++++++++++++++------------------- stl/BPCore@0.1.0.stl | Bin 3027 -> 3069 bytes stl/BPCore@0.1.0.sty | 9 +-- stl/Bitcoin@0.1.0.sta | 94 +++++++++++++++--------------- stl/Bitcoin@0.1.0.stl | Bin 2579 -> 2667 bytes stl/Bitcoin@0.1.0.sty | 14 +++-- 9 files changed, 141 insertions(+), 117 deletions(-) diff --git a/primitives/src/coding.rs b/primitives/src/coding.rs index 44ffc84e..0f358b3a 100644 --- a/primitives/src/coding.rs +++ b/primitives/src/coding.rs @@ -496,7 +496,7 @@ impl ConsensusEncode for ControlBlock { self.leaf_version.to_consensus_u8() & self.output_key_parity.to_consensus_u8(); first_byte.consensus_encode(writer)?; - counter += self.internal_key.consensus_encode(writer)?; + counter += self.internal_pk.consensus_encode(writer)?; for step in &self.merkle_branch { counter += step.consensus_encode(writer)?; } @@ -526,7 +526,7 @@ impl ConsensusDecode for ControlBlock { Ok(ControlBlock { leaf_version, output_key_parity, - internal_key, + internal_pk: internal_key, merkle_branch, }) } diff --git a/primitives/src/stl.rs b/primitives/src/stl.rs index 17a6c76a..b0f0db84 100644 --- a/primitives/src/stl.rs +++ b/primitives/src/stl.rs @@ -35,7 +35,7 @@ pub const LIB_ID_BITCOIN: &str = pub const LIB_ID_BP_TX: &str = "urn:ubideco:stl:6GgF7biXPVNcus2FfQj2pQuRzau11rXApMQLfCZhojgi#money-pardon-parody"; pub const LIB_ID_BP_CONSENSUS: &str = - "urn:ubideco:stl:A9EKnosv2TJAJvQvRgCDLUpajnfSjS7oRiuogFs1S8Nq#chapter-henry-unit"; + "urn:ubideco:stl:DxmVFuGffDNS1w5tBAhWS798qXBCqDtpmVPQanLbmBRX#vendor-inside-forum"; #[deprecated(since = "0.10.8", note = "use _bp_tx_stl instead")] fn _bitcoin_stl() -> Result { _bp_tx_stl() } diff --git a/primitives/src/taproot.rs b/primitives/src/taproot.rs index 383e7d44..14b09217 100644 --- a/primitives/src/taproot.rs +++ b/primitives/src/taproot.rs @@ -661,7 +661,24 @@ pub struct ControlBlock { /// XONLY). pub output_key_parity: Parity, /// The internal key. - pub internal_key: InternalPk, + pub internal_pk: InternalPk, /// The merkle proof of a script associated with this leaf. pub merkle_branch: TapMerklePath, } + +impl ControlBlock { + #[inline] + pub fn with( + leaf_version: LeafVer, + internal_pk: InternalPk, + output_key_parity: Parity, + merkle_branch: TapMerklePath, + ) -> Self { + ControlBlock { + leaf_version, + output_key_parity, + internal_pk, + merkle_branch, + } + } +} diff --git a/stl/BPCore@0.1.0.sta b/stl/BPCore@0.1.0.sta index 95cb1ff1..4a658d91 100644 --- a/stl/BPCore@0.1.0.sta +++ b/stl/BPCore@0.1.0.sta @@ -1,5 +1,5 @@ -----BEGIN STRICT TYPE LIB----- -Id: urn:ubideco:stl:2YsxMW6xygK2FxFSbbBLqmzaUSytmLHHNF9DRio5zNr2 +Id: urn:ubideco:stl:5cbnbTwuKKKpRqh9WJejEKXcWahnHc3jgwBeJCNr48cL Name: BPCore Dependencies: urn:ubideco:stl:ZtHaBzu9ojbDahaGKEXe5v9DfSDxLERbLkEB23R6Q6V, @@ -8,68 +8,68 @@ Dependencies: BkJQQ29yZQMIbJMpP1Zo7NnfnUB1CNehMyMWREFWAosurAm/5d+NQgxDb21taXRW ZXJpZnlOToT0cBbJ5dJifL/D9Day3WzU0bmwRFv/Xu+CdnJ3VwdCaXRjb2lue4SA -PJ764hElp3wsObxw0v3o+UOuDf2c9OaC7cdmynADU3RkAwdCaXRjb2luBwAh4z5D +PJ764hElp3wsObxw0v3o+UOuDf2c9OaC7cdmynADU3RkAwdCaXRjb2luCAAh4z5D xapc8iknU6M4wWftO2OcTdnOvamPNGkXuslDdQRWb3V0Jav1uRIUF7qjOdRfexV1 p3FL4Xp1GF3QMTV61Mkt6YYLU2NyaXB0Qnl0ZXMxu67ohIl3xbAHMXIxzZL2MLYp Lc2Jf9y63sW6xOl/2QtUYXBOb2RlSGFzaF+s2W3lP07FFNmxjWeA2gqr6y0mC/03 LaPAeqRdOZ9NCkxlYWZTY3JpcHSjgkLzy9fR0KES2o3hYC9W1PhvDsTEdsXAaFlM SwRlVgRUeGlktjMJqRi/tpINbshYpCSHI0ZaaT9yQwe//x3XOnOBTskHTGVhZlZl -ct/4ADyB/kf8VCOx0sbiDw3fqma9zPN9dBPJH2XaADyICkludGVybmFsUGsMQ29t -bWl0VmVyaWZ5BwAv7s8eRNKhKbmKFDhHSzlxlSsoHKIBktUTJviyNmBeZwtNZXJr -bGVQcm9vZjCVfuYdYTRZuwUI5OGvPWohv9b7+x0xgqd55UV04FaxClByb3RvY29s -SWQ1N6lRFcjqhdxS96uB8nFlUQUmU5RCV6+JE+h71Jux0wdNZXNzYWdlU0OVD0Qz -KiP/6IDPUOfPCAahBM3gSGsT4Qz8GINDsNcIVHJlZU5vZGVVjTcH+EWGU4DuzEFV -JOikmWBR05SCQ/GU9/GRVyPp5gpNZXJrbGVOb2RlxKN7LSxSbrVJWtXZihWIvHNJ -7AFaxfUJdqdV7py7D1QLTWVya2xlQmxvY2vLhaeLEqU3TP/7I/XLv5m2ZEsplYZ9 -cReJIjVZ/HuLVwpNZXJrbGVUcmVlA1N0ZAEAIuTglum9fVyG9eHfXXcBav45xzzZ -NIVQlECJjKijeV4CVTUQAAhBbmNob3JJZAUBAAcAAEAgABFBbmNob3JNZXJrbGVC -bG9jawYDBHR4aWQCTk6E9HAWyeXSYny/w/Q2st1s1NG5sERb/17vgnZyd1ejgkLz -y9fR0KES2o3hYC9W1PhvDsTEdsXAaFlMSwRlVghtcGNQcm9vZgIIbJMpP1Zo7Nnf -nUB1CNehMyMWREFWAosurAm/5d+NQsSjey0sUm61SVrV2YoViLxzSewBWsX1CXan -Ve6cuw9UCGRiY1Byb29mAapKxGjifpS21gMqlp26VvtdZYFcCXpQBHAl7YizA5S/ -EUFuY2hvck1lcmtsZVByb29mBgMEdHhpZAJOToT0cBbJ5dJifL/D9Day3WzU0bmw -RFv/Xu+CdnJ3V6OCQvPL19HQoRLajeFgL1bU+G8OxMR2xcBoWUxLBGVWCG1wY1By -b29mAghskyk/Vmjs2d+dQHUI16EzIxZEQVYCiy6sCb/l341CL+7PHkTSoSm5ihQ4 -R0s5cZUrKByiAZLVEyb4sjZgXmcIZGJjUHJvb2YBqkrEaOJ+lLbWAyqWnbpW+11l -gVwJelAEcCXtiLMDlL8QQW5jaG9yTWVya2xlVHJlZQYDBHR4aWQCTk6E9HAWyeXS -Yny/w/Q2st1s1NG5sERb/17vgnZyd1ejgkLzy9fR0KES2o3hYC9W1PhvDsTEdsXA -aFlMSwRlVghtcGNQcm9vZgIIbJMpP1Zo7NnfnUB1CNehMyMWREFWAosurAm/5d+N -QsuFp4sSpTdM//sj9cu/mbZkSymVhn1xF4kiNVn8e4tXCGRiY1Byb29mAapKxGji -fpS21gMqlp26VvtdZYFcCXpQBHAl7YizA5S/DkJsaW5kU2VhbFR4UHRyBgQGbWV0 -aG9kAdJSMHx9cZA19zB+6Cgl7BuBK6GH3Z2YSYtKjRb6btVDBHR4aWQBseU4ORQK -OL7wbxrPvhxgpW/h4fR9eAgoeb/R+tMQId0Edm91dAJOToT0cBbJ5dJifL/D9Day -3WzU0bmwRFv/Xu+CdnJ3VyHjPkPFqlzyKSdTozjBZ+07Y5xN2c69qY80aRe6yUN1 -CGJsaW5kaW5nAAAIDUJsaW5kU2VhbFR4aWQGBAZtZXRob2QB0lIwfH1xkDX3MH7o -KCXsG4EroYfdnZhJi0qNFvpu1UMEdHhpZAJOToT0cBbJ5dJifL/D9Day3WzU0bmw -RFv/Xu+CdnJ3V6OCQvPL19HQoRLajeFgL1bU+G8OxMR2xcBoWUxLBGVWBHZvdXQC -Tk6E9HAWyeXSYny/w/Q2st1s1NG5sERb/17vgnZyd1ch4z5Dxapc8iknU6M4wWft -O2OcTdnOvamPNGkXuslDdQhibGluZGluZwAACAtDbG9zZU1ldGhvZAMCCm9wcmV0 -Rmlyc3QAC3RhcHJldEZpcnN0ARFFeHBsaWNpdFNlYWxUeFB0cgYDBm1ldGhvZAHS -UjB8fXGQNfcwfugoJewbgSuhh92dmEmLSo0W+m7VQwR0eGlkAbHlODkUCji+8G8a -z74cYKVv4eH0fXgIKHm/0frTECHdBHZvdXQCTk6E9HAWyeXSYny/w/Q2st1s1NG5 -sERb/17vgnZyd1ch4z5Dxapc8iknU6M4wWftO2OcTdnOvamPNGkXuslDdRBFeHBs -aWNpdFNlYWxUeGlkBgMGbWV0aG9kAdJSMHx9cZA19zB+6Cgl7BuBK6GH3Z2YSYtK -jRb6btVDBHR4aWQCTk6E9HAWyeXSYny/w/Q2st1s1NG5sERb/17vgnZyd1ejgkLz -y9fR0KES2o3hYC9W1PhvDsTEdsXAaFlMSwRlVgR2b3V0Ak5OhPRwFsnl0mJ8v8P0 -NrLdbNTRubBEW/9e74J2cndXIeM+Q8WqXPIpJ1OjOMFn7TtjnE3Zzr2pjzRpF7rJ -Q3UFUHJvb2YEAgAKb3ByZXRGaXJzdAAAAAELdGFwcmV0Rmlyc3QABQEBGyc5NK5H -VuHrx50i/fbG0qXZSO79Qa2pcwuGhQ73eTAKU2VjcmV0U2VhbAUBAAcAAEAgABFU -YXByZXROb2RlUGFydG5lcgQDAAhsZWZ0Tm9kZQAFAQJOToT0cBbJ5dJifL/D9Day -3WzU0bmwRFv/Xu+CdnJ3VzG7ruiEiXfFsAcxcjHNkvYwtiktzYl/3LrexbrE6X/Z -AQlyaWdodExlYWYABQECTk6E9HAWyeXSYny/w/Q2st1s1NG5sERb/17vgnZyd1df -rNlt5T9OxRTZsY1ngNoKq+stJgv9Ny2jwHqkXTmfTQILcmlnaHRCcmFuY2gABQEB -OD9iLnFT0sghkTzLdx2fPWTfdvIoVVkt+EZDlBZNbQUPVGFwcmV0UGF0aFByb29m -BgILcGFydG5lck5vZGUABAIABG5vbmUAAAABBHNvbWUABQEBAXwHXQBASxaVmBsX -w2Etxrjqrg1/cFlikhZ1WuUZkxEFbm9uY2UAAAELVGFwcmV0UHJvb2YGAglwYXRo -UHJvb2YBE8RTUmYnu0QljDtn9MzCfv785Ce3z14P/YGPL3572HwKaW50ZXJuYWxQ -awJOToT0cBbJ5dJifL/D9Day3WzU0bmwRFv/Xu+CdnJ3V9/4ADyB/kf8VCOx0sbi -Dw3fqma9zPN9dBPJH2XaADyIEVRhcHJldFJpZ2h0QnJhbmNoBgIMbGVmdE5vZGVI -YXNoAk5OhPRwFsnl0mJ8v8P0NrLdbNTRubBEW/9e74J2cndXMbuu6ISJd8WwBzFy -Mc2S9jC2KS3NiX/cut7FusTpf9kNcmlnaHROb2RlSGFzaAJOToT0cBbJ5dJifL/D -9Day3WzU0bmwRFv/Xu+CdnJ3VzG7ruiEiXfFsAcxcjHNkvYwtiktzYl/3LrexbrE -6X/ZBVR4UHRyBAIACXdpdG5lc3NUeAAAAAEEdHhpZAAFAQJOToT0cBbJ5dJifL/D -9Day3WzU0bmwRFv/Xu+CdnJ3V6OCQvPL19HQoRLajeFgL1bU+G8OxMR2xcBoWUxL -BGVW +cr18s/79ARrjodNVM67jWNIpDIaIvrGSH/1AHJAU2n5UCkludGVybmFsUGu/yha7 +wj6MQHrzikzrFji7JXWHUoEh+dLdarQgEksl1glUYXByb290UGsMQ29tbWl0VmVy +aWZ5BwAv7s8eRNKhKbmKFDhHSzlxlSsoHKIBktUTJviyNmBeZwtNZXJrbGVQcm9v +ZjCVfuYdYTRZuwUI5OGvPWohv9b7+x0xgqd55UV04FaxClByb3RvY29sSWQ1N6lR +FcjqhdxS96uB8nFlUQUmU5RCV6+JE+h71Jux0wdNZXNzYWdlU0OVD0QzKiP/6IDP +UOfPCAahBM3gSGsT4Qz8GINDsNcIVHJlZU5vZGVVjTcH+EWGU4DuzEFVJOikmWBR +05SCQ/GU9/GRVyPp5gpNZXJrbGVOb2RlxKN7LSxSbrVJWtXZihWIvHNJ7AFaxfUJ +dqdV7py7D1QLTWVya2xlQmxvY2vLhaeLEqU3TP/7I/XLv5m2ZEsplYZ9cReJIjVZ +/HuLVwpNZXJrbGVUcmVlA1N0ZAEAIuTglum9fVyG9eHfXXcBav45xzzZNIVQlECJ +jKijeV4CVTUQAAhBbmNob3JJZAUBAAcAAEAgABFBbmNob3JNZXJrbGVCbG9jawYD +BHR4aWQCTk6E9HAWyeXSYny/w/Q2st1s1NG5sERb/17vgnZyd1ejgkLzy9fR0KES +2o3hYC9W1PhvDsTEdsXAaFlMSwRlVghtcGNQcm9vZgIIbJMpP1Zo7NnfnUB1CNeh +MyMWREFWAosurAm/5d+NQsSjey0sUm61SVrV2YoViLxzSewBWsX1CXanVe6cuw9U +CGRiY1Byb29mATWZWar1vLwVVPxn9z0BFB0FY8WzlnYC1GcBvQCfMeUYEUFuY2hv +ck1lcmtsZVByb29mBgMEdHhpZAJOToT0cBbJ5dJifL/D9Day3WzU0bmwRFv/Xu+C +dnJ3V6OCQvPL19HQoRLajeFgL1bU+G8OxMR2xcBoWUxLBGVWCG1wY1Byb29mAghs +kyk/Vmjs2d+dQHUI16EzIxZEQVYCiy6sCb/l341CL+7PHkTSoSm5ihQ4R0s5cZUr +KByiAZLVEyb4sjZgXmcIZGJjUHJvb2YBNZlZqvW8vBVU/Gf3PQEUHQVjxbOWdgLU +ZwG9AJ8x5RgQQW5jaG9yTWVya2xlVHJlZQYDBHR4aWQCTk6E9HAWyeXSYny/w/Q2 +st1s1NG5sERb/17vgnZyd1ejgkLzy9fR0KES2o3hYC9W1PhvDsTEdsXAaFlMSwRl +VghtcGNQcm9vZgIIbJMpP1Zo7NnfnUB1CNehMyMWREFWAosurAm/5d+NQsuFp4sS +pTdM//sj9cu/mbZkSymVhn1xF4kiNVn8e4tXCGRiY1Byb29mATWZWar1vLwVVPxn +9z0BFB0FY8WzlnYC1GcBvQCfMeUYDkJsaW5kU2VhbFR4UHRyBgQGbWV0aG9kAdJS +MHx9cZA19zB+6Cgl7BuBK6GH3Z2YSYtKjRb6btVDBHR4aWQBseU4ORQKOL7wbxrP +vhxgpW/h4fR9eAgoeb/R+tMQId0Edm91dAJOToT0cBbJ5dJifL/D9Day3WzU0bmw +RFv/Xu+CdnJ3VyHjPkPFqlzyKSdTozjBZ+07Y5xN2c69qY80aRe6yUN1CGJsaW5k +aW5nAAAIDUJsaW5kU2VhbFR4aWQGBAZtZXRob2QB0lIwfH1xkDX3MH7oKCXsG4Er +oYfdnZhJi0qNFvpu1UMEdHhpZAJOToT0cBbJ5dJifL/D9Day3WzU0bmwRFv/Xu+C +dnJ3V6OCQvPL19HQoRLajeFgL1bU+G8OxMR2xcBoWUxLBGVWBHZvdXQCTk6E9HAW +yeXSYny/w/Q2st1s1NG5sERb/17vgnZyd1ch4z5Dxapc8iknU6M4wWftO2OcTdnO +vamPNGkXuslDdQhibGluZGluZwAACAtDbG9zZU1ldGhvZAMCCm9wcmV0Rmlyc3QA +C3RhcHJldEZpcnN0ARFFeHBsaWNpdFNlYWxUeFB0cgYDBm1ldGhvZAHSUjB8fXGQ +NfcwfugoJewbgSuhh92dmEmLSo0W+m7VQwR0eGlkAbHlODkUCji+8G8az74cYKVv +4eH0fXgIKHm/0frTECHdBHZvdXQCTk6E9HAWyeXSYny/w/Q2st1s1NG5sERb/17v +gnZyd1ch4z5Dxapc8iknU6M4wWftO2OcTdnOvamPNGkXuslDdRBFeHBsaWNpdFNl +YWxUeGlkBgMGbWV0aG9kAdJSMHx9cZA19zB+6Cgl7BuBK6GH3Z2YSYtKjRb6btVD +BHR4aWQCTk6E9HAWyeXSYny/w/Q2st1s1NG5sERb/17vgnZyd1ejgkLzy9fR0KES +2o3hYC9W1PhvDsTEdsXAaFlMSwRlVgR2b3V0Ak5OhPRwFsnl0mJ8v8P0NrLdbNTR +ubBEW/9e74J2cndXIeM+Q8WqXPIpJ1OjOMFn7TtjnE3Zzr2pjzRpF7rJQ3UFUHJv +b2YEAgAKb3ByZXRGaXJzdAAAAAELdGFwcmV0Rmlyc3QABQEBw7JLtgSdryy0A9M+ +AJxUQp4pH1QTsu22i8UWoA+Nk/wKU2VjcmV0U2VhbAUBAAcAAEAgABFUYXByZXRO +b2RlUGFydG5lcgQDAAhsZWZ0Tm9kZQAFAQJOToT0cBbJ5dJifL/D9Day3WzU0bmw +RFv/Xu+CdnJ3VzG7ruiEiXfFsAcxcjHNkvYwtiktzYl/3LrexbrE6X/ZAQlyaWdo +dExlYWYABQECTk6E9HAWyeXSYny/w/Q2st1s1NG5sERb/17vgnZyd1dfrNlt5T9O +xRTZsY1ngNoKq+stJgv9Ny2jwHqkXTmfTQILcmlnaHRCcmFuY2gABQEBOD9iLnFT +0sghkTzLdx2fPWTfdvIoVVkt+EZDlBZNbQUPVGFwcmV0UGF0aFByb29mBgILcGFy +dG5lck5vZGUABAIABG5vbmUAAAABBHNvbWUABQEBAXwHXQBASxaVmBsXw2Etxrjq +rg1/cFlikhZ1WuUZkxEFbm9uY2UAAAELVGFwcmV0UHJvb2YGAglwYXRoUHJvb2YB +E8RTUmYnu0QljDtn9MzCfv785Ce3z14P/YGPL3572HwKaW50ZXJuYWxQawJOToT0 +cBbJ5dJifL/D9Day3WzU0bmwRFv/Xu+CdnJ3V718s/79ARrjodNVM67jWNIpDIaI +vrGSH/1AHJAU2n5UEVRhcHJldFJpZ2h0QnJhbmNoBgIMbGVmdE5vZGVIYXNoAk5O +hPRwFsnl0mJ8v8P0NrLdbNTRubBEW/9e74J2cndXMbuu6ISJd8WwBzFyMc2S9jC2 +KS3NiX/cut7FusTpf9kNcmlnaHROb2RlSGFzaAJOToT0cBbJ5dJifL/D9Day3WzU +0bmwRFv/Xu+CdnJ3VzG7ruiEiXfFsAcxcjHNkvYwtiktzYl/3LrexbrE6X/ZBVR4 +UHRyBAIACXdpdG5lc3NUeAAAAAEEdHhpZAAFAQJOToT0cBbJ5dJifL/D9Day3WzU +0bmwRFv/Xu+CdnJ3V6OCQvPL19HQoRLajeFgL1bU+G8OxMR2xcBoWUxLBGVW -----END STRICT TYPE LIB----- diff --git a/stl/BPCore@0.1.0.stl b/stl/BPCore@0.1.0.stl index 87e68e2320283d9027f17593a1e2861697b6cb18..4e1471c1baa6258a1b3601ceee05c731c159321f 100644 GIT binary patch delta 293 zcmcaC{#SfL7ZV4=WC1pXiEFL~@2%PV?=Pd&BG%G805@ z)rD|*=9Q!tWbZ#Ew)>D>k3-exE}z$87Q0nT+k+Yve_pzqwM9Y5TlE@eNMb=z zetya3Rg7v(3Z^q7SAE^HM>OP5`gdDK5n0ycqnoFdFep!4%7bE+`?r)m+e=yiI{&W8mqP+3au}A#8_gAIuJ@dJ?MEIn9>MaJF4ld8U zlGLKS#GK7n7}b~*R(T!CcvLrK+cjpbX>)gl{f%KphxEb9m> zdcm@mprXxNS?!q>q}44=*13m0e0_Yb(%)~#E-k(3@$RqV+LguJZLNIYD-AY_aPDAK MAmoY7Z@2^*0d_WZT>t<8 diff --git a/stl/BPCore@0.1.0.sty b/stl/BPCore@0.1.0.sty index 7f2a7d87..b559fffe 100644 --- a/stl/BPCore@0.1.0.sty +++ b/stl/BPCore@0.1.0.sty @@ -1,5 +1,5 @@ {- - Id: urn:ubideco:stl:2YsxMW6xygK2FxFSbbBLqmzaUSytmLHHNF9DRio5zNr2#sultan-data-copy + Id: urn:ubideco:stl:5cbnbTwuKKKpRqh9WJejEKXcWahnHc3jgwBeJCNr48cL#gyro-minute-maestro Name: BPCore Version: 0.1.0 Description: Bitcoin client-side-validation library @@ -28,7 +28,8 @@ import urn:ubideco:stl:6GgF7biXPVNcus2FfQj2pQuRzau11rXApMQLfCZhojgi#money-pardon -- LeafScript := urn:ubideco:semid:7SUbonQ62tSaBTPpbZPACQo2NogXodi2mW5WEEDfBvp4#brenda-round-micro -- Txid := urn:ubideco:semid:C1GfCrG7AXu2sFhRBspd7KpJK2YgyTkVy6pty5rZynRs#cowboy-diego-betty -- LeafVer := urn:ubideco:semid:DGELfUvcU62GNQRo7HaMbKDzYQwdYRMW3b91JHd4d3WY#tunnel-lagoon-cowboy --- InternalPk := urn:ubideco:semid:G5HFVaWwWNYSzqk548JgGZ8WKy6dQ2ftVgkJvHjgRudZ#horse-major-vienna +-- InternalPk := urn:ubideco:semid:DkgLteYQvM5jASrE2R8Z2z1jmzgwrnVNGBXLPoa8gDm5#monaco-special-needle +-- TaprootPk := urn:ubideco:semid:DufbiodesBkHAgaCpqgXzZYoJa97fEMjmTBxr6JoVATF#sound-humor-adam import urn:ubideco:stl:9KALDYR8Nyjq4FdMW6kYoL7vdkWnqPqNuFnmE9qHpNjZ#justice-rocket-type as Std -- Imports: @@ -82,8 +83,8 @@ data TapretNodePartner :: leftNode Bitcoin.TapNodeHash {- urn:ubideco:semid:4M8x | rightBranch TapretRightBranch -- urn:ubideco:semid:BPYcTtbxvzWp8h7SMapT14FzLCnrnGzSShHTWGHCSD4C#clark-magic-salon data TapretPathProof :: partnerNode TapretNodePartner?, nonce U8 --- urn:ubideco:semid:7QQkknWxkJLkef2AJrPSH3q165rB8ZTAUofNwW3ia5im#helena-wizard-podium -data TapretProof :: pathProof TapretPathProof, internalPk Bitcoin.InternalPk {- urn:ubideco:semid:G5HFVaWwWNYSzqk548JgGZ8WKy6dQ2ftVgkJvHjgRudZ#horse-major-vienna -} +-- urn:ubideco:semid:CWF7gRmqznx45aDH9ubzkYaxswU2xmvo8CNdNWRtaDrW#stamp-inca-drama +data TapretProof :: pathProof TapretPathProof, internalPk Bitcoin.InternalPk {- urn:ubideco:semid:DkgLteYQvM5jASrE2R8Z2z1jmzgwrnVNGBXLPoa8gDm5#monaco-special-needle -} -- urn:ubideco:semid:4nZtVVw7QJaMDHYffkHBWhxXSkLXLcJ89qTLZH4Z3xck#basket-prelude-bridge data TapretRightBranch :: leftNodeHash Bitcoin.TapNodeHash {- urn:ubideco:semid:4M8xyvABKKKJseN6Pme5eKrAuusMNMXoY5s6ifsEcreC#crash-culture-jamaica -}, rightNodeHash Bitcoin.TapNodeHash {- urn:ubideco:semid:4M8xyvABKKKJseN6Pme5eKrAuusMNMXoY5s6ifsEcreC#crash-culture-jamaica -} -- urn:ubideco:semid:CyRtMpPJkKLX3AdhgY7ZyA7PnYAzCo7yFTeYwwGsUBhn#strange-source-father diff --git a/stl/Bitcoin@0.1.0.sta b/stl/Bitcoin@0.1.0.sta index c37e080a..66f80495 100644 --- a/stl/Bitcoin@0.1.0.sta +++ b/stl/Bitcoin@0.1.0.sta @@ -1,11 +1,11 @@ -----BEGIN STRICT TYPE LIB----- -Id: urn:ubideco:stl:A6tfQFthqmb39wR5sWvrfgf3oiAyazm8rh7ff35ruioi +Id: urn:ubideco:stl:DxmVFuGffDNS1w5tBAhWS798qXBCqDtpmVPQanLbmBRX Name: Bitcoin Dependencies: urn:ubideco:stl:9KALDYR8Nyjq4FdMW6kYoL7vdkWnqPqNuFnmE9qHpNjZ B0JpdGNvaW4Be4SAPJ764hElp3wsObxw0v3o+UOuDf2c9OaC7cdmynADU3RkAQNT -dGQBAGGGItF7rvBmAt/ndcmA4LNrbrroCQ2AdfdRO+xLk/ZNBEJvb2wrAAlCaXAz +dGQBAGGGItF7rvBmAt/ndcmA4LNrbrroCQ2AdfdRO+xLk/ZNBEJvb2wtAAlCaXAz NDBTaWcGAgNzaWcABwAAQEAADHNpZ2hhc2hfdHlwZQAEAgAEbm9uZQAAAAEEc29t ZQAFAQHbF2Q+dwkTJ+gEmSSB1dxgFSMIlVM55Yszn9RMT3JIKglCbG9ja0hhc2gF AQAHAABAIAALQmxvY2tIZWFkZXIGBgd2ZXJzaW9uAABEDXByZXZCbG9ja0hhc2gB @@ -14,50 +14,52 @@ IAAEdGltZQAABARiaXRzAAAEBW5vbmNlAAAEB0J5dGVTdHIFAQAIAABAAAAAAAAA AAD/////AAAAAAVDaGFpbgMEB2JpdGNvaW4AB3JlZ3Rlc3SACHRlc3RuZXQzgwZz aWduZXSEDENvbnRyb2xCbG9jawYEC2xlYWZWZXJzaW9uAbYzCakYv7aSDW7IWKQk hyNGWmk/ckMHv/8d1zpzgU7JD291dHB1dEtleVBhcml0eQGPyiYjolVEI5WPpnqn -bUNqFd5k6xCz9PmZFCIvlRFmiAtpbnRlcm5hbEtleQHf+AA8gf5H/FQjsdLG4g8N -36pmvczzfXQTyR9l2gA8iAxtZXJrbGVCcmFuY2gB7gMeZlFQaLZ0GVxRd/QKg8QA -UlvBpDAUGABpT73wc6QNRnV0dXJlTGVhZlZlcgUBAAABCkludGVybmFsUGsFAQAH -AABAIAAKTGVhZlNjcmlwdAYCB3ZlcnNpb24BtjMJqRi/tpINbshYpCSHI0ZaaT9y -Qwe//x3XOnOBTskGc2NyaXB0ASWr9bkSFBe6oznUX3sVdadxS+F6dRhd0DE1etTJ -LemGB0xlYWZWZXIFAQAAAQlMZWdhY3lTaWcGAgNzaWcACAAAQAAAAAAAAAAA/wAA -AAAAAAAMc2lnaGFzaF90eXBlAdsXZD53CRMn6ASZJIHV3GAVIwiVUznlizOf1ExP -ckgqCExvY2tUaW1lBQEAAAQGT3BDb2RlAxIKcHVzaEJ5dGVzMAALcHVzaEJ5dGVz -MzIgCXB1c2hEYXRhMUwJcHVzaERhdGEyTQlwdXNoRGF0YTROCHJlc2VydmVkUAhw -dXNoTnVtMVEGcmV0dXJuagNkdXB2BWVxdWFshwtlcXVhbFZlcmlmeYgJcmlwZW1k -MTYwpgRzaGExpwZzaGEyNTaoB2hhc2gxNjCpB2hhc2gyNTaqCGNoZWNrU2lnrA5j -aGVja1NpZ1Zlcmlmea0IT3V0cG9pbnQGAgR0eGlkAaOCQvPL19HQoRLajeFgL1bU -+G8OxMR2xcBoWUxLBGVWBHZvdXQBIeM+Q8WqXPIpJ1OjOMFn7TtjnE3Zzr2pjzRp -F7rJQ3UGUGFyaXR5AwIEZXZlbgADb2RkAQxSZWRlZW1TY3JpcHQFAQElq/W5EhQX -uqM51F97FXWncUvhenUYXdAxNXrUyS3phgRTYXRzBQEAAAgLU2NyaXB0Qnl0ZXMF -AQAIAABAAAAAAAAAAAD/////AAAAAAxTY3JpcHRQdWJrZXkFAQElq/W5EhQXuqM5 -1F97FXWncUvhenUYXdAxNXrUyS3phgVTZXFObwUBAAAECVNpZ1NjcmlwdAUBASWr -9bkSFBe6oznUX3sVdadxS+F6dRhd0DE1etTJLemGC1NpZ2hhc2hGbGFnAwMDYWxs -AQRub25lAgZzaW5nbGUDC1NpZ2hhc2hUeXBlBgIEZmxhZwH/Pmp/yMeFQ078jud0 -swCxm+yYcaKaHvEAi+8Q6yjVNAxhbnlvbmVDYW5QYXkCe4SAPJ764hElp3wsObxw -0v3o+UOuDf2c9OaC7cdmynBhhiLRe67wZgLf53XJgOCza2666AkNgHX3UTvsS5P2 -TQ1UYXBCcmFuY2hIYXNoBQEABwAAQCAAB1RhcENvZGUDBgtwdXNoQnl0ZXMzMiAJ -cHVzaERhdGExTAlwdXNoRGF0YTJNCXB1c2hEYXRhNE4IcmVzZXJ2ZWRQBnJldHVy -bmoLVGFwTGVhZkhhc2gFAQAHAABAIAANVGFwTWVya2xlUGF0aAUBAAgBr+vFndj9 -UEcdmF3CQSguq6mMSIryZGPBdn5RBiLCktgAAAAAAAAAAIAAAAAAAAAAC1RhcE5v -ZGVIYXNoBQEABwAAQCAACVRhcFNjcmlwdAUBASWr9bkSFBe6oznUX3sVdadxS+F6 -dRhd0DE1etTJLemGAlR4BgQHdmVyc2lvbgGofMZ5ZGflV9dE5cliOuAMy5XZGg0v -A990wHUST77HngZpbnB1dHMACAEZRy0X2GIHpw8hMalYoWilbirWUz+cZkwZd9pc -+f5ihgAAAAAAAAAA/////wAAAAAHb3V0cHV0cwAIAZA7ZHB5hI8bJlMq5M7GpolE -oFNYuPCByyazu/gtnjvzAAAAAAAAAAD/////AAAAAAhsb2NrVGltZQE12h0VOSBu -u93cpMM9hzHq8pun2nTfPciCIBxOFrW5HARUeEluBgQKcHJldk91dHB1dAHoakDN -XCX5veKE/2mlETKnQSshVb0OVhLBv+OElWDFBglzaWdTY3JpcHQBOHUEsUt8DkZt -R54XR30kdCR/+ANk7D1Lqvc6IPdBdGsIc2VxdWVuY2UBARlthSnI9tpETRVOjZyM -vZ4PjYkCWjuwkSHGPVKwHocHd2l0bmVzcwFzd0NwNpMgSc0olQiqcXzjgp2yRS5V -6E7U/C48zS4AnQVUeE91dAYCBXZhbHVlAZf11wZCriozkiU7qE4dzsST478+03Gx -h3OGNU7MiIJrDHNjcmlwdFB1YmtleQG+/B78ZqUZ/WRSajoTh0Dn8RAtC77/OsFG -TvP3QHZ0XAVUeFZlcgUBAABEBFR4aWQFAQAHAABAIAAGVkJ5dGVzBQEAAAQGVmFy -SW50BQEAAAgEVm91dAUBAAAEC1dlaWdodFVuaXRzBQEAAAQHV2l0bmVzcwUBAAgA -CAAAQAAAAAAAAAAA/////wAAAAAAAAAAAAAAAP////8AAAAADldpdG5lc3NQcm9n -cmFtBgIHdmVyc2lvbgHR7Np2Z+RC7U0SaaZnAzbl/vQ3r17OK2muugxGVsT6rQdw -cm9ncmFtAAgAAEACAAAAAAAAACgAAAAAAAAADVdpdG5lc3NTY3JpcHQFAQElq/W5 -EhQXuqM51F97FXWncUvhenUYXdAxNXrUyS3phgpXaXRuZXNzVmVyAxECdjAAAnYx -UQJ2MlICdjNTAnY0VAJ2NVUCdjZWAnY3VwJ2OFgCdjlZA3YxMFoDdjExWwN2MTJc -A3YxM10DdjE0XgN2MTVfA3YxNmAFV3R4aWQFAQAHAABAIAA= +bUNqFd5k6xCz9PmZFCIvlRFmiAppbnRlcm5hbFBrAb18s/79ARrjodNVM67jWNIp +DIaIvrGSH/1AHJAU2n5UDG1lcmtsZUJyYW5jaAHuAx5mUVBotnQZXFF39AqDxABS +W8GkMBQYAGlPvfBzpA1GdXR1cmVMZWFmVmVyBQEAAAEKSW50ZXJuYWxQawUBAb/K +FrvCPoxAevOKTOsWOLsldYdSgSH50t1qtCASSyXWCkxlYWZTY3JpcHQGAgd2ZXJz +aW9uAbYzCakYv7aSDW7IWKQkhyNGWmk/ckMHv/8d1zpzgU7JBnNjcmlwdAElq/W5 +EhQXuqM51F97FXWncUvhenUYXdAxNXrUyS3phgdMZWFmVmVyBQEAAAEJTGVnYWN5 +U2lnBgIDc2lnAAgAAEAAAAAAAAAAAP8AAAAAAAAADHNpZ2hhc2hfdHlwZQHbF2Q+ +dwkTJ+gEmSSB1dxgFSMIlVM55Yszn9RMT3JIKghMb2NrVGltZQUBAAAEBk9wQ29k +ZQMSCnB1c2hCeXRlczAAC3B1c2hCeXRlczMyIAlwdXNoRGF0YTFMCXB1c2hEYXRh +Mk0JcHVzaERhdGE0TghyZXNlcnZlZFAIcHVzaE51bTFRBnJldHVybmoDZHVwdgVl +cXVhbIcLZXF1YWxWZXJpZnmICXJpcGVtZDE2MKYEc2hhMacGc2hhMjU2qAdoYXNo +MTYwqQdoYXNoMjU2qghjaGVja1NpZ6wOY2hlY2tTaWdWZXJpZnmtCE91dHBvaW50 +BgIEdHhpZAGjgkLzy9fR0KES2o3hYC9W1PhvDsTEdsXAaFlMSwRlVgR2b3V0ASHj +PkPFqlzyKSdTozjBZ+07Y5xN2c69qY80aRe6yUN1CE91dHB1dFBrBQEBv8oWu8I+ +jEB684pM6xY4uyV1h1KBIfnS3Wq0IBJLJdYGUGFyaXR5AwIEZXZlbgADb2RkAQxS +ZWRlZW1TY3JpcHQFAQElq/W5EhQXuqM51F97FXWncUvhenUYXdAxNXrUyS3phgRT +YXRzBQEAAAgLU2NyaXB0Qnl0ZXMFAQAIAABAAAAAAAAAAAD/////AAAAAAxTY3Jp +cHRQdWJrZXkFAQElq/W5EhQXuqM51F97FXWncUvhenUYXdAxNXrUyS3phgVTZXFO +bwUBAAAECVNpZ1NjcmlwdAUBASWr9bkSFBe6oznUX3sVdadxS+F6dRhd0DE1etTJ +LemGC1NpZ2hhc2hGbGFnAwMDYWxsAQRub25lAgZzaW5nbGUDC1NpZ2hhc2hUeXBl +BgIEZmxhZwH/Pmp/yMeFQ078jud0swCxm+yYcaKaHvEAi+8Q6yjVNAxhbnlvbmVD +YW5QYXkCe4SAPJ764hElp3wsObxw0v3o+UOuDf2c9OaC7cdmynBhhiLRe67wZgLf +53XJgOCza2666AkNgHX3UTvsS5P2TQ1UYXBCcmFuY2hIYXNoBQEABwAAQCAAB1Rh +cENvZGUDBgtwdXNoQnl0ZXMzMiAJcHVzaERhdGExTAlwdXNoRGF0YTJNCXB1c2hE +YXRhNE4IcmVzZXJ2ZWRQBnJldHVybmoLVGFwTGVhZkhhc2gFAQAHAABAIAANVGFw +TWVya2xlUGF0aAUBAAgBr+vFndj9UEcdmF3CQSguq6mMSIryZGPBdn5RBiLCktgA +AAAAAAAAAIAAAAAAAAAAC1RhcE5vZGVIYXNoBQEABwAAQCAACVRhcFNjcmlwdAUB +ASWr9bkSFBe6oznUX3sVdadxS+F6dRhd0DE1etTJLemGCVRhcHJvb3RQawUBAAcA +AEAgAAJUeAYEB3ZlcnNpb24BqHzGeWRn5VfXROXJYjrgDMuV2RoNLwPfdMB1Ek++ +x54GaW5wdXRzAAgBGUctF9hiB6cPITGpWKFopW4q1lM/nGZMGXfaXPn+YoYAAAAA +AAAAAP////8AAAAAB291dHB1dHMACAGQO2RweYSPGyZTKuTOxqaJRKBTWLjwgcsm +s7v4LZ478wAAAAAAAAAA/////wAAAAAIbG9ja1RpbWUBNdodFTkgbrvd3KTDPYcx +6vKbp9p03z3IgiAcTha1uRwEVHhJbgYECnByZXZPdXRwdXQB6GpAzVwl+b3ihP9p +pREyp0ErIVW9DlYSwb/jhJVgxQYJc2lnU2NyaXB0ATh1BLFLfA5GbUeeF0d9JHQk +f/gDZOw9S6r3OiD3QXRrCHNlcXVlbmNlAQEZbYUpyPbaRE0VTo2cjL2eD42JAlo7 +sJEhxj1SsB6HB3dpdG5lc3MBc3dDcDaTIEnNKJUIqnF844KdskUuVehO1PwuPM0u +AJ0FVHhPdXQGAgV2YWx1ZQGX9dcGQq4qM5IlO6hOHc7Ek+O/PtNxsYdzhjVOzIiC +awxzY3JpcHRQdWJrZXkBvvwe/GalGf1kUmo6E4dA5/EQLQu+/zrBRk7z90B2dFwF +VHhWZXIFAQAARARUeGlkBQEABwAAQCAABlZCeXRlcwUBAAAEBlZhckludAUBAAAI +BFZvdXQFAQAABAtXZWlnaHRVbml0cwUBAAAEB1dpdG5lc3MFAQAIAAgAAEAAAAAA +AAAAAP////8AAAAAAAAAAAAAAAD/////AAAAAA5XaXRuZXNzUHJvZ3JhbQYCB3Zl +cnNpb24B0ezadmfkQu1NEmmmZwM25f70N69ezitprroMRlbE+q0HcHJvZ3JhbQAI +AABAAgAAAAAAAAAoAAAAAAAAAA1XaXRuZXNzU2NyaXB0BQEBJav1uRIUF7qjOdRf +exV1p3FL4Xp1GF3QMTV61Mkt6YYKV2l0bmVzc1ZlcgMRAnYwAAJ2MVECdjJSAnYz +UwJ2NFQCdjVVAnY2VgJ2N1cCdjhYAnY5WQN2MTBaA3YxMVsDdjEyXAN2MTNdA3Yx +NF4DdjE1XwN2MTZgBVd0eGlkBQEABwAAQCAA -----END STRICT TYPE LIB----- diff --git a/stl/Bitcoin@0.1.0.stl b/stl/Bitcoin@0.1.0.stl index 75bdc339309f5d806661fd0dcee73eb22fd7dd8e..6013a675798bc5f379386ab62bec266a5fe36b3f 100644 GIT binary patch delta 175 zcmbO%@>*mduulT`^zZxc;V$x<8_ZCE@|?#b?n`#nEVtO_n#8meaNoIq3Uy&&ucM@-KwSSL5+$(FWt@Bq9Ek0dTnzl w(*s5w4*$}Ug3^+JY*t3XIzm~>nS?n*5(|p*^TApe*clic6c{$2VRL5&0N4^n@&Et; delta 85 zcmV-b0IL7%6q6K?Sph4tTA2YY3u$h2WpZv|Y)fT%0pIulJc0g4{8S^c(#GNs4d1F} rz0C7{bQ8%RW!eBdh?5@zP6q%7002NB0JDw)-~qFm1a|_nBnL+W-rOLQ diff --git a/stl/Bitcoin@0.1.0.sty b/stl/Bitcoin@0.1.0.sty index 113c8d71..daf15fa5 100644 --- a/stl/Bitcoin@0.1.0.sty +++ b/stl/Bitcoin@0.1.0.sty @@ -1,5 +1,5 @@ {- - Id: urn:ubideco:stl:A6tfQFthqmb39wR5sWvrfgf3oiAyazm8rh7ff35ruioi#russian-emerald-extra + Id: urn:ubideco:stl:DxmVFuGffDNS1w5tBAhWS798qXBCqDtpmVPQanLbmBRX#vendor-inside-forum Name: Bitcoin Version: 0.1.0 Description: Consensus library for bitcoin protocol @@ -32,15 +32,15 @@ data ByteStr :: [Byte ^ ..0xffffffff] -- urn:ubideco:semid:6aRP3odHaTGySvSWHjreC8HsbX5ss9LxkQqwcjaoxhpv#aspirin-brown-alpine data Chain :: bitcoin:0 | regtest:128 | testnet3:131 | signet:132 --- urn:ubideco:semid:C7rC7icVsoUF43k8QpzxWSx6BAbT8uyY2PWGjsQuf2kd#mega-optic-type +-- urn:ubideco:semid:BPzqzv3DN65MTwzbTXJbHFyiKeYvmX1VExcqvk5FUb5c#nuclear-coral-gilbert data ControlBlock :: leafVersion LeafVer , outputKeyParity Parity - , internalKey InternalPk + , internalPk InternalPk , merkleBranch TapMerklePath -- urn:ubideco:semid:CvDS9EgqtBkWLvADynNeR7VGwVAy14EXViKnLaBkqtac#student-formula-circus data FutureLeafVer :: U8 --- urn:ubideco:semid:G5HFVaWwWNYSzqk548JgGZ8WKy6dQ2ftVgkJvHjgRudZ#horse-major-vienna -data InternalPk :: [Byte ^ 32] +-- urn:ubideco:semid:FKSMf7xnPBKRaY67CP9nNbVMV8ZscunJeLmqgzLk2h7N#pinball-culture-salt +data InternalPk :: TaprootPk -- urn:ubideco:semid:Birr99aCTGqzwnuBou79KNhyLLBTNQvoTAkTbMu7C4y5#anvil-arctic-cloud data LeafScript :: version LeafVer, script ScriptBytes -- urn:ubideco:semid:DGELfUvcU62GNQRo7HaMbKDzYQwdYRMW3b91JHd4d3WY#tunnel-lagoon-cowboy @@ -58,6 +58,8 @@ data OpCode :: pushBytes0:0 | pushBytes32:32 | pushData1:76 | pushData -- urn:ubideco:semid:FWt2MSo8A4nsYgYbuBqMRNLiKgtzvLBgUn774iKzTcuf#pocket-pegasus-frank data Outpoint :: txid Txid, vout Vout +-- urn:ubideco:semid:8xqfr5BJ4FJ9Sv7wYEhz9a5gen2wyYpEAUqbBDngjuth#video-flex-harbor +data OutputPk :: TaprootPk -- urn:ubideco:semid:AgJ5n58hrH761B4MV7giZ1FhMipaDrUmnFYCLno74HDy#method-editor-echo data Parity :: even:0 | odd:1 @@ -92,6 +94,8 @@ data TapMerklePath :: [TapBranchHash ^ ..0x80] data TapNodeHash :: [Byte ^ 32] -- urn:ubideco:semid:71AxyLFsoRG6hJ1c11gxad65nEbWfzkQBjWCPPrgCyjX#telecom-quest-helium data TapScript :: ScriptBytes +-- urn:ubideco:semid:DufbiodesBkHAgaCpqgXzZYoJa97fEMjmTBxr6JoVATF#sound-humor-adam +data TaprootPk :: [Byte ^ 32] -- urn:ubideco:semid:DynChojW1sfr8VjSoZbmReHhZoU8u9KCiuwijgEGdToe#milk-gloria-prize data Tx :: version TxVer , inputs [TxIn ^ ..0xffffffff] From 2798bf75661bc995bc18001f2d93996fc2836d62 Mon Sep 17 00:00:00 2001 From: Dr Maxim Orlovsky Date: Fri, 6 Oct 2023 18:18:42 +0200 Subject: [PATCH 29/31] primitives: fix consensus encoding of control block data --- primitives/src/coding.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/primitives/src/coding.rs b/primitives/src/coding.rs index 0f358b3a..e77f2f59 100644 --- a/primitives/src/coding.rs +++ b/primitives/src/coding.rs @@ -490,7 +490,7 @@ impl ConsensusDecode for InternalPk { impl ConsensusEncode for ControlBlock { fn consensus_encode(&self, writer: &mut impl Write) -> Result { - let mut counter = 0; + let mut counter = 1; let first_byte = self.leaf_version.to_consensus_u8() & self.output_key_parity.to_consensus_u8(); From 49b7d801320b8069bdb086222b5125047dbdeb02 Mon Sep 17 00:00:00 2001 From: Dr Maxim Orlovsky Date: Sat, 7 Oct 2023 08:58:55 +0200 Subject: [PATCH 30/31] stl: reverse previous changes --- primitives/src/stl.rs | 2 +- primitives/src/taproot.rs | 94 +++++++++++++++++++++++------- src/stl.rs | 2 +- stl/BPCore@0.1.0.sta | 116 +++++++++++++++++++------------------- stl/BPCore@0.1.0.stl | Bin 3069 -> 3027 bytes stl/BPCore@0.1.0.sty | 9 ++- stl/Bitcoin@0.1.0.sta | 95 +++++++++++++++---------------- stl/Bitcoin@0.1.0.stl | Bin 2667 -> 2596 bytes stl/Bitcoin@0.1.0.sty | 12 ++-- 9 files changed, 190 insertions(+), 140 deletions(-) diff --git a/primitives/src/stl.rs b/primitives/src/stl.rs index b0f0db84..2fcf5d41 100644 --- a/primitives/src/stl.rs +++ b/primitives/src/stl.rs @@ -35,7 +35,7 @@ pub const LIB_ID_BITCOIN: &str = pub const LIB_ID_BP_TX: &str = "urn:ubideco:stl:6GgF7biXPVNcus2FfQj2pQuRzau11rXApMQLfCZhojgi#money-pardon-parody"; pub const LIB_ID_BP_CONSENSUS: &str = - "urn:ubideco:stl:DxmVFuGffDNS1w5tBAhWS798qXBCqDtpmVPQanLbmBRX#vendor-inside-forum"; + "urn:ubideco:stl:D42LxJBQokrGJzvoSV3E1HoriGgLzPcxuL61JymwjEqV#arena-complex-husband"; #[deprecated(since = "0.10.8", note = "use _bp_tx_stl instead")] fn _bitcoin_stl() -> Result { _bp_tx_stl() } diff --git a/primitives/src/taproot.rs b/primitives/src/taproot.rs index 14b09217..0fb3373a 100644 --- a/primitives/src/taproot.rs +++ b/primitives/src/taproot.rs @@ -57,13 +57,25 @@ const MIDSTATE_TAPSIGHASH: [u8; 10] = *b"TapSighash"; #[derive(Copy, Clone, Eq, PartialEq, Debug, Display, Error)] #[display("invalid public key")] -pub struct InvalidPubkey; +pub struct InvalidPubkey(pub Bytes32); + +impl From for DecodeError { + fn from(e: InvalidPubkey) -> Self { + DecodeError::DataIntegrityError(format!("invalid x-only public key value '{:x}'", e.0)) + } +} + +macro_rules! dumb_key { + () => { + Self(XOnlyPublicKey::from_slice(&[1u8; 32]).unwrap()) + }; +} #[derive(Wrapper, WrapperMut, Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Debug, From)] #[wrapper(Deref, LowerHex, Display, FromStr)] #[wrapper_mut(DerefMut)] #[derive(StrictType, StrictDumb)] -#[strict_type(lib = LIB_NAME_BITCOIN, dumb = { Self(XOnlyPublicKey::from_slice(&[1u8; 32]).unwrap()) })] +#[strict_type(lib = LIB_NAME_BITCOIN, dumb = dumb_key!())] #[cfg_attr( feature = "serde", derive(Serialize, Deserialize), @@ -75,7 +87,7 @@ impl TaprootPk { pub fn from_byte_array(data: [u8; 32]) -> Result { XOnlyPublicKey::from_slice(data.as_ref()) .map(Self) - .map_err(|_| InvalidPubkey) + .map_err(|_| InvalidPubkey(data.into())) } pub fn to_byte_array(&self) -> [u8; 32] { self.0.serialize() } @@ -102,11 +114,7 @@ impl StrictDecode for TaprootPk { let bytes: Bytes32 = r.read_field()?; XOnlyPublicKey::from_slice(bytes.as_slice()) .map(Self) - .map_err(|_| { - DecodeError::DataIntegrityError(format!( - "invalid x-only public key value '{bytes:x}'" - )) - }) + .map_err(|_| InvalidPubkey(bytes).into()) }) } } @@ -114,26 +122,31 @@ impl StrictDecode for TaprootPk { #[derive(Wrapper, WrapperMut, Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Debug, From)] #[wrapper(Deref, LowerHex, Display, FromStr)] #[wrapper_mut(DerefMut)] -#[derive(StrictType, StrictEncode, StrictDecode, StrictDumb)] -#[strict_type(lib = LIB_NAME_BITCOIN, dumb = Self(strict_dumb!()))] +#[derive(StrictType, StrictDumb)] +#[strict_type(lib = LIB_NAME_BITCOIN, dumb = dumb_key!())] #[cfg_attr( feature = "serde", derive(Serialize, Deserialize), serde(crate = "serde_crate", transparent) )] -pub struct InternalPk(TaprootPk); +pub struct InternalPk(XOnlyPublicKey); impl InternalPk { + #[inline] + pub fn from_unchecked(pk: TaprootPk) -> Self { Self(pk.0) } + pub fn from_byte_array(data: [u8; 32]) -> Result { - TaprootPk::from_byte_array(data).map(Self) + XOnlyPublicKey::from_slice(&data) + .map(Self) + .map_err(|_| InvalidPubkey(data.into())) } - pub fn to_byte_array(&self) -> [u8; 32] { self.0.to_byte_array() } + pub fn to_byte_array(&self) -> [u8; 32] { self.0.serialize() } #[deprecated(since = "0.10.9", note = "use to_output_pk")] pub fn to_output_key(&self, merkle_root: Option) -> XOnlyPublicKey { let (pk, _) = self.to_output_pk(merkle_root); - pk.0.0 + pk.0 } pub fn to_output_pk(&self, merkle_root: Option) -> (OutputPk, Parity) { @@ -155,7 +168,7 @@ impl InternalPk { tweaked_parity, tweak )); - (OutputPk(TaprootPk(output_key)), tweaked_parity.into()) + (OutputPk(output_key), tweaked_parity.into()) } } @@ -163,30 +176,71 @@ impl From for [u8; 32] { fn from(pk: InternalPk) -> [u8; 32] { pk.to_byte_array() } } +impl StrictEncode for InternalPk { + fn strict_encode(&self, writer: W) -> io::Result { + let bytes = Bytes32::from(self.0.serialize()); + writer.write_newtype::(&bytes) + } +} + +impl StrictDecode for InternalPk { + fn strict_decode(reader: &mut impl TypedRead) -> Result { + reader.read_tuple(|r| { + let bytes: Bytes32 = r.read_field()?; + XOnlyPublicKey::from_slice(bytes.as_slice()) + .map(Self) + .map_err(|_| InvalidPubkey(bytes).into()) + }) + } +} + #[derive(Wrapper, WrapperMut, Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Debug, From)] #[wrapper(Deref, LowerHex, Display, FromStr)] #[wrapper_mut(DerefMut)] -#[derive(StrictType, StrictEncode, StrictDecode, StrictDumb)] -#[strict_type(lib = LIB_NAME_BITCOIN, dumb = Self(strict_dumb!()))] +#[derive(StrictType, StrictDumb)] +#[strict_type(lib = LIB_NAME_BITCOIN, dumb = dumb_key!())] #[cfg_attr( feature = "serde", derive(Serialize, Deserialize), serde(crate = "serde_crate", transparent) )] -pub struct OutputPk(TaprootPk); +pub struct OutputPk(XOnlyPublicKey); impl OutputPk { + #[inline] + pub fn from_unchecked(pk: TaprootPk) -> Self { Self(pk.0) } + pub fn from_byte_array(data: [u8; 32]) -> Result { - TaprootPk::from_byte_array(data).map(Self) + XOnlyPublicKey::from_slice(&data) + .map(Self) + .map_err(|_| InvalidPubkey(data.into())) } - pub fn to_byte_array(&self) -> [u8; 32] { self.0.to_byte_array() } + pub fn to_byte_array(&self) -> [u8; 32] { self.0.serialize() } } impl From for [u8; 32] { fn from(pk: OutputPk) -> [u8; 32] { pk.to_byte_array() } } +impl StrictEncode for OutputPk { + fn strict_encode(&self, writer: W) -> io::Result { + let bytes = Bytes32::from(self.0.serialize()); + writer.write_newtype::(&bytes) + } +} + +impl StrictDecode for OutputPk { + fn strict_decode(reader: &mut impl TypedRead) -> Result { + reader.read_tuple(|r| { + let bytes: Bytes32 = r.read_field()?; + XOnlyPublicKey::from_slice(bytes.as_slice()) + .map(Self) + .map_err(|_| InvalidPubkey(bytes).into()) + }) + } +} + pub trait IntoTapHash { fn into_tap_hash(self) -> TapNodeHash; } diff --git a/src/stl.rs b/src/stl.rs index 9745480b..005f26b9 100644 --- a/src/stl.rs +++ b/src/stl.rs @@ -30,7 +30,7 @@ use strict_types::{CompileError, LibBuilder, TypeLib}; /// Strict types id for the library providing data types from [`dbc`] and /// [`seals`] crates. pub const LIB_ID_BPCORE: &str = - "urn:ubideco:stl:5cbnbTwuKKKpRqh9WJejEKXcWahnHc3jgwBeJCNr48cL#gyro-minute-maestro"; + "urn:ubideco:stl:2YsxMW6xygK2FxFSbbBLqmzaUSytmLHHNF9DRio5zNr2#sultan-data-copy"; fn _bp_core_stl() -> Result { LibBuilder::new(libname!(LIB_NAME_BPCORE), tiny_bset! { diff --git a/stl/BPCore@0.1.0.sta b/stl/BPCore@0.1.0.sta index 4a658d91..95cb1ff1 100644 --- a/stl/BPCore@0.1.0.sta +++ b/stl/BPCore@0.1.0.sta @@ -1,5 +1,5 @@ -----BEGIN STRICT TYPE LIB----- -Id: urn:ubideco:stl:5cbnbTwuKKKpRqh9WJejEKXcWahnHc3jgwBeJCNr48cL +Id: urn:ubideco:stl:2YsxMW6xygK2FxFSbbBLqmzaUSytmLHHNF9DRio5zNr2 Name: BPCore Dependencies: urn:ubideco:stl:ZtHaBzu9ojbDahaGKEXe5v9DfSDxLERbLkEB23R6Q6V, @@ -8,68 +8,68 @@ Dependencies: BkJQQ29yZQMIbJMpP1Zo7NnfnUB1CNehMyMWREFWAosurAm/5d+NQgxDb21taXRW ZXJpZnlOToT0cBbJ5dJifL/D9Day3WzU0bmwRFv/Xu+CdnJ3VwdCaXRjb2lue4SA -PJ764hElp3wsObxw0v3o+UOuDf2c9OaC7cdmynADU3RkAwdCaXRjb2luCAAh4z5D +PJ764hElp3wsObxw0v3o+UOuDf2c9OaC7cdmynADU3RkAwdCaXRjb2luBwAh4z5D xapc8iknU6M4wWftO2OcTdnOvamPNGkXuslDdQRWb3V0Jav1uRIUF7qjOdRfexV1 p3FL4Xp1GF3QMTV61Mkt6YYLU2NyaXB0Qnl0ZXMxu67ohIl3xbAHMXIxzZL2MLYp Lc2Jf9y63sW6xOl/2QtUYXBOb2RlSGFzaF+s2W3lP07FFNmxjWeA2gqr6y0mC/03 LaPAeqRdOZ9NCkxlYWZTY3JpcHSjgkLzy9fR0KES2o3hYC9W1PhvDsTEdsXAaFlM SwRlVgRUeGlktjMJqRi/tpINbshYpCSHI0ZaaT9yQwe//x3XOnOBTskHTGVhZlZl -cr18s/79ARrjodNVM67jWNIpDIaIvrGSH/1AHJAU2n5UCkludGVybmFsUGu/yha7 -wj6MQHrzikzrFji7JXWHUoEh+dLdarQgEksl1glUYXByb290UGsMQ29tbWl0VmVy -aWZ5BwAv7s8eRNKhKbmKFDhHSzlxlSsoHKIBktUTJviyNmBeZwtNZXJrbGVQcm9v -ZjCVfuYdYTRZuwUI5OGvPWohv9b7+x0xgqd55UV04FaxClByb3RvY29sSWQ1N6lR -FcjqhdxS96uB8nFlUQUmU5RCV6+JE+h71Jux0wdNZXNzYWdlU0OVD0QzKiP/6IDP -UOfPCAahBM3gSGsT4Qz8GINDsNcIVHJlZU5vZGVVjTcH+EWGU4DuzEFVJOikmWBR -05SCQ/GU9/GRVyPp5gpNZXJrbGVOb2RlxKN7LSxSbrVJWtXZihWIvHNJ7AFaxfUJ -dqdV7py7D1QLTWVya2xlQmxvY2vLhaeLEqU3TP/7I/XLv5m2ZEsplYZ9cReJIjVZ -/HuLVwpNZXJrbGVUcmVlA1N0ZAEAIuTglum9fVyG9eHfXXcBav45xzzZNIVQlECJ -jKijeV4CVTUQAAhBbmNob3JJZAUBAAcAAEAgABFBbmNob3JNZXJrbGVCbG9jawYD -BHR4aWQCTk6E9HAWyeXSYny/w/Q2st1s1NG5sERb/17vgnZyd1ejgkLzy9fR0KES -2o3hYC9W1PhvDsTEdsXAaFlMSwRlVghtcGNQcm9vZgIIbJMpP1Zo7NnfnUB1CNeh -MyMWREFWAosurAm/5d+NQsSjey0sUm61SVrV2YoViLxzSewBWsX1CXanVe6cuw9U -CGRiY1Byb29mATWZWar1vLwVVPxn9z0BFB0FY8WzlnYC1GcBvQCfMeUYEUFuY2hv -ck1lcmtsZVByb29mBgMEdHhpZAJOToT0cBbJ5dJifL/D9Day3WzU0bmwRFv/Xu+C -dnJ3V6OCQvPL19HQoRLajeFgL1bU+G8OxMR2xcBoWUxLBGVWCG1wY1Byb29mAghs -kyk/Vmjs2d+dQHUI16EzIxZEQVYCiy6sCb/l341CL+7PHkTSoSm5ihQ4R0s5cZUr -KByiAZLVEyb4sjZgXmcIZGJjUHJvb2YBNZlZqvW8vBVU/Gf3PQEUHQVjxbOWdgLU -ZwG9AJ8x5RgQQW5jaG9yTWVya2xlVHJlZQYDBHR4aWQCTk6E9HAWyeXSYny/w/Q2 -st1s1NG5sERb/17vgnZyd1ejgkLzy9fR0KES2o3hYC9W1PhvDsTEdsXAaFlMSwRl -VghtcGNQcm9vZgIIbJMpP1Zo7NnfnUB1CNehMyMWREFWAosurAm/5d+NQsuFp4sS -pTdM//sj9cu/mbZkSymVhn1xF4kiNVn8e4tXCGRiY1Byb29mATWZWar1vLwVVPxn -9z0BFB0FY8WzlnYC1GcBvQCfMeUYDkJsaW5kU2VhbFR4UHRyBgQGbWV0aG9kAdJS -MHx9cZA19zB+6Cgl7BuBK6GH3Z2YSYtKjRb6btVDBHR4aWQBseU4ORQKOL7wbxrP -vhxgpW/h4fR9eAgoeb/R+tMQId0Edm91dAJOToT0cBbJ5dJifL/D9Day3WzU0bmw -RFv/Xu+CdnJ3VyHjPkPFqlzyKSdTozjBZ+07Y5xN2c69qY80aRe6yUN1CGJsaW5k -aW5nAAAIDUJsaW5kU2VhbFR4aWQGBAZtZXRob2QB0lIwfH1xkDX3MH7oKCXsG4Er -oYfdnZhJi0qNFvpu1UMEdHhpZAJOToT0cBbJ5dJifL/D9Day3WzU0bmwRFv/Xu+C -dnJ3V6OCQvPL19HQoRLajeFgL1bU+G8OxMR2xcBoWUxLBGVWBHZvdXQCTk6E9HAW -yeXSYny/w/Q2st1s1NG5sERb/17vgnZyd1ch4z5Dxapc8iknU6M4wWftO2OcTdnO -vamPNGkXuslDdQhibGluZGluZwAACAtDbG9zZU1ldGhvZAMCCm9wcmV0Rmlyc3QA -C3RhcHJldEZpcnN0ARFFeHBsaWNpdFNlYWxUeFB0cgYDBm1ldGhvZAHSUjB8fXGQ -NfcwfugoJewbgSuhh92dmEmLSo0W+m7VQwR0eGlkAbHlODkUCji+8G8az74cYKVv -4eH0fXgIKHm/0frTECHdBHZvdXQCTk6E9HAWyeXSYny/w/Q2st1s1NG5sERb/17v -gnZyd1ch4z5Dxapc8iknU6M4wWftO2OcTdnOvamPNGkXuslDdRBFeHBsaWNpdFNl -YWxUeGlkBgMGbWV0aG9kAdJSMHx9cZA19zB+6Cgl7BuBK6GH3Z2YSYtKjRb6btVD -BHR4aWQCTk6E9HAWyeXSYny/w/Q2st1s1NG5sERb/17vgnZyd1ejgkLzy9fR0KES -2o3hYC9W1PhvDsTEdsXAaFlMSwRlVgR2b3V0Ak5OhPRwFsnl0mJ8v8P0NrLdbNTR -ubBEW/9e74J2cndXIeM+Q8WqXPIpJ1OjOMFn7TtjnE3Zzr2pjzRpF7rJQ3UFUHJv -b2YEAgAKb3ByZXRGaXJzdAAAAAELdGFwcmV0Rmlyc3QABQEBw7JLtgSdryy0A9M+ -AJxUQp4pH1QTsu22i8UWoA+Nk/wKU2VjcmV0U2VhbAUBAAcAAEAgABFUYXByZXRO -b2RlUGFydG5lcgQDAAhsZWZ0Tm9kZQAFAQJOToT0cBbJ5dJifL/D9Day3WzU0bmw -RFv/Xu+CdnJ3VzG7ruiEiXfFsAcxcjHNkvYwtiktzYl/3LrexbrE6X/ZAQlyaWdo -dExlYWYABQECTk6E9HAWyeXSYny/w/Q2st1s1NG5sERb/17vgnZyd1dfrNlt5T9O -xRTZsY1ngNoKq+stJgv9Ny2jwHqkXTmfTQILcmlnaHRCcmFuY2gABQEBOD9iLnFT -0sghkTzLdx2fPWTfdvIoVVkt+EZDlBZNbQUPVGFwcmV0UGF0aFByb29mBgILcGFy -dG5lck5vZGUABAIABG5vbmUAAAABBHNvbWUABQEBAXwHXQBASxaVmBsXw2Etxrjq -rg1/cFlikhZ1WuUZkxEFbm9uY2UAAAELVGFwcmV0UHJvb2YGAglwYXRoUHJvb2YB -E8RTUmYnu0QljDtn9MzCfv785Ce3z14P/YGPL3572HwKaW50ZXJuYWxQawJOToT0 -cBbJ5dJifL/D9Day3WzU0bmwRFv/Xu+CdnJ3V718s/79ARrjodNVM67jWNIpDIaI -vrGSH/1AHJAU2n5UEVRhcHJldFJpZ2h0QnJhbmNoBgIMbGVmdE5vZGVIYXNoAk5O -hPRwFsnl0mJ8v8P0NrLdbNTRubBEW/9e74J2cndXMbuu6ISJd8WwBzFyMc2S9jC2 -KS3NiX/cut7FusTpf9kNcmlnaHROb2RlSGFzaAJOToT0cBbJ5dJifL/D9Day3WzU -0bmwRFv/Xu+CdnJ3VzG7ruiEiXfFsAcxcjHNkvYwtiktzYl/3LrexbrE6X/ZBVR4 -UHRyBAIACXdpdG5lc3NUeAAAAAEEdHhpZAAFAQJOToT0cBbJ5dJifL/D9Day3WzU -0bmwRFv/Xu+CdnJ3V6OCQvPL19HQoRLajeFgL1bU+G8OxMR2xcBoWUxLBGVW +ct/4ADyB/kf8VCOx0sbiDw3fqma9zPN9dBPJH2XaADyICkludGVybmFsUGsMQ29t +bWl0VmVyaWZ5BwAv7s8eRNKhKbmKFDhHSzlxlSsoHKIBktUTJviyNmBeZwtNZXJr +bGVQcm9vZjCVfuYdYTRZuwUI5OGvPWohv9b7+x0xgqd55UV04FaxClByb3RvY29s +SWQ1N6lRFcjqhdxS96uB8nFlUQUmU5RCV6+JE+h71Jux0wdNZXNzYWdlU0OVD0Qz +KiP/6IDPUOfPCAahBM3gSGsT4Qz8GINDsNcIVHJlZU5vZGVVjTcH+EWGU4DuzEFV +JOikmWBR05SCQ/GU9/GRVyPp5gpNZXJrbGVOb2RlxKN7LSxSbrVJWtXZihWIvHNJ +7AFaxfUJdqdV7py7D1QLTWVya2xlQmxvY2vLhaeLEqU3TP/7I/XLv5m2ZEsplYZ9 +cReJIjVZ/HuLVwpNZXJrbGVUcmVlA1N0ZAEAIuTglum9fVyG9eHfXXcBav45xzzZ +NIVQlECJjKijeV4CVTUQAAhBbmNob3JJZAUBAAcAAEAgABFBbmNob3JNZXJrbGVC +bG9jawYDBHR4aWQCTk6E9HAWyeXSYny/w/Q2st1s1NG5sERb/17vgnZyd1ejgkLz +y9fR0KES2o3hYC9W1PhvDsTEdsXAaFlMSwRlVghtcGNQcm9vZgIIbJMpP1Zo7Nnf +nUB1CNehMyMWREFWAosurAm/5d+NQsSjey0sUm61SVrV2YoViLxzSewBWsX1CXan +Ve6cuw9UCGRiY1Byb29mAapKxGjifpS21gMqlp26VvtdZYFcCXpQBHAl7YizA5S/ +EUFuY2hvck1lcmtsZVByb29mBgMEdHhpZAJOToT0cBbJ5dJifL/D9Day3WzU0bmw +RFv/Xu+CdnJ3V6OCQvPL19HQoRLajeFgL1bU+G8OxMR2xcBoWUxLBGVWCG1wY1By +b29mAghskyk/Vmjs2d+dQHUI16EzIxZEQVYCiy6sCb/l341CL+7PHkTSoSm5ihQ4 +R0s5cZUrKByiAZLVEyb4sjZgXmcIZGJjUHJvb2YBqkrEaOJ+lLbWAyqWnbpW+11l +gVwJelAEcCXtiLMDlL8QQW5jaG9yTWVya2xlVHJlZQYDBHR4aWQCTk6E9HAWyeXS +Yny/w/Q2st1s1NG5sERb/17vgnZyd1ejgkLzy9fR0KES2o3hYC9W1PhvDsTEdsXA +aFlMSwRlVghtcGNQcm9vZgIIbJMpP1Zo7NnfnUB1CNehMyMWREFWAosurAm/5d+N +QsuFp4sSpTdM//sj9cu/mbZkSymVhn1xF4kiNVn8e4tXCGRiY1Byb29mAapKxGji +fpS21gMqlp26VvtdZYFcCXpQBHAl7YizA5S/DkJsaW5kU2VhbFR4UHRyBgQGbWV0 +aG9kAdJSMHx9cZA19zB+6Cgl7BuBK6GH3Z2YSYtKjRb6btVDBHR4aWQBseU4ORQK +OL7wbxrPvhxgpW/h4fR9eAgoeb/R+tMQId0Edm91dAJOToT0cBbJ5dJifL/D9Day +3WzU0bmwRFv/Xu+CdnJ3VyHjPkPFqlzyKSdTozjBZ+07Y5xN2c69qY80aRe6yUN1 +CGJsaW5kaW5nAAAIDUJsaW5kU2VhbFR4aWQGBAZtZXRob2QB0lIwfH1xkDX3MH7o +KCXsG4EroYfdnZhJi0qNFvpu1UMEdHhpZAJOToT0cBbJ5dJifL/D9Day3WzU0bmw +RFv/Xu+CdnJ3V6OCQvPL19HQoRLajeFgL1bU+G8OxMR2xcBoWUxLBGVWBHZvdXQC +Tk6E9HAWyeXSYny/w/Q2st1s1NG5sERb/17vgnZyd1ch4z5Dxapc8iknU6M4wWft +O2OcTdnOvamPNGkXuslDdQhibGluZGluZwAACAtDbG9zZU1ldGhvZAMCCm9wcmV0 +Rmlyc3QAC3RhcHJldEZpcnN0ARFFeHBsaWNpdFNlYWxUeFB0cgYDBm1ldGhvZAHS +UjB8fXGQNfcwfugoJewbgSuhh92dmEmLSo0W+m7VQwR0eGlkAbHlODkUCji+8G8a +z74cYKVv4eH0fXgIKHm/0frTECHdBHZvdXQCTk6E9HAWyeXSYny/w/Q2st1s1NG5 +sERb/17vgnZyd1ch4z5Dxapc8iknU6M4wWftO2OcTdnOvamPNGkXuslDdRBFeHBs +aWNpdFNlYWxUeGlkBgMGbWV0aG9kAdJSMHx9cZA19zB+6Cgl7BuBK6GH3Z2YSYtK +jRb6btVDBHR4aWQCTk6E9HAWyeXSYny/w/Q2st1s1NG5sERb/17vgnZyd1ejgkLz +y9fR0KES2o3hYC9W1PhvDsTEdsXAaFlMSwRlVgR2b3V0Ak5OhPRwFsnl0mJ8v8P0 +NrLdbNTRubBEW/9e74J2cndXIeM+Q8WqXPIpJ1OjOMFn7TtjnE3Zzr2pjzRpF7rJ +Q3UFUHJvb2YEAgAKb3ByZXRGaXJzdAAAAAELdGFwcmV0Rmlyc3QABQEBGyc5NK5H +VuHrx50i/fbG0qXZSO79Qa2pcwuGhQ73eTAKU2VjcmV0U2VhbAUBAAcAAEAgABFU +YXByZXROb2RlUGFydG5lcgQDAAhsZWZ0Tm9kZQAFAQJOToT0cBbJ5dJifL/D9Day +3WzU0bmwRFv/Xu+CdnJ3VzG7ruiEiXfFsAcxcjHNkvYwtiktzYl/3LrexbrE6X/Z +AQlyaWdodExlYWYABQECTk6E9HAWyeXSYny/w/Q2st1s1NG5sERb/17vgnZyd1df +rNlt5T9OxRTZsY1ngNoKq+stJgv9Ny2jwHqkXTmfTQILcmlnaHRCcmFuY2gABQEB +OD9iLnFT0sghkTzLdx2fPWTfdvIoVVkt+EZDlBZNbQUPVGFwcmV0UGF0aFByb29m +BgILcGFydG5lck5vZGUABAIABG5vbmUAAAABBHNvbWUABQEBAXwHXQBASxaVmBsX +w2Etxrjqrg1/cFlikhZ1WuUZkxEFbm9uY2UAAAELVGFwcmV0UHJvb2YGAglwYXRo +UHJvb2YBE8RTUmYnu0QljDtn9MzCfv785Ce3z14P/YGPL3572HwKaW50ZXJuYWxQ +awJOToT0cBbJ5dJifL/D9Day3WzU0bmwRFv/Xu+CdnJ3V9/4ADyB/kf8VCOx0sbi +Dw3fqma9zPN9dBPJH2XaADyIEVRhcHJldFJpZ2h0QnJhbmNoBgIMbGVmdE5vZGVI +YXNoAk5OhPRwFsnl0mJ8v8P0NrLdbNTRubBEW/9e74J2cndXMbuu6ISJd8WwBzFy +Mc2S9jC2KS3NiX/cut7FusTpf9kNcmlnaHROb2RlSGFzaAJOToT0cBbJ5dJifL/D +9Day3WzU0bmwRFv/Xu+CdnJ3VzG7ruiEiXfFsAcxcjHNkvYwtiktzYl/3LrexbrE +6X/ZBVR4UHRyBAIACXdpdG5lc3NUeAAAAAEEdHhpZAAFAQJOToT0cBbJ5dJifL/D +9Day3WzU0bmwRFv/Xu+CdnJ3V6OCQvPL19HQoRLajeFgL1bU+G8OxMR2xcBoWUxL +BGVW -----END STRICT TYPE LIB----- diff --git a/stl/BPCore@0.1.0.stl b/stl/BPCore@0.1.0.stl index 4e1471c1baa6258a1b3601ceee05c731c159321f..87e68e2320283d9027f17593a1e2861697b6cb18 100644 GIT binary patch delta 246 zcmew>ep!4%7bE+`?r)m+e=yiI{&W8mqP+3au}A#8_gAIuJ@dJ?MEIn9>MaJF4ld8U zlGLKS#GK7n7}b~*R(T!CcvLrK+cjpbX>)gl{f%KphxEb9m> zdcm@mprXxNS?!q>q}44=*13m0e0_Yb(%)~#E-k(3@$RqV+LguJZLNIYD-AY_aPDAK MAmoY7Z@2^*0d_WZT>t<8 delta 293 zcmcaC{#SfL7ZV4=WC1pXiEFL~@2%PV?=Pd&BG%G805@ z)rD|*=9Q!tWbZ#Ew)>D>k3-exE}z$87Q0nT+k+Yve_pzqwM9Y5TlE@eNMb=z zetya3Rg7v(3Z^q7SAE^HM>OP5`gdDK5n0ycqnoFdFSUy!Th7?LG6kwnX@(eCjO*n~ury fOn&SP>Y8 delta 152 zcmZ1?@>*m}G znfw$P_n#8meaNoIq3Uy&&ucM@-KwSSL5+$(FWt@Bq9Ek0dTnzF(`!Z|l%=thGYNBs bBo-9q=a&RzvobQUGcY(PFl@fd=FSWNfcZbB diff --git a/stl/Bitcoin@0.1.0.sty b/stl/Bitcoin@0.1.0.sty index daf15fa5..984f907c 100644 --- a/stl/Bitcoin@0.1.0.sty +++ b/stl/Bitcoin@0.1.0.sty @@ -1,5 +1,5 @@ {- - Id: urn:ubideco:stl:DxmVFuGffDNS1w5tBAhWS798qXBCqDtpmVPQanLbmBRX#vendor-inside-forum + Id: urn:ubideco:stl:D42LxJBQokrGJzvoSV3E1HoriGgLzPcxuL61JymwjEqV#arena-complex-husband Name: Bitcoin Version: 0.1.0 Description: Consensus library for bitcoin protocol @@ -39,8 +39,8 @@ data ControlBlock :: leafVersion LeafVer , merkleBranch TapMerklePath -- urn:ubideco:semid:CvDS9EgqtBkWLvADynNeR7VGwVAy14EXViKnLaBkqtac#student-formula-circus data FutureLeafVer :: U8 --- urn:ubideco:semid:FKSMf7xnPBKRaY67CP9nNbVMV8ZscunJeLmqgzLk2h7N#pinball-culture-salt -data InternalPk :: TaprootPk +-- urn:ubideco:semid:G5HFVaWwWNYSzqk548JgGZ8WKy6dQ2ftVgkJvHjgRudZ#horse-major-vienna +data InternalPk :: [Byte ^ 32] -- urn:ubideco:semid:Birr99aCTGqzwnuBou79KNhyLLBTNQvoTAkTbMu7C4y5#anvil-arctic-cloud data LeafScript :: version LeafVer, script ScriptBytes -- urn:ubideco:semid:DGELfUvcU62GNQRo7HaMbKDzYQwdYRMW3b91JHd4d3WY#tunnel-lagoon-cowboy @@ -58,8 +58,8 @@ data OpCode :: pushBytes0:0 | pushBytes32:32 | pushData1:76 | pushData -- urn:ubideco:semid:FWt2MSo8A4nsYgYbuBqMRNLiKgtzvLBgUn774iKzTcuf#pocket-pegasus-frank data Outpoint :: txid Txid, vout Vout --- urn:ubideco:semid:8xqfr5BJ4FJ9Sv7wYEhz9a5gen2wyYpEAUqbBDngjuth#video-flex-harbor -data OutputPk :: TaprootPk +-- urn:ubideco:semid:BA7caGkXGi42re8gf15M9awB9BwFrnHzxHpB9gMUpDQK#regular-vision-origin +data OutputPk :: [Byte ^ 32] -- urn:ubideco:semid:AgJ5n58hrH761B4MV7giZ1FhMipaDrUmnFYCLno74HDy#method-editor-echo data Parity :: even:0 | odd:1 @@ -94,8 +94,6 @@ data TapMerklePath :: [TapBranchHash ^ ..0x80] data TapNodeHash :: [Byte ^ 32] -- urn:ubideco:semid:71AxyLFsoRG6hJ1c11gxad65nEbWfzkQBjWCPPrgCyjX#telecom-quest-helium data TapScript :: ScriptBytes --- urn:ubideco:semid:DufbiodesBkHAgaCpqgXzZYoJa97fEMjmTBxr6JoVATF#sound-humor-adam -data TaprootPk :: [Byte ^ 32] -- urn:ubideco:semid:DynChojW1sfr8VjSoZbmReHhZoU8u9KCiuwijgEGdToe#milk-gloria-prize data Tx :: version TxVer , inputs [TxIn ^ ..0xffffffff] From d324a2560f8729170426033adbe25f80877e3f72 Mon Sep 17 00:00:00 2001 From: Dr Maxim Orlovsky Date: Sat, 7 Oct 2023 09:17:27 +0200 Subject: [PATCH 31/31] primitives: document difference between forms of taproot public keys --- primitives/src/taproot.rs | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/primitives/src/taproot.rs b/primitives/src/taproot.rs index 0fb3373a..26c9552f 100644 --- a/primitives/src/taproot.rs +++ b/primitives/src/taproot.rs @@ -71,6 +71,11 @@ macro_rules! dumb_key { }; } +/// Generic taproot x-only (BIP-340) public key - a wrapper around +/// [`XOnlyPublicKey`] providing APIs compatible with the rest of the library. +/// Should be used everywhere when [`InternalPk`] and [`OutputPk`] do not apply: +/// as an output of BIP32 key derivation functions, inside tapscripts/ +/// leafscripts etc. #[derive(Wrapper, WrapperMut, Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Debug, From)] #[wrapper(Deref, LowerHex, Display, FromStr)] #[wrapper_mut(DerefMut)] @@ -119,6 +124,8 @@ impl StrictDecode for TaprootPk { } } +/// Internal taproot public key, which can be present only in key fragment +/// inside taproot descriptors. #[derive(Wrapper, WrapperMut, Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Debug, From)] #[wrapper(Deref, LowerHex, Display, FromStr)] #[wrapper_mut(DerefMut)] @@ -194,6 +201,9 @@ impl StrictDecode for InternalPk { } } +/// Output taproot key - an [`InternalPk`] tweaked with merkle root of the +/// script tree - or its own hash. Used only inside addresses and raw taproot +/// descriptors. #[derive(Wrapper, WrapperMut, Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Debug, From)] #[wrapper(Deref, LowerHex, Display, FromStr)] #[wrapper_mut(DerefMut)] @@ -481,7 +491,11 @@ impl UpperHex for LeafVer { #[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, Ord, PartialOrd)] #[derive(StrictType, StrictDumb, StrictEncode, StrictDecode)] #[strict_type(lib = LIB_NAME_BITCOIN, dumb = { Self(0x51) })] -#[cfg_attr(feature = "serde", derive(Serialize, Deserialize), serde(crate = "serde_crate"))] +#[cfg_attr( + feature = "serde", + derive(Serialize, Deserialize), + serde(crate = "serde_crate", transparent) +)] pub struct FutureLeafVer(u8); impl FutureLeafVer {