Commit ba578844 by Martin Schläffer Committed by Sebastian Renner

low/midsize ascon

parent 1640476b
#pragma GCC push_options
#pragma GCC optimize ("Os")
#include "api.h"
#include "ascon.h"
#include "permutations.h"
#include "printstate.h"
#if !ASCON_INLINE_MODE
#undef forceinline
#define forceinline
#endif
#ifdef ASCON_AEAD_RATE
forceinline void ascon_loadkey(key_t* key, const uint8_t* k) {
#if CRYPTO_KEYBYTES == 16
key->k1 = LOAD(k, 8);
key->k2 = LOAD(k + 8, 8);
#else /* CRYPTO_KEYBYTES == 20 */
key->k0 = KEYROT(0, LOADBYTES(k, 4));
key->k1 = LOADBYTES(k + 4, 8);
key->k2 = LOADBYTES(k + 12, 8);
#endif
}
forceinline void ascon_initaead(state_t* s, const uint8_t* npub,
const key_t* key) {
#if CRYPTO_KEYBYTES == 16
if (ASCON_AEAD_RATE == 8) s->x[0] = ASCON_128_IV;
if (ASCON_AEAD_RATE == 16) s->x[0] = ASCON_128A_IV;
#else /* CRYPTO_KEYBYTES == 20 */
s->x[0] = ASCON_80PQ_IV ^ key->k0;
#endif
s->x[1] = key->k1;
s->x[2] = key->k2;
s->x[3] = LOAD(npub, 8);
s->x[4] = LOAD(npub + 8, 8);
printstate("init 1st key xor", s);
P(s, 12);
#if CRYPTO_KEYBYTES == 20
s->x[2] ^= key->k0;
#endif
s->x[3] ^= key->k1;
s->x[4] ^= key->k2;
printstate("init 2nd key xor", s);
}
forceinline void ascon_final(state_t* s, const key_t* key) {
#if CRYPTO_KEYBYTES == 16
if (ASCON_AEAD_RATE == 8) {
s->x[1] ^= key->k1;
s->x[2] ^= key->k2;
} else {
s->x[2] ^= key->k1;
s->x[3] ^= key->k2;
}
#else /* CRYPTO_KEYBYTES == 20 */
s->x[1] ^= KEYROT(key->k0, key->k1);
s->x[2] ^= KEYROT(key->k1, key->k2);
s->x[3] ^= KEYROT(key->k2, 0);
#endif
printstate("final 1st key xor", s);
P(s, 12);
s->x[3] ^= key->k1;
s->x[4] ^= key->k2;
printstate("final 2nd key xor", s);
}
void ascon_aead(uint8_t* t, uint8_t* out, const uint8_t* in, uint64_t tlen,
const uint8_t* ad, uint64_t adlen, const uint8_t* npub,
const uint8_t* k, uint8_t mode) {
const int nr = (ASCON_AEAD_RATE == 8) ? 6 : 8;
key_t key;
ascon_loadkey(&key, k);
/* initialize */
state_t s;
ascon_initaead(&s, npub, &key);
/* process associated data */
if (adlen) {
ascon_update(&s, (void*)0, ad, adlen, ASCON_ABSORB);
printstate("pad adata", &s);
P(&s, nr);
}
/* domain separation */
s.x[4] ^= 1;
printstate("domain separation", &s);
/* process plaintext/ciphertext */
ascon_update(&s, out, in, tlen, mode);
if (mode == ASCON_ENCRYPT) printstate("pad plaintext", &s);
if (mode == ASCON_DECRYPT) printstate("pad ciphertext", &s);
/* finalize */
ascon_final(&s, &key);
((uint64_t*)t)[0] = WORDTOU64(s.x[3]);
((uint64_t*)t)[1] = WORDTOU64(s.x[4]);
}
#endif
#pragma GCC pop_options
#pragma GCC push_options
#pragma GCC optimize ("Os")
#include "api.h"
#include "ascon.h"
#include "permutations.h"
#include "printstate.h"
#if !ASCON_INLINE_MODE
#undef forceinline
#define forceinline
#endif
#ifdef ASCON_AEAD_RATE
forceinline void ascon_loadkey(key_t* key, const uint8_t* k) {
#if CRYPTO_KEYBYTES == 16
key->k1 = LOAD(k, 8);
key->k2 = LOAD(k + 8, 8);
#else /* CRYPTO_KEYBYTES == 20 */
key->k0 = KEYROT(0, LOADBYTES(k, 4));
key->k1 = LOADBYTES(k + 4, 8);
key->k2 = LOADBYTES(k + 12, 8);
#endif
}
forceinline void ascon_initaead(state_t* s, const uint8_t* npub,
const key_t* key) {
#if CRYPTO_KEYBYTES == 16
if (ASCON_AEAD_RATE == 8) s->x[0] = ASCON_128_IV;
if (ASCON_AEAD_RATE == 16) s->x[0] = ASCON_128A_IV;
#else /* CRYPTO_KEYBYTES == 20 */
s->x[0] = ASCON_80PQ_IV ^ key->k0;
#endif
s->x[1] = key->k1;
s->x[2] = key->k2;
s->x[3] = LOAD(npub, 8);
s->x[4] = LOAD(npub + 8, 8);
printstate("init 1st key xor", s);
P(s, 12);
#if CRYPTO_KEYBYTES == 20
s->x[2] ^= key->k0;
#endif
s->x[3] ^= key->k1;
s->x[4] ^= key->k2;
printstate("init 2nd key xor", s);
}
forceinline void ascon_final(state_t* s, const key_t* key) {
#if CRYPTO_KEYBYTES == 16
if (ASCON_AEAD_RATE == 8) {
s->x[1] ^= key->k1;
s->x[2] ^= key->k2;
} else {
s->x[2] ^= key->k1;
s->x[3] ^= key->k2;
}
#else /* CRYPTO_KEYBYTES == 20 */
s->x[1] ^= KEYROT(key->k0, key->k1);
s->x[2] ^= KEYROT(key->k1, key->k2);
s->x[3] ^= KEYROT(key->k2, 0);
#endif
printstate("final 1st key xor", s);
P(s, 12);
s->x[3] ^= key->k1;
s->x[4] ^= key->k2;
printstate("final 2nd key xor", s);
}
void ascon_aead(uint8_t* t, uint8_t* out, const uint8_t* in, uint64_t tlen,
const uint8_t* ad, uint64_t adlen, const uint8_t* npub,
const uint8_t* k, uint8_t mode) {
const int nr = (ASCON_AEAD_RATE == 8) ? 6 : 8;
key_t key;
ascon_loadkey(&key, k);
/* initialize */
state_t s;
ascon_initaead(&s, npub, &key);
/* process associated data */
if (adlen) {
ascon_update(&s, (void*)0, ad, adlen, ASCON_ABSORB);
printstate("pad adata", &s);
P(&s, nr);
}
/* domain separation */
s.x[4] ^= 1;
printstate("domain separation", &s);
/* process plaintext/ciphertext */
ascon_update(&s, out, in, tlen, mode);
if (mode == ASCON_ENCRYPT) printstate("pad plaintext", &s);
if (mode == ASCON_DECRYPT) printstate("pad ciphertext", &s);
/* finalize */
ascon_final(&s, &key);
((uint64_t*)t)[0] = WORDTOU64(s.x[3]);
((uint64_t*)t)[1] = WORDTOU64(s.x[4]);
}
#endif
#pragma GCC pop_options
#pragma GCC push_options
#pragma GCC optimize ("Os")
#include "api.h"
#include "ascon.h"
#include "permutations.h"
#include "printstate.h"
#if !ASCON_INLINE_MODE
#undef forceinline
#define forceinline
#endif
#ifdef ASCON_AEAD_RATE
forceinline void ascon_loadkey(key_t* key, const uint8_t* k) {
#if CRYPTO_KEYBYTES == 16
key->k1 = LOAD(k, 8);
key->k2 = LOAD(k + 8, 8);
#else /* CRYPTO_KEYBYTES == 20 */
key->k0 = KEYROT(0, LOADBYTES(k, 4));
key->k1 = LOADBYTES(k + 4, 8);
key->k2 = LOADBYTES(k + 12, 8);
#endif
}
forceinline void ascon_initaead(state_t* s, const uint8_t* npub,
const key_t* key) {
#if CRYPTO_KEYBYTES == 16
if (ASCON_AEAD_RATE == 8) s->x[0] = ASCON_128_IV;
if (ASCON_AEAD_RATE == 16) s->x[0] = ASCON_128A_IV;
#else /* CRYPTO_KEYBYTES == 20 */
s->x[0] = ASCON_80PQ_IV ^ key->k0;
#endif
s->x[1] = key->k1;
s->x[2] = key->k2;
s->x[3] = LOAD(npub, 8);
s->x[4] = LOAD(npub + 8, 8);
printstate("init 1st key xor", s);
P(s, 12);
#if CRYPTO_KEYBYTES == 20
s->x[2] ^= key->k0;
#endif
s->x[3] ^= key->k1;
s->x[4] ^= key->k2;
printstate("init 2nd key xor", s);
}
forceinline void ascon_final(state_t* s, const key_t* key) {
#if CRYPTO_KEYBYTES == 16
if (ASCON_AEAD_RATE == 8) {
s->x[1] ^= key->k1;
s->x[2] ^= key->k2;
} else {
s->x[2] ^= key->k1;
s->x[3] ^= key->k2;
}
#else /* CRYPTO_KEYBYTES == 20 */
s->x[1] ^= KEYROT(key->k0, key->k1);
s->x[2] ^= KEYROT(key->k1, key->k2);
s->x[3] ^= KEYROT(key->k2, 0);
#endif
printstate("final 1st key xor", s);
P(s, 12);
s->x[3] ^= key->k1;
s->x[4] ^= key->k2;
printstate("final 2nd key xor", s);
}
void ascon_aead(uint8_t* t, uint8_t* out, const uint8_t* in, uint64_t tlen,
const uint8_t* ad, uint64_t adlen, const uint8_t* npub,
const uint8_t* k, uint8_t mode) {
const int nr = (ASCON_AEAD_RATE == 8) ? 6 : 8;
key_t key;
ascon_loadkey(&key, k);
/* initialize */
state_t s;
ascon_initaead(&s, npub, &key);
/* process associated data */
if (adlen) {
ascon_update(&s, (void*)0, ad, adlen, ASCON_ABSORB);
printstate("pad adata", &s);
P(&s, nr);
}
/* domain separation */
s.x[4] ^= 1;
printstate("domain separation", &s);
/* process plaintext/ciphertext */
ascon_update(&s, out, in, tlen, mode);
if (mode == ASCON_ENCRYPT) printstate("pad plaintext", &s);
if (mode == ASCON_DECRYPT) printstate("pad ciphertext", &s);
/* finalize */
ascon_final(&s, &key);
((uint64_t*)t)[0] = WORDTOU64(s.x[3]);
((uint64_t*)t)[1] = WORDTOU64(s.x[4]);
}
#endif
#pragma GCC pop_options
#pragma GCC push_options
#pragma GCC optimize ("Os")
#include "api.h"
#include "ascon.h"
#include "permutations.h"
#include "printstate.h"
#if !ASCON_INLINE_MODE
#undef forceinline
#define forceinline
#endif
#ifdef ASCON_AEAD_RATE
forceinline void ascon_loadkey(key_t* key, const uint8_t* k) {
#if CRYPTO_KEYBYTES == 16
key->k1 = LOAD(k, 8);
key->k2 = LOAD(k + 8, 8);
#else /* CRYPTO_KEYBYTES == 20 */
key->k0 = KEYROT(0, LOADBYTES(k, 4));
key->k1 = LOADBYTES(k + 4, 8);
key->k2 = LOADBYTES(k + 12, 8);
#endif
}
forceinline void ascon_initaead(state_t* s, const uint8_t* npub,
const key_t* key) {
#if CRYPTO_KEYBYTES == 16
if (ASCON_AEAD_RATE == 8) s->x[0] = ASCON_128_IV;
if (ASCON_AEAD_RATE == 16) s->x[0] = ASCON_128A_IV;
#else /* CRYPTO_KEYBYTES == 20 */
s->x[0] = ASCON_80PQ_IV ^ key->k0;
#endif
s->x[1] = key->k1;
s->x[2] = key->k2;
s->x[3] = LOAD(npub, 8);
s->x[4] = LOAD(npub + 8, 8);
printstate("init 1st key xor", s);
P(s, 12);
#if CRYPTO_KEYBYTES == 20
s->x[2] ^= key->k0;
#endif
s->x[3] ^= key->k1;
s->x[4] ^= key->k2;
printstate("init 2nd key xor", s);
}
forceinline void ascon_final(state_t* s, const key_t* key) {
#if CRYPTO_KEYBYTES == 16
if (ASCON_AEAD_RATE == 8) {
s->x[1] ^= key->k1;
s->x[2] ^= key->k2;
} else {
s->x[2] ^= key->k1;
s->x[3] ^= key->k2;
}
#else /* CRYPTO_KEYBYTES == 20 */
s->x[1] ^= KEYROT(key->k0, key->k1);
s->x[2] ^= KEYROT(key->k1, key->k2);
s->x[3] ^= KEYROT(key->k2, 0);
#endif
printstate("final 1st key xor", s);
P(s, 12);
s->x[3] ^= key->k1;
s->x[4] ^= key->k2;
printstate("final 2nd key xor", s);
}
void ascon_aead(uint8_t* t, uint8_t* out, const uint8_t* in, uint64_t tlen,
const uint8_t* ad, uint64_t adlen, const uint8_t* npub,
const uint8_t* k, uint8_t mode) {
const int nr = (ASCON_AEAD_RATE == 8) ? 6 : 8;
key_t key;
ascon_loadkey(&key, k);
/* initialize */
state_t s;
ascon_initaead(&s, npub, &key);
/* process associated data */
if (adlen) {
ascon_update(&s, (void*)0, ad, adlen, ASCON_ABSORB);
printstate("pad adata", &s);
P(&s, nr);
}
/* domain separation */
s.x[4] ^= 1;
printstate("domain separation", &s);
/* process plaintext/ciphertext */
ascon_update(&s, out, in, tlen, mode);
if (mode == ASCON_ENCRYPT) printstate("pad plaintext", &s);
if (mode == ASCON_DECRYPT) printstate("pad ciphertext", &s);
/* finalize */
ascon_final(&s, &key);
((uint64_t*)t)[0] = WORDTOU64(s.x[3]);
((uint64_t*)t)[1] = WORDTOU64(s.x[4]);
}
#endif
#pragma GCC pop_options
#define CRYPTO_VERSION "1.2.6"
#define CRYPTO_KEYBYTES 16
#define CRYPTO_NSECBYTES 0
#define CRYPTO_NPUBBYTES 16
#define CRYPTO_ABYTES 16
#define CRYPTO_NOOVERLAP 1
#define ASCON_AEAD_RATE 16
#ifndef ASCON_H_
#define ASCON_H_
#include <stdint.h>
#include "word.h"
typedef union {
uint64_t x[5];
uint32_t w[5][2];
uint8_t b[5][8];
} state_t;
typedef struct {
#if (CRYPTO_KEYBYTES == 20)
uint64_t k0;
#endif
uint64_t k1;
uint64_t k2;
} key_t;
void ascon_initaead(state_t* s, const uint8_t* npub, const key_t* k);
void ascon_adata(state_t* s, const uint8_t* ad, uint64_t adlen);
void ascon_encrypt(state_t* s, uint8_t* c, const uint8_t* m, uint64_t mlen);
void ascon_decrypt(state_t* s, uint8_t* m, const uint8_t* c, uint64_t clen);
void ascon_final(state_t* s, const key_t* k);
void ascon_inithash(state_t* s);
void ascon_absorb(state_t* s, const uint8_t* in, uint64_t inlen);
void ascon_squeeze(state_t* s, uint8_t* out, uint64_t outlen);
#endif /* ASCON_H_ */
#ifndef CONFIG_H_
#define CONFIG_H_
/* inline the ascon mode */
#ifndef ASCON_INLINE_MODE
#define ASCON_INLINE_MODE 1
#endif
/* inline all permutations */
#ifndef ASCON_INLINE_PERM
#define ASCON_INLINE_PERM 0
#endif
/* unroll permutation loops */
#ifndef ASCON_UNROLL_LOOPS
#define ASCON_UNROLL_LOOPS 0
#endif
/* inline bitinterleaving */
#ifndef ASCON_INLINE_BI
#define ASCON_INLINE_BI 1
#endif
/* extern bitinterleaving */
#ifndef ASCON_EXTERN_BI
#define ASCON_EXTERN_BI 0
#endif
#endif /* CONFIG_H_ */
#include "constants.h"
#if !ASCON_UNROLL_LOOPS
const uint8_t constants[] = {0xc, 0xc, 0x9, 0xc, 0xc, 0x9, 0x9, 0x9,
0x6, 0xc, 0x3, 0xc, 0x6, 0x9, 0x3, 0x9,
0xc, 0x6, 0x9, 0x6, 0xc, 0x3, 0x9, 0x3};
#endif
#ifndef CONSTANTS_H_
#define CONSTANTS_H_
#include <stdint.h>
#define ASCON_128_KEYBYTES 16
#define ASCON_128A_KEYBYTES 16
#define ASCON_80PQ_KEYBYTES 20
#define ASCON_128_RATE 8
#define ASCON_128A_RATE 16
#define ASCON_HASH_RATE 8
#define ASCON_PRF_IN_RATE 32
#define ASCON_PRF_OUT_RATE 16
#define ASCON_128_PA_ROUNDS 12
#define ASCON_128_PB_ROUNDS 6
#define ASCON_128A_PA_ROUNDS 12
#define ASCON_128A_PB_ROUNDS 8
#define ASCON_HASH_PA_ROUNDS 12
#define ASCON_HASH_PB_ROUNDS 12
#define ASCON_HASHA_PA_ROUNDS 12
#define ASCON_HASHA_PB_ROUNDS 8
#define ASCON_PRF_PA_ROUNDS 12
#define ASCON_PRF_PB_ROUNDS 12
#define ASCON_128_IV 0x8021000008220000ull
#define ASCON_128A_IV 0x8822000000200000ull
#define ASCON_80PQ_IV 0xc021000008220000ull
#define ASCON_HASH_IV 0x0020000008200010ull
#define ASCON_HASHA_IV 0x0020000008220010ull
#define ASCON_XOF_IV 0x0020000008200000ull
#define ASCON_XOFA_IV 0x0020000008220000ull
#define ASCON_PRF_IV 0x88a0000000200000ull
#define ASCON_MAC_IV 0x88a0000800200000ull
#define ASCON_PRFS_IV 0x8028000000a00000ull
#define ASCON_HASH_IV0 0xf9afb5c6a540dbc7ull
#define ASCON_HASH_IV1 0xbd2493011445a340ull
#define ASCON_HASH_IV2 0xcb9ba8b5604d4fc8ull
#define ASCON_HASH_IV3 0x12a4eede94514c98ull
#define ASCON_HASH_IV4 0x4bca84c06339f398ull
#define ASCON_HASHA_IV0 0x0108e46d1b16eb02ull
#define ASCON_HASHA_IV1 0x5b9b8efdd29083f3ull
#define ASCON_HASHA_IV2 0x7ad665622891ae4aull
#define ASCON_HASHA_IV3 0x9dc27156ee3bfc7full
#define ASCON_HASHA_IV4 0xc61d5fa916801633ull
#define ASCON_XOF_IV0 0xc75782817e351ae6ull
#define ASCON_XOF_IV1 0x70045f441d238220ull
#define ASCON_XOF_IV2 0x5dd5ab52a13e3f04ull
#define ASCON_XOF_IV3 0x3e378142c30c1db2ull
#define ASCON_XOF_IV4 0x3735189db624d656ull
#define ASCON_XOFA_IV0 0x0846d7a5a4b87d44ull
#define ASCON_XOFA_IV1 0xaa6f1005b3a2dbf4ull
#define ASCON_XOFA_IV2 0xdc451146f713e811ull
#define ASCON_XOFA_IV3 0x468cb2532839e30dull
#define ASCON_XOFA_IV4 0xeb2d429709e96977ull
#define RC0 0x0000000c0000000cull
#define RC1 0x0000000c00000009ull
#define RC2 0x000000090000000cull
#define RC3 0x0000000900000009ull
#define RC4 0x0000000c00000006ull
#define RC5 0x0000000c00000003ull
#define RC6 0x0000000900000006ull
#define RC7 0x0000000900000003ull
#define RC8 0x000000060000000cull
#define RC9 0x0000000600000009ull
#define RCa 0x000000030000000cull
#define RCb 0x0000000300000009ull
#define RC(i) ((uint64_t)constants[i + 1] << 32 | constants[i])
#define START(n) (24 - 2 * (n))
#define INC 2
#define END 24
extern const uint8_t constants[];
#endif /* CONSTANTS_H_ */
#include "api.h"
#include "ascon.h"
#include "crypto_aead.h"
#include "permutations.h"
#include "printstate.h"
#if !ASCON_INLINE_MODE
#undef forceinline
#define forceinline
#endif
#ifdef ASCON_AEAD_RATE
forceinline void ascon_loadkey(key_t* key, const uint8_t* k) {
#if CRYPTO_KEYBYTES == 16
key->k1 = LOAD(k, 8);
key->k2 = LOAD(k + 8, 8);
#else /* CRYPTO_KEYBYTES == 20 */
key->k0 = KEYROT(0, LOADBYTES(k, 4));
key->k1 = LOADBYTES(k + 4, 8);
key->k2 = LOADBYTES(k + 12, 8);
#endif
}
forceinline void ascon_initaead(state_t* s, const uint8_t* npub,
const key_t* key) {
#if CRYPTO_KEYBYTES == 16
if (ASCON_AEAD_RATE == 8) s->x[0] = ASCON_128_IV;
if (ASCON_AEAD_RATE == 16) s->x[0] = ASCON_128A_IV;
#else /* CRYPTO_KEYBYTES == 20 */
s->x[0] = ASCON_80PQ_IV ^ key->k0;
#endif
s->x[1] = key->k1;
s->x[2] = key->k2;
s->x[3] = LOAD(npub, 8);
s->x[4] = LOAD(npub + 8, 8);
printstate("init 1st key xor", s);
P(s, 12);
#if CRYPTO_KEYBYTES == 20
s->x[2] ^= key->k0;
#endif
s->x[3] ^= key->k1;
s->x[4] ^= key->k2;
printstate("init 2nd key xor", s);
}
forceinline void ascon_adata(state_t* s, const uint8_t* ad, uint64_t adlen) {
const int nr = (ASCON_AEAD_RATE == 8) ? 6 : 8;
if (adlen) {
/* full associated data blocks */
while (adlen >= ASCON_AEAD_RATE) {
s->x[0] ^= LOAD(ad, 8);
if (ASCON_AEAD_RATE == 16) s->x[1] ^= LOAD(ad + 8, 8);
printstate("absorb adata", s);
P(s, nr);
ad += ASCON_AEAD_RATE;
adlen -= ASCON_AEAD_RATE;
}
/* final associated data block */
uint64_t* px = &s->x[0];
if (ASCON_AEAD_RATE == 16 && adlen >= 8) {
s->x[0] ^= LOAD(ad, 8);
px = &s->x[1];
ad += 8;
adlen -= 8;
}
*px ^= PAD(adlen);
if (adlen) *px ^= LOAD(ad, adlen);
printstate("pad adata", s);
P(s, nr);
}
/* domain separation */
s->x[4] ^= 1;
printstate("domain separation", s);
}
forceinline void ascon_encrypt(state_t* s, uint8_t* c, const uint8_t* m,
uint64_t mlen) {
const int nr = (ASCON_AEAD_RATE == 8) ? 6 : 8;
/* full plaintext blocks */
while (mlen >= ASCON_AEAD_RATE) {
s->x[0] ^= LOAD(m, 8);
STORE(c, s->x[0], 8);
if (ASCON_AEAD_RATE == 16) {
s->x[1] ^= LOAD(m + 8, 8);
STORE(c + 8, s->x[1], 8);
}
printstate("absorb plaintext", s);
P(s, nr);
m += ASCON_AEAD_RATE;
c += ASCON_AEAD_RATE;
mlen -= ASCON_AEAD_RATE;
}
/* final plaintext block */
uint64_t* px = &s->x[0];
if (ASCON_AEAD_RATE == 16 && mlen >= 8) {
s->x[0] ^= LOAD(m, 8);
STORE(c, s->x[0], 8);
px = &s->x[1];
m += 8;
c += 8;
mlen -= 8;
}
*px ^= PAD(mlen);
if (mlen) {
*px ^= LOAD(m, mlen);
STORE(c, *px, mlen);
}
printstate("pad plaintext", s);
}
forceinline void ascon_decrypt(state_t* s, uint8_t* m, const uint8_t* c,
uint64_t clen) {
const int nr = (ASCON_AEAD_RATE == 8) ? 6 : 8;
/* full ciphertext blocks */
while (clen >= ASCON_AEAD_RATE) {
uint64_t cx = LOAD(c, 8);
s->x[0] ^= cx;
STORE(m, s->x[0], 8);
s->x[0] = cx;
if (ASCON_AEAD_RATE == 16) {
cx = LOAD(c + 8, 8);
s->x[1] ^= cx;
STORE(m + 8, s->x[1], 8);
s->x[1] = cx;
}
printstate("insert ciphertext", s);
P(s, nr);
m += ASCON_AEAD_RATE;
c += ASCON_AEAD_RATE;
clen -= ASCON_AEAD_RATE;
}
/* final ciphertext block */
uint64_t* px = &s->x[0];
if (ASCON_AEAD_RATE == 16 && clen >= 8) {
uint64_t cx = LOAD(c, 8);
s->x[0] ^= cx;
STORE(m, s->x[0], 8);
s->x[0] = cx;
px = &s->x[1];
m += 8;
c += 8;
clen -= 8;
}
*px ^= PAD(clen);
if (clen) {
uint64_t cx = LOAD(c, clen);
*px ^= cx;
STORE(m, *px, clen);
*px = CLEAR(*px, clen);
*px ^= cx;
}
printstate("pad ciphertext", s);
}
forceinline void ascon_final(state_t* s, const key_t* key) {
#if CRYPTO_KEYBYTES == 16
if (ASCON_AEAD_RATE == 8) {
s->x[1] ^= key->k1;
s->x[2] ^= key->k2;
} else {
s->x[2] ^= key->k1;
s->x[3] ^= key->k2;
}
#else /* CRYPTO_KEYBYTES == 20 */
s->x[1] ^= KEYROT(key->k0, key->k1);
s->x[2] ^= KEYROT(key->k1, key->k2);
s->x[3] ^= KEYROT(key->k2, 0);
#endif
printstate("final 1st key xor", s);
P(s, 12);
s->x[3] ^= key->k1;
s->x[4] ^= key->k2;
printstate("final 2nd key xor", s);
}
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_t s;
(void)nsec;
*clen = mlen + CRYPTO_ABYTES;
/* perform ascon computation */
key_t key;
ascon_loadkey(&key, k);
ascon_initaead(&s, npub, &key);
ascon_adata(&s, ad, adlen);
ascon_encrypt(&s, c, m, mlen);
ascon_final(&s, &key);
/* set tag */
STOREBYTES(c + mlen, s.x[3], 8);
STOREBYTES(c + mlen + 8, s.x[4], 8);
return 0;
}
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) {
state_t s;
(void)nsec;
if (clen < CRYPTO_ABYTES) return -1;
*mlen = clen = clen - CRYPTO_ABYTES;
/* perform ascon computation */
key_t key;
ascon_loadkey(&key, k);
ascon_initaead(&s, npub, &key);
ascon_adata(&s, ad, adlen);
ascon_decrypt(&s, m, c, clen);
ascon_final(&s, &key);
/* verify tag (should be constant time, check compiler output) */
s.x[3] ^= LOADBYTES(c + clen, 8);
s.x[4] ^= LOADBYTES(c + clen + 8, 8);
return NOTZERO(s.x[3], s.x[4]);
}
#endif
#ifndef ENDIAN_H_
#define ENDIAN_H_
#if defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
/* macros for big endian machines */
#ifdef PRAGMA_ENDIAN
#pragma message("Using macros for big endian machines")
#endif
#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 */
#ifdef PRAGMA_ENDIAN
#pragma message("Using macros for little endian machines")
#endif
#define U64BIG(x) \
(((0x00000000000000FFULL & (x)) << 56) | \
((0x000000000000FF00ULL & (x)) << 40) | \
((0x0000000000FF0000ULL & (x)) << 24) | \
((0x00000000FF000000ULL & (x)) << 8) | \
((0x000000FF00000000ULL & (x)) >> 8) | \
((0x0000FF0000000000ULL & (x)) >> 24) | \
((0x00FF000000000000ULL & (x)) >> 40) | \
((0xFF00000000000000ULL & (x)) >> 56))
#define U32BIG(x) \
(((0x000000FF & (x)) << 24) | ((0x0000FF00 & (x)) << 8) | \
((0x00FF0000 & (x)) >> 8) | ((0xFF000000 & (x)) >> 24))
#define U16BIG(x) (((0x00FF & (x)) << 8) | ((0xFF00 & (x)) >> 8))
#else
#error "Ascon byte order macros not defined in endian.h"
#endif
#endif /* ENDIAN_H_ */
#ifndef FORCEINLINE_H_
#define FORCEINLINE_H_
/* define forceinline macro */
#ifdef _MSC_VER
#define forceinline __forceinline
#elif defined(__GNUC__)
#define forceinline inline __attribute__((__always_inline__))
#elif defined(__CLANG__)
#if __has_attribute(__always_inline__)
#define forceinline inline __attribute__((__always_inline__))
#else
#define forceinline inline
#endif
#else
#define forceinline inline
#endif
#endif /* FORCEINLINE_H_ */
#include "interleave.h"
#if !ASCON_EXTERN_BI
const uint32_t B[3] = {0x22222222, 0x0c0c0c0c, 0x00f000f0};
#if !ASCON_INLINE_BI
uint64_t TOBI(uint64_t in) { return deinterleave32(in); }
uint64_t FROMBI(uint64_t in) { return interleave32(in); }
#endif
#endif
#ifndef INTERLEAVE_H_
#define INTERLEAVE_H_
#include <stdint.h>
#include "config.h"
#include "endian.h"
#include "forceinline.h"
#if ASCON_INLINE_BI
#define TOBI deinterleave32
#define FROMBI interleave32
#else
uint64_t TOBI(uint64_t in);
uint64_t FROMBI(uint64_t in);
#endif
extern const uint32_t B[3];
forceinline uint32_t deinterleave16(uint32_t x) {
uint32_t t;
t = (x ^ (x >> 1)) & B[0], x ^= t ^ (t << 1);
t = (x ^ (x >> 2)) & B[1], x ^= t ^ (t << 2);
t = (x ^ (x >> 4)) & B[2], x ^= t ^ (t << 4);
t = (x ^ (x >> 8)) & 0xff00, x ^= t ^ (t << 8);
return x;
}
forceinline uint32_t interleave16(uint32_t x) {
uint32_t t;
t = (x ^ (x >> 8)) & 0xff00, x ^= t ^ (t << 8);
t = (x ^ (x >> 4)) & B[2], x ^= t ^ (t << 4);
t = (x ^ (x >> 2)) & B[1], x ^= t ^ (t << 2);
t = (x ^ (x >> 1)) & B[0], x ^= t ^ (t << 1);
return x;
}
/* credit to Henry S. Warren, Hacker's Delight, Addison-Wesley, 2002 */
forceinline uint64_t deinterleave32(uint64_t in) {
in = U64BIG(in);
uint32_t hi = in >> 32;
uint32_t lo = in;
uint32_t t0, t1, e, o;
t0 = deinterleave16(lo);
t1 = deinterleave16(hi);
e = (t1 << 16) | (t0 & 0x0000FFFF);
o = (t1 & 0xFFFF0000) | (t0 >> 16);
return (uint64_t)o << 32 | e;
}
/* credit to Henry S. Warren, Hacker's Delight, Addison-Wesley, 2002 */
forceinline uint64_t interleave32(uint64_t in) {
uint32_t e = in;
uint32_t o = in >> 32;
uint32_t t0, t1, lo, hi;
t0 = (o << 16) | (e & 0x0000FFFF);
t1 = (o & 0xFFFF0000) | (e >> 16);
lo = interleave16(t0);
hi = interleave16(t1);
return U64BIG((uint64_t)hi << 32 | lo);
}
#endif /* INTERLEAVE_H_ */
#include "permutations.h"
#if !ASCON_INLINE_PERM && ASCON_UNROLL_LOOPS
void P12(state_t* s) { P12ROUNDS(s); }
#endif
#if ((defined(ASCON_AEAD_RATE) && ASCON_AEAD_RATE == 16) || \
(defined(ASCON_HASH_ROUNDS) && ASCON_HASH_ROUNDS == 8)) && \
!ASCON_INLINE_PERM && ASCON_UNROLL_LOOPS
void P8(state_t* s) { P8ROUNDS(s); }
#endif
#if (defined(ASCON_AEAD_RATE) && ASCON_AEAD_RATE == 8) && \
!ASCON_INLINE_PERM && ASCON_UNROLL_LOOPS
void P6(state_t* s) { P6ROUNDS(s); }
#endif
#if !ASCON_INLINE_PERM && !ASCON_UNROLL_LOOPS
void P(state_t* s, int nr) { PROUNDS(s, nr); }
#endif
#ifndef PERMUTATIONS_H_
#define PERMUTATIONS_H_
#include <stdint.h>
#include "api.h"
#include "ascon.h"
#include "config.h"
#include "constants.h"
#include "printstate.h"
#include "round.h"
#define LOADSTATE(s, a, b, c, d, e) \
do { \
a.x = s->x[0]; \
b.x = s->x[1]; \
c.x = s->x[2]; \
d.x = s->x[3]; \
e.x = s->x[4]; \
} while (0)
#define STORESTATE(s, a, b, c, d, e) \
do { \
s->x[0] = a.x; \
s->x[1] = b.x; \
s->x[2] = c.x; \
s->x[3] = d.x; \
s->x[4] = e.x; \
} while (0)
forceinline void P12ROUNDS(state_t* s) {
word_t x0, x1, x2, x3, x4;
LOADSTATE(s, x0, x1, x2, x3, x4);
ROUND5(x0, x1, x2, x3, x4, RC0);
ROUND5(x2, x3, x4, x0, x1, RC1);
ROUND5(x4, x0, x1, x2, x3, RC2);
ROUND5(x1, x2, x3, x4, x0, RC3);
ROUND5(x3, x4, x0, x1, x2, RC4);
ROUND5(x0, x1, x2, x3, x4, RC5);
ROUND5(x2, x3, x4, x0, x1, RC6);
ROUND5(x4, x0, x1, x2, x3, RC7);
ROUND5(x1, x2, x3, x4, x0, RC8);
ROUND5(x3, x4, x0, x1, x2, RC9);
#if !ASCON_INLINE_PERM
ROUND5(x0, x1, x2, x3, x4, RCa);
ROUND5(x2, x3, x4, x0, x1, RCb);
STORESTATE(s, x4, x0, x1, x2, x3);
#else
STORESTATE(s, x0, x1, x2, x3, x4);
ROUND(s, RCa);
ROUND(s, RCb);
#endif
}
forceinline void P8ROUNDS(state_t* s) {
word_t x0, x1, x2, x3, x4;
LOADSTATE(s, x0, x1, x2, x3, x4);
ROUND5(x0, x1, x2, x3, x4, RC4);
ROUND5(x2, x3, x4, x0, x1, RC5);
ROUND5(x4, x0, x1, x2, x3, RC6);
ROUND5(x1, x2, x3, x4, x0, RC7);
ROUND5(x3, x4, x0, x1, x2, RC8);
#if !ASCON_INLINE_PERM
ROUND5(x0, x1, x2, x3, x4, RC9);
ROUND5(x2, x3, x4, x0, x1, RCa);
ROUND5(x4, x0, x1, x2, x3, RCb);
STORESTATE(s, x1, x2, x3, x4, x0);
#else /* ASCON_INLINE_PERM */
STORESTATE(s, x0, x1, x2, x3, x4);
ROUND(s, RC9);
ROUND(s, RCa);
ROUND(s, RCb);
#endif
}
forceinline void P6ROUNDS(state_t* s) {
word_t x0, x1, x2, x3, x4;
LOADSTATE(s, x0, x1, x2, x3, x4);
ROUND5(x0, x1, x2, x3, x4, RC6);
ROUND5(x2, x3, x4, x0, x1, RC7);
ROUND5(x4, x0, x1, x2, x3, RC8);
ROUND5(x1, x2, x3, x4, x0, RC9);
ROUND5(x3, x4, x0, x1, x2, RCa);
#if !ASCON_INLINE_PERM
ROUND5(x0, x1, x2, x3, x4, RCb);
STORESTATE(s, x2, x3, x4, x0, x1);
#else /* ASCON_INLINE_PERM */
STORESTATE(s, x0, x1, x2, x3, x4);
ROUND(s, RCb);
#endif
}
#if ASCON_INLINE_PERM && ASCON_UNROLL_LOOPS
forceinline void P(state_t* s, int nr) {
if (nr == 12) P12ROUNDS(s);
if (nr == 8) P8ROUNDS(s);
if (nr == 6) P6ROUNDS(s);
}
#elif !ASCON_INLINE_PERM && ASCON_UNROLL_LOOPS
void P12(state_t* s);
void P8(state_t* s);
void P6(state_t* s);
forceinline void P(state_t* s, int nr) {
if (nr == 12) P12(s);
if (nr == 8) P8(s);
if (nr == 6) P6(s);
}
#elif ASCON_INLINE_PERM && !ASCON_UNROLL_LOOPS
forceinline void P(state_t* s, int nr) { PROUNDS(s, nr); }
#else /* !ASCON_INLINE_PERM && !ASCON_UNROLL_LOOPS */
void P(state_t* s, int nr);
#endif
#endif /* PERMUTATIONS_H_ */
#ifdef ASCON_PRINT_STATE
#include "printstate.h"
#include <inttypes.h>
#include <stdio.h>
#include <string.h>
#ifndef WORDTOU64
#define WORDTOU64
#endif
#ifndef U64BIG
#define U64BIG
#endif
void printword(const char* text, const uint64_t x) {
printf("%s=%016" PRIx64, text, U64BIG(WORDTOU64(x)));
}
void printstate(const char* text, const state_t* s) {
printf("%s:", text);
for (int i = strlen(text); i < 17; ++i) printf(" ");
printword(" x0", s->x[0]);
printword(" x1", s->x[1]);
printword(" x2", s->x[2]);
printword(" x3", s->x[3]);
printword(" x4", s->x[4]);
#ifdef ASCON_PRINT_BI
printf(" ");
printf(" x0=%08x_%08x", s->w[0][1], s->w[0][0]);
printf(" x1=%08x_%08x", s->w[1][1], s->w[1][0]);
printf(" x2=%08x_%08x", s->w[2][1], s->w[2][0]);
printf(" x3=%08x_%08x", s->w[3][1], s->w[3][0]);
printf(" x4=%08x_%08x", s->w[4][1], s->w[4][0]);
#endif
printf("\n");
}
#endif
#ifndef PRINTSTATE_H_
#define PRINTSTATE_H_
#ifdef ASCON_PRINT_STATE
#include "ascon.h"
#include "word.h"
void printword(const char* text, const uint64_t x);
void printstate(const char* text, const state_t* s);
#else
#define printword(text, w) \
do { \
} while (0)
#define printstate(text, s) \
do { \
} while (0)
#endif
#endif /* PRINTSTATE_H_ */
#ifndef WORD_H_
#define WORD_H_
#include <stdint.h>
#include <string.h>
#include "config.h"
#include "endian.h"
#include "forceinline.h"
#include "interleave.h"
#if ASCON_EXTERN_BI
#define U64TOWORD(x) U64BIG(x)
#define WORDTOU64(x) U64BIG(x)
#else
#define U64TOWORD(x) TOBI(x)
#define WORDTOU64(x) FROMBI(x)
#endif
typedef union {
uint64_t x;
uint32_t w[2];
uint8_t b[8];
} word_t;
forceinline uint32_t ROR32(uint32_t x, int n) {
return x >> n | x << (-n & 31);
}
forceinline uint64_t ROR(uint64_t x, int n) {
word_t b, a = {.x = x};
b.w[0] = (n % 2) ? ROR32(a.w[1], (n - 1) / 2) : ROR32(a.w[0], n / 2);
b.w[1] = (n % 2) ? ROR32(a.w[0], (n + 1) / 2) : ROR32(a.w[1], n / 2);
return b.x;
}
forceinline uint64_t KEYROT(uint64_t a, uint64_t b) {
word_t w, lo2hi = {.x = a}, hi2lo = {.x = b};
w.w[0] = lo2hi.w[0] << 16 | hi2lo.w[0] >> 16;
w.w[1] = lo2hi.w[1] << 16 | hi2lo.w[1] >> 16;
return w.x;
}
forceinline int NOTZERO(uint64_t a, uint64_t b) {
uint64_t result = a | b;
result |= result >> 32;
result |= result >> 16;
result |= result >> 8;
return ((((int)(result & 0xff) - 1) >> 8) & 1) - 1;
}
#if ASCON_EXTERN_BI
forceinline uint64_t PAD(int i) { return 0x80ull << (56 - 8 * i); }
forceinline uint64_t PRFS_MLEN(uint64_t len) { return len << 51; }
forceinline uint64_t CLEAR(uint64_t w, int n) {
/* undefined for n == 0 */
uint64_t mask = ~0ull >> (8 * n);
return w & mask;
}
#else
forceinline uint64_t PAD(int i) {
return ((uint64_t)((uint32_t)0x08 << (28 - 4 * i)) << 32);
}
forceinline uint64_t PRFS_MLEN(uint64_t len) {
return ((len & 0x01) << 57) | /* 0000x */
((len & 0x02) << 25) | /* 000x0 */
((len & 0x04) << 56) | /* 00x00 */
((len & 0x08) << 24) | /* 0x000 */
((len & 0x10) << 55); /* x0000 */
}
forceinline uint64_t CLEAR(uint64_t w, int n) {
/* undefined for n == 0 */
uint32_t mask = 0xffffffffull >> (4 * n);
return w & ((uint64_t)mask << 32 | mask);
}
#endif
forceinline uint64_t MASK(int n) {
/* undefined for n == 0 */
return ~0ull >> (64 - 8 * n);
}
forceinline uint64_t LOAD(const uint8_t* bytes, int n) {
uint64_t x = *(uint64_t*)bytes & MASK(n);
return U64TOWORD(x);
}
forceinline void STORE(uint8_t* bytes, uint64_t w, int n) {
*(uint64_t*)bytes &= ~MASK(n);
*(uint64_t*)bytes |= WORDTOU64(w);
}
forceinline uint64_t LOADBYTES(const uint8_t* bytes, int n) {
uint64_t x = 0;
memcpy(&x, bytes, n);
return U64TOWORD(x);
}
forceinline void STOREBYTES(uint8_t* bytes, uint64_t w, int n) {
uint64_t x = WORDTOU64(w);
memcpy(bytes, &x, n);
}
#endif /* WORD_H_ */
#pragma GCC push_options
#pragma GCC optimize ("Os")
#include "api.h"
#include "ascon.h"
#include "permutations.h"
#include "printstate.h"
#if !ASCON_INLINE_MODE
#undef forceinline
#define forceinline
#endif
#ifdef ASCON_AEAD_RATE
forceinline void ascon_loadkey(key_t* key, const uint8_t* k) {
#if CRYPTO_KEYBYTES == 16
key->k1 = LOAD(k, 8);
key->k2 = LOAD(k + 8, 8);
#else /* CRYPTO_KEYBYTES == 20 */
key->k0 = KEYROT(0, LOADBYTES(k, 4));
key->k1 = LOADBYTES(k + 4, 8);
key->k2 = LOADBYTES(k + 12, 8);
#endif
}
forceinline void ascon_initaead(state_t* s, const uint8_t* npub,
const key_t* key) {
#if CRYPTO_KEYBYTES == 16
if (ASCON_AEAD_RATE == 8) s->x[0] = ASCON_128_IV;
if (ASCON_AEAD_RATE == 16) s->x[0] = ASCON_128A_IV;
#else /* CRYPTO_KEYBYTES == 20 */
s->x[0] = ASCON_80PQ_IV ^ key->k0;
#endif
s->x[1] = key->k1;
s->x[2] = key->k2;
s->x[3] = LOAD(npub, 8);
s->x[4] = LOAD(npub + 8, 8);
printstate("init 1st key xor", s);
P(s, 12);
#if CRYPTO_KEYBYTES == 20
s->x[2] ^= key->k0;
#endif
s->x[3] ^= key->k1;
s->x[4] ^= key->k2;
printstate("init 2nd key xor", s);
}
forceinline void ascon_final(state_t* s, const key_t* key) {
#if CRYPTO_KEYBYTES == 16
if (ASCON_AEAD_RATE == 8) {
s->x[1] ^= key->k1;
s->x[2] ^= key->k2;
} else {
s->x[2] ^= key->k1;
s->x[3] ^= key->k2;
}
#else /* CRYPTO_KEYBYTES == 20 */
s->x[1] ^= KEYROT(key->k0, key->k1);
s->x[2] ^= KEYROT(key->k1, key->k2);
s->x[3] ^= KEYROT(key->k2, 0);
#endif
printstate("final 1st key xor", s);
P(s, 12);
s->x[3] ^= key->k1;
s->x[4] ^= key->k2;
printstate("final 2nd key xor", s);
}
void ascon_aead(uint8_t* t, uint8_t* out, const uint8_t* in, uint64_t tlen,
const uint8_t* ad, uint64_t adlen, const uint8_t* npub,
const uint8_t* k, uint8_t mode) {
const int nr = (ASCON_AEAD_RATE == 8) ? 6 : 8;
key_t key;
ascon_loadkey(&key, k);
/* initialize */
state_t s;
ascon_initaead(&s, npub, &key);
/* process associated data */
if (adlen) {
ascon_update(&s, (void*)0, ad, adlen, ASCON_ABSORB);
printstate("pad adata", &s);
P(&s, nr);
}
/* domain separation */
s.x[4] ^= 1;
printstate("domain separation", &s);
/* process plaintext/ciphertext */
ascon_update(&s, out, in, tlen, mode);
if (mode == ASCON_ENCRYPT) printstate("pad plaintext", &s);
if (mode == ASCON_DECRYPT) printstate("pad ciphertext", &s);
/* finalize */
ascon_final(&s, &key);
((uint64_t*)t)[0] = WORDTOU64(s.x[3]);
((uint64_t*)t)[1] = WORDTOU64(s.x[4]);
}
#endif
#pragma GCC pop_options
#pragma GCC push_options
#pragma GCC optimize ("Os")
#include "api.h"
#include "ascon.h"
#include "permutations.h"
#include "printstate.h"
#if !ASCON_INLINE_MODE
#undef forceinline
#define forceinline
#endif
#ifdef ASCON_AEAD_RATE
forceinline void ascon_loadkey(key_t* key, const uint8_t* k) {
#if CRYPTO_KEYBYTES == 16
key->k1 = LOAD(k, 8);
key->k2 = LOAD(k + 8, 8);
#else /* CRYPTO_KEYBYTES == 20 */
key->k0 = KEYROT(0, LOADBYTES(k, 4));
key->k1 = LOADBYTES(k + 4, 8);
key->k2 = LOADBYTES(k + 12, 8);
#endif
}
forceinline void ascon_initaead(state_t* s, const uint8_t* npub,
const key_t* key) {
#if CRYPTO_KEYBYTES == 16
if (ASCON_AEAD_RATE == 8) s->x[0] = ASCON_128_IV;
if (ASCON_AEAD_RATE == 16) s->x[0] = ASCON_128A_IV;
#else /* CRYPTO_KEYBYTES == 20 */
s->x[0] = ASCON_80PQ_IV ^ key->k0;
#endif
s->x[1] = key->k1;
s->x[2] = key->k2;
s->x[3] = LOAD(npub, 8);
s->x[4] = LOAD(npub + 8, 8);
printstate("init 1st key xor", s);
P(s, 12);
#if CRYPTO_KEYBYTES == 20
s->x[2] ^= key->k0;
#endif
s->x[3] ^= key->k1;
s->x[4] ^= key->k2;
printstate("init 2nd key xor", s);
}
forceinline void ascon_final(state_t* s, const key_t* key) {
#if CRYPTO_KEYBYTES == 16
if (ASCON_AEAD_RATE == 8) {
s->x[1] ^= key->k1;
s->x[2] ^= key->k2;
} else {
s->x[2] ^= key->k1;
s->x[3] ^= key->k2;
}
#else /* CRYPTO_KEYBYTES == 20 */
s->x[1] ^= KEYROT(key->k0, key->k1);
s->x[2] ^= KEYROT(key->k1, key->k2);
s->x[3] ^= KEYROT(key->k2, 0);
#endif
printstate("final 1st key xor", s);
P(s, 12);
s->x[3] ^= key->k1;
s->x[4] ^= key->k2;
printstate("final 2nd key xor", s);
}
void ascon_aead(uint8_t* t, uint8_t* out, const uint8_t* in, uint64_t tlen,
const uint8_t* ad, uint64_t adlen, const uint8_t* npub,
const uint8_t* k, uint8_t mode) {
const int nr = (ASCON_AEAD_RATE == 8) ? 6 : 8;
key_t key;
ascon_loadkey(&key, k);
/* initialize */
state_t s;
ascon_initaead(&s, npub, &key);
/* process associated data */
if (adlen) {
ascon_update(&s, (void*)0, ad, adlen, ASCON_ABSORB);
printstate("pad adata", &s);
P(&s, nr);
}
/* domain separation */
s.x[4] ^= 1;
printstate("domain separation", &s);
/* process plaintext/ciphertext */
ascon_update(&s, out, in, tlen, mode);
if (mode == ASCON_ENCRYPT) printstate("pad plaintext", &s);
if (mode == ASCON_DECRYPT) printstate("pad ciphertext", &s);
/* finalize */
ascon_final(&s, &key);
((uint64_t*)t)[0] = WORDTOU64(s.x[3]);
((uint64_t*)t)[1] = WORDTOU64(s.x[4]);
}
#endif
#pragma GCC pop_options
#pragma GCC push_options
#pragma GCC optimize ("Os")
#include "api.h"
#include "ascon.h"
#include "permutations.h"
#include "printstate.h"
#if !ASCON_INLINE_MODE
#undef forceinline
#define forceinline
#endif
#ifdef ASCON_AEAD_RATE
forceinline void ascon_loadkey(key_t* key, const uint8_t* k) {
#if CRYPTO_KEYBYTES == 16
key->k1 = LOAD(k, 8);
key->k2 = LOAD(k + 8, 8);
#else /* CRYPTO_KEYBYTES == 20 */
key->k0 = KEYROT(0, LOADBYTES(k, 4));
key->k1 = LOADBYTES(k + 4, 8);
key->k2 = LOADBYTES(k + 12, 8);
#endif
}
forceinline void ascon_initaead(state_t* s, const uint8_t* npub,
const key_t* key) {
#if CRYPTO_KEYBYTES == 16
if (ASCON_AEAD_RATE == 8) s->x[0] = ASCON_128_IV;
if (ASCON_AEAD_RATE == 16) s->x[0] = ASCON_128A_IV;
#else /* CRYPTO_KEYBYTES == 20 */
s->x[0] = ASCON_80PQ_IV ^ key->k0;
#endif
s->x[1] = key->k1;
s->x[2] = key->k2;
s->x[3] = LOAD(npub, 8);
s->x[4] = LOAD(npub + 8, 8);
printstate("init 1st key xor", s);
P(s, 12);
#if CRYPTO_KEYBYTES == 20
s->x[2] ^= key->k0;
#endif
s->x[3] ^= key->k1;
s->x[4] ^= key->k2;
printstate("init 2nd key xor", s);
}
forceinline void ascon_final(state_t* s, const key_t* key) {
#if CRYPTO_KEYBYTES == 16
if (ASCON_AEAD_RATE == 8) {
s->x[1] ^= key->k1;
s->x[2] ^= key->k2;
} else {
s->x[2] ^= key->k1;
s->x[3] ^= key->k2;
}
#else /* CRYPTO_KEYBYTES == 20 */
s->x[1] ^= KEYROT(key->k0, key->k1);
s->x[2] ^= KEYROT(key->k1, key->k2);
s->x[3] ^= KEYROT(key->k2, 0);
#endif
printstate("final 1st key xor", s);
P(s, 12);
s->x[3] ^= key->k1;
s->x[4] ^= key->k2;
printstate("final 2nd key xor", s);
}
void ascon_aead(uint8_t* t, uint8_t* out, const uint8_t* in, uint64_t tlen,
const uint8_t* ad, uint64_t adlen, const uint8_t* npub,
const uint8_t* k, uint8_t mode) {
const int nr = (ASCON_AEAD_RATE == 8) ? 6 : 8;
key_t key;
ascon_loadkey(&key, k);
/* initialize */
state_t s;
ascon_initaead(&s, npub, &key);
/* process associated data */
if (adlen) {
ascon_update(&s, (void*)0, ad, adlen, ASCON_ABSORB);
printstate("pad adata", &s);
P(&s, nr);
}
/* domain separation */
s.x[4] ^= 1;
printstate("domain separation", &s);
/* process plaintext/ciphertext */
ascon_update(&s, out, in, tlen, mode);
if (mode == ASCON_ENCRYPT) printstate("pad plaintext", &s);
if (mode == ASCON_DECRYPT) printstate("pad ciphertext", &s);
/* finalize */
ascon_final(&s, &key);
((uint64_t*)t)[0] = WORDTOU64(s.x[3]);
((uint64_t*)t)[1] = WORDTOU64(s.x[4]);
}
#endif
#pragma GCC pop_options
#pragma GCC push_options
#pragma GCC optimize ("Os")
#include "api.h"
#include "ascon.h"
#include "permutations.h"
#include "printstate.h"
#if !ASCON_INLINE_MODE
#undef forceinline
#define forceinline
#endif
#ifdef ASCON_AEAD_RATE
forceinline void ascon_loadkey(key_t* key, const uint8_t* k) {
#if CRYPTO_KEYBYTES == 16
key->k1 = LOAD(k, 8);
key->k2 = LOAD(k + 8, 8);
#else /* CRYPTO_KEYBYTES == 20 */
key->k0 = KEYROT(0, LOADBYTES(k, 4));
key->k1 = LOADBYTES(k + 4, 8);
key->k2 = LOADBYTES(k + 12, 8);
#endif
}
forceinline void ascon_initaead(state_t* s, const uint8_t* npub,
const key_t* key) {
#if CRYPTO_KEYBYTES == 16
if (ASCON_AEAD_RATE == 8) s->x[0] = ASCON_128_IV;
if (ASCON_AEAD_RATE == 16) s->x[0] = ASCON_128A_IV;
#else /* CRYPTO_KEYBYTES == 20 */
s->x[0] = ASCON_80PQ_IV ^ key->k0;
#endif
s->x[1] = key->k1;
s->x[2] = key->k2;
s->x[3] = LOAD(npub, 8);
s->x[4] = LOAD(npub + 8, 8);
printstate("init 1st key xor", s);
P(s, 12);
#if CRYPTO_KEYBYTES == 20
s->x[2] ^= key->k0;
#endif
s->x[3] ^= key->k1;
s->x[4] ^= key->k2;
printstate("init 2nd key xor", s);
}
forceinline void ascon_final(state_t* s, const key_t* key) {
#if CRYPTO_KEYBYTES == 16
if (ASCON_AEAD_RATE == 8) {
s->x[1] ^= key->k1;
s->x[2] ^= key->k2;
} else {
s->x[2] ^= key->k1;
s->x[3] ^= key->k2;
}
#else /* CRYPTO_KEYBYTES == 20 */
s->x[1] ^= KEYROT(key->k0, key->k1);
s->x[2] ^= KEYROT(key->k1, key->k2);
s->x[3] ^= KEYROT(key->k2, 0);
#endif
printstate("final 1st key xor", s);
P(s, 12);
s->x[3] ^= key->k1;
s->x[4] ^= key->k2;
printstate("final 2nd key xor", s);
}
void ascon_aead(uint8_t* t, uint8_t* out, const uint8_t* in, uint64_t tlen,
const uint8_t* ad, uint64_t adlen, const uint8_t* npub,
const uint8_t* k, uint8_t mode) {
const int nr = (ASCON_AEAD_RATE == 8) ? 6 : 8;
key_t key;
ascon_loadkey(&key, k);
/* initialize */
state_t s;
ascon_initaead(&s, npub, &key);
/* process associated data */
if (adlen) {
ascon_update(&s, (void*)0, ad, adlen, ASCON_ABSORB);
printstate("pad adata", &s);
P(&s, nr);
}
/* domain separation */
s.x[4] ^= 1;
printstate("domain separation", &s);
/* process plaintext/ciphertext */
ascon_update(&s, out, in, tlen, mode);
if (mode == ASCON_ENCRYPT) printstate("pad plaintext", &s);
if (mode == ASCON_DECRYPT) printstate("pad ciphertext", &s);
/* finalize */
ascon_final(&s, &key);
((uint64_t*)t)[0] = WORDTOU64(s.x[3]);
((uint64_t*)t)[1] = WORDTOU64(s.x[4]);
}
#endif
#pragma GCC pop_options
#pragma GCC push_options
#pragma GCC optimize ("Os")
#include "api.h"
#include "ascon.h"
#include "permutations.h"
#include "printstate.h"
#if !ASCON_INLINE_MODE
#undef forceinline
#define forceinline
#endif
#ifdef ASCON_AEAD_RATE
forceinline void ascon_loadkey(key_t* key, const uint8_t* k) {
#if CRYPTO_KEYBYTES == 16
key->k1 = LOAD(k, 8);
key->k2 = LOAD(k + 8, 8);
#else /* CRYPTO_KEYBYTES == 20 */
key->k0 = KEYROT(0, LOADBYTES(k, 4));
key->k1 = LOADBYTES(k + 4, 8);
key->k2 = LOADBYTES(k + 12, 8);
#endif
}
forceinline void ascon_initaead(state_t* s, const uint8_t* npub,
const key_t* key) {
#if CRYPTO_KEYBYTES == 16
if (ASCON_AEAD_RATE == 8) s->x[0] = ASCON_128_IV;
if (ASCON_AEAD_RATE == 16) s->x[0] = ASCON_128A_IV;
#else /* CRYPTO_KEYBYTES == 20 */
s->x[0] = ASCON_80PQ_IV ^ key->k0;
#endif
s->x[1] = key->k1;
s->x[2] = key->k2;
s->x[3] = LOAD(npub, 8);
s->x[4] = LOAD(npub + 8, 8);
printstate("init 1st key xor", s);
P(s, 12);
#if CRYPTO_KEYBYTES == 20
s->x[2] ^= key->k0;
#endif
s->x[3] ^= key->k1;
s->x[4] ^= key->k2;
printstate("init 2nd key xor", s);
}
forceinline void ascon_final(state_t* s, const key_t* key) {
#if CRYPTO_KEYBYTES == 16
if (ASCON_AEAD_RATE == 8) {
s->x[1] ^= key->k1;
s->x[2] ^= key->k2;
} else {
s->x[2] ^= key->k1;
s->x[3] ^= key->k2;
}
#else /* CRYPTO_KEYBYTES == 20 */
s->x[1] ^= KEYROT(key->k0, key->k1);
s->x[2] ^= KEYROT(key->k1, key->k2);
s->x[3] ^= KEYROT(key->k2, 0);
#endif
printstate("final 1st key xor", s);
P(s, 12);
s->x[3] ^= key->k1;
s->x[4] ^= key->k2;
printstate("final 2nd key xor", s);
}
void ascon_aead(uint8_t* t, uint8_t* out, const uint8_t* in, uint64_t tlen,
const uint8_t* ad, uint64_t adlen, const uint8_t* npub,
const uint8_t* k, uint8_t mode) {
const int nr = (ASCON_AEAD_RATE == 8) ? 6 : 8;
key_t key;
ascon_loadkey(&key, k);
/* initialize */
state_t s;
ascon_initaead(&s, npub, &key);
/* process associated data */
if (adlen) {
ascon_update(&s, (void*)0, ad, adlen, ASCON_ABSORB);
printstate("pad adata", &s);
P(&s, nr);
}
/* domain separation */
s.x[4] ^= 1;
printstate("domain separation", &s);
/* process plaintext/ciphertext */
ascon_update(&s, out, in, tlen, mode);
if (mode == ASCON_ENCRYPT) printstate("pad plaintext", &s);
if (mode == ASCON_DECRYPT) printstate("pad ciphertext", &s);
/* finalize */
ascon_final(&s, &key);
((uint64_t*)t)[0] = WORDTOU64(s.x[3]);
((uint64_t*)t)[1] = WORDTOU64(s.x[4]);
}
#endif
#pragma GCC pop_options
#define CRYPTO_VERSION "1.2.6"
#define CRYPTO_KEYBYTES 16
#define CRYPTO_NSECBYTES 0
#define CRYPTO_NPUBBYTES 16
#define CRYPTO_ABYTES 16
#define CRYPTO_NOOVERLAP 1
#define ASCON_AEAD_RATE 8
#ifndef ASCON_H_
#define ASCON_H_
#include <stdint.h>
#include "word.h"
typedef union {
uint64_t x[5];
uint32_t w[5][2];
uint8_t b[5][8];
} state_t;
typedef struct {
#if (CRYPTO_KEYBYTES == 20)
uint64_t k0;
#endif
uint64_t k1;
uint64_t k2;
} key_t;
void ascon_initaead(state_t* s, const uint8_t* npub, const key_t* k);
void ascon_adata(state_t* s, const uint8_t* ad, uint64_t adlen);
void ascon_encrypt(state_t* s, uint8_t* c, const uint8_t* m, uint64_t mlen);
void ascon_decrypt(state_t* s, uint8_t* m, const uint8_t* c, uint64_t clen);
void ascon_final(state_t* s, const key_t* k);
void ascon_inithash(state_t* s);
void ascon_absorb(state_t* s, const uint8_t* in, uint64_t inlen);
void ascon_squeeze(state_t* s, uint8_t* out, uint64_t outlen);
#endif /* ASCON_H_ */
#ifndef CONFIG_H_
#define CONFIG_H_
/* inline the ascon mode */
#ifndef ASCON_INLINE_MODE
#define ASCON_INLINE_MODE 1
#endif
/* inline all permutations */
#ifndef ASCON_INLINE_PERM
#define ASCON_INLINE_PERM 0
#endif
/* unroll permutation loops */
#ifndef ASCON_UNROLL_LOOPS
#define ASCON_UNROLL_LOOPS 0
#endif
/* inline bitinterleaving */
#ifndef ASCON_INLINE_BI
#define ASCON_INLINE_BI 1
#endif
/* extern bitinterleaving */
#ifndef ASCON_EXTERN_BI
#define ASCON_EXTERN_BI 0
#endif
#endif /* CONFIG_H_ */
#include "constants.h"
#if !ASCON_UNROLL_LOOPS
const uint8_t constants[] = {0xc, 0xc, 0x9, 0xc, 0xc, 0x9, 0x9, 0x9,
0x6, 0xc, 0x3, 0xc, 0x6, 0x9, 0x3, 0x9,
0xc, 0x6, 0x9, 0x6, 0xc, 0x3, 0x9, 0x3};
#endif
#ifndef CONSTANTS_H_
#define CONSTANTS_H_
#include <stdint.h>
#define ASCON_128_KEYBYTES 16
#define ASCON_128A_KEYBYTES 16
#define ASCON_80PQ_KEYBYTES 20
#define ASCON_128_RATE 8
#define ASCON_128A_RATE 16
#define ASCON_HASH_RATE 8
#define ASCON_PRF_IN_RATE 32
#define ASCON_PRF_OUT_RATE 16
#define ASCON_128_PA_ROUNDS 12
#define ASCON_128_PB_ROUNDS 6
#define ASCON_128A_PA_ROUNDS 12
#define ASCON_128A_PB_ROUNDS 8
#define ASCON_HASH_PA_ROUNDS 12
#define ASCON_HASH_PB_ROUNDS 12
#define ASCON_HASHA_PA_ROUNDS 12
#define ASCON_HASHA_PB_ROUNDS 8
#define ASCON_PRF_PA_ROUNDS 12
#define ASCON_PRF_PB_ROUNDS 12
#define ASCON_128_IV 0x8021000008220000ull
#define ASCON_128A_IV 0x8822000000200000ull
#define ASCON_80PQ_IV 0xc021000008220000ull
#define ASCON_HASH_IV 0x0020000008200010ull
#define ASCON_HASHA_IV 0x0020000008220010ull
#define ASCON_XOF_IV 0x0020000008200000ull
#define ASCON_XOFA_IV 0x0020000008220000ull
#define ASCON_PRF_IV 0x88a0000000200000ull
#define ASCON_MAC_IV 0x88a0000800200000ull
#define ASCON_PRFS_IV 0x8028000000a00000ull
#define ASCON_HASH_IV0 0xf9afb5c6a540dbc7ull
#define ASCON_HASH_IV1 0xbd2493011445a340ull
#define ASCON_HASH_IV2 0xcb9ba8b5604d4fc8ull
#define ASCON_HASH_IV3 0x12a4eede94514c98ull
#define ASCON_HASH_IV4 0x4bca84c06339f398ull
#define ASCON_HASHA_IV0 0x0108e46d1b16eb02ull
#define ASCON_HASHA_IV1 0x5b9b8efdd29083f3ull
#define ASCON_HASHA_IV2 0x7ad665622891ae4aull
#define ASCON_HASHA_IV3 0x9dc27156ee3bfc7full
#define ASCON_HASHA_IV4 0xc61d5fa916801633ull
#define ASCON_XOF_IV0 0xc75782817e351ae6ull
#define ASCON_XOF_IV1 0x70045f441d238220ull
#define ASCON_XOF_IV2 0x5dd5ab52a13e3f04ull
#define ASCON_XOF_IV3 0x3e378142c30c1db2ull
#define ASCON_XOF_IV4 0x3735189db624d656ull
#define ASCON_XOFA_IV0 0x0846d7a5a4b87d44ull
#define ASCON_XOFA_IV1 0xaa6f1005b3a2dbf4ull
#define ASCON_XOFA_IV2 0xdc451146f713e811ull
#define ASCON_XOFA_IV3 0x468cb2532839e30dull
#define ASCON_XOFA_IV4 0xeb2d429709e96977ull
#define RC0 0x0000000c0000000cull
#define RC1 0x0000000c00000009ull
#define RC2 0x000000090000000cull
#define RC3 0x0000000900000009ull
#define RC4 0x0000000c00000006ull
#define RC5 0x0000000c00000003ull
#define RC6 0x0000000900000006ull
#define RC7 0x0000000900000003ull
#define RC8 0x000000060000000cull
#define RC9 0x0000000600000009ull
#define RCa 0x000000030000000cull
#define RCb 0x0000000300000009ull
#define RC(i) ((uint64_t)constants[i + 1] << 32 | constants[i])
#define START(n) (24 - 2 * (n))
#define INC 2
#define END 24
extern const uint8_t constants[];
#endif /* CONSTANTS_H_ */
#include "api.h"
#include "ascon.h"
#include "crypto_aead.h"
#include "permutations.h"
#include "printstate.h"
#if !ASCON_INLINE_MODE
#undef forceinline
#define forceinline
#endif
#ifdef ASCON_AEAD_RATE
forceinline void ascon_loadkey(key_t* key, const uint8_t* k) {
#if CRYPTO_KEYBYTES == 16
key->k1 = LOAD(k, 8);
key->k2 = LOAD(k + 8, 8);
#else /* CRYPTO_KEYBYTES == 20 */
key->k0 = KEYROT(0, LOADBYTES(k, 4));
key->k1 = LOADBYTES(k + 4, 8);
key->k2 = LOADBYTES(k + 12, 8);
#endif
}
forceinline void ascon_initaead(state_t* s, const uint8_t* npub,
const key_t* key) {
#if CRYPTO_KEYBYTES == 16
if (ASCON_AEAD_RATE == 8) s->x[0] = ASCON_128_IV;
if (ASCON_AEAD_RATE == 16) s->x[0] = ASCON_128A_IV;
#else /* CRYPTO_KEYBYTES == 20 */
s->x[0] = ASCON_80PQ_IV ^ key->k0;
#endif
s->x[1] = key->k1;
s->x[2] = key->k2;
s->x[3] = LOAD(npub, 8);
s->x[4] = LOAD(npub + 8, 8);
printstate("init 1st key xor", s);
P(s, 12);
#if CRYPTO_KEYBYTES == 20
s->x[2] ^= key->k0;
#endif
s->x[3] ^= key->k1;
s->x[4] ^= key->k2;
printstate("init 2nd key xor", s);
}
forceinline void ascon_adata(state_t* s, const uint8_t* ad, uint64_t adlen) {
const int nr = (ASCON_AEAD_RATE == 8) ? 6 : 8;
if (adlen) {
/* full associated data blocks */
while (adlen >= ASCON_AEAD_RATE) {
s->x[0] ^= LOAD(ad, 8);
if (ASCON_AEAD_RATE == 16) s->x[1] ^= LOAD(ad + 8, 8);
printstate("absorb adata", s);
P(s, nr);
ad += ASCON_AEAD_RATE;
adlen -= ASCON_AEAD_RATE;
}
/* final associated data block */
uint64_t* px = &s->x[0];
if (ASCON_AEAD_RATE == 16 && adlen >= 8) {
s->x[0] ^= LOAD(ad, 8);
px = &s->x[1];
ad += 8;
adlen -= 8;
}
*px ^= PAD(adlen);
if (adlen) *px ^= LOAD(ad, adlen);
printstate("pad adata", s);
P(s, nr);
}
/* domain separation */
s->x[4] ^= 1;
printstate("domain separation", s);
}
forceinline void ascon_encrypt(state_t* s, uint8_t* c, const uint8_t* m,
uint64_t mlen) {
const int nr = (ASCON_AEAD_RATE == 8) ? 6 : 8;
/* full plaintext blocks */
while (mlen >= ASCON_AEAD_RATE) {
s->x[0] ^= LOAD(m, 8);
STORE(c, s->x[0], 8);
if (ASCON_AEAD_RATE == 16) {
s->x[1] ^= LOAD(m + 8, 8);
STORE(c + 8, s->x[1], 8);
}
printstate("absorb plaintext", s);
P(s, nr);
m += ASCON_AEAD_RATE;
c += ASCON_AEAD_RATE;
mlen -= ASCON_AEAD_RATE;
}
/* final plaintext block */
uint64_t* px = &s->x[0];
if (ASCON_AEAD_RATE == 16 && mlen >= 8) {
s->x[0] ^= LOAD(m, 8);
STORE(c, s->x[0], 8);
px = &s->x[1];
m += 8;
c += 8;
mlen -= 8;
}
*px ^= PAD(mlen);
if (mlen) {
*px ^= LOAD(m, mlen);
STORE(c, *px, mlen);
}
printstate("pad plaintext", s);
}
forceinline void ascon_decrypt(state_t* s, uint8_t* m, const uint8_t* c,
uint64_t clen) {
const int nr = (ASCON_AEAD_RATE == 8) ? 6 : 8;
/* full ciphertext blocks */
while (clen >= ASCON_AEAD_RATE) {
uint64_t cx = LOAD(c, 8);
s->x[0] ^= cx;
STORE(m, s->x[0], 8);
s->x[0] = cx;
if (ASCON_AEAD_RATE == 16) {
cx = LOAD(c + 8, 8);
s->x[1] ^= cx;
STORE(m + 8, s->x[1], 8);
s->x[1] = cx;
}
printstate("insert ciphertext", s);
P(s, nr);
m += ASCON_AEAD_RATE;
c += ASCON_AEAD_RATE;
clen -= ASCON_AEAD_RATE;
}
/* final ciphertext block */
uint64_t* px = &s->x[0];
if (ASCON_AEAD_RATE == 16 && clen >= 8) {
uint64_t cx = LOAD(c, 8);
s->x[0] ^= cx;
STORE(m, s->x[0], 8);
s->x[0] = cx;
px = &s->x[1];
m += 8;
c += 8;
clen -= 8;
}
*px ^= PAD(clen);
if (clen) {
uint64_t cx = LOAD(c, clen);
*px ^= cx;
STORE(m, *px, clen);
*px = CLEAR(*px, clen);
*px ^= cx;
}
printstate("pad ciphertext", s);
}
forceinline void ascon_final(state_t* s, const key_t* key) {
#if CRYPTO_KEYBYTES == 16
if (ASCON_AEAD_RATE == 8) {
s->x[1] ^= key->k1;
s->x[2] ^= key->k2;
} else {
s->x[2] ^= key->k1;
s->x[3] ^= key->k2;
}
#else /* CRYPTO_KEYBYTES == 20 */
s->x[1] ^= KEYROT(key->k0, key->k1);
s->x[2] ^= KEYROT(key->k1, key->k2);
s->x[3] ^= KEYROT(key->k2, 0);
#endif
printstate("final 1st key xor", s);
P(s, 12);
s->x[3] ^= key->k1;
s->x[4] ^= key->k2;
printstate("final 2nd key xor", s);
}
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_t s;
(void)nsec;
*clen = mlen + CRYPTO_ABYTES;
/* perform ascon computation */
key_t key;
ascon_loadkey(&key, k);
ascon_initaead(&s, npub, &key);
ascon_adata(&s, ad, adlen);
ascon_encrypt(&s, c, m, mlen);
ascon_final(&s, &key);
/* set tag */
STOREBYTES(c + mlen, s.x[3], 8);
STOREBYTES(c + mlen + 8, s.x[4], 8);
return 0;
}
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) {
state_t s;
(void)nsec;
if (clen < CRYPTO_ABYTES) return -1;
*mlen = clen = clen - CRYPTO_ABYTES;
/* perform ascon computation */
key_t key;
ascon_loadkey(&key, k);
ascon_initaead(&s, npub, &key);
ascon_adata(&s, ad, adlen);
ascon_decrypt(&s, m, c, clen);
ascon_final(&s, &key);
/* verify tag (should be constant time, check compiler output) */
s.x[3] ^= LOADBYTES(c + clen, 8);
s.x[4] ^= LOADBYTES(c + clen + 8, 8);
return NOTZERO(s.x[3], s.x[4]);
}
#endif
#ifndef ENDIAN_H_
#define ENDIAN_H_
#if defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
/* macros for big endian machines */
#ifdef PRAGMA_ENDIAN
#pragma message("Using macros for big endian machines")
#endif
#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 */
#ifdef PRAGMA_ENDIAN
#pragma message("Using macros for little endian machines")
#endif
#define U64BIG(x) \
(((0x00000000000000FFULL & (x)) << 56) | \
((0x000000000000FF00ULL & (x)) << 40) | \
((0x0000000000FF0000ULL & (x)) << 24) | \
((0x00000000FF000000ULL & (x)) << 8) | \
((0x000000FF00000000ULL & (x)) >> 8) | \
((0x0000FF0000000000ULL & (x)) >> 24) | \
((0x00FF000000000000ULL & (x)) >> 40) | \
((0xFF00000000000000ULL & (x)) >> 56))
#define U32BIG(x) \
(((0x000000FF & (x)) << 24) | ((0x0000FF00 & (x)) << 8) | \
((0x00FF0000 & (x)) >> 8) | ((0xFF000000 & (x)) >> 24))
#define U16BIG(x) (((0x00FF & (x)) << 8) | ((0xFF00 & (x)) >> 8))
#else
#error "Ascon byte order macros not defined in endian.h"
#endif
#endif /* ENDIAN_H_ */
#ifndef FORCEINLINE_H_
#define FORCEINLINE_H_
/* define forceinline macro */
#ifdef _MSC_VER
#define forceinline __forceinline
#elif defined(__GNUC__)
#define forceinline inline __attribute__((__always_inline__))
#elif defined(__CLANG__)
#if __has_attribute(__always_inline__)
#define forceinline inline __attribute__((__always_inline__))
#else
#define forceinline inline
#endif
#else
#define forceinline inline
#endif
#endif /* FORCEINLINE_H_ */
#include "interleave.h"
#if !ASCON_EXTERN_BI
const uint32_t B[3] = {0x22222222, 0x0c0c0c0c, 0x00f000f0};
#if !ASCON_INLINE_BI
uint64_t TOBI(uint64_t in) { return deinterleave32(in); }
uint64_t FROMBI(uint64_t in) { return interleave32(in); }
#endif
#endif
#ifndef INTERLEAVE_H_
#define INTERLEAVE_H_
#include <stdint.h>
#include "config.h"
#include "endian.h"
#include "forceinline.h"
#if ASCON_INLINE_BI
#define TOBI deinterleave32
#define FROMBI interleave32
#else
uint64_t TOBI(uint64_t in);
uint64_t FROMBI(uint64_t in);
#endif
extern const uint32_t B[3];
forceinline uint32_t deinterleave16(uint32_t x) {
uint32_t t;
t = (x ^ (x >> 1)) & B[0], x ^= t ^ (t << 1);
t = (x ^ (x >> 2)) & B[1], x ^= t ^ (t << 2);
t = (x ^ (x >> 4)) & B[2], x ^= t ^ (t << 4);
t = (x ^ (x >> 8)) & 0xff00, x ^= t ^ (t << 8);
return x;
}
forceinline uint32_t interleave16(uint32_t x) {
uint32_t t;
t = (x ^ (x >> 8)) & 0xff00, x ^= t ^ (t << 8);
t = (x ^ (x >> 4)) & B[2], x ^= t ^ (t << 4);
t = (x ^ (x >> 2)) & B[1], x ^= t ^ (t << 2);
t = (x ^ (x >> 1)) & B[0], x ^= t ^ (t << 1);
return x;
}
/* credit to Henry S. Warren, Hacker's Delight, Addison-Wesley, 2002 */
forceinline uint64_t deinterleave32(uint64_t in) {
in = U64BIG(in);
uint32_t hi = in >> 32;
uint32_t lo = in;
uint32_t t0, t1, e, o;
t0 = deinterleave16(lo);
t1 = deinterleave16(hi);
e = (t1 << 16) | (t0 & 0x0000FFFF);
o = (t1 & 0xFFFF0000) | (t0 >> 16);
return (uint64_t)o << 32 | e;
}
/* credit to Henry S. Warren, Hacker's Delight, Addison-Wesley, 2002 */
forceinline uint64_t interleave32(uint64_t in) {
uint32_t e = in;
uint32_t o = in >> 32;
uint32_t t0, t1, lo, hi;
t0 = (o << 16) | (e & 0x0000FFFF);
t1 = (o & 0xFFFF0000) | (e >> 16);
lo = interleave16(t0);
hi = interleave16(t1);
return U64BIG((uint64_t)hi << 32 | lo);
}
#endif /* INTERLEAVE_H_ */
#include "permutations.h"
#if !ASCON_INLINE_PERM && ASCON_UNROLL_LOOPS
void P12(state_t* s) { P12ROUNDS(s); }
#endif
#if ((defined(ASCON_AEAD_RATE) && ASCON_AEAD_RATE == 16) || \
(defined(ASCON_HASH_ROUNDS) && ASCON_HASH_ROUNDS == 8)) && \
!ASCON_INLINE_PERM && ASCON_UNROLL_LOOPS
void P8(state_t* s) { P8ROUNDS(s); }
#endif
#if (defined(ASCON_AEAD_RATE) && ASCON_AEAD_RATE == 8) && \
!ASCON_INLINE_PERM && ASCON_UNROLL_LOOPS
void P6(state_t* s) { P6ROUNDS(s); }
#endif
#if !ASCON_INLINE_PERM && !ASCON_UNROLL_LOOPS
void P(state_t* s, int nr) { PROUNDS(s, nr); }
#endif
#ifndef PERMUTATIONS_H_
#define PERMUTATIONS_H_
#include <stdint.h>
#include "api.h"
#include "ascon.h"
#include "config.h"
#include "constants.h"
#include "printstate.h"
#include "round.h"
#define LOADSTATE(s, a, b, c, d, e) \
do { \
a.x = s->x[0]; \
b.x = s->x[1]; \
c.x = s->x[2]; \
d.x = s->x[3]; \
e.x = s->x[4]; \
} while (0)
#define STORESTATE(s, a, b, c, d, e) \
do { \
s->x[0] = a.x; \
s->x[1] = b.x; \
s->x[2] = c.x; \
s->x[3] = d.x; \
s->x[4] = e.x; \
} while (0)
forceinline void P12ROUNDS(state_t* s) {
word_t x0, x1, x2, x3, x4;
LOADSTATE(s, x0, x1, x2, x3, x4);
ROUND5(x0, x1, x2, x3, x4, RC0);
ROUND5(x2, x3, x4, x0, x1, RC1);
ROUND5(x4, x0, x1, x2, x3, RC2);
ROUND5(x1, x2, x3, x4, x0, RC3);
ROUND5(x3, x4, x0, x1, x2, RC4);
ROUND5(x0, x1, x2, x3, x4, RC5);
ROUND5(x2, x3, x4, x0, x1, RC6);
ROUND5(x4, x0, x1, x2, x3, RC7);
ROUND5(x1, x2, x3, x4, x0, RC8);
ROUND5(x3, x4, x0, x1, x2, RC9);
#if !ASCON_INLINE_PERM
ROUND5(x0, x1, x2, x3, x4, RCa);
ROUND5(x2, x3, x4, x0, x1, RCb);
STORESTATE(s, x4, x0, x1, x2, x3);
#else
STORESTATE(s, x0, x1, x2, x3, x4);
ROUND(s, RCa);
ROUND(s, RCb);
#endif
}
forceinline void P8ROUNDS(state_t* s) {
word_t x0, x1, x2, x3, x4;
LOADSTATE(s, x0, x1, x2, x3, x4);
ROUND5(x0, x1, x2, x3, x4, RC4);
ROUND5(x2, x3, x4, x0, x1, RC5);
ROUND5(x4, x0, x1, x2, x3, RC6);
ROUND5(x1, x2, x3, x4, x0, RC7);
ROUND5(x3, x4, x0, x1, x2, RC8);
#if !ASCON_INLINE_PERM
ROUND5(x0, x1, x2, x3, x4, RC9);
ROUND5(x2, x3, x4, x0, x1, RCa);
ROUND5(x4, x0, x1, x2, x3, RCb);
STORESTATE(s, x1, x2, x3, x4, x0);
#else /* ASCON_INLINE_PERM */
STORESTATE(s, x0, x1, x2, x3, x4);
ROUND(s, RC9);
ROUND(s, RCa);
ROUND(s, RCb);
#endif
}
forceinline void P6ROUNDS(state_t* s) {
word_t x0, x1, x2, x3, x4;
LOADSTATE(s, x0, x1, x2, x3, x4);
ROUND5(x0, x1, x2, x3, x4, RC6);
ROUND5(x2, x3, x4, x0, x1, RC7);
ROUND5(x4, x0, x1, x2, x3, RC8);
ROUND5(x1, x2, x3, x4, x0, RC9);
ROUND5(x3, x4, x0, x1, x2, RCa);
#if !ASCON_INLINE_PERM
ROUND5(x0, x1, x2, x3, x4, RCb);
STORESTATE(s, x2, x3, x4, x0, x1);
#else /* ASCON_INLINE_PERM */
STORESTATE(s, x0, x1, x2, x3, x4);
ROUND(s, RCb);
#endif
}
#if ASCON_INLINE_PERM && ASCON_UNROLL_LOOPS
forceinline void P(state_t* s, int nr) {
if (nr == 12) P12ROUNDS(s);
if (nr == 8) P8ROUNDS(s);
if (nr == 6) P6ROUNDS(s);
}
#elif !ASCON_INLINE_PERM && ASCON_UNROLL_LOOPS
void P12(state_t* s);
void P8(state_t* s);
void P6(state_t* s);
forceinline void P(state_t* s, int nr) {
if (nr == 12) P12(s);
if (nr == 8) P8(s);
if (nr == 6) P6(s);
}
#elif ASCON_INLINE_PERM && !ASCON_UNROLL_LOOPS
forceinline void P(state_t* s, int nr) { PROUNDS(s, nr); }
#else /* !ASCON_INLINE_PERM && !ASCON_UNROLL_LOOPS */
void P(state_t* s, int nr);
#endif
#endif /* PERMUTATIONS_H_ */
#ifdef ASCON_PRINT_STATE
#include "printstate.h"
#include <inttypes.h>
#include <stdio.h>
#include <string.h>
#ifndef WORDTOU64
#define WORDTOU64
#endif
#ifndef U64BIG
#define U64BIG
#endif
void printword(const char* text, const uint64_t x) {
printf("%s=%016" PRIx64, text, U64BIG(WORDTOU64(x)));
}
void printstate(const char* text, const state_t* s) {
printf("%s:", text);
for (int i = strlen(text); i < 17; ++i) printf(" ");
printword(" x0", s->x[0]);
printword(" x1", s->x[1]);
printword(" x2", s->x[2]);
printword(" x3", s->x[3]);
printword(" x4", s->x[4]);
#ifdef ASCON_PRINT_BI
printf(" ");
printf(" x0=%08x_%08x", s->w[0][1], s->w[0][0]);
printf(" x1=%08x_%08x", s->w[1][1], s->w[1][0]);
printf(" x2=%08x_%08x", s->w[2][1], s->w[2][0]);
printf(" x3=%08x_%08x", s->w[3][1], s->w[3][0]);
printf(" x4=%08x_%08x", s->w[4][1], s->w[4][0]);
#endif
printf("\n");
}
#endif
#ifndef PRINTSTATE_H_
#define PRINTSTATE_H_
#ifdef ASCON_PRINT_STATE
#include "ascon.h"
#include "word.h"
void printword(const char* text, const uint64_t x);
void printstate(const char* text, const state_t* s);
#else
#define printword(text, w) \
do { \
} while (0)
#define printstate(text, s) \
do { \
} while (0)
#endif
#endif /* PRINTSTATE_H_ */
#ifndef WORD_H_
#define WORD_H_
#include <stdint.h>
#include <string.h>
#include "config.h"
#include "endian.h"
#include "forceinline.h"
#include "interleave.h"
#if ASCON_EXTERN_BI
#define U64TOWORD(x) U64BIG(x)
#define WORDTOU64(x) U64BIG(x)
#else
#define U64TOWORD(x) TOBI(x)
#define WORDTOU64(x) FROMBI(x)
#endif
typedef union {
uint64_t x;
uint32_t w[2];
uint8_t b[8];
} word_t;
forceinline uint32_t ROR32(uint32_t x, int n) {
return x >> n | x << (-n & 31);
}
forceinline uint64_t ROR(uint64_t x, int n) {
word_t b, a = {.x = x};
b.w[0] = (n % 2) ? ROR32(a.w[1], (n - 1) / 2) : ROR32(a.w[0], n / 2);
b.w[1] = (n % 2) ? ROR32(a.w[0], (n + 1) / 2) : ROR32(a.w[1], n / 2);
return b.x;
}
forceinline uint64_t KEYROT(uint64_t a, uint64_t b) {
word_t w, lo2hi = {.x = a}, hi2lo = {.x = b};
w.w[0] = lo2hi.w[0] << 16 | hi2lo.w[0] >> 16;
w.w[1] = lo2hi.w[1] << 16 | hi2lo.w[1] >> 16;
return w.x;
}
forceinline int NOTZERO(uint64_t a, uint64_t b) {
uint64_t result = a | b;
result |= result >> 32;
result |= result >> 16;
result |= result >> 8;
return ((((int)(result & 0xff) - 1) >> 8) & 1) - 1;
}
#if ASCON_EXTERN_BI
forceinline uint64_t PAD(int i) { return 0x80ull << (56 - 8 * i); }
forceinline uint64_t PRFS_MLEN(uint64_t len) { return len << 51; }
forceinline uint64_t CLEAR(uint64_t w, int n) {
/* undefined for n == 0 */
uint64_t mask = ~0ull >> (8 * n);
return w & mask;
}
#else
forceinline uint64_t PAD(int i) {
return ((uint64_t)((uint32_t)0x08 << (28 - 4 * i)) << 32);
}
forceinline uint64_t PRFS_MLEN(uint64_t len) {
return ((len & 0x01) << 57) | /* 0000x */
((len & 0x02) << 25) | /* 000x0 */
((len & 0x04) << 56) | /* 00x00 */
((len & 0x08) << 24) | /* 0x000 */
((len & 0x10) << 55); /* x0000 */
}
forceinline uint64_t CLEAR(uint64_t w, int n) {
/* undefined for n == 0 */
uint32_t mask = 0xffffffffull >> (4 * n);
return w & ((uint64_t)mask << 32 | mask);
}
#endif
forceinline uint64_t MASK(int n) {
/* undefined for n == 0 */
return ~0ull >> (64 - 8 * n);
}
forceinline uint64_t LOAD(const uint8_t* bytes, int n) {
uint64_t x = *(uint64_t*)bytes & MASK(n);
return U64TOWORD(x);
}
forceinline void STORE(uint8_t* bytes, uint64_t w, int n) {
*(uint64_t*)bytes &= ~MASK(n);
*(uint64_t*)bytes |= WORDTOU64(w);
}
forceinline uint64_t LOADBYTES(const uint8_t* bytes, int n) {
uint64_t x = 0;
memcpy(&x, bytes, n);
return U64TOWORD(x);
}
forceinline void STOREBYTES(uint8_t* bytes, uint64_t w, int n) {
uint64_t x = WORDTOU64(w);
memcpy(bytes, &x, n);
}
#endif /* WORD_H_ */
#pragma GCC push_options
#pragma GCC optimize ("Os")
#include "api.h"
#include "ascon.h"
#include "permutations.h"
#include "printstate.h"
#if !ASCON_INLINE_MODE
#undef forceinline
#define forceinline
#endif
#ifdef ASCON_AEAD_RATE
forceinline void ascon_loadkey(key_t* key, const uint8_t* k) {
#if CRYPTO_KEYBYTES == 16
key->k1 = LOAD(k, 8);
key->k2 = LOAD(k + 8, 8);
#else /* CRYPTO_KEYBYTES == 20 */
key->k0 = KEYROT(0, LOADBYTES(k, 4));
key->k1 = LOADBYTES(k + 4, 8);
key->k2 = LOADBYTES(k + 12, 8);
#endif
}
forceinline void ascon_initaead(state_t* s, const uint8_t* npub,
const key_t* key) {
#if CRYPTO_KEYBYTES == 16
if (ASCON_AEAD_RATE == 8) s->x[0] = ASCON_128_IV;
if (ASCON_AEAD_RATE == 16) s->x[0] = ASCON_128A_IV;
#else /* CRYPTO_KEYBYTES == 20 */
s->x[0] = ASCON_80PQ_IV ^ key->k0;
#endif
s->x[1] = key->k1;
s->x[2] = key->k2;
s->x[3] = LOAD(npub, 8);
s->x[4] = LOAD(npub + 8, 8);
printstate("init 1st key xor", s);
P(s, 12);
#if CRYPTO_KEYBYTES == 20
s->x[2] ^= key->k0;
#endif
s->x[3] ^= key->k1;
s->x[4] ^= key->k2;
printstate("init 2nd key xor", s);
}
forceinline void ascon_final(state_t* s, const key_t* key) {
#if CRYPTO_KEYBYTES == 16
if (ASCON_AEAD_RATE == 8) {
s->x[1] ^= key->k1;
s->x[2] ^= key->k2;
} else {
s->x[2] ^= key->k1;
s->x[3] ^= key->k2;
}
#else /* CRYPTO_KEYBYTES == 20 */
s->x[1] ^= KEYROT(key->k0, key->k1);
s->x[2] ^= KEYROT(key->k1, key->k2);
s->x[3] ^= KEYROT(key->k2, 0);
#endif
printstate("final 1st key xor", s);
P(s, 12);
s->x[3] ^= key->k1;
s->x[4] ^= key->k2;
printstate("final 2nd key xor", s);
}
void ascon_aead(uint8_t* t, uint8_t* out, const uint8_t* in, uint64_t tlen,
const uint8_t* ad, uint64_t adlen, const uint8_t* npub,
const uint8_t* k, uint8_t mode) {
const int nr = (ASCON_AEAD_RATE == 8) ? 6 : 8;
key_t key;
ascon_loadkey(&key, k);
/* initialize */
state_t s;
ascon_initaead(&s, npub, &key);
/* process associated data */
if (adlen) {
ascon_update(&s, (void*)0, ad, adlen, ASCON_ABSORB);
printstate("pad adata", &s);
P(&s, nr);
}
/* domain separation */
s.x[4] ^= 1;
printstate("domain separation", &s);
/* process plaintext/ciphertext */
ascon_update(&s, out, in, tlen, mode);
if (mode == ASCON_ENCRYPT) printstate("pad plaintext", &s);
if (mode == ASCON_DECRYPT) printstate("pad ciphertext", &s);
/* finalize */
ascon_final(&s, &key);
((uint64_t*)t)[0] = WORDTOU64(s.x[3]);
((uint64_t*)t)[1] = WORDTOU64(s.x[4]);
}
#endif
#pragma GCC pop_options
#pragma GCC push_options
#pragma GCC optimize ("Os")
#include "api.h"
#include "ascon.h"
#include "permutations.h"
#include "printstate.h"
#if !ASCON_INLINE_MODE
#undef forceinline
#define forceinline
#endif
#ifdef ASCON_AEAD_RATE
forceinline void ascon_loadkey(key_t* key, const uint8_t* k) {
#if CRYPTO_KEYBYTES == 16
key->k1 = LOAD(k, 8);
key->k2 = LOAD(k + 8, 8);
#else /* CRYPTO_KEYBYTES == 20 */
key->k0 = KEYROT(0, LOADBYTES(k, 4));
key->k1 = LOADBYTES(k + 4, 8);
key->k2 = LOADBYTES(k + 12, 8);
#endif
}
forceinline void ascon_initaead(state_t* s, const uint8_t* npub,
const key_t* key) {
#if CRYPTO_KEYBYTES == 16
if (ASCON_AEAD_RATE == 8) s->x[0] = ASCON_128_IV;
if (ASCON_AEAD_RATE == 16) s->x[0] = ASCON_128A_IV;
#else /* CRYPTO_KEYBYTES == 20 */
s->x[0] = ASCON_80PQ_IV ^ key->k0;
#endif
s->x[1] = key->k1;
s->x[2] = key->k2;
s->x[3] = LOAD(npub, 8);
s->x[4] = LOAD(npub + 8, 8);
printstate("init 1st key xor", s);
P(s, 12);
#if CRYPTO_KEYBYTES == 20
s->x[2] ^= key->k0;
#endif
s->x[3] ^= key->k1;
s->x[4] ^= key->k2;
printstate("init 2nd key xor", s);
}
forceinline void ascon_final(state_t* s, const key_t* key) {
#if CRYPTO_KEYBYTES == 16
if (ASCON_AEAD_RATE == 8) {
s->x[1] ^= key->k1;
s->x[2] ^= key->k2;
} else {
s->x[2] ^= key->k1;
s->x[3] ^= key->k2;
}
#else /* CRYPTO_KEYBYTES == 20 */
s->x[1] ^= KEYROT(key->k0, key->k1);
s->x[2] ^= KEYROT(key->k1, key->k2);
s->x[3] ^= KEYROT(key->k2, 0);
#endif
printstate("final 1st key xor", s);
P(s, 12);
s->x[3] ^= key->k1;
s->x[4] ^= key->k2;
printstate("final 2nd key xor", s);
}
void ascon_aead(uint8_t* t, uint8_t* out, const uint8_t* in, uint64_t tlen,
const uint8_t* ad, uint64_t adlen, const uint8_t* npub,
const uint8_t* k, uint8_t mode) {
const int nr = (ASCON_AEAD_RATE == 8) ? 6 : 8;
key_t key;
ascon_loadkey(&key, k);
/* initialize */
state_t s;
ascon_initaead(&s, npub, &key);
/* process associated data */
if (adlen) {
ascon_update(&s, (void*)0, ad, adlen, ASCON_ABSORB);
printstate("pad adata", &s);
P(&s, nr);
}
/* domain separation */
s.x[4] ^= 1;
printstate("domain separation", &s);
/* process plaintext/ciphertext */
ascon_update(&s, out, in, tlen, mode);
if (mode == ASCON_ENCRYPT) printstate("pad plaintext", &s);
if (mode == ASCON_DECRYPT) printstate("pad ciphertext", &s);
/* finalize */
ascon_final(&s, &key);
((uint64_t*)t)[0] = WORDTOU64(s.x[3]);
((uint64_t*)t)[1] = WORDTOU64(s.x[4]);
}
#endif
#pragma GCC pop_options
#pragma GCC push_options
#pragma GCC optimize ("Os")
#include "api.h"
#include "ascon.h"
#include "permutations.h"
#include "printstate.h"
#if !ASCON_INLINE_MODE
#undef forceinline
#define forceinline
#endif
#ifdef ASCON_AEAD_RATE
forceinline void ascon_loadkey(key_t* key, const uint8_t* k) {
#if CRYPTO_KEYBYTES == 16
key->k1 = LOAD(k, 8);
key->k2 = LOAD(k + 8, 8);
#else /* CRYPTO_KEYBYTES == 20 */
key->k0 = KEYROT(0, LOADBYTES(k, 4));
key->k1 = LOADBYTES(k + 4, 8);
key->k2 = LOADBYTES(k + 12, 8);
#endif
}
forceinline void ascon_initaead(state_t* s, const uint8_t* npub,
const key_t* key) {
#if CRYPTO_KEYBYTES == 16
if (ASCON_AEAD_RATE == 8) s->x[0] = ASCON_128_IV;
if (ASCON_AEAD_RATE == 16) s->x[0] = ASCON_128A_IV;
#else /* CRYPTO_KEYBYTES == 20 */
s->x[0] = ASCON_80PQ_IV ^ key->k0;
#endif
s->x[1] = key->k1;
s->x[2] = key->k2;
s->x[3] = LOAD(npub, 8);
s->x[4] = LOAD(npub + 8, 8);
printstate("init 1st key xor", s);
P(s, 12);
#if CRYPTO_KEYBYTES == 20
s->x[2] ^= key->k0;
#endif
s->x[3] ^= key->k1;
s->x[4] ^= key->k2;
printstate("init 2nd key xor", s);
}
forceinline void ascon_final(state_t* s, const key_t* key) {
#if CRYPTO_KEYBYTES == 16
if (ASCON_AEAD_RATE == 8) {
s->x[1] ^= key->k1;
s->x[2] ^= key->k2;
} else {
s->x[2] ^= key->k1;
s->x[3] ^= key->k2;
}
#else /* CRYPTO_KEYBYTES == 20 */
s->x[1] ^= KEYROT(key->k0, key->k1);
s->x[2] ^= KEYROT(key->k1, key->k2);
s->x[3] ^= KEYROT(key->k2, 0);
#endif
printstate("final 1st key xor", s);
P(s, 12);
s->x[3] ^= key->k1;
s->x[4] ^= key->k2;
printstate("final 2nd key xor", s);
}
void ascon_aead(uint8_t* t, uint8_t* out, const uint8_t* in, uint64_t tlen,
const uint8_t* ad, uint64_t adlen, const uint8_t* npub,
const uint8_t* k, uint8_t mode) {
const int nr = (ASCON_AEAD_RATE == 8) ? 6 : 8;
key_t key;
ascon_loadkey(&key, k);
/* initialize */
state_t s;
ascon_initaead(&s, npub, &key);
/* process associated data */
if (adlen) {
ascon_update(&s, (void*)0, ad, adlen, ASCON_ABSORB);
printstate("pad adata", &s);
P(&s, nr);
}
/* domain separation */
s.x[4] ^= 1;
printstate("domain separation", &s);
/* process plaintext/ciphertext */
ascon_update(&s, out, in, tlen, mode);
if (mode == ASCON_ENCRYPT) printstate("pad plaintext", &s);
if (mode == ASCON_DECRYPT) printstate("pad ciphertext", &s);
/* finalize */
ascon_final(&s, &key);
((uint64_t*)t)[0] = WORDTOU64(s.x[3]);
((uint64_t*)t)[1] = WORDTOU64(s.x[4]);
}
#endif
#pragma GCC pop_options
#pragma GCC push_options
#pragma GCC optimize ("Os")
#include "api.h"
#include "ascon.h"
#include "permutations.h"
#include "printstate.h"
#if !ASCON_INLINE_MODE
#undef forceinline
#define forceinline
#endif
#ifdef ASCON_AEAD_RATE
forceinline void ascon_loadkey(key_t* key, const uint8_t* k) {
#if CRYPTO_KEYBYTES == 16
key->k1 = LOAD(k, 8);
key->k2 = LOAD(k + 8, 8);
#else /* CRYPTO_KEYBYTES == 20 */
key->k0 = KEYROT(0, LOADBYTES(k, 4));
key->k1 = LOADBYTES(k + 4, 8);
key->k2 = LOADBYTES(k + 12, 8);
#endif
}
forceinline void ascon_initaead(state_t* s, const uint8_t* npub,
const key_t* key) {
#if CRYPTO_KEYBYTES == 16
if (ASCON_AEAD_RATE == 8) s->x[0] = ASCON_128_IV;
if (ASCON_AEAD_RATE == 16) s->x[0] = ASCON_128A_IV;
#else /* CRYPTO_KEYBYTES == 20 */
s->x[0] = ASCON_80PQ_IV ^ key->k0;
#endif
s->x[1] = key->k1;
s->x[2] = key->k2;
s->x[3] = LOAD(npub, 8);
s->x[4] = LOAD(npub + 8, 8);
printstate("init 1st key xor", s);
P(s, 12);
#if CRYPTO_KEYBYTES == 20
s->x[2] ^= key->k0;
#endif
s->x[3] ^= key->k1;
s->x[4] ^= key->k2;
printstate("init 2nd key xor", s);
}
forceinline void ascon_final(state_t* s, const key_t* key) {
#if CRYPTO_KEYBYTES == 16
if (ASCON_AEAD_RATE == 8) {
s->x[1] ^= key->k1;
s->x[2] ^= key->k2;
} else {
s->x[2] ^= key->k1;
s->x[3] ^= key->k2;
}
#else /* CRYPTO_KEYBYTES == 20 */
s->x[1] ^= KEYROT(key->k0, key->k1);
s->x[2] ^= KEYROT(key->k1, key->k2);
s->x[3] ^= KEYROT(key->k2, 0);
#endif
printstate("final 1st key xor", s);
P(s, 12);
s->x[3] ^= key->k1;
s->x[4] ^= key->k2;
printstate("final 2nd key xor", s);
}
void ascon_aead(uint8_t* t, uint8_t* out, const uint8_t* in, uint64_t tlen,
const uint8_t* ad, uint64_t adlen, const uint8_t* npub,
const uint8_t* k, uint8_t mode) {
const int nr = (ASCON_AEAD_RATE == 8) ? 6 : 8;
key_t key;
ascon_loadkey(&key, k);
/* initialize */
state_t s;
ascon_initaead(&s, npub, &key);
/* process associated data */
if (adlen) {
ascon_update(&s, (void*)0, ad, adlen, ASCON_ABSORB);
printstate("pad adata", &s);
P(&s, nr);
}
/* domain separation */
s.x[4] ^= 1;
printstate("domain separation", &s);
/* process plaintext/ciphertext */
ascon_update(&s, out, in, tlen, mode);
if (mode == ASCON_ENCRYPT) printstate("pad plaintext", &s);
if (mode == ASCON_DECRYPT) printstate("pad ciphertext", &s);
/* finalize */
ascon_final(&s, &key);
((uint64_t*)t)[0] = WORDTOU64(s.x[3]);
((uint64_t*)t)[1] = WORDTOU64(s.x[4]);
}
#endif
#pragma GCC pop_options
#define CRYPTO_VERSION "1.2.6"
#define CRYPTO_KEYBYTES 20
#define CRYPTO_NSECBYTES 0
#define CRYPTO_NPUBBYTES 16
#define CRYPTO_ABYTES 16
#define CRYPTO_NOOVERLAP 1
#define ASCON_AEAD_RATE 8
#ifndef ASCON_H_
#define ASCON_H_
#include <stdint.h>
#include "word.h"
typedef union {
uint64_t x[5];
uint32_t w[5][2];
uint8_t b[5][8];
} state_t;
typedef struct {
#if (CRYPTO_KEYBYTES == 20)
uint64_t k0;
#endif
uint64_t k1;
uint64_t k2;
} key_t;
void ascon_initaead(state_t* s, const uint8_t* npub, const key_t* k);
void ascon_adata(state_t* s, const uint8_t* ad, uint64_t adlen);
void ascon_encrypt(state_t* s, uint8_t* c, const uint8_t* m, uint64_t mlen);
void ascon_decrypt(state_t* s, uint8_t* m, const uint8_t* c, uint64_t clen);
void ascon_final(state_t* s, const key_t* k);
void ascon_inithash(state_t* s);
void ascon_absorb(state_t* s, const uint8_t* in, uint64_t inlen);
void ascon_squeeze(state_t* s, uint8_t* out, uint64_t outlen);
#endif /* ASCON_H_ */
#ifndef CONFIG_H_
#define CONFIG_H_
/* inline the ascon mode */
#ifndef ASCON_INLINE_MODE
#define ASCON_INLINE_MODE 1
#endif
/* inline all permutations */
#ifndef ASCON_INLINE_PERM
#define ASCON_INLINE_PERM 0
#endif
/* unroll permutation loops */
#ifndef ASCON_UNROLL_LOOPS
#define ASCON_UNROLL_LOOPS 0
#endif
/* inline bitinterleaving */
#ifndef ASCON_INLINE_BI
#define ASCON_INLINE_BI 1
#endif
/* extern bitinterleaving */
#ifndef ASCON_EXTERN_BI
#define ASCON_EXTERN_BI 0
#endif
#endif /* CONFIG_H_ */
#include "constants.h"
#if !ASCON_UNROLL_LOOPS
const uint8_t constants[] = {0xc, 0xc, 0x9, 0xc, 0xc, 0x9, 0x9, 0x9,
0x6, 0xc, 0x3, 0xc, 0x6, 0x9, 0x3, 0x9,
0xc, 0x6, 0x9, 0x6, 0xc, 0x3, 0x9, 0x3};
#endif
#ifndef CONSTANTS_H_
#define CONSTANTS_H_
#include <stdint.h>
#define ASCON_128_KEYBYTES 16
#define ASCON_128A_KEYBYTES 16
#define ASCON_80PQ_KEYBYTES 20
#define ASCON_128_RATE 8
#define ASCON_128A_RATE 16
#define ASCON_HASH_RATE 8
#define ASCON_PRF_IN_RATE 32
#define ASCON_PRF_OUT_RATE 16
#define ASCON_128_PA_ROUNDS 12
#define ASCON_128_PB_ROUNDS 6
#define ASCON_128A_PA_ROUNDS 12
#define ASCON_128A_PB_ROUNDS 8
#define ASCON_HASH_PA_ROUNDS 12
#define ASCON_HASH_PB_ROUNDS 12
#define ASCON_HASHA_PA_ROUNDS 12
#define ASCON_HASHA_PB_ROUNDS 8
#define ASCON_PRF_PA_ROUNDS 12
#define ASCON_PRF_PB_ROUNDS 12
#define ASCON_128_IV 0x8021000008220000ull
#define ASCON_128A_IV 0x8822000000200000ull
#define ASCON_80PQ_IV 0xc021000008220000ull
#define ASCON_HASH_IV 0x0020000008200010ull
#define ASCON_HASHA_IV 0x0020000008220010ull
#define ASCON_XOF_IV 0x0020000008200000ull
#define ASCON_XOFA_IV 0x0020000008220000ull
#define ASCON_PRF_IV 0x88a0000000200000ull
#define ASCON_MAC_IV 0x88a0000800200000ull
#define ASCON_PRFS_IV 0x8028000000a00000ull
#define ASCON_HASH_IV0 0xf9afb5c6a540dbc7ull
#define ASCON_HASH_IV1 0xbd2493011445a340ull
#define ASCON_HASH_IV2 0xcb9ba8b5604d4fc8ull
#define ASCON_HASH_IV3 0x12a4eede94514c98ull
#define ASCON_HASH_IV4 0x4bca84c06339f398ull
#define ASCON_HASHA_IV0 0x0108e46d1b16eb02ull
#define ASCON_HASHA_IV1 0x5b9b8efdd29083f3ull
#define ASCON_HASHA_IV2 0x7ad665622891ae4aull
#define ASCON_HASHA_IV3 0x9dc27156ee3bfc7full
#define ASCON_HASHA_IV4 0xc61d5fa916801633ull
#define ASCON_XOF_IV0 0xc75782817e351ae6ull
#define ASCON_XOF_IV1 0x70045f441d238220ull
#define ASCON_XOF_IV2 0x5dd5ab52a13e3f04ull
#define ASCON_XOF_IV3 0x3e378142c30c1db2ull
#define ASCON_XOF_IV4 0x3735189db624d656ull
#define ASCON_XOFA_IV0 0x0846d7a5a4b87d44ull
#define ASCON_XOFA_IV1 0xaa6f1005b3a2dbf4ull
#define ASCON_XOFA_IV2 0xdc451146f713e811ull
#define ASCON_XOFA_IV3 0x468cb2532839e30dull
#define ASCON_XOFA_IV4 0xeb2d429709e96977ull
#define RC0 0x0000000c0000000cull
#define RC1 0x0000000c00000009ull
#define RC2 0x000000090000000cull
#define RC3 0x0000000900000009ull
#define RC4 0x0000000c00000006ull
#define RC5 0x0000000c00000003ull
#define RC6 0x0000000900000006ull
#define RC7 0x0000000900000003ull
#define RC8 0x000000060000000cull
#define RC9 0x0000000600000009ull
#define RCa 0x000000030000000cull
#define RCb 0x0000000300000009ull
#define RC(i) ((uint64_t)constants[i + 1] << 32 | constants[i])
#define START(n) (24 - 2 * (n))
#define INC 2
#define END 24
extern const uint8_t constants[];
#endif /* CONSTANTS_H_ */
#include "api.h"
#include "ascon.h"
#include "crypto_aead.h"
#include "permutations.h"
#include "printstate.h"
#if !ASCON_INLINE_MODE
#undef forceinline
#define forceinline
#endif
#ifdef ASCON_AEAD_RATE
forceinline void ascon_loadkey(key_t* key, const uint8_t* k) {
#if CRYPTO_KEYBYTES == 16
key->k1 = LOAD(k, 8);
key->k2 = LOAD(k + 8, 8);
#else /* CRYPTO_KEYBYTES == 20 */
key->k0 = KEYROT(0, LOADBYTES(k, 4));
key->k1 = LOADBYTES(k + 4, 8);
key->k2 = LOADBYTES(k + 12, 8);
#endif
}
forceinline void ascon_initaead(state_t* s, const uint8_t* npub,
const key_t* key) {
#if CRYPTO_KEYBYTES == 16
if (ASCON_AEAD_RATE == 8) s->x[0] = ASCON_128_IV;
if (ASCON_AEAD_RATE == 16) s->x[0] = ASCON_128A_IV;
#else /* CRYPTO_KEYBYTES == 20 */
s->x[0] = ASCON_80PQ_IV ^ key->k0;
#endif
s->x[1] = key->k1;
s->x[2] = key->k2;
s->x[3] = LOAD(npub, 8);
s->x[4] = LOAD(npub + 8, 8);
printstate("init 1st key xor", s);
P(s, 12);
#if CRYPTO_KEYBYTES == 20
s->x[2] ^= key->k0;
#endif
s->x[3] ^= key->k1;
s->x[4] ^= key->k2;
printstate("init 2nd key xor", s);
}
forceinline void ascon_adata(state_t* s, const uint8_t* ad, uint64_t adlen) {
const int nr = (ASCON_AEAD_RATE == 8) ? 6 : 8;
if (adlen) {
/* full associated data blocks */
while (adlen >= ASCON_AEAD_RATE) {
s->x[0] ^= LOAD(ad, 8);
if (ASCON_AEAD_RATE == 16) s->x[1] ^= LOAD(ad + 8, 8);
printstate("absorb adata", s);
P(s, nr);
ad += ASCON_AEAD_RATE;
adlen -= ASCON_AEAD_RATE;
}
/* final associated data block */
uint64_t* px = &s->x[0];
if (ASCON_AEAD_RATE == 16 && adlen >= 8) {
s->x[0] ^= LOAD(ad, 8);
px = &s->x[1];
ad += 8;
adlen -= 8;
}
*px ^= PAD(adlen);
if (adlen) *px ^= LOAD(ad, adlen);
printstate("pad adata", s);
P(s, nr);
}
/* domain separation */
s->x[4] ^= 1;
printstate("domain separation", s);
}
forceinline void ascon_encrypt(state_t* s, uint8_t* c, const uint8_t* m,
uint64_t mlen) {
const int nr = (ASCON_AEAD_RATE == 8) ? 6 : 8;
/* full plaintext blocks */
while (mlen >= ASCON_AEAD_RATE) {
s->x[0] ^= LOAD(m, 8);
STORE(c, s->x[0], 8);
if (ASCON_AEAD_RATE == 16) {
s->x[1] ^= LOAD(m + 8, 8);
STORE(c + 8, s->x[1], 8);
}
printstate("absorb plaintext", s);
P(s, nr);
m += ASCON_AEAD_RATE;
c += ASCON_AEAD_RATE;
mlen -= ASCON_AEAD_RATE;
}
/* final plaintext block */
uint64_t* px = &s->x[0];
if (ASCON_AEAD_RATE == 16 && mlen >= 8) {
s->x[0] ^= LOAD(m, 8);
STORE(c, s->x[0], 8);
px = &s->x[1];
m += 8;
c += 8;
mlen -= 8;
}
*px ^= PAD(mlen);
if (mlen) {
*px ^= LOAD(m, mlen);
STORE(c, *px, mlen);
}
printstate("pad plaintext", s);
}
forceinline void ascon_decrypt(state_t* s, uint8_t* m, const uint8_t* c,
uint64_t clen) {
const int nr = (ASCON_AEAD_RATE == 8) ? 6 : 8;
/* full ciphertext blocks */
while (clen >= ASCON_AEAD_RATE) {
uint64_t cx = LOAD(c, 8);
s->x[0] ^= cx;
STORE(m, s->x[0], 8);
s->x[0] = cx;
if (ASCON_AEAD_RATE == 16) {
cx = LOAD(c + 8, 8);
s->x[1] ^= cx;
STORE(m + 8, s->x[1], 8);
s->x[1] = cx;
}
printstate("insert ciphertext", s);
P(s, nr);
m += ASCON_AEAD_RATE;
c += ASCON_AEAD_RATE;
clen -= ASCON_AEAD_RATE;
}
/* final ciphertext block */
uint64_t* px = &s->x[0];
if (ASCON_AEAD_RATE == 16 && clen >= 8) {
uint64_t cx = LOAD(c, 8);
s->x[0] ^= cx;
STORE(m, s->x[0], 8);
s->x[0] = cx;
px = &s->x[1];
m += 8;
c += 8;
clen -= 8;
}
*px ^= PAD(clen);
if (clen) {
uint64_t cx = LOAD(c, clen);
*px ^= cx;
STORE(m, *px, clen);
*px = CLEAR(*px, clen);
*px ^= cx;
}
printstate("pad ciphertext", s);
}
forceinline void ascon_final(state_t* s, const key_t* key) {
#if CRYPTO_KEYBYTES == 16
if (ASCON_AEAD_RATE == 8) {
s->x[1] ^= key->k1;
s->x[2] ^= key->k2;
} else {
s->x[2] ^= key->k1;
s->x[3] ^= key->k2;
}
#else /* CRYPTO_KEYBYTES == 20 */
s->x[1] ^= KEYROT(key->k0, key->k1);
s->x[2] ^= KEYROT(key->k1, key->k2);
s->x[3] ^= KEYROT(key->k2, 0);
#endif
printstate("final 1st key xor", s);
P(s, 12);
s->x[3] ^= key->k1;
s->x[4] ^= key->k2;
printstate("final 2nd key xor", s);
}
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_t s;
(void)nsec;
*clen = mlen + CRYPTO_ABYTES;
/* perform ascon computation */
key_t key;
ascon_loadkey(&key, k);
ascon_initaead(&s, npub, &key);
ascon_adata(&s, ad, adlen);
ascon_encrypt(&s, c, m, mlen);
ascon_final(&s, &key);
/* set tag */
STOREBYTES(c + mlen, s.x[3], 8);
STOREBYTES(c + mlen + 8, s.x[4], 8);
return 0;
}
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) {
state_t s;
(void)nsec;
if (clen < CRYPTO_ABYTES) return -1;
*mlen = clen = clen - CRYPTO_ABYTES;
/* perform ascon computation */
key_t key;
ascon_loadkey(&key, k);
ascon_initaead(&s, npub, &key);
ascon_adata(&s, ad, adlen);
ascon_decrypt(&s, m, c, clen);
ascon_final(&s, &key);
/* verify tag (should be constant time, check compiler output) */
s.x[3] ^= LOADBYTES(c + clen, 8);
s.x[4] ^= LOADBYTES(c + clen + 8, 8);
return NOTZERO(s.x[3], s.x[4]);
}
#endif
#ifndef ENDIAN_H_
#define ENDIAN_H_
#if defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
/* macros for big endian machines */
#ifdef PRAGMA_ENDIAN
#pragma message("Using macros for big endian machines")
#endif
#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 */
#ifdef PRAGMA_ENDIAN
#pragma message("Using macros for little endian machines")
#endif
#define U64BIG(x) \
(((0x00000000000000FFULL & (x)) << 56) | \
((0x000000000000FF00ULL & (x)) << 40) | \
((0x0000000000FF0000ULL & (x)) << 24) | \
((0x00000000FF000000ULL & (x)) << 8) | \
((0x000000FF00000000ULL & (x)) >> 8) | \
((0x0000FF0000000000ULL & (x)) >> 24) | \
((0x00FF000000000000ULL & (x)) >> 40) | \
((0xFF00000000000000ULL & (x)) >> 56))
#define U32BIG(x) \
(((0x000000FF & (x)) << 24) | ((0x0000FF00 & (x)) << 8) | \
((0x00FF0000 & (x)) >> 8) | ((0xFF000000 & (x)) >> 24))
#define U16BIG(x) (((0x00FF & (x)) << 8) | ((0xFF00 & (x)) >> 8))
#else
#error "Ascon byte order macros not defined in endian.h"
#endif
#endif /* ENDIAN_H_ */
#ifndef FORCEINLINE_H_
#define FORCEINLINE_H_
/* define forceinline macro */
#ifdef _MSC_VER
#define forceinline __forceinline
#elif defined(__GNUC__)
#define forceinline inline __attribute__((__always_inline__))
#elif defined(__CLANG__)
#if __has_attribute(__always_inline__)
#define forceinline inline __attribute__((__always_inline__))
#else
#define forceinline inline
#endif
#else
#define forceinline inline
#endif
#endif /* FORCEINLINE_H_ */
#include "interleave.h"
#if !ASCON_EXTERN_BI
const uint32_t B[3] = {0x22222222, 0x0c0c0c0c, 0x00f000f0};
#if !ASCON_INLINE_BI
uint64_t TOBI(uint64_t in) { return deinterleave32(in); }
uint64_t FROMBI(uint64_t in) { return interleave32(in); }
#endif
#endif
#ifndef INTERLEAVE_H_
#define INTERLEAVE_H_
#include <stdint.h>
#include "config.h"
#include "endian.h"
#include "forceinline.h"
#if ASCON_INLINE_BI
#define TOBI deinterleave32
#define FROMBI interleave32
#else
uint64_t TOBI(uint64_t in);
uint64_t FROMBI(uint64_t in);
#endif
extern const uint32_t B[3];
forceinline uint32_t deinterleave16(uint32_t x) {
uint32_t t;
t = (x ^ (x >> 1)) & B[0], x ^= t ^ (t << 1);
t = (x ^ (x >> 2)) & B[1], x ^= t ^ (t << 2);
t = (x ^ (x >> 4)) & B[2], x ^= t ^ (t << 4);
t = (x ^ (x >> 8)) & 0xff00, x ^= t ^ (t << 8);
return x;
}
forceinline uint32_t interleave16(uint32_t x) {
uint32_t t;
t = (x ^ (x >> 8)) & 0xff00, x ^= t ^ (t << 8);
t = (x ^ (x >> 4)) & B[2], x ^= t ^ (t << 4);
t = (x ^ (x >> 2)) & B[1], x ^= t ^ (t << 2);
t = (x ^ (x >> 1)) & B[0], x ^= t ^ (t << 1);
return x;
}
/* credit to Henry S. Warren, Hacker's Delight, Addison-Wesley, 2002 */
forceinline uint64_t deinterleave32(uint64_t in) {
in = U64BIG(in);
uint32_t hi = in >> 32;
uint32_t lo = in;
uint32_t t0, t1, e, o;
t0 = deinterleave16(lo);
t1 = deinterleave16(hi);
e = (t1 << 16) | (t0 & 0x0000FFFF);
o = (t1 & 0xFFFF0000) | (t0 >> 16);
return (uint64_t)o << 32 | e;
}
/* credit to Henry S. Warren, Hacker's Delight, Addison-Wesley, 2002 */
forceinline uint64_t interleave32(uint64_t in) {
uint32_t e = in;
uint32_t o = in >> 32;
uint32_t t0, t1, lo, hi;
t0 = (o << 16) | (e & 0x0000FFFF);
t1 = (o & 0xFFFF0000) | (e >> 16);
lo = interleave16(t0);
hi = interleave16(t1);
return U64BIG((uint64_t)hi << 32 | lo);
}
#endif /* INTERLEAVE_H_ */
#include "permutations.h"
#if !ASCON_INLINE_PERM && ASCON_UNROLL_LOOPS
void P12(state_t* s) { P12ROUNDS(s); }
#endif
#if ((defined(ASCON_AEAD_RATE) && ASCON_AEAD_RATE == 16) || \
(defined(ASCON_HASH_ROUNDS) && ASCON_HASH_ROUNDS == 8)) && \
!ASCON_INLINE_PERM && ASCON_UNROLL_LOOPS
void P8(state_t* s) { P8ROUNDS(s); }
#endif
#if (defined(ASCON_AEAD_RATE) && ASCON_AEAD_RATE == 8) && \
!ASCON_INLINE_PERM && ASCON_UNROLL_LOOPS
void P6(state_t* s) { P6ROUNDS(s); }
#endif
#if !ASCON_INLINE_PERM && !ASCON_UNROLL_LOOPS
void P(state_t* s, int nr) { PROUNDS(s, nr); }
#endif
#ifndef PERMUTATIONS_H_
#define PERMUTATIONS_H_
#include <stdint.h>
#include "api.h"
#include "ascon.h"
#include "config.h"
#include "constants.h"
#include "printstate.h"
#include "round.h"
#define LOADSTATE(s, a, b, c, d, e) \
do { \
a.x = s->x[0]; \
b.x = s->x[1]; \
c.x = s->x[2]; \
d.x = s->x[3]; \
e.x = s->x[4]; \
} while (0)
#define STORESTATE(s, a, b, c, d, e) \
do { \
s->x[0] = a.x; \
s->x[1] = b.x; \
s->x[2] = c.x; \
s->x[3] = d.x; \
s->x[4] = e.x; \
} while (0)
forceinline void P12ROUNDS(state_t* s) {
word_t x0, x1, x2, x3, x4;
LOADSTATE(s, x0, x1, x2, x3, x4);
ROUND5(x0, x1, x2, x3, x4, RC0);
ROUND5(x2, x3, x4, x0, x1, RC1);
ROUND5(x4, x0, x1, x2, x3, RC2);
ROUND5(x1, x2, x3, x4, x0, RC3);
ROUND5(x3, x4, x0, x1, x2, RC4);
ROUND5(x0, x1, x2, x3, x4, RC5);
ROUND5(x2, x3, x4, x0, x1, RC6);
ROUND5(x4, x0, x1, x2, x3, RC7);
ROUND5(x1, x2, x3, x4, x0, RC8);
ROUND5(x3, x4, x0, x1, x2, RC9);
#if !ASCON_INLINE_PERM
ROUND5(x0, x1, x2, x3, x4, RCa);
ROUND5(x2, x3, x4, x0, x1, RCb);
STORESTATE(s, x4, x0, x1, x2, x3);
#else
STORESTATE(s, x0, x1, x2, x3, x4);
ROUND(s, RCa);
ROUND(s, RCb);
#endif
}
forceinline void P8ROUNDS(state_t* s) {
word_t x0, x1, x2, x3, x4;
LOADSTATE(s, x0, x1, x2, x3, x4);
ROUND5(x0, x1, x2, x3, x4, RC4);
ROUND5(x2, x3, x4, x0, x1, RC5);
ROUND5(x4, x0, x1, x2, x3, RC6);
ROUND5(x1, x2, x3, x4, x0, RC7);
ROUND5(x3, x4, x0, x1, x2, RC8);
#if !ASCON_INLINE_PERM
ROUND5(x0, x1, x2, x3, x4, RC9);
ROUND5(x2, x3, x4, x0, x1, RCa);
ROUND5(x4, x0, x1, x2, x3, RCb);
STORESTATE(s, x1, x2, x3, x4, x0);
#else /* ASCON_INLINE_PERM */
STORESTATE(s, x0, x1, x2, x3, x4);
ROUND(s, RC9);
ROUND(s, RCa);
ROUND(s, RCb);
#endif
}
forceinline void P6ROUNDS(state_t* s) {
word_t x0, x1, x2, x3, x4;
LOADSTATE(s, x0, x1, x2, x3, x4);
ROUND5(x0, x1, x2, x3, x4, RC6);
ROUND5(x2, x3, x4, x0, x1, RC7);
ROUND5(x4, x0, x1, x2, x3, RC8);
ROUND5(x1, x2, x3, x4, x0, RC9);
ROUND5(x3, x4, x0, x1, x2, RCa);
#if !ASCON_INLINE_PERM
ROUND5(x0, x1, x2, x3, x4, RCb);
STORESTATE(s, x2, x3, x4, x0, x1);
#else /* ASCON_INLINE_PERM */
STORESTATE(s, x0, x1, x2, x3, x4);
ROUND(s, RCb);
#endif
}
#if ASCON_INLINE_PERM && ASCON_UNROLL_LOOPS
forceinline void P(state_t* s, int nr) {
if (nr == 12) P12ROUNDS(s);
if (nr == 8) P8ROUNDS(s);
if (nr == 6) P6ROUNDS(s);
}
#elif !ASCON_INLINE_PERM && ASCON_UNROLL_LOOPS
void P12(state_t* s);
void P8(state_t* s);
void P6(state_t* s);
forceinline void P(state_t* s, int nr) {
if (nr == 12) P12(s);
if (nr == 8) P8(s);
if (nr == 6) P6(s);
}
#elif ASCON_INLINE_PERM && !ASCON_UNROLL_LOOPS
forceinline void P(state_t* s, int nr) { PROUNDS(s, nr); }
#else /* !ASCON_INLINE_PERM && !ASCON_UNROLL_LOOPS */
void P(state_t* s, int nr);
#endif
#endif /* PERMUTATIONS_H_ */
#ifdef ASCON_PRINT_STATE
#include "printstate.h"
#include <inttypes.h>
#include <stdio.h>
#include <string.h>
#ifndef WORDTOU64
#define WORDTOU64
#endif
#ifndef U64BIG
#define U64BIG
#endif
void printword(const char* text, const uint64_t x) {
printf("%s=%016" PRIx64, text, U64BIG(WORDTOU64(x)));
}
void printstate(const char* text, const state_t* s) {
printf("%s:", text);
for (int i = strlen(text); i < 17; ++i) printf(" ");
printword(" x0", s->x[0]);
printword(" x1", s->x[1]);
printword(" x2", s->x[2]);
printword(" x3", s->x[3]);
printword(" x4", s->x[4]);
#ifdef ASCON_PRINT_BI
printf(" ");
printf(" x0=%08x_%08x", s->w[0][1], s->w[0][0]);
printf(" x1=%08x_%08x", s->w[1][1], s->w[1][0]);
printf(" x2=%08x_%08x", s->w[2][1], s->w[2][0]);
printf(" x3=%08x_%08x", s->w[3][1], s->w[3][0]);
printf(" x4=%08x_%08x", s->w[4][1], s->w[4][0]);
#endif
printf("\n");
}
#endif
#ifndef PRINTSTATE_H_
#define PRINTSTATE_H_
#ifdef ASCON_PRINT_STATE
#include "ascon.h"
#include "word.h"
void printword(const char* text, const uint64_t x);
void printstate(const char* text, const state_t* s);
#else
#define printword(text, w) \
do { \
} while (0)
#define printstate(text, s) \
do { \
} while (0)
#endif
#endif /* PRINTSTATE_H_ */
#ifndef WORD_H_
#define WORD_H_
#include <stdint.h>
#include <string.h>
#include "config.h"
#include "endian.h"
#include "forceinline.h"
#include "interleave.h"
#if ASCON_EXTERN_BI
#define U64TOWORD(x) U64BIG(x)
#define WORDTOU64(x) U64BIG(x)
#else
#define U64TOWORD(x) TOBI(x)
#define WORDTOU64(x) FROMBI(x)
#endif
typedef union {
uint64_t x;
uint32_t w[2];
uint8_t b[8];
} word_t;
forceinline uint32_t ROR32(uint32_t x, int n) {
return x >> n | x << (-n & 31);
}
forceinline uint64_t ROR(uint64_t x, int n) {
word_t b, a = {.x = x};
b.w[0] = (n % 2) ? ROR32(a.w[1], (n - 1) / 2) : ROR32(a.w[0], n / 2);
b.w[1] = (n % 2) ? ROR32(a.w[0], (n + 1) / 2) : ROR32(a.w[1], n / 2);
return b.x;
}
forceinline uint64_t KEYROT(uint64_t a, uint64_t b) {
word_t w, lo2hi = {.x = a}, hi2lo = {.x = b};
w.w[0] = lo2hi.w[0] << 16 | hi2lo.w[0] >> 16;
w.w[1] = lo2hi.w[1] << 16 | hi2lo.w[1] >> 16;
return w.x;
}
forceinline int NOTZERO(uint64_t a, uint64_t b) {
uint64_t result = a | b;
result |= result >> 32;
result |= result >> 16;
result |= result >> 8;
return ((((int)(result & 0xff) - 1) >> 8) & 1) - 1;
}
#if ASCON_EXTERN_BI
forceinline uint64_t PAD(int i) { return 0x80ull << (56 - 8 * i); }
forceinline uint64_t PRFS_MLEN(uint64_t len) { return len << 51; }
forceinline uint64_t CLEAR(uint64_t w, int n) {
/* undefined for n == 0 */
uint64_t mask = ~0ull >> (8 * n);
return w & mask;
}
#else
forceinline uint64_t PAD(int i) {
return ((uint64_t)((uint32_t)0x08 << (28 - 4 * i)) << 32);
}
forceinline uint64_t PRFS_MLEN(uint64_t len) {
return ((len & 0x01) << 57) | /* 0000x */
((len & 0x02) << 25) | /* 000x0 */
((len & 0x04) << 56) | /* 00x00 */
((len & 0x08) << 24) | /* 0x000 */
((len & 0x10) << 55); /* x0000 */
}
forceinline uint64_t CLEAR(uint64_t w, int n) {
/* undefined for n == 0 */
uint32_t mask = 0xffffffffull >> (4 * n);
return w & ((uint64_t)mask << 32 | mask);
}
#endif
forceinline uint64_t MASK(int n) {
/* undefined for n == 0 */
return ~0ull >> (64 - 8 * n);
}
forceinline uint64_t LOAD(const uint8_t* bytes, int n) {
uint64_t x = *(uint64_t*)bytes & MASK(n);
return U64TOWORD(x);
}
forceinline void STORE(uint8_t* bytes, uint64_t w, int n) {
*(uint64_t*)bytes &= ~MASK(n);
*(uint64_t*)bytes |= WORDTOU64(w);
}
forceinline uint64_t LOADBYTES(const uint8_t* bytes, int n) {
uint64_t x = 0;
memcpy(&x, bytes, n);
return U64TOWORD(x);
}
forceinline void STOREBYTES(uint8_t* bytes, uint64_t w, int n) {
uint64_t x = WORDTOU64(w);
memcpy(bytes, &x, n);
}
#endif /* WORD_H_ */
#pragma GCC push_options
#pragma GCC optimize ("Os")
#include "api.h"
#include "ascon.h"
#include "permutations.h"
#include "printstate.h"
#if !ASCON_INLINE_MODE
#undef forceinline
#define forceinline
#endif
#ifdef ASCON_AEAD_RATE
forceinline void ascon_loadkey(key_t* key, const uint8_t* k) {
#if CRYPTO_KEYBYTES == 16
key->k1 = LOAD(k, 8);
key->k2 = LOAD(k + 8, 8);
#else /* CRYPTO_KEYBYTES == 20 */
key->k0 = KEYROT(0, LOADBYTES(k, 4));
key->k1 = LOADBYTES(k + 4, 8);
key->k2 = LOADBYTES(k + 12, 8);
#endif
}
forceinline void ascon_initaead(state_t* s, const uint8_t* npub,
const key_t* key) {
#if CRYPTO_KEYBYTES == 16
if (ASCON_AEAD_RATE == 8) s->x[0] = ASCON_128_IV;
if (ASCON_AEAD_RATE == 16) s->x[0] = ASCON_128A_IV;
#else /* CRYPTO_KEYBYTES == 20 */
s->x[0] = ASCON_80PQ_IV ^ key->k0;
#endif
s->x[1] = key->k1;
s->x[2] = key->k2;
s->x[3] = LOAD(npub, 8);
s->x[4] = LOAD(npub + 8, 8);
printstate("init 1st key xor", s);
P(s, 12);
#if CRYPTO_KEYBYTES == 20
s->x[2] ^= key->k0;
#endif
s->x[3] ^= key->k1;
s->x[4] ^= key->k2;
printstate("init 2nd key xor", s);
}
forceinline void ascon_final(state_t* s, const key_t* key) {
#if CRYPTO_KEYBYTES == 16
if (ASCON_AEAD_RATE == 8) {
s->x[1] ^= key->k1;
s->x[2] ^= key->k2;
} else {
s->x[2] ^= key->k1;
s->x[3] ^= key->k2;
}
#else /* CRYPTO_KEYBYTES == 20 */
s->x[1] ^= KEYROT(key->k0, key->k1);
s->x[2] ^= KEYROT(key->k1, key->k2);
s->x[3] ^= KEYROT(key->k2, 0);
#endif
printstate("final 1st key xor", s);
P(s, 12);
s->x[3] ^= key->k1;
s->x[4] ^= key->k2;
printstate("final 2nd key xor", s);
}
void ascon_aead(uint8_t* t, uint8_t* out, const uint8_t* in, uint64_t tlen,
const uint8_t* ad, uint64_t adlen, const uint8_t* npub,
const uint8_t* k, uint8_t mode) {
const int nr = (ASCON_AEAD_RATE == 8) ? 6 : 8;
key_t key;
ascon_loadkey(&key, k);
/* initialize */
state_t s;
ascon_initaead(&s, npub, &key);
/* process associated data */
if (adlen) {
ascon_update(&s, (void*)0, ad, adlen, ASCON_ABSORB);
printstate("pad adata", &s);
P(&s, nr);
}
/* domain separation */
s.x[4] ^= 1;
printstate("domain separation", &s);
/* process plaintext/ciphertext */
ascon_update(&s, out, in, tlen, mode);
if (mode == ASCON_ENCRYPT) printstate("pad plaintext", &s);
if (mode == ASCON_DECRYPT) printstate("pad ciphertext", &s);
/* finalize */
ascon_final(&s, &key);
((uint64_t*)t)[0] = WORDTOU64(s.x[3]);
((uint64_t*)t)[1] = WORDTOU64(s.x[4]);
}
#endif
#pragma GCC pop_options
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
#pragma GCC push_options
#pragma GCC optimize ("Os")
#include "api.h"
#include "ascon.h"
#include "permutations.h"
#include "printstate.h"
#if !ASCON_INLINE_MODE
#undef forceinline
#define forceinline
#endif
#ifdef ASCON_AEAD_RATE
forceinline void ascon_loadkey(key_t* key, const uint8_t* k) {
#if CRYPTO_KEYBYTES == 16
key->k1 = LOAD(k, 8);
key->k2 = LOAD(k + 8, 8);
#else /* CRYPTO_KEYBYTES == 20 */
key->k0 = KEYROT(0, LOADBYTES(k, 4));
key->k1 = LOADBYTES(k + 4, 8);
key->k2 = LOADBYTES(k + 12, 8);
#endif
}
forceinline void ascon_initaead(state_t* s, const uint8_t* npub,
const key_t* key) {
#if CRYPTO_KEYBYTES == 16
if (ASCON_AEAD_RATE == 8) s->x[0] = ASCON_128_IV;
if (ASCON_AEAD_RATE == 16) s->x[0] = ASCON_128A_IV;
#else /* CRYPTO_KEYBYTES == 20 */
s->x[0] = ASCON_80PQ_IV ^ key->k0;
#endif
s->x[1] = key->k1;
s->x[2] = key->k2;
s->x[3] = LOAD(npub, 8);
s->x[4] = LOAD(npub + 8, 8);
printstate("init 1st key xor", s);
P(s, 12);
#if CRYPTO_KEYBYTES == 20
s->x[2] ^= key->k0;
#endif
s->x[3] ^= key->k1;
s->x[4] ^= key->k2;
printstate("init 2nd key xor", s);
}
forceinline void ascon_final(state_t* s, const key_t* key) {
#if CRYPTO_KEYBYTES == 16
if (ASCON_AEAD_RATE == 8) {
s->x[1] ^= key->k1;
s->x[2] ^= key->k2;
} else {
s->x[2] ^= key->k1;
s->x[3] ^= key->k2;
}
#else /* CRYPTO_KEYBYTES == 20 */
s->x[1] ^= KEYROT(key->k0, key->k1);
s->x[2] ^= KEYROT(key->k1, key->k2);
s->x[3] ^= KEYROT(key->k2, 0);
#endif
printstate("final 1st key xor", s);
P(s, 12);
s->x[3] ^= key->k1;
s->x[4] ^= key->k2;
printstate("final 2nd key xor", s);
}
void ascon_aead(uint8_t* t, uint8_t* out, const uint8_t* in, uint64_t tlen,
const uint8_t* ad, uint64_t adlen, const uint8_t* npub,
const uint8_t* k, uint8_t mode) {
const int nr = (ASCON_AEAD_RATE == 8) ? 6 : 8;
key_t key;
ascon_loadkey(&key, k);
/* initialize */
state_t s;
ascon_initaead(&s, npub, &key);
/* process associated data */
if (adlen) {
ascon_update(&s, (void*)0, ad, adlen, ASCON_ABSORB);
printstate("pad adata", &s);
P(&s, nr);
}
/* domain separation */
s.x[4] ^= 1;
printstate("domain separation", &s);
/* process plaintext/ciphertext */
ascon_update(&s, out, in, tlen, mode);
if (mode == ASCON_ENCRYPT) printstate("pad plaintext", &s);
if (mode == ASCON_DECRYPT) printstate("pad ciphertext", &s);
/* finalize */
ascon_final(&s, &key);
((uint64_t*)t)[0] = WORDTOU64(s.x[3]);
((uint64_t*)t)[1] = WORDTOU64(s.x[4]);
}
#endif
#pragma GCC pop_options
#define CRYPTO_VERSION "1.2.6"
// AEAD defines
#define CRYPTO_KEYBYTES 16
#define CRYPTO_NSECBYTES 0
#define CRYPTO_NPUBBYTES 16
#define CRYPTO_ABYTES 16
#define CRYPTO_NOOVERLAP 1
#define ASCON_AEAD_RATE 16
// Hash defines
#define CRYPTO_BYTES 32
#define ASCON_HASH_BYTES 32 /* HASH */
#define ASCON_HASH_ROUNDS 8
#ifndef ASCON_H_
#define ASCON_H_
#include <stdint.h>
#include "word.h"
typedef union {
uint64_t x[5];
uint32_t w[5][2];
uint8_t b[5][8];
} state_t;
typedef struct {
#if (CRYPTO_KEYBYTES == 20)
uint64_t k0;
#endif
uint64_t k1;
uint64_t k2;
} key_t;
#define ASCON_ABSORB 0x1
#define ASCON_SQUEEZE 0x2
#define ASCON_INSERT 0x4
#define ASCON_HASH 0x8
#define ASCON_ENCRYPT (ASCON_ABSORB | ASCON_SQUEEZE)
#define ASCON_DECRYPT (ASCON_ABSORB | ASCON_SQUEEZE | ASCON_INSERT)
void ascon_update(state_t* s, uint8_t* out, const uint8_t* in, uint64_t len,
uint8_t mode);
void ascon_aead(uint8_t* t, uint8_t* out, const uint8_t* in, uint64_t len,
const uint8_t* ad, uint64_t adlen, const uint8_t* npub,
const uint8_t* k, uint8_t mode);
#endif /* ASCON_H_ */
#ifndef CONFIG_H_
#define CONFIG_H_
/* inline the ascon mode */
#ifndef ASCON_INLINE_MODE
#define ASCON_INLINE_MODE 1
#endif
/* inline all permutations */
#ifndef ASCON_INLINE_PERM
#define ASCON_INLINE_PERM 0
#endif
/* unroll permutation loops */
#ifndef ASCON_UNROLL_LOOPS
#define ASCON_UNROLL_LOOPS 0
#endif
/* inline bitinterleaving */
#ifndef ASCON_INLINE_BI
#define ASCON_INLINE_BI 0
#endif
/* extern bitinterleaving */
#ifndef ASCON_EXTERN_BI
#define ASCON_EXTERN_BI 1
#endif
#endif /* CONFIG_H_ */
#pragma GCC push_options
#pragma GCC optimize ("Os")
#include "constants.h"
#if !ASCON_UNROLL_LOOPS
const uint8_t constants[] = {0xc, 0xc, 0x9, 0xc, 0xc, 0x9, 0x9, 0x9,
0x6, 0xc, 0x3, 0xc, 0x6, 0x9, 0x3, 0x9,
0xc, 0x6, 0x9, 0x6, 0xc, 0x3, 0x9, 0x3};
#endif
#pragma GCC pop_options
#ifndef CONSTANTS_H_
#define CONSTANTS_H_
#include <stdint.h>
#define ASCON_128_KEYBYTES 16
#define ASCON_128A_KEYBYTES 16
#define ASCON_80PQ_KEYBYTES 20
#define ASCON_128_RATE 8
#define ASCON_128A_RATE 16
#define ASCON_HASH_RATE 8
#define ASCON_PRF_IN_RATE 32
#define ASCON_PRF_OUT_RATE 16
#define ASCON_128_PA_ROUNDS 12
#define ASCON_128_PB_ROUNDS 6
#define ASCON_128A_PA_ROUNDS 12
#define ASCON_128A_PB_ROUNDS 8
#define ASCON_HASH_PA_ROUNDS 12
#define ASCON_HASH_PB_ROUNDS 12
#define ASCON_HASHA_PA_ROUNDS 12
#define ASCON_HASHA_PB_ROUNDS 8
#define ASCON_PRF_PA_ROUNDS 12
#define ASCON_PRF_PB_ROUNDS 12
#define ASCON_128_IV 0x8021000008220000ull
#define ASCON_128A_IV 0x8822000000200000ull
#define ASCON_80PQ_IV 0xc021000008220000ull
#define ASCON_HASH_IV 0x0020000008200010ull
#define ASCON_HASHA_IV 0x0020000008220010ull
#define ASCON_XOF_IV 0x0020000008200000ull
#define ASCON_XOFA_IV 0x0020000008220000ull
#define ASCON_PRF_IV 0x88a0000000200000ull
#define ASCON_MAC_IV 0x88a0000800200000ull
#define ASCON_PRFS_IV 0x8028000000a00000ull
#define ASCON_HASH_IV0 0xf9afb5c6a540dbc7ull
#define ASCON_HASH_IV1 0xbd2493011445a340ull
#define ASCON_HASH_IV2 0xcb9ba8b5604d4fc8ull
#define ASCON_HASH_IV3 0x12a4eede94514c98ull
#define ASCON_HASH_IV4 0x4bca84c06339f398ull
#define ASCON_HASHA_IV0 0x0108e46d1b16eb02ull
#define ASCON_HASHA_IV1 0x5b9b8efdd29083f3ull
#define ASCON_HASHA_IV2 0x7ad665622891ae4aull
#define ASCON_HASHA_IV3 0x9dc27156ee3bfc7full
#define ASCON_HASHA_IV4 0xc61d5fa916801633ull
#define ASCON_XOF_IV0 0xc75782817e351ae6ull
#define ASCON_XOF_IV1 0x70045f441d238220ull
#define ASCON_XOF_IV2 0x5dd5ab52a13e3f04ull
#define ASCON_XOF_IV3 0x3e378142c30c1db2ull
#define ASCON_XOF_IV4 0x3735189db624d656ull
#define ASCON_XOFA_IV0 0x0846d7a5a4b87d44ull
#define ASCON_XOFA_IV1 0xaa6f1005b3a2dbf4ull
#define ASCON_XOFA_IV2 0xdc451146f713e811ull
#define ASCON_XOFA_IV3 0x468cb2532839e30dull
#define ASCON_XOFA_IV4 0xeb2d429709e96977ull
#define RC0 0x0000000c0000000cull
#define RC1 0x0000000c00000009ull
#define RC2 0x000000090000000cull
#define RC3 0x0000000900000009ull
#define RC4 0x0000000c00000006ull
#define RC5 0x0000000c00000003ull
#define RC6 0x0000000900000006ull
#define RC7 0x0000000900000003ull
#define RC8 0x000000060000000cull
#define RC9 0x0000000600000009ull
#define RCa 0x000000030000000cull
#define RCb 0x0000000300000009ull
#define RC(i) ((uint64_t)constants[i + 1] << 32 | constants[i])
#define START(n) (24 - 2 * (n))
#define INC 2
#define END 24
extern const uint8_t constants[];
#endif /* CONSTANTS_H_ */
#pragma GCC push_options
#pragma GCC optimize ("Os")
#include "crypto_aead.h"
#include <string.h>
#include "api.h"
#include "ascon.h"
#include "permutations.h"
#include "printstate.h"
#ifdef ASCON_AEAD_RATE
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) {
uint8_t t[16];
(void)nsec;
/* set ciphertext size */
*clen = mlen + CRYPTO_ABYTES;
/* ascon encryption */
ascon_aead(t, c, m, mlen, ad, adlen, npub, k, ASCON_ENCRYPT);
/* set tag */
for (int i = 0; i < CRYPTO_ABYTES; ++i) c[mlen + i] = t[i];
return 0;
}
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) {
uint8_t t[16];
(void)nsec;
if (clen < CRYPTO_ABYTES) return -1;
/* set plaintext size */
*mlen = clen - CRYPTO_ABYTES;
/* ascon decryption */
ascon_aead(t, m, c, *mlen, ad, adlen, npub, k, ASCON_DECRYPT);
/* verify tag (should be constant time, check compiler output) */
int result = 0;
for (int i = 0; i < CRYPTO_ABYTES; ++i) result |= t[i] ^ c[*mlen + i];
return (((result - 1) >> 8) & 1) - 1;
}
#endif
#pragma GCC pop_options
#ifndef ENDIAN_H_
#define ENDIAN_H_
#if defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
/* macros for big endian machines */
#ifdef PRAGMA_ENDIAN
#pragma message("Using macros for big endian machines")
#endif
#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 */
#ifdef PRAGMA_ENDIAN
#pragma message("Using macros for little endian machines")
#endif
#define U64BIG(x) \
(((0x00000000000000FFULL & (x)) << 56) | \
((0x000000000000FF00ULL & (x)) << 40) | \
((0x0000000000FF0000ULL & (x)) << 24) | \
((0x00000000FF000000ULL & (x)) << 8) | \
((0x000000FF00000000ULL & (x)) >> 8) | \
((0x0000FF0000000000ULL & (x)) >> 24) | \
((0x00FF000000000000ULL & (x)) >> 40) | \
((0xFF00000000000000ULL & (x)) >> 56))
#define U32BIG(x) \
(((0x000000FF & (x)) << 24) | ((0x0000FF00 & (x)) << 8) | \
((0x00FF0000 & (x)) >> 8) | ((0xFF000000 & (x)) >> 24))
#define U16BIG(x) (((0x00FF & (x)) << 8) | ((0xFF00 & (x)) >> 8))
#else
#error "Ascon byte order macros not defined in endian.h"
#endif
#endif /* ENDIAN_H_ */
#ifndef FORCEINLINE_H_
#define FORCEINLINE_H_
/* define forceinline macro */
#ifdef _MSC_VER
#define forceinline __forceinline
#elif defined(__GNUC__)
#define forceinline inline __attribute__((__always_inline__))
#elif defined(__CLANG__)
#if __has_attribute(__always_inline__)
#define forceinline inline __attribute__((__always_inline__))
#else
#define forceinline inline
#endif
#else
#define forceinline inline
#endif
#endif /* FORCEINLINE_H_ */
#pragma GCC push_options
#pragma GCC optimize ("Os")
#include "api.h"
#include "ascon.h"
#include "crypto_hash.h"
#include "permutations.h"
#include "printstate.h"
#if !ASCON_INLINE_MODE
#undef forceinline
#define forceinline
#endif
#ifdef ASCON_HASH_BYTES
forceinline void ascon_inithash(state_t* s) {
/* initialize */
#ifdef ASCON_PRINT_STATE
#if ASCON_HASH_BYTES == 32 && ASCON_HASH_ROUNDS == 12
s->x[0] = ASCON_HASH_IV;
#elif ASCON_HASH_BYTES == 32 && ASCON_HASH_ROUNDS == 8
s->x[0] = ASCON_HASHA_IV;
#elif ASCON_HASH_BYTES == 0 && ASCON_HASH_ROUNDS == 12
s->x[0] = ASCON_XOF_IV;
#elif ASCON_HASH_BYTES == 0 && ASCON_HASH_ROUNDS == 8
s->x[0] = ASCON_XOFA_IV;
#endif
for (int i = 1; i < 5; ++i) s->x[i] = 0;
printstate("initial value", s);
P(s, 12);
#endif
#if ASCON_HASH_BYTES == 32 && ASCON_HASH_ROUNDS == 12
const uint64_t iv[5] = {ASCON_HASH_IV0, ASCON_HASH_IV1, ASCON_HASH_IV2,
ASCON_HASH_IV3, ASCON_HASH_IV4};
#elif ASCON_HASH_BYTES == 32 && ASCON_HASH_ROUNDS == 8
const uint64_t iv[5] = {ASCON_HASHA_IV0, ASCON_HASHA_IV1, ASCON_HASHA_IV2,
ASCON_HASHA_IV3, ASCON_HASHA_IV4};
#elif ASCON_HASH_BYTES == 0 && ASCON_HASH_ROUNDS == 12
const uint64_t iv[5] = {ASCON_XOF_IV0, ASCON_XOF_IV1, ASCON_XOF_IV2,
ASCON_XOF_IV3, ASCON_XOF_IV4};
#elif ASCON_HASH_BYTES == 0 && ASCON_HASH_ROUNDS == 8
const uint64_t iv[5] = {ASCON_XOFA_IV0, ASCON_XOFA_IV1, ASCON_XOFA_IV2,
ASCON_XOFA_IV3, ASCON_XOFA_IV4};
#endif
for (int i = 0; i < 5; ++i) s->x[i] = (iv[i]);
printstate("initialization", s);
}
forceinline void ascon_absorb(state_t* s, const uint8_t* in, uint64_t inlen) {
/* absorb full plaintext blocks */
while (inlen >= ASCON_HASH_RATE) {
s->x[0] ^= LOAD(in, 8);
printstate("absorb plaintext", s);
P(s, ASCON_HASH_ROUNDS);
in += ASCON_HASH_RATE;
inlen -= ASCON_HASH_RATE;
}
/* absorb final plaintext block */
s->x[0] ^= LOADBYTES(in, inlen);
s->x[0] ^= PAD(inlen);
printstate("pad plaintext", s);
}
forceinline void ascon_squeeze(state_t* s, uint8_t* out, uint64_t outlen) {
/* squeeze full output blocks */
P(s, 12);
while (outlen > ASCON_HASH_RATE) {
STORE(out, s->x[0], 8);
printstate("squeeze output", s);
P(s, ASCON_HASH_ROUNDS);
out += ASCON_HASH_RATE;
outlen -= ASCON_HASH_RATE;
}
/* squeeze final output block */
STOREBYTES(out, s->x[0], outlen);
printstate("squeeze output", s);
}
int crypto_hash(unsigned char* out, const unsigned char* in,
unsigned long long inlen) {
state_t s;
ascon_inithash(&s);
ascon_absorb(&s, in, inlen);
ascon_squeeze(&s, out, CRYPTO_BYTES);
return 0;
}
#endif
#pragma GCC pop_options
#pragma GCC push_options
#pragma GCC optimize ("Os")
#include "interleave.h"
#if !ASCON_EXTERN_BI
const uint32_t B[3] = {0x22222222, 0x0c0c0c0c, 0x00f000f0};
#if !ASCON_INLINE_BI
uint64_t TOBI(uint64_t in) { return deinterleave32(in); }
uint64_t FROMBI(uint64_t in) { return interleave32(in); }
#endif
#endif
#pragma GCC pop_options
#ifndef INTERLEAVE_H_
#define INTERLEAVE_H_
#include <stdint.h>
#include "config.h"
#include "endian.h"
#include "forceinline.h"
#if ASCON_INLINE_BI
#define TOBI deinterleave32
#define FROMBI interleave32
#else
uint64_t TOBI(uint64_t in);
uint64_t FROMBI(uint64_t in);
#endif
extern const uint32_t B[3];
forceinline uint32_t deinterleave16(uint32_t x) {
uint32_t t;
t = (x ^ (x >> 1)) & B[0], x ^= t ^ (t << 1);
t = (x ^ (x >> 2)) & B[1], x ^= t ^ (t << 2);
t = (x ^ (x >> 4)) & B[2], x ^= t ^ (t << 4);
t = (x ^ (x >> 8)) & 0xff00, x ^= t ^ (t << 8);
return x;
}
forceinline uint32_t interleave16(uint32_t x) {
uint32_t t;
t = (x ^ (x >> 8)) & 0xff00, x ^= t ^ (t << 8);
t = (x ^ (x >> 4)) & B[2], x ^= t ^ (t << 4);
t = (x ^ (x >> 2)) & B[1], x ^= t ^ (t << 2);
t = (x ^ (x >> 1)) & B[0], x ^= t ^ (t << 1);
return x;
}
/* credit to Henry S. Warren, Hacker's Delight, Addison-Wesley, 2002 */
forceinline uint64_t deinterleave32(uint64_t in) {
in = U64BIG(in);
uint32_t hi = in >> 32;
uint32_t lo = in;
uint32_t t0, t1, e, o;
t0 = deinterleave16(lo);
t1 = deinterleave16(hi);
e = (t1 << 16) | (t0 & 0x0000FFFF);
o = (t1 & 0xFFFF0000) | (t0 >> 16);
return (uint64_t)o << 32 | e;
}
/* credit to Henry S. Warren, Hacker's Delight, Addison-Wesley, 2002 */
forceinline uint64_t interleave32(uint64_t in) {
uint32_t e = in;
uint32_t o = in >> 32;
uint32_t t0, t1, lo, hi;
t0 = (o << 16) | (e & 0x0000FFFF);
t1 = (o & 0xFFFF0000) | (e >> 16);
lo = interleave16(t0);
hi = interleave16(t1);
return U64BIG((uint64_t)hi << 32 | lo);
}
#endif /* INTERLEAVE_H_ */
#pragma GCC push_options
#pragma GCC optimize ("Os")
#include "permutations.h"
#if !ASCON_INLINE_PERM && ASCON_UNROLL_LOOPS
void P12(state_t* s) { P12ROUNDS(s); }
#endif
#if ((defined(ASCON_AEAD_RATE) && ASCON_AEAD_RATE == 16) || \
(defined(ASCON_HASH_ROUNDS) && ASCON_HASH_ROUNDS == 8)) && \
!ASCON_INLINE_PERM && ASCON_UNROLL_LOOPS
void P8(state_t* s) { P8ROUNDS(s); }
#endif
#if (defined(ASCON_AEAD_RATE) && ASCON_AEAD_RATE == 8) && \
!ASCON_INLINE_PERM && ASCON_UNROLL_LOOPS
void P6(state_t* s) { P6ROUNDS(s); }
#endif
#if !ASCON_INLINE_PERM && !ASCON_UNROLL_LOOPS
void P(state_t* s, int nr) { PROUNDS(s, nr); }
#endif
#pragma GCC pop_options
#ifndef PERMUTATIONS_H_
#define PERMUTATIONS_H_
#include <stdint.h>
#include "api.h"
#include "ascon.h"
#include "config.h"
#include "constants.h"
#include "printstate.h"
#include "round.h"
forceinline void P12ROUNDS(state_t* s) {
ROUND(s, RC0);
ROUND(s, RC1);
ROUND(s, RC2);
ROUND(s, RC3);
ROUND(s, RC4);
ROUND(s, RC5);
ROUND(s, RC6);
ROUND(s, RC7);
ROUND(s, RC8);
ROUND(s, RC9);
ROUND(s, RCa);
ROUND(s, RCb);
}
forceinline void P8ROUNDS(state_t* s) {
ROUND(s, RC4);
ROUND(s, RC5);
ROUND(s, RC6);
ROUND(s, RC7);
ROUND(s, RC8);
ROUND(s, RC9);
ROUND(s, RCa);
ROUND(s, RCb);
}
forceinline void P6ROUNDS(state_t* s) {
ROUND(s, RC6);
ROUND(s, RC7);
ROUND(s, RC8);
ROUND(s, RC9);
ROUND(s, RCa);
ROUND(s, RCb);
}
#if ASCON_INLINE_PERM && ASCON_UNROLL_LOOPS
forceinline void P(state_t* s, int nr) {
if (nr == 12) P12ROUNDS(s);
if (nr == 8) P8ROUNDS(s);
if (nr == 6) P6ROUNDS(s);
}
#elif !ASCON_INLINE_PERM && ASCON_UNROLL_LOOPS
void P12(state_t* s);
void P8(state_t* s);
void P6(state_t* s);
forceinline void P(state_t* s, int nr) {
if (nr == 12) P12(s);
if (nr == 8) P8(s);
if (nr == 6) P6(s);
}
#elif ASCON_INLINE_PERM && !ASCON_UNROLL_LOOPS
forceinline void P(state_t* s, int nr) { PROUNDS(s, nr); }
#else /* !ASCON_INLINE_PERM && !ASCON_UNROLL_LOOPS */
void P(state_t* s, int nr);
#endif
#endif /* PERMUTATIONS_H_ */
#ifdef ASCON_PRINT_STATE
#include "printstate.h"
#include <inttypes.h>
#include <stdio.h>
#include <string.h>
#ifndef WORDTOU64
#define WORDTOU64
#endif
#ifndef U64BIG
#define U64BIG
#endif
void printword(const char* text, const uint64_t x) {
printf("%s=%016" PRIx64, text, U64BIG(WORDTOU64(x)));
}
void printstate(const char* text, const state_t* s) {
printf("%s:", text);
for (int i = strlen(text); i < 17; ++i) printf(" ");
printword(" x0", s->x[0]);
printword(" x1", s->x[1]);
printword(" x2", s->x[2]);
printword(" x3", s->x[3]);
printword(" x4", s->x[4]);
#ifdef ASCON_PRINT_BI
printf(" ");
printf(" x0=%08x_%08x", s->w[0][1], s->w[0][0]);
printf(" x1=%08x_%08x", s->w[1][1], s->w[1][0]);
printf(" x2=%08x_%08x", s->w[2][1], s->w[2][0]);
printf(" x3=%08x_%08x", s->w[3][1], s->w[3][0]);
printf(" x4=%08x_%08x", s->w[4][1], s->w[4][0]);
#endif
printf("\n");
}
#endif
#ifndef PRINTSTATE_H_
#define PRINTSTATE_H_
#ifdef ASCON_PRINT_STATE
#include "ascon.h"
#include "word.h"
void printword(const char* text, const uint64_t x);
void printstate(const char* text, const state_t* s);
#else
#define printword(text, w) \
do { \
} while (0)
#define printstate(text, s) \
do { \
} while (0)
#endif
#endif /* PRINTSTATE_H_ */
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
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