RPM build fix (reverted CI changes which will need to be un-reverted or made conditional) and vendor Rust dependencies to make builds much faster in any CI system.
This commit is contained in:
1
zeroidc/vendor/subtle/.cargo-checksum.json
vendored
Normal file
1
zeroidc/vendor/subtle/.cargo-checksum.json
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"files":{"CHANGELOG.md":"1d604ca36159c79a4341f0c15fc249da7bf2912cd5b1bbf4964ce03dd887fc02","CONTRIBUTING.md":"2fbb44138ececdef7c0950fae6ed1dcad481fb2f368df0e3734c9902be791f3e","Cargo.toml":"2206ebe5be7cca3ad0a5dcbb0b12f85ac091b4b6a58861cddc8ecd5d137d4c7c","LICENSE":"36c48715a280d334a995f26fc38103f21cb92425a20c8eeaa368b229b49b6d4d","README.md":"ee1a1768f9b119a36db27a170f7f6bb8bdb79f868db28b37a11d1a57a208e9f5","src/lib.rs":"d873dd52215caf21a385391ed88f75e09f8f32203e93e3530c2a22d19e5a6452","tests/mod.rs":"127c8ab8ddbfa554f11876d76926f710382e293629875673e3bc99d738a13733"},"package":"6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601"}
|
||||
59
zeroidc/vendor/subtle/CHANGELOG.md
vendored
Normal file
59
zeroidc/vendor/subtle/CHANGELOG.md
vendored
Normal file
@@ -0,0 +1,59 @@
|
||||
# Changelog
|
||||
|
||||
Entries are listed in reverse chronological order.
|
||||
|
||||
## 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.
|
||||
33
zeroidc/vendor/subtle/CONTRIBUTING.md
vendored
Normal file
33
zeroidc/vendor/subtle/CONTRIBUTING.md
vendored
Normal file
@@ -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.
|
||||
36
zeroidc/vendor/subtle/Cargo.toml
vendored
Normal file
36
zeroidc/vendor/subtle/Cargo.toml
vendored
Normal file
@@ -0,0 +1,36 @@
|
||||
# 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 believe there's an error in this file please file an
|
||||
# issue against the rust-lang/cargo repository. If you're
|
||||
# editing this file be aware that the upstream Cargo.toml
|
||||
# will likely look very different (and much more reasonable)
|
||||
|
||||
[package]
|
||||
name = "subtle"
|
||||
version = "2.4.1"
|
||||
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.7"
|
||||
|
||||
[features]
|
||||
default = ["std", "i128"]
|
||||
i128 = []
|
||||
nightly = []
|
||||
std = []
|
||||
[badges.travis-ci]
|
||||
branch = "master"
|
||||
repository = "dalek-cryptography/subtle"
|
||||
28
zeroidc/vendor/subtle/LICENSE
vendored
Normal file
28
zeroidc/vendor/subtle/LICENSE
vendored
Normal file
@@ -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.
|
||||
69
zeroidc/vendor/subtle/README.md
vendored
Normal file
69
zeroidc/vendor/subtle/README.md
vendored
Normal file
@@ -0,0 +1,69 @@
|
||||
# subtle [](https://crates.io/crates/subtle) [](https://doc.dalek.rs/subtle) [](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.4"
|
||||
```
|
||||
|
||||
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.
|
||||
|
||||
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.
|
||||
|
||||
The optimization barrier in `impl From<u8> for Choice` was 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.
|
||||
|
||||
`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
|
||||
[rust-timing-shield]: https://www.chosenplaintext.ca/open-source/rust-timing-shield/security
|
||||
864
zeroidc/vendor/subtle/src/lib.rs
vendored
Normal file
864
zeroidc/vendor/subtle/src/lib.rs
vendored
Normal file
@@ -0,0 +1,864 @@
|
||||
// -*- 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.4.1")]
|
||||
|
||||
//! # subtle [](https://crates.io/crates/subtle) [](https://doc.dalek.rs/subtle) [](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.4"
|
||||
//! ```
|
||||
//!
|
||||
//! 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.
|
||||
//!
|
||||
//! 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.
|
||||
//!
|
||||
//! The optimization barrier in `impl From<u8> for Choice` was 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.
|
||||
//!
|
||||
//! `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
|
||||
//! [rust-timing-shield]: https://www.chosenplaintext.ca/open-source/rust-timing-shield/security
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
#[macro_use]
|
||||
extern crate std;
|
||||
|
||||
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.
|
||||
#[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)
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
/// 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
|
||||
///
|
||||
/// ```
|
||||
/// # extern crate subtle;
|
||||
/// 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
|
||||
///
|
||||
/// ```
|
||||
/// # extern crate subtle;
|
||||
/// 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
|
||||
///
|
||||
/// ```
|
||||
/// # extern crate subtle;
|
||||
/// 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);
|
||||
|
||||
impl ConditionallySelectable for Choice {
|
||||
#[inline]
|
||||
fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self {
|
||||
Choice(u8::conditional_select(&a.0, &b.0, 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,
|
||||
}
|
||||
}
|
||||
|
||||
/// 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.
|
||||
#[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
|
||||
///
|
||||
/// ```
|
||||
/// # extern crate subtle;
|
||||
/// 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);
|
||||
|
||||
/// 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
|
||||
///
|
||||
/// ```
|
||||
/// # extern crate subtle;
|
||||
/// 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 {}
|
||||
389
zeroidc/vendor/subtle/tests/mod.rs
vendored
Normal file
389
zeroidc/vendor/subtle/tests/mod.rs
vendored
Normal file
@@ -0,0 +1,389 @@
|
||||
extern crate rand;
|
||||
extern crate subtle;
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
)*)
|
||||
}
|
||||
|
||||
#[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 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]
|
||||
/// 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);
|
||||
}
|
||||
Reference in New Issue
Block a user