1use monero_serai_mirror::{
2 wallet::{
3 seed::{Seed, Language},
4 address::{AddressType, AddressMeta, AddressSpec, MoneroAddress, Network, SubaddressIndex},
5 ViewPair,
6 },
7};
8
9use rand_core::OsRng; use zeroize::{Zeroizing};
11use std::os::raw::{c_char};
12use std::ffi::CString;
13use std::ffi::CStr;
14
15use curve25519_dalek::{
16 edwards::EdwardsPoint,
17 scalar::Scalar,
18 constants::ED25519_BASEPOINT_TABLE,
19};
20
21use sha3::{Digest, Keccak256}; #[no_mangle]
25pub extern "C" fn generate_mnemonic(language: u8) -> *const c_char {
26 let _language: Language = match language{
28 0=>Language::German,
29 1=>Language::English,
30 2=>Language::Spanish,
31 3=>Language::French,
32 4=>Language::Italian,
33 5=>Language::Dutch,
34 6=>Language::Portuguese,
35 7=>Language::Russian,
36 8=>Language::Chinese,
37 9=>Language::Japanese,
38 10=>Language::Esperanto,
39 11=>Language::Lojban,
40 12=>Language::EnglishOld,
41 _=>Language::English,
42 };
43
44 let ptr: *const c_char = convert_zeroize_string_to_c_char_ptr(&Seed::to_string(&Seed::new(&mut OsRng, _language)));
46 ptr
47}
48
49
50
51#[no_mangle]
53pub extern "C" fn generate_address(
54 mnemonic: *const c_char,
55 network: u8,
56 account: u32,
57 index: u32,
58) -> *const c_char {
59 let seed = match Seed::from_string(Zeroizing::new(convert_c_char_ptr_to_string(mnemonic))) {
60 Ok(seed) => seed,
61 Err(_) => {
62 return CString::new("").unwrap().into_raw();
64 }
65 };
66
67 let _network: Network = match network{
68 0=>Network::Mainnet,
69 1=>Network::Testnet,
70 2=>Network::Stagenet,
71 _=>Network::Mainnet,
72 };
74
75 let spend: [u8; 32] = *seed.entropy();
77 let spend_scalar: Scalar = Scalar::from_bytes_mod_order(spend);
78 let spend_point: EdwardsPoint = &spend_scalar * &ED25519_BASEPOINT_TABLE;
79
80 let view: [u8; 32] = Keccak256::digest(&spend).into();
82 let view_scalar: Scalar = Scalar::from_bytes_mod_order(view);
83 let view_point: EdwardsPoint = &view_scalar * &ED25519_BASEPOINT_TABLE;
84
85 let address: MoneroAddress;
86 if (account == 0) && (index == 0) {
87 address = MoneroAddress::new(
89 AddressMeta::new(_network, AddressType::Standard),
90 spend_point,
91 view_point,
92 );
93 } else {
94 let view: ViewPair = ViewPair::new(spend_point, Zeroizing::new(view_scalar));
96 address = view.address(_network, AddressSpec::Subaddress(SubaddressIndex::new(account, index).unwrap()));
97 }
98
99 let c_string = CString::new(address.to_string()).unwrap(); let ptr: *const c_char = c_string.as_ptr() as *const c_char;
102
103 std::mem::forget(c_string); ptr
108}
109
110fn convert_zeroize_string_to_c_char_ptr(zeroized_string: &str) -> *const c_char {
111 let rust_string = zeroized_string;
113
114 let c_string = CString::new(rust_string).expect("Failed to create CString");
116
117 let raw_ptr = c_string.into_raw();
119
120 raw_ptr
122}
123
124
125fn convert_c_char_ptr_to_string(c_char_ptr: *const c_char) -> String {
126 let c_str: &CStr = unsafe {
128 assert!(!c_char_ptr.is_null());
129 CStr::from_ptr(c_char_ptr)
130 };
131
132 c_str.to_string_lossy().into_owned()
134}
135
136