From c6c3ef396a015f72d2ba9e75a9953390126c0d33 Mon Sep 17 00:00:00 2001 From: Joris van Rantwijk Date: Wed, 23 Nov 2016 23:38:51 +0100 Subject: [PATCH] Add C++ implementation of Trivium. --- refimpl/Makefile | 7 +- refimpl/ref_trivium.cpp | 172 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 177 insertions(+), 2 deletions(-) create mode 100644 refimpl/ref_trivium.cpp diff --git a/refimpl/Makefile b/refimpl/Makefile index 84b0a79..50b16d4 100644 --- a/refimpl/Makefile +++ b/refimpl/Makefile @@ -5,7 +5,7 @@ # .PHONY: all -all: ref_xoroshiro ref_mt19937 +all: ref_xoroshiro ref_mt19937 ref_trivium ref_xoroshiro: ref_xoroshiro.c $(CC) -std=c11 -Wall -O2 -o $@ $< @@ -13,7 +13,10 @@ ref_xoroshiro: ref_xoroshiro.c ref_mt19937: ref_mt19937.cpp $(CXX) -std=c++11 -Wall -O2 -o $@ $< +ref_trivium: ref_trivium.cpp + $(CXX) -std=c++11 -Wall -O2 -o $@ $< + .PHONY: clean clean: - $(RM) ref_xoroshiro ref_mt19937 + $(RM) ref_xoroshiro ref_mt19937 ref_trivium diff --git a/refimpl/ref_trivium.cpp b/refimpl/ref_trivium.cpp new file mode 100644 index 0000000..1c6d117 --- /dev/null +++ b/refimpl/ref_trivium.cpp @@ -0,0 +1,172 @@ +/* + * Reference implementation of "Trivium" in C++11. + * + * Written in 2016 by Joris van Rantwijk + * + * To the extent possible under law, the author has dedicated all copyright + * and related and neighboring rights to this software to the public domain + * worldwide. This software is distributed without any warranty. + * + * See + * + * NOTE: This is a very naive and slow implementation of Trivium, + * not suitable for practical use. + */ + +#include +#include + +struct trivium_state { + std::bitset<93> s1; + std::bitset<84> s2; + std::bitset<111> s3; +}; + +/* + * Generate one random bit and update state. + * + * Returns: one random bit, value 0 or 1. + */ +unsigned int trivium_step(struct trivium_state *state) +{ + unsigned int t1 = state->s1[65] ^ state->s1[92]; + unsigned int t2 = state->s2[68] ^ state->s2[83]; + unsigned int t3 = state->s3[65] ^ state->s3[110]; + + unsigned int z = t1 ^ t2 ^ t3; + + t1 ^= (state->s1[90] & state->s1[91]) ^ state->s2[77]; + t2 ^= (state->s2[81] & state->s2[82]) ^ state->s3[86]; + t3 ^= (state->s3[108] & state->s3[109]) ^ state->s1[68]; + + state->s1 <<= 1; + state->s1[0] = t3; + state->s2 <<= 1; + state->s2[0] = t1; + state->s3 <<= 1; + state->s3[0] = t2; + + return z; +} + +/* + * Initialize stream state with given key and IV. + * + * key: pointer to 10 bytes of key data. + * iv: pointer to 10 bytes of IV data. + */ +void trivium_init(struct trivium_state *state, + const unsigned char *key, + const unsigned char *iv) +{ + state->s1.reset(); + state->s2.reset(); + state->s3.reset(); + + /* + * NOTE: The least significant bit of the first byte of the key + * is mapped to s_80. The most significant bit of the last + * byte of the key is mapped to s_1. + * + * This is the same as the phase-3, API-compliant version + * of Trivium as published on the ECRYPT website (but different + * from the original submitted code.) + */ + for (unsigned int p = 0; p < 10; p++) { + for (unsigned int k = 0; k < 8; k++) { + state->s1[79-8*p-k] = ((key[p] >> k) & 1); + } + } + + /* + * NOTE: The least significant bit of the first byte of the IV + * is mapped to s_173. The most significant bit of the last + * byte of the key is mapped to s_94. + */ + for (unsigned int p = 0; p < 10; p++) { + for (unsigned int k = 0; k < 8; k++) { + state->s2[79-8*p-k] = ((iv[p] >> k) & 1); + } + } + + state->s3[108] = true; + state->s3[109] = true; + state->s3[110] = true; + + for (int i = 0; i < 4 * 288; i++) { + trivium_step(state); + } +} + +/* + * This is a small subset of the test vectors from + * the ECRYPT stream cipher project. + */ +static const struct testvec { + unsigned char key[10]; + unsigned char iv[10]; +} testvecs[5] = { + { { 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + { 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { { 0x00, 0x53, 0xA6, 0xF9, 0x4C, 0x9F, 0xF2, 0x45, 0x98, 0xEB }, + { 0x0D, 0x74, 0xDB, 0x42, 0xA9, 0x10, 0x77, 0xDE, 0x45, 0xAC } }, + { { 0x05, 0x58, 0xAB, 0xFE, 0x51, 0xA4, 0xF7, 0x4A, 0x9D, 0xF0 }, + { 0x16, 0x7D, 0xE4, 0x4B, 0xB2, 0x19, 0x80, 0xE7, 0x4E, 0xB5 } } +}; + + +int main(void) +{ + const unsigned int nvec = sizeof(testvecs) / sizeof(testvecs[0]); + struct trivium_state state; + + for (unsigned int i = 0; i < nvec; i++) { + + printf("key ="); + for (unsigned int p = 0; p < 10; p++) + printf(" %02x", testvecs[i].key[p]); + printf("\n"); + + printf("iv ="); + for (unsigned int p = 0; p < 10; p++) + printf(" %02x", testvecs[i].iv[p]); + printf("\n"); + + trivium_init(&state, testvecs[i].key, testvecs[i].iv); + + unsigned int np = 0; + for (unsigned int p = 0; p < 131072; p++) { + + // Generate 8 random bits. + // Map first-generated bit to least significant bit within byte; + // last-generated bit to most significant bit. + unsigned int t = 0; + for (unsigned int k = 0; k < 8; k++) { + t = (t >> 1) | (trivium_step(&state) << 7); + } + + // Write parts of the output to screen. + if (p == 0 || p == 448 || p == 131008) { + np = 64; + printf("data+%-6d =", p); + } else if (np > 0 && np % 16 == 0) { + printf(" "); + } + if (np > 0) { + printf(" %02x", t); + np--; + if (np % 16 == 0) { + printf("\n"); + } + } + } + printf("\n"); + } + + return 0; +} +