ring 0.7.2-alpha2

Safe, fast, small crypto using Rust.
Documentation
// Copyright 2015-2016 Brian Smith.
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND AND THE AUTHORS DISCLAIM ALL WARRANTIES
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY
// SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
// OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
// CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.

use {error, rand};
use core;
use super::{bigint, N};
use super::bigint::{R, RR};

pub struct Blinding(Option<Contents>);

struct Contents {
    blinding_factor: bigint::Elem<N, R>,
    blinding_factor_inv: bigint::Elem<N, R>,
    remaining: usize,
}

impl Blinding {
    pub fn new() -> Self { Blinding(None) }

    pub fn blind<F>(&mut self, x: bigint::Elem<N>,
                    e: bigint::PublicExponent, n: &bigint::Modulus<N>,
                    oneRR_mod_n: &bigint::One<N, RR>,
                    rng: &rand::SecureRandom, f: F)
                    -> Result<bigint::Elem<N>, error::Unspecified>
                    where F: FnOnce(bigint::Elem<N>)
                                    -> Result<bigint::Elem<N>,
                                              error::Unspecified> {
        let old_contents = core::mem::replace(&mut self.0, None);

        let new_contents = try!(match old_contents {
            Some(Contents {
                blinding_factor,
                blinding_factor_inv,
                remaining,
            }) => {
                if remaining > 0 {
                    let blinding_factor =
                        try!(bigint::elem_squared(blinding_factor, n));
                    let blinding_factor_inv =
                        try!(bigint::elem_squared(blinding_factor_inv, n));
                    Ok(Contents {
                        blinding_factor: blinding_factor,
                        blinding_factor_inv: blinding_factor_inv,
                        remaining: remaining - 1,
                    })
                } else {
                    reset(blinding_factor, blinding_factor_inv, e, n,
                          oneRR_mod_n, rng)
                }
            },

            None => {
                let elem1 = try!(bigint::Elem::zero());
                let elem2 = try!(bigint::Elem::zero());
                reset(elem1, elem2, e, n, oneRR_mod_n, rng)
            },
        });

        let blinded_input =
            try!(bigint::elem_mul(&new_contents.blinding_factor, x, n));
        let blinded_result = try!(f(blinded_input));
        let result =
            try!(bigint::elem_mul(&new_contents.blinding_factor_inv,
                                  blinded_result, n));

        let _ = core::mem::replace(&mut self.0, Some(new_contents));

        Ok(result)
    }

    #[cfg(test)]
    pub fn remaining(&self) -> usize {
        match &self.0 {
            &Some(Contents { remaining, .. }) => remaining,
            &None => { 0 },
        }
    }
}

fn reset(elem1: bigint::Elem<N, R>, elem2: bigint::Elem<N, R>,
         e: bigint::PublicExponent, n: &bigint::Modulus<N>,
         oneRR_mod_n: &bigint::One<N, RR>, rng: &rand::SecureRandom)
         -> Result<Contents, error::Unspecified> {
    let mut random = bigint::Elem::take_storage(elem1);
    let mut random_inv = bigint::Elem::take_storage(elem2);

    for _ in 0..32 {
        try!(bigint::elem_randomize(&mut random, n, rng));
        match bigint::elem_set_to_inverse_blinded(&mut random_inv, &random, n,
                                                  rng) {
            Ok(()) => {
                let random =
                    try!(bigint::elem_mul(oneRR_mod_n.as_ref(), random, n));
                let random = try!(bigint::elem_exp_vartime(random, e, n));
                let random_inv =
                    try!(bigint::elem_mul(oneRR_mod_n.as_ref(), random_inv, n));
                return Ok(Contents {
                    blinding_factor: random,
                    blinding_factor_inv: random_inv,
                    remaining: REMAINING_MAX - 1,
                });
            },
            Err(bigint::InversionError::NoInverse) => {}, // continue
            Err(_) => { return Err(error::Unspecified); }
        }
    }

    Err(error::Unspecified)
}


// The paper suggests reusing blinding factors 32 times. Note that this must
// never be zero.
// TODO: citation. TODO: Skepticism.
pub const REMAINING_MAX: usize = 32;

#[cfg(test)]
mod tests {
    // Testing for this module is done as part of the ring::rsa::signing tests.
}