123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560 |
- #!/usr/bin/env perl
- # Copyright 2017-2018 The OpenSSL Project Authors. All Rights Reserved.
- #
- # Licensed under the OpenSSL license (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 <appro@openssl.org> 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 s390x.
- #
- # June 2017.
- #
- # Below code is [lane complementing] KECCAK_2X implementation (see
- # sha/keccak1600.c) with C[5] and D[5] held in register bank. Though
- # instead of actually unrolling the loop pair-wise I simply flip
- # pointers to T[][] and A[][] at the end of round. Since number of
- # rounds is even, last round writes to A[][] and everything works out.
- # In the nutshell it's transliteration of x86_64 module, because both
- # architectures have similar capabilities/limitations. Performance
- # measurement is problematic as I don't have access to an idle system.
- # It looks like z13 processes one byte [out of long message] in ~14
- # cycles. At least the result is consistent with estimate based on
- # amount of instruction and assumed instruction issue rate. It's ~2.5x
- # faster than compiler-generated code.
- $flavour = shift;
- if ($flavour =~ /3[12]/) {
- $SIZE_T=4;
- $g="";
- } else {
- $SIZE_T=8;
- $g="g";
- }
- while (($output=shift) && ($output!~/\w[\w\-]*\.\w+$/)) {}
- open STDOUT,">$output";
- my @A = map([ 8*$_, 8*($_+1), 8*($_+2), 8*($_+3), 8*($_+4) ], (0,5,10,15,20));
- my @C = map("%r$_",(0,1,5..7));
- my @D = map("%r$_",(8..12));
- my @T = map("%r$_",(13..14));
- my ($src,$dst,$iotas) = map("%r$_",(2..4));
- my $sp = "%r15";
- $stdframe=16*$SIZE_T+4*8;
- $frame=$stdframe+25*8;
- my @rhotates = ([ 0, 1, 62, 28, 27 ],
- [ 36, 44, 6, 55, 20 ],
- [ 3, 10, 43, 25, 39 ],
- [ 41, 45, 15, 21, 8 ],
- [ 18, 2, 61, 56, 14 ]);
- { my @C = @C; # copy, because we mess them up...
- my @D = @D;
- $code.=<<___;
- .text
- .type __KeccakF1600,\@function
- .align 32
- __KeccakF1600:
- st${g} %r14,$SIZE_T*14($sp)
- lg @C[0],$A[4][0]($src)
- lg @C[1],$A[4][1]($src)
- lg @C[2],$A[4][2]($src)
- lg @C[3],$A[4][3]($src)
- lg @C[4],$A[4][4]($src)
- larl $iotas,iotas
- j .Loop
- .align 16
- .Loop:
- lg @D[0],$A[0][0]($src)
- lg @D[1],$A[1][1]($src)
- lg @D[2],$A[2][2]($src)
- lg @D[3],$A[3][3]($src)
- xgr @C[0],@D[0]
- xg @C[1],$A[0][1]($src)
- xg @C[2],$A[0][2]($src)
- xg @C[3],$A[0][3]($src)
- lgr @D[4],@C[4]
- xg @C[4],$A[0][4]($src)
- xg @C[0],$A[1][0]($src)
- xgr @C[1],@D[1]
- xg @C[2],$A[1][2]($src)
- xg @C[3],$A[1][3]($src)
- xg @C[4],$A[1][4]($src)
- xg @C[0],$A[2][0]($src)
- xg @C[1],$A[2][1]($src)
- xgr @C[2],@D[2]
- xg @C[3],$A[2][3]($src)
- xg @C[4],$A[2][4]($src)
- xg @C[0],$A[3][0]($src)
- xg @C[1],$A[3][1]($src)
- xg @C[2],$A[3][2]($src)
- xgr @C[3],@D[3]
- xg @C[4],$A[3][4]($src)
- lgr @T[0],@C[2]
- rllg @C[2],@C[2],1
- xgr @C[2],@C[0] # D[1] = ROL64(C[2], 1) ^ C[0]
- rllg @C[0],@C[0],1
- xgr @C[0],@C[3] # D[4] = ROL64(C[0], 1) ^ C[3]
- rllg @C[3],@C[3],1
- xgr @C[3],@C[1] # D[2] = ROL64(C[3], 1) ^ C[1]
- rllg @C[1],@C[1],1
- xgr @C[1],@C[4] # D[0] = ROL64(C[1], 1) ^ C[4]
- rllg @C[4],@C[4],1
- xgr @C[4],@T[0] # D[3] = ROL64(C[4], 1) ^ C[2]
- ___
- (@D[0..4], @C) = (@C[1..4,0], @D);
- $code.=<<___;
- xgr @C[1],@D[1]
- xgr @C[2],@D[2]
- xgr @C[3],@D[3]
- rllg @C[1],@C[1],$rhotates[1][1]
- xgr @C[4],@D[4]
- rllg @C[2],@C[2],$rhotates[2][2]
- xgr @C[0],@D[0]
- lgr @T[0],@C[1]
- ogr @C[1],@C[2]
- rllg @C[3],@C[3],$rhotates[3][3]
- xgr @C[1],@C[0] # C[0] ^ ( C[1] | C[2])
- rllg @C[4],@C[4],$rhotates[4][4]
- xg @C[1],0($iotas)
- la $iotas,8($iotas)
- stg @C[1],$A[0][0]($dst) # R[0][0] = C[0] ^ ( C[1] | C[2]) ^ iotas[i]
- lgr @T[1],@C[4]
- ngr @C[4],@C[3]
- lghi @C[1],-1 # no 'not' instruction :-(
- xgr @C[4],@C[2] # C[2] ^ ( C[4] & C[3])
- xgr @C[2],@C[1] # not @C[2]
- stg @C[4],$A[0][2]($dst) # R[0][2] = C[2] ^ ( C[4] & C[3])
- ogr @C[2],@C[3]
- xgr @C[2],@T[0] # C[1] ^ (~C[2] | C[3])
- ngr @T[0],@C[0]
- stg @C[2],$A[0][1]($dst) # R[0][1] = C[1] ^ (~C[2] | C[3])
- xgr @T[0],@T[1] # C[4] ^ ( C[1] & C[0])
- ogr @T[1],@C[0]
- stg @T[0],$A[0][4]($dst) # R[0][4] = C[4] ^ ( C[1] & C[0])
- xgr @T[1],@C[3] # C[3] ^ ( C[4] | C[0])
- stg @T[1],$A[0][3]($dst) # R[0][3] = C[3] ^ ( C[4] | C[0])
- lg @C[0],$A[0][3]($src)
- lg @C[4],$A[4][2]($src)
- lg @C[3],$A[3][1]($src)
- lg @C[1],$A[1][4]($src)
- lg @C[2],$A[2][0]($src)
- xgr @C[0],@D[3]
- xgr @C[4],@D[2]
- rllg @C[0],@C[0],$rhotates[0][3]
- xgr @C[3],@D[1]
- rllg @C[4],@C[4],$rhotates[4][2]
- xgr @C[1],@D[4]
- rllg @C[3],@C[3],$rhotates[3][1]
- xgr @C[2],@D[0]
- lgr @T[0],@C[0]
- ogr @C[0],@C[4]
- rllg @C[1],@C[1],$rhotates[1][4]
- xgr @C[0],@C[3] # C[3] ^ (C[0] | C[4])
- rllg @C[2],@C[2],$rhotates[2][0]
- stg @C[0],$A[1][3]($dst) # R[1][3] = C[3] ^ (C[0] | C[4])
- lgr @T[1],@C[1]
- ngr @C[1],@T[0]
- lghi @C[0],-1 # no 'not' instruction :-(
- xgr @C[1],@C[4] # C[4] ^ (C[1] & C[0])
- xgr @C[4],@C[0] # not @C[4]
- stg @C[1],$A[1][4]($dst) # R[1][4] = C[4] ^ (C[1] & C[0])
- ogr @C[4],@C[3]
- xgr @C[4],@C[2] # C[2] ^ (~C[4] | C[3])
- ngr @C[3],@C[2]
- stg @C[4],$A[1][2]($dst) # R[1][2] = C[2] ^ (~C[4] | C[3])
- xgr @C[3],@T[1] # C[1] ^ (C[3] & C[2])
- ogr @T[1],@C[2]
- stg @C[3],$A[1][1]($dst) # R[1][1] = C[1] ^ (C[3] & C[2])
- xgr @T[1],@T[0] # C[0] ^ (C[1] | C[2])
- stg @T[1],$A[1][0]($dst) # R[1][0] = C[0] ^ (C[1] | C[2])
- lg @C[2],$A[2][3]($src)
- lg @C[3],$A[3][4]($src)
- lg @C[1],$A[1][2]($src)
- lg @C[4],$A[4][0]($src)
- lg @C[0],$A[0][1]($src)
- xgr @C[2],@D[3]
- xgr @C[3],@D[4]
- rllg @C[2],@C[2],$rhotates[2][3]
- xgr @C[1],@D[2]
- rllg @C[3],@C[3],$rhotates[3][4]
- xgr @C[4],@D[0]
- rllg @C[1],@C[1],$rhotates[1][2]
- xgr @C[0],@D[1]
- lgr @T[0],@C[2]
- ngr @C[2],@C[3]
- rllg @C[4],@C[4],$rhotates[4][0]
- xgr @C[2],@C[1] # C[1] ^ ( C[2] & C[3])
- lghi @T[1],-1 # no 'not' instruction :-(
- stg @C[2],$A[2][1]($dst) # R[2][1] = C[1] ^ ( C[2] & C[3])
- xgr @C[3],@T[1] # not @C[3]
- lgr @T[1],@C[4]
- ngr @C[4],@C[3]
- rllg @C[0],@C[0],$rhotates[0][1]
- xgr @C[4],@T[0] # C[2] ^ ( C[4] & ~C[3])
- ogr @T[0],@C[1]
- stg @C[4],$A[2][2]($dst) # R[2][2] = C[2] ^ ( C[4] & ~C[3])
- xgr @T[0],@C[0] # C[0] ^ ( C[2] | C[1])
- ngr @C[1],@C[0]
- stg @T[0],$A[2][0]($dst) # R[2][0] = C[0] ^ ( C[2] | C[1])
- xgr @C[1],@T[1] # C[4] ^ ( C[1] & C[0])
- ogr @C[0],@T[1]
- stg @C[1],$A[2][4]($dst) # R[2][4] = C[4] ^ ( C[1] & C[0])
- xgr @C[0],@C[3] # ~C[3] ^ ( C[0] | C[4])
- stg @C[0],$A[2][3]($dst) # R[2][3] = ~C[3] ^ ( C[0] | C[4])
- lg @C[2],$A[2][1]($src)
- lg @C[3],$A[3][2]($src)
- lg @C[1],$A[1][0]($src)
- lg @C[4],$A[4][3]($src)
- lg @C[0],$A[0][4]($src)
- xgr @C[2],@D[1]
- xgr @C[3],@D[2]
- rllg @C[2],@C[2],$rhotates[2][1]
- xgr @C[1],@D[0]
- rllg @C[3],@C[3],$rhotates[3][2]
- xgr @C[4],@D[3]
- rllg @C[1],@C[1],$rhotates[1][0]
- xgr @C[0],@D[4]
- rllg @C[4],@C[4],$rhotates[4][3]
- lgr @T[0],@C[2]
- ogr @C[2],@C[3]
- lghi @T[1],-1 # no 'not' instruction :-(
- xgr @C[2],@C[1] # C[1] ^ ( C[2] | C[3])
- xgr @C[3],@T[1] # not @C[3]
- stg @C[2],$A[3][1]($dst) # R[3][1] = C[1] ^ ( C[2] | C[3])
- lgr @T[1],@C[4]
- ogr @C[4],@C[3]
- rllg @C[0],@C[0],$rhotates[0][4]
- xgr @C[4],@T[0] # C[2] ^ ( C[4] | ~C[3])
- ngr @T[0],@C[1]
- stg @C[4],$A[3][2]($dst) # R[3][2] = C[2] ^ ( C[4] | ~C[3])
- xgr @T[0],@C[0] # C[0] ^ ( C[2] & C[1])
- ogr @C[1],@C[0]
- stg @T[0],$A[3][0]($dst) # R[3][0] = C[0] ^ ( C[2] & C[1])
- xgr @C[1],@T[1] # C[4] ^ ( C[1] | C[0])
- ngr @C[0],@T[1]
- stg @C[1],$A[3][4]($dst) # R[3][4] = C[4] ^ ( C[1] | C[0])
- xgr @C[0],@C[3] # ~C[3] ^ ( C[0] & C[4])
- stg @C[0],$A[3][3]($dst) # R[3][3] = ~C[3] ^ ( C[0] & C[4])
- xg @D[2],$A[0][2]($src)
- xg @D[3],$A[1][3]($src)
- xg @D[1],$A[4][1]($src)
- xg @D[4],$A[2][4]($src)
- xgr $dst,$src # xchg $dst,$src
- rllg @D[2],@D[2],$rhotates[0][2]
- xg @D[0],$A[3][0]($src)
- rllg @D[3],@D[3],$rhotates[1][3]
- xgr $src,$dst
- rllg @D[1],@D[1],$rhotates[4][1]
- xgr $dst,$src
- rllg @D[4],@D[4],$rhotates[2][4]
- ___
- @C = @D[2..4,0,1];
- $code.=<<___;
- lgr @T[0],@C[0]
- ngr @C[0],@C[1]
- lghi @T[1],-1 # no 'not' instruction :-(
- xgr @C[0],@C[4] # C[4] ^ ( C[0] & C[1])
- xgr @C[1],@T[1] # not @C[1]
- stg @C[0],$A[4][4]($src) # R[4][4] = C[4] ^ ( C[0] & C[1])
- lgr @T[1],@C[2]
- ngr @C[2],@C[1]
- rllg @D[0],@D[0],$rhotates[3][0]
- xgr @C[2],@T[0] # C[0] ^ ( C[2] & ~C[1])
- ogr @T[0],@C[4]
- stg @C[2],$A[4][0]($src) # R[4][0] = C[0] ^ ( C[2] & ~C[1])
- xgr @T[0],@C[3] # C[3] ^ ( C[0] | C[4])
- ngr @C[4],@C[3]
- stg @T[0],$A[4][3]($src) # R[4][3] = C[3] ^ ( C[0] | C[4])
- xgr @C[4],@T[1] # C[2] ^ ( C[4] & C[3])
- ogr @C[3],@T[1]
- stg @C[4],$A[4][2]($src) # R[4][2] = C[2] ^ ( C[4] & C[3])
- xgr @C[3],@C[1] # ~C[1] ^ ( C[2] | C[3])
- lgr @C[1],@C[0] # harmonize with the loop top
- lgr @C[0],@T[0]
- stg @C[3],$A[4][1]($src) # R[4][1] = ~C[1] ^ ( C[2] | C[3])
- tmll $iotas,255
- jnz .Loop
- l${g} %r14,$SIZE_T*14($sp)
- br %r14
- .size __KeccakF1600,.-__KeccakF1600
- ___
- }
- {
- $code.=<<___;
- .type KeccakF1600,\@function
- .align 32
- KeccakF1600:
- .LKeccakF1600:
- lghi %r1,-$frame
- stm${g} %r6,%r15,$SIZE_T*6($sp)
- lgr %r0,$sp
- la $sp,0(%r1,$sp)
- st${g} %r0,0($sp)
- lghi @D[0],-1 # no 'not' instruction :-(
- lghi @D[1],-1
- lghi @D[2],-1
- lghi @D[3],-1
- lghi @D[4],-1
- lghi @T[0],-1
- xg @D[0],$A[0][1]($src)
- xg @D[1],$A[0][2]($src)
- xg @D[2],$A[1][3]($src)
- xg @D[3],$A[2][2]($src)
- xg @D[4],$A[3][2]($src)
- xg @T[0],$A[4][0]($src)
- stmg @D[0],@D[1],$A[0][1]($src)
- stg @D[2],$A[1][3]($src)
- stg @D[3],$A[2][2]($src)
- stg @D[4],$A[3][2]($src)
- stg @T[0],$A[4][0]($src)
- la $dst,$stdframe($sp)
- bras %r14,__KeccakF1600
- lghi @D[0],-1 # no 'not' instruction :-(
- lghi @D[1],-1
- lghi @D[2],-1
- lghi @D[3],-1
- lghi @D[4],-1
- lghi @T[0],-1
- xg @D[0],$A[0][1]($src)
- xg @D[1],$A[0][2]($src)
- xg @D[2],$A[1][3]($src)
- xg @D[3],$A[2][2]($src)
- xg @D[4],$A[3][2]($src)
- xg @T[0],$A[4][0]($src)
- stmg @D[0],@D[1],$A[0][1]($src)
- stg @D[2],$A[1][3]($src)
- stg @D[3],$A[2][2]($src)
- stg @D[4],$A[3][2]($src)
- stg @T[0],$A[4][0]($src)
- lm${g} %r6,%r15,$frame+6*$SIZE_T($sp)
- br %r14
- .size KeccakF1600,.-KeccakF1600
- ___
- }
- { my ($A_flat,$inp,$len,$bsz) = map("%r$_",(2..5));
- $code.=<<___;
- .globl SHA3_absorb
- .type SHA3_absorb,\@function
- .align 32
- SHA3_absorb:
- lghi %r1,-$frame
- stm${g} %r5,%r15,$SIZE_T*5($sp)
- lgr %r0,$sp
- la $sp,0(%r1,$sp)
- st${g} %r0,0($sp)
- lghi @D[0],-1 # no 'not' instruction :-(
- lghi @D[1],-1
- lghi @D[2],-1
- lghi @D[3],-1
- lghi @D[4],-1
- lghi @T[0],-1
- xg @D[0],$A[0][1]($src)
- xg @D[1],$A[0][2]($src)
- xg @D[2],$A[1][3]($src)
- xg @D[3],$A[2][2]($src)
- xg @D[4],$A[3][2]($src)
- xg @T[0],$A[4][0]($src)
- stmg @D[0],@D[1],$A[0][1]($src)
- stg @D[2],$A[1][3]($src)
- stg @D[3],$A[2][2]($src)
- stg @D[4],$A[3][2]($src)
- stg @T[0],$A[4][0]($src)
- .Loop_absorb:
- cl${g}r $len,$bsz
- jl .Ldone_absorb
- srl${g} $bsz,3
- la %r1,0($A_flat)
- .Lblock_absorb:
- lrvg %r0,0($inp)
- la $inp,8($inp)
- xg %r0,0(%r1)
- a${g}hi $len,-8
- stg %r0,0(%r1)
- la %r1,8(%r1)
- brct $bsz,.Lblock_absorb
- stm${g} $inp,$len,$frame+3*$SIZE_T($sp)
- la $dst,$stdframe($sp)
- bras %r14,__KeccakF1600
- lm${g} $inp,$bsz,$frame+3*$SIZE_T($sp)
- j .Loop_absorb
- .align 16
- .Ldone_absorb:
- lghi @D[0],-1 # no 'not' instruction :-(
- lghi @D[1],-1
- lghi @D[2],-1
- lghi @D[3],-1
- lghi @D[4],-1
- lghi @T[0],-1
- xg @D[0],$A[0][1]($src)
- xg @D[1],$A[0][2]($src)
- xg @D[2],$A[1][3]($src)
- xg @D[3],$A[2][2]($src)
- xg @D[4],$A[3][2]($src)
- xg @T[0],$A[4][0]($src)
- stmg @D[0],@D[1],$A[0][1]($src)
- stg @D[2],$A[1][3]($src)
- stg @D[3],$A[2][2]($src)
- stg @D[4],$A[3][2]($src)
- stg @T[0],$A[4][0]($src)
- lgr %r2,$len # return value
- lm${g} %r6,%r15,$frame+6*$SIZE_T($sp)
- br %r14
- .size SHA3_absorb,.-SHA3_absorb
- ___
- }
- { my ($A_flat,$out,$len,$bsz) = map("%r$_",(2..5));
- $code.=<<___;
- .globl SHA3_squeeze
- .type SHA3_squeeze,\@function
- .align 32
- SHA3_squeeze:
- srl${g} $bsz,3
- st${g} %r14,2*$SIZE_T($sp)
- lghi %r14,8
- st${g} $bsz,5*$SIZE_T($sp)
- la %r1,0($A_flat)
- j .Loop_squeeze
- .align 16
- .Loop_squeeze:
- cl${g}r $len,%r14
- jl .Ltail_squeeze
- lrvg %r0,0(%r1)
- la %r1,8(%r1)
- stg %r0,0($out)
- la $out,8($out)
- a${g}hi $len,-8 # len -= 8
- jz .Ldone_squeeze
- brct $bsz,.Loop_squeeze # bsz--
- stm${g} $out,$len,3*$SIZE_T($sp)
- bras %r14,.LKeccakF1600
- lm${g} $out,$bsz,3*$SIZE_T($sp)
- lghi %r14,8
- la %r1,0($A_flat)
- j .Loop_squeeze
- .Ltail_squeeze:
- lg %r0,0(%r1)
- .Loop_tail_squeeze:
- stc %r0,0($out)
- la $out,1($out)
- srlg %r0,8
- brct $len,.Loop_tail_squeeze
- .Ldone_squeeze:
- l${g} %r14,2*$SIZE_T($sp)
- br %r14
- .size SHA3_squeeze,.-SHA3_squeeze
- ___
- }
- $code.=<<___;
- .align 256
- .quad 0,0,0,0,0,0,0,0
- .type iotas,\@object
- iotas:
- .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 iotas,.-iotas
- .asciz "Keccak-1600 absorb and squeeze for s390x, CRYPTOGAMS by <appro\@openssl.org>"
- ___
- # unlike 32-bit shift 64-bit one takes three arguments
- $code =~ s/(srlg\s+)(%r[0-9]+),/$1$2,$2,/gm;
- print $code;
- close STDOUT;
|