forked from axiom-team/gecko
Merge pull request 'dubp/secret-code-type' (#4) from dubp/secret-code-type into master
Reviewed-on: axiom-team/gecko#4
This commit is contained in:
commit
60c9d00c61
|
@ -0,0 +1,3 @@
|
|||
[alias]
|
||||
bd = "make android-dev32"
|
||||
br = "make"
|
|
@ -59,6 +59,15 @@ version = "0.5.2"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "23b62fc65de8e4e7f52534fb52b0f3ed04746ae267519eef2a83941e8085068b"
|
||||
|
||||
[[package]]
|
||||
name = "async-oneshot"
|
||||
version = "0.4.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "50f4770cbbff928c30a991de67fb3976f44d8e3e202f8c79ef91b47006e04904"
|
||||
dependencies = [
|
||||
"futures-micro",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "atty"
|
||||
version = "0.2.14"
|
||||
|
@ -245,6 +254,8 @@ dependencies = [
|
|||
"cbindgen",
|
||||
"dart-bindgen",
|
||||
"dup-crypto",
|
||||
"fast-threadpool",
|
||||
"once_cell",
|
||||
"thiserror",
|
||||
]
|
||||
|
||||
|
@ -270,6 +281,32 @@ dependencies = [
|
|||
"zeroize",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fast-threadpool"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cccb66774e02743b4be61c19e09bf59de9058e9a7b4096040689003e7a901a3d"
|
||||
dependencies = [
|
||||
"async-oneshot",
|
||||
"flume",
|
||||
"num_cpus",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "flume"
|
||||
version = "0.10.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0362ef9c4c1fa854ff95b4cb78045a86e810d804dc04937961988b45427104a9"
|
||||
dependencies = [
|
||||
"spinning_top",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "futures-micro"
|
||||
version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "61e9325be55c5581082cd110294fa988c1f920bc573ec370ef201e33c469a95a"
|
||||
|
||||
[[package]]
|
||||
name = "generic-array"
|
||||
version = "0.14.4"
|
||||
|
@ -344,6 +381,15 @@ version = "0.2.81"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1482821306169ec4d07f6aca392a4681f66c75c9918aa49641a2595db64053cb"
|
||||
|
||||
[[package]]
|
||||
name = "lock_api"
|
||||
version = "0.4.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dd96ffd135b2fd7b973ac026d28085defbe8983df057ced3eb4f2130b0831312"
|
||||
dependencies = [
|
||||
"scopeguard",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "log"
|
||||
version = "0.4.11"
|
||||
|
@ -353,6 +399,16 @@ dependencies = [
|
|||
"cfg-if 0.1.10",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num_cpus"
|
||||
version = "1.13.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "05499f3756671c15885fee9034446956fff3f243d6077b91e5767df161f766b3"
|
||||
dependencies = [
|
||||
"hermit-abi",
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "once_cell"
|
||||
version = "1.5.2"
|
||||
|
@ -466,6 +522,12 @@ version = "1.0.5"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e"
|
||||
|
||||
[[package]]
|
||||
name = "scopeguard"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.118"
|
||||
|
@ -503,6 +565,15 @@ version = "0.5.2"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d"
|
||||
|
||||
[[package]]
|
||||
name = "spinning_top"
|
||||
version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7e529d73e80d64b5f2631f9035113347c578a1c9c7774b83a2b880788459ab36"
|
||||
dependencies = [
|
||||
"lock_api",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "strsim"
|
||||
version = "0.8.0"
|
||||
|
|
|
@ -11,6 +11,8 @@ crate-type = ["rlib"]
|
|||
[dependencies]
|
||||
allo-isolate = "0.1.6"
|
||||
dup-crypto = { version = "0.36.0", features = ["dewif", "mnemonic", "mnemonic_french", "rand", "scrypt"] }
|
||||
fast-threadpool = { version = "0.3.0", default-features = false }
|
||||
once_cell = { version = "1.3.1", default-features = false, features = ["std"] }
|
||||
thiserror = "1.0.23"
|
||||
|
||||
[build-dependencies]
|
||||
|
|
|
@ -0,0 +1,42 @@
|
|||
// Copyright (C) 2020 Éloïs SANCHEZ.
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as
|
||||
// published by the Free Software Foundation, either version 3 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
use crate::*;
|
||||
|
||||
static THREAD_POOL: Lazy<ThreadPoolSyncHandler<()>> = Lazy::new(|| {
|
||||
ThreadPool::start(ThreadPoolConfig::low().queue_size(Some(16)), ()).into_sync_handler()
|
||||
});
|
||||
|
||||
pub(crate) fn exec_async<F, F2, P, R>(port: i64, parse_params: F, async_job: F2)
|
||||
where
|
||||
P: 'static + Send + Sync,
|
||||
F: FnOnce() -> Result<P, DubpError>,
|
||||
F2: 'static + Send + Sync + FnOnce(P) -> R,
|
||||
DartRes: From<R>,
|
||||
{
|
||||
match parse_params() {
|
||||
Ok(parsed_params) => {
|
||||
if THREAD_POOL
|
||||
.launch(move |_| Isolate::new(port).post(DartRes::from(async_job(parsed_params))))
|
||||
.is_err()
|
||||
{
|
||||
Isolate::new(port).post(DartRes::err("thread pool panicked"));
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
Isolate::new(port).post(DartRes::err(e));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -15,82 +15,51 @@
|
|||
|
||||
use crate::*;
|
||||
|
||||
pub(super) fn gen_pin6() -> Result<String, DubpError> {
|
||||
let i = dup_crypto::rand::gen_u32().map_err(|_| DubpError::RandErr)?;
|
||||
Ok(gen_pin6_inner(i))
|
||||
}
|
||||
pub(super) fn gen_pin8() -> Result<String, DubpError> {
|
||||
let i = dup_crypto::rand::gen_u32().map_err(|_| DubpError::RandErr)?;
|
||||
let i2 = dup_crypto::rand::gen_u32().map_err(|_| DubpError::RandErr)?;
|
||||
let mut pin = gen_pin6_inner(i);
|
||||
gen_pin2_inner(i2, &mut pin);
|
||||
Ok(pin)
|
||||
}
|
||||
pub(super) fn gen_pin10() -> Result<String, DubpError> {
|
||||
let i = dup_crypto::rand::gen_u32().map_err(|_| DubpError::RandErr)?;
|
||||
let i2 = dup_crypto::rand::gen_u32().map_err(|_| DubpError::RandErr)?;
|
||||
let mut pin = gen_pin6_inner(i);
|
||||
gen_pin4_inner(i2, &mut pin);
|
||||
Ok(pin)
|
||||
}
|
||||
|
||||
pub(super) fn change_pin(
|
||||
currency: *const raw::c_char,
|
||||
dewif: *const raw::c_char,
|
||||
old_pin: *const raw::c_char,
|
||||
new_pin: *const raw::c_char,
|
||||
) -> Result<String, DubpError> {
|
||||
let currency = char_ptr_to_str(currency)?;
|
||||
let dewif = char_ptr_to_str(dewif)?;
|
||||
let old_pin = char_ptr_to_str(old_pin)?;
|
||||
let new_pin = char_ptr_to_str(new_pin)?;
|
||||
|
||||
pub(super) fn change_secret_code(
|
||||
currency: &str,
|
||||
dewif: &str,
|
||||
old_secret_code: &str,
|
||||
member_wallet: bool,
|
||||
secret_code_type: SecretCodeType,
|
||||
) -> Result<Vec<String>, DubpError> {
|
||||
let currency = parse_currency(currency)?;
|
||||
let mut keypairs = dup_crypto::dewif::read_dewif_file_content(
|
||||
ExpectedCurrency::Specific(currency),
|
||||
dewif,
|
||||
old_pin,
|
||||
old_secret_code,
|
||||
)
|
||||
.map_err(DubpError::DewifReadError)?;
|
||||
if let Some(KeyPairEnum::Ed25519(keypair)) = keypairs.next() {
|
||||
Ok(dup_crypto::dewif::write_dewif_v1_content(
|
||||
currency, &keypair, new_pin,
|
||||
))
|
||||
let new_secret_code = gen_secret_code(member_wallet, secret_code_type)?;
|
||||
|
||||
let dewif = dup_crypto::dewif::write_dewif_v1_content(currency, &keypair, &new_secret_code);
|
||||
let pubkey = keypair.public_key().to_base58();
|
||||
Ok(vec![dewif, new_secret_code, pubkey])
|
||||
} else {
|
||||
Err(DubpError::DewifReadError(DewifReadError::CorruptedContent))
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn gen_dewif(
|
||||
currency: *const raw::c_char,
|
||||
language: u32,
|
||||
mnemonic: *const raw::c_char,
|
||||
pin: *const raw::c_char,
|
||||
) -> Result<String, DubpError> {
|
||||
let currency = char_ptr_to_str(currency)?;
|
||||
let mnemonic = char_ptr_to_str(mnemonic)?;
|
||||
let pin = char_ptr_to_str(pin)?;
|
||||
|
||||
currency: &str,
|
||||
language: Language,
|
||||
mnemonic: &str,
|
||||
member_wallet: bool,
|
||||
secret_code_type: SecretCodeType,
|
||||
) -> Result<Vec<String>, DubpError> {
|
||||
let currency = parse_currency(currency)?;
|
||||
let mnemonic = Mnemonic::from_phrase(mnemonic, u32_to_language(language)?)
|
||||
.map_err(|_| DubpError::WrongLanguage)?;
|
||||
let mnemonic =
|
||||
Mnemonic::from_phrase(mnemonic, language).map_err(|_| DubpError::WrongLanguage)?;
|
||||
let seed = dup_crypto::mnemonic::mnemonic_to_seed(&mnemonic);
|
||||
let keypair = KeyPairFromSeed32Generator::generate(seed);
|
||||
Ok(dup_crypto::dewif::write_dewif_v1_content(
|
||||
currency, &keypair, pin,
|
||||
))
|
||||
|
||||
let secret_code = gen_secret_code(member_wallet, secret_code_type)?;
|
||||
let dewif = dup_crypto::dewif::write_dewif_v1_content(currency, &keypair, &secret_code);
|
||||
let pubkey = keypair.public_key().to_base58();
|
||||
Ok(vec![dewif, secret_code, pubkey])
|
||||
}
|
||||
|
||||
pub(super) fn get_pubkey(
|
||||
currency: *const raw::c_char,
|
||||
dewif: *const raw::c_char,
|
||||
pin: *const raw::c_char,
|
||||
) -> Result<String, DubpError> {
|
||||
let currency = char_ptr_to_str(currency)?;
|
||||
let dewif = char_ptr_to_str(dewif)?;
|
||||
let pin = char_ptr_to_str(pin)?;
|
||||
|
||||
let currency = parse_currency(currency)?;
|
||||
pub(super) fn get_pubkey(currency: Currency, dewif: &str, pin: &str) -> Result<String, DubpError> {
|
||||
let mut keypairs = dup_crypto::dewif::read_dewif_file_content(
|
||||
ExpectedCurrency::Specific(currency),
|
||||
dewif,
|
||||
|
@ -104,17 +73,7 @@ pub(super) fn get_pubkey(
|
|||
}
|
||||
}
|
||||
|
||||
pub(super) fn sign(
|
||||
currency: *const raw::c_char,
|
||||
dewif: *const raw::c_char,
|
||||
pin: *const raw::c_char,
|
||||
msg: *const raw::c_char,
|
||||
) -> Result<String, DubpError> {
|
||||
let currency = char_ptr_to_str(currency)?;
|
||||
let dewif = char_ptr_to_str(dewif)?;
|
||||
let pin = char_ptr_to_str(pin)?;
|
||||
let msg = char_ptr_to_str(msg)?;
|
||||
|
||||
pub(super) fn sign(currency: &str, dewif: &str, pin: &str, msg: &str) -> Result<String, DubpError> {
|
||||
let currency = parse_currency(currency)?;
|
||||
let mut keypairs = dup_crypto::dewif::read_dewif_file_content(
|
||||
ExpectedCurrency::Specific(currency),
|
||||
|
@ -130,22 +89,11 @@ pub(super) fn sign(
|
|||
}
|
||||
|
||||
pub(super) fn sign_several(
|
||||
currency: *const raw::c_char,
|
||||
dewif: *const raw::c_char,
|
||||
pin: *const raw::c_char,
|
||||
msgs_len: usize,
|
||||
msgs: *const *const raw::c_char,
|
||||
currency: &str,
|
||||
dewif: &str,
|
||||
pin: &str,
|
||||
msgs: &[&str],
|
||||
) -> Result<Vec<String>, DubpError> {
|
||||
let currency = char_ptr_to_str(currency)?;
|
||||
let dewif = char_ptr_to_str(dewif)?;
|
||||
let pin = char_ptr_to_str(pin)?;
|
||||
|
||||
let msgs_slice: &[*const raw::c_char] = unsafe { std::slice::from_raw_parts(msgs, msgs_len) };
|
||||
let mut msgs = Vec::with_capacity(msgs_len);
|
||||
for ptr_c_char in msgs_slice {
|
||||
msgs.push(char_ptr_to_str(*ptr_c_char)?);
|
||||
}
|
||||
|
||||
let currency = parse_currency(currency)?;
|
||||
let mut keypairs = dup_crypto::dewif::read_dewif_file_content(
|
||||
ExpectedCurrency::Specific(currency),
|
||||
|
@ -163,92 +111,3 @@ pub(super) fn sign_several(
|
|||
Err(DubpError::DewifReadError(DewifReadError::CorruptedContent))
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_currency(currency: &str) -> Result<Currency, DubpError> {
|
||||
let currency_code = match currency {
|
||||
"g1" => G1_CURRENCY,
|
||||
"g1-test" | "gt" => G1_TEST_CURRENCY,
|
||||
_ => return Err(DubpError::UnknownCurrencyName),
|
||||
};
|
||||
Ok(Currency::from(currency_code))
|
||||
}
|
||||
|
||||
fn gen_pin2_inner(mut i: u32, pin: &mut String) {
|
||||
for _ in 0..2 {
|
||||
pin.push(to_char(i));
|
||||
i /= 35;
|
||||
}
|
||||
}
|
||||
fn gen_pin4_inner(mut i: u32, pin: &mut String) {
|
||||
for _ in 0..4 {
|
||||
pin.push(to_char(i));
|
||||
i /= 35;
|
||||
}
|
||||
}
|
||||
fn gen_pin6_inner(mut i: u32) -> String {
|
||||
let mut pin = String::new();
|
||||
|
||||
for _ in 0..6 {
|
||||
pin.push(to_char(i));
|
||||
i /= 35;
|
||||
}
|
||||
|
||||
pin
|
||||
}
|
||||
|
||||
fn to_char(i: u32) -> char {
|
||||
match i % 35 {
|
||||
0 => 'Z',
|
||||
1 => '1',
|
||||
2 => '2',
|
||||
3 => '3',
|
||||
4 => '4',
|
||||
5 => '5',
|
||||
6 => '6',
|
||||
7 => '7',
|
||||
8 => '8',
|
||||
9 => '9',
|
||||
10 => 'A',
|
||||
11 => 'B',
|
||||
12 => 'C',
|
||||
13 => 'D',
|
||||
14 => 'E',
|
||||
15 => 'F',
|
||||
16 => 'G',
|
||||
17 => 'H',
|
||||
18 => 'I',
|
||||
19 => 'J',
|
||||
20 => 'K',
|
||||
21 => 'L',
|
||||
22 => 'M',
|
||||
23 => 'N',
|
||||
24 => 'O',
|
||||
25 => 'P',
|
||||
26 => 'Q',
|
||||
27 => 'R',
|
||||
28 => 'S',
|
||||
29 => 'T',
|
||||
30 => 'U',
|
||||
31 => 'V',
|
||||
32 => 'W',
|
||||
33 => 'X',
|
||||
34 => 'Y',
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_gen_pin_6() {
|
||||
assert_eq!("ZZZZZZ", &gen_pin6_inner(0));
|
||||
assert_eq!("YZZZZZ", &gen_pin6_inner(34));
|
||||
assert_eq!("Z1ZZZZ", &gen_pin6_inner(35));
|
||||
assert_eq!("ZZ1ZZZ", &gen_pin6_inner(1225));
|
||||
assert_eq!("2Z1ZZZ", &gen_pin6_inner(1227));
|
||||
assert_eq!("Z11ZZZ", &gen_pin6_inner(1260));
|
||||
assert_eq!("111ZZZ", &gen_pin6_inner(1261));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,79 @@
|
|||
// Copyright (C) 2020 Éloïs SANCHEZ.
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as
|
||||
// published by the Free Software Foundation, either version 3 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
use crate::*;
|
||||
|
||||
/// Dubp error
|
||||
#[derive(Debug, Error)]
|
||||
pub(crate) enum DubpError {
|
||||
#[error("{0}")]
|
||||
DewifReadError(DewifReadError),
|
||||
#[error("I/O error: {0}")]
|
||||
IoErr(io::Error),
|
||||
#[error("Digits secret code forbid for member wallet")]
|
||||
DigitsCodeForbidForMemberWallet,
|
||||
#[error("A given parameter is null")]
|
||||
NullParamErr,
|
||||
#[error("fail to generate random bytes")]
|
||||
RandErr,
|
||||
#[error("Unknown currency name")]
|
||||
UnknownCurrencyName,
|
||||
#[error("Unknown language")]
|
||||
UnknownLanguage,
|
||||
#[error("{0}")]
|
||||
Utf8Error(std::str::Utf8Error),
|
||||
#[error("Wrong language")]
|
||||
WrongLanguage,
|
||||
}
|
||||
|
||||
impl From<io::Error> for DubpError {
|
||||
fn from(e: io::Error) -> Self {
|
||||
Self::IoErr(e)
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) struct DartRes(allo_isolate::ffi::DartCObject);
|
||||
impl DartRes {
|
||||
pub(crate) fn err<E: ToString>(e: E) -> allo_isolate::ffi::DartCObject {
|
||||
vec![format!("DUBP_RS_ERROR: {}", e.to_string())].into_dart()
|
||||
}
|
||||
}
|
||||
impl IntoDart for DartRes {
|
||||
fn into_dart(self) -> allo_isolate::ffi::DartCObject {
|
||||
self.0.into_dart()
|
||||
}
|
||||
}
|
||||
impl<E> From<Result<String, E>> for DartRes
|
||||
where
|
||||
E: ToString,
|
||||
{
|
||||
fn from(res: Result<String, E>) -> Self {
|
||||
match res {
|
||||
Ok(string) => Self(string.into_dart()),
|
||||
Err(e) => Self(format!("DUBP_RS_ERROR: {}", e.to_string()).into_dart()),
|
||||
}
|
||||
}
|
||||
}
|
||||
impl<E> From<Result<Vec<String>, E>> for DartRes
|
||||
where
|
||||
E: ToString,
|
||||
{
|
||||
fn from(res: Result<Vec<String>, E>) -> Self {
|
||||
match res {
|
||||
Ok(vec_string) => Self(vec_string.into_dart()),
|
||||
Err(e) => Self(vec![format!("DUBP_RS_ERROR: {}", e.to_string())].into_dart()),
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,69 @@
|
|||
// Copyright (C) 2020 Éloïs SANCHEZ.
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as
|
||||
// published by the Free Software Foundation, either version 3 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
use crate::*;
|
||||
|
||||
pub(crate) enum SecretCodeType {
|
||||
Digits,
|
||||
Letters,
|
||||
}
|
||||
impl From<u32> for SecretCodeType {
|
||||
fn from(i: u32) -> Self {
|
||||
if i == 0 {
|
||||
SecretCodeType::Digits
|
||||
} else {
|
||||
SecretCodeType::Letters
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn char_ptr_to_str<'a>(c_char_ptr: *const raw::c_char) -> Result<&'a str, DubpError> {
|
||||
if c_char_ptr.is_null() {
|
||||
Err(DubpError::NullParamErr)
|
||||
} else {
|
||||
unsafe { CStr::from_ptr(c_char_ptr).to_str() }.map_err(DubpError::Utf8Error)
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn char_ptr_prt_to_vec_str<'a>(
|
||||
char_ptr_ptr: *const *const raw::c_char,
|
||||
len: u32,
|
||||
) -> Result<Vec<&'a str>, DubpError> {
|
||||
let len = len as usize;
|
||||
let char_ptr_slice: &[*const raw::c_char] =
|
||||
unsafe { std::slice::from_raw_parts(char_ptr_ptr, len) };
|
||||
let mut str_vec = Vec::with_capacity(len);
|
||||
for char_ptr in char_ptr_slice {
|
||||
str_vec.push(char_ptr_to_str(*char_ptr)?);
|
||||
}
|
||||
Ok(str_vec)
|
||||
}
|
||||
|
||||
pub(crate) fn parse_currency(currency: &str) -> Result<Currency, DubpError> {
|
||||
let currency_code = match currency {
|
||||
"g1" => G1_CURRENCY,
|
||||
"g1-test" | "gt" => G1_TEST_CURRENCY,
|
||||
_ => return Err(DubpError::UnknownCurrencyName),
|
||||
};
|
||||
Ok(Currency::from(currency_code))
|
||||
}
|
||||
|
||||
pub(crate) fn u32_to_language(i: u32) -> Result<Language, DubpError> {
|
||||
match i {
|
||||
0 => Ok(Language::English),
|
||||
1 => Ok(Language::French),
|
||||
_ => Err(DubpError::UnknownLanguage),
|
||||
}
|
||||
}
|
|
@ -15,9 +15,17 @@
|
|||
|
||||
#![allow(clippy::missing_safety_doc, clippy::not_unsafe_ptr_arg_deref)]
|
||||
|
||||
mod r#async;
|
||||
mod dewif;
|
||||
mod error;
|
||||
mod inputs;
|
||||
mod mnemonic;
|
||||
mod secret_code;
|
||||
|
||||
use crate::error::{DartRes, DubpError};
|
||||
use crate::inputs::*;
|
||||
use crate::r#async::exec_async;
|
||||
use crate::secret_code::gen_secret_code;
|
||||
use allo_isolate::{IntoDart, Isolate};
|
||||
use dup_crypto::{
|
||||
bases::b58::ToBase58,
|
||||
|
@ -28,84 +36,34 @@ use dup_crypto::{
|
|||
},
|
||||
mnemonic::{Language, Mnemonic, MnemonicType},
|
||||
};
|
||||
use fast_threadpool::{ThreadPool, ThreadPoolConfig, ThreadPoolSyncHandler};
|
||||
use once_cell::sync::Lazy;
|
||||
use std::{ffi::CStr, io, os::raw};
|
||||
use thiserror::Error;
|
||||
|
||||
/// Dubp error
|
||||
#[derive(Debug, Error)]
|
||||
pub enum DubpError {
|
||||
#[error("{0}")]
|
||||
DewifReadError(DewifReadError),
|
||||
#[error("I/O error: {0}")]
|
||||
IoErr(io::Error),
|
||||
#[error("A given parameter is null")]
|
||||
NullParamErr,
|
||||
#[error("fail to generate random bytes")]
|
||||
RandErr,
|
||||
#[error("Unknown currency name")]
|
||||
UnknownCurrencyName,
|
||||
#[error("Unknown language")]
|
||||
UnknownLanguage,
|
||||
#[error("{0}")]
|
||||
Utf8Error(std::str::Utf8Error),
|
||||
#[error("Wrong language")]
|
||||
WrongLanguage,
|
||||
}
|
||||
|
||||
impl From<io::Error> for DubpError {
|
||||
fn from(e: io::Error) -> Self {
|
||||
Self::IoErr(e)
|
||||
}
|
||||
}
|
||||
|
||||
struct DartRes(allo_isolate::ffi::DartCObject);
|
||||
impl IntoDart for DartRes {
|
||||
fn into_dart(self) -> allo_isolate::ffi::DartCObject {
|
||||
self.0.into_dart()
|
||||
}
|
||||
}
|
||||
impl<E> From<Result<String, E>> for DartRes
|
||||
where
|
||||
E: ToString,
|
||||
{
|
||||
fn from(res: Result<String, E>) -> Self {
|
||||
match res {
|
||||
Ok(string) => Self(vec![string].into_dart()),
|
||||
Err(e) => Self(vec![String::from("_"), e.to_string()].into_dart()),
|
||||
}
|
||||
}
|
||||
}
|
||||
impl<E> From<Result<Vec<String>, E>> for DartRes
|
||||
where
|
||||
E: ToString,
|
||||
{
|
||||
fn from(res: Result<Vec<String>, E>) -> Self {
|
||||
match res {
|
||||
Ok(vec_string) => Self(vec_string.into_dart()),
|
||||
Err(e) => Self(vec![String::with_capacity(0), e.to_string()].into_dart()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn char_ptr_to_str<'a>(c_char_ptr: *const raw::c_char) -> Result<&'a str, DubpError> {
|
||||
if c_char_ptr.is_null() {
|
||||
Err(DubpError::NullParamErr)
|
||||
} else {
|
||||
unsafe { CStr::from_ptr(c_char_ptr).to_str() }.map_err(DubpError::Utf8Error)
|
||||
}
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn change_dewif_pin(
|
||||
pub extern "C" fn change_dewif_secret_code(
|
||||
port: i64,
|
||||
currency: *const raw::c_char,
|
||||
dewif: *const raw::c_char,
|
||||
old_pin: *const raw::c_char,
|
||||
new_pin: *const raw::c_char,
|
||||
member_wallet: u32,
|
||||
secret_code_type: u32,
|
||||
) {
|
||||
Isolate::new(port).post(DartRes::from(dewif::change_pin(
|
||||
currency, dewif, old_pin, new_pin,
|
||||
)));
|
||||
exec_async(
|
||||
port,
|
||||
|| {
|
||||
let currency = char_ptr_to_str(currency)?;
|
||||
let dewif = char_ptr_to_str(dewif)?;
|
||||
let old_pin = char_ptr_to_str(old_pin)?;
|
||||
let member_wallet = member_wallet != 0;
|
||||
let secret_code_type = SecretCodeType::from(secret_code_type);
|
||||
Ok((currency, dewif, old_pin, member_wallet, secret_code_type))
|
||||
},
|
||||
|(currency, dewif, old_pin, member_wallet, secret_code_type)| {
|
||||
dewif::change_secret_code(currency, dewif, old_pin, member_wallet, secret_code_type)
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
|
@ -114,11 +72,35 @@ pub extern "C" fn gen_dewif(
|
|||
currency: *const raw::c_char,
|
||||
language: u32,
|
||||
mnemonic: *const raw::c_char,
|
||||
pin: *const raw::c_char,
|
||||
member_wallet: u32,
|
||||
secret_code_type: u32,
|
||||
) {
|
||||
Isolate::new(port).post(DartRes::from(dewif::gen_dewif(
|
||||
currency, language, mnemonic, pin,
|
||||
)));
|
||||
exec_async(
|
||||
port,
|
||||
|| {
|
||||
let currency = char_ptr_to_str(currency)?;
|
||||
let language = u32_to_language(language)?;
|
||||
let mnemonic = char_ptr_to_str(mnemonic)?;
|
||||
let member_wallet = member_wallet != 0;
|
||||
let secret_code_type = SecretCodeType::from(secret_code_type);
|
||||
Ok((
|
||||
currency,
|
||||
language,
|
||||
mnemonic,
|
||||
member_wallet,
|
||||
secret_code_type,
|
||||
))
|
||||
},
|
||||
|(currency, language, mnemonic, member_wallet, secret_code_type)| {
|
||||
dewif::gen_dewif(
|
||||
currency,
|
||||
language,
|
||||
mnemonic,
|
||||
member_wallet,
|
||||
secret_code_type,
|
||||
)
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
|
@ -126,21 +108,6 @@ pub extern "C" fn gen_mnemonic(port: i64, language: u32) {
|
|||
Isolate::new(port).post(DartRes::from(mnemonic::gen_mnemonic(language)));
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn gen_pin6(port: i64) {
|
||||
Isolate::new(port).post(DartRes::from(dewif::gen_pin6()));
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn gen_pin8(port: i64) {
|
||||
Isolate::new(port).post(DartRes::from(dewif::gen_pin8()));
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn gen_pin10(port: i64) {
|
||||
Isolate::new(port).post(DartRes::from(dewif::gen_pin10()));
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn get_dewif_pubkey(
|
||||
port: i64,
|
||||
|
@ -148,7 +115,16 @@ pub extern "C" fn get_dewif_pubkey(
|
|||
dewif: *const raw::c_char,
|
||||
pin: *const raw::c_char,
|
||||
) {
|
||||
Isolate::new(port).post(DartRes::from(dewif::get_pubkey(currency, dewif, pin)));
|
||||
exec_async(
|
||||
port,
|
||||
|| {
|
||||
let currency = parse_currency(char_ptr_to_str(currency)?)?;
|
||||
let dewif = char_ptr_to_str(dewif)?;
|
||||
let pin = char_ptr_to_str(pin)?;
|
||||
Ok((currency, dewif, pin))
|
||||
},
|
||||
|(currency, dewif, pin)| dewif::get_pubkey(currency, dewif, pin),
|
||||
)
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
|
@ -157,10 +133,14 @@ pub extern "C" fn mnemonic_to_pubkey(
|
|||
language: u32,
|
||||
mnemonic_phrase: *const raw::c_char,
|
||||
) {
|
||||
Isolate::new(port).post(DartRes::from(mnemonic::mnemonic_to_pubkey(
|
||||
language,
|
||||
mnemonic_phrase,
|
||||
)));
|
||||
exec_async(
|
||||
port,
|
||||
|| {
|
||||
let mnemonic_phrase = char_ptr_to_str(mnemonic_phrase)?;
|
||||
Ok((language, mnemonic_phrase))
|
||||
},
|
||||
|(language, mnemonic_phrase)| mnemonic::mnemonic_to_pubkey(language, mnemonic_phrase),
|
||||
)
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
|
@ -171,7 +151,17 @@ pub extern "C" fn sign(
|
|||
pin: *const raw::c_char,
|
||||
msg: *const raw::c_char,
|
||||
) {
|
||||
Isolate::new(port).post(DartRes::from(dewif::sign(currency, dewif, pin, msg)));
|
||||
exec_async(
|
||||
port,
|
||||
|| {
|
||||
let currency = char_ptr_to_str(currency)?;
|
||||
let dewif = char_ptr_to_str(dewif)?;
|
||||
let pin = char_ptr_to_str(pin)?;
|
||||
let msg = char_ptr_to_str(msg)?;
|
||||
Ok((currency, dewif, pin, msg))
|
||||
},
|
||||
|(currency, dewif, pin, msg)| dewif::sign(currency, dewif, pin, msg),
|
||||
)
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
|
@ -180,16 +170,18 @@ pub extern "C" fn sign_several(
|
|||
currency: *const raw::c_char,
|
||||
dewif: *const raw::c_char,
|
||||
pin: *const raw::c_char,
|
||||
msgs_len: usize,
|
||||
msgs_len: u32,
|
||||
msgs: *const *const raw::c_char,
|
||||
) {
|
||||
Isolate::new(port).post(dewif::sign_several(currency, dewif, pin, msgs_len, msgs));
|
||||
}
|
||||
|
||||
fn u32_to_language(i: u32) -> Result<Language, DubpError> {
|
||||
match i {
|
||||
0 => Ok(Language::English),
|
||||
1 => Ok(Language::French),
|
||||
_ => Err(DubpError::UnknownLanguage),
|
||||
}
|
||||
exec_async(
|
||||
port,
|
||||
|| {
|
||||
let currency = char_ptr_to_str(currency)?;
|
||||
let dewif = char_ptr_to_str(dewif)?;
|
||||
let pin = char_ptr_to_str(pin)?;
|
||||
let msgs = char_ptr_prt_to_vec_str(msgs, msgs_len)?;
|
||||
Ok((currency, dewif, pin, msgs))
|
||||
},
|
||||
|(currency, dewif, pin, msgs)| dewif::sign_several(currency, dewif, pin, &msgs),
|
||||
)
|
||||
}
|
||||
|
|
|
@ -21,12 +21,7 @@ pub(super) fn gen_mnemonic(language: u32) -> Result<String, DubpError> {
|
|||
Ok(mnemonic.phrase().to_owned())
|
||||
}
|
||||
|
||||
pub(super) fn mnemonic_to_pubkey(
|
||||
language: u32,
|
||||
mnemonic: *const raw::c_char,
|
||||
) -> Result<String, DubpError> {
|
||||
let mnemonic = char_ptr_to_str(mnemonic)?;
|
||||
|
||||
pub(super) fn mnemonic_to_pubkey(language: u32, mnemonic: &str) -> Result<String, DubpError> {
|
||||
let mnemonic = Mnemonic::from_phrase(mnemonic, u32_to_language(language)?)
|
||||
.map_err(|_| DubpError::WrongLanguage)?;
|
||||
let seed = dup_crypto::mnemonic::mnemonic_to_seed(&mnemonic);
|
||||
|
|
|
@ -0,0 +1,130 @@
|
|||
// Copyright (C) 2020 Éloïs SANCHEZ.
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as
|
||||
// published by the Free Software Foundation, either version 3 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
use crate::*;
|
||||
|
||||
pub(crate) fn gen_secret_code(
|
||||
member_wallet: bool,
|
||||
secret_code_type: SecretCodeType,
|
||||
) -> Result<String, DubpError> {
|
||||
match secret_code_type {
|
||||
SecretCodeType::Digits => {
|
||||
if member_wallet {
|
||||
Err(DubpError::DigitsCodeForbidForMemberWallet)
|
||||
} else {
|
||||
gen_random_digits(8)
|
||||
}
|
||||
}
|
||||
SecretCodeType::Letters => {
|
||||
if member_wallet {
|
||||
gen_random_letters(10)
|
||||
} else {
|
||||
gen_random_letters(6)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn gen_random_digits(n: usize) -> Result<String, DubpError> {
|
||||
let mut digits_string = dup_crypto::rand::gen_u32()
|
||||
.map_err(|_| DubpError::RandErr)?
|
||||
.to_string();
|
||||
digits_string.truncate(n);
|
||||
|
||||
if digits_string.len() == n {
|
||||
Ok(digits_string)
|
||||
} else {
|
||||
let missing_digits = n - digits_string.len();
|
||||
let mut digits_string_ = String::with_capacity(n);
|
||||
for _ in 0..missing_digits {
|
||||
digits_string_.push('0');
|
||||
}
|
||||
digits_string_.push_str(&digits_string);
|
||||
Ok(digits_string_)
|
||||
}
|
||||
}
|
||||
|
||||
fn gen_random_letters(mut n: usize) -> Result<String, DubpError> {
|
||||
let mut letters = String::with_capacity(n);
|
||||
while n >= 6 {
|
||||
letters.push_str(&gen_random_letters_inner(6)?);
|
||||
n -= 6;
|
||||
}
|
||||
letters.push_str(&gen_random_letters_inner(n)?);
|
||||
|
||||
Ok(letters)
|
||||
}
|
||||
|
||||
fn gen_random_letters_inner(n: usize) -> Result<String, DubpError> {
|
||||
let mut i = dup_crypto::rand::gen_u32().map_err(|_| DubpError::RandErr)?;
|
||||
let mut letters = String::new();
|
||||
|
||||
for _ in 0..n {
|
||||
letters.push(to_char(i));
|
||||
i /= 26;
|
||||
}
|
||||
|
||||
Ok(letters)
|
||||
}
|
||||
|
||||
fn to_char(i: u32) -> char {
|
||||
match i % 26 {
|
||||
0 => 'A',
|
||||
1 => 'B',
|
||||
2 => 'C',
|
||||
3 => 'D',
|
||||
4 => 'E',
|
||||
5 => 'F',
|
||||
6 => 'G',
|
||||
7 => 'H',
|
||||
8 => 'I',
|
||||
9 => 'J',
|
||||
10 => 'K',
|
||||
11 => 'L',
|
||||
12 => 'M',
|
||||
13 => 'N',
|
||||
14 => 'O',
|
||||
15 => 'P',
|
||||
16 => 'Q',
|
||||
17 => 'R',
|
||||
18 => 'S',
|
||||
19 => 'T',
|
||||
20 => 'U',
|
||||
21 => 'V',
|
||||
22 => 'W',
|
||||
23 => 'X',
|
||||
24 => 'Y',
|
||||
25 => 'Z',
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_gen_random_digits() -> Result<(), DubpError> {
|
||||
assert_eq!(gen_random_digits(8)?.len(), 8);
|
||||
//println!("TMP: {}", gen_random_digits(8)?);
|
||||
Ok(())
|
||||
}
|
||||
#[test]
|
||||
fn test_gen_random_letters() -> Result<(), DubpError> {
|
||||
assert_eq!(gen_random_letters(6)?.len(), 6);
|
||||
//println!("TMP: {}", gen_random_letters(6)?);
|
||||
Ok(())
|
||||
}
|
||||
}
|
|
@ -57,7 +57,7 @@ The project use [`dart-bindgen`](https://github.com/sunshine-protocol/dart-bindg
|
|||
* 32bit emulator (`x86`/`i686` architecture)
|
||||
|
||||
```sh
|
||||
cargo make android-dev32
|
||||
cargo bd
|
||||
```
|
||||
|
||||
* 64bit emulator (`x86_64` architecture)
|
||||
|
@ -71,7 +71,7 @@ cargo make android-dev
|
|||
In the Root of the project simply run:
|
||||
|
||||
```sh
|
||||
cargo make
|
||||
cargo br
|
||||
```
|
||||
|
||||
WARNING: This will take a lot of time because the Rust code will have to be recompiled for each different architecture, 4 times for android and 2 times for iOS!
|
||||
|
@ -113,7 +113,7 @@ static Future<NewWallet> genWalletFromMnemonic({
|
|||
String currency = "g1",
|
||||
Language language = Language.english,
|
||||
String mnemonic,
|
||||
PinLength pinLength = PinLength.six
|
||||
SecretCodeType secretCodeType = SecretCodeType.letters
|
||||
});
|
||||
```
|
||||
|
||||
|
@ -129,13 +129,13 @@ NewWallet new_wallet = await DubpRust.genWalletFromMnemonic(
|
|||
);
|
||||
```
|
||||
|
||||
You can choose a different length for the pin code (6 by default):
|
||||
You can choose a different secret code type:
|
||||
|
||||
```dart
|
||||
NewWallet new_wallet = await DubpRust.genWalletFromMnemonic(
|
||||
language: Language.english,
|
||||
mnemonic: "tongue cute mail fossil great frozen same social weasel impact brush kind",
|
||||
pinLength: PinLength.eight
|
||||
secretCodeType: SecretCodeType.digits
|
||||
);
|
||||
```
|
||||
|
||||
|
@ -164,9 +164,9 @@ String signature = await DubpRust.sign(
|
|||
);
|
||||
```
|
||||
|
||||
### Change pin code
|
||||
### Change secret code
|
||||
|
||||
You can change the pin code that encrypts the [DEWIF].
|
||||
You can change the secret code that encrypts the [DEWIF].
|
||||
|
||||
#### Function signature
|
||||
|
||||
|
@ -175,7 +175,7 @@ static Future<NewWallet> changeDewifPin({
|
|||
String currency = "g1",
|
||||
String dewif,
|
||||
String oldPin,
|
||||
PinLength newPinLength = PinLength.six
|
||||
SecretCodeType secretCodeType = SecretCodeType.letters
|
||||
});
|
||||
```
|
||||
|
||||
|
@ -186,7 +186,7 @@ If the wallet is not dedicated to the Ğ1 currency, you must indicate the curren
|
|||
```dart
|
||||
NewWallet new_wallet = await DubpRust.changeDewifPin(
|
||||
dewif: "AAAAARAAAAGfFDAs+jVZYkfhBlHZZ2fEQIvBqnG16g5+02cY18wSOjW0cUg2JV3SUTJYN2CrbQeRDwGazWnzSFBphchMmiL0",
|
||||
oldPin: "CDJ4UB",
|
||||
oldPin: "CDJAUB",
|
||||
);
|
||||
```
|
||||
|
||||
|
|
|
@ -19,7 +19,7 @@ class NewWallet {
|
|||
/// DEWIF: Encrypted wallet
|
||||
String dewif;
|
||||
|
||||
/// Pin code
|
||||
/// Secret code
|
||||
String pin;
|
||||
|
||||
/// Public key
|
||||
|
@ -28,16 +28,13 @@ class NewWallet {
|
|||
NewWallet._(this.dewif, this.pin, this.publicKey);
|
||||
}
|
||||
|
||||
/// Pin code length
|
||||
enum PinLength {
|
||||
/// 6 characters
|
||||
six,
|
||||
/// Secret code type
|
||||
enum SecretCodeType {
|
||||
/// Digits
|
||||
digits,
|
||||
|
||||
/// 8 characters
|
||||
eight,
|
||||
|
||||
/// 10 characters
|
||||
ten,
|
||||
/// Letters
|
||||
letters,
|
||||
}
|
||||
|
||||
/// DUBP Rust utilities
|
||||
|
@ -55,7 +52,7 @@ class DubpRust {
|
|||
static Future<String> genMnemonic({Language language = Language.english}) {
|
||||
final completer = Completer<String>();
|
||||
final sendPort =
|
||||
singleCompletePort<String, List>(completer, callback: _handleErr);
|
||||
singleCompletePort<String, String>(completer, callback: _handleErr);
|
||||
native.gen_mnemonic(
|
||||
sendPort.nativePort,
|
||||
language.index,
|
||||
|
@ -63,70 +60,27 @@ class DubpRust {
|
|||
return completer.future;
|
||||
}
|
||||
|
||||
static Future<String> _genPin(PinLength pinLength) {
|
||||
final completer = Completer<String>();
|
||||
final sendPort =
|
||||
singleCompletePort<String, List>(completer, callback: _handleErr);
|
||||
switch (pinLength) {
|
||||
case PinLength.ten:
|
||||
native.gen_pin10(
|
||||
sendPort.nativePort,
|
||||
);
|
||||
break;
|
||||
case PinLength.eight:
|
||||
native.gen_pin8(
|
||||
sendPort.nativePort,
|
||||
);
|
||||
break;
|
||||
case PinLength.six:
|
||||
default:
|
||||
native.gen_pin6(
|
||||
sendPort.nativePort,
|
||||
);
|
||||
break;
|
||||
}
|
||||
return completer.future;
|
||||
}
|
||||
|
||||
/// Change the pin code that encrypts the `dewif` keypair.
|
||||
static Future<NewWallet> changeDewifPin(
|
||||
{String currency = "g1",
|
||||
/// Change the secret code that encrypts the `dewif` keypair.
|
||||
static Future<NewWallet> changeDewifPin({
|
||||
String currency = "g1",
|
||||
String dewif,
|
||||
String oldPin,
|
||||
PinLength newPinLength = PinLength.six}) async {
|
||||
// pin
|
||||
String newPin = await _genPin(newPinLength);
|
||||
// dewif
|
||||
String newDewif;
|
||||
{
|
||||
final completer = Completer<String>();
|
||||
final sendPort =
|
||||
singleCompletePort<String, List>(completer, callback: _handleErr);
|
||||
native.change_dewif_pin(
|
||||
SecretCodeType secretCodeType = SecretCodeType.letters,
|
||||
}) async {
|
||||
final completer = Completer<List<String>>();
|
||||
final sendPort = singleCompletePort<List<String>, List>(completer,
|
||||
callback: _handleErrList);
|
||||
native.change_dewif_secret_code(
|
||||
sendPort.nativePort,
|
||||
Utf8.toUtf8(currency),
|
||||
Utf8.toUtf8(dewif),
|
||||
Utf8.toUtf8(oldPin),
|
||||
Utf8.toUtf8(newPin),
|
||||
0,
|
||||
secretCodeType.index,
|
||||
);
|
||||
newDewif = await completer.future;
|
||||
}
|
||||
// publicKey
|
||||
String publicKey;
|
||||
{
|
||||
final completer = Completer<String>();
|
||||
final sendPort =
|
||||
singleCompletePort<String, List>(completer, callback: _handleErr);
|
||||
native.get_dewif_pubkey(
|
||||
sendPort.nativePort,
|
||||
Utf8.toUtf8(currency),
|
||||
Utf8.toUtf8(newDewif),
|
||||
Utf8.toUtf8(newPin),
|
||||
);
|
||||
publicKey = await completer.future;
|
||||
}
|
||||
List<String> newWallet = await completer.future;
|
||||
|
||||
return Future.value(NewWallet._(newDewif, newPin, publicKey));
|
||||
return Future.value(NewWallet._(newWallet[0], newWallet[1], newWallet[2]));
|
||||
}
|
||||
|
||||
/// Generate a wallet from a mnemonic phrase.
|
||||
|
@ -136,42 +90,26 @@ class DubpRust {
|
|||
///
|
||||
/// If the wallet to be generated is not dedicated to the Ğ1 currency, you
|
||||
/// must indicate the currency for which this wallet will be used.
|
||||
static Future<NewWallet> genWalletFromMnemonic(
|
||||
{String currency = "g1",
|
||||
static Future<NewWallet> genWalletFromMnemonic({
|
||||
String currency = "g1",
|
||||
Language language = Language.english,
|
||||
String mnemonic,
|
||||
PinLength pinLength = PinLength.six}) async {
|
||||
// pin
|
||||
String pin = await _genPin(pinLength);
|
||||
// publicKey
|
||||
String publicKey;
|
||||
{
|
||||
final completer = Completer<String>();
|
||||
final sendPort =
|
||||
singleCompletePort<String, List>(completer, callback: _handleErr);
|
||||
native.mnemonic_to_pubkey(
|
||||
sendPort.nativePort,
|
||||
language.index,
|
||||
Utf8.toUtf8(mnemonic),
|
||||
);
|
||||
publicKey = await completer.future;
|
||||
}
|
||||
// dewif
|
||||
String dewif;
|
||||
{
|
||||
final completer = Completer<String>();
|
||||
final sendPort =
|
||||
singleCompletePort<String, List>(completer, callback: _handleErr);
|
||||
SecretCodeType secretCodeType = SecretCodeType.letters,
|
||||
}) async {
|
||||
final completer = Completer<List<String>>();
|
||||
final sendPort = singleCompletePort<List<String>, List>(completer,
|
||||
callback: _handleErrList);
|
||||
native.gen_dewif(
|
||||
sendPort.nativePort,
|
||||
Utf8.toUtf8(currency),
|
||||
language.index,
|
||||
Utf8.toUtf8(mnemonic),
|
||||
Utf8.toUtf8(pin),
|
||||
0,
|
||||
secretCodeType.index,
|
||||
);
|
||||
dewif = await completer.future;
|
||||
}
|
||||
return Future.value(NewWallet._(dewif, pin, publicKey));
|
||||
List<String> newWallet = await completer.future;
|
||||
|
||||
return Future.value(NewWallet._(newWallet[0], newWallet[1], newWallet[2]));
|
||||
}
|
||||
|
||||
/// Get pulblic key (in base 58) of `dewif` keypair.
|
||||
|
@ -179,7 +117,7 @@ class DubpRust {
|
|||
{String currency = "g1", String dewif, String pin}) async {
|
||||
final completer = Completer<String>();
|
||||
final sendPort =
|
||||
singleCompletePort<String, List>(completer, callback: _handleErr);
|
||||
singleCompletePort<String, String>(completer, callback: _handleErr);
|
||||
native.get_dewif_pubkey(
|
||||
sendPort.nativePort,
|
||||
Utf8.toUtf8(currency),
|
||||
|
@ -196,7 +134,7 @@ class DubpRust {
|
|||
{String currency = "g1", String dewif, String pin, String message}) {
|
||||
final completer = Completer<String>();
|
||||
final sendPort =
|
||||
singleCompletePort<String, List>(completer, callback: _handleErr);
|
||||
singleCompletePort<String, String>(completer, callback: _handleErr);
|
||||
native.sign(
|
||||
sendPort.nativePort,
|
||||
Utf8.toUtf8(currency),
|
||||
|
@ -243,21 +181,20 @@ class DubpRust {
|
|||
return ptr;
|
||||
}
|
||||
|
||||
static String _handleErr(List res) {
|
||||
final List<String> arr = res.cast();
|
||||
if (arr.length == 1) {
|
||||
return arr[0];
|
||||
} else {
|
||||
final error = arr[1];
|
||||
static String _handleErr(String res) {
|
||||
if (res.startsWith('DUBP_RS_ERROR: ')) {
|
||||
final error = res;
|
||||
print(error);
|
||||
throw error;
|
||||
} else {
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
static List<String> _handleErrList(List res) {
|
||||
final List<String> arr = res.cast();
|
||||
if (arr.isNotEmpty && arr[0].isEmpty) {
|
||||
final error = arr[1];
|
||||
if (arr.isNotEmpty && arr[0].startsWith('DUBP_RS_ERROR: ')) {
|
||||
final error = arr[0];
|
||||
print(error);
|
||||
throw error;
|
||||
} else {
|
||||
|
|
45
pubspec.lock
45
pubspec.lock
|
@ -21,42 +21,42 @@ packages:
|
|||
name: async
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.5.0-nullsafety.3"
|
||||
version: "2.5.0-nullsafety.1"
|
||||
boolean_selector:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: boolean_selector
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.1.0-nullsafety.3"
|
||||
version: "2.1.0-nullsafety.1"
|
||||
characters:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: characters
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.1.0-nullsafety.5"
|
||||
version: "1.1.0-nullsafety.3"
|
||||
charcode:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: charcode
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.2.0-nullsafety.3"
|
||||
version: "1.2.0-nullsafety.1"
|
||||
clock:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: clock
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.1.0-nullsafety.3"
|
||||
version: "1.1.0-nullsafety.1"
|
||||
collection:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: collection
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.15.0-nullsafety.5"
|
||||
version: "1.15.0-nullsafety.3"
|
||||
connectivity:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -112,7 +112,7 @@ packages:
|
|||
name: fake_async
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.2.0-nullsafety.3"
|
||||
version: "1.2.0-nullsafety.1"
|
||||
ffi:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -282,27 +282,20 @@ packages:
|
|||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.0.3"
|
||||
js:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: js
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "0.6.3-nullsafety.3"
|
||||
matcher:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: matcher
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "0.12.10-nullsafety.3"
|
||||
version: "0.12.10-nullsafety.1"
|
||||
meta:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: meta
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.3.0-nullsafety.6"
|
||||
version: "1.3.0-nullsafety.3"
|
||||
nested:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -330,7 +323,7 @@ packages:
|
|||
name: path
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.8.0-nullsafety.3"
|
||||
version: "1.8.0-nullsafety.1"
|
||||
path_provider:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
|
@ -468,42 +461,42 @@ packages:
|
|||
name: source_span
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.8.0-nullsafety.4"
|
||||
version: "1.8.0-nullsafety.2"
|
||||
stack_trace:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: stack_trace
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.10.0-nullsafety.6"
|
||||
version: "1.10.0-nullsafety.1"
|
||||
stream_channel:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: stream_channel
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.1.0-nullsafety.3"
|
||||
version: "2.1.0-nullsafety.1"
|
||||
string_scanner:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: string_scanner
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.1.0-nullsafety.3"
|
||||
version: "1.1.0-nullsafety.1"
|
||||
term_glyph:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: term_glyph
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.2.0-nullsafety.3"
|
||||
version: "1.2.0-nullsafety.1"
|
||||
test_api:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: test_api
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "0.2.19-nullsafety.6"
|
||||
version: "0.2.19-nullsafety.2"
|
||||
truncate:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
|
@ -517,7 +510,7 @@ packages:
|
|||
name: typed_data
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.3.0-nullsafety.5"
|
||||
version: "1.3.0-nullsafety.3"
|
||||
uuid:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -538,7 +531,7 @@ packages:
|
|||
name: vector_math
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.1.0-nullsafety.5"
|
||||
version: "2.1.0-nullsafety.3"
|
||||
websocket:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -575,5 +568,5 @@ packages:
|
|||
source: hosted
|
||||
version: "2.2.1"
|
||||
sdks:
|
||||
dart: ">=2.12.0-0.0 <3.0.0"
|
||||
dart: ">=2.10.0-110 <2.11.0"
|
||||
flutter: ">=1.22.0 <2.0.0"
|
||||
|
|
Loading…
Reference in New Issue