did-key 0.1.0

Implementation of the did:key method
Documentation
use bls12_381_plus::Scalar;
use hkdf::HkdfExtract;
use signature_bls::{PublicKey, PublicKeyVt, SecretKey, Signature};

use crate::{
    didcore::{Config, KeyFormat, JWK},
    generate_seed,
    traits::{CoreSign, DIDCore, Fingerprint, Generate, ECDH},
    Document, Error, KeyMaterial, KeyPair, VerificationMethod,
};

pub struct Bls12381KeyPairs {
    pk_g1: PublicKeyVt,
    pk_g2: PublicKey,
    secret_key: Option<SecretKey>,
}

impl Bls12381KeyPairs {
    fn get_fingerprint_g1(&self) -> String {
        let codec: &[u8] = &[0xea, 0x1];
        let data = [codec, &self.pk_g1.to_bytes()[..]].concat().to_vec();
        format!("z{}", bs58::encode(data).into_string())
    }

    fn get_fingerprint_g2(&self) -> String {
        let codec: &[u8] = &[0xeb, 0x1];
        let data = [codec, &self.pk_g2.to_bytes()[..]].concat().to_vec();
        format!("z{}", bs58::encode(data).into_string())
    }
}

impl CoreSign for Bls12381KeyPairs {
    fn sign(&self, payload: &[u8]) -> Vec<u8> {
        Signature::new(&self.secret_key.as_ref().unwrap(), payload)
            .expect("secret key not present")
            .to_bytes()
            .to_vec()
    }

    fn verify(&self, payload: &[u8], signature: &[u8]) -> Result<(), Error> {
        if signature.len() != Signature::BYTES {
            return Err(Error::SignatureError);
        }

        let mut sig = [0u8; Signature::BYTES];
        sig.copy_from_slice(signature);

        match Signature::from_bytes(&sig).unwrap().verify(self.pk_g2, payload).unwrap_u8() {
            1 => Ok(()),
            _ => Err(Error::SignatureError),
        }
    }
}

impl Generate for Bls12381KeyPairs {
    fn new() -> Bls12381KeyPairs {
        generate_keypair(None)
    }

    fn new_with_seed(seed: &[u8]) -> Bls12381KeyPairs {
        generate_keypair(Some(seed.into()))
    }

    fn from_public_key(_public_key: &[u8]) -> Bls12381KeyPairs {
        let mut pk_g1 = [0u8; PublicKeyVt::BYTES];
        pk_g1.copy_from_slice(&_public_key[..PublicKeyVt::BYTES]);

        let mut pk_g2 = [0u8; PublicKey::BYTES];
        pk_g2.copy_from_slice(&_public_key[PublicKeyVt::BYTES..]);

        Bls12381KeyPairs {
            pk_g1: PublicKeyVt::from_bytes(&pk_g1).unwrap(),
            pk_g2: PublicKey::from_bytes(&pk_g2).unwrap(),
            secret_key: None,
        }
    }

    fn from_secret_key(secret_key_bytes: &[u8]) -> Bls12381KeyPairs {
        let mut bytes: [u8; 32] = [0; 32];
        bytes.copy_from_slice(secret_key_bytes);

        let sk = SecretKey::from_bytes(&bytes).unwrap();
        let pk_g1 = PublicKeyVt::from(&sk);
        let pk_g2 = PublicKey::from(&sk);

        Bls12381KeyPairs {
            pk_g1: pk_g1,
            pk_g2: pk_g2,
            secret_key: Some(sk),
        }
    }
}
impl KeyMaterial for Bls12381KeyPairs {
    fn public_key_bytes(&self) -> Vec<u8> {
        [self.pk_g1.to_bytes().to_vec(), self.pk_g2.to_bytes().to_vec()].concat().to_vec()
    }

    fn private_key_bytes(&self) -> Vec<u8> {
        self.secret_key.as_ref().unwrap().to_bytes().to_vec()
    }
}

