#![cfg(feature = "encryption")]
use dusk_bls12_381::BlsScalar;
use dusk_jubjub::{JubJubExtended, JubJubScalar, GENERATOR_EXTENDED};
use dusk_safe::{decrypt, encrypt, Encryption, Error, Safe};
use ff::Field;
use rand::rngs::StdRng;
use rand::SeedableRng;
const W: usize = 7;
const DOMAIN: u64 = 1 << 31;
#[derive(Default, Debug, Clone, Copy, PartialEq)]
struct HashState();
impl Safe<BlsScalar, W> for HashState {
fn permute(&mut self, state: &mut [BlsScalar; W]) {
let mut state_bytes: Vec<u8> =
state.iter().flat_map(|s| s.to_bytes()).collect();
state.iter_mut().enumerate().for_each(|(i, s)| {
state_bytes.push(i as u8);
*s = BlsScalar::hash_to_scalar(&state_bytes[..]);
state_bytes.pop();
});
}
fn tag(&mut self, input: &[u8]) -> BlsScalar {
BlsScalar::hash_to_scalar(input)
}
fn add(&mut self, right: &BlsScalar, left: &BlsScalar) -> BlsScalar {
right + left
}
}
impl Encryption<BlsScalar, W> for HashState {
fn subtract(
&mut self,
minuend: &BlsScalar,
subtrahend: &BlsScalar,
) -> BlsScalar {
minuend - subtrahend
}
fn is_equal(&mut self, lhs: &BlsScalar, rhs: &BlsScalar) -> bool {
lhs == rhs
}
}
impl HashState {
pub fn new() -> Self {
Self()
}
}
fn encryption_variables(
rng: &mut StdRng,
message_len: usize,
) -> (Vec<BlsScalar>, JubJubExtended, BlsScalar) {
let mut message = Vec::with_capacity(message_len);
for _ in 0..message_len {
message.push(BlsScalar::random(&mut *rng));
}
let shared_secret = GENERATOR_EXTENDED * &JubJubScalar::random(&mut *rng);
let nonce = BlsScalar::random(&mut *rng);
(message, shared_secret, nonce)
}
#[test]
fn encrypt_decrypt() -> Result<(), Error> {
let mut rng = StdRng::seed_from_u64(0x42424242);
let message_len = 42usize;
let (message, shared_secret, nonce) =
encryption_variables(&mut rng, message_len);
let cipher = encrypt(
HashState::new(),
DOMAIN,
&message,
&shared_secret.to_hash_inputs(),
&nonce,
)?;
let decrypted_message = decrypt(
HashState::new(),
DOMAIN,
&cipher,
&shared_secret.to_hash_inputs(),
&nonce,
)?;
assert_eq!(decrypted_message, message);
Ok(())
}
#[test]
fn incorrect_shared_secret_fails() -> Result<(), Error> {
let mut rng = StdRng::seed_from_u64(0x42424242);
let message_len = 21usize;
let (message, shared_secret, nonce) =
encryption_variables(&mut rng, message_len);
let cipher = encrypt(
HashState::new(),
DOMAIN,
&message,
&shared_secret.to_hash_inputs(),
&nonce,
)?;
let wrong_shared_secret =
GENERATOR_EXTENDED * &JubJubScalar::random(&mut rng);
assert_ne!(shared_secret, wrong_shared_secret);
assert_eq!(
decrypt(
HashState::new(),
DOMAIN,
&cipher,
&wrong_shared_secret.to_hash_inputs(),
&nonce,
)
.unwrap_err(),
Error::DecryptionFailed
);
Ok(())
}
#[test]
fn incorrect_nonce_fails() -> Result<(), Error> {
let mut rng = StdRng::seed_from_u64(0x42424242);
let message_len = 21usize;
let (message, shared_secret, nonce) =
encryption_variables(&mut rng, message_len);
let cipher = encrypt(
HashState::new(),
DOMAIN,
&message,
&shared_secret.to_hash_inputs(),
&nonce,
)?;
let wrong_nonce = BlsScalar::random(&mut rng);
assert_ne!(nonce, wrong_nonce);
assert_eq!(
decrypt(
HashState::new(),
DOMAIN,
&cipher,
&shared_secret.to_hash_inputs(),
&wrong_nonce,
)
.unwrap_err(),
Error::DecryptionFailed
);
Ok(())
}
#[test]
fn incorrect_domain_fails() -> Result<(), Error> {
let mut rng = StdRng::seed_from_u64(0x42424242);
let message_len = 21usize;
let (message, shared_secret, nonce) =
encryption_variables(&mut rng, message_len);
let cipher = encrypt(
HashState::new(),
DOMAIN,
&message,
&shared_secret.to_hash_inputs(),
&nonce,
)?;
assert_eq!(
decrypt(
HashState::new(),
1u64,
&cipher,
&shared_secret.to_hash_inputs(),
&nonce,
)
.unwrap_err(),
Error::DecryptionFailed
);
Ok(())
}
#[test]
fn incorrect_cipher_fails() -> Result<(), Error> {
let mut rng = StdRng::seed_from_u64(0x42424242);
let message_len = 21usize;
let (message, shared_secret, nonce) =
encryption_variables(&mut rng, message_len);
let cipher = encrypt(
HashState::new(),
DOMAIN,
&message,
&shared_secret.to_hash_inputs(),
&nonce,
)?;
let mut wrong_cipher = cipher.clone();
wrong_cipher[message_len] += BlsScalar::from(42);
assert_eq!(
decrypt(
HashState::new(),
1u64,
&wrong_cipher,
&shared_secret.to_hash_inputs(),
&nonce,
)
.unwrap_err(),
Error::DecryptionFailed
);
let mut wrong_cipher = cipher.clone();
wrong_cipher[0] += BlsScalar::from(42);
assert_eq!(
decrypt(
HashState::new(),
1u64,
&wrong_cipher,
&shared_secret.to_hash_inputs(),
&nonce,
)
.unwrap_err(),
Error::DecryptionFailed
);
Ok(())
}