Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Misc rustdoc updates #405

Merged
merged 1 commit into from
Jan 23, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 0 additions & 14 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -175,20 +175,6 @@ To build WASM on MacOS you need to install `llvm` from homebrew (at the time of

<details>

<summary>
React Native
</summary>

```bash
cd rusty-kaspa
cd wasm
./build-react-native
```

</details>

<details>

<summary>
ES6
</summary>
Expand Down
1 change: 1 addition & 0 deletions crypto/addresses/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ impl From<workflow_wasm::error::Error> for AddressError {
}
}

/// Address prefix identifying the network type this address belongs to (such as `kaspa`, `kaspatest`, `kaspasim`, `kaspadev`).
#[derive(
PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Debug, Hash, Serialize, Deserialize, BorshSerialize, BorshDeserialize, BorshSchema,
)]
Expand Down
1 change: 1 addition & 0 deletions wallet/bip32/src/mnemonic/phrase.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ const PBKDF2_ROUNDS: u32 = 2048;
pub type Entropy32 = [u8; KEY_SIZE];
pub type Entropy16 = [u8; 16];

/// Word count for a BIP39 mnemonic phrase. Identifies mnemonic as 12 or 24 word variants.
#[derive(Default, Clone, Copy, Debug, Serialize, Deserialize, BorshSerialize, BorshDeserialize, BorshSchema)]
#[serde(rename_all = "kebab-case")]
pub enum WordCount {
Expand Down
14 changes: 11 additions & 3 deletions wallet/core/src/account/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,14 @@ use kaspa_bip32::{ChildNumber, ExtendedPrivateKey, PrivateKey};
use kaspa_consensus_wasm::UtxoEntryReference;
use workflow_core::abortable::Abortable;

pub const DEFAULT_AMOUNT_PADDING: usize = 19;

/// Notification callback type used by [`Account::sweep`] and [`Account::send`].
/// Allows tracking in-flight transactions during transaction generation.
pub type GenerationNotifier = Arc<dyn Fn(&PendingTransaction) + Send + Sync>;
/// Scan notification callback type used by [`Account::derivation_scan`].
/// Provides derivation discovery scan progress information.
pub type ScanNotifier = Arc<dyn Fn(usize, usize, u64, Option<TransactionId>) + Send + Sync>;

/// General-purpose wrapper around [`AccountSettings`] (managed by [`Inner`]).
pub struct Context {
pub settings: AccountSettings,
}
Expand All @@ -43,6 +46,7 @@ impl Context {
}
}

/// Account `Inner` struct used by most account types.
pub struct Inner {
context: Mutex<Context>,
id: AccountId,
Expand Down Expand Up @@ -72,6 +76,8 @@ impl Inner {
}
}

/// Generic wallet [`Account`] trait implementation used
/// by different types of accounts.
#[async_trait]
pub trait Account: AnySync + Send + Sync + 'static {
fn inner(&self) -> &Arc<Inner>;
Expand Down Expand Up @@ -421,6 +427,7 @@ pub trait Account: AnySync + Send + Sync + 'static {

downcast_sync!(dyn Account);

