From d9d541dce82e83d1d70e4427eb310a1f72189884 Mon Sep 17 00:00:00 2001 From: SUZUKI Tetsuya Date: Wed, 3 Oct 2012 15:05:19 +0900 Subject: [PATCH] initial import --- .gitignore | 14 + .travis.yml | 12 + Makefile | 23 + README.md | 21 + c_src/AVR8-rotate64.h | 27 + c_src/AVR8-rotate64.s | 285 ++++ c_src/Keccak-avr8-settings.h | 2 + c_src/KeccakF-1600-32-rvk.macros | 555 ++++++++ c_src/KeccakF-1600-32-s1.macros | 1187 +++++++++++++++++ c_src/KeccakF-1600-32-s2.macros | 1187 +++++++++++++++++ c_src/KeccakF-1600-32.macros | 26 + c_src/KeccakF-1600-64.macros | 728 ++++++++++ c_src/KeccakF-1600-arm.c | 123 ++ c_src/KeccakF-1600-armcc.s | 653 +++++++++ c_src/KeccakF-1600-armgcc.s | 686 ++++++++++ c_src/KeccakF-1600-avr8.c | 163 +++ c_src/KeccakF-1600-avr8asm-compact.s | 647 +++++++++ c_src/KeccakF-1600-avr8asm-fast.s | 934 +++++++++++++ .../KeccakF-1600-inplace-armgcc-ARMv7A-NEON.s | 446 +++++++ c_src/KeccakF-1600-int-set.h | 6 + c_src/KeccakF-1600-interface.h | 46 + c_src/KeccakF-1600-opt32-settings.h | 4 + c_src/KeccakF-1600-opt32.c | 524 ++++++++ c_src/KeccakF-1600-opt64-settings.h | 7 + c_src/KeccakF-1600-opt64.c | 504 +++++++ c_src/KeccakF-1600-reference.c | 300 +++++ c_src/KeccakF-1600-reference.h | 20 + c_src/KeccakF-1600-reference32BI.c | 371 ++++++ c_src/KeccakF-1600-simd128.macros | 651 +++++++++ c_src/KeccakF-1600-simd64.macros | 517 +++++++ c_src/KeccakF-1600-unrolling.macros | 124 ++ c_src/KeccakF-1600-x86-64-asm.c | 62 + c_src/KeccakF-1600-x86-64-gas.s | 766 +++++++++++ c_src/KeccakF-1600-x86-64-shld-gas.s | 766 +++++++++++ c_src/KeccakF-1600-xop.macros | 573 ++++++++ c_src/KeccakNISTInterface.c | 81 ++ c_src/KeccakNISTInterface.h | 70 + c_src/KeccakSponge.c | 266 ++++ c_src/KeccakSponge.h | 76 ++ c_src/brg_endian.h | 142 ++ c_src/displayIntermediateValues.c | 117 ++ c_src/displayIntermediateValues.h | 29 + c_src/sha3_nif.c | 144 ++ doc/overview.edoc | 8 + rebar | Bin 0 -> 148087 bytes rebar.config | 33 + src/sha3.app.src | 12 + src/sha3.erl | 41 + test/sha3_tests.erl | 48 + 49 files changed, 14027 insertions(+) create mode 100644 .gitignore create mode 100644 .travis.yml create mode 100644 Makefile create mode 100644 README.md create mode 100755 c_src/AVR8-rotate64.h create mode 100755 c_src/AVR8-rotate64.s create mode 100755 c_src/Keccak-avr8-settings.h create mode 100755 c_src/KeccakF-1600-32-rvk.macros create mode 100755 c_src/KeccakF-1600-32-s1.macros create mode 100755 c_src/KeccakF-1600-32-s2.macros create mode 100755 c_src/KeccakF-1600-32.macros create mode 100755 c_src/KeccakF-1600-64.macros create mode 100755 c_src/KeccakF-1600-arm.c create mode 100755 c_src/KeccakF-1600-armcc.s create mode 100755 c_src/KeccakF-1600-armgcc.s create mode 100755 c_src/KeccakF-1600-avr8.c create mode 100755 c_src/KeccakF-1600-avr8asm-compact.s create mode 100755 c_src/KeccakF-1600-avr8asm-fast.s create mode 100755 c_src/KeccakF-1600-inplace-armgcc-ARMv7A-NEON.s create mode 100755 c_src/KeccakF-1600-int-set.h create mode 100755 c_src/KeccakF-1600-interface.h create mode 100755 c_src/KeccakF-1600-opt32-settings.h create mode 100755 c_src/KeccakF-1600-opt32.c create mode 100755 c_src/KeccakF-1600-opt64-settings.h create mode 100755 c_src/KeccakF-1600-opt64.c create mode 100755 c_src/KeccakF-1600-reference.c create mode 100755 c_src/KeccakF-1600-reference.h create mode 100755 c_src/KeccakF-1600-reference32BI.c create mode 100755 c_src/KeccakF-1600-simd128.macros create mode 100755 c_src/KeccakF-1600-simd64.macros create mode 100755 c_src/KeccakF-1600-unrolling.macros create mode 100755 c_src/KeccakF-1600-x86-64-asm.c create mode 100755 c_src/KeccakF-1600-x86-64-gas.s create mode 100755 c_src/KeccakF-1600-x86-64-shld-gas.s create mode 100755 c_src/KeccakF-1600-xop.macros create mode 100755 c_src/KeccakNISTInterface.c create mode 100755 c_src/KeccakNISTInterface.h create mode 100755 c_src/KeccakSponge.c create mode 100755 c_src/KeccakSponge.h create mode 100755 c_src/brg_endian.h create mode 100755 c_src/displayIntermediateValues.c create mode 100755 c_src/displayIntermediateValues.h create mode 100644 c_src/sha3_nif.c create mode 100644 doc/overview.edoc create mode 100755 rebar create mode 100644 rebar.config create mode 100644 src/sha3.app.src create mode 100644 src/sha3.erl create mode 100644 test/sha3_tests.erl diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..81fb1a5 --- /dev/null +++ b/.gitignore @@ -0,0 +1,14 @@ +.DS_Store +.eunit +ebin +deps +priv +*.o +*.beam +*.plt +*.swp +*.html +*.png +edoc-info +stylesheet.css + diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..cfd50bf --- /dev/null +++ b/.travis.yml @@ -0,0 +1,12 @@ +language: erlang +notifications: + disabled: true +branches: + only: + - develop + - 0.1.0 +otp_release: + - R15B02 + - R15B01 + - R15B + diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..3e8b822 --- /dev/null +++ b/Makefile @@ -0,0 +1,23 @@ +.PHONY: doc + +all: + ./rebar compile + ./rebar doc + ./rebar xref + ./rebar eunit + +compile: + ./rebar compile + +doc: + ./rebar doc + +xref: compile + ./rebar xref + +clean: + ./rebar clean + +test: xref + ./rebar eunit + diff --git a/README.md b/README.md new file mode 100644 index 0000000..9e95ae5 --- /dev/null +++ b/README.md @@ -0,0 +1,21 @@ +erlang-sha3 +=========== + +[![Build Status](https://secure.travis-ci.org/szktty/erlang-sha3.png?branch=develop)](http://travis-ci.org/szktty/erlang-sha3) + +SHA3 for Erlang + + +Licenses +-------- + +This program is distributed under Apache License 2.0. + +Keccak source files are distributed under CC0 1.0 Universal (CC0 1.0) Public Domain Dedication license. + + +Author +------ + +SUZUKI Tetsuya + diff --git a/c_src/AVR8-rotate64.h b/c_src/AVR8-rotate64.h new file mode 100755 index 0000000..4f921b9 --- /dev/null +++ b/c_src/AVR8-rotate64.h @@ -0,0 +1,27 @@ +/* +File: AVR8-rotate64.h + +This code is originally by Daniel Otte (daniel.otte@rub.de) in 2006-2010 as part of the AVR-Crypto-Lib, and was then improved by Ronny Van Keer, STMicroelectronics, in 2010. + +Implementation by Daniel Otte and Ronny Van Keer, +hereby denoted as "the implementer". + +To the extent possible under law, the implementer has waived all copyright +and related or neighboring rights to the source code in this file. +http://creativecommons.org/publicdomain/zero/1.0/ +*/ + +#ifndef ROTATE64_H_ +#define ROTATE64_H_ + +#include + + +#define ROT_CODE(a) ((((a)/8+((((a)%8)>4)?1:0))<<4) | ((a) & 7)) + +uint64_t rotate64_1bit_left(uint64_t a); +uint64_t rotate64_1bit_right(uint64_t a); +uint64_t rotate64left_code(uint64_t a, int8_t code); + +#endif /* ROTATE64_H_ */ + diff --git a/c_src/AVR8-rotate64.s b/c_src/AVR8-rotate64.s new file mode 100755 index 0000000..f30d030 --- /dev/null +++ b/c_src/AVR8-rotate64.s @@ -0,0 +1,285 @@ +/* +File: AVR8-rotate64.s + +This code is originally by Daniel Otte (daniel.otte@rub.de) in 2006-2010 as part of the AVR-Crypto-Lib, and was then improved by Ronny Van Keer, STMicroelectronics, in 2010. + +Implementation by Daniel Otte and Ronny Van Keer, +hereby denoted as "the implementer". + +To the extent possible under law, the implementer has waived all copyright +and related or neighboring rights to the source code in this file. +http://creativecommons.org/publicdomain/zero/1.0/ +*/ + +.global rotate64_1bit_left +rotate64_4bit_left: + lsl r18 + rol r19 + rol r20 + rol r21 + rol r22 + rol r23 + rol r24 + rol r25 + adc r18, r1 +rotate64_3bit_left: + lsl r18 + rol r19 + rol r20 + rol r21 + rol r22 + rol r23 + rol r24 + rol r25 + adc r18, r1 +rotate64_2bit_left: + lsl r18 + rol r19 + rol r20 + rol r21 + rol r22 + rol r23 + rol r24 + rol r25 + adc r18, r1 +rotate64_1bit_left: + lsl r18 + rol r19 + rol r20 + rol r21 + rol r22 + rol r23 + rol r24 + rol r25 + adc r18, r1 + ret + +.global rotate64_1bit_right +rotate64_3bit_right: + bst r18, 0 + ror r25 + ror r24 + ror r23 + ror r22 + ror r21 + ror r20 + ror r19 + ror r18 + bld r25, 7 +rotate64_2bit_right: + bst r18, 0 + ror r25 + ror r24 + ror r23 + ror r22 + ror r21 + ror r20 + ror r19 + ror r18 + bld r25, 7 +rotate64_1bit_right: + bst r18, 0 + ror r25 + ror r24 + ror r23 + ror r22 + ror r21 + ror r20 + ror r19 + ror r18 + bld r25, 7 + ret + +/* +** Each byte rotate routine must be 16 instructions long. +*/ +rotate64_0byte_left: + andi r16, 0x07 + ldi r30, pm_lo8(bit_rot_jmp_table) + ldi r31, pm_hi8(bit_rot_jmp_table) + add r30, r16 + + adc r31, r1 + ijmp + nop + nop + + nop + nop + nop + nop + + nop + nop + nop + nop + +rotate64_1byte_left: + mov r0, r25 + mov r25, r24 + mov r24, r23 + mov r23, r22 + + mov r22, r21 + mov r21, r20 + mov r20, r19 + mov r19, r18 + + mov r18, r0 + andi r16, 0x07 + ldi r30, pm_lo8(bit_rot_jmp_table) + ldi r31, pm_hi8(bit_rot_jmp_table) + + add r30, r16 + adc r31, r1 + ijmp + nop + +rotate64_2byte_left: + movw r0, r24 + movw r24, r22 + movw r22, r20 + movw r20, r18 + + movw r18, r0 + clr r1 + andi r16, 0x07 + ldi r30, pm_lo8(bit_rot_jmp_table) + + ldi r31, pm_hi8(bit_rot_jmp_table) + add r30, r16 + adc r31, r1 + ijmp + + nop + nop + nop + nop + +rotate64_3byte_left: + mov r0, r25 + mov r25, r22 + mov r22, r19 + mov r19, r24 + + mov r24, r21 + mov r21, r18 + mov r18, r23 + mov r23, r20 + + mov r20, r0 + andi r16, 0x07 + ldi r30, pm_lo8(bit_rot_jmp_table) + ldi r31, pm_hi8(bit_rot_jmp_table) + + add r30, r16 + adc r31, r1 + ijmp + nop + +rotate64_4byte_left: + movw r0, r24 + movw r24, r20 + movw r20, r0 + movw r0, r22 + + movw r22, r18 + movw r18, r0 + clr r1 + andi r16, 0x07 + + ldi r30, pm_lo8(bit_rot_jmp_table) + ldi r31, pm_hi8(bit_rot_jmp_table) + add r30, r16 + adc r31, r1 + + ijmp + nop + nop + nop + +rotate64_5byte_left: + mov r0, r25 + mov r25, r20 + mov r20, r23 + mov r23, r18 + + mov r18, r21 + mov r21, r24 + mov r24, r19 + mov r19, r22 + + mov r22, r0 + andi r16, 0x07 + ldi r30, pm_lo8(bit_rot_jmp_table) + ldi r31, pm_hi8(bit_rot_jmp_table) + + add r30, r16 + adc r31, r1 + ijmp + nop + +rotate64_6byte_left: + movw r0, r18 + movw r18, r20 + movw r20, r22 + movw r22, r24 + + movw r24, r0 + clr r1 + andi r16, 0x07 + ldi r30, pm_lo8(bit_rot_jmp_table) + + ldi r31, pm_hi8(bit_rot_jmp_table) + add r30, r16 + adc r31, r1 + ijmp + + nop + nop + nop + nop + +rotate64_7byte_left: + mov r0, r18 + mov r18, r19 + mov r19, r20 + mov r20, r21 + + mov r21, r22 + mov r22, r23 + mov r23, r24 + mov r24, r25 + + mov r25, r0 + andi r16, 0x07 + ldi r30, pm_lo8(bit_rot_jmp_table) + ldi r31, pm_hi8(bit_rot_jmp_table) + + add r30, r16 + adc r31, r1 + ijmp + nop + + +bit_rot_jmp_table: + ret + rjmp rotate64_1bit_left + rjmp rotate64_2bit_left + rjmp rotate64_3bit_left + rjmp rotate64_4bit_left + rjmp rotate64_3bit_right + rjmp rotate64_2bit_right + rjmp rotate64_1bit_right + +.global rotate64left_code +rotate64left_code: + ldi r30, pm_lo8(rotate64_0byte_left) + ldi r31, pm_hi8(rotate64_0byte_left) + mov r0, r16 + andi r16, 0x70 + add r30, r16 + adc r31, r1 + mov r16, r0 + ijmp + \ No newline at end of file diff --git a/c_src/Keccak-avr8-settings.h b/c_src/Keccak-avr8-settings.h new file mode 100755 index 0000000..030e8eb --- /dev/null +++ b/c_src/Keccak-avr8-settings.h @@ -0,0 +1,2 @@ +#define cKeccakR 1088 +#define cKeccakFixedOutputLengthInBytes 32 diff --git a/c_src/KeccakF-1600-32-rvk.macros b/c_src/KeccakF-1600-32-rvk.macros new file mode 100755 index 0000000..c0c9029 --- /dev/null +++ b/c_src/KeccakF-1600-32-rvk.macros @@ -0,0 +1,555 @@ +/* +The Keccak sponge function, designed by Guido Bertoni, Joan Daemen, +Michaël Peeters and Gilles Van Assche. For more information, feedback or +questions, please refer to our website: http://keccak.noekeon.org/ + +Implementation by Ronny Van Keer, +hereby denoted as "the implementer". + +To the extent possible under law, the implementer has waived all copyright +and related or neighboring rights to the source code in this file. +http://creativecommons.org/publicdomain/zero/1.0/ +*/ + +static const UINT32 KeccakF1600RoundConstants_int2[2*24] = +{ + 0x00000001UL, 0x00000000UL, + 0x00000000UL, 0x00000089UL, + 0x00000000UL, 0x8000008bUL, + 0x00000000UL, 0x80008080UL, + 0x00000001UL, 0x0000008bUL, + 0x00000001UL, 0x00008000UL, + 0x00000001UL, 0x80008088UL, + 0x00000001UL, 0x80000082UL, + 0x00000000UL, 0x0000000bUL, + 0x00000000UL, 0x0000000aUL, + 0x00000001UL, 0x00008082UL, + 0x00000000UL, 0x00008003UL, + 0x00000001UL, 0x0000808bUL, + 0x00000001UL, 0x8000000bUL, + 0x00000001UL, 0x8000008aUL, + 0x00000001UL, 0x80000081UL, + 0x00000000UL, 0x80000081UL, + 0x00000000UL, 0x80000008UL, + 0x00000000UL, 0x00000083UL, + 0x00000000UL, 0x80008003UL, + 0x00000001UL, 0x80008088UL, + 0x00000000UL, 0x80000088UL, + 0x00000001UL, 0x00008000UL, + 0x00000000UL, 0x80008082UL +}; + +#undef rounds + +#define rounds \ +{ \ + UINT32 Da0, De0, Di0, Do0, Du0; \ + UINT32 Da1, De1, Di1, Do1, Du1; \ + UINT32 Ba, Be, Bi, Bo, Bu; \ + UINT32 Aba0, Abe0, Abi0, Abo0, Abu0; \ + UINT32 Aba1, Abe1, Abi1, Abo1, Abu1; \ + UINT32 Aga0, Age0, Agi0, Ago0, Agu0; \ + UINT32 Aga1, Age1, Agi1, Ago1, Agu1; \ + UINT32 Aka0, Ake0, Aki0, Ako0, Aku0; \ + UINT32 Aka1, Ake1, Aki1, Ako1, Aku1; \ + UINT32 Ama0, Ame0, Ami0, Amo0, Amu0; \ + UINT32 Ama1, Ame1, Ami1, Amo1, Amu1; \ + UINT32 Asa0, Ase0, Asi0, Aso0, Asu0; \ + UINT32 Asa1, Ase1, Asi1, Aso1, Asu1; \ + UINT32 Cw, Cx, Cy, Cz; \ + UINT32 Eba0, Ebe0, Ebi0, Ebo0, Ebu0; \ + UINT32 Eba1, Ebe1, Ebi1, Ebo1, Ebu1; \ + UINT32 Ega0, Ege0, Egi0, Ego0, Egu0; \ + UINT32 Ega1, Ege1, Egi1, Ego1, Egu1; \ + UINT32 Eka0, Eke0, Eki0, Eko0, Eku0; \ + UINT32 Eka1, Eke1, Eki1, Eko1, Eku1; \ + UINT32 Ema0, Eme0, Emi0, Emo0, Emu0; \ + UINT32 Ema1, Eme1, Emi1, Emo1, Emu1; \ + UINT32 Esa0, Ese0, Esi0, Eso0, Esu0; \ + UINT32 Esa1, Ese1, Esi1, Eso1, Esu1; \ + const UINT32 * pRoundConstants = KeccakF1600RoundConstants_int2; \ + UINT32 i; \ +\ + copyFromState(A, state) \ +\ + for( i = 12; i != 0; --i ) { \ + Cx = Abu0^Agu0^Aku0^Amu0^Asu0; \ + Du1 = Abe1^Age1^Ake1^Ame1^Ase1; \ + Da0 = Cx^ROL32(Du1, 1); \ + Cz = Abu1^Agu1^Aku1^Amu1^Asu1; \ + Du0 = Abe0^Age0^Ake0^Ame0^Ase0; \ + Da1 = Cz^Du0; \ +\ + Cw = Abi0^Agi0^Aki0^Ami0^Asi0; \ + Do0 = Cw^ROL32(Cz, 1); \ + Cy = Abi1^Agi1^Aki1^Ami1^Asi1; \ + Do1 = Cy^Cx; \ +\ + Cx = Aba0^Aga0^Aka0^Ama0^Asa0; \ + De0 = Cx^ROL32(Cy, 1); \ + Cz = Aba1^Aga1^Aka1^Ama1^Asa1; \ + De1 = Cz^Cw; \ +\ + Cy = Abo1^Ago1^Ako1^Amo1^Aso1; \ + Di0 = Du0^ROL32(Cy, 1); \ + Cw = Abo0^Ago0^Ako0^Amo0^Aso0; \ + Di1 = Du1^Cw; \ +\ + Du0 = Cw^ROL32(Cz, 1); \ + Du1 = Cy^Cx; \ +\ + Aba0 ^= Da0; \ + Ba = Aba0; \ + Age0 ^= De0; \ + Be = ROL32(Age0, 22); \ + Aki1 ^= Di1; \ + Bi = ROL32(Aki1, 22); \ + Amo1 ^= Do1; \ + Bo = ROL32(Amo1, 11); \ + Asu0 ^= Du0; \ + Bu = ROL32(Asu0, 7); \ + Eba0 = Ba ^((~Be)& Bi ) ^ *(pRoundConstants++); \ + Ebe0 = Be ^((~Bi)& Bo ); \ + Ebi0 = Bi ^((~Bo)& Bu ); \ + Ebo0 = Bo ^((~Bu)& Ba ); \ + Ebu0 = Bu ^((~Ba)& Be ); \ +\ + Abo0 ^= Do0; \ + Ba = ROL32(Abo0, 14); \ + Agu0 ^= Du0; \ + Be = ROL32(Agu0, 10); \ + Aka1 ^= Da1; \ + Bi = ROL32(Aka1, 2); \ + Ame1 ^= De1; \ + Bo = ROL32(Ame1, 23); \ + Asi1 ^= Di1; \ + Bu = ROL32(Asi1, 31); \ + Ega0 = Ba ^((~Be)& Bi ); \ + Ege0 = Be ^((~Bi)& Bo ); \ + Egi0 = Bi ^((~Bo)& Bu ); \ + Ego0 = Bo ^((~Bu)& Ba ); \ + Egu0 = Bu ^((~Ba)& Be ); \ +\ + Abe1 ^= De1; \ + Ba = ROL32(Abe1, 1); \ + Agi0 ^= Di0; \ + Be = ROL32(Agi0, 3); \ + Ako1 ^= Do1; \ + Bi = ROL32(Ako1, 13); \ + Amu0 ^= Du0; \ + Bo = ROL32(Amu0, 4); \ + Asa0 ^= Da0; \ + Bu = ROL32(Asa0, 9); \ + Eka0 = Ba ^((~Be)& Bi ); \ + Eke0 = Be ^((~Bi)& Bo ); \ + Eki0 = Bi ^((~Bo)& Bu ); \ + Eko0 = Bo ^((~Bu)& Ba ); \ + Eku0 = Bu ^((~Ba)& Be ); \ +\ + Abu1 ^= Du1; \ + Ba = ROL32(Abu1, 14); \ + Aga0 ^= Da0; \ + Be = ROL32(Aga0, 18); \ + Ake0 ^= De0; \ + Bi = ROL32(Ake0, 5); \ + Ami1 ^= Di1; \ + Bo = ROL32(Ami1, 8); \ + Aso0 ^= Do0; \ + Bu = ROL32(Aso0, 28); \ + Ema0 = Ba ^((~Be)& Bi ); \ + Eme0 = Be ^((~Bi)& Bo ); \ + Emi0 = Bi ^((~Bo)& Bu ); \ + Emo0 = Bo ^((~Bu)& Ba ); \ + Emu0 = Bu ^((~Ba)& Be ); \ +\ + Abi0 ^= Di0; \ + Ba = ROL32(Abi0, 31); \ + Ago1 ^= Do1; \ + Be = ROL32(Ago1, 28); \ + Aku1 ^= Du1; \ + Bi = ROL32(Aku1, 20); \ + Ama1 ^= Da1; \ + Bo = ROL32(Ama1, 21); \ + Ase0 ^= De0; \ + Bu = ROL32(Ase0, 1); \ + Esa0 = Ba ^((~Be)& Bi ); \ + Ese0 = Be ^((~Bi)& Bo ); \ + Esi0 = Bi ^((~Bo)& Bu ); \ + Eso0 = Bo ^((~Bu)& Ba ); \ + Esu0 = Bu ^((~Ba)& Be ); \ +\ + Aba1 ^= Da1; \ + Ba = Aba1; \ + Age1 ^= De1; \ + Be = ROL32(Age1, 22); \ + Aki0 ^= Di0; \ + Bi = ROL32(Aki0, 21); \ + Amo0 ^= Do0; \ + Bo = ROL32(Amo0, 10); \ + Asu1 ^= Du1; \ + Bu = ROL32(Asu1, 7); \ + Eba1 = Ba ^((~Be)& Bi ); \ + Eba1 ^= *(pRoundConstants++); \ + Ebe1 = Be ^((~Bi)& Bo ); \ + Ebi1 = Bi ^((~Bo)& Bu ); \ + Ebo1 = Bo ^((~Bu)& Ba ); \ + Ebu1 = Bu ^((~Ba)& Be ); \ +\ + Abo1 ^= Do1; \ + Ba = ROL32(Abo1, 14); \ + Agu1 ^= Du1; \ + Be = ROL32(Agu1, 10); \ + Aka0 ^= Da0; \ + Bi = ROL32(Aka0, 1); \ + Ame0 ^= De0; \ + Bo = ROL32(Ame0, 22); \ + Asi0 ^= Di0; \ + Bu = ROL32(Asi0, 30); \ + Ega1 = Ba ^((~Be)& Bi ); \ + Ege1 = Be ^((~Bi)& Bo ); \ + Egi1 = Bi ^((~Bo)& Bu ); \ + Ego1 = Bo ^((~Bu)& Ba ); \ + Egu1 = Bu ^((~Ba)& Be ); \ +\ + Abe0 ^= De0; \ + Ba = Abe0; \ + Agi1 ^= Di1; \ + Be = ROL32(Agi1, 3); \ + Ako0 ^= Do0; \ + Bi = ROL32(Ako0, 12); \ + Amu1 ^= Du1; \ + Bo = ROL32(Amu1, 4); \ + Asa1 ^= Da1; \ + Bu = ROL32(Asa1, 9); \ + Eka1 = Ba ^((~Be)& Bi ); \ + Eke1 = Be ^((~Bi)& Bo ); \ + Eki1 = Bi ^((~Bo)& Bu ); \ + Eko1 = Bo ^((~Bu)& Ba ); \ + Eku1 = Bu ^((~Ba)& Be ); \ +\ + Abu0 ^= Du0; \ + Ba = ROL32(Abu0, 13); \ + Aga1 ^= Da1; \ + Be = ROL32(Aga1, 18); \ + Ake1 ^= De1; \ + Bi = ROL32(Ake1, 5); \ + Ami0 ^= Di0; \ + Bo = ROL32(Ami0, 7); \ + Aso1 ^= Do1; \ + Bu = ROL32(Aso1, 28); \ + Ema1 = Ba ^((~Be)& Bi ); \ + Eme1 = Be ^((~Bi)& Bo ); \ + Emi1 = Bi ^((~Bo)& Bu ); \ + Emo1 = Bo ^((~Bu)& Ba ); \ + Emu1 = Bu ^((~Ba)& Be ); \ +\ + Abi1 ^= Di1; \ + Ba = ROL32(Abi1, 31); \ + Ago0 ^= Do0; \ + Be = ROL32(Ago0, 27); \ + Aku0 ^= Du0; \ + Bi = ROL32(Aku0, 19); \ + Ama0 ^= Da0; \ + Bo = ROL32(Ama0, 20); \ + Ase1 ^= De1; \ + Bu = ROL32(Ase1, 1); \ + Esa1 = Ba ^((~Be)& Bi ); \ + Ese1 = Be ^((~Bi)& Bo ); \ + Esi1 = Bi ^((~Bo)& Bu ); \ + Eso1 = Bo ^((~Bu)& Ba ); \ + Esu1 = Bu ^((~Ba)& Be ); \ +\ + Cx = Ebu0^Egu0^Eku0^Emu0^Esu0; \ + Du1 = Ebe1^Ege1^Eke1^Eme1^Ese1; \ + Da0 = Cx^ROL32(Du1, 1); \ + Cz = Ebu1^Egu1^Eku1^Emu1^Esu1; \ + Du0 = Ebe0^Ege0^Eke0^Eme0^Ese0; \ + Da1 = Cz^Du0; \ +\ + Cw = Ebi0^Egi0^Eki0^Emi0^Esi0; \ + Do0 = Cw^ROL32(Cz, 1); \ + Cy = Ebi1^Egi1^Eki1^Emi1^Esi1; \ + Do1 = Cy^Cx; \ +\ + Cx = Eba0^Ega0^Eka0^Ema0^Esa0; \ + De0 = Cx^ROL32(Cy, 1); \ + Cz = Eba1^Ega1^Eka1^Ema1^Esa1; \ + De1 = Cz^Cw; \ +\ + Cy = Ebo1^Ego1^Eko1^Emo1^Eso1; \ + Di0 = Du0^ROL32(Cy, 1); \ + Cw = Ebo0^Ego0^Eko0^Emo0^Eso0; \ + Di1 = Du1^Cw; \ +\ + Du0 = Cw^ROL32(Cz, 1); \ + Du1 = Cy^Cx; \ +\ + Eba0 ^= Da0; \ + Ba = Eba0; \ + Ege0 ^= De0; \ + Be = ROL32(Ege0, 22); \ + Eki1 ^= Di1; \ + Bi = ROL32(Eki1, 22); \ + Emo1 ^= Do1; \ + Bo = ROL32(Emo1, 11); \ + Esu0 ^= Du0; \ + Bu = ROL32(Esu0, 7); \ + Aba0 = Ba ^((~Be)& Bi ); \ + Aba0 ^= *(pRoundConstants++); \ + Abe0 = Be ^((~Bi)& Bo ); \ + Abi0 = Bi ^((~Bo)& Bu ); \ + Abo0 = Bo ^((~Bu)& Ba ); \ + Abu0 = Bu ^((~Ba)& Be ); \ +\ + Ebo0 ^= Do0; \ + Ba = ROL32(Ebo0, 14); \ + Egu0 ^= Du0; \ + Be = ROL32(Egu0, 10); \ + Eka1 ^= Da1; \ + Bi = ROL32(Eka1, 2); \ + Eme1 ^= De1; \ + Bo = ROL32(Eme1, 23); \ + Esi1 ^= Di1; \ + Bu = ROL32(Esi1, 31); \ + Aga0 = Ba ^((~Be)& Bi ); \ + Age0 = Be ^((~Bi)& Bo ); \ + Agi0 = Bi ^((~Bo)& Bu ); \ + Ago0 = Bo ^((~Bu)& Ba ); \ + Agu0 = Bu ^((~Ba)& Be ); \ +\ + Ebe1 ^= De1; \ + Ba = ROL32(Ebe1, 1); \ + Egi0 ^= Di0; \ + Be = ROL32(Egi0, 3); \ + Eko1 ^= Do1; \ + Bi = ROL32(Eko1, 13); \ + Emu0 ^= Du0; \ + Bo = ROL32(Emu0, 4); \ + Esa0 ^= Da0; \ + Bu = ROL32(Esa0, 9); \ + Aka0 = Ba ^((~Be)& Bi ); \ + Ake0 = Be ^((~Bi)& Bo ); \ + Aki0 = Bi ^((~Bo)& Bu ); \ + Ako0 = Bo ^((~Bu)& Ba ); \ + Aku0 = Bu ^((~Ba)& Be ); \ +\ + Ebu1 ^= Du1; \ + Ba = ROL32(Ebu1, 14); \ + Ega0 ^= Da0; \ + Be = ROL32(Ega0, 18); \ + Eke0 ^= De0; \ + Bi = ROL32(Eke0, 5); \ + Emi1 ^= Di1; \ + Bo = ROL32(Emi1, 8); \ + Eso0 ^= Do0; \ + Bu = ROL32(Eso0, 28); \ + Ama0 = Ba ^((~Be)& Bi ); \ + Ame0 = Be ^((~Bi)& Bo ); \ + Ami0 = Bi ^((~Bo)& Bu ); \ + Amo0 = Bo ^((~Bu)& Ba ); \ + Amu0 = Bu ^((~Ba)& Be ); \ +\ + Ebi0 ^= Di0; \ + Ba = ROL32(Ebi0, 31); \ + Ego1 ^= Do1; \ + Be = ROL32(Ego1, 28); \ + Eku1 ^= Du1; \ + Bi = ROL32(Eku1, 20); \ + Ema1 ^= Da1; \ + Bo = ROL32(Ema1, 21); \ + Ese0 ^= De0; \ + Bu = ROL32(Ese0, 1); \ + Asa0 = Ba ^((~Be)& Bi ); \ + Ase0 = Be ^((~Bi)& Bo ); \ + Asi0 = Bi ^((~Bo)& Bu ); \ + Aso0 = Bo ^((~Bu)& Ba ); \ + Asu0 = Bu ^((~Ba)& Be ); \ +\ + Eba1 ^= Da1; \ + Ba = Eba1; \ + Ege1 ^= De1; \ + Be = ROL32(Ege1, 22); \ + Eki0 ^= Di0; \ + Bi = ROL32(Eki0, 21); \ + Emo0 ^= Do0; \ + Bo = ROL32(Emo0, 10); \ + Esu1 ^= Du1; \ + Bu = ROL32(Esu1, 7); \ + Aba1 = Ba ^((~Be)& Bi ); \ + Aba1 ^= *(pRoundConstants++); \ + Abe1 = Be ^((~Bi)& Bo ); \ + Abi1 = Bi ^((~Bo)& Bu ); \ + Abo1 = Bo ^((~Bu)& Ba ); \ + Abu1 = Bu ^((~Ba)& Be ); \ +\ + Ebo1 ^= Do1; \ + Ba = ROL32(Ebo1, 14); \ + Egu1 ^= Du1; \ + Be = ROL32(Egu1, 10); \ + Eka0 ^= Da0; \ + Bi = ROL32(Eka0, 1); \ + Eme0 ^= De0; \ + Bo = ROL32(Eme0, 22); \ + Esi0 ^= Di0; \ + Bu = ROL32(Esi0, 30); \ + Aga1 = Ba ^((~Be)& Bi ); \ + Age1 = Be ^((~Bi)& Bo ); \ + Agi1 = Bi ^((~Bo)& Bu ); \ + Ago1 = Bo ^((~Bu)& Ba ); \ + Agu1 = Bu ^((~Ba)& Be ); \ +\ + Ebe0 ^= De0; \ + Ba = Ebe0; \ + Egi1 ^= Di1; \ + Be = ROL32(Egi1, 3); \ + Eko0 ^= Do0; \ + Bi = ROL32(Eko0, 12); \ + Emu1 ^= Du1; \ + Bo = ROL32(Emu1, 4); \ + Esa1 ^= Da1; \ + Bu = ROL32(Esa1, 9); \ + Aka1 = Ba ^((~Be)& Bi ); \ + Ake1 = Be ^((~Bi)& Bo ); \ + Aki1 = Bi ^((~Bo)& Bu ); \ + Ako1 = Bo ^((~Bu)& Ba ); \ + Aku1 = Bu ^((~Ba)& Be ); \ +\ + Ebu0 ^= Du0; \ + Ba = ROL32(Ebu0, 13); \ + Ega1 ^= Da1; \ + Be = ROL32(Ega1, 18); \ + Eke1 ^= De1; \ + Bi = ROL32(Eke1, 5); \ + Emi0 ^= Di0; \ + Bo = ROL32(Emi0, 7); \ + Eso1 ^= Do1; \ + Bu = ROL32(Eso1, 28); \ + Ama1 = Ba ^((~Be)& Bi ); \ + Ame1 = Be ^((~Bi)& Bo ); \ + Ami1 = Bi ^((~Bo)& Bu ); \ + Amo1 = Bo ^((~Bu)& Ba ); \ + Amu1 = Bu ^((~Ba)& Be ); \ +\ + Ebi1 ^= Di1; \ + Ba = ROL32(Ebi1, 31); \ + Ego0 ^= Do0; \ + Be = ROL32(Ego0, 27); \ + Eku0 ^= Du0; \ + Bi = ROL32(Eku0, 19); \ + Ema0 ^= Da0; \ + Bo = ROL32(Ema0, 20); \ + Ese1 ^= De1; \ + Bu = ROL32(Ese1, 1); \ + Asa1 = Ba ^((~Be)& Bi ); \ + Ase1 = Be ^((~Bi)& Bo ); \ + Asi1 = Bi ^((~Bo)& Bu ); \ + Aso1 = Bo ^((~Bu)& Ba ); \ + Asu1 = Bu ^((~Ba)& Be ); \ + } \ + copyToState(state, A) \ +} + +#define copyFromState(X, state) \ + X##ba0 = state[ 0]; \ + X##ba1 = state[ 1]; \ + X##be0 = state[ 2]; \ + X##be1 = state[ 3]; \ + X##bi0 = state[ 4]; \ + X##bi1 = state[ 5]; \ + X##bo0 = state[ 6]; \ + X##bo1 = state[ 7]; \ + X##bu0 = state[ 8]; \ + X##bu1 = state[ 9]; \ + X##ga0 = state[10]; \ + X##ga1 = state[11]; \ + X##ge0 = state[12]; \ + X##ge1 = state[13]; \ + X##gi0 = state[14]; \ + X##gi1 = state[15]; \ + X##go0 = state[16]; \ + X##go1 = state[17]; \ + X##gu0 = state[18]; \ + X##gu1 = state[19]; \ + X##ka0 = state[20]; \ + X##ka1 = state[21]; \ + X##ke0 = state[22]; \ + X##ke1 = state[23]; \ + X##ki0 = state[24]; \ + X##ki1 = state[25]; \ + X##ko0 = state[26]; \ + X##ko1 = state[27]; \ + X##ku0 = state[28]; \ + X##ku1 = state[29]; \ + X##ma0 = state[30]; \ + X##ma1 = state[31]; \ + X##me0 = state[32]; \ + X##me1 = state[33]; \ + X##mi0 = state[34]; \ + X##mi1 = state[35]; \ + X##mo0 = state[36]; \ + X##mo1 = state[37]; \ + X##mu0 = state[38]; \ + X##mu1 = state[39]; \ + X##sa0 = state[40]; \ + X##sa1 = state[41]; \ + X##se0 = state[42]; \ + X##se1 = state[43]; \ + X##si0 = state[44]; \ + X##si1 = state[45]; \ + X##so0 = state[46]; \ + X##so1 = state[47]; \ + X##su0 = state[48]; \ + X##su1 = state[49]; \ + +#define copyToState(state, X) \ + state[ 0] = X##ba0; \ + state[ 1] = X##ba1; \ + state[ 2] = X##be0; \ + state[ 3] = X##be1; \ + state[ 4] = X##bi0; \ + state[ 5] = X##bi1; \ + state[ 6] = X##bo0; \ + state[ 7] = X##bo1; \ + state[ 8] = X##bu0; \ + state[ 9] = X##bu1; \ + state[10] = X##ga0; \ + state[11] = X##ga1; \ + state[12] = X##ge0; \ + state[13] = X##ge1; \ + state[14] = X##gi0; \ + state[15] = X##gi1; \ + state[16] = X##go0; \ + state[17] = X##go1; \ + state[18] = X##gu0; \ + state[19] = X##gu1; \ + state[20] = X##ka0; \ + state[21] = X##ka1; \ + state[22] = X##ke0; \ + state[23] = X##ke1; \ + state[24] = X##ki0; \ + state[25] = X##ki1; \ + state[26] = X##ko0; \ + state[27] = X##ko1; \ + state[28] = X##ku0; \ + state[29] = X##ku1; \ + state[30] = X##ma0; \ + state[31] = X##ma1; \ + state[32] = X##me0; \ + state[33] = X##me1; \ + state[34] = X##mi0; \ + state[35] = X##mi1; \ + state[36] = X##mo0; \ + state[37] = X##mo1; \ + state[38] = X##mu0; \ + state[39] = X##mu1; \ + state[40] = X##sa0; \ + state[41] = X##sa1; \ + state[42] = X##se0; \ + state[43] = X##se1; \ + state[44] = X##si0; \ + state[45] = X##si1; \ + state[46] = X##so0; \ + state[47] = X##so1; \ + state[48] = X##su0; \ + state[49] = X##su1; \ + diff --git a/c_src/KeccakF-1600-32-s1.macros b/c_src/KeccakF-1600-32-s1.macros new file mode 100755 index 0000000..973cc19 --- /dev/null +++ b/c_src/KeccakF-1600-32-s1.macros @@ -0,0 +1,1187 @@ +/* +Code automatically generated by KeccakTools! + +The Keccak sponge function, designed by Guido Bertoni, Joan Daemen, +Michaël Peeters and Gilles Van Assche. For more information, feedback or +questions, please refer to our website: http://keccak.noekeon.org/ + +Implementation by the designers, +hereby denoted as "the implementer". + +To the extent possible under law, the implementer has waived all copyright +and related or neighboring rights to the source code in this file. +http://creativecommons.org/publicdomain/zero/1.0/ +*/ + +#define declareABCDE \ + UINT32 Aba0, Abe0, Abi0, Abo0, Abu0; \ + UINT32 Aba1, Abe1, Abi1, Abo1, Abu1; \ + UINT32 Aga0, Age0, Agi0, Ago0, Agu0; \ + UINT32 Aga1, Age1, Agi1, Ago1, Agu1; \ + UINT32 Aka0, Ake0, Aki0, Ako0, Aku0; \ + UINT32 Aka1, Ake1, Aki1, Ako1, Aku1; \ + UINT32 Ama0, Ame0, Ami0, Amo0, Amu0; \ + UINT32 Ama1, Ame1, Ami1, Amo1, Amu1; \ + UINT32 Asa0, Ase0, Asi0, Aso0, Asu0; \ + UINT32 Asa1, Ase1, Asi1, Aso1, Asu1; \ + UINT32 Bba0, Bbe0, Bbi0, Bbo0, Bbu0; \ + UINT32 Bba1, Bbe1, Bbi1, Bbo1, Bbu1; \ + UINT32 Bga0, Bge0, Bgi0, Bgo0, Bgu0; \ + UINT32 Bga1, Bge1, Bgi1, Bgo1, Bgu1; \ + UINT32 Bka0, Bke0, Bki0, Bko0, Bku0; \ + UINT32 Bka1, Bke1, Bki1, Bko1, Bku1; \ + UINT32 Bma0, Bme0, Bmi0, Bmo0, Bmu0; \ + UINT32 Bma1, Bme1, Bmi1, Bmo1, Bmu1; \ + UINT32 Bsa0, Bse0, Bsi0, Bso0, Bsu0; \ + UINT32 Bsa1, Bse1, Bsi1, Bso1, Bsu1; \ + UINT32 Ca0, Ce0, Ci0, Co0, Cu0; \ + UINT32 Ca1, Ce1, Ci1, Co1, Cu1; \ + UINT32 Da0, De0, Di0, Do0, Du0; \ + UINT32 Da1, De1, Di1, Do1, Du1; \ + UINT32 Eba0, Ebe0, Ebi0, Ebo0, Ebu0; \ + UINT32 Eba1, Ebe1, Ebi1, Ebo1, Ebu1; \ + UINT32 Ega0, Ege0, Egi0, Ego0, Egu0; \ + UINT32 Ega1, Ege1, Egi1, Ego1, Egu1; \ + UINT32 Eka0, Eke0, Eki0, Eko0, Eku0; \ + UINT32 Eka1, Eke1, Eki1, Eko1, Eku1; \ + UINT32 Ema0, Eme0, Emi0, Emo0, Emu0; \ + UINT32 Ema1, Eme1, Emi1, Emo1, Emu1; \ + UINT32 Esa0, Ese0, Esi0, Eso0, Esu0; \ + UINT32 Esa1, Ese1, Esi1, Eso1, Esu1; \ + +#define prepareTheta \ + Ca0 = Aba0^Aga0^Aka0^Ama0^Asa0; \ + Ca1 = Aba1^Aga1^Aka1^Ama1^Asa1; \ + Ce0 = Abe0^Age0^Ake0^Ame0^Ase0; \ + Ce1 = Abe1^Age1^Ake1^Ame1^Ase1; \ + Ci0 = Abi0^Agi0^Aki0^Ami0^Asi0; \ + Ci1 = Abi1^Agi1^Aki1^Ami1^Asi1; \ + Co0 = Abo0^Ago0^Ako0^Amo0^Aso0; \ + Co1 = Abo1^Ago1^Ako1^Amo1^Aso1; \ + Cu0 = Abu0^Agu0^Aku0^Amu0^Asu0; \ + Cu1 = Abu1^Agu1^Aku1^Amu1^Asu1; \ + +#ifdef UseBebigokimisa +// --- Code for round, with prepare-theta (lane complementing pattern 'bebigokimisa') +// --- using factor 2 interleaving, 64-bit lanes mapped to 32-bit words +#define thetaRhoPiChiIotaPrepareTheta(i, A, E) \ + Da0 = Cu0^ROL32(Ce1, 1); \ + Da1 = Cu1^Ce0; \ + De0 = Ca0^ROL32(Ci1, 1); \ + De1 = Ca1^Ci0; \ + Di0 = Ce0^ROL32(Co1, 1); \ + Di1 = Ce1^Co0; \ + Do0 = Ci0^ROL32(Cu1, 1); \ + Do1 = Ci1^Cu0; \ + Du0 = Co0^ROL32(Ca1, 1); \ + Du1 = Co1^Ca0; \ +\ + A##ba0 ^= Da0; \ + Bba0 = A##ba0; \ + A##ge0 ^= De0; \ + Bbe0 = ROL32(A##ge0, 22); \ + A##ki1 ^= Di1; \ + Bbi0 = ROL32(A##ki1, 22); \ + A##mo1 ^= Do1; \ + Bbo0 = ROL32(A##mo1, 11); \ + A##su0 ^= Du0; \ + Bbu0 = ROL32(A##su0, 7); \ + E##ba0 = Bba0 ^( Bbe0 | Bbi0 ); \ + E##ba0 ^= KeccakF1600RoundConstants_int2_0[i]; \ + Ca0 = E##ba0; \ + E##be0 = Bbe0 ^((~Bbi0)| Bbo0 ); \ + Ce0 = E##be0; \ + E##bi0 = Bbi0 ^( Bbo0 & Bbu0 ); \ + Ci0 = E##bi0; \ + E##bo0 = Bbo0 ^( Bbu0 | Bba0 ); \ + Co0 = E##bo0; \ + E##bu0 = Bbu0 ^( Bba0 & Bbe0 ); \ + Cu0 = E##bu0; \ +\ + A##ba1 ^= Da1; \ + Bba1 = A##ba1; \ + A##ge1 ^= De1; \ + Bbe1 = ROL32(A##ge1, 22); \ + A##ki0 ^= Di0; \ + Bbi1 = ROL32(A##ki0, 21); \ + A##mo0 ^= Do0; \ + Bbo1 = ROL32(A##mo0, 10); \ + A##su1 ^= Du1; \ + Bbu1 = ROL32(A##su1, 7); \ + E##ba1 = Bba1 ^( Bbe1 | Bbi1 ); \ + E##ba1 ^= KeccakF1600RoundConstants_int2_1[i]; \ + Ca1 = E##ba1; \ + E##be1 = Bbe1 ^((~Bbi1)| Bbo1 ); \ + Ce1 = E##be1; \ + E##bi1 = Bbi1 ^( Bbo1 & Bbu1 ); \ + Ci1 = E##bi1; \ + E##bo1 = Bbo1 ^( Bbu1 | Bba1 ); \ + Co1 = E##bo1; \ + E##bu1 = Bbu1 ^( Bba1 & Bbe1 ); \ + Cu1 = E##bu1; \ +\ + A##bo0 ^= Do0; \ + Bga0 = ROL32(A##bo0, 14); \ + A##gu0 ^= Du0; \ + Bge0 = ROL32(A##gu0, 10); \ + A##ka1 ^= Da1; \ + Bgi0 = ROL32(A##ka1, 2); \ + A##me1 ^= De1; \ + Bgo0 = ROL32(A##me1, 23); \ + A##si1 ^= Di1; \ + Bgu0 = ROL32(A##si1, 31); \ + E##ga0 = Bga0 ^( Bge0 | Bgi0 ); \ + Ca0 ^= E##ga0; \ + E##ge0 = Bge0 ^( Bgi0 & Bgo0 ); \ + Ce0 ^= E##ge0; \ + E##gi0 = Bgi0 ^( Bgo0 |(~Bgu0)); \ + Ci0 ^= E##gi0; \ + E##go0 = Bgo0 ^( Bgu0 | Bga0 ); \ + Co0 ^= E##go0; \ + E##gu0 = Bgu0 ^( Bga0 & Bge0 ); \ + Cu0 ^= E##gu0; \ +\ + A##bo1 ^= Do1; \ + Bga1 = ROL32(A##bo1, 14); \ + A##gu1 ^= Du1; \ + Bge1 = ROL32(A##gu1, 10); \ + A##ka0 ^= Da0; \ + Bgi1 = ROL32(A##ka0, 1); \ + A##me0 ^= De0; \ + Bgo1 = ROL32(A##me0, 22); \ + A##si0 ^= Di0; \ + Bgu1 = ROL32(A##si0, 30); \ + E##ga1 = Bga1 ^( Bge1 | Bgi1 ); \ + Ca1 ^= E##ga1; \ + E##ge1 = Bge1 ^( Bgi1 & Bgo1 ); \ + Ce1 ^= E##ge1; \ + E##gi1 = Bgi1 ^( Bgo1 |(~Bgu1)); \ + Ci1 ^= E##gi1; \ + E##go1 = Bgo1 ^( Bgu1 | Bga1 ); \ + Co1 ^= E##go1; \ + E##gu1 = Bgu1 ^( Bga1 & Bge1 ); \ + Cu1 ^= E##gu1; \ +\ + A##be1 ^= De1; \ + Bka0 = ROL32(A##be1, 1); \ + A##gi0 ^= Di0; \ + Bke0 = ROL32(A##gi0, 3); \ + A##ko1 ^= Do1; \ + Bki0 = ROL32(A##ko1, 13); \ + A##mu0 ^= Du0; \ + Bko0 = ROL32(A##mu0, 4); \ + A##sa0 ^= Da0; \ + Bku0 = ROL32(A##sa0, 9); \ + E##ka0 = Bka0 ^( Bke0 | Bki0 ); \ + Ca0 ^= E##ka0; \ + E##ke0 = Bke0 ^( Bki0 & Bko0 ); \ + Ce0 ^= E##ke0; \ + E##ki0 = Bki0 ^((~Bko0)& Bku0 ); \ + Ci0 ^= E##ki0; \ + E##ko0 = (~Bko0)^( Bku0 | Bka0 ); \ + Co0 ^= E##ko0; \ + E##ku0 = Bku0 ^( Bka0 & Bke0 ); \ + Cu0 ^= E##ku0; \ +\ + A##be0 ^= De0; \ + Bka1 = A##be0; \ + A##gi1 ^= Di1; \ + Bke1 = ROL32(A##gi1, 3); \ + A##ko0 ^= Do0; \ + Bki1 = ROL32(A##ko0, 12); \ + A##mu1 ^= Du1; \ + Bko1 = ROL32(A##mu1, 4); \ + A##sa1 ^= Da1; \ + Bku1 = ROL32(A##sa1, 9); \ + E##ka1 = Bka1 ^( Bke1 | Bki1 ); \ + Ca1 ^= E##ka1; \ + E##ke1 = Bke1 ^( Bki1 & Bko1 ); \ + Ce1 ^= E##ke1; \ + E##ki1 = Bki1 ^((~Bko1)& Bku1 ); \ + Ci1 ^= E##ki1; \ + E##ko1 = (~Bko1)^( Bku1 | Bka1 ); \ + Co1 ^= E##ko1; \ + E##ku1 = Bku1 ^( Bka1 & Bke1 ); \ + Cu1 ^= E##ku1; \ +\ + A##bu1 ^= Du1; \ + Bma0 = ROL32(A##bu1, 14); \ + A##ga0 ^= Da0; \ + Bme0 = ROL32(A##ga0, 18); \ + A##ke0 ^= De0; \ + Bmi0 = ROL32(A##ke0, 5); \ + A##mi1 ^= Di1; \ + Bmo0 = ROL32(A##mi1, 8); \ + A##so0 ^= Do0; \ + Bmu0 = ROL32(A##so0, 28); \ + E##ma0 = Bma0 ^( Bme0 & Bmi0 ); \ + Ca0 ^= E##ma0; \ + E##me0 = Bme0 ^( Bmi0 | Bmo0 ); \ + Ce0 ^= E##me0; \ + E##mi0 = Bmi0 ^((~Bmo0)| Bmu0 ); \ + Ci0 ^= E##mi0; \ + E##mo0 = (~Bmo0)^( Bmu0 & Bma0 ); \ + Co0 ^= E##mo0; \ + E##mu0 = Bmu0 ^( Bma0 | Bme0 ); \ + Cu0 ^= E##mu0; \ +\ + A##bu0 ^= Du0; \ + Bma1 = ROL32(A##bu0, 13); \ + A##ga1 ^= Da1; \ + Bme1 = ROL32(A##ga1, 18); \ + A##ke1 ^= De1; \ + Bmi1 = ROL32(A##ke1, 5); \ + A##mi0 ^= Di0; \ + Bmo1 = ROL32(A##mi0, 7); \ + A##so1 ^= Do1; \ + Bmu1 = ROL32(A##so1, 28); \ + E##ma1 = Bma1 ^( Bme1 & Bmi1 ); \ + Ca1 ^= E##ma1; \ + E##me1 = Bme1 ^( Bmi1 | Bmo1 ); \ + Ce1 ^= E##me1; \ + E##mi1 = Bmi1 ^((~Bmo1)| Bmu1 ); \ + Ci1 ^= E##mi1; \ + E##mo1 = (~Bmo1)^( Bmu1 & Bma1 ); \ + Co1 ^= E##mo1; \ + E##mu1 = Bmu1 ^( Bma1 | Bme1 ); \ + Cu1 ^= E##mu1; \ +\ + A##bi0 ^= Di0; \ + Bsa0 = ROL32(A##bi0, 31); \ + A##go1 ^= Do1; \ + Bse0 = ROL32(A##go1, 28); \ + A##ku1 ^= Du1; \ + Bsi0 = ROL32(A##ku1, 20); \ + A##ma1 ^= Da1; \ + Bso0 = ROL32(A##ma1, 21); \ + A##se0 ^= De0; \ + Bsu0 = ROL32(A##se0, 1); \ + E##sa0 = Bsa0 ^((~Bse0)& Bsi0 ); \ + Ca0 ^= E##sa0; \ + E##se0 = (~Bse0)^( Bsi0 | Bso0 ); \ + Ce0 ^= E##se0; \ + E##si0 = Bsi0 ^( Bso0 & Bsu0 ); \ + Ci0 ^= E##si0; \ + E##so0 = Bso0 ^( Bsu0 | Bsa0 ); \ + Co0 ^= E##so0; \ + E##su0 = Bsu0 ^( Bsa0 & Bse0 ); \ + Cu0 ^= E##su0; \ +\ + A##bi1 ^= Di1; \ + Bsa1 = ROL32(A##bi1, 31); \ + A##go0 ^= Do0; \ + Bse1 = ROL32(A##go0, 27); \ + A##ku0 ^= Du0; \ + Bsi1 = ROL32(A##ku0, 19); \ + A##ma0 ^= Da0; \ + Bso1 = ROL32(A##ma0, 20); \ + A##se1 ^= De1; \ + Bsu1 = ROL32(A##se1, 1); \ + E##sa1 = Bsa1 ^((~Bse1)& Bsi1 ); \ + Ca1 ^= E##sa1; \ + E##se1 = (~Bse1)^( Bsi1 | Bso1 ); \ + Ce1 ^= E##se1; \ + E##si1 = Bsi1 ^( Bso1 & Bsu1 ); \ + Ci1 ^= E##si1; \ + E##so1 = Bso1 ^( Bsu1 | Bsa1 ); \ + Co1 ^= E##so1; \ + E##su1 = Bsu1 ^( Bsa1 & Bse1 ); \ + Cu1 ^= E##su1; \ +\ + +// --- Code for round (lane complementing pattern 'bebigokimisa') +// --- using factor 2 interleaving, 64-bit lanes mapped to 32-bit words +#define thetaRhoPiChiIota(i, A, E) \ + Da0 = Cu0^ROL32(Ce1, 1); \ + Da1 = Cu1^Ce0; \ + De0 = Ca0^ROL32(Ci1, 1); \ + De1 = Ca1^Ci0; \ + Di0 = Ce0^ROL32(Co1, 1); \ + Di1 = Ce1^Co0; \ + Do0 = Ci0^ROL32(Cu1, 1); \ + Do1 = Ci1^Cu0; \ + Du0 = Co0^ROL32(Ca1, 1); \ + Du1 = Co1^Ca0; \ +\ + A##ba0 ^= Da0; \ + Bba0 = A##ba0; \ + A##ge0 ^= De0; \ + Bbe0 = ROL32(A##ge0, 22); \ + A##ki1 ^= Di1; \ + Bbi0 = ROL32(A##ki1, 22); \ + A##mo1 ^= Do1; \ + Bbo0 = ROL32(A##mo1, 11); \ + A##su0 ^= Du0; \ + Bbu0 = ROL32(A##su0, 7); \ + E##ba0 = Bba0 ^( Bbe0 | Bbi0 ); \ + E##ba0 ^= KeccakF1600RoundConstants_int2_0[i]; \ + E##be0 = Bbe0 ^((~Bbi0)| Bbo0 ); \ + E##bi0 = Bbi0 ^( Bbo0 & Bbu0 ); \ + E##bo0 = Bbo0 ^( Bbu0 | Bba0 ); \ + E##bu0 = Bbu0 ^( Bba0 & Bbe0 ); \ +\ + A##ba1 ^= Da1; \ + Bba1 = A##ba1; \ + A##ge1 ^= De1; \ + Bbe1 = ROL32(A##ge1, 22); \ + A##ki0 ^= Di0; \ + Bbi1 = ROL32(A##ki0, 21); \ + A##mo0 ^= Do0; \ + Bbo1 = ROL32(A##mo0, 10); \ + A##su1 ^= Du1; \ + Bbu1 = ROL32(A##su1, 7); \ + E##ba1 = Bba1 ^( Bbe1 | Bbi1 ); \ + E##ba1 ^= KeccakF1600RoundConstants_int2_1[i]; \ + E##be1 = Bbe1 ^((~Bbi1)| Bbo1 ); \ + E##bi1 = Bbi1 ^( Bbo1 & Bbu1 ); \ + E##bo1 = Bbo1 ^( Bbu1 | Bba1 ); \ + E##bu1 = Bbu1 ^( Bba1 & Bbe1 ); \ +\ + A##bo0 ^= Do0; \ + Bga0 = ROL32(A##bo0, 14); \ + A##gu0 ^= Du0; \ + Bge0 = ROL32(A##gu0, 10); \ + A##ka1 ^= Da1; \ + Bgi0 = ROL32(A##ka1, 2); \ + A##me1 ^= De1; \ + Bgo0 = ROL32(A##me1, 23); \ + A##si1 ^= Di1; \ + Bgu0 = ROL32(A##si1, 31); \ + E##ga0 = Bga0 ^( Bge0 | Bgi0 ); \ + E##ge0 = Bge0 ^( Bgi0 & Bgo0 ); \ + E##gi0 = Bgi0 ^( Bgo0 |(~Bgu0)); \ + E##go0 = Bgo0 ^( Bgu0 | Bga0 ); \ + E##gu0 = Bgu0 ^( Bga0 & Bge0 ); \ +\ + A##bo1 ^= Do1; \ + Bga1 = ROL32(A##bo1, 14); \ + A##gu1 ^= Du1; \ + Bge1 = ROL32(A##gu1, 10); \ + A##ka0 ^= Da0; \ + Bgi1 = ROL32(A##ka0, 1); \ + A##me0 ^= De0; \ + Bgo1 = ROL32(A##me0, 22); \ + A##si0 ^= Di0; \ + Bgu1 = ROL32(A##si0, 30); \ + E##ga1 = Bga1 ^( Bge1 | Bgi1 ); \ + E##ge1 = Bge1 ^( Bgi1 & Bgo1 ); \ + E##gi1 = Bgi1 ^( Bgo1 |(~Bgu1)); \ + E##go1 = Bgo1 ^( Bgu1 | Bga1 ); \ + E##gu1 = Bgu1 ^( Bga1 & Bge1 ); \ +\ + A##be1 ^= De1; \ + Bka0 = ROL32(A##be1, 1); \ + A##gi0 ^= Di0; \ + Bke0 = ROL32(A##gi0, 3); \ + A##ko1 ^= Do1; \ + Bki0 = ROL32(A##ko1, 13); \ + A##mu0 ^= Du0; \ + Bko0 = ROL32(A##mu0, 4); \ + A##sa0 ^= Da0; \ + Bku0 = ROL32(A##sa0, 9); \ + E##ka0 = Bka0 ^( Bke0 | Bki0 ); \ + E##ke0 = Bke0 ^( Bki0 & Bko0 ); \ + E##ki0 = Bki0 ^((~Bko0)& Bku0 ); \ + E##ko0 = (~Bko0)^( Bku0 | Bka0 ); \ + E##ku0 = Bku0 ^( Bka0 & Bke0 ); \ +\ + A##be0 ^= De0; \ + Bka1 = A##be0; \ + A##gi1 ^= Di1; \ + Bke1 = ROL32(A##gi1, 3); \ + A##ko0 ^= Do0; \ + Bki1 = ROL32(A##ko0, 12); \ + A##mu1 ^= Du1; \ + Bko1 = ROL32(A##mu1, 4); \ + A##sa1 ^= Da1; \ + Bku1 = ROL32(A##sa1, 9); \ + E##ka1 = Bka1 ^( Bke1 | Bki1 ); \ + E##ke1 = Bke1 ^( Bki1 & Bko1 ); \ + E##ki1 = Bki1 ^((~Bko1)& Bku1 ); \ + E##ko1 = (~Bko1)^( Bku1 | Bka1 ); \ + E##ku1 = Bku1 ^( Bka1 & Bke1 ); \ +\ + A##bu1 ^= Du1; \ + Bma0 = ROL32(A##bu1, 14); \ + A##ga0 ^= Da0; \ + Bme0 = ROL32(A##ga0, 18); \ + A##ke0 ^= De0; \ + Bmi0 = ROL32(A##ke0, 5); \ + A##mi1 ^= Di1; \ + Bmo0 = ROL32(A##mi1, 8); \ + A##so0 ^= Do0; \ + Bmu0 = ROL32(A##so0, 28); \ + E##ma0 = Bma0 ^( Bme0 & Bmi0 ); \ + E##me0 = Bme0 ^( Bmi0 | Bmo0 ); \ + E##mi0 = Bmi0 ^((~Bmo0)| Bmu0 ); \ + E##mo0 = (~Bmo0)^( Bmu0 & Bma0 ); \ + E##mu0 = Bmu0 ^( Bma0 | Bme0 ); \ +\ + A##bu0 ^= Du0; \ + Bma1 = ROL32(A##bu0, 13); \ + A##ga1 ^= Da1; \ + Bme1 = ROL32(A##ga1, 18); \ + A##ke1 ^= De1; \ + Bmi1 = ROL32(A##ke1, 5); \ + A##mi0 ^= Di0; \ + Bmo1 = ROL32(A##mi0, 7); \ + A##so1 ^= Do1; \ + Bmu1 = ROL32(A##so1, 28); \ + E##ma1 = Bma1 ^( Bme1 & Bmi1 ); \ + E##me1 = Bme1 ^( Bmi1 | Bmo1 ); \ + E##mi1 = Bmi1 ^((~Bmo1)| Bmu1 ); \ + E##mo1 = (~Bmo1)^( Bmu1 & Bma1 ); \ + E##mu1 = Bmu1 ^( Bma1 | Bme1 ); \ +\ + A##bi0 ^= Di0; \ + Bsa0 = ROL32(A##bi0, 31); \ + A##go1 ^= Do1; \ + Bse0 = ROL32(A##go1, 28); \ + A##ku1 ^= Du1; \ + Bsi0 = ROL32(A##ku1, 20); \ + A##ma1 ^= Da1; \ + Bso0 = ROL32(A##ma1, 21); \ + A##se0 ^= De0; \ + Bsu0 = ROL32(A##se0, 1); \ + E##sa0 = Bsa0 ^((~Bse0)& Bsi0 ); \ + E##se0 = (~Bse0)^( Bsi0 | Bso0 ); \ + E##si0 = Bsi0 ^( Bso0 & Bsu0 ); \ + E##so0 = Bso0 ^( Bsu0 | Bsa0 ); \ + E##su0 = Bsu0 ^( Bsa0 & Bse0 ); \ +\ + A##bi1 ^= Di1; \ + Bsa1 = ROL32(A##bi1, 31); \ + A##go0 ^= Do0; \ + Bse1 = ROL32(A##go0, 27); \ + A##ku0 ^= Du0; \ + Bsi1 = ROL32(A##ku0, 19); \ + A##ma0 ^= Da0; \ + Bso1 = ROL32(A##ma0, 20); \ + A##se1 ^= De1; \ + Bsu1 = ROL32(A##se1, 1); \ + E##sa1 = Bsa1 ^((~Bse1)& Bsi1 ); \ + E##se1 = (~Bse1)^( Bsi1 | Bso1 ); \ + E##si1 = Bsi1 ^( Bso1 & Bsu1 ); \ + E##so1 = Bso1 ^( Bsu1 | Bsa1 ); \ + E##su1 = Bsu1 ^( Bsa1 & Bse1 ); \ +\ + +#else // UseBebigokimisa +// --- Code for round, with prepare-theta +// --- using factor 2 interleaving, 64-bit lanes mapped to 32-bit words +#define thetaRhoPiChiIotaPrepareTheta(i, A, E) \ + Da0 = Cu0^ROL32(Ce1, 1); \ + Da1 = Cu1^Ce0; \ + De0 = Ca0^ROL32(Ci1, 1); \ + De1 = Ca1^Ci0; \ + Di0 = Ce0^ROL32(Co1, 1); \ + Di1 = Ce1^Co0; \ + Do0 = Ci0^ROL32(Cu1, 1); \ + Do1 = Ci1^Cu0; \ + Du0 = Co0^ROL32(Ca1, 1); \ + Du1 = Co1^Ca0; \ +\ + A##ba0 ^= Da0; \ + Bba0 = A##ba0; \ + A##ge0 ^= De0; \ + Bbe0 = ROL32(A##ge0, 22); \ + A##ki1 ^= Di1; \ + Bbi0 = ROL32(A##ki1, 22); \ + A##mo1 ^= Do1; \ + Bbo0 = ROL32(A##mo1, 11); \ + A##su0 ^= Du0; \ + Bbu0 = ROL32(A##su0, 7); \ + E##ba0 = Bba0 ^((~Bbe0)& Bbi0 ); \ + E##ba0 ^= KeccakF1600RoundConstants_int2_0[i]; \ + Ca0 = E##ba0; \ + E##be0 = Bbe0 ^((~Bbi0)& Bbo0 ); \ + Ce0 = E##be0; \ + E##bi0 = Bbi0 ^((~Bbo0)& Bbu0 ); \ + Ci0 = E##bi0; \ + E##bo0 = Bbo0 ^((~Bbu0)& Bba0 ); \ + Co0 = E##bo0; \ + E##bu0 = Bbu0 ^((~Bba0)& Bbe0 ); \ + Cu0 = E##bu0; \ +\ + A##ba1 ^= Da1; \ + Bba1 = A##ba1; \ + A##ge1 ^= De1; \ + Bbe1 = ROL32(A##ge1, 22); \ + A##ki0 ^= Di0; \ + Bbi1 = ROL32(A##ki0, 21); \ + A##mo0 ^= Do0; \ + Bbo1 = ROL32(A##mo0, 10); \ + A##su1 ^= Du1; \ + Bbu1 = ROL32(A##su1, 7); \ + E##ba1 = Bba1 ^((~Bbe1)& Bbi1 ); \ + E##ba1 ^= KeccakF1600RoundConstants_int2_1[i]; \ + Ca1 = E##ba1; \ + E##be1 = Bbe1 ^((~Bbi1)& Bbo1 ); \ + Ce1 = E##be1; \ + E##bi1 = Bbi1 ^((~Bbo1)& Bbu1 ); \ + Ci1 = E##bi1; \ + E##bo1 = Bbo1 ^((~Bbu1)& Bba1 ); \ + Co1 = E##bo1; \ + E##bu1 = Bbu1 ^((~Bba1)& Bbe1 ); \ + Cu1 = E##bu1; \ +\ + A##bo0 ^= Do0; \ + Bga0 = ROL32(A##bo0, 14); \ + A##gu0 ^= Du0; \ + Bge0 = ROL32(A##gu0, 10); \ + A##ka1 ^= Da1; \ + Bgi0 = ROL32(A##ka1, 2); \ + A##me1 ^= De1; \ + Bgo0 = ROL32(A##me1, 23); \ + A##si1 ^= Di1; \ + Bgu0 = ROL32(A##si1, 31); \ + E##ga0 = Bga0 ^((~Bge0)& Bgi0 ); \ + Ca0 ^= E##ga0; \ + E##ge0 = Bge0 ^((~Bgi0)& Bgo0 ); \ + Ce0 ^= E##ge0; \ + E##gi0 = Bgi0 ^((~Bgo0)& Bgu0 ); \ + Ci0 ^= E##gi0; \ + E##go0 = Bgo0 ^((~Bgu0)& Bga0 ); \ + Co0 ^= E##go0; \ + E##gu0 = Bgu0 ^((~Bga0)& Bge0 ); \ + Cu0 ^= E##gu0; \ +\ + A##bo1 ^= Do1; \ + Bga1 = ROL32(A##bo1, 14); \ + A##gu1 ^= Du1; \ + Bge1 = ROL32(A##gu1, 10); \ + A##ka0 ^= Da0; \ + Bgi1 = ROL32(A##ka0, 1); \ + A##me0 ^= De0; \ + Bgo1 = ROL32(A##me0, 22); \ + A##si0 ^= Di0; \ + Bgu1 = ROL32(A##si0, 30); \ + E##ga1 = Bga1 ^((~Bge1)& Bgi1 ); \ + Ca1 ^= E##ga1; \ + E##ge1 = Bge1 ^((~Bgi1)& Bgo1 ); \ + Ce1 ^= E##ge1; \ + E##gi1 = Bgi1 ^((~Bgo1)& Bgu1 ); \ + Ci1 ^= E##gi1; \ + E##go1 = Bgo1 ^((~Bgu1)& Bga1 ); \ + Co1 ^= E##go1; \ + E##gu1 = Bgu1 ^((~Bga1)& Bge1 ); \ + Cu1 ^= E##gu1; \ +\ + A##be1 ^= De1; \ + Bka0 = ROL32(A##be1, 1); \ + A##gi0 ^= Di0; \ + Bke0 = ROL32(A##gi0, 3); \ + A##ko1 ^= Do1; \ + Bki0 = ROL32(A##ko1, 13); \ + A##mu0 ^= Du0; \ + Bko0 = ROL32(A##mu0, 4); \ + A##sa0 ^= Da0; \ + Bku0 = ROL32(A##sa0, 9); \ + E##ka0 = Bka0 ^((~Bke0)& Bki0 ); \ + Ca0 ^= E##ka0; \ + E##ke0 = Bke0 ^((~Bki0)& Bko0 ); \ + Ce0 ^= E##ke0; \ + E##ki0 = Bki0 ^((~Bko0)& Bku0 ); \ + Ci0 ^= E##ki0; \ + E##ko0 = Bko0 ^((~Bku0)& Bka0 ); \ + Co0 ^= E##ko0; \ + E##ku0 = Bku0 ^((~Bka0)& Bke0 ); \ + Cu0 ^= E##ku0; \ +\ + A##be0 ^= De0; \ + Bka1 = A##be0; \ + A##gi1 ^= Di1; \ + Bke1 = ROL32(A##gi1, 3); \ + A##ko0 ^= Do0; \ + Bki1 = ROL32(A##ko0, 12); \ + A##mu1 ^= Du1; \ + Bko1 = ROL32(A##mu1, 4); \ + A##sa1 ^= Da1; \ + Bku1 = ROL32(A##sa1, 9); \ + E##ka1 = Bka1 ^((~Bke1)& Bki1 ); \ + Ca1 ^= E##ka1; \ + E##ke1 = Bke1 ^((~Bki1)& Bko1 ); \ + Ce1 ^= E##ke1; \ + E##ki1 = Bki1 ^((~Bko1)& Bku1 ); \ + Ci1 ^= E##ki1; \ + E##ko1 = Bko1 ^((~Bku1)& Bka1 ); \ + Co1 ^= E##ko1; \ + E##ku1 = Bku1 ^((~Bka1)& Bke1 ); \ + Cu1 ^= E##ku1; \ +\ + A##bu1 ^= Du1; \ + Bma0 = ROL32(A##bu1, 14); \ + A##ga0 ^= Da0; \ + Bme0 = ROL32(A##ga0, 18); \ + A##ke0 ^= De0; \ + Bmi0 = ROL32(A##ke0, 5); \ + A##mi1 ^= Di1; \ + Bmo0 = ROL32(A##mi1, 8); \ + A##so0 ^= Do0; \ + Bmu0 = ROL32(A##so0, 28); \ + E##ma0 = Bma0 ^((~Bme0)& Bmi0 ); \ + Ca0 ^= E##ma0; \ + E##me0 = Bme0 ^((~Bmi0)& Bmo0 ); \ + Ce0 ^= E##me0; \ + E##mi0 = Bmi0 ^((~Bmo0)& Bmu0 ); \ + Ci0 ^= E##mi0; \ + E##mo0 = Bmo0 ^((~Bmu0)& Bma0 ); \ + Co0 ^= E##mo0; \ + E##mu0 = Bmu0 ^((~Bma0)& Bme0 ); \ + Cu0 ^= E##mu0; \ +\ + A##bu0 ^= Du0; \ + Bma1 = ROL32(A##bu0, 13); \ + A##ga1 ^= Da1; \ + Bme1 = ROL32(A##ga1, 18); \ + A##ke1 ^= De1; \ + Bmi1 = ROL32(A##ke1, 5); \ + A##mi0 ^= Di0; \ + Bmo1 = ROL32(A##mi0, 7); \ + A##so1 ^= Do1; \ + Bmu1 = ROL32(A##so1, 28); \ + E##ma1 = Bma1 ^((~Bme1)& Bmi1 ); \ + Ca1 ^= E##ma1; \ + E##me1 = Bme1 ^((~Bmi1)& Bmo1 ); \ + Ce1 ^= E##me1; \ + E##mi1 = Bmi1 ^((~Bmo1)& Bmu1 ); \ + Ci1 ^= E##mi1; \ + E##mo1 = Bmo1 ^((~Bmu1)& Bma1 ); \ + Co1 ^= E##mo1; \ + E##mu1 = Bmu1 ^((~Bma1)& Bme1 ); \ + Cu1 ^= E##mu1; \ +\ + A##bi0 ^= Di0; \ + Bsa0 = ROL32(A##bi0, 31); \ + A##go1 ^= Do1; \ + Bse0 = ROL32(A##go1, 28); \ + A##ku1 ^= Du1; \ + Bsi0 = ROL32(A##ku1, 20); \ + A##ma1 ^= Da1; \ + Bso0 = ROL32(A##ma1, 21); \ + A##se0 ^= De0; \ + Bsu0 = ROL32(A##se0, 1); \ + E##sa0 = Bsa0 ^((~Bse0)& Bsi0 ); \ + Ca0 ^= E##sa0; \ + E##se0 = Bse0 ^((~Bsi0)& Bso0 ); \ + Ce0 ^= E##se0; \ + E##si0 = Bsi0 ^((~Bso0)& Bsu0 ); \ + Ci0 ^= E##si0; \ + E##so0 = Bso0 ^((~Bsu0)& Bsa0 ); \ + Co0 ^= E##so0; \ + E##su0 = Bsu0 ^((~Bsa0)& Bse0 ); \ + Cu0 ^= E##su0; \ +\ + A##bi1 ^= Di1; \ + Bsa1 = ROL32(A##bi1, 31); \ + A##go0 ^= Do0; \ + Bse1 = ROL32(A##go0, 27); \ + A##ku0 ^= Du0; \ + Bsi1 = ROL32(A##ku0, 19); \ + A##ma0 ^= Da0; \ + Bso1 = ROL32(A##ma0, 20); \ + A##se1 ^= De1; \ + Bsu1 = ROL32(A##se1, 1); \ + E##sa1 = Bsa1 ^((~Bse1)& Bsi1 ); \ + Ca1 ^= E##sa1; \ + E##se1 = Bse1 ^((~Bsi1)& Bso1 ); \ + Ce1 ^= E##se1; \ + E##si1 = Bsi1 ^((~Bso1)& Bsu1 ); \ + Ci1 ^= E##si1; \ + E##so1 = Bso1 ^((~Bsu1)& Bsa1 ); \ + Co1 ^= E##so1; \ + E##su1 = Bsu1 ^((~Bsa1)& Bse1 ); \ + Cu1 ^= E##su1; \ +\ + +// --- Code for round +// --- using factor 2 interleaving, 64-bit lanes mapped to 32-bit words +#define thetaRhoPiChiIota(i, A, E) \ + Da0 = Cu0^ROL32(Ce1, 1); \ + Da1 = Cu1^Ce0; \ + De0 = Ca0^ROL32(Ci1, 1); \ + De1 = Ca1^Ci0; \ + Di0 = Ce0^ROL32(Co1, 1); \ + Di1 = Ce1^Co0; \ + Do0 = Ci0^ROL32(Cu1, 1); \ + Do1 = Ci1^Cu0; \ + Du0 = Co0^ROL32(Ca1, 1); \ + Du1 = Co1^Ca0; \ +\ + A##ba0 ^= Da0; \ + Bba0 = A##ba0; \ + A##ge0 ^= De0; \ + Bbe0 = ROL32(A##ge0, 22); \ + A##ki1 ^= Di1; \ + Bbi0 = ROL32(A##ki1, 22); \ + A##mo1 ^= Do1; \ + Bbo0 = ROL32(A##mo1, 11); \ + A##su0 ^= Du0; \ + Bbu0 = ROL32(A##su0, 7); \ + E##ba0 = Bba0 ^((~Bbe0)& Bbi0 ); \ + E##ba0 ^= KeccakF1600RoundConstants_int2_0[i]; \ + E##be0 = Bbe0 ^((~Bbi0)& Bbo0 ); \ + E##bi0 = Bbi0 ^((~Bbo0)& Bbu0 ); \ + E##bo0 = Bbo0 ^((~Bbu0)& Bba0 ); \ + E##bu0 = Bbu0 ^((~Bba0)& Bbe0 ); \ +\ + A##ba1 ^= Da1; \ + Bba1 = A##ba1; \ + A##ge1 ^= De1; \ + Bbe1 = ROL32(A##ge1, 22); \ + A##ki0 ^= Di0; \ + Bbi1 = ROL32(A##ki0, 21); \ + A##mo0 ^= Do0; \ + Bbo1 = ROL32(A##mo0, 10); \ + A##su1 ^= Du1; \ + Bbu1 = ROL32(A##su1, 7); \ + E##ba1 = Bba1 ^((~Bbe1)& Bbi1 ); \ + E##ba1 ^= KeccakF1600RoundConstants_int2_1[i]; \ + E##be1 = Bbe1 ^((~Bbi1)& Bbo1 ); \ + E##bi1 = Bbi1 ^((~Bbo1)& Bbu1 ); \ + E##bo1 = Bbo1 ^((~Bbu1)& Bba1 ); \ + E##bu1 = Bbu1 ^((~Bba1)& Bbe1 ); \ +\ + A##bo0 ^= Do0; \ + Bga0 = ROL32(A##bo0, 14); \ + A##gu0 ^= Du0; \ + Bge0 = ROL32(A##gu0, 10); \ + A##ka1 ^= Da1; \ + Bgi0 = ROL32(A##ka1, 2); \ + A##me1 ^= De1; \ + Bgo0 = ROL32(A##me1, 23); \ + A##si1 ^= Di1; \ + Bgu0 = ROL32(A##si1, 31); \ + E##ga0 = Bga0 ^((~Bge0)& Bgi0 ); \ + E##ge0 = Bge0 ^((~Bgi0)& Bgo0 ); \ + E##gi0 = Bgi0 ^((~Bgo0)& Bgu0 ); \ + E##go0 = Bgo0 ^((~Bgu0)& Bga0 ); \ + E##gu0 = Bgu0 ^((~Bga0)& Bge0 ); \ +\ + A##bo1 ^= Do1; \ + Bga1 = ROL32(A##bo1, 14); \ + A##gu1 ^= Du1; \ + Bge1 = ROL32(A##gu1, 10); \ + A##ka0 ^= Da0; \ + Bgi1 = ROL32(A##ka0, 1); \ + A##me0 ^= De0; \ + Bgo1 = ROL32(A##me0, 22); \ + A##si0 ^= Di0; \ + Bgu1 = ROL32(A##si0, 30); \ + E##ga1 = Bga1 ^((~Bge1)& Bgi1 ); \ + E##ge1 = Bge1 ^((~Bgi1)& Bgo1 ); \ + E##gi1 = Bgi1 ^((~Bgo1)& Bgu1 ); \ + E##go1 = Bgo1 ^((~Bgu1)& Bga1 ); \ + E##gu1 = Bgu1 ^((~Bga1)& Bge1 ); \ +\ + A##be1 ^= De1; \ + Bka0 = ROL32(A##be1, 1); \ + A##gi0 ^= Di0; \ + Bke0 = ROL32(A##gi0, 3); \ + A##ko1 ^= Do1; \ + Bki0 = ROL32(A##ko1, 13); \ + A##mu0 ^= Du0; \ + Bko0 = ROL32(A##mu0, 4); \ + A##sa0 ^= Da0; \ + Bku0 = ROL32(A##sa0, 9); \ + E##ka0 = Bka0 ^((~Bke0)& Bki0 ); \ + E##ke0 = Bke0 ^((~Bki0)& Bko0 ); \ + E##ki0 = Bki0 ^((~Bko0)& Bku0 ); \ + E##ko0 = Bko0 ^((~Bku0)& Bka0 ); \ + E##ku0 = Bku0 ^((~Bka0)& Bke0 ); \ +\ + A##be0 ^= De0; \ + Bka1 = A##be0; \ + A##gi1 ^= Di1; \ + Bke1 = ROL32(A##gi1, 3); \ + A##ko0 ^= Do0; \ + Bki1 = ROL32(A##ko0, 12); \ + A##mu1 ^= Du1; \ + Bko1 = ROL32(A##mu1, 4); \ + A##sa1 ^= Da1; \ + Bku1 = ROL32(A##sa1, 9); \ + E##ka1 = Bka1 ^((~Bke1)& Bki1 ); \ + E##ke1 = Bke1 ^((~Bki1)& Bko1 ); \ + E##ki1 = Bki1 ^((~Bko1)& Bku1 ); \ + E##ko1 = Bko1 ^((~Bku1)& Bka1 ); \ + E##ku1 = Bku1 ^((~Bka1)& Bke1 ); \ +\ + A##bu1 ^= Du1; \ + Bma0 = ROL32(A##bu1, 14); \ + A##ga0 ^= Da0; \ + Bme0 = ROL32(A##ga0, 18); \ + A##ke0 ^= De0; \ + Bmi0 = ROL32(A##ke0, 5); \ + A##mi1 ^= Di1; \ + Bmo0 = ROL32(A##mi1, 8); \ + A##so0 ^= Do0; \ + Bmu0 = ROL32(A##so0, 28); \ + E##ma0 = Bma0 ^((~Bme0)& Bmi0 ); \ + E##me0 = Bme0 ^((~Bmi0)& Bmo0 ); \ + E##mi0 = Bmi0 ^((~Bmo0)& Bmu0 ); \ + E##mo0 = Bmo0 ^((~Bmu0)& Bma0 ); \ + E##mu0 = Bmu0 ^((~Bma0)& Bme0 ); \ +\ + A##bu0 ^= Du0; \ + Bma1 = ROL32(A##bu0, 13); \ + A##ga1 ^= Da1; \ + Bme1 = ROL32(A##ga1, 18); \ + A##ke1 ^= De1; \ + Bmi1 = ROL32(A##ke1, 5); \ + A##mi0 ^= Di0; \ + Bmo1 = ROL32(A##mi0, 7); \ + A##so1 ^= Do1; \ + Bmu1 = ROL32(A##so1, 28); \ + E##ma1 = Bma1 ^((~Bme1)& Bmi1 ); \ + E##me1 = Bme1 ^((~Bmi1)& Bmo1 ); \ + E##mi1 = Bmi1 ^((~Bmo1)& Bmu1 ); \ + E##mo1 = Bmo1 ^((~Bmu1)& Bma1 ); \ + E##mu1 = Bmu1 ^((~Bma1)& Bme1 ); \ +\ + A##bi0 ^= Di0; \ + Bsa0 = ROL32(A##bi0, 31); \ + A##go1 ^= Do1; \ + Bse0 = ROL32(A##go1, 28); \ + A##ku1 ^= Du1; \ + Bsi0 = ROL32(A##ku1, 20); \ + A##ma1 ^= Da1; \ + Bso0 = ROL32(A##ma1, 21); \ + A##se0 ^= De0; \ + Bsu0 = ROL32(A##se0, 1); \ + E##sa0 = Bsa0 ^((~Bse0)& Bsi0 ); \ + E##se0 = Bse0 ^((~Bsi0)& Bso0 ); \ + E##si0 = Bsi0 ^((~Bso0)& Bsu0 ); \ + E##so0 = Bso0 ^((~Bsu0)& Bsa0 ); \ + E##su0 = Bsu0 ^((~Bsa0)& Bse0 ); \ +\ + A##bi1 ^= Di1; \ + Bsa1 = ROL32(A##bi1, 31); \ + A##go0 ^= Do0; \ + Bse1 = ROL32(A##go0, 27); \ + A##ku0 ^= Du0; \ + Bsi1 = ROL32(A##ku0, 19); \ + A##ma0 ^= Da0; \ + Bso1 = ROL32(A##ma0, 20); \ + A##se1 ^= De1; \ + Bsu1 = ROL32(A##se1, 1); \ + E##sa1 = Bsa1 ^((~Bse1)& Bsi1 ); \ + E##se1 = Bse1 ^((~Bsi1)& Bso1 ); \ + E##si1 = Bsi1 ^((~Bso1)& Bsu1 ); \ + E##so1 = Bso1 ^((~Bsu1)& Bsa1 ); \ + E##su1 = Bsu1 ^((~Bsa1)& Bse1 ); \ +\ + +#endif // UseBebigokimisa + +const UINT32 KeccakF1600RoundConstants_int2_0[24] = { + 0x00000001UL, + 0x00000000UL, + 0x00000000UL, + 0x00000000UL, + 0x00000001UL, + 0x00000001UL, + 0x00000001UL, + 0x00000001UL, + 0x00000000UL, + 0x00000000UL, + 0x00000001UL, + 0x00000000UL, + 0x00000001UL, + 0x00000001UL, + 0x00000001UL, + 0x00000001UL, + 0x00000000UL, + 0x00000000UL, + 0x00000000UL, + 0x00000000UL, + 0x00000001UL, + 0x00000000UL, + 0x00000001UL, + 0x00000000UL }; + +const UINT32 KeccakF1600RoundConstants_int2_1[24] = { + 0x00000000UL, + 0x00000089UL, + 0x8000008bUL, + 0x80008080UL, + 0x0000008bUL, + 0x00008000UL, + 0x80008088UL, + 0x80000082UL, + 0x0000000bUL, + 0x0000000aUL, + 0x00008082UL, + 0x00008003UL, + 0x0000808bUL, + 0x8000000bUL, + 0x8000008aUL, + 0x80000081UL, + 0x80000081UL, + 0x80000008UL, + 0x00000083UL, + 0x80008003UL, + 0x80008088UL, + 0x80000088UL, + 0x00008000UL, + 0x80008082UL }; + +#define copyFromStateAndXor1024bits(X, state, input) \ + X##ba0 = state[ 0]^input[ 0]; \ + X##ba1 = state[ 1]^input[ 1]; \ + X##be0 = state[ 2]^input[ 2]; \ + X##be1 = state[ 3]^input[ 3]; \ + X##bi0 = state[ 4]^input[ 4]; \ + X##bi1 = state[ 5]^input[ 5]; \ + X##bo0 = state[ 6]^input[ 6]; \ + X##bo1 = state[ 7]^input[ 7]; \ + X##bu0 = state[ 8]^input[ 8]; \ + X##bu1 = state[ 9]^input[ 9]; \ + X##ga0 = state[10]^input[10]; \ + X##ga1 = state[11]^input[11]; \ + X##ge0 = state[12]^input[12]; \ + X##ge1 = state[13]^input[13]; \ + X##gi0 = state[14]^input[14]; \ + X##gi1 = state[15]^input[15]; \ + X##go0 = state[16]^input[16]; \ + X##go1 = state[17]^input[17]; \ + X##gu0 = state[18]^input[18]; \ + X##gu1 = state[19]^input[19]; \ + X##ka0 = state[20]^input[20]; \ + X##ka1 = state[21]^input[21]; \ + X##ke0 = state[22]^input[22]; \ + X##ke1 = state[23]^input[23]; \ + X##ki0 = state[24]^input[24]; \ + X##ki1 = state[25]^input[25]; \ + X##ko0 = state[26]^input[26]; \ + X##ko1 = state[27]^input[27]; \ + X##ku0 = state[28]^input[28]; \ + X##ku1 = state[29]^input[29]; \ + X##ma0 = state[30]^input[30]; \ + X##ma1 = state[31]^input[31]; \ + X##me0 = state[32]; \ + X##me1 = state[33]; \ + X##mi0 = state[34]; \ + X##mi1 = state[35]; \ + X##mo0 = state[36]; \ + X##mo1 = state[37]; \ + X##mu0 = state[38]; \ + X##mu1 = state[39]; \ + X##sa0 = state[40]; \ + X##sa1 = state[41]; \ + X##se0 = state[42]; \ + X##se1 = state[43]; \ + X##si0 = state[44]; \ + X##si1 = state[45]; \ + X##so0 = state[46]; \ + X##so1 = state[47]; \ + X##su0 = state[48]; \ + X##su1 = state[49]; \ + +#define copyFromStateAndXor1088bits(X, state, input) \ + X##ba0 = state[ 0]^input[ 0]; \ + X##ba1 = state[ 1]^input[ 1]; \ + X##be0 = state[ 2]^input[ 2]; \ + X##be1 = state[ 3]^input[ 3]; \ + X##bi0 = state[ 4]^input[ 4]; \ + X##bi1 = state[ 5]^input[ 5]; \ + X##bo0 = state[ 6]^input[ 6]; \ + X##bo1 = state[ 7]^input[ 7]; \ + X##bu0 = state[ 8]^input[ 8]; \ + X##bu1 = state[ 9]^input[ 9]; \ + X##ga0 = state[10]^input[10]; \ + X##ga1 = state[11]^input[11]; \ + X##ge0 = state[12]^input[12]; \ + X##ge1 = state[13]^input[13]; \ + X##gi0 = state[14]^input[14]; \ + X##gi1 = state[15]^input[15]; \ + X##go0 = state[16]^input[16]; \ + X##go1 = state[17]^input[17]; \ + X##gu0 = state[18]^input[18]; \ + X##gu1 = state[19]^input[19]; \ + X##ka0 = state[20]^input[20]; \ + X##ka1 = state[21]^input[21]; \ + X##ke0 = state[22]^input[22]; \ + X##ke1 = state[23]^input[23]; \ + X##ki0 = state[24]^input[24]; \ + X##ki1 = state[25]^input[25]; \ + X##ko0 = state[26]^input[26]; \ + X##ko1 = state[27]^input[27]; \ + X##ku0 = state[28]^input[28]; \ + X##ku1 = state[29]^input[29]; \ + X##ma0 = state[30]^input[30]; \ + X##ma1 = state[31]^input[31]; \ + X##me0 = state[32]^input[32]; \ + X##me1 = state[33]^input[33]; \ + X##mi0 = state[34]; \ + X##mi1 = state[35]; \ + X##mo0 = state[36]; \ + X##mo1 = state[37]; \ + X##mu0 = state[38]; \ + X##mu1 = state[39]; \ + X##sa0 = state[40]; \ + X##sa1 = state[41]; \ + X##se0 = state[42]; \ + X##se1 = state[43]; \ + X##si0 = state[44]; \ + X##si1 = state[45]; \ + X##so0 = state[46]; \ + X##so1 = state[47]; \ + X##su0 = state[48]; \ + X##su1 = state[49]; \ + +#define copyFromState(X, state) \ + X##ba0 = state[ 0]; \ + X##ba1 = state[ 1]; \ + X##be0 = state[ 2]; \ + X##be1 = state[ 3]; \ + X##bi0 = state[ 4]; \ + X##bi1 = state[ 5]; \ + X##bo0 = state[ 6]; \ + X##bo1 = state[ 7]; \ + X##bu0 = state[ 8]; \ + X##bu1 = state[ 9]; \ + X##ga0 = state[10]; \ + X##ga1 = state[11]; \ + X##ge0 = state[12]; \ + X##ge1 = state[13]; \ + X##gi0 = state[14]; \ + X##gi1 = state[15]; \ + X##go0 = state[16]; \ + X##go1 = state[17]; \ + X##gu0 = state[18]; \ + X##gu1 = state[19]; \ + X##ka0 = state[20]; \ + X##ka1 = state[21]; \ + X##ke0 = state[22]; \ + X##ke1 = state[23]; \ + X##ki0 = state[24]; \ + X##ki1 = state[25]; \ + X##ko0 = state[26]; \ + X##ko1 = state[27]; \ + X##ku0 = state[28]; \ + X##ku1 = state[29]; \ + X##ma0 = state[30]; \ + X##ma1 = state[31]; \ + X##me0 = state[32]; \ + X##me1 = state[33]; \ + X##mi0 = state[34]; \ + X##mi1 = state[35]; \ + X##mo0 = state[36]; \ + X##mo1 = state[37]; \ + X##mu0 = state[38]; \ + X##mu1 = state[39]; \ + X##sa0 = state[40]; \ + X##sa1 = state[41]; \ + X##se0 = state[42]; \ + X##se1 = state[43]; \ + X##si0 = state[44]; \ + X##si1 = state[45]; \ + X##so0 = state[46]; \ + X##so1 = state[47]; \ + X##su0 = state[48]; \ + X##su1 = state[49]; \ + +#define copyToState(state, X) \ + state[ 0] = X##ba0; \ + state[ 1] = X##ba1; \ + state[ 2] = X##be0; \ + state[ 3] = X##be1; \ + state[ 4] = X##bi0; \ + state[ 5] = X##bi1; \ + state[ 6] = X##bo0; \ + state[ 7] = X##bo1; \ + state[ 8] = X##bu0; \ + state[ 9] = X##bu1; \ + state[10] = X##ga0; \ + state[11] = X##ga1; \ + state[12] = X##ge0; \ + state[13] = X##ge1; \ + state[14] = X##gi0; \ + state[15] = X##gi1; \ + state[16] = X##go0; \ + state[17] = X##go1; \ + state[18] = X##gu0; \ + state[19] = X##gu1; \ + state[20] = X##ka0; \ + state[21] = X##ka1; \ + state[22] = X##ke0; \ + state[23] = X##ke1; \ + state[24] = X##ki0; \ + state[25] = X##ki1; \ + state[26] = X##ko0; \ + state[27] = X##ko1; \ + state[28] = X##ku0; \ + state[29] = X##ku1; \ + state[30] = X##ma0; \ + state[31] = X##ma1; \ + state[32] = X##me0; \ + state[33] = X##me1; \ + state[34] = X##mi0; \ + state[35] = X##mi1; \ + state[36] = X##mo0; \ + state[37] = X##mo1; \ + state[38] = X##mu0; \ + state[39] = X##mu1; \ + state[40] = X##sa0; \ + state[41] = X##sa1; \ + state[42] = X##se0; \ + state[43] = X##se1; \ + state[44] = X##si0; \ + state[45] = X##si1; \ + state[46] = X##so0; \ + state[47] = X##so1; \ + state[48] = X##su0; \ + state[49] = X##su1; \ + +#define copyStateVariables(X, Y) \ + X##ba0 = Y##ba0; \ + X##ba1 = Y##ba1; \ + X##be0 = Y##be0; \ + X##be1 = Y##be1; \ + X##bi0 = Y##bi0; \ + X##bi1 = Y##bi1; \ + X##bo0 = Y##bo0; \ + X##bo1 = Y##bo1; \ + X##bu0 = Y##bu0; \ + X##bu1 = Y##bu1; \ + X##ga0 = Y##ga0; \ + X##ga1 = Y##ga1; \ + X##ge0 = Y##ge0; \ + X##ge1 = Y##ge1; \ + X##gi0 = Y##gi0; \ + X##gi1 = Y##gi1; \ + X##go0 = Y##go0; \ + X##go1 = Y##go1; \ + X##gu0 = Y##gu0; \ + X##gu1 = Y##gu1; \ + X##ka0 = Y##ka0; \ + X##ka1 = Y##ka1; \ + X##ke0 = Y##ke0; \ + X##ke1 = Y##ke1; \ + X##ki0 = Y##ki0; \ + X##ki1 = Y##ki1; \ + X##ko0 = Y##ko0; \ + X##ko1 = Y##ko1; \ + X##ku0 = Y##ku0; \ + X##ku1 = Y##ku1; \ + X##ma0 = Y##ma0; \ + X##ma1 = Y##ma1; \ + X##me0 = Y##me0; \ + X##me1 = Y##me1; \ + X##mi0 = Y##mi0; \ + X##mi1 = Y##mi1; \ + X##mo0 = Y##mo0; \ + X##mo1 = Y##mo1; \ + X##mu0 = Y##mu0; \ + X##mu1 = Y##mu1; \ + X##sa0 = Y##sa0; \ + X##sa1 = Y##sa1; \ + X##se0 = Y##se0; \ + X##se1 = Y##se1; \ + X##si0 = Y##si0; \ + X##si1 = Y##si1; \ + X##so0 = Y##so0; \ + X##so1 = Y##so1; \ + X##su0 = Y##su0; \ + X##su1 = Y##su1; \ + diff --git a/c_src/KeccakF-1600-32-s2.macros b/c_src/KeccakF-1600-32-s2.macros new file mode 100755 index 0000000..3c27a34 --- /dev/null +++ b/c_src/KeccakF-1600-32-s2.macros @@ -0,0 +1,1187 @@ +/* +Code automatically generated by KeccakTools! + +The Keccak sponge function, designed by Guido Bertoni, Joan Daemen, +Michaël Peeters and Gilles Van Assche. For more information, feedback or +questions, please refer to our website: http://keccak.noekeon.org/ + +Implementation by the designers, +hereby denoted as "the implementer". + +To the extent possible under law, the implementer has waived all copyright +and related or neighboring rights to the source code in this file. +http://creativecommons.org/publicdomain/zero/1.0/ +*/ + +#define declareABCDE \ + UINT32 Aba0, Abe0, Abi0, Abo0, Abu0; \ + UINT32 Aba1, Abe1, Abi1, Abo1, Abu1; \ + UINT32 Aga0, Age0, Agi0, Ago0, Agu0; \ + UINT32 Aga1, Age1, Agi1, Ago1, Agu1; \ + UINT32 Aka0, Ake0, Aki0, Ako0, Aku0; \ + UINT32 Aka1, Ake1, Aki1, Ako1, Aku1; \ + UINT32 Ama0, Ame0, Ami0, Amo0, Amu0; \ + UINT32 Ama1, Ame1, Ami1, Amo1, Amu1; \ + UINT32 Asa0, Ase0, Asi0, Aso0, Asu0; \ + UINT32 Asa1, Ase1, Asi1, Aso1, Asu1; \ + UINT32 Bba0, Bbe0, Bbi0, Bbo0, Bbu0; \ + UINT32 Bba1, Bbe1, Bbi1, Bbo1, Bbu1; \ + UINT32 Bga0, Bge0, Bgi0, Bgo0, Bgu0; \ + UINT32 Bga1, Bge1, Bgi1, Bgo1, Bgu1; \ + UINT32 Bka0, Bke0, Bki0, Bko0, Bku0; \ + UINT32 Bka1, Bke1, Bki1, Bko1, Bku1; \ + UINT32 Bma0, Bme0, Bmi0, Bmo0, Bmu0; \ + UINT32 Bma1, Bme1, Bmi1, Bmo1, Bmu1; \ + UINT32 Bsa0, Bse0, Bsi0, Bso0, Bsu0; \ + UINT32 Bsa1, Bse1, Bsi1, Bso1, Bsu1; \ + UINT32 Ca0, Ce0, Ci0, Co0, Cu0; \ + UINT32 Ca1, Ce1, Ci1, Co1, Cu1; \ + UINT32 Da0, De0, Di0, Do0, Du0; \ + UINT32 Da1, De1, Di1, Do1, Du1; \ + UINT32 Eba0, Ebe0, Ebi0, Ebo0, Ebu0; \ + UINT32 Eba1, Ebe1, Ebi1, Ebo1, Ebu1; \ + UINT32 Ega0, Ege0, Egi0, Ego0, Egu0; \ + UINT32 Ega1, Ege1, Egi1, Ego1, Egu1; \ + UINT32 Eka0, Eke0, Eki0, Eko0, Eku0; \ + UINT32 Eka1, Eke1, Eki1, Eko1, Eku1; \ + UINT32 Ema0, Eme0, Emi0, Emo0, Emu0; \ + UINT32 Ema1, Eme1, Emi1, Emo1, Emu1; \ + UINT32 Esa0, Ese0, Esi0, Eso0, Esu0; \ + UINT32 Esa1, Ese1, Esi1, Eso1, Esu1; \ + +#define prepareTheta \ + Ca0 = Aba0^Aga0^Aka0^Ama0^Asa0; \ + Ca1 = Aba1^Aga1^Aka1^Ama1^Asa1; \ + Ce0 = Abe0^Age0^Ake0^Ame0^Ase0; \ + Ce1 = Abe1^Age1^Ake1^Ame1^Ase1; \ + Ci0 = Abi0^Agi0^Aki0^Ami0^Asi0; \ + Ci1 = Abi1^Agi1^Aki1^Ami1^Asi1; \ + Co0 = Abo0^Ago0^Ako0^Amo0^Aso0; \ + Co1 = Abo1^Ago1^Ako1^Amo1^Aso1; \ + Cu0 = Abu0^Agu0^Aku0^Amu0^Asu0; \ + Cu1 = Abu1^Agu1^Aku1^Amu1^Asu1; \ + +#ifdef UseBebigokimisa +// --- Code for round, with prepare-theta (lane complementing pattern 'bebigokimisa') +// --- using factor 2 interleaving, 64-bit lanes mapped to 32-bit words +#define thetaRhoPiChiIotaPrepareTheta(i, A, E) \ + Da0 = Cu0^ROL32(Ce1, 1); \ + Da1 = Cu1^Ce0; \ + De0 = Ca0^ROL32(Ci1, 1); \ + De1 = Ca1^Ci0; \ + Di0 = Ce0^ROL32(Co1, 1); \ + Di1 = Ce1^Co0; \ + Do0 = Ci0^ROL32(Cu1, 1); \ + Do1 = Ci1^Cu0; \ + Du0 = Co0^ROL32(Ca1, 1); \ + Du1 = Co1^Ca0; \ +\ + A##ba0 ^= Da0; \ + Bba0 = A##ba0; \ + A##ge0 ^= De0; \ + Bbe0 = ROL32(A##ge0, 22); \ + A##ki1 ^= Di1; \ + Bbi0 = ROL32(A##ki1, 22); \ + E##ba0 = Bba0 ^( Bbe0 | Bbi0 ); \ + E##ba0 ^= KeccakF1600RoundConstants_int2_0[i]; \ + Ca0 = E##ba0; \ + A##mo1 ^= Do1; \ + Bbo0 = ROL32(A##mo1, 11); \ + E##be0 = Bbe0 ^((~Bbi0)| Bbo0 ); \ + Ce0 = E##be0; \ + A##su0 ^= Du0; \ + Bbu0 = ROL32(A##su0, 7); \ + E##bi0 = Bbi0 ^( Bbo0 & Bbu0 ); \ + Ci0 = E##bi0; \ + E##bo0 = Bbo0 ^( Bbu0 | Bba0 ); \ + Co0 = E##bo0; \ + E##bu0 = Bbu0 ^( Bba0 & Bbe0 ); \ + Cu0 = E##bu0; \ +\ + A##ba1 ^= Da1; \ + Bba1 = A##ba1; \ + A##ge1 ^= De1; \ + Bbe1 = ROL32(A##ge1, 22); \ + A##ki0 ^= Di0; \ + Bbi1 = ROL32(A##ki0, 21); \ + E##ba1 = Bba1 ^( Bbe1 | Bbi1 ); \ + E##ba1 ^= KeccakF1600RoundConstants_int2_1[i]; \ + Ca1 = E##ba1; \ + A##mo0 ^= Do0; \ + Bbo1 = ROL32(A##mo0, 10); \ + E##be1 = Bbe1 ^((~Bbi1)| Bbo1 ); \ + Ce1 = E##be1; \ + A##su1 ^= Du1; \ + Bbu1 = ROL32(A##su1, 7); \ + E##bi1 = Bbi1 ^( Bbo1 & Bbu1 ); \ + Ci1 = E##bi1; \ + E##bo1 = Bbo1 ^( Bbu1 | Bba1 ); \ + Co1 = E##bo1; \ + E##bu1 = Bbu1 ^( Bba1 & Bbe1 ); \ + Cu1 = E##bu1; \ +\ + A##bo0 ^= Do0; \ + Bga0 = ROL32(A##bo0, 14); \ + A##gu0 ^= Du0; \ + Bge0 = ROL32(A##gu0, 10); \ + A##ka1 ^= Da1; \ + Bgi0 = ROL32(A##ka1, 2); \ + E##ga0 = Bga0 ^( Bge0 | Bgi0 ); \ + Ca0 ^= E##ga0; \ + A##me1 ^= De1; \ + Bgo0 = ROL32(A##me1, 23); \ + E##ge0 = Bge0 ^( Bgi0 & Bgo0 ); \ + Ce0 ^= E##ge0; \ + A##si1 ^= Di1; \ + Bgu0 = ROL32(A##si1, 31); \ + E##gi0 = Bgi0 ^( Bgo0 |(~Bgu0)); \ + Ci0 ^= E##gi0; \ + E##go0 = Bgo0 ^( Bgu0 | Bga0 ); \ + Co0 ^= E##go0; \ + E##gu0 = Bgu0 ^( Bga0 & Bge0 ); \ + Cu0 ^= E##gu0; \ +\ + A##bo1 ^= Do1; \ + Bga1 = ROL32(A##bo1, 14); \ + A##gu1 ^= Du1; \ + Bge1 = ROL32(A##gu1, 10); \ + A##ka0 ^= Da0; \ + Bgi1 = ROL32(A##ka0, 1); \ + E##ga1 = Bga1 ^( Bge1 | Bgi1 ); \ + Ca1 ^= E##ga1; \ + A##me0 ^= De0; \ + Bgo1 = ROL32(A##me0, 22); \ + E##ge1 = Bge1 ^( Bgi1 & Bgo1 ); \ + Ce1 ^= E##ge1; \ + A##si0 ^= Di0; \ + Bgu1 = ROL32(A##si0, 30); \ + E##gi1 = Bgi1 ^( Bgo1 |(~Bgu1)); \ + Ci1 ^= E##gi1; \ + E##go1 = Bgo1 ^( Bgu1 | Bga1 ); \ + Co1 ^= E##go1; \ + E##gu1 = Bgu1 ^( Bga1 & Bge1 ); \ + Cu1 ^= E##gu1; \ +\ + A##be1 ^= De1; \ + Bka0 = ROL32(A##be1, 1); \ + A##gi0 ^= Di0; \ + Bke0 = ROL32(A##gi0, 3); \ + A##ko1 ^= Do1; \ + Bki0 = ROL32(A##ko1, 13); \ + E##ka0 = Bka0 ^( Bke0 | Bki0 ); \ + Ca0 ^= E##ka0; \ + A##mu0 ^= Du0; \ + Bko0 = ROL32(A##mu0, 4); \ + E##ke0 = Bke0 ^( Bki0 & Bko0 ); \ + Ce0 ^= E##ke0; \ + A##sa0 ^= Da0; \ + Bku0 = ROL32(A##sa0, 9); \ + E##ki0 = Bki0 ^((~Bko0)& Bku0 ); \ + Ci0 ^= E##ki0; \ + E##ko0 = (~Bko0)^( Bku0 | Bka0 ); \ + Co0 ^= E##ko0; \ + E##ku0 = Bku0 ^( Bka0 & Bke0 ); \ + Cu0 ^= E##ku0; \ +\ + A##be0 ^= De0; \ + Bka1 = A##be0; \ + A##gi1 ^= Di1; \ + Bke1 = ROL32(A##gi1, 3); \ + A##ko0 ^= Do0; \ + Bki1 = ROL32(A##ko0, 12); \ + E##ka1 = Bka1 ^( Bke1 | Bki1 ); \ + Ca1 ^= E##ka1; \ + A##mu1 ^= Du1; \ + Bko1 = ROL32(A##mu1, 4); \ + E##ke1 = Bke1 ^( Bki1 & Bko1 ); \ + Ce1 ^= E##ke1; \ + A##sa1 ^= Da1; \ + Bku1 = ROL32(A##sa1, 9); \ + E##ki1 = Bki1 ^((~Bko1)& Bku1 ); \ + Ci1 ^= E##ki1; \ + E##ko1 = (~Bko1)^( Bku1 | Bka1 ); \ + Co1 ^= E##ko1; \ + E##ku1 = Bku1 ^( Bka1 & Bke1 ); \ + Cu1 ^= E##ku1; \ +\ + A##bu1 ^= Du1; \ + Bma0 = ROL32(A##bu1, 14); \ + A##ga0 ^= Da0; \ + Bme0 = ROL32(A##ga0, 18); \ + A##ke0 ^= De0; \ + Bmi0 = ROL32(A##ke0, 5); \ + E##ma0 = Bma0 ^( Bme0 & Bmi0 ); \ + Ca0 ^= E##ma0; \ + A##mi1 ^= Di1; \ + Bmo0 = ROL32(A##mi1, 8); \ + E##me0 = Bme0 ^( Bmi0 | Bmo0 ); \ + Ce0 ^= E##me0; \ + A##so0 ^= Do0; \ + Bmu0 = ROL32(A##so0, 28); \ + E##mi0 = Bmi0 ^((~Bmo0)| Bmu0 ); \ + Ci0 ^= E##mi0; \ + E##mo0 = (~Bmo0)^( Bmu0 & Bma0 ); \ + Co0 ^= E##mo0; \ + E##mu0 = Bmu0 ^( Bma0 | Bme0 ); \ + Cu0 ^= E##mu0; \ +\ + A##bu0 ^= Du0; \ + Bma1 = ROL32(A##bu0, 13); \ + A##ga1 ^= Da1; \ + Bme1 = ROL32(A##ga1, 18); \ + A##ke1 ^= De1; \ + Bmi1 = ROL32(A##ke1, 5); \ + E##ma1 = Bma1 ^( Bme1 & Bmi1 ); \ + Ca1 ^= E##ma1; \ + A##mi0 ^= Di0; \ + Bmo1 = ROL32(A##mi0, 7); \ + E##me1 = Bme1 ^( Bmi1 | Bmo1 ); \ + Ce1 ^= E##me1; \ + A##so1 ^= Do1; \ + Bmu1 = ROL32(A##so1, 28); \ + E##mi1 = Bmi1 ^((~Bmo1)| Bmu1 ); \ + Ci1 ^= E##mi1; \ + E##mo1 = (~Bmo1)^( Bmu1 & Bma1 ); \ + Co1 ^= E##mo1; \ + E##mu1 = Bmu1 ^( Bma1 | Bme1 ); \ + Cu1 ^= E##mu1; \ +\ + A##bi0 ^= Di0; \ + Bsa0 = ROL32(A##bi0, 31); \ + A##go1 ^= Do1; \ + Bse0 = ROL32(A##go1, 28); \ + A##ku1 ^= Du1; \ + Bsi0 = ROL32(A##ku1, 20); \ + E##sa0 = Bsa0 ^((~Bse0)& Bsi0 ); \ + Ca0 ^= E##sa0; \ + A##ma1 ^= Da1; \ + Bso0 = ROL32(A##ma1, 21); \ + E##se0 = (~Bse0)^( Bsi0 | Bso0 ); \ + Ce0 ^= E##se0; \ + A##se0 ^= De0; \ + Bsu0 = ROL32(A##se0, 1); \ + E##si0 = Bsi0 ^( Bso0 & Bsu0 ); \ + Ci0 ^= E##si0; \ + E##so0 = Bso0 ^( Bsu0 | Bsa0 ); \ + Co0 ^= E##so0; \ + E##su0 = Bsu0 ^( Bsa0 & Bse0 ); \ + Cu0 ^= E##su0; \ +\ + A##bi1 ^= Di1; \ + Bsa1 = ROL32(A##bi1, 31); \ + A##go0 ^= Do0; \ + Bse1 = ROL32(A##go0, 27); \ + A##ku0 ^= Du0; \ + Bsi1 = ROL32(A##ku0, 19); \ + E##sa1 = Bsa1 ^((~Bse1)& Bsi1 ); \ + Ca1 ^= E##sa1; \ + A##ma0 ^= Da0; \ + Bso1 = ROL32(A##ma0, 20); \ + E##se1 = (~Bse1)^( Bsi1 | Bso1 ); \ + Ce1 ^= E##se1; \ + A##se1 ^= De1; \ + Bsu1 = ROL32(A##se1, 1); \ + E##si1 = Bsi1 ^( Bso1 & Bsu1 ); \ + Ci1 ^= E##si1; \ + E##so1 = Bso1 ^( Bsu1 | Bsa1 ); \ + Co1 ^= E##so1; \ + E##su1 = Bsu1 ^( Bsa1 & Bse1 ); \ + Cu1 ^= E##su1; \ +\ + +// --- Code for round (lane complementing pattern 'bebigokimisa') +// --- using factor 2 interleaving, 64-bit lanes mapped to 32-bit words +#define thetaRhoPiChiIota(i, A, E) \ + Da0 = Cu0^ROL32(Ce1, 1); \ + Da1 = Cu1^Ce0; \ + De0 = Ca0^ROL32(Ci1, 1); \ + De1 = Ca1^Ci0; \ + Di0 = Ce0^ROL32(Co1, 1); \ + Di1 = Ce1^Co0; \ + Do0 = Ci0^ROL32(Cu1, 1); \ + Do1 = Ci1^Cu0; \ + Du0 = Co0^ROL32(Ca1, 1); \ + Du1 = Co1^Ca0; \ +\ + A##ba0 ^= Da0; \ + Bba0 = A##ba0; \ + A##ge0 ^= De0; \ + Bbe0 = ROL32(A##ge0, 22); \ + A##ki1 ^= Di1; \ + Bbi0 = ROL32(A##ki1, 22); \ + E##ba0 = Bba0 ^( Bbe0 | Bbi0 ); \ + E##ba0 ^= KeccakF1600RoundConstants_int2_0[i]; \ + A##mo1 ^= Do1; \ + Bbo0 = ROL32(A##mo1, 11); \ + E##be0 = Bbe0 ^((~Bbi0)| Bbo0 ); \ + A##su0 ^= Du0; \ + Bbu0 = ROL32(A##su0, 7); \ + E##bi0 = Bbi0 ^( Bbo0 & Bbu0 ); \ + E##bo0 = Bbo0 ^( Bbu0 | Bba0 ); \ + E##bu0 = Bbu0 ^( Bba0 & Bbe0 ); \ +\ + A##ba1 ^= Da1; \ + Bba1 = A##ba1; \ + A##ge1 ^= De1; \ + Bbe1 = ROL32(A##ge1, 22); \ + A##ki0 ^= Di0; \ + Bbi1 = ROL32(A##ki0, 21); \ + E##ba1 = Bba1 ^( Bbe1 | Bbi1 ); \ + E##ba1 ^= KeccakF1600RoundConstants_int2_1[i]; \ + A##mo0 ^= Do0; \ + Bbo1 = ROL32(A##mo0, 10); \ + E##be1 = Bbe1 ^((~Bbi1)| Bbo1 ); \ + A##su1 ^= Du1; \ + Bbu1 = ROL32(A##su1, 7); \ + E##bi1 = Bbi1 ^( Bbo1 & Bbu1 ); \ + E##bo1 = Bbo1 ^( Bbu1 | Bba1 ); \ + E##bu1 = Bbu1 ^( Bba1 & Bbe1 ); \ +\ + A##bo0 ^= Do0; \ + Bga0 = ROL32(A##bo0, 14); \ + A##gu0 ^= Du0; \ + Bge0 = ROL32(A##gu0, 10); \ + A##ka1 ^= Da1; \ + Bgi0 = ROL32(A##ka1, 2); \ + E##ga0 = Bga0 ^( Bge0 | Bgi0 ); \ + A##me1 ^= De1; \ + Bgo0 = ROL32(A##me1, 23); \ + E##ge0 = Bge0 ^( Bgi0 & Bgo0 ); \ + A##si1 ^= Di1; \ + Bgu0 = ROL32(A##si1, 31); \ + E##gi0 = Bgi0 ^( Bgo0 |(~Bgu0)); \ + E##go0 = Bgo0 ^( Bgu0 | Bga0 ); \ + E##gu0 = Bgu0 ^( Bga0 & Bge0 ); \ +\ + A##bo1 ^= Do1; \ + Bga1 = ROL32(A##bo1, 14); \ + A##gu1 ^= Du1; \ + Bge1 = ROL32(A##gu1, 10); \ + A##ka0 ^= Da0; \ + Bgi1 = ROL32(A##ka0, 1); \ + E##ga1 = Bga1 ^( Bge1 | Bgi1 ); \ + A##me0 ^= De0; \ + Bgo1 = ROL32(A##me0, 22); \ + E##ge1 = Bge1 ^( Bgi1 & Bgo1 ); \ + A##si0 ^= Di0; \ + Bgu1 = ROL32(A##si0, 30); \ + E##gi1 = Bgi1 ^( Bgo1 |(~Bgu1)); \ + E##go1 = Bgo1 ^( Bgu1 | Bga1 ); \ + E##gu1 = Bgu1 ^( Bga1 & Bge1 ); \ +\ + A##be1 ^= De1; \ + Bka0 = ROL32(A##be1, 1); \ + A##gi0 ^= Di0; \ + Bke0 = ROL32(A##gi0, 3); \ + A##ko1 ^= Do1; \ + Bki0 = ROL32(A##ko1, 13); \ + E##ka0 = Bka0 ^( Bke0 | Bki0 ); \ + A##mu0 ^= Du0; \ + Bko0 = ROL32(A##mu0, 4); \ + E##ke0 = Bke0 ^( Bki0 & Bko0 ); \ + A##sa0 ^= Da0; \ + Bku0 = ROL32(A##sa0, 9); \ + E##ki0 = Bki0 ^((~Bko0)& Bku0 ); \ + E##ko0 = (~Bko0)^( Bku0 | Bka0 ); \ + E##ku0 = Bku0 ^( Bka0 & Bke0 ); \ +\ + A##be0 ^= De0; \ + Bka1 = A##be0; \ + A##gi1 ^= Di1; \ + Bke1 = ROL32(A##gi1, 3); \ + A##ko0 ^= Do0; \ + Bki1 = ROL32(A##ko0, 12); \ + E##ka1 = Bka1 ^( Bke1 | Bki1 ); \ + A##mu1 ^= Du1; \ + Bko1 = ROL32(A##mu1, 4); \ + E##ke1 = Bke1 ^( Bki1 & Bko1 ); \ + A##sa1 ^= Da1; \ + Bku1 = ROL32(A##sa1, 9); \ + E##ki1 = Bki1 ^((~Bko1)& Bku1 ); \ + E##ko1 = (~Bko1)^( Bku1 | Bka1 ); \ + E##ku1 = Bku1 ^( Bka1 & Bke1 ); \ +\ + A##bu1 ^= Du1; \ + Bma0 = ROL32(A##bu1, 14); \ + A##ga0 ^= Da0; \ + Bme0 = ROL32(A##ga0, 18); \ + A##ke0 ^= De0; \ + Bmi0 = ROL32(A##ke0, 5); \ + E##ma0 = Bma0 ^( Bme0 & Bmi0 ); \ + A##mi1 ^= Di1; \ + Bmo0 = ROL32(A##mi1, 8); \ + E##me0 = Bme0 ^( Bmi0 | Bmo0 ); \ + A##so0 ^= Do0; \ + Bmu0 = ROL32(A##so0, 28); \ + E##mi0 = Bmi0 ^((~Bmo0)| Bmu0 ); \ + E##mo0 = (~Bmo0)^( Bmu0 & Bma0 ); \ + E##mu0 = Bmu0 ^( Bma0 | Bme0 ); \ +\ + A##bu0 ^= Du0; \ + Bma1 = ROL32(A##bu0, 13); \ + A##ga1 ^= Da1; \ + Bme1 = ROL32(A##ga1, 18); \ + A##ke1 ^= De1; \ + Bmi1 = ROL32(A##ke1, 5); \ + E##ma1 = Bma1 ^( Bme1 & Bmi1 ); \ + A##mi0 ^= Di0; \ + Bmo1 = ROL32(A##mi0, 7); \ + E##me1 = Bme1 ^( Bmi1 | Bmo1 ); \ + A##so1 ^= Do1; \ + Bmu1 = ROL32(A##so1, 28); \ + E##mi1 = Bmi1 ^((~Bmo1)| Bmu1 ); \ + E##mo1 = (~Bmo1)^( Bmu1 & Bma1 ); \ + E##mu1 = Bmu1 ^( Bma1 | Bme1 ); \ +\ + A##bi0 ^= Di0; \ + Bsa0 = ROL32(A##bi0, 31); \ + A##go1 ^= Do1; \ + Bse0 = ROL32(A##go1, 28); \ + A##ku1 ^= Du1; \ + Bsi0 = ROL32(A##ku1, 20); \ + E##sa0 = Bsa0 ^((~Bse0)& Bsi0 ); \ + A##ma1 ^= Da1; \ + Bso0 = ROL32(A##ma1, 21); \ + E##se0 = (~Bse0)^( Bsi0 | Bso0 ); \ + A##se0 ^= De0; \ + Bsu0 = ROL32(A##se0, 1); \ + E##si0 = Bsi0 ^( Bso0 & Bsu0 ); \ + E##so0 = Bso0 ^( Bsu0 | Bsa0 ); \ + E##su0 = Bsu0 ^( Bsa0 & Bse0 ); \ +\ + A##bi1 ^= Di1; \ + Bsa1 = ROL32(A##bi1, 31); \ + A##go0 ^= Do0; \ + Bse1 = ROL32(A##go0, 27); \ + A##ku0 ^= Du0; \ + Bsi1 = ROL32(A##ku0, 19); \ + E##sa1 = Bsa1 ^((~Bse1)& Bsi1 ); \ + A##ma0 ^= Da0; \ + Bso1 = ROL32(A##ma0, 20); \ + E##se1 = (~Bse1)^( Bsi1 | Bso1 ); \ + A##se1 ^= De1; \ + Bsu1 = ROL32(A##se1, 1); \ + E##si1 = Bsi1 ^( Bso1 & Bsu1 ); \ + E##so1 = Bso1 ^( Bsu1 | Bsa1 ); \ + E##su1 = Bsu1 ^( Bsa1 & Bse1 ); \ +\ + +#else // UseBebigokimisa +// --- Code for round, with prepare-theta +// --- using factor 2 interleaving, 64-bit lanes mapped to 32-bit words +#define thetaRhoPiChiIotaPrepareTheta(i, A, E) \ + Da0 = Cu0^ROL32(Ce1, 1); \ + Da1 = Cu1^Ce0; \ + De0 = Ca0^ROL32(Ci1, 1); \ + De1 = Ca1^Ci0; \ + Di0 = Ce0^ROL32(Co1, 1); \ + Di1 = Ce1^Co0; \ + Do0 = Ci0^ROL32(Cu1, 1); \ + Do1 = Ci1^Cu0; \ + Du0 = Co0^ROL32(Ca1, 1); \ + Du1 = Co1^Ca0; \ +\ + A##ba0 ^= Da0; \ + Bba0 = A##ba0; \ + A##ge0 ^= De0; \ + Bbe0 = ROL32(A##ge0, 22); \ + A##ki1 ^= Di1; \ + Bbi0 = ROL32(A##ki1, 22); \ + E##ba0 = Bba0 ^((~Bbe0)& Bbi0 ); \ + E##ba0 ^= KeccakF1600RoundConstants_int2_0[i]; \ + Ca0 = E##ba0; \ + A##mo1 ^= Do1; \ + Bbo0 = ROL32(A##mo1, 11); \ + E##be0 = Bbe0 ^((~Bbi0)& Bbo0 ); \ + Ce0 = E##be0; \ + A##su0 ^= Du0; \ + Bbu0 = ROL32(A##su0, 7); \ + E##bi0 = Bbi0 ^((~Bbo0)& Bbu0 ); \ + Ci0 = E##bi0; \ + E##bo0 = Bbo0 ^((~Bbu0)& Bba0 ); \ + Co0 = E##bo0; \ + E##bu0 = Bbu0 ^((~Bba0)& Bbe0 ); \ + Cu0 = E##bu0; \ +\ + A##ba1 ^= Da1; \ + Bba1 = A##ba1; \ + A##ge1 ^= De1; \ + Bbe1 = ROL32(A##ge1, 22); \ + A##ki0 ^= Di0; \ + Bbi1 = ROL32(A##ki0, 21); \ + E##ba1 = Bba1 ^((~Bbe1)& Bbi1 ); \ + E##ba1 ^= KeccakF1600RoundConstants_int2_1[i]; \ + Ca1 = E##ba1; \ + A##mo0 ^= Do0; \ + Bbo1 = ROL32(A##mo0, 10); \ + E##be1 = Bbe1 ^((~Bbi1)& Bbo1 ); \ + Ce1 = E##be1; \ + A##su1 ^= Du1; \ + Bbu1 = ROL32(A##su1, 7); \ + E##bi1 = Bbi1 ^((~Bbo1)& Bbu1 ); \ + Ci1 = E##bi1; \ + E##bo1 = Bbo1 ^((~Bbu1)& Bba1 ); \ + Co1 = E##bo1; \ + E##bu1 = Bbu1 ^((~Bba1)& Bbe1 ); \ + Cu1 = E##bu1; \ +\ + A##bo0 ^= Do0; \ + Bga0 = ROL32(A##bo0, 14); \ + A##gu0 ^= Du0; \ + Bge0 = ROL32(A##gu0, 10); \ + A##ka1 ^= Da1; \ + Bgi0 = ROL32(A##ka1, 2); \ + E##ga0 = Bga0 ^((~Bge0)& Bgi0 ); \ + Ca0 ^= E##ga0; \ + A##me1 ^= De1; \ + Bgo0 = ROL32(A##me1, 23); \ + E##ge0 = Bge0 ^((~Bgi0)& Bgo0 ); \ + Ce0 ^= E##ge0; \ + A##si1 ^= Di1; \ + Bgu0 = ROL32(A##si1, 31); \ + E##gi0 = Bgi0 ^((~Bgo0)& Bgu0 ); \ + Ci0 ^= E##gi0; \ + E##go0 = Bgo0 ^((~Bgu0)& Bga0 ); \ + Co0 ^= E##go0; \ + E##gu0 = Bgu0 ^((~Bga0)& Bge0 ); \ + Cu0 ^= E##gu0; \ +\ + A##bo1 ^= Do1; \ + Bga1 = ROL32(A##bo1, 14); \ + A##gu1 ^= Du1; \ + Bge1 = ROL32(A##gu1, 10); \ + A##ka0 ^= Da0; \ + Bgi1 = ROL32(A##ka0, 1); \ + E##ga1 = Bga1 ^((~Bge1)& Bgi1 ); \ + Ca1 ^= E##ga1; \ + A##me0 ^= De0; \ + Bgo1 = ROL32(A##me0, 22); \ + E##ge1 = Bge1 ^((~Bgi1)& Bgo1 ); \ + Ce1 ^= E##ge1; \ + A##si0 ^= Di0; \ + Bgu1 = ROL32(A##si0, 30); \ + E##gi1 = Bgi1 ^((~Bgo1)& Bgu1 ); \ + Ci1 ^= E##gi1; \ + E##go1 = Bgo1 ^((~Bgu1)& Bga1 ); \ + Co1 ^= E##go1; \ + E##gu1 = Bgu1 ^((~Bga1)& Bge1 ); \ + Cu1 ^= E##gu1; \ +\ + A##be1 ^= De1; \ + Bka0 = ROL32(A##be1, 1); \ + A##gi0 ^= Di0; \ + Bke0 = ROL32(A##gi0, 3); \ + A##ko1 ^= Do1; \ + Bki0 = ROL32(A##ko1, 13); \ + E##ka0 = Bka0 ^((~Bke0)& Bki0 ); \ + Ca0 ^= E##ka0; \ + A##mu0 ^= Du0; \ + Bko0 = ROL32(A##mu0, 4); \ + E##ke0 = Bke0 ^((~Bki0)& Bko0 ); \ + Ce0 ^= E##ke0; \ + A##sa0 ^= Da0; \ + Bku0 = ROL32(A##sa0, 9); \ + E##ki0 = Bki0 ^((~Bko0)& Bku0 ); \ + Ci0 ^= E##ki0; \ + E##ko0 = Bko0 ^((~Bku0)& Bka0 ); \ + Co0 ^= E##ko0; \ + E##ku0 = Bku0 ^((~Bka0)& Bke0 ); \ + Cu0 ^= E##ku0; \ +\ + A##be0 ^= De0; \ + Bka1 = A##be0; \ + A##gi1 ^= Di1; \ + Bke1 = ROL32(A##gi1, 3); \ + A##ko0 ^= Do0; \ + Bki1 = ROL32(A##ko0, 12); \ + E##ka1 = Bka1 ^((~Bke1)& Bki1 ); \ + Ca1 ^= E##ka1; \ + A##mu1 ^= Du1; \ + Bko1 = ROL32(A##mu1, 4); \ + E##ke1 = Bke1 ^((~Bki1)& Bko1 ); \ + Ce1 ^= E##ke1; \ + A##sa1 ^= Da1; \ + Bku1 = ROL32(A##sa1, 9); \ + E##ki1 = Bki1 ^((~Bko1)& Bku1 ); \ + Ci1 ^= E##ki1; \ + E##ko1 = Bko1 ^((~Bku1)& Bka1 ); \ + Co1 ^= E##ko1; \ + E##ku1 = Bku1 ^((~Bka1)& Bke1 ); \ + Cu1 ^= E##ku1; \ +\ + A##bu1 ^= Du1; \ + Bma0 = ROL32(A##bu1, 14); \ + A##ga0 ^= Da0; \ + Bme0 = ROL32(A##ga0, 18); \ + A##ke0 ^= De0; \ + Bmi0 = ROL32(A##ke0, 5); \ + E##ma0 = Bma0 ^((~Bme0)& Bmi0 ); \ + Ca0 ^= E##ma0; \ + A##mi1 ^= Di1; \ + Bmo0 = ROL32(A##mi1, 8); \ + E##me0 = Bme0 ^((~Bmi0)& Bmo0 ); \ + Ce0 ^= E##me0; \ + A##so0 ^= Do0; \ + Bmu0 = ROL32(A##so0, 28); \ + E##mi0 = Bmi0 ^((~Bmo0)& Bmu0 ); \ + Ci0 ^= E##mi0; \ + E##mo0 = Bmo0 ^((~Bmu0)& Bma0 ); \ + Co0 ^= E##mo0; \ + E##mu0 = Bmu0 ^((~Bma0)& Bme0 ); \ + Cu0 ^= E##mu0; \ +\ + A##bu0 ^= Du0; \ + Bma1 = ROL32(A##bu0, 13); \ + A##ga1 ^= Da1; \ + Bme1 = ROL32(A##ga1, 18); \ + A##ke1 ^= De1; \ + Bmi1 = ROL32(A##ke1, 5); \ + E##ma1 = Bma1 ^((~Bme1)& Bmi1 ); \ + Ca1 ^= E##ma1; \ + A##mi0 ^= Di0; \ + Bmo1 = ROL32(A##mi0, 7); \ + E##me1 = Bme1 ^((~Bmi1)& Bmo1 ); \ + Ce1 ^= E##me1; \ + A##so1 ^= Do1; \ + Bmu1 = ROL32(A##so1, 28); \ + E##mi1 = Bmi1 ^((~Bmo1)& Bmu1 ); \ + Ci1 ^= E##mi1; \ + E##mo1 = Bmo1 ^((~Bmu1)& Bma1 ); \ + Co1 ^= E##mo1; \ + E##mu1 = Bmu1 ^((~Bma1)& Bme1 ); \ + Cu1 ^= E##mu1; \ +\ + A##bi0 ^= Di0; \ + Bsa0 = ROL32(A##bi0, 31); \ + A##go1 ^= Do1; \ + Bse0 = ROL32(A##go1, 28); \ + A##ku1 ^= Du1; \ + Bsi0 = ROL32(A##ku1, 20); \ + E##sa0 = Bsa0 ^((~Bse0)& Bsi0 ); \ + Ca0 ^= E##sa0; \ + A##ma1 ^= Da1; \ + Bso0 = ROL32(A##ma1, 21); \ + E##se0 = Bse0 ^((~Bsi0)& Bso0 ); \ + Ce0 ^= E##se0; \ + A##se0 ^= De0; \ + Bsu0 = ROL32(A##se0, 1); \ + E##si0 = Bsi0 ^((~Bso0)& Bsu0 ); \ + Ci0 ^= E##si0; \ + E##so0 = Bso0 ^((~Bsu0)& Bsa0 ); \ + Co0 ^= E##so0; \ + E##su0 = Bsu0 ^((~Bsa0)& Bse0 ); \ + Cu0 ^= E##su0; \ +\ + A##bi1 ^= Di1; \ + Bsa1 = ROL32(A##bi1, 31); \ + A##go0 ^= Do0; \ + Bse1 = ROL32(A##go0, 27); \ + A##ku0 ^= Du0; \ + Bsi1 = ROL32(A##ku0, 19); \ + E##sa1 = Bsa1 ^((~Bse1)& Bsi1 ); \ + Ca1 ^= E##sa1; \ + A##ma0 ^= Da0; \ + Bso1 = ROL32(A##ma0, 20); \ + E##se1 = Bse1 ^((~Bsi1)& Bso1 ); \ + Ce1 ^= E##se1; \ + A##se1 ^= De1; \ + Bsu1 = ROL32(A##se1, 1); \ + E##si1 = Bsi1 ^((~Bso1)& Bsu1 ); \ + Ci1 ^= E##si1; \ + E##so1 = Bso1 ^((~Bsu1)& Bsa1 ); \ + Co1 ^= E##so1; \ + E##su1 = Bsu1 ^((~Bsa1)& Bse1 ); \ + Cu1 ^= E##su1; \ +\ + +// --- Code for round +// --- using factor 2 interleaving, 64-bit lanes mapped to 32-bit words +#define thetaRhoPiChiIota(i, A, E) \ + Da0 = Cu0^ROL32(Ce1, 1); \ + Da1 = Cu1^Ce0; \ + De0 = Ca0^ROL32(Ci1, 1); \ + De1 = Ca1^Ci0; \ + Di0 = Ce0^ROL32(Co1, 1); \ + Di1 = Ce1^Co0; \ + Do0 = Ci0^ROL32(Cu1, 1); \ + Do1 = Ci1^Cu0; \ + Du0 = Co0^ROL32(Ca1, 1); \ + Du1 = Co1^Ca0; \ +\ + A##ba0 ^= Da0; \ + Bba0 = A##ba0; \ + A##ge0 ^= De0; \ + Bbe0 = ROL32(A##ge0, 22); \ + A##ki1 ^= Di1; \ + Bbi0 = ROL32(A##ki1, 22); \ + E##ba0 = Bba0 ^((~Bbe0)& Bbi0 ); \ + E##ba0 ^= KeccakF1600RoundConstants_int2_0[i]; \ + A##mo1 ^= Do1; \ + Bbo0 = ROL32(A##mo1, 11); \ + E##be0 = Bbe0 ^((~Bbi0)& Bbo0 ); \ + A##su0 ^= Du0; \ + Bbu0 = ROL32(A##su0, 7); \ + E##bi0 = Bbi0 ^((~Bbo0)& Bbu0 ); \ + E##bo0 = Bbo0 ^((~Bbu0)& Bba0 ); \ + E##bu0 = Bbu0 ^((~Bba0)& Bbe0 ); \ +\ + A##ba1 ^= Da1; \ + Bba1 = A##ba1; \ + A##ge1 ^= De1; \ + Bbe1 = ROL32(A##ge1, 22); \ + A##ki0 ^= Di0; \ + Bbi1 = ROL32(A##ki0, 21); \ + E##ba1 = Bba1 ^((~Bbe1)& Bbi1 ); \ + E##ba1 ^= KeccakF1600RoundConstants_int2_1[i]; \ + A##mo0 ^= Do0; \ + Bbo1 = ROL32(A##mo0, 10); \ + E##be1 = Bbe1 ^((~Bbi1)& Bbo1 ); \ + A##su1 ^= Du1; \ + Bbu1 = ROL32(A##su1, 7); \ + E##bi1 = Bbi1 ^((~Bbo1)& Bbu1 ); \ + E##bo1 = Bbo1 ^((~Bbu1)& Bba1 ); \ + E##bu1 = Bbu1 ^((~Bba1)& Bbe1 ); \ +\ + A##bo0 ^= Do0; \ + Bga0 = ROL32(A##bo0, 14); \ + A##gu0 ^= Du0; \ + Bge0 = ROL32(A##gu0, 10); \ + A##ka1 ^= Da1; \ + Bgi0 = ROL32(A##ka1, 2); \ + E##ga0 = Bga0 ^((~Bge0)& Bgi0 ); \ + A##me1 ^= De1; \ + Bgo0 = ROL32(A##me1, 23); \ + E##ge0 = Bge0 ^((~Bgi0)& Bgo0 ); \ + A##si1 ^= Di1; \ + Bgu0 = ROL32(A##si1, 31); \ + E##gi0 = Bgi0 ^((~Bgo0)& Bgu0 ); \ + E##go0 = Bgo0 ^((~Bgu0)& Bga0 ); \ + E##gu0 = Bgu0 ^((~Bga0)& Bge0 ); \ +\ + A##bo1 ^= Do1; \ + Bga1 = ROL32(A##bo1, 14); \ + A##gu1 ^= Du1; \ + Bge1 = ROL32(A##gu1, 10); \ + A##ka0 ^= Da0; \ + Bgi1 = ROL32(A##ka0, 1); \ + E##ga1 = Bga1 ^((~Bge1)& Bgi1 ); \ + A##me0 ^= De0; \ + Bgo1 = ROL32(A##me0, 22); \ + E##ge1 = Bge1 ^((~Bgi1)& Bgo1 ); \ + A##si0 ^= Di0; \ + Bgu1 = ROL32(A##si0, 30); \ + E##gi1 = Bgi1 ^((~Bgo1)& Bgu1 ); \ + E##go1 = Bgo1 ^((~Bgu1)& Bga1 ); \ + E##gu1 = Bgu1 ^((~Bga1)& Bge1 ); \ +\ + A##be1 ^= De1; \ + Bka0 = ROL32(A##be1, 1); \ + A##gi0 ^= Di0; \ + Bke0 = ROL32(A##gi0, 3); \ + A##ko1 ^= Do1; \ + Bki0 = ROL32(A##ko1, 13); \ + E##ka0 = Bka0 ^((~Bke0)& Bki0 ); \ + A##mu0 ^= Du0; \ + Bko0 = ROL32(A##mu0, 4); \ + E##ke0 = Bke0 ^((~Bki0)& Bko0 ); \ + A##sa0 ^= Da0; \ + Bku0 = ROL32(A##sa0, 9); \ + E##ki0 = Bki0 ^((~Bko0)& Bku0 ); \ + E##ko0 = Bko0 ^((~Bku0)& Bka0 ); \ + E##ku0 = Bku0 ^((~Bka0)& Bke0 ); \ +\ + A##be0 ^= De0; \ + Bka1 = A##be0; \ + A##gi1 ^= Di1; \ + Bke1 = ROL32(A##gi1, 3); \ + A##ko0 ^= Do0; \ + Bki1 = ROL32(A##ko0, 12); \ + E##ka1 = Bka1 ^((~Bke1)& Bki1 ); \ + A##mu1 ^= Du1; \ + Bko1 = ROL32(A##mu1, 4); \ + E##ke1 = Bke1 ^((~Bki1)& Bko1 ); \ + A##sa1 ^= Da1; \ + Bku1 = ROL32(A##sa1, 9); \ + E##ki1 = Bki1 ^((~Bko1)& Bku1 ); \ + E##ko1 = Bko1 ^((~Bku1)& Bka1 ); \ + E##ku1 = Bku1 ^((~Bka1)& Bke1 ); \ +\ + A##bu1 ^= Du1; \ + Bma0 = ROL32(A##bu1, 14); \ + A##ga0 ^= Da0; \ + Bme0 = ROL32(A##ga0, 18); \ + A##ke0 ^= De0; \ + Bmi0 = ROL32(A##ke0, 5); \ + E##ma0 = Bma0 ^((~Bme0)& Bmi0 ); \ + A##mi1 ^= Di1; \ + Bmo0 = ROL32(A##mi1, 8); \ + E##me0 = Bme0 ^((~Bmi0)& Bmo0 ); \ + A##so0 ^= Do0; \ + Bmu0 = ROL32(A##so0, 28); \ + E##mi0 = Bmi0 ^((~Bmo0)& Bmu0 ); \ + E##mo0 = Bmo0 ^((~Bmu0)& Bma0 ); \ + E##mu0 = Bmu0 ^((~Bma0)& Bme0 ); \ +\ + A##bu0 ^= Du0; \ + Bma1 = ROL32(A##bu0, 13); \ + A##ga1 ^= Da1; \ + Bme1 = ROL32(A##ga1, 18); \ + A##ke1 ^= De1; \ + Bmi1 = ROL32(A##ke1, 5); \ + E##ma1 = Bma1 ^((~Bme1)& Bmi1 ); \ + A##mi0 ^= Di0; \ + Bmo1 = ROL32(A##mi0, 7); \ + E##me1 = Bme1 ^((~Bmi1)& Bmo1 ); \ + A##so1 ^= Do1; \ + Bmu1 = ROL32(A##so1, 28); \ + E##mi1 = Bmi1 ^((~Bmo1)& Bmu1 ); \ + E##mo1 = Bmo1 ^((~Bmu1)& Bma1 ); \ + E##mu1 = Bmu1 ^((~Bma1)& Bme1 ); \ +\ + A##bi0 ^= Di0; \ + Bsa0 = ROL32(A##bi0, 31); \ + A##go1 ^= Do1; \ + Bse0 = ROL32(A##go1, 28); \ + A##ku1 ^= Du1; \ + Bsi0 = ROL32(A##ku1, 20); \ + E##sa0 = Bsa0 ^((~Bse0)& Bsi0 ); \ + A##ma1 ^= Da1; \ + Bso0 = ROL32(A##ma1, 21); \ + E##se0 = Bse0 ^((~Bsi0)& Bso0 ); \ + A##se0 ^= De0; \ + Bsu0 = ROL32(A##se0, 1); \ + E##si0 = Bsi0 ^((~Bso0)& Bsu0 ); \ + E##so0 = Bso0 ^((~Bsu0)& Bsa0 ); \ + E##su0 = Bsu0 ^((~Bsa0)& Bse0 ); \ +\ + A##bi1 ^= Di1; \ + Bsa1 = ROL32(A##bi1, 31); \ + A##go0 ^= Do0; \ + Bse1 = ROL32(A##go0, 27); \ + A##ku0 ^= Du0; \ + Bsi1 = ROL32(A##ku0, 19); \ + E##sa1 = Bsa1 ^((~Bse1)& Bsi1 ); \ + A##ma0 ^= Da0; \ + Bso1 = ROL32(A##ma0, 20); \ + E##se1 = Bse1 ^((~Bsi1)& Bso1 ); \ + A##se1 ^= De1; \ + Bsu1 = ROL32(A##se1, 1); \ + E##si1 = Bsi1 ^((~Bso1)& Bsu1 ); \ + E##so1 = Bso1 ^((~Bsu1)& Bsa1 ); \ + E##su1 = Bsu1 ^((~Bsa1)& Bse1 ); \ +\ + +#endif // UseBebigokimisa + +const UINT32 KeccakF1600RoundConstants_int2_0[24] = { + 0x00000001UL, + 0x00000000UL, + 0x00000000UL, + 0x00000000UL, + 0x00000001UL, + 0x00000001UL, + 0x00000001UL, + 0x00000001UL, + 0x00000000UL, + 0x00000000UL, + 0x00000001UL, + 0x00000000UL, + 0x00000001UL, + 0x00000001UL, + 0x00000001UL, + 0x00000001UL, + 0x00000000UL, + 0x00000000UL, + 0x00000000UL, + 0x00000000UL, + 0x00000001UL, + 0x00000000UL, + 0x00000001UL, + 0x00000000UL }; + +const UINT32 KeccakF1600RoundConstants_int2_1[24] = { + 0x00000000UL, + 0x00000089UL, + 0x8000008bUL, + 0x80008080UL, + 0x0000008bUL, + 0x00008000UL, + 0x80008088UL, + 0x80000082UL, + 0x0000000bUL, + 0x0000000aUL, + 0x00008082UL, + 0x00008003UL, + 0x0000808bUL, + 0x8000000bUL, + 0x8000008aUL, + 0x80000081UL, + 0x80000081UL, + 0x80000008UL, + 0x00000083UL, + 0x80008003UL, + 0x80008088UL, + 0x80000088UL, + 0x00008000UL, + 0x80008082UL }; + +#define copyFromStateAndXor1024bits(X, state, input) \ + X##ba0 = state[ 0]^input[ 0]; \ + X##ba1 = state[ 1]^input[ 1]; \ + X##be0 = state[ 2]^input[ 2]; \ + X##be1 = state[ 3]^input[ 3]; \ + X##bi0 = state[ 4]^input[ 4]; \ + X##bi1 = state[ 5]^input[ 5]; \ + X##bo0 = state[ 6]^input[ 6]; \ + X##bo1 = state[ 7]^input[ 7]; \ + X##bu0 = state[ 8]^input[ 8]; \ + X##bu1 = state[ 9]^input[ 9]; \ + X##ga0 = state[10]^input[10]; \ + X##ga1 = state[11]^input[11]; \ + X##ge0 = state[12]^input[12]; \ + X##ge1 = state[13]^input[13]; \ + X##gi0 = state[14]^input[14]; \ + X##gi1 = state[15]^input[15]; \ + X##go0 = state[16]^input[16]; \ + X##go1 = state[17]^input[17]; \ + X##gu0 = state[18]^input[18]; \ + X##gu1 = state[19]^input[19]; \ + X##ka0 = state[20]^input[20]; \ + X##ka1 = state[21]^input[21]; \ + X##ke0 = state[22]^input[22]; \ + X##ke1 = state[23]^input[23]; \ + X##ki0 = state[24]^input[24]; \ + X##ki1 = state[25]^input[25]; \ + X##ko0 = state[26]^input[26]; \ + X##ko1 = state[27]^input[27]; \ + X##ku0 = state[28]^input[28]; \ + X##ku1 = state[29]^input[29]; \ + X##ma0 = state[30]^input[30]; \ + X##ma1 = state[31]^input[31]; \ + X##me0 = state[32]; \ + X##me1 = state[33]; \ + X##mi0 = state[34]; \ + X##mi1 = state[35]; \ + X##mo0 = state[36]; \ + X##mo1 = state[37]; \ + X##mu0 = state[38]; \ + X##mu1 = state[39]; \ + X##sa0 = state[40]; \ + X##sa1 = state[41]; \ + X##se0 = state[42]; \ + X##se1 = state[43]; \ + X##si0 = state[44]; \ + X##si1 = state[45]; \ + X##so0 = state[46]; \ + X##so1 = state[47]; \ + X##su0 = state[48]; \ + X##su1 = state[49]; \ + +#define copyFromStateAndXor1088bits(X, state, input) \ + X##ba0 = state[ 0]^input[ 0]; \ + X##ba1 = state[ 1]^input[ 1]; \ + X##be0 = state[ 2]^input[ 2]; \ + X##be1 = state[ 3]^input[ 3]; \ + X##bi0 = state[ 4]^input[ 4]; \ + X##bi1 = state[ 5]^input[ 5]; \ + X##bo0 = state[ 6]^input[ 6]; \ + X##bo1 = state[ 7]^input[ 7]; \ + X##bu0 = state[ 8]^input[ 8]; \ + X##bu1 = state[ 9]^input[ 9]; \ + X##ga0 = state[10]^input[10]; \ + X##ga1 = state[11]^input[11]; \ + X##ge0 = state[12]^input[12]; \ + X##ge1 = state[13]^input[13]; \ + X##gi0 = state[14]^input[14]; \ + X##gi1 = state[15]^input[15]; \ + X##go0 = state[16]^input[16]; \ + X##go1 = state[17]^input[17]; \ + X##gu0 = state[18]^input[18]; \ + X##gu1 = state[19]^input[19]; \ + X##ka0 = state[20]^input[20]; \ + X##ka1 = state[21]^input[21]; \ + X##ke0 = state[22]^input[22]; \ + X##ke1 = state[23]^input[23]; \ + X##ki0 = state[24]^input[24]; \ + X##ki1 = state[25]^input[25]; \ + X##ko0 = state[26]^input[26]; \ + X##ko1 = state[27]^input[27]; \ + X##ku0 = state[28]^input[28]; \ + X##ku1 = state[29]^input[29]; \ + X##ma0 = state[30]^input[30]; \ + X##ma1 = state[31]^input[31]; \ + X##me0 = state[32]^input[32]; \ + X##me1 = state[33]^input[33]; \ + X##mi0 = state[34]; \ + X##mi1 = state[35]; \ + X##mo0 = state[36]; \ + X##mo1 = state[37]; \ + X##mu0 = state[38]; \ + X##mu1 = state[39]; \ + X##sa0 = state[40]; \ + X##sa1 = state[41]; \ + X##se0 = state[42]; \ + X##se1 = state[43]; \ + X##si0 = state[44]; \ + X##si1 = state[45]; \ + X##so0 = state[46]; \ + X##so1 = state[47]; \ + X##su0 = state[48]; \ + X##su1 = state[49]; \ + +#define copyFromState(X, state) \ + X##ba0 = state[ 0]; \ + X##ba1 = state[ 1]; \ + X##be0 = state[ 2]; \ + X##be1 = state[ 3]; \ + X##bi0 = state[ 4]; \ + X##bi1 = state[ 5]; \ + X##bo0 = state[ 6]; \ + X##bo1 = state[ 7]; \ + X##bu0 = state[ 8]; \ + X##bu1 = state[ 9]; \ + X##ga0 = state[10]; \ + X##ga1 = state[11]; \ + X##ge0 = state[12]; \ + X##ge1 = state[13]; \ + X##gi0 = state[14]; \ + X##gi1 = state[15]; \ + X##go0 = state[16]; \ + X##go1 = state[17]; \ + X##gu0 = state[18]; \ + X##gu1 = state[19]; \ + X##ka0 = state[20]; \ + X##ka1 = state[21]; \ + X##ke0 = state[22]; \ + X##ke1 = state[23]; \ + X##ki0 = state[24]; \ + X##ki1 = state[25]; \ + X##ko0 = state[26]; \ + X##ko1 = state[27]; \ + X##ku0 = state[28]; \ + X##ku1 = state[29]; \ + X##ma0 = state[30]; \ + X##ma1 = state[31]; \ + X##me0 = state[32]; \ + X##me1 = state[33]; \ + X##mi0 = state[34]; \ + X##mi1 = state[35]; \ + X##mo0 = state[36]; \ + X##mo1 = state[37]; \ + X##mu0 = state[38]; \ + X##mu1 = state[39]; \ + X##sa0 = state[40]; \ + X##sa1 = state[41]; \ + X##se0 = state[42]; \ + X##se1 = state[43]; \ + X##si0 = state[44]; \ + X##si1 = state[45]; \ + X##so0 = state[46]; \ + X##so1 = state[47]; \ + X##su0 = state[48]; \ + X##su1 = state[49]; \ + +#define copyToState(state, X) \ + state[ 0] = X##ba0; \ + state[ 1] = X##ba1; \ + state[ 2] = X##be0; \ + state[ 3] = X##be1; \ + state[ 4] = X##bi0; \ + state[ 5] = X##bi1; \ + state[ 6] = X##bo0; \ + state[ 7] = X##bo1; \ + state[ 8] = X##bu0; \ + state[ 9] = X##bu1; \ + state[10] = X##ga0; \ + state[11] = X##ga1; \ + state[12] = X##ge0; \ + state[13] = X##ge1; \ + state[14] = X##gi0; \ + state[15] = X##gi1; \ + state[16] = X##go0; \ + state[17] = X##go1; \ + state[18] = X##gu0; \ + state[19] = X##gu1; \ + state[20] = X##ka0; \ + state[21] = X##ka1; \ + state[22] = X##ke0; \ + state[23] = X##ke1; \ + state[24] = X##ki0; \ + state[25] = X##ki1; \ + state[26] = X##ko0; \ + state[27] = X##ko1; \ + state[28] = X##ku0; \ + state[29] = X##ku1; \ + state[30] = X##ma0; \ + state[31] = X##ma1; \ + state[32] = X##me0; \ + state[33] = X##me1; \ + state[34] = X##mi0; \ + state[35] = X##mi1; \ + state[36] = X##mo0; \ + state[37] = X##mo1; \ + state[38] = X##mu0; \ + state[39] = X##mu1; \ + state[40] = X##sa0; \ + state[41] = X##sa1; \ + state[42] = X##se0; \ + state[43] = X##se1; \ + state[44] = X##si0; \ + state[45] = X##si1; \ + state[46] = X##so0; \ + state[47] = X##so1; \ + state[48] = X##su0; \ + state[49] = X##su1; \ + +#define copyStateVariables(X, Y) \ + X##ba0 = Y##ba0; \ + X##ba1 = Y##ba1; \ + X##be0 = Y##be0; \ + X##be1 = Y##be1; \ + X##bi0 = Y##bi0; \ + X##bi1 = Y##bi1; \ + X##bo0 = Y##bo0; \ + X##bo1 = Y##bo1; \ + X##bu0 = Y##bu0; \ + X##bu1 = Y##bu1; \ + X##ga0 = Y##ga0; \ + X##ga1 = Y##ga1; \ + X##ge0 = Y##ge0; \ + X##ge1 = Y##ge1; \ + X##gi0 = Y##gi0; \ + X##gi1 = Y##gi1; \ + X##go0 = Y##go0; \ + X##go1 = Y##go1; \ + X##gu0 = Y##gu0; \ + X##gu1 = Y##gu1; \ + X##ka0 = Y##ka0; \ + X##ka1 = Y##ka1; \ + X##ke0 = Y##ke0; \ + X##ke1 = Y##ke1; \ + X##ki0 = Y##ki0; \ + X##ki1 = Y##ki1; \ + X##ko0 = Y##ko0; \ + X##ko1 = Y##ko1; \ + X##ku0 = Y##ku0; \ + X##ku1 = Y##ku1; \ + X##ma0 = Y##ma0; \ + X##ma1 = Y##ma1; \ + X##me0 = Y##me0; \ + X##me1 = Y##me1; \ + X##mi0 = Y##mi0; \ + X##mi1 = Y##mi1; \ + X##mo0 = Y##mo0; \ + X##mo1 = Y##mo1; \ + X##mu0 = Y##mu0; \ + X##mu1 = Y##mu1; \ + X##sa0 = Y##sa0; \ + X##sa1 = Y##sa1; \ + X##se0 = Y##se0; \ + X##se1 = Y##se1; \ + X##si0 = Y##si0; \ + X##si1 = Y##si1; \ + X##so0 = Y##so0; \ + X##so1 = Y##so1; \ + X##su0 = Y##su0; \ + X##su1 = Y##su1; \ + diff --git a/c_src/KeccakF-1600-32.macros b/c_src/KeccakF-1600-32.macros new file mode 100755 index 0000000..9ade600 --- /dev/null +++ b/c_src/KeccakF-1600-32.macros @@ -0,0 +1,26 @@ +/* +The Keccak sponge function, designed by Guido Bertoni, Joan Daemen, +Michaël Peeters and Gilles Van Assche. For more information, feedback or +questions, please refer to our website: http://keccak.noekeon.org/ + +Implementation by the designers, +hereby denoted as "the implementer". + +To the extent possible under law, the implementer has waived all copyright +and related or neighboring rights to the source code in this file. +http://creativecommons.org/publicdomain/zero/1.0/ +*/ + +#ifdef UseSchedule + #if (UseSchedule == 1) + #include "KeccakF-1600-32-s1.macros" + #elif (UseSchedule == 2) + #include "KeccakF-1600-32-s2.macros" + #elif (UseSchedule == 3) + #include "KeccakF-1600-32-rvk.macros" + #else + #error "This schedule is not supported." + #endif +#else + #include "KeccakF-1600-32-s1.macros" +#endif diff --git a/c_src/KeccakF-1600-64.macros b/c_src/KeccakF-1600-64.macros new file mode 100755 index 0000000..0c20bca --- /dev/null +++ b/c_src/KeccakF-1600-64.macros @@ -0,0 +1,728 @@ +/* +Code automatically generated by KeccakTools! + +The Keccak sponge function, designed by Guido Bertoni, Joan Daemen, +Michaël Peeters and Gilles Van Assche. For more information, feedback or +questions, please refer to our website: http://keccak.noekeon.org/ + +Implementation by the designers, +hereby denoted as "the implementer". + +To the extent possible under law, the implementer has waived all copyright +and related or neighboring rights to the source code in this file. +http://creativecommons.org/publicdomain/zero/1.0/ +*/ + +#define declareABCDE \ + UINT64 Aba, Abe, Abi, Abo, Abu; \ + UINT64 Aga, Age, Agi, Ago, Agu; \ + UINT64 Aka, Ake, Aki, Ako, Aku; \ + UINT64 Ama, Ame, Ami, Amo, Amu; \ + UINT64 Asa, Ase, Asi, Aso, Asu; \ + UINT64 Bba, Bbe, Bbi, Bbo, Bbu; \ + UINT64 Bga, Bge, Bgi, Bgo, Bgu; \ + UINT64 Bka, Bke, Bki, Bko, Bku; \ + UINT64 Bma, Bme, Bmi, Bmo, Bmu; \ + UINT64 Bsa, Bse, Bsi, Bso, Bsu; \ + UINT64 Ca, Ce, Ci, Co, Cu; \ + UINT64 Da, De, Di, Do, Du; \ + UINT64 Eba, Ebe, Ebi, Ebo, Ebu; \ + UINT64 Ega, Ege, Egi, Ego, Egu; \ + UINT64 Eka, Eke, Eki, Eko, Eku; \ + UINT64 Ema, Eme, Emi, Emo, Emu; \ + UINT64 Esa, Ese, Esi, Eso, Esu; \ + +#define prepareTheta \ + Ca = Aba^Aga^Aka^Ama^Asa; \ + Ce = Abe^Age^Ake^Ame^Ase; \ + Ci = Abi^Agi^Aki^Ami^Asi; \ + Co = Abo^Ago^Ako^Amo^Aso; \ + Cu = Abu^Agu^Aku^Amu^Asu; \ + +#ifdef UseBebigokimisa +// --- Code for round, with prepare-theta (lane complementing pattern 'bebigokimisa') +// --- 64-bit lanes mapped to 64-bit words +#define thetaRhoPiChiIotaPrepareTheta(i, A, E) \ + Da = Cu^ROL64(Ce, 1); \ + De = Ca^ROL64(Ci, 1); \ + Di = Ce^ROL64(Co, 1); \ + Do = Ci^ROL64(Cu, 1); \ + Du = Co^ROL64(Ca, 1); \ +\ + A##ba ^= Da; \ + Bba = A##ba; \ + A##ge ^= De; \ + Bbe = ROL64(A##ge, 44); \ + A##ki ^= Di; \ + Bbi = ROL64(A##ki, 43); \ + A##mo ^= Do; \ + Bbo = ROL64(A##mo, 21); \ + A##su ^= Du; \ + Bbu = ROL64(A##su, 14); \ + E##ba = Bba ^( Bbe | Bbi ); \ + E##ba ^= KeccakF1600RoundConstants[i]; \ + Ca = E##ba; \ + E##be = Bbe ^((~Bbi)| Bbo ); \ + Ce = E##be; \ + E##bi = Bbi ^( Bbo & Bbu ); \ + Ci = E##bi; \ + E##bo = Bbo ^( Bbu | Bba ); \ + Co = E##bo; \ + E##bu = Bbu ^( Bba & Bbe ); \ + Cu = E##bu; \ +\ + A##bo ^= Do; \ + Bga = ROL64(A##bo, 28); \ + A##gu ^= Du; \ + Bge = ROL64(A##gu, 20); \ + A##ka ^= Da; \ + Bgi = ROL64(A##ka, 3); \ + A##me ^= De; \ + Bgo = ROL64(A##me, 45); \ + A##si ^= Di; \ + Bgu = ROL64(A##si, 61); \ + E##ga = Bga ^( Bge | Bgi ); \ + Ca ^= E##ga; \ + E##ge = Bge ^( Bgi & Bgo ); \ + Ce ^= E##ge; \ + E##gi = Bgi ^( Bgo |(~Bgu)); \ + Ci ^= E##gi; \ + E##go = Bgo ^( Bgu | Bga ); \ + Co ^= E##go; \ + E##gu = Bgu ^( Bga & Bge ); \ + Cu ^= E##gu; \ +\ + A##be ^= De; \ + Bka = ROL64(A##be, 1); \ + A##gi ^= Di; \ + Bke = ROL64(A##gi, 6); \ + A##ko ^= Do; \ + Bki = ROL64(A##ko, 25); \ + A##mu ^= Du; \ + Bko = ROL64(A##mu, 8); \ + A##sa ^= Da; \ + Bku = ROL64(A##sa, 18); \ + E##ka = Bka ^( Bke | Bki ); \ + Ca ^= E##ka; \ + E##ke = Bke ^( Bki & Bko ); \ + Ce ^= E##ke; \ + E##ki = Bki ^((~Bko)& Bku ); \ + Ci ^= E##ki; \ + E##ko = (~Bko)^( Bku | Bka ); \ + Co ^= E##ko; \ + E##ku = Bku ^( Bka & Bke ); \ + Cu ^= E##ku; \ +\ + A##bu ^= Du; \ + Bma = ROL64(A##bu, 27); \ + A##ga ^= Da; \ + Bme = ROL64(A##ga, 36); \ + A##ke ^= De; \ + Bmi = ROL64(A##ke, 10); \ + A##mi ^= Di; \ + Bmo = ROL64(A##mi, 15); \ + A##so ^= Do; \ + Bmu = ROL64(A##so, 56); \ + E##ma = Bma ^( Bme & Bmi ); \ + Ca ^= E##ma; \ + E##me = Bme ^( Bmi | Bmo ); \ + Ce ^= E##me; \ + E##mi = Bmi ^((~Bmo)| Bmu ); \ + Ci ^= E##mi; \ + E##mo = (~Bmo)^( Bmu & Bma ); \ + Co ^= E##mo; \ + E##mu = Bmu ^( Bma | Bme ); \ + Cu ^= E##mu; \ +\ + A##bi ^= Di; \ + Bsa = ROL64(A##bi, 62); \ + A##go ^= Do; \ + Bse = ROL64(A##go, 55); \ + A##ku ^= Du; \ + Bsi = ROL64(A##ku, 39); \ + A##ma ^= Da; \ + Bso = ROL64(A##ma, 41); \ + A##se ^= De; \ + Bsu = ROL64(A##se, 2); \ + E##sa = Bsa ^((~Bse)& Bsi ); \ + Ca ^= E##sa; \ + E##se = (~Bse)^( Bsi | Bso ); \ + Ce ^= E##se; \ + E##si = Bsi ^( Bso & Bsu ); \ + Ci ^= E##si; \ + E##so = Bso ^( Bsu | Bsa ); \ + Co ^= E##so; \ + E##su = Bsu ^( Bsa & Bse ); \ + Cu ^= E##su; \ +\ + +// --- Code for round (lane complementing pattern 'bebigokimisa') +// --- 64-bit lanes mapped to 64-bit words +#define thetaRhoPiChiIota(i, A, E) \ + Da = Cu^ROL64(Ce, 1); \ + De = Ca^ROL64(Ci, 1); \ + Di = Ce^ROL64(Co, 1); \ + Do = Ci^ROL64(Cu, 1); \ + Du = Co^ROL64(Ca, 1); \ +\ + A##ba ^= Da; \ + Bba = A##ba; \ + A##ge ^= De; \ + Bbe = ROL64(A##ge, 44); \ + A##ki ^= Di; \ + Bbi = ROL64(A##ki, 43); \ + A##mo ^= Do; \ + Bbo = ROL64(A##mo, 21); \ + A##su ^= Du; \ + Bbu = ROL64(A##su, 14); \ + E##ba = Bba ^( Bbe | Bbi ); \ + E##ba ^= KeccakF1600RoundConstants[i]; \ + E##be = Bbe ^((~Bbi)| Bbo ); \ + E##bi = Bbi ^( Bbo & Bbu ); \ + E##bo = Bbo ^( Bbu | Bba ); \ + E##bu = Bbu ^( Bba & Bbe ); \ +\ + A##bo ^= Do; \ + Bga = ROL64(A##bo, 28); \ + A##gu ^= Du; \ + Bge = ROL64(A##gu, 20); \ + A##ka ^= Da; \ + Bgi = ROL64(A##ka, 3); \ + A##me ^= De; \ + Bgo = ROL64(A##me, 45); \ + A##si ^= Di; \ + Bgu = ROL64(A##si, 61); \ + E##ga = Bga ^( Bge | Bgi ); \ + E##ge = Bge ^( Bgi & Bgo ); \ + E##gi = Bgi ^( Bgo |(~Bgu)); \ + E##go = Bgo ^( Bgu | Bga ); \ + E##gu = Bgu ^( Bga & Bge ); \ +\ + A##be ^= De; \ + Bka = ROL64(A##be, 1); \ + A##gi ^= Di; \ + Bke = ROL64(A##gi, 6); \ + A##ko ^= Do; \ + Bki = ROL64(A##ko, 25); \ + A##mu ^= Du; \ + Bko = ROL64(A##mu, 8); \ + A##sa ^= Da; \ + Bku = ROL64(A##sa, 18); \ + E##ka = Bka ^( Bke | Bki ); \ + E##ke = Bke ^( Bki & Bko ); \ + E##ki = Bki ^((~Bko)& Bku ); \ + E##ko = (~Bko)^( Bku | Bka ); \ + E##ku = Bku ^( Bka & Bke ); \ +\ + A##bu ^= Du; \ + Bma = ROL64(A##bu, 27); \ + A##ga ^= Da; \ + Bme = ROL64(A##ga, 36); \ + A##ke ^= De; \ + Bmi = ROL64(A##ke, 10); \ + A##mi ^= Di; \ + Bmo = ROL64(A##mi, 15); \ + A##so ^= Do; \ + Bmu = ROL64(A##so, 56); \ + E##ma = Bma ^( Bme & Bmi ); \ + E##me = Bme ^( Bmi | Bmo ); \ + E##mi = Bmi ^((~Bmo)| Bmu ); \ + E##mo = (~Bmo)^( Bmu & Bma ); \ + E##mu = Bmu ^( Bma | Bme ); \ +\ + A##bi ^= Di; \ + Bsa = ROL64(A##bi, 62); \ + A##go ^= Do; \ + Bse = ROL64(A##go, 55); \ + A##ku ^= Du; \ + Bsi = ROL64(A##ku, 39); \ + A##ma ^= Da; \ + Bso = ROL64(A##ma, 41); \ + A##se ^= De; \ + Bsu = ROL64(A##se, 2); \ + E##sa = Bsa ^((~Bse)& Bsi ); \ + E##se = (~Bse)^( Bsi | Bso ); \ + E##si = Bsi ^( Bso & Bsu ); \ + E##so = Bso ^( Bsu | Bsa ); \ + E##su = Bsu ^( Bsa & Bse ); \ +\ + +#else // UseBebigokimisa +// --- Code for round, with prepare-theta +// --- 64-bit lanes mapped to 64-bit words +#define thetaRhoPiChiIotaPrepareTheta(i, A, E) \ + Da = Cu^ROL64(Ce, 1); \ + De = Ca^ROL64(Ci, 1); \ + Di = Ce^ROL64(Co, 1); \ + Do = Ci^ROL64(Cu, 1); \ + Du = Co^ROL64(Ca, 1); \ +\ + A##ba ^= Da; \ + Bba = A##ba; \ + A##ge ^= De; \ + Bbe = ROL64(A##ge, 44); \ + A##ki ^= Di; \ + Bbi = ROL64(A##ki, 43); \ + A##mo ^= Do; \ + Bbo = ROL64(A##mo, 21); \ + A##su ^= Du; \ + Bbu = ROL64(A##su, 14); \ + E##ba = Bba ^((~Bbe)& Bbi ); \ + E##ba ^= KeccakF1600RoundConstants[i]; \ + Ca = E##ba; \ + E##be = Bbe ^((~Bbi)& Bbo ); \ + Ce = E##be; \ + E##bi = Bbi ^((~Bbo)& Bbu ); \ + Ci = E##bi; \ + E##bo = Bbo ^((~Bbu)& Bba ); \ + Co = E##bo; \ + E##bu = Bbu ^((~Bba)& Bbe ); \ + Cu = E##bu; \ +\ + A##bo ^= Do; \ + Bga = ROL64(A##bo, 28); \ + A##gu ^= Du; \ + Bge = ROL64(A##gu, 20); \ + A##ka ^= Da; \ + Bgi = ROL64(A##ka, 3); \ + A##me ^= De; \ + Bgo = ROL64(A##me, 45); \ + A##si ^= Di; \ + Bgu = ROL64(A##si, 61); \ + E##ga = Bga ^((~Bge)& Bgi ); \ + Ca ^= E##ga; \ + E##ge = Bge ^((~Bgi)& Bgo ); \ + Ce ^= E##ge; \ + E##gi = Bgi ^((~Bgo)& Bgu ); \ + Ci ^= E##gi; \ + E##go = Bgo ^((~Bgu)& Bga ); \ + Co ^= E##go; \ + E##gu = Bgu ^((~Bga)& Bge ); \ + Cu ^= E##gu; \ +\ + A##be ^= De; \ + Bka = ROL64(A##be, 1); \ + A##gi ^= Di; \ + Bke = ROL64(A##gi, 6); \ + A##ko ^= Do; \ + Bki = ROL64(A##ko, 25); \ + A##mu ^= Du; \ + Bko = ROL64(A##mu, 8); \ + A##sa ^= Da; \ + Bku = ROL64(A##sa, 18); \ + E##ka = Bka ^((~Bke)& Bki ); \ + Ca ^= E##ka; \ + E##ke = Bke ^((~Bki)& Bko ); \ + Ce ^= E##ke; \ + E##ki = Bki ^((~Bko)& Bku ); \ + Ci ^= E##ki; \ + E##ko = Bko ^((~Bku)& Bka ); \ + Co ^= E##ko; \ + E##ku = Bku ^((~Bka)& Bke ); \ + Cu ^= E##ku; \ +\ + A##bu ^= Du; \ + Bma = ROL64(A##bu, 27); \ + A##ga ^= Da; \ + Bme = ROL64(A##ga, 36); \ + A##ke ^= De; \ + Bmi = ROL64(A##ke, 10); \ + A##mi ^= Di; \ + Bmo = ROL64(A##mi, 15); \ + A##so ^= Do; \ + Bmu = ROL64(A##so, 56); \ + E##ma = Bma ^((~Bme)& Bmi ); \ + Ca ^= E##ma; \ + E##me = Bme ^((~Bmi)& Bmo ); \ + Ce ^= E##me; \ + E##mi = Bmi ^((~Bmo)& Bmu ); \ + Ci ^= E##mi; \ + E##mo = Bmo ^((~Bmu)& Bma ); \ + Co ^= E##mo; \ + E##mu = Bmu ^((~Bma)& Bme ); \ + Cu ^= E##mu; \ +\ + A##bi ^= Di; \ + Bsa = ROL64(A##bi, 62); \ + A##go ^= Do; \ + Bse = ROL64(A##go, 55); \ + A##ku ^= Du; \ + Bsi = ROL64(A##ku, 39); \ + A##ma ^= Da; \ + Bso = ROL64(A##ma, 41); \ + A##se ^= De; \ + Bsu = ROL64(A##se, 2); \ + E##sa = Bsa ^((~Bse)& Bsi ); \ + Ca ^= E##sa; \ + E##se = Bse ^((~Bsi)& Bso ); \ + Ce ^= E##se; \ + E##si = Bsi ^((~Bso)& Bsu ); \ + Ci ^= E##si; \ + E##so = Bso ^((~Bsu)& Bsa ); \ + Co ^= E##so; \ + E##su = Bsu ^((~Bsa)& Bse ); \ + Cu ^= E##su; \ +\ + +// --- Code for round +// --- 64-bit lanes mapped to 64-bit words +#define thetaRhoPiChiIota(i, A, E) \ + Da = Cu^ROL64(Ce, 1); \ + De = Ca^ROL64(Ci, 1); \ + Di = Ce^ROL64(Co, 1); \ + Do = Ci^ROL64(Cu, 1); \ + Du = Co^ROL64(Ca, 1); \ +\ + A##ba ^= Da; \ + Bba = A##ba; \ + A##ge ^= De; \ + Bbe = ROL64(A##ge, 44); \ + A##ki ^= Di; \ + Bbi = ROL64(A##ki, 43); \ + A##mo ^= Do; \ + Bbo = ROL64(A##mo, 21); \ + A##su ^= Du; \ + Bbu = ROL64(A##su, 14); \ + E##ba = Bba ^((~Bbe)& Bbi ); \ + E##ba ^= KeccakF1600RoundConstants[i]; \ + E##be = Bbe ^((~Bbi)& Bbo ); \ + E##bi = Bbi ^((~Bbo)& Bbu ); \ + E##bo = Bbo ^((~Bbu)& Bba ); \ + E##bu = Bbu ^((~Bba)& Bbe ); \ +\ + A##bo ^= Do; \ + Bga = ROL64(A##bo, 28); \ + A##gu ^= Du; \ + Bge = ROL64(A##gu, 20); \ + A##ka ^= Da; \ + Bgi = ROL64(A##ka, 3); \ + A##me ^= De; \ + Bgo = ROL64(A##me, 45); \ + A##si ^= Di; \ + Bgu = ROL64(A##si, 61); \ + E##ga = Bga ^((~Bge)& Bgi ); \ + E##ge = Bge ^((~Bgi)& Bgo ); \ + E##gi = Bgi ^((~Bgo)& Bgu ); \ + E##go = Bgo ^((~Bgu)& Bga ); \ + E##gu = Bgu ^((~Bga)& Bge ); \ +\ + A##be ^= De; \ + Bka = ROL64(A##be, 1); \ + A##gi ^= Di; \ + Bke = ROL64(A##gi, 6); \ + A##ko ^= Do; \ + Bki = ROL64(A##ko, 25); \ + A##mu ^= Du; \ + Bko = ROL64(A##mu, 8); \ + A##sa ^= Da; \ + Bku = ROL64(A##sa, 18); \ + E##ka = Bka ^((~Bke)& Bki ); \ + E##ke = Bke ^((~Bki)& Bko ); \ + E##ki = Bki ^((~Bko)& Bku ); \ + E##ko = Bko ^((~Bku)& Bka ); \ + E##ku = Bku ^((~Bka)& Bke ); \ +\ + A##bu ^= Du; \ + Bma = ROL64(A##bu, 27); \ + A##ga ^= Da; \ + Bme = ROL64(A##ga, 36); \ + A##ke ^= De; \ + Bmi = ROL64(A##ke, 10); \ + A##mi ^= Di; \ + Bmo = ROL64(A##mi, 15); \ + A##so ^= Do; \ + Bmu = ROL64(A##so, 56); \ + E##ma = Bma ^((~Bme)& Bmi ); \ + E##me = Bme ^((~Bmi)& Bmo ); \ + E##mi = Bmi ^((~Bmo)& Bmu ); \ + E##mo = Bmo ^((~Bmu)& Bma ); \ + E##mu = Bmu ^((~Bma)& Bme ); \ +\ + A##bi ^= Di; \ + Bsa = ROL64(A##bi, 62); \ + A##go ^= Do; \ + Bse = ROL64(A##go, 55); \ + A##ku ^= Du; \ + Bsi = ROL64(A##ku, 39); \ + A##ma ^= Da; \ + Bso = ROL64(A##ma, 41); \ + A##se ^= De; \ + Bsu = ROL64(A##se, 2); \ + E##sa = Bsa ^((~Bse)& Bsi ); \ + E##se = Bse ^((~Bsi)& Bso ); \ + E##si = Bsi ^((~Bso)& Bsu ); \ + E##so = Bso ^((~Bsu)& Bsa ); \ + E##su = Bsu ^((~Bsa)& Bse ); \ +\ + +#endif // UseBebigokimisa + +const UINT64 KeccakF1600RoundConstants[24] = { + 0x0000000000000001ULL, + 0x0000000000008082ULL, + 0x800000000000808aULL, + 0x8000000080008000ULL, + 0x000000000000808bULL, + 0x0000000080000001ULL, + 0x8000000080008081ULL, + 0x8000000000008009ULL, + 0x000000000000008aULL, + 0x0000000000000088ULL, + 0x0000000080008009ULL, + 0x000000008000000aULL, + 0x000000008000808bULL, + 0x800000000000008bULL, + 0x8000000000008089ULL, + 0x8000000000008003ULL, + 0x8000000000008002ULL, + 0x8000000000000080ULL, + 0x000000000000800aULL, + 0x800000008000000aULL, + 0x8000000080008081ULL, + 0x8000000000008080ULL, + 0x0000000080000001ULL, + 0x8000000080008008ULL }; + +#define copyFromStateAndXor576bits(X, state, input) \ + X##ba = state[ 0]^input[ 0]; \ + X##be = state[ 1]^input[ 1]; \ + X##bi = state[ 2]^input[ 2]; \ + X##bo = state[ 3]^input[ 3]; \ + X##bu = state[ 4]^input[ 4]; \ + X##ga = state[ 5]^input[ 5]; \ + X##ge = state[ 6]^input[ 6]; \ + X##gi = state[ 7]^input[ 7]; \ + X##go = state[ 8]^input[ 8]; \ + X##gu = state[ 9]; \ + X##ka = state[10]; \ + X##ke = state[11]; \ + X##ki = state[12]; \ + X##ko = state[13]; \ + X##ku = state[14]; \ + X##ma = state[15]; \ + X##me = state[16]; \ + X##mi = state[17]; \ + X##mo = state[18]; \ + X##mu = state[19]; \ + X##sa = state[20]; \ + X##se = state[21]; \ + X##si = state[22]; \ + X##so = state[23]; \ + X##su = state[24]; \ + +#define copyFromStateAndXor832bits(X, state, input) \ + X##ba = state[ 0]^input[ 0]; \ + X##be = state[ 1]^input[ 1]; \ + X##bi = state[ 2]^input[ 2]; \ + X##bo = state[ 3]^input[ 3]; \ + X##bu = state[ 4]^input[ 4]; \ + X##ga = state[ 5]^input[ 5]; \ + X##ge = state[ 6]^input[ 6]; \ + X##gi = state[ 7]^input[ 7]; \ + X##go = state[ 8]^input[ 8]; \ + X##gu = state[ 9]^input[ 9]; \ + X##ka = state[10]^input[10]; \ + X##ke = state[11]^input[11]; \ + X##ki = state[12]^input[12]; \ + X##ko = state[13]; \ + X##ku = state[14]; \ + X##ma = state[15]; \ + X##me = state[16]; \ + X##mi = state[17]; \ + X##mo = state[18]; \ + X##mu = state[19]; \ + X##sa = state[20]; \ + X##se = state[21]; \ + X##si = state[22]; \ + X##so = state[23]; \ + X##su = state[24]; \ + +#define copyFromStateAndXor1024bits(X, state, input) \ + X##ba = state[ 0]^input[ 0]; \ + X##be = state[ 1]^input[ 1]; \ + X##bi = state[ 2]^input[ 2]; \ + X##bo = state[ 3]^input[ 3]; \ + X##bu = state[ 4]^input[ 4]; \ + X##ga = state[ 5]^input[ 5]; \ + X##ge = state[ 6]^input[ 6]; \ + X##gi = state[ 7]^input[ 7]; \ + X##go = state[ 8]^input[ 8]; \ + X##gu = state[ 9]^input[ 9]; \ + X##ka = state[10]^input[10]; \ + X##ke = state[11]^input[11]; \ + X##ki = state[12]^input[12]; \ + X##ko = state[13]^input[13]; \ + X##ku = state[14]^input[14]; \ + X##ma = state[15]^input[15]; \ + X##me = state[16]; \ + X##mi = state[17]; \ + X##mo = state[18]; \ + X##mu = state[19]; \ + X##sa = state[20]; \ + X##se = state[21]; \ + X##si = state[22]; \ + X##so = state[23]; \ + X##su = state[24]; \ + +#define copyFromStateAndXor1088bits(X, state, input) \ + X##ba = state[ 0]^input[ 0]; \ + X##be = state[ 1]^input[ 1]; \ + X##bi = state[ 2]^input[ 2]; \ + X##bo = state[ 3]^input[ 3]; \ + X##bu = state[ 4]^input[ 4]; \ + X##ga = state[ 5]^input[ 5]; \ + X##ge = state[ 6]^input[ 6]; \ + X##gi = state[ 7]^input[ 7]; \ + X##go = state[ 8]^input[ 8]; \ + X##gu = state[ 9]^input[ 9]; \ + X##ka = state[10]^input[10]; \ + X##ke = state[11]^input[11]; \ + X##ki = state[12]^input[12]; \ + X##ko = state[13]^input[13]; \ + X##ku = state[14]^input[14]; \ + X##ma = state[15]^input[15]; \ + X##me = state[16]^input[16]; \ + X##mi = state[17]; \ + X##mo = state[18]; \ + X##mu = state[19]; \ + X##sa = state[20]; \ + X##se = state[21]; \ + X##si = state[22]; \ + X##so = state[23]; \ + X##su = state[24]; \ + +#define copyFromStateAndXor1152bits(X, state, input) \ + X##ba = state[ 0]^input[ 0]; \ + X##be = state[ 1]^input[ 1]; \ + X##bi = state[ 2]^input[ 2]; \ + X##bo = state[ 3]^input[ 3]; \ + X##bu = state[ 4]^input[ 4]; \ + X##ga = state[ 5]^input[ 5]; \ + X##ge = state[ 6]^input[ 6]; \ + X##gi = state[ 7]^input[ 7]; \ + X##go = state[ 8]^input[ 8]; \ + X##gu = state[ 9]^input[ 9]; \ + X##ka = state[10]^input[10]; \ + X##ke = state[11]^input[11]; \ + X##ki = state[12]^input[12]; \ + X##ko = state[13]^input[13]; \ + X##ku = state[14]^input[14]; \ + X##ma = state[15]^input[15]; \ + X##me = state[16]^input[16]; \ + X##mi = state[17]^input[17]; \ + X##mo = state[18]; \ + X##mu = state[19]; \ + X##sa = state[20]; \ + X##se = state[21]; \ + X##si = state[22]; \ + X##so = state[23]; \ + X##su = state[24]; \ + +#define copyFromStateAndXor1344bits(X, state, input) \ + X##ba = state[ 0]^input[ 0]; \ + X##be = state[ 1]^input[ 1]; \ + X##bi = state[ 2]^input[ 2]; \ + X##bo = state[ 3]^input[ 3]; \ + X##bu = state[ 4]^input[ 4]; \ + X##ga = state[ 5]^input[ 5]; \ + X##ge = state[ 6]^input[ 6]; \ + X##gi = state[ 7]^input[ 7]; \ + X##go = state[ 8]^input[ 8]; \ + X##gu = state[ 9]^input[ 9]; \ + X##ka = state[10]^input[10]; \ + X##ke = state[11]^input[11]; \ + X##ki = state[12]^input[12]; \ + X##ko = state[13]^input[13]; \ + X##ku = state[14]^input[14]; \ + X##ma = state[15]^input[15]; \ + X##me = state[16]^input[16]; \ + X##mi = state[17]^input[17]; \ + X##mo = state[18]^input[18]; \ + X##mu = state[19]^input[19]; \ + X##sa = state[20]^input[20]; \ + X##se = state[21]; \ + X##si = state[22]; \ + X##so = state[23]; \ + X##su = state[24]; \ + +#define copyFromState(X, state) \ + X##ba = state[ 0]; \ + X##be = state[ 1]; \ + X##bi = state[ 2]; \ + X##bo = state[ 3]; \ + X##bu = state[ 4]; \ + X##ga = state[ 5]; \ + X##ge = state[ 6]; \ + X##gi = state[ 7]; \ + X##go = state[ 8]; \ + X##gu = state[ 9]; \ + X##ka = state[10]; \ + X##ke = state[11]; \ + X##ki = state[12]; \ + X##ko = state[13]; \ + X##ku = state[14]; \ + X##ma = state[15]; \ + X##me = state[16]; \ + X##mi = state[17]; \ + X##mo = state[18]; \ + X##mu = state[19]; \ + X##sa = state[20]; \ + X##se = state[21]; \ + X##si = state[22]; \ + X##so = state[23]; \ + X##su = state[24]; \ + +#define copyToState(state, X) \ + state[ 0] = X##ba; \ + state[ 1] = X##be; \ + state[ 2] = X##bi; \ + state[ 3] = X##bo; \ + state[ 4] = X##bu; \ + state[ 5] = X##ga; \ + state[ 6] = X##ge; \ + state[ 7] = X##gi; \ + state[ 8] = X##go; \ + state[ 9] = X##gu; \ + state[10] = X##ka; \ + state[11] = X##ke; \ + state[12] = X##ki; \ + state[13] = X##ko; \ + state[14] = X##ku; \ + state[15] = X##ma; \ + state[16] = X##me; \ + state[17] = X##mi; \ + state[18] = X##mo; \ + state[19] = X##mu; \ + state[20] = X##sa; \ + state[21] = X##se; \ + state[22] = X##si; \ + state[23] = X##so; \ + state[24] = X##su; \ + +#define copyStateVariables(X, Y) \ + X##ba = Y##ba; \ + X##be = Y##be; \ + X##bi = Y##bi; \ + X##bo = Y##bo; \ + X##bu = Y##bu; \ + X##ga = Y##ga; \ + X##ge = Y##ge; \ + X##gi = Y##gi; \ + X##go = Y##go; \ + X##gu = Y##gu; \ + X##ka = Y##ka; \ + X##ke = Y##ke; \ + X##ki = Y##ki; \ + X##ko = Y##ko; \ + X##ku = Y##ku; \ + X##ma = Y##ma; \ + X##me = Y##me; \ + X##mi = Y##mi; \ + X##mo = Y##mo; \ + X##mu = Y##mu; \ + X##sa = Y##sa; \ + X##se = Y##se; \ + X##si = Y##si; \ + X##so = Y##so; \ + X##su = Y##su; \ + diff --git a/c_src/KeccakF-1600-arm.c b/c_src/KeccakF-1600-arm.c new file mode 100755 index 0000000..abd6dc9 --- /dev/null +++ b/c_src/KeccakF-1600-arm.c @@ -0,0 +1,123 @@ +/* +The Keccak sponge function, designed by Guido Bertoni, Joan Daemen, +Michaël Peeters and Gilles Van Assche. For more information, feedback or +questions, please refer to our website: http://keccak.noekeon.org/ + +Implementation by Ronny Van Keer, +hereby denoted as "the implementer". + +To the extent possible under law, the implementer has waived all copyright +and related or neighboring rights to the source code in this file. +http://creativecommons.org/publicdomain/zero/1.0/ +*/ + +#include "KeccakF-1600-interface.h" +#include "KeccakSponge.h" +#include + +typedef unsigned char UINT8; +typedef unsigned short UINT16; +typedef unsigned int UINT32; +typedef unsigned long long int UINT64; + +void KeccakPermutationOnWordsAfterXoring_ARM_asm(UINT32 *state, const UINT8 *input, int laneCount); + +void KeccakInitialize( void ) +{ +} + +void KeccakInitializeState(unsigned char *state) +{ + memset(state, 0, KeccakPermutationSizeInBytes); +} + +void KeccakPermutation(unsigned char *state) +{ + KeccakPermutationOnWordsAfterXoring_ARM_asm((UINT32*)state, 0, 0); +} + +#ifdef ProvideFast576 +void KeccakAbsorb576bits(unsigned char *state, const unsigned char *data) +{ + KeccakPermutationOnWordsAfterXoring_ARM_asm((UINT32*)state, data, 9); +} +#endif + +#ifdef ProvideFast832 +void KeccakAbsorb832bits(unsigned char *state, const unsigned char *data) +{ + KeccakPermutationOnWordsAfterXoring_ARM_asm((UINT32*)state, data, 13); +} +#endif + +#ifdef ProvideFast1024 +void KeccakAbsorb1024bits(unsigned char *state, const unsigned char *data) +{ + KeccakPermutationOnWordsAfterXoring_ARM_asm((UINT32*)state, data, 16); +} +#endif + +#ifdef ProvideFast1088 +void KeccakAbsorb1088bits(unsigned char *state, const unsigned char *data) +{ + KeccakPermutationOnWordsAfterXoring_ARM_asm((UINT32*)state, data, 17); +} +#endif + +#ifdef ProvideFast1152 +void KeccakAbsorb1152bits(unsigned char *state, const unsigned char *data) +{ + KeccakPermutationOnWordsAfterXoring_ARM_asm((UINT32*)state, data, 18); +} +#endif + +#ifdef ProvideFast1344 +void KeccakAbsorb1344bits(unsigned char *state, const unsigned char *data) +{ + KeccakPermutationOnWordsAfterXoring_ARM_asm((UINT32*)state, data, 21); +} +#endif + + +void KeccakAbsorb(unsigned char *state, const unsigned char *data, unsigned int laneCount) +{ + KeccakPermutationOnWordsAfterXoring_ARM_asm((UINT32*)state, data, laneCount); +} + +// Credit: Henry S. Warren, Hacker's Delight, Addison-Wesley, 2002 +UINT64 fromInterleaving(UINT64 x) +{ + UINT64 t; + + t = (x ^ (x >> 16)) & 0x00000000FFFF0000ULL; x = x ^ t ^ (t << 16); + t = (x ^ (x >> 8)) & 0x0000FF000000FF00ULL; x = x ^ t ^ (t << 8); + t = (x ^ (x >> 4)) & 0x00F000F000F000F0ULL; x = x ^ t ^ (t << 4); + t = (x ^ (x >> 2)) & 0x0C0C0C0C0C0C0C0CULL; x = x ^ t ^ (t << 2); + t = (x ^ (x >> 1)) & 0x2222222222222222ULL; x = x ^ t ^ (t << 1); + + return x; +} + +void setInterleavedWordsInto8bytes(UINT8* dest, UINT32* evenAndOdd) +{ + ((UINT64*)dest)[0] = fromInterleaving(*(UINT64*)evenAndOdd); +} + +#define extractLanes(laneCount, state, data) \ + { \ + int i; \ + for(i=0; i<(laneCount); i++) \ + setInterleavedWordsInto8bytes(data+i*8, (UINT32*)state+i*2); \ + } + +#ifdef ProvideFast1024 +void KeccakExtract1024bits(const unsigned char *state, unsigned char *data) +{ + extractLanes(16, state, data) +} +#endif + +void KeccakExtract(const unsigned char *state, unsigned char *data, unsigned int laneCount) +{ + extractLanes(laneCount, state, data) +} diff --git a/c_src/KeccakF-1600-armcc.s b/c_src/KeccakF-1600-armcc.s new file mode 100755 index 0000000..b87d0ba --- /dev/null +++ b/c_src/KeccakF-1600-armcc.s @@ -0,0 +1,653 @@ +;// The Keccak sponge function, designed by Guido Bertoni, Joan Daemen, +;// Michaël Peeters and Gilles Van Assche. For more information, feedback or +;// questions, please refer to our website: http://keccak.noekeon.org/ +;// +;// Implementation by Ronny Van Keer, +;// hereby denoted as "the implementer". +;// +;// To the extent possible under law, the implementer has waived all copyright +;// and related or neighboring rights to the source code in this file. +;// http://creativecommons.org/publicdomain/zero/1.0/ + + + PRESERVE8 + THUMB + AREA |.text|, CODE, READONLY + +;// --- defines + +_ba0 equ 0*4 +_ba1 equ 1*4 +_be0 equ 2*4 +_be1 equ 3*4 +_bi0 equ 4*4 +_bi1 equ 5*4 +_bo0 equ 6*4 +_bo1 equ 7*4 +_bu0 equ 8*4 +_bu1 equ 9*4 +_ga0 equ 10*4 +_ga1 equ 11*4 +_ge0 equ 12*4 +_ge1 equ 13*4 +_gi0 equ 14*4 +_gi1 equ 15*4 +_go0 equ 16*4 +_go1 equ 17*4 +_gu0 equ 18*4 +_gu1 equ 19*4 +_ka0 equ 20*4 +_ka1 equ 21*4 +_ke0 equ 22*4 +_ke1 equ 23*4 +_ki0 equ 24*4 +_ki1 equ 25*4 +_ko0 equ 26*4 +_ko1 equ 27*4 +_ku0 equ 28*4 +_ku1 equ 29*4 +_ma0 equ 30*4 +_ma1 equ 31*4 +_me0 equ 32*4 +_me1 equ 33*4 +_mi0 equ 34*4 +_mi1 equ 35*4 +_mo0 equ 36*4 +_mo1 equ 37*4 +_mu0 equ 38*4 +_mu1 equ 39*4 +_sa0 equ 40*4 +_sa1 equ 41*4 +_se0 equ 42*4 +_se1 equ 43*4 +_si0 equ 44*4 +_si1 equ 45*4 +_so0 equ 46*4 +_so1 equ 47*4 +_su0 equ 48*4 +_su1 equ 49*4 + +mDe1 equ 50*4 +mDi0 equ 51*4 +mDo0 equ 52*4 +mDo1 equ 53*4 + +;// --- macros + + MACRO + xor5 $result,$ptr,$b,$g,$k,$m,$s + + ldr $result, [$ptr, #$b] + ldr r1, [$ptr, #$g] + ldr r2, [$ptr, #$k] + eor $result, $result, r1 + ldr r1, [$ptr, #$m] + eor $result, $result, r2 + ldr r2, [$ptr, #$s] + eor $result, $result, r1 + eor $result, $result, r2 + MEND + + MACRO + xorrol $b, $yy, $rr + + eor $b, $b, $yy + ror $b, #32-$rr + MEND + + + MACRO + xandnot $resptr, $resofs, $aa, $bb, $cc + + bic r1, $cc, $bb + eor r1, r1, $aa + str r1, [$resptr, #$resofs] + MEND + + MACRO + xandnotRC $resptr, $resofs, $aa, $bb, $cc + + ldr r1, [r3], #4 + bic $cc, $cc, $bb + eor $cc, $cc, r1 + eor $cc, $cc, $aa + str $cc, [$resptr, #$resofs] + MEND + + + EXPORT KeccakPermutationOnWordsAfterXoring_ARM_asm +KeccakPermutationOnWordsAfterXoring_ARM_asm PROC + + push {r4-r12,lr} + sub sp,sp,#4*(50+4) + + movs r9, r2 + beq interleaveDone + mov r8,r0 +interleaveLoop + + ldr r4, [r1], #4 + ldr r5, [r1], #4 + ldrd r6, r7, [r8] + + ;// Credit: Henry S. Warren, Hacker's Delight, Addison-Wesley, 2002 + and r3,r4,#0x55555555 + orr r3,r3,r3, LSR #1 + and r3,r3,#0x33333333 + orr r3,r3,r3, LSR #2 + and r3,r3,#0x0F0F0F0F + orr r3,r3,r3, LSR #4 + and r3,r3,#0x00FF00FF + bfi r3,r3,#8, #8 + eor r6,r6,r3, LSR #8 + + and r3,r5,#0x55555555 + orr r3,r3,r3, LSR #1 + and r3,r3,#0x33333333 + orr r3,r3,r3, LSR #2 + and r3,r3,#0x0F0F0F0F + orr r3,r3,r3, LSR #4 + and r3,r3,#0x00FF00FF + orr r3,r3,r3, LSR #8 + eor r6,r6,r3, LSL #16 + + and r3,r4,#0xAAAAAAAA + orr r3,r3,r3, LSL #1 + and r3,r3,#0xCCCCCCCC + orr r3,r3,r3, LSL #2 + and r3,r3,#0xF0F0F0F0 + orr r3,r3,r3, LSL #4 + and r3,r3,#0xFF00FF00 + orr r3,r3,r3, LSL #8 + eor r7,r7,r3, LSR #16 + + and r3,r5,#0xAAAAAAAA + orr r3,r3,r3, LSL #1 + and r3,r3,#0xCCCCCCCC + orr r3,r3,r3, LSL #2 + and r3,r3,#0xF0F0F0F0 + orr r3,r3,r3, LSL #4 + and r3,r3,#0xFF00FF00 + orr r3,r3,r3, LSL #8 + bfc r3, #0, #16 + eor r7,r7,r3 + + strd r6,r7,[r8], #8 + + subs r9,r9,#1 + bne interleaveLoop + +interleaveDone + + ldr r3, =KeccakF1600RoundConstantsWithTerminator + b roundLoop ;//jump over the table + LTORG + + ALIGN + +KeccakF1600RoundConstantsWithTerminator + ;// 0 1 + dcd 0x00000001, 0x00000000 + dcd 0x00000000, 0x00000089 + dcd 0x00000000, 0x8000008b + dcd 0x00000000, 0x80008080 + dcd 0x00000001, 0x0000008b + dcd 0x00000001, 0x00008000 + dcd 0x00000001, 0x80008088 + dcd 0x00000001, 0x80000082 + dcd 0x00000000, 0x0000000b + dcd 0x00000000, 0x0000000a + dcd 0x00000001, 0x00008082 + dcd 0x00000000, 0x00008003 + dcd 0x00000001, 0x0000808b + dcd 0x00000001, 0x8000000b + dcd 0x00000001, 0x8000008a + dcd 0x00000001, 0x80000081 + dcd 0x00000000, 0x80000081 + dcd 0x00000000, 0x80000008 + dcd 0x00000000, 0x00000083 + dcd 0x00000000, 0x80008003 + dcd 0x00000001, 0x80008088 + dcd 0x00000000, 0x80000088 + dcd 0x00000001, 0x00008000 + dcd 0x00000000, 0x80008082 + dcd 0xFFFFFFFF ;//terminator + +roundLoop + + ;//prepTheta A + xor5 r10, r0,_bu0, _gu0, _ku0, _mu0, _su0 + xor5 r6, r0,_be1, _ge1, _ke1, _me1, _se1 + eor r5, r10, r6, ROR #31 + xor5 r11, r0,_bu1, _gu1, _ku1, _mu1, _su1 + xor5 r7, r0,_be0, _ge0, _ke0, _me0, _se0 + eor r4, r11, r7 + + xor5 r8, r0,_bi0, _gi0, _ki0, _mi0, _si0 + eor r1, r8, r11, ROR #31 + str r1, [sp, #mDo0] + xor5 r9, r0,_bi1, _gi1, _ki1, _mi1, _si1 + eor r1, r9, r10 + str r1, [sp, #mDo1] + + xor5 r10, r0,_ba0, _ga0, _ka0, _ma0, _sa0 + eor lr, r10, r9, ROR #31 + xor5 r11, r0,_ba1, _ga1, _ka1, _ma1, _sa1 + eor r1, r11, r8 + str r1, [sp, #mDe1] + + xor5 r9, r0,_bo1, _go1, _ko1, _mo1, _so1 + eor r1, r7, r9, ROR #31 + str r1, [sp, #mDi0] + xor5 r8, r0,_bo0, _go0, _ko0, _mo0, _so0 + eor r2, r6, r8 + + eor r7, r8, r11, ROR #31 + eor r6, r9, r10 + + ;//thetaRhoPiChiIota 0, in A, out E + ldr r8, [r0, #_ba0] + ldr r9, [r0, #_ge0] + ldr r10, [r0, #_ki1] + ldr r11, [r0, #_mo1] + ldr r12, [r0, #_su0] + ldr r1, [sp, #mDo1] + eor r8, r8, r5 + xorrol r9, lr, 22 + xorrol r10, r2, 22 + xorrol r11, r1, 11 + xorrol r12, r7, 7 + xandnot sp, _be0, r9, r10, r11 + xandnot sp, _bi0, r10, r11, r12 + xandnot sp, _bo0, r11, r12, r8 + xandnot sp, _bu0, r12, r8, r9 + xandnotRC sp, _ba0, r8, r9, r10 + + ldr r8, [r0, #_bo0] + ldr r1, [sp, #mDo0] + ldr r9, [r0, #_gu0] + xorrol r8, r1, 14 + ldr r1, [sp, #mDe1] + ldr r10, [r0, #_ka1] + ldr r11, [r0, #_me1] + ldr r12, [r0, #_si1] + xorrol r9, r7, 10 + xorrol r10, r4, 2 + xorrol r11, r1, 23 + xorrol r12, r2, 31 + xandnot sp, _ga0, r8, r9, r10 + xandnot sp, _ge0, r9, r10, r11 + xandnot sp, _gi0, r10, r11, r12 + xandnot sp, _go0, r11, r12, r8 + xandnot sp, _gu0, r12, r8, r9 + + ldr r8, [r0, #_be1] + ldr r1, [sp, #mDe1] + ldr r9, [r0, #_gi0] + xorrol r8, r1, 1 + ldr r1, [sp, #mDi0] + ldr r10, [r0, #_ko1] + xorrol r9, r1, 3 + ldr r1, [sp, #mDo1] + ldr r11, [r0, #_mu0] + ldr r12, [r0, #_sa0] + xorrol r10, r1, 13 + xorrol r11, r7, 4 + xorrol r12, r5, 9 + xandnot sp, _ka0, r8, r9, r10 + xandnot sp, _ke0, r9, r10, r11 + xandnot sp, _ki0, r10, r11, r12 + xandnot sp, _ko0, r11, r12, r8 + xandnot sp, _ku0, r12, r8, r9 + + ldr r8, [r0, #_bu1] + ldr r9, [r0, #_ga0] + ldr r10, [r0, #_ke0] + ldr r11, [r0, #_mi1] + ldr r12, [r0, #_so0] + ldr r1, [sp, #mDo0] + xorrol r8, r6, 14 + xorrol r9, r5, 18 + xorrol r10, lr, 5 + xorrol r11, r2, 8 + xorrol r12, r1, 28 + xandnot sp, _ma0, r8, r9, r10 + xandnot sp, _me0, r9, r10, r11 + xandnot sp, _mi0, r10, r11, r12 + xandnot sp, _mo0, r11, r12, r8 + xandnot sp, _mu0, r12, r8, r9 + + ldr r1, [sp, #mDi0] + ldr r8, [r0, #_bi0] + ldr r9, [r0, #_go1] + xorrol r8, r1, 31 + ldr r1, [sp, #mDo1] + ldr r10, [r0, #_ku1] + xorrol r9, r1, 28 + ldr r11, [r0, #_ma1] + ldr r12, [r0, #_se0] + xorrol r10, r6, 20 + xorrol r11, r4, 21 + xorrol r12, lr, 1 + xandnot sp, _sa0, r8, r9, r10 + xandnot sp, _se0, r9, r10, r11 + xandnot sp, _si0, r10, r11, r12 + xandnot sp, _so0, r11, r12, r8 + xandnot sp, _su0, r12, r8, r9 + + ;// thetaRhoPiChiIota 1, in A, out E + ldr r1, [sp, #mDe1] + ldr r9, [r0, #_ge1] + ldr r8, [r0, #_ba1] + xorrol r9, r1, 22 + ldr r1, [sp, #mDi0] + ldr r10, [r0, #_ki0] + eor r8, r8, r4 + xorrol r10, r1, 21 + ldr r1, [sp, #mDo0] + ldr r11, [r0, #_mo0] + ldr r12, [r0, #_su1] + xorrol r11, r1, 10 + xorrol r12, r6, 7 + xandnot sp, _be1, r9, r10, r11 + xandnot sp, _bi1, r10, r11, r12 + xandnot sp, _bo1, r11, r12, r8 + xandnot sp, _bu1, r12, r8, r9 + xandnotRC sp, _ba1, r8, r9, r10 + + ldr r1, [sp, #mDo1] + ldr r8, [r0, #_bo1] + ldr r12, [r0, #_si0] + xorrol r8, r1, 14 + ldr r1, [sp, #mDi0] + ldr r9, [r0, #_gu1] + xorrol r12, r1, 30 + ldr r10, [r0, #_ka0] + ldr r11, [r0, #_me0] + xorrol r9, r6, 10 + xorrol r10, r5, 1 + xorrol r11, lr, 22 + xandnot sp, _ga1, r8, r9, r10 + xandnot sp, _ge1, r9, r10, r11 + xandnot sp, _gi1, r10, r11, r12 + xandnot sp, _go1, r11, r12, r8 + xandnot sp, _gu1, r12, r8, r9 + + ldr r1, [sp, #mDo0] + ldr r10, [r0, #_ko0] + ldr r8, [r0, #_be0] + xorrol r10, r1, 12 + ldr r9, [r0, #_gi1] + ldr r11, [r0, #_mu1] + ldr r12, [r0, #_sa1] + eor r8, r8, lr + xorrol r9, r2, 3 + xorrol r11, r6, 4 + xorrol r12, r4, 9 + xandnot sp, _ka1, r8, r9, r10 + xandnot sp, _ke1, r9, r10, r11 + xandnot sp, _ki1, r10, r11, r12 + xandnot sp, _ko1, r11, r12, r8 + xandnot sp, _ku1, r12, r8, r9 + + ldr r1, [sp, #mDe1] + ldr r10, [r0, #_ke1] + ldr r11, [r0, #_mi0] + xorrol r10, r1, 5 + ldr r1, [sp, #mDi0] + ldr r12, [r0, #_so1] + xorrol r11, r1, 7 + ldr r1, [sp, #mDo1] + ldr r8, [r0, #_bu0] + ldr r9, [r0, #_ga1] + xorrol r8, r7, 13 + xorrol r9, r4, 18 + xorrol r12, r1, 28 + xandnot sp, _ma1, r8, r9, r10 + xandnot sp, _me1, r9, r10, r11 + xandnot sp, _mi1, r10, r11, r12 + xandnot sp, _mo1, r11, r12, r8 + xandnot sp, _mu1, r12, r8, r9 + + ldr r1, [sp, #mDo0] + ldr r9, [r0, #_go0] + ldr r8, [r0, #_bi1] + xorrol r9, r1, 27 + ldr r10, [r0, #_ku0] + ldr r11, [r0, #_ma0] + ldr r12, [r0, #_se1] + ldr r1, [sp, #mDe1] + xorrol r8, r2, 31 + xorrol r10, r7, 19 + xorrol r11, r5, 20 + xorrol r12, r1, 1 + xandnot sp, _sa1, r8, r9, r10 + xandnot sp, _se1, r9, r10, r11 + xandnot sp, _si1, r10, r11, r12 + xandnot sp, _so1, r11, r12, r8 + xandnot sp, _su1, r12, r8, r9 + + ;//prepTheta E + xor5 r10, sp,_bu0, _gu0, _ku0, _mu0, _su0 + xor5 r6, sp,_be1, _ge1, _ke1, _me1, _se1 + eor r5, r10, r6, ROR #31 + xor5 r11, sp,_bu1, _gu1, _ku1, _mu1, _su1 + xor5 r7, sp,_be0, _ge0, _ke0, _me0, _se0 + eor r4, r11, r7 + + xor5 r8, sp,_bi0, _gi0, _ki0, _mi0, _si0 + eor r1, r8, r11, ROR #31 + str r1, [sp, #mDo0] + xor5 r9, sp,_bi1, _gi1, _ki1, _mi1, _si1 + eor r1, r9, r10 + str r1, [sp, #mDo1] + + xor5 r10, sp,_ba0, _ga0, _ka0, _ma0, _sa0 + eor lr, r10, r9, ROR #31 + xor5 r11, sp,_ba1, _ga1, _ka1, _ma1, _sa1 + eor r1, r11, r8 + str r1, [sp, #mDe1] + + xor5 r9, sp,_bo1, _go1, _ko1, _mo1, _so1 + eor r1, r7, r9, ROR #31 + str r1, [sp, #mDi0] + xor5 r8, sp,_bo0, _go0, _ko0, _mo0, _so0 + eor r2, r6, r8 + + eor r7, r8, r11, ROR #31 + eor r6, r9, r10 + + ;//thetaRhoPiChiIota 0, in E, out A + ldr r8, [sp, #_ba0] + ldr r9, [sp, #_ge0] + ldr r10, [sp, #_ki1] + ldr r11, [sp, #_mo1] + ldr r12, [sp, #_su0] + ldr r1, [sp, #mDo1] + eor r8, r8, r5 + xorrol r9, lr, 22 + xorrol r10, r2, 22 + xorrol r11, r1, 11 + xorrol r12, r7, 7 + xandnot r0, _be0, r9, r10, r11 + xandnot r0, _bi0, r10, r11, r12 + xandnot r0, _bo0, r11, r12, r8 + xandnot r0, _bu0, r12, r8, r9 + xandnotRC r0, _ba0, r8, r9, r10 + + ldr r8, [sp, #_bo0] + ldr r1, [sp, #mDo0] + ldr r9, [sp, #_gu0] + xorrol r8, r1, 14 + ldr r1, [sp, #mDe1] + ldr r10, [sp, #_ka1] + ldr r11, [sp, #_me1] + ldr r12, [sp, #_si1] + xorrol r9, r7, 10 + xorrol r10, r4, 2 + xorrol r11, r1, 23 + xorrol r12, r2, 31 + xandnot r0, _ga0, r8, r9, r10 + xandnot r0, _ge0, r9, r10, r11 + xandnot r0, _gi0, r10, r11, r12 + xandnot r0, _go0, r11, r12, r8 + xandnot r0, _gu0, r12, r8, r9 + + ldr r8, [sp, #_be1] + ldr r1, [sp, #mDe1] + ldr r9, [sp, #_gi0] + xorrol r8, r1, 1 + ldr r1, [sp, #mDi0] + ldr r10, [sp, #_ko1] + xorrol r9, r1, 3 + ldr r1, [sp, #mDo1] + ldr r11, [sp, #_mu0] + ldr r12, [sp, #_sa0] + xorrol r10, r1, 13 + xorrol r11, r7, 4 + xorrol r12, r5, 9 + xandnot r0, _ka0, r8, r9, r10 + xandnot r0, _ke0, r9, r10, r11 + xandnot r0, _ki0, r10, r11, r12 + xandnot r0, _ko0, r11, r12, r8 + xandnot r0, _ku0, r12, r8, r9 + + ldr r8, [sp, #_bu1] + ldr r9, [sp, #_ga0] + ldr r10, [sp, #_ke0] + ldr r11, [sp, #_mi1] + ldr r12, [sp, #_so0] + ldr r1, [sp, #mDo0] + xorrol r8, r6, 14 + xorrol r9, r5, 18 + xorrol r10, lr, 5 + xorrol r11, r2, 8 + xorrol r12, r1, 28 + xandnot r0, _ma0, r8, r9, r10 + xandnot r0, _me0, r9, r10, r11 + xandnot r0, _mi0, r10, r11, r12 + xandnot r0, _mo0, r11, r12, r8 + xandnot r0, _mu0, r12, r8, r9 + + ldr r1, [sp, #mDi0] + ldr r8, [sp, #_bi0] + ldr r9, [sp, #_go1] + xorrol r8, r1, 31 + ldr r1, [sp, #mDo1] + ldr r10, [sp, #_ku1] + xorrol r9, r1, 28 + ldr r11, [sp, #_ma1] + ldr r12, [sp, #_se0] + xorrol r10, r6, 20 + xorrol r11, r4, 21 + xorrol r12, lr, 1 + xandnot r0, _sa0, r8, r9, r10 + xandnot r0, _se0, r9, r10, r11 + xandnot r0, _si0, r10, r11, r12 + xandnot r0, _so0, r11, r12, r8 + xandnot r0, _su0, r12, r8, r9 + + ;// thetaRhoPiChiIota 1, in A, out E + ldr r1, [sp, #mDe1] + ldr r9, [sp, #_ge1] + ldr r8, [sp, #_ba1] + xorrol r9, r1, 22 + ldr r1, [sp, #mDi0] + ldr r10, [sp, #_ki0] + eor r8, r8, r4 + xorrol r10, r1, 21 + ldr r1, [sp, #mDo0] + ldr r11, [sp, #_mo0] + ldr r12, [sp, #_su1] + xorrol r11, r1, 10 + xorrol r12, r6, 7 + xandnot r0, _be1, r9, r10, r11 + xandnot r0, _bi1, r10, r11, r12 + xandnot r0, _bo1, r11, r12, r8 + xandnot r0, _bu1, r12, r8, r9 + xandnotRC r0, _ba1, r8, r9, r10 + + ldr r1, [sp, #mDo1] + ldr r8, [sp, #_bo1] + ldr r12, [sp, #_si0] + xorrol r8, r1, 14 + ldr r1, [sp, #mDi0] + ldr r9, [sp, #_gu1] + xorrol r12, r1, 30 + ldr r10, [sp, #_ka0] + ldr r11, [sp, #_me0] + xorrol r9, r6, 10 + xorrol r10, r5, 1 + xorrol r11, lr, 22 + xandnot r0, _ga1, r8, r9, r10 + xandnot r0, _ge1, r9, r10, r11 + xandnot r0, _gi1, r10, r11, r12 + xandnot r0, _go1, r11, r12, r8 + xandnot r0, _gu1, r12, r8, r9 + + ldr r1, [sp, #mDo0] + ldr r10, [sp, #_ko0] + ldr r8, [sp, #_be0] + xorrol r10, r1, 12 + ldr r9, [sp, #_gi1] + ldr r11, [sp, #_mu1] + ldr r12, [sp, #_sa1] + eor r8, r8, lr + xorrol r9, r2, 3 + xorrol r11, r6, 4 + xorrol r12, r4, 9 + xandnot r0, _ka1, r8, r9, r10 + xandnot r0, _ke1, r9, r10, r11 + xandnot r0, _ki1, r10, r11, r12 + xandnot r0, _ko1, r11, r12, r8 + xandnot r0, _ku1, r12, r8, r9 + + ldr r1, [sp, #mDe1] + ldr r10, [sp, #_ke1] + ldr r11, [sp, #_mi0] + xorrol r10, r1, 5 + ldr r1, [sp, #mDi0] + ldr r12, [sp, #_so1] + xorrol r11, r1, 7 + ldr r1, [sp, #mDo1] + ldr r8, [sp, #_bu0] + ldr r9, [sp, #_ga1] + xorrol r8, r7, 13 + xorrol r9, r4, 18 + xorrol r12, r1, 28 + xandnot r0, _ma1, r8, r9, r10 + xandnot r0, _me1, r9, r10, r11 + xandnot r0, _mi1, r10, r11, r12 + xandnot r0, _mo1, r11, r12, r8 + xandnot r0, _mu1, r12, r8, r9 + + ldr r1, [sp, #mDo0] + ldr r9, [sp, #_go0] + ldr r8, [sp, #_bi1] + xorrol r9, r1, 27 + ldr r10, [sp, #_ku0] + ldr r11, [sp, #_ma0] + ldr r12, [sp, #_se1] + ldr r1, [sp, #mDe1] + xorrol r8, r2, 31 + xorrol r10, r7, 19 + xorrol r11, r5, 20 + xorrol r12, r1, 1 + xandnot r0, _sa1, r8, r9, r10 + xandnot r0, _se1, r9, r10, r11 + xandnot r0, _si1, r10, r11, r12 + xandnot r0, _so1, r11, r12, r8 + ldr r10, [r3] + xandnot r0, _su1, r12, r8, r9 + + cmp r10, #0xFFFFFFFF + bne roundLoop + + add sp,sp,#4*(50+4) + pop {r4-r12,pc} + + ENDP + + ALIGN + + END diff --git a/c_src/KeccakF-1600-armgcc.s b/c_src/KeccakF-1600-armgcc.s new file mode 100755 index 0000000..d16594b --- /dev/null +++ b/c_src/KeccakF-1600-armgcc.s @@ -0,0 +1,686 @@ +@ The Keccak sponge function, designed by Guido Bertoni, Joan Daemen, +@ Michaël Peeters and Gilles Van Assche. For more information, feedback or +@ questions, please refer to our website: http://keccak.noekeon.org/ +@ +@ Implementation by Ronny Van Keer, +@ hereby denoted as "the implementer". +@ +@ To the extent possible under law, the implementer has waived all copyright +@ and related or neighboring rights to the source code in this file. +@ http://creativecommons.org/publicdomain/zero/1.0/ + +@ This file was created from a .asm file +@ using the ads2gas.pl script. + .equ DO1STROUNDING, 0 + + @ PRESERVE8 + @ THUMB + .syntax unified + .cpu cortex-m3 + .thumb + + +@// --- defines + +.equ _ba0 , 0*4 +.equ _ba1 , 1*4 +.equ _be0 , 2*4 +.equ _be1 , 3*4 +.equ _bi0 , 4*4 +.equ _bi1 , 5*4 +.equ _bo0 , 6*4 +.equ _bo1 , 7*4 +.equ _bu0 , 8*4 +.equ _bu1 , 9*4 +.equ _ga0 , 10*4 +.equ _ga1 , 11*4 +.equ _ge0 , 12*4 +.equ _ge1 , 13*4 +.equ _gi0 , 14*4 +.equ _gi1 , 15*4 +.equ _go0 , 16*4 +.equ _go1 , 17*4 +.equ _gu0 , 18*4 +.equ _gu1 , 19*4 +.equ _ka0 , 20*4 +.equ _ka1 , 21*4 +.equ _ke0 , 22*4 +.equ _ke1 , 23*4 +.equ _ki0 , 24*4 +.equ _ki1 , 25*4 +.equ _ko0 , 26*4 +.equ _ko1 , 27*4 +.equ _ku0 , 28*4 +.equ _ku1 , 29*4 +.equ _ma0 , 30*4 +.equ _ma1 , 31*4 +.equ _me0 , 32*4 +.equ _me1 , 33*4 +.equ _mi0 , 34*4 +.equ _mi1 , 35*4 +.equ _mo0 , 36*4 +.equ _mo1 , 37*4 +.equ _mu0 , 38*4 +.equ _mu1 , 39*4 +.equ _sa0 , 40*4 +.equ _sa1 , 41*4 +.equ _se0 , 42*4 +.equ _se1 , 43*4 +.equ _si0 , 44*4 +.equ _si1 , 45*4 +.equ _so0 , 46*4 +.equ _so1 , 47*4 +.equ _su0 , 48*4 +.equ _su1 , 49*4 + +.equ mDe1 , 50*4 +.equ mDi0 , 51*4 +.equ mDo0 , 52*4 +.equ mDo1 , 53*4 + +@// --- macros + +.macro xor5 result,ptr,b,g,k,m,s + + ldr \result, [\ptr, #\b] + ldr r1, [\ptr, #\g] + ldr r2, [\ptr, #\k] + eor \result, \result, r1 + ldr r1, [\ptr, #\m] + eor \result, \result, r2 + ldr r2, [\ptr, #\s] + eor \result, \result, r1 + eor \result, \result, r2 + .endm + +.macro xorrol b, yy, rr + + eor \b, \b, \yy + ror \b, #32-\rr + .endm + + +.macro xandnot resptr, resofs, aa, bb, cc + + bic r1, \cc, \bb + eor r1, r1, \aa + str r1, [\resptr, #\resofs] + .endm + +.macro xandnotRC resptr, resofs, aa, bb, cc + + ldr r1, [r3], #4 + bic \cc, \cc, \bb + eor \cc, \cc, r1 + eor \cc, \cc, \aa + str \cc, [\resptr, #\resofs] + .endm + + + .size KeccakPermutationOnWords, .-KeccakPermutationOnWords + .align 2 + .global KeccakPermutationOnWordsAfterXoring_ARM_asm + .thumb + .thumb_func + .type KeccakPermutationOnWordsAfterXoring_ARM_asm, %function +KeccakPermutationOnWordsAfterXoring_ARM_asm: + @ args = 0, pretend = 0, frame = 408 + @ frame_needed = 0, uses_anonymous_args = 0 + @ link register save eliminated. + + push {r4-r12,lr} + sub sp,sp,#4*(50+4) + + movs r9, r2 + beq interleaveDone + mov r8,r0 +interleaveLoop: + + ldr r4, [r1], #4 + ldr r5, [r1], #4 + ldrd r6, r7, [r8] + + @// Credit: Henry S. Warren, Hacker's Delight, Addison-Wesley, 2002 + and r3,r4,#0x55555555 + orr r3,r3,r3, LSR #1 + and r3,r3,#0x33333333 + orr r3,r3,r3, LSR #2 + and r3,r3,#0x0F0F0F0F + orr r3,r3,r3, LSR #4 + and r3,r3,#0x00FF00FF + bfi r3,r3,#8, #8 + eor r6,r6,r3, LSR #8 + + and r3,r5,#0x55555555 + orr r3,r3,r3, LSR #1 + and r3,r3,#0x33333333 + orr r3,r3,r3, LSR #2 + and r3,r3,#0x0F0F0F0F + orr r3,r3,r3, LSR #4 + and r3,r3,#0x00FF00FF + orr r3,r3,r3, LSR #8 + eor r6,r6,r3, LSL #16 + + and r3,r4,#0xAAAAAAAA + orr r3,r3,r3, LSL #1 + and r3,r3,#0xCCCCCCCC + orr r3,r3,r3, LSL #2 + and r3,r3,#0xF0F0F0F0 + orr r3,r3,r3, LSL #4 + and r3,r3,#0xFF00FF00 + orr r3,r3,r3, LSL #8 + eor r7,r7,r3, LSR #16 + + and r3,r5,#0xAAAAAAAA + orr r3,r3,r3, LSL #1 + and r3,r3,#0xCCCCCCCC + orr r3,r3,r3, LSL #2 + and r3,r3,#0xF0F0F0F0 + orr r3,r3,r3, LSL #4 + and r3,r3,#0xFF00FF00 + orr r3,r3,r3, LSL #8 + bfc r3, #0, #16 + eor r7,r7,r3 + + strd r6,r7,[r8], #8 + + subs r9,r9,#1 + bne interleaveLoop + +interleaveDone: + + ldr r3, =KeccakF1600RoundConstantsWithTerminator + b roundLoop @//jump over the table + .ltorg + + @ ALIGN + +KeccakF1600RoundConstantsWithTerminator: + @// 0 1 + .word 0x00000001 + .word 0x00000000 + .word 0x00000000 + .word 0x00000089 + .word 0x00000000 + .word 0x8000008b + .word 0x00000000 + .word 0x80008080 + .word 0x00000001 + .word 0x0000008b + .word 0x00000001 + .word 0x00008000 + .word 0x00000001 + .word 0x80008088 + .word 0x00000001 + .word 0x80000082 + .word 0x00000000 + .word 0x0000000b + .word 0x00000000 + .word 0x0000000a + .word 0x00000001 + .word 0x00008082 + .word 0x00000000 + .word 0x00008003 + .word 0x00000001 + .word 0x0000808b + .word 0x00000001 + .word 0x8000000b + .word 0x00000001 + .word 0x8000008a + .word 0x00000001 + .word 0x80000081 + .word 0x00000000 + .word 0x80000081 + .word 0x00000000 + .word 0x80000008 + .word 0x00000000 + .word 0x00000083 + .word 0x00000000 + .word 0x80008003 + .word 0x00000001 + .word 0x80008088 + .word 0x00000000 + .word 0x80000088 + .word 0x00000001 + .word 0x00008000 + .word 0x00000000 + .word 0x80008082 + .word 0xFFFFFFFF @//terminator + +roundLoop: + + @//prepTheta A + xor5 r10, r0,_bu0, _gu0, _ku0, _mu0, _su0 + xor5 r6, r0,_be1, _ge1, _ke1, _me1, _se1 + eor r5, r10, r6, ROR #31 + xor5 r11, r0,_bu1, _gu1, _ku1, _mu1, _su1 + xor5 r7, r0,_be0, _ge0, _ke0, _me0, _se0 + eor r4, r11, r7 + + xor5 r8, r0,_bi0, _gi0, _ki0, _mi0, _si0 + eor r1, r8, r11, ROR #31 + str r1, [sp, #mDo0] + xor5 r9, r0,_bi1, _gi1, _ki1, _mi1, _si1 + eor r1, r9, r10 + str r1, [sp, #mDo1] + + xor5 r10, r0,_ba0, _ga0, _ka0, _ma0, _sa0 + eor lr, r10, r9, ROR #31 + xor5 r11, r0,_ba1, _ga1, _ka1, _ma1, _sa1 + eor r1, r11, r8 + str r1, [sp, #mDe1] + + xor5 r9, r0,_bo1, _go1, _ko1, _mo1, _so1 + eor r1, r7, r9, ROR #31 + str r1, [sp, #mDi0] + xor5 r8, r0,_bo0, _go0, _ko0, _mo0, _so0 + eor r2, r6, r8 + + eor r7, r8, r11, ROR #31 + eor r6, r9, r10 + + @//thetaRhoPiChiIota 0, in A, out E + ldr r8, [r0, #_ba0] + ldr r9, [r0, #_ge0] + ldr r10, [r0, #_ki1] + ldr r11, [r0, #_mo1] + ldr r12, [r0, #_su0] + ldr r1, [sp, #mDo1] + eor r8, r8, r5 + xorrol r9, lr, 22 + xorrol r10, r2, 22 + xorrol r11, r1, 11 + xorrol r12, r7, 7 + xandnot sp, _be0, r9, r10, r11 + xandnot sp, _bi0, r10, r11, r12 + xandnot sp, _bo0, r11, r12, r8 + xandnot sp, _bu0, r12, r8, r9 + xandnotRC sp, _ba0, r8, r9, r10 + + ldr r8, [r0, #_bo0] + ldr r1, [sp, #mDo0] + ldr r9, [r0, #_gu0] + xorrol r8, r1, 14 + ldr r1, [sp, #mDe1] + ldr r10, [r0, #_ka1] + ldr r11, [r0, #_me1] + ldr r12, [r0, #_si1] + xorrol r9, r7, 10 + xorrol r10, r4, 2 + xorrol r11, r1, 23 + xorrol r12, r2, 31 + xandnot sp, _ga0, r8, r9, r10 + xandnot sp, _ge0, r9, r10, r11 + xandnot sp, _gi0, r10, r11, r12 + xandnot sp, _go0, r11, r12, r8 + xandnot sp, _gu0, r12, r8, r9 + + ldr r8, [r0, #_be1] + ldr r1, [sp, #mDe1] + ldr r9, [r0, #_gi0] + xorrol r8, r1, 1 + ldr r1, [sp, #mDi0] + ldr r10, [r0, #_ko1] + xorrol r9, r1, 3 + ldr r1, [sp, #mDo1] + ldr r11, [r0, #_mu0] + ldr r12, [r0, #_sa0] + xorrol r10, r1, 13 + xorrol r11, r7, 4 + xorrol r12, r5, 9 + xandnot sp, _ka0, r8, r9, r10 + xandnot sp, _ke0, r9, r10, r11 + xandnot sp, _ki0, r10, r11, r12 + xandnot sp, _ko0, r11, r12, r8 + xandnot sp, _ku0, r12, r8, r9 + + ldr r8, [r0, #_bu1] + ldr r9, [r0, #_ga0] + ldr r10, [r0, #_ke0] + ldr r11, [r0, #_mi1] + ldr r12, [r0, #_so0] + ldr r1, [sp, #mDo0] + xorrol r8, r6, 14 + xorrol r9, r5, 18 + xorrol r10, lr, 5 + xorrol r11, r2, 8 + xorrol r12, r1, 28 + xandnot sp, _ma0, r8, r9, r10 + xandnot sp, _me0, r9, r10, r11 + xandnot sp, _mi0, r10, r11, r12 + xandnot sp, _mo0, r11, r12, r8 + xandnot sp, _mu0, r12, r8, r9 + + ldr r1, [sp, #mDi0] + ldr r8, [r0, #_bi0] + ldr r9, [r0, #_go1] + xorrol r8, r1, 31 + ldr r1, [sp, #mDo1] + ldr r10, [r0, #_ku1] + xorrol r9, r1, 28 + ldr r11, [r0, #_ma1] + ldr r12, [r0, #_se0] + xorrol r10, r6, 20 + xorrol r11, r4, 21 + xorrol r12, lr, 1 + xandnot sp, _sa0, r8, r9, r10 + xandnot sp, _se0, r9, r10, r11 + xandnot sp, _si0, r10, r11, r12 + xandnot sp, _so0, r11, r12, r8 + xandnot sp, _su0, r12, r8, r9 + + @// thetaRhoPiChiIota 1, in A, out E + ldr r1, [sp, #mDe1] + ldr r9, [r0, #_ge1] + ldr r8, [r0, #_ba1] + xorrol r9, r1, 22 + ldr r1, [sp, #mDi0] + ldr r10, [r0, #_ki0] + eor r8, r8, r4 + xorrol r10, r1, 21 + ldr r1, [sp, #mDo0] + ldr r11, [r0, #_mo0] + ldr r12, [r0, #_su1] + xorrol r11, r1, 10 + xorrol r12, r6, 7 + xandnot sp, _be1, r9, r10, r11 + xandnot sp, _bi1, r10, r11, r12 + xandnot sp, _bo1, r11, r12, r8 + xandnot sp, _bu1, r12, r8, r9 + xandnotRC sp, _ba1, r8, r9, r10 + + ldr r1, [sp, #mDo1] + ldr r8, [r0, #_bo1] + ldr r12, [r0, #_si0] + xorrol r8, r1, 14 + ldr r1, [sp, #mDi0] + ldr r9, [r0, #_gu1] + xorrol r12, r1, 30 + ldr r10, [r0, #_ka0] + ldr r11, [r0, #_me0] + xorrol r9, r6, 10 + xorrol r10, r5, 1 + xorrol r11, lr, 22 + xandnot sp, _ga1, r8, r9, r10 + xandnot sp, _ge1, r9, r10, r11 + xandnot sp, _gi1, r10, r11, r12 + xandnot sp, _go1, r11, r12, r8 + xandnot sp, _gu1, r12, r8, r9 + + ldr r1, [sp, #mDo0] + ldr r10, [r0, #_ko0] + ldr r8, [r0, #_be0] + xorrol r10, r1, 12 + ldr r9, [r0, #_gi1] + ldr r11, [r0, #_mu1] + ldr r12, [r0, #_sa1] + eor r8, r8, lr + xorrol r9, r2, 3 + xorrol r11, r6, 4 + xorrol r12, r4, 9 + xandnot sp, _ka1, r8, r9, r10 + xandnot sp, _ke1, r9, r10, r11 + xandnot sp, _ki1, r10, r11, r12 + xandnot sp, _ko1, r11, r12, r8 + xandnot sp, _ku1, r12, r8, r9 + + ldr r1, [sp, #mDe1] + ldr r10, [r0, #_ke1] + ldr r11, [r0, #_mi0] + xorrol r10, r1, 5 + ldr r1, [sp, #mDi0] + ldr r12, [r0, #_so1] + xorrol r11, r1, 7 + ldr r1, [sp, #mDo1] + ldr r8, [r0, #_bu0] + ldr r9, [r0, #_ga1] + xorrol r8, r7, 13 + xorrol r9, r4, 18 + xorrol r12, r1, 28 + xandnot sp, _ma1, r8, r9, r10 + xandnot sp, _me1, r9, r10, r11 + xandnot sp, _mi1, r10, r11, r12 + xandnot sp, _mo1, r11, r12, r8 + xandnot sp, _mu1, r12, r8, r9 + + ldr r1, [sp, #mDo0] + ldr r9, [r0, #_go0] + ldr r8, [r0, #_bi1] + xorrol r9, r1, 27 + ldr r10, [r0, #_ku0] + ldr r11, [r0, #_ma0] + ldr r12, [r0, #_se1] + ldr r1, [sp, #mDe1] + xorrol r8, r2, 31 + xorrol r10, r7, 19 + xorrol r11, r5, 20 + xorrol r12, r1, 1 + xandnot sp, _sa1, r8, r9, r10 + xandnot sp, _se1, r9, r10, r11 + xandnot sp, _si1, r10, r11, r12 + xandnot sp, _so1, r11, r12, r8 + xandnot sp, _su1, r12, r8, r9 + + @//prepTheta E + xor5 r10, sp,_bu0, _gu0, _ku0, _mu0, _su0 + xor5 r6, sp,_be1, _ge1, _ke1, _me1, _se1 + eor r5, r10, r6, ROR #31 + xor5 r11, sp,_bu1, _gu1, _ku1, _mu1, _su1 + xor5 r7, sp,_be0, _ge0, _ke0, _me0, _se0 + eor r4, r11, r7 + + xor5 r8, sp,_bi0, _gi0, _ki0, _mi0, _si0 + eor r1, r8, r11, ROR #31 + str r1, [sp, #mDo0] + xor5 r9, sp,_bi1, _gi1, _ki1, _mi1, _si1 + eor r1, r9, r10 + str r1, [sp, #mDo1] + + xor5 r10, sp,_ba0, _ga0, _ka0, _ma0, _sa0 + eor lr, r10, r9, ROR #31 + xor5 r11, sp,_ba1, _ga1, _ka1, _ma1, _sa1 + eor r1, r11, r8 + str r1, [sp, #mDe1] + + xor5 r9, sp,_bo1, _go1, _ko1, _mo1, _so1 + eor r1, r7, r9, ROR #31 + str r1, [sp, #mDi0] + xor5 r8, sp,_bo0, _go0, _ko0, _mo0, _so0 + eor r2, r6, r8 + + eor r7, r8, r11, ROR #31 + eor r6, r9, r10 + + @//thetaRhoPiChiIota 0, in E, out A + ldr r8, [sp, #_ba0] + ldr r9, [sp, #_ge0] + ldr r10, [sp, #_ki1] + ldr r11, [sp, #_mo1] + ldr r12, [sp, #_su0] + ldr r1, [sp, #mDo1] + eor r8, r8, r5 + xorrol r9, lr, 22 + xorrol r10, r2, 22 + xorrol r11, r1, 11 + xorrol r12, r7, 7 + xandnot r0, _be0, r9, r10, r11 + xandnot r0, _bi0, r10, r11, r12 + xandnot r0, _bo0, r11, r12, r8 + xandnot r0, _bu0, r12, r8, r9 + xandnotRC r0, _ba0, r8, r9, r10 + + ldr r8, [sp, #_bo0] + ldr r1, [sp, #mDo0] + ldr r9, [sp, #_gu0] + xorrol r8, r1, 14 + ldr r1, [sp, #mDe1] + ldr r10, [sp, #_ka1] + ldr r11, [sp, #_me1] + ldr r12, [sp, #_si1] + xorrol r9, r7, 10 + xorrol r10, r4, 2 + xorrol r11, r1, 23 + xorrol r12, r2, 31 + xandnot r0, _ga0, r8, r9, r10 + xandnot r0, _ge0, r9, r10, r11 + xandnot r0, _gi0, r10, r11, r12 + xandnot r0, _go0, r11, r12, r8 + xandnot r0, _gu0, r12, r8, r9 + + ldr r8, [sp, #_be1] + ldr r1, [sp, #mDe1] + ldr r9, [sp, #_gi0] + xorrol r8, r1, 1 + ldr r1, [sp, #mDi0] + ldr r10, [sp, #_ko1] + xorrol r9, r1, 3 + ldr r1, [sp, #mDo1] + ldr r11, [sp, #_mu0] + ldr r12, [sp, #_sa0] + xorrol r10, r1, 13 + xorrol r11, r7, 4 + xorrol r12, r5, 9 + xandnot r0, _ka0, r8, r9, r10 + xandnot r0, _ke0, r9, r10, r11 + xandnot r0, _ki0, r10, r11, r12 + xandnot r0, _ko0, r11, r12, r8 + xandnot r0, _ku0, r12, r8, r9 + + ldr r8, [sp, #_bu1] + ldr r9, [sp, #_ga0] + ldr r10, [sp, #_ke0] + ldr r11, [sp, #_mi1] + ldr r12, [sp, #_so0] + ldr r1, [sp, #mDo0] + xorrol r8, r6, 14 + xorrol r9, r5, 18 + xorrol r10, lr, 5 + xorrol r11, r2, 8 + xorrol r12, r1, 28 + xandnot r0, _ma0, r8, r9, r10 + xandnot r0, _me0, r9, r10, r11 + xandnot r0, _mi0, r10, r11, r12 + xandnot r0, _mo0, r11, r12, r8 + xandnot r0, _mu0, r12, r8, r9 + + ldr r1, [sp, #mDi0] + ldr r8, [sp, #_bi0] + ldr r9, [sp, #_go1] + xorrol r8, r1, 31 + ldr r1, [sp, #mDo1] + ldr r10, [sp, #_ku1] + xorrol r9, r1, 28 + ldr r11, [sp, #_ma1] + ldr r12, [sp, #_se0] + xorrol r10, r6, 20 + xorrol r11, r4, 21 + xorrol r12, lr, 1 + xandnot r0, _sa0, r8, r9, r10 + xandnot r0, _se0, r9, r10, r11 + xandnot r0, _si0, r10, r11, r12 + xandnot r0, _so0, r11, r12, r8 + xandnot r0, _su0, r12, r8, r9 + + @// thetaRhoPiChiIota 1, in A, out E + ldr r1, [sp, #mDe1] + ldr r9, [sp, #_ge1] + ldr r8, [sp, #_ba1] + xorrol r9, r1, 22 + ldr r1, [sp, #mDi0] + ldr r10, [sp, #_ki0] + eor r8, r8, r4 + xorrol r10, r1, 21 + ldr r1, [sp, #mDo0] + ldr r11, [sp, #_mo0] + ldr r12, [sp, #_su1] + xorrol r11, r1, 10 + xorrol r12, r6, 7 + xandnot r0, _be1, r9, r10, r11 + xandnot r0, _bi1, r10, r11, r12 + xandnot r0, _bo1, r11, r12, r8 + xandnot r0, _bu1, r12, r8, r9 + xandnotRC r0, _ba1, r8, r9, r10 + + ldr r1, [sp, #mDo1] + ldr r8, [sp, #_bo1] + ldr r12, [sp, #_si0] + xorrol r8, r1, 14 + ldr r1, [sp, #mDi0] + ldr r9, [sp, #_gu1] + xorrol r12, r1, 30 + ldr r10, [sp, #_ka0] + ldr r11, [sp, #_me0] + xorrol r9, r6, 10 + xorrol r10, r5, 1 + xorrol r11, lr, 22 + xandnot r0, _ga1, r8, r9, r10 + xandnot r0, _ge1, r9, r10, r11 + xandnot r0, _gi1, r10, r11, r12 + xandnot r0, _go1, r11, r12, r8 + xandnot r0, _gu1, r12, r8, r9 + + ldr r1, [sp, #mDo0] + ldr r10, [sp, #_ko0] + ldr r8, [sp, #_be0] + xorrol r10, r1, 12 + ldr r9, [sp, #_gi1] + ldr r11, [sp, #_mu1] + ldr r12, [sp, #_sa1] + eor r8, r8, lr + xorrol r9, r2, 3 + xorrol r11, r6, 4 + xorrol r12, r4, 9 + xandnot r0, _ka1, r8, r9, r10 + xandnot r0, _ke1, r9, r10, r11 + xandnot r0, _ki1, r10, r11, r12 + xandnot r0, _ko1, r11, r12, r8 + xandnot r0, _ku1, r12, r8, r9 + + ldr r1, [sp, #mDe1] + ldr r10, [sp, #_ke1] + ldr r11, [sp, #_mi0] + xorrol r10, r1, 5 + ldr r1, [sp, #mDi0] + ldr r12, [sp, #_so1] + xorrol r11, r1, 7 + ldr r1, [sp, #mDo1] + ldr r8, [sp, #_bu0] + ldr r9, [sp, #_ga1] + xorrol r8, r7, 13 + xorrol r9, r4, 18 + xorrol r12, r1, 28 + xandnot r0, _ma1, r8, r9, r10 + xandnot r0, _me1, r9, r10, r11 + xandnot r0, _mi1, r10, r11, r12 + xandnot r0, _mo1, r11, r12, r8 + xandnot r0, _mu1, r12, r8, r9 + + ldr r1, [sp, #mDo0] + ldr r9, [sp, #_go0] + ldr r8, [sp, #_bi1] + xorrol r9, r1, 27 + ldr r10, [sp, #_ku0] + ldr r11, [sp, #_ma0] + ldr r12, [sp, #_se1] + ldr r1, [sp, #mDe1] + xorrol r8, r2, 31 + xorrol r10, r7, 19 + xorrol r11, r5, 20 + xorrol r12, r1, 1 + xandnot r0, _sa1, r8, r9, r10 + xandnot r0, _se1, r9, r10, r11 + xandnot r0, _si1, r10, r11, r12 + xandnot r0, _so1, r11, r12, r8 + ldr r10, [r3] + xandnot r0, _su1, r12, r8, r9 + + cmp r10, #0xFFFFFFFF + bne roundLoop + + add sp,sp,#4*(50+4) + pop {r4-r12,pc} + + @ + + @ ALIGN + diff --git a/c_src/KeccakF-1600-avr8.c b/c_src/KeccakF-1600-avr8.c new file mode 100755 index 0000000..7ea2679 --- /dev/null +++ b/c_src/KeccakF-1600-avr8.c @@ -0,0 +1,163 @@ +/* +The Keccak sponge function, designed by Guido Bertoni, Joan Daemen, +Michaël Peeters and Gilles Van Assche. For more information, feedback or +questions, please refer to our website: http://keccak.noekeon.org/ + +Implementation by Ronny Van Keer, +hereby denoted as "the implementer". + +To the extent possible under law, the implementer has waived all copyright +and related or neighboring rights to the source code in this file. +http://creativecommons.org/publicdomain/zero/1.0/ +*/ + +#include +#include +#include "AVR8-rotate64.h" + +typedef unsigned char UINT8; +typedef UINT8 tSmallUInt; +typedef unsigned long long UINT64; +typedef UINT64 tKeccakLane; + +#define cKeccakLaneSizeInBits (sizeof(tKeccakLane) * 8) + +#define cKeccakNumberOfRounds 24 + +static tKeccakLane KeccakF_RoundConstants[cKeccakNumberOfRounds] PROGMEM = +{ + (tKeccakLane)0x0000000000000001ULL, + (tKeccakLane)0x0000000000008082ULL, + (tKeccakLane)0x800000000000808aULL, + (tKeccakLane)0x8000000080008000ULL, + (tKeccakLane)0x000000000000808bULL, + (tKeccakLane)0x0000000080000001ULL, + (tKeccakLane)0x8000000080008081ULL, + (tKeccakLane)0x8000000000008009ULL, + (tKeccakLane)0x000000000000008aULL, + (tKeccakLane)0x0000000000000088ULL, + (tKeccakLane)0x0000000080008009ULL, + (tKeccakLane)0x000000008000000aULL, + (tKeccakLane)0x000000008000808bULL, + (tKeccakLane)0x800000000000008bULL, + (tKeccakLane)0x8000000000008089ULL, + (tKeccakLane)0x8000000000008003ULL, + (tKeccakLane)0x8000000000008002ULL, + (tKeccakLane)0x8000000000000080ULL, + (tKeccakLane)0x000000000000800aULL, + (tKeccakLane)0x800000008000000aULL, + (tKeccakLane)0x8000000080008081ULL, + (tKeccakLane)0x8000000000008080ULL, + (tKeccakLane)0x0000000080000001ULL, + (tKeccakLane)0x8000000080008008ULL +}; + +static tSmallUInt KeccakF_RotationConstants[24] PROGMEM = +{ + ROT_CODE( 1), ROT_CODE( 3), ROT_CODE( 6), ROT_CODE(10), ROT_CODE(15), + ROT_CODE(21), ROT_CODE(28), ROT_CODE(36), ROT_CODE(45), ROT_CODE(55), + ROT_CODE( 2), ROT_CODE(14), ROT_CODE(27), ROT_CODE(41), ROT_CODE(56), + ROT_CODE( 8), ROT_CODE(25), ROT_CODE(43), ROT_CODE(62), ROT_CODE(18), + ROT_CODE(39), ROT_CODE(61), ROT_CODE(20), ROT_CODE(44) +}; + +static tSmallUInt KeccakF_PiLane[24] PROGMEM = +{ + 10, 7, 11, 17, 18, 3, 5, 16, 8, 21, 24, 4, 15, 23, 19, 13, 12, 2, 20, 14, 22, 9, 6, 1 +}; + +static tSmallUInt KeccakF_Mod5[10] PROGMEM = +{ + 0, 1, 2, 3, 4, 0, 1, 2, 3, 4 +}; + + +void KeccakF( tKeccakLane * state ) +{ + tSmallUInt round; + tKeccakLane C[5]; + + // prepare Theta + { + tSmallUInt x; + tKeccakLane * pC; + for ( x = 0, pC = C; x < 5; ++x, ++pC ) + { + *pC = state[x] ^ state[5 + x] ^ state[10 + x] ^ state[15 + x] ^ state[20 + x]; + } + } + + for( round = 0; round < cKeccakNumberOfRounds; ++round ) + { + // Theta + { + tSmallUInt x; + for ( x = 0; x < 5; ++x ) + { + tKeccakLane temp; + tSmallUInt y; + temp = rotate64_1bit_left( C[pgm_read_byte((KeccakF_Mod5+1)+x)] ); + temp ^= C[pgm_read_byte((KeccakF_Mod5+4)+x)]; + for ( y = 0; y < 25; y += 5 ) + { + state[y + x] ^= temp; + } + } + } + + // Rho Pi + { + tKeccakLane temp; + tSmallUInt x; + + temp = state[1]; + for ( x = 0; x < 24; ++x ) + { + tSmallUInt t; + tKeccakLane T[1]; + t = pgm_read_byte(&KeccakF_PiLane[x]); + T[0] = state[t]; + state[t] = rotate64left_code( temp, pgm_read_byte(&KeccakF_RotationConstants[x]) ); + temp = T[0]; + } + } + + // Chi Iota Prepare Theta + { + tSmallUInt z; + UINT8 * p = (unsigned char *)state; + UINT8 * pC = (unsigned char *)C; + + for( z = 0; z < 8; ++z, ++p, ++pC ) + { + tSmallUInt y; + UINT8 c0, c1, c2, c3, c4, t; + + c0 = c1 = c2 = c3 = c4 = 0; + for( y = 5; y != 0; --y, p += 40 ) + { + UINT8 a0 = *p; + UINT8 a1 = *(p+8); + UINT8 a2 = *(p+16); + UINT8 a3 = *(p+24); + UINT8 a4 = *(p+32); + + *p = t = a0 ^ ((~a1) & a2); c0 ^= t; + *(p+8) = t = a1 ^ ((~a2) & a3); c1 ^= t; + *(p+16) = a2 ^= ((~a3) & a4); c2 ^= a2; + *(p+24) = a3 ^= ((~a4) & a0); c3 ^= a3; + *(p+32) = a4 ^= ((~a0) & a1); c4 ^= a4; + } + p -= 5 * 5 * 8; + y = pgm_read_byte( (UINT8 *)(KeccakF_RoundConstants+round) + z ); + *p ^= y; + *pC = c0 ^ y; + *(pC+ 8) = c1; + *(pC+16) = c2; + *(pC+24) = c3; + *(pC+32) = c4; + } + } + } + +} diff --git a/c_src/KeccakF-1600-avr8asm-compact.s b/c_src/KeccakF-1600-avr8asm-compact.s new file mode 100755 index 0000000..c87920f --- /dev/null +++ b/c_src/KeccakF-1600-avr8asm-compact.s @@ -0,0 +1,647 @@ +/* +The Keccak sponge function, designed by Guido Bertoni, Joan Daemen, +Michaël Peeters and Gilles Van Assche. For more information, feedback or +questions, please refer to our website: http://keccak.noekeon.org/ + +Implementation by Ronny Van Keer, hereby denoted as "the implementer". + +To the extent possible under law, the implementer has waived all copyright +and related or neighboring rights to the source code in this file. +http://creativecommons.org/publicdomain/zero/1.0/ +*/ + +#include "Keccak-avr8-settings.h" +#include "crypto_hash.h" + +#define cKeccakR_SizeInBytes (cKeccakR/8) + +#ifndef crypto_hash_BYTES + #ifdef cKeccakFixedOutputLengthInBytes + #define crypto_hash_BYTES cKeccakFixedOutputLengthInBytes + #else + #define crypto_hash_BYTES cKeccakR_SizeInBytes + #endif +#endif + +// Registers used in all routines +#define zero 1 +#define rpState 24 +#define rX 26 +#define rY 28 +#define rZ 30 + + +/* + * int crypto_hash( unsigned char *out, const unsigned char *in, unsigned long long inlen ) + * + * argument out is passed in r24:r25 + * argument in is passed in r22:r23 + * argument inlen is passed in r14:r21, only lowest 16-bits (r14-r15) are used + */ +.global crypto_hash // populate.py, please update crypto_hash +crypto_hash: // populate.py, please update crypto_hash + + // crypto_hash only registers + #define rT1 16 + #define rT2 17 + #define rT3 18 + #define rInLen 22 //(2 regs) + #define sp 0x3D + + push r2 + push r3 + push r4 + push r5 + push r6 + push r7 + push r8 + push r9 + push r10 + push r11 + push r12 + push r13 + push r14 + push r15 + push r16 + push r17 + push r28 + push r29 + + // Allocate state (25*8) + C variables (5*8) + in rZ, sp + in rZ+1, sp+1 + subi rZ, 240 + sbci rZ+1, 0 + in r0, 0x3F + cli + out sp+1, rZ+1 + out sp, rZ + out 0x3F, r0 + adiw rZ, 41 // pointer to start of state, end of C, compensate post decrement + + push r24 // save out pointer + push r25 + + movw rpState, rZ + movw rY, r22 //y contains in pointer + movw rInLen, r14 + + ldi rT3, 5*5*8 //clear state +clearStateLoop: + st z+, zero + dec rT3 + brne clearStateLoop + + // Full blocks + cpi rInLen, cKeccakR_SizeInBytes + cpc rInLen+1, zero + brcs ch_lastblock + +ch_FullRateLoop: + ldi rT3, cKeccakR_SizeInBytes + movw rZ, rpState +ch_XorLanesLoop: + ld rT1, Y+ + ld rT2, Z + eor rT1, rT2 + st Z+, rT1 + subi rT3, 1 + brne ch_XorLanesLoop + + push rY + push rY+1 + call KeccakF + pop rY+1 + pop rY + + subi rInLen, cKeccakR_SizeInBytes + sbci rInLen+1, 0 + cpi rInLen, cKeccakR_SizeInBytes + cpc rInLen+1, zero + brcc ch_FullRateLoop + +ch_lastblock: // XOR last uncomplete block into state + movw rZ, rpState + + subi rInLen, 0 + breq ch_Padding +ch_xorBytesLoop: + ld rT1, Y+ + ld rT2, Z + eor rT1, rT2 + st Z+, rT1 + subi rInLen, 1 + brne ch_xorBytesLoop + +ch_Padding: + ldi rT1, 1 + ld rT2, Z + eor rT1, rT2 + st Z, rT1 + + ldi rZ, cKeccakR_SizeInBytes-1 + add rZ, rpState + mov rZ+1, rpState+1 + adc rZ+1, zero + ld rT1, Z + subi rT1, 0x80 + st Z, rT1 + + call KeccakF + + //output + ldi rT3, crypto_hash_BYTES + movw rY, rpState + pop rZ+1 ; restore out pointer + pop rZ +outputLoop: + ld rT1, Y+ + st Z+, rT1 + dec rT3 + brne outputLoop + + + // Free state and pop registers + ldi rZ, 199 + add rpState, rZ + adc rpState+1, zero + in r0, 0x3F + cli + out sp+1, rpState+1 + out sp, rpState + out 0x3F, r0 + + pop r29 + pop r28 + pop r17 + pop r16 + pop r15 + pop r14 + pop r13 + pop r12 + pop r11 + pop r10 + pop r9 + pop r8 + pop r7 + pop r6 + pop r5 + pop r4 + pop r3 + pop r2 + + // return 0 + mov r24, zero + mov r25, zero + + #undef rInLen + #undef rT1 + #undef rT2 + #undef rT3 + #undef sp + + ret + + +//#define ROT_BIT(a) (a <= 4) ? ((a == 0) ? 0x80 : (a & 7)) : (0x80 | (8-a)) + +#define ROT_BIT(a) ((a) & 7) +#define ROT_BYTE(a) (((a)/8 + !!(((a)%8) > 4)) & 7) + +KeccakF_RhoPiConstants: + .BYTE ROT_BIT( 1), ROT_BYTE( 3), 10 * 8 + .BYTE ROT_BIT( 3), ROT_BYTE( 6), 7 * 8 + .BYTE ROT_BIT( 6), ROT_BYTE(10), 11 * 8 + .BYTE ROT_BIT(10), ROT_BYTE(15), 17 * 8 + .BYTE ROT_BIT(15), ROT_BYTE(21), 18 * 8 + .BYTE ROT_BIT(21), ROT_BYTE(28), 3 * 8 + .BYTE ROT_BIT(28), ROT_BYTE(36), 5 * 8 + .BYTE ROT_BIT(36), ROT_BYTE(45), 16 * 8 + .BYTE ROT_BIT(45), ROT_BYTE(55), 8 * 8 + .BYTE ROT_BIT(55), ROT_BYTE( 2), 21 * 8 + .BYTE ROT_BIT( 2), ROT_BYTE(14), 24 * 8 + .BYTE ROT_BIT(14), ROT_BYTE(27), 4 * 8 + .BYTE ROT_BIT(27), ROT_BYTE(41), 15 * 8 + .BYTE ROT_BIT(41), ROT_BYTE(56), 23 * 8 + .BYTE ROT_BIT(56), ROT_BYTE( 8), 19 * 8 + .BYTE ROT_BIT( 8), ROT_BYTE(25), 13 * 8 + .BYTE ROT_BIT(25), ROT_BYTE(43), 12 * 8 + .BYTE ROT_BIT(43), ROT_BYTE(62), 2 * 8 + .BYTE ROT_BIT(62), ROT_BYTE(18), 20 * 8 + .BYTE ROT_BIT(18), ROT_BYTE(39), 14 * 8 + .BYTE ROT_BIT(39), ROT_BYTE(61), 22 * 8 + .BYTE ROT_BIT(61), ROT_BYTE(20), 9 * 8 + .BYTE ROT_BIT(20), ROT_BYTE(44), 6 * 8 + .BYTE ROT_BIT(44), ROT_BYTE( 1), 1 * 8 + + +KeccakF_RoundConstants: + .BYTE 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + .BYTE 0x82, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + .BYTE 0x8a, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80 + .BYTE 0x00, 0x80, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80 + .BYTE 0x8b, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + .BYTE 0x01, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00 + .BYTE 0x81, 0x80, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80 + .BYTE 0x09, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80 + .BYTE 0x8a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + .BYTE 0x88, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + .BYTE 0x09, 0x80, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00 + .BYTE 0x0a, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00 + .BYTE 0x8b, 0x80, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00 + .BYTE 0x8b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80 + .BYTE 0x89, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80 + .BYTE 0x03, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80 + .BYTE 0x02, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80 + .BYTE 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80 + .BYTE 0x0a, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + .BYTE 0x0a, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80 + .BYTE 0x81, 0x80, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80 + .BYTE 0x80, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80 + .BYTE 0x01, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00 + .BYTE 0x08, 0x80, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80 + .BYTE 0xFF, 0 //terminator + + .text + + + +// KeccakF +// Not callable from C! +// +// argument rpState is passed in r24:r25 +// +KeccakF: + + // Variables used in multiple operations + #define rTemp 2 // 8 regs (2-9) + #define rTempBis 10 // 8 regs (10-17) + #define rTempTer 18 // 2 regs (18-19) + #define pRound 20 // 2 regs (20-21) + + // Initial Prepare Theta + #define TCIPx rTempTer + + movw rZ, rpState // Z points to 5 C lanes + sbiw rZ, 40 + movw rY, rpState + ldi TCIPx, 5*8 +KeccakInitialPrepTheta_Loop: + ld r0, Y + adiw rY, 40 + ld rTemp, Y + adiw rY, 40 + eor r0, rTemp + ld rTemp, Y + adiw rY, 40 + eor r0, rTemp + ld rTemp, Y + eor r0, rTemp + ldd rTemp, Y+40 + eor r0, rTemp + st Z+, r0 + subi rY, 119 + sbc rY+1, zero + dec TCIPx + brne KeccakInitialPrepTheta_Loop + #undef TCIPx + + ldi pRound, lo8(KeccakF_RoundConstants) + ldi pRound+1, hi8(KeccakF_RoundConstants) +Keccak_RoundLoop: + + // Theta + #define TCplus rX + #define TCminus rZ + #define TCcoordX rTempTer + #define TCcoordY rTempTer+1 + + movw TCminus, rpState + sbiw TCminus, 1*8 + movw TCplus, rpState + sbiw TCplus, 4*8 + movw rY, rpState + + ldi TCcoordX, 0x16 +KeccakTheta_Loop1: + ld rTemp+0, X+ + ld rTemp+1, X+ + ld rTemp+2, X+ + ld rTemp+3, X+ + ld rTemp+4, X+ + ld rTemp+5, X+ + ld rTemp+6, X+ + ld rTemp+7, X+ + + lsl rTemp+0 + rol rTemp+1 + rol rTemp+2 + rol rTemp+3 + rol rTemp+4 + rol rTemp+5 + rol rTemp+6 + rol rTemp+7 + adc rTemp+0, zero + + ld r0, Z+ + eor rTemp+0, r0 + ld r0, Z+ + eor rTemp+1, r0 + ld r0, Z+ + eor rTemp+2, r0 + ld r0, Z+ + eor rTemp+3, r0 + ld r0, Z+ + eor rTemp+4, r0 + ld r0, Z+ + eor rTemp+5, r0 + ld r0, Z+ + eor rTemp+6, r0 + ld r0, Z+ + eor rTemp+7, r0 + + ldi TCcoordY, 5 +KeccakTheta_Loop2: + ld r0, Y + eor r0, rTemp+0 + st Y+, r0 + ld r0, Y + eor r0, rTemp+1 + st Y+, r0 + ld r0, Y + eor r0, rTemp+2 + st Y+, r0 + ld r0, Y + eor r0, rTemp+3 + st Y+, r0 + ld r0, Y + eor r0, rTemp+4 + st Y+, r0 + ld r0, Y + eor r0, rTemp+5 + st Y+, r0 + ld r0, Y + eor r0, rTemp+6 + st Y+, r0 + ld r0, Y + eor r0, rTemp+7 + st Y+, r0 + adiw rY, 32 + + dec TCcoordY + brne KeccakTheta_Loop2 + + subi rY, 200-8 + sbc rY+1, zero + + lsr TCcoordX + brcc 1f + breq KeccakTheta_End + rjmp KeccakTheta_Loop1 +1: + cpi TCcoordX, 0x0B + brne 2f + sbiw TCminus, 40 + rjmp KeccakTheta_Loop1 +2: + sbiw TCplus, 40 + rjmp KeccakTheta_Loop1 + +KeccakTheta_End: + #undef TCplus + #undef TCminus + #undef TCcoordX + #undef TCcoordY + + + // Rho Pi + #define RPindex rTempTer+0 + #define RPTemp rTempTer+1 + + sbiw rY, 32 + + ld rTemp+0, Y+ + ld rTemp+1, Y+ + ld rTemp+2, Y+ + ld rTemp+3, Y+ + ld rTemp+4, Y+ + ld rTemp+5, Y+ + ld rTemp+6, Y+ + ld rTemp+7, Y+ + + ldi rZ, lo8(KeccakF_RhoPiConstants) + ldi rZ+1, hi8(KeccakF_RhoPiConstants) + +KeccakRhoPi_Loop: + ; do bit rotation + lpm RPTemp, Z+ ;get nuber of bits to rotate + cpi RPTemp, 5 + brcs rotate64_nbit_leftOrNot + neg RPTemp + andi RPTemp, 3 + +rotate64_nbit_right: + bst rTemp, 0 + ror rTemp+7 + ror rTemp+6 + ror rTemp+5 + ror rTemp+4 + ror rTemp+3 + ror rTemp+2 + ror rTemp+1 + ror rTemp + bld rTemp+7, 7 + dec RPTemp + brne rotate64_nbit_right + rjmp KeccakRhoPi_RhoBitRotateDone + +rotate64_nbit_leftOrNot: + tst RPTemp + breq KeccakRhoPi_RhoBitRotateDone +rotate64_nbit_left: + lsl rTemp + rol rTemp+1 + rol rTemp+2 + rol rTemp+3 + rol rTemp+4 + rol rTemp+5 + rol rTemp+6 + rol rTemp+7 + adc rTemp, r1 + dec RPTemp + brne rotate64_nbit_left + +KeccakRhoPi_RhoBitRotateDone: + lpm r0, Z+ ;get number of bytes to rotate + lpm RPindex, Z+ ;get index in state + movw rY, rpState + add rY, RPindex + adc rY+1, zero + + ldi rX, rTempBis + add rX, r0 + mov rX+1, zero + ldi RPTemp, 8 +KeccakRhoPi_PiByteRotLoop: + ld r0, Y+ + st X+, r0 + cpi rX, rTempBis+8 + brne KeccakRhoPi_PiByteRotFirst + ldi rX, rTempBis +KeccakRhoPi_PiByteRotFirst: + dec RPTemp + brne KeccakRhoPi_PiByteRotLoop + + sbiw rY, 8 + st Y+, rTemp+0 + st Y+, rTemp+1 + st Y+, rTemp+2 + st Y+, rTemp+3 + st Y+, rTemp+4 + st Y+, rTemp+5 + st Y+, rTemp+6 + st Y+, rTemp+7 + + movw rTemp+0, rTempBis+0 + movw rTemp+2, rTempBis+2 + movw rTemp+4, rTempBis+4 + movw rTemp+6, rTempBis+6 +KeccakRhoPi_RhoDone: + subi RPindex, 8 + brne KeccakRhoPi_Loop + + #undef RPindex + #undef RPTemp + + + // Chi Iota prepare Theta + #define CIPTa0 rTemp + #define CIPTa1 rTemp+1 + #define CIPTa2 rTemp+2 + #define CIPTa3 rTemp+3 + #define CIPTa4 rTemp+4 + #define CIPTc0 rTempBis + #define CIPTc1 rTempBis+1 + #define CIPTc2 rTempBis+2 + #define CIPTc3 rTempBis+3 + #define CIPTc4 rTempBis+4 + #define CIPTz rTempBis+6 + #define CIPTy rTempBis+7 + + movw rY, rpState + movw rX, rpState ; 5 * C + sbiw rX, 40 + movw rZ, pRound + + ldi CIPTz, 8 +KeccakChiIotaPrepareTheta_zLoop: + mov CIPTc0, zero + mov CIPTc1, zero + movw CIPTc2, CIPTc0 + mov CIPTc4, zero + + ldi CIPTy, 5 +KeccakChiIotaPrepareTheta_yLoop: + ld CIPTa0, Y + ldd CIPTa1, Y+8 + ldd CIPTa2, Y+16 + ldd CIPTa3, Y+24 + ldd CIPTa4, Y+32 + + ;*p = t = a0 ^ ((~a1) & a2); c0 ^= t; + mov r0, CIPTa1 + com r0 + and r0, CIPTa2 + eor r0, CIPTa0 + eor CIPTc0, r0 + st Y, r0 + + ;*(p+8) = t = a1 ^ ((~a2) & a3); c1 ^= t; + mov r0, CIPTa2 + com r0 + and r0, CIPTa3 + eor r0, CIPTa1 + eor CIPTc1, r0 + std Y+8, r0 + + ;*(p+16) = a2 ^= ((~a3) & a4); c2 ^= a2; + mov r0, CIPTa3 + com r0 + and r0, CIPTa4 + eor r0, CIPTa2 + eor CIPTc2, r0 + std Y+16, r0 + + ;*(p+24) = a3 ^= ((~a4) & a0); c3 ^= a3; + mov r0, CIPTa4 + com r0 + and r0, CIPTa0 + eor r0, CIPTa3 + eor CIPTc3, r0 + std Y+24, r0 + + ;*(p+32) = a4 ^= ((~a0) & a1); c4 ^= a4; + com CIPTa0 + and CIPTa0, CIPTa1 + eor CIPTa0, CIPTa4 + eor CIPTc4, CIPTa0 + std Y+32, CIPTa0 + + adiw rY, 40 + dec CIPTy + brne KeccakChiIotaPrepareTheta_yLoop + + subi rY, 200 + sbc rY+1, zero + + lpm r0, Z+ ;Round Constant + ld CIPTa0, Y + eor CIPTa0, r0 + st Y+, CIPTa0 + + movw pRound, rZ + movw rZ, rX + eor CIPTc0, r0 + st Z+, CIPTc0 + std Z+7, CIPTc1 + std Z+15, CIPTc2 + std Z+23, CIPTc3 + std Z+31, CIPTc4 + movw rX, rZ + movw rZ, pRound + + dec CIPTz + brne KeccakChiIotaPrepareTheta_zLoop + + #undef CIPTa0 + #undef CIPTa1 + #undef CIPTa2 + #undef CIPTa3 + #undef CIPTa4 + #undef CIPTc0 + #undef CIPTc1 + #undef CIPTc2 + #undef CIPTc3 + #undef CIPTc4 + #undef CIPTz + #undef CIPTy + + + ;Check for terminator + lpm r0, Z + inc r0 + breq Keccak_Done + rjmp Keccak_RoundLoop +Keccak_Done: + ret + + #undef rTemp + #undef rTempBis + #undef rTempTer + #undef pRound + + #undef rpState + #undef zero + #undef rX + #undef rY + #undef rZ diff --git a/c_src/KeccakF-1600-avr8asm-fast.s b/c_src/KeccakF-1600-avr8asm-fast.s new file mode 100755 index 0000000..e27f174 --- /dev/null +++ b/c_src/KeccakF-1600-avr8asm-fast.s @@ -0,0 +1,934 @@ +/* +The Keccak sponge function, designed by Guido Bertoni, Joan Daemen, +Michaël Peeters and Gilles Van Assche. For more information, feedback or +questions, please refer to our website: http://keccak.noekeon.org/ + +Implementation by Ronny Van Keer, hereby denoted as "the implementer". + +To the extent possible under law, the implementer has waived all copyright +and related or neighboring rights to the source code in this file. +http://creativecommons.org/publicdomain/zero/1.0/ +*/ + +#include "Keccak-avr8-settings.h" +#include "crypto_hash.h" + +#define cKeccakR_SizeInBytes (cKeccakR/8) + +#ifndef crypto_hash_BYTES + #ifdef cKeccakFixedOutputLengthInBytes + #define crypto_hash_BYTES cKeccakFixedOutputLengthInBytes + #else + #define crypto_hash_BYTES cKeccakR_SizeInBytes + #endif +#endif + +// Registers used in all routines +#define zero 1 +#define rpState 24 +#define rX 26 +#define rY 28 +#define rZ 30 + + +/* + * int crypto_hash( unsigned char *out, const unsigned char *in, unsigned long long inlen ) + * + * argument out is passed in r24:r25 + * argument in is passed in r22:r23 + * argument inlen is passed in r14:r21, only lowest 16-bits (r14-r15) are used + */ +.global crypto_hash // populate.py, please update crypto_hash +crypto_hash: // populate.py, please update crypto_hash + + // crypto_hash only registers + #define rInLen 16 //(2 regs) + #define rT1 18 + #define rT2 19 + #define rT3 20 + #define sp 0x3D + + push r2 + push r3 + push r4 + push r5 + push r6 + push r7 + push r8 + push r9 + push r10 + push r11 + push r12 + push r13 + push r14 + push r15 + push r16 + push r17 + push r28 + push r29 + + // Allocate state (25*8) + C variables (5*8) + in rZ, sp + in rZ+1, sp+1 + subi rZ, 240 + sbci rZ+1, 0 + in r0, 0x3F + cli + out sp+1, rZ+1 + out sp, rZ + out 0x3F, r0 + adiw rZ, 41 // pointer to start of state, end of C, compensate post decrement + + push r24 // save out pointer + push r25 + + movw rpState, rZ + movw rY, r22 //y contains in pointer + movw rInLen, r14 + + ldi rT3, 5*5*2 //clear state (4 bytes each iteration) +clearStateLoop: + st z+, zero + st z+, zero + st z+, zero + st z+, zero + dec rT3 + brne clearStateLoop + + // Full blocks + cpi rInLen, cKeccakR_SizeInBytes + cpc rInLen+1, zero + brcs ch_lastblock + +ch_FullRateLoop: + ldi rT3, cKeccakR_SizeInBytes/8 + movw rZ, rpState +ch_XorLanesLoop: + ld rT1, Y+ + ld rT2, Z + eor rT1, rT2 + st Z+, rT1 + ld rT1, Y+ + ld rT2, Z + eor rT1, rT2 + st Z+, rT1 + ld rT1, Y+ + ld rT2, Z + eor rT1, rT2 + st Z+, rT1 + ld rT1, Y+ + ld rT2, Z + eor rT1, rT2 + st Z+, rT1 + ld rT1, Y+ + ld rT2, Z + eor rT1, rT2 + st Z+, rT1 + ld rT1, Y+ + ld rT2, Z + eor rT1, rT2 + st Z+, rT1 + ld rT1, Y+ + ld rT2, Z + eor rT1, rT2 + st Z+, rT1 + ld rT1, Y+ + ld rT2, Z + eor rT1, rT2 + st Z+, rT1 + + subi rT3, 1 + brne ch_XorLanesLoop + + push rY + push rY+1 + push rInLen + push rInLen+1 + call KeccakF + pop rInLen+1 + pop rInLen + pop rY+1 + pop rY + + subi rInLen, cKeccakR_SizeInBytes + sbci rInLen+1, 0 + cpi rInLen, cKeccakR_SizeInBytes + cpc rInLen+1, zero + brcc ch_FullRateLoop + +ch_lastblock: // XOR last uncomplete block into state + movw rZ, rpState + + lsr rInLen + brcc ch_xorBytes2 + ld rT1, Y+ + ld rT2, Z + eor rT1, rT2 + st Z+, rT1 + subi rInLen, 0 +ch_xorBytes2: + breq ch_Padding +ch_xorBytes2Loop: + ld rT1, Y+ + ld rT2, Z + eor rT1, rT2 + st Z+, rT1 + ld rT1, Y+ + ld rT2, Z + eor rT1, rT2 + st Z+, rT1 + subi rInLen, 1 + brne ch_xorBytes2Loop + +ch_Padding: + ldi rT1, 1 + ld rT2, Z + eor rT1, rT2 + st Z, rT1 + + ldi rZ, cKeccakR_SizeInBytes-1 + add rZ, rpState + mov rZ+1, rpState+1 + adc rZ+1, zero + ld rT1, Z + subi rT1, 0x80 + st Z, rT1 + + call KeccakF + + //output + ldi rT3, crypto_hash_BYTES/4 ; copy 4 bytes per iteration + movw rY, rpState + pop rZ+1 ; restore out pointer + pop rZ +outputLoop: + ld rT1, Y+ + st Z+, rT1 + ld rT1, Y+ + st Z+, rT1 + ld rT1, Y+ + st Z+, rT1 + ld rT1, Y+ + st Z+, rT1 + dec rT3 + brne outputLoop + + + // Free state and pop registers + ldi rZ, 199 + add rpState, rZ + adc rpState+1, zero + in r0, 0x3F + cli + out sp+1, rpState+1 + out sp, rpState + out 0x3F, r0 + + pop r29 + pop r28 + pop r17 + pop r16 + pop r15 + pop r14 + pop r13 + pop r12 + pop r11 + pop r10 + pop r9 + pop r8 + pop r7 + pop r6 + pop r5 + pop r4 + pop r3 + pop r2 + + // return 0 + mov r24, zero + mov r25, zero + + #undef rInLen + #undef rT1 + #undef rT2 + #undef rT3 + #undef sp + + ret + + +#define ROT_BIT(a) ((a) & 7) +#define ROT_BYTE(a) ((((a)/8 + !!(((a)%8) > 4)) & 7) * 9) + +KeccakF_RhoPiConstants: + .BYTE ROT_BIT( 1), ROT_BYTE( 3), 10 * 8 + .BYTE ROT_BIT( 3), ROT_BYTE( 6), 7 * 8 + .BYTE ROT_BIT( 6), ROT_BYTE(10), 11 * 8 + .BYTE ROT_BIT(10), ROT_BYTE(15), 17 * 8 + .BYTE ROT_BIT(15), ROT_BYTE(21), 18 * 8 + .BYTE ROT_BIT(21), ROT_BYTE(28), 3 * 8 + .BYTE ROT_BIT(28), ROT_BYTE(36), 5 * 8 + .BYTE ROT_BIT(36), ROT_BYTE(45), 16 * 8 + .BYTE ROT_BIT(45), ROT_BYTE(55), 8 * 8 + .BYTE ROT_BIT(55), ROT_BYTE( 2), 21 * 8 + .BYTE ROT_BIT( 2), ROT_BYTE(14), 24 * 8 + .BYTE ROT_BIT(14), ROT_BYTE(27), 4 * 8 + .BYTE ROT_BIT(27), ROT_BYTE(41), 15 * 8 + .BYTE ROT_BIT(41), ROT_BYTE(56), 23 * 8 + .BYTE ROT_BIT(56), ROT_BYTE( 8), 19 * 8 + .BYTE ROT_BIT( 8), ROT_BYTE(25), 13 * 8 + .BYTE ROT_BIT(25), ROT_BYTE(43), 12 * 8 + .BYTE ROT_BIT(43), ROT_BYTE(62), 2 * 8 + .BYTE ROT_BIT(62), ROT_BYTE(18), 20 * 8 + .BYTE ROT_BIT(18), ROT_BYTE(39), 14 * 8 + .BYTE ROT_BIT(39), ROT_BYTE(61), 22 * 8 + .BYTE ROT_BIT(61), ROT_BYTE(20), 9 * 8 + .BYTE ROT_BIT(20), ROT_BYTE(44), 6 * 8 + .BYTE ROT_BIT(44), ROT_BYTE( 1), 1 * 8 + + +KeccakF_RoundConstants: + .BYTE 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + .BYTE 0x82, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + .BYTE 0x8a, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80 + .BYTE 0x00, 0x80, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80 + .BYTE 0x8b, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + .BYTE 0x01, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00 + .BYTE 0x81, 0x80, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80 + .BYTE 0x09, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80 + .BYTE 0x8a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + .BYTE 0x88, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + .BYTE 0x09, 0x80, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00 + .BYTE 0x0a, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00 + .BYTE 0x8b, 0x80, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00 + .BYTE 0x8b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80 + .BYTE 0x89, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80 + .BYTE 0x03, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80 + .BYTE 0x02, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80 + .BYTE 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80 + .BYTE 0x0a, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + .BYTE 0x0a, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80 + .BYTE 0x81, 0x80, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80 + .BYTE 0x80, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80 + .BYTE 0x01, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00 + .BYTE 0x08, 0x80, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80 + .BYTE 0xFF, 0 //terminator + + .text + + + +// KeccakF +// Not callable from C! +// +// argument rpState is passed in r24:r25 +// +KeccakF: + + // Variables used in multiple operations + #define rTemp 2 // 8 regs (2-9) + #define rTempBis 10 // 8 regs (10-17) + #define rTempTer 18 // 4 regs (18-21) + #define pRound 22 // 2 regs (22-23) + + // Initial Prepare Theta + #define TCIPx rTempTer + + movw rZ, rpState // Z points to 8 C + sbiw rZ, 40 + ldi TCIPx, 5 + movw rY, rpState +KeccakInitialPrepTheta_Loop: + ld rTemp+0, Y+ ;state[x] + ld rTemp+1, Y+ + ld rTemp+2, Y+ + ld rTemp+3, Y+ + ld rTemp+4, Y+ + ld rTemp+5, Y+ + ld rTemp+6, Y+ + ld rTemp+7, Y+ + + adiw rY, 32 + ld r0, Y+ ;state[5+x] + eor rTemp+0, r0 + ld r0, Y+ + eor rTemp+1, r0 + ld r0, Y+ + eor rTemp+2, r0 + ld r0, Y+ + eor rTemp+3, r0 + ld r0, Y+ + eor rTemp+4, r0 + ld r0, Y+ + eor rTemp+5, r0 + ld r0, Y+ + eor rTemp+6, r0 + ld r0, Y+ + eor rTemp+7, r0 + + adiw rY, 32 + ld r0, Y+ ;state[10+x] + eor rTemp+0, r0 + ld r0, Y+ + eor rTemp+1, r0 + ld r0, Y+ + eor rTemp+2, r0 + ld r0, Y+ + eor rTemp+3, r0 + ld r0, Y+ + eor rTemp+4, r0 + ld r0, Y+ + eor rTemp+5, r0 + ld r0, Y+ + eor rTemp+6, r0 + ld r0, Y+ + eor rTemp+7, r0 + + adiw rY, 32 + ld r0, Y+ ;state[15+x] + eor rTemp+0, r0 + ld r0, Y+ + eor rTemp+1, r0 + ld r0, Y+ + eor rTemp+2, r0 + ld r0, Y+ + eor rTemp+3, r0 + ld r0, Y+ + eor rTemp+4, r0 + ld r0, Y+ + eor rTemp+5, r0 + ld r0, Y+ + eor rTemp+6, r0 + ld r0, Y+ + eor rTemp+7, r0 + + adiw rY, 32 + ld r0, Y+ ;state[20+x] + eor rTemp+0, r0 + ld r0, Y+ + eor rTemp+1, r0 + ld r0, Y+ + eor rTemp+2, r0 + ld r0, Y+ + eor rTemp+3, r0 + ld r0, Y+ + eor rTemp+4, r0 + ld r0, Y+ + eor rTemp+5, r0 + ld r0, Y+ + eor rTemp+6, r0 + ld r0, Y+ + eor rTemp+7, r0 + + st Z+, rTemp+0 + st Z+, rTemp+1 + st Z+, rTemp+2 + st Z+, rTemp+3 + st Z+, rTemp+4 + st Z+, rTemp+5 + st Z+, rTemp+6 + st Z+, rTemp+7 + + subi rY, 160 + sbc rY+1, zero + + subi TCIPx, 1 + breq KeccakInitialPrepTheta_Done + rjmp KeccakInitialPrepTheta_Loop +KeccakInitialPrepTheta_Done: + #undef TCIPx + + ldi pRound, lo8(KeccakF_RoundConstants) + ldi pRound+1, hi8(KeccakF_RoundConstants) +Keccak_RoundLoop: + + // Theta + #define TCplus rX + #define TCminus rZ + #define TCcoordX rTempTer + #define TCcoordY rTempTer+1 + + movw TCminus, rpState + sbiw TCminus, 1*8 + movw TCplus, rpState + sbiw TCplus, 4*8 + movw rY, rpState + + ldi TCcoordX, 0x16 +KeccakTheta_Loop1: + ld rTemp+0, X+ + ld rTemp+1, X+ + ld rTemp+2, X+ + ld rTemp+3, X+ + ld rTemp+4, X+ + ld rTemp+5, X+ + ld rTemp+6, X+ + ld rTemp+7, X+ + + lsl rTemp+0 + rol rTemp+1 + rol rTemp+2 + rol rTemp+3 + rol rTemp+4 + rol rTemp+5 + rol rTemp+6 + rol rTemp+7 + adc rTemp+0, zero + + ld r0, Z+ + eor rTemp+0, r0 + ld r0, Z+ + eor rTemp+1, r0 + ld r0, Z+ + eor rTemp+2, r0 + ld r0, Z+ + eor rTemp+3, r0 + ld r0, Z+ + eor rTemp+4, r0 + ld r0, Z+ + eor rTemp+5, r0 + ld r0, Z+ + eor rTemp+6, r0 + ld r0, Z+ + eor rTemp+7, r0 + + ldi TCcoordY, 5 +KeccakTheta_Loop2: + ld r0, Y + eor r0, rTemp+0 + st Y+, r0 + ld r0, Y + eor r0, rTemp+1 + st Y+, r0 + ld r0, Y + eor r0, rTemp+2 + st Y+, r0 + ld r0, Y + eor r0, rTemp+3 + st Y+, r0 + ld r0, Y + eor r0, rTemp+4 + st Y+, r0 + ld r0, Y + eor r0, rTemp+5 + st Y+, r0 + ld r0, Y + eor r0, rTemp+6 + st Y+, r0 + ld r0, Y + eor r0, rTemp+7 + st Y+, r0 + adiw rY, 32 + + dec TCcoordY + brne KeccakTheta_Loop2 + + subi rY, 200-8 + sbc rY+1, zero + + lsr TCcoordX + brcc 1f + breq KeccakTheta_End + rjmp KeccakTheta_Loop1 +1: + cpi TCcoordX, 0x0B + brne 2f + sbiw TCminus, 40 + rjmp KeccakTheta_Loop1 +2: + sbiw TCplus, 40 + rjmp KeccakTheta_Loop1 + +KeccakTheta_End: + #undef TCplus + #undef TCminus + #undef TCcoordX + #undef TCcoordY + + + // Rho Pi + #define RPpConst rTempTer // 2 regs + #define RPindex rTempTer+2 + #define RPpBitRot rX + #define RPpByteRot pRound + + sbiw rY, 32 + + ld rTemp+0, Y+ + ld rTemp+1, Y+ + ld rTemp+2, Y+ + ld rTemp+3, Y+ + ld rTemp+4, Y+ + ld rTemp+5, Y+ + ld rTemp+6, Y+ + ld rTemp+7, Y+ + + push pRound + push pRound+1 + ldi RPpConst, lo8(KeccakF_RhoPiConstants) + ldi RPpConst+1, hi8(KeccakF_RhoPiConstants) + ldi RPpBitRot, pm_lo8(bit_rot_jmp_table) + ldi RPpBitRot+1, pm_hi8(bit_rot_jmp_table) + ldi RPpByteRot, pm_lo8(rotate64_0byte_left) + ldi RPpByteRot+1, pm_hi8(rotate64_0byte_left) + +KeccakRhoPi_Loop: + ; get rotation codes and state index + movw rZ, RPpConst + lpm r0, Z+ ;bits + lpm rTempBis, Z+ ;bytes + lpm RPindex, Z+ + movw RPpConst, rZ + + ; do bit rotation + movw rZ, RPpBitRot + add rZ, r0 + adc rZ+1, zero + ijmp + +KeccakRhoPi_RhoBitRotateDone: + movw rY, rpState + add rY, RPindex + adc rY+1, zero + + movw rZ, RPpByteRot + add rZ, rTempBis + adc rZ+1, zero + ijmp + +KeccakRhoPi_PiStore: + sbiw rY, 8 + st Y+, rTemp+0 + st Y+, rTemp+1 + st Y+, rTemp+2 + st Y+, rTemp+3 + st Y+, rTemp+4 + st Y+, rTemp+5 + st Y+, rTemp+6 + st Y+, rTemp+7 + + movw rTemp+0, rTempBis+0 + movw rTemp+2, rTempBis+2 + movw rTemp+4, rTempBis+4 + movw rTemp+6, rTempBis+6 +KeccakRhoPi_RhoDone: + subi RPindex, 8 + brne KeccakRhoPi_Loop + pop pRound+1 + pop pRound + + #undef RPpConst + #undef RPindex + #undef RPpBitRot + #undef RPpByteRot + + + // Chi Iota prepare Theta + #define CIPTa0 rTemp + #define CIPTa1 rTemp+1 + #define CIPTa2 rTemp+2 + #define CIPTa3 rTemp+3 + #define CIPTa4 rTemp+4 + #define CIPTc0 rTempBis + #define CIPTc1 rTempBis+1 + #define CIPTc2 rTempBis+2 + #define CIPTc3 rTempBis+3 + #define CIPTc4 rTempBis+4 + #define CIPTz rTempBis+6 + #define CIPTy rTempBis+7 + + movw rY, rpState + movw rX, rpState ; 5 * C + sbiw rX, 40 + movw rZ, pRound + + ldi CIPTz, 8 +KeccakChiIotaPrepareTheta_zLoop: + mov CIPTc0, zero + mov CIPTc1, zero + movw CIPTc2, CIPTc0 + mov CIPTc4, zero + + ldi CIPTy, 5 +KeccakChiIotaPrepareTheta_yLoop: + ld CIPTa0, Y + ldd CIPTa1, Y+8 + ldd CIPTa2, Y+16 + ldd CIPTa3, Y+24 + ldd CIPTa4, Y+32 + + ;*p = t = a0 ^ ((~a1) & a2); c0 ^= t; + mov r0, CIPTa1 + com r0 + and r0, CIPTa2 + eor r0, CIPTa0 + eor CIPTc0, r0 + st Y, r0 + + ;*(p+8) = t = a1 ^ ((~a2) & a3); c1 ^= t; + mov r0, CIPTa2 + com r0 + and r0, CIPTa3 + eor r0, CIPTa1 + eor CIPTc1, r0 + std Y+8, r0 + + ;*(p+16) = a2 ^= ((~a3) & a4); c2 ^= a2; + mov r0, CIPTa3 + com r0 + and r0, CIPTa4 + eor r0, CIPTa2 + eor CIPTc2, r0 + std Y+16, r0 + + ;*(p+24) = a3 ^= ((~a4) & a0); c3 ^= a3; + mov r0, CIPTa4 + com r0 + and r0, CIPTa0 + eor r0, CIPTa3 + eor CIPTc3, r0 + std Y+24, r0 + + ;*(p+32) = a4 ^= ((~a0) & a1); c4 ^= a4; + com CIPTa0 + and CIPTa0, CIPTa1 + eor CIPTa0, CIPTa4 + eor CIPTc4, CIPTa0 + std Y+32, CIPTa0 + + adiw rY, 40 + dec CIPTy + brne KeccakChiIotaPrepareTheta_yLoop + + subi rY, 200 + sbc rY+1, zero + + lpm r0, Z+ ;Round Constant + ld CIPTa0, Y + eor CIPTa0, r0 + st Y+, CIPTa0 + + movw pRound, rZ + movw rZ, rX + eor CIPTc0, r0 + st Z+, CIPTc0 + std Z+7, CIPTc1 + std Z+15, CIPTc2 + std Z+23, CIPTc3 + std Z+31, CIPTc4 + movw rX, rZ + movw rZ, pRound + + dec CIPTz + brne KeccakChiIotaPrepareTheta_zLoop + + #undef CIPTa0 + #undef CIPTa1 + #undef CIPTa2 + #undef CIPTa3 + #undef CIPTa4 + #undef CIPTc0 + #undef CIPTc1 + #undef CIPTc2 + #undef CIPTc3 + #undef CIPTc4 + #undef CIPTz + #undef CIPTy + + + ;Check for terminator + lpm r0, Z + inc r0 + breq Keccak_Done + rjmp Keccak_RoundLoop +Keccak_Done: + ret + + +bit_rot_jmp_table: + rjmp KeccakRhoPi_RhoBitRotateDone + rjmp rotate64_1bit_left + rjmp rotate64_2bit_left + rjmp rotate64_3bit_left + rjmp rotate64_4bit_left + rjmp rotate64_3bit_right + rjmp rotate64_2bit_right + rjmp rotate64_1bit_right + +rotate64_4bit_left: + lsl rTemp + rol rTemp+1 + rol rTemp+2 + rol rTemp+3 + rol rTemp+4 + rol rTemp+5 + rol rTemp+6 + rol rTemp+7 + adc rTemp, r1 +rotate64_3bit_left: + lsl rTemp + rol rTemp+1 + rol rTemp+2 + rol rTemp+3 + rol rTemp+4 + rol rTemp+5 + rol rTemp+6 + rol rTemp+7 + adc rTemp, r1 +rotate64_2bit_left: + lsl rTemp + rol rTemp+1 + rol rTemp+2 + rol rTemp+3 + rol rTemp+4 + rol rTemp+5 + rol rTemp+6 + rol rTemp+7 + adc rTemp, r1 +rotate64_1bit_left: + lsl rTemp + rol rTemp+1 + rol rTemp+2 + rol rTemp+3 + rol rTemp+4 + rol rTemp+5 + rol rTemp+6 + rol rTemp+7 + adc rTemp, r1 + rjmp KeccakRhoPi_RhoBitRotateDone + +rotate64_3bit_right: + bst rTemp, 0 + ror rTemp+7 + ror rTemp+6 + ror rTemp+5 + ror rTemp+4 + ror rTemp+3 + ror rTemp+2 + ror rTemp+1 + ror rTemp + bld rTemp+7, 7 +rotate64_2bit_right: + bst rTemp, 0 + ror rTemp+7 + ror rTemp+6 + ror rTemp+5 + ror rTemp+4 + ror rTemp+3 + ror rTemp+2 + ror rTemp+1 + ror rTemp + bld rTemp+7, 7 +rotate64_1bit_right: + bst rTemp, 0 + ror rTemp+7 + ror rTemp+6 + ror rTemp+5 + ror rTemp+4 + ror rTemp+3 + ror rTemp+2 + ror rTemp+1 + ror rTemp + bld rTemp+7, 7 + rjmp KeccakRhoPi_RhoBitRotateDone + +/* +** Each byte rotate routine must be 9 instructions long. +*/ +rotate64_0byte_left: + ld rTempBis+0, Y+ + ld rTempBis+1, Y+ + ld rTempBis+2, Y+ + ld rTempBis+3, Y+ + ld rTempBis+4, Y+ + ld rTempBis+5, Y+ + ld rTempBis+6, Y+ + ld rTempBis+7, Y+ + rjmp KeccakRhoPi_PiStore + +rotate64_1byte_left: + ld rTempBis+1, Y+ + ld rTempBis+2, Y+ + ld rTempBis+3, Y+ + ld rTempBis+4, Y+ + ld rTempBis+5, Y+ + ld rTempBis+6, Y+ + ld rTempBis+7, Y+ + ld rTempBis+0, Y+ + rjmp KeccakRhoPi_PiStore + +rotate64_2byte_left: + ld rTempBis+2, Y+ + ld rTempBis+3, Y+ + ld rTempBis+4, Y+ + ld rTempBis+5, Y+ + ld rTempBis+6, Y+ + ld rTempBis+7, Y+ + ld rTempBis+0, Y+ + ld rTempBis+1, Y+ + rjmp KeccakRhoPi_PiStore + +rotate64_3byte_left: + ld rTempBis+3, Y+ + ld rTempBis+4, Y+ + ld rTempBis+5, Y+ + ld rTempBis+6, Y+ + ld rTempBis+7, Y+ + ld rTempBis+0, Y+ + ld rTempBis+1, Y+ + ld rTempBis+2, Y+ + rjmp KeccakRhoPi_PiStore + +rotate64_4byte_left: + ld rTempBis+4, Y+ + ld rTempBis+5, Y+ + ld rTempBis+6, Y+ + ld rTempBis+7, Y+ + ld rTempBis+0, Y+ + ld rTempBis+1, Y+ + ld rTempBis+2, Y+ + ld rTempBis+3, Y+ + rjmp KeccakRhoPi_PiStore + +rotate64_5byte_left: + ld rTempBis+5, Y+ + ld rTempBis+6, Y+ + ld rTempBis+7, Y+ + ld rTempBis+0, Y+ + ld rTempBis+1, Y+ + ld rTempBis+2, Y+ + ld rTempBis+3, Y+ + ld rTempBis+4, Y+ + rjmp KeccakRhoPi_PiStore + +rotate64_6byte_left: + ld rTempBis+6, Y+ + ld rTempBis+7, Y+ + ld rTempBis+0, Y+ + ld rTempBis+1, Y+ + ld rTempBis+2, Y+ + ld rTempBis+3, Y+ + ld rTempBis+4, Y+ + ld rTempBis+5, Y+ + rjmp KeccakRhoPi_PiStore + +rotate64_7byte_left: + ld rTempBis+7, Y+ + ld rTempBis+0, Y+ + ld rTempBis+1, Y+ + ld rTempBis+2, Y+ + ld rTempBis+3, Y+ + ld rTempBis+4, Y+ + ld rTempBis+5, Y+ + ld rTempBis+6, Y+ + rjmp KeccakRhoPi_PiStore + + #undef rTemp + #undef rTempBis + #undef rTempTer + #undef pRound + + #undef rpState + #undef zero + #undef rX + #undef rY + #undef rZ diff --git a/c_src/KeccakF-1600-inplace-armgcc-ARMv7A-NEON.s b/c_src/KeccakF-1600-inplace-armgcc-ARMv7A-NEON.s new file mode 100755 index 0000000..539e8ea --- /dev/null +++ b/c_src/KeccakF-1600-inplace-armgcc-ARMv7A-NEON.s @@ -0,0 +1,446 @@ +@ The Keccak sponge function, designed by Guido Bertoni, Joan Daemen, +@ Michaël Peeters and Gilles Van Assche. For more information, feedback or +@ questions, please refer to our website: http://keccak.noekeon.org/ +@ +@ Implementation by Ronny Van Keer, hereby denoted as "the implementer". +@ +@ To the extent possible under law, the implementer has waived all copyright +@ and related or neighboring rights to the source code in this file. +@ http://creativecommons.org/publicdomain/zero/1.0/ + +@ This file was created from a .asm file +@ using the ads2gas.pl script. +.equ DO1STROUNDING, 0 + + @ PRESERVE8 +.text + +@// --- offsets in state +.equ Aba, 0*8 +.equ Aga, 1*8 +.equ Aka, 2*8 +.equ Ama, 3*8 +.equ Asa, 4*8 + +@// --- macros + +.macro KeccakThetaRhoPiChiIota argA1, argA2, argA3, argA4, argA5 + + @Prepare Theta + @Ca = Aba^Aga^Aka^Ama^Asa@ + @Ce = Abe^Age^Ake^Ame^Ase@ + @Ci = Abi^Agi^Aki^Ami^Asi@ + @Co = Abo^Ago^Ako^Amo^Aso@ + @Cu = Abu^Agu^Aku^Amu^Asu@ + @De = Ca^ROL64(Ci, 1)@ + @Di = Ce^ROL64(Co, 1)@ + @Do = Ci^ROL64(Cu, 1)@ + @Du = Co^ROL64(Ca, 1)@ + @Da = Cu^ROL64(Ce, 1)@ + + veor.64 q4, q6, q7 + veor.64 q5, q9, q10 + veor.64 d8, d8, d9 + veor.64 d10, d10, d11 + veor.64 d1, d8, d16 + veor.64 d2, d10, d17 + + veor.64 q4, q11, q12 + veor.64 q5, q14, q15 + veor.64 d8, d8, d9 + veor.64 d10, d10, d11 + veor.64 d3, d8, d26 + + vadd.u64 q4, q1, q1 + veor.64 d4, d10, d27 + vmov.64 d0, d5 + vsri.64 q4, q1, #63 + + vadd.u64 q5, q2, q2 + veor.64 q4, q4, q0 + vsri.64 q5, q2, #63 + vadd.u64 d7, d1, d1 + veor.64 \argA2, \argA2, d8 + veor.64 q5, q5, q1 + + vsri.64 d7, d1, #63 + vshl.u64 d1, \argA2, #44 + veor.64 \argA3, \argA3, d9 + veor.64 d7, d7, d4 + + @Ba = argA1^Da@ + @Be = ROL64((argA2^De), 44)@ + @Bi = ROL64((argA3^Di), 43)@ + @Bo = ROL64((argA4^Do), 21)@ + @Bu = ROL64((argA5^Du), 14)@ + @argA2 = Be ^((~Bi)& Bo )@ + @argA3 = Bi ^((~Bo)& Bu )@ + @argA4 = Bo ^((~Bu)& Ba )@ + @argA5 = Bu ^((~Ba)& Be )@ + @argA1 = Ba ^((~Be)& Bi )@ argA1 ^= KeccakF1600RoundConstants[i+round]@ + vsri.64 d1, \argA2, #64-44 + vshl.u64 d2, \argA3, #43 + vldr.64 d0, [sp, #\argA1] + veor.64 \argA4, \argA4, d10 + vsri.64 d2, \argA3, #64-43 + vshl.u64 d3, \argA4, #21 + veor.64 \argA5, \argA5, d11 + veor.64 d0, d0, d7 + vsri.64 d3, \argA4, #64-21 + vbic.64 d5, d2, d1 + vshl.u64 d4, \argA5, #14 + vbic.64 \argA2, d3, d2 + vld1.64 d6, [r3]! + veor.64 d5, d0 + vsri.64 d4, \argA5, #64-14 + veor.64 d5, d6 + vbic.64 \argA5, d1, d0 + vbic.64 \argA3, d4, d3 + vbic.64 \argA4, d0, d4 + veor.64 \argA2, d1 + vstr.64 d5, [sp, #\argA1] + veor.64 \argA3, d2 + veor.64 \argA4, d3 + veor.64 \argA5, d4 + + .endm + +.macro KeccakThetaRhoPiChi1 argA1, argA2, argA3, argA4, argA5 + + @d2 = ROL64((argA1^Da), 3)@ + @d3 = ROL64((argA2^De), 45)@ + @d4 = ROL64((argA3^Di), 61)@ + @d0 = ROL64((argA4^Do), 28)@ + @d1 = ROL64((argA5^Du), 20)@ + @argA1 = Ba ^((~Be)& Bi )@ Ca ^= argA1@ + @argA2 = Be ^((~Bi)& Bo )@ + @argA3 = Bi ^((~Bo)& Bu )@ + @argA4 = Bo ^((~Bu)& Ba )@ + @argA5 = Bu ^((~Ba)& Be )@ + + veor.64 \argA2, \argA2, d8 + veor.64 \argA3, \argA3, d9 + vshl.u64 d3, \argA2, #45 + vldr.64 d6, [sp, #\argA1] + vshl.u64 d4, \argA3, #61 + veor.64 \argA4, \argA4, d10 + vsri.64 d3, \argA2, #64-45 + veor.64 \argA5, \argA5, d11 + vsri.64 d4, \argA3, #64-61 + vshl.u64 d0, \argA4, #28 + veor.64 d6, d6, d7 + vshl.u64 d1, \argA5, #20 + vbic.64 \argA3, d4, d3 + vsri.64 d0, \argA4, #64-28 + vbic.64 \argA4, d0, d4 + vshl.u64 d2, d6, #3 + vsri.64 d1, \argA5, #64-20 + veor.64 \argA4, d3 + vsri.64 d2, d6, #64-3 + vbic.64 \argA5, d1, d0 + vbic.64 d6, d2, d1 + vbic.64 \argA2, d3, d2 + veor.64 d6, d0 + veor.64 \argA2, d1 + vstr.64 d6, [sp, #\argA1] + veor.64 \argA3, d2 + veor.64 d5, d6 + veor.64 \argA5, d4 + + .endm + +.macro KeccakThetaRhoPiChi2 argA1, argA2, argA3, argA4, argA5 + + @d4 = ROL64((argA1^Da), 18)@ + @d0 = ROL64((argA2^De), 1)@ + @d1 = ROL64((argA3^Di), 6)@ + @d2 = ROL64((argA4^Do), 25)@ + @d3 = ROL64((argA5^Du), 8)@ + @argA1 = Ba ^((~Be)& Bi )@ Ca ^= argA1@ + @argA2 = Be ^((~Bi)& Bo )@ + @argA3 = Bi ^((~Bo)& Bu )@ + @argA4 = Bo ^((~Bu)& Ba )@ + @argA5 = Bu ^((~Ba)& Be )@ + + veor.64 \argA3, \argA3, d9 + veor.64 \argA4, \argA4, d10 + vshl.u64 d1, \argA3, #6 + vldr.64 d6, [sp, #\argA1] + vshl.u64 d2, \argA4, #25 + veor.64 \argA5, \argA5, d11 + vsri.64 d1, \argA3, #64-6 + veor.64 \argA2, \argA2, d8 + vsri.64 d2, \argA4, #64-25 + vext.8 d3, \argA5, \argA5, #7 + veor.64 d6, d6, d7 + vbic.64 \argA3, d2, d1 + vadd.u64 d0, \argA2, \argA2 + vbic.64 \argA4, d3, d2 + vsri.64 d0, \argA2, #64-1 + vshl.u64 d4, d6, #18 + veor.64 \argA2, d1, \argA4 + veor.64 \argA3, d0 + vsri.64 d4, d6, #64-18 + vstr.64 \argA3, [sp, #\argA1] + veor.64 d5, \argA3 + vbic.64 \argA5, d1, d0 + vbic.64 \argA3, d4, d3 + vbic.64 \argA4, d0, d4 + veor.64 \argA3, d2 + veor.64 \argA4, d3 + veor.64 \argA5, d4 + + .endm + +.macro KeccakThetaRhoPiChi3 argA1, argA2, argA3, argA4, argA5 + + @d1 = ROL64((argA1^Da), 36)@ + @d2 = ROL64((argA2^De), 10)@ + @d3 = ROL64((argA3^Di), 15)@ + @d4 = ROL64((argA4^Do), 56)@ + @d0 = ROL64((argA5^Du), 27)@ + @argA1 = Ba ^((~Be)& Bi )@ Ca ^= argA1@ + @argA2 = Be ^((~Bi)& Bo )@ + @argA3 = Bi ^((~Bo)& Bu )@ + @argA4 = Bo ^((~Bu)& Ba )@ + @argA5 = Bu ^((~Ba)& Be )@ + + veor.64 \argA2, \argA2, d8 + veor.64 \argA3, \argA3, d9 + vshl.u64 d2, \argA2, #10 + vldr.64 d6, [sp, #\argA1] + vshl.u64 d3, \argA3, #15 + veor.64 \argA4, \argA4, d10 + vsri.64 d2, \argA2, #64-10 + vsri.64 d3, \argA3, #64-15 + veor.64 \argA5, \argA5, d11 + vext.8 d4, \argA4, \argA4, #1 + vbic.64 \argA2, d3, d2 + vshl.u64 d0, \argA5, #27 + veor.64 d6, d6, d7 + vbic.64 \argA3, d4, d3 + vsri.64 d0, \argA5, #64-27 + vshl.u64 d1, d6, #36 + veor.64 \argA3, d2 + vbic.64 \argA4, d0, d4 + vsri.64 d1, d6, #64-36 + + veor.64 \argA4, d3 + vbic.64 d6, d2, d1 + vbic.64 \argA5, d1, d0 + veor.64 d6, d0 + veor.64 \argA2, d1 + vstr.64 d6, [sp, #\argA1] + veor.64 d5, d6 + veor.64 \argA5, d4 + + .endm + +.macro KeccakThetaRhoPiChi4 argA1, argA2, argA3, argA4, argA5 + + @d3 = ROL64((argA1^Da), 41)@ + @d4 = ROL64((argA2^De), 2)@ + @d0 = ROL64((argA3^Di), 62)@ + @d1 = ROL64((argA4^Do), 55)@ + @d2 = ROL64((argA5^Du), 39)@ + @argA1 = Ba ^((~Be)& Bi )@ Ca ^= argA1@ + @argA2 = Be ^((~Bi)& Bo )@ + @argA3 = Bi ^((~Bo)& Bu )@ + @argA4 = Bo ^((~Bu)& Ba )@ + @argA5 = Bu ^((~Ba)& Be )@ + + veor.64 \argA2, \argA2, d8 + veor.64 \argA3, \argA3, d9 + vshl.u64 d4, \argA2, #2 + veor.64 \argA5, \argA5, d11 + vshl.u64 d0, \argA3, #62 + vldr.64 d6, [sp, #\argA1] + vsri.64 d4, \argA2, #64-2 + veor.64 \argA4, \argA4, d10 + vsri.64 d0, \argA3, #64-62 + + vshl.u64 d1, \argA4, #55 + veor.64 d6, d6, d7 + vshl.u64 d2, \argA5, #39 + vsri.64 d1, \argA4, #64-55 + vbic.64 \argA4, d0, d4 + vsri.64 d2, \argA5, #64-39 + vbic.64 \argA2, d1, d0 + vshl.u64 d3, d6, #41 + veor.64 \argA5, d4, \argA2 + vbic.64 \argA2, d2, d1 + vsri.64 d3, d6, #64-41 + veor.64 d6, d0, \argA2 + + vbic.64 \argA2, d3, d2 + vbic.64 \argA3, d4, d3 + veor.64 \argA2, d1 + vstr.64 d6, [sp, #\argA1] + veor.64 d5, d6 + veor.64 \argA3, d2 + veor.64 \argA4, d3 + + .endm + +@// --- constants + + + .align 8 + .ltorg +KeccakF1600RoundConstantsWithTerminator: + .quad 0x0000000000000001 + .quad 0x0000000000008082 + .quad 0x800000000000808a + .quad 0x8000000080008000 + .quad 0x000000000000808b + .quad 0x0000000080000001 + .quad 0x8000000080008081 + .quad 0x8000000000008009 + .quad 0x000000000000008a + .quad 0x0000000000000088 + .quad 0x0000000080008009 + .quad 0x000000008000000a + .quad 0x000000008000808b + .quad 0x800000000000008b + .quad 0x8000000000008089 + .quad 0x8000000000008003 + .quad 0x8000000000008002 + .quad 0x8000000000000080 + .quad 0x000000000000800a + .quad 0x800000008000000a + .quad 0x8000000080008081 + .quad 0x8000000000008080 + .quad 0x0000000080000001 + .quad 0x8000000080008008 + .quad 0xFFFFFFFFFFFFFFFF @//terminator + + .align 8 + +@// --- code + +@not callable from C! +.global KeccakF_armv7a_neon_asm +KeccakF_armv7a_neon_asm: @ + + adr r3, KeccakF1600RoundConstantsWithTerminator +roundLoop: + + KeccakThetaRhoPiChiIota Aba, d13, d19, d25, d31 + KeccakThetaRhoPiChi1 Aka, d15, d21, d22, d28 + KeccakThetaRhoPiChi2 Asa, d12, d18, d24, d30 + KeccakThetaRhoPiChi3 Aga, d14, d20, d26, d27 + KeccakThetaRhoPiChi4 Ama, d16, d17, d23, d29 + + KeccakThetaRhoPiChiIota Aba, d15, d18, d26, d29 + KeccakThetaRhoPiChi1 Asa, d14, d17, d25, d28 + KeccakThetaRhoPiChi2 Ama, d13, d21, d24, d27 + KeccakThetaRhoPiChi3 Aka, d12, d20, d23, d31 + KeccakThetaRhoPiChi4 Aga, d16, d19, d22, d30 + + KeccakThetaRhoPiChiIota Aba, d14, d21, d23, d30 + KeccakThetaRhoPiChi1 Ama, d12, d19, d26, d28 + KeccakThetaRhoPiChi2 Aga, d15, d17, d24, d31 + KeccakThetaRhoPiChi3 Asa, d13, d20, d22, d29 + KeccakThetaRhoPiChi4 Aka, d16, d18, d25, d27 + + KeccakThetaRhoPiChiIota Aba, d12, d17, d22, d27 + KeccakThetaRhoPiChi1 Aga, d13, d18, d23, d28 + KeccakThetaRhoPiChi2 Aka, d14, d19, d24, d29 + ldr r0, [r3] + KeccakThetaRhoPiChi3 Ama, d15, d20, d25, d30 + cmp r0, #0xFFFFFFFF + KeccakThetaRhoPiChi4 Asa, d16, d21, d26, d31 + + bne roundLoop + bx lr + + @ + .align 8 + +@//void KeccakF_armv7a( tKeccakLane * state ) callable from C +.global KeccakF_armv7a_neon +KeccakF_armv7a_neon: @ + + vpush {q4-q7} + sub sp,sp, #5*8 + + vldr.64 d0, [r0, #0*8] + vldr.64 d12, [r0, #1*8] + vldr.64 d17, [r0, #2*8] + vldr.64 d22, [r0, #3*8] + vldr.64 d27, [r0, #4*8] + + vldr.64 d1, [r0, #5*8] + vldr.64 d13, [r0, #6*8] + vldr.64 d18, [r0, #7*8] + vldr.64 d23, [r0, #8*8] + vldr.64 d28, [r0, #9*8] + + vldr.64 d2, [r0, #10*8] + vldr.64 d14, [r0, #11*8] + vldr.64 d19, [r0, #12*8] + vldr.64 d24, [r0, #13*8] + vldr.64 d29, [r0, #14*8] + + vldr.64 d3, [r0, #15*8] + vldr.64 d15, [r0, #16*8] + vldr.64 d20, [r0, #17*8] + vldr.64 d25, [r0, #18*8] + vldr.64 d30, [r0, #19*8] + + vldr.64 d4, [r0, #20*8] + vldr.64 d16, [r0, #21*8] + vldr.64 d21, [r0, #22*8] + vldr.64 d26, [r0, #23*8] + vldr.64 d31, [r0, #24*8] + + vstr.64 d0, [sp, #Aba] + mov r2, lr + vstr.64 d1, [sp, #Aga] + veor.64 q0, q0, q1 + vstr.64 d2, [sp, #Aka] + veor.64 d5, d0, d1 + vstr.64 d3, [sp, #Ama] + mov r1, r0 + vstr.64 d4, [sp, #Asa] + veor.64 d5, d5, d4 + + bl KeccakF_armv7a_neon_asm + + vpop.64 { d0- d4 } + + vstr.64 d0, [r1, #0*8] + vstr.64 d12, [r1, #1*8] + vstr.64 d17, [r1, #2*8] + vstr.64 d22, [r1, #3*8] + vstr.64 d27, [r1, #4*8] + + vstr.64 d1, [r1, #5*8] + vstr.64 d13, [r1, #6*8] + vstr.64 d18, [r1, #7*8] + vstr.64 d23, [r1, #8*8] + vstr.64 d28, [r1, #9*8] + + vstr.64 d2, [r1, #10*8] + vstr.64 d14, [r1, #11*8] + vstr.64 d19, [r1, #12*8] + vstr.64 d24, [r1, #13*8] + vstr.64 d29, [r1, #14*8] + + vstr.64 d3, [r1, #15*8] + vstr.64 d15, [r1, #16*8] + vstr.64 d20, [r1, #17*8] + vstr.64 d25, [r1, #18*8] + vstr.64 d30, [r1, #19*8] + + vstr.64 d4, [r1, #20*8] + vstr.64 d16, [r1, #21*8] + vstr.64 d21, [r1, #22*8] + vstr.64 d26, [r1, #23*8] + vstr.64 d31, [r1, #24*8] + + vpop {q4-q7} + bx r2 + + @ + diff --git a/c_src/KeccakF-1600-int-set.h b/c_src/KeccakF-1600-int-set.h new file mode 100755 index 0000000..0ed1d80 --- /dev/null +++ b/c_src/KeccakF-1600-int-set.h @@ -0,0 +1,6 @@ +#define ProvideFast576 +#define ProvideFast832 +#define ProvideFast1024 +#define ProvideFast1088 +#define ProvideFast1152 +#define ProvideFast1344 diff --git a/c_src/KeccakF-1600-interface.h b/c_src/KeccakF-1600-interface.h new file mode 100755 index 0000000..22185a4 --- /dev/null +++ b/c_src/KeccakF-1600-interface.h @@ -0,0 +1,46 @@ +/* +The Keccak sponge function, designed by Guido Bertoni, Joan Daemen, +Michaël Peeters and Gilles Van Assche. For more information, feedback or +questions, please refer to our website: http://keccak.noekeon.org/ + +Implementation by the designers, +hereby denoted as "the implementer". + +To the extent possible under law, the implementer has waived all copyright +and related or neighboring rights to the source code in this file. +http://creativecommons.org/publicdomain/zero/1.0/ +*/ + +#ifndef _KeccakPermutationInterface_h_ +#define _KeccakPermutationInterface_h_ + +#include "KeccakF-1600-int-set.h" + +void KeccakInitialize( void ); +void KeccakInitializeState(unsigned char *state); +void KeccakPermutation(unsigned char *state); +#ifdef ProvideFast576 +void KeccakAbsorb576bits(unsigned char *state, const unsigned char *data); +#endif +#ifdef ProvideFast832 +void KeccakAbsorb832bits(unsigned char *state, const unsigned char *data); +#endif +#ifdef ProvideFast1024 +void KeccakAbsorb1024bits(unsigned char *state, const unsigned char *data); +#endif +#ifdef ProvideFast1088 +void KeccakAbsorb1088bits(unsigned char *state, const unsigned char *data); +#endif +#ifdef ProvideFast1152 +void KeccakAbsorb1152bits(unsigned char *state, const unsigned char *data); +#endif +#ifdef ProvideFast1344 +void KeccakAbsorb1344bits(unsigned char *state, const unsigned char *data); +#endif +void KeccakAbsorb(unsigned char *state, const unsigned char *data, unsigned int laneCount); +#ifdef ProvideFast1024 +void KeccakExtract1024bits(const unsigned char *state, unsigned char *data); +#endif +void KeccakExtract(const unsigned char *state, unsigned char *data, unsigned int laneCount); + +#endif diff --git a/c_src/KeccakF-1600-opt32-settings.h b/c_src/KeccakF-1600-opt32-settings.h new file mode 100755 index 0000000..b135918 --- /dev/null +++ b/c_src/KeccakF-1600-opt32-settings.h @@ -0,0 +1,4 @@ +#define Unrolling 2 +//#define UseBebigokimisa +//#define UseInterleaveTables +#define UseSchedule 3 diff --git a/c_src/KeccakF-1600-opt32.c b/c_src/KeccakF-1600-opt32.c new file mode 100755 index 0000000..aded3a9 --- /dev/null +++ b/c_src/KeccakF-1600-opt32.c @@ -0,0 +1,524 @@ +/* +The Keccak sponge function, designed by Guido Bertoni, Joan Daemen, +Michaël Peeters and Gilles Van Assche. For more information, feedback or +questions, please refer to our website: http://keccak.noekeon.org/ + +Implementation by the designers, +hereby denoted as "the implementer". + +To the extent possible under law, the implementer has waived all copyright +and related or neighboring rights to the source code in this file. +http://creativecommons.org/publicdomain/zero/1.0/ +*/ + +#include +#include "brg_endian.h" +#include "KeccakF-1600-opt32-settings.h" +#include "KeccakF-1600-interface.h" + +typedef unsigned char UINT8; +typedef unsigned short UINT16; +typedef unsigned int UINT32; +typedef unsigned long long int UINT64; + +#ifdef UseInterleaveTables +int interleaveTablesBuilt = 0; +UINT16 interleaveTable[65536]; +UINT16 deinterleaveTable[65536]; + +void buildInterleaveTables() +{ + UINT32 i, j; + UINT16 x; + + if (!interleaveTablesBuilt) { + for(i=0; i<65536; i++) { + x = 0; + for(j=0; j<16; j++) { + if (i & (1 << j)) + x |= (1 << (j/2 + 8*(j%2))); + } + interleaveTable[i] = x; + deinterleaveTable[x] = (UINT16)i; + } + interleaveTablesBuilt = 1; + } +} + +#if (PLATFORM_BYTE_ORDER == IS_LITTLE_ENDIAN) + +#define xor2bytesIntoInterleavedWords(even, odd, source, j) \ + i##j = interleaveTable[((const UINT16*)source)[j]]; \ + ((UINT8*)even)[j] ^= i##j & 0xFF; \ + ((UINT8*)odd)[j] ^= i##j >> 8; + +#define setInterleavedWordsInto2bytes(dest, even, odd, j) \ + d##j = deinterleaveTable[((even >> (j*8)) & 0xFF) ^ (((odd >> (j*8)) & 0xFF) << 8)]; \ + ((UINT16*)dest)[j] = d##j; + +#else // (PLATFORM_BYTE_ORDER == IS_BIG_ENDIAN) + +#define xor2bytesIntoInterleavedWords(even, odd, source, j) \ + i##j = interleaveTable[source[2*j] ^ ((UINT16)source[2*j+1] << 8)]; \ + *even ^= (i##j & 0xFF) << (j*8); \ + *odd ^= ((i##j >> 8) & 0xFF) << (j*8); + +#define setInterleavedWordsInto2bytes(dest, even, odd, j) \ + d##j = deinterleaveTable[((even >> (j*8)) & 0xFF) ^ (((odd >> (j*8)) & 0xFF) << 8)]; \ + dest[2*j] = d##j & 0xFF; \ + dest[2*j+1] = d##j >> 8; + +#endif // Endianness + +void xor8bytesIntoInterleavedWords(UINT32 *even, UINT32 *odd, const UINT8* source) +{ + UINT16 i0, i1, i2, i3; + + xor2bytesIntoInterleavedWords(even, odd, source, 0) + xor2bytesIntoInterleavedWords(even, odd, source, 1) + xor2bytesIntoInterleavedWords(even, odd, source, 2) + xor2bytesIntoInterleavedWords(even, odd, source, 3) +} + +#define xorLanesIntoState(laneCount, state, input) \ + { \ + int i; \ + for(i=0; i<(laneCount); i++) \ + xor8bytesIntoInterleavedWords(state+i*2, state+i*2+1, input+i*8); \ + } + +void setInterleavedWordsInto8bytes(UINT8* dest, UINT32 even, UINT32 odd) +{ + UINT16 d0, d1, d2, d3; + + setInterleavedWordsInto2bytes(dest, even, odd, 0) + setInterleavedWordsInto2bytes(dest, even, odd, 1) + setInterleavedWordsInto2bytes(dest, even, odd, 2) + setInterleavedWordsInto2bytes(dest, even, odd, 3) +} + +#define extractLanes(laneCount, state, data) \ + { \ + int i; \ + for(i=0; i<(laneCount); i++) \ + setInterleavedWordsInto8bytes(data+i*8, ((UINT32*)state)[i*2], ((UINT32*)state)[i*2+1]); \ + } + +#else // No interleaving tables + +#if (PLATFORM_BYTE_ORDER == IS_LITTLE_ENDIAN) + +// Credit: Henry S. Warren, Hacker's Delight, Addison-Wesley, 2002 +#define xorInterleavedLE(rateInLanes, state, input) \ + { \ + const UINT32 * pI = (const UINT32 *)input; \ + UINT32 * pS = state; \ + UINT32 t, x0, x1; \ + int i; \ + for (i = (rateInLanes)-1; i >= 0; --i) \ + { \ + x0 = *(pI++); \ + t = (x0 ^ (x0 >> 1)) & 0x22222222UL; x0 = x0 ^ t ^ (t << 1); \ + t = (x0 ^ (x0 >> 2)) & 0x0C0C0C0CUL; x0 = x0 ^ t ^ (t << 2); \ + t = (x0 ^ (x0 >> 4)) & 0x00F000F0UL; x0 = x0 ^ t ^ (t << 4); \ + t = (x0 ^ (x0 >> 8)) & 0x0000FF00UL; x0 = x0 ^ t ^ (t << 8); \ + x1 = *(pI++); \ + t = (x1 ^ (x1 >> 1)) & 0x22222222UL; x1 = x1 ^ t ^ (t << 1); \ + t = (x1 ^ (x1 >> 2)) & 0x0C0C0C0CUL; x1 = x1 ^ t ^ (t << 2); \ + t = (x1 ^ (x1 >> 4)) & 0x00F000F0UL; x1 = x1 ^ t ^ (t << 4); \ + t = (x1 ^ (x1 >> 8)) & 0x0000FF00UL; x1 = x1 ^ t ^ (t << 8); \ + *(pS++) ^= (UINT16)x0 | (x1 << 16); \ + *(pS++) ^= (x0 >> 16) | (x1 & 0xFFFF0000); \ + } \ + } + +#define xorLanesIntoState(laneCount, state, input) \ + xorInterleavedLE(laneCount, state, input) + +#else // (PLATFORM_BYTE_ORDER == IS_BIG_ENDIAN) + +// Credit: Henry S. Warren, Hacker's Delight, Addison-Wesley, 2002 +UINT64 toInterleaving(UINT64 x) +{ + UINT64 t; + + t = (x ^ (x >> 1)) & 0x2222222222222222ULL; x = x ^ t ^ (t << 1); + t = (x ^ (x >> 2)) & 0x0C0C0C0C0C0C0C0CULL; x = x ^ t ^ (t << 2); + t = (x ^ (x >> 4)) & 0x00F000F000F000F0ULL; x = x ^ t ^ (t << 4); + t = (x ^ (x >> 8)) & 0x0000FF000000FF00ULL; x = x ^ t ^ (t << 8); + t = (x ^ (x >> 16)) & 0x00000000FFFF0000ULL; x = x ^ t ^ (t << 16); + + return x; +} + +void xor8bytesIntoInterleavedWords(UINT32* evenAndOdd, const UINT8* source) +{ + // This can be optimized + UINT64 sourceWord = + (UINT64)source[0] + ^ (((UINT64)source[1]) << 8) + ^ (((UINT64)source[2]) << 16) + ^ (((UINT64)source[3]) << 24) + ^ (((UINT64)source[4]) << 32) + ^ (((UINT64)source[5]) << 40) + ^ (((UINT64)source[6]) << 48) + ^ (((UINT64)source[7]) << 56); + UINT64 evenAndOddWord = toInterleaving(sourceWord); + evenAndOdd[0] ^= (UINT32)evenAndOddWord; + evenAndOdd[1] ^= (UINT32)(evenAndOddWord >> 32); +} + +#define xorLanesIntoState(laneCount, state, input) \ + { \ + int i; \ + for(i=0; i<(laneCount); i++) \ + xor8bytesIntoInterleavedWords(state+i*2, input+i*8); \ + } + +#endif // Endianness + +// Credit: Henry S. Warren, Hacker's Delight, Addison-Wesley, 2002 +UINT64 fromInterleaving(UINT64 x) +{ + UINT64 t; + + t = (x ^ (x >> 16)) & 0x00000000FFFF0000ULL; x = x ^ t ^ (t << 16); + t = (x ^ (x >> 8)) & 0x0000FF000000FF00ULL; x = x ^ t ^ (t << 8); + t = (x ^ (x >> 4)) & 0x00F000F000F000F0ULL; x = x ^ t ^ (t << 4); + t = (x ^ (x >> 2)) & 0x0C0C0C0C0C0C0C0CULL; x = x ^ t ^ (t << 2); + t = (x ^ (x >> 1)) & 0x2222222222222222ULL; x = x ^ t ^ (t << 1); + + return x; +} + +void setInterleavedWordsInto8bytes(UINT8* dest, UINT32* evenAndOdd) +{ +#if (PLATFORM_BYTE_ORDER == IS_LITTLE_ENDIAN) + ((UINT64*)dest)[0] = fromInterleaving(*(UINT64*)evenAndOdd); +#else // (PLATFORM_BYTE_ORDER == IS_BIG_ENDIAN) + // This can be optimized + UINT64 evenAndOddWord = (UINT64)evenAndOdd[0] ^ ((UINT64)evenAndOdd[1] << 32); + UINT64 destWord = fromInterleaving(evenAndOddWord); + dest[0] = destWord & 0xFF; + dest[1] = (destWord >> 8) & 0xFF; + dest[2] = (destWord >> 16) & 0xFF; + dest[3] = (destWord >> 24) & 0xFF; + dest[4] = (destWord >> 32) & 0xFF; + dest[5] = (destWord >> 40) & 0xFF; + dest[6] = (destWord >> 48) & 0xFF; + dest[7] = (destWord >> 56) & 0xFF; +#endif // Endianness +} + +#define extractLanes(laneCount, state, data) \ + { \ + int i; \ + for(i=0; i<(laneCount); i++) \ + setInterleavedWordsInto8bytes(data+i*8, (UINT32*)state+i*2); \ + } + +#endif // With or without interleaving tables + +#if defined(_MSC_VER) +#define ROL32(a, offset) _rotl(a, offset) +#elif (defined (__arm__) && defined(__ARMCC_VERSION)) +#define ROL32(a, offset) __ror(a, 32-(offset)) +#else +#define ROL32(a, offset) ((((UINT32)a) << (offset)) ^ (((UINT32)a) >> (32-(offset)))) +#endif + +#include "KeccakF-1600-unrolling.macros" +#include "KeccakF-1600-32.macros" + +#if (UseSchedule == 3) + +#ifdef UseBebigokimisa +#error "No lane complementing with schedule 3." +#endif + +#if (Unrolling != 2) +#error "Only unrolling 2 is supported by schedule 3." +#endif + +void KeccakPermutationOnWords(UINT32 *state) +{ + rounds +} + +void KeccakPermutationOnWordsAfterXoring(UINT32 *state, const UINT8 *input, unsigned int laneCount) +{ + xorLanesIntoState(laneCount, state, input) + rounds +} + +#ifdef ProvideFast576 +void KeccakPermutationOnWordsAfterXoring576bits(UINT32 *state, const UINT8 *input) +{ + xorLanesIntoState(9, state, input) + rounds +} +#endif + +#ifdef ProvideFast832 +void KeccakPermutationOnWordsAfterXoring832bits(UINT32 *state, const UINT8 *input) +{ + xorLanesIntoState(13, state, input) + rounds +} +#endif + +#ifdef ProvideFast1024 +void KeccakPermutationOnWordsAfterXoring1024bits(UINT32 *state, const UINT8 *input) +{ + xorLanesIntoState(16, state, input) + rounds +} +#endif + +#ifdef ProvideFast1088 +void KeccakPermutationOnWordsAfterXoring1088bits(UINT32 *state, const UINT8 *input) +{ + xorLanesIntoState(17, state, input) + rounds +} +#endif + +#ifdef ProvideFast1152 +void KeccakPermutationOnWordsAfterXoring1152bits(UINT32 *state, const UINT8 *input) +{ + xorLanesIntoState(18, state, input) + rounds +} +#endif + +#ifdef ProvideFast1344 +void KeccakPermutationOnWordsAfterXoring1344bits(UINT32 *state, const UINT8 *input) +{ + xorLanesIntoState(21, state, input) + rounds +} +#endif + +#else // (Schedule != 3) + +void KeccakPermutationOnWords(UINT32 *state) +{ + declareABCDE +#if (Unrolling != 24) + unsigned int i; +#endif + + copyFromState(A, state) + rounds +} + +void KeccakPermutationOnWordsAfterXoring(UINT32 *state, const UINT8 *input, unsigned int laneCount) +{ + declareABCDE + unsigned int i; + + xorLanesIntoState(laneCount, state, input) + copyFromState(A, state) + rounds +} + +#ifdef ProvideFast576 +void KeccakPermutationOnWordsAfterXoring576bits(UINT32 *state, const UINT8 *input) +{ + declareABCDE + unsigned int i; + + xorLanesIntoState(9, state, input) + copyFromState(A, state) + rounds +} +#endif + +#ifdef ProvideFast832 +void KeccakPermutationOnWordsAfterXoring832bits(UINT32 *state, const UINT8 *input) +{ + declareABCDE + unsigned int i; + + xorLanesIntoState(13, state, input) + copyFromState(A, state) + rounds +} +#endif + +#ifdef ProvideFast1024 +void KeccakPermutationOnWordsAfterXoring1024bits(UINT32 *state, const UINT8 *input) +{ + declareABCDE + unsigned int i; + + xorLanesIntoState(16, state, input) + copyFromState(A, state) + rounds +} +#endif + +#ifdef ProvideFast1088 +void KeccakPermutationOnWordsAfterXoring1088bits(UINT32 *state, const UINT8 *input) +{ + declareABCDE + unsigned int i; + + xorLanesIntoState(17, state, input) + copyFromState(A, state) + rounds +} +#endif + +#ifdef ProvideFast1152 +void KeccakPermutationOnWordsAfterXoring1152bits(UINT32 *state, const UINT8 *input) +{ + declareABCDE + unsigned int i; + + xorLanesIntoState(18, state, input) + copyFromState(A, state) + rounds +} +#endif + +#ifdef ProvideFast1344 +void KeccakPermutationOnWordsAfterXoring1344bits(UINT32 *state, const UINT8 *input) +{ + declareABCDE + unsigned int i; + + xorLanesIntoState(21, state, input) + copyFromState(A, state) + rounds +} +#endif + +#endif + +void KeccakInitialize() +{ +#ifdef UseInterleaveTables + buildInterleaveTables(); +#endif +} + +void KeccakInitializeState(unsigned char *state) +{ + memset(state, 0, 200); +#ifdef UseBebigokimisa + ((UINT32*)state)[ 2] = ~(UINT32)0; + ((UINT32*)state)[ 3] = ~(UINT32)0; + ((UINT32*)state)[ 4] = ~(UINT32)0; + ((UINT32*)state)[ 5] = ~(UINT32)0; + ((UINT32*)state)[16] = ~(UINT32)0; + ((UINT32*)state)[17] = ~(UINT32)0; + ((UINT32*)state)[24] = ~(UINT32)0; + ((UINT32*)state)[25] = ~(UINT32)0; + ((UINT32*)state)[34] = ~(UINT32)0; + ((UINT32*)state)[35] = ~(UINT32)0; + ((UINT32*)state)[40] = ~(UINT32)0; + ((UINT32*)state)[41] = ~(UINT32)0; +#endif +} + +void KeccakPermutation(unsigned char *state) +{ + // We assume the state is always stored as interleaved 32-bit words + KeccakPermutationOnWords((UINT32*)state); +} + +#ifdef ProvideFast576 +void KeccakAbsorb576bits(unsigned char *state, const unsigned char *data) +{ + KeccakPermutationOnWordsAfterXoring576bits((UINT32*)state, data); +} +#endif + +#ifdef ProvideFast832 +void KeccakAbsorb832bits(unsigned char *state, const unsigned char *data) +{ + KeccakPermutationOnWordsAfterXoring832bits((UINT32*)state, data); +} +#endif + +#ifdef ProvideFast1024 +void KeccakAbsorb1024bits(unsigned char *state, const unsigned char *data) +{ + KeccakPermutationOnWordsAfterXoring1024bits((UINT32*)state, data); +} +#endif + +#ifdef ProvideFast1088 +void KeccakAbsorb1088bits(unsigned char *state, const unsigned char *data) +{ + KeccakPermutationOnWordsAfterXoring1088bits((UINT32*)state, data); +} +#endif + +#ifdef ProvideFast1152 +void KeccakAbsorb1152bits(unsigned char *state, const unsigned char *data) +{ + KeccakPermutationOnWordsAfterXoring1152bits((UINT32*)state, data); +} +#endif + +#ifdef ProvideFast1344 +void KeccakAbsorb1344bits(unsigned char *state, const unsigned char *data) +{ + KeccakPermutationOnWordsAfterXoring1344bits((UINT32*)state, data); +} +#endif + +void KeccakAbsorb(unsigned char *state, const unsigned char *data, unsigned int laneCount) +{ + KeccakPermutationOnWordsAfterXoring((UINT32*)state, data, laneCount); +} + +#ifdef ProvideFast1024 +void KeccakExtract1024bits(const unsigned char *state, unsigned char *data) +{ + extractLanes(16, state, data) +#ifdef UseBebigokimisa + ((UINT32*)data)[ 2] = ~((UINT32*)data)[ 2]; + ((UINT32*)data)[ 3] = ~((UINT32*)data)[ 3]; + ((UINT32*)data)[ 4] = ~((UINT32*)data)[ 4]; + ((UINT32*)data)[ 5] = ~((UINT32*)data)[ 5]; + ((UINT32*)data)[16] = ~((UINT32*)data)[16]; + ((UINT32*)data)[17] = ~((UINT32*)data)[17]; + ((UINT32*)data)[24] = ~((UINT32*)data)[24]; + ((UINT32*)data)[25] = ~((UINT32*)data)[25]; +#endif +} +#endif + +void KeccakExtract(const unsigned char *state, unsigned char *data, unsigned int laneCount) +{ + extractLanes(laneCount, state, data) +#ifdef UseBebigokimisa + if (laneCount > 1) { + ((UINT32*)data)[ 2] = ~((UINT32*)data)[ 2]; + ((UINT32*)data)[ 3] = ~((UINT32*)data)[ 3]; + if (laneCount > 2) { + ((UINT32*)data)[ 4] = ~((UINT32*)data)[ 4]; + ((UINT32*)data)[ 5] = ~((UINT32*)data)[ 5]; + if (laneCount > 8) { + ((UINT32*)data)[16] = ~((UINT32*)data)[16]; + ((UINT32*)data)[17] = ~((UINT32*)data)[17]; + if (laneCount > 12) { + ((UINT32*)data)[24] = ~((UINT32*)data)[24]; + ((UINT32*)data)[25] = ~((UINT32*)data)[25]; + if (laneCount > 17) { + ((UINT32*)data)[34] = ~((UINT32*)data)[34]; + ((UINT32*)data)[35] = ~((UINT32*)data)[35]; + if (laneCount > 20) { + ((UINT32*)data)[40] = ~((UINT32*)data)[40]; + ((UINT32*)data)[41] = ~((UINT32*)data)[41]; + } + } + } + } + } + } +#endif +} diff --git a/c_src/KeccakF-1600-opt64-settings.h b/c_src/KeccakF-1600-opt64-settings.h new file mode 100755 index 0000000..8f16ada --- /dev/null +++ b/c_src/KeccakF-1600-opt64-settings.h @@ -0,0 +1,7 @@ +#define Unrolling 24 +#define UseBebigokimisa +//#define UseSSE +//#define UseOnlySIMD64 +//#define UseMMX +//#define UseSHLD +//#define UseXOP diff --git a/c_src/KeccakF-1600-opt64.c b/c_src/KeccakF-1600-opt64.c new file mode 100755 index 0000000..9349f03 --- /dev/null +++ b/c_src/KeccakF-1600-opt64.c @@ -0,0 +1,504 @@ +/* +The Keccak sponge function, designed by Guido Bertoni, Joan Daemen, +Michaël Peeters and Gilles Van Assche. For more information, feedback or +questions, please refer to our website: http://keccak.noekeon.org/ + +Implementation by the designers, +hereby denoted as "the implementer". + +To the extent possible under law, the implementer has waived all copyright +and related or neighboring rights to the source code in this file. +http://creativecommons.org/publicdomain/zero/1.0/ +*/ + +#include +#include "brg_endian.h" +#include "KeccakF-1600-opt64-settings.h" +#include "KeccakF-1600-interface.h" + +typedef unsigned char UINT8; +typedef unsigned long long int UINT64; + +#if defined(__GNUC__) +#define ALIGN __attribute__ ((aligned(32))) +#elif defined(_MSC_VER) +#define ALIGN __declspec(align(32)) +#else +#define ALIGN +#endif + +#if defined(UseSSE) + #include + typedef __m128i V64; + typedef __m128i V128; + typedef union { + V128 v128; + UINT64 v64[2]; + } V6464; + + #define ANDnu64(a, b) _mm_andnot_si128(a, b) + #define LOAD64(a) _mm_loadl_epi64((const V64 *)&(a)) + #define CONST64(a) _mm_loadl_epi64((const V64 *)&(a)) + #define ROL64(a, o) _mm_or_si128(_mm_slli_epi64(a, o), _mm_srli_epi64(a, 64-(o))) + #define STORE64(a, b) _mm_storel_epi64((V64 *)&(a), b) + #define XOR64(a, b) _mm_xor_si128(a, b) + #define XOReq64(a, b) a = _mm_xor_si128(a, b) + #define SHUFFLEBYTES128(a, b) _mm_shuffle_epi8(a, b) + + #define ANDnu128(a, b) _mm_andnot_si128(a, b) + #define LOAD6464(a, b) _mm_set_epi64((__m64)(a), (__m64)(b)) + #define CONST128(a) _mm_load_si128((const V128 *)&(a)) + #define LOAD128(a) _mm_load_si128((const V128 *)&(a)) + #define LOAD128u(a) _mm_loadu_si128((const V128 *)&(a)) + #define ROL64in128(a, o) _mm_or_si128(_mm_slli_epi64(a, o), _mm_srli_epi64(a, 64-(o))) + #define STORE128(a, b) _mm_store_si128((V128 *)&(a), b) + #define XOR128(a, b) _mm_xor_si128(a, b) + #define XOReq128(a, b) a = _mm_xor_si128(a, b) + #define GET64LOLO(a, b) _mm_unpacklo_epi64(a, b) + #define GET64HIHI(a, b) _mm_unpackhi_epi64(a, b) + #define COPY64HI2LO(a) _mm_shuffle_epi32(a, 0xEE) + #define COPY64LO2HI(a) _mm_shuffle_epi32(a, 0x44) + #define ZERO128() _mm_setzero_si128() + + #ifdef UseOnlySIMD64 + #include "KeccakF-1600-simd64.macros" + #else +ALIGN const UINT64 rho8_56[2] = {0x0605040302010007, 0x080F0E0D0C0B0A09}; + #include "KeccakF-1600-simd128.macros" + #endif + + #ifdef UseBebigokimisa + #error "UseBebigokimisa cannot be used in combination with UseSSE" + #endif +#elif defined(UseXOP) + #include + typedef __m128i V64; + typedef __m128i V128; + + #define LOAD64(a) _mm_loadl_epi64((const V64 *)&(a)) + #define CONST64(a) _mm_loadl_epi64((const V64 *)&(a)) + #define STORE64(a, b) _mm_storel_epi64((V64 *)&(a), b) + #define XOR64(a, b) _mm_xor_si128(a, b) + #define XOReq64(a, b) a = _mm_xor_si128(a, b) + + #define ANDnu128(a, b) _mm_andnot_si128(a, b) + #define LOAD6464(a, b) _mm_set_epi64((__m64)(a), (__m64)(b)) + #define CONST128(a) _mm_load_si128((const V128 *)&(a)) + #define LOAD128(a) _mm_load_si128((const V128 *)&(a)) + #define LOAD128u(a) _mm_loadu_si128((const V128 *)&(a)) + #define STORE128(a, b) _mm_store_si128((V128 *)&(a), b) + #define XOR128(a, b) _mm_xor_si128(a, b) + #define XOReq128(a, b) a = _mm_xor_si128(a, b) + #define ZERO128() _mm_setzero_si128() + + #define SWAP64(a) _mm_shuffle_epi32(a, 0x4E) + #define GET64LOLO(a, b) _mm_unpacklo_epi64(a, b) + #define GET64HIHI(a, b) _mm_unpackhi_epi64(a, b) + #define GET64LOHI(a, b) ((__m128i)_mm_blend_pd((__m128d)a, (__m128d)b, 2)) + #define GET64HILO(a, b) SWAP64(GET64LOHI(b, a)) + #define COPY64HI2LO(a) _mm_shuffle_epi32(a, 0xEE) + #define COPY64LO2HI(a) _mm_shuffle_epi32(a, 0x44) + + #define ROL6464same(a, o) _mm_roti_epi64(a, o) + #define ROL6464(a, r1, r2) _mm_rot_epi64(a, CONST128( rot_##r1##_##r2 )) +ALIGN const UINT64 rot_0_20[2] = { 0, 20}; +ALIGN const UINT64 rot_44_3[2] = {44, 3}; +ALIGN const UINT64 rot_43_45[2] = {43, 45}; +ALIGN const UINT64 rot_21_61[2] = {21, 61}; +ALIGN const UINT64 rot_14_28[2] = {14, 28}; +ALIGN const UINT64 rot_1_36[2] = { 1, 36}; +ALIGN const UINT64 rot_6_10[2] = { 6, 10}; +ALIGN const UINT64 rot_25_15[2] = {25, 15}; +ALIGN const UINT64 rot_8_56[2] = { 8, 56}; +ALIGN const UINT64 rot_18_27[2] = {18, 27}; +ALIGN const UINT64 rot_62_55[2] = {62, 55}; +ALIGN const UINT64 rot_39_41[2] = {39, 41}; + +#if defined(UseSimulatedXOP) + // For debugging purposes, when XOP is not available + #undef ROL6464 + #undef ROL6464same + #define ROL6464same(a, o) _mm_or_si128(_mm_slli_epi64(a, o), _mm_srli_epi64(a, 64-(o))) + V128 ROL6464(V128 a, int r0, int r1) + { + V128 a0 = ROL64(a, r0); + V128 a1 = COPY64HI2LO(ROL64(a, r1)); + return GET64LOLO(a0, a1); + } +#endif + + #include "KeccakF-1600-xop.macros" + + #ifdef UseBebigokimisa + #error "UseBebigokimisa cannot be used in combination with UseXOP" + #endif +#elif defined(UseMMX) + #include + typedef __m64 V64; + #define ANDnu64(a, b) _mm_andnot_si64(a, b) + + #if (defined(_MSC_VER) || defined (__INTEL_COMPILER)) + #define LOAD64(a) *(V64*)&(a) + #define CONST64(a) *(V64*)&(a) + #define STORE64(a, b) *(V64*)&(a) = b + #else + #define LOAD64(a) (V64)a + #define CONST64(a) (V64)a + #define STORE64(a, b) a = (UINT64)b + #endif + #define ROL64(a, o) _mm_or_si64(_mm_slli_si64(a, o), _mm_srli_si64(a, 64-(o))) + #define XOR64(a, b) _mm_xor_si64(a, b) + #define XOReq64(a, b) a = _mm_xor_si64(a, b) + + #include "KeccakF-1600-simd64.macros" + + #ifdef UseBebigokimisa + #error "UseBebigokimisa cannot be used in combination with UseMMX" + #endif +#else + #if defined(_MSC_VER) + #define ROL64(a, offset) _rotl64(a, offset) + #elif defined(UseSHLD) + #define ROL64(x,N) ({ \ + register UINT64 __out; \ + register UINT64 __in = x; \ + __asm__ ("shld %2,%0,%0" : "=r"(__out) : "0"(__in), "i"(N)); \ + __out; \ + }) + #else + #define ROL64(a, offset) ((((UINT64)a) << offset) ^ (((UINT64)a) >> (64-offset))) + #endif + + #include "KeccakF-1600-64.macros" +#endif + +#include "KeccakF-1600-unrolling.macros" + +void KeccakPermutationOnWords(UINT64 *state) +{ + declareABCDE +#if (Unrolling != 24) + unsigned int i; +#endif + + copyFromState(A, state) + rounds +#if defined(UseMMX) + _mm_empty(); +#endif +} + +void KeccakPermutationOnWordsAfterXoring(UINT64 *state, const UINT64 *input, unsigned int laneCount) +{ + declareABCDE +#if (Unrolling != 24) + unsigned int i; +#endif + unsigned int j; + + for(j=0; j> (8*i)) & 0xFF; +} + +#ifdef ProvideFast1024 +void KeccakExtract1024bits(const unsigned char *state, unsigned char *data) +{ +#if (PLATFORM_BYTE_ORDER == IS_LITTLE_ENDIAN) + memcpy(data, state, 128); +#else + unsigned int i; + + for(i=0; i<16; i++) + fromWordToBytes(data+(i*8), ((const UINT64*)state)[i]); +#endif +#ifdef UseBebigokimisa + ((UINT64*)data)[ 1] = ~((UINT64*)data)[ 1]; + ((UINT64*)data)[ 2] = ~((UINT64*)data)[ 2]; + ((UINT64*)data)[ 8] = ~((UINT64*)data)[ 8]; + ((UINT64*)data)[12] = ~((UINT64*)data)[12]; +#endif +} +#endif + +void KeccakExtract(const unsigned char *state, unsigned char *data, unsigned int laneCount) +{ +#if (PLATFORM_BYTE_ORDER == IS_LITTLE_ENDIAN) + memcpy(data, state, laneCount*8); +#else + unsigned int i; + + for(i=0; i 1) { + ((UINT64*)data)[ 1] = ~((UINT64*)data)[ 1]; + if (laneCount > 2) { + ((UINT64*)data)[ 2] = ~((UINT64*)data)[ 2]; + if (laneCount > 8) { + ((UINT64*)data)[ 8] = ~((UINT64*)data)[ 8]; + if (laneCount > 12) { + ((UINT64*)data)[12] = ~((UINT64*)data)[12]; + if (laneCount > 17) { + ((UINT64*)data)[17] = ~((UINT64*)data)[17]; + if (laneCount > 20) { + ((UINT64*)data)[20] = ~((UINT64*)data)[20]; + } + } + } + } + } + } +#endif +} diff --git a/c_src/KeccakF-1600-reference.c b/c_src/KeccakF-1600-reference.c new file mode 100755 index 0000000..628f710 --- /dev/null +++ b/c_src/KeccakF-1600-reference.c @@ -0,0 +1,300 @@ +/* +The Keccak sponge function, designed by Guido Bertoni, Joan Daemen, +Michaël Peeters and Gilles Van Assche. For more information, feedback or +questions, please refer to our website: http://keccak.noekeon.org/ + +Implementation by the designers, +hereby denoted as "the implementer". + +To the extent possible under law, the implementer has waived all copyright +and related or neighboring rights to the source code in this file. +http://creativecommons.org/publicdomain/zero/1.0/ +*/ + +#include +#include +#include "brg_endian.h" +#include "displayIntermediateValues.h" +#include "KeccakNISTInterface.h" +#include "KeccakF-1600-interface.h" + +typedef unsigned char UINT8; +typedef unsigned long long int UINT64; + +#define nrRounds 24 +UINT64 KeccakRoundConstants[nrRounds]; +#define nrLanes 25 +unsigned int KeccakRhoOffsets[nrLanes]; + +void KeccakPermutationOnWords(UINT64 *state); +void theta(UINT64 *A); +void rho(UINT64 *A); +void pi(UINT64 *A); +void chi(UINT64 *A); +void iota(UINT64 *A, unsigned int indexRound); + +void fromBytesToWords(UINT64 *stateAsWords, const unsigned char *state) +{ + unsigned int i, j; + + for(i=0; i<(KeccakPermutationSize/64); i++) { + stateAsWords[i] = 0; + for(j=0; j<(64/8); j++) + stateAsWords[i] |= (UINT64)(state[i*(64/8)+j]) << (8*j); + } +} + +void fromWordsToBytes(unsigned char *state, const UINT64 *stateAsWords) +{ + unsigned int i, j; + + for(i=0; i<(KeccakPermutationSize/64); i++) + for(j=0; j<(64/8); j++) + state[i*(64/8)+j] = (stateAsWords[i] >> (8*j)) & 0xFF; +} + +void KeccakPermutation(unsigned char *state) +{ +#if (PLATFORM_BYTE_ORDER != IS_LITTLE_ENDIAN) + UINT64 stateAsWords[KeccakPermutationSize/64]; +#endif + + displayStateAsBytes(1, "Input of permutation", state); +#if (PLATFORM_BYTE_ORDER == IS_LITTLE_ENDIAN) + KeccakPermutationOnWords((UINT64*)state); +#else + fromBytesToWords(stateAsWords, state); + KeccakPermutationOnWords(stateAsWords); + fromWordsToBytes(state, stateAsWords); +#endif + displayStateAsBytes(1, "State after permutation", state); +} + +void KeccakPermutationAfterXor(unsigned char *state, const unsigned char *data, unsigned int dataLengthInBytes) +{ + unsigned int i; + + for(i=0; i> (64-offset))) : a) + +void theta(UINT64 *A) +{ + unsigned int x, y; + UINT64 C[5], D[5]; + + for(x=0; x<5; x++) { + C[x] = 0; + for(y=0; y<5; y++) + C[x] ^= A[index(x, y)]; + } + for(x=0; x<5; x++) + D[x] = ROL64(C[(x+1)%5], 1) ^ C[(x+4)%5]; + for(x=0; x<5; x++) + for(y=0; y<5; y++) + A[index(x, y)] ^= D[x]; +} + +void rho(UINT64 *A) +{ + unsigned int x, y; + + for(x=0; x<5; x++) for(y=0; y<5; y++) + A[index(x, y)] = ROL64(A[index(x, y)], KeccakRhoOffsets[index(x, y)]); +} + +void pi(UINT64 *A) +{ + unsigned int x, y; + UINT64 tempA[25]; + + for(x=0; x<5; x++) for(y=0; y<5; y++) + tempA[index(x, y)] = A[index(x, y)]; + for(x=0; x<5; x++) for(y=0; y<5; y++) + A[index(0*x+1*y, 2*x+3*y)] = tempA[index(x, y)]; +} + +void chi(UINT64 *A) +{ + unsigned int x, y; + UINT64 C[5]; + + for(y=0; y<5; y++) { + for(x=0; x<5; x++) + C[x] = A[index(x, y)] ^ ((~A[index(x+1, y)]) & A[index(x+2, y)]); + for(x=0; x<5; x++) + A[index(x, y)] = C[x]; + } +} + +void iota(UINT64 *A, unsigned int indexRound) +{ + A[index(0, 0)] ^= KeccakRoundConstants[indexRound]; +} + +int LFSR86540(UINT8 *LFSR) +{ + int result = ((*LFSR) & 0x01) != 0; + if (((*LFSR) & 0x80) != 0) + // Primitive polynomial over GF(2): x^8+x^6+x^5+x^4+1 + (*LFSR) = ((*LFSR) << 1) ^ 0x71; + else + (*LFSR) <<= 1; + return result; +} + +void KeccakInitializeRoundConstants() +{ + UINT8 LFSRstate = 0x01; + unsigned int i, j, bitPosition; + + for(i=0; i> 32)); + fprintf(f, "%08X", (unsigned int)(KeccakRoundConstants[i] & 0xFFFFFFFFULL)); + fprintf(f, "\n"); + } + fprintf(f, "\n"); +} + +void displayRhoOffsets(FILE *f) +{ + unsigned int x, y; + + for(y=0; y<5; y++) for(x=0; x<5; x++) { + fprintf(f, "RhoOffset[%i][%i] = ", x, y); + fprintf(f, "%2i", KeccakRhoOffsets[index(x, y)]); + fprintf(f, "\n"); + } + fprintf(f, "\n"); +} + +void KeccakInitializeState(unsigned char *state) +{ + memset(state, 0, KeccakPermutationSizeInBytes); +} + +#ifdef ProvideFast576 +void KeccakAbsorb576bits(unsigned char *state, const unsigned char *data) +{ + KeccakPermutationAfterXor(state, data, 72); +} +#endif + +#ifdef ProvideFast832 +void KeccakAbsorb832bits(unsigned char *state, const unsigned char *data) +{ + KeccakPermutationAfterXor(state, data, 104); +} +#endif + +#ifdef ProvideFast1024 +void KeccakAbsorb1024bits(unsigned char *state, const unsigned char *data) +{ + KeccakPermutationAfterXor(state, data, 128); +} +#endif + +#ifdef ProvideFast1088 +void KeccakAbsorb1088bits(unsigned char *state, const unsigned char *data) +{ + KeccakPermutationAfterXor(state, data, 136); +} +#endif + +#ifdef ProvideFast1152 +void KeccakAbsorb1152bits(unsigned char *state, const unsigned char *data) +{ + KeccakPermutationAfterXor(state, data, 144); +} +#endif + +#ifdef ProvideFast1344 +void KeccakAbsorb1344bits(unsigned char *state, const unsigned char *data) +{ + KeccakPermutationAfterXor(state, data, 168); +} +#endif + +void KeccakAbsorb(unsigned char *state, const unsigned char *data, unsigned int laneCount) +{ + KeccakPermutationAfterXor(state, data, laneCount*8); +} + +#ifdef ProvideFast1024 +void KeccakExtract1024bits(const unsigned char *state, unsigned char *data) +{ + memcpy(data, state, 128); +} +#endif + +void KeccakExtract(const unsigned char *state, unsigned char *data, unsigned int laneCount) +{ + memcpy(data, state, laneCount*8); +} diff --git a/c_src/KeccakF-1600-reference.h b/c_src/KeccakF-1600-reference.h new file mode 100755 index 0000000..698bab8 --- /dev/null +++ b/c_src/KeccakF-1600-reference.h @@ -0,0 +1,20 @@ +/* +The Keccak sponge function, designed by Guido Bertoni, Joan Daemen, +Michaël Peeters and Gilles Van Assche. For more information, feedback or +questions, please refer to our website: http://keccak.noekeon.org/ + +Implementation by the designers, +hereby denoted as "the implementer". + +To the extent possible under law, the implementer has waived all copyright +and related or neighboring rights to the source code in this file. +http://creativecommons.org/publicdomain/zero/1.0/ +*/ + +#ifndef _KeccakPermutationReference_h_ +#define _KeccakPermutationReference_h_ + +void displayRoundConstants(FILE *f); +void displayRhoOffsets(FILE *f); + +#endif diff --git a/c_src/KeccakF-1600-reference32BI.c b/c_src/KeccakF-1600-reference32BI.c new file mode 100755 index 0000000..1ec4c23 --- /dev/null +++ b/c_src/KeccakF-1600-reference32BI.c @@ -0,0 +1,371 @@ +/* +The Keccak sponge function, designed by Guido Bertoni, Joan Daemen, +Michaël Peeters and Gilles Van Assche. For more information, feedback or +questions, please refer to our website: http://keccak.noekeon.org/ + +Implementation by the designers, +hereby denoted as "the implementer". + +To the extent possible under law, the implementer has waived all copyright +and related or neighboring rights to the source code in this file. +http://creativecommons.org/publicdomain/zero/1.0/ +*/ + +#include +#include +#include "brg_endian.h" +#include "displayIntermediateValues.h" +#include "KeccakNISTInterface.h" +#include "KeccakF-1600-interface.h" + +typedef unsigned char UINT8; +typedef unsigned int UINT32; + +#define nrRounds 24 +UINT32 KeccakRoundConstants[nrRounds][2]; +#define nrLanes 25 +unsigned int KeccakRhoOffsets[nrLanes]; + +void KeccakPermutationOnWords(UINT32 *state); +void theta(UINT32 *A); +void rho(UINT32 *A); +void pi(UINT32 *A); +void chi(UINT32 *A); +void iota(UINT32 *A, unsigned int indexRound); + +void toBitInterleaving(UINT32 low, UINT32 high, UINT32 *even, UINT32 *odd) +{ + unsigned int i; + + *even = 0; + *odd = 0; + for(i=0; i<64; i++) { + unsigned int inBit; + if (i < 32) + inBit = (low >> i) & 1; + else + inBit = (high >> (i-32)) & 1; + if ((i % 2) == 0) + *even |= inBit << (i/2); + else + *odd |= inBit << ((i-1)/2); + } +} + +void fromBitInterleaving(UINT32 even, UINT32 odd, UINT32 *low, UINT32 *high) +{ + unsigned int i; + + *low = 0; + *high = 0; + for(i=0; i<64; i++) { + unsigned int inBit; + if ((i % 2) == 0) + inBit = (even >> (i/2)) & 1; + else + inBit = (odd >> ((i-1)/2)) & 1; + if (i < 32) + *low |= inBit << i; + else + *high |= inBit << (i-32); + } +} + +void fromBytesToWords(UINT32 *stateAsWords, const unsigned char *state) +{ + unsigned int i, j; + UINT32 low, high; + UINT32 even, odd; + + for(i=0; i<(KeccakPermutationSize/64); i++) { + low = 0; + high = 0; + for(j=0; j<(32/8); j++) + low |= (UINT32)(state[i*(64/8)+j]) << (8*j); + for(j=(32/8); j<(64/8); j++) + high |= (UINT32)(state[i*(64/8)+j]) << (8*j-32); + toBitInterleaving(low, high, &even, &odd); + stateAsWords[2*i+0] = even; + stateAsWords[2*i+1] = odd; + } +} + +void fromWordsToBytes(unsigned char *state, const UINT32 *stateAsWords) +{ + unsigned int i, j; + UINT32 low, high; + + for(i=0; i<(KeccakPermutationSize/64); i++) { + fromBitInterleaving(stateAsWords[2*i+0], stateAsWords[2*i+1], &low, &high); + for(j=0; j<(32/8); j++) + state[i*(64/8)+j] = (low >> (8*j)) & 0xFF; + for(j=32/8; j<(64/8); j++) + state[i*(64/8)+j] = (high >> (8*j-32)) & 0xFF; + } +} + +void KeccakPermutation(unsigned char *state) +{ + UINT32 stateAsWords[KeccakPermutationSize/32]; + + displayStateAsBytes(1, "Input of permutation", state); + fromBytesToWords(stateAsWords, state); + KeccakPermutationOnWords(stateAsWords); + fromWordsToBytes(state, stateAsWords); + displayStateAsBytes(1, "State after permutation", state); +} + +void KeccakPermutationAfterXor(unsigned char *state, const unsigned char *data, unsigned int dataLengthInBytes) +{ + unsigned int i; + + for(i=0; i> (32-offset))) : a) + +void ROL64(UINT32 inEven, UINT32 inOdd, UINT32 *outEven, UINT32 *outOdd, unsigned int offset) +{ + if ((offset % 2) == 0) { + *outEven = ROL32(inEven, offset/2); + *outOdd = ROL32(inOdd, offset/2); + } + else { + *outEven = ROL32(inOdd, (offset+1)/2); + *outOdd = ROL32(inEven, (offset-1)/2); + } +} + +void theta(UINT32 *A) +{ + unsigned int x, y, z; + UINT32 C[5][2], D[5][2]; + + for(x=0; x<5; x++) { + for(z=0; z<2; z++) { + C[x][z] = 0; + for(y=0; y<5; y++) + C[x][z] ^= A[index(x, y, z)]; + } + } + for(x=0; x<5; x++) { + ROL64(C[(x+1)%5][0], C[(x+1)%5][1], &(D[x][0]), &(D[x][1]), 1); + for(z=0; z<2; z++) + D[x][z] ^= C[(x+4)%5][z]; + } + for(x=0; x<5; x++) + for(y=0; y<5; y++) + for(z=0; z<2; z++) + A[index(x, y, z)] ^= D[x][z]; +} + +void rho(UINT32 *A) +{ + unsigned int x, y; + + for(x=0; x<5; x++) for(y=0; y<5; y++) + ROL64(A[index(x, y, 0)], A[index(x, y, 1)], &(A[index(x, y, 0)]), &(A[index(x, y, 1)]), KeccakRhoOffsets[5*y+x]); +} + +void pi(UINT32 *A) +{ + unsigned int x, y, z; + UINT32 tempA[50]; + + for(x=0; x<5; x++) for(y=0; y<5; y++) for(z=0; z<2; z++) + tempA[index(x, y, z)] = A[index(x, y, z)]; + for(x=0; x<5; x++) for(y=0; y<5; y++) for(z=0; z<2; z++) + A[index(0*x+1*y, 2*x+3*y, z)] = tempA[index(x, y, z)]; +} + +void chi(UINT32 *A) +{ + unsigned int x, y, z; + UINT32 C[5][2]; + + for(y=0; y<5; y++) { + for(x=0; x<5; x++) + for(z=0; z<2; z++) + C[x][z] = A[index(x, y, z)] ^ ((~A[index(x+1, y, z)]) & A[index(x+2, y, z)]); + for(x=0; x<5; x++) + for(z=0; z<2; z++) + A[index(x, y, z)] = C[x][z]; + } +} + +void iota(UINT32 *A, unsigned int indexRound) +{ + A[index(0, 0, 0)] ^= KeccakRoundConstants[indexRound][0]; + A[index(0, 0, 1)] ^= KeccakRoundConstants[indexRound][1]; +} + +int LFSR86540(UINT8 *LFSR) +{ + int result = ((*LFSR) & 0x01) != 0; + if (((*LFSR) & 0x80) != 0) + // Primitive polynomial over GF(2): x^8+x^6+x^5+x^4+1 + (*LFSR) = ((*LFSR) << 1) ^ 0x71; + else + (*LFSR) <<= 1; + return result; +} + +void KeccakInitializeRoundConstants() +{ + UINT8 LFSRstate = 0x01; + unsigned int i, j, bitPosition; + UINT32 low, high; + + for(i=0; i +#include "KeccakF-1600-interface.h" + +#define UseBebigokimisa + +typedef unsigned char UINT8; +typedef unsigned long long int UINT64; + +void KeccakInitialize() +{ +} + +void KeccakExtract(const unsigned char *state, unsigned char *data, unsigned int laneCount) +{ + memcpy(data, state, laneCount*8); +#ifdef UseBebigokimisa + if (laneCount > 8) + { + ((UINT64*)data)[ 1] = ~((UINT64*)data)[ 1]; + ((UINT64*)data)[ 2] = ~((UINT64*)data)[ 2]; + ((UINT64*)data)[ 8] = ~((UINT64*)data)[ 8]; + + if (laneCount > 12) + { + ((UINT64*)data)[12] = ~((UINT64*)data)[12]; + if (laneCount > 17) + { + ((UINT64*)data)[17] = ~((UINT64*)data)[17]; + if (laneCount > 20) + { + ((UINT64*)data)[20] = ~((UINT64*)data)[20]; + } + } + } + } + else + { + if (laneCount > 1) + { + ((UINT64*)data)[ 1] = ~((UINT64*)data)[ 1]; + if (laneCount > 2) + { + ((UINT64*)data)[ 2] = ~((UINT64*)data)[ 2]; + } + } + } + +#endif +} diff --git a/c_src/KeccakF-1600-x86-64-gas.s b/c_src/KeccakF-1600-x86-64-gas.s new file mode 100755 index 0000000..289a84e --- /dev/null +++ b/c_src/KeccakF-1600-x86-64-gas.s @@ -0,0 +1,766 @@ +# +# The Keccak sponge function, designed by Guido Bertoni, Joan Daemen, +# Michaël Peeters and Gilles Van Assche. For more information, feedback or +# questions, please refer to our website: http://keccak.noekeon.org/ +# +# Implementation by Ronny Van Keer, +# hereby denoted as "the implementer". +# +# To the extent possible under law, the implementer has waived all copyright +# and related or neighboring rights to the source code in this file. +# http://creativecommons.org/publicdomain/zero/1.0/ +# + + .text + + +#// --- defines + +.equ UseSIMD, 1 + + +.equ _ba, 0*8 +.equ _be, 1*8 +.equ _bi, 2*8 +.equ _bo, 3*8 +.equ _bu, 4*8 +.equ _ga, 5*8 +.equ _ge, 6*8 +.equ _gi, 7*8 +.equ _go, 8*8 +.equ _gu, 9*8 +.equ _ka, 10*8 +.equ _ke, 11*8 +.equ _ki, 12*8 +.equ _ko, 13*8 +.equ _ku, 14*8 +.equ _ma, 15*8 +.equ _me, 16*8 +.equ _mi, 17*8 +.equ _mo, 18*8 +.equ _mu, 19*8 +.equ _sa, 20*8 +.equ _se, 21*8 +.equ _si, 22*8 +.equ _so, 23*8 +.equ _su, 24*8 + + +# arguments +.equ apState, %rdi +.equ apInput, %rsi +.equ aNbrWords, %rdx + +# xor input into state section +.equ xpState, %r9 + +# round vars +.equ rT1, %rax +.equ rpState, %rdi +.equ rpStack, %rsp + +.equ rDa, %rbx +.equ rDe, %rcx +.equ rDi, %rdx +.equ rDo, %r8 +.equ rDu, %r9 + +.equ rBa, %r10 +.equ rBe, %r11 +.equ rBi, %r12 +.equ rBo, %r13 +.equ rBu, %r14 + +.equ rCa, %rsi +.equ rCe, %rbp +.equ rCi, rBi +.equ rCo, rBo +.equ rCu, %r15 + +.macro mKeccakRound iState, oState, rc, lastRound + + movq rCe, rDa + rolq rDa + + movq _bi(\iState), rCi + xorq _gi(\iState), rDi + xorq rCu, rDa + xorq _ki(\iState), rCi + xorq _mi(\iState), rDi + xorq rDi, rCi + + movq rCi, rDe + rolq rDe + + movq _bo(\iState), rCo + xorq _go(\iState), rDo + xorq rCa, rDe + xorq _ko(\iState), rCo + xorq _mo(\iState), rDo + xorq rDo, rCo + + movq rCo, rDi + rolq rDi + + movq rCu, rDo + xorq rCe, rDi + rolq rDo + + movq rCa, rDu + xorq rCi, rDo + rolq rDu + + movq _ba(\iState), rBa + movq _ge(\iState), rBe + xorq rCo, rDu + movq _ki(\iState), rBi + movq _mo(\iState), rBo + movq _su(\iState), rBu + xorq rDe, rBe + rolq $44, rBe + xorq rDi, rBi + xorq rDa, rBa + rolq $43, rBi + + movq rBe, rCa + movq $\rc, rT1 + orq rBi, rCa + xorq rBa, rT1 + xorq rT1, rCa + movq rCa, _ba(\oState) + + xorq rDu, rBu + rolq $14, rBu + movq rBa, rCu + andq rBe, rCu + xorq rBu, rCu + movq rCu, _bu(\oState) + + xorq rDo, rBo + rolq $21, rBo + movq rBo, rT1 + andq rBu, rT1 + xorq rBi, rT1 + movq rT1, _bi(\oState) + + notq rBi + orq rBa, rBu + orq rBo, rBi + xorq rBo, rBu + xorq rBe, rBi + movq rBu, _bo(\oState) + movq rBi, _be(\oState) + .if \lastRound == 0 + movq rBi, rCe + .endif + + + movq _gu(\iState), rBe + xorq rDu, rBe + movq _ka(\iState), rBi + rolq $20, rBe + xorq rDa, rBi + rolq $3, rBi + movq _bo(\iState), rBa + movq rBe, rT1 + orq rBi, rT1 + xorq rDo, rBa + movq _me(\iState), rBo + movq _si(\iState), rBu + rolq $28, rBa + xorq rBa, rT1 + movq rT1, _ga(\oState) + .if \lastRound == 0 + xor rT1, rCa + .endif + + xorq rDe, rBo + rolq $45, rBo + movq rBi, rT1 + andq rBo, rT1 + xorq rBe, rT1 + movq rT1, _ge(\oState) + .if \lastRound == 0 + xorq rT1, rCe + .endif + + xorq rDi, rBu + rolq $61, rBu + movq rBu, rT1 + orq rBa, rT1 + xorq rBo, rT1 + movq rT1, _go(\oState) + + andq rBe, rBa + xorq rBu, rBa + movq rBa, _gu(\oState) + notq rBu + .if \lastRound == 0 + xorq rBa, rCu + .endif + + orq rBu, rBo + xorq rBi, rBo + movq rBo, _gi(\oState) + + + movq _be(\iState), rBa + movq _gi(\iState), rBe + movq _ko(\iState), rBi + movq _mu(\iState), rBo + movq _sa(\iState), rBu + xorq rDi, rBe + rolq $6, rBe + xorq rDo, rBi + rolq $25, rBi + movq rBe, rT1 + orq rBi, rT1 + xorq rDe, rBa + rolq $1, rBa + xorq rBa, rT1 + movq rT1, _ka(\oState) + .if \lastRound == 0 + xor rT1, rCa + .endif + + xorq rDu, rBo + rolq $8, rBo + movq rBi, rT1 + andq rBo, rT1 + xorq rBe, rT1 + movq rT1, _ke(\oState) + .if \lastRound == 0 + xorq rT1, rCe + .endif + + xorq rDa, rBu + rolq $18, rBu + notq rBo + movq rBo, rT1 + andq rBu, rT1 + xorq rBi, rT1 + movq rT1, _ki(\oState) + + movq rBu, rT1 + orq rBa, rT1 + xorq rBo, rT1 + movq rT1, _ko(\oState) + + andq rBe, rBa + xorq rBu, rBa + movq rBa, _ku(\oState) + .if \lastRound == 0 + xorq rBa, rCu + .endif + + movq _ga(\iState), rBe + xorq rDa, rBe + movq _ke(\iState), rBi + rolq $36, rBe + xorq rDe, rBi + movq _bu(\iState), rBa + rolq $10, rBi + movq rBe, rT1 + movq _mi(\iState), rBo + andq rBi, rT1 + xorq rDu, rBa + movq _so(\iState), rBu + rolq $27, rBa + xorq rBa, rT1 + movq rT1, _ma(\oState) + .if \lastRound == 0 + xor rT1, rCa + .endif + + xorq rDi, rBo + rolq $15, rBo + movq rBi, rT1 + orq rBo, rT1 + xorq rBe, rT1 + movq rT1, _me(\oState) + .if \lastRound == 0 + xorq rT1, rCe + .endif + + xorq rDo, rBu + rolq $56, rBu + notq rBo + movq rBo, rT1 + orq rBu, rT1 + xorq rBi, rT1 + movq rT1, _mi(\oState) + + orq rBa, rBe + xorq rBu, rBe + movq rBe, _mu(\oState) + + andq rBa, rBu + xorq rBo, rBu + movq rBu, _mo(\oState) + .if \lastRound == 0 + xorq rBe, rCu + .endif + + + movq _bi(\iState), rBa + movq _go(\iState), rBe + movq _ku(\iState), rBi + xorq rDi, rBa + movq _ma(\iState), rBo + rolq $62, rBa + xorq rDo, rBe + movq _se(\iState), rBu + rolq $55, rBe + + xorq rDu, rBi + movq rBa, rDu + xorq rDe, rBu + rolq $2, rBu + andq rBe, rDu + xorq rBu, rDu + movq rDu, _su(\oState) + + rolq $39, rBi + .if \lastRound == 0 + xorq rDu, rCu + .endif + notq rBe + xorq rDa, rBo + movq rBe, rDa + andq rBi, rDa + xorq rBa, rDa + movq rDa, _sa(\oState) + .if \lastRound == 0 + xor rDa, rCa + .endif + + rolq $41, rBo + movq rBi, rDe + orq rBo, rDe + xorq rBe, rDe + movq rDe, _se(\oState) + .if \lastRound == 0 + xorq rDe, rCe + .endif + + movq rBo, rDi + movq rBu, rDo + andq rBu, rDi + orq rBa, rDo + xorq rBi, rDi + xorq rBo, rDo + movq rDi, _si(\oState) + movq rDo, _so(\oState) + + .endm + +.macro mKeccakPermutation + + subq $8*25, %rsp + + movq _ba(rpState), rCa + movq _be(rpState), rCe + movq _bu(rpState), rCu + + xorq _ga(rpState), rCa + xorq _ge(rpState), rCe + xorq _gu(rpState), rCu + + xorq _ka(rpState), rCa + xorq _ke(rpState), rCe + xorq _ku(rpState), rCu + + xorq _ma(rpState), rCa + xorq _me(rpState), rCe + xorq _mu(rpState), rCu + + xorq _sa(rpState), rCa + xorq _se(rpState), rCe + movq _si(rpState), rDi + movq _so(rpState), rDo + xorq _su(rpState), rCu + + + mKeccakRound rpState, rpStack, 0x0000000000000001, 0 + mKeccakRound rpStack, rpState, 0x0000000000008082, 0 + mKeccakRound rpState, rpStack, 0x800000000000808a, 0 + mKeccakRound rpStack, rpState, 0x8000000080008000, 0 + mKeccakRound rpState, rpStack, 0x000000000000808b, 0 + mKeccakRound rpStack, rpState, 0x0000000080000001, 0 + + mKeccakRound rpState, rpStack, 0x8000000080008081, 0 + mKeccakRound rpStack, rpState, 0x8000000000008009, 0 + mKeccakRound rpState, rpStack, 0x000000000000008a, 0 + mKeccakRound rpStack, rpState, 0x0000000000000088, 0 + mKeccakRound rpState, rpStack, 0x0000000080008009, 0 + mKeccakRound rpStack, rpState, 0x000000008000000a, 0 + + mKeccakRound rpState, rpStack, 0x000000008000808b, 0 + mKeccakRound rpStack, rpState, 0x800000000000008b, 0 + mKeccakRound rpState, rpStack, 0x8000000000008089, 0 + mKeccakRound rpStack, rpState, 0x8000000000008003, 0 + mKeccakRound rpState, rpStack, 0x8000000000008002, 0 + mKeccakRound rpStack, rpState, 0x8000000000000080, 0 + + mKeccakRound rpState, rpStack, 0x000000000000800a, 0 + mKeccakRound rpStack, rpState, 0x800000008000000a, 0 + mKeccakRound rpState, rpStack, 0x8000000080008081, 0 + mKeccakRound rpStack, rpState, 0x8000000000008080, 0 + mKeccakRound rpState, rpStack, 0x0000000080000001, 0 + mKeccakRound rpStack, rpState, 0x8000000080008008, 1 + + addq $8*25, %rsp + + .endm + +.macro mPushRegs + + pushq %rbx + pushq %rbp + pushq %r12 + pushq %r13 + pushq %r14 + pushq %r15 + + .endm + + +.macro mPopRegs + + popq %r15 + popq %r14 + popq %r13 + popq %r12 + popq %rbp + popq %rbx + + .endm + + +.macro mXorState128 input, state, offset + .if UseSIMD == 0 + movq \offset(\input), %rax + movq \offset+8(\input), %rcx + xorq %rax, \offset(\state) + xorq %rcx, \offset+8(\state) + .else + movdqu \offset(\input), %xmm0 + pxor \offset(\state), %xmm0 + movdqu %xmm0, \offset(\state) + .endif + .endm + +.macro mXorState256 input, state, offset + .if UseSIMD == 0 + movq \offset(\input), %rax + movq \offset+8(\input), %r10 + movq \offset+16(\input), %rcx + movq \offset+24(\input), %r8 + xorq %rax, \offset(\state) + xorq %r10, \offset+8(\state) + xorq %rcx, \offset+16(\state) + xorq %r8, \offset+24(\state) + .else + movdqu \offset(\input), %xmm0 + pxor \offset(\state), %xmm0 + movdqu \offset+16(\input), %xmm1 + pxor \offset+16(\state), %xmm1 + movdqu %xmm0, \offset(\state) + movdqu %xmm1, \offset+16(\state) + .endif + .endm + +.macro mXorState512 input, state, offset + .if UseSIMD == 0 + mXorState256 \input, \state, \offset + mXorState256 \input, \state, \offset+32 + .else + movdqu \offset(\input), %xmm0 + movdqu \offset+16(\input), %xmm1 + pxor \offset(\state), %xmm0 + movdqu \offset+32(\input), %xmm2 + pxor \offset+16(\state), %xmm1 + movdqu %xmm0, \offset(\state) + movdqu \offset+48(\input), %xmm3 + pxor \offset+32(\state), %xmm2 + movdqu %xmm1, \offset+16(\state) + pxor \offset+48(\state), %xmm3 + movdqu %xmm2, \offset+32(\state) + movdqu %xmm3, \offset+48(\state) + .endif + .endm + +# ------------------------------------------------------------------------- + + .size KeccakPermutation, .-KeccakPermutation + .align 2 + .global KeccakPermutation + .type KeccakPermutation, %function +KeccakPermutation: + + mPushRegs + mKeccakPermutation + mPopRegs + ret + +# ------------------------------------------------------------------------- + + .size KeccakAbsorb576bits, .-KeccakAbsorb576bits + .align 2 + .global KeccakAbsorb576bits + .type KeccakAbsorb576bits, %function +KeccakAbsorb576bits: + + mXorState512 apInput, apState, 0 + movq 64(apInput), %rax + xorq %rax, 64(apState) + mPushRegs + mKeccakPermutation + mPopRegs + ret + +# ------------------------------------------------------------------------- + + .size KeccakAbsorb832bits, .-KeccakAbsorb832bits + .align 2 + .global KeccakAbsorb832bits + .type KeccakAbsorb832bits, %function +KeccakAbsorb832bits: + + mXorState512 apInput, apState, 0 + mXorState256 apInput, apState, 64 + movq 96(apInput), %rax + xorq %rax, 96(apState) + mPushRegs + mKeccakPermutation + mPopRegs + ret + +# ------------------------------------------------------------------------- + + .size KeccakAbsorb1024bits, .-KeccakAbsorb1024bits + .align 2 + .global KeccakAbsorb1024bits + .type KeccakAbsorb1024bits, %function +KeccakAbsorb1024bits: + + mXorState512 apInput, apState, 0 + mXorState512 apInput, apState, 64 + mPushRegs + mKeccakPermutation + mPopRegs + ret + +# ------------------------------------------------------------------------- + + .size KeccakAbsorb1088bits, .-KeccakAbsorb1088bits + .align 2 + .global KeccakAbsorb1088bits + .type KeccakAbsorb1088bits, %function +KeccakAbsorb1088bits: + + mXorState512 apInput, apState, 0 + mXorState512 apInput, apState, 64 + movq 128(apInput), %rax + xorq %rax, 128(apState) + mPushRegs + mKeccakPermutation + mPopRegs + ret + +# ------------------------------------------------------------------------- + + .size KeccakAbsorb1152bits, .-KeccakAbsorb1152bits + .align 2 + .global KeccakAbsorb1152bits + .type KeccakAbsorb1152bits, %function +KeccakAbsorb1152bits: + + mXorState512 apInput, apState, 0 + mXorState512 apInput, apState, 64 + mXorState128 apInput, apState, 128 + mPushRegs + mKeccakPermutation + mPopRegs + ret + +# ------------------------------------------------------------------------- + + .size KeccakAbsorb1344bits, .-KeccakAbsorb1344bits + .align 2 + .global KeccakAbsorb1344bits + .type KeccakAbsorb1344bits, %function +KeccakAbsorb1344bits: + + mXorState512 apInput, apState, 0 + mXorState512 apInput, apState, 64 + mXorState256 apInput, apState, 128 + movq 160(apInput), %rax + xorq %rax, 160(apState) + mPushRegs + mKeccakPermutation + mPopRegs + ret + +# ------------------------------------------------------------------------- + + .size KeccakAbsorb, .-KeccakAbsorb + .align 2 + .global KeccakAbsorb + .type KeccakAbsorb, %function +KeccakAbsorb: + + movq apState, xpState + + test $16, aNbrWords + jz xorInputToState8 + mXorState512 apInput, xpState, 0 + mXorState512 apInput, xpState, 64 + addq $128, apInput + addq $128, xpState + +xorInputToState8: + test $8, aNbrWords + jz xorInputToState4 + mXorState512 apInput, xpState, 0 + addq $64, apInput + addq $64, xpState + +xorInputToState4: + test $4, aNbrWords + jz xorInputToState2 + mXorState256 apInput, xpState, 0 + addq $32, apInput + addq $32, xpState + +xorInputToState2: + test $2, aNbrWords + jz xorInputToState1 + mXorState128 apInput, xpState, 0 + addq $16, apInput + addq $16, xpState + +xorInputToState1: + test $1, aNbrWords + jz xorInputToStateDone + movq (apInput), %rax + xorq %rax, (xpState) + +xorInputToStateDone: + + mPushRegs + mKeccakPermutation + mPopRegs + ret + +# ------------------------------------------------------------------------- + + .size KeccakInitializeState, .-KeccakInitializeState + .align 2 + .global KeccakInitializeState + .type KeccakInitializeState, %function +KeccakInitializeState: + xorq %rax, %rax + xorq %rcx, %rcx + notq %rcx + + .if UseSIMD == 0 + movq %rax, 0*8(apState) + movq %rcx, 1*8(apState) + movq %rcx, 2*8(apState) + movq %rax, 3*8(apState) + movq %rax, 4*8(apState) + movq %rax, 5*8(apState) + movq %rax, 6*8(apState) + movq %rax, 7*8(apState) + movq %rcx, 8*8(apState) + movq %rax, 9*8(apState) + movq %rax, 10*8(apState) + movq %rax, 11*8(apState) + movq %rcx, 12*8(apState) + movq %rax, 13*8(apState) + movq %rax, 14*8(apState) + movq %rax, 15*8(apState) + movq %rax, 16*8(apState) + movq %rcx, 17*8(apState) + movq %rax, 18*8(apState) + movq %rax, 19*8(apState) + movq %rcx, 20*8(apState) + movq %rax, 21*8(apState) + movq %rax, 22*8(apState) + movq %rax, 23*8(apState) + movq %rax, 24*8(apState) + .else + pxor %xmm0, %xmm0 + + movq %rax, 0*8(apState) + movq %rcx, 1*8(apState) + movq %rcx, 2*8(apState) + movq %rax, 3*8(apState) + movdqu %xmm0, 4*8(apState) + movdqu %xmm0, 6*8(apState) + movq %rcx, 8*8(apState) + movq %rax, 9*8(apState) + movdqu %xmm0, 10*8(apState) + movq %rcx, 12*8(apState) + movq %rax, 13*8(apState) + movdqu %xmm0, 14*8(apState) + movq %rax, 16*8(apState) + movq %rcx, 17*8(apState) + movdqu %xmm0, 18*8(apState) + movq %rcx, 20*8(apState) + movq %rax, 21*8(apState) + movdqu %xmm0, 22*8(apState) + movq %rax, 24*8(apState) + .endif + ret + +# ------------------------------------------------------------------------- + + .size KeccakExtract1024bits, .-KeccakExtract1024bits + .align 2 + .global KeccakExtract1024bits + .type KeccakExtract1024bits, %function +KeccakExtract1024bits: + + movq 0*8(apState), %rax + movq 1*8(apState), %rcx + movq 2*8(apState), %rdx + movq 3*8(apState), %r8 + notq %rcx + notq %rdx + movq %rax, 0*8(%rsi) + movq %rcx, 1*8(%rsi) + movq %rdx, 2*8(%rsi) + movq %r8, 3*8(%rsi) + + movq 4*8(apState), %rax + movq 5*8(apState), %rcx + movq 6*8(apState), %rdx + movq 7*8(apState), %r8 + movq %rax, 4*8(%rsi) + movq %rcx, 5*8(%rsi) + movq %rdx, 6*8(%rsi) + movq %r8, 7*8(%rsi) + + movq 8*8(apState), %rax + movq 9*8(apState), %rcx + movq 10*8(apState), %rdx + movq 11*8(apState), %r8 + notq %rax + movq %rax, 8*8(%rsi) + movq %rcx, 9*8(%rsi) + movq %rdx, 10*8(%rsi) + movq %r8, 11*8(%rsi) + + movq 12*8(apState), %rax + movq 13*8(apState), %rcx + movq 14*8(apState), %rdx + movq 15*8(apState), %r8 + notq %rax + movq %rax, 12*8(%rsi) + movq %rcx, 13*8(%rsi) + movq %rdx, 14*8(%rsi) + movq %r8, 15*8(%rsi) + ret + diff --git a/c_src/KeccakF-1600-x86-64-shld-gas.s b/c_src/KeccakF-1600-x86-64-shld-gas.s new file mode 100755 index 0000000..bc84762 --- /dev/null +++ b/c_src/KeccakF-1600-x86-64-shld-gas.s @@ -0,0 +1,766 @@ +# +# The Keccak sponge function, designed by Guido Bertoni, Joan Daemen, +# Michaël Peeters and Gilles Van Assche. For more information, feedback or +# questions, please refer to our website: http://keccak.noekeon.org/ +# +# Implementation by Ronny Van Keer, +# hereby denoted as "the implementer". +# +# To the extent possible under law, the implementer has waived all copyright +# and related or neighboring rights to the source code in this file. +# http://creativecommons.org/publicdomain/zero/1.0/ +# + + .text + + +#// --- defines + +.equ UseSIMD, 1 + + +.equ _ba, 0*8 +.equ _be, 1*8 +.equ _bi, 2*8 +.equ _bo, 3*8 +.equ _bu, 4*8 +.equ _ga, 5*8 +.equ _ge, 6*8 +.equ _gi, 7*8 +.equ _go, 8*8 +.equ _gu, 9*8 +.equ _ka, 10*8 +.equ _ke, 11*8 +.equ _ki, 12*8 +.equ _ko, 13*8 +.equ _ku, 14*8 +.equ _ma, 15*8 +.equ _me, 16*8 +.equ _mi, 17*8 +.equ _mo, 18*8 +.equ _mu, 19*8 +.equ _sa, 20*8 +.equ _se, 21*8 +.equ _si, 22*8 +.equ _so, 23*8 +.equ _su, 24*8 + + +# arguments +.equ apState, %rdi +.equ apInput, %rsi +.equ aNbrWords, %rdx + +# xor input into state section +.equ xpState, %r9 + +# round vars +.equ rT1, %rax +.equ rpState, %rdi +.equ rpStack, %rsp + +.equ rDa, %rbx +.equ rDe, %rcx +.equ rDi, %rdx +.equ rDo, %r8 +.equ rDu, %r9 + +.equ rBa, %r10 +.equ rBe, %r11 +.equ rBi, %r12 +.equ rBo, %r13 +.equ rBu, %r14 + +.equ rCa, %rsi +.equ rCe, %rbp +.equ rCi, rBi +.equ rCo, rBo +.equ rCu, %r15 + +.macro mKeccakRound iState, oState, rc, lastRound + + movq rCe, rDa + shld $1, rDa, rDa + + movq _bi(\iState), rCi + xorq _gi(\iState), rDi + xorq _ki(\iState), rCi + xorq rCu, rDa + xorq _mi(\iState), rDi + xorq rDi, rCi + + movq rCi, rDe + shld $1, rDe, rDe + + movq _bo(\iState), rCo + xorq _go(\iState), rDo + xorq _ko(\iState), rCo + xorq rCa, rDe + xorq _mo(\iState), rDo + xorq rDo, rCo + + movq rCo, rDi + shld $1, rDi, rDi + + movq rCu, rDo + xorq rCe, rDi + shld $1, rDo, rDo + + movq rCa, rDu + xorq rCi, rDo + shld $1, rDu, rDu + + movq _ba(\iState), rBa + movq _ge(\iState), rBe + xorq rCo, rDu + movq _ki(\iState), rBi + movq _mo(\iState), rBo + movq _su(\iState), rBu + xorq rDe, rBe + shld $44, rBe, rBe + xorq rDi, rBi + xorq rDa, rBa + shld $43, rBi, rBi + + movq rBe, rCa + movq $\rc, rT1 + orq rBi, rCa + xorq rBa, rT1 + xorq rT1, rCa + movq rCa, _ba(\oState) + + xorq rDu, rBu + shld $14, rBu, rBu + movq rBa, rCu + andq rBe, rCu + xorq rBu, rCu + movq rCu, _bu(\oState) + + xorq rDo, rBo + shld $21, rBo, rBo + movq rBo, rT1 + andq rBu, rT1 + xorq rBi, rT1 + movq rT1, _bi(\oState) + + notq rBi + orq rBa, rBu + orq rBo, rBi + xorq rBo, rBu + xorq rBe, rBi + movq rBu, _bo(\oState) + movq rBi, _be(\oState) + .if \lastRound == 0 + movq rBi, rCe + .endif + + + movq _gu(\iState), rBe + xorq rDu, rBe + movq _ka(\iState), rBi + shld $20, rBe, rBe + xorq rDa, rBi + shld $3, rBi, rBi + movq _bo(\iState), rBa + movq rBe, rT1 + orq rBi, rT1 + xorq rDo, rBa + movq _me(\iState), rBo + movq _si(\iState), rBu + shld $28, rBa, rBa + xorq rBa, rT1 + movq rT1, _ga(\oState) + .if \lastRound == 0 + xor rT1, rCa + .endif + + xorq rDe, rBo + shld $45, rBo, rBo + movq rBi, rT1 + andq rBo, rT1 + xorq rBe, rT1 + movq rT1, _ge(\oState) + .if \lastRound == 0 + xorq rT1, rCe + .endif + + xorq rDi, rBu + shld $61, rBu, rBu + movq rBu, rT1 + orq rBa, rT1 + xorq rBo, rT1 + movq rT1, _go(\oState) + + andq rBe, rBa + xorq rBu, rBa + movq rBa, _gu(\oState) + notq rBu + .if \lastRound == 0 + xorq rBa, rCu + .endif + + orq rBu, rBo + xorq rBi, rBo + movq rBo, _gi(\oState) + + + movq _be(\iState), rBa + movq _gi(\iState), rBe + movq _ko(\iState), rBi + movq _mu(\iState), rBo + movq _sa(\iState), rBu + xorq rDi, rBe + shld $6, rBe, rBe + xorq rDo, rBi + shld $25, rBi, rBi + movq rBe, rT1 + orq rBi, rT1 + xorq rDe, rBa + shld $1, rBa, rBa + xorq rBa, rT1 + movq rT1, _ka(\oState) + .if \lastRound == 0 + xor rT1, rCa + .endif + + xorq rDu, rBo + shld $8, rBo, rBo + movq rBi, rT1 + andq rBo, rT1 + xorq rBe, rT1 + movq rT1, _ke(\oState) + .if \lastRound == 0 + xorq rT1, rCe + .endif + + xorq rDa, rBu + shld $18, rBu, rBu + notq rBo + movq rBo, rT1 + andq rBu, rT1 + xorq rBi, rT1 + movq rT1, _ki(\oState) + + movq rBu, rT1 + orq rBa, rT1 + xorq rBo, rT1 + movq rT1, _ko(\oState) + + andq rBe, rBa + xorq rBu, rBa + movq rBa, _ku(\oState) + .if \lastRound == 0 + xorq rBa, rCu + .endif + + movq _ga(\iState), rBe + xorq rDa, rBe + movq _ke(\iState), rBi + shld $36, rBe, rBe + xorq rDe, rBi + movq _bu(\iState), rBa + shld $10, rBi, rBi + movq rBe, rT1 + movq _mi(\iState), rBo + andq rBi, rT1 + xorq rDu, rBa + movq _so(\iState), rBu + shld $27, rBa, rBa + xorq rBa, rT1 + movq rT1, _ma(\oState) + .if \lastRound == 0 + xor rT1, rCa + .endif + + xorq rDi, rBo + shld $15, rBo, rBo + movq rBi, rT1 + orq rBo, rT1 + xorq rBe, rT1 + movq rT1, _me(\oState) + .if \lastRound == 0 + xorq rT1, rCe + .endif + + xorq rDo, rBu + shld $56, rBu, rBu + notq rBo + movq rBo, rT1 + orq rBu, rT1 + xorq rBi, rT1 + movq rT1, _mi(\oState) + + orq rBa, rBe + xorq rBu, rBe + movq rBe, _mu(\oState) + + andq rBa, rBu + xorq rBo, rBu + movq rBu, _mo(\oState) + .if \lastRound == 0 + xorq rBe, rCu + .endif + + + movq _bi(\iState), rBa + movq _go(\iState), rBe + movq _ku(\iState), rBi + xorq rDi, rBa + movq _ma(\iState), rBo + shld $62, rBa, rBa + xorq rDo, rBe + movq _se(\iState), rBu + shld $55, rBe, rBe + + xorq rDu, rBi + movq rBa, rDu + xorq rDe, rBu + shld $2, rBu, rBu + andq rBe, rDu + xorq rBu, rDu + movq rDu, _su(\oState) + + shld $39, rBi, rBi + .if \lastRound == 0 + xorq rDu, rCu + .endif + notq rBe + xorq rDa, rBo + movq rBe, rDa + andq rBi, rDa + xorq rBa, rDa + movq rDa, _sa(\oState) + .if \lastRound == 0 + xor rDa, rCa + .endif + + shld $41, rBo, rBo + movq rBi, rDe + orq rBo, rDe + xorq rBe, rDe + movq rDe, _se(\oState) + .if \lastRound == 0 + xorq rDe, rCe + .endif + + movq rBo, rDi + movq rBu, rDo + andq rBu, rDi + orq rBa, rDo + xorq rBi, rDi + xorq rBo, rDo + movq rDi, _si(\oState) + movq rDo, _so(\oState) + + .endm + +.macro mKeccakPermutation + + subq $8*25, %rsp + + movq _ba(rpState), rCa + movq _be(rpState), rCe + movq _bu(rpState), rCu + + xorq _ga(rpState), rCa + xorq _ge(rpState), rCe + xorq _gu(rpState), rCu + + xorq _ka(rpState), rCa + xorq _ke(rpState), rCe + xorq _ku(rpState), rCu + + xorq _ma(rpState), rCa + xorq _me(rpState), rCe + xorq _mu(rpState), rCu + + xorq _sa(rpState), rCa + xorq _se(rpState), rCe + movq _si(rpState), rDi + movq _so(rpState), rDo + xorq _su(rpState), rCu + + + mKeccakRound rpState, rpStack, 0x0000000000000001, 0 + mKeccakRound rpStack, rpState, 0x0000000000008082, 0 + mKeccakRound rpState, rpStack, 0x800000000000808a, 0 + mKeccakRound rpStack, rpState, 0x8000000080008000, 0 + mKeccakRound rpState, rpStack, 0x000000000000808b, 0 + mKeccakRound rpStack, rpState, 0x0000000080000001, 0 + + mKeccakRound rpState, rpStack, 0x8000000080008081, 0 + mKeccakRound rpStack, rpState, 0x8000000000008009, 0 + mKeccakRound rpState, rpStack, 0x000000000000008a, 0 + mKeccakRound rpStack, rpState, 0x0000000000000088, 0 + mKeccakRound rpState, rpStack, 0x0000000080008009, 0 + mKeccakRound rpStack, rpState, 0x000000008000000a, 0 + + mKeccakRound rpState, rpStack, 0x000000008000808b, 0 + mKeccakRound rpStack, rpState, 0x800000000000008b, 0 + mKeccakRound rpState, rpStack, 0x8000000000008089, 0 + mKeccakRound rpStack, rpState, 0x8000000000008003, 0 + mKeccakRound rpState, rpStack, 0x8000000000008002, 0 + mKeccakRound rpStack, rpState, 0x8000000000000080, 0 + + mKeccakRound rpState, rpStack, 0x000000000000800a, 0 + mKeccakRound rpStack, rpState, 0x800000008000000a, 0 + mKeccakRound rpState, rpStack, 0x8000000080008081, 0 + mKeccakRound rpStack, rpState, 0x8000000000008080, 0 + mKeccakRound rpState, rpStack, 0x0000000080000001, 0 + mKeccakRound rpStack, rpState, 0x8000000080008008, 1 + + addq $8*25, %rsp + + .endm + +.macro mPushRegs + + pushq %rbx + pushq %rbp + pushq %r12 + pushq %r13 + pushq %r14 + pushq %r15 + + .endm + + +.macro mPopRegs + + popq %r15 + popq %r14 + popq %r13 + popq %r12 + popq %rbp + popq %rbx + + .endm + + +.macro mXorState128 input, state, offset + .if UseSIMD == 0 + movq \offset(\input), %rax + movq \offset+8(\input), %rcx + xorq %rax, \offset(\state) + xorq %rcx, \offset+8(\state) + .else + movdqu \offset(\input), %xmm0 + pxor \offset(\state), %xmm0 + movdqu %xmm0, \offset(\state) + .endif + .endm + +.macro mXorState256 input, state, offset + .if UseSIMD == 0 + movq \offset(\input), %rax + movq \offset+8(\input), %r10 + movq \offset+16(\input), %rcx + movq \offset+24(\input), %r8 + xorq %rax, \offset(\state) + xorq %r10, \offset+8(\state) + xorq %rcx, \offset+16(\state) + xorq %r8, \offset+24(\state) + .else + movdqu \offset(\input), %xmm0 + pxor \offset(\state), %xmm0 + movdqu \offset+16(\input), %xmm1 + pxor \offset+16(\state), %xmm1 + movdqu %xmm0, \offset(\state) + movdqu %xmm1, \offset+16(\state) + .endif + .endm + +.macro mXorState512 input, state, offset + .if UseSIMD == 0 + mXorState256 \input, \state, \offset + mXorState256 \input, \state, \offset+32 + .else + movdqu \offset(\input), %xmm0 + movdqu \offset+16(\input), %xmm1 + pxor \offset(\state), %xmm0 + movdqu \offset+32(\input), %xmm2 + pxor \offset+16(\state), %xmm1 + movdqu %xmm0, \offset(\state) + movdqu \offset+48(\input), %xmm3 + pxor \offset+32(\state), %xmm2 + movdqu %xmm1, \offset+16(\state) + pxor \offset+48(\state), %xmm3 + movdqu %xmm2, \offset+32(\state) + movdqu %xmm3, \offset+48(\state) + .endif + .endm + +# ------------------------------------------------------------------------- + + .size KeccakPermutation, .-KeccakPermutation + .align 2 + .global KeccakPermutation + .type KeccakPermutation, %function +KeccakPermutation: + + mPushRegs + mKeccakPermutation + mPopRegs + ret + +# ------------------------------------------------------------------------- + + .size KeccakAbsorb576bits, .-KeccakAbsorb576bits + .align 2 + .global KeccakAbsorb576bits + .type KeccakAbsorb576bits, %function +KeccakAbsorb576bits: + + mXorState512 apInput, apState, 0 + movq 64(apInput), %rax + xorq %rax, 64(apState) + mPushRegs + mKeccakPermutation + mPopRegs + ret + +# ------------------------------------------------------------------------- + + .size KeccakAbsorb832bits, .-KeccakAbsorb832bits + .align 2 + .global KeccakAbsorb832bits + .type KeccakAbsorb832bits, %function +KeccakAbsorb832bits: + + mXorState512 apInput, apState, 0 + mXorState256 apInput, apState, 64 + movq 96(apInput), %rax + xorq %rax, 96(apState) + mPushRegs + mKeccakPermutation + mPopRegs + ret + +# ------------------------------------------------------------------------- + + .size KeccakAbsorb1024bits, .-KeccakAbsorb1024bits + .align 2 + .global KeccakAbsorb1024bits + .type KeccakAbsorb1024bits, %function +KeccakAbsorb1024bits: + + mXorState512 apInput, apState, 0 + mXorState512 apInput, apState, 64 + mPushRegs + mKeccakPermutation + mPopRegs + ret + +# ------------------------------------------------------------------------- + + .size KeccakAbsorb1088bits, .-KeccakAbsorb1088bits + .align 2 + .global KeccakAbsorb1088bits + .type KeccakAbsorb1088bits, %function +KeccakAbsorb1088bits: + + mXorState512 apInput, apState, 0 + mXorState512 apInput, apState, 64 + movq 128(apInput), %rax + xorq %rax, 128(apState) + mPushRegs + mKeccakPermutation + mPopRegs + ret + +# ------------------------------------------------------------------------- + + .size KeccakAbsorb1152bits, .-KeccakAbsorb1152bits + .align 2 + .global KeccakAbsorb1152bits + .type KeccakAbsorb1152bits, %function +KeccakAbsorb1152bits: + + mXorState512 apInput, apState, 0 + mXorState512 apInput, apState, 64 + mXorState128 apInput, apState, 128 + mPushRegs + mKeccakPermutation + mPopRegs + ret + +# ------------------------------------------------------------------------- + + .size KeccakAbsorb1344bits, .-KeccakAbsorb1344bits + .align 2 + .global KeccakAbsorb1344bits + .type KeccakAbsorb1344bits, %function +KeccakAbsorb1344bits: + + mXorState512 apInput, apState, 0 + mXorState512 apInput, apState, 64 + mXorState256 apInput, apState, 128 + movq 160(apInput), %rax + xorq %rax, 160(apState) + mPushRegs + mKeccakPermutation + mPopRegs + ret + +# ------------------------------------------------------------------------- + + .size KeccakAbsorb, .-KeccakAbsorb + .align 2 + .global KeccakAbsorb + .type KeccakAbsorb, %function +KeccakAbsorb: + + movq apState, xpState + + test $16, aNbrWords + jz xorInputToState8 + mXorState512 apInput, xpState, 0 + mXorState512 apInput, xpState, 64 + addq $128, apInput + addq $128, xpState + +xorInputToState8: + test $8, aNbrWords + jz xorInputToState4 + mXorState512 apInput, xpState, 0 + addq $64, apInput + addq $64, xpState + +xorInputToState4: + test $4, aNbrWords + jz xorInputToState2 + mXorState256 apInput, xpState, 0 + addq $32, apInput + addq $32, xpState + +xorInputToState2: + test $2, aNbrWords + jz xorInputToState1 + mXorState128 apInput, xpState, 0 + addq $16, apInput + addq $16, xpState + +xorInputToState1: + test $1, aNbrWords + jz xorInputToStateDone + movq (apInput), %rax + xorq %rax, (xpState) + +xorInputToStateDone: + + mPushRegs + mKeccakPermutation + mPopRegs + ret + +# ------------------------------------------------------------------------- + + .size KeccakInitializeState, .-KeccakInitializeState + .align 2 + .global KeccakInitializeState + .type KeccakInitializeState, %function +KeccakInitializeState: + xorq %rax, %rax + xorq %rcx, %rcx + notq %rcx + + .if UseSIMD == 0 + movq %rax, 0*8(apState) + movq %rcx, 1*8(apState) + movq %rcx, 2*8(apState) + movq %rax, 3*8(apState) + movq %rax, 4*8(apState) + movq %rax, 5*8(apState) + movq %rax, 6*8(apState) + movq %rax, 7*8(apState) + movq %rcx, 8*8(apState) + movq %rax, 9*8(apState) + movq %rax, 10*8(apState) + movq %rax, 11*8(apState) + movq %rcx, 12*8(apState) + movq %rax, 13*8(apState) + movq %rax, 14*8(apState) + movq %rax, 15*8(apState) + movq %rax, 16*8(apState) + movq %rcx, 17*8(apState) + movq %rax, 18*8(apState) + movq %rax, 19*8(apState) + movq %rcx, 20*8(apState) + movq %rax, 21*8(apState) + movq %rax, 22*8(apState) + movq %rax, 23*8(apState) + movq %rax, 24*8(apState) + .else + pxor %xmm0, %xmm0 + + movq %rax, 0*8(apState) + movq %rcx, 1*8(apState) + movq %rcx, 2*8(apState) + movq %rax, 3*8(apState) + movdqu %xmm0, 4*8(apState) + movdqu %xmm0, 6*8(apState) + movq %rcx, 8*8(apState) + movq %rax, 9*8(apState) + movdqu %xmm0, 10*8(apState) + movq %rcx, 12*8(apState) + movq %rax, 13*8(apState) + movdqu %xmm0, 14*8(apState) + movq %rax, 16*8(apState) + movq %rcx, 17*8(apState) + movdqu %xmm0, 18*8(apState) + movq %rcx, 20*8(apState) + movq %rax, 21*8(apState) + movdqu %xmm0, 22*8(apState) + movq %rax, 24*8(apState) + .endif + ret + +# ------------------------------------------------------------------------- + + .size KeccakExtract1024bits, .-KeccakExtract1024bits + .align 2 + .global KeccakExtract1024bits + .type KeccakExtract1024bits, %function +KeccakExtract1024bits: + + movq 0*8(apState), %rax + movq 1*8(apState), %rcx + movq 2*8(apState), %rdx + movq 3*8(apState), %r8 + notq %rcx + notq %rdx + movq %rax, 0*8(%rsi) + movq %rcx, 1*8(%rsi) + movq %rdx, 2*8(%rsi) + movq %r8, 3*8(%rsi) + + movq 4*8(apState), %rax + movq 5*8(apState), %rcx + movq 6*8(apState), %rdx + movq 7*8(apState), %r8 + movq %rax, 4*8(%rsi) + movq %rcx, 5*8(%rsi) + movq %rdx, 6*8(%rsi) + movq %r8, 7*8(%rsi) + + movq 8*8(apState), %rax + movq 9*8(apState), %rcx + movq 10*8(apState), %rdx + movq 11*8(apState), %r8 + notq %rax + movq %rax, 8*8(%rsi) + movq %rcx, 9*8(%rsi) + movq %rdx, 10*8(%rsi) + movq %r8, 11*8(%rsi) + + movq 12*8(apState), %rax + movq 13*8(apState), %rcx + movq 14*8(apState), %rdx + movq 15*8(apState), %r8 + notq %rax + movq %rax, 12*8(%rsi) + movq %rcx, 13*8(%rsi) + movq %rdx, 14*8(%rsi) + movq %r8, 15*8(%rsi) + ret + diff --git a/c_src/KeccakF-1600-xop.macros b/c_src/KeccakF-1600-xop.macros new file mode 100755 index 0000000..e5d6514 --- /dev/null +++ b/c_src/KeccakF-1600-xop.macros @@ -0,0 +1,573 @@ +/* +The Keccak sponge function, designed by Guido Bertoni, Joan Daemen, +Michaël Peeters and Gilles Van Assche. For more information, feedback or +questions, please refer to our website: http://keccak.noekeon.org/ + +Implementation by the designers, +hereby denoted as "the implementer". + +To the extent possible under law, the implementer has waived all copyright +and related or neighboring rights to the source code in this file. +http://creativecommons.org/publicdomain/zero/1.0/ +*/ + +#define declareABCDE \ + V128 Abage, Abegi, Abigo, Abogu, Abuga; \ + V128 Akame, Akemi, Akimo, Akomu, Akuma; \ + V128 Abae, Abio, Agae, Agio, Akae, Akio, Amae, Amio; \ + V64 Aba, Abe, Abi, Abo, Abu; \ + V64 Aga, Age, Agi, Ago, Agu; \ + V64 Aka, Ake, Aki, Ako, Aku; \ + V64 Ama, Ame, Ami, Amo, Amu; \ + V128 Asase, Asiso; \ + V64 Asu; \ + V128 Bbage, Bbegi, Bbigo, Bbogu, Bbuga; \ + V128 Bkame, Bkemi, Bkimo, Bkomu, Bkuma; \ + V128 Bsase, Bsesi, Bsiso, Bsosu, Bsusa; \ + V128 Cae, Cei, Cio, Cou, Cua; \ + V128 Dau, Dea, Die, Doi, Duo; \ + V128 Dua, Dae, Dei, Dio, Dou; \ + V128 Ebage, Ebegi, Ebigo, Ebogu, Ebuga; \ + V128 Ekame, Ekemi, Ekimo, Ekomu, Ekuma; \ + V128 Esase, Esiso; \ + V64 Esu; \ + V128 Zero; + +#define prepareTheta + +#define computeD \ + Cua = GET64LOLO(Cua, Cae); \ + Dei = XOR128(Cae, ROL6464same(Cio, 1)); \ + Dou = XOR128(Cio, ROL6464same(Cua, 1)); \ + Cei = GET64HILO(Cae, Cio); \ + Dae = XOR128(Cua, ROL6464same(Cei, 1)); \ + Dau = GET64LOHI(Dae, Dou); \ + Dea = SWAP64(Dae); \ + Die = SWAP64(Dei); \ + Doi = GET64LOLO(Dou, Die); \ + Duo = SWAP64(Dou); + +// --- Theta Rho Pi Chi Iota Prepare-theta +// --- 64-bit lanes mapped to 64-bit and 128-bit words +#define thetaRhoPiChiIotaPrepareTheta(i, A, E) \ + computeD \ + \ + Bbage = XOR128(GET64LOHI(A##bage, A##bogu), Dau); \ + Bbage = ROL6464(Bbage, 0, 20); \ + Bbegi = XOR128(GET64HILO(A##bage, A##kame), Dea); \ + Bbegi = ROL6464(Bbegi, 44, 3); \ + Bbigo = XOR128(GET64LOHI(A##kimo, A##kame), Die); \ + Bbigo = ROL6464(Bbigo, 43, 45); \ + E##bage = XOR128(Bbage, ANDnu128(Bbegi, Bbigo)); \ + XOReq128(E##bage, CONST64(KeccakF1600RoundConstants[i])); \ + Cae = E##bage; \ + Bbogu = XOR128(GET64HILO(A##kimo, A##siso), Doi); \ + Bbogu = ROL6464(Bbogu, 21, 61); \ + E##begi = XOR128(Bbegi, ANDnu128(Bbigo, Bbogu)); \ + Cei = E##begi; \ + Bbuga = XOR128(GET64LOLO(A##su, A##bogu), Duo); \ + Bbuga = ROL6464(Bbuga, 14, 28); \ + E##bigo = XOR128(Bbigo, ANDnu128(Bbogu, Bbuga)); \ + Cio = E##bigo; \ + E##bogu = XOR128(Bbogu, ANDnu128(Bbuga, Bbage)); \ + Cou = E##bogu; \ + E##buga = XOR128(Bbuga, ANDnu128(Bbage, Bbegi)); \ + Cua = E##buga; \ +\ + Bkame = XOR128(GET64LOHI(A##begi, A##buga), Dea); \ + Bkame = ROL6464(Bkame, 1, 36); \ + Bkemi = XOR128(GET64HILO(A##begi, A##kemi), Die); \ + Bkemi = ROL6464(Bkemi, 6, 10); \ + Bkimo = XOR128(GET64LOHI(A##komu, A##kemi), Doi); \ + Bkimo = ROL6464(Bkimo, 25, 15); \ + E##kame = XOR128(Bkame, ANDnu128(Bkemi, Bkimo)); \ + XOReq128(Cae, E##kame); \ + Bkomu = XOR128(GET64HIHI(A##komu, A##siso), Duo); \ + Bkomu = ROL6464(Bkomu, 8, 56); \ + E##kemi = XOR128(Bkemi, ANDnu128(Bkimo, Bkomu)); \ + XOReq128(Cei, E##kemi); \ + Bkuma = XOR128(GET64LOLO(A##sase, A##buga), Dau); \ + Bkuma = ROL6464(Bkuma, 18, 27); \ + E##kimo = XOR128(Bkimo, ANDnu128(Bkomu, Bkuma)); \ + XOReq128(Cio, E##kimo); \ + E##komu = XOR128(Bkomu, ANDnu128(Bkuma, Bkame)); \ + XOReq128(Cou, E##komu); \ + E##kuma = XOR128(Bkuma, ANDnu128(Bkame, Bkemi)); \ + XOReq128(Cua, E##kuma); \ +\ + Bsase = XOR128(A##bigo, SWAP64(Doi)); \ + Bsase = ROL6464(Bsase, 62, 55); \ + Bsiso = XOR128(A##kuma, SWAP64(Dau)); \ + Bsiso = ROL6464(Bsiso, 39, 41); \ + Bsusa = XOR64(COPY64HI2LO(A##sase), Dei); \ + Bsusa = ROL6464same(Bsusa, 2); \ + Bsusa = GET64LOLO(Bsusa, Bsase); \ + Bsesi = GET64HILO(Bsase, Bsiso); \ + Bsosu = GET64HILO(Bsiso, Bsusa); \ + E##sase = XOR128(Bsase, ANDnu128(Bsesi, Bsiso)); \ + XOReq128(Cae, E##sase); \ + E##siso = XOR128(Bsiso, ANDnu128(Bsosu, Bsusa)); \ + XOReq128(Cio, E##siso); \ + E##su = GET64LOLO(XOR128(Bsusa, ANDnu128(Bsase, Bsesi)), Zero); \ + XOReq128(Cua, E##su); \ +\ + Zero = ZERO128(); \ + XOReq128(Cae, GET64HIHI(Cua, Zero)); \ + XOReq128(Cae, GET64LOLO(Zero, Cei)); \ + XOReq128(Cio, GET64HIHI(Cei, Zero)); \ + XOReq128(Cio, GET64LOLO(Zero, Cou)); \ + XOReq128(Cua, GET64HIHI(Cou, Zero)); \ + +// --- Theta Rho Pi Chi Iota +// --- 64-bit lanes mapped to 64-bit and 128-bit words +#define thetaRhoPiChiIota(i, A, E) thetaRhoPiChiIotaPrepareTheta(i, A, E) + +const UINT64 KeccakF1600RoundConstants[24] = { + 0x0000000000000001ULL, + 0x0000000000008082ULL, + 0x800000000000808aULL, + 0x8000000080008000ULL, + 0x000000000000808bULL, + 0x0000000080000001ULL, + 0x8000000080008081ULL, + 0x8000000000008009ULL, + 0x000000000000008aULL, + 0x0000000000000088ULL, + 0x0000000080008009ULL, + 0x000000008000000aULL, + 0x000000008000808bULL, + 0x800000000000008bULL, + 0x8000000000008089ULL, + 0x8000000000008003ULL, + 0x8000000000008002ULL, + 0x8000000000000080ULL, + 0x000000000000800aULL, + 0x800000008000000aULL, + 0x8000000080008081ULL, + 0x8000000000008080ULL, + 0x0000000080000001ULL, + 0x8000000080008008ULL }; + +#define copyFromStateAndXor576bits(X, state, input) \ + X##bae = XOR128(LOAD128(state[ 0]), LOAD128u(input[ 0])); \ + X##ba = X##bae; \ + X##be = GET64HIHI(X##bae, X##bae); \ + Cae = X##bae; \ + X##bio = XOR128(LOAD128(state[ 2]), LOAD128u(input[ 2])); \ + X##bi = X##bio; \ + X##bo = GET64HIHI(X##bio, X##bio); \ + Cio = X##bio; \ + X##bu = XOR64(LOAD64(state[ 4]), LOAD64(input[ 4])); \ + Cua = X##bu; \ + X##gae = XOR128(LOAD128u(state[ 5]), LOAD128u(input[ 5])); \ + X##ga = X##gae; \ + X##buga = GET64LOLO(X##bu, X##ga); \ + X##ge = GET64HIHI(X##gae, X##gae); \ + X##bage = GET64LOLO(X##ba, X##ge); \ + XOReq128(Cae, X##gae); \ + X##gio = XOR128(LOAD128u(state[ 7]), LOAD128u(input[ 7])); \ + X##gi = X##gio; \ + X##begi = GET64LOLO(X##be, X##gi); \ + X##go = GET64HIHI(X##gio, X##gio); \ + X##bigo = GET64LOLO(X##bi, X##go); \ + XOReq128(Cio, X##gio); \ + X##gu = LOAD64(state[ 9]); \ + X##bogu = GET64LOLO(X##bo, X##gu); \ + XOReq64(Cua, X##gu); \ + X##kae = LOAD128(state[10]); \ + X##ka = X##kae; \ + X##ke = GET64HIHI(X##kae, X##kae); \ + XOReq128(Cae, X##kae); \ + X##kio = LOAD128(state[12]); \ + X##ki = X##kio; \ + X##ko = GET64HIHI(X##kio, X##kio); \ + XOReq128(Cio, X##kio); \ + X##kuma = LOAD128(state[14]); \ + XOReq64(Cua, X##kuma); \ + X##me = LOAD64(state[16]); \ + X##kame = GET64LOLO(X##ka, X##me); \ + XOReq128(Cae, GET64HIHI(X##kuma, X##kame)); \ + X##mio = LOAD128u(state[17]); \ + X##mi = X##mio; \ + X##kemi = GET64LOLO(X##ke, X##mi); \ + X##mo = GET64HIHI(X##mio, X##mio); \ + X##kimo = GET64LOLO(X##ki, X##mo); \ + XOReq128(Cio, X##mio); \ + X##mu = LOAD64(state[19]); \ + X##komu = GET64LOLO(X##ko, X##mu); \ + XOReq64(Cua, X##mu); \ + X##sase = LOAD128(state[20]); \ + XOReq128(Cae, X##sase); \ + X##siso = LOAD128(state[22]); \ + XOReq128(Cio, X##siso); \ + X##su = LOAD64(state[24]); \ + XOReq64(Cua, X##su); \ + +#define copyFromStateAndXor832bits(X, state, input) \ + X##bae = XOR128(LOAD128(state[ 0]), LOAD128u(input[ 0])); \ + X##ba = X##bae; \ + X##be = GET64HIHI(X##bae, X##bae); \ + Cae = X##bae; \ + X##bio = XOR128(LOAD128(state[ 2]), LOAD128u(input[ 2])); \ + X##bi = X##bio; \ + X##bo = GET64HIHI(X##bio, X##bio); \ + Cio = X##bio; \ + X##bu = XOR64(LOAD64(state[ 4]), LOAD64(input[ 4])); \ + Cua = X##bu; \ + X##gae = XOR128(LOAD128u(state[ 5]), LOAD128u(input[ 5])); \ + X##ga = X##gae; \ + X##buga = GET64LOLO(X##bu, X##ga); \ + X##ge = GET64HIHI(X##gae, X##gae); \ + X##bage = GET64LOLO(X##ba, X##ge); \ + XOReq128(Cae, X##gae); \ + X##gio = XOR128(LOAD128u(state[ 7]), LOAD128u(input[ 7])); \ + X##gi = X##gio; \ + X##begi = GET64LOLO(X##be, X##gi); \ + X##go = GET64HIHI(X##gio, X##gio); \ + X##bigo = GET64LOLO(X##bi, X##go); \ + XOReq128(Cio, X##gio); \ + X##gu = XOR64(LOAD64(state[ 9]), LOAD64(input[ 9])); \ + X##bogu = GET64LOLO(X##bo, X##gu); \ + XOReq64(Cua, X##gu); \ + X##kae = XOR128(LOAD128(state[10]), LOAD128u(input[10])); \ + X##ka = X##kae; \ + X##ke = GET64HIHI(X##kae, X##kae); \ + XOReq128(Cae, X##kae); \ + X##kio = XOR128(LOAD128(state[12]), LOAD64(input[12])); \ + X##ki = X##kio; \ + X##ko = GET64HIHI(X##kio, X##kio); \ + XOReq128(Cio, X##kio); \ + X##kuma = LOAD128(state[14]); \ + XOReq64(Cua, X##kuma); \ + X##me = LOAD64(state[16]); \ + X##kame = GET64LOLO(X##ka, X##me); \ + XOReq128(Cae, GET64HIHI(X##kuma, X##kame)); \ + X##mio = LOAD128u(state[17]); \ + X##mi = X##mio; \ + X##kemi = GET64LOLO(X##ke, X##mi); \ + X##mo = GET64HIHI(X##mio, X##mio); \ + X##kimo = GET64LOLO(X##ki, X##mo); \ + XOReq128(Cio, X##mio); \ + X##mu = LOAD64(state[19]); \ + X##komu = GET64LOLO(X##ko, X##mu); \ + XOReq64(Cua, X##mu); \ + X##sase = LOAD128(state[20]); \ + XOReq128(Cae, X##sase); \ + X##siso = LOAD128(state[22]); \ + XOReq128(Cio, X##siso); \ + X##su = LOAD64(state[24]); \ + XOReq64(Cua, X##su); \ + +#define copyFromStateAndXor1024bits(X, state, input) \ + X##bae = XOR128(LOAD128(state[ 0]), LOAD128u(input[ 0])); \ + X##ba = X##bae; \ + X##be = GET64HIHI(X##bae, X##bae); \ + Cae = X##bae; \ + X##bio = XOR128(LOAD128(state[ 2]), LOAD128u(input[ 2])); \ + X##bi = X##bio; \ + X##bo = GET64HIHI(X##bio, X##bio); \ + Cio = X##bio; \ + X##bu = XOR64(LOAD64(state[ 4]), LOAD64(input[ 4])); \ + Cua = X##bu; \ + X##gae = XOR128(LOAD128u(state[ 5]), LOAD128u(input[ 5])); \ + X##ga = X##gae; \ + X##buga = GET64LOLO(X##bu, X##ga); \ + X##ge = GET64HIHI(X##gae, X##gae); \ + X##bage = GET64LOLO(X##ba, X##ge); \ + XOReq128(Cae, X##gae); \ + X##gio = XOR128(LOAD128u(state[ 7]), LOAD128u(input[ 7])); \ + X##gi = X##gio; \ + X##begi = GET64LOLO(X##be, X##gi); \ + X##go = GET64HIHI(X##gio, X##gio); \ + X##bigo = GET64LOLO(X##bi, X##go); \ + XOReq128(Cio, X##gio); \ + X##gu = XOR64(LOAD64(state[ 9]), LOAD64(input[ 9])); \ + X##bogu = GET64LOLO(X##bo, X##gu); \ + XOReq64(Cua, X##gu); \ + X##kae = XOR128(LOAD128(state[10]), LOAD128u(input[10])); \ + X##ka = X##kae; \ + X##ke = GET64HIHI(X##kae, X##kae); \ + XOReq128(Cae, X##kae); \ + X##kio = XOR128(LOAD128(state[12]), LOAD128u(input[12])); \ + X##ki = X##kio; \ + X##ko = GET64HIHI(X##kio, X##kio); \ + XOReq128(Cio, X##kio); \ + X##kuma = XOR128(LOAD128(state[14]), LOAD128(input[14])); \ + XOReq64(Cua, X##kuma); \ + X##me = LOAD64(state[16]); \ + X##kame = GET64LOLO(X##ka, X##me); \ + XOReq128(Cae, GET64HIHI(X##kuma, X##kame)); \ + X##mio = LOAD128u(state[17]); \ + X##mi = X##mio; \ + X##kemi = GET64LOLO(X##ke, X##mi); \ + X##mo = GET64HIHI(X##mio, X##mio); \ + X##kimo = GET64LOLO(X##ki, X##mo); \ + XOReq128(Cio, X##mio); \ + X##mu = LOAD64(state[19]); \ + X##komu = GET64LOLO(X##ko, X##mu); \ + XOReq64(Cua, X##mu); \ + X##sase = LOAD128(state[20]); \ + XOReq128(Cae, X##sase); \ + X##siso = LOAD128(state[22]); \ + XOReq128(Cio, X##siso); \ + X##su = LOAD64(state[24]); \ + XOReq64(Cua, X##su); \ + +#define copyFromStateAndXor1088bits(X, state, input) \ + X##bae = XOR128(LOAD128(state[ 0]), LOAD128u(input[ 0])); \ + X##ba = X##bae; \ + X##be = GET64HIHI(X##bae, X##bae); \ + Cae = X##bae; \ + X##bio = XOR128(LOAD128(state[ 2]), LOAD128u(input[ 2])); \ + X##bi = X##bio; \ + X##bo = GET64HIHI(X##bio, X##bio); \ + Cio = X##bio; \ + X##bu = XOR64(LOAD64(state[ 4]), LOAD64(input[ 4])); \ + Cua = X##bu; \ + X##gae = XOR128(LOAD128u(state[ 5]), LOAD128u(input[ 5])); \ + X##ga = X##gae; \ + X##buga = GET64LOLO(X##bu, X##ga); \ + X##ge = GET64HIHI(X##gae, X##gae); \ + X##bage = GET64LOLO(X##ba, X##ge); \ + XOReq128(Cae, X##gae); \ + X##gio = XOR128(LOAD128u(state[ 7]), LOAD128u(input[ 7])); \ + X##gi = X##gio; \ + X##begi = GET64LOLO(X##be, X##gi); \ + X##go = GET64HIHI(X##gio, X##gio); \ + X##bigo = GET64LOLO(X##bi, X##go); \ + XOReq128(Cio, X##gio); \ + X##gu = XOR64(LOAD64(state[ 9]), LOAD64(input[ 9])); \ + X##bogu = GET64LOLO(X##bo, X##gu); \ + XOReq64(Cua, X##gu); \ + X##kae = XOR128(LOAD128(state[10]), LOAD128u(input[10])); \ + X##ka = X##kae; \ + X##ke = GET64HIHI(X##kae, X##kae); \ + XOReq128(Cae, X##kae); \ + X##kio = XOR128(LOAD128(state[12]), LOAD128u(input[12])); \ + X##ki = X##kio; \ + X##ko = GET64HIHI(X##kio, X##kio); \ + XOReq128(Cio, X##kio); \ + X##kuma = XOR128(LOAD128(state[14]), LOAD128(input[14])); \ + XOReq64(Cua, X##kuma); \ + X##me = XOR64(LOAD64(state[16]), LOAD64(input[16])); \ + X##kame = GET64LOLO(X##ka, X##me); \ + XOReq128(Cae, GET64HIHI(X##kuma, X##kame)); \ + X##mio = LOAD128u(state[17]); \ + X##mi = X##mio; \ + X##kemi = GET64LOLO(X##ke, X##mi); \ + X##mo = GET64HIHI(X##mio, X##mio); \ + X##kimo = GET64LOLO(X##ki, X##mo); \ + XOReq128(Cio, X##mio); \ + X##mu = LOAD64(state[19]); \ + X##komu = GET64LOLO(X##ko, X##mu); \ + XOReq64(Cua, X##mu); \ + X##sase = LOAD128(state[20]); \ + XOReq128(Cae, X##sase); \ + X##siso = LOAD128(state[22]); \ + XOReq128(Cio, X##siso); \ + X##su = LOAD64(state[24]); \ + XOReq64(Cua, X##su); \ + +#define copyFromStateAndXor1152bits(X, state, input) \ + X##bae = XOR128(LOAD128(state[ 0]), LOAD128u(input[ 0])); \ + X##ba = X##bae; \ + X##be = GET64HIHI(X##bae, X##bae); \ + Cae = X##bae; \ + X##bio = XOR128(LOAD128(state[ 2]), LOAD128u(input[ 2])); \ + X##bi = X##bio; \ + X##bo = GET64HIHI(X##bio, X##bio); \ + Cio = X##bio; \ + X##bu = XOR64(LOAD64(state[ 4]), LOAD64(input[ 4])); \ + Cua = X##bu; \ + X##gae = XOR128(LOAD128u(state[ 5]), LOAD128u(input[ 5])); \ + X##ga = X##gae; \ + X##buga = GET64LOLO(X##bu, X##ga); \ + X##ge = GET64HIHI(X##gae, X##gae); \ + X##bage = GET64LOLO(X##ba, X##ge); \ + XOReq128(Cae, X##gae); \ + X##gio = XOR128(LOAD128u(state[ 7]), LOAD128u(input[ 7])); \ + X##gi = X##gio; \ + X##begi = GET64LOLO(X##be, X##gi); \ + X##go = GET64HIHI(X##gio, X##gio); \ + X##bigo = GET64LOLO(X##bi, X##go); \ + XOReq128(Cio, X##gio); \ + X##gu = XOR64(LOAD64(state[ 9]), LOAD64(input[ 9])); \ + X##bogu = GET64LOLO(X##bo, X##gu); \ + XOReq64(Cua, X##gu); \ + X##kae = XOR128(LOAD128(state[10]), LOAD128u(input[10])); \ + X##ka = X##kae; \ + X##ke = GET64HIHI(X##kae, X##kae); \ + XOReq128(Cae, X##kae); \ + X##kio = XOR128(LOAD128(state[12]), LOAD128u(input[12])); \ + X##ki = X##kio; \ + X##ko = GET64HIHI(X##kio, X##kio); \ + XOReq128(Cio, X##kio); \ + X##kuma = XOR128(LOAD128(state[14]), LOAD128(input[14])); \ + XOReq64(Cua, X##kuma); \ + X##me = XOR64(LOAD64(state[16]), LOAD64(input[16])); \ + X##kame = GET64LOLO(X##ka, X##me); \ + XOReq128(Cae, GET64HIHI(X##kuma, X##kame)); \ + X##mio = XOR128(LOAD128u(state[17]), LOAD64(input[17])); \ + X##mi = X##mio; \ + X##kemi = GET64LOLO(X##ke, X##mi); \ + X##mo = GET64HIHI(X##mio, X##mio); \ + X##kimo = GET64LOLO(X##ki, X##mo); \ + XOReq128(Cio, X##mio); \ + X##mu = LOAD64(state[19]); \ + X##komu = GET64LOLO(X##ko, X##mu); \ + XOReq64(Cua, X##mu); \ + X##sase = LOAD128(state[20]); \ + XOReq128(Cae, X##sase); \ + X##siso = LOAD128(state[22]); \ + XOReq128(Cio, X##siso); \ + X##su = LOAD64(state[24]); \ + XOReq64(Cua, X##su); \ + +#define copyFromStateAndXor1344bits(X, state, input) \ + X##bae = XOR128(LOAD128(state[ 0]), LOAD128u(input[ 0])); \ + X##ba = X##bae; \ + X##be = GET64HIHI(X##bae, X##bae); \ + Cae = X##bae; \ + X##bio = XOR128(LOAD128(state[ 2]), LOAD128u(input[ 2])); \ + X##bi = X##bio; \ + X##bo = GET64HIHI(X##bio, X##bio); \ + Cio = X##bio; \ + X##bu = XOR64(LOAD64(state[ 4]), LOAD64(input[ 4])); \ + Cua = X##bu; \ + X##gae = XOR128(LOAD128u(state[ 5]), LOAD128u(input[ 5])); \ + X##ga = X##gae; \ + X##buga = GET64LOLO(X##bu, X##ga); \ + X##ge = GET64HIHI(X##gae, X##gae); \ + X##bage = GET64LOLO(X##ba, X##ge); \ + XOReq128(Cae, X##gae); \ + X##gio = XOR128(LOAD128u(state[ 7]), LOAD128u(input[ 7])); \ + X##gi = X##gio; \ + X##begi = GET64LOLO(X##be, X##gi); \ + X##go = GET64HIHI(X##gio, X##gio); \ + X##bigo = GET64LOLO(X##bi, X##go); \ + XOReq128(Cio, X##gio); \ + X##gu = XOR64(LOAD64(state[ 9]), LOAD64(input[ 9])); \ + X##bogu = GET64LOLO(X##bo, X##gu); \ + XOReq64(Cua, X##gu); \ + X##kae = XOR128(LOAD128(state[10]), LOAD128u(input[10])); \ + X##ka = X##kae; \ + X##ke = GET64HIHI(X##kae, X##kae); \ + XOReq128(Cae, X##kae); \ + X##kio = XOR128(LOAD128(state[12]), LOAD128u(input[12])); \ + X##ki = X##kio; \ + X##ko = GET64HIHI(X##kio, X##kio); \ + XOReq128(Cio, X##kio); \ + X##kuma = XOR128(LOAD128(state[14]), LOAD128(input[14])); \ + XOReq64(Cua, X##kuma); \ + X##me = XOR64(LOAD64(state[16]), LOAD64(input[16])); \ + X##kame = GET64LOLO(X##ka, X##me); \ + XOReq128(Cae, GET64HIHI(X##kuma, X##kame)); \ + X##mio = XOR128(LOAD128u(state[17]), LOAD128u(input[17])); \ + X##mi = X##mio; \ + X##kemi = GET64LOLO(X##ke, X##mi); \ + X##mo = GET64HIHI(X##mio, X##mio); \ + X##kimo = GET64LOLO(X##ki, X##mo); \ + XOReq128(Cio, X##mio); \ + X##mu = XOR64(LOAD64(state[19]), LOAD64(input[19])); \ + X##komu = GET64LOLO(X##ko, X##mu); \ + XOReq64(Cua, X##mu); \ + X##sase = XOR128(LOAD128(state[20]), LOAD64(input[20])); \ + XOReq128(Cae, X##sase); \ + X##siso = LOAD128(state[22]); \ + XOReq128(Cio, X##siso); \ + X##su = LOAD64(state[24]); \ + XOReq64(Cua, X##su); \ + +#define copyFromState(X, state) \ + X##bae = LOAD128(state[ 0]); \ + X##ba = X##bae; \ + X##be = GET64HIHI(X##bae, X##bae); \ + Cae = X##bae; \ + X##bio = LOAD128(state[ 2]); \ + X##bi = X##bio; \ + X##bo = GET64HIHI(X##bio, X##bio); \ + Cio = X##bio; \ + X##bu = LOAD64(state[ 4]); \ + Cua = X##bu; \ + X##gae = LOAD128u(state[ 5]); \ + X##ga = X##gae; \ + X##buga = GET64LOLO(X##bu, X##ga); \ + X##ge = GET64HIHI(X##gae, X##gae); \ + X##bage = GET64LOLO(X##ba, X##ge); \ + XOReq128(Cae, X##gae); \ + X##gio = LOAD128u(state[ 7]); \ + X##gi = X##gio; \ + X##begi = GET64LOLO(X##be, X##gi); \ + X##go = GET64HIHI(X##gio, X##gio); \ + X##bigo = GET64LOLO(X##bi, X##go); \ + XOReq128(Cio, X##gio); \ + X##gu = LOAD64(state[ 9]); \ + X##bogu = GET64LOLO(X##bo, X##gu); \ + XOReq64(Cua, X##gu); \ + X##kae = LOAD128(state[10]); \ + X##ka = X##kae; \ + X##ke = GET64HIHI(X##kae, X##kae); \ + XOReq128(Cae, X##kae); \ + X##kio = LOAD128(state[12]); \ + X##ki = X##kio; \ + X##ko = GET64HIHI(X##kio, X##kio); \ + XOReq128(Cio, X##kio); \ + X##kuma = LOAD128(state[14]); \ + XOReq64(Cua, X##kuma); \ + X##me = LOAD64(state[16]); \ + X##kame = GET64LOLO(X##ka, X##me); \ + XOReq128(Cae, GET64HIHI(X##kuma, X##kame)); \ + X##mio = LOAD128u(state[17]); \ + X##mi = X##mio; \ + X##kemi = GET64LOLO(X##ke, X##mi); \ + X##mo = GET64HIHI(X##mio, X##mio); \ + X##kimo = GET64LOLO(X##ki, X##mo); \ + XOReq128(Cio, X##mio); \ + X##mu = LOAD64(state[19]); \ + X##komu = GET64LOLO(X##ko, X##mu); \ + XOReq64(Cua, X##mu); \ + X##sase = LOAD128(state[20]); \ + XOReq128(Cae, X##sase); \ + X##siso = LOAD128(state[22]); \ + XOReq128(Cio, X##siso); \ + X##su = LOAD64(state[24]); \ + XOReq64(Cua, X##su); \ + +#define copyToState(state, X) \ + STORE64(state[ 0], X##bage); \ + STORE64(state[ 1], X##begi); \ + STORE64(state[ 2], X##bigo); \ + STORE64(state[ 3], X##bogu); \ + STORE128(state[ 4], X##buga); \ + STORE64(state[ 6], COPY64HI2LO(X##bage)); \ + STORE64(state[ 7], COPY64HI2LO(X##begi)); \ + STORE64(state[ 8], COPY64HI2LO(X##bigo)); \ + STORE64(state[ 9], COPY64HI2LO(X##bogu)); \ + STORE64(state[10], X##kame); \ + STORE64(state[11], X##kemi); \ + STORE64(state[12], X##kimo); \ + STORE64(state[13], X##komu); \ + STORE128(state[14], X##kuma); \ + STORE64(state[16], COPY64HI2LO(X##kame)); \ + STORE64(state[17], COPY64HI2LO(X##kemi)); \ + STORE64(state[18], COPY64HI2LO(X##kimo)); \ + STORE64(state[19], COPY64HI2LO(X##komu)); \ + STORE128(state[20], X##sase); \ + STORE128(state[22], X##siso); \ + STORE64(state[24], X##su); \ + +#define copyStateVariables(X, Y) \ + X##bage = Y##bage; \ + X##begi = Y##begi; \ + X##bigo = Y##bigo; \ + X##bogu = Y##bogu; \ + X##buga = Y##buga; \ + X##kame = Y##kame; \ + X##kemi = Y##kemi; \ + X##kimo = Y##kimo; \ + X##komu = Y##komu; \ + X##kuma = Y##kuma; \ + X##sase = Y##sase; \ + X##siso = Y##siso; \ + X##su = Y##su; \ + diff --git a/c_src/KeccakNISTInterface.c b/c_src/KeccakNISTInterface.c new file mode 100755 index 0000000..5d92c74 --- /dev/null +++ b/c_src/KeccakNISTInterface.c @@ -0,0 +1,81 @@ +/* +The Keccak sponge function, designed by Guido Bertoni, Joan Daemen, +Michaël Peeters and Gilles Van Assche. For more information, feedback or +questions, please refer to our website: http://keccak.noekeon.org/ + +Implementation by the designers, +hereby denoted as "the implementer". + +To the extent possible under law, the implementer has waived all copyright +and related or neighboring rights to the source code in this file. +http://creativecommons.org/publicdomain/zero/1.0/ +*/ + +#include +#include "KeccakNISTInterface.h" +#include "KeccakF-1600-interface.h" + +HashReturn Init(hashState *state, int hashbitlen) +{ + switch(hashbitlen) { + case 0: // Default parameters, arbitrary length output + InitSponge((spongeState*)state, 1024, 576); + break; + case 224: + InitSponge((spongeState*)state, 1152, 448); + break; + case 256: + InitSponge((spongeState*)state, 1088, 512); + break; + case 384: + InitSponge((spongeState*)state, 832, 768); + break; + case 512: + InitSponge((spongeState*)state, 576, 1024); + break; + default: + return BAD_HASHLEN; + } + state->fixedOutputLength = hashbitlen; + return SUCCESS; +} + +HashReturn Update(hashState *state, const BitSequence *data, DataLength databitlen) +{ + if ((databitlen % 8) == 0) + return Absorb((spongeState*)state, data, databitlen); + else { + HashReturn ret = Absorb((spongeState*)state, data, databitlen - (databitlen % 8)); + if (ret == SUCCESS) { + unsigned char lastByte; + // Align the last partial byte to the least significant bits + lastByte = data[databitlen/8] >> (8 - (databitlen % 8)); + return Absorb((spongeState*)state, &lastByte, databitlen % 8); + } + else + return ret; + } +} + +HashReturn Final(hashState *state, BitSequence *hashval) +{ + return Squeeze(state, hashval, state->fixedOutputLength); +} + +HashReturn Hash(int hashbitlen, const BitSequence *data, DataLength databitlen, BitSequence *hashval) +{ + hashState state; + HashReturn result; + + if ((hashbitlen != 224) && (hashbitlen != 256) && (hashbitlen != 384) && (hashbitlen != 512)) + return BAD_HASHLEN; // Only the four fixed output lengths available through this API + result = Init(&state, hashbitlen); + if (result != SUCCESS) + return result; + result = Update(&state, data, databitlen); + if (result != SUCCESS) + return result; + result = Final(&state, hashval); + return result; +} + diff --git a/c_src/KeccakNISTInterface.h b/c_src/KeccakNISTInterface.h new file mode 100755 index 0000000..c6987d4 --- /dev/null +++ b/c_src/KeccakNISTInterface.h @@ -0,0 +1,70 @@ +/* +The Keccak sponge function, designed by Guido Bertoni, Joan Daemen, +Michaël Peeters and Gilles Van Assche. For more information, feedback or +questions, please refer to our website: http://keccak.noekeon.org/ + +Implementation by the designers, +hereby denoted as "the implementer". + +To the extent possible under law, the implementer has waived all copyright +and related or neighboring rights to the source code in this file. +http://creativecommons.org/publicdomain/zero/1.0/ +*/ + +#ifndef _KeccakNISTInterface_h_ +#define _KeccakNISTInterface_h_ + +#include "KeccakSponge.h" + +typedef unsigned char BitSequence; +typedef unsigned long long DataLength; +typedef enum { SUCCESS = 0, FAIL = 1, BAD_HASHLEN = 2 } HashReturn; + +typedef spongeState hashState; + +/** + * Function to initialize the state of the Keccak[r, c] sponge function. + * The rate r and capacity c values are determined from @a hashbitlen. + * @param state Pointer to the state of the sponge function to be initialized. + * @param hashbitlen The desired number of output bits, + * or 0 for Keccak[] with default parameters + * and arbitrarily-long output. + * @pre The value of hashbitlen must be one of 0, 224, 256, 384 and 512. + * @return SUCCESS if successful, BAD_HASHLEN if the value of hashbitlen is incorrect. + */ +HashReturn Init(hashState *state, int hashbitlen); +/** + * Function to give input data for the sponge function to absorb. + * @param state Pointer to the state of the sponge function initialized by Init(). + * @param data Pointer to the input data. + * When @a databitLen is not a multiple of 8, the last bits of data must be + * in the most significant bits of the last byte. + * @param databitLen The number of input bits provided in the input data. + * @pre In the previous call to Absorb(), databitLen was a multiple of 8. + * @return SUCCESS if successful, FAIL otherwise. + */ +HashReturn Update(hashState *state, const BitSequence *data, DataLength databitlen); +/** + * Function to squeeze output data from the sponge function. + * If @a hashbitlen was not 0 in the call to Init(), the number of output bits is equal to @a hashbitlen. + * If @a hashbitlen was 0 in the call to Init(), the output bits must be extracted using the Squeeze() function. + * @param state Pointer to the state of the sponge function initialized by Init(). + * @param hashval Pointer to the buffer where to store the output data. + * @return SUCCESS if successful, FAIL otherwise. + */ +HashReturn Final(hashState *state, BitSequence *hashval); +/** + * Function to compute a hash using the Keccak[r, c] sponge function. + * The rate r and capacity c values are determined from @a hashbitlen. + * @param hashbitlen The desired number of output bits. + * @param data Pointer to the input data. + * When @a databitLen is not a multiple of 8, the last bits of data must be + * in the most significant bits of the last byte. + * @param databitLen The number of input bits provided in the input data. + * @param hashval Pointer to the buffer where to store the output data. + * @pre The value of hashbitlen must be one of 224, 256, 384 and 512. + * @return SUCCESS if successful, BAD_HASHLEN if the value of hashbitlen is incorrect. + */ +HashReturn Hash(int hashbitlen, const BitSequence *data, DataLength databitlen, BitSequence *hashval); + +#endif diff --git a/c_src/KeccakSponge.c b/c_src/KeccakSponge.c new file mode 100755 index 0000000..5939ba4 --- /dev/null +++ b/c_src/KeccakSponge.c @@ -0,0 +1,266 @@ +/* +The Keccak sponge function, designed by Guido Bertoni, Joan Daemen, +Michaël Peeters and Gilles Van Assche. For more information, feedback or +questions, please refer to our website: http://keccak.noekeon.org/ + +Implementation by the designers, +hereby denoted as "the implementer". + +To the extent possible under law, the implementer has waived all copyright +and related or neighboring rights to the source code in this file. +http://creativecommons.org/publicdomain/zero/1.0/ +*/ + +#include +#include "KeccakSponge.h" +#include "KeccakF-1600-interface.h" +#ifdef KeccakReference +#include "displayIntermediateValues.h" +#endif + +int InitSponge(spongeState *state, unsigned int rate, unsigned int capacity) +{ + if (rate+capacity != 1600) + return 1; + if ((rate <= 0) || (rate >= 1600) || ((rate % 64) != 0)) + return 1; + KeccakInitialize(); + state->rate = rate; + state->capacity = capacity; + state->fixedOutputLength = 0; + KeccakInitializeState(state->state); + memset(state->dataQueue, 0, KeccakMaximumRateInBytes); + state->bitsInQueue = 0; + state->squeezing = 0; + state->bitsAvailableForSqueezing = 0; + + return 0; +} + +void AbsorbQueue(spongeState *state) +{ + // state->bitsInQueue is assumed to be equal to state->rate + #ifdef KeccakReference + displayBytes(1, "Block to be absorbed", state->dataQueue, state->rate/8); + #endif +#ifdef ProvideFast576 + if (state->rate == 576) + KeccakAbsorb576bits(state->state, state->dataQueue); + else +#endif +#ifdef ProvideFast832 + if (state->rate == 832) + KeccakAbsorb832bits(state->state, state->dataQueue); + else +#endif +#ifdef ProvideFast1024 + if (state->rate == 1024) + KeccakAbsorb1024bits(state->state, state->dataQueue); + else +#endif +#ifdef ProvideFast1088 + if (state->rate == 1088) + KeccakAbsorb1088bits(state->state, state->dataQueue); + else +#endif +#ifdef ProvideFast1152 + if (state->rate == 1152) + KeccakAbsorb1152bits(state->state, state->dataQueue); + else +#endif +#ifdef ProvideFast1344 + if (state->rate == 1344) + KeccakAbsorb1344bits(state->state, state->dataQueue); + else +#endif + KeccakAbsorb(state->state, state->dataQueue, state->rate/64); + state->bitsInQueue = 0; +} + +int Absorb(spongeState *state, const unsigned char *data, unsigned long long databitlen) +{ + unsigned long long i, j, wholeBlocks; + unsigned int partialBlock, partialByte; + const unsigned char *curData; + + if ((state->bitsInQueue % 8) != 0) + return 1; // Only the last call may contain a partial byte + if (state->squeezing) + return 1; // Too late for additional input + + i = 0; + while(i < databitlen) { + if ((state->bitsInQueue == 0) && (databitlen >= state->rate) && (i <= (databitlen-state->rate))) { + wholeBlocks = (databitlen-i)/state->rate; + curData = data+i/8; +#ifdef ProvideFast576 + if (state->rate == 576) { + for(j=0; jrate/8); + #endif + KeccakAbsorb576bits(state->state, curData); + } + } + else +#endif +#ifdef ProvideFast832 + if (state->rate == 832) { + for(j=0; jrate/8); + #endif + KeccakAbsorb832bits(state->state, curData); + } + } + else +#endif +#ifdef ProvideFast1024 + if (state->rate == 1024) { + for(j=0; jrate/8); + #endif + KeccakAbsorb1024bits(state->state, curData); + } + } + else +#endif +#ifdef ProvideFast1088 + if (state->rate == 1088) { + for(j=0; jrate/8); + #endif + KeccakAbsorb1088bits(state->state, curData); + } + } + else +#endif +#ifdef ProvideFast1152 + if (state->rate == 1152) { + for(j=0; jrate/8); + #endif + KeccakAbsorb1152bits(state->state, curData); + } + } + else +#endif +#ifdef ProvideFast1344 + if (state->rate == 1344) { + for(j=0; jrate/8); + #endif + KeccakAbsorb1344bits(state->state, curData); + } + } + else +#endif + { + for(j=0; jrate/8) { + #ifdef KeccakReference + displayBytes(1, "Block to be absorbed", curData, state->rate/8); + #endif + KeccakAbsorb(state->state, curData, state->rate/64); + } + } + i += wholeBlocks*state->rate; + } + else { + partialBlock = (unsigned int)(databitlen - i); + if (partialBlock+state->bitsInQueue > state->rate) + partialBlock = state->rate-state->bitsInQueue; + partialByte = partialBlock % 8; + partialBlock -= partialByte; + memcpy(state->dataQueue+state->bitsInQueue/8, data+i/8, partialBlock/8); + state->bitsInQueue += partialBlock; + i += partialBlock; + if (state->bitsInQueue == state->rate) + AbsorbQueue(state); + if (partialByte > 0) { + unsigned char mask = (1 << partialByte)-1; + state->dataQueue[state->bitsInQueue/8] = data[i/8] & mask; + state->bitsInQueue += partialByte; + i += partialByte; + } + } + } + return 0; +} + +void PadAndSwitchToSqueezingPhase(spongeState *state) +{ + // Note: the bits are numbered from 0=LSB to 7=MSB + if (state->bitsInQueue + 1 == state->rate) { + state->dataQueue[state->bitsInQueue/8 ] |= 1 << (state->bitsInQueue % 8); + AbsorbQueue(state); + memset(state->dataQueue, 0, state->rate/8); + } + else { + memset(state->dataQueue + (state->bitsInQueue+7)/8, 0, state->rate/8 - (state->bitsInQueue+7)/8); + state->dataQueue[state->bitsInQueue/8 ] |= 1 << (state->bitsInQueue % 8); + } + state->dataQueue[(state->rate-1)/8] |= 1 << ((state->rate-1) % 8); + AbsorbQueue(state); + + #ifdef KeccakReference + displayText(1, "--- Switching to squeezing phase ---"); + #endif +#ifdef ProvideFast1024 + if (state->rate == 1024) { + KeccakExtract1024bits(state->state, state->dataQueue); + state->bitsAvailableForSqueezing = 1024; + } + else +#endif + { + KeccakExtract(state->state, state->dataQueue, state->rate/64); + state->bitsAvailableForSqueezing = state->rate; + } + #ifdef KeccakReference + displayBytes(1, "Block available for squeezing", state->dataQueue, state->bitsAvailableForSqueezing/8); + #endif + state->squeezing = 1; +} + +int Squeeze(spongeState *state, unsigned char *output, unsigned long long outputLength) +{ + unsigned long long i; + unsigned int partialBlock; + + if (!state->squeezing) + PadAndSwitchToSqueezingPhase(state); + if ((outputLength % 8) != 0) + return 1; // Only multiple of 8 bits are allowed, truncation can be done at user level + + i = 0; + while(i < outputLength) { + if (state->bitsAvailableForSqueezing == 0) { + KeccakPermutation(state->state); +#ifdef ProvideFast1024 + if (state->rate == 1024) { + KeccakExtract1024bits(state->state, state->dataQueue); + state->bitsAvailableForSqueezing = 1024; + } + else +#endif + { + KeccakExtract(state->state, state->dataQueue, state->rate/64); + state->bitsAvailableForSqueezing = state->rate; + } + #ifdef KeccakReference + displayBytes(1, "Block available for squeezing", state->dataQueue, state->bitsAvailableForSqueezing/8); + #endif + } + partialBlock = state->bitsAvailableForSqueezing; + if ((unsigned long long)partialBlock > outputLength - i) + partialBlock = (unsigned int)(outputLength - i); + memcpy(output+i/8, state->dataQueue+(state->rate-state->bitsAvailableForSqueezing)/8, partialBlock/8); + state->bitsAvailableForSqueezing -= partialBlock; + i += partialBlock; + } + return 0; +} diff --git a/c_src/KeccakSponge.h b/c_src/KeccakSponge.h new file mode 100755 index 0000000..df3d797 --- /dev/null +++ b/c_src/KeccakSponge.h @@ -0,0 +1,76 @@ +/* +The Keccak sponge function, designed by Guido Bertoni, Joan Daemen, +Michaël Peeters and Gilles Van Assche. For more information, feedback or +questions, please refer to our website: http://keccak.noekeon.org/ + +Implementation by the designers, +hereby denoted as "the implementer". + +To the extent possible under law, the implementer has waived all copyright +and related or neighboring rights to the source code in this file. +http://creativecommons.org/publicdomain/zero/1.0/ +*/ + +#ifndef _KeccakSponge_h_ +#define _KeccakSponge_h_ + +#define KeccakPermutationSize 1600 +#define KeccakPermutationSizeInBytes (KeccakPermutationSize/8) +#define KeccakMaximumRate 1536 +#define KeccakMaximumRateInBytes (KeccakMaximumRate/8) + +#if defined(__GNUC__) +#define ALIGN __attribute__ ((aligned(32))) +#elif defined(_MSC_VER) +#define ALIGN __declspec(align(32)) +#else +#define ALIGN +#endif + +ALIGN typedef struct spongeStateStruct { + ALIGN unsigned char state[KeccakPermutationSizeInBytes]; + ALIGN unsigned char dataQueue[KeccakMaximumRateInBytes]; + unsigned int rate; + unsigned int capacity; + unsigned int bitsInQueue; + unsigned int fixedOutputLength; + int squeezing; + unsigned int bitsAvailableForSqueezing; +} spongeState; + +/** + * Function to initialize the state of the Keccak[r, c] sponge function. + * The sponge function is set to the absorbing phase. + * @param state Pointer to the state of the sponge function to be initialized. + * @param rate The value of the rate r. + * @param capacity The value of the capacity c. + * @pre One must have r+c=1600 and the rate a multiple of 64 bits in this implementation. + * @return Zero if successful, 1 otherwise. + */ +int InitSponge(spongeState *state, unsigned int rate, unsigned int capacity); +/** + * Function to give input data for the sponge function to absorb. + * @param state Pointer to the state of the sponge function initialized by InitSponge(). + * @param data Pointer to the input data. + * When @a databitLen is not a multiple of 8, the last bits of data must be + * in the least significant bits of the last byte. + * @param databitLen The number of input bits provided in the input data. + * @pre In the previous call to Absorb(), databitLen was a multiple of 8. + * @pre The sponge function must be in the absorbing phase, + * i.e., Squeeze() must not have been called before. + * @return Zero if successful, 1 otherwise. + */ +int Absorb(spongeState *state, const unsigned char *data, unsigned long long databitlen); +/** + * Function to squeeze output data from the sponge function. + * If the sponge function was in the absorbing phase, this function + * switches it to the squeezing phase. + * @param state Pointer to the state of the sponge function initialized by InitSponge(). + * @param output Pointer to the buffer where to store the output data. + * @param outputLength The number of output bits desired. + * It must be a multiple of 8. + * @return Zero if successful, 1 otherwise. + */ +int Squeeze(spongeState *state, unsigned char *output, unsigned long long outputLength); + +#endif diff --git a/c_src/brg_endian.h b/c_src/brg_endian.h new file mode 100755 index 0000000..7226eb3 --- /dev/null +++ b/c_src/brg_endian.h @@ -0,0 +1,142 @@ +/* + --------------------------------------------------------------------------- + Copyright (c) 1998-2008, Brian Gladman, Worcester, UK. All rights reserved. + + LICENSE TERMS + + The redistribution and use of this software (with or without changes) + is allowed without the payment of fees or royalties provided that: + + 1. source code distributions include the above copyright notice, this + list of conditions and the following disclaimer; + + 2. binary distributions include the above copyright notice, this list + of conditions and the following disclaimer in their documentation; + + 3. the name of the copyright holder is not used to endorse products + built using this software without specific written permission. + + DISCLAIMER + + This software is provided 'as is' with no explicit or implied warranties + in respect of its properties, including, but not limited to, correctness + and/or fitness for purpose. + --------------------------------------------------------------------------- + Issue Date: 20/12/2007 + Changes for ARM 9/9/2010 +*/ + +#ifndef _BRG_ENDIAN_H +#define _BRG_ENDIAN_H + +#define IS_BIG_ENDIAN 4321 /* byte 0 is most significant (mc68k) */ +#define IS_LITTLE_ENDIAN 1234 /* byte 0 is least significant (i386) */ + +#if 0 +/* Include files where endian defines and byteswap functions may reside */ +#if defined( __sun ) +# include +#elif defined( __FreeBSD__ ) || defined( __OpenBSD__ ) || defined( __NetBSD__ ) +# include +#elif defined( BSD ) && ( BSD >= 199103 ) || defined( __APPLE__ ) || \ + defined( __CYGWIN32__ ) || defined( __DJGPP__ ) || defined( __osf__ ) +# include +#elif defined( __linux__ ) || defined( __GNUC__ ) || defined( __GNU_LIBRARY__ ) +# if !defined( __MINGW32__ ) && !defined( _AIX ) +# include +# if !defined( __BEOS__ ) +# include +# endif +# endif +#endif +#endif + +/* Now attempt to set the define for platform byte order using any */ +/* of the four forms SYMBOL, _SYMBOL, __SYMBOL & __SYMBOL__, which */ +/* seem to encompass most endian symbol definitions */ + +#if defined( BIG_ENDIAN ) && defined( LITTLE_ENDIAN ) +# if defined( BYTE_ORDER ) && BYTE_ORDER == BIG_ENDIAN +# define PLATFORM_BYTE_ORDER IS_BIG_ENDIAN +# elif defined( BYTE_ORDER ) && BYTE_ORDER == LITTLE_ENDIAN +# define PLATFORM_BYTE_ORDER IS_LITTLE_ENDIAN +# endif +#elif defined( BIG_ENDIAN ) +# define PLATFORM_BYTE_ORDER IS_BIG_ENDIAN +#elif defined( LITTLE_ENDIAN ) +# define PLATFORM_BYTE_ORDER IS_LITTLE_ENDIAN +#endif + +#if defined( _BIG_ENDIAN ) && defined( _LITTLE_ENDIAN ) +# if defined( _BYTE_ORDER ) && _BYTE_ORDER == _BIG_ENDIAN +# define PLATFORM_BYTE_ORDER IS_BIG_ENDIAN +# elif defined( _BYTE_ORDER ) && _BYTE_ORDER == _LITTLE_ENDIAN +# define PLATFORM_BYTE_ORDER IS_LITTLE_ENDIAN +# endif +#elif defined( _BIG_ENDIAN ) +# define PLATFORM_BYTE_ORDER IS_BIG_ENDIAN +#elif defined( _LITTLE_ENDIAN ) +# define PLATFORM_BYTE_ORDER IS_LITTLE_ENDIAN +#endif + +#if defined( __BIG_ENDIAN ) && defined( __LITTLE_ENDIAN ) +# if defined( __BYTE_ORDER ) && __BYTE_ORDER == __BIG_ENDIAN +# define PLATFORM_BYTE_ORDER IS_BIG_ENDIAN +# elif defined( __BYTE_ORDER ) && __BYTE_ORDER == __LITTLE_ENDIAN +# define PLATFORM_BYTE_ORDER IS_LITTLE_ENDIAN +# endif +#elif defined( __BIG_ENDIAN ) +# define PLATFORM_BYTE_ORDER IS_BIG_ENDIAN +#elif defined( __LITTLE_ENDIAN ) +# define PLATFORM_BYTE_ORDER IS_LITTLE_ENDIAN +#endif + +#if defined( __BIG_ENDIAN__ ) && defined( __LITTLE_ENDIAN__ ) +# if defined( __BYTE_ORDER__ ) && __BYTE_ORDER__ == __BIG_ENDIAN__ +# define PLATFORM_BYTE_ORDER IS_BIG_ENDIAN +# elif defined( __BYTE_ORDER__ ) && __BYTE_ORDER__ == __LITTLE_ENDIAN__ +# define PLATFORM_BYTE_ORDER IS_LITTLE_ENDIAN +# endif +#elif defined( __BIG_ENDIAN__ ) +# define PLATFORM_BYTE_ORDER IS_BIG_ENDIAN +#elif defined( __LITTLE_ENDIAN__ ) +# define PLATFORM_BYTE_ORDER IS_LITTLE_ENDIAN +#endif + +/* if the platform byte order could not be determined, then try to */ +/* set this define using common machine defines */ +#if !defined(PLATFORM_BYTE_ORDER) + +#if defined( __alpha__ ) || defined( __alpha ) || defined( i386 ) || \ + defined( __i386__ ) || defined( _M_I86 ) || defined( _M_IX86 ) || \ + defined( __OS2__ ) || defined( sun386 ) || defined( __TURBOC__ ) || \ + defined( vax ) || defined( vms ) || defined( VMS ) || \ + defined( __VMS ) || defined( _M_X64 ) +# define PLATFORM_BYTE_ORDER IS_LITTLE_ENDIAN + +#elif defined( AMIGA ) || defined( applec ) || defined( __AS400__ ) || \ + defined( _CRAY ) || defined( __hppa ) || defined( __hp9000 ) || \ + defined( ibm370 ) || defined( mc68000 ) || defined( m68k ) || \ + defined( __MRC__ ) || defined( __MVS__ ) || defined( __MWERKS__ ) || \ + defined( sparc ) || defined( __sparc) || defined( SYMANTEC_C ) || \ + defined( __VOS__ ) || defined( __TIGCC__ ) || defined( __TANDEM ) || \ + defined( THINK_C ) || defined( __VMCMS__ ) || defined( _AIX ) +# define PLATFORM_BYTE_ORDER IS_BIG_ENDIAN + +#elif defined(__arm__) +# ifdef __BIG_ENDIAN +# define PLATFORM_BYTE_ORDER IS_BIG_ENDIAN +# else +# define PLATFORM_BYTE_ORDER IS_LITTLE_ENDIAN +# endif +#elif 1 /* **** EDIT HERE IF NECESSARY **** */ +# define PLATFORM_BYTE_ORDER IS_LITTLE_ENDIAN +#elif 0 /* **** EDIT HERE IF NECESSARY **** */ +# define PLATFORM_BYTE_ORDER IS_BIG_ENDIAN +#else +# error Please edit lines 132 or 134 in brg_endian.h to set the platform byte order +#endif + +#endif + +#endif diff --git a/c_src/displayIntermediateValues.c b/c_src/displayIntermediateValues.c new file mode 100755 index 0000000..f3bf9e2 --- /dev/null +++ b/c_src/displayIntermediateValues.c @@ -0,0 +1,117 @@ +/* +The Keccak sponge function, designed by Guido Bertoni, Joan Daemen, +Michaël Peeters and Gilles Van Assche. For more information, feedback or +questions, please refer to our website: http://keccak.noekeon.org/ + +Implementation by the designers, +hereby denoted as "the implementer". + +To the extent possible under law, the implementer has waived all copyright +and related or neighboring rights to the source code in this file. +http://creativecommons.org/publicdomain/zero/1.0/ +*/ + +#include +#include "displayIntermediateValues.h" +#include "KeccakNISTInterface.h" + +FILE *intermediateValueFile = 0; +int displayLevel = 0; + +void displaySetIntermediateValueFile(FILE *f) +{ + intermediateValueFile = f; +} + +void displaySetLevel(int level) +{ + displayLevel = level; +} + +void displayBytes(int level, const char *text, const unsigned char *bytes, unsigned int size) +{ + unsigned int i; + + if ((intermediateValueFile) && (level <= displayLevel)) { + fprintf(intermediateValueFile, "%s:\n", text); + for(i=0; i> iBit) & 0x01) != 0); + } + fprintf(intermediateValueFile, "\n"); + fprintf(intermediateValueFile, "\n"); + } +} + +void displayStateAsBytes(int level, const char *text, const unsigned char *state) +{ + displayBytes(level, text, state, KeccakPermutationSizeInBytes); +} + +void displayStateAs32bitWords(int level, const char *text, const unsigned int *state) +{ + unsigned int i; + + if ((intermediateValueFile) && (level <= displayLevel)) { + fprintf(intermediateValueFile, "%s:\n", text); + for(i=0; i> 32)); + fprintf(intermediateValueFile, "%08X", (unsigned int)(state[i] & 0xFFFFFFFFULL)); + if ((i%5) == 4) + fprintf(intermediateValueFile, "\n"); + else + fprintf(intermediateValueFile, " "); + } + } +} + +void displayRoundNumber(int level, unsigned int i) +{ + if ((intermediateValueFile) && (level <= displayLevel)) { + fprintf(intermediateValueFile, "\n"); + fprintf(intermediateValueFile, "--- Round %d ---\n", i); + fprintf(intermediateValueFile, "\n"); + } +} + +void displayText(int level, const char *text) +{ + if ((intermediateValueFile) && (level <= displayLevel)) { + fprintf(intermediateValueFile, text); + fprintf(intermediateValueFile, "\n"); + fprintf(intermediateValueFile, "\n"); + } +} diff --git a/c_src/displayIntermediateValues.h b/c_src/displayIntermediateValues.h new file mode 100755 index 0000000..1d6c6c8 --- /dev/null +++ b/c_src/displayIntermediateValues.h @@ -0,0 +1,29 @@ +/* +The Keccak sponge function, designed by Guido Bertoni, Joan Daemen, +Michaël Peeters and Gilles Van Assche. For more information, feedback or +questions, please refer to our website: http://keccak.noekeon.org/ + +Implementation by the designers, +hereby denoted as "the implementer". + +To the extent possible under law, the implementer has waived all copyright +and related or neighboring rights to the source code in this file. +http://creativecommons.org/publicdomain/zero/1.0/ +*/ + +#ifndef _displayIntermediateValues_h_ +#define _displayIntermediateValues_h_ + +#include + +void displaySetIntermediateValueFile(FILE *f); +void displaySetLevel(int level); +void displayBytes(int level, const char *text, const unsigned char *bytes, unsigned int size); +void displayBits(int level, const char *text, const unsigned char *data, unsigned int size, int MSBfirst); +void displayStateAsBytes(int level, const char *text, const unsigned char *state); +void displayStateAs32bitWords(int level, const char *text, const unsigned int *state); +void displayStateAs64bitWords(int level, const char *text, const unsigned long long int *state); +void displayRoundNumber(int level, unsigned int i); +void displayText(int level, const char *text); + +#endif diff --git a/c_src/sha3_nif.c b/c_src/sha3_nif.c new file mode 100644 index 0000000..d485250 --- /dev/null +++ b/c_src/sha3_nif.c @@ -0,0 +1,144 @@ +#include "erl_nif.h" +#include "KeccakNISTInterface.h" + +typedef struct nif_hash_context nif_hash_context; + +struct nif_hash_context { + int bitlen; + hashState state; +}; + +static void sha3_resource_cleanup(ErlNifEnv* env, void* arg); +static ERL_NIF_TERM nif_hash_init(ErlNifEnv* env, int argc, + const ERL_NIF_TERM argv[]); +static ERL_NIF_TERM nif_hash_update(ErlNifEnv* env, int argc, + const ERL_NIF_TERM argv[]); +static ERL_NIF_TERM nif_hash_final(ErlNifEnv* env, int argc, + const ERL_NIF_TERM argv[]); +static ERL_NIF_TERM nif_hash(ErlNifEnv* env, int argc, + const ERL_NIF_TERM argv[]); + +static ErlNifFunc nif_funcs[] = +{ + {"hash_init", 1, nif_hash_init}, + {"hash_update", 2, nif_hash_update}, + {"hash_final", 1, nif_hash_final}, + {"hash", 2, nif_hash} +}; + +static ErlNifResourceType *sha3_resource_type; + +static void +sha3_resource_cleanup(ErlNifEnv* env, void* arg) +{ + /* do nothing */ +} + +static ERL_NIF_TERM +nif_hash_init(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) +{ + ERL_NIF_TERM ctxt_term; + nif_hash_context *ctxt; + int bitlen; + + if (!enif_get_int(env, argv[0], &bitlen)) + return 0; + + if (bitlen != 224 && bitlen != 256 && bitlen != 384 && bitlen != 512) + return 0; + + ctxt = enif_alloc_resource(sha3_resource_type, sizeof(nif_hash_context)); + ctxt->bitlen = bitlen; + Init(&ctxt->state, bitlen); + ctxt_term = enif_make_resource(env, ctxt); + enif_release_resource(ctxt); + + return ctxt_term; +} + +static ERL_NIF_TERM +nif_hash_update(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) +{ + ERL_NIF_TERM ctxt_term; + ErlNifBinary src_bin; + nif_hash_context *ctxt, *new; + hashState state; + + if (!enif_get_resource(env, argv[0], sha3_resource_type, (void **)&ctxt) || + !enif_inspect_binary(env, argv[1], &src_bin)) + return 0; + + state = ctxt->state; + Update(&state, src_bin.data, src_bin.size * 8); + new = enif_alloc_resource(sha3_resource_type, sizeof(nif_hash_context)); + new->bitlen = ctxt->bitlen; + new->state = state; + ctxt_term = enif_make_resource(env, new); + enif_release_resource(new); + + return ctxt_term; +} + +static ERL_NIF_TERM +nif_hash_final(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) +{ + ERL_NIF_TERM digest_term; + ErlNifBinary digest_bin; + nif_hash_context *ctxt; + hashState state; + + if (!enif_get_resource(env, argv[0], sha3_resource_type, (void **)&ctxt)) + return 0; + + state = ctxt->state; + enif_alloc_binary(ctxt->bitlen / 8, &digest_bin); + Final(&state, digest_bin.data); + digest_term = enif_make_binary(env, &digest_bin); + enif_release_binary(&digest_bin); + + return digest_term; +} + +static ERL_NIF_TERM +nif_hash(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) +{ + ERL_NIF_TERM digest_term; + ErlNifBinary src_bin, digest_bin; + int bitlen; + + if (!enif_get_int(env, argv[0], &bitlen) || + !enif_inspect_binary(env, argv[1], &src_bin)) + return 0; + + if (bitlen != 224 && bitlen != 256 && bitlen != 384 && bitlen != 512) + return 0; + + enif_alloc_binary(bitlen / 8, &digest_bin); + Hash(bitlen, src_bin.data, src_bin.size * 8, digest_bin.data); + digest_term = enif_make_binary(env, &digest_bin); + enif_release_binary(&digest_bin); + + return digest_term; +} + +static int +on_load(ErlNifEnv* env, void** priv_data, ERL_NIF_TERM load_info) +{ + ErlNifResourceFlags flags = ERL_NIF_RT_CREATE | ERL_NIF_RT_TAKEOVER; + + sha3_resource_type = enif_open_resource_type(env, NULL, "sha3_resource", + &sha3_resource_cleanup, flags, NULL); + if (sha3_resource_type == NULL) + return -1; + else + return 0; +} + +static void +on_unload(ErlNifEnv* env, void* priv_data) +{ + /* do nothing */ +} + +ERL_NIF_INIT(sha3, nif_funcs, &on_load, NULL, NULL, &on_unload); + diff --git a/doc/overview.edoc b/doc/overview.edoc new file mode 100644 index 0000000..41de035 --- /dev/null +++ b/doc/overview.edoc @@ -0,0 +1,8 @@ +@title SHA-3 for Erlang +@author SUZUKI Tetsuya +@copyright 2012- SUZUKI Tetsuya +@version 0.1.0 +@reference Wikipedia: SHA-3 +@reference NIST: Cryptographic Hash Algorithm Competition +@reference The Keccak sponge function family + diff --git a/rebar b/rebar new file mode 100755 index 0000000000000000000000000000000000000000..e364a2b117a3b4b6da36eb55e42d20c98e7d4fd0 GIT binary patch literal 148087 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%0DRBeMJm0<<;|6NMsZ7dw)eppOJe-ACy@@UrsqP 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

Uy~Q$=1>kXb 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 z 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%0A7L;Hhn1h%v)_lyubYC#+0{i-oV4a4)*dI8d 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 Jpb!Ma{{z#A=@$S1 literal 0 HcmV?d00001 diff --git a/rebar.config b/rebar.config new file mode 100644 index 0000000..16377e2 --- /dev/null +++ b/rebar.config @@ -0,0 +1,33 @@ +{erl_opts, [{i, "src"}, + warnings_as_errors, + {w, all}, + warn_export_all]}. + +{clean_files, [".eunit", + "ebin/*.beam"]}. + +{port_env, [{"CFLAGS", "$CFLAGS -O2 -finline-functions -fomit-frame-pointer -fno-strict-aliasing -Wmissing-prototypes -Wall -std=c99"}]}. + +{port_specs, [ + % TODO: support optimization + % {"i386", "priv/sha3_nif.so", ["c_src/sha3_nif.c", + % "c_src/KeccakNISTInterface.c", + % "c_src/KeccakSponge.c", + % "c_src/KeccakF-1600-opt32.c", + % "c_src/displayIntermediateValues.c"]}, + % {"x86_64", "priv/sha3_nif.so", ["c_src/sha3_nif.c", + % "c_src/KeccakNISTInterface.c", + % "c_src/KeccakSponge.c", + % "c_src/KeccakF-1600-opt64.c", + % "c_src/displayIntermediateValues.c"]}, + {"priv/sha3_nif.so", ["c_src/sha3_nif.c", + "c_src/KeccakNISTInterface.c", + "c_src/KeccakSponge.c", + "c_src/KeccakF-1600-reference.c", + "c_src/displayIntermediateValues.c"]} +]}. + +{eunit_opts, [{report,{eunit_surefire,[{dir,"."}]}}]}. + +{xref_checks, [fail_on_warning, undefined_function_calls]}. + diff --git a/src/sha3.app.src b/src/sha3.app.src new file mode 100644 index 0000000..aee6773 --- /dev/null +++ b/src/sha3.app.src @@ -0,0 +1,12 @@ +{application, sha3, + [ + {description, ""}, + {vsn, "0.1.0"}, + {registered, []}, + {applications, [ + kernel, + stdlib + ]}, + {modules, [sha3]}, + {env, []} + ]}. diff --git a/src/sha3.erl b/src/sha3.erl new file mode 100644 index 0000000..1b15118 --- /dev/null +++ b/src/sha3.erl @@ -0,0 +1,41 @@ +-module(sha3). + +-export([hash_init/1, hash_update/2, hash_final/1, hash/2]). + +-on_load(init/0). + +-type bitlen() :: 224 | 256 | 384 | 512. +-type context() :: binary(). +-type digest() :: <<_:224>> | <<_:256>> | <<_:384>> | <<_:512>>. + +-define(nif_stub, nif_stub_error(?LINE)). +nif_stub_error(Line) -> + erlang:nif_error({nif_not_loaded,module,?MODULE,line,Line}). + +init() -> + PrivDir = case code:priv_dir(?MODULE) of + {error, bad_name} -> + EbinDir = filename:dirname(code:which(?MODULE)), + AppPath = filename:dirname(EbinDir), + filename:join(AppPath, "priv"); + Path -> + Path + end, + erlang:load_nif(filename:join(PrivDir, sha3_nif), 0). + +-spec hash_init(bitlen()) -> context(). +hash_init(_BitLen) -> + ?nif_stub. + +-spec hash_update(context(), binary()) -> context(). +hash_update(_Context, _Binary) -> + ?nif_stub. + +-spec hash_final(context()) -> digest(). +hash_final(_Context) -> + ?nif_stub. + +-spec hash(bitlen(), binary()) -> digest(). +hash(_BitLen, _Binary) -> + ?nif_stub. + diff --git a/test/sha3_tests.erl b/test/sha3_tests.erl new file mode 100644 index 0000000..c8b262f --- /dev/null +++ b/test/sha3_tests.erl @@ -0,0 +1,48 @@ +-module(sha3_tests). + +-include_lib("eunit/include/eunit.hrl"). + +simple_data() -> + <<16#00112233445566778899AABBCCDDEEFF:128>>. + +simple_digest() -> + <<16#038907E89C919CD8F90A7FBC5A88FF9278108DAEF3EBCDA0CEB383E1:224>>. + +simple_test() -> + Digest = sha3:hash(224, simple_data()), + Expected = simple_digest(), + ?assertEqual(Expected, Digest). + +update_test() -> + Context1 = sha3:hash_init(224), + Context2 = sha3:hash_update(Context1, simple_data()), + Digest = sha3:hash_final(Context2), + Expected = simple_digest(), + ?assertEqual(Expected, Digest). + +update_context_test() -> + Context1 = sha3:hash_init(224), + Context2 = sha3:hash_update(Context1, simple_data()), + Context3 = sha3:hash_update(Context1, simple_data()), + Digest1 = sha3:hash_final(Context2), + Digest2 = sha3:hash_final(Context3), + Expected = simple_digest(), + ?assertEqual(Expected, Digest1), + ?assertEqual(Expected, Digest2). + +hash_224_test() -> + ?assertEqual(<<16#038907E89C919CD8F90A7FBC5A88FF9278108DAEF3EBCDA0CEB383E1:224>>, + sha3:hash(224, <<16#00112233445566778899AABBCCDDEEFF:128>>)). + +hash_256_test() -> + ?assertEqual(<<16#22BCE46032802AF0ABFACF3768F7BE04A34F5F01DF60F44FFD52D3CA937350C0:256>>, + sha3:hash(256, <<16#00112233445566778899AABBCCDDEEFF:128>>)). + +hash_384_test() -> + ?assertEqual(<<16#25FAC1ADECBE1B254976FE32C2FE78829B23D7D84316141ECD208D6806A9DB4352A014ADA4106BA0D210DDA0FD18E150:384>>, + sha3:hash(384, <<16#00112233445566778899AABBCCDDEEFF:128>>)). + +hash_512_test() -> + ?assertEqual(<<16#94EE7851163C39C3489373AA0BF885D95925EAD7484C586D2E0D01D9C8069D3C30E2EEA2DC63A91B517FE53E43A31D764A2154A2DA92876366B138ABC4406805:512>>, + sha3:hash(512, <<16#00112233445566778899AABBCCDDEEFF:128>>)). +