Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -60,3 +60,7 @@ winter-crypto = { git = "https://github.com/lambdaclass/winterfell-for-lambdawor
lto = true
codegen-units = 1
opt-level = 3

[workspace.lints.clippy]
restriction = "warn"
as_conversions = "warn"
6 changes: 2 additions & 4 deletions crates/crypto/src/commitments/kzg.rs
Original file line number Diff line number Diff line change
Expand Up @@ -322,10 +322,8 @@ mod tests {
});
let g1 = BLS12381Curve::generator();
let g2 = BLS12381TwistCurve::generator();
let powers_main_group: Vec<G1> = (0..100)
.map(|exponent| {
g1.operate_with_self(toxic_waste.pow(exponent as u128).representative())
})
let powers_main_group: Vec<G1> = (0..100u128)
.map(|exponent| g1.operate_with_self(toxic_waste.pow(exponent).representative()))
.collect();
let powers_secondary_group = [
g2.clone(),
Expand Down
75 changes: 54 additions & 21 deletions crates/crypto/src/hash/monolith/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,38 +38,47 @@ impl<const WIDTH: usize, const NUM_FULL_ROUNDS: usize> MonolithMersenne31<WIDTH,
assert!(WIDTH <= 24);
assert!(WIDTH.is_multiple_of(4));
Self {
round_constants: Self::instantiate_round_constants(),
round_constants: Self::instantiate_round_constants().unwrap(),
lookup1: Self::instantiate_lookup1(),
lookup2: Self::instantiate_lookup2(),
}
}

fn instantiate_round_constants() -> Vec<Vec<u32>> {
fn instantiate_round_constants() -> Result<Vec<Vec<u32>>, String> {
let mut shake = Shake128::default();
shake.update("Monolith".as_bytes());
shake.update(&[WIDTH as u8, (NUM_FULL_ROUNDS + 1) as u8]);
let num_full_round_plus_one =
u8::try_from(NUM_FULL_ROUNDS + 1).map_err(|e| format!("size conversion error: {e}"))?;
shake.update(&[
u8::try_from(WIDTH).expect("as 8<=WIDTH<=24, this should never fail"),
num_full_round_plus_one,
]);
shake.update(&MERSENNE_31_PRIME_FIELD_ORDER.to_le_bytes());
shake.update(&[8, 8, 8, 7]);
let mut shake_finalized = shake.finalize_xof();
random_matrix(&mut shake_finalized, NUM_FULL_ROUNDS, WIDTH)
Ok(random_matrix(&mut shake_finalized, NUM_FULL_ROUNDS, WIDTH))
}

fn instantiate_lookup1() -> Vec<u16> {
(0..=u16::MAX)
.map(|i| {
let hi = (i >> 8) as u8;
let lo = i as u8;
((Self::s_box(hi) as u16) << 8) | Self::s_box(lo) as u16
let hi =
u8::try_from(i >> 8).expect("as (i>>8) <= u8::MAX this should never fail");
let lo = u8::try_from(i & 0xFF)
.expect("as (i & 0xFF) <= u8::MAX this should never fail");
(u16::from(Self::s_box(hi)) << 8) | u16::from(Self::s_box(lo))
})
.collect()
}

fn instantiate_lookup2() -> Vec<u16> {
(0..(1 << 15))
.map(|i| {
let hi = (i >> 8) as u8;
let lo: u8 = i as u8;
((Self::final_s_box(hi) as u16) << 8) | Self::s_box(lo) as u16
let hi =
u8::try_from(i >> 8).expect("as (i>>8) <= u8::MAX and this should never fail");
let lo = u8::try_from(i & 0xFF)
.expect("as (i & 0xFF) <= u8::MAX this should never fail");
((u16::from(Self::final_s_box(hi))) << 8) | u16::from(Self::s_box(lo))
})
.collect()
}
Expand All @@ -89,39 +98,55 @@ impl<const WIDTH: usize, const NUM_FULL_ROUNDS: usize> MonolithMersenne31<WIDTH,
}

pub fn permutation(&self, state: &mut Vec<u32>) {
self.concrete(state);
self.concrete(state).unwrap();
for round in 0..NUM_FULL_ROUNDS {
self.bars(state);
Self::bricks(state);
self.concrete(state);
self.concrete(state).unwrap();
Self::add_round_constants(state, &self.round_constants[round]);
}
self.bars(state);
Self::bricks(state);
self.concrete(state);
self.concrete(state).unwrap();
}

