1
0
mirror of https://github.com/taigrr/arduinolibs synced 2025-01-18 04:33:12 -08:00

ASCON-128 finalist from the CAESAR competition

This commit is contained in:
Rhys Weatherley 2018-04-27 11:01:29 +10:00
parent 84962a2008
commit 455549f835
8 changed files with 2067 additions and 2 deletions

View File

@ -24,7 +24,8 @@ Recent significant changes to the library
Apr 2018:
* Acorn128 authenticated cipher (finalist in the CAESAR AEAD competition).
* Acorn128 and Ascon128 authenticated ciphers (finalists in the CAESAR AEAD
competition in the light-weight category).
* Split the library into Crypto (core), CryptoLW (light-weight), and
CryptoLegacy (deprecated algorithms).
* Tiny and small versions of AES for reducing memory requirements.

View File

@ -59,7 +59,7 @@ The algorithms in the "libraries/CryptoLW" directory are new algorithms
that have been designed for "light-weight" environments where memory and
CPU resources are constrained:
\li Authenticated encryption with associated data (AEAD): Acorn128
\li Authenticated encryption with associated data (AEAD): Acorn128, Ascon128
\li Block ciphers: Speck, SpeckSmall, SpeckTiny
These algorithms are fairly new, but they are ideal for Arduino devices.
@ -165,6 +165,7 @@ Ardunino Mega 2560 running at 16 MHz are similar:
<tr><td>EAX&lt;Speck&gt; (256-bit key)</td><td align="right">25.89us</td><td align="right">25.88us</td><td align="right">690.63us</td><td align="right">362</td></tr>
<tr><td>EAX&lt;SpeckTiny&gt; (256-bit key)</td><td align="right">78.20us</td><td align="right">78.20us</td><td align="right">1269.19us</td><td align="right">122</td></tr>
<tr><td>Acorn128</td><td align="right">20.39us</td><td align="right">20.06us</td><td align="right">4817.82us</td><td align="right">60</td></tr>
<tr><td>Ascon128</td><td align="right">42.71us</td><td align="right">43.07us</td><td align="right">738.68us</td><td align="right">60</td></tr>
<tr><td colspan="5"> </td></tr>
<tr><td>Hash Algorithm</td><td align="right">Hashing (per byte)</td><td align="right">Finalization</td><td> </td><td>State Size (bytes)</td></tr>
<tr><td>SHA256</td><td align="right">43.85us</td><td align="right">2841.04us</td><td align="right"> </td><td align="right">107</td></tr>
@ -253,6 +254,7 @@ All figures are for the Arduino Due running at 84 MHz:
<tr><td>EAX&lt;Speck&gt; (256-bit key)</td><td align="right">2.80us</td><td align="right">2.80us</td><td align="right">81.63us</td><td align="right">384</td></tr>
<tr><td>EAX&lt;SpeckTiny&gt; (256-bit key)</td><td align="right">6.69us</td><td align="right">6.69us</td><td align="right">110.91us</td><td align="right">144</td></tr>
<tr><td>Acorn128</td><td align="right">0.75us</td><td align="right">0.75us</td><td align="right">175.70us</td><td align="right">64</td></tr>
<tr><td>Ascon128</td><td align="right">3.52us</td><td align="right">3.50us</td><td align="right">51.67us</td><td align="right">72</td></tr>
<tr><td colspan="5"> </td></tr>
<tr><td>Hash Algorithm</td><td align="right">Hashing (per byte)</td><td align="right">Finalization</td><td> </td><td>State Size (bytes)</td></tr>
<tr><td>SHA256</td><td align="right">1.15us</td><td align="right">76.60us</td><td align="right"> </td><td align="right">120</td></tr>

520
gen/genascon.c Normal file
View File

