Skip to main content

avalanche_types/key/bls/
mod.rs

1//! BLS key module.
2pub mod private_key;
3pub mod public_key;
4pub mod signature;
5
6use std::io::{self, Error, ErrorKind};
7
8use crate::codec::serde::hex_0x_bytes::Hex0xBytes;
9use serde::{Deserialize, Serialize};
10use serde_with::serde_as;
11
12/// ref. "avalanchego"/vms/platformvm/signer.ProofOfPossession"
13/// ref. <https://docs.avax.network/build/avalanchego-apis/info/#infogetnodeid>
14#[serde_as]
15#[derive(Debug, Serialize, Deserialize, Eq, PartialEq, Clone, Default)]
16pub struct ProofOfPossession {
17    #[serde(rename = "publicKey")]
18    #[serde_as(as = "Hex0xBytes")]
19    pub public_key: Vec<u8>,
20    #[serde(rename = "proofOfPossession")]
21    #[serde_as(as = "Hex0xBytes")]
22    pub proof_of_possession: Vec<u8>,
23
24    #[serde(skip)]
25    pub pubkey: Option<public_key::Key>,
26}
27
28impl ProofOfPossession {
29    pub fn new(public_key: &[u8], proof_of_possession: &[u8]) -> io::Result<Self> {
30        let pubkey = public_key::Key::from_bytes(public_key)?;
31        let sig = signature::Sig::from_bytes(proof_of_possession)?;
32
33        if !pubkey.verify_proof_of_possession(public_key, &sig) {
34            return Err(Error::new(
35                ErrorKind::Other,
36                "failed verify_proof_of_possession",
37            ));
38        }
39
40        Ok(Self {
41            public_key: public_key.to_vec(),
42            proof_of_possession: proof_of_possession.to_vec(),
43            pubkey: Some(pubkey),
44        })
45    }
46
47    /// ref. "avalanchego"/vms/platformvm/signer.ProofOfPossession.Verify"
48    pub fn verify(&self) -> io::Result<bool> {
49        let pubkey = public_key::Key::from_bytes(&self.public_key)?;
50        let pubkey_bytes = pubkey.to_compressed_bytes();
51
52        let sig = signature::Sig::from_bytes(&self.proof_of_possession)?;
53
54        Ok(pubkey.verify_proof_of_possession(&pubkey_bytes, &sig))
55    }
56
57    pub fn load_pubkey(&self) -> io::Result<public_key::Key> {
58        // ref. "avalanchego/vms/platformvm/signer.ProofOfPossession.UnmarshalJSON"
59        let pubkey = public_key::Key::from_bytes(&self.public_key)?;
60        Ok(pubkey)
61    }
62}
63
64/// RUST_LOG=debug cargo test --package avalanche-types --all-features --lib -- key::bls::test_proof_of_possession --exact --show-output
65#[test]
66fn test_proof_of_possession() {
67    let _ = env_logger::builder()
68        .filter_level(log::LevelFilter::Info)
69        .is_test(true)
70        .try_init();
71
72    let sk = private_key::Key::generate().unwrap();
73    let pubkey = sk.to_public_key();
74
75    let msg = random_manager::secure_bytes(50).unwrap();
76    let sig = sk.sign(&msg);
77    assert!(sig.verify(&msg, &pubkey));
78    assert!(!sig.verify_proof_of_possession(&msg, &pubkey));
79
80    let sig_pop = sk.sign_proof_of_possession(&msg);
81    assert!(!sig_pop.verify(&msg, &pubkey));
82    assert!(sig_pop.verify_proof_of_possession(&msg, &pubkey));
83
84    let b = sk.to_bytes();
85    let sk2 = private_key::Key::from_bytes(&b).unwrap();
86    assert_eq!(sk.to_bytes(), sk2.to_bytes());
87
88    let key_path = random_manager::tmp_path(10, None).unwrap();
89    let generated_key = private_key::Key::generate_to_file(&key_path).unwrap();
90    let loaded_key = private_key::Key::from_file(&key_path).unwrap();
91    assert_eq!(generated_key.to_bytes(), loaded_key.to_bytes());
92
93    let (loaded_key_2, generated) = private_key::Key::load_or_generate(&key_path).unwrap();
94    assert!(!generated);
95    assert_eq!(loaded_key.to_bytes(), loaded_key_2.to_bytes());
96
97    std::fs::remove_file(&key_path).unwrap();
98
99    let pop = sk.to_proof_of_possession();
100    log::info!(
101        "proof-of-possession: {}",
102        serde_json::to_string_pretty(&pop).unwrap()
103    );
104    assert!(pop.verify().unwrap());
105
106    let pop =
107        ProofOfPossession::new(&pubkey.to_compressed_bytes(), &pop.proof_of_possession).unwrap();
108    assert!(pop.verify().unwrap());
109    assert_eq!(pop.public_key, pubkey.to_compressed_bytes());
110    assert_eq!(
111        pop.pubkey.unwrap().to_compressed_bytes(),
112        pubkey.to_compressed_bytes()
113    );
114}