use std::str::FromStr;
use crate::errors::SlugErrors;
use crate::slugcrypt::internals::signature::ed25519::{ED25519PublicKey,ED25519SecretKey,ED25519Signature};
use crate::slugcrypt::internals::signature::ml_dsa::{SlugMLDSA3,MLDSA3Keypair,MLDSA3PublicKey,MLDSA3SecretKey,MLDSA3Signature};
use pem::Pem;
use serde::{Serialize,Deserialize};
use zeroize::{Zeroize,ZeroizeOnDrop};
pub const ABSOLVE_CONTEXT: &str = "libslug20";
use crate::slugcrypt::traits::{IntoPemPublic,IntoPemSecret, IntoPemSignature};
use crate::slugcrypt::traits::IntoPem;
use crate::slugcrypt::traits::{IntoX59PublicKey,IntoX59SecretKey,IntoX59Signature};
use crate::slugcrypt::traits::{FromEncoding,IntoEncoding};
use crate::errors::{SlugErrorAlgorithms,EncodingError};
use crate::slugcrypt::traits::IntoPemX59;
use crate::slugcrypt::traits::{FromBincode,IntoBincode};
use crate::slugcrypt::traits::{FromStandardPem, IntoStandardPem};
use crate::slugcrypt::traits::{IntoStandardEncoding,FromStandardEncoding};
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, PartialOrd, Zeroize, ZeroizeOnDrop, Hash)]
pub struct AbsolveKeypair {
pub ed25519pk: ED25519PublicKey,
pub mldsa3pk: MLDSA3PublicKey,
pub ed25519sk: Option<ED25519SecretKey>,
pub mldsa3sk: Option<MLDSA3SecretKey>,
}
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, PartialOrd, Zeroize, ZeroizeOnDrop, Hash)]
pub struct AbsolveSignature {
pub ed25519sig: ED25519Signature,
pub mldsa3sig: MLDSA3Signature,
pub context: Vec<u8>,
}
impl AbsolveKeypair {
pub fn generate() -> Self {
let ed25519_sk = ED25519SecretKey::generate();
let ed25519_pk = ed25519_sk.public_key().unwrap();
let mldsa_keypair = SlugMLDSA3::generate();
let mldsa_pk = mldsa_keypair.public_key();
let mldsa_sk = mldsa_keypair.secret_key();
Self {
ed25519pk: ed25519_pk,
mldsa3pk: mldsa_pk.to_owned(),
ed25519sk: Some(ed25519_sk),
mldsa3sk: Some(mldsa_sk.to_owned())
}
}
pub fn sign_with_context<T: AsRef<[u8]>>(&self, msg: T, context: T) -> Result<AbsolveSignature,SlugErrors> {
if self.ed25519sk.is_some() == true && self.mldsa3sk.is_some() == true {
let sig = self.ed25519sk.clone().unwrap().sign(msg.as_ref())?;
let sig_mldsa = self.mldsa3sk.clone().unwrap().sign(msg.as_ref(),context.as_ref())?;
return Ok(AbsolveSignature { ed25519sig: sig.to_owned(), mldsa3sig: sig_mldsa.to_owned(), context: context.as_ref().to_vec() })
}
else {
return Err(SlugErrors::SigningFailure(crate::errors::SlugErrorAlgorithms::SIG_ABSOLVESIGNING))
}
}
pub fn sign<T: AsRef<[u8]>>(&self, msg: T) -> Result<AbsolveSignature,SlugErrors> {
return self.sign_with_context(msg.as_ref(), ABSOLVE_CONTEXT.as_bytes())
}
pub fn verify<T: AsRef<[u8]>>(&self, msg: T, signature: AbsolveSignature) -> Result<bool,SlugErrors> {
let is_valid = self.ed25519pk.verify(signature.ed25519sig.clone(), msg.as_ref())?;
let is_valid_pq = self.mldsa3pk.verify(msg.as_ref(), signature.context.as_slice(), &signature.mldsa3sig)?;
if is_valid == true && is_valid_pq == true {
return Ok(true)
}
else if is_valid == true && is_valid_pq == false {
return Ok(false)
}
else if is_valid == false && is_valid_pq == true {
return Ok(false)
}
else if is_valid == false && is_valid_pq == false {
return Ok(false)
}
else {
return Err(SlugErrors::VerifyingError(crate::errors::SlugErrorAlgorithms::SIG_ABSOLVESIGNING))
}
}
pub fn into_public_key(&self) -> Self {
Self {
ed25519pk: self.ed25519pk.clone(),
ed25519sk: None,
mldsa3pk: self.mldsa3pk.clone(),
mldsa3sk: None,
}
}
}
impl IntoX59PublicKey for AbsolveKeypair {
fn into_x59_pk(&self) -> Result<String,SlugErrors> {
let classical_ed25519 = self.ed25519pk.to_hexadecimal()?;
let pq_mldsa = self.mldsa3pk.into_hex()?;;
let mut output: String = String::new();
output.push_str(&classical_ed25519);
output.push_str(":");
output.push_str(&pq_mldsa);
return Ok(output)
}
fn from_x59_pk<T: AsRef<str>>(x59_encoded: T) -> Result<Self,SlugErrors> {
let input = x59_encoded.as_ref();
let keys = input.split_once(":");
if keys.is_some() {
let ed25519 = keys.unwrap().0;
let mldsa = keys.unwrap().1;
let output_1 = ED25519PublicKey::from_hex(ed25519)?;
let output_2= MLDSA3PublicKey::from_hex(mldsa)?;
return Ok(Self {
ed25519pk: output_1,
mldsa3pk: output_2,
ed25519sk: None,
mldsa3sk: None,
})
}
else {
return Err(SlugErrors::DecodingError { alg: SlugErrorAlgorithms::SIG_MLDSA, encoding: EncodingError::X59_fmt, other: None })
}
}
fn x59_metadata_pk() -> String {
String::from("libslug20/AbsolveSigning")
}
}
impl IntoX59SecretKey for AbsolveKeypair {
fn into_x59(&self) -> Result<String,SlugErrors> {
let classical_key_pk = self.ed25519pk.to_hexadecimal()?;
let mldsa_pk = self.mldsa3pk.into_hex()?;;
if self.ed25519sk.is_some() && self.mldsa3sk.is_some() {
let classical_key_sk = self.ed25519sk.clone().unwrap().to_hexadecimal()?;
let mldsa_sk = self.mldsa3sk.clone().unwrap().into_hex()?;;
let mut output = String::new();
output.push_str(&classical_key_pk);
output.push_str(":");
output.push_str(&mldsa_pk);
output.push_str("/");
output.push_str(&classical_key_sk);
output.push_str(":");
output.push_str(&mldsa_sk);
return Ok(output)
}
else {
return Err(SlugErrors::Other(String::from("No Secret Key For AbsolveSigning (ML-DSA3 + ED25519)")))
}
}
fn from_x59<T: AsRef<str>>(x59_encoded_secret_key: T) -> Result<Self,SlugErrors> {
let x = x59_encoded_secret_key.as_ref();
let output = x.split_once("/");
if output.is_some() {
let (pk, sk) = output.unwrap();
let pk_output = pk.split_once(":");
let sk_output = sk.split_once(":");
if pk_output.is_some() && sk_output.is_some() {
let (ed25519pk, mldsa3pk) = pk_output.unwrap();
let (ed25519sk, mldsa3sk) = pk_output.unwrap();
let output_ed25519_pk = ED25519PublicKey::from_hex(ed25519pk)?;
let output_mldsa3_pk = MLDSA3PublicKey::from_hex(mldsa3pk)?;
let output_ed25519_sk = ED25519SecretKey::from_hex(ed25519sk)?;
let output_mldsa3_sk = MLDSA3SecretKey::from_hex(mldsa3sk)?;
return Ok(Self {
ed25519pk: output_ed25519_pk,
mldsa3pk: output_mldsa3_pk,
ed25519sk: Some(output_ed25519_sk),
mldsa3sk: Some(output_mldsa3_sk),
})
}
else {
return Err(SlugErrors::DecodingError { alg: SlugErrorAlgorithms::SIG_ABSOLVESIGNING, encoding: EncodingError::X59_fmt, other: None })
}
}
else {
return Err(SlugErrors::DecodingError { alg: SlugErrorAlgorithms::SIG_ABSOLVESIGNING, encoding: EncodingError::X59_fmt, other: None })
}
}
fn x59_metadata() -> String {
String::from("libslug20/AbsolveSigning")
}
}
impl IntoX59Signature for AbsolveSignature {
fn into_x59(&self) -> Result<String,SlugErrors> {
let ed25519sig = self.ed25519sig.to_hexadecimal()?;
let mldsa3sig = self.mldsa3sig.into_hex()?;;
let context_encoder = slugencode::SlugEncodingUsage::new(slugencode::SlugEncodings::Hex);
let context_as_hex = context_encoder.encode(&self.context)?;
let mut output = String::new();
output.push_str(&ed25519sig);
output.push_str(":");
output.push_str(&mldsa3sig);
output.push_str("/");
output.push_str(&context_as_hex);
return Ok(output)
}
fn from_x59<T: AsRef<str>>(x59_encoded_signature: T) -> Result<Self,SlugErrors> {
let x = x59_encoded_signature.as_ref();
let y = x.split_once(":");
if y.is_some() {
let sig = y.unwrap();
let ed25519_sig = sig.0;
let output = sig.1;
let mldsa3 = output.split_once("/");
if mldsa3.is_some() {
let (mldsa3sig, context) = mldsa3.unwrap();
let output_mldsa3_sig = MLDSA3Signature::from_hex(mldsa3sig)?;
let output_ed25519_sig = ED25519Signature::from_hex(output)?;
let encoder = slugencode::SlugEncodingUsage::new(slugencode::SlugEncodings::Hex);
let output_context_sig = encoder.decode(context)?;
return Ok(Self {
mldsa3sig: output_mldsa3_sig,
ed25519sig: output_ed25519_sig,
context: output_context_sig,
})
}
else {
return Err(SlugErrors::DecodingError { alg: SlugErrorAlgorithms::SIG_ABSOLVESIGNING, encoding: EncodingError::X59_fmt, other: None })
}
}
else {
return Err(SlugErrors::DecodingError { alg: SlugErrorAlgorithms::SIG_ABSOLVESIGNING, encoding: EncodingError::X59_fmt, other: None })
}
}
fn x59_metadata() -> String {
String::from("libslug20/AbsolveSigning")
}
}
impl IntoPemX59 for AbsolveKeypair {
fn into_pem_x59_standard(&self) -> Result<String,SlugErrors> {
let x = self.into_x59()?;
let output: Pem = Pem::new(Self::info_pem_x59_standard_label(), x);
return Ok(output.to_string())
}
fn from_pem_x59_standard<T: AsRef<str>>(s: T) -> Result<Self,SlugErrors> {
let x = Pem::from_str(s.as_ref())?;
let output: Vec<u8> = x.into_contents();
let x59 = String::from_utf8(output)?;
let output = Self::from_x59(x59)?;
return Ok(output)
}
fn info_pem_x59_standard_label() -> String {
String::from("libslug20/AbsolveSigningX59FMT")
}
}
impl IntoBincode for AbsolveKeypair {
fn into_bincode(&self) -> Result<Vec<u8>, SlugErrors> {
let output = bincode::serialize(self)?;
Ok(output)
}
}
impl IntoBincode for AbsolveSignature {
fn into_bincode(&self) -> Result<Vec<u8>, SlugErrors> {
let output = bincode::serialize(self)?;
Ok(output)
}
}
impl FromBincode for AbsolveKeypair {
fn from_bincode<T: AsRef<[u8]>>(bincode: T) -> Result<Self, SlugErrors> {
let x = bincode::deserialize(bincode.as_ref())?;
Ok(x)
}
}
impl FromBincode for AbsolveSignature {
fn from_bincode<T: AsRef<[u8]>>(bincode: T) -> Result<Self, SlugErrors> {
let x = bincode::deserialize(bincode.as_ref())?;
Ok(x)
}
}
impl IntoStandardPem for AbsolveKeypair {
fn into_standard_pem(&self) -> Result<String,SlugErrors> {
if self.ed25519sk.is_none() || self.mldsa3sk.is_none() {
let bincode = self.into_bincode()?;
let output: Pem = Pem::new(Self::label_for_standard_pem(), bincode);
return Ok(output.to_string())
}
else if self.ed25519sk.is_some() && self.mldsa3sk.is_some() {
let bincode = self.into_bincode()?;
let output: Pem = Pem::new(Self::label_for_standard_pem_secret(), bincode);
return Ok(output.to_string())
}
else {
return Err(SlugErrors::InvalidPemLabel)
}
}
fn label_for_standard_pem() -> String {
String::from("OpenInternetCryptographyProject/AbsolveSigning-Public-Key")
}
fn label_for_standard_pem_secret() -> String {
String::from("OpenInternetCryptographyProject/AbsolveSigning-Secret-Key")
}
}
impl IntoStandardPem for AbsolveSignature {
fn into_standard_pem(&self) -> Result<String,SlugErrors> {
let bincode = self.into_bincode()?;
let output: Pem = Pem::new(Self::label_for_standard_pem(), bincode);
return Ok(output.to_string())
}
fn label_for_standard_pem() -> String {
String::from("OpenInternetCryptographyProject/AbsolveSigning-Signature")
}
fn label_for_standard_pem_secret() -> String {
String::from("OpenInternetCryptographyProject/AbsolveSigning-Secret-Key")
}
}
impl FromStandardPem for AbsolveSignature {
fn from_standard_pem<T: AsRef<str>>(s: T) -> Result<Self, SlugErrors> {
let pem = Pem::from_str(s.as_ref())?;
if pem.tag() != Self::label_for_standard_pem() {
return Err(SlugErrors::InvalidPemLabel)
}
let output: AbsolveSignature = Self::from_bincode(pem.contents())?;
return Ok(output)
}
}
impl FromStandardPem for AbsolveKeypair {
fn from_standard_pem<T: AsRef<str>>(s: T) -> Result<Self,SlugErrors> {
let pem = Pem::from_str(s.as_ref())?;
if pem.tag() == Self::label_for_standard_pem() {
let output: AbsolveKeypair = Self::from_bincode(pem.contents())?;
return Ok(output)
}
else if pem.tag() == Self::label_for_standard_pem_secret() {
let output: AbsolveKeypair = Self::from_bincode(pem.contents())?;
return Ok(output)
}
else {
return Err(SlugErrors::InvalidPemLabel)
}
}
}