risc0-curve25519-dalek-source/src/subtle.rs

168 lines
4.1 KiB
Rust
Raw Normal View History

2016-12-08 05:12:00 +00:00
// -*- mode: rust; -*-
//
// To the extent possible under law, the authors have waived all copyright and
// related or neighboring rights to curve25519-dalek, using the Creative
// Commons "CC0" public domain dedication. See
// <http://creativecommons.org/publicdomain/zero/.0/> for full details.
//
// Authors:
// - Isis Agora Lovecruft <isis@patternsinthevoid.net>
// - Henry de Valence <hdevalence@hdevalence.ca>
//! Constant-time traits and utility functions.
2016-12-08 05:12:00 +00:00
2017-02-20 22:20:43 +00:00
use core::ops::Neg;
/// Trait for items which can be conditionally assigned in constant time.
pub trait CTAssignable {
/// If `choice == 1u8`, assign `other` to `self`.
/// Otherwise, leave `self` unchanged.
/// Executes in constant time.
fn conditional_assign(&mut self, other: &Self, choice: u8);
}
/// Trait for items whose equality to another item may be tested in constant time.
pub trait CTEq {
/// Determine if two items are equal in constant time.
///
/// # Returns
///
/// `1u8` if the two items are equal, and `0u8` otherwise.
fn ct_eq(&self, other: &Self) -> u8;
}
/// Trait for items which can be conditionally negated in constant time.
///
/// Note: it is not necessary to implement this trait, as a generic
/// implementation is provided.
pub trait CTNegatable
{
/// Conditionally negate an element if `choice == 1u8`.
fn conditional_negate(&mut self, choice: u8);
}
impl<T> CTNegatable for T
2017-02-20 22:20:43 +00:00
where T: CTAssignable, for<'a> &'a T: Neg<Output=T>
{
fn conditional_negate(&mut self, choice: u8) {
// Need to cast to eliminate mutability
let self_neg: T = -(self as &T);
self.conditional_assign(&self_neg, choice);
}
2017-02-20 22:20:43 +00:00
}
2016-12-08 05:12:00 +00:00
/// Check equality of two bytes in constant time.
///
/// # Return
///
/// Returns `1u8` if `a == b` and `0u8` otherwise.
2016-12-08 05:12:00 +00:00
#[inline(always)]
pub fn bytes_equal_ct(a: u8, b: u8) -> u8 {
let mut x: u8;
x = !(a ^ b);
x &= x >> 4;
x &= x >> 2;
x &= x >> 1;
x
}
/// Test if a byte is non-zero in constant time.
///
2017-05-26 20:53:18 +00:00
/// ```
/// # extern crate curve25519_dalek;
/// # use curve25519_dalek::subtle::byte_is_nonzero;
/// # fn main() {
2016-12-08 05:12:00 +00:00
/// let mut x: u8;
/// x = 0;
2017-05-26 20:53:18 +00:00
/// assert!(byte_is_nonzero(x) == 0);
2016-12-08 05:12:00 +00:00
/// x = 3;
/// assert!(byte_is_nonzero(x) == 1);
2017-05-26 20:53:18 +00:00
/// # }
2016-12-08 05:12:00 +00:00
/// ```
///
/// # Return
///
/// * If b != 0, returns 1u8.
/// * If b == 0, returns 0u8.
#[inline(always)]
pub fn byte_is_nonzero(b: u8) -> u8 {
let mut x = b;
x |= x >> 4;
x |= x >> 2;
x |= x >> 1;
(x & 1)
}
/// Check equality of two arrays, `a` and `b`, in constant time.
2016-12-08 05:12:00 +00:00
///
/// There is an `assert!` that the two arrays are of equal length. For
/// example, the following code will panic:
///
/// ```rust,ignore
/// let a: [u8; 3] = [0, 0, 0];
/// let b: [u8; 4] = [0, 0, 0, 0];
///
/// assert!(arrays_equal(&a, &b) == 1);
/// ```
///
/// However, if the arrays are equal length, but their contents do *not* match,
/// `0u8` will be returned:
///
/// ```
/// # extern crate curve25519_dalek;
/// # use curve25519_dalek::subtle::arrays_equal;
/// # fn main() {
/// let a: [u8; 3] = [0, 1, 2];
/// let b: [u8; 3] = [1, 2, 3];
///
/// assert!(arrays_equal(&a, &b) == 0);
/// # }
/// ```
///
/// And finally, if the contents *do* match, `1u8` is returned:
///
/// ```
/// # extern crate curve25519_dalek;
/// # use curve25519_dalek::subtle::arrays_equal;
/// # fn main() {
/// let a: [u8; 3] = [0, 1, 2];
/// let b: [u8; 3] = [0, 1, 2];
///
/// assert!(arrays_equal(&a, &b) == 1);
/// # }
/// ```
///
/// This function is commonly used in various cryptographic applications, such
/// as [signature verification](https://github.com/isislovecruft/ed25519-dalek/blob/0.3.2/src/ed25519.rs#L280),
/// among many other applications.
///
2016-12-08 05:12:00 +00:00
/// # Return
///
/// Returns `1u8` if `a == b` and `0u8` otherwise.
2016-12-08 05:12:00 +00:00
#[inline(always)]
pub fn arrays_equal(a: &[u8], b: &[u8]) -> u8 {
assert_eq!(a.len(), b.len());
2016-12-08 05:12:00 +00:00
let mut x: u8 = 0;
for i in 0 .. a.len() {
2016-12-08 05:12:00 +00:00
x |= a[i] ^ b[i];
}
bytes_equal_ct(x, 0)
}
#[cfg(test)]
mod test {
use super::*;
#[test]
#[should_panic]
fn arrays_equal_different_lengths() {
let a: [u8; 3] = [0, 0, 0];
let b: [u8; 4] = [0, 0, 0, 0];
assert!(arrays_equal(&a, &b) == 1);
}
}