From 13baec7846a765844796499a4187ad1f91ed3af0 Mon Sep 17 00:00:00 2001 From: zhoulu Date: Tue, 21 Jul 2026 09:31:13 +0800 Subject: [PATCH] Performance optimization of SM4-XTS encryption and decryption on RISC-V This module implements hardware instruction acceleration for SM4-XTS encryption and decryption calculations. Code from the OpenAnolis community at https://gitee.com/src-anolis-os/openssl/pulls, jointly developed by Alibaba DAMO Academy and ZTE. Hardware simulation environment verification data: Encrypt Test Baseline Optimized Improvement ratio 16 bytes 7678.64k 9123.29k 19% 64 bytes 13388.16k 27949.34k 109% 256 bytes 16292.61k 60993.07k 274% 1024 bytes 17157.58k 67229.52k 292% 8192 bytes 17506.3k 73404.54k 319% 16384 bytes 17503.3k 73679.28k 321% Decrypt Test Baseline Optimized Improvement ratio 16 bytes 7571.44k 10867.31k 44% 64 bytes 13108.21k 31051.57k 137% 256 bytes 16308.99k 59285.31k 264% 1024 bytes 17143.38k 70561.16k 312% 8192 bytes 17612.8k 73996.33k 320% 16384 bytes 17661.95k 74066.56k 319% Test Verification All relevant tests pass in the default build configuration: make test 99-test_fuzz_x509.t ...................... ok All tests successful. Files=350, Tests=4030, 7925 wallclock secs (93.00 usr 24.55 sys + 5698.70 cusr 1960.42 csys = 7776.67 CPU) Result: PASS --- .../workflows/riscv-more-cross-compiles.yml | 14 + crypto/perlasm/riscv.pm | 20 + .../sm4/asm/sm4-riscv64-zvbb-zvkg-zvksed.pl | 852 ++++++++++++++++++ crypto/sm4/build.info | 3 +- include/crypto/sm4_platform.h | 24 + .../ciphers/cipher_sm4_xts_hw_rv64i.inc | 43 +- 6 files changed, 949 insertions(+), 7 deletions(-) create mode 100644 crypto/sm4/asm/sm4-riscv64-zvbb-zvkg-zvksed.pl diff --git a/.github/workflows/riscv-more-cross-compiles.yml b/.github/workflows/riscv-more-cross-compiles.yml index cac662b8d34fc..59bdbf41d81e9 100644 --- a/.github/workflows/riscv-more-cross-compiles.yml +++ b/.github/workflows/riscv-more-cross-compiles.yml @@ -149,6 +149,7 @@ jobs: # crypto/chacha/chacha_riscv.c (with ZVKB) # crypto/modes/gcm128.c (with ZVKG/ZVKB) # crypto/sm3/asm/sm3-riscv64-zvksh.pl + # crypto/sm4/asm/sm4-riscv64-zvbb-zvkg-zvksed.pl # crypto/sm4/asm/sm4-riscv64-zvksed.pl # crypto/aes/asm/aes-riscv64-zvbb-zvkg-zvkned.pl # crypto/aes/asm/aes-riscv64-zvkb-zvkned.pl @@ -164,6 +165,19 @@ jobs: qemucpu: "rv64,zba=true,zbb=true,zbc=true,zbs=true,zbkb=true,zbkc=true,zbkx=true,zknd=true,zkne=true,zknh=true,zksed=true,zksh=true,zkr=true,zkt=true,v=true,vlen=128,zvbb=true,zvbc=true,zvkb=true,zvkg=true,zvkned=true,zvknha=true,zvknhb=true,zvksed=true,zvksh=true", opensslcapsname: riscvcap, # OPENSSL_riscvcap opensslcaps: "rv64gc_zba_zbb_zbc_zbs_zbkb_zbkc_zbkx_zknd_zkne_zknh_zksed_zksh_zkr_zkt_v_zvbb_zvbc_zvkb_zvkg_zvkned_zvknha_zvknhb_zvksed_zvksh" + }, { + # RV64GC with ZVKB and ZVKSED + # crypto/sm4/asm/sm4-riscv64-zvksed.pl + arch: riscv64-linux-gnu, + libs: libc6-dev-riscv64-cross, + target: linux64-riscv64, + fips: no, + # do not use zvkb flag for qemucpu as ubuntu-latest (24.04) uses QEMU 8.2.2 + # see https://lists.nongnu.org/archive/html/qemu-devel/2024-05/msg02231.html + # Should be zvkb=true,zvksed=true + qemucpu: "rv64,v=true,vlen=128,zvbb=true,zvksed=true", + opensslcapsname: riscvcap, # OPENSSL_riscvcap + opensslcaps: "rv64gc_zvkb_zvksed" }, { # RV64GC with all currently OpenSSL-supported extensions, with zvl256 # crypto/sha/asm/sha512-riscv64-zvkb-zvknhb.pl diff --git a/crypto/perlasm/riscv.pm b/crypto/perlasm/riscv.pm index 5d62f3a660df7..10af559ebdb2a 100644 --- a/crypto/perlasm/riscv.pm +++ b/crypto/perlasm/riscv.pm @@ -488,6 +488,17 @@ sub vadd_vx { return ".word ".($template | ($vm << 25) | ($vs2 << 20) | ($rs1 << 15) | ($vd << 7)); } +sub vand_vi { + # vand.vi vd, vs2, uimm + my $template = 0b0_010011_00000_00000_011_00000_1010111; + my $vd = read_vreg shift; # vd (vN) -> [7:11] + my $vs2 = read_vreg shift; # vs2 (vN) -> [20:24] + my $uimm = shift; # uimm (imm5) -> [15:19] + my $uimm_i4_0 = $uimm & 0b11111; + + return ".word ".($template | ($vs2 << 20) | ($uimm_i4_0 << 15) | ($vd << 7)); +} + sub vsub_vv { # vsub.vv vd, vs2, vs1, vm my $template = 0b000010_0_00000_00000_000_00000_1010111; @@ -1129,4 +1140,13 @@ sub vrgather_vv{ return ".word ".($template | ($vs2 << 20) | ($vs1 << 15 ) | ($vd << 7)); } +sub vrgatherei16_vv{ + # vrgatherei16.vv vd, vs2, vs1 + my $template = 0b0011101_00000_00000_000_00000_1010111; + my $vd = read_vreg shift; + my $vs2 = read_vreg shift; + my $vs1 = read_vreg shift; + return ".word ".($template | ($vs2 << 20) | ($vs1 << 15 ) | ($vd << 7)); +} + 1; diff --git a/crypto/sm4/asm/sm4-riscv64-zvbb-zvkg-zvksed.pl b/crypto/sm4/asm/sm4-riscv64-zvbb-zvkg-zvksed.pl new file mode 100644 index 0000000000000..84a22ab5627c2 --- /dev/null +++ b/crypto/sm4/asm/sm4-riscv64-zvbb-zvkg-zvksed.pl @@ -0,0 +1,852 @@ +#! /usr/bin/env perl +# This file is dual-licensed, meaning that you can use it under your +# choice of either of the following two licenses: +# +# Copyright 2026 The OpenSSL Project Authors. All Rights Reserved. +# +# Licensed under the Apache License 2.0 (the "License"). You can obtain +# a copy in the file LICENSE in the source distribution or at +# https://www.openssl.org/source/license.html +# +# or +# +# Copyright (c) 2023, Jerry Shih +# All rights reserved. +# +#This module implements hardware instruction acceleration +#for SM4-XTS encryption and decryption calculations. +#author is +#author is +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +# - RV64I +# - RISC-V Vector ('V') with 2048 > VLEN >= 128 +# - RISC-V Vector Bit-manipulation extension ('Zvbb') +# - RISC-V Vector GCM/GMAC extension ('Zvkg') +# - RISC-V Vector SM4 block cipher extension ('Zvksed') +# - RISC-V Zicclsm(Main memory supports misaligned loads/stores) + +use strict; +use warnings; + +use FindBin qw($Bin); +use lib "$Bin"; +use lib "$Bin/../../perlasm"; +use riscv; + +# $output is the last argument if it looks like a file (it has an extension) +# $flavour is the first argument if it doesn't look like a file +my $output = $#ARGV >= 0 && $ARGV[$#ARGV] =~ m|\.\w+$| ? pop : undef; +my $flavour = $#ARGV >= 0 && $ARGV[0] !~ m|\.| ? shift : undef; + +$output and open STDOUT,">$output"; + +my $code=<<___; +.text +___ + +{ +################################################################################ +# void rv64i_zvbb_zvkg_zvksed_sm4_xts_encrypt(const unsigned char *in, +# unsigned char *out, size_t length, +# const SM4_KEY *key1, +# const SM4_KEY *key2, +# const unsigned char iv[16], +# const int enc) +my ($INPUT, $OUTPUT, $LENGTH, $KEY1, $KEY2, $IV) = ("a0", "a1", "a2", "a3", "a4", "a5"); +my ($TAIL_LENGTH) = ("a6"); +my ($VL) = ("a7"); +my ($T0, $T1, $T2) = ("t0", "t1", "t2"); +my ($STORE_LEN32) = ("t3"); +my ($LEN32) = ("t4"); +my ($V0, $V1, $V2, $V3, $V4, $V5, $V6, $V7, + $V8, $V9, $V10, $V11, $V12, $V13, $V14, $V15, + $V16, $V17, $V18, $V19, $V20, $V21, $V22, $V23, + $V24, $V25, $V26, $V27, $V28, $V29, $V30, $V31, +) = map("v$_",(0..31)); + +sub compute_xts_iv0 { + my $code=<<___; + @{[vsetivli "zero", 4, "e32", "m1", "ta", "ma"]} + la $T0, ORDERH + @{[vle32_v $V8, $T0]} + @{[vle32_v $V28, $IV]} + @{[vle32_v $V0, $KEY2]} # rk[0:3] + addi $KEY2, $KEY2, 16 + @{[vle32_v $V1, $KEY2]} # rk[4:7] + addi $KEY2, $KEY2, 16 + @{[vle32_v $V2, $KEY2]} # rk[8:11] + addi $KEY2, $KEY2, 16 + @{[vle32_v $V3, $KEY2]} # rk[12:15] + addi $KEY2, $KEY2, 16 + @{[vle32_v $V4, $KEY2]} # rk[16:19] + addi $KEY2, $KEY2, 16 + @{[vle32_v $V5, $KEY2]} # rk[20:23] + addi $KEY2, $KEY2, 16 + @{[vle32_v $V6, $KEY2]} # rk[24:27] + addi $KEY2, $KEY2, 16 + @{[vle32_v $V7, $KEY2]} # rk[28:31] + @{[vrev8_v $V12, $V28]} + @{[vsm4r_vs $V12, $V0]} + @{[vsm4r_vs $V12, $V1]} + @{[vsm4r_vs $V12, $V2]} + @{[vsm4r_vs $V12, $V3]} + @{[vsm4r_vs $V12, $V4]} + @{[vsm4r_vs $V12, $V5]} + @{[vsm4r_vs $V12, $V6]} + @{[vsm4r_vs $V12, $V7]} + @{[vrev8_v $V12, $V12]} + @{[vrgatherei16_vv $V28, $V12, $V8]} +___ + + return $code; +} + +# prepare input data(v24), iv(v28), bit-reversed-iv(v16), bit-reversed-iv-multiplier(v20) +sub init_first_round { + my $code=<<___; + # load input + @{[vsetvli $VL, $LEN32, "e32", "m4", "ta", "ma"]} + @{[vle32_v $V24, $INPUT]} + + li $T0, 5 + # We could simplify the initialization steps if we have `block<=1`. + blt $LEN32, $T0, 1f + + # Note: We use `vgmul` for GF(2^128) multiplication. The `vgmul` uses + # different order of coefficients. We should use`vbrev8` to reverse the + # data when we use `vgmul`. + @{[vsetivli "zero", 4, "e32", "m1", "ta", "ma"]} + @{[vbrev8_v $V0, $V28]} + @{[vsetvli "zero", $LEN32, "e32", "m4", "ta", "ma"]} + @{[vmv_v_i $V16, 0]} + # v16: [r-IV0, r-IV0, ...] + @{[vid_v $V20]} # v20 = 0,1,2,3,4,5,... + @{[vand_vi $V20, $V20, 3]} # v20 = 0,1,2,3,0,1,2,3,... + @{[vrgather_vv $V16, $V0, $V20]} # v16[i] = v0[v20[i]] + # Prepare GF(2^128) multiplier [1, x, x^2, x^3, ...] in v8. + slli $T0, $LEN32, 2 + @{[vsetvli "zero", $T0, "e32", "m1", "ta", "ma"]} + # v2: [`1`, `1`, `1`, `1`, ...] + @{[vmv_v_i $V2, 1]} + # v3: [`0`, `1`, `2`, `3`, ...] + @{[vid_v $V3]} + @{[vsetvli "zero", $T0, "e64", "m2", "ta", "ma"]} + # v4: [`1`, 0, `1`, 0, `1`, 0, `1`, 0, ...] + @{[vzext_vf2 $V4, $V2]} + # v6: [`0`, 0, `1`, 0, `2`, 0, `3`, 0, ...] + @{[vzext_vf2 $V6, $V3]} + slli $T0, $LEN32, 1 + @{[vsetvli "zero", $T0, "e32", "m2", "ta", "ma"]} + # v8: [1<<0=1, 0, 0, 0, 1<<1=x, 0, 0, 0, 1<<2=x^2, 0, 0, 0, ...] + @{[vwsll_vv $V8, $V4, $V6]} + + # Compute [r-IV0*1, r-IV0*x, r-IV0*x^2, r-IV0*x^3, ...] in v16 + @{[vsetvli "zero", $LEN32, "e32", "m4", "ta", "ma"]} + @{[vbrev8_v $V8, $V8]} + @{[vgmul_vv $V16, $V8]} + + # Compute [IV0*1, IV0*x, IV0*x^2, IV0*x^3, ...] in v28. + # Reverse the bits order back. + @{[vbrev8_v $V28, $V16]} + + # Prepare the x^n multiplier in v20. The `n` is the sm4-xts block number + # in a LMUL=4 register group. + # n = ((VLEN*LMUL)/(32*4)) = ((VLEN*4)/(32*4)) + # = (VLEN/32) + # We could use vsetvli with `e32, m1` to compute the `n` number. + @{[vsetvli $T0, "zero", "e32", "m1", "ta", "ma"]} + li $T1, 1 + sll $T0, $T1, $T0 + @{[vsetivli "zero", 2, "e64", "m1", "ta", "ma"]} + @{[vmv_v_i $V0, 0]} + @{[vsetivli "zero", 1, "e64", "m1", "tu", "ma"]} + @{[vmv_v_x $V0, $T0]} + @{[vsetivli "zero", 2, "e64", "m1", "ta", "ma"]} + @{[vbrev8_v $V0, $V0]} + @{[vsetvli "zero", $LEN32, "e32", "m4", "ta", "ma"]} + @{[vmv_v_i $V20, 0]} + @{[vid_v $V12]} # v12 = 0,1,2,3,4,5,... + @{[vand_vi $V12, $V12, 3]} # v12 = 0,1,2,3,0,1,2,3,... + @{[vrgather_vv $V20, $V0, $V12]} # v20[i] = v0[v12[i]] + + j 2f +1: + @{[vsetivli "zero", 4, "e32", "m1", "ta", "ma"]} + @{[vbrev8_v $V16, $V28]} +2: +___ + + return $code; +} + +# prepare xts enc last block's input(v24) and iv(v28) +sub handle_xts_enc_last_block { + my $code=<<___; + bnez $TAIL_LENGTH, 1f + ret +1: + # slidedown second to last block + addi $VL, $VL, -4 + @{[vsetivli "zero", 4, "e32", "m4", "ta", "ma"]} + # ciphertext + @{[vslidedown_vx $V24, $V24, $VL]} + # multiplier + @{[vslidedown_vx $V16, $V16, $VL]} + + @{[vsetivli "zero", 4, "e32", "m1", "ta", "ma"]} + @{[vmv_v_v $V25, $V24]} + + # load last block into v24 + # note: We should load the last block before store the second to last block + # for in-place operation. + @{[vsetvli "zero", $TAIL_LENGTH, "e8", "m1", "tu", "ma"]} + @{[vle8_v $V24, $INPUT]} + + # setup `x` multiplier with byte-reversed order + # 0b00000010 => 0b01000000 (0x40) + li $T0, 0x40 + @{[vsetivli "zero", 4, "e32", "m1", "ta", "ma"]} + @{[vmv_v_i $V28, 0]} + @{[vsetivli "zero", 1, "e8", "m1", "tu", "ma"]} + @{[vmv_v_x $V28, $T0]} + + # compute IV for last block + @{[vsetivli "zero", 4, "e32", "m1", "ta", "ma"]} + @{[vgmul_vv $V16, $V28]} + @{[vbrev8_v $V28, $V16]} + + # store second to last block + @{[vsetvli "zero", $TAIL_LENGTH, "e8", "m1", "ta", "ma"]} + @{[vse8_v $V25, $OUTPUT]} +___ + + return $code; +} + +# prepare xts dec second to last block's input(v24) and iv(v29) and +# last block's and iv(v28) +sub handle_xts_dec_last_block { + my $code=<<___; + bnez $TAIL_LENGTH, 1f + ret +1: + # load second to last block's ciphertext + @{[vsetivli "zero", 4, "e32", "m1", "ta", "ma"]} + @{[vle32_v $V24, $INPUT]} + addi $INPUT, $INPUT, 16 + + # setup `x` multiplier with byte-reversed order + # 0b00000010 => 0b01000000 (0x40) + li $T0, 0x40 + @{[vsetivli "zero", 4, "e32", "m1", "ta", "ma"]} + @{[vmv_v_i $V20, 0]} + @{[vsetivli "zero", 1, "e8", "m1", "tu", "ma"]} + @{[vmv_v_x $V20, $T0]} + + beqz $LENGTH, 1f + # slidedown third to last block + addi $VL, $VL, -4 + @{[vsetivli "zero", 4, "e32", "m4", "ta", "ma"]} + # multiplier + @{[vslidedown_vx $V16, $V16, $VL]} + + # compute IV for last block + @{[vsetivli "zero", 4, "e32", "m1", "ta", "ma"]} + @{[vgmul_vv $V16, $V20]} + @{[vbrev8_v $V28, $V16]} + + # compute IV for second to last block + @{[vgmul_vv $V16, $V20]} + @{[vbrev8_v $V29, $V16]} + j 2f +1: + # compute IV for second to last block + @{[vsetivli "zero", 4, "e32", "m1", "ta", "ma"]} + @{[vgmul_vv $V16, $V20]} + @{[vbrev8_v $V29, $V16]} +2: +___ + + return $code; +} + +# Load all 32 round keys in groups of four into registers v0-v7. +sub sm4_load_key { + my $code=<<___; + csrr $T0, vlenb + srli $T0, $T0, 1 + @{[vsetvli "zero", $T0, "e32", "m2", "ta", "mu"]} + la $T0, ORDERH + @{[vle32_v $V8, $T0]} + @{[vsetivli "zero", 4, "e32", "m1", "ta", "ma"]} + @{[vle32_v $V0, $KEY1]} # rk[0:3] + addi $KEY1, $KEY1, 16 + @{[vle32_v $V1, $KEY1]} # rk[4:7] + addi $KEY1, $KEY1, 16 + @{[vle32_v $V2, $KEY1]} # rk[8:11] + addi $KEY1, $KEY1, 16 + @{[vle32_v $V3, $KEY1]} # rk[12:15] + addi $KEY1, $KEY1, 16 + @{[vle32_v $V4, $KEY1]} # rk[16:19] + addi $KEY1, $KEY1, 16 + @{[vle32_v $V5, $KEY1]} # rk[20:23] + addi $KEY1, $KEY1, 16 + @{[vle32_v $V6, $KEY1]} # rk[24:27] + addi $KEY1, $KEY1, 16 + @{[vle32_v $V7, $KEY1]} # rk[28:31] +___ + + return $code; +} + +# sm4 enc/dec with round keys v1-v11 +sub sm4_enc_dec { + my $code=<<___; + @{[vrev8_v $V12, $V24]} + @{[vsm4r_vs $V12, $V0]} + @{[vsm4r_vs $V12, $V1]} + @{[vsm4r_vs $V12, $V2]} + @{[vsm4r_vs $V12, $V3]} + @{[vsm4r_vs $V12, $V4]} + @{[vsm4r_vs $V12, $V5]} + @{[vsm4r_vs $V12, $V6]} + @{[vsm4r_vs $V12, $V7]} + @{[vrev8_v $V12, $V12]} + @{[vrgatherei16_vv $V24, $V12, $V8]} +___ + + return $code; +} + +$code .= <<___; +.p2align 3 +.globl rv64i_zvbb_zvkg_zvksed_sm4_xts_encrypt +.type rv64i_zvbb_zvkg_zvksed_sm4_xts_encrypt,\@function +rv64i_zvbb_zvkg_zvksed_sm4_xts_encrypt: + @{[compute_xts_iv0]} + + # sm4 block size is 16 + andi $TAIL_LENGTH, $LENGTH, 15 + mv $STORE_LEN32, $LENGTH + beqz $TAIL_LENGTH, 1f + sub $LENGTH, $LENGTH, $TAIL_LENGTH + addi $STORE_LEN32, $LENGTH, -16 +1: + # We make the `LENGTH` become e32 length here. + srli $LEN32, $LENGTH, 2 + srli $STORE_LEN32, $STORE_LEN32, 2 + + j sm4_xts_enc_128 +.size rv64i_zvbb_zvkg_zvksed_sm4_xts_encrypt,.-rv64i_zvbb_zvkg_zvksed_sm4_xts_encrypt +___ + +$code .= <<___; +.p2align 3 +sm4_xts_enc_128: + @{[init_first_round]} + @{[sm4_load_key]} + @{[vsetvli $VL, $LEN32, "e32", "m4", "ta", "ma"]} + j 1f + +.Lenc_blocks_128: + @{[vsetvli $VL, $LEN32, "e32", "m4", "ta", "ma"]} + # load plaintext into v24 + @{[vle32_v $V24, $INPUT]} + # update iv + @{[vgmul_vv $V16, $V20]} + # reverse the iv's bits order back + @{[vbrev8_v $V28, $V16]} +1: + @{[vxor_vv $V24, $V24, $V28]} + slli $T0, $VL, 2 + sub $LEN32, $LEN32, $VL + add $INPUT, $INPUT, $T0 + @{[sm4_enc_dec]} + @{[vxor_vv $V24, $V24, $V28]} + + # store ciphertext + @{[vsetvli "zero", $STORE_LEN32, "e32", "m4", "ta", "ma"]} + @{[vse32_v $V24, $OUTPUT]} + add $OUTPUT, $OUTPUT, $T0 + sub $STORE_LEN32, $STORE_LEN32, $VL + + bnez $LEN32, .Lenc_blocks_128 + + @{[handle_xts_enc_last_block]} + + # xts last block + @{[vsetivli "zero", 4, "e32", "m1", "ta", "ma"]} + @{[vxor_vv $V24, $V24, $V28]} + @{[sm4_enc_dec]} + @{[vxor_vv $V24, $V24, $V28]} + + # store last block ciphertext + addi $OUTPUT, $OUTPUT, -16 + @{[vse32_v $V24, $OUTPUT]} + + ret +.size sm4_xts_enc_128,.-sm4_xts_enc_128 +___ + +################################################################################ +# void rv64i_zvbb_zvkg_zvksed_sm4_xts_decrypt(const unsigned char *in, +# unsigned char *out, size_t length, +# const SM4_KEY *key1, +# const SM4_KEY *key2, +# const unsigned char iv[16], +# const int enc) +$code .= <<___; +.p2align 3 +.globl rv64i_zvbb_zvkg_zvksed_sm4_xts_decrypt +.type rv64i_zvbb_zvkg_zvksed_sm4_xts_decrypt,\@function +rv64i_zvbb_zvkg_zvksed_sm4_xts_decrypt: + @{[compute_xts_iv0]} + + # sm4 block size is 16 + andi $TAIL_LENGTH, $LENGTH, 15 + beqz $TAIL_LENGTH, 1f + sub $LENGTH, $LENGTH, $TAIL_LENGTH + addi $LENGTH, $LENGTH, -16 +1: + # We make the `LENGTH` become e32 length here. + srli $LEN32, $LENGTH, 2 + + j sm4_xts_dec_128 +.size rv64i_zvbb_zvkg_zvksed_sm4_xts_decrypt,.-rv64i_zvbb_zvkg_zvksed_sm4_xts_decrypt +___ + +$code .= <<___; +.p2align 3 +sm4_xts_dec_128: + @{[init_first_round]} + @{[sm4_load_key]} + beqz $LEN32, 2f + + @{[vsetvli $VL, $LEN32, "e32", "m4", "ta", "ma"]} + j 1f + +.Ldec_blocks_128: + @{[vsetvli $VL, $LEN32, "e32", "m4", "ta", "ma"]} + # load ciphertext into v24 + @{[vle32_v $V24, $INPUT]} + # update iv + @{[vgmul_vv $V16, $V20]} + # reverse the iv's bits order back + @{[vbrev8_v $V28, $V16]} +1: + @{[vxor_vv $V24, $V24, $V28]} + slli $T0, $VL, 2 + sub $LEN32, $LEN32, $VL + add $INPUT, $INPUT, $T0 + @{[sm4_enc_dec]} + @{[vxor_vv $V24, $V24, $V28]} + + # store plaintext + @{[vse32_v $V24, $OUTPUT]} + add $OUTPUT, $OUTPUT, $T0 + + bnez $LEN32, .Ldec_blocks_128 + +2: + @{[handle_xts_dec_last_block]} + + ## xts second to last block + @{[vsetivli "zero", 4, "e32", "m1", "ta", "ma"]} + @{[vxor_vv $V24, $V24, $V29]} + @{[sm4_enc_dec]} + @{[vxor_vv $V24, $V24, $V29]} + @{[vmv_v_v $V25, $V24]} + + # load last block ciphertext + @{[vsetvli "zero", $TAIL_LENGTH, "e8", "m1", "tu", "ma"]} + @{[vle8_v $V24, $INPUT]} + + # store second to last block plaintext + addi $T0, $OUTPUT, 16 + @{[vse8_v $V25, $T0]} + + ## xts last block + @{[vsetivli "zero", 4, "e32", "m1", "ta", "ma"]} + @{[vxor_vv $V24, $V24, $V28]} + @{[sm4_enc_dec]} + @{[vxor_vv $V24, $V24, $V28]} + + # store last block plaintext + @{[vse32_v $V24, $OUTPUT]} + + ret +.size sm4_xts_dec_128,.-sm4_xts_dec_128 +___ +} + +{ +################################################################################ +# void rv64i_zvbb_zvkg_zvksed_sm4_xtsgb_encrypt(const unsigned char *in, +# unsigned char *out, size_t length, +# const SM4_KEY *key1, +# const SM4_KEY *key2, +# const unsigned char iv[16], +# const int enc) +my ($INPUT, $OUTPUT, $LENGTH, $KEY1, $KEY2, $IV) = ("a0", "a1", "a2", "a3", "a4", "a5"); +my ($TAIL_LENGTH) = ("a6"); +my ($VL) = ("a7"); +my ($T0, $T1, $T2) = ("t0", "t1", "t2"); +my ($STORE_LEN32) = ("t3"); +my ($LEN32) = ("t4"); +my ($V0, $V1, $V2, $V3, $V4, $V5, $V6, $V7, + $V8, $V9, $V10, $V11, $V12, $V13, $V14, $V15, + $V16, $V17, $V18, $V19, $V20, $V21, $V22, $V23, + $V24, $V25, $V26, $V27, $V28, $V29, $V30, $V31, +) = map("v$_",(0..31)); + +# prepare input data(v24), iv(v28), iv-multiplier(v20) +sub initgb_first_round { + my $code=<<___; + @{[vmv_v_v $V16, $V28]} + # load input + @{[vsetvli $VL, $LEN32, "e32", "m4", "ta", "ma"]} + @{[vle32_v $V24, $INPUT]} + + li $T0, 5 + # We could simplify the initialization steps if we have `block<=1`. + blt $LEN32, $T0, 1f + + # Note: We use `vgmul` for GF(2^128) multiplication. + @{[vsetvli "zero", $LEN32, "e32", "m4", "ta", "ma"]} + @{[vmv_v_i $V16, 0]} + # v16: [IV0, IV0, ...] + @{[vid_v $V20]} # v20 = 0,1,2,3,4,5,... + @{[vand_vi $V20, $V20, 3]} # v20 = 0,1,2,3,0,1,2,3,... + @{[vrgather_vv $V16, $V28, $V20]} # v16[i] = v0[v20[i]] + + # Prepare GF(2^128) multiplier [1, x, x^2, x^3, ...] in v8. + slli $T0, $LEN32, 2 + @{[vsetvli "zero", $T0, "e32", "m1", "ta", "ma"]} + # v2: [`1`, `1`, `1`, `1`, ...] + @{[vmv_v_i $V2, 1]} + # v3: [`0`, `1`, `2`, `3`, ...] + @{[vid_v $V3]} + @{[vsetvli "zero", $T0, "e64", "m2", "ta", "ma"]} + # v4: [`1`, 0, `1`, 0, `1`, 0, `1`, 0, ...] + @{[vzext_vf2 $V4, $V2]} + # v6: [`0`, 0, `1`, 0, `2`, 0, `3`, 0, ...] + @{[vzext_vf2 $V6, $V3]} + slli $T0, $LEN32, 1 + @{[vsetvli "zero", $T0, "e32", "m2", "ta", "ma"]} + # v8: [1<<0=1, 0, 0, 0, 1<<1=x, 0, 0, 0, 1<<2=x^2, 0, 0, 0, ...] + @{[vwsll_vv $V8, $V4, $V6]} + + # Compute [IV0*1, IV0*x, IV0*x^2, IV0*x^3, ...] in v16 + @{[vsetvli "zero", $LEN32, "e32", "m4", "ta", "ma"]} + @{[vbrev8_v $V8, $V8]} + @{[vgmul_vv $V16, $V8]} + + # Prepare the x^n multiplier in v20. The `n` is the sm4-xts block number + # in a LMUL=4 register group. + # n = ((VLEN*LMUL)/(32*4)) = ((VLEN*4)/(32*4)) + # = (VLEN/32) + # We could use vsetvli with `e32, m1` to compute the `n` number. + @{[vsetvli $T0, "zero", "e32", "m1", "ta", "ma"]} + li $T1, 1 + sll $T0, $T1, $T0 + @{[vsetivli "zero", 2, "e64", "m1", "ta", "ma"]} + @{[vmv_v_i $V0, 0]} + @{[vsetivli "zero", 1, "e64", "m1", "tu", "ma"]} + @{[vmv_v_x $V0, $T0]} + @{[vsetivli "zero", 2, "e64", "m1", "ta", "ma"]} + @{[vbrev8_v $V0, $V0]} + @{[vsetvli "zero", $LEN32, "e32", "m4", "ta", "ma"]} + @{[vmv_v_i $V20, 0]} + @{[vid_v $V12]} # v12 = 0,1,2,3,4,5,... + @{[vand_vi $V12, $V12, 3]} # v12 = 0,1,2,3,0,1,2,3,... + @{[vrgather_vv $V20, $V0, $V12]} # v20[i] = v0[v12[i]] +1: +___ + + return $code; +} + +# prepare xts enc last block's input(v24) and iv(v28) +sub handle_xtsgb_enc_last_block { + my $code=<<___; + bnez $TAIL_LENGTH, 1f + ret +1: + # slidedown second to last block + addi $VL, $VL, -4 + @{[vsetivli "zero", 4, "e32", "m4", "ta", "ma"]} + # ciphertext + @{[vslidedown_vx $V24, $V24, $VL]} + # multiplier + @{[vslidedown_vx $V16, $V16, $VL]} + + @{[vsetivli "zero", 4, "e32", "m1", "ta", "ma"]} + @{[vmv_v_v $V25, $V24]} + + # load last block into v24 + # note: We should load the last block before store the second to last block + # for in-place operation. + @{[vsetvli "zero", $TAIL_LENGTH, "e8", "m1", "tu", "ma"]} + @{[vle8_v $V24, $INPUT]} + + # setup `x` multiplier with byte-reversed order + # 0b00000010 => 0b01000000 (0x40) + li $T0, 0x40 + @{[vsetivli "zero", 4, "e32", "m1", "ta", "ma"]} + @{[vmv_v_i $V28, 0]} + @{[vsetivli "zero", 1, "e8", "m1", "tu", "ma"]} + @{[vmv_v_x $V28, $T0]} + + # compute IV for last block + @{[vsetivli "zero", 4, "e32", "m1", "ta", "ma"]} + @{[vgmul_vv $V16, $V28]} + + # store second to last block + @{[vsetvli "zero", $TAIL_LENGTH, "e8", "m1", "ta", "ma"]} + @{[vse8_v $V25, $OUTPUT]} +___ + + return $code; +} + +# prepare xts dec second to last block's input(v24) and iv(v29) and +# last block's and iv(v28) +sub handle_xtsgb_dec_last_block { + my $code=<<___; + bnez $TAIL_LENGTH, 1f + ret +1: + # load second to last block's ciphertext + @{[vsetivli "zero", 4, "e32", "m1", "ta", "ma"]} + @{[vle32_v $V24, $INPUT]} + addi $INPUT, $INPUT, 16 + + # setup `x` multiplier with byte-reversed order + # 0b00000010 => 0b01000000 (0x40) + li $T0, 0x40 + @{[vsetivli "zero", 4, "e32", "m1", "ta", "ma"]} + @{[vmv_v_i $V20, 0]} + @{[vsetivli "zero", 1, "e8", "m1", "tu", "ma"]} + @{[vmv_v_x $V20, $T0]} + + beqz $LENGTH, 1f + # slidedown third to last block + addi $VL, $VL, -4 + @{[vsetivli "zero", 4, "e32", "m4", "ta", "ma"]} + # multiplier + @{[vslidedown_vx $V16, $V16, $VL]} + + # compute IV for last block + @{[vsetivli "zero", 4, "e32", "m1", "ta", "ma"]} + @{[vgmul_vv $V16, $V20]} + @{[vmv_v_v $V28, $V16]} + + # compute IV for second to last block + @{[vgmul_vv $V16, $V20]} + j 2f +1: + # compute IV for second to last block + @{[vsetivli "zero", 4, "e32", "m1", "ta", "ma"]} + @{[vgmul_vv $V16, $V20]} +2: +___ + + return $code; +} + +$code .= <<___; +.p2align 3 +.globl rv64i_zvbb_zvkg_zvksed_sm4_xtsgb_encrypt +.type rv64i_zvbb_zvkg_zvksed_sm4_xtsgb_encrypt,\@function +rv64i_zvbb_zvkg_zvksed_sm4_xtsgb_encrypt: + @{[compute_xts_iv0]} + + # sm4 block size is 16 + andi $TAIL_LENGTH, $LENGTH, 15 + mv $STORE_LEN32, $LENGTH + beqz $TAIL_LENGTH, 1f + sub $LENGTH, $LENGTH, $TAIL_LENGTH + addi $STORE_LEN32, $LENGTH, -16 +1: + # We make the `LENGTH` become e32 length here. + srli $LEN32, $LENGTH, 2 + srli $STORE_LEN32, $STORE_LEN32, 2 + + j sm4_xtsgb_enc_128 +.size rv64i_zvbb_zvkg_zvksed_sm4_xtsgb_encrypt,.-rv64i_zvbb_zvkg_zvksed_sm4_xtsgb_encrypt +___ + +$code .= <<___; +.p2align 3 +sm4_xtsgb_enc_128: + @{[initgb_first_round]} + @{[sm4_load_key]} + @{[vsetvli $VL, $LEN32, "e32", "m4", "ta", "ma"]} + j 1f + +.Lencgb_blocks_128: + @{[vsetvli $VL, $LEN32, "e32", "m4", "ta", "ma"]} + # load plaintext into v24 + @{[vle32_v $V24, $INPUT]} + # update iv + @{[vgmul_vv $V16, $V20]} +1: + @{[vxor_vv $V24, $V24, $V16]} + slli $T0, $VL, 2 + sub $LEN32, $LEN32, $VL + add $INPUT, $INPUT, $T0 + @{[sm4_enc_dec]} + @{[vxor_vv $V24, $V24, $V16]} + + # store ciphertext + @{[vsetvli "zero", $STORE_LEN32, "e32", "m4", "ta", "ma"]} + @{[vse32_v $V24, $OUTPUT]} + add $OUTPUT, $OUTPUT, $T0 + sub $STORE_LEN32, $STORE_LEN32, $VL + + bnez $LEN32, .Lencgb_blocks_128 + + @{[handle_xtsgb_enc_last_block]} + + # xts last block + @{[vsetivli "zero", 4, "e32", "m1", "ta", "ma"]} + @{[vxor_vv $V24, $V24, $V16]} + @{[sm4_enc_dec]} + @{[vxor_vv $V24, $V24, $V16]} + + # store last block ciphertext + addi $OUTPUT, $OUTPUT, -16 + @{[vse32_v $V24, $OUTPUT]} + + ret +.size sm4_xtsgb_enc_128,.-sm4_xtsgb_enc_128 +___ + +################################################################################ +# void rv64i_zvbb_zvkg_zvksed_sm4_xtsgb_decrypt(const unsigned char *in, +# unsigned char *out, size_t length, +# const SM4_KEY *key1, +# const SM4_KEY *key2, +# const unsigned char iv[16], +# const int enc) +$code .= <<___; +.p2align 3 +.globl rv64i_zvbb_zvkg_zvksed_sm4_xtsgb_decrypt +.type rv64i_zvbb_zvkg_zvksed_sm4_xtsgb_decrypt,\@function +rv64i_zvbb_zvkg_zvksed_sm4_xtsgb_decrypt: + @{[compute_xts_iv0]} + + # sm4 block size is 16 + andi $TAIL_LENGTH, $LENGTH, 15 + beqz $TAIL_LENGTH, 1f + sub $LENGTH, $LENGTH, $TAIL_LENGTH + addi $LENGTH, $LENGTH, -16 +1: + # We make the `LENGTH` become e32 length here. + srli $LEN32, $LENGTH, 2 + + j sm4_xtsgb_dec_128 +.size rv64i_zvbb_zvkg_zvksed_sm4_xtsgb_decrypt,.-rv64i_zvbb_zvkg_zvksed_sm4_xtsgb_decrypt +___ + +$code .= <<___; +.p2align 3 +sm4_xtsgb_dec_128: + @{[initgb_first_round]} + @{[sm4_load_key]} + beqz $LEN32, 2f + + @{[vsetvli $VL, $LEN32, "e32", "m4", "ta", "ma"]} + j 1f + +.Ldecgb_blocks_128: + @{[vsetvli $VL, $LEN32, "e32", "m4", "ta", "ma"]} + # load ciphertext into v24 + @{[vle32_v $V24, $INPUT]} + # update iv + @{[vgmul_vv $V16, $V20]} +1: + @{[vxor_vv $V24, $V24, $V16]} + slli $T0, $VL, 2 + sub $LEN32, $LEN32, $VL + add $INPUT, $INPUT, $T0 + @{[sm4_enc_dec]} + @{[vxor_vv $V24, $V24, $V16]} + + # store plaintext + @{[vse32_v $V24, $OUTPUT]} + add $OUTPUT, $OUTPUT, $T0 + + bnez $LEN32, .Ldecgb_blocks_128 + +2: + @{[handle_xtsgb_dec_last_block]} + + ## xts second to last block + @{[vsetivli "zero", 4, "e32", "m1", "ta", "ma"]} + @{[vxor_vv $V24, $V24, $V16]} + @{[sm4_enc_dec]} + @{[vxor_vv $V24, $V24, $V16]} + @{[vmv_v_v $V25, $V24]} + + # load last block ciphertext + @{[vsetvli "zero", $TAIL_LENGTH, "e8", "m1", "tu", "ma"]} + @{[vle8_v $V24, $INPUT]} + + # store second to last block plaintext + addi $T0, $OUTPUT, 16 + @{[vse8_v $V25, $T0]} + + ## xts last block + @{[vsetivli "zero", 4, "e32", "m1", "ta", "ma"]} + @{[vxor_vv $V24, $V24, $V28]} + @{[sm4_enc_dec]} + @{[vxor_vv $V24, $V24, $V28]} + + ## store last block plaintext + @{[vse32_v $V24, $OUTPUT]} + + ret +.size sm4_xtsgb_dec_128,.-sm4_xtsgb_dec_128 +___ +} + +$code .= <<___; +.section .rodata +.p2align 3 +ORDERH: + .half 3, 2, 1, 0, 7, 6, 5, 4, 11, 10, 9, 8, 15, 14, 13, 12 + .half 19, 18, 17, 16, 23, 22, 21, 20, 27, 26, 25, 24, 31, 30, 29, 28 + .half 35, 34, 33, 32, 39, 38, 37, 36, 43, 42, 41, 40, 47, 46, 45, 44 + .half 51, 50, 49, 48, 55, 54, 53, 52, 59, 58, 57, 56, 63, 62, 61, 60 + .half 67, 66, 65, 64, 71, 70, 69, 68, 75, 74, 73, 72, 79, 78, 77, 76 + .half 83, 82, 81, 80, 87, 86, 85, 84, 91, 90, 89, 88, 95, 94, 93, 92 + .half 99, 98, 97, 96, 103, 102, 101, 100, 107, 106, 105, 104, 111, 110, 109, 108 + .half 115, 114, 113, 112, 119, 118, 117, 116, 123, 122, 121, 120, 127, 126, 125, 124 +.size ORDERH,.-ORDERH +___ + +print $code; + +close STDOUT or die "error closing STDOUT: $!"; \ No newline at end of file diff --git a/crypto/sm4/build.info b/crypto/sm4/build.info index 2f36b6b595e4b..a8840db38a8d3 100644 --- a/crypto/sm4/build.info +++ b/crypto/sm4/build.info @@ -5,7 +5,7 @@ IF[{- !$disabled{asm} -}] $SM4ASM_aarch64=sm4-armv8.S vpsm4-armv8.S vpsm4_ex-armv8.S $SM4DEF_riscv64=SM4_ASM - $SM4ASM_riscv64=sm4-riscv64-zvksed.s + $SM4ASM_riscv64=sm4-riscv64-zvksed.s sm4-riscv64-zvbb-zvkg-zvksed.s $SM4DEF_x86_64=SM4_ASM $SM4ASM_x86_64=sm4-x86_64.S @@ -41,4 +41,5 @@ INCLUDE[sm4-armv8.o]=.. INCLUDE[vpsm4-armv8.o]=.. INCLUDE[vpsm4_ex-armv8.o]=.. GENERATE[sm4-riscv64-zvksed.s]=asm/sm4-riscv64-zvksed.pl +GENERATE[sm4-riscv64-zvbb-zvkg-zvksed.s]=asm/sm4-riscv64-zvbb-zvkg-zvksed.pl GENERATE[sm4-x86_64.S]=asm/sm4-x86_64.pl diff --git a/include/crypto/sm4_platform.h b/include/crypto/sm4_platform.h index 48c9ff93cf691..9da07c91156dc 100644 --- a/include/crypto/sm4_platform.h +++ b/include/crypto/sm4_platform.h @@ -53,6 +53,30 @@ void rv64i_zvksed_sm4_cbc_encrypt(const unsigned char *in, unsigned char *out, void rv64i_zvksed_sm4_cbc_decrypt(const unsigned char *in, unsigned char *out, size_t len, const SM4_KEY *key, unsigned char *iv, int enc); +void rv64i_zvbb_zvkg_zvksed_sm4_xts_encrypt(const unsigned char *in, + unsigned char *out, size_t length, + const SM4_KEY *key1, + const SM4_KEY *key2, + const unsigned char iv[16], + const int enc); +void rv64i_zvbb_zvkg_zvksed_sm4_xts_decrypt(const unsigned char *in, + unsigned char *out, size_t length, + const SM4_KEY *key1, + const SM4_KEY *key2, + const unsigned char iv[16], + const int enc); +void rv64i_zvbb_zvkg_zvksed_sm4_xtsgb_encrypt(const unsigned char *in, + unsigned char *out, size_t length, + const SM4_KEY *key1, + const SM4_KEY *key2, + const unsigned char iv[16], + const int enc); +void rv64i_zvbb_zvkg_zvksed_sm4_xtsgb_decrypt(const unsigned char *in, + unsigned char *out, size_t length, + const SM4_KEY *key1, + const SM4_KEY *key2, + const unsigned char iv[16], + const int enc); #elif (defined(__x86_64) || defined(__x86_64__) || defined(_M_AMD64) || defined(_M_X64)) /* Intel x86_64 support */ #include "internal/cryptlib.h" diff --git a/providers/implementations/ciphers/cipher_sm4_xts_hw_rv64i.inc b/providers/implementations/ciphers/cipher_sm4_xts_hw_rv64i.inc index 2ab15269cc751..81cc2c5addb4e 100644 --- a/providers/implementations/ciphers/cipher_sm4_xts_hw_rv64i.inc +++ b/providers/implementations/ciphers/cipher_sm4_xts_hw_rv64i.inc @@ -8,8 +8,8 @@ */ /*- - * RISC-V 64 ZVKSED support for SM4 GCM. - * This file is included by cipher_sm4_gcm_hw.c + * RISC-V 64 ZVKSED support for SM4 XTS. + * This file is included by cipher_sm4_xts_hw.c */ static int rv64i_zvksed_sm4_xts_initkey(PROV_CIPHER_CTX *ctx, @@ -17,14 +17,13 @@ static int rv64i_zvksed_sm4_xts_initkey(PROV_CIPHER_CTX *ctx, size_t keylen) { PROV_SM4_XTS_CTX *xctx = (PROV_SM4_XTS_CTX *)ctx; - OSSL_xts_stream_fn stream_fn = NULL; - OSSL_xts_stream_fn stream_gb_fn = NULL; XTS_SET_KEY_FN(rv64i_zvksed_sm4_set_encrypt_key, rv64i_zvksed_sm4_set_decrypt_key, rv64i_zvksed_sm4_encrypt, rv64i_zvksed_sm4_decrypt, - stream_fn, stream_gb_fn); + (OSSL_xts_stream_fn)NULL, + (OSSL_xts_stream_fn)NULL); return 1; } @@ -34,9 +33,41 @@ static const PROV_CIPHER_HW rv64i_zvksed_sm4_xts = { cipher_hw_sm4_xts_copyctx }; +static int cipher_hw_sm4_xts_rv64i_zvbb_zvkg_zvksed_initkey(PROV_CIPHER_CTX *ctx, + const unsigned char *key, + size_t keylen) +{ + PROV_SM4_XTS_CTX *xctx = (PROV_SM4_XTS_CTX *)ctx; + + XTS_SET_KEY_FN(rv64i_zvksed_sm4_set_encrypt_key, + rv64i_zvksed_sm4_set_decrypt_key, + rv64i_zvksed_sm4_encrypt, + rv64i_zvksed_sm4_decrypt, + (OSSL_xts_stream_fn)NULL, + (OSSL_xts_stream_fn)NULL); + + if (ctx->enc) { + xctx->stream = (OSSL_xts_stream_fn)rv64i_zvbb_zvkg_zvksed_sm4_xts_encrypt; + xctx->stream_gb = (OSSL_xts_stream_fn)rv64i_zvbb_zvkg_zvksed_sm4_xtsgb_encrypt; + } else { + xctx->stream = (OSSL_xts_stream_fn)rv64i_zvbb_zvkg_zvksed_sm4_xts_decrypt; + xctx->stream_gb = (OSSL_xts_stream_fn)rv64i_zvbb_zvkg_zvksed_sm4_xtsgb_decrypt; + } + + return 1; +} + +static const PROV_CIPHER_HW rv64i_zvbb_zvkg_zvksed_sm4_xts = { + cipher_hw_sm4_xts_rv64i_zvbb_zvkg_zvksed_initkey, + NULL, + cipher_hw_sm4_xts_copyctx +}; + const PROV_CIPHER_HW *ossl_prov_cipher_hw_sm4_xts(size_t keybits) { - if (RISCV_HAS_ZVKB_AND_ZVKSED() && riscv_vlen() >= 128) + if (RISCV_HAS_ZVBB() && RISCV_HAS_ZVKG() && RISCV_HAS_ZVKSED() && riscv_vlen() >= 128 && riscv_vlen() < 2048) + return &rv64i_zvbb_zvkg_zvksed_sm4_xts; + else if (RISCV_HAS_ZVKB_AND_ZVKSED() && riscv_vlen() >= 128) return &rv64i_zvksed_sm4_xts; else return &sm4_generic_xts;