use {ec, error, rand};
use super::ops::*;
use super::verify_affine_point_is_on_the_curve;
use untrusted;
pub fn generate_private_key(ops: &PrivateKeyOps, rng: &rand::SecureRandom)
-> Result<ec::PrivateKey, error::Unspecified> {
let num_limbs = ops.common.num_limbs;
for _ in 0..100 {
let mut candidate = [0; ec::SCALAR_MAX_BYTES];
{
let candidate = &mut candidate[..(num_limbs * LIMB_BYTES)];
rng.fill(candidate)?;
if check_scalar_big_endian_bytes(ops, candidate).is_err() {
continue;
}
}
return Ok(ec::PrivateKey {
bytes: candidate,
});
}
Err(error::Unspecified)
}
#[inline]
pub fn private_key_as_scalar(ops: &PrivateKeyOps,
private_key: &ec::PrivateKey) -> Scalar {
scalar_from_big_endian_bytes(
ops, &private_key.bytes[..(ops.common.num_limbs * LIMB_BYTES)]).unwrap()
}
pub fn check_scalar_big_endian_bytes(ops: &PrivateKeyOps, bytes: &[u8])
-> Result<(), error::Unspecified> {
debug_assert_eq!(bytes.len(), ops.common.num_limbs * LIMB_BYTES);
scalar_from_big_endian_bytes(ops, bytes).map(|_| ())
}
pub fn scalar_from_big_endian_bytes(ops: &PrivateKeyOps, bytes: &[u8])
-> Result<Scalar, error::Unspecified> {
scalar_parse_big_endian_fixed_consttime(
ops.common, untrusted::Input::from(bytes))
}
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 zz_inv = ops.elem_inverse_squared(&z);
let x_aff = ops.common.elem_product(&x, &zz_inv);
let y_aff = {
let zzzz_inv = ops.common.elem_squared(&zz_inv);
let zzz_inv = ops.common.elem_product(&z, &zzzz_inv);
ops.common.elem_product(&y, &zzz_inv)
};
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 = ops.common.elem_unencoded(&x_aff);
big_endian_from_limbs_padded(&x.limbs[..num_limbs], x_out);
}
if let Some(y_out) = y_out {
let y = ops.common.elem_unencoded(&y_aff);
big_endian_from_limbs_padded(&y.limbs[..num_limbs], y_out);
}
Ok(())
}