/* Spook Reference Implementation v1 * * Written in 2019 at UCLouvain (Belgium) by Olivier Bronchain, Gaetan Cassiers * and Charles Momin. * To the extent possible under law, the author(s) have dedicated all copyright * and related and neighboring rights to this software to the public domain * worldwide. This software is distributed without any warranty. * * You should have received a copy of the CC0 Public Domain Dedication along * with this software. If not, see * . */ #include #include #include "primitives.h" #include "utils.h" #define CLYDE_128_NS 6 // Number of steps #define CLYDE_128_NR 2 * CLYDE_128_NS // Number of rounds #define SHADOW_NS 6 // Number of steps #define SHADOW_NR 2 * SHADOW_NS // Number of rounds #define LS_ROWS 4 // Rows in the LS design #define LS_ROW_BYTES 4 // number of bytes per row in the LS design #define MLS_BUNDLES \ (SHADOW_NBYTES / (LS_ROWS * LS_ROW_BYTES)) // Bundles in the mLS design static void sbox_layer(uint32_t* state); static void sbox_layer_inv(uint32_t* state); static void lbox(uint32_t* x, uint32_t* y); static void lbox_inv(uint32_t* x, uint32_t* y); static void lbox_layer(uint32_t* state); static void lbox_layer_inv(uint32_t* state); static void bytes2state(uint32_t* state, const unsigned char* byte); static void state2bytes(unsigned char* bytes, const uint32_t* state); static void xor_ls_state(uint32_t* state, const uint32_t* x); static void add_rc(uint32_t state[LS_ROWS], unsigned int round); static void tweakey(unsigned char tk[3][CLYDE128_NBYTES], const unsigned char* k, const unsigned char* t); static uint32_t update_lfsr(uint32_t lfsr); static uint32_t xtime(uint32_t x); static void dbox_mls_layer(uint32_t state[MLS_BUNDLES][LS_ROWS]); // Round constants for Clyde-128 static const uint32_t clyde128_rc[CLYDE_128_NR][LS_ROWS] = { { 1, 0, 0, 0 }, // 0 { 0, 1, 0, 0 }, // 1 { 0, 0, 1, 0 }, // 2 { 0, 0, 0, 1 }, // 3 { 1, 1, 0, 0 }, // 4 { 0, 1, 1, 0 }, // 5 { 0, 0, 1, 1 }, // 6 { 1, 1, 0, 1 }, // 7 { 1, 0, 1, 0 }, // 8 { 0, 1, 0, 1 }, // 9 { 1, 1, 1, 0 }, // 10 { 0, 1, 1, 1 } // 11 }; static const uint32_t CST_LFSR_POLY_MASK = 0xc5; // Initial value of the constant generation polynomial // This is the result of applying the LFSR function 1024 times // the value 0x1. static const uint32_t CST_LFSR_INIT_VALUE = 0xf8737400; // Row on which to XOR the constant in Shadow Round A static const uint32_t SHADOW_RA_CST_ROW = 1; // Bundle on which to XOR the constant in Shadow Round B static const uint32_t SHADOW_RB_CST_BUNDLE = 0; // Apply a S-box layer to a Clyde-128 state. static void sbox_layer(uint32_t* state) { uint32_t y1 = (state[0] & state[1]) ^ state[2]; uint32_t y0 = (state[3] & state[0]) ^ state[1]; uint32_t y3 = (y1 & state[3]) ^ state[0]; uint32_t y2 = (y0 & y1) ^ state[3]; state[0] = y0; state[1] = y1; state[2] = y2; state[3] = y3; } // Apply a inverse S-box layer to a Clyde-128 state. static void sbox_layer_inv(uint32_t* state) { uint32_t y3 = (state[0] & state[1]) ^ state[2]; uint32_t y0 = (state[1] & y3) ^ state[3]; uint32_t y1 = (y3 & y0) ^ state[0]; uint32_t y2 = (y0 & y1) ^ state[1]; state[0] = y0; state[1] = y1; state[2] = y2; state[3] = y3; } // Apply a L-box to a pair of Clyde-128 rows. static void lbox(uint32_t* x, uint32_t* y) { uint32_t a, b, c, d; a = *x ^ rotr(*x, 12); b = *y ^ rotr(*y, 12); a = a ^ rotr(a, 3); b = b ^ rotr(b, 3); a = a ^ rotr(*x, 17); b = b ^ rotr(*y, 17); c = a ^ rotr(a, 31); d = b ^ rotr(b, 31); a = a ^ rotr(d, 26); b = b ^ rotr(c, 25); a = a ^ rotr(c, 15); b = b ^ rotr(d, 15); *x = a; *y = b; } // Apply a inverse L-box to a pair of Clyde-128 rows. static void lbox_inv(uint32_t* x, uint32_t* y) { uint32_t a, b, c, d; a = *x ^ rotr(*x, 25); b = *y ^ rotr(*y, 25); c = *x ^ rotr(a, 31); d = *y ^ rotr(b, 31); c = c ^ rotr(a, 20); d = d ^ rotr(b, 20); a = c ^ rotr(c, 31); b = d ^ rotr(d, 31); c = c ^ rotr(b, 26); d = d ^ rotr(a, 25); a = a ^ rotr(c, 17); b = b ^ rotr(d, 17); a = rotr(a, 16); b = rotr(b, 16); *x = a; *y = b; } // Apply a L-box layer to a Clyde-128 state. static void lbox_layer(uint32_t* state) { lbox(&state[0], &state[1]); lbox(&state[2], &state[3]); } // Apply inverse L-box layer to a Clyde-128 state. static void lbox_layer_inv(uint32_t* state) { lbox_inv(&state[0], &state[1]); lbox_inv(&state[2], &state[3]); } // Convert bytes to a Clyde-128 state. Bytes are in ordered by row (first-row // first), and in little-endian order inside a row. static void bytes2state(uint32_t* state, const unsigned char* bytes) { for (unsigned int row = 0; row < LS_ROWS; row++) { state[row] = le32u_dec(bytes + 4 * row); } } // Convert Clyde-128 state to bytes. Bytes are in ordered by row (first-row // first), and in little-endian order inside a row. static void state2bytes(unsigned char* bytes, const uint32_t* state) { for (unsigned int row = 0; row < LS_ROWS; row++) { le32u_enc(bytes + 4 * row, state[row]); } } // XOR the Clyde-128 state x into state. static void xor_ls_state(uint32_t* state, const uint32_t* x) { for (unsigned int i = 0; i < LS_ROWS; i++) { state[i] ^= x[i]; } } // XOR the Clyde-128 round constant of given round into state, left shifting // each constant by shift. static void add_rc(uint32_t state[LS_ROWS], unsigned int round) { for (unsigned int i = 0; i < LS_ROWS; i++) { state[i] ^= clyde128_rc[round][i]; } } // Key schedule for Clyde-128. Generate 3 Clyde-128 states from key k and tweak // t. static void tweakey(unsigned char tk[3][CLYDE128_NBYTES], const unsigned char* k, const unsigned char* t) { const unsigned char* t0 = t; const unsigned char* t1 = t + CLYDE128_NBYTES / 2; unsigned char tx[CLYDE128_NBYTES / 2]; xor_bytes(tx, t0, t1, CLYDE128_NBYTES / 2); // TK[0] xor_bytes(tk[0], k, t, CLYDE128_NBYTES); // TK[1] xor_bytes(tk[1], k, tx, CLYDE128_NBYTES / 2); xor_bytes(tk[1] + CLYDE128_NBYTES / 2, k + CLYDE128_NBYTES / 2, t0, CLYDE128_NBYTES / 2); // TK[2] xor_bytes(tk[2], k, t1, CLYDE128_NBYTES / 2); xor_bytes(tk[2] + CLYDE128_NBYTES / 2, k + CLYDE128_NBYTES / 2, tx, CLYDE128_NBYTES / 2); } // Update (by 1 step) the constant generation LFSR static uint32_t update_lfsr(uint32_t lfsr) { // Arithmetic shift left, equivalent to // uint32_t b_out_ext = (lfsr & 0x80000000) ? 0xffffffff : 0x0; // but constant-time. uint32_t b_out_ext = (uint32_t)(((int32_t)lfsr) >> 31); return (lfsr << 1) ^ (b_out_ext & CST_LFSR_POLY_MASK); } // Multiplication by polynomial x modulo x^32+x^8+1 static uint32_t xtime(uint32_t x) { uint32_t b = x >> 31; return (x << 1) ^ b ^ (b << 8); } // Apply a D-box layer to a Shadow state. static void dbox_mls_layer(uint32_t state[MLS_BUNDLES][LS_ROWS]) { for (unsigned int row = 0; row < LS_ROWS; row++) { #if SMALL_PERM uint32_t x0 = state[0][row]; uint32_t x1 = state[1][row]; uint32_t x2 = state[2][row]; uint32_t a = x0 ^ x1; uint32_t b = x0 ^ x2; uint32_t c = x1 ^ b; uint32_t d = a ^ xtime(b); state[0][row] = b ^ d; state[1][row] = c; state[2][row] = d; #else state[0][row] ^= state[1][row]; state[2][row] ^= state[3][row]; state[1][row] ^= state[2][row]; state[3][row] ^= xtime(state[0][row]); state[1][row] = xtime(state[1][row]); state[0][row] ^= state[1][row]; state[2][row] ^= xtime(state[3][row]); state[1][row] ^= state[2][row]; state[3][row] ^= state[0][row]; #endif // SMALL_PERM } } // Clyde-128 TBC. // Output in buffer c the TBC for block m, tweak t and key k. // All buffers have length CLYDE128_NBYTES. void clyde128_encrypt(unsigned char* c, const unsigned char* m, const unsigned char* t, const unsigned char* k) { // Key schedule unsigned char tkb[3][CLYDE128_NBYTES]; uint32_t tk[3][LS_ROWS]; tweakey(tkb, k, t); bytes2state(tk[0], tkb[0]); bytes2state(tk[1], tkb[1]); bytes2state(tk[2], tkb[2]); // Datapath uint32_t state[LS_ROWS]; bytes2state(state, m); xor_ls_state(state, tk[0]); for (unsigned int s = 0; s < CLYDE_128_NS; s++) { for (unsigned int rho = 0; rho < 2; rho++) { unsigned int r = 2 * s + rho; sbox_layer(state); lbox_layer(state); add_rc(state, r); } xor_ls_state(state, tk[(s + 1) % 3]); } state2bytes(c, state); } // Clyde-128 inverse TBC. // Output in buffer m the inverse TBC for block c, tweak t and key k. // All buffers have length CLYDE128_NBYTES. void clyde128_decrypt(unsigned char* m, const unsigned char* c, const unsigned char* t, const unsigned char* k) { // Key schedule unsigned char tkb[3][CLYDE128_NBYTES]; uint32_t tk[3][LS_ROWS]; tweakey(tkb, k, t); bytes2state(tk[0], tkb[0]); bytes2state(tk[1], tkb[1]); bytes2state(tk[2], tkb[2]); // Datapath uint32_t state[LS_ROWS]; bytes2state(state, c); for (int s = CLYDE_128_NS - 1; s >= 0; s--) { xor_ls_state(state, tk[(s + 1) % 3]); for (int rho = 1; rho >= 0; rho--) { unsigned int r = 2 * s + rho; add_rc(state, r); lbox_layer_inv(state); sbox_layer_inv(state); } } xor_ls_state(state, tk[0]); state2bytes(m, state); } // Shadow permutation. Updates x (array of SHADOW_NBYTES bytes). void shadow(unsigned char* x) { uint32_t state[MLS_BUNDLES][LS_ROWS]; uint32_t lfsr = CST_LFSR_INIT_VALUE; for (unsigned int b = 0; b < MLS_BUNDLES; b++) { bytes2state(state[b], x + (b * SHADOW_NBYTES / MLS_BUNDLES)); } for (unsigned int s = 0; s < SHADOW_NS; s++) { for (unsigned int b = 0; b < MLS_BUNDLES; b++) { sbox_layer(state[b]); lbox_layer(state[b]); state[b][SHADOW_RA_CST_ROW] ^= lfsr; lfsr = update_lfsr(lfsr); sbox_layer(state[b]); } dbox_mls_layer(state); for (unsigned int row = 0; row < LS_ROWS; row++) { state[SHADOW_RB_CST_BUNDLE][row] ^= lfsr; lfsr = update_lfsr(lfsr); } } for (unsigned int b = 0; b < MLS_BUNDLES; b++) { state2bytes(x + (b * SHADOW_NBYTES / MLS_BUNDLES), state[b]); } }