aes-riscv64-zkn.pl 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594
  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 2022-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) 2022, Hongren (Zenithal) Zheng <i@zenithal.me>
  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. use strict;
  37. use warnings;
  38. use FindBin qw($Bin);
  39. use lib "$Bin";
  40. use lib "$Bin/../../perlasm";
  41. use riscv;
  42. # $output is the last argument if it looks like a file (it has an extension)
  43. # $flavour is the first argument if it doesn't look like a file
  44. my $output = $#ARGV >= 0 && $ARGV[$#ARGV] =~ m|\.\w+$| ? pop : undef;
  45. my $flavour = $#ARGV >= 0 && $ARGV[0] !~ m|\.| ? shift : undef;
  46. $output and open STDOUT,">$output";
  47. ################################################################################
  48. # Utility functions to help with keeping track of which registers to stack/
  49. # unstack when entering / exiting routines.
  50. ################################################################################
  51. {
  52. # Callee-saved registers
  53. my @callee_saved = map("x$_",(2,8,9,18..27));
  54. # Caller-saved registers
  55. my @caller_saved = map("x$_",(1,5..7,10..17,28..31));
  56. my @must_save;
  57. sub use_reg {
  58. my $reg = shift;
  59. if (grep(/^$reg$/, @callee_saved)) {
  60. push(@must_save, $reg);
  61. } elsif (!grep(/^$reg$/, @caller_saved)) {
  62. # Register is not usable!
  63. die("Unusable register ".$reg);
  64. }
  65. return $reg;
  66. }
  67. sub use_regs {
  68. return map(use_reg("x$_"), @_);
  69. }
  70. sub save_regs {
  71. my $ret = '';
  72. my $stack_reservation = ($#must_save + 1) * 8;
  73. my $stack_offset = $stack_reservation;
  74. if ($stack_reservation % 16) {
  75. $stack_reservation += 8;
  76. }
  77. $ret.=" addi sp,sp,-$stack_reservation\n";
  78. foreach (@must_save) {
  79. $stack_offset -= 8;
  80. $ret.=" sd $_,$stack_offset(sp)\n";
  81. }
  82. return $ret;
  83. }
  84. sub load_regs {
  85. my $ret = '';
  86. my $stack_reservation = ($#must_save + 1) * 8;
  87. my $stack_offset = $stack_reservation;
  88. if ($stack_reservation % 16) {
  89. $stack_reservation += 8;
  90. }
  91. foreach (@must_save) {
  92. $stack_offset -= 8;
  93. $ret.=" ld $_,$stack_offset(sp)\n";
  94. }
  95. $ret.=" addi sp,sp,$stack_reservation\n";
  96. return $ret;
  97. }
  98. sub clear_regs {
  99. @must_save = ();
  100. }
  101. }
  102. ################################################################################
  103. # Register assignment for rv64i_zkne_encrypt and rv64i_zknd_decrypt
  104. ################################################################################
  105. # Registers to hold AES state (called s0-s3 or y0-y3 elsewhere)
  106. my ($Q0,$Q1,$Q2,$Q3) = use_regs(6..9);
  107. # Function arguments (x10-x12 are a0-a2 in the ABI)
  108. # Input block pointer, output block pointer, key pointer
  109. my ($INP,$OUTP,$KEYP) = use_regs(10..12);
  110. # Temporaries
  111. my ($T0,$T1) = use_regs(13..14);
  112. # Loop counter
  113. my ($loopcntr) = use_regs(30);
  114. ################################################################################
  115. # void rv64i_zkne_encrypt(const unsigned char *in, unsigned char *out,
  116. # const AES_KEY *key);
  117. ################################################################################
  118. my $code .= <<___;
  119. .text
  120. .balign 16
  121. .globl rv64i_zkne_encrypt
  122. .type rv64i_zkne_encrypt,\@function
  123. rv64i_zkne_encrypt:
  124. ___
  125. $code .= save_regs();
  126. $code .= <<___;
  127. # Load input to block cipher
  128. ld $Q0,0($INP)
  129. ld $Q1,8($INP)
  130. # Load key
  131. ld $T0,0($KEYP)
  132. ld $T1,8($KEYP)
  133. # Load number of rounds
  134. lwu $loopcntr,240($KEYP)
  135. # initial transformation
  136. xor $Q0,$Q0,$T0
  137. xor $Q1,$Q1,$T1
  138. # The main loop only executes the first N-1 rounds.
  139. add $loopcntr,$loopcntr,-1
  140. # Do Nr - 1 rounds (final round is special)
  141. 1:
  142. @{[aes64esm $Q2,$Q0,$Q1]}
  143. @{[aes64esm $Q3,$Q1,$Q0]}
  144. # Update key ptr to point to next key in schedule
  145. add $KEYP,$KEYP,16
  146. # Grab next key in schedule
  147. ld $T0,0($KEYP)
  148. ld $T1,8($KEYP)
  149. xor $Q0,$Q2,$T0
  150. xor $Q1,$Q3,$T1
  151. add $loopcntr,$loopcntr,-1
  152. bgtz $loopcntr,1b
  153. # final round
  154. @{[aes64es $Q2,$Q0,$Q1]}
  155. @{[aes64es $Q3,$Q1,$Q0]}
  156. # since not added 16 before
  157. ld $T0,16($KEYP)
  158. ld $T1,24($KEYP)
  159. xor $Q0,$Q2,$T0
  160. xor $Q1,$Q3,$T1
  161. sd $Q0,0($OUTP)
  162. sd $Q1,8($OUTP)
  163. # Pop registers and return
  164. ___
  165. $code .= load_regs();
  166. $code .= <<___;
  167. ret
  168. ___
  169. ################################################################################
  170. # void rv64i_zknd_decrypt(const unsigned char *in, unsigned char *out,
  171. # const AES_KEY *key);
  172. ################################################################################
  173. $code .= <<___;
  174. .text
  175. .balign 16
  176. .globl rv64i_zknd_decrypt
  177. .type rv64i_zknd_decrypt,\@function
  178. rv64i_zknd_decrypt:
  179. ___
  180. $code .= save_regs();
  181. $code .= <<___;
  182. # Load input to block cipher
  183. ld $Q0,0($INP)
  184. ld $Q1,8($INP)
  185. # Load number of rounds
  186. lwu $loopcntr,240($KEYP)
  187. # Load the last key
  188. slli $T0,$loopcntr,4
  189. add $KEYP,$KEYP,$T0
  190. ld $T0,0($KEYP)
  191. ld $T1,8($KEYP)
  192. xor $Q0,$Q0,$T0
  193. xor $Q1,$Q1,$T1
  194. # The main loop only executes the first N-1 rounds.
  195. add $loopcntr,$loopcntr,-1
  196. # Do Nr - 1 rounds (final round is special)
  197. 1:
  198. @{[aes64dsm $Q2,$Q0,$Q1]}
  199. @{[aes64dsm $Q3,$Q1,$Q0]}
  200. # Update key ptr to point to next key in schedule
  201. add $KEYP,$KEYP,-16
  202. # Grab next key in schedule
  203. ld $T0,0($KEYP)
  204. ld $T1,8($KEYP)
  205. xor $Q0,$Q2,$T0
  206. xor $Q1,$Q3,$T1
  207. add $loopcntr,$loopcntr,-1
  208. bgtz $loopcntr,1b
  209. # final round
  210. @{[aes64ds $Q2,$Q0,$Q1]}
  211. @{[aes64ds $Q3,$Q1,$Q0]}
  212. add $KEYP,$KEYP,-16
  213. ld $T0,0($KEYP)
  214. ld $T1,8($KEYP)
  215. xor $Q0,$Q2,$T0
  216. xor $Q1,$Q3,$T1
  217. sd $Q0,0($OUTP)
  218. sd $Q1,8($OUTP)
  219. # Pop registers and return
  220. ___
  221. $code .= load_regs();
  222. $code .= <<___;
  223. ret
  224. ___
  225. clear_regs();
  226. ################################################################################
  227. # Register assignment for rv64i_zkn[e/d]_set_[en/de]crypt_key
  228. ################################################################################
  229. # Function arguments (x10-x12 are a0-a2 in the ABI)
  230. # Pointer to user key, number of bits in key, key pointer
  231. my ($UKEY,$BITS,$KEYP) = use_regs(10..12);
  232. # Temporaries
  233. my ($T0,$T1,$T2,$T3,$T4) = use_regs(6..8,13..14);
  234. ################################################################################
  235. # utility functions for rv64i_zkne_set_encrypt_key
  236. ################################################################################
  237. sub ke128enc {
  238. my $rnum = 0;
  239. my $ret = '';
  240. $ret .= <<___;
  241. ld $T0,0($UKEY)
  242. ld $T1,8($UKEY)
  243. sd $T0,0($KEYP)
  244. sd $T1,8($KEYP)
  245. ___
  246. while($rnum < 10) {
  247. $ret .= <<___;
  248. @{[aes64ks1i $T2,$T1,$rnum]}
  249. @{[aes64ks2 $T0,$T2,$T0]}
  250. @{[aes64ks2 $T1,$T0,$T1]}
  251. add $KEYP,$KEYP,16
  252. sd $T0,0($KEYP)
  253. sd $T1,8($KEYP)
  254. ___
  255. $rnum++;
  256. }
  257. return $ret;
  258. }
  259. sub ke192enc {
  260. my $rnum = 0;
  261. my $ret = '';
  262. $ret .= <<___;
  263. ld $T0,0($UKEY)
  264. ld $T1,8($UKEY)
  265. ld $T2,16($UKEY)
  266. sd $T0,0($KEYP)
  267. sd $T1,8($KEYP)
  268. sd $T2,16($KEYP)
  269. ___
  270. while($rnum < 8) {
  271. $ret .= <<___;
  272. @{[aes64ks1i $T3,$T2,$rnum]}
  273. @{[aes64ks2 $T0,$T3,$T0]}
  274. @{[aes64ks2 $T1,$T0,$T1]}
  275. ___
  276. if ($rnum != 7) {
  277. # note that (8+1)*24 = 216, (12+1)*16 = 208
  278. # thus the last 8 bytes can be dropped
  279. $ret .= <<___;
  280. @{[aes64ks2 $T2,$T1,$T2]}
  281. ___
  282. }
  283. $ret .= <<___;
  284. add $KEYP,$KEYP,24
  285. sd $T0,0($KEYP)
  286. sd $T1,8($KEYP)
  287. ___
  288. if ($rnum != 7) {
  289. $ret .= <<___;
  290. sd $T2,16($KEYP)
  291. ___
  292. }
  293. $rnum++;
  294. }
  295. return $ret;
  296. }
  297. sub ke256enc {
  298. my $rnum = 0;
  299. my $ret = '';
  300. $ret .= <<___;
  301. ld $T0,0($UKEY)
  302. ld $T1,8($UKEY)
  303. ld $T2,16($UKEY)
  304. ld $T3,24($UKEY)
  305. sd $T0,0($KEYP)
  306. sd $T1,8($KEYP)
  307. sd $T2,16($KEYP)
  308. sd $T3,24($KEYP)
  309. ___
  310. while($rnum < 7) {
  311. $ret .= <<___;
  312. @{[aes64ks1i $T4,$T3,$rnum]}
  313. @{[aes64ks2 $T0,$T4,$T0]}
  314. @{[aes64ks2 $T1,$T0,$T1]}
  315. add $KEYP,$KEYP,32
  316. sd $T0,0($KEYP)
  317. sd $T1,8($KEYP)
  318. ___
  319. if ($rnum != 6) {
  320. # note that (7+1)*32 = 256, (14+1)*16 = 240
  321. # thus the last 16 bytes can be dropped
  322. $ret .= <<___;
  323. @{[aes64ks1i $T4,$T1,0xA]}
  324. @{[aes64ks2 $T2,$T4,$T2]}
  325. @{[aes64ks2 $T3,$T2,$T3]}
  326. sd $T2,16($KEYP)
  327. sd $T3,24($KEYP)
  328. ___
  329. }
  330. $rnum++;
  331. }
  332. return $ret;
  333. }
  334. ################################################################################
  335. # void rv64i_zkne_set_encrypt_key(const unsigned char *userKey, const int bits,
  336. # AES_KEY *key)
  337. ################################################################################
  338. sub AES_set_common {
  339. my ($ke128, $ke192, $ke256) = @_;
  340. my $ret = '';
  341. $ret .= <<___;
  342. bnez $UKEY,1f # if (!userKey || !key) return -1;
  343. bnez $KEYP,1f
  344. li a0,-1
  345. ret
  346. 1:
  347. # Determine number of rounds from key size in bits
  348. li $T0,128
  349. bne $BITS,$T0,1f
  350. li $T1,10 # key->rounds = 10 if bits == 128
  351. sw $T1,240($KEYP) # store key->rounds
  352. $ke128
  353. j 4f
  354. 1:
  355. li $T0,192
  356. bne $BITS,$T0,2f
  357. li $T1,12 # key->rounds = 12 if bits == 192
  358. sw $T1,240($KEYP) # store key->rounds
  359. $ke192
  360. j 4f
  361. 2:
  362. li $T1,14 # key->rounds = 14 if bits == 256
  363. li $T0,256
  364. beq $BITS,$T0,3f
  365. li a0,-2 # If bits != 128, 192, or 256, return -2
  366. j 5f
  367. 3:
  368. sw $T1,240($KEYP) # store key->rounds
  369. $ke256
  370. 4: # return 0
  371. li a0,0
  372. 5: # return a0
  373. ___
  374. return $ret;
  375. }
  376. $code .= <<___;
  377. .text
  378. .balign 16
  379. .globl rv64i_zkne_set_encrypt_key
  380. .type rv64i_zkne_set_encrypt_key,\@function
  381. rv64i_zkne_set_encrypt_key:
  382. ___
  383. $code .= save_regs();
  384. $code .= AES_set_common(ke128enc(), ke192enc(),ke256enc());
  385. $code .= load_regs();
  386. $code .= <<___;
  387. ret
  388. ___
  389. ################################################################################
  390. # utility functions for rv64i_zknd_set_decrypt_key
  391. ################################################################################
  392. sub ke128dec {
  393. my $rnum = 0;
  394. my $ret = '';
  395. $ret .= <<___;
  396. ld $T0,0($UKEY)
  397. ld $T1,8($UKEY)
  398. sd $T0,0($KEYP)
  399. sd $T1,8($KEYP)
  400. ___
  401. while($rnum < 10) {
  402. $ret .= <<___;
  403. @{[aes64ks1i $T2,$T1,$rnum]}
  404. @{[aes64ks2 $T0,$T2,$T0]}
  405. @{[aes64ks2 $T1,$T0,$T1]}
  406. add $KEYP,$KEYP,16
  407. ___
  408. # need to aes64im for [1:N-1] round keys
  409. # this is from the fact that aes64dsm subwords first then mix column
  410. # intuitively decryption needs to first mix column then subwords
  411. # however, for merging datapaths (encryption first subwords then mix column)
  412. # aes64dsm chooses to inverse the order of them, thus
  413. # transform should then be done on the round key
  414. if ($rnum < 9) {
  415. $ret .= <<___;
  416. @{[aes64im $T2,$T0]}
  417. sd $T2,0($KEYP)
  418. @{[aes64im $T2,$T1]}
  419. sd $T2,8($KEYP)
  420. ___
  421. } else {
  422. $ret .= <<___;
  423. sd $T0,0($KEYP)
  424. sd $T1,8($KEYP)
  425. ___
  426. }
  427. $rnum++;
  428. }
  429. return $ret;
  430. }
  431. sub ke192dec {
  432. my $rnum = 0;
  433. my $ret = '';
  434. $ret .= <<___;
  435. ld $T0,0($UKEY)
  436. ld $T1,8($UKEY)
  437. ld $T2,16($UKEY)
  438. sd $T0,0($KEYP)
  439. sd $T1,8($KEYP)
  440. @{[aes64im $T3,$T2]}
  441. sd $T3,16($KEYP)
  442. ___
  443. while($rnum < 8) {
  444. $ret .= <<___;
  445. @{[aes64ks1i $T3,$T2,$rnum]}
  446. @{[aes64ks2 $T0,$T3,$T0]}
  447. @{[aes64ks2 $T1,$T0,$T1]}
  448. add $KEYP,$KEYP,24
  449. ___
  450. if ($rnum < 7) {
  451. $ret .= <<___;
  452. @{[aes64im $T3,$T0]}
  453. sd $T3,0($KEYP)
  454. @{[aes64im $T3,$T1]}
  455. sd $T3,8($KEYP)
  456. # the reason is in ke192enc
  457. @{[aes64ks2 $T2,$T1,$T2]}
  458. @{[aes64im $T3,$T2]}
  459. sd $T3,16($KEYP)
  460. ___
  461. } else { # rnum == 7
  462. $ret .= <<___;
  463. sd $T0,0($KEYP)
  464. sd $T1,8($KEYP)
  465. ___
  466. }
  467. $rnum++;
  468. }
  469. return $ret;
  470. }
  471. sub ke256dec {
  472. my $rnum = 0;
  473. my $ret = '';
  474. $ret .= <<___;
  475. ld $T0,0($UKEY)
  476. ld $T1,8($UKEY)
  477. ld $T2,16($UKEY)
  478. ld $T3,24($UKEY)
  479. sd $T0,0($KEYP)
  480. sd $T1,8($KEYP)
  481. @{[aes64im $T4,$T2]}
  482. sd $T4,16($KEYP)
  483. @{[aes64im $T4,$T3]}
  484. sd $T4,24($KEYP)
  485. ___
  486. while($rnum < 7) {
  487. $ret .= <<___;
  488. @{[aes64ks1i $T4,$T3,$rnum]}
  489. @{[aes64ks2 $T0,$T4,$T0]}
  490. @{[aes64ks2 $T1,$T0,$T1]}
  491. add $KEYP,$KEYP,32
  492. ___
  493. if ($rnum < 6) {
  494. $ret .= <<___;
  495. @{[aes64ks1i $T4,$T1,0xA]}
  496. @{[aes64ks2 $T2,$T4,$T2]}
  497. @{[aes64ks2 $T3,$T2,$T3]}
  498. @{[aes64im $T4,$T0]}
  499. sd $T4,0($KEYP)
  500. @{[aes64im $T4,$T1]}
  501. sd $T4,8($KEYP)
  502. @{[aes64im $T4,$T2]}
  503. sd $T4,16($KEYP)
  504. @{[aes64im $T4,$T3]}
  505. sd $T4,24($KEYP)
  506. ___
  507. } else {
  508. $ret .= <<___;
  509. sd $T0,0($KEYP)
  510. sd $T1,8($KEYP)
  511. # last two one dropped
  512. ___
  513. }
  514. $rnum++;
  515. }
  516. return $ret;
  517. }
  518. ################################################################################
  519. # void rv64i_zknd_set_decrypt_key(const unsigned char *userKey, const int bits,
  520. # AES_KEY *key)
  521. ################################################################################
  522. $code .= <<___;
  523. .text
  524. .balign 16
  525. .globl rv64i_zknd_set_decrypt_key
  526. .type rv64i_zknd_set_decrypt_key,\@function
  527. rv64i_zknd_set_decrypt_key:
  528. ___
  529. $code .= save_regs();
  530. $code .= AES_set_common(ke128dec(), ke192dec(),ke256dec());
  531. $code .= load_regs();
  532. $code .= <<___;
  533. ret
  534. ___
  535. print $code;
  536. close STDOUT or die "error closing STDOUT: $!";