use crate::{LwkError, Mnemonic, Network, Pset, WolletDescriptor};
use std::sync::Arc;
#[derive(uniffi::Enum)]
pub enum Singlesig {
Wpkh,
ShWpkh,
}
impl From<Singlesig> for lwk_common::Singlesig {
fn from(singlesig: Singlesig) -> Self {
match singlesig {
Singlesig::Wpkh => lwk_common::Singlesig::Wpkh,
Singlesig::ShWpkh => lwk_common::Singlesig::ShWpkh,
}
}
}
#[derive(uniffi::Enum)]
pub enum DescriptorBlindingKey {
Slip77,
Slip77Rand,
Elip151,
}
impl From<DescriptorBlindingKey> for lwk_common::DescriptorBlindingKey {
fn from(blinding_key: DescriptorBlindingKey) -> Self {
match blinding_key {
DescriptorBlindingKey::Slip77 => lwk_common::DescriptorBlindingKey::Slip77,
DescriptorBlindingKey::Slip77Rand => lwk_common::DescriptorBlindingKey::Slip77Rand,
DescriptorBlindingKey::Elip151 => lwk_common::DescriptorBlindingKey::Elip151,
}
}
}
#[derive(uniffi::Object)]
pub struct Bip {
inner: lwk_common::Bip,
}
#[uniffi::export]
impl Bip {
#[uniffi::constructor]
pub fn new_bip49() -> Self {
Self {
inner: lwk_common::Bip::Bip49,
}
}
#[uniffi::constructor]
pub fn new_bip84() -> Self {
Self {
inner: lwk_common::Bip::Bip84,
}
}
#[uniffi::constructor]
pub fn new_bip87() -> Self {
Self {
inner: lwk_common::Bip::Bip87,
}
}
}
#[derive(uniffi::Object)]
pub struct Signer {
pub(crate) inner: lwk_signer::SwSigner,
}
#[uniffi::export]
impl Signer {
#[uniffi::constructor]
pub fn new(mnemonic: &Mnemonic, network: &Network) -> Result<Arc<Self>, LwkError> {
let inner = lwk_signer::SwSigner::new(&mnemonic.to_string(), network.is_mainnet())?;
Ok(Arc::new(Self { inner }))
}
#[uniffi::constructor]
pub fn random(network: &Network) -> Result<Arc<Self>, LwkError> {
let (inner, _mnemonic) = lwk_signer::SwSigner::random(network.is_mainnet())?;
Ok(Arc::new(Self { inner }))
}
pub fn sign(&self, pset: &Pset) -> Result<Arc<Pset>, LwkError> {
let mut pset = pset.inner();
lwk_common::Signer::sign(&self.inner, &mut pset)?;
Ok(Arc::new(pset.into()))
}
pub fn wpkh_slip77_descriptor(&self) -> Result<Arc<WolletDescriptor>, LwkError> {
self.singlesig_desc(Singlesig::Wpkh, DescriptorBlindingKey::Slip77)
}
pub fn singlesig_desc(
&self,
script_variant: Singlesig,
blinding_variant: DescriptorBlindingKey,
) -> Result<Arc<WolletDescriptor>, LwkError> {
let desc_str = lwk_common::singlesig_desc(
&self.inner,
script_variant.into(),
blinding_variant.into(),
)?;
WolletDescriptor::new(&desc_str)
}
pub fn keyorigin_xpub(&self, bip: &Bip) -> Result<String, LwkError> {
let is_mainnet = lwk_common::Signer::is_mainnet(&self.inner)?;
Ok(lwk_common::Signer::keyorigin_xpub(
&self.inner,
bip.inner,
is_mainnet,
)?)
}
pub fn fingerprint(&self) -> Result<String, LwkError> {
Ok(self.inner.fingerprint().to_string())
}
pub fn mnemonic(&self) -> Result<Arc<Mnemonic>, LwkError> {
Ok(Arc::new(self.inner.mnemonic().map(Into::into).ok_or_else(
|| LwkError::Generic {
msg: "Mnemonic not available".to_string(),
},
)?))
}
pub fn derive_bip85_mnemonic(
&self,
index: u32,
word_count: u32,
) -> Result<Arc<Mnemonic>, LwkError> {
let derived_mnemonic = self.inner.derive_bip85_mnemonic(index, word_count)?;
Ok(Arc::new(derived_mnemonic.into()))
}
}
#[cfg(test)]
mod tests {
use lwk_wollet::ElementsNetwork;
use crate::{Bip, Mnemonic, Pset, Signer};
#[test]
fn signer() {
let mnemonic_str = lwk_test_util::TEST_MNEMONIC;
let mnemonic = Mnemonic::new(mnemonic_str).unwrap();
let network: crate::Network = ElementsNetwork::default_regtest().into();
let signer = Signer::new(&mnemonic, &network).unwrap();
let pset_string =
include_str!("../../lwk_jade/test_data/pset_to_be_signed.base64").to_string();
let pset = Pset::new(&pset_string).unwrap();
let signed_pset = signer.sign(&pset).unwrap();
assert_ne!(pset, signed_pset);
let xpub = signer.keyorigin_xpub(&Bip::new_bip49()).unwrap();
let expected = "[73c5da0a/49h/1h/0h]tpubDD7tXK8KeQ3YY83yWq755fHY2JW8Ha8Q765tknUM5rSvjPcGWfUppDFMpQ1ScziKfW3ZNtZvAD7M3u7bSs7HofjTD3KP3YxPK7X6hwV8Rk2";
assert_eq!(xpub, expected);
let xpub = signer.keyorigin_xpub(&Bip::new_bip84()).unwrap();
let expected = "[73c5da0a/84h/1h/0h]tpubDC8msFGeGuwnKG9Upg7DM2b4DaRqg3CUZa5g8v2SRQ6K4NSkxUgd7HsL2XVWbVm39yBA4LAxysQAm397zwQSQoQgewGiYZqrA9DsP4zbQ1M";
assert_eq!(xpub, expected);
let xpub = signer.keyorigin_xpub(&Bip::new_bip87()).unwrap();
let expected = "[73c5da0a/87h/1h/0h]tpubDCChhoz5Qdrkn7Z7KXawq6Ad6r3A4MUkCoVTqeWxfTkA6bHNJ3CHUEtALQdkNeixNz4446PcAmw4WKcj3mV2vb29H7sg9EPzbyCU1y2merw";
assert_eq!(xpub, expected);
assert_eq!(signer.mnemonic().unwrap(), mnemonic);
assert_eq!(signer.fingerprint().unwrap(), xpub[1..9])
}
#[test]
fn test_bip85_derivation() {
let mnemonic_str = lwk_test_util::TEST_MNEMONIC;
let mnemonic = Mnemonic::new(mnemonic_str).unwrap();
let network: crate::Network = ElementsNetwork::default_regtest().into();
let signer = Signer::new(&mnemonic, &network).unwrap();
let derived_mnemonic_12 = signer.derive_bip85_mnemonic(0, 12).unwrap();
assert_eq!(derived_mnemonic_12.word_count(), 12);
let expected_mnemonic_12 =
"prosper short ramp prepare exchange stove life snack client enough purpose fold";
assert_eq!(derived_mnemonic_12.to_string(), expected_mnemonic_12);
let derived_mnemonic_24 = signer.derive_bip85_mnemonic(0, 24).unwrap();
assert_eq!(derived_mnemonic_24.word_count(), 24);
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";
assert_eq!(derived_mnemonic_24.to_string(), expected_mnemonic_24);
let derived_mnemonic_1 = signer.derive_bip85_mnemonic(1, 12).unwrap();
assert_ne!(
derived_mnemonic_12.to_string(),
derived_mnemonic_1.to_string()
);
let derived_mnemonic_0_again = signer.derive_bip85_mnemonic(0, 12).unwrap();
assert_eq!(
derived_mnemonic_12.to_string(),
derived_mnemonic_0_again.to_string()
);
}
}