Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
aa5a4eb
feat: make empty block_kes_validator and add KesValidationError Type
golddydev Nov 7, 2025
7061589
Merge branch 'golddydev/vrf-validation' into golddydev/kes-validation
golddydev Nov 10, 2025
9590495
wip: add kes validation module
golddydev Nov 10, 2025
17e6b26
Merge branch 'golddydev/vrf-validation' into golddydev/kes-validation
golddydev Nov 10, 2025
19e960e
feat: add kes ocert validation
golddydev Nov 11, 2025
44e4562
Merge branch 'golddydev/vrf-validation' into golddydev/kes-validation
golddydev Nov 11, 2025
15d14bd
Merge branch 'golddydev/vrf-validation' into golddydev/kes-validation
golddydev Nov 11, 2025
1fb00b8
feat: add kes signature check function and test data
golddydev Nov 11, 2025
49896d0
Merge branch 'main' into golddydev/kes-validation
golddydev Nov 11, 2025
f69be53
feat: implement kes validation with genesis key's block test
golddydev Nov 12, 2025
80e851c
fix: cargo shear
golddydev Nov 12, 2025
bb8642f
refactor: update active spos on kes validator
golddydev Nov 12, 2025
890445c
fix: cargo fmt
golddydev Nov 12, 2025
007a358
refactor: add more test cases - both tpraos and praos blocks
golddydev Nov 12, 2025
7ddd2f0
feat: update ocert counters when block is validated successfully
golddydev Nov 12, 2025
4d1e300
fix: log kes validation with details
golddydev Nov 12, 2025
acc81ca
Merge branch 'main' into golddydev/kes-validation
golddydev Nov 13, 2025
3c6ee83
fix: add pool id to InvalidSignatureOcert error
golddydev Nov 16, 2025
46a107c
fix: move unnecessary functions to test section
golddydev Nov 16, 2025
17088d7
fix: remove mut for publisher
golddydev Nov 16, 2025
6a4c2a3
fix: cargo fmt
golddydev Nov 16, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion .cargo/audit.toml
Original file line number Diff line number Diff line change
@@ -1,3 +1,2 @@
[advisories]
ignore = []
informational_warnings = []
32 changes: 31 additions & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ members = [
"modules/chain_store", # Tracks historical information about blocks and TXs
"modules/tx_submitter", # Submits TXs to peers
"modules/block_vrf_validator", # Validate the VRF calculation in the block header
"modules/block_kes_validator", # Validate KES in the block header

# Process builds
"processes/omnibus", # All-inclusive omnibus process
Expand Down
107 changes: 105 additions & 2 deletions common/src/validation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@ pub enum ValidationError {
#[error("VRF failure: {0}")]
BadVRF(#[from] VrfValidationError),

#[error("KES failure")]
BadKES,
#[error("KES failure: {0}")]
BadKES(#[from] KesValidationError),

#[error("Doubly spent UTXO: {0}")]
DoubleSpendUTXO(String),
Expand Down Expand Up @@ -224,3 +224,106 @@ impl PartialEq for BadVrfProofError {
}
}
}

/// Reference
/// https://github.com/IntersectMBO/ouroboros-consensus/blob/e3c52b7c583bdb6708fac4fdaa8bf0b9588f5a88/ouroboros-consensus-protocol/src/ouroboros-consensus-protocol/Ouroboros/Consensus/Protocol/Praos.hs#L342
#[derive(Error, Clone, Debug, serde::Serialize, serde::Deserialize, PartialEq)]
pub enum KesValidationError {
/// **Cause:** The KES signature on the block header is invalid.
#[error("KES Signature Error: {0}")]
KesSignatureError(#[from] KesSignatureError),
/// **Cause:** The operational certificate is invalid.
#[error("Operational Certificate Error: {0}")]
OperationalCertificateError(#[from] OperationalCertificateError),
/// **Cause:** No OCert counter found for this issuer (not a stake pool or genesis delegate)
#[error("No OCert Counter For Issuer: Pool ID={}", hex::encode(pool_id))]
NoOCertCounter { pool_id: PoolId },
/// **Cause:** Some data has incorrect bytes
#[error("TryFromSlice: {0}")]
TryFromSlice(String),
#[error("Other Kes Validation Error: {0}")]
Other(String),
}

/// Validation function for Kes
pub type KesValidation<'a> = Box<dyn Fn() -> Result<(), KesValidationError> + Send + Sync + 'a>;

#[derive(Error, Clone, Debug, serde::Serialize, serde::Deserialize, PartialEq)]
pub enum KesSignatureError {
/// **Cause:** Current KES period is before the operational certificate's
/// start period.
#[error(
"KES Before Start OCert: OCert Start Period={}, Current Period={}",
ocert_start_period,
current_period
)]
KesBeforeStartOcert {
ocert_start_period: u64,
current_period: u64,
},
/// **Cause:** Current KES period exceeds the operational certificate's
/// validity period.
#[error(
"KES After End OCert: Current Period={}, OCert Start Period={}, Max KES Evolutions={}",
current_period,
ocert_start_period,
max_kes_evolutions
)]
KesAfterEndOcert {
current_period: u64,
ocert_start_period: u64,
max_kes_evolutions: u64,
},
/// **Cause:** The KES signature on the block header is cryptographically invalid.
#[error(
"Invalid KES Signature OCert: Current Period={}, OCert Start Period={}, Reason={}",
current_period,
ocert_start_period,
reason
)]
InvalidKesSignatureOcert {
current_period: u64,
ocert_start_period: u64,
reason: String,
},
}