// MDS matrix
fn concrete(&self, state: &mut Vec<u32>) {
fn concrete(&self, state: &mut Vec<u32>) -> Result<(), Box<dyn std::error::Error>> {
*state = if WIDTH == 16 {
Self::apply_circulant(&mut MATRIX_CIRC_MDS_16_MERSENNE31_MONOLITH.clone(), state)
} else {
let mut shake = Shake128::default();
shake.update("Monolith".as_bytes());
shake.update(&[WIDTH as u8, (NUM_FULL_ROUNDS + 1) as u8]);
let num_full_round_plus_one = u8::try_from(NUM_FULL_ROUNDS + 1)
.map_err(|e| format!("size conversion error: {e}"))?;
shake.update(&[
u8::try_from(WIDTH).expect("as 8<=WIDTH<=24 this should never fail"),
num_full_round_plus_one,
]);
shake.update(&MERSENNE_31_PRIME_FIELD_ORDER.to_le_bytes());
shake.update(&[16, 15]);
shake.update("MDS".as_bytes());
let mut shake_finalized = shake.finalize_xof();
Self::apply_cauchy_mds_matrix(&mut shake_finalized, state)
};
Ok(())
}

// S-box lookups
fn bars(&self, state: &mut [u32]) {
for state in state.iter_mut().take(NUM_BARS) {
*state = ((self.lookup2[(*state >> 16) as u16 as usize] as u32) << 16)
| (self.lookup1[*state as u16 as usize] as u32);
*state = ((u32::from(
self.lookup2[usize::from(
u16::try_from((*state >> 16) & 0xFFFF)
.expect("as (*state >> 16) & 0xFFFF <= u16::MAX this should never fail"),
)],
)) << 16)
| (u32::from(
self.lookup1[usize::from(
u16::try_from(*state & 0xFFFF)
.expect("as *state & 0xFFFF <= u16::MAX this should never fail"),
)],
));
}
}

Expand Down Expand Up @@ -153,7 +178,7 @@ impl<const WIDTH: usize, const NUM_FULL_ROUNDS: usize> MonolithMersenne31<WIDTH,
let mut output = vec![F::zero(); WIDTH];

let bits: u32 = u64::BITS
- (MERSENNE_31_PRIME_FIELD_ORDER as u64)
- (u64::from(MERSENNE_31_PRIME_FIELD_ORDER))
.saturating_sub(1)
.leading_zeros();

Expand Down Expand Up @@ -183,13 +208,19 @@ mod tests {
use super::*;

fn get_test_input(width: usize) -> Vec<u32> {
(0..width).map(|i| F::from_base_type(i as u32)).collect()
(0..width)
.map(|i| {
F::from_base_type(u32::try_from(i).expect("as 8<=WIDTH<=24 this should never fail"))
})
.collect()
}

#[test]
fn from_plonky3_concrete_width_16() {
let mut input = get_test_input(16);
MonolithMersenne31::<16, 5>::new().concrete(&mut input);
MonolithMersenne31::<16, 5>::new()
.concrete(&mut input)
.expect("as WIDTH = 16 this never fails");
assert_eq!(
input,
[
Expand All @@ -202,7 +233,9 @@ mod tests {
#[test]
fn from_plonky3_concrete_width_12() {
let mut input = get_test_input(12);
MonolithMersenne31::<12, 5>::new().concrete(&mut input);
MonolithMersenne31::<12, 5>::new()
.concrete(&mut input)
.expect("as WIDTH = 12 this never fails");
assert_eq!(
input,
[
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -111,11 +111,11 @@ impl RescuePrimeOptimized {
};
let mds_vector = self.mds_vector.as_slice();

let mds_ntt = ntt(mds_vector, omega);
let mds_ntt = ntt(mds_vector, omega)?;
let state_rev: Vec<Fp> = iter::once(state[0])
.chain(state[1..].iter().rev().cloned())
.collect();
let state_ntt = ntt(&state_rev, omega);
let state_ntt = ntt(&state_rev, omega)?;

let mut product_ntt = vec![Fp::zero(); m];
for i in 0..m {
Expand Down
14 changes: 8 additions & 6 deletions crates/crypto/src/hash/rescue_prime/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,20 +20,22 @@ pub fn bytes_to_field_elements(input: &[u8]) -> Vec<Fp> {
.collect()
}

pub fn ntt(input: &[Fp], omega: Fp) -> Vec<Fp> {
(0..input.len())
pub fn ntt(input: &[Fp], omega: Fp) -> Result<Vec<Fp>, FieldError> {
let input_64 = u64::try_from(input.len()).map_err(|_| FieldError::ConversionError)?;
Ok((0..input_64)
.map(|i| {
input.iter().enumerate().fold(Fp::zero(), |acc, (j, val)| {
acc + *val * omega.pow((i * j) as u64)
let j = u64::try_from(j).expect("as j < input_64 this should never fail");
acc + *val * omega.pow(i * j)
})
})
.collect()
.collect())
}

pub fn intt(input: &[Fp], omega_inv: Fp) -> Result<Vec<Fp>, FieldError> {
let n = input.len() as u64;
let n = u64::try_from(input.len()).map_err(|_| FieldError::ConversionError)?;
let inv_n = Fp::from(n).inv()?;
let transformed = ntt(input, omega_inv);
let transformed = ntt(input, omega_inv)?;
Ok(transformed.into_iter().map(|val| val * inv_n).collect())
}

Expand Down
43 changes: 28 additions & 15 deletions crates/crypto/src/hash/sha3/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,52 +14,65 @@ impl Sha3Hasher {
}

pub fn expand_message(msg: &[u8], dst: &[u8], len_in_bytes: u64) -> Result<Vec<u8>, String> {
let b_in_bytes = Sha3_256::output_size() as u64;
let b_in_bytes = u64::try_from(Sha3_256::output_size())
.expect("Sha3_256::output_size() <= u64::MAX this should never fail");

let ell = len_in_bytes.div_ceil(b_in_bytes);
if ell > 255 {
return Err("Abort".to_string());
}

let dst_prime: Vec<u8> = [dst, &Self::i2osp(dst.len() as u64, 1)].concat();
let z_pad = Self::i2osp(0, 64);
let l_i_b_str = Self::i2osp(len_in_bytes, 2);
let dst_64 = u64::try_from(dst.len()).map_err(|e| format!("size conversion error: {e}"))?;
let dst_prime: Vec<u8> = [dst, &Self::i2osp(dst_64, 1)?].concat();
let z_pad = Self::i2osp(0, 64)?;
let l_i_b_str = Self::i2osp(len_in_bytes, 2)?;
let msg_prime = [
z_pad,
msg.to_vec(),
l_i_b_str,
Self::i2osp(0, 1),
Self::i2osp(0, 1)?,
dst_prime.clone(),
]
.concat();
let b_0: Vec<u8> = Sha3_256::digest(msg_prime).to_vec();
let a = [b_0.clone(), Self::i2osp(1, 1), dst_prime.clone()].concat();
let a = [b_0.clone(), Self::i2osp(1, 1)?, dst_prime.clone()].concat();
let b_1 = Sha3_256::digest(a).to_vec();

let mut b_vals = Vec::<Vec<u8>>::with_capacity(ell as usize);
let mut b_vals = Vec::<Vec<u8>>::with_capacity(
usize::try_from(ell).expect("as 0 <=ell<= 255 this should never fail"),
);
b_vals.push(b_1);
for idx in 1..ell {
let aux = Self::strxor(&b_0, &b_vals[idx as usize - 1]);
let b_i = [aux, Self::i2osp(idx, 1), dst_prime.clone()].concat();
let aux = Self::strxor(
&b_0,
&b_vals
[usize::try_from(idx).expect("as idx < ell<= 256 this should never fail") - 1],
);
let b_i = [aux, Self::i2osp(idx, 1)?, dst_prime.clone()].concat();
b_vals.push(Sha3_256::digest(b_i).to_vec());
}

let mut b_vals = b_vals.concat();
b_vals.truncate(len_in_bytes as usize);
b_vals.truncate(
usize::try_from(len_in_bytes).map_err(|e| format!("size conversion error: {e}"))?,
);

Ok(b_vals)
}

fn i2osp(x: u64, length: u64) -> Vec<u8> {
fn i2osp(x: u64, length: u64) -> Result<Vec<u8>, String> {
let mut x_aux = x;
let mut digits = Vec::new();
while x_aux != 0 {
digits.push((x_aux % 256) as u8);
digits.push(
u8::try_from(x_aux % 256)
.expect("as (x_aux % 256) <= u8::MAX this should never fail"),
);
x_aux /= 256;
}
digits.resize(length as usize, 0);
let length = usize::try_from(length).map_err(|e| format!("size conversion error: {e}"))?;
digits.resize(length, 0);
digits.reverse();
digits
Ok(digits)
}

fn strxor(a: &[u8], b: &[u8]) -> Vec<u8> {
Expand Down
1 change: 1 addition & 0 deletions crates/crypto/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
#![warn(clippy::as_conversions)]
#![allow(clippy::op_ref)]
#![cfg_attr(not(feature = "std"), no_std)]
#[macro_use]
Expand Down
9 changes: 6 additions & 3 deletions crates/math/src/circle/polynomial.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ use super::{
cosets::Coset,
twiddles::{get_twiddles, TwiddlesConfig},
};
#[cfg(feature = "alloc")]
use crate::{
fft::cpu::bit_reversing::in_place_bit_reverse_permute,
field::{element::FieldElement, fields::mersenne31::field::Mersenne31Field},
Expand Down Expand Up @@ -66,9 +67,11 @@ pub fn interpolate_cfft(
// The icfft returns all the coefficients multiplied by 2^n, the length of the evaluations.
// So we multiply every element that outputs the icfft by the inverse of 2^n to get the actual coefficients.
// Note that this `unwrap` will never panic because eval.len() != 0.
let factor = (FieldElement::<Mersenne31Field>::from(eval.len() as u64))
.inv()
.unwrap();
let factor = (FieldElement::<Mersenne31Field>::from(
u64::try_from(eval.len()).expect("as usize fits in u64 this should never fail"),
))
.inv()
.unwrap();
eval_ordered.iter().map(|coef| coef * factor).collect()
}

Expand Down
2 changes: 2 additions & 0 deletions crates/math/src/circle/twiddles.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
extern crate alloc;
#[cfg(feature = "alloc")]
use crate::{
circle::cosets::Coset,
field::{element::FieldElement, fields::mersenne31::field::Mersenne31Field},
};
#[cfg(feature = "alloc")]
use alloc::vec::Vec;

#[derive(PartialEq)]
Expand Down
3 changes: 3 additions & 0 deletions crates/math/src/fft/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,9 @@ impl From<FieldError> for FFTError {
FieldError::InvZeroError => {
panic!("Can't calculate inverse of zero during FFT");
}
FieldError::ConversionError => {
panic!("Can't convert usize to integer type during FFT");
}
FieldError::RootOfUnityError(order) => FFTError::RootOfUnityError(order),
}
}
Expand Down
9 changes: 7 additions & 2 deletions crates/math/src/field/element.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
use crate::errors::{ByteConversionError, CreationError};
#[cfg(feature = "alloc")]
use crate::errors::ByteConversionError;
use crate::errors::CreationError;
use crate::field::errors::FieldError;
use crate::field::traits::IsField;
#[cfg(feature = "alloc")]
use crate::traits::ByteConversion;
use crate::unsigned_integer::element::UnsignedInteger;
use crate::unsigned_integer::montgomery::MontgomeryAlgorithms;
Expand All @@ -16,7 +19,9 @@ use core::iter::Sum;
))]
use core::marker::PhantomData;
use core::ops::{Add, AddAssign, Div, Mul, MulAssign, Neg, Sub};
#[cfg(feature = "alloc")]
use num_bigint::BigUint;
#[cfg(feature = "alloc")]
use num_traits::Num;
#[cfg(any(
feature = "lambdaworks-serde-binary",
Expand Down Expand Up @@ -836,7 +841,7 @@ mod tests {
.map(|x| { FieldElement::<U64TestField>::from(x) })
.sum::<FieldElement<U64TestField>>()
.value,
((n - 1) as f64 / 2. * ((n - 1) as f64 + 1.)) as u64 % MODULUS
n * (n - 1) / 2 % MODULUS
);
}

Expand Down
2 changes: 2 additions & 0 deletions crates/math/src/field/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,6 @@ pub enum FieldError {
RootOfUnityError(u64),
/// Can't calculate inverse of zero
InvZeroError,
/// usize conversion error
ConversionError,
}