-
Notifications
You must be signed in to change notification settings - Fork 27
Expand file tree
/
Copy pathkey_manager.rs
More file actions
161 lines (145 loc) · 5.34 KB
/
Copy pathkey_manager.rs
File metadata and controls
161 lines (145 loc) · 5.34 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
use std::collections::HashMap;
use ethlambda_types::{
attestation::{AttestationData, XmssSignature},
primitives::{H256, HashTreeRoot as _},
signature::{ValidatorSecretKey, ValidatorSignature},
};
use tracing::info;
use crate::metrics;
/// Error types for KeyManager operations.
#[derive(Debug, thiserror::Error)]
pub enum KeyManagerError {
#[error("Validator key not found for validator_id: {0}")]
ValidatorKeyNotFound(u64),
#[error("Signing error: {0}")]
SigningError(String),
#[error("Signature conversion error: {0}")]
SignatureConversionError(String),
}
/// Manages validator secret keys for signing attestations.
///
/// The KeyManager stores a mapping of validator IDs to their secret keys
/// and provides methods to sign attestations on behalf of validators.
pub struct KeyManager {
keys: HashMap<u64, ValidatorSecretKey>,
}
impl KeyManager {
/// Creates a new KeyManager with the given mapping of validator IDs to secret keys.
///
/// # Arguments
///
/// * `keys` - A HashMap mapping validator IDs (u64) to their secret keys
///
/// # Example
///
/// ```ignore
/// let mut keys = HashMap::new();
/// keys.insert(0, ValidatorSecretKey::from_bytes(&key_bytes)?);
/// let key_manager = KeyManager::new(keys);
/// ```
pub fn new(keys: HashMap<u64, ValidatorSecretKey>) -> Self {
Self { keys }
}
/// Returns a list of all registered validator IDs.
///
/// The returned vector contains all validator IDs that have keys registered
/// in this KeyManager instance.
pub fn validator_ids(&self) -> Vec<u64> {
self.keys.keys().copied().collect()
}
/// Signs an attestation for the specified validator.
///
/// This method computes the message hash from the attestation data and signs it
/// using the validator's secret key.
///
/// # Arguments
///
/// * `validator_id` - The ID of the validator whose key should be used for signing
/// * `attestation_data` - The attestation data to sign
///
/// # Returns
///
/// Returns an `XmssSignature` (3112 bytes) on success, or a `KeyManagerError` if:
/// - The validator ID is not found in the KeyManager
/// - The signing operation fails
pub fn sign_attestation(
&mut self,
validator_id: u64,
attestation_data: &AttestationData,
) -> Result<XmssSignature, KeyManagerError> {
let message_hash = attestation_data.hash_tree_root();
let slot = attestation_data.slot as u32;
self.sign_message(validator_id, slot, &message_hash)
}
/// Signs a message hash for the specified validator.
///
/// # Arguments
///
/// * `validator_id` - The ID of the validator whose key should be used for signing
/// * `slot` - The slot number used in the XMSS signature scheme
/// * `message` - The message hash to sign
///
/// # Returns
///
/// Returns an `XmssSignature` (3112 bytes) on success, or a `KeyManagerError` if:
/// - The validator ID is not found in the KeyManager
/// - The signing operation fails
fn sign_message(
&mut self,
validator_id: u64,
slot: u32,
message: &H256,
) -> Result<XmssSignature, KeyManagerError> {
let secret_key = self
.keys
.get_mut(&validator_id)
.ok_or(KeyManagerError::ValidatorKeyNotFound(validator_id))?;
// Advance XMSS key preparation window if the slot is outside the current window.
// Each bottom tree covers 65,536 slots; the window holds 2 at a time.
if !secret_key.is_prepared_for(slot) {
info!(validator_id, slot, "Advancing XMSS key preparation window");
while !secret_key.is_prepared_for(slot) {
secret_key.advance_preparation();
if !secret_key.is_prepared_for(slot) {
return Err(KeyManagerError::SigningError(format!(
"XMSS key exhausted for validator {validator_id}: \
slot {slot} is beyond the key's activation interval"
)));
}
}
}
let signature: ValidatorSignature = {
let _timing = metrics::time_pq_sig_attestation_signing();
secret_key
.sign(slot, message)
.map_err(|e| KeyManagerError::SigningError(e.to_string()))
}?;
metrics::inc_pq_sig_attestation_signatures();
// Convert ValidatorSignature to XmssSignature (FixedVector<u8, SignatureSize>)
let sig_bytes = signature.to_bytes();
let xmss_sig = XmssSignature::try_from(sig_bytes)
.map_err(|e| KeyManagerError::SignatureConversionError(format!("{e:?}")))?;
Ok(xmss_sig)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_validator_ids() {
let keys = HashMap::new();
let key_manager = KeyManager::new(keys);
assert_eq!(key_manager.validator_ids().len(), 0);
}
#[test]
fn test_sign_attestation_validator_not_found() {
let keys = HashMap::new();
let mut key_manager = KeyManager::new(keys);
let message = H256::default();
let result = key_manager.sign_message(123, 0, &message);
assert!(matches!(
result,
Err(KeyManagerError::ValidatorKeyNotFound(123))
));
}
}