-
Notifications
You must be signed in to change notification settings - Fork 258
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
bd40099
commit 581b119
Showing
13 changed files
with
1,326 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
[package] | ||
name = "kupyna512" | ||
version = "0.1.0" | ||
edition = "2021" | ||
|
||
[dependencies] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,101 @@ | ||
#[cfg(test)] | ||
mod tests; | ||
mod sub_units; | ||
|
||
const STATE_SIZE: usize = 1024; | ||
const HASH_SIZE: usize = 512; | ||
|
||
const MAX_MESSAGE_LENGTH: usize = 18446744073709551615; | ||
|
||
fn pad_message(message: &[u8], msg_len_bits: usize, state_size: usize) -> Vec<u8> { | ||
let round_msg_len = message.len() * 8; | ||
let d = | ||
((-((round_msg_len + 97) as isize) % (state_size as isize)) + state_size as isize) as usize; | ||
|
||
// Calculate the length of padding to be added | ||
let pad_len = d / 8; | ||
|
||
// We set the padded message size upfront to reduce allocations | ||
let padded_len = (msg_len_bits + 7) / 8 + pad_len + 13; | ||
let mut padded_message = vec![0x00; padded_len]; | ||
|
||
// Copy n bits from the input message | ||
let full_bytes = msg_len_bits / 8; | ||
let remaining_bits = msg_len_bits % 8; | ||
|
||
padded_message[..full_bytes].copy_from_slice(&message[..full_bytes]); | ||
|
||
if remaining_bits > 0 { | ||
let last_byte = message[full_bytes]; | ||
padded_message[full_bytes] = last_byte & ((1 << remaining_bits) - 1); | ||
} | ||
|
||
// Set the n+1'th bit to high | ||
padded_message[msg_len_bits / 8] |= 1 << (7 - (msg_len_bits % 8)); | ||
|
||
// Convert the length to a byte array and copy it into the padded message | ||
let n_bytes = (msg_len_bits as u128).to_le_bytes(); // message length in little-endian | ||
padded_message[padded_len - 12..].copy_from_slice(&n_bytes[0..12]); | ||
|
||
padded_message | ||
} | ||
|
||
fn divide_into_blocks(padded_message: &[u8], state_size: usize) -> Vec<&[u8]> { | ||
padded_message.chunks(state_size / 8).collect() | ||
} | ||
|
||
fn truncate(block: &[u8], n: usize) -> Vec<u8> { | ||
let bytes_to_keep = n / 8; | ||
let start_index = if block.len() > bytes_to_keep { | ||
block.len() - bytes_to_keep | ||
} else { | ||
0 | ||
}; | ||
block[start_index..].to_vec() | ||
} | ||
|
||
pub fn hash(message: Vec<u8>, length: Option<usize>) -> Result<Vec<u8>, &'static str> { | ||
let mut message = message; | ||
let message_length: usize; | ||
if let Some(len) = length { | ||
if len > MAX_MESSAGE_LENGTH { | ||
return Err("Message is too long"); | ||
} | ||
if len > message.len() * 8 { | ||
return Err("Message length is less than the provided length"); | ||
} | ||
|
||
let mut trimmed_message = message[..(len/8)].to_vec(); | ||
|
||
if len % 8 != 0 { | ||
let extra_byte = message[len/8]; | ||
let extra_bits = len % 8; | ||
let mask = 0xFF << (8 - extra_bits); | ||
trimmed_message.push(extra_byte & mask); | ||
} | ||
|
||
message = trimmed_message; | ||
message_length = len; | ||
|
||
} else { | ||
if message.len() * 8 > MAX_MESSAGE_LENGTH { | ||
return Err("Message is too long"); | ||
} | ||
message_length = message.len() * 8; | ||
} | ||
|
||
let padded_message = pad_message(&message, message_length, STATE_SIZE); | ||
|
||
let blocks = divide_into_blocks(&padded_message, STATE_SIZE); | ||
|
||
let mut init_vector: Vec<u8> = vec![0; STATE_SIZE/8]; | ||
init_vector[0] = 0x80; // set the first bit of this init vector to high | ||
|
||
|
||
let fin_vector = sub_units::plant(blocks, &init_vector); | ||
|
||
let hash = truncate(&fin_vector, HASH_SIZE); | ||
|
||
Ok(hash) | ||
} | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
use kupyna512; | ||
|
||
fn main() { | ||
let message = b"Hello, World!".to_vec(); | ||
let _message_length = 0; | ||
|
||
let hash_code = kupyna512::hash(message, None).unwrap(); | ||
|
||
println!("{:02X?}", hash_code); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
mod t_xor_plus; | ||
|
||
use t_xor_plus::{t_xor_l, t_plus_l}; | ||
|
||
const ROUNDS: usize = 14; | ||
|
||
fn xor_bytes(a: &[u8], b: &[u8]) -> Vec<u8> { | ||
a.iter().zip(b.iter()).map(|(x, y)| x ^ y).collect() | ||
} | ||
|
||
fn silo(message_block: &[u8], prev_vector: &[u8]) -> Vec<u8> { | ||
|
||
let m_xor_p = xor_bytes(message_block, prev_vector); | ||
|
||
let t_xor_mp = t_xor_l(&m_xor_p, ROUNDS); | ||
|
||
let t_plus_m = t_plus_l(&message_block, ROUNDS); | ||
|
||
let return_vector = xor_bytes(&(xor_bytes(&t_xor_mp, &t_plus_m)), prev_vector); | ||
|
||
return_vector | ||
|
||
} | ||
|
||
pub(crate) fn plant(message_blocks: Vec<&[u8]>, init_vector: &[u8]) -> Vec<u8> { | ||
|
||
let mut last_vector = init_vector.to_vec(); | ||
|
||
for block in message_blocks { | ||
last_vector = silo(block, &last_vector); | ||
} | ||
|
||
let last_vector = finalize(&last_vector); | ||
|
||
last_vector | ||
} | ||
|
||
fn finalize(ult_processed_block: &[u8]) -> Vec<u8> { | ||
let t_xor_ult_processed_block = t_xor_l(ult_processed_block, ROUNDS); | ||
let final_state = xor_bytes(ult_processed_block, &t_xor_ult_processed_block); | ||
final_state | ||
} | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,162 @@ | ||
#[cfg(test)] | ||
mod tests; | ||
|
||
mod tables; | ||
|
||
const ROWS: usize = 16; | ||
const COLS: usize = 8; // For 512-bit state, adjust if needed | ||
|
||
const BITS_IN_BYTE: u8 = 8; | ||
const REDUCTION_POLYNOMIAL: u16 = 0x011d; | ||
|
||
type Matrix = [[u8; COLS]; ROWS]; | ||
|
||
use tables::{MDS_MATRIX, SBOXES}; | ||
|
||
|
||
pub(crate) fn block_to_matrix(block: &[u8]) -> Matrix { | ||
let mut matrix = [[0u8; COLS]; ROWS]; | ||
for i in 0..ROWS { | ||
for j in 0..COLS { | ||
matrix[i][j] = block[i * COLS + j]; | ||
} | ||
} | ||
matrix | ||
} | ||
|
||
fn matrix_to_block(matrix: Matrix) -> Vec<u8> { | ||
let mut block = vec![0u8; ROWS * COLS]; | ||
for i in 0..ROWS { | ||
for j in 0..COLS { | ||
block[i * COLS + j] = matrix[i][j]; | ||
} | ||
} | ||
block | ||
} | ||
|
||
pub(crate) fn add_constant_xor(mut state: Matrix, round: usize) -> Matrix { | ||
for j in 0..ROWS { | ||
let constant = ((j * 0x10) ^ round) as u8; | ||
state[j][0] ^= constant; | ||
} | ||
state | ||
} | ||
|
||
pub(crate) fn add_constant_plus(mut state: Matrix, round: usize) -> Matrix { | ||
let state_ptr = state.as_mut_ptr() as *mut u64; | ||
|
||
for j in 0..ROWS { | ||
// dbg!("{}",j); | ||
unsafe { | ||
*state_ptr.add(j) = state_ptr.add(j).read().wrapping_add( | ||
0x00F0F0F0F0F0F0F3u64 ^ (((((ROWS - j - 1) * 0x10) ^ round) as u64) << 56), | ||
); | ||
} | ||
} | ||
|
||
state | ||
} | ||
|
||
pub(crate) fn s_box_layer(mut state: Matrix) -> Matrix { | ||
for i in 0..COLS { | ||
for j in 0..ROWS { | ||
state[j][i] = SBOXES[i % 4][state[j][i] as usize]; | ||
} | ||
} | ||
state | ||
} | ||
|
||
pub(crate) fn rotate_rows(mut state: Matrix) -> Matrix { | ||
let mut temp = [0u8; ROWS]; | ||
let mut shift: i32 = -1; | ||
for i in 0..COLS { | ||
if (i == COLS - 1) && true { | ||
shift = 11; | ||
} else { | ||
shift += 1; | ||
} | ||
for col in 0..ROWS { | ||
temp[(col + shift as usize) % ROWS] = state[col][i]; | ||
} | ||
for col in 0..ROWS { | ||
state[col][i] = temp[col]; | ||
} | ||
} | ||
state | ||
} | ||
|
||
fn multiply_gf(mut x: u8, mut y: u8) -> u8 { | ||
let mut r = 0u8; | ||
|
||
for _ in 0..BITS_IN_BYTE { | ||
if y & 1 == 1 { | ||
r ^= x; | ||
} | ||
let hbit = (x & 0x80) >> 7; | ||
x <<= 1; | ||
if hbit == 1 { | ||
x ^= REDUCTION_POLYNOMIAL as u8; | ||
} | ||
y >>= 1; | ||
} | ||
|
||
r | ||
} | ||
|
||
pub(crate) fn mix_columns(state: Matrix) -> Matrix { | ||
let mut result = [[0u8; COLS]; ROWS]; | ||
|
||
for col in 0..ROWS { | ||
for row in (0..COLS).rev() { | ||
let mut product = 0u8; | ||
for b in (0..COLS).rev() { | ||
product ^= multiply_gf(state[col][b], MDS_MATRIX[row][b]); | ||
} | ||
result[col][row] = product; | ||
} | ||
} | ||
|
||
result | ||
} | ||
|
||
/// Placeholder for the T⊕l transformation. | ||
/// | ||
/// # Arguments | ||
/// | ||
/// * `block` - A byte slice representing the block to be transformed. | ||
/// * `_rounds` - The number of rounds to perform. | ||
/// | ||
/// # Returns | ||
/// | ||
/// * A `Vec<u8>` containing the transformed block. | ||
pub fn t_xor_l(block: &[u8], rounds: usize) -> Vec<u8> { | ||
let mut state = block_to_matrix(block); | ||
for nu in 0..rounds { | ||
state = add_constant_xor(state, nu); | ||
state = s_box_layer(state); | ||
state = rotate_rows(state); | ||
state = mix_columns(state); | ||
} | ||
matrix_to_block(state) | ||
} | ||
|
||
/// Placeholder for the T+l transformation. | ||
/// | ||
/// # Arguments | ||
/// | ||
/// * `block` - A byte slice representing the block to be transformed. | ||
/// * `_rounds` - The number of rounds to perform. | ||
/// | ||
/// # Returns | ||
/// | ||
/// * A `Vec<u8>` containing the transformed block. | ||
pub fn t_plus_l(block: &[u8], rounds: usize) -> Vec<u8> { | ||
let mut state = block_to_matrix(block); | ||
for nu in 0..rounds { | ||
state = add_constant_plus(state, nu); | ||
state = s_box_layer(state); | ||
state = rotate_rows(state); | ||
state = mix_columns(state); | ||
} | ||
matrix_to_block(state) | ||
} |
Oops, something went wrong.