bsaes-armv7.pl 25.4 KB
Newer Older
1 2 3
#!/usr/bin/env perl

# ====================================================================
4
# Written by Andy Polyakov <appro@openssl.org> for the OpenSSL
5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
# 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/.
# ====================================================================

# Bit-sliced AES for ARM NEON
#
# February 2012.
#
# This implementation is direct adaptation of bsaes-x86_64 module for
# ARM NEON. Except that this module is endian-neutral [in sense that
# it can be compiled for either endianness] by courtesy of vld1.8's
# neutrality. Initial version doesn't implement interface to OpenSSL,
# only low-level primitives and unsupported entry points, just enough
# to collect performance results, which for Cortex-A8 core are:
#
21 22 23
# encrypt	19.5 cycles per byte processed with 128-bit key
# decrypt	24.0 cycles per byte processed with 128-bit key
# key conv.	440  cycles per 128-bit key/0.18 of 8x block
24
#
25 26 27
# Snapdragon S4 encrypts byte in 17.6 cycles and decrypts in 22.6,
# which is [much] worse than anticipated (for further details see
# http://www.openssl.org/~appro/Snapdragon-S4.html).
28
#
29
# When comparing to x86_64 results keep in mind that NEON unit is
30 31 32 33
# [mostly] single-issue and thus can't [fully] benefit from
# instruction-level parallelism. And when comparing to aes-armv4
# results keep in mind key schedule conversion overhead (see
# bsaes-x86_64.pl for further details)...
34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65
#
#						<appro@openssl.org>

while (($output=shift) && ($output!~/^\w[\w\-]*\.\w+$/)) {}
open STDOUT,">$output";

my ($inp,$out,$len,$key)=("r0","r1","r2","r3");
my @XMM=map("q$_",(0..15));

