Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 0 additions & 15 deletions .github/workflows/rust.yml
Original file line number Diff line number Diff line change
Expand Up @@ -83,18 +83,3 @@ jobs:
env:
DO_FEATURE_MATRIX: true
run: ./contrib/test.sh

IntTests:
name: Integration tests
runs-on: ubuntu-latest
steps:
- name: Checkout Crate
uses: actions/checkout@v2
- name: Checkout Toolchain
uses: actions-rs/toolchain@v1
with:
profile: minimal
toolchain: stable
override: true
- name: Running cargo
run: ./contrib/test.sh
12 changes: 6 additions & 6 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,10 @@ rand = ["bitcoin/rand"]
base64 = ["bitcoin/base64"]

[dependencies]
bitcoin = "0.30.0"
elements = "0.23.0"
bitcoin-miniscript = { package = "miniscript", version = "10.0" }
simplicity = { git = "https://github.com/BlockstreamResearch/rust-simplicity", rev = "d5c0d65320816bfdf36411feed4bdff0708b5b12", optional = true }
bitcoin = "0.31.0"
elements = "0.24.0"
bitcoin-miniscript = { package = "miniscript", version = "11.0" }
simplicity = { git = "https://github.com/BlockstreamResearch/rust-simplicity", rev = "39fe6d7533b06001e9954fa08df34a1052702caf", optional = true }

# Do NOT use this as a feature! Use the `serde` feature instead.
actual-serde = { package = "serde", version = "1.0", optional = true }
Expand All @@ -31,8 +31,8 @@ actual-serde = { package = "serde", version = "1.0", optional = true }
serde_json = "1.0"
actual-rand = { package = "rand", version = "0.8.4"}
serde_test = "1.0.147"
bitcoin = { version = "0.30.0", features = ["base64"] }
secp256k1 = {version = "0.27.0", features = ["rand-std"]}
bitcoin = { version = "0.31.0", features = ["base64"] }
secp256k1 = {version = "0.28.0", features = ["rand-std"]}
actual-base64 = { package = "base64", version = "0.13.0" }


Expand Down
4 changes: 2 additions & 2 deletions bitcoind-tests/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,6 @@ edition = "2018"