@ -0,0 +1,520 @@
/*
* Copyright (C) 2018 Southern Storm Software, Pty Ltd.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
// Special-purpose compiler that generates the AVR version of Ascon128.
#include <stdio.h>
#include <stdarg.h>
#include <stdlib.h>
static int indent = 4;
static const int temp_reg = 0; // Register number for the AVR "__tmp_reg__".
// Registers that can be used for temporary values, in the best
// order to allocate them. High registers are listed first.
static int regs[] = {
16, 17, 18, 19, 20, 21, 22, 23, 7, 8, 9, 10, 11, 12, 13, 14, 15
};
#define num_regs (sizeof(regs) / sizeof(regs[0]))
// Which registers are currently in use?
static int reg_in_use[num_regs] = {0};
// Which registers did we use while generating the code?
static int reg_used[num_regs] = {0};
// Information about a set of registers storing a 64-bit quantity.
typedef struct
{
int first; // First register in the set for 8-bit rotates.
int reg[8]; // Register numbers.
} Reg64;
// Indent the code and print a string.
void indent_printf(const char *format, ...)
{
va_list va;
int posn;
va_start(va, format);
for (posn = 0; posn < indent; ++posn)
putc(' ', stdout);
vfprintf(stdout, format, va);
va_end(va);
}
// Print an assembler instruction within quotes.
void insn_printf(const char *format, ...)
{
va_list va;
int posn;
va_start(va, format);
for (posn = 0; posn < indent; ++posn)
putc(' ', stdout);
putc('"', stdout);
vfprintf(stdout, format, va);
putc('\\', stdout);
putc('n', stdout);
putc('"', stdout);
putc('\n', stdout);
va_end(va);
}
// Allocate an unused register, starting with high registers.
void alloc_high_reg(int *reg)
{
unsigned index;
if (*reg != -1) {
fprintf(stderr, "Temporary register wasn't previously released\n");
exit(1);
}
for (index = 0; index < num_regs; ++index) {
if (!reg_in_use[index]) {
reg_in_use[index] = 1;
reg_used[index] = 1;
*reg = regs[index];
if (*reg < 16) {
fprintf(stderr, "Ran out of temporary high registers\n");
exit(1);
}
return;
}
}
fprintf(stderr, "Ran out of temporary registers\n");
exit(1);
}
// Allocate an unused register, starting with low registers
// because we know we won't need the value in a high reg later.
static void alloc_low_reg(int *reg)
{
unsigned index;
if (*reg != -1) {
fprintf(stderr, "Temporary register wasn't previously released\n");
exit(1);
}
for (index = num_regs; index > 0; --index) {
if (!reg_in_use[index - 1]) {
reg_in_use[index - 1] = 1;
reg_used[index - 1] = 1;
*reg = regs[index - 1];
return;
}
}
fprintf(stderr, "Ran out of temporary registers\n");
exit(1);
}
// Release a register back to the allocation pool.
static void release_reg(int *reg)
{
unsigned index;
for (index = 0; index < num_regs; ++index) {
if (regs[index] == *reg && reg_in_use[index]) {
reg_in_use[index] = 0;
*reg = -1;
return;
}
}
fprintf(stderr, "Released a register that was not in use\n");
exit(1);
}
// Check that we have a high register when we need one.
void check_high_reg(int *reg)
{
if ((*reg) < 16) {
fprintf(stderr, "r%d is not a high register\n", *reg);
exit(1);
}
}
// Check that all temporary registers have been released.
static void check_regs(void)
{
unsigned index;
for (index = 0; index < num_regs; ++index) {
if (reg_in_use[index]) {
fprintf(stderr, "Register r%d has not been released\n",
regs[index]);
exit(1);
}
}
}
// Allocate a 64-bit register set.
static void alloc_reg64(Reg64 *reg)
{
reg->first = 0;
reg->reg[0] = -1;
reg->reg[1] = -1;
reg->reg[2] = -1;
reg->reg[3] = -1;
reg->reg[4] = -1;
reg->reg[5] = -1;
reg->reg[6] = -1;
reg->reg[7] = -1;
alloc_low_reg(&(reg->reg[0]));
alloc_low_reg(&(reg->reg[1]));
alloc_low_reg(&(reg->reg[2]));
alloc_low_reg(&(reg->reg[3]));
alloc_low_reg(&(reg->reg[4]));
alloc_low_reg(&(reg->reg[5]));
alloc_low_reg(&(reg->reg[6]));
alloc_low_reg(&(reg->reg[7]));
}
// Release a 64-bit register set.
static void release_reg64(Reg64 *reg)
{
release_reg(&(reg->reg[0]));
release_reg(&(reg->reg[1]));
release_reg(&(reg->reg[2]));
release_reg(&(reg->reg[3]));
release_reg(&(reg->reg[4]));
release_reg(&(reg->reg[5]));
release_reg(&(reg->reg[6]));
release_reg(&(reg->reg[7]));
}
#define REGn(r, n) ((r)->reg[((n) + (r)->first) % 8])
// Rotate a 64-bit register left by 1 bit.
static void rotate_reg64_left_1(Reg64 *reg)
{
insn_printf("lsl r%d", REGn(reg, 0));
insn_printf("rol r%d", REGn(reg, 1));
insn_printf("rol r%d", REGn(reg, 2));
insn_printf("rol r%d", REGn(reg, 3));
insn_printf("rol r%d", REGn(reg, 4));
insn_printf("rol r%d", REGn(reg, 5));
insn_printf("rol r%d", REGn(reg, 6));
insn_printf("rol r%d", REGn(reg, 7));
insn_printf("adc r%d,__zero_reg__", REGn(reg, 0));
}
// Rotate a 64-bit register left by 8 bits.
static void rotate_reg64_left_8(Reg64 *reg)
{
reg->first = (reg->first + 7) % 8;
}
// Rotate a 64-bit register right by 1 bit.
static void rotate_reg64_right_1(Reg64 *reg)
{
insn_printf("bst r%d,0", REGn(reg, 0));
insn_printf("ror r%d", REGn(reg, 7));
insn_printf("ror r%d", REGn(reg, 6));
insn_printf("ror r%d", REGn(reg, 5));
insn_printf("ror r%d", REGn(reg, 4));
insn_printf("ror r%d", REGn(reg, 3));
insn_printf("ror r%d", REGn(reg, 2));
insn_printf("ror r%d", REGn(reg, 1));
insn_printf("ror r%d", REGn(reg, 0));
insn_printf("bld r%d,7", REGn(reg, 7));
}
// Rotate a 64-bit register right by 8 bits.
static void rotate_reg64_right_8(Reg64 *reg)
{
reg->first = (reg->first + 1) % 8;
}
// Rotate a 64-bit register right by a number of bits.
static void rotate_reg64_right(Reg64 *reg, int bits)
{
int bytes;
if ((bits % 8) < 4) {
// Rotate in the right direction.
bytes = bits / 8;
while (bytes > 0) {
rotate_reg64_right_8(reg);
--bytes;
}
bits %= 8;
while (bits > 0) {
rotate_reg64_right_1(reg);
--bits;
}
} else {
// Quicker to rotate in the left direction.
bits = 64 - bits;
bytes = bits / 8;
while (bytes > 0) {
rotate_reg64_left_8(reg);
--bytes;
}
bits %= 8;
while (bits > 0) {
rotate_reg64_left_1(reg);
--bits;
}
}
}
// Load a 64-bit register from a Z pointer offset.
static void load_reg64(Reg64 *reg, int offset)
{
int index;
for (index = 0; index < 8; ++index, ++offset) {
if (offset != 0)
insn_printf("ldd r%d,Z+%d", REGn(reg, index), offset);
else
insn_printf("ld r%d,Z", REGn(reg, index));
}
}
// Store a 64-bit register to a Z pointer offset.
static void store_reg64(Reg64 *reg, int offset)
{
int index;
for (index = 0; index < 8; ++index, ++offset) {
if (offset != 0)
insn_printf("std Z+%d,r%d", offset, REGn(reg, index));
else
insn_printf("st Z,r%d", REGn(reg, index));
}
}
// Copy one 64-bit register into another.
static void copy_reg64(Reg64 *dst, Reg64 *src)
{
int index;
for (index = 0; index < 8; ++index)
insn_printf("mov r%d,r%d", REGn(dst, index), REGn(src, index));
}
// XOR two 64-bit registers.
static void xor_reg64(Reg64 *dst, Reg64 *src)
{
int index;
for (index = 0; index < 8; ++index)
insn_printf("eor r%d,r%d", REGn(dst, index), REGn(src, index));
}
// Print the names of the temporary registers that we used.
static void temp_regs(void)
{
unsigned index;
int first = 1;
indent_printf(": ");
for (index = 0; index < num_regs; ++index) {
if (reg_used[index]) {
if (first) {
first = 0;
printf("\"r%d\"", regs[index]);
} else {
printf(", \"r%d\"", regs[index]);
}
}
}
printf(", \"memory\"\n");
}
// Handle one byte within the substitution layer.
static void substitute(int offset, int reg)
{
int x0 = -1;
int x1 = -1;
int x2 = reg;
int x3 = -1;
int x4 = -1;
int t0 = -1;
int t1 = -1;
int t2 = -1;
int t3 = -1;
int t4 = -1;
// Allocate five temporary registers for the five words.
// When processing the zero byte, we already have x2 loaded.
alloc_low_reg(&x0);
alloc_low_reg(&x1);
if (reg == -1)
alloc_low_reg(&x2);
alloc_low_reg(&x3);
alloc_low_reg(&x4);
// Need five more registers for intermediate results.
alloc_low_reg(&t0);
alloc_low_reg(&t1);
alloc_low_reg(&t2);
alloc_low_reg(&t3);
alloc_low_reg(&t4);
// Read the five bytes from the state.
if (offset != 0)
insn_printf("ldd r%d,Z+%d", x0, offset);
else
insn_printf("ld r%d,Z", x0);
insn_printf("ldd r%d,Z+%d", x1, 8 + offset);
if (reg == -1)
insn_printf("ldd r%d,Z+%d", x2, 16 + offset);
insn_printf("ldd r%d,Z+%d", x3, 24 + offset);
insn_printf("ldd r%d,Z+%d", x4, 32 + offset);
// Mix the bytes together.
// x0 ^= x4; x4 ^= x3; x2 ^= x1;
// t0 = ~x0; t1 = ~x1; t2 = ~x2; t3 = ~x3; t4 = ~x4;
// t0 &= x1; t1 &= x2; t2 &= x3; t3 &= x4; t4 &= x0;
// x0 ^= t1; x1 ^= t2; x2 ^= t3; x3 ^= t4; x4 ^= t0;
// x1 ^= x0; x0 ^= x4; x3 ^= x2; x2 = ~x2;
insn_printf("eor r%d,r%d", x0, x4);
insn_printf("eor r%d,r%d", x4, x3);
insn_printf("eor r%d,r%d", x2, x1);
insn_printf("mov r%d,r%d", t0, x0);
insn_printf("com r%d", t0);
insn_printf("and r%d,r%d", t0, x1);
insn_printf("mov r%d,r%d", t1, x1);
insn_printf("com r%d", t1);
insn_printf("and r%d,r%d", t1, x2);
insn_printf("mov r%d,r%d", t2, x2);
insn_printf("com r%d", t2);
insn_printf("and r%d,r%d", t2, x3);
insn_printf("mov r%d,r%d", t3, x3);
insn_printf("com r%d", t3);
insn_printf("and r%d,r%d", t3, x4);
insn_printf("mov r%d,r%d", t4, x4);
insn_printf("com r%d", t4);
insn_printf("and r%d,r%d", t4, x0);
insn_printf("eor r%d,r%d", x0, t1);
insn_printf("eor r%d,r%d", x1, t2);
insn_printf("eor r%d,r%d", x2, t3);
insn_printf("eor r%d,r%d", x3, t4);
insn_printf("eor r%d,r%d", x4, t0);
insn_printf("eor r%d,r%d", x1, x0);
insn_printf("eor r%d,r%d", x0, x4);
insn_printf("eor r%d,r%d", x3, x2);
insn_printf("com r%d", x2);
// Write the five bytes back to the state.
if (offset != 0)
insn_printf("std Z+%d,r%d", offset, x0);
else
insn_printf("st Z,r%d", x0);
insn_printf("std Z+%d,r%d", 8 + offset, x1);
insn_printf("std Z+%d,r%d", 16 + offset, x2);
insn_printf("std Z+%d,r%d", 24 + offset, x3);
insn_printf("std Z+%d,r%d", 32 + offset, x4);
// Release the temporary registers.
release_reg(&x0);
release_reg(&x1);
if (reg == -1)
release_reg(&x2);
release_reg(&x3);
release_reg(&x4);
release_reg(&t0);
release_reg(&t1);
release_reg(&t2);
release_reg(&t3);
release_reg(&t4);
}
static void diffuse(int n, int shift1, int shift2)
{
Reg64 x, t;
int offset = n * 8;
// Allocate the temporary registers that we need.
alloc_reg64(&x);
alloc_reg64(&t);
// Read the 64-bit word into the x registers.
load_reg64(&x, offset);
// Rotate step 1: t = x >>> shift1, t ^= x
copy_reg64(&t, &x);
rotate_reg64_right(&t, shift1);
xor_reg64(&t, &x);
// Rotate step 2: x = x >>> shift2, x ^= t
rotate_reg64_right(&x, shift2);
xor_reg64(&x, &t);
// Store the 64-bit result back to the state.
store_reg64(&x, offset);
// Release the temporary registers.
release_reg64(&x);
release_reg64(&t);
}
static void permute(void)
{
int reg = -1;
// Print the function header.
printf("void Ascon128::permute(uint8_t first)\n");
printf("{\n");
indent_printf("// AVR version generated by the genascon tool.\n");
indent_printf("__asm__ __volatile__ (\n");
indent += 4;
// Output the top of the loop.
insn_printf("1:");
// XOR the low byte of x2 with the round constant.
alloc_low_reg(&reg);
insn_printf("ldd r%d,Z+16", reg);
insn_printf("eor r%d,%%1", reg);
// Substitution layer. Mix the words one byte at a time.
// For the first byte we already have x2 loaded into "reg".
substitute(0, reg);
release_reg(&reg);
substitute(1, -1);
substitute(2, -1);
substitute(3, -1);
substitute(4, -1);
substitute(5, -1);
substitute(6, -1);
substitute(7, -1);
// Linear diffusion layer.
diffuse(0, 19, 28);
diffuse(1, 61, 39);
diffuse(2, 1, 6);
diffuse(3, 10, 17);
diffuse(4, 7, 41);
// Output the bottom of the loop.
insn_printf("subi %%1,0x0F");
insn_printf("cpi %%1,0x3C");
insn_printf("breq 2f");
insn_printf("rjmp 1b");
insn_printf("2:");
// Declare the registers that we need.
indent_printf(":: \"z\"(state.S), \"d\"((uint8_t)(0xF0 - (first << 4) + first))\n");
temp_regs();
indent -= 4;
indent_printf(");\n");
printf("}\n\n");
check_regs();
}
int main(int argc, char *argv[])
{
permute();
return 0;
}

View File

@ -37,6 +37,7 @@ SOURCES = \
AES192.cpp \
AES256.cpp \
AESCommon.cpp \
Ascon128.cpp \
AuthenticatedCipher.cpp \
BigNumberUtil.cpp \
BLAKE2b.cpp \
@ -79,6 +80,7 @@ SKETCHES = \
TestAES/TestAES.ino \
TestAESTiny/TestAESTiny.ino \
TestAESSmall/TestAESSmall.ino \
TestAscon/TestAscon.ino \
TestBigNumberUtil/TestBigNumberUtil.ino \
TestBLAKE2b/TestBLAKE2b.ino \
TestBLAKE2s/TestBLAKE2s.ino \

View File

@ -0,0 +1,403 @@
/*
* Copyright (C) 2018 Southern Storm Software, Pty Ltd.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
/*
This example runs tests on the Ascon128 implementation to verify
correct behaviour.
*/
#include <Crypto.h>
#include <CryptoLW.h>
#include <Ascon128.h>
#include "utility/ProgMemUtil.h"
#define MAX_PLAINTEXT_LEN 43
#define MAX_AUTHDATA_LEN 17
struct TestVector
{
const char *name;
uint8_t key[16];
uint8_t plaintext[MAX_PLAINTEXT_LEN];
uint8_t ciphertext[MAX_PLAINTEXT_LEN];
uint8_t authdata[MAX_AUTHDATA_LEN];
uint8_t iv[16];
uint8_t tag[16];
size_t authsize;
size_t datasize;
};
// Test vectors for Ascon128, generated with the reference Python version:
// https://github.com/meichlseder/pyascon
static TestVector const testVectorAscon128_1 PROGMEM = {
.name = "Ascon128 #1",
.key = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
.plaintext = {0x61, 0x73, 0x63, 0x6f, 0x6e},
.ciphertext = {0x86, 0x88, 0x62, 0x14, 0x0e},
.authdata = {0x41, 0x53, 0x43, 0x4f, 0x4e},
.iv = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
.tag = {0xad, 0x65, 0xf5, 0x94, 0x22, 0x58, 0xda, 0xd5,
0x3c, 0xaa, 0x7a, 0x56, 0xf3, 0xa2, 0x92, 0xd8},
.authsize = 5,
.datasize = 5
};
static TestVector const testVectorAscon128_2 PROGMEM = {
.name = "Ascon128 #2",
.key = {0x0d, 0x49, 0x29, 0x92, 0x65, 0x8b, 0xd8, 0xa3,
0xe4, 0x7b, 0xf9, 0x10, 0xd4, 0xc5, 0x87, 0xad},
.plaintext = {0x61},
.ciphertext = {0xc5},
.authdata = {0},
.iv = {0x5a, 0xcb, 0x17, 0x2a, 0x1a, 0x93, 0x3d, 0xb1,
0x8a, 0x6a, 0x40, 0xac, 0x6e, 0x4c, 0x68, 0xd0},
.tag = {0x2e, 0x0b, 0xf2, 0xb1, 0xfc, 0xd8, 0x64, 0x69,
0x01, 0x1c, 0x4f, 0x8b, 0x78, 0x4a, 0x65, 0x0d},
.authsize = 0,
.datasize = 1
};
static TestVector const testVectorAscon128_3 PROGMEM = {
.name = "Ascon128 #3",
.key = {0x91, 0xb3, 0x9d, 0x22, 0xf3, 0xb7, 0x7f, 0x51,
0x33, 0x0a, 0xa3, 0xa4, 0xea, 0x38, 0xea, 0xa2},
.plaintext = {0},
.ciphertext = {0},
.authdata = {0x64},
.iv = {0x2e, 0xec, 0x64, 0x25, 0xb3, 0xec, 0xf0, 0x63,
0xb4, 0x3e, 0x29, 0xc7, 0x68, 0x29, 0x3c, 0x49},
.tag = {0xfd, 0x24, 0x0e, 0x3c, 0x3d, 0xc4, 0x11, 0x0d,
0xe1, 0x54, 0x4c, 0xd5, 0x24, 0x18, 0xd9, 0x4c},
.authsize = 1,
.datasize = 0
};
static TestVector const testVectorAscon128_4 PROGMEM = {
.name = "Ascon128 #4",
.key = {0x72, 0xfd, 0x18, 0xde, 0xbd, 0xee, 0x86, 0x13,
0x4f, 0x7c, 0x44, 0x29, 0x84, 0x37, 0x56, 0x06},
.plaintext = {0x70, 0x6c, 0x61, 0x69, 0x6e, 0x74, 0x78, 0x74},
.ciphertext = {0x91, 0xd0, 0xc3, 0x88, 0xea, 0xc0, 0xe6, 0xd9},
.authdata = {0x61, 0x73, 0x73, 0x64, 0x61, 0x74, 0x31, 0x32},
.iv = {0x91, 0x5f, 0xf8, 0xff, 0xca, 0xd8, 0xae, 0x1d,
0xf4, 0x45, 0xeb, 0x03, 0xe2, 0x18, 0xfd, 0x25},
.tag = {0x16, 0x69, 0x74, 0xbf, 0xbd, 0x43, 0xd7, 0xa8,
0xfe, 0x43, 0xf0, 0xce, 0xe2, 0xdd, 0xb9, 0xf8},
.authsize = 8,
.datasize = 8
};
static TestVector const testVectorAscon128_5 PROGMEM = {
.name = "Ascon128 #5",
.key = {0x8a, 0xa5, 0xed, 0xc5, 0x88, 0x49, 0x75, 0xc8,
0xd1, 0xa1, 0xb8, 0x44, 0xd0, 0x15, 0x50, 0x5a},
.plaintext = {0x54, 0x68, 0x65, 0x20, 0x72, 0x61, 0x69, 0x6e,
0x20, 0x69, 0x6e, 0x20, 0x73, 0x70, 0x61, 0x69,
0x6e, 0x20, 0x66, 0x61, 0x6c, 0x6c, 0x73, 0x20,
0x6d, 0x61, 0x69, 0x6e, 0x6c, 0x79, 0x20, 0x6f,
0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x70, 0x6c,
0x61, 0x69, 0x6e},
.ciphertext = {0x4a, 0xb4, 0xe2, 0x87, 0x90, 0x07, 0x4b, 0x78,
0x88, 0x70, 0x71, 0xc0, 0x62, 0xd6, 0xab, 0x6b,
0x32, 0xd4, 0xb1, 0xec, 0xc7, 0xd8, 0x44, 0x93,
0x36, 0x9a, 0x38, 0x81, 0xd6, 0x65, 0x2f, 0x85,
0xaa, 0xf9, 0x70, 0x90, 0x61, 0x97, 0x3e, 0x1f,
0x60, 0x12, 0x66},
.authdata = {0x48, 0x6f, 0x77, 0x20, 0x6e, 0x6f, 0x77, 0x20,
0x62, 0x72, 0x6f, 0x77, 0x6e, 0x20, 0x63, 0x6f,
0x77},
.iv = {0xbc, 0x52, 0x27, 0xa5, 0x72, 0x58, 0xfe, 0x00,
0xcb, 0x7b, 0x0f, 0x31, 0xa4, 0xb6, 0xff, 0xda},
.tag = {0x92, 0xfe, 0x72, 0xf8, 0x69, 0xc9, 0x95, 0x41,
0x1f, 0xc4, 0x57, 0xde, 0xa6, 0xf2, 0xf9, 0x2d},
.authsize = 17,
.datasize = 43
};
TestVector testVector;
Ascon128 acorn;
byte buffer[128];
bool testCipher_N(Ascon128 *cipher, const struct TestVector *test, size_t inc)
{
size_t posn, len;
uint8_t tag[16];
if (!inc)
inc = 1;
cipher->clear();
if (!cipher->setKey(test->key, 16)) {
Serial.print("setKey ");
return false;
}
if (!cipher->setIV(test->iv, 16)) {
Serial.print("setIV ");
return false;
}
memset(buffer, 0xBA, sizeof(buffer));
for (posn = 0; posn < test->authsize; posn += inc) {
len = test->authsize - posn;
if (len > inc)
len = inc;
cipher->addAuthData(test->authdata + posn, len);
}
for (posn = 0; posn < test->datasize; posn += inc) {
len = test->datasize - posn;
if (len > inc)
len = inc;
cipher->encrypt(buffer + posn, test->plaintext + posn, len);
}
if (memcmp(buffer, test->ciphertext, test->datasize) != 0) {
Serial.print(buffer[0], HEX);
Serial.print("->");
Serial.print(test->ciphertext[0], HEX);
return false;
}
cipher->computeTag(tag, sizeof(tag));
if (memcmp(tag, test->tag, sizeof(tag)) != 0) {
Serial.print("computed wrong tag ... ");
return false;
}
cipher->setKey(test->key, 16);
cipher->setIV(test->iv, 16);
for (posn = 0; posn < test->authsize; posn += inc) {
len = test->authsize - posn;
if (len > inc)
len = inc;
cipher->addAuthData(test->authdata + posn, len);
}
for (posn = 0; posn < test->datasize; posn += inc) {
len = test->datasize - posn;
if (len > inc)
len = inc;
cipher->decrypt(buffer + posn, test->ciphertext + posn, len);
}
if (memcmp(buffer, test->plaintext, test->datasize) != 0)
return false;
if (!cipher->checkTag(tag, sizeof(tag))) {
Serial.print("tag did not check ... ");
return false;
}
return true;
}
void testCipher(Ascon128 *cipher, const struct TestVector *test)
{
bool ok;
memcpy_P(&testVector, test, sizeof(TestVector));
test = &testVector;
Serial.print(test->name);
Serial.print(" ... ");
ok = testCipher_N(cipher, test, test->datasize);
ok &= testCipher_N(cipher, test, 1);
ok &= testCipher_N(cipher, test, 2);
ok &= testCipher_N(cipher, test, 5);
ok &= testCipher_N(cipher, test, 8);
ok &= testCipher_N(cipher, test, 13);
ok &= testCipher_N(cipher, test, 16);
if (ok)
Serial.println("Passed");
else
Serial.println("Failed");
}
void perfCipherSetKey(Ascon128 *cipher, const struct TestVector *test)
{
unsigned long start;
unsigned long elapsed;
int count;
memcpy_P(&testVector, test, sizeof(TestVector));
test = &testVector;
Serial.print(test->name);
Serial.print(" SetKey ... ");
start = micros();
for (count = 0; count < 1000; ++count) {
cipher->setKey(test->key, 16);
cipher->setIV(test->iv, 16);
}
elapsed = micros() - start;
Serial.print(elapsed / 1000.0);
Serial.print("us per operation, ");
Serial.print((1000.0 * 1000000.0) / elapsed);
Serial.println(" per second");
}
void perfCipherEncrypt(Ascon128 *cipher, const struct TestVector *test)
{
unsigned long start;
unsigned long elapsed;
int count;
memcpy_P(&testVector, test, sizeof(TestVector));
test = &testVector;
Serial.print(test->name);
Serial.print(" Encrypt ... ");
cipher->setKey(test->key, 16);
cipher->setIV(test->iv, 16);
start = micros();
for (count = 0; count < 500; ++count) {
cipher->encrypt(buffer, buffer, 128);
}
elapsed = micros() - start;
Serial.print(elapsed / (128.0 * 500.0));
Serial.print("us per byte, ");
Serial.print((128.0 * 500.0 * 1000000.0) / elapsed);
Serial.println(" bytes per second");
}
void perfCipherDecrypt(Ascon128 *cipher, const struct TestVector *test)
{
unsigned long start;
unsigned long elapsed;
int count;
memcpy_P(&testVector, test, sizeof(TestVector));
test = &testVector;
Serial.print(test->name);
Serial.print(" Decrypt ... ");
cipher->setKey(test->key, 16);
cipher->setIV(test->iv, 16);
start = micros();
for (count = 0; count < 500; ++count) {
cipher->decrypt(buffer, buffer, 128);
}
elapsed = micros() - start;
Serial.print(elapsed / (128.0 * 500.0));
Serial.print("us per byte, ");
Serial.print((128.0 * 500.0 * 1000000.0) / elapsed);
Serial.println(" bytes per second");
}
void perfCipherAddAuthData(Ascon128 *cipher, const struct TestVector *test)
{
unsigned long start;
unsigned long elapsed;
int count;
memcpy_P(&testVector, test, sizeof(TestVector));
test = &testVector;
Serial.print(test->name);
Serial.print(" AddAuthData ... ");
cipher->setKey(test->key, 16);
cipher->setIV(test->iv, 16);
start = micros();
memset(buffer, 0xBA, 128);
for (count = 0; count < 500; ++count) {
cipher->addAuthData(buffer, 128);
}
elapsed = micros() - start;
Serial.print(elapsed / (128.0 * 500.0));
Serial.print("us per byte, ");
Serial.print((128.0 * 500.0 * 1000000.0) / elapsed);
Serial.println(" bytes per second");
}
void perfCipherComputeTag(Ascon128 *cipher, const struct TestVector *test)
{
unsigned long start;
unsigned long elapsed;
int count;
memcpy_P(&testVector, test, sizeof(TestVector));
test = &testVector;
Serial.print(test->name);
Serial.print(" ComputeTag ... ");
cipher->setKey(test->key, 16);
cipher->setIV(test->iv, 16);
start = micros();
for (count = 0; count < 1000; ++count) {
cipher->computeTag(buffer, 16);
}
elapsed = micros() - start;
Serial.print(elapsed / 1000.0);
Serial.print("us per operation, ");
Serial.print((1000.0 * 1000000.0) / elapsed);
Serial.println(" per second");
}
void perfCipher(Ascon128 *cipher, const struct TestVector *test)
{
perfCipherSetKey(cipher, test);
perfCipherEncrypt(cipher, test);
perfCipherDecrypt(cipher, test);
perfCipherAddAuthData(cipher, test);
perfCipherComputeTag(cipher, test);
}
void setup()
{
Serial.begin(9600);
Serial.println();
Serial.print("State Size ... ");
Serial.println(sizeof(Ascon128));
Serial.println();
Serial.println("Test Vectors:");
testCipher(&acorn, &testVectorAscon128_1);
testCipher(&acorn, &testVectorAscon128_2);
testCipher(&acorn, &testVectorAscon128_3);
testCipher(&acorn, &testVectorAscon128_4);
testCipher(&acorn, &testVectorAscon128_5);
Serial.println();
Serial.println("Performance Tests:");
perfCipher(&acorn, &testVectorAscon128_4);
}
void loop()
{
}