{
my ($key,$rounds,$const)=("r4","r5","r6");

sub Dlo()   { shift=~m|q([1]?[0-9])|?"d".($1*2):"";     }
sub Dhi()   { shift=~m|q([1]?[0-9])|?"d".($1*2+1):"";   }

sub Sbox {
# input in  lsb > [b0, b1, b2, b3, b4, b5, b6, b7] < msb
# output in lsb > [b0, b1, b4, b6, b3, b7, b2, b5] < msb
my @b=@_[0..7];
my @t=@_[8..11];
my @s=@_[12..15];
	&InBasisChange	(@b);
	&Inv_GF256	(@b[6,5,0,3,7,1,4,2],@t,@s);
	&OutBasisChange	(@b[7,1,4,2,6,5,0,3]);
}

sub InBasisChange {
# input in  lsb > [b0, b1, b2, b3, b4, b5, b6, b7] < msb
# output in lsb > [b6, b5, b0, b3, b7, b1, b4, b2] < msb 
my @b=@_[0..7];
$code.=<<___;
	veor	@b[2], @b[2], @b[1]
66
	veor	@b[5], @b[5], @b[6]
67 68 69 70 71 72 73 74 75 76 77
	veor	@b[3], @b[3], @b[0]
	veor	@b[6], @b[6], @b[2]
	veor	@b[5], @b[5], @b[0]

	veor	@b[6], @b[6], @b[3]
	veor	@b[3], @b[3], @b[7]
	veor	@b[7], @b[7], @b[5]
	veor	@b[3], @b[3], @b[4]
	veor	@b[4], @b[4], @b[5]

	veor	@b[2], @b[2], @b[7]
78
	veor	@b[3], @b[3], @b[1]
79 80 81 82 83 84 85 86 87 88 89 90
	veor	@b[1], @b[1], @b[5]
___
}

sub OutBasisChange {
# input in  lsb > [b0, b1, b2, b3, b4, b5, b6, b7] < msb
# output in lsb > [b6, b1, b2, b4, b7, b0, b3, b5] < msb
my @b=@_[0..7];
$code.=<<___;
	veor	@b[0], @b[0], @b[6]
	veor	@b[1], @b[1], @b[4]
	veor	@b[4], @b[4], @b[6]
91
	veor	@b[2], @b[2], @b[0]
92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114
	veor	@b[6], @b[6], @b[1]

	veor	@b[1], @b[1], @b[5]
	veor	@b[5], @b[5], @b[3]
	veor	@b[3], @b[3], @b[7]
	veor	@b[7], @b[7], @b[5]
	veor	@b[2], @b[2], @b[5]

	veor	@b[4], @b[4], @b[7]
___
}

sub InvSbox {
# input in lsb 	> [b0, b1, b2, b3, b4, b5, b6, b7] < msb
# output in lsb	> [b0, b1, b6, b4, b2, b7, b3, b5] < msb
my @b=@_[0..7];
my @t=@_[8..11];
my @s=@_[12..15];
	&InvInBasisChange	(@b);
	&Inv_GF256		(@b[5,1,2,6,3,7,0,4],@t,@s);
	&InvOutBasisChange	(@b[3,7,0,4,5,1,2,6]);
}

115
sub InvInBasisChange {		# OutBasisChange in reverse (with twist)
116 117
my @b=@_[5,1,2,6,3,7,0,4];
$code.=<<___
118
	 veor	@b[1], @b[1], @b[7]
119 120 121
	veor	@b[4], @b[4], @b[7]

	veor	@b[7], @b[7], @b[5]
122
	 veor	@b[1], @b[1], @b[3]
123 124 125 126 127
	veor	@b[2], @b[2], @b[5]
	veor	@b[3], @b[3], @b[7]

	veor	@b[6], @b[6], @b[1]
	veor	@b[2], @b[2], @b[0]
128
	 veor	@b[5], @b[5], @b[3]
129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159
	veor	@b[4], @b[4], @b[6]
	veor	@b[0], @b[0], @b[6]
	veor	@b[1], @b[1], @b[4]
___
}

sub InvOutBasisChange {		# InBasisChange in reverse
my @b=@_[2,5,7,3,6,1,0,4];
$code.=<<___;
	veor	@b[1], @b[1], @b[5]
	veor	@b[2], @b[2], @b[7]

	veor	@b[3], @b[3], @b[1]
	veor	@b[4], @b[4], @b[5]
	veor	@b[7], @b[7], @b[5]
	veor	@b[3], @b[3], @b[4]
	 veor 	@b[5], @b[5], @b[0]
	veor	@b[3], @b[3], @b[7]
	 veor	@b[6], @b[6], @b[2]
	 veor	@b[2], @b[2], @b[1]
	veor	@b[6], @b[6], @b[3]

	veor	@b[3], @b[3], @b[0]
	veor	@b[5], @b[5], @b[6]
___
}

sub Mul_GF4 {
#;*************************************************************
#;* Mul_GF4: Input x0-x1,y0-y1 Output x0-x1 Temp t0 (8) *
#;*************************************************************
160
my ($x0,$x1,$y0,$y1,$t0,$t1)=@_;
161 162 163 164
$code.=<<___;
	veor 	$t0, $y0, $y1
	vand	$t0, $t0, $x0
	veor	$x0, $x0, $x1
165
	vand	$t1, $x1, $y0
166
	vand	$x0, $x0, $y1
167 168
	veor	$x1, $t1, $t0
	veor	$x0, $x0, $t1
169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211
___
}

sub Mul_GF4_N {				# not used, see next subroutine
# multiply and scale by N
my ($x0,$x1,$y0,$y1,$t0)=@_;
$code.=<<___;
	veor	$t0, $y0, $y1
	vand	$t0, $t0, $x0
	veor	$x0, $x0, $x1
	vand	$x1, $x1, $y0
	vand	$x0, $x0, $y1
	veor	$x1, $x1, $x0
	veor	$x0, $x0, $t0
___
}

sub Mul_GF4_N_GF4 {
# interleaved Mul_GF4_N and Mul_GF4
my ($x0,$x1,$y0,$y1,$t0,
    $x2,$x3,$y2,$y3,$t1)=@_;
$code.=<<___;
	veor	$t0, $y0, $y1
	 veor 	$t1, $y2, $y3
	vand	$t0, $t0, $x0
	 vand	$t1, $t1, $x2
	veor	$x0, $x0, $x1
	 veor	$x2, $x2, $x3
	vand	$x1, $x1, $y0
	 vand	$x3, $x3, $y2
	vand	$x0, $x0, $y1
	 vand	$x2, $x2, $y3
	veor	$x1, $x1, $x0
	 veor	$x2, $x2, $x3
	veor	$x0, $x0, $t0
	 veor	$x3, $x3, $t1
___
}
sub Mul_GF16_2 {
my @x=@_[0..7];
my @y=@_[8..11];
my @t=@_[12..15];
$code.=<<___;
212 213
	veor	@t[0], @x[0], @x[2]
	veor	@t[1], @x[1], @x[3]
214
___
215
	&Mul_GF4  	(@x[0], @x[1], @y[0], @y[1], @t[2..3]);
216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236
$code.=<<___;
	veor	@y[0], @y[0], @y[2]
	veor	@y[1], @y[1], @y[3]
___
	Mul_GF4_N_GF4	(@t[0], @t[1], @y[0], @y[1], @t[3],
			 @x[2], @x[3], @y[2], @y[3], @t[2]);
$code.=<<___;
	veor	@x[0], @x[0], @t[0]
	veor	@x[2], @x[2], @t[0]
	veor	@x[1], @x[1], @t[1]
	veor	@x[3], @x[3], @t[1]

	veor	@t[0], @x[4], @x[6]
	veor	@t[1], @x[5], @x[7]
___
	&Mul_GF4_N_GF4	(@t[0], @t[1], @y[0], @y[1], @t[3],
			 @x[6], @x[7], @y[2], @y[3], @t[2]);
$code.=<<___;
	veor	@y[0], @y[0], @y[2]
	veor	@y[1], @y[1], @y[3]
___
237
	&Mul_GF4  	(@x[4], @x[5], @y[0], @y[1], @t[2..3]);
238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266
$code.=<<___;
	veor	@x[4], @x[4], @t[0]
	veor	@x[6], @x[6], @t[0]
	veor	@x[5], @x[5], @t[1]
	veor	@x[7], @x[7], @t[1]
___
}
sub Inv_GF256 {
#;********************************************************************
#;* Inv_GF256: Input x0-x7 Output x0-x7 Temp t0-t3,s0-s3 (144)       *
#;********************************************************************
my @x=@_[0..7];
my @t=@_[8..11];
my @s=@_[12..15];
# direct optimizations from hardware
$code.=<<___;
	veor	@t[3], @x[4], @x[6]
	veor	@t[2], @x[5], @x[7]
	veor	@t[1], @x[1], @x[3]
	veor	@s[1], @x[7], @x[6]
	 vmov	@t[0], @t[2]
	veor	@s[0], @x[0], @x[2]

	vorr	@t[2], @t[2], @t[1]
	veor	@s[3], @t[3], @t[0]
	vand	@s[2], @t[3], @s[0]
	vorr	@t[3], @t[3], @s[0]
	veor	@s[0], @s[0], @t[1]
	vand	@t[0], @t[0], @t[1]
267
	veor	@t[1], @x[3], @x[2]
268
	vand	@s[3], @s[3], @s[0]
269 270 271
	vand	@s[1], @s[1], @t[1]
	veor	@t[1], @x[4], @x[5]
	veor	@s[0], @x[1], @x[0]
272 273
	veor	@t[3], @t[3], @s[1]
	veor	@t[2], @t[2], @s[1]
274 275
	vand	@s[1], @t[1], @s[0]
	vorr	@t[1], @t[1], @s[0]
276
	veor	@t[3], @t[3], @s[3]
277
	veor	@t[0], @t[0], @s[1]
278 279 280 281
	veor	@t[2], @t[2], @s[2]
	veor	@t[1], @t[1], @s[3]
	veor	@t[0], @t[0], @s[2]
	vand	@s[0], @x[7], @x[3]
282
	veor	@t[1], @t[1], @s[2]
283 284 285 286 287 288
	vand	@s[1], @x[6], @x[2]
	vand	@s[2], @x[5], @x[1]
	vorr	@s[3], @x[4], @x[0]
	veor	@t[3], @t[3], @s[0]
	veor	@t[1], @t[1], @s[2]
	veor	@t[0], @t[0], @s[3]
289
	veor	@t[2], @t[2], @s[1]
290 291 292 293 294

	@ Inv_GF16 \t0, \t1, \t2, \t3, \s0, \s1, \s2, \s3

	@ new smaller inversion

295 296
	vand	@s[2], @t[3], @t[1]
	vmov	@s[0], @t[0]
297

298 299 300
	veor	@s[1], @t[2], @s[2]
	veor	@s[3], @t[0], @s[2]
	veor	@s[2], @t[0], @s[2]	@ @s[2]=@s[3]
301 302

	vbsl	@s[1], @t[1], @t[0]
303 304
	vbsl	@s[3], @t[3], @t[2]
	veor	@t[3], @t[3], @t[2]
305

306
	vbsl	@s[0], @s[1], @s[2]
307
	vbsl	@t[0], @s[2], @s[1]
308

309
	vand	@s[2], @s[0], @s[3]
310
	veor	@t[1], @t[1], @t[0]
311

312
	veor	@s[2], @s[2], @t[3]
313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384
___
# output in s3, s2, s1, t1

# Mul_GF16_2 \x0, \x1, \x2, \x3, \x4, \x5, \x6, \x7, \t2, \t3, \t0, \t1, \s0, \s1, \s2, \s3

# Mul_GF16_2 \x0, \x1, \x2, \x3, \x4, \x5, \x6, \x7, \s3, \s2, \s1, \t1, \s0, \t0, \t2, \t3
	&Mul_GF16_2(@x,@s[3,2,1],@t[1],@s[0],@t[0,2,3]);

### output msb > [x3,x2,x1,x0,x7,x6,x5,x4] < lsb
}

# AES linear components

sub ShiftRows {
my @x=@_[0..7];
my @t=@_[8..11];
my $mask=pop;
$code.=<<___;
	vldmia	$key!, {@t[0]-@t[3]}
	veor	@t[0], @t[0], @x[0]
	veor	@t[1], @t[1], @x[1]
	vtbl.8	`&Dlo(@x[0])`, {@t[0]}, `&Dlo($mask)`
	vtbl.8	`&Dhi(@x[0])`, {@t[0]}, `&Dhi($mask)`
	vldmia	$key!, {@t[0]}
	veor	@t[2], @t[2], @x[2]
	vtbl.8	`&Dlo(@x[1])`, {@t[1]}, `&Dlo($mask)`
	vtbl.8	`&Dhi(@x[1])`, {@t[1]}, `&Dhi($mask)`
	vldmia	$key!, {@t[1]}
	veor	@t[3], @t[3], @x[3]
	vtbl.8	`&Dlo(@x[2])`, {@t[2]}, `&Dlo($mask)`
	vtbl.8	`&Dhi(@x[2])`, {@t[2]}, `&Dhi($mask)`
	vldmia	$key!, {@t[2]}
	vtbl.8	`&Dlo(@x[3])`, {@t[3]}, `&Dlo($mask)`
	vtbl.8	`&Dhi(@x[3])`, {@t[3]}, `&Dhi($mask)`
	vldmia	$key!, {@t[3]}
	veor	@t[0], @t[0], @x[4]
	veor	@t[1], @t[1], @x[5]
	vtbl.8	`&Dlo(@x[4])`, {@t[0]}, `&Dlo($mask)`
	vtbl.8	`&Dhi(@x[4])`, {@t[0]}, `&Dhi($mask)`
	veor	@t[2], @t[2], @x[6]
	vtbl.8	`&Dlo(@x[5])`, {@t[1]}, `&Dlo($mask)`
	vtbl.8	`&Dhi(@x[5])`, {@t[1]}, `&Dhi($mask)`
	veor	@t[3], @t[3], @x[7]
	vtbl.8	`&Dlo(@x[6])`, {@t[2]}, `&Dlo($mask)`
	vtbl.8	`&Dhi(@x[6])`, {@t[2]}, `&Dhi($mask)`
	vtbl.8	`&Dlo(@x[7])`, {@t[3]}, `&Dlo($mask)`
	vtbl.8	`&Dhi(@x[7])`, {@t[3]}, `&Dhi($mask)`
___
}

sub MixColumns {
# modified to emit output in order suitable for feeding back to aesenc[last]
my @x=@_[0..7];
my @t=@_[8..15];
$code.=<<___;
	vext.8	@t[0], @x[0], @x[0], #12	@ x0 <<< 32
	vext.8	@t[1], @x[1], @x[1], #12
	 veor	@x[0], @x[0], @t[0]		@ x0 ^ (x0 <<< 32)
	vext.8	@t[2], @x[2], @x[2], #12
	 veor	@x[1], @x[1], @t[1]
	vext.8	@t[3], @x[3], @x[3], #12
	 veor	@x[2], @x[2], @t[2]
	vext.8	@t[4], @x[4], @x[4], #12
	 veor	@x[3], @x[3], @t[3]
	vext.8	@t[5], @x[5], @x[5], #12
	 veor	@x[4], @x[4], @t[4]
	vext.8	@t[6], @x[6], @x[6], #12
	 veor	@x[5], @x[5], @t[5]
	vext.8	@t[7], @x[7], @x[7], #12
	 veor	@x[6], @x[6], @t[6]

	veor	@t[1], @t[1], @x[0]
385
	 veor	@x[7], @x[7], @t[7]
386
	 vext.8	@x[0], @x[0], @x[0], #8		@ (x0 ^ (x0 <<< 32)) <<< 64)
387
	veor	@t[2], @t[2], @x[1]
388 389 390 391 392 393 394 395 396 397 398 399 400 401 402
	veor	@t[0], @t[0], @x[7]
	veor	@t[1], @t[1], @x[7]
	 vext.8	@x[1], @x[1], @x[1], #8
	veor	@t[5], @t[5], @x[4]
	 veor	@x[0], @x[0], @t[0]
	veor	@t[6], @t[6], @x[5]
	 veor	@x[1], @x[1], @t[1]
	 vext.8	@t[0], @x[4], @x[4], #8
	veor	@t[4], @t[4], @x[3]
	 vext.8	@t[1], @x[5], @x[5], #8
	veor	@t[7], @t[7], @x[6]
	 vext.8	@x[4], @x[3], @x[3], #8
	veor	@t[3], @t[3], @x[2]
	 vext.8	@x[5], @x[7], @x[7], #8
	veor	@t[4], @t[4], @x[7]
403 404
	 vext.8	@x[3], @x[6], @x[6], #8
	veor	@t[3], @t[3], @x[7]
405 406
	 vext.8	@x[6], @x[2], @x[2], #8
	veor	@x[7], @t[1], @t[5]
407
	veor	@x[2], @t[0], @t[4]
408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426

	veor	@x[4], @x[4], @t[3]
	veor	@x[5], @x[5], @t[7]
	veor	@x[3], @x[3], @t[6]
	 @ vmov	@x[2], @t[0]
	veor	@x[6], @x[6], @t[2]
	 @ vmov	@x[7], @t[1]
___
}

sub InvMixColumns {
my @x=@_[0..7];
my @t=@_[8..15];

$code.=<<___;
	@ multiplication by 0x0e
	vext.8	@t[7], @x[7], @x[7], #12
	vmov	@t[2], @x[2]
	veor	@x[2], @x[2], @x[5]		@ 2 5
427
	veor	@x[7], @x[7], @x[5]		@ 7 5
428 429 430 431 432 433 434 435
	vext.8	@t[0], @x[0], @x[0], #12
	vmov	@t[5], @x[5]
	veor	@x[5], @x[5], @x[0]		@ 5 0		[1]
	veor	@x[0], @x[0], @x[1]		@ 0 1
	vext.8	@t[1], @x[1], @x[1], #12
	veor	@x[1], @x[1], @x[2]		@ 1 25
	veor	@x[0], @x[0], @x[6]		@ 01 6		[2]
	vext.8	@t[3], @x[3], @x[3], #12
436
	veor	@x[1], @x[1], @x[3]		@ 125 3		[4]
437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455
	veor	@x[2], @x[2], @x[0]		@ 25 016	[3]
	veor	@x[3], @x[3], @x[7]		@ 3 75
	veor	@x[7], @x[7], @x[6]		@ 75 6		[0]
	vext.8	@t[6], @x[6], @x[6], #12
	vmov	@t[4], @x[4]
	veor	@x[6], @x[6], @x[4]		@ 6 4
	veor	@x[4], @x[4], @x[3]		@ 4 375		[6]
	veor	@x[3], @x[3], @x[7]		@ 375 756=36
	veor	@x[6], @x[6], @t[5]		@ 64 5		[7]
	veor	@x[3], @x[3], @t[2]		@ 36 2
	vext.8	@t[5], @t[5], @t[5], #12
	veor	@x[3], @x[3], @t[4]		@ 362 4		[5]
___
					my @y = @x[7,5,0,2,1,3,4,6];
$code.=<<___;
	@ multiplication by 0x0b
	veor	@y[1], @y[1], @y[0]
	veor	@y[0], @y[0], @t[0]
	vext.8	@t[2], @t[2], @t[2], #12
456
	veor	@y[1], @y[1], @t[1]
457
	veor	@y[0], @y[0], @t[5]
458
	vext.8	@t[4], @t[4], @t[4], #12
459 460 461 462 463
	veor	@y[1], @y[1], @t[6]
	veor	@y[0], @y[0], @t[7]
	veor	@t[7], @t[7], @t[6]		@ clobber t[7]

	veor	@y[3], @y[3], @t[0]
464
	 veor	@y[1], @y[1], @y[0]
465 466 467 468
	vext.8	@t[0], @t[0], @t[0], #12
	veor	@y[2], @y[2], @t[1]
	veor	@y[4], @y[4], @t[1]
	vext.8	@t[1], @t[1], @t[1], #12
469
	veor	@y[2], @y[2], @t[2]
470 471 472 473 474 475 476 477
	veor	@y[3], @y[3], @t[2]
	veor	@y[5], @y[5], @t[2]
	veor	@y[2], @y[2], @t[7]
	vext.8	@t[2], @t[2], @t[2], #12
	veor	@y[3], @y[3], @t[3]
	veor	@y[6], @y[6], @t[3]
	veor	@y[4], @y[4], @t[3]
	veor	@y[7], @y[7], @t[4]
478
	vext.8	@t[3], @t[3], @t[3], #12
479 480
	veor	@y[5], @y[5], @t[4]
	veor	@y[7], @y[7], @t[7]
481
	veor	@t[7], @t[7], @t[5]		@ clobber t[7] even more
482 483 484 485 486 487 488 489 490 491 492 493 494
	veor	@y[3], @y[3], @t[5]
	veor	@y[4], @y[4], @t[4]

	veor	@y[5], @y[5], @t[7]
	vext.8	@t[4], @t[4], @t[4], #12
	veor	@y[6], @y[6], @t[7]
	veor	@y[4], @y[4], @t[7]

	veor	@t[7], @t[7], @t[5]
	vext.8	@t[5], @t[5], @t[5], #12

	@ multiplication by 0x0d
	veor	@y[4], @y[4], @y[7]
495
	 veor	@t[7], @t[7], @t[6]		@ restore t[7]
496 497 498 499 500
	veor	@y[7], @y[7], @t[4]
	vext.8	@t[6], @t[6], @t[6], #12
	veor	@y[2], @y[2], @t[0]
	veor	@y[7], @y[7], @t[5]
	vext.8	@t[7], @t[7], @t[7], #12
501
	veor	@y[2], @y[2], @t[2]
502 503 504 505 506 507 508 509

	veor	@y[3], @y[3], @y[1]
	veor	@y[1], @y[1], @t[1]
	veor	@y[0], @y[0], @t[0]
	veor	@y[3], @y[3], @t[0]
	veor	@y[1], @y[1], @t[5]
	veor	@y[0], @y[0], @t[5]
	vext.8	@t[0], @t[0], @t[0], #12
510
	veor	@y[1], @y[1], @t[7]
511 512 513 514 515 516 517 518 519 520
	veor	@y[0], @y[0], @t[6]
	veor	@y[3], @y[3], @y[1]
	veor	@y[4], @y[4], @t[1]
	vext.8	@t[1], @t[1], @t[1], #12

	veor	@y[7], @y[7], @t[7]
	veor	@y[4], @y[4], @t[2]
	veor	@y[5], @y[5], @t[2]
	veor	@y[2], @y[2], @t[6]
	veor	@t[6], @t[6], @t[3]		@ clobber t[6]
521
	vext.8	@t[2], @t[2], @t[2], #12
522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549
	veor	@y[4], @y[4], @y[7]
	veor	@y[3], @y[3], @t[6]

	veor	@y[6], @y[6], @t[6]
	veor	@y[5], @y[5], @t[5]
	vext.8	@t[5], @t[5], @t[5], #12
	veor	@y[6], @y[6], @t[4]
	vext.8	@t[4], @t[4], @t[4], #12
	veor	@y[5], @y[5], @t[6]
	veor	@y[6], @y[6], @t[7]
	vext.8	@t[7], @t[7], @t[7], #12
	veor	@t[6], @t[6], @t[3]		@ restore t[6]
	vext.8	@t[3], @t[3], @t[3], #12

	@ multiplication by 0x09
	veor	@y[4], @y[4], @y[1]
	veor	@t[1], @t[1], @y[1]		@ t[1]=y[1]
	veor	@t[0], @t[0], @t[5]		@ clobber t[0]
	vext.8	@t[6], @t[6], @t[6], #12
	veor	@t[1], @t[1], @t[5]
	veor	@y[3], @y[3], @t[0]
	veor	@t[0], @t[0], @y[0]		@ t[0]=y[0]
	veor	@t[1], @t[1], @t[6]
	veor	@t[6], @t[6], @t[7]		@ clobber t[6]
	veor	@y[4], @y[4], @t[1]
	veor	@y[7], @y[7], @t[4]
	veor	@y[6], @y[6], @t[3]
	veor	@y[5], @y[5], @t[2]
550 551 552
	veor	@t[4], @t[4], @y[4]		@ t[4]=y[4]
	veor	@t[3], @t[3], @y[3]		@ t[3]=y[3]
	veor	@t[5], @t[5], @y[5]		@ t[5]=y[5]
553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825
	veor	@t[2], @t[2], @y[2]		@ t[2]=y[2]
	veor	@t[3], @t[3], @t[7]
	veor	@XMM[5], @t[5], @t[6]
	veor	@XMM[6], @t[6], @y[6]		@ t[6]=y[6]
	veor	@XMM[2], @t[2], @t[6]
	veor	@XMM[7], @t[7], @y[7]		@ t[7]=y[7]

	vmov	@XMM[0], @t[0]
	vmov	@XMM[1], @t[1]
	@ vmov	@XMM[2], @t[2]
	vmov	@XMM[3], @t[3]
	vmov	@XMM[4], @t[4]
	@ vmov	@XMM[5], @t[5]
	@ vmov	@XMM[6], @t[6]
	@ vmov	@XMM[7], @t[7]
___
}

sub swapmove {
my ($a,$b,$n,$mask,$t)=@_;
$code.=<<___;
	vshr.u64	$t, $b, #$n
	veor		$t, $t, $a
	vand		$t, $t, $mask
	veor		$a, $a, $t
	vshl.u64	$t, $t, #$n
	veor		$b, $b, $t
___
}
sub swapmove2x {
my ($a0,$b0,$a1,$b1,$n,$mask,$t0,$t1)=@_;
$code.=<<___;
	vshr.u64	$t0, $b0, #$n
	 vshr.u64	$t1, $b1, #$n
	veor		$t0, $t0, $a0
	 veor		$t1, $t1, $a1
	vand		$t0, $t0, $mask
	 vand		$t1, $t1, $mask
	veor		$a0, $a0, $t0
	vshl.u64	$t0, $t0, #$n
	 veor		$a1, $a1, $t1
	 vshl.u64	$t1, $t1, #$n
	veor		$b0, $b0, $t0
	 veor		$b1, $b1, $t1
___
}

sub bitslice {
my @x=reverse(@_[0..7]);
my ($t0,$t1,$t2,$t3)=@_[8..11];
$code.=<<___;
	vmov.i8	$t0,#0x55			@ compose .LBS0
	vmov.i8	$t1,#0x33			@ compose .LBS1
___
	&swapmove2x(@x[0,1,2,3],1,$t0,$t2,$t3);
	&swapmove2x(@x[4,5,6,7],1,$t0,$t2,$t3);
$code.=<<___;
	vmov.i8	$t0,#0x0f			@ compose .LBS2
___
	&swapmove2x(@x[0,2,1,3],2,$t1,$t2,$t3);
	&swapmove2x(@x[4,6,5,7],2,$t1,$t2,$t3);

	&swapmove2x(@x[0,4,1,5],4,$t0,$t2,$t3);
	&swapmove2x(@x[2,6,3,7],4,$t0,$t2,$t3);
}

$code.=<<___;
.text
.code	32
.fpu	neon

.type	_bsaes_decrypt8,%function
.align	4
_bsaes_decrypt8:
	sub	$const,pc,#8			@ _bsaes_decrypt8
	vldmia	$key!, {@XMM[9]}		@ round 0 key
	add	$const,$const,#.LM0ISR-_bsaes_decrypt8

	vldmia	$const!, {@XMM[8]}		@ .LM0ISR
	veor	@XMM[10], @XMM[0], @XMM[9]	@ xor with round0 key
	veor	@XMM[11], @XMM[1], @XMM[9]
	 vtbl.8	`&Dlo(@XMM[0])`, {@XMM[10]}, `&Dlo(@XMM[8])`
	 vtbl.8	`&Dhi(@XMM[0])`, {@XMM[10]}, `&Dhi(@XMM[8])`
	veor	@XMM[12], @XMM[2], @XMM[9]
	 vtbl.8	`&Dlo(@XMM[1])`, {@XMM[11]}, `&Dlo(@XMM[8])`
	 vtbl.8	`&Dhi(@XMM[1])`, {@XMM[11]}, `&Dhi(@XMM[8])`
	veor	@XMM[13], @XMM[3], @XMM[9]
	 vtbl.8	`&Dlo(@XMM[2])`, {@XMM[12]}, `&Dlo(@XMM[8])`
	 vtbl.8	`&Dhi(@XMM[2])`, {@XMM[12]}, `&Dhi(@XMM[8])`
	veor	@XMM[14], @XMM[4], @XMM[9]
	 vtbl.8	`&Dlo(@XMM[3])`, {@XMM[13]}, `&Dlo(@XMM[8])`
	 vtbl.8	`&Dhi(@XMM[3])`, {@XMM[13]}, `&Dhi(@XMM[8])`
	veor	@XMM[15], @XMM[5], @XMM[9]
	 vtbl.8	`&Dlo(@XMM[4])`, {@XMM[14]}, `&Dlo(@XMM[8])`
	 vtbl.8	`&Dhi(@XMM[4])`, {@XMM[14]}, `&Dhi(@XMM[8])`
	veor	@XMM[10], @XMM[6], @XMM[9]
	 vtbl.8	`&Dlo(@XMM[5])`, {@XMM[15]}, `&Dlo(@XMM[8])`
	 vtbl.8	`&Dhi(@XMM[5])`, {@XMM[15]}, `&Dhi(@XMM[8])`
	veor	@XMM[11], @XMM[7], @XMM[9]
	 vtbl.8	`&Dlo(@XMM[6])`, {@XMM[10]}, `&Dlo(@XMM[8])`
	 vtbl.8	`&Dhi(@XMM[6])`, {@XMM[10]}, `&Dhi(@XMM[8])`
	 vtbl.8	`&Dlo(@XMM[7])`, {@XMM[11]}, `&Dlo(@XMM[8])`
	 vtbl.8	`&Dhi(@XMM[7])`, {@XMM[11]}, `&Dhi(@XMM[8])`
___
	&bitslice	(@XMM[0..7, 8..11]);
$code.=<<___;
	sub	$rounds,$rounds,#1
	b	.Ldec_sbox
.align	4
.Ldec_loop:
___
	&ShiftRows	(@XMM[0..7, 8..12]);
$code.=".Ldec_sbox:\n";
	&InvSbox	(@XMM[0..7, 8..15]);
$code.=<<___;
	subs	$rounds,$rounds,#1
	bcc	.Ldec_done
___
	&InvMixColumns	(@XMM[0,1,6,4,2,7,3,5, 8..15]);
$code.=<<___;
	vldmia	$const, {@XMM[12]}		@ .LISR
	addeq	$const,$const,#0x10
	bne	.Ldec_loop
	vldmia	$const, {@XMM[12]}		@ .LISRM0
	b	.Ldec_loop
.align	4
.Ldec_done:
___
	&bitslice	(@XMM[0,1,6,4,2,7,3,5, 8..11]);
$code.=<<___;
	vldmia	$key, {@XMM[8]}			@ last round key
	veor	@XMM[6], @XMM[6], @XMM[8]
	veor	@XMM[4], @XMM[4], @XMM[8]
	veor	@XMM[2], @XMM[2], @XMM[8]
	veor	@XMM[7], @XMM[7], @XMM[8]
	veor	@XMM[3], @XMM[3], @XMM[8]
	veor	@XMM[5], @XMM[5], @XMM[8]
	veor	@XMM[0], @XMM[0], @XMM[8]
	veor	@XMM[1], @XMM[1], @XMM[8]
	bx	lr
.size	_bsaes_decrypt8,.-_bsaes_decrypt8

.type	_bsaes_const,%object
.align	6
_bsaes_const:
.LM0ISR:	@ InvShiftRows constants
	.quad	0x0a0e0206070b0f03, 0x0004080c0d010509
.LISR:
	.quad	0x0504070602010003, 0x0f0e0d0c080b0a09
.LISRM0:
	.quad	0x01040b0e0205080f, 0x0306090c00070a0d
.LM0SR:		@ ShiftRows constants
	.quad	0x0a0e02060f03070b, 0x0004080c05090d01
.LSR:
	.quad	0x0504070600030201, 0x0f0e0d0c0a09080b
.LSRM0:
	.quad	0x0304090e00050a0f, 0x01060b0c0207080d
.LM0:
	.quad	0x02060a0e03070b0f, 0x0004080c0105090d
.asciz	"Bit-sliced AES for NEON, CRYPTOGAMS by <appro\@openssl.org>"
.align	6
.size	_bsaes_const,.-_bsaes_const

.type	_bsaes_encrypt8,%function
.align	4
_bsaes_encrypt8:
	sub	$const,pc,#8			@ _bsaes_encrypt8
	vldmia	$key!, {@XMM[9]}		@ round 0 key
	sub	$const,$const,#_bsaes_encrypt8-.LM0SR

	vldmia	$const!, {@XMM[8]}		@ .LM0SR
	veor	@XMM[10], @XMM[0], @XMM[9]	@ xor with round0 key
	veor	@XMM[11], @XMM[1], @XMM[9]
	 vtbl.8	`&Dlo(@XMM[0])`, {@XMM[10]}, `&Dlo(@XMM[8])`
	 vtbl.8	`&Dhi(@XMM[0])`, {@XMM[10]}, `&Dhi(@XMM[8])`
	veor	@XMM[12], @XMM[2], @XMM[9]
	 vtbl.8	`&Dlo(@XMM[1])`, {@XMM[11]}, `&Dlo(@XMM[8])`
	 vtbl.8	`&Dhi(@XMM[1])`, {@XMM[11]}, `&Dhi(@XMM[8])`
	veor	@XMM[13], @XMM[3], @XMM[9]
	 vtbl.8	`&Dlo(@XMM[2])`, {@XMM[12]}, `&Dlo(@XMM[8])`
	 vtbl.8	`&Dhi(@XMM[2])`, {@XMM[12]}, `&Dhi(@XMM[8])`
	veor	@XMM[14], @XMM[4], @XMM[9]
	 vtbl.8	`&Dlo(@XMM[3])`, {@XMM[13]}, `&Dlo(@XMM[8])`
	 vtbl.8	`&Dhi(@XMM[3])`, {@XMM[13]}, `&Dhi(@XMM[8])`
	veor	@XMM[15], @XMM[5], @XMM[9]
	 vtbl.8	`&Dlo(@XMM[4])`, {@XMM[14]}, `&Dlo(@XMM[8])`
	 vtbl.8	`&Dhi(@XMM[4])`, {@XMM[14]}, `&Dhi(@XMM[8])`
	veor	@XMM[10], @XMM[6], @XMM[9]
	 vtbl.8	`&Dlo(@XMM[5])`, {@XMM[15]}, `&Dlo(@XMM[8])`
	 vtbl.8	`&Dhi(@XMM[5])`, {@XMM[15]}, `&Dhi(@XMM[8])`
	veor	@XMM[11], @XMM[7], @XMM[9]
	 vtbl.8	`&Dlo(@XMM[6])`, {@XMM[10]}, `&Dlo(@XMM[8])`
	 vtbl.8	`&Dhi(@XMM[6])`, {@XMM[10]}, `&Dhi(@XMM[8])`
	 vtbl.8	`&Dlo(@XMM[7])`, {@XMM[11]}, `&Dlo(@XMM[8])`
	 vtbl.8	`&Dhi(@XMM[7])`, {@XMM[11]}, `&Dhi(@XMM[8])`
_bsaes_encrypt8_bitslice:
___
	&bitslice	(@XMM[0..7, 8..11]);
$code.=<<___;
	sub	$rounds,$rounds,#1
	b	.Lenc_sbox
.align	4
.Lenc_loop:
___
	&ShiftRows	(@XMM[0..7, 8..12]);
$code.=".Lenc_sbox:\n";
	&Sbox		(@XMM[0..7, 8..15]);
$code.=<<___;
	subs	$rounds,$rounds,#1
	bcc	.Lenc_done
___
	&MixColumns	(@XMM[0,1,4,6,3,7,2,5, 8..15]);
$code.=<<___;
	vldmia	$const, {@XMM[12]}		@ .LSR
	addeq	$const,$const,#0x10
	bne	.Lenc_loop
	vldmia	$const, {@XMM[12]}		@ .LSRM0
	b	.Lenc_loop
.align	4
.Lenc_done:
___
	# output in lsb > [t0, t1, t4, t6, t3, t7, t2, t5] < msb
	&bitslice	(@XMM[0,1,4,6,3,7,2,5, 8..11]);
$code.=<<___;
	vldmia	$key, {@XMM[8]}			@ last round key
	veor	@XMM[4], @XMM[4], @XMM[8]
	veor	@XMM[6], @XMM[6], @XMM[8]
	veor	@XMM[3], @XMM[3], @XMM[8]
	veor	@XMM[7], @XMM[7], @XMM[8]
	veor	@XMM[2], @XMM[2], @XMM[8]
	veor	@XMM[5], @XMM[5], @XMM[8]
	veor	@XMM[0], @XMM[0], @XMM[8]
	veor	@XMM[1], @XMM[1], @XMM[8]
	bx	lr
.size	_bsaes_encrypt8,.-_bsaes_encrypt8
___
}
{
my ($out,$inp,$rounds,$const)=("r12","r4","r5","r6");

sub bitslice_key {
my @x=reverse(@_[0..7]);
my ($bs0,$bs1,$bs2,$t2,$t3)=@_[8..12];

	&swapmove	(@x[0,1],1,$bs0,$t2,$t3);
$code.=<<___;
	@ &swapmove(@x[2,3],1,$t0,$t2,$t3);
	vmov	@x[2], @x[0]
	vmov	@x[3], @x[1]
___
	#&swapmove2x(@x[4,5,6,7],1,$t0,$t2,$t3);

	&swapmove2x	(@x[0,2,1,3],2,$bs1,$t2,$t3);
$code.=<<___;
	@ &swapmove2x(@x[4,6,5,7],2,$t1,$t2,$t3);
	vmov	@x[4], @x[0]
	vmov	@x[6], @x[2]
	vmov	@x[5], @x[1]
	vmov	@x[7], @x[3]
___
	&swapmove2x	(@x[0,4,1,5],4,$bs2,$t2,$t3);
	&swapmove2x	(@x[2,6,3,7],4,$bs2,$t2,$t3);
}

$code.=<<___;
.type	_bsaes_key_convert,%function
.align	4
_bsaes_key_convert:
	sub	$const,pc,#8			@ _bsaes_key_convert
	vld1.8	{@XMM[7]},  [$inp]!		@ load round 0 key
	sub	$const,$const,#_bsaes_key_convert-.LM0
	vld1.8	{@XMM[15]}, [$inp]!		@ load round 1 key

826 827 828 829 830 831 832
	vmov.i8	@XMM[8],  #0x01			@ bit masks
	vmov.i8	@XMM[9],  #0x02
	vmov.i8	@XMM[10], #0x04
	vmov.i8	@XMM[11], #0x08
	vmov.i8	@XMM[12], #0x10
	vmov.i8	@XMM[13], #0x20
	vldmia	$const, {@XMM[14]}		@ .LM0
833 834 835 836 837 838 839 840 841 842 843

#ifdef __ARMEL__
	vrev32.8	@XMM[7],  @XMM[7]
	vrev32.8	@XMM[15], @XMM[15]
#endif
	sub	$rounds,$rounds,#1
	vstmia	$out!, {@XMM[7]}		@ save round 0 key
	b	.Lkey_loop

.align	4
.Lkey_loop:
844 845 846 847 848 849 850 851 852 853 854 855 856
	vtbl.8	`&Dlo(@XMM[7])`,{@XMM[15]},`&Dlo(@XMM[14])`
	vtbl.8	`&Dhi(@XMM[7])`,{@XMM[15]},`&Dhi(@XMM[14])`
	vmov.i8	@XMM[6],  #0x40
	vmov.i8	@XMM[15], #0x80

	vtst.8	@XMM[0], @XMM[7], @XMM[8]
	vtst.8	@XMM[1], @XMM[7], @XMM[9]
	vtst.8	@XMM[2], @XMM[7], @XMM[10]
	vtst.8	@XMM[3], @XMM[7], @XMM[11]
	vtst.8	@XMM[4], @XMM[7], @XMM[12]
	vtst.8	@XMM[5], @XMM[7], @XMM[13]
	vtst.8	@XMM[6], @XMM[7], @XMM[6]
	vtst.8	@XMM[7], @XMM[7], @XMM[15]
857
	vld1.8	{@XMM[15]}, [$inp]!		@ load next round key
858
	vmvn	@XMM[0], @XMM[0]		@ "pnot"
859
	vmvn	@XMM[1], @XMM[1]
860 861
	vmvn	@XMM[5], @XMM[5]
	vmvn	@XMM[6], @XMM[6]
862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903
#ifdef __ARMEL__
	vrev32.8	@XMM[15], @XMM[15]
#endif
	subs	$rounds,$rounds,#1
	vstmia	$out!,{@XMM[0]-@XMM[7]}		@ write bit-sliced round key
	bne	.Lkey_loop

	vmov.i8	@XMM[7],#0x63			@ compose .L63
	@ don't save last round key
	bx	lr
.size	_bsaes_key_convert,.-_bsaes_key_convert
___
}

