Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Signing abilities: adding necessary types and logic to consensus #101

Merged
merged 20 commits into from
Jul 17, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
3b60f62
consensus: improve use of VarIntBytes type
dr-orlovsky Jun 29, 2024
fda64da
consensuus: allow min restriction on number of items in VarIntArray
dr-orlovsky Jun 29, 2024
d7e32dd
consensus: add Annex type
dr-orlovsky Jun 29, 2024
5e8d9dc
consensus: add sighash types
dr-orlovsky Jun 29, 2024
312ace3
consensus: add ScriptCode type
dr-orlovsky Jun 29, 2024
97310dd
consensus: add todo on checking for OP_CODESEPARATOR
dr-orlovsky Jun 29, 2024
302448d
consensus: implement sighash hashing
dr-orlovsky Jun 29, 2024
d0e4f58
consensus: add generic defaults to sigcache
dr-orlovsky Jun 29, 2024
7fbd015
consensus: improve sighash error types
dr-orlovsky Jun 29, 2024
12539c4
consensus: add convertors from sighash types to Secp message
dr-orlovsky Jun 29, 2024
5ef1851
consensus: fix use of secp features
dr-orlovsky Jun 29, 2024
2f08775
consensus: fix use of Sats in sighash cache
dr-orlovsky Jul 14, 2024
47e7d59
consensus: construct script code out of script references
dr-orlovsky Jul 14, 2024
4bad1a1
consensus: add nested segwit methods to redeem script
dr-orlovsky Jul 14, 2024
7da1d90
consensus: implement Display for sighash types
dr-orlovsky Jul 16, 2024
2d5818d
consensus: fix Taproot default sighash value
dr-orlovsky Jul 16, 2024
9318036
consensus: improve InternalPk::to_output_pk API
dr-orlovsky Jul 16, 2024
743e4d5
consensus: add InternalPk and OutputPk::to_xonly_pk method
dr-orlovsky Jul 16, 2024
ecc7f69
consensus: add InternalKeypair type
dr-orlovsky Jul 16, 2024
23bc44c
consensus: remove unneeded derives for InternalKeypair
dr-orlovsky Jul 17, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ single_use_seals = "0.11.0-beta.6"
bp-consensus = { version = "0.11.0-beta.6", path = "consensus" }
bp-dbc = { version = "0.11.0-beta.6", path = "./dbc" }
bp-seals = { version = "0.11.0-beta.6", path = "./seals" }
secp256k1 = { version = "0.29.0", features = ["global-context"] }
secp256k1 = { version = "0.29.0", features = ["global-context", "rand-std"] }
serde_crate = { package = "serde", version = "1", features = ["derive"] }

[package]
Expand Down
67 changes: 56 additions & 11 deletions consensus/src/coding.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,20 +25,20 @@
use amplify::{confinement, ByteArray, Bytes32, IoError, Wrapper};

use crate::{
BlockHash, BlockHeader, BlockMerkleRoot, 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,
Annex, BlockHash, BlockHeader, BlockMerkleRoot, ControlBlock, InternalPk, InvalidLeafVer,
LeafVer, LockTime, Outpoint, Parity, RedeemScript, Sats, ScriptBytes, ScriptPubkey, SeqNo,
SigScript, Sighash, TapBranchHash, TapLeafHash, TapMerklePath, TapScript, Tx, TxIn, TxOut,
TxVer, Txid, Vout, Witness, WitnessScript, LIB_NAME_BITCOIN, TAPROOT_ANNEX_PREFIX,
};

/// Bitcoin consensus allows arrays which length is encoded as VarInt to grow up
/// to 64-bit values. However, at the same time no consensus rule allows any
/// block data structure to exceed 2^32 bytes (4GB), and any change to that rule
/// will be a hardfork. So for practical reasons we are safe to restrict the
/// maximum size here with just 32 bits.
pub type VarIntArray<T> = Confined<Vec<T>, 0, U32>;
pub type VarIntArray<T, const MIN_LEN: usize = 0> = Confined<Vec<T>, MIN_LEN, U32>;

