use super::{ops::*, verify_affine_point_is_on_the_curve};
use crate::{
arithmetic::montgomery::R,
ec, error,
limb::{self, LIMB_BYTES},
rand,
};
pub fn random_scalar(
ops: &PrivateKeyOps,
rng: &dyn rand::SecureRandom,
) -> Result<Scalar, error::Unspecified> {
let num_limbs = ops.common.num_limbs;
let mut bytes = [0; ec::SCALAR_MAX_BYTES];
let bytes = &mut bytes[..(num_limbs * LIMB_BYTES)];
generate_private_scalar_bytes(ops, rng, bytes)?;
scalar_from_big_endian_bytes(ops, bytes)
}
pub fn generate_private_scalar_bytes(
ops: &PrivateKeyOps,
rng: &dyn rand::SecureRandom,
out: &mut [u8],
) -> Result<(), error::Unspecified> {
let candidate = out;
for _ in 0..100 {
rng.fill(candidate)?;
if check_scalar_big_endian_bytes(ops, candidate).is_err() {
continue;
}
return Ok(());
}
Err(error::Unspecified)
}
#[inline]
pub fn private_key_as_scalar(ops: &PrivateKeyOps, private_key: &ec::Seed) -> Scalar {
scalar_from_big_endian_bytes(ops, private_key.bytes_less_safe()).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::Seed,
) -> 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 affine_from_jacobian(
ops: &PrivateKeyOps,
p: &Point,
) -> Result<(Elem<R>, Elem<R>), 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))?;
Ok((x_aff, y_aff))
}
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 (x_aff, y_aff) = affine_from_jacobian(ops, p)?;
let num_limbs = ops.common.num_limbs;
if let Some(x_out) = x_out {
let x = ops.common.elem_unencoded(&x_aff);
limb::big_endian_from_limbs(&x.limbs[..num_limbs], x_out);
}
if let Some(y_out) = y_out {
let y = ops.common.elem_unencoded(&y_aff);
limb::big_endian_from_limbs(&y.limbs[..num_limbs], y_out);
}
Ok(())
}