Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

const fn hashing #50

Open
rubdos opened this issue Jul 2, 2021 · 0 comments
Open

const fn hashing #50

rubdos opened this issue Jul 2, 2021 · 0 comments

Comments

@rubdos
Copy link

rubdos commented Jul 2, 2021

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. keccakf is now const fn.
  • The Permutation trait. A trait function cannot be const. 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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant