Skip to content

Instantly share code, notes, and snippets.

@et4te
Created October 5, 2017 19:25
Show Gist options
  • Save et4te/d59293bcd305268f4a8c4777ebeabf94 to your computer and use it in GitHub Desktop.
Save et4te/d59293bcd305268f4a8c4777ebeabf94 to your computer and use it in GitHub Desktop.
salsa20
#![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