impl DIDCore for Bls12381KeyPairs {
    fn get_verification_methods(&self, config: Config, controller: &str) -> Vec<VerificationMethod> {
        vec![
            VerificationMethod {
                id: format!("{}#{}", controller, self.get_fingerprint_g1()),
                key_type: match config.use_jose_format {
                    false => "Bls12381G1Key2020".into(),
                    true => "JsonWebKey2020".into(),
                },
                controller: controller.to_string(),
                public_key: Some(match config.use_jose_format {
                    false => KeyFormat::Base58(bs58::encode(self.pk_g1.to_bytes()).into_string()),
                    true => KeyFormat::JWK(JWK {
                        key_type: "EC".into(),
                        curve: "BLS12381_G1".into(),
                        x: Some(base64::encode_config(self.pk_g1.to_bytes(), base64::URL_SAFE_NO_PAD)),
                        ..Default::default()
                    }),
                }),
                private_key: self.secret_key.as_ref().map(|_| match config.use_jose_format {
                    false => KeyFormat::Base58(bs58::encode(self.pk_g1.to_bytes()).into_string()),
                    true => KeyFormat::JWK(JWK {
                        key_type: "EC".into(),
                        curve: "BLS12381_G1".into(),
                        x: Some(base64::encode_config(self.pk_g1.to_bytes(), base64::URL_SAFE_NO_PAD)),
                        d: Some(base64::encode_config(self.private_key_bytes(), base64::URL_SAFE_NO_PAD)),
                        ..Default::default()
                    }),
                }),
                ..Default::default()
            },
            VerificationMethod {
                id: format!("{}#{}", controller, self.get_fingerprint_g2()),
                key_type: match config.use_jose_format {
                    false => "Bls12381G2Key2020".into(),
                    true => "JsonWebKey2020".into(),
                },
                controller: controller.to_string(),
                public_key: Some(match config.use_jose_format {
                    false => KeyFormat::Base58(bs58::encode(self.pk_g2.to_bytes()).into_string()),
                    true => KeyFormat::JWK(JWK {
                        key_type: "EC".into(),
                        curve: "BLS12381_G2".into(),
                        x: Some(base64::encode_config(self.pk_g2.to_bytes(), base64::URL_SAFE_NO_PAD)),
                        ..Default::default()
                    }),
                }),
                private_key: self.secret_key.as_ref().map(|_| match config.use_jose_format {
                    false => KeyFormat::Base58(bs58::encode(self.private_key_bytes()).into_string()),
                    true => KeyFormat::JWK(JWK {
                        key_type: "EC".into(),
                        curve: "BLS12381_G2".into(),
                        x: Some(base64::encode_config(self.pk_g2.to_bytes(), base64::URL_SAFE_NO_PAD)),
                        d: Some(base64::encode_config(self.private_key_bytes(), base64::URL_SAFE_NO_PAD)),
                        ..Default::default()
                    }),
                }),
                ..Default::default()
            },
        ]
    }

    fn get_did_document(&self, config: Config) -> crate::Document {
        let fingerprint = self.fingerprint();
        let controller = format!("did:key:{}", fingerprint.clone());

        let vm = &self.get_verification_methods(config, &controller);
        let vm_ids: Vec<String> = vm.iter().map(|x| x.id.to_string()).collect();

        Document {
            context: "https://www.w3.org/ns/did/v1".to_string(),
            id: controller.to_string(),
            key_agreement: None,
            authentication: Some(vm_ids.clone()),
            assertion_method: Some(vm_ids.clone()),
            capability_delegation: Some(vm_ids.clone()),
            capability_invocation: Some(vm_ids.clone()),
            verification_method: vm.clone(),
        }
    }
}

impl Fingerprint for Bls12381KeyPairs {
    fn fingerprint(&self) -> String {
        let codec: &[u8] = &[0xee, 0x1];
        let data = [codec, &self.pk_g1.to_bytes()[..], &self.pk_g2.to_bytes()[..]].concat().to_vec();
        format!("z{}", bs58::encode(data).into_string())
    }
}

impl ECDH for Bls12381KeyPairs {
    fn key_exchange(&self, _: &Self) -> Vec<u8> {
        unimplemented!("ECDH is not supported for this key type")
    }
}

impl From<Bls12381KeyPairs> for KeyPair {
    fn from(key_pair: Bls12381KeyPairs) -> Self {
        KeyPair::Bls12381G1G2(key_pair)
    }
}

