#!/usr/bin/env perl # Copyright 2017-2020 The OpenSSL Project Authors. All Rights Reserved. # # Licensed under the Apache License 2.0 (the "License"). You may not use # this file except in compliance with the License. You can obtain a copy # in the file LICENSE in the source distribution or at # https://www.openssl.org/source/license.html # # ==================================================================== # Written by Andy Polyakov for the OpenSSL # project. The module is, however, dual licensed under OpenSSL and # CRYPTOGAMS licenses depending on where you obtain it. For further # details see http://www.openssl.org/~appro/cryptogams/. # ==================================================================== # # Keccak-1600 for ARMv4. # # June 2017. # # Non-NEON code is KECCAK_1X variant (see sha/keccak1600.c) with bit # interleaving. How does it compare to Keccak Code Package? It's as # fast, but several times smaller, and is endian- and ISA-neutral. ISA # neutrality means that minimum ISA requirement is ARMv4, yet it can # be assembled even as Thumb-2. NEON code path is KECCAK_1X_ALT with # register layout taken from Keccak Code Package. It's also as fast, # in fact faster by 10-15% on some processors, and endian-neutral. # # August 2017. # # Switch to KECCAK_2X variant for non-NEON code and merge almost 1/2 # of rotate instructions with logical ones. This resulted in ~10% # improvement on most processors. Switch to KECCAK_2X effectively # minimizes re-loads from temporary storage, and merged rotates just # eliminate corresponding instructions. As for latter. When examining # code you'll notice commented ror instructions. These are eliminated # ones, and you should trace destination register below to see what's # going on. Just in case, why not all rotates are eliminated. Trouble # is that you have operations that require both inputs to be rotated, # e.g. 'eor a,b>>>x,c>>>y'. This conundrum is resolved by using # 'eor a,b,c>>>(x-y)' and then merge-rotating 'a' in next operation # that takes 'a' as input. And thing is that this next operation can # be in next round. It's totally possible to "carry" rotate "factors" # to the next round, but it makes code more complex. And the last word # is the keyword, i.e. "almost 1/2" is kind of complexity cap [for the # time being]... # # Reduce per-round instruction count in Thumb-2 case by 16%. This is # achieved by folding ldr/str pairs to their double-word counterparts. # Theoretically this should have improved performance on single-issue # cores, such as Cortex-A5/A7, by 19%. Reality is a bit different, as # usual... # ######################################################################## # Numbers are cycles per processed byte. Non-NEON results account even # for input bit interleaving. # # r=1088(*) Thumb-2(**) NEON # # ARM11xx 82/+150% # Cortex-A5 88/+160%, 86, 36 # Cortex-A7 78/+160%, 68, 34 # Cortex-A8 51/+230%, 57, 30 # Cortex-A9 53/+210%, 51, 26 # Cortex-A15 42/+160%, 38, 18 # Snapdragon S4 43/+210%, 38, 24 # # (*) Corresponds to SHA3-256. Percentage after slash is improvement # over compiler-generated KECCAK_2X reference code. # (**) Thumb-2 results for Cortex-A5/A7 are likely to apply even to # Cortex-Mx, x>=3. Otherwise, non-NEON results for NEON-capable # processors are presented mostly for reference purposes. # $output is the last argument if it looks like a file (it has an extension) # $flavour is the first argument if it doesn't look like a file $output = $#ARGV >= 0 && $ARGV[$#ARGV] =~ m|\.\w+$| ? pop : undef; $flavour = $#ARGV >= 0 && $ARGV[0] !~ m|\.| ? shift : undef; if ($flavour && $flavour ne "void") { $0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1; ( $xlate="${dir}arm-xlate.pl" and -f $xlate ) or ( $xlate="${dir}../../perlasm/arm-xlate.pl" and -f $xlate) or die "can't locate arm-xlate.pl"; open STDOUT,"| \"$^X\" $xlate $flavour \"$output\"" or die "can't call $xlate: $!"; } else { $output and open STDOUT,">$output"; } my @C = map("r$_",(0..9)); my @E = map("r$_",(10..12,14)); ######################################################################## # Stack layout # ----->+-----------------------+ # | uint64_t A[5][5] | # | ... | # +200->+-----------------------+ # | uint64_t D[5] | # | ... | # +240->+-----------------------+ # | uint64_t T[5][5] | # | ... | # +440->+-----------------------+ # | saved lr | # +444->+-----------------------+ # | loop counter | # +448->+-----------------------+ # | ... my @A = map([ 8*$_, 8*($_+1), 8*($_+2), 8*($_+3), 8*($_+4) ], (0,5,10,15,20)); my @D = map(8*$_, (25..29)); my @T = map([ 8*$_, 8*($_+1), 8*($_+2), 8*($_+3), 8*($_+4) ], (30,35,40,45,50)); $code.=<<___; #include "arm_arch.h" #if defined(__thumb2__) .syntax unified .thumb #else .code 32 #endif .text .type iotas32, %object .align 5 iotas32: .long 0x00000001, 0x00000000 .long 0x00000000, 0x00000089 .long 0x00000000, 0x8000008b .long 0x00000000, 0x80008080 .long 0x00000001, 0x0000008b .long 0x00000001, 0x00008000 .long 0x00000001, 0x80008088 .long 0x00000001, 0x80000082 .long 0x00000000, 0x0000000b .long 0x00000000, 0x0000000a .long 0x00000001, 0x00008082 .long 0x00000000, 0x00008003 .long 0x00000001, 0x0000808b .long 0x00000001, 0x8000000b .long 0x00000001, 0x8000008a .long 0x00000001, 0x80000081 .long 0x00000000, 0x80000081 .long 0x00000000, 0x80000008 .long 0x00000000, 0x00000083 .long 0x00000000, 0x80008003 .long 0x00000001, 0x80008088 .long 0x00000000, 0x80000088 .long 0x00000001, 0x00008000 .long 0x00000000, 0x80008082 .size iotas32,.-iotas32 .type KeccakF1600_int, %function .align 5 KeccakF1600_int: add @C[9],sp,#$A[4][2] add @E[2],sp,#$A[0][0] add @E[0],sp,#$A[1][0] ldmia @C[9],{@C[4]-@C[9]} @ A[4][2..4] KeccakF1600_enter: str lr,[sp,#440] eor @E[1],@E[1],@E[1] str @E[1],[sp,#444] b .Lround2x .align 4 .Lround2x: ___ sub Round { my (@A,@R); (@A[0..4],@R) = @_; $code.=<<___; ldmia @E[2],{@C[0]-@C[3]} @ A[0][0..1] ldmia @E[0],{@E[0]-@E[2],@E[3]} @ A[1][0..1] #ifdef __thumb2__ eor @C[0],@C[0],@E[0] eor @C[1],@C[1],@E[1] eor @C[2],@C[2],@E[2] ldrd @E[0],@E[1],[sp,#$A[1][2]] eor @C[3],@C[3],@E[3] ldrd @E[2],@E[3],[sp,#$A[1][3]] eor @C[4],@C[4],@E[0] eor @C[5],@C[5],@E[1] eor @C[6],@C[6],@E[2] ldrd @E[0],@E[1],[sp,#$A[1][4]] eor @C[7],@C[7],@E[3] ldrd @E[2],@E[3],[sp,#$A[2][0]] eor @C[8],@C[8],@E[0] eor @C[9],@C[9],@E[1] eor @C[0],@C[0],@E[2] ldrd @E[0],@E[1],[sp,#$A[2][1]] eor @C[1],@C[1],@E[3] ldrd @E[2],@E[3],[sp,#$A[2][2]] eor @C[2],@C[2],@E[0] eor @C[3],@C[3],@E[1] eor @C[4],@C[4],@E[2] ldrd @E[0],@E[1],[sp,#$A[2][3]] eor @C[5],@C[5],@E[3] ldrd @E[2],@E[3],[sp,#$A[2][4]] eor @C[6],@C[6],@E[0] eor @C[7],@C[7],@E[1] eor @C[8],@C[8],@E[2] ldrd @E[0],@E[1],[sp,#$A[3][0]] eor @C[9],@C[9],@E[3] ldrd @E[2],@E[3],[sp,#$A[3][1]] eor @C[0],@C[0],@E[0] eor @C[1],@C[1],@E[1] eor @C[2],@C[2],@E[2] ldrd @E[0],@E[1],[sp,#$A[3][2]] eor @C[3],@C[3],@E[3] ldrd @E[2],@E[3],[sp,#$A[3][3]] eor @C[4],@C[4],@E[0] eor @C[5],@C[5],@E[1] eor @C[6],@C[6],@E[2] ldrd @E[0],@E[1],[sp,#$A[3][4]] eor @C[7],@C[7],@E[3] ldrd @E[2],@E[3],[sp,#$A[4][0]] eor @C[8],@C[8],@E[0] eor @C[9],@C[9],@E[1] eor @C[0],@C[0],@E[2] ldrd @E[0],@E[1],[sp,#$A[4][1]] eor @C[1],@C[1],@E[3] ldrd @E[2],@E[3],[sp,#$A[0][2]] eor @C[2],@C[2],@E[0] eor @C[3],@C[3],@E[1] eor @C[4],@C[4],@E[2] ldrd @E[0],@E[1],[sp,#$A[0][3]] eor @C[5],@C[5],@E[3] ldrd @E[2],@E[3],[sp,#$A[0][4]] #else eor @C[0],@C[0],@E[0] add @E[0],sp,#$A[1][2] eor @C[1],@C[1],@E[1] eor @C[2],@C[2],@E[2] eor @C[3],@C[3],@E[3] ldmia @E[0],{@E[0]-@E[2],@E[3]} @ A[1][2..3] eor @C[4],@C[4],@E[0] add @E[0],sp,#$A[1][4] eor @C[5],@C[5],@E[1] eor @C[6],@C[6],@E[2] eor @C[7],@C[7],@E[3] ldmia @E[0],{@E[0]-@E[2],@E[3]} @ A[1][4]..A[2][0] eor @C[8],@C[8],@E[0] add @E[0],sp,#$A[2][1] eor @C[9],@C[9],@E[1] eor @C[0],@C[0],@E[2] eor @C[1],@C[1],@E[3] ldmia @E[0],{@E[0]-@E[2],@E[3]} @ A[2][1..2] eor @C[2],@C[2],@E[0] add @E[0],sp,#$A[2][3] eor @C[3],@C[3],@E[1] eor @C[4],@C[4],@E[2] eor @C[5],@C[5],@E[3] ldmia @E[0],{@E[0]-@E[2],@E[3]} @ A[2][3..4] eor @C[6],@C[6],@E[0] add @E[0],sp,#$A[3][0] eor @C[7],@C[7],@E[1] eor @C[8],@C[8],@E[2] eor @C[9],@C[9],@E[3] ldmia @E[0],{@E[0]-@E[2],@E[3]} @ A[3][0..1] eor @C[0],@C[0],@E[0] add @E[0],sp,#$A[3][2] eor @C[1],@C[1],@E[1] eor @C[2],@C[2],@E[2] eor @C[3],@C[3],@E[3] ldmia @E[0],{@E[0]-@E[2],@E[3]} @ A[3][2..3] eor @C[4],@C[4],@E[0] add @E[0],sp,#$A[3][4] eor @C[5],@C[5],@E[1] eor @C[6],@C[6],@E[2] eor @C[7],@C[7],@E[3] ldmia @E[0],{@E[0]-@E[2],@E[3]} @ A[3][4]..A[4][0] eor @C[8],@C[8],@E[0] ldr @E[0],[sp,#$A[4][1]] @ A[4][1] eor @C[9],@C[9],@E[1] ldr @E[1],[sp,#$A[4][1]+4] eor @C[0],@C[0],@E[2] ldr @E[2],[sp,#$A[0][2]] @ A[0][2] eor @C[1],@C[1],@E[3] ldr @E[3],[sp,#$A[0][2]+4] eor @C[2],@C[2],@E[0] add @E[0],sp,#$A[0][3] eor @C[3],@C[3],@E[1] eor @C[4],@C[4],@E[2] eor @C[5],@C[5],@E[3] ldmia @E[0],{@E[0]-@E[2],@E[3]} @ A[0][3..4] #endif eor @C[6],@C[6],@E[0] eor @C[7],@C[7],@E[1] eor @C[8],@C[8],@E[2] eor @C[9],@C[9],@E[3] eor @E[0],@C[0],@C[5],ror#32-1 @ E[0] = ROL64(C[2], 1) ^ C[0]; str.l @E[0],[sp,#$D[1]] @ D[1] = E[0] eor @E[1],@C[1],@C[4] str.h @E[1],[sp,#$D[1]+4] eor @E[2],@C[6],@C[1],ror#32-1 @ E[1] = ROL64(C[0], 1) ^ C[3]; eor @E[3],@C[7],@C[0] str.l @E[2],[sp,#$D[4]] @ D[4] = E[1] eor @C[0],@C[8],@C[3],ror#32-1 @ C[0] = ROL64(C[1], 1) ^ C[4]; str.h @E[3],[sp,#$D[4]+4] eor @C[1],@C[9],@C[2] str.l @C[0],[sp,#$D[0]] @ D[0] = C[0] eor @C[2],@C[2],@C[7],ror#32-1 @ C[1] = ROL64(C[3], 1) ^ C[1]; ldr.l @C[7],[sp,#$A[3][3]] eor @C[3],@C[3],@C[6] str.h @C[1],[sp,#$D[0]+4] ldr.h @C[6],[sp,#$A[3][3]+4] str.l @C[2],[sp,#$D[2]] @ D[2] = C[1] eor @C[4],@C[4],@C[9],ror#32-1 @ C[2] = ROL64(C[4], 1) ^ C[2]; str.h @C[3],[sp,#$D[2]+4] eor @C[5],@C[5],@C[8] ldr.l @C[8],[sp,#$A[4][4]] ldr.h @C[9],[sp,#$A[4][4]+4] str.l @C[4],[sp,#$D[3]] @ D[3] = C[2] eor @C[7],@C[7],@C[4] str.h @C[5],[sp,#$D[3]+4] eor @C[6],@C[6],@C[5] ldr.l @C[4],[sp,#$A[0][0]] @ ror @C[7],@C[7],#32-10 @ C[3] = ROL64(A[3][3] ^ C[2], rhotates[3][3]); /* D[3] */ @ ror @C[6],@C[6],#32-11 ldr.h @C[5],[sp,#$A[0][0]+4] eor @C[8],@C[8],@E[2] eor @C[9],@C[9],@E[3] ldr.l @E[2],[sp,#$A[2][2]] eor @C[0],@C[0],@C[4] ldr.h @E[3],[sp,#$A[2][2]+4] @ ror @C[8],@C[8],#32-7 @ C[4] = ROL64(A[4][4] ^ E[1], rhotates[4][4]); /* D[4] */ @ ror @C[9],@C[9],#32-7 eor @C[1],@C[1],@C[5] @ C[0] = A[0][0] ^ C[0]; /* rotate by 0 */ /* D[0] */ eor @E[2],@E[2],@C[2] ldr.l @C[2],[sp,#$A[1][1]] eor @E[3],@E[3],@C[3] ldr.h @C[3],[sp,#$A[1][1]+4] ror @C[5],@E[2],#32-21 @ C[2] = ROL64(A[2][2] ^ C[1], rhotates[2][2]); /* D[2] */ ldr @E[2],[sp,#444] @ load counter eor @C[2],@C[2],@E[0] adr @E[0],iotas32 ror @C[4],@E[3],#32-22 add @E[3],@E[0],@E[2] eor @C[3],@C[3],@E[1] ___ $code.=<<___ if ($A[0][0] != $T[0][0]); ldmia @E[3],{@E[0],@E[1]} @ iotas[i] ___ $code.=<<___ if ($A[0][0] == $T[0][0]); ldr.l @E[0],[@E[3],#8] @ iotas[i].lo add @E[2],@E[2],#16 ldr.h @E[1],[@E[3],#12] @ iotas[i].hi cmp @E[2],#192 str @E[2],[sp,#444] @ store counter ___ $code.=<<___; bic @E[2],@C[4],@C[2],ror#32-22 bic @E[3],@C[5],@C[3],ror#32-22 ror @C[2],@C[2],#32-22 @ C[1] = ROL64(A[1][1] ^ E[0], rhotates[1][1]); /* D[1] */ ror @C[3],@C[3],#32-22 eor @E[2],@E[2],@C[0] eor @E[3],@E[3],@C[1] eor @E[0],@E[0],@E[2] eor @E[1],@E[1],@E[3] str.l @E[0],[sp,#$R[0][0]] @ R[0][0] = C[0] ^ (~C[1] & C[2]) ^ iotas[i]; bic @E[2],@C[6],@C[4],ror#11 str.h @E[1],[sp,#$R[0][0]+4] bic @E[3],@C[7],@C[5],ror#10 bic @E[0],@C[8],@C[6],ror#32-(11-7) bic @E[1],@C[9],@C[7],ror#32-(10-7) eor @E[2],@C[2],@E[2],ror#32-11 str.l @E[2],[sp,#$R[0][1]] @ R[0][1] = C[1] ^ (~C[2] & C[3]); eor @E[3],@C[3],@E[3],ror#32-10 str.h @E[3],[sp,#$R[0][1]+4] eor @E[0],@C[4],@E[0],ror#32-7 eor @E[1],@C[5],@E[1],ror#32-7 str.l @E[0],[sp,#$R[0][2]] @ R[0][2] = C[2] ^ (~C[3] & C[4]); bic @E[2],@C[0],@C[8],ror#32-7 str.h @E[1],[sp,#$R[0][2]+4] bic @E[3],@C[1],@C[9],ror#32-7 eor @E[2],@E[2],@C[6],ror#32-11 str.l @E[2],[sp,#$R[0][3]] @ R[0][3] = C[3] ^ (~C[4] & C[0]); eor @E[3],@E[3],@C[7],ror#32-10 str.h @E[3],[sp,#$R[0][3]+4] bic @E[0],@C[2],@C[0] add @E[3],sp,#$D[3] ldr.l @C[0],[sp,#$A[0][3]] @ A[0][3] bic @E[1],@C[3],@C[1] ldr.h @C[1],[sp,#$A[0][3]+4] eor @E[0],@E[0],@C[8],ror#32-7 eor @E[1],@E[1],@C[9],ror#32-7 str.l @E[0],[sp,#$R[0][4]] @ R[0][4] = C[4] ^ (~C[0] & C[1]); add @C[9],sp,#$D[0] str.h @E[1],[sp,#$R[0][4]+4] ldmia @E[3],{@E[0]-@E[2],@E[3]} @ D[3..4] ldmia @C[9],{@C[6]-@C[9]} @ D[0..1] ldr.l @C[2],[sp,#$A[1][4]] @ A[1][4] eor @C[0],@C[0],@E[0] ldr.h @C[3],[sp,#$A[1][4]+4] eor @C[1],@C[1],@E[1] @ ror @C[0],@C[0],#32-14 @ C[0] = ROL64(A[0][3] ^ D[3], rhotates[0][3]); ldr.l @E[0],[sp,#$A[3][1]] @ A[3][1] @ ror @C[1],@C[1],#32-14 ldr.h @E[1],[sp,#$A[3][1]+4] eor @C[2],@C[2],@E[2] ldr.l @C[4],[sp,#$A[2][0]] @ A[2][0] eor @C[3],@C[3],@E[3] ldr.h @C[5],[sp,#$A[2][0]+4] @ ror @C[2],@C[2],#32-10 @ C[1] = ROL64(A[1][4] ^ D[4], rhotates[1][4]); @ ror @C[3],@C[3],#32-10 eor @C[6],@C[6],@C[4] ldr.l @E[2],[sp,#$D[2]] @ D[2] eor @C[7],@C[7],@C[5] ldr.h @E[3],[sp,#$D[2]+4] ror @C[5],@C[6],#32-1 @ C[2] = ROL64(A[2][0] ^ D[0], rhotates[2][0]); ror @C[4],@C[7],#32-2 eor @E[0],@E[0],@C[8] ldr.l @C[8],[sp,#$A[4][2]] @ A[4][2] eor @E[1],@E[1],@C[9] ldr.h @C[9],[sp,#$A[4][2]+4] ror @C[7],@E[0],#32-22 @ C[3] = ROL64(A[3][1] ^ D[1], rhotates[3][1]); ror @C[6],@E[1],#32-23 bic @E[0],@C[4],@C[2],ror#32-10 bic @E[1],@C[5],@C[3],ror#32-10 eor @E[2],@E[2],@C[8] eor @E[3],@E[3],@C[9] ror @C[9],@E[2],#32-30 @ C[4] = ROL64(A[4][2] ^ D[2], rhotates[4][2]); ror @C[8],@E[3],#32-31 eor @E[0],@E[0],@C[0],ror#32-14 eor @E[1],@E[1],@C[1],ror#32-14 str.l @E[0],[sp,#$R[1][0]] @ R[1][0] = C[0] ^ (~C[1] & C[2]) bic @E[2],@C[6],@C[4] str.h @E[1],[sp,#$R[1][0]+4] bic @E[3],@C[7],@C[5] eor @E[2],@E[2],@C[2],ror#32-10 str.l @E[2],[sp,#$R[1][1]] @ R[1][1] = C[1] ^ (~C[2] & C[3]); eor @E[3],@E[3],@C[3],ror#32-10 str.h @E[3],[sp,#$R[1][1]+4] bic @E[0],@C[8],@C[6] bic @E[1],@C[9],@C[7] bic @E[2],@C[0],@C[8],ror#14 bic @E[3],@C[1],@C[9],ror#14 eor @E[0],@E[0],@C[4] eor @E[1],@E[1],@C[5] str.l @E[0],[sp,#$R[1][2]] @ R[1][2] = C[2] ^ (~C[3] & C[4]); bic @C[2],@C[2],@C[0],ror#32-(14-10) str.h @E[1],[sp,#$R[1][2]+4] eor @E[2],@C[6],@E[2],ror#32-14 bic @E[1],@C[3],@C[1],ror#32-(14-10) str.l @E[2],[sp,#$R[1][3]] @ R[1][3] = C[3] ^ (~C[4] & C[0]); eor @E[3],@C[7],@E[3],ror#32-14 str.h @E[3],[sp,#$R[1][3]+4] add @E[2],sp,#$D[1] ldr.l @C[1],[sp,#$A[0][1]] @ A[0][1] eor @E[0],@C[8],@C[2],ror#32-10 ldr.h @C[0],[sp,#$A[0][1]+4] eor @E[1],@C[9],@E[1],ror#32-10 str.l @E[0],[sp,#$R[1][4]] @ R[1][4] = C[4] ^ (~C[0] & C[1]); str.h @E[1],[sp,#$R[1][4]+4] add @C[9],sp,#$D[3] ldmia @E[2],{@E[0]-@E[2],@E[3]} @ D[1..2] ldr.l @C[2],[sp,#$A[1][2]] @ A[1][2] ldr.h @C[3],[sp,#$A[1][2]+4] ldmia @C[9],{@C[6]-@C[9]} @ D[3..4] eor @C[1],@C[1],@E[0] ldr.l @C[4],[sp,#$A[2][3]] @ A[2][3] eor @C[0],@C[0],@E[1] ldr.h @C[5],[sp,#$A[2][3]+4] ror @C[0],@C[0],#32-1 @ C[0] = ROL64(A[0][1] ^ D[1], rhotates[0][1]); eor @C[2],@C[2],@E[2] ldr.l @E[0],[sp,#$A[3][4]] @ A[3][4] eor @C[3],@C[3],@E[3] ldr.h @E[1],[sp,#$A[3][4]+4] @ ror @C[2],@C[2],#32-3 @ C[1] = ROL64(A[1][2] ^ D[2], rhotates[1][2]); ldr.l @E[2],[sp,#$D[0]] @ D[0] @ ror @C[3],@C[3],#32-3 ldr.h @E[3],[sp,#$D[0]+4] eor @C[4],@C[4],@C[6] eor @C[5],@C[5],@C[7] @ ror @C[5],@C[6],#32-12 @ C[2] = ROL64(A[2][3] ^ D[3], rhotates[2][3]); @ ror @C[4],@C[7],#32-13 @ [track reverse order below] eor @E[0],@E[0],@C[8] ldr.l @C[8],[sp,#$A[4][0]] @ A[4][0] eor @E[1],@E[1],@C[9] ldr.h @C[9],[sp,#$A[4][0]+4] ror @C[6],@E[0],#32-4 @ C[3] = ROL64(A[3][4] ^ D[4], rhotates[3][4]); ror @C[7],@E[1],#32-4 eor @E[2],@E[2],@C[8] eor @E[3],@E[3],@C[9] ror @C[8],@E[2],#32-9 @ C[4] = ROL64(A[4][0] ^ D[0], rhotates[4][0]); ror @C[9],@E[3],#32-9 bic @E[0],@C[5],@C[2],ror#13-3 bic @E[1],@C[4],@C[3],ror#12-3 bic @E[2],@C[6],@C[5],ror#32-13 bic @E[3],@C[7],@C[4],ror#32-12 eor @E[0],@C[0],@E[0],ror#32-13 eor @E[1],@C[1],@E[1],ror#32-12 str.l @E[0],[sp,#$R[2][0]] @ R[2][0] = C[0] ^ (~C[1] & C[2]) eor @E[2],@E[2],@C[2],ror#32-3 str.h @E[1],[sp,#$R[2][0]+4] eor @E[3],@E[3],@C[3],ror#32-3 str.l @E[2],[sp,#$R[2][1]] @ R[2][1] = C[1] ^ (~C[2] & C[3]); bic @E[0],@C[8],@C[6] bic @E[1],@C[9],@C[7] str.h @E[3],[sp,#$R[2][1]+4] eor @E[0],@E[0],@C[5],ror#32-13 eor @E[1],@E[1],@C[4],ror#32-12 str.l @E[0],[sp,#$R[2][2]] @ R[2][2] = C[2] ^ (~C[3] & C[4]); bic @E[2],@C[0],@C[8] str.h @E[1],[sp,#$R[2][2]+4] bic @E[3],@C[1],@C[9] eor @E[2],@E[2],@C[6] eor @E[3],@E[3],@C[7] str.l @E[2],[sp,#$R[2][3]] @ R[2][3] = C[3] ^ (~C[4] & C[0]); bic @E[0],@C[2],@C[0],ror#3 str.h @E[3],[sp,#$R[2][3]+4] bic @E[1],@C[3],@C[1],ror#3 ldr.l @C[1],[sp,#$A[0][4]] @ A[0][4] [in reverse order] eor @E[0],@C[8],@E[0],ror#32-3 ldr.h @C[0],[sp,#$A[0][4]+4] eor @E[1],@C[9],@E[1],ror#32-3 str.l @E[0],[sp,#$R[2][4]] @ R[2][4] = C[4] ^ (~C[0] & C[1]); add @C[9],sp,#$D[1] str.h @E[1],[sp,#$R[2][4]+4] ldr.l @E[0],[sp,#$D[4]] @ D[4] ldr.h @E[1],[sp,#$D[4]+4] ldr.l @E[2],[sp,#$D[0]] @ D[0] ldr.h @E[3],[sp,#$D[0]+4] ldmia @C[9],{@C[6]-@C[9]} @ D[1..2] eor @C[1],@C[1],@E[0] ldr.l @C[2],[sp,#$A[1][0]] @ A[1][0] eor @C[0],@C[0],@E[1] ldr.h @C[3],[sp,#$A[1][0]+4] @ ror @C[1],@E[0],#32-13 @ C[0] = ROL64(A[0][4] ^ D[4], rhotates[0][4]); ldr.l @C[4],[sp,#$A[2][1]] @ A[2][1] @ ror @C[0],@E[1],#32-14 @ [was loaded in reverse order] ldr.h @C[5],[sp,#$A[2][1]+4] eor @C[2],@C[2],@E[2] ldr.l @E[0],[sp,#$A[3][2]] @ A[3][2] eor @C[3],@C[3],@E[3] ldr.h @E[1],[sp,#$A[3][2]+4] @ ror @C[2],@C[2],#32-18 @ C[1] = ROL64(A[1][0] ^ D[0], rhotates[1][0]); ldr.l @E[2],[sp,#$D[3]] @ D[3] @ ror @C[3],@C[3],#32-18 ldr.h @E[3],[sp,#$D[3]+4] eor @C[6],@C[6],@C[4] eor @C[7],@C[7],@C[5] ror @C[4],@C[6],#32-5 @ C[2] = ROL64(A[2][1] ^ D[1], rhotates[2][1]); ror @C[5],@C[7],#32-5 eor @E[0],@E[0],@C[8] ldr.l @C[8],[sp,#$A[4][3]] @ A[4][3] eor @E[1],@E[1],@C[9] ldr.h @C[9],[sp,#$A[4][3]+4] ror @C[7],@E[0],#32-7 @ C[3] = ROL64(A[3][2] ^ D[2], rhotates[3][2]); ror @C[6],@E[1],#32-8 eor @E[2],@E[2],@C[8] eor @E[3],@E[3],@C[9] ror @C[8],@E[2],#32-28 @ C[4] = ROL64(A[4][3] ^ D[3], rhotates[4][3]); ror @C[9],@E[3],#32-28 bic @E[0],@C[4],@C[2],ror#32-18 bic @E[1],@C[5],@C[3],ror#32-18 eor @E[0],@E[0],@C[0],ror#32-14 eor @E[1],@E[1],@C[1],ror#32-13 str.l @E[0],[sp,#$R[3][0]] @ R[3][0] = C[0] ^ (~C[1] & C[2]) bic @E[2],@C[6],@C[4] str.h @E[1],[sp,#$R[3][0]+4] bic @E[3],@C[7],@C[5] eor @E[2],@E[2],@C[2],ror#32-18 str.l @E[2],[sp,#$R[3][1]] @ R[3][1] = C[1] ^ (~C[2] & C[3]); eor @E[3],@E[3],@C[3],ror#32-18 str.h @E[3],[sp,#$R[3][1]+4] bic @E[0],@C[8],@C[6] bic @E[1],@C[9],@C[7] bic @E[2],@C[0],@C[8],ror#14 bic @E[3],@C[1],@C[9],ror#13 eor @E[0],@E[0],@C[4] eor @E[1],@E[1],@C[5] str.l @E[0],[sp,#$R[3][2]] @ R[3][2] = C[2] ^ (~C[3] & C[4]); bic @C[2],@C[2],@C[0],ror#18-14 str.h @E[1],[sp,#$R[3][2]+4] eor @E[2],@C[6],@E[2],ror#32-14 bic @E[1],@C[3],@C[1],ror#18-13 eor @E[3],@C[7],@E[3],ror#32-13 str.l @E[2],[sp,#$R[3][3]] @ R[3][3] = C[3] ^ (~C[4] & C[0]); str.h @E[3],[sp,#$R[3][3]+4] add @E[3],sp,#$D[2] ldr.l @C[0],[sp,#$A[0][2]] @ A[0][2] eor @E[0],@C[8],@C[2],ror#32-18 ldr.h @C[1],[sp,#$A[0][2]+4] eor @E[1],@C[9],@E[1],ror#32-18 str.l @E[0],[sp,#$R[3][4]] @ R[3][4] = C[4] ^ (~C[0] & C[1]); str.h @E[1],[sp,#$R[3][4]+4] ldmia @E[3],{@E[0]-@E[2],@E[3]} @ D[2..3] ldr.l @C[2],[sp,#$A[1][3]] @ A[1][3] ldr.h @C[3],[sp,#$A[1][3]+4] ldr.l @C[6],[sp,#$D[4]] @ D[4] ldr.h @C[7],[sp,#$D[4]+4] eor @C[0],@C[0],@E[0] ldr.l @C[4],[sp,#$A[2][4]] @ A[2][4] eor @C[1],@C[1],@E[1] ldr.h @C[5],[sp,#$A[2][4]+4] @ ror @C[0],@C[0],#32-31 @ C[0] = ROL64(A[0][2] ^ D[2], rhotates[0][2]); ldr.l @C[8],[sp,#$D[0]] @ D[0] @ ror @C[1],@C[1],#32-31 ldr.h @C[9],[sp,#$D[0]+4] eor @E[2],@E[2],@C[2] ldr.l @E[0],[sp,#$A[3][0]] @ A[3][0] eor @E[3],@E[3],@C[3] ldr.h @E[1],[sp,#$A[3][0]+4] ror @C[3],@E[2],#32-27 @ C[1] = ROL64(A[1][3] ^ D[3], rhotates[1][3]); ldr.l @E[2],[sp,#$D[1]] @ D[1] ror @C[2],@E[3],#32-28 ldr.h @E[3],[sp,#$D[1]+4] eor @C[6],@C[6],@C[4] eor @C[7],@C[7],@C[5] ror @C[5],@C[6],#32-19 @ C[2] = ROL64(A[2][4] ^ D[4], rhotates[2][4]); ror @C[4],@C[7],#32-20 eor @E[0],@E[0],@C[8] ldr.l @C[8],[sp,#$A[4][1]] @ A[4][1] eor @E[1],@E[1],@C[9] ldr.h @C[9],[sp,#$A[4][1]+4] ror @C[7],@E[0],#32-20 @ C[3] = ROL64(A[3][0] ^ D[0], rhotates[3][0]); ror @C[6],@E[1],#32-21 eor @C[8],@C[8],@E[2] eor @C[9],@C[9],@E[3] @ ror @C[8],@C[2],#32-1 @ C[4] = ROL64(A[4][1] ^ D[1], rhotates[4][1]); @ ror @C[9],@C[3],#32-1 bic @E[0],@C[4],@C[2] bic @E[1],@C[5],@C[3] eor @E[0],@E[0],@C[0],ror#32-31 str.l @E[0],[sp,#$R[4][0]] @ R[4][0] = C[0] ^ (~C[1] & C[2]) eor @E[1],@E[1],@C[1],ror#32-31 str.h @E[1],[sp,#$R[4][0]+4] bic @E[2],@C[6],@C[4] bic @E[3],@C[7],@C[5] eor @E[2],@E[2],@C[2] eor @E[3],@E[3],@C[3] str.l @E[2],[sp,#$R[4][1]] @ R[4][1] = C[1] ^ (~C[2] & C[3]); bic @E[0],@C[8],@C[6],ror#1 str.h @E[3],[sp,#$R[4][1]+4] bic @E[1],@C[9],@C[7],ror#1 bic @E[2],@C[0],@C[8],ror#31-1 bic @E[3],@C[1],@C[9],ror#31-1 eor @C[4],@C[4],@E[0],ror#32-1 str.l @C[4],[sp,#$R[4][2]] @ R[4][2] = C[2] ^= (~C[3] & C[4]); eor @C[5],@C[5],@E[1],ror#32-1 str.h @C[5],[sp,#$R[4][2]+4] eor @C[6],@C[6],@E[2],ror#32-31 eor @C[7],@C[7],@E[3],ror#32-31 str.l @C[6],[sp,#$R[4][3]] @ R[4][3] = C[3] ^= (~C[4] & C[0]); bic @E[0],@C[2],@C[0],ror#32-31 str.h @C[7],[sp,#$R[4][3]+4] bic @E[1],@C[3],@C[1],ror#32-31 add @E[2],sp,#$R[0][0] eor @C[8],@E[0],@C[8],ror#32-1 add @E[0],sp,#$R[1][0] eor @C[9],@E[1],@C[9],ror#32-1 str.l @C[8],[sp,#$R[4][4]] @ R[4][4] = C[4] ^= (~C[0] & C[1]); str.h @C[9],[sp,#$R[4][4]+4] ___ } Round(@A,@T); Round(@T,@A); $code.=<<___; blo .Lround2x #if __ARM_ARCH__>=5 ldr pc,[sp,#440] #else ldr lr,[sp,#440] tst lr,#1 moveq pc,lr @ be binary compatible with V4, yet bx lr @ interoperable with Thumb ISA:-) #endif .size KeccakF1600_int,.-KeccakF1600_int .type KeccakF1600, %function .align 5 KeccakF1600: stmdb sp!,{r0,r4-r11,lr} sub sp,sp,#440+16 @ space for A[5][5],D[5],T[5][5],... add @E[0],r0,#$A[1][0] add @E[1],sp,#$A[1][0] ldmia r0, {@C[0]-@C[9]} @ copy A[5][5] to stack stmia sp, {@C[0]-@C[9]} ldmia @E[0]!,{@C[0]-@C[9]} stmia @E[1]!,{@C[0]-@C[9]} ldmia @E[0]!,{@C[0]-@C[9]} stmia @E[1]!,{@C[0]-@C[9]} ldmia @E[0]!,{@C[0]-@C[9]} stmia @E[1]!,{@C[0]-@C[9]} ldmia @E[0], {@C[0]-@C[9]} add @E[2],sp,#$A[0][0] add @E[0],sp,#$A[1][0] stmia @E[1], {@C[0]-@C[9]} bl KeccakF1600_enter ldr @E[1], [sp,#440+16] @ restore pointer to A ldmia sp, {@C[0]-@C[9]} stmia @E[1]!,{@C[0]-@C[9]} @ return A[5][5] ldmia @E[0]!,{@C[0]-@C[9]} stmia @E[1]!,{@C[0]-@C[9]} ldmia @E[0]!,{@C[0]-@C[9]} stmia @E[1]!,{@C[0]-@C[9]} ldmia @E[0]!,{@C[0]-@C[9]} stmia @E[1]!,{@C[0]-@C[9]} ldmia @E[0], {@C[0]-@C[9]} stmia @E[1], {@C[0]-@C[9]} add sp,sp,#440+20 #if __ARM_ARCH__>=5 ldmia sp!,{r4-r11,pc} #else ldmia sp!,{r4-r11,lr} tst lr,#1 moveq pc,lr @ be binary compatible with V4, yet bx lr @ interoperable with Thumb ISA:-) #endif .size KeccakF1600,.-KeccakF1600 ___ { my ($A_flat,$inp,$len,$bsz) = map("r$_",(10..12,14)); ######################################################################## # Stack layout # ----->+-----------------------+ # | uint64_t A[5][5] | # | ... | # | ... | # +456->+-----------------------+ # | 0x55555555 | # +460->+-----------------------+ # | 0x33333333 | # +464->+-----------------------+ # | 0x0f0f0f0f | # +468->+-----------------------+ # | 0x00ff00ff | # +472->+-----------------------+ # | uint64_t *A | # +476->+-----------------------+ # | const void *inp | # +480->+-----------------------+ # | size_t len | # +484->+-----------------------+ # | size_t bs | # +488->+-----------------------+ # | .... $code.=<<___; .global SHA3_absorb .type SHA3_absorb,%function .align 5 SHA3_absorb: stmdb sp!,{r0-r12,lr} sub sp,sp,#456+16 add $A_flat,r0,#$A[1][0] @ mov $inp,r1 mov $len,r2 mov $bsz,r3 cmp r2,r3 blo .Labsorb_abort add $inp,sp,#0 ldmia r0, {@C[0]-@C[9]} @ copy A[5][5] to stack stmia $inp!, {@C[0]-@C[9]} ldmia $A_flat!,{@C[0]-@C[9]} stmia $inp!, {@C[0]-@C[9]} ldmia $A_flat!,{@C[0]-@C[9]} stmia $inp!, {@C[0]-@C[9]} ldmia $A_flat!,{@C[0]-@C[9]} stmia $inp!, {@C[0]-@C[9]} ldmia $A_flat!,{@C[0]-@C[9]} stmia $inp, {@C[0]-@C[9]} ldr $inp,[sp,#476] @ restore $inp #ifdef __thumb2__ mov r9,#0x00ff00ff mov r8,#0x0f0f0f0f mov r7,#0x33333333 mov r6,#0x55555555 #else mov r6,#0x11 @ compose constants mov r8,#0x0f mov r9,#0xff orr r6,r6,r6,lsl#8 orr r8,r8,r8,lsl#8 orr r6,r6,r6,lsl#16 @ 0x11111111 orr r9,r9,r9,lsl#16 @ 0x00ff00ff orr r8,r8,r8,lsl#16 @ 0x0f0f0f0f orr r7,r6,r6,lsl#1 @ 0x33333333 orr r6,r6,r6,lsl#2 @ 0x55555555 #endif str r9,[sp,#468] str r8,[sp,#464] str r7,[sp,#460] str r6,[sp,#456] b .Loop_absorb .align 4 .Loop_absorb: subs r0,$len,$bsz blo .Labsorbed add $A_flat,sp,#0 str r0,[sp,#480] @ save len - bsz .align 4 .Loop_block: ldrb r0,[$inp],#1 ldrb r1,[$inp],#1 ldrb r2,[$inp],#1 ldrb r3,[$inp],#1 ldrb r4,[$inp],#1 orr r0,r0,r1,lsl#8 ldrb r1,[$inp],#1 orr r0,r0,r2,lsl#16 ldrb r2,[$inp],#1 orr r0,r0,r3,lsl#24 @ lo ldrb r3,[$inp],#1 orr r1,r4,r1,lsl#8 orr r1,r1,r2,lsl#16 orr r1,r1,r3,lsl#24 @ hi and r2,r0,r6 @ &=0x55555555 and r0,r0,r6,lsl#1 @ &=0xaaaaaaaa and r3,r1,r6 @ &=0x55555555 and r1,r1,r6,lsl#1 @ &=0xaaaaaaaa orr r2,r2,r2,lsr#1 orr r0,r0,r0,lsl#1 orr r3,r3,r3,lsr#1 orr r1,r1,r1,lsl#1 and r2,r2,r7 @ &=0x33333333 and r0,r0,r7,lsl#2 @ &=0xcccccccc and r3,r3,r7 @ &=0x33333333 and r1,r1,r7,lsl#2 @ &=0xcccccccc orr r2,r2,r2,lsr#2 orr r0,r0,r0,lsl#2 orr r3,r3,r3,lsr#2 orr r1,r1,r1,lsl#2 and r2,r2,r8 @ &=0x0f0f0f0f and r0,r0,r8,lsl#4 @ &=0xf0f0f0f0 and r3,r3,r8 @ &=0x0f0f0f0f and r1,r1,r8,lsl#4 @ &=0xf0f0f0f0 ldmia $A_flat,{r4-r5} @ A_flat[i] orr r2,r2,r2,lsr#4 orr r0,r0,r0,lsl#4 orr r3,r3,r3,lsr#4 orr r1,r1,r1,lsl#4 and r2,r2,r9 @ &=0x00ff00ff and r0,r0,r9,lsl#8 @ &=0xff00ff00 and r3,r3,r9 @ &=0x00ff00ff and r1,r1,r9,lsl#8 @ &=0xff00ff00 orr r2,r2,r2,lsr#8 orr r0,r0,r0,lsl#8 orr r3,r3,r3,lsr#8 orr r1,r1,r1,lsl#8 lsl r2,r2,#16 lsr r1,r1,#16 eor r4,r4,r3,lsl#16 eor r5,r5,r0,lsr#16 eor r4,r4,r2,lsr#16 eor r5,r5,r1,lsl#16 stmia $A_flat!,{r4-r5} @ A_flat[i++] ^= BitInterleave(inp[0..7]) subs $bsz,$bsz,#8 bhi .Loop_block str $inp,[sp,#476] bl KeccakF1600_int add r14,sp,#456 ldmia r14,{r6-r12,r14} @ restore constants and variables b .Loop_absorb .align 4 .Labsorbed: add $inp,sp,#$A[1][0] ldmia sp, {@C[0]-@C[9]} stmia $A_flat!,{@C[0]-@C[9]} @ return A[5][5] ldmia $inp!, {@C[0]-@C[9]} stmia $A_flat!,{@C[0]-@C[9]} ldmia $inp!, {@C[0]-@C[9]} stmia $A_flat!,{@C[0]-@C[9]} ldmia $inp!, {@C[0]-@C[9]} stmia $A_flat!,{@C[0]-@C[9]} ldmia $inp, {@C[0]-@C[9]} stmia $A_flat, {@C[0]-@C[9]} .Labsorb_abort: add sp,sp,#456+32 mov r0,$len @ return value #if __ARM_ARCH__>=5 ldmia sp!,{r4-r12,pc} #else ldmia sp!,{r4-r12,lr} tst lr,#1 moveq pc,lr @ be binary compatible with V4, yet bx lr @ interoperable with Thumb ISA:-) #endif .size SHA3_absorb,.-SHA3_absorb ___ } { my ($out,$len,$A_flat,$bsz,$next) = map("r$_", (4,5,10,12,0)); # void SHA3_squeeze(uint64_t A[5][5], # unsigned char *out, size_t len, size_t r, int next) # # The first 4 parameters are passed in via r0..r3, # next is passed on the stack [sp, #0] $code.=<<___; .global SHA3_squeeze .type SHA3_squeeze,%function .align 5 SHA3_squeeze: stmdb sp!,{r0,r3-r10,lr} mov $A_flat,r0 mov $out,r1 mov $len,r2 mov $bsz,r3 ldr $next, [sp, #40] @ next is after the 10 pushed registers (10*4) #ifdef __thumb2__ mov r9,#0x00ff00ff mov r8,#0x0f0f0f0f mov r7,#0x33333333 mov r6,#0x55555555 #else mov r6,#0x11 @ compose constants mov r8,#0x0f mov r9,#0xff orr r6,r6,r6,lsl#8 orr r8,r8,r8,lsl#8 orr r6,r6,r6,lsl#16 @ 0x11111111 orr r9,r9,r9,lsl#16 @ 0x00ff00ff orr r8,r8,r8,lsl#16 @ 0x0f0f0f0f orr r7,r6,r6,lsl#1 @ 0x33333333 orr r6,r6,r6,lsl#2 @ 0x55555555 #endif stmdb sp!,{r6-r9} mov r14,$A_flat cmp $next, #1 beq .Lnext_block b .Loop_squeeze .align 4 .Loop_squeeze: ldmia $A_flat!,{r0,r1} @ A_flat[i++] lsl r2,r0,#16 lsl r3,r1,#16 @ r3 = r1 << 16 lsr r2,r2,#16 @ r2 = r0 & 0x0000ffff lsr r1,r1,#16 lsr r0,r0,#16 @ r0 = r0 >> 16 lsl r1,r1,#16 @ r1 = r1 & 0xffff0000 orr r2,r2,r2,lsl#8 orr r3,r3,r3,lsr#8 orr r0,r0,r0,lsl#8 orr r1,r1,r1,lsr#8 and r2,r2,r9 @ &=0x00ff00ff and r3,r3,r9,lsl#8 @ &=0xff00ff00 and r0,r0,r9 @ &=0x00ff00ff and r1,r1,r9,lsl#8 @ &=0xff00ff00 orr r2,r2,r2,lsl#4 orr r3,r3,r3,lsr#4 orr r0,r0,r0,lsl#4 orr r1,r1,r1,lsr#4 and r2,r2,r8 @ &=0x0f0f0f0f and r3,r3,r8,lsl#4 @ &=0xf0f0f0f0 and r0,r0,r8 @ &=0x0f0f0f0f and r1,r1,r8,lsl#4 @ &=0xf0f0f0f0 orr r2,r2,r2,lsl#2 orr r3,r3,r3,lsr#2 orr r0,r0,r0,lsl#2 orr r1,r1,r1,lsr#2 and r2,r2,r7 @ &=0x33333333 and r3,r3,r7,lsl#2 @ &=0xcccccccc and r0,r0,r7 @ &=0x33333333 and r1,r1,r7,lsl#2 @ &=0xcccccccc orr r2,r2,r2,lsl#1 orr r3,r3,r3,lsr#1 orr r0,r0,r0,lsl#1 orr r1,r1,r1,lsr#1 and r2,r2,r6 @ &=0x55555555 and r3,r3,r6,lsl#1 @ &=0xaaaaaaaa and r0,r0,r6 @ &=0x55555555 and r1,r1,r6,lsl#1 @ &=0xaaaaaaaa orr r2,r2,r3 orr r0,r0,r1 cmp $len,#8 blo .Lsqueeze_tail lsr r1,r2,#8 strb r2,[$out],#1 lsr r3,r2,#16 strb r1,[$out],#1 lsr r2,r2,#24 strb r3,[$out],#1 strb r2,[$out],#1 lsr r1,r0,#8 strb r0,[$out],#1 lsr r3,r0,#16 strb r1,[$out],#1 lsr r0,r0,#24 strb r3,[$out],#1 strb r0,[$out],#1 subs $len,$len,#8 beq .Lsqueeze_done subs $bsz,$bsz,#8 @ bsz -= 8 bhi .Loop_squeeze .Lnext_block: mov r0,r14 @ original $A_flat bl KeccakF1600 ldmia sp,{r6-r10,r12} @ restore constants and variables mov r14,$A_flat b .Loop_squeeze .align 4 .Lsqueeze_tail: strb r2,[$out],#1 lsr r2,r2,#8 subs $len,$len,#1 beq .Lsqueeze_done strb r2,[$out],#1 lsr r2,r2,#8 subs $len,$len,#1 beq .Lsqueeze_done strb r2,[$out],#1 lsr r2,r2,#8 subs $len,$len,#1 beq .Lsqueeze_done strb r2,[$out],#1 subs $len,$len,#1 beq .Lsqueeze_done strb r0,[$out],#1 lsr r0,r0,#8 subs $len,$len,#1 beq .Lsqueeze_done strb r0,[$out],#1 lsr r0,r0,#8 subs $len,$len,#1 beq .Lsqueeze_done strb r0,[$out] b .Lsqueeze_done .align 4 .Lsqueeze_done: add sp,sp,#24 #if __ARM_ARCH__>=5 ldmia sp!,{r4-r10,pc} #else ldmia sp!,{r4-r10,lr} tst lr,#1 moveq pc,lr @ be binary compatible with V4, yet bx lr @ interoperable with Thumb ISA:-) #endif .size SHA3_squeeze,.-SHA3_squeeze ___ } $code.=<<___; #if __ARM_MAX_ARCH__>=7 .fpu neon .type iotas64, %object .align 5 iotas64: .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 .size iotas64,.-iotas64 .type KeccakF1600_neon, %function .align 5 KeccakF1600_neon: add r1, r0, #16 adr r2, iotas64 mov r3, #24 @ loop counter b .Loop_neon .align 4 .Loop_neon: @ Theta vst1.64 {q4}, [r0,:64] @ offload A[0..1][4] veor q13, q0, q5 @ A[0..1][0]^A[2..3][0] vst1.64 {d18}, [r1,:64] @ offload A[2][4] veor q14, q1, q6 @ A[0..1][1]^A[2..3][1] veor q15, q2, q7 @ A[0..1][2]^A[2..3][2] veor d26, d26, d27 @ C[0]=A[0][0]^A[1][0]^A[2][0]^A[3][0] veor d27, d28, d29 @ C[1]=A[0][1]^A[1][1]^A[2][1]^A[3][1] veor q14, q3, q8 @ A[0..1][3]^A[2..3][3] veor q4, q4, q9 @ A[0..1][4]^A[2..3][4] veor d30, d30, d31 @ C[2]=A[0][2]^A[1][2]^A[2][2]^A[3][2] veor d31, d28, d29 @ C[3]=A[0][3]^A[1][3]^A[2][3]^A[3][3] veor d25, d8, d9 @ C[4]=A[0][4]^A[1][4]^A[2][4]^A[3][4] veor q13, q13, q10 @ C[0..1]^=A[4][0..1] veor q14, q15, q11 @ C[2..3]^=A[4][2..3] veor d25, d25, d24 @ C[4]^=A[4][4] vadd.u64 q4, q13, q13 @ C[0..1]<<1 vadd.u64 q15, q14, q14 @ C[2..3]<<1 vadd.u64 d18, d25, d25 @ C[4]<<1 vsri.u64 q4, q13, #63 @ ROL64(C[0..1],1) vsri.u64 q15, q14, #63 @ ROL64(C[2..3],1) vsri.u64 d18, d25, #63 @ ROL64(C[4],1) veor d25, d25, d9 @ D[0] = C[4] ^= ROL64(C[1],1) veor q13, q13, q15 @ D[1..2] = C[0..1] ^ ROL64(C[2..3],1) veor d28, d28, d18 @ D[3] = C[2] ^= ROL64(C[4],1) veor d29, d29, d8 @ D[4] = C[3] ^= ROL64(C[0],1) veor d0, d0, d25 @ A[0][0] ^= C[4] veor d1, d1, d25 @ A[1][0] ^= C[4] veor d10, d10, d25 @ A[2][0] ^= C[4] veor d11, d11, d25 @ A[3][0] ^= C[4] veor d20, d20, d25 @ A[4][0] ^= C[4] veor d2, d2, d26 @ A[0][1] ^= D[1] veor d3, d3, d26 @ A[1][1] ^= D[1] veor d12, d12, d26 @ A[2][1] ^= D[1] veor d13, d13, d26 @ A[3][1] ^= D[1] veor d21, d21, d26 @ A[4][1] ^= D[1] vmov d26, d27 veor d6, d6, d28 @ A[0][3] ^= C[2] veor d7, d7, d28 @ A[1][3] ^= C[2] veor d16, d16, d28 @ A[2][3] ^= C[2] veor d17, d17, d28 @ A[3][3] ^= C[2] veor d23, d23, d28 @ A[4][3] ^= C[2] vld1.64 {q4}, [r0,:64] @ restore A[0..1][4] vmov d28, d29 vld1.64 {d18}, [r1,:64] @ restore A[2][4] veor q2, q2, q13 @ A[0..1][2] ^= D[2] veor q7, q7, q13 @ A[2..3][2] ^= D[2] veor d22, d22, d27 @ A[4][2] ^= D[2] veor q4, q4, q14 @ A[0..1][4] ^= C[3] veor q9, q9, q14 @ A[2..3][4] ^= C[3] veor d24, d24, d29 @ A[4][4] ^= C[3] @ Rho + Pi vmov d26, d2 @ C[1] = A[0][1] vshl.u64 d2, d3, #44 vmov d27, d4 @ C[2] = A[0][2] vshl.u64 d4, d14, #43 vmov d28, d6 @ C[3] = A[0][3] vshl.u64 d6, d17, #21 vmov d29, d8 @ C[4] = A[0][4] vshl.u64 d8, d24, #14 vsri.u64 d2, d3, #64-44 @ A[0][1] = ROL64(A[1][1], rhotates[1][1]) vsri.u64 d4, d14, #64-43 @ A[0][2] = ROL64(A[2][2], rhotates[2][2]) vsri.u64 d6, d17, #64-21 @ A[0][3] = ROL64(A[3][3], rhotates[3][3]) vsri.u64 d8, d24, #64-14 @ A[0][4] = ROL64(A[4][4], rhotates[4][4]) vshl.u64 d3, d9, #20 vshl.u64 d14, d16, #25 vshl.u64 d17, d15, #15 vshl.u64 d24, d21, #2 vsri.u64 d3, d9, #64-20 @ A[1][1] = ROL64(A[1][4], rhotates[1][4]) vsri.u64 d14, d16, #64-25 @ A[2][2] = ROL64(A[2][3], rhotates[2][3]) vsri.u64 d17, d15, #64-15 @ A[3][3] = ROL64(A[3][2], rhotates[3][2]) vsri.u64 d24, d21, #64-2 @ A[4][4] = ROL64(A[4][1], rhotates[4][1]) vshl.u64 d9, d22, #61 @ vshl.u64 d16, d19, #8 vshl.u64 d15, d12, #10 vshl.u64 d21, d7, #55 vsri.u64 d9, d22, #64-61 @ A[1][4] = ROL64(A[4][2], rhotates[4][2]) vext.8 d16, d19, d19, #8-1 @ A[2][3] = ROL64(A[3][4], rhotates[3][4]) vsri.u64 d15, d12, #64-10 @ A[3][2] = ROL64(A[2][1], rhotates[2][1]) vsri.u64 d21, d7, #64-55 @ A[4][1] = ROL64(A[1][3], rhotates[1][3]) vshl.u64 d22, d18, #39 @ vshl.u64 d19, d23, #56 vshl.u64 d12, d5, #6 vshl.u64 d7, d13, #45 vsri.u64 d22, d18, #64-39 @ A[4][2] = ROL64(A[2][4], rhotates[2][4]) vext.8 d19, d23, d23, #8-7 @ A[3][4] = ROL64(A[4][3], rhotates[4][3]) vsri.u64 d12, d5, #64-6 @ A[2][1] = ROL64(A[1][2], rhotates[1][2]) vsri.u64 d7, d13, #64-45 @ A[1][3] = ROL64(A[3][1], rhotates[3][1]) vshl.u64 d18, d20, #18 vshl.u64 d23, d11, #41 vshl.u64 d5, d10, #3 vshl.u64 d13, d1, #36 vsri.u64 d18, d20, #64-18 @ A[2][4] = ROL64(A[4][0], rhotates[4][0]) vsri.u64 d23, d11, #64-41 @ A[4][3] = ROL64(A[3][0], rhotates[3][0]) vsri.u64 d5, d10, #64-3 @ A[1][2] = ROL64(A[2][0], rhotates[2][0]) vsri.u64 d13, d1, #64-36 @ A[3][1] = ROL64(A[1][0], rhotates[1][0]) vshl.u64 d1, d28, #28 vshl.u64 d10, d26, #1 vshl.u64 d11, d29, #27 vshl.u64 d20, d27, #62 vsri.u64 d1, d28, #64-28 @ A[1][0] = ROL64(C[3], rhotates[0][3]) vsri.u64 d10, d26, #64-1 @ A[2][0] = ROL64(C[1], rhotates[0][1]) vsri.u64 d11, d29, #64-27 @ A[3][0] = ROL64(C[4], rhotates[0][4]) vsri.u64 d20, d27, #64-62 @ A[4][0] = ROL64(C[2], rhotates[0][2]) @ Chi + Iota vbic q13, q2, q1 vbic q14, q3, q2 vbic q15, q4, q3 veor q13, q13, q0 @ A[0..1][0] ^ (~A[0..1][1] & A[0..1][2]) veor q14, q14, q1 @ A[0..1][1] ^ (~A[0..1][2] & A[0..1][3]) veor q2, q2, q15 @ A[0..1][2] ^= (~A[0..1][3] & A[0..1][4]) vst1.64 {q13}, [r0,:64] @ offload A[0..1][0] vbic q13, q0, q4 vbic q15, q1, q0 vmov q1, q14 @ A[0..1][1] veor q3, q3, q13 @ A[0..1][3] ^= (~A[0..1][4] & A[0..1][0]) veor q4, q4, q15 @ A[0..1][4] ^= (~A[0..1][0] & A[0..1][1]) vbic q13, q7, q6 vmov q0, q5 @ A[2..3][0] vbic q14, q8, q7 vmov q15, q6 @ A[2..3][1] veor q5, q5, q13 @ A[2..3][0] ^= (~A[2..3][1] & A[2..3][2]) vbic q13, q9, q8 veor q6, q6, q14 @ A[2..3][1] ^= (~A[2..3][2] & A[2..3][3]) vbic q14, q0, q9 veor q7, q7, q13 @ A[2..3][2] ^= (~A[2..3][3] & A[2..3][4]) vbic q13, q15, q0 veor q8, q8, q14 @ A[2..3][3] ^= (~A[2..3][4] & A[2..3][0]) vmov q14, q10 @ A[4][0..1] veor q9, q9, q13 @ A[2..3][4] ^= (~A[2..3][0] & A[2..3][1]) vld1.64 d25, [r2,:64]! @ Iota[i++] vbic d26, d22, d21 vbic d27, d23, d22 vld1.64 {q0}, [r0,:64] @ restore A[0..1][0] veor d20, d20, d26 @ A[4][0] ^= (~A[4][1] & A[4][2]) vbic d26, d24, d23 veor d21, d21, d27 @ A[4][1] ^= (~A[4][2] & A[4][3]) vbic d27, d28, d24 veor d22, d22, d26 @ A[4][2] ^= (~A[4][3] & A[4][4]) vbic d26, d29, d28 veor d23, d23, d27 @ A[4][3] ^= (~A[4][4] & A[4][0]) veor d0, d0, d25 @ A[0][0] ^= Iota[i] veor d24, d24, d26 @ A[4][4] ^= (~A[4][0] & A[4][1]) subs r3, r3, #1 bne .Loop_neon ret .size KeccakF1600_neon,.-KeccakF1600_neon .global SHA3_absorb_neon .type SHA3_absorb_neon, %function .align 5 SHA3_absorb_neon: stmdb sp!, {r4-r6,lr} vstmdb sp!, {d8-d15} mov r4, r1 @ inp mov r5, r2 @ len mov r6, r3 @ bsz vld1.32 {d0}, [r0,:64]! @ A[0][0] vld1.32 {d2}, [r0,:64]! @ A[0][1] vld1.32 {d4}, [r0,:64]! @ A[0][2] vld1.32 {d6}, [r0,:64]! @ A[0][3] vld1.32 {d8}, [r0,:64]! @ A[0][4] vld1.32 {d1}, [r0,:64]! @ A[1][0] vld1.32 {d3}, [r0,:64]! @ A[1][1] vld1.32 {d5}, [r0,:64]! @ A[1][2] vld1.32 {d7}, [r0,:64]! @ A[1][3] vld1.32 {d9}, [r0,:64]! @ A[1][4] vld1.32 {d10}, [r0,:64]! @ A[2][0] vld1.32 {d12}, [r0,:64]! @ A[2][1] vld1.32 {d14}, [r0,:64]! @ A[2][2] vld1.32 {d16}, [r0,:64]! @ A[2][3] vld1.32 {d18}, [r0,:64]! @ A[2][4] vld1.32 {d11}, [r0,:64]! @ A[3][0] vld1.32 {d13}, [r0,:64]! @ A[3][1] vld1.32 {d15}, [r0,:64]! @ A[3][2] vld1.32 {d17}, [r0,:64]! @ A[3][3] vld1.32 {d19}, [r0,:64]! @ A[3][4] vld1.32 {d20-d23}, [r0,:64]! @ A[4][0..3] vld1.32 {d24}, [r0,:64] @ A[4][4] sub r0, r0, #24*8 @ rewind b .Loop_absorb_neon .align 4 .Loop_absorb_neon: subs r12, r5, r6 @ len - bsz blo .Labsorbed_neon mov r5, r12 vld1.8 {d31}, [r4]! @ endian-neutral loads... cmp r6, #8*2 veor d0, d0, d31 @ A[0][0] ^= *inp++ blo .Lprocess_neon vld1.8 {d31}, [r4]! veor d2, d2, d31 @ A[0][1] ^= *inp++ beq .Lprocess_neon vld1.8 {d31}, [r4]! cmp r6, #8*4 veor d4, d4, d31 @ A[0][2] ^= *inp++ blo .Lprocess_neon vld1.8 {d31}, [r4]! veor d6, d6, d31 @ A[0][3] ^= *inp++ beq .Lprocess_neon vld1.8 {d31},[r4]! cmp r6, #8*6 veor d8, d8, d31 @ A[0][4] ^= *inp++ blo .Lprocess_neon vld1.8 {d31}, [r4]! veor d1, d1, d31 @ A[1][0] ^= *inp++ beq .Lprocess_neon vld1.8 {d31}, [r4]! cmp r6, #8*8 veor d3, d3, d31 @ A[1][1] ^= *inp++ blo .Lprocess_neon vld1.8 {d31}, [r4]! veor d5, d5, d31 @ A[1][2] ^= *inp++ beq .Lprocess_neon vld1.8 {d31}, [r4]! cmp r6, #8*10 veor d7, d7, d31 @ A[1][3] ^= *inp++ blo .Lprocess_neon vld1.8 {d31}, [r4]! veor d9, d9, d31 @ A[1][4] ^= *inp++ beq .Lprocess_neon vld1.8 {d31}, [r4]! cmp r6, #8*12 veor d10, d10, d31 @ A[2][0] ^= *inp++ blo .Lprocess_neon vld1.8 {d31}, [r4]! veor d12, d12, d31 @ A[2][1] ^= *inp++ beq .Lprocess_neon vld1.8 {d31}, [r4]! cmp r6, #8*14 veor d14, d14, d31 @ A[2][2] ^= *inp++ blo .Lprocess_neon vld1.8 {d31}, [r4]! veor d16, d16, d31 @ A[2][3] ^= *inp++ beq .Lprocess_neon vld1.8 {d31}, [r4]! cmp r6, #8*16 veor d18, d18, d31 @ A[2][4] ^= *inp++ blo .Lprocess_neon vld1.8 {d31}, [r4]! veor d11, d11, d31 @ A[3][0] ^= *inp++ beq .Lprocess_neon vld1.8 {d31}, [r4]! cmp r6, #8*18 veor d13, d13, d31 @ A[3][1] ^= *inp++ blo .Lprocess_neon vld1.8 {d31}, [r4]! veor d15, d15, d31 @ A[3][2] ^= *inp++ beq .Lprocess_neon vld1.8 {d31}, [r4]! cmp r6, #8*20 veor d17, d17, d31 @ A[3][3] ^= *inp++ blo .Lprocess_neon vld1.8 {d31}, [r4]! veor d19, d19, d31 @ A[3][4] ^= *inp++ beq .Lprocess_neon vld1.8 {d31}, [r4]! cmp r6, #8*22 veor d20, d20, d31 @ A[4][0] ^= *inp++ blo .Lprocess_neon vld1.8 {d31}, [r4]! veor d21, d21, d31 @ A[4][1] ^= *inp++ beq .Lprocess_neon vld1.8 {d31}, [r4]! cmp r6, #8*24 veor d22, d22, d31 @ A[4][2] ^= *inp++ blo .Lprocess_neon vld1.8 {d31}, [r4]! veor d23, d23, d31 @ A[4][3] ^= *inp++ beq .Lprocess_neon vld1.8 {d31}, [r4]! veor d24, d24, d31 @ A[4][4] ^= *inp++ .Lprocess_neon: bl KeccakF1600_neon b .Loop_absorb_neon .align 4 .Labsorbed_neon: vst1.32 {d0}, [r0,:64]! @ A[0][0..4] vst1.32 {d2}, [r0,:64]! vst1.32 {d4}, [r0,:64]! vst1.32 {d6}, [r0,:64]! vst1.32 {d8}, [r0,:64]! vst1.32 {d1}, [r0,:64]! @ A[1][0..4] vst1.32 {d3}, [r0,:64]! vst1.32 {d5}, [r0,:64]! vst1.32 {d7}, [r0,:64]! vst1.32 {d9}, [r0,:64]! vst1.32 {d10}, [r0,:64]! @ A[2][0..4] vst1.32 {d12}, [r0,:64]! vst1.32 {d14}, [r0,:64]! vst1.32 {d16}, [r0,:64]! vst1.32 {d18}, [r0,:64]! vst1.32 {d11}, [r0,:64]! @ A[3][0..4] vst1.32 {d13}, [r0,:64]! vst1.32 {d15}, [r0,:64]! vst1.32 {d17}, [r0,:64]! vst1.32 {d19}, [r0,:64]! vst1.32 {d20-d23}, [r0,:64]! @ A[4][0..4] vst1.32 {d24}, [r0,:64] mov r0, r5 @ return value vldmia sp!, {d8-d15} ldmia sp!, {r4-r6,pc} .size SHA3_absorb_neon,.-SHA3_absorb_neon .global SHA3_squeeze_neon .type SHA3_squeeze_neon, %function .align 5 SHA3_squeeze_neon: stmdb sp!, {r4-r6,lr} mov r4, r1 @ out mov r5, r2 @ len mov r6, r3 @ bsz mov r12, r0 @ A_flat mov r14, r3 @ bsz b .Loop_squeeze_neon .align 4 .Loop_squeeze_neon: cmp r5, #8 blo .Lsqueeze_neon_tail vld1.32 {d0}, [r12]! vst1.8 {d0}, [r4]! @ endian-neutral store subs r5, r5, #8 @ len -= 8 beq .Lsqueeze_neon_done subs r14, r14, #8 @ bsz -= 8 bhi .Loop_squeeze_neon vstmdb sp!, {d8-d15} vld1.32 {d0}, [r0,:64]! @ A[0][0..4] vld1.32 {d2}, [r0,:64]! vld1.32 {d4}, [r0,:64]! vld1.32 {d6}, [r0,:64]! vld1.32 {d8}, [r0,:64]! vld1.32 {d1}, [r0,:64]! @ A[1][0..4] vld1.32 {d3}, [r0,:64]! vld1.32 {d5}, [r0,:64]! vld1.32 {d7}, [r0,:64]! vld1.32 {d9}, [r0,:64]! vld1.32 {d10}, [r0,:64]! @ A[2][0..4] vld1.32 {d12}, [r0,:64]! vld1.32 {d14}, [r0,:64]! vld1.32 {d16}, [r0,:64]! vld1.32 {d18}, [r0,:64]! vld1.32 {d11}, [r0,:64]! @ A[3][0..4] vld1.32 {d13}, [r0,:64]! vld1.32 {d15}, [r0,:64]! vld1.32 {d17}, [r0,:64]! vld1.32 {d19}, [r0,:64]! vld1.32 {d20-d23}, [r0,:64]! @ A[4][0..4] vld1.32 {d24}, [r0,:64] sub r0, r0, #24*8 @ rewind bl KeccakF1600_neon mov r12, r0 @ A_flat vst1.32 {d0}, [r0,:64]! @ A[0][0..4] vst1.32 {d2}, [r0,:64]! vst1.32 {d4}, [r0,:64]! vst1.32 {d6}, [r0,:64]! vst1.32 {d8}, [r0,:64]! vst1.32 {d1}, [r0,:64]! @ A[1][0..4] vst1.32 {d3}, [r0,:64]! vst1.32 {d5}, [r0,:64]! vst1.32 {d7}, [r0,:64]! vst1.32 {d9}, [r0,:64]! vst1.32 {d10}, [r0,:64]! @ A[2][0..4] vst1.32 {d12}, [r0,:64]! vst1.32 {d14}, [r0,:64]! vst1.32 {d16}, [r0,:64]! vst1.32 {d18}, [r0,:64]! vst1.32 {d11}, [r0,:64]! @ A[3][0..4] vst1.32 {d13}, [r0,:64]! vst1.32 {d15}, [r0,:64]! vst1.32 {d17}, [r0,:64]! vst1.32 {d19}, [r0,:64]! vst1.32 {d20-d23}, [r0,:64]! @ A[4][0..4] mov r14, r6 @ bsz vst1.32 {d24}, [r0,:64] mov r0, r12 @ rewind vldmia sp!, {d8-d15} b .Loop_squeeze_neon .align 4 .Lsqueeze_neon_tail: ldmia r12, {r2,r3} cmp r5, #2 strb r2, [r4],#1 @ endian-neutral store lsr r2, r2, #8 blo .Lsqueeze_neon_done strb r2, [r4], #1 lsr r2, r2, #8 beq .Lsqueeze_neon_done strb r2, [r4], #1 lsr r2, r2, #8 cmp r5, #4 blo .Lsqueeze_neon_done strb r2, [r4], #1 beq .Lsqueeze_neon_done strb r3, [r4], #1 lsr r3, r3, #8 cmp r5, #6 blo .Lsqueeze_neon_done strb r3, [r4], #1 lsr r3, r3, #8 beq .Lsqueeze_neon_done strb r3, [r4], #1 .Lsqueeze_neon_done: ldmia sp!, {r4-r6,pc} .size SHA3_squeeze_neon,.-SHA3_squeeze_neon #endif .asciz "Keccak-1600 absorb and squeeze for ARMv4/NEON, CRYPTOGAMS by " .align 2 ___ { my %ldr, %str; sub ldrd { my ($mnemonic,$half,$reg,$ea) = @_; my $op = $mnemonic eq "ldr" ? \%ldr : \%str; if ($half eq "l") { $$op{reg} = $reg; $$op{ea} = $ea; sprintf "#ifndef __thumb2__\n" . " %s\t%s,%s\n" . "#endif", $mnemonic,$reg,$ea; } else { sprintf "#ifndef __thumb2__\n" . " %s\t%s,%s\n" . "#else\n" . " %sd\t%s,%s,%s\n" . "#endif", $mnemonic,$reg,$ea, $mnemonic,$$op{reg},$reg,$$op{ea}; } } } foreach (split($/,$code)) { s/\`([^\`]*)\`/eval $1/ge; s/^\s+(ldr|str)\.([lh])\s+(r[0-9]+),\s*(\[.*)/ldrd($1,$2,$3,$4)/ge or s/\b(ror|ls[rl])\s+(r[0-9]+.*)#/mov $2$1#/g or s/\bret\b/bx lr/g or s/\bbx\s+lr\b/.word\t0xe12fff1e/g; # make it possible to compile with -march=armv4 print $_,"\n"; } close STDOUT or die "error closing STDOUT: $!"; # enforce flush