Commit 0bc74386 by Alexandre Adomnicai Committed by Enrico Pozzobon

giftcofb128v1.opt32

parent 6d6bc5a2
#define CRYPTO_KEYBYTES 16
#define CRYPTO_NSECBYTES 0
#define CRYPTO_NPUBBYTES 16
#define CRYPTO_ABYTES 16
#define CRYPTO_NOOVERLAP 1
#ifndef COFB_H_
#define COFB_H_
#define DOUBLE_HALF_BLOCK(x) ({ \
tmp0 = (x)[0]; \
(x)[0] = (((x)[0] & 0x7f7f7f7f) << 1) | (((x)[0] & 0x80808080) >> 15); \
(x)[0] |= ((x)[1] & 0x80808080) << 17; \
(x)[1] = (((x)[1] & 0x7f7f7f7f) << 1) | (((x)[1] & 0x80808080) >> 15); \
(x)[1] ^= (((tmp0 >> 7) & 1) * 27) << 24; \
})
#define TRIPLE_HALF_BLOCK(x) ({ \
tmp0 = (x)[0]; \
tmp1 = (x)[1]; \
(x)[0] = (((x)[0] & 0x7f7f7f7f) << 1) | (((x)[0] & 0x80808080) >> 15); \
(x)[0] |= ((x)[1] & 0x80808080) << 17; \
(x)[1] = (((x)[1] & 0x7f7f7f7f) << 1) | (((x)[1] & 0x80808080) >> 15); \
(x)[1] ^= (((tmp0 >> 7) & 1) * 27) << 24; \
(x)[0] ^= tmp0; \
(x)[1] ^= tmp1; \
})
#define G(x) ({ \
tmp0 = (x)[0]; \
tmp1 = (x)[1]; \
(x)[0] = (x)[2]; \
(x)[1] = (x)[3]; \
(x)[2] = ((tmp0 & 0x7f7f7f7f) << 1) | ((tmp0 & 0x80808080) >> 15); \
(x)[2] |= ((tmp1 & 0x80808080) << 17); \
(x)[3] = ((tmp1 & 0x7f7f7f7f) << 1) | ((tmp1 & 0x80808080) >> 15); \
(x)[3] |= ((tmp0 & 0x80808080) << 17); \
})
#define XOR_BLOCK(x, y, z) ({ \
(x)[0] = (y)[0] ^ (z)[0]; \
(x)[1] = (y)[1] ^ (z)[1]; \
(x)[2] = (y)[2] ^ (z)[2]; \
(x)[3] = (y)[3] ^ (z)[3]; \
})
#define XOR_TOP_BAR_BLOCK(x, y) ({ \
(x)[0] ^= (y)[0]; \
(x)[1] ^= (y)[1]; \
})
#define RHO1(d, y, m, n) ({ \
G(y); \
padding(d,m,n); \
XOR_BLOCK(d, d, y); \
})
#define RHO(y, m, x, c, n) ({ \
XOR_BLOCK(c, y, m); \
RHO1(x, y, m, n); \
})
#define RHO_PRIME(y, c, x, m, n) ({ \
XOR_BLOCK(m, y, c); \
RHO1(x, y, m, n); \
})
#endif // COFB_H_
\ No newline at end of file
/*******************************************************************************
* Constant-time 32-bit implementation of the GIFT-COFB authenticated cipher.
*
* @author Alexandre Adomnicai, Nanyang Technological University,
* alexandre.adomnicai@ntu.edu.sg
* @date January 2020
*******************************************************************************/
#include <string.h> //for memcpy
#include "api.h"
#include "cofb.h"
#include "giftb128.h"
#define TAGBYTES CRYPTO_ABYTES
#define BLOCKBYTES CRYPTO_ABYTES
#define COFB_ENCRYPT 1
#define COFB_DECRYPT 0
/****************************************************************************
* 32-bit padding implementation.
****************************************************************************/
static inline void padding(u32* d, const u32* s, const u32 no_of_bytes){
u32 i;
if (no_of_bytes == 0) {
d[0] = 0x00000080; // little-endian
d[1] = 0x00000000;
d[2] = 0x00000000;
d[3] = 0x00000000;
}
else if (no_of_bytes < BLOCKBYTES) {
for (i = 0; i < no_of_bytes/4+1; i++)
d[i] = s[i];
d[i-1] &= ~(0xffffffffL << (no_of_bytes % 4)*8);
d[i-1] |= 0x00000080L << (no_of_bytes % 4)*8;
for (; i < 4; i++)
d[i] = 0x00000000;
}
else {
d[0] = s[0];
d[1] = s[1];
d[2] = s[2];
d[3] = s[3];
}
}
/****************************************************************************
* Constant-time implementation of the GIFT-COFB authenticated cipher based on
* fixsliced GIFTb-128. Encryption/decryption is handled by the same function,
* depending on the 'encrypting' parameter (1/0).
****************************************************************************/
int giftcofb_crypt(u8* out, const u8* key, const u8* nonce, const u8* ad,
u32 ad_len, const u8* in, u32 in_len, const int encrypting) {
u32 tmp0, tmp1, emptyA, emptyM;
u32 offset[2], input[4], rkey[80];
u8 Y[16];
if (!encrypting) {
if (in_len < TAGBYTES)
return -1;
in_len -= TAGBYTES;
}
if (ad_len == 0)
emptyA = 1;
else
emptyA = 0;
if (in_len == 0)
emptyM =1;
else
emptyM = 0;
precompute_rkeys(rkey, key);
giftb128(Y, nonce, rkey);
offset[0] = ((u32*)Y)[0];
offset[1] = ((u32*)Y)[1];
while (ad_len > BLOCKBYTES) {
RHO1(input, (u32*)Y, (u32*)ad, BLOCKBYTES);
DOUBLE_HALF_BLOCK(offset);
XOR_TOP_BAR_BLOCK(input, offset);
giftb128(Y, (u8*)input, rkey);
ad += BLOCKBYTES;
ad_len -= BLOCKBYTES;
}
TRIPLE_HALF_BLOCK(offset);
if ((ad_len % BLOCKBYTES != 0) || (emptyA))
TRIPLE_HALF_BLOCK(offset);
if (emptyM) {
TRIPLE_HALF_BLOCK(offset);
TRIPLE_HALF_BLOCK(offset);
}
RHO1(input, (u32*)Y, (u32*)ad, ad_len);
XOR_TOP_BAR_BLOCK(input, offset);
giftb128(Y, (u8*)input, rkey);
while (in_len > BLOCKBYTES) {
DOUBLE_HALF_BLOCK(offset);
if (encrypting)
RHO((u32*)Y, (u32*)in, input, (u32*)out, BLOCKBYTES);
else
RHO_PRIME((u32*)Y, (u32*)in, input, (u32*)out, BLOCKBYTES);
XOR_TOP_BAR_BLOCK(input, offset);
giftb128(Y, (u8*)input, rkey);
in += BLOCKBYTES;
out += BLOCKBYTES;
in_len -= BLOCKBYTES;
}
if (!emptyM) {
TRIPLE_HALF_BLOCK(offset);
if(in_len % BLOCKBYTES != 0)
TRIPLE_HALF_BLOCK(offset);
if (encrypting) {
RHO((u32*)Y, (u32*)in, input, (u32*)out, in_len);
out += in_len;
}
else {
RHO_PRIME((u32*)Y, (u32*)in, input, (u32*)out, in_len);
in += in_len;
}
XOR_TOP_BAR_BLOCK(input, offset);
giftb128(Y, (u8*)input, rkey);
}
if (encrypting) {
memcpy(out, Y, TAGBYTES);
return 0;
}
// decrypting
tmp0 = 0;
for(tmp1 = 0; tmp1 < TAGBYTES; tmp1++)
tmp0 |= in[tmp1] ^ Y[tmp1];
return tmp0;
}
/****************************************************************************
* API required by the NIST for the LWC competition.
****************************************************************************/
int crypto_aead_encrypt(unsigned char* c, unsigned long long* clen,
const unsigned char* m, unsigned long long mlen,
const unsigned char* ad, unsigned long long adlen,
const unsigned char* nsec, const unsigned char* npub,
const unsigned char* k) {
(void)nsec;
*clen = mlen + TAGBYTES;
return giftcofb_crypt(c, k, npub, ad, adlen, m, mlen, COFB_ENCRYPT);
}
/****************************************************************************
* API required by the NIST for the LWC competition.
****************************************************************************/
int crypto_aead_decrypt(unsigned char* m, unsigned long long *mlen,
unsigned char* nsec, const unsigned char* c,
unsigned long long clen, const unsigned char* ad,
unsigned long long adlen, const unsigned char* npub,
const unsigned char *k) {
(void)nsec;
*mlen = clen - TAGBYTES;
return giftcofb_crypt(m, k, npub, ad, adlen, c, clen, COFB_DECRYPT);
}
#ifndef ENDIAN_H_
#define ENDIAN_H_
#define U32BIG(x) \
((((x) & 0x000000FF) << 24) | (((x) & 0x0000FF00) << 8) | \
(((x) & 0x00FF0000) >> 8) | (((x) & 0xFF000000) >> 24))
#define U8BIG(x, y) \
(x)[0] = (y) >> 24; \
(x)[1] = ((y) >> 16) & 0xff; \
(x)[2] = ((y) >> 8) & 0xff; \
(x)[3] = (y) & 0xff;
#endif // ENDIAN_H_
\ No newline at end of file
/*******************************************************************************
* Optimized constant-time implementation of the GIFTb-128 block cipher.
*
* @author Alexandre Adomnicai, Nanyang Technological University,
* alexandre.adomnicai@ntu.edu.sg
*
* @date January 2020
*******************************************************************************/
#include "endian.h"
#include "giftb128.h"
#include "key_schedule.h"
/*****************************************************************************
* The round constants according to the fixsliced representation.
*****************************************************************************/
const u32 rconst[40] = {
0x10000008, 0x80018000, 0x54000002, 0x01010181,
0x8000001f, 0x10888880, 0x6001e000, 0x51500002,
0x03030180, 0x8000002f, 0x10088880, 0x60016000,
0x41500002, 0x03030080, 0x80000027, 0x10008880,
0x4001e000, 0x11500002, 0x03020180, 0x8000002b,
0x10080880, 0x60014000, 0x01400002, 0x02020080,
0x80000021, 0x10000080, 0x0001c000, 0x51000002,
0x03010180, 0x8000002e, 0x10088800, 0x60012000,
0x40500002, 0x01030080, 0x80000006, 0x10008808,
0xc001a000, 0x14500002, 0x01020181, 0x8000001a
};
/*****************************************************************************
* The first 20 rkeys are computed using the classical representation before
* being rearranged into fixsliced representations depending on round numbers.
* The 60 remaining rkeys are directly computed in fixscliced representations.
*****************************************************************************/
void precompute_rkeys(u32* rkey, const u8* key) {
u32 tmp;
//classical initialization
rkey[0] = U32BIG(((u32*)key)[3]);
rkey[1] = U32BIG(((u32*)key)[1]);
rkey[2] = U32BIG(((u32*)key)[2]);
rkey[3] = U32BIG(((u32*)key)[0]);
// classical keyschedule
for(int i = 0; i < 16; i+=2) {
rkey[i+4] = rkey[i+1];
rkey[i+5] = KEY_UPDATE(rkey[i]);
}
// transposition to fixsliced representations
for(int i = 0; i < 20; i+=10) {
rkey[i] = REARRANGE_RKEY_0(rkey[i]);
rkey[i + 1] = REARRANGE_RKEY_0(rkey[i + 1]);
rkey[i + 2] = REARRANGE_RKEY_1(rkey[i + 2]);
rkey[i + 3] = REARRANGE_RKEY_1(rkey[i + 3]);
rkey[i + 4] = REARRANGE_RKEY_2(rkey[i + 4]);
rkey[i + 5] = REARRANGE_RKEY_2(rkey[i + 5]);
rkey[i + 6] = REARRANGE_RKEY_3(rkey[i + 6]);
rkey[i + 7] = REARRANGE_RKEY_3(rkey[i + 7]);
}
// keyschedule according to fixsliced representations
for(int i = 20; i < 80; i+=10) {
rkey[i] = rkey[i-19];
rkey[i+1] = KEY_TRIPLE_UPDATE_0(rkey[i-20]);
rkey[i+2] = KEY_DOUBLE_UPDATE_1(rkey[i-17]);
rkey[i+3] = KEY_TRIPLE_UPDATE_1(rkey[i-18]);
rkey[i+4] = KEY_DOUBLE_UPDATE_2(rkey[i-15]);
rkey[i+5] = KEY_TRIPLE_UPDATE_2(rkey[i-16]);
rkey[i+6] = KEY_DOUBLE_UPDATE_3(rkey[i-13]);
rkey[i+7] = KEY_TRIPLE_UPDATE_3(rkey[i-14]);
rkey[i+8] = KEY_DOUBLE_UPDATE_4(rkey[i-11]);
rkey[i+9] = KEY_TRIPLE_UPDATE_4(rkey[i-12]);
SWAPMOVE(rkey[i], rkey[i], 0x00003333, 16);
SWAPMOVE(rkey[i], rkey[i], 0x55554444, 1);
SWAPMOVE(rkey[i+1], rkey[i+1], 0x55551100, 1);
}
}
/*****************************************************************************
* Encryption of a single 128-bit block with GIFTb-128 (used in GIFT-COFB).
*****************************************************************************/
void giftb128(u8* ctext, const u8* ptext, const u32* rkey) {
u32 tmp, state[4];
state[0] = U32BIG(((u32*)ptext)[0]);
state[1] = U32BIG(((u32*)ptext)[1]);
state[2] = U32BIG(((u32*)ptext)[2]);
state[3] = U32BIG(((u32*)ptext)[3]);
QUINTUPLE_ROUND(state, rkey, rconst);
QUINTUPLE_ROUND(state, rkey + 10, rconst + 5);
QUINTUPLE_ROUND(state, rkey + 20, rconst + 10);
QUINTUPLE_ROUND(state, rkey + 30, rconst + 15);
QUINTUPLE_ROUND(state, rkey + 40, rconst + 20);
QUINTUPLE_ROUND(state, rkey + 50, rconst + 25);
QUINTUPLE_ROUND(state, rkey + 60, rconst + 30);
QUINTUPLE_ROUND(state, rkey + 70, rconst + 35);
U8BIG(ctext, state[0]);
U8BIG(ctext + 4, state[1]);
U8BIG(ctext + 8, state[2]);
U8BIG(ctext + 12, state[3]);
}
#ifndef GIFT128_H_
#define GIFT128_H_
typedef unsigned char u8;
typedef unsigned int u32;
extern void precompute_rkeys(u32* rkeys, const u8* key);
extern void giftb128(u8* out, const u8* in, const u32* rkeys);
#define ROR(x,y) \
(((x) >> (y)) | ((x) << (32 - (y))))
#define BYTE_ROR_2(x) \
((((x) >> 2) & 0x3f3f3f3f) | (((x) & 0x03030303) << 6))
#define BYTE_ROR_4(x) \
((((x) >> 4) & 0x0f0f0f0f) | (((x) & 0x0f0f0f0f) << 4))
#define BYTE_ROR_6(x) \
((((x) >> 6) & 0x03030303) | (((x) & 0x3f3f3f3f) << 2))
#define HALF_ROR_4(x) \
((((x) >> 4) & 0x0fff0fff) | (((x) & 0x000f000f) << 12))
#define HALF_ROR_8(x) \
((((x) >> 8) & 0x00ff00ff) | (((x) & 0x00ff00ff) << 8))
#define HALF_ROR_12(x) \
((((x) >> 12)& 0x000f000f) | (((x) & 0x0fff0fff) << 4))
#define NIBBLE_ROR_1(x) \
((((x) >> 1) & 0x77777777) | (((x) & 0x11111111) << 3))
#define NIBBLE_ROR_2(x) \
((((x) >> 2) & 0x33333333) | (((x) & 0x33333333) << 2))
#define NIBBLE_ROR_3(x) \
((((x) >> 3) & 0x11111111) | (((x) & 0x77777777) << 1))
#define SWAPMOVE(a, b, mask, n) \
tmp = (b ^ (a >> n)) & mask; \
b ^= tmp; \
a ^= (tmp << n);
#define SBOX(s0, s1, s2, s3) \
s1 ^= s0 & s2; \
s0 ^= s1 & s3; \
s2 ^= s0 | s1; \
s3 ^= s2; \
s1 ^= s3; \
s3 ^= 0xffffffff; \
s2 ^= s0 & s1;
#define QUINTUPLE_ROUND(state, rkey, rconst) ({ \
SBOX(state[0], state[1], state[2], state[3]); \
state[3] = NIBBLE_ROR_1(state[3]); \
state[1] = NIBBLE_ROR_2(state[1]); \
state[2] = NIBBLE_ROR_3(state[2]); \
state[1] ^= (rkey)[0]; \
state[2] ^= (rkey)[1]; \
state[0] ^= (rconst)[0]; \
SBOX(state[3], state[1], state[2], state[0]); \
state[0] = HALF_ROR_4(state[0]); \
state[1] = HALF_ROR_8(state[1]); \
state[2] = HALF_ROR_12(state[2]); \
state[1] ^= (rkey)[2]; \
state[2] ^= (rkey)[3]; \
state[3] ^= (rconst)[1]; \
SBOX(state[0], state[1], state[2], state[3]); \
state[3] = ROR(state[3], 16); \
state[2] = ROR(state[2], 16); \
SWAPMOVE(state[1], state[1], 0x55555555, 1); \
SWAPMOVE(state[2], state[2], 0x00005555, 1); \
SWAPMOVE(state[3], state[3], 0x55550000, 1); \
state[1] ^= (rkey)[4]; \
state[2] ^= (rkey)[5]; \
state[0] ^= (rconst)[2]; \
SBOX(state[3], state[1], state[2], state[0]); \
state[0] = BYTE_ROR_6(state[0]); \
state[1] = BYTE_ROR_4(state[1]); \
state[2] = BYTE_ROR_2(state[2]); \
state[1] ^= (rkey)[6]; \
state[2] ^= (rkey)[7]; \
state[3] ^= (rconst)[3]; \
SBOX(state[0], state[1], state[2], state[3]); \
state[3] = ROR(state[3], 24); \
state[1] = ROR(state[1], 16); \
state[2] = ROR(state[2], 8); \
state[1] ^= (rkey)[8]; \
state[2] ^= (rkey)[9]; \
state[0] ^= (rconst)[4]; \
state[0] ^= state[3]; \
state[3] ^= state[0]; \
state[0] ^= state[3]; \
})
#endif // GIFT128_H_
\ No newline at end of file
#ifndef KEYSCHEDULE_H_
#define KEYSCHEDULE_H_
#define REARRANGE_RKEY_0(x) ({ \
SWAPMOVE(x, x, 0x00550055, 9); \
SWAPMOVE(x, x, 0x000f000f, 12); \
SWAPMOVE(x, x, 0x00003333, 18); \
SWAPMOVE(x, x, 0x000000ff, 24); \
})
#define REARRANGE_RKEY_1(x) ({ \
SWAPMOVE(x, x, 0x11111111, 3); \
SWAPMOVE(x, x, 0x03030303, 6); \
SWAPMOVE(x, x, 0x000f000f, 12); \
SWAPMOVE(x, x, 0x000000ff, 24); \
})
#define REARRANGE_RKEY_2(x) ({ \
SWAPMOVE(x, x, 0x0000aaaa, 15); \
SWAPMOVE(x, x, 0x00003333, 18); \
SWAPMOVE(x, x, 0x0000f0f0, 12); \
SWAPMOVE(x, x, 0x000000ff, 24); \
})
#define REARRANGE_RKEY_3(x) ({ \
SWAPMOVE(x, x, 0x0a0a0a0a, 3); \
SWAPMOVE(x, x, 0x00cc00cc, 6); \
SWAPMOVE(x, x, 0x0000f0f0, 12); \
SWAPMOVE(x, x, 0x000000ff, 24); \
})
#define KEY_UPDATE(x) \
(((x) >> 12) & 0x0000000f) | (((x) & 0x00000fff) << 4) | \
(((x) >> 2) & 0x3fff0000) | (((x) & 0x00030000) << 14)
#define KEY_TRIPLE_UPDATE_0(x) \
(ROR((x) & 0x33333333, 24) | ROR((x) & 0xcccccccc, 16))
#define KEY_DOUBLE_UPDATE_1(x) \
((((x) >> 4) & 0x0f000f00) | (((x) & 0x0f000f00) << 4) | \
(((x) >> 6) & 0x00030003) | (((x) & 0x003f003f) << 2))
#define KEY_TRIPLE_UPDATE_1(x) \
((((x) >> 6) & 0x03000300) | (((x) & 0x3f003f00) << 2) | \
(((x) >> 5) & 0x00070007) | (((x) & 0x001f001f) << 3))
#define KEY_DOUBLE_UPDATE_2(x) \
(ROR((x) & 0xaaaaaaaa, 24) | ROR((x) & 0x55555555, 16))
#define KEY_TRIPLE_UPDATE_2(x) \
(ROR((x) & 0x55555555, 24) | ROR((x) & 0xaaaaaaaa, 20))
#define KEY_DOUBLE_UPDATE_3(x) \
((((x) >> 2) & 0x03030303) | (((x) & 0x03030303) << 2) | \
(((x) >> 1) & 0x70707070) | (((x) & 0x10101010) << 3))
#define KEY_TRIPLE_UPDATE_3(x) \
((((x) >> 18) & 0x00003030) | (((x) & 0x01010101) << 3) | \
(((x) >> 14) & 0x0000c0c0) | (((x) & 0x0000e0e0) << 15)| \
(((x) >> 1) & 0x07070707) | (((x) & 0x00001010) << 19))
#define KEY_DOUBLE_UPDATE_4(x) \
((((x) >> 4) & 0x0fff0000) | (((x) & 0x000f0000) << 12) | \
(((x) >> 8) & 0x000000ff) | (((x) & 0x000000ff) << 8))
#define KEY_TRIPLE_UPDATE_4(x) \
((((x) >> 6) & 0x03ff0000) | (((x) & 0x003f0000) << 10) | \
(((x) >> 4) & 0x00000fff) | (((x) & 0x0000000f) << 12))
#endif // KEYSCHEDULE_H_
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment