Commit c039e9951f for openssl.org

commit c039e9951f2c333972b03f69a2f8184c511b23b7
Author: Julian Zhu <julian.oerv@isrc.iscas.ac.cn>
Date:   Mon Sep 7 12:33:25 2026 +0800

    RISC-V: handle misaligned input in the SHA-256 core

    The Zbb path loads input with ld, which is very slow on cores that trap
    misaligned accesses. Build each doubleword from two aligned loads when the
    input is misaligned.

    Signed-off-by: Julian Zhu <julian.oerv@isrc.iscas.ac.cn>
    Reviewed-by: Paul Dale <paul.dale@oracle.com>
    Reviewed-by: Tomas Mraz <tomas@openssl.foundation>
    Merge-date: Fri Oct  2 08:26:48 2026
    Merged-from: https://github.com/openssl/openssl/pull/33008

diff --git a/crypto/sha/asm/sha256-riscv64-zbb.pl b/crypto/sha/asm/sha256-riscv64-zbb.pl
index d57236118c..2755e4483c 100644
--- a/crypto/sha/asm/sha256-riscv64-zbb.pl
+++ b/crypto/sha/asm/sha256-riscv64-zbb.pl
@@ -66,19 +66,38 @@ my $K256 = "K256";
 # Function arguments
 my ($INP, $LEN, $ADDR) = ("a1", "a2", "sp");
 my ($KT, $T1, $T2, $T3, $T4, $T5, $T6, $T7, $T8) = ("t0", "t1", "t2", "t3", "t4", "t5", "t6", "a3", "a4");
+# Shift amounts for misaligned input (Zbb only, T7/T8 are free there)
+my ($SHL, $SHR) = ($T7, $T8);
+my ($MISALIGNED_INPUT, $ALIGNED_INPUT) = (0, 1);
 # Parity-indexed pairs: W = W[i], U = W[i-15], X = a ^ b
 my ($W0, $W1, $U0, $U1, $X0, $X1) = ("a5", "a6", "a7", "s0", "s1", "s10");
 my ($A, $B, $C, $D ,$E ,$F ,$G ,$H) = ("s2", "s3", "s4", "s5", "s6", "s7", "s8", "s9");

