use {ec, error, rand};
use super::ops::*;
use super::verify_affine_point_is_on_the_curve;
pub fn generate_private_key(ops: &PrivateKeyOps, rng: &rand::SecureRandom)
-> Result<ec::PrivateKey, error::Unspecified> {
let num_limbs = ops.common.num_limbs;
let max_exclusive = &ops.common.n.limbs[..num_limbs];
for _ in 0..100 {
let mut candidate_private_key =
ec::PrivateKey { bytes: [0; ec::SCALAR_MAX_BYTES] };
let num_bytes = num_limbs * LIMB_BYTES;
try!(rng.fill(&mut candidate_private_key.bytes[..num_bytes]));
let scalar = private_key_as_scalar_(ops, &candidate_private_key);
if !is_scalar_within_range(&scalar, max_exclusive) {
continue;
}
return Ok(candidate_private_key);
}
Err(error::Unspecified)
}
#[inline]
pub fn private_key_as_scalar(ops: &PrivateKeyOps,
private_key: &ec::PrivateKey) -> Scalar {
let num_limbs = ops.common.num_limbs;
let max_exclusive = &ops.common.n.limbs[..num_limbs];
let r = private_key_as_scalar_(ops, private_key);
assert!(is_scalar_within_range(&r, max_exclusive));
r
}
fn private_key_as_scalar_(ops: &PrivateKeyOps, private_key: &ec::PrivateKey)
-> Scalar {
let num_limbs = ops.common.num_limbs;
let bytes = &private_key.bytes;
let mut limbs = [0; MAX_LIMBS];
for i in 0..num_limbs {
let mut limb = 0;
for j in 0..LIMB_BYTES {
limb = (limb << 8) |
(bytes[((num_limbs - i - 1) * LIMB_BYTES) + j] as Limb);
}
limbs[i] = limb;
}
Scalar::from_limbs_unchecked(&limbs)
}
fn is_scalar_within_range(scalar: &Scalar, max_exclusive: &[Limb]) -> bool {
let limbs = &scalar.limbs[..max_exclusive.len()];
let eq_zero = limbs_are_zero_constant_time(limbs);
let lt_bound = limbs_less_than_limbs_constant_time(limbs, max_exclusive);
eq_zero == LimbMask::False && lt_bound == LimbMask::True
}
pub fn public_from_private(ops: &PrivateKeyOps, public_out: &mut [u8],
my_private_key: &ec::PrivateKey)
-> Result<(), error::Unspecified> {
let elem_and_scalar_bytes = ops.common.num_limbs * LIMB_BYTES;
debug_assert_eq!(public_out.len(), 1 + (2 * elem_and_scalar_bytes));
let my_private_key = private_key_as_scalar(ops, my_private_key);
let my_public_key = ops.point_mul_base(&my_private_key);
public_out[0] = 4; let (x_out, y_out) =
(&mut public_out[1..]).split_at_mut(elem_and_scalar_bytes);
big_endian_affine_from_jacobian(ops, Some(x_out), Some(y_out),
&my_public_key)
}
pub fn big_endian_affine_from_jacobian(ops: &PrivateKeyOps,
x_out: Option<&mut [u8]>,
y_out: Option<&mut [u8]>, p: &Point)
-> Result<(), error::Unspecified> {
let z = ops.common.point_z(p);
assert!(ops.common.elem_verify_is_not_zero(&z).is_ok());
let x = ops.common.point_x(p);
let y = ops.common.point_y(p);
let z_inv = ops.elem_inverse(&z);
let zz_inv = ops.common.elem_squared(&z_inv);
let zzz_inv = ops.common.elem_product(&z_inv, &zz_inv);
let x_aff = ops.common.elem_product(&x, &zz_inv);
let y_aff = ops.common.elem_product(&y, &zzz_inv);
try!(verify_affine_point_is_on_the_curve(ops.common, (&x_aff, &y_aff)));
let num_limbs = ops.common.num_limbs;
if let Some(x_out) = x_out {
let x_decoded = ops.common.elem_decoded(&x_aff);
big_endian_from_limbs(x_out, &x_decoded.limbs[..num_limbs]);
}
if let Some(y_out) = y_out {
let y_decoded = ops.common.elem_decoded(&y_aff);
big_endian_from_limbs(y_out, &y_decoded.limbs[..num_limbs]);
}
Ok(())
}
fn big_endian_from_limbs(out: &mut [u8], limbs: &[Limb]) {
let num_limbs = limbs.len();
debug_assert_eq!(out.len(), num_limbs * LIMB_BYTES);
for i in 0..num_limbs {
let mut limb = limbs[i];
for j in 0..LIMB_BYTES {
out[((num_limbs - i - 1) * LIMB_BYTES) + (LIMB_BYTES - j - 1)] =
(limb & 0xff) as u8;
limb >>= 8;
}
}
}
#[cfg(test)]
pub mod test_util {
use super::super::ops::Limb;
pub fn big_endian_from_limbs(out: &mut [u8], limbs: &[Limb]) {
super::big_endian_from_limbs(out, limbs)
}
}