[dependencies]
elements-miniscript = { path = "../" }
elementsd = { version = "0.8.0" }
elementsd = { version = "0.9.0" }
actual-rand = { package = "rand", version = "0.8.4" }
secp256k1 = { version = "0.27.0", features = ["rand-std"] }
secp256k1 = { version = "0.28.1", features = ["rand-std"] }
6 changes: 3 additions & 3 deletions bitcoind-tests/tests/setup/test_util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ pub struct PubData {
#[derive(Debug, Clone)]
pub struct SecretData {
pub sks: Vec<bitcoin::secp256k1::SecretKey>,
pub x_only_keypairs: Vec<bitcoin::key::KeyPair>,
pub x_only_keypairs: Vec<bitcoin::key::Keypair>,
pub sha256_pre: [u8; 32],
pub hash256_pre: [u8; 32],
pub ripemd160_pre: [u8; 32],
Expand All @@ -75,7 +75,7 @@ fn setup_keys(
) -> (
Vec<bitcoin::secp256k1::SecretKey>,
Vec<miniscript::bitcoin::PublicKey>,
Vec<bitcoin::key::KeyPair>,
Vec<bitcoin::key::Keypair>,
Vec<bitcoin::key::XOnlyPublicKey>,
) {
let secp_sign = secp256k1::Secp256k1::signing_only();
Expand All @@ -100,7 +100,7 @@ fn setup_keys(
let mut x_only_pks = vec![];

for sk in &sks {
let keypair = bitcoin::key::KeyPair::from_secret_key(&secp_sign, sk);
let keypair = bitcoin::key::Keypair::from_secret_key(&secp_sign, sk);
let (xpk, _parity) = bitcoin::key::XOnlyPublicKey::from_keypair(&keypair);
x_only_keypairs.push(keypair);
x_only_pks.push(xpk);
Expand Down
2 changes: 1 addition & 1 deletion bitcoind-tests/tests/test_arith.rs
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ pub fn test_desc_satisfy(cl: &ElementsD, testdata: &TestData, desc: &str) -> Vec
let prevouts = [witness_utxo];
let prevouts = sighash::Prevouts::All(&prevouts);
// ------------------ script spend -------------
let x_only_keypairs_reqd: Vec<(secp256k1::KeyPair, TapLeafHash)> = tr
let x_only_keypairs_reqd: Vec<(secp256k1::Keypair, TapLeafHash)> = tr
.iter_scripts()
.flat_map(|(_depth, script)| {
let leaf_hash = TapLeafHash::from_script(&script.encode(), script.version());
Expand Down
2 changes: 1 addition & 1 deletion bitcoind-tests/tests/test_cpp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,7 @@ pub fn test_from_cpp_ms(cl: &ElementsD, testdata: &TestData) {

// requires both signing and verification because we check the tx
// after we psbt extract it
let msg = secp256k1_zkp::Message::from_slice(&sighash[..]).unwrap();
let msg = secp256k1_zkp::Message::from_digest_slice(&sighash[..]).unwrap();

// Finally construct the signature and add to psbt
for sk in sks_reqd {
Expand Down
6 changes: 3 additions & 3 deletions bitcoind-tests/tests/test_csfs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ pub fn test_desc_satisfy(cl: &ElementsD, testdata: &TestData, desc: &str) -> Vec
let prevouts = [witness_utxo];
let prevouts = sighash::Prevouts::All(&prevouts);
// ------------------ script spend -------------
let x_only_keypairs_reqd: Vec<(secp256k1::KeyPair, TapLeafHash)> = tr
let x_only_keypairs_reqd: Vec<(secp256k1::Keypair, TapLeafHash)> = tr
.iter_scripts()
.flat_map(|(_depth, script)| {
let leaf_hash = TapLeafHash::from_script(&script.encode(), script.version());
Expand All @@ -126,7 +126,7 @@ pub fn test_desc_satisfy(cl: &ElementsD, testdata: &TestData, desc: &str) -> Vec
testdata.pubdata.genesis_hash,
)
.unwrap();
let msg = secp256k1::Message::from_slice(&sighash_msg[..]).unwrap();
let msg = secp256k1::Message::from_digest_slice(&sighash_msg[..]).unwrap();
let mut aux_rand = [0u8; 32];
rand::thread_rng().fill_bytes(&mut aux_rand);
let sig = secp.sign_schnorr_with_aux_rand(&msg, &keypair, &aux_rand);
Expand Down Expand Up @@ -167,7 +167,7 @@ pub fn test_desc_satisfy(cl: &ElementsD, testdata: &TestData, desc: &str) -> Vec

// Create a signature
let keypair = &self.0.secretdata.x_only_keypairs[i];
let msg = secp256k1::Message::from_slice(msg.as_inner()).unwrap();
let msg = secp256k1::Message::from_digest_slice(msg.as_inner()).unwrap();
let mut aux_rand = [0u8; 32];
rand::thread_rng().fill_bytes(&mut aux_rand);

Expand Down
6 changes: 3 additions & 3 deletions bitcoind-tests/tests/test_desc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,7 @@ pub fn test_desc_satisfy(
testdata.pubdata.genesis_hash,
)
.unwrap();
let msg = secp256k1::Message::from_slice(&sighash_msg[..]).unwrap();
let msg = secp256k1::Message::from_digest_slice(&sighash_msg[..]).unwrap();
let mut aux_rand = [0u8; 32];
rand::thread_rng().fill_bytes(&mut aux_rand);
let schnorr_sig =
Expand All @@ -176,7 +176,7 @@ pub fn test_desc_satisfy(
// No internal key
}
// ------------------ script spend -------------
let x_only_keypairs_reqd: Vec<(secp256k1::KeyPair, TapLeafHash)> = tr
let x_only_keypairs_reqd: Vec<(secp256k1::Keypair, TapLeafHash)> = tr
.iter_scripts()
.flat_map(|(_depth, script)| {
let leaf_hash = TapLeafHash::from_script(&script.encode(), script.version());
Expand All @@ -196,7 +196,7 @@ pub fn test_desc_satisfy(
testdata.pubdata.genesis_hash,
)
.unwrap();
let msg = secp256k1::Message::from_slice(&sighash_msg[..]).unwrap();
let msg = secp256k1::Message::from_digest_slice(&sighash_msg[..]).unwrap();
let mut aux_rand = [0u8; 32];
rand::thread_rng().fill_bytes(&mut aux_rand);
let sig = secp.sign_schnorr_with_aux_rand(&msg, &keypair, &aux_rand);
Expand Down
4 changes: 2 additions & 2 deletions bitcoind-tests/tests/test_introspect.rs
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ pub fn test_desc_satisfy(cl: &ElementsD, testdata: &TestData, desc: &str) -> Vec
let prevouts = [witness_utxo];
let prevouts = sighash::Prevouts::All(&prevouts);
// ------------------ script spend -------------
let x_only_keypairs_reqd: Vec<(secp256k1::KeyPair, TapLeafHash)> = tr
let x_only_keypairs_reqd: Vec<(secp256k1::Keypair, TapLeafHash)> = tr
.iter_scripts()
.flat_map(|(_depth, script)| {
let leaf_hash = TapLeafHash::from_script(&script.encode(), script.version());
Expand All @@ -125,7 +125,7 @@ pub fn test_desc_satisfy(cl: &ElementsD, testdata: &TestData, desc: &str) -> Vec
testdata.pubdata.genesis_hash,
)
.unwrap();
let msg = secp256k1::Message::from_slice(&sighash_msg[..]).unwrap();
let msg = secp256k1::Message::from_digest_slice(&sighash_msg[..]).unwrap();
let mut aux_rand = [0u8; 32];
rand::thread_rng().fill_bytes(&mut aux_rand);
let sig = secp.sign_schnorr_with_aux_rand(&msg, &keypair, &aux_rand);
Expand Down
17 changes: 11 additions & 6 deletions examples/taproot.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,14 @@ extern crate elements_miniscript as miniscript;
use std::collections::HashMap;
use std::str::FromStr;

use bitcoin::address::WitnessVersion;
use bitcoin::WitnessVersion;
use miniscript::descriptor::DescriptorType;
use miniscript::descriptor::TapLeafScript;
use miniscript::policy::Concrete;
use miniscript::{
translate_hash_fail, Descriptor, Miniscript, NoExt, Tap, TranslatePk, Translator,
};
use miniscript::descriptor::TapLeafScript;
use secp256k1::{rand, KeyPair};
use secp256k1::{rand, Keypair};

// Refer to https://github.com/sanket1729/adv_btc_workshop/blob/master/workshop.md#creating-a-taproot-descriptor
// for a detailed explanation of the policy and it's compilation
Expand Down Expand Up @@ -71,14 +71,19 @@ fn main() {
iter.next().unwrap(),
(
1,
TapLeafScript::Miniscript(&Miniscript::<String, Tap, NoExt>::from_str("and_v(vc:pk_k(In),older(9))").unwrap())
TapLeafScript::Miniscript(
&Miniscript::<String, Tap, NoExt>::from_str("and_v(vc:pk_k(In),older(9))")
.unwrap()
)
)
);
assert_eq!(
iter.next().unwrap(),
(
1,
TapLeafScript::Miniscript(&Miniscript::<String, Tap, NoExt>::from_str("multi_a(2,hA,S)").unwrap())
TapLeafScript::Miniscript(
&Miniscript::<String, Tap, NoExt>::from_str("multi_a(2,hA,S)").unwrap()
)
)
);
assert_eq!(iter.next(), None);
Expand All @@ -88,7 +93,7 @@ fn main() {

// We require secp for generating a random XOnlyPublicKey
let secp = secp256k1::Secp256k1::new();
let key_pair = KeyPair::new(&secp, &mut rand::thread_rng());
let key_pair = Keypair::new(&secp, &mut rand::thread_rng());
// Random unspendable XOnlyPublicKey provided for compilation to Taproot Descriptor
let (unspendable_pubkey, _parity) = bitcoin::key::XOnlyPublicKey::from_keypair(&key_pair);

Expand Down
2 changes: 1 addition & 1 deletion examples/verify_tx.rs
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ fn main() {
// 3. Example three: same, but with the wrong signature hash, to demonstrate
// what happens given an apparently invalid script
let secp = secp256k1_zkp::Secp256k1::new();
let message = secp256k1_zkp::Message::from_slice(&[0x01; 32][..]).expect("32-byte hash");
let message = secp256k1_zkp::Message::from_digest_slice(&[0x01; 32][..]).expect("32-byte hash");
let interpreter = miniscript::Interpreter::from_txdata(
&spk_input_1,
&transaction.input[0].script_sig,
Expand Down
40 changes: 19 additions & 21 deletions src/confidential/bare.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,20 +20,12 @@ use elements::secp256k1_zkp;

use crate::ToPublicKey;

/// The SHA-256 initial midstate value for the [`TweakHash`].
const MIDSTATE_HASH_TO_PRIVATE_HASH: [u8; 32] = [
0x2f, 0x85, 0x61, 0xec, 0x30, 0x88, 0xad, 0xa9, 0x5a, 0xe7, 0x43, 0xcd, 0x3c, 0x5f, 0x59, 0x7d,
0xc0, 0x4b, 0xd0, 0x7f, 0x06, 0x5f, 0x1c, 0x06, 0x47, 0x89, 0x36, 0x63, 0xf3, 0x92, 0x6e, 0x65,
];

sha256t_hash_newtype!(
TweakHash,
TweakTag,
MIDSTATE_HASH_TO_PRIVATE_HASH,
64,
doc = "BIP-340 Tagged hash for tweaking blinding keys",
forward
);
sha256t_hash_newtype! {
pub struct TapTweakTag = hash_str("CT-Blinding-Key/1.0");
/// Taproot-tagged hash for elements tapscript Merkle tree leafs
#[hash_newtype(forward)]
pub struct TapTweakHash(_);
}

/// Tweaks a bare key using the scriptPubKey of a descriptor
pub fn tweak_key<'a, Pk, V>(
Expand All @@ -45,12 +37,12 @@ where
Pk: ToPublicKey + 'a,
V: secp256k1_zkp::Verification,
{
let mut eng = TweakHash::engine();
let mut eng = TapTweakHash::engine();
pk.to_public_key()
.write_into(&mut eng)
.expect("engines don't error");
spk.consensus_encode(&mut eng).expect("engines don't error");
let hash_bytes = TweakHash::from_engine(eng).to_byte_array();
let hash_bytes = TapTweakHash::from_engine(eng).to_byte_array();
let hash_scalar = secp256k1_zkp::Scalar::from_be_bytes(hash_bytes).expect("bytes from hash");
pk.to_public_key()
.inner
Expand All @@ -67,12 +59,12 @@ pub fn tweak_private_key<V>(
where
V: secp256k1_zkp::Signing,
{
let mut eng = TweakHash::engine();
let mut eng = TapTweakHash::engine();
bitcoin::PublicKey::new(sk.public_key(secp))
.write_into(&mut eng)
.expect("engines don't error");
spk.consensus_encode(&mut eng).expect("engines don't error");
let hash_bytes = TweakHash::from_engine(eng).to_byte_array();
let hash_bytes = TapTweakHash::from_engine(eng).to_byte_array();
let hash_scalar = secp256k1_zkp::Scalar::from_be_bytes(hash_bytes).expect("bytes from hash");
sk.add_tweak(&hash_scalar).unwrap()
}
Expand All @@ -84,6 +76,12 @@ mod tests {

use super::*;

const MIDSTATE_HASH_TO_PRIVATE_HASH: [u8; 32] = [
0x2f, 0x85, 0x61, 0xec, 0x30, 0x88, 0xad, 0xa9, 0x5a, 0xe7, 0x43, 0xcd, 0x3c, 0x5f, 0x59,
0x7d, 0xc0, 0x4b, 0xd0, 0x7f, 0x06, 0x5f, 0x1c, 0x06, 0x47, 0x89, 0x36, 0x63, 0xf3, 0x92,
0x6e, 0x65,
];

#[test]
fn tagged_hash() {
// Check that cached midstate is computed correctly
Expand All @@ -100,18 +98,18 @@ mod tests {

// Test empty hash
assert_eq!(
TweakHash::from_engine(TweakTag::engine()).to_string(),
TapTweakHash::from_engine(TapTweakTag::engine()).to_string(),
"d12a140aca856fbb917b931f263c42f064608985e2ce17ae5157daa17c55e8d9",
);
assert_eq!(
TweakHash::hash(&[]).to_string(),
TapTweakHash::hash(&[]).to_string(),
"d12a140aca856fbb917b931f263c42f064608985e2ce17ae5157daa17c55e8d9",
);

// And hash of 100 bytes
let data: Vec<u8> = (0..80).collect();
assert_eq!(
TweakHash::hash(&data).to_string(),
TapTweakHash::hash(&data).to_string(),
"e1e52419a2934d278c50e29608969d2f23c1bd1243a09bfc8026d4ed4b085e39",
);
}
Expand Down
30 changes: 15 additions & 15 deletions src/confidential/elip151.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,20 +29,12 @@ use crate::descriptor::{DescriptorSecretKey, SinglePriv};
use crate::extensions::{Extension, ParseableExt};
use crate::{Descriptor as OrdinaryDescriptor, DescriptorPublicKey, Error};

/// The SHA-256 initial midstate value for the [`Elip151Hash`].
const MIDSTATE_ELIP151: [u8; 32] = [
0x49, 0x81, 0x61, 0xd8, 0x52, 0x45, 0xf7, 0xaa, 0xd8, 0x24, 0x27, 0xb5, 0x64, 0x69, 0xe7, 0xd6,
0x98, 0x17, 0xeb, 0x0f, 0x27, 0x14, 0x6f, 0x4e, 0x7b, 0x95, 0xb3, 0x6e, 0x46, 0xc1, 0xb5, 0x61,
];

sha256t_hash_newtype!(
Elip151Hash,
Elip151Tag,
MIDSTATE_ELIP151,
64,
doc = "ELIP-151 Deterministic descriptor blinding keys",
forward
);
sha256t_hash_newtype! {
pub struct Elip151Tag = hash_str("ELIP-151 Deterministic descriptor blinding keys");
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🐞🐞🐞

sorry :(

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Lol, derp. But we really should have had tests to catch this!!

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

would it be feasible and makes sense to have a parameter of the macro requiring to specify the result of the hash for the empty string and the macro generates a test for it?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

oo I like that idea.

cc @tcharding what do you think?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't quite get it, what is the test hoping to catch? Is it hoped to be a regression test? (I don't see how one would get the hash of the empty string without first using the new tagged type.) Am I missing some context?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, you'd run the test once to get the correct string.

And then yes, it would be a regression test which would (hopefully) detect whenever anybody poked at the macro, or replaced the macro, or something, causing the hash to change.

Having said that, having such a test as part of the macro limits its value, since it's likely to go away when the macro is changed, which is exactly when we want it..

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We could definitely, and probably should already, have a single unit test in each repo that calls the macro and tests the empty hash - "don't trust verify" and all that.

Copy link
Contributor

@tcharding tcharding May 7, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I hear those lads that maintain hashes chop and change every week like a bunch of cowboys.

/// ELIP-151 Deterministic descriptor blinding keys
#[hash_newtype(forward)]
pub struct Elip151Hash(_);
}

impl Key {
pub fn from_elip151<T: Extension + ParseableExt>(
Expand Down Expand Up @@ -114,6 +106,13 @@ mod test {
use bitcoin::hashes::{sha256, HashEngine};
use std::str::FromStr;

/// The SHA-256 initial midstate value for the [`Elip151Hash`].
const MIDSTATE_ELIP151: [u8; 32] = [
0x49, 0x81, 0x61, 0xd8, 0x52, 0x45, 0xf7, 0xaa, 0xd8, 0x24, 0x27, 0xb5, 0x64, 0x69, 0xe7,
0xd6, 0x98, 0x17, 0xeb, 0x0f, 0x27, 0x14, 0x6f, 0x4e, 0x7b, 0x95, 0xb3, 0x6e, 0x46, 0xc1,
0xb5, 0x61,
];

#[test]
fn tagged_hash_elip151() {
// Check that cached midstate is computed correctly, code from rust-bitcoin
Expand Down Expand Up @@ -175,7 +174,8 @@ mod test {
] {
let conf_desc = confidential_descriptor(desc).unwrap();
let elip151_desc = add_checksum(&format!("ct(elip151,{})", desc));
let conf_desc_elip151 = ConfidentialDescriptor::<DescriptorPublicKey>::from_str(&elip151_desc).unwrap();
let conf_desc_elip151 =
ConfidentialDescriptor::<DescriptorPublicKey>::from_str(&elip151_desc).unwrap();
assert_eq!(conf_desc, conf_desc_elip151);

// Uncomment this and below to regenerate test vectors; to see the output, run
Expand Down
Loading