Skip to content

Commit

Permalink
chore!: update to use latest feature-dan2 (#1086)
Browse files Browse the repository at this point in the history
Description
---

Updates dan to use latest feature-dan2 branch
Skips balance proof signature check for revealed only transfer

Motivation and Context
---
Requires tari-project/tari#6420

In the updated version of tari crypto, Schnorr signature verification
correctly explicitly rejects a (previously valid) signature signed by a
zero key. For our use case, we want to allow this so that a template can
easily construct a withdraw proof for revealed funds without needing to
sign with the secret (which should never go into template land).


Breaking Changes
---

- [ ] None
- [ ] Requires data directory to be deleted
- [x] Other - Please specify

BREAKING CHANGE: many breaking changes in the layer one code.
Confidential output encrypted data not backward compatible.
  • Loading branch information
sdbondi authored Jul 24, 2024
1 parent 7c3cda2 commit f060e77
Show file tree
Hide file tree
Showing 23 changed files with 1,184 additions and 937 deletions.
1,767 changes: 945 additions & 822 deletions Cargo.lock

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -162,8 +162,8 @@ convert_case = "0.6.0"
cucumber = "0.21.0"
d3ne = { git = "https://github.com/stringhandler/d3ne-rs.git", tag = "v0.8.0-pre.3" }
dashmap = "5.5.0"
diesel = { version = "2.1", default-features = false }
diesel_migrations = "2.1"
diesel = { version = "<=2.1.6", default-features = false }
diesel_migrations = "<=2.1.0"
digest = "0.10"
dirs = "4.0.0"
env_logger = "0.10.0"
Expand Down
10 changes: 9 additions & 1 deletion applications/tari_dan_app_utilities/src/base_layer_scanner.rs
Original file line number Diff line number Diff line change
Expand Up @@ -444,10 +444,18 @@ impl<TAddr: NodeAddressable + 'static> BaseLayerScanner<TAddr> {
// Technically impossible, but anyway
BaseLayerScannerError::InvalidSideChainUtxoResponse(format!("Invalid commitment: {}", e)))?,
);
let encrypted_data_bytes = output.encrypted_data.as_bytes();
if encrypted_data_bytes.len() < EncryptedData::size() {
return Err(BaseLayerScannerError::InvalidSideChainUtxoResponse(
"Encrypted data is the incorrect size".to_string(),
));
}

