core/stdarch/crates/core_arch/src/riscv_shared/
zk.rs

1#[cfg(test)]
2use stdarch_test::assert_instr;
3
4extern "unadjusted" {
5    #[link_name = "llvm.riscv.sm4ed"]
6    fn _sm4ed(rs1: i32, rs2: i32, bs: i32) -> i32;
7
8    #[link_name = "llvm.riscv.sm4ks"]
9    fn _sm4ks(rs1: i32, rs2: i32, bs: i32) -> i32;
10
11    #[link_name = "llvm.riscv.sm3p0"]
12    fn _sm3p0(rs1: i32) -> i32;
13
14    #[link_name = "llvm.riscv.sm3p1"]
15    fn _sm3p1(rs1: i32) -> i32;
16
17    #[link_name = "llvm.riscv.sha256sig0"]
18    fn _sha256sig0(rs1: i32) -> i32;
19
20    #[link_name = "llvm.riscv.sha256sig1"]
21    fn _sha256sig1(rs1: i32) -> i32;
22
23    #[link_name = "llvm.riscv.sha256sum0"]
24    fn _sha256sum0(rs1: i32) -> i32;
25
26    #[link_name = "llvm.riscv.sha256sum1"]
27    fn _sha256sum1(rs1: i32) -> i32;
28}
29
30#[cfg(target_arch = "riscv32")]
31extern "unadjusted" {
32    #[link_name = "llvm.riscv.xperm8.i32"]
33    fn _xperm8_32(rs1: i32, rs2: i32) -> i32;
34
35    #[link_name = "llvm.riscv.xperm4.i32"]
36    fn _xperm4_32(rs1: i32, rs2: i32) -> i32;
37}
38
39#[cfg(target_arch = "riscv64")]
40extern "unadjusted" {
41    #[link_name = "llvm.riscv.xperm8.i64"]
42    fn _xperm8_64(rs1: i64, rs2: i64) -> i64;
43
44    #[link_name = "llvm.riscv.xperm4.i64"]
45    fn _xperm4_64(rs1: i64, rs2: i64) -> i64;
46}
47
48/// Byte-wise lookup of indicies into a vector in registers.
49///
50/// The xperm8 instruction operates on bytes. The rs1 register contains a vector of XLEN/8
51/// 8-bit elements. The rs2 register contains a vector of XLEN/8 8-bit indexes. The result is
52/// each element in rs2 replaced by the indexed element in rs1, or zero if the index into rs2
53/// is out of bounds.
54///
55/// Source: RISC-V Cryptography Extensions Volume I: Scalar & Entropy Source Instructions
56///
57/// Version: v1.0.1
58///
59/// Section: 3.47
60///
61/// # Safety
62///
63/// This function is safe to use if the `zbkx` target feature is present.
64#[unstable(feature = "riscv_ext_intrinsics", issue = "114544")]
65#[target_feature(enable = "zbkx")]
66#[cfg_attr(test, assert_instr(xperm8))]
67#[inline]
68pub unsafe fn xperm8(rs1: usize, rs2: usize) -> usize {
69    #[cfg(target_arch = "riscv32")]
70    {
71        _xperm8_32(rs1 as i32, rs2 as i32) as usize
72    }
73
74    #[cfg(target_arch = "riscv64")]
75    {
76        _xperm8_64(rs1 as i64, rs2 as i64) as usize
77    }
78}
79
80/// Nibble-wise lookup of indicies into a vector.
81///
82/// The xperm4 instruction operates on nibbles. The rs1 register contains a vector of XLEN/4
83/// 4-bit elements. The rs2 register contains a vector of XLEN/4 4-bit indexes. The result is
84/// each element in rs2 replaced by the indexed element in rs1, or zero if the index into rs2
85/// is out of bounds.
86///
87/// Source: RISC-V Cryptography Extensions Volume I: Scalar & Entropy Source Instructions
88///
89/// Version: v1.0.1
90///
91/// Section: 3.48
92///
93/// # Safety
94///
95/// This function is safe to use if the `zbkx` target feature is present.
96#[unstable(feature = "riscv_ext_intrinsics", issue = "114544")]
97#[target_feature(enable = "zbkx")]
98#[cfg_attr(test, assert_instr(xperm4))]
99#[inline]
100pub unsafe fn xperm4(rs1: usize, rs2: usize) -> usize {
101    #[cfg(target_arch = "riscv32")]
102    {
103        _xperm4_32(rs1 as i32, rs2 as i32) as usize
104    }
105
106    #[cfg(target_arch = "riscv64")]
107    {
108        _xperm4_64(rs1 as i64, rs2 as i64) as usize
109    }
110}
111
112/// Implements the Sigma0 transformation function as used in the SHA2-256 hash function \[49\]
113/// (Section 4.1.2).
114///
115/// This instruction is supported for both RV32 and RV64 base architectures. For RV32, the
116/// entire XLEN source register is operated on. For RV64, the low 32 bits of the source
117/// register are operated on, and the result sign extended to XLEN bits. Though named for
118/// SHA2-256, the instruction works for both the SHA2-224 and SHA2-256 parameterisations as
119/// described in \[49\]. This instruction must always be implemented such that its execution
120/// latency does not depend on the data being operated on.
121///
122/// Source: RISC-V Cryptography Extensions Volume I: Scalar & Entropy Source Instructions
123///
124/// Version: v1.0.1
125///
126/// Section: 3.27
127///
128/// # Safety
129///
130/// This function is safe to use if the `zknh` target feature is present.
131#[unstable(feature = "riscv_ext_intrinsics", issue = "114544")]
132#[target_feature(enable = "zknh")]
133#[cfg_attr(test, assert_instr(sha256sig0))]
134#[inline]
135pub unsafe fn sha256sig0(rs1: u32) -> u32 {
136    _sha256sig0(rs1 as i32) as u32
137}
138
139/// Implements the Sigma1 transformation function as used in the SHA2-256 hash function \[49\]
140/// (Section 4.1.2).
141///
142/// This instruction is supported for both RV32 and RV64 base architectures. For RV32, the
143/// entire XLEN source register is operated on. For RV64, the low 32 bits of the source
144/// register are operated on, and the result sign extended to XLEN bits. Though named for
145/// SHA2-256, the instruction works for both the SHA2-224 and SHA2-256 parameterisations as
146/// described in \[49\]. This instruction must always be implemented such that its execution
147/// latency does not depend on the data being operated on.
148///
149/// Source: RISC-V Cryptography Extensions Volume I: Scalar & Entropy Source Instructions
150///
151/// Version: v1.0.1
152///
153/// Section: 3.28
154///
155/// # Safety
156///
157/// This function is safe to use if the `zknh` target feature is present.
158#[unstable(feature = "riscv_ext_intrinsics", issue = "114544")]
159#[target_feature(enable = "zknh")]
160#[cfg_attr(test, assert_instr(sha256sig1))]
161#[inline]
162pub unsafe fn sha256sig1(rs1: u32) -> u32 {
163    _sha256sig1(rs1 as i32) as u32
164}
165
166/// Implements the Sum0 transformation function as used in the SHA2-256 hash function \[49\]
167/// (Section 4.1.2).
168///
169/// This instruction is supported for both RV32 and RV64 base architectures. For RV32, the
170/// entire XLEN source register is operated on. For RV64, the low 32 bits of the source
171/// register are operated on, and the result sign extended to XLEN bits. Though named for
172/// SHA2-256, the instruction works for both the SHA2-224 and SHA2-256 parameterisations as
173/// described in \[49\]. This instruction must always be implemented such that its execution
174/// latency does not depend on the data being operated on.
175///
176/// Source: RISC-V Cryptography Extensions Volume I: Scalar & Entropy Source Instructions
177///
178/// Version: v1.0.1
179///
180/// Section: 3.29
181///
182/// # Safety
183///
184/// This function is safe to use if the `zknh` target feature is present.
185#[unstable(feature = "riscv_ext_intrinsics", issue = "114544")]
186#[target_feature(enable = "zknh")]
187#[cfg_attr(test, assert_instr(sha256sum0))]
188#[inline]
189pub unsafe fn sha256sum0(rs1: u32) -> u32 {
190    _sha256sum0(rs1 as i32) as u32
191}
192
193/// Implements the Sum1 transformation function as used in the SHA2-256 hash function \[49\]
194/// (Section 4.1.2).
195///
196/// This instruction is supported for both RV32 and RV64 base architectures. For RV32, the
197/// entire XLEN source register is operated on. For RV64, the low 32 bits of the source
198/// register are operated on, and the result sign extended to XLEN bits. Though named for
199/// SHA2-256, the instruction works for both the SHA2-224 and SHA2-256 parameterisations as
200/// described in \[49\]. This instruction must always be implemented such that its execution
201/// latency does not depend on the data being operated on.
202///
203/// Source: RISC-V Cryptography Extensions Volume I: Scalar & Entropy Source Instructions
204///
205/// Version: v1.0.1
206///
207/// Section: 3.30
208///
209/// # Safety
210///
211/// This function is safe to use if the `zknh` target feature is present.
212#[unstable(feature = "riscv_ext_intrinsics", issue = "114544")]
213#[target_feature(enable = "zknh")]
214#[cfg_attr(test, assert_instr(sha256sum1))]
215#[inline]
216pub unsafe fn sha256sum1(rs1: u32) -> u32 {
217    _sha256sum1(rs1 as i32) as u32
218}
219
220/// Accelerates the block encrypt/decrypt operation of the SM4 block cipher \[5, 31\].
221///
222/// Implements a T-tables in hardware style approach to accelerating the SM4 round function. A
223/// byte is extracted from rs2 based on bs, to which the SBox and linear layer transforms are
224/// applied, before the result is XOR’d with rs1 and written back to rd. This instruction
225/// exists on RV32 and RV64 base architectures. On RV64, the 32-bit result is sign extended to
226/// XLEN bits. This instruction must always be implemented such that its execution latency does
227/// not depend on the data being operated on.
228///
229/// Source: RISC-V Cryptography Extensions Volume I: Scalar & Entropy Source Instructions
230///
231/// Version: v1.0.1
232///
233/// Section: 3.43
234///
235/// # Note
236///
237/// The `BS` parameter is expected to be a constant value and only the bottom 2 bits of `bs` are
238/// used.
239///
240/// # Safety
241///
242/// This function is safe to use if the `zksed` target feature is present.
243///
244/// # Details
245///
246/// Accelerates the round function `F` in the SM4 block cipher algorithm
247///
248/// This instruction is included in extension `Zksed`. It's defined as:
249///
250/// ```text
251/// SM4ED(x, a, BS) = x ⊕ T(ai)
252/// ... where
253/// ai = a.bytes[BS]
254/// T(ai) = L(τ(ai))
255/// bi = τ(ai) = SM4-S-Box(ai)
256/// ci = L(bi) = bi ⊕ (bi ≪ 2) ⊕ (bi ≪ 10) ⊕ (bi ≪ 18) ⊕ (bi ≪ 24)
257/// SM4ED = (ci ≪ (BS * 8)) ⊕ x
258/// ```
259///
260/// where `⊕` represents 32-bit xor, and `≪ k` represents rotate left by `k` bits.
261/// As is defined above, `T` is a combined transformation of non linear S-Box transform `τ`
262/// and linear layer transform `L`.
263///
264/// In the SM4 algorithm, the round function `F` is defined as:
265///
266/// ```text
267/// F(x0, x1, x2, x3, rk) = x0 ⊕ T(x1 ⊕ x2 ⊕ x3 ⊕ rk)
268/// ... where
269/// T(A) = L(τ(A))
270/// B = τ(A) = (SM4-S-Box(a0), SM4-S-Box(a1), SM4-S-Box(a2), SM4-S-Box(a3))
271/// C = L(B) = B ⊕ (B ≪ 2) ⊕ (B ≪ 10) ⊕ (B ≪ 18) ⊕ (B ≪ 24)
272/// ```
273///
274/// It can be implemented by `sm4ed` instruction like:
275///
276/// ```no_run
277/// # #[cfg(any(target_arch = "riscv32", target_arch = "riscv64"))]
278/// # fn round_function(x0: u32, x1: u32, x2: u32, x3: u32, rk: u32) -> u32 {
279/// # #[cfg(target_arch = "riscv32")] use core::arch::riscv32::sm4ed;
280/// # #[cfg(target_arch = "riscv64")] use core::arch::riscv64::sm4ed;
281/// let a = x1 ^ x2 ^ x3 ^ rk;
282/// let c0 = sm4ed(x0, a, 0);
283/// let c1 = sm4ed(c0, a, 1); // c1 represents c[0..=1], etc.
284/// let c2 = sm4ed(c1, a, 2);
285/// let c3 = sm4ed(c2, a, 3);
286/// return c3; // c3 represents c[0..=3]
287/// # }
288/// ```
289#[unstable(feature = "riscv_ext_intrinsics", issue = "114544")]
290#[target_feature(enable = "zksed")]
291#[rustc_legacy_const_generics(2)]
292#[cfg_attr(test, assert_instr(sm4ed, BS = 0))]
293#[inline]
294pub unsafe fn sm4ed<const BS: u8>(rs1: u32, rs2: u32) -> u32 {
295    static_assert!(BS < 4);
296
297    _sm4ed(rs1 as i32, rs2 as i32, BS as i32) as u32
298}
299
300/// Accelerates the Key Schedule operation of the SM4 block cipher \[5, 31\] with `bs=0`.
301///
302/// Implements a T-tables in hardware style approach to accelerating the SM4 Key Schedule. A
303/// byte is extracted from rs2 based on bs, to which the SBox and linear layer transforms are
304/// applied, before the result is XOR’d with rs1 and written back to rd. This instruction
305/// exists on RV32 and RV64 base architectures. On RV64, the 32-bit result is sign extended to
306/// XLEN bits. This instruction must always be implemented such that its execution latency does
307/// not depend on the data being operated on.
308///
309/// Source: RISC-V Cryptography Extensions Volume I: Scalar & Entropy Source Instructions
310///
311/// Version: v1.0.1
312///
313/// Section: 3.44
314///
315/// # Note
316///
317/// The `BS` parameter is expected to be a constant value and only the bottom 2 bits of `bs` are
318/// used.
319///
320/// # Safety
321///
322/// This function is safe to use if the `zksed` target feature is present.
323///
324/// # Details
325///
326/// Accelerates the round function `F` in the SM4 block cipher algorithm
327///
328/// This instruction is included in extension `Zksed`. It's defined as:
329///
330/// ```text
331/// SM4ED(x, a, BS) = x ⊕ T(ai)
332/// ... where
333/// ai = a.bytes[BS]
334/// T(ai) = L(τ(ai))
335/// bi = τ(ai) = SM4-S-Box(ai)
336/// ci = L(bi) = bi ⊕ (bi ≪ 2) ⊕ (bi ≪ 10) ⊕ (bi ≪ 18) ⊕ (bi ≪ 24)
337/// SM4ED = (ci ≪ (BS * 8)) ⊕ x
338/// ```
339///
340/// where `⊕` represents 32-bit xor, and `≪ k` represents rotate left by `k` bits.
341/// As is defined above, `T` is a combined transformation of non linear S-Box transform `τ`
342/// and linear layer transform `L`.
343///
344/// In the SM4 algorithm, the round function `F` is defined as:
345///
346/// ```text
347/// F(x0, x1, x2, x3, rk) = x0 ⊕ T(x1 ⊕ x2 ⊕ x3 ⊕ rk)
348/// ... where
349/// T(A) = L(τ(A))
350/// B = τ(A) = (SM4-S-Box(a0), SM4-S-Box(a1), SM4-S-Box(a2), SM4-S-Box(a3))
351/// C = L(B) = B ⊕ (B ≪ 2) ⊕ (B ≪ 10) ⊕ (B ≪ 18) ⊕ (B ≪ 24)
352/// ```
353///
354/// It can be implemented by `sm4ed` instruction like:
355///
356/// ```no_run
357/// # #[cfg(any(target_arch = "riscv32", target_arch = "riscv64"))]
358/// # fn round_function(x0: u32, x1: u32, x2: u32, x3: u32, rk: u32) -> u32 {
359/// # #[cfg(target_arch = "riscv32")] use core::arch::riscv32::sm4ed;
360/// # #[cfg(target_arch = "riscv64")] use core::arch::riscv64::sm4ed;
361/// let a = x1 ^ x2 ^ x3 ^ rk;
362/// let c0 = sm4ed(x0, a, 0);
363/// let c1 = sm4ed(c0, a, 1); // c1 represents c[0..=1], etc.
364/// let c2 = sm4ed(c1, a, 2);
365/// let c3 = sm4ed(c2, a, 3);
366/// return c3; // c3 represents c[0..=3]
367/// # }
368/// ```
369#[unstable(feature = "riscv_ext_intrinsics", issue = "114544")]
370#[target_feature(enable = "zksed")]
371#[rustc_legacy_const_generics(2)]
372#[cfg_attr(test, assert_instr(sm4ks, BS = 0))]
373#[inline]
374pub unsafe fn sm4ks<const BS: u8>(rs1: u32, rs2: u32) -> u32 {
375    static_assert!(BS < 4);
376
377    _sm4ks(rs1 as i32, rs2 as i32, BS as i32) as u32
378}
379
380/// Implements the P0 transformation function as used in the SM3 hash function [4, 30].
381///
382/// This instruction is supported for the RV32 and RV64 base architectures. It implements the
383/// P0 transform of the SM3 hash function [4, 30]. This instruction must always be implemented
384/// such that its execution latency does not depend on the data being operated on.
385///
386/// Source: RISC-V Cryptography Extensions Volume I: Scalar & Entropy Source Instructions
387///
388/// Version: v1.0.1
389///
390/// Section: 3.41
391///
392/// # Safety
393///
394/// This function is safe to use if the `zksh` target feature is present.
395///
396/// # Details
397///
398/// `P0` transformation function as is used in the SM3 hash algorithm
399///
400/// This function is included in `Zksh` extension. It's defined as:
401///
402/// ```text
403/// P0(X) = X ⊕ (X ≪ 9) ⊕ (X ≪ 17)
404/// ```
405///
406/// where `⊕` represents 32-bit xor, and `≪ k` represents rotate left by `k` bits.
407///
408/// In the SM3 algorithm, the `P0` transformation is used as `E ← P0(TT2)` when the
409/// compression function `CF` uses the intermediate value `TT2` to calculate
410/// the variable `E` in one iteration for subsequent processes.
411#[unstable(feature = "riscv_ext_intrinsics", issue = "114544")]
412#[target_feature(enable = "zksh")]
413#[cfg_attr(test, assert_instr(sm3p0))]
414#[inline]
415pub unsafe fn sm3p0(rs1: u32) -> u32 {
416    _sm3p0(rs1 as i32) as u32
417}
418
419/// Implements the P1 transformation function as used in the SM3 hash function [4, 30].
420///
421/// This instruction is supported for the RV32 and RV64 base architectures. It implements the
422/// P1 transform of the SM3 hash function [4, 30]. This instruction must always be implemented
423/// such that its execution latency does not depend on the data being operated on.
424///
425/// Source: RISC-V Cryptography Extensions Volume I: Scalar & Entropy Source Instructions
426///
427/// Version: v1.0.1
428///
429/// Section: 3.42
430///
431/// # Safety
432///
433/// This function is safe to use if the `zksh` target feature is present.
434///
435/// # Details
436///
437/// `P1` transformation function as is used in the SM3 hash algorithm
438///
439/// This function is included in `Zksh` extension. It's defined as:
440///
441/// ```text
442/// P1(X) = X ⊕ (X ≪ 15) ⊕ (X ≪ 23)
443/// ```
444///
445/// where `⊕` represents 32-bit xor, and `≪ k` represents rotate left by `k` bits.
446///
447/// In the SM3 algorithm, the `P1` transformation is used to expand message,
448/// where expanded word `Wj` can be generated from the previous words.
449/// The whole process can be described as the following pseudocode:
450///
451/// ```text
452/// FOR j=16 TO 67
453///     Wj ← P1(Wj−16 ⊕ Wj−9 ⊕ (Wj−3 ≪ 15)) ⊕ (Wj−13 ≪ 7) ⊕ Wj−6
454/// ENDFOR
455/// ```
456#[unstable(feature = "riscv_ext_intrinsics", issue = "114544")]
457#[target_feature(enable = "zksh")]
458#[cfg_attr(test, assert_instr(sm3p1))]
459#[inline]
460pub unsafe fn sm3p1(rs1: u32) -> u32 {
461    _sm3p1(rs1 as i32) as u32
462}