mirror of
https://github.com/jwinterm/grin-wallet.git
synced 2026-10-17 07:11:36 +02:00
Late locking (experimental) (#530)
* Late locking (experimental) * Error on fee change * Improve comments * Fix typo in comment * Add late locking flag to CLI command
This commit is contained in:
@@ -105,6 +105,9 @@ where
|
||||
use_test_rng,
|
||||
)?;
|
||||
|
||||
// Add our contribution to the offset
|
||||
ret_slate.adjust_offset(&keychain, &context)?;
|
||||
|
||||
let excess = ret_slate.calc_excess(keychain.secp())?;
|
||||
|
||||
if let Some(ref mut p) = ret_slate.payment_proof {
|
||||
@@ -143,6 +146,9 @@ where
|
||||
if sl.state == SlateState::Invoice2 {
|
||||
check_ttl(w, &sl)?;
|
||||
|
||||
// Add our contribution to the offset
|
||||
sl.adjust_offset(&w.keychain(keychain_mask)?, &context)?;
|
||||
|
||||
let mut temp_ctx = context.clone();
|
||||
temp_ctx.sec_key = context.initial_sec_key.clone();
|
||||
temp_ctx.sec_nonce = context.initial_sec_nonce.clone();
|
||||
|
||||
@@ -457,9 +457,9 @@ where
|
||||
C: NodeClient + 'a,
|
||||
K: Keychain + 'a,
|
||||
{
|
||||
let parent_key_id = match args.src_acct_name {
|
||||
let parent_key_id = match &args.src_acct_name {
|
||||
Some(d) => {
|
||||
let pm = w.get_acct_path(d)?;
|
||||
let pm = w.get_acct_path(d.clone())?;
|
||||
match pm {
|
||||
Some(p) => p.path,
|
||||
None => w.parent_key_id(),
|
||||
@@ -500,19 +500,31 @@ where
|
||||
}
|
||||
|
||||
let height = w.w2n_client().get_chain_tip()?.0;
|
||||
let mut context = tx::add_inputs_to_slate(
|
||||
&mut *w,
|
||||
keychain_mask,
|
||||
&mut slate,
|
||||
height,
|
||||
args.minimum_confirmations,
|
||||
args.max_outputs as usize,
|
||||
args.num_change_outputs as usize,
|
||||
args.selection_strategy_is_use_all,
|
||||
&parent_key_id,
|
||||
true,
|
||||
use_test_rng,
|
||||
)?;
|
||||
let mut context = if args.late_lock.unwrap_or(false) {
|
||||
tx::create_late_lock_context(
|
||||
&mut *w,
|
||||
keychain_mask,
|
||||
&mut slate,
|
||||
height,
|
||||
&args,
|
||||
&parent_key_id,
|
||||
use_test_rng,
|
||||
)?
|
||||
} else {
|
||||
tx::add_inputs_to_slate(
|
||||
&mut *w,
|
||||
keychain_mask,
|
||||
&mut slate,
|
||||
height,
|
||||
args.minimum_confirmations,
|
||||
args.max_outputs as usize,
|
||||
args.num_change_outputs as usize,
|
||||
args.selection_strategy_is_use_all,
|
||||
&parent_key_id,
|
||||
true,
|
||||
use_test_rng,
|
||||
)?
|
||||
};
|
||||
|
||||
// Payment Proof, add addresses to slate and save address
|
||||
// TODO: Note we only use single derivation path for now,
|
||||
@@ -667,6 +679,19 @@ where
|
||||
)?;
|
||||
|
||||
let keychain = w.keychain(keychain_mask)?;
|
||||
|
||||
// Add our contribution to the offset
|
||||
if context_res.is_ok() {
|
||||
// Self sending: don't correct for inputs and outputs
|
||||
// here, as we will do it during finalization.
|
||||
let mut tmp_context = context.clone();
|
||||
tmp_context.input_ids.clear();
|
||||
tmp_context.output_ids.clear();
|
||||
ret_slate.adjust_offset(&keychain, &tmp_context)?;
|
||||
} else {
|
||||
ret_slate.adjust_offset(&keychain, &context)?;
|
||||
}
|
||||
|
||||
// needs to be stored as we're removing sig data for return trip. this needs to be present
|
||||
// when locking transaction context and updating tx log with excess later
|
||||
context.calculated_excess = Some(ret_slate.calc_excess(keychain.secp())?);
|
||||
@@ -685,7 +710,6 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
tx::sub_inputs_from_offset(&mut *w, keychain_mask, &context, &mut ret_slate)?;
|
||||
selection::repopulate_tx(&mut *w, keychain_mask, &mut ret_slate, &context, false)?;
|
||||
|
||||
// Save the aggsig context in our DB for when we
|
||||
@@ -754,16 +778,51 @@ where
|
||||
{
|
||||
let mut sl = slate.clone();
|
||||
check_ttl(w, &sl)?;
|
||||
let context = w.get_private_context(keychain_mask, sl.id.as_bytes())?;
|
||||
let mut context = w.get_private_context(keychain_mask, sl.id.as_bytes())?;
|
||||
let keychain = w.keychain(keychain_mask)?;
|
||||
let parent_key_id = w.parent_key_id();
|
||||
|
||||
// since we're now actually inserting our inputs, pick an offset and adjust
|
||||
// our contribution to the excess by offset amount
|
||||
// TODO: Post HF3, this should allow for inputs to be picked at this stage
|
||||
// as opposed to locking them prior to this stage, as the excess to this point
|
||||
// will just be the change output
|
||||
if let Some(args) = context.late_lock_args.take() {
|
||||
// Transaction was late locked, select inputs+change now
|
||||
// and insert into original context
|
||||
|
||||
let current_height = w.w2n_client().get_chain_tip()?.0;
|
||||
let mut temp_sl =
|
||||
tx::new_tx_slate(&mut *w, context.amount, false, 2, false, args.ttl_blocks)?;
|
||||
let temp_context = selection::build_send_tx(
|
||||
w,
|
||||
&keychain,
|
||||
keychain_mask,
|
||||
&mut temp_sl,
|
||||
current_height,
|
||||
args.minimum_confirmations,
|
||||
args.max_outputs as usize,
|
||||
args.num_change_outputs as usize,
|
||||
args.selection_strategy_is_use_all,
|
||||
Some(context.fee),
|
||||
parent_key_id.clone(),
|
||||
false,
|
||||
true,
|
||||
)?;
|
||||
|
||||
// Add inputs and outputs to original context
|
||||
context.input_ids = temp_context.input_ids;
|
||||
context.output_ids = temp_context.output_ids;
|
||||
|
||||
// Store the updated context
|
||||
{
|
||||
let mut batch = w.batch(keychain_mask)?;
|
||||
batch.save_private_context(sl.id.as_bytes(), &context)?;
|
||||
batch.commit()?;
|
||||
}
|
||||
|
||||
// Now do the actual locking
|
||||
tx_lock_outputs(w, keychain_mask, &sl)?;
|
||||
}
|
||||
|
||||
// Add our contribution to the offset
|
||||
sl.adjust_offset(&keychain, &context)?;
|
||||
|
||||
tx::sub_inputs_from_offset(&mut *w, keychain_mask, &context, &mut sl)?;
|
||||
selection::repopulate_tx(&mut *w, keychain_mask, &mut sl, &context, true)?;
|
||||
|
||||
tx::complete_tx(&mut *w, keychain_mask, &mut sl, &context)?;
|
||||
|
||||
@@ -25,7 +25,7 @@ use crate::SlatepackAddress;
|
||||
use ed25519_dalek::Signature as DalekSignature;
|
||||
|
||||
/// V2 Init / Send TX API Args
|
||||
#[derive(Clone, Serialize, Deserialize)]
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
pub struct InitTxArgs {
|
||||
/// The human readable account name from which to draw outputs
|
||||
/// for the transaction, overriding whatever the active account is as set via the
|
||||
@@ -71,6 +71,10 @@ pub struct InitTxArgs {
|
||||
/// 'true', the amount field in the slate will contain the total amount locked, not the provided
|
||||
/// transaction amount
|
||||
pub estimate_only: Option<bool>,
|
||||
/// EXPERIMENTAL: if flagged, create the transaction as late-locked, i.e. don't select actual
|
||||
/// inputs until just before finalization
|
||||
#[serde(default)]
|
||||
pub late_lock: Option<bool>,
|
||||
/// Sender arguments. If present, the underlying function will also attempt to send the
|
||||
/// transaction to a destination and optionally finalize the result
|
||||
pub send_args: Option<InitTxSendArgs>,
|
||||
@@ -78,7 +82,7 @@ pub struct InitTxArgs {
|
||||
|
||||
/// Send TX API Args, for convenience functionality that inits the transaction and sends
|
||||
/// in one go
|
||||
#[derive(Clone, Serialize, Deserialize)]
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
pub struct InitTxSendArgs {
|
||||
/// The destination, contents will depend on the particular method
|
||||
pub dest: String,
|
||||
@@ -103,6 +107,7 @@ impl Default for InitTxArgs {
|
||||
ttl_blocks: None,
|
||||
estimate_only: Some(false),
|
||||
payment_proof_recipient_address: None,
|
||||
late_lock: Some(false),
|
||||
send_args: None,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -46,8 +46,10 @@ pub fn build_send_tx<'a, T: ?Sized, C, K>(
|
||||
max_outputs: usize,
|
||||
change_outputs: usize,
|
||||
selection_strategy_is_use_all: bool,
|
||||
fixed_fee: Option<u64>,
|
||||
parent_key_id: Identifier,
|
||||
use_test_nonce: bool,
|
||||
is_initiator: bool,
|
||||
) -> Result<Context, Error>
|
||||
where
|
||||
T: WalletBackend<'a, C, K>,
|
||||
@@ -67,17 +69,20 @@ where
|
||||
false,
|
||||
)?;
|
||||
|
||||
if fixed_fee.map(|f| fee != f).unwrap_or(false) {
|
||||
return Err(ErrorKind::Fee("The initially selected fee is not sufficient".into()).into());
|
||||
}
|
||||
|
||||
// Update the fee on the slate so we account for this when building the tx.
|
||||
slate.fee = fee;
|
||||
|
||||
let blinding = slate.add_transaction_elements(keychain, &ProofBuilder::new(keychain), elems)?;
|
||||
slate.add_transaction_elements(keychain, &ProofBuilder::new(keychain), elems)?;
|
||||
|
||||
// Create our own private context
|
||||
let mut context = Context::new(
|
||||
keychain.secp(),
|
||||
blinding.secret_key(&keychain.secp()).unwrap(),
|
||||
&parent_key_id,
|
||||
use_test_nonce,
|
||||
is_initiator,
|
||||
);
|
||||
|
||||
context.fee = fee;
|
||||
@@ -237,6 +242,7 @@ pub fn build_recipient_output<'a, T: ?Sized, C, K>(
|
||||
current_height: u64,
|
||||
parent_key_id: Identifier,
|
||||
use_test_rng: bool,
|
||||
is_initiator: bool,
|
||||
) -> Result<(Identifier, Context, TxLogEntry), Error>
|
||||
where
|
||||
T: WalletBackend<'a, C, K>,
|
||||
@@ -251,21 +257,14 @@ where
|
||||
let height = current_height;
|
||||
|
||||
let slate_id = slate.id;
|
||||
let blinding = slate.add_transaction_elements(
|
||||
slate.add_transaction_elements(
|
||||
&keychain,
|
||||
&ProofBuilder::new(&keychain),
|
||||
vec![build::output(amount, key_id.clone())],
|
||||
)?;
|
||||
|
||||
// Add blinding sum to our context
|
||||
let mut context = Context::new(
|
||||
keychain.secp(),
|
||||
blinding
|
||||
.secret_key(wallet.keychain(keychain_mask)?.secp())
|
||||
.unwrap(),
|
||||
&parent_key_id,
|
||||
use_test_rng,
|
||||
);
|
||||
let mut context = Context::new(keychain.secp(), &parent_key_id, use_test_rng, is_initiator);
|
||||
|
||||
context.add_output(&key_id, &None, amount);
|
||||
context.amount = amount;
|
||||
@@ -398,9 +397,6 @@ where
|
||||
// recipient should double check the fee calculation and not blindly trust the
|
||||
// sender
|
||||
|
||||
// TODO - Is it safe to spend without a change output? (1 input -> 1 output)
|
||||
// TODO - Does this not potentially reveal the senders private key?
|
||||
//
|
||||
// First attempt to spend without change
|
||||
let mut fee = tx_fee(coins.len(), 1, 1, None);
|
||||
let mut total: u64 = coins.iter().map(|c| c.value).sum();
|
||||
@@ -665,7 +661,7 @@ where
|
||||
let keychain = wallet.keychain(keychain_mask)?;
|
||||
|
||||
// restore my signature data
|
||||
slate.add_participant_info(&keychain, &context.sec_key, &context.sec_nonce, None)?;
|
||||
slate.add_participant_info(&keychain, &context, None)?;
|
||||
|
||||
let mut parts = vec![];
|
||||
for (id, _, value) in &context.get_inputs() {
|
||||
|
||||
@@ -20,7 +20,7 @@ use uuid::Uuid;
|
||||
|
||||
use crate::grin_core::consensus::valid_header_version;
|
||||
use crate::grin_core::core::HeaderVersion;
|
||||
use crate::grin_keychain::{BlindSum, BlindingFactor, Identifier, Keychain, SwitchCommitmentType};
|
||||
use crate::grin_keychain::{Identifier, Keychain};
|
||||
use crate::grin_util::secp::key::SecretKey;
|
||||
use crate::grin_util::secp::pedersen;
|
||||
use crate::grin_util::Mutex;
|
||||
@@ -28,6 +28,7 @@ use crate::internal::{selection, updater};
|
||||
use crate::slate::Slate;
|
||||
use crate::types::{Context, NodeClient, StoredProofInfo, TxLogEntryType, WalletBackend};
|
||||
use crate::util::OnionV3Address;
|
||||
use crate::InitTxArgs;
|
||||
use crate::{address, Error, ErrorKind};
|
||||
use ed25519_dalek::Keypair as DalekKeypair;
|
||||
use ed25519_dalek::PublicKey as DalekPublicKey;
|
||||
@@ -175,19 +176,16 @@ where
|
||||
max_outputs,
|
||||
num_change_outputs,
|
||||
selection_strategy_is_use_all,
|
||||
None,
|
||||
parent_key_id.clone(),
|
||||
use_test_rng,
|
||||
is_initiator,
|
||||
)?;
|
||||
|
||||
// Generate a kernel offset and subtract from our context's secret key. Store
|
||||
// the offset in the slate's transaction kernel, and adds our public key
|
||||
// information to the slate
|
||||
slate.fill_round_1(
|
||||
&wallet.keychain(keychain_mask)?,
|
||||
&mut context.sec_key,
|
||||
&context.sec_nonce,
|
||||
use_test_rng,
|
||||
)?;
|
||||
slate.fill_round_1(&wallet.keychain(keychain_mask)?, &mut context)?;
|
||||
|
||||
context.initial_sec_key = context.sec_key.clone();
|
||||
|
||||
@@ -227,15 +225,11 @@ where
|
||||
current_height,
|
||||
parent_key_id.clone(),
|
||||
use_test_rng,
|
||||
is_initiator,
|
||||
)?;
|
||||
|
||||
// fill public keys
|
||||
slate.fill_round_1(
|
||||
&keychain,
|
||||
&mut context.sec_key,
|
||||
&context.sec_nonce,
|
||||
use_test_rng,
|
||||
)?;
|
||||
slate.fill_round_1(&keychain, &mut context)?;
|
||||
|
||||
context.initial_sec_key = context.sec_key.clone();
|
||||
|
||||
@@ -252,6 +246,53 @@ where
|
||||
Ok(context)
|
||||
}
|
||||
|
||||
/// Create context, without adding inputs to slate
|
||||
pub fn create_late_lock_context<'a, T: ?Sized, C, K>(
|
||||
wallet: &mut T,
|
||||
keychain_mask: Option<&SecretKey>,
|
||||
slate: &mut Slate,
|
||||
current_height: u64,
|
||||
init_tx_args: &InitTxArgs,
|
||||
parent_key_id: &Identifier,
|
||||
use_test_rng: bool,
|
||||
) -> Result<Context, Error>
|
||||
where
|
||||
T: WalletBackend<'a, C, K>,
|
||||
C: NodeClient + 'a,
|
||||
K: Keychain + 'a,
|
||||
{
|
||||
// sender should always refresh outputs
|
||||
updater::refresh_outputs(wallet, keychain_mask, parent_key_id, false)?;
|
||||
|
||||
// we're just going to run a selection to get the potential fee,
|
||||
// but this won't be locked
|
||||
let (_coins, _total, _amount, fee) = selection::select_coins_and_fee(
|
||||
wallet,
|
||||
init_tx_args.amount,
|
||||
current_height,
|
||||
init_tx_args.minimum_confirmations,
|
||||
init_tx_args.max_outputs as usize,
|
||||
init_tx_args.num_change_outputs as usize,
|
||||
init_tx_args.selection_strategy_is_use_all,
|
||||
&parent_key_id,
|
||||
)?;
|
||||
slate.fee = fee;
|
||||
|
||||
let keychain = wallet.keychain(keychain_mask)?;
|
||||
|
||||
// Create our own private context
|
||||
let mut context = Context::new(keychain.secp(), &parent_key_id, use_test_rng, true);
|
||||
context.fee = slate.fee;
|
||||
context.amount = slate.amount;
|
||||
context.late_lock_args = Some(init_tx_args.clone());
|
||||
|
||||
// Generate a blinding factor for the tx and add
|
||||
// public key info to the slate
|
||||
slate.fill_round_1(&wallet.keychain(keychain_mask)?, &mut context)?;
|
||||
|
||||
Ok(context)
|
||||
}
|
||||
|
||||
/// Complete a transaction
|
||||
pub fn complete_tx<'a, T: ?Sized, C, K>(
|
||||
wallet: &mut T,
|
||||
@@ -396,47 +437,6 @@ where
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Update the transaction's offset by subtracting the inputs
|
||||
/// stored in the context
|
||||
pub fn sub_inputs_from_offset<'a, T: ?Sized, C, K>(
|
||||
wallet: &mut T,
|
||||
keychain_mask: Option<&SecretKey>,
|
||||
context: &Context,
|
||||
slate: &mut Slate,
|
||||
) -> Result<(), Error>
|
||||
where
|
||||
T: WalletBackend<'a, C, K>,
|
||||
C: NodeClient + 'a,
|
||||
K: Keychain + 'a,
|
||||
{
|
||||
let k = wallet.keychain(keychain_mask)?;
|
||||
// Offset has been created and adjusted
|
||||
// Now subtract sum total of all my inputs from the offset
|
||||
let new_offset = k.blind_sum(
|
||||
&context
|
||||
.get_inputs()
|
||||
.iter()
|
||||
.map(
|
||||
|i| match k.derive_key(i.2, &i.0, SwitchCommitmentType::Regular) {
|
||||
Ok(k) => BlindingFactor::from_secret_key(k),
|
||||
Err(e) => {
|
||||
error!("Error deriving key for offset: {}", e);
|
||||
BlindingFactor::zero()
|
||||
}
|
||||
},
|
||||
)
|
||||
.fold(
|
||||
BlindSum::new().add_blinding_factor(slate.offset.clone()),
|
||||
|acc, x| acc.sub_blinding_factor(x.clone()),
|
||||
),
|
||||
)?;
|
||||
|
||||
slate.offset = new_offset.clone();
|
||||
slate.tx_or_err_mut()?.offset = new_offset;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn payment_proof_message(
|
||||
amount: u64,
|
||||
kernel_commitment: &pedersen::Commitment,
|
||||
|
||||
+32
-57
@@ -24,15 +24,13 @@ use crate::grin_core::core::transaction::{
|
||||
use crate::grin_core::core::verifier_cache::LruVerifierCache;
|
||||
use crate::grin_core::libtx::{aggsig, build, proof::ProofBuild, tx_fee};
|
||||
use crate::grin_core::map_vec;
|
||||
use crate::grin_keychain::{BlindSum, BlindingFactor, Keychain};
|
||||
use crate::grin_keychain::{BlindSum, BlindingFactor, Keychain, SwitchCommitmentType};
|
||||
use crate::grin_util::secp::key::{PublicKey, SecretKey};
|
||||
use crate::grin_util::secp::pedersen::Commitment;
|
||||
use crate::grin_util::secp::Signature;
|
||||
use crate::grin_util::{secp, static_secp_instance, RwLock};
|
||||
use ed25519_dalek::PublicKey as DalekPublicKey;
|
||||
use ed25519_dalek::Signature as DalekSignature;
|
||||
use rand::rngs::mock::StepRng;
|
||||
use rand::thread_rng;
|
||||
use serde::ser::{Serialize, Serializer};
|
||||
use serde_json;
|
||||
use std::fmt;
|
||||
@@ -45,6 +43,7 @@ use crate::slate_versions::v4::{
|
||||
};
|
||||
use crate::slate_versions::VersionedSlate;
|
||||
use crate::slate_versions::{CURRENT_SLATE_VERSION, GRIN_BLOCK_HEADER_VERSION};
|
||||
use crate::Context;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct PaymentInfo {
|
||||
@@ -337,20 +336,11 @@ impl Slate {
|
||||
|
||||
/// Completes callers part of round 1, adding public key info
|
||||
/// to the slate
|
||||
pub fn fill_round_1<K>(
|
||||
&mut self,
|
||||
keychain: &K,
|
||||
sec_key: &mut SecretKey,
|
||||
sec_nonce: &SecretKey,
|
||||
use_test_rng: bool,
|
||||
) -> Result<(), Error>
|
||||
pub fn fill_round_1<K>(&mut self, keychain: &K, context: &mut Context) -> Result<(), Error>
|
||||
where
|
||||
K: Keychain,
|
||||
{
|
||||
// Always choose my part of the offset, and subtract from my excess
|
||||
self.generate_offset(keychain, sec_key, use_test_rng)?;
|
||||
self.add_participant_info(keychain, &sec_key, &sec_nonce, None)?;
|
||||
Ok(())
|
||||
self.add_participant_info(keychain, context, None)
|
||||
}
|
||||
|
||||
// Build kernel features based on variant and associated data.
|
||||
@@ -455,7 +445,7 @@ impl Slate {
|
||||
}
|
||||
|
||||
/// Return the sum of public blinding factors
|
||||
fn pub_blind_sum(&self, secp: &secp::Secp256k1) -> Result<PublicKey, Error> {
|
||||
pub fn pub_blind_sum(&self, secp: &secp::Secp256k1) -> Result<PublicKey, Error> {
|
||||
let pub_blinds: Vec<&PublicKey> = self
|
||||
.participant_data
|
||||
.iter()
|
||||
@@ -488,16 +478,15 @@ impl Slate {
|
||||
pub fn add_participant_info<K>(
|
||||
&mut self,
|
||||
keychain: &K,
|
||||
sec_key: &SecretKey,
|
||||
sec_nonce: &SecretKey,
|
||||
context: &Context,
|
||||
part_sig: Option<Signature>,
|
||||
) -> Result<(), Error>
|
||||
where
|
||||
K: Keychain,
|
||||
{
|
||||
// Add our public key and nonce to the slate
|
||||
let pub_key = PublicKey::from_secret_key(keychain.secp(), &sec_key)?;
|
||||
let pub_nonce = PublicKey::from_secret_key(keychain.secp(), &sec_nonce)?;
|
||||
let pub_key = PublicKey::from_secret_key(keychain.secp(), &context.sec_key)?;
|
||||
let pub_nonce = PublicKey::from_secret_key(keychain.secp(), &context.sec_nonce)?;
|
||||
let mut part_sig = part_sig;
|
||||
|
||||
// Remove if already here and replace
|
||||
@@ -524,46 +513,32 @@ impl Slate {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Somebody involved needs to generate an offset with their private key
|
||||
/// For now, we'll have the transaction initiator be responsible for it
|
||||
/// Return offset private key for the participant to use later in the
|
||||
/// transaction
|
||||
pub fn generate_offset<K>(
|
||||
/// Add our contribution to the offset based on the excess, inputs and outputs
|
||||
pub fn adjust_offset<K: Keychain>(
|
||||
&mut self,
|
||||
keychain: &K,
|
||||
sec_key: &mut SecretKey,
|
||||
use_test_rng: bool,
|
||||
) -> Result<(), Error>
|
||||
where
|
||||
K: Keychain,
|
||||
{
|
||||
// Generate a random kernel offset here
|
||||
// and subtract it from the blind_sum so we create
|
||||
// the aggsig context with the "split" key
|
||||
let my_offset = match use_test_rng {
|
||||
false => {
|
||||
BlindingFactor::from_secret_key(SecretKey::new(&keychain.secp(), &mut thread_rng()))
|
||||
}
|
||||
true => {
|
||||
// allow for consistent test results
|
||||
let mut test_rng = StepRng::new(1_234_567_890_u64, 1);
|
||||
BlindingFactor::from_secret_key(SecretKey::new(&keychain.secp(), &mut test_rng))
|
||||
}
|
||||
};
|
||||
|
||||
let total_offset = keychain.blind_sum(
|
||||
&BlindSum::new()
|
||||
.add_blinding_factor(self.offset.clone())
|
||||
.add_blinding_factor(my_offset.clone()),
|
||||
)?;
|
||||
self.offset = total_offset;
|
||||
|
||||
let adjusted_offset = keychain.blind_sum(
|
||||
&BlindSum::new()
|
||||
.add_blinding_factor(BlindingFactor::from_secret_key(sec_key.clone()))
|
||||
.sub_blinding_factor(my_offset),
|
||||
)?;
|
||||
*sec_key = adjusted_offset.secret_key(&keychain.secp())?;
|
||||
context: &Context,
|
||||
) -> Result<(), Error> {
|
||||
let mut sum = BlindSum::new()
|
||||
.add_blinding_factor(self.offset.clone())
|
||||
.sub_blinding_factor(BlindingFactor::from_secret_key(
|
||||
context.initial_sec_key.clone(),
|
||||
));
|
||||
for (id, _, amount) in &context.input_ids {
|
||||
sum = sum.sub_blinding_factor(BlindingFactor::from_secret_key(keychain.derive_key(
|
||||
*amount,
|
||||
id,
|
||||
SwitchCommitmentType::Regular,
|
||||
)?));
|
||||
}
|
||||
for (id, _, amount) in &context.output_ids {
|
||||
sum = sum.add_blinding_factor(BlindingFactor::from_secret_key(keychain.derive_key(
|
||||
*amount,
|
||||
id,
|
||||
SwitchCommitmentType::Regular,
|
||||
)?));
|
||||
}
|
||||
self.offset = keychain.blind_sum(&sum)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
+33
-4
@@ -27,10 +27,13 @@ use crate::grin_util::secp::key::{PublicKey, SecretKey};
|
||||
use crate::grin_util::secp::{self, pedersen, Secp256k1};
|
||||
use crate::grin_util::{ToHex, ZeroingString};
|
||||
use crate::slate_versions::ser as dalek_ser;
|
||||
use crate::InitTxArgs;
|
||||
use chrono::prelude::*;
|
||||
use ed25519_dalek::PublicKey as DalekPublicKey;
|
||||
use ed25519_dalek::Signature as DalekSignature;
|
||||
use failure::ResultExt;
|
||||
use rand::rngs::mock::StepRng;
|
||||
use rand::thread_rng;
|
||||
use serde;
|
||||
use serde_json;
|
||||
use std::collections::HashMap;
|
||||
@@ -554,6 +557,9 @@ pub struct Context {
|
||||
pub fee: u64,
|
||||
/// Payment proof sender address derivation path, if needed
|
||||
pub payment_proof_derivation_index: Option<u32>,
|
||||
/// If late-locking, store my tranasction creation prefs
|
||||
/// for later
|
||||
pub late_lock_args: Option<InitTxArgs>,
|
||||
/// for invoice I2 Only, store the tx excess so we can
|
||||
/// remove it from the slate on return
|
||||
pub calculated_excess: Option<pedersen::Commitment>,
|
||||
@@ -562,26 +568,49 @@ pub struct Context {
|
||||
impl Context {
|
||||
/// Create a new context with defaults
|
||||
pub fn new(
|
||||
secp: &secp::Secp256k1,
|
||||
parent_key_id: &Identifier,
|
||||
use_test_rng: bool,
|
||||
is_initiator: bool,
|
||||
) -> Self {
|
||||
let sec_key = match use_test_rng {
|
||||
false => SecretKey::new(secp, &mut thread_rng()),
|
||||
true => {
|
||||
// allow for consistent test results
|
||||
let mut test_rng = if is_initiator {
|
||||
StepRng::new(1_234_567_890_u64, 1)
|
||||
} else {
|
||||
StepRng::new(1_234_567_891_u64, 1)
|
||||
};
|
||||
SecretKey::new(secp, &mut test_rng)
|
||||
}
|
||||
};
|
||||
Self::with_excess(secp, sec_key, parent_key_id, use_test_rng)
|
||||
}
|
||||
|
||||
/// Create a new context with a specific excess
|
||||
pub fn with_excess(
|
||||
secp: &secp::Secp256k1,
|
||||
sec_key: SecretKey,
|
||||
parent_key_id: &Identifier,
|
||||
use_test_rng: bool,
|
||||
) -> Context {
|
||||
) -> Self {
|
||||
let sec_nonce = match use_test_rng {
|
||||
false => aggsig::create_secnonce(secp).unwrap(),
|
||||
true => SecretKey::from_slice(secp, &[1; 32]).unwrap(),
|
||||
};
|
||||
Context {
|
||||
Self {
|
||||
parent_key_id: parent_key_id.clone(),
|
||||
sec_key: sec_key.clone(),
|
||||
sec_nonce: sec_nonce.clone(),
|
||||
initial_sec_key: sec_key.clone(),
|
||||
initial_sec_nonce: sec_nonce.clone(),
|
||||
initial_sec_key: sec_key,
|
||||
initial_sec_nonce: sec_nonce,
|
||||
input_ids: vec![],
|
||||
output_ids: vec![],
|
||||
amount: 0,
|
||||
fee: 0,
|
||||
payment_proof_derivation_index: None,
|
||||
late_lock_args: None,
|
||||
calculated_excess: None,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -74,7 +74,7 @@ fn aggsig_sender_receiver_interaction() {
|
||||
|
||||
let blind = blinding_factor.secret_key(&keychain.secp()).unwrap();
|
||||
|
||||
s_cx = Context::new(&keychain.secp(), blind, &parent, false);
|
||||
s_cx = Context::with_excess(&keychain.secp(), blind, &parent, false);
|
||||
s_cx.get_public_keys(&keychain.secp())
|
||||
};
|
||||
|
||||
@@ -88,7 +88,7 @@ fn aggsig_sender_receiver_interaction() {
|
||||
// let blind = blind_sum.secret_key(&keychain.secp())?;
|
||||
let blind = keychain.derive_key(0, &key_id, switch).unwrap();
|
||||
|
||||
rx_cx = Context::new(&keychain.secp(), blind, &parent, false);
|
||||
rx_cx = Context::with_excess(&keychain.secp(), blind, &parent, false);
|
||||
let (pub_excess, pub_nonce) = rx_cx.get_public_keys(&keychain.secp());
|
||||
rx_cx.add_output(&key_id, &None, 0);
|
||||
|
||||
@@ -293,7 +293,7 @@ fn aggsig_sender_receiver_interaction_offset() {
|
||||
|
||||
let blind = blinding_factor.secret_key(&keychain.secp()).unwrap();
|
||||
|
||||
s_cx = Context::new(&keychain.secp(), blind, &parent, false);
|
||||
s_cx = Context::with_excess(&keychain.secp(), blind, &parent, false);
|
||||
s_cx.get_public_keys(&keychain.secp())
|
||||
};
|
||||
|
||||
@@ -306,7 +306,7 @@ fn aggsig_sender_receiver_interaction_offset() {
|
||||
|
||||
let blind = keychain.derive_key(0, &key_id, switch).unwrap();
|
||||
|
||||
rx_cx = Context::new(&keychain.secp(), blind, &parent, false);
|
||||
rx_cx = Context::with_excess(&keychain.secp(), blind, &parent, false);
|
||||
let (pub_excess, pub_nonce) = rx_cx.get_public_keys(&keychain.secp());
|
||||
rx_cx.add_output(&key_id, &None, 0);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user