use std::str::FromStr;
use actual_rand as rand;
use bitcoin::hashes::hex::ToHex;
use bitcoin::hashes::{hash160, ripemd160, sha256, Hash};
use bitcoin::secp256k1;
use miniscript::descriptor::{SinglePub, SinglePubKey};
use miniscript::{
hash256, Descriptor, DescriptorPublicKey, Error, Miniscript, ScriptContext, TranslatePk,
Translator,
};
use rand::RngCore;
#[derive(Clone, Debug)]
pub struct PubData {
pub pks: Vec<bitcoin::PublicKey>,
pub x_only_pks: Vec<bitcoin::XOnlyPublicKey>,
pub sha256: sha256::Hash,
pub hash256: hash256::Hash,
pub ripemd160: ripemd160::Hash,
pub hash160: hash160::Hash,
}
#[derive(Debug, Clone)]
pub struct SecretData {
pub sks: Vec<bitcoin::secp256k1::SecretKey>,
pub x_only_keypairs: Vec<bitcoin::KeyPair>,
pub sha256_pre: [u8; 32],
pub hash256_pre: [u8; 32],
pub ripemd160_pre: [u8; 32],
pub hash160_pre: [u8; 32],
}
#[derive(Debug, Clone)]
pub struct TestData {
pub pubdata: PubData,
pub secretdata: SecretData,
}
fn setup_keys(
n: usize,
) -> (
Vec<bitcoin::secp256k1::SecretKey>,
Vec<miniscript::bitcoin::PublicKey>,
Vec<bitcoin::KeyPair>,
Vec<bitcoin::XOnlyPublicKey>,
) {
let secp_sign = secp256k1::Secp256k1::signing_only();
let mut sk = [0; 32];
let mut sks = vec![];
let mut pks = vec![];
for i in 1..n + 1 {
sk[0] = i as u8;
sk[1] = (i >> 8) as u8;
sk[2] = (i >> 16) as u8;
let sk = secp256k1::SecretKey::from_slice(&sk[..]).expect("secret key");
let pk = miniscript::bitcoin::PublicKey {
inner: secp256k1::PublicKey::from_secret_key(&secp_sign, &sk),
compressed: true,
};
pks.push(pk);
sks.push(sk);
}
let mut x_only_keypairs = vec![];
let mut x_only_pks = vec![];
for i in 0..n {
let keypair = bitcoin::KeyPair::from_secret_key(&secp_sign, &sks[i]);
let (xpk, _parity) = bitcoin::XOnlyPublicKey::from_keypair(&keypair);
x_only_keypairs.push(keypair);
x_only_pks.push(xpk);
}
(sks, pks, x_only_keypairs, x_only_pks)
}
impl TestData {
pub(crate) fn new_fixed_data(n: usize) -> Self {
let (sks, pks, x_only_keypairs, x_only_pks) = setup_keys(n);
let sha256_pre = [0x12 as u8; 32];
let sha256 = sha256::Hash::hash(&sha256_pre);
let hash256_pre = [0x34 as u8; 32];
let hash256 = hash256::Hash::hash(&hash256_pre);
let hash160_pre = [0x56 as u8; 32];
let hash160 = hash160::Hash::hash(&hash160_pre);
let ripemd160_pre = [0x78 as u8; 32];
let ripemd160 = ripemd160::Hash::hash(&ripemd160_pre);
let pubdata = PubData {
pks,
sha256,
hash256,
ripemd160,
hash160,
x_only_pks,
};
let secretdata = SecretData {
sks,
sha256_pre,
hash256_pre,
ripemd160_pre,
hash160_pre,
x_only_keypairs,
};
Self {
pubdata,
secretdata,
}
}
}
pub fn random_pk(mut seed: u8) -> bitcoin::PublicKey {
loop {
let mut data = [0; 33];
for byte in &mut data[..] {
*byte = seed;
seed = seed.wrapping_mul(41).wrapping_add(53);
}
data[0] = 2 + (data[0] >> 7);
if let Ok(key) = bitcoin::PublicKey::from_slice(&data[..33]) {
return key;
}
}
}
#[allow(dead_code)]
pub fn parse_insane_ms<Ctx: ScriptContext>(
ms: &str,
pubdata: &PubData,
) -> Miniscript<DescriptorPublicKey, Ctx> {
let ms = subs_hash_frag(ms, pubdata);
let ms =
Miniscript::<String, Ctx>::from_str_insane(&ms).expect("only parsing valid minsicripts");
let mut translator = StrTranslatorLoose(0, pubdata);
let ms = ms.translate_pk(&mut translator).unwrap();
ms
}
#[derive(Debug, Clone)]
struct StrDescPubKeyTranslator<'a>(usize, &'a PubData);
impl<'a> Translator<String, DescriptorPublicKey, ()> for StrDescPubKeyTranslator<'a> {
fn pk(&mut self, pk_str: &String) -> Result<DescriptorPublicKey, ()> {
let avail = !pk_str.ends_with("!");
if avail {
self.0 = self.0 + 1;
if pk_str.starts_with("K") {
Ok(DescriptorPublicKey::Single(SinglePub {
origin: None,
key: SinglePubKey::FullKey(self.1.pks[self.0]),
}))
} else if pk_str.starts_with("X") {
Ok(DescriptorPublicKey::Single(SinglePub {
origin: None,
key: SinglePubKey::XOnly(self.1.x_only_pks[self.0]),
}))
} else {
panic!("Key must start with either K or X")
}
} else {
Ok(DescriptorPublicKey::Single(SinglePub {
origin: None,
key: SinglePubKey::FullKey(random_pk(59)),
}))
}
}
fn sha256(&mut self, sha256: &String) -> Result<sha256::Hash, ()> {
let sha = sha256::Hash::from_str(sha256).unwrap();
Ok(sha)
}
fn hash256(&mut self, hash256: &String) -> Result<hash256::Hash, ()> {
let hash256 = hash256::Hash::from_str(hash256).unwrap();
Ok(hash256)
}
fn ripemd160(&mut self, ripemd160: &String) -> Result<ripemd160::Hash, ()> {
let ripemd160 = ripemd160::Hash::from_str(ripemd160).unwrap();
Ok(ripemd160)
}
fn hash160(&mut self, hash160: &String) -> Result<hash160::Hash, ()> {
let hash160 = hash160::Hash::from_str(hash160).unwrap();
Ok(hash160)
}
}
#[derive(Debug, Clone)]
struct StrTranslatorLoose<'a>(usize, &'a PubData);
impl<'a> Translator<String, DescriptorPublicKey, ()> for StrTranslatorLoose<'a> {
fn pk(&mut self, pk_str: &String) -> Result<DescriptorPublicKey, ()> {
let avail = !pk_str.ends_with("!");
if avail {
self.0 = self.0 + 1;
if pk_str.starts_with("K") {
Ok(DescriptorPublicKey::Single(SinglePub {
origin: None,
key: SinglePubKey::FullKey(self.1.pks[self.0]),
}))
} else if pk_str.starts_with("X") {
Ok(DescriptorPublicKey::Single(SinglePub {
origin: None,
key: SinglePubKey::XOnly(self.1.x_only_pks[self.0]),
}))
} else {
Ok(DescriptorPublicKey::Single(SinglePub {
origin: None,
key: SinglePubKey::FullKey(self.1.pks[self.0]),
}))
}
} else {
Ok(DescriptorPublicKey::Single(SinglePub {
origin: None,
key: SinglePubKey::FullKey(random_pk(59)),
}))
}
}
fn sha256(&mut self, sha256: &String) -> Result<sha256::Hash, ()> {
let sha = sha256::Hash::from_str(sha256).unwrap();
Ok(sha)
}
fn hash256(&mut self, hash256: &String) -> Result<hash256::Hash, ()> {
let hash256 = hash256::Hash::from_str(hash256).unwrap();
Ok(hash256)
}
fn ripemd160(&mut self, ripemd160: &String) -> Result<ripemd160::Hash, ()> {
let ripemd160 = ripemd160::Hash::from_str(ripemd160).unwrap();
Ok(ripemd160)
}
fn hash160(&mut self, hash160: &String) -> Result<hash160::Hash, ()> {
let hash160 = hash160::Hash::from_str(hash160).unwrap();
Ok(hash160)
}
}
#[allow(dead_code)]
pub fn parse_test_desc(
desc: &str,
pubdata: &PubData,
) -> Result<Descriptor<DescriptorPublicKey>, Error> {
let desc = subs_hash_frag(desc, pubdata);
let desc = Descriptor::<String>::from_str(&desc)?;
let mut translator = StrDescPubKeyTranslator(0, pubdata);
let desc: Result<_, ()> = desc.translate_pk(&mut translator);
Ok(desc.expect("Translate must succeed"))
}
fn subs_hash_frag(ms: &str, pubdata: &PubData) -> String {
let ms = ms.replace(
"sha256(H)",
&format!("sha256({})", &pubdata.sha256.to_hex()),
);
let ms = ms.replace(
"hash256(H)",
&format!("hash256({})", &pubdata.hash256.into_inner().to_hex()),
);
let ms = ms.replace(
"ripemd160(H)",
&format!("ripemd160({})", &pubdata.ripemd160.to_hex()),
);
let ms = ms.replace(
"hash160(H)",
&format!("hash160({})", &pubdata.hash160.to_hex()),
);
let mut rand_hash32 = [0u8; 32];
rand::thread_rng().fill_bytes(&mut rand_hash32);
let mut rand_hash20 = [0u8; 20];
rand::thread_rng().fill_bytes(&mut rand_hash20);
let ms = ms.replace("sha256(H!)", &format!("sha256({})", rand_hash32.to_hex()));
let ms = ms.replace("hash256(H!)", &format!("hash256({})", rand_hash32.to_hex()));
let ms = ms.replace(
"ripemd160(H!)",
&format!("ripemd160({})", rand_hash20.to_hex()),
);
let ms = ms.replace("hash160(H!)", &format!("hash160({})", rand_hash20.to_hex()));
ms
}