#[derive(Error, Clone, Debug, serde::Serialize, serde::Deserialize, PartialEq)]
pub enum OperationalCertificateError {
/// **Cause:** The operational certificate is malformed.
#[error("Malformed Signature OCert: Reason={}", reason)]
MalformedSignatureOcert { reason: String },
/// **Cause:** The cold key signature on the operational certificate is invalid.
/// The OCert was not properly signed by the pool's cold key.
#[error(
"Invalid Signature OCert: Issuer={}, Pool ID={}",
hex::encode(issuer),
hex::encode(pool_id)
)]
InvalidSignatureOcert { issuer: Vec<u8>, pool_id: PoolId },
/// **Cause:** The operational certificate counter in the header is not greater
/// than the last counter used by this pool.
#[error(
"Counter Too Small OCert: Latest Counter={}, Declared Counter={}",
latest_counter,
declared_counter
)]
CounterTooSmallOcert {
latest_counter: u64,
declared_counter: u64,
},
/// **Cause:** OCert counter jumped by more than 1. While not strictly invalid,
/// this is suspicious and may indicate key compromise. (Praos Only)
#[error(
"Counter Over Incremented OCert: Latest Counter={}, Declared Counter={}",
latest_counter,
declared_counter
)]
CounterOverIncrementedOcert {
latest_counter: u64,
declared_counter: u64,
},
/// **Cause:** No counter found for this key hash (not a stake pool or genesis delegate)
#[error("No Counter For Key Hash OCert: Pool ID={}", hex::encode(pool_id))]
NoCounterForKeyHashOcert { pool_id: PoolId },
}
28 changes: 28 additions & 0 deletions modules/block_kes_validator/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# Acropolis Block KES Validator

[package]
name = "acropolis_module_block_kes_validator"
version = "0.1.0"
edition = "2021"
authors = ["Golddy <golddy@sundae.fi>"]
description = "Validate the KES in the block header"
license = "Apache-2.0"

[dependencies]
acropolis_common = { path = "../../common" }

caryatid_sdk = { workspace = true }

anyhow = { workspace = true }
config = { workspace = true }
hex = { workspace = true }
imbl = { workspace = true }
tokio = { workspace = true }
tracing = { workspace = true }
thiserror = "2.0.17"
pallas = { workspace = true }

kes-summed-ed25519 = { git = "https://github.com/txpipe/kes", rev = "f69fb357d46f6a18925543d785850059569d7e78" }

[lib]
path = "src/block_kes_validator.rs"
Loading