1use crate::{LwkError, Mnemonic, Network, Pset, WolletDescriptor};
2use std::sync::Arc;
3
4#[derive(uniffi::Enum)]
5pub enum Singlesig {
6 Wpkh,
7 ShWpkh,
8}
9
10impl From<Singlesig> for lwk_common::Singlesig {
11 fn from(singlesig: Singlesig) -> Self {
12 match singlesig {
13 Singlesig::Wpkh => lwk_common::Singlesig::Wpkh,
14 Singlesig::ShWpkh => lwk_common::Singlesig::ShWpkh,
15 }
16 }
17}
18
19#[derive(uniffi::Enum)]
20pub enum DescriptorBlindingKey {
21 Slip77,
22 Slip77Rand,
23 Elip151,
24}
25
26impl From<DescriptorBlindingKey> for lwk_common::DescriptorBlindingKey {
27 fn from(blinding_key: DescriptorBlindingKey) -> Self {
28 match blinding_key {
29 DescriptorBlindingKey::Slip77 => lwk_common::DescriptorBlindingKey::Slip77,
30 DescriptorBlindingKey::Slip77Rand => lwk_common::DescriptorBlindingKey::Slip77Rand,
31 DescriptorBlindingKey::Elip151 => lwk_common::DescriptorBlindingKey::Elip151,
32 }
33 }
34}
35
36#[derive(uniffi::Object)]
38pub struct Bip {
39 inner: lwk_common::Bip,
40}
41
42#[uniffi::export]
43impl Bip {
44 #[uniffi::constructor]
46 pub fn new_bip49() -> Self {
47 Self {
48 inner: lwk_common::Bip::Bip49,
49 }
50 }
51
52 #[uniffi::constructor]
54 pub fn new_bip84() -> Self {
55 Self {
56 inner: lwk_common::Bip::Bip84,
57 }
58 }
59
60 #[uniffi::constructor]
62 pub fn new_bip87() -> Self {
63 Self {
64 inner: lwk_common::Bip::Bip87,
65 }
66 }
67}
68
69#[derive(uniffi::Object)]
71pub struct Signer {
72 pub(crate) inner: lwk_signer::SwSigner,
73}
74
75#[uniffi::export]
76impl Signer {
77 #[uniffi::constructor]
79 pub fn new(mnemonic: &Mnemonic, network: &Network) -> Result<Arc<Self>, LwkError> {
80 let inner = lwk_signer::SwSigner::new(&mnemonic.to_string(), network.is_mainnet())?;
81 Ok(Arc::new(Self { inner }))
82 }
83
84 #[uniffi::constructor]
86 pub fn random(network: &Network) -> Result<Arc<Self>, LwkError> {
87 let (inner, _mnemonic) = lwk_signer::SwSigner::random(network.is_mainnet())?;
88 Ok(Arc::new(Self { inner }))
89 }
90
91 pub fn sign(&self, pset: &Pset) -> Result<Arc<Pset>, LwkError> {
96 let mut pset = pset.inner();
97 lwk_common::Signer::sign(&self.inner, &mut pset)?;
98 Ok(Arc::new(pset.into()))
99 }
100
101 pub fn wpkh_slip77_descriptor(&self) -> Result<Arc<WolletDescriptor>, LwkError> {
103 self.singlesig_desc(Singlesig::Wpkh, DescriptorBlindingKey::Slip77)
104 }
105
106 pub fn singlesig_desc(
108 &self,
109 script_variant: Singlesig,
110 blinding_variant: DescriptorBlindingKey,
111 ) -> Result<Arc<WolletDescriptor>, LwkError> {
112 let desc_str = lwk_common::singlesig_desc(
113 &self.inner,
114 script_variant.into(),
115 blinding_variant.into(),
116 )?;
117 WolletDescriptor::new(&desc_str)
118 }
119
120 pub fn keyorigin_xpub(&self, bip: &Bip) -> Result<String, LwkError> {
122 let is_mainnet = lwk_common::Signer::is_mainnet(&self.inner)?;
123 Ok(lwk_common::Signer::keyorigin_xpub(
124 &self.inner,
125 bip.inner,
126 is_mainnet,
127 )?)
128 }
129
130 pub fn fingerprint(&self) -> Result<String, LwkError> {
132 Ok(self.inner.fingerprint().to_string())
133 }
134
135 pub fn mnemonic(&self) -> Result<Arc<Mnemonic>, LwkError> {
137 Ok(Arc::new(self.inner.mnemonic().map(Into::into).ok_or_else(
138 || LwkError::Generic {
139 msg: "Mnemonic not available".to_string(),
140 },
141 )?))
142 }
143
144 pub fn derive_bip85_mnemonic(
160 &self,
161 index: u32,
162 word_count: u32,
163 ) -> Result<Arc<Mnemonic>, LwkError> {
164 let derived_mnemonic = self.inner.derive_bip85_mnemonic(index, word_count)?;
165 Ok(Arc::new(derived_mnemonic.into()))
166 }
167}
168
169#[cfg(test)]
170mod tests {
171 use lwk_wollet::ElementsNetwork;
172
173 use crate::{Bip, Mnemonic, Pset, Signer};
174
175 #[test]
176 fn signer() {
177 let mnemonic_str = lwk_test_util::TEST_MNEMONIC;
178 let mnemonic = Mnemonic::new(mnemonic_str).unwrap();
179 let network: crate::Network = ElementsNetwork::default_regtest().into();
180
181 let signer = Signer::new(&mnemonic, &network).unwrap();
182
183 let pset_string =
184 include_str!("../../lwk_jade/test_data/pset_to_be_signed.base64").to_string();
185 let pset = Pset::new(&pset_string).unwrap();
186
187 let signed_pset = signer.sign(&pset).unwrap();
188
189 assert_ne!(pset, signed_pset);
190
191 let xpub = signer.keyorigin_xpub(&Bip::new_bip49()).unwrap();
192 let expected = "[73c5da0a/49h/1h/0h]tpubDD7tXK8KeQ3YY83yWq755fHY2JW8Ha8Q765tknUM5rSvjPcGWfUppDFMpQ1ScziKfW3ZNtZvAD7M3u7bSs7HofjTD3KP3YxPK7X6hwV8Rk2";
193 assert_eq!(xpub, expected);
194
195 let xpub = signer.keyorigin_xpub(&Bip::new_bip84()).unwrap();
196 let expected = "[73c5da0a/84h/1h/0h]tpubDC8msFGeGuwnKG9Upg7DM2b4DaRqg3CUZa5g8v2SRQ6K4NSkxUgd7HsL2XVWbVm39yBA4LAxysQAm397zwQSQoQgewGiYZqrA9DsP4zbQ1M";
197 assert_eq!(xpub, expected);
198
199 let xpub = signer.keyorigin_xpub(&Bip::new_bip87()).unwrap();
200 let expected = "[73c5da0a/87h/1h/0h]tpubDCChhoz5Qdrkn7Z7KXawq6Ad6r3A4MUkCoVTqeWxfTkA6bHNJ3CHUEtALQdkNeixNz4446PcAmw4WKcj3mV2vb29H7sg9EPzbyCU1y2merw";
201 assert_eq!(xpub, expected);
202
203 assert_eq!(signer.mnemonic().unwrap(), mnemonic);
204
205 assert_eq!(signer.fingerprint().unwrap(), xpub[1..9])
206 }
207
208 #[test]
209 fn test_bip85_derivation() {
210 let mnemonic_str = lwk_test_util::TEST_MNEMONIC;
211 let mnemonic = Mnemonic::new(mnemonic_str).unwrap();
212 let network: crate::Network = ElementsNetwork::default_regtest().into();
213
214 let signer = Signer::new(&mnemonic, &network).unwrap();
215
216 let derived_mnemonic_12 = signer.derive_bip85_mnemonic(0, 12).unwrap();
218 assert_eq!(derived_mnemonic_12.word_count(), 12);
219 let expected_mnemonic_12 =
220 "prosper short ramp prepare exchange stove life snack client enough purpose fold";
221 assert_eq!(derived_mnemonic_12.to_string(), expected_mnemonic_12);
222
223 let derived_mnemonic_24 = signer.derive_bip85_mnemonic(0, 24).unwrap();
225 assert_eq!(derived_mnemonic_24.word_count(), 24);
226 let expected_mnemonic_24 = "stick exact spice sock filter ginger museum horse kit multiply manual wear grief demand derive alert quiz fault december lava picture immune decade jaguar";
227 assert_eq!(derived_mnemonic_24.to_string(), expected_mnemonic_24);
228
229 let derived_mnemonic_1 = signer.derive_bip85_mnemonic(1, 12).unwrap();
231 assert_ne!(
232 derived_mnemonic_12.to_string(),
233 derived_mnemonic_1.to_string()
234 );
235
236 let derived_mnemonic_0_again = signer.derive_bip85_mnemonic(0, 12).unwrap();
238 assert_eq!(
239 derived_mnemonic_12.to_string(),
240 derived_mnemonic_0_again.to_string()
241 );
242 }
243}