11// Fuego Crypto Library for Native Wallet Operations
22// This provides FFI-safe crypto primitives for the Dart/Flutter wallet
33
4- use ed25519_dalek:: { SigningKey , VerifyingKey , Signature } ;
4+ use ed25519_dalek:: { SigningKey , VerifyingKey , Signature , Signer , Verifier , SecretKey } ;
55use sha2:: { Sha512 , Digest } ;
66use sha2:: Sha256 ;
7- use curve25519_dalek:: scalar:: Scalar ;
87use rand:: rngs:: OsRng ;
8+ use rand:: RngCore ;
99use std:: ffi:: { CStr , CString } ;
1010use std:: os:: raw:: { c_char, c_int} ;
11- use hex;
12- use base58check;
1311
1412// Fuego uses Ed25519 for key pairs (similar to CryptoNote)
1513// Public key and secret key are 32 bytes each
@@ -26,38 +24,43 @@ pub extern "C" fn fuego_generate_keys(
2624 public_view_key : * mut u8 ,
2725) -> c_int {
2826 // Generate random private spend key
29- let spend_secret = SigningKey :: generate ( & mut OsRng ) ;
27+ let mut spend_key_bytes = [ 0u8 ; 32 ] ;
28+ let mut rng = OsRng ;
29+ rng. fill_bytes ( & mut spend_key_bytes) ;
30+ let spend_secret = SigningKey :: from_bytes ( & SecretKey :: from ( spend_key_bytes) ) ;
3031 let spend_pub = spend_secret. verifying_key ( ) ;
3132
3233 // Generate private view key from spend key (deterministic)
3334 let mut hasher = Sha512 :: new ( ) ;
34- hasher. update ( spend_secret . to_bytes ( ) ) ;
35+ hasher. update ( spend_key_bytes ) ;
3536 hasher. update ( b"view_key" ) ;
3637 let view_secret_hash = hasher. finalize ( ) ;
3738
3839 // Convert hash to signing key (32 bytes)
39- let view_secret = SigningKey :: from_bytes ( & view_secret_hash[ ..32 ] ) ;
40+ let mut view_key_bytes = [ 0u8 ; 32 ] ;
41+ view_key_bytes. copy_from_slice ( & view_secret_hash[ ..32 ] ) ;
42+ let view_secret = SigningKey :: from_bytes ( & SecretKey :: from ( view_key_bytes) ) ;
4043 let view_pub = view_secret. verifying_key ( ) ;
4144
4245 // Copy to output buffers
4346 unsafe {
4447 std:: ptr:: copy_nonoverlapping (
45- spend_secret. to_bytes ( ) . as_ptr ( ) ,
48+ spend_secret. as_bytes ( ) . as_ptr ( ) ,
4649 private_spend_key,
4750 KEY_SIZE ,
4851 ) ;
4952 std:: ptr:: copy_nonoverlapping (
50- view_secret. to_bytes ( ) . as_ptr ( ) ,
53+ view_secret. as_bytes ( ) . as_ptr ( ) ,
5154 private_view_key,
5255 KEY_SIZE ,
5356 ) ;
5457 std:: ptr:: copy_nonoverlapping (
55- spend_pub. to_bytes ( ) . as_ptr ( ) ,
58+ spend_pub. as_bytes ( ) . as_ptr ( ) ,
5659 public_spend_key,
5760 KEY_SIZE ,
5861 ) ;
5962 std:: ptr:: copy_nonoverlapping (
60- view_pub. to_bytes ( ) . as_ptr ( ) ,
63+ view_pub. as_bytes ( ) . as_ptr ( ) ,
6164 public_view_key,
6265 KEY_SIZE ,
6366 ) ;
@@ -80,15 +83,11 @@ pub extern "C" fn fuego_private_to_public(
8083 arr
8184 } ;
8285
83- let signing_key = match SigningKey :: from_bytes ( & private_arr) {
84- Ok ( key) => key,
85- Err ( _) => return -1 ,
86- } ;
87-
86+ let signing_key = SigningKey :: from_bytes ( & SecretKey :: from ( private_arr) ) ;
8887 let verifying_key = signing_key. verifying_key ( ) ;
8988
9089 std:: ptr:: copy_nonoverlapping (
91- verifying_key. to_bytes ( ) . as_ptr ( ) ,
90+ verifying_key. as_bytes ( ) . as_ptr ( ) ,
9291 public_key,
9392 KEY_SIZE ,
9493 ) ;
@@ -235,11 +234,7 @@ pub extern "C" fn fuego_sign(
235234 arr
236235 } ;
237236
238- let signing_key = match SigningKey :: from_bytes ( & private_key_arr) {
239- Ok ( key) => key,
240- Err ( _) => return -1 ,
241- } ;
242-
237+ let signing_key = SigningKey :: from_bytes ( & SecretKey :: from ( private_key_arr) ) ;
243238 let message_slice = std:: slice:: from_raw_parts ( message, message_len) ;
244239 let signature = signing_key. sign ( message_slice) ;
245240
@@ -282,7 +277,7 @@ pub extern "C" fn fuego_verify_signature(
282277 arr
283278 } ;
284279
285- let signature = match Signature :: from_bytes ( & signature_arr) {
280+ let signature = match Signature :: try_from ( & signature_arr) {
286281 Ok ( sig) => sig,
287282 Err ( _) => return 0 ,
288283 } ;
@@ -385,18 +380,23 @@ pub extern "C" fn fuego_key_to_mnemonic(
385380 use zeroize:: Zeroize ;
386381
387382 unsafe {
388- let private_key_arr: [ u8 ; KEY_SIZE ] = {
383+ let mut private_key_arr: [ u8 ; KEY_SIZE ] = {
389384 let slice = std:: slice:: from_raw_parts ( private_key, KEY_SIZE ) ;
390385 let mut arr = [ 0u8 ; KEY_SIZE ] ;
391386 arr. copy_from_slice ( slice) ;
392387 arr
393388 } ;
394389
395390 // Generate mnemonic using BIP39
396- let mnemonic = bip39:: Mnemonic :: from_entropy ( & private_key_arr, bip39:: Language :: English )
397- . unwrap_or_else ( |_| bip39:: Mnemonic :: generate_in ( bip39:: Language :: English , bip39:: MnemonicType :: Words12 ) ) ;
398-
399- let mnemonic_str = mnemonic. phrase ( ) ;
391+ let mnemonic = bip39:: Mnemonic :: from_entropy_in ( bip39:: Language :: English , & private_key_arr)
392+ . unwrap_or_else ( |_| {
393+ // Generate new mnemonic if entropy derivation fails
394+ let mut entropy = [ 0u8 ; 16 ] ;
395+ OsRng . fill_bytes ( & mut entropy) ;
396+ bip39:: Mnemonic :: from_entropy_in ( bip39:: Language :: English , & entropy) . unwrap ( )
397+ } ) ;
398+
399+ let mnemonic_str = mnemonic. to_string ( ) ;
400400
401401 let mnemonic_cstr = match CString :: new ( mnemonic_str) {
402402 Ok ( cstr) => cstr,
@@ -432,12 +432,12 @@ pub extern "C" fn fuego_mnemonic_to_key(
432432 Err ( _) => return -1 ,
433433 } ;
434434
435- let mnemonic_obj = match bip39:: Mnemonic :: from_phrase ( mnemonic_str , bip39:: Language :: English ) {
435+ let mnemonic_obj = match bip39:: Mnemonic :: parse_in_normalized ( bip39:: Language :: English , mnemonic_str ) {
436436 Ok ( m) => m,
437437 Err ( _) => return -1 ,
438438 } ;
439439
440- let entropy = mnemonic_obj. entropy ( ) ;
440+ let entropy = mnemonic_obj. to_entropy ( ) ;
441441
442442 if entropy. len ( ) < KEY_SIZE {
443443 return -1 ;
@@ -464,7 +464,7 @@ pub extern "C" fn fuego_validate_mnemonic(
464464 Err ( _) => return 0 ,
465465 } ;
466466
467- match bip39:: Mnemonic :: from_phrase ( mnemonic_str , bip39:: Language :: English ) {
467+ match bip39:: Mnemonic :: parse_in_normalized ( bip39:: Language :: English , mnemonic_str ) {
468468 Ok ( _) => 1 , // Valid
469469 Err ( _) => 0 , // Invalid
470470 }
0 commit comments