simplicityhl_core/
taproot_pubkey_gen.rs1use std::{fmt::Display, str::FromStr};
9
10use sha2::{Digest, Sha256};
11use simplicityhl::elements::{Address, schnorr::XOnlyPublicKey};
12use simplicityhl::simplicity::ToXOnlyPubkey;
13use simplicityhl::simplicity::bitcoin::PublicKey;
14use simplicityhl::simplicity::bitcoin::key::Parity;
15use simplicityhl::simplicity::elements::AddressParams;
16
17#[derive(Debug, Clone)]
19pub struct TaprootPubkeyGen {
20 pub seed: Vec<u8>,
21 pub pubkey: PublicKey,
22 pub address: Address,
23}
24
25impl TaprootPubkeyGen {
26 pub fn from<A>(
28 arguments: &A,
29 params: &'static AddressParams,
30 get_address: &impl Fn(&XOnlyPublicKey, &A, &'static AddressParams) -> anyhow::Result<Address>,
31 ) -> anyhow::Result<Self> {
32 let (not_existent_public_key, seed) = generate_public_key_without_private();
33
34 let address = get_address(
35 ¬_existent_public_key.to_x_only_pubkey(),
36 arguments,
37 params,
38 )?;
39
40 Ok(Self {
41 seed,
42 pubkey: not_existent_public_key,
43 address,
44 })
45 }
46
47 pub fn build_from_str<A>(
49 s: &str,
50 arguments: &A,
51 params: &'static AddressParams,
52 get_address: &impl Fn(&XOnlyPublicKey, &A, &'static AddressParams) -> anyhow::Result<Address>,
53 ) -> anyhow::Result<Self> {
54 let taproot_pubkey_gen = Self::from_str(s)?;
55
56 taproot_pubkey_gen.verify(arguments, params, get_address)?;
57
58 Ok(taproot_pubkey_gen)
59 }
60
61 pub fn verify<A>(
63 &self,
64 arguments: &A,
65 params: &'static AddressParams,
66 get_address: &impl Fn(&XOnlyPublicKey, &A, &'static AddressParams) -> anyhow::Result<Address>,
67 ) -> anyhow::Result<()> {
68 let rand_seed = self.seed.as_slice();
69
70 let mut hasher = Sha256::new();
71 sha2::digest::Update::update(&mut hasher, rand_seed);
72 sha2::digest::Update::update(&mut hasher, rand_seed);
73 sha2::digest::Update::update(&mut hasher, rand_seed);
74 let potential_pubkey: [u8; 32] = hasher.finalize().into();
75
76 let expected_pubkey: PublicKey = XOnlyPublicKey::from_slice(&potential_pubkey)?
77 .public_key(Parity::Even)
78 .into();
79 if expected_pubkey != self.pubkey {
80 return Err(anyhow::anyhow!("Invalid pubkey"));
81 }
82
83 if self.address != get_address(&self.pubkey.to_x_only_pubkey(), arguments, params)? {
84 return Err(anyhow::anyhow!("Invalid address"));
85 }
86
87 Ok(())
88 }
89
90 fn from_str(s: &str) -> anyhow::Result<Self> {
92 let parts = s.split(':').collect::<Vec<&str>>();
93
94 if parts.len() != 3 {
95 return Err(anyhow::anyhow!("Invalid taproot pubkey gen string"));
96 }
97
98 Ok(Self {
99 seed: hex::decode(parts[0])?,
100 pubkey: PublicKey::from_str(parts[1])?,
101 address: Address::from_str(parts[2])?,
102 })
103 }
104}
105
106impl Display for TaprootPubkeyGen {
107 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
108 write!(
109 f,
110 "{}:{}:{}",
111 hex::encode(&self.seed),
112 self.pubkey,
113 self.address
114 )
115 }
116}
117
118fn try_generate_public_key_without_private() -> anyhow::Result<(PublicKey, Vec<u8>)> {
120 let rand_seed: [u8; 32] = get_random_seed();
121
122 let mut hasher = Sha256::new();
123 sha2::digest::Update::update(&mut hasher, &rand_seed);
124 sha2::digest::Update::update(&mut hasher, &rand_seed);
125 sha2::digest::Update::update(&mut hasher, &rand_seed);
126 let potential_pubkey: [u8; 32] = hasher.finalize().into();
127
128 Ok((
129 XOnlyPublicKey::from_slice(&potential_pubkey)?
130 .public_key(Parity::Even)
131 .into(),
132 rand_seed.to_vec(),
133 ))
134}
135
136pub fn generate_public_key_without_private() -> (PublicKey, Vec<u8>) {
138 let not_existent_public_key;
139 loop {
140 if let Ok(public_key) = try_generate_public_key_without_private() {
141 not_existent_public_key = public_key;
142 break;
143 }
144 }
145
146 not_existent_public_key
147}
148
149pub fn get_random_seed() -> [u8; 32] {
151 ring::rand::generate(&ring::rand::SystemRandom::new())
152 .unwrap()
153 .expose()
154}