-
Notifications
You must be signed in to change notification settings - Fork 165
Expand file tree
/
Copy patharray.rs
More file actions
91 lines (80 loc) · 2.83 KB
/
Copy patharray.rs
File metadata and controls
91 lines (80 loc) · 2.83 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
//! Array helpers: generic selection/equality operations for arrays.
//!
//! Use these in the event there isn't an impl of a given trait for `[T; N]`. If there is, however,
//! you should prefer that for performance reasons.
use crate::{Choice, CtAssign, CtEq, CtSelect, slice};
/// Generic implementation of conditional assignment for arrays which works with any type which
/// impls `CtSelect`. Useful in the event there isn't a `CtAssign` impl for `[T; N]`.
///
/// Assigns `src` to `dst` in constant-time when `choice` is [`Choice::TRUE`].
///
/// Unfortunately we can't provide this as a trait impl without specialization, since it would
/// overlap with the optimized type-specific impls we provide.
#[inline]
pub fn ct_assign<T, const N: usize>(dst: &mut [T; N], src: &[T; N], choice: Choice)
where
T: CtAssign,
{
slice::ct_assign(dst, src, choice);
}
/// Generic implementation of constant-time equality testing for arrays which works with any type
/// which impls `CtEq`. Useful in the event there isn't a `CtEq` impl for `[T; N]`.
#[inline]
#[must_use]
pub fn ct_eq<T, const N: usize>(a: &[T; N], b: &[T; N]) -> Choice
where
T: CtEq,
{
let mut ret = Choice::TRUE;
for (a, b) in a.iter().zip(b.iter()) {
ret &= a.ct_eq(b);
}
ret
}
/// Generic implementation of conditional selection for arrays which works with any type which
/// impls `CtSelect`. Useful in the event there isn't a `CtSelect` impl for `[T; N]`.
///
/// Selects `a` if `choice` is `Choice::FALSE`, and `b` if `choice` is `Choice::TRUE`.
///
/// Unfortunately we can't provide this as a trait impl without specialization, since it would
/// overlap with the optimized type-specific impls we provide.
#[inline]
#[must_use]
pub fn ct_select<T, const N: usize>(a: &[T; N], b: &[T; N], choice: Choice) -> [T; N]
where
T: CtSelect,
{
core::array::from_fn(|i| T::ct_select(&a[i], &b[i], choice))
}
#[cfg(test)]
mod tests {
use crate::Choice;
// Note: this violates our own advice not to use these functions with e.g. `[u8; N]` but this
// is just for testing purposes
const EXAMPLE_A: [u8; 3] = [1, 2, 3];
const EXAMPLE_B: [u8; 3] = [4, 5, 6];
#[test]
fn ct_assign() {
let mut x = EXAMPLE_A;
super::ct_assign(&mut x, &EXAMPLE_B, Choice::FALSE);
assert_eq!(EXAMPLE_A, x);
super::ct_assign(&mut x, &EXAMPLE_B, Choice::TRUE);
assert_eq!(EXAMPLE_B, x);
}
#[test]
fn ct_eq() {
assert!(super::ct_eq(&EXAMPLE_A, &EXAMPLE_A).to_bool());
assert!(!super::ct_eq(&EXAMPLE_A, &EXAMPLE_B).to_bool());
}
#[test]
fn ct_select() {
assert_eq!(
EXAMPLE_A,
super::ct_select(&EXAMPLE_A, &EXAMPLE_B, Choice::FALSE)
);
assert_eq!(
EXAMPLE_B,
super::ct_select(&EXAMPLE_A, &EXAMPLE_B, Choice::TRUE)
);
}
}