diff --git a/apps/desktop-wallet/src-tauri/icons/128x128.png b/apps/desktop-wallet/src-tauri/icons/128x128.png new file mode 100644 index 0000000..883e4ad Binary files /dev/null and b/apps/desktop-wallet/src-tauri/icons/128x128.png differ diff --git a/apps/desktop-wallet/src-tauri/icons/128x128@2x.png b/apps/desktop-wallet/src-tauri/icons/128x128@2x.png new file mode 100644 index 0000000..883e4ad Binary files /dev/null and b/apps/desktop-wallet/src-tauri/icons/128x128@2x.png differ diff --git a/apps/desktop-wallet/src-tauri/icons/32x32.png b/apps/desktop-wallet/src-tauri/icons/32x32.png new file mode 100644 index 0000000..883e4ad Binary files /dev/null and b/apps/desktop-wallet/src-tauri/icons/32x32.png differ diff --git a/apps/desktop-wallet/src-tauri/icons/icon.icns b/apps/desktop-wallet/src-tauri/icons/icon.icns new file mode 100644 index 0000000..e69de29 diff --git a/apps/desktop-wallet/src-tauri/icons/icon.ico b/apps/desktop-wallet/src-tauri/icons/icon.ico new file mode 100644 index 0000000..e69de29 diff --git a/apps/desktop-wallet/src-tauri/icons/icon.png b/apps/desktop-wallet/src-tauri/icons/icon.png new file mode 100644 index 0000000..883e4ad Binary files /dev/null and b/apps/desktop-wallet/src-tauri/icons/icon.png differ diff --git a/apps/desktop-wallet/src-tauri/src/crypto.rs b/apps/desktop-wallet/src-tauri/src/crypto.rs index be88f99..52e039b 100644 --- a/apps/desktop-wallet/src-tauri/src/crypto.rs +++ b/apps/desktop-wallet/src-tauri/src/crypto.rs @@ -5,26 +5,29 @@ //! - Argon2id password-based key derivation //! - ChaCha20-Poly1305 authenticated encryption //! - Ed25519 key derivation from seed -//! - Bech32 address encoding +//! - Bech32m address encoding use argon2::{ - password_hash::{rand_core::OsRng, PasswordHasher, SaltString}, + password_hash::SaltString, Argon2, Params, }; -use bip39::{Language, Mnemonic}; +use bip39::Mnemonic; use chacha20poly1305::{ aead::{Aead, KeyInit}, ChaCha20Poly1305, Nonce, }; -use hmac::{Hmac, Mac}; -use rand::RngCore; +use hmac::Mac; +use rand::{rngs::OsRng, RngCore}; use sha2::Sha512; use zeroize::{Zeroize, ZeroizeOnDrop}; use crate::{Error, Result}; +/// Type alias for HMAC-SHA512 to avoid ambiguity +type HmacSha512 = hmac::Hmac; + /// Encrypted wallet data stored on disk -#[derive(serde::Serialize, serde::Deserialize)] +#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)] pub struct EncryptedWallet { /// Argon2 salt (22 bytes, base64 encoded) pub salt: String, @@ -46,7 +49,10 @@ pub struct SeedData { /// Generate a new random 24-word BIP39 mnemonic pub fn generate_mnemonic() -> Result { // Generate 256 bits of entropy for 24 words - let mnemonic = Mnemonic::generate_in(Language::English, 24) + let mut entropy = [0u8; 32]; // 256 bits for 24 words + OsRng.fill_bytes(&mut entropy); + + let mnemonic = Mnemonic::from_entropy(&entropy) .map_err(|e| Error::Crypto(format!("Failed to generate mnemonic: {}", e)))?; Ok(mnemonic.to_string()) @@ -54,15 +60,15 @@ pub fn generate_mnemonic() -> Result { /// Validate a BIP39 mnemonic phrase pub fn validate_mnemonic(phrase: &str) -> Result<()> { - Mnemonic::parse_in(Language::English, phrase) - .map_err(|e| Error::InvalidMnemonic)?; + Mnemonic::parse(phrase) + .map_err(|_| Error::InvalidMnemonic)?; Ok(()) } /// Derive a 64-byte seed from mnemonic using BIP39 /// The passphrase is optional (empty string if not used) pub fn mnemonic_to_seed(mnemonic: &str, passphrase: &str) -> Result { - let mnemonic = Mnemonic::parse_in(Language::English, mnemonic) + let mnemonic = Mnemonic::parse(mnemonic) .map_err(|_| Error::InvalidMnemonic)?; let seed = mnemonic.to_seed(passphrase); @@ -169,14 +175,13 @@ pub fn decrypt_seed(wallet: &EncryptedWallet, password: &str) -> Result ([u8; 32], [u8; 32]) { // Use HMAC-SHA512 for deterministic key derivation // Path: m/44'/synor'/0'/0/index - type HmacSha512 = Hmac; - let mut mac = HmacSha512::new_from_slice(b"ed25519 seed").unwrap(); + let mut mac: HmacSha512 = Mac::new_from_slice(b"ed25519 seed").unwrap(); mac.update(seed); let master = mac.finalize().into_bytes(); // Derive child key for index - let mut mac = HmacSha512::new_from_slice(&master[32..]).unwrap(); + let mut mac: HmacSha512 = Mac::new_from_slice(&master[32..]).unwrap(); mac.update(&master[..32]); mac.update(&index.to_be_bytes()); let derived = mac.finalize().into_bytes(); @@ -193,36 +198,21 @@ pub fn derive_ed25519_keypair(seed: &[u8; 64], index: u32) -> ([u8; 32], [u8; 32 } /// Generate a Synor address from a public key -/// Format: synor1 +/// Format: synor1 pub fn pubkey_to_address(pubkey: &[u8; 32], testnet: bool) -> Result { + use bech32::Hrp; use sha2::{Digest, Sha256}; // Hash the public key (SHA256 then take first 20 bytes like Bitcoin) let hash = Sha256::digest(pubkey); - let pubkey_hash: Vec = hash[..20].to_vec(); + let pubkey_hash: &[u8] = &hash[..20]; - // Convert to 5-bit groups for bech32 - let mut data5 = Vec::with_capacity(33); - data5.push(bech32::u5::try_from_u8(0).unwrap()); // version byte + let hrp_str = if testnet { "tsynor" } else { "synor" }; + let hrp = Hrp::parse(hrp_str) + .map_err(|e| Error::Crypto(format!("Invalid HRP: {}", e)))?; - // Convert 8-bit to 5-bit - let mut acc = 0u32; - let mut bits = 0u32; - for byte in &pubkey_hash { - acc = (acc << 8) | (*byte as u32); - bits += 8; - while bits >= 5 { - bits -= 5; - data5.push(bech32::u5::try_from_u8(((acc >> bits) & 31) as u8).unwrap()); - } - } - if bits > 0 { - data5.push(bech32::u5::try_from_u8(((acc << (5 - bits)) & 31) as u8).unwrap()); - } - - let hrp = if testnet { "tsynor" } else { "synor" }; - - bech32::encode(hrp, data5, bech32::Variant::Bech32) + // Encode using bech32 segwit encoding (version 0) + bech32::segwit::encode(hrp, bech32::segwit::VERSION_0, pubkey_hash) .map_err(|e| Error::Crypto(format!("Bech32 encoding failed: {}", e))) } diff --git a/apps/desktop-wallet/src-tauri/src/lib.rs b/apps/desktop-wallet/src-tauri/src/lib.rs index a3712ff..542b662 100644 --- a/apps/desktop-wallet/src-tauri/src/lib.rs +++ b/apps/desktop-wallet/src-tauri/src/lib.rs @@ -120,7 +120,7 @@ pub fn run() { let _tray = TrayIconBuilder::new() .icon(app.default_window_icon().unwrap().clone()) .menu(&menu) - .menu_on_left_click(false) + .show_menu_on_left_click(false) .on_tray_icon_event(|tray, event| { handle_tray_event(tray.app_handle(), event); })