-
Notifications
You must be signed in to change notification settings - Fork 61
Open
Description
Hi!
I'm using Shake in a setting where all input data is known at compile-time, a case where the hash value could be computed at compile-time too.
I feel that Rust has everything needed for it, so I've been toying with const fn for all the things.
Main hurdles:
- The "rounds" for loop. Solved by a macro that transforms the for loop into a while loop. We could just manually make it a while loop too, probably simpler. The other for loops are unrolled, so nothing more needed.
keccakfis nowconst fn. - The
Permutationtrait. A trait function cannot beconst. Not sure how to solve; we could get rid of the trait entirely (since there's only one permutation).
Would a const implementation be welcome? If so, do you have an idea to get around the trait problem?
My WIP const implementation
diff --git a/src/lib.rs b/src/lib.rs
index 9329fd3..a46aa79 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -38,6 +38,7 @@
//! [`@oleganza`]: https://github.com/oleganza
//! [`CC0`]: https://github.com/debris/tiny-keccak/blob/master/LICENSE
+#![feature(const_mut_refs)]
#![no_std]
#![deny(missing_docs)]
@@ -51,71 +52,83 @@ const PI: [usize; 24] = [
const WORDS: usize = 25;
+macro_rules! const_for {
+ (for $i:ident in $begin:tt..$end:tt { $($body:tt)* }) => {
+ let mut $i = $begin;
+ while $i < $end {
+ $($body)*
+ $i += 1;
+ }
+ };
+}
+
macro_rules! keccak_function {
($doc: expr, $name: ident, $rounds: expr, $rc: expr) => {
#[doc = $doc]
#[allow(unused_assignments)]
#[allow(non_upper_case_globals)]
- pub fn $name(a: &mut [u64; $crate::WORDS]) {
+ pub const fn $name(a: &mut [u64; $crate::WORDS]) {
use crunchy::unroll;
- for i in 0..$rounds {
- let mut array: [u64; 5] = [0; 5];
-
- // Theta
- unroll! {
- for x in 0..5 {
- unroll! {
- for y_count in 0..5 {
- let y = y_count * 5;
- array[x] ^= a[x + y];
+ const_for! {
+ for i in 0..$rounds {
+ let mut array: [u64; 5] = [0; 5];
+
+ // Theta
+ unroll! {
+ for x in 0..5 {
+ unroll! {
+ for y_count in 0..5 {
+ let y = y_count * 5;
+ array[x] ^= a[x + y];
+ }
}
}
}
- }
- unroll! {
- for x in 0..5 {
- unroll! {
- for y_count in 0..5 {
- let y = y_count * 5;
- a[y + x] ^= array[(x + 4) % 5] ^ array[(x + 1) % 5].rotate_left(1);
+ unroll! {
+ for x in 0..5 {
+ unroll! {
+ for y_count in 0..5 {
+ let y = y_count * 5;
+ a[y + x] ^= array[(x + 4) % 5] ^ array[(x + 1) % 5].rotate_left(1);
+ }
}
}
}
- }
- // Rho and pi
- let mut last = a[1];
- unroll! {
- for x in 0..24 {
- array[0] = a[$crate::PI[x]];
- a[$crate::PI[x]] = last.rotate_left($crate::RHO[x]);
- last = array[0];
+ // Rho and pi
+ let mut last = a[1];
+ unroll! {
+ for x in 0..24 {
+ array[0] = a[$crate::PI[x]];
+ a[$crate::PI[x]] = last.rotate_left($crate::RHO[x]);
+ last = array[0];
+ }
}
- }
- // Chi
- unroll! {
- for y_step in 0..5 {
- let y = y_step * 5;
+ // Chi
+ unroll! {
+ for y_step in 0..5 {
+ let y = y_step * 5;
- unroll! {
- for x in 0..5 {
- array[x] = a[y + x];
+ unroll! {
+ for x in 0..5 {
+ array[x] = a[y + x];
+ }
}
- }
- unroll! {
- for x in 0..5 {
- a[y + x] = array[x] ^ ((!array[(x + 1) % 5]) & (array[(x + 2) % 5]));
+ unroll! {
+ for x in 0..5 {
+ a[y + x] = array[x] ^ ((!array[(x + 1) % 5]) & (array[(x + 2) % 5]));
+ }
}
}
- }
- };
+ };
- // Iota
- a[0] ^= $rc[i];
+ // Iota
+ a[0] ^= $rc[i];
+ }
}
}
}
@@ -301,7 +314,7 @@ fn right_encode(len: usize) -> EncodedLen {
struct Buffer([u64; WORDS]);
impl Buffer {
- fn words(&mut self) -> &mut [u64; WORDS] {
+ const fn words(&mut self) -> &mut [u64; WORDS] {
&mut self.0
}
Best regards,
Ruben
thvdveld
Metadata
Metadata
Assignees
Labels
No labels