View File

@ -0,0 +1,356 @@
/*
* Copyright (C) 2018 Southern Storm Software, Pty Ltd.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#include "Ascon128.h"
#include "Crypto.h"
#include "utility/EndianUtil.h"
#include "utility/RotateUtil.h"
#include "utility/ProgMemUtil.h"
#include <string.h>
/**
* \class Ascon128 Ascon128.h <Ascon128.h>
* \brief ASCON-128 authenticated cipher.
*
* Ascon128 is an authenticated cipher designed for memory-limited
* environments with a 128-bit key, a 128-bit initialization vector,
* and a 128-bit authentication tag. It was one of the finalists
* in the CAESAR AEAD competition.
*
* References: http://competitions.cr.yp.to/round3/asconv12.pdf,
* http://ascon.iaik.tugraz.at/
*
* \sa AuthenticatedCipher
*/
/**
* \brief Constructs a new Ascon128 authenticated cipher.
*/
Ascon128::Ascon128()
#if defined(CRYPTO_LITTLE_ENDIAN)
: posn(7)
, authMode(1)
#else
: posn(0)
, authMode(1)
#endif
{
}
/**
* \brief Destroys this Ascon128 authenticated cipher.
*/
Ascon128::~Ascon128()
{
clean(state);
}
/**
* \brief Gets the size of the Ascon128 key in bytes.
*
* \return Always returns 16, indicating a 128-bit key.
*/
size_t Ascon128::keySize() const
{
return 16;
}
/**
* \brief Gets the size of the Ascon128 initialization vector in bytes.
*
* \return Always returns 16, indicating a 128-bit IV.
*
* Authentication tags may be truncated to 8 bytes, but the algorithm authors
* recommend using a full 16-byte tag.
*/
size_t Ascon128::ivSize() const
{
return 16;
}
/**
* \brief Gets the size of the Ascon128 authentication tag in bytes.
*
* \return Always returns 16, indicating a 128-bit authentication tag.
*/
size_t Ascon128::tagSize() const
{
return 16;
}
bool Ascon128::setKey(const uint8_t *key, size_t len)
{
if (len != 16)
return false;
memcpy(state.K, key, 16);
#if defined(CRYPTO_LITTLE_ENDIAN)
state.K[0] = be64toh(state.K[0]);
state.K[1] = be64toh(state.K[1]);
#endif
return true;
}
bool Ascon128::setIV(const uint8_t *iv, size_t len)
{
// Validate the length of the IV.
if (len != 16)
return false;
// Set up the initial state.
state.S[0] = 0x80400C0600000000ULL;
state.S[1] = state.K[0];
state.S[2] = state.K[1];
memcpy(state.S + 3, iv, 16);
#if defined(CRYPTO_LITTLE_ENDIAN)
state.S[3] = be64toh(state.S[3]);
state.S[4] = be64toh(state.S[4]);
posn = 7;
authMode = 1;
#else
posn = 0;
authMode = 1;
#endif
// Permute the state with 12 rounds starting at round 0.
permute(0);
// XOR the end of the state with the original key.
state.S[3] ^= state.K[0];
state.S[4] ^= state.K[1];
return true;
}
void Ascon128::encrypt(uint8_t *output, const uint8_t *input, size_t len)
{
if (authMode)
endAuth();
const uint8_t *in = (const uint8_t *)input;
uint8_t *out = (uint8_t *)output;
while (len > 0) {
// Encrypt the next byte using the first 64-bit word in the state.
((uint8_t *)(state.S))[posn] ^= *in++;
*out++ = ((const uint8_t *)(state.S))[posn];
--len;
// Permute the state for b = 6 rounds at the end of each block.
#if defined(CRYPTO_LITTLE_ENDIAN)
if (posn > 0) {
--posn;
} else {
permute(6);
posn = 7;
}
#else
if ((++posn) == 8) {
permute(6);
posn = 0;
}
#endif
}
}
void Ascon128::decrypt(uint8_t *output, const uint8_t *input, size_t len)
{
if (authMode)
endAuth();
const uint8_t *in = (const uint8_t *)input;
uint8_t *out = (uint8_t *)output;
while (len > 0) {
// Decrypt the next byte using the first 64-bit word in the state.
*out++ = ((const uint8_t *)(state.S))[posn] ^ *in;
((uint8_t *)(state.S))[posn] = *in++;
--len;
// Permute the state for b = 6 rounds at the end of each block.
#if defined(CRYPTO_LITTLE_ENDIAN)
if (posn > 0) {
--posn;
} else {
permute(6);
posn = 7;
}
#else
if ((++posn) == 8) {
permute(6);
posn = 0;
}
#endif
}
}
void Ascon128::addAuthData(const void *data, size_t len)
{
if (!authMode)
return;
const uint8_t *in = (const uint8_t *)data;
while (len > 0) {
// Incorporate the next byte of auth data into the internal state.
((uint8_t *)(state.S))[posn] ^= *in++;
--len;
// Permute the state for b = 6 rounds at the end of each block.
#if defined(CRYPTO_LITTLE_ENDIAN)
if (posn > 0) {
--posn;
} else {
permute(6);
posn = 7;
}
#else
if ((++posn) == 8) {
permute(6);
posn = 0;
}
#endif
}
authMode = 2; // We have some auth data now.
}
void Ascon128::computeTag(void *tag, size_t len)
{
// End authentication mode if there was no plaintext/ciphertext.
if (authMode)
endAuth();
// Pad the last block, add the original key, and permute the state.
((uint8_t *)(state.S))[posn] ^= 0x80;
state.S[1] ^= state.K[0];
state.S[2] ^= state.K[1];
permute(0);
// Compute the tag and convert it into big-endian in the return buffer.
uint64_t T[2];
T[0] = htobe64(state.S[3] ^ state.K[0]);
T[1] = htobe64(state.S[4] ^ state.K[1]);
if (len > 16)
len = 16;
memcpy(tag, T, len);
clean(T);
}
bool Ascon128::checkTag(const void *tag, size_t len)
{
// The tag can never match if it is larger than the maximum allowed size.
if (len > 16)
return false;
// End authentication mode if there was no plaintext/ciphertext.
if (authMode)
endAuth();
// Pad the last block, add the original key, and permute the state.
((uint8_t *)(state.S))[posn] ^= 0x80;
state.S[1] ^= state.K[0];
state.S[2] ^= state.K[1];
permute(0);
// Compute the tag and convert it into big-endian.
uint64_t T[2];
T[0] = htobe64(state.S[3] ^ state.K[0]);
T[1] = htobe64(state.S[4] ^ state.K[1]);
if (len > 16)
len = 16;
bool ok = secure_compare(T, tag, len);
clean(T);
return ok;
}
/**
* \brief Clears all security-sensitive state from this cipher object.
*/
void Ascon128::clear()
{
clean(state);
#if defined(CRYPTO_LITTLE_ENDIAN)
posn = 7;
authMode = 1;
#else
posn = 0;
authMode = 1;
#endif
}
#if !defined(__AVR__) || defined(CRYPTO_DOC)
/**
* \brief Permutes the Ascon128 state.
*
* \param first The first round start permuting at, between 0 and 11.
*/
void Ascon128::permute(uint8_t first)
{
uint64_t t0, t1, t2, t3, t4;
#define x0 state.S[0]
#define x1 state.S[1]
#define x2 state.S[2]
#define x3 state.S[3]
#define x4 state.S[4]
while (first < 12) {
// Add the round constant to the state.
x2 ^= ((0x0F - first) << 4) | first;
// Substitution layer - apply the s-box using bit-slicing
// according to the algorithm recommended in the specification.
x0 ^= x4; x4 ^= x3; x2 ^= x1;
t0 = ~x0; t1 = ~x1; t2 = ~x2; t3 = ~x3; t4 = ~x4;
t0 &= x1; t1 &= x2; t2 &= x3; t3 &= x4; t4 &= x0;
x0 ^= t1; x1 ^= t2; x2 ^= t3; x3 ^= t4; x4 ^= t0;
x1 ^= x0; x0 ^= x4; x3 ^= x2; x2 = ~x2;
// Linear diffusion layer.
x0 ^= rightRotate19_64(x0) ^ rightRotate28_64(x0);
x1 ^= rightRotate61_64(x1) ^ rightRotate39_64(x1);
x2 ^= rightRotate1_64(x2) ^ rightRotate6_64(x2);
x3 ^= rightRotate10_64(x3) ^ rightRotate17_64(x3);
x4 ^= rightRotate7_64(x4) ^ rightRotate41_64(x4);
// Move onto the next round.
++first;
}
#undef x0
#undef x1
#undef x2
#undef x3
#undef x4
}
#endif // !__AVR__
/**
* \brief Ends authenticating the associated data and moves onto encryption.
*/
void Ascon128::endAuth()
{
if (authMode == 2) {
// We had some auth data, so we need to pad and permute the last block.
// There is no need to do this if there were zero bytes of auth data.
((uint8_t *)(state.S))[posn] ^= 0x80;
permute(6);
}
state.S[4] ^= 1; // Domain separation between auth data and payload data.
authMode = 0;
#if defined(CRYPTO_LITTLE_ENDIAN)
posn = 7;
#else
posn = 0;
#endif
}