fn generate_keypair(seed: Option<Vec<u8>>) -> Bls12381KeyPairs {
    let seed_data = generate_seed(seed.map_or(vec![], |x| x).as_slice()).unwrap();
    let sk = gen_sk(seed_data.to_vec().as_slice()).unwrap();

    let pk_g1 = PublicKeyVt::from(&sk);
    let pk_g2 = PublicKey::from(&sk);

    Bls12381KeyPairs {
        pk_g1: pk_g1,
        pk_g2: pk_g2,
        secret_key: Some(sk),
    }
}

fn gen_sk(ikm: &[u8]) -> Option<SecretKey> {
    const SALT: &'static [u8] = b"BLS-SIG-KEYGEN-SALT-";
    const INFO: [u8; 2] = [0u8, 48u8];

    let mut extracter = HkdfExtract::<sha2::Sha256>::new(Some(SALT));
    extracter.input_ikm(ikm);
    extracter.input_ikm(&[0u8]);
    let (_, h) = extracter.finalize();

    let mut output = [0u8; 48];
    if let Err(_) = h.expand(&INFO, &mut output) {
        None
    } else {
        let mut bytes = Scalar::from_okm(&output).to_bytes();
        bytes.reverse();
        Some(SecretKey::from_bytes(&bytes).unwrap())
    }
}

#[cfg(test)]
pub mod test {
    use super::*;
    use crate::CONFIG_LD_PRIVATE;

    #[test]
    fn test_signature() {
        let keypair = generate_keypair(None);
        let payload = b"secret message".to_vec();

        let signature = keypair.sign(&payload);

        assert_eq!(signature.len(), Signature::BYTES);
    }

    #[test]
    fn test_public_key() {
        let keypair = generate_keypair(None);

        let from = Bls12381KeyPairs::from_public_key(&keypair.public_key_bytes());

        assert!(from.pk_g1.eq(&keypair.pk_g1));
        assert!(from.pk_g2.eq(&keypair.pk_g2));
    }

    #[test]
    fn test_signature_and_verify() {
        let keypair = generate_keypair(None);
        let payload = b"secret message".to_vec();

        let signature = keypair.sign(&payload.clone());

        let verify_result = keypair.verify(&payload.clone(), signature.as_slice());

        assert!(matches!(verify_result, Ok(_)));
    }

    #[test]
    fn test_signature_and_verify_fails_invalid_signature() {
        let keypair = generate_keypair(None);
        let payload = b"secret message".to_vec();
        let invalid_payload = b"incorrect secret message".to_vec();

        let signature = keypair.sign(&payload.clone());

        let verify_result = keypair.verify(&invalid_payload.clone(), signature.as_slice());

        assert!(matches!(verify_result, Err(_)));
    }

    #[test]
    fn test_signature_and_verify_fails_signature_parse() {
        let keypair = generate_keypair(None);
        let payload = b"secret message".to_vec();

        let signature = keypair.sign(&payload.clone());

        let verify_result = keypair.verify(&payload.clone(), signature[1..].as_ref());

        assert!(matches!(verify_result, Err(_)));
    }

    #[test]
    fn test_generate_public_key() {
        let key = Bls12381KeyPairs::new_with_seed(vec![].as_slice());
        let pk = key.public_key_bytes();

        assert_eq!(PublicKeyVt::BYTES + PublicKey::BYTES, pk.len());
    }

    #[test]
    fn test_generate_public_key_from_bytes() {
        let key = Bls12381KeyPairs::new_with_seed(vec![].as_slice());
        let pk = key.public_key_bytes();

        let actual = Bls12381KeyPairs::from_public_key(&pk);
        let pk1 = actual.public_key_bytes();

        assert_eq!(pk, pk1);
    }

    #[test]
    fn test_resolve() {
        let key = Bls12381KeyPairs::new();
        let doc = key.get_did_document(CONFIG_LD_PRIVATE);
        let g2 = doc.authentication.unwrap()[1].clone();

        let resolved = crate::resolve(g2.as_str());

        let doc2 = resolved.unwrap().get_did_document(CONFIG_LD_PRIVATE);

        assert_eq!(doc.id, doc2.id)
    }

    #[test]
    fn secret_key_size() {
        let key = Bls12381KeyPairs::new();
        let sk_bytes = key.private_key_bytes();

        assert_eq!(sk_bytes.len(), 32);
        let key = Bls12381KeyPairs::from_secret_key(&sk_bytes);
        assert_eq!(key.private_key_bytes().len(), 32)
    }
}