adds initial version of lwc

This commit is contained in:
Eyck-Alexander Jentzsch 2025-01-16 16:38:16 +01:00
parent bccfc67926
commit 6c48a29db1
2528 changed files with 578574 additions and 0 deletions

36
lwc/Makefile Normal file
View File

@ -0,0 +1,36 @@
# Copyright (C) 2021 SCARV project <info@scarv.org>
#
# Use of this source code is restricted per the MIT license, a copy of which
# can be found at https://opensource.org/licenses/MIT (or should be included
# as LICENSE.txt within the associated archive or repository).
export REPO_HOME = ${PWD}
# =============================================================================
export ALG ?= ascon
export API ?= aead
export ARCH ?= generic
export IMP ?= nist
export ISE ?= xalu
export CONF ?=
# -----------------------------------------------------------------------------
sw-build :
@make --directory="${REPO_HOME}/src" build
sw-run :
@make --directory="${REPO_HOME}/src" run
sw-scan :
@make --directory="${REPO_HOME}/src" scan
sw-clean :
@make --directory="${REPO_HOME}/src" clean
# -----------------------------------------------------------------------------
clean :
@rm --force --recursive ${REPO_HOME}/build/*
# =============================================================================

110
lwc/src/Makefile Normal file
View File

@ -0,0 +1,110 @@
# Copyright (C) 2021 SCARV project <info@scarv.org>
#
# Use of this source code is restricted per the MIT license, a copy of which
# can be found at https://opensource.org/licenses/MIT (or should be included
# as LICENSE.txt within the associated archive or repository).
ifndef REPO_HOME
$(error "execute 'source ./bin/conf.sh' to configure environment")
endif
ifndef REPO_VERSION
$(error "execute 'source ./bin/conf.sh' to configure environment")
endif
export API ?= aead
# =============================================================================
# include build-related content for algorithm
include ./${ALG}/Makefile.in
# include build-related content for architecture
include ./share/arch/${ARCH}/Makefile.in
# parameterise source code using environment variables
ifeq "${API}" "aead"
GCC_FLAGS += -DAPI_AEAD
endif
ifeq "${API}" "hash"
GCC_FLAGS += -DAPI_HASH
endif
ifeq "${IMP}" "nist"
GCC_FLAGS += -DALG="\"${ALG}\"" -DAPI="\"${API}\"" ${CONF} -DARCH="\"${ARCH}\"" -DIMP="\"${IMP}\""
else
GCC_FLAGS += -DALG="\"${ALG}\"" -DAPI="\"${API}\"" ${CONF} -DARCH="\"${ARCH}\"" -DIMP="\"${IMP}\"" -DLWISE
endif
# -----------------------------------------------------------------------------
ifeq "${IMP}" "nist"
export LWISE_INCLUDES += ${REPO_HOME}/build/${ALG} ./share ./share/nist ./share/arch/${ARCH}
else
export LWISE_INCLUDES += ${REPO_HOME}/build/${ALG} ./share ./share/nist ./share/arch/${ARCH} ./${ALG}/arch/${ARCH} ./${ALG}/imp/${IMP} ./${ALG}/imp/share
endif
export LWISE_SOURCES += $(wildcard $(addsuffix /*.c, ${LWISE_INCLUDES}))
export LWISE_SOURCES += $(wildcard $(addsuffix /*.cpp, ${LWISE_INCLUDES}))
export LWISE_SOURCES += $(wildcard $(addsuffix /*.s, ${LWISE_INCLUDES}))
export LWISE_SOURCES += $(wildcard $(addsuffix /*.S, ${LWISE_INCLUDES}))
export LWISE_HEADERS += $(wildcard $(addsuffix /*.h, ${LWISE_INCLUDES}))
export INCLUDES := ${LWISE_INCLUDES} ${NIST_INCLUDES}
export SOURCES := ${LWISE_SOURCES} ${NIST_SOURCES} ${REPO_HOME}/build/${ALG}/kat_${API}.c
export HEADERS := ${LWISE_HEADERS} ${NIST_HEADERS} ${REPO_HOME}/build/${ALG}/kat_${API}.h
export TARGETS += ${REPO_HOME}/build/${ALG}
export TARGETS += ${REPO_HOME}/build/${ALG}/kat_${API}.h
export TARGETS += ${REPO_HOME}/build/${ALG}/kat_${API}.c
export TARGETS += ${REPO_HOME}/build/${ALG}/driver-${API}_${ARCH}_${IMP}.elf
export TARGETS += ${REPO_HOME}/build/${ALG}/driver-${API}_${ARCH}_${IMP}.asm
# -----------------------------------------------------------------------------
${REPO_HOME}/build/${ALG} :
@mkdir --parents ${@}
${REPO_HOME}/build/${ALG}/kat_${API}.h : ${NIST_KAT}
@python3 ./share/kat.py --api="${API}" --header < ${<} > ${@}
${REPO_HOME}/build/${ALG}/kat_${API}.c : ${NIST_KAT}
@python3 ./share/kat.py --api="${API}" --source < ${<} > ${@}
${REPO_HOME}/build/${ALG}/driver-${API}_${ARCH}_${IMP}.elf : ${SOURCES}
@${GCC_PREFIX}-gcc ${GCC_FLAGS} ${GCC_PATHS} $(addprefix -I ,${INCLUDES}) -std='gnu99' -O3 -o ${@} $(filter %.c, ${^}) $(filter %.cpp, ${^}) $(filter %.S, ${^}) ${GCC_LIBS}
${REPO_HOME}/build/${ALG}/driver-${API}_${ARCH}_${IMP}.asm : ${REPO_HOME}/build/${ALG}/driver-${API}_${ARCH}_${IMP}.elf
@${GCC_PREFIX}-objdump --disassemble-all ${<} > ${@}
# -----------------------------------------------------------------------------
.PHONY : run debug scan
dump :
@echo "ALG = ${ALG}"
@echo "API = ${API}"
@echo "ARCH = ${ARCH}"
@echo "IMP = ${IMP}"
@echo "CONF = ${CONF}"
@echo "NIST_HOME = ${NIST_HOME}"
@echo "NIST_IMP = ${NIST_IMP}"
@echo "NIST_KAT = ${NIST_KAT}"
@echo "GCC_PREFIX = ${GCC_PREFIX}"
@echo "GCC_PATHS = ${GCC_PATHS}"
@echo "GCC_FLAGS = ${GCC_FLAGS}"
@echo "GCC_LIBS = ${GCC_LIBS}"
@echo "INCLUDES = ${INCLUDES}"
@echo "SOURCES = ${SOURCES}"
@echo "HEADERS = ${HEADERS}"
@echo "TARGETS = ${TARGETS}"
build : ${TARGETS}
clean :
@rm --force --recursive ${TARGETS}
# =============================================================================

39
lwc/src/ascon/Makefile.in Normal file
View File

@ -0,0 +1,39 @@
# Copyright (C) 2021 SCARV project <info@scarv.org>
#
# Use of this source code is restricted per the MIT license, a copy of which
# can be found at https://opensource.org/licenses/MIT (or should be included
# as LICENSE.txt within the associated archive or repository).
# =============================================================================
ifeq "${API}" "aead"
export NIST_HOME ?= ${REPO_HOME}/src/ascon/nist/Implementations/crypto_aead/ascon128v12
export NIST_IMP ?= ref
export NIST_KAT ?= ${NIST_HOME}/LWC_AEAD_KAT_128_128.txt
export NIST_INCLUDES = ${NIST_HOME}/${NIST_IMP}
export NIST_SOURCES = $(wildcard ${NIST_HOME}/${NIST_IMP}/*.c )
export NIST_SOURCES += $(wildcard ${NIST_HOME}/${NIST_IMP}/*.cpp)
export NIST_SOURCES += $(wildcard ${NIST_HOME}/${NIST_IMP}/*.s )
export NIST_SOURCES += $(wildcard ${NIST_HOME}/${NIST_IMP}/*.S )
export NIST_HEADERS = $(wildcard ${NIST_HOME}/${NIST_IMP}/*.h )
endif
# -----------------------------------------------------------------------------
ifeq "${API}" "hash"
export NIST_HOME ?= ${REPO_HOME}/src/ascon/nist/Implementations/crypto_hash/asconhashv12
export NIST_IMP ?= ref
export NIST_KAT ?= ${NIST_HOME}/LWC_HASH_KAT_256.txt
export NIST_INCLUDES = ${NIST_HOME}/${NIST_IMP}
export NIST_SOURCES = $(wildcard ${NIST_HOME}/${NIST_IMP}/*.c )
export NIST_SOURCES += $(wildcard ${NIST_HOME}/${NIST_IMP}/*.cpp)
export NIST_SOURCES += $(wildcard ${NIST_HOME}/${NIST_IMP}/*.s )
export NIST_SOURCES += $(wildcard ${NIST_HOME}/${NIST_IMP}/*.S )
export NIST_HEADERS = $(wildcard ${NIST_HOME}/${NIST_IMP}/*.h )
endif
# =============================================================================

View File

@ -0,0 +1,18 @@
// Copyright (C) 2021 SCARV project <info@scarv.org>
//
// Use of this source code is restricted per the MIT license, a copy of which
// can be found at https://opensource.org/licenses/MIT (or should be included
// as LICENSE.txt within the associated archive or repository).
// ============================================================================
#if ( ASCON_RV32_TYPE2 )
.macro ascon.sigma.lo rd, rs1, rs2, imm
.insn r CUSTOM_1, 7, \imm+( 0*32), \rd, \rs1, \rs2
.endm
.macro ascon.sigma.hi rd, rs1, rs2, imm
.insn r CUSTOM_1, 7, \imm+( 1*32), \rd, \rs1, \rs2
.endm
#endif
// ============================================================================

View File

@ -0,0 +1,15 @@
// Copyright (C) 2021 SCARV project <info@scarv.org>
//
// Use of this source code is restricted per the MIT license, a copy of which
// can be found at https://opensource.org/licenses/MIT (or should be included
// as LICENSE.txt within the associated archive or repository).
// ============================================================================
#if ( ASCON_RV64_TYPE2 )
.macro ascon.sigma rd, rs1, imm
.insn r CUSTOM_1, 6, \imm+( 2*32), \rd, \rs1, x0
.endm
#endif
// ============================================================================

View File

@ -0,0 +1,35 @@
# Copyright (C) 2021 SCARV project <info@scarv.org>
#
# Use of this source code is restricted per the MIT license, a copy of which
# can be found at https://opensource.org/licenses/MIT (or should be included
# as LICENSE.txt within the associated archive or repository).
import driver, itertools
# =============================================================================
def rv32( args ) :
if ( args.prog ) :
driver.program_fpga( args, 'ascon', 'rv32', 'xalu' )
if ( args.nist ) :
CONF = ['DRIVER_BYPASS_TEST']
driver.run( args, 'ascon', CONF, 'rv32', 'nist', NIST_IMP = 'ref' )
for TYPE in [ 'ASCON_RV32_TYPE1', 'ASCON_RV32_TYPE2' ] :
CONF = [ TYPE ]
# there is only unrolled implementation for Ascon on rv32
CONF += ['ASCON_RV32_UNROLL']
CONF += ['DRIVER_BYPASS_TEST']
driver.run( args, 'ascon', CONF, 'rv32', 'rv32' )
# -----------------------------------------------------------------------------
def rv64( args ) :
pass
# -----------------------------------------------------------------------------
if ( __name__ == '__main__' ) :
driver.main( rv32, rv64 )
# =============================================================================

View File

@ -0,0 +1,272 @@
#include "zbkb.h"
#include "zbkx.h"
#include "ise.h"
// ----------------------------------------------------------------------------
// Register Allocation
// (use caller-saved registers to save push/pop instructions)
//
// a0: the address of state
// a2-a7, t2-t5: state
// t0-t1, t6: temp registers
//
// Comments:
// Excluding resigers storing the state, this implementation needs only three
// additional registers for temp use, which might be useful for other platforms
// with smaller register space (e.g., AVR, ARM Cortex-M).
// ----------------------------------------------------------------------------
// prologue + epilogue
.macro ASCON_PROLOGUE
.endm
.macro ASCON_EPILOGUE
ret
.endm
// load state + store state
.macro ASCON_LDSTATE x0l, x0h, x1l, x1h, x2l, x2h, x3l, x3h, x4l, x4h
lw \x0l, 0(a0)
lw \x0h, 4(a0)
lw \x1l, 8(a0)
lw \x1h, 12(a0)
lw \x2l, 16(a0)
lw \x2h, 20(a0)
lw \x3l, 24(a0)
lw \x3h, 28(a0)
lw \x4l, 32(a0)
lw \x4h, 36(a0)
.endm
.macro ASCON_STSTATE x0l, x0h, x1l, x1h, x2l, x2h, x3l, x3h, x4l, x4h
sw \x0l, 0(a0)
sw \x0h, 4(a0)
sw \x1l, 8(a0)
sw \x1h, 12(a0)
sw \x2l, 16(a0)
sw \x2h, 20(a0)
sw \x3l, 24(a0)
sw \x3h, 28(a0)
sw \x4l, 32(a0)
sw \x4h, 36(a0)
.endm
// layers: PC + PS + PL
// PC: addition of constants
.macro ASCON_PC x2l, rci
xori \x2l, \x2l, \rci
.endm
// PS: SBox x0 x1 x2 x3 x4 -> x3 x1 x2 x0 x4
.macro ASCON_PS x0, x1, x2, x3, x4, t0, t1, t2, t3
xor \t2, \x1, \x2 // t2 = x1 ^ x2
xor \t0, \x0, \x4 // t0 = x0 ^ x4
xor \t1, \x3, \x4 // t1 = x3 ^ x4
orn \x2, \x3, \x4 // x2 = x3 | ~x4
xor \x2, \x2, \t2 // x2 = x1 ^ x2 ^ (x3 | ~x4)
andn \x4, \x1, \t0 // x4 = x1 & ~(x0 ^ x4)
xor \x4, \x4, \t1 // x4 = x3 ^ x4 ^ (x1 & ~(x0 ^ x4))
or \x0, \x0, \t1 // x0 = x0 | (x3 ^ x4)
xor \x3, \x1, \x3 // x3 = x1 ^ x3
xor \x0, \x0, \t2 // x0 = x1 ^ x2 ^ (x0 | (x3 ^ x4))
or \x3, \x3, \t2 // x3 = (x1 ^ x3) | (x1 ^ x2)
xor \t2, \t2, \t0 // t2 = x0 ^ x4 ^ x1 ^ x2
or \t2, \t2, \x1 // t2 = x1 | (x0 ^ x4 ^ x1 ^ x2)
xor \x1, \t0, \x3 // x1 = x0 ^ x4 ^ ((x1 ^ x3) | (x1 ^ x2))
xor \x3, \t1, \t2 // x3 = x3 ^ x4 ^ (x1 | (x0 ^ x4 ^ x1 ^ x2))
.endm
// PL: linear diffusion
#if (ASCON_RV32_TYPE1)
// 64-bit rotate right (immediate)
.macro ASCON_RORI64L dl, sl, sh, imm, t0
srli \t0, \sl, \imm
slli \dl, \sh, 32-\imm
xor \dl, \t0, \dl
.endm
.macro ASCON_RORI64H_0 dh, sl, sh, imm, t0
slli \t0, \sl, 32-\imm
srli \dh, \sh, \imm
xor \dh, \t0, \dh
.endm
.macro ASCON_RORI64H_1 dh, sl, sh, imm, t0, t1
slli \t0, \sl, 32-\imm
xor \sl, \sl, \t1
srli \t1, \sh, \imm
xor \dh, \t0, \t1
.endm
// 64-bit rotate left (immediate)
.macro ASCON_ROLI64L dl, sl, sh, imm, t0
slli \t0, \sl, \imm
srli \dl, \sh, 32-\imm
xor \dl, \t0, \dl
.endm
.macro ASCON_ROLI64H_0 dh, sl, sh, imm, t0
srli \t0, \sl, 32-\imm
slli \dh, \sh, \imm
xor \dh, \t0, \dh
.endm
.macro ASCON_ROLI64H_1 dh, sl, sh, imm, t0, t1
srli \t0, \sl, 32-\imm
xor \sl, \sl, \t1
slli \t1, \sh, \imm
xor \dh, \t0, \t1
.endm
.macro ASCON_PL_STEP_0 xl, xh, imm0, imm1, t0, t1, t2
ASCON_RORI64L \t1, \xl, \xh, \imm0, \t0
ASCON_RORI64L \t2, \xl, \xh, \imm1, \t0
xor \t1, \t1, \t2
ASCON_RORI64H_0 \t2, \xl, \xh, \imm0, \t0
ASCON_RORI64H_1 \t1, \xl, \xh, \imm1, \t0, \t1
xor \t1, \t2, \t1
xor \xh, \xh, \t1
.endm
.macro ASCON_PL_STEP_1 xl, xh, imm0, imm1, t0, t1, t2
ASCON_ROLI64L \t1, \xl, \xh, \imm0, \t0
ASCON_ROLI64L \t2, \xl, \xh, \imm1, \t0
xor \t1, \t1, \t2
ASCON_ROLI64H_0 \t2, \xl, \xh, \imm0, \t0
ASCON_ROLI64H_1 \t1, \xl, \xh, \imm1, \t0, \t1
xor \t1, \t2, \t1
xor \xh, \xh, \t1
.endm
.macro ASCON_PL_STEP_2 xl, xh, imm0, imm1, t0, t1, t2
ASCON_RORI64L \t1, \xl, \xh, \imm0, \t0
ASCON_ROLI64L \t2, \xl, \xh, \imm1, \t0
xor \t1, \t1, \t2
ASCON_RORI64H_0 \t2, \xl, \xh, \imm0, \t0
ASCON_ROLI64H_1 \t1, \xl, \xh, \imm1, \t0, \t1
xor \t1, \t2, \t1
xor \xh, \xh, \t1
.endm
.macro ASCON_PL x0l, x0h, x1l, x1h, x2l, x2h, x3l, x3h, x4l, x4h, t0, t1, t2
ASCON_PL_STEP_0 \x0l, \x0h, 19, 28, \t0, \t1, \t2
ASCON_PL_STEP_1 \x1l, \x1h, 3, 25, \t0, \t1, \t2
ASCON_PL_STEP_0 \x2l, \x2h, 1, 6, \t0, \t1, \t2
ASCON_PL_STEP_0 \x3l, \x3h, 10, 17, \t0, \t1, \t2
ASCON_PL_STEP_2 \x4l, \x4h, 7, 23, \t0, \t1, \t2
.endm
#elif (ASCON_RV32_TYPE2)
// x0l, x0h, x1l, x1h, x2l, x2h, x3l, x3h, x4l, x4h ->
// t0l, t0h, x0l, x0h, x1l, x1h, x2l, x2h, x3l, x3h
.macro ASCON_PL x0l, x0h, x1l, x1h, x2l, x2h, x3l, x3h, x4l, x4h, t0l, t0h, t2
ascon.sigma.lo \t0l, \x0l, \x0h, 0
ascon.sigma.hi \t0h, \x0l, \x0h, 0
ascon.sigma.lo \x0l, \x1l, \x1h, 1
ascon.sigma.hi \x0h, \x1l, \x1h, 1
ascon.sigma.lo \x1l, \x2l, \x2h, 2
ascon.sigma.hi \x1h, \x2l, \x2h, 2
ascon.sigma.lo \x2l, \x3l, \x3h, 3
ascon.sigma.hi \x2h, \x3l, \x3h, 3
ascon.sigma.lo \x3l, \x4l, \x4h, 4
ascon.sigma.hi \x3h, \x4l, \x4h, 4
.endm
#endif
// operations in each round
.macro ASCON_ROUND x0l, x0h, x1l, x1h, x2l, x2h, x3l, x3h, x4l, x4h, rci, t0, t1, t2
ASCON_PC \x2l, \rci
ASCON_PS \x0l, \x1l, \x2l, \x3l, \x4l, \t0, \t1, \t2
ASCON_PS \x0h, \x1h, \x2h, \x3h, \x4h, \t0, \t1, \t2
ASCON_PL \x3l, \x3h, \x1l, \x1h, \x2l, \x2h, \x0l, \x0h, \x4l, \x4h, \t0, \t1, \t2
.endm
// Ascon permutation
.section .text
.global P6
P6:
ASCON_PROLOGUE
ASCON_LDSTATE a2, a3, a4, a5, a6, a7, t2, t3, t4, t5
//
#if (ASCON_RV32_TYPE1)
ASCON_ROUND a2, a3, a4, a5, a6, a7, t2, t3, t4, t5, 0x96, t0, t1, t6
ASCON_ROUND t2, t3, a4, a5, a6, a7, a2, a3, t4, t5, 0x87, t0, t1, t6
ASCON_ROUND a2, a3, a4, a5, a6, a7, t2, t3, t4, t5, 0x78, t0, t1, t6
ASCON_ROUND t2, t3, a4, a5, a6, a7, a2, a3, t4, t5, 0x69, t0, t1, t6
ASCON_ROUND a2, a3, a4, a5, a6, a7, t2, t3, t4, t5, 0x5A, t0, t1, t6
ASCON_ROUND t2, t3, a4, a5, a6, a7, a2, a3, t4, t5, 0x4B, t0, t1, t6
#elif (ASCON_RV32_TYPE2)
ASCON_ROUND a2, a3, a4, a5, a6, a7, t2, t3, t4, t5, 0x96, t0, t1, t6
ASCON_ROUND t0, t1, t2, t3, a4, a5, a6, a7, a2, a3, 0x87, t4, t5, t6
ASCON_ROUND t4, t5, a6, a7, t2, t3, a4, a5, t0, t1, 0x78, a2, a3, t6
ASCON_ROUND a2, a3, a4, a5, a6, a7, t2, t3, t4, t5, 0x69, t0, t1, t6
ASCON_ROUND t0, t1, t2, t3, a4, a5, a6, a7, a2, a3, 0x5A, t4, t5, t6
ASCON_ROUND t4, t5, a6, a7, t2, t3, a4, a5, t0, t1, 0x4B, a2, a3, t6
#endif
//
ASCON_STSTATE a2, a3, a4, a5, a6, a7, t2, t3, t4, t5
ASCON_EPILOGUE
.section .text
.global P12
P12:
ASCON_PROLOGUE
ASCON_LDSTATE a2, a3, a4, a5, a6, a7, t2, t3, t4, t5
//
#if (ASCON_RV32_TYPE1)
ASCON_ROUND a2, a3, a4, a5, a6, a7, t2, t3, t4, t5, 0xF0, t0, t1, t6
ASCON_ROUND t2, t3, a4, a5, a6, a7, a2, a3, t4, t5, 0xE1, t0, t1, t6
ASCON_ROUND a2, a3, a4, a5, a6, a7, t2, t3, t4, t5, 0xD2, t0, t1, t6
ASCON_ROUND t2, t3, a4, a5, a6, a7, a2, a3, t4, t5, 0xC3, t0, t1, t6
ASCON_ROUND a2, a3, a4, a5, a6, a7, t2, t3, t4, t5, 0xB4, t0, t1, t6
ASCON_ROUND t2, t3, a4, a5, a6, a7, a2, a3, t4, t5, 0xA5, t0, t1, t6
ASCON_ROUND a2, a3, a4, a5, a6, a7, t2, t3, t4, t5, 0x96, t0, t1, t6
ASCON_ROUND t2, t3, a4, a5, a6, a7, a2, a3, t4, t5, 0x87, t0, t1, t6
ASCON_ROUND a2, a3, a4, a5, a6, a7, t2, t3, t4, t5, 0x78, t0, t1, t6
ASCON_ROUND t2, t3, a4, a5, a6, a7, a2, a3, t4, t5, 0x69, t0, t1, t6
ASCON_ROUND a2, a3, a4, a5, a6, a7, t2, t3, t4, t5, 0x5A, t0, t1, t6
ASCON_ROUND t2, t3, a4, a5, a6, a7, a2, a3, t4, t5, 0x4B, t0, t1, t6
#elif (ASCON_RV32_TYPE2)
ASCON_ROUND a2, a3, a4, a5, a6, a7, t2, t3, t4, t5, 0xF0, t0, t1, t6
ASCON_ROUND t0, t1, t2, t3, a4, a5, a6, a7, a2, a3, 0xE1, t4, t5, t6
ASCON_ROUND t4, t5, a6, a7, t2, t3, a4, a5, t0, t1, 0xD2, a2, a3, t6
ASCON_ROUND a2, a3, a4, a5, a6, a7, t2, t3, t4, t5, 0xC3, t0, t1, t6
ASCON_ROUND t0, t1, t2, t3, a4, a5, a6, a7, a2, a3, 0xB4, t4, t5, t6
ASCON_ROUND t4, t5, a6, a7, t2, t3, a4, a5, t0, t1, 0xA5, a2, a3, t6
ASCON_ROUND a2, a3, a4, a5, a6, a7, t2, t3, t4, t5, 0x96, t0, t1, t6
ASCON_ROUND t0, t1, t2, t3, a4, a5, a6, a7, a2, a3, 0x87, t4, t5, t6
ASCON_ROUND t4, t5, a6, a7, t2, t3, a4, a5, t0, t1, 0x78, a2, a3, t6
ASCON_ROUND a2, a3, a4, a5, a6, a7, t2, t3, t4, t5, 0x69, t0, t1, t6
ASCON_ROUND t0, t1, t2, t3, a4, a5, a6, a7, a2, a3, 0x5A, t4, t5, t6
ASCON_ROUND t4, t5, a6, a7, t2, t3, a4, a5, t0, t1, 0x4B, a2, a3, t6
#endif
//
ASCON_STSTATE a2, a3, a4, a5, a6, a7, t2, t3, t4, t5
ASCON_EPILOGUE

View File

@ -0,0 +1,158 @@
#include "zbkb.h"
#include "zbkx.h"
#include "ise.h"
// ----------------------------------------------------------------------------
// Register Allocation
// (use caller-saved registers to save push/pop instructions)
//
// a0: the address of state
// a2-a6: state
// t0-t1, t6: temp registers
// ----------------------------------------------------------------------------
// prologue + epilogue
.macro ASCON_PROLOGUE
.endm
.macro ASCON_EPILOGUE
ret
.endm
// load state + store state
.macro ASCON_LDSTATE x0, x1, x2, x3, x4
ld \x0, 0(a0)
ld \x1, 8(a0)
ld \x2, 16(a0)
ld \x3, 24(a0)
ld \x4, 32(a0)
.endm
.macro ASCON_STSTATE x0, x1, x2, x3, x4
sd \x0, 0(a0)
sd \x1, 8(a0)
sd \x2, 16(a0)
sd \x3, 24(a0)
sd \x4, 32(a0)
.endm
// layers: PC + PS + PL
// PC: addition of constants
.macro ASCON_PC x2, rci
xori \x2, \x2, \rci
.endm
// PS: SBox x0 x1 x2 x3 x4 -> x3 x1 x2 x0 x4
.macro ASCON_PS x0, x1, x2, x3, x4, t0, t1, t2
xor \t2, \x1, \x2 // t2 = x1 ^ x2
xor \t0, \x0, \x4 // t0 = x0 ^ x4
xor \t1, \x3, \x4 // t1 = x3 ^ x4
orn \x2, \x3, \x4 // x2 = x3 | ~x4
xor \x2, \x2, \t2 // x2 = x1 ^ x2 ^ (x3 | ~x4)
andn \x4, \x1, \t0 // x4 = x1 & ~(x0 ^ x4)
xor \x4, \x4, \t1 // x4 = x3 ^ x4 ^ (x1 & ~(x0 ^ x4))
or \x0, \x0, \t1 // x0 = x0 | (x3 ^ x4)
xor \x3, \x1, \x3 // x3 = x1 ^ x3
xor \x0, \x0, \t2 // x0 = x1 ^ x2 ^ (x0 | (x3 ^ x4))
or \x3, \x3, \t2 // x3 = (x1 ^ x3) | (x1 ^ x2)
xor \t2, \t2, \t0 // t2 = x0 ^ x4 ^ x1 ^ x2
or \t2, \t2, \x1 // t2 = x1 | (x0 ^ x4 ^ x1 ^ x2)
xor \x1, \t0, \x3 // x1 = x0 ^ x4 ^ ((x1 ^ x3) | (x1 ^ x2))
xor \x3, \t1, \t2 // x3 = x3 ^ x4 ^ (x1 | (x0 ^ x4 ^ x1 ^ x2))
.endm
// PL: linear diffusion
#if (ASCON_RV64_TYPE1)
.macro ASCON_PL_STEP x0, imm0, imm1, t0
rori \t0, \x0, \imm0
xor \t0, \x0, \t0
rori \x0, \x0, \imm1
xor \x0, \t0, \x0
.endm
.macro ASCON_PL x0, x1, x2, x3, x4, t0
ASCON_PL_STEP \x0, 19, 28, \t0
ASCON_PL_STEP \x1, 61, 39, \t0
ASCON_PL_STEP \x2, 1, 6, \t0
ASCON_PL_STEP \x3, 10, 17, \t0
ASCON_PL_STEP \x4, 7, 41, \t0
.endm
#elif (ASCON_RV64_TYPE2)
.macro ASCON_PL x0, x1, x2, x3, x4, t0
ascon.sigma \x0, \x0, 0
ascon.sigma \x1, \x1, 1
ascon.sigma \x2, \x2, 2
ascon.sigma \x3, \x3, 3
ascon.sigma \x4, \x4, 4
.endm
#endif
// operations in each round
.macro ASCON_ROUND x0, x1, x2, x3, x4, rci, t0, t1, t2
ASCON_PC \x2, \rci
ASCON_PS \x0, \x1, \x2, \x3, \x4, \t0, \t1, \t2
ASCON_PL \x3, \x1, \x2, \x0, \x4, \t0
.endm
// Ascon permutation
.section .text
.global P6
P6:
ASCON_PROLOGUE
ASCON_LDSTATE a2, a3, a4, a5, a6
//
ASCON_ROUND a2, a3, a4, a5, a6, 0x96, t0, t1, t6
ASCON_ROUND a5, a3, a4, a2, a6, 0x87, t0, t1, t6
ASCON_ROUND a2, a3, a4, a5, a6, 0x78, t0, t1, t6
ASCON_ROUND a5, a3, a4, a2, a6, 0x69, t0, t1, t6
ASCON_ROUND a2, a3, a4, a5, a6, 0x5A, t0, t1, t6
ASCON_ROUND a5, a3, a4, a2, a6, 0x4B, t0, t1, t6
//
ASCON_STSTATE a2, a3, a4, a5, a6
ASCON_EPILOGUE
.section .text
.global P12
P12:
ASCON_PROLOGUE
ASCON_LDSTATE a2, a3, a4, a5, a6
//
ASCON_ROUND a2, a3, a4, a5, a6, 0xF0, t0, t1, t6
ASCON_ROUND a5, a3, a4, a2, a6, 0xE1, t0, t1, t6
ASCON_ROUND a2, a3, a4, a5, a6, 0xD2, t0, t1, t6
ASCON_ROUND a5, a3, a4, a2, a6, 0xC3, t0, t1, t6
ASCON_ROUND a2, a3, a4, a5, a6, 0xB4, t0, t1, t6
ASCON_ROUND a5, a3, a4, a2, a6, 0xA5, t0, t1, t6
ASCON_ROUND a2, a3, a4, a5, a6, 0x96, t0, t1, t6
ASCON_ROUND a5, a3, a4, a2, a6, 0x87, t0, t1, t6
ASCON_ROUND a2, a3, a4, a5, a6, 0x78, t0, t1, t6
ASCON_ROUND a5, a3, a4, a2, a6, 0x69, t0, t1, t6
ASCON_ROUND a2, a3, a4, a5, a6, 0x5A, t0, t1, t6
ASCON_ROUND a5, a3, a4, a2, a6, 0x4B, t0, t1, t6
//
ASCON_STSTATE a2, a3, a4, a5, a6
ASCON_EPILOGUE

1
lwc/src/ascon/nist.url Normal file
View File

@ -0,0 +1 @@
https://csrc.nist.gov/CSRC/media/Projects/lightweight-cryptography/documents/finalist-round/updated-submissions/ascon.zip

3
lwc/src/ascon/nist.zip Normal file
View File

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:07a2bc8432612d260cef0945e6a16ff9aa94c9279a2e83b76ae984fdbe8b1a5d
size 2032754

View File

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:49403e24b9cd05a234d27c5a7f37e3f28de52c8f8db07ac744515be225bd7aa6
size 485542

View File

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:68eb5de5bbe2c1d19a212827f9daaec22b49777e93f4fed6300764bbbd5aa480
size 153824

View File

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:ffbefd2edd8d997de9157c2bf6ea6bfaa53e03e8ce26f1ee136108ae924b127e
size 164033

View File

@ -0,0 +1,237 @@
#include "api.h"
#include "ascon.h"
#include "crypto_aead.h"
#include "permutations.h"
#include "printstate.h"
#define AVX512_SHUFFLE_U64BIG \
_mm512_set_epi8(-1, -1, -1, -1, -1, -1, -1, -1, /* word 7 */ \
-1, -1, -1, -1, -1, -1, -1, -1, /* word 6 */ \
-1, -1, -1, -1, -1, -1, -1, -1, /* word 5 */ \
-1, -1, -1, -1, -1, -1, -1, -1, /* word 4 */ \
-1, -1, -1, -1, -1, -1, -1, -1, /* word 3 */ \
-1, -1, -1, -1, -1, -1, -1, -1, /* word 2 */ \
8, 9, 10, 11, 12, 13, 14, 15, /* word 1 */ \
0, 1, 2, 3, 4, 5, 6, 7) /* word 0 */
#if !ASCON_INLINE_MODE
#undef forceinline
#define forceinline
#endif
forceinline void ascon_loadkey(word_t* K0, word_t* K1, word_t* K2,
const uint8_t* k) {
KINIT(K0, K1, K2);
if (CRYPTO_KEYBYTES == 16) {
*K1 = XOR(*K1, LOAD(k, 8));
*K2 = XOR(*K2, LOAD(k + 8, 8));
}
if (CRYPTO_KEYBYTES == 20) {
*K0 = XOR(*K0, KEYROT(WORD_T(0), LOADBYTES(k, 4)));
*K1 = XOR(*K1, LOADBYTES(k + 4, 8));
*K2 = XOR(*K2, LOADBYTES(k + 12, 8));
}
}
forceinline void ascon_aeadinit(state_t* s, const uint8_t* npub,
const uint8_t* k) {
/* load nonce */
word_t N0 = LOAD(npub, 8);
word_t N1 = LOAD(npub + 8, 8);
/* load key */
word_t K0, K1, K2;
ascon_loadkey(&K0, &K1, &K2, k);
/* initialize */
PINIT(s);
if (CRYPTO_KEYBYTES == 16 && ASCON_AEAD_RATE == 8)
s->x0 = XOR(s->x0, ASCON_128_IV);
if (CRYPTO_KEYBYTES == 16 && ASCON_AEAD_RATE == 16)
s->x0 = XOR(s->x0, ASCON_128A_IV);
if (CRYPTO_KEYBYTES == 20) s->x0 = XOR(s->x0, ASCON_80PQ_IV);
if (CRYPTO_KEYBYTES == 20) s->x0 = XOR(s->x0, K0);
s->x1 = XOR(s->x1, K1);
s->x2 = XOR(s->x2, K2);
s->x3 = XOR(s->x3, N0);
s->x4 = XOR(s->x4, N1);
P(s, 12);
if (CRYPTO_KEYBYTES == 20) s->x2 = XOR(s->x2, K0);
s->x3 = XOR(s->x3, K1);
s->x4 = XOR(s->x4, K2);
printstate("initialization", s);
}
forceinline void ascon_adata(state_t* s, const uint8_t* ad, uint64_t adlen) {
const __m512i u64big = AVX512_SHUFFLE_U64BIG;
const int mask = (ASCON_AEAD_RATE == 8) ? 0xff : 0xffff;
const int nr = (ASCON_AEAD_RATE == 8) ? 6 : 8;
state_t r = *s, t;
if (adlen) {
/* full associated data blocks */
while (adlen >= ASCON_AEAD_RATE) {
t.z = _mm512_maskz_loadu_epi8(mask, ad);
t.z = _mm512_maskz_shuffle_epi8(mask, t.z, u64big);
r.z = _mm512_xor_epi64(r.z, t.z);
P(&r, nr);
ad += ASCON_AEAD_RATE;
adlen -= ASCON_AEAD_RATE;
}
*s = r;
/* final associated data block */
word_t* px = &s->x0;
if (ASCON_AEAD_RATE == 16 && adlen >= 8) {
s->x0 = XOR(s->x0, LOAD(ad, 8));
px = &s->x1;
ad += 8;
adlen -= 8;
}
*px = XOR(*px, PAD(adlen));
if (adlen) *px = XOR(*px, LOAD(ad, adlen));
P(s, nr);
}
/* domain separation */
s->x4 = XOR(s->x4, WORD_T(1));
printstate("process associated data", s);
}
forceinline void ascon_encrypt(state_t* s, uint8_t* c, const uint8_t* m,
uint64_t mlen) {
const __m512i u64big = AVX512_SHUFFLE_U64BIG;
const int mask = (ASCON_AEAD_RATE == 8) ? 0xff : 0xffff;
const int nr = (ASCON_AEAD_RATE == 8) ? 6 : 8;
state_t r = *s, t;
/* full plaintext blocks */
while (mlen >= ASCON_AEAD_RATE) {
t.z = _mm512_maskz_loadu_epi8(mask, m);
t.z = _mm512_maskz_shuffle_epi8(mask, t.z, u64big);
r.z = _mm512_xor_epi64(r.z, t.z);
t.z = _mm512_maskz_shuffle_epi8(mask, r.z, u64big);
_mm512_mask_storeu_epi8(c, mask, t.z);
P(&r, nr);
m += ASCON_AEAD_RATE;
c += ASCON_AEAD_RATE;
mlen -= ASCON_AEAD_RATE;
}
*s = r;
/* final plaintext block */
word_t* px = &s->x0;
if (ASCON_AEAD_RATE == 16 && mlen >= 8) {
s->x0 = XOR(s->x0, LOAD(m, 8));
STORE(c, s->x0, 8);
px = &s->x1;
m += 8;
c += 8;
mlen -= 8;
}
*px = XOR(*px, PAD(mlen));
if (mlen) {
*px = XOR(*px, LOAD(m, mlen));
STORE(c, *px, mlen);
}
printstate("process plaintext", s);
}
forceinline void ascon_decrypt(state_t* s, uint8_t* m, const uint8_t* c,
uint64_t clen) {
const __m512i u64big = AVX512_SHUFFLE_U64BIG;
const int mask = (ASCON_AEAD_RATE == 8) ? 0xff : 0xffff;
const int nr = (ASCON_AEAD_RATE == 8) ? 6 : 8;
state_t r = *s, t, u;
/* full ciphertext blocks */
while (clen >= ASCON_AEAD_RATE) {
t.z = _mm512_maskz_loadu_epi8(mask, c);
t.z = _mm512_maskz_shuffle_epi8(mask, t.z, u64big);
r.z = _mm512_xor_epi64(r.z, t.z);
u.z = _mm512_maskz_shuffle_epi8(mask, r.z, u64big);
r.z = _mm512_mask_blend_epi8(mask, r.z, t.z);
_mm512_mask_storeu_epi8(m, mask, u.z);
P(&r, nr);
m += ASCON_AEAD_RATE;
c += ASCON_AEAD_RATE;
clen -= ASCON_AEAD_RATE;
}
*s = r;
/* final ciphertext block */
word_t* px = &s->x0;
if (ASCON_AEAD_RATE == 16 && clen >= 8) {
word_t cx = LOAD(c, 8);
s->x0 = XOR(s->x0, cx);
STORE(m, s->x0, 8);
s->x0 = cx;
px = &s->x1;
m += 8;
c += 8;
clen -= 8;
}
*px = XOR(*px, PAD(clen));
if (clen) {
word_t cx = LOAD(c, clen);
*px = XOR(*px, cx);
STORE(m, *px, clen);
*px = CLEAR(*px, clen);
*px = XOR(*px, cx);
}
printstate("process ciphertext", s);
}
forceinline void ascon_final(state_t* s, const uint8_t* k) {
/* load key */
word_t K0, K1, K2;
ascon_loadkey(&K0, &K1, &K2, k);
/* finalize */
if (CRYPTO_KEYBYTES == 16 && ASCON_AEAD_RATE == 8) {
s->x1 = XOR(s->x1, K1);
s->x2 = XOR(s->x2, K2);
}
if (CRYPTO_KEYBYTES == 16 && ASCON_AEAD_RATE == 16) {
s->x2 = XOR(s->x2, K1);
s->x3 = XOR(s->x3, K2);
}
if (CRYPTO_KEYBYTES == 20) {
s->x1 = XOR(s->x1, KEYROT(K0, K1));
s->x2 = XOR(s->x2, KEYROT(K1, K2));
s->x3 = XOR(s->x3, KEYROT(K2, WORD_T(0)));
}
P(s, 12);
s->x3 = XOR(s->x3, K1);
s->x4 = XOR(s->x4, K2);
printstate("finalization", 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 */
ascon_aeadinit(&s, npub, k);
ascon_adata(&s, ad, adlen);
ascon_encrypt(&s, c, m, mlen);
ascon_final(&s, k);
/* set tag */
STOREBYTES(c + mlen, s.x3, 8);
STOREBYTES(c + mlen + 8, s.x4, 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 */
ascon_aeadinit(&s, npub, k);
ascon_adata(&s, ad, adlen);
ascon_decrypt(&s, m, c, clen);
ascon_final(&s, k);
/* verify tag (should be constant time, check compiler output) */
s.x3 = XOR(s.x3, LOADBYTES(c + clen, 8));
s.x4 = XOR(s.x4, LOADBYTES(c + clen + 8, 8));
return NOTZERO(s.x3, s.x4);
}

View File

@ -0,0 +1,7 @@
#define CRYPTO_VERSION "1.2.5"
#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

View File

@ -0,0 +1,22 @@
#ifndef ASCON_H_
#define ASCON_H_
#include <immintrin.h>
#include <stdint.h>
#include "word.h"
typedef union {
__m512i z;
struct {
word_t x0, x1, x2, x3, x4, x5, x6, x7;
};
} state_t;
void ascon_aeadinit(state_t* s, const uint8_t* npub, const uint8_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 uint8_t* k);
#endif /* ASCON_H */

View File

@ -0,0 +1,19 @@
#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 1
#endif
/* unroll permutation loops */
#ifndef ASCON_UNROLL_LOOPS
#define ASCON_UNROLL_LOOPS 1
#endif
#endif /* CONFIG_H_ */

View File

@ -0,0 +1,39 @@
#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_ */

View File

@ -0,0 +1,19 @@
#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_ */

View File

@ -0,0 +1 @@
Branches reviewed 2020-11-13 by Martin Schläffer.

View File

@ -0,0 +1 @@
Addresses reviewed 2020-11-13 by Martin Schläffer.

View File

@ -0,0 +1,2 @@
Christoph Dobraunig
Martin Schläffer

View File

@ -0,0 +1,15 @@
#include "permutations.h"
#if !ASCON_INLINE_PERM && ASCON_UNROLL_LOOPS
void P12(state_t* s) { P12ROUNDS(s); }
void P8(state_t* s) { P8ROUNDS(s); }
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

View File

@ -0,0 +1,138 @@
#ifndef PERMUTATIONS_H_
#define PERMUTATIONS_H_
#include <stdint.h>
#include "api.h"
#include "ascon.h"
#include "config.h"
#include "printstate.h"
#include "round.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_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_HASH_BYTES 32
#define ASCON_128_IV WORD_T(0x80400c0600000000ull)
#define ASCON_128A_IV WORD_T(0x80800c0800000000ull)
#define ASCON_80PQ_IV WORD_T(0xa0400c0600000000ull)
#define ASCON_HASH_IV WORD_T(0x00400c0000000100ull)
#define ASCON_HASHA_IV WORD_T(0x00400c0400000100ull)
#define ASCON_XOF_IV WORD_T(0x00400c0000000000ull)
#define ASCON_XOFA_IV WORD_T(0x00400c0400000000ull)
#define ASCON_HASH_IV0 WORD_T(0xee9398aadb67f03dull)
#define ASCON_HASH_IV1 WORD_T(0x8bb21831c60f1002ull)
#define ASCON_HASH_IV2 WORD_T(0xb48a92db98d5da62ull)
#define ASCON_HASH_IV3 WORD_T(0x43189921b8f8e3e8ull)
#define ASCON_HASH_IV4 WORD_T(0x348fa5c9d525e140ull)
#define ASCON_HASHA_IV0 WORD_T(0x01470194fc6528a6ull)
#define ASCON_HASHA_IV1 WORD_T(0x738ec38ac0adffa7ull)
#define ASCON_HASHA_IV2 WORD_T(0x2ec8e3296c76384cull)
#define ASCON_HASHA_IV3 WORD_T(0xd6f6a54d7f52377dull)
#define ASCON_HASHA_IV4 WORD_T(0xa13c42a223be8d87ull)
#define ASCON_XOF_IV0 WORD_T(0xb57e273b814cd416ull)
#define ASCON_XOF_IV1 WORD_T(0x2b51042562ae2420ull)
#define ASCON_XOF_IV2 WORD_T(0x66a3a7768ddf2218ull)
#define ASCON_XOF_IV3 WORD_T(0x5aad0a7a8153650cull)
#define ASCON_XOF_IV4 WORD_T(0x4f3e0e32539493b6ull)
#define ASCON_XOFA_IV0 WORD_T(0x44906568b77b9832ull)
#define ASCON_XOFA_IV1 WORD_T(0xcd8d6cae53455532ull)
#define ASCON_XOFA_IV2 WORD_T(0xf7b5212756422129ull)
#define ASCON_XOFA_IV3 WORD_T(0x246885e1de0d225bull)
#define ASCON_XOFA_IV4 WORD_T(0xa8cb5ce33449973full)
#define START(n) ((3 + (n)) << 4 | (12 - (n)))
#define RC(c) WORD_T(c)
forceinline void P12ROUNDS(state_t* s) {
ROUND(s, RC(0xf0));
ROUND(s, RC(0xe1));
ROUND(s, RC(0xd2));
ROUND(s, RC(0xc3));
ROUND(s, RC(0xb4));
ROUND(s, RC(0xa5));
ROUND(s, RC(0x96));
ROUND(s, RC(0x87));
ROUND(s, RC(0x78));
ROUND(s, RC(0x69));
ROUND(s, RC(0x5a));
ROUND(s, RC(0x4b));
}
forceinline void P8ROUNDS(state_t* s) {
ROUND(s, RC(0xb4));
ROUND(s, RC(0xa5));
ROUND(s, RC(0x96));
ROUND(s, RC(0x87));
ROUND(s, RC(0x78));
ROUND(s, RC(0x69));
ROUND(s, RC(0x5a));
ROUND(s, RC(0x4b));
}
forceinline void P6ROUNDS(state_t* s) {
ROUND(s, RC(0x96));
ROUND(s, RC(0x87));
ROUND(s, RC(0x78));
ROUND(s, RC(0x69));
ROUND(s, RC(0x5a));
ROUND(s, RC(0x4b));
}
forceinline void PROUNDS(state_t* s, int nr) {
for (int i = START(nr); i > 0x4a; i -= 0x0f) ROUND(s, RC(i));
}
#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_ */

View File

@ -0,0 +1,21 @@
#ifdef ASCON_PRINTSTATE
#include "printstate.h"
#include <inttypes.h>
#include <stdio.h>
void printword(const char* text, const word_t x) {
printf("%s=%016" PRIx64 "\n", text, WORDTOU64(x));
}
void printstate(const char* text, const state_t* s) {
printf("%s:\n", text);
printword(" x0", s->x0);
printword(" x1", s->x1);
printword(" x2", s->x2);
printword(" x3", s->x3);
printword(" x4", s->x4);
}
#endif

View File

@ -0,0 +1,24 @@
#ifndef PRINTSTATE_H_
#define PRINTSTATE_H_
#ifdef ASCON_PRINTSTATE
#include "ascon.h"
#include "word.h"
void printword(const char* text, const word_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_ */

View File

@ -0,0 +1,51 @@
#ifndef ROUND_H_
#define ROUND_H_
#include "ascon.h"
#include "printstate.h"
forceinline void KINIT(word_t* K0, word_t* K1, word_t* K2) {
*K0 = WORD_T(0);
*K1 = WORD_T(0);
*K2 = WORD_T(0);
}
forceinline void PINIT(state_t* s) {
s->x0 = WORD_T(0);
s->x1 = WORD_T(0);
s->x2 = WORD_T(0);
s->x3 = WORD_T(0);
s->x4 = WORD_T(0);
}
forceinline void ROUND(state_t* s, word_t C) {
uint64_t x = 0;
__mmask8 mxor1 = 0x15;
__mmask8 mxor2 = 0x0b;
__m512i pxor1 = _mm512_set_epi64(x, x, x, 3, x, 1, x, 4);
__m512i pxor2 = _mm512_set_epi64(x, x, x, x, 2, x, 0, 4);
__m512i c = _mm512_set_epi64(x, x, x, 0, 0, C, 0, 0);
__m512i n = _mm512_set_epi64(x, x, x, 0, 0, ~0ull, 0, 0);
__m512i pchi1 = _mm512_set_epi64(x, x, x, 0, 4, 3, 2, 1);
__m512i pchi2 = _mm512_set_epi64(x, x, x, 1, 0, 4, 3, 2);
__m512i rot1 = _mm512_set_epi64(x, x, x, 7, 10, 1, 61, 19);
__m512i rot2 = _mm512_set_epi64(x, x, x, 41, 17, 6, 39, 28);
__m512i t0, t1, t2;
/* round constant + s-box layer */
t0 = _mm512_maskz_permutexvar_epi64(mxor1, pxor1, s->z);
t0 = _mm512_ternarylogic_epi64(s->z, t0, c, 0x96);
/* keccak s-box start */
t1 = _mm512_permutexvar_epi64(pchi1, t0);
t2 = _mm512_permutexvar_epi64(pchi2, t0);
t0 = _mm512_ternarylogic_epi64(t0, t1, t2, 0xd2);
/* keccak s-box end */
t1 = _mm512_maskz_permutexvar_epi64(mxor2, pxor2, t0);
t0 = _mm512_ternarylogic_epi64(t0, t1, n, 0x96);
/* linear layer */
t1 = _mm512_rorv_epi64(t0, rot1);
t2 = _mm512_rorv_epi64(t0, rot2);
s->z = _mm512_ternarylogic_epi64(t0, t1, t2, 0x96);
printstate(" round output", s);
}
#endif /* ROUND_H_ */

View File

@ -0,0 +1,69 @@
#ifndef WORD_H_
#define WORD_H_
#include <stdint.h>
#include "endian.h"
#include "forceinline.h"
typedef uint64_t word_t;
#define WORD_T
#define UINT64_T
#define U64TOWORD
#define WORDTOU64
forceinline word_t ROR(word_t x, int n) { return x >> n | x << (64 - n); }
forceinline word_t NOT(word_t a) { return ~a; }
forceinline word_t XOR(word_t a, word_t b) { return a ^ b; }
forceinline word_t AND(word_t a, word_t b) { return a & b; }
forceinline word_t KEYROT(word_t lo2hi, word_t hi2lo) {
return lo2hi << 32 | hi2lo >> 32;
}
forceinline int NOTZERO(word_t a, word_t b) {
uint64_t result = a | b;
result |= result >> 32;
result |= result >> 16;
result |= result >> 8;
return ((((int)(result & 0xff) - 1) >> 8) & 1) - 1;
}
forceinline word_t PAD(int i) { return 0x80ull << (56 - 8 * i); }
forceinline word_t CLEAR(word_t w, int n) {
/* undefined for n == 0 */
uint64_t mask = 0x00ffffffffffffffull >> (n * 8 - 8);
return w & mask;
}
forceinline uint64_t MASK(int n) {
/* undefined for n == 0 */
return ~0ull >> (64 - 8 * n);
}
forceinline word_t LOAD(const uint8_t* bytes, int n) {
uint64_t x = *(uint64_t*)bytes & MASK(n);
return U64BIG(x);
}
forceinline void STORE(uint8_t* bytes, word_t w, int n) {
*(uint64_t*)bytes &= ~MASK(n);
*(uint64_t*)bytes |= U64BIG(w);
}
forceinline word_t LOADBYTES(const uint8_t* bytes, int n) {
uint64_t x = 0;
for (int i = 0; i < n; ++i) ((uint8_t*)&x)[7 - i] = bytes[i];
return x;
}
forceinline void STOREBYTES(uint8_t* bytes, word_t w, int n) {
for (int i = 0; i < n; ++i) bytes[i] = ((uint8_t*)&w)[7 - i];
}
#endif /* WORD_H_ */

View File

@ -0,0 +1,219 @@
#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
forceinline void ascon_loadkey(word_t* K0, word_t* K1, word_t* K2,
const uint8_t* k) {
KINIT(K0, K1, K2);
if (CRYPTO_KEYBYTES == 16) {
*K1 = XOR(*K1, LOAD(k, 8));
*K2 = XOR(*K2, LOAD(k + 8, 8));
}
if (CRYPTO_KEYBYTES == 20) {
*K0 = XOR(*K0, KEYROT(WORD_T(0), LOADBYTES(k, 4)));
*K1 = XOR(*K1, LOADBYTES(k + 4, 8));
*K2 = XOR(*K2, LOADBYTES(k + 12, 8));
}
}
forceinline void ascon_aeadinit(state_t* s, const uint8_t* npub,
const uint8_t* k) {
/* load nonce */
word_t N0 = LOAD(npub, 8);
word_t N1 = LOAD(npub + 8, 8);
/* load key */
word_t K0, K1, K2;
ascon_loadkey(&K0, &K1, &K2, k);
/* initialize */
PINIT(s);
if (CRYPTO_KEYBYTES == 16 && ASCON_AEAD_RATE == 8)
s->x0 = XOR(s->x0, ASCON_128_IV);
if (CRYPTO_KEYBYTES == 16 && ASCON_AEAD_RATE == 16)
s->x0 = XOR(s->x0, ASCON_128A_IV);
if (CRYPTO_KEYBYTES == 20) s->x0 = XOR(s->x0, ASCON_80PQ_IV);
if (CRYPTO_KEYBYTES == 20) s->x0 = XOR(s->x0, K0);
s->x1 = XOR(s->x1, K1);
s->x2 = XOR(s->x2, K2);
s->x3 = XOR(s->x3, N0);
s->x4 = XOR(s->x4, N1);
P(s, 12);
if (CRYPTO_KEYBYTES == 20) s->x2 = XOR(s->x2, K0);
s->x3 = XOR(s->x3, K1);
s->x4 = XOR(s->x4, K2);
printstate("initialization", 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->x0 = XOR(s->x0, LOAD(ad, 8));
if (ASCON_AEAD_RATE == 16) s->x1 = XOR(s->x1, LOAD(ad + 8, 8));
P(s, nr);
ad += ASCON_AEAD_RATE;
adlen -= ASCON_AEAD_RATE;
}
/* final associated data block */
word_t* px = &s->x0;
if (ASCON_AEAD_RATE == 16 && adlen >= 8) {
s->x0 = XOR(s->x0, LOAD(ad, 8));
px = &s->x1;
ad += 8;
adlen -= 8;
}
*px = XOR(*px, PAD(adlen));
if (adlen) *px = XOR(*px, LOAD(ad, adlen));
P(s, nr);
}
/* domain separation */
s->x4 = XOR(s->x4, WORD_T(1));
printstate("process associated data", 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->x0 = XOR(s->x0, LOAD(m, 8));
STORE(c, s->x0, 8);
if (ASCON_AEAD_RATE == 16) {
s->x1 = XOR(s->x1, LOAD(m + 8, 8));
STORE(c + 8, s->x1, 8);
}
P(s, nr);
m += ASCON_AEAD_RATE;
c += ASCON_AEAD_RATE;
mlen -= ASCON_AEAD_RATE;
}
/* final plaintext block */
word_t* px = &s->x0;
if (ASCON_AEAD_RATE == 16 && mlen >= 8) {
s->x0 = XOR(s->x0, LOAD(m, 8));
STORE(c, s->x0, 8);
px = &s->x1;
m += 8;
c += 8;
mlen -= 8;
}
*px = XOR(*px, PAD(mlen));
if (mlen) {
*px = XOR(*px, LOAD(m, mlen));
STORE(c, *px, mlen);
}
printstate("process 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) {
word_t cx = LOAD(c, 8);
s->x0 = XOR(s->x0, cx);
STORE(m, s->x0, 8);
s->x0 = cx;
if (ASCON_AEAD_RATE == 16) {
cx = LOAD(c + 8, 8);
s->x1 = XOR(s->x1, cx);
STORE(m + 8, s->x1, 8);
s->x1 = cx;
}
P(s, nr);
m += ASCON_AEAD_RATE;
c += ASCON_AEAD_RATE;
clen -= ASCON_AEAD_RATE;
}
/* final ciphertext block */
word_t* px = &s->x0;
if (ASCON_AEAD_RATE == 16 && clen >= 8) {
word_t cx = LOAD(c, 8);
s->x0 = XOR(s->x0, cx);
STORE(m, s->x0, 8);
s->x0 = cx;
px = &s->x1;
m += 8;
c += 8;
clen -= 8;
}
*px = XOR(*px, PAD(clen));
if (clen) {
word_t cx = LOAD(c, clen);
*px = XOR(*px, cx);
STORE(m, *px, clen);
*px = CLEAR(*px, clen);
*px = XOR(*px, cx);
}
printstate("process ciphertext", s);
}
forceinline void ascon_final(state_t* s, const uint8_t* k) {
/* load key */
word_t K0, K1, K2;
ascon_loadkey(&K0, &K1, &K2, k);
/* finalize */
if (CRYPTO_KEYBYTES == 16 && ASCON_AEAD_RATE == 8) {
s->x1 = XOR(s->x1, K1);
s->x2 = XOR(s->x2, K2);
}
if (CRYPTO_KEYBYTES == 16 && ASCON_AEAD_RATE == 16) {
s->x2 = XOR(s->x2, K1);
s->x3 = XOR(s->x3, K2);
}
if (CRYPTO_KEYBYTES == 20) {
s->x1 = XOR(s->x1, KEYROT(K0, K1));
s->x2 = XOR(s->x2, KEYROT(K1, K2));
s->x3 = XOR(s->x3, KEYROT(K2, WORD_T(0)));
}
P(s, 12);
s->x3 = XOR(s->x3, K1);
s->x4 = XOR(s->x4, K2);
printstate("finalization", 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 */
ascon_aeadinit(&s, npub, k);
ascon_adata(&s, ad, adlen);
ascon_encrypt(&s, c, m, mlen);
ascon_final(&s, k);
/* set tag */
STOREBYTES(c + mlen, s.x3, 8);
STOREBYTES(c + mlen + 8, s.x4, 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 */
ascon_aeadinit(&s, npub, k);
ascon_adata(&s, ad, adlen);
ascon_decrypt(&s, m, c, clen);
ascon_final(&s, k);
/* verify tag (should be constant time, check compiler output) */
s.x3 = XOR(s.x3, LOADBYTES(c + clen, 8));
s.x4 = XOR(s.x4, LOADBYTES(c + clen + 8, 8));
return NOTZERO(s.x3, s.x4);
}

View File

@ -0,0 +1,7 @@
#define CRYPTO_VERSION "1.2.5"
#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

View File

@ -0,0 +1,18 @@
#ifndef ASCON_H_
#define ASCON_H_
#include <stdint.h>
#include "word.h"
typedef struct {
word_t x0, x1, x2, x3, x4;
} state_t;
void ascon_aeadinit(state_t* s, const uint8_t* npub, const uint8_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 uint8_t* k);
#endif /* ASCON_H */

View File

@ -0,0 +1,19 @@
#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 1
#endif
#endif /* CONFIG_H_ */

View File

@ -0,0 +1,39 @@
#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_ */

View File

@ -0,0 +1,19 @@
#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_ */

View File

@ -0,0 +1 @@
Branches reviewed 2020-11-13 by Martin Schläffer.

View File

@ -0,0 +1 @@
Addresses reviewed 2020-11-13 by Martin Schläffer.

View File

@ -0,0 +1,2 @@
Christoph Dobraunig
Martin Schläffer

View File

@ -0,0 +1,49 @@
#ifndef INTERLEAVE_H_
#define INTERLEAVE_H_
#include <stdint.h>
#include "forceinline.h"
forceinline uint32_t deinterleave_uint32(uint32_t x) {
uint32_t t;
t = (x ^ (x >> 1)) & 0x22222222, x ^= t ^ (t << 1);
t = (x ^ (x >> 2)) & 0x0C0C0C0C, x ^= t ^ (t << 2);
t = (x ^ (x >> 4)) & 0x00F000F0, x ^= t ^ (t << 4);
t = (x ^ (x >> 8)) & 0x0000FF00, x ^= t ^ (t << 8);
return x;
}
forceinline uint32_t interleave_uint32(uint32_t x) {
uint32_t t;
t = (x ^ (x >> 8)) & 0x0000FF00, x ^= t ^ (t << 8);
t = (x ^ (x >> 4)) & 0x00F000F0, x ^= t ^ (t << 4);
t = (x ^ (x >> 2)) & 0x0C0C0C0C, x ^= t ^ (t << 2);
t = (x ^ (x >> 1)) & 0x22222222, x ^= t ^ (t << 1);
return x;
}
/* credit to Henry S. Warren, Hacker's Delight, Addison-Wesley, 2002 */
forceinline uint64_t deinterleave32(uint64_t in) {
uint32_t hi = in >> 32;
uint32_t lo = in;
uint32_t r0, r1;
lo = deinterleave_uint32(lo);
hi = deinterleave_uint32(hi);
r0 = (lo & 0x0000FFFF) | (hi << 16);
r1 = (lo >> 16) | (hi & 0xFFFF0000);
return (uint64_t)r1 << 32 | r0;
}
/* credit to Henry S. Warren, Hacker's Delight, Addison-Wesley, 2002 */
forceinline uint64_t interleave32(uint64_t in) {
uint32_t r0 = in;
uint32_t r1 = in >> 32;
uint32_t lo = (r0 & 0x0000FFFF) | (r1 << 16);
uint32_t hi = (r0 >> 16) | (r1 & 0xFFFF0000);
lo = interleave_uint32(lo);
hi = interleave_uint32(hi);
return (uint64_t)hi << 32 | lo;
}
#endif /* INTERLEAVE_H_ */

View File

@ -0,0 +1,23 @@
#include "permutations.h"
#if !ASCON_UNROLL_LOOPS
const uint8_t constants[][2] = {{0xc, 0xc}, {0x9, 0xc}, {0xc, 0x9}, {0x9, 0x9},
{0x6, 0xc}, {0x3, 0xc}, {0x6, 0x9}, {0x3, 0x9},
{0xc, 0x6}, {0x9, 0x6}, {0xc, 0x3}, {0x9, 0x3}};
#endif
#if !ASCON_INLINE_PERM && ASCON_UNROLL_LOOPS
void P12(state_t* s) { P12ROUNDS(s); }
void P8(state_t* s) { P8ROUNDS(s); }
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

View File

@ -0,0 +1,139 @@
#ifndef PERMUTATIONS_H_
#define PERMUTATIONS_H_
#include <stdint.h>
#include "api.h"
#include "ascon.h"
#include "config.h"
#include "printstate.h"
#include "round.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_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_HASH_BYTES 32
#define ASCON_128_IV WORD_T(0x8021000008220000ull)
#define ASCON_128A_IV WORD_T(0x8822000000200000ull)
#define ASCON_80PQ_IV WORD_T(0xc021000008220000ull)
#define ASCON_HASH_IV WORD_T(0x0020000008020010ull)
#define ASCON_XOF_IV WORD_T(0x0020000008020000ull)
#define ASCON_HASH_IV0 WORD_T(0xf9afb5c6a540dbc7ull)
#define ASCON_HASH_IV1 WORD_T(0xbd2493011445a340ull)
#define ASCON_HASH_IV2 WORD_T(0xcb9ba8b5604d4fc8ull)
#define ASCON_HASH_IV3 WORD_T(0x12a4eede94514c98ull)
#define ASCON_HASH_IV4 WORD_T(0x4bca84c06339f398ull)
#define ASCON_HASHA_IV0 WORD_T(0x0108e46d1b16eb02ull)
#define ASCON_HASHA_IV1 WORD_T(0x5b9b8efdd29083f3ull)
#define ASCON_HASHA_IV2 WORD_T(0x7ad665622891ae4aull)
#define ASCON_HASHA_IV3 WORD_T(0x9dc27156ee3bfc7full)
#define ASCON_HASHA_IV4 WORD_T(0xc61d5fa916801633ull)
#define ASCON_XOF_IV0 WORD_T(0xc75782817e351ae6ull)
#define ASCON_XOF_IV1 WORD_T(0x70045f441d238220ull)
#define ASCON_XOF_IV2 WORD_T(0x5dd5ab52a13e3f04ull)
#define ASCON_XOF_IV3 WORD_T(0x3e378142c30c1db2ull)
#define ASCON_XOF_IV4 WORD_T(0x3735189db624d656ull)
#define ASCON_XOFA_IV0 WORD_T(0x0846d7a5a4b87d44ull)
#define ASCON_XOFA_IV1 WORD_T(0xaa6f1005b3a2dbf4ull)
#define ASCON_XOFA_IV2 WORD_T(0xdc451146f713e811ull)
#define ASCON_XOFA_IV3 WORD_T(0x468cb2532839e30dull)
#define ASCON_XOFA_IV4 WORD_T(0xeb2d429709e96977ull)
#define START(n) (12 - n)
#define RC(e, o) WORD_T((uint64_t)o << 32 | e)
forceinline void P12ROUNDS(state_t* s) {
ROUND(s, RC(0xc, 0xc));
ROUND(s, RC(0x9, 0xc));
ROUND(s, RC(0xc, 0x9));
ROUND(s, RC(0x9, 0x9));
ROUND(s, RC(0x6, 0xc));
ROUND(s, RC(0x3, 0xc));
ROUND(s, RC(0x6, 0x9));
ROUND(s, RC(0x3, 0x9));
ROUND(s, RC(0xc, 0x6));
ROUND(s, RC(0x9, 0x6));
ROUND(s, RC(0xc, 0x3));
ROUND(s, RC(0x9, 0x3));
}
forceinline void P8ROUNDS(state_t* s) {
ROUND(s, RC(0x6, 0xc));
ROUND(s, RC(0x3, 0xc));
ROUND(s, RC(0x6, 0x9));
ROUND(s, RC(0x3, 0x9));
ROUND(s, RC(0xc, 0x6));
ROUND(s, RC(0x9, 0x6));
ROUND(s, RC(0xc, 0x3));
ROUND(s, RC(0x9, 0x3));
}
forceinline void P6ROUNDS(state_t* s) {
ROUND(s, RC(0x6, 0x9));
ROUND(s, RC(0x3, 0x9));
ROUND(s, RC(0xc, 0x6));
ROUND(s, RC(0x9, 0x6));
ROUND(s, RC(0xc, 0x3));
ROUND(s, RC(0x9, 0x3));
}
extern const uint8_t constants[][2];
forceinline void PROUNDS(state_t* s, int nr) {
for (int i = START(nr); i < 12; i++)
ROUND(s, RC(constants[i][0], constants[i][1]));
}
#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_ */

View File

@ -0,0 +1,21 @@
#ifdef ASCON_PRINTSTATE
#include "printstate.h"
#include <inttypes.h>
#include <stdio.h>
void printword(const char* text, const word_t x) {
printf("%s=%016" PRIx64 "\n", text, WORDTOU64(x));
}
void printstate(const char* text, const state_t* s) {
printf("%s:\n", text);
printword(" x0", s->x0);
printword(" x1", s->x1);
printword(" x2", s->x2);
printword(" x3", s->x3);
printword(" x4", s->x4);
}
#endif

View File

@ -0,0 +1,24 @@
#ifndef PRINTSTATE_H_
#define PRINTSTATE_H_
#ifdef ASCON_PRINTSTATE
#include "ascon.h"
#include "word.h"
void printword(const char* text, const word_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_ */

View File

@ -0,0 +1,52 @@
#ifndef ROUND_H_
#define ROUND_H_
#include "ascon.h"
#include "printstate.h"
forceinline void KINIT(word_t* K0, word_t* K1, word_t* K2) {
*K0 = WORD_T(0);
*K1 = WORD_T(0);
*K2 = WORD_T(0);
}
forceinline void PINIT(state_t* s) {
s->x0 = WORD_T(0);
s->x1 = WORD_T(0);
s->x2 = WORD_T(0);
s->x3 = WORD_T(0);
s->x4 = WORD_T(0);
}
forceinline void ROUND(state_t* s, word_t C) {
state_t t;
/* round constant */
s->x2 = XOR(s->x2, C);
/* s-box layer */
s->x0 = XOR(s->x0, s->x4);
s->x4 = XOR(s->x4, s->x3);
s->x2 = XOR(s->x2, s->x1);
t.x0 = XOR(s->x0, AND(NOT(s->x1), s->x2));
t.x2 = XOR(s->x2, AND(NOT(s->x3), s->x4));
t.x4 = XOR(s->x4, AND(NOT(s->x0), s->x1));
t.x1 = XOR(s->x1, AND(NOT(s->x2), s->x3));
t.x3 = XOR(s->x3, AND(NOT(s->x4), s->x0));
t.x1 = XOR(t.x1, t.x0);
t.x3 = XOR(t.x3, t.x2);
t.x0 = XOR(t.x0, t.x4);
/* linear layer */
s->x2 = XOR(t.x2, ROR(t.x2, 6 - 1));
s->x3 = XOR(t.x3, ROR(t.x3, 17 - 10));
s->x4 = XOR(t.x4, ROR(t.x4, 41 - 7));
s->x0 = XOR(t.x0, ROR(t.x0, 28 - 19));
s->x1 = XOR(t.x1, ROR(t.x1, 61 - 39));
s->x2 = XOR(t.x2, ROR(s->x2, 1));
s->x3 = XOR(t.x3, ROR(s->x3, 10));
s->x4 = XOR(t.x4, ROR(s->x4, 7));
s->x0 = XOR(t.x0, ROR(s->x0, 19));
s->x1 = XOR(t.x1, ROR(s->x1, 39));
s->x2 = NOT(s->x2);
printstate(" round output", s);
}
#endif /* ROUND_H_ */

View File

@ -0,0 +1,105 @@
#ifndef WORD_H_
#define WORD_H_
#include <stdint.h>
#include "endian.h"
#include "forceinline.h"
#include "interleave.h"
typedef struct {
uint32_t e;
uint32_t o;
} word_t;
forceinline uint32_t ROR32(uint32_t x, int n) {
return (n == 0) ? x : x >> n | x << (32 - n);
}
forceinline word_t ROR(word_t x, int n) {
word_t r;
r.e = (n % 2) ? ROR32(x.o, (n - 1) / 2) : ROR32(x.e, n / 2);
r.o = (n % 2) ? ROR32(x.e, (n + 1) / 2) : ROR32(x.o, n / 2);
return r;
}
forceinline word_t WORD_T(uint64_t x) { return (word_t){.o = x >> 32, .e = x}; }
forceinline uint64_t UINT64_T(word_t x) { return (uint64_t)x.o << 32 | x.e; }
forceinline word_t U64TOWORD(uint64_t x) { return WORD_T(deinterleave32(x)); }
forceinline uint64_t WORDTOU64(word_t w) { return interleave32(UINT64_T(w)); }
forceinline word_t NOT(word_t a) {
a.e = ~a.e;
a.o = ~a.o;
return a;
}
forceinline word_t XOR(word_t a, word_t b) {
a.e ^= b.e;
a.o ^= b.o;
return a;
}
forceinline word_t AND(word_t a, word_t b) {
a.e &= b.e;
a.o &= b.o;
return a;
}
forceinline word_t KEYROT(word_t lo2hi, word_t hi2lo) {
word_t r;
r.e = lo2hi.e << 16 | hi2lo.e >> 16;
r.o = lo2hi.o << 16 | hi2lo.o >> 16;
return r;
}
forceinline int NOTZERO(word_t a, word_t b) {
uint32_t result = a.e | a.o | b.e | b.o;
result |= result >> 16;
result |= result >> 8;
return ((((int)(result & 0xff) - 1) >> 8) & 1) - 1;
}
forceinline word_t PAD(int i) {
return WORD_T((uint64_t)(0x8ul << (28 - 4 * i)) << 32);
}
forceinline word_t CLEAR(word_t w, int n) {
/* undefined for n == 0 */
uint32_t mask = 0x0fffffff >> (n * 4 - 4);
w.e &= mask;
w.o &= mask;
return w;
}
forceinline uint64_t MASK(int n) {
/* undefined for n == 0 */
return ~0ull >> (64 - 8 * n);
}
forceinline word_t LOAD(const uint8_t* bytes, int n) {
uint64_t x = *(uint64_t*)bytes & MASK(n);
return U64TOWORD(U64BIG(x));
}
forceinline void STORE(uint8_t* bytes, word_t w, int n) {
uint64_t x = WORDTOU64(w);
*(uint64_t*)bytes &= ~MASK(n);
*(uint64_t*)bytes |= U64BIG(x);
}
forceinline word_t LOADBYTES(const uint8_t* bytes, int n) {
uint64_t x = 0;
for (int i = 0; i < n; ++i) ((uint8_t*)&x)[7 - i] = bytes[i];
return U64TOWORD(x);
}
forceinline void STOREBYTES(uint8_t* bytes, word_t w, int n) {
uint64_t x = WORDTOU64(w);
for (int i = 0; i < n; ++i) bytes[i] = ((uint8_t*)&x)[7 - i];
}
#endif /* WORD_H_ */

View File

@ -0,0 +1,219 @@
#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
forceinline void ascon_loadkey(word_t* K0, word_t* K1, word_t* K2,
const uint8_t* k) {
KINIT(K0, K1, K2);
if (CRYPTO_KEYBYTES == 16) {
*K1 = XOR(*K1, LOAD(k, 8));
*K2 = XOR(*K2, LOAD(k + 8, 8));
}
if (CRYPTO_KEYBYTES == 20) {
*K0 = XOR(*K0, KEYROT(WORD_T(0), LOADBYTES(k, 4)));
*K1 = XOR(*K1, LOADBYTES(k + 4, 8));
*K2 = XOR(*K2, LOADBYTES(k + 12, 8));
}
}
forceinline void ascon_aeadinit(state_t* s, const uint8_t* npub,
const uint8_t* k) {
/* load nonce */
word_t N0 = LOAD(npub, 8);
word_t N1 = LOAD(npub + 8, 8);
/* load key */
word_t K0, K1, K2;
ascon_loadkey(&K0, &K1, &K2, k);
/* initialize */
PINIT(s);
if (CRYPTO_KEYBYTES == 16 && ASCON_AEAD_RATE == 8)
s->x0 = XOR(s->x0, ASCON_128_IV);
if (CRYPTO_KEYBYTES == 16 && ASCON_AEAD_RATE == 16)
s->x0 = XOR(s->x0, ASCON_128A_IV);
if (CRYPTO_KEYBYTES == 20) s->x0 = XOR(s->x0, ASCON_80PQ_IV);
if (CRYPTO_KEYBYTES == 20) s->x0 = XOR(s->x0, K0);
s->x1 = XOR(s->x1, K1);
s->x2 = XOR(s->x2, K2);
s->x3 = XOR(s->x3, N0);
s->x4 = XOR(s->x4, N1);
P(s, 12);
if (CRYPTO_KEYBYTES == 20) s->x2 = XOR(s->x2, K0);
s->x3 = XOR(s->x3, K1);
s->x4 = XOR(s->x4, K2);
printstate("initialization", 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->x0 = XOR(s->x0, LOAD(ad, 8));
if (ASCON_AEAD_RATE == 16) s->x1 = XOR(s->x1, LOAD(ad + 8, 8));
P(s, nr);
ad += ASCON_AEAD_RATE;
adlen -= ASCON_AEAD_RATE;
}
/* final associated data block */
word_t* px = &s->x0;
if (ASCON_AEAD_RATE == 16 && adlen >= 8) {
s->x0 = XOR(s->x0, LOAD(ad, 8));
px = &s->x1;
ad += 8;
adlen -= 8;
}
*px = XOR(*px, PAD(adlen));
if (adlen) *px = XOR(*px, LOAD(ad, adlen));
P(s, nr);
}
/* domain separation */
s->x4 = XOR(s->x4, WORD_T(1));
printstate("process associated data", 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->x0 = XOR(s->x0, LOAD(m, 8));
STORE(c, s->x0, 8);
if (ASCON_AEAD_RATE == 16) {
s->x1 = XOR(s->x1, LOAD(m + 8, 8));
STORE(c + 8, s->x1, 8);
}
P(s, nr);
m += ASCON_AEAD_RATE;
c += ASCON_AEAD_RATE;
mlen -= ASCON_AEAD_RATE;
}
/* final plaintext block */
word_t* px = &s->x0;
if (ASCON_AEAD_RATE == 16 && mlen >= 8) {
s->x0 = XOR(s->x0, LOAD(m, 8));
STORE(c, s->x0, 8);
px = &s->x1;
m += 8;
c += 8;
mlen -= 8;
}
*px = XOR(*px, PAD(mlen));
if (mlen) {
*px = XOR(*px, LOAD(m, mlen));
STORE(c, *px, mlen);
}
printstate("process 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) {
word_t cx = LOAD(c, 8);
s->x0 = XOR(s->x0, cx);
STORE(m, s->x0, 8);
s->x0 = cx;
if (ASCON_AEAD_RATE == 16) {
cx = LOAD(c + 8, 8);
s->x1 = XOR(s->x1, cx);
STORE(m + 8, s->x1, 8);
s->x1 = cx;
}
P(s, nr);
m += ASCON_AEAD_RATE;
c += ASCON_AEAD_RATE;
clen -= ASCON_AEAD_RATE;
}
/* final ciphertext block */
word_t* px = &s->x0;
if (ASCON_AEAD_RATE == 16 && clen >= 8) {
word_t cx = LOAD(c, 8);
s->x0 = XOR(s->x0, cx);
STORE(m, s->x0, 8);
s->x0 = cx;
px = &s->x1;
m += 8;
c += 8;
clen -= 8;
}
*px = XOR(*px, PAD(clen));
if (clen) {
word_t cx = LOAD(c, clen);
*px = XOR(*px, cx);
STORE(m, *px, clen);
*px = CLEAR(*px, clen);
*px = XOR(*px, cx);
}
printstate("process ciphertext", s);
}
forceinline void ascon_final(state_t* s, const uint8_t* k) {
/* load key */
word_t K0, K1, K2;
ascon_loadkey(&K0, &K1, &K2, k);
/* finalize */
if (CRYPTO_KEYBYTES == 16 && ASCON_AEAD_RATE == 8) {
s->x1 = XOR(s->x1, K1);
s->x2 = XOR(s->x2, K2);
}
if (CRYPTO_KEYBYTES == 16 && ASCON_AEAD_RATE == 16) {
s->x2 = XOR(s->x2, K1);
s->x3 = XOR(s->x3, K2);
}
if (CRYPTO_KEYBYTES == 20) {
s->x1 = XOR(s->x1, KEYROT(K0, K1));
s->x2 = XOR(s->x2, KEYROT(K1, K2));
s->x3 = XOR(s->x3, KEYROT(K2, WORD_T(0)));
}
P(s, 12);
s->x3 = XOR(s->x3, K1);
s->x4 = XOR(s->x4, K2);
printstate("finalization", 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 */
ascon_aeadinit(&s, npub, k);
ascon_adata(&s, ad, adlen);
ascon_encrypt(&s, c, m, mlen);
ascon_final(&s, k);
/* set tag */
STOREBYTES(c + mlen, s.x3, 8);
STOREBYTES(c + mlen + 8, s.x4, 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 */
ascon_aeadinit(&s, npub, k);
ascon_adata(&s, ad, adlen);
ascon_decrypt(&s, m, c, clen);
ascon_final(&s, k);
/* verify tag (should be constant time, check compiler output) */
s.x3 = XOR(s.x3, LOADBYTES(c + clen, 8));
s.x4 = XOR(s.x4, LOADBYTES(c + clen + 8, 8));
return NOTZERO(s.x3, s.x4);
}

View File

@ -0,0 +1,7 @@
#define CRYPTO_VERSION "1.2.5"
#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

View File

@ -0,0 +1,3 @@
aarch64
armeabi
arm

View File

@ -0,0 +1,18 @@
#ifndef ASCON_H_
#define ASCON_H_
#include <stdint.h>
#include "word.h"
typedef struct {
word_t x0, x1, x2, x3, x4;
} state_t;
void ascon_aeadinit(state_t* s, const uint8_t* npub, const uint8_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 uint8_t* k);
#endif /* ASCON_H */

View File

@ -0,0 +1,19 @@
#ifndef CONFIG_H_
#define CONFIG_H_
/* inline the ascon mode */
#ifndef ASCON_INLINE_MODE
#define ASCON_INLINE_MODE 0
#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 1
#endif
#endif /* CONFIG_H_ */

View File

@ -0,0 +1,39 @@
#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_ */

View File

@ -0,0 +1,19 @@
#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_ */

View File

@ -0,0 +1 @@
Branches reviewed 2020-11-13 by Martin Schläffer.

View File

@ -0,0 +1 @@
Addresses reviewed 2020-11-13 by Martin Schläffer.

View File

@ -0,0 +1,2 @@
Christoph Dobraunig
Martin Schläffer

View File

@ -0,0 +1,49 @@
#ifndef INTERLEAVE_H_
#define INTERLEAVE_H_
#include <stdint.h>
#include "forceinline.h"
forceinline uint32_t deinterleave_uint32(uint32_t x) {
uint32_t t;
t = (x ^ (x >> 1)) & 0x22222222, x ^= t ^ (t << 1);
t = (x ^ (x >> 2)) & 0x0C0C0C0C, x ^= t ^ (t << 2);
t = (x ^ (x >> 4)) & 0x00F000F0, x ^= t ^ (t << 4);
t = (x ^ (x >> 8)) & 0x0000FF00, x ^= t ^ (t << 8);
return x;
}
forceinline uint32_t interleave_uint32(uint32_t x) {
uint32_t t;
t = (x ^ (x >> 8)) & 0x0000FF00, x ^= t ^ (t << 8);
t = (x ^ (x >> 4)) & 0x00F000F0, x ^= t ^ (t << 4);
t = (x ^ (x >> 2)) & 0x0C0C0C0C, x ^= t ^ (t << 2);
t = (x ^ (x >> 1)) & 0x22222222, x ^= t ^ (t << 1);
return x;
}
/* credit to Henry S. Warren, Hacker's Delight, Addison-Wesley, 2002 */
forceinline uint64_t deinterleave32(uint64_t in) {
uint32_t hi = in >> 32;
uint32_t lo = in;
uint32_t r0, r1;
lo = deinterleave_uint32(lo);
hi = deinterleave_uint32(hi);
r0 = (lo & 0x0000FFFF) | (hi << 16);
r1 = (lo >> 16) | (hi & 0xFFFF0000);
return (uint64_t)r1 << 32 | r0;
}
/* credit to Henry S. Warren, Hacker's Delight, Addison-Wesley, 2002 */
forceinline uint64_t interleave32(uint64_t in) {
uint32_t r0 = in;
uint32_t r1 = in >> 32;
uint32_t lo = (r0 & 0x0000FFFF) | (r1 << 16);
uint32_t hi = (r0 >> 16) | (r1 & 0xFFFF0000);
lo = interleave_uint32(lo);
hi = interleave_uint32(hi);
return (uint64_t)hi << 32 | lo;
}
#endif /* INTERLEAVE_H_ */

View File

@ -0,0 +1,23 @@
#include "permutations.h"
#if !ASCON_UNROLL_LOOPS
const uint8_t constants[][2] = {{0xc, 0xc}, {0x9, 0xc}, {0xc, 0x9}, {0x9, 0x9},
{0x6, 0xc}, {0x3, 0xc}, {0x6, 0x9}, {0x3, 0x9},
{0xc, 0x6}, {0x9, 0x6}, {0xc, 0x3}, {0x9, 0x3}};
#endif
#if !ASCON_INLINE_PERM && ASCON_UNROLL_LOOPS
void P12(state_t* s) { P12ROUNDS(s); }
void P8(state_t* s) { P8ROUNDS(s); }
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

View File

@ -0,0 +1,139 @@
#ifndef PERMUTATIONS_H_
#define PERMUTATIONS_H_
#include <stdint.h>
#include "api.h"
#include "ascon.h"
#include "config.h"
#include "printstate.h"
#include "round.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_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_HASH_BYTES 32
#define ASCON_128_IV WORD_T(0x8021000008220000ull)
#define ASCON_128A_IV WORD_T(0x8822000000200000ull)
#define ASCON_80PQ_IV WORD_T(0xc021000008220000ull)
#define ASCON_HASH_IV WORD_T(0x0020000008020010ull)
#define ASCON_XOF_IV WORD_T(0x0020000008020000ull)
#define ASCON_HASH_IV0 WORD_T(0xf9afb5c6a540dbc7ull)
#define ASCON_HASH_IV1 WORD_T(0xbd2493011445a340ull)
#define ASCON_HASH_IV2 WORD_T(0xcb9ba8b5604d4fc8ull)
#define ASCON_HASH_IV3 WORD_T(0x12a4eede94514c98ull)
#define ASCON_HASH_IV4 WORD_T(0x4bca84c06339f398ull)
#define ASCON_HASHA_IV0 WORD_T(0x0108e46d1b16eb02ull)
#define ASCON_HASHA_IV1 WORD_T(0x5b9b8efdd29083f3ull)
#define ASCON_HASHA_IV2 WORD_T(0x7ad665622891ae4aull)
#define ASCON_HASHA_IV3 WORD_T(0x9dc27156ee3bfc7full)
#define ASCON_HASHA_IV4 WORD_T(0xc61d5fa916801633ull)
#define ASCON_XOF_IV0 WORD_T(0xc75782817e351ae6ull)
#define ASCON_XOF_IV1 WORD_T(0x70045f441d238220ull)
#define ASCON_XOF_IV2 WORD_T(0x5dd5ab52a13e3f04ull)
#define ASCON_XOF_IV3 WORD_T(0x3e378142c30c1db2ull)
#define ASCON_XOF_IV4 WORD_T(0x3735189db624d656ull)
#define ASCON_XOFA_IV0 WORD_T(0x0846d7a5a4b87d44ull)
#define ASCON_XOFA_IV1 WORD_T(0xaa6f1005b3a2dbf4ull)
#define ASCON_XOFA_IV2 WORD_T(0xdc451146f713e811ull)
#define ASCON_XOFA_IV3 WORD_T(0x468cb2532839e30dull)
#define ASCON_XOFA_IV4 WORD_T(0xeb2d429709e96977ull)
#define START(n) (12 - n)
#define RC(e, o) WORD_T((uint64_t)o << 32 | e)
forceinline void P12ROUNDS(state_t* s) {
ROUND(s, RC(0xc, 0xc));
ROUND(s, RC(0x9, 0xc));
ROUND(s, RC(0xc, 0x9));
ROUND(s, RC(0x9, 0x9));
ROUND(s, RC(0x6, 0xc));
ROUND(s, RC(0x3, 0xc));
ROUND(s, RC(0x6, 0x9));
ROUND(s, RC(0x3, 0x9));
ROUND(s, RC(0xc, 0x6));
ROUND(s, RC(0x9, 0x6));
ROUND(s, RC(0xc, 0x3));
ROUND(s, RC(0x9, 0x3));
}
forceinline void P8ROUNDS(state_t* s) {
ROUND(s, RC(0x6, 0xc));
ROUND(s, RC(0x3, 0xc));
ROUND(s, RC(0x6, 0x9));
ROUND(s, RC(0x3, 0x9));
ROUND(s, RC(0xc, 0x6));
ROUND(s, RC(0x9, 0x6));
ROUND(s, RC(0xc, 0x3));
ROUND(s, RC(0x9, 0x3));
}
forceinline void P6ROUNDS(state_t* s) {
ROUND(s, RC(0x6, 0x9));
ROUND(s, RC(0x3, 0x9));
ROUND(s, RC(0xc, 0x6));
ROUND(s, RC(0x9, 0x6));
ROUND(s, RC(0xc, 0x3));
ROUND(s, RC(0x9, 0x3));
}
extern const uint8_t constants[][2];
forceinline void PROUNDS(state_t* s, int nr) {
for (int i = START(nr); i < 12; i++)
ROUND(s, RC(constants[i][0], constants[i][1]));
}
#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_ */

View File

@ -0,0 +1,21 @@
#ifdef ASCON_PRINTSTATE
#include "printstate.h"
#include <inttypes.h>
#include <stdio.h>
void printword(const char* text, const word_t x) {
printf("%s=%016" PRIx64 "\n", text, WORDTOU64(x));
}
void printstate(const char* text, const state_t* s) {
printf("%s:\n", text);
printword(" x0", s->x0);
printword(" x1", s->x1);
printword(" x2", s->x2);
printword(" x3", s->x3);
printword(" x4", s->x4);
}
#endif

View File

@ -0,0 +1,24 @@
#ifndef PRINTSTATE_H_
#define PRINTSTATE_H_
#ifdef ASCON_PRINTSTATE
#include "ascon.h"
#include "word.h"
void printword(const char* text, const word_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_ */

View File

@ -0,0 +1,102 @@
#ifndef ROUND_H_
#define ROUND_H_
#include "ascon.h"
#include "printstate.h"
forceinline void KINIT(word_t* K0, word_t* K1, word_t* K2) {
*K0 = WORD_T(0);
*K1 = WORD_T(0);
*K2 = WORD_T(0);
}
forceinline void PINIT(state_t* s) {
s->x0 = WORD_T(0);
s->x1 = WORD_T(0);
s->x2 = WORD_T(0);
s->x3 = WORD_T(0);
s->x4 = WORD_T(0);
}
forceinline void ROUND(state_t* s, word_t C) {
uint32_t tmp0, tmp1, tmp2, tmp3;
/* clang-format off */
__asm__ __volatile__( \
"eor %[x2_e], %[x2_e], %[C_e]\n\t" \
"eor %[x2_o], %[x2_o], %[C_o]\n\t" \
"eor %[x0_e], %[x0_e], %[x4_e]\n\t" \
"eor %[x0_o], %[x0_o], %[x4_o]\n\t" \
"eor %[x4_e], %[x4_e], %[x3_e]\n\t" \
"eor %[x4_o], %[x4_o], %[x3_o]\n\t" \
"eor %[x2_e], %[x2_e], %[x1_e]\n\t" \
"eor %[x2_o], %[x2_o], %[x1_o]\n\t" \
"bic %[tmp0], %[x0_e], %[x4_e]\n\t" \
"bic %[tmp1], %[x4_e], %[x3_e]\n\t" \
"bic %[tmp2], %[x2_e], %[x1_e]\n\t" \
"bic %[tmp3], %[x1_e], %[x0_e]\n\t" \
"eor %[x2_e], %[x2_e], %[tmp1]\n\t" \
"eor %[x0_e], %[x0_e], %[tmp2]\n\t" \
"eor %[x4_e], %[x4_e], %[tmp3]\n\t" \
"bic %[tmp3], %[x3_e], %[x2_e]\n\t" \
"eor %[x3_e], %[x3_e], %[tmp0]\n\t" \
"bic %[tmp2], %[x0_o], %[x4_o]\n\t" \
"bic %[tmp0], %[x2_o], %[x1_o]\n\t" \
"bic %[tmp1], %[x4_o], %[x3_o]\n\t" \
"eor %[x1_e], %[x1_e], %[tmp3]\n\t" \
"eor %[x0_o], %[x0_o], %[tmp0]\n\t" \
"eor %[x2_o], %[x2_o], %[tmp1]\n\t" \
"bic %[tmp3], %[x1_o], %[x0_o]\n\t" \
"bic %[tmp0], %[x3_o], %[x2_o]\n\t" \
"eor %[x3_o], %[x3_o], %[tmp2]\n\t" \
"eor %[x3_o], %[x3_o], %[x2_o]\n\t" \
"eor %[x4_o], %[x4_o], %[tmp3]\n\t" \
"eor %[x1_o], %[x1_o], %[tmp0]\n\t" \
"eor %[x3_e], %[x3_e], %[x2_e]\n\t" \
"eor %[x1_e], %[x1_e], %[x0_e]\n\t" \
"eor %[x1_o], %[x1_o], %[x0_o]\n\t" \
"eor %[x0_e], %[x0_e], %[x4_e]\n\t" \
"eor %[x0_o], %[x0_o], %[x4_o]\n\t" \
"mvn %[x2_e], %[x2_e]\n\t" \
"mvn %[x2_o], %[x2_o]\n\t" \
"eor %[tmp0], %[x0_e], %[x0_o], ror #4\n\t" \
"eor %[tmp1], %[x0_o], %[x0_e], ror #5\n\t" \
"eor %[tmp2], %[x1_e], %[x1_e], ror #11\n\t" \
"eor %[tmp3], %[x1_o], %[x1_o], ror #11\n\t" \
"eor %[x0_e], %[x0_e], %[tmp1], ror #9\n\t" \
"eor %[x0_o], %[x0_o], %[tmp0], ror #10\n\t" \
"eor %[x1_e], %[x1_e], %[tmp3], ror #19\n\t" \
"eor %[x1_o], %[x1_o], %[tmp2], ror #20\n\t" \
"eor %[tmp0], %[x2_e], %[x2_o], ror #2\n\t" \
"eor %[tmp1], %[x2_o], %[x2_e], ror #3\n\t" \
"eor %[tmp2], %[x3_e], %[x3_o], ror #3\n\t" \
"eor %[tmp3], %[x3_o], %[x3_e], ror #4\n\t" \
"eor %[x2_e], %[x2_e], %[tmp1]\n\t" \
"eor %[x2_o], %[x2_o], %[tmp0], ror #1\n\t" \
"eor %[x3_e], %[x3_e], %[tmp2], ror #5\n\t" \
"eor %[x3_o], %[x3_o], %[tmp3], ror #5\n\t" \
"eor %[tmp0], %[x4_e], %[x4_e], ror #17\n\t" \
"eor %[tmp1], %[x4_o], %[x4_o], ror #17\n\t" \
"eor %[x4_e], %[x4_e], %[tmp1], ror #3\n\t" \
"eor %[x4_o], %[x4_o], %[tmp0], ror #4\n\t" \
: [ x0_e ] "+r"(s->x0.e), \
[ x1_e ] "+r"(s->x1.e), \
[ x2_e ] "+r"(s->x2.e), \
[ x3_e ] "+r"(s->x3.e), \
[ x4_e ] "+r"(s->x4.e), \
[ x0_o ] "+r"(s->x0.o), \
[ x1_o ] "+r"(s->x1.o), \
[ x2_o ] "+r"(s->x2.o), \
[ x3_o ] "+r"(s->x3.o), \
[ x4_o ] "+r"(s->x4.o), \
[ tmp0 ] "=r"(tmp0), \
[ tmp1 ] "=r"(tmp1), \
[ tmp2 ] "=r"(tmp2), \
[ tmp3 ] "=r"(tmp3) \
: [ C_e ] "ri"(C.e), \
[ C_o ] "ri"(C.o) \
: );
/* clang-format on */
printstate(" round output", s);
}
#endif /* ROUND_H_ */

View File

@ -0,0 +1,105 @@
#ifndef WORD_H_
#define WORD_H_
#include <stdint.h>
#include "endian.h"
#include "forceinline.h"
#include "interleave.h"
typedef struct {
uint32_t e;
uint32_t o;
} word_t;
forceinline uint32_t ROR32(uint32_t x, int n) {
return (n == 0) ? x : x >> n | x << (32 - n);
}
forceinline word_t ROR(word_t x, int n) {
word_t r;
r.e = (n % 2) ? ROR32(x.o, (n - 1) / 2) : ROR32(x.e, n / 2);
r.o = (n % 2) ? ROR32(x.e, (n + 1) / 2) : ROR32(x.o, n / 2);
return r;
}
forceinline word_t WORD_T(uint64_t x) { return (word_t){.o = x >> 32, .e = x}; }
forceinline uint64_t UINT64_T(word_t x) { return (uint64_t)x.o << 32 | x.e; }
forceinline word_t U64TOWORD(uint64_t x) { return WORD_T(deinterleave32(x)); }
forceinline uint64_t WORDTOU64(word_t w) { return interleave32(UINT64_T(w)); }
forceinline word_t NOT(word_t a) {
a.e = ~a.e;
a.o = ~a.o;
return a;
}
forceinline word_t XOR(word_t a, word_t b) {
a.e ^= b.e;
a.o ^= b.o;
return a;
}
forceinline word_t AND(word_t a, word_t b) {
a.e &= b.e;
a.o &= b.o;
return a;
}
forceinline word_t KEYROT(word_t lo2hi, word_t hi2lo) {
word_t r;
r.e = lo2hi.e << 16 | hi2lo.e >> 16;
r.o = lo2hi.o << 16 | hi2lo.o >> 16;
return r;
}
forceinline int NOTZERO(word_t a, word_t b) {
uint32_t result = a.e | a.o | b.e | b.o;
result |= result >> 16;
result |= result >> 8;
return ((((int)(result & 0xff) - 1) >> 8) & 1) - 1;
}
forceinline word_t PAD(int i) {
return WORD_T((uint64_t)(0x8ul << (28 - 4 * i)) << 32);
}
forceinline word_t CLEAR(word_t w, int n) {
/* undefined for n == 0 */
uint32_t mask = 0x0fffffff >> (n * 4 - 4);
w.e &= mask;
w.o &= mask;
return w;
}
forceinline uint64_t MASK(int n) {
/* undefined for n == 0 */
return ~0ull >> (64 - 8 * n);
}
forceinline word_t LOAD(const uint8_t* bytes, int n) {
uint64_t x = *(uint64_t*)bytes & MASK(n);
return U64TOWORD(U64BIG(x));
}
forceinline void STORE(uint8_t* bytes, word_t w, int n) {
uint64_t x = WORDTOU64(w);
*(uint64_t*)bytes &= ~MASK(n);
*(uint64_t*)bytes |= U64BIG(x);
}
forceinline word_t LOADBYTES(const uint8_t* bytes, int n) {
uint64_t x = 0;
for (int i = 0; i < n; ++i) ((uint8_t*)&x)[7 - i] = bytes[i];
return U64TOWORD(x);
}
forceinline void STOREBYTES(uint8_t* bytes, word_t w, int n) {
uint64_t x = WORDTOU64(w);
for (int i = 0; i < n; ++i) bytes[i] = ((uint8_t*)&x)[7 - i];
}
#endif /* WORD_H_ */

View File

@ -0,0 +1,219 @@
#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
forceinline void ascon_loadkey(word_t* K0, word_t* K1, word_t* K2,
const uint8_t* k) {
KINIT(K0, K1, K2);
if (CRYPTO_KEYBYTES == 16) {
*K1 = XOR(*K1, LOAD(k, 8));
*K2 = XOR(*K2, LOAD(k + 8, 8));
}
if (CRYPTO_KEYBYTES == 20) {
*K0 = XOR(*K0, KEYROT(WORD_T(0), LOADBYTES(k, 4)));
*K1 = XOR(*K1, LOADBYTES(k + 4, 8));
*K2 = XOR(*K2, LOADBYTES(k + 12, 8));
}
}
forceinline void ascon_aeadinit(state_t* s, const uint8_t* npub,
const uint8_t* k) {
/* load nonce */
word_t N0 = LOAD(npub, 8);
word_t N1 = LOAD(npub + 8, 8);
/* load key */
word_t K0, K1, K2;
ascon_loadkey(&K0, &K1, &K2, k);
/* initialize */
PINIT(s);
if (CRYPTO_KEYBYTES == 16 && ASCON_AEAD_RATE == 8)
s->x0 = XOR(s->x0, ASCON_128_IV);
if (CRYPTO_KEYBYTES == 16 && ASCON_AEAD_RATE == 16)
s->x0 = XOR(s->x0, ASCON_128A_IV);
if (CRYPTO_KEYBYTES == 20) s->x0 = XOR(s->x0, ASCON_80PQ_IV);
if (CRYPTO_KEYBYTES == 20) s->x0 = XOR(s->x0, K0);
s->x1 = XOR(s->x1, K1);
s->x2 = XOR(s->x2, K2);
s->x3 = XOR(s->x3, N0);
s->x4 = XOR(s->x4, N1);
P(s, 12);
if (CRYPTO_KEYBYTES == 20) s->x2 = XOR(s->x2, K0);
s->x3 = XOR(s->x3, K1);
s->x4 = XOR(s->x4, K2);
printstate("initialization", 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->x0 = XOR(s->x0, LOAD(ad, 8));
if (ASCON_AEAD_RATE == 16) s->x1 = XOR(s->x1, LOAD(ad + 8, 8));
P(s, nr);
ad += ASCON_AEAD_RATE;
adlen -= ASCON_AEAD_RATE;
}
/* final associated data block */
word_t* px = &s->x0;
if (ASCON_AEAD_RATE == 16 && adlen >= 8) {
s->x0 = XOR(s->x0, LOAD(ad, 8));
px = &s->x1;
ad += 8;
adlen -= 8;
}
*px = XOR(*px, PAD(adlen));
if (adlen) *px = XOR(*px, LOAD(ad, adlen));
P(s, nr);
}
/* domain separation */
s->x4 = XOR(s->x4, WORD_T(1));
printstate("process associated data", 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->x0 = XOR(s->x0, LOAD(m, 8));
STORE(c, s->x0, 8);
if (ASCON_AEAD_RATE == 16) {
s->x1 = XOR(s->x1, LOAD(m + 8, 8));
STORE(c + 8, s->x1, 8);
}
P(s, nr);
m += ASCON_AEAD_RATE;
c += ASCON_AEAD_RATE;
mlen -= ASCON_AEAD_RATE;
}
/* final plaintext block */
word_t* px = &s->x0;
if (ASCON_AEAD_RATE == 16 && mlen >= 8) {
s->x0 = XOR(s->x0, LOAD(m, 8));
STORE(c, s->x0, 8);
px = &s->x1;
m += 8;
c += 8;
mlen -= 8;
}
*px = XOR(*px, PAD(mlen));
if (mlen) {
*px = XOR(*px, LOAD(m, mlen));
STORE(c, *px, mlen);
}
printstate("process 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) {
word_t cx = LOAD(c, 8);
s->x0 = XOR(s->x0, cx);
STORE(m, s->x0, 8);
s->x0 = cx;
if (ASCON_AEAD_RATE == 16) {
cx = LOAD(c + 8, 8);
s->x1 = XOR(s->x1, cx);
STORE(m + 8, s->x1, 8);
s->x1 = cx;
}
P(s, nr);
m += ASCON_AEAD_RATE;
c += ASCON_AEAD_RATE;
clen -= ASCON_AEAD_RATE;
}
/* final ciphertext block */
word_t* px = &s->x0;
if (ASCON_AEAD_RATE == 16 && clen >= 8) {
word_t cx = LOAD(c, 8);
s->x0 = XOR(s->x0, cx);
STORE(m, s->x0, 8);
s->x0 = cx;
px = &s->x1;
m += 8;
c += 8;
clen -= 8;
}
*px = XOR(*px, PAD(clen));
if (clen) {
word_t cx = LOAD(c, clen);
*px = XOR(*px, cx);
STORE(m, *px, clen);
*px = CLEAR(*px, clen);
*px = XOR(*px, cx);
}
printstate("process ciphertext", s);
}
forceinline void ascon_final(state_t* s, const uint8_t* k) {
/* load key */
word_t K0, K1, K2;
ascon_loadkey(&K0, &K1, &K2, k);
/* finalize */
if (CRYPTO_KEYBYTES == 16 && ASCON_AEAD_RATE == 8) {
s->x1 = XOR(s->x1, K1);
s->x2 = XOR(s->x2, K2);
}
if (CRYPTO_KEYBYTES == 16 && ASCON_AEAD_RATE == 16) {
s->x2 = XOR(s->x2, K1);
s->x3 = XOR(s->x3, K2);
}
if (CRYPTO_KEYBYTES == 20) {
s->x1 = XOR(s->x1, KEYROT(K0, K1));
s->x2 = XOR(s->x2, KEYROT(K1, K2));
s->x3 = XOR(s->x3, KEYROT(K2, WORD_T(0)));
}
P(s, 12);
s->x3 = XOR(s->x3, K1);
s->x4 = XOR(s->x4, K2);
printstate("finalization", 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 */
ascon_aeadinit(&s, npub, k);
ascon_adata(&s, ad, adlen);
ascon_encrypt(&s, c, m, mlen);
ascon_final(&s, k);
/* set tag */
STOREBYTES(c + mlen, s.x3, 8);
STOREBYTES(c + mlen + 8, s.x4, 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 */
ascon_aeadinit(&s, npub, k);
ascon_adata(&s, ad, adlen);
ascon_decrypt(&s, m, c, clen);
ascon_final(&s, k);
/* verify tag (should be constant time, check compiler output) */
s.x3 = XOR(s.x3, LOADBYTES(c + clen, 8));
s.x4 = XOR(s.x4, LOADBYTES(c + clen + 8, 8));
return NOTZERO(s.x3, s.x4);
}

View File

@ -0,0 +1,7 @@
#define CRYPTO_VERSION "1.2.5"
#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

View File

@ -0,0 +1,18 @@
#ifndef ASCON_H_
#define ASCON_H_
#include <stdint.h>
#include "word.h"
typedef struct {
word_t x0, x1, x2, x3, x4;
} state_t;
void ascon_aeadinit(state_t* s, const uint8_t* npub, const uint8_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 uint8_t* k);
#endif /* ASCON_H */

View File

@ -0,0 +1,19 @@
#ifndef CONFIG_H_
#define CONFIG_H_
/* inline the ascon mode */
#ifndef ASCON_INLINE_MODE
#define ASCON_INLINE_MODE 0
#endif
/* inline all permutations */
#ifndef ASCON_INLINE_PERM
#define ASCON_INLINE_PERM 1
#endif
/* unroll permutation loops */
#ifndef ASCON_UNROLL_LOOPS
#define ASCON_UNROLL_LOOPS 0
#endif
#endif /* CONFIG_H_ */

View File

@ -0,0 +1,39 @@
#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_ */

View File

@ -0,0 +1,19 @@
#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_ */

View File

@ -0,0 +1 @@
Branches reviewed 2020-11-13 by Martin Schläffer.

View File

@ -0,0 +1 @@
Addresses reviewed 2020-11-13 by Martin Schläffer.

View File

@ -0,0 +1,2 @@
Christoph Dobraunig
Martin Schläffer

View File

@ -0,0 +1,49 @@
#ifndef INTERLEAVE_H_
#define INTERLEAVE_H_
#include <stdint.h>
#include "forceinline.h"
forceinline uint32_t deinterleave_uint32(uint32_t x) {
uint32_t t;
t = (x ^ (x >> 1)) & 0x22222222, x ^= t ^ (t << 1);
t = (x ^ (x >> 2)) & 0x0C0C0C0C, x ^= t ^ (t << 2);
t = (x ^ (x >> 4)) & 0x00F000F0, x ^= t ^ (t << 4);
t = (x ^ (x >> 8)) & 0x0000FF00, x ^= t ^ (t << 8);
return x;
}
forceinline uint32_t interleave_uint32(uint32_t x) {
uint32_t t;
t = (x ^ (x >> 8)) & 0x0000FF00, x ^= t ^ (t << 8);
t = (x ^ (x >> 4)) & 0x00F000F0, x ^= t ^ (t << 4);
t = (x ^ (x >> 2)) & 0x0C0C0C0C, x ^= t ^ (t << 2);
t = (x ^ (x >> 1)) & 0x22222222, x ^= t ^ (t << 1);
return x;
}
/* credit to Henry S. Warren, Hacker's Delight, Addison-Wesley, 2002 */
forceinline uint64_t deinterleave32(uint64_t in) {
uint32_t hi = in >> 32;
uint32_t lo = in;
uint32_t r0, r1;
lo = deinterleave_uint32(lo);
hi = deinterleave_uint32(hi);
r0 = (lo & 0x0000FFFF) | (hi << 16);
r1 = (lo >> 16) | (hi & 0xFFFF0000);
return (uint64_t)r1 << 32 | r0;
}
/* credit to Henry S. Warren, Hacker's Delight, Addison-Wesley, 2002 */
forceinline uint64_t interleave32(uint64_t in) {
uint32_t r0 = in;
uint32_t r1 = in >> 32;
uint32_t lo = (r0 & 0x0000FFFF) | (r1 << 16);
uint32_t hi = (r0 >> 16) | (r1 & 0xFFFF0000);
lo = interleave_uint32(lo);
hi = interleave_uint32(hi);
return (uint64_t)hi << 32 | lo;
}
#endif /* INTERLEAVE_H_ */

View File

@ -0,0 +1,23 @@
#include "permutations.h"
#if !ASCON_UNROLL_LOOPS
const uint8_t constants[][2] = {{0xc, 0xc}, {0x9, 0xc}, {0xc, 0x9}, {0x9, 0x9},
{0x6, 0xc}, {0x3, 0xc}, {0x6, 0x9}, {0x3, 0x9},
{0xc, 0x6}, {0x9, 0x6}, {0xc, 0x3}, {0x9, 0x3}};
#endif
#if !ASCON_INLINE_PERM && ASCON_UNROLL_LOOPS
void P12(state_t* s) { P12ROUNDS(s); }
void P8(state_t* s) { P8ROUNDS(s); }
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

View File

@ -0,0 +1,139 @@
#ifndef PERMUTATIONS_H_
#define PERMUTATIONS_H_
#include <stdint.h>
#include "api.h"
#include "ascon.h"
#include "config.h"
#include "printstate.h"
#include "round.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_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_HASH_BYTES 32
#define ASCON_128_IV WORD_T(0x8021000008220000ull)
#define ASCON_128A_IV WORD_T(0x8822000000200000ull)
#define ASCON_80PQ_IV WORD_T(0xc021000008220000ull)
#define ASCON_HASH_IV WORD_T(0x0020000008020010ull)
#define ASCON_XOF_IV WORD_T(0x0020000008020000ull)
#define ASCON_HASH_IV0 WORD_T(0xf9afb5c6a540dbc7ull)
#define ASCON_HASH_IV1 WORD_T(0xbd2493011445a340ull)
#define ASCON_HASH_IV2 WORD_T(0xcb9ba8b5604d4fc8ull)
#define ASCON_HASH_IV3 WORD_T(0x12a4eede94514c98ull)
#define ASCON_HASH_IV4 WORD_T(0x4bca84c06339f398ull)
#define ASCON_HASHA_IV0 WORD_T(0x0108e46d1b16eb02ull)
#define ASCON_HASHA_IV1 WORD_T(0x5b9b8efdd29083f3ull)
#define ASCON_HASHA_IV2 WORD_T(0x7ad665622891ae4aull)
#define ASCON_HASHA_IV3 WORD_T(0x9dc27156ee3bfc7full)
#define ASCON_HASHA_IV4 WORD_T(0xc61d5fa916801633ull)
#define ASCON_XOF_IV0 WORD_T(0xc75782817e351ae6ull)
#define ASCON_XOF_IV1 WORD_T(0x70045f441d238220ull)
#define ASCON_XOF_IV2 WORD_T(0x5dd5ab52a13e3f04ull)
#define ASCON_XOF_IV3 WORD_T(0x3e378142c30c1db2ull)
#define ASCON_XOF_IV4 WORD_T(0x3735189db624d656ull)
#define ASCON_XOFA_IV0 WORD_T(0x0846d7a5a4b87d44ull)
#define ASCON_XOFA_IV1 WORD_T(0xaa6f1005b3a2dbf4ull)
#define ASCON_XOFA_IV2 WORD_T(0xdc451146f713e811ull)
#define ASCON_XOFA_IV3 WORD_T(0x468cb2532839e30dull)
#define ASCON_XOFA_IV4 WORD_T(0xeb2d429709e96977ull)
#define START(n) (12 - n)
#define RC(e, o) WORD_T((uint64_t)o << 32 | e)
forceinline void P12ROUNDS(state_t* s) {
ROUND(s, RC(0xc, 0xc));
ROUND(s, RC(0x9, 0xc));
ROUND(s, RC(0xc, 0x9));
ROUND(s, RC(0x9, 0x9));
ROUND(s, RC(0x6, 0xc));
ROUND(s, RC(0x3, 0xc));
ROUND(s, RC(0x6, 0x9));
ROUND(s, RC(0x3, 0x9));
ROUND(s, RC(0xc, 0x6));
ROUND(s, RC(0x9, 0x6));
ROUND(s, RC(0xc, 0x3));
ROUND(s, RC(0x9, 0x3));
}
forceinline void P8ROUNDS(state_t* s) {
ROUND(s, RC(0x6, 0xc));
ROUND(s, RC(0x3, 0xc));
ROUND(s, RC(0x6, 0x9));
ROUND(s, RC(0x3, 0x9));
ROUND(s, RC(0xc, 0x6));
ROUND(s, RC(0x9, 0x6));
ROUND(s, RC(0xc, 0x3));
ROUND(s, RC(0x9, 0x3));
}
forceinline void P6ROUNDS(state_t* s) {
ROUND(s, RC(0x6, 0x9));
ROUND(s, RC(0x3, 0x9));
ROUND(s, RC(0xc, 0x6));
ROUND(s, RC(0x9, 0x6));
ROUND(s, RC(0xc, 0x3));
ROUND(s, RC(0x9, 0x3));
}
extern const uint8_t constants[][2];
forceinline void PROUNDS(state_t* s, int nr) {
for (int i = START(nr); i < 12; i++)
ROUND(s, RC(constants[i][0], constants[i][1]));
}
#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_ */

View File

@ -0,0 +1,21 @@
#ifdef ASCON_PRINTSTATE
#include "printstate.h"
#include <inttypes.h>
#include <stdio.h>
void printword(const char* text, const word_t x) {
printf("%s=%016" PRIx64 "\n", text, WORDTOU64(x));
}
void printstate(const char* text, const state_t* s) {
printf("%s:\n", text);
printword(" x0", s->x0);
printword(" x1", s->x1);
printword(" x2", s->x2);
printword(" x3", s->x3);
printword(" x4", s->x4);
}
#endif

View File

@ -0,0 +1,24 @@
#ifndef PRINTSTATE_H_
#define PRINTSTATE_H_
#ifdef ASCON_PRINTSTATE
#include "ascon.h"
#include "word.h"
void printword(const char* text, const word_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_ */

View File

@ -0,0 +1,53 @@
#ifndef ROUND_H_
#define ROUND_H_
#include "ascon.h"
#include "printstate.h"
forceinline void KINIT(word_t* K0, word_t* K1, word_t* K2) {
*K0 = WORD_T(0);
*K1 = WORD_T(0);
*K2 = WORD_T(0);
}
forceinline void PINIT(state_t* s) {
s->x0 = WORD_T(0);
s->x1 = WORD_T(0);
s->x2 = WORD_T(0);
s->x3 = WORD_T(0);
s->x4 = WORD_T(0);
}
forceinline void ROUND(state_t* s, word_t C) {
word_t xtemp;
/* round constant */
s->x2 = XOR(s->x2, C);
/* s-box layer */
s->x0 = XOR(s->x0, s->x4);
s->x4 = XOR(s->x4, s->x3);
s->x2 = XOR(s->x2, s->x1);
xtemp = AND(s->x0, NOT(s->x4));
s->x0 = XOR(s->x0, AND(s->x2, NOT(s->x1)));
s->x2 = XOR(s->x2, AND(s->x4, NOT(s->x3)));
s->x4 = XOR(s->x4, AND(s->x1, NOT(s->x0)));
s->x1 = XOR(s->x1, AND(s->x3, NOT(s->x2)));
s->x3 = XOR(s->x3, xtemp);
s->x1 = XOR(s->x1, s->x0);
s->x3 = XOR(s->x3, s->x2);
s->x0 = XOR(s->x0, s->x4);
/* linear layer */
xtemp = XOR(s->x0, ROR(s->x0, 28 - 19));
s->x0 = XOR(s->x0, ROR(xtemp, 19));
xtemp = XOR(s->x1, ROR(s->x1, 61 - 39));
s->x1 = XOR(s->x1, ROR(xtemp, 39));
xtemp = XOR(s->x2, ROR(s->x2, 6 - 1));
s->x2 = XOR(s->x2, ROR(xtemp, 1));
xtemp = XOR(s->x3, ROR(s->x3, 17 - 10));
s->x3 = XOR(s->x3, ROR(xtemp, 10));
xtemp = XOR(s->x4, ROR(s->x4, 41 - 7));
s->x4 = XOR(s->x4, ROR(xtemp, 7));
s->x2 = NOT(s->x2);
printstate(" round output", s);
}
#endif /* ROUND_H_ */

View File

@ -0,0 +1,105 @@
#ifndef WORD_H_
#define WORD_H_
#include <stdint.h>
#include "endian.h"
#include "forceinline.h"
#include "interleave.h"
typedef struct {
uint32_t e;
uint32_t o;
} word_t;
forceinline uint32_t ROR32(uint32_t x, int n) {
return (n == 0) ? x : x >> n | x << (32 - n);
}
forceinline word_t ROR(word_t x, int n) {
word_t r;
r.e = (n % 2) ? ROR32(x.o, (n - 1) / 2) : ROR32(x.e, n / 2);
r.o = (n % 2) ? ROR32(x.e, (n + 1) / 2) : ROR32(x.o, n / 2);
return r;
}
forceinline word_t WORD_T(uint64_t x) { return (word_t){.o = x >> 32, .e = x}; }
forceinline uint64_t UINT64_T(word_t x) { return (uint64_t)x.o << 32 | x.e; }
forceinline word_t U64TOWORD(uint64_t x) { return WORD_T(deinterleave32(x)); }
forceinline uint64_t WORDTOU64(word_t w) { return interleave32(UINT64_T(w)); }
forceinline word_t NOT(word_t a) {
a.e = ~a.e;
a.o = ~a.o;
return a;
}
forceinline word_t XOR(word_t a, word_t b) {
a.e ^= b.e;
a.o ^= b.o;
return a;
}
forceinline word_t AND(word_t a, word_t b) {
a.e &= b.e;
a.o &= b.o;
return a;
}
forceinline word_t KEYROT(word_t lo2hi, word_t hi2lo) {
word_t r;
r.e = lo2hi.e << 16 | hi2lo.e >> 16;
r.o = lo2hi.o << 16 | hi2lo.o >> 16;
return r;
}
forceinline int NOTZERO(word_t a, word_t b) {
uint32_t result = a.e | a.o | b.e | b.o;
result |= result >> 16;
result |= result >> 8;
return ((((int)(result & 0xff) - 1) >> 8) & 1) - 1;
}
forceinline word_t PAD(int i) {
return WORD_T((uint64_t)(0x8ul << (28 - 4 * i)) << 32);
}
forceinline word_t CLEAR(word_t w, int n) {
/* undefined for n == 0 */
uint32_t mask = 0x0fffffff >> (n * 4 - 4);
w.e &= mask;
w.o &= mask;
return w;
}
forceinline uint64_t MASK(int n) {
/* undefined for n == 0 */
return ~0ull >> (64 - 8 * n);
}
forceinline word_t LOAD(const uint8_t* bytes, int n) {
uint64_t x = *(uint64_t*)bytes & MASK(n);
return U64TOWORD(U64BIG(x));
}
forceinline void STORE(uint8_t* bytes, word_t w, int n) {
uint64_t x = WORDTOU64(w);
*(uint64_t*)bytes &= ~MASK(n);
*(uint64_t*)bytes |= U64BIG(x);
}
forceinline word_t LOADBYTES(const uint8_t* bytes, int n) {
uint64_t x = 0;
for (int i = 0; i < n; ++i) ((uint8_t*)&x)[7 - i] = bytes[i];
return U64TOWORD(x);
}
forceinline void STOREBYTES(uint8_t* bytes, word_t w, int n) {
uint64_t x = WORDTOU64(w);
for (int i = 0; i < n; ++i) bytes[i] = ((uint8_t*)&x)[7 - i];
}
#endif /* WORD_H_ */

View File

@ -0,0 +1,79 @@
#include "api.h"
#include "ascon.h"
#include "permutations.h"
#include "printstate.h"
forceinline void ascon_loadkey(word_t* K0, word_t* K1, word_t* K2,
const uint8_t* k) {
KINIT(K0, K1, K2);
if (CRYPTO_KEYBYTES == 16) {
*K1 = XOR(*K1, LOAD(k, 8));
*K2 = XOR(*K2, LOAD(k + 8, 8));
}
if (CRYPTO_KEYBYTES == 20) {
*K0 = XOR(*K0, KEYROT(WORD_T(0), LOADBYTES(k, 4)));
*K1 = XOR(*K1, LOADBYTES(k + 4, 8));
*K2 = XOR(*K2, LOADBYTES(k + 12, 8));
}
}
forceinline void ascon_aeadinit(state_t* s, const uint8_t* npub, word_t K0,
word_t K1, word_t K2) {
if (CRYPTO_KEYBYTES == 16 && ASCON_AEAD_RATE == 8) s->x0 = ASCON_128_IV;
if (CRYPTO_KEYBYTES == 16 && ASCON_AEAD_RATE == 16) s->x0 = ASCON_128A_IV;
if (CRYPTO_KEYBYTES == 20) s->x0 = ASCON_80PQ_IV;
if (CRYPTO_KEYBYTES == 20) s->x0 = XOR(s->x0, K0);
s->x1 = K1;
s->x2 = K2;
s->x3 = LOAD(npub, 8);
s->x4 = LOAD(npub + 8, 8);
P(s, 12);
if (CRYPTO_KEYBYTES == 20) s->x2 = XOR(s->x2, K0);
s->x3 = XOR(s->x3, K1);
s->x4 = XOR(s->x4, K2);
printstate("initialization", s);
}
forceinline void ascon_final(state_t* s, word_t K0, word_t K1, word_t K2) {
if (CRYPTO_KEYBYTES == 16 && ASCON_AEAD_RATE == 8) {
s->x1 = XOR(s->x1, K1);
s->x2 = XOR(s->x2, K2);
}
if (CRYPTO_KEYBYTES == 16 && ASCON_AEAD_RATE == 16) {
s->x2 = XOR(s->x2, K1);
s->x3 = XOR(s->x3, K2);
}
if (CRYPTO_KEYBYTES == 20) {
s->x1 = XOR(s->x1, KEYROT(K0, K1));
s->x2 = XOR(s->x2, KEYROT(K1, K2));
s->x3 = XOR(s->x3, KEYROT(K2, WORD_T(0)));
}
P(s, 12);
s->x3 = XOR(s->x3, K1);
s->x4 = XOR(s->x4, K2);
printstate("finalization", s);
}
void ascon_aead(state_t* s, 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;
word_t K0, K1, K2;
ascon_loadkey(&K0, &K1, &K2, k);
/* initialize */
ascon_aeadinit(s, npub, K0, K1, K2);
/* process associated data */
if (adlen) {
ascon_update(s, (void*)0, ad, adlen, ASCON_ABSORB);
P(s, nr);
}
/* domain separation */
s->x4 = XOR(s->x4, WORD_T(1));
printstate("process associated data", s);
/* process plaintext/ciphertext */
ascon_update(s, out, in, tlen, mode);
if (mode == ASCON_ENCRYPT) printstate("process plaintext", s);
if (mode == ASCON_DECRYPT) printstate("process ciphertext", s);
/* finalize */
ascon_final(s, K0, K1, K2);
}

View File

@ -0,0 +1,7 @@
#define CRYPTO_VERSION "1.2.5"
#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

View File

@ -0,0 +1,26 @@
#ifndef ASCON_H_
#define ASCON_H_
#include <stdint.h>
#include "word.h"
typedef struct {
word_t x0, x1, x2, x3, x4;
} state_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(state_t* s, 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);
#endif /* ASCON_H */

View File

@ -0,0 +1,19 @@
#ifndef CONFIG_H_
#define CONFIG_H_
/* inline the ascon mode */
#ifndef ASCON_INLINE_MODE
#define ASCON_INLINE_MODE 0
#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
#endif /* CONFIG_H_ */

View File

@ -0,0 +1,27 @@
#include "api.h"
#include "ascon.h"
#include "crypto_aead.h"
#include "permutations.h"
#include "printstate.h"
void ascon_aead(state_t* s, 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);
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;
/* set plaintext size */
*mlen = clen - CRYPTO_ABYTES;
/* ascon decryption */
ascon_aead(&s, m, c, *mlen, ad, adlen, npub, k, ASCON_DECRYPT);
/* verify tag (should be constant time, check compiler output) */
s.x3 = XOR(s.x3, LOADBYTES(c + *mlen, 8));
s.x4 = XOR(s.x4, LOADBYTES(c + *mlen + 8, 8));
return NOTZERO(s.x3, s.x4);
}

View File

@ -0,0 +1,26 @@
#include "api.h"
#include "ascon.h"
#include "crypto_aead.h"
#include "permutations.h"
#include "printstate.h"
void ascon_aead(state_t* s, 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);
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;
/* set ciphertext size */
*clen = mlen + CRYPTO_ABYTES;
/* ascon encryption */
ascon_aead(&s, c, m, mlen, ad, adlen, npub, k, ASCON_ENCRYPT);
/* set tag */
STOREBYTES(c + mlen, s.x3, 8);
STOREBYTES(c + mlen + 8, s.x4, 8);
return 0;
}

View File

@ -0,0 +1,39 @@
#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_ */

View File

@ -0,0 +1,19 @@
#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_ */

View File

@ -0,0 +1 @@
Branches reviewed 2020-11-13 by Martin Schläffer.

View File

@ -0,0 +1 @@
Addresses reviewed 2020-11-13 by Martin Schläffer.

View File

@ -0,0 +1,2 @@
Christoph Dobraunig
Martin Schläffer

View File

@ -0,0 +1,42 @@
#include "interleave.h"
static inline uint32_t deinterleave_uint32(uint32_t x) {
uint32_t t;
t = (x ^ (x >> 1)) & 0x22222222, x ^= t ^ (t << 1);
t = (x ^ (x >> 2)) & 0x0C0C0C0C, x ^= t ^ (t << 2);
t = (x ^ (x >> 4)) & 0x00F000F0, x ^= t ^ (t << 4);
t = (x ^ (x >> 8)) & 0x0000FF00, x ^= t ^ (t << 8);
return x;
}
static inline uint32_t interleave_uint32(uint32_t x) {
uint32_t t;
t = (x ^ (x >> 8)) & 0x0000FF00, x ^= t ^ (t << 8);
t = (x ^ (x >> 4)) & 0x00F000F0, x ^= t ^ (t << 4);
t = (x ^ (x >> 2)) & 0x0C0C0C0C, x ^= t ^ (t << 2);
t = (x ^ (x >> 1)) & 0x22222222, x ^= t ^ (t << 1);
return x;
}
/* credit to Henry S. Warren, Hacker's Delight, Addison-Wesley, 2002 */
uint64_t deinterleave32(uint64_t in) {
uint32_t hi = in >> 32;
uint32_t lo = in;
uint32_t r0, r1;
lo = deinterleave_uint32(lo);
hi = deinterleave_uint32(hi);
r0 = (lo & 0x0000FFFF) | (hi << 16);
r1 = (lo >> 16) | (hi & 0xFFFF0000);
return (uint64_t)r1 << 32 | r0;
}
/* credit to Henry S. Warren, Hacker's Delight, Addison-Wesley, 2002 */
uint64_t interleave32(uint64_t in) {
uint32_t r0 = in;
uint32_t r1 = in >> 32;
uint32_t lo = (r0 & 0x0000FFFF) | (r1 << 16);
uint32_t hi = (r0 >> 16) | (r1 & 0xFFFF0000);
lo = interleave_uint32(lo);
hi = interleave_uint32(hi);
return (uint64_t)hi << 32 | lo;
}

View File

@ -0,0 +1,11 @@
#ifndef INTERLEAVE_H_
#define INTERLEAVE_H_
#include <stdint.h>
#include "forceinline.h"
uint64_t deinterleave32(uint64_t in);
uint64_t interleave32(uint64_t in);
#endif /* INTERLEAVE_H_ */

View File

@ -0,0 +1,23 @@
#include "permutations.h"
#if !ASCON_UNROLL_LOOPS
const uint8_t constants[][2] = {{0xc, 0xc}, {0x9, 0xc}, {0xc, 0x9}, {0x9, 0x9},
{0x6, 0xc}, {0x3, 0xc}, {0x6, 0x9}, {0x3, 0x9},
{0xc, 0x6}, {0x9, 0x6}, {0xc, 0x3}, {0x9, 0x3}};
#endif
#if !ASCON_INLINE_PERM && ASCON_UNROLL_LOOPS
void P12(state_t* s) { P12ROUNDS(s); }
void P8(state_t* s) { P8ROUNDS(s); }
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

View File

@ -0,0 +1,139 @@
#ifndef PERMUTATIONS_H_
#define PERMUTATIONS_H_
#include <stdint.h>
#include "api.h"
#include "ascon.h"
#include "config.h"
#include "printstate.h"
#include "round.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_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_HASH_BYTES 32
#define ASCON_128_IV WORD_T(0x8021000008220000ull)
#define ASCON_128A_IV WORD_T(0x8822000000200000ull)
#define ASCON_80PQ_IV WORD_T(0xc021000008220000ull)
#define ASCON_HASH_IV WORD_T(0x0020000008020010ull)
#define ASCON_XOF_IV WORD_T(0x0020000008020000ull)
#define ASCON_HASH_IV0 WORD_T(0xf9afb5c6a540dbc7ull)
#define ASCON_HASH_IV1 WORD_T(0xbd2493011445a340ull)
#define ASCON_HASH_IV2 WORD_T(0xcb9ba8b5604d4fc8ull)
#define ASCON_HASH_IV3 WORD_T(0x12a4eede94514c98ull)
#define ASCON_HASH_IV4 WORD_T(0x4bca84c06339f398ull)
#define ASCON_HASHA_IV0 WORD_T(0x0108e46d1b16eb02ull)
#define ASCON_HASHA_IV1 WORD_T(0x5b9b8efdd29083f3ull)
#define ASCON_HASHA_IV2 WORD_T(0x7ad665622891ae4aull)
#define ASCON_HASHA_IV3 WORD_T(0x9dc27156ee3bfc7full)
#define ASCON_HASHA_IV4 WORD_T(0xc61d5fa916801633ull)
#define ASCON_XOF_IV0 WORD_T(0xc75782817e351ae6ull)
#define ASCON_XOF_IV1 WORD_T(0x70045f441d238220ull)
#define ASCON_XOF_IV2 WORD_T(0x5dd5ab52a13e3f04ull)
#define ASCON_XOF_IV3 WORD_T(0x3e378142c30c1db2ull)
#define ASCON_XOF_IV4 WORD_T(0x3735189db624d656ull)
#define ASCON_XOFA_IV0 WORD_T(0x0846d7a5a4b87d44ull)
#define ASCON_XOFA_IV1 WORD_T(0xaa6f1005b3a2dbf4ull)
#define ASCON_XOFA_IV2 WORD_T(0xdc451146f713e811ull)
#define ASCON_XOFA_IV3 WORD_T(0x468cb2532839e30dull)
#define ASCON_XOFA_IV4 WORD_T(0xeb2d429709e96977ull)
#define START(n) (12 - n)
#define RC(e, o) WORD_T((uint64_t)o << 32 | e)
forceinline void P12ROUNDS(state_t* s) {
ROUND(s, RC(0xc, 0xc));
ROUND(s, RC(0x9, 0xc));
ROUND(s, RC(0xc, 0x9));
ROUND(s, RC(0x9, 0x9));
ROUND(s, RC(0x6, 0xc));
ROUND(s, RC(0x3, 0xc));
ROUND(s, RC(0x6, 0x9));
ROUND(s, RC(0x3, 0x9));
ROUND(s, RC(0xc, 0x6));
ROUND(s, RC(0x9, 0x6));
ROUND(s, RC(0xc, 0x3));
ROUND(s, RC(0x9, 0x3));
}
forceinline void P8ROUNDS(state_t* s) {
ROUND(s, RC(0x6, 0xc));
ROUND(s, RC(0x3, 0xc));
ROUND(s, RC(0x6, 0x9));
ROUND(s, RC(0x3, 0x9));
ROUND(s, RC(0xc, 0x6));
ROUND(s, RC(0x9, 0x6));
ROUND(s, RC(0xc, 0x3));
ROUND(s, RC(0x9, 0x3));
}
forceinline void P6ROUNDS(state_t* s) {
ROUND(s, RC(0x6, 0x9));
ROUND(s, RC(0x3, 0x9));
ROUND(s, RC(0xc, 0x6));
ROUND(s, RC(0x9, 0x6));
ROUND(s, RC(0xc, 0x3));
ROUND(s, RC(0x9, 0x3));
}
extern const uint8_t constants[][2];
forceinline void PROUNDS(state_t* s, int nr) {
for (int i = START(nr); i < 12; i++)
ROUND(s, RC(constants[i][0], constants[i][1]));
}
#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_ */

View File

@ -0,0 +1,21 @@
#ifdef ASCON_PRINTSTATE
#include "printstate.h"
#include <inttypes.h>
#include <stdio.h>
void printword(const char* text, const word_t x) {
printf("%s=%016" PRIx64 "\n", text, WORDTOU64(x));
}
void printstate(const char* text, const state_t* s) {
printf("%s:\n", text);
printword(" x0", s->x0);
printword(" x1", s->x1);
printword(" x2", s->x2);
printword(" x3", s->x3);
printword(" x4", s->x4);
}
#endif

View File

@ -0,0 +1,24 @@
#ifndef PRINTSTATE_H_
#define PRINTSTATE_H_
#ifdef ASCON_PRINTSTATE
#include "ascon.h"
#include "word.h"
void printword(const char* text, const word_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_ */

View File

@ -0,0 +1,53 @@
#ifndef ROUND_H_
#define ROUND_H_
#include "ascon.h"
#include "printstate.h"
forceinline void KINIT(word_t* K0, word_t* K1, word_t* K2) {
*K0 = WORD_T(0);
*K1 = WORD_T(0);
*K2 = WORD_T(0);
}
forceinline void PINIT(state_t* s) {
s->x0 = WORD_T(0);
s->x1 = WORD_T(0);
s->x2 = WORD_T(0);
s->x3 = WORD_T(0);
s->x4 = WORD_T(0);
}
forceinline void ROUND(state_t* s, word_t C) {
word_t xtemp;
/* round constant */
s->x2 = XOR(s->x2, C);
/* s-box layer */
s->x0 = XOR(s->x0, s->x4);
s->x4 = XOR(s->x4, s->x3);
s->x2 = XOR(s->x2, s->x1);
xtemp = AND(s->x0, NOT(s->x4));
s->x0 = XOR(s->x0, AND(s->x2, NOT(s->x1)));
s->x2 = XOR(s->x2, AND(s->x4, NOT(s->x3)));
s->x4 = XOR(s->x4, AND(s->x1, NOT(s->x0)));
s->x1 = XOR(s->x1, AND(s->x3, NOT(s->x2)));
s->x3 = XOR(s->x3, xtemp);
s->x1 = XOR(s->x1, s->x0);
s->x3 = XOR(s->x3, s->x2);
s->x0 = XOR(s->x0, s->x4);
/* linear layer */
xtemp = XOR(s->x0, ROR(s->x0, 28 - 19));
s->x0 = XOR(s->x0, ROR(xtemp, 19));
xtemp = XOR(s->x1, ROR(s->x1, 61 - 39));
s->x1 = XOR(s->x1, ROR(xtemp, 39));
xtemp = XOR(s->x2, ROR(s->x2, 6 - 1));
s->x2 = XOR(s->x2, ROR(xtemp, 1));
xtemp = XOR(s->x3, ROR(s->x3, 17 - 10));
s->x3 = XOR(s->x3, ROR(xtemp, 10));
xtemp = XOR(s->x4, ROR(s->x4, 41 - 7));
s->x4 = XOR(s->x4, ROR(xtemp, 7));
s->x2 = NOT(s->x2);
printstate(" round output", s);
}
#endif /* ROUND_H_ */

View File

@ -0,0 +1,44 @@
#include "api.h"
#include "ascon.h"
#include "permutations.h"
#include "printstate.h"
void ascon_update(state_t* s, uint8_t* out, const uint8_t* in, uint64_t len,
uint8_t mode) {
const int rate = 16;
const int nr = 8;
word_t tmp0, tmp1;
int n = 0, n0 = 0, n1 = 0;
while (len) {
/* determine block size */
n0 = len < 8 ? len : 8;
n1 = len < 8 ? 0 : (len < 16 ? len - 8 : 8);
n = n0 + n1;
/* absorb data */
tmp0 = LOAD(in, n0);
s->x0 = XOR(s->x0, tmp0);
if (n1) tmp1 = LOAD(in + 8, n1);
if (n1) s->x1 = XOR(s->x1, tmp1);
/* extract data */
if (mode & ASCON_SQUEEZE) {
STORE(out, s->x0, n0);
if (n1) STORE(out + 8, s->x1, n1);
}
/* insert data */
if (mode & ASCON_INSERT) {
s->x0 = CLEAR(s->x0, n0);
s->x0 = XOR(s->x0, tmp0);
if (n1) s->x1 = CLEAR(s->x1, n1);
if (n1) s->x1 = XOR(s->x1, tmp1);
}
/* compute permutation for full blocks */
if (n == rate) P(s, nr);
in += n;
out += n;
len -= n;
}
if (n % rate < 8)
s->x0 = XOR(s->x0, PAD(n0 % 8));
else
s->x1 = XOR(s->x1, PAD(n1 % 8));
}

View File

@ -0,0 +1,105 @@
#ifndef WORD_H_
#define WORD_H_
#include <stdint.h>
#include "endian.h"
#include "forceinline.h"
#include "interleave.h"
typedef struct {
uint32_t e;
uint32_t o;
} word_t;
forceinline uint32_t ROR32(uint32_t x, int n) {
return (n == 0) ? x : x >> n | x << (32 - n);
}
forceinline word_t ROR(word_t x, int n) {
word_t r;
r.e = (n % 2) ? ROR32(x.o, (n - 1) / 2) : ROR32(x.e, n / 2);
r.o = (n % 2) ? ROR32(x.e, (n + 1) / 2) : ROR32(x.o, n / 2);
return r;
}
forceinline word_t WORD_T(uint64_t x) { return (word_t){.o = x >> 32, .e = x}; }
forceinline uint64_t UINT64_T(word_t x) { return (uint64_t)x.o << 32 | x.e; }
forceinline word_t U64TOWORD(uint64_t x) { return WORD_T(deinterleave32(x)); }
forceinline uint64_t WORDTOU64(word_t w) { return interleave32(UINT64_T(w)); }
forceinline word_t NOT(word_t a) {
a.e = ~a.e;
a.o = ~a.o;
return a;
}
forceinline word_t XOR(word_t a, word_t b) {
a.e ^= b.e;
a.o ^= b.o;
return a;
}
forceinline word_t AND(word_t a, word_t b) {
a.e &= b.e;
a.o &= b.o;
return a;
}
forceinline word_t KEYROT(word_t lo2hi, word_t hi2lo) {
word_t r;
r.e = lo2hi.e << 16 | hi2lo.e >> 16;
r.o = lo2hi.o << 16 | hi2lo.o >> 16;
return r;
}
forceinline int NOTZERO(word_t a, word_t b) {
uint32_t result = a.e | a.o | b.e | b.o;
result |= result >> 16;
result |= result >> 8;
return ((((int)(result & 0xff) - 1) >> 8) & 1) - 1;
}
forceinline word_t PAD(int i) {
return WORD_T((uint64_t)(0x8ul << (28 - 4 * i)) << 32);
}
forceinline word_t CLEAR(word_t w, int n) {
/* undefined for n == 0 */
uint32_t mask = 0x0fffffff >> (n * 4 - 4);
w.e &= mask;
w.o &= mask;
return w;
}
forceinline uint64_t MASK(int n) {
/* undefined for n == 0 */
return ~0ull >> (64 - 8 * n);
}
forceinline word_t LOAD(const uint8_t* bytes, int n) {
uint64_t x = *(uint64_t*)bytes & MASK(n);
return U64TOWORD(U64BIG(x));
}
forceinline void STORE(uint8_t* bytes, word_t w, int n) {
uint64_t x = WORDTOU64(w);
*(uint64_t*)bytes &= ~MASK(n);
*(uint64_t*)bytes |= U64BIG(x);
}
forceinline word_t LOADBYTES(const uint8_t* bytes, int n) {
uint64_t x = 0;
for (int i = 0; i < n; ++i) ((uint8_t*)&x)[7 - i] = bytes[i];
return U64TOWORD(x);
}
forceinline void STOREBYTES(uint8_t* bytes, word_t w, int n) {
uint64_t x = WORDTOU64(w);
for (int i = 0; i < n; ++i) bytes[i] = ((uint8_t*)&x)[7 - i];
}
#endif /* WORD_H_ */

View File

@ -0,0 +1,219 @@
#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
forceinline void ascon_loadkey(word_t* K0, word_t* K1, word_t* K2,
const uint8_t* k) {
KINIT(K0, K1, K2);
if (CRYPTO_KEYBYTES == 16) {
*K1 = XOR(*K1, LOAD(k, 8));
*K2 = XOR(*K2, LOAD(k + 8, 8));
}
if (CRYPTO_KEYBYTES == 20) {
*K0 = XOR(*K0, KEYROT(WORD_T(0), LOADBYTES(k, 4)));
*K1 = XOR(*K1, LOADBYTES(k + 4, 8));
*K2 = XOR(*K2, LOADBYTES(k + 12, 8));
}
}
forceinline void ascon_aeadinit(state_t* s, const uint8_t* npub,
const uint8_t* k) {
/* load nonce */
word_t N0 = LOAD(npub, 8);
word_t N1 = LOAD(npub + 8, 8);
/* load key */
word_t K0, K1, K2;
ascon_loadkey(&K0, &K1, &K2, k);
/* initialize */
PINIT(s);
if (CRYPTO_KEYBYTES == 16 && ASCON_AEAD_RATE == 8)
s->x0 = XOR(s->x0, ASCON_128_IV);
if (CRYPTO_KEYBYTES == 16 && ASCON_AEAD_RATE == 16)
s->x0 = XOR(s->x0, ASCON_128A_IV);
if (CRYPTO_KEYBYTES == 20) s->x0 = XOR(s->x0, ASCON_80PQ_IV);
if (CRYPTO_KEYBYTES == 20) s->x0 = XOR(s->x0, K0);
s->x1 = XOR(s->x1, K1);
s->x2 = XOR(s->x2, K2);
s->x3 = XOR(s->x3, N0);
s->x4 = XOR(s->x4, N1);
P(s, 12);
if (CRYPTO_KEYBYTES == 20) s->x2 = XOR(s->x2, K0);
s->x3 = XOR(s->x3, K1);
s->x4 = XOR(s->x4, K2);
printstate("initialization", 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->x0 = XOR(s->x0, LOAD(ad, 8));
if (ASCON_AEAD_RATE == 16) s->x1 = XOR(s->x1, LOAD(ad + 8, 8));
P(s, nr);
ad += ASCON_AEAD_RATE;
adlen -= ASCON_AEAD_RATE;
}
/* final associated data block */
word_t* px = &s->x0;
if (ASCON_AEAD_RATE == 16 && adlen >= 8) {
s->x0 = XOR(s->x0, LOAD(ad, 8));
px = &s->x1;
ad += 8;
adlen -= 8;
}
*px = XOR(*px, PAD(adlen));
if (adlen) *px = XOR(*px, LOAD(ad, adlen));
P(s, nr);
}
/* domain separation */
s->x4 = XOR(s->x4, WORD_T(1));
printstate("process associated data", 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->x0 = XOR(s->x0, LOAD(m, 8));
STORE(c, s->x0, 8);
if (ASCON_AEAD_RATE == 16) {
s->x1 = XOR(s->x1, LOAD(m + 8, 8));
STORE(c + 8, s->x1, 8);
}
P(s, nr);
m += ASCON_AEAD_RATE;
c += ASCON_AEAD_RATE;
mlen -= ASCON_AEAD_RATE;
}
/* final plaintext block */
word_t* px = &s->x0;
if (ASCON_AEAD_RATE == 16 && mlen >= 8) {
s->x0 = XOR(s->x0, LOAD(m, 8));
STORE(c, s->x0, 8);
px = &s->x1;
m += 8;
c += 8;
mlen -= 8;
}
*px = XOR(*px, PAD(mlen));
if (mlen) {
*px = XOR(*px, LOAD(m, mlen));
STORE(c, *px, mlen);
}
printstate("process 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) {
word_t cx = LOAD(c, 8);
s->x0 = XOR(s->x0, cx);
STORE(m, s->x0, 8);
s->x0 = cx;
if (ASCON_AEAD_RATE == 16) {
cx = LOAD(c + 8, 8);
s->x1 = XOR(s->x1, cx);
STORE(m + 8, s->x1, 8);
s->x1 = cx;
}
P(s, nr);
m += ASCON_AEAD_RATE;
c += ASCON_AEAD_RATE;
clen -= ASCON_AEAD_RATE;
}
/* final ciphertext block */
word_t* px = &s->x0;
if (ASCON_AEAD_RATE == 16 && clen >= 8) {
word_t cx = LOAD(c, 8);
s->x0 = XOR(s->x0, cx);
STORE(m, s->x0, 8);
s->x0 = cx;
px = &s->x1;
m += 8;
c += 8;
clen -= 8;
}
*px = XOR(*px, PAD(clen));
if (clen) {
word_t cx = LOAD(c, clen);
*px = XOR(*px, cx);
STORE(m, *px, clen);
*px = CLEAR(*px, clen);
*px = XOR(*px, cx);
}
printstate("process ciphertext", s);
}
forceinline void ascon_final(state_t* s, const uint8_t* k) {
/* load key */
word_t K0, K1, K2;
ascon_loadkey(&K0, &K1, &K2, k);
/* finalize */
if (CRYPTO_KEYBYTES == 16 && ASCON_AEAD_RATE == 8) {
s->x1 = XOR(s->x1, K1);
s->x2 = XOR(s->x2, K2);
}
if (CRYPTO_KEYBYTES == 16 && ASCON_AEAD_RATE == 16) {
s->x2 = XOR(s->x2, K1);
s->x3 = XOR(s->x3, K2);
}
if (CRYPTO_KEYBYTES == 20) {
s->x1 = XOR(s->x1, KEYROT(K0, K1));
s->x2 = XOR(s->x2, KEYROT(K1, K2));
s->x3 = XOR(s->x3, KEYROT(K2, WORD_T(0)));
}
P(s, 12);
s->x3 = XOR(s->x3, K1);
s->x4 = XOR(s->x4, K2);
printstate("finalization", 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 */
ascon_aeadinit(&s, npub, k);
ascon_adata(&s, ad, adlen);
ascon_encrypt(&s, c, m, mlen);
ascon_final(&s, k);
/* set tag */
STOREBYTES(c + mlen, s.x3, 8);
STOREBYTES(c + mlen + 8, s.x4, 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 */
ascon_aeadinit(&s, npub, k);
ascon_adata(&s, ad, adlen);
ascon_decrypt(&s, m, c, clen);
ascon_final(&s, k);
/* verify tag (should be constant time, check compiler output) */
s.x3 = XOR(s.x3, LOADBYTES(c + clen, 8));
s.x4 = XOR(s.x4, LOADBYTES(c + clen + 8, 8));
return NOTZERO(s.x3, s.x4);
}

Some files were not shown because too many files have changed in this diff Show More