From cca66d86c66834d043b02032845dda66fc9111cd Mon Sep 17 00:00:00 2001 From: Christian Lewe Date: Tue, 18 Jul 2023 14:53:43 +0200 Subject: [PATCH 1/2] simplicity: Update to latest bitcoin and miniscript bitcoin-hashes no longer provides ToHex and elements is an optional dependency, so I copied hex.rs from elements, which was itself copied from the previous version of bitcoin-hashes. Once bitcoin-hashes is fixed we can easily switch over to that. Fuzzing is updated. We have multiple versions of bitcoin_hashes. slip21 requires bitcoin_hashes < 0.12.0, which resolves to 0.11. We have to be careful to overwrite 0.12.0 but not 0.11. The jet benches are updated. FFI is updated. --- Cargo.toml | 8 +- fuzz/Cargo.toml | 4 +- fuzz/fuzz_targets/parse_compile.rs | 2 +- jets-bench/Cargo.toml | 4 +- .../benches/elements/data_structures.rs | 2 +- jets-bench/benches/elements/env.rs | 21 +- jets-bench/benches/elements/main.rs | 14 +- simplicity-sys/Cargo.toml | 2 +- simplicity-sys/src/c_jets/c_env.rs | 2 +- src/bit_machine/mod.rs | 2 +- src/hex.rs | 368 ++++++++++++++++++ src/human_encoding/serialize.rs | 2 +- src/jet/bitcoin/environment.rs | 4 +- src/jet/elements/c_env.rs | 17 +- src/jet/elements/environment.rs | 4 +- src/jet/elements/tests.rs | 11 +- src/lib.rs | 2 + src/merkle/mod.rs | 20 +- src/node/commit.rs | 2 +- src/node/redeem.rs | 2 +- src/policy/descriptor.rs | 2 +- src/policy/embed.rs | 4 +- src/policy/satisfy.rs | 46 +-- src/policy/serialize.rs | 26 +- 24 files changed, 476 insertions(+), 95 deletions(-) create mode 100644 src/hex.rs diff --git a/Cargo.toml b/Cargo.toml index a6f93ed4..15cf6549 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -16,11 +16,11 @@ name = "simplicity" path = "src/lib.rs" [dependencies] -bitcoin = { version = "0.29.2", optional = true } -bitcoin_hashes = "0.11" +bitcoin = { version = "0.30.0", optional = true } +bitcoin_hashes = "0.12" byteorder = "1.3" -elements = { version = "0.21.1", optional = true } -elements-miniscript = { git = "https://github.com/apoelstra/elements-miniscript", tag = "2023-07--rust-simplicity-patch" } +elements = { version = "0.22.0", optional = true } +elements-miniscript = "0.2.0" simplicity-sys = { version = "0.1.0", path = "./simplicity-sys" } actual-serde = { package = "serde", version = "1.0.103", features = ["derive"], optional = true } diff --git a/fuzz/Cargo.toml b/fuzz/Cargo.toml index 45416dc8..3c3f1bef 100644 --- a/fuzz/Cargo.toml +++ b/fuzz/Cargo.toml @@ -13,8 +13,8 @@ honggfuzz = { version = "0.5.55", default-features = false } simplicity = { path = ".." } [patch.crates-io.bitcoin_hashes] -git = "https://github.com/apoelstra/bitcoin_hashes" -branch = "2023-04--fuzzcfg" +git = "https://github.com/apoelstra/rust-bitcoin" +tag = "2023-07--0.30.1-with-fuzzcfg" [[bin]] name = "c_rust_merkle" diff --git a/fuzz/fuzz_targets/parse_compile.rs b/fuzz/fuzz_targets/parse_compile.rs index ce25681c..75169e3a 100644 --- a/fuzz/fuzz_targets/parse_compile.rs +++ b/fuzz/fuzz_targets/parse_compile.rs @@ -14,7 +14,7 @@ use honggfuzz::fuzz; -use simplicity::bitcoin::XOnlyPublicKey; +use simplicity::bitcoin::key::XOnlyPublicKey; use simplicity::policy::Policy; use std::str::{self, FromStr}; diff --git a/jets-bench/Cargo.toml b/jets-bench/Cargo.toml index 000296a7..e46fe599 100644 --- a/jets-bench/Cargo.toml +++ b/jets-bench/Cargo.toml @@ -11,10 +11,10 @@ serde_cbor = "0.11.1" serde_json = "1.0.70" serde = { version = "1.0.130", features = ["derive"] } chrono = "0.4.19" -simplicity = {version = "0.1.0", path = "../"} +simplicity = { path = ".." } criterion = "0.4.0" rand = "0.8" -bitcoin_hashes = "0.11.0" +bitcoin_hashes = "0.12.0" [[bench]] name = "elements" diff --git a/jets-bench/benches/elements/data_structures.rs b/jets-bench/benches/elements/data_structures.rs index ab01e516..a326c9a7 100644 --- a/jets-bench/benches/elements/data_structures.rs +++ b/jets-bench/benches/elements/data_structures.rs @@ -301,7 +301,7 @@ impl BenchSample for elements::OutPoint { rng.fill_bytes(&mut txid); let vout = rng.next_u32(); elements::OutPoint { - txid: Txid::from_inner(txid), + txid: Txid::from_byte_array(txid), vout, } } diff --git a/jets-bench/benches/elements/env.rs b/jets-bench/benches/elements/env.rs index b7321c57..57f9532b 100644 --- a/jets-bench/benches/elements/env.rs +++ b/jets-bench/benches/elements/env.rs @@ -1,7 +1,8 @@ use bitcoin::hashes as bitcoin_hashes; use bitcoin_hashes::Hash; +use elements::locktime::LockTime; use elements::taproot::ControlBlock; -use elements::{BlockHash, PackedLockTime, Transaction}; +use elements::{BlockHash, Transaction}; use simplicity::jet::elements::{ElementsEnv, ElementsUtxo}; use simplicity::Cmr; use simplicity::{bitcoin, elements}; @@ -69,7 +70,7 @@ impl EnvSampling { } let tx = Transaction { version: u32::default(), - lock_time: PackedLockTime::ZERO, + lock_time: LockTime::ZERO, input: tx_ins, output: tx_outs, }; @@ -101,7 +102,7 @@ fn env_with_spent_utxos( fn null_env() -> ElementsEnv { let tx = Transaction { version: u32::default(), - lock_time: PackedLockTime::ZERO, + lock_time: LockTime::ZERO, input: Vec::default(), output: Vec::default(), }; @@ -109,8 +110,8 @@ fn null_env() -> ElementsEnv { } pub(super) mod txout_utils { - use bitcoin::XOnlyPublicKey; - use bitcoin_hashes::hex::FromHex; + use bitcoin::key::XOnlyPublicKey; + use elements::hex::FromHex; use elements::{confidential, encode::deserialize, schnorr::TapTweak, AssetId, Transaction}; use simplicity::{bitcoin, elements}; @@ -143,10 +144,10 @@ pub(super) mod txout_utils { } } pub(super) mod txin_utils { - use bitcoin_hashes::{hex::FromHex, Hash}; + use bitcoin_hashes::Hash; use elements::{ - confidential, encode::deserialize, AssetIssuance, OutPoint, Script, Sequence, TxInWitness, - Txid, + confidential, encode::deserialize, hex::FromHex, AssetIssuance, OutPoint, Script, Sequence, + TxInWitness, Txid, }; use simplicity::{elements, jet::elements::ElementsUtxo}; @@ -162,7 +163,7 @@ pub(super) mod txin_utils { let tx_bytes = rand::random::<[u8; 32]>(); let vout = rand::random::() as u32; let txin = elements::TxIn { - previous_output: OutPoint::new(Txid::from_inner(tx_bytes), vout), + previous_output: OutPoint::new(Txid::from_byte_array(tx_bytes), vout), is_pegin: false, script_sig: Script::new(), sequence: Sequence::MAX, @@ -179,7 +180,7 @@ pub(super) mod txin_utils { let tx_bytes = rand::random::<[u8; 32]>(); let vout = rand::random::() as u32; let txin = elements::TxIn { - previous_output: OutPoint::new(Txid::from_inner(tx_bytes), vout), + previous_output: OutPoint::new(Txid::from_byte_array(tx_bytes), vout), is_pegin: false, script_sig: Script::new(), sequence: Sequence::MAX, diff --git a/jets-bench/benches/elements/main.rs b/jets-bench/benches/elements/main.rs index a79dca1d..6b0efa2e 100644 --- a/jets-bench/benches/elements/main.rs +++ b/jets-bench/benches/elements/main.rs @@ -83,7 +83,7 @@ impl ElementsBenchEnvType { // is hashed let mut annex = rand::random::<[u8; 32]>(); // same annex prefix in bitcoin and elements - annex[0] = bitcoin::util::taproot::TAPROOT_ANNEX_PREFIX; + annex[0] = bitcoin::taproot::TAPROOT_ANNEX_PREFIX; let annex = elements::sighash::Annex::new(&annex).unwrap(); env_sampler.env_with_annex(Some(annex.as_bytes().to_vec())) } else { @@ -236,8 +236,8 @@ fn bench(c: &mut Criterion) { fn bip_0340() -> Value { let secp_ctx = bitcoin::secp256k1::Secp256k1::new(); - let keypair = bitcoin::secp256k1::KeyPair::new(&secp_ctx, &mut thread_rng()); - let xpk = bitcoin::XOnlyPublicKey::from_keypair(&keypair); + let keypair = bitcoin::key::KeyPair::new(&secp_ctx, &mut thread_rng()); + let xpk = bitcoin::key::XOnlyPublicKey::from_keypair(&keypair); let msg = bitcoin::secp256k1::Message::from_slice(&rand::random::<[u8; 32]>()).unwrap(); let sig = secp_ctx.sign_schnorr(&msg, &keypair); @@ -250,7 +250,7 @@ fn bench(c: &mut Criterion) { fn tagged_hash(tag: &[u8], msg_block: [u8; 64]) -> sha256::Hash { let tag_hash = sha256::Hash::hash(tag); - let block = [tag_hash.into_inner(), tag_hash.into_inner()].concat(); + let block = [tag_hash.to_byte_array(), tag_hash.to_byte_array()].concat(); let mut engine = sha256::Hash::engine(); engine.input(&block); engine.input(&msg_block); @@ -260,12 +260,12 @@ fn bench(c: &mut Criterion) { fn check_sig_verify() -> Value { let secp_ctx = bitcoin::secp256k1::Secp256k1::signing_only(); - let keypair = bitcoin::secp256k1::KeyPair::new(&secp_ctx, &mut thread_rng()); - let xpk = bitcoin::XOnlyPublicKey::from_keypair(&keypair); + let keypair = bitcoin::key::KeyPair::new(&secp_ctx, &mut thread_rng()); + let xpk = bitcoin::key::XOnlyPublicKey::from_keypair(&keypair); let msg = [0xab; 64]; let hashed_msg = tagged_hash(b"Simplicity-Draft\x1fSignature", msg); - let hashed_msg = bitcoin::secp256k1::Message::from_slice(&hashed_msg).unwrap(); + let hashed_msg = bitcoin::secp256k1::Message::from(hashed_msg); let sig = secp_ctx.sign_schnorr(&hashed_msg, &keypair); let xpk_value = Value::u256_from_slice(&xpk.0.serialize()); let sig_value = Value::u512_from_slice(sig.as_ref()); diff --git a/simplicity-sys/Cargo.toml b/simplicity-sys/Cargo.toml index 1bc70f67..343cdf83 100644 --- a/simplicity-sys/Cargo.toml +++ b/simplicity-sys/Cargo.toml @@ -10,7 +10,7 @@ cc = "1.0" [dependencies] libc = "0.2" -bitcoin_hashes = "0.11" +bitcoin_hashes = "0.12" [features] test-utils = [] diff --git a/simplicity-sys/src/c_jets/c_env.rs b/simplicity-sys/src/c_jets/c_env.rs index ec3cb484..ec7c1425 100644 --- a/simplicity-sys/src/c_jets/c_env.rs +++ b/simplicity-sys/src/c_jets/c_env.rs @@ -198,7 +198,7 @@ extern "C" { impl CElementsTxEnv { pub fn sighash_all(&self) -> sha256::Hash { let midstate: sha256::Midstate = self.sighash_all.into(); - sha256::Hash::from_inner(midstate.into_inner()) + sha256::Hash::from_byte_array(midstate.to_byte_array()) } } diff --git a/src/bit_machine/mod.rs b/src/bit_machine/mod.rs index 007cb9a8..1a1d6e6e 100644 --- a/src/bit_machine/mod.rs +++ b/src/bit_machine/mod.rs @@ -501,7 +501,7 @@ mod tests { use super::*; #[cfg(feature = "elements")] - use crate::bitcoin_hashes::hex::ToHex; + use crate::hex::ToHex; #[cfg(feature = "elements")] use crate::jet::{elements::ElementsEnv, Elements}; #[cfg(feature = "elements")] diff --git a/src/hex.rs b/src/hex.rs new file mode 100644 index 00000000..396a4709 --- /dev/null +++ b/src/hex.rs @@ -0,0 +1,368 @@ +// SPDX-License-Identifier: CC0-1.0 + +//! Hex Encoding and Decoding + +// The rust-bitcoin hex stury is such a mess right now that the most +// straightforward thing is to just reimplement everything here. +// +// This is a copy/paste of the bitcoin_hashes hex module, with the +// std/alloc feature gates, and the benchmarks, removed. +// + +use std::{fmt, io, str}; + +/// Hex decoding error. +#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub enum Error { + /// Non-hexadecimal character. + InvalidChar(u8), + /// Purported hex string had odd length. + OddLengthString(usize), + /// Tried to parse fixed-length hash from a string with the wrong type (expected, got). + InvalidLength(usize, usize), +} + +impl fmt::Display for Error { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match *self { + Error::InvalidChar(ch) => write!(f, "invalid hex character {}", ch), + Error::OddLengthString(ell) => write!(f, "odd hex string length {}", ell), + Error::InvalidLength(ell, ell2) => { + write!(f, "bad hex string length {} (expected {})", ell2, ell) + } + } + } +} + +/// Trait for objects that can be serialized as hex strings. +pub trait ToHex { + /// Converts to a hexadecimal representation of the object. + fn to_hex(&self) -> String; +} + +/// Trait for objects that can be deserialized from hex strings. +pub trait FromHex: Sized { + /// Produces an object from a byte iterator. + fn from_byte_iter(iter: I) -> Result + where + I: Iterator> + ExactSizeIterator + DoubleEndedIterator; + + /// Produces an object from a hex string. + fn from_hex(s: &str) -> Result { + Self::from_byte_iter(HexIterator::new(s)?) + } +} + +impl ToHex for T { + /// Outputs the hash in hexadecimal form. + fn to_hex(&self) -> String { + format!("{:x}", self) + } +} + +/// Iterator over a hex-encoded string slice which decodes hex and yields bytes. +pub struct HexIterator<'a> { + /// The `Bytes` iterator whose next two bytes will be decoded to yield + /// the next byte. + iter: str::Bytes<'a>, +} + +impl<'a> HexIterator<'a> { + /// Constructs a new `HexIterator` from a string slice. + /// + /// # Errors + /// + /// If the input string is of odd length. + pub fn new(s: &'a str) -> Result, Error> { + if s.len() % 2 != 0 { + Err(Error::OddLengthString(s.len())) + } else { + Ok(HexIterator { iter: s.bytes() }) + } + } +} + +fn chars_to_hex(hi: u8, lo: u8) -> Result { + let hih = (hi as char).to_digit(16).ok_or(Error::InvalidChar(hi))?; + let loh = (lo as char).to_digit(16).ok_or(Error::InvalidChar(lo))?; + + let ret = (hih << 4) + loh; + Ok(ret as u8) +} + +impl<'a> Iterator for HexIterator<'a> { + type Item = Result; + + fn next(&mut self) -> Option> { + let hi = self.iter.next()?; + let lo = self.iter.next().unwrap(); + Some(chars_to_hex(hi, lo)) + } + + fn size_hint(&self) -> (usize, Option) { + let (min, max) = self.iter.size_hint(); + (min / 2, max.map(|x| x / 2)) + } +} + +impl<'a> io::Read for HexIterator<'a> { + fn read(&mut self, buf: &mut [u8]) -> io::Result { + let mut bytes_read = 0usize; + for dst in buf { + match self.next() { + Some(Ok(src)) => { + *dst = src; + bytes_read += 1; + } + _ => break, + } + } + Ok(bytes_read) + } +} + +impl<'a> DoubleEndedIterator for HexIterator<'a> { + fn next_back(&mut self) -> Option> { + let lo = self.iter.next_back()?; + let hi = self.iter.next_back().unwrap(); + Some(chars_to_hex(hi, lo)) + } +} + +impl<'a> ExactSizeIterator for HexIterator<'a> {} + +/// Outputs hex into an object implementing `fmt::Write`. +/// +/// This is usually more efficient than going through a `String` using [`ToHex`]. +pub fn format_hex(data: &[u8], f: &mut fmt::Formatter) -> fmt::Result { + let prec = f.precision().unwrap_or(2 * data.len()); + let width = f.width().unwrap_or(2 * data.len()); + for _ in (2 * data.len())..width { + f.write_str("0")?; + } + for ch in data.iter().take(prec / 2) { + write!(f, "{:02x}", *ch)?; + } + if prec < 2 * data.len() && prec % 2 == 1 { + write!(f, "{:x}", data[prec / 2] / 16)?; + } + Ok(()) +} + +/// Outputs hex in reverse order. +/// +/// Used for `sha256d::Hash` whose standard hex encoding has the bytes reversed. +pub fn format_hex_reverse(data: &[u8], f: &mut fmt::Formatter) -> fmt::Result { + let prec = f.precision().unwrap_or(2 * data.len()); + let width = f.width().unwrap_or(2 * data.len()); + for _ in (2 * data.len())..width { + f.write_str("0")?; + } + for ch in data.iter().rev().take(prec / 2) { + write!(f, "{:02x}", *ch)?; + } + if prec < 2 * data.len() && prec % 2 == 1 { + write!(f, "{:x}", data[data.len() - 1 - prec / 2] / 16)?; + } + Ok(()) +} + +impl ToHex for [u8] { + fn to_hex(&self) -> String { + use core::fmt::Write; + let mut ret = String::with_capacity(2 * self.len()); + for ch in self { + write!(ret, "{:02x}", ch).expect("writing to string"); + } + ret + } +} + +/// A struct implementing [`io::Write`] that converts what's written to it into +/// a hex String. +/// +/// If you already have the data to be converted in a `Vec` use [`ToHex`] +/// but if you have an encodable object, by using this you avoid the +/// serialization to `Vec` by going directly to `String`. +/// +/// Note that to achieve better perfomance than [`ToHex`] the struct must be +/// created with the right `capacity` of the final hex string so that the inner +/// `String` doesn't re-allocate. +pub struct HexWriter(String); + +impl HexWriter { + /// Creates a new [`HexWriter`] with the `capacity` of the inner `String` + /// that will contain final hex value. + pub fn new(capacity: usize) -> Self { + HexWriter(String::with_capacity(capacity)) + } + + /// Returns the resulting hex string. + pub fn result(self) -> String { + self.0 + } +} + +impl io::Write for HexWriter { + fn write(&mut self, buf: &[u8]) -> io::Result { + use core::fmt::Write; + for ch in buf { + write!(self.0, "{:02x}", ch).expect("writing to string"); + } + Ok(buf.len()) + } + + fn flush(&mut self) -> io::Result<()> { + Ok(()) + } +} + +impl FromHex for Vec { + fn from_byte_iter(iter: I) -> Result + where + I: Iterator> + ExactSizeIterator + DoubleEndedIterator, + { + iter.collect() + } +} + +macro_rules! impl_fromhex_array { + ($len:expr) => { + impl FromHex for [u8; $len] { + fn from_byte_iter(iter: I) -> Result + where + I: Iterator> + ExactSizeIterator + DoubleEndedIterator, + { + if iter.len() == $len { + let mut ret = [0; $len]; + for (n, byte) in iter.enumerate() { + ret[n] = byte?; + } + Ok(ret) + } else { + Err(Error::InvalidLength(2 * $len, 2 * iter.len())) + } + } + } + }; +} + +impl_fromhex_array!(2); +impl_fromhex_array!(4); +impl_fromhex_array!(6); +impl_fromhex_array!(8); +impl_fromhex_array!(10); +impl_fromhex_array!(12); +impl_fromhex_array!(14); +impl_fromhex_array!(16); +impl_fromhex_array!(20); +impl_fromhex_array!(24); +impl_fromhex_array!(28); +impl_fromhex_array!(32); +impl_fromhex_array!(33); +impl_fromhex_array!(64); +impl_fromhex_array!(65); +impl_fromhex_array!(128); +impl_fromhex_array!(256); +impl_fromhex_array!(384); +impl_fromhex_array!(512); + +#[cfg(test)] +mod tests { + use super::*; + + use core::fmt; + use std::io::Write; + + #[test] + fn hex_roundtrip() { + let expected = "0123456789abcdef"; + let expected_up = "0123456789ABCDEF"; + + let parse: Vec = FromHex::from_hex(expected).expect("parse lowercase string"); + assert_eq!(parse, vec![0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef]); + let ser = parse.to_hex(); + assert_eq!(ser, expected); + + let parse: Vec = FromHex::from_hex(expected_up).expect("parse uppercase string"); + assert_eq!(parse, vec![0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef]); + let ser = parse.to_hex(); + assert_eq!(ser, expected); + + let parse: [u8; 8] = FromHex::from_hex(expected_up).expect("parse uppercase string"); + assert_eq!(parse, [0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef]); + let ser = parse.to_hex(); + assert_eq!(ser, expected); + } + + #[test] + fn hex_truncate() { + struct HexBytes(Vec); + impl fmt::LowerHex for HexBytes { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + format_hex(&self.0, f) + } + } + + let bytes = HexBytes(vec![1u8, 2, 3, 4, 5, 6, 7, 8, 9, 10]); + + assert_eq!(format!("{:x}", bytes), "0102030405060708090a"); + + for i in 0..20 { + assert_eq!( + format!("{:.prec$x}", bytes, prec = i), + &"0102030405060708090a"[0..i] + ); + } + + assert_eq!(format!("{:25x}", bytes), "000000102030405060708090a"); + assert_eq!(format!("{:26x}", bytes), "0000000102030405060708090a"); + } + + #[test] + fn hex_truncate_rev() { + struct HexBytes(Vec); + impl fmt::LowerHex for HexBytes { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + format_hex_reverse(&self.0, f) + } + } + + let bytes = HexBytes(vec![1u8, 2, 3, 4, 5, 6, 7, 8, 9, 10]); + + assert_eq!(format!("{:x}", bytes), "0a090807060504030201"); + + for i in 0..20 { + assert_eq!( + format!("{:.prec$x}", bytes, prec = i), + &"0a090807060504030201"[0..i] + ); + } + + assert_eq!(format!("{:25x}", bytes), "000000a090807060504030201"); + assert_eq!(format!("{:26x}", bytes), "0000000a090807060504030201"); + } + + #[test] + fn hex_error() { + let oddlen = "0123456789abcdef0"; + let badchar1 = "Z123456789abcdef"; + let badchar2 = "012Y456789abcdeb"; + let badchar3 = "«23456789abcdef"; + + assert_eq!(Vec::::from_hex(oddlen), Err(Error::OddLengthString(17))); + assert_eq!(<[u8; 4]>::from_hex(oddlen), Err(Error::OddLengthString(17))); + assert_eq!(<[u8; 8]>::from_hex(oddlen), Err(Error::OddLengthString(17))); + assert_eq!(Vec::::from_hex(badchar1), Err(Error::InvalidChar(b'Z'))); + assert_eq!(Vec::::from_hex(badchar2), Err(Error::InvalidChar(b'Y'))); + assert_eq!(Vec::::from_hex(badchar3), Err(Error::InvalidChar(194))); + } + + #[test] + fn hex_writer() { + let vec: Vec<_> = (0u8..32).collect(); + let mut writer = HexWriter::new(64); + writer.write_all(&vec[..]).unwrap(); + assert_eq!(vec.to_hex(), writer.result()); + } +} diff --git a/src/human_encoding/serialize.rs b/src/human_encoding/serialize.rs index 856ba7dd..f4e92b4c 100644 --- a/src/human_encoding/serialize.rs +++ b/src/human_encoding/serialize.rs @@ -14,10 +14,10 @@ //! Serialization -use bitcoin_hashes::hex::ToHex; use std::fmt; use crate::dag::{DagLike, NoSharing}; +use crate::hex::ToHex; use crate::Value; pub struct DisplayWord<'a>(pub &'a crate::Value); diff --git a/src/jet/bitcoin/environment.rs b/src/jet/bitcoin/environment.rs index f5dac9f7..a8daa845 100644 --- a/src/jet/bitcoin/environment.rs +++ b/src/jet/bitcoin/environment.rs @@ -12,7 +12,7 @@ // If not, see . // -use bitcoin::PackedLockTime; +use bitcoin::absolute; /// Environment for Bitcoin Simplicity pub struct BitcoinEnv { @@ -30,7 +30,7 @@ impl Default for BitcoinEnv { // FIXME: Review and check if the defaults make sense BitcoinEnv::new(bitcoin::Transaction { version: 2, - lock_time: PackedLockTime::ZERO, + lock_time: absolute::LockTime::ZERO, input: vec![], output: vec![], }) diff --git a/src/jet/elements/c_env.rs b/src/jet/elements/c_env.rs index ed44a64e..4fe2a77a 100644 --- a/src/jet/elements/c_env.rs +++ b/src/jet/elements/c_env.rs @@ -1,6 +1,7 @@ //! High level APIs for creating C FFI compatible environment. //! +use elements::secp256k1_zkp::ffi::CPtr; use std::os::raw::{c_uchar, c_uint}; use elements::{ @@ -47,7 +48,7 @@ fn new_raw_input( let (issue_nonce_ptr, issue_entropy_ptr, issue_amt_ptr, issue_infl_key_ptr) = if inp.has_issuance() { ( - inp.asset_issuance.asset_blinding_nonce.as_ptr(), + inp.asset_issuance.asset_blinding_nonce.as_c_ptr(), inp.asset_issuance.asset_entropy.as_ptr(), value_ptr(inp.asset_issuance.amount, &inp_data.issuance_amount), value_ptr( @@ -67,10 +68,10 @@ fn new_raw_input( raw_input.as_mut_ptr(), opt_ptr(annex_ptr(&inp_data.annex).as_ref()), inp.pegin_data() - .map(|x| x.genesis_hash.as_ptr()) + .map(|x| AsRef::<[u8]>::as_ref(&x.genesis_hash).as_ptr()) .unwrap_or(std::ptr::null()), &script_ptr(&inp.script_sig), - inp.previous_output.txid.as_ptr(), + AsRef::<[u8]>::as_ref(&inp.previous_output.txid).as_ptr(), inp.previous_output.vout as c_uint, asset_ptr(in_utxo.asset, &inp_data.asset), value_ptr(in_utxo.value, &inp_data.value), @@ -144,7 +145,7 @@ pub(super) fn new_tx(tx: &elements::Transaction, in_utxos: &[ElementsUtxo]) -> * raw_inputs.len() as c_uint, raw_outputs.as_ptr(), raw_outputs.len() as c_uint, - tx.lock_time.0 as c_uint, + tx.lock_time.to_consensus_u32() as c_uint, ); let raw_tx = raw_tx.assume_init(); elements_simplicity_mallocTransaction(&raw_tx) @@ -174,7 +175,13 @@ pub(super) fn new_tx_env( ) -> CElementsTxEnv { unsafe { let mut tx_env = std::mem::MaybeUninit::::uninit(); - c_set_txEnv(tx_env.as_mut_ptr(), tx, taproot, genesis_hash.as_ptr(), ix); + c_set_txEnv( + tx_env.as_mut_ptr(), + tx, + taproot, + AsRef::<[u8]>::as_ref(&genesis_hash).as_ptr(), + ix, + ); tx_env.assume_init() } } diff --git a/src/jet/elements/environment.rs b/src/jet/elements/environment.rs index 90360e11..b98de35f 100644 --- a/src/jet/elements/environment.rs +++ b/src/jet/elements/environment.rs @@ -131,11 +131,11 @@ impl ElementsEnv { impl ElementsEnv { /// Return a dummy Elements environment pub fn dummy() -> Self { - Self::dummy_with(elements::PackedLockTime::ZERO, elements::Sequence::MAX) + Self::dummy_with(elements::LockTime::ZERO, elements::Sequence::MAX) } /// Return a dummy Elements environment with given locktime - pub fn dummy_with(lock_time: elements::PackedLockTime, sequence: elements::Sequence) -> Self { + pub fn dummy_with(lock_time: elements::LockTime, sequence: elements::Sequence) -> Self { use bitcoin_hashes::Hash; use elements::AssetIssuance; diff --git a/src/jet/elements/tests.rs b/src/jet/elements/tests.rs index d13ed288..c9278a64 100644 --- a/src/jet/elements/tests.rs +++ b/src/jet/elements/tests.rs @@ -9,8 +9,8 @@ use bitcoin_hashes::Hash; use elements::secp256k1_zkp::Tweak; use elements::taproot::ControlBlock; use elements::{ - confidential, AssetId, AssetIssuance, BlockHash, OutPoint, PackedLockTime, Sequence, - Transaction, TxIn, TxInWitness, TxOut, TxOutWitness, + confidential, AssetId, AssetIssuance, BlockHash, OutPoint, Sequence, Transaction, TxIn, + TxInWitness, TxOut, TxOutWitness, }; #[test] @@ -30,13 +30,14 @@ fn test_ffi_env() { 0x33, 0x2f, 0xb7, 0x1d, 0xda, 0x90, 0xff, 0x4b, 0xef, 0x53, 0x70, 0xf2, 0x52, 0x26, 0xd3, 0xbc, 0x09, 0xfc, ]; - let asset = confidential::Asset::Explicit(AssetId::from_inner(Midstate::from_inner(asset))); + let asset = + confidential::Asset::Explicit(AssetId::from_inner(Midstate::from_byte_array(asset))); let tx = Transaction { version: 2, - lock_time: PackedLockTime(100), + lock_time: elements::LockTime::from_consensus(100), input: vec![TxIn { previous_output: OutPoint { - txid: elements::Txid::from_inner(tx_id), + txid: elements::Txid::from_byte_array(tx_id), vout: 0, }, sequence: Sequence::ENABLE_LOCKTIME_NO_RBF, diff --git a/src/lib.rs b/src/lib.rs index 630d611a..ad29e8ab 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -37,6 +37,8 @@ mod analysis; mod bit_encoding; pub mod bit_machine; pub mod dag; +#[allow(dead_code)] +mod hex; pub mod human_encoding; pub mod jet; mod merkle; diff --git a/src/merkle/mod.rs b/src/merkle/mod.rs index 27f63943..8f3c098a 100644 --- a/src/merkle/mod.rs +++ b/src/merkle/mod.rs @@ -23,7 +23,7 @@ pub mod imr; pub mod tmr; use crate::Value; -use bitcoin_hashes::{hex, sha256, Hash, HashEngine}; +use bitcoin_hashes::{sha256, Hash, HashEngine}; use std::fmt; /// 512-bit opaque blob of data used to seed `Fail` nodes @@ -42,7 +42,7 @@ impl FailEntropy { impl fmt::Display for FailEntropy { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - hex::format_hex(&self.0, f) + crate::hex::format_hex(&self.0, f) } } @@ -91,14 +91,14 @@ fn compact_value(value: &Value) -> [u8; 32] { consumed += 16; } debug_assert!(consumed == bytes.len()); - engine.midstate().into_inner() + engine.midstate().to_byte_array() } fn bip340_iv(tag: &[u8]) -> sha256::Midstate { let tag_hash = sha256::Hash::hash(tag); let mut engine = sha256::Hash::engine(); - engine.input(&tag_hash); - engine.input(&tag_hash); + engine.input(tag_hash.as_ref()); + engine.input(tag_hash.as_ref()); engine.midstate() } @@ -117,13 +117,13 @@ macro_rules! impl_midstate_wrapper { impl std::fmt::Debug for $wrapper { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { - bitcoin_hashes::hex::format_hex(&self.0.as_ref(), f) + $crate::hex::format_hex(&self.0.as_ref(), f) } } impl std::fmt::Display for $wrapper { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { - bitcoin_hashes::hex::format_hex(&self.0.as_ref(), f) + $crate::hex::format_hex(&self.0.as_ref(), f) } } @@ -132,7 +132,7 @@ macro_rules! impl_midstate_wrapper { fn from_str(s: &str) -> Result { let x: [u8; 32] = bitcoin_hashes::hex::FromHex::from_hex(s)?; - Ok($wrapper(Midstate::from_inner(x))) + Ok($wrapper(Midstate::from_byte_array(x))) } } @@ -175,12 +175,12 @@ macro_rules! impl_midstate_wrapper { /// Converts the given tagged hash into a byte array pub fn from_byte_array(data: [u8; 32]) -> Self { - $wrapper(Midstate::from_inner(data)) + $wrapper(Midstate::from_byte_array(data)) } /// Converts the given tagged hash into a byte array pub fn to_byte_array(self) -> [u8; 32] { - self.0.into_inner() + self.0.to_byte_array() } } }; diff --git a/src/node/commit.rs b/src/node/commit.rs index 3ecd121e..612a1e1a 100644 --- a/src/node/commit.rs +++ b/src/node/commit.rs @@ -290,7 +290,7 @@ impl CommitNode { mod tests { use super::*; - use bitcoin_hashes::hex::ToHex; + use crate::hex::ToHex; use std::fmt; use crate::decode::Error; diff --git a/src/node/redeem.rs b/src/node/redeem.rs index e55cd5dd..fa2945fe 100644 --- a/src/node/redeem.rs +++ b/src/node/redeem.rs @@ -342,7 +342,7 @@ impl RedeemNode { mod tests { use super::*; - use bitcoin_hashes::hex::ToHex; + use crate::hex::ToHex; use std::fmt; use crate::jet::Core; diff --git a/src/policy/descriptor.rs b/src/policy/descriptor.rs index b4762c46..e508e2cd 100644 --- a/src/policy/descriptor.rs +++ b/src/policy/descriptor.rs @@ -153,7 +153,7 @@ impl Descriptor { // Single leaf: leaf hash = merkle root let (script, leaf_version) = self.leaf(); let leaf_hash = TapLeafHash::from_script(&script, leaf_version); - let merkle_root = TapBranchHash::from_inner(leaf_hash.into_inner()); + let merkle_root = TapBranchHash::from_byte_array(leaf_hash.to_byte_array()); // Single leaf: empty merkle inclusion proof let merkle_branch = TaprootMerkleBranch::from_inner(Vec::new()).expect("constant branch"); diff --git a/src/policy/embed.rs b/src/policy/embed.rs index c9e701d9..0a9284fa 100644 --- a/src/policy/embed.rs +++ b/src/policy/embed.rs @@ -111,7 +111,7 @@ impl<'a, Pk: ToPublicKey, Ctx: ScriptContext> TryFrom<&'a Miniscript> f Terminal::PkH(_) | Terminal::RawPkH(_) => { Err(Error::Policy(policy::Error::PublicKeyHash)) } - Terminal::After(n) => Ok(Policy::After(n.0)), + Terminal::After(n) => Ok(Policy::After(n.to_consensus_u32())), Terminal::Older(n) => { if !n.is_height_locked() { return Err(Error::Policy(policy::Error::InvalidSequence)); @@ -178,7 +178,7 @@ impl<'a, Pk: ToPublicKey, Ctx: ScriptContext> TryFrom<&'a Miniscript> f #[cfg(test)] mod tests { use super::*; - use crate::miniscript::bitcoin::XOnlyPublicKey; + use crate::miniscript::bitcoin::key::XOnlyPublicKey; #[test] fn parse_bad_thresh() { diff --git a/src/policy/satisfy.rs b/src/policy/satisfy.rs index a46b2099..727db211 100644 --- a/src/policy/satisfy.rs +++ b/src/policy/satisfy.rs @@ -5,7 +5,6 @@ use crate::{Error, Policy, Value}; use bitcoin_hashes::Hash; use elements::locktime::Height; use elements::taproot::TapLeafHash; -use elements::{LockTime, Sequence}; use elements_miniscript::{MiniscriptKey, Preimage32, Satisfier, ToPublicKey}; use crate::analysis::Cost; @@ -29,14 +28,13 @@ impl<'a, Pk: ToPublicKey> Satisfier for PolicySatisfier<'a, Pk> { self.preimages.get(hash).copied() } - fn check_older(&self, sequence: Sequence) -> bool { + fn check_older(&self, sequence: elements::Sequence) -> bool { let self_sequence = self.tx.input[self.index].sequence; - >::check_older(&self_sequence, sequence) + >::check_older(&self_sequence, sequence) } - fn check_after(&self, locktime: LockTime) -> bool { - let self_locktime = LockTime::from(self.tx.lock_time); - >::check_after(&self_locktime, locktime) + fn check_after(&self, locktime: elements::LockTime) -> bool { + >::check_after(&self.tx.lock_time, locktime) } } @@ -57,7 +55,7 @@ impl Policy { Policy::After(n) => { let node = super::serialize::after(n); let height = Height::from_consensus(n).expect("timelock is valid"); - if satisfier.check_after(LockTime::Blocks(height)) { + if satisfier.check_after(elements::LockTime::Blocks(height)) { node } else { node.pruned() @@ -65,7 +63,7 @@ impl Policy { } Policy::Older(n) => { let node = super::serialize::older(n); - if satisfier.check_older(Sequence((n).into())) { + if satisfier.check_older(elements::Sequence((n).into())) { node } else { node.pruned() @@ -179,10 +177,11 @@ mod tests { use crate::node::SimpleFinalizer; use crate::{BitMachine, FailEntropy}; use bitcoin_hashes::{sha256, Hash}; - use elements::{bitcoin, secp256k1_zkp, PackedLockTime, SchnorrSigHashType}; + use elements::bitcoin::key::{KeyPair, XOnlyPublicKey}; + use elements::{secp256k1_zkp, LockTime, SchnorrSigHashType}; use std::sync::Arc; - fn get_satisfier(env: &ElementsEnv) -> PolicySatisfier { + fn get_satisfier(env: &ElementsEnv) -> PolicySatisfier { let mut preimages = HashMap::new(); let mut signatures = HashMap::new(); @@ -195,11 +194,11 @@ mod tests { let mut rng = secp256k1_zkp::rand::rngs::ThreadRng::default(); for _ in 0..3 { - let keypair = bitcoin::KeyPair::new(&secp, &mut rng); + let keypair = KeyPair::new(&secp, &mut rng); let xonly = keypair.x_only_public_key().0; let sighash = env.c_tx_env().sighash_all(); - let msg = secp256k1_zkp::Message::from_slice(&sighash).expect("constant sighash"); + let msg = secp256k1_zkp::Message::from(sighash); let sig = elements::SchnorrSig { sig: keypair.sign_schnorr(msg), hash_ty: SchnorrSigHashType::All, @@ -304,7 +303,8 @@ mod tests { #[test] fn satisfy_after() { - let env = ElementsEnv::dummy_with(PackedLockTime(42), Sequence::ZERO); + let height = Height::from_consensus(42).unwrap(); + let env = ElementsEnv::dummy_with(LockTime::Blocks(height), elements::Sequence::ZERO); let satisfier = get_satisfier(&env); let policy0 = Policy::After(41); @@ -325,7 +325,7 @@ mod tests { #[test] fn satisfy_older() { - let env = ElementsEnv::dummy_with(PackedLockTime::ZERO, Sequence::from_consensus(42)); + let env = ElementsEnv::dummy_with(LockTime::ZERO, elements::Sequence::from_consensus(42)); let satisfier = get_satisfier(&env); let policy0 = Policy::Older(41); @@ -376,7 +376,7 @@ mod tests { // Policy 1 let policy1 = Policy::And { - left: Arc::new(Policy::Sha256(sha256::Hash::from_inner([0; 32]))), + left: Arc::new(Policy::Sha256(sha256::Hash::from_byte_array([0; 32]))), right: Arc::new(Policy::Sha256(images[1])), }; assert!(policy1.satisfy(&satisfier).is_err()); @@ -385,7 +385,7 @@ mod tests { let policy2 = Policy::And { left: Arc::new(Policy::Sha256(images[0])), - right: Arc::new(Policy::Sha256(sha256::Hash::from_inner([0; 32]))), + right: Arc::new(Policy::Sha256(sha256::Hash::from_byte_array([0; 32]))), }; assert!(policy2.satisfy(&satisfier).is_err()); } @@ -400,7 +400,7 @@ mod tests { .map(|x| satisfier.preimages.get(x).unwrap()) .collect(); - let assert_branch = |policy: &Policy, bit: bool| { + let assert_branch = |policy: &Policy, bit: bool| { let program = policy.satisfy(&satisfier).expect("satisfiable"); let witness = to_witness(&program); assert_eq!(2, witness.len()); @@ -426,14 +426,14 @@ mod tests { let policy1 = Policy::Or { left: Arc::new(Policy::Sha256(images[0])), - right: Arc::new(Policy::Sha256(sha256::Hash::from_inner([1; 32]))), + right: Arc::new(Policy::Sha256(sha256::Hash::from_byte_array([1; 32]))), }; assert_branch(&policy1, false); // Policy 2 let policy2 = Policy::Or { - left: Arc::new(Policy::Sha256(sha256::Hash::from_inner([0; 32]))), + left: Arc::new(Policy::Sha256(sha256::Hash::from_byte_array([0; 32]))), right: Arc::new(Policy::Sha256(images[1])), }; assert_branch(&policy2, true); @@ -441,8 +441,8 @@ mod tests { // Policy 3 let policy3 = Policy::Or { - left: Arc::new(Policy::Sha256(sha256::Hash::from_inner([0; 32]))), - right: Arc::new(Policy::Sha256(sha256::Hash::from_inner([1; 32]))), + left: Arc::new(Policy::Sha256(sha256::Hash::from_byte_array([0; 32]))), + right: Arc::new(Policy::Sha256(sha256::Hash::from_byte_array([1; 32]))), }; assert!(policy3.satisfy(&satisfier).is_err()); } @@ -457,7 +457,7 @@ mod tests { .map(|x| satisfier.preimages.get(x).unwrap()) .collect(); - let assert_branches = |policy: &Policy, bits: &[bool]| { + let assert_branches = |policy: &Policy, bits: &[bool]| { let program = policy.satisfy(&satisfier).expect("satisfiable"); let witness = to_witness(&program); assert_eq!( @@ -483,7 +483,7 @@ mod tests { if bit { images[j as usize] } else { - sha256::Hash::from_inner([j; 32]) + sha256::Hash::from_byte_array([j; 32]) } }; diff --git a/src/policy/serialize.rs b/src/policy/serialize.rs index 1d746893..f4f079aa 100644 --- a/src/policy/serialize.rs +++ b/src/policy/serialize.rs @@ -250,12 +250,12 @@ mod tests { use crate::policy::Policy; use crate::{BitMachine, FailEntropy, Value}; use bitcoin_hashes::{sha256, Hash}; - use elements::{bitcoin, secp256k1_zkp}; + use elements::bitcoin::key::XOnlyPublicKey; + use elements::locktime::Height; + use elements::secp256k1_zkp; use std::sync::Arc; - fn compile( - policy: Policy, - ) -> (Arc>, ElementsEnv) { + fn compile(policy: Policy) -> (Arc>, ElementsEnv) { let commit = policy.serialize_no_witness(); let env = ElementsEnv::dummy(); @@ -314,32 +314,34 @@ mod tests { #[test] fn execute_after() { - let env = ElementsEnv::dummy_with(elements::PackedLockTime(42), elements::Sequence::ZERO); + let height = Height::from_consensus(42).unwrap(); + let env = + ElementsEnv::dummy_with(elements::LockTime::Blocks(height), elements::Sequence::ZERO); - let commit = Policy::::After(41).serialize_no_witness(); + let commit = Policy::::After(41).serialize_no_witness(); assert!(execute_successful(&commit, vec![], &env)); - let commit = Policy::::After(42).serialize_no_witness(); + let commit = Policy::::After(42).serialize_no_witness(); assert!(execute_successful(&commit, vec![], &env)); - let commit = Policy::::After(43).serialize_no_witness(); + let commit = Policy::::After(43).serialize_no_witness(); assert!(!execute_successful(&commit, vec![], &env)); } #[test] fn execute_older() { let env = ElementsEnv::dummy_with( - elements::PackedLockTime::ZERO, + elements::LockTime::ZERO, elements::Sequence::from_consensus(42), ); - let commit = Policy::::Older(41).serialize_no_witness(); + let commit = Policy::::Older(41).serialize_no_witness(); assert!(execute_successful(&commit, vec![], &env)); - let commit = Policy::::Older(42).serialize_no_witness(); + let commit = Policy::::Older(42).serialize_no_witness(); assert!(execute_successful(&commit, vec![], &env)); - let commit = Policy::::Older(43).serialize_no_witness(); + let commit = Policy::::Older(43).serialize_no_witness(); assert!(!execute_successful(&commit, vec![], &env)); } From 91ecf06b7a3ccdbfd745f5183962036104c08697 Mon Sep 17 00:00:00 2001 From: Christian Lewe Date: Wed, 19 Jul 2023 14:37:19 +0200 Subject: [PATCH 2/2] Fix CI proc-macro2 1.0.66 jumps editions and quote depends on that. --- .github/workflows/main.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 6778c01e..1074182c 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -98,6 +98,10 @@ jobs: cargo update -p serde_json --precise 1.0.99 # 1.0.157 uses syn 2.0 cargo update -p serde --precise 1.0.156 + # 1.0.31 uses proc-macro 1.0.66 + cargo update -p quote --precise 1.0.30 + # 1.0.66 uses edition 2021 + cargo update -p proc-macro2 --precise 1.0.65 fi for f in $FEATURES; do echo "Features: $f" && cargo test --no-default-features --features="$f"; done echo "No default features" && cargo test --no-default-features