Skip to content

Commit

Permalink
feat: add encryption service
Browse files Browse the repository at this point in the history
  • Loading branch information
therustmonk committed Jun 25, 2022
1 parent 46f9bb8 commit 9af4010
Show file tree
Hide file tree
Showing 23 changed files with 376 additions and 61 deletions.
3 changes: 2 additions & 1 deletion applications/test_faucet/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -200,7 +200,8 @@ fn create_utxo(
if !factories.range_proof.verify(&proof, &commitment) {
panic!("Range proof does not verify");
};
let encrypted_value = EncryptedValue::todo_encrypt_from(value);
let encryption_keys = generate_keys();
let encrypted_value = EncryptedValue::encrypt_value(&encryption_keys.k, &commitment, value);
let metadata_sig = TransactionOutput::create_final_metadata_signature(
TransactionOutputVersion::get_current_version(),
value,
Expand Down
1 change: 1 addition & 0 deletions base_layer/core/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ bincode = "1.1.4"
bitflags = "1.0.4"
blake2 = "^0.9.0"
bytes = "0.5"
#chacha20poly1305 = "0.9.0"
chrono = { version = "0.4.19", default-features = false, features = ["serde"] }
criterion = { version = "0.3.5", optional = true }
croaring = { version = "0.5.2", optional = true }
Expand Down
3 changes: 2 additions & 1 deletion base_layer/core/src/test_helpers/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,8 @@ pub fn create_block(rules: &ConsensusManager, prev_block: &Block, spec: BlockSpe
)
});

