summaryrefslogtreecommitdiffstats
path: root/third_party/rust/subtle
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 00:47:55 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 00:47:55 +0000
commit26a029d407be480d791972afb5975cf62c9360a6 (patch)
treef435a8308119effd964b339f76abb83a57c29483 /third_party/rust/subtle
parentInitial commit. (diff)
downloadfirefox-26a029d407be480d791972afb5975cf62c9360a6.tar.xz
firefox-26a029d407be480d791972afb5975cf62c9360a6.zip
Adding upstream version 124.0.1.upstream/124.0.1
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'third_party/rust/subtle')
-rw-r--r--third_party/rust/subtle/.cargo-checksum.json1
-rw-r--r--third_party/rust/subtle/CHANGELOG.md74
-rw-r--r--third_party/rust/subtle/CONTRIBUTING.md33
-rw-r--r--third_party/rust/subtle/Cargo.toml38
-rw-r--r--third_party/rust/subtle/LICENSE28
-rw-r--r--third_party/rust/subtle/README.md82
-rw-r--r--third_party/rust/subtle/src/lib.rs976
-rw-r--r--third_party/rust/subtle/tests/mod.rs425
8 files changed, 1657 insertions, 0 deletions
diff --git a/third_party/rust/subtle/.cargo-checksum.json b/third_party/rust/subtle/.cargo-checksum.json
new file mode 100644
index 0000000000..62db1587b3
--- /dev/null
+++ b/third_party/rust/subtle/.cargo-checksum.json
@@ -0,0 +1 @@
+{"files":{"CHANGELOG.md":"02f92a31269311c965b1dfa705f22f341dc9cce73af08a8c9840c91b8ceb79df","CONTRIBUTING.md":"2fbb44138ececdef7c0950fae6ed1dcad481fb2f368df0e3734c9902be791f3e","Cargo.toml":"72ff6f9d47061233fc938824f2adc126ba9e8f686df75dec4ab7a0f44327d5c6","LICENSE":"36c48715a280d334a995f26fc38103f21cb92425a20c8eeaa368b229b49b6d4d","README.md":"9a04bb0dee4e6c350d1728ec225f162081d31273dbae6580757aadb363c76cdf","src/lib.rs":"7e14a5d5f2351343e41ff0e085a348190178ebe19cf12ffce083ce75ae6fba9d","tests/mod.rs":"61e6540375c1ccf5a5f134336d5297ecbda6ef76dd3cd81c600b303d2572e7ee"},"package":"81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc"} \ No newline at end of file
diff --git a/third_party/rust/subtle/CHANGELOG.md b/third_party/rust/subtle/CHANGELOG.md
new file mode 100644
index 0000000000..e6a3863653
--- /dev/null
+++ b/third_party/rust/subtle/CHANGELOG.md
@@ -0,0 +1,74 @@
+# Changelog
+
+Entries are listed in reverse chronological order.
+
+## 2.5.0
+
+* Add constant-timedness note to the documentation for `CtOption::unwrap_or_else`.
+* Add `CtOption::expect`.
+* Add `ConstantTimeEq::ct_ne` with default implementation.
+* Add new `core_hint_black_box` feature from Diane Hosfelt and Amber
+ Sprenkels which utilises the original `black_box` functionality from
+ when subtle was first written, which has now found it's way into the
+ Rust standard library.
+* Add new `const-generics` feature from @survived which adds support
+ for subtle traits for generic arrays `[T; N]`.
+* Add new feature for supporting `core::cmp::Ordering` for types which
+ implement subtle traits, patch from @tarcieri.
+* Update `rand` dependency to 0.8.
+
+## 2.4.1
+
+* Fix a bug in how the README was included in the documentation builds
+ which caused nightly builds to break.
+
+## 2.4.0
+
+* Add new `ConstantTimeGreater` and `ConstantTimeLess` traits, as well
+ as implementations for unsigned integers, by @isislovecruft.
+
+## 2.3.0
+
+* Add `impl ConstantTimeEq for Choice` by @tarcieri.
+* Add `impl From<CtOption<T>> for Option<T>` by @CPerezz. This is useful for
+ handling library code that produces `CtOption`s in contexts where timing
+ doesn't matter.
+* Introduce an MSRV policy.
+
+## 2.2.3
+
+* Remove the `nightly`-only asm-based `black_box` barrier in favor of the
+ volatile-based one, fixing compilation on current nightlies.
+
+## 2.2.2
+
+* Update README.md to clarify that 2.2 and above do not require the `nightly`
+ feature.
+
+## 2.2.1
+
+* Adds an `or_else` combinator for `CtOption`, by @ebfull.
+* Optimized `black_box` for `nightly`, by @jethrogb.
+* Optimized `black_box` for `stable`, by @dsprenkels.
+* Fixed CI for `no_std`, by @dsprenkels.
+* Fixed fuzz target compilation, by @3for.
+
+## 2.2.0
+
+* Error during `cargo publish`, yanked.
+
+## 2.1.1
+
+* Adds the "crypto" tag to crate metadata.
+* New shorter, more efficient ct_eq() for integers, contributed by Thomas Pornin.
+
+## 2.1.0
+
+* Adds a new `CtOption<T>` which acts as a constant-time `Option<T>`
+ (thanks to @ebfull for the implementation).
+* `Choice` now itself implements `ConditionallySelectable`.
+
+## 2.0.0
+
+* Stable version with traits reworked from 1.0.0 to interact better
+ with the orphan rules.
diff --git a/third_party/rust/subtle/CONTRIBUTING.md b/third_party/rust/subtle/CONTRIBUTING.md
new file mode 100644
index 0000000000..2d24605166
--- /dev/null
+++ b/third_party/rust/subtle/CONTRIBUTING.md
@@ -0,0 +1,33 @@
+# Contributing to subtle
+
+If you have questions or comments, please feel free to email the
+authors.
+
+For feature requests, suggestions, and bug reports, please open an
+issue on [our Github](https://github.com/dalek-cryptography/subtle). (Or,
+send us an email if you're opposed to using Github for whatever reason.)
+
+Patches are welcomed as pull requests on
+[our Github](https://github.com/dalek-cryptography/subtle), as well as by
+email (preferably sent to all of the authors listed in `Cargo.toml`).
+
+We're happy to take generalised utility code, provided the code is:
+
+1. constant time for all potential valid invocations, and
+2. applicable to implementations of several different protocols/primitives.
+
+All issues on subtle are mentored, if you want help with a bug just ask
+@isislovecruft or @hdevalence.
+
+Some issues are easier than others. The `easy` label can be used to find the
+easy issues. If you want to work on an issue, please leave a comment so that we
+can assign it to you!
+
+# Code of Conduct
+
+We follow the [Rust Code of Conduct](http://www.rust-lang.org/conduct.html),
+with the following additional clauses:
+
+* We respect the rights to privacy and anonymity for contributors and people in
+ the community. If someone wishes to contribute under a pseudonym different to
+ their primary identity, that wish is to be respected by all contributors.
diff --git a/third_party/rust/subtle/Cargo.toml b/third_party/rust/subtle/Cargo.toml
new file mode 100644
index 0000000000..351989ace0
--- /dev/null
+++ b/third_party/rust/subtle/Cargo.toml
@@ -0,0 +1,38 @@
+# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO
+#
+# When uploading crates to the registry Cargo will automatically
+# "normalize" Cargo.toml files for maximal compatibility
+# with all versions of Cargo and also rewrite `path` dependencies
+# to registry (e.g., crates.io) dependencies.
+#
+# If you are reading this file be aware that the original Cargo.toml
+# will likely look very different (and much more reasonable).
+# See Cargo.toml.orig for the original contents.
+
+[package]
+edition = "2018"
+name = "subtle"
+version = "2.5.0"
+authors = ["Isis Lovecruft <isis@patternsinthevoid.net>", "Henry de Valence <hdevalence@hdevalence.ca>"]
+exclude = ["**/.gitignore", ".travis.yml"]
+description = "Pure-Rust traits and utilities for constant-time cryptographic implementations."
+homepage = "https://dalek.rs/"
+documentation = "https://docs.rs/subtle"
+readme = "README.md"
+keywords = ["cryptography", "crypto", "constant-time", "utilities"]
+categories = ["cryptography", "no-std"]
+license = "BSD-3-Clause"
+repository = "https://github.com/dalek-cryptography/subtle"
+[dev-dependencies.rand]
+version = "0.8"
+
+[features]
+const-generics = []
+core_hint_black_box = []
+default = ["std", "i128"]
+i128 = []
+nightly = []
+std = []
+[badges.travis-ci]
+branch = "master"
+repository = "dalek-cryptography/subtle"
diff --git a/third_party/rust/subtle/LICENSE b/third_party/rust/subtle/LICENSE
new file mode 100644
index 0000000000..927c02c80b
--- /dev/null
+++ b/third_party/rust/subtle/LICENSE
@@ -0,0 +1,28 @@
+Copyright (c) 2016-2017 Isis Agora Lovecruft, Henry de Valence. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+1. Redistributions of source code must retain the above copyright
+notice, this list of conditions and the following disclaimer.
+
+2. Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+
+3. Neither the name of the copyright holder nor the names of its
+contributors may be used to endorse or promote products derived from
+this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/third_party/rust/subtle/README.md b/third_party/rust/subtle/README.md
new file mode 100644
index 0000000000..de77575540
--- /dev/null
+++ b/third_party/rust/subtle/README.md
@@ -0,0 +1,82 @@
+# subtle [![](https://img.shields.io/crates/v/subtle.svg)](https://crates.io/crates/subtle) [![](https://img.shields.io/badge/dynamic/json.svg?label=docs&uri=https%3A%2F%2Fcrates.io%2Fapi%2Fv1%2Fcrates%2Fsubtle%2Fversions&query=%24.versions%5B0%5D.num&colorB=4F74A6)](https://doc.dalek.rs/subtle) [![](https://travis-ci.org/dalek-cryptography/subtle.svg?branch=master)](https://travis-ci.org/dalek-cryptography/subtle)
+
+**Pure-Rust traits and utilities for constant-time cryptographic implementations.**
+
+It consists of a `Choice` type, and a collection of traits using `Choice`
+instead of `bool` which are intended to execute in constant-time. The `Choice`
+type is a wrapper around a `u8` that holds a `0` or `1`.
+
+```toml
+subtle = "2.5"
+```
+
+This crate represents a “best-effort” attempt, since side-channels
+are ultimately a property of a deployed cryptographic system
+including the hardware it runs on, not just of software.
+
+The traits are implemented using bitwise operations, and should execute in
+constant time provided that a) the bitwise operations are constant-time and
+b) the bitwise operations are not recognized as a conditional assignment and
+optimized back into a branch.
+
+For a compiler to recognize that bitwise operations represent a conditional
+assignment, it needs to know that the value used to generate the bitmasks is
+really a boolean `i1` rather than an `i8` byte value. In an attempt to
+prevent this refinement, the crate tries to hide the value of a `Choice`'s
+inner `u8` by passing it through a volatile read. For more information, see
+the _About_ section below.
+
+Rust versions from 1.66 or higher support a new best-effort optimization
+barrier ([`core::hint::black_box`]). To use the new optimization barrier,
+enable the `core_hint_black_box` feature.
+
+Rust versions from 1.51 or higher have const generics support. You may enable
+`const-generics` feautre to have `subtle` traits implemented for arrays `[T; N]`.
+
+Versions prior to `2.2` recommended use of the `nightly` feature to enable an
+optimization barrier; this is not required in versions `2.2` and above.
+
+Note: the `subtle` crate contains `debug_assert`s to check invariants during
+debug builds. These invariant checks involve secret-dependent branches, and
+are not present when compiled in release mode. This crate is intended to be
+used in release mode.
+
+## Documentation
+
+Documentation is available [here][docs].
+
+## Minimum Supported Rust Version
+
+Rust **1.41** or higher.
+
+Minimum supported Rust version can be changed in the future, but it will be done with a minor version bump.
+
+## About
+
+This library aims to be the Rust equivalent of Go’s `crypto/subtle` module.
+
+Old versions of the optimization barrier in `impl From<u8> for Choice` were
+based on Tim Maclean's [work on `rust-timing-shield`][rust-timing-shield],
+which attempts to provide a more comprehensive approach for preventing
+software side-channels in Rust code.
+
+From version `2.2`, it was based on Diane Hosfelt and Amber Sprenkels' work on
+"Secret Types in Rust". Version `2.5` adds the `core_hint_black_box` feature,
+which uses the original method through the [`core::hint::black_box`] function
+from the Rust standard library.
+
+`subtle` is authored by isis agora lovecruft and Henry de Valence.
+
+## Warning
+
+This code is a low-level library, intended for specific use-cases implementing
+cryptographic protocols. It represents a best-effort attempt to protect
+against some software side-channels. Because side-channel resistance is not a
+property of software alone, but of software together with hardware, any such
+effort is fundamentally limited.
+
+**USE AT YOUR OWN RISK**
+
+[docs]: https://docs.rs/subtle
+[`core::hint::black_box`]: https://doc.rust-lang.org/core/hint/fn.black_box.html
+[rust-timing-shield]: https://www.chosenplaintext.ca/open-source/rust-timing-shield/security
diff --git a/third_party/rust/subtle/src/lib.rs b/third_party/rust/subtle/src/lib.rs
new file mode 100644
index 0000000000..795eade44a
--- /dev/null
+++ b/third_party/rust/subtle/src/lib.rs
@@ -0,0 +1,976 @@
+// -*- mode: rust; -*-
+//
+// This file is part of subtle, part of the dalek cryptography project.
+// Copyright (c) 2016-2018 isis lovecruft, Henry de Valence
+// See LICENSE for licensing information.
+//
+// Authors:
+// - isis agora lovecruft <isis@patternsinthevoid.net>
+// - Henry de Valence <hdevalence@hdevalence.ca>
+
+#![no_std]
+#![deny(missing_docs)]
+#![doc(html_logo_url = "https://doc.dalek.rs/assets/dalek-logo-clear.png")]
+#![doc(html_root_url = "https://docs.rs/subtle/2.5.0")]
+
+//! # subtle [![](https://img.shields.io/crates/v/subtle.svg)](https://crates.io/crates/subtle) [![](https://img.shields.io/badge/dynamic/json.svg?label=docs&uri=https%3A%2F%2Fcrates.io%2Fapi%2Fv1%2Fcrates%2Fsubtle%2Fversions&query=%24.versions%5B0%5D.num&colorB=4F74A6)](https://doc.dalek.rs/subtle) [![](https://travis-ci.org/dalek-cryptography/subtle.svg?branch=master)](https://travis-ci.org/dalek-cryptography/subtle)
+//!
+//! **Pure-Rust traits and utilities for constant-time cryptographic implementations.**
+//!
+//! It consists of a `Choice` type, and a collection of traits using `Choice`
+//! instead of `bool` which are intended to execute in constant-time. The `Choice`
+//! type is a wrapper around a `u8` that holds a `0` or `1`.
+//!
+//! ```toml
+//! subtle = "2.5"
+//! ```
+//!
+//! This crate represents a “best-effort” attempt, since side-channels
+//! are ultimately a property of a deployed cryptographic system
+//! including the hardware it runs on, not just of software.
+//!
+//! The traits are implemented using bitwise operations, and should execute in
+//! constant time provided that a) the bitwise operations are constant-time and
+//! b) the bitwise operations are not recognized as a conditional assignment and
+//! optimized back into a branch.
+//!
+//! For a compiler to recognize that bitwise operations represent a conditional
+//! assignment, it needs to know that the value used to generate the bitmasks is
+//! really a boolean `i1` rather than an `i8` byte value. In an attempt to
+//! prevent this refinement, the crate tries to hide the value of a `Choice`'s
+//! inner `u8` by passing it through a volatile read. For more information, see
+//! the _About_ section below.
+//!
+//! Rust versions from 1.66 or higher support a new best-effort optimization
+//! barrier ([`core::hint::black_box`]). To use the new optimization barrier,
+//! enable the `core_hint_black_box` feature.
+//!
+//! Rust versions from 1.51 or higher have const generics support. You may enable
+//! `const-generics` feautre to have `subtle` traits implemented for arrays `[T; N]`.
+//!
+//! Versions prior to `2.2` recommended use of the `nightly` feature to enable an
+//! optimization barrier; this is not required in versions `2.2` and above.
+//!
+//! Note: the `subtle` crate contains `debug_assert`s to check invariants during
+//! debug builds. These invariant checks involve secret-dependent branches, and
+//! are not present when compiled in release mode. This crate is intended to be
+//! used in release mode.
+//!
+//! ## Documentation
+//!
+//! Documentation is available [here][docs].
+//!
+//! ## Minimum Supported Rust Version
+//!
+//! Rust **1.41** or higher.
+//!
+//! Minimum supported Rust version can be changed in the future, but it will be done with a minor version bump.
+//!
+//! ## About
+//!
+//! This library aims to be the Rust equivalent of Go’s `crypto/subtle` module.
+//!
+//! Old versions of the optimization barrier in `impl From<u8> for Choice` were
+//! based on Tim Maclean's [work on `rust-timing-shield`][rust-timing-shield],
+//! which attempts to provide a more comprehensive approach for preventing
+//! software side-channels in Rust code.
+//!
+//! From version `2.2`, it was based on Diane Hosfelt and Amber Sprenkels' work on
+//! "Secret Types in Rust". Version `2.5` adds the `core_hint_black_box` feature,
+//! which uses the original method through the [`core::hint::black_box`] function
+//! from the Rust standard library.
+//!
+//! `subtle` is authored by isis agora lovecruft and Henry de Valence.
+//!
+//! ## Warning
+//!
+//! This code is a low-level library, intended for specific use-cases implementing
+//! cryptographic protocols. It represents a best-effort attempt to protect
+//! against some software side-channels. Because side-channel resistance is not a
+//! property of software alone, but of software together with hardware, any such
+//! effort is fundamentally limited.
+//!
+//! **USE AT YOUR OWN RISK**
+//!
+//! [docs]: https://docs.rs/subtle
+//! [`core::hint::black_box`]: https://doc.rust-lang.org/core/hint/fn.black_box.html
+//! [rust-timing-shield]: https://www.chosenplaintext.ca/open-source/rust-timing-shield/security
+
+#[cfg(feature = "std")]
+#[macro_use]
+extern crate std;
+
+use core::cmp;
+use core::ops::{BitAnd, BitAndAssign, BitOr, BitOrAssign, BitXor, BitXorAssign, Neg, Not};
+use core::option::Option;
+
+/// The `Choice` struct represents a choice for use in conditional assignment.
+///
+/// It is a wrapper around a `u8`, which should have the value either `1` (true)
+/// or `0` (false).
+///
+/// The conversion from `u8` to `Choice` passes the value through an optimization
+/// barrier, as a best-effort attempt to prevent the compiler from inferring that
+/// the `Choice` value is a boolean. This strategy is based on Tim Maclean's
+/// [work on `rust-timing-shield`][rust-timing-shield], which attempts to provide
+/// a more comprehensive approach for preventing software side-channels in Rust
+/// code.
+///
+/// The `Choice` struct implements operators for AND, OR, XOR, and NOT, to allow
+/// combining `Choice` values. These operations do not short-circuit.
+///
+/// [rust-timing-shield]:
+/// https://www.chosenplaintext.ca/open-source/rust-timing-shield/security
+#[derive(Copy, Clone, Debug)]
+pub struct Choice(u8);
+
+impl Choice {
+ /// Unwrap the `Choice` wrapper to reveal the underlying `u8`.
+ ///
+ /// # Note
+ ///
+ /// This function only exists as an **escape hatch** for the rare case
+ /// where it's not possible to use one of the `subtle`-provided
+ /// trait impls.
+ ///
+ /// **To convert a `Choice` to a `bool`, use the `From` implementation instead.**
+ #[inline]
+ pub fn unwrap_u8(&self) -> u8 {
+ self.0
+ }
+}
+
+impl From<Choice> for bool {
+ /// Convert the `Choice` wrapper into a `bool`, depending on whether
+ /// the underlying `u8` was a `0` or a `1`.
+ ///
+ /// # Note
+ ///
+ /// This function exists to avoid having higher-level cryptographic protocol
+ /// implementations duplicating this pattern.
+ ///
+ /// The intended use case for this conversion is at the _end_ of a
+ /// higher-level primitive implementation: for example, in checking a keyed
+ /// MAC, where the verification should happen in constant-time (and thus use
+ /// a `Choice`) but it is safe to return a `bool` at the end of the
+ /// verification.
+ #[inline]
+ fn from(source: Choice) -> bool {
+ debug_assert!((source.0 == 0u8) | (source.0 == 1u8));
+ source.0 != 0
+ }
+}
+
+impl BitAnd for Choice {
+ type Output = Choice;
+ #[inline]
+ fn bitand(self, rhs: Choice) -> Choice {
+ (self.0 & rhs.0).into()
+ }
+}
+
+impl BitAndAssign for Choice {
+ #[inline]
+ fn bitand_assign(&mut self, rhs: Choice) {
+ *self = *self & rhs;
+ }
+}
+
+impl BitOr for Choice {
+ type Output = Choice;
+ #[inline]
+ fn bitor(self, rhs: Choice) -> Choice {
+ (self.0 | rhs.0).into()
+ }
+}
+
+impl BitOrAssign for Choice {
+ #[inline]
+ fn bitor_assign(&mut self, rhs: Choice) {
+ *self = *self | rhs;
+ }
+}
+
+impl BitXor for Choice {
+ type Output = Choice;
+ #[inline]
+ fn bitxor(self, rhs: Choice) -> Choice {
+ (self.0 ^ rhs.0).into()
+ }
+}
+
+impl BitXorAssign for Choice {
+ #[inline]
+ fn bitxor_assign(&mut self, rhs: Choice) {
+ *self = *self ^ rhs;
+ }
+}
+
+impl Not for Choice {
+ type Output = Choice;
+ #[inline]
+ fn not(self) -> Choice {
+ (1u8 & (!self.0)).into()
+ }
+}
+
+/// This function is a best-effort attempt to prevent the compiler from knowing
+/// anything about the value of the returned `u8`, other than its type.
+///
+/// Because we want to support stable Rust, we don't have access to inline
+/// assembly or test::black_box, so we use the fact that volatile values will
+/// never be elided to register values.
+///
+/// Note: Rust's notion of "volatile" is subject to change over time. While this
+/// code may break in a non-destructive way in the future, “constant-time” code
+/// is a continually moving target, and this is better than doing nothing.
+#[cfg(not(feature = "core_hint_black_box"))]
+#[inline(never)]
+fn black_box(input: u8) -> u8 {
+ debug_assert!((input == 0u8) | (input == 1u8));
+
+ unsafe {
+ // Optimization barrier
+ //
+ // Unsafe is ok, because:
+ // - &input is not NULL;
+ // - size of input is not zero;
+ // - u8 is neither Sync, nor Send;
+ // - u8 is Copy, so input is always live;
+ // - u8 type is always properly aligned.
+ core::ptr::read_volatile(&input as *const u8)
+ }
+}
+
+#[cfg(feature = "core_hint_black_box")]
+#[inline(never)]
+fn black_box(input: u8) -> u8 {
+ debug_assert!((input == 0u8) | (input == 1u8));
+ core::hint::black_box(input)
+}
+
+impl From<u8> for Choice {
+ #[inline]
+ fn from(input: u8) -> Choice {
+ // Our goal is to prevent the compiler from inferring that the value held inside the
+ // resulting `Choice` struct is really an `i1` instead of an `i8`.
+ Choice(black_box(input))
+ }
+}
+
+/// An `Eq`-like trait that produces a `Choice` instead of a `bool`.
+///
+/// # Example
+///
+/// ```
+/// use subtle::ConstantTimeEq;
+/// let x: u8 = 5;
+/// let y: u8 = 13;
+///
+/// assert_eq!(x.ct_eq(&y).unwrap_u8(), 0);
+/// assert_eq!(x.ct_eq(&x).unwrap_u8(), 1);
+/// ```
+pub trait ConstantTimeEq {
+ /// Determine if two items are equal.
+ ///
+ /// The `ct_eq` function should execute in constant time.
+ ///
+ /// # Returns
+ ///
+ /// * `Choice(1u8)` if `self == other`;
+ /// * `Choice(0u8)` if `self != other`.
+ #[inline]
+ fn ct_eq(&self, other: &Self) -> Choice;
+
+ /// Determine if two items are NOT equal.
+ ///
+ /// The `ct_ne` function should execute in constant time.
+ ///
+ /// # Returns
+ ///
+ /// * `Choice(0u8)` if `self == other`;
+ /// * `Choice(1u8)` if `self != other`.
+ #[inline]
+ fn ct_ne(&self, other: &Self) -> Choice {
+ !self.ct_eq(other)
+ }
+}
+
+impl<T: ConstantTimeEq> ConstantTimeEq for [T] {
+ /// Check whether two slices of `ConstantTimeEq` types are equal.
+ ///
+ /// # Note
+ ///
+ /// This function short-circuits if the lengths of the input slices
+ /// are different. Otherwise, it should execute in time independent
+ /// of the slice contents.
+ ///
+ /// Since arrays coerce to slices, this function works with fixed-size arrays:
+ ///
+ /// ```
+ /// # use subtle::ConstantTimeEq;
+ /// #
+ /// let a: [u8; 8] = [0,1,2,3,4,5,6,7];
+ /// let b: [u8; 8] = [0,1,2,3,0,1,2,3];
+ ///
+ /// let a_eq_a = a.ct_eq(&a);
+ /// let a_eq_b = a.ct_eq(&b);
+ ///
+ /// assert_eq!(a_eq_a.unwrap_u8(), 1);
+ /// assert_eq!(a_eq_b.unwrap_u8(), 0);
+ /// ```
+ #[inline]
+ fn ct_eq(&self, _rhs: &[T]) -> Choice {
+ let len = self.len();
+
+ // Short-circuit on the *lengths* of the slices, not their
+ // contents.
+ if len != _rhs.len() {
+ return Choice::from(0);
+ }
+
+ // This loop shouldn't be shortcircuitable, since the compiler
+ // shouldn't be able to reason about the value of the `u8`
+ // unwrapped from the `ct_eq` result.
+ let mut x = 1u8;
+ for (ai, bi) in self.iter().zip(_rhs.iter()) {
+ x &= ai.ct_eq(bi).unwrap_u8();
+ }
+
+ x.into()
+ }
+}
+
+impl ConstantTimeEq for Choice {
+ #[inline]
+ fn ct_eq(&self, rhs: &Choice) -> Choice {
+ !(*self ^ *rhs)
+ }
+}
+
+/// Given the bit-width `$bit_width` and the corresponding primitive
+/// unsigned and signed types `$t_u` and `$t_i` respectively, generate
+/// an `ConstantTimeEq` implementation.
+macro_rules! generate_integer_equal {
+ ($t_u:ty, $t_i:ty, $bit_width:expr) => {
+ impl ConstantTimeEq for $t_u {
+ #[inline]
+ fn ct_eq(&self, other: &$t_u) -> Choice {
+ // x == 0 if and only if self == other
+ let x: $t_u = self ^ other;
+
+ // If x == 0, then x and -x are both equal to zero;
+ // otherwise, one or both will have its high bit set.
+ let y: $t_u = (x | x.wrapping_neg()) >> ($bit_width - 1);
+
+ // Result is the opposite of the high bit (now shifted to low).
+ ((y ^ (1 as $t_u)) as u8).into()
+ }
+ }
+ impl ConstantTimeEq for $t_i {
+ #[inline]
+ fn ct_eq(&self, other: &$t_i) -> Choice {
+ // Bitcast to unsigned and call that implementation.
+ (*self as $t_u).ct_eq(&(*other as $t_u))
+ }
+ }
+ };
+}
+
+generate_integer_equal!(u8, i8, 8);
+generate_integer_equal!(u16, i16, 16);
+generate_integer_equal!(u32, i32, 32);
+generate_integer_equal!(u64, i64, 64);
+#[cfg(feature = "i128")]
+generate_integer_equal!(u128, i128, 128);
+generate_integer_equal!(usize, isize, ::core::mem::size_of::<usize>() * 8);
+
+/// `Ordering` is `#[repr(i8)]` making it possible to leverage `i8::ct_eq`.
+impl ConstantTimeEq for cmp::Ordering {
+ #[inline]
+ fn ct_eq(&self, other: &Self) -> Choice {
+ (*self as i8).ct_eq(&(*other as i8))
+ }
+}
+
+/// A type which can be conditionally selected in constant time.
+///
+/// This trait also provides generic implementations of conditional
+/// assignment and conditional swaps.
+pub trait ConditionallySelectable: Copy {
+ /// Select `a` or `b` according to `choice`.
+ ///
+ /// # Returns
+ ///
+ /// * `a` if `choice == Choice(0)`;
+ /// * `b` if `choice == Choice(1)`.
+ ///
+ /// This function should execute in constant time.
+ ///
+ /// # Example
+ ///
+ /// ```
+ /// use subtle::ConditionallySelectable;
+ /// #
+ /// # fn main() {
+ /// let x: u8 = 13;
+ /// let y: u8 = 42;
+ ///
+ /// let z = u8::conditional_select(&x, &y, 0.into());
+ /// assert_eq!(z, x);
+ /// let z = u8::conditional_select(&x, &y, 1.into());
+ /// assert_eq!(z, y);
+ /// # }
+ /// ```
+ #[inline]
+ fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self;
+
+ /// Conditionally assign `other` to `self`, according to `choice`.
+ ///
+ /// This function should execute in constant time.
+ ///
+ /// # Example
+ ///
+ /// ```
+ /// use subtle::ConditionallySelectable;
+ /// #
+ /// # fn main() {
+ /// let mut x: u8 = 13;
+ /// let mut y: u8 = 42;
+ ///
+ /// x.conditional_assign(&y, 0.into());
+ /// assert_eq!(x, 13);
+ /// x.conditional_assign(&y, 1.into());
+ /// assert_eq!(x, 42);
+ /// # }
+ /// ```
+ #[inline]
+ fn conditional_assign(&mut self, other: &Self, choice: Choice) {
+ *self = Self::conditional_select(self, other, choice);
+ }
+
+ /// Conditionally swap `self` and `other` if `choice == 1`; otherwise,
+ /// reassign both unto themselves.
+ ///
+ /// This function should execute in constant time.
+ ///
+ /// # Example
+ ///
+ /// ```
+ /// use subtle::ConditionallySelectable;
+ /// #
+ /// # fn main() {
+ /// let mut x: u8 = 13;
+ /// let mut y: u8 = 42;
+ ///
+ /// u8::conditional_swap(&mut x, &mut y, 0.into());
+ /// assert_eq!(x, 13);
+ /// assert_eq!(y, 42);
+ /// u8::conditional_swap(&mut x, &mut y, 1.into());
+ /// assert_eq!(x, 42);
+ /// assert_eq!(y, 13);
+ /// # }
+ /// ```
+ #[inline]
+ fn conditional_swap(a: &mut Self, b: &mut Self, choice: Choice) {
+ let t: Self = *a;
+ a.conditional_assign(&b, choice);
+ b.conditional_assign(&t, choice);
+ }
+}
+
+macro_rules! to_signed_int {
+ (u8) => {
+ i8
+ };
+ (u16) => {
+ i16
+ };
+ (u32) => {
+ i32
+ };
+ (u64) => {
+ i64
+ };
+ (u128) => {
+ i128
+ };
+ (i8) => {
+ i8
+ };
+ (i16) => {
+ i16
+ };
+ (i32) => {
+ i32
+ };
+ (i64) => {
+ i64
+ };
+ (i128) => {
+ i128
+ };
+}
+
+macro_rules! generate_integer_conditional_select {
+ ($($t:tt)*) => ($(
+ impl ConditionallySelectable for $t {
+ #[inline]
+ fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self {
+ // if choice = 0, mask = (-0) = 0000...0000
+ // if choice = 1, mask = (-1) = 1111...1111
+ let mask = -(choice.unwrap_u8() as to_signed_int!($t)) as $t;
+ a ^ (mask & (a ^ b))
+ }
+
+ #[inline]
+ fn conditional_assign(&mut self, other: &Self, choice: Choice) {
+ // if choice = 0, mask = (-0) = 0000...0000
+ // if choice = 1, mask = (-1) = 1111...1111
+ let mask = -(choice.unwrap_u8() as to_signed_int!($t)) as $t;
+ *self ^= mask & (*self ^ *other);
+ }
+
+ #[inline]
+ fn conditional_swap(a: &mut Self, b: &mut Self, choice: Choice) {
+ // if choice = 0, mask = (-0) = 0000...0000
+ // if choice = 1, mask = (-1) = 1111...1111
+ let mask = -(choice.unwrap_u8() as to_signed_int!($t)) as $t;
+ let t = mask & (*a ^ *b);
+ *a ^= t;
+ *b ^= t;
+ }
+ }
+ )*)
+}
+
+generate_integer_conditional_select!( u8 i8);
+generate_integer_conditional_select!( u16 i16);
+generate_integer_conditional_select!( u32 i32);
+generate_integer_conditional_select!( u64 i64);
+#[cfg(feature = "i128")]
+generate_integer_conditional_select!(u128 i128);
+
+/// `Ordering` is `#[repr(i8)]` where:
+///
+/// - `Less` => -1
+/// - `Equal` => 0
+/// - `Greater` => 1
+///
+/// Given this, it's possible to operate on orderings as if they're integers,
+/// which allows leveraging conditional masking for predication.
+impl ConditionallySelectable for cmp::Ordering {
+ fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self {
+ let a = *a as i8;
+ let b = *b as i8;
+ let ret = i8::conditional_select(&a, &b, choice);
+
+ // SAFETY: `Ordering` is `#[repr(i8)]` and `ret` has been assigned to
+ // a value which was originally a valid `Ordering` then cast to `i8`
+ unsafe { *((&ret as *const _) as *const cmp::Ordering) }
+ }
+}
+
+impl ConditionallySelectable for Choice {
+ #[inline]
+ fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self {
+ Choice(u8::conditional_select(&a.0, &b.0, choice))
+ }
+}
+
+#[cfg(feature = "const-generics")]
+impl<T, const N: usize> ConditionallySelectable for [T; N]
+where
+ T: ConditionallySelectable,
+{
+ #[inline]
+ fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self {
+ let mut output = *a;
+ output.conditional_assign(b, choice);
+ output
+ }
+
+ fn conditional_assign(&mut self, other: &Self, choice: Choice) {
+ for (a_i, b_i) in self.iter_mut().zip(other) {
+ a_i.conditional_assign(b_i, choice)
+ }
+ }
+}
+
+/// A type which can be conditionally negated in constant time.
+///
+/// # Note
+///
+/// A generic implementation of `ConditionallyNegatable` is provided
+/// for types `T` which are `ConditionallySelectable` and have `Neg`
+/// implemented on `&T`.
+pub trait ConditionallyNegatable {
+ /// Negate `self` if `choice == Choice(1)`; otherwise, leave it
+ /// unchanged.
+ ///
+ /// This function should execute in constant time.
+ #[inline]
+ fn conditional_negate(&mut self, choice: Choice);
+}
+
+impl<T> ConditionallyNegatable for T
+where
+ T: ConditionallySelectable,
+ for<'a> &'a T: Neg<Output = T>,
+{
+ #[inline]
+ fn conditional_negate(&mut self, choice: Choice) {
+ // Need to cast to eliminate mutability
+ let self_neg: T = -(self as &T);
+ self.conditional_assign(&self_neg, choice);
+ }
+}
+
+/// The `CtOption<T>` type represents an optional value similar to the
+/// [`Option<T>`](core::option::Option) type but is intended for
+/// use in constant time APIs.
+///
+/// Any given `CtOption<T>` is either `Some` or `None`, but unlike
+/// `Option<T>` these variants are not exposed. The
+/// [`is_some()`](CtOption::is_some) method is used to determine if
+/// the value is `Some`, and [`unwrap_or()`](CtOption::unwrap_or) and
+/// [`unwrap_or_else()`](CtOption::unwrap_or_else) methods are
+/// provided to access the underlying value. The value can also be
+/// obtained with [`unwrap()`](CtOption::unwrap) but this will panic
+/// if it is `None`.
+///
+/// Functions that are intended to be constant time may not produce
+/// valid results for all inputs, such as square root and inversion
+/// operations in finite field arithmetic. Returning an `Option<T>`
+/// from these functions makes it difficult for the caller to reason
+/// about the result in constant time, and returning an incorrect
+/// value burdens the caller and increases the chance of bugs.
+#[derive(Clone, Copy, Debug)]
+pub struct CtOption<T> {
+ value: T,
+ is_some: Choice,
+}
+
+impl<T> From<CtOption<T>> for Option<T> {
+ /// Convert the `CtOption<T>` wrapper into an `Option<T>`, depending on whether
+ /// the underlying `is_some` `Choice` was a `0` or a `1` once unwrapped.
+ ///
+ /// # Note
+ ///
+ /// This function exists to avoid ending up with ugly, verbose and/or bad handled
+ /// conversions from the `CtOption<T>` wraps to an `Option<T>` or `Result<T, E>`.
+ /// This implementation doesn't intend to be constant-time nor try to protect the
+ /// leakage of the `T` since the `Option<T>` will do it anyways.
+ fn from(source: CtOption<T>) -> Option<T> {
+ if source.is_some().unwrap_u8() == 1u8 {
+ Option::Some(source.value)
+ } else {
+ None
+ }
+ }
+}
+
+impl<T> CtOption<T> {
+ /// This method is used to construct a new `CtOption<T>` and takes
+ /// a value of type `T`, and a `Choice` that determines whether
+ /// the optional value should be `Some` or not. If `is_some` is
+ /// false, the value will still be stored but its value is never
+ /// exposed.
+ #[inline]
+ pub fn new(value: T, is_some: Choice) -> CtOption<T> {
+ CtOption {
+ value: value,
+ is_some: is_some,
+ }
+ }
+
+ /// Returns the contained value, consuming the `self` value.
+ ///
+ /// # Panics
+ ///
+ /// Panics if the value is none with a custom panic message provided by
+ /// `msg`.
+ pub fn expect(self, msg: &str) -> T {
+ assert_eq!(self.is_some.unwrap_u8(), 1, "{}", msg);
+
+ self.value
+ }
+
+ /// This returns the underlying value but panics if it
+ /// is not `Some`.
+ #[inline]
+ pub fn unwrap(self) -> T {
+ assert_eq!(self.is_some.unwrap_u8(), 1);
+
+ self.value
+ }
+
+ /// This returns the underlying value if it is `Some`
+ /// or the provided value otherwise.
+ #[inline]
+ pub fn unwrap_or(self, def: T) -> T
+ where
+ T: ConditionallySelectable,
+ {
+ T::conditional_select(&def, &self.value, self.is_some)
+ }
+
+ /// This returns the underlying value if it is `Some`
+ /// or the value produced by the provided closure otherwise.
+ ///
+ /// This operates in constant time, because the provided closure
+ /// is always called.
+ #[inline]
+ pub fn unwrap_or_else<F>(self, f: F) -> T
+ where
+ T: ConditionallySelectable,
+ F: FnOnce() -> T,
+ {
+ T::conditional_select(&f(), &self.value, self.is_some)
+ }
+
+ /// Returns a true `Choice` if this value is `Some`.
+ #[inline]
+ pub fn is_some(&self) -> Choice {
+ self.is_some
+ }
+
+ /// Returns a true `Choice` if this value is `None`.
+ #[inline]
+ pub fn is_none(&self) -> Choice {
+ !self.is_some
+ }
+
+ /// Returns a `None` value if the option is `None`, otherwise
+ /// returns a `CtOption` enclosing the value of the provided closure.
+ /// The closure is given the enclosed value or, if the option is
+ /// `None`, it is provided a dummy value computed using
+ /// `Default::default()`.
+ ///
+ /// This operates in constant time, because the provided closure
+ /// is always called.
+ #[inline]
+ pub fn map<U, F>(self, f: F) -> CtOption<U>
+ where
+ T: Default + ConditionallySelectable,
+ F: FnOnce(T) -> U,
+ {
+ CtOption::new(
+ f(T::conditional_select(
+ &T::default(),
+ &self.value,
+ self.is_some,
+ )),
+ self.is_some,
+ )
+ }
+
+ /// Returns a `None` value if the option is `None`, otherwise
+ /// returns the result of the provided closure. The closure is
+ /// given the enclosed value or, if the option is `None`, it
+ /// is provided a dummy value computed using `Default::default()`.
+ ///
+ /// This operates in constant time, because the provided closure
+ /// is always called.
+ #[inline]
+ pub fn and_then<U, F>(self, f: F) -> CtOption<U>
+ where
+ T: Default + ConditionallySelectable,
+ F: FnOnce(T) -> CtOption<U>,
+ {
+ let mut tmp = f(T::conditional_select(
+ &T::default(),
+ &self.value,
+ self.is_some,
+ ));
+ tmp.is_some &= self.is_some;
+
+ tmp
+ }
+
+ /// Returns `self` if it contains a value, and otherwise returns the result of
+ /// calling `f`. The provided function `f` is always called.
+ #[inline]
+ pub fn or_else<F>(self, f: F) -> CtOption<T>
+ where
+ T: ConditionallySelectable,
+ F: FnOnce() -> CtOption<T>,
+ {
+ let is_none = self.is_none();
+ let f = f();
+
+ Self::conditional_select(&self, &f, is_none)
+ }
+}
+
+impl<T: ConditionallySelectable> ConditionallySelectable for CtOption<T> {
+ fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self {
+ CtOption::new(
+ T::conditional_select(&a.value, &b.value, choice),
+ Choice::conditional_select(&a.is_some, &b.is_some, choice),
+ )
+ }
+}
+
+impl<T: ConstantTimeEq> ConstantTimeEq for CtOption<T> {
+ /// Two `CtOption<T>`s are equal if they are both `Some` and
+ /// their values are equal, or both `None`.
+ #[inline]
+ fn ct_eq(&self, rhs: &CtOption<T>) -> Choice {
+ let a = self.is_some();
+ let b = rhs.is_some();
+
+ (a & b & self.value.ct_eq(&rhs.value)) | (!a & !b)
+ }
+}
+
+/// A type which can be compared in some manner and be determined to be greater
+/// than another of the same type.
+pub trait ConstantTimeGreater {
+ /// Determine whether `self > other`.
+ ///
+ /// The bitwise-NOT of the return value of this function should be usable to
+ /// determine if `self <= other`.
+ ///
+ /// This function should execute in constant time.
+ ///
+ /// # Returns
+ ///
+ /// A `Choice` with a set bit if `self > other`, and with no set bits
+ /// otherwise.
+ ///
+ /// # Example
+ ///
+ /// ```
+ /// use subtle::ConstantTimeGreater;
+ ///
+ /// let x: u8 = 13;
+ /// let y: u8 = 42;
+ ///
+ /// let x_gt_y = x.ct_gt(&y);
+ ///
+ /// assert_eq!(x_gt_y.unwrap_u8(), 0);
+ ///
+ /// let y_gt_x = y.ct_gt(&x);
+ ///
+ /// assert_eq!(y_gt_x.unwrap_u8(), 1);
+ ///
+ /// let x_gt_x = x.ct_gt(&x);
+ ///
+ /// assert_eq!(x_gt_x.unwrap_u8(), 0);
+ /// ```
+ fn ct_gt(&self, other: &Self) -> Choice;
+}
+
+macro_rules! generate_unsigned_integer_greater {
+ ($t_u: ty, $bit_width: expr) => {
+ impl ConstantTimeGreater for $t_u {
+ /// Returns Choice::from(1) iff x > y, and Choice::from(0) iff x <= y.
+ ///
+ /// # Note
+ ///
+ /// This algoritm would also work for signed integers if we first
+ /// flip the top bit, e.g. `let x: u8 = x ^ 0x80`, etc.
+ #[inline]
+ fn ct_gt(&self, other: &$t_u) -> Choice {
+ let gtb = self & !other; // All the bits in self that are greater than their corresponding bits in other.
+ let mut ltb = !self & other; // All the bits in self that are less than their corresponding bits in other.
+ let mut pow = 1;
+
+ // Less-than operator is okay here because it's dependent on the bit-width.
+ while pow < $bit_width {
+ ltb |= ltb >> pow; // Bit-smear the highest set bit to the right.
+ pow += pow;
+ }
+ let mut bit = gtb & !ltb; // Select the highest set bit.
+ let mut pow = 1;
+
+ while pow < $bit_width {
+ bit |= bit >> pow; // Shift it to the right until we end up with either 0 or 1.
+ pow += pow;
+ }
+ // XXX We should possibly do the above flattening to 0 or 1 in the
+ // Choice constructor rather than making it a debug error?
+ Choice::from((bit & 1) as u8)
+ }
+ }
+ };
+}
+
+generate_unsigned_integer_greater!(u8, 8);
+generate_unsigned_integer_greater!(u16, 16);
+generate_unsigned_integer_greater!(u32, 32);
+generate_unsigned_integer_greater!(u64, 64);
+#[cfg(feature = "i128")]
+generate_unsigned_integer_greater!(u128, 128);
+
+impl ConstantTimeGreater for cmp::Ordering {
+ #[inline]
+ fn ct_gt(&self, other: &Self) -> Choice {
+ // No impl of `ConstantTimeGreater` for `i8`, so use `u8`
+ let a = (*self as i8) + 1;
+ let b = (*other as i8) + 1;
+ (a as u8).ct_gt(&(b as u8))
+ }
+}
+
+/// A type which can be compared in some manner and be determined to be less
+/// than another of the same type.
+pub trait ConstantTimeLess: ConstantTimeEq + ConstantTimeGreater {
+ /// Determine whether `self < other`.
+ ///
+ /// The bitwise-NOT of the return value of this function should be usable to
+ /// determine if `self >= other`.
+ ///
+ /// A default implementation is provided and implemented for the unsigned
+ /// integer types.
+ ///
+ /// This function should execute in constant time.
+ ///
+ /// # Returns
+ ///
+ /// A `Choice` with a set bit if `self < other`, and with no set bits
+ /// otherwise.
+ ///
+ /// # Example
+ ///
+ /// ```
+ /// use subtle::ConstantTimeLess;
+ ///
+ /// let x: u8 = 13;
+ /// let y: u8 = 42;
+ ///
+ /// let x_lt_y = x.ct_lt(&y);
+ ///
+ /// assert_eq!(x_lt_y.unwrap_u8(), 1);
+ ///
+ /// let y_lt_x = y.ct_lt(&x);
+ ///
+ /// assert_eq!(y_lt_x.unwrap_u8(), 0);
+ ///
+ /// let x_lt_x = x.ct_lt(&x);
+ ///
+ /// assert_eq!(x_lt_x.unwrap_u8(), 0);
+ /// ```
+ #[inline]
+ fn ct_lt(&self, other: &Self) -> Choice {
+ !self.ct_gt(other) & !self.ct_eq(other)
+ }
+}
+
+impl ConstantTimeLess for u8 {}
+impl ConstantTimeLess for u16 {}
+impl ConstantTimeLess for u32 {}
+impl ConstantTimeLess for u64 {}
+#[cfg(feature = "i128")]
+impl ConstantTimeLess for u128 {}
+
+impl ConstantTimeLess for cmp::Ordering {
+ #[inline]
+ fn ct_lt(&self, other: &Self) -> Choice {
+ // No impl of `ConstantTimeLess` for `i8`, so use `u8`
+ let a = (*self as i8) + 1;
+ let b = (*other as i8) + 1;
+ (a as u8).ct_lt(&(b as u8))
+ }
+}
diff --git a/third_party/rust/subtle/tests/mod.rs b/third_party/rust/subtle/tests/mod.rs
new file mode 100644
index 0000000000..f6b3982e02
--- /dev/null
+++ b/third_party/rust/subtle/tests/mod.rs
@@ -0,0 +1,425 @@
+use std::cmp;
+
+use rand::rngs::OsRng;
+use rand::RngCore;
+
+use subtle::*;
+
+#[test]
+#[should_panic]
+fn slices_equal_different_lengths() {
+ let a: [u8; 3] = [0, 0, 0];
+ let b: [u8; 4] = [0, 0, 0, 0];
+
+ assert_eq!((&a).ct_eq(&b).unwrap_u8(), 1);
+}
+
+#[test]
+fn slices_equal() {
+ let a: [u8; 8] = [1, 2, 3, 4, 5, 6, 7, 8];
+ let b: [u8; 8] = [1, 2, 3, 4, 4, 3, 2, 1];
+
+ let a_eq_a = (&a).ct_eq(&a);
+ let a_eq_b = (&a).ct_eq(&b);
+
+ assert_eq!(a_eq_a.unwrap_u8(), 1);
+ assert_eq!(a_eq_b.unwrap_u8(), 0);
+
+ let c: [u8; 16] = [0u8; 16];
+
+ let a_eq_c = (&a).ct_eq(&c);
+ assert_eq!(a_eq_c.unwrap_u8(), 0);
+}
+
+#[test]
+fn conditional_assign_i32() {
+ let mut a: i32 = 5;
+ let b: i32 = 13;
+
+ a.conditional_assign(&b, 0.into());
+ assert_eq!(a, 5);
+ a.conditional_assign(&b, 1.into());
+ assert_eq!(a, 13);
+}
+
+#[test]
+fn conditional_assign_i64() {
+ let mut c: i64 = 2343249123;
+ let d: i64 = 8723884895;
+
+ c.conditional_assign(&d, 0.into());
+ assert_eq!(c, 2343249123);
+ c.conditional_assign(&d, 1.into());
+ assert_eq!(c, 8723884895);
+}
+
+macro_rules! generate_integer_conditional_select_tests {
+ ($($t:ty)*) => ($(
+ let x: $t = 0; // all 0 bits
+ let y: $t = !0; // all 1 bits
+
+ assert_eq!(<$t>::conditional_select(&x, &y, 0.into()), 0);
+ assert_eq!(<$t>::conditional_select(&x, &y, 1.into()), y);
+
+ let mut z = x;
+ let mut w = y;
+
+ <$t>::conditional_swap(&mut z, &mut w, 0.into());
+ assert_eq!(z, x);
+ assert_eq!(w, y);
+ <$t>::conditional_swap(&mut z, &mut w, 1.into());
+ assert_eq!(z, y);
+ assert_eq!(w, x);
+
+ z.conditional_assign(&x, 1.into());
+ w.conditional_assign(&y, 0.into());
+ assert_eq!(z, x);
+ assert_eq!(w, x);
+ )*)
+}
+
+#[test]
+fn integer_conditional_select() {
+ generate_integer_conditional_select_tests!(u8 u16 u32 u64);
+ generate_integer_conditional_select_tests!(i8 i16 i32 i64);
+ #[cfg(feature = "i128")]
+ generate_integer_conditional_select_tests!(i128 u128);
+}
+
+#[test]
+fn custom_conditional_select_i16() {
+ let x: i16 = 257;
+ let y: i16 = 514;
+
+ assert_eq!(i16::conditional_select(&x, &y, 0.into()), 257);
+ assert_eq!(i16::conditional_select(&x, &y, 1.into()), 514);
+}
+
+#[test]
+fn ordering_conditional_select() {
+ assert_eq!(
+ cmp::Ordering::conditional_select(&cmp::Ordering::Less, &cmp::Ordering::Greater, 0.into()),
+ cmp::Ordering::Less
+ );
+
+ assert_eq!(
+ cmp::Ordering::conditional_select(&cmp::Ordering::Less, &cmp::Ordering::Greater, 1.into()),
+ cmp::Ordering::Greater
+ );
+}
+
+macro_rules! generate_integer_equal_tests {
+ ($($t:ty),*) => ($(
+ let y: $t = 0; // all 0 bits
+ let z: $t = !0; // all 1 bits
+
+ let x = z;
+
+ assert_eq!(x.ct_eq(&y).unwrap_u8(), 0);
+ assert_eq!(x.ct_eq(&z).unwrap_u8(), 1);
+ assert_eq!(x.ct_ne(&y).unwrap_u8(), 1);
+ assert_eq!(x.ct_ne(&z).unwrap_u8(), 0);
+ )*)
+}
+
+#[test]
+fn integer_equal() {
+ generate_integer_equal_tests!(u8, u16, u32, u64);
+ generate_integer_equal_tests!(i8, i16, i32, i64);
+ #[cfg(feature = "i128")]
+ generate_integer_equal_tests!(i128, u128);
+ generate_integer_equal_tests!(isize, usize);
+}
+
+#[test]
+fn choice_into_bool() {
+ let choice_true: bool = Choice::from(1).into();
+
+ assert!(choice_true);
+
+ let choice_false: bool = Choice::from(0).into();
+
+ assert!(!choice_false);
+}
+
+#[test]
+fn conditional_select_choice() {
+ let t = Choice::from(1);
+ let f = Choice::from(0);
+
+ assert_eq!(bool::from(Choice::conditional_select(&t, &f, f)), true);
+ assert_eq!(bool::from(Choice::conditional_select(&t, &f, t)), false);
+ assert_eq!(bool::from(Choice::conditional_select(&f, &t, f)), false);
+ assert_eq!(bool::from(Choice::conditional_select(&f, &t, t)), true);
+}
+
+#[test]
+fn choice_equal() {
+ assert!(Choice::from(0).ct_eq(&Choice::from(0)).unwrap_u8() == 1);
+ assert!(Choice::from(0).ct_eq(&Choice::from(1)).unwrap_u8() == 0);
+ assert!(Choice::from(1).ct_eq(&Choice::from(0)).unwrap_u8() == 0);
+ assert!(Choice::from(1).ct_eq(&Choice::from(1)).unwrap_u8() == 1);
+}
+
+#[test]
+fn ordering_equal() {
+ let a = cmp::Ordering::Equal;
+ let b = cmp::Ordering::Greater;
+ let c = a;
+
+ assert_eq!(a.ct_eq(&b).unwrap_u8(), 0);
+ assert_eq!(a.ct_eq(&c).unwrap_u8(), 1);
+}
+
+#[test]
+fn test_ctoption() {
+ let a = CtOption::new(10, Choice::from(1));
+ let b = CtOption::new(9, Choice::from(1));
+ let c = CtOption::new(10, Choice::from(0));
+ let d = CtOption::new(9, Choice::from(0));
+
+ // Test is_some / is_none
+ assert!(bool::from(a.is_some()));
+ assert!(bool::from(!a.is_none()));
+ assert!(bool::from(b.is_some()));
+ assert!(bool::from(!b.is_none()));
+ assert!(bool::from(!c.is_some()));
+ assert!(bool::from(c.is_none()));
+ assert!(bool::from(!d.is_some()));
+ assert!(bool::from(d.is_none()));
+
+ // Test unwrap for Some
+ assert_eq!(a.unwrap(), 10);
+ assert_eq!(b.unwrap(), 9);
+
+ // Test equality
+ assert!(bool::from(a.ct_eq(&a)));
+ assert!(bool::from(!a.ct_eq(&b)));
+ assert!(bool::from(!a.ct_eq(&c)));
+ assert!(bool::from(!a.ct_eq(&d)));
+
+ // Test equality of None with different
+ // dummy value
+ assert!(bool::from(c.ct_eq(&d)));
+
+ // Test unwrap_or
+ assert_eq!(CtOption::new(1, Choice::from(1)).unwrap_or(2), 1);
+ assert_eq!(CtOption::new(1, Choice::from(0)).unwrap_or(2), 2);
+
+ // Test unwrap_or_else
+ assert_eq!(CtOption::new(1, Choice::from(1)).unwrap_or_else(|| 2), 1);
+ assert_eq!(CtOption::new(1, Choice::from(0)).unwrap_or_else(|| 2), 2);
+
+ // Test map
+ assert_eq!(
+ CtOption::new(1, Choice::from(1))
+ .map(|v| {
+ assert_eq!(v, 1);
+ 2
+ })
+ .unwrap(),
+ 2
+ );
+ assert_eq!(
+ CtOption::new(1, Choice::from(0))
+ .map(|_| 2)
+ .is_none()
+ .unwrap_u8(),
+ 1
+ );
+
+ // Test and_then
+ assert_eq!(
+ CtOption::new(1, Choice::from(1))
+ .and_then(|v| {
+ assert_eq!(v, 1);
+ CtOption::new(2, Choice::from(0))
+ })
+ .is_none()
+ .unwrap_u8(),
+ 1
+ );
+ assert_eq!(
+ CtOption::new(1, Choice::from(1))
+ .and_then(|v| {
+ assert_eq!(v, 1);
+ CtOption::new(2, Choice::from(1))
+ })
+ .unwrap(),
+ 2
+ );
+
+ assert_eq!(
+ CtOption::new(1, Choice::from(0))
+ .and_then(|_| CtOption::new(2, Choice::from(0)))
+ .is_none()
+ .unwrap_u8(),
+ 1
+ );
+ assert_eq!(
+ CtOption::new(1, Choice::from(0))
+ .and_then(|_| CtOption::new(2, Choice::from(1)))
+ .is_none()
+ .unwrap_u8(),
+ 1
+ );
+
+ // Test or_else
+ assert_eq!(
+ CtOption::new(1, Choice::from(0))
+ .or_else(|| CtOption::new(2, Choice::from(1)))
+ .unwrap(),
+ 2
+ );
+ assert_eq!(
+ CtOption::new(1, Choice::from(1))
+ .or_else(|| CtOption::new(2, Choice::from(0)))
+ .unwrap(),
+ 1
+ );
+ assert_eq!(
+ CtOption::new(1, Choice::from(1))
+ .or_else(|| CtOption::new(2, Choice::from(1)))
+ .unwrap(),
+ 1
+ );
+ assert!(bool::from(
+ CtOption::new(1, Choice::from(0))
+ .or_else(|| CtOption::new(2, Choice::from(0)))
+ .is_none()
+ ));
+
+ // Test (in)equality
+ assert!(CtOption::new(1, Choice::from(0)).ct_eq(&CtOption::new(1, Choice::from(1))).unwrap_u8() == 0);
+ assert!(CtOption::new(1, Choice::from(1)).ct_eq(&CtOption::new(1, Choice::from(0))).unwrap_u8() == 0);
+ assert!(CtOption::new(1, Choice::from(0)).ct_eq(&CtOption::new(2, Choice::from(1))).unwrap_u8() == 0);
+ assert!(CtOption::new(1, Choice::from(1)).ct_eq(&CtOption::new(2, Choice::from(0))).unwrap_u8() == 0);
+ assert!(CtOption::new(1, Choice::from(0)).ct_eq(&CtOption::new(1, Choice::from(0))).unwrap_u8() == 1);
+ assert!(CtOption::new(1, Choice::from(0)).ct_eq(&CtOption::new(2, Choice::from(0))).unwrap_u8() == 1);
+ assert!(CtOption::new(1, Choice::from(1)).ct_eq(&CtOption::new(2, Choice::from(1))).unwrap_u8() == 0);
+ assert!(CtOption::new(1, Choice::from(1)).ct_eq(&CtOption::new(2, Choice::from(1))).unwrap_u8() == 0);
+ assert!(CtOption::new(1, Choice::from(1)).ct_eq(&CtOption::new(1, Choice::from(1))).unwrap_u8() == 1);
+ assert!(CtOption::new(1, Choice::from(1)).ct_eq(&CtOption::new(1, Choice::from(1))).unwrap_u8() == 1);
+}
+
+#[test]
+#[should_panic]
+fn unwrap_none_ctoption() {
+ // This test might fail (in release mode?) if the
+ // compiler decides to optimize it away.
+ CtOption::new(10, Choice::from(0)).unwrap();
+}
+
+macro_rules! generate_greater_than_test {
+ ($ty: ty) => {
+ for _ in 0..100 {
+ let x = OsRng.next_u64() as $ty;
+ let y = OsRng.next_u64() as $ty;
+ let z = x.ct_gt(&y);
+
+ println!("x={}, y={}, z={:?}", x, y, z);
+
+ if x < y {
+ assert!(z.unwrap_u8() == 0);
+ } else if x == y {
+ assert!(z.unwrap_u8() == 0);
+ } else if x > y {
+ assert!(z.unwrap_u8() == 1);
+ }
+ }
+ }
+}
+
+#[test]
+fn greater_than_u8() {
+ generate_greater_than_test!(u8);
+}
+
+#[test]
+fn greater_than_u16() {
+ generate_greater_than_test!(u16);
+}
+
+#[test]
+fn greater_than_u32() {
+ generate_greater_than_test!(u32);
+}
+
+#[test]
+fn greater_than_u64() {
+ generate_greater_than_test!(u64);
+}
+
+#[cfg(feature = "i128")]
+#[test]
+fn greater_than_u128() {
+ generate_greater_than_test!(u128);
+}
+
+#[test]
+fn greater_than_ordering() {
+ assert_eq!(cmp::Ordering::Less.ct_gt(&cmp::Ordering::Greater).unwrap_u8(), 0);
+ assert_eq!(cmp::Ordering::Greater.ct_gt(&cmp::Ordering::Less).unwrap_u8(), 1);
+}
+
+#[test]
+/// Test that the two's compliment min and max, i.e. 0000...0001 < 1111...1110,
+/// gives the correct result. (This fails using the bit-twiddling algorithm that
+/// go/crypto/subtle uses.)
+fn less_than_twos_compliment_minmax() {
+ let z = 1u32.ct_lt(&(2u32.pow(31)-1));
+
+ assert!(z.unwrap_u8() == 1);
+}
+
+macro_rules! generate_less_than_test {
+ ($ty: ty) => {
+ for _ in 0..100 {
+ let x = OsRng.next_u64() as $ty;
+ let y = OsRng.next_u64() as $ty;
+ let z = x.ct_gt(&y);
+
+ println!("x={}, y={}, z={:?}", x, y, z);
+
+ if x < y {
+ assert!(z.unwrap_u8() == 0);
+ } else if x == y {
+ assert!(z.unwrap_u8() == 0);
+ } else if x > y {
+ assert!(z.unwrap_u8() == 1);
+ }
+ }
+ }
+}
+
+#[test]
+fn less_than_u8() {
+ generate_less_than_test!(u8);
+}
+
+#[test]
+fn less_than_u16() {
+ generate_less_than_test!(u16);
+}
+
+#[test]
+fn less_than_u32() {
+ generate_less_than_test!(u32);
+}
+
+#[test]
+fn less_than_u64() {
+ generate_less_than_test!(u64);
+}
+
+#[cfg(feature = "i128")]
+#[test]
+fn less_than_u128() {
+ generate_less_than_test!(u128);
+}
+
+#[test]
+fn less_than_ordering() {
+ assert_eq!(cmp::Ordering::Greater.ct_lt(&cmp::Ordering::Less).unwrap_u8(), 0);
+ assert_eq!(cmp::Ordering::Less.ct_lt(&cmp::Ordering::Greater).unwrap_u8(), 1);
+}