if (1) {		# following four functions are unsupported interface
			# used for benchmarking...
$code.=<<___;
.globl	bsaes_enc_key_convert
.type	bsaes_enc_key_convert,%function
.align	4
bsaes_enc_key_convert:
	stmdb	sp!,{r4-r6,lr}
	vstmdb	sp!,{d8-d15}		@ ABI specification says so

	ldr	r5,[$inp,#240]			@ pass rounds
	mov	r4,$inp				@ pass key
	mov	r12,$out			@ pass key schedule
	bl	_bsaes_key_convert
	veor	@XMM[7],@XMM[7],@XMM[15]	@ fix up last round key
	vstmia	r12, {@XMM[7]}			@ save last round key

	vldmia	sp!,{d8-d15}
	ldmia	sp!,{r4-r6,pc}
.size	bsaes_enc_key_convert,.-bsaes_enc_key_convert

.globl	bsaes_encrypt_128
.type	bsaes_encrypt_128,%function
.align	4
bsaes_encrypt_128:
	stmdb	sp!,{r4-r6,lr}
	vstmdb	sp!,{d8-d15}		@ ABI specification says so
.Lenc128_loop:
904 905
	vld1.8	{@XMM[0]-@XMM[1]}, [$inp]!	@ load input
	vld1.8	{@XMM[2]-@XMM[3]}, [$inp]!
906
	mov	r4,$key				@ pass the key
907
	vld1.8	{@XMM[4]-@XMM[5]}, [$inp]!
908
	mov	r5,#10				@ pass rounds
909
	vld1.8	{@XMM[6]-@XMM[7]}, [$inp]!
910 911 912

	bl	_bsaes_encrypt8

913
	vst1.8	{@XMM[0]-@XMM[1]}, [$out]!	@ write output
914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953
	vst1.8	{@XMM[4]}, [$out]!
	vst1.8	{@XMM[6]}, [$out]!
	vst1.8	{@XMM[3]}, [$out]!
	vst1.8	{@XMM[7]}, [$out]!
	vst1.8	{@XMM[2]}, [$out]!
	subs	$len,$len,#0x80
	vst1.8	{@XMM[5]}, [$out]!
	bhi	.Lenc128_loop

	vldmia	sp!,{d8-d15}
	ldmia	sp!,{r4-r6,pc}
.size	bsaes_encrypt_128,.-bsaes_encrypt_128

.globl	bsaes_dec_key_convert
.type	bsaes_dec_key_convert,%function
.align	4
bsaes_dec_key_convert:
	stmdb	sp!,{r4-r6,lr}
	vstmdb	sp!,{d8-d15}		@ ABI specification says so

	ldr	r5,[$inp,#240]			@ pass rounds
	mov	r4,$inp				@ pass key
	mov	r12,$out			@ pass key schedule
	bl	_bsaes_key_convert
	vldmia	$out, {@XMM[6]}
	vstmia	r12,  {@XMM[15]}		@ save last round key
	veor	@XMM[7], @XMM[7], @XMM[6]	@ fix up round 0 key
	vstmia	$out, {@XMM[7]}

	vldmia	sp!,{d8-d15}
	ldmia	sp!,{r4-r6,pc}
.size	bsaes_dec_key_convert,.-bsaes_dec_key_convert

.globl	bsaes_decrypt_128
.type	bsaes_decrypt_128,%function
.align	4
bsaes_decrypt_128:
	stmdb	sp!,{r4-r6,lr}
	vstmdb	sp!,{d8-d15}		@ ABI specification says so
.Ldec128_loop:
954 955
	vld1.8	{@XMM[0]-@XMM[1]}, [$inp]!	@ load input
	vld1.8	{@XMM[2]-@XMM[3]}, [$inp]!
956
	mov	r4,$key				@ pass the key
957
	vld1.8	{@XMM[4]-@XMM[5]}, [$inp]!
958
	mov	r5,#10				@ pass rounds
959
	vld1.8	{@XMM[6]-@XMM[7]}, [$inp]!
960 961 962

	bl	_bsaes_decrypt8

963
	vst1.8	{@XMM[0]-@XMM[1]}, [$out]!	@ write output
964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983
	vst1.8	{@XMM[6]}, [$out]!
	vst1.8	{@XMM[4]}, [$out]!
	vst1.8	{@XMM[2]}, [$out]!
	vst1.8	{@XMM[7]}, [$out]!
	vst1.8	{@XMM[3]}, [$out]!
	subs	$len,$len,#0x80
	vst1.8	{@XMM[5]}, [$out]!
	bhi	.Ldec128_loop

	vldmia	sp!,{d8-d15}
	ldmia	sp!,{r4-r6,pc}
.size	bsaes_decrypt_128,.-bsaes_decrypt_128
___
}

$code =~ s/\`([^\`]*)\`/eval($1)/gem;

print $code;

close STDOUT;