let (coinbase, coinbase_output) = CoinbaseBuilder::new(CryptoFactories::default())
let factories = CryptoFactories::default();
let (coinbase, coinbase_output) = CoinbaseBuilder::new(factories)
.with_block_height(header.height)
.with_fees(0.into())
.with_nonce(0.into())
Expand Down
18 changes: 14 additions & 4 deletions base_layer/core/src/transactions/coinbase_builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,8 @@ pub enum CoinbaseBuildError {
MissingSpendKey,
#[error("The script key for this coinbase transaction wasn't provided")]
MissingScriptKey,
#[error("The encryption key for this coinbase transaction wasn't provided")]
MissingEncryptionKey,
#[error("An error occurred building the final transaction: `{0}`")]
BuildError(String),
#[error("Some inconsistent data was given to the builder. This transaction is not valid")]
Expand Down Expand Up @@ -206,7 +208,12 @@ impl CoinbaseBuilder {
let sender_offset_public_key = PublicKey::from_secret_key(&sender_offset_private_key);
let covenant = self.covenant;

let encrypted_value = EncryptedValue::todo_encrypt_from(total_reward);
let encrypted_value = self
.rewind_data
.as_ref()
.map(|rd| EncryptedValue::encrypt_value(&rd.encryption_key, &commitment, total_reward))
.unwrap_or_default();

let metadata_sig = TransactionOutput::create_final_metadata_signature(
TransactionOutputVersion::get_current_version(),
total_reward,
Expand Down Expand Up @@ -276,9 +283,9 @@ mod test {
transactions::{
coinbase_builder::CoinbaseBuildError,
crypto_factories::CryptoFactories,
tari_amount::{uT, MicroTari},
tari_amount::uT,
test_helpers::TestParams,
transaction_components::{KernelFeatures, OutputFeatures, OutputType, TransactionError},
transaction_components::{EncryptedValue, KernelFeatures, OutputFeatures, OutputType, TransactionError},
transaction_protocol::RewindData,
CoinbaseBuilder,
},
Expand Down Expand Up @@ -366,6 +373,7 @@ mod test {
let rewind_data = RewindData {
rewind_blinding_key: rewind_blinding_key.clone(),
recovery_byte_key: PrivateKey::random(&mut OsRng),
encryption_key: PrivateKey::random(&mut OsRng),
};

let p = TestParams::new();
Expand All @@ -381,7 +389,9 @@ mod test {
.unwrap();
let block_reward = rules.emission_schedule().block_reward(42) + 145 * uT;

let committed_value = MicroTari::from(tx.body.outputs()[0].encrypted_value.todo_decrypt());
let committed_value =
EncryptedValue::decrypt_value(&p.rewind_data.encryption_key, &tx.body.outputs()[0].encrypted_value)
.unwrap();
assert_eq!(committed_value, block_reward);
let blinding_factor = tx.body.outputs()[0]
.recover_mask(&factories.range_proof, &rewind_blinding_key)
Expand Down
17 changes: 12 additions & 5 deletions base_layer/core/src/transactions/test_helpers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ use tari_crypto::{
};
use tari_script::{inputs, script, ExecutionStack, TariScript};

use super::transaction_components::{EncryptedValue, TransactionInputVersion, TransactionOutputVersion};
use super::transaction_components::{TransactionInputVersion, TransactionOutputVersion};
use crate::{
consensus::{ConsensusEncodingSized, ConsensusManager},
covenants::Covenant,
Expand All @@ -42,6 +42,7 @@ use crate::{
fee::Fee,
tari_amount::MicroTari,
transaction_components::{
EncryptedValue,
KernelBuilder,
KernelFeatures,
OutputFeatures,
Expand Down Expand Up @@ -90,6 +91,7 @@ pub struct TestParams {
pub sender_private_commitment_nonce: PrivateKey,
pub sender_public_commitment_nonce: PublicKey,
pub commitment_factory: CommitmentFactory,
pub encryption_key: PrivateKey,
pub transaction_weight: TransactionWeight,
pub rewind_data: RewindData,
}
Expand Down Expand Up @@ -149,10 +151,12 @@ impl TestParams {
sender_private_commitment_nonce: sender_sig_pvt_nonce.clone(),
sender_public_commitment_nonce: PublicKey::from_secret_key(&sender_sig_pvt_nonce),
commitment_factory: CommitmentFactory::default(),
encryption_key: PrivateKey::random(&mut OsRng),
transaction_weight: TransactionWeight::v2(),
rewind_data: RewindData {
rewind_blinding_key: PrivateKey::random(&mut OsRng),
recovery_byte_key: PrivateKey::random(&mut OsRng),
encryption_key: PrivateKey::random(&mut OsRng),
},
}
}
Expand All @@ -176,7 +180,7 @@ impl TestParams {
let updated_features =
OutputFeatures::features_with_updated_recovery_byte(&commitment, rewind_data, &params.features);

let encrypted_value = EncryptedValue::todo_encrypt_from(params.value);
let encrypted_value = EncryptedValue::encrypt_value(&self.encryption_key, &commitment, params.value);
let metadata_signature = TransactionOutput::create_final_metadata_signature(
TransactionOutputVersion::get_current_version(),
params.value,
Expand Down Expand Up @@ -738,8 +742,9 @@ pub fn create_stx_protocol(schema: TransactionSchema) -> (SenderTransactionProto
..Default::default()
};

// TODO: Get it using `something.encrypt_value(change)`
let encrypted_value = EncryptedValue::todo_encrypt_from(change);
let encrypted_value =
EncryptedValue::encrypt_value(&test_params_change_and_txn.encryption_key, &commitment, change);

let change_metadata_sig = TransactionOutput::create_final_metadata_signature(
output_version,
change,
Expand Down Expand Up @@ -809,7 +814,9 @@ pub fn create_utxo(

let updated_features = OutputFeatures::features_with_updated_recovery_byte(&commitment, None, features);

let encrypted_value = EncryptedValue::todo_encrypt_from(value);
let encryption_keys = generate_keys();
let encrypted_value = EncryptedValue::encrypt_value(&encryption_keys.k, &commitment, value);

let metadata_sig = TransactionOutput::create_final_metadata_signature(
TransactionOutputVersion::get_current_version(),
value,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,13 @@
use std::io::{self, Read, Write};

use serde::{Deserialize, Serialize};
use tari_common_types::types::{Commitment, PrivateKey};
use tari_utilities::{ByteArray, ByteArrayError};

use crate::consensus::{ConsensusDecoding, ConsensusEncoding, ConsensusEncodingSized};
use crate::{
consensus::{ConsensusDecoding, ConsensusEncoding, ConsensusEncodingSized},
transactions::tari_amount::MicroTari,
};

const SIZE: usize = 24;

Expand All @@ -53,24 +57,85 @@ impl ByteArray for EncryptedValue {
}

impl EncryptedValue {
/// TODO: Replace this method with a real call of encryption service
/// that will produce an encrypted value from the given `amount`.
pub fn todo_encrypt_from(amount: impl Into<u64>) -> Self {
pub fn encrypt_value(key: &PrivateKey, commitment: &Commitment, value: MicroTari) -> EncryptedValue {
const SIZE: usize = 24;
let mut data: [u8; SIZE] = [0; SIZE];
let value = amount.into().to_le_bytes();
let value = u64::from(value).to_le_bytes();
data[0..8].copy_from_slice(&value);
Self(data)
EncryptedValue(data)
}

/// TODO: Replace this method with a real call of decryption service
/// that will produce a decrypted value from self.
pub fn todo_decrypt(&self) -> u64 {
// TODO: Add the specific error
pub fn decrypt_value(key: &PrivateKey, value: &EncryptedValue) -> Result<MicroTari, ()> {
let mut buffer = [0u8; 8];
(&mut buffer[0..8]).copy_from_slice(&self.0.as_slice()[0..8]);
u64::from_le_bytes(buffer)
(&mut buffer[0..8]).copy_from_slice(&value.0.as_slice()[0..8]);
Ok(u64::from_le_bytes(buffer).into())
}
}

// use blake2::{Blake2b, Digest};
// use chacha20poly1305::{
// aead::{Aead, Error, NewAead, Payload},
// ChaCha20Poly1305,
// Key,
// Nonce,
// };
//
// use tari_crypto::{
// commitment::HomomorphicCommitment,
// keys::PublicKey,
// ristretto::{RistrettoPublicKey, RistrettoSecretKey, RistrettoPoint},
// };
// fn encrypt_value(
// encryption_key: &RistrettoSecretKey,
// commitment: &HomomorphicCommitment<RistrettoPublicKey>,
// value: u64,
// ) -> Result<Vec<u8>, Error> {
// let shared_secret = RistrettoPublicKey::from_secret_key(encryption_key).point();
// let commitment = commitment.as_public_key().point();
// let aead_key = kdf_aead(&shared_secret, &commitment);
// Encrypt the value (with fixed length) using ChaCha20-Poly1305 with a fixed zero nonce
// let aead_payload = Payload {
// msg: &value.to_le_bytes(),
// aad: b"TARI_AAD_SCAN".as_ref(),
// };
// Included in the public transaction
// ChaCha20Poly1305::new(&aead_key).encrypt(&Nonce::default(), aead_payload)
// }
//
// Authenticate and decrypt an AEAD value
// fn decrypt_value(
// encryption_key: &RistrettoSecretKey,
// commitment: &HomomorphicCommitment<RistrettoPublicKey>,
// aead_value: &[u8],
// ) -> Result<u64, Error> {
// let shared_secret = RistrettoPublicKey::from_secret_key(encryption_key).point();
// let commitment = commitment.as_public_key().point();
// let aead_key = kdf_aead(&shared_secret, &commitment);
// Authenticate and decrypt the value
// let aead_payload = Payload {
// msg: &aead_value,
// aad: b"TARI_AAD_SCAN".as_ref(),
// };
// let mut value_bytes = [0u8; 8];
// let decrypted_bytes = ChaCha20Poly1305::new(&aead_key).decrypt(&Nonce::default(), aead_payload)?;
// value_bytes.clone_from_slice(&decrypted_bytes[..8]);
// Ok(u64::from_le_bytes(value_bytes))
// }
//
// Generate a ChaCha20-Poly1305 key from an ECDH shared secret and commitment using Blake2b
// fn kdf_aead(shared_secret: &RistrettoPoint, commitment: &RistrettoPoint) -> Key {
// const AEAD_KEY_LENGTH: usize = 32; // The length in bytes of a ChaCha20-Poly1305 AEAD key
// assert!(Blake2b::output_size() >= AEAD_KEY_LENGTH); // Make sure the hash function can produce enough key
//
// let mut hasher = Blake2b::with_params(&[], &mut b"SCAN_AEAD".as_ref(), &mut b"TARI_KDF".as_ref());
// hasher.update(shared_secret.compress().as_bytes());
// hasher.update(commitment.compress().as_bytes());
// let output = hasher.finalize();
//
// Key::from_slice(&output[..AEAD_KEY_LENGTH])
// }

impl ConsensusEncoding for EncryptedValue {
fn consensus_encode<W: Write>(&self, writer: &mut W) -> Result<(), io::Error> {
self.0.consensus_encode(writer)?;
Expand All @@ -93,12 +158,21 @@ impl ConsensusDecoding for EncryptedValue {

#[cfg(test)]
mod test {
use rand::rngs::OsRng;
use tari_common_types::types::{CommitmentFactory, PrivateKey};
use tari_crypto::{commitment::HomomorphicCommitmentFactory, keys::SecretKey};

use super::*;
use crate::consensus::ToConsensusBytes;

#[test]
fn it_encodes_to_bytes() {
let bytes = EncryptedValue::todo_encrypt_from(123u64).to_consensus_bytes();
let commitment_factory = CommitmentFactory::default();
let spending_key = PrivateKey::random(&mut OsRng);
let encryption_key = PrivateKey::random(&mut OsRng);
let value = 123u64;
let commitment = commitment_factory.commit(&spending_key, &PrivateKey::from(value));
let bytes = EncryptedValue::encrypt_value(&encryption_key, &commitment, value.into()).to_consensus_bytes();
assert_eq!(&bytes[0..8], &123u64.to_le_bytes());
assert_eq!(bytes.len(), SIZE);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,7 @@ pub struct RewindData {
#[derivative(Debug = "ignore")]
pub rewind_blinding_key: PrivateKey,
pub recovery_byte_key: PrivateKey,
pub encryption_key: PrivateKey,
}

/// Convenience function that calculates the challenge for the Schnorr signatures
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -215,7 +215,7 @@ mod test {
crypto_factories::CryptoFactories,
tari_amount::*,
test_helpers::TestParams,
transaction_components::OutputFeatures,
transaction_components::{EncryptedValue, OutputFeatures},
transaction_protocol::{
build_challenge,
sender::{SingleRoundSenderData, TransactionSenderMessage},
Expand Down Expand Up @@ -284,6 +284,7 @@ mod test {
let rewind_data = RewindData {
rewind_blinding_key: rewind_blinding_key.clone(),
recovery_byte_key,
encryption_key: PrivateKey::random(&mut OsRng),
};
let amount = MicroTari(500);
let m = TransactionMetadata {
Expand Down Expand Up @@ -324,8 +325,8 @@ mod test {
let data = receiver.get_signed_data().unwrap();
assert_eq!(data.output.features.recovery_byte, recovery_byte);

let committed_value = data.output.encrypted_value.todo_decrypt();
assert_eq!(committed_value, amount.as_u64());
let committed_value = EncryptedValue::decrypt_value(&rewind_data.encryption_key, &data.output.encrypted_value);
assert_eq!(committed_value, Ok(amount));
let blinding_factor = data
.output
.recover_mask(&factories.range_proof, &rewind_blinding_key)
Expand Down
14 changes: 11 additions & 3 deletions base_layer/core/src/transactions/transaction_protocol/sender.rs
Original file line number Diff line number Diff line change
Expand Up @@ -897,7 +897,10 @@ mod test {
.unwrap();
let covenant = Covenant::default();

let encrypted_value = EncryptedValue::todo_encrypt_from(value);
// Encrypted value
let encryption_key = PrivateKey::random(&mut OsRng);
let encrypted_value = EncryptedValue::encrypt_value(&encryption_key, &commitment, value.into());

let partial_metadata_signature = TransactionOutput::create_partial_metadata_signature(
TransactionOutputVersion::get_current_version(),
value.into(),
Expand Down Expand Up @@ -1249,6 +1252,7 @@ mod test {
let rewind_data = RewindData {
rewind_blinding_key: rewind_blinding_key.clone(),
recovery_byte_key: PrivateKey::random(&mut OsRng),
encryption_key: PrivateKey::random(&mut OsRng),
};

let script = script!(Nop);
Expand Down Expand Up @@ -1310,8 +1314,12 @@ mod test {

// If the first output isn't alice's then the second must be
// TODO: Fix this logic when 'encrypted_value.todo_decrypt()' is fixed only one of these will be possible
let committed_value_0 = MicroTari::from(tx.body.outputs()[0].encrypted_value.todo_decrypt());
let committed_value_1 = MicroTari::from(tx.body.outputs()[1].encrypted_value.todo_decrypt());
let committed_value_0 =
EncryptedValue::decrypt_value(&a.rewind_data.encryption_key, &tx.body.outputs()[0].encrypted_value)
.unwrap();
let committed_value_1 =
EncryptedValue::decrypt_value(&a.rewind_data.encryption_key, &tx.body.outputs()[1].encrypted_value)
.unwrap();
// TODO: Fix this logic when 'encrypted_value.todo_decrypt()' is fixed only one of these will be possible
let blinding_factor_0 = tx.body.outputs()[0]
.recover_mask(&factories.range_proof, &rewind_blinding_key)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,11 @@ impl SingleReceiverTransactionProtocol {
&sender_info.features.clone(),
);

let encrypted_value = EncryptedValue::todo_encrypt_from(sender_info.amount);
let encrypted_value = rewind_data
.as_ref()
.map(|rd| EncryptedValue::encrypt_value(&rd.encryption_key, &commitment, sender_info.amount))
.unwrap_or_default();

let partial_metadata_signature = TransactionOutput::create_partial_metadata_signature(
TransactionOutputVersion::get_current_version(),
sender_info.amount,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -393,7 +393,13 @@ impl SenderTransactionInitializer {
.ok_or("Change spending key was not provided")?;
let commitment = factories.commitment.commit_value(&change_key.clone(), v.as_u64());
output_features.update_recovery_byte(&commitment, self.rewind_data.as_ref());
let encrypted_value = EncryptedValue::todo_encrypt_from(v);

let encrypted_value = self
.rewind_data
.as_ref()
.map(|rd| EncryptedValue::encrypt_value(&rd.encryption_key, &commitment, v))
.unwrap_or_default();

let metadata_signature = TransactionOutput::create_final_metadata_signature(
TransactionOutputVersion::get_current_version(),
v,
Expand Down
4 changes: 3 additions & 1 deletion base_layer/core/src/validation/block_validators/test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,9 @@ async fn it_checks_exactly_one_coinbase() {

let (mut block, coinbase) = blockchain.create_unmined_block(block_spec!("A1", parent: "GB"));

let (_, coinbase_output) = CoinbaseBuilder::new(CryptoFactories::default())
let factories = CryptoFactories::default();

let (_, coinbase_output) = CoinbaseBuilder::new(factories)
.with_block_height(1)
.with_fees(0.into())
.with_nonce(0.into())
Expand Down
Loading

0 comments on commit 9af4010

Please sign in to comment.