use core::ops::Range;
use math::{fields::f64::BaseElement, FieldElement, StarkField};
use super::{super::mds::mds_f64_8x8::mds_multiply, exp_acc, Digest, ElementHasher, Hasher};
mod digest;
pub use digest::ElementDigest;
#[cfg(test)]
mod tests;
const STATE_WIDTH: usize = 8;
const RATE_RANGE: Range<usize> = 4..8;
const RATE_WIDTH: usize = RATE_RANGE.end - RATE_RANGE.start;
const INPUT1_RANGE: Range<usize> = 0..4;
const INPUT2_RANGE: Range<usize> = 4..8;
const CAPACITY_RANGE: Range<usize> = 0..4;
const DIGEST_RANGE: Range<usize> = 4..8;
const DIGEST_SIZE: usize = DIGEST_RANGE.end - DIGEST_RANGE.start;
const NUM_ROUNDS: usize = 7;
#[cfg(test)]
const ALPHA: u64 = 7;
#[cfg(test)]
const INV_ALPHA: u64 = 10540996611094048183;
pub struct RpJive64_256();
impl Hasher for RpJive64_256 {
type Digest = ElementDigest;
const COLLISION_RESISTANCE: u32 = 128;
fn hash(bytes: &[u8]) -> Self::Digest {
let num_elements = if bytes.len().is_multiple_of(7) {
bytes.len() / 7
} else {
bytes.len() / 7 + 1
};
let mut state = [BaseElement::ZERO; STATE_WIDTH];
if !num_elements.is_multiple_of(RATE_WIDTH) {
state[CAPACITY_RANGE.start] = BaseElement::ONE;
}
let mut i = 0;
let mut buf = [0_u8; 8];
for (index, chunk) in bytes.chunks(7).enumerate() {
if index < num_elements - 1 {
buf[..7].copy_from_slice(chunk);
} else {
let chunk_len = chunk.len();
buf = [0_u8; 8];
buf[..chunk_len].copy_from_slice(chunk);
buf[chunk_len] = 1;
}
state[RATE_RANGE.start + i] += BaseElement::new(u64::from_le_bytes(buf));
i += 1;
if i.is_multiple_of(RATE_WIDTH) {
Self::apply_permutation(&mut state);
i = 0;
}
}
if i > 0 {
state[RATE_RANGE.start + i] = BaseElement::ONE;
i += 1;
while i != RATE_WIDTH {
state[RATE_RANGE.start + i] = BaseElement::ZERO;
i += 1;
}
Self::apply_permutation(&mut state);
}
ElementDigest::new(state[DIGEST_RANGE].try_into().unwrap())
}
fn merge(values: &[Self::Digest; 2]) -> Self::Digest {
let initial_state: [BaseElement; STATE_WIDTH] =
Self::Digest::digests_as_elements(values).try_into().unwrap();
let mut state = initial_state;
Self::apply_permutation(&mut state);
Self::apply_jive_summation(&initial_state, &state)
}
fn merge_many(values: &[Self::Digest]) -> Self::Digest {
Self::hash_elements(ElementDigest::digests_as_elements(values))
}
fn merge_with_int(seed: Self::Digest, value: u64) -> Self::Digest {
let mut state = [BaseElement::ZERO; STATE_WIDTH];
state[INPUT1_RANGE].copy_from_slice(seed.as_elements());
state[INPUT2_RANGE.start] = BaseElement::new(value);
if value < BaseElement::MODULUS {
state[INPUT2_RANGE.end - 1] = BaseElement::new(DIGEST_SIZE as u64 + 1);
} else {
state[INPUT2_RANGE.start + 1] = BaseElement::new(value / BaseElement::MODULUS);
state[INPUT2_RANGE.end - 1] = BaseElement::new(DIGEST_SIZE as u64 + 2);
}
let initial_state = state;
Self::apply_permutation(&mut state);
Self::apply_jive_summation(&initial_state, &state)
}
}
impl ElementHasher for RpJive64_256 {
type BaseField = BaseElement;
fn hash_elements<E: FieldElement<BaseField = Self::BaseField>>(elements: &[E]) -> Self::Digest {
let elements = E::slice_as_base_elements(elements);
let mut state = [BaseElement::ZERO; STATE_WIDTH];
if !elements.len().is_multiple_of(RATE_WIDTH) {
state[CAPACITY_RANGE.start] = BaseElement::ONE;
}
let mut i = 0;
for &element in elements.iter() {
state[RATE_RANGE.start + i] += element;
i += 1;
if i.is_multiple_of(RATE_WIDTH) {
Self::apply_permutation(&mut state);
i = 0;
}
}
if i > 0 {
state[RATE_RANGE.start + i] = BaseElement::ONE;
i += 1;
while i != RATE_WIDTH {
state[RATE_RANGE.start + i] = BaseElement::ZERO;
i += 1;
}
Self::apply_permutation(&mut state);
}
ElementDigest::new(state[DIGEST_RANGE].try_into().unwrap())
}
}
impl RpJive64_256 {
pub const NUM_ROUNDS: usize = NUM_ROUNDS;
pub const STATE_WIDTH: usize = STATE_WIDTH;
pub const RATE_RANGE: Range<usize> = RATE_RANGE;
pub const CAPACITY_RANGE: Range<usize> = CAPACITY_RANGE;
pub const DIGEST_RANGE: Range<usize> = DIGEST_RANGE;
pub const MDS: [[BaseElement; STATE_WIDTH]; STATE_WIDTH] = MDS;
pub const INV_MDS: [[BaseElement; STATE_WIDTH]; STATE_WIDTH] = INV_MDS;
pub const ARK1: [[BaseElement; STATE_WIDTH]; NUM_ROUNDS] = ARK1;
pub const ARK2: [[BaseElement; STATE_WIDTH]; NUM_ROUNDS] = ARK2;
pub fn apply_permutation(state: &mut [BaseElement; STATE_WIDTH]) {
for i in 0..NUM_ROUNDS {
Self::apply_round(state, i);
}
}
#[inline(always)]
pub fn apply_round(state: &mut [BaseElement; STATE_WIDTH], round: usize) {
Self::apply_sbox(state);
Self::apply_mds(state);
Self::add_constants(state, &ARK1[round]);
Self::apply_inv_sbox(state);
Self::apply_mds(state);
Self::add_constants(state, &ARK2[round]);
}
#[inline(always)]
pub fn apply_jive_summation(
initial_state: &[BaseElement; STATE_WIDTH],
final_state: &[BaseElement; STATE_WIDTH],
) -> ElementDigest {
let mut result = [BaseElement::ZERO; DIGEST_SIZE];
for (i, r) in result.iter_mut().enumerate() {
*r = initial_state[i]
+ initial_state[DIGEST_SIZE + i]
+ final_state[i]
+ final_state[DIGEST_SIZE + i];
}
ElementDigest::new(result)
}
#[inline(always)]
fn apply_mds(state: &mut [BaseElement; STATE_WIDTH]) {
mds_multiply(state)
}
#[inline(always)]
fn add_constants(state: &mut [BaseElement; STATE_WIDTH], ark: &[BaseElement; STATE_WIDTH]) {
state.iter_mut().zip(ark).for_each(|(s, &k)| *s += k);
}
#[inline(always)]
fn apply_sbox(state: &mut [BaseElement; STATE_WIDTH]) {
state[0] = state[0].exp7();
state[1] = state[1].exp7();
state[2] = state[2].exp7();
state[3] = state[3].exp7();
state[4] = state[4].exp7();
state[5] = state[5].exp7();
state[6] = state[6].exp7();
state[7] = state[7].exp7();
}
#[inline(always)]
fn apply_inv_sbox(state: &mut [BaseElement; STATE_WIDTH]) {
let mut t1 = *state;
t1.iter_mut().for_each(|t| *t = t.square());
let mut t2 = t1;
t2.iter_mut().for_each(|t| *t = t.square());
let t3 = exp_acc::<BaseElement, STATE_WIDTH, 3>(t2, t2);
let t4 = exp_acc::<BaseElement, STATE_WIDTH, 6>(t3, t3);
let t5 = exp_acc::<BaseElement, STATE_WIDTH, 12>(t4, t4);
let t6 = exp_acc::<BaseElement, STATE_WIDTH, 6>(t5, t3);
let t7 = exp_acc::<BaseElement, STATE_WIDTH, 31>(t6, t6);
for (i, s) in state.iter_mut().enumerate() {
let a = (t7[i].square() * t6[i]).square().square();
let b = t1[i] * t2[i] * *s;
*s = a * b;
}
}
}
const MDS: [[BaseElement; STATE_WIDTH]; STATE_WIDTH] = [
[
BaseElement::new(23),
BaseElement::new(8),
BaseElement::new(13),
BaseElement::new(10),
BaseElement::new(7),
BaseElement::new(6),
BaseElement::new(21),
BaseElement::new(8),
],
[
BaseElement::new(8),
BaseElement::new(23),
BaseElement::new(8),
BaseElement::new(13),
BaseElement::new(10),
BaseElement::new(7),
BaseElement::new(6),
BaseElement::new(21),
],
[
BaseElement::new(21),
BaseElement::new(8),
BaseElement::new(23),
BaseElement::new(8),
BaseElement::new(13),
BaseElement::new(10),
BaseElement::new(7),
BaseElement::new(6),
],
[
BaseElement::new(6),
BaseElement::new(21),
BaseElement::new(8),
BaseElement::new(23),
BaseElement::new(8),
BaseElement::new(13),
BaseElement::new(10),
BaseElement::new(7),
],
[
BaseElement::new(7),
BaseElement::new(6),
BaseElement::new(21),
BaseElement::new(8),
BaseElement::new(23),
BaseElement::new(8),
BaseElement::new(13),
BaseElement::new(10),
],
[
BaseElement::new(10),
BaseElement::new(7),
BaseElement::new(6),
BaseElement::new(21),
BaseElement::new(8),
BaseElement::new(23),
BaseElement::new(8),
BaseElement::new(13),
],
[
BaseElement::new(13),
BaseElement::new(10),
BaseElement::new(7),
BaseElement::new(6),
BaseElement::new(21),
BaseElement::new(8),
BaseElement::new(23),
BaseElement::new(8),
],
[
BaseElement::new(8),
BaseElement::new(13),
BaseElement::new(10),
BaseElement::new(7),
BaseElement::new(6),
BaseElement::new(21),
BaseElement::new(8),
BaseElement::new(23),
],
];
const INV_MDS: [[BaseElement; STATE_WIDTH]; STATE_WIDTH] = [
[
BaseElement::new(10671399028204489528),
BaseElement::new(15436289366139187412),
BaseElement::new(4624329233769728317),
BaseElement::new(18200084821960740316),
BaseElement::new(8736112961492104393),
BaseElement::new(1953609990965186349),
BaseElement::new(12477339747250042564),
BaseElement::new(1495657543820456485),
],
[
BaseElement::new(1495657543820456485),
BaseElement::new(10671399028204489528),
BaseElement::new(15436289366139187412),
BaseElement::new(4624329233769728317),
BaseElement::new(18200084821960740316),
BaseElement::new(8736112961492104393),
BaseElement::new(1953609990965186349),
BaseElement::new(12477339747250042564),
],
[
BaseElement::new(12477339747250042564),
BaseElement::new(1495657543820456485),
BaseElement::new(10671399028204489528),
BaseElement::new(15436289366139187412),
BaseElement::new(4624329233769728317),
BaseElement::new(18200084821960740316),
BaseElement::new(8736112961492104393),
BaseElement::new(1953609990965186349),
],
[
BaseElement::new(1953609990965186349),
BaseElement::new(12477339747250042564),
BaseElement::new(1495657543820456485),
BaseElement::new(10671399028204489528),
BaseElement::new(15436289366139187412),
BaseElement::new(4624329233769728317),
BaseElement::new(18200084821960740316),
BaseElement::new(8736112961492104393),
],
[
BaseElement::new(8736112961492104393),
BaseElement::new(1953609990965186349),
BaseElement::new(12477339747250042564),
BaseElement::new(1495657543820456485),
BaseElement::new(10671399028204489528),
BaseElement::new(15436289366139187412),
BaseElement::new(4624329233769728317),
BaseElement::new(18200084821960740316),
],
[
BaseElement::new(18200084821960740316),
BaseElement::new(8736112961492104393),
BaseElement::new(1953609990965186349),
BaseElement::new(12477339747250042564),
BaseElement::new(1495657543820456485),
BaseElement::new(10671399028204489528),
BaseElement::new(15436289366139187412),
BaseElement::new(4624329233769728317),
],
[
BaseElement::new(4624329233769728317),
BaseElement::new(18200084821960740316),
BaseElement::new(8736112961492104393),
BaseElement::new(1953609990965186349),
BaseElement::new(12477339747250042564),
BaseElement::new(1495657543820456485),
BaseElement::new(10671399028204489528),
BaseElement::new(15436289366139187412),
],
[
BaseElement::new(15436289366139187412),
BaseElement::new(4624329233769728317),
BaseElement::new(18200084821960740316),
BaseElement::new(8736112961492104393),
BaseElement::new(1953609990965186349),
BaseElement::new(12477339747250042564),
BaseElement::new(1495657543820456485),
BaseElement::new(10671399028204489528),
],
];
const ARK1: [[BaseElement; STATE_WIDTH]; NUM_ROUNDS] = [
[
BaseElement::new(5250156239823432273),
BaseElement::new(17991370199276831394),
BaseElement::new(15363758995121189373),
BaseElement::new(7550390719632034712),
BaseElement::new(705744964663370588),
BaseElement::new(14718080047998507086),
BaseElement::new(15612952641514293932),
BaseElement::new(8827614218997241655),
],
[
BaseElement::new(3820104553051581938),
BaseElement::new(3385456123263281593),
BaseElement::new(16094709323995557719),
BaseElement::new(16303336019291352506),
BaseElement::new(8678496957982514796),
BaseElement::new(498270172890916765),
BaseElement::new(17676155962043649331),
BaseElement::new(14993644560894569061),
],
[
BaseElement::new(14258773164148374760),
BaseElement::new(1655972393090532756),
BaseElement::new(7105012644980738960),
BaseElement::new(11852376844296856307),
BaseElement::new(17816158174482938174),
BaseElement::new(3981864273667206359),
BaseElement::new(2807469273751819673),
BaseElement::new(14974221859211617968),
],
[
BaseElement::new(15947271309323471269),
BaseElement::new(14698197888879866148),
BaseElement::new(14077077040726269118),
BaseElement::new(2859805440338816615),
BaseElement::new(4945184696648790387),
BaseElement::new(15183288803792940883),
BaseElement::new(7601775560447886378),
BaseElement::new(6477224812816853098),
],
[
BaseElement::new(18213733347601447845),
BaseElement::new(10031679943792626621),
BaseElement::new(5971928707867502549),
BaseElement::new(4916840084933933812),
BaseElement::new(3613815642787339926),
BaseElement::new(16715066477165606893),
BaseElement::new(14603075385258290966),
BaseElement::new(6037771699330759024),
],
[
BaseElement::new(11092469678405138663),
BaseElement::new(14512788091784891767),
BaseElement::new(12690682422447262976),
BaseElement::new(4807355108863118656),
BaseElement::new(5207405791308193025),
BaseElement::new(5970889292753030887),
BaseElement::new(17691092604759176390),
BaseElement::new(2731892623388788619),
],
[
BaseElement::new(9320990164295747317),
BaseElement::new(8313044787501051613),
BaseElement::new(15388579942433649113),
BaseElement::new(16827303822369113172),
BaseElement::new(7362247368635881413),
BaseElement::new(5501558211335089067),
BaseElement::new(16959364163466644433),
BaseElement::new(15127897185888596873),
],
];
const ARK2: [[BaseElement; STATE_WIDTH]; NUM_ROUNDS] = [
[
BaseElement::new(9860068499471230379),
BaseElement::new(10391494434594667033),
BaseElement::new(4986587677027284267),
BaseElement::new(17781977240739864050),
BaseElement::new(6888921375142581299),
BaseElement::new(8950831725295674725),
BaseElement::new(17048848277806802259),
BaseElement::new(14146306451370933851),
],
[
BaseElement::new(707569561928852298),
BaseElement::new(6724851263229096394),
BaseElement::new(16052786826295129381),
BaseElement::new(1966016718617096590),
BaseElement::new(9416027981257317341),
BaseElement::new(650995073054283087),
BaseElement::new(10013853213448688130),
BaseElement::new(14400137552134409897),
],
[
BaseElement::new(7149263702162640230),
BaseElement::new(7096225564191267298),
BaseElement::new(12197502430442379401),
BaseElement::new(12804378092281676880),
BaseElement::new(17409570408925731570),
BaseElement::new(2819914464281065415),
BaseElement::new(15831648359524824910),
BaseElement::new(15629743966484525526),
],
[
BaseElement::new(17953398529773387863),
BaseElement::new(6198711330432012203),
BaseElement::new(9157726872360640492),
BaseElement::new(9493333679697066249),
BaseElement::new(16030612341681265024),
BaseElement::new(4739709630031417239),
BaseElement::new(18287301685877696586),
BaseElement::new(8798230489526342293),
],
[
BaseElement::new(11624786627634502148),
BaseElement::new(12924370583547723043),
BaseElement::new(11192385058160295505),
BaseElement::new(14350900531623057057),
BaseElement::new(6649040255431543914),
BaseElement::new(2106567763792008889),
BaseElement::new(12434281915569617273),
BaseElement::new(8101377239551798417),
],
[
BaseElement::new(13925815041351874730),
BaseElement::new(15981136477777934021),
BaseElement::new(17398194123970783302),
BaseElement::new(17377636820017036987),
BaseElement::new(5173992930377549692),
BaseElement::new(3688194845376511083),
BaseElement::new(16177005022792194790),
BaseElement::new(6482787365501773067),
],
[
BaseElement::new(9197066592623932055),
BaseElement::new(1777435748159421921),
BaseElement::new(5079482957444239813),
BaseElement::new(15080163201683705054),
BaseElement::new(4278835591662809119),
BaseElement::new(6609842793229774583),
BaseElement::new(651644751771720476),
BaseElement::new(14434199410773467460),
],
];