pub type VarIntBytes = Confined<Vec<u8>, 0, U32>;
pub type VarIntBytes<const MIN_LEN: usize = 0> = Confined<Vec<u8>, MIN_LEN, U32>;

/// A variable-length unsigned integer.
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Default)]
Expand Down Expand Up @@ -82,7 +82,7 @@
fn len_var_int(&self) -> VarInt;
}

impl<T> LenVarInt for VarIntArray<T> {
impl<T, const MIN_LEN: usize> LenVarInt for VarIntArray<T, MIN_LEN> {
fn len_var_int(&self) -> VarInt { VarInt::with(self.len()) }
}

Expand Down Expand Up @@ -190,6 +190,9 @@
#[display(inner)]
InvalidLeafVer(InvalidLeafVer),

/// invalid first annex byte `{0:#02x}`, which must be `0x50`.
WrongAnnexFirstByte(u8),

#[from]
#[display(inner)]
Confined(confinement::Error),
Expand Down Expand Up @@ -459,7 +462,7 @@

impl ConsensusEncode for ScriptBytes {
fn consensus_encode(&self, writer: &mut impl Write) -> Result<usize, IoError> {
self.as_var_int_array().consensus_encode(writer)
self.as_var_int_bytes().consensus_encode(writer)
}
}

Expand Down Expand Up @@ -529,6 +532,22 @@
}
}

impl ConsensusEncode for Annex {
fn consensus_encode(&self, writer: &mut impl Write) -> Result<usize, IoError> {
self.as_var_int_bytes().consensus_encode(writer)
}

Check warning on line 538 in consensus/src/coding.rs

View check run for this annotation

Codecov / codecov/patch

consensus/src/coding.rs#L536-L538

Added lines #L536 - L538 were not covered by tests
}

impl ConsensusDecode for Annex {
fn consensus_decode(reader: &mut impl Read) -> Result<Self, ConsensusDecodeError> {
let bytes = VarIntBytes::<1>::consensus_decode(reader)?;
if bytes[0] != TAPROOT_ANNEX_PREFIX {
return Err(ConsensusDataError::WrongAnnexFirstByte(bytes[0]).into());
}
Ok(Self::from(bytes))
}

Check warning on line 548 in consensus/src/coding.rs

View check run for this annotation

Codecov / codecov/patch

consensus/src/coding.rs#L542-L548

Added lines #L542 - L548 were not covered by tests
}

impl ConsensusEncode for Witness {
fn consensus_encode(&self, writer: &mut impl Write) -> Result<usize, IoError> {
self.as_var_int_array().consensus_encode(writer)
Expand Down Expand Up @@ -628,6 +647,18 @@
}
}

impl ConsensusEncode for Sighash {
fn consensus_encode(&self, writer: &mut impl Write) -> Result<usize, IoError> {
self.to_byte_array().consensus_encode(writer)
}

Check warning on line 653 in consensus/src/coding.rs

View check run for this annotation

Codecov / codecov/patch

consensus/src/coding.rs#L651-L653

Added lines #L651 - L653 were not covered by tests
}

impl ConsensusEncode for TapLeafHash {
fn consensus_encode(&self, writer: &mut impl Write) -> Result<usize, IoError> {
self.to_byte_array().consensus_encode(writer)
}

Check warning on line 659 in consensus/src/coding.rs

View check run for this annotation

Codecov / codecov/patch

consensus/src/coding.rs#L657-L659

Added lines #L657 - L659 were not covered by tests
}