+# Misaligned: $dst = (lo >> SHL) | (hi << SHR) from two aligned loads
+sub loadDword {
+    my ($ALIGNED, $dst, $off) = @_;
+    if ($ALIGNED) {
+        return "ld $dst, $off($INP)";
+    }
+    my $code=<<___;
+    ld $T5, $off($INP)
+    ld $T6, ($off+8)($INP)
+    srl $dst, $T5, $SHL
+    sll $T6, $T6, $SHR
+    or $dst, $dst, $T6
+___
+    return $code;
+}
+
 sub MSGSCHEDULE0 {
-    my ($index) = @_;
+    my ($ALIGNED, $index) = @_;
     if ($use_zbb) {
         # Odd rounds: W[i] is already in W1
         if ($index & 1) {
             return "";
         }
         my $code=<<___;
-        ld $W1, 4*$index($INP)
+        @{[loadDword $ALIGNED, $W1, "4*$index"]}
         @{[rev8 $W1, $W1]} # rev8 $W1, $W1
         srli $W0, $W1, 32
         sw $W0, 4*$index($ADDR)
@@ -245,9 +264,9 @@ ___
 }

 sub SHA256ROUND0 {
-    my ($INDEX, $a, $b, $c, $d, $e, $f, $g, $h) = @_;
+    my ($ALIGNED, $INDEX, $a, $b, $c, $d, $e, $f, $g, $h) = @_;
     my $code=<<___;
-    @{[MSGSCHEDULE0 $INDEX]}
+    @{[MSGSCHEDULE0 $ALIGNED, $INDEX]}
     @{[SHA256ROUND $INDEX, $a, $b, $c, $d, $e, $f, $g, $h]}
 ___

@@ -300,6 +319,21 @@ sha256_block_data_order@{[$isaext]}:
     lw $F, 20(a0)
     lw $G, 24(a0)
     lw $H, 28(a0)
+___
+
+if ($use_zbb) {
+$code .= <<___;
+
+    andi $SHL, $INP, 7
+    beqz $SHL, L_round_loop
+    andi $INP, $INP, -8
+    slli $SHL, $SHL, 3
+    li $T1, 64
+    sub $SHR, $T1, $SHL
+___
+}
+
+$code .= <<___;

 L_round_loop:
     # Decrement length by 1
@@ -309,20 +343,47 @@ L_round_loop:
     xor $X1, $B, $C
 ___

+# Rounds 0..15, plus a misaligned-input copy for Zbb (byte loads need none)
+if ($use_zbb) {
+    $code .= <<___;
+    bnez $SHL, L_load_misaligned
+___
+}
+
 for (my $i = 0; $i < 16; $i += 8) {
     $code .= <<___;
-    @{[SHA256ROUND0 $i, $A, $B, $C, $D, $E, $F, $G, $H]}
-    @{[SHA256ROUND0 $i+1, $H, $A, $B, $C, $D, $E, $F, $G]}
-    @{[SHA256ROUND0 $i+2, $G, $H, $A, $B, $C, $D, $E, $F]}
-    @{[SHA256ROUND0 $i+3, $F, $G, $H, $A, $B, $C, $D, $E]}
-    @{[SHA256ROUND0 $i+4, $E, $F, $G, $H, $A, $B, $C, $D]}
-    @{[SHA256ROUND0 $i+5, $D, $E, $F, $G, $H, $A, $B, $C]}
-    @{[SHA256ROUND0 $i+6, $C, $D, $E, $F, $G, $H, $A, $B]}
-    @{[SHA256ROUND0 $i+7, $B, $C, $D, $E, $F, $G, $H, $A]}
+    @{[SHA256ROUND0 $ALIGNED_INPUT, $i, $A, $B, $C, $D, $E, $F, $G, $H]}
+    @{[SHA256ROUND0 $ALIGNED_INPUT, $i+1, $H, $A, $B, $C, $D, $E, $F, $G]}
+    @{[SHA256ROUND0 $ALIGNED_INPUT, $i+2, $G, $H, $A, $B, $C, $D, $E, $F]}
+    @{[SHA256ROUND0 $ALIGNED_INPUT, $i+3, $F, $G, $H, $A, $B, $C, $D, $E]}
+    @{[SHA256ROUND0 $ALIGNED_INPUT, $i+4, $E, $F, $G, $H, $A, $B, $C, $D]}
+    @{[SHA256ROUND0 $ALIGNED_INPUT, $i+5, $D, $E, $F, $G, $H, $A, $B, $C]}
+    @{[SHA256ROUND0 $ALIGNED_INPUT, $i+6, $C, $D, $E, $F, $G, $H, $A, $B]}
+    @{[SHA256ROUND0 $ALIGNED_INPUT, $i+7, $B, $C, $D, $E, $F, $G, $H, $A]}
 ___
 }

+if ($use_zbb) {
+    $code .= <<___;
+    j L_message_schedule
+L_load_misaligned:
+___
+    for (my $i = 0; $i < 16; $i += 8) {
+        $code .= <<___;
+    @{[SHA256ROUND0 $MISALIGNED_INPUT, $i, $A, $B, $C, $D, $E, $F, $G, $H]}
+    @{[SHA256ROUND0 $MISALIGNED_INPUT, $i+1, $H, $A, $B, $C, $D, $E, $F, $G]}
+    @{[SHA256ROUND0 $MISALIGNED_INPUT, $i+2, $G, $H, $A, $B, $C, $D, $E, $F]}
+    @{[SHA256ROUND0 $MISALIGNED_INPUT, $i+3, $F, $G, $H, $A, $B, $C, $D, $E]}
+    @{[SHA256ROUND0 $MISALIGNED_INPUT, $i+4, $E, $F, $G, $H, $A, $B, $C, $D]}
+    @{[SHA256ROUND0 $MISALIGNED_INPUT, $i+5, $D, $E, $F, $G, $H, $A, $B, $C]}
+    @{[SHA256ROUND0 $MISALIGNED_INPUT, $i+6, $C, $D, $E, $F, $G, $H, $A, $B]}
+    @{[SHA256ROUND0 $MISALIGNED_INPUT, $i+7, $B, $C, $D, $E, $F, $G, $H, $A]}
+___
+    }
+}
+
 $code .= <<___;
+L_message_schedule:
     # Round 16's W[i-16] is W[0]; later rounds reuse the previous W[i-15]
     lw $U1, 0($ADDR)
 ___