dig_keystore/scheme/
bls_signing.rs1use chia_bls::{PublicKey, SecretKey, Signature};
11use rand_core::{CryptoRng, RngCore};
12use zeroize::Zeroizing;
13
14use crate::error::{KeystoreError, Result};
15use crate::scheme::KeyScheme;
16
17#[derive(Debug, Clone, Copy)]
21pub struct BlsSigning;
22
23impl KeyScheme for BlsSigning {
24 type PublicKey = PublicKey;
25 type Signature = Signature;
26
27 const MAGIC: [u8; 6] = *b"DIGVK1";
28 const NAME: &'static str = "BlsSigning";
29 const SCHEME_ID: u16 = 0x0001;
30 const SECRET_LEN: usize = 32;
31
32 fn generate<R: RngCore + CryptoRng>(rng: &mut R) -> Zeroizing<Vec<u8>> {
33 let mut seed = Zeroizing::new(vec![0u8; Self::SECRET_LEN]);
34 rng.fill_bytes(&mut seed);
35 seed
36 }
37
38 fn public_key(secret: &[u8]) -> Result<Self::PublicKey> {
39 let sk = secret_to_bls_secret_key(secret)?;
40 let pk = sk.public_key();
41 Ok(pk)
42 }
43
44 fn sign(secret: &[u8], msg: &[u8]) -> Result<Self::Signature> {
45 let sk = secret_to_bls_secret_key(secret)?;
46 Ok(chia_bls::sign(&sk, msg))
47 }
48}
49
50pub(crate) fn secret_to_bls_secret_key(secret: &[u8]) -> Result<SecretKey> {
52 if secret.len() != BlsSigning::SECRET_LEN {
53 return Err(KeystoreError::InvalidPlaintext {
54 expected: BlsSigning::SECRET_LEN,
55 got: secret.len(),
56 });
57 }
58 Ok(SecretKey::from_seed(secret))
61}
62
63#[cfg(test)]
64mod tests {
65 use super::*;
66 use rand_chacha::rand_core::SeedableRng;
67
68 #[test]
69 fn generate_is_32_bytes() {
70 let mut rng = rand_chacha::ChaCha20Rng::seed_from_u64(42);
71 let seed = BlsSigning::generate(&mut rng);
72 assert_eq!(seed.len(), 32);
73 }
74
75 #[test]
76 fn public_key_deterministic() {
77 let seed = [7u8; 32];
78 let pk1 = BlsSigning::public_key(&seed).unwrap();
79 let pk2 = BlsSigning::public_key(&seed).unwrap();
80 assert_eq!(pk1.to_bytes(), pk2.to_bytes());
81 }
82
83 #[test]
84 fn sign_verifies_via_chia_bls() {
85 let seed = [11u8; 32];
86 let pk = BlsSigning::public_key(&seed).unwrap();
87 let msg = b"hello";
88 let sig = BlsSigning::sign(&seed, msg).unwrap();
89 assert!(chia_bls::verify(&sig, &pk, msg));
90 }
91
92 #[test]
93 fn sign_different_messages_produce_different_signatures() {
94 let seed = [11u8; 32];
95 let s1 = BlsSigning::sign(&seed, b"msg1").unwrap();
96 let s2 = BlsSigning::sign(&seed, b"msg2").unwrap();
97 assert_ne!(s1.to_bytes(), s2.to_bytes());
98 }
99
100 #[test]
101 fn different_seeds_produce_different_keys() {
102 let pk1 = BlsSigning::public_key(&[1u8; 32]).unwrap();
103 let pk2 = BlsSigning::public_key(&[2u8; 32]).unwrap();
104 assert_ne!(pk1.to_bytes(), pk2.to_bytes());
105 }
106
107 #[test]
108 fn wrong_seed_length_errors() {
109 let err = BlsSigning::public_key(&[0u8; 16]).unwrap_err();
110 assert!(matches!(
111 err,
112 KeystoreError::InvalidPlaintext {
113 expected: 32,
114 got: 16
115 }
116 ));
117 }
118}