impl ConsensusEncode for VarInt {
fn consensus_encode(&self, writer: &mut impl Write) -> Result<usize, IoError> {
match self.0 {
Expand Down Expand Up @@ -699,7 +730,7 @@
}
}

impl<T: ConsensusEncode> ConsensusEncode for VarIntArray<T> {
impl<T: ConsensusEncode, const MIN_LEN: usize> ConsensusEncode for VarIntArray<T, MIN_LEN> {
fn consensus_encode(&self, writer: &mut impl Write) -> Result<usize, IoError> {
let mut counter = self.len_var_int().consensus_encode(writer)?;
for item in self {
Expand All @@ -709,14 +740,14 @@
}
}

impl<T: ConsensusDecode> ConsensusDecode for VarIntArray<T> {
impl<T: ConsensusDecode, const MIN_LEN: usize> ConsensusDecode for VarIntArray<T, MIN_LEN> {
fn consensus_decode(reader: &mut impl Read) -> Result<Self, ConsensusDecodeError> {
let len = VarInt::consensus_decode(reader)?;
let mut arr = Vec::new();
for _ in 0..len.0 {
arr.push(T::consensus_decode(reader)?);
}
VarIntArray::try_from(arr).map_err(ConsensusDecodeError::from)
VarIntArray::<T, MIN_LEN>::try_from(arr).map_err(ConsensusDecodeError::from)
}
}

Expand Down Expand Up @@ -795,6 +826,20 @@
}
}

impl ConsensusEncode for Bytes32 {
fn consensus_encode(&self, writer: &mut impl Write) -> Result<usize, IoError> {
writer.write_all(&self.to_byte_array())?;
Ok(8)
}

Check warning on line 833 in consensus/src/coding.rs

View check run for this annotation

Codecov / codecov/patch

consensus/src/coding.rs#L830-L833

Added lines #L830 - L833 were not covered by tests
}

impl ConsensusEncode for [u8; 32] {
fn consensus_encode(&self, writer: &mut impl Write) -> Result<usize, IoError> {
writer.write_all(self)?;
Ok(8)
}

Check warning on line 840 in consensus/src/coding.rs

View check run for this annotation

Codecov / codecov/patch

consensus/src/coding.rs#L837-L840

Added lines #L837 - L840 were not covered by tests
}

impl ConsensusDecode for [u8; 32] {
fn consensus_decode(reader: &mut impl Read) -> Result<Self, ConsensusDecodeError> {
let mut buf = [0u8; 32];
Expand Down
12 changes: 7 additions & 5 deletions consensus/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ mod weights;
#[cfg(feature = "stl")]
pub mod stl;
mod coding;
mod sigcache;

pub use block::{BlockHash, BlockHeader, BlockMerkleRoot};
pub use coding::{
Expand All @@ -76,12 +77,13 @@ pub use opcodes::OpCode;
pub use pubkeys::{CompressedPk, InvalidPubkey, LegacyPk, PubkeyParseError, UncompressedPk};
pub use script::{RedeemScript, ScriptBytes, ScriptPubkey, SigScript};
pub use segwit::{SegwitError, Witness, WitnessProgram, WitnessScript, WitnessVer, Wtxid};
pub use sigtypes::{Bip340Sig, LegacySig, SigError, SighashFlag, SighashType};
pub use sigcache::{PrevoutMismatch, SighashCache, SighashError};
pub use sigtypes::{Bip340Sig, LegacySig, ScriptCode, SigError, Sighash, SighashFlag, SighashType};
pub use taproot::{
ControlBlock, FutureLeafVer, InternalPk, IntoTapHash, InvalidLeafVer, InvalidParityValue,
LeafScript, LeafVer, OutputPk, Parity, TapBranchHash, TapCode, TapLeafHash, TapMerklePath,
TapNodeHash, TapScript, XOnlyPk, MIDSTATE_TAPSIGHASH, TAPROOT_ANNEX_PREFIX, TAPROOT_LEAF_MASK,
TAPROOT_LEAF_TAPSCRIPT,
Annex, AnnexError, ControlBlock, FutureLeafVer, InternalKeypair, InternalPk, IntoTapHash,
InvalidLeafVer, InvalidParityValue, LeafScript, LeafVer, OutputPk, Parity, TapBranchHash,
TapCode, TapLeafHash, TapMerklePath, TapNodeHash, TapScript, TapSighash, XOnlyPk,
MIDSTATE_TAPSIGHASH, TAPROOT_ANNEX_PREFIX, TAPROOT_LEAF_MASK, TAPROOT_LEAF_TAPSCRIPT,
};
pub use timelocks::{
InvalidTimelock, LockHeight, LockTime, LockTimestamp, SeqNo, TimelockParseError,
Expand Down
27 changes: 25 additions & 2 deletions consensus/src/script.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
use amplify::confinement::Confined;

use crate::opcodes::*;
use crate::{ScriptHash, VarInt, VarIntArray, VarIntBytes, LIB_NAME_BITCOIN};
use crate::{ScriptHash, VarInt, VarIntBytes, WitnessVer, LIB_NAME_BITCOIN};

#[derive(Wrapper, WrapperMut, Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Debug, From, Default)]
#[wrapper(Deref, AsSlice, Hex)]
Expand Down Expand Up @@ -193,6 +193,29 @@
Self(ScriptBytes::from_unsafe(script_bytes))
}

pub fn p2sh_wpkh(hash: impl Into<[u8; 20]>) -> Self {
Self::with_witness_program_unchecked(WitnessVer::V0, &hash.into())
}

Check warning on line 198 in consensus/src/script.rs

View check run for this annotation

Codecov / codecov/patch

consensus/src/script.rs#L196-L198

Added lines #L196 - L198 were not covered by tests

pub fn p2sh_wsh(hash: impl Into<[u8; 32]>) -> Self {
Self::with_witness_program_unchecked(WitnessVer::V0, &hash.into())
}

Check warning on line 202 in consensus/src/script.rs

View check run for this annotation

Codecov / codecov/patch

consensus/src/script.rs#L200-L202

Added lines #L200 - L202 were not covered by tests

fn with_witness_program_unchecked(ver: WitnessVer, prog: &[u8]) -> Self {
let mut script = Self::with_capacity(ScriptBytes::len_for_slice(prog.len()) + 2);
script.push_opcode(ver.op_code());
script.push_slice(prog);
script
}

Check warning on line 209 in consensus/src/script.rs

View check run for this annotation

Codecov / codecov/patch

consensus/src/script.rs#L204-L209

Added lines #L204 - L209 were not covered by tests

pub fn is_p2sh_wpkh(&self) -> bool {
self.len() == 22 && self[0] == WitnessVer::V0.op_code() as u8 && self[1] == OP_PUSHBYTES_20
}

Check warning on line 213 in consensus/src/script.rs

View check run for this annotation

Codecov / codecov/patch

consensus/src/script.rs#L211-L213

Added lines #L211 - L213 were not covered by tests

pub fn is_p2sh_wsh(&self) -> bool {
self.len() == 34 && self[0] == WitnessVer::V0.op_code() as u8 && self[1] == OP_PUSHBYTES_32
}

Check warning on line 217 in consensus/src/script.rs

View check run for this annotation

Codecov / codecov/patch

consensus/src/script.rs#L215-L217

Added lines #L215 - L217 were not covered by tests

/// Adds a single opcode to the script.
#[inline]
pub fn push_opcode(&mut self, op_code: OpCode) { self.0.push(op_code as u8); }
Expand Down Expand Up @@ -285,7 +308,7 @@

pub fn into_vec(self) -> Vec<u8> { self.0.into_inner() }

pub(crate) fn as_var_int_array(&self) -> &VarIntArray<u8> { &self.0 }
pub(crate) fn as_var_int_bytes(&self) -> &VarIntBytes { &self.0 }
}

#[cfg(feature = "serde")]
Expand Down
Loading
Loading