#[cfg(feature = "serialization")]
use serde::{Deserialize, Serialize};
use crate::digest;
use crate::ed25519;
use crate::p256;
#[derive(Debug, PartialEq)]
pub enum Error {
InvalidPoint,
UnknownAlgorithm,
NonceMissing,
HashAlgorithmMissing,
InvalidSignature,
KeyGenError,
}
#[derive(Debug, PartialEq, Clone, Copy)]
#[cfg_attr(feature = "serialization", derive(Serialize, Deserialize))]
pub enum Mode {
Ed25519,
P256,
}
#[cfg(feature = "random")]
pub fn key_gen(mode: Mode) -> Result<(Vec<u8>, Vec<u8>), Error> {
match mode {
Mode::Ed25519 => {
let sk = ed25519::key_gen();
let pk = ed25519::sk2pk(&sk);
Ok((sk.to_vec(), pk.to_vec()))
}
Mode::P256 => {
let sk = p256::key_gen().map_err(|_| Error::KeyGenError)?;
let pk = match p256::ecdh_base(&sk) {
Ok(k) => {
let mut pk = vec![0x04];
pk.extend_from_slice(&k);
pk
}
Err(_) => return Err(Error::InvalidPoint),
};
Ok((sk.to_vec(), pk))
}
}
}
pub fn sign<'a>(
mode: Mode,
hash: impl Into<Option<digest::Algorithm>>,
sk: &[u8],
msg: &[u8],
nonce: impl Into<Option<&'a p256::Nonce>>,
) -> Result<Vec<u8>, Error> {
match mode {
Mode::Ed25519 => {
let mut key = [0u8; 32];
key.clone_from_slice(sk);
Ok(ed25519::eddsa_sign(&key, msg).to_vec())
}
Mode::P256 => {
let nonce = match nonce.into() {
Some(n) => n,
None => return Err(Error::NonceMissing),
};
let hash = match hash.into() {
Some(h) => h,
None => return Err(Error::HashAlgorithmMissing),
};
let mut key = [0u8; 32];
key.clone_from_slice(sk);
match p256::ecdsa_sign(hash, msg, &key, nonce) {
Ok(r) => Ok(r.raw().to_vec()),
Err(_) => Err(Error::InvalidPoint),
}
}
}
}
pub fn verify(
mode: Mode,
hash: impl Into<Option<digest::Algorithm>>,
pk: &[u8],
signature: &[u8],
msg: &[u8],
) -> Result<bool, Error> {
match mode {
Mode::Ed25519 => {
if signature.len() != 64 {
return Err(Error::InvalidSignature);
}
if pk.len() != 32 {
return Err(Error::InvalidPoint);
}
let mut key = [0u8; 32];
key.clone_from_slice(pk);
let mut sig = [0u8; 64];
sig.clone_from_slice(signature);
Ok(ed25519::eddsa_verify(&key, &sig, msg))
}
Mode::P256 => {
let hash = match hash.into() {
Some(h) => h,
None => return Err(Error::HashAlgorithmMissing),
};
let sig = match p256::Signature::from_byte_slice(signature) {
Ok(s) => s,
Err(_) => return Err(Error::InvalidSignature),
};
match p256::ecdsa_verify(hash, msg, pk, &sig) {
Ok(r) => Ok(r),
Err(_) => Err(Error::InvalidPoint),
}
}
}
}