1#! /usr/bin/env perl
2# This file is dual-licensed, meaning that you can use it under your
3# choice of either of the following two licenses:
4#
5# Copyright 2023 The OpenSSL Project Authors. All Rights Reserved.
6#
7# Licensed under the Apache License 2.0 (the "License"). You can obtain
8# a copy in the file LICENSE in the source distribution or at
9# https://www.openssl.org/source/license.html
10#
11# or
12#
13# Copyright (c) 2023, Christoph Müllner <christoph.muellner@vrull.eu>
14# All rights reserved.
15#
16# Redistribution and use in source and binary forms, with or without
17# modification, are permitted provided that the following conditions
18# are met:
19# 1. Redistributions of source code must retain the above copyright
20#    notice, this list of conditions and the following disclaimer.
21# 2. Redistributions in binary form must reproduce the above copyright
22#    notice, this list of conditions and the following disclaimer in the
23#    documentation and/or other materials provided with the distribution.
24#
25# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
26# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
27# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
28# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
29# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
30# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
31# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
32# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
33# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
34# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
35# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36
37# The generated code of this file depends on the following RISC-V extensions:
38# - RV64I
39# - RISC-V Vector ('V') with VLEN >= 128
40# - RISC-V Vector Cryptography Bit-manipulation extension ('Zvkb')
41# - RISC-V Vector SM4 Block Cipher extension ('Zvksed')
42
43use strict;
44use warnings;
45
46use FindBin qw($Bin);
47use lib "$Bin";
48use lib "$Bin/../../perlasm";
49use riscv;
50
51# $output is the last argument if it looks like a file (it has an extension)
52# $flavour is the first argument if it doesn't look like a file
53my $output = $#ARGV >= 0 && $ARGV[$#ARGV] =~ m|\.\w+$| ? pop : undef;
54my $flavour = $#ARGV >= 0 && $ARGV[0] !~ m|\.| ? shift : undef;
55
56$output and open STDOUT,">$output";
57
58my $code=<<___;
59.text
60___
61
62####
63# int rv64i_zvksed_sm4_set_encrypt_key(const unsigned char *userKey,
64#                                      SM4_KEY *key);
65#
66{
67my ($ukey,$keys,$fk)=("a0","a1","t0");
68my ($vukey,$vfk,$vk0,$vk1,$vk2,$vk3,$vk4,$vk5,$vk6,$vk7)=("v1","v2","v3","v4","v5","v6","v7","v8","v9","v10");
69$code .= <<___;
70.p2align 3
71.globl rv64i_zvksed_sm4_set_encrypt_key
72.type rv64i_zvksed_sm4_set_encrypt_key,\@function
73rv64i_zvksed_sm4_set_encrypt_key:
74    @{[vsetivli__x0_4_e32_m1_tu_mu]}
75
76    # Load the user key
77    @{[vle32_v $vukey, $ukey]}
78    @{[vrev8_v $vukey, $vukey]}
79
80    # Load the FK.
81    la $fk, FK
82    @{[vle32_v $vfk, $fk]}
83
84    # Generate round keys.
85    @{[vxor_vv $vukey, $vukey, $vfk]}
86    @{[vsm4k_vi $vk0, $vukey, 0]} # rk[0:3]
87    @{[vsm4k_vi $vk1, $vk0, 1]} # rk[4:7]
88    @{[vsm4k_vi $vk2, $vk1, 2]} # rk[8:11]
89    @{[vsm4k_vi $vk3, $vk2, 3]} # rk[12:15]
90    @{[vsm4k_vi $vk4, $vk3, 4]} # rk[16:19]
91    @{[vsm4k_vi $vk5, $vk4, 5]} # rk[20:23]
92    @{[vsm4k_vi $vk6, $vk5, 6]} # rk[24:27]
93    @{[vsm4k_vi $vk7, $vk6, 7]} # rk[28:31]
94
95    # Store round keys
96    @{[vse32_v $vk0, $keys]} # rk[0:3]
97    addi $keys, $keys, 16
98    @{[vse32_v $vk1, $keys]} # rk[4:7]
99    addi $keys, $keys, 16
100    @{[vse32_v $vk2, $keys]} # rk[8:11]
101    addi $keys, $keys, 16
102    @{[vse32_v $vk3, $keys]} # rk[12:15]
103    addi $keys, $keys, 16
104    @{[vse32_v $vk4, $keys]} # rk[16:19]
105    addi $keys, $keys, 16
106    @{[vse32_v $vk5, $keys]} # rk[20:23]
107    addi $keys, $keys, 16
108    @{[vse32_v $vk6, $keys]} # rk[24:27]
109    addi $keys, $keys, 16
110    @{[vse32_v $vk7, $keys]} # rk[28:31]
111
112    li a0, 1
113    ret
114.size rv64i_zvksed_sm4_set_encrypt_key,.-rv64i_zvksed_sm4_set_encrypt_key
115___
116}
117
118####
119# int rv64i_zvksed_sm4_set_decrypt_key(const unsigned char *userKey,
120#                                      SM4_KEY *key);
121#
122{
123my ($ukey,$keys,$fk,$stride)=("a0","a1","t0","t1");
124my ($vukey,$vfk,$vk0,$vk1,$vk2,$vk3,$vk4,$vk5,$vk6,$vk7)=("v1","v2","v3","v4","v5","v6","v7","v8","v9","v10");
125$code .= <<___;
126.p2align 3
127.globl rv64i_zvksed_sm4_set_decrypt_key
128.type rv64i_zvksed_sm4_set_decrypt_key,\@function
129rv64i_zvksed_sm4_set_decrypt_key:
130    @{[vsetivli__x0_4_e32_m1_tu_mu]}
131
132    # Load the user key
133    @{[vle32_v $vukey, $ukey]}
134    @{[vrev8_v $vukey, $vukey]}
135
136    # Load the FK.
137    la $fk, FK
138    @{[vle32_v $vfk, $fk]}
139
140    # Generate round keys.
141    @{[vxor_vv $vukey, $vukey, $vfk]}
142    @{[vsm4k_vi $vk0, $vukey, 0]} # rk[0:3]
143    @{[vsm4k_vi $vk1, $vk0, 1]} # rk[4:7]
144    @{[vsm4k_vi $vk2, $vk1, 2]} # rk[8:11]
145    @{[vsm4k_vi $vk3, $vk2, 3]} # rk[12:15]
146    @{[vsm4k_vi $vk4, $vk3, 4]} # rk[16:19]
147    @{[vsm4k_vi $vk5, $vk4, 5]} # rk[20:23]
148    @{[vsm4k_vi $vk6, $vk5, 6]} # rk[24:27]
149    @{[vsm4k_vi $vk7, $vk6, 7]} # rk[28:31]
150
151    # Store round keys in reverse order
152    addi $keys, $keys, 12
153    li $stride, -4
154    @{[vsse32_v $vk7, $keys, $stride]} # rk[31:28]
155    addi $keys, $keys, 16
156    @{[vsse32_v $vk6, $keys, $stride]} # rk[27:24]
157    addi $keys, $keys, 16
158    @{[vsse32_v $vk5, $keys, $stride]} # rk[23:20]
159    addi $keys, $keys, 16
160    @{[vsse32_v $vk4, $keys, $stride]} # rk[19:16]
161    addi $keys, $keys, 16
162    @{[vsse32_v $vk3, $keys, $stride]} # rk[15:12]
163    addi $keys, $keys, 16
164    @{[vsse32_v $vk2, $keys, $stride]} # rk[11:8]
165    addi $keys, $keys, 16
166    @{[vsse32_v $vk1, $keys, $stride]} # rk[7:4]
167    addi $keys, $keys, 16
168    @{[vsse32_v $vk0, $keys, $stride]} # rk[3:0]
169
170    li a0, 1
171    ret
172.size rv64i_zvksed_sm4_set_decrypt_key,.-rv64i_zvksed_sm4_set_decrypt_key
173___
174}
175
176####
177# void rv64i_zvksed_sm4_encrypt(const unsigned char *in, unsigned char *out,
178#                               const SM4_KEY *key);
179#
180{
181my ($in,$out,$keys,$stride)=("a0","a1","a2","t0");
182my ($vdata,$vk0,$vk1,$vk2,$vk3,$vk4,$vk5,$vk6,$vk7,$vgen)=("v1","v2","v3","v4","v5","v6","v7","v8","v9","v10");
183$code .= <<___;
184.p2align 3
185.globl rv64i_zvksed_sm4_encrypt
186.type rv64i_zvksed_sm4_encrypt,\@function
187rv64i_zvksed_sm4_encrypt:
188    @{[vsetivli__x0_4_e32_m1_tu_mu]}
189
190    # Order of elements was adjusted in set_encrypt_key()
191    @{[vle32_v $vk0, $keys]} # rk[0:3]
192    addi $keys, $keys, 16
193    @{[vle32_v $vk1, $keys]} # rk[4:7]
194    addi $keys, $keys, 16
195    @{[vle32_v $vk2, $keys]} # rk[8:11]
196    addi $keys, $keys, 16
197    @{[vle32_v $vk3, $keys]} # rk[12:15]
198    addi $keys, $keys, 16
199    @{[vle32_v $vk4, $keys]} # rk[16:19]
200    addi $keys, $keys, 16
201    @{[vle32_v $vk5, $keys]} # rk[20:23]
202    addi $keys, $keys, 16
203    @{[vle32_v $vk6, $keys]} # rk[24:27]
204    addi $keys, $keys, 16
205    @{[vle32_v $vk7, $keys]} # rk[28:31]
206
207    # Load input data
208    @{[vle32_v $vdata, $in]}
209    @{[vrev8_v $vdata, $vdata]}
210
211    # Encrypt with all keys
212    @{[vsm4r_vs $vdata, $vk0]}
213    @{[vsm4r_vs $vdata, $vk1]}
214    @{[vsm4r_vs $vdata, $vk2]}
215    @{[vsm4r_vs $vdata, $vk3]}
216    @{[vsm4r_vs $vdata, $vk4]}
217    @{[vsm4r_vs $vdata, $vk5]}
218    @{[vsm4r_vs $vdata, $vk6]}
219    @{[vsm4r_vs $vdata, $vk7]}
220
221    # Save the ciphertext (in reverse element order)
222    @{[vrev8_v $vdata, $vdata]}
223    li $stride, -4
224    addi $out, $out, 12
225    @{[vsse32_v $vdata, $out, $stride]}
226
227    ret
228.size rv64i_zvksed_sm4_encrypt,.-rv64i_zvksed_sm4_encrypt
229___
230}
231
232####
233# void rv64i_zvksed_sm4_decrypt(const unsigned char *in, unsigned char *out,
234#                               const SM4_KEY *key);
235#
236{
237my ($in,$out,$keys,$stride)=("a0","a1","a2","t0");
238my ($vdata,$vk0,$vk1,$vk2,$vk3,$vk4,$vk5,$vk6,$vk7,$vgen)=("v1","v2","v3","v4","v5","v6","v7","v8","v9","v10");
239$code .= <<___;
240.p2align 3
241.globl rv64i_zvksed_sm4_decrypt
242.type rv64i_zvksed_sm4_decrypt,\@function
243rv64i_zvksed_sm4_decrypt:
244    @{[vsetivli__x0_4_e32_m1_tu_mu]}
245
246    # Order of elements was adjusted in set_decrypt_key()
247    @{[vle32_v $vk7, $keys]} # rk[31:28]
248    addi $keys, $keys, 16
249    @{[vle32_v $vk6, $keys]} # rk[27:24]
250    addi $keys, $keys, 16
251    @{[vle32_v $vk5, $keys]} # rk[23:20]
252    addi $keys, $keys, 16
253    @{[vle32_v $vk4, $keys]} # rk[19:16]
254    addi $keys, $keys, 16
255    @{[vle32_v $vk3, $keys]} # rk[15:11]
256    addi $keys, $keys, 16
257    @{[vle32_v $vk2, $keys]} # rk[11:8]
258    addi $keys, $keys, 16
259    @{[vle32_v $vk1, $keys]} # rk[7:4]
260    addi $keys, $keys, 16
261    @{[vle32_v $vk0, $keys]} # rk[3:0]
262
263    # Load input data
264    @{[vle32_v $vdata, $in]}
265    @{[vrev8_v $vdata, $vdata]}
266
267    # Encrypt with all keys
268    @{[vsm4r_vs $vdata, $vk7]}
269    @{[vsm4r_vs $vdata, $vk6]}
270    @{[vsm4r_vs $vdata, $vk5]}
271    @{[vsm4r_vs $vdata, $vk4]}
272    @{[vsm4r_vs $vdata, $vk3]}
273    @{[vsm4r_vs $vdata, $vk2]}
274    @{[vsm4r_vs $vdata, $vk1]}
275    @{[vsm4r_vs $vdata, $vk0]}
276
277    # Save the ciphertext (in reverse element order)
278    @{[vrev8_v $vdata, $vdata]}
279    li $stride, -4
280    addi $out, $out, 12
281    @{[vsse32_v $vdata, $out, $stride]}
282
283    ret
284.size rv64i_zvksed_sm4_decrypt,.-rv64i_zvksed_sm4_decrypt
285___
286}
287
288$code .= <<___;
289# Family Key (little-endian 32-bit chunks)
290.p2align 3
291FK:
292    .word 0xA3B1BAC6, 0x56AA3350, 0x677D9197, 0xB27022DC
293.size FK,.-FK
294___
295
296print $code;
297
298close STDOUT or die "error closing STDOUT: $!";
299