mod tapscript;
mod tx;
mod txout;
mod spk;
mod xonlypk;
use bc::{InternalPk, IntoTapHash, LeafScript, ScriptPubkey, TapBranchHash, TapNodeHash, Tx};
use commit_verify::mpc::Commitment;
use commit_verify::{CommitmentProtocol, ConvolveCommitProof, ConvolveVerifyError};
use strict_encoding::{StrictDeserialize, StrictSerialize};
pub use tapscript::{TapretCommitment, TAPRET_SCRIPT_COMMITMENT_PREFIX};
pub use tx::TapretError;
pub use xonlypk::TapretKeyError;
use crate::LIB_NAME_BPCORE;
pub enum TapretFirst {}
impl CommitmentProtocol for TapretFirst {}
#[derive(Clone, Eq, PartialEq, Hash, Debug, Display, Error)]
#[display(doc_comments)]
pub enum TapretPathError {
MaxDepthExceeded,
InvalidNodePartner(TapretNodePartner),
}
#[derive(Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Debug, Display)]
#[derive(StrictType, StrictDumb, StrictEncode, StrictDecode)]
#[strict_type(lib = LIB_NAME_BPCORE)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize), serde(rename_all = "camelCase"))]
#[display("{left_node_hash}:{right_node_hash}")]
pub struct TapretRightBranch {
left_node_hash: TapNodeHash,
right_node_hash: TapNodeHash,
}
impl TapretRightBranch {
pub fn with(a: TapNodeHash, b: TapNodeHash) -> TapretRightBranch {
let (left, right) = if a < b { (a, b) } else { (b, a) };
TapretRightBranch {
left_node_hash: left,
right_node_hash: right,
}
}
#[inline]
pub fn left_node_hash(self) -> TapNodeHash { self.left_node_hash }
#[inline]
pub fn right_node_hash(self) -> TapNodeHash { self.right_node_hash }
pub fn node_hash(&self) -> TapNodeHash {
TapBranchHash::with_nodes(self.left_node_hash, self.right_node_hash).into_tap_hash()
}
}
#[derive(Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Debug, Display, From)]
#[derive(StrictType, StrictDumb, StrictEncode, StrictDecode)]
#[strict_type(lib = LIB_NAME_BPCORE, tags = order, dumb = Self::RightLeaf(default!()))]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize), serde(rename_all = "camelCase"))]
#[display(inner)]
pub enum TapretNodePartner {
LeftNode(TapNodeHash),
#[from]
RightLeaf(LeafScript),
RightBranch(TapretRightBranch),
}
impl TapretNodePartner {
pub fn right_branch(a: TapNodeHash, b: TapNodeHash) -> TapretNodePartner {
TapretNodePartner::RightBranch(TapretRightBranch::with(a, b))
}
pub fn check_no_commitment(&self) -> bool {
match self {
TapretNodePartner::LeftNode(_) => true,
TapretNodePartner::RightLeaf(LeafScript { script, .. }) if script.len() < 64 => true,
TapretNodePartner::RightLeaf(LeafScript { script, .. }) => {
script[..31] != TAPRET_SCRIPT_COMMITMENT_PREFIX[..]
}
TapretNodePartner::RightBranch(right_branch) => {
right_branch.left_node_hash()[..31] != TAPRET_SCRIPT_COMMITMENT_PREFIX[..]
}
}
}
pub fn check_ordering(&self, other_node: TapNodeHash) -> bool {
match self {
TapretNodePartner::LeftNode(left_node) => *left_node <= other_node,
TapretNodePartner::RightLeaf(leaf_script) => {
let right_node = leaf_script.tap_leaf_hash().into_tap_hash();
other_node <= right_node
}
TapretNodePartner::RightBranch(right_branch) => {
let right_node = right_branch.node_hash();
other_node <= right_node
}
}
}
pub fn tap_node_hash(&self) -> TapNodeHash {
match self {
TapretNodePartner::LeftNode(hash) => *hash,
TapretNodePartner::RightLeaf(leaf_script) => {
leaf_script.tap_leaf_hash().into_tap_hash()
}
TapretNodePartner::RightBranch(right_branch) => right_branch.node_hash(),
}
}
}
#[derive(Getters, Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Debug)]
#[derive(StrictType, StrictDumb, StrictEncode, StrictDecode)]
#[strict_type(lib = LIB_NAME_BPCORE)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize), serde(rename_all = "camelCase"))]
pub struct TapretPathProof {
partner_node: Option<TapretNodePartner>,
#[getter(as_copy)]
nonce: u8,
}
impl StrictSerialize for TapretPathProof {}
impl StrictDeserialize for TapretPathProof {}
impl TapretPathProof {
#[inline]
pub fn root(nonce: u8) -> TapretPathProof {
TapretPathProof {
partner_node: None,
nonce,
}
}
pub fn with(elem: TapretNodePartner, nonce: u8) -> Result<TapretPathProof, TapretPathError> {
if !elem.check_no_commitment() {
return Err(TapretPathError::InvalidNodePartner(elem));
}
Ok(TapretPathProof {
partner_node: Some(elem),
nonce,
})
}
#[inline]
pub fn check_no_commitment(&self) -> bool {
self.partner_node.as_ref().map(TapretNodePartner::check_no_commitment).unwrap_or(true)
}
#[inline]
pub fn original_merkle_root(&self) -> Option<TapNodeHash> {
self.partner_node.as_ref().map(|partner| partner.tap_node_hash())
}
}
#[derive(Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Debug)]
#[derive(StrictType, StrictDumb, StrictEncode, StrictDecode)]
#[strict_type(lib = LIB_NAME_BPCORE)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize), serde(rename_all = "camelCase"))]
pub struct TapretProof {
pub path_proof: TapretPathProof,
pub internal_pk: InternalPk,
}
impl StrictSerialize for TapretProof {}
impl StrictDeserialize for TapretProof {}
impl TapretProof {
#[inline]
pub fn original_pubkey_script(&self) -> ScriptPubkey {
let merkle_root = self.path_proof.original_merkle_root();
ScriptPubkey::p2tr(self.internal_pk, merkle_root)
}
pub fn verify(&self, msg: &Commitment, tx: &Tx) -> Result<(), ConvolveVerifyError> {
ConvolveCommitProof::<_, Tx, _>::verify(self, msg, tx)
}
}