Completely functional implementation with tests

This commit is contained in:
Sean Bowe 2015-12-28 00:45:11 -07:00
parent a0d56f3451
commit 4eac6417c3
5 changed files with 51 additions and 446 deletions

@ -108,30 +108,8 @@ fn keccakf(st: &mut [Chunk], rounds: usize)
} }
} }
fn temporary_shim(state: &mut [Byte]) {
assert_eq!(state.len(), 200);
let mut chunks = Vec::with_capacity(25);
for i in 0..25 {
chunks.push(Chunk::from(0x0000000000000000));
}
for (chunk_bit, input_bit) in chunks.iter_mut().flat_map(|c| c.bits.iter_mut())
.zip(state.iter().flat_map(|c| c.bits.iter()))
{
*chunk_bit = input_bit.clone();
}
keccakf(&mut chunks, 24);
for (chunk_bit, input_bit) in chunks.iter().flat_map(|c| c.bits.iter())
.zip(state.iter_mut().flat_map(|c| c.bits.iter_mut()))
{
*input_bit = chunk_bit.clone();
}
}
fn sha3_256(message: &[Byte]) -> Vec<Byte> { fn sha3_256(message: &[Byte]) -> Vec<Byte> {
// As defined by FIPS202
keccak(1088, 512, message, 0x06, 32) keccak(1088, 512, message, 0x06, 32)
} }
@ -191,36 +169,30 @@ fn keccak(rate: usize, capacity: usize, mut input: &[Byte], delimited_suffix: u8
output output
} }
fn keccak256(input: &[Byte]) -> Vec<Bit> { fn temporary_shim(state: &mut [Byte]) {
assert_eq!(input.len(), 144); assert_eq!(state.len(), 200);
let mut st: Vec<Chunk> = Some(Chunk::from(0)).into_iter().cycle().take(25).collect(); println!("RUNNING TEMPORARY SHIM!");
let mdlen = 32; // 256 bit let mut chunks = Vec::with_capacity(25);
let rsiz = 200 - 2 * mdlen; for i in 0..25 {
let rsizw = rsiz / 8; chunks.push(Chunk::from(0x0000000000000000));
for i in 0..rsizw {
let j = i * 8;
st[i] = st[i].xor(&Chunk::from(&input[j..(j+8)]));
} }
keccakf(&mut st, 24); for (chunk_bit, input_bit) in chunks.iter_mut().flat_map(|c| c.bits.iter_mut())
//.zip(state.iter().flat_map(|c| c.bits.iter()))
let mut v = vec![]; .zip(state.chunks(8).flat_map(|e| e.iter().rev()).flat_map(|c| c.bits.iter()))
for i in 0..4 { {
// due to endianness... *chunk_bit = input_bit.clone();
let tmp: Vec<_> = st[i].bits.chunks(8)
.rev()
.flat_map(|x| x.iter())
.map(|x| x.clone())
.collect();
v.extend_from_slice(&tmp);
} }
assert!(v.len() == 256); keccakf(&mut chunks, 24);
v for (chunk_bit, input_bit) in chunks.iter().flat_map(|c| c.bits.iter())
.zip(state.chunks_mut(8).flat_map(|e| e.iter_mut().rev()).flat_map(|c| c.bits.iter_mut()))
{
*input_bit = chunk_bit.clone();
}
} }
#[derive(Clone)] #[derive(Clone)]
@ -377,95 +349,51 @@ impl Bit {
} }
#[test] #[test]
fn test_shim() { fn test_sha3_256() {
let mut chunks: Vec<_> = (0..25).map(|_| Chunk::from(0xABCDEF0123456789)).collect(); let test_vector: Vec<(Vec<Byte>, [u8; 32])> = vec![
keccakf(&mut chunks, 24); (vec![Bit::byte(0x30)],
[0xf9,0xe2,0xea,0xaa,0x42,0xd9,0xfe,0x9e,0x55,0x8a,0x9b,0x8e,0xf1,0xbf,0x36,0x6f,0x19,0x0a,0xac,0xaa,0x83,0xba,0xd2,0x64,0x1e,0xe1,0x06,0xe9,0x04,0x10,0x96,0xe4]
),
(vec![Bit::byte(0x30),Bit::byte(0x30)],
[0x2e,0x16,0xaa,0xb4,0x83,0xcb,0x95,0x57,0x7c,0x50,0xd3,0x8c,0x8d,0x0d,0x70,0x40,0xf4,0x67,0x26,0x83,0x23,0x84,0x46,0xc9,0x90,0xba,0xbb,0xca,0x5a,0xe1,0x33,0xc8]
),
((0..64).map(|_| Bit::byte(0x30)).collect::<Vec<_>>(),
[0xc6,0xfd,0xd7,0xa7,0xf7,0x08,0x62,0xb3,0x6a,0x26,0xcc,0xd1,0x47,0x52,0x26,0x80,0x61,0xe9,0x81,0x03,0x29,0x9b,0x28,0xfe,0x77,0x63,0xbd,0x96,0x29,0x92,0x6f,0x4b]
),
((0..128).map(|_| Bit::byte(0x30)).collect::<Vec<_>>(),
[0x99,0x9d,0xb4,0xd4,0x28,0x7b,0x52,0x15,0x20,0x8d,0x11,0xe4,0x0a,0x27,0xca,0x54,0xac,0xa0,0x09,0xb2,0x5c,0x4f,0x7a,0xb9,0x1a,0xd8,0xaa,0x93,0x60,0xf0,0x63,0x71]
),
((0..256).map(|_| Bit::byte(0x30)).collect::<Vec<_>>(),
[0x11,0xea,0x74,0x37,0x7b,0x74,0xf1,0x53,0x9f,0x2e,0xd9,0x0a,0xb8,0xca,0x9e,0xb1,0xe0,0x70,0x8a,0x4b,0xfb,0xad,0x4e,0x81,0xcc,0x77,0xd9,0xa1,0x61,0x9a,0x10,0xdb]
),
((0..512).map(|_| Bit::byte(0x30)).collect::<Vec<_>>(),
[0x1c,0x80,0x1b,0x16,0x3a,0x2a,0xbe,0xd0,0xe8,0x07,0x1e,0x7f,0xf2,0x60,0x4e,0x98,0x11,0x22,0x80,0x54,0x14,0xf3,0xc8,0xfd,0x96,0x59,0x5d,0x7e,0xe1,0xd6,0x54,0xe2]
),
];
let mut bytes: Vec<Byte> = (0..200).map(|i| { for (i, &(ref message, ref expected)) in test_vector.iter().enumerate() {
match i % 8 { let result: Vec<u8> = sha3_256(message).into_iter().map(|a| a.grab()).collect();
0 => Bit::byte(0xAB),
1 => Bit::byte(0xCD),
2 => Bit::byte(0xEF),
3 => Bit::byte(0x01),
4 => Bit::byte(0x23),
5 => Bit::byte(0x45),
6 => Bit::byte(0x67),
7 => Bit::byte(0x89),
_ => unreachable!()
}
}).collect();
temporary_shim(&mut bytes); if &*result != expected {
print!("Expected: ");
for (i, bit) in bytes.iter().flat_map(|c| c.bits.iter()).enumerate() { for i in result.iter() {
//println!("i = {}", i); print!("0x{:02x},", i);
if &chunks[i / 64].bits[i % 64] != bit { }
panic!("fuck."); panic!("Hash {} failed!", i+1);
} else {
println!("--- HASH {} SUCCESS ---", i+1);
} }
} }
} }
#[test] #[test]
fn byte_grab_works() { fn test_keccakf() {
{
let b = Bit::byte(0xef);
assert_eq!(0xef, b.grab());
}
}
#[test]
fn woohoo() {
let message = [Bit::byte(0x30)];
let test = sha3_256(&message);
for i in 0..32 {
print!("{:02x} ", test[i].grab());
}
println!("");
panic!("fuck");
}
#[test]
fn testsha3() {
let bb = |x: usize| {
match x % 5 {
0 => Bit::byte(0xBB),
1 => Bit::byte(0x3B),
2 => Bit::byte(0x1B),
3 => Bit::byte(0x0B),
4 => Bit::byte(0xFF),
_ => unreachable!()
}
};
let msg: Vec<Byte> = (0..144).map(bb).collect();
let result = keccak256(&msg);
let correct_result: [u64; 4] =
[0x6746c5f4559bc1dd,
0x49d08e1adcf3be12,
0x80a2fcca8ce98789,
0x659f40a0053e2989
];
for i in 0..4 {
let j = i * 64;
let ours = Chunk::from(&result[j..(j+64)]);
let correct = Chunk::from(correct_result[i]);
assert!(ours == correct);
}
}
#[test]
fn testff() {
let base = Chunk::from(0xABCDEF0123456789); let base = Chunk::from(0xABCDEF0123456789);
let mut a: Vec<Chunk> = (0..25).map(|i| base.rotl(i*4)).collect(); let mut a: Vec<Chunk> = (0..25).map(|i| base.rotl(i*4)).collect();
keccakf(&mut a, 24); keccakf(&mut a, 24);
const TEST_VECTOR: [u64; 25] = [ const TEST_VECTOR: [u64; 25] = [
0x4c8948fcb6616044, 0x4c8948fcb6616044,
0x75642a21f8bd1299, 0x75642a21f8bd1299,

@ -1,24 +0,0 @@
# Makefile
# 19-Nov-11 Markku-Juhani O. Saarinen <mjos@iki.fi>
BINARY = kctest
OBJS = keccak.o main.o
DIST = readable_keccak
CC = gcc
CFLAGS = -Wall -O
LIBS =
LDFLAGS =
INCLUDES =
$(BINARY): $(OBJS)
$(CC) $(LDFLAGS) -o $(BINARY) $(OBJS) $(LIBS)
.c.o:
$(CC) $(CFLAGS) $(INCLUDES) -c $< -o $@
clean:
rm -rf $(DIST).tgz $(OBJS) $(BINARY) *~
dist: clean
cd ..; tar cfvz $(DIST)/$(DIST).tgz $(DIST)/*

@ -1,109 +0,0 @@
// keccak.c
// 19-Nov-11 Markku-Juhani O. Saarinen <mjos@iki.fi>
// A baseline Keccak (3rd round) implementation.
#include "keccak.h"
const uint64_t keccakf_rndc[24] =
{
0x0000000000000001, 0x0000000000008082, 0x800000000000808a,
0x8000000080008000, 0x000000000000808b, 0x0000000080000001,
0x8000000080008081, 0x8000000000008009, 0x000000000000008a,
0x0000000000000088, 0x0000000080008009, 0x000000008000000a,
0x000000008000808b, 0x800000000000008b, 0x8000000000008089,
0x8000000000008003, 0x8000000000008002, 0x8000000000000080,
0x000000000000800a, 0x800000008000000a, 0x8000000080008081,
0x8000000000008080, 0x0000000080000001, 0x8000000080008008
};
const int keccakf_rotc[24] =
{
1, 3, 6, 10, 15, 21, 28, 36, 45, 55, 2, 14,
27, 41, 56, 8, 25, 43, 62, 18, 39, 61, 20, 44
};
const int keccakf_piln[24] =
{
10, 7, 11, 17, 18, 3, 5, 16, 8, 21, 24, 4,
15, 23, 19, 13, 12, 2, 20, 14, 22, 9, 6, 1
};
// update the state with given number of rounds
void keccakf(uint64_t st[25], int rounds)
{
int i, j, round;
uint64_t t, bc[5];
for (round = 0; round < rounds; round++) {
// Theta
for (i = 0; i < 5; i++)
bc[i] = st[i] ^ st[i + 5] ^ st[i + 10] ^ st[i + 15] ^ st[i + 20];
for (i = 0; i < 5; i++) {
t = bc[(i + 4) % 5] ^ ROTL64(bc[(i + 1) % 5], 1);
for (j = 0; j < 25; j += 5)
st[j + i] ^= t;
}
// Rho Pi
t = st[1];
for (i = 0; i < 24; i++) {
j = keccakf_piln[i];
bc[0] = st[j];
st[j] = ROTL64(t, keccakf_rotc[i]);
t = bc[0];
}
// Chi
for (j = 0; j < 25; j += 5) {
for (i = 0; i < 5; i++)
bc[i] = st[j + i];
for (i = 0; i < 5; i++)
st[j + i] ^= (~bc[(i + 1) % 5]) & bc[(i + 2) % 5];
}
// Iota
st[0] ^= keccakf_rndc[round];
}
}
// compute a keccak hash (md) of given byte length from "in"
int keccak(const uint8_t *in, int inlen, uint8_t *md, int mdlen)
{
uint64_t st[25];
//uint8_t temp[144];
int i, rsiz, rsizw;
rsiz = 200 - 2 * mdlen;
rsizw = rsiz / 8;
memset(st, 0, sizeof(st));
/*
for ( ; inlen >= rsiz; inlen -= rsiz, in += rsiz) {
for (i = 0; i < rsizw; i++)
st[i] ^= ((uint64_t *) in)[i];
keccakf(st, KECCAK_ROUNDS);
}
// last block and padding
memcpy(temp, in, inlen);
temp[inlen++] = 1;
memset(temp + inlen, 0, rsiz - inlen);
temp[rsiz - 1] |= 0x80;
*/
for (i = 0; i < rsizw; i++) {
st[i] ^= ((uint64_t *) in)[i];
}
keccakf(st, KECCAK_ROUNDS);
memcpy(md, st, mdlen);
return 0;
}

@ -1,25 +0,0 @@
// keccak.h
// 19-Nov-11 Markku-Juhani O. Saarinen <mjos@iki.fi>
#ifndef KECCAK_H
#define KECCAK_H
#include <stdint.h>
#include <string.h>
#ifndef KECCAK_ROUNDS
#define KECCAK_ROUNDS 24
#endif
#ifndef ROTL64
#define ROTL64(x, y) (((x) << (y)) | ((x) >> (64 - (y))))
#endif
// compute a keccak hash (md) of given byte length from "in"
int keccak(const uint8_t *in, int inlen, uint8_t *md, int mdlen);
// update the state
void keccakf(uint64_t st[25], int norounds);
#endif

@ -1,165 +0,0 @@
// main.c
// 19-Nov-11 Markku-Juhani O. Saarinen <mjos@iki.fi>
#include <stdio.h>
#include <string.h>
#include "keccak.h"
#include <inttypes.h>
// test each length
typedef struct {
int mdlen;
char *msgstr;
uint8_t md[64];
} test_triplet_t;
// returns zero on success, nonzero + stderr messages on failure
int keccak_test()
{
test_triplet_t testvec[4] = {
{
28, "Keccak-224 Test Hash", {
0x30, 0x04, 0x5B, 0x34, 0x94, 0x6E, 0x1B, 0x2E,
0x09, 0x16, 0x13, 0x36, 0x2F, 0xD2, 0x2A, 0xA0,
0x8E, 0x2B, 0xEA, 0xFE, 0xC5, 0xE8, 0xDA, 0xEE,
0x42, 0xC2, 0xE6, 0x65 }
}, {
32, "Keccak-256 Test Hash", {
0xA8, 0xD7, 0x1B, 0x07, 0xF4, 0xAF, 0x26, 0xA4,
0xFF, 0x21, 0x02, 0x7F, 0x62, 0xFF, 0x60, 0x26,
0x7F, 0xF9, 0x55, 0xC9, 0x63, 0xF0, 0x42, 0xC4,
0x6D, 0xA5, 0x2E, 0xE3, 0xCF, 0xAF, 0x3D, 0x3C }
}, {
48, "Keccak-384 Test Hash", {
0xE2, 0x13, 0xFD, 0x74, 0xAF, 0x0C, 0x5F, 0xF9,
0x1B, 0x42, 0x3C, 0x8B, 0xCE, 0xEC, 0xD7, 0x01,
0xF8, 0xDD, 0x64, 0xEC, 0x18, 0xFD, 0x6F, 0x92,
0x60, 0xFC, 0x9E, 0xC1, 0xED, 0xBD, 0x22, 0x30,
0xA6, 0x90, 0x86, 0x65, 0xBC, 0xD9, 0xFB, 0xF4,
0x1A, 0x99, 0xA1, 0x8A, 0x7D, 0x9E, 0x44, 0x6E }
}, {
64, "Keccak-512 Test Hash", {
0x96, 0xEE, 0x47, 0x18, 0xDC, 0xBA, 0x3C, 0x74,
0x61, 0x9B, 0xA1, 0xFA, 0x7F, 0x57, 0xDF, 0xE7,
0x76, 0x9D, 0x3F, 0x66, 0x98, 0xA8, 0xB3, 0x3F,
0xA1, 0x01, 0x83, 0x89, 0x70, 0xA1, 0x31, 0xE6,
0x21, 0xCC, 0xFD, 0x05, 0xFE, 0xFF, 0xBC, 0x11,
0x80, 0xF2, 0x63, 0xC2, 0x7F, 0x1A, 0xDA, 0xB4,
0x60, 0x95, 0xD6, 0xF1, 0x25, 0x33, 0x14, 0x72,
0x4B, 0x5C, 0xBF, 0x78, 0x28, 0x65, 0x8E, 0x6A }
}
};
int i, fails;
uint8_t md[64];
fails = 0;
for (i = 0; i < 4; i++) {
keccak((uint8_t *) testvec[i].msgstr,
strlen(testvec[i].msgstr),
md, testvec[i].mdlen);
if (memcmp(md, testvec[i].md, testvec[i].mdlen)) {
fails++;
fprintf(stderr, "Keccak-%d FAILED.", testvec[i].mdlen * 8);
}
}
return fails;
}
// main
int main(int argc, char **argv)
{
/*
if (keccak_test() == 0)
printf("Keccak self-test OK!\n");
return 0;
*/
/*
uint8_t in[144] = {
0xBB, 0x3B, 0x1B, 0x0B, 0xFF,
0xBB, 0x3B, 0x1B, 0x0B, 0xFF,
0xBB, 0x3B, 0x1B, 0x0B, 0xFF,
0xBB, 0x3B, 0x1B, 0x0B, 0xFF,
0xBB, 0x3B, 0x1B, 0x0B, 0xFF,
0xBB, 0x3B, 0x1B, 0x0B, 0xFF,
0xBB, 0x3B, 0x1B, 0x0B, 0xFF,
0xBB, 0x3B, 0x1B, 0x0B, 0xFF,
0xBB, 0x3B, 0x1B, 0x0B, 0xFF,
0xBB, 0x3B, 0x1B, 0x0B, 0xFF,
0xBB, 0x3B, 0x1B, 0x0B, 0xFF,
0xBB, 0x3B, 0x1B, 0x0B, 0xFF,
0xBB, 0x3B, 0x1B, 0x0B, 0xFF,
0xBB, 0x3B, 0x1B, 0x0B, 0xFF,
0xBB, 0x3B, 0x1B, 0x0B, 0xFF,
0xBB, 0x3B, 0x1B, 0x0B, 0xFF,
0xBB, 0x3B, 0x1B, 0x0B, 0xFF,
0xBB, 0x3B, 0x1B, 0x0B, 0xFF,
0xBB, 0x3B, 0x1B, 0x0B, 0xFF,
0xBB, 0x3B, 0x1B, 0x0B, 0xFF,
0xBB, 0x3B, 0x1B, 0x0B, 0xFF,
0xBB, 0x3B, 0x1B, 0x0B, 0xFF,
0xBB, 0x3B, 0x1B, 0x0B, 0xFF,
0xBB, 0x3B, 0x1B, 0x0B, 0xFF,
0xBB, 0x3B, 0x1B, 0x0B, 0xFF,
0xBB, 0x3B, 0x1B, 0x0B, 0xFF,
0xBB, 0x3B, 0x1B, 0x0B, 0xFF,
0xBB, 0x3B, 0x1B, 0x0B, 0xFF,
0xBB, 0x3B, 0x1B, 0x0B
};
uint8_t md[32] = {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
};
keccak(in, 144, md, 32);
for (int i = 0; i < 32; i++) {
printf("%02x ", md[i]);
}
*/
uint64_t st[25] = {
0xabcdef0123456789,
0xbcdef0123456789a,
0xcdef0123456789ab,
0xdef0123456789abc,
0xef0123456789abcd,
0xf0123456789abcde,
0x0123456789abcdef,
0x123456789abcdef0,
0x23456789abcdef01,
0x3456789abcdef012,
0x456789abcdef0123,
0x56789abcdef01234,
0x6789abcdef012345,
0x789abcdef0123456,
0x89abcdef01234567,
0x9abcdef012345678,
0xabcdef0123456789,
0xbcdef0123456789a,
0xcdef0123456789ab,
0xdef0123456789abc,
0xef0123456789abcd,
0xf0123456789abcde,
0x0123456789abcdef,
0x123456789abcdef0,
0x23456789abcdef01,
};
keccakf(st, 24);
for (int i = 0; i < 25; i++) {
printf("%" PRIx64 "\n", st[i]);
}
}