use crate::hash::{HashFn, hash_chain};
use crate::pushbytes::push_bytes;
use crate::script::Script;
#[derive(Clone)]
pub enum Insertable {
Bytes(Vec<u8>),
Lookup(&'static str),
PushBytes(Box<Insertable>),
Hash(Box<Insertable>, Vec<HashFn>),
TaprootTweak(Box<Insertable>),
}
pub type Format = Vec<Insertable>;
impl Insertable {
pub fn bytes(&self, script: &Script) -> Result<Vec<u8>, String> {
match self {
Insertable::Bytes(b) => Ok(b.clone()),
Insertable::Lookup(name) => script.generate(name),
Insertable::PushBytes(inner) => {
let v = inner.bytes(script)?;
Ok(push_bytes(&v))
}
Insertable::Hash(inner, fns) => {
let v = inner.bytes(script)?;
Ok(hash_chain(&v, fns))
}
Insertable::TaprootTweak(inner) => {
let v = inner.bytes(script)?;
if v.len() != 33 {
return Err(format!(
"taproot tweak expects 33-byte compressed pubkey, got {}",
v.len()
));
}
let mut x_only = [0u8; 32];
x_only.copy_from_slice(&v[1..]);
let (tweaked, _) =
crate::crypto::secp256k1::taproot_tweak(&x_only).map_err(|e| e.to_string())?;
Ok(tweaked.to_vec())
}
}
}
}
pub(crate) fn b(bytes: &[u8]) -> Insertable {
Insertable::Bytes(bytes.to_vec())
}
pub(crate) fn lookup(name: &'static str) -> Insertable {
Insertable::Lookup(name)
}
pub(crate) fn push(inner: Insertable) -> Insertable {
Insertable::PushBytes(Box::new(inner))
}
pub(crate) fn ihash(inner: Insertable, fns: &[HashFn]) -> Insertable {
Insertable::Hash(Box::new(inner), fns.to_vec())
}
pub(crate) fn ihash160(inner: Insertable) -> Insertable {
ihash(inner, &[HashFn::Sha256, HashFn::Ripemd160])
}
pub(crate) fn ttweak(inner: Insertable) -> Insertable {
Insertable::TaprootTweak(Box::new(inner))
}