Skip to content

Commit

Permalink
feat: encode max allowable encrypted bytes into struct (#6425)
Browse files Browse the repository at this point in the history
Description
---
remove vec<u8> and replace with max_bytes_type

Motivation and Context
---
Does not allow the allocation of more than max bytes
  • Loading branch information
SWvheerden authored Jul 24, 2024
1 parent bd32f10 commit 65567d5
Show file tree
Hide file tree
Showing 4 changed files with 51 additions and 16 deletions.
2 changes: 1 addition & 1 deletion base_layer/core/src/consensus/consensus_constants.rs
Original file line number Diff line number Diff line change
Expand Up @@ -402,7 +402,7 @@ impl ConsensusConstants {
faucet_value: 0.into(),
transaction_weight: TransactionWeight::latest(),
max_script_byte_size: 512,
max_extra_encrypted_data_byte_size: 256,
max_extra_encrypted_data_byte_size: 240,
input_version_range,
output_version_range,
kernel_version_range,
Expand Down
33 changes: 31 additions & 2 deletions base_layer/core/src/consensus/consensus_encoding/bytes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,19 @@
// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
// USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

use std::{cmp, convert::TryFrom, ops::Deref};
use std::{
cmp,
convert::TryFrom,
ops::{Deref, DerefMut},
};

use borsh::{BorshDeserialize, BorshSerialize};
use serde::{Deserialize, Serialize};
use tari_utilities::hex::{from_hex, HexError};
use tari_utilities::{
hex::{from_hex, HexError},
ByteArray,
ByteArrayError,
};

#[derive(
Debug,
Expand Down Expand Up @@ -118,6 +126,27 @@ impl<const MAX: usize> Deref for MaxSizeBytes<MAX> {
}
}

impl<const MAX: usize> DerefMut for MaxSizeBytes<MAX> {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.inner
}
}

impl<const MAX: usize> ByteArray for MaxSizeBytes<MAX> {
/// Try and convert the given byte array to a MaxSizeBytes. Any failures (incorrect array length,
/// implementation-specific checks, etc) return a [ByteArrayError](enum.ByteArrayError.html).
fn from_canonical_bytes(bytes: &[u8]) -> Result<Self, ByteArrayError> {
Self::from_bytes_checked(bytes).ok_or(ByteArrayError::ConversionError {
reason: "Invalid byte length".to_string(),
})
}

/// Return the NodeId as a byte array
fn as_bytes(&self) -> &[u8] {
self.inner.as_ref()
}
}

#[derive(Debug, thiserror::Error)]
pub enum MaxSizeBytesError {
#[error("Invalid Bytes length: expected {expected}, got {actual}")]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
//! Encrypted data using the extended-nonce variant XChaCha20-Poly1305 encryption with secure random nonce.
use std::{
convert::TryInto,
convert::{TryFrom, TryInto},
fmt,
fmt::{Display, Formatter},
mem::size_of,
Expand Down Expand Up @@ -60,22 +60,22 @@ use thiserror::Error;
use zeroize::{Zeroize, Zeroizing};

use super::EncryptedDataKey;
use crate::transactions::tari_amount::MicroMinotari;

use crate::{consensus::MaxSizeBytes, transactions::tari_amount::MicroMinotari};
// Useful size constants, each in bytes
const SIZE_NONCE: usize = size_of::<XNonce>();
const SIZE_VALUE: usize = size_of::<u64>();
const SIZE_MASK: usize = PrivateKey::KEY_LEN;
const SIZE_TAG: usize = size_of::<Tag>();
pub const STATIC_ENCRYPTED_DATA_SIZE_TOTAL: usize = SIZE_NONCE + SIZE_VALUE + SIZE_MASK + SIZE_TAG;
const MAX_ENCRYPTED_DATA_SIZE: usize = 256 + STATIC_ENCRYPTED_DATA_SIZE_TOTAL;

// Number of hex characters of encrypted data to display on each side of ellipsis when truncating
const DISPLAY_CUTOFF: usize = 16;

#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, Eq, Hash, BorshSerialize, BorshDeserialize, Zeroize)]
pub struct EncryptedData {
#[serde(with = "tari_utilities::serde::hex")]
data: Vec<u8>,
data: MaxSizeBytes<MAX_ENCRYPTED_DATA_SIZE>,
}

#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, Eq)]
Expand Down Expand Up @@ -185,7 +185,10 @@ impl EncryptedData {
data[SIZE_TAG + SIZE_NONCE..SIZE_TAG + SIZE_NONCE + SIZE_VALUE + SIZE_MASK + payment_id.get_size()]
.clone_from_slice(bytes.as_slice());

Ok(Self { data })
Ok(Self {
data: MaxSizeBytes::try_from(data)
.map_err(|_| EncryptedDataError::IncorrectLength("Data too long".to_string()))?,
})
}

/// Authenticate and decrypt the value and mask
Expand Down Expand Up @@ -235,19 +238,22 @@ impl EncryptedData {
bytes.len()
)));
}
let mut data = vec![0; bytes.len()];
data.copy_from_slice(bytes);
Ok(Self { data })
Ok(Self {
data: MaxSizeBytes::from_bytes_checked(bytes)
.ok_or(EncryptedDataError::IncorrectLength("Data too long".to_string()))?,
})
}

#[cfg(test)]
pub fn from_vec_unsafe(data: Vec<u8>) -> Self {
Self { data }
Self {
data: MaxSizeBytes::from_bytes_checked(data).unwrap(),
}
}

/// Get a byte vector with the encrypted data contents
pub fn to_byte_vec(&self) -> Vec<u8> {
self.data.clone()
self.data.clone().into()
}

/// Get a byte slice with the encrypted data contents
Expand Down Expand Up @@ -290,11 +296,11 @@ impl Hex for EncryptedData {
to_hex(&self.to_byte_vec())
}
}

impl Default for EncryptedData {
fn default() -> Self {
Self {
data: vec![0; STATIC_ENCRYPTED_DATA_SIZE_TOTAL],
data: MaxSizeBytes::try_from(vec![0; STATIC_ENCRYPTED_DATA_SIZE_TOTAL])
.expect("This will always be less then the max length"),
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion base_layer/core/src/validation/block_body/test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -437,7 +437,7 @@ async fn it_limits_the_encrypted_data_byte_size() {
let (txs, _) = schema_to_transaction(&[schema1], &blockchain.km).await;
let mut txs = txs.into_iter().map(|t| Arc::try_unwrap(t).unwrap()).collect::<Vec<_>>();
let mut outputs = txs[0].body.outputs().clone();
outputs[0].encrypted_data = EncryptedData::from_vec_unsafe(vec![0; STATIC_ENCRYPTED_DATA_SIZE_TOTAL + 257]);
outputs[0].encrypted_data = EncryptedData::from_vec_unsafe(vec![0; STATIC_ENCRYPTED_DATA_SIZE_TOTAL + 250]);
txs[0].body = AggregateBody::new(txs[0].body.inputs().clone(), outputs, txs[0].body.kernels().clone());
let (block, _) = blockchain.create_next_tip(block_spec!("B", transactions: txs)).await;

Expand Down

0 comments on commit 65567d5

Please sign in to comment.