diff --git a/bindings/ergo-lib-c-core/src/ext_pub_key.rs b/bindings/ergo-lib-c-core/src/ext_pub_key.rs new file mode 100644 index 000000000..ff7c2bf60 --- /dev/null +++ b/bindings/ergo-lib-c-core/src/ext_pub_key.rs @@ -0,0 +1,87 @@ +//! Extended Public Key functionality + +use derive_more::{From, Into}; + +use ergo_lib::ergotree_ir::chain::address::Address as InnerAddress; +use ergo_lib::wallet::derivation_path::ChildIndexNormal; +use ergo_lib::wallet::ext_pub_key::{ExtPubKey as InnerExtPubKey, PubKeyBytes}; +use ergo_lib::ArrLength; + +use crate::address::{Address, AddressPtr}; +use crate::derivation_path::ConstDerivationPathPtr; +use crate::util::{const_ptr_as_ref, mut_ptr_as_mut}; +use crate::Error; + +#[derive(From, Into)] +pub struct ExtPubKey(pub InnerExtPubKey); +pub type ExtPubKeyPtr = *mut ExtPubKey; +pub type ConstExtPubKeyPtr = *const ExtPubKey; + +/// Create ExtPubKey from public key bytes, chain code and derivation path +pub unsafe fn ext_pub_key_new( + public_key_bytes: *const u8, + chain_code: *const u8, + derivation_path_ptr: ConstDerivationPathPtr, + ext_pub_key_out: *mut ExtPubKeyPtr, +) -> Result<(), Error> { + let ext_pub_key_out = mut_ptr_as_mut(ext_pub_key_out, "ext_pub_key_out")?; + let derivation_path = const_ptr_as_ref(derivation_path_ptr, "derivation_path_ptr")?; + let secret_key_bytes = std::slice::from_raw_parts(public_key_bytes, PubKeyBytes::LEN); + let chain_code = + std::slice::from_raw_parts(chain_code, ergo_lib::wallet::ext_pub_key::ChainCode::LEN); + let key = InnerExtPubKey::new( + secret_key_bytes.try_into().map_err(Error::misc)?, + chain_code.try_into().map_err(Error::misc)?, + derivation_path.0.clone(), + ) + .map_err(Error::misc)?; + *ext_pub_key_out = Box::into_raw(Box::new(ExtPubKey(key))); + Ok(()) +} + +/// Derive a new extended public key from the provided index +/// The index is in the form of soft or hardened indices +/// For example: 4 or 4' respectively +pub unsafe fn ext_pub_key_child( + derive_from_key_ptr: ConstExtPubKeyPtr, + child_index: u32, + ext_pub_key_out: *mut ExtPubKeyPtr, +) -> Result<(), Error> { + let ext_pub_key = const_ptr_as_ref(derive_from_key_ptr, "derive_from_key_ptr")?; + let ext_pub_key_out = mut_ptr_as_mut(ext_pub_key_out, "ext_pub_key_out")?; + let index = ChildIndexNormal::normal(child_index).map_err(Error::misc)?; + let key = ext_pub_key.0.child(index); + *ext_pub_key_out = Box::into_raw(Box::new(ExtPubKey(key))); + Ok(()) +} + +/// Derive a new extended public key from the derivation path +pub unsafe fn ext_pub_key_derive( + ext_pub_key_ptr: ConstExtPubKeyPtr, + derivation_path_ptr: ConstDerivationPathPtr, + ext_pub_key_out: *mut ExtPubKeyPtr, +) -> Result<(), Error> { + let ext_pub_key_ptr = const_ptr_as_ref(ext_pub_key_ptr, "ext_pub_key_ptr")?; + let derivation_path = const_ptr_as_ref(derivation_path_ptr, "derivation_path_ptr")?; + let ext_pub_key_out = mut_ptr_as_mut(ext_pub_key_out, "ext_pub_key_out")?; + *ext_pub_key_out = Box::into_raw(Box::new(ExtPubKey( + ext_pub_key_ptr + .0 + .derive(derivation_path.0.clone()) + .map_err(Error::misc)?, + ))); + Ok(()) +} + +/// Get address for extended public key +pub unsafe fn ext_pub_key_address( + ext_pub_key_ptr: ConstExtPubKeyPtr, + address_out: *mut AddressPtr, +) -> Result<(), Error> { + let ext_pub_key_ptr = const_ptr_as_ref(ext_pub_key_ptr, "ext_pub_key_ptr")?; + let address_out = mut_ptr_as_mut(address_out, "address_out")?; + let ext_pub_key: InnerExtPubKey = ext_pub_key_ptr.0.clone(); + let address = InnerAddress::from(ext_pub_key); + *address_out = Box::into_raw(Box::new(Address(address))); + Ok(()) +} diff --git a/bindings/ergo-lib-c-core/src/lib.rs b/bindings/ergo-lib-c-core/src/lib.rs index ce82a5168..f268d5860 100644 --- a/bindings/ergo-lib-c-core/src/lib.rs +++ b/bindings/ergo-lib-c-core/src/lib.rs @@ -40,5 +40,6 @@ pub mod wallet; pub use crate::error::*; pub mod derivation_path; mod error; +pub mod ext_pub_key; #[cfg(feature = "rest")] pub mod rest; diff --git a/bindings/ergo-lib-c/src/ext_pub_key.rs b/bindings/ergo-lib-c/src/ext_pub_key.rs new file mode 100644 index 000000000..d90452079 --- /dev/null +++ b/bindings/ergo-lib-c/src/ext_pub_key.rs @@ -0,0 +1,67 @@ +//! Extended Public Key functionality + +use crate::{delete_ptr, ErrorPtr}; +use ergo_lib_c_core::address::AddressPtr; +use ergo_lib_c_core::derivation_path::ConstDerivationPathPtr; +use ergo_lib_c_core::ext_pub_key::{ + ext_pub_key_address, ext_pub_key_child, ext_pub_key_derive, ext_pub_key_new, ConstExtPubKeyPtr, + ExtPubKeyPtr, +}; +use ergo_lib_c_core::Error; + +/// Create ExtPubKey from public key bytes, chain code and derivation path +#[no_mangle] +pub unsafe extern "C" fn ergo_lib_ext_pub_key_new( + public_key_bytes: *const u8, + chain_code_ptr: *const u8, + derivation_path_ptr: ConstDerivationPathPtr, + ext_pub_key_out: *mut ExtPubKeyPtr, +) -> ErrorPtr { + let res = ext_pub_key_new( + public_key_bytes, + chain_code_ptr, + derivation_path_ptr, + ext_pub_key_out, + ); + Error::c_api_from(res) +} + +/// Derive a new extended public key from the provided index +/// The index is in the form of soft or hardened indices +/// For example: 4 or 4' respectively +#[no_mangle] +pub unsafe extern "C" fn ergo_lib_ext_pub_key_child( + derive_from_key_ptr: ConstExtPubKeyPtr, + child_index: u32, + ext_pub_key_out: *mut ExtPubKeyPtr, +) -> ErrorPtr { + let res = ext_pub_key_child(derive_from_key_ptr, child_index, ext_pub_key_out); + Error::c_api_from(res) +} + +/// Derive a new extended public key from the derivation path +#[no_mangle] +pub unsafe extern "C" fn ergo_lib_ext_pub_key_derive( + ext_pub_key_ptr: ConstExtPubKeyPtr, + derivation_path_ptr: ConstDerivationPathPtr, + ext_pub_key_out: *mut ExtPubKeyPtr, +) -> ErrorPtr { + let res = ext_pub_key_derive(ext_pub_key_ptr, derivation_path_ptr, ext_pub_key_out); + Error::c_api_from(res) +} + +/// Get address for extended public key +#[no_mangle] +pub unsafe extern "C" fn ergo_lib_ext_pub_key_address( + ext_pub_key_ptr: ConstExtPubKeyPtr, + address_out: *mut AddressPtr, +) { + #[allow(clippy::unwrap_used)] + ext_pub_key_address(ext_pub_key_ptr, address_out).unwrap() +} + +/// Drop `ExtPubKey` +#[no_mangle] +pub extern "C" fn ergo_lib_ext_pub_key_delete(ptr: ExtPubKeyPtr) { + unsafe { delete_ptr(ptr) } +} diff --git a/bindings/ergo-lib-c/src/lib.rs b/bindings/ergo-lib-c/src/lib.rs index 4ce7dd2fd..e500bb330 100644 --- a/bindings/ergo-lib-c/src/lib.rs +++ b/bindings/ergo-lib-c/src/lib.rs @@ -39,6 +39,7 @@ mod reduced; mod rest; mod derivation_path; +mod ext_pub_key; mod secret_key; mod token; mod transaction;