2022-05-21 15:33:35 -04:00
|
|
|
use thiserror::Error;
|
|
|
|
|
|
|
|
|
|
use rand_core::{RngCore, CryptoRng};
|
|
|
|
|
use rand::seq::SliceRandom;
|
|
|
|
|
|
Utilize zeroize (#76)
* Apply Zeroize to nonces used in Bulletproofs
Also makes bit decomposition constant time for a given amount of
outputs.
* Fix nonce reuse for single-signer CLSAG
* Attach Zeroize to most structures in Monero, and ZOnDrop to anything with private data
* Zeroize private keys and nonces
* Merge prepare_outputs and prepare_transactions
* Ensure CLSAG is constant time
* Pass by borrow where needed, bug fixes
The past few commitments have been one in-progress chunk which I've
broken up as best read.
* Add Zeroize to FROST structs
Still needs to zeroize internally, yet next step. Not quite as
aggressive as Monero, partially due to the limitations of HashMaps,
partially due to less concern about metadata, yet does still delete a
few smaller items of metadata (group key, context string...).
* Remove Zeroize from most Monero multisig structs
These structs largely didn't have private data, just fields with private
data, yet those fields implemented ZeroizeOnDrop making them already
covered. While there is still traces of the transaction left in RAM,
fully purging that was never the intent.
* Use Zeroize within dleq
bitvec doesn't offer Zeroize, so a manual zeroing has been implemented.
* Use Zeroize for random_nonce
It isn't perfect, due to the inability to zeroize the digest, and due to
kp256 requiring a few transformations. It does the best it can though.
Does move the per-curve random_nonce to a provided one, which is allowed
as of https://github.com/cfrg/draft-irtf-cfrg-frost/pull/231.
* Use Zeroize on FROST keygen/signing
* Zeroize constant time multiexp.
* Correct when FROST keygen zeroizes
* Move the FROST keys Arc into FrostKeys
Reduces amount of instances in memory.
* Manually implement Debug for FrostCore to not leak the secret share
* Misc bug fixes
* clippy + multiexp test bug fixes
* Correct FROST key gen share summation
It leaked our own share for ourself.
* Fix cross-group DLEq tests
2022-08-03 03:25:18 -05:00
|
|
|
use zeroize::{Zeroize, ZeroizeOnDrop};
|
|
|
|
|
|
2022-07-15 01:26:07 -04:00
|
|
|
use curve25519_dalek::{constants::ED25519_BASEPOINT_TABLE, scalar::Scalar, edwards::EdwardsPoint};
|
2022-05-21 15:33:35 -04:00
|
|
|
|
|
|
|
|
#[cfg(feature = "multisig")]
|
|
|
|
|
use frost::FrostError;
|
|
|
|
|
|
|
|
|
|
use crate::{
|
2022-07-27 04:05:43 -05:00
|
|
|
Protocol, Commitment, random_scalar,
|
2022-05-22 02:24:24 -04:00
|
|
|
ringct::{
|
2022-07-10 16:11:55 -04:00
|
|
|
generate_key_image,
|
2022-05-22 02:24:24 -04:00
|
|
|
clsag::{ClsagError, ClsagInput, Clsag},
|
2022-06-19 12:03:01 -04:00
|
|
|
bulletproofs::{MAX_OUTPUTS, Bulletproofs},
|
2022-07-15 01:26:07 -04:00
|
|
|
RctBase, RctPrunable, RctSignatures,
|
2022-05-22 02:24:24 -04:00
|
|
|
},
|
2022-06-02 00:00:26 -04:00
|
|
|
transaction::{Input, Output, Timelock, TransactionPrefix, Transaction},
|
2022-05-21 15:33:35 -04:00
|
|
|
rpc::{Rpc, RpcError},
|
2022-06-28 00:01:20 -04:00
|
|
|
wallet::{
|
2022-08-22 04:27:58 -04:00
|
|
|
address::Address, SpendableOutput, Decoys, PaymentId, ExtraField, Extra, key_image_sort,
|
|
|
|
|
uniqueness, shared_key, commitment_mask, amount_encryption,
|
2022-07-15 01:26:07 -04:00
|
|
|
},
|
2022-05-21 15:33:35 -04:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
#[cfg(feature = "multisig")]
|
|
|
|
|
mod multisig;
|
2022-06-10 09:36:07 -04:00
|
|
|
#[cfg(feature = "multisig")]
|
|
|
|
|
pub use multisig::TransactionMachine;
|
2022-05-21 15:33:35 -04:00
|
|
|
|
|
|
|
|
#[allow(non_snake_case)]
|
Utilize zeroize (#76)
* Apply Zeroize to nonces used in Bulletproofs
Also makes bit decomposition constant time for a given amount of
outputs.
* Fix nonce reuse for single-signer CLSAG
* Attach Zeroize to most structures in Monero, and ZOnDrop to anything with private data
* Zeroize private keys and nonces
* Merge prepare_outputs and prepare_transactions
* Ensure CLSAG is constant time
* Pass by borrow where needed, bug fixes
The past few commitments have been one in-progress chunk which I've
broken up as best read.
* Add Zeroize to FROST structs
Still needs to zeroize internally, yet next step. Not quite as
aggressive as Monero, partially due to the limitations of HashMaps,
partially due to less concern about metadata, yet does still delete a
few smaller items of metadata (group key, context string...).
* Remove Zeroize from most Monero multisig structs
These structs largely didn't have private data, just fields with private
data, yet those fields implemented ZeroizeOnDrop making them already
covered. While there is still traces of the transaction left in RAM,
fully purging that was never the intent.
* Use Zeroize within dleq
bitvec doesn't offer Zeroize, so a manual zeroing has been implemented.
* Use Zeroize for random_nonce
It isn't perfect, due to the inability to zeroize the digest, and due to
kp256 requiring a few transformations. It does the best it can though.
Does move the per-curve random_nonce to a provided one, which is allowed
as of https://github.com/cfrg/draft-irtf-cfrg-frost/pull/231.
* Use Zeroize on FROST keygen/signing
* Zeroize constant time multiexp.
* Correct when FROST keygen zeroizes
* Move the FROST keys Arc into FrostKeys
Reduces amount of instances in memory.
* Manually implement Debug for FrostCore to not leak the secret share
* Misc bug fixes
* clippy + multiexp test bug fixes
* Correct FROST key gen share summation
It leaked our own share for ourself.
* Fix cross-group DLEq tests
2022-08-03 03:25:18 -05:00
|
|
|
#[derive(Clone, PartialEq, Eq, Debug, Zeroize, ZeroizeOnDrop)]
|
2022-05-21 15:33:35 -04:00
|
|
|
struct SendOutput {
|
|
|
|
|
R: EdwardsPoint,
|
2022-07-27 06:29:14 -04:00
|
|
|
view_tag: u8,
|
2022-05-21 15:33:35 -04:00
|
|
|
dest: EdwardsPoint,
|
2022-06-19 12:03:01 -04:00
|
|
|
commitment: Commitment,
|
2022-07-15 01:26:07 -04:00
|
|
|
amount: [u8; 8],
|
2022-05-21 15:33:35 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl SendOutput {
|
|
|
|
|
fn new<R: RngCore + CryptoRng>(
|
|
|
|
|
rng: &mut R,
|
2022-06-19 12:03:01 -04:00
|
|
|
unique: [u8; 32],
|
2022-08-22 06:54:01 -04:00
|
|
|
output: (usize, (Address, u64)),
|
|
|
|
|
) -> (SendOutput, Option<[u8; 8]>) {
|
|
|
|
|
let o = output.0;
|
|
|
|
|
let output = output.1;
|
|
|
|
|
|
2022-05-21 15:33:35 -04:00
|
|
|
let r = random_scalar(rng);
|
2022-08-22 06:54:01 -04:00
|
|
|
let (view_tag, shared_key, payment_id_xor) =
|
2022-08-22 04:27:58 -04:00
|
|
|
shared_key(Some(unique).filter(|_| output.0.meta.kind.guaranteed()), &r, &output.0.view, o);
|
|
|
|
|
|
2022-08-22 06:54:01 -04:00
|
|
|
(
|
|
|
|
|
SendOutput {
|
|
|
|
|
R: if !output.0.meta.kind.subaddress() {
|
|
|
|
|
&r * &ED25519_BASEPOINT_TABLE
|
|
|
|
|
} else {
|
|
|
|
|
r * output.0.spend
|
|
|
|
|
},
|
|
|
|
|
view_tag,
|
|
|
|
|
dest: ((&shared_key * &ED25519_BASEPOINT_TABLE) + output.0.spend),
|
|
|
|
|
commitment: Commitment::new(commitment_mask(shared_key), output.1),
|
|
|
|
|
amount: amount_encryption(output.1, shared_key),
|
2022-06-19 12:03:01 -04:00
|
|
|
},
|
2022-08-22 06:54:01 -04:00
|
|
|
output
|
|
|
|
|
.0
|
|
|
|
|
.payment_id()
|
|
|
|
|
.map(|id| (u64::from_le_bytes(id) ^ u64::from_le_bytes(payment_id_xor)).to_le_bytes()),
|
|
|
|
|
)
|
2022-05-21 15:33:35 -04:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-05-28 05:08:37 -04:00
|
|
|
#[derive(Clone, Error, Debug)]
|
2022-05-21 15:33:35 -04:00
|
|
|
pub enum TransactionError {
|
2022-08-22 06:54:01 -04:00
|
|
|
#[error("multiple addresses with payment IDs")]
|
|
|
|
|
MultiplePaymentIds,
|
2022-05-21 15:33:35 -04:00
|
|
|
#[error("no inputs")]
|
|
|
|
|
NoInputs,
|
|
|
|
|
#[error("no outputs")]
|
|
|
|
|
NoOutputs,
|
2022-06-19 12:03:01 -04:00
|
|
|
#[error("only one output and no change address")]
|
|
|
|
|
NoChange,
|
2022-05-21 15:33:35 -04:00
|
|
|
#[error("too many outputs")]
|
|
|
|
|
TooManyOutputs,
|
2022-08-30 15:42:23 -04:00
|
|
|
#[error("too much data")]
|
|
|
|
|
TooMuchData,
|
2022-05-21 15:33:35 -04:00
|
|
|
#[error("not enough funds (in {0}, out {1})")]
|
|
|
|
|
NotEnoughFunds(u64, u64),
|
2022-06-09 04:05:57 -04:00
|
|
|
#[error("wrong spend private key")]
|
|
|
|
|
WrongPrivateKey,
|
2022-05-21 15:33:35 -04:00
|
|
|
#[error("rpc error ({0})")]
|
|
|
|
|
RpcError(RpcError),
|
|
|
|
|
#[error("clsag error ({0})")]
|
|
|
|
|
ClsagError(ClsagError),
|
|
|
|
|
#[error("invalid transaction ({0})")]
|
|
|
|
|
InvalidTransaction(RpcError),
|
|
|
|
|
#[cfg(feature = "multisig")]
|
|
|
|
|
#[error("frost error {0}")]
|
|
|
|
|
FrostError(FrostError),
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async fn prepare_inputs<R: RngCore + CryptoRng>(
|
|
|
|
|
rng: &mut R,
|
|
|
|
|
rpc: &Rpc,
|
2022-07-27 04:05:43 -05:00
|
|
|
ring_len: usize,
|
2022-05-21 15:33:35 -04:00
|
|
|
inputs: &[SpendableOutput],
|
|
|
|
|
spend: &Scalar,
|
2022-07-15 01:26:07 -04:00
|
|
|
tx: &mut Transaction,
|
2022-05-21 15:33:35 -04:00
|
|
|
) -> Result<Vec<(Scalar, EdwardsPoint, ClsagInput)>, TransactionError> {
|
|
|
|
|
let mut signable = Vec::with_capacity(inputs.len());
|
|
|
|
|
|
|
|
|
|
// Select decoys
|
|
|
|
|
let decoys = Decoys::select(
|
|
|
|
|
rng,
|
|
|
|
|
rpc,
|
2022-07-27 04:05:43 -05:00
|
|
|
ring_len,
|
2022-07-22 02:34:36 -04:00
|
|
|
rpc.get_height().await.map_err(TransactionError::RpcError)? - 10,
|
2022-07-15 01:26:07 -04:00
|
|
|
inputs,
|
|
|
|
|
)
|
|
|
|
|
.await
|
2022-07-22 02:34:36 -04:00
|
|
|
.map_err(TransactionError::RpcError)?;
|
2022-05-21 15:33:35 -04:00
|
|
|
|
|
|
|
|
for (i, input) in inputs.iter().enumerate() {
|
|
|
|
|
signable.push((
|
2022-08-22 13:35:49 -04:00
|
|
|
spend + input.key_offset(),
|
|
|
|
|
generate_key_image(spend + input.key_offset()),
|
2022-08-22 12:15:14 -04:00
|
|
|
ClsagInput::new(input.commitment().clone(), decoys[i].clone())
|
Utilize zeroize (#76)
* Apply Zeroize to nonces used in Bulletproofs
Also makes bit decomposition constant time for a given amount of
outputs.
* Fix nonce reuse for single-signer CLSAG
* Attach Zeroize to most structures in Monero, and ZOnDrop to anything with private data
* Zeroize private keys and nonces
* Merge prepare_outputs and prepare_transactions
* Ensure CLSAG is constant time
* Pass by borrow where needed, bug fixes
The past few commitments have been one in-progress chunk which I've
broken up as best read.
* Add Zeroize to FROST structs
Still needs to zeroize internally, yet next step. Not quite as
aggressive as Monero, partially due to the limitations of HashMaps,
partially due to less concern about metadata, yet does still delete a
few smaller items of metadata (group key, context string...).
* Remove Zeroize from most Monero multisig structs
These structs largely didn't have private data, just fields with private
data, yet those fields implemented ZeroizeOnDrop making them already
covered. While there is still traces of the transaction left in RAM,
fully purging that was never the intent.
* Use Zeroize within dleq
bitvec doesn't offer Zeroize, so a manual zeroing has been implemented.
* Use Zeroize for random_nonce
It isn't perfect, due to the inability to zeroize the digest, and due to
kp256 requiring a few transformations. It does the best it can though.
Does move the per-curve random_nonce to a provided one, which is allowed
as of https://github.com/cfrg/draft-irtf-cfrg-frost/pull/231.
* Use Zeroize on FROST keygen/signing
* Zeroize constant time multiexp.
* Correct when FROST keygen zeroizes
* Move the FROST keys Arc into FrostKeys
Reduces amount of instances in memory.
* Manually implement Debug for FrostCore to not leak the secret share
* Misc bug fixes
* clippy + multiexp test bug fixes
* Correct FROST key gen share summation
It leaked our own share for ourself.
* Fix cross-group DLEq tests
2022-08-03 03:25:18 -05:00
|
|
|
.map_err(TransactionError::ClsagError)?,
|
2022-05-21 15:33:35 -04:00
|
|
|
));
|
|
|
|
|
|
|
|
|
|
tx.prefix.inputs.push(Input::ToKey {
|
|
|
|
|
amount: 0,
|
|
|
|
|
key_offsets: decoys[i].offsets.clone(),
|
2022-07-15 01:26:07 -04:00
|
|
|
key_image: signable[i].1,
|
2022-05-21 15:33:35 -04:00
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
signable.sort_by(|x, y| x.1.compress().to_bytes().cmp(&y.1.compress().to_bytes()).reverse());
|
2022-07-15 01:26:07 -04:00
|
|
|
tx.prefix.inputs.sort_by(|x, y| {
|
|
|
|
|
if let (Input::ToKey { key_image: x, .. }, Input::ToKey { key_image: y, .. }) = (x, y) {
|
|
|
|
|
x.compress().to_bytes().cmp(&y.compress().to_bytes()).reverse()
|
|
|
|
|
} else {
|
|
|
|
|
panic!("Input wasn't ToKey")
|
|
|
|
|
}
|
2022-05-21 15:33:35 -04:00
|
|
|
});
|
|
|
|
|
|
|
|
|
|
Ok(signable)
|
|
|
|
|
}
|
|
|
|
|
|
2022-09-28 07:44:49 -05:00
|
|
|
/// Fee struct, defined as a per-unit cost and a mask for rounding purposes.
|
2022-06-19 12:03:01 -04:00
|
|
|
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
|
|
|
|
|
pub struct Fee {
|
|
|
|
|
pub per_weight: u64,
|
2022-07-15 01:26:07 -04:00
|
|
|
pub mask: u64,
|
2022-06-19 12:03:01 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl Fee {
|
|
|
|
|
pub fn calculate(&self, weight: usize) -> u64 {
|
|
|
|
|
((((self.per_weight * u64::try_from(weight).unwrap()) - 1) / self.mask) + 1) * self.mask
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-09-28 07:44:49 -05:00
|
|
|
/// A signable transaction, either in a single-signer or multisig context.
|
Utilize zeroize (#76)
* Apply Zeroize to nonces used in Bulletproofs
Also makes bit decomposition constant time for a given amount of
outputs.
* Fix nonce reuse for single-signer CLSAG
* Attach Zeroize to most structures in Monero, and ZOnDrop to anything with private data
* Zeroize private keys and nonces
* Merge prepare_outputs and prepare_transactions
* Ensure CLSAG is constant time
* Pass by borrow where needed, bug fixes
The past few commitments have been one in-progress chunk which I've
broken up as best read.
* Add Zeroize to FROST structs
Still needs to zeroize internally, yet next step. Not quite as
aggressive as Monero, partially due to the limitations of HashMaps,
partially due to less concern about metadata, yet does still delete a
few smaller items of metadata (group key, context string...).
* Remove Zeroize from most Monero multisig structs
These structs largely didn't have private data, just fields with private
data, yet those fields implemented ZeroizeOnDrop making them already
covered. While there is still traces of the transaction left in RAM,
fully purging that was never the intent.
* Use Zeroize within dleq
bitvec doesn't offer Zeroize, so a manual zeroing has been implemented.
* Use Zeroize for random_nonce
It isn't perfect, due to the inability to zeroize the digest, and due to
kp256 requiring a few transformations. It does the best it can though.
Does move the per-curve random_nonce to a provided one, which is allowed
as of https://github.com/cfrg/draft-irtf-cfrg-frost/pull/231.
* Use Zeroize on FROST keygen/signing
* Zeroize constant time multiexp.
* Correct when FROST keygen zeroizes
* Move the FROST keys Arc into FrostKeys
Reduces amount of instances in memory.
* Manually implement Debug for FrostCore to not leak the secret share
* Misc bug fixes
* clippy + multiexp test bug fixes
* Correct FROST key gen share summation
It leaked our own share for ourself.
* Fix cross-group DLEq tests
2022-08-03 03:25:18 -05:00
|
|
|
#[derive(Clone, PartialEq, Eq, Debug, Zeroize, ZeroizeOnDrop)]
|
2022-05-21 15:33:35 -04:00
|
|
|
pub struct SignableTransaction {
|
2022-07-27 04:05:43 -05:00
|
|
|
protocol: Protocol,
|
2022-05-21 15:33:35 -04:00
|
|
|
inputs: Vec<SpendableOutput>,
|
2022-06-28 00:01:20 -04:00
|
|
|
payments: Vec<(Address, u64)>,
|
2022-08-30 15:42:23 -04:00
|
|
|
data: Option<Vec<u8>>,
|
2022-07-15 01:26:07 -04:00
|
|
|
fee: u64,
|
2022-05-21 15:33:35 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl SignableTransaction {
|
2022-09-28 07:44:49 -05:00
|
|
|
/// Create a signable transaction. If the change address is specified, leftover funds will be
|
|
|
|
|
/// sent to it. If the change address isn't specified, up to 16 outputs may be specified, using
|
|
|
|
|
/// any leftover funds as a bonus to the fee. The optional data field will be embedded in TX
|
|
|
|
|
/// extra.
|
2022-05-21 15:33:35 -04:00
|
|
|
pub fn new(
|
2022-07-27 04:05:43 -05:00
|
|
|
protocol: Protocol,
|
2022-05-21 15:33:35 -04:00
|
|
|
inputs: Vec<SpendableOutput>,
|
2022-06-28 00:01:20 -04:00
|
|
|
mut payments: Vec<(Address, u64)>,
|
2022-06-19 12:03:01 -04:00
|
|
|
change_address: Option<Address>,
|
2022-08-30 15:42:23 -04:00
|
|
|
data: Option<Vec<u8>>,
|
2022-07-15 01:26:07 -04:00
|
|
|
fee_rate: Fee,
|
2022-05-21 15:33:35 -04:00
|
|
|
) -> Result<SignableTransaction, TransactionError> {
|
2022-08-22 06:54:01 -04:00
|
|
|
// Make sure there's only one payment ID
|
|
|
|
|
{
|
|
|
|
|
let mut payment_ids = 0;
|
|
|
|
|
let mut count = |addr: Address| {
|
|
|
|
|
if addr.payment_id().is_some() {
|
|
|
|
|
payment_ids += 1
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
for payment in &payments {
|
|
|
|
|
count(payment.0);
|
|
|
|
|
}
|
|
|
|
|
if let Some(change) = change_address {
|
|
|
|
|
count(change);
|
|
|
|
|
}
|
|
|
|
|
if payment_ids > 1 {
|
|
|
|
|
Err(TransactionError::MultiplePaymentIds)?;
|
2022-08-22 04:27:58 -04:00
|
|
|
}
|
2022-06-19 12:03:01 -04:00
|
|
|
}
|
|
|
|
|
|
2022-07-22 02:34:36 -04:00
|
|
|
if inputs.is_empty() {
|
2022-05-21 15:33:35 -04:00
|
|
|
Err(TransactionError::NoInputs)?;
|
|
|
|
|
}
|
2022-07-22 02:34:36 -04:00
|
|
|
if payments.is_empty() {
|
2022-05-21 15:33:35 -04:00
|
|
|
Err(TransactionError::NoOutputs)?;
|
|
|
|
|
}
|
|
|
|
|
|
2022-08-30 15:42:23 -04:00
|
|
|
if data.as_ref().map(|v| v.len()).unwrap_or(0) > 255 {
|
|
|
|
|
Err(TransactionError::TooMuchData)?;
|
|
|
|
|
}
|
|
|
|
|
|
2022-06-19 12:03:01 -04:00
|
|
|
// TODO TX MAX SIZE
|
|
|
|
|
|
|
|
|
|
// If we don't have two outputs, as required by Monero, add a second
|
|
|
|
|
let mut change = payments.len() == 1;
|
|
|
|
|
if change && change_address.is_none() {
|
|
|
|
|
Err(TransactionError::NoChange)?;
|
|
|
|
|
}
|
2022-09-17 04:35:08 -04:00
|
|
|
let outputs = payments.len() + usize::from(change);
|
2022-06-19 12:03:01 -04:00
|
|
|
|
2022-08-21 08:41:19 -04:00
|
|
|
// Calculate the extra length
|
2022-08-30 15:42:23 -04:00
|
|
|
let extra = Extra::fee_weight(outputs, data.as_ref());
|
2022-06-19 12:19:57 -04:00
|
|
|
|
2022-06-19 12:03:01 -04:00
|
|
|
// Calculate the fee.
|
2022-08-21 10:35:10 -04:00
|
|
|
let mut fee =
|
|
|
|
|
fee_rate.calculate(Transaction::fee_weight(protocol, inputs.len(), outputs, extra));
|
2022-06-19 12:03:01 -04:00
|
|
|
|
|
|
|
|
// Make sure we have enough funds
|
2022-08-22 12:15:14 -04:00
|
|
|
let in_amount = inputs.iter().map(|input| input.commitment().amount).sum::<u64>();
|
2022-06-19 12:03:01 -04:00
|
|
|
let mut out_amount = payments.iter().map(|payment| payment.1).sum::<u64>() + fee;
|
|
|
|
|
if in_amount < out_amount {
|
|
|
|
|
Err(TransactionError::NotEnoughFunds(in_amount, out_amount))?;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// If we have yet to add a change output, do so if it's economically viable
|
|
|
|
|
if (!change) && change_address.is_some() && (in_amount != out_amount) {
|
|
|
|
|
// Check even with the new fee, there's remaining funds
|
2022-08-21 10:35:10 -04:00
|
|
|
let change_fee =
|
|
|
|
|
fee_rate.calculate(Transaction::fee_weight(protocol, inputs.len(), outputs + 1, extra)) -
|
|
|
|
|
fee;
|
2022-06-19 12:03:01 -04:00
|
|
|
if (out_amount + change_fee) < in_amount {
|
|
|
|
|
change = true;
|
|
|
|
|
out_amount += change_fee;
|
|
|
|
|
fee += change_fee;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if change {
|
2022-06-28 00:01:20 -04:00
|
|
|
payments.push((change_address.unwrap(), in_amount - out_amount));
|
2022-06-19 12:03:01 -04:00
|
|
|
}
|
|
|
|
|
|
2022-07-27 04:05:43 -05:00
|
|
|
if payments.len() > MAX_OUTPUTS {
|
|
|
|
|
Err(TransactionError::TooManyOutputs)?;
|
|
|
|
|
}
|
|
|
|
|
|
2022-08-30 15:42:23 -04:00
|
|
|
Ok(SignableTransaction { protocol, inputs, payments, data, fee })
|
2022-05-21 15:33:35 -04:00
|
|
|
}
|
|
|
|
|
|
Utilize zeroize (#76)
* Apply Zeroize to nonces used in Bulletproofs
Also makes bit decomposition constant time for a given amount of
outputs.
* Fix nonce reuse for single-signer CLSAG
* Attach Zeroize to most structures in Monero, and ZOnDrop to anything with private data
* Zeroize private keys and nonces
* Merge prepare_outputs and prepare_transactions
* Ensure CLSAG is constant time
* Pass by borrow where needed, bug fixes
The past few commitments have been one in-progress chunk which I've
broken up as best read.
* Add Zeroize to FROST structs
Still needs to zeroize internally, yet next step. Not quite as
aggressive as Monero, partially due to the limitations of HashMaps,
partially due to less concern about metadata, yet does still delete a
few smaller items of metadata (group key, context string...).
* Remove Zeroize from most Monero multisig structs
These structs largely didn't have private data, just fields with private
data, yet those fields implemented ZeroizeOnDrop making them already
covered. While there is still traces of the transaction left in RAM,
fully purging that was never the intent.
* Use Zeroize within dleq
bitvec doesn't offer Zeroize, so a manual zeroing has been implemented.
* Use Zeroize for random_nonce
It isn't perfect, due to the inability to zeroize the digest, and due to
kp256 requiring a few transformations. It does the best it can though.
Does move the per-curve random_nonce to a provided one, which is allowed
as of https://github.com/cfrg/draft-irtf-cfrg-frost/pull/231.
* Use Zeroize on FROST keygen/signing
* Zeroize constant time multiexp.
* Correct when FROST keygen zeroizes
* Move the FROST keys Arc into FrostKeys
Reduces amount of instances in memory.
* Manually implement Debug for FrostCore to not leak the secret share
* Misc bug fixes
* clippy + multiexp test bug fixes
* Correct FROST key gen share summation
It leaked our own share for ourself.
* Fix cross-group DLEq tests
2022-08-03 03:25:18 -05:00
|
|
|
fn prepare_transaction<R: RngCore + CryptoRng>(
|
2022-05-21 15:33:35 -04:00
|
|
|
&mut self,
|
|
|
|
|
rng: &mut R,
|
2022-07-15 01:26:07 -04:00
|
|
|
uniqueness: [u8; 32],
|
Utilize zeroize (#76)
* Apply Zeroize to nonces used in Bulletproofs
Also makes bit decomposition constant time for a given amount of
outputs.
* Fix nonce reuse for single-signer CLSAG
* Attach Zeroize to most structures in Monero, and ZOnDrop to anything with private data
* Zeroize private keys and nonces
* Merge prepare_outputs and prepare_transactions
* Ensure CLSAG is constant time
* Pass by borrow where needed, bug fixes
The past few commitments have been one in-progress chunk which I've
broken up as best read.
* Add Zeroize to FROST structs
Still needs to zeroize internally, yet next step. Not quite as
aggressive as Monero, partially due to the limitations of HashMaps,
partially due to less concern about metadata, yet does still delete a
few smaller items of metadata (group key, context string...).
* Remove Zeroize from most Monero multisig structs
These structs largely didn't have private data, just fields with private
data, yet those fields implemented ZeroizeOnDrop making them already
covered. While there is still traces of the transaction left in RAM,
fully purging that was never the intent.
* Use Zeroize within dleq
bitvec doesn't offer Zeroize, so a manual zeroing has been implemented.
* Use Zeroize for random_nonce
It isn't perfect, due to the inability to zeroize the digest, and due to
kp256 requiring a few transformations. It does the best it can though.
Does move the per-curve random_nonce to a provided one, which is allowed
as of https://github.com/cfrg/draft-irtf-cfrg-frost/pull/231.
* Use Zeroize on FROST keygen/signing
* Zeroize constant time multiexp.
* Correct when FROST keygen zeroizes
* Move the FROST keys Arc into FrostKeys
Reduces amount of instances in memory.
* Manually implement Debug for FrostCore to not leak the secret share
* Misc bug fixes
* clippy + multiexp test bug fixes
* Correct FROST key gen share summation
It leaked our own share for ourself.
* Fix cross-group DLEq tests
2022-08-03 03:25:18 -05:00
|
|
|
) -> (Transaction, Scalar) {
|
2022-06-19 12:03:01 -04:00
|
|
|
// Shuffle the payments
|
|
|
|
|
self.payments.shuffle(rng);
|
2022-05-21 15:33:35 -04:00
|
|
|
|
|
|
|
|
// Actually create the outputs
|
2022-08-22 06:54:01 -04:00
|
|
|
let mut outputs = Vec::with_capacity(self.payments.len());
|
|
|
|
|
let mut id = None;
|
|
|
|
|
for payment in self.payments.drain(..).enumerate() {
|
|
|
|
|
let (output, payment_id) = SendOutput::new(rng, uniqueness, payment);
|
|
|
|
|
outputs.push(output);
|
|
|
|
|
id = id.or(payment_id);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Include a random payment ID if we don't actually have one
|
|
|
|
|
// It prevents transactions from leaking if they're sending to integrated addresses or not
|
|
|
|
|
let id = if let Some(id) = id {
|
|
|
|
|
id
|
|
|
|
|
} else {
|
|
|
|
|
let mut id = [0; 8];
|
|
|
|
|
rng.fill_bytes(&mut id);
|
|
|
|
|
id
|
|
|
|
|
};
|
Utilize zeroize (#76)
* Apply Zeroize to nonces used in Bulletproofs
Also makes bit decomposition constant time for a given amount of
outputs.
* Fix nonce reuse for single-signer CLSAG
* Attach Zeroize to most structures in Monero, and ZOnDrop to anything with private data
* Zeroize private keys and nonces
* Merge prepare_outputs and prepare_transactions
* Ensure CLSAG is constant time
* Pass by borrow where needed, bug fixes
The past few commitments have been one in-progress chunk which I've
broken up as best read.
* Add Zeroize to FROST structs
Still needs to zeroize internally, yet next step. Not quite as
aggressive as Monero, partially due to the limitations of HashMaps,
partially due to less concern about metadata, yet does still delete a
few smaller items of metadata (group key, context string...).
* Remove Zeroize from most Monero multisig structs
These structs largely didn't have private data, just fields with private
data, yet those fields implemented ZeroizeOnDrop making them already
covered. While there is still traces of the transaction left in RAM,
fully purging that was never the intent.
* Use Zeroize within dleq
bitvec doesn't offer Zeroize, so a manual zeroing has been implemented.
* Use Zeroize for random_nonce
It isn't perfect, due to the inability to zeroize the digest, and due to
kp256 requiring a few transformations. It does the best it can though.
Does move the per-curve random_nonce to a provided one, which is allowed
as of https://github.com/cfrg/draft-irtf-cfrg-frost/pull/231.
* Use Zeroize on FROST keygen/signing
* Zeroize constant time multiexp.
* Correct when FROST keygen zeroizes
* Move the FROST keys Arc into FrostKeys
Reduces amount of instances in memory.
* Manually implement Debug for FrostCore to not leak the secret share
* Misc bug fixes
* clippy + multiexp test bug fixes
* Correct FROST key gen share summation
It leaked our own share for ourself.
* Fix cross-group DLEq tests
2022-08-03 03:25:18 -05:00
|
|
|
|
|
|
|
|
let commitments = outputs.iter().map(|output| output.commitment.clone()).collect::<Vec<_>>();
|
2022-06-19 12:03:01 -04:00
|
|
|
let sum = commitments.iter().map(|commitment| commitment.mask).sum();
|
2022-05-21 15:33:35 -04:00
|
|
|
|
2022-07-27 04:05:43 -05:00
|
|
|
// Safe due to the constructor checking MAX_OUTPUTS
|
Utilize zeroize (#76)
* Apply Zeroize to nonces used in Bulletproofs
Also makes bit decomposition constant time for a given amount of
outputs.
* Fix nonce reuse for single-signer CLSAG
* Attach Zeroize to most structures in Monero, and ZOnDrop to anything with private data
* Zeroize private keys and nonces
* Merge prepare_outputs and prepare_transactions
* Ensure CLSAG is constant time
* Pass by borrow where needed, bug fixes
The past few commitments have been one in-progress chunk which I've
broken up as best read.
* Add Zeroize to FROST structs
Still needs to zeroize internally, yet next step. Not quite as
aggressive as Monero, partially due to the limitations of HashMaps,
partially due to less concern about metadata, yet does still delete a
few smaller items of metadata (group key, context string...).
* Remove Zeroize from most Monero multisig structs
These structs largely didn't have private data, just fields with private
data, yet those fields implemented ZeroizeOnDrop making them already
covered. While there is still traces of the transaction left in RAM,
fully purging that was never the intent.
* Use Zeroize within dleq
bitvec doesn't offer Zeroize, so a manual zeroing has been implemented.
* Use Zeroize for random_nonce
It isn't perfect, due to the inability to zeroize the digest, and due to
kp256 requiring a few transformations. It does the best it can though.
Does move the per-curve random_nonce to a provided one, which is allowed
as of https://github.com/cfrg/draft-irtf-cfrg-frost/pull/231.
* Use Zeroize on FROST keygen/signing
* Zeroize constant time multiexp.
* Correct when FROST keygen zeroizes
* Move the FROST keys Arc into FrostKeys
Reduces amount of instances in memory.
* Manually implement Debug for FrostCore to not leak the secret share
* Misc bug fixes
* clippy + multiexp test bug fixes
* Correct FROST key gen share summation
It leaked our own share for ourself.
* Fix cross-group DLEq tests
2022-08-03 03:25:18 -05:00
|
|
|
let bp = Bulletproofs::prove(rng, &commitments, self.protocol.bp_plus()).unwrap();
|
2022-07-27 04:05:43 -05:00
|
|
|
|
2022-05-21 15:33:35 -04:00
|
|
|
// Create the TX extra
|
2022-08-21 08:41:19 -04:00
|
|
|
let extra = {
|
|
|
|
|
let mut extra = Extra::new(outputs.iter().map(|output| output.R).collect());
|
|
|
|
|
|
2022-08-30 15:42:23 -04:00
|
|
|
let mut id_vec = Vec::with_capacity(1 + 8);
|
|
|
|
|
PaymentId::Encrypted(id).serialize(&mut id_vec).unwrap();
|
|
|
|
|
extra.push(ExtraField::Nonce(id_vec));
|
|
|
|
|
|
|
|
|
|
// Include data if present
|
|
|
|
|
if let Some(data) = self.data.take() {
|
|
|
|
|
extra.push(ExtraField::Nonce(data));
|
|
|
|
|
}
|
2022-08-21 08:41:19 -04:00
|
|
|
|
2022-08-30 15:42:23 -04:00
|
|
|
let mut serialized = Vec::with_capacity(Extra::fee_weight(outputs.len(), self.data.as_ref()));
|
2022-08-21 08:41:19 -04:00
|
|
|
extra.serialize(&mut serialized).unwrap();
|
|
|
|
|
serialized
|
|
|
|
|
};
|
2022-05-21 15:33:35 -04:00
|
|
|
|
Utilize zeroize (#76)
* Apply Zeroize to nonces used in Bulletproofs
Also makes bit decomposition constant time for a given amount of
outputs.
* Fix nonce reuse for single-signer CLSAG
* Attach Zeroize to most structures in Monero, and ZOnDrop to anything with private data
* Zeroize private keys and nonces
* Merge prepare_outputs and prepare_transactions
* Ensure CLSAG is constant time
* Pass by borrow where needed, bug fixes
The past few commitments have been one in-progress chunk which I've
broken up as best read.
* Add Zeroize to FROST structs
Still needs to zeroize internally, yet next step. Not quite as
aggressive as Monero, partially due to the limitations of HashMaps,
partially due to less concern about metadata, yet does still delete a
few smaller items of metadata (group key, context string...).
* Remove Zeroize from most Monero multisig structs
These structs largely didn't have private data, just fields with private
data, yet those fields implemented ZeroizeOnDrop making them already
covered. While there is still traces of the transaction left in RAM,
fully purging that was never the intent.
* Use Zeroize within dleq
bitvec doesn't offer Zeroize, so a manual zeroing has been implemented.
* Use Zeroize for random_nonce
It isn't perfect, due to the inability to zeroize the digest, and due to
kp256 requiring a few transformations. It does the best it can though.
Does move the per-curve random_nonce to a provided one, which is allowed
as of https://github.com/cfrg/draft-irtf-cfrg-frost/pull/231.
* Use Zeroize on FROST keygen/signing
* Zeroize constant time multiexp.
* Correct when FROST keygen zeroizes
* Move the FROST keys Arc into FrostKeys
Reduces amount of instances in memory.
* Manually implement Debug for FrostCore to not leak the secret share
* Misc bug fixes
* clippy + multiexp test bug fixes
* Correct FROST key gen share summation
It leaked our own share for ourself.
* Fix cross-group DLEq tests
2022-08-03 03:25:18 -05:00
|
|
|
let mut tx_outputs = Vec::with_capacity(outputs.len());
|
|
|
|
|
let mut ecdh_info = Vec::with_capacity(outputs.len());
|
|
|
|
|
for output in &outputs {
|
2022-07-27 04:05:43 -05:00
|
|
|
tx_outputs.push(Output {
|
|
|
|
|
amount: 0,
|
2022-08-30 01:02:55 -04:00
|
|
|
key: output.dest.compress(),
|
Utilize zeroize (#76)
* Apply Zeroize to nonces used in Bulletproofs
Also makes bit decomposition constant time for a given amount of
outputs.
* Fix nonce reuse for single-signer CLSAG
* Attach Zeroize to most structures in Monero, and ZOnDrop to anything with private data
* Zeroize private keys and nonces
* Merge prepare_outputs and prepare_transactions
* Ensure CLSAG is constant time
* Pass by borrow where needed, bug fixes
The past few commitments have been one in-progress chunk which I've
broken up as best read.
* Add Zeroize to FROST structs
Still needs to zeroize internally, yet next step. Not quite as
aggressive as Monero, partially due to the limitations of HashMaps,
partially due to less concern about metadata, yet does still delete a
few smaller items of metadata (group key, context string...).
* Remove Zeroize from most Monero multisig structs
These structs largely didn't have private data, just fields with private
data, yet those fields implemented ZeroizeOnDrop making them already
covered. While there is still traces of the transaction left in RAM,
fully purging that was never the intent.
* Use Zeroize within dleq
bitvec doesn't offer Zeroize, so a manual zeroing has been implemented.
* Use Zeroize for random_nonce
It isn't perfect, due to the inability to zeroize the digest, and due to
kp256 requiring a few transformations. It does the best it can though.
Does move the per-curve random_nonce to a provided one, which is allowed
as of https://github.com/cfrg/draft-irtf-cfrg-frost/pull/231.
* Use Zeroize on FROST keygen/signing
* Zeroize constant time multiexp.
* Correct when FROST keygen zeroizes
* Move the FROST keys Arc into FrostKeys
Reduces amount of instances in memory.
* Manually implement Debug for FrostCore to not leak the secret share
* Misc bug fixes
* clippy + multiexp test bug fixes
* Correct FROST key gen share summation
It leaked our own share for ourself.
* Fix cross-group DLEq tests
2022-08-03 03:25:18 -05:00
|
|
|
view_tag: Some(output.view_tag).filter(|_| matches!(self.protocol, Protocol::v16)),
|
2022-07-27 04:05:43 -05:00
|
|
|
});
|
Utilize zeroize (#76)
* Apply Zeroize to nonces used in Bulletproofs
Also makes bit decomposition constant time for a given amount of
outputs.
* Fix nonce reuse for single-signer CLSAG
* Attach Zeroize to most structures in Monero, and ZOnDrop to anything with private data
* Zeroize private keys and nonces
* Merge prepare_outputs and prepare_transactions
* Ensure CLSAG is constant time
* Pass by borrow where needed, bug fixes
The past few commitments have been one in-progress chunk which I've
broken up as best read.
* Add Zeroize to FROST structs
Still needs to zeroize internally, yet next step. Not quite as
aggressive as Monero, partially due to the limitations of HashMaps,
partially due to less concern about metadata, yet does still delete a
few smaller items of metadata (group key, context string...).
* Remove Zeroize from most Monero multisig structs
These structs largely didn't have private data, just fields with private
data, yet those fields implemented ZeroizeOnDrop making them already
covered. While there is still traces of the transaction left in RAM,
fully purging that was never the intent.
* Use Zeroize within dleq
bitvec doesn't offer Zeroize, so a manual zeroing has been implemented.
* Use Zeroize for random_nonce
It isn't perfect, due to the inability to zeroize the digest, and due to
kp256 requiring a few transformations. It does the best it can though.
Does move the per-curve random_nonce to a provided one, which is allowed
as of https://github.com/cfrg/draft-irtf-cfrg-frost/pull/231.
* Use Zeroize on FROST keygen/signing
* Zeroize constant time multiexp.
* Correct when FROST keygen zeroizes
* Move the FROST keys Arc into FrostKeys
Reduces amount of instances in memory.
* Manually implement Debug for FrostCore to not leak the secret share
* Misc bug fixes
* clippy + multiexp test bug fixes
* Correct FROST key gen share summation
It leaked our own share for ourself.
* Fix cross-group DLEq tests
2022-08-03 03:25:18 -05:00
|
|
|
ecdh_info.push(output.amount);
|
2022-05-21 15:33:35 -04:00
|
|
|
}
|
|
|
|
|
|
Utilize zeroize (#76)
* Apply Zeroize to nonces used in Bulletproofs
Also makes bit decomposition constant time for a given amount of
outputs.
* Fix nonce reuse for single-signer CLSAG
* Attach Zeroize to most structures in Monero, and ZOnDrop to anything with private data
* Zeroize private keys and nonces
* Merge prepare_outputs and prepare_transactions
* Ensure CLSAG is constant time
* Pass by borrow where needed, bug fixes
The past few commitments have been one in-progress chunk which I've
broken up as best read.
* Add Zeroize to FROST structs
Still needs to zeroize internally, yet next step. Not quite as
aggressive as Monero, partially due to the limitations of HashMaps,
partially due to less concern about metadata, yet does still delete a
few smaller items of metadata (group key, context string...).
* Remove Zeroize from most Monero multisig structs
These structs largely didn't have private data, just fields with private
data, yet those fields implemented ZeroizeOnDrop making them already
covered. While there is still traces of the transaction left in RAM,
fully purging that was never the intent.
* Use Zeroize within dleq
bitvec doesn't offer Zeroize, so a manual zeroing has been implemented.
* Use Zeroize for random_nonce
It isn't perfect, due to the inability to zeroize the digest, and due to
kp256 requiring a few transformations. It does the best it can though.
Does move the per-curve random_nonce to a provided one, which is allowed
as of https://github.com/cfrg/draft-irtf-cfrg-frost/pull/231.
* Use Zeroize on FROST keygen/signing
* Zeroize constant time multiexp.
* Correct when FROST keygen zeroizes
* Move the FROST keys Arc into FrostKeys
Reduces amount of instances in memory.
* Manually implement Debug for FrostCore to not leak the secret share
* Misc bug fixes
* clippy + multiexp test bug fixes
* Correct FROST key gen share summation
It leaked our own share for ourself.
* Fix cross-group DLEq tests
2022-08-03 03:25:18 -05:00
|
|
|
(
|
|
|
|
|
Transaction {
|
|
|
|
|
prefix: TransactionPrefix {
|
|
|
|
|
version: 2,
|
|
|
|
|
timelock: Timelock::None,
|
|
|
|
|
inputs: vec![],
|
|
|
|
|
outputs: tx_outputs,
|
|
|
|
|
extra,
|
2022-05-21 15:33:35 -04:00
|
|
|
},
|
2022-09-28 05:28:42 -04:00
|
|
|
signatures: vec![],
|
Utilize zeroize (#76)
* Apply Zeroize to nonces used in Bulletproofs
Also makes bit decomposition constant time for a given amount of
outputs.
* Fix nonce reuse for single-signer CLSAG
* Attach Zeroize to most structures in Monero, and ZOnDrop to anything with private data
* Zeroize private keys and nonces
* Merge prepare_outputs and prepare_transactions
* Ensure CLSAG is constant time
* Pass by borrow where needed, bug fixes
The past few commitments have been one in-progress chunk which I've
broken up as best read.
* Add Zeroize to FROST structs
Still needs to zeroize internally, yet next step. Not quite as
aggressive as Monero, partially due to the limitations of HashMaps,
partially due to less concern about metadata, yet does still delete a
few smaller items of metadata (group key, context string...).
* Remove Zeroize from most Monero multisig structs
These structs largely didn't have private data, just fields with private
data, yet those fields implemented ZeroizeOnDrop making them already
covered. While there is still traces of the transaction left in RAM,
fully purging that was never the intent.
* Use Zeroize within dleq
bitvec doesn't offer Zeroize, so a manual zeroing has been implemented.
* Use Zeroize for random_nonce
It isn't perfect, due to the inability to zeroize the digest, and due to
kp256 requiring a few transformations. It does the best it can though.
Does move the per-curve random_nonce to a provided one, which is allowed
as of https://github.com/cfrg/draft-irtf-cfrg-frost/pull/231.
* Use Zeroize on FROST keygen/signing
* Zeroize constant time multiexp.
* Correct when FROST keygen zeroizes
* Move the FROST keys Arc into FrostKeys
Reduces amount of instances in memory.
* Manually implement Debug for FrostCore to not leak the secret share
* Misc bug fixes
* clippy + multiexp test bug fixes
* Correct FROST key gen share summation
It leaked our own share for ourself.
* Fix cross-group DLEq tests
2022-08-03 03:25:18 -05:00
|
|
|
rct_signatures: RctSignatures {
|
|
|
|
|
base: RctBase {
|
|
|
|
|
fee: self.fee,
|
|
|
|
|
ecdh_info,
|
|
|
|
|
commitments: commitments.iter().map(|commitment| commitment.calculate()).collect(),
|
|
|
|
|
},
|
|
|
|
|
prunable: RctPrunable::Clsag {
|
|
|
|
|
bulletproofs: vec![bp],
|
|
|
|
|
clsags: vec![],
|
|
|
|
|
pseudo_outs: vec![],
|
|
|
|
|
},
|
2022-07-15 01:26:07 -04:00
|
|
|
},
|
|
|
|
|
},
|
Utilize zeroize (#76)
* Apply Zeroize to nonces used in Bulletproofs
Also makes bit decomposition constant time for a given amount of
outputs.
* Fix nonce reuse for single-signer CLSAG
* Attach Zeroize to most structures in Monero, and ZOnDrop to anything with private data
* Zeroize private keys and nonces
* Merge prepare_outputs and prepare_transactions
* Ensure CLSAG is constant time
* Pass by borrow where needed, bug fixes
The past few commitments have been one in-progress chunk which I've
broken up as best read.
* Add Zeroize to FROST structs
Still needs to zeroize internally, yet next step. Not quite as
aggressive as Monero, partially due to the limitations of HashMaps,
partially due to less concern about metadata, yet does still delete a
few smaller items of metadata (group key, context string...).
* Remove Zeroize from most Monero multisig structs
These structs largely didn't have private data, just fields with private
data, yet those fields implemented ZeroizeOnDrop making them already
covered. While there is still traces of the transaction left in RAM,
fully purging that was never the intent.
* Use Zeroize within dleq
bitvec doesn't offer Zeroize, so a manual zeroing has been implemented.
* Use Zeroize for random_nonce
It isn't perfect, due to the inability to zeroize the digest, and due to
kp256 requiring a few transformations. It does the best it can though.
Does move the per-curve random_nonce to a provided one, which is allowed
as of https://github.com/cfrg/draft-irtf-cfrg-frost/pull/231.
* Use Zeroize on FROST keygen/signing
* Zeroize constant time multiexp.
* Correct when FROST keygen zeroizes
* Move the FROST keys Arc into FrostKeys
Reduces amount of instances in memory.
* Manually implement Debug for FrostCore to not leak the secret share
* Misc bug fixes
* clippy + multiexp test bug fixes
* Correct FROST key gen share summation
It leaked our own share for ourself.
* Fix cross-group DLEq tests
2022-08-03 03:25:18 -05:00
|
|
|
sum,
|
|
|
|
|
)
|
2022-05-21 15:33:35 -04:00
|
|
|
}
|
|
|
|
|
|
2022-09-28 07:44:49 -05:00
|
|
|
/// Sign this transaction.
|
2022-05-21 15:33:35 -04:00
|
|
|
pub async fn sign<R: RngCore + CryptoRng>(
|
|
|
|
|
&mut self,
|
|
|
|
|
rng: &mut R,
|
|
|
|
|
rpc: &Rpc,
|
2022-07-15 01:26:07 -04:00
|
|
|
spend: &Scalar,
|
2022-05-21 15:33:35 -04:00
|
|
|
) -> Result<Transaction, TransactionError> {
|
2022-05-21 21:44:57 -04:00
|
|
|
let mut images = Vec::with_capacity(self.inputs.len());
|
|
|
|
|
for input in &self.inputs {
|
2022-08-22 13:35:49 -04:00
|
|
|
let mut offset = spend + input.key_offset();
|
|
|
|
|
if (&offset * &ED25519_BASEPOINT_TABLE) != input.key() {
|
2022-06-09 04:05:57 -04:00
|
|
|
Err(TransactionError::WrongPrivateKey)?;
|
|
|
|
|
}
|
|
|
|
|
|
2022-07-10 16:11:55 -04:00
|
|
|
images.push(generate_key_image(offset));
|
Utilize zeroize (#76)
* Apply Zeroize to nonces used in Bulletproofs
Also makes bit decomposition constant time for a given amount of
outputs.
* Fix nonce reuse for single-signer CLSAG
* Attach Zeroize to most structures in Monero, and ZOnDrop to anything with private data
* Zeroize private keys and nonces
* Merge prepare_outputs and prepare_transactions
* Ensure CLSAG is constant time
* Pass by borrow where needed, bug fixes
The past few commitments have been one in-progress chunk which I've
broken up as best read.
* Add Zeroize to FROST structs
Still needs to zeroize internally, yet next step. Not quite as
aggressive as Monero, partially due to the limitations of HashMaps,
partially due to less concern about metadata, yet does still delete a
few smaller items of metadata (group key, context string...).
* Remove Zeroize from most Monero multisig structs
These structs largely didn't have private data, just fields with private
data, yet those fields implemented ZeroizeOnDrop making them already
covered. While there is still traces of the transaction left in RAM,
fully purging that was never the intent.
* Use Zeroize within dleq
bitvec doesn't offer Zeroize, so a manual zeroing has been implemented.
* Use Zeroize for random_nonce
It isn't perfect, due to the inability to zeroize the digest, and due to
kp256 requiring a few transformations. It does the best it can though.
Does move the per-curve random_nonce to a provided one, which is allowed
as of https://github.com/cfrg/draft-irtf-cfrg-frost/pull/231.
* Use Zeroize on FROST keygen/signing
* Zeroize constant time multiexp.
* Correct when FROST keygen zeroizes
* Move the FROST keys Arc into FrostKeys
Reduces amount of instances in memory.
* Manually implement Debug for FrostCore to not leak the secret share
* Misc bug fixes
* clippy + multiexp test bug fixes
* Correct FROST key gen share summation
It leaked our own share for ourself.
* Fix cross-group DLEq tests
2022-08-03 03:25:18 -05:00
|
|
|
offset.zeroize();
|
2022-05-21 21:44:57 -04:00
|
|
|
}
|
2022-05-22 01:56:17 -04:00
|
|
|
images.sort_by(key_image_sort);
|
2022-05-21 21:44:57 -04:00
|
|
|
|
Utilize zeroize (#76)
* Apply Zeroize to nonces used in Bulletproofs
Also makes bit decomposition constant time for a given amount of
outputs.
* Fix nonce reuse for single-signer CLSAG
* Attach Zeroize to most structures in Monero, and ZOnDrop to anything with private data
* Zeroize private keys and nonces
* Merge prepare_outputs and prepare_transactions
* Ensure CLSAG is constant time
* Pass by borrow where needed, bug fixes
The past few commitments have been one in-progress chunk which I've
broken up as best read.
* Add Zeroize to FROST structs
Still needs to zeroize internally, yet next step. Not quite as
aggressive as Monero, partially due to the limitations of HashMaps,
partially due to less concern about metadata, yet does still delete a
few smaller items of metadata (group key, context string...).
* Remove Zeroize from most Monero multisig structs
These structs largely didn't have private data, just fields with private
data, yet those fields implemented ZeroizeOnDrop making them already
covered. While there is still traces of the transaction left in RAM,
fully purging that was never the intent.
* Use Zeroize within dleq
bitvec doesn't offer Zeroize, so a manual zeroing has been implemented.
* Use Zeroize for random_nonce
It isn't perfect, due to the inability to zeroize the digest, and due to
kp256 requiring a few transformations. It does the best it can though.
Does move the per-curve random_nonce to a provided one, which is allowed
as of https://github.com/cfrg/draft-irtf-cfrg-frost/pull/231.
* Use Zeroize on FROST keygen/signing
* Zeroize constant time multiexp.
* Correct when FROST keygen zeroizes
* Move the FROST keys Arc into FrostKeys
Reduces amount of instances in memory.
* Manually implement Debug for FrostCore to not leak the secret share
* Misc bug fixes
* clippy + multiexp test bug fixes
* Correct FROST key gen share summation
It leaked our own share for ourself.
* Fix cross-group DLEq tests
2022-08-03 03:25:18 -05:00
|
|
|
let (mut tx, mask_sum) = self.prepare_transaction(
|
2022-05-21 15:33:35 -04:00
|
|
|
rng,
|
2022-05-22 01:56:17 -04:00
|
|
|
uniqueness(
|
2022-07-15 01:26:07 -04:00
|
|
|
&images
|
|
|
|
|
.iter()
|
|
|
|
|
.map(|image| Input::ToKey { amount: 0, key_offsets: vec![], key_image: *image })
|
|
|
|
|
.collect::<Vec<_>>(),
|
|
|
|
|
),
|
2022-06-19 12:03:01 -04:00
|
|
|
);
|
2022-05-21 15:33:35 -04:00
|
|
|
|
2022-07-27 04:05:43 -05:00
|
|
|
let signable =
|
|
|
|
|
prepare_inputs(rng, rpc, self.protocol.ring_len(), &self.inputs, spend, &mut tx).await?;
|
2022-05-21 15:33:35 -04:00
|
|
|
|
Utilize zeroize (#76)
* Apply Zeroize to nonces used in Bulletproofs
Also makes bit decomposition constant time for a given amount of
outputs.
* Fix nonce reuse for single-signer CLSAG
* Attach Zeroize to most structures in Monero, and ZOnDrop to anything with private data
* Zeroize private keys and nonces
* Merge prepare_outputs and prepare_transactions
* Ensure CLSAG is constant time
* Pass by borrow where needed, bug fixes
The past few commitments have been one in-progress chunk which I've
broken up as best read.
* Add Zeroize to FROST structs
Still needs to zeroize internally, yet next step. Not quite as
aggressive as Monero, partially due to the limitations of HashMaps,
partially due to less concern about metadata, yet does still delete a
few smaller items of metadata (group key, context string...).
* Remove Zeroize from most Monero multisig structs
These structs largely didn't have private data, just fields with private
data, yet those fields implemented ZeroizeOnDrop making them already
covered. While there is still traces of the transaction left in RAM,
fully purging that was never the intent.
* Use Zeroize within dleq
bitvec doesn't offer Zeroize, so a manual zeroing has been implemented.
* Use Zeroize for random_nonce
It isn't perfect, due to the inability to zeroize the digest, and due to
kp256 requiring a few transformations. It does the best it can though.
Does move the per-curve random_nonce to a provided one, which is allowed
as of https://github.com/cfrg/draft-irtf-cfrg-frost/pull/231.
* Use Zeroize on FROST keygen/signing
* Zeroize constant time multiexp.
* Correct when FROST keygen zeroizes
* Move the FROST keys Arc into FrostKeys
Reduces amount of instances in memory.
* Manually implement Debug for FrostCore to not leak the secret share
* Misc bug fixes
* clippy + multiexp test bug fixes
* Correct FROST key gen share summation
It leaked our own share for ourself.
* Fix cross-group DLEq tests
2022-08-03 03:25:18 -05:00
|
|
|
let clsag_pairs = Clsag::sign(rng, signable, mask_sum, tx.signature_hash());
|
2022-05-21 15:33:35 -04:00
|
|
|
match tx.rct_signatures.prunable {
|
|
|
|
|
RctPrunable::Null => panic!("Signing for RctPrunable::Null"),
|
|
|
|
|
RctPrunable::Clsag { ref mut clsags, ref mut pseudo_outs, .. } => {
|
|
|
|
|
clsags.append(&mut clsag_pairs.iter().map(|clsag| clsag.0.clone()).collect::<Vec<_>>());
|
2022-07-22 02:34:36 -04:00
|
|
|
pseudo_outs.append(&mut clsag_pairs.iter().map(|clsag| clsag.1).collect::<Vec<_>>());
|
2022-05-21 15:33:35 -04:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
Ok(tx)
|
|
|
|
|
}
|
|
|
|
|
}
|