Skip to content

Commit b3ba6bc

Browse files
committed
Merge branch 'develop' into release/2.5
2 parents 5676ecf + 6bae3ff commit b3ba6bc

11 files changed

+172
-46
lines changed

.travis.yml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,9 @@ script:
2727
cargo test --no-default-features --features std &&
2828
cargo test --no-default-features --features "std i128" &&
2929
cargo test --no-default-features --features "std core_hint_black_box" &&
30-
cargo test --no-default-features --features "std i128 core_hint_black_box"
30+
cargo test --no-default-features --features "std const-generics" &&
31+
cargo test --no-default-features --features "std i128 core_hint_black_box" &&
32+
cargo test --no-default-features --features "std i128 core_hint_black_box const-generics"
3133

3234
notifications:
3335
slack:

Cargo.toml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ name = "subtle"
66
# - update README if necessary by semver
77
# - if any updates were made to the README, also update the module documentation in src/lib.rs
88
version = "2.5.0"
9+
edition = "2018"
910
authors = ["Isis Lovecruft <isis@patternsinthevoid.net>",
1011
"Henry de Valence <hdevalence@hdevalence.ca>"]
1112
readme = "README.md"
@@ -25,9 +26,10 @@ exclude = [
2526
travis-ci = { repository = "dalek-cryptography/subtle", branch = "master"}
2627

2728
[dev-dependencies]
28-
rand = { version = "0.7" }
29+
rand = { version = "0.8" }
2930

3031
[features]
32+
const-generics = []
3133
core_hint_black_box = []
3234
default = ["std", "i128"]
3335
std = []

README.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,9 @@ Rust versions from 1.66 or higher support a new best-effort optimization
3030
barrier ([`core::hint::black_box`]). To use the new optimization barrier,
3131
enable the `core_hint_black_box` feature.
3232

33+
Rust versions from 1.51 or higher have const generics support. You may enable
34+
`const-generics` feautre to have `subtle` traits implemented for arrays `[T; N]`.
35+
3336
Versions prior to `2.2` recommended use of the `nightly` feature to enable an
3437
optimization barrier; this is not required in versions `2.2` and above.
3538

fuzz/Cargo.toml

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,19 @@
1-
21
[package]
32
name = "subtle-fuzz"
43
version = "0.0.1"
54
authors = ["Automatically generated"]
65
publish = false
6+
edition = "2018"
77

88
[package.metadata]
99
cargo-fuzz = true
1010

1111
[dependencies.subtle]
1212
path = ".."
13-
features = ["nightly"]
14-
[dependencies.libfuzzer-sys]
15-
git = "https://github.com/rust-fuzz/libfuzzer-sys.git"
13+
features = ["nightly", "const-generics"]
14+
15+
[dependencies]
16+
libfuzzer-sys = "0.4"
1617

1718
# Prevent this from interfering with workspaces
1819
[workspace]
@@ -21,15 +22,27 @@ members = ["."]
2122
[[bin]]
2223
name = "conditional_assign_u8"
2324
path = "fuzzers/conditional_assign_u8.rs"
25+
test = false
26+
doc = false
2427

2528
[[bin]]
2629
name = "conditional_assign_u16"
2730
path = "fuzzers/conditional_assign_u16.rs"
31+
test = false
32+
doc = false
2833

2934
[[bin]]
3035
name = "conditional_assign_i8"
3136
path = "fuzzers/conditional_assign_i8.rs"
37+
test = false
38+
doc = false
3239

3340
[[bin]]
3441
name = "conditional_assign_i128"
3542
path = "fuzzers/conditional_assign_i128.rs"
43+
test = false
44+
doc = false
45+
46+
[[bin]]
47+
name = "conditional_assign_array"
48+
path = "fuzzers/conditional_assign_array.rs"
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
#![no_main]
2+
3+
#[macro_use]
4+
extern crate libfuzzer_sys;
5+
extern crate subtle;
6+
extern crate core;
7+
8+
use core::convert::TryFrom;
9+
10+
use subtle::ConditionallySelectable;
11+
12+
fuzz_target!(|data: &[u8]| {
13+
let chunk_size: usize = 16;
14+
15+
if data.len() % chunk_size != 0 {
16+
return;
17+
}
18+
19+
for bytes in data.chunks(chunk_size) {
20+
let mut x = [0u8; 16];
21+
let y = <[u8; 16]>::try_from(bytes).unwrap();
22+
23+
x.conditional_assign(&y, 0.into());
24+
assert_eq!(x, [0u8; 16]);
25+
26+
x.conditional_assign(&y, 1.into());
27+
assert_eq!(x, y);
28+
}
29+
});

fuzz/fuzzers/conditional_assign_i128.rs

Lines changed: 5 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,6 @@
11
#![no_main]
2-
3-
#[macro_use]
4-
extern crate libfuzzer_sys;
5-
extern crate subtle;
6-
extern crate core;
7-
2+
use libfuzzer_sys::fuzz_target;
83
use core::intrinsics::transmute;
9-
104
use subtle::ConditionallySelectable;
115

126
fuzz_target!(|data: &[u8]| {
@@ -20,10 +14,10 @@ fuzz_target!(|data: &[u8]| {
2014
unsafe {
2115
let mut x: i128 = 0;
2216
let y: i128 = transmute::<[u8; 16], i128>([
23-
bytes[0], bytes[1], bytes[2], bytes[3],
24-
bytes[4], bytes[5], bytes[6], bytes[7],
25-
bytes[8], bytes[9], bytes[10], bytes[11],
26-
bytes[12], bytes[13], bytes[14], bytes[15]]);
17+
bytes[0], bytes[1], bytes[2], bytes[3], bytes[4], bytes[5], bytes[6], bytes[7],
18+
bytes[8], bytes[9], bytes[10], bytes[11], bytes[12], bytes[13], bytes[14],
19+
bytes[15],
20+
]);
2721

2822
x.conditional_assign(&y, 0.into());
2923
assert_eq!(x, 0);

fuzz/fuzzers/conditional_assign_i8.rs

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,6 @@
11
#![no_main]
2-
3-
#[macro_use]
4-
extern crate libfuzzer_sys;
5-
extern crate subtle;
6-
extern crate core;
7-
2+
use libfuzzer_sys::fuzz_target;
83
use core::intrinsics::transmute;
9-
104
use subtle::ConditionallySelectable;
115

126
fuzz_target!(|data: &[u8]| {

fuzz/fuzzers/conditional_assign_u16.rs

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,6 @@
11
#![no_main]
2-
3-
#[macro_use]
4-
extern crate libfuzzer_sys;
5-
extern crate subtle;
6-
extern crate core;
7-
2+
use libfuzzer_sys::fuzz_target;
83
use core::intrinsics::transmute;
9-
104
use subtle::ConditionallySelectable;
115

126
fuzz_target!(|data: &[u8]| {

fuzz/fuzzers/conditional_assign_u8.rs

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,5 @@
11
#![no_main]
2-
3-
#[macro_use]
4-
extern crate libfuzzer_sys;
5-
extern crate subtle;
6-
extern crate core;
7-
2+
use libfuzzer_sys::fuzz_target;
83
use subtle::ConditionallySelectable;
94

105
fuzz_target!(|data: &[u8]| {

src/lib.rs

Lines changed: 73 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,9 @@
4545
//! barrier ([`core::hint::black_box`]). To use the new optimization barrier,
4646
//! enable the `core_hint_black_box` feature.
4747
//!
48+
//! Rust versions from 1.51 or higher have const generics support. You may enable
49+
//! `const-generics` feautre to have `subtle` traits implemented for arrays `[T; N]`.
50+
//!
4851
//! Versions prior to `2.2` recommended use of the `nightly` feature to enable an
4952
//! optimization barrier; this is not required in versions `2.2` and above.
5053
//!
@@ -97,6 +100,7 @@
97100
#[macro_use]
98101
extern crate std;
99102

103+
use core::cmp;
100104
use core::ops::{BitAnd, BitAndAssign, BitOr, BitOrAssign, BitXor, BitXorAssign, Neg, Not};
101105
use core::option::Option;
102106

@@ -239,7 +243,7 @@ fn black_box(input: u8) -> u8 {
239243
}
240244

241245
#[cfg(feature = "core_hint_black_box")]
242-
#[inline]
246+
#[inline(never)]
243247
fn black_box(input: u8) -> u8 {
244248
debug_assert!((input == 0u8) | (input == 1u8));
245249
core::hint::black_box(input)
@@ -381,6 +385,14 @@ generate_integer_equal!(u64, i64, 64);
381385
generate_integer_equal!(u128, i128, 128);
382386
generate_integer_equal!(usize, isize, ::core::mem::size_of::<usize>() * 8);
383387

388+
/// `Ordering` is `#[repr(i8)]` making it possible to leverage `i8::ct_eq`.
389+
impl ConstantTimeEq for cmp::Ordering {
390+
#[inline]
391+
fn ct_eq(&self, other: &Self) -> Choice {
392+
(*self as i8).ct_eq(&(*other as i8))
393+
}
394+
}
395+
384396
/// A type which can be conditionally selected in constant time.
385397
///
386398
/// This trait also provides generic implementations of conditional
@@ -398,7 +410,6 @@ pub trait ConditionallySelectable: Copy {
398410
/// # Example
399411
///
400412
/// ```
401-
/// # extern crate subtle;
402413
/// use subtle::ConditionallySelectable;
403414
/// #
404415
/// # fn main() {
@@ -421,7 +432,6 @@ pub trait ConditionallySelectable: Copy {
421432
/// # Example
422433
///
423434
/// ```
424-
/// # extern crate subtle;
425435
/// use subtle::ConditionallySelectable;
426436
/// #
427437
/// # fn main() {
@@ -447,7 +457,6 @@ pub trait ConditionallySelectable: Copy {
447457
/// # Example
448458
///
449459
/// ```
450-
/// # extern crate subtle;
451460
/// use subtle::ConditionallySelectable;
452461
/// #
453462
/// # fn main() {
@@ -542,13 +551,52 @@ generate_integer_conditional_select!( u64 i64);
542551
#[cfg(feature = "i128")]
543552
generate_integer_conditional_select!(u128 i128);
544553

554+
/// `Ordering` is `#[repr(i8)]` where:
555+
///
556+
/// - `Less` => -1
557+
/// - `Equal` => 0
558+
/// - `Greater` => 1
559+
///
560+
/// Given this, it's possible to operate on orderings as if they're integers,
561+
/// which allows leveraging conditional masking for predication.
562+
impl ConditionallySelectable for cmp::Ordering {
563+
fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self {
564+
let a = *a as i8;
565+
let b = *b as i8;
566+
let ret = i8::conditional_select(&a, &b, choice);
567+
568+
// SAFETY: `Ordering` is `#[repr(i8)]` and `ret` has been assigned to
569+
// a value which was originally a valid `Ordering` then cast to `i8`
570+
unsafe { *((&ret as *const _) as *const cmp::Ordering) }
571+
}
572+
}
573+
545574
impl ConditionallySelectable for Choice {
546575
#[inline]
547576
fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self {
548577
Choice(u8::conditional_select(&a.0, &b.0, choice))
549578
}
550579
}
551580

581+
#[cfg(feature = "const-generics")]
582+
impl<T, const N: usize> ConditionallySelectable for [T; N]
583+
where
584+
T: ConditionallySelectable,
585+
{
586+
#[inline]
587+
fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self {
588+
let mut output = *a;
589+
output.conditional_assign(b, choice);
590+
output
591+
}
592+
593+
fn conditional_assign(&mut self, other: &Self, choice: Choice) {
594+
for (a_i, b_i) in self.iter_mut().zip(other) {
595+
a_i.conditional_assign(b_i, choice)
596+
}
597+
}
598+
}
599+
552600
/// A type which can be conditionally negated in constant time.
553601
///
554602
/// # Note
@@ -794,7 +842,6 @@ pub trait ConstantTimeGreater {
794842
/// # Example
795843
///
796844
/// ```
797-
/// # extern crate subtle;
798845
/// use subtle::ConstantTimeGreater;
799846
///
800847
/// let x: u8 = 13;
@@ -847,7 +894,7 @@ macro_rules! generate_unsigned_integer_greater {
847894
Choice::from((bit & 1) as u8)
848895
}
849896
}
850-
}
897+
};
851898
}
852899

853900
generate_unsigned_integer_greater!(u8, 8);
@@ -857,6 +904,16 @@ generate_unsigned_integer_greater!(u64, 64);
857904
#[cfg(feature = "i128")]
858905
generate_unsigned_integer_greater!(u128, 128);
859906

907+
impl ConstantTimeGreater for cmp::Ordering {
908+
#[inline]
909+
fn ct_gt(&self, other: &Self) -> Choice {
910+
// No impl of `ConstantTimeGreater` for `i8`, so use `u8`
911+
let a = (*self as i8) + 1;
912+
let b = (*other as i8) + 1;
913+
(a as u8).ct_gt(&(b as u8))
914+
}
915+
}
916+
860917
/// A type which can be compared in some manner and be determined to be less
861918
/// than another of the same type.
862919
pub trait ConstantTimeLess: ConstantTimeEq + ConstantTimeGreater {
@@ -878,7 +935,6 @@ pub trait ConstantTimeLess: ConstantTimeEq + ConstantTimeGreater {
878935
/// # Example
879936
///
880937
/// ```
881-
/// # extern crate subtle;
882938
/// use subtle::ConstantTimeLess;
883939
///
884940
/// let x: u8 = 13;
@@ -908,3 +964,13 @@ impl ConstantTimeLess for u32 {}
908964
impl ConstantTimeLess for u64 {}
909965
#[cfg(feature = "i128")]
910966
impl ConstantTimeLess for u128 {}
967+
968+
impl ConstantTimeLess for cmp::Ordering {
969+
#[inline]
970+
fn ct_lt(&self, other: &Self) -> Choice {
971+
// No impl of `ConstantTimeLess` for `i8`, so use `u8`
972+
let a = (*self as i8) + 1;
973+
let b = (*other as i8) + 1;
974+
(a as u8).ct_lt(&(b as u8))
975+
}
976+
}

0 commit comments

Comments
 (0)