1use rustc_span::Symbol;
8
9use crate::intrinsics::math::sha256;
10use crate::*;
11
12impl<'tcx> EvalContextExt<'tcx> for crate::MiriInterpCx<'tcx> {}
13pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
14 fn emulate_x86_sha_intrinsic(
15 &mut self,
16 link_name: Symbol,
17 args: &[OpTy<'tcx>],
18 dest: &MPlaceTy<'tcx>,
19 ) -> InterpResult<'tcx, EmulateItemResult> {
20 let this = self.eval_context_mut();
21 this.expect_target_feature_for_intrinsic(link_name, "sha")?;
22 let unprefixed_name = link_name.as_str().strip_prefix("llvm.x86.sha").unwrap();
24
25 fn read<'c>(ecx: &mut MiriInterpCx<'c>, vec: &OpTy<'c>) -> InterpResult<'c, [u32; 4]> {
26 let mut res = [0; 4];
27 for (i, dst) in res.iter_mut().rev().enumerate() {
30 let projected = &ecx.project_index(vec, i.try_into().unwrap())?;
31 *dst = ecx.read_scalar(projected)?.to_u32()?
32 }
33 interp_ok(res)
34 }
35
36 fn write<'c>(
37 ecx: &mut MiriInterpCx<'c>,
38 dest: &MPlaceTy<'c>,
39 val: [u32; 4],
40 ) -> InterpResult<'c, ()> {
41 for (i, part) in val.into_iter().rev().enumerate() {
44 let projected = &ecx.project_index(dest, i.to_u64())?;
45 ecx.write_scalar(Scalar::from_u32(part), projected)?;
46 }
47 interp_ok(())
48 }
49
50 match unprefixed_name {
51 "256rnds2" => {
53 let [a, b, k] = this.check_shim_sig_unadjusted(link_name, args)?;
54
55 let (a, a_len) = this.project_to_simd(a)?;
56 let (b, b_len) = this.project_to_simd(b)?;
57 let (k, k_len) = this.project_to_simd(k)?;
58 let (dest, dest_len) = this.project_to_simd(dest)?;
59
60 assert_eq!(a_len, 4);
61 assert_eq!(b_len, 4);
62 assert_eq!(k_len, 4);
63 assert_eq!(dest_len, 4);
64
65 let a = read(this, &a)?;
66 let b = read(this, &b)?;
67 let k = read(this, &k)?;
68
69 let result = sha256_digest_round_x2(a, b, k);
70 write(this, &dest, result)?;
71 }
72 "256msg1" => {
74 let [a, b] = this.check_shim_sig_unadjusted(link_name, args)?;
75
76 let (a, a_len) = this.project_to_simd(a)?;
77 let (b, b_len) = this.project_to_simd(b)?;
78 let (dest, dest_len) = this.project_to_simd(dest)?;
79
80 assert_eq!(a_len, 4);
81 assert_eq!(b_len, 4);
82 assert_eq!(dest_len, 4);
83
84 let a = read(this, &a)?;
85 let b = read(this, &b)?;
86
87 let result = sha256msg1(a, b);
88 write(this, &dest, result)?;
89 }
90 "256msg2" => {
92 let [a, b] = this.check_shim_sig_unadjusted(link_name, args)?;
93
94 let (a, a_len) = this.project_to_simd(a)?;
95 let (b, b_len) = this.project_to_simd(b)?;
96 let (dest, dest_len) = this.project_to_simd(dest)?;
97
98 assert_eq!(a_len, 4);
99 assert_eq!(b_len, 4);
100 assert_eq!(dest_len, 4);
101
102 let a = read(this, &a)?;
103 let b = read(this, &b)?;
104
105 let result = sha256msg2(a, b);
106 write(this, &dest, result)?;
107 }
108 _ => return interp_ok(EmulateItemResult::NotSupported),
109 }
110 interp_ok(EmulateItemResult::NeedsReturn)
111 }
112}
113
114fn sha256load(v2: [u32; 4], v3: [u32; 4]) -> [u32; 4] {
115 [v3[3], v2[0], v2[1], v2[2]]
116}
117
118fn sha256_digest_round_x2(cdgh: [u32; 4], abef: [u32; 4], wk: [u32; 4]) -> [u32; 4] {
119 let [_, _, wk1, wk0] = wk;
122 let [a0, b0, e0, f0] = abef;
123 let [c0, d0, g0, h0] = cdgh;
124
125 let state = sha256::round([a0, b0, c0, d0, e0, f0, g0, h0], wk0);
126 let state = sha256::round(state, wk1);
127
128 [state[0], state[1], state[4], state[5]]
129}
130
131fn sha256msg1(v0: [u32; 4], v1: [u32; 4]) -> [u32; 4] {
132 let x = sha256load(v0, v1);
133 [
134 v0[0].wrapping_add(sha256::sigma0(x[0])),
135 v0[1].wrapping_add(sha256::sigma0(x[1])),
136 v0[2].wrapping_add(sha256::sigma0(x[2])),
137 v0[3].wrapping_add(sha256::sigma0(x[3])),
138 ]
139}
140
141fn sha256msg2(v4: [u32; 4], v3: [u32; 4]) -> [u32; 4] {
142 let [x3, x2, x1, x0] = v4;
143 let [w15, w14, _, _] = v3;
144
145 let w16 = x0.wrapping_add(sha256::sigma1(w14));
146 let w17 = x1.wrapping_add(sha256::sigma1(w15));
147 let w18 = x2.wrapping_add(sha256::sigma1(w16));
148 let w19 = x3.wrapping_add(sha256::sigma1(w17));
149
150 [w19, w18, w17, w16]
151}