Openssl 1.1.0h

This commit is contained in:
Hakase
2018-04-02 22:33:38 +09:00
commit 1fd4faa81c
2471 changed files with 719220 additions and 0 deletions
+1158
View File
@@ -0,0 +1,1158 @@
#! /usr/bin/env perl
# Copyright 2016 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/.
# ====================================================================
#
# December 2014
#
# ChaCha20 for ARMv4.
#
# Performance in cycles per byte out of large buffer.
#
# IALU/gcc-4.4 1xNEON 3xNEON+1xIALU
#
# Cortex-A5 19.3(*)/+95% 21.8 14.1
# Cortex-A8 10.5(*)/+160% 13.9 6.35
# Cortex-A9 12.9(**)/+110% 14.3 6.50
# Cortex-A15 11.0/+40% 16.0 5.00
# Snapdragon S4 11.5/+125% 13.6 4.90
#
# (*) most "favourable" result for aligned data on little-endian
# processor, result for misaligned data is 10-15% lower;
# (**) this result is a trade-off: it can be improved by 20%,
# but then Snapdragon S4 and Cortex-A8 results get
# 20-25% worse;
$flavour = shift;
if ($flavour=~/\w[\w\-]*\.\w+$/) { $output=$flavour; undef $flavour; }
else { while (($output=shift) && ($output!~/\w[\w\-]*\.\w+$/)) {} }
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";
} else {
open STDOUT,">$output";
}
sub AUTOLOAD() # thunk [simplified] x86-style perlasm
{ my $opcode = $AUTOLOAD; $opcode =~ s/.*:://; $opcode =~ s/_/\./;
my $arg = pop;
$arg = "#$arg" if ($arg*1 eq $arg);
$code .= "\t$opcode\t".join(',',@_,$arg)."\n";
}
my @x=map("r$_",(0..7,"x","x","x","x",12,"x",14,"x"));
my @t=map("r$_",(8..11));
sub ROUND {
my ($a0,$b0,$c0,$d0)=@_;
my ($a1,$b1,$c1,$d1)=map(($_&~3)+(($_+1)&3),($a0,$b0,$c0,$d0));
my ($a2,$b2,$c2,$d2)=map(($_&~3)+(($_+1)&3),($a1,$b1,$c1,$d1));
my ($a3,$b3,$c3,$d3)=map(($_&~3)+(($_+1)&3),($a2,$b2,$c2,$d2));
my $odd = $d0&1;
my ($xc,$xc_) = (@t[0..1]);
my ($xd,$xd_) = $odd ? (@t[2],@x[$d1]) : (@x[$d0],@t[2]);
my @ret;
# Consider order in which variables are addressed by their
# index:
#
# a b c d
#
# 0 4 8 12 < even round
# 1 5 9 13
# 2 6 10 14
# 3 7 11 15
# 0 5 10 15 < odd round
# 1 6 11 12
# 2 7 8 13
# 3 4 9 14
#
# 'a', 'b' are permanently allocated in registers, @x[0..7],
# while 'c's and pair of 'd's are maintained in memory. If
# you observe 'c' column, you'll notice that pair of 'c's is
# invariant between rounds. This means that we have to reload
# them once per round, in the middle. This is why you'll see
# bunch of 'c' stores and loads in the middle, but none in
# the beginning or end. If you observe 'd' column, you'll
# notice that 15 and 13 are reused in next pair of rounds.
# This is why these two are chosen for offloading to memory,
# to make loads count more.
push @ret,(
"&add (@x[$a0],@x[$a0],@x[$b0])",
"&mov ($xd,$xd,'ror#16')",
"&add (@x[$a1],@x[$a1],@x[$b1])",
"&mov ($xd_,$xd_,'ror#16')",
"&eor ($xd,$xd,@x[$a0],'ror#16')",
"&eor ($xd_,$xd_,@x[$a1],'ror#16')",
"&add ($xc,$xc,$xd)",
"&mov (@x[$b0],@x[$b0],'ror#20')",
"&add ($xc_,$xc_,$xd_)",
"&mov (@x[$b1],@x[$b1],'ror#20')",
"&eor (@x[$b0],@x[$b0],$xc,'ror#20')",
"&eor (@x[$b1],@x[$b1],$xc_,'ror#20')",
"&add (@x[$a0],@x[$a0],@x[$b0])",
"&mov ($xd,$xd,'ror#24')",
"&add (@x[$a1],@x[$a1],@x[$b1])",
"&mov ($xd_,$xd_,'ror#24')",
"&eor ($xd,$xd,@x[$a0],'ror#24')",
"&eor ($xd_,$xd_,@x[$a1],'ror#24')",
"&add ($xc,$xc,$xd)",
"&mov (@x[$b0],@x[$b0],'ror#25')" );
push @ret,(
"&str ($xd,'[sp,#4*(16+$d0)]')",
"&ldr ($xd,'[sp,#4*(16+$d2)]')" ) if ($odd);
push @ret,(
"&add ($xc_,$xc_,$xd_)",
"&mov (@x[$b1],@x[$b1],'ror#25')" );
push @ret,(
"&str ($xd_,'[sp,#4*(16+$d1)]')",
"&ldr ($xd_,'[sp,#4*(16+$d3)]')" ) if (!$odd);
push @ret,(
"&eor (@x[$b0],@x[$b0],$xc,'ror#25')",
"&eor (@x[$b1],@x[$b1],$xc_,'ror#25')" );
$xd=@x[$d2] if (!$odd);
$xd_=@x[$d3] if ($odd);
push @ret,(
"&str ($xc,'[sp,#4*(16+$c0)]')",
"&ldr ($xc,'[sp,#4*(16+$c2)]')",
"&add (@x[$a2],@x[$a2],@x[$b2])",
"&mov ($xd,$xd,'ror#16')",
"&str ($xc_,'[sp,#4*(16+$c1)]')",
"&ldr ($xc_,'[sp,#4*(16+$c3)]')",
"&add (@x[$a3],@x[$a3],@x[$b3])",
"&mov ($xd_,$xd_,'ror#16')",
"&eor ($xd,$xd,@x[$a2],'ror#16')",
"&eor ($xd_,$xd_,@x[$a3],'ror#16')",
"&add ($xc,$xc,$xd)",
"&mov (@x[$b2],@x[$b2],'ror#20')",
"&add ($xc_,$xc_,$xd_)",
"&mov (@x[$b3],@x[$b3],'ror#20')",
"&eor (@x[$b2],@x[$b2],$xc,'ror#20')",
"&eor (@x[$b3],@x[$b3],$xc_,'ror#20')",
"&add (@x[$a2],@x[$a2],@x[$b2])",
"&mov ($xd,$xd,'ror#24')",
"&add (@x[$a3],@x[$a3],@x[$b3])",
"&mov ($xd_,$xd_,'ror#24')",
"&eor ($xd,$xd,@x[$a2],'ror#24')",
"&eor ($xd_,$xd_,@x[$a3],'ror#24')",
"&add ($xc,$xc,$xd)",
"&mov (@x[$b2],@x[$b2],'ror#25')",
"&add ($xc_,$xc_,$xd_)",
"&mov (@x[$b3],@x[$b3],'ror#25')",
"&eor (@x[$b2],@x[$b2],$xc,'ror#25')",
"&eor (@x[$b3],@x[$b3],$xc_,'ror#25')" );
@ret;
}
$code.=<<___;
#include "arm_arch.h"
.text
#if defined(__thumb2__)
.syntax unified
.thumb
#else
.code 32
#endif
#if defined(__thumb2__) || defined(__clang__)
#define ldrhsb ldrbhs
#endif
.align 5
.Lsigma:
.long 0x61707865,0x3320646e,0x79622d32,0x6b206574 @ endian-neutral
.Lone:
.long 1,0,0,0
#if __ARM_MAX_ARCH__>=7
.LOPENSSL_armcap:
.word OPENSSL_armcap_P-.LChaCha20_ctr32
#else
.word -1
#endif
.globl ChaCha20_ctr32
.type ChaCha20_ctr32,%function
.align 5
ChaCha20_ctr32:
.LChaCha20_ctr32:
ldr r12,[sp,#0] @ pull pointer to counter and nonce
stmdb sp!,{r0-r2,r4-r11,lr}
#if __ARM_ARCH__<7 && !defined(__thumb2__)
sub r14,pc,#16 @ ChaCha20_ctr32
#else
adr r14,.LChaCha20_ctr32
#endif
cmp r2,#0 @ len==0?
#ifdef __thumb2__
itt eq
#endif
addeq sp,sp,#4*3
beq .Lno_data
#if __ARM_MAX_ARCH__>=7
cmp r2,#192 @ test len
bls .Lshort
ldr r4,[r14,#-32]
ldr r4,[r14,r4]
# ifdef __APPLE__
ldr r4,[r4]
# endif
tst r4,#ARMV7_NEON
bne .LChaCha20_neon
.Lshort:
#endif
ldmia r12,{r4-r7} @ load counter and nonce
sub sp,sp,#4*(16) @ off-load area
sub r14,r14,#64 @ .Lsigma
stmdb sp!,{r4-r7} @ copy counter and nonce
ldmia r3,{r4-r11} @ load key
ldmia r14,{r0-r3} @ load sigma
stmdb sp!,{r4-r11} @ copy key
stmdb sp!,{r0-r3} @ copy sigma
str r10,[sp,#4*(16+10)] @ off-load "@x[10]"
str r11,[sp,#4*(16+11)] @ off-load "@x[11]"
b .Loop_outer_enter
.align 4
.Loop_outer:
ldmia sp,{r0-r9} @ load key material
str @t[3],[sp,#4*(32+2)] @ save len
str r12, [sp,#4*(32+1)] @ save inp
str r14, [sp,#4*(32+0)] @ save out
.Loop_outer_enter:
ldr @t[3], [sp,#4*(15)]
ldr @x[12],[sp,#4*(12)] @ modulo-scheduled load
ldr @t[2], [sp,#4*(13)]
ldr @x[14],[sp,#4*(14)]
str @t[3], [sp,#4*(16+15)]
mov @t[3],#10
b .Loop
.align 4
.Loop:
subs @t[3],@t[3],#1
___
foreach (&ROUND(0, 4, 8,12)) { eval; }
foreach (&ROUND(0, 5,10,15)) { eval; }
$code.=<<___;
bne .Loop
ldr @t[3],[sp,#4*(32+2)] @ load len
str @t[0], [sp,#4*(16+8)] @ modulo-scheduled store
str @t[1], [sp,#4*(16+9)]
str @x[12],[sp,#4*(16+12)]
str @t[2], [sp,#4*(16+13)]
str @x[14],[sp,#4*(16+14)]
@ at this point we have first half of 512-bit result in
@ @x[0-7] and second half at sp+4*(16+8)
cmp @t[3],#64 @ done yet?
#ifdef __thumb2__
itete lo
#endif
addlo r12,sp,#4*(0) @ shortcut or ...
ldrhs r12,[sp,#4*(32+1)] @ ... load inp
addlo r14,sp,#4*(0) @ shortcut or ...
ldrhs r14,[sp,#4*(32+0)] @ ... load out
ldr @t[0],[sp,#4*(0)] @ load key material
ldr @t[1],[sp,#4*(1)]
#if __ARM_ARCH__>=6 || !defined(__ARMEB__)
# if __ARM_ARCH__<7
orr @t[2],r12,r14
tst @t[2],#3 @ are input and output aligned?
ldr @t[2],[sp,#4*(2)]
bne .Lunaligned
cmp @t[3],#64 @ restore flags
# else
ldr @t[2],[sp,#4*(2)]
# endif
ldr @t[3],[sp,#4*(3)]
add @x[0],@x[0],@t[0] @ accumulate key material
add @x[1],@x[1],@t[1]
# ifdef __thumb2__
itt hs
# endif
ldrhs @t[0],[r12],#16 @ load input
ldrhs @t[1],[r12,#-12]
add @x[2],@x[2],@t[2]
add @x[3],@x[3],@t[3]
# ifdef __thumb2__
itt hs
# endif
ldrhs @t[2],[r12,#-8]
ldrhs @t[3],[r12,#-4]
# if __ARM_ARCH__>=6 && defined(__ARMEB__)
rev @x[0],@x[0]
rev @x[1],@x[1]
rev @x[2],@x[2]
rev @x[3],@x[3]
# endif
# ifdef __thumb2__
itt hs
# endif
eorhs @x[0],@x[0],@t[0] @ xor with input
eorhs @x[1],@x[1],@t[1]
add @t[0],sp,#4*(4)
str @x[0],[r14],#16 @ store output
# ifdef __thumb2__
itt hs
# endif
eorhs @x[2],@x[2],@t[2]
eorhs @x[3],@x[3],@t[3]
ldmia @t[0],{@t[0]-@t[3]} @ load key material
str @x[1],[r14,#-12]
str @x[2],[r14,#-8]
str @x[3],[r14,#-4]
add @x[4],@x[4],@t[0] @ accumulate key material
add @x[5],@x[5],@t[1]
# ifdef __thumb2__
itt hs
# endif
ldrhs @t[0],[r12],#16 @ load input
ldrhs @t[1],[r12,#-12]
add @x[6],@x[6],@t[2]
add @x[7],@x[7],@t[3]
# ifdef __thumb2__
itt hs
# endif
ldrhs @t[2],[r12,#-8]
ldrhs @t[3],[r12,#-4]
# if __ARM_ARCH__>=6 && defined(__ARMEB__)
rev @x[4],@x[4]
rev @x[5],@x[5]
rev @x[6],@x[6]
rev @x[7],@x[7]
# endif
# ifdef __thumb2__
itt hs
# endif
eorhs @x[4],@x[4],@t[0]
eorhs @x[5],@x[5],@t[1]
add @t[0],sp,#4*(8)
str @x[4],[r14],#16 @ store output
# ifdef __thumb2__
itt hs
# endif
eorhs @x[6],@x[6],@t[2]
eorhs @x[7],@x[7],@t[3]
str @x[5],[r14,#-12]
ldmia @t[0],{@t[0]-@t[3]} @ load key material
str @x[6],[r14,#-8]
add @x[0],sp,#4*(16+8)
str @x[7],[r14,#-4]
ldmia @x[0],{@x[0]-@x[7]} @ load second half
add @x[0],@x[0],@t[0] @ accumulate key material
add @x[1],@x[1],@t[1]
# ifdef __thumb2__
itt hs
# endif
ldrhs @t[0],[r12],#16 @ load input
ldrhs @t[1],[r12,#-12]
# ifdef __thumb2__
itt hi
# endif
strhi @t[2],[sp,#4*(16+10)] @ copy "@x[10]" while at it
strhi @t[3],[sp,#4*(16+11)] @ copy "@x[11]" while at it
add @x[2],@x[2],@t[2]
add @x[3],@x[3],@t[3]
# ifdef __thumb2__
itt hs
# endif
ldrhs @t[2],[r12,#-8]
ldrhs @t[3],[r12,#-4]
# if __ARM_ARCH__>=6 && defined(__ARMEB__)
rev @x[0],@x[0]
rev @x[1],@x[1]
rev @x[2],@x[2]
rev @x[3],@x[3]
# endif
# ifdef __thumb2__
itt hs
# endif
eorhs @x[0],@x[0],@t[0]
eorhs @x[1],@x[1],@t[1]
add @t[0],sp,#4*(12)
str @x[0],[r14],#16 @ store output
# ifdef __thumb2__
itt hs
# endif
eorhs @x[2],@x[2],@t[2]
eorhs @x[3],@x[3],@t[3]
str @x[1],[r14,#-12]
ldmia @t[0],{@t[0]-@t[3]} @ load key material
str @x[2],[r14,#-8]
str @x[3],[r14,#-4]
add @x[4],@x[4],@t[0] @ accumulate key material
add @x[5],@x[5],@t[1]
# ifdef __thumb2__
itt hi
# endif
addhi @t[0],@t[0],#1 @ next counter value
strhi @t[0],[sp,#4*(12)] @ save next counter value
# ifdef __thumb2__
itt hs
# endif
ldrhs @t[0],[r12],#16 @ load input
ldrhs @t[1],[r12,#-12]
add @x[6],@x[6],@t[2]
add @x[7],@x[7],@t[3]
# ifdef __thumb2__
itt hs
# endif
ldrhs @t[2],[r12,#-8]
ldrhs @t[3],[r12,#-4]
# if __ARM_ARCH__>=6 && defined(__ARMEB__)
rev @x[4],@x[4]
rev @x[5],@x[5]
rev @x[6],@x[6]
rev @x[7],@x[7]
# endif
# ifdef __thumb2__
itt hs
# endif
eorhs @x[4],@x[4],@t[0]
eorhs @x[5],@x[5],@t[1]
# ifdef __thumb2__
it ne
# endif
ldrne @t[0],[sp,#4*(32+2)] @ re-load len
# ifdef __thumb2__
itt hs
# endif
eorhs @x[6],@x[6],@t[2]
eorhs @x[7],@x[7],@t[3]
str @x[4],[r14],#16 @ store output
str @x[5],[r14,#-12]
# ifdef __thumb2__
it hs
# endif
subhs @t[3],@t[0],#64 @ len-=64
str @x[6],[r14,#-8]
str @x[7],[r14,#-4]
bhi .Loop_outer
beq .Ldone
# if __ARM_ARCH__<7
b .Ltail
.align 4
.Lunaligned: @ unaligned endian-neutral path
cmp @t[3],#64 @ restore flags
# endif
#endif
#if __ARM_ARCH__<7
ldr @t[3],[sp,#4*(3)]
___
for ($i=0;$i<16;$i+=4) {
my $j=$i&0x7;
$code.=<<___ if ($i==4);
add @x[0],sp,#4*(16+8)
___
$code.=<<___ if ($i==8);
ldmia @x[0],{@x[0]-@x[7]} @ load second half
# ifdef __thumb2__
itt hi
# endif
strhi @t[2],[sp,#4*(16+10)] @ copy "@x[10]"
strhi @t[3],[sp,#4*(16+11)] @ copy "@x[11]"
___
$code.=<<___;
add @x[$j+0],@x[$j+0],@t[0] @ accumulate key material
___
$code.=<<___ if ($i==12);
# ifdef __thumb2__
itt hi
# endif
addhi @t[0],@t[0],#1 @ next counter value
strhi @t[0],[sp,#4*(12)] @ save next counter value
___
$code.=<<___;
add @x[$j+1],@x[$j+1],@t[1]
add @x[$j+2],@x[$j+2],@t[2]
# ifdef __thumb2__
itete lo
# endif
eorlo @t[0],@t[0],@t[0] @ zero or ...
ldrhsb @t[0],[r12],#16 @ ... load input
eorlo @t[1],@t[1],@t[1]
ldrhsb @t[1],[r12,#-12]
add @x[$j+3],@x[$j+3],@t[3]
# ifdef __thumb2__
itete lo
# endif
eorlo @t[2],@t[2],@t[2]
ldrhsb @t[2],[r12,#-8]
eorlo @t[3],@t[3],@t[3]
ldrhsb @t[3],[r12,#-4]
eor @x[$j+0],@t[0],@x[$j+0] @ xor with input (or zero)
eor @x[$j+1],@t[1],@x[$j+1]
# ifdef __thumb2__
itt hs
# endif
ldrhsb @t[0],[r12,#-15] @ load more input
ldrhsb @t[1],[r12,#-11]
eor @x[$j+2],@t[2],@x[$j+2]
strb @x[$j+0],[r14],#16 @ store output
eor @x[$j+3],@t[3],@x[$j+3]
# ifdef __thumb2__
itt hs
# endif
ldrhsb @t[2],[r12,#-7]
ldrhsb @t[3],[r12,#-3]
strb @x[$j+1],[r14,#-12]
eor @x[$j+0],@t[0],@x[$j+0],lsr#8
strb @x[$j+2],[r14,#-8]
eor @x[$j+1],@t[1],@x[$j+1],lsr#8
# ifdef __thumb2__
itt hs
# endif
ldrhsb @t[0],[r12,#-14] @ load more input
ldrhsb @t[1],[r12,#-10]
strb @x[$j+3],[r14,#-4]
eor @x[$j+2],@t[2],@x[$j+2],lsr#8
strb @x[$j+0],[r14,#-15]
eor @x[$j+3],@t[3],@x[$j+3],lsr#8
# ifdef __thumb2__
itt hs
# endif
ldrhsb @t[2],[r12,#-6]
ldrhsb @t[3],[r12,#-2]
strb @x[$j+1],[r14,#-11]
eor @x[$j+0],@t[0],@x[$j+0],lsr#8
strb @x[$j+2],[r14,#-7]
eor @x[$j+1],@t[1],@x[$j+1],lsr#8
# ifdef __thumb2__
itt hs
# endif
ldrhsb @t[0],[r12,#-13] @ load more input
ldrhsb @t[1],[r12,#-9]
strb @x[$j+3],[r14,#-3]
eor @x[$j+2],@t[2],@x[$j+2],lsr#8
strb @x[$j+0],[r14,#-14]
eor @x[$j+3],@t[3],@x[$j+3],lsr#8
# ifdef __thumb2__
itt hs
# endif
ldrhsb @t[2],[r12,#-5]
ldrhsb @t[3],[r12,#-1]
strb @x[$j+1],[r14,#-10]
strb @x[$j+2],[r14,#-6]
eor @x[$j+0],@t[0],@x[$j+0],lsr#8
strb @x[$j+3],[r14,#-2]
eor @x[$j+1],@t[1],@x[$j+1],lsr#8
strb @x[$j+0],[r14,#-13]
eor @x[$j+2],@t[2],@x[$j+2],lsr#8
strb @x[$j+1],[r14,#-9]
eor @x[$j+3],@t[3],@x[$j+3],lsr#8
strb @x[$j+2],[r14,#-5]
strb @x[$j+3],[r14,#-1]
___
$code.=<<___ if ($i<12);
add @t[0],sp,#4*(4+$i)
ldmia @t[0],{@t[0]-@t[3]} @ load key material
___
}
$code.=<<___;
# ifdef __thumb2__
it ne
# endif
ldrne @t[0],[sp,#4*(32+2)] @ re-load len
# ifdef __thumb2__
it hs
# endif
subhs @t[3],@t[0],#64 @ len-=64
bhi .Loop_outer
beq .Ldone
#endif
.Ltail:
ldr r12,[sp,#4*(32+1)] @ load inp
add @t[1],sp,#4*(0)
ldr r14,[sp,#4*(32+0)] @ load out
.Loop_tail:
ldrb @t[2],[@t[1]],#1 @ read buffer on stack
ldrb @t[3],[r12],#1 @ read input
subs @t[0],@t[0],#1
eor @t[3],@t[3],@t[2]
strb @t[3],[r14],#1 @ store output
bne .Loop_tail
.Ldone:
add sp,sp,#4*(32+3)
.Lno_data:
ldmia sp!,{r4-r11,pc}
.size ChaCha20_ctr32,.-ChaCha20_ctr32
___
{{{
my ($a0,$b0,$c0,$d0,$a1,$b1,$c1,$d1,$a2,$b2,$c2,$d2,$t0,$t1,$t2,$t3) =
map("q$_",(0..15));
sub NEONROUND {
my $odd = pop;
my ($a,$b,$c,$d,$t)=@_;
(
"&vadd_i32 ($a,$a,$b)",
"&veor ($d,$d,$a)",
"&vrev32_16 ($d,$d)", # vrot ($d,16)
"&vadd_i32 ($c,$c,$d)",
"&veor ($t,$b,$c)",
"&vshr_u32 ($b,$t,20)",
"&vsli_32 ($b,$t,12)",
"&vadd_i32 ($a,$a,$b)",
"&veor ($t,$d,$a)",
"&vshr_u32 ($d,$t,24)",
"&vsli_32 ($d,$t,8)",
"&vadd_i32 ($c,$c,$d)",
"&veor ($t,$b,$c)",
"&vshr_u32 ($b,$t,25)",
"&vsli_32 ($b,$t,7)",
"&vext_8 ($c,$c,$c,8)",
"&vext_8 ($b,$b,$b,$odd?12:4)",
"&vext_8 ($d,$d,$d,$odd?4:12)"
);
}
$code.=<<___;
#if __ARM_MAX_ARCH__>=7
.arch armv7-a
.fpu neon
.type ChaCha20_neon,%function
.align 5
ChaCha20_neon:
ldr r12,[sp,#0] @ pull pointer to counter and nonce
stmdb sp!,{r0-r2,r4-r11,lr}
.LChaCha20_neon:
adr r14,.Lsigma
vstmdb sp!,{d8-d15} @ ABI spec says so
stmdb sp!,{r0-r3}
vld1.32 {$b0-$c0},[r3] @ load key
ldmia r3,{r4-r11} @ load key
sub sp,sp,#4*(16+16)
vld1.32 {$d0},[r12] @ load counter and nonce
add r12,sp,#4*8
ldmia r14,{r0-r3} @ load sigma
vld1.32 {$a0},[r14]! @ load sigma
vld1.32 {$t0},[r14] @ one
vst1.32 {$c0-$d0},[r12] @ copy 1/2key|counter|nonce
vst1.32 {$a0-$b0},[sp] @ copy sigma|1/2key
str r10,[sp,#4*(16+10)] @ off-load "@x[10]"
str r11,[sp,#4*(16+11)] @ off-load "@x[11]"
vshl.i32 $t1#lo,$t0#lo,#1 @ two
vstr $t0#lo,[sp,#4*(16+0)]
vshl.i32 $t2#lo,$t0#lo,#2 @ four
vstr $t1#lo,[sp,#4*(16+2)]
vmov $a1,$a0
vstr $t2#lo,[sp,#4*(16+4)]
vmov $a2,$a0
vmov $b1,$b0
vmov $b2,$b0
b .Loop_neon_enter
.align 4
.Loop_neon_outer:
ldmia sp,{r0-r9} @ load key material
cmp @t[3],#64*2 @ if len<=64*2
bls .Lbreak_neon @ switch to integer-only
vmov $a1,$a0
str @t[3],[sp,#4*(32+2)] @ save len
vmov $a2,$a0
str r12, [sp,#4*(32+1)] @ save inp
vmov $b1,$b0
str r14, [sp,#4*(32+0)] @ save out
vmov $b2,$b0
.Loop_neon_enter:
ldr @t[3], [sp,#4*(15)]
vadd.i32 $d1,$d0,$t0 @ counter+1
ldr @x[12],[sp,#4*(12)] @ modulo-scheduled load
vmov $c1,$c0
ldr @t[2], [sp,#4*(13)]
vmov $c2,$c0
ldr @x[14],[sp,#4*(14)]
vadd.i32 $d2,$d1,$t0 @ counter+2
str @t[3], [sp,#4*(16+15)]
mov @t[3],#10
add @x[12],@x[12],#3 @ counter+3
b .Loop_neon
.align 4
.Loop_neon:
subs @t[3],@t[3],#1
___
my @thread0=&NEONROUND($a0,$b0,$c0,$d0,$t0,0);
my @thread1=&NEONROUND($a1,$b1,$c1,$d1,$t1,0);
my @thread2=&NEONROUND($a2,$b2,$c2,$d2,$t2,0);
my @thread3=&ROUND(0,4,8,12);
foreach (@thread0) {
eval; eval(shift(@thread3));
eval(shift(@thread1)); eval(shift(@thread3));
eval(shift(@thread2)); eval(shift(@thread3));
}
@thread0=&NEONROUND($a0,$b0,$c0,$d0,$t0,1);
@thread1=&NEONROUND($a1,$b1,$c1,$d1,$t1,1);
@thread2=&NEONROUND($a2,$b2,$c2,$d2,$t2,1);
@thread3=&ROUND(0,5,10,15);
foreach (@thread0) {
eval; eval(shift(@thread3));
eval(shift(@thread1)); eval(shift(@thread3));
eval(shift(@thread2)); eval(shift(@thread3));
}
$code.=<<___;
bne .Loop_neon
add @t[3],sp,#32
vld1.32 {$t0-$t1},[sp] @ load key material
vld1.32 {$t2-$t3},[@t[3]]
ldr @t[3],[sp,#4*(32+2)] @ load len
str @t[0], [sp,#4*(16+8)] @ modulo-scheduled store
str @t[1], [sp,#4*(16+9)]
str @x[12],[sp,#4*(16+12)]
str @t[2], [sp,#4*(16+13)]
str @x[14],[sp,#4*(16+14)]
@ at this point we have first half of 512-bit result in
@ @x[0-7] and second half at sp+4*(16+8)
ldr r12,[sp,#4*(32+1)] @ load inp
ldr r14,[sp,#4*(32+0)] @ load out
vadd.i32 $a0,$a0,$t0 @ accumulate key material
vadd.i32 $a1,$a1,$t0
vadd.i32 $a2,$a2,$t0
vldr $t0#lo,[sp,#4*(16+0)] @ one
vadd.i32 $b0,$b0,$t1
vadd.i32 $b1,$b1,$t1
vadd.i32 $b2,$b2,$t1
vldr $t1#lo,[sp,#4*(16+2)] @ two
vadd.i32 $c0,$c0,$t2
vadd.i32 $c1,$c1,$t2
vadd.i32 $c2,$c2,$t2
vadd.i32 $d1#lo,$d1#lo,$t0#lo @ counter+1
vadd.i32 $d2#lo,$d2#lo,$t1#lo @ counter+2
vadd.i32 $d0,$d0,$t3
vadd.i32 $d1,$d1,$t3
vadd.i32 $d2,$d2,$t3
cmp @t[3],#64*4
blo .Ltail_neon
vld1.8 {$t0-$t1},[r12]! @ load input
mov @t[3],sp
vld1.8 {$t2-$t3},[r12]!
veor $a0,$a0,$t0 @ xor with input
veor $b0,$b0,$t1
vld1.8 {$t0-$t1},[r12]!
veor $c0,$c0,$t2
veor $d0,$d0,$t3
vld1.8 {$t2-$t3},[r12]!
veor $a1,$a1,$t0
vst1.8 {$a0-$b0},[r14]! @ store output
veor $b1,$b1,$t1
vld1.8 {$t0-$t1},[r12]!
veor $c1,$c1,$t2
vst1.8 {$c0-$d0},[r14]!
veor $d1,$d1,$t3
vld1.8 {$t2-$t3},[r12]!
veor $a2,$a2,$t0
vld1.32 {$a0-$b0},[@t[3]]! @ load for next iteration
veor $t0#hi,$t0#hi,$t0#hi
vldr $t0#lo,[sp,#4*(16+4)] @ four
veor $b2,$b2,$t1
vld1.32 {$c0-$d0},[@t[3]]
veor $c2,$c2,$t2
vst1.8 {$a1-$b1},[r14]!
veor $d2,$d2,$t3
vst1.8 {$c1-$d1},[r14]!
vadd.i32 $d0#lo,$d0#lo,$t0#lo @ next counter value
vldr $t0#lo,[sp,#4*(16+0)] @ one
ldmia sp,{@t[0]-@t[3]} @ load key material
add @x[0],@x[0],@t[0] @ accumulate key material
ldr @t[0],[r12],#16 @ load input
vst1.8 {$a2-$b2},[r14]!
add @x[1],@x[1],@t[1]
ldr @t[1],[r12,#-12]
vst1.8 {$c2-$d2},[r14]!
add @x[2],@x[2],@t[2]
ldr @t[2],[r12,#-8]
add @x[3],@x[3],@t[3]
ldr @t[3],[r12,#-4]
# ifdef __ARMEB__
rev @x[0],@x[0]
rev @x[1],@x[1]
rev @x[2],@x[2]
rev @x[3],@x[3]
# endif
eor @x[0],@x[0],@t[0] @ xor with input
add @t[0],sp,#4*(4)
eor @x[1],@x[1],@t[1]
str @x[0],[r14],#16 @ store output
eor @x[2],@x[2],@t[2]
str @x[1],[r14,#-12]
eor @x[3],@x[3],@t[3]
ldmia @t[0],{@t[0]-@t[3]} @ load key material
str @x[2],[r14,#-8]
str @x[3],[r14,#-4]
add @x[4],@x[4],@t[0] @ accumulate key material
ldr @t[0],[r12],#16 @ load input
add @x[5],@x[5],@t[1]
ldr @t[1],[r12,#-12]
add @x[6],@x[6],@t[2]
ldr @t[2],[r12,#-8]
add @x[7],@x[7],@t[3]
ldr @t[3],[r12,#-4]
# ifdef __ARMEB__
rev @x[4],@x[4]
rev @x[5],@x[5]
rev @x[6],@x[6]
rev @x[7],@x[7]
# endif
eor @x[4],@x[4],@t[0]
add @t[0],sp,#4*(8)
eor @x[5],@x[5],@t[1]
str @x[4],[r14],#16 @ store output
eor @x[6],@x[6],@t[2]
str @x[5],[r14,#-12]
eor @x[7],@x[7],@t[3]
ldmia @t[0],{@t[0]-@t[3]} @ load key material
str @x[6],[r14,#-8]
add @x[0],sp,#4*(16+8)
str @x[7],[r14,#-4]
ldmia @x[0],{@x[0]-@x[7]} @ load second half
add @x[0],@x[0],@t[0] @ accumulate key material
ldr @t[0],[r12],#16 @ load input
add @x[1],@x[1],@t[1]
ldr @t[1],[r12,#-12]
# ifdef __thumb2__
it hi
# endif
strhi @t[2],[sp,#4*(16+10)] @ copy "@x[10]" while at it
add @x[2],@x[2],@t[2]
ldr @t[2],[r12,#-8]
# ifdef __thumb2__
it hi
# endif
strhi @t[3],[sp,#4*(16+11)] @ copy "@x[11]" while at it
add @x[3],@x[3],@t[3]
ldr @t[3],[r12,#-4]
# ifdef __ARMEB__
rev @x[0],@x[0]
rev @x[1],@x[1]
rev @x[2],@x[2]
rev @x[3],@x[3]
# endif
eor @x[0],@x[0],@t[0]
add @t[0],sp,#4*(12)
eor @x[1],@x[1],@t[1]
str @x[0],[r14],#16 @ store output
eor @x[2],@x[2],@t[2]
str @x[1],[r14,#-12]
eor @x[3],@x[3],@t[3]
ldmia @t[0],{@t[0]-@t[3]} @ load key material
str @x[2],[r14,#-8]
str @x[3],[r14,#-4]
add @x[4],@x[4],@t[0] @ accumulate key material
add @t[0],@t[0],#4 @ next counter value
add @x[5],@x[5],@t[1]
str @t[0],[sp,#4*(12)] @ save next counter value
ldr @t[0],[r12],#16 @ load input
add @x[6],@x[6],@t[2]
add @x[4],@x[4],#3 @ counter+3
ldr @t[1],[r12,#-12]
add @x[7],@x[7],@t[3]
ldr @t[2],[r12,#-8]
ldr @t[3],[r12,#-4]
# ifdef __ARMEB__
rev @x[4],@x[4]
rev @x[5],@x[5]
rev @x[6],@x[6]
rev @x[7],@x[7]
# endif
eor @x[4],@x[4],@t[0]
# ifdef __thumb2__
it hi
# endif
ldrhi @t[0],[sp,#4*(32+2)] @ re-load len
eor @x[5],@x[5],@t[1]
eor @x[6],@x[6],@t[2]
str @x[4],[r14],#16 @ store output
eor @x[7],@x[7],@t[3]
str @x[5],[r14,#-12]
sub @t[3],@t[0],#64*4 @ len-=64*4
str @x[6],[r14,#-8]
str @x[7],[r14,#-4]
bhi .Loop_neon_outer
b .Ldone_neon
.align 4
.Lbreak_neon:
@ harmonize NEON and integer-only stack frames: load data
@ from NEON frame, but save to integer-only one; distance
@ between the two is 4*(32+4+16-32)=4*(20).
str @t[3], [sp,#4*(20+32+2)] @ save len
add @t[3],sp,#4*(32+4)
str r12, [sp,#4*(20+32+1)] @ save inp
str r14, [sp,#4*(20+32+0)] @ save out
ldr @x[12],[sp,#4*(16+10)]
ldr @x[14],[sp,#4*(16+11)]
vldmia @t[3],{d8-d15} @ fulfill ABI requirement
str @x[12],[sp,#4*(20+16+10)] @ copy "@x[10]"
str @x[14],[sp,#4*(20+16+11)] @ copy "@x[11]"
ldr @t[3], [sp,#4*(15)]
ldr @x[12],[sp,#4*(12)] @ modulo-scheduled load
ldr @t[2], [sp,#4*(13)]
ldr @x[14],[sp,#4*(14)]
str @t[3], [sp,#4*(20+16+15)]
add @t[3],sp,#4*(20)
vst1.32 {$a0-$b0},[@t[3]]! @ copy key
add sp,sp,#4*(20) @ switch frame
vst1.32 {$c0-$d0},[@t[3]]
mov @t[3],#10
b .Loop @ go integer-only
.align 4
.Ltail_neon:
cmp @t[3],#64*3
bhs .L192_or_more_neon
cmp @t[3],#64*2
bhs .L128_or_more_neon
cmp @t[3],#64*1
bhs .L64_or_more_neon
add @t[0],sp,#4*(8)
vst1.8 {$a0-$b0},[sp]
add @t[2],sp,#4*(0)
vst1.8 {$c0-$d0},[@t[0]]
b .Loop_tail_neon
.align 4
.L64_or_more_neon:
vld1.8 {$t0-$t1},[r12]!
vld1.8 {$t2-$t3},[r12]!
veor $a0,$a0,$t0
veor $b0,$b0,$t1
veor $c0,$c0,$t2
veor $d0,$d0,$t3
vst1.8 {$a0-$b0},[r14]!
vst1.8 {$c0-$d0},[r14]!
beq .Ldone_neon
add @t[0],sp,#4*(8)
vst1.8 {$a1-$b1},[sp]
add @t[2],sp,#4*(0)
vst1.8 {$c1-$d1},[@t[0]]
sub @t[3],@t[3],#64*1 @ len-=64*1
b .Loop_tail_neon
.align 4
.L128_or_more_neon:
vld1.8 {$t0-$t1},[r12]!
vld1.8 {$t2-$t3},[r12]!
veor $a0,$a0,$t0
veor $b0,$b0,$t1
vld1.8 {$t0-$t1},[r12]!
veor $c0,$c0,$t2
veor $d0,$d0,$t3
vld1.8 {$t2-$t3},[r12]!
veor $a1,$a1,$t0
veor $b1,$b1,$t1
vst1.8 {$a0-$b0},[r14]!
veor $c1,$c1,$t2
vst1.8 {$c0-$d0},[r14]!
veor $d1,$d1,$t3
vst1.8 {$a1-$b1},[r14]!
vst1.8 {$c1-$d1},[r14]!
beq .Ldone_neon
add @t[0],sp,#4*(8)
vst1.8 {$a2-$b2},[sp]
add @t[2],sp,#4*(0)
vst1.8 {$c2-$d2},[@t[0]]
sub @t[3],@t[3],#64*2 @ len-=64*2
b .Loop_tail_neon
.align 4
.L192_or_more_neon:
vld1.8 {$t0-$t1},[r12]!
vld1.8 {$t2-$t3},[r12]!
veor $a0,$a0,$t0
veor $b0,$b0,$t1
vld1.8 {$t0-$t1},[r12]!
veor $c0,$c0,$t2
veor $d0,$d0,$t3
vld1.8 {$t2-$t3},[r12]!
veor $a1,$a1,$t0
veor $b1,$b1,$t1
vld1.8 {$t0-$t1},[r12]!
veor $c1,$c1,$t2
vst1.8 {$a0-$b0},[r14]!
veor $d1,$d1,$t3
vld1.8 {$t2-$t3},[r12]!
veor $a2,$a2,$t0
vst1.8 {$c0-$d0},[r14]!
veor $b2,$b2,$t1
vst1.8 {$a1-$b1},[r14]!
veor $c2,$c2,$t2
vst1.8 {$c1-$d1},[r14]!
veor $d2,$d2,$t3
vst1.8 {$a2-$b2},[r14]!
vst1.8 {$c2-$d2},[r14]!
beq .Ldone_neon
ldmia sp,{@t[0]-@t[3]} @ load key material
add @x[0],@x[0],@t[0] @ accumulate key material
add @t[0],sp,#4*(4)
add @x[1],@x[1],@t[1]
add @x[2],@x[2],@t[2]
add @x[3],@x[3],@t[3]
ldmia @t[0],{@t[0]-@t[3]} @ load key material
add @x[4],@x[4],@t[0] @ accumulate key material
add @t[0],sp,#4*(8)
add @x[5],@x[5],@t[1]
add @x[6],@x[6],@t[2]
add @x[7],@x[7],@t[3]
ldmia @t[0],{@t[0]-@t[3]} @ load key material
# ifdef __ARMEB__
rev @x[0],@x[0]
rev @x[1],@x[1]
rev @x[2],@x[2]
rev @x[3],@x[3]
rev @x[4],@x[4]
rev @x[5],@x[5]
rev @x[6],@x[6]
rev @x[7],@x[7]
# endif
stmia sp,{@x[0]-@x[7]}
add @x[0],sp,#4*(16+8)
ldmia @x[0],{@x[0]-@x[7]} @ load second half
add @x[0],@x[0],@t[0] @ accumulate key material
add @t[0],sp,#4*(12)
add @x[1],@x[1],@t[1]
add @x[2],@x[2],@t[2]
add @x[3],@x[3],@t[3]
ldmia @t[0],{@t[0]-@t[3]} @ load key material
add @x[4],@x[4],@t[0] @ accumulate key material
add @t[0],sp,#4*(8)
add @x[5],@x[5],@t[1]
add @x[4],@x[4],#3 @ counter+3
add @x[6],@x[6],@t[2]
add @x[7],@x[7],@t[3]
ldr @t[3],[sp,#4*(32+2)] @ re-load len
# ifdef __ARMEB__
rev @x[0],@x[0]
rev @x[1],@x[1]
rev @x[2],@x[2]
rev @x[3],@x[3]
rev @x[4],@x[4]
rev @x[5],@x[5]
rev @x[6],@x[6]
rev @x[7],@x[7]
# endif
stmia @t[0],{@x[0]-@x[7]}
add @t[2],sp,#4*(0)
sub @t[3],@t[3],#64*3 @ len-=64*3
.Loop_tail_neon:
ldrb @t[0],[@t[2]],#1 @ read buffer on stack
ldrb @t[1],[r12],#1 @ read input
subs @t[3],@t[3],#1
eor @t[0],@t[0],@t[1]
strb @t[0],[r14],#1 @ store output
bne .Loop_tail_neon
.Ldone_neon:
add sp,sp,#4*(32+4)
vldmia sp,{d8-d15}
add sp,sp,#4*(16+3)
ldmia sp!,{r4-r11,pc}
.size ChaCha20_neon,.-ChaCha20_neon
.comm OPENSSL_armcap_P,4,4
#endif
___
}}}
foreach (split("\n",$code)) {
s/\`([^\`]*)\`/eval $1/geo;
s/\bq([0-9]+)#(lo|hi)/sprintf "d%d",2*$1+($2 eq "hi")/geo;
print $_,"\n";
}
close STDOUT;
+1135
View File
@@ -0,0 +1,1135 @@
#! /usr/bin/env perl
# Copyright 2016 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/.
# ====================================================================
#
# June 2015
#
# ChaCha20 for ARMv8.
#
# Performance in cycles per byte out of large buffer.
#
# IALU/gcc-4.9 3xNEON+1xIALU 6xNEON+2xIALU
#
# Apple A7 5.50/+49% 3.33 1.70
# Cortex-A53 8.40/+80% 4.72 4.72(*)
# Cortex-A57 8.06/+43% 4.90 4.43(**)
# Denver 4.50/+82% 2.63 2.67(*)
# X-Gene 9.50/+46% 8.82 8.89(*)
# Mongoose 8.00/+44% 3.64 3.25
#
# (*) it's expected that doubling interleave factor doesn't help
# all processors, only those with higher NEON latency and
# higher instruction issue rate;
# (**) expected improvement was actually higher;
$flavour=shift;
$output=shift;
$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 OUT,"| \"$^X\" $xlate $flavour $output";
*STDOUT=*OUT;
sub AUTOLOAD() # thunk [simplified] x86-style perlasm
{ my $opcode = $AUTOLOAD; $opcode =~ s/.*:://; $opcode =~ s/_/\./;
my $arg = pop;
$arg = "#$arg" if ($arg*1 eq $arg);
$code .= "\t$opcode\t".join(',',@_,$arg)."\n";
}
my ($out,$inp,$len,$key,$ctr) = map("x$_",(0..4));
my @x=map("x$_",(5..17,19..21));
my @d=map("x$_",(22..28,30));
sub ROUND {
my ($a0,$b0,$c0,$d0)=@_;
my ($a1,$b1,$c1,$d1)=map(($_&~3)+(($_+1)&3),($a0,$b0,$c0,$d0));
my ($a2,$b2,$c2,$d2)=map(($_&~3)+(($_+1)&3),($a1,$b1,$c1,$d1));
my ($a3,$b3,$c3,$d3)=map(($_&~3)+(($_+1)&3),($a2,$b2,$c2,$d2));
(
"&add_32 (@x[$a0],@x[$a0],@x[$b0])",
"&add_32 (@x[$a1],@x[$a1],@x[$b1])",
"&add_32 (@x[$a2],@x[$a2],@x[$b2])",
"&add_32 (@x[$a3],@x[$a3],@x[$b3])",
"&eor_32 (@x[$d0],@x[$d0],@x[$a0])",
"&eor_32 (@x[$d1],@x[$d1],@x[$a1])",
"&eor_32 (@x[$d2],@x[$d2],@x[$a2])",
"&eor_32 (@x[$d3],@x[$d3],@x[$a3])",
"&ror_32 (@x[$d0],@x[$d0],16)",
"&ror_32 (@x[$d1],@x[$d1],16)",
"&ror_32 (@x[$d2],@x[$d2],16)",
"&ror_32 (@x[$d3],@x[$d3],16)",
"&add_32 (@x[$c0],@x[$c0],@x[$d0])",
"&add_32 (@x[$c1],@x[$c1],@x[$d1])",
"&add_32 (@x[$c2],@x[$c2],@x[$d2])",
"&add_32 (@x[$c3],@x[$c3],@x[$d3])",
"&eor_32 (@x[$b0],@x[$b0],@x[$c0])",
"&eor_32 (@x[$b1],@x[$b1],@x[$c1])",
"&eor_32 (@x[$b2],@x[$b2],@x[$c2])",
"&eor_32 (@x[$b3],@x[$b3],@x[$c3])",
"&ror_32 (@x[$b0],@x[$b0],20)",
"&ror_32 (@x[$b1],@x[$b1],20)",
"&ror_32 (@x[$b2],@x[$b2],20)",
"&ror_32 (@x[$b3],@x[$b3],20)",
"&add_32 (@x[$a0],@x[$a0],@x[$b0])",
"&add_32 (@x[$a1],@x[$a1],@x[$b1])",
"&add_32 (@x[$a2],@x[$a2],@x[$b2])",
"&add_32 (@x[$a3],@x[$a3],@x[$b3])",
"&eor_32 (@x[$d0],@x[$d0],@x[$a0])",
"&eor_32 (@x[$d1],@x[$d1],@x[$a1])",
"&eor_32 (@x[$d2],@x[$d2],@x[$a2])",
"&eor_32 (@x[$d3],@x[$d3],@x[$a3])",
"&ror_32 (@x[$d0],@x[$d0],24)",
"&ror_32 (@x[$d1],@x[$d1],24)",
"&ror_32 (@x[$d2],@x[$d2],24)",
"&ror_32 (@x[$d3],@x[$d3],24)",
"&add_32 (@x[$c0],@x[$c0],@x[$d0])",
"&add_32 (@x[$c1],@x[$c1],@x[$d1])",
"&add_32 (@x[$c2],@x[$c2],@x[$d2])",
"&add_32 (@x[$c3],@x[$c3],@x[$d3])",
"&eor_32 (@x[$b0],@x[$b0],@x[$c0])",
"&eor_32 (@x[$b1],@x[$b1],@x[$c1])",
"&eor_32 (@x[$b2],@x[$b2],@x[$c2])",
"&eor_32 (@x[$b3],@x[$b3],@x[$c3])",
"&ror_32 (@x[$b0],@x[$b0],25)",
"&ror_32 (@x[$b1],@x[$b1],25)",
"&ror_32 (@x[$b2],@x[$b2],25)",
"&ror_32 (@x[$b3],@x[$b3],25)"
);
}
$code.=<<___;
#include "arm_arch.h"
.text
.extern OPENSSL_armcap_P
.align 5
.Lsigma:
.quad 0x3320646e61707865,0x6b20657479622d32 // endian-neutral
.Lone:
.long 1,0,0,0
.LOPENSSL_armcap_P:
#ifdef __ILP32__
.long OPENSSL_armcap_P-.
#else
.quad OPENSSL_armcap_P-.
#endif
.asciz "ChaCha20 for ARMv8, CRYPTOGAMS by <appro\@openssl.org>"
.globl ChaCha20_ctr32
.type ChaCha20_ctr32,%function
.align 5
ChaCha20_ctr32:
cbz $len,.Labort
adr @x[0],.LOPENSSL_armcap_P
cmp $len,#192
b.lo .Lshort
#ifdef __ILP32__
ldrsw @x[1],[@x[0]]
#else
ldr @x[1],[@x[0]]
#endif
ldr w17,[@x[1],@x[0]]
tst w17,#ARMV7_NEON
b.ne ChaCha20_neon
.Lshort:
stp x29,x30,[sp,#-96]!
add x29,sp,#0
adr @x[0],.Lsigma
stp x19,x20,[sp,#16]
stp x21,x22,[sp,#32]
stp x23,x24,[sp,#48]
stp x25,x26,[sp,#64]
stp x27,x28,[sp,#80]
sub sp,sp,#64
ldp @d[0],@d[1],[@x[0]] // load sigma
ldp @d[2],@d[3],[$key] // load key
ldp @d[4],@d[5],[$key,#16]
ldp @d[6],@d[7],[$ctr] // load counter
#ifdef __ARMEB__
ror @d[2],@d[2],#32
ror @d[3],@d[3],#32
ror @d[4],@d[4],#32
ror @d[5],@d[5],#32
ror @d[6],@d[6],#32
ror @d[7],@d[7],#32
#endif
.Loop_outer:
mov.32 @x[0],@d[0] // unpack key block
lsr @x[1],@d[0],#32
mov.32 @x[2],@d[1]
lsr @x[3],@d[1],#32
mov.32 @x[4],@d[2]
lsr @x[5],@d[2],#32
mov.32 @x[6],@d[3]
lsr @x[7],@d[3],#32
mov.32 @x[8],@d[4]
lsr @x[9],@d[4],#32
mov.32 @x[10],@d[5]
lsr @x[11],@d[5],#32
mov.32 @x[12],@d[6]
lsr @x[13],@d[6],#32
mov.32 @x[14],@d[7]
lsr @x[15],@d[7],#32
mov $ctr,#10
subs $len,$len,#64
.Loop:
sub $ctr,$ctr,#1
___
foreach (&ROUND(0, 4, 8,12)) { eval; }
foreach (&ROUND(0, 5,10,15)) { eval; }
$code.=<<___;
cbnz $ctr,.Loop
add.32 @x[0],@x[0],@d[0] // accumulate key block
add @x[1],@x[1],@d[0],lsr#32
add.32 @x[2],@x[2],@d[1]
add @x[3],@x[3],@d[1],lsr#32
add.32 @x[4],@x[4],@d[2]
add @x[5],@x[5],@d[2],lsr#32
add.32 @x[6],@x[6],@d[3]
add @x[7],@x[7],@d[3],lsr#32
add.32 @x[8],@x[8],@d[4]
add @x[9],@x[9],@d[4],lsr#32
add.32 @x[10],@x[10],@d[5]
add @x[11],@x[11],@d[5],lsr#32
add.32 @x[12],@x[12],@d[6]
add @x[13],@x[13],@d[6],lsr#32
add.32 @x[14],@x[14],@d[7]
add @x[15],@x[15],@d[7],lsr#32
b.lo .Ltail
add @x[0],@x[0],@x[1],lsl#32 // pack
add @x[2],@x[2],@x[3],lsl#32
ldp @x[1],@x[3],[$inp,#0] // load input
add @x[4],@x[4],@x[5],lsl#32
add @x[6],@x[6],@x[7],lsl#32
ldp @x[5],@x[7],[$inp,#16]
add @x[8],@x[8],@x[9],lsl#32
add @x[10],@x[10],@x[11],lsl#32
ldp @x[9],@x[11],[$inp,#32]
add @x[12],@x[12],@x[13],lsl#32
add @x[14],@x[14],@x[15],lsl#32
ldp @x[13],@x[15],[$inp,#48]
add $inp,$inp,#64
#ifdef __ARMEB__
rev @x[0],@x[0]
rev @x[2],@x[2]
rev @x[4],@x[4]
rev @x[6],@x[6]
rev @x[8],@x[8]
rev @x[10],@x[10]
rev @x[12],@x[12]
rev @x[14],@x[14]
#endif
eor @x[0],@x[0],@x[1]
eor @x[2],@x[2],@x[3]
eor @x[4],@x[4],@x[5]
eor @x[6],@x[6],@x[7]
eor @x[8],@x[8],@x[9]
eor @x[10],@x[10],@x[11]
eor @x[12],@x[12],@x[13]
eor @x[14],@x[14],@x[15]
stp @x[0],@x[2],[$out,#0] // store output
add @d[6],@d[6],#1 // increment counter
stp @x[4],@x[6],[$out,#16]
stp @x[8],@x[10],[$out,#32]
stp @x[12],@x[14],[$out,#48]
add $out,$out,#64
b.hi .Loop_outer
ldp x19,x20,[x29,#16]
add sp,sp,#64
ldp x21,x22,[x29,#32]
ldp x23,x24,[x29,#48]
ldp x25,x26,[x29,#64]
ldp x27,x28,[x29,#80]
ldp x29,x30,[sp],#96
.Labort:
ret
.align 4
.Ltail:
add $len,$len,#64
.Less_than_64:
sub $out,$out,#1
add $inp,$inp,$len
add $out,$out,$len
add $ctr,sp,$len
neg $len,$len
add @x[0],@x[0],@x[1],lsl#32 // pack
add @x[2],@x[2],@x[3],lsl#32
add @x[4],@x[4],@x[5],lsl#32
add @x[6],@x[6],@x[7],lsl#32
add @x[8],@x[8],@x[9],lsl#32
add @x[10],@x[10],@x[11],lsl#32
add @x[12],@x[12],@x[13],lsl#32
add @x[14],@x[14],@x[15],lsl#32
#ifdef __ARMEB__
rev @x[0],@x[0]
rev @x[2],@x[2]
rev @x[4],@x[4]
rev @x[6],@x[6]
rev @x[8],@x[8]
rev @x[10],@x[10]
rev @x[12],@x[12]
rev @x[14],@x[14]
#endif
stp @x[0],@x[2],[sp,#0]
stp @x[4],@x[6],[sp,#16]
stp @x[8],@x[10],[sp,#32]
stp @x[12],@x[14],[sp,#48]
.Loop_tail:
ldrb w10,[$inp,$len]
ldrb w11,[$ctr,$len]
add $len,$len,#1
eor w10,w10,w11
strb w10,[$out,$len]
cbnz $len,.Loop_tail
stp xzr,xzr,[sp,#0]
stp xzr,xzr,[sp,#16]
stp xzr,xzr,[sp,#32]
stp xzr,xzr,[sp,#48]
ldp x19,x20,[x29,#16]
add sp,sp,#64
ldp x21,x22,[x29,#32]
ldp x23,x24,[x29,#48]
ldp x25,x26,[x29,#64]
ldp x27,x28,[x29,#80]
ldp x29,x30,[sp],#96
ret
.size ChaCha20_ctr32,.-ChaCha20_ctr32
___
{{{
my ($A0,$B0,$C0,$D0,$A1,$B1,$C1,$D1,$A2,$B2,$C2,$D2,$T0,$T1,$T2,$T3) =
map("v$_.4s",(0..7,16..23));
my (@K)=map("v$_.4s",(24..30));
my $ONE="v31.4s";
sub NEONROUND {
my $odd = pop;
my ($a,$b,$c,$d,$t)=@_;
(
"&add ('$a','$a','$b')",
"&eor ('$d','$d','$a')",
"&rev32_16 ('$d','$d')", # vrot ($d,16)
"&add ('$c','$c','$d')",
"&eor ('$t','$b','$c')",
"&ushr ('$b','$t',20)",
"&sli ('$b','$t',12)",
"&add ('$a','$a','$b')",
"&eor ('$t','$d','$a')",
"&ushr ('$d','$t',24)",
"&sli ('$d','$t',8)",
"&add ('$c','$c','$d')",
"&eor ('$t','$b','$c')",
"&ushr ('$b','$t',25)",
"&sli ('$b','$t',7)",
"&ext ('$c','$c','$c',8)",
"&ext ('$d','$d','$d',$odd?4:12)",
"&ext ('$b','$b','$b',$odd?12:4)"
);
}
$code.=<<___;
.type ChaCha20_neon,%function
.align 5
ChaCha20_neon:
stp x29,x30,[sp,#-96]!
add x29,sp,#0
adr @x[0],.Lsigma
stp x19,x20,[sp,#16]
stp x21,x22,[sp,#32]
stp x23,x24,[sp,#48]
stp x25,x26,[sp,#64]
stp x27,x28,[sp,#80]
cmp $len,#512
b.hs .L512_or_more_neon
sub sp,sp,#64
ldp @d[0],@d[1],[@x[0]] // load sigma
ld1 {@K[0]},[@x[0]],#16
ldp @d[2],@d[3],[$key] // load key
ldp @d[4],@d[5],[$key,#16]
ld1 {@K[1],@K[2]},[$key]
ldp @d[6],@d[7],[$ctr] // load counter
ld1 {@K[3]},[$ctr]
ld1 {$ONE},[@x[0]]
#ifdef __ARMEB__
rev64 @K[0],@K[0]
ror @d[2],@d[2],#32
ror @d[3],@d[3],#32
ror @d[4],@d[4],#32
ror @d[5],@d[5],#32
ror @d[6],@d[6],#32
ror @d[7],@d[7],#32
#endif
add @K[3],@K[3],$ONE // += 1
add @K[4],@K[3],$ONE
add @K[5],@K[4],$ONE
shl $ONE,$ONE,#2 // 1 -> 4
.Loop_outer_neon:
mov.32 @x[0],@d[0] // unpack key block
lsr @x[1],@d[0],#32
mov $A0,@K[0]
mov.32 @x[2],@d[1]
lsr @x[3],@d[1],#32
mov $A1,@K[0]
mov.32 @x[4],@d[2]
lsr @x[5],@d[2],#32
mov $A2,@K[0]
mov.32 @x[6],@d[3]
mov $B0,@K[1]
lsr @x[7],@d[3],#32
mov $B1,@K[1]
mov.32 @x[8],@d[4]
mov $B2,@K[1]
lsr @x[9],@d[4],#32
mov $D0,@K[3]
mov.32 @x[10],@d[5]
mov $D1,@K[4]
lsr @x[11],@d[5],#32
mov $D2,@K[5]
mov.32 @x[12],@d[6]
mov $C0,@K[2]
lsr @x[13],@d[6],#32
mov $C1,@K[2]
mov.32 @x[14],@d[7]
mov $C2,@K[2]
lsr @x[15],@d[7],#32
mov $ctr,#10
subs $len,$len,#256
.Loop_neon:
sub $ctr,$ctr,#1
___
my @thread0=&NEONROUND($A0,$B0,$C0,$D0,$T0,0);
my @thread1=&NEONROUND($A1,$B1,$C1,$D1,$T1,0);
my @thread2=&NEONROUND($A2,$B2,$C2,$D2,$T2,0);
my @thread3=&ROUND(0,4,8,12);
foreach (@thread0) {
eval; eval(shift(@thread3));
eval(shift(@thread1)); eval(shift(@thread3));
eval(shift(@thread2)); eval(shift(@thread3));
}
@thread0=&NEONROUND($A0,$B0,$C0,$D0,$T0,1);
@thread1=&NEONROUND($A1,$B1,$C1,$D1,$T1,1);
@thread2=&NEONROUND($A2,$B2,$C2,$D2,$T2,1);
@thread3=&ROUND(0,5,10,15);
foreach (@thread0) {
eval; eval(shift(@thread3));
eval(shift(@thread1)); eval(shift(@thread3));
eval(shift(@thread2)); eval(shift(@thread3));
}
$code.=<<___;
cbnz $ctr,.Loop_neon
add.32 @x[0],@x[0],@d[0] // accumulate key block
add $A0,$A0,@K[0]
add @x[1],@x[1],@d[0],lsr#32
add $A1,$A1,@K[0]
add.32 @x[2],@x[2],@d[1]
add $A2,$A2,@K[0]
add @x[3],@x[3],@d[1],lsr#32
add $C0,$C0,@K[2]
add.32 @x[4],@x[4],@d[2]
add $C1,$C1,@K[2]
add @x[5],@x[5],@d[2],lsr#32
add $C2,$C2,@K[2]
add.32 @x[6],@x[6],@d[3]
add $D0,$D0,@K[3]
add @x[7],@x[7],@d[3],lsr#32
add.32 @x[8],@x[8],@d[4]
add $D1,$D1,@K[4]
add @x[9],@x[9],@d[4],lsr#32
add.32 @x[10],@x[10],@d[5]
add $D2,$D2,@K[5]
add @x[11],@x[11],@d[5],lsr#32
add.32 @x[12],@x[12],@d[6]
add $B0,$B0,@K[1]
add @x[13],@x[13],@d[6],lsr#32
add.32 @x[14],@x[14],@d[7]
add $B1,$B1,@K[1]
add @x[15],@x[15],@d[7],lsr#32
add $B2,$B2,@K[1]
b.lo .Ltail_neon
add @x[0],@x[0],@x[1],lsl#32 // pack
add @x[2],@x[2],@x[3],lsl#32
ldp @x[1],@x[3],[$inp,#0] // load input
add @x[4],@x[4],@x[5],lsl#32
add @x[6],@x[6],@x[7],lsl#32
ldp @x[5],@x[7],[$inp,#16]
add @x[8],@x[8],@x[9],lsl#32
add @x[10],@x[10],@x[11],lsl#32
ldp @x[9],@x[11],[$inp,#32]
add @x[12],@x[12],@x[13],lsl#32
add @x[14],@x[14],@x[15],lsl#32
ldp @x[13],@x[15],[$inp,#48]
add $inp,$inp,#64
#ifdef __ARMEB__
rev @x[0],@x[0]
rev @x[2],@x[2]
rev @x[4],@x[4]
rev @x[6],@x[6]
rev @x[8],@x[8]
rev @x[10],@x[10]
rev @x[12],@x[12]
rev @x[14],@x[14]
#endif
ld1.8 {$T0-$T3},[$inp],#64
eor @x[0],@x[0],@x[1]
eor @x[2],@x[2],@x[3]
eor @x[4],@x[4],@x[5]
eor @x[6],@x[6],@x[7]
eor @x[8],@x[8],@x[9]
eor $A0,$A0,$T0
eor @x[10],@x[10],@x[11]
eor $B0,$B0,$T1
eor @x[12],@x[12],@x[13]
eor $C0,$C0,$T2
eor @x[14],@x[14],@x[15]
eor $D0,$D0,$T3
ld1.8 {$T0-$T3},[$inp],#64
stp @x[0],@x[2],[$out,#0] // store output
add @d[6],@d[6],#4 // increment counter
stp @x[4],@x[6],[$out,#16]
add @K[3],@K[3],$ONE // += 4
stp @x[8],@x[10],[$out,#32]
add @K[4],@K[4],$ONE
stp @x[12],@x[14],[$out,#48]
add @K[5],@K[5],$ONE
add $out,$out,#64
st1.8 {$A0-$D0},[$out],#64
ld1.8 {$A0-$D0},[$inp],#64
eor $A1,$A1,$T0
eor $B1,$B1,$T1
eor $C1,$C1,$T2
eor $D1,$D1,$T3
st1.8 {$A1-$D1},[$out],#64
eor $A2,$A2,$A0
eor $B2,$B2,$B0
eor $C2,$C2,$C0
eor $D2,$D2,$D0
st1.8 {$A2-$D2},[$out],#64
b.hi .Loop_outer_neon
ldp x19,x20,[x29,#16]
add sp,sp,#64
ldp x21,x22,[x29,#32]
ldp x23,x24,[x29,#48]
ldp x25,x26,[x29,#64]
ldp x27,x28,[x29,#80]
ldp x29,x30,[sp],#96
ret
.Ltail_neon:
add $len,$len,#256
cmp $len,#64
b.lo .Less_than_64
add @x[0],@x[0],@x[1],lsl#32 // pack
add @x[2],@x[2],@x[3],lsl#32
ldp @x[1],@x[3],[$inp,#0] // load input
add @x[4],@x[4],@x[5],lsl#32
add @x[6],@x[6],@x[7],lsl#32
ldp @x[5],@x[7],[$inp,#16]
add @x[8],@x[8],@x[9],lsl#32
add @x[10],@x[10],@x[11],lsl#32
ldp @x[9],@x[11],[$inp,#32]
add @x[12],@x[12],@x[13],lsl#32
add @x[14],@x[14],@x[15],lsl#32
ldp @x[13],@x[15],[$inp,#48]
add $inp,$inp,#64
#ifdef __ARMEB__
rev @x[0],@x[0]
rev @x[2],@x[2]
rev @x[4],@x[4]
rev @x[6],@x[6]
rev @x[8],@x[8]
rev @x[10],@x[10]
rev @x[12],@x[12]
rev @x[14],@x[14]
#endif
eor @x[0],@x[0],@x[1]
eor @x[2],@x[2],@x[3]
eor @x[4],@x[4],@x[5]
eor @x[6],@x[6],@x[7]
eor @x[8],@x[8],@x[9]
eor @x[10],@x[10],@x[11]
eor @x[12],@x[12],@x[13]
eor @x[14],@x[14],@x[15]
stp @x[0],@x[2],[$out,#0] // store output
add @d[6],@d[6],#4 // increment counter
stp @x[4],@x[6],[$out,#16]
stp @x[8],@x[10],[$out,#32]
stp @x[12],@x[14],[$out,#48]
add $out,$out,#64
b.eq .Ldone_neon
sub $len,$len,#64
cmp $len,#64
b.lo .Less_than_128
ld1.8 {$T0-$T3},[$inp],#64
eor $A0,$A0,$T0
eor $B0,$B0,$T1
eor $C0,$C0,$T2
eor $D0,$D0,$T3
st1.8 {$A0-$D0},[$out],#64
b.eq .Ldone_neon
sub $len,$len,#64
cmp $len,#64
b.lo .Less_than_192
ld1.8 {$T0-$T3},[$inp],#64
eor $A1,$A1,$T0
eor $B1,$B1,$T1
eor $C1,$C1,$T2
eor $D1,$D1,$T3
st1.8 {$A1-$D1},[$out],#64
b.eq .Ldone_neon
sub $len,$len,#64
st1.8 {$A2-$D2},[sp]
b .Last_neon
.Less_than_128:
st1.8 {$A0-$D0},[sp]
b .Last_neon
.Less_than_192:
st1.8 {$A1-$D1},[sp]
b .Last_neon
.align 4
.Last_neon:
sub $out,$out,#1
add $inp,$inp,$len
add $out,$out,$len
add $ctr,sp,$len
neg $len,$len
.Loop_tail_neon:
ldrb w10,[$inp,$len]
ldrb w11,[$ctr,$len]
add $len,$len,#1
eor w10,w10,w11
strb w10,[$out,$len]
cbnz $len,.Loop_tail_neon
stp xzr,xzr,[sp,#0]
stp xzr,xzr,[sp,#16]
stp xzr,xzr,[sp,#32]
stp xzr,xzr,[sp,#48]
.Ldone_neon:
ldp x19,x20,[x29,#16]
add sp,sp,#64
ldp x21,x22,[x29,#32]
ldp x23,x24,[x29,#48]
ldp x25,x26,[x29,#64]
ldp x27,x28,[x29,#80]
ldp x29,x30,[sp],#96
ret
.size ChaCha20_neon,.-ChaCha20_neon
___
{
my ($T0,$T1,$T2,$T3,$T4,$T5)=@K;
my ($A0,$B0,$C0,$D0,$A1,$B1,$C1,$D1,$A2,$B2,$C2,$D2,
$A3,$B3,$C3,$D3,$A4,$B4,$C4,$D4,$A5,$B5,$C5,$D5) = map("v$_.4s",(0..23));
$code.=<<___;
.type ChaCha20_512_neon,%function
.align 5
ChaCha20_512_neon:
stp x29,x30,[sp,#-96]!
add x29,sp,#0
adr @x[0],.Lsigma
stp x19,x20,[sp,#16]
stp x21,x22,[sp,#32]
stp x23,x24,[sp,#48]
stp x25,x26,[sp,#64]
stp x27,x28,[sp,#80]
.L512_or_more_neon:
sub sp,sp,#128+64
ldp @d[0],@d[1],[@x[0]] // load sigma
ld1 {@K[0]},[@x[0]],#16
ldp @d[2],@d[3],[$key] // load key
ldp @d[4],@d[5],[$key,#16]
ld1 {@K[1],@K[2]},[$key]
ldp @d[6],@d[7],[$ctr] // load counter
ld1 {@K[3]},[$ctr]
ld1 {$ONE},[@x[0]]
#ifdef __ARMEB__
rev64 @K[0],@K[0]
ror @d[2],@d[2],#32
ror @d[3],@d[3],#32
ror @d[4],@d[4],#32
ror @d[5],@d[5],#32
ror @d[6],@d[6],#32
ror @d[7],@d[7],#32
#endif
add @K[3],@K[3],$ONE // += 1
stp @K[0],@K[1],[sp,#0] // off-load key block, invariant part
add @K[3],@K[3],$ONE // not typo
str @K[2],[sp,#32]
add @K[4],@K[3],$ONE
add @K[5],@K[4],$ONE
add @K[6],@K[5],$ONE
shl $ONE,$ONE,#2 // 1 -> 4
stp d8,d9,[sp,#128+0] // meet ABI requirements
stp d10,d11,[sp,#128+16]
stp d12,d13,[sp,#128+32]
stp d14,d15,[sp,#128+48]
sub $len,$len,#512 // not typo
.Loop_outer_512_neon:
mov $A0,@K[0]
mov $A1,@K[0]
mov $A2,@K[0]
mov $A3,@K[0]
mov $A4,@K[0]
mov $A5,@K[0]
mov $B0,@K[1]
mov.32 @x[0],@d[0] // unpack key block
mov $B1,@K[1]
lsr @x[1],@d[0],#32
mov $B2,@K[1]
mov.32 @x[2],@d[1]
mov $B3,@K[1]
lsr @x[3],@d[1],#32
mov $B4,@K[1]
mov.32 @x[4],@d[2]
mov $B5,@K[1]
lsr @x[5],@d[2],#32
mov $D0,@K[3]
mov.32 @x[6],@d[3]
mov $D1,@K[4]
lsr @x[7],@d[3],#32
mov $D2,@K[5]
mov.32 @x[8],@d[4]
mov $D3,@K[6]
lsr @x[9],@d[4],#32
mov $C0,@K[2]
mov.32 @x[10],@d[5]
mov $C1,@K[2]
lsr @x[11],@d[5],#32
add $D4,$D0,$ONE // +4
mov.32 @x[12],@d[6]
add $D5,$D1,$ONE // +4
lsr @x[13],@d[6],#32
mov $C2,@K[2]
mov.32 @x[14],@d[7]
mov $C3,@K[2]
lsr @x[15],@d[7],#32
mov $C4,@K[2]
stp @K[3],@K[4],[sp,#48] // off-load key block, variable part
mov $C5,@K[2]
str @K[5],[sp,#80]
mov $ctr,#5
subs $len,$len,#512
.Loop_upper_neon:
sub $ctr,$ctr,#1
___
my @thread0=&NEONROUND($A0,$B0,$C0,$D0,$T0,0);
my @thread1=&NEONROUND($A1,$B1,$C1,$D1,$T1,0);
my @thread2=&NEONROUND($A2,$B2,$C2,$D2,$T2,0);
my @thread3=&NEONROUND($A3,$B3,$C3,$D3,$T3,0);
my @thread4=&NEONROUND($A4,$B4,$C4,$D4,$T4,0);
my @thread5=&NEONROUND($A5,$B5,$C5,$D5,$T5,0);
my @thread67=(&ROUND(0,4,8,12),&ROUND(0,5,10,15));
my $diff = ($#thread0+1)*6 - $#thread67 - 1;
my $i = 0;
foreach (@thread0) {
eval; eval(shift(@thread67));
eval(shift(@thread1)); eval(shift(@thread67));
eval(shift(@thread2)); eval(shift(@thread67));
eval(shift(@thread3)); eval(shift(@thread67));
eval(shift(@thread4)); eval(shift(@thread67));
eval(shift(@thread5)); eval(shift(@thread67));
}
@thread0=&NEONROUND($A0,$B0,$C0,$D0,$T0,1);
@thread1=&NEONROUND($A1,$B1,$C1,$D1,$T1,1);
@thread2=&NEONROUND($A2,$B2,$C2,$D2,$T2,1);
@thread3=&NEONROUND($A3,$B3,$C3,$D3,$T3,1);
@thread4=&NEONROUND($A4,$B4,$C4,$D4,$T4,1);
@thread5=&NEONROUND($A5,$B5,$C5,$D5,$T5,1);
@thread67=(&ROUND(0,4,8,12),&ROUND(0,5,10,15));
foreach (@thread0) {
eval; eval(shift(@thread67));
eval(shift(@thread1)); eval(shift(@thread67));
eval(shift(@thread2)); eval(shift(@thread67));
eval(shift(@thread3)); eval(shift(@thread67));
eval(shift(@thread4)); eval(shift(@thread67));
eval(shift(@thread5)); eval(shift(@thread67));
}
$code.=<<___;
cbnz $ctr,.Loop_upper_neon
add.32 @x[0],@x[0],@d[0] // accumulate key block
add @x[1],@x[1],@d[0],lsr#32
add.32 @x[2],@x[2],@d[1]
add @x[3],@x[3],@d[1],lsr#32
add.32 @x[4],@x[4],@d[2]
add @x[5],@x[5],@d[2],lsr#32
add.32 @x[6],@x[6],@d[3]
add @x[7],@x[7],@d[3],lsr#32
add.32 @x[8],@x[8],@d[4]
add @x[9],@x[9],@d[4],lsr#32
add.32 @x[10],@x[10],@d[5]
add @x[11],@x[11],@d[5],lsr#32
add.32 @x[12],@x[12],@d[6]
add @x[13],@x[13],@d[6],lsr#32
add.32 @x[14],@x[14],@d[7]
add @x[15],@x[15],@d[7],lsr#32
add @x[0],@x[0],@x[1],lsl#32 // pack
add @x[2],@x[2],@x[3],lsl#32
ldp @x[1],@x[3],[$inp,#0] // load input
add @x[4],@x[4],@x[5],lsl#32
add @x[6],@x[6],@x[7],lsl#32
ldp @x[5],@x[7],[$inp,#16]
add @x[8],@x[8],@x[9],lsl#32
add @x[10],@x[10],@x[11],lsl#32
ldp @x[9],@x[11],[$inp,#32]
add @x[12],@x[12],@x[13],lsl#32
add @x[14],@x[14],@x[15],lsl#32
ldp @x[13],@x[15],[$inp,#48]
add $inp,$inp,#64
#ifdef __ARMEB__
rev @x[0],@x[0]
rev @x[2],@x[2]
rev @x[4],@x[4]
rev @x[6],@x[6]
rev @x[8],@x[8]
rev @x[10],@x[10]
rev @x[12],@x[12]
rev @x[14],@x[14]
#endif
eor @x[0],@x[0],@x[1]
eor @x[2],@x[2],@x[3]
eor @x[4],@x[4],@x[5]
eor @x[6],@x[6],@x[7]
eor @x[8],@x[8],@x[9]
eor @x[10],@x[10],@x[11]
eor @x[12],@x[12],@x[13]
eor @x[14],@x[14],@x[15]
stp @x[0],@x[2],[$out,#0] // store output
add @d[6],@d[6],#1 // increment counter
mov.32 @x[0],@d[0] // unpack key block
lsr @x[1],@d[0],#32
stp @x[4],@x[6],[$out,#16]
mov.32 @x[2],@d[1]
lsr @x[3],@d[1],#32
stp @x[8],@x[10],[$out,#32]
mov.32 @x[4],@d[2]
lsr @x[5],@d[2],#32
stp @x[12],@x[14],[$out,#48]
add $out,$out,#64
mov.32 @x[6],@d[3]
lsr @x[7],@d[3],#32
mov.32 @x[8],@d[4]
lsr @x[9],@d[4],#32
mov.32 @x[10],@d[5]
lsr @x[11],@d[5],#32
mov.32 @x[12],@d[6]
lsr @x[13],@d[6],#32
mov.32 @x[14],@d[7]
lsr @x[15],@d[7],#32
mov $ctr,#5
.Loop_lower_neon:
sub $ctr,$ctr,#1
___
@thread0=&NEONROUND($A0,$B0,$C0,$D0,$T0,0);
@thread1=&NEONROUND($A1,$B1,$C1,$D1,$T1,0);
@thread2=&NEONROUND($A2,$B2,$C2,$D2,$T2,0);
@thread3=&NEONROUND($A3,$B3,$C3,$D3,$T3,0);
@thread4=&NEONROUND($A4,$B4,$C4,$D4,$T4,0);
@thread5=&NEONROUND($A5,$B5,$C5,$D5,$T5,0);
@thread67=(&ROUND(0,4,8,12),&ROUND(0,5,10,15));
foreach (@thread0) {
eval; eval(shift(@thread67));
eval(shift(@thread1)); eval(shift(@thread67));
eval(shift(@thread2)); eval(shift(@thread67));
eval(shift(@thread3)); eval(shift(@thread67));
eval(shift(@thread4)); eval(shift(@thread67));
eval(shift(@thread5)); eval(shift(@thread67));
}
@thread0=&NEONROUND($A0,$B0,$C0,$D0,$T0,1);
@thread1=&NEONROUND($A1,$B1,$C1,$D1,$T1,1);
@thread2=&NEONROUND($A2,$B2,$C2,$D2,$T2,1);
@thread3=&NEONROUND($A3,$B3,$C3,$D3,$T3,1);
@thread4=&NEONROUND($A4,$B4,$C4,$D4,$T4,1);
@thread5=&NEONROUND($A5,$B5,$C5,$D5,$T5,1);
@thread67=(&ROUND(0,4,8,12),&ROUND(0,5,10,15));
foreach (@thread0) {
eval; eval(shift(@thread67));
eval(shift(@thread1)); eval(shift(@thread67));
eval(shift(@thread2)); eval(shift(@thread67));
eval(shift(@thread3)); eval(shift(@thread67));
eval(shift(@thread4)); eval(shift(@thread67));
eval(shift(@thread5)); eval(shift(@thread67));
}
$code.=<<___;
cbnz $ctr,.Loop_lower_neon
add.32 @x[0],@x[0],@d[0] // accumulate key block
ldp @K[0],@K[1],[sp,#0]
add @x[1],@x[1],@d[0],lsr#32
ldp @K[2],@K[3],[sp,#32]
add.32 @x[2],@x[2],@d[1]
ldp @K[4],@K[5],[sp,#64]
add @x[3],@x[3],@d[1],lsr#32
add $A0,$A0,@K[0]
add.32 @x[4],@x[4],@d[2]
add $A1,$A1,@K[0]
add @x[5],@x[5],@d[2],lsr#32
add $A2,$A2,@K[0]
add.32 @x[6],@x[6],@d[3]
add $A3,$A3,@K[0]
add @x[7],@x[7],@d[3],lsr#32
add $A4,$A4,@K[0]
add.32 @x[8],@x[8],@d[4]
add $A5,$A5,@K[0]
add @x[9],@x[9],@d[4],lsr#32
add $C0,$C0,@K[2]
add.32 @x[10],@x[10],@d[5]
add $C1,$C1,@K[2]
add @x[11],@x[11],@d[5],lsr#32
add $C2,$C2,@K[2]
add.32 @x[12],@x[12],@d[6]
add $C3,$C3,@K[2]
add @x[13],@x[13],@d[6],lsr#32
add $C4,$C4,@K[2]
add.32 @x[14],@x[14],@d[7]
add $C5,$C5,@K[2]
add @x[15],@x[15],@d[7],lsr#32
add $D4,$D4,$ONE // +4
add @x[0],@x[0],@x[1],lsl#32 // pack
add $D5,$D5,$ONE // +4
add @x[2],@x[2],@x[3],lsl#32
add $D0,$D0,@K[3]
ldp @x[1],@x[3],[$inp,#0] // load input
add $D1,$D1,@K[4]
add @x[4],@x[4],@x[5],lsl#32
add $D2,$D2,@K[5]
add @x[6],@x[6],@x[7],lsl#32
add $D3,$D3,@K[6]
ldp @x[5],@x[7],[$inp,#16]
add $D4,$D4,@K[3]
add @x[8],@x[8],@x[9],lsl#32
add $D5,$D5,@K[4]
add @x[10],@x[10],@x[11],lsl#32
add $B0,$B0,@K[1]
ldp @x[9],@x[11],[$inp,#32]
add $B1,$B1,@K[1]
add @x[12],@x[12],@x[13],lsl#32
add $B2,$B2,@K[1]
add @x[14],@x[14],@x[15],lsl#32
add $B3,$B3,@K[1]
ldp @x[13],@x[15],[$inp,#48]
add $B4,$B4,@K[1]
add $inp,$inp,#64
add $B5,$B5,@K[1]
#ifdef __ARMEB__
rev @x[0],@x[0]
rev @x[2],@x[2]
rev @x[4],@x[4]
rev @x[6],@x[6]
rev @x[8],@x[8]
rev @x[10],@x[10]
rev @x[12],@x[12]
rev @x[14],@x[14]
#endif
ld1.8 {$T0-$T3},[$inp],#64
eor @x[0],@x[0],@x[1]
eor @x[2],@x[2],@x[3]
eor @x[4],@x[4],@x[5]
eor @x[6],@x[6],@x[7]
eor @x[8],@x[8],@x[9]
eor $A0,$A0,$T0
eor @x[10],@x[10],@x[11]
eor $B0,$B0,$T1
eor @x[12],@x[12],@x[13]
eor $C0,$C0,$T2
eor @x[14],@x[14],@x[15]
eor $D0,$D0,$T3
ld1.8 {$T0-$T3},[$inp],#64
stp @x[0],@x[2],[$out,#0] // store output
add @d[6],@d[6],#7 // increment counter
stp @x[4],@x[6],[$out,#16]
stp @x[8],@x[10],[$out,#32]
stp @x[12],@x[14],[$out,#48]
add $out,$out,#64
st1.8 {$A0-$D0},[$out],#64
ld1.8 {$A0-$D0},[$inp],#64
eor $A1,$A1,$T0
eor $B1,$B1,$T1
eor $C1,$C1,$T2
eor $D1,$D1,$T3
st1.8 {$A1-$D1},[$out],#64
ld1.8 {$A1-$D1},[$inp],#64
eor $A2,$A2,$A0
ldp @K[0],@K[1],[sp,#0]
eor $B2,$B2,$B0
ldp @K[2],@K[3],[sp,#32]
eor $C2,$C2,$C0
eor $D2,$D2,$D0
st1.8 {$A2-$D2},[$out],#64
ld1.8 {$A2-$D2},[$inp],#64
eor $A3,$A3,$A1
eor $B3,$B3,$B1
eor $C3,$C3,$C1
eor $D3,$D3,$D1
st1.8 {$A3-$D3},[$out],#64
ld1.8 {$A3-$D3},[$inp],#64
eor $A4,$A4,$A2
eor $B4,$B4,$B2
eor $C4,$C4,$C2
eor $D4,$D4,$D2
st1.8 {$A4-$D4},[$out],#64
shl $A0,$ONE,#1 // 4 -> 8
eor $A5,$A5,$A3
eor $B5,$B5,$B3
eor $C5,$C5,$C3
eor $D5,$D5,$D3
st1.8 {$A5-$D5},[$out],#64
add @K[3],@K[3],$A0 // += 8
add @K[4],@K[4],$A0
add @K[5],@K[5],$A0
add @K[6],@K[6],$A0
b.hs .Loop_outer_512_neon
adds $len,$len,#512
ushr $A0,$ONE,#2 // 4 -> 1
ldp d8,d9,[sp,#128+0] // meet ABI requirements
ldp d10,d11,[sp,#128+16]
ldp d12,d13,[sp,#128+32]
ldp d14,d15,[sp,#128+48]
stp @K[0],$ONE,[sp,#0] // wipe off-load area
stp @K[0],$ONE,[sp,#32]
stp @K[0],$ONE,[sp,#64]
b.eq .Ldone_512_neon
cmp $len,#192
sub @K[3],@K[3],$A0 // -= 1
sub @K[4],@K[4],$A0
sub @K[5],@K[5],$A0
add sp,sp,#128
b.hs .Loop_outer_neon
eor @K[1],@K[1],@K[1]
eor @K[2],@K[2],@K[2]
eor @K[3],@K[3],@K[3]
eor @K[4],@K[4],@K[4]
eor @K[5],@K[5],@K[5]
eor @K[6],@K[6],@K[6]
b .Loop_outer
.Ldone_512_neon:
ldp x19,x20,[x29,#16]
add sp,sp,#128+64
ldp x21,x22,[x29,#32]
ldp x23,x24,[x29,#48]
ldp x25,x26,[x29,#64]
ldp x27,x28,[x29,#80]
ldp x29,x30,[sp],#96
ret
.size ChaCha20_512_neon,.-ChaCha20_512_neon
___
}
}}}
foreach (split("\n",$code)) {
s/\`([^\`]*)\`/eval $1/geo;
(s/\b([a-z]+)\.32\b/$1/ and (s/x([0-9]+)/w$1/g or 1)) or
(m/\b(eor|ext|mov)\b/ and (s/\.4s/\.16b/g or 1)) or
(s/\b((?:ld|st)1)\.8\b/$1/ and (s/\.4s/\.16b/g or 1)) or
(m/\b(ld|st)[rp]\b/ and (s/v([0-9]+)\.4s/q$1/g or 1)) or
(s/\brev32\.16\b/rev32/ and (s/\.4s/\.8h/g or 1));
#s/\bq([0-9]+)#(lo|hi)/sprintf "d%d",2*$1+($2 eq "hi")/geo;
print $_,"\n";
}
close STDOUT; # flush
+926
View File
@@ -0,0 +1,926 @@
#! /usr/bin/env perl
# Copyright 2016 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/.
# ====================================================================
#
# ChaCha20 for C64x+.
#
# October 2015
#
# Performance is 3.54 cycles per processed byte, which is ~4.3 times
# faster than code generated by TI compiler. Compiler also disables
# interrupts for some reason, thus making interrupt response time
# dependent on input length. This module on the other hand is free
# from such limiation.
$output=pop;
open STDOUT,">$output";
($OUT,$INP,$LEN,$KEYB,$COUNTERA)=("A4","B4","A6","B6","A8");
($KEYA,$COUNTERB,$STEP)=("A7","B7","A3");
@X= ("A16","B16","A17","B17","A18","B18","A19","B19",
"A20","B20","A21","B21","A22","B22","A23","B23");
@Y= ("A24","B24","A25","B25","A26","B26","A27","B27",
"A28","B28","A29","B29","A30","B30","A31","B31");
@DAT=("A6", "A7", "B6", "B7", "A8", "A9", "B8", "B9",
"A10","A11","B10","B11","A12","A13","B12","B13");
# yes, overlaps with @DAT, used only in 2x interleave code path...
@K2x=("A6", "B6", "A7", "B7", "A8", "B8", "A9", "B9",
"A10","B10","A11","B11","A2", "B2", "A13","B13");
$code.=<<___;
.text
.if .ASSEMBLER_VERSION<7000000
.asg 0,__TI_EABI__
.endif
.if __TI_EABI__
.asg ChaCha20_ctr32,_ChaCha20_ctr32
.endif
.asg B3,RA
.asg A15,FP
.asg B15,SP
.global _ChaCha20_ctr32
.align 32
_ChaCha20_ctr32:
.asmfunc stack_usage(40+64)
MV $LEN,A0 ; reassign
[!A0] BNOP RA ; no data
|| [A0] STW FP,*SP--(40+64) ; save frame pointer and alloca(40+64)
|| [A0] MV SP,FP
[A0] STDW B13:B12,*SP[4+8] ; ABI says so
|| [A0] MV $KEYB,$KEYA
|| [A0] MV $COUNTERA,$COUNTERB
[A0] STDW B11:B10,*SP[3+8]
|| [A0] STDW A13:A12,*FP[-3]
[A0] STDW A11:A10,*FP[-4]
|| [A0] MVK 128,$STEP ; 2 * input block size
[A0] LDW *${KEYA}[0],@Y[4] ; load key
|| [A0] LDW *${KEYB}[1],@Y[5]
|| [A0] MVK 0x00007865,@Y[0] ; synthesize sigma
|| [A0] MVK 0x0000646e,@Y[1]
[A0] LDW *${KEYA}[2],@Y[6]
|| [A0] LDW *${KEYB}[3],@Y[7]
|| [A0] MVKH 0x61700000,@Y[0]
|| [A0] MVKH 0x33200000,@Y[1]
LDW *${KEYA}[4],@Y[8]
|| LDW *${KEYB}[5],@Y[9]
|| MVK 0x00002d32,@Y[2]
|| MVK 0x00006574,@Y[3]
LDW *${KEYA}[6],@Y[10]
|| LDW *${KEYB}[7],@Y[11]
|| MVKH 0x79620000,@Y[2]
|| MVKH 0x6b200000,@Y[3]
LDW *${COUNTERA}[0],@Y[12] ; load counter||nonce
|| LDW *${COUNTERB}[1],@Y[13]
|| CMPLTU A0,$STEP,A1 ; is length < 2*blocks?
LDW *${COUNTERA}[2],@Y[14]
|| LDW *${COUNTERB}[3],@Y[15]
|| [A1] BNOP top1x?
[A1] MVK 64,$STEP ; input block size
|| MVK 10,B0 ; inner loop counter
DMV @Y[2],@Y[0],@X[2]:@X[0] ; copy block
|| DMV @Y[3],@Y[1],@X[3]:@X[1]
||[!A1] STDW @Y[2]:@Y[0],*FP[-12] ; offload key material to stack
||[!A1] STDW @Y[3]:@Y[1],*SP[2]
DMV @Y[6],@Y[4],@X[6]:@X[4]
|| DMV @Y[7],@Y[5],@X[7]:@X[5]
||[!A1] STDW @Y[6]:@Y[4],*FP[-10]
||[!A1] STDW @Y[7]:@Y[5],*SP[4]
DMV @Y[10],@Y[8],@X[10]:@X[8]
|| DMV @Y[11],@Y[9],@X[11]:@X[9]
||[!A1] STDW @Y[10]:@Y[8],*FP[-8]
||[!A1] STDW @Y[11]:@Y[9],*SP[6]
DMV @Y[14],@Y[12],@X[14]:@X[12]
|| DMV @Y[15],@Y[13],@X[15]:@X[13]
||[!A1] MV @Y[12],@K2x[12] ; counter
||[!A1] MV @Y[13],@K2x[13]
||[!A1] STW @Y[14],*FP[-6*2]
||[!A1] STW @Y[15],*SP[8*2]
___
{ ################################################################
# 2x interleave gives 50% performance improvement
#
my ($a0,$a1,$a2,$a3) = (0..3);
my ($b0,$b1,$b2,$b3) = (4..7);
my ($c0,$c1,$c2,$c3) = (8..11);
my ($d0,$d1,$d2,$d3) = (12..15);
$code.=<<___;
outer2x?:
ADD @X[$b1],@X[$a1],@X[$a1]
|| ADD @X[$b2],@X[$a2],@X[$a2]
|| ADD @X[$b0],@X[$a0],@X[$a0]
|| ADD @X[$b3],@X[$a3],@X[$a3]
|| DMV @Y[2],@Y[0],@K2x[2]:@K2x[0]
|| DMV @Y[3],@Y[1],@K2x[3]:@K2x[1]
XOR @X[$a1],@X[$d1],@X[$d1]
|| XOR @X[$a2],@X[$d2],@X[$d2]
|| XOR @X[$a0],@X[$d0],@X[$d0]
|| XOR @X[$a3],@X[$d3],@X[$d3]
|| DMV @Y[6],@Y[4],@K2x[6]:@K2x[4]
|| DMV @Y[7],@Y[5],@K2x[7]:@K2x[5]
SWAP2 @X[$d1],@X[$d1] ; rotate by 16
|| SWAP2 @X[$d2],@X[$d2]
|| SWAP2 @X[$d0],@X[$d0]
|| SWAP2 @X[$d3],@X[$d3]
ADD @X[$d1],@X[$c1],@X[$c1]
|| ADD @X[$d2],@X[$c2],@X[$c2]
|| ADD @X[$d0],@X[$c0],@X[$c0]
|| ADD @X[$d3],@X[$c3],@X[$c3]
|| DMV @Y[10],@Y[8],@K2x[10]:@K2x[8]
|| DMV @Y[11],@Y[9],@K2x[11]:@K2x[9]
XOR @X[$c1],@X[$b1],@X[$b1]
|| XOR @X[$c2],@X[$b2],@X[$b2]
|| XOR @X[$c0],@X[$b0],@X[$b0]
|| XOR @X[$c3],@X[$b3],@X[$b3]
|| ADD 1,@Y[12],@Y[12] ; adjust counter for 2nd block
ROTL @X[$b1],12,@X[$b1]
|| ROTL @X[$b2],12,@X[$b2]
|| MV @Y[14],@K2x[14]
|| MV @Y[15],@K2x[15]
top2x?:
ROTL @X[$b0],12,@X[$b0]
|| ROTL @X[$b3],12,@X[$b3]
|| ADD @Y[$b1],@Y[$a1],@Y[$a1]
|| ADD @Y[$b2],@Y[$a2],@Y[$a2]
ADD @Y[$b0],@Y[$a0],@Y[$a0]
|| ADD @Y[$b3],@Y[$a3],@Y[$a3]
|| ADD @X[$b1],@X[$a1],@X[$a1]
|| ADD @X[$b2],@X[$a2],@X[$a2]
|| XOR @Y[$a1],@Y[$d1],@Y[$d1]
|| XOR @Y[$a2],@Y[$d2],@Y[$d2]
XOR @Y[$a0],@Y[$d0],@Y[$d0]
|| XOR @Y[$a3],@Y[$d3],@Y[$d3]
|| ADD @X[$b0],@X[$a0],@X[$a0]
|| ADD @X[$b3],@X[$a3],@X[$a3]
|| XOR @X[$a1],@X[$d1],@X[$d1]
|| XOR @X[$a2],@X[$d2],@X[$d2]
XOR @X[$a0],@X[$d0],@X[$d0]
|| XOR @X[$a3],@X[$d3],@X[$d3]
|| ROTL @X[$d1],8,@X[$d1]
|| ROTL @X[$d2],8,@X[$d2]
|| SWAP2 @Y[$d1],@Y[$d1] ; rotate by 16
|| SWAP2 @Y[$d2],@Y[$d2]
|| SWAP2 @Y[$d0],@Y[$d0]
|| SWAP2 @Y[$d3],@Y[$d3]
ROTL @X[$d0],8,@X[$d0]
|| ROTL @X[$d3],8,@X[$d3]
|| ADD @Y[$d1],@Y[$c1],@Y[$c1]
|| ADD @Y[$d2],@Y[$c2],@Y[$c2]
|| ADD @Y[$d0],@Y[$c0],@Y[$c0]
|| ADD @Y[$d3],@Y[$c3],@Y[$c3]
|| BNOP middle2x1? ; protect from interrupt
ADD @X[$d1],@X[$c1],@X[$c1]
|| ADD @X[$d2],@X[$c2],@X[$c2]
|| XOR @Y[$c1],@Y[$b1],@Y[$b1]
|| XOR @Y[$c2],@Y[$b2],@Y[$b2]
|| XOR @Y[$c0],@Y[$b0],@Y[$b0]
|| XOR @Y[$c3],@Y[$b3],@Y[$b3]
ADD @X[$d0],@X[$c0],@X[$c0]
|| ADD @X[$d3],@X[$c3],@X[$c3]
|| XOR @X[$c1],@X[$b1],@X[$b1]
|| XOR @X[$c2],@X[$b2],@X[$b2]
|| ROTL @X[$d1],0,@X[$d2] ; moved to avoid cross-path stall
|| ROTL @X[$d2],0,@X[$d3]
XOR @X[$c0],@X[$b0],@X[$b0]
|| XOR @X[$c3],@X[$b3],@X[$b3]
|| MV @X[$d0],@X[$d1]
|| MV @X[$d3],@X[$d0]
|| ROTL @Y[$b1],12,@Y[$b1]
|| ROTL @Y[$b2],12,@Y[$b2]
ROTL @X[$b1],7,@X[$b0] ; avoided cross-path stall
|| ROTL @X[$b2],7,@X[$b1]
ROTL @X[$b0],7,@X[$b3]
|| ROTL @X[$b3],7,@X[$b2]
middle2x1?:
ROTL @Y[$b0],12,@Y[$b0]
|| ROTL @Y[$b3],12,@Y[$b3]
|| ADD @X[$b0],@X[$a0],@X[$a0]
|| ADD @X[$b1],@X[$a1],@X[$a1]
ADD @X[$b2],@X[$a2],@X[$a2]
|| ADD @X[$b3],@X[$a3],@X[$a3]
|| ADD @Y[$b1],@Y[$a1],@Y[$a1]
|| ADD @Y[$b2],@Y[$a2],@Y[$a2]
|| XOR @X[$a0],@X[$d0],@X[$d0]
|| XOR @X[$a1],@X[$d1],@X[$d1]
XOR @X[$a2],@X[$d2],@X[$d2]
|| XOR @X[$a3],@X[$d3],@X[$d3]
|| ADD @Y[$b0],@Y[$a0],@Y[$a0]
|| ADD @Y[$b3],@Y[$a3],@Y[$a3]
|| XOR @Y[$a1],@Y[$d1],@Y[$d1]
|| XOR @Y[$a2],@Y[$d2],@Y[$d2]
XOR @Y[$a0],@Y[$d0],@Y[$d0]
|| XOR @Y[$a3],@Y[$d3],@Y[$d3]
|| ROTL @Y[$d1],8,@Y[$d1]
|| ROTL @Y[$d2],8,@Y[$d2]
|| SWAP2 @X[$d0],@X[$d0] ; rotate by 16
|| SWAP2 @X[$d1],@X[$d1]
|| SWAP2 @X[$d2],@X[$d2]
|| SWAP2 @X[$d3],@X[$d3]
ROTL @Y[$d0],8,@Y[$d0]
|| ROTL @Y[$d3],8,@Y[$d3]
|| ADD @X[$d0],@X[$c2],@X[$c2]
|| ADD @X[$d1],@X[$c3],@X[$c3]
|| ADD @X[$d2],@X[$c0],@X[$c0]
|| ADD @X[$d3],@X[$c1],@X[$c1]
|| BNOP middle2x2? ; protect from interrupt
ADD @Y[$d1],@Y[$c1],@Y[$c1]
|| ADD @Y[$d2],@Y[$c2],@Y[$c2]
|| XOR @X[$c2],@X[$b0],@X[$b0]
|| XOR @X[$c3],@X[$b1],@X[$b1]
|| XOR @X[$c0],@X[$b2],@X[$b2]
|| XOR @X[$c1],@X[$b3],@X[$b3]
ADD @Y[$d0],@Y[$c0],@Y[$c0]
|| ADD @Y[$d3],@Y[$c3],@Y[$c3]
|| XOR @Y[$c1],@Y[$b1],@Y[$b1]
|| XOR @Y[$c2],@Y[$b2],@Y[$b2]
|| ROTL @Y[$d1],0,@Y[$d2] ; moved to avoid cross-path stall
|| ROTL @Y[$d2],0,@Y[$d3]
XOR @Y[$c0],@Y[$b0],@Y[$b0]
|| XOR @Y[$c3],@Y[$b3],@Y[$b3]
|| MV @Y[$d0],@Y[$d1]
|| MV @Y[$d3],@Y[$d0]
|| ROTL @X[$b0],12,@X[$b0]
|| ROTL @X[$b1],12,@X[$b1]
ROTL @Y[$b1],7,@Y[$b0] ; avoided cross-path stall
|| ROTL @Y[$b2],7,@Y[$b1]
ROTL @Y[$b0],7,@Y[$b3]
|| ROTL @Y[$b3],7,@Y[$b2]
middle2x2?:
ROTL @X[$b2],12,@X[$b2]
|| ROTL @X[$b3],12,@X[$b3]
|| ADD @Y[$b0],@Y[$a0],@Y[$a0]
|| ADD @Y[$b1],@Y[$a1],@Y[$a1]
ADD @Y[$b2],@Y[$a2],@Y[$a2]
|| ADD @Y[$b3],@Y[$a3],@Y[$a3]
|| ADD @X[$b0],@X[$a0],@X[$a0]
|| ADD @X[$b1],@X[$a1],@X[$a1]
|| XOR @Y[$a0],@Y[$d0],@Y[$d0]
|| XOR @Y[$a1],@Y[$d1],@Y[$d1]
XOR @Y[$a2],@Y[$d2],@Y[$d2]
|| XOR @Y[$a3],@Y[$d3],@Y[$d3]
|| ADD @X[$b2],@X[$a2],@X[$a2]
|| ADD @X[$b3],@X[$a3],@X[$a3]
|| XOR @X[$a0],@X[$d0],@X[$d0]
|| XOR @X[$a1],@X[$d1],@X[$d1]
XOR @X[$a2],@X[$d2],@X[$d2]
|| XOR @X[$a3],@X[$d3],@X[$d3]
|| ROTL @X[$d0],8,@X[$d0]
|| ROTL @X[$d1],8,@X[$d1]
|| SWAP2 @Y[$d0],@Y[$d0] ; rotate by 16
|| SWAP2 @Y[$d1],@Y[$d1]
|| SWAP2 @Y[$d2],@Y[$d2]
|| SWAP2 @Y[$d3],@Y[$d3]
ROTL @X[$d2],8,@X[$d2]
|| ROTL @X[$d3],8,@X[$d3]
|| ADD @Y[$d0],@Y[$c2],@Y[$c2]
|| ADD @Y[$d1],@Y[$c3],@Y[$c3]
|| ADD @Y[$d2],@Y[$c0],@Y[$c0]
|| ADD @Y[$d3],@Y[$c1],@Y[$c1]
|| BNOP bottom2x1? ; protect from interrupt
ADD @X[$d0],@X[$c2],@X[$c2]
|| ADD @X[$d1],@X[$c3],@X[$c3]
|| XOR @Y[$c2],@Y[$b0],@Y[$b0]
|| XOR @Y[$c3],@Y[$b1],@Y[$b1]
|| XOR @Y[$c0],@Y[$b2],@Y[$b2]
|| XOR @Y[$c1],@Y[$b3],@Y[$b3]
ADD @X[$d2],@X[$c0],@X[$c0]
|| ADD @X[$d3],@X[$c1],@X[$c1]
|| XOR @X[$c2],@X[$b0],@X[$b0]
|| XOR @X[$c3],@X[$b1],@X[$b1]
|| ROTL @X[$d0],0,@X[$d3] ; moved to avoid cross-path stall
|| ROTL @X[$d1],0,@X[$d0]
XOR @X[$c0],@X[$b2],@X[$b2]
|| XOR @X[$c1],@X[$b3],@X[$b3]
|| MV @X[$d2],@X[$d1]
|| MV @X[$d3],@X[$d2]
|| ROTL @Y[$b0],12,@Y[$b0]
|| ROTL @Y[$b1],12,@Y[$b1]
ROTL @X[$b0],7,@X[$b1] ; avoided cross-path stall
|| ROTL @X[$b1],7,@X[$b2]
ROTL @X[$b2],7,@X[$b3]
|| ROTL @X[$b3],7,@X[$b0]
|| [B0] SUB B0,1,B0 ; decrement inner loop counter
bottom2x1?:
ROTL @Y[$b2],12,@Y[$b2]
|| ROTL @Y[$b3],12,@Y[$b3]
|| [B0] ADD @X[$b1],@X[$a1],@X[$a1] ; modulo-scheduled
|| [B0] ADD @X[$b2],@X[$a2],@X[$a2]
[B0] ADD @X[$b0],@X[$a0],@X[$a0]
|| [B0] ADD @X[$b3],@X[$a3],@X[$a3]
|| ADD @Y[$b0],@Y[$a0],@Y[$a0]
|| ADD @Y[$b1],@Y[$a1],@Y[$a1]
|| [B0] XOR @X[$a1],@X[$d1],@X[$d1]
|| [B0] XOR @X[$a2],@X[$d2],@X[$d2]
[B0] XOR @X[$a0],@X[$d0],@X[$d0]
|| [B0] XOR @X[$a3],@X[$d3],@X[$d3]
|| ADD @Y[$b2],@Y[$a2],@Y[$a2]
|| ADD @Y[$b3],@Y[$a3],@Y[$a3]
|| XOR @Y[$a0],@Y[$d0],@Y[$d0]
|| XOR @Y[$a1],@Y[$d1],@Y[$d1]
XOR @Y[$a2],@Y[$d2],@Y[$d2]
|| XOR @Y[$a3],@Y[$d3],@Y[$d3]
|| ROTL @Y[$d0],8,@Y[$d0]
|| ROTL @Y[$d1],8,@Y[$d1]
|| [B0] SWAP2 @X[$d1],@X[$d1] ; rotate by 16
|| [B0] SWAP2 @X[$d2],@X[$d2]
|| [B0] SWAP2 @X[$d0],@X[$d0]
|| [B0] SWAP2 @X[$d3],@X[$d3]
ROTL @Y[$d2],8,@Y[$d2]
|| ROTL @Y[$d3],8,@Y[$d3]
|| [B0] ADD @X[$d1],@X[$c1],@X[$c1]
|| [B0] ADD @X[$d2],@X[$c2],@X[$c2]
|| [B0] ADD @X[$d0],@X[$c0],@X[$c0]
|| [B0] ADD @X[$d3],@X[$c3],@X[$c3]
|| [B0] BNOP top2x? ; even protects from interrupt
ADD @Y[$d0],@Y[$c2],@Y[$c2]
|| ADD @Y[$d1],@Y[$c3],@Y[$c3]
|| [B0] XOR @X[$c1],@X[$b1],@X[$b1]
|| [B0] XOR @X[$c2],@X[$b2],@X[$b2]
|| [B0] XOR @X[$c0],@X[$b0],@X[$b0]
|| [B0] XOR @X[$c3],@X[$b3],@X[$b3]
ADD @Y[$d2],@Y[$c0],@Y[$c0]
|| ADD @Y[$d3],@Y[$c1],@Y[$c1]
|| XOR @Y[$c2],@Y[$b0],@Y[$b0]
|| XOR @Y[$c3],@Y[$b1],@Y[$b1]
|| ROTL @Y[$d0],0,@Y[$d3] ; moved to avoid cross-path stall
|| ROTL @Y[$d1],0,@Y[$d0]
XOR @Y[$c0],@Y[$b2],@Y[$b2]
|| XOR @Y[$c1],@Y[$b3],@Y[$b3]
|| MV @Y[$d2],@Y[$d1]
|| MV @Y[$d3],@Y[$d2]
|| [B0] ROTL @X[$b1],12,@X[$b1]
|| [B0] ROTL @X[$b2],12,@X[$b2]
ROTL @Y[$b0],7,@Y[$b1] ; avoided cross-path stall
|| ROTL @Y[$b1],7,@Y[$b2]
ROTL @Y[$b2],7,@Y[$b3]
|| ROTL @Y[$b3],7,@Y[$b0]
bottom2x2?:
___
}
$code.=<<___;
ADD @K2x[0],@X[0],@X[0] ; accumulate key material
|| ADD @K2x[1],@X[1],@X[1]
|| ADD @K2x[2],@X[2],@X[2]
|| ADD @K2x[3],@X[3],@X[3]
ADD @K2x[0],@Y[0],@Y[0]
|| ADD @K2x[1],@Y[1],@Y[1]
|| ADD @K2x[2],@Y[2],@Y[2]
|| ADD @K2x[3],@Y[3],@Y[3]
|| LDNDW *${INP}++[8],@DAT[1]:@DAT[0]
ADD @K2x[4],@X[4],@X[4]
|| ADD @K2x[5],@X[5],@X[5]
|| ADD @K2x[6],@X[6],@X[6]
|| ADD @K2x[7],@X[7],@X[7]
|| LDNDW *${INP}[-7],@DAT[3]:@DAT[2]
ADD @K2x[4],@Y[4],@Y[4]
|| ADD @K2x[5],@Y[5],@Y[5]
|| ADD @K2x[6],@Y[6],@Y[6]
|| ADD @K2x[7],@Y[7],@Y[7]
|| LDNDW *${INP}[-6],@DAT[5]:@DAT[4]
ADD @K2x[8],@X[8],@X[8]
|| ADD @K2x[9],@X[9],@X[9]
|| ADD @K2x[10],@X[10],@X[10]
|| ADD @K2x[11],@X[11],@X[11]
|| LDNDW *${INP}[-5],@DAT[7]:@DAT[6]
ADD @K2x[8],@Y[8],@Y[8]
|| ADD @K2x[9],@Y[9],@Y[9]
|| ADD @K2x[10],@Y[10],@Y[10]
|| ADD @K2x[11],@Y[11],@Y[11]
|| LDNDW *${INP}[-4],@DAT[9]:@DAT[8]
ADD @K2x[12],@X[12],@X[12]
|| ADD @K2x[13],@X[13],@X[13]
|| ADD @K2x[14],@X[14],@X[14]
|| ADD @K2x[15],@X[15],@X[15]
|| LDNDW *${INP}[-3],@DAT[11]:@DAT[10]
ADD @K2x[12],@Y[12],@Y[12]
|| ADD @K2x[13],@Y[13],@Y[13]
|| ADD @K2x[14],@Y[14],@Y[14]
|| ADD @K2x[15],@Y[15],@Y[15]
|| LDNDW *${INP}[-2],@DAT[13]:@DAT[12]
ADD 1,@Y[12],@Y[12] ; adjust counter for 2nd block
|| ADD 2,@K2x[12],@K2x[12] ; increment counter
|| LDNDW *${INP}[-1],@DAT[15]:@DAT[14]
.if .BIG_ENDIAN
SWAP2 @X[0],@X[0]
|| SWAP2 @X[1],@X[1]
|| SWAP2 @X[2],@X[2]
|| SWAP2 @X[3],@X[3]
SWAP2 @X[4],@X[4]
|| SWAP2 @X[5],@X[5]
|| SWAP2 @X[6],@X[6]
|| SWAP2 @X[7],@X[7]
SWAP2 @X[8],@X[8]
|| SWAP2 @X[9],@X[9]
|| SWAP4 @X[0],@X[1]
|| SWAP4 @X[1],@X[0]
SWAP2 @X[10],@X[10]
|| SWAP2 @X[11],@X[11]
|| SWAP4 @X[2],@X[3]
|| SWAP4 @X[3],@X[2]
SWAP2 @X[12],@X[12]
|| SWAP2 @X[13],@X[13]
|| SWAP4 @X[4],@X[5]
|| SWAP4 @X[5],@X[4]
SWAP2 @X[14],@X[14]
|| SWAP2 @X[15],@X[15]
|| SWAP4 @X[6],@X[7]
|| SWAP4 @X[7],@X[6]
SWAP4 @X[8],@X[9]
|| SWAP4 @X[9],@X[8]
|| SWAP2 @Y[0],@Y[0]
|| SWAP2 @Y[1],@Y[1]
SWAP4 @X[10],@X[11]
|| SWAP4 @X[11],@X[10]
|| SWAP2 @Y[2],@Y[2]
|| SWAP2 @Y[3],@Y[3]
SWAP4 @X[12],@X[13]
|| SWAP4 @X[13],@X[12]
|| SWAP2 @Y[4],@Y[4]
|| SWAP2 @Y[5],@Y[5]
SWAP4 @X[14],@X[15]
|| SWAP4 @X[15],@X[14]
|| SWAP2 @Y[6],@Y[6]
|| SWAP2 @Y[7],@Y[7]
SWAP2 @Y[8],@Y[8]
|| SWAP2 @Y[9],@Y[9]
|| SWAP4 @Y[0],@Y[1]
|| SWAP4 @Y[1],@Y[0]
SWAP2 @Y[10],@Y[10]
|| SWAP2 @Y[11],@Y[11]
|| SWAP4 @Y[2],@Y[3]
|| SWAP4 @Y[3],@Y[2]
SWAP2 @Y[12],@Y[12]
|| SWAP2 @Y[13],@Y[13]
|| SWAP4 @Y[4],@Y[5]
|| SWAP4 @Y[5],@Y[4]
SWAP2 @Y[14],@Y[14]
|| SWAP2 @Y[15],@Y[15]
|| SWAP4 @Y[6],@Y[7]
|| SWAP4 @Y[7],@Y[6]
SWAP4 @Y[8],@Y[9]
|| SWAP4 @Y[9],@Y[8]
SWAP4 @Y[10],@Y[11]
|| SWAP4 @Y[11],@Y[10]
SWAP4 @Y[12],@Y[13]
|| SWAP4 @Y[13],@Y[12]
SWAP4 @Y[14],@Y[15]
|| SWAP4 @Y[15],@Y[14]
.endif
XOR @DAT[0],@X[0],@X[0] ; xor 1st block
|| XOR @DAT[3],@X[3],@X[3]
|| XOR @DAT[2],@X[2],@X[1]
|| XOR @DAT[1],@X[1],@X[2]
|| LDNDW *${INP}++[8],@DAT[1]:@DAT[0]
XOR @DAT[4],@X[4],@X[4]
|| XOR @DAT[7],@X[7],@X[7]
|| LDNDW *${INP}[-7],@DAT[3]:@DAT[2]
XOR @DAT[6],@X[6],@X[5]
|| XOR @DAT[5],@X[5],@X[6]
|| LDNDW *${INP}[-6],@DAT[5]:@DAT[4]
XOR @DAT[8],@X[8],@X[8]
|| XOR @DAT[11],@X[11],@X[11]
|| LDNDW *${INP}[-5],@DAT[7]:@DAT[6]
XOR @DAT[10],@X[10],@X[9]
|| XOR @DAT[9],@X[9],@X[10]
|| LDNDW *${INP}[-4],@DAT[9]:@DAT[8]
XOR @DAT[12],@X[12],@X[12]
|| XOR @DAT[15],@X[15],@X[15]
|| LDNDW *${INP}[-3],@DAT[11]:@DAT[10]
XOR @DAT[14],@X[14],@X[13]
|| XOR @DAT[13],@X[13],@X[14]
|| LDNDW *${INP}[-2],@DAT[13]:@DAT[12]
[A0] SUB A0,$STEP,A0 ; SUB A0,128,A0
|| LDNDW *${INP}[-1],@DAT[15]:@DAT[14]
XOR @Y[0],@DAT[0],@DAT[0] ; xor 2nd block
|| XOR @Y[1],@DAT[1],@DAT[1]
|| STNDW @X[2]:@X[0],*${OUT}++[8]
XOR @Y[2],@DAT[2],@DAT[2]
|| XOR @Y[3],@DAT[3],@DAT[3]
|| STNDW @X[3]:@X[1],*${OUT}[-7]
XOR @Y[4],@DAT[4],@DAT[4]
|| [A0] LDDW *FP[-12],@X[2]:@X[0] ; re-load key material from stack
|| [A0] LDDW *SP[2], @X[3]:@X[1]
XOR @Y[5],@DAT[5],@DAT[5]
|| STNDW @X[6]:@X[4],*${OUT}[-6]
XOR @Y[6],@DAT[6],@DAT[6]
|| XOR @Y[7],@DAT[7],@DAT[7]
|| STNDW @X[7]:@X[5],*${OUT}[-5]
XOR @Y[8],@DAT[8],@DAT[8]
|| [A0] LDDW *FP[-10],@X[6]:@X[4]
|| [A0] LDDW *SP[4], @X[7]:@X[5]
XOR @Y[9],@DAT[9],@DAT[9]
|| STNDW @X[10]:@X[8],*${OUT}[-4]
XOR @Y[10],@DAT[10],@DAT[10]
|| XOR @Y[11],@DAT[11],@DAT[11]
|| STNDW @X[11]:@X[9],*${OUT}[-3]
XOR @Y[12],@DAT[12],@DAT[12]
|| [A0] LDDW *FP[-8], @X[10]:@X[8]
|| [A0] LDDW *SP[6], @X[11]:@X[9]
XOR @Y[13],@DAT[13],@DAT[13]
|| STNDW @X[14]:@X[12],*${OUT}[-2]
XOR @Y[14],@DAT[14],@DAT[14]
|| XOR @Y[15],@DAT[15],@DAT[15]
|| STNDW @X[15]:@X[13],*${OUT}[-1]
[A0] MV @K2x[12],@X[12]
|| [A0] MV @K2x[13],@X[13]
|| [A0] LDW *FP[-6*2], @X[14]
|| [A0] LDW *SP[8*2], @X[15]
[A0] DMV @X[2],@X[0],@Y[2]:@Y[0] ; duplicate key material
|| STNDW @DAT[1]:@DAT[0],*${OUT}++[8]
[A0] DMV @X[3],@X[1],@Y[3]:@Y[1]
|| STNDW @DAT[3]:@DAT[2],*${OUT}[-7]
[A0] DMV @X[6],@X[4],@Y[6]:@Y[4]
|| STNDW @DAT[5]:@DAT[4],*${OUT}[-6]
|| CMPLTU A0,$STEP,A1 ; is remaining length < 2*blocks?
||[!A0] BNOP epilogue?
[A0] DMV @X[7],@X[5],@Y[7]:@Y[5]
|| STNDW @DAT[7]:@DAT[6],*${OUT}[-5]
||[!A1] BNOP outer2x?
[A0] DMV @X[10],@X[8],@Y[10]:@Y[8]
|| STNDW @DAT[9]:@DAT[8],*${OUT}[-4]
[A0] DMV @X[11],@X[9],@Y[11]:@Y[9]
|| STNDW @DAT[11]:@DAT[10],*${OUT}[-3]
[A0] DMV @X[14],@X[12],@Y[14]:@Y[12]
|| STNDW @DAT[13]:@DAT[12],*${OUT}[-2]
[A0] DMV @X[15],@X[13],@Y[15]:@Y[13]
|| STNDW @DAT[15]:@DAT[14],*${OUT}[-1]
;;===== branch to epilogue? is taken here
[A1] MVK 64,$STEP
|| [A0] MVK 10,B0 ; inner loop counter
;;===== branch to outer2x? is taken here
___
{
my ($a0,$a1,$a2,$a3) = (0..3);
my ($b0,$b1,$b2,$b3) = (4..7);
my ($c0,$c1,$c2,$c3) = (8..11);
my ($d0,$d1,$d2,$d3) = (12..15);
$code.=<<___;
top1x?:
ADD @X[$b1],@X[$a1],@X[$a1]
|| ADD @X[$b2],@X[$a2],@X[$a2]
ADD @X[$b0],@X[$a0],@X[$a0]
|| ADD @X[$b3],@X[$a3],@X[$a3]
|| XOR @X[$a1],@X[$d1],@X[$d1]
|| XOR @X[$a2],@X[$d2],@X[$d2]
XOR @X[$a0],@X[$d0],@X[$d0]
|| XOR @X[$a3],@X[$d3],@X[$d3]
|| SWAP2 @X[$d1],@X[$d1] ; rotate by 16
|| SWAP2 @X[$d2],@X[$d2]
SWAP2 @X[$d0],@X[$d0]
|| SWAP2 @X[$d3],@X[$d3]
|| ADD @X[$d1],@X[$c1],@X[$c1]
|| ADD @X[$d2],@X[$c2],@X[$c2]
ADD @X[$d0],@X[$c0],@X[$c0]
|| ADD @X[$d3],@X[$c3],@X[$c3]
|| XOR @X[$c1],@X[$b1],@X[$b1]
|| XOR @X[$c2],@X[$b2],@X[$b2]
XOR @X[$c0],@X[$b0],@X[$b0]
|| XOR @X[$c3],@X[$b3],@X[$b3]
|| ROTL @X[$b1],12,@X[$b1]
|| ROTL @X[$b2],12,@X[$b2]
ROTL @X[$b0],12,@X[$b0]
|| ROTL @X[$b3],12,@X[$b3]
ADD @X[$b1],@X[$a1],@X[$a1]
|| ADD @X[$b2],@X[$a2],@X[$a2]
ADD @X[$b0],@X[$a0],@X[$a0]
|| ADD @X[$b3],@X[$a3],@X[$a3]
|| XOR @X[$a1],@X[$d1],@X[$d1]
|| XOR @X[$a2],@X[$d2],@X[$d2]
XOR @X[$a0],@X[$d0],@X[$d0]
|| XOR @X[$a3],@X[$d3],@X[$d3]
|| ROTL @X[$d1],8,@X[$d1]
|| ROTL @X[$d2],8,@X[$d2]
ROTL @X[$d0],8,@X[$d0]
|| ROTL @X[$d3],8,@X[$d3]
|| BNOP middle1x? ; protect from interrupt
ADD @X[$d1],@X[$c1],@X[$c1]
|| ADD @X[$d2],@X[$c2],@X[$c2]
ADD @X[$d0],@X[$c0],@X[$c0]
|| ADD @X[$d3],@X[$c3],@X[$c3]
|| XOR @X[$c1],@X[$b1],@X[$b1]
|| XOR @X[$c2],@X[$b2],@X[$b2]
|| ROTL @X[$d1],0,@X[$d2] ; moved to avoid cross-path stall
|| ROTL @X[$d2],0,@X[$d3]
XOR @X[$c0],@X[$b0],@X[$b0]
|| XOR @X[$c3],@X[$b3],@X[$b3]
|| ROTL @X[$d0],0,@X[$d1]
|| ROTL @X[$d3],0,@X[$d0]
ROTL @X[$b1],7,@X[$b0] ; avoided cross-path stall
|| ROTL @X[$b2],7,@X[$b1]
ROTL @X[$b0],7,@X[$b3]
|| ROTL @X[$b3],7,@X[$b2]
middle1x?:
ADD @X[$b0],@X[$a0],@X[$a0]
|| ADD @X[$b1],@X[$a1],@X[$a1]
ADD @X[$b2],@X[$a2],@X[$a2]
|| ADD @X[$b3],@X[$a3],@X[$a3]
|| XOR @X[$a0],@X[$d0],@X[$d0]
|| XOR @X[$a1],@X[$d1],@X[$d1]
XOR @X[$a2],@X[$d2],@X[$d2]
|| XOR @X[$a3],@X[$d3],@X[$d3]
|| SWAP2 @X[$d0],@X[$d0] ; rotate by 16
|| SWAP2 @X[$d1],@X[$d1]
SWAP2 @X[$d2],@X[$d2]
|| SWAP2 @X[$d3],@X[$d3]
|| ADD @X[$d0],@X[$c2],@X[$c2]
|| ADD @X[$d1],@X[$c3],@X[$c3]
ADD @X[$d2],@X[$c0],@X[$c0]
|| ADD @X[$d3],@X[$c1],@X[$c1]
|| XOR @X[$c2],@X[$b0],@X[$b0]
|| XOR @X[$c3],@X[$b1],@X[$b1]
XOR @X[$c0],@X[$b2],@X[$b2]
|| XOR @X[$c1],@X[$b3],@X[$b3]
|| ROTL @X[$b0],12,@X[$b0]
|| ROTL @X[$b1],12,@X[$b1]
ROTL @X[$b2],12,@X[$b2]
|| ROTL @X[$b3],12,@X[$b3]
ADD @X[$b0],@X[$a0],@X[$a0]
|| ADD @X[$b1],@X[$a1],@X[$a1]
|| [B0] SUB B0,1,B0 ; decrement inner loop counter
ADD @X[$b2],@X[$a2],@X[$a2]
|| ADD @X[$b3],@X[$a3],@X[$a3]
|| XOR @X[$a0],@X[$d0],@X[$d0]
|| XOR @X[$a1],@X[$d1],@X[$d1]
XOR @X[$a2],@X[$d2],@X[$d2]
|| XOR @X[$a3],@X[$d3],@X[$d3]
|| ROTL @X[$d0],8,@X[$d0]
|| ROTL @X[$d1],8,@X[$d1]
ROTL @X[$d2],8,@X[$d2]
|| ROTL @X[$d3],8,@X[$d3]
|| [B0] BNOP top1x? ; even protects from interrupt
ADD @X[$d0],@X[$c2],@X[$c2]
|| ADD @X[$d1],@X[$c3],@X[$c3]
ADD @X[$d2],@X[$c0],@X[$c0]
|| ADD @X[$d3],@X[$c1],@X[$c1]
|| XOR @X[$c2],@X[$b0],@X[$b0]
|| XOR @X[$c3],@X[$b1],@X[$b1]
|| ROTL @X[$d0],0,@X[$d3] ; moved to avoid cross-path stall
|| ROTL @X[$d1],0,@X[$d0]
XOR @X[$c0],@X[$b2],@X[$b2]
|| XOR @X[$c1],@X[$b3],@X[$b3]
|| ROTL @X[$d2],0,@X[$d1]
|| ROTL @X[$d3],0,@X[$d2]
ROTL @X[$b0],7,@X[$b1] ; avoided cross-path stall
|| ROTL @X[$b1],7,@X[$b2]
ROTL @X[$b2],7,@X[$b3]
|| ROTL @X[$b3],7,@X[$b0]
||[!B0] CMPLTU A0,$STEP,A1 ; less than 64 bytes left?
bottom1x?:
___
}
$code.=<<___;
ADD @Y[0],@X[0],@X[0] ; accumulate key material
|| ADD @Y[1],@X[1],@X[1]
|| ADD @Y[2],@X[2],@X[2]
|| ADD @Y[3],@X[3],@X[3]
||[!A1] LDNDW *${INP}++[8],@DAT[1]:@DAT[0]
|| [A1] BNOP tail?
ADD @Y[4],@X[4],@X[4]
|| ADD @Y[5],@X[5],@X[5]
|| ADD @Y[6],@X[6],@X[6]
|| ADD @Y[7],@X[7],@X[7]
||[!A1] LDNDW *${INP}[-7],@DAT[3]:@DAT[2]
ADD @Y[8],@X[8],@X[8]
|| ADD @Y[9],@X[9],@X[9]
|| ADD @Y[10],@X[10],@X[10]
|| ADD @Y[11],@X[11],@X[11]
||[!A1] LDNDW *${INP}[-6],@DAT[5]:@DAT[4]
ADD @Y[12],@X[12],@X[12]
|| ADD @Y[13],@X[13],@X[13]
|| ADD @Y[14],@X[14],@X[14]
|| ADD @Y[15],@X[15],@X[15]
||[!A1] LDNDW *${INP}[-5],@DAT[7]:@DAT[6]
[!A1] LDNDW *${INP}[-4],@DAT[9]:@DAT[8]
[!A1] LDNDW *${INP}[-3],@DAT[11]:@DAT[10]
LDNDW *${INP}[-2],@DAT[13]:@DAT[12]
LDNDW *${INP}[-1],@DAT[15]:@DAT[14]
.if .BIG_ENDIAN
SWAP2 @X[0],@X[0]
|| SWAP2 @X[1],@X[1]
|| SWAP2 @X[2],@X[2]
|| SWAP2 @X[3],@X[3]
SWAP2 @X[4],@X[4]
|| SWAP2 @X[5],@X[5]
|| SWAP2 @X[6],@X[6]
|| SWAP2 @X[7],@X[7]
SWAP2 @X[8],@X[8]
|| SWAP2 @X[9],@X[9]
|| SWAP4 @X[0],@X[1]
|| SWAP4 @X[1],@X[0]
SWAP2 @X[10],@X[10]
|| SWAP2 @X[11],@X[11]
|| SWAP4 @X[2],@X[3]
|| SWAP4 @X[3],@X[2]
SWAP2 @X[12],@X[12]
|| SWAP2 @X[13],@X[13]
|| SWAP4 @X[4],@X[5]
|| SWAP4 @X[5],@X[4]
SWAP2 @X[14],@X[14]
|| SWAP2 @X[15],@X[15]
|| SWAP4 @X[6],@X[7]
|| SWAP4 @X[7],@X[6]
SWAP4 @X[8],@X[9]
|| SWAP4 @X[9],@X[8]
SWAP4 @X[10],@X[11]
|| SWAP4 @X[11],@X[10]
SWAP4 @X[12],@X[13]
|| SWAP4 @X[13],@X[12]
SWAP4 @X[14],@X[15]
|| SWAP4 @X[15],@X[14]
.else
NOP 1
.endif
XOR @X[0],@DAT[0],@DAT[0] ; xor with input
|| XOR @X[1],@DAT[1],@DAT[1]
|| XOR @X[2],@DAT[2],@DAT[2]
|| XOR @X[3],@DAT[3],@DAT[3]
|| [A0] SUB A0,$STEP,A0 ; SUB A0,64,A0
XOR @X[4],@DAT[4],@DAT[4]
|| XOR @X[5],@DAT[5],@DAT[5]
|| XOR @X[6],@DAT[6],@DAT[6]
|| XOR @X[7],@DAT[7],@DAT[7]
|| STNDW @DAT[1]:@DAT[0],*${OUT}++[8]
XOR @X[8],@DAT[8],@DAT[8]
|| XOR @X[9],@DAT[9],@DAT[9]
|| XOR @X[10],@DAT[10],@DAT[10]
|| XOR @X[11],@DAT[11],@DAT[11]
|| STNDW @DAT[3]:@DAT[2],*${OUT}[-7]
XOR @X[12],@DAT[12],@DAT[12]
|| XOR @X[13],@DAT[13],@DAT[13]
|| XOR @X[14],@DAT[14],@DAT[14]
|| XOR @X[15],@DAT[15],@DAT[15]
|| STNDW @DAT[5]:@DAT[4],*${OUT}[-6]
|| [A0] BNOP top1x?
[A0] DMV @Y[2],@Y[0],@X[2]:@X[0] ; duplicate key material
|| [A0] DMV @Y[3],@Y[1],@X[3]:@X[1]
|| STNDW @DAT[7]:@DAT[6],*${OUT}[-5]
[A0] DMV @Y[6],@Y[4],@X[6]:@X[4]
|| [A0] DMV @Y[7],@Y[5],@X[7]:@X[5]
|| STNDW @DAT[9]:@DAT[8],*${OUT}[-4]
[A0] DMV @Y[10],@Y[8],@X[10]:@X[8]
|| [A0] DMV @Y[11],@Y[9],@X[11]:@X[9]
|| [A0] ADD 1,@Y[12],@Y[12] ; increment counter
|| STNDW @DAT[11]:@DAT[10],*${OUT}[-3]
[A0] DMV @Y[14],@Y[12],@X[14]:@X[12]
|| [A0] DMV @Y[15],@Y[13],@X[15]:@X[13]
|| STNDW @DAT[13]:@DAT[12],*${OUT}[-2]
[A0] MVK 10,B0 ; inner loop counter
|| STNDW @DAT[15]:@DAT[14],*${OUT}[-1]
;;===== branch to top1x? is taken here
epilogue?:
LDDW *FP[-4],A11:A10 ; ABI says so
LDDW *FP[-3],A13:A12
|| LDDW *SP[3+8],B11:B10
LDDW *SP[4+8],B13:B12
|| BNOP RA
LDW *++SP(40+64),FP ; restore frame pointer
NOP 4
tail?:
LDBU *${INP}++[1],B24 ; load byte by byte
|| SUB A0,1,A0
|| SUB A0,1,B1
[!B1] BNOP epilogue? ; interrupts are disabled for whole time
|| [A0] LDBU *${INP}++[1],B24
|| [A0] SUB A0,1,A0
|| SUB B1,1,B1
[!B1] BNOP epilogue?
|| [A0] LDBU *${INP}++[1],B24
|| [A0] SUB A0,1,A0
|| SUB B1,1,B1
[!B1] BNOP epilogue?
|| ROTL @X[0],0,A24
|| [A0] LDBU *${INP}++[1],B24
|| [A0] SUB A0,1,A0
|| SUB B1,1,B1
[!B1] BNOP epilogue?
|| ROTL @X[0],24,A24
|| [A0] LDBU *${INP}++[1],A24
|| [A0] SUB A0,1,A0
|| SUB B1,1,B1
[!B1] BNOP epilogue?
|| ROTL @X[0],16,A24
|| [A0] LDBU *${INP}++[1],A24
|| [A0] SUB A0,1,A0
|| SUB B1,1,B1
|| XOR A24,B24,B25
STB B25,*${OUT}++[1] ; store byte by byte
||[!B1] BNOP epilogue?
|| ROTL @X[0],8,A24
|| [A0] LDBU *${INP}++[1],A24
|| [A0] SUB A0,1,A0
|| SUB B1,1,B1
|| XOR A24,B24,B25
STB B25,*${OUT}++[1]
___
sub TAIL_STEP {
my $Xi= shift;
my $T = ($Xi=~/^B/?"B24":"A24"); # match @X[i] to avoid cross path
my $D = $T; $D=~tr/AB/BA/;
my $O = $D; $O=~s/24/25/;
$code.=<<___;
||[!B1] BNOP epilogue?
|| ROTL $Xi,0,$T
|| [A0] LDBU *${INP}++[1],$D
|| [A0] SUB A0,1,A0
|| SUB B1,1,B1
|| XOR A24,B24,$O
STB $O,*${OUT}++[1]
||[!B1] BNOP epilogue?
|| ROTL $Xi,24,$T
|| [A0] LDBU *${INP}++[1],$T
|| [A0] SUB A0,1,A0
|| SUB B1,1,B1
|| XOR A24,B24,$O
STB $O,*${OUT}++[1]
||[!B1] BNOP epilogue?
|| ROTL $Xi,16,$T
|| [A0] LDBU *${INP}++[1],$T
|| [A0] SUB A0,1,A0
|| SUB B1,1,B1
|| XOR A24,B24,$O
STB $O,*${OUT}++[1]
||[!B1] BNOP epilogue?
|| ROTL $Xi,8,$T
|| [A0] LDBU *${INP}++[1],$T
|| [A0] SUB A0,1,A0
|| SUB B1,1,B1
|| XOR A24,B24,$O
STB $O,*${OUT}++[1]
___
}
foreach (1..14) { TAIL_STEP(@X[$_]); }
$code.=<<___;
||[!B1] BNOP epilogue?
|| ROTL @X[15],0,B24
|| XOR A24,B24,A25
STB A25,*${OUT}++[1]
|| ROTL @X[15],24,B24
|| XOR A24,B24,A25
STB A25,*${OUT}++[1]
|| ROTL @X[15],16,B24
|| XOR A24,B24,A25
STB A25,*${OUT}++[1]
|| XOR A24,B24,A25
STB A25,*${OUT}++[1]
|| XOR A24,B24,B25
STB B25,*${OUT}++[1]
.endasmfunc
.sect .const
.cstring "ChaCha20 for C64x+, CRYPTOGAMS by <appro\@openssl.org>"
.align 4
___
print $code;
close STDOUT;
+953
View File
@@ -0,0 +1,953 @@
#! /usr/bin/env perl
# Copyright 2016 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/.
# ====================================================================
#
# October 2015
#
# ChaCha20 for PowerPC/AltiVec.
#
# Performance in cycles per byte out of large buffer.
#
# IALU/gcc-4.x 3xAltiVec+1xIALU
#
# Freescale e300 13.6/+115% -
# PPC74x0/G4e 6.81/+310% 4.66
# PPC970/G5 9.29/+160% 4.60
# POWER7 8.62/+61% 4.27
# POWER8 8.70/+51% 3.96
$flavour = shift;
if ($flavour =~ /64/) {
$SIZE_T =8;
$LRSAVE =2*$SIZE_T;
$STU ="stdu";
$POP ="ld";
$PUSH ="std";
$UCMP ="cmpld";
} elsif ($flavour =~ /32/) {
$SIZE_T =4;
$LRSAVE =$SIZE_T;
$STU ="stwu";
$POP ="lwz";
$PUSH ="stw";
$UCMP ="cmplw";
} else { die "nonsense $flavour"; }
$LITTLE_ENDIAN = ($flavour=~/le$/) ? 1 : 0;
$0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1;
( $xlate="${dir}ppc-xlate.pl" and -f $xlate ) or
( $xlate="${dir}../../perlasm/ppc-xlate.pl" and -f $xlate) or
die "can't locate ppc-xlate.pl";
open STDOUT,"| $^X $xlate $flavour ".shift || die "can't call $xlate: $!";
$LOCALS=6*$SIZE_T;
$FRAME=$LOCALS+64+18*$SIZE_T; # 64 is for local variables
sub AUTOLOAD() # thunk [simplified] x86-style perlasm
{ my $opcode = $AUTOLOAD; $opcode =~ s/.*:://; $opcode =~ s/_/\./;
$code .= "\t$opcode\t".join(',',@_)."\n";
}
my $sp = "r1";
my ($out,$inp,$len,$key,$ctr) = map("r$_",(3..7));
my @x=map("r$_",(16..31));
my @d=map("r$_",(11,12,14,15));
my @t=map("r$_",(7..10));
sub ROUND {
my ($a0,$b0,$c0,$d0)=@_;
my ($a1,$b1,$c1,$d1)=map(($_&~3)+(($_+1)&3),($a0,$b0,$c0,$d0));
my ($a2,$b2,$c2,$d2)=map(($_&~3)+(($_+1)&3),($a1,$b1,$c1,$d1));
my ($a3,$b3,$c3,$d3)=map(($_&~3)+(($_+1)&3),($a2,$b2,$c2,$d2));
(
"&add (@x[$a0],@x[$a0],@x[$b0])",
"&add (@x[$a1],@x[$a1],@x[$b1])",
"&add (@x[$a2],@x[$a2],@x[$b2])",
"&add (@x[$a3],@x[$a3],@x[$b3])",
"&xor (@x[$d0],@x[$d0],@x[$a0])",
"&xor (@x[$d1],@x[$d1],@x[$a1])",
"&xor (@x[$d2],@x[$d2],@x[$a2])",
"&xor (@x[$d3],@x[$d3],@x[$a3])",
"&rotlwi (@x[$d0],@x[$d0],16)",
"&rotlwi (@x[$d1],@x[$d1],16)",
"&rotlwi (@x[$d2],@x[$d2],16)",
"&rotlwi (@x[$d3],@x[$d3],16)",
"&add (@x[$c0],@x[$c0],@x[$d0])",
"&add (@x[$c1],@x[$c1],@x[$d1])",
"&add (@x[$c2],@x[$c2],@x[$d2])",
"&add (@x[$c3],@x[$c3],@x[$d3])",
"&xor (@x[$b0],@x[$b0],@x[$c0])",
"&xor (@x[$b1],@x[$b1],@x[$c1])",
"&xor (@x[$b2],@x[$b2],@x[$c2])",
"&xor (@x[$b3],@x[$b3],@x[$c3])",
"&rotlwi (@x[$b0],@x[$b0],12)",
"&rotlwi (@x[$b1],@x[$b1],12)",
"&rotlwi (@x[$b2],@x[$b2],12)",
"&rotlwi (@x[$b3],@x[$b3],12)",
"&add (@x[$a0],@x[$a0],@x[$b0])",
"&add (@x[$a1],@x[$a1],@x[$b1])",
"&add (@x[$a2],@x[$a2],@x[$b2])",
"&add (@x[$a3],@x[$a3],@x[$b3])",
"&xor (@x[$d0],@x[$d0],@x[$a0])",
"&xor (@x[$d1],@x[$d1],@x[$a1])",
"&xor (@x[$d2],@x[$d2],@x[$a2])",
"&xor (@x[$d3],@x[$d3],@x[$a3])",
"&rotlwi (@x[$d0],@x[$d0],8)",
"&rotlwi (@x[$d1],@x[$d1],8)",
"&rotlwi (@x[$d2],@x[$d2],8)",
"&rotlwi (@x[$d3],@x[$d3],8)",
"&add (@x[$c0],@x[$c0],@x[$d0])",
"&add (@x[$c1],@x[$c1],@x[$d1])",
"&add (@x[$c2],@x[$c2],@x[$d2])",
"&add (@x[$c3],@x[$c3],@x[$d3])",
"&xor (@x[$b0],@x[$b0],@x[$c0])",
"&xor (@x[$b1],@x[$b1],@x[$c1])",
"&xor (@x[$b2],@x[$b2],@x[$c2])",
"&xor (@x[$b3],@x[$b3],@x[$c3])",
"&rotlwi (@x[$b0],@x[$b0],7)",
"&rotlwi (@x[$b1],@x[$b1],7)",
"&rotlwi (@x[$b2],@x[$b2],7)",
"&rotlwi (@x[$b3],@x[$b3],7)"
);
}
$code.=<<___;
.machine "any"
.text
.globl .ChaCha20_ctr32_int
.align 5
.ChaCha20_ctr32_int:
__ChaCha20_ctr32_int:
${UCMP}i $len,0
beqlr-
$STU $sp,-$FRAME($sp)
mflr r0
$PUSH r14,`$FRAME-$SIZE_T*18`($sp)
$PUSH r15,`$FRAME-$SIZE_T*17`($sp)
$PUSH r16,`$FRAME-$SIZE_T*16`($sp)
$PUSH r17,`$FRAME-$SIZE_T*15`($sp)
$PUSH r18,`$FRAME-$SIZE_T*14`($sp)
$PUSH r19,`$FRAME-$SIZE_T*13`($sp)
$PUSH r20,`$FRAME-$SIZE_T*12`($sp)
$PUSH r21,`$FRAME-$SIZE_T*11`($sp)
$PUSH r22,`$FRAME-$SIZE_T*10`($sp)
$PUSH r23,`$FRAME-$SIZE_T*9`($sp)
$PUSH r24,`$FRAME-$SIZE_T*8`($sp)
$PUSH r25,`$FRAME-$SIZE_T*7`($sp)
$PUSH r26,`$FRAME-$SIZE_T*6`($sp)
$PUSH r27,`$FRAME-$SIZE_T*5`($sp)
$PUSH r28,`$FRAME-$SIZE_T*4`($sp)
$PUSH r29,`$FRAME-$SIZE_T*3`($sp)
$PUSH r30,`$FRAME-$SIZE_T*2`($sp)
$PUSH r31,`$FRAME-$SIZE_T*1`($sp)
$PUSH r0,`$FRAME+$LRSAVE`($sp)
lwz @d[0],0($ctr) # load counter
lwz @d[1],4($ctr)
lwz @d[2],8($ctr)
lwz @d[3],12($ctr)
bl __ChaCha20_1x
$POP r0,`$FRAME+$LRSAVE`($sp)
$POP r14,`$FRAME-$SIZE_T*18`($sp)
$POP r15,`$FRAME-$SIZE_T*17`($sp)
$POP r16,`$FRAME-$SIZE_T*16`($sp)
$POP r17,`$FRAME-$SIZE_T*15`($sp)
$POP r18,`$FRAME-$SIZE_T*14`($sp)
$POP r19,`$FRAME-$SIZE_T*13`($sp)
$POP r20,`$FRAME-$SIZE_T*12`($sp)
$POP r21,`$FRAME-$SIZE_T*11`($sp)
$POP r22,`$FRAME-$SIZE_T*10`($sp)
$POP r23,`$FRAME-$SIZE_T*9`($sp)
$POP r24,`$FRAME-$SIZE_T*8`($sp)
$POP r25,`$FRAME-$SIZE_T*7`($sp)
$POP r26,`$FRAME-$SIZE_T*6`($sp)
$POP r27,`$FRAME-$SIZE_T*5`($sp)
$POP r28,`$FRAME-$SIZE_T*4`($sp)
$POP r29,`$FRAME-$SIZE_T*3`($sp)
$POP r30,`$FRAME-$SIZE_T*2`($sp)
$POP r31,`$FRAME-$SIZE_T*1`($sp)
mtlr r0
addi $sp,$sp,$FRAME
blr
.long 0
.byte 0,12,4,1,0x80,18,5,0
.long 0
.size .ChaCha20_ctr32_int,.-.ChaCha20_ctr32_int
.align 5
__ChaCha20_1x:
Loop_outer:
lis @x[0],0x6170 # synthesize sigma
lis @x[1],0x3320
lis @x[2],0x7962
lis @x[3],0x6b20
ori @x[0],@x[0],0x7865
ori @x[1],@x[1],0x646e
ori @x[2],@x[2],0x2d32
ori @x[3],@x[3],0x6574
li r0,10 # inner loop counter
lwz @x[4],0($key) # load key
lwz @x[5],4($key)
lwz @x[6],8($key)
lwz @x[7],12($key)
lwz @x[8],16($key)
mr @x[12],@d[0] # copy counter
lwz @x[9],20($key)
mr @x[13],@d[1]
lwz @x[10],24($key)
mr @x[14],@d[2]
lwz @x[11],28($key)
mr @x[15],@d[3]
mr @t[0],@x[4]
mr @t[1],@x[5]
mr @t[2],@x[6]
mr @t[3],@x[7]
mtctr r0
Loop:
___
foreach (&ROUND(0, 4, 8,12)) { eval; }
foreach (&ROUND(0, 5,10,15)) { eval; }
$code.=<<___;
bdnz Loop
subic $len,$len,64 # $len-=64
addi @x[0],@x[0],0x7865 # accumulate key block
addi @x[1],@x[1],0x646e
addi @x[2],@x[2],0x2d32
addi @x[3],@x[3],0x6574
addis @x[0],@x[0],0x6170
addis @x[1],@x[1],0x3320
addis @x[2],@x[2],0x7962
addis @x[3],@x[3],0x6b20
subfe. r0,r0,r0 # borrow?-1:0
add @x[4],@x[4],@t[0]
lwz @t[0],16($key)
add @x[5],@x[5],@t[1]
lwz @t[1],20($key)
add @x[6],@x[6],@t[2]
lwz @t[2],24($key)
add @x[7],@x[7],@t[3]
lwz @t[3],28($key)
add @x[8],@x[8],@t[0]
add @x[9],@x[9],@t[1]
add @x[10],@x[10],@t[2]
add @x[11],@x[11],@t[3]
add @x[12],@x[12],@d[0]
add @x[13],@x[13],@d[1]
add @x[14],@x[14],@d[2]
add @x[15],@x[15],@d[3]
addi @d[0],@d[0],1 # increment counter
___
if (!$LITTLE_ENDIAN) { for($i=0;$i<16;$i++) { # flip byte order
$code.=<<___;
mr @t[$i&3],@x[$i]
rotlwi @x[$i],@x[$i],8
rlwimi @x[$i],@t[$i&3],24,0,7
rlwimi @x[$i],@t[$i&3],24,16,23
___
} }
$code.=<<___;
bne Ltail # $len-=64 borrowed
lwz @t[0],0($inp) # load input, aligned or not
lwz @t[1],4($inp)
${UCMP}i $len,0 # done already?
lwz @t[2],8($inp)
lwz @t[3],12($inp)
xor @x[0],@x[0],@t[0] # xor with input
lwz @t[0],16($inp)
xor @x[1],@x[1],@t[1]
lwz @t[1],20($inp)
xor @x[2],@x[2],@t[2]
lwz @t[2],24($inp)
xor @x[3],@x[3],@t[3]
lwz @t[3],28($inp)
xor @x[4],@x[4],@t[0]
lwz @t[0],32($inp)
xor @x[5],@x[5],@t[1]
lwz @t[1],36($inp)
xor @x[6],@x[6],@t[2]
lwz @t[2],40($inp)
xor @x[7],@x[7],@t[3]
lwz @t[3],44($inp)
xor @x[8],@x[8],@t[0]
lwz @t[0],48($inp)
xor @x[9],@x[9],@t[1]
lwz @t[1],52($inp)
xor @x[10],@x[10],@t[2]
lwz @t[2],56($inp)
xor @x[11],@x[11],@t[3]
lwz @t[3],60($inp)
xor @x[12],@x[12],@t[0]
stw @x[0],0($out) # store output, aligned or not
xor @x[13],@x[13],@t[1]
stw @x[1],4($out)
xor @x[14],@x[14],@t[2]
stw @x[2],8($out)
xor @x[15],@x[15],@t[3]
stw @x[3],12($out)
stw @x[4],16($out)
stw @x[5],20($out)
stw @x[6],24($out)
stw @x[7],28($out)
stw @x[8],32($out)
stw @x[9],36($out)
stw @x[10],40($out)
stw @x[11],44($out)
stw @x[12],48($out)
stw @x[13],52($out)
stw @x[14],56($out)
addi $inp,$inp,64
stw @x[15],60($out)
addi $out,$out,64
bne Loop_outer
blr
.align 4
Ltail:
addi $len,$len,64 # restore tail length
subi $inp,$inp,1 # prepare for *++ptr
subi $out,$out,1
addi @t[0],$sp,$LOCALS-1
mtctr $len
stw @x[0],`$LOCALS+0`($sp) # save whole block to stack
stw @x[1],`$LOCALS+4`($sp)
stw @x[2],`$LOCALS+8`($sp)
stw @x[3],`$LOCALS+12`($sp)
stw @x[4],`$LOCALS+16`($sp)
stw @x[5],`$LOCALS+20`($sp)
stw @x[6],`$LOCALS+24`($sp)
stw @x[7],`$LOCALS+28`($sp)
stw @x[8],`$LOCALS+32`($sp)
stw @x[9],`$LOCALS+36`($sp)
stw @x[10],`$LOCALS+40`($sp)
stw @x[11],`$LOCALS+44`($sp)
stw @x[12],`$LOCALS+48`($sp)
stw @x[13],`$LOCALS+52`($sp)
stw @x[14],`$LOCALS+56`($sp)
stw @x[15],`$LOCALS+60`($sp)
Loop_tail: # byte-by-byte loop
lbzu @d[0],1($inp)
lbzu @x[0],1(@t[0])
xor @d[1],@d[0],@x[0]
stbu @d[1],1($out)
bdnz Loop_tail
stw $sp,`$LOCALS+0`($sp) # wipe block on stack
stw $sp,`$LOCALS+4`($sp)
stw $sp,`$LOCALS+8`($sp)
stw $sp,`$LOCALS+12`($sp)
stw $sp,`$LOCALS+16`($sp)
stw $sp,`$LOCALS+20`($sp)
stw $sp,`$LOCALS+24`($sp)
stw $sp,`$LOCALS+28`($sp)
stw $sp,`$LOCALS+32`($sp)
stw $sp,`$LOCALS+36`($sp)
stw $sp,`$LOCALS+40`($sp)
stw $sp,`$LOCALS+44`($sp)
stw $sp,`$LOCALS+48`($sp)
stw $sp,`$LOCALS+52`($sp)
stw $sp,`$LOCALS+56`($sp)
stw $sp,`$LOCALS+60`($sp)
blr
.long 0
.byte 0,12,0x14,0,0,0,0,0
___
{{{
my ($A0,$B0,$C0,$D0,$A1,$B1,$C1,$D1,$A2,$B2,$C2,$D2,$T0,$T1,$T2) =
map("v$_",(0..14));
my (@K)=map("v$_",(15..20));
my ($FOUR,$sixteen,$twenty4,$twenty,$twelve,$twenty5,$seven) =
map("v$_",(21..27));
my ($inpperm,$outperm,$outmask) = map("v$_",(28..30));
my @D=("v31",$seven,$T0,$T1,$T2);
my $FRAME=$LOCALS+64+13*16+18*$SIZE_T; # 13*16 is for v20-v31 offload
sub VMXROUND {
my $odd = pop;
my ($a,$b,$c,$d,$t)=@_;
(
"&vadduwm ('$a','$a','$b')",
"&vxor ('$d','$d','$a')",
"&vperm ('$d','$d','$d','$sixteen')",
"&vadduwm ('$c','$c','$d')",
"&vxor ('$t','$b','$c')",
"&vsrw ('$b','$t','$twenty')",
"&vslw ('$t','$t','$twelve')",
"&vor ('$b','$b','$t')",
"&vadduwm ('$a','$a','$b')",
"&vxor ('$d','$d','$a')",
"&vperm ('$d','$d','$d','$twenty4')",
"&vadduwm ('$c','$c','$d')",
"&vxor ('$t','$b','$c')",
"&vsrw ('$b','$t','$twenty5')",
"&vslw ('$t','$t','$seven')",
"&vor ('$b','$b','$t')",
"&vsldoi ('$c','$c','$c',8)",
"&vsldoi ('$b','$b','$b',$odd?4:12)",
"&vsldoi ('$d','$d','$d',$odd?12:4)"
);
}
$code.=<<___;
.globl .ChaCha20_ctr32_vmx
.align 5
.ChaCha20_ctr32_vmx:
${UCMP}i $len,256
blt __ChaCha20_ctr32_int
$STU $sp,-$FRAME($sp)
mflr r0
li r10,`15+$LOCALS+64`
li r11,`31+$LOCALS+64`
mfspr r12,256
stvx v20,r10,$sp
addi r10,r10,32
stvx v21,r11,$sp
addi r11,r11,32
stvx v22,r10,$sp
addi r10,r10,32
stvx v23,r11,$sp
addi r11,r11,32
stvx v24,r10,$sp
addi r10,r10,32
stvx v25,r11,$sp
addi r11,r11,32
stvx v26,r10,$sp
addi r10,r10,32
stvx v27,r11,$sp
addi r11,r11,32
stvx v28,r10,$sp
addi r10,r10,32
stvx v29,r11,$sp
addi r11,r11,32
stvx v30,r10,$sp
stvx v31,r11,$sp
stw r12,`$FRAME-$SIZE_T*18-4`($sp) # save vrsave
$PUSH r14,`$FRAME-$SIZE_T*18`($sp)
$PUSH r15,`$FRAME-$SIZE_T*17`($sp)
$PUSH r16,`$FRAME-$SIZE_T*16`($sp)
$PUSH r17,`$FRAME-$SIZE_T*15`($sp)
$PUSH r18,`$FRAME-$SIZE_T*14`($sp)
$PUSH r19,`$FRAME-$SIZE_T*13`($sp)
$PUSH r20,`$FRAME-$SIZE_T*12`($sp)
$PUSH r21,`$FRAME-$SIZE_T*11`($sp)
$PUSH r22,`$FRAME-$SIZE_T*10`($sp)
$PUSH r23,`$FRAME-$SIZE_T*9`($sp)
$PUSH r24,`$FRAME-$SIZE_T*8`($sp)
$PUSH r25,`$FRAME-$SIZE_T*7`($sp)
$PUSH r26,`$FRAME-$SIZE_T*6`($sp)
$PUSH r27,`$FRAME-$SIZE_T*5`($sp)
$PUSH r28,`$FRAME-$SIZE_T*4`($sp)
$PUSH r29,`$FRAME-$SIZE_T*3`($sp)
$PUSH r30,`$FRAME-$SIZE_T*2`($sp)
$PUSH r31,`$FRAME-$SIZE_T*1`($sp)
li r12,-1
$PUSH r0, `$FRAME+$LRSAVE`($sp)
mtspr 256,r12 # preserve all AltiVec registers
bl Lconsts # returns pointer Lsigma in r12
li @x[0],16
li @x[1],32
li @x[2],48
li @x[3],64
li @x[4],31 # 31 is not a typo
li @x[5],15 # nor is 15
lvx @K[1],0,$key # load key
?lvsr $T0,0,$key # prepare unaligned load
lvx @K[2],@x[0],$key
lvx @D[0],@x[4],$key
lvx @K[3],0,$ctr # load counter
?lvsr $T1,0,$ctr # prepare unaligned load
lvx @D[1],@x[5],$ctr
lvx @K[0],0,r12 # load constants
lvx @K[5],@x[0],r12 # one
lvx $FOUR,@x[1],r12
lvx $sixteen,@x[2],r12
lvx $twenty4,@x[3],r12
?vperm @K[1],@K[2],@K[1],$T0 # align key
?vperm @K[2],@D[0],@K[2],$T0
?vperm @K[3],@D[1],@K[3],$T1 # align counter
lwz @d[0],0($ctr) # load counter to GPR
lwz @d[1],4($ctr)
vadduwm @K[3],@K[3],@K[5] # adjust AltiVec counter
lwz @d[2],8($ctr)
vadduwm @K[4],@K[3],@K[5]
lwz @d[3],12($ctr)
vadduwm @K[5],@K[4],@K[5]
vspltisw $twenty,-12 # synthesize constants
vspltisw $twelve,12
vspltisw $twenty5,-7
#vspltisw $seven,7 # synthesized in the loop
vxor $T0,$T0,$T0 # 0x00..00
vspltisw $outmask,-1 # 0xff..ff
?lvsr $inpperm,0,$inp # prepare for unaligned load
?lvsl $outperm,0,$out # prepare for unaligned store
?vperm $outmask,$outmask,$T0,$outperm
be?lvsl $T0,0,@x[0] # 0x00..0f
be?vspltisb $T1,3 # 0x03..03
be?vxor $T0,$T0,$T1 # swap bytes within words
be?vxor $outperm,$outperm,$T1
be?vperm $inpperm,$inpperm,$inpperm,$T0
b Loop_outer_vmx
.align 4
Loop_outer_vmx:
lis @x[0],0x6170 # synthesize sigma
lis @x[1],0x3320
vmr $A0,@K[0]
lis @x[2],0x7962
lis @x[3],0x6b20
vmr $A1,@K[0]
ori @x[0],@x[0],0x7865
ori @x[1],@x[1],0x646e
vmr $A2,@K[0]
ori @x[2],@x[2],0x2d32
ori @x[3],@x[3],0x6574
vmr $B0,@K[1]
li r0,10 # inner loop counter
lwz @x[4],0($key) # load key to GPR
vmr $B1,@K[1]
lwz @x[5],4($key)
vmr $B2,@K[1]
lwz @x[6],8($key)
vmr $C0,@K[2]
lwz @x[7],12($key)
vmr $C1,@K[2]
lwz @x[8],16($key)
vmr $C2,@K[2]
mr @x[12],@d[0] # copy GPR counter
lwz @x[9],20($key)
vmr $D0,@K[3]
mr @x[13],@d[1]
lwz @x[10],24($key)
vmr $D1,@K[4]
mr @x[14],@d[2]
lwz @x[11],28($key)
vmr $D2,@K[5]
mr @x[15],@d[3]
mr @t[0],@x[4]
mr @t[1],@x[5]
mr @t[2],@x[6]
mr @t[3],@x[7]
vspltisw $seven,7
mtctr r0
nop
Loop_vmx:
___
my @thread0=&VMXROUND($A0,$B0,$C0,$D0,$T0,0);
my @thread1=&VMXROUND($A1,$B1,$C1,$D1,$T1,0);
my @thread2=&VMXROUND($A2,$B2,$C2,$D2,$T2,0);
my @thread3=&ROUND(0,4,8,12);
foreach (@thread0) {
eval; eval(shift(@thread3));
eval(shift(@thread1)); eval(shift(@thread3));
eval(shift(@thread2)); eval(shift(@thread3));
}
@thread0=&VMXROUND($A0,$B0,$C0,$D0,$T0,1);
@thread1=&VMXROUND($A1,$B1,$C1,$D1,$T1,1);
@thread2=&VMXROUND($A2,$B2,$C2,$D2,$T2,1);
@thread3=&ROUND(0,5,10,15);
foreach (@thread0) {
eval; eval(shift(@thread3));
eval(shift(@thread1)); eval(shift(@thread3));
eval(shift(@thread2)); eval(shift(@thread3));
}
$code.=<<___;
bdnz Loop_vmx
subi $len,$len,256 # $len-=256
addi @x[0],@x[0],0x7865 # accumulate key block
addi @x[1],@x[1],0x646e
addi @x[2],@x[2],0x2d32
addi @x[3],@x[3],0x6574
addis @x[0],@x[0],0x6170
addis @x[1],@x[1],0x3320
addis @x[2],@x[2],0x7962
addis @x[3],@x[3],0x6b20
add @x[4],@x[4],@t[0]
lwz @t[0],16($key)
add @x[5],@x[5],@t[1]
lwz @t[1],20($key)
add @x[6],@x[6],@t[2]
lwz @t[2],24($key)
add @x[7],@x[7],@t[3]
lwz @t[3],28($key)
add @x[8],@x[8],@t[0]
add @x[9],@x[9],@t[1]
add @x[10],@x[10],@t[2]
add @x[11],@x[11],@t[3]
add @x[12],@x[12],@d[0]
add @x[13],@x[13],@d[1]
add @x[14],@x[14],@d[2]
add @x[15],@x[15],@d[3]
vadduwm $A0,$A0,@K[0] # accumulate key block
vadduwm $A1,$A1,@K[0]
vadduwm $A2,$A2,@K[0]
vadduwm $B0,$B0,@K[1]
vadduwm $B1,$B1,@K[1]
vadduwm $B2,$B2,@K[1]
vadduwm $C0,$C0,@K[2]
vadduwm $C1,$C1,@K[2]
vadduwm $C2,$C2,@K[2]
vadduwm $D0,$D0,@K[3]
vadduwm $D1,$D1,@K[4]
vadduwm $D2,$D2,@K[5]
addi @d[0],@d[0],4 # increment counter
vadduwm @K[3],@K[3],$FOUR
vadduwm @K[4],@K[4],$FOUR
vadduwm @K[5],@K[5],$FOUR
___
if (!$LITTLE_ENDIAN) { for($i=0;$i<16;$i++) { # flip byte order
$code.=<<___;
mr @t[$i&3],@x[$i]
rotlwi @x[$i],@x[$i],8
rlwimi @x[$i],@t[$i&3],24,0,7
rlwimi @x[$i],@t[$i&3],24,16,23
___
} }
$code.=<<___;
lwz @t[0],0($inp) # load input, aligned or not
lwz @t[1],4($inp)
lwz @t[2],8($inp)
lwz @t[3],12($inp)
xor @x[0],@x[0],@t[0] # xor with input
lwz @t[0],16($inp)
xor @x[1],@x[1],@t[1]
lwz @t[1],20($inp)
xor @x[2],@x[2],@t[2]
lwz @t[2],24($inp)
xor @x[3],@x[3],@t[3]
lwz @t[3],28($inp)
xor @x[4],@x[4],@t[0]
lwz @t[0],32($inp)
xor @x[5],@x[5],@t[1]
lwz @t[1],36($inp)
xor @x[6],@x[6],@t[2]
lwz @t[2],40($inp)
xor @x[7],@x[7],@t[3]
lwz @t[3],44($inp)
xor @x[8],@x[8],@t[0]
lwz @t[0],48($inp)
xor @x[9],@x[9],@t[1]
lwz @t[1],52($inp)
xor @x[10],@x[10],@t[2]
lwz @t[2],56($inp)
xor @x[11],@x[11],@t[3]
lwz @t[3],60($inp)
xor @x[12],@x[12],@t[0]
stw @x[0],0($out) # store output, aligned or not
xor @x[13],@x[13],@t[1]
stw @x[1],4($out)
xor @x[14],@x[14],@t[2]
stw @x[2],8($out)
xor @x[15],@x[15],@t[3]
stw @x[3],12($out)
addi $inp,$inp,64
stw @x[4],16($out)
li @t[0],16
stw @x[5],20($out)
li @t[1],32
stw @x[6],24($out)
li @t[2],48
stw @x[7],28($out)
li @t[3],64
stw @x[8],32($out)
stw @x[9],36($out)
stw @x[10],40($out)
stw @x[11],44($out)
stw @x[12],48($out)
stw @x[13],52($out)
stw @x[14],56($out)
stw @x[15],60($out)
addi $out,$out,64
lvx @D[0],0,$inp # load input
lvx @D[1],@t[0],$inp
lvx @D[2],@t[1],$inp
lvx @D[3],@t[2],$inp
lvx @D[4],@t[3],$inp
addi $inp,$inp,64
?vperm @D[0],@D[1],@D[0],$inpperm # align input
?vperm @D[1],@D[2],@D[1],$inpperm
?vperm @D[2],@D[3],@D[2],$inpperm
?vperm @D[3],@D[4],@D[3],$inpperm
vxor $A0,$A0,@D[0] # xor with input
vxor $B0,$B0,@D[1]
lvx @D[1],@t[0],$inp # keep loading input
vxor $C0,$C0,@D[2]
lvx @D[2],@t[1],$inp
vxor $D0,$D0,@D[3]
lvx @D[3],@t[2],$inp
lvx @D[0],@t[3],$inp
addi $inp,$inp,64
li @t[3],63 # 63 is not a typo
vperm $A0,$A0,$A0,$outperm # pre-misalign output
vperm $B0,$B0,$B0,$outperm
vperm $C0,$C0,$C0,$outperm
vperm $D0,$D0,$D0,$outperm
?vperm @D[4],@D[1],@D[4],$inpperm # align input
?vperm @D[1],@D[2],@D[1],$inpperm
?vperm @D[2],@D[3],@D[2],$inpperm
?vperm @D[3],@D[0],@D[3],$inpperm
vxor $A1,$A1,@D[4]
vxor $B1,$B1,@D[1]
lvx @D[1],@t[0],$inp # keep loading input
vxor $C1,$C1,@D[2]
lvx @D[2],@t[1],$inp
vxor $D1,$D1,@D[3]
lvx @D[3],@t[2],$inp
lvx @D[4],@t[3],$inp # redundant in aligned case
addi $inp,$inp,64
vperm $A1,$A1,$A1,$outperm # pre-misalign output
vperm $B1,$B1,$B1,$outperm
vperm $C1,$C1,$C1,$outperm
vperm $D1,$D1,$D1,$outperm
?vperm @D[0],@D[1],@D[0],$inpperm # align input
?vperm @D[1],@D[2],@D[1],$inpperm
?vperm @D[2],@D[3],@D[2],$inpperm
?vperm @D[3],@D[4],@D[3],$inpperm
vxor $A2,$A2,@D[0]
vxor $B2,$B2,@D[1]
vxor $C2,$C2,@D[2]
vxor $D2,$D2,@D[3]
vperm $A2,$A2,$A2,$outperm # pre-misalign output
vperm $B2,$B2,$B2,$outperm
vperm $C2,$C2,$C2,$outperm
vperm $D2,$D2,$D2,$outperm
andi. @x[1],$out,15 # is $out aligned?
mr @x[0],$out
vsel @D[0],$A0,$B0,$outmask # collect pre-misaligned output
vsel @D[1],$B0,$C0,$outmask
vsel @D[2],$C0,$D0,$outmask
vsel @D[3],$D0,$A1,$outmask
vsel $B0,$A1,$B1,$outmask
vsel $C0,$B1,$C1,$outmask
vsel $D0,$C1,$D1,$outmask
vsel $A1,$D1,$A2,$outmask
vsel $B1,$A2,$B2,$outmask
vsel $C1,$B2,$C2,$outmask
vsel $D1,$C2,$D2,$outmask
#stvx $A0,0,$out # take it easy on the edges
stvx @D[0],@t[0],$out # store output
stvx @D[1],@t[1],$out
stvx @D[2],@t[2],$out
addi $out,$out,64
stvx @D[3],0,$out
stvx $B0,@t[0],$out
stvx $C0,@t[1],$out
stvx $D0,@t[2],$out
addi $out,$out,64
stvx $A1,0,$out
stvx $B1,@t[0],$out
stvx $C1,@t[1],$out
stvx $D1,@t[2],$out
addi $out,$out,64
beq Laligned_vmx
sub @x[2],$out,@x[1] # in misaligned case edges
li @x[3],0 # are written byte-by-byte
Lunaligned_tail_vmx:
stvebx $D2,@x[3],@x[2]
addi @x[3],@x[3],1
cmpw @x[3],@x[1]
bne Lunaligned_tail_vmx
sub @x[2],@x[0],@x[1]
Lunaligned_head_vmx:
stvebx $A0,@x[1],@x[2]
cmpwi @x[1],15
addi @x[1],@x[1],1
bne Lunaligned_head_vmx
${UCMP}i $len,255 # done with 256-byte blocks yet?
bgt Loop_outer_vmx
b Ldone_vmx
.align 4
Laligned_vmx:
stvx $A0,0,@x[0] # head hexaword was not stored
${UCMP}i $len,255 # done with 256-byte blocks yet?
bgt Loop_outer_vmx
nop
Ldone_vmx:
${UCMP}i $len,0 # done yet?
bnel __ChaCha20_1x
lwz r12,`$FRAME-$SIZE_T*18-4`($sp) # pull vrsave
li r10,`15+$LOCALS+64`
li r11,`31+$LOCALS+64`
mtspr 256,r12 # restore vrsave
lvx v20,r10,$sp
addi r10,r10,32
lvx v21,r11,$sp
addi r11,r11,32
lvx v22,r10,$sp
addi r10,r10,32
lvx v23,r11,$sp
addi r11,r11,32
lvx v24,r10,$sp
addi r10,r10,32
lvx v25,r11,$sp
addi r11,r11,32
lvx v26,r10,$sp
addi r10,r10,32
lvx v27,r11,$sp
addi r11,r11,32
lvx v28,r10,$sp
addi r10,r10,32
lvx v29,r11,$sp
addi r11,r11,32
lvx v30,r10,$sp
lvx v31,r11,$sp
$POP r0, `$FRAME+$LRSAVE`($sp)
$POP r14,`$FRAME-$SIZE_T*18`($sp)
$POP r15,`$FRAME-$SIZE_T*17`($sp)
$POP r16,`$FRAME-$SIZE_T*16`($sp)
$POP r17,`$FRAME-$SIZE_T*15`($sp)
$POP r18,`$FRAME-$SIZE_T*14`($sp)
$POP r19,`$FRAME-$SIZE_T*13`($sp)
$POP r20,`$FRAME-$SIZE_T*12`($sp)
$POP r21,`$FRAME-$SIZE_T*11`($sp)
$POP r22,`$FRAME-$SIZE_T*10`($sp)
$POP r23,`$FRAME-$SIZE_T*9`($sp)
$POP r24,`$FRAME-$SIZE_T*8`($sp)
$POP r25,`$FRAME-$SIZE_T*7`($sp)
$POP r26,`$FRAME-$SIZE_T*6`($sp)
$POP r27,`$FRAME-$SIZE_T*5`($sp)
$POP r28,`$FRAME-$SIZE_T*4`($sp)
$POP r29,`$FRAME-$SIZE_T*3`($sp)
$POP r30,`$FRAME-$SIZE_T*2`($sp)
$POP r31,`$FRAME-$SIZE_T*1`($sp)
mtlr r0
addi $sp,$sp,$FRAME
blr
.long 0
.byte 0,12,0x04,1,0x80,18,5,0
.long 0
.size .ChaCha20_ctr32_vmx,.-.ChaCha20_ctr32_vmx
.align 5
Lconsts:
mflr r0
bcl 20,31,\$+4
mflr r12 #vvvvv "distance between . and _vpaes_consts
addi r12,r12,`64-8`
mtlr r0
blr
.long 0
.byte 0,12,0x14,0,0,0,0,0
.space `64-9*4`
Lsigma:
.long 0x61707865,0x3320646e,0x79622d32,0x6b206574
.long 1,0,0,0
.long 4,0,0,0
___
$code.=<<___ if ($LITTLE_ENDIAN);
.long 0x0e0f0c0d,0x0a0b0809,0x06070405,0x02030001
.long 0x0d0e0f0c,0x090a0b08,0x05060704,0x01020300
___
$code.=<<___ if (!$LITTLE_ENDIAN); # flipped words
.long 0x02030001,0x06070405,0x0a0b0809,0x0e0f0c0d
.long 0x01020300,0x05060704,0x090a0b08,0x0d0e0f0c
___
$code.=<<___;
.asciz "ChaCha20 for PowerPC/AltiVec, CRYPTOGAMS by <appro\@openssl.org>"
.align 2
___
}}}
foreach (split("\n",$code)) {
s/\`([^\`]*)\`/eval $1/ge;
# instructions prefixed with '?' are endian-specific and need
# to be adjusted accordingly...
if ($flavour !~ /le$/) { # big-endian
s/be\?// or
s/le\?/#le#/ or
s/\?lvsr/lvsl/ or
s/\?lvsl/lvsr/ or
s/\?(vperm\s+v[0-9]+,\s*)(v[0-9]+,\s*)(v[0-9]+,\s*)(v[0-9]+)/$1$3$2$4/ or
s/(vsldoi\s+v[0-9]+,\s*)(v[0-9]+,)\s*(v[0-9]+,\s*)([0-9]+)/$1$3$2 16-$4/;
} else { # little-endian
s/le\?// or
s/be\?/#be#/ or
s/\?([a-z]+)/$1/;
}
print $_,"\n";
}
close STDOUT;
+326
View File
@@ -0,0 +1,326 @@
#! /usr/bin/env perl
# Copyright 2016 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/.
# ====================================================================
#
# December 2015
#
# ChaCha20 for s390x.
#
# 3 times 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";
sub AUTOLOAD() # thunk [simplified] x86-style perlasm
{ my $opcode = $AUTOLOAD; $opcode =~ s/.*:://;
$code .= "\t$opcode\t".join(',',@_)."\n";
}
my $sp="%r15";
my $stdframe=16*$SIZE_T+4*8;
my $frame=$stdframe+4*20;
my ($out,$inp,$len,$key,$counter)=map("%r$_",(2..6));
my @x=map("%r$_",(0..7,"x","x","x","x",(10..13)));
my @t=map("%r$_",(8,9));
sub ROUND {
my ($a0,$b0,$c0,$d0)=@_;
my ($a1,$b1,$c1,$d1)=map(($_&~3)+(($_+1)&3),($a0,$b0,$c0,$d0));
my ($a2,$b2,$c2,$d2)=map(($_&~3)+(($_+1)&3),($a1,$b1,$c1,$d1));
my ($a3,$b3,$c3,$d3)=map(($_&~3)+(($_+1)&3),($a2,$b2,$c2,$d2));
my ($xc,$xc_)=map("\"$_\"",@t);
my @x=map("\"$_\"",@x);
# Consider order in which variables are addressed by their
# index:
#
# a b c d
#
# 0 4 8 12 < even round
# 1 5 9 13
# 2 6 10 14
# 3 7 11 15
# 0 5 10 15 < odd round
# 1 6 11 12
# 2 7 8 13
# 3 4 9 14
#
# 'a', 'b' and 'd's are permanently allocated in registers,
# @x[0..7,12..15], while 'c's are maintained in memory. If
# you observe 'c' column, you'll notice that pair of 'c's is
# invariant between rounds. This means that we have to reload
# them once per round, in the middle. This is why you'll see
# 'c' stores and loads in the middle, but none in the beginning
# or end.
(
"&alr (@x[$a0],@x[$b0])", # Q1
"&alr (@x[$a1],@x[$b1])", # Q2
"&xr (@x[$d0],@x[$a0])",
"&xr (@x[$d1],@x[$a1])",
"&rll (@x[$d0],@x[$d0],16)",
"&rll (@x[$d1],@x[$d1],16)",
"&alr ($xc,@x[$d0])",
"&alr ($xc_,@x[$d1])",
"&xr (@x[$b0],$xc)",
"&xr (@x[$b1],$xc_)",
"&rll (@x[$b0],@x[$b0],12)",
"&rll (@x[$b1],@x[$b1],12)",
"&alr (@x[$a0],@x[$b0])",
"&alr (@x[$a1],@x[$b1])",
"&xr (@x[$d0],@x[$a0])",
"&xr (@x[$d1],@x[$a1])",
"&rll (@x[$d0],@x[$d0],8)",
"&rll (@x[$d1],@x[$d1],8)",
"&alr ($xc,@x[$d0])",
"&alr ($xc_,@x[$d1])",
"&xr (@x[$b0],$xc)",
"&xr (@x[$b1],$xc_)",
"&rll (@x[$b0],@x[$b0],7)",
"&rll (@x[$b1],@x[$b1],7)",
"&stm ($xc,$xc_,'$stdframe+4*8+4*$c0($sp)')", # reload pair of 'c's
"&lm ($xc,$xc_,'$stdframe+4*8+4*$c2($sp)')",
"&alr (@x[$a2],@x[$b2])", # Q3
"&alr (@x[$a3],@x[$b3])", # Q4
"&xr (@x[$d2],@x[$a2])",
"&xr (@x[$d3],@x[$a3])",
"&rll (@x[$d2],@x[$d2],16)",
"&rll (@x[$d3],@x[$d3],16)",
"&alr ($xc,@x[$d2])",
"&alr ($xc_,@x[$d3])",
"&xr (@x[$b2],$xc)",
"&xr (@x[$b3],$xc_)",
"&rll (@x[$b2],@x[$b2],12)",
"&rll (@x[$b3],@x[$b3],12)",
"&alr (@x[$a2],@x[$b2])",
"&alr (@x[$a3],@x[$b3])",
"&xr (@x[$d2],@x[$a2])",
"&xr (@x[$d3],@x[$a3])",
"&rll (@x[$d2],@x[$d2],8)",
"&rll (@x[$d3],@x[$d3],8)",
"&alr ($xc,@x[$d2])",
"&alr ($xc_,@x[$d3])",
"&xr (@x[$b2],$xc)",
"&xr (@x[$b3],$xc_)",
"&rll (@x[$b2],@x[$b2],7)",
"&rll (@x[$b3],@x[$b3],7)"
);
}
$code.=<<___;
.text
.globl ChaCha20_ctr32
.type ChaCha20_ctr32,\@function
.align 32
ChaCha20_ctr32:
lt${g}r $len,$len # $len==0?
bzr %r14
a${g}hi $len,-64
l${g}hi %r1,-$frame
stm${g} %r6,%r15,`6*$SIZE_T`($sp)
sl${g}r $out,$inp # difference
la $len,0($inp,$len) # end of input minus 64
larl %r7,.Lsigma
lgr %r0,$sp
la $sp,0(%r1,$sp)
st${g} %r0,0($sp)
lmg %r8,%r11,0($key) # load key
lmg %r12,%r13,0($counter) # load counter
lmg %r6,%r7,0(%r7) # load sigma constant
la %r14,0($inp)
st${g} $out,$frame+3*$SIZE_T($sp)
st${g} $len,$frame+4*$SIZE_T($sp)
stmg %r6,%r13,$stdframe($sp) # copy key schedule to stack
srlg @x[12],%r12,32 # 32-bit counter value
j .Loop_outer
.align 16
.Loop_outer:
lm @x[0],@x[7],$stdframe+4*0($sp) # load x[0]-x[7]
lm @t[0],@t[1],$stdframe+4*10($sp) # load x[10]-x[11]
lm @x[13],@x[15],$stdframe+4*13($sp) # load x[13]-x[15]
stm @t[0],@t[1],$stdframe+4*8+4*10($sp) # offload x[10]-x[11]
lm @t[0],@t[1],$stdframe+4*8($sp) # load x[8]-x[9]
st @x[12],$stdframe+4*12($sp) # save counter
st${g} %r14,$frame+2*$SIZE_T($sp) # save input pointer
lhi %r14,10
j .Loop
.align 4
.Loop:
___
foreach (&ROUND(0, 4, 8,12)) { eval; }
foreach (&ROUND(0, 5,10,15)) { eval; }
$code.=<<___;
brct %r14,.Loop
l${g} %r14,$frame+2*$SIZE_T($sp) # pull input pointer
stm @t[0],@t[1],$stdframe+4*8+4*8($sp) # offload x[8]-x[9]
lm${g} @t[0],@t[1],$frame+3*$SIZE_T($sp)
al @x[0],$stdframe+4*0($sp) # accumulate key schedule
al @x[1],$stdframe+4*1($sp)
al @x[2],$stdframe+4*2($sp)
al @x[3],$stdframe+4*3($sp)
al @x[4],$stdframe+4*4($sp)
al @x[5],$stdframe+4*5($sp)
al @x[6],$stdframe+4*6($sp)
al @x[7],$stdframe+4*7($sp)
lrvr @x[0],@x[0]
lrvr @x[1],@x[1]
lrvr @x[2],@x[2]
lrvr @x[3],@x[3]
lrvr @x[4],@x[4]
lrvr @x[5],@x[5]
lrvr @x[6],@x[6]
lrvr @x[7],@x[7]
al @x[12],$stdframe+4*12($sp)
al @x[13],$stdframe+4*13($sp)
al @x[14],$stdframe+4*14($sp)
al @x[15],$stdframe+4*15($sp)
lrvr @x[12],@x[12]
lrvr @x[13],@x[13]
lrvr @x[14],@x[14]
lrvr @x[15],@x[15]
la @t[0],0(@t[0],%r14) # reconstruct output pointer
cl${g}r %r14,@t[1]
jh .Ltail
x @x[0],4*0(%r14) # xor with input
x @x[1],4*1(%r14)
st @x[0],4*0(@t[0]) # store output
x @x[2],4*2(%r14)
st @x[1],4*1(@t[0])
x @x[3],4*3(%r14)
st @x[2],4*2(@t[0])
x @x[4],4*4(%r14)
st @x[3],4*3(@t[0])
lm @x[0],@x[3],$stdframe+4*8+4*8($sp) # load x[8]-x[11]
x @x[5],4*5(%r14)
st @x[4],4*4(@t[0])
x @x[6],4*6(%r14)
al @x[0],$stdframe+4*8($sp)
st @x[5],4*5(@t[0])
x @x[7],4*7(%r14)
al @x[1],$stdframe+4*9($sp)
st @x[6],4*6(@t[0])
x @x[12],4*12(%r14)
al @x[2],$stdframe+4*10($sp)
st @x[7],4*7(@t[0])
x @x[13],4*13(%r14)
al @x[3],$stdframe+4*11($sp)
st @x[12],4*12(@t[0])
x @x[14],4*14(%r14)
st @x[13],4*13(@t[0])
x @x[15],4*15(%r14)
st @x[14],4*14(@t[0])
lrvr @x[0],@x[0]
st @x[15],4*15(@t[0])
lrvr @x[1],@x[1]
lrvr @x[2],@x[2]
lrvr @x[3],@x[3]
lhi @x[12],1
x @x[0],4*8(%r14)
al @x[12],$stdframe+4*12($sp) # increment counter
x @x[1],4*9(%r14)
st @x[0],4*8(@t[0])
x @x[2],4*10(%r14)
st @x[1],4*9(@t[0])
x @x[3],4*11(%r14)
st @x[2],4*10(@t[0])
st @x[3],4*11(@t[0])
cl${g}r %r14,@t[1] # done yet?
la %r14,64(%r14)
jl .Loop_outer
.Ldone:
xgr %r0,%r0
xgr %r1,%r1
xgr %r2,%r2
xgr %r3,%r3
stmg %r0,%r3,$stdframe+4*4($sp) # wipe key copy
stmg %r0,%r3,$stdframe+4*12($sp)
lm${g} %r6,%r15,`$frame+6*$SIZE_T`($sp)
br %r14
.align 16
.Ltail:
la @t[1],64($t[1])
stm @x[0],@x[7],$stdframe+4*0($sp)
sl${g}r @t[1],%r14
lm @x[0],@x[3],$stdframe+4*8+4*8($sp)
l${g}hi @x[6],0
stm @x[12],@x[15],$stdframe+4*12($sp)
al @x[0],$stdframe+4*8($sp)
al @x[1],$stdframe+4*9($sp)
al @x[2],$stdframe+4*10($sp)
al @x[3],$stdframe+4*11($sp)
lrvr @x[0],@x[0]
lrvr @x[1],@x[1]
lrvr @x[2],@x[2]
lrvr @x[3],@x[3]
stm @x[0],@x[3],$stdframe+4*8($sp)
.Loop_tail:
llgc @x[4],0(@x[6],%r14)
llgc @x[5],$stdframe(@x[6],$sp)
xr @x[5],@x[4]
stc @x[5],0(@x[6],@t[0])
la @x[6],1(@x[6])
brct @t[1],.Loop_tail
j .Ldone
.size ChaCha20_ctr32,.-ChaCha20_ctr32
.align 32
.Lsigma:
.long 0x61707865,0x3320646e,0x79622d32,0x6b206574 # endian-neutral
.asciz "ChaCha20 for s390x, CRYPTOGAMS by <appro\@openssl.org>"
.align 4
___
foreach (split("\n",$code)) {
s/\`([^\`]*)\`/eval $1/ge;
print $_,"\n";
}
close STDOUT;
+1154
View File
@@ -0,0 +1,1154 @@
#! /usr/bin/env perl
# Copyright 2016 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/.
# ====================================================================
#
# January 2015
#
# ChaCha20 for x86.
#
# Performance in cycles per byte out of large buffer.
#
# 1xIALU/gcc 4xSSSE3
# Pentium 17.5/+80%
# PIII 14.2/+60%
# P4 18.6/+84%
# Core2 9.56/+89% 4.83
# Westmere 9.50/+45% 3.35
# Sandy Bridge 10.5/+47% 3.20
# Haswell 8.15/+50% 2.83
# Silvermont 17.4/+36% 8.35
# Goldmont 13.4/+40% 4.36
# Sledgehammer 10.2/+54%
# Bulldozer 13.4/+50% 4.38(*)
#
# (*) Bulldozer actually executes 4xXOP code path that delivers 3.55;
$0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1;
push(@INC,"${dir}","${dir}../../perlasm");
require "x86asm.pl";
$output=pop;
open STDOUT,">$output";
&asm_init($ARGV[0],"chacha-x86.pl",$ARGV[$#ARGV] eq "386");
$xmm=$ymm=0;
for (@ARGV) { $xmm=1 if (/-DOPENSSL_IA32_SSE2/); }
$ymm=1 if ($xmm &&
`$ENV{CC} -Wa,-v -c -o /dev/null -x assembler /dev/null 2>&1`
=~ /GNU assembler version ([2-9]\.[0-9]+)/ &&
($gasver=$1)>=2.19); # first version supporting AVX
$ymm=1 if ($xmm && !$ymm && $ARGV[0] eq "win32n" &&
`nasm -v 2>&1` =~ /NASM version ([2-9]\.[0-9]+)/ &&
$1>=2.03); # first version supporting AVX
$ymm=1 if ($xmm && !$ymm && $ARGV[0] eq "win32" &&
`ml 2>&1` =~ /Version ([0-9]+)\./ &&
$1>=10); # first version supporting AVX
$ymm=1 if ($xmm && !$ymm &&
`$ENV{CC} -v 2>&1` =~ /(^clang version|based on LLVM) ([3-9]\.[0-9]+)/ &&
$2>=3.0); # first version supporting AVX
$a="eax";
($b,$b_)=("ebx","ebp");
($c,$c_)=("ecx","esi");
($d,$d_)=("edx","edi");
sub QUARTERROUND {
my ($ai,$bi,$ci,$di,$i)=@_;
my ($an,$bn,$cn,$dn)=map(($_&~3)+(($_+1)&3),($ai,$bi,$ci,$di)); # next
my ($ap,$bp,$cp,$dp)=map(($_&~3)+(($_-1)&3),($ai,$bi,$ci,$di)); # previous
# a b c d
#
# 0 4 8 12 < even round
# 1 5 9 13
# 2 6 10 14
# 3 7 11 15
# 0 5 10 15 < odd round
# 1 6 11 12
# 2 7 8 13
# 3 4 9 14
if ($i==0) {
my $j=4;
($ap,$bp,$cp,$dp)=map(($_&~3)+(($_-$j--)&3),($ap,$bp,$cp,$dp));
} elsif ($i==3) {
my $j=0;
($an,$bn,$cn,$dn)=map(($_&~3)+(($_+$j++)&3),($an,$bn,$cn,$dn));
} elsif ($i==4) {
my $j=4;
($ap,$bp,$cp,$dp)=map(($_&~3)+(($_+$j--)&3),($ap,$bp,$cp,$dp));
} elsif ($i==7) {
my $j=0;
($an,$bn,$cn,$dn)=map(($_&~3)+(($_-$j++)&3),($an,$bn,$cn,$dn));
}
#&add ($a,$b); # see elsewhere
&xor ($d,$a);
&mov (&DWP(4*$cp,"esp"),$c_) if ($ai>0 && $ai<3);
&rol ($d,16);
&mov (&DWP(4*$bp,"esp"),$b_) if ($i!=0);
&add ($c,$d);
&mov ($c_,&DWP(4*$cn,"esp")) if ($ai>0 && $ai<3);
&xor ($b,$c);
&mov ($d_,&DWP(4*$dn,"esp")) if ($di!=$dn);
&rol ($b,12);
&mov ($b_,&DWP(4*$bn,"esp")) if ($i<7);
&mov ($b_,&DWP(128,"esp")) if ($i==7); # loop counter
&add ($a,$b);
&xor ($d,$a);
&mov (&DWP(4*$ai,"esp"),$a);
&rol ($d,8);
&mov ($a,&DWP(4*$an,"esp"));
&add ($c,$d);
&mov (&DWP(4*$di,"esp"),$d) if ($di!=$dn);
&mov ($d_,$d) if ($di==$dn);
&xor ($b,$c);
&add ($a,$b_) if ($i<7); # elsewhere
&rol ($b,7);
($b,$b_)=($b_,$b);
($c,$c_)=($c_,$c);
($d,$d_)=($d_,$d);
}
&static_label("ssse3_shortcut");
&static_label("xop_shortcut");
&static_label("ssse3_data");
&static_label("pic_point");
&function_begin("ChaCha20_ctr32");
&xor ("eax","eax");
&cmp ("eax",&wparam(2)); # len==0?
&je (&label("no_data"));
if ($xmm) {
&call (&label("pic_point"));
&set_label("pic_point");
&blindpop("eax");
&picmeup("ebp","OPENSSL_ia32cap_P","eax",&label("pic_point"));
&test (&DWP(0,"ebp"),1<<24); # test FXSR bit
&jz (&label("x86"));
&test (&DWP(4,"ebp"),1<<9); # test SSSE3 bit
&jz (&label("x86"));
&jmp (&label("ssse3_shortcut"));
&set_label("x86");
}
&mov ("esi",&wparam(3)); # key
&mov ("edi",&wparam(4)); # counter and nonce
&stack_push(33);
&mov ("eax",&DWP(4*0,"esi")); # copy key
&mov ("ebx",&DWP(4*1,"esi"));
&mov ("ecx",&DWP(4*2,"esi"));
&mov ("edx",&DWP(4*3,"esi"));
&mov (&DWP(64+4*4,"esp"),"eax");
&mov (&DWP(64+4*5,"esp"),"ebx");
&mov (&DWP(64+4*6,"esp"),"ecx");
&mov (&DWP(64+4*7,"esp"),"edx");
&mov ("eax",&DWP(4*4,"esi"));
&mov ("ebx",&DWP(4*5,"esi"));
&mov ("ecx",&DWP(4*6,"esi"));
&mov ("edx",&DWP(4*7,"esi"));
&mov (&DWP(64+4*8,"esp"),"eax");
&mov (&DWP(64+4*9,"esp"),"ebx");
&mov (&DWP(64+4*10,"esp"),"ecx");
&mov (&DWP(64+4*11,"esp"),"edx");
&mov ("eax",&DWP(4*0,"edi")); # copy counter and nonce
&mov ("ebx",&DWP(4*1,"edi"));
&mov ("ecx",&DWP(4*2,"edi"));
&mov ("edx",&DWP(4*3,"edi"));
&sub ("eax",1);
&mov (&DWP(64+4*12,"esp"),"eax");
&mov (&DWP(64+4*13,"esp"),"ebx");
&mov (&DWP(64+4*14,"esp"),"ecx");
&mov (&DWP(64+4*15,"esp"),"edx");
&jmp (&label("entry"));
&set_label("outer_loop",16);
&mov (&wparam(1),$b); # save input
&mov (&wparam(0),$a); # save output
&mov (&wparam(2),$c); # save len
&set_label("entry");
&mov ($a,0x61707865);
&mov (&DWP(4*1,"esp"),0x3320646e);
&mov (&DWP(4*2,"esp"),0x79622d32);
&mov (&DWP(4*3,"esp"),0x6b206574);
&mov ($b, &DWP(64+4*5,"esp")); # copy key material
&mov ($b_,&DWP(64+4*6,"esp"));
&mov ($c, &DWP(64+4*10,"esp"));
&mov ($c_,&DWP(64+4*11,"esp"));
&mov ($d, &DWP(64+4*13,"esp"));
&mov ($d_,&DWP(64+4*14,"esp"));
&mov (&DWP(4*5,"esp"),$b);
&mov (&DWP(4*6,"esp"),$b_);
&mov (&DWP(4*10,"esp"),$c);
&mov (&DWP(4*11,"esp"),$c_);
&mov (&DWP(4*13,"esp"),$d);
&mov (&DWP(4*14,"esp"),$d_);
&mov ($b, &DWP(64+4*7,"esp"));
&mov ($d_,&DWP(64+4*15,"esp"));
&mov ($d, &DWP(64+4*12,"esp"));
&mov ($b_,&DWP(64+4*4,"esp"));
&mov ($c, &DWP(64+4*8,"esp"));
&mov ($c_,&DWP(64+4*9,"esp"));
&add ($d,1); # counter value
&mov (&DWP(4*7,"esp"),$b);
&mov (&DWP(4*15,"esp"),$d_);
&mov (&DWP(64+4*12,"esp"),$d); # save counter value
&mov ($b,10); # loop counter
&jmp (&label("loop"));
&set_label("loop",16);
&add ($a,$b_); # elsewhere
&mov (&DWP(128,"esp"),$b); # save loop counter
&mov ($b,$b_);
&QUARTERROUND(0, 4, 8, 12, 0);
&QUARTERROUND(1, 5, 9, 13, 1);
&QUARTERROUND(2, 6,10, 14, 2);
&QUARTERROUND(3, 7,11, 15, 3);
&QUARTERROUND(0, 5,10, 15, 4);
&QUARTERROUND(1, 6,11, 12, 5);
&QUARTERROUND(2, 7, 8, 13, 6);
&QUARTERROUND(3, 4, 9, 14, 7);
&dec ($b);
&jnz (&label("loop"));
&mov ($b,&wparam(2)); # load len
&add ($a,0x61707865); # accumulate key material
&add ($b_,&DWP(64+4*4,"esp"));
&add ($c, &DWP(64+4*8,"esp"));
&add ($c_,&DWP(64+4*9,"esp"));
&cmp ($b,64);
&jb (&label("tail"));
&mov ($b,&wparam(1)); # load input pointer
&add ($d, &DWP(64+4*12,"esp"));
&add ($d_,&DWP(64+4*14,"esp"));
&xor ($a, &DWP(4*0,$b)); # xor with input
&xor ($b_,&DWP(4*4,$b));
&mov (&DWP(4*0,"esp"),$a);
&mov ($a,&wparam(0)); # load output pointer
&xor ($c, &DWP(4*8,$b));
&xor ($c_,&DWP(4*9,$b));
&xor ($d, &DWP(4*12,$b));
&xor ($d_,&DWP(4*14,$b));
&mov (&DWP(4*4,$a),$b_); # write output
&mov (&DWP(4*8,$a),$c);
&mov (&DWP(4*9,$a),$c_);
&mov (&DWP(4*12,$a),$d);
&mov (&DWP(4*14,$a),$d_);
&mov ($b_,&DWP(4*1,"esp"));
&mov ($c, &DWP(4*2,"esp"));
&mov ($c_,&DWP(4*3,"esp"));
&mov ($d, &DWP(4*5,"esp"));
&mov ($d_,&DWP(4*6,"esp"));
&add ($b_,0x3320646e); # accumulate key material
&add ($c, 0x79622d32);
&add ($c_,0x6b206574);
&add ($d, &DWP(64+4*5,"esp"));
&add ($d_,&DWP(64+4*6,"esp"));
&xor ($b_,&DWP(4*1,$b));
&xor ($c, &DWP(4*2,$b));
&xor ($c_,&DWP(4*3,$b));
&xor ($d, &DWP(4*5,$b));
&xor ($d_,&DWP(4*6,$b));
&mov (&DWP(4*1,$a),$b_);
&mov (&DWP(4*2,$a),$c);
&mov (&DWP(4*3,$a),$c_);
&mov (&DWP(4*5,$a),$d);
&mov (&DWP(4*6,$a),$d_);
&mov ($b_,&DWP(4*7,"esp"));
&mov ($c, &DWP(4*10,"esp"));
&mov ($c_,&DWP(4*11,"esp"));
&mov ($d, &DWP(4*13,"esp"));
&mov ($d_,&DWP(4*15,"esp"));
&add ($b_,&DWP(64+4*7,"esp"));
&add ($c, &DWP(64+4*10,"esp"));
&add ($c_,&DWP(64+4*11,"esp"));
&add ($d, &DWP(64+4*13,"esp"));
&add ($d_,&DWP(64+4*15,"esp"));
&xor ($b_,&DWP(4*7,$b));
&xor ($c, &DWP(4*10,$b));
&xor ($c_,&DWP(4*11,$b));
&xor ($d, &DWP(4*13,$b));
&xor ($d_,&DWP(4*15,$b));
&lea ($b,&DWP(4*16,$b));
&mov (&DWP(4*7,$a),$b_);
&mov ($b_,&DWP(4*0,"esp"));
&mov (&DWP(4*10,$a),$c);
&mov ($c,&wparam(2)); # len
&mov (&DWP(4*11,$a),$c_);
&mov (&DWP(4*13,$a),$d);
&mov (&DWP(4*15,$a),$d_);
&mov (&DWP(4*0,$a),$b_);
&lea ($a,&DWP(4*16,$a));
&sub ($c,64);
&jnz (&label("outer_loop"));
&jmp (&label("done"));
&set_label("tail");
&add ($d, &DWP(64+4*12,"esp"));
&add ($d_,&DWP(64+4*14,"esp"));
&mov (&DWP(4*0,"esp"),$a);
&mov (&DWP(4*4,"esp"),$b_);
&mov (&DWP(4*8,"esp"),$c);
&mov (&DWP(4*9,"esp"),$c_);
&mov (&DWP(4*12,"esp"),$d);
&mov (&DWP(4*14,"esp"),$d_);
&mov ($b_,&DWP(4*1,"esp"));
&mov ($c, &DWP(4*2,"esp"));
&mov ($c_,&DWP(4*3,"esp"));
&mov ($d, &DWP(4*5,"esp"));
&mov ($d_,&DWP(4*6,"esp"));
&add ($b_,0x3320646e); # accumulate key material
&add ($c, 0x79622d32);
&add ($c_,0x6b206574);
&add ($d, &DWP(64+4*5,"esp"));
&add ($d_,&DWP(64+4*6,"esp"));
&mov (&DWP(4*1,"esp"),$b_);
&mov (&DWP(4*2,"esp"),$c);
&mov (&DWP(4*3,"esp"),$c_);
&mov (&DWP(4*5,"esp"),$d);
&mov (&DWP(4*6,"esp"),$d_);
&mov ($b_,&DWP(4*7,"esp"));
&mov ($c, &DWP(4*10,"esp"));
&mov ($c_,&DWP(4*11,"esp"));
&mov ($d, &DWP(4*13,"esp"));
&mov ($d_,&DWP(4*15,"esp"));
&add ($b_,&DWP(64+4*7,"esp"));
&add ($c, &DWP(64+4*10,"esp"));
&add ($c_,&DWP(64+4*11,"esp"));
&add ($d, &DWP(64+4*13,"esp"));
&add ($d_,&DWP(64+4*15,"esp"));
&mov (&DWP(4*7,"esp"),$b_);
&mov ($b_,&wparam(1)); # load input
&mov (&DWP(4*10,"esp"),$c);
&mov ($c,&wparam(0)); # load output
&mov (&DWP(4*11,"esp"),$c_);
&xor ($c_,$c_);
&mov (&DWP(4*13,"esp"),$d);
&mov (&DWP(4*15,"esp"),$d_);
&xor ("eax","eax");
&xor ("edx","edx");
&set_label("tail_loop");
&movb ("al",&BP(0,$c_,$b_));
&movb ("dl",&BP(0,"esp",$c_));
&lea ($c_,&DWP(1,$c_));
&xor ("al","dl");
&mov (&BP(-1,$c,$c_),"al");
&dec ($b);
&jnz (&label("tail_loop"));
&set_label("done");
&stack_pop(33);
&set_label("no_data");
&function_end("ChaCha20_ctr32");
if ($xmm) {
my ($xa,$xa_,$xb,$xb_,$xc,$xc_,$xd,$xd_)=map("xmm$_",(0..7));
my ($out,$inp,$len)=("edi","esi","ecx");
sub QUARTERROUND_SSSE3 {
my ($ai,$bi,$ci,$di,$i)=@_;
my ($an,$bn,$cn,$dn)=map(($_&~3)+(($_+1)&3),($ai,$bi,$ci,$di)); # next
my ($ap,$bp,$cp,$dp)=map(($_&~3)+(($_-1)&3),($ai,$bi,$ci,$di)); # previous
# a b c d
#
# 0 4 8 12 < even round
# 1 5 9 13
# 2 6 10 14
# 3 7 11 15
# 0 5 10 15 < odd round
# 1 6 11 12
# 2 7 8 13
# 3 4 9 14
if ($i==0) {
my $j=4;
($ap,$bp,$cp,$dp)=map(($_&~3)+(($_-$j--)&3),($ap,$bp,$cp,$dp));
} elsif ($i==3) {
my $j=0;
($an,$bn,$cn,$dn)=map(($_&~3)+(($_+$j++)&3),($an,$bn,$cn,$dn));
} elsif ($i==4) {
my $j=4;
($ap,$bp,$cp,$dp)=map(($_&~3)+(($_+$j--)&3),($ap,$bp,$cp,$dp));
} elsif ($i==7) {
my $j=0;
($an,$bn,$cn,$dn)=map(($_&~3)+(($_-$j++)&3),($an,$bn,$cn,$dn));
}
#&paddd ($xa,$xb); # see elsewhere
#&pxor ($xd,$xa); # see elsewhere
&movdqa(&QWP(16*$cp-128,"ebx"),$xc_) if ($ai>0 && $ai<3);
&pshufb ($xd,&QWP(0,"eax")); # rot16
&movdqa(&QWP(16*$bp-128,"ebx"),$xb_) if ($i!=0);
&paddd ($xc,$xd);
&movdqa($xc_,&QWP(16*$cn-128,"ebx")) if ($ai>0 && $ai<3);
&pxor ($xb,$xc);
&movdqa($xb_,&QWP(16*$bn-128,"ebx")) if ($i<7);
&movdqa ($xa_,$xb); # borrow as temporary
&pslld ($xb,12);
&psrld ($xa_,20);
&por ($xb,$xa_);
&movdqa($xa_,&QWP(16*$an-128,"ebx"));
&paddd ($xa,$xb);
&movdqa($xd_,&QWP(16*$dn-128,"ebx")) if ($di!=$dn);
&pxor ($xd,$xa);
&movdqa (&QWP(16*$ai-128,"ebx"),$xa);
&pshufb ($xd,&QWP(16,"eax")); # rot8
&paddd ($xc,$xd);
&movdqa (&QWP(16*$di-128,"ebx"),$xd) if ($di!=$dn);
&movdqa ($xd_,$xd) if ($di==$dn);
&pxor ($xb,$xc);
&paddd ($xa_,$xb_) if ($i<7); # elsewhere
&movdqa ($xa,$xb); # borrow as temporary
&pslld ($xb,7);
&psrld ($xa,25);
&pxor ($xd_,$xa_) if ($i<7); # elsewhere
&por ($xb,$xa);
($xa,$xa_)=($xa_,$xa);
($xb,$xb_)=($xb_,$xb);
($xc,$xc_)=($xc_,$xc);
($xd,$xd_)=($xd_,$xd);
}
&function_begin("ChaCha20_ssse3");
&set_label("ssse3_shortcut");
if ($ymm) {
&test (&DWP(4,"ebp"),1<<11); # test XOP bit
&jnz (&label("xop_shortcut"));
}
&mov ($out,&wparam(0));
&mov ($inp,&wparam(1));
&mov ($len,&wparam(2));
&mov ("edx",&wparam(3)); # key
&mov ("ebx",&wparam(4)); # counter and nonce
&mov ("ebp","esp");
&stack_push (131);
&and ("esp",-64);
&mov (&DWP(512,"esp"),"ebp");
&lea ("eax",&DWP(&label("ssse3_data")."-".
&label("pic_point"),"eax"));
&movdqu ("xmm3",&QWP(0,"ebx")); # counter and nonce
if (defined($gasver) && $gasver>=2.17) { # even though we encode
# pshufb manually, we
# handle only register
# operands, while this
# segment uses memory
# operand...
&cmp ($len,64*4);
&jb (&label("1x"));
&mov (&DWP(512+4,"esp"),"edx"); # offload pointers
&mov (&DWP(512+8,"esp"),"ebx");
&sub ($len,64*4); # bias len
&lea ("ebp",&DWP(256+128,"esp")); # size optimization
&movdqu ("xmm7",&QWP(0,"edx")); # key
&pshufd ("xmm0","xmm3",0x00);
&pshufd ("xmm1","xmm3",0x55);
&pshufd ("xmm2","xmm3",0xaa);
&pshufd ("xmm3","xmm3",0xff);
&paddd ("xmm0",&QWP(16*3,"eax")); # fix counters
&pshufd ("xmm4","xmm7",0x00);
&pshufd ("xmm5","xmm7",0x55);
&psubd ("xmm0",&QWP(16*4,"eax"));
&pshufd ("xmm6","xmm7",0xaa);
&pshufd ("xmm7","xmm7",0xff);
&movdqa (&QWP(16*12-128,"ebp"),"xmm0");
&movdqa (&QWP(16*13-128,"ebp"),"xmm1");
&movdqa (&QWP(16*14-128,"ebp"),"xmm2");
&movdqa (&QWP(16*15-128,"ebp"),"xmm3");
&movdqu ("xmm3",&QWP(16,"edx")); # key
&movdqa (&QWP(16*4-128,"ebp"),"xmm4");
&movdqa (&QWP(16*5-128,"ebp"),"xmm5");
&movdqa (&QWP(16*6-128,"ebp"),"xmm6");
&movdqa (&QWP(16*7-128,"ebp"),"xmm7");
&movdqa ("xmm7",&QWP(16*2,"eax")); # sigma
&lea ("ebx",&DWP(128,"esp")); # size optimization
&pshufd ("xmm0","xmm3",0x00);
&pshufd ("xmm1","xmm3",0x55);
&pshufd ("xmm2","xmm3",0xaa);
&pshufd ("xmm3","xmm3",0xff);
&pshufd ("xmm4","xmm7",0x00);
&pshufd ("xmm5","xmm7",0x55);
&pshufd ("xmm6","xmm7",0xaa);
&pshufd ("xmm7","xmm7",0xff);
&movdqa (&QWP(16*8-128,"ebp"),"xmm0");
&movdqa (&QWP(16*9-128,"ebp"),"xmm1");
&movdqa (&QWP(16*10-128,"ebp"),"xmm2");
&movdqa (&QWP(16*11-128,"ebp"),"xmm3");
&movdqa (&QWP(16*0-128,"ebp"),"xmm4");
&movdqa (&QWP(16*1-128,"ebp"),"xmm5");
&movdqa (&QWP(16*2-128,"ebp"),"xmm6");
&movdqa (&QWP(16*3-128,"ebp"),"xmm7");
&lea ($inp,&DWP(128,$inp)); # size optimization
&lea ($out,&DWP(128,$out)); # size optimization
&jmp (&label("outer_loop"));
&set_label("outer_loop",16);
#&movdqa ("xmm0",&QWP(16*0-128,"ebp")); # copy key material
&movdqa ("xmm1",&QWP(16*1-128,"ebp"));
&movdqa ("xmm2",&QWP(16*2-128,"ebp"));
&movdqa ("xmm3",&QWP(16*3-128,"ebp"));
#&movdqa ("xmm4",&QWP(16*4-128,"ebp"));
&movdqa ("xmm5",&QWP(16*5-128,"ebp"));
&movdqa ("xmm6",&QWP(16*6-128,"ebp"));
&movdqa ("xmm7",&QWP(16*7-128,"ebp"));
#&movdqa (&QWP(16*0-128,"ebx"),"xmm0");
&movdqa (&QWP(16*1-128,"ebx"),"xmm1");
&movdqa (&QWP(16*2-128,"ebx"),"xmm2");
&movdqa (&QWP(16*3-128,"ebx"),"xmm3");
#&movdqa (&QWP(16*4-128,"ebx"),"xmm4");
&movdqa (&QWP(16*5-128,"ebx"),"xmm5");
&movdqa (&QWP(16*6-128,"ebx"),"xmm6");
&movdqa (&QWP(16*7-128,"ebx"),"xmm7");
#&movdqa ("xmm0",&QWP(16*8-128,"ebp"));
#&movdqa ("xmm1",&QWP(16*9-128,"ebp"));
&movdqa ("xmm2",&QWP(16*10-128,"ebp"));
&movdqa ("xmm3",&QWP(16*11-128,"ebp"));
&movdqa ("xmm4",&QWP(16*12-128,"ebp"));
&movdqa ("xmm5",&QWP(16*13-128,"ebp"));
&movdqa ("xmm6",&QWP(16*14-128,"ebp"));
&movdqa ("xmm7",&QWP(16*15-128,"ebp"));
&paddd ("xmm4",&QWP(16*4,"eax")); # counter value
#&movdqa (&QWP(16*8-128,"ebx"),"xmm0");
#&movdqa (&QWP(16*9-128,"ebx"),"xmm1");
&movdqa (&QWP(16*10-128,"ebx"),"xmm2");
&movdqa (&QWP(16*11-128,"ebx"),"xmm3");
&movdqa (&QWP(16*12-128,"ebx"),"xmm4");
&movdqa (&QWP(16*13-128,"ebx"),"xmm5");
&movdqa (&QWP(16*14-128,"ebx"),"xmm6");
&movdqa (&QWP(16*15-128,"ebx"),"xmm7");
&movdqa (&QWP(16*12-128,"ebp"),"xmm4"); # save counter value
&movdqa ($xa, &QWP(16*0-128,"ebp"));
&movdqa ($xd, "xmm4");
&movdqa ($xb_,&QWP(16*4-128,"ebp"));
&movdqa ($xc, &QWP(16*8-128,"ebp"));
&movdqa ($xc_,&QWP(16*9-128,"ebp"));
&mov ("edx",10); # loop counter
&nop ();
&set_label("loop",16);
&paddd ($xa,$xb_); # elsewhere
&movdqa ($xb,$xb_);
&pxor ($xd,$xa); # elsewhere
&QUARTERROUND_SSSE3(0, 4, 8, 12, 0);
&QUARTERROUND_SSSE3(1, 5, 9, 13, 1);
&QUARTERROUND_SSSE3(2, 6,10, 14, 2);
&QUARTERROUND_SSSE3(3, 7,11, 15, 3);
&QUARTERROUND_SSSE3(0, 5,10, 15, 4);
&QUARTERROUND_SSSE3(1, 6,11, 12, 5);
&QUARTERROUND_SSSE3(2, 7, 8, 13, 6);
&QUARTERROUND_SSSE3(3, 4, 9, 14, 7);
&dec ("edx");
&jnz (&label("loop"));
&movdqa (&QWP(16*4-128,"ebx"),$xb_);
&movdqa (&QWP(16*8-128,"ebx"),$xc);
&movdqa (&QWP(16*9-128,"ebx"),$xc_);
&movdqa (&QWP(16*12-128,"ebx"),$xd);
&movdqa (&QWP(16*14-128,"ebx"),$xd_);
my ($xa0,$xa1,$xa2,$xa3,$xt0,$xt1,$xt2,$xt3)=map("xmm$_",(0..7));
#&movdqa ($xa0,&QWP(16*0-128,"ebx")); # it's there
&movdqa ($xa1,&QWP(16*1-128,"ebx"));
&movdqa ($xa2,&QWP(16*2-128,"ebx"));
&movdqa ($xa3,&QWP(16*3-128,"ebx"));
for($i=0;$i<256;$i+=64) {
&paddd ($xa0,&QWP($i+16*0-128,"ebp")); # accumulate key material
&paddd ($xa1,&QWP($i+16*1-128,"ebp"));
&paddd ($xa2,&QWP($i+16*2-128,"ebp"));
&paddd ($xa3,&QWP($i+16*3-128,"ebp"));
&movdqa ($xt2,$xa0); # "de-interlace" data
&punpckldq ($xa0,$xa1);
&movdqa ($xt3,$xa2);
&punpckldq ($xa2,$xa3);
&punpckhdq ($xt2,$xa1);
&punpckhdq ($xt3,$xa3);
&movdqa ($xa1,$xa0);
&punpcklqdq ($xa0,$xa2); # "a0"
&movdqa ($xa3,$xt2);
&punpcklqdq ($xt2,$xt3); # "a2"
&punpckhqdq ($xa1,$xa2); # "a1"
&punpckhqdq ($xa3,$xt3); # "a3"
#($xa2,$xt2)=($xt2,$xa2);
&movdqu ($xt0,&QWP(64*0-128,$inp)); # load input
&movdqu ($xt1,&QWP(64*1-128,$inp));
&movdqu ($xa2,&QWP(64*2-128,$inp));
&movdqu ($xt3,&QWP(64*3-128,$inp));
&lea ($inp,&QWP($i<192?16:(64*4-16*3),$inp));
&pxor ($xt0,$xa0);
&movdqa ($xa0,&QWP($i+16*4-128,"ebx")) if ($i<192);
&pxor ($xt1,$xa1);
&movdqa ($xa1,&QWP($i+16*5-128,"ebx")) if ($i<192);
&pxor ($xt2,$xa2);
&movdqa ($xa2,&QWP($i+16*6-128,"ebx")) if ($i<192);
&pxor ($xt3,$xa3);
&movdqa ($xa3,&QWP($i+16*7-128,"ebx")) if ($i<192);
&movdqu (&QWP(64*0-128,$out),$xt0); # store output
&movdqu (&QWP(64*1-128,$out),$xt1);
&movdqu (&QWP(64*2-128,$out),$xt2);
&movdqu (&QWP(64*3-128,$out),$xt3);
&lea ($out,&QWP($i<192?16:(64*4-16*3),$out));
}
&sub ($len,64*4);
&jnc (&label("outer_loop"));
&add ($len,64*4);
&jz (&label("done"));
&mov ("ebx",&DWP(512+8,"esp")); # restore pointers
&lea ($inp,&DWP(-128,$inp));
&mov ("edx",&DWP(512+4,"esp"));
&lea ($out,&DWP(-128,$out));
&movd ("xmm2",&DWP(16*12-128,"ebp")); # counter value
&movdqu ("xmm3",&QWP(0,"ebx"));
&paddd ("xmm2",&QWP(16*6,"eax")); # +four
&pand ("xmm3",&QWP(16*7,"eax"));
&por ("xmm3","xmm2"); # counter value
}
{
my ($a,$b,$c,$d,$t,$t1,$rot16,$rot24)=map("xmm$_",(0..7));
sub SSSE3ROUND { # critical path is 20 "SIMD ticks" per round
&paddd ($a,$b);
&pxor ($d,$a);
&pshufb ($d,$rot16);
&paddd ($c,$d);
&pxor ($b,$c);
&movdqa ($t,$b);
&psrld ($b,20);
&pslld ($t,12);
&por ($b,$t);
&paddd ($a,$b);
&pxor ($d,$a);
&pshufb ($d,$rot24);
&paddd ($c,$d);
&pxor ($b,$c);
&movdqa ($t,$b);
&psrld ($b,25);
&pslld ($t,7);
&por ($b,$t);
}
&set_label("1x");
&movdqa ($a,&QWP(16*2,"eax")); # sigma
&movdqu ($b,&QWP(0,"edx"));
&movdqu ($c,&QWP(16,"edx"));
#&movdqu ($d,&QWP(0,"ebx")); # already loaded
&movdqa ($rot16,&QWP(0,"eax"));
&movdqa ($rot24,&QWP(16,"eax"));
&mov (&DWP(16*3,"esp"),"ebp");
&movdqa (&QWP(16*0,"esp"),$a);
&movdqa (&QWP(16*1,"esp"),$b);
&movdqa (&QWP(16*2,"esp"),$c);
&movdqa (&QWP(16*3,"esp"),$d);
&mov ("edx",10);
&jmp (&label("loop1x"));
&set_label("outer1x",16);
&movdqa ($d,&QWP(16*5,"eax")); # one
&movdqa ($a,&QWP(16*0,"esp"));
&movdqa ($b,&QWP(16*1,"esp"));
&movdqa ($c,&QWP(16*2,"esp"));
&paddd ($d,&QWP(16*3,"esp"));
&mov ("edx",10);
&movdqa (&QWP(16*3,"esp"),$d);
&jmp (&label("loop1x"));
&set_label("loop1x",16);
&SSSE3ROUND();
&pshufd ($c,$c,0b01001110);
&pshufd ($b,$b,0b00111001);
&pshufd ($d,$d,0b10010011);
&nop ();
&SSSE3ROUND();
&pshufd ($c,$c,0b01001110);
&pshufd ($b,$b,0b10010011);
&pshufd ($d,$d,0b00111001);
&dec ("edx");
&jnz (&label("loop1x"));
&paddd ($a,&QWP(16*0,"esp"));
&paddd ($b,&QWP(16*1,"esp"));
&paddd ($c,&QWP(16*2,"esp"));
&paddd ($d,&QWP(16*3,"esp"));
&cmp ($len,64);
&jb (&label("tail"));
&movdqu ($t,&QWP(16*0,$inp));
&movdqu ($t1,&QWP(16*1,$inp));
&pxor ($a,$t); # xor with input
&movdqu ($t,&QWP(16*2,$inp));
&pxor ($b,$t1);
&movdqu ($t1,&QWP(16*3,$inp));
&pxor ($c,$t);
&pxor ($d,$t1);
&lea ($inp,&DWP(16*4,$inp)); # inp+=64
&movdqu (&QWP(16*0,$out),$a); # write output
&movdqu (&QWP(16*1,$out),$b);
&movdqu (&QWP(16*2,$out),$c);
&movdqu (&QWP(16*3,$out),$d);
&lea ($out,&DWP(16*4,$out)); # inp+=64
&sub ($len,64);
&jnz (&label("outer1x"));
&jmp (&label("done"));
&set_label("tail");
&movdqa (&QWP(16*0,"esp"),$a);
&movdqa (&QWP(16*1,"esp"),$b);
&movdqa (&QWP(16*2,"esp"),$c);
&movdqa (&QWP(16*3,"esp"),$d);
&xor ("eax","eax");
&xor ("edx","edx");
&xor ("ebp","ebp");
&set_label("tail_loop");
&movb ("al",&BP(0,"esp","ebp"));
&movb ("dl",&BP(0,$inp,"ebp"));
&lea ("ebp",&DWP(1,"ebp"));
&xor ("al","dl");
&movb (&BP(-1,$out,"ebp"),"al");
&dec ($len);
&jnz (&label("tail_loop"));
}
&set_label("done");
&mov ("esp",&DWP(512,"esp"));
&function_end("ChaCha20_ssse3");
&align (64);
&set_label("ssse3_data");
&data_byte(0x2,0x3,0x0,0x1, 0x6,0x7,0x4,0x5, 0xa,0xb,0x8,0x9, 0xe,0xf,0xc,0xd);
&data_byte(0x3,0x0,0x1,0x2, 0x7,0x4,0x5,0x6, 0xb,0x8,0x9,0xa, 0xf,0xc,0xd,0xe);
&data_word(0x61707865,0x3320646e,0x79622d32,0x6b206574);
&data_word(0,1,2,3);
&data_word(4,4,4,4);
&data_word(1,0,0,0);
&data_word(4,0,0,0);
&data_word(0,-1,-1,-1);
&align (64);
}
&asciz ("ChaCha20 for x86, CRYPTOGAMS by <appro\@openssl.org>");
if ($ymm) {
my ($xa,$xa_,$xb,$xb_,$xc,$xc_,$xd,$xd_)=map("xmm$_",(0..7));
my ($out,$inp,$len)=("edi","esi","ecx");
sub QUARTERROUND_XOP {
my ($ai,$bi,$ci,$di,$i)=@_;
my ($an,$bn,$cn,$dn)=map(($_&~3)+(($_+1)&3),($ai,$bi,$ci,$di)); # next
my ($ap,$bp,$cp,$dp)=map(($_&~3)+(($_-1)&3),($ai,$bi,$ci,$di)); # previous
# a b c d
#
# 0 4 8 12 < even round
# 1 5 9 13
# 2 6 10 14
# 3 7 11 15
# 0 5 10 15 < odd round
# 1 6 11 12
# 2 7 8 13
# 3 4 9 14
if ($i==0) {
my $j=4;
($ap,$bp,$cp,$dp)=map(($_&~3)+(($_-$j--)&3),($ap,$bp,$cp,$dp));
} elsif ($i==3) {
my $j=0;
($an,$bn,$cn,$dn)=map(($_&~3)+(($_+$j++)&3),($an,$bn,$cn,$dn));
} elsif ($i==4) {
my $j=4;
($ap,$bp,$cp,$dp)=map(($_&~3)+(($_+$j--)&3),($ap,$bp,$cp,$dp));
} elsif ($i==7) {
my $j=0;
($an,$bn,$cn,$dn)=map(($_&~3)+(($_-$j++)&3),($an,$bn,$cn,$dn));
}
#&vpaddd ($xa,$xa,$xb); # see elsewhere
#&vpxor ($xd,$xd,$xa); # see elsewhere
&vmovdqa (&QWP(16*$cp-128,"ebx"),$xc_) if ($ai>0 && $ai<3);
&vprotd ($xd,$xd,16);
&vmovdqa (&QWP(16*$bp-128,"ebx"),$xb_) if ($i!=0);
&vpaddd ($xc,$xc,$xd);
&vmovdqa ($xc_,&QWP(16*$cn-128,"ebx")) if ($ai>0 && $ai<3);
&vpxor ($xb,$i!=0?$xb:$xb_,$xc);
&vmovdqa ($xa_,&QWP(16*$an-128,"ebx"));
&vprotd ($xb,$xb,12);
&vmovdqa ($xb_,&QWP(16*$bn-128,"ebx")) if ($i<7);
&vpaddd ($xa,$xa,$xb);
&vmovdqa ($xd_,&QWP(16*$dn-128,"ebx")) if ($di!=$dn);
&vpxor ($xd,$xd,$xa);
&vpaddd ($xa_,$xa_,$xb_) if ($i<7); # elsewhere
&vprotd ($xd,$xd,8);
&vmovdqa (&QWP(16*$ai-128,"ebx"),$xa);
&vpaddd ($xc,$xc,$xd);
&vmovdqa (&QWP(16*$di-128,"ebx"),$xd) if ($di!=$dn);
&vpxor ($xb,$xb,$xc);
&vpxor ($xd_,$di==$dn?$xd:$xd_,$xa_) if ($i<7); # elsewhere
&vprotd ($xb,$xb,7);
($xa,$xa_)=($xa_,$xa);
($xb,$xb_)=($xb_,$xb);
($xc,$xc_)=($xc_,$xc);
($xd,$xd_)=($xd_,$xd);
}
&function_begin("ChaCha20_xop");
&set_label("xop_shortcut");
&mov ($out,&wparam(0));
&mov ($inp,&wparam(1));
&mov ($len,&wparam(2));
&mov ("edx",&wparam(3)); # key
&mov ("ebx",&wparam(4)); # counter and nonce
&vzeroupper ();
&mov ("ebp","esp");
&stack_push (131);
&and ("esp",-64);
&mov (&DWP(512,"esp"),"ebp");
&lea ("eax",&DWP(&label("ssse3_data")."-".
&label("pic_point"),"eax"));
&vmovdqu ("xmm3",&QWP(0,"ebx")); # counter and nonce
&cmp ($len,64*4);
&jb (&label("1x"));
&mov (&DWP(512+4,"esp"),"edx"); # offload pointers
&mov (&DWP(512+8,"esp"),"ebx");
&sub ($len,64*4); # bias len
&lea ("ebp",&DWP(256+128,"esp")); # size optimization
&vmovdqu ("xmm7",&QWP(0,"edx")); # key
&vpshufd ("xmm0","xmm3",0x00);
&vpshufd ("xmm1","xmm3",0x55);
&vpshufd ("xmm2","xmm3",0xaa);
&vpshufd ("xmm3","xmm3",0xff);
&vpaddd ("xmm0","xmm0",&QWP(16*3,"eax")); # fix counters
&vpshufd ("xmm4","xmm7",0x00);
&vpshufd ("xmm5","xmm7",0x55);
&vpsubd ("xmm0","xmm0",&QWP(16*4,"eax"));
&vpshufd ("xmm6","xmm7",0xaa);
&vpshufd ("xmm7","xmm7",0xff);
&vmovdqa (&QWP(16*12-128,"ebp"),"xmm0");
&vmovdqa (&QWP(16*13-128,"ebp"),"xmm1");
&vmovdqa (&QWP(16*14-128,"ebp"),"xmm2");
&vmovdqa (&QWP(16*15-128,"ebp"),"xmm3");
&vmovdqu ("xmm3",&QWP(16,"edx")); # key
&vmovdqa (&QWP(16*4-128,"ebp"),"xmm4");
&vmovdqa (&QWP(16*5-128,"ebp"),"xmm5");
&vmovdqa (&QWP(16*6-128,"ebp"),"xmm6");
&vmovdqa (&QWP(16*7-128,"ebp"),"xmm7");
&vmovdqa ("xmm7",&QWP(16*2,"eax")); # sigma
&lea ("ebx",&DWP(128,"esp")); # size optimization
&vpshufd ("xmm0","xmm3",0x00);
&vpshufd ("xmm1","xmm3",0x55);
&vpshufd ("xmm2","xmm3",0xaa);
&vpshufd ("xmm3","xmm3",0xff);
&vpshufd ("xmm4","xmm7",0x00);
&vpshufd ("xmm5","xmm7",0x55);
&vpshufd ("xmm6","xmm7",0xaa);
&vpshufd ("xmm7","xmm7",0xff);
&vmovdqa (&QWP(16*8-128,"ebp"),"xmm0");
&vmovdqa (&QWP(16*9-128,"ebp"),"xmm1");
&vmovdqa (&QWP(16*10-128,"ebp"),"xmm2");
&vmovdqa (&QWP(16*11-128,"ebp"),"xmm3");
&vmovdqa (&QWP(16*0-128,"ebp"),"xmm4");
&vmovdqa (&QWP(16*1-128,"ebp"),"xmm5");
&vmovdqa (&QWP(16*2-128,"ebp"),"xmm6");
&vmovdqa (&QWP(16*3-128,"ebp"),"xmm7");
&lea ($inp,&DWP(128,$inp)); # size optimization
&lea ($out,&DWP(128,$out)); # size optimization
&jmp (&label("outer_loop"));
&set_label("outer_loop",32);
#&vmovdqa ("xmm0",&QWP(16*0-128,"ebp")); # copy key material
&vmovdqa ("xmm1",&QWP(16*1-128,"ebp"));
&vmovdqa ("xmm2",&QWP(16*2-128,"ebp"));
&vmovdqa ("xmm3",&QWP(16*3-128,"ebp"));
#&vmovdqa ("xmm4",&QWP(16*4-128,"ebp"));
&vmovdqa ("xmm5",&QWP(16*5-128,"ebp"));
&vmovdqa ("xmm6",&QWP(16*6-128,"ebp"));
&vmovdqa ("xmm7",&QWP(16*7-128,"ebp"));
#&vmovdqa (&QWP(16*0-128,"ebx"),"xmm0");
&vmovdqa (&QWP(16*1-128,"ebx"),"xmm1");
&vmovdqa (&QWP(16*2-128,"ebx"),"xmm2");
&vmovdqa (&QWP(16*3-128,"ebx"),"xmm3");
#&vmovdqa (&QWP(16*4-128,"ebx"),"xmm4");
&vmovdqa (&QWP(16*5-128,"ebx"),"xmm5");
&vmovdqa (&QWP(16*6-128,"ebx"),"xmm6");
&vmovdqa (&QWP(16*7-128,"ebx"),"xmm7");
#&vmovdqa ("xmm0",&QWP(16*8-128,"ebp"));
#&vmovdqa ("xmm1",&QWP(16*9-128,"ebp"));
&vmovdqa ("xmm2",&QWP(16*10-128,"ebp"));
&vmovdqa ("xmm3",&QWP(16*11-128,"ebp"));
&vmovdqa ("xmm4",&QWP(16*12-128,"ebp"));
&vmovdqa ("xmm5",&QWP(16*13-128,"ebp"));
&vmovdqa ("xmm6",&QWP(16*14-128,"ebp"));
&vmovdqa ("xmm7",&QWP(16*15-128,"ebp"));
&vpaddd ("xmm4","xmm4",&QWP(16*4,"eax")); # counter value
#&vmovdqa (&QWP(16*8-128,"ebx"),"xmm0");
#&vmovdqa (&QWP(16*9-128,"ebx"),"xmm1");
&vmovdqa (&QWP(16*10-128,"ebx"),"xmm2");
&vmovdqa (&QWP(16*11-128,"ebx"),"xmm3");
&vmovdqa (&QWP(16*12-128,"ebx"),"xmm4");
&vmovdqa (&QWP(16*13-128,"ebx"),"xmm5");
&vmovdqa (&QWP(16*14-128,"ebx"),"xmm6");
&vmovdqa (&QWP(16*15-128,"ebx"),"xmm7");
&vmovdqa (&QWP(16*12-128,"ebp"),"xmm4"); # save counter value
&vmovdqa ($xa, &QWP(16*0-128,"ebp"));
&vmovdqa ($xd, "xmm4");
&vmovdqa ($xb_,&QWP(16*4-128,"ebp"));
&vmovdqa ($xc, &QWP(16*8-128,"ebp"));
&vmovdqa ($xc_,&QWP(16*9-128,"ebp"));
&mov ("edx",10); # loop counter
&nop ();
&set_label("loop",32);
&vpaddd ($xa,$xa,$xb_); # elsewhere
&vpxor ($xd,$xd,$xa); # elsewhere
&QUARTERROUND_XOP(0, 4, 8, 12, 0);
&QUARTERROUND_XOP(1, 5, 9, 13, 1);
&QUARTERROUND_XOP(2, 6,10, 14, 2);
&QUARTERROUND_XOP(3, 7,11, 15, 3);
&QUARTERROUND_XOP(0, 5,10, 15, 4);
&QUARTERROUND_XOP(1, 6,11, 12, 5);
&QUARTERROUND_XOP(2, 7, 8, 13, 6);
&QUARTERROUND_XOP(3, 4, 9, 14, 7);
&dec ("edx");
&jnz (&label("loop"));
&vmovdqa (&QWP(16*4-128,"ebx"),$xb_);
&vmovdqa (&QWP(16*8-128,"ebx"),$xc);
&vmovdqa (&QWP(16*9-128,"ebx"),$xc_);
&vmovdqa (&QWP(16*12-128,"ebx"),$xd);
&vmovdqa (&QWP(16*14-128,"ebx"),$xd_);
my ($xa0,$xa1,$xa2,$xa3,$xt0,$xt1,$xt2,$xt3)=map("xmm$_",(0..7));
#&vmovdqa ($xa0,&QWP(16*0-128,"ebx")); # it's there
&vmovdqa ($xa1,&QWP(16*1-128,"ebx"));
&vmovdqa ($xa2,&QWP(16*2-128,"ebx"));
&vmovdqa ($xa3,&QWP(16*3-128,"ebx"));
for($i=0;$i<256;$i+=64) {
&vpaddd ($xa0,$xa0,&QWP($i+16*0-128,"ebp")); # accumulate key material
&vpaddd ($xa1,$xa1,&QWP($i+16*1-128,"ebp"));
&vpaddd ($xa2,$xa2,&QWP($i+16*2-128,"ebp"));
&vpaddd ($xa3,$xa3,&QWP($i+16*3-128,"ebp"));
&vpunpckldq ($xt2,$xa0,$xa1); # "de-interlace" data
&vpunpckldq ($xt3,$xa2,$xa3);
&vpunpckhdq ($xa0,$xa0,$xa1);
&vpunpckhdq ($xa2,$xa2,$xa3);
&vpunpcklqdq ($xa1,$xt2,$xt3); # "a0"
&vpunpckhqdq ($xt2,$xt2,$xt3); # "a1"
&vpunpcklqdq ($xt3,$xa0,$xa2); # "a2"
&vpunpckhqdq ($xa3,$xa0,$xa2); # "a3"
&vpxor ($xt0,$xa1,&QWP(64*0-128,$inp));
&vpxor ($xt1,$xt2,&QWP(64*1-128,$inp));
&vpxor ($xt2,$xt3,&QWP(64*2-128,$inp));
&vpxor ($xt3,$xa3,&QWP(64*3-128,$inp));
&lea ($inp,&QWP($i<192?16:(64*4-16*3),$inp));
&vmovdqa ($xa0,&QWP($i+16*4-128,"ebx")) if ($i<192);
&vmovdqa ($xa1,&QWP($i+16*5-128,"ebx")) if ($i<192);
&vmovdqa ($xa2,&QWP($i+16*6-128,"ebx")) if ($i<192);
&vmovdqa ($xa3,&QWP($i+16*7-128,"ebx")) if ($i<192);
&vmovdqu (&QWP(64*0-128,$out),$xt0); # store output
&vmovdqu (&QWP(64*1-128,$out),$xt1);
&vmovdqu (&QWP(64*2-128,$out),$xt2);
&vmovdqu (&QWP(64*3-128,$out),$xt3);
&lea ($out,&QWP($i<192?16:(64*4-16*3),$out));
}
&sub ($len,64*4);
&jnc (&label("outer_loop"));
&add ($len,64*4);
&jz (&label("done"));
&mov ("ebx",&DWP(512+8,"esp")); # restore pointers
&lea ($inp,&DWP(-128,$inp));
&mov ("edx",&DWP(512+4,"esp"));
&lea ($out,&DWP(-128,$out));
&vmovd ("xmm2",&DWP(16*12-128,"ebp")); # counter value
&vmovdqu ("xmm3",&QWP(0,"ebx"));
&vpaddd ("xmm2","xmm2",&QWP(16*6,"eax"));# +four
&vpand ("xmm3","xmm3",&QWP(16*7,"eax"));
&vpor ("xmm3","xmm3","xmm2"); # counter value
{
my ($a,$b,$c,$d,$t,$t1,$rot16,$rot24)=map("xmm$_",(0..7));
sub XOPROUND {
&vpaddd ($a,$a,$b);
&vpxor ($d,$d,$a);
&vprotd ($d,$d,16);
&vpaddd ($c,$c,$d);
&vpxor ($b,$b,$c);
&vprotd ($b,$b,12);
&vpaddd ($a,$a,$b);
&vpxor ($d,$d,$a);
&vprotd ($d,$d,8);
&vpaddd ($c,$c,$d);
&vpxor ($b,$b,$c);
&vprotd ($b,$b,7);
}
&set_label("1x");
&vmovdqa ($a,&QWP(16*2,"eax")); # sigma
&vmovdqu ($b,&QWP(0,"edx"));
&vmovdqu ($c,&QWP(16,"edx"));
#&vmovdqu ($d,&QWP(0,"ebx")); # already loaded
&vmovdqa ($rot16,&QWP(0,"eax"));
&vmovdqa ($rot24,&QWP(16,"eax"));
&mov (&DWP(16*3,"esp"),"ebp");
&vmovdqa (&QWP(16*0,"esp"),$a);
&vmovdqa (&QWP(16*1,"esp"),$b);
&vmovdqa (&QWP(16*2,"esp"),$c);
&vmovdqa (&QWP(16*3,"esp"),$d);
&mov ("edx",10);
&jmp (&label("loop1x"));
&set_label("outer1x",16);
&vmovdqa ($d,&QWP(16*5,"eax")); # one
&vmovdqa ($a,&QWP(16*0,"esp"));
&vmovdqa ($b,&QWP(16*1,"esp"));
&vmovdqa ($c,&QWP(16*2,"esp"));
&vpaddd ($d,$d,&QWP(16*3,"esp"));
&mov ("edx",10);
&vmovdqa (&QWP(16*3,"esp"),$d);
&jmp (&label("loop1x"));
&set_label("loop1x",16);
&XOPROUND();
&vpshufd ($c,$c,0b01001110);
&vpshufd ($b,$b,0b00111001);
&vpshufd ($d,$d,0b10010011);
&XOPROUND();
&vpshufd ($c,$c,0b01001110);
&vpshufd ($b,$b,0b10010011);
&vpshufd ($d,$d,0b00111001);
&dec ("edx");
&jnz (&label("loop1x"));
&vpaddd ($a,$a,&QWP(16*0,"esp"));
&vpaddd ($b,$b,&QWP(16*1,"esp"));
&vpaddd ($c,$c,&QWP(16*2,"esp"));
&vpaddd ($d,$d,&QWP(16*3,"esp"));
&cmp ($len,64);
&jb (&label("tail"));
&vpxor ($a,$a,&QWP(16*0,$inp)); # xor with input
&vpxor ($b,$b,&QWP(16*1,$inp));
&vpxor ($c,$c,&QWP(16*2,$inp));
&vpxor ($d,$d,&QWP(16*3,$inp));
&lea ($inp,&DWP(16*4,$inp)); # inp+=64
&vmovdqu (&QWP(16*0,$out),$a); # write output
&vmovdqu (&QWP(16*1,$out),$b);
&vmovdqu (&QWP(16*2,$out),$c);
&vmovdqu (&QWP(16*3,$out),$d);
&lea ($out,&DWP(16*4,$out)); # inp+=64
&sub ($len,64);
&jnz (&label("outer1x"));
&jmp (&label("done"));
&set_label("tail");
&vmovdqa (&QWP(16*0,"esp"),$a);
&vmovdqa (&QWP(16*1,"esp"),$b);
&vmovdqa (&QWP(16*2,"esp"),$c);
&vmovdqa (&QWP(16*3,"esp"),$d);
&xor ("eax","eax");
&xor ("edx","edx");
&xor ("ebp","ebp");
&set_label("tail_loop");
&movb ("al",&BP(0,"esp","ebp"));
&movb ("dl",&BP(0,$inp,"ebp"));
&lea ("ebp",&DWP(1,"ebp"));
&xor ("al","dl");
&movb (&BP(-1,$out,"ebp"),"al");
&dec ($len);
&jnz (&label("tail_loop"));
}
&set_label("done");
&vzeroupper ();
&mov ("esp",&DWP(512,"esp"));
&function_end("ChaCha20_xop");
}
&asm_finish();
close STDOUT;
+2245
View File
@@ -0,0 +1,2245 @@
#! /usr/bin/env perl
# Copyright 2016 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/.
# ====================================================================
#
# November 2014
#
# ChaCha20 for x86_64.
#
# Performance in cycles per byte out of large buffer.
#
# IALU/gcc 4.8(i) 1xSSSE3/SSE2 4xSSSE3 8xAVX2
#
# P4 9.48/+99% -/22.7(ii) -
# Core2 7.83/+55% 7.90/8.08 4.35
# Westmere 7.19/+50% 5.60/6.70 3.00
# Sandy Bridge 8.31/+42% 5.45/6.76 2.72
# Ivy Bridge 6.71/+46% 5.40/6.49 2.41
# Haswell 5.92/+43% 5.20/6.45 2.42 1.23
# Silvermont 12.0/+33% 7.75/7.40 7.03(iii)
# Goldmont 10.6/+17% 5.10/- 3.28
# Sledgehammer 7.28/+52% -/14.2(ii) -
# Bulldozer 9.66/+28% 9.85/11.1 3.06(iv)
# VIA Nano 10.5/+46% 6.72/8.60 6.05
#
# (i) compared to older gcc 3.x one can observe >2x improvement on
# most platforms;
# (ii) as it can be seen, SSE2 performance is too low on legacy
# processors; NxSSE2 results are naturally better, but not
# impressively better than IALU ones, which is why you won't
# find SSE2 code below;
# (iii) this is not optimal result for Atom because of MSROM
# limitations, SSE2 can do better, but gain is considered too
# low to justify the [maintenance] effort;
# (iv) Bulldozer actually executes 4xXOP code path that delivers 2.20;
$flavour = shift;
$output = shift;
if ($flavour =~ /\./) { $output = $flavour; undef $flavour; }
$win64=0; $win64=1 if ($flavour =~ /[nm]asm|mingw64/ || $output =~ /\.asm$/);
$0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1;
( $xlate="${dir}x86_64-xlate.pl" and -f $xlate ) or
( $xlate="${dir}../../perlasm/x86_64-xlate.pl" and -f $xlate) or
die "can't locate x86_64-xlate.pl";
if (`$ENV{CC} -Wa,-v -c -o /dev/null -x assembler /dev/null 2>&1`
=~ /GNU assembler version ([2-9]\.[0-9]+)/) {
$avx = ($1>=2.19) + ($1>=2.22);
}
if (!$avx && $win64 && ($flavour =~ /nasm/ || $ENV{ASM} =~ /nasm/) &&
`nasm -v 2>&1` =~ /NASM version ([2-9]\.[0-9]+)/) {
$avx = ($1>=2.09) + ($1>=2.10);
}
if (!$avx && $win64 && ($flavour =~ /masm/ || $ENV{ASM} =~ /ml64/) &&
`ml64 2>&1` =~ /Version ([0-9]+)\./) {
$avx = ($1>=10) + ($1>=11);
}
if (!$avx && `$ENV{CC} -v 2>&1` =~ /((?:^clang|LLVM) version|.*based on LLVM) ([3-9]\.[0-9]+)/) {
$avx = ($2>=3.0) + ($2>3.0);
}
open OUT,"| \"$^X\" \"$xlate\" $flavour \"$output\"";
*STDOUT=*OUT;
# input parameter block
($out,$inp,$len,$key,$counter)=("%rdi","%rsi","%rdx","%rcx","%r8");
$code.=<<___;
.text
.extern OPENSSL_ia32cap_P
.align 64
.Lzero:
.long 0,0,0,0
.Lone:
.long 1,0,0,0
.Linc:
.long 0,1,2,3
.Lfour:
.long 4,4,4,4
.Lincy:
.long 0,2,4,6,1,3,5,7
.Leight:
.long 8,8,8,8,8,8,8,8
.Lrot16:
.byte 0x2,0x3,0x0,0x1, 0x6,0x7,0x4,0x5, 0xa,0xb,0x8,0x9, 0xe,0xf,0xc,0xd
.Lrot24:
.byte 0x3,0x0,0x1,0x2, 0x7,0x4,0x5,0x6, 0xb,0x8,0x9,0xa, 0xf,0xc,0xd,0xe
.Lsigma:
.asciz "expand 32-byte k"
.asciz "ChaCha20 for x86_64, CRYPTOGAMS by <appro\@openssl.org>"
___
sub AUTOLOAD() # thunk [simplified] 32-bit style perlasm
{ my $opcode = $AUTOLOAD; $opcode =~ s/.*:://;
my $arg = pop;
$arg = "\$$arg" if ($arg*1 eq $arg);
$code .= "\t$opcode\t".join(',',$arg,reverse @_)."\n";
}
@x=("%eax","%ebx","%ecx","%edx",map("%r${_}d",(8..11)),
"%nox","%nox","%nox","%nox",map("%r${_}d",(12..15)));
@t=("%esi","%edi");
sub ROUND { # critical path is 24 cycles per round
my ($a0,$b0,$c0,$d0)=@_;
my ($a1,$b1,$c1,$d1)=map(($_&~3)+(($_+1)&3),($a0,$b0,$c0,$d0));
my ($a2,$b2,$c2,$d2)=map(($_&~3)+(($_+1)&3),($a1,$b1,$c1,$d1));
my ($a3,$b3,$c3,$d3)=map(($_&~3)+(($_+1)&3),($a2,$b2,$c2,$d2));
my ($xc,$xc_)=map("\"$_\"",@t);
my @x=map("\"$_\"",@x);
# Consider order in which variables are addressed by their
# index:
#
# a b c d
#
# 0 4 8 12 < even round
# 1 5 9 13
# 2 6 10 14
# 3 7 11 15
# 0 5 10 15 < odd round
# 1 6 11 12
# 2 7 8 13
# 3 4 9 14
#
# 'a', 'b' and 'd's are permanently allocated in registers,
# @x[0..7,12..15], while 'c's are maintained in memory. If
# you observe 'c' column, you'll notice that pair of 'c's is
# invariant between rounds. This means that we have to reload
# them once per round, in the middle. This is why you'll see
# bunch of 'c' stores and loads in the middle, but none in
# the beginning or end.
# Normally instructions would be interleaved to favour in-order
# execution. Generally out-of-order cores manage it gracefully,
# but not this time for some reason. As in-order execution
# cores are dying breed, old Atom is the only one around,
# instructions are left uninterleaved. Besides, Atom is better
# off executing 1xSSSE3 code anyway...
(
"&add (@x[$a0],@x[$b0])", # Q1
"&xor (@x[$d0],@x[$a0])",
"&rol (@x[$d0],16)",
"&add (@x[$a1],@x[$b1])", # Q2
"&xor (@x[$d1],@x[$a1])",
"&rol (@x[$d1],16)",
"&add ($xc,@x[$d0])",
"&xor (@x[$b0],$xc)",
"&rol (@x[$b0],12)",
"&add ($xc_,@x[$d1])",
"&xor (@x[$b1],$xc_)",
"&rol (@x[$b1],12)",
"&add (@x[$a0],@x[$b0])",
"&xor (@x[$d0],@x[$a0])",
"&rol (@x[$d0],8)",
"&add (@x[$a1],@x[$b1])",
"&xor (@x[$d1],@x[$a1])",
"&rol (@x[$d1],8)",
"&add ($xc,@x[$d0])",
"&xor (@x[$b0],$xc)",
"&rol (@x[$b0],7)",
"&add ($xc_,@x[$d1])",
"&xor (@x[$b1],$xc_)",
"&rol (@x[$b1],7)",
"&mov (\"4*$c0(%rsp)\",$xc)", # reload pair of 'c's
"&mov (\"4*$c1(%rsp)\",$xc_)",
"&mov ($xc,\"4*$c2(%rsp)\")",
"&mov ($xc_,\"4*$c3(%rsp)\")",
"&add (@x[$a2],@x[$b2])", # Q3
"&xor (@x[$d2],@x[$a2])",
"&rol (@x[$d2],16)",
"&add (@x[$a3],@x[$b3])", # Q4
"&xor (@x[$d3],@x[$a3])",
"&rol (@x[$d3],16)",
"&add ($xc,@x[$d2])",
"&xor (@x[$b2],$xc)",
"&rol (@x[$b2],12)",
"&add ($xc_,@x[$d3])",
"&xor (@x[$b3],$xc_)",
"&rol (@x[$b3],12)",
"&add (@x[$a2],@x[$b2])",
"&xor (@x[$d2],@x[$a2])",
"&rol (@x[$d2],8)",
"&add (@x[$a3],@x[$b3])",
"&xor (@x[$d3],@x[$a3])",
"&rol (@x[$d3],8)",
"&add ($xc,@x[$d2])",
"&xor (@x[$b2],$xc)",
"&rol (@x[$b2],7)",
"&add ($xc_,@x[$d3])",
"&xor (@x[$b3],$xc_)",
"&rol (@x[$b3],7)"
);
}
########################################################################
# Generic code path that handles all lengths on pre-SSSE3 processors.
$code.=<<___;
.globl ChaCha20_ctr32
.type ChaCha20_ctr32,\@function,5
.align 64
ChaCha20_ctr32:
cmp \$0,$len
je .Lno_data
mov OPENSSL_ia32cap_P+4(%rip),%r10
test \$`1<<(41-32)`,%r10d
jnz .LChaCha20_ssse3
push %rbx
push %rbp
push %r12
push %r13
push %r14
push %r15
sub \$64+24,%rsp
#movdqa .Lsigma(%rip),%xmm0
movdqu ($key),%xmm1
movdqu 16($key),%xmm2
movdqu ($counter),%xmm3
movdqa .Lone(%rip),%xmm4
#movdqa %xmm0,4*0(%rsp) # key[0]
movdqa %xmm1,4*4(%rsp) # key[1]
movdqa %xmm2,4*8(%rsp) # key[2]
movdqa %xmm3,4*12(%rsp) # key[3]
mov $len,%rbp # reassign $len
jmp .Loop_outer
.align 32
.Loop_outer:
mov \$0x61707865,@x[0] # 'expa'
mov \$0x3320646e,@x[1] # 'nd 3'
mov \$0x79622d32,@x[2] # '2-by'
mov \$0x6b206574,@x[3] # 'te k'
mov 4*4(%rsp),@x[4]
mov 4*5(%rsp),@x[5]
mov 4*6(%rsp),@x[6]
mov 4*7(%rsp),@x[7]
movd %xmm3,@x[12]
mov 4*13(%rsp),@x[13]
mov 4*14(%rsp),@x[14]
mov 4*15(%rsp),@x[15]
mov %rbp,64+0(%rsp) # save len
mov \$10,%ebp
mov $inp,64+8(%rsp) # save inp
movq %xmm2,%rsi # "@x[8]"
mov $out,64+16(%rsp) # save out
mov %rsi,%rdi
shr \$32,%rdi # "@x[9]"
jmp .Loop
.align 32
.Loop:
___
foreach (&ROUND (0, 4, 8,12)) { eval; }
foreach (&ROUND (0, 5,10,15)) { eval; }
&dec ("%ebp");
&jnz (".Loop");
$code.=<<___;
mov @t[1],4*9(%rsp) # modulo-scheduled
mov @t[0],4*8(%rsp)
mov 64(%rsp),%rbp # load len
movdqa %xmm2,%xmm1
mov 64+8(%rsp),$inp # load inp
paddd %xmm4,%xmm3 # increment counter
mov 64+16(%rsp),$out # load out
add \$0x61707865,@x[0] # 'expa'
add \$0x3320646e,@x[1] # 'nd 3'
add \$0x79622d32,@x[2] # '2-by'
add \$0x6b206574,@x[3] # 'te k'
add 4*4(%rsp),@x[4]
add 4*5(%rsp),@x[5]
add 4*6(%rsp),@x[6]
add 4*7(%rsp),@x[7]
add 4*12(%rsp),@x[12]
add 4*13(%rsp),@x[13]
add 4*14(%rsp),@x[14]
add 4*15(%rsp),@x[15]
paddd 4*8(%rsp),%xmm1
cmp \$64,%rbp
jb .Ltail
xor 4*0($inp),@x[0] # xor with input
xor 4*1($inp),@x[1]
xor 4*2($inp),@x[2]
xor 4*3($inp),@x[3]
xor 4*4($inp),@x[4]
xor 4*5($inp),@x[5]
xor 4*6($inp),@x[6]
xor 4*7($inp),@x[7]
movdqu 4*8($inp),%xmm0
xor 4*12($inp),@x[12]
xor 4*13($inp),@x[13]
xor 4*14($inp),@x[14]
xor 4*15($inp),@x[15]
lea 4*16($inp),$inp # inp+=64
pxor %xmm1,%xmm0
movdqa %xmm2,4*8(%rsp)
movd %xmm3,4*12(%rsp)
mov @x[0],4*0($out) # write output
mov @x[1],4*1($out)
mov @x[2],4*2($out)
mov @x[3],4*3($out)
mov @x[4],4*4($out)
mov @x[5],4*5($out)
mov @x[6],4*6($out)
mov @x[7],4*7($out)
movdqu %xmm0,4*8($out)
mov @x[12],4*12($out)
mov @x[13],4*13($out)
mov @x[14],4*14($out)
mov @x[15],4*15($out)
lea 4*16($out),$out # out+=64
sub \$64,%rbp
jnz .Loop_outer
jmp .Ldone
.align 16
.Ltail:
mov @x[0],4*0(%rsp)
mov @x[1],4*1(%rsp)
xor %rbx,%rbx
mov @x[2],4*2(%rsp)
mov @x[3],4*3(%rsp)
mov @x[4],4*4(%rsp)
mov @x[5],4*5(%rsp)
mov @x[6],4*6(%rsp)
mov @x[7],4*7(%rsp)
movdqa %xmm1,4*8(%rsp)
mov @x[12],4*12(%rsp)
mov @x[13],4*13(%rsp)
mov @x[14],4*14(%rsp)
mov @x[15],4*15(%rsp)
.Loop_tail:
movzb ($inp,%rbx),%eax
movzb (%rsp,%rbx),%edx
lea 1(%rbx),%rbx
xor %edx,%eax
mov %al,-1($out,%rbx)
dec %rbp
jnz .Loop_tail
.Ldone:
add \$64+24,%rsp
pop %r15
pop %r14
pop %r13
pop %r12
pop %rbp
pop %rbx
.Lno_data:
ret
.size ChaCha20_ctr32,.-ChaCha20_ctr32
___
########################################################################
# SSSE3 code path that handles shorter lengths
{
my ($a,$b,$c,$d,$t,$t1,$rot16,$rot24)=map("%xmm$_",(0..7));
sub SSSE3ROUND { # critical path is 20 "SIMD ticks" per round
&paddd ($a,$b);
&pxor ($d,$a);
&pshufb ($d,$rot16);
&paddd ($c,$d);
&pxor ($b,$c);
&movdqa ($t,$b);
&psrld ($b,20);
&pslld ($t,12);
&por ($b,$t);
&paddd ($a,$b);
&pxor ($d,$a);
&pshufb ($d,$rot24);
&paddd ($c,$d);
&pxor ($b,$c);
&movdqa ($t,$b);
&psrld ($b,25);
&pslld ($t,7);
&por ($b,$t);
}
my $xframe = $win64 ? 32+32+8 : 24;
$code.=<<___;
.type ChaCha20_ssse3,\@function,5
.align 32
ChaCha20_ssse3:
.LChaCha20_ssse3:
___
$code.=<<___ if ($avx);
test \$`1<<(43-32)`,%r10d
jnz .LChaCha20_4xop # XOP is fastest even if we use 1/4
___
$code.=<<___;
cmp \$128,$len # we might throw away some data,
ja .LChaCha20_4x # but overall it won't be slower
.Ldo_sse3_after_all:
push %rbx
push %rbp
push %r12
push %r13
push %r14
push %r15
sub \$64+$xframe,%rsp
___
$code.=<<___ if ($win64);
movaps %xmm6,64+32(%rsp)
movaps %xmm7,64+48(%rsp)
___
$code.=<<___;
movdqa .Lsigma(%rip),$a
movdqu ($key),$b
movdqu 16($key),$c
movdqu ($counter),$d
movdqa .Lrot16(%rip),$rot16
movdqa .Lrot24(%rip),$rot24
movdqa $a,0x00(%rsp)
movdqa $b,0x10(%rsp)
movdqa $c,0x20(%rsp)
movdqa $d,0x30(%rsp)
mov \$10,%ebp
jmp .Loop_ssse3
.align 32
.Loop_outer_ssse3:
movdqa .Lone(%rip),$d
movdqa 0x00(%rsp),$a
movdqa 0x10(%rsp),$b
movdqa 0x20(%rsp),$c
paddd 0x30(%rsp),$d
mov \$10,%ebp
movdqa $d,0x30(%rsp)
jmp .Loop_ssse3
.align 32
.Loop_ssse3:
___
&SSSE3ROUND();
&pshufd ($c,$c,0b01001110);
&pshufd ($b,$b,0b00111001);
&pshufd ($d,$d,0b10010011);
&nop ();
&SSSE3ROUND();
&pshufd ($c,$c,0b01001110);
&pshufd ($b,$b,0b10010011);
&pshufd ($d,$d,0b00111001);
&dec ("%ebp");
&jnz (".Loop_ssse3");
$code.=<<___;
paddd 0x00(%rsp),$a
paddd 0x10(%rsp),$b
paddd 0x20(%rsp),$c
paddd 0x30(%rsp),$d
cmp \$64,$len
jb .Ltail_ssse3
movdqu 0x00($inp),$t
movdqu 0x10($inp),$t1
pxor $t,$a # xor with input
movdqu 0x20($inp),$t
pxor $t1,$b
movdqu 0x30($inp),$t1
lea 0x40($inp),$inp # inp+=64
pxor $t,$c
pxor $t1,$d
movdqu $a,0x00($out) # write output
movdqu $b,0x10($out)
movdqu $c,0x20($out)
movdqu $d,0x30($out)
lea 0x40($out),$out # out+=64
sub \$64,$len
jnz .Loop_outer_ssse3
jmp .Ldone_ssse3
.align 16
.Ltail_ssse3:
movdqa $a,0x00(%rsp)
movdqa $b,0x10(%rsp)
movdqa $c,0x20(%rsp)
movdqa $d,0x30(%rsp)
xor %rbx,%rbx
.Loop_tail_ssse3:
movzb ($inp,%rbx),%eax
movzb (%rsp,%rbx),%ecx
lea 1(%rbx),%rbx
xor %ecx,%eax
mov %al,-1($out,%rbx)
dec $len
jnz .Loop_tail_ssse3
.Ldone_ssse3:
___
$code.=<<___ if ($win64);
movaps 64+32(%rsp),%xmm6
movaps 64+48(%rsp),%xmm7
___
$code.=<<___;
add \$64+$xframe,%rsp
pop %r15
pop %r14
pop %r13
pop %r12
pop %rbp
pop %rbx
ret
.size ChaCha20_ssse3,.-ChaCha20_ssse3
___
}
########################################################################
# SSSE3 code path that handles longer messages.
{
# assign variables to favor Atom front-end
my ($xd0,$xd1,$xd2,$xd3, $xt0,$xt1,$xt2,$xt3,
$xa0,$xa1,$xa2,$xa3, $xb0,$xb1,$xb2,$xb3)=map("%xmm$_",(0..15));
my @xx=($xa0,$xa1,$xa2,$xa3, $xb0,$xb1,$xb2,$xb3,
"%nox","%nox","%nox","%nox", $xd0,$xd1,$xd2,$xd3);
sub SSSE3_lane_ROUND {
my ($a0,$b0,$c0,$d0)=@_;
my ($a1,$b1,$c1,$d1)=map(($_&~3)+(($_+1)&3),($a0,$b0,$c0,$d0));
my ($a2,$b2,$c2,$d2)=map(($_&~3)+(($_+1)&3),($a1,$b1,$c1,$d1));
my ($a3,$b3,$c3,$d3)=map(($_&~3)+(($_+1)&3),($a2,$b2,$c2,$d2));
my ($xc,$xc_,$t0,$t1)=map("\"$_\"",$xt0,$xt1,$xt2,$xt3);
my @x=map("\"$_\"",@xx);
# Consider order in which variables are addressed by their
# index:
#
# a b c d
#
# 0 4 8 12 < even round
# 1 5 9 13
# 2 6 10 14
# 3 7 11 15
# 0 5 10 15 < odd round
# 1 6 11 12
# 2 7 8 13
# 3 4 9 14
#
# 'a', 'b' and 'd's are permanently allocated in registers,
# @x[0..7,12..15], while 'c's are maintained in memory. If
# you observe 'c' column, you'll notice that pair of 'c's is
# invariant between rounds. This means that we have to reload
# them once per round, in the middle. This is why you'll see
# bunch of 'c' stores and loads in the middle, but none in
# the beginning or end.
(
"&paddd (@x[$a0],@x[$b0])", # Q1
"&paddd (@x[$a1],@x[$b1])", # Q2
"&pxor (@x[$d0],@x[$a0])",
"&pxor (@x[$d1],@x[$a1])",
"&pshufb (@x[$d0],$t1)",
"&pshufb (@x[$d1],$t1)",
"&paddd ($xc,@x[$d0])",
"&paddd ($xc_,@x[$d1])",
"&pxor (@x[$b0],$xc)",
"&pxor (@x[$b1],$xc_)",
"&movdqa ($t0,@x[$b0])",
"&pslld (@x[$b0],12)",
"&psrld ($t0,20)",
"&movdqa ($t1,@x[$b1])",
"&pslld (@x[$b1],12)",
"&por (@x[$b0],$t0)",
"&psrld ($t1,20)",
"&movdqa ($t0,'(%r11)')", # .Lrot24(%rip)
"&por (@x[$b1],$t1)",
"&paddd (@x[$a0],@x[$b0])",
"&paddd (@x[$a1],@x[$b1])",
"&pxor (@x[$d0],@x[$a0])",
"&pxor (@x[$d1],@x[$a1])",
"&pshufb (@x[$d0],$t0)",
"&pshufb (@x[$d1],$t0)",
"&paddd ($xc,@x[$d0])",
"&paddd ($xc_,@x[$d1])",
"&pxor (@x[$b0],$xc)",
"&pxor (@x[$b1],$xc_)",
"&movdqa ($t1,@x[$b0])",
"&pslld (@x[$b0],7)",
"&psrld ($t1,25)",
"&movdqa ($t0,@x[$b1])",
"&pslld (@x[$b1],7)",
"&por (@x[$b0],$t1)",
"&psrld ($t0,25)",
"&movdqa ($t1,'(%r10)')", # .Lrot16(%rip)
"&por (@x[$b1],$t0)",
"&movdqa (\"`16*($c0-8)`(%rsp)\",$xc)", # reload pair of 'c's
"&movdqa (\"`16*($c1-8)`(%rsp)\",$xc_)",
"&movdqa ($xc,\"`16*($c2-8)`(%rsp)\")",
"&movdqa ($xc_,\"`16*($c3-8)`(%rsp)\")",
"&paddd (@x[$a2],@x[$b2])", # Q3
"&paddd (@x[$a3],@x[$b3])", # Q4
"&pxor (@x[$d2],@x[$a2])",
"&pxor (@x[$d3],@x[$a3])",
"&pshufb (@x[$d2],$t1)",
"&pshufb (@x[$d3],$t1)",
"&paddd ($xc,@x[$d2])",
"&paddd ($xc_,@x[$d3])",
"&pxor (@x[$b2],$xc)",
"&pxor (@x[$b3],$xc_)",
"&movdqa ($t0,@x[$b2])",
"&pslld (@x[$b2],12)",
"&psrld ($t0,20)",
"&movdqa ($t1,@x[$b3])",
"&pslld (@x[$b3],12)",
"&por (@x[$b2],$t0)",
"&psrld ($t1,20)",
"&movdqa ($t0,'(%r11)')", # .Lrot24(%rip)
"&por (@x[$b3],$t1)",
"&paddd (@x[$a2],@x[$b2])",
"&paddd (@x[$a3],@x[$b3])",
"&pxor (@x[$d2],@x[$a2])",
"&pxor (@x[$d3],@x[$a3])",
"&pshufb (@x[$d2],$t0)",
"&pshufb (@x[$d3],$t0)",
"&paddd ($xc,@x[$d2])",
"&paddd ($xc_,@x[$d3])",
"&pxor (@x[$b2],$xc)",
"&pxor (@x[$b3],$xc_)",
"&movdqa ($t1,@x[$b2])",
"&pslld (@x[$b2],7)",
"&psrld ($t1,25)",
"&movdqa ($t0,@x[$b3])",
"&pslld (@x[$b3],7)",
"&por (@x[$b2],$t1)",
"&psrld ($t0,25)",
"&movdqa ($t1,'(%r10)')", # .Lrot16(%rip)
"&por (@x[$b3],$t0)"
);
}
my $xframe = $win64 ? 0xa0 : 0;
$code.=<<___;
.type ChaCha20_4x,\@function,5
.align 32
ChaCha20_4x:
.LChaCha20_4x:
mov %r10,%r11
___
$code.=<<___ if ($avx>1);
shr \$32,%r10 # OPENSSL_ia32cap_P+8
test \$`1<<5`,%r10 # test AVX2
jnz .LChaCha20_8x
___
$code.=<<___;
cmp \$192,$len
ja .Lproceed4x
and \$`1<<26|1<<22`,%r11 # isolate XSAVE+MOVBE
cmp \$`1<<22`,%r11 # check for MOVBE without XSAVE
je .Ldo_sse3_after_all # to detect Atom
.Lproceed4x:
lea -0x78(%rsp),%r11
sub \$0x148+$xframe,%rsp
___
################ stack layout
# +0x00 SIMD equivalent of @x[8-12]
# ...
# +0x40 constant copy of key[0-2] smashed by lanes
# ...
# +0x100 SIMD counters (with nonce smashed by lanes)
# ...
# +0x140
$code.=<<___ if ($win64);
movaps %xmm6,-0x30(%r11)
movaps %xmm7,-0x20(%r11)
movaps %xmm8,-0x10(%r11)
movaps %xmm9,0x00(%r11)
movaps %xmm10,0x10(%r11)
movaps %xmm11,0x20(%r11)
movaps %xmm12,0x30(%r11)
movaps %xmm13,0x40(%r11)
movaps %xmm14,0x50(%r11)
movaps %xmm15,0x60(%r11)
___
$code.=<<___;
movdqa .Lsigma(%rip),$xa3 # key[0]
movdqu ($key),$xb3 # key[1]
movdqu 16($key),$xt3 # key[2]
movdqu ($counter),$xd3 # key[3]
lea 0x100(%rsp),%rcx # size optimization
lea .Lrot16(%rip),%r10
lea .Lrot24(%rip),%r11
pshufd \$0x00,$xa3,$xa0 # smash key by lanes...
pshufd \$0x55,$xa3,$xa1
movdqa $xa0,0x40(%rsp) # ... and offload
pshufd \$0xaa,$xa3,$xa2
movdqa $xa1,0x50(%rsp)
pshufd \$0xff,$xa3,$xa3
movdqa $xa2,0x60(%rsp)
movdqa $xa3,0x70(%rsp)
pshufd \$0x00,$xb3,$xb0
pshufd \$0x55,$xb3,$xb1
movdqa $xb0,0x80-0x100(%rcx)
pshufd \$0xaa,$xb3,$xb2
movdqa $xb1,0x90-0x100(%rcx)
pshufd \$0xff,$xb3,$xb3
movdqa $xb2,0xa0-0x100(%rcx)
movdqa $xb3,0xb0-0x100(%rcx)
pshufd \$0x00,$xt3,$xt0 # "$xc0"
pshufd \$0x55,$xt3,$xt1 # "$xc1"
movdqa $xt0,0xc0-0x100(%rcx)
pshufd \$0xaa,$xt3,$xt2 # "$xc2"
movdqa $xt1,0xd0-0x100(%rcx)
pshufd \$0xff,$xt3,$xt3 # "$xc3"
movdqa $xt2,0xe0-0x100(%rcx)
movdqa $xt3,0xf0-0x100(%rcx)
pshufd \$0x00,$xd3,$xd0
pshufd \$0x55,$xd3,$xd1
paddd .Linc(%rip),$xd0 # don't save counters yet
pshufd \$0xaa,$xd3,$xd2
movdqa $xd1,0x110-0x100(%rcx)
pshufd \$0xff,$xd3,$xd3
movdqa $xd2,0x120-0x100(%rcx)
movdqa $xd3,0x130-0x100(%rcx)
jmp .Loop_enter4x
.align 32
.Loop_outer4x:
movdqa 0x40(%rsp),$xa0 # re-load smashed key
movdqa 0x50(%rsp),$xa1
movdqa 0x60(%rsp),$xa2
movdqa 0x70(%rsp),$xa3
movdqa 0x80-0x100(%rcx),$xb0
movdqa 0x90-0x100(%rcx),$xb1
movdqa 0xa0-0x100(%rcx),$xb2
movdqa 0xb0-0x100(%rcx),$xb3
movdqa 0xc0-0x100(%rcx),$xt0 # "$xc0"
movdqa 0xd0-0x100(%rcx),$xt1 # "$xc1"
movdqa 0xe0-0x100(%rcx),$xt2 # "$xc2"
movdqa 0xf0-0x100(%rcx),$xt3 # "$xc3"
movdqa 0x100-0x100(%rcx),$xd0
movdqa 0x110-0x100(%rcx),$xd1
movdqa 0x120-0x100(%rcx),$xd2
movdqa 0x130-0x100(%rcx),$xd3
paddd .Lfour(%rip),$xd0 # next SIMD counters
.Loop_enter4x:
movdqa $xt2,0x20(%rsp) # SIMD equivalent of "@x[10]"
movdqa $xt3,0x30(%rsp) # SIMD equivalent of "@x[11]"
movdqa (%r10),$xt3 # .Lrot16(%rip)
mov \$10,%eax
movdqa $xd0,0x100-0x100(%rcx) # save SIMD counters
jmp .Loop4x
.align 32
.Loop4x:
___
foreach (&SSSE3_lane_ROUND(0, 4, 8,12)) { eval; }
foreach (&SSSE3_lane_ROUND(0, 5,10,15)) { eval; }
$code.=<<___;
dec %eax
jnz .Loop4x
paddd 0x40(%rsp),$xa0 # accumulate key material
paddd 0x50(%rsp),$xa1
paddd 0x60(%rsp),$xa2
paddd 0x70(%rsp),$xa3
movdqa $xa0,$xt2 # "de-interlace" data
punpckldq $xa1,$xa0
movdqa $xa2,$xt3
punpckldq $xa3,$xa2
punpckhdq $xa1,$xt2
punpckhdq $xa3,$xt3
movdqa $xa0,$xa1
punpcklqdq $xa2,$xa0 # "a0"
movdqa $xt2,$xa3
punpcklqdq $xt3,$xt2 # "a2"
punpckhqdq $xa2,$xa1 # "a1"
punpckhqdq $xt3,$xa3 # "a3"
___
($xa2,$xt2)=($xt2,$xa2);
$code.=<<___;
paddd 0x80-0x100(%rcx),$xb0
paddd 0x90-0x100(%rcx),$xb1
paddd 0xa0-0x100(%rcx),$xb2
paddd 0xb0-0x100(%rcx),$xb3
movdqa $xa0,0x00(%rsp) # offload $xaN
movdqa $xa1,0x10(%rsp)
movdqa 0x20(%rsp),$xa0 # "xc2"
movdqa 0x30(%rsp),$xa1 # "xc3"
movdqa $xb0,$xt2
punpckldq $xb1,$xb0
movdqa $xb2,$xt3
punpckldq $xb3,$xb2
punpckhdq $xb1,$xt2
punpckhdq $xb3,$xt3
movdqa $xb0,$xb1
punpcklqdq $xb2,$xb0 # "b0"
movdqa $xt2,$xb3
punpcklqdq $xt3,$xt2 # "b2"
punpckhqdq $xb2,$xb1 # "b1"
punpckhqdq $xt3,$xb3 # "b3"
___
($xb2,$xt2)=($xt2,$xb2);
my ($xc0,$xc1,$xc2,$xc3)=($xt0,$xt1,$xa0,$xa1);
$code.=<<___;
paddd 0xc0-0x100(%rcx),$xc0
paddd 0xd0-0x100(%rcx),$xc1
paddd 0xe0-0x100(%rcx),$xc2
paddd 0xf0-0x100(%rcx),$xc3
movdqa $xa2,0x20(%rsp) # keep offloading $xaN
movdqa $xa3,0x30(%rsp)
movdqa $xc0,$xt2
punpckldq $xc1,$xc0
movdqa $xc2,$xt3
punpckldq $xc3,$xc2
punpckhdq $xc1,$xt2
punpckhdq $xc3,$xt3
movdqa $xc0,$xc1
punpcklqdq $xc2,$xc0 # "c0"
movdqa $xt2,$xc3
punpcklqdq $xt3,$xt2 # "c2"
punpckhqdq $xc2,$xc1 # "c1"
punpckhqdq $xt3,$xc3 # "c3"
___
($xc2,$xt2)=($xt2,$xc2);
($xt0,$xt1)=($xa2,$xa3); # use $xaN as temporary
$code.=<<___;
paddd 0x100-0x100(%rcx),$xd0
paddd 0x110-0x100(%rcx),$xd1
paddd 0x120-0x100(%rcx),$xd2
paddd 0x130-0x100(%rcx),$xd3
movdqa $xd0,$xt2
punpckldq $xd1,$xd0
movdqa $xd2,$xt3
punpckldq $xd3,$xd2
punpckhdq $xd1,$xt2
punpckhdq $xd3,$xt3
movdqa $xd0,$xd1
punpcklqdq $xd2,$xd0 # "d0"
movdqa $xt2,$xd3
punpcklqdq $xt3,$xt2 # "d2"
punpckhqdq $xd2,$xd1 # "d1"
punpckhqdq $xt3,$xd3 # "d3"
___
($xd2,$xt2)=($xt2,$xd2);
$code.=<<___;
cmp \$64*4,$len
jb .Ltail4x
movdqu 0x00($inp),$xt0 # xor with input
movdqu 0x10($inp),$xt1
movdqu 0x20($inp),$xt2
movdqu 0x30($inp),$xt3
pxor 0x00(%rsp),$xt0 # $xaN is offloaded, remember?
pxor $xb0,$xt1
pxor $xc0,$xt2
pxor $xd0,$xt3
movdqu $xt0,0x00($out)
movdqu 0x40($inp),$xt0
movdqu $xt1,0x10($out)
movdqu 0x50($inp),$xt1
movdqu $xt2,0x20($out)
movdqu 0x60($inp),$xt2
movdqu $xt3,0x30($out)
movdqu 0x70($inp),$xt3
lea 0x80($inp),$inp # size optimization
pxor 0x10(%rsp),$xt0
pxor $xb1,$xt1
pxor $xc1,$xt2
pxor $xd1,$xt3
movdqu $xt0,0x40($out)
movdqu 0x00($inp),$xt0
movdqu $xt1,0x50($out)
movdqu 0x10($inp),$xt1
movdqu $xt2,0x60($out)
movdqu 0x20($inp),$xt2
movdqu $xt3,0x70($out)
lea 0x80($out),$out # size optimization
movdqu 0x30($inp),$xt3
pxor 0x20(%rsp),$xt0
pxor $xb2,$xt1
pxor $xc2,$xt2
pxor $xd2,$xt3
movdqu $xt0,0x00($out)
movdqu 0x40($inp),$xt0
movdqu $xt1,0x10($out)
movdqu 0x50($inp),$xt1
movdqu $xt2,0x20($out)
movdqu 0x60($inp),$xt2
movdqu $xt3,0x30($out)
movdqu 0x70($inp),$xt3
lea 0x80($inp),$inp # inp+=64*4
pxor 0x30(%rsp),$xt0
pxor $xb3,$xt1
pxor $xc3,$xt2
pxor $xd3,$xt3
movdqu $xt0,0x40($out)
movdqu $xt1,0x50($out)
movdqu $xt2,0x60($out)
movdqu $xt3,0x70($out)
lea 0x80($out),$out # out+=64*4
sub \$64*4,$len
jnz .Loop_outer4x
jmp .Ldone4x
.Ltail4x:
cmp \$192,$len
jae .L192_or_more4x
cmp \$128,$len
jae .L128_or_more4x
cmp \$64,$len
jae .L64_or_more4x
#movdqa 0x00(%rsp),$xt0 # $xaN is offloaded, remember?
xor %r10,%r10
#movdqa $xt0,0x00(%rsp)
movdqa $xb0,0x10(%rsp)
movdqa $xc0,0x20(%rsp)
movdqa $xd0,0x30(%rsp)
jmp .Loop_tail4x
.align 32
.L64_or_more4x:
movdqu 0x00($inp),$xt0 # xor with input
movdqu 0x10($inp),$xt1
movdqu 0x20($inp),$xt2
movdqu 0x30($inp),$xt3
pxor 0x00(%rsp),$xt0 # $xaxN is offloaded, remember?
pxor $xb0,$xt1
pxor $xc0,$xt2
pxor $xd0,$xt3
movdqu $xt0,0x00($out)
movdqu $xt1,0x10($out)
movdqu $xt2,0x20($out)
movdqu $xt3,0x30($out)
je .Ldone4x
movdqa 0x10(%rsp),$xt0 # $xaN is offloaded, remember?
lea 0x40($inp),$inp # inp+=64*1
xor %r10,%r10
movdqa $xt0,0x00(%rsp)
movdqa $xb1,0x10(%rsp)
lea 0x40($out),$out # out+=64*1
movdqa $xc1,0x20(%rsp)
sub \$64,$len # len-=64*1
movdqa $xd1,0x30(%rsp)
jmp .Loop_tail4x
.align 32
.L128_or_more4x:
movdqu 0x00($inp),$xt0 # xor with input
movdqu 0x10($inp),$xt1
movdqu 0x20($inp),$xt2
movdqu 0x30($inp),$xt3
pxor 0x00(%rsp),$xt0 # $xaN is offloaded, remember?
pxor $xb0,$xt1
pxor $xc0,$xt2
pxor $xd0,$xt3
movdqu $xt0,0x00($out)
movdqu 0x40($inp),$xt0
movdqu $xt1,0x10($out)
movdqu 0x50($inp),$xt1
movdqu $xt2,0x20($out)
movdqu 0x60($inp),$xt2
movdqu $xt3,0x30($out)
movdqu 0x70($inp),$xt3
pxor 0x10(%rsp),$xt0
pxor $xb1,$xt1
pxor $xc1,$xt2
pxor $xd1,$xt3
movdqu $xt0,0x40($out)
movdqu $xt1,0x50($out)
movdqu $xt2,0x60($out)
movdqu $xt3,0x70($out)
je .Ldone4x
movdqa 0x20(%rsp),$xt0 # $xaN is offloaded, remember?
lea 0x80($inp),$inp # inp+=64*2
xor %r10,%r10
movdqa $xt0,0x00(%rsp)
movdqa $xb2,0x10(%rsp)
lea 0x80($out),$out # out+=64*2
movdqa $xc2,0x20(%rsp)
sub \$128,$len # len-=64*2
movdqa $xd2,0x30(%rsp)
jmp .Loop_tail4x
.align 32
.L192_or_more4x:
movdqu 0x00($inp),$xt0 # xor with input
movdqu 0x10($inp),$xt1
movdqu 0x20($inp),$xt2
movdqu 0x30($inp),$xt3
pxor 0x00(%rsp),$xt0 # $xaN is offloaded, remember?
pxor $xb0,$xt1
pxor $xc0,$xt2
pxor $xd0,$xt3
movdqu $xt0,0x00($out)
movdqu 0x40($inp),$xt0
movdqu $xt1,0x10($out)
movdqu 0x50($inp),$xt1
movdqu $xt2,0x20($out)
movdqu 0x60($inp),$xt2
movdqu $xt3,0x30($out)
movdqu 0x70($inp),$xt3
lea 0x80($inp),$inp # size optimization
pxor 0x10(%rsp),$xt0
pxor $xb1,$xt1
pxor $xc1,$xt2
pxor $xd1,$xt3
movdqu $xt0,0x40($out)
movdqu 0x00($inp),$xt0
movdqu $xt1,0x50($out)
movdqu 0x10($inp),$xt1
movdqu $xt2,0x60($out)
movdqu 0x20($inp),$xt2
movdqu $xt3,0x70($out)
lea 0x80($out),$out # size optimization
movdqu 0x30($inp),$xt3
pxor 0x20(%rsp),$xt0
pxor $xb2,$xt1
pxor $xc2,$xt2
pxor $xd2,$xt3
movdqu $xt0,0x00($out)
movdqu $xt1,0x10($out)
movdqu $xt2,0x20($out)
movdqu $xt3,0x30($out)
je .Ldone4x
movdqa 0x30(%rsp),$xt0 # $xaN is offloaded, remember?
lea 0x40($inp),$inp # inp+=64*3
xor %r10,%r10
movdqa $xt0,0x00(%rsp)
movdqa $xb3,0x10(%rsp)
lea 0x40($out),$out # out+=64*3
movdqa $xc3,0x20(%rsp)
sub \$192,$len # len-=64*3
movdqa $xd3,0x30(%rsp)
.Loop_tail4x:
movzb ($inp,%r10),%eax
movzb (%rsp,%r10),%ecx
lea 1(%r10),%r10
xor %ecx,%eax
mov %al,-1($out,%r10)
dec $len
jnz .Loop_tail4x
.Ldone4x:
___
$code.=<<___ if ($win64);
lea 0x140+0x30(%rsp),%r11
movaps -0x30(%r11),%xmm6
movaps -0x20(%r11),%xmm7
movaps -0x10(%r11),%xmm8
movaps 0x00(%r11),%xmm9
movaps 0x10(%r11),%xmm10
movaps 0x20(%r11),%xmm11
movaps 0x30(%r11),%xmm12
movaps 0x40(%r11),%xmm13
movaps 0x50(%r11),%xmm14
movaps 0x60(%r11),%xmm15
___
$code.=<<___;
add \$0x148+$xframe,%rsp
ret
.size ChaCha20_4x,.-ChaCha20_4x
___
}
########################################################################
# XOP code path that handles all lengths.
if ($avx) {
# There is some "anomaly" observed depending on instructions' size or
# alignment. If you look closely at below code you'll notice that
# sometimes argument order varies. The order affects instruction
# encoding by making it larger, and such fiddling gives 5% performance
# improvement. This is on FX-4100...
my ($xb0,$xb1,$xb2,$xb3, $xd0,$xd1,$xd2,$xd3,
$xa0,$xa1,$xa2,$xa3, $xt0,$xt1,$xt2,$xt3)=map("%xmm$_",(0..15));
my @xx=($xa0,$xa1,$xa2,$xa3, $xb0,$xb1,$xb2,$xb3,
$xt0,$xt1,$xt2,$xt3, $xd0,$xd1,$xd2,$xd3);
sub XOP_lane_ROUND {
my ($a0,$b0,$c0,$d0)=@_;
my ($a1,$b1,$c1,$d1)=map(($_&~3)+(($_+1)&3),($a0,$b0,$c0,$d0));
my ($a2,$b2,$c2,$d2)=map(($_&~3)+(($_+1)&3),($a1,$b1,$c1,$d1));
my ($a3,$b3,$c3,$d3)=map(($_&~3)+(($_+1)&3),($a2,$b2,$c2,$d2));
my @x=map("\"$_\"",@xx);
(
"&vpaddd (@x[$a0],@x[$a0],@x[$b0])", # Q1
"&vpaddd (@x[$a1],@x[$a1],@x[$b1])", # Q2
"&vpaddd (@x[$a2],@x[$a2],@x[$b2])", # Q3
"&vpaddd (@x[$a3],@x[$a3],@x[$b3])", # Q4
"&vpxor (@x[$d0],@x[$a0],@x[$d0])",
"&vpxor (@x[$d1],@x[$a1],@x[$d1])",
"&vpxor (@x[$d2],@x[$a2],@x[$d2])",
"&vpxor (@x[$d3],@x[$a3],@x[$d3])",
"&vprotd (@x[$d0],@x[$d0],16)",
"&vprotd (@x[$d1],@x[$d1],16)",
"&vprotd (@x[$d2],@x[$d2],16)",
"&vprotd (@x[$d3],@x[$d3],16)",
"&vpaddd (@x[$c0],@x[$c0],@x[$d0])",
"&vpaddd (@x[$c1],@x[$c1],@x[$d1])",
"&vpaddd (@x[$c2],@x[$c2],@x[$d2])",
"&vpaddd (@x[$c3],@x[$c3],@x[$d3])",
"&vpxor (@x[$b0],@x[$c0],@x[$b0])",
"&vpxor (@x[$b1],@x[$c1],@x[$b1])",
"&vpxor (@x[$b2],@x[$b2],@x[$c2])", # flip
"&vpxor (@x[$b3],@x[$b3],@x[$c3])", # flip
"&vprotd (@x[$b0],@x[$b0],12)",
"&vprotd (@x[$b1],@x[$b1],12)",
"&vprotd (@x[$b2],@x[$b2],12)",
"&vprotd (@x[$b3],@x[$b3],12)",
"&vpaddd (@x[$a0],@x[$b0],@x[$a0])", # flip
"&vpaddd (@x[$a1],@x[$b1],@x[$a1])", # flip
"&vpaddd (@x[$a2],@x[$a2],@x[$b2])",
"&vpaddd (@x[$a3],@x[$a3],@x[$b3])",
"&vpxor (@x[$d0],@x[$a0],@x[$d0])",
"&vpxor (@x[$d1],@x[$a1],@x[$d1])",
"&vpxor (@x[$d2],@x[$a2],@x[$d2])",
"&vpxor (@x[$d3],@x[$a3],@x[$d3])",
"&vprotd (@x[$d0],@x[$d0],8)",
"&vprotd (@x[$d1],@x[$d1],8)",
"&vprotd (@x[$d2],@x[$d2],8)",
"&vprotd (@x[$d3],@x[$d3],8)",
"&vpaddd (@x[$c0],@x[$c0],@x[$d0])",
"&vpaddd (@x[$c1],@x[$c1],@x[$d1])",
"&vpaddd (@x[$c2],@x[$c2],@x[$d2])",
"&vpaddd (@x[$c3],@x[$c3],@x[$d3])",
"&vpxor (@x[$b0],@x[$c0],@x[$b0])",
"&vpxor (@x[$b1],@x[$c1],@x[$b1])",
"&vpxor (@x[$b2],@x[$b2],@x[$c2])", # flip
"&vpxor (@x[$b3],@x[$b3],@x[$c3])", # flip
"&vprotd (@x[$b0],@x[$b0],7)",
"&vprotd (@x[$b1],@x[$b1],7)",
"&vprotd (@x[$b2],@x[$b2],7)",
"&vprotd (@x[$b3],@x[$b3],7)"
);
}
my $xframe = $win64 ? 0xa0 : 0;
$code.=<<___;
.type ChaCha20_4xop,\@function,5
.align 32
ChaCha20_4xop:
.LChaCha20_4xop:
lea -0x78(%rsp),%r11
sub \$0x148+$xframe,%rsp
___
################ stack layout
# +0x00 SIMD equivalent of @x[8-12]
# ...
# +0x40 constant copy of key[0-2] smashed by lanes
# ...
# +0x100 SIMD counters (with nonce smashed by lanes)
# ...
# +0x140
$code.=<<___ if ($win64);
movaps %xmm6,-0x30(%r11)
movaps %xmm7,-0x20(%r11)
movaps %xmm8,-0x10(%r11)
movaps %xmm9,0x00(%r11)
movaps %xmm10,0x10(%r11)
movaps %xmm11,0x20(%r11)
movaps %xmm12,0x30(%r11)
movaps %xmm13,0x40(%r11)
movaps %xmm14,0x50(%r11)
movaps %xmm15,0x60(%r11)
___
$code.=<<___;
vzeroupper
vmovdqa .Lsigma(%rip),$xa3 # key[0]
vmovdqu ($key),$xb3 # key[1]
vmovdqu 16($key),$xt3 # key[2]
vmovdqu ($counter),$xd3 # key[3]
lea 0x100(%rsp),%rcx # size optimization
vpshufd \$0x00,$xa3,$xa0 # smash key by lanes...
vpshufd \$0x55,$xa3,$xa1
vmovdqa $xa0,0x40(%rsp) # ... and offload
vpshufd \$0xaa,$xa3,$xa2
vmovdqa $xa1,0x50(%rsp)
vpshufd \$0xff,$xa3,$xa3
vmovdqa $xa2,0x60(%rsp)
vmovdqa $xa3,0x70(%rsp)
vpshufd \$0x00,$xb3,$xb0
vpshufd \$0x55,$xb3,$xb1
vmovdqa $xb0,0x80-0x100(%rcx)
vpshufd \$0xaa,$xb3,$xb2
vmovdqa $xb1,0x90-0x100(%rcx)
vpshufd \$0xff,$xb3,$xb3
vmovdqa $xb2,0xa0-0x100(%rcx)
vmovdqa $xb3,0xb0-0x100(%rcx)
vpshufd \$0x00,$xt3,$xt0 # "$xc0"
vpshufd \$0x55,$xt3,$xt1 # "$xc1"
vmovdqa $xt0,0xc0-0x100(%rcx)
vpshufd \$0xaa,$xt3,$xt2 # "$xc2"
vmovdqa $xt1,0xd0-0x100(%rcx)
vpshufd \$0xff,$xt3,$xt3 # "$xc3"
vmovdqa $xt2,0xe0-0x100(%rcx)
vmovdqa $xt3,0xf0-0x100(%rcx)
vpshufd \$0x00,$xd3,$xd0
vpshufd \$0x55,$xd3,$xd1
vpaddd .Linc(%rip),$xd0,$xd0 # don't save counters yet
vpshufd \$0xaa,$xd3,$xd2
vmovdqa $xd1,0x110-0x100(%rcx)
vpshufd \$0xff,$xd3,$xd3
vmovdqa $xd2,0x120-0x100(%rcx)
vmovdqa $xd3,0x130-0x100(%rcx)
jmp .Loop_enter4xop
.align 32
.Loop_outer4xop:
vmovdqa 0x40(%rsp),$xa0 # re-load smashed key
vmovdqa 0x50(%rsp),$xa1
vmovdqa 0x60(%rsp),$xa2
vmovdqa 0x70(%rsp),$xa3
vmovdqa 0x80-0x100(%rcx),$xb0
vmovdqa 0x90-0x100(%rcx),$xb1
vmovdqa 0xa0-0x100(%rcx),$xb2
vmovdqa 0xb0-0x100(%rcx),$xb3
vmovdqa 0xc0-0x100(%rcx),$xt0 # "$xc0"
vmovdqa 0xd0-0x100(%rcx),$xt1 # "$xc1"
vmovdqa 0xe0-0x100(%rcx),$xt2 # "$xc2"
vmovdqa 0xf0-0x100(%rcx),$xt3 # "$xc3"
vmovdqa 0x100-0x100(%rcx),$xd0
vmovdqa 0x110-0x100(%rcx),$xd1
vmovdqa 0x120-0x100(%rcx),$xd2
vmovdqa 0x130-0x100(%rcx),$xd3
vpaddd .Lfour(%rip),$xd0,$xd0 # next SIMD counters
.Loop_enter4xop:
mov \$10,%eax
vmovdqa $xd0,0x100-0x100(%rcx) # save SIMD counters
jmp .Loop4xop
.align 32
.Loop4xop:
___
foreach (&XOP_lane_ROUND(0, 4, 8,12)) { eval; }
foreach (&XOP_lane_ROUND(0, 5,10,15)) { eval; }
$code.=<<___;
dec %eax
jnz .Loop4xop
vpaddd 0x40(%rsp),$xa0,$xa0 # accumulate key material
vpaddd 0x50(%rsp),$xa1,$xa1
vpaddd 0x60(%rsp),$xa2,$xa2
vpaddd 0x70(%rsp),$xa3,$xa3
vmovdqa $xt2,0x20(%rsp) # offload $xc2,3
vmovdqa $xt3,0x30(%rsp)
vpunpckldq $xa1,$xa0,$xt2 # "de-interlace" data
vpunpckldq $xa3,$xa2,$xt3
vpunpckhdq $xa1,$xa0,$xa0
vpunpckhdq $xa3,$xa2,$xa2
vpunpcklqdq $xt3,$xt2,$xa1 # "a0"
vpunpckhqdq $xt3,$xt2,$xt2 # "a1"
vpunpcklqdq $xa2,$xa0,$xa3 # "a2"
vpunpckhqdq $xa2,$xa0,$xa0 # "a3"
___
($xa0,$xa1,$xa2,$xa3,$xt2)=($xa1,$xt2,$xa3,$xa0,$xa2);
$code.=<<___;
vpaddd 0x80-0x100(%rcx),$xb0,$xb0
vpaddd 0x90-0x100(%rcx),$xb1,$xb1
vpaddd 0xa0-0x100(%rcx),$xb2,$xb2
vpaddd 0xb0-0x100(%rcx),$xb3,$xb3
vmovdqa $xa0,0x00(%rsp) # offload $xa0,1
vmovdqa $xa1,0x10(%rsp)
vmovdqa 0x20(%rsp),$xa0 # "xc2"
vmovdqa 0x30(%rsp),$xa1 # "xc3"
vpunpckldq $xb1,$xb0,$xt2
vpunpckldq $xb3,$xb2,$xt3
vpunpckhdq $xb1,$xb0,$xb0
vpunpckhdq $xb3,$xb2,$xb2
vpunpcklqdq $xt3,$xt2,$xb1 # "b0"
vpunpckhqdq $xt3,$xt2,$xt2 # "b1"
vpunpcklqdq $xb2,$xb0,$xb3 # "b2"
vpunpckhqdq $xb2,$xb0,$xb0 # "b3"
___
($xb0,$xb1,$xb2,$xb3,$xt2)=($xb1,$xt2,$xb3,$xb0,$xb2);
my ($xc0,$xc1,$xc2,$xc3)=($xt0,$xt1,$xa0,$xa1);
$code.=<<___;
vpaddd 0xc0-0x100(%rcx),$xc0,$xc0
vpaddd 0xd0-0x100(%rcx),$xc1,$xc1
vpaddd 0xe0-0x100(%rcx),$xc2,$xc2
vpaddd 0xf0-0x100(%rcx),$xc3,$xc3
vpunpckldq $xc1,$xc0,$xt2
vpunpckldq $xc3,$xc2,$xt3
vpunpckhdq $xc1,$xc0,$xc0
vpunpckhdq $xc3,$xc2,$xc2
vpunpcklqdq $xt3,$xt2,$xc1 # "c0"
vpunpckhqdq $xt3,$xt2,$xt2 # "c1"
vpunpcklqdq $xc2,$xc0,$xc3 # "c2"
vpunpckhqdq $xc2,$xc0,$xc0 # "c3"
___
($xc0,$xc1,$xc2,$xc3,$xt2)=($xc1,$xt2,$xc3,$xc0,$xc2);
$code.=<<___;
vpaddd 0x100-0x100(%rcx),$xd0,$xd0
vpaddd 0x110-0x100(%rcx),$xd1,$xd1
vpaddd 0x120-0x100(%rcx),$xd2,$xd2
vpaddd 0x130-0x100(%rcx),$xd3,$xd3
vpunpckldq $xd1,$xd0,$xt2
vpunpckldq $xd3,$xd2,$xt3
vpunpckhdq $xd1,$xd0,$xd0
vpunpckhdq $xd3,$xd2,$xd2
vpunpcklqdq $xt3,$xt2,$xd1 # "d0"
vpunpckhqdq $xt3,$xt2,$xt2 # "d1"
vpunpcklqdq $xd2,$xd0,$xd3 # "d2"
vpunpckhqdq $xd2,$xd0,$xd0 # "d3"
___
($xd0,$xd1,$xd2,$xd3,$xt2)=($xd1,$xt2,$xd3,$xd0,$xd2);
($xa0,$xa1)=($xt2,$xt3);
$code.=<<___;
vmovdqa 0x00(%rsp),$xa0 # restore $xa0,1
vmovdqa 0x10(%rsp),$xa1
cmp \$64*4,$len
jb .Ltail4xop
vpxor 0x00($inp),$xa0,$xa0 # xor with input
vpxor 0x10($inp),$xb0,$xb0
vpxor 0x20($inp),$xc0,$xc0
vpxor 0x30($inp),$xd0,$xd0
vpxor 0x40($inp),$xa1,$xa1
vpxor 0x50($inp),$xb1,$xb1
vpxor 0x60($inp),$xc1,$xc1
vpxor 0x70($inp),$xd1,$xd1
lea 0x80($inp),$inp # size optimization
vpxor 0x00($inp),$xa2,$xa2
vpxor 0x10($inp),$xb2,$xb2
vpxor 0x20($inp),$xc2,$xc2
vpxor 0x30($inp),$xd2,$xd2
vpxor 0x40($inp),$xa3,$xa3
vpxor 0x50($inp),$xb3,$xb3
vpxor 0x60($inp),$xc3,$xc3
vpxor 0x70($inp),$xd3,$xd3
lea 0x80($inp),$inp # inp+=64*4
vmovdqu $xa0,0x00($out)
vmovdqu $xb0,0x10($out)
vmovdqu $xc0,0x20($out)
vmovdqu $xd0,0x30($out)
vmovdqu $xa1,0x40($out)
vmovdqu $xb1,0x50($out)
vmovdqu $xc1,0x60($out)
vmovdqu $xd1,0x70($out)
lea 0x80($out),$out # size optimization
vmovdqu $xa2,0x00($out)
vmovdqu $xb2,0x10($out)
vmovdqu $xc2,0x20($out)
vmovdqu $xd2,0x30($out)
vmovdqu $xa3,0x40($out)
vmovdqu $xb3,0x50($out)
vmovdqu $xc3,0x60($out)
vmovdqu $xd3,0x70($out)
lea 0x80($out),$out # out+=64*4
sub \$64*4,$len
jnz .Loop_outer4xop
jmp .Ldone4xop
.align 32
.Ltail4xop:
cmp \$192,$len
jae .L192_or_more4xop
cmp \$128,$len
jae .L128_or_more4xop
cmp \$64,$len
jae .L64_or_more4xop
xor %r10,%r10
vmovdqa $xa0,0x00(%rsp)
vmovdqa $xb0,0x10(%rsp)
vmovdqa $xc0,0x20(%rsp)
vmovdqa $xd0,0x30(%rsp)
jmp .Loop_tail4xop
.align 32
.L64_or_more4xop:
vpxor 0x00($inp),$xa0,$xa0 # xor with input
vpxor 0x10($inp),$xb0,$xb0
vpxor 0x20($inp),$xc0,$xc0
vpxor 0x30($inp),$xd0,$xd0
vmovdqu $xa0,0x00($out)
vmovdqu $xb0,0x10($out)
vmovdqu $xc0,0x20($out)
vmovdqu $xd0,0x30($out)
je .Ldone4xop
lea 0x40($inp),$inp # inp+=64*1
vmovdqa $xa1,0x00(%rsp)
xor %r10,%r10
vmovdqa $xb1,0x10(%rsp)
lea 0x40($out),$out # out+=64*1
vmovdqa $xc1,0x20(%rsp)
sub \$64,$len # len-=64*1
vmovdqa $xd1,0x30(%rsp)
jmp .Loop_tail4xop
.align 32
.L128_or_more4xop:
vpxor 0x00($inp),$xa0,$xa0 # xor with input
vpxor 0x10($inp),$xb0,$xb0
vpxor 0x20($inp),$xc0,$xc0
vpxor 0x30($inp),$xd0,$xd0
vpxor 0x40($inp),$xa1,$xa1
vpxor 0x50($inp),$xb1,$xb1
vpxor 0x60($inp),$xc1,$xc1
vpxor 0x70($inp),$xd1,$xd1
vmovdqu $xa0,0x00($out)
vmovdqu $xb0,0x10($out)
vmovdqu $xc0,0x20($out)
vmovdqu $xd0,0x30($out)
vmovdqu $xa1,0x40($out)
vmovdqu $xb1,0x50($out)
vmovdqu $xc1,0x60($out)
vmovdqu $xd1,0x70($out)
je .Ldone4xop
lea 0x80($inp),$inp # inp+=64*2
vmovdqa $xa2,0x00(%rsp)
xor %r10,%r10
vmovdqa $xb2,0x10(%rsp)
lea 0x80($out),$out # out+=64*2
vmovdqa $xc2,0x20(%rsp)
sub \$128,$len # len-=64*2
vmovdqa $xd2,0x30(%rsp)
jmp .Loop_tail4xop
.align 32
.L192_or_more4xop:
vpxor 0x00($inp),$xa0,$xa0 # xor with input
vpxor 0x10($inp),$xb0,$xb0
vpxor 0x20($inp),$xc0,$xc0
vpxor 0x30($inp),$xd0,$xd0
vpxor 0x40($inp),$xa1,$xa1
vpxor 0x50($inp),$xb1,$xb1
vpxor 0x60($inp),$xc1,$xc1
vpxor 0x70($inp),$xd1,$xd1
lea 0x80($inp),$inp # size optimization
vpxor 0x00($inp),$xa2,$xa2
vpxor 0x10($inp),$xb2,$xb2
vpxor 0x20($inp),$xc2,$xc2
vpxor 0x30($inp),$xd2,$xd2
vmovdqu $xa0,0x00($out)
vmovdqu $xb0,0x10($out)
vmovdqu $xc0,0x20($out)
vmovdqu $xd0,0x30($out)
vmovdqu $xa1,0x40($out)
vmovdqu $xb1,0x50($out)
vmovdqu $xc1,0x60($out)
vmovdqu $xd1,0x70($out)
lea 0x80($out),$out # size optimization
vmovdqu $xa2,0x00($out)
vmovdqu $xb2,0x10($out)
vmovdqu $xc2,0x20($out)
vmovdqu $xd2,0x30($out)
je .Ldone4xop
lea 0x40($inp),$inp # inp+=64*3
vmovdqa $xa3,0x00(%rsp)
xor %r10,%r10
vmovdqa $xb3,0x10(%rsp)
lea 0x40($out),$out # out+=64*3
vmovdqa $xc3,0x20(%rsp)
sub \$192,$len # len-=64*3
vmovdqa $xd3,0x30(%rsp)
.Loop_tail4xop:
movzb ($inp,%r10),%eax
movzb (%rsp,%r10),%ecx
lea 1(%r10),%r10
xor %ecx,%eax
mov %al,-1($out,%r10)
dec $len
jnz .Loop_tail4xop
.Ldone4xop:
vzeroupper
___
$code.=<<___ if ($win64);
lea 0x140+0x30(%rsp),%r11
movaps -0x30(%r11),%xmm6
movaps -0x20(%r11),%xmm7
movaps -0x10(%r11),%xmm8
movaps 0x00(%r11),%xmm9
movaps 0x10(%r11),%xmm10
movaps 0x20(%r11),%xmm11
movaps 0x30(%r11),%xmm12
movaps 0x40(%r11),%xmm13
movaps 0x50(%r11),%xmm14
movaps 0x60(%r11),%xmm15
___
$code.=<<___;
add \$0x148+$xframe,%rsp
ret
.size ChaCha20_4xop,.-ChaCha20_4xop
___
}
########################################################################
# AVX2 code path
if ($avx>1) {
my ($xb0,$xb1,$xb2,$xb3, $xd0,$xd1,$xd2,$xd3,
$xa0,$xa1,$xa2,$xa3, $xt0,$xt1,$xt2,$xt3)=map("%ymm$_",(0..15));
my @xx=($xa0,$xa1,$xa2,$xa3, $xb0,$xb1,$xb2,$xb3,
"%nox","%nox","%nox","%nox", $xd0,$xd1,$xd2,$xd3);
sub AVX2_lane_ROUND {
my ($a0,$b0,$c0,$d0)=@_;
my ($a1,$b1,$c1,$d1)=map(($_&~3)+(($_+1)&3),($a0,$b0,$c0,$d0));
my ($a2,$b2,$c2,$d2)=map(($_&~3)+(($_+1)&3),($a1,$b1,$c1,$d1));
my ($a3,$b3,$c3,$d3)=map(($_&~3)+(($_+1)&3),($a2,$b2,$c2,$d2));
my ($xc,$xc_,$t0,$t1)=map("\"$_\"",$xt0,$xt1,$xt2,$xt3);
my @x=map("\"$_\"",@xx);
# Consider order in which variables are addressed by their
# index:
#
# a b c d
#
# 0 4 8 12 < even round
# 1 5 9 13
# 2 6 10 14
# 3 7 11 15
# 0 5 10 15 < odd round
# 1 6 11 12
# 2 7 8 13
# 3 4 9 14
#
# 'a', 'b' and 'd's are permanently allocated in registers,
# @x[0..7,12..15], while 'c's are maintained in memory. If
# you observe 'c' column, you'll notice that pair of 'c's is
# invariant between rounds. This means that we have to reload
# them once per round, in the middle. This is why you'll see
# bunch of 'c' stores and loads in the middle, but none in
# the beginning or end.
(
"&vpaddd (@x[$a0],@x[$a0],@x[$b0])", # Q1
"&vpxor (@x[$d0],@x[$a0],@x[$d0])",
"&vpshufb (@x[$d0],@x[$d0],$t1)",
"&vpaddd (@x[$a1],@x[$a1],@x[$b1])", # Q2
"&vpxor (@x[$d1],@x[$a1],@x[$d1])",
"&vpshufb (@x[$d1],@x[$d1],$t1)",
"&vpaddd ($xc,$xc,@x[$d0])",
"&vpxor (@x[$b0],$xc,@x[$b0])",
"&vpslld ($t0,@x[$b0],12)",
"&vpsrld (@x[$b0],@x[$b0],20)",
"&vpor (@x[$b0],$t0,@x[$b0])",
"&vbroadcasti128($t0,'(%r11)')", # .Lrot24(%rip)
"&vpaddd ($xc_,$xc_,@x[$d1])",
"&vpxor (@x[$b1],$xc_,@x[$b1])",
"&vpslld ($t1,@x[$b1],12)",
"&vpsrld (@x[$b1],@x[$b1],20)",
"&vpor (@x[$b1],$t1,@x[$b1])",
"&vpaddd (@x[$a0],@x[$a0],@x[$b0])",
"&vpxor (@x[$d0],@x[$a0],@x[$d0])",
"&vpshufb (@x[$d0],@x[$d0],$t0)",
"&vpaddd (@x[$a1],@x[$a1],@x[$b1])",
"&vpxor (@x[$d1],@x[$a1],@x[$d1])",
"&vpshufb (@x[$d1],@x[$d1],$t0)",
"&vpaddd ($xc,$xc,@x[$d0])",
"&vpxor (@x[$b0],$xc,@x[$b0])",
"&vpslld ($t1,@x[$b0],7)",
"&vpsrld (@x[$b0],@x[$b0],25)",
"&vpor (@x[$b0],$t1,@x[$b0])",
"&vbroadcasti128($t1,'(%r10)')", # .Lrot16(%rip)
"&vpaddd ($xc_,$xc_,@x[$d1])",
"&vpxor (@x[$b1],$xc_,@x[$b1])",
"&vpslld ($t0,@x[$b1],7)",
"&vpsrld (@x[$b1],@x[$b1],25)",
"&vpor (@x[$b1],$t0,@x[$b1])",
"&vmovdqa (\"`32*($c0-8)`(%rsp)\",$xc)", # reload pair of 'c's
"&vmovdqa (\"`32*($c1-8)`(%rsp)\",$xc_)",
"&vmovdqa ($xc,\"`32*($c2-8)`(%rsp)\")",
"&vmovdqa ($xc_,\"`32*($c3-8)`(%rsp)\")",
"&vpaddd (@x[$a2],@x[$a2],@x[$b2])", # Q3
"&vpxor (@x[$d2],@x[$a2],@x[$d2])",
"&vpshufb (@x[$d2],@x[$d2],$t1)",
"&vpaddd (@x[$a3],@x[$a3],@x[$b3])", # Q4
"&vpxor (@x[$d3],@x[$a3],@x[$d3])",
"&vpshufb (@x[$d3],@x[$d3],$t1)",
"&vpaddd ($xc,$xc,@x[$d2])",
"&vpxor (@x[$b2],$xc,@x[$b2])",
"&vpslld ($t0,@x[$b2],12)",
"&vpsrld (@x[$b2],@x[$b2],20)",
"&vpor (@x[$b2],$t0,@x[$b2])",
"&vbroadcasti128($t0,'(%r11)')", # .Lrot24(%rip)
"&vpaddd ($xc_,$xc_,@x[$d3])",
"&vpxor (@x[$b3],$xc_,@x[$b3])",
"&vpslld ($t1,@x[$b3],12)",
"&vpsrld (@x[$b3],@x[$b3],20)",
"&vpor (@x[$b3],$t1,@x[$b3])",
"&vpaddd (@x[$a2],@x[$a2],@x[$b2])",
"&vpxor (@x[$d2],@x[$a2],@x[$d2])",
"&vpshufb (@x[$d2],@x[$d2],$t0)",
"&vpaddd (@x[$a3],@x[$a3],@x[$b3])",
"&vpxor (@x[$d3],@x[$a3],@x[$d3])",
"&vpshufb (@x[$d3],@x[$d3],$t0)",
"&vpaddd ($xc,$xc,@x[$d2])",
"&vpxor (@x[$b2],$xc,@x[$b2])",
"&vpslld ($t1,@x[$b2],7)",
"&vpsrld (@x[$b2],@x[$b2],25)",
"&vpor (@x[$b2],$t1,@x[$b2])",
"&vbroadcasti128($t1,'(%r10)')", # .Lrot16(%rip)
"&vpaddd ($xc_,$xc_,@x[$d3])",
"&vpxor (@x[$b3],$xc_,@x[$b3])",
"&vpslld ($t0,@x[$b3],7)",
"&vpsrld (@x[$b3],@x[$b3],25)",
"&vpor (@x[$b3],$t0,@x[$b3])"
);
}
my $xframe = $win64 ? 0xb0 : 8;
$code.=<<___;
.type ChaCha20_8x,\@function,5
.align 32
ChaCha20_8x:
.LChaCha20_8x:
mov %rsp,%r10
sub \$0x280+$xframe,%rsp
and \$-32,%rsp
___
$code.=<<___ if ($win64);
lea 0x290+0x30(%rsp),%r11
movaps %xmm6,-0x30(%r11)
movaps %xmm7,-0x20(%r11)
movaps %xmm8,-0x10(%r11)
movaps %xmm9,0x00(%r11)
movaps %xmm10,0x10(%r11)
movaps %xmm11,0x20(%r11)
movaps %xmm12,0x30(%r11)
movaps %xmm13,0x40(%r11)
movaps %xmm14,0x50(%r11)
movaps %xmm15,0x60(%r11)
___
$code.=<<___;
vzeroupper
mov %r10,0x280(%rsp)
################ stack layout
# +0x00 SIMD equivalent of @x[8-12]
# ...
# +0x80 constant copy of key[0-2] smashed by lanes
# ...
# +0x200 SIMD counters (with nonce smashed by lanes)
# ...
# +0x280 saved %rsp
vbroadcasti128 .Lsigma(%rip),$xa3 # key[0]
vbroadcasti128 ($key),$xb3 # key[1]
vbroadcasti128 16($key),$xt3 # key[2]
vbroadcasti128 ($counter),$xd3 # key[3]
lea 0x100(%rsp),%rcx # size optimization
lea 0x200(%rsp),%rax # size optimization
lea .Lrot16(%rip),%r10
lea .Lrot24(%rip),%r11
vpshufd \$0x00,$xa3,$xa0 # smash key by lanes...
vpshufd \$0x55,$xa3,$xa1
vmovdqa $xa0,0x80-0x100(%rcx) # ... and offload
vpshufd \$0xaa,$xa3,$xa2
vmovdqa $xa1,0xa0-0x100(%rcx)
vpshufd \$0xff,$xa3,$xa3
vmovdqa $xa2,0xc0-0x100(%rcx)
vmovdqa $xa3,0xe0-0x100(%rcx)
vpshufd \$0x00,$xb3,$xb0
vpshufd \$0x55,$xb3,$xb1
vmovdqa $xb0,0x100-0x100(%rcx)
vpshufd \$0xaa,$xb3,$xb2
vmovdqa $xb1,0x120-0x100(%rcx)
vpshufd \$0xff,$xb3,$xb3
vmovdqa $xb2,0x140-0x100(%rcx)
vmovdqa $xb3,0x160-0x100(%rcx)
vpshufd \$0x00,$xt3,$xt0 # "xc0"
vpshufd \$0x55,$xt3,$xt1 # "xc1"
vmovdqa $xt0,0x180-0x200(%rax)
vpshufd \$0xaa,$xt3,$xt2 # "xc2"
vmovdqa $xt1,0x1a0-0x200(%rax)
vpshufd \$0xff,$xt3,$xt3 # "xc3"
vmovdqa $xt2,0x1c0-0x200(%rax)
vmovdqa $xt3,0x1e0-0x200(%rax)
vpshufd \$0x00,$xd3,$xd0
vpshufd \$0x55,$xd3,$xd1
vpaddd .Lincy(%rip),$xd0,$xd0 # don't save counters yet
vpshufd \$0xaa,$xd3,$xd2
vmovdqa $xd1,0x220-0x200(%rax)
vpshufd \$0xff,$xd3,$xd3
vmovdqa $xd2,0x240-0x200(%rax)
vmovdqa $xd3,0x260-0x200(%rax)
jmp .Loop_enter8x
.align 32
.Loop_outer8x:
vmovdqa 0x80-0x100(%rcx),$xa0 # re-load smashed key
vmovdqa 0xa0-0x100(%rcx),$xa1
vmovdqa 0xc0-0x100(%rcx),$xa2
vmovdqa 0xe0-0x100(%rcx),$xa3
vmovdqa 0x100-0x100(%rcx),$xb0
vmovdqa 0x120-0x100(%rcx),$xb1
vmovdqa 0x140-0x100(%rcx),$xb2
vmovdqa 0x160-0x100(%rcx),$xb3
vmovdqa 0x180-0x200(%rax),$xt0 # "xc0"
vmovdqa 0x1a0-0x200(%rax),$xt1 # "xc1"
vmovdqa 0x1c0-0x200(%rax),$xt2 # "xc2"
vmovdqa 0x1e0-0x200(%rax),$xt3 # "xc3"
vmovdqa 0x200-0x200(%rax),$xd0
vmovdqa 0x220-0x200(%rax),$xd1
vmovdqa 0x240-0x200(%rax),$xd2
vmovdqa 0x260-0x200(%rax),$xd3
vpaddd .Leight(%rip),$xd0,$xd0 # next SIMD counters
.Loop_enter8x:
vmovdqa $xt2,0x40(%rsp) # SIMD equivalent of "@x[10]"
vmovdqa $xt3,0x60(%rsp) # SIMD equivalent of "@x[11]"
vbroadcasti128 (%r10),$xt3
vmovdqa $xd0,0x200-0x200(%rax) # save SIMD counters
mov \$10,%eax
jmp .Loop8x
.align 32
.Loop8x:
___
foreach (&AVX2_lane_ROUND(0, 4, 8,12)) { eval; }
foreach (&AVX2_lane_ROUND(0, 5,10,15)) { eval; }
$code.=<<___;
dec %eax
jnz .Loop8x
lea 0x200(%rsp),%rax # size optimization
vpaddd 0x80-0x100(%rcx),$xa0,$xa0 # accumulate key
vpaddd 0xa0-0x100(%rcx),$xa1,$xa1
vpaddd 0xc0-0x100(%rcx),$xa2,$xa2
vpaddd 0xe0-0x100(%rcx),$xa3,$xa3
vpunpckldq $xa1,$xa0,$xt2 # "de-interlace" data
vpunpckldq $xa3,$xa2,$xt3
vpunpckhdq $xa1,$xa0,$xa0
vpunpckhdq $xa3,$xa2,$xa2
vpunpcklqdq $xt3,$xt2,$xa1 # "a0"
vpunpckhqdq $xt3,$xt2,$xt2 # "a1"
vpunpcklqdq $xa2,$xa0,$xa3 # "a2"
vpunpckhqdq $xa2,$xa0,$xa0 # "a3"
___
($xa0,$xa1,$xa2,$xa3,$xt2)=($xa1,$xt2,$xa3,$xa0,$xa2);
$code.=<<___;
vpaddd 0x100-0x100(%rcx),$xb0,$xb0
vpaddd 0x120-0x100(%rcx),$xb1,$xb1
vpaddd 0x140-0x100(%rcx),$xb2,$xb2
vpaddd 0x160-0x100(%rcx),$xb3,$xb3
vpunpckldq $xb1,$xb0,$xt2
vpunpckldq $xb3,$xb2,$xt3
vpunpckhdq $xb1,$xb0,$xb0
vpunpckhdq $xb3,$xb2,$xb2
vpunpcklqdq $xt3,$xt2,$xb1 # "b0"
vpunpckhqdq $xt3,$xt2,$xt2 # "b1"
vpunpcklqdq $xb2,$xb0,$xb3 # "b2"
vpunpckhqdq $xb2,$xb0,$xb0 # "b3"
___
($xb0,$xb1,$xb2,$xb3,$xt2)=($xb1,$xt2,$xb3,$xb0,$xb2);
$code.=<<___;
vperm2i128 \$0x20,$xb0,$xa0,$xt3 # "de-interlace" further
vperm2i128 \$0x31,$xb0,$xa0,$xb0
vperm2i128 \$0x20,$xb1,$xa1,$xa0
vperm2i128 \$0x31,$xb1,$xa1,$xb1
vperm2i128 \$0x20,$xb2,$xa2,$xa1
vperm2i128 \$0x31,$xb2,$xa2,$xb2
vperm2i128 \$0x20,$xb3,$xa3,$xa2
vperm2i128 \$0x31,$xb3,$xa3,$xb3
___
($xa0,$xa1,$xa2,$xa3,$xt3)=($xt3,$xa0,$xa1,$xa2,$xa3);
my ($xc0,$xc1,$xc2,$xc3)=($xt0,$xt1,$xa0,$xa1);
$code.=<<___;
vmovdqa $xa0,0x00(%rsp) # offload $xaN
vmovdqa $xa1,0x20(%rsp)
vmovdqa 0x40(%rsp),$xc2 # $xa0
vmovdqa 0x60(%rsp),$xc3 # $xa1
vpaddd 0x180-0x200(%rax),$xc0,$xc0
vpaddd 0x1a0-0x200(%rax),$xc1,$xc1
vpaddd 0x1c0-0x200(%rax),$xc2,$xc2
vpaddd 0x1e0-0x200(%rax),$xc3,$xc3
vpunpckldq $xc1,$xc0,$xt2
vpunpckldq $xc3,$xc2,$xt3
vpunpckhdq $xc1,$xc0,$xc0
vpunpckhdq $xc3,$xc2,$xc2
vpunpcklqdq $xt3,$xt2,$xc1 # "c0"
vpunpckhqdq $xt3,$xt2,$xt2 # "c1"
vpunpcklqdq $xc2,$xc0,$xc3 # "c2"
vpunpckhqdq $xc2,$xc0,$xc0 # "c3"
___
($xc0,$xc1,$xc2,$xc3,$xt2)=($xc1,$xt2,$xc3,$xc0,$xc2);
$code.=<<___;
vpaddd 0x200-0x200(%rax),$xd0,$xd0
vpaddd 0x220-0x200(%rax),$xd1,$xd1
vpaddd 0x240-0x200(%rax),$xd2,$xd2
vpaddd 0x260-0x200(%rax),$xd3,$xd3
vpunpckldq $xd1,$xd0,$xt2
vpunpckldq $xd3,$xd2,$xt3
vpunpckhdq $xd1,$xd0,$xd0
vpunpckhdq $xd3,$xd2,$xd2
vpunpcklqdq $xt3,$xt2,$xd1 # "d0"
vpunpckhqdq $xt3,$xt2,$xt2 # "d1"
vpunpcklqdq $xd2,$xd0,$xd3 # "d2"
vpunpckhqdq $xd2,$xd0,$xd0 # "d3"
___
($xd0,$xd1,$xd2,$xd3,$xt2)=($xd1,$xt2,$xd3,$xd0,$xd2);
$code.=<<___;
vperm2i128 \$0x20,$xd0,$xc0,$xt3 # "de-interlace" further
vperm2i128 \$0x31,$xd0,$xc0,$xd0
vperm2i128 \$0x20,$xd1,$xc1,$xc0
vperm2i128 \$0x31,$xd1,$xc1,$xd1
vperm2i128 \$0x20,$xd2,$xc2,$xc1
vperm2i128 \$0x31,$xd2,$xc2,$xd2
vperm2i128 \$0x20,$xd3,$xc3,$xc2
vperm2i128 \$0x31,$xd3,$xc3,$xd3
___
($xc0,$xc1,$xc2,$xc3,$xt3)=($xt3,$xc0,$xc1,$xc2,$xc3);
($xb0,$xb1,$xb2,$xb3,$xc0,$xc1,$xc2,$xc3)=
($xc0,$xc1,$xc2,$xc3,$xb0,$xb1,$xb2,$xb3);
($xa0,$xa1)=($xt2,$xt3);
$code.=<<___;
vmovdqa 0x00(%rsp),$xa0 # $xaN was offloaded, remember?
vmovdqa 0x20(%rsp),$xa1
cmp \$64*8,$len
jb .Ltail8x
vpxor 0x00($inp),$xa0,$xa0 # xor with input
vpxor 0x20($inp),$xb0,$xb0
vpxor 0x40($inp),$xc0,$xc0
vpxor 0x60($inp),$xd0,$xd0
lea 0x80($inp),$inp # size optimization
vmovdqu $xa0,0x00($out)
vmovdqu $xb0,0x20($out)
vmovdqu $xc0,0x40($out)
vmovdqu $xd0,0x60($out)
lea 0x80($out),$out # size optimization
vpxor 0x00($inp),$xa1,$xa1
vpxor 0x20($inp),$xb1,$xb1
vpxor 0x40($inp),$xc1,$xc1
vpxor 0x60($inp),$xd1,$xd1
lea 0x80($inp),$inp # size optimization
vmovdqu $xa1,0x00($out)
vmovdqu $xb1,0x20($out)
vmovdqu $xc1,0x40($out)
vmovdqu $xd1,0x60($out)
lea 0x80($out),$out # size optimization
vpxor 0x00($inp),$xa2,$xa2
vpxor 0x20($inp),$xb2,$xb2
vpxor 0x40($inp),$xc2,$xc2
vpxor 0x60($inp),$xd2,$xd2
lea 0x80($inp),$inp # size optimization
vmovdqu $xa2,0x00($out)
vmovdqu $xb2,0x20($out)
vmovdqu $xc2,0x40($out)
vmovdqu $xd2,0x60($out)
lea 0x80($out),$out # size optimization
vpxor 0x00($inp),$xa3,$xa3
vpxor 0x20($inp),$xb3,$xb3
vpxor 0x40($inp),$xc3,$xc3
vpxor 0x60($inp),$xd3,$xd3
lea 0x80($inp),$inp # size optimization
vmovdqu $xa3,0x00($out)
vmovdqu $xb3,0x20($out)
vmovdqu $xc3,0x40($out)
vmovdqu $xd3,0x60($out)
lea 0x80($out),$out # size optimization
sub \$64*8,$len
jnz .Loop_outer8x
jmp .Ldone8x
.Ltail8x:
cmp \$448,$len
jae .L448_or_more8x
cmp \$384,$len
jae .L384_or_more8x
cmp \$320,$len
jae .L320_or_more8x
cmp \$256,$len
jae .L256_or_more8x
cmp \$192,$len
jae .L192_or_more8x
cmp \$128,$len
jae .L128_or_more8x
cmp \$64,$len
jae .L64_or_more8x
xor %r10,%r10
vmovdqa $xa0,0x00(%rsp)
vmovdqa $xb0,0x20(%rsp)
jmp .Loop_tail8x
.align 32
.L64_or_more8x:
vpxor 0x00($inp),$xa0,$xa0 # xor with input
vpxor 0x20($inp),$xb0,$xb0
vmovdqu $xa0,0x00($out)
vmovdqu $xb0,0x20($out)
je .Ldone8x
lea 0x40($inp),$inp # inp+=64*1
xor %r10,%r10
vmovdqa $xc0,0x00(%rsp)
lea 0x40($out),$out # out+=64*1
sub \$64,$len # len-=64*1
vmovdqa $xd0,0x20(%rsp)
jmp .Loop_tail8x
.align 32
.L128_or_more8x:
vpxor 0x00($inp),$xa0,$xa0 # xor with input
vpxor 0x20($inp),$xb0,$xb0
vpxor 0x40($inp),$xc0,$xc0
vpxor 0x60($inp),$xd0,$xd0
vmovdqu $xa0,0x00($out)
vmovdqu $xb0,0x20($out)
vmovdqu $xc0,0x40($out)
vmovdqu $xd0,0x60($out)
je .Ldone8x
lea 0x80($inp),$inp # inp+=64*2
xor %r10,%r10
vmovdqa $xa1,0x00(%rsp)
lea 0x80($out),$out # out+=64*2
sub \$128,$len # len-=64*2
vmovdqa $xb1,0x20(%rsp)
jmp .Loop_tail8x
.align 32
.L192_or_more8x:
vpxor 0x00($inp),$xa0,$xa0 # xor with input
vpxor 0x20($inp),$xb0,$xb0
vpxor 0x40($inp),$xc0,$xc0
vpxor 0x60($inp),$xd0,$xd0
vpxor 0x80($inp),$xa1,$xa1
vpxor 0xa0($inp),$xb1,$xb1
vmovdqu $xa0,0x00($out)
vmovdqu $xb0,0x20($out)
vmovdqu $xc0,0x40($out)
vmovdqu $xd0,0x60($out)
vmovdqu $xa1,0x80($out)
vmovdqu $xb1,0xa0($out)
je .Ldone8x
lea 0xc0($inp),$inp # inp+=64*3
xor %r10,%r10
vmovdqa $xc1,0x00(%rsp)
lea 0xc0($out),$out # out+=64*3
sub \$192,$len # len-=64*3
vmovdqa $xd1,0x20(%rsp)
jmp .Loop_tail8x
.align 32
.L256_or_more8x:
vpxor 0x00($inp),$xa0,$xa0 # xor with input
vpxor 0x20($inp),$xb0,$xb0
vpxor 0x40($inp),$xc0,$xc0
vpxor 0x60($inp),$xd0,$xd0
vpxor 0x80($inp),$xa1,$xa1
vpxor 0xa0($inp),$xb1,$xb1
vpxor 0xc0($inp),$xc1,$xc1
vpxor 0xe0($inp),$xd1,$xd1
vmovdqu $xa0,0x00($out)
vmovdqu $xb0,0x20($out)
vmovdqu $xc0,0x40($out)
vmovdqu $xd0,0x60($out)
vmovdqu $xa1,0x80($out)
vmovdqu $xb1,0xa0($out)
vmovdqu $xc1,0xc0($out)
vmovdqu $xd1,0xe0($out)
je .Ldone8x
lea 0x100($inp),$inp # inp+=64*4
xor %r10,%r10
vmovdqa $xa2,0x00(%rsp)
lea 0x100($out),$out # out+=64*4
sub \$256,$len # len-=64*4
vmovdqa $xb2,0x20(%rsp)
jmp .Loop_tail8x
.align 32
.L320_or_more8x:
vpxor 0x00($inp),$xa0,$xa0 # xor with input
vpxor 0x20($inp),$xb0,$xb0
vpxor 0x40($inp),$xc0,$xc0
vpxor 0x60($inp),$xd0,$xd0
vpxor 0x80($inp),$xa1,$xa1
vpxor 0xa0($inp),$xb1,$xb1
vpxor 0xc0($inp),$xc1,$xc1
vpxor 0xe0($inp),$xd1,$xd1
vpxor 0x100($inp),$xa2,$xa2
vpxor 0x120($inp),$xb2,$xb2
vmovdqu $xa0,0x00($out)
vmovdqu $xb0,0x20($out)
vmovdqu $xc0,0x40($out)
vmovdqu $xd0,0x60($out)
vmovdqu $xa1,0x80($out)
vmovdqu $xb1,0xa0($out)
vmovdqu $xc1,0xc0($out)
vmovdqu $xd1,0xe0($out)
vmovdqu $xa2,0x100($out)
vmovdqu $xb2,0x120($out)
je .Ldone8x
lea 0x140($inp),$inp # inp+=64*5
xor %r10,%r10
vmovdqa $xc2,0x00(%rsp)
lea 0x140($out),$out # out+=64*5
sub \$320,$len # len-=64*5
vmovdqa $xd2,0x20(%rsp)
jmp .Loop_tail8x
.align 32
.L384_or_more8x:
vpxor 0x00($inp),$xa0,$xa0 # xor with input
vpxor 0x20($inp),$xb0,$xb0
vpxor 0x40($inp),$xc0,$xc0
vpxor 0x60($inp),$xd0,$xd0
vpxor 0x80($inp),$xa1,$xa1
vpxor 0xa0($inp),$xb1,$xb1
vpxor 0xc0($inp),$xc1,$xc1
vpxor 0xe0($inp),$xd1,$xd1
vpxor 0x100($inp),$xa2,$xa2
vpxor 0x120($inp),$xb2,$xb2
vpxor 0x140($inp),$xc2,$xc2
vpxor 0x160($inp),$xd2,$xd2
vmovdqu $xa0,0x00($out)
vmovdqu $xb0,0x20($out)
vmovdqu $xc0,0x40($out)
vmovdqu $xd0,0x60($out)
vmovdqu $xa1,0x80($out)
vmovdqu $xb1,0xa0($out)
vmovdqu $xc1,0xc0($out)
vmovdqu $xd1,0xe0($out)
vmovdqu $xa2,0x100($out)
vmovdqu $xb2,0x120($out)
vmovdqu $xc2,0x140($out)
vmovdqu $xd2,0x160($out)
je .Ldone8x
lea 0x180($inp),$inp # inp+=64*6
xor %r10,%r10
vmovdqa $xa3,0x00(%rsp)
lea 0x180($out),$out # out+=64*6
sub \$384,$len # len-=64*6
vmovdqa $xb3,0x20(%rsp)
jmp .Loop_tail8x
.align 32
.L448_or_more8x:
vpxor 0x00($inp),$xa0,$xa0 # xor with input
vpxor 0x20($inp),$xb0,$xb0
vpxor 0x40($inp),$xc0,$xc0
vpxor 0x60($inp),$xd0,$xd0
vpxor 0x80($inp),$xa1,$xa1
vpxor 0xa0($inp),$xb1,$xb1
vpxor 0xc0($inp),$xc1,$xc1
vpxor 0xe0($inp),$xd1,$xd1
vpxor 0x100($inp),$xa2,$xa2
vpxor 0x120($inp),$xb2,$xb2
vpxor 0x140($inp),$xc2,$xc2
vpxor 0x160($inp),$xd2,$xd2
vpxor 0x180($inp),$xa3,$xa3
vpxor 0x1a0($inp),$xb3,$xb3
vmovdqu $xa0,0x00($out)
vmovdqu $xb0,0x20($out)
vmovdqu $xc0,0x40($out)
vmovdqu $xd0,0x60($out)
vmovdqu $xa1,0x80($out)
vmovdqu $xb1,0xa0($out)
vmovdqu $xc1,0xc0($out)
vmovdqu $xd1,0xe0($out)
vmovdqu $xa2,0x100($out)
vmovdqu $xb2,0x120($out)
vmovdqu $xc2,0x140($out)
vmovdqu $xd2,0x160($out)
vmovdqu $xa3,0x180($out)
vmovdqu $xb3,0x1a0($out)
je .Ldone8x
lea 0x1c0($inp),$inp # inp+=64*7
xor %r10,%r10
vmovdqa $xc3,0x00(%rsp)
lea 0x1c0($out),$out # out+=64*7
sub \$448,$len # len-=64*7
vmovdqa $xd3,0x20(%rsp)
.Loop_tail8x:
movzb ($inp,%r10),%eax
movzb (%rsp,%r10),%ecx
lea 1(%r10),%r10
xor %ecx,%eax
mov %al,-1($out,%r10)
dec $len
jnz .Loop_tail8x
.Ldone8x:
vzeroall
___
$code.=<<___ if ($win64);
lea 0x290+0x30(%rsp),%r11
movaps -0x30(%r11),%xmm6
movaps -0x20(%r11),%xmm7
movaps -0x10(%r11),%xmm8
movaps 0x00(%r11),%xmm9
movaps 0x10(%r11),%xmm10
movaps 0x20(%r11),%xmm11
movaps 0x30(%r11),%xmm12
movaps 0x40(%r11),%xmm13
movaps 0x50(%r11),%xmm14
movaps 0x60(%r11),%xmm15
___
$code.=<<___;
mov 0x280(%rsp),%rsp
ret
.size ChaCha20_8x,.-ChaCha20_8x
___
}
foreach (split("\n",$code)) {
s/\`([^\`]*)\`/eval $1/geo;
s/%x#%y/%x/go;
print $_,"\n";
}
close STDOUT;
+17
View File
@@ -0,0 +1,17 @@
LIBS=../../libcrypto
SOURCE[../../libcrypto]={- $target{chacha_asm_src} -}
GENERATE[chacha-x86.s]=asm/chacha-x86.pl $(PERLASM_SCHEME) $(CFLAGS) $(LIB_CFLAGS) $(PROCESSOR)
GENERATE[chacha-x86_64.s]=asm/chacha-x86_64.pl $(PERLASM_SCHEME)
GENERATE[chacha-ppc.s]=asm/chacha-ppc.pl $(PERLASM_SCHEME)
GENERATE[chacha-armv4.S]=asm/chacha-armv4.pl $(PERLASM_SCHEME)
INCLUDE[chacha-armv4.o]=..
GENERATE[chacha-armv8.S]=asm/chacha-armv8.pl $(PERLASM_SCHEME)
INCLUDE[chacha-armv8.o]=..
BEGINRAW[Makefile(unix)]
##### CHACHA assembler implementations
{- $builddir -}/chacha-%.S: {- $sourcedir -}/asm/chacha-%.pl
CC="$(CC)" $(PERL) $< $(PERLASM_SCHEME) $@
ENDRAW[Makefile(unix)]
+121
View File
@@ -0,0 +1,121 @@
/*
* Copyright 2015-2016 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
*/
/* Adapted from the public domain code by D. Bernstein from SUPERCOP. */
#include <string.h>
#include "internal/chacha.h"
typedef unsigned int u32;
typedef unsigned char u8;
typedef union {
u32 u[16];
u8 c[64];
} chacha_buf;
# define ROTATE(v, n) (((v) << (n)) | ((v) >> (32 - (n))))
# define U32TO8_LITTLE(p, v) do { \
(p)[0] = (u8)(v >> 0); \
(p)[1] = (u8)(v >> 8); \
(p)[2] = (u8)(v >> 16); \
(p)[3] = (u8)(v >> 24); \
} while(0)
/* QUARTERROUND updates a, b, c, d with a ChaCha "quarter" round. */
# define QUARTERROUND(a,b,c,d) ( \
x[a] += x[b], x[d] = ROTATE((x[d] ^ x[a]),16), \
x[c] += x[d], x[b] = ROTATE((x[b] ^ x[c]),12), \
x[a] += x[b], x[d] = ROTATE((x[d] ^ x[a]), 8), \
x[c] += x[d], x[b] = ROTATE((x[b] ^ x[c]), 7) )
/* chacha_core performs 20 rounds of ChaCha on the input words in
* |input| and writes the 64 output bytes to |output|. */
static void chacha20_core(chacha_buf *output, const u32 input[16])
{
u32 x[16];
int i;
const union {
long one;
char little;
} is_endian = { 1 };
memcpy(x, input, sizeof(x));
for (i = 20; i > 0; i -= 2) {
QUARTERROUND(0, 4, 8, 12);
QUARTERROUND(1, 5, 9, 13);
QUARTERROUND(2, 6, 10, 14);
QUARTERROUND(3, 7, 11, 15);
QUARTERROUND(0, 5, 10, 15);
QUARTERROUND(1, 6, 11, 12);
QUARTERROUND(2, 7, 8, 13);
QUARTERROUND(3, 4, 9, 14);
}
if (is_endian.little) {
for (i = 0; i < 16; ++i)
output->u[i] = x[i] + input[i];
} else {
for (i = 0; i < 16; ++i)
U32TO8_LITTLE(output->c + 4 * i, (x[i] + input[i]));
}
}
void ChaCha20_ctr32(unsigned char *out, const unsigned char *inp,
size_t len, const unsigned int key[8],
const unsigned int counter[4])
{
u32 input[16];
chacha_buf buf;
size_t todo, i;
/* sigma constant "expand 32-byte k" in little-endian encoding */
input[0] = ((u32)'e') | ((u32)'x'<<8) | ((u32)'p'<<16) | ((u32)'a'<<24);
input[1] = ((u32)'n') | ((u32)'d'<<8) | ((u32)' '<<16) | ((u32)'3'<<24);
input[2] = ((u32)'2') | ((u32)'-'<<8) | ((u32)'b'<<16) | ((u32)'y'<<24);
input[3] = ((u32)'t') | ((u32)'e'<<8) | ((u32)' '<<16) | ((u32)'k'<<24);
input[4] = key[0];
input[5] = key[1];
input[6] = key[2];
input[7] = key[3];
input[8] = key[4];
input[9] = key[5];
input[10] = key[6];
input[11] = key[7];
input[12] = counter[0];
input[13] = counter[1];
input[14] = counter[2];
input[15] = counter[3];
while (len > 0) {
todo = sizeof(buf);
if (len < todo)
todo = len;
chacha20_core(&buf, input);
for (i = 0; i < todo; i++)
out[i] = inp[i] ^ buf.c[i];
out += todo;
inp += todo;
len -= todo;
/*
* Advance 32-bit counter. Note that as subroutine is so to
* say nonce-agnostic, this limited counter width doesn't
* prevent caller from implementing wider counter. It would
* simply take two calls split on counter overflow...
*/
input[12]++;
}
}