xref: /openssl/crypto/sm4/asm/sm4-armv8.pl (revision d5c208b6)
1#! /usr/bin/env perl
2# Copyright 2022 The OpenSSL Project Authors. All Rights Reserved.
3#
4# Licensed under the Apache License 2.0 (the "License").  You may not use
5# this file except in compliance with the License.  You can obtain a copy
6# in the file LICENSE in the source distribution or at
7# https://www.openssl.org/source/license.html
8
9#
10# This module implements support for SM4 hw support on aarch64
11# Oct 2021
12#
13
14# $output is the last argument if it looks like a file (it has an extension)
15# $flavour is the first argument if it doesn't look like a file
16$output = $#ARGV >= 0 && $ARGV[$#ARGV] =~ m|\.\w+$| ? pop : undef;
17$flavour = $#ARGV >= 0 && $ARGV[0] !~ m|\.| ? shift : undef;
18
19$0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1;
20( $xlate="${dir}arm-xlate.pl" and -f $xlate ) or
21( $xlate="${dir}../../perlasm/arm-xlate.pl" and -f $xlate) or
22die "can't locate arm-xlate.pl";
23
24open OUT,"| \"$^X\" $xlate $flavour \"$output\""
25    or die "can't call $xlate: $!";
26*STDOUT=*OUT;
27
28$prefix="sm4_v8";
29my @rks=map("v$_",(0..7));
30
31sub rev32() {
32my $dst = shift;
33my $src = shift;
34$code.=<<___;
35#ifndef __ARMEB__
36	rev32	$dst.16b,$src.16b
37#endif
38___
39}
40
41sub enc_blk () {
42my $data = shift;
43$code.=<<___;
44	sm4e	$data.4s,@rks[0].4s
45	sm4e	$data.4s,@rks[1].4s
46	sm4e	$data.4s,@rks[2].4s
47	sm4e	$data.4s,@rks[3].4s
48	sm4e	$data.4s,@rks[4].4s
49	sm4e	$data.4s,@rks[5].4s
50	sm4e	$data.4s,@rks[6].4s
51	sm4e	$data.4s,@rks[7].4s
52	rev64	$data.4S,$data.4S
53	ext	$data.16b,$data.16b,$data.16b,#8
54___
55}
56
57sub enc_4blks () {
58my $data0 = shift;
59my $data1 = shift;
60my $data2 = shift;
61my $data3 = shift;
62$code.=<<___;
63	sm4e	$data0.4s,@rks[0].4s
64	sm4e	$data1.4s,@rks[0].4s
65	sm4e	$data2.4s,@rks[0].4s
66	sm4e	$data3.4s,@rks[0].4s
67
68	sm4e	$data0.4s,@rks[1].4s
69	sm4e	$data1.4s,@rks[1].4s
70	sm4e	$data2.4s,@rks[1].4s
71	sm4e	$data3.4s,@rks[1].4s
72
73	sm4e	$data0.4s,@rks[2].4s
74	sm4e	$data1.4s,@rks[2].4s
75	sm4e	$data2.4s,@rks[2].4s
76	sm4e	$data3.4s,@rks[2].4s
77
78	sm4e	$data0.4s,@rks[3].4s
79	sm4e	$data1.4s,@rks[3].4s
80	sm4e	$data2.4s,@rks[3].4s
81	sm4e	$data3.4s,@rks[3].4s
82
83	sm4e	$data0.4s,@rks[4].4s
84	sm4e	$data1.4s,@rks[4].4s
85	sm4e	$data2.4s,@rks[4].4s
86	sm4e	$data3.4s,@rks[4].4s
87
88	sm4e	$data0.4s,@rks[5].4s
89	sm4e	$data1.4s,@rks[5].4s
90	sm4e	$data2.4s,@rks[5].4s
91	sm4e	$data3.4s,@rks[5].4s
92
93	sm4e	$data0.4s,@rks[6].4s
94	sm4e	$data1.4s,@rks[6].4s
95	sm4e	$data2.4s,@rks[6].4s
96	sm4e	$data3.4s,@rks[6].4s
97
98	sm4e	$data0.4s,@rks[7].4s
99	rev64	$data0.4S,$data0.4S
100	sm4e	$data1.4s,@rks[7].4s
101	ext	$data0.16b,$data0.16b,$data0.16b,#8
102	rev64	$data1.4S,$data1.4S
103	sm4e	$data2.4s,@rks[7].4s
104	ext	$data1.16b,$data1.16b,$data1.16b,#8
105	rev64	$data2.4S,$data2.4S
106	sm4e	$data3.4s,@rks[7].4s
107	ext	$data2.16b,$data2.16b,$data2.16b,#8
108	rev64	$data3.4S,$data3.4S
109	ext	$data3.16b,$data3.16b,$data3.16b,#8
110___
111}
112
113$code=<<___;
114#include "arm_arch.h"
115.arch	armv8-a+crypto
116.text
117___
118
119{{{
120$code.=<<___;
121
122.rodata
123.type	_${prefix}_consts,%object
124.align	6
125_${prefix}_consts:
126.Lck:
127	.long 0x00070E15, 0x1C232A31, 0x383F464D, 0x545B6269
128	.long 0x70777E85, 0x8C939AA1, 0xA8AFB6BD, 0xC4CBD2D9
129	.long 0xE0E7EEF5, 0xFC030A11, 0x181F262D, 0x343B4249
130	.long 0x50575E65, 0x6C737A81, 0x888F969D, 0xA4ABB2B9
131	.long 0xC0C7CED5, 0xDCE3EAF1, 0xF8FF060D, 0x141B2229
132	.long 0x30373E45, 0x4C535A61, 0x686F767D, 0x848B9299
133	.long 0xA0A7AEB5, 0xBCC3CAD1, 0xD8DFE6ED, 0xF4FB0209
134	.long 0x10171E25, 0x2C333A41, 0x484F565D, 0x646B7279
135.Lfk:
136	.long 0xa3b1bac6, 0x56aa3350, 0x677d9197, 0xb27022dc
137.size _${prefix}_consts,.-_${prefix}_consts
138.previous
139
140___
141}}}
142
143{{{
144my ($key,$keys)=("x0","x1");
145my ($tmp)=("x2");
146my ($key0,$key1,$key2,$key3,$key4,$key5,$key6,$key7)=map("v$_",(0..7));
147my ($const0,$const1,$const2,$const3,$const4,$const5,$const6,$const7)=map("v$_",(16..23));
148my ($fkconst) = ("v24");
149$code.=<<___;
150.globl	${prefix}_set_encrypt_key
151.type	${prefix}_set_encrypt_key,%function
152.align	5
153${prefix}_set_encrypt_key:
154	AARCH64_VALID_CALL_TARGET
155	ld1	{$key0.4s},[$key]
156	adrp	$tmp,.Lfk
157	add	$tmp,$tmp,#:lo12:.Lfk
158	ld1	{$fkconst.4s},[$tmp]
159	adrp	$tmp,.Lck
160	add	$tmp,$tmp,#:lo12:.Lck
161	ld1	{$const0.4s,$const1.4s,$const2.4s,$const3.4s},[$tmp],64
162___
163	&rev32($key0, $key0);
164$code.=<<___;
165	ld1	{$const4.4s,$const5.4s,$const6.4s,$const7.4s},[$tmp]
166	eor	$key0.16b,$key0.16b,$fkconst.16b;
167	sm4ekey	$key0.4S,$key0.4S,$const0.4S
168	sm4ekey	$key1.4S,$key0.4S,$const1.4S
169	sm4ekey	$key2.4S,$key1.4S,$const2.4S
170	sm4ekey	$key3.4S,$key2.4S,$const3.4S
171	sm4ekey	$key4.4S,$key3.4S,$const4.4S
172	st1	{$key0.4s,$key1.4s,$key2.4s,$key3.4s},[$keys],64
173	sm4ekey	$key5.4S,$key4.4S,$const5.4S
174	sm4ekey	$key6.4S,$key5.4S,$const6.4S
175	sm4ekey	$key7.4S,$key6.4S,$const7.4S
176	st1	{$key4.4s,$key5.4s,$key6.4s,$key7.4s},[$keys]
177	ret
178.size	${prefix}_set_encrypt_key,.-${prefix}_set_encrypt_key
179___
180}}}
181
182{{{
183my ($key,$keys)=("x0","x1");
184my ($tmp)=("x2");
185my ($key7,$key6,$key5,$key4,$key3,$key2,$key1,$key0)=map("v$_",(0..7));
186my ($const0,$const1,$const2,$const3,$const4,$const5,$const6,$const7)=map("v$_",(16..23));
187my ($fkconst) = ("v24");
188$code.=<<___;
189.globl	${prefix}_set_decrypt_key
190.type	${prefix}_set_decrypt_key,%function
191.align	5
192${prefix}_set_decrypt_key:
193	AARCH64_VALID_CALL_TARGET
194	ld1	{$key0.4s},[$key]
195	adrp	$tmp,.Lfk
196	add	$tmp,$tmp,#:lo12:.Lfk
197	ld1	{$fkconst.4s},[$tmp]
198	adrp	$tmp,.Lck
199	add	$tmp,$tmp,#:lo12:.Lck
200	ld1	{$const0.4s,$const1.4s,$const2.4s,$const3.4s},[$tmp],64
201___
202	&rev32($key0, $key0);
203$code.=<<___;
204	ld1	{$const4.4s,$const5.4s,$const6.4s,$const7.4s},[$tmp]
205	eor	$key0.16b, $key0.16b,$fkconst.16b;
206	sm4ekey	$key0.4S,$key0.4S,$const0.4S
207	sm4ekey	$key1.4S,$key0.4S,$const1.4S
208	sm4ekey	$key2.4S,$key1.4S,$const2.4S
209	rev64	$key0.4s,$key0.4s
210	rev64	$key1.4s,$key1.4s
211	ext	$key0.16b,$key0.16b,$key0.16b,#8
212	ext	$key1.16b,$key1.16b,$key1.16b,#8
213	sm4ekey	$key3.4S,$key2.4S,$const3.4S
214	sm4ekey	$key4.4S,$key3.4S,$const4.4S
215	rev64	$key2.4s,$key2.4s
216	rev64	$key3.4s,$key3.4s
217	ext	$key2.16b,$key2.16b,$key2.16b,#8
218	ext	$key3.16b,$key3.16b,$key3.16b,#8
219	sm4ekey	$key5.4S,$key4.4S,$const5.4S
220	sm4ekey	$key6.4S,$key5.4S,$const6.4S
221	rev64	$key4.4s,$key4.4s
222	rev64	$key5.4s,$key5.4s
223	ext	$key4.16b,$key4.16b,$key4.16b,#8
224	ext	$key5.16b,$key5.16b,$key5.16b,#8
225	sm4ekey	$key7.4S,$key6.4S,$const7.4S
226	rev64	$key6.4s, $key6.4s
227	rev64	$key7.4s, $key7.4s
228	ext	$key6.16b,$key6.16b,$key6.16b,#8
229	ext	$key7.16b,$key7.16b,$key7.16b,#8
230	st1	{$key7.4s,$key6.4s,$key5.4s,$key4.4s},[$keys],64
231	st1	{$key3.4s,$key2.4s,$key1.4s,$key0.4s},[$keys]
232	ret
233.size	${prefix}_set_decrypt_key,.-${prefix}_set_decrypt_key
234___
235}}}
236
237{{{
238sub gen_block () {
239my $dir = shift;
240my ($inp,$out,$rk)=map("x$_",(0..2));
241my ($data)=("v16");
242$code.=<<___;
243.globl	${prefix}_${dir}crypt
244.type	${prefix}_${dir}crypt,%function
245.align	5
246${prefix}_${dir}crypt:
247	AARCH64_VALID_CALL_TARGET
248	ld1	{$data.4s},[$inp]
249	ld1	{@rks[0].4s,@rks[1].4s,@rks[2].4s,@rks[3].4s},[$rk],64
250	ld1	{@rks[4].4s,@rks[5].4s,@rks[6].4s,@rks[7].4s},[$rk]
251___
252	&rev32($data,$data);
253	&enc_blk($data);
254	&rev32($data,$data);
255$code.=<<___;
256	st1	{$data.4s},[$out]
257	ret
258.size	${prefix}_${dir}crypt,.-${prefix}_${dir}crypt
259___
260}
261
262&gen_block("en");
263&gen_block("de");
264}}}
265
266{{{
267my ($inp,$out,$len,$rk)=map("x$_",(0..3));
268my ($enc) = ("w4");
269my @dat=map("v$_",(16..23));
270$code.=<<___;
271.globl	${prefix}_ecb_encrypt
272.type	${prefix}_ecb_encrypt,%function
273.align	5
274${prefix}_ecb_encrypt:
275	AARCH64_VALID_CALL_TARGET
276	ld1	{@rks[0].4s,@rks[1].4s,@rks[2].4s,@rks[3].4s},[$rk],#64
277	ld1	{@rks[4].4s,@rks[5].4s,@rks[6].4s,@rks[7].4s},[$rk]
2781:
279	cmp	$len,#64
280	b.lt	1f
281	ld1	{@dat[0].4s,@dat[1].4s,@dat[2].4s,@dat[3].4s},[$inp],#64
282	cmp	$len,#128
283	b.lt	2f
284	ld1	{@dat[4].4s,@dat[5].4s,@dat[6].4s,@dat[7].4s},[$inp],#64
285	// 8 blocks
286___
287	&rev32(@dat[0],@dat[0]);
288	&rev32(@dat[1],@dat[1]);
289	&rev32(@dat[2],@dat[2]);
290	&rev32(@dat[3],@dat[3]);
291	&rev32(@dat[4],@dat[4]);
292	&rev32(@dat[5],@dat[5]);
293	&rev32(@dat[6],@dat[6]);
294	&rev32(@dat[7],@dat[7]);
295	&enc_4blks(@dat[0],@dat[1],@dat[2],@dat[3]);
296	&enc_4blks(@dat[4],@dat[5],@dat[6],@dat[7]);
297	&rev32(@dat[0],@dat[0]);
298	&rev32(@dat[1],@dat[1]);
299	&rev32(@dat[2],@dat[2]);
300	&rev32(@dat[3],@dat[3]);
301	&rev32(@dat[4],@dat[4]);
302	&rev32(@dat[5],@dat[5]);
303$code.=<<___;
304	st1	{@dat[0].4s,@dat[1].4s,@dat[2].4s,@dat[3].4s},[$out],#64
305___
306	&rev32(@dat[6],@dat[6]);
307	&rev32(@dat[7],@dat[7]);
308$code.=<<___;
309	st1	{@dat[4].4s,@dat[5].4s,@dat[6].4s,@dat[7].4s},[$out],#64
310	subs	$len,$len,#128
311	b.gt	1b
312	ret
313	// 4 blocks
3142:
315___
316	&rev32(@dat[0],@dat[0]);
317	&rev32(@dat[1],@dat[1]);
318	&rev32(@dat[2],@dat[2]);
319	&rev32(@dat[3],@dat[3]);
320	&enc_4blks(@dat[0],@dat[1],@dat[2],@dat[3]);
321	&rev32(@dat[0],@dat[0]);
322	&rev32(@dat[1],@dat[1]);
323	&rev32(@dat[2],@dat[2]);
324	&rev32(@dat[3],@dat[3]);
325$code.=<<___;
326	st1	{@dat[0].4s,@dat[1].4s,@dat[2].4s,@dat[3].4s},[$out],#64
327	subs	$len,$len,#64
328	b.gt	1b
3291:
330	subs	$len,$len,#16
331	b.lt	1f
332	ld1	{@dat[0].4s},[$inp],#16
333___
334	&rev32(@dat[0],@dat[0]);
335	&enc_blk(@dat[0]);
336	&rev32(@dat[0],@dat[0]);
337$code.=<<___;
338	st1	{@dat[0].4s},[$out],#16
339	b.ne	1b
3401:
341	ret
342.size	${prefix}_ecb_encrypt,.-${prefix}_ecb_encrypt
343___
344}}}
345
346{{{
347my ($inp,$out,$len,$rk,$ivp)=map("x$_",(0..4));
348my ($enc) = ("w5");
349my @dat=map("v$_",(16..23));
350my @in=map("v$_",(24..31));
351my ($ivec) = ("v8");
352$code.=<<___;
353.globl	${prefix}_cbc_encrypt
354.type	${prefix}_cbc_encrypt,%function
355.align	5
356${prefix}_cbc_encrypt:
357	AARCH64_VALID_CALL_TARGET
358	stp	d8,d9,[sp, #-16]!
359
360	ld1	{@rks[0].4s,@rks[1].4s,@rks[2].4s,@rks[3].4s},[$rk],#64
361	ld1	{@rks[4].4s,@rks[5].4s,@rks[6].4s,@rks[7].4s},[$rk]
362	ld1	{$ivec.4s},[$ivp]
363	cmp	$enc,#0
364	b.eq	.Ldec
3651:
366	cmp	$len, #64
367	b.lt	1f
368	ld1	{@dat[0].4s,@dat[1].4s,@dat[2].4s,@dat[3].4s},[$inp],#64
369	eor	@dat[0].16b,@dat[0].16b,$ivec.16b
370___
371	&rev32(@dat[1],@dat[1]);
372	&rev32(@dat[0],@dat[0]);
373	&rev32(@dat[2],@dat[2]);
374	&rev32(@dat[3],@dat[3]);
375	&enc_blk(@dat[0]);
376$code.=<<___;
377	eor	@dat[1].16b,@dat[1].16b,@dat[0].16b
378___
379	&enc_blk(@dat[1]);
380	&rev32(@dat[0],@dat[0]);
381$code.=<<___;
382	eor	@dat[2].16b,@dat[2].16b,@dat[1].16b
383___
384	&enc_blk(@dat[2]);
385	&rev32(@dat[1],@dat[1]);
386$code.=<<___;
387	eor	@dat[3].16b,@dat[3].16b,@dat[2].16b
388___
389	&enc_blk(@dat[3]);
390	&rev32(@dat[2],@dat[2]);
391	&rev32(@dat[3],@dat[3]);
392$code.=<<___;
393	mov	$ivec.16b,@dat[3].16b
394	st1	{@dat[0].4s,@dat[1].4s,@dat[2].4s,@dat[3].4s},[$out],#64
395	subs	$len,$len,#64
396	b.ne	1b
3971:
398	subs	$len,$len,#16
399	b.lt	3f
400	ld1	{@dat[0].4s},[$inp],#16
401	eor	$ivec.16b,$ivec.16b,@dat[0].16b
402___
403	&rev32($ivec,$ivec);
404	&enc_blk($ivec);
405	&rev32($ivec,$ivec);
406$code.=<<___;
407	st1	{$ivec.16b},[$out],#16
408	b.ne	1b
409	b	3f
410.Ldec:
4111:
412	cmp	$len, #64
413	b.lt	1f
414	ld1	{@dat[0].4s,@dat[1].4s,@dat[2].4s,@dat[3].4s},[$inp]
415	ld1	{@in[0].4s,@in[1].4s,@in[2].4s,@in[3].4s},[$inp],#64
416	cmp	$len,#128
417	b.lt	2f
418	// 8 blocks mode
419	ld1	{@dat[4].4s,@dat[5].4s,@dat[6].4s,@dat[7].4s},[$inp]
420	ld1	{@in[4].4s,@in[5].4s,@in[6].4s,@in[7].4s},[$inp],#64
421___
422	&rev32(@dat[0],@dat[0]);
423	&rev32(@dat[1],@dat[1]);
424	&rev32(@dat[2],@dat[2]);
425	&rev32(@dat[3],$dat[3]);
426	&rev32(@dat[4],@dat[4]);
427	&rev32(@dat[5],@dat[5]);
428	&rev32(@dat[6],@dat[6]);
429	&rev32(@dat[7],$dat[7]);
430	&enc_4blks(@dat[0],@dat[1],@dat[2],@dat[3]);
431	&enc_4blks(@dat[4],@dat[5],@dat[6],@dat[7]);
432	&rev32(@dat[0],@dat[0]);
433	&rev32(@dat[1],@dat[1]);
434	&rev32(@dat[2],@dat[2]);
435	&rev32(@dat[3],@dat[3]);
436	&rev32(@dat[4],@dat[4]);
437	&rev32(@dat[5],@dat[5]);
438	&rev32(@dat[6],@dat[6]);
439	&rev32(@dat[7],@dat[7]);
440$code.=<<___;
441	eor	@dat[0].16b,@dat[0].16b,$ivec.16b
442	eor	@dat[1].16b,@dat[1].16b,@in[0].16b
443	eor	@dat[2].16b,@dat[2].16b,@in[1].16b
444	mov	$ivec.16b,@in[7].16b
445	eor	@dat[3].16b,$dat[3].16b,@in[2].16b
446	eor	@dat[4].16b,$dat[4].16b,@in[3].16b
447	eor	@dat[5].16b,$dat[5].16b,@in[4].16b
448	eor	@dat[6].16b,$dat[6].16b,@in[5].16b
449	eor	@dat[7].16b,$dat[7].16b,@in[6].16b
450	st1	{@dat[0].4s,@dat[1].4s,@dat[2].4s,@dat[3].4s},[$out],#64
451	st1	{@dat[4].4s,@dat[5].4s,@dat[6].4s,@dat[7].4s},[$out],#64
452	subs	$len,$len,128
453	b.gt	1b
454	b	3f
455	// 4 blocks mode
4562:
457___
458	&rev32(@dat[0],@dat[0]);
459	&rev32(@dat[1],@dat[1]);
460	&rev32(@dat[2],@dat[2]);
461	&rev32(@dat[3],$dat[3]);
462	&enc_4blks(@dat[0],@dat[1],@dat[2],@dat[3]);
463	&rev32(@dat[0],@dat[0]);
464	&rev32(@dat[1],@dat[1]);
465	&rev32(@dat[2],@dat[2]);
466	&rev32(@dat[3],@dat[3]);
467$code.=<<___;
468	eor	@dat[0].16b,@dat[0].16b,$ivec.16b
469	eor	@dat[1].16b,@dat[1].16b,@in[0].16b
470	mov	$ivec.16b,@in[3].16b
471	eor	@dat[2].16b,@dat[2].16b,@in[1].16b
472	eor	@dat[3].16b,$dat[3].16b,@in[2].16b
473	st1	{@dat[0].4s,@dat[1].4s,@dat[2].4s,@dat[3].4s},[$out],#64
474	subs	$len,$len,#64
475	b.gt	1b
4761:
477	subs	$len,$len,#16
478	b.lt	3f
479	ld1	{@dat[0].4s},[$inp],#16
480	mov	@in[0].16b,@dat[0].16b
481___
482	&rev32(@dat[0],@dat[0]);
483	&enc_blk(@dat[0]);
484	&rev32(@dat[0],@dat[0]);
485$code.=<<___;
486	eor	@dat[0].16b,@dat[0].16b,$ivec.16b
487	mov	$ivec.16b,@in[0].16b
488	st1	{@dat[0].16b},[$out],#16
489	b.ne	1b
4903:
491	// save back IV
492	st1	{$ivec.16b},[$ivp]
493	ldp	d8,d9,[sp],#16
494	ret
495.size	${prefix}_cbc_encrypt,.-${prefix}_cbc_encrypt
496___
497}}}
498
499{{{
500my ($inp,$out,$len,$rk,$ivp)=map("x$_",(0..4));
501my ($ctr)=("w5");
502my @dat=map("v$_",(16..23));
503my @in=map("v$_",(24..31));
504my ($ivec)=("v8");
505$code.=<<___;
506.globl	${prefix}_ctr32_encrypt_blocks
507.type	${prefix}_ctr32_encrypt_blocks,%function
508.align	5
509${prefix}_ctr32_encrypt_blocks:
510	AARCH64_VALID_CALL_TARGET
511	stp	d8,d9,[sp, #-16]!
512
513	ld1	{$ivec.4s},[$ivp]
514	ld1	{@rks[0].4s,@rks[1].4s,@rks[2].4s,@rks[3].4s},[$rk],64
515	ld1	{@rks[4].4s,@rks[5].4s,@rks[6].4s,@rks[7].4s},[$rk]
516___
517	&rev32($ivec,$ivec);
518$code.=<<___;
519	mov	$ctr,$ivec.s[3]
5201:
521	cmp	$len,#4
522	b.lt	1f
523	ld1	{@in[0].4s,@in[1].4s,@in[2].4s,@in[3].4s},[$inp],#64
524	mov	@dat[0].16b,$ivec.16b
525	mov	@dat[1].16b,$ivec.16b
526	mov	@dat[2].16b,$ivec.16b
527	mov	@dat[3].16b,$ivec.16b
528	add	$ctr,$ctr,#1
529	mov	$dat[1].s[3],$ctr
530	add	$ctr,$ctr,#1
531	mov	@dat[2].s[3],$ctr
532	add	$ctr,$ctr,#1
533	mov	@dat[3].s[3],$ctr
534	cmp	$len,#8
535	b.lt	2f
536	ld1	{@in[4].4s,@in[5].4s,@in[6].4s,@in[7].4s},[$inp],#64
537	mov	@dat[4].16b,$ivec.16b
538	mov	@dat[5].16b,$ivec.16b
539	mov	@dat[6].16b,$ivec.16b
540	mov	@dat[7].16b,$ivec.16b
541	add	$ctr,$ctr,#1
542	mov	$dat[4].s[3],$ctr
543	add	$ctr,$ctr,#1
544	mov	@dat[5].s[3],$ctr
545	add	$ctr,$ctr,#1
546	mov	@dat[6].s[3],$ctr
547	add	$ctr,$ctr,#1
548	mov	@dat[7].s[3],$ctr
549___
550	&enc_4blks(@dat[0],@dat[1],@dat[2],@dat[3]);
551	&enc_4blks(@dat[4],@dat[5],@dat[6],@dat[7]);
552	&rev32(@dat[0],@dat[0]);
553	&rev32(@dat[1],@dat[1]);
554	&rev32(@dat[2],@dat[2]);
555	&rev32(@dat[3],@dat[3]);
556	&rev32(@dat[4],@dat[4]);
557	&rev32(@dat[5],@dat[5]);
558	&rev32(@dat[6],@dat[6]);
559	&rev32(@dat[7],@dat[7]);
560$code.=<<___;
561	eor	@dat[0].16b,@dat[0].16b,@in[0].16b
562	eor	@dat[1].16b,@dat[1].16b,@in[1].16b
563	eor	@dat[2].16b,@dat[2].16b,@in[2].16b
564	eor	@dat[3].16b,@dat[3].16b,@in[3].16b
565	eor	@dat[4].16b,@dat[4].16b,@in[4].16b
566	eor	@dat[5].16b,@dat[5].16b,@in[5].16b
567	eor	@dat[6].16b,@dat[6].16b,@in[6].16b
568	eor	@dat[7].16b,@dat[7].16b,@in[7].16b
569	st1	{@dat[0].4s,@dat[1].4s,@dat[2].4s,@dat[3].4s},[$out],#64
570	st1	{@dat[4].4s,@dat[5].4s,@dat[6].4s,@dat[7].4s},[$out],#64
571	subs	$len,$len,#8
572	b.eq	3f
573	add	$ctr,$ctr,#1
574	mov	$ivec.s[3],$ctr
575	b	1b
5762:
577___
578	&enc_4blks(@dat[0],@dat[1],@dat[2],@dat[3]);
579	&rev32(@dat[0],@dat[0]);
580	&rev32(@dat[1],@dat[1]);
581	&rev32(@dat[2],@dat[2]);
582	&rev32(@dat[3],@dat[3]);
583$code.=<<___;
584	eor	@dat[0].16b,@dat[0].16b,@in[0].16b
585	eor	@dat[1].16b,@dat[1].16b,@in[1].16b
586	eor	@dat[2].16b,@dat[2].16b,@in[2].16b
587	eor	@dat[3].16b,@dat[3].16b,@in[3].16b
588	st1	{@dat[0].4s,@dat[1].4s,@dat[2].4s,@dat[3].4s},[$out],#64
589	subs	$len,$len,#4
590	b.eq	3f
591	add	$ctr,$ctr,#1
592	mov	$ivec.s[3],$ctr
593	b	1b
5941:
595	subs	$len,$len,#1
596	b.lt	3f
597	mov	$dat[0].16b,$ivec.16b
598	ld1	{@in[0].4s},[$inp],#16
599___
600	&enc_blk(@dat[0]);
601	&rev32(@dat[0],@dat[0]);
602$code.=<<___;
603	eor	$dat[0].16b,$dat[0].16b,@in[0].16b
604	st1	{$dat[0].4s},[$out],#16
605	b.eq	3f
606	add	$ctr,$ctr,#1
607	mov	$ivec.s[3],$ctr
608	b	1b
6093:
610	ldp	d8,d9,[sp],#16
611	ret
612.size	${prefix}_ctr32_encrypt_blocks,.-${prefix}_ctr32_encrypt_blocks
613___
614}}}
615########################################
616{   my  %opcode = (
617        "sm4e"          => 0xcec08400,
618        "sm4ekey"       => 0xce60c800);
619
620    sub unsm4 {
621        my ($mnemonic,$arg)=@_;
622
623        $arg =~ m/[qv]([0-9]+)[^,]*,\s*[qv]([0-9]+)[^,]*(?:,\s*[qv]([0-9]+))?/o
624        &&
625        sprintf ".inst\t0x%08x\t//%s %s",
626                        $opcode{$mnemonic}|$1|($2<<5)|($3<<16),
627                        $mnemonic,$arg;
628    }
629}
630
631open SELF,$0;
632while(<SELF>) {
633        next if (/^#!/);
634        last if (!s/^#/\/\// and !/^$/);
635        print;
636}
637close SELF;
638
639foreach(split("\n",$code)) {
640	s/\`([^\`]*)\`/eval($1)/ge;
641
642	s/\b(sm4\w+)\s+([qv].*)/unsm4($1,$2)/ge;
643	print $_,"\n";
644}
645
646close STDOUT or die "error closing STDOUT: $!";
647