From 2415930e592803d4442d8d466213099e8da0b6ea Mon Sep 17 00:00:00 2001 From: Andrew Poelstra Date: Sun, 26 Oct 2025 15:14:42 +0000 Subject: [PATCH 1/2] simplicity: refactor taprootspendinfo and address generation The next commit will change the "unspendable key" from the sketchy one whose provenance we can't figure out, to the BIP 341 one which is provably unspendable. For now, refactor these functions so that we will be able to do more flexible things with these Taptrees than just generating addresses. --- src/hal_simplicity.rs | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/src/hal_simplicity.rs b/src/hal_simplicity.rs index 34b8e20..54095b5 100644 --- a/src/hal_simplicity.rs +++ b/src/hal_simplicity.rs @@ -3,6 +3,7 @@ use std::sync::Arc; +use elements::taproot::{TaprootBuilder, TaprootSpendInfo}; use simplicity::bitcoin::secp256k1; use simplicity::jet::Jet; use simplicity::{BitIter, CommitNode, DecodeError, ParseError, RedeemNode}; @@ -92,7 +93,7 @@ impl Program { } // Stolen from simplicity-webide -fn unspendable_internal_key() -> secp256k1::XOnlyPublicKey { +pub fn unspendable_internal_key() -> secp256k1::XOnlyPublicKey { secp256k1::XOnlyPublicKey::from_slice(&[ 0xf5, 0x91, 0x9f, 0xa6, 0x4c, 0xe4, 0x5f, 0x83, 0x06, 0x84, 0x90, 0x72, 0xb2, 0x6c, 0x1b, 0xfd, 0xd2, 0x93, 0x7e, 0x6b, 0x81, 0x77, 0x47, 0x96, 0xff, 0x37, 0x2b, 0xd1, 0xeb, 0x53, @@ -106,20 +107,26 @@ fn script_ver(cmr: simplicity::Cmr) -> (elements::Script, elements::taproot::Lea (script, simplicity::leaf_version()) } -fn taproot_spend_info(cmr: simplicity::Cmr) -> elements::taproot::TaprootSpendInfo { - let builder = elements::taproot::TaprootBuilder::new(); +/// Given a Simplicity CMR and an internal key, computes the [`TaprootSpendInfo`] +/// for a Taptree with this CMR as its single leaf. +pub fn taproot_spend_info( + internal_key: secp256k1::XOnlyPublicKey, + cmr: simplicity::Cmr, +) -> TaprootSpendInfo { + let builder = TaprootBuilder::new(); let (script, version) = script_ver(cmr); let builder = builder.add_leaf_with_ver(0, script, version).expect("tap tree should be valid"); - builder - .finalize(secp256k1::SECP256K1, unspendable_internal_key()) - .expect("tap tree should be valid") + builder.finalize(secp256k1::SECP256K1, internal_key).expect("tap tree should be valid") } +/// Given a Simplicity CMR, computes an unconfidential Elements address +/// (for the given network) corresponding to a Taptree with an unspendable +/// internal key and this CMR as its single leaf. pub fn elements_address( cmr: simplicity::Cmr, params: &'static elements::AddressParams, ) -> elements::Address { - let info = taproot_spend_info(cmr); + let info = taproot_spend_info(unspendable_internal_key(), cmr); let blinder = None; elements::Address::p2tr( secp256k1::SECP256K1, From 1d211d6d8f446e74941a96f5898478fcd83d0cf7 Mon Sep 17 00:00:00 2001 From: Andrew Poelstra Date: Sun, 26 Oct 2025 15:16:49 +0000 Subject: [PATCH 2/2] simplicity: switch 'unspendable key' to the one specified in BIP 341 Our current "unspendable key" comes from the Simplicity web IDE (from where it was copied to several other places, oops). However, this key seems to come from an old rust-simplicity unit test where it wasn't described as being "unspendable" and which we suspect that a private key was once known. --- src/hal_simplicity.rs | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/hal_simplicity.rs b/src/hal_simplicity.rs index 54095b5..6316a6d 100644 --- a/src/hal_simplicity.rs +++ b/src/hal_simplicity.rs @@ -92,12 +92,15 @@ impl Program { } } -// Stolen from simplicity-webide +/// The unspendable internal key specified in BIP-0341. +/// +/// This is a "nothing up my sleeve" (NUMS) point. See the text of BIP-0341 +/// for its derivation. +#[rustfmt::skip] // mangles byte vectors pub fn unspendable_internal_key() -> secp256k1::XOnlyPublicKey { secp256k1::XOnlyPublicKey::from_slice(&[ - 0xf5, 0x91, 0x9f, 0xa6, 0x4c, 0xe4, 0x5f, 0x83, 0x06, 0x84, 0x90, 0x72, 0xb2, 0x6c, 0x1b, - 0xfd, 0xd2, 0x93, 0x7e, 0x6b, 0x81, 0x77, 0x47, 0x96, 0xff, 0x37, 0x2b, 0xd1, 0xeb, 0x53, - 0x62, 0xd2, + 0x50, 0x92, 0x9b, 0x74, 0xc1, 0xa0, 0x49, 0x54, 0xb7, 0x8b, 0x4b, 0x60, 0x35, 0xe9, 0x7a, 0x5e, + 0x07, 0x8a, 0x5a, 0x0f, 0x28, 0xec, 0x96, 0xd5, 0x47, 0xbf, 0xee, 0x9a, 0xce, 0x80, 0x3a, 0xc0, ]) .expect("key should be valid") }