use super::KeyPair;
use super::SeaError;
use base64::{engine::general_purpose, Engine as _};
use p256::ecdsa::{SigningKey, VerifyingKey};
use p256::elliptic_curve::sec1::ToEncodedPoint;
use p256::{PublicKey as EcdhPublicKey, SecretKey};
use rand::rngs::OsRng;
pub async fn generate_pair() -> Result<KeyPair, SeaError> {
let signing_key = SigningKey::random(&mut OsRng);
let verifying_key = VerifyingKey::from(&signing_key);
let priv_bytes = signing_key.to_bytes();
#[allow(deprecated)] let priv_key = general_purpose::STANDARD_NO_PAD.encode(priv_bytes.as_slice());
let pub_point = verifying_key.to_encoded_point(false);
let pub_bytes = pub_point.as_bytes();
if pub_bytes.len() != 65 || pub_bytes[0] != 0x04 {
return Err(SeaError::Crypto("Invalid public key format".to_string()));
}
let x = &pub_bytes[1..33];
let y = &pub_bytes[33..65];
let pub_key = format!(
"{}.{}",
general_purpose::STANDARD_NO_PAD.encode(x),
general_purpose::STANDARD_NO_PAD.encode(y)
);
let ecdh_secret = SecretKey::random(&mut OsRng);
let ecdh_public = EcdhPublicKey::from_secret_scalar(&ecdh_secret.to_nonzero_scalar());
let pub_point = ecdh_public.to_encoded_point(false);
let epub_bytes = pub_point.as_bytes();
if epub_bytes.len() != 65 || epub_bytes[0] != 0x04 {
return Err(SeaError::Crypto(
"Invalid ECDH public key format".to_string(),
));
}
let ex = &epub_bytes[1..33];
let ey = &epub_bytes[33..65];
let epub_key = Some(format!(
"{}.{}",
general_purpose::STANDARD_NO_PAD.encode(ex),
general_purpose::STANDARD_NO_PAD.encode(ey)
));
let epriv_bytes = ecdh_secret.to_bytes();
#[allow(deprecated)] let epriv_key = Some(general_purpose::STANDARD_NO_PAD.encode(epriv_bytes.as_slice()));
Ok(KeyPair {
pub_key,
priv_key,
epub_key,
epriv_key,
})
}