Created
October 5, 2017 19:25
-
-
Save et4te/d59293bcd305268f4a8c4777ebeabf94 to your computer and use it in GitHub Desktop.
salsa20
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
#![feature(slice_patterns)] | |
pub fn quarter_round(y: [u32; 4]) -> [u32; 4] { | |
let z1 = y[1] ^ (y[0].wrapping_add(y[3])).rotate_left(7); | |
let z2 = y[2] ^ (z1.wrapping_add(y[0])).rotate_left(9); | |
let z3 = y[3] ^ (z2.wrapping_add(z1)).rotate_left(13); | |
let z0 = y[0] ^ (z3.wrapping_add(z2)).rotate_left(18); | |
[z0, z1, z2, z3] | |
} | |
pub fn row_round(y: [u32; 16]) -> [u32; 16] { | |
let [z0, z1, z2, z3] = quarter_round([y[0], y[1], y[2], y[3]]); | |
let [z5, z6, z7, z4] = quarter_round([y[5], y[6], y[7], y[4]]); | |
let [z10, z11, z8, z9] = quarter_round([y[10], y[11], y[8], y[9]]); | |
let [z15, z12, z13, z14] = quarter_round([y[15], y[12], y[13], y[14]]); | |
[ z0, z1, z2, z3, z4, z5, z6, z7, z8, z9, z10, z11, z12, z13, z14, z15 ] | |
} | |
pub fn column_round(x: [u32; 16]) -> [u32; 16] { | |
let [y0, y4, y8, y12] = quarter_round([x[0], x[4], x[8], x[12]]); | |
let [y5, y9, y13, y1] = quarter_round([x[5], x[9], x[13], x[1]]); | |
let [y10, y14, y2, y6] = quarter_round([x[10], x[14], x[2], x[6]]); | |
let [y15, y3, y7, y11] = quarter_round([x[15], x[3], x[7], x[11]]); | |
[ y0, y1, y2, y3, y4, y5, y6, y7, y8, y9, y10, y11, y12, y13, y14, y15 ] | |
} | |
pub fn double_round(x: [u32; 16]) -> [u32; 16] { | |
row_round(column_round(x)) | |
} | |
pub fn little_endian(b: [u8; 4]) -> u32 { | |
b[0] as u32 + ((b[1] as u32) << 8) + ((b[2] as u32) << 16) + ((b[3] as u32) << 24) | |
} | |
pub fn little_endian_inv(x: u32) -> [u8; 4] { | |
let b0 = x & 0xFF; | |
let b1 = (x & 0xFF00) >> 8; | |
let b2 = (x & 0xFF0000) >> 16; | |
let b3 = (x & 0xFF000000) >> 24; | |
[b0 as u8, b1 as u8, b2 as u8, b3 as u8] | |
} | |
pub fn salsa20_hash(x: [u8; 64]) -> [u8; 64] { | |
let mut xs = [0u32; 16]; | |
for i in 0..16 { | |
xs[i] = little_endian([x[i*4], x[i*4+1], x[i*4+2], x[i*4+3]]); | |
} | |
let mut zs = xs; | |
for _ in 0..10 { | |
zs = double_round(zs); | |
} | |
let mut rs = [0; 64]; | |
for i in 0..16 { | |
let vs = little_endian_inv(zs[i].wrapping_add(xs[i])); | |
rs[i*4] = vs[0]; | |
rs[i*4+1] = vs[1]; | |
rs[i*4+2] = vs[2]; | |
rs[i*4+3] = vs[3]; | |
} | |
rs | |
} | |
#[cfg(test)] | |
mod tests { | |
use super::*; | |
#[test] | |
fn test_quarter_round() { | |
let test_v1 = [0x00000000, 0x00000000, 0x00000000, 0x00000000]; | |
let test_r1 = [0x00000000, 0x00000000, 0x00000000, 0x00000000]; | |
assert_eq!(quarter_round(test_v1), test_r1); | |
let test_v2 = [0x00000001, 0x00000000, 0x00000000, 0x00000000]; | |
let test_r2 = [0x08008145, 0x00000080, 0x00010200, 0x20500000]; | |
assert_eq!(quarter_round(test_v2), test_r2); | |
} | |
#[test] | |
fn test_row_round() { | |
let test_v1 = [ | |
0x00000001, 0x00000000, 0x00000000, 0x00000000, | |
0x00000001, 0x00000000, 0x00000000, 0x00000000, | |
0x00000001, 0x00000000, 0x00000000, 0x00000000, | |
0x00000001, 0x00000000, 0x00000000, 0x00000000, | |
]; | |
let test_r1 = [ | |
0x08008145, 0x00000080, 0x00010200, 0x20500000, | |
0x20100001, 0x00048044, 0x00000080, 0x00010000, | |
0x00000001, 0x00002000, 0x80040000, 0x00000000, | |
0x00000001, 0x00000200, 0x00402000, 0x88000100, | |
]; | |
assert_eq!(row_round(test_v1), test_r1); | |
} | |
#[test] | |
fn test_column_round() { | |
let test_v1 = [ | |
0x00000001, 0x00000000, 0x00000000, 0x00000000, | |
0x00000001, 0x00000000, 0x00000000, 0x00000000, | |
0x00000001, 0x00000000, 0x00000000, 0x00000000, | |
0x00000001, 0x00000000, 0x00000000, 0x00000000, | |
]; | |
let test_r1 = [ | |
0x10090288, 0x00000000, 0x00000000, 0x00000000, | |
0x00000101, 0x00000000, 0x00000000, 0x00000000, | |
0x00020401, 0x00000000, 0x00000000, 0x00000000, | |
0x40a04001, 0x00000000, 0x00000000, 0x00000000, | |
]; | |
assert_eq!(column_round(test_v1), test_r1) | |
} | |
#[test] | |
fn test_double_round() { | |
let test_v1 = [ | |
0x00000001, 0x00000000, 0x00000000, 0x00000000, | |
0x00000000, 0x00000000, 0x00000000, 0x00000000, | |
0x00000000, 0x00000000, 0x00000000, 0x00000000, | |
0x00000000, 0x00000000, 0x00000000, 0x00000000, | |
]; | |
let test_r1 = [ | |
0x8186a22d, 0x0040a284, 0x82479210, 0x06929051, | |
0x08000090, 0x02402200, 0x00004000, 0x00800000, | |
0x00010200, 0x20400000, 0x08008104, 0x00000000, | |
0x20500000, 0xa0000040, 0x0008180a, 0x612a8020, | |
]; | |
assert_eq!(double_round(test_v1), test_r1) | |
} | |
#[test] | |
fn test_little_endian() { | |
let test_v1 = [0, 0, 0, 0]; | |
assert_eq!(little_endian(test_v1), 0); | |
assert_eq!(little_endian_inv(0), test_v1); | |
let test_v2 = [86, 75, 30, 9]; | |
assert_eq!(little_endian(test_v2), 0x091e4b56); | |
assert_eq!(little_endian_inv(0x091e4b56), test_v2); | |
let test_v3 = [255, 255, 255, 250]; | |
assert_eq!(little_endian(test_v3), 0xfaffffff); | |
assert_eq!(little_endian_inv(0xfaffffff), test_v3); | |
} | |
#[test] | |
fn test_salsa20_hash() { | |
let test_v1 = [ | |
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | |
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | |
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | |
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | |
]; | |
let r1 = salsa20_hash(test_v1); | |
let mut r1_result = true; | |
for i in 0..64 { | |
if r1[i] != test_v1[i] { | |
r1_result = false; | |
} | |
} | |
assert_eq!(r1_result, true); | |
let test_v2 = [ | |
211,159, 13,115, 76, 55, 82,183, 3,117,222, 37,191,187,234,136, | |
49,237,179, 48, 1,106,178,219,175,199,166, 48, 86, 16,179,207, | |
31,240, 32, 63, 15, 83, 93,161,116,147, 48,113,238, 55,204, 36, | |
79,201,235, 79, 3, 81,156, 47,203, 26,244,243, 88,118,104, 54, | |
]; | |
let test_r2 = [ | |
109, 42,178,168,156,240,248,238,168,196,190,203, 26,110,170,154, | |
29, 29,150, 26,150, 30,235,249,190,163,251, 48, 69,144, 51, 57, | |
118, 40,152,157,180, 57, 27, 94,107, 42,236, 35, 27,111,114,114, | |
219,236,232,135,111,155,110, 18, 24,232, 95,158,179, 19, 48,202, | |
]; | |
let r2 = salsa20_hash(test_v2); | |
let mut r2_result = true; | |
for i in 0..64 { | |
if r2[i] != test_r2[i] { | |
r2_result = false; | |
} | |
} | |
assert_eq!(r2_result, true); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment