elements_miniscript/confidential/
bare.rs1use bitcoin::hashes::{sha256t_hash_newtype, Hash};
18use elements::encode::Encodable;
19use elements::secp256k1_zkp;
20
21use crate::ToPublicKey;
22
23sha256t_hash_newtype! {
24 pub struct TapTweakTag = hash_str("CT-Blinding-Key/1.0");
25 #[hash_newtype(forward)]
27 pub struct TapTweakHash(_);
28}
29
30pub fn tweak_key<'a, Pk, V>(
32 secp: &secp256k1_zkp::Secp256k1<V>,
33 spk: &elements::Script,
34 pk: &Pk,
35) -> secp256k1_zkp::PublicKey
36where
37 Pk: ToPublicKey + 'a,
38 V: secp256k1_zkp::Verification,
39{
40 let mut eng = TapTweakHash::engine();
41 pk.to_public_key()
42 .write_into(&mut eng)
43 .expect("engines don't error");
44 spk.consensus_encode(&mut eng).expect("engines don't error");
45 let hash_bytes = TapTweakHash::from_engine(eng).to_byte_array();
46 let hash_scalar = secp256k1_zkp::Scalar::from_be_bytes(hash_bytes).expect("bytes from hash");
47 pk.to_public_key()
48 .inner
49 .add_exp_tweak(secp, &hash_scalar)
50 .unwrap()
51}
52
53pub fn tweak_private_key<V>(
55 secp: &secp256k1_zkp::Secp256k1<V>,
56 spk: &elements::Script,
57 sk: &secp256k1_zkp::SecretKey,
58) -> secp256k1_zkp::SecretKey
59where
60 V: secp256k1_zkp::Signing,
61{
62 let mut eng = TapTweakHash::engine();
63 bitcoin::PublicKey::new(sk.public_key(secp))
64 .write_into(&mut eng)
65 .expect("engines don't error");
66 spk.consensus_encode(&mut eng).expect("engines don't error");
67 let hash_bytes = TapTweakHash::from_engine(eng).to_byte_array();
68 let hash_scalar = secp256k1_zkp::Scalar::from_be_bytes(hash_bytes).expect("bytes from hash");
69 sk.add_tweak(&hash_scalar).unwrap()
70}
71
72#[cfg(test)]
73mod tests {
74 use bitcoin::hashes::sha256t::Tag;
75 use bitcoin::hashes::{sha256, HashEngine};
76
77 use super::*;
78
79 const MIDSTATE_HASH_TO_PRIVATE_HASH: [u8; 32] = [
80 0x2f, 0x85, 0x61, 0xec, 0x30, 0x88, 0xad, 0xa9, 0x5a, 0xe7, 0x43, 0xcd, 0x3c, 0x5f, 0x59,
81 0x7d, 0xc0, 0x4b, 0xd0, 0x7f, 0x06, 0x5f, 0x1c, 0x06, 0x47, 0x89, 0x36, 0x63, 0xf3, 0x92,
82 0x6e, 0x65,
83 ];
84
85 #[test]
86 fn tagged_hash() {
87 let mut engine = sha256::Hash::engine();
91 let tag_hash = sha256::Hash::hash(b"CT-Blinding-Key/1.0");
92 engine.input(&tag_hash[..]);
93 engine.input(&tag_hash[..]);
94 assert_eq!(
95 MIDSTATE_HASH_TO_PRIVATE_HASH,
96 engine.midstate().to_byte_array()
97 );
98
99 assert_eq!(
101 TapTweakHash::from_engine(TapTweakTag::engine()).to_string(),
102 "d12a140aca856fbb917b931f263c42f064608985e2ce17ae5157daa17c55e8d9",
103 );
104 assert_eq!(
105 TapTweakHash::hash(&[]).to_string(),
106 "d12a140aca856fbb917b931f263c42f064608985e2ce17ae5157daa17c55e8d9",
107 );
108
109 let data: Vec<u8> = (0..80).collect();
111 assert_eq!(
112 TapTweakHash::hash(&data).to_string(),
113 "e1e52419a2934d278c50e29608969d2f23c1bd1243a09bfc8026d4ed4b085e39",
114 );
115 }
116
117 #[test]
118 fn tweak() {
119 let secp = secp256k1_zkp::Secp256k1::new();
121 let sk = secp256k1_zkp::SecretKey::from_slice(&[1u8; 32]).unwrap();
122 let pk = sk.public_key(&secp);
123 let spk = elements::Script::default();
124 let tweaked_pk = tweak_key(&secp, &spk, &pk);
125 let tweaked_sk = tweak_private_key(&secp, &spk, &sk);
126 assert_eq!(tweaked_pk, tweaked_sk.public_key(&secp));
127 }
128}