use base64::decode_config;
use serde::{de::Deserializer, Deserialize, Serialize, Serializer};
use crate::identifier;
use identifier::error::Error;
use super::{create_seed, BaseKeyPair, KeyGenerator, KeyMaterial, KeyPair, Payload, DHKE, DSA};
use libsecp256k1::{Message, PublicKey, SecretKey, Signature};
use sha2::{Digest, Sha256};
pub type Secp256k1KeyPair = BaseKeyPair<PublicKey, SecretKey>;
pub const SECRET_KEY_LENGTH: usize = 32;
pub const KEYPAIR_LENGTH: usize = 97;
impl KeyGenerator for Secp256k1KeyPair {
fn from_seed(seed: &[u8]) -> Self {
let secret_seed = create_seed(seed).expect("invalid seed");
let sk = SecretKey::parse(&secret_seed).expect("Couldn't create key");
let pk = PublicKey::from_secret_key(&sk);
Secp256k1KeyPair {
public_key: pk,
secret_key: Some(sk),
}
}
fn from_public_key(pk: &[u8]) -> Self {
let pk = PublicKey::parse_slice(pk, None).expect("Could not parse public key");
Secp256k1KeyPair {
secret_key: None,
public_key: pk,
}
}
fn from_secret_key(secret_key: &[u8]) -> Self {
let sk = SecretKey::parse_slice(secret_key).unwrap();
let pk = PublicKey::from_secret_key(&sk);
Secp256k1KeyPair {
public_key: pk,
secret_key: Some(sk),
}
}
}
impl KeyMaterial for Secp256k1KeyPair {
fn public_key_bytes(&self) -> Vec<u8> {
self.public_key.serialize().to_vec()
}
fn secret_key_bytes(&self) -> Vec<u8> {
self.secret_key
.as_ref()
.map_or(vec![], |x| x.serialize().to_vec())
}
fn to_bytes(&self) -> Vec<u8> {
let mut bytes: [u8; KEYPAIR_LENGTH] = [0u8; KEYPAIR_LENGTH];
bytes[..SECRET_KEY_LENGTH].copy_from_slice(&self.secret_key_bytes());
bytes[SECRET_KEY_LENGTH..].copy_from_slice(&self.public_key_bytes());
bytes.to_vec()
}
}
impl DSA for Secp256k1KeyPair {
fn sign(&self, payload: Payload) -> Result<Vec<u8>, Error> {
match payload {
Payload::Buffer(payload) => {
let signature = match &self.secret_key {
Some(sig) => {
let message = Message::parse(&get_hash(&payload));
libsecp256k1::sign(&message, sig).0
}
None => panic!("secret key not found"),
};
let signature = signature.serialize();
Ok(signature.as_ref().to_vec())
}
_ => Err(Error::SignError(
"Payload type not supported for this key".into(),
)),
}
}
fn verify(&self, payload: Payload, signature: &[u8]) -> Result<(), Error> {
let verified = match payload {
Payload::Buffer(payload) => {
let message = Message::parse(&get_hash(&payload));
let signature =
Signature::parse_standard_slice(signature).expect("Couldn't parse signature");
libsecp256k1::verify(&message, &signature, &self.public_key)
}
_ => unimplemented!("payload type not supported for this key"),
};
if verified {
Ok(())
} else {
Err(Error::SignError("Signature verify failed".into()))
}
}
}
impl DHKE for Secp256k1KeyPair {
fn key_exchange(&self, _: &Self) -> Result<Vec<u8>, Error> {
unimplemented!("ECDH is not supported for this key type")
}
}
impl Serialize for Secp256k1KeyPair {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
serializer.serialize_str(&self.to_str())
}
}
impl<'de> Deserialize<'de> for Secp256k1KeyPair {
fn deserialize<D>(deserializer: D) -> Result<Secp256k1KeyPair, D::Error>
where
D: Deserializer<'de>,
{
let s = String::deserialize(deserializer)?;
let bytes = decode_config(&s, base64::URL_SAFE).map_err(serde::de::Error::custom)?;
Ok(Secp256k1KeyPair::from_secret_key(
&bytes[..SECRET_KEY_LENGTH],
))
}
}
fn get_hash(payload: &[u8]) -> [u8; 32] {
let hash = Sha256::digest(&payload);
let mut output = [0u8; 32];
output.copy_from_slice(&hash[..32]);
output
}
impl From<Secp256k1KeyPair> for KeyPair {
fn from(key_pair: Secp256k1KeyPair) -> Self {
KeyPair::Secp256k1(key_pair)
}
}
#[cfg(test)]
mod tests {
use super::Secp256k1KeyPair;
use crate::commons::crypto::{KeyGenerator, Payload, DSA};
#[test]
fn test_ser_des() {
let msg = b"message";
let kp = Secp256k1KeyPair::new();
let signature = kp.sign(Payload::Buffer(msg.to_vec())).unwrap();
let kp_str = serde_json::to_string_pretty(&kp).unwrap();
let new_kp: Result<Secp256k1KeyPair, serde_json::Error> = serde_json::from_str(&kp_str);
assert!(new_kp.is_ok());
let result = new_kp
.unwrap()
.verify(Payload::Buffer(msg.to_vec()), &signature);
assert!(result.is_ok());
}
}