mod constants;
mod field;
mod point;
mod scalar;
pub use constants::{
P256_FIELD_ELEMENT_SIZE, P256_KEM_SHARED_SECRET_KDF_OUTPUT_SIZE, P256_POINT_COMPRESSED_SIZE,
P256_POINT_UNCOMPRESSED_SIZE, P256_SCALAR_SIZE,
};
pub use field::FieldElement;
pub use point::{Point, PointFormat};
pub use scalar::Scalar;
use crate::error::{Error, Result};
use crate::hash::sha2::Sha256;
use crate::kdf::hkdf::Hkdf;
use crate::kdf::KeyDerivationFunction as KdfTrait;
use dcrypt_params::traditional::ecdsa::NIST_P256;
use rand::{CryptoRng, RngCore};
pub fn base_point_g() -> Point {
Point::new_uncompressed(&NIST_P256.g_x, &NIST_P256.g_y)
.expect("Standard base point must be valid")
}
pub fn scalar_mult_base_g(scalar: &Scalar) -> Result<Point> {
let g = base_point_g();
g.mul(scalar)
}
pub fn generate_keypair<R: CryptoRng + RngCore>(rng: &mut R) -> Result<(Scalar, Point)> {
let mut scalar_bytes = [0u8; P256_SCALAR_SIZE];
loop {
rng.fill_bytes(&mut scalar_bytes);
match Scalar::new(scalar_bytes) {
Ok(private_key) => {
let public_key = scalar_mult_base_g(&private_key)?;
return Ok((private_key, public_key));
}
Err(_) => {
continue;
}
}
}
}
pub fn scalar_mult(scalar: &Scalar, point: &Point) -> Result<Point> {
if point.is_identity() {
return Ok(Point::identity());
}
point.mul(scalar)
}
pub fn kdf_hkdf_sha256_for_ecdh_kem(
ikm: &[u8],
info: Option<&[u8]>,
) -> Result<[u8; P256_KEM_SHARED_SECRET_KDF_OUTPUT_SIZE]> {
let hkdf_instance = <Hkdf<Sha256, 16> as KdfTrait>::new();
let derived_key_vec = hkdf_instance.derive_key(
ikm,
None, info, P256_KEM_SHARED_SECRET_KDF_OUTPUT_SIZE,
)?;
let mut output_array = [0u8; P256_KEM_SHARED_SECRET_KDF_OUTPUT_SIZE];
if derived_key_vec.len() == P256_KEM_SHARED_SECRET_KDF_OUTPUT_SIZE {
output_array.copy_from_slice(&derived_key_vec);
Ok(output_array)
} else {
Err(Error::Length {
context: "KDF output for ECDH",
expected: P256_KEM_SHARED_SECRET_KDF_OUTPUT_SIZE,
actual: derived_key_vec.len(),
})
}
}
#[cfg(test)]
mod tests;