Rename Maybe to CtOption, and do not expose submodule.

This commit is contained in:
Sean Bowe 2019-03-26 21:04:51 -06:00
parent 26de2362db
commit 390aa23db2
No known key found for this signature in database
GPG Key ID: 95684257D8F8B031
4 changed files with 57 additions and 57 deletions

View File

@ -1,13 +1,13 @@
//! This module provides a "Maybe" abstraction as a constant-time
//! This module provides a "CtOption" abstraction as a constant-time
//! alternative for APIs that want to return optional values.
//! Ideally, this would be merged into upstream `subtle` at some
//! point.
use subtle::{Choice, ConditionallySelectable, ConstantTimeEq};
/// The `Maybe<T>` type represents an optional value similar to the
/// 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 `Maybe<T>` is either
/// 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()` method is used to determine if the
/// value is `Some`, and `unwrap_or`/`unwrap_or_else` methods are
@ -21,20 +21,20 @@ use subtle::{Choice, ConditionallySelectable, ConstantTimeEq};
/// 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 Maybe<T> {
pub struct CtOption<T> {
value: T,
is_some: Choice,
}
impl<T> Maybe<T> {
/// This method is used to construct a new `Maybe<T>` and takes
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) -> Maybe<T> {
Maybe { value, is_some }
pub fn new(value: T, is_some: Choice) -> CtOption<T> {
CtOption { value, is_some }
}
/// This returns the underlying value but panics if it
@ -80,7 +80,7 @@ impl<T> Maybe<T> {
}
/// Returns a `None` value if the option is `None`, otherwise
/// returns a `Maybe` enclosing the value of the provided closure.
/// 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()`.
@ -88,12 +88,12 @@ impl<T> Maybe<T> {
/// This operates in constant time, because the provided closure
/// is always called.
#[inline]
pub fn map<U, F>(self, f: F) -> Maybe<U>
pub fn map<U, F>(self, f: F) -> CtOption<U>
where
T: Default + ConditionallySelectable,
F: FnOnce(T) -> U,
{
Maybe::new(
CtOption::new(
f(T::conditional_select(
&T::default(),
&self.value,
@ -111,10 +111,10 @@ impl<T> Maybe<T> {
/// This operates in constant time, because the provided closure
/// is always called.
#[inline]
pub fn and_then<U, F>(self, f: F) -> Maybe<U>
pub fn and_then<U, F>(self, f: F) -> CtOption<U>
where
T: Default + ConditionallySelectable,
F: FnOnce(T) -> Maybe<U>,
F: FnOnce(T) -> CtOption<U>,
{
let mut tmp = f(T::conditional_select(
&T::default(),
@ -127,9 +127,9 @@ impl<T> Maybe<T> {
}
}
impl<T: ConditionallySelectable> ConditionallySelectable for Maybe<T> {
impl<T: ConditionallySelectable> ConditionallySelectable for CtOption<T> {
fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self {
Maybe::new(
CtOption::new(
T::conditional_select(&a.value, &b.value, choice),
// TODO: subtle crate currently doesn't implement ConditionallySelectable
// for Choice so we must unwrap these manually.
@ -142,11 +142,11 @@ impl<T: ConditionallySelectable> ConditionallySelectable for Maybe<T> {
}
}
impl<T: ConstantTimeEq> ConstantTimeEq for Maybe<T> {
/// Two `Maybe<T>`s are equal if they are both `Some` and
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: &Maybe<T>) -> Choice {
fn ct_eq(&self, rhs: &CtOption<T>) -> Choice {
let a = self.is_some();
let b = rhs.is_some();
@ -155,11 +155,11 @@ impl<T: ConstantTimeEq> ConstantTimeEq for Maybe<T> {
}
#[test]
fn test_maybe() {
let a = Maybe::new(10, Choice::from(1));
let b = Maybe::new(9, Choice::from(1));
let c = Maybe::new(10, Choice::from(0));
let d = Maybe::new(9, Choice::from(0));
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()));
@ -186,16 +186,16 @@ fn test_maybe() {
assert!(bool::from(c.ct_eq(&d)));
// Test unwrap_or
assert_eq!(Maybe::new(1, Choice::from(1)).unwrap_or(2), 1);
assert_eq!(Maybe::new(1, Choice::from(0)).unwrap_or(2), 2);
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!(Maybe::new(1, Choice::from(1)).unwrap_or_else(|| 2), 1);
assert_eq!(Maybe::new(1, Choice::from(0)).unwrap_or_else(|| 2), 2);
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!(
Maybe::new(1, Choice::from(1))
CtOption::new(1, Choice::from(1))
.map(|v| {
assert_eq!(v, 1);
2
@ -204,7 +204,7 @@ fn test_maybe() {
2
);
assert_eq!(
Maybe::new(1, Choice::from(0))
CtOption::new(1, Choice::from(0))
.map(|_| 2)
.is_none()
.unwrap_u8(),
@ -213,35 +213,35 @@ fn test_maybe() {
// Test and_then
assert_eq!(
Maybe::new(1, Choice::from(1))
CtOption::new(1, Choice::from(1))
.and_then(|v| {
assert_eq!(v, 1);
Maybe::new(2, Choice::from(0))
CtOption::new(2, Choice::from(0))
})
.is_none()
.unwrap_u8(),
1
);
assert_eq!(
Maybe::new(1, Choice::from(1))
CtOption::new(1, Choice::from(1))
.and_then(|v| {
assert_eq!(v, 1);
Maybe::new(2, Choice::from(1))
CtOption::new(2, Choice::from(1))
})
.unwrap(),
2
);
assert_eq!(
Maybe::new(1, Choice::from(0))
.and_then(|_| Maybe::new(2, Choice::from(0)))
CtOption::new(1, Choice::from(0))
.and_then(|_| CtOption::new(2, Choice::from(0)))
.is_none()
.unwrap_u8(),
1
);
assert_eq!(
Maybe::new(1, Choice::from(0))
.and_then(|_| Maybe::new(2, Choice::from(1)))
CtOption::new(1, Choice::from(0))
.and_then(|_| CtOption::new(2, Choice::from(1)))
.is_none()
.unwrap_u8(),
1
@ -250,8 +250,8 @@ fn test_maybe() {
#[test]
#[should_panic]
fn unwrap_none_maybe() {
fn unwrap_none_ctoption() {
// This test might fail (in release mode?) if the
// compiler decides to optimize it away.
Maybe::new(10, Choice::from(0)).unwrap();
CtOption::new(10, Choice::from(0)).unwrap();
}

View File

@ -4,8 +4,8 @@ use core::ops::{Add, AddAssign, Mul, MulAssign, Neg, Sub, SubAssign};
use byteorder::{ByteOrder, LittleEndian};
use subtle::{Choice, ConditionallySelectable, ConstantTimeEq};
use crate::maybe::Maybe;
use crate::util::{adc, mac, sbb};
use crate::CtOption;
/// Represents an element of `GF(q)`.
// The internal representation of this type is four 64-bit unsigned
@ -208,7 +208,7 @@ impl Fq {
/// Attempts to convert a little-endian byte representation of
/// a field element into an element of `Fq`, failing if the input
/// is not canonical (is not smaller than q).
pub fn from_bytes(bytes: [u8; 32]) -> Maybe<Fq> {
pub fn from_bytes(bytes: [u8; 32]) -> CtOption<Fq> {
let mut tmp = Fq([0, 0, 0, 0]);
tmp.0[0] = LittleEndian::read_u64(&bytes[0..8]);
@ -231,7 +231,7 @@ impl Fq {
// (a.R^{-1} * R^2) / R = a.R
tmp *= &R2;
Maybe::new(tmp, Choice::from(is_some))
CtOption::new(tmp, Choice::from(is_some))
}
/// Converts an element of `Fq` into a byte representation in
@ -324,7 +324,7 @@ impl Fq {
}
/// Computes the square root of this element, if it exists.
pub fn sqrt(&self) -> Maybe<Self> {
pub fn sqrt(&self) -> CtOption<Self> {
// Tonelli-Shank's algorithm for q mod 16 = 1
// https://eprint.iacr.org/2012/685.pdf (page 12, algorithm 5)
@ -366,7 +366,7 @@ impl Fq {
v = k;
}
Maybe::new(
CtOption::new(
x,
(&x * &x).ct_eq(self), // Only return Some if it's the square root.
)
@ -409,7 +409,7 @@ impl Fq {
/// Computes the multiplicative inverse of this element,
/// failing if the element is zero.
pub fn invert(&self) -> Maybe<Self> {
pub fn invert(&self) -> CtOption<Self> {
#[inline(always)]
fn square_assign_multi(n: &mut Fq, num_times: usize) {
for _ in 0..num_times {
@ -504,7 +504,7 @@ impl Fq {
square_assign_multi(&mut t0, 5);
t0.mul_assign(&t1);
Maybe::new(t0, !self.ct_eq(&Self::zero()))
CtOption::new(t0, !self.ct_eq(&Self::zero()))
}
#[inline]

View File

@ -4,8 +4,8 @@ use core::ops::{Add, AddAssign, Mul, MulAssign, Neg, Sub, SubAssign};
use byteorder::{ByteOrder, LittleEndian};
use subtle::{Choice, ConditionallySelectable, ConstantTimeEq};
use crate::maybe::Maybe;
use crate::util::{adc, mac, sbb};
use crate::CtOption;
/// Represents an element of `GF(r)`.
// The internal representation of this type is four 64-bit unsigned
@ -190,7 +190,7 @@ impl Fr {
/// Attempts to convert a little-endian byte representation of
/// a field element into an element of `Fr`, failing if the input
/// is not canonical (is not smaller than r).
pub fn from_bytes(bytes: [u8; 32]) -> Maybe<Fr> {
pub fn from_bytes(bytes: [u8; 32]) -> CtOption<Fr> {
let mut tmp = Fr([0, 0, 0, 0]);
tmp.0[0] = LittleEndian::read_u64(&bytes[0..8]);
@ -213,7 +213,7 @@ impl Fr {
// (a.R^{-1} * R^2) / R = a.R
tmp *= &R2;
Maybe::new(tmp, Choice::from(is_some))
CtOption::new(tmp, Choice::from(is_some))
}
/// Converts an element of `Fr` into a byte representation in
@ -306,7 +306,7 @@ impl Fr {
}
/// Computes the square root of this element, if it exists.
pub fn sqrt(&self) -> Maybe<Self> {
pub fn sqrt(&self) -> CtOption<Self> {
// Because r = 3 (mod 4)
// sqrt can be done with only one exponentiation,
// via the computation of self^((r + 1) // 4) (mod r)
@ -317,7 +317,7 @@ impl Fr {
0x039f6d3a994cebea,
]);
Maybe::new(
CtOption::new(
sqrt,
(&sqrt * &sqrt).ct_eq(self), // Only return Some if it's the square root.
)
@ -360,7 +360,7 @@ impl Fr {
/// Computes the multiplicative inverse of this element,
/// failing if the element is zero.
pub fn invert(&self) -> Maybe<Self> {
pub fn invert(&self) -> CtOption<Self> {
#[inline(always)]
fn square_assign_multi(n: &mut Fr, num_times: usize) {
for _ in 0..num_times {
@ -462,7 +462,7 @@ impl Fr {
square_assign_multi(&mut t0, 7);
t0.mul_assign(&t1);
Maybe::new(t0, !self.ct_eq(&Self::zero()))
CtOption::new(t0, !self.ct_eq(&Self::zero()))
}
#[inline]

View File

@ -41,8 +41,8 @@ use subtle::{Choice, ConditionallySelectable, ConstantTimeEq};
#[macro_use]
mod util;
pub mod maybe;
use maybe::Maybe;
mod ctoption;
pub use ctoption::CtOption;
mod fq;
mod fr;
@ -318,7 +318,7 @@ impl AffinePoint {
/// Attempts to interpret a byte representation of an
/// affine point, failing if the element is not on
/// the curve or non-canonical.
pub fn from_bytes(mut b: [u8; 32]) -> Maybe<Self> {
pub fn from_bytes(mut b: [u8; 32]) -> CtOption<Self> {
// Grab the sign bit from the representation
let sign = b[31] >> 7;
@ -348,7 +348,7 @@ impl AffinePoint {
let u_negated = -u;
let final_u = Fq::conditional_select(&u, &u_negated, flip_sign);
Maybe::new(AffinePoint { u: final_u, v }, Choice::from(1u8))
CtOption::new(AffinePoint { u: final_u, v }, Choice::from(1u8))
})
})
}