feat(dubp): impl opaque hd wallet
This commit is contained in:
parent
d551a3032c
commit
57e2a88116
|
@ -58,6 +58,12 @@ version = "0.5.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "23b62fc65de8e4e7f52534fb52b0f3ed04746ae267519eef2a83941e8085068b"
|
checksum = "23b62fc65de8e4e7f52534fb52b0f3ed04746ae267519eef2a83941e8085068b"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "assert_matches"
|
||||||
|
version = "1.5.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9b34d609dfbaf33d6889b2b7106d3ca345eacad44200913df5ba02bfd31d2ba9"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "async-oneshot"
|
name = "async-oneshot"
|
||||||
version = "0.4.2"
|
version = "0.4.2"
|
||||||
|
@ -250,19 +256,21 @@ name = "dubp_rs"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"allo-isolate",
|
"allo-isolate",
|
||||||
|
"assert_matches",
|
||||||
"cbindgen",
|
"cbindgen",
|
||||||
"dart-bindgen",
|
"dart-bindgen",
|
||||||
"dup-crypto",
|
"dup-crypto",
|
||||||
"fast-threadpool",
|
"fast-threadpool",
|
||||||
"once_cell",
|
"once_cell",
|
||||||
|
"parking_lot",
|
||||||
"thiserror",
|
"thiserror",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "dup-crypto"
|
name = "dup-crypto"
|
||||||
version = "0.44.0"
|
version = "0.45.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e4281497a99e7bb67d54800671558d707c48ca35320f8c5747fb0eda4d8cbc71"
|
checksum = "58a3b88cbd886b092a7e6c58608d87744706e0fc66a48eaf452c297e5aac3802"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"aes",
|
"aes",
|
||||||
"arrayvec",
|
"arrayvec",
|
||||||
|
@ -272,7 +280,7 @@ dependencies = [
|
||||||
"byteorder",
|
"byteorder",
|
||||||
"cryptoxide",
|
"cryptoxide",
|
||||||
"ed25519-bip32",
|
"ed25519-bip32",
|
||||||
"getrandom 0.2.2",
|
"getrandom",
|
||||||
"once_cell",
|
"once_cell",
|
||||||
"ring",
|
"ring",
|
||||||
"serde",
|
"serde",
|
||||||
|
@ -326,17 +334,6 @@ dependencies = [
|
||||||
"version_check",
|
"version_check",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "getrandom"
|
|
||||||
version = "0.1.16"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce"
|
|
||||||
dependencies = [
|
|
||||||
"cfg-if 1.0.0",
|
|
||||||
"libc",
|
|
||||||
"wasi 0.9.0+wasi-snapshot-preview1",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "getrandom"
|
name = "getrandom"
|
||||||
version = "0.2.2"
|
version = "0.2.2"
|
||||||
|
@ -345,7 +342,7 @@ checksum = "c9495705279e7140bf035dde1f6e750c162df8b625267cd52cc44e0b156732c8"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if 1.0.0",
|
"cfg-if 1.0.0",
|
||||||
"libc",
|
"libc",
|
||||||
"wasi 0.10.2+wasi-snapshot-preview1",
|
"wasi",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -372,6 +369,15 @@ dependencies = [
|
||||||
"libc",
|
"libc",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "instant"
|
||||||
|
version = "0.1.9"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "61124eeebbd69b8190558df225adf7e4caafce0d743919e5d6b19652314ec5ec"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if 1.0.0",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "itoa"
|
name = "itoa"
|
||||||
version = "0.4.7"
|
version = "0.4.7"
|
||||||
|
@ -439,6 +445,31 @@ version = "0.3.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5"
|
checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "parking_lot"
|
||||||
|
version = "0.11.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "6d7744ac029df22dca6284efe4e898991d28e3085c706c972bcd7da4a27a15eb"
|
||||||
|
dependencies = [
|
||||||
|
"instant",
|
||||||
|
"lock_api",
|
||||||
|
"parking_lot_core",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "parking_lot_core"
|
||||||
|
version = "0.8.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "fa7a782938e745763fe6907fc6ba86946d72f49fe7e21de074e08128a99fb018"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if 1.0.0",
|
||||||
|
"instant",
|
||||||
|
"libc",
|
||||||
|
"redox_syscall",
|
||||||
|
"smallvec",
|
||||||
|
"winapi",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ppv-lite86"
|
name = "ppv-lite86"
|
||||||
version = "0.2.10"
|
version = "0.2.10"
|
||||||
|
@ -465,11 +496,10 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rand"
|
name = "rand"
|
||||||
version = "0.7.3"
|
version = "0.8.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03"
|
checksum = "0ef9e7e66b4468674bfcb0c81af8b7fa0bb154fa9f28eb840da5c447baeb8d7e"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"getrandom 0.1.16",
|
|
||||||
"libc",
|
"libc",
|
||||||
"rand_chacha",
|
"rand_chacha",
|
||||||
"rand_core",
|
"rand_core",
|
||||||
|
@ -478,9 +508,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rand_chacha"
|
name = "rand_chacha"
|
||||||
version = "0.2.2"
|
version = "0.3.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402"
|
checksum = "e12735cf05c9e10bf21534da50a147b924d555dc7a547c42e6bb2d5b6017ae0d"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"ppv-lite86",
|
"ppv-lite86",
|
||||||
"rand_core",
|
"rand_core",
|
||||||
|
@ -488,27 +518,30 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rand_core"
|
name = "rand_core"
|
||||||
version = "0.5.1"
|
version = "0.6.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19"
|
checksum = "34cf66eb183df1c5876e2dcf6b13d57340741e8dc255b48e40a26de954d06ae7"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"getrandom 0.1.16",
|
"getrandom",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rand_hc"
|
name = "rand_hc"
|
||||||
version = "0.2.0"
|
version = "0.3.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c"
|
checksum = "3190ef7066a446f2e7f42e239d161e905420ccab01eb967c9eb27d21b2322a73"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"rand_core",
|
"rand_core",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "redox_syscall"
|
name = "redox_syscall"
|
||||||
version = "0.1.57"
|
version = "0.2.5"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "41cc0f7e4d5d4544e8861606a285bb08d3e70712ccc7d2b84d7c0ccfaf4b05ce"
|
checksum = "94341e4e44e24f6b591b59e47a8a027df12e008d73fd5672dbea9cc22f4507d9"
|
||||||
|
dependencies = [
|
||||||
|
"bitflags",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "remove_dir_all"
|
name = "remove_dir_all"
|
||||||
|
@ -577,6 +610,12 @@ dependencies = [
|
||||||
"serde",
|
"serde",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "smallvec"
|
||||||
|
version = "1.6.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "fe0f37c9e8f3c5a4a66ad655a93c74daac4ad00c441533bf5c6e7990bb42604e"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "spin"
|
name = "spin"
|
||||||
version = "0.5.2"
|
version = "0.5.2"
|
||||||
|
@ -629,11 +668,11 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tempfile"
|
name = "tempfile"
|
||||||
version = "3.1.0"
|
version = "3.2.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "7a6e24d9338a0a5be79593e2fa15a648add6138caa803e2d5bc782c371732ca9"
|
checksum = "dac1c663cfc93810f88aed9b8941d48cabf856a1b111c29a40439018d870eb22"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if 0.1.10",
|
"cfg-if 1.0.0",
|
||||||
"libc",
|
"libc",
|
||||||
"rand",
|
"rand",
|
||||||
"redox_syscall",
|
"redox_syscall",
|
||||||
|
@ -721,12 +760,6 @@ version = "0.9.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b5a972e5669d67ba988ce3dc826706fb0a8b01471c088cb0b6110b805cc36aed"
|
checksum = "b5a972e5669d67ba988ce3dc826706fb0a8b01471c088cb0b6110b805cc36aed"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "wasi"
|
|
||||||
version = "0.9.0+wasi-snapshot-preview1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wasi"
|
name = "wasi"
|
||||||
version = "0.10.2+wasi-snapshot-preview1"
|
version = "0.10.2+wasi-snapshot-preview1"
|
||||||
|
|
|
@ -11,11 +11,15 @@ crate-type = ["rlib"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
allo-isolate = "0.1.6"
|
allo-isolate = "0.1.6"
|
||||||
dup-crypto = { version = "0.44.0", features = ["bip32-ed25519", "dewif", "mnemonic", "mnemonic_french", "scrypt"] }
|
dup-crypto = { version = "0.45.0", features = ["bip32-ed25519", "dewif", "mnemonic", "mnemonic_french", "scrypt"] }
|
||||||
fast-threadpool = { version = "0.3.0", default-features = false }
|
fast-threadpool = { version = "0.3.0", default-features = false }
|
||||||
once_cell = { version = "1.3.1", default-features = false, features = ["std"] }
|
once_cell = { version = "1.3.1", default-features = false, features = ["std"] }
|
||||||
|
parking_lot = "0.11.1"
|
||||||
thiserror = "1.0.24"
|
thiserror = "1.0.24"
|
||||||
|
|
||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
cbindgen = "0.14.3"
|
cbindgen = "0.14.3"
|
||||||
dart-bindgen = "0.1.7"
|
dart-bindgen = "0.1.7"
|
||||||
|
|
||||||
|
[dev-dependencies]
|
||||||
|
assert_matches = "1.5.0"
|
||||||
|
|
|
@ -81,10 +81,23 @@ pub(super) fn get_dewif_meta(
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) fn get_pubkey(
|
pub(super) fn get_pubkey(
|
||||||
|
account_index_opt: Option<u32>,
|
||||||
|
address_index_opt: Option<U31>,
|
||||||
currency: Currency,
|
currency: Currency,
|
||||||
dewif: &str,
|
dewif: &str,
|
||||||
|
external_opt: Option<bool>,
|
||||||
secret_code: &str,
|
secret_code: &str,
|
||||||
) -> Result<String, DubpError> {
|
) -> Result<String, DubpError> {
|
||||||
|
if let Some(account_index) = account_index_opt {
|
||||||
|
dewif::bip32::get_bip32_pubkey(
|
||||||
|
account_index,
|
||||||
|
address_index_opt,
|
||||||
|
currency,
|
||||||
|
dewif,
|
||||||
|
external_opt,
|
||||||
|
secret_code,
|
||||||
|
)
|
||||||
|
} else if address_index_opt.is_none() && external_opt.is_none() {
|
||||||
let mut keypairs = dup_crypto::dewif::read_dewif_file_content(
|
let mut keypairs = dup_crypto::dewif::read_dewif_file_content(
|
||||||
ExpectedCurrency::Specific(currency),
|
ExpectedCurrency::Specific(currency),
|
||||||
dewif,
|
dewif,
|
||||||
|
@ -98,6 +111,9 @@ pub(super) fn get_pubkey(
|
||||||
Some(_) => Err(DubpError::UnsupportedDewifVersion),
|
Some(_) => Err(DubpError::UnsupportedDewifVersion),
|
||||||
None => Err(DubpError::DewifReadError(DewifReadError::CorruptedContent)),
|
None => Err(DubpError::DewifReadError(DewifReadError::CorruptedContent)),
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
Err(DubpError::GiveExternalBoolOrAddressIndexForLegacyWallet)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) fn get_secret_code_len(
|
pub(super) fn get_secret_code_len(
|
||||||
|
@ -126,3 +142,51 @@ pub(crate) fn log_n(system_memory: i64) -> u8 {
|
||||||
12
|
12
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(super) fn sign(
|
||||||
|
account_index_opt: Option<u32>,
|
||||||
|
address_index_opt: Option<U31>,
|
||||||
|
currency: Currency,
|
||||||
|
dewif: &str,
|
||||||
|
external_opt: Option<bool>,
|
||||||
|
secret_code: &str,
|
||||||
|
msg: &str,
|
||||||
|
) -> Result<String, DubpError> {
|
||||||
|
if let Some(account_index) = account_index_opt {
|
||||||
|
dewif::bip32::sign_bip32(
|
||||||
|
account_index,
|
||||||
|
address_index_opt,
|
||||||
|
currency,
|
||||||
|
dewif,
|
||||||
|
external_opt,
|
||||||
|
secret_code,
|
||||||
|
msg,
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
dewif::classic::sign(currency, dewif, secret_code, msg)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(super) fn sign_several(
|
||||||
|
account_index_opt: Option<u32>,
|
||||||
|
address_index_opt: Option<U31>,
|
||||||
|
currency: Currency,
|
||||||
|
dewif: &str,
|
||||||
|
external_opt: Option<bool>,
|
||||||
|
secret_code: &str,
|
||||||
|
msgs: &[&str],
|
||||||
|
) -> Result<Vec<String>, DubpError> {
|
||||||
|
if let Some(account_index) = account_index_opt {
|
||||||
|
dewif::bip32::sign_several_bip32(
|
||||||
|
account_index,
|
||||||
|
address_index_opt,
|
||||||
|
currency,
|
||||||
|
dewif,
|
||||||
|
external_opt,
|
||||||
|
secret_code,
|
||||||
|
msgs,
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
dewif::classic::sign_several(currency, dewif, secret_code, msgs)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -15,30 +15,24 @@
|
||||||
|
|
||||||
use crate::*;
|
use crate::*;
|
||||||
|
|
||||||
const MEMBER_ACCOUNT_INDEX: u32 = 0;
|
#[derive(Debug)]
|
||||||
|
struct OpaqueAccount {
|
||||||
|
address_index: u32,
|
||||||
|
chain_code: ChainCode,
|
||||||
|
public_key: PublicKey,
|
||||||
|
}
|
||||||
|
|
||||||
|
static CHAINING_EXTERNAL_PUBKEYS: Lazy<Arc<Mutex<HashMap<u32, OpaqueAccount>>>> =
|
||||||
|
Lazy::new(|| Arc::new(Mutex::new(HashMap::new())));
|
||||||
|
|
||||||
pub(crate) fn get_accounts_pubkeys(
|
pub(crate) fn get_accounts_pubkeys(
|
||||||
currency: Currency,
|
currency: Currency,
|
||||||
dewif: &str,
|
dewif: &str,
|
||||||
secret_code: &str,
|
secret_code: &str,
|
||||||
accounts_indexs: Vec<DerivationIndex>,
|
accounts_indexs: Vec<U31>,
|
||||||
) -> Result<Vec<String>, DubpError> {
|
) -> Result<Vec<String>, DubpError> {
|
||||||
if accounts_indexs.contains(
|
if accounts_indexs.contains(&U31::new(0)?) {
|
||||||
&DerivationIndex::hard(MEMBER_ACCOUNT_INDEX).map_err(DubpError::InvalidDerivationIndex)?,
|
verify_member_secret_code(currency, dewif, secret_code)?;
|
||||||
) {
|
|
||||||
if crate::secret_code::is_ascii_letters(secret_code) {
|
|
||||||
let log_n =
|
|
||||||
dup_crypto::dewif::read_dewif_log_n(ExpectedCurrency::Specific(currency), dewif)
|
|
||||||
.map_err(DubpError::DewifReadError)?;
|
|
||||||
let expected_secret_code_len =
|
|
||||||
crate::secret_code::compute_secret_code_len(true, SecretCodeType::Letters, log_n)?;
|
|
||||||
|
|
||||||
if secret_code.len() < expected_secret_code_len {
|
|
||||||
return Err(DubpError::SecretCodeTooShort);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return Err(DubpError::InvalidSecretCodeType);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
let mut keypairs = dup_crypto::dewif::read_dewif_file_content(
|
let mut keypairs = dup_crypto::dewif::read_dewif_file_content(
|
||||||
ExpectedCurrency::Specific(currency),
|
ExpectedCurrency::Specific(currency),
|
||||||
|
@ -50,25 +44,109 @@ pub(crate) fn get_accounts_pubkeys(
|
||||||
Some(KeyPairEnum::Bip32Ed25519(master_keypair)) => Ok(accounts_indexs
|
Some(KeyPairEnum::Bip32Ed25519(master_keypair)) => Ok(accounts_indexs
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|account_index| {
|
.map(|account_index| {
|
||||||
master_keypair
|
PrivateDerivationPath::transparent(account_index)
|
||||||
.derive(account_index)
|
.map(|path| master_keypair.derive(path).public_key().to_base58())
|
||||||
.public_key()
|
|
||||||
.to_base58()
|
|
||||||
})
|
})
|
||||||
.collect()),
|
.collect::<Result<Vec<_>, InvalidAccountIndex>>()?),
|
||||||
Some(_) => Err(DubpError::NotHdWallet),
|
Some(_) => Err(DubpError::NotHdWallet),
|
||||||
None => Err(DubpError::DewifReadError(DewifReadError::CorruptedContent)),
|
None => Err(DubpError::DewifReadError(DewifReadError::CorruptedContent)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn sign_transparent(
|
pub(crate) fn get_bip32_pubkey(
|
||||||
account_index: DerivationIndex,
|
account_index: u32,
|
||||||
currency: &str,
|
address_index_opt: Option<U31>,
|
||||||
|
currency: Currency,
|
||||||
dewif: &str,
|
dewif: &str,
|
||||||
|
external_opt: Option<bool>,
|
||||||
|
secret_code: &str,
|
||||||
|
) -> Result<String, DubpError> {
|
||||||
|
let mut keypairs = dup_crypto::dewif::read_dewif_file_content(
|
||||||
|
ExpectedCurrency::Specific(currency),
|
||||||
|
dewif,
|
||||||
|
&secret_code.to_ascii_uppercase(),
|
||||||
|
)
|
||||||
|
.map_err(DubpError::DewifReadError)?;
|
||||||
|
|
||||||
|
if account_index == 0 {
|
||||||
|
verify_member_secret_code(currency, dewif, secret_code)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
match keypairs.next() {
|
||||||
|
Some(KeyPairEnum::Bip32Ed25519(master_keypair)) => get_bip32_pubkey_inner(
|
||||||
|
account_index,
|
||||||
|
address_index_opt,
|
||||||
|
external_opt,
|
||||||
|
master_keypair,
|
||||||
|
),
|
||||||
|
Some(_) => Err(DubpError::NotHdWallet),
|
||||||
|
None => Err(DubpError::DewifReadError(DewifReadError::CorruptedContent)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn get_opaque_account_next_external_address(
|
||||||
|
account_index: U31,
|
||||||
|
) -> Result<String, DubpError> {
|
||||||
|
let mut guard = CHAINING_EXTERNAL_PUBKEYS.lock();
|
||||||
|
if let Some(opaque_account) = guard.get_mut(&account_index.into_u32()) {
|
||||||
|
let next_address = PublicKeyWithChainCode {
|
||||||
|
chain_code: opaque_account.chain_code,
|
||||||
|
public_key: opaque_account.public_key,
|
||||||
|
}
|
||||||
|
.derive(U31::new(opaque_account.address_index).expect("unreachable"))
|
||||||
|
.expect("unreachable")
|
||||||
|
.public_key;
|
||||||
|
|
||||||
|
opaque_account.address_index += 1;
|
||||||
|
|
||||||
|
Ok(next_address.to_base58())
|
||||||
|
} else {
|
||||||
|
Err(DubpError::OpaqueAccountNotLoaded)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn load_opaque_bip32_accounts(
|
||||||
|
accounts_indexs: Vec<U31>,
|
||||||
|
currency: Currency,
|
||||||
|
dewif: &str,
|
||||||
|
secret_code: &str,
|
||||||
|
) -> Result<(), DubpError> {
|
||||||
|
let mut keypairs = dup_crypto::dewif::read_dewif_file_content(
|
||||||
|
ExpectedCurrency::Specific(currency),
|
||||||
|
dewif,
|
||||||
|
&secret_code.to_ascii_uppercase(),
|
||||||
|
)
|
||||||
|
.map_err(DubpError::DewifReadError)?;
|
||||||
|
match keypairs.next() {
|
||||||
|
Some(KeyPairEnum::Bip32Ed25519(master_keypair)) => {
|
||||||
|
for account_index in accounts_indexs {
|
||||||
|
let external_path = PrivateDerivationPath::opaque(account_index, true, None)?;
|
||||||
|
let external_kp = master_keypair.derive(external_path);
|
||||||
|
let opaque_account = OpaqueAccount {
|
||||||
|
address_index: 0,
|
||||||
|
public_key: external_kp.public_key(),
|
||||||
|
chain_code: external_kp.chain_code(),
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut guard = CHAINING_EXTERNAL_PUBKEYS.lock();
|
||||||
|
guard.insert(account_index.into_u32(), opaque_account);
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
Some(_) => Err(DubpError::NotHdWallet),
|
||||||
|
None => Err(DubpError::DewifReadError(DewifReadError::CorruptedContent)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn sign_bip32(
|
||||||
|
account_index: u32,
|
||||||
|
address_index_opt: Option<U31>,
|
||||||
|
currency: Currency,
|
||||||
|
dewif: &str,
|
||||||
|
external_opt: Option<bool>,
|
||||||
secret_code: &str,
|
secret_code: &str,
|
||||||
msg: &str,
|
msg: &str,
|
||||||
) -> Result<String, DubpError> {
|
) -> Result<String, DubpError> {
|
||||||
let currency = parse_currency(currency)?;
|
|
||||||
let mut keypairs = dup_crypto::dewif::read_dewif_file_content(
|
let mut keypairs = dup_crypto::dewif::read_dewif_file_content(
|
||||||
ExpectedCurrency::Specific(currency),
|
ExpectedCurrency::Specific(currency),
|
||||||
dewif,
|
dewif,
|
||||||
|
@ -76,25 +154,32 @@ pub(crate) fn sign_transparent(
|
||||||
)
|
)
|
||||||
.map_err(DubpError::DewifReadError)?;
|
.map_err(DubpError::DewifReadError)?;
|
||||||
|
|
||||||
|
if account_index == 0 {
|
||||||
|
verify_member_secret_code(currency, dewif, secret_code)?;
|
||||||
|
}
|
||||||
|
|
||||||
match keypairs.next() {
|
match keypairs.next() {
|
||||||
Some(KeyPairEnum::Bip32Ed25519(master_keypair)) => Ok(master_keypair
|
Some(KeyPairEnum::Bip32Ed25519(master_keypair)) => sign_bip32_inner(
|
||||||
.derive(account_index)
|
account_index,
|
||||||
.generate_signator()
|
address_index_opt,
|
||||||
.sign(msg.as_bytes())
|
external_opt,
|
||||||
.to_base64()),
|
master_keypair,
|
||||||
|
msg,
|
||||||
|
),
|
||||||
Some(_) => Err(DubpError::NotHdWallet),
|
Some(_) => Err(DubpError::NotHdWallet),
|
||||||
None => Err(DubpError::DewifReadError(DewifReadError::CorruptedContent)),
|
None => Err(DubpError::DewifReadError(DewifReadError::CorruptedContent)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn sign_several_transparent(
|
pub(crate) fn sign_several_bip32(
|
||||||
account_index: DerivationIndex,
|
account_index: u32,
|
||||||
currency: &str,
|
address_index_opt: Option<U31>,
|
||||||
|
currency: Currency,
|
||||||
dewif: &str,
|
dewif: &str,
|
||||||
|
external_opt: Option<bool>,
|
||||||
secret_code: &str,
|
secret_code: &str,
|
||||||
msgs: &[&str],
|
msgs: &[&str],
|
||||||
) -> Result<Vec<String>, DubpError> {
|
) -> Result<Vec<String>, DubpError> {
|
||||||
let currency = parse_currency(currency)?;
|
|
||||||
let mut keypairs = dup_crypto::dewif::read_dewif_file_content(
|
let mut keypairs = dup_crypto::dewif::read_dewif_file_content(
|
||||||
ExpectedCurrency::Specific(currency),
|
ExpectedCurrency::Specific(currency),
|
||||||
dewif,
|
dewif,
|
||||||
|
@ -102,15 +187,206 @@ pub(crate) fn sign_several_transparent(
|
||||||
)
|
)
|
||||||
.map_err(DubpError::DewifReadError)?;
|
.map_err(DubpError::DewifReadError)?;
|
||||||
|
|
||||||
|
if account_index == 0 {
|
||||||
|
verify_member_secret_code(currency, dewif, secret_code)?;
|
||||||
|
}
|
||||||
|
|
||||||
match keypairs.next() {
|
match keypairs.next() {
|
||||||
Some(KeyPairEnum::Bip32Ed25519(master_keypair)) => {
|
Some(KeyPairEnum::Bip32Ed25519(master_keypair)) => sign_several_bip32_inner(
|
||||||
let signator = master_keypair.derive(account_index).generate_signator();
|
account_index,
|
||||||
|
address_index_opt,
|
||||||
|
external_opt,
|
||||||
|
master_keypair,
|
||||||
|
msgs,
|
||||||
|
),
|
||||||
|
Some(_) => Err(DubpError::NotHdWallet),
|
||||||
|
None => Err(DubpError::DewifReadError(DewifReadError::CorruptedContent)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_bip32_pubkey_inner(
|
||||||
|
account_index: u32,
|
||||||
|
address_index_opt: Option<U31>,
|
||||||
|
external_opt: Option<bool>,
|
||||||
|
master_keypair: KeyPair,
|
||||||
|
) -> Result<String, DubpError> {
|
||||||
|
Ok(master_keypair
|
||||||
|
.derive(z_get_derivation_path(
|
||||||
|
account_index,
|
||||||
|
address_index_opt,
|
||||||
|
external_opt,
|
||||||
|
)?)
|
||||||
|
.public_key()
|
||||||
|
.to_base58())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn sign_bip32_inner(
|
||||||
|
account_index: u32,
|
||||||
|
address_index_opt: Option<U31>,
|
||||||
|
external_opt: Option<bool>,
|
||||||
|
master_keypair: KeyPair,
|
||||||
|
msg: &str,
|
||||||
|
) -> Result<String, DubpError> {
|
||||||
|
Ok(master_keypair
|
||||||
|
.derive(z_get_derivation_path(
|
||||||
|
account_index,
|
||||||
|
address_index_opt,
|
||||||
|
external_opt,
|
||||||
|
)?)
|
||||||
|
.generate_signator()
|
||||||
|
.sign(msg.as_bytes())
|
||||||
|
.to_base64())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn sign_several_bip32_inner(
|
||||||
|
account_index: u32,
|
||||||
|
address_index_opt: Option<U31>,
|
||||||
|
external_opt: Option<bool>,
|
||||||
|
master_keypair: KeyPair,
|
||||||
|
msgs: &[&str],
|
||||||
|
) -> Result<Vec<String>, DubpError> {
|
||||||
|
let signator = master_keypair
|
||||||
|
.derive(z_get_derivation_path(
|
||||||
|
account_index,
|
||||||
|
address_index_opt,
|
||||||
|
external_opt,
|
||||||
|
)?)
|
||||||
|
.generate_signator();
|
||||||
|
|
||||||
Ok(msgs
|
Ok(msgs
|
||||||
.iter()
|
.iter()
|
||||||
.map(|msg| signator.sign(msg.as_bytes()).to_base64())
|
.map(|msg| signator.sign(msg.as_bytes()).to_base64())
|
||||||
.collect())
|
.collect())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn verify_member_secret_code(
|
||||||
|
currency: Currency,
|
||||||
|
dewif: &str,
|
||||||
|
secret_code: &str,
|
||||||
|
) -> Result<(), DubpError> {
|
||||||
|
if crate::secret_code::is_ascii_letters(secret_code) {
|
||||||
|
let log_n =
|
||||||
|
dup_crypto::dewif::read_dewif_log_n(ExpectedCurrency::Specific(currency), dewif)
|
||||||
|
.map_err(DubpError::DewifReadError)?;
|
||||||
|
let expected_secret_code_len =
|
||||||
|
crate::secret_code::compute_secret_code_len(true, SecretCodeType::Letters, log_n)?;
|
||||||
|
|
||||||
|
if secret_code.len() < expected_secret_code_len {
|
||||||
|
Err(DubpError::SecretCodeTooShort)
|
||||||
|
} else {
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
Some(_) => Err(DubpError::NotHdWallet),
|
} else {
|
||||||
None => Err(DubpError::DewifReadError(DewifReadError::CorruptedContent)),
|
Err(DubpError::InvalidSecretCodeType)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn z_get_derivation_path(
|
||||||
|
account_index: u32,
|
||||||
|
address_index_opt: Option<U31>,
|
||||||
|
external_opt: Option<bool>,
|
||||||
|
) -> Result<PrivateDerivationPath, DubpError> {
|
||||||
|
let account_index_u31 = U31::new(account_index)?;
|
||||||
|
match account_index % 3 {
|
||||||
|
0 => Ok(PrivateDerivationPath::transparent(account_index_u31)?),
|
||||||
|
1 => {
|
||||||
|
if let Some(external) = external_opt {
|
||||||
|
if external {
|
||||||
|
if address_index_opt.is_none() {
|
||||||
|
Ok(PrivateDerivationPath::semi_opaque_external(
|
||||||
|
account_index_u31,
|
||||||
|
)?)
|
||||||
|
} else {
|
||||||
|
Err(DubpError::InvalidAccountIndex(InvalidAccountIndex))
|
||||||
|
}
|
||||||
|
} else if address_index_opt.is_some() {
|
||||||
|
Ok(PrivateDerivationPath::semi_opaque_internal(
|
||||||
|
account_index_u31,
|
||||||
|
address_index_opt,
|
||||||
|
)?)
|
||||||
|
} else {
|
||||||
|
Err(DubpError::TryToSignWithInternalChainingAddress)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Err(DubpError::MissingExternalBool)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
2 => {
|
||||||
|
if address_index_opt.is_some() {
|
||||||
|
if let Some(external) = external_opt {
|
||||||
|
Ok(PrivateDerivationPath::opaque(
|
||||||
|
account_index_u31,
|
||||||
|
external,
|
||||||
|
address_index_opt,
|
||||||
|
)?)
|
||||||
|
} else {
|
||||||
|
Err(DubpError::MissingExternalBool)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Err(DubpError::TryToSignWithChainingAddress)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => unreachable!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
use assert_matches::assert_matches;
|
||||||
|
|
||||||
|
const MNEMONIC: &str =
|
||||||
|
"tongue cute mail fossil great frozen same social weasel impact brush kind";
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_get_accounts_pubkeys() -> Result<(), DubpError> {
|
||||||
|
let vec = crate::dewif::gen_dewif(
|
||||||
|
"g1",
|
||||||
|
Language::English,
|
||||||
|
MNEMONIC,
|
||||||
|
false,
|
||||||
|
SecretCodeType::Letters,
|
||||||
|
1_000,
|
||||||
|
)?;
|
||||||
|
let dewif = &vec[0];
|
||||||
|
let secret_code = &vec[1];
|
||||||
|
//println!("TMP: secret_code={}", secret_code);
|
||||||
|
|
||||||
|
assert_matches!(
|
||||||
|
get_accounts_pubkeys(
|
||||||
|
Currency::from(G1_CURRENCY),
|
||||||
|
dewif,
|
||||||
|
secret_code,
|
||||||
|
vec![U31::new(0).expect("unreachable")],
|
||||||
|
),
|
||||||
|
Err(DubpError::SecretCodeTooShort)
|
||||||
|
);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_sign_bip32() {
|
||||||
|
assert_matches!(
|
||||||
|
z_get_derivation_path(1, None, None),
|
||||||
|
Err(DubpError::MissingExternalBool)
|
||||||
|
);
|
||||||
|
assert_matches!(
|
||||||
|
z_get_derivation_path(2, None, None),
|
||||||
|
Err(DubpError::TryToSignWithChainingAddress)
|
||||||
|
);
|
||||||
|
assert_matches!(z_get_derivation_path(3, None, None), Ok(_));
|
||||||
|
assert_matches!(
|
||||||
|
z_get_derivation_path(1, None, Some(false)),
|
||||||
|
Err(DubpError::TryToSignWithInternalChainingAddress)
|
||||||
|
);
|
||||||
|
assert_matches!(
|
||||||
|
z_get_derivation_path(2, None, Some(true)),
|
||||||
|
Err(DubpError::TryToSignWithChainingAddress)
|
||||||
|
);
|
||||||
|
assert_matches!(
|
||||||
|
z_get_derivation_path(1, Some(U31::new(5).expect("unreachable")), Some(true),),
|
||||||
|
Err(DubpError::InvalidAccountIndex(_))
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,12 +16,11 @@
|
||||||
use crate::*;
|
use crate::*;
|
||||||
|
|
||||||
pub(crate) fn sign(
|
pub(crate) fn sign(
|
||||||
currency: &str,
|
currency: Currency,
|
||||||
dewif: &str,
|
dewif: &str,
|
||||||
secret_code: &str,
|
secret_code: &str,
|
||||||
msg: &str,
|
msg: &str,
|
||||||
) -> Result<String, DubpError> {
|
) -> Result<String, DubpError> {
|
||||||
let currency = parse_currency(currency)?;
|
|
||||||
let mut keypairs = dup_crypto::dewif::read_dewif_file_content(
|
let mut keypairs = dup_crypto::dewif::read_dewif_file_content(
|
||||||
ExpectedCurrency::Specific(currency),
|
ExpectedCurrency::Specific(currency),
|
||||||
dewif,
|
dewif,
|
||||||
|
@ -36,12 +35,11 @@ pub(crate) fn sign(
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn sign_several(
|
pub(crate) fn sign_several(
|
||||||
currency: &str,
|
currency: Currency,
|
||||||
dewif: &str,
|
dewif: &str,
|
||||||
secret_code: &str,
|
secret_code: &str,
|
||||||
msgs: &[&str],
|
msgs: &[&str],
|
||||||
) -> Result<Vec<String>, DubpError> {
|
) -> Result<Vec<String>, DubpError> {
|
||||||
let currency = parse_currency(currency)?;
|
|
||||||
let mut keypairs = dup_crypto::dewif::read_dewif_file_content(
|
let mut keypairs = dup_crypto::dewif::read_dewif_file_content(
|
||||||
ExpectedCurrency::Specific(currency),
|
ExpectedCurrency::Specific(currency),
|
||||||
dewif,
|
dewif,
|
||||||
|
|
|
@ -13,8 +13,6 @@
|
||||||
// You should have received a copy of the GNU Affero General Public License
|
// 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/>.
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
use dup_crypto::keys::ed25519::bip32::InvalidDerivationIndex;
|
|
||||||
|
|
||||||
use crate::*;
|
use crate::*;
|
||||||
|
|
||||||
/// Dubp error
|
/// Dubp error
|
||||||
|
@ -26,20 +24,30 @@ pub(crate) enum DubpError {
|
||||||
DigitsCodeForbidForMemberWallet,
|
DigitsCodeForbidForMemberWallet,
|
||||||
#[error("It is forbidden to retrieve the master public key of an HD wallet.")]
|
#[error("It is forbidden to retrieve the master public key of an HD wallet.")]
|
||||||
GetMasterPubkeyOfHdWallet,
|
GetMasterPubkeyOfHdWallet,
|
||||||
|
#[error("Give external bool or address index for legacy wallet.")]
|
||||||
|
GiveExternalBoolOrAddressIndexForLegacyWallet,
|
||||||
#[error("I/O error: {0}")]
|
#[error("I/O error: {0}")]
|
||||||
IoErr(io::Error),
|
IoErr(io::Error),
|
||||||
#[error("{0}")]
|
#[error("{0}")]
|
||||||
InvalidDerivationIndex(InvalidDerivationIndex),
|
InvalidAccountIndex(InvalidAccountIndex),
|
||||||
|
#[error("{0}")]
|
||||||
|
InvalidU31(U31Error),
|
||||||
#[error("Invalid secret code type")]
|
#[error("Invalid secret code type")]
|
||||||
InvalidSecretCodeType,
|
InvalidSecretCodeType,
|
||||||
|
#[error("Missing external bool")]
|
||||||
|
MissingExternalBool,
|
||||||
#[error("this wallet is not an HD wallet")]
|
#[error("this wallet is not an HD wallet")]
|
||||||
NotHdWallet,
|
NotHdWallet,
|
||||||
#[error("this account index is not a transparent account index")]
|
|
||||||
NotTransparentAccountIndex,
|
|
||||||
#[error("A given parameter is null")]
|
#[error("A given parameter is null")]
|
||||||
NullParamErr,
|
NullParamErr,
|
||||||
|
#[error("Opaque account not loaded")]
|
||||||
|
OpaqueAccountNotLoaded,
|
||||||
#[error("Secret code too short: please change your secret code")]
|
#[error("Secret code too short: please change your secret code")]
|
||||||
SecretCodeTooShort,
|
SecretCodeTooShort,
|
||||||
|
#[error("The chaining address cannot be used to sign with opaque account")]
|
||||||
|
TryToSignWithChainingAddress,
|
||||||
|
#[error("The internal chaining address cannot be used to sign with semi-opaque account")]
|
||||||
|
TryToSignWithInternalChainingAddress,
|
||||||
#[error("fail to generate random bytes")]
|
#[error("fail to generate random bytes")]
|
||||||
RandErr,
|
RandErr,
|
||||||
#[error("Unknown currency name")]
|
#[error("Unknown currency name")]
|
||||||
|
@ -60,9 +68,15 @@ impl From<io::Error> for DubpError {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<InvalidDerivationIndex> for DubpError {
|
impl From<InvalidAccountIndex> for DubpError {
|
||||||
fn from(e: InvalidDerivationIndex) -> Self {
|
fn from(e: InvalidAccountIndex) -> Self {
|
||||||
Self::InvalidDerivationIndex(e)
|
Self::InvalidAccountIndex(e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<U31Error> for DubpError {
|
||||||
|
fn from(e: U31Error) -> Self {
|
||||||
|
Self::InvalidU31(e)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -77,6 +91,17 @@ impl IntoDart for DartRes {
|
||||||
self.0.into_dart()
|
self.0.into_dart()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
impl<E> From<Result<(), E>> for DartRes
|
||||||
|
where
|
||||||
|
E: ToString,
|
||||||
|
{
|
||||||
|
fn from(res: Result<(), E>) -> Self {
|
||||||
|
match res {
|
||||||
|
Ok(()) => Self("".into_dart()),
|
||||||
|
Err(e) => Self(format!("DUBP_RS_ERROR: {}", e.to_string()).into_dart()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
impl<E> From<Result<String, E>> for DartRes
|
impl<E> From<Result<String, E>> for DartRes
|
||||||
where
|
where
|
||||||
E: ToString,
|
E: ToString,
|
||||||
|
|
|
@ -52,13 +52,13 @@ pub(crate) fn char_ptr_to_str<'a>(c_char_ptr: *const raw::c_char) -> Result<&'a
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn char_ptr_prt_to_vec_hard_derivation_index(
|
pub(crate) fn char_ptr_prt_to_vec_u31(
|
||||||
u32_ptr: *const u32,
|
u32_ptr: *const u32,
|
||||||
len: u32,
|
len: u32,
|
||||||
) -> Result<Vec<DerivationIndex>, DubpError> {
|
) -> Result<Vec<U31>, DubpError> {
|
||||||
u32_ptr_to_vec_u32(u32_ptr, len)
|
u32_ptr_to_vec_u32(u32_ptr, len)
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|ai| DerivationIndex::hard(ai).map_err(DubpError::InvalidDerivationIndex))
|
.map(|ai| U31::new(ai).map_err(DubpError::InvalidU31))
|
||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -76,6 +76,30 @@ pub(crate) fn char_ptr_prt_to_vec_str<'a>(
|
||||||
Ok(str_vec)
|
Ok(str_vec)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) fn i32_to_opt_bool(i: i32) -> Option<bool> {
|
||||||
|
match i {
|
||||||
|
1 => Some(true),
|
||||||
|
0 => Some(false),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn i32_to_opt_u31(i: i32) -> Result<Option<U31>, DubpError> {
|
||||||
|
if i >= 0 {
|
||||||
|
Ok(Some(U31::new(i as u32)?))
|
||||||
|
} else {
|
||||||
|
Ok(None)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn i32_to_opt_u32(i: i32) -> Option<u32> {
|
||||||
|
if i >= 0 {
|
||||||
|
Some(i as u32)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub(crate) fn parse_currency(currency: &str) -> Result<Currency, DubpError> {
|
pub(crate) fn parse_currency(currency: &str) -> Result<Currency, DubpError> {
|
||||||
let currency_code = match currency {
|
let currency_code = match currency {
|
||||||
"g1" => G1_CURRENCY,
|
"g1" => G1_CURRENCY,
|
||||||
|
@ -85,14 +109,6 @@ pub(crate) fn parse_currency(currency: &str) -> Result<Currency, DubpError> {
|
||||||
Ok(Currency::from(currency_code))
|
Ok(Currency::from(currency_code))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn transparent_account_index(account_index: u32) -> Result<DerivationIndex, DubpError> {
|
|
||||||
if account_index % 3 == 0 {
|
|
||||||
DerivationIndex::hard(account_index).map_err(DubpError::InvalidDerivationIndex)
|
|
||||||
} else {
|
|
||||||
Err(DubpError::NotTransparentAccountIndex)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn u32_ptr_to_vec_u32(u32_ptr: *const u32, len: u32) -> Vec<u32> {
|
pub(crate) fn u32_ptr_to_vec_u32(u32_ptr: *const u32, len: u32) -> Vec<u32> {
|
||||||
let len = len as usize;
|
let len = len as usize;
|
||||||
let u32_slice: &[u32] = unsafe { std::slice::from_raw_parts(u32_ptr, len) };
|
let u32_slice: &[u32] = unsafe { std::slice::from_raw_parts(u32_ptr, len) };
|
||||||
|
|
|
@ -42,14 +42,6 @@ pub(super) fn get_pubkey(salt: &str, password: &str) -> String {
|
||||||
.to_base58()
|
.to_base58()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) fn sign(salt: &str, password: &str, msg: &str) -> String {
|
|
||||||
KeyPairFromSaltedPasswordGenerator::with_default_parameters()
|
|
||||||
.generate(SaltedPassword::new(salt.to_owned(), password.to_owned()))
|
|
||||||
.generate_signator()
|
|
||||||
.sign(msg.as_bytes())
|
|
||||||
.to_base64()
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
@ -73,7 +65,14 @@ mod tests {
|
||||||
assert_eq!(get_pubkey("salt", "pass"), pubkey.to_owned());
|
assert_eq!(get_pubkey("salt", "pass"), pubkey.to_owned());
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
crate::dewif::get_pubkey(Currency::from(G1_CURRENCY), &dewif, &secret_code)?,
|
crate::dewif::get_pubkey(
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
Currency::from(G1_CURRENCY),
|
||||||
|
&dewif,
|
||||||
|
None,
|
||||||
|
&secret_code
|
||||||
|
)?,
|
||||||
pubkey.to_owned()
|
pubkey.to_owned()
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
@ -32,14 +32,19 @@ use dup_crypto::{
|
||||||
bases::b58::ToBase58,
|
bases::b58::ToBase58,
|
||||||
dewif::{Currency, DewifReadError, ExpectedCurrency, G1_CURRENCY, G1_TEST_CURRENCY},
|
dewif::{Currency, DewifReadError, ExpectedCurrency, G1_CURRENCY, G1_TEST_CURRENCY},
|
||||||
keys::{
|
keys::{
|
||||||
ed25519::bip32::DerivationIndex, ed25519::KeyPairFromSeed32Generator, KeyPair as _,
|
ed25519::bip32::{
|
||||||
KeyPairEnum, Signator as _, Signature as _,
|
ChainCode, InvalidAccountIndex, KeyPair, PrivateDerivationPath, PublicKeyWithChainCode,
|
||||||
|
},
|
||||||
|
ed25519::{KeyPairFromSeed32Generator, PublicKey},
|
||||||
|
KeyPair as _, KeyPairEnum, Signator as _, Signature as _,
|
||||||
},
|
},
|
||||||
mnemonic::{Language, Mnemonic, MnemonicType},
|
mnemonic::{Language, Mnemonic, MnemonicType},
|
||||||
|
utils::{U31Error, U31},
|
||||||
};
|
};
|
||||||
use fast_threadpool::{ThreadPool, ThreadPoolConfig, ThreadPoolSyncHandler};
|
use fast_threadpool::{ThreadPool, ThreadPoolConfig, ThreadPoolSyncHandler};
|
||||||
use once_cell::sync::Lazy;
|
use once_cell::sync::Lazy;
|
||||||
use std::{ffi::CStr, io, os::raw};
|
use parking_lot::Mutex;
|
||||||
|
use std::{collections::HashMap, ffi::CStr, io, os::raw, sync::Arc};
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
|
@ -163,6 +168,30 @@ pub extern "C" fn gen_mnemonic(port: i64, language: u32) {
|
||||||
exec_async(port, || u32_to_language(language), mnemonic::gen_mnemonic)
|
exec_async(port, || u32_to_language(language), mnemonic::gen_mnemonic)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
pub extern "C" fn get_bip32_dewif_accounts_pubkeys(
|
||||||
|
port: i64,
|
||||||
|
currency: *const raw::c_char,
|
||||||
|
dewif: *const raw::c_char,
|
||||||
|
secret_code: *const raw::c_char,
|
||||||
|
accounts_indexs_len: u32,
|
||||||
|
accounts_indexs: *const u32,
|
||||||
|
) {
|
||||||
|
exec_async(
|
||||||
|
port,
|
||||||
|
|| {
|
||||||
|
let currency = parse_currency(char_ptr_to_str(currency)?)?;
|
||||||
|
let dewif = char_ptr_to_str(dewif)?;
|
||||||
|
let secret_code = char_ptr_to_str(secret_code)?;
|
||||||
|
let accounts_indexs = char_ptr_prt_to_vec_u31(accounts_indexs, accounts_indexs_len)?;
|
||||||
|
Ok((currency, dewif, secret_code, accounts_indexs))
|
||||||
|
},
|
||||||
|
|(currency, dewif, secret_code, accounts_indexs)| {
|
||||||
|
dewif::bip32::get_accounts_pubkeys(currency, dewif, secret_code, accounts_indexs)
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub extern "C" fn get_dewif_meta(
|
pub extern "C" fn get_dewif_meta(
|
||||||
port: i64,
|
port: i64,
|
||||||
|
@ -201,43 +230,76 @@ pub extern "C" fn get_dewif_secret_code_len(
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub extern "C" fn get_dewif_pubkey(
|
pub extern "C" fn get_dewif_pubkey(
|
||||||
port: i64,
|
port: i64,
|
||||||
|
account_index: i32,
|
||||||
|
address_index: i32,
|
||||||
currency: *const raw::c_char,
|
currency: *const raw::c_char,
|
||||||
dewif: *const raw::c_char,
|
dewif: *const raw::c_char,
|
||||||
|
external_opt: i32,
|
||||||
pin: *const raw::c_char,
|
pin: *const raw::c_char,
|
||||||
) {
|
) {
|
||||||
exec_async(
|
exec_async(
|
||||||
port,
|
port,
|
||||||
|| {
|
|| {
|
||||||
|
let account_index_opt = i32_to_opt_u32(account_index);
|
||||||
|
let address_index_opt = i32_to_opt_u31(address_index)?;
|
||||||
let currency = parse_currency(char_ptr_to_str(currency)?)?;
|
let currency = parse_currency(char_ptr_to_str(currency)?)?;
|
||||||
let dewif = char_ptr_to_str(dewif)?;
|
let dewif = char_ptr_to_str(dewif)?;
|
||||||
|
let external_opt = i32_to_opt_bool(external_opt);
|
||||||
let pin = char_ptr_to_str(pin)?;
|
let pin = char_ptr_to_str(pin)?;
|
||||||
Ok((currency, dewif, pin))
|
Ok((
|
||||||
|
account_index_opt,
|
||||||
|
address_index_opt,
|
||||||
|
currency,
|
||||||
|
dewif,
|
||||||
|
external_opt,
|
||||||
|
pin,
|
||||||
|
))
|
||||||
|
},
|
||||||
|
|(account_index_opt, address_index_opt, currency, dewif, external_opt, pin)| {
|
||||||
|
dewif::get_pubkey(
|
||||||
|
account_index_opt,
|
||||||
|
address_index_opt,
|
||||||
|
currency,
|
||||||
|
dewif,
|
||||||
|
external_opt,
|
||||||
|
pin,
|
||||||
|
)
|
||||||
},
|
},
|
||||||
|(currency, dewif, pin)| dewif::get_pubkey(currency, dewif, pin),
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub extern "C" fn get_bip32_dewif_accounts_pubkeys(
|
pub extern "C" fn get_opaque_account_next_external_address(port: i64, account_index: u32) {
|
||||||
|
exec_async(
|
||||||
|
port,
|
||||||
|
|| {
|
||||||
|
let account_index = U31::new(account_index)?;
|
||||||
|
Ok(account_index)
|
||||||
|
},
|
||||||
|
dewif::bip32::get_opaque_account_next_external_address,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
pub extern "C" fn load_opaque_bip32_accounts(
|
||||||
port: i64,
|
port: i64,
|
||||||
|
accounts_indexs_len: u32,
|
||||||
|
accounts_indexs: *const u32,
|
||||||
currency: *const raw::c_char,
|
currency: *const raw::c_char,
|
||||||
dewif: *const raw::c_char,
|
dewif: *const raw::c_char,
|
||||||
secret_code: *const raw::c_char,
|
secret_code: *const raw::c_char,
|
||||||
accounts_indexs_len: u32,
|
|
||||||
accounts_indexs: *const u32,
|
|
||||||
) {
|
) {
|
||||||
exec_async(
|
exec_async(
|
||||||
port,
|
port,
|
||||||
|| {
|
|| {
|
||||||
|
let accounts_indexs = char_ptr_prt_to_vec_u31(accounts_indexs, accounts_indexs_len)?;
|
||||||
let currency = parse_currency(char_ptr_to_str(currency)?)?;
|
let currency = parse_currency(char_ptr_to_str(currency)?)?;
|
||||||
let dewif = char_ptr_to_str(dewif)?;
|
let dewif = char_ptr_to_str(dewif)?;
|
||||||
let secret_code = char_ptr_to_str(secret_code)?;
|
let secret_code = char_ptr_to_str(secret_code)?;
|
||||||
let accounts_indexs =
|
Ok((accounts_indexs, currency, dewif, secret_code))
|
||||||
char_ptr_prt_to_vec_hard_derivation_index(accounts_indexs, accounts_indexs_len)?;
|
|
||||||
Ok((currency, dewif, secret_code, accounts_indexs))
|
|
||||||
},
|
},
|
||||||
|(currency, dewif, secret_code, accounts_indexs)| {
|
|(accounts_indexs, currency, dewif, secret_code)| {
|
||||||
dewif::bip32::get_accounts_pubkeys(currency, dewif, secret_code, accounts_indexs)
|
dewif::bip32::load_opaque_bip32_accounts(accounts_indexs, currency, dewif, secret_code)
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -279,112 +341,106 @@ pub extern "C" fn mnemonic_to_pubkey(
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub extern "C" fn sign(
|
pub extern "C" fn sign(
|
||||||
port: i64,
|
port: i64,
|
||||||
|
account_index: i32,
|
||||||
|
address_index: i32,
|
||||||
currency: *const raw::c_char,
|
currency: *const raw::c_char,
|
||||||
dewif: *const raw::c_char,
|
dewif: *const raw::c_char,
|
||||||
pin: *const raw::c_char,
|
external_opt: i32,
|
||||||
msg: *const raw::c_char,
|
|
||||||
) {
|
|
||||||
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::classic::sign(currency, dewif, pin, msg),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[no_mangle]
|
|
||||||
pub extern "C" fn sign_bip32_transparent(
|
|
||||||
port: i64,
|
|
||||||
account_index: u32,
|
|
||||||
currency: *const raw::c_char,
|
|
||||||
dewif: *const raw::c_char,
|
|
||||||
secret_code: *const raw::c_char,
|
secret_code: *const raw::c_char,
|
||||||
msg: *const raw::c_char,
|
msg: *const raw::c_char,
|
||||||
) {
|
) {
|
||||||
exec_async(
|
exec_async(
|
||||||
port,
|
port,
|
||||||
|| {
|
|| {
|
||||||
let account_index = transparent_account_index(account_index)?;
|
let account_index_opt = i32_to_opt_u32(account_index);
|
||||||
let currency = char_ptr_to_str(currency)?;
|
let address_index_opt = i32_to_opt_u31(address_index)?;
|
||||||
|
let currency = parse_currency(char_ptr_to_str(currency)?)?;
|
||||||
let dewif = char_ptr_to_str(dewif)?;
|
let dewif = char_ptr_to_str(dewif)?;
|
||||||
let pin = char_ptr_to_str(secret_code)?;
|
let external_opt = i32_to_opt_bool(external_opt);
|
||||||
|
let secret_code = char_ptr_to_str(secret_code)?;
|
||||||
let msg = char_ptr_to_str(msg)?;
|
let msg = char_ptr_to_str(msg)?;
|
||||||
Ok((currency, dewif, pin, msg, account_index))
|
Ok((
|
||||||
},
|
account_index_opt,
|
||||||
|(currency, dewif, secret_code, msg, account_index)| {
|
address_index_opt,
|
||||||
dewif::bip32::sign_transparent(account_index, currency, dewif, secret_code, msg)
|
currency,
|
||||||
|
dewif,
|
||||||
|
external_opt,
|
||||||
|
secret_code,
|
||||||
|
msg,
|
||||||
|
))
|
||||||
},
|
},
|
||||||
|
|(
|
||||||
|
account_index_opt,
|
||||||
|
address_index_opt,
|
||||||
|
currency,
|
||||||
|
dewif,
|
||||||
|
external_opt,
|
||||||
|
secret_code,
|
||||||
|
msg,
|
||||||
|
)| {
|
||||||
|
dewif::sign(
|
||||||
|
account_index_opt,
|
||||||
|
address_index_opt,
|
||||||
|
currency,
|
||||||
|
dewif,
|
||||||
|
external_opt,
|
||||||
|
secret_code,
|
||||||
|
msg,
|
||||||
)
|
)
|
||||||
}
|
|
||||||
|
|
||||||
#[no_mangle]
|
|
||||||
pub extern "C" fn sign_legacy(
|
|
||||||
port: i64,
|
|
||||||
salt: *const raw::c_char,
|
|
||||||
password: *const raw::c_char,
|
|
||||||
msg: *const raw::c_char,
|
|
||||||
) {
|
|
||||||
exec_async(
|
|
||||||
port,
|
|
||||||
|| {
|
|
||||||
let salt = char_ptr_to_str(salt)?;
|
|
||||||
let password = char_ptr_to_str(password)?;
|
|
||||||
let msg = char_ptr_to_str(msg)?;
|
|
||||||
Ok((salt, password, msg))
|
|
||||||
},
|
},
|
||||||
|(salt, password, msg)| Ok::<_, DubpError>(legacy::sign(salt, password, msg)),
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub extern "C" fn sign_several(
|
pub extern "C" fn sign_several(
|
||||||
port: i64,
|
port: i64,
|
||||||
|
account_index: i32,
|
||||||
|
address_index: i32,
|
||||||
currency: *const raw::c_char,
|
currency: *const raw::c_char,
|
||||||
dewif: *const raw::c_char,
|
dewif: *const raw::c_char,
|
||||||
pin: *const raw::c_char,
|
external_opt: i32,
|
||||||
|
secret_code: *const raw::c_char,
|
||||||
msgs_len: u32,
|
msgs_len: u32,
|
||||||
msgs: *const *const raw::c_char,
|
msgs: *const *const raw::c_char,
|
||||||
) {
|
) {
|
||||||
exec_async(
|
exec_async(
|
||||||
port,
|
port,
|
||||||
|| {
|
|| {
|
||||||
let currency = char_ptr_to_str(currency)?;
|
let account_index_opt = i32_to_opt_u32(account_index);
|
||||||
|
let address_index_opt = i32_to_opt_u31(address_index)?;
|
||||||
|
let currency = parse_currency(char_ptr_to_str(currency)?)?;
|
||||||
let dewif = char_ptr_to_str(dewif)?;
|
let dewif = char_ptr_to_str(dewif)?;
|
||||||
let pin = char_ptr_to_str(pin)?;
|
let external_opt = i32_to_opt_bool(external_opt);
|
||||||
|
let secret_code = char_ptr_to_str(secret_code)?;
|
||||||
let msgs = char_ptr_prt_to_vec_str(msgs, msgs_len)?;
|
let msgs = char_ptr_prt_to_vec_str(msgs, msgs_len)?;
|
||||||
Ok((currency, dewif, pin, msgs))
|
Ok((
|
||||||
|
account_index_opt,
|
||||||
|
address_index_opt,
|
||||||
|
currency,
|
||||||
|
dewif,
|
||||||
|
external_opt,
|
||||||
|
secret_code,
|
||||||
|
msgs,
|
||||||
|
))
|
||||||
},
|
},
|
||||||
|(currency, dewif, pin, msgs)| dewif::classic::sign_several(currency, dewif, pin, &msgs),
|
|(
|
||||||
|
account_index_opt,
|
||||||
|
address_index_opt,
|
||||||
|
currency,
|
||||||
|
dewif,
|
||||||
|
external_opt,
|
||||||
|
secret_code,
|
||||||
|
msgs,
|
||||||
|
)| {
|
||||||
|
dewif::sign_several(
|
||||||
|
account_index_opt,
|
||||||
|
address_index_opt,
|
||||||
|
currency,
|
||||||
|
dewif,
|
||||||
|
external_opt,
|
||||||
|
secret_code,
|
||||||
|
&msgs,
|
||||||
)
|
)
|
||||||
}
|
|
||||||
|
|
||||||
#[no_mangle]
|
|
||||||
pub extern "C" fn sign_several_bip32_transparent(
|
|
||||||
port: i64,
|
|
||||||
account_index: u32,
|
|
||||||
currency: *const raw::c_char,
|
|
||||||
dewif: *const raw::c_char,
|
|
||||||
pin: *const raw::c_char,
|
|
||||||
msgs_len: u32,
|
|
||||||
msgs: *const *const raw::c_char,
|
|
||||||
) {
|
|
||||||
exec_async(
|
|
||||||
port,
|
|
||||||
|| {
|
|
||||||
let account_index = transparent_account_index(account_index)?;
|
|
||||||
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, account_index))
|
|
||||||
},
|
|
||||||
|(currency, dewif, pin, msgs, account_index)| {
|
|
||||||
dewif::bip32::sign_several_transparent(account_index, currency, dewif, pin, &msgs)
|
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -144,10 +144,12 @@ NewWallet new_wallet = await DubpRust.genWalletFromMnemonic(
|
||||||
#### Function signature
|
#### Function signature
|
||||||
|
|
||||||
```dart
|
```dart
|
||||||
static Future<String> signBip32Transparent({
|
static Future<String> sign({
|
||||||
int accountIndex,
|
int accountIndex,
|
||||||
|
int addressIndexOpt,
|
||||||
String currency = "g1",
|
String currency = "g1",
|
||||||
String dewif,
|
String dewif,
|
||||||
|
bool externalOpt,
|
||||||
String secretCode,
|
String secretCode,
|
||||||
String message
|
String message
|
||||||
});
|
});
|
||||||
|
@ -158,7 +160,7 @@ If the wallet is not dedicated to the Ğ1 currency, you must indicate the curren
|
||||||
#### Usage example
|
#### Usage example
|
||||||
|
|
||||||
```dart
|
```dart
|
||||||
String signature = await DubpRust.signBip32Transparent(
|
String signature = await DubpRust.sign(
|
||||||
accountIndex: 3,
|
accountIndex: 3,
|
||||||
dewif: "AAAAARAAAAGfFDAs+jVZYkfhBlHZZ2fEQIvBqnG16g5+02cY18wSOjW0cUg2JV3SUTJYN2CrbQeRDwGazWnzSFBphchMmiL0",
|
dewif: "AAAAARAAAAGfFDAs+jVZYkfhBlHZZ2fEQIvBqnG16g5+02cY18wSOjW0cUg2JV3SUTJYN2CrbQeRDwGazWnzSFBphchMmiL0",
|
||||||
pin: "CDJ4UB",
|
pin: "CDJ4UB",
|
||||||
|
|
|
@ -177,7 +177,16 @@ class DubpRust {
|
||||||
return Future.value(NewWallet._(newWallet[0], newWallet[1]));
|
return Future.value(NewWallet._(newWallet[0], newWallet[1]));
|
||||||
}
|
}
|
||||||
|
|
||||||
//get_bip32_dewif_accounts_pubkeys
|
/// Get next external public key of a specific opaque account
|
||||||
|
static Future<String> getOpaqueAccountNextExternalPublicKey(
|
||||||
|
{int accountIndex}) async {
|
||||||
|
final completer = Completer<String>();
|
||||||
|
final sendPort =
|
||||||
|
singleCompletePort<String, String>(completer, callback: _handleErr);
|
||||||
|
native.get_opaque_account_next_external_address(
|
||||||
|
sendPort.nativePort, accountIndex.toUnsigned(31));
|
||||||
|
return completer.future;
|
||||||
|
}
|
||||||
|
|
||||||
/// Get BIP32 accounts public keys (in base 58) of `dewif` master keypair.
|
/// Get BIP32 accounts public keys (in base 58) of `dewif` master keypair.
|
||||||
static Future<List<String>> getBip32DewifAccountsPublicKeys(
|
static Future<List<String>> getBip32DewifAccountsPublicKeys(
|
||||||
|
@ -194,7 +203,7 @@ class DubpRust {
|
||||||
Utf8.toUtf8(dewif),
|
Utf8.toUtf8(dewif),
|
||||||
Utf8.toUtf8(secretCode),
|
Utf8.toUtf8(secretCode),
|
||||||
accountsIndex.length,
|
accountsIndex.length,
|
||||||
_listIntToPtr(accountsIndex));
|
_listIntToPtrUint32(accountsIndex));
|
||||||
return completer.future;
|
return completer.future;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -215,14 +224,26 @@ class DubpRust {
|
||||||
|
|
||||||
/// Get public key (in base 58) of `dewif` keypair.
|
/// Get public key (in base 58) of `dewif` keypair.
|
||||||
static Future<String> getDewifPublicKey(
|
static Future<String> getDewifPublicKey(
|
||||||
{String currency = "g1", String dewif, String pin}) async {
|
{int accountIndexOpt,
|
||||||
|
int addressIndexOpt,
|
||||||
|
String currency = "g1",
|
||||||
|
String dewif,
|
||||||
|
bool externalOpt,
|
||||||
|
String pin}) async {
|
||||||
|
var externalOptInt = -1;
|
||||||
|
if (externalOpt != null) {
|
||||||
|
externalOptInt = externalOpt ? 1 : 0;
|
||||||
|
}
|
||||||
final completer = Completer<String>();
|
final completer = Completer<String>();
|
||||||
final sendPort =
|
final sendPort =
|
||||||
singleCompletePort<String, String>(completer, callback: _handleErr);
|
singleCompletePort<String, String>(completer, callback: _handleErr);
|
||||||
native.get_dewif_pubkey(
|
native.get_dewif_pubkey(
|
||||||
sendPort.nativePort,
|
sendPort.nativePort,
|
||||||
|
accountIndexOpt ?? -1,
|
||||||
|
addressIndexOpt ?? -1,
|
||||||
Utf8.toUtf8(currency),
|
Utf8.toUtf8(currency),
|
||||||
Utf8.toUtf8(dewif),
|
Utf8.toUtf8(dewif),
|
||||||
|
externalOptInt,
|
||||||
Utf8.toUtf8(pin),
|
Utf8.toUtf8(pin),
|
||||||
);
|
);
|
||||||
return completer.future;
|
return completer.future;
|
||||||
|
@ -261,43 +282,55 @@ class DubpRust {
|
||||||
return completer.future;
|
return completer.future;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Sign the message `message` with `dewif` Bip32-Ed25519 keypair encryted
|
/// Load opaque accounts
|
||||||
/// in DEWIF format.
|
static Future<void> loadOpaqueAccounts(
|
||||||
///
|
List<int> accountsIndex,
|
||||||
/// If you have several messages to sign, use `signSeveralBip32Transparent`
|
String currency,
|
||||||
/// method instead.
|
|
||||||
static Future<String> signBip32Transparent(
|
|
||||||
{int accountIndex,
|
|
||||||
String currency = "g1",
|
|
||||||
String dewif,
|
String dewif,
|
||||||
String secretCode,
|
String secretCode,
|
||||||
String message}) {
|
) {
|
||||||
final completer = Completer<String>();
|
final completer = Completer<void>();
|
||||||
final sendPort =
|
final sendPort =
|
||||||
singleCompletePort<String, String>(completer, callback: _handleErr);
|
singleCompletePort<void, String>(completer, callback: _handleErrVoid);
|
||||||
native.sign_bip32_transparent(
|
native.load_opaque_bip32_accounts(
|
||||||
sendPort.nativePort,
|
sendPort.nativePort,
|
||||||
accountIndex,
|
accountsIndex.length,
|
||||||
|
_listIntToPtrUint32(accountsIndex),
|
||||||
Utf8.toUtf8(currency),
|
Utf8.toUtf8(currency),
|
||||||
Utf8.toUtf8(dewif),
|
Utf8.toUtf8(dewif),
|
||||||
Utf8.toUtf8(secretCode),
|
Utf8.toUtf8(secretCode));
|
||||||
Utf8.toUtf8(message),
|
|
||||||
);
|
|
||||||
return completer.future;
|
return completer.future;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Sign the message `message` with legacy wallet (password + salt)
|
/// Sign the message `message` with `dewif` keypair encryted
|
||||||
|
/// in DEWIF format.
|
||||||
///
|
///
|
||||||
/// This deprecated method must be used only for compatibility purpose !
|
/// If you have several messages to sign, use `signSeveral`
|
||||||
static Future<String> signLegacy(
|
/// method instead.
|
||||||
{String password, String salt, String message}) {
|
static Future<String> sign(
|
||||||
|
{int accountIndexOpt,
|
||||||
|
int addressIndexOpt,
|
||||||
|
String currency = "g1",
|
||||||
|
String dewif,
|
||||||
|
bool externalOpt,
|
||||||
|
String secretCode,
|
||||||
|
String message}) {
|
||||||
|
var externalOptInt = -1;
|
||||||
|
if (externalOpt != null) {
|
||||||
|
externalOptInt = externalOpt ? 1 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
final completer = Completer<String>();
|
final completer = Completer<String>();
|
||||||
final sendPort =
|
final sendPort =
|
||||||
singleCompletePort<String, String>(completer, callback: _handleErr);
|
singleCompletePort<String, String>(completer, callback: _handleErr);
|
||||||
native.sign_legacy(
|
native.sign(
|
||||||
sendPort.nativePort,
|
sendPort.nativePort,
|
||||||
Utf8.toUtf8(password),
|
accountIndexOpt ?? -1,
|
||||||
Utf8.toUtf8(salt),
|
addressIndexOpt ?? -1,
|
||||||
|
Utf8.toUtf8(currency),
|
||||||
|
Utf8.toUtf8(dewif),
|
||||||
|
externalOptInt,
|
||||||
|
Utf8.toUtf8(secretCode),
|
||||||
Utf8.toUtf8(message),
|
Utf8.toUtf8(message),
|
||||||
);
|
);
|
||||||
return completer.future;
|
return completer.future;
|
||||||
|
@ -309,22 +342,31 @@ class DubpRust {
|
||||||
/// This method is optimized to sign several messages at once. If you have
|
/// This method is optimized to sign several messages at once. If you have
|
||||||
/// several messages to sign, avoid calling the `sign` method for each
|
/// several messages to sign, avoid calling the `sign` method for each
|
||||||
/// message. Use this `signSeveral` method instead.
|
/// message. Use this `signSeveral` method instead.
|
||||||
static Future<List<String>> signSeveralBip32Transparent(
|
static Future<List<String>> signSeveral(
|
||||||
{int accountIndex,
|
{int accountIndexOpt,
|
||||||
|
int addressIndexOpt,
|
||||||
String currency = "g1",
|
String currency = "g1",
|
||||||
String dewif,
|
String dewif,
|
||||||
String pin,
|
bool externalOpt,
|
||||||
|
String secretCode,
|
||||||
List<String> messages}) {
|
List<String> messages}) {
|
||||||
|
var externalOptInt = -1;
|
||||||
|
if (externalOpt != null) {
|
||||||
|
externalOptInt = externalOpt ? 1 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
final completer = Completer<List<String>>();
|
final completer = Completer<List<String>>();
|
||||||
final sendPort = singleCompletePort<List<String>, List>(completer,
|
final sendPort = singleCompletePort<List<String>, List>(completer,
|
||||||
callback: _handleErrList);
|
callback: _handleErrList);
|
||||||
|
|
||||||
native.sign_several_bip32_transparent(
|
native.sign_several(
|
||||||
sendPort.nativePort,
|
sendPort.nativePort,
|
||||||
accountIndex,
|
accountIndexOpt ?? -1,
|
||||||
|
addressIndexOpt ?? -1,
|
||||||
Utf8.toUtf8(currency),
|
Utf8.toUtf8(currency),
|
||||||
Utf8.toUtf8(dewif),
|
Utf8.toUtf8(dewif),
|
||||||
Utf8.toUtf8(pin),
|
externalOptInt,
|
||||||
|
Utf8.toUtf8(secretCode),
|
||||||
messages.length,
|
messages.length,
|
||||||
_listStringToPtr(messages),
|
_listStringToPtr(messages),
|
||||||
);
|
);
|
||||||
|
@ -332,11 +374,11 @@ class DubpRust {
|
||||||
return completer.future;
|
return completer.future;
|
||||||
}
|
}
|
||||||
|
|
||||||
static Pointer<Uint32> _listIntToPtr(List<int> list) {
|
static Pointer<Uint32> _listIntToPtrUint32(List<int> list) {
|
||||||
//final listUint32 = list.map(int.toUnsigned).toList();
|
final listUint32 = list.map((i) => i.toUnsigned(31)).toList();
|
||||||
final Pointer<Uint32> ptr = allocate(count: list.length);
|
final Pointer<Uint32> ptr = allocate(count: listUint32.length);
|
||||||
for (var i = 0; i < list.length; i++) {
|
for (var i = 0; i < listUint32.length; i++) {
|
||||||
ptr[i] = list[i];
|
ptr[i] = listUint32[i];
|
||||||
}
|
}
|
||||||
return ptr;
|
return ptr;
|
||||||
}
|
}
|
||||||
|
@ -371,6 +413,14 @@ class DubpRust {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void _handleErrVoid(String res) {
|
||||||
|
if (res.startsWith('DUBP_RS_ERROR: ')) {
|
||||||
|
final error = res;
|
||||||
|
print(error);
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*static int _handleErrInt(String res) {
|
/*static int _handleErrInt(String res) {
|
||||||
if (res.startsWith('DUBP_RS_ERROR: ')) {
|
if (res.startsWith('DUBP_RS_ERROR: ')) {
|
||||||
final error = res;
|
final error = res;
|
||||||
|
|
Loading…
Reference in New Issue