1#![no_std]
4
5pub use aligned_array::{subtle, Aligned, AsAlignedChunks, AsNeSlice, A64, A8};
6pub use generic_array::{arr, typenum, ArrayLength, GenericArray};
7use subtle::Choice;
8
9pub type A8Bytes<N> = Aligned<A8, GenericArray<u8, N>>;
11pub type A64Bytes<N> = Aligned<A64, GenericArray<u8, N>>;
13
14pub trait CMov: Sized {
32 fn cmov(&mut self, condition: Choice, src: &Self);
33}
34
35impl CMov for u32 {
36 #[inline]
37 fn cmov(&mut self, condition: Choice, src: &u32) {
38 cmov_impl::cmov_u32(condition.unwrap_u8() != 0, src, self)
39 }
40}
41
42impl CMov for u64 {
43 #[inline]
44 fn cmov(&mut self, condition: Choice, src: &u64) {
45 cmov_impl::cmov_u64(condition.unwrap_u8() != 0, src, self)
46 }
47}
48
49impl CMov for i32 {
50 #[inline]
51 fn cmov(&mut self, condition: Choice, src: &i32) {
52 cmov_impl::cmov_i32(condition.unwrap_u8() != 0, src, self)
53 }
54}
55
56impl CMov for i64 {
57 #[inline]
58 fn cmov(&mut self, condition: Choice, src: &i64) {
59 cmov_impl::cmov_i64(condition.unwrap_u8() != 0, src, self)
60 }
61}
62
63impl CMov for usize {
64 #[inline]
65 fn cmov(&mut self, condition: Choice, src: &usize) {
66 cmov_impl::cmov_usize(condition.unwrap_u8() != 0, src, self)
67 }
68}
69
70impl CMov for bool {
71 #[inline]
72 fn cmov(&mut self, condition: Choice, src: &bool) {
73 let mut temp = *self as u32;
74 temp.cmov(condition, &(*src as u32));
75 *self = temp != 0;
76 }
77}
78
79impl<N: ArrayLength<u8>> CMov for A8Bytes<N> {
80 #[inline]
81 fn cmov(&mut self, condition: Choice, src: &A8Bytes<N>) {
82 cmov_impl::cmov_a8_bytes(condition.unwrap_u8() != 0, src, self)
83 }
84}
85
86impl<N: ArrayLength<u8>> CMov for A64Bytes<N> {
87 #[inline]
88 fn cmov(&mut self, condition: Choice, src: &A64Bytes<N>) {
89 cmov_impl::cmov_a64_bytes(condition.unwrap_u8() != 0, src, self)
90 }
91}
92
93#[inline]
94pub fn cswap<T: CMov + Default>(condition: Choice, a: &mut T, b: &mut T) {
95 let mut temp = T::default();
96 temp.cmov(condition, a);
97 a.cmov(condition, b);
98 b.cmov(condition, &temp);
99}
100
101#[cfg_attr(not(feature = "no_asm_insecure"), path = "cmov_impl_asm.rs")]
102#[cfg_attr(feature = "no_asm_insecure", path = "cmov_impl_no_asm.rs")]
103mod cmov_impl;
104
105#[cfg(test)]
106mod testing {
107 use super::*;
108 use typenum::{U128, U3, U320, U448, U64, U72, U8, U96};
109
110 fn to_a8_bytes<N: ArrayLength<u8>>(src: &[u8]) -> A8Bytes<N> {
114 Aligned(GenericArray::from_slice(src).clone())
115 }
116
117 fn to_a64_bytes<N: ArrayLength<u8>>(src: &[u8]) -> A64Bytes<N> {
118 Aligned(GenericArray::from_slice(src).clone())
119 }
120
121 #[test]
122 fn test_cmov_u32() {
123 let ctrue: Choice = Choice::from(1u8);
124 let cfalse: Choice = Choice::from(0u8);
125
126 let mut a = 0u32;
127 a.cmov(ctrue, &1);
128 assert_eq!(a, 1);
129
130 a.cmov(ctrue, &2);
131 assert_eq!(a, 2);
132
133 a.cmov(cfalse, &0);
134 assert_eq!(a, 2);
135
136 a.cmov(ctrue, &0);
137 assert_eq!(a, 0);
138 }
139
140 #[test]
141 fn test_cmov_u64() {
142 let ctrue: Choice = Choice::from(1u8);
143 let cfalse: Choice = Choice::from(0u8);
144
145 let mut a = 0u64;
146 a.cmov(ctrue, &1);
147 assert_eq!(a, 1);
148
149 a.cmov(ctrue, &2);
150 assert_eq!(a, 2);
151
152 a.cmov(cfalse, &0);
153 assert_eq!(a, 2);
154
155 a.cmov(ctrue, &0);
156 assert_eq!(a, 0);
157 }
158
159 #[test]
160 fn test_cmov_i32() {
161 let ctrue: Choice = Choice::from(1u8);
162 let cfalse: Choice = Choice::from(0u8);
163
164 let mut a = 0i32;
165 a.cmov(ctrue, &1);
166 assert_eq!(a, 1);
167
168 a.cmov(ctrue, &2);
169 assert_eq!(a, 2);
170
171 a.cmov(cfalse, &0);
172 assert_eq!(a, 2);
173
174 a.cmov(ctrue, &0);
175 assert_eq!(a, 0);
176 }
177
178 #[test]
179 fn test_cmov_i64() {
180 let ctrue: Choice = Choice::from(1u8);
181 let cfalse: Choice = Choice::from(0u8);
182
183 let mut a = 0i64;
184 a.cmov(ctrue, &1);
185 assert_eq!(a, 1);
186
187 a.cmov(ctrue, &2);
188 assert_eq!(a, 2);
189
190 a.cmov(cfalse, &0);
191 assert_eq!(a, 2);
192
193 a.cmov(ctrue, &0);
194 assert_eq!(a, 0);
195 }
196
197 #[test]
198 fn test_cmov_usize() {
199 let ctrue: Choice = Choice::from(1u8);
200 let cfalse: Choice = Choice::from(0u8);
201
202 let mut a = 0usize;
203 a.cmov(ctrue, &1usize);
204 assert_eq!(a, 1);
205
206 a.cmov(ctrue, &2usize);
207 assert_eq!(a, 2);
208
209 a.cmov(cfalse, &0usize);
210 assert_eq!(a, 2);
211
212 a.cmov(ctrue, &0usize);
213 assert_eq!(a, 0);
214 }
215
216 #[test]
217 fn test_cmov_64bytes() {
218 let ctrue: Choice = Choice::from(1u8);
219 let cfalse: Choice = Choice::from(0u8);
220
221 let mut a: A8Bytes<U64> = to_a8_bytes(&[0u8; 64]);
222 a.cmov(ctrue, &to_a8_bytes(&[1u8; 64]));
223 assert_eq!(*a, *to_a8_bytes(&[1u8; 64]));
224
225 a.cmov(cfalse, &to_a8_bytes(&[0u8; 64]));
226 assert_eq!(*a, *to_a8_bytes(&[1u8; 64]));
227
228 a.cmov(ctrue, &to_a8_bytes(&[2u8; 64]));
229 assert_eq!(*a, *to_a8_bytes(&[2u8; 64]));
230
231 a.cmov(cfalse, &to_a8_bytes(&[1u8; 64]));
232 assert_eq!(*a, *to_a8_bytes(&[2u8; 64]));
233
234 a.cmov(cfalse, &to_a8_bytes(&[0u8; 64]));
235 assert_eq!(*a, *to_a8_bytes(&[2u8; 64]));
236
237 a.cmov(ctrue, &to_a8_bytes(&[0u8; 64]));
238 assert_eq!(*a, *to_a8_bytes(&[0u8; 64]));
239
240 a.cmov(ctrue, &to_a8_bytes(&[3u8; 64]));
241 assert_eq!(*a, *to_a8_bytes(&[3u8; 64]));
242
243 a.cmov(cfalse, &to_a8_bytes(&[0u8; 64]));
244 assert_eq!(*a, *to_a8_bytes(&[3u8; 64]));
245 }
246
247 #[test]
248 fn test_cmov_96bytes() {
249 let ctrue: Choice = Choice::from(1u8);
250 let cfalse: Choice = Choice::from(0u8);
251
252 let mut a: A8Bytes<U96> = to_a8_bytes(&[0u8; 96]);
253 a.cmov(ctrue, &to_a8_bytes(&[1u8; 96]));
254 assert_eq!(*a, *to_a8_bytes(&[1u8; 96]));
255
256 a.cmov(cfalse, &to_a8_bytes(&[0u8; 96]));
257 assert_eq!(*a, *to_a8_bytes(&[1u8; 96]));
258
259 a.cmov(ctrue, &to_a8_bytes(&[2u8; 96]));
260 assert_eq!(*a, *to_a8_bytes(&[2u8; 96]));
261
262 a.cmov(cfalse, &to_a8_bytes(&[1u8; 96]));
263 assert_eq!(*a, *to_a8_bytes(&[2u8; 96]));
264
265 a.cmov(cfalse, &to_a8_bytes(&[0u8; 96]));
266 assert_eq!(*a, *to_a8_bytes(&[2u8; 96]));
267
268 a.cmov(ctrue, &to_a8_bytes(&[0u8; 96]));
269 assert_eq!(*a, *to_a8_bytes(&[0u8; 96]));
270
271 a.cmov(ctrue, &to_a8_bytes(&[3u8; 96]));
272 assert_eq!(*a, *to_a8_bytes(&[3u8; 96]));
273
274 a.cmov(cfalse, &to_a8_bytes(&[0u8; 96]));
275 assert_eq!(*a, *to_a8_bytes(&[3u8; 96]));
276 }
277
278 #[test]
279 fn test_cmov_72bytes() {
280 let ctrue: Choice = Choice::from(1u8);
281 let cfalse: Choice = Choice::from(0u8);
282
283 let mut a: A8Bytes<U72> = to_a8_bytes(&[0u8; 72]);
284 a.cmov(ctrue, &to_a8_bytes(&[1u8; 72]));
285 assert_eq!(*a, *to_a8_bytes(&[1u8; 72]));
286
287 a.cmov(cfalse, &to_a8_bytes(&[0u8; 72]));
288 assert_eq!(*a, *to_a8_bytes(&[1u8; 72]));
289
290 a.cmov(ctrue, &to_a8_bytes(&[2u8; 72]));
291 assert_eq!(*a, *to_a8_bytes(&[2u8; 72]));
292
293 a.cmov(cfalse, &to_a8_bytes(&[1u8; 72]));
294 assert_eq!(*a, *to_a8_bytes(&[2u8; 72]));
295
296 a.cmov(cfalse, &to_a8_bytes(&[0u8; 72]));
297 assert_eq!(*a, *to_a8_bytes(&[2u8; 72]));
298
299 a.cmov(ctrue, &to_a8_bytes(&[0u8; 72]));
300 assert_eq!(*a, *to_a8_bytes(&[0u8; 72]));
301
302 a.cmov(ctrue, &to_a8_bytes(&[3u8; 72]));
303 assert_eq!(*a, *to_a8_bytes(&[3u8; 72]));
304
305 a.cmov(cfalse, &to_a8_bytes(&[0u8; 72]));
306 assert_eq!(*a, *to_a8_bytes(&[3u8; 72]));
307 }
308
309 #[test]
310 fn test_cmov_8bytes() {
311 let ctrue: Choice = Choice::from(1u8);
312 let cfalse: Choice = Choice::from(0u8);
313
314 let mut a: A8Bytes<U8> = to_a8_bytes(&[0u8; 8]);
315 a.cmov(ctrue, &to_a8_bytes(&[1u8; 8]));
316 assert_eq!(*a, *to_a8_bytes(&[1u8; 8]));
317
318 a.cmov(cfalse, &to_a8_bytes(&[0u8; 8]));
319 assert_eq!(*a, *to_a8_bytes(&[1u8; 8]));
320
321 a.cmov(ctrue, &to_a8_bytes(&[2u8; 8]));
322 assert_eq!(*a, *to_a8_bytes(&[2u8; 8]));
323
324 a.cmov(cfalse, &to_a8_bytes(&[1u8; 8]));
325 assert_eq!(*a, *to_a8_bytes(&[2u8; 8]));
326
327 a.cmov(cfalse, &to_a8_bytes(&[0u8; 8]));
328 assert_eq!(*a, *to_a8_bytes(&[2u8; 8]));
329
330 a.cmov(ctrue, &to_a8_bytes(&[0u8; 8]));
331 assert_eq!(*a, *to_a8_bytes(&[0u8; 8]));
332
333 a.cmov(ctrue, &to_a8_bytes(&[3u8; 8]));
334 assert_eq!(*a, *to_a8_bytes(&[3u8; 8]));
335
336 a.cmov(cfalse, &to_a8_bytes(&[0u8; 8]));
337 assert_eq!(*a, *to_a8_bytes(&[3u8; 8]));
338 }
339
340 #[test]
341 fn test_cmov_a64_64bytes() {
342 let ctrue: Choice = Choice::from(1u8);
343 let cfalse: Choice = Choice::from(0u8);
344
345 let mut a: A64Bytes<U64> = to_a64_bytes(&[0u8; 64]);
346 a.cmov(ctrue, &to_a64_bytes(&[1u8; 64]));
347 assert_eq!(*a, *to_a64_bytes(&[1u8; 64]));
348
349 a.cmov(cfalse, &to_a64_bytes(&[0u8; 64]));
350 assert_eq!(*a, *to_a64_bytes(&[1u8; 64]));
351
352 a.cmov(ctrue, &to_a64_bytes(&[2u8; 64]));
353 assert_eq!(*a, *to_a64_bytes(&[2u8; 64]));
354
355 a.cmov(cfalse, &to_a64_bytes(&[1u8; 64]));
356 assert_eq!(*a, *to_a64_bytes(&[2u8; 64]));
357
358 a.cmov(cfalse, &to_a64_bytes(&[0u8; 64]));
359 assert_eq!(*a, *to_a64_bytes(&[2u8; 64]));
360
361 a.cmov(ctrue, &to_a64_bytes(&[0u8; 64]));
362 assert_eq!(*a, *to_a64_bytes(&[0u8; 64]));
363
364 a.cmov(ctrue, &to_a64_bytes(&[3u8; 64]));
365 assert_eq!(*a, *to_a64_bytes(&[3u8; 64]));
366
367 a.cmov(cfalse, &to_a64_bytes(&[0u8; 64]));
368 assert_eq!(*a, *to_a64_bytes(&[3u8; 64]));
369 }
370
371 #[test]
372 fn test_cmov_a64_128bytes() {
373 let ctrue: Choice = Choice::from(1u8);
374 let cfalse: Choice = Choice::from(0u8);
375
376 let mut a: A64Bytes<U128> = to_a64_bytes(&[0u8; 128]);
377 a.cmov(ctrue, &to_a64_bytes(&[1u8; 128]));
378 assert_eq!(*a, *to_a64_bytes(&[1u8; 128]));
379
380 a.cmov(cfalse, &to_a64_bytes(&[0u8; 128]));
381 assert_eq!(*a, *to_a64_bytes(&[1u8; 128]));
382
383 a.cmov(ctrue, &to_a64_bytes(&[2u8; 128]));
384 assert_eq!(*a, *to_a64_bytes(&[2u8; 128]));
385
386 a.cmov(cfalse, &to_a64_bytes(&[1u8; 128]));
387 assert_eq!(*a, *to_a64_bytes(&[2u8; 128]));
388
389 a.cmov(cfalse, &to_a64_bytes(&[0u8; 128]));
390 assert_eq!(*a, *to_a64_bytes(&[2u8; 128]));
391
392 a.cmov(ctrue, &to_a64_bytes(&[0u8; 128]));
393 assert_eq!(*a, *to_a64_bytes(&[0u8; 128]));
394
395 a.cmov(ctrue, &to_a64_bytes(&[3u8; 128]));
396 assert_eq!(*a, *to_a64_bytes(&[3u8; 128]));
397
398 a.cmov(cfalse, &to_a64_bytes(&[0u8; 128]));
399 assert_eq!(*a, *to_a64_bytes(&[3u8; 128]));
400 }
401
402 #[test]
403 fn test_cmov_a64_320bytes() {
404 let ctrue: Choice = Choice::from(1u8);
405 let cfalse: Choice = Choice::from(0u8);
406
407 let mut a: A64Bytes<U320> = to_a64_bytes(&[0u8; 320]);
408 a.cmov(ctrue, &to_a64_bytes(&[1u8; 320]));
409 assert_eq!(*a, *to_a64_bytes(&[1u8; 320]));
410
411 a.cmov(cfalse, &to_a64_bytes(&[0u8; 320]));
412 assert_eq!(*a, *to_a64_bytes(&[1u8; 320]));
413
414 a.cmov(ctrue, &to_a64_bytes(&[2u8; 320]));
415 assert_eq!(*a, *to_a64_bytes(&[2u8; 320]));
416
417 a.cmov(cfalse, &to_a64_bytes(&[1u8; 320]));
418 assert_eq!(*a, *to_a64_bytes(&[2u8; 320]));
419
420 a.cmov(cfalse, &to_a64_bytes(&[0u8; 320]));
421 assert_eq!(*a, *to_a64_bytes(&[2u8; 320]));
422
423 a.cmov(ctrue, &to_a64_bytes(&[0u8; 320]));
424 assert_eq!(*a, *to_a64_bytes(&[0u8; 320]));
425
426 a.cmov(ctrue, &to_a64_bytes(&[3u8; 320]));
427 assert_eq!(*a, *to_a64_bytes(&[3u8; 320]));
428
429 a.cmov(cfalse, &to_a64_bytes(&[0u8; 320]));
430 assert_eq!(*a, *to_a64_bytes(&[3u8; 320]));
431 }
432
433 #[test]
434 fn test_cmov_a64_448bytes() {
435 let ctrue: Choice = Choice::from(1u8);
436 let cfalse: Choice = Choice::from(0u8);
437
438 let mut a: A64Bytes<U448> = to_a64_bytes(&[0u8; 448]);
439 a.cmov(ctrue, &to_a64_bytes(&[1u8; 448]));
440 assert_eq!(*a, *to_a64_bytes(&[1u8; 448]));
441
442 a.cmov(cfalse, &to_a64_bytes(&[0u8; 448]));
443 assert_eq!(*a, *to_a64_bytes(&[1u8; 448]));
444
445 a.cmov(ctrue, &to_a64_bytes(&[2u8; 448]));
446 assert_eq!(*a, *to_a64_bytes(&[2u8; 448]));
447
448 a.cmov(cfalse, &to_a64_bytes(&[1u8; 448]));
449 assert_eq!(*a, *to_a64_bytes(&[2u8; 448]));
450
451 a.cmov(cfalse, &to_a64_bytes(&[0u8; 448]));
452 assert_eq!(*a, *to_a64_bytes(&[2u8; 448]));
453
454 a.cmov(ctrue, &to_a64_bytes(&[0u8; 448]));
455 assert_eq!(*a, *to_a64_bytes(&[0u8; 448]));
456
457 a.cmov(ctrue, &to_a64_bytes(&[3u8; 448]));
458 assert_eq!(*a, *to_a64_bytes(&[3u8; 448]));
459
460 a.cmov(cfalse, &to_a64_bytes(&[0u8; 448]));
461 assert_eq!(*a, *to_a64_bytes(&[3u8; 448]));
462 }
463
464 #[test]
465 fn test_cmov_a64_96bytes() {
466 let ctrue: Choice = Choice::from(1u8);
467 let cfalse: Choice = Choice::from(0u8);
468
469 let mut a: A64Bytes<U96> = to_a64_bytes(&[0u8; 96]);
470 a.cmov(ctrue, &to_a64_bytes(&[1u8; 96]));
471 assert_eq!(*a, *to_a64_bytes(&[1u8; 96]));
472
473 a.cmov(cfalse, &to_a64_bytes(&[0u8; 96]));
474 assert_eq!(*a, *to_a64_bytes(&[1u8; 96]));
475
476 a.cmov(ctrue, &to_a64_bytes(&[2u8; 96]));
477 assert_eq!(*a, *to_a64_bytes(&[2u8; 96]));
478
479 a.cmov(cfalse, &to_a64_bytes(&[1u8; 96]));
480 assert_eq!(*a, *to_a64_bytes(&[2u8; 96]));
481
482 a.cmov(cfalse, &to_a64_bytes(&[0u8; 96]));
483 assert_eq!(*a, *to_a64_bytes(&[2u8; 96]));
484
485 a.cmov(ctrue, &to_a64_bytes(&[0u8; 96]));
486 assert_eq!(*a, *to_a64_bytes(&[0u8; 96]));
487
488 a.cmov(ctrue, &to_a64_bytes(&[3u8; 96]));
489 assert_eq!(*a, *to_a64_bytes(&[3u8; 96]));
490
491 a.cmov(cfalse, &to_a64_bytes(&[0u8; 96]));
492 assert_eq!(*a, *to_a64_bytes(&[3u8; 96]));
493 }
494
495 #[test]
496 fn test_cmov_a64_3bytes() {
497 let ctrue: Choice = Choice::from(1u8);
498 let cfalse: Choice = Choice::from(0u8);
499
500 let mut a: A64Bytes<U3> = to_a64_bytes(&[0u8; 3]);
501 a.cmov(ctrue, &to_a64_bytes(&[1u8; 3]));
502 assert_eq!(*a, *to_a64_bytes(&[1u8; 3]));
503
504 a.cmov(cfalse, &to_a64_bytes(&[0u8; 3]));
505 assert_eq!(*a, *to_a64_bytes(&[1u8; 3]));
506
507 a.cmov(ctrue, &to_a64_bytes(&[2u8; 3]));
508 assert_eq!(*a, *to_a64_bytes(&[2u8; 3]));
509
510 a.cmov(cfalse, &to_a64_bytes(&[1u8; 3]));
511 assert_eq!(*a, *to_a64_bytes(&[2u8; 3]));
512
513 a.cmov(cfalse, &to_a64_bytes(&[0u8; 3]));
514 assert_eq!(*a, *to_a64_bytes(&[2u8; 3]));
515
516 a.cmov(ctrue, &to_a64_bytes(&[0u8; 3]));
517 assert_eq!(*a, *to_a64_bytes(&[0u8; 3]));
518
519 a.cmov(ctrue, &to_a64_bytes(&[3u8; 3]));
520 assert_eq!(*a, *to_a64_bytes(&[3u8; 3]));
521
522 a.cmov(cfalse, &to_a64_bytes(&[0u8; 3]));
523 assert_eq!(*a, *to_a64_bytes(&[3u8; 3]));
524 }
525
526 #[test]
527 fn test_cmov_a64_72bytes() {
528 let ctrue: Choice = Choice::from(1u8);
529 let cfalse: Choice = Choice::from(0u8);
530
531 let mut a: A64Bytes<U72> = to_a64_bytes(&[0u8; 72]);
532 a.cmov(ctrue, &to_a64_bytes(&[1u8; 72]));
533 assert_eq!(*a, *to_a64_bytes(&[1u8; 72]));
534
535 a.cmov(cfalse, &to_a64_bytes(&[0u8; 72]));
536 assert_eq!(*a, *to_a64_bytes(&[1u8; 72]));
537
538 a.cmov(ctrue, &to_a64_bytes(&[2u8; 72]));
539 assert_eq!(*a, *to_a64_bytes(&[2u8; 72]));
540
541 a.cmov(cfalse, &to_a64_bytes(&[1u8; 72]));
542 assert_eq!(*a, *to_a64_bytes(&[2u8; 72]));
543
544 a.cmov(cfalse, &to_a64_bytes(&[0u8; 72]));
545 assert_eq!(*a, *to_a64_bytes(&[2u8; 72]));
546
547 a.cmov(ctrue, &to_a64_bytes(&[0u8; 72]));
548 assert_eq!(*a, *to_a64_bytes(&[0u8; 72]));
549
550 a.cmov(ctrue, &to_a64_bytes(&[3u8; 72]));
551 assert_eq!(*a, *to_a64_bytes(&[3u8; 72]));
552
553 a.cmov(cfalse, &to_a64_bytes(&[0u8; 72]));
554 assert_eq!(*a, *to_a64_bytes(&[3u8; 72]));
555 }
556}