pub mod ed25519;
pub mod keymanip;
pub mod rsa;
pub mod curve25519 {
use derive_deftly::Deftly;
use educe::Educe;
use subtle::ConstantTimeEq;
use crate::util::ct::derive_deftly_template_PartialEqFromCtEq;
use crate::util::rng::RngCompat;
#[allow(clippy::exhaustive_structs)]
#[derive(Clone, Educe)]
#[educe(Debug)]
pub struct StaticKeypair {
#[educe(Debug(ignore))]
pub secret: StaticSecret,
pub public: PublicKey,
}
pub struct EphemeralSecret(x25519_dalek::EphemeralSecret);
#[derive(Clone)]
pub struct StaticSecret(x25519_dalek::StaticSecret);
impl ConstantTimeEq for StaticSecret {
fn ct_eq(&self, other: &Self) -> subtle::Choice {
let Self { 0: self_secret } = self;
let Self { 0: other_secret } = other;
self_secret.as_bytes().ct_eq(other_secret.as_bytes())
}
}
#[derive(Clone, Copy, Debug, Eq, Deftly)]
#[derive_deftly(PartialEqFromCtEq)]
pub struct PublicKey(x25519_dalek::PublicKey);
impl ConstantTimeEq for PublicKey {
fn ct_eq(&self, other: &Self) -> subtle::Choice {
let Self { 0: self_secret } = self;
let Self { 0: other_secret } = other;
self_secret.as_bytes().ct_eq(other_secret.as_bytes())
}
}
pub struct SharedSecret(x25519_dalek::SharedSecret);
impl<'a> From<&'a EphemeralSecret> for PublicKey {
fn from(secret: &'a EphemeralSecret) -> Self {
Self((&secret.0).into())
}
}
impl<'a> From<&'a StaticSecret> for PublicKey {
fn from(secret: &'a StaticSecret) -> Self {
Self((&secret.0).into())
}
}
impl From<[u8; 32]> for StaticSecret {
fn from(value: [u8; 32]) -> Self {
Self(value.into())
}
}
impl From<[u8; 32]> for PublicKey {
fn from(value: [u8; 32]) -> Self {
Self(value.into())
}
}
impl EphemeralSecret {
pub fn random_from_rng<R: rand_core::RngCore + rand_core::CryptoRng>(csprng: R) -> Self {
Self(x25519_dalek::EphemeralSecret::random_from_rng(
RngCompat::new(csprng),
))
}
pub fn diffie_hellman(self, their_public: &PublicKey) -> SharedSecret {
SharedSecret(self.0.diffie_hellman(&their_public.0))
}
}
impl StaticSecret {
pub fn random_from_rng<R: rand_core::RngCore + rand_core::CryptoRng>(csprng: R) -> Self {
Self(x25519_dalek::StaticSecret::random_from_rng(RngCompat::new(
csprng,
)))
}
pub fn diffie_hellman(&self, their_public: &PublicKey) -> SharedSecret {
SharedSecret(self.0.diffie_hellman(&their_public.0))
}
pub fn to_bytes(&self) -> [u8; 32] {
self.0.to_bytes()
}
pub fn as_bytes(&self) -> &[u8; 32] {
self.0.as_bytes()
}
}
impl SharedSecret {
pub fn as_bytes(&self) -> &[u8; 32] {
self.0.as_bytes()
}
pub fn was_contributory(&self) -> bool {
self.0.was_contributory()
}
}
impl PublicKey {
pub fn as_bytes(&self) -> &[u8; 32] {
self.0.as_bytes()
}
pub fn to_bytes(&self) -> [u8; 32] {
self.0.to_bytes()
}
}
}
pub trait ValidatableSignature {
fn is_valid(&self) -> bool;
fn as_ed25519(&self) -> Option<&ed25519::ValidatableEd25519Signature> {
None
}
}
pub fn validate_all_sigs(v: &[Box<dyn ValidatableSignature>]) -> bool {
let mut ed_sigs = Vec::new();
let mut non_ed_sigs = Vec::new();
for sig in v.iter() {
match sig.as_ed25519() {
Some(ed_sig) => ed_sigs.push(ed_sig),
None => non_ed_sigs.push(sig),
}
}
let ed_batch_is_valid = crate::pk::ed25519::validate_batch(&ed_sigs[..]);
ed_batch_is_valid && non_ed_sigs.iter().all(|b| b.is_valid())
}
#[cfg(test)]
mod test {
#![allow(clippy::bool_assert_comparison)]
#![allow(clippy::clone_on_copy)]
#![allow(clippy::dbg_macro)]
#![allow(clippy::mixed_attributes_style)]
#![allow(clippy::print_stderr)]
#![allow(clippy::print_stdout)]
#![allow(clippy::single_char_pattern)]
#![allow(clippy::unwrap_used)]
#![allow(clippy::unchecked_time_subtraction)]
#![allow(clippy::useless_vec)]
#![allow(clippy::needless_pass_by_value)]
#[test]
fn validatable_ed_sig() {
use super::ValidatableSignature;
use super::ed25519::{PublicKey, Signature, ValidatableEd25519Signature};
use hex_literal::hex;
let pk = PublicKey::from_bytes(&hex!(
"fc51cd8e6218a1a38da47ed00230f058
0816ed13ba3303ac5deb911548908025"
))
.unwrap();
let sig: Signature = hex!(
"6291d657deec24024827e69c3abe01a3
0ce548a284743a445e3680d7db5ac3ac
18ff9b538d16f290ae67f760984dc659
4a7c15e9716ed28dc027beceea1ec40a"
)
.into();
let valid = ValidatableEd25519Signature::new(pk, sig, &hex!("af82"));
let invalid = ValidatableEd25519Signature::new(pk, sig, &hex!("af83"));
assert!(valid.is_valid());
assert!(!invalid.is_valid());
}
}