View File

@ -0,0 +1,63 @@
/*
* Copyright (C) 2018 Southern Storm Software, Pty Ltd.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#ifndef CRYPTO_ASCON128_H
#define CRYPTO_ASCON128_H
#include "AuthenticatedCipher.h"
class Ascon128 : public AuthenticatedCipher
{
public:
Ascon128();
virtual ~Ascon128();
size_t keySize() const;
size_t ivSize() const;
size_t tagSize() const;
bool setKey(const uint8_t *key, size_t len);
bool setIV(const uint8_t *iv, size_t len);
void encrypt(uint8_t *output, const uint8_t *input, size_t len);
void decrypt(uint8_t *output, const uint8_t *input, size_t len);
void addAuthData(const void *data, size_t len);
void computeTag(void *tag, size_t len);
bool checkTag(const void *tag, size_t len);
void clear();
private:
struct {
uint64_t K[2];
uint64_t S[5];
} state;
uint8_t posn;
uint8_t authMode;
void permute(uint8_t first);
void endAuth();
};
#endif

View File

@ -0,0 +1,718 @@
/*
* Copyright (C) 2018 Southern Storm Software, Pty Ltd.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#include "Ascon128.h"
#if defined(__AVR__)
void Ascon128::permute(uint8_t first)
{
// AVR version generated by the genascon tool.
__asm__ __volatile__ (
"1:\n"
"ldd r15,Z+16\n"
"eor r15,%1\n"
"ld r14,Z\n"
"ldd r13,Z+8\n"
"ldd r12,Z+24\n"
"ldd r11,Z+32\n"
"eor r14,r11\n"
"eor r11,r12\n"
"eor r15,r13\n"
"mov r10,r14\n"
"com r10\n"
"and r10,r13\n"
"mov r9,r13\n"
"com r9\n"
"and r9,r15\n"
"mov r8,r15\n"
"com r8\n"
"and r8,r12\n"
"mov r7,r12\n"
"com r7\n"
"and r7,r11\n"
"mov r23,r11\n"
"com r23\n"
"and r23,r14\n"
"eor r14,r9\n"
"eor r13,r8\n"
"eor r15,r7\n"
"eor r12,r23\n"
"eor r11,r10\n"
"eor r13,r14\n"
"eor r14,r11\n"
"eor r12,r15\n"
"com r15\n"
"st Z,r14\n"
"std Z+8,r13\n"
"std Z+16,r15\n"
"std Z+24,r12\n"
"std Z+32,r11\n"
"ldd r15,Z+1\n"
"ldd r14,Z+9\n"
"ldd r13,Z+17\n"
"ldd r12,Z+25\n"
"ldd r11,Z+33\n"
"eor r15,r11\n"
"eor r11,r12\n"
"eor r13,r14\n"
"mov r10,r15\n"
"com r10\n"
"and r10,r14\n"
"mov r9,r14\n"
"com r9\n"
"and r9,r13\n"
"mov r8,r13\n"
"com r8\n"
"and r8,r12\n"
"mov r7,r12\n"
"com r7\n"
"and r7,r11\n"
"mov r23,r11\n"
"com r23\n"
"and r23,r15\n"
"eor r15,r9\n"
"eor r14,r8\n"
"eor r13,r7\n"
"eor r12,r23\n"
"eor r11,r10\n"
"eor r14,r15\n"
"eor r15,r11\n"
"eor r12,r13\n"
"com r13\n"
"std Z+1,r15\n"
"std Z+9,r14\n"
"std Z+17,r13\n"
"std Z+25,r12\n"
"std Z+33,r11\n"
"ldd r15,Z+2\n"
"ldd r14,Z+10\n"
"ldd r13,Z+18\n"
"ldd r12,Z+26\n"
"ldd r11,Z+34\n"
"eor r15,r11\n"
"eor r11,r12\n"
"eor r13,r14\n"
"mov r10,r15\n"
"com r10\n"
"and r10,r14\n"
"mov r9,r14\n"
"com r9\n"
"and r9,r13\n"
"mov r8,r13\n"
"com r8\n"
"and r8,r12\n"
"mov r7,r12\n"
"com r7\n"
"and r7,r11\n"
"mov r23,r11\n"
"com r23\n"
"and r23,r15\n"
"eor r15,r9\n"
"eor r14,r8\n"
"eor r13,r7\n"
"eor r12,r23\n"
"eor r11,r10\n"
"eor r14,r15\n"
"eor r15,r11\n"
"eor r12,r13\n"
"com r13\n"
"std Z+2,r15\n"
"std Z+10,r14\n"
"std Z+18,r13\n"
"std Z+26,r12\n"
"std Z+34,r11\n"
"ldd r15,Z+3\n"
"ldd r14,Z+11\n"
"ldd r13,Z+19\n"
"ldd r12,Z+27\n"
"ldd r11,Z+35\n"
"eor r15,r11\n"
"eor r11,r12\n"
"eor r13,r14\n"
"mov r10,r15\n"
"com r10\n"
"and r10,r14\n"
"mov r9,r14\n"
"com r9\n"
"and r9,r13\n"
"mov r8,r13\n"
"com r8\n"
"and r8,r12\n"
"mov r7,r12\n"
"com r7\n"
"and r7,r11\n"
"mov r23,r11\n"
"com r23\n"
"and r23,r15\n"
"eor r15,r9\n"
"eor r14,r8\n"
"eor r13,r7\n"
"eor r12,r23\n"
"eor r11,r10\n"
"eor r14,r15\n"
"eor r15,r11\n"
"eor r12,r13\n"
"com r13\n"
"std Z+3,r15\n"
"std Z+11,r14\n"
"std Z+19,r13\n"
"std Z+27,r12\n"
"std Z+35,r11\n"
"ldd r15,Z+4\n"
"ldd r14,Z+12\n"
"ldd r13,Z+20\n"
"ldd r12,Z+28\n"
"ldd r11,Z+36\n"
"eor r15,r11\n"
"eor r11,r12\n"
"eor r13,r14\n"
"mov r10,r15\n"
"com r10\n"
"and r10,r14\n"
"mov r9,r14\n"
"com r9\n"
"and r9,r13\n"
"mov r8,r13\n"
"com r8\n"
"and r8,r12\n"
"mov r7,r12\n"
"com r7\n"
"and r7,r11\n"
"mov r23,r11\n"
"com r23\n"
"and r23,r15\n"
"eor r15,r9\n"
"eor r14,r8\n"
"eor r13,r7\n"
"eor r12,r23\n"
"eor r11,r10\n"
"eor r14,r15\n"
"eor r15,r11\n"
"eor r12,r13\n"
"com r13\n"
"std Z+4,r15\n"
"std Z+12,r14\n"
"std Z+20,r13\n"
"std Z+28,r12\n"
"std Z+36,r11\n"
"ldd r15,Z+5\n"
"ldd r14,Z+13\n"
"ldd r13,Z+21\n"
"ldd r12,Z+29\n"
"ldd r11,Z+37\n"
"eor r15,r11\n"
"eor r11,r12\n"
"eor r13,r14\n"
"mov r10,r15\n"
"com r10\n"
"and r10,r14\n"
"mov r9,r14\n"
"com r9\n"
"and r9,r13\n"
"mov r8,r13\n"
"com r8\n"
"and r8,r12\n"
"mov r7,r12\n"
"com r7\n"
"and r7,r11\n"
"mov r23,r11\n"
"com r23\n"
"and r23,r15\n"
"eor r15,r9\n"
"eor r14,r8\n"
"eor r13,r7\n"
"eor r12,r23\n"
"eor r11,r10\n"
"eor r14,r15\n"
"eor r15,r11\n"
"eor r12,r13\n"
"com r13\n"
"std Z+5,r15\n"
"std Z+13,r14\n"
"std Z+21,r13\n"
"std Z+29,r12\n"
"std Z+37,r11\n"
"ldd r15,Z+6\n"
"ldd r14,Z+14\n"
"ldd r13,Z+22\n"
"ldd r12,Z+30\n"
"ldd r11,Z+38\n"
"eor r15,r11\n"
"eor r11,r12\n"
"eor r13,r14\n"
"mov r10,r15\n"
"com r10\n"
"and r10,r14\n"
"mov r9,r14\n"
"com r9\n"
"and r9,r13\n"
"mov r8,r13\n"
"com r8\n"
"and r8,r12\n"
"mov r7,r12\n"
"com r7\n"
"and r7,r11\n"
"mov r23,r11\n"
"com r23\n"
"and r23,r15\n"
"eor r15,r9\n"
"eor r14,r8\n"
"eor r13,r7\n"
"eor r12,r23\n"
"eor r11,r10\n"
"eor r14,r15\n"
"eor r15,r11\n"
"eor r12,r13\n"
"com r13\n"
"std Z+6,r15\n"
"std Z+14,r14\n"
"std Z+22,r13\n"
"std Z+30,r12\n"
"std Z+38,r11\n"
"ldd r15,Z+7\n"
"ldd r14,Z+15\n"
"ldd r13,Z+23\n"
"ldd r12,Z+31\n"
"ldd r11,Z+39\n"
"eor r15,r11\n"
"eor r11,r12\n"
"eor r13,r14\n"
"mov r10,r15\n"
"com r10\n"
"and r10,r14\n"
"mov r9,r14\n"
"com r9\n"
"and r9,r13\n"
"mov r8,r13\n"
"com r8\n"
"and r8,r12\n"
"mov r7,r12\n"
"com r7\n"
"and r7,r11\n"
"mov r23,r11\n"
"com r23\n"
"and r23,r15\n"
"eor r15,r9\n"
"eor r14,r8\n"
"eor r13,r7\n"
"eor r12,r23\n"
"eor r11,r10\n"
"eor r14,r15\n"
"eor r15,r11\n"
"eor r12,r13\n"
"com r13\n"
"std Z+7,r15\n"
"std Z+15,r14\n"
"std Z+23,r13\n"
"std Z+31,r12\n"
"std Z+39,r11\n"
"ld r15,Z\n"
"ldd r14,Z+1\n"
"ldd r13,Z+2\n"
"ldd r12,Z+3\n"
"ldd r11,Z+4\n"
"ldd r10,Z+5\n"
"ldd r9,Z+6\n"
"ldd r8,Z+7\n"
"mov r7,r15\n"
"mov r23,r14\n"
"mov r22,r13\n"
"mov r21,r12\n"
"mov r20,r11\n"
"mov r19,r10\n"
"mov r18,r9\n"
"mov r17,r8\n"
"bst r22,0\n"
"ror r23\n"
"ror r7\n"
"ror r17\n"
"ror r18\n"
"ror r19\n"
"ror r20\n"
"ror r21\n"
"ror r22\n"
"bld r23,7\n"
"bst r22,0\n"
"ror r23\n"
"ror r7\n"
"ror r17\n"
"ror r18\n"
"ror r19\n"
"ror r20\n"
"ror r21\n"
"ror r22\n"
"bld r23,7\n"
"bst r22,0\n"
"ror r23\n"
"ror r7\n"
"ror r17\n"
"ror r18\n"
"ror r19\n"
"ror r20\n"
"ror r21\n"
"ror r22\n"
"bld r23,7\n"
"eor r22,r15\n"
"eor r21,r14\n"
"eor r20,r13\n"
"eor r19,r12\n"
"eor r18,r11\n"
"eor r17,r10\n"
"eor r7,r9\n"
"eor r23,r8\n"
"lsl r11\n"
"rol r10\n"
"rol r9\n"
"rol r8\n"
"rol r15\n"
"rol r14\n"
"rol r13\n"
"rol r12\n"
"adc r11,__zero_reg__\n"
"lsl r11\n"
"rol r10\n"
"rol r9\n"
"rol r8\n"
"rol r15\n"
"rol r14\n"
"rol r13\n"
"rol r12\n"
"adc r11,__zero_reg__\n"
"lsl r11\n"
"rol r10\n"
"rol r9\n"
"rol r8\n"
"rol r15\n"
"rol r14\n"
"rol r13\n"
"rol r12\n"
"adc r11,__zero_reg__\n"
"lsl r11\n"
"rol r10\n"
"rol r9\n"
"rol r8\n"
"rol r15\n"
"rol r14\n"
"rol r13\n"
"rol r12\n"
"adc r11,__zero_reg__\n"
"eor r11,r22\n"
"eor r10,r21\n"
"eor r9,r20\n"
"eor r8,r19\n"
"eor r15,r18\n"
"eor r14,r17\n"
"eor r13,r7\n"
"eor r12,r23\n"
"st Z,r11\n"
"std Z+1,r10\n"
"std Z+2,r9\n"
"std Z+3,r8\n"
"std Z+4,r15\n"
"std Z+5,r14\n"
"std Z+6,r13\n"
"std Z+7,r12\n"
"ldd r15,Z+8\n"
"ldd r14,Z+9\n"
"ldd r13,Z+10\n"
"ldd r12,Z+11\n"
"ldd r11,Z+12\n"
"ldd r10,Z+13\n"
"ldd r9,Z+14\n"
"ldd r8,Z+15\n"
"mov r7,r15\n"
"mov r23,r14\n"
"mov r22,r13\n"
"mov r21,r12\n"
"mov r20,r11\n"
"mov r19,r10\n"
"mov r18,r9\n"
"mov r17,r8\n"
"lsl r7\n"
"rol r23\n"
"rol r22\n"
"rol r21\n"
"rol r20\n"
"rol r19\n"
"rol r18\n"
"rol r17\n"
"adc r7,__zero_reg__\n"
"lsl r7\n"
"rol r23\n"
"rol r22\n"
"rol r21\n"
"rol r20\n"
"rol r19\n"
"rol r18\n"
"rol r17\n"
"adc r7,__zero_reg__\n"
"lsl r7\n"
"rol r23\n"
"rol r22\n"
"rol r21\n"
"rol r20\n"
"rol r19\n"
"rol r18\n"
"rol r17\n"
"adc r7,__zero_reg__\n"
"eor r7,r15\n"
"eor r23,r14\n"
"eor r22,r13\n"
"eor r21,r12\n"
"eor r20,r11\n"
"eor r19,r10\n"
"eor r18,r9\n"
"eor r17,r8\n"
"lsl r10\n"
"rol r9\n"
"rol r8\n"
"rol r15\n"
"rol r14\n"
"rol r13\n"
"rol r12\n"
"rol r11\n"
"adc r10,__zero_reg__\n"
"eor r10,r7\n"
"eor r9,r23\n"
"eor r8,r22\n"
"eor r15,r21\n"
"eor r14,r20\n"
"eor r13,r19\n"
"eor r12,r18\n"
"eor r11,r17\n"
"std Z+8,r10\n"
"std Z+9,r9\n"
"std Z+10,r8\n"
"std Z+11,r15\n"
"std Z+12,r14\n"
"std Z+13,r13\n"
"std Z+14,r12\n"
"std Z+15,r11\n"
"ldd r15,Z+16\n"
"ldd r14,Z+17\n"
"ldd r13,Z+18\n"
"ldd r12,Z+19\n"
"ldd r11,Z+20\n"
"ldd r10,Z+21\n"
"ldd r9,Z+22\n"
"ldd r8,Z+23\n"
"mov r7,r15\n"
"mov r23,r14\n"
"mov r22,r13\n"
"mov r21,r12\n"
"mov r20,r11\n"
"mov r19,r10\n"
"mov r18,r9\n"
"mov r17,r8\n"
"bst r7,0\n"
"ror r17\n"
"ror r18\n"
"ror r19\n"
"ror r20\n"
"ror r21\n"
"ror r22\n"
"ror r23\n"
"ror r7\n"
"bld r17,7\n"
"eor r7,r15\n"
"eor r23,r14\n"
"eor r22,r13\n"
"eor r21,r12\n"
"eor r20,r11\n"
"eor r19,r10\n"
"eor r18,r9\n"
"eor r17,r8\n"
"lsl r14\n"
"rol r13\n"
"rol r12\n"
"rol r11\n"
"rol r10\n"
"rol r9\n"
"rol r8\n"
"rol r15\n"
"adc r14,__zero_reg__\n"
"lsl r14\n"
"rol r13\n"
"rol r12\n"
"rol r11\n"
"rol r10\n"
"rol r9\n"
"rol r8\n"
"rol r15\n"
"adc r14,__zero_reg__\n"
"eor r14,r7\n"
"eor r13,r23\n"
"eor r12,r22\n"
"eor r11,r21\n"
"eor r10,r20\n"
"eor r9,r19\n"
"eor r8,r18\n"
"eor r15,r17\n"
"std Z+16,r14\n"
"std Z+17,r13\n"
"std Z+18,r12\n"
"std Z+19,r11\n"
"std Z+20,r10\n"
"std Z+21,r9\n"
"std Z+22,r8\n"
"std Z+23,r15\n"
"ldd r15,Z+24\n"
"ldd r14,Z+25\n"
"ldd r13,Z+26\n"
"ldd r12,Z+27\n"
"ldd r11,Z+28\n"
"ldd r10,Z+29\n"
"ldd r9,Z+30\n"
"ldd r8,Z+31\n"
"mov r7,r15\n"
"mov r23,r14\n"
"mov r22,r13\n"
"mov r21,r12\n"
"mov r20,r11\n"
"mov r19,r10\n"
"mov r18,r9\n"
"mov r17,r8\n"
"bst r23,0\n"
"ror r7\n"
"ror r17\n"
"ror r18\n"
"ror r19\n"
"ror r20\n"
"ror r21\n"
"ror r22\n"
"ror r23\n"
"bld r7,7\n"
"bst r23,0\n"
"ror r7\n"
"ror r17\n"
"ror r18\n"
"ror r19\n"
"ror r20\n"
"ror r21\n"
"ror r22\n"
"ror r23\n"
"bld r7,7\n"
"eor r23,r15\n"
"eor r22,r14\n"
"eor r21,r13\n"
"eor r20,r12\n"
"eor r19,r11\n"
"eor r18,r10\n"
"eor r17,r9\n"
"eor r7,r8\n"
"bst r13,0\n"
"ror r14\n"
"ror r15\n"
"ror r8\n"
"ror r9\n"
"ror r10\n"
"ror r11\n"
"ror r12\n"
"ror r13\n"
"bld r14,7\n"
"eor r13,r23\n"
"eor r12,r22\n"
"eor r11,r21\n"
"eor r10,r20\n"
"eor r9,r19\n"
"eor r8,r18\n"
"eor r15,r17\n"
"eor r14,r7\n"
"std Z+24,r13\n"
"std Z+25,r12\n"
"std Z+26,r11\n"
"std Z+27,r10\n"
"std Z+28,r9\n"
"std Z+29,r8\n"
"std Z+30,r15\n"
"std Z+31,r14\n"
"ldd r15,Z+32\n"
"ldd r14,Z+33\n"
"ldd r13,Z+34\n"
"ldd r12,Z+35\n"
"ldd r11,Z+36\n"
"ldd r10,Z+37\n"
"ldd r9,Z+38\n"
"ldd r8,Z+39\n"
"mov r7,r15\n"
"mov r23,r14\n"
"mov r22,r13\n"
"mov r21,r12\n"
"mov r20,r11\n"
"mov r19,r10\n"
"mov r18,r9\n"
"mov r17,r8\n"
"lsl r23\n"
"rol r22\n"
"rol r21\n"
"rol r20\n"
"rol r19\n"
"rol r18\n"
"rol r17\n"
"rol r7\n"
"adc r23,__zero_reg__\n"
"eor r23,r15\n"
"eor r22,r14\n"
"eor r21,r13\n"
"eor r20,r12\n"
"eor r19,r11\n"
"eor r18,r10\n"
"eor r17,r9\n"
"eor r7,r8\n"
"bst r10,0\n"
"ror r11\n"
"ror r12\n"
"ror r13\n"
"ror r14\n"
"ror r15\n"
"ror r8\n"
"ror r9\n"
"ror r10\n"
"bld r11,7\n"
"eor r10,r23\n"
"eor r9,r22\n"
"eor r8,r21\n"
"eor r15,r20\n"
"eor r14,r19\n"
"eor r13,r18\n"
"eor r12,r17\n"
"eor r11,r7\n"
"std Z+32,r10\n"
"std Z+33,r9\n"
"std Z+34,r8\n"
"std Z+35,r15\n"
"std Z+36,r14\n"
"std Z+37,r13\n"
"std Z+38,r12\n"
"std Z+39,r11\n"
"subi %1,0x0F\n"
"cpi %1,0x3C\n"
"breq 2f\n"
"rjmp 1b\n"
"2:\n"
:: "z"(state.S), "d"((uint8_t)(0xF0 - (first << 4) + first))
: "r17", "r18", "r19", "r20", "r21", "r22", "r23", "r7", "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15", "memory"
);
}
#endif // __AVR__