Skip to main content

ab_riscv_interpreter/rv32/zk/zkn/
zknh.rs

1//! RV32 Zknh extension
2
3#[cfg(test)]
4mod tests;
5pub mod zknh_helpers;
6
7use crate::{ExecutableInstruction, ExecutionError, InterpreterState};
8use ab_riscv_macros::instruction_execution;
9use ab_riscv_primitives::instructions::rv32::zk::zkn::zknh::Rv32ZknhInstruction;
10use ab_riscv_primitives::registers::general_purpose::Register;
11use core::ops::ControlFlow;
12
13#[instruction_execution]
14impl<Reg, ExtState, Memory, PC, InstructionHandler, CustomError>
15    ExecutableInstruction<
16        InterpreterState<Reg, ExtState, Memory, PC, InstructionHandler, CustomError>,
17        CustomError,
18    > for Rv32ZknhInstruction<Reg>
19where
20    Reg: Register<Type = u32>,
21    [(); Reg::N]:,
22{
23    #[inline(always)]
24    fn execute(
25        self,
26        state: &mut InterpreterState<Reg, ExtState, Memory, PC, InstructionHandler, CustomError>,
27    ) -> Result<ControlFlow<()>, ExecutionError<Reg::Type, CustomError>> {
28        match self {
29            // SHA-256 (single-register)
30            Self::Sha256Sig0 { rd, rs1 } => {
31                let x = state.regs.read(rs1);
32                let res = cfg_select! {
33                    all(not(miri), target_arch = "riscv32", target_feature = "zknh") => {
34                        // SAFETY: Just an intrinsic, no undefined behavior
35                        unsafe { core::arch::riscv32::sha256sig0(x) }
36                    }
37                    _ => {
38                        x.rotate_right(7) ^ x.rotate_right(18) ^ (x >> 3)
39                    }
40                };
41                state.regs.write(rd, res);
42            }
43            Self::Sha256Sig1 { rd, rs1 } => {
44                let x = state.regs.read(rs1);
45                let res = cfg_select! {
46                    all(not(miri), target_arch = "riscv32", target_feature = "zknh") => {
47                        // SAFETY: Just an intrinsic, no undefined behavior
48                        unsafe { core::arch::riscv32::sha256sig1(x) }
49                    }
50                    _ => {
51                        x.rotate_right(17) ^ x.rotate_right(19) ^ (x >> 10)
52                    }
53                };
54                state.regs.write(rd, res);
55            }
56            Self::Sha256Sum0 { rd, rs1 } => {
57                let x = state.regs.read(rs1);
58                let res = cfg_select! {
59                    all(not(miri), target_arch = "riscv32", target_feature = "zknh") => {
60                        // SAFETY: Just an intrinsic, no undefined behavior
61                        unsafe { core::arch::riscv32::sha256sum0(x) }
62                    }
63                    _ => {
64                        x.rotate_right(2) ^ x.rotate_right(13) ^ x.rotate_right(22)
65                    }
66                };
67                state.regs.write(rd, res);
68            }
69            Self::Sha256Sum1 { rd, rs1 } => {
70                let x = state.regs.read(rs1);
71                let res = cfg_select! {
72                    all(not(miri), target_arch = "riscv32", target_feature = "zknh") => {
73                        // SAFETY: Just an intrinsic, no undefined behavior
74                        unsafe { core::arch::riscv32::sha256sum1(x) }
75                    }
76                    _ => {
77                        x.rotate_right(6) ^ x.rotate_right(11) ^ x.rotate_right(25)
78                    }
79                };
80                state.regs.write(rd, res);
81            }
82
83            // SHA-512 (two-register R-type)
84            //
85            // Register conventions (from the RISC-V scalar crypto spec, Sail pseudocode):
86            //
87            //   sha512sig0l, sha512sig1l : rs1 = LOW word,  rs2 = HIGH word
88            //   sha512sig0h, sha512sig1h : rs1 = HIGH word, rs2 = LOW word
89            //   sha512sum0r, sha512sum1r : rs1 = LOW word,  rs2 = HIGH word
90            //
91            // The Sail model for sum0r/sum1r assembles the operand as:
92            //   x[63:32] = X(rs2),  x[31:0] = X(rs1)
93            // and writes x[31:0] of the result to rd.
94            //
95            // The helpers receive (rs1, rs2) exactly as read from the register file;
96            // they handle the asymmetric convention internally.
97            Self::Sha512Sig0h { rd, rs1, rs2 } => {
98                // Only here to prevent compiler warnings about unused `zknh_helpers` module
99                let () = zknh_helpers::PLACEHOLDER;
100                let rs1_val = state.regs.read(rs1);
101                let rs2_val = state.regs.read(rs2);
102                let res = cfg_select! {
103                    all(not(miri), target_arch = "riscv32", target_feature = "zknh") => {
104                        // SAFETY: Just an intrinsic, no undefined behavior
105                        unsafe { core::arch::riscv32::sha512sig0h(rs1_val, rs2_val) }
106                    }
107                    _ => {
108                        zknh_helpers::sha512sig0h(rs1_val, rs2_val)
109                    }
110                };
111                state.regs.write(rd, res);
112            }
113            Self::Sha512Sig0l { rd, rs1, rs2 } => {
114                let rs1_val = state.regs.read(rs1);
115                let rs2_val = state.regs.read(rs2);
116                let res = cfg_select! {
117                    all(not(miri), target_arch = "riscv32", target_feature = "zknh") => {
118                        // SAFETY: Just an intrinsic, no undefined behavior
119                        unsafe { core::arch::riscv32::sha512sig0l(rs1_val, rs2_val) }
120                    }
121                    _ => {
122                        zknh_helpers::sha512sig0l(rs1_val, rs2_val)
123                    }
124                };
125                state.regs.write(rd, res);
126            }
127            Self::Sha512Sig1h { rd, rs1, rs2 } => {
128                let rs1_val = state.regs.read(rs1);
129                let rs2_val = state.regs.read(rs2);
130                let res = cfg_select! {
131                    all(not(miri), target_arch = "riscv32", target_feature = "zknh") => {
132                        // SAFETY: Just an intrinsic, no undefined behavior
133                        unsafe { core::arch::riscv32::sha512sig1h(rs1_val, rs2_val) }
134                    }
135                    _ => {
136                        zknh_helpers::sha512sig1h(rs1_val, rs2_val)
137                    }
138                };
139                state.regs.write(rd, res);
140            }
141            Self::Sha512Sig1l { rd, rs1, rs2 } => {
142                let rs1_val = state.regs.read(rs1);
143                let rs2_val = state.regs.read(rs2);
144                let res = cfg_select! {
145                    all(not(miri), target_arch = "riscv32", target_feature = "zknh") => {
146                        // SAFETY: Just an intrinsic, no undefined behavior
147                        unsafe { core::arch::riscv32::sha512sig1l(rs1_val, rs2_val) }
148                    }
149                    _ => {
150                        zknh_helpers::sha512sig1l(rs1_val, rs2_val)
151                    }
152                };
153                state.regs.write(rd, res);
154            }
155            Self::Sha512Sum0r { rd, rs1, rs2 } => {
156                let rs1_val = state.regs.read(rs1);
157                let rs2_val = state.regs.read(rs2);
158                let res = cfg_select! {
159                    all(not(miri), target_arch = "riscv32", target_feature = "zknh") => {
160                        // SAFETY: Just an intrinsic, no undefined behavior
161                        unsafe { core::arch::riscv32::sha512sum0r(rs1_val, rs2_val) }
162                    }
163                    _ => {
164                        zknh_helpers::sha512sum0r(rs1_val, rs2_val)
165                    }
166                };
167                state.regs.write(rd, res);
168            }
169            Self::Sha512Sum1r { rd, rs1, rs2 } => {
170                let rs1_val = state.regs.read(rs1);
171                let rs2_val = state.regs.read(rs2);
172                let res = cfg_select! {
173                    all(not(miri), target_arch = "riscv32", target_feature = "zknh") => {
174                        // SAFETY: Just an intrinsic, no undefined behavior
175                        unsafe { core::arch::riscv32::sha512sum1r(rs1_val, rs2_val) }
176                    }
177                    _ => {
178                        zknh_helpers::sha512sum1r(rs1_val, rs2_val)
179                    }
180                };
181                state.regs.write(rd, res);
182            }
183        }
184
185        Ok(ControlFlow::Continue(()))
186    }
187}