Commit 32c03519 by Christoph Dobraunig Committed by Enrico Pozzobon

ascon lowsize

parent 7090c60d
#define CRYPTO_KEYBYTES 16
#define CRYPTO_NSECBYTES 0
#define CRYPTO_NPUBBYTES 16
#define CRYPTO_ABYTES 16
#define CRYPTO_NOOVERLAP 1
#include "core.h"
void process_data(state* s, unsigned char* out, const unsigned char* in,
unsigned long long len, u8 mode) {
u32_2 t0, t1;
u64 tmp0, tmp1;
u64 i;
while (len >= RATE) {
tmp0 = U64BIG(*(u64*)in);
t0 = to_bit_interleaving(tmp0);
s->x0.e ^= t0.e;
s->x0.o ^= t0.o;
tmp1 = U64BIG(*(u64*)(in + 8));
t1 = to_bit_interleaving(tmp1);
s->x1.e ^= t1.e;
s->x1.o ^= t1.o;
if (mode != ASCON_AD) {
tmp0 = from_bit_interleaving(s->x0);
*(u64*)out = U64BIG(tmp0);
tmp1 = from_bit_interleaving(s->x1);
*(u64*)(out + 8) = U64BIG(tmp1);
}
if (mode == ASCON_DEC) {
s->x0 = t0;
s->x1 = t1;
}
P(s, PB_ROUNDS);
in += RATE;
out += RATE;
len -= RATE;
}
tmp0 = 0;
tmp1 = 0;
for (i = 0; i < len; ++i, ++in)
if (i < 8)
tmp0 ^= INS_BYTE64(*in, i);
else
tmp1 ^= INS_BYTE64(*in, i % 8);
in -= len;
if (len < 8)
tmp0 ^= INS_BYTE64(0x80, len);
else
tmp1 ^= INS_BYTE64(0x80, len % 8);
t0 = to_bit_interleaving(tmp0);
s->x0.e ^= t0.e;
s->x0.o ^= t0.o;
t1 = to_bit_interleaving(tmp1);
s->x1.e ^= t1.e;
s->x1.o ^= t1.o;
if (mode != ASCON_AD) {
tmp0 = from_bit_interleaving(s->x0);
tmp1 = from_bit_interleaving(s->x1);
for (i = 0; i < len; ++i, ++out)
if (i < 8)
*out = EXT_BYTE64(tmp0, i);
else
*out = EXT_BYTE64(tmp1, i % 8);
}
if (mode == ASCON_DEC) {
for (i = 0; i < len; ++i, ++in)
if (i < 8) {
tmp0 &= ~INS_BYTE64(0xff, i);
tmp0 |= INS_BYTE64(*in, i);
} else {
tmp1 &= ~INS_BYTE64(0xff, i % 8);
tmp1 |= INS_BYTE64(*in, i % 8);
}
s->x0 = to_bit_interleaving(tmp0);
s->x1 = to_bit_interleaving(tmp1);
}
}
void ascon_core(state* s, unsigned char* out, const unsigned char* in,
unsigned long long tlen, const unsigned char* ad,
unsigned long long adlen, const unsigned char* npub,
const unsigned char* k, u8 mode) {
u32_2 K0, K1, N0, N1;
// load key and nonce
K0 = to_bit_interleaving(U64BIG(*(u64*)k));
K1 = to_bit_interleaving(U64BIG(*(u64*)(k + 8)));
N0 = to_bit_interleaving(U64BIG(*(u64*)npub));
N1 = to_bit_interleaving(U64BIG(*(u64*)(npub + 8)));
// initialization
s->x0 = to_bit_interleaving(IV);
s->x1.o = K0.o;
s->x1.e = K0.e;
s->x2.e = K1.e;
s->x2.o = K1.o;
s->x3.e = N0.e;
s->x3.o = N0.o;
s->x4.e = N1.e;
s->x4.o = N1.o;
P(s, PA_ROUNDS);
s->x3.e ^= K0.e;
s->x3.o ^= K0.o;
s->x4.e ^= K1.e;
s->x4.o ^= K1.o;
// process associated data
if (adlen) {
process_data(s, (void*)0, ad, adlen, ASCON_AD);
P(s, PB_ROUNDS);
}
s->x4.e ^= 1;
// process plaintext/ciphertext
process_data(s, out, in, tlen, mode);
// finalization
s->x2.e ^= K0.e;
s->x2.o ^= K0.o;
s->x3.e ^= K1.e;
s->x3.o ^= K1.o;
P(s, PA_ROUNDS);
s->x3.e ^= K0.e;
s->x3.o ^= K0.o;
s->x4.e ^= K1.e;
s->x4.o ^= K1.o;
}
#ifndef CORE_H_
#define CORE_H_
#include "api.h"
#include "endian.h"
#include "permutations.h"
#define ASCON_AD 0
#define ASCON_ENC 1
#define ASCON_DEC 2
#define RATE (128 / 8)
#define PA_ROUNDS 12
#define PB_ROUNDS 8
#define IV \
((u64)(8 * (CRYPTO_KEYBYTES)) << 56 | (u64)(8 * (RATE)) << 48 | \
(u64)(PA_ROUNDS) << 40 | (u64)(PB_ROUNDS) << 32)
void process_data(state* s, unsigned char* out, const unsigned char* in,
unsigned long long len, u8 mode);
void ascon_core(state* s, unsigned char* out, const unsigned char* in,
unsigned long long tlen, const unsigned char* ad,
unsigned long long adlen, const unsigned char* npub,
const unsigned char* k, u8 mode);
#endif // CORE_H_
#include "core.h"
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) {
if (clen < CRYPTO_ABYTES) {
*mlen = 0;
return -1;
}
state s;
u32_2 t0, t1;
(void)nsec;
// set plaintext size
*mlen = clen - CRYPTO_ABYTES;
ascon_core(&s, m, c, *mlen, ad, adlen, npub, k, ASCON_DEC);
// verify tag (should be constant time, check compiler output)
t0 = to_bit_interleaving(U64BIG(*(u64*)(c + *mlen)));
t1 = to_bit_interleaving(U64BIG(*(u64*)(c + *mlen + 8)));
if (((s.x3.e ^ t0.e) | (s.x3.o ^ t0.o) | (s.x4.e ^ t1.e) | (s.x4.o ^ t1.o)) !=
0) {
*mlen = 0;
return -1;
}
return 0;
}
#include "core.h"
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) {
state s;
u64 tmp0, tmp1;
(void)nsec;
// set ciphertext size
*clen = mlen + CRYPTO_ABYTES;
ascon_core(&s, c, m, mlen, ad, adlen, npub, k, ASCON_ENC);
// set tag
tmp0 = from_bit_interleaving(s.x3);
*(u64*)(c + mlen) = U64BIG(tmp0);
tmp1 = from_bit_interleaving(s.x4);
*(u64*)(c + mlen + 8) = U64BIG(tmp1);
return 0;
}
#ifndef ENDIAN_H_
#define ENDIAN_H_
#if defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
// macros for big endian machines
#define U64BIG(x) (x)
#define U32BIG(x) (x)
#define U16BIG(x) (x)
#elif defined(_MSC_VER) || \
(defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)
// macros for little endian machines
#define U64BIG(x) \
((((x)&0x00000000000000FFULL) << 56) | (((x)&0x000000000000FF00ULL) << 40) | \
(((x)&0x0000000000FF0000ULL) << 24) | (((x)&0x00000000FF000000ULL) << 8) | \
(((x)&0x000000FF00000000ULL) >> 8) | (((x)&0x0000FF0000000000ULL) >> 24) | \
(((x)&0x00FF000000000000ULL) >> 40) | (((x)&0xFF00000000000000ULL) >> 56))
#define U32BIG(x) \
((((x)&0x000000FF) << 24) | (((x)&0x0000FF00) << 8) | \
(((x)&0x00FF0000) >> 8) | (((x)&0xFF000000) >> 24))
#define U16BIG(x) ((((x)&0x00FF) << 8) | (((x)&0xFF00) >> 8))
#else
#error "ascon byte order macros not defined in endian.h"
#endif
#endif // ENDIAN_H_
#include "permutations.h"
static const u8 constants[][2] = {
{0xc, 0xc}, {0x9, 0xc}, {0xc, 0x9}, {0x9, 0x9}, {0x6, 0xc}, {0x3, 0xc},
{0x6, 0x9}, {0x3, 0x9}, {0xc, 0x6}, {0x9, 0x6}, {0xc, 0x3}, {0x9, 0x3}};
// Credit to Henry S. Warren, Hacker's Delight, Addison-Wesley, 2002
u32_2 to_bit_interleaving(u64 in) {
u32 hi = (in) >> 32;
u32 lo = (u32)(in);
u32 r0, r1;
u32_2 out;
r0 = (lo ^ (lo >> 1)) & 0x22222222, lo ^= r0 ^ (r0 << 1);
r0 = (lo ^ (lo >> 2)) & 0x0C0C0C0C, lo ^= r0 ^ (r0 << 2);
r0 = (lo ^ (lo >> 4)) & 0x00F000F0, lo ^= r0 ^ (r0 << 4);
r0 = (lo ^ (lo >> 8)) & 0x0000FF00, lo ^= r0 ^ (r0 << 8);
r1 = (hi ^ (hi >> 1)) & 0x22222222, hi ^= r1 ^ (r1 << 1);
r1 = (hi ^ (hi >> 2)) & 0x0C0C0C0C, hi ^= r1 ^ (r1 << 2);
r1 = (hi ^ (hi >> 4)) & 0x00F000F0, hi ^= r1 ^ (r1 << 4);
r1 = (hi ^ (hi >> 8)) & 0x0000FF00, hi ^= r1 ^ (r1 << 8);
out.e = (lo & 0x0000FFFF) | (hi << 16);
out.o = (lo >> 16) | (hi & 0xFFFF0000);
return out;
}
// Credit to Henry S. Warren, Hacker's Delight, Addison-Wesley, 2002
u64 from_bit_interleaving(u32_2 in) {
u32 lo = (in.e & 0x0000FFFF) | (in.o << 16);
u32 hi = (in.e >> 16) | (in.o & 0xFFFF0000);
u32 r0, r1;
u64 out;
r0 = (lo ^ (lo >> 8)) & 0x0000FF00, lo ^= r0 ^ (r0 << 8);
r0 = (lo ^ (lo >> 4)) & 0x00F000F0, lo ^= r0 ^ (r0 << 4);
r0 = (lo ^ (lo >> 2)) & 0x0C0C0C0C, lo ^= r0 ^ (r0 << 2);
r0 = (lo ^ (lo >> 1)) & 0x22222222, lo ^= r0 ^ (r0 << 1);
r1 = (hi ^ (hi >> 8)) & 0x0000FF00, hi ^= r1 ^ (r1 << 8);
r1 = (hi ^ (hi >> 4)) & 0x00F000F0, hi ^= r1 ^ (r1 << 4);
r1 = (hi ^ (hi >> 2)) & 0x0C0C0C0C, hi ^= r1 ^ (r1 << 2);
r1 = (hi ^ (hi >> 1)) & 0x22222222, hi ^= r1 ^ (r1 << 1);
out = (u64)hi << 32 | lo;
return out;
}
void P(state *p, u8 rounds) {
state s = *p;
u32_2 t0, t1, t2, t3, t4;
u32 i, start = START_ROUND(rounds);
for (i = start; i < 12; i++) ROUND(constants[i][0], constants[i][1]);
*p = s;
}
#ifndef PERMUTATIONS_H_
#define PERMUTATIONS_H_
typedef unsigned char u8;
typedef unsigned int u32;
typedef unsigned long long u64;
typedef struct {
u32 e;
u32 o;
} u32_2;
typedef struct {
u32_2 x0;
u32_2 x1;
u32_2 x2;
u32_2 x3;
u32_2 x4;
} state;
#define EXT_BYTE64(x, n) ((u8)((u64)(x) >> (8 * (7 - (n)))))
#define INS_BYTE64(x, n) ((u64)(x) << (8 * (7 - (n))))
#define ROTR32(x, n) (((x) >> (n)) | ((x) << (32 - (n))))
#define START_ROUND(x) (12 - (x))
// Credit to Henry S. Warren, Hacker's Delight, Addison-Wesley, 2002
u32_2 to_bit_interleaving(u64 in);
// Credit to Henry S. Warren, Hacker's Delight, Addison-Wesley, 2002
u64 from_bit_interleaving(u32_2 in);
/* clang-format off */
#define ROUND(C_e, C_o) \
do { \
/* round constant */ \
s.x2.e ^= C_e; s.x2.o ^= C_o; \
/* s-box layer */ \
s.x0.e ^= s.x4.e; s.x0.o ^= s.x4.o; \
s.x4.e ^= s.x3.e; s.x4.o ^= s.x3.o; \
s.x2.e ^= s.x1.e; s.x2.o ^= s.x1.o; \
t0.e = s.x0.e; t0.o = s.x0.o; \
t4.e = s.x4.e; t4.o = s.x4.o; \
t3.e = s.x3.e; t3.o = s.x3.o; \
t1.e = s.x1.e; t1.o = s.x1.o; \
t2.e = s.x2.e; t2.o = s.x2.o; \
s.x0.e = t0.e ^ (~t1.e & t2.e); s.x0.o = t0.o ^ (~t1.o & t2.o); \
s.x2.e = t2.e ^ (~t3.e & t4.e); s.x2.o = t2.o ^ (~t3.o & t4.o); \
s.x4.e = t4.e ^ (~t0.e & t1.e); s.x4.o = t4.o ^ (~t0.o & t1.o); \
s.x1.e = t1.e ^ (~t2.e & t3.e); s.x1.o = t1.o ^ (~t2.o & t3.o); \
s.x3.e = t3.e ^ (~t4.e & t0.e); s.x3.o = t3.o ^ (~t4.o & t0.o); \
s.x1.e ^= s.x0.e; s.x1.o ^= s.x0.o; \
s.x3.e ^= s.x2.e; s.x3.o ^= s.x2.o; \
s.x0.e ^= s.x4.e; s.x0.o ^= s.x4.o; \
/* linear layer */ \
t0.e = s.x0.e ^ ROTR32(s.x0.o, 4); t0.o = s.x0.o ^ ROTR32(s.x0.e, 5); \
t1.e = s.x1.e ^ ROTR32(s.x1.e, 11); t1.o = s.x1.o ^ ROTR32(s.x1.o, 11); \
t2.e = s.x2.e ^ ROTR32(s.x2.o, 2); t2.o = s.x2.o ^ ROTR32(s.x2.e, 3); \
t3.e = s.x3.e ^ ROTR32(s.x3.o, 3); t3.o = s.x3.o ^ ROTR32(s.x3.e, 4); \
t4.e = s.x4.e ^ ROTR32(s.x4.e, 17); t4.o = s.x4.o ^ ROTR32(s.x4.o, 17); \
s.x0.e ^= ROTR32(t0.o, 9); s.x0.o ^= ROTR32(t0.e, 10); \
s.x1.e ^= ROTR32(t1.o, 19); s.x1.o ^= ROTR32(t1.e, 20); \
s.x2.e ^= t2.o; s.x2.o ^= ROTR32(t2.e, 1); \
s.x3.e ^= ROTR32(t3.e, 5); s.x3.o ^= ROTR32(t3.o, 5); \
s.x4.e ^= ROTR32(t4.o, 3); s.x4.o ^= ROTR32(t4.e, 4); \
s.x2.e = ~s.x2.e; s.x2.o = ~s.x2.o; \
} while(0)
/* clang-format on */
void P(state *p, u8 rounds);
#endif // PERMUTATIONS_H_
#define CRYPTO_KEYBYTES 16
#define CRYPTO_NSECBYTES 0
#define CRYPTO_NPUBBYTES 16
#define CRYPTO_ABYTES 16
#define CRYPTO_NOOVERLAP 1
#include "core.h"
void process_data(state* s, unsigned char* out, const unsigned char* in,
unsigned long long len, u8 mode) {
u64* x;
u64 i;
while (len >= RATE) {
s->x0 ^= U64BIG(*(u64*)in);
s->x1 ^= U64BIG(*(u64*)(in + 8));
if (mode != ASCON_AD) {
*(u64*)out = U64BIG(s->x0);
*(u64*)(out + 8) = U64BIG(s->x1);
}
if (mode == ASCON_DEC) {
s->x0 = U64BIG(*((u64*)in));
s->x1 = U64BIG(*((u64*)(in + 8)));
}
P(s, PB_ROUNDS);
in += RATE;
out += RATE;
len -= RATE;
}
for (i = 0; i < len; ++i, ++out, ++in) {
if (i < 8)
x = &(s->x0);
else
x = &(s->x1);
*x ^= INS_BYTE64(*in, i % 8);
if (mode != ASCON_AD) *out = EXT_BYTE64(*x, i % 8);
if (mode == ASCON_DEC) {
*x &= ~INS_BYTE64(0xff, i % 8);
*x |= INS_BYTE64(*in, i % 8);
}
}
if (len < 8)
s->x0 ^= INS_BYTE64(0x80, len);
else
s->x1 ^= INS_BYTE64(0x80, len % 8);
}
void ascon_core(state* s, unsigned char* out, const unsigned char* in,
unsigned long long tlen, const unsigned char* ad,
unsigned long long adlen, const unsigned char* npub,
const unsigned char* k, u8 mode) {
const u64 K0 = U64BIG(*(u64*)k);
const u64 K1 = U64BIG(*(u64*)(k + 8));
const u64 N0 = U64BIG(*(u64*)npub);
const u64 N1 = U64BIG(*(u64*)(npub + 8));
// initialization
s->x0 = IV;
s->x1 = K0;
s->x2 = K1;
s->x3 = N0;
s->x4 = N1;
P(s, PA_ROUNDS);
s->x3 ^= K0;
s->x4 ^= K1;
// process associated data
if (adlen) {
process_data(s, (void*)0, ad, adlen, ASCON_AD);
P(s, PB_ROUNDS);
}
s->x4 ^= 1;
// process plaintext/ciphertext
process_data(s, out, in, tlen, mode);
// finalization
s->x2 ^= K0;
s->x3 ^= K1;
P(s, PA_ROUNDS);
s->x3 ^= K0;
s->x4 ^= K1;
}
#ifndef CORE_H_
#define CORE_H_
#include "api.h"
#include "endian.h"
#include "permutations.h"
#define ASCON_AD 0
#define ASCON_ENC 1
#define ASCON_DEC 2
#define RATE (128 / 8)
#define PA_ROUNDS 12
#define PB_ROUNDS 8
#define IV \
((u64)(8 * (CRYPTO_KEYBYTES)) << 56 | (u64)(8 * (RATE)) << 48 | \
(u64)(PA_ROUNDS) << 40 | (u64)(PB_ROUNDS) << 32)
void process_data(state* s, unsigned char* out, const unsigned char* in,
unsigned long long len, u8 mode);
void ascon_core(state* s, unsigned char* out, const unsigned char* in,
unsigned long long tlen, const unsigned char* ad,
unsigned long long adlen, const unsigned char* npub,
const unsigned char* k, u8 mode);
#endif // CORE_H_
#include "core.h"
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) {
if (clen < CRYPTO_ABYTES) {
*mlen = 0;
return -1;
}
state s;
(void)nsec;
// set plaintext size
*mlen = clen - CRYPTO_ABYTES;
ascon_core(&s, m, c, *mlen, ad, adlen, npub, k, ASCON_DEC);
// verify tag (should be constant time, check compiler output)
if (((s.x3 ^ U64BIG(*(u64*)(c + *mlen))) |
(s.x4 ^ U64BIG(*(u64*)(c + *mlen + 8)))) != 0) {
*mlen = 0;
return -1;
}
return 0;
}
#include "core.h"
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) {
state s;
(void)nsec;
// set ciphertext size
*clen = mlen + CRYPTO_ABYTES;
ascon_core(&s, c, m, mlen, ad, adlen, npub, k, ASCON_ENC);
// set tag
*(u64*)(c + mlen) = U64BIG(s.x3);
*(u64*)(c + mlen + 8) = U64BIG(s.x4);
return 0;
}
#ifndef ENDIAN_H_
#define ENDIAN_H_
#if defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
// macros for big endian machines
#define U64BIG(x) (x)
#define U32BIG(x) (x)
#define U16BIG(x) (x)
#elif defined(_MSC_VER) || \
(defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)
// macros for little endian machines
#define U64BIG(x) \
((((x)&0x00000000000000FFULL) << 56) | (((x)&0x000000000000FF00ULL) << 40) | \
(((x)&0x0000000000FF0000ULL) << 24) | (((x)&0x00000000FF000000ULL) << 8) | \
(((x)&0x000000FF00000000ULL) >> 8) | (((x)&0x0000FF0000000000ULL) >> 24) | \
(((x)&0x00FF000000000000ULL) >> 40) | (((x)&0xFF00000000000000ULL) >> 56))
#define U32BIG(x) \
((((x)&0x000000FF) << 24) | (((x)&0x0000FF00) << 8) | \
(((x)&0x00FF0000) >> 8) | (((x)&0xFF000000) >> 24))
#define U16BIG(x) ((((x)&0x00FF) << 8) | (((x)&0xFF00) >> 8))
#else
#error "ascon byte order macros not defined in endian.h"
#endif
#endif // ENDIAN_H_
#include "permutations.h"
void P(state *p, u8 rounds) {
state s = *p;
u8 i, start = START_CONSTANT(rounds);
for (i = start; i > 0x4a; i -= 0x0f) ROUND(i);
*p = s;
}
#ifndef PERMUTATIONS_H_
#define PERMUTATIONS_H_
typedef unsigned char u8;
typedef unsigned long long u64;
typedef struct {
u64 x0, x1, x2, x3, x4;
} state;
#define EXT_BYTE64(x, n) ((u8)((u64)(x) >> (8 * (7 - (n)))))
#define INS_BYTE64(x, n) ((u64)(x) << (8 * (7 - (n))))
#define ROTR64(x, n) (((x) >> (n)) | ((x) << (64 - (n))))
#define START_CONSTANT(x) (((0xf - (12 - (x))) << 4) | (12 - (x)))
#define ROUND(C) \
do { \
state t; \
s.x2 ^= C; \
s.x0 ^= s.x4; \
s.x4 ^= s.x3; \
s.x2 ^= s.x1; \
t.x0 = s.x0; \
t.x4 = s.x4; \
t.x3 = s.x3; \
t.x1 = s.x1; \
t.x2 = s.x2; \
s.x0 = t.x0 ^ ((~t.x1) & t.x2); \
s.x2 = t.x2 ^ ((~t.x3) & t.x4); \
s.x4 = t.x4 ^ ((~t.x0) & t.x1); \
s.x1 = t.x1 ^ ((~t.x2) & t.x3); \
s.x3 = t.x3 ^ ((~t.x4) & t.x0); \
s.x1 ^= s.x0; \
t.x1 = s.x1; \
s.x1 = ROTR64(s.x1, 39); \
s.x3 ^= s.x2; \
t.x2 = s.x2; \
s.x2 = ROTR64(s.x2, 1); \
t.x4 = s.x4; \
t.x2 ^= s.x2; \
s.x2 = ROTR64(s.x2, 6 - 1); \
t.x3 = s.x3; \
t.x1 ^= s.x1; \
s.x3 = ROTR64(s.x3, 10); \
s.x0 ^= s.x4; \
s.x4 = ROTR64(s.x4, 7); \
t.x3 ^= s.x3; \
s.x2 ^= t.x2; \
s.x1 = ROTR64(s.x1, 61 - 39); \
t.x0 = s.x0; \
s.x2 = ~s.x2; \
s.x3 = ROTR64(s.x3, 17 - 10); \
t.x4 ^= s.x4; \
s.x4 = ROTR64(s.x4, 41 - 7); \
s.x3 ^= t.x3; \
s.x1 ^= t.x1; \
s.x0 = ROTR64(s.x0, 19); \
s.x4 ^= t.x4; \
t.x0 ^= s.x0; \
s.x0 = ROTR64(s.x0, 28 - 19); \
s.x0 ^= t.x0; \
} while (0)
void P(state *p, u8 rounds);
#endif // PERMUTATIONS_H_
#define CRYPTO_KEYBYTES 16
#define CRYPTO_NSECBYTES 0
#define CRYPTO_NPUBBYTES 16
#define CRYPTO_ABYTES 16
#define CRYPTO_NOOVERLAP 1
#include "core.h"
void process_data(state* s, unsigned char* out, const unsigned char* in,
unsigned long long len, u8 mode) {
u32_2 t0;
u64 tmp0;
u64 i;
while (len >= RATE) {
tmp0 = U64BIG(*(u64*)in);
t0 = to_bit_interleaving(tmp0);
s->x0.e ^= t0.e;
s->x0.o ^= t0.o;
if (mode != ASCON_AD) {
tmp0 = from_bit_interleaving(s->x0);
*(u64*)out = U64BIG(tmp0);
}
if (mode == ASCON_DEC) s->x0 = t0;
P(s, PB_ROUNDS);
in += RATE;
out += RATE;
len -= RATE;
}
tmp0 = 0;
for (i = 0; i < len; ++i, ++in) tmp0 |= INS_BYTE64(*in, i);
in -= len;
tmp0 |= INS_BYTE64(0x80, len);
t0 = to_bit_interleaving(tmp0);
s->x0.e ^= t0.e;
s->x0.o ^= t0.o;
if (mode != ASCON_AD) {
tmp0 = from_bit_interleaving(s->x0);
for (i = 0; i < len; ++i, ++out) *out = EXT_BYTE64(tmp0, i);
}
if (mode == ASCON_DEC) {
for (i = 0; i < len; ++i, ++in) {
tmp0 &= ~INS_BYTE64(0xff, i);
tmp0 |= INS_BYTE64(*in, i);
}
s->x0 = to_bit_interleaving(tmp0);
}
}
void ascon_core(state* s, unsigned char* out, const unsigned char* in,
unsigned long long tlen, const unsigned char* ad,
unsigned long long adlen, const unsigned char* npub,
const unsigned char* k, u8 mode) {
u32_2 K0, K1, N0, N1;
// load key and nonce
K0 = to_bit_interleaving(U64BIG(*(u64*)k));
K1 = to_bit_interleaving(U64BIG(*(u64*)(k + 8)));
N0 = to_bit_interleaving(U64BIG(*(u64*)npub));
N1 = to_bit_interleaving(U64BIG(*(u64*)(npub + 8)));
// initialization
s->x0 = to_bit_interleaving(IV);
s->x1.o = K0.o;
s->x1.e = K0.e;
s->x2.e = K1.e;
s->x2.o = K1.o;
s->x3.e = N0.e;
s->x3.o = N0.o;
s->x4.e = N1.e;
s->x4.o = N1.o;
P(s, PA_ROUNDS);
s->x3.e ^= K0.e;
s->x3.o ^= K0.o;
s->x4.e ^= K1.e;
s->x4.o ^= K1.o;
// process associated data
if (adlen) {
process_data(s, (void*)0, ad, adlen, ASCON_AD);
P(s, PB_ROUNDS);
}
s->x4.e ^= 1;
// process plaintext/ciphertext
process_data(s, out, in, tlen, mode);
// finalization
s->x1.e ^= K0.e;
s->x1.o ^= K0.o;
s->x2.e ^= K1.e;
s->x2.o ^= K1.o;
P(s, PA_ROUNDS);
s->x3.e ^= K0.e;
s->x3.o ^= K0.o;
s->x4.e ^= K1.e;
s->x4.o ^= K1.o;
}
#ifndef CORE_H_
#define CORE_H_
#include "api.h"
#include "endian.h"
#include "permutations.h"
#define ASCON_AD 0
#define ASCON_ENC 1
#define ASCON_DEC 2
#define RATE (64 / 8)
#define PA_ROUNDS 12
#define PB_ROUNDS 6
#define IV \
((u64)(8 * (CRYPTO_KEYBYTES)) << 56 | (u64)(8 * (RATE)) << 48 | \
(u64)(PA_ROUNDS) << 40 | (u64)(PB_ROUNDS) << 32)
void process_data(state* s, unsigned char* out, const unsigned char* in,
unsigned long long len, u8 mode);
void ascon_core(state* s, unsigned char* out, const unsigned char* in,
unsigned long long tlen, const unsigned char* ad,
unsigned long long adlen, const unsigned char* npub,
const unsigned char* k, u8 mode);
#endif // CORE_H_
#include "core.h"
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) {
if (clen < CRYPTO_ABYTES) {
*mlen = 0;
return -1;
}
state s;
u32_2 t0, t1;
(void)nsec;
// set plaintext size
*mlen = clen - CRYPTO_ABYTES;
ascon_core(&s, m, c, *mlen, ad, adlen, npub, k, ASCON_DEC);
// verify tag (should be constant time, check compiler output)
t0 = to_bit_interleaving(U64BIG(*(u64*)(c + *mlen)));
t1 = to_bit_interleaving(U64BIG(*(u64*)(c + *mlen + 8)));
if (((s.x3.e ^ t0.e) | (s.x3.o ^ t0.o) | (s.x4.e ^ t1.e) | (s.x4.o ^ t1.o)) !=
0) {
*mlen = 0;
return -1;
}
return 0;
}
#include "core.h"
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) {
state s;
u64 tmp0, tmp1;
(void)nsec;
// set ciphertext size
*clen = mlen + CRYPTO_ABYTES;
ascon_core(&s, c, m, mlen, ad, adlen, npub, k, ASCON_ENC);
// set tag
tmp0 = from_bit_interleaving(s.x3);
*(u64*)(c + mlen) = U64BIG(tmp0);
tmp1 = from_bit_interleaving(s.x4);
*(u64*)(c + mlen + 8) = U64BIG(tmp1);
return 0;
}
#ifndef ENDIAN_H_
#define ENDIAN_H_
#if defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
// macros for big endian machines
#define U64BIG(x) (x)
#define U32BIG(x) (x)
#define U16BIG(x) (x)
#elif defined(_MSC_VER) || \
(defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)
// macros for little endian machines
#define U64BIG(x) \
((((x)&0x00000000000000FFULL) << 56) | (((x)&0x000000000000FF00ULL) << 40) | \
(((x)&0x0000000000FF0000ULL) << 24) | (((x)&0x00000000FF000000ULL) << 8) | \
(((x)&0x000000FF00000000ULL) >> 8) | (((x)&0x0000FF0000000000ULL) >> 24) | \
(((x)&0x00FF000000000000ULL) >> 40) | (((x)&0xFF00000000000000ULL) >> 56))
#define U32BIG(x) \
((((x)&0x000000FF) << 24) | (((x)&0x0000FF00) << 8) | \
(((x)&0x00FF0000) >> 8) | (((x)&0xFF000000) >> 24))
#define U16BIG(x) ((((x)&0x00FF) << 8) | (((x)&0xFF00) >> 8))
#else
#error "ascon byte order macros not defined in endian.h"
#endif
#endif // ENDIAN_H_
#include "permutations.h"
static const u8 constants[][2] = {
{0xc, 0xc}, {0x9, 0xc}, {0xc, 0x9}, {0x9, 0x9}, {0x6, 0xc}, {0x3, 0xc},
{0x6, 0x9}, {0x3, 0x9}, {0xc, 0x6}, {0x9, 0x6}, {0xc, 0x3}, {0x9, 0x3}};
// Credit to Henry S. Warren, Hacker's Delight, Addison-Wesley, 2002
u32_2 to_bit_interleaving(u64 in) {
u32 hi = (in) >> 32;
u32 lo = (u32)(in);
u32 r0, r1;
u32_2 out;
r0 = (lo ^ (lo >> 1)) & 0x22222222, lo ^= r0 ^ (r0 << 1);
r0 = (lo ^ (lo >> 2)) & 0x0C0C0C0C, lo ^= r0 ^ (r0 << 2);
r0 = (lo ^ (lo >> 4)) & 0x00F000F0, lo ^= r0 ^ (r0 << 4);
r0 = (lo ^ (lo >> 8)) & 0x0000FF00, lo ^= r0 ^ (r0 << 8);
r1 = (hi ^ (hi >> 1)) & 0x22222222, hi ^= r1 ^ (r1 << 1);
r1 = (hi ^ (hi >> 2)) & 0x0C0C0C0C, hi ^= r1 ^ (r1 << 2);
r1 = (hi ^ (hi >> 4)) & 0x00F000F0, hi ^= r1 ^ (r1 << 4);
r1 = (hi ^ (hi >> 8)) & 0x0000FF00, hi ^= r1 ^ (r1 << 8);
out.e = (lo & 0x0000FFFF) | (hi << 16);
out.o = (lo >> 16) | (hi & 0xFFFF0000);
return out;
}
// Credit to Henry S. Warren, Hacker's Delight, Addison-Wesley, 2002
u64 from_bit_interleaving(u32_2 in) {
u32 lo = (in.e & 0x0000FFFF) | (in.o << 16);
u32 hi = (in.e >> 16) | (in.o & 0xFFFF0000);
u32 r0, r1;
u64 out;
r0 = (lo ^ (lo >> 8)) & 0x0000FF00, lo ^= r0 ^ (r0 << 8);
r0 = (lo ^ (lo >> 4)) & 0x00F000F0, lo ^= r0 ^ (r0 << 4);
r0 = (lo ^ (lo >> 2)) & 0x0C0C0C0C, lo ^= r0 ^ (r0 << 2);
r0 = (lo ^ (lo >> 1)) & 0x22222222, lo ^= r0 ^ (r0 << 1);
r1 = (hi ^ (hi >> 8)) & 0x0000FF00, hi ^= r1 ^ (r1 << 8);
r1 = (hi ^ (hi >> 4)) & 0x00F000F0, hi ^= r1 ^ (r1 << 4);
r1 = (hi ^ (hi >> 2)) & 0x0C0C0C0C, hi ^= r1 ^ (r1 << 2);
r1 = (hi ^ (hi >> 1)) & 0x22222222, hi ^= r1 ^ (r1 << 1);
out = (u64)hi << 32 | lo;
return out;
}
void P(state *p, u8 rounds) {
state s = *p;
u32_2 t0, t1, t2, t3, t4;
u32 i, start = START_ROUND(rounds);
for (i = start; i < 12; i++) ROUND(constants[i][0], constants[i][1]);
*p = s;
}
#ifndef PERMUTATIONS_H_
#define PERMUTATIONS_H_
typedef unsigned char u8;
typedef unsigned int u32;
typedef unsigned long long u64;
typedef struct {
u32 e;
u32 o;
} u32_2;
typedef struct {
u32_2 x0;
u32_2 x1;
u32_2 x2;
u32_2 x3;
u32_2 x4;
} state;
#define EXT_BYTE64(x, n) ((u8)((u64)(x) >> (8 * (7 - (n)))))
#define INS_BYTE64(x, n) ((u64)(x) << (8 * (7 - (n))))
#define ROTR32(x, n) (((x) >> (n)) | ((x) << (32 - (n))))
#define START_ROUND(x) (12 - (x))
// Credit to Henry S. Warren, Hacker's Delight, Addison-Wesley, 2002
u32_2 to_bit_interleaving(u64 in);
// Credit to Henry S. Warren, Hacker's Delight, Addison-Wesley, 2002
u64 from_bit_interleaving(u32_2 in);
/* clang-format off */
#define ROUND(C_e, C_o) \
do { \
/* round constant */ \
s.x2.e ^= C_e; s.x2.o ^= C_o; \
/* s-box layer */ \
s.x0.e ^= s.x4.e; s.x0.o ^= s.x4.o; \
s.x4.e ^= s.x3.e; s.x4.o ^= s.x3.o; \
s.x2.e ^= s.x1.e; s.x2.o ^= s.x1.o; \
t0.e = s.x0.e; t0.o = s.x0.o; \
t4.e = s.x4.e; t4.o = s.x4.o; \
t3.e = s.x3.e; t3.o = s.x3.o; \
t1.e = s.x1.e; t1.o = s.x1.o; \
t2.e = s.x2.e; t2.o = s.x2.o; \
s.x0.e = t0.e ^ (~t1.e & t2.e); s.x0.o = t0.o ^ (~t1.o & t2.o); \
s.x2.e = t2.e ^ (~t3.e & t4.e); s.x2.o = t2.o ^ (~t3.o & t4.o); \
s.x4.e = t4.e ^ (~t0.e & t1.e); s.x4.o = t4.o ^ (~t0.o & t1.o); \
s.x1.e = t1.e ^ (~t2.e & t3.e); s.x1.o = t1.o ^ (~t2.o & t3.o); \
s.x3.e = t3.e ^ (~t4.e & t0.e); s.x3.o = t3.o ^ (~t4.o & t0.o); \
s.x1.e ^= s.x0.e; s.x1.o ^= s.x0.o; \
s.x3.e ^= s.x2.e; s.x3.o ^= s.x2.o; \
s.x0.e ^= s.x4.e; s.x0.o ^= s.x4.o; \
/* linear layer */ \
t0.e = s.x0.e ^ ROTR32(s.x0.o, 4); t0.o = s.x0.o ^ ROTR32(s.x0.e, 5); \
t1.e = s.x1.e ^ ROTR32(s.x1.e, 11); t1.o = s.x1.o ^ ROTR32(s.x1.o, 11); \
t2.e = s.x2.e ^ ROTR32(s.x2.o, 2); t2.o = s.x2.o ^ ROTR32(s.x2.e, 3); \
t3.e = s.x3.e ^ ROTR32(s.x3.o, 3); t3.o = s.x3.o ^ ROTR32(s.x3.e, 4); \
t4.e = s.x4.e ^ ROTR32(s.x4.e, 17); t4.o = s.x4.o ^ ROTR32(s.x4.o, 17); \
s.x0.e ^= ROTR32(t0.o, 9); s.x0.o ^= ROTR32(t0.e, 10); \
s.x1.e ^= ROTR32(t1.o, 19); s.x1.o ^= ROTR32(t1.e, 20); \
s.x2.e ^= t2.o; s.x2.o ^= ROTR32(t2.e, 1); \
s.x3.e ^= ROTR32(t3.e, 5); s.x3.o ^= ROTR32(t3.o, 5); \
s.x4.e ^= ROTR32(t4.o, 3); s.x4.o ^= ROTR32(t4.e, 4); \
s.x2.e = ~s.x2.e; s.x2.o = ~s.x2.o; \
} while(0)
/* clang-format on */
void P(state *p, u8 rounds);
#endif // PERMUTATIONS_H_
#define CRYPTO_KEYBYTES 16
#define CRYPTO_NSECBYTES 0
#define CRYPTO_NPUBBYTES 16
#define CRYPTO_ABYTES 16
#define CRYPTO_NOOVERLAP 1
#include "core.h"
void process_data(state* s, unsigned char* out, const unsigned char* in,
unsigned long long len, u8 mode) {
u64 i;
while (len >= RATE) {
s->x0 ^= U64BIG(*(u64*)in);
if (mode != ASCON_AD) *(u64*)out = U64BIG(s->x0);
if (mode == ASCON_DEC) s->x0 = U64BIG(*((u64*)in));
P(s, PB_ROUNDS);
in += RATE;
out += RATE;
len -= RATE;
}
for (i = 0; i < len; ++i, ++out, ++in) {
s->x0 ^= INS_BYTE64(*in, i);
if (mode != ASCON_AD) *out = EXT_BYTE64(s->x0, i);
if (mode == ASCON_DEC) {
s->x0 &= ~INS_BYTE64(0xff, i);
s->x0 |= INS_BYTE64(*in, i);
}
}
s->x0 ^= INS_BYTE64(0x80, len);
}
void ascon_core(state* s, unsigned char* out, const unsigned char* in,
unsigned long long tlen, const unsigned char* ad,
unsigned long long adlen, const unsigned char* npub,
const unsigned char* k, u8 mode) {
const u64 K0 = U64BIG(*(u64*)k);
const u64 K1 = U64BIG(*(u64*)(k + 8));
const u64 N0 = U64BIG(*(u64*)npub);
const u64 N1 = U64BIG(*(u64*)(npub + 8));
// initialization
s->x0 = IV;
s->x1 = K0;
s->x2 = K1;
s->x3 = N0;
s->x4 = N1;
P(s, PA_ROUNDS);
s->x3 ^= K0;
s->x4 ^= K1;
// process associated data
if (adlen) {
process_data(s, (void*)0, ad, adlen, ASCON_AD);
P(s, PB_ROUNDS);
}
s->x4 ^= 1;
// process plaintext/ciphertext
process_data(s, out, in, tlen, mode);
// finalization
s->x1 ^= K0;
s->x2 ^= K1;
P(s, PA_ROUNDS);
s->x3 ^= K0;
s->x4 ^= K1;
}
#ifndef CORE_H_
#define CORE_H_
#include "api.h"
#include "endian.h"
#include "permutations.h"
#define ASCON_AD 0
#define ASCON_ENC 1
#define ASCON_DEC 2
#define RATE (64 / 8)
#define PA_ROUNDS 12
#define PB_ROUNDS 6
#define IV \
((u64)(8 * (CRYPTO_KEYBYTES)) << 56 | (u64)(8 * (RATE)) << 48 | \
(u64)(PA_ROUNDS) << 40 | (u64)(PB_ROUNDS) << 32)
void process_data(state* s, unsigned char* out, const unsigned char* in,
unsigned long long len, u8 mode);
void ascon_core(state* s, unsigned char* out, const unsigned char* in,
unsigned long long tlen, const unsigned char* ad,
unsigned long long adlen, const unsigned char* npub,
const unsigned char* k, u8 mode);
#endif // CORE_H_
#include "core.h"
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) {
if (clen < CRYPTO_ABYTES) {
*mlen = 0;
return -1;
}
state s;
(void)nsec;
// set plaintext size
*mlen = clen - CRYPTO_ABYTES;
ascon_core(&s, m, c, *mlen, ad, adlen, npub, k, ASCON_DEC);
// verify tag (should be constant time, check compiler output)
if (((s.x3 ^ U64BIG(*(u64*)(c + *mlen))) |
(s.x4 ^ U64BIG(*(u64*)(c + *mlen + 8)))) != 0) {
*mlen = 0;
return -1;
}
return 0;
}
#include "core.h"
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) {
state s;
(void)nsec;
// set ciphertext size
*clen = mlen + CRYPTO_ABYTES;
ascon_core(&s, c, m, mlen, ad, adlen, npub, k, ASCON_ENC);
// set tag
*(u64*)(c + mlen) = U64BIG(s.x3);
*(u64*)(c + mlen + 8) = U64BIG(s.x4);
return 0;
}
#ifndef ENDIAN_H_
#define ENDIAN_H_
#if defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
// macros for big endian machines
#define U64BIG(x) (x)
#define U32BIG(x) (x)
#define U16BIG(x) (x)
#elif defined(_MSC_VER) || \
(defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)
// macros for little endian machines
#define U64BIG(x) \
((((x)&0x00000000000000FFULL) << 56) | (((x)&0x000000000000FF00ULL) << 40) | \
(((x)&0x0000000000FF0000ULL) << 24) | (((x)&0x00000000FF000000ULL) << 8) | \
(((x)&0x000000FF00000000ULL) >> 8) | (((x)&0x0000FF0000000000ULL) >> 24) | \
(((x)&0x00FF000000000000ULL) >> 40) | (((x)&0xFF00000000000000ULL) >> 56))
#define U32BIG(x) \
((((x)&0x000000FF) << 24) | (((x)&0x0000FF00) << 8) | \
(((x)&0x00FF0000) >> 8) | (((x)&0xFF000000) >> 24))
#define U16BIG(x) ((((x)&0x00FF) << 8) | (((x)&0xFF00) >> 8))
#else
#error "ascon byte order macros not defined in endian.h"
#endif
#endif // ENDIAN_H_
#include "permutations.h"
void P(state *p, u8 rounds) {
state s = *p;
u8 i, start = START_CONSTANT(rounds);
for (i = start; i > 0x4a; i -= 0x0f) ROUND(i);
*p = s;
}
#ifndef PERMUTATIONS_H_
#define PERMUTATIONS_H_
typedef unsigned char u8;
typedef unsigned long long u64;
typedef struct {
u64 x0, x1, x2, x3, x4;
} state;
#define EXT_BYTE64(x, n) ((u8)((u64)(x) >> (8 * (7 - (n)))))
#define INS_BYTE64(x, n) ((u64)(x) << (8 * (7 - (n))))
#define ROTR64(x, n) (((x) >> (n)) | ((x) << (64 - (n))))
#define START_CONSTANT(x) (((0xf - (12 - (x))) << 4) | (12 - (x)))
#define ROUND(C) \
do { \
state t; \
s.x2 ^= C; \
s.x0 ^= s.x4; \
s.x4 ^= s.x3; \
s.x2 ^= s.x1; \
t.x0 = s.x0; \
t.x4 = s.x4; \
t.x3 = s.x3; \
t.x1 = s.x1; \
t.x2 = s.x2; \
s.x0 = t.x0 ^ ((~t.x1) & t.x2); \
s.x2 = t.x2 ^ ((~t.x3) & t.x4); \
s.x4 = t.x4 ^ ((~t.x0) & t.x1); \
s.x1 = t.x1 ^ ((~t.x2) & t.x3); \
s.x3 = t.x3 ^ ((~t.x4) & t.x0); \
s.x1 ^= s.x0; \
t.x1 = s.x1; \
s.x1 = ROTR64(s.x1, 39); \
s.x3 ^= s.x2; \
t.x2 = s.x2; \
s.x2 = ROTR64(s.x2, 1); \
t.x4 = s.x4; \
t.x2 ^= s.x2; \
s.x2 = ROTR64(s.x2, 6 - 1); \
t.x3 = s.x3; \
t.x1 ^= s.x1; \
s.x3 = ROTR64(s.x3, 10); \
s.x0 ^= s.x4; \
s.x4 = ROTR64(s.x4, 7); \
t.x3 ^= s.x3; \
s.x2 ^= t.x2; \
s.x1 = ROTR64(s.x1, 61 - 39); \
t.x0 = s.x0; \
s.x2 = ~s.x2; \
s.x3 = ROTR64(s.x3, 17 - 10); \
t.x4 ^= s.x4; \
s.x4 = ROTR64(s.x4, 41 - 7); \
s.x3 ^= t.x3; \
s.x1 ^= t.x1; \
s.x0 = ROTR64(s.x0, 19); \
s.x4 ^= t.x4; \
t.x0 ^= s.x0; \
s.x0 = ROTR64(s.x0, 28 - 19); \
s.x0 ^= t.x0; \
} while (0)
void P(state *p, u8 rounds);
#endif // PERMUTATIONS_H_
#define CRYPTO_KEYBYTES 20
#define CRYPTO_NSECBYTES 0
#define CRYPTO_NPUBBYTES 16
#define CRYPTO_ABYTES 16
#define CRYPTO_NOOVERLAP 1
#include "core.h"
void process_data(state* s, unsigned char* out, const unsigned char* in,
unsigned long long len, u8 mode) {
u64 i;
while (len >= RATE) {
s->x0 ^= U64BIG(*(u64*)in);
if (mode != ASCON_AD) *(u64*)out = U64BIG(s->x0);
if (mode == ASCON_DEC) s->x0 = U64BIG(*((u64*)in));
P(s, PB_ROUNDS);
in += RATE;
out += RATE;
len -= RATE;
}
for (i = 0; i < len; ++i, ++out, ++in) {
s->x0 ^= INS_BYTE64(*in, i);
if (mode != ASCON_AD) *out = EXT_BYTE64(s->x0, i);
if (mode == ASCON_DEC) {
s->x0 &= ~INS_BYTE64(0xff, i);
s->x0 |= INS_BYTE64(*in, i);
}
}
s->x0 ^= INS_BYTE64(0x80, len);
}
void ascon_core(state* s, unsigned char* out, const unsigned char* in,
unsigned long long tlen, const unsigned char* ad,
unsigned long long adlen, const unsigned char* npub,
const unsigned char* k, u8 mode) {
const u64 K0 = U64BIG(*(u64*)(k + 0)) >> 32;
const u64 K1 = U64BIG(*(u64*)(k + 4));
const u64 K2 = U64BIG(*(u64*)(k + 12));
const u64 N0 = U64BIG(*(u64*)npub);
const u64 N1 = U64BIG(*(u64*)(npub + 8));
// initialization
s->x0 = IV | K0;
s->x1 = K1;
s->x2 = K2;
s->x3 = N0;
s->x4 = N1;
P(s, PA_ROUNDS);
s->x2 ^= K0;
s->x3 ^= K1;
s->x4 ^= K2;
// process associated data
if (adlen) {
process_data(s, (void*)0, ad, adlen, ASCON_AD);
P(s, PB_ROUNDS);
}
s->x4 ^= 1;
// process plaintext/ciphertext
process_data(s, out, in, tlen, mode);
// finalization
s->x1 ^= K0 << 32 | K1 >> 32;
s->x2 ^= K1 << 32 | K2 >> 32;
s->x3 ^= K2 << 32;
P(s, PA_ROUNDS);
s->x3 ^= K1;
s->x4 ^= K2;
}
#ifndef CORE_H_
#define CORE_H_
#include "api.h"
#include "endian.h"
#include "permutations.h"
#define ASCON_AD 0
#define ASCON_ENC 1
#define ASCON_DEC 2
#define RATE (64 / 8)
#define PA_ROUNDS 12
#define PB_ROUNDS 6
#define IV \
((u64)(8 * (CRYPTO_KEYBYTES)) << 56 | (u64)(8 * (RATE)) << 48 | \
(u64)(PA_ROUNDS) << 40 | (u64)(PB_ROUNDS) << 32)
void process_data(state* s, unsigned char* out, const unsigned char* in,
unsigned long long len, u8 mode);
void ascon_core(state* s, unsigned char* out, const unsigned char* in,
unsigned long long tlen, const unsigned char* ad,
unsigned long long adlen, const unsigned char* npub,
const unsigned char* k, u8 mode);
#endif // CORE_H_
#include "core.h"
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) {
if (clen < CRYPTO_ABYTES) {
*mlen = 0;
return -1;
}
state s;
(void)nsec;
// set plaintext size
*mlen = clen - CRYPTO_ABYTES;
ascon_core(&s, m, c, *mlen, ad, adlen, npub, k, ASCON_DEC);
// verify tag (should be constant time, check compiler output)
if (((s.x3 ^ U64BIG(*(u64*)(c + *mlen))) |
(s.x4 ^ U64BIG(*(u64*)(c + *mlen + 8)))) != 0) {
*mlen = 0;
return -1;
}
return 0;
}
#include "core.h"
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) {
state s;
(void)nsec;
// set ciphertext size
*clen = mlen + CRYPTO_ABYTES;
ascon_core(&s, c, m, mlen, ad, adlen, npub, k, ASCON_ENC);
// set tag
*(u64*)(c + mlen) = U64BIG(s.x3);
*(u64*)(c + mlen + 8) = U64BIG(s.x4);
return 0;
}
#ifndef ENDIAN_H_
#define ENDIAN_H_
#if defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
// macros for big endian machines
#define U64BIG(x) (x)
#define U32BIG(x) (x)
#define U16BIG(x) (x)
#elif defined(_MSC_VER) || \
(defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)
// macros for little endian machines
#define U64BIG(x) \
((((x)&0x00000000000000FFULL) << 56) | (((x)&0x000000000000FF00ULL) << 40) | \
(((x)&0x0000000000FF0000ULL) << 24) | (((x)&0x00000000FF000000ULL) << 8) | \
(((x)&0x000000FF00000000ULL) >> 8) | (((x)&0x0000FF0000000000ULL) >> 24) | \
(((x)&0x00FF000000000000ULL) >> 40) | (((x)&0xFF00000000000000ULL) >> 56))
#define U32BIG(x) \
((((x)&0x000000FF) << 24) | (((x)&0x0000FF00) << 8) | \
(((x)&0x00FF0000) >> 8) | (((x)&0xFF000000) >> 24))
#define U16BIG(x) ((((x)&0x00FF) << 8) | (((x)&0xFF00) >> 8))
#else
#error "ascon byte order macros not defined in endian.h"
#endif
#endif // ENDIAN_H_
#include "permutations.h"
void P(state *p, u8 rounds) {
state s = *p;
u8 i, start = START_CONSTANT(rounds);
for (i = start; i > 0x4a; i -= 0x0f) ROUND(i);
*p = s;
}
#ifndef PERMUTATIONS_H_
#define PERMUTATIONS_H_
typedef unsigned char u8;
typedef unsigned long long u64;
typedef struct {
u64 x0, x1, x2, x3, x4;
} state;
#define EXT_BYTE64(x, n) ((u8)((u64)(x) >> (8 * (7 - (n)))))
#define INS_BYTE64(x, n) ((u64)(x) << (8 * (7 - (n))))
#define ROTR64(x, n) (((x) >> (n)) | ((x) << (64 - (n))))
#define START_CONSTANT(x) (((0xf - (12 - (x))) << 4) | (12 - (x)))
#define ROUND(C) \
do { \
state t; \
s.x2 ^= C; \
s.x0 ^= s.x4; \
s.x4 ^= s.x3; \
s.x2 ^= s.x1; \
t.x0 = s.x0; \
t.x4 = s.x4; \
t.x3 = s.x3; \
t.x1 = s.x1; \
t.x2 = s.x2; \
s.x0 = t.x0 ^ ((~t.x1) & t.x2); \
s.x2 = t.x2 ^ ((~t.x3) & t.x4); \
s.x4 = t.x4 ^ ((~t.x0) & t.x1); \
s.x1 = t.x1 ^ ((~t.x2) & t.x3); \
s.x3 = t.x3 ^ ((~t.x4) & t.x0); \
s.x1 ^= s.x0; \
t.x1 = s.x1; \
s.x1 = ROTR64(s.x1, 39); \
s.x3 ^= s.x2; \
t.x2 = s.x2; \
s.x2 = ROTR64(s.x2, 1); \
t.x4 = s.x4; \
t.x2 ^= s.x2; \
s.x2 = ROTR64(s.x2, 6 - 1); \
t.x3 = s.x3; \
t.x1 ^= s.x1; \
s.x3 = ROTR64(s.x3, 10); \
s.x0 ^= s.x4; \
s.x4 = ROTR64(s.x4, 7); \
t.x3 ^= s.x3; \
s.x2 ^= t.x2; \
s.x1 = ROTR64(s.x1, 61 - 39); \
t.x0 = s.x0; \
s.x2 = ~s.x2; \
s.x3 = ROTR64(s.x3, 17 - 10); \
t.x4 ^= s.x4; \
s.x4 = ROTR64(s.x4, 41 - 7); \
s.x3 ^= t.x3; \
s.x1 ^= t.x1; \
s.x0 = ROTR64(s.x0, 19); \
s.x4 ^= t.x4; \
t.x0 ^= s.x0; \
s.x0 = ROTR64(s.x0, 28 - 19); \
s.x0 ^= t.x0; \
} while (0)
void P(state *p, u8 rounds);
#endif // PERMUTATIONS_H_
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