Skip to content

Commit

Permalink
feat!: update key parsing (#5900)
Browse files Browse the repository at this point in the history
Description
---
Updates key parsing to differentiate between canonical- and
reduction-based use cases. Makes several updates to account for
`EpochTime` changes. Updates genesis data.

Motivation and Context
---
An [update](tari-project/tari-crypto#194) to
`tari-crypto` differentiates secret key parsing between cases that
should use canonical byte arrays, and those that use random byte arrays
requiring modular wide reduction.

This PR makes corresponding changes to account for this.

It also makes several updates required since the `tari_utilities`
release used here also makes breaking `EpochTime` changes that can't be
cleanly done separately.

How Has This Been Tested?
---
Existing tests pass. Uses of parsed secret keys have been manually
inspected for correctness.

What process can a PR reviewer use to test or verify this change?
---
Assert that secret keys and scalars instantiated from byte arrays use
the appropriate approach: parsing from canonical byte arrays, or modular
wide reduction from uniform byte arrays.

Confirm that `EpochTime` changes reflect the intended logic, especially
relating to timestamp and difficulty handling.

BREAKING CHANGE: This modifies how secret keys and scalars are
constructed and is therefore a breaking change.

---------

Co-authored-by: Aaron Feickert <66188213+AaronFeickert@users.noreply.github.com>
  • Loading branch information
SWvheerden and AaronFeickert committed Nov 2, 2023
1 parent e445244 commit 59d7ceb
Show file tree
Hide file tree
Showing 120 changed files with 2,802 additions and 6,921 deletions.
1,121 changes: 602 additions & 519 deletions Cargo.lock

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions applications/minotari_app_grpc/Cargo.toml
Expand Up @@ -11,9 +11,9 @@ edition = "2018"
tari_common_types = { path = "../../base_layer/common_types" }
tari_comms = { path = "../../comms/core" }
tari_core = { path = "../../base_layer/core" }
tari_crypto = { version = "0.18" }
tari_crypto = { version = "0.19" }
tari_script = { path = "../../infrastructure/tari_script" }
tari_utilities = { version = "0.5" }
tari_utilities = { version = "0.6" }

argon2 = { version = "0.4.1", features = ["std", "password-hash"] }
base64 = "0.13.0"
Expand Down
Expand Up @@ -58,9 +58,11 @@ impl TryFrom<grpc::BlockHeader> for BlockHeader {
type Error = String;

fn try_from(header: grpc::BlockHeader) -> Result<Self, Self::Error> {
let total_kernel_offset = PrivateKey::from_bytes(&header.total_kernel_offset).map_err(|err| err.to_string())?;
let total_kernel_offset =
PrivateKey::from_canonical_bytes(&header.total_kernel_offset).map_err(|err| err.to_string())?;

let total_script_offset = PrivateKey::from_bytes(&header.total_script_offset).map_err(|err| err.to_string())?;
let total_script_offset =
PrivateKey::from_canonical_bytes(&header.total_script_offset).map_err(|err| err.to_string())?;

let pow = match header.pow {
Some(p) => ProofOfWork::try_from(p)?,
Expand Down
Expand Up @@ -31,13 +31,16 @@ impl TryFrom<grpc::ComAndPubSignature> for ComAndPubSignature {
type Error = String;

fn try_from(sig: grpc::ComAndPubSignature) -> Result<Self, Self::Error> {
let ephemeral_commitment = Commitment::from_bytes(&sig.ephemeral_commitment)
let ephemeral_commitment = Commitment::from_canonical_bytes(&sig.ephemeral_commitment)
.map_err(|_| "Could not get ephemeral commitment".to_string())?;
let ephemeral_pubkey = PublicKey::from_bytes(&sig.ephemeral_pubkey)
let ephemeral_pubkey = PublicKey::from_canonical_bytes(&sig.ephemeral_pubkey)
.map_err(|_| "Could not get ephemeral public key".to_string())?;
let u_a = PrivateKey::from_bytes(&sig.u_a).map_err(|_| "Could not get partial signature u_a".to_string())?;
let u_x = PrivateKey::from_bytes(&sig.u_x).map_err(|_| "Could not get partial signature u_x".to_string())?;
let u_y = PrivateKey::from_bytes(&sig.u_y).map_err(|_| "Could not get partial signature u_y".to_string())?;
let u_a = PrivateKey::from_canonical_bytes(&sig.u_a)
.map_err(|_| "Could not get partial signature u_a".to_string())?;
let u_x = PrivateKey::from_canonical_bytes(&sig.u_x)
.map_err(|_| "Could not get partial signature u_x".to_string())?;
let u_y = PrivateKey::from_canonical_bytes(&sig.u_y)
.map_err(|_| "Could not get partial signature u_y".to_string())?;

Ok(Self::new(ephemeral_commitment, ephemeral_pubkey, u_a, u_x, u_y))
}
Expand Down
Expand Up @@ -32,10 +32,10 @@ impl TryFrom<grpc::CommitmentSignature> for CommitmentSignature<PublicKey, Priva
type Error = String;

fn try_from(sig: grpc::CommitmentSignature) -> Result<Self, Self::Error> {
let public_nonce = HomomorphicCommitment::<PublicKey>::from_bytes(&sig.public_nonce)
let public_nonce = HomomorphicCommitment::<PublicKey>::from_canonical_bytes(&sig.public_nonce)
.map_err(|_| "Could not get public nonce".to_string())?;
let u = PrivateKey::from_bytes(&sig.u).map_err(|_| "Could not get u_x".to_string())?;
let v = PrivateKey::from_bytes(&sig.v).map_err(|_| "Could not get v_x".to_string())?;
let u = PrivateKey::from_canonical_bytes(&sig.u).map_err(|_| "Could not get u_x".to_string())?;
let v = PrivateKey::from_canonical_bytes(&sig.v).map_err(|_| "Could not get v_x".to_string())?;

Ok(Self::new(public_nonce, u, v))
}
Expand Down
Expand Up @@ -76,9 +76,9 @@ impl TryFrom<grpc::NewBlockTemplate> for NewBlockTemplate {

fn try_from(block: grpc::NewBlockTemplate) -> Result<Self, Self::Error> {
let header = block.header.clone().ok_or_else(|| "No header provided".to_string())?;
let total_kernel_offset = PrivateKey::from_bytes(&header.total_kernel_offset)
let total_kernel_offset = PrivateKey::from_canonical_bytes(&header.total_kernel_offset)
.map_err(|err| format!("total_kernel_offset {}", err))?;
let total_script_offset = PrivateKey::from_bytes(&header.total_script_offset)
let total_script_offset = PrivateKey::from_canonical_bytes(&header.total_script_offset)
.map_err(|err| format!("total_script_offset {}", err))?;
let pow = match header.pow {
Some(p) => ProofOfWork::try_from(p)?,
Expand Down
Expand Up @@ -88,7 +88,7 @@ impl TryFrom<grpc::ValidatorNodeRegistration> for ValidatorNodeRegistration {

fn try_from(value: grpc::ValidatorNodeRegistration) -> Result<Self, Self::Error> {
Ok(ValidatorNodeRegistration::new(ValidatorNodeSignature::new(
PublicKey::from_bytes(&value.public_key).map_err(|e| e.to_string())?,
PublicKey::from_canonical_bytes(&value.public_key).map_err(|e| e.to_string())?,
value
.signature
.map(Signature::try_from)
Expand All @@ -112,7 +112,7 @@ impl TryFrom<grpc::TemplateRegistration> for CodeTemplateRegistration {

fn try_from(value: grpc::TemplateRegistration) -> Result<Self, Self::Error> {
Ok(Self {
author_public_key: PublicKey::from_bytes(&value.author_public_key).map_err(|e| e.to_string())?,
author_public_key: PublicKey::from_canonical_bytes(&value.author_public_key).map_err(|e| e.to_string())?,
author_signature: value
.author_signature
.map(Signature::try_from)
Expand Down Expand Up @@ -157,7 +157,7 @@ impl TryFrom<grpc::ConfidentialOutputData> for ConfidentialOutputData {

fn try_from(value: grpc::ConfidentialOutputData) -> Result<Self, Self::Error> {
Ok(ConfidentialOutputData {
claim_public_key: PublicKey::from_bytes(&value.claim_public_key).map_err(|e| e.to_string())?,
claim_public_key: PublicKey::from_canonical_bytes(&value.claim_public_key).map_err(|e| e.to_string())?,
})
}
}
Expand Down
5 changes: 3 additions & 2 deletions applications/minotari_app_grpc/src/conversions/signature.rs
Expand Up @@ -32,8 +32,9 @@ impl TryFrom<grpc::Signature> for Signature {

fn try_from(sig: grpc::Signature) -> Result<Self, Self::Error> {
let public_nonce =
PublicKey::from_bytes(&sig.public_nonce).map_err(|_| "Could not get public nonce".to_string())?;
let signature = PrivateKey::from_bytes(&sig.signature).map_err(|_| "Could not get signature".to_string())?;
PublicKey::from_canonical_bytes(&sig.public_nonce).map_err(|_| "Could not get public nonce".to_string())?;
let signature =
PrivateKey::from_canonical_bytes(&sig.signature).map_err(|_| "Could not get signature".to_string())?;

Ok(Self::new(public_nonce, signature))
}
Expand Down
5 changes: 3 additions & 2 deletions applications/minotari_app_grpc/src/conversions/transaction.rs
Expand Up @@ -64,12 +64,13 @@ impl TryFrom<grpc::Transaction> for Transaction {

fn try_from(source: grpc::Transaction) -> Result<Self, Self::Error> {
Ok(Self {
offset: RistrettoSecretKey::from_bytes(&source.offset).map_err(|e| format!("Offset is not valid:{}", e))?,
offset: RistrettoSecretKey::from_canonical_bytes(&source.offset)
.map_err(|e| format!("Offset is not valid:{}", e))?,
body: source
.body
.ok_or_else(|| "Transaction body not provided".to_string())?
.try_into()?,
script_offset: RistrettoSecretKey::from_bytes(&source.script_offset)
script_offset: RistrettoSecretKey::from_canonical_bytes(&source.script_offset)
.map_err(|e| format!("Script offset is not valid:{}", e))?,
})
}
Expand Down
Expand Up @@ -59,14 +59,14 @@ impl TryFrom<grpc::TransactionInput> for TransactionInput {
script_signature,
))
} else {
let commitment = Commitment::from_bytes(&input.commitment).map_err(|e| e.to_string())?;
let commitment = Commitment::from_canonical_bytes(&input.commitment).map_err(|e| e.to_string())?;
let features = input
.features
.map(TryInto::try_into)
.ok_or_else(|| "transaction output features not provided".to_string())??;

let sender_offset_public_key =
PublicKey::from_bytes(input.sender_offset_public_key.as_bytes()).map_err(|err| format!("{:?}", err))?;
let sender_offset_public_key = PublicKey::from_canonical_bytes(input.sender_offset_public_key.as_bytes())
.map_err(|err| format!("{:?}", err))?;

let encrypted_data = EncryptedData::from_bytes(&input.encrypted_data).map_err(|err| err.to_string())?;
let minimum_value_promise = input.minimum_value_promise.into();
Expand Down
Expand Up @@ -35,8 +35,8 @@ impl TryFrom<grpc::TransactionKernel> for TransactionKernel {
type Error = String;

fn try_from(kernel: grpc::TransactionKernel) -> Result<Self, Self::Error> {
let excess =
Commitment::from_bytes(&kernel.excess).map_err(|err| format!("Excess could not be converted:{}", err))?;
let excess = Commitment::from_canonical_bytes(&kernel.excess)
.map_err(|err| format!("Excess could not be converted:{}", err))?;

let excess_sig = kernel
.excess_sig
Expand All @@ -49,7 +49,7 @@ impl TryFrom<grpc::TransactionKernel> for TransactionKernel {
None
} else {
Some(
Commitment::from_bytes(&kernel.burn_commitment)
Commitment::from_canonical_bytes(&kernel.burn_commitment)
.map_err(|err| format!("Burn commitment could not be converted:{}", err))?,
)
};
Expand Down
Expand Up @@ -42,13 +42,13 @@ impl TryFrom<grpc::TransactionOutput> for TransactionOutput {
.map(TryInto::try_into)
.ok_or_else(|| "Transaction output features not provided".to_string())??;

let commitment =
Commitment::from_bytes(&output.commitment).map_err(|err| format!("Invalid output commitment: {}", err))?;
let sender_offset_public_key = PublicKey::from_bytes(output.sender_offset_public_key.as_bytes())
let commitment = Commitment::from_canonical_bytes(&output.commitment)
.map_err(|err| format!("Invalid output commitment: {}", err))?;
let sender_offset_public_key = PublicKey::from_canonical_bytes(output.sender_offset_public_key.as_bytes())
.map_err(|err| format!("Invalid sender_offset_public_key {:?}", err))?;

let range_proof = if let Some(proof) = output.range_proof {
Some(BulletRangeProof::from_bytes(&proof.proof_bytes).map_err(|err| err.to_string())?)
Some(BulletRangeProof::from_canonical_bytes(&proof.proof_bytes).map_err(|err| err.to_string())?)
} else {
None
};
Expand Down
Expand Up @@ -67,8 +67,8 @@ impl TryFrom<grpc::UnblindedOutput> for UnblindedOutput {
type Error = String;

fn try_from(mut output: grpc::UnblindedOutput) -> Result<Self, Self::Error> {
let spending_key =
PrivateKey::from_bytes(output.spending_key.as_bytes()).map_err(|e| format!("spending_key: {:?}", e))?;
let spending_key = PrivateKey::from_canonical_bytes(output.spending_key.as_bytes())
.map_err(|e| format!("spending_key: {:?}", e))?;

let features = output
.features
Expand All @@ -80,10 +80,10 @@ impl TryFrom<grpc::UnblindedOutput> for UnblindedOutput {
let input_data =
ExecutionStack::from_bytes(output.input_data.as_bytes()).map_err(|e| format!("input_data: {:?}", e))?;

let script_private_key = PrivateKey::from_bytes(output.script_private_key.as_bytes())
let script_private_key = PrivateKey::from_canonical_bytes(output.script_private_key.as_bytes())
.map_err(|e| format!("script_private_key: {:?}", e))?;

let sender_offset_public_key = PublicKey::from_bytes(output.sender_offset_public_key.as_bytes())
let sender_offset_public_key = PublicKey::from_canonical_bytes(output.sender_offset_public_key.as_bytes())
.map_err(|err| format!("sender_offset_public_key {:?}", err))?;

let metadata_signature = output
Expand Down
2 changes: 1 addition & 1 deletion applications/minotari_app_utilities/Cargo.toml
Expand Up @@ -10,7 +10,7 @@ tari_common = { path = "../../common" }
tari_common_types = { path = "../../base_layer/common_types" }
tari_comms = { path = "../../comms/core" }
tari_features = { path = "../../common/tari_features"}
tari_utilities = { version = "0.5" }
tari_utilities = { version = "0.6" }

clap = { version = "3.2", features = ["derive", "env"] }
futures = { version = "^0.3.16", default-features = false, features = ["alloc"] }
Expand Down
4 changes: 2 additions & 2 deletions applications/minotari_console_wallet/Cargo.toml
Expand Up @@ -13,13 +13,13 @@ tari_common_types = { path = "../../base_layer/common_types" }
tari_comms = { path = "../../comms/core" }
tari_comms_dht = { path = "../../comms/dht" }
tari_contacts = { path = "../../base_layer/contacts" }
tari_crypto = { version = "0.18" }
tari_crypto = { version = "0.19" }
tari_key_manager = { path = "../../base_layer/key_manager" }
tari_libtor = { path = "../../infrastructure/libtor", optional = true }
tari_p2p = { path = "../../base_layer/p2p", features = ["auto-update"] }
tari_script = { path = "../../infrastructure/tari_script" }
tari_shutdown = { path = "../../infrastructure/shutdown" }
tari_utilities = { version = "0.5" }
tari_utilities = { version = "0.6" }
minotari_wallet = { path = "../../base_layer/wallet", features = ["bundled_sqlite"] }

# Uncomment for tokio tracing via tokio-console (needs "tracing" featurs)
Expand Down
Expand Up @@ -601,7 +601,7 @@ impl wallet_server::Wallet for WalletGrpcServer {
None
} else {
Some(
PublicKey::from_bytes(&message.claim_public_key)
PublicKey::from_canonical_bytes(&message.claim_public_key)
.map_err(|e| Status::invalid_argument(e.to_string()))?,
)
},
Expand Down Expand Up @@ -1002,7 +1002,7 @@ impl wallet_server::Wallet for WalletGrpcServer {
) -> Result<Response<RegisterValidatorNodeResponse>, Status> {
let request = request.into_inner();
let mut transaction_service = self.get_transaction_service();
let validator_node_public_key = CommsPublicKey::from_bytes(&request.validator_node_public_key)
let validator_node_public_key = CommsPublicKey::from_canonical_bytes(&request.validator_node_public_key)
.map_err(|_| Status::internal("Destination address is malformed".to_string()))?;
let validator_node_signature = request
.validator_node_signature
Expand Down
2 changes: 1 addition & 1 deletion applications/minotari_console_wallet/src/init/mod.rs
Expand Up @@ -503,7 +503,7 @@ async fn detect_local_base_node(network: Network) -> Option<SeedPeer> {
};
let resp = node_conn.identify(Empty {}).await.ok()?;
let identity = resp.get_ref();
let public_key = CommsPublicKey::from_bytes(&identity.public_key).ok()?;
let public_key = CommsPublicKey::from_canonical_bytes(&identity.public_key).ok()?;
let addresses = identity
.public_addresses
.iter()
Expand Down
Expand Up @@ -139,7 +139,7 @@ impl TransactionsTab {
None => String::new(),
Some(mined_timestamp) => format!(
"{}",
DateTime::<Local>::from_utc(mined_timestamp, Local::now().offset().to_owned())
DateTime::<Local>::from_naive_utc_and_offset(mined_timestamp, Local::now().offset().to_owned())
.format("%Y-%m-%d %H:%M:%S")
),
},
Expand Down Expand Up @@ -246,7 +246,7 @@ impl TransactionsTab {
None => String::new(),
Some(mined_timestamp) => format!(
"{}",
DateTime::<Local>::from_utc(mined_timestamp, Local::now().offset().to_owned())
DateTime::<Local>::from_naive_utc_and_offset(mined_timestamp, Local::now().offset().to_owned())
.format("%Y-%m-%d %H:%M:%S")
),
},
Expand Down Expand Up @@ -388,19 +388,22 @@ impl TransactionsTab {
let status = Span::styled(status_msg, Style::default().fg(Color::White));
let message = Span::styled(tx.message.as_str(), Style::default().fg(Color::White));

// let mined_time = DateTime::<Local>::from_naive_utc_and_offset(tx.mined_timestamp,
// Local::now().offset().to_owned());
let mined_timestamp = Span::styled(
match tx.mined_timestamp {
None => String::new(),
Some(mined_timestamp) => format!(
"{}",
DateTime::<Local>::from_utc(mined_timestamp, Local::now().offset().to_owned())
DateTime::<Local>::from_naive_utc_and_offset(mined_timestamp, Local::now().offset().to_owned())
.format("%Y-%m-%d %H:%M:%S")
),
},
Style::default().fg(Color::White),
);

let imported_time = DateTime::<Local>::from_utc(tx.timestamp, Local::now().offset().to_owned());
let imported_time =
DateTime::<Local>::from_naive_utc_and_offset(tx.timestamp, Local::now().offset().to_owned());
let imported_timestamp = Span::styled(
format!("{}", imported_time.format("%Y-%m-%d %H:%M:%S")),
Style::default().fg(Color::White),
Expand Down
24 changes: 11 additions & 13 deletions applications/minotari_console_wallet/src/ui/state/tasks.rs
Expand Up @@ -23,7 +23,7 @@
use std::{convert::TryFrom, path::PathBuf};

use blake2::Blake2b;
use digest::consts::U32;
use digest::consts::U64;
use log::{error, warn};
use minotari_wallet::{
output_manager_service::UtxoSelectionCriteria,
Expand All @@ -33,7 +33,7 @@ use minotari_wallet::{
use rand::{random, rngs::OsRng};
use tari_common_types::{
tari_address::TariAddress,
types::{FixedHash, PublicKey, Signature},
types::{PublicKey, Signature},
};
use tari_core::{
consensus::{DomainSeparatedConsensusHasher, MaxSizeBytes, MaxSizeString},
Expand Down Expand Up @@ -421,7 +421,7 @@ pub async fn send_register_template_transaction_task(
// signing and sending code template registration request
// ----------------------------------------------------------------------------

let mut km = KeyManager::<RistrettoPublicKey, Blake2b<U32>>::new();
let mut km = KeyManager::<RistrettoPublicKey, Blake2b<U64>>::new();

let author_private_key = match km.next_key() {
Ok(secret_key) => secret_key.key,
Expand All @@ -434,16 +434,14 @@ pub async fn send_register_template_transaction_task(

let author_public_key = PublicKey::from_secret_key(&author_private_key);
let (secret_nonce, public_nonce) = PublicKey::random_keypair(&mut OsRng);
let challenge = FixedHash::from(
DomainSeparatedConsensusHasher::<TransactionHashDomain>::new("template_registration")
.chain(&author_public_key)
.chain(&public_nonce)
.chain(&binary_sha)
.chain(&b"")
.finalize(),
);

let author_signature = Signature::sign_raw(&author_private_key, secret_nonce, &*challenge)
let challenge = DomainSeparatedConsensusHasher::<TransactionHashDomain, Blake2b<U64>>::new("template_registration")
.chain(&author_public_key)
.chain(&public_nonce)
.chain(&binary_sha)
.chain(&b"")
.finalize();

let author_signature = Signature::sign_raw_uniform(&author_private_key, secret_nonce, &challenge)
.expect("Sign cannot fail with 32-byte challenge and a RistrettoPublicKey");

// ----------------------------------------------------------------------------
Expand Down
2 changes: 1 addition & 1 deletion applications/minotari_console_wallet/src/ui/ui_contact.rs
Expand Up @@ -47,7 +47,7 @@ impl From<Contact> for UiContact {
address: c.address.to_hex(),
emoji_id: c.address.to_emoji_string(),
last_seen: match c.last_seen {
Some(val) => DateTime::<Local>::from_utc(val, Local::now().offset().to_owned())
Some(val) => DateTime::<Local>::from_naive_utc_and_offset(val, Local::now().offset().to_owned())
.format("%m-%dT%H:%M")
.to_string(),
None => "".to_string(),
Expand Down

0 comments on commit 59d7ceb

Please sign in to comment.