feat(dubp): impl simple payment from transparent account

This commit is contained in:
librelois 2021-03-27 23:36:39 +01:00
parent 2d1652db2c
commit 279f35d6c4
13 changed files with 1343 additions and 58 deletions

1097
Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -11,6 +11,8 @@ crate-type = ["rlib"]
[dependencies]
allo-isolate = "0.1.6"
dubp-client = { git = "https://git.duniter.org/libs/dubp-rs-client-lib", branch = "master", features = ["blocking"], default-features = false }
#dubp-client= { path = "../dubp-rs-client-lib", features = ["blocking"], default-features = false }
dup-crypto = { version = "0.46.0", features = ["bip32-ed25519", "dewif", "mnemonic", "mnemonic_french", "scrypt"] }
fast-threadpool = { version = "0.3.0", default-features = false }
once_cell = { version = "1.3.1", default-features = false, features = ["std"] }

View File

@ -28,9 +28,12 @@ pub(super) fn change_secret_code(
let new_log_n = log_n(system_memory);
let new_secret_code = gen_secret_code(member_wallet, secret_code_type, new_log_n)?;
let new_dewif =
dup_crypto::dewif::change_dewif_passphrase(dewif, old_secret_code, &new_secret_code)
.map_err(DubpError::DewifReadError)?;
let new_dewif = dubp_client::crypto::dewif::change_dewif_passphrase(
dewif,
old_secret_code,
&new_secret_code,
)
.map_err(DubpError::DewifReadError)?;
Ok(vec![new_dewif, new_secret_code])
}
@ -46,15 +49,20 @@ pub(super) fn gen_dewif(
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 seed = dubp_client::crypto::mnemonic::mnemonic_to_seed(&mnemonic);
let log_n = log_n(system_memory);
let secret_code = gen_secret_code(member_wallet, secret_code_type, log_n)?;
let keypair = dup_crypto::keys::ed25519::bip32::KeyPair::from_seed(seed.clone());
let keypair = dubp_client::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);
let dewif = dubp_client::crypto::dewif::write_dewif_v4_content(
currency,
log_n,
&secret_code,
&pubkey,
seed,
);
Ok(vec![dewif, secret_code])
}
@ -64,11 +72,11 @@ pub(super) fn get_dewif_meta(
member_wallet: bool,
secret_code_type: SecretCodeType,
) -> Result<Vec<String>, DubpError> {
let dup_crypto::dewif::DewifMeta {
let dubp_client::crypto::dewif::DewifMeta {
currency,
log_n,
version,
} = dup_crypto::dewif::read_dewif_meta(dewif).map_err(DubpError::DewifReadError)?;
} = dubp_client::crypto::dewif::read_dewif_meta(dewif).map_err(DubpError::DewifReadError)?;
let secret_code_len =
crate::secret_code::compute_secret_code_len(member_wallet, secret_code_type, log_n)?;
@ -98,7 +106,7 @@ pub(super) fn get_pubkey(
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 = dubp_client::crypto::dewif::read_dewif_file_content(
ExpectedCurrency::Specific(currency),
dewif,
&secret_code.to_ascii_uppercase(),
@ -125,7 +133,7 @@ pub(super) fn get_secret_code_len(
let member_wallet = member_wallet != 0;
let secret_code_type = SecretCodeType::from(secret_code_type);
let log_n = dup_crypto::dewif::read_dewif_log_n(ExpectedCurrency::Any, dewif)
let log_n = dubp_client::crypto::dewif::read_dewif_log_n(ExpectedCurrency::Any, dewif)
.map_err(DubpError::DewifReadError)?;
Ok(crate::secret_code::compute_secret_code_len(

View File

@ -34,7 +34,7 @@ pub(crate) fn get_accounts_pubkeys(
if accounts_indexs.contains(&U31::new(0)?) {
verify_member_secret_code(currency, dewif, secret_code)?;
}
let mut keypairs = dup_crypto::dewif::read_dewif_file_content(
let mut keypairs = dubp_client::crypto::dewif::read_dewif_file_content(
ExpectedCurrency::Specific(currency),
dewif,
&secret_code.to_ascii_uppercase(),
@ -53,15 +53,15 @@ pub(crate) fn get_accounts_pubkeys(
}
}
pub(crate) fn get_bip32_pubkey(
pub(crate) fn get_bip32_keypair(
account_index: u32,
address_index_opt: Option<U31>,
currency: Currency,
dewif: &str,
external_opt: Option<bool>,
secret_code: &str,
) -> Result<String, DubpError> {
let mut keypairs = dup_crypto::dewif::read_dewif_file_content(
) -> Result<KeyPairEnum, DubpError> {
let mut keypairs = dubp_client::crypto::dewif::read_dewif_file_content(
ExpectedCurrency::Specific(currency),
dewif,
&secret_code.to_ascii_uppercase(),
@ -73,12 +73,44 @@ pub(crate) fn get_bip32_pubkey(
}
match keypairs.next() {
Some(KeyPairEnum::Bip32Ed25519(master_keypair)) => get_bip32_pubkey_inner(
account_index,
address_index_opt,
external_opt,
master_keypair,
),
Some(KeyPairEnum::Bip32Ed25519(master_keypair)) => {
Ok(KeyPairEnum::Bip32Ed25519(master_keypair.derive(
z_get_derivation_path(account_index, address_index_opt, external_opt)?,
)))
}
Some(_) => Err(DubpError::NotHdWallet),
None => Err(DubpError::DewifReadError(DewifReadError::CorruptedContent)),
}
}
pub(crate) fn get_bip32_pubkey(
account_index: u32,
address_index_opt: Option<U31>,
currency: Currency,
dewif: &str,
external_opt: Option<bool>,
secret_code: &str,
) -> Result<String, DubpError> {
let mut keypairs = dubp_client::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)) => Ok(master_keypair
.derive(z_get_derivation_path(
account_index,
address_index_opt,
external_opt,
)?)
.public_key()
.to_base58()),
Some(_) => Err(DubpError::NotHdWallet),
None => Err(DubpError::DewifReadError(DewifReadError::CorruptedContent)),
}
@ -111,7 +143,7 @@ pub(crate) fn load_opaque_bip32_accounts(
dewif: &str,
secret_code: &str,
) -> Result<(), DubpError> {
let mut keypairs = dup_crypto::dewif::read_dewif_file_content(
let mut keypairs = dubp_client::crypto::dewif::read_dewif_file_content(
ExpectedCurrency::Specific(currency),
dewif,
&secret_code.to_ascii_uppercase(),
@ -147,7 +179,7 @@ pub(crate) fn sign_bip32(
secret_code: &str,
msg: &str,
) -> Result<String, DubpError> {
let mut keypairs = dup_crypto::dewif::read_dewif_file_content(
let mut keypairs = dubp_client::crypto::dewif::read_dewif_file_content(
ExpectedCurrency::Specific(currency),
dewif,
&secret_code.to_ascii_uppercase(),
@ -180,7 +212,7 @@ pub(crate) fn sign_several_bip32(
secret_code: &str,
msgs: &[&str],
) -> Result<Vec<String>, DubpError> {
let mut keypairs = dup_crypto::dewif::read_dewif_file_content(
let mut keypairs = dubp_client::crypto::dewif::read_dewif_file_content(
ExpectedCurrency::Specific(currency),
dewif,
&secret_code.to_ascii_uppercase(),
@ -204,22 +236,6 @@ pub(crate) fn sign_several_bip32(
}
}
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>,
@ -265,9 +281,11 @@ fn verify_member_secret_code(
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 log_n = dubp_client::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)?;

View File

@ -21,7 +21,7 @@ pub(crate) fn sign(
secret_code: &str,
msg: &str,
) -> Result<String, DubpError> {
let mut keypairs = dup_crypto::dewif::read_dewif_file_content(
let mut keypairs = dubp_client::crypto::dewif::read_dewif_file_content(
ExpectedCurrency::Specific(currency),
dewif,
&secret_code.to_ascii_uppercase(),
@ -40,7 +40,7 @@ pub(crate) fn sign_several(
secret_code: &str,
msgs: &[&str],
) -> Result<Vec<String>, DubpError> {
let mut keypairs = dup_crypto::dewif::read_dewif_file_content(
let mut keypairs = dubp_client::crypto::dewif::read_dewif_file_content(
ExpectedCurrency::Specific(currency),
dewif,
&secret_code.to_ascii_uppercase(),

View File

@ -16,6 +16,7 @@
use crate::*;
/// Dubp error
#[allow(clippy::large_enum_variant)]
#[derive(Debug, Error)]
pub(crate) enum DubpError {
#[error("{0}")]
@ -26,6 +27,8 @@ pub(crate) enum DubpError {
GetMasterPubkeyOfHdWallet,
#[error("Give external bool or address index for legacy wallet.")]
GiveExternalBoolOrAddressIndexForLegacyWallet,
#[error("{0}")]
GvaClientError(dubp_client::GvaClientError),
#[error("I/O error: {0}")]
IoErr(io::Error),
#[error("{0}")]
@ -33,6 +36,8 @@ pub(crate) enum DubpError {
#[error("{0}")]
InvalidPubkey(PublicKeyFromStrErr),
#[error("{0}")]
InvalidScript(dubp_client::documents_parser::TextParseError),
#[error("{0}")]
InvalidU31(U31Error),
#[error("Invalid secret code type")]
InvalidSecretCodeType,
@ -44,6 +49,8 @@ pub(crate) enum DubpError {
NullParamErr,
#[error("Opaque account not loaded")]
OpaqueAccountNotLoaded,
#[error("Payment error: {0}")]
PaymentError(String),
#[error("Secret code too short: please change your secret code")]
SecretCodeTooShort,
#[error("The chaining address cannot be used to sign with opaque account")]

View File

@ -52,6 +52,20 @@ pub(crate) fn char_ptr_to_str<'a>(c_char_ptr: *const raw::c_char) -> Result<&'a
}
}
pub(crate) fn char_ptr_to_opt_string(
c_char_ptr: *const raw::c_char,
) -> Result<Option<String>, DubpError> {
Ok(if c_char_ptr.is_null() {
None
} else {
Some(
unsafe { CStr::from_ptr(c_char_ptr).to_str() }
.map_err(DubpError::Utf8Error)?
.to_owned(),
)
})
}
pub(crate) fn char_ptr_prt_to_vec_u31(
u32_ptr: *const u32,
len: u32,

View File

@ -14,7 +14,7 @@
// along with this program. If not, see <https://www.gnu.org/licenses/>.
use crate::*;
use dup_crypto::keys::ed25519::{KeyPairFromSaltedPasswordGenerator, SaltedPassword};
use dubp_client::crypto::keys::ed25519::{KeyPairFromSaltedPasswordGenerator, SaltedPassword};
pub(super) fn gen_dewif_from_legacy(
currency: &str,
@ -30,7 +30,8 @@ pub(super) fn gen_dewif_from_legacy(
let log_n = crate::dewif::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 dewif =
dubp_client::crypto::dewif::write_dewif_v3_content(currency, &keypair, log_n, &secret_code);
let pubkey = keypair.public_key().to_base58();
Ok(vec![dewif, secret_code, pubkey])
}

View File

@ -21,6 +21,7 @@ mod error;
mod inputs;
mod legacy;
mod mnemonic;
mod payment;
mod pubkey;
mod secret_code;
@ -29,7 +30,7 @@ use crate::inputs::*;
use crate::r#async::exec_async;
use crate::secret_code::gen_secret_code;
use allo_isolate::{IntoDart, Isolate};
use dup_crypto::{
use dubp_client::crypto::{
bases::b58::ToBase58,
dewif::{Currency, DewifReadError, ExpectedCurrency, G1_CURRENCY, G1_TEST_CURRENCY},
keys::{
@ -459,3 +460,59 @@ pub extern "C" fn sign_several(
},
)
}
#[no_mangle]
pub extern "C" fn simple_payment_bip32(
port: i64,
account_index: u32,
amount: f64,
currency: *const raw::c_char,
dewif: *const raw::c_char,
gva_endpoint: *const raw::c_char,
recipient: *const raw::c_char,
secret_code: *const raw::c_char,
tx_comment: *const raw::c_char,
) {
exec_async(
port,
|| {
let currency = parse_currency(char_ptr_to_str(currency)?)?;
let dewif = char_ptr_to_str(dewif)?;
let gva_endpoint = char_ptr_to_str(gva_endpoint)?;
let recipient = char_ptr_to_str(recipient)?;
let secret_code = char_ptr_to_str(secret_code)?;
let tx_comment = char_ptr_to_opt_string(tx_comment)?;
Ok((
account_index,
amount,
currency,
dewif,
gva_endpoint,
secret_code,
recipient,
tx_comment,
))
},
|(
account_index,
amount,
currency,
dewif,
gva_endpoint,
secret_code,
recipient,
tx_comment,
)| {
payment::simple_payment(
account_index,
amount,
currency,
dewif,
gva_endpoint,
secret_code,
recipient,
tx_comment,
)
},
)
}

View File

@ -24,7 +24,7 @@ pub(super) fn gen_mnemonic(language: Language) -> Result<String, DubpError> {
pub(super) fn mnemonic_to_pubkey(language: Language, mnemonic: &str) -> Result<String, DubpError> {
let mnemonic =
Mnemonic::from_phrase(mnemonic, language).map_err(|_| DubpError::WrongLanguage)?;
let seed = dup_crypto::mnemonic::mnemonic_to_seed(&mnemonic);
let seed = dubp_client::crypto::mnemonic::mnemonic_to_seed(&mnemonic);
let keypair = KeyPairFromSeed32Generator::generate(seed);
Ok(keypair.public_key().to_base58())
}

View File

@ -0,0 +1,66 @@
// 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::*;
use dubp_client::wallet::prelude::*;
use dubp_client::{GvaClient, NaiveGvaClient};
#[allow(clippy::too_many_arguments)]
pub(super) fn simple_payment(
account_index: u32,
amount: f64,
currency: Currency,
dewif: &str,
gva_endpoint: &str,
secret_code: &str,
recipient: &str,
tx_comment: Option<String>,
) -> Result<(), DubpError> {
let keypair = crate::dewif::bip32::get_bip32_keypair(
account_index,
None,
currency,
dewif,
None,
secret_code,
)?;
let gva_client = NaiveGvaClient::new(gva_endpoint).expect("invalid' endpoint");
let amount = dubp_client::Amount::Uds(amount);
let recipient = if let Ok(pubkey) = PublicKey::from_base58(recipient) {
WalletScriptV10::single_sig(pubkey)
} else {
dubp_client::documents_parser::wallet_script_from_str(recipient)
.map_err(DubpError::InvalidScript)?
};
let res = match keypair.generate_signator() {
dubp_client::crypto::keys::SignatorEnum::Ed25519(signator) => gva_client
.simple_payment(amount, &signator, recipient, tx_comment, None)
.map_err(DubpError::GvaClientError)?,
dubp_client::crypto::keys::SignatorEnum::Schnorr() => unreachable!(),
dubp_client::crypto::keys::SignatorEnum::Bip32Ed25519(signator) => gva_client
.simple_payment(amount, &signator, recipient, tx_comment, None)
.map_err(DubpError::GvaClientError)?,
};
if let dubp_client::PaymentResult::Errors(errors) = res {
Err(DubpError::PaymentError(format!("{:?}", errors)))
} else {
Ok(())
}
}

View File

@ -67,7 +67,7 @@ pub(crate) fn is_ascii_letters(secret_code: &str) -> bool {
}
fn gen_random_digits(n: usize) -> Result<String, DubpError> {
let mut digits_string = dup_crypto::rand::gen_u32()
let mut digits_string = dubp_client::crypto::rand::gen_u32()
.map_err(|_| DubpError::RandErr)?
.to_string();
digits_string.truncate(n);
@ -97,7 +97,7 @@ fn gen_random_letters(mut n: usize) -> Result<String, DubpError> {
}
fn gen_random_letters_inner(n: usize) -> Result<String, DubpError> {
let mut i = dup_crypto::rand::gen_u32().map_err(|_| DubpError::RandErr)?;
let mut i = dubp_client::crypto::rand::gen_u32().map_err(|_| DubpError::RandErr)?;
let mut letters = String::new();
for _ in 0..n {

View File

@ -399,6 +399,35 @@ class DubpRust {
return completer.future;
}
/// Make a simple payment from a transparent account
static Future<void> simplePaymentFromTransparentAccount(
{int accountIndex,
double amount,
String currency = "g1",
String dewif,
String gvaEndpoint,
String recipient,
String secretCode,
String txComment}) {
final completer = Completer<void>();
final sendPort =
singleCompletePort<void, String>(completer, callback: _handleErrVoid);
native.simple_payment_bip32(
sendPort.nativePort,
accountIndex,
amount,
StringUtf8Pointer(currency).toNativeUtf8(),
StringUtf8Pointer(dewif).toNativeUtf8(),
StringUtf8Pointer(gvaEndpoint).toNativeUtf8(),
StringUtf8Pointer(recipient).toNativeUtf8(),
StringUtf8Pointer(secretCode).toNativeUtf8(),
StringUtf8Pointer(txComment).toNativeUtf8(),
);
return completer.future;
}
static Pointer<Uint32> _listIntToPtrUint32(List<int> list) {
final listUint32 = list.map((i) => i.toUnsigned(31)).toList();
final Pointer<Uint32> ptr = malloc.allocate(listUint32.length);