/// Account trait used by legacy account types (BIP32 account types with the `'972` derivation path).
#[async_trait]
pub trait AsLegacyAccount: Account {
async fn create_private_context(
Expand All @@ -433,6 +440,7 @@ pub trait AsLegacyAccount: Account {
async fn clear_private_context(&self) -> Result<()>;
}

/// Account trait used by derivation capable account types (BIP32, MultiSig, etc.)
#[async_trait]
pub trait DerivationCapableAccount: Account {
fn derivation(&self) -> Arc<dyn AddressDerivationManagerTrait>;
Expand Down Expand Up @@ -611,7 +619,7 @@ pub trait DerivationCapableAccount: Account {

downcast_sync!(dyn DerivationCapableAccount);

pub fn create_private_keys<'l>(
pub(crate) fn create_private_keys<'l>(
account_kind: &AccountKind,
cosigner_index: u32,
account_index: u64,
Expand Down
10 changes: 10 additions & 0 deletions wallet/core/src/api/transport.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,22 +20,29 @@ use async_trait::async_trait;
use borsh::{BorshDeserialize, BorshSerialize};
use kaspa_wallet_macros::{build_wallet_client_transport_interface, build_wallet_server_transport_interface};

/// Transport interface supporting Borsh serialization
#[async_trait]
pub trait BorshTransport: Send + Sync {
async fn call(&self, op: u64, request: Vec<u8>) -> Result<Vec<u8>>;
}

/// Transport interface supporting Serde JSON serialization
#[async_trait]
pub trait SerdeTransport: Send + Sync {
async fn call(&self, op: &str, request: &str) -> Result<String>;
}

/// Transport interface enum supporting either Borsh and Serde JSON serialization
#[derive(Clone)]
pub enum Transport {
Borsh(Arc<dyn BorshTransport>),
Serde(Arc<dyn SerdeTransport>),
}

/// [`WalletServer`] is a server-side transport interface that declares
/// API methods that can be invoked via Borsh or Serde messages containing
/// serializations created using the [`Transport`] interface. The [`WalletServer`]
/// is a counter-part to [`WalletClient`].
pub struct WalletServer {
pub wallet_api: Arc<dyn WalletApi>,
}
Expand Down Expand Up @@ -90,6 +97,9 @@ impl WalletServer {
]}
}

/// [`WalletClient`] is a client-side transport interface declaring
/// API methods that can be invoked via WalletApi method calls.
/// [`WalletClient`] is a counter-part to [`WalletServer`].
pub struct WalletClient {
pub transport: Transport,
}
Expand Down
2 changes: 2 additions & 0 deletions wallet/core/src/derivation/gen0/mod.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
//! Derivation management for legacy account derivation scheme `972`

mod hd;
pub use hd::{PubkeyDerivationManagerV0, WalletDerivationManagerV0};
pub mod import;
1 change: 1 addition & 0 deletions wallet/core/src/derivation/gen1/mod.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
/// Derivation management for the Kaspa standard derivation scheme `111111'`
mod hd;
pub use hd::{PubkeyDerivationManager, WalletDerivationManager};
pub mod import;
8 changes: 8 additions & 0 deletions wallet/core/src/deterministic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ use kaspa_hashes::Hash;
use kaspa_utils::as_slice::AsSlice;
use secp256k1::PublicKey;

/// Deterministic byte sequence derived from account data (can be used for auxiliary data storage encryption).
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Ord, PartialOrd, Serialize, Deserialize, BorshSerialize, BorshDeserialize)]
pub struct AccountStorageKey(pub(crate) Hash);

Expand All @@ -32,6 +33,7 @@ impl std::fmt::Display for AccountStorageKey {
}
}

/// Deterministic Account Id derived from account data.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Ord, PartialOrd, Serialize, Deserialize, BorshSerialize, BorshDeserialize)]
pub struct AccountId(pub(crate) Hash);

Expand Down Expand Up @@ -86,6 +88,7 @@ where
hashes
}

