Skip to content

Commit a8a36b4

Browse files
authored
Merge pull request #357 from input-output-hk/golddydev/kes-validation
feat: kes validation
2 parents 5210273 + 6a4c2a3 commit a8a36b4

File tree

20 files changed

+1281
-6
lines changed

20 files changed

+1281
-6
lines changed

.cargo/audit.toml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,2 @@
11
[advisories]
2-
ignore = []
32
informational_warnings = []

Cargo.lock

Lines changed: 31 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ members = [
2828
"modules/chain_store", # Tracks historical information about blocks and TXs
2929
"modules/tx_submitter", # Submits TXs to peers
3030
"modules/block_vrf_validator", # Validate the VRF calculation in the block header
31+
"modules/block_kes_validator", # Validate KES in the block header
3132

3233
# Process builds
3334
"processes/omnibus", # All-inclusive omnibus process

common/src/validation.rs

Lines changed: 105 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,8 @@ pub enum ValidationError {
1515
#[error("VRF failure: {0}")]
1616
BadVRF(#[from] VrfValidationError),
1717

18-
#[error("KES failure")]
19-
BadKES,
18+
#[error("KES failure: {0}")]
19+
BadKES(#[from] KesValidationError),
2020

2121
#[error("Doubly spent UTXO: {0}")]
2222
DoubleSpendUTXO(String),
@@ -224,3 +224,106 @@ impl PartialEq for BadVrfProofError {
224224
}
225225
}
226226
}
227+
228+
/// Reference
229+
/// https://github.com/IntersectMBO/ouroboros-consensus/blob/e3c52b7c583bdb6708fac4fdaa8bf0b9588f5a88/ouroboros-consensus-protocol/src/ouroboros-consensus-protocol/Ouroboros/Consensus/Protocol/Praos.hs#L342
230+
#[derive(Error, Clone, Debug, serde::Serialize, serde::Deserialize, PartialEq)]
231+
pub enum KesValidationError {
232+
/// **Cause:** The KES signature on the block header is invalid.
233+
#[error("KES Signature Error: {0}")]
234+
KesSignatureError(#[from] KesSignatureError),
235+
/// **Cause:** The operational certificate is invalid.
236+
#[error("Operational Certificate Error: {0}")]
237+
OperationalCertificateError(#[from] OperationalCertificateError),
238+
/// **Cause:** No OCert counter found for this issuer (not a stake pool or genesis delegate)
239+
#[error("No OCert Counter For Issuer: Pool ID={}", hex::encode(pool_id))]
240+
NoOCertCounter { pool_id: PoolId },
241+
/// **Cause:** Some data has incorrect bytes
242+
#[error("TryFromSlice: {0}")]
243+
TryFromSlice(String),
244+
#[error("Other Kes Validation Error: {0}")]
245+
Other(String),
246+
}
247+
248+
/// Validation function for Kes
249+
pub type KesValidation<'a> = Box<dyn Fn() -> Result<(), KesValidationError> + Send + Sync + 'a>;
250+
251+
#[derive(Error, Clone, Debug, serde::Serialize, serde::Deserialize, PartialEq)]
252+
pub enum KesSignatureError {
253+
/// **Cause:** Current KES period is before the operational certificate's
254+
/// start period.
255+
#[error(
256+
"KES Before Start OCert: OCert Start Period={}, Current Period={}",
257+
ocert_start_period,
258+
current_period
259+
)]
260+
KesBeforeStartOcert {
261+
ocert_start_period: u64,
262+
current_period: u64,
263+
},
264+
/// **Cause:** Current KES period exceeds the operational certificate's
265+
/// validity period.
266+
#[error(
267+
"KES After End OCert: Current Period={}, OCert Start Period={}, Max KES Evolutions={}",
268+
current_period,
269+
ocert_start_period,
270+
max_kes_evolutions
271+
)]
272+
KesAfterEndOcert {
273+
current_period: u64,
274+
ocert_start_period: u64,
275+
max_kes_evolutions: u64,
276+
},
277+
/// **Cause:** The KES signature on the block header is cryptographically invalid.
278+
#[error(
279+
"Invalid KES Signature OCert: Current Period={}, OCert Start Period={}, Reason={}",
280+
current_period,
281+
ocert_start_period,
282+
reason
283+
)]
284+
InvalidKesSignatureOcert {
285+
current_period: u64,
286+
ocert_start_period: u64,
287+
reason: String,
288+
},
289+
}
290+
291+
#[derive(Error, Clone, Debug, serde::Serialize, serde::Deserialize, PartialEq)]
292+
pub enum OperationalCertificateError {
293+
/// **Cause:** The operational certificate is malformed.
294+
#[error("Malformed Signature OCert: Reason={}", reason)]
295+
MalformedSignatureOcert { reason: String },
296+
/// **Cause:** The cold key signature on the operational certificate is invalid.
297+
/// The OCert was not properly signed by the pool's cold key.
298+
#[error(
299+
"Invalid Signature OCert: Issuer={}, Pool ID={}",
300+
hex::encode(issuer),
301+
hex::encode(pool_id)
302+
)]
303+
InvalidSignatureOcert { issuer: Vec<u8>, pool_id: PoolId },
304+
/// **Cause:** The operational certificate counter in the header is not greater
305+
/// than the last counter used by this pool.
306+
#[error(
307+
"Counter Too Small OCert: Latest Counter={}, Declared Counter={}",
308+
latest_counter,
309+
declared_counter
310+
)]
311+
CounterTooSmallOcert {
312+
latest_counter: u64,
313+
declared_counter: u64,
314+
},
315+
/// **Cause:** OCert counter jumped by more than 1. While not strictly invalid,
316+
/// this is suspicious and may indicate key compromise. (Praos Only)
317+
#[error(
318+
"Counter Over Incremented OCert: Latest Counter={}, Declared Counter={}",
319+
latest_counter,
320+
declared_counter
321+
)]
322+
CounterOverIncrementedOcert {
323+
latest_counter: u64,
324+
declared_counter: u64,
325+
},
326+
/// **Cause:** No counter found for this key hash (not a stake pool or genesis delegate)
327+
#[error("No Counter For Key Hash OCert: Pool ID={}", hex::encode(pool_id))]
328+
NoCounterForKeyHashOcert { pool_id: PoolId },
329+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
# Acropolis Block KES Validator
2+
3+
[package]
4+
name = "acropolis_module_block_kes_validator"
5+
version = "0.1.0"
6+
edition = "2021"
7+
authors = ["Golddy <[email protected]>"]
8+
description = "Validate the KES in the block header"
9+
license = "Apache-2.0"
10+
11+
[dependencies]
12+
acropolis_common = { path = "../../common" }
13+
14+
caryatid_sdk = { workspace = true }
15+
16+
anyhow = { workspace = true }
17+
config = { workspace = true }
18+
hex = { workspace = true }
19+
imbl = { workspace = true }
20+
tokio = { workspace = true }
21+
tracing = { workspace = true }
22+
thiserror = "2.0.17"
23+
pallas = { workspace = true }
24+
25+
kes-summed-ed25519 = { git = "https://github.com/txpipe/kes", rev = "f69fb357d46f6a18925543d785850059569d7e78" }
26+
27+
[lib]
28+
path = "src/block_kes_validator.rs"

0 commit comments

Comments
 (0)