use self::ops::*;
use crate::{arithmetic::montgomery::*, cpu, ec, error, io::der, limb::LimbMask, pkcs8};
fn verify_affine_point_is_on_the_curve(
ops: &CommonOps,
(x, y): (&Elem<R>, &Elem<R>),
) -> Result<(), error::Unspecified> {
verify_affine_point_is_on_the_curve_scaled(ops, (x, y), &ops.a, &ops.b)
}
fn verify_jacobian_point_is_on_the_curve(
ops: &CommonOps,
p: &Point,
) -> Result<Elem<R>, error::Unspecified> {
let z = ops.point_z(p);
ops.elem_verify_is_not_zero(&z)?;
let x = ops.point_x(p);
let y = ops.point_y(p);
let z2 = ops.elem_squared(&z);
let z4 = ops.elem_squared(&z2);
let z4_a = ops.elem_product(&z4, &ops.a);
let z6 = ops.elem_product(&z4, &z2);
let z6_b = ops.elem_product(&z6, &ops.b);
verify_affine_point_is_on_the_curve_scaled(ops, (&x, &y), &z4_a, &z6_b)?;
Ok(z2)
}
fn verify_affine_point_is_on_the_curve_scaled(
ops: &CommonOps,
(x, y): (&Elem<R>, &Elem<R>),
a_scaled: &Elem<R>,
b_scaled: &Elem<R>,
) -> Result<(), error::Unspecified> {
let lhs = ops.elem_squared(y);
let mut rhs = ops.elem_squared(x);
ops.elem_add(&mut rhs, a_scaled);
ops.elem_mul(&mut rhs, x);
ops.elem_add(&mut rhs, b_scaled);
if ops.elems_are_equal(&lhs, &rhs) != LimbMask::True {
return Err(error::Unspecified);
}
Ok(())
}
pub(crate) fn key_pair_from_pkcs8(
curve: &'static ec::Curve,
template: &pkcs8::Template,
input: untrusted::Input,
cpu_features: cpu::Features,
) -> Result<ec::KeyPair, error::KeyRejected> {
let (ec_private_key, _) = pkcs8::unwrap_key(template, pkcs8::Version::V1Only, input)?;
let (private_key, public_key) =
ec_private_key.read_all(error::KeyRejected::invalid_encoding(), |input| {
der::nested(
input,
der::Tag::Sequence,
error::KeyRejected::invalid_encoding(),
|input| key_pair_from_pkcs8_(template, input),
)
})?;
key_pair_from_bytes(curve, private_key, public_key, cpu_features)
}
fn key_pair_from_pkcs8_<'a>(
template: &pkcs8::Template,
input: &mut untrusted::Reader<'a>,
) -> Result<(untrusted::Input<'a>, untrusted::Input<'a>), error::KeyRejected> {
let version = der::small_nonnegative_integer(input)
.map_err(|error::Unspecified| error::KeyRejected::invalid_encoding())?;
if version != 1 {
return Err(error::KeyRejected::version_not_supported());
}
let private_key = der::expect_tag_and_get_value(input, der::Tag::OctetString)
.map_err(|error::Unspecified| error::KeyRejected::invalid_encoding())?;
if input.peek(u8::from(der::Tag::ContextSpecificConstructed0)) {
let actual_alg_id =
der::expect_tag_and_get_value(input, der::Tag::ContextSpecificConstructed0)
.map_err(|error::Unspecified| error::KeyRejected::invalid_encoding())?;
if actual_alg_id != template.curve_oid() {
return Err(error::KeyRejected::wrong_algorithm());
}
}
let public_key = der::nested(
input,
der::Tag::ContextSpecificConstructed1,
error::Unspecified,
der::bit_string_with_no_unused_bits,
)
.map_err(|error::Unspecified| error::KeyRejected::invalid_encoding())?;
Ok((private_key, public_key))
}
pub(crate) fn key_pair_from_bytes(
curve: &'static ec::Curve,
private_key_bytes: untrusted::Input,
public_key_bytes: untrusted::Input,
cpu_features: cpu::Features,
) -> Result<ec::KeyPair, error::KeyRejected> {
let seed = ec::Seed::from_bytes(curve, private_key_bytes, cpu_features)
.map_err(|error::Unspecified| error::KeyRejected::invalid_component())?;
let r = ec::KeyPair::derive(seed)
.map_err(|error::Unspecified| error::KeyRejected::unexpected_error())?;
if public_key_bytes != *r.public_key().as_ref() {
return Err(error::KeyRejected::inconsistent_components());
}
Ok(r)
}
pub mod curve;
pub mod ecdh;
pub mod ecdsa;
mod ops;
mod private_key;
mod public_key;