aligned_cmov/
lib.rs

1// Copyright (c) 2018-2023 The MobileCoin Foundation
2
3#![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
9/// An alias representing 8-byte aligned bytes, mainly to save typing
10pub type A8Bytes<N> = Aligned<A8, GenericArray<u8, N>>;
11/// An alias representing 64-byte aligned bytes, mainly to save typing
12pub type A64Bytes<N> = Aligned<A64, GenericArray<u8, N>>;
13
14/// CMov represents types that can be (obliviously) conditionally moved.
15///
16/// "Conditional move" means: `if condition { *dest = *src }`
17/// The interesting case is when this must be side-channel resistant and
18/// the condition cannot be leaked over CPU side-channels.
19///
20/// This API is object-oriented, and we take self = dest.
21/// This is good in rust because then you don't have to name the type
22/// to call the function.
23///
24/// These are the types that we can hope to support with ORAM,
25/// and this API allows ORAM to be written in a generic way.
26///
27/// Note: Types that own dynamic memory cannot be CMov by design.
28/// They also cannot be in an ORAM, by design.
29/// If your type has nontrivial `Drop` it is likely not reasonable to `CMov` it
30/// or put it in an ORAM.
31pub 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    // Helper to reduce boilerplate.
111    // This panics if the slice is not the right length, so it's not a good API
112    // outside of tests.
113    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}