diff --git a/Cargo.lock b/Cargo.lock index a28e4d5..8b8b749 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -261,9 +261,7 @@ dependencies = [ [[package]] name = "dup-crypto" -version = "0.40.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba9cba3d83bf946b9e2d3b444f98df563d6ffefa94579bdfc6f06b158cd872a9" +version = "0.41.0" dependencies = [ "aes", "arrayvec", diff --git a/Cargo.toml b/Cargo.toml index 90c3171..bc65ba0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,4 +7,4 @@ codegen-units = 1 debug = true [patch.crates-io] -#dup-crypto = { path = "/home/elois/dev/duniter/libs/dubp-rs-libs/crypto" } +dup-crypto = { path = "/home/elois/dev/duniter/libs/dubp-rs-libs/crypto" } diff --git a/native/dubp_rs/Cargo.toml b/native/dubp_rs/Cargo.toml index 5d104fa..3d0519e 100644 --- a/native/dubp_rs/Cargo.toml +++ b/native/dubp_rs/Cargo.toml @@ -10,7 +10,7 @@ crate-type = ["rlib"] [dependencies] allo-isolate = "0.1.6" -dup-crypto = { version = "0.40.0", features = ["bip32-ed25519", "dewif", "mnemonic", "mnemonic_french", "rand", "scrypt"] } +dup-crypto = { version = "0.41.0", features = ["bip32-ed25519", "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" diff --git a/native/dubp_rs/src/dewif.rs b/native/dubp_rs/src/dewif.rs index 1ed860d..49e35b6 100644 --- a/native/dubp_rs/src/dewif.rs +++ b/native/dubp_rs/src/dewif.rs @@ -13,6 +13,9 @@ // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . +pub mod bip32; +pub mod classic; + use crate::*; pub(super) fn change_secret_code( @@ -24,23 +27,16 @@ pub(super) fn change_secret_code( system_memory: i64, ) -> Result, DubpError> { let currency = parse_currency(currency)?; - let mut keypairs = dup_crypto::dewif::read_dewif_file_content( - ExpectedCurrency::Specific(currency), - dewif, - old_secret_code, - ) - .map_err(DubpError::DewifReadError)?; - if let Some(KeyPairEnum::Ed25519(keypair)) = keypairs.next() { - let log_n = log_n(system_memory); - let new_secret_code = gen_secret_code(member_wallet, secret_code_type, log_n)?; + let new_log_n = log_n(system_memory); + let new_secret_code = gen_secret_code(member_wallet, secret_code_type, new_log_n)?; - let dewif = - dup_crypto::dewif::write_dewif_v3_content(currency, &keypair, log_n, &new_secret_code); - let pubkey = keypair.public_key().to_base58(); - Ok(vec![dewif, new_secret_code, pubkey]) - } else { - Err(DubpError::DewifReadError(DewifReadError::CorruptedContent)) - } + let new_dewif = + dup_crypto::dewif::change_dewif_passphrase(dewif, old_secret_code, &new_secret_code) + .map_err(DubpError::DewifReadError)?; + + let pubkey = get_pubkey(currency, &new_dewif, &new_secret_code)?; + + Ok(vec![new_dewif, new_secret_code, pubkey]) } pub(super) fn gen_dewif( @@ -50,17 +46,37 @@ pub(super) fn gen_dewif( member_wallet: bool, secret_code_type: SecretCodeType, system_memory: i64, + wallet_type: WalletType, ) -> Result, DubpError> { let currency = parse_currency(currency)?; 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); let log_n = log_n(system_memory); let secret_code = gen_secret_code(member_wallet, secret_code_type, log_n)?; - let dewif = dup_crypto::dewif::write_dewif_v3_content(currency, &keypair, log_n, &secret_code); - let pubkey = keypair.public_key().to_base58(); + + let (dewif, pubkey) = match wallet_type { + WalletType::Ed25519 => { + let keypair = dup_crypto::keys::ed25519::bip32::KeyPair::from_seed(seed.clone()); + let pubkey = keypair.public_key(); + let dewif = dup_crypto::dewif::write_dewif_v4_content( + currency, + log_n, + &secret_code, + &pubkey, + seed, + ); + (dewif, pubkey.to_base58()) + } + WalletType::Bip32Ed25519 => { + let keypair = KeyPairFromSeed32Generator::generate(seed); + let dewif = + dup_crypto::dewif::write_dewif_v3_content(currency, &keypair, log_n, &secret_code); + (dewif, keypair.public_key().to_base58()) + } + }; + Ok(vec![dewif, secret_code, pubkey]) } @@ -83,54 +99,19 @@ pub(super) fn get_secret_code_len( )?) } -pub(super) fn get_pubkey(currency: Currency, dewif: &str, pin: &str) -> Result { - let mut keypairs = dup_crypto::dewif::read_dewif_file_content( - ExpectedCurrency::Specific(currency), - dewif, - &pin.to_ascii_uppercase(), - ) - .map_err(DubpError::DewifReadError)?; - if let Some(KeyPairEnum::Ed25519(keypair)) = keypairs.next() { - Ok(keypair.public_key().to_base58()) - } else { - Err(DubpError::DewifReadError(DewifReadError::CorruptedContent)) - } -} - -pub(super) fn sign(currency: &str, dewif: &str, pin: &str, msg: &str) -> Result { - let currency = parse_currency(currency)?; - let mut keypairs = dup_crypto::dewif::read_dewif_file_content( - ExpectedCurrency::Specific(currency), - dewif, - &pin.to_ascii_uppercase(), - ) - .map_err(DubpError::DewifReadError)?; - if let Some(KeyPairEnum::Ed25519(keypair)) = keypairs.next() { - Ok(keypair.generate_signator().sign(msg.as_bytes()).to_base64()) - } else { - Err(DubpError::DewifReadError(DewifReadError::CorruptedContent)) - } -} - -pub(super) fn sign_several( - currency: &str, +pub(super) fn get_pubkey( + currency: Currency, dewif: &str, - pin: &str, - msgs: &[&str], -) -> Result, DubpError> { - let currency = parse_currency(currency)?; + secret_code: &str, +) -> Result { let mut keypairs = dup_crypto::dewif::read_dewif_file_content( ExpectedCurrency::Specific(currency), dewif, - &pin.to_ascii_uppercase(), + &secret_code.to_ascii_uppercase(), ) .map_err(DubpError::DewifReadError)?; - if let Some(KeyPairEnum::Ed25519(keypair)) = keypairs.next() { - let signator = keypair.generate_signator(); - Ok(msgs - .iter() - .map(|msg| signator.sign(msg.as_bytes()).to_base64()) - .collect()) + if let Some(keypair) = keypairs.next() { + Ok(keypair.public_key().to_base58()) } else { Err(DubpError::DewifReadError(DewifReadError::CorruptedContent)) } diff --git a/native/dubp_rs/src/dewif/bip32.rs b/native/dubp_rs/src/dewif/bip32.rs new file mode 100644 index 0000000..374dcaf --- /dev/null +++ b/native/dubp_rs/src/dewif/bip32.rs @@ -0,0 +1,97 @@ +// 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 . + +use crate::*; + +pub(crate) fn get_accounts_pubkeys( + currency: Currency, + dewif: &str, + secret_code: &str, + accounts_indexs: Vec, +) -> 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)) => Ok(accounts_indexs + .into_iter() + .map(|account_index| { + master_keypair + .derive(account_index) + .public_key() + .to_base58() + }) + .collect()), + Some(_) => Err(DubpError::NotHdWallet), + None => Err(DubpError::DewifReadError(DewifReadError::CorruptedContent)), + } +} + +pub(crate) fn sign_transparent( + account_index: DerivationIndex, + currency: &str, + dewif: &str, + secret_code: &str, + msg: &str, +) -> Result { + let currency = parse_currency(currency)?; + 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)) => Ok(master_keypair + .derive(account_index) + .generate_signator() + .sign(msg.as_bytes()) + .to_base64()), + Some(_) => Err(DubpError::NotHdWallet), + None => Err(DubpError::DewifReadError(DewifReadError::CorruptedContent)), + } +} + +pub(crate) fn sign_several_transparent( + account_index: DerivationIndex, + currency: &str, + dewif: &str, + secret_code: &str, + msgs: &[&str], +) -> Result, DubpError> { + let currency = parse_currency(currency)?; + 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)) => { + let signator = master_keypair.derive(account_index).generate_signator(); + Ok(msgs + .iter() + .map(|msg| signator.sign(msg.as_bytes()).to_base64()) + .collect()) + } + Some(_) => Err(DubpError::NotHdWallet), + None => Err(DubpError::DewifReadError(DewifReadError::CorruptedContent)), + } +} diff --git a/native/dubp_rs/src/dewif/classic.rs b/native/dubp_rs/src/dewif/classic.rs new file mode 100644 index 0000000..dcfd97a --- /dev/null +++ b/native/dubp_rs/src/dewif/classic.rs @@ -0,0 +1,60 @@ +// 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 . + +use crate::*; + +pub(crate) fn sign( + currency: &str, + dewif: &str, + secret_code: &str, + msg: &str, +) -> Result { + let currency = parse_currency(currency)?; + let mut keypairs = dup_crypto::dewif::read_dewif_file_content( + ExpectedCurrency::Specific(currency), + dewif, + &secret_code.to_ascii_uppercase(), + ) + .map_err(DubpError::DewifReadError)?; + if let Some(KeyPairEnum::Ed25519(keypair)) = keypairs.next() { + Ok(keypair.generate_signator().sign(msg.as_bytes()).to_base64()) + } else { + Err(DubpError::DewifReadError(DewifReadError::CorruptedContent)) + } +} + +pub(crate) fn sign_several( + currency: &str, + dewif: &str, + secret_code: &str, + msgs: &[&str], +) -> Result, DubpError> { + let currency = parse_currency(currency)?; + let mut keypairs = dup_crypto::dewif::read_dewif_file_content( + ExpectedCurrency::Specific(currency), + dewif, + &secret_code.to_ascii_uppercase(), + ) + .map_err(DubpError::DewifReadError)?; + if let Some(KeyPairEnum::Ed25519(keypair)) = keypairs.next() { + let signator = keypair.generate_signator(); + Ok(msgs + .iter() + .map(|msg| signator.sign(msg.as_bytes()).to_base64()) + .collect()) + } else { + Err(DubpError::DewifReadError(DewifReadError::CorruptedContent)) + } +} diff --git a/native/dubp_rs/src/error.rs b/native/dubp_rs/src/error.rs index b8f3d41..2f55f01 100644 --- a/native/dubp_rs/src/error.rs +++ b/native/dubp_rs/src/error.rs @@ -13,6 +13,8 @@ // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . +use dup_crypto::keys::ed25519::bip32::InvalidDerivationIndex; + use crate::*; /// Dubp error @@ -22,8 +24,14 @@ pub(crate) enum DubpError { DewifReadError(DewifReadError), #[error("I/O error: {0}")] IoErr(io::Error), + #[error("{0}")] + InvalidDerivationIndex(InvalidDerivationIndex), #[error("Digits secret code forbid for member wallet")] DigitsCodeForbidForMemberWallet, + #[error("this wallet is not an HD wallet")] + NotHdWallet, + #[error("this account index is not a transparent account index")] + NotTransparentAccountIndex, #[error("A given parameter is null")] NullParamErr, #[error("fail to generate random bytes")] @@ -44,6 +52,12 @@ impl From for DubpError { } } +impl From for DubpError { + fn from(e: InvalidDerivationIndex) -> Self { + Self::InvalidDerivationIndex(e) + } +} + pub(crate) struct DartRes(allo_isolate::ffi::DartCObject); impl DartRes { pub(crate) fn err(e: E) -> allo_isolate::ffi::DartCObject { diff --git a/native/dubp_rs/src/inputs.rs b/native/dubp_rs/src/inputs.rs index 557e0c4..54d7fe3 100644 --- a/native/dubp_rs/src/inputs.rs +++ b/native/dubp_rs/src/inputs.rs @@ -29,6 +29,20 @@ impl From for SecretCodeType { } } } +#[derive(Clone, Copy, Debug)] +pub(crate) enum WalletType { + Ed25519, + Bip32Ed25519, +} +impl From for WalletType { + fn from(i: u32) -> Self { + if i == 1 { + WalletType::Bip32Ed25519 + } else { + WalletType::Ed25519 + } + } +} 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() { @@ -38,6 +52,16 @@ 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( + u32_ptr: *const u32, + len: u32, +) -> Result, DubpError> { + u32_ptr_to_vec_u32(u32_ptr, len)? + .into_iter() + .map(|ai| DerivationIndex::hard(ai).map_err(DubpError::InvalidDerivationIndex)) + .collect() +} + pub(crate) fn char_ptr_prt_to_vec_str<'a>( char_ptr_ptr: *const *const raw::c_char, len: u32, @@ -61,6 +85,24 @@ pub(crate) fn parse_currency(currency: &str) -> Result { Ok(Currency::from(currency_code)) } +pub(crate) fn transparent_account_index(account_index: u32) -> Result { + 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) -> Result, DubpError> { + let len = len as usize; + let u32_slice: &[u32] = unsafe { std::slice::from_raw_parts(u32_ptr, len) }; + let mut vec = Vec::with_capacity(len); + for u32_ in u32_slice { + vec.push(*u32_); + } + Ok(vec) +} + pub(crate) fn u32_to_language(i: u32) -> Result { match i { 0 => Ok(Language::English), diff --git a/native/dubp_rs/src/lib.rs b/native/dubp_rs/src/lib.rs index 92f19a4..3a319ae 100644 --- a/native/dubp_rs/src/lib.rs +++ b/native/dubp_rs/src/lib.rs @@ -32,8 +32,8 @@ use dup_crypto::{ bases::b58::ToBase58, dewif::{Currency, DewifReadError, ExpectedCurrency, G1_CURRENCY, G1_TEST_CURRENCY}, keys::{ - ed25519::KeyPairFromSeed32Generator, KeyPair as _, KeyPairEnum, Signator as _, - Signature as _, + ed25519::bip32::DerivationIndex, ed25519::KeyPairFromSeed32Generator, KeyPair as _, + KeyPairEnum, Signator as _, Signature as _, }, mnemonic::{Language, Mnemonic, MnemonicType}, }; @@ -91,6 +91,7 @@ pub extern "C" fn gen_dewif( member_wallet: u32, secret_code_type: u32, system_memory: i64, + wallet_type: u32, ) { exec_async( port, @@ -100,6 +101,7 @@ pub extern "C" fn gen_dewif( let mnemonic = char_ptr_to_str(mnemonic)?; let member_wallet = member_wallet != 0; let secret_code_type = SecretCodeType::from(secret_code_type); + let wallet_type = WalletType::from(wallet_type); Ok(( currency, language, @@ -107,9 +109,18 @@ pub extern "C" fn gen_dewif( member_wallet, secret_code_type, system_memory, + wallet_type, )) }, - |(currency, language, mnemonic, member_wallet, secret_code_type, system_memory)| { + |( + currency, + language, + mnemonic, + member_wallet, + secret_code_type, + system_memory, + wallet_type, + )| { dewif::gen_dewif( currency, language, @@ -117,6 +128,7 @@ pub extern "C" fn gen_dewif( member_wallet, secret_code_type, system_memory, + wallet_type, ) }, ) @@ -201,6 +213,31 @@ pub extern "C" fn get_dewif_pubkey( } #[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_hard_derivation_index(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] pub extern "C" fn get_legacy_pubkey( port: i64, salt: *const raw::c_char, @@ -251,7 +288,32 @@ pub extern "C" fn sign( let msg = char_ptr_to_str(msg)?; Ok((currency, dewif, pin, msg)) }, - |(currency, dewif, pin, msg)| dewif::sign(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, + msg: *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(secret_code)?; + let msg = char_ptr_to_str(msg)?; + Ok((currency, dewif, pin, msg, account_index)) + }, + |(currency, dewif, secret_code, msg, account_index)| { + dewif::bip32::sign_transparent(account_index, currency, dewif, secret_code, msg) + }, ) } @@ -292,6 +354,32 @@ pub extern "C" fn sign_several( 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), + |(currency, dewif, pin, msgs)| dewif::classic::sign_several(currency, dewif, pin, &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) + }, ) } diff --git a/packages/dubp_rs/lib/dubp.dart b/packages/dubp_rs/lib/dubp.dart index 505f8f1..3f1cc46 100644 --- a/packages/dubp_rs/lib/dubp.dart +++ b/packages/dubp_rs/lib/dubp.dart @@ -38,6 +38,15 @@ enum SecretCodeType { letters, } +/// Wallet type +enum WalletType { + /// Ed25519 + ed25519, + + /// BIP32-Ed25519 + bip32Ed25519, +} + /// DUBP Rust utilities /// /// All the functions of this package are static methods of this @@ -128,6 +137,7 @@ class DubpRust { Language language = Language.english, String mnemonic, SecretCodeType secretCodeType = SecretCodeType.letters, + WalletType walletType = WalletType.ed25519, }) async { int ram = SysInfo.getTotalPhysicalMemory(); print('ram=$ram'); @@ -143,12 +153,34 @@ class DubpRust { 0, secretCodeType.index, ram, + walletType.index, ); List newWallet = await completer.future; return Future.value(NewWallet._(newWallet[0], newWallet[1], newWallet[2])); } + //get_bip32_dewif_accounts_pubkeys + + /// Get BIP32 accounts public keys (in base 58) of `dewif` master keypair. + static Future getBip32DewifAccountsPublicKeys( + {String currency = "g1", + String dewif, + String secretCode, + List accountsIndex}) async { + final completer = Completer(); + final sendPort = + singleCompletePort(completer, callback: _handleErr); + native.get_bip32_dewif_accounts_pubkeys( + sendPort.nativePort, + Utf8.toUtf8(currency), + Utf8.toUtf8(dewif), + Utf8.toUtf8(secretCode), + accountsIndex.length, + _listIntToPtr(accountsIndex)); + return completer.future; + } + /// Get public key (in base 58) of `dewif` keypair. static Future getDewifPublicKey( {String currency = "g1", String dewif, String pin}) async { @@ -215,6 +247,31 @@ class DubpRust { return completer.future; } + /// Sign the message `message` with `dewif` Bip32-Ed25519 keypair encryted + /// in DEWIF format. + /// + /// If you have several messages to sign, use `signSeveralBip32Transparent` + /// method instead. + static Future signBip32Transparent( + {int accountIndex, + String currency = "g1", + String dewif, + String secretCode, + String message}) { + final completer = Completer(); + final sendPort = + singleCompletePort(completer, callback: _handleErr); + native.sign_bip32_transparent( + sendPort.nativePort, + accountIndex, + Utf8.toUtf8(currency), + Utf8.toUtf8(dewif), + Utf8.toUtf8(secretCode), + Utf8.toUtf8(message), + ); + return completer.future; + } + /// Sign the message `message` with legacy wallet (password + salt) /// /// This deprecated method must be used only for compatibility purpose ! @@ -259,6 +316,44 @@ class DubpRust { return completer.future; } + /// Sign several messages `messages` with `dewif` keypair encryted in DEWIF + /// format. + /// + /// This method is optimized to sign several messages at once. If you have + /// several messages to sign, avoid calling the `sign` method for each + /// message. Use this `signSeveral` method instead. + static Future> signSeveralBip32Transparent( + {int accountIndex, + String currency = "g1", + String dewif, + String pin, + List messages}) { + final completer = Completer>(); + final sendPort = singleCompletePort, List>(completer, + callback: _handleErrList); + + native.sign_several_bip32_transparent( + sendPort.nativePort, + accountIndex, + Utf8.toUtf8(currency), + Utf8.toUtf8(dewif), + Utf8.toUtf8(pin), + messages.length, + _listStringToPtr(messages), + ); + + return completer.future; + } + + static Pointer _listIntToPtr(List list) { + //final listUint32 = list.map(int.toUnsigned).toList(); + final Pointer ptr = allocate(count: list.length); + for (var i = 0; i < list.length; i++) { + ptr[i] = list[i]; + } + return ptr; + } + static Pointer> _listStringToPtr(List list) { final listUtf8 = list.map(Utf8.toUtf8).toList(); final Pointer> ptr = allocate(count: listUtf8.length);