use ed25519_dalek::Keypair;
use rand::{CryptoRng, Rng};
use signature::{Signer, Verifier};
use zeroize::{Zeroize, Zeroizing};
use crate::pgp::crypto::{ECCCurve, HashAlgorithm};
use crate::pgp::errors::Result;
use crate::pgp::types::{EdDSASecretKey, Mpi, PlainSecretParams, PublicParams};
pub fn generate_key<R: Rng + CryptoRng>(rng: &mut R) -> (PublicParams, PlainSecretParams) {
let mut bytes = Zeroizing::new([0u8; ed25519_dalek::SECRET_KEY_LENGTH]);
rng.fill_bytes(&mut *bytes);
let secret = ed25519_dalek::SecretKey::from_bytes(&*bytes).expect("hard coded length");
let public = ed25519_dalek::PublicKey::from(&secret);
let keypair = Keypair { secret, public };
let mut bytes = keypair.to_bytes();
let mut q = Vec::with_capacity(33);
q.push(0x40);
q.extend_from_slice(&bytes[32..]);
let p = Mpi::from_raw_slice(&bytes[..32]);
bytes.zeroize();
(
PublicParams::EdDSA {
curve: ECCCurve::Ed25519,
q: q.into(),
},
PlainSecretParams::EdDSA(p),
)
}
pub fn verify(
curve: &ECCCurve,
q: &[u8],
_hash: HashAlgorithm,
hashed: &[u8],
sig: &[Mpi],
) -> Result<()> {
match *curve {
ECCCurve::Ed25519 => {
ensure_eq!(sig.len(), 2);
let r = sig[0].as_bytes();
let s = sig[1].as_bytes();
ensure!(r.len() < 33, "invalid R (len)");
ensure!(s.len() < 33, "invalid S (len)");
ensure_eq!(q.len(), 33, "invalid Q (len)");
ensure_eq!(q[0], 0x40, "invalid Q (prefix)");
let pk = ed25519_dalek::PublicKey::from_bytes(&q[1..])?;
let mut sig_bytes = vec![0u8; 64];
sig_bytes[(32 - r.len())..32].copy_from_slice(r);
sig_bytes[32 + (32 - s.len())..].copy_from_slice(s);
let sig = ed25519_dalek::Signature::from_bytes(&sig_bytes)?;
pk.verify(hashed, &sig)?;
Ok(())
}
_ => unsupported_err!("curve {:?} for EdDSA", curve.to_string()),
}
}
pub fn sign(
q: &[u8],
secret_key: &EdDSASecretKey,
_hash: HashAlgorithm,
digest: &[u8],
) -> Result<Vec<Vec<u8>>> {
ensure_eq!(q.len(), 33, "invalid Q (len)");
ensure_eq!(q[0], 0x40, "invalid Q (prefix)");
let mut kp_bytes = vec![0u8; 64];
kp_bytes[..32].copy_from_slice(&secret_key.secret);
kp_bytes[32..].copy_from_slice(&q[1..]);
let kp = ed25519_dalek::Keypair::from_bytes(&kp_bytes)?;
let signature = kp.sign(digest);
let bytes = signature.to_bytes();
let r = bytes[..32].to_vec();
let s = bytes[32..].to_vec();
Ok(vec![r, s])
}