use std::os::raw::c_int;
use std::ffi::CStr;
use std::os::raw::c_char;
use crate::{Seed, SeedEnc};
pub const PKTSEED_RET_OK: c_int = 0;
pub const PKTSEED_RET_INVAL_WORDS: c_int = -1;
pub const PKTSEED_RET_WRONG_WORDS: c_int = -2;
pub const PKTSEED_RET_ENCRYPTED_NO_PASS: c_int = -3;
pub const PKTSEED_RET_FAILED_DECRYPT: c_int = -4;
pub const PKTSEED_RET_INTERNAL: c_int = -5;
pub const PKTSEED_RET_SHORT: c_int = -6;
pub const PKTSEED_RET_INVAL_LANG: c_int = -7;
pub const PKTSEED_RET_INVAL: c_int = -8;
#[no_mangle]
pub unsafe extern "C" fn pktseed_needs_passphrase(
needs_passphrase: *mut u32,
words: *const c_char,
) -> c_int {
let words_s = if let Ok(ws) = CStr::from_ptr(words).to_str() {
ws
} else {
return PKTSEED_RET_INVAL_WORDS;
};
let se = if let Ok(w) = SeedEnc::from_words(words_s) {
w
} else {
return PKTSEED_RET_WRONG_WORDS;
};
*needs_passphrase = if se.is_encrypted() {
1
} else {
0
};
PKTSEED_RET_OK
}
#[no_mangle]
pub unsafe extern "C" fn pktseed_from_words(
seed_out: *mut u8,
seed_len: u32,
birthday_out: *mut u64,
words: *const c_char,
passphrase_opt: *const c_char,
) -> c_int {
if seed_len < Seed::BYTES_LEN as u32 {
return PKTSEED_RET_INVAL;
}
let so = std::slice::from_raw_parts_mut(seed_out, Seed::BYTES_LEN);
let words_s = if let Ok(ws) = CStr::from_ptr(words).to_str() {
ws
} else {
return PKTSEED_RET_INVAL_WORDS;
};
let passphrase = if passphrase_opt.is_null() {
None
} else {
Some(CStr::from_ptr(passphrase_opt).to_bytes())
};
let se = if let Ok(w) = SeedEnc::from_words(words_s) {
w
} else {
return PKTSEED_RET_WRONG_WORDS;
};
let seed = if se.is_encrypted() {
if passphrase.is_none() {
return PKTSEED_RET_ENCRYPTED_NO_PASS;
}
if let Ok(seed) = se.decrypt(passphrase, false) {
seed
} else {
return PKTSEED_RET_FAILED_DECRYPT;
}
} else {
if let Ok(seed) = se.decrypt(None, false) {
seed
} else {
return PKTSEED_RET_INTERNAL
}
};
so.copy_from_slice(&seed.bytes[..]);
*birthday_out = seed.get_bday();
PKTSEED_RET_OK
}
#[no_mangle]
pub unsafe extern "C" fn pktseed_new(
seed_out: *mut u8,
seed_len: u32,
rand_in: *const u8,
rand_len: u32,
) -> c_int {
if seed_len < Seed::BYTES_LEN as u32 {
return PKTSEED_RET_INVAL;
}
if rand_len < (Seed::BYTES_LEN - 2) as u32 {
return PKTSEED_RET_INVAL;
}
let in_bytes = std::slice::from_raw_parts(rand_in, Seed::BYTES_LEN - 2);
let out_bytes = std::slice::from_raw_parts_mut(seed_out, Seed::BYTES_LEN);
let s = Seed::new(in_bytes);
out_bytes.copy_from_slice(&s.bytes[..]);
PKTSEED_RET_OK
}
#[no_mangle]
pub unsafe extern "C" fn pktseed_to_words(
words_out: *mut c_char,
words_len: u32,
seed: *const u8,
seed_len: u32,
language: *const c_char,
passphrase_opt: *const c_char,
) -> c_int {
if seed_len != Seed::BYTES_LEN as u32 {
return PKTSEED_RET_INVAL;
}
let passphrase = if passphrase_opt.is_null() {
None
} else {
Some(CStr::from_ptr(passphrase_opt).to_bytes())
};
let seed_bytes = std::slice::from_raw_parts(seed, Seed::BYTES_LEN);
let seed = Seed::new_raw(&seed_bytes[..]);
let seed_enc = seed.encrypt(passphrase);
let lang = CStr::from_ptr(language).to_str().unwrap();
let words = if let Ok(se) = seed_enc.words(lang) {
se
} else {
return PKTSEED_RET_INVAL_LANG;
};
if words_len < (words.as_bytes().len() + 1) as u32 {
return PKTSEED_RET_SHORT;
}
let wo = std::slice::from_raw_parts_mut(words_out as *mut u8, words.as_bytes().len() + 1);
wo.copy_from_slice(words.as_bytes());
wo[wo.len() - 1] = 0;
PKTSEED_RET_OK
}