use crate::{
core::{
actually_used_field::ActuallyUsedField,
bounds::FieldBounds,
circuits::{
boolean::{
boolean_value::{Boolean, BooleanValue},
byte::Byte,
sha2::Sha256,
sha3::{Sha3_256, Sha3_512},
},
traits::arithmetic_circuit::ArithmeticCircuit,
},
expressions::expr::EvalFailure,
global_value::value::FieldValue,
},
utils::{
crypto::{rescue_desc::RescueArg, rescue_prime_hash::RescuePrimeHash},
field::BaseField,
},
};
use hmac::Mac;
pub trait Hmac<T> {
fn digest(&self, key: Vec<T>, message: Vec<T>) -> Vec<T>;
}
#[derive(Debug)]
#[allow(non_camel_case_types)]
pub struct Hmac_RescuePrime<F: ActuallyUsedField, T: RescueArg<F>> {
pub hasher: RescuePrimeHash<F, T>,
}
impl<F: ActuallyUsedField, T: RescueArg<F>> Hmac_RescuePrime<F, T> {
pub fn new() -> Self {
Self {
hasher: RescuePrimeHash::new(),
}
}
}
impl<F: ActuallyUsedField, T: RescueArg<F>> Hmac<T> for Hmac_RescuePrime<F, T> {
fn digest(&self, key: Vec<T>, message: Vec<T>) -> Vec<T> {
assert!(
self.hasher.digest_len <= key.len() && key.len() <= self.hasher.rate,
"The length of the key is supposed to be at least the hash function's digest length and at most the hash function's rate (found key length: {}, digest length: {} and rate: {})",
key.len(),
self.hasher.digest_len,
self.hasher.rate
);
let ipad = T::from(F::from_le_bytes([0x36; 32]));
let opad = T::from(F::from_le_bytes([0x5c; 32]));
let mut key_extended = key;
key_extended.resize(self.hasher.rate, T::from(F::ZERO));
let mut key_plus_ipad = key_extended.iter().map(|k| *k + ipad).collect::<Vec<T>>();
key_plus_ipad.extend(message);
let inner_digest = self.hasher.digest(key_plus_ipad).to_vec();
let mut key_plus_opad = key_extended.iter().map(|k| *k + opad).collect::<Vec<T>>();
key_plus_opad.extend(inner_digest);
self.hasher.digest(key_plus_opad).to_vec()
}
}
impl<F: ActuallyUsedField, T: RescueArg<F>> Default for Hmac_RescuePrime<F, T> {
fn default() -> Self {
Self::new()
}
}
macro_rules! impl_hmac {
($t: ident, $hasher: ident) => {
#[derive(Clone, Debug)]
#[allow(non_camel_case_types)]
pub struct $t {
pub hasher: $hasher,
}
impl $t {
pub fn new() -> Self {
Self { hasher: $hasher::new() }
}
}
impl<B: Boolean> Hmac<Byte<B>> for $t {
fn digest(&self, key: Vec<Byte<B>>, message: Vec<Byte<B>>) -> Vec<Byte<B>> {
assert!(
$hasher::DIGEST_BYTES <= key.len() && key.len() <= $hasher::BLOCK_BYTES,
"The key length is supposed to be at least the hash function's digest length and at most the hash function's block length (found key length: {}, digest length: {} and block length: {})",
key.len(),
$hasher::DIGEST_BYTES,
$hasher::BLOCK_BYTES
);
let ipad = Byte::from(0x36);
let opad = Byte::from(0x5C);
let mut key_extended = key;
key_extended.resize($hasher::BLOCK_BYTES, Byte::from(0u8));
let mut key_xor_ipad = key_extended.iter().map(|k| *k ^ ipad).collect::<Vec<Byte<B>>>();
key_xor_ipad.extend(&message);
let inner_digest = self.hasher.digest(key_xor_ipad).to_vec();
let mut key_xor_opad = key_extended.iter().map(|k| *k ^ opad).collect::<Vec<Byte<B>>>();
key_xor_opad.extend(inner_digest);
self.hasher.digest(key_xor_opad).to_vec()
}
}
impl Default for $t {
fn default() -> Self {
Self::new()
}
}
};
}
impl_hmac!(Hmac_Sha256, Sha256);
impl_hmac!(Hmac_Sha3_256, Sha3_256);
impl_hmac!(Hmac_Sha3_512, Sha3_512);
impl ArithmeticCircuit<BaseField> for Hmac_Sha256 {
fn eval(&self, x: Vec<BaseField>) -> Result<Vec<BaseField>, EvalFailure> {
x.iter()
.for_each(|byte| assert!(*byte <= BaseField::from(255)));
let mut key = x
.into_iter()
.map(|val| val.to_le_bytes()[0])
.collect::<Vec<u8>>();
let message = key.split_off(Sha256::DIGEST_BYTES);
let mut mac = hmac::Hmac::<sha2::Sha256>::new_from_slice(&key)
.expect("HMAC can take key of any size");
mac.update(&message);
Ok(mac
.finalize()
.into_bytes()
.iter()
.map(|byte| BaseField::from(*byte as u64))
.collect::<Vec<BaseField>>())
}
fn bounds(&self, _bounds: Vec<FieldBounds<BaseField>>) -> Vec<FieldBounds<BaseField>> {
vec![FieldBounds::new(BaseField::from(0), BaseField::from(255)); Sha256::DIGEST_BYTES]
}
fn run(&self, vals: Vec<FieldValue<BaseField>>) -> Vec<FieldValue<BaseField>> {
let mut key = vals
.into_iter()
.map(Byte::from)
.collect::<Vec<Byte<BooleanValue>>>();
let message = key.split_off(Sha256::DIGEST_BYTES);
let hmac = Hmac_Sha256::new();
let mac = hmac.digest(key, message);
mac.into_iter()
.map(FieldValue::<BaseField>::from)
.collect::<Vec<FieldValue<BaseField>>>()
}
}
impl ArithmeticCircuit<BaseField> for Hmac_Sha3_256 {
fn eval(&self, x: Vec<BaseField>) -> Result<Vec<BaseField>, EvalFailure> {
x.iter()
.for_each(|byte| assert!(*byte <= BaseField::from(255)));
let mut key = x
.into_iter()
.map(|val| val.to_le_bytes()[0])
.collect::<Vec<u8>>();
let message = key.split_off(Sha3_256::DIGEST_BYTES);
let mut mac = hmac::Hmac::<sha3::Sha3_256>::new_from_slice(&key)
.expect("HMAC can take key of any size");
mac.update(&message);
Ok(mac
.finalize()
.into_bytes()
.iter()
.map(|byte| BaseField::from(*byte as u64))
.collect::<Vec<BaseField>>())
}
fn bounds(&self, _bounds: Vec<FieldBounds<BaseField>>) -> Vec<FieldBounds<BaseField>> {
vec![FieldBounds::new(BaseField::from(0), BaseField::from(255)); Sha3_256::DIGEST_BYTES]
}
fn run(&self, vals: Vec<FieldValue<BaseField>>) -> Vec<FieldValue<BaseField>> {
let mut key = vals
.into_iter()
.map(Byte::from)
.collect::<Vec<Byte<BooleanValue>>>();
let message = key.split_off(Sha3_256::DIGEST_BYTES);
let hmac = Hmac_Sha3_256::new();
let mac = hmac.digest(key, message);
mac.into_iter()
.map(FieldValue::<BaseField>::from)
.collect::<Vec<FieldValue<BaseField>>>()
}
}
impl ArithmeticCircuit<BaseField> for Hmac_Sha3_512 {
fn eval(&self, x: Vec<BaseField>) -> Result<Vec<BaseField>, EvalFailure> {
x.iter()
.for_each(|byte| assert!(*byte <= BaseField::from(255)));
let mut key = x
.into_iter()
.map(|val| val.to_le_bytes()[0])
.collect::<Vec<u8>>();
let message = key.split_off(Sha3_512::DIGEST_BYTES);
let mut mac = hmac::Hmac::<sha3::Sha3_512>::new_from_slice(&key)
.expect("HMAC can take key of any size");
mac.update(&message);
Ok(mac
.finalize()
.into_bytes()
.iter()
.map(|byte| BaseField::from(*byte as u64))
.collect::<Vec<BaseField>>())
}
fn bounds(&self, _bounds: Vec<FieldBounds<BaseField>>) -> Vec<FieldBounds<BaseField>> {
vec![FieldBounds::new(BaseField::from(0), BaseField::from(255)); Sha3_512::DIGEST_BYTES]
}
fn run(&self, vals: Vec<FieldValue<BaseField>>) -> Vec<FieldValue<BaseField>> {
let mut key = vals
.into_iter()
.map(Byte::from)
.collect::<Vec<Byte<BooleanValue>>>();
let message = key.split_off(Sha3_512::DIGEST_BYTES);
let hmac = Hmac_Sha3_512::new();
let mac = hmac.digest(key, message);
mac.into_iter()
.map(FieldValue::<BaseField>::from)
.collect::<Vec<FieldValue<BaseField>>>()
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::core::circuits::traits::arithmetic_circuit::tests::TestedArithmeticCircuit;
use rand::Rng;
impl TestedArithmeticCircuit<BaseField> for Hmac_Sha256 {
fn gen_desc<R: Rng + ?Sized>(_rng: &mut R) -> Self {
Self::new()
}
fn gen_n_inputs<R: Rng + ?Sized>(&self, rng: &mut R) -> usize {
Sha256::DIGEST_BYTES
+ TryInto::<usize>::try_into(rng.next_u32()).unwrap() % Sha256::BLOCK_BYTES
}
fn gen_input_bounds<R: Rng + ?Sized>(_rng: &mut R) -> FieldBounds<BaseField> {
FieldBounds::new(BaseField::from(0), BaseField::from(255))
}
}
impl TestedArithmeticCircuit<BaseField> for Hmac_Sha3_256 {
fn gen_desc<R: Rng + ?Sized>(_rng: &mut R) -> Self {
Self::new()
}
fn gen_n_inputs<R: Rng + ?Sized>(&self, rng: &mut R) -> usize {
Sha3_256::DIGEST_BYTES
+ TryInto::<usize>::try_into(rng.next_u32()).unwrap() % Sha3_256::BLOCK_BYTES
}
fn gen_input_bounds<R: Rng + ?Sized>(_rng: &mut R) -> FieldBounds<BaseField> {
FieldBounds::new(BaseField::from(0), BaseField::from(255))
}
}
impl TestedArithmeticCircuit<BaseField> for Hmac_Sha3_512 {
fn gen_desc<R: Rng + ?Sized>(_rng: &mut R) -> Self {
Self::new()
}
fn gen_n_inputs<R: Rng + ?Sized>(&self, rng: &mut R) -> usize {
Sha3_512::DIGEST_BYTES
+ TryInto::<usize>::try_into(rng.next_u32()).unwrap() % Sha3_512::BLOCK_BYTES
}
fn gen_input_bounds<R: Rng + ?Sized>(_rng: &mut R) -> FieldBounds<BaseField> {
FieldBounds::new(BaseField::from(0), BaseField::from(255))
}
}
#[test]
fn tested_hmac_sha256() {
Hmac_Sha256::test(1, 1)
}
#[test]
fn tested_hmac_sha3_256() {
Hmac_Sha3_256::test(1, 1)
}
#[test]
fn tested_hmac_sha3_512() {
Hmac_Sha3_512::test(1, 1)
}
}