Skip to content

Commit a56d1b1

Browse files
authored
Merge pull request #61 from WithAutonomi/fix/dos-signature-validation-reorder
fix: validate ML-DSA-65 signatures before on-chain RPC queries
2 parents 445473d + 52e05d8 commit a56d1b1

1 file changed

Lines changed: 12 additions & 13 deletions

File tree

src/payment/verifier.rs

Lines changed: 12 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -484,6 +484,17 @@ impl PaymentVerifier {
484484

485485
let pool_hash = merkle_proof.winner_pool_hash();
486486

487+
// Run cheap local checks BEFORE expensive on-chain queries.
488+
// This prevents DoS via garbage proofs that trigger RPC lookups.
489+
for candidate in &merkle_proof.winner_pool.candidate_nodes {
490+
if !crate::payment::verify_merkle_candidate_signature(candidate) {
491+
return Err(Error::Payment(format!(
492+
"Invalid ML-DSA-65 signature on merkle candidate node (reward: {})",
493+
candidate.reward_address
494+
)));
495+
}
496+
}
497+
487498
// Check pool cache first
488499
let cached_info = {
489500
let mut pool_cache = self.pool_cache.lock();
@@ -534,20 +545,8 @@ impl PaymentVerifier {
534545
on_chain_info
535546
};
536547

537-
// pool_hash was derived from merkle_proof.winner_pool and used to query
538-
// the contract. The contract only returns data if a payment exists for that
539-
// hash. The ML-DSA signature check below ensures the pool contents are
540-
// authentic (nodes actually signed their candidate quotes).
541-
542-
// Verify ML-DSA-65 signatures and timestamp/data_type consistency
543-
// on all candidate nodes in the winner pool.
548+
// Verify timestamp consistency (signatures already checked above before RPC).
544549
for candidate in &merkle_proof.winner_pool.candidate_nodes {
545-
if !crate::payment::verify_merkle_candidate_signature(candidate) {
546-
return Err(Error::Payment(format!(
547-
"Invalid ML-DSA-65 signature on merkle candidate node (reward: {})",
548-
candidate.reward_address
549-
)));
550-
}
551550
if candidate.merkle_payment_timestamp != payment_info.merkle_payment_timestamp {
552551
return Err(Error::Payment(format!(
553552
"Candidate timestamp mismatch: expected {}, got {} (reward: {})",

0 commit comments

Comments
 (0)