simplicity/
lib.rs

1// SPDX-License-Identifier: CC0-1.0
2
3#![cfg_attr(bench, feature(test))]
4#![allow(
5    // we use `bool` to represent bits and frequentely assert_eq against them
6    clippy::bool_assert_comparison,
7    // we use () as the environment for Core (FIXME we should probabl use a newtype)
8    clippy::let_unit_value,
9    // We write map(Arc::clone) to signify that a cheap Arc is being cloned
10    clippy::map_clone
11)]
12
13#[cfg(feature = "bitcoin")]
14pub extern crate bitcoin;
15#[cfg(feature = "elements")]
16pub extern crate elements;
17#[cfg(feature = "serde")]
18pub extern crate serde;
19
20/// Re-export of base64 crate
21#[cfg(feature = "base64")]
22pub use bitcoin::base64;
23/// Re-export of byteorder crate
24pub extern crate byteorder;
25/// Re-export of hashes crate
26pub extern crate hashes;
27/// Re-export of hex crate
28pub extern crate hex;
29
30#[cfg(bench)]
31extern crate test;
32
33#[macro_use]
34mod macros;
35
36mod analysis;
37mod bit_encoding;
38pub mod bit_machine;
39pub mod dag;
40pub mod human_encoding;
41pub mod jet;
42mod merkle;
43pub mod node;
44#[cfg(feature = "elements")]
45pub mod policy;
46pub mod types;
47mod value;
48
49pub use bit_encoding::decode;
50pub use bit_encoding::encode;
51pub use bit_encoding::{
52    u2, BitCollector, BitIter, CloseError as BitIterCloseError, EarlyEndOfStreamError,
53};
54pub use bit_encoding::{write_to_vec, BitWriter};
55
56#[cfg(feature = "elements")]
57pub use crate::policy::{
58    sighash, Policy, Preimage32, Satisfier, SimplicityKey, ToXOnlyPubkey, Translator,
59};
60
61pub use crate::analysis::{Cost, NodeBounds};
62pub use crate::bit_machine::BitMachine;
63pub use crate::encode::{encode_natural, encode_value, encode_witness};
64pub use crate::merkle::{
65    amr::Amr,
66    cmr::Cmr,
67    ihr::{Ihr, Imr},
68    tmr::Tmr,
69    FailEntropy, HasCmr,
70};
71pub use crate::node::{CommitNode, ConstructNode, Hiding, RedeemNode};
72pub use crate::value::{Value, ValueRef, Word};
73pub use simplicity_sys as ffi;
74use std::fmt;
75
76/// Return the version of Simplicity leaves inside a tap tree.
77#[cfg(feature = "elements")]
78pub fn leaf_version() -> elements::taproot::LeafVersion {
79    elements::taproot::LeafVersion::from_u8(0xbe).expect("constant leaf version")
80}
81
82/// Error decoding a program from the bit encoding.
83#[non_exhaustive]
84#[derive(Debug)]
85pub enum DecodeError {
86    /// Decoder error
87    Decode(decode::Error),
88    /// A disconnect node was *not* populated at redeem time
89    DisconnectRedeemTime,
90    /// Type-checking error
91    Type(types::Error),
92}
93
94impl fmt::Display for DecodeError {
95    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
96        match self {
97            Self::Decode(ref e) => fmt::Display::fmt(e, f),
98            Self::DisconnectRedeemTime => {
99                f.write_str("disconnect node had one child (redeem time); must have two")
100            }
101            Self::Type(ref e) => fmt::Display::fmt(e, f),
102        }
103    }
104}
105
106impl std::error::Error for DecodeError {
107    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
108        match self {
109            Self::Decode(ref e) => Some(e),
110            Self::DisconnectRedeemTime => None,
111            Self::Type(ref e) => Some(e),
112        }
113    }
114}
115
116/// Error parsing a program or witness (decoding it from a string encoding).
117#[non_exhaustive]
118#[derive(Debug)]
119pub enum ParseError {
120    /// Bit-encoding error.
121    Decode(DecodeError),
122    /// Base64 decoding error
123    #[cfg(feature = "base64")]
124    Base64(base64::DecodeError),
125    /// Hex decoding error
126    Hex(hex::error::HexToBytesError),
127}
128
129impl fmt::Display for ParseError {
130    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
131        match self {
132            Self::Decode(ref e) => e.fmt(f),
133            #[cfg(feature = "base64")]
134            Self::Base64(ref e) => e.fmt(f),
135            Self::Hex(ref e) => e.fmt(f),
136        }
137    }
138}
139
140impl std::error::Error for ParseError {
141    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
142        match self {
143            Self::Decode(ref e) => Some(e),
144            #[cfg(feature = "base64")]
145            Self::Base64(ref e) => Some(e),
146            Self::Hex(ref e) => Some(e),
147        }
148    }
149}
150
151/// Error finalizing a program (i.e. typechecking and pruning).
152#[non_exhaustive]
153#[derive(Debug)]
154pub enum FinalizeError {
155    /// A disconnect node was *not* populated at redeem time
156    DisconnectRedeemTime,
157    // Execution error
158    Execution(bit_machine::ExecutionError),
159    /// Type-checking error
160    Type(types::Error),
161}
162
163impl fmt::Display for FinalizeError {
164    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
165        match self {
166            Self::DisconnectRedeemTime => {
167                f.write_str("disconnect node had one child (redeem time); must have two")
168            }
169            Self::Execution(ref e) => fmt::Display::fmt(e, f),
170            Self::Type(ref e) => fmt::Display::fmt(e, f),
171        }
172    }
173}
174
175impl std::error::Error for FinalizeError {
176    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
177        match self {
178            Self::DisconnectRedeemTime => None,
179            Self::Execution(ref e) => Some(e),
180            Self::Type(ref e) => Some(e),
181        }
182    }
183}
184
185/// Error type for simplicity
186// FIXME we should collapse this error to its single variant; but need to update
187// autogenerated code to do so, so we leave it be for now.
188#[non_exhaustive]
189#[derive(Debug)]
190pub enum Error {
191    /// Tried to parse a jet but the name wasn't recognized
192    InvalidJetName(String),
193}
194
195impl fmt::Display for Error {
196    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
197        match self {
198            Error::InvalidJetName(s) => write!(f, "unknown jet `{}`", s),
199        }
200    }
201}
202
203impl std::error::Error for Error {
204    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
205        match *self {
206            Error::InvalidJetName(..) => None,
207        }
208    }
209}