Very simple implementation of sha3_256 (doesn't work for very long inputs)
This commit is contained in:
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
/target
|
||||||
7
Cargo.lock
generated
Normal file
7
Cargo.lock
generated
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
# This file is automatically @generated by Cargo.
|
||||||
|
# It is not intended for manual editing.
|
||||||
|
version = 4
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "sha3"
|
||||||
|
version = "0.1.0"
|
||||||
4
Cargo.toml
Normal file
4
Cargo.toml
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
[package]
|
||||||
|
name = "sha3"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2024"
|
||||||
37
src/lib.rs
Normal file
37
src/lib.rs
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
pub mod sha3;
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
// use super::*;
|
||||||
|
|
||||||
|
use crate::sha3::Sha3_256;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn it_works() {
|
||||||
|
let mut sha = Sha3_256::default();
|
||||||
|
|
||||||
|
let text = "";
|
||||||
|
|
||||||
|
let arr = text.as_bytes();
|
||||||
|
|
||||||
|
let mut data = [0_u8; 136];
|
||||||
|
data.clone_from_slice(arr);
|
||||||
|
|
||||||
|
// sha.absorb([0, 1, 2, 3, 4, 5, 6, 7]);
|
||||||
|
sha.absorb(&data);
|
||||||
|
let res = sha.squeeze();
|
||||||
|
// a7ffc6f8bf1ed76651c14756a061d662f580ff4de43b49fa82d80a4b80f8434a
|
||||||
|
let expected_res: [u8; 32] = [
|
||||||
|
0xa7, 0xff, 0xc6, 0xf8, 0xbf, 0x1e, 0xd7, 0x66, 0x51, 0xc1, 0x47, 0x56, 0xa0, 0x61,
|
||||||
|
0xd6, 0x62, 0xf5, 0x80, 0xff, 0x4d, 0xe4, 0x3b, 0x49, 0xfa, 0x82, 0xd8, 0x0a, 0x4b,
|
||||||
|
0x80, 0xf8, 0x43, 0x4a,
|
||||||
|
];
|
||||||
|
|
||||||
|
for i in 0..32 {
|
||||||
|
print!("{:#001x}", res[i]);
|
||||||
|
}
|
||||||
|
println!();
|
||||||
|
|
||||||
|
assert!(res == expected_res);
|
||||||
|
}
|
||||||
|
}
|
||||||
26
src/main.rs
Normal file
26
src/main.rs
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
use sha3::sha3::Sha3_256;
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let mut sha = Sha3_256::default();
|
||||||
|
|
||||||
|
// println!("{:?}", (0x01 as u64).to_ne_bytes());
|
||||||
|
|
||||||
|
let text = "hola";
|
||||||
|
|
||||||
|
sha.absorb(text.as_bytes());
|
||||||
|
let res = sha.squeeze();
|
||||||
|
|
||||||
|
let expected_res: [u8; 32] = [
|
||||||
|
0x8a, 0xf1, 0x3d, 0x92, 0x44, 0x61, 0x8e, 0xee, 0x87, 0x6d, 0x04, 0x31, 0xf3, 0x44, 0x9a,
|
||||||
|
0xa4, 0xff, 0x95, 0x27, 0x4c, 0xa3, 0xe7, 0xe5, 0xc6, 0x54, 0x19, 0x79, 0x49, 0x9f, 0x5b,
|
||||||
|
0x85, 0xde,
|
||||||
|
];
|
||||||
|
|
||||||
|
for i in 0..32 {
|
||||||
|
print!("{:#001x} ", res[i]);
|
||||||
|
}
|
||||||
|
println!();
|
||||||
|
|
||||||
|
assert!(res == expected_res);
|
||||||
|
println!("FUNCIONAAAAA");
|
||||||
|
}
|
||||||
171
src/sha3.rs
Normal file
171
src/sha3.rs
Normal file
@@ -0,0 +1,171 @@
|
|||||||
|
// Rate: 1088
|
||||||
|
// Capacity: 512
|
||||||
|
|
||||||
|
// use std::arch::x86_64::_mm256_xor_epi64;
|
||||||
|
|
||||||
|
use std::array;
|
||||||
|
|
||||||
|
const RATE_256: usize = 136;
|
||||||
|
const TOTAL_STATE_SIZE: usize = 200;
|
||||||
|
const ROUNDS: usize = 24;
|
||||||
|
const DELIMITER_SUFFIX: u8 = 0x06; // delimiter suffix for sha3
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct Sha3_256 {
|
||||||
|
state: [u8; TOTAL_STATE_SIZE],
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for Sha3_256 {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self {
|
||||||
|
state: [0; TOTAL_STATE_SIZE],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Sha3_256 {
|
||||||
|
pub fn absorb(&mut self, input: &[u8]) {
|
||||||
|
// Xor input with rate
|
||||||
|
let mut remaining = input.len();
|
||||||
|
let mut off = 0;
|
||||||
|
let mut in_len = 0;
|
||||||
|
while remaining > 0 {
|
||||||
|
in_len = remaining.min(RATE_256);
|
||||||
|
println!("{}", in_len);
|
||||||
|
for i in 0..in_len {
|
||||||
|
self.state[i] ^= input[i + off];
|
||||||
|
}
|
||||||
|
off += in_len - 1;
|
||||||
|
remaining -= in_len;
|
||||||
|
|
||||||
|
if in_len == RATE_256 {
|
||||||
|
keccak_permute(&mut self.state);
|
||||||
|
in_len = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
self.state[in_len] ^= DELIMITER_SUFFIX;
|
||||||
|
|
||||||
|
if (DELIMITER_SUFFIX & 0x80) != 0 && in_len == RATE_256 - 1 {
|
||||||
|
keccak_permute(&mut self.state);
|
||||||
|
}
|
||||||
|
|
||||||
|
self.state[RATE_256 - 1] ^= 0x80;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn squeeze<const S: usize>(&mut self) -> [u8; S] {
|
||||||
|
keccak_permute(&mut self.state);
|
||||||
|
let mut res = [0_u8; S];
|
||||||
|
let mut out_len;
|
||||||
|
let mut remaining = S;
|
||||||
|
let mut off = 0;
|
||||||
|
while remaining > 0 {
|
||||||
|
out_len = remaining.min(RATE_256);
|
||||||
|
res[off..off + out_len].copy_from_slice(&self.state[0..out_len]);
|
||||||
|
off += out_len;
|
||||||
|
remaining -= out_len;
|
||||||
|
|
||||||
|
if out_len > 0 {
|
||||||
|
keccak_permute(&mut self.state);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// *self.state.first_chunk().unwrap()
|
||||||
|
res
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn keccak_permute(input: &mut [u8; TOTAL_STATE_SIZE]) {
|
||||||
|
let (lanes, _) = input.as_chunks_mut::<8>();
|
||||||
|
let mut lfsr_state = 0x01_u8;
|
||||||
|
for _ in 0..ROUNDS {
|
||||||
|
// θ step
|
||||||
|
let c: [u64; 5] = array::from_fn(|x| {
|
||||||
|
get_lane(lanes, x, 0)
|
||||||
|
^ get_lane(lanes, x, 1)
|
||||||
|
^ get_lane(lanes, x, 2)
|
||||||
|
^ get_lane(lanes, x, 3)
|
||||||
|
^ get_lane(lanes, x, 4)
|
||||||
|
});
|
||||||
|
|
||||||
|
let mut d: u64;
|
||||||
|
for x in 0..5 {
|
||||||
|
d = c[(x + 4) % 5] ^ rol64(c[(x + 1) % 5], 1);
|
||||||
|
for y in 0..5 {
|
||||||
|
xor_lane(d, lanes, x, y);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ρ and π steps
|
||||||
|
let (mut x, mut y) = (1, 0);
|
||||||
|
let mut current = get_lane(lanes, x, y);
|
||||||
|
let mut temp: u64;
|
||||||
|
|
||||||
|
for t in 0..24 {
|
||||||
|
let r = ((t + 1) * (t + 2) / 2) % 64;
|
||||||
|
let y2 = (2 * x + 3 * y) % 5;
|
||||||
|
x = y;
|
||||||
|
y = y2;
|
||||||
|
|
||||||
|
temp = get_lane(lanes, x, y);
|
||||||
|
set_lane(rol64(current, r), x, y, lanes);
|
||||||
|
current = temp;
|
||||||
|
}
|
||||||
|
|
||||||
|
// χ step
|
||||||
|
let mut temp2 = [0_u64; 5];
|
||||||
|
for y in 0..5 {
|
||||||
|
for x in 0..5 {
|
||||||
|
temp2[x] = get_lane(lanes, x, y);
|
||||||
|
}
|
||||||
|
for x in 0..5 {
|
||||||
|
set_lane(
|
||||||
|
temp2[x] ^ ((!temp2[(x + 1) % 5]) & temp2[(x + 2) % 5]),
|
||||||
|
x,
|
||||||
|
y,
|
||||||
|
lanes,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ι step
|
||||||
|
|
||||||
|
for j in 0..7 {
|
||||||
|
let bit_pos: usize = (1 << j) - 1;
|
||||||
|
if lfsr86540(&mut lfsr_state) {
|
||||||
|
xor_lane((1 as u64) << bit_pos, lanes, 0, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn get_lane(lanes: &[[u8; 8]], x: usize, y: usize) -> u64 {
|
||||||
|
u64::from_ne_bytes(lanes[x + 5 * y])
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn set_lane(lane: u64, x: usize, y: usize, lanes: &mut [[u8; 8]]) {
|
||||||
|
lanes[x + 5 * y] = lane.to_ne_bytes();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn rol64(v: u64, off: usize) -> u64 {
|
||||||
|
((v) << off) ^ ((v) >> (64 - off))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn xor_lane(lane: u64, lanes: &mut [[u8; 8]], x: usize, y: usize) {
|
||||||
|
set_lane(get_lane(lanes, x, y) ^ lane, x, y, lanes);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Function that computes the linear feedback shift register (LFSR)
|
||||||
|
// I have absolutely no idea wtf is this shit. Copied from a github repo lol.
|
||||||
|
fn lfsr86540(lfsr: &mut u8) -> bool {
|
||||||
|
let res = (*lfsr & 0x01) != 0;
|
||||||
|
if (*lfsr & 0x80) != 0 {
|
||||||
|
*lfsr = (*lfsr << 1) ^ 0x71;
|
||||||
|
} else {
|
||||||
|
*lfsr <<= 1;
|
||||||
|
}
|
||||||
|
res
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user