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# $output is the last argument if it looks like a file (it has an extension) 10# $flavour is the first argument if it doesn't look like a file 11$output = $#ARGV >= 0 && $ARGV[$#ARGV] =~ m|\.\w+$| ? pop : undef; 12$flavour = $#ARGV >= 0 && $ARGV[0] !~ m|\.| ? shift : undef; 13 14$output and open STDOUT,">$output"; 15 16################################################################################ 17# Utility functions to help with keeping track of which registers to stack/ 18# unstack when entering / exiting routines. 19################################################################################ 20{ 21 # Callee-saved registers 22 my @callee_saved = map("x$_",(2,8,9,18..27)); 23 # Caller-saved registers 24 my @caller_saved = map("x$_",(1,5..7,10..17,28..31)); 25 my @must_save; 26 sub use_reg { 27 my $reg = shift; 28 if (grep(/^$reg$/, @callee_saved)) { 29 push(@must_save, $reg); 30 } elsif (!grep(/^$reg$/, @caller_saved)) { 31 # Register is not usable! 32 die("Unusable register ".$reg); 33 } 34 return $reg; 35 } 36 sub use_regs { 37 return map(use_reg("x$_"), @_); 38 } 39 sub save_regs { 40 my $ret = ''; 41 my $stack_reservation = ($#must_save + 1) * 8; 42 my $stack_offset = $stack_reservation; 43 if ($stack_reservation % 16) { 44 $stack_reservation += 8; 45 } 46 $ret.=" addi sp,sp,-$stack_reservation\n"; 47 foreach (@must_save) { 48 $stack_offset -= 8; 49 $ret.=" sd $_,$stack_offset(sp)\n"; 50 } 51 return $ret; 52 } 53 sub load_regs { 54 my $ret = ''; 55 my $stack_reservation = ($#must_save + 1) * 8; 56 my $stack_offset = $stack_reservation; 57 if ($stack_reservation % 16) { 58 $stack_reservation += 8; 59 } 60 foreach (@must_save) { 61 $stack_offset -= 8; 62 $ret.=" ld $_,$stack_offset(sp)\n"; 63 } 64 $ret.=" addi sp,sp,$stack_reservation\n"; 65 return $ret; 66 } 67 sub clear_regs { 68 @must_save = (); 69 } 70} 71 72################################################################################ 73# util for encoding scalar crypto extension instructions 74################################################################################ 75 76my @regs = map("x$_",(0..31)); 77my %reglookup; 78@reglookup{@regs} = @regs; 79 80# Takes a register name, possibly an alias, and converts it to a register index 81# from 0 to 31 82sub read_reg { 83 my $reg = lc shift; 84 if (!exists($reglookup{$reg})) { 85 die("Unknown register ".$reg); 86 } 87 my $regstr = $reglookup{$reg}; 88 if (!($regstr =~ /^x([0-9]+)$/)) { 89 die("Could not process register ".$reg); 90 } 91 return $1; 92} 93 94sub rv64_aes64ds { 95 # Encoding for aes64ds rd, rs1, rs2 instruction on RV64 96 # XXXXXXX_ rs2 _ rs1 _XXX_ rd _XXXXXXX 97 my $template = 0b0011101_00000_00000_000_00000_0110011; 98 my $rd = read_reg shift; 99 my $rs1 = read_reg shift; 100 my $rs2 = read_reg shift; 101 102 return ".word ".($template | ($rs2 << 20) | ($rs1 << 15) | ($rd << 7)); 103} 104 105sub rv64_aes64dsm { 106 # Encoding for aes64dsm rd, rs1, rs2 instruction on RV64 107 # XXXXXXX_ rs2 _ rs1 _XXX_ rd _XXXXXXX 108 my $template = 0b0011111_00000_00000_000_00000_0110011; 109 my $rd = read_reg shift; 110 my $rs1 = read_reg shift; 111 my $rs2 = read_reg shift; 112 113 return ".word ".($template | ($rs2 << 20) | ($rs1 << 15) | ($rd << 7)); 114} 115 116sub rv64_aes64es { 117 # Encoding for aes64es rd, rs1, rs2 instruction on RV64 118 # XXXXXXX_ rs2 _ rs1 _XXX_ rd _XXXXXXX 119 my $template = 0b0011001_00000_00000_000_00000_0110011; 120 my $rd = read_reg shift; 121 my $rs1 = read_reg shift; 122 my $rs2 = read_reg shift; 123 124 return ".word ".($template | ($rs2 << 20) | ($rs1 << 15) | ($rd << 7)); 125} 126 127sub rv64_aes64esm { 128 # Encoding for aes64esm rd, rs1, rs2 instruction on RV64 129 # XXXXXXX_ rs2 _ rs1 _XXX_ rd _XXXXXXX 130 my $template = 0b0011011_00000_00000_000_00000_0110011; 131 my $rd = read_reg shift; 132 my $rs1 = read_reg shift; 133 my $rs2 = read_reg shift; 134 135 return ".word ".($template | ($rs2 << 20) | ($rs1 << 15) | ($rd << 7)); 136} 137 138sub rv64_aes64im { 139 # Encoding for aes64im rd, rs1 instruction on RV64 140 # XXXXXXXXXXXX_ rs1 _XXX_ rd _XXXXXXX 141 my $template = 0b001100000000_00000_001_00000_0010011; 142 my $rd = read_reg shift; 143 my $rs1 = read_reg shift; 144 145 return ".word ".($template | ($rs1 << 15) | ($rd << 7)); 146} 147 148sub rv64_aes64ks1i { 149 # Encoding for aes64ks1i rd, rs1, rnum instruction on RV64 150 # XXXXXXXX_rnum_ rs1 _XXX_ rd _XXXXXXX 151 my $template = 0b00110001_0000_00000_001_00000_0010011; 152 my $rd = read_reg shift; 153 my $rs1 = read_reg shift; 154 my $rnum = shift; 155 156 return ".word ".($template | ($rnum << 20) | ($rs1 << 15) | ($rd << 7)); 157} 158 159sub rv64_aes64ks2 { 160 # Encoding for aes64ks2 rd, rs1, rs2 instruction on RV64 161 # XXXXXXX_ rs2 _ rs1 _XXX_ rd _XXXXXXX 162 my $template = 0b0111111_00000_00000_000_00000_0110011; 163 my $rd = read_reg shift; 164 my $rs1 = read_reg shift; 165 my $rs2 = read_reg shift; 166 167 return ".word ".($template | ($rs2 << 20) | ($rs1 << 15) | ($rd << 7)); 168} 169################################################################################ 170# Register assignment for rv64i_zkne_encrypt and rv64i_zknd_decrypt 171################################################################################ 172 173# Registers to hold AES state (called s0-s3 or y0-y3 elsewhere) 174my ($Q0,$Q1,$Q2,$Q3) = use_regs(6..9); 175 176# Function arguments (x10-x12 are a0-a2 in the ABI) 177# Input block pointer, output block pointer, key pointer 178my ($INP,$OUTP,$KEYP) = use_regs(10..12); 179 180# Temporaries 181my ($T0,$T1) = use_regs(13..14); 182 183# Loop counter 184my ($loopcntr) = use_regs(30); 185 186################################################################################ 187# void rv64i_zkne_encrypt(const unsigned char *in, unsigned char *out, 188# const AES_KEY *key); 189################################################################################ 190my $code .= <<___; 191.text 192.balign 16 193.globl rv64i_zkne_encrypt 194.type rv64i_zkne_encrypt,\@function 195rv64i_zkne_encrypt: 196___ 197 198$code .= save_regs(); 199 200$code .= <<___; 201 202 # Load input to block cipher 203 ld $Q0,0($INP) 204 ld $Q1,8($INP) 205 206 # Load key 207 ld $T0,0($KEYP) 208 ld $T1,8($KEYP) 209 210 # Load number of rounds 211 lwu $loopcntr,240($KEYP) 212 213 # initial transformation 214 xor $Q0,$Q0,$T0 215 xor $Q1,$Q1,$T1 216 217 # The main loop only executes the first N-1 rounds. 218 add $loopcntr,$loopcntr,-1 219 220 # Do Nr - 1 rounds (final round is special) 2211: 222 @{[rv64_aes64esm $Q2,$Q0,$Q1]} 223 @{[rv64_aes64esm $Q3,$Q1,$Q0]} 224 225 # Update key ptr to point to next key in schedule 226 add $KEYP,$KEYP,16 227 228 # Grab next key in schedule 229 ld $T0,0($KEYP) 230 ld $T1,8($KEYP) 231 xor $Q0,$Q2,$T0 232 xor $Q1,$Q3,$T1 233 234 add $loopcntr,$loopcntr,-1 235 bgtz $loopcntr,1b 236 237 # final round 238 @{[rv64_aes64es $Q2,$Q0,$Q1]} 239 @{[rv64_aes64es $Q3,$Q1,$Q0]} 240 241 # since not added 16 before 242 ld $T0,16($KEYP) 243 ld $T1,24($KEYP) 244 xor $Q0,$Q2,$T0 245 xor $Q1,$Q3,$T1 246 247 sd $Q0,0($OUTP) 248 sd $Q1,8($OUTP) 249 250 # Pop registers and return 251___ 252 253$code .= load_regs(); 254 255$code .= <<___; 256 ret 257___ 258 259################################################################################ 260# void rv64i_zknd_decrypt(const unsigned char *in, unsigned char *out, 261# const AES_KEY *key); 262################################################################################ 263$code .= <<___; 264.text 265.balign 16 266.globl rv64i_zknd_decrypt 267.type rv64i_zknd_decrypt,\@function 268rv64i_zknd_decrypt: 269___ 270 271$code .= save_regs(); 272 273$code .= <<___; 274 275 # Load input to block cipher 276 ld $Q0,0($INP) 277 ld $Q1,8($INP) 278 279 # Load number of rounds 280 lwu $loopcntr,240($KEYP) 281 282 # Load the last key 283 slli $T0,$loopcntr,4 284 add $KEYP,$KEYP,$T0 285 ld $T0,0($KEYP) 286 ld $T1,8($KEYP) 287 288 xor $Q0,$Q0,$T0 289 xor $Q1,$Q1,$T1 290 291 # The main loop only executes the first N-1 rounds. 292 add $loopcntr,$loopcntr,-1 293 294 # Do Nr - 1 rounds (final round is special) 2951: 296 @{[rv64_aes64dsm $Q2,$Q0,$Q1]} 297 @{[rv64_aes64dsm $Q3,$Q1,$Q0]} 298 299 # Update key ptr to point to next key in schedule 300 add $KEYP,$KEYP,-16 301 302 # Grab next key in schedule 303 ld $T0,0($KEYP) 304 ld $T1,8($KEYP) 305 xor $Q0,$Q2,$T0 306 xor $Q1,$Q3,$T1 307 308 add $loopcntr,$loopcntr,-1 309 bgtz $loopcntr,1b 310 311 # final round 312 @{[rv64_aes64ds $Q2,$Q0,$Q1]} 313 @{[rv64_aes64ds $Q3,$Q1,$Q0]} 314 315 add $KEYP,$KEYP,-16 316 ld $T0,0($KEYP) 317 ld $T1,8($KEYP) 318 xor $Q0,$Q2,$T0 319 xor $Q1,$Q3,$T1 320 321 sd $Q0,0($OUTP) 322 sd $Q1,8($OUTP) 323 # Pop registers and return 324___ 325 326$code .= load_regs(); 327 328$code .= <<___; 329 ret 330___ 331 332clear_regs(); 333 334################################################################################ 335# Register assignment for rv64i_zkn[e/d]_set_[en/de]crypt_key 336################################################################################ 337 338# Function arguments (x10-x12 are a0-a2 in the ABI) 339# Pointer to user key, number of bits in key, key pointer 340my ($UKEY,$BITS,$KEYP) = use_regs(10..12); 341 342# Temporaries 343my ($T0,$T1,$T2,$T3,$T4) = use_regs(6..8,13..14); 344 345################################################################################ 346# utility functions for rv64i_zkne_set_encrypt_key 347################################################################################ 348sub ke128enc { 349 my $rnum = 0; 350 my $ret = ''; 351$ret .= <<___; 352 ld $T0,0($UKEY) 353 ld $T1,8($UKEY) 354 sd $T0,0($KEYP) 355 sd $T1,8($KEYP) 356___ 357 while($rnum < 10) { 358$ret .= <<___; 359 @{[rv64_aes64ks1i $T2,$T1,$rnum]} 360 @{[rv64_aes64ks2 $T0,$T2,$T0]} 361 @{[rv64_aes64ks2 $T1,$T0,$T1]} 362 add $KEYP,$KEYP,16 363 sd $T0,0($KEYP) 364 sd $T1,8($KEYP) 365___ 366 $rnum++; 367 } 368 return $ret; 369} 370 371sub ke192enc { 372 my $rnum = 0; 373 my $ret = ''; 374$ret .= <<___; 375 ld $T0,0($UKEY) 376 ld $T1,8($UKEY) 377 ld $T2,16($UKEY) 378 sd $T0,0($KEYP) 379 sd $T1,8($KEYP) 380 sd $T2,16($KEYP) 381___ 382 while($rnum < 8) { 383$ret .= <<___; 384 @{[rv64_aes64ks1i $T3,$T2,$rnum]} 385 @{[rv64_aes64ks2 $T0,$T3,$T0]} 386 @{[rv64_aes64ks2 $T1,$T0,$T1]} 387___ 388 if ($rnum != 7) { 389 # note that (8+1)*24 = 216, (12+1)*16 = 208 390 # thus the last 8 bytes can be dropped 391$ret .= <<___; 392 @{[rv64_aes64ks2 $T2,$T1,$T2]} 393___ 394 } 395$ret .= <<___; 396 add $KEYP,$KEYP,24 397 sd $T0,0($KEYP) 398 sd $T1,8($KEYP) 399___ 400 if ($rnum != 7) { 401$ret .= <<___; 402 sd $T2,16($KEYP) 403___ 404 } 405 $rnum++; 406 } 407 return $ret; 408} 409 410sub ke256enc { 411 my $rnum = 0; 412 my $ret = ''; 413$ret .= <<___; 414 ld $T0,0($UKEY) 415 ld $T1,8($UKEY) 416 ld $T2,16($UKEY) 417 ld $T3,24($UKEY) 418 sd $T0,0($KEYP) 419 sd $T1,8($KEYP) 420 sd $T2,16($KEYP) 421 sd $T3,24($KEYP) 422___ 423 while($rnum < 7) { 424$ret .= <<___; 425 @{[rv64_aes64ks1i $T4,$T3,$rnum]} 426 @{[rv64_aes64ks2 $T0,$T4,$T0]} 427 @{[rv64_aes64ks2 $T1,$T0,$T1]} 428 add $KEYP,$KEYP,32 429 sd $T0,0($KEYP) 430 sd $T1,8($KEYP) 431___ 432 if ($rnum != 6) { 433 # note that (7+1)*32 = 256, (14+1)*16 = 240 434 # thus the last 16 bytes can be dropped 435$ret .= <<___; 436 @{[rv64_aes64ks1i $T4,$T1,0xA]} 437 @{[rv64_aes64ks2 $T2,$T4,$T2]} 438 @{[rv64_aes64ks2 $T3,$T2,$T3]} 439 sd $T2,16($KEYP) 440 sd $T3,24($KEYP) 441___ 442 } 443 $rnum++; 444 } 445 return $ret; 446} 447 448################################################################################ 449# void rv64i_zkne_set_encrypt_key(const unsigned char *userKey, const int bits, 450# AES_KEY *key) 451################################################################################ 452sub AES_set_common { 453 my ($ke128, $ke192, $ke256) = @_; 454 my $ret = ''; 455$ret .= <<___; 456 bnez $UKEY,1f # if (!userKey || !key) return -1; 457 bnez $KEYP,1f 458 li a0,-1 459 ret 4601: 461 # Determine number of rounds from key size in bits 462 li $T0,128 463 bne $BITS,$T0,1f 464 li $T1,10 # key->rounds = 10 if bits == 128 465 sw $T1,240($KEYP) # store key->rounds 466$ke128 467 j 4f 4681: 469 li $T0,192 470 bne $BITS,$T0,2f 471 li $T1,12 # key->rounds = 12 if bits == 192 472 sw $T1,240($KEYP) # store key->rounds 473$ke192 474 j 4f 4752: 476 li $T1,14 # key->rounds = 14 if bits == 256 477 li $T0,256 478 beq $BITS,$T0,3f 479 li a0,-2 # If bits != 128, 192, or 256, return -2 480 j 5f 4813: 482 sw $T1,240($KEYP) # store key->rounds 483$ke256 4844: # return 0 485 li a0,0 4865: # return a0 487___ 488 return $ret; 489} 490$code .= <<___; 491.text 492.balign 16 493.globl rv64i_zkne_set_encrypt_key 494.type rv64i_zkne_set_encrypt_key,\@function 495rv64i_zkne_set_encrypt_key: 496___ 497$code .= save_regs(); 498$code .= AES_set_common(ke128enc(), ke192enc(),ke256enc()); 499$code .= load_regs(); 500$code .= <<___; 501 ret 502___ 503 504################################################################################ 505# utility functions for rv64i_zknd_set_decrypt_key 506################################################################################ 507sub ke128dec { 508 my $rnum = 0; 509 my $ret = ''; 510$ret .= <<___; 511 ld $T0,0($UKEY) 512 ld $T1,8($UKEY) 513 sd $T0,0($KEYP) 514 sd $T1,8($KEYP) 515___ 516 while($rnum < 10) { 517$ret .= <<___; 518 @{[rv64_aes64ks1i $T2,$T1,$rnum]} 519 @{[rv64_aes64ks2 $T0,$T2,$T0]} 520 @{[rv64_aes64ks2 $T1,$T0,$T1]} 521 add $KEYP,$KEYP,16 522___ 523 # need to aes64im for [1:N-1] round keys 524 # this is from the fact that aes64dsm subwords first then mix column 525 # intuitively decryption needs to first mix column then subwords 526 # however, for merging datapaths (encryption first subwords then mix column) 527 # aes64dsm chooses to inverse the order of them, thus 528 # transform should then be done on the round key 529 if ($rnum < 9) { 530$ret .= <<___; 531 @{[rv64_aes64im $T2,$T0]} 532 sd $T2,0($KEYP) 533 @{[rv64_aes64im $T2,$T1]} 534 sd $T2,8($KEYP) 535___ 536 } else { 537$ret .= <<___; 538 sd $T0,0($KEYP) 539 sd $T1,8($KEYP) 540___ 541 } 542 $rnum++; 543 } 544 return $ret; 545} 546 547sub ke192dec { 548 my $rnum = 0; 549 my $ret = ''; 550$ret .= <<___; 551 ld $T0,0($UKEY) 552 ld $T1,8($UKEY) 553 ld $T2,16($UKEY) 554 sd $T0,0($KEYP) 555 sd $T1,8($KEYP) 556 @{[rv64_aes64im $T3,$T2]} 557 sd $T3,16($KEYP) 558___ 559 while($rnum < 8) { 560$ret .= <<___; 561 @{[rv64_aes64ks1i $T3,$T2,$rnum]} 562 @{[rv64_aes64ks2 $T0,$T3,$T0]} 563 @{[rv64_aes64ks2 $T1,$T0,$T1]} 564 add $KEYP,$KEYP,24 565___ 566 if ($rnum < 7) { 567$ret .= <<___; 568 @{[rv64_aes64im $T3,$T0]} 569 sd $T3,0($KEYP) 570 @{[rv64_aes64im $T3,$T1]} 571 sd $T3,8($KEYP) 572 # the reason is in ke192enc 573 @{[rv64_aes64ks2 $T2,$T1,$T2]} 574 @{[rv64_aes64im $T3,$T2]} 575 sd $T3,16($KEYP) 576___ 577 } else { # rnum == 7 578$ret .= <<___; 579 sd $T0,0($KEYP) 580 sd $T1,8($KEYP) 581___ 582 } 583 $rnum++; 584 } 585 return $ret; 586} 587 588sub ke256dec { 589 my $rnum = 0; 590 my $ret = ''; 591$ret .= <<___; 592 ld $T0,0($UKEY) 593 ld $T1,8($UKEY) 594 ld $T2,16($UKEY) 595 ld $T3,24($UKEY) 596 sd $T0,0($KEYP) 597 sd $T1,8($KEYP) 598 @{[rv64_aes64im $T4,$T2]} 599 sd $T4,16($KEYP) 600 @{[rv64_aes64im $T4,$T3]} 601 sd $T4,24($KEYP) 602___ 603 while($rnum < 7) { 604$ret .= <<___; 605 @{[rv64_aes64ks1i $T4,$T3,$rnum]} 606 @{[rv64_aes64ks2 $T0,$T4,$T0]} 607 @{[rv64_aes64ks2 $T1,$T0,$T1]} 608 add $KEYP,$KEYP,32 609___ 610 if ($rnum < 6) { 611$ret .= <<___; 612 @{[rv64_aes64ks1i $T4,$T1,0xA]} 613 @{[rv64_aes64ks2 $T2,$T4,$T2]} 614 @{[rv64_aes64ks2 $T3,$T2,$T3]} 615 @{[rv64_aes64im $T4,$T0]} 616 sd $T4,0($KEYP) 617 @{[rv64_aes64im $T4,$T1]} 618 sd $T4,8($KEYP) 619 @{[rv64_aes64im $T4,$T2]} 620 sd $T4,16($KEYP) 621 @{[rv64_aes64im $T4,$T3]} 622 sd $T4,24($KEYP) 623___ 624 } else { 625$ret .= <<___; 626 sd $T0,0($KEYP) 627 sd $T1,8($KEYP) 628 # last two one dropped 629___ 630 } 631 $rnum++; 632 } 633 return $ret; 634} 635 636################################################################################ 637# void rv64i_zknd_set_decrypt_key(const unsigned char *userKey, const int bits, 638# AES_KEY *key) 639################################################################################ 640$code .= <<___; 641.text 642.balign 16 643.globl rv64i_zknd_set_decrypt_key 644.type rv64i_zknd_set_decrypt_key,\@function 645rv64i_zknd_set_decrypt_key: 646___ 647$code .= save_regs(); 648$code .= AES_set_common(ke128dec(), ke192dec(),ke256dec()); 649$code .= load_regs(); 650$code .= <<___; 651 ret 652___ 653 654print $code; 655close STDOUT or die "error closing STDOUT: $!"; 656