/// Create deterministic hashes from BIP32 account data.
pub fn from_bip32<const N: usize>(prv_key_data_id: &PrvKeyDataId, data: &bip32::Payload) -> [Hash; N] {
let hashable = DeterministicHashData {
account_kind: &bip32::BIP32_ACCOUNT_KIND.into(),
Expand All @@ -98,6 +101,7 @@ pub fn from_bip32<const N: usize>(prv_key_data_id: &PrvKeyDataId, data: &bip32::
make_hashes(hashable)
}

/// Create deterministic hashes from legacy account data.
pub fn from_legacy<const N: usize>(prv_key_data_id: &PrvKeyDataId, _data: &legacy::Payload) -> [Hash; N] {
let hashable = DeterministicHashData {
account_kind: &legacy::LEGACY_ACCOUNT_KIND.into(),
Expand All @@ -110,6 +114,7 @@ pub fn from_legacy<const N: usize>(prv_key_data_id: &PrvKeyDataId, _data: &legac
make_hashes(hashable)
}

/// Create deterministic hashes from multisig account data.
pub fn from_multisig<const N: usize>(prv_key_data_ids: &Option<Arc<Vec<PrvKeyDataId>>>, data: &multisig::Payload) -> [Hash; N] {
let hashable = DeterministicHashData {
account_kind: &multisig::MULTISIG_ACCOUNT_KIND.into(),
Expand All @@ -122,6 +127,7 @@ pub fn from_multisig<const N: usize>(prv_key_data_ids: &Option<Arc<Vec<PrvKeyDat
make_hashes(hashable)
}

/// Create deterministic hashes from keypair account data.
pub(crate) fn from_keypair<const N: usize>(prv_key_data_id: &PrvKeyDataId, data: &keypair::Payload) -> [Hash; N] {
let hashable = DeterministicHashData {
account_kind: &keypair::KEYPAIR_ACCOUNT_KIND.into(),
Expand All @@ -134,6 +140,7 @@ pub(crate) fn from_keypair<const N: usize>(prv_key_data_id: &PrvKeyDataId, data:
make_hashes(hashable)
}

/// Create deterministic hashes from a public key.
pub fn from_public_key<const N: usize>(account_kind: &AccountKind, public_key: &PublicKey) -> [Hash; N] {
let hashable: DeterministicHashData<[PrvKeyDataId; 0]> = DeterministicHashData {
account_kind,
Expand All @@ -146,6 +153,7 @@ pub fn from_public_key<const N: usize>(account_kind: &AccountKind, public_key: &
make_hashes(hashable)
}

/// Create deterministic hashes from arbitrary data (supplied data slice must be deterministic).
pub fn from_data<const N: usize>(account_kind: &AccountKind, data: &[u8]) -> [Hash; N] {
let hashable: DeterministicHashData<[PrvKeyDataId; 0]> = DeterministicHashData {
account_kind,
Expand Down
15 changes: 15 additions & 0 deletions wallet/core/src/encryption.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,14 @@ use sha2::{Digest, Sha256};
use std::ops::{Deref, DerefMut};
use zeroize::Zeroize;

/// Encryption algorithms supported by the Wallet framework.
#[derive(Clone, Copy, Debug, Serialize, Deserialize, BorshSerialize, BorshDeserialize)]
pub enum EncryptionKind {
XChaCha20Poly1305,
}

/// Abstract data container that can contain either plain or encrypted data and
/// transform the data between the two states.
#[derive(Clone, Debug, Serialize, Deserialize, BorshSerialize, BorshDeserialize)]
#[serde(tag = "encryptable", content = "payload")]
pub enum Encryptable<T> {
Expand Down Expand Up @@ -92,6 +95,7 @@ impl<T> From<T> for Encryptable<T> {
}
}

/// Abstract decrypted data container.
#[derive(Clone, Debug, BorshSerialize, BorshDeserialize)]
pub struct Decrypted<T>(pub(crate) T)
where
Expand Down Expand Up @@ -155,6 +159,7 @@ where
}
}

/// Encrypted data container (wraps an encrypted payload)
#[derive(Clone, Serialize, Deserialize, BorshSerialize, BorshDeserialize)]
pub struct Encrypted {
encryption_kind: EncryptionKind,
Expand Down Expand Up @@ -199,53 +204,61 @@ impl Encrypted {
}
}

/// WASM32 binding for `SHA256` hash function.
#[wasm_bindgen(js_name = "sha256")]
pub fn js_sha256_hash(data: JsValue) -> Result<String> {
let data = data.try_as_vec_u8()?;
let hash = sha256_hash(&data);
Ok(hash.as_ref().to_hex())
}

/// WASM32 binding for `SHA256d` hash function.
#[wasm_bindgen(js_name = "sha256d")]
pub fn js_sha256d_hash(data: JsValue) -> Result<String> {
let data = data.try_as_vec_u8()?;
let hash = sha256d_hash(&data);
Ok(hash.as_ref().to_hex())
}

/// WASM32 binding for `argon2sha256iv` hash function.
#[wasm_bindgen(js_name = "argon2sha256iv")]
pub fn js_argon2_sha256iv_phash(data: JsValue, byte_length: usize) -> Result<String> {
let data = data.try_as_vec_u8()?;
let hash = argon2_sha256iv_hash(&data, byte_length)?;
Ok(hash.as_ref().to_hex())
}

/// Produces `SHA256` hash of the given data.
pub fn sha256_hash(data: &[u8]) -> Secret {
let mut sha256 = Sha256::default();
sha256.update(data);
Secret::new(sha256.finalize().to_vec())
}

/// Produces `SHA256d` hash of the given data.
pub fn sha256d_hash(data: &[u8]) -> Secret {
let mut sha256 = Sha256::default();
sha256.update(data);
sha256_hash(sha256.finalize().as_slice())
}

/// Produces `argon2sha256iv` hash of the given data.
pub fn argon2_sha256iv_hash(data: &[u8], byte_length: usize) -> Result<Secret> {
let salt = sha256_hash(data);
let mut key = vec![0u8; byte_length];
Argon2::default().hash_password_into(data, salt.as_ref(), &mut key)?;
Ok(key.into())
}

/// WASM32 binding for `encryptXChaCha20Poly1305` function.
#[wasm_bindgen(js_name = "encryptXChaCha20Poly1305")]
pub fn js_encrypt_xchacha20poly1305(text: String, password: String) -> Result<String> {
let secret = sha256_hash(password.as_bytes());
let encrypted = encrypt_xchacha20poly1305(text.as_bytes(), &secret)?;
Ok(general_purpose::STANDARD.encode(encrypted))
}

/// Encrypts the given data using `XChaCha20Poly1305` algorithm.
pub fn encrypt_xchacha20poly1305(data: &[u8], secret: &Secret) -> Result<Vec<u8>> {
let private_key_bytes = argon2_sha256iv_hash(secret.as_ref(), 32)?;
let key = Key::from_slice(private_key_bytes.as_ref());
Expand All @@ -258,6 +271,7 @@ pub fn encrypt_xchacha20poly1305(data: &[u8], secret: &Secret) -> Result<Vec<u8>
Ok(buffer)
}

/// WASM32 binding for `decryptXChaCha20Poly1305` function.
#[wasm_bindgen(js_name = "decryptXChaCha20Poly1305")]
pub fn js_decrypt_xchacha20poly1305(text: String, password: String) -> Result<String> {
let secret = sha256_hash(password.as_bytes());
Expand All @@ -266,6 +280,7 @@ pub fn js_decrypt_xchacha20poly1305(text: String, password: String) -> Result<St
Ok(String::from_utf8(encrypted.as_ref().to_vec())?)
}

/// Decrypts the given data using `XChaCha20Poly1305` algorithm.
pub fn decrypt_xchacha20poly1305(data: &[u8], secret: &Secret) -> Result<Secret> {
let private_key_bytes = argon2_sha256iv_hash(secret.as_ref(), 32)?;
let key = Key::from_slice(private_key_bytes.as_ref());
Expand Down
1 change: 1 addition & 0 deletions wallet/core/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ use workflow_rpc::client::error::Error as RpcError;
use workflow_wasm::jserror::*;
use workflow_wasm::printable::*;

/// [`Error`](enum@Error) variants emitted by the wallet framework.
#[derive(Debug, Error)]
pub enum Error {
#[error("{0}")]
Expand Down
2 changes: 2 additions & 0 deletions wallet/core/src/events.rs
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,8 @@ pub enum Events {
/// contain a developer-assigned internal id.
id: UtxoContextId,
},
/// A general wallet framework error, emitted when an unexpected
/// error occurs within the wallet framework.
Error {
message: String,
},
Expand Down
17 changes: 17 additions & 0 deletions wallet/core/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,23 @@
//! within native Rust applications as well as within the NodeJS
//! and browser environments via WASM32.
//!
//! For JavaScript / TypeScript environments, there are two
//! available NPM modules:
//! - <https://www.npmjs.com/package/kaspa>
//! - <https://www.npmjs.com/package/kaspa-wasm>
//!
//! The `kaspa-wasm` module is a pure WASM32 module that includes
//! the entire wallet framework, but does not support RPC, while
//! the `kaspa` module also includes `isomorphic-ws` simulating
//! the W3C WebSocket available natively in browsers and supports RPC.
//!
//! JavaScript examples for using this framework can be found at:
//! <https://github.com/kaspanet/rusty-kaspa/tree/master/wasm/nodejs>
//!
//! For pre-built browser-compatible WASM32 redistributables of this
//! framework please see the releases section of the Rusty Kaspa
//! repository at <https://github.com/kaspanet/rusty-kaspa/releases>.
//!

extern crate alloc;
extern crate self as kaspa_wallet_core;
Expand Down
8 changes: 6 additions & 2 deletions wallet/core/src/message.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ impl AsRef<[u8]> for PersonalMessage<'_> {
}
}

/// Sign a message with the given private key
pub fn sign_message(msg: &PersonalMessage, privkey: &[u8; 32]) -> Result<Vec<u8>, Error> {
let hash = calc_personal_message_hash(msg);

Expand All @@ -24,8 +25,11 @@ pub fn sign_message(msg: &PersonalMessage, privkey: &[u8; 32]) -> Result<Vec<u8>
Ok(sig.to_vec())
}

/// Ok(()) if the signature matches the given message and pubkey
/// Error if any of the inputs are incorrect, or the signature is invalid
/// Verifies signed message.
///
/// Produces `Ok(())` if the signature matches the given message and [`secp256k1::Error`]
/// if any of the inputs are incorrect, or the signature is invalid.
///
pub fn verify_message(msg: &PersonalMessage, signature: &Vec<u8>, pubkey: &XOnlyPublicKey) -> Result<(), Error> {
let hash = calc_personal_message_hash(msg);
let msg = secp256k1::Message::from_slice(hash.as_bytes().as_slice())?;
Expand Down
1 change: 1 addition & 0 deletions wallet/core/src/result.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,5 @@
//! [`Result`] type alias bound to the framework [`Error`](crate::error::Error) enum.
//!

/// [`Result`] type alias bound to the framework [`Error`](crate::error::Error) enum.
pub type Result<T, E = super::error::Error> = std::result::Result<T, E>;
1 change: 1 addition & 0 deletions wallet/core/src/secret.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ use borsh::{BorshDeserialize, BorshSchema, BorshSerialize};
use serde::{Deserialize, Serialize};
use zeroize::Zeroize;

/// Secret container for sensitive data. Performs memory zeroization on drop.
#[derive(Clone, Serialize, Deserialize, BorshSerialize, BorshDeserialize, BorshSchema)]
pub struct Secret(Vec<u8>);

Expand Down
Loading