let substate = SubstateValue::UnclaimedConfidentialOutput(UnclaimedConfidentialOutput {
commitment: output.commitment.clone(),
encrypted_data: EncryptedData(output.encrypted_data.to_bytes()),
encrypted_data: EncryptedData::try_from(&encrypted_data_bytes[..EncryptedData::size()]).map_err(|_| {
BaseLayerScannerError::InvalidSideChainUtxoResponse("Encrypted data has too few bytes".to_string())
})?,
});
self.state_store
.with_write_tx(|tx| {
Expand Down
17 changes: 11 additions & 6 deletions applications/tari_dan_wallet_daemon/src/handlers/accounts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -363,17 +363,21 @@ pub async fn handle_reveal_funds(
sender_public_nonce: public_nonce,
minimum_value_promise: 0,
encrypted_data,
reveal_amount: amount_to_reveal,
resource_view_key: None,
};

let inputs = sdk
.confidential_outputs_api()
.resolve_output_masks(inputs, key_manager::TRANSACTION_BRANCH)?;

let reveal_proof =
sdk.confidential_crypto_api()
.generate_withdraw_proof(&inputs, Amount::zero(), &output_statement, None)?;
let reveal_proof = sdk.confidential_crypto_api().generate_withdraw_proof(
&inputs,
Amount::zero(),
Some(&output_statement),
amount_to_reveal,
None,
Amount::zero(),
)?;

info!(
target: LOG_TARGET,
Expand Down Expand Up @@ -590,15 +594,16 @@ pub async fn handle_claim_burn(
sender_public_nonce: output_public_nonce,
minimum_value_promise: 0,
encrypted_data,
reveal_amount: max_fee,
resource_view_key: None,
};

let reveal_proof = sdk.confidential_crypto_api().generate_withdraw_proof(
&[unmasked_output],
Amount::zero(),
&output_statement,
Some(&output_statement).filter(|o| !o.amount.is_zero()),
max_fee,
None,
Amount::zero(),
)?;

let instructions = vec![Instruction::ClaimBurn {
Expand Down
11 changes: 6 additions & 5 deletions applications/tari_dan_wallet_daemon/src/handlers/confidential.rs
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,6 @@ pub async fn handle_create_transfer_proof(
sender_public_nonce: public_nonce,
minimum_value_promise: 0,
encrypted_data,
reveal_amount: req.reveal_amount,
resource_view_key: resource_view_key.clone(),
};

Expand Down Expand Up @@ -155,7 +154,6 @@ pub async fn handle_create_transfer_proof(
sender_public_nonce: public_nonce,
encrypted_data,
minimum_value_promise: 0,
reveal_amount: Amount::zero(),
resource_view_key,
})
} else {
Expand All @@ -170,8 +168,10 @@ pub async fn handle_create_transfer_proof(
&inputs,
// TODO: support for using revealed funds as input for proof generation
Amount::zero(),
&output_statement,
Some(&output_statement).filter(|o| !o.amount.is_zero()),
req.reveal_amount,
maybe_change_statement.as_ref(),
Amount::zero(),
)?;

Ok(ProofsGenerateResponse { proof_id, proof })
Expand Down Expand Up @@ -230,11 +230,12 @@ pub async fn handle_create_output_proof(
sender_public_nonce: public_nonce,
minimum_value_promise: 0,
encrypted_data,
reveal_amount: Amount::zero(),
// TODO: the request must include the resource address so that we can fetch the view key
resource_view_key: None,
};
let proof = sdk.confidential_crypto_api().generate_output_proof(&statement)?;
let proof = sdk
.confidential_crypto_api()
.generate_output_proof(&statement, Amount::zero())?;
Ok(ConfidentialCreateOutputProofResponse { proof })
}

Expand Down
1 change: 1 addition & 0 deletions dan_layer/engine_types/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ serde = { workspace = true, default-features = true }
serde_json = { workspace = true }
thiserror = { workspace = true }
ts-rs = { workspace = true, optional = true }
log = { workspace = true }

[features]
default = []
Expand Down
27 changes: 27 additions & 0 deletions dan_layer/engine_types/src/confidential/withdraw.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,27 @@ pub(crate) fn validate_confidential_withdraw<'a, I: IntoIterator<Item = &'a Comm
let total_output_revealed_amount =
withdraw_proof.output_proof.output_revealed_amount + withdraw_proof.output_proof.change_revealed_amount;

// Balance proof not required if only revealed funds are transferred
if withdraw_proof.is_revealed_only() {
if input_revealed_amount.checked_sub(total_output_revealed_amount) != Some(Amount::zero()) {
return Err(ResourceError::InvalidBalanceProof {
details: "Incorrect balance for revealed only withdraw proof".to_string(),
});
}

// This only contains revealed funds transfer, so a simple balance check is all that's needed.
// The given zero signature _would_ be valid (public_excess == (0)), however the signature implementation
// correctly disallows the zero key. See [ConfidentialWithdrawProof::revealed_withdraw].
return Ok(ValidatedConfidentialWithdrawProof {
output: None,
change_output: validated_proof.change_output,
range_proof: BulletRangeProof(withdraw_proof.output_proof.range_proof),
input_revealed_amount,
output_revealed_amount: withdraw_proof.output_proof.output_revealed_amount,
change_revealed_amount: withdraw_proof.output_proof.change_revealed_amount,
});
}

// k.G + v.H or 0.G if None
let output_commitment = validated_proof
.output
Expand Down Expand Up @@ -93,6 +114,12 @@ pub(crate) fn validate_confidential_withdraw<'a, I: IntoIterator<Item = &'a Comm
.map(|output| output.commitment.as_public_key())
.unwrap_or(&PublicKey::default());

const LOG_TARGET: &str = "tari::dan::engine::confidential::withdraw";
log::error!(target: LOG_TARGET, "🐞public_excess: {public_excess}");
log::error!(target: LOG_TARGET, "🐞public_nonce: {}", balance_proof.get_public_nonce());
log::error!(target: LOG_TARGET, "🐞input_revealed_amount: {input_revealed_amount}");
log::error!(target: LOG_TARGET, "🐞total_output_revealed_amount: {total_output_revealed_amount}");

let challenge = challenges::confidential_withdraw64(
&public_excess,
balance_proof.get_public_nonce(),
Expand Down
5 changes: 5 additions & 0 deletions dan_layer/template_lib/src/crypto/balance_proof.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
// Copyright 2023 The Tari Project
// SPDX-License-Identifier: BSD-3-Clause

use serde::{Deserialize, Serialize};
use serde_with::{serde_as, Bytes};

Expand All @@ -16,6 +17,10 @@ impl BalanceProofSignature {
64
}

pub fn zero() -> Self {
Self([0u8; Self::length()])
}

pub fn try_from_parts(public_nonce: &[u8], signature: &[u8]) -> Result<Self, InvalidByteLengthError> {
if public_nonce.len() != 32 {
return Err(InvalidByteLengthError {
Expand Down
33 changes: 31 additions & 2 deletions dan_layer/template_lib/src/models/confidential_proof.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
// Copyright 2023 The Tari Project
// SPDX-License-Identifier: BSD-3-Clause

use std::mem::size_of;

use serde::{Deserialize, Serialize};
use serde_with::{serde_as, Bytes};
#[cfg(feature = "ts")]
Expand Down Expand Up @@ -148,7 +150,7 @@ impl ConfidentialWithdrawProof {
pub fn revealed_withdraw<T: Into<Amount>>(amount: T) -> Self {
// There are no confidential inputs or outputs (this amounts to the same thing as a Fungible resource transfer)
// So signature s = 0 + e.x where x is a 0 excess, is valid.
let balance_proof = BalanceProofSignature::try_from_parts(&[0u8; 32], &[0u8; 32]).unwrap();
let balance_proof = BalanceProofSignature::zero();

let amount = amount.into();
Self {
Expand All @@ -172,6 +174,28 @@ impl ConfidentialWithdrawProof {
}
}

/// Returns true if the withdraw proof is only transferring revealed funds, otherwise false
/// The method for determining this is strict, as this can be used to determine whether to
/// safely skip the balance proof check. To return true it requires:
/// - Empty inputs
/// - Output and Change outputs must be None
/// - Empty range proof
/// - Zero balance proof
/// - Revealed funds > 0 in the inputs and outputs
pub fn is_revealed_only(&self) -> bool {
// Range proof must be empty
self.output_proof.range_proof.is_empty() &&
// Excess will be zero
self.inputs.is_empty() &&
self.output_proof.output_statement.is_none() &&
self.output_proof.change_statement.is_none() &&
// zero balance proof
self.balance_proof == BalanceProofSignature::zero() &&
// There are revealed funds
self.input_revealed_amount > Amount::zero() &&
self.output_proof.output_revealed_amount + self.output_proof.change_revealed_amount > Amount::zero()
}

pub fn revealed_input_amount(&self) -> Amount {
self.input_revealed_amount
}
Expand All @@ -194,7 +218,12 @@ pub struct EncryptedData(#[serde_as(as = "Bytes")] pub [u8; EncryptedData::size(

impl EncryptedData {
pub const fn size() -> usize {
80
const SIZE_NONCE: usize = 24;
const SIZE_VALUE: usize = size_of::<u64>();
const SIZE_MASK: usize = 32;
const SIZE_TAG: usize = 16;
const STATIC_ENCRYPTED_DATA_SIZE_TOTAL: usize = SIZE_NONCE + SIZE_VALUE + SIZE_MASK + SIZE_TAG;
STATIC_ENCRYPTED_DATA_SIZE_TOTAL
}

pub fn as_bytes(&self) -> &[u8] {
Expand Down
18 changes: 10 additions & 8 deletions dan_layer/template_test_tooling/src/support/confidential.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,6 @@ fn generate_confidential_proof_internal(
sender_public_nonce: Default::default(),
minimum_value_promise: 0,
encrypted_data: Default::default(),
reveal_amount: Default::default(),
resource_view_key: view_key.clone(),
};

Expand All @@ -49,13 +48,16 @@ fn generate_confidential_proof_internal(
sender_public_nonce: Default::default(),
minimum_value_promise: 0,
encrypted_data: Default::default(),
reveal_amount: Default::default(),
resource_view_key: view_key,
});

let proof =
tari_dan_wallet_crypto::create_confidential_output_statement(&output_statement, change_statement.as_ref())
.unwrap();
let proof = tari_dan_wallet_crypto::create_confidential_output_statement(
Some(&output_statement),
Amount::zero(),
change_statement.as_ref(),
Amount::zero(),
)
.unwrap();
(proof, mask, change.map(|_| change_mask))
}

Expand Down Expand Up @@ -147,7 +149,6 @@ fn generate_withdraw_proof_internal(
sender_public_nonce: Default::default(),
minimum_value_promise: 0,
encrypted_data: Default::default(),
reveal_amount: revealed_output_amount,
resource_view_key: view_key.clone(),
};
let change_proof = change_amount.map(|amount| ConfidentialProofStatement {
Expand All @@ -156,7 +157,6 @@ fn generate_withdraw_proof_internal(
sender_public_nonce: Default::default(),
minimum_value_promise: 0,
encrypted_data: Default::default(),
reveal_amount: Default::default(),
resource_view_key: view_key,
});

Expand All @@ -169,8 +169,10 @@ fn generate_withdraw_proof_internal(
})
.collect::<Vec<_>>(),
input_revealed_amount,
&output_proof,
Some(&output_proof),
revealed_output_amount,
change_proof.as_ref(),
Amount::zero(),
)
.unwrap();

Expand Down
1 change: 1 addition & 0 deletions dan_layer/wallet/crypto/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ digest = { workspace = true }
rand = { workspace = true }
thiserror = { workspace = true }
zeroize = { workspace = true }
log = { workspace = true }

[dev-dependencies]
tari_template_test_tooling = { workspace = true }
32 changes: 25 additions & 7 deletions dan_layer/wallet/crypto/src/api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,17 @@ use crate::{
pub fn create_withdraw_proof(
inputs: &[ConfidentialOutputMaskAndValue],
input_revealed_amount: Amount,
output_statement: &ConfidentialProofStatement,
output_statement: Option<&ConfidentialProofStatement>,
output_revealed_amount: Amount,
change_statement: Option<&ConfidentialProofStatement>,
change_revealed_amount: Amount,
) -> Result<ConfidentialWithdrawProof, WalletCryptoError> {
let output_proof = create_confidential_output_statement(output_statement, change_statement)?;
let output_proof = create_confidential_output_statement(
output_statement,
output_revealed_amount,
change_statement,
change_revealed_amount,
)?;
let (input_commitments, agg_input_mask) = inputs.iter().fold(
(Vec::with_capacity(inputs.len()), RistrettoSecretKey::default()),
|(mut commitments, agg_input), input| {
Expand All @@ -44,7 +51,7 @@ pub fn create_withdraw_proof(
let balance_proof = generate_balance_proof(
&agg_input_mask,
input_revealed_amount,
&output_statement.mask,
output_statement.as_ref().map(|o| &o.mask),
change_statement.as_ref().map(|ch| &ch.mask),
output_revealed_amount,
);
Expand Down Expand Up @@ -139,17 +146,28 @@ fn create_commitment(mask: &RistrettoSecretKey, value: u64) -> PedersenCommitmen
fn generate_balance_proof(
input_mask: &RistrettoSecretKey,
input_revealed_amount: Amount,
output_mask: &RistrettoSecretKey,
output_mask: Option<&RistrettoSecretKey>,
change_mask: Option<&RistrettoSecretKey>,
output_reveal_amount: Amount,
) -> BalanceProofSignature {
let secret_excess = input_mask - output_mask - change_mask.unwrap_or(&RistrettoSecretKey::default());
let secret_excess = input_mask -
output_mask.unwrap_or(&RistrettoSecretKey::default()) -
change_mask.unwrap_or(&RistrettoSecretKey::default());
if secret_excess == RistrettoSecretKey::default() {
// This is a revealed only proof
return BalanceProofSignature::zero();
}
let excess = RistrettoPublicKey::from_secret_key(&secret_excess);
let (nonce, public_nonce) = RistrettoPublicKey::random_keypair(&mut OsRng);
let challenge =
const LOG_TARGET: &str = "tari::dan::wallet::confidential::withdraw";
log::error!(target: LOG_TARGET, "🐞W public_excess: {excess}");
log::error!(target: LOG_TARGET, "🐞W public_nonce: {}", public_nonce);
log::error!(target: LOG_TARGET, "🐞W input_revealed_amount: {input_revealed_amount}");
log::error!(target: LOG_TARGET, "🐞W output_revealed_amount: {output_reveal_amount}");
let message =
challenges::confidential_withdraw64(&excess, &public_nonce, input_revealed_amount, output_reveal_amount);

let sig = RistrettoSchnorr::sign_raw_uniform(&secret_excess, nonce, &challenge).unwrap();
let sig = RistrettoSchnorr::sign_raw_uniform(&secret_excess, nonce, &message).unwrap();
BalanceProofSignature::try_from_parts(sig.get_public_nonce().as_bytes(), sig.get_signature().as_bytes()).unwrap()
}

Expand Down
1 change: 0 additions & 1 deletion dan_layer/wallet/crypto/src/confidential_statement.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ pub struct ConfidentialProofStatement {
pub sender_public_nonce: RistrettoPublicKey,
pub minimum_value_promise: u64,
pub encrypted_data: EncryptedData,
pub reveal_amount: Amount,
pub resource_view_key: Option<RistrettoPublicKey>,
}

Expand Down
Loading

0 comments on commit f060e77

Please sign in to comment.