1const PADDING: [u8; 64] = [
2 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
5 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
6];
7
8#[derive(Clone)]
9struct Context {
10 input: [u8; 64],
11 i: [u32; 2],
12 buf: [u32; 4],
13}
14
15fn transform(state: &mut [u32; 4], input: &[u32; 16]) {
16 let (mut a, mut b, mut c, mut d) = (state[0], state[1], state[2], state[3]);
17 macro_rules! add(
18 ($a:expr, $b:expr) => ($a.wrapping_add($b));
19 );
20 macro_rules! rotate(
21 ($x:expr, $n:expr) => (($x << $n) | ($x >> (32 - $n)));
22 );
23 {
24 macro_rules! F(
25 ($x:expr, $y:expr, $z:expr) => (($x & $y) | (!$x & $z));
26 );
27 macro_rules! T(
28 ($a:expr, $b:expr, $c:expr, $d:expr, $x:expr, $s:expr, $ac:expr) => ({
29 $a = add!(add!(add!($a, F!($b, $c, $d)), $x), $ac);
30 $a = rotate!($a, $s);
31 $a = add!($a, $b);
32 });
33 );
34 const S1: u32 = 7;
35 const S2: u32 = 12;
36 const S3: u32 = 17;
37 const S4: u32 = 22;
38 T!(a, b, c, d, input[0], S1, 3614090360);
39 T!(d, a, b, c, input[1], S2, 3905402710);
40 T!(c, d, a, b, input[2], S3, 606105819);
41 T!(b, c, d, a, input[3], S4, 3250441966);
42 T!(a, b, c, d, input[4], S1, 4118548399);
43 T!(d, a, b, c, input[5], S2, 1200080426);
44 T!(c, d, a, b, input[6], S3, 2821735955);
45 T!(b, c, d, a, input[7], S4, 4249261313);
46 T!(a, b, c, d, input[8], S1, 1770035416);
47 T!(d, a, b, c, input[9], S2, 2336552879);
48 T!(c, d, a, b, input[10], S3, 4294925233);
49 T!(b, c, d, a, input[11], S4, 2304563134);
50 T!(a, b, c, d, input[12], S1, 1804603682);
51 T!(d, a, b, c, input[13], S2, 4254626195);
52 T!(c, d, a, b, input[14], S3, 2792965006);
53 T!(b, c, d, a, input[15], S4, 1236535329);
54 }
55 {
56 macro_rules! F(
57 ($x:expr, $y:expr, $z:expr) => (($x & $z) | ($y & !$z));
58 );
59 macro_rules! T(
60 ($a:expr, $b:expr, $c:expr, $d:expr, $x:expr, $s:expr, $ac:expr) => ({
61 $a = add!(add!(add!($a, F!($b, $c, $d)), $x), $ac);
62 $a = rotate!($a, $s);
63 $a = add!($a, $b);
64 });
65 );
66 const S1: u32 = 5;
67 const S2: u32 = 9;
68 const S3: u32 = 14;
69 const S4: u32 = 20;
70 T!(a, b, c, d, input[1], S1, 4129170786);
71 T!(d, a, b, c, input[6], S2, 3225465664);
72 T!(c, d, a, b, input[11], S3, 643717713);
73 T!(b, c, d, a, input[0], S4, 3921069994);
74 T!(a, b, c, d, input[5], S1, 3593408605);
75 T!(d, a, b, c, input[10], S2, 38016083);
76 T!(c, d, a, b, input[15], S3, 3634488961);
77 T!(b, c, d, a, input[4], S4, 3889429448);
78 T!(a, b, c, d, input[9], S1, 568446438);
79 T!(d, a, b, c, input[14], S2, 3275163606);
80 T!(c, d, a, b, input[3], S3, 4107603335);
81 T!(b, c, d, a, input[8], S4, 1163531501);
82 T!(a, b, c, d, input[13], S1, 2850285829);
83 T!(d, a, b, c, input[2], S2, 4243563512);
84 T!(c, d, a, b, input[7], S3, 1735328473);
85 T!(b, c, d, a, input[12], S4, 2368359562);
86 }
87 {
88 macro_rules! F(
89 ($x:expr, $y:expr, $z:expr) => ($x ^ $y ^ $z);
90 );
91 macro_rules! T(
92 ($a:expr, $b:expr, $c:expr, $d:expr, $x:expr, $s:expr, $ac:expr) => ({
93 $a = add!(add!(add!($a, F!($b, $c, $d)), $x), $ac);
94 $a = rotate!($a, $s);
95 $a = add!($a, $b);
96 });
97 );
98 const S1: u32 = 4;
99 const S2: u32 = 11;
100 const S3: u32 = 16;
101 const S4: u32 = 23;
102 T!(a, b, c, d, input[5], S1, 4294588738);
103 T!(d, a, b, c, input[8], S2, 2272392833);
104 T!(c, d, a, b, input[11], S3, 1839030562);
105 T!(b, c, d, a, input[14], S4, 4259657740);
106 T!(a, b, c, d, input[1], S1, 2763975236);
107 T!(d, a, b, c, input[4], S2, 1272893353);
108 T!(c, d, a, b, input[7], S3, 4139469664);
109 T!(b, c, d, a, input[10], S4, 3200236656);
110 T!(a, b, c, d, input[13], S1, 681279174);
111 T!(d, a, b, c, input[0], S2, 3936430074);
112 T!(c, d, a, b, input[3], S3, 3572445317);
113 T!(b, c, d, a, input[6], S4, 76029189);
114 T!(a, b, c, d, input[9], S1, 3654602809);
115 T!(d, a, b, c, input[12], S2, 3873151461);
116 T!(c, d, a, b, input[15], S3, 530742520);
117 T!(b, c, d, a, input[2], S4, 3299628645);
118 }
119 {
120 macro_rules! F(
121 ($x:expr, $y:expr, $z:expr) => ($y ^ ($x | !$z));
122 );
123 macro_rules! T(
124 ($a:expr, $b:expr, $c:expr, $d:expr, $x:expr, $s:expr, $ac:expr) => ({
125 $a = add!(add!(add!($a, F!($b, $c, $d)), $x), $ac);
126 $a = rotate!($a, $s);
127 $a = add!($a, $b);
128 });
129 );
130 const S1: u32 = 6;
131 const S2: u32 = 10;
132 const S3: u32 = 15;
133 const S4: u32 = 21;
134 T!(a, b, c, d, input[0], S1, 4096336452);
135 T!(d, a, b, c, input[7], S2, 1126891415);
136 T!(c, d, a, b, input[14], S3, 2878612391);
137 T!(b, c, d, a, input[5], S4, 4237533241);
138 T!(a, b, c, d, input[12], S1, 1700485571);
139 T!(d, a, b, c, input[3], S2, 2399980690);
140 T!(c, d, a, b, input[10], S3, 4293915773);
141 T!(b, c, d, a, input[1], S4, 2240044497);
142 T!(a, b, c, d, input[8], S1, 1873313359);
143 T!(d, a, b, c, input[15], S2, 4264355552);
144 T!(c, d, a, b, input[6], S3, 2734768916);
145 T!(b, c, d, a, input[13], S4, 1309151649);
146 T!(a, b, c, d, input[4], S1, 4149444226);
147 T!(d, a, b, c, input[11], S2, 3174756917);
148 T!(c, d, a, b, input[2], S3, 718787259);
149 T!(b, c, d, a, input[9], S4, 3951481745);
150 }
151 state[0] = add!(state[0], a);
152 state[1] = add!(state[1], b);
153 state[2] = add!(state[2], c);
154 state[3] = add!(state[3], d);
155}
156
157impl Context {
158 fn new() -> Self {
159 Context {
160 input: [0u8; 64],
161 i: [0, 0],
162 buf: [0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476],
163 }
164 }
165
166 fn update(&mut self, buf: &[u8]) {
167 let mut input = [0u32; 16];
168 let mut mdi = ((self.i[0] >> 3) & 0x3f) as usize;
169
170 let length = buf.len() as u32;
172
173 if self.i[0].wrapping_add(length) << 3 < self.i[0] {
174 self.i[1] = self.i[1].wrapping_add(1);
175 }
176
177 self.i[0] = self.i[0].wrapping_add(length << 3);
178 self.i[1] = self.i[1].wrapping_add(length >> 29);
179
180 for &byte in buf {
181 self.input[mdi] = byte;
182 mdi += 1;
183
184 if mdi == 0x40 {
185 let mut j = 0;
186 for i in 0..16 {
187 input[i] = (self.input[j + 3] as u32) << 24;
188 input[i] |= (self.input[j + 2] as u32) << 16;
189 input[i] |= (self.input[j + 1] as u32) << 8;
190 input[i] |= self.input[j] as u32;
191 j += 4;
192 }
193
194 transform(&mut self.buf, &input);
195 mdi = 0;
196 }
197 }
198 }
199}
200
201pub fn sign(blob: &[u8], out: &mut [u32; 4]) {
203 const SECRET_HASH_OFFSET: usize = 20;
204 let mut context = Context::new();
205
206 let blob = &blob[SECRET_HASH_OFFSET..];
209
210 let len = blob.len() as u32;
211 let num_bits = len * 8;
212 let full_chunks_size = len & 0xffffffc0;
213
214 context.update(&blob[..full_chunks_size as usize]);
215
216 let last_chunk_data = &blob[full_chunks_size as usize..];
217 let padding_size = 64 - (blob.len() - full_chunks_size as usize);
218
219 if last_chunk_data.len() >= 56 {
220 context.update(last_chunk_data);
221
222 context.update(&PADDING[0..padding_size]);
224
225 let mut input = [0u32; 16];
226 input[0] = num_bits;
227 input[15] = (num_bits >> 2) | 1;
228 transform(&mut context.buf, &input);
229 } else {
230 let num_bits_bytes = bytemuck::bytes_of(&num_bits);
231 context.update(num_bits_bytes);
232 if last_chunk_data.len() != 0 {
233 context.update(last_chunk_data);
234 }
235
236 let padding_size = padding_size - ::core::mem::size_of::<u32>();
238
239 context.input[last_chunk_data.len() + ::core::mem::size_of::<u32>()..]
241 .copy_from_slice(&PADDING[0..padding_size]);
242
243 let num_bits_shift = num_bits >> 2 | 1;
244
245 bytemuck::cast_slice_mut::<_, u32>(&mut context.input)[15] = num_bits_shift;
246
247 let mut input = [0u32; 16];
248 input.copy_from_slice(bytemuck::cast_slice(&context.input));
249 transform(&mut context.buf, &input);
250 }
251
252 out.copy_from_slice(&context.buf);
253}
254
255pub fn sign_in_place(blob: &mut [u8]) {
257 let mut signature = [0u32; 4];
258 sign(&blob, &mut signature);
259 blob[4..20].copy_from_slice(bytemuck::cast_slice(&signature));
260}
261
262#[cfg(test)]
263mod test {
264 use crate::sign;
265
266 const REAL_SIGNED_BLOB: &[u8] = include_bytes!("../mipmap.dxil.blob");
267 const REAL_SIGNED_COMPLEX_BLOB: &[u8] = include_bytes!("../realsigned_complex.blob");
268
269 #[test]
270 pub fn test() {
271 let sig = &REAL_SIGNED_BLOB[4..20];
272 let mut out_sig = [0u32; 4];
273
274 sign(&REAL_SIGNED_BLOB, &mut out_sig);
275
276 assert_eq!(sig, bytemuck::cast_slice(&out_sig));
277 }
278
279 #[test]
280 pub fn test_complex() {
281 let sig = &REAL_SIGNED_COMPLEX_BLOB[4..20];
282 let mut out_sig = [0u32; 4];
283
284 sign(&REAL_SIGNED_COMPLEX_BLOB, &mut out_sig);
285
286 assert_eq!(sig, bytemuck::cast_slice(&out_sig));
287 }
288}