Skip to content

Commit 0a02a35

Browse files
committed
fix: reject unchallenged response chunks
1 parent c0520b0 commit 0a02a35

File tree

3 files changed

+73
-19
lines changed

3 files changed

+73
-19
lines changed

crates/cac/protocol/src/evaluator/stf.rs

Lines changed: 25 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ use mosaic_cac_types::{
66
ChallengeResponseMsgChunk, ChallengeResponseMsgHeader, CommitMsgChunk, CommitMsgHeader,
77
CompletedSignatures, DepositAdaptors, DepositId, GarblingTableCommitment, HeapArray, Index,
88
OpenedGarblingTableCommitments, PubKey, ReservedSetupInputShares, Seed, SetupInputs,
9-
TableTransferReceiptMsg, TableTransferRequestMsg, WideLabelWirePolynomialCommitments,
9+
TableTransferReceiptMsg, WideLabelWirePolynomialCommitments,
1010
WideLabelZerothPolynomialCoefficients, WithdrawalAdaptors, WithdrawalAdaptorsChunk,
1111
WithdrawalInputs, state_machine::evaluator::*,
1212
};
@@ -582,7 +582,7 @@ async fn handle_commit_msg_header<S: StateMut>(
582582
match &mut state.step {
583583
Step::WaitingForCommit { header, chunks, .. } => {
584584
if *header {
585-
warn!("evaluator received duplicate commit header, ack and ignore");
585+
debug!("evaluator received duplicate commit header, ack and ignore");
586586
return Ok(());
587587
}
588588

@@ -637,7 +637,7 @@ async fn handle_commit_msg_header<S: StateMut>(
637637
post_handle_commit_msg(state, artifact_store, actions).await
638638
}
639639
step if step.phase() > StepPhase::WaitingForCommit => {
640-
warn!("evaluator received commit header after completion, ack and ignore");
640+
debug!("evaluator received commit header after completion, ack and ignore");
641641
Ok(())
642642
}
643643
_ => Err(SMError::UnexpectedInput),
@@ -659,7 +659,7 @@ async fn handle_commit_msg_chunk<S: StateMut>(
659659
}
660660
Some(true) => {
661661
// already seen chunk
662-
warn!(%chunk_idx, "evaluator received duplicate commit chunk, ack and ignore");
662+
debug!(%chunk_idx, "evaluator received duplicate commit chunk, ack and ignore");
663663
return Ok(());
664664
}
665665
None => {
@@ -699,7 +699,7 @@ async fn handle_commit_msg_chunk<S: StateMut>(
699699
post_handle_commit_msg(root_state, state, actions).await
700700
}
701701
step if step.phase() > StepPhase::WaitingForCommit => {
702-
warn!("evaluator received commit chunk after completion, ack and ignore");
702+
debug!("evaluator received commit chunk after completion, ack and ignore");
703703
Ok(())
704704
}
705705
_ => Err(SMError::UnexpectedInput),
@@ -744,7 +744,7 @@ async fn handle_recv_challenge_response_header<S: StateMut>(
744744
remaining_chunks,
745745
} => {
746746
if *header {
747-
warn!("evaluator received duplicate challenge response header, ack and ignore");
747+
debug!("evaluator received duplicate challenge response header, ack and ignore");
748748
return Ok(());
749749
}
750750

@@ -789,7 +789,7 @@ async fn handle_recv_challenge_response_header<S: StateMut>(
789789
post_handle_challenge_response(root_state, state, actions).await
790790
}
791791
step if step.phase() > StepPhase::WaitingForChallengeResponse => {
792-
warn!("evaluator received challenge response header after completion, ack and ignore");
792+
debug!("evaluator received challenge response header after completion, ack and ignore");
793793
Ok(())
794794
}
795795
_ => Err(SMError::UnexpectedInput),
@@ -807,6 +807,18 @@ async fn handle_recv_challenge_response_msg<S: StateMut>(
807807
header,
808808
remaining_chunks,
809809
} => {
810+
let challenge_idxs = state
811+
.get_challenge_indices()
812+
.await
813+
.require("expected challenge indices")?;
814+
815+
if !challenge_idxs
816+
.iter()
817+
.any(|idx| idx.get() == response_msg_chunk.circuit_index as usize)
818+
{
819+
return Err(SMError::InvalidInputData);
820+
}
821+
810822
let chunk_idx = (response_msg_chunk.circuit_index as usize)
811823
.checked_sub(1)
812824
.unwrap();
@@ -815,8 +827,11 @@ async fn handle_recv_challenge_response_msg<S: StateMut>(
815827
// expected chunk
816828
}
817829
Some(false) => {
818-
// already seen chunk
819-
warn!(%chunk_idx, "evaluator received duplicate commit chunk, ack and ignore");
830+
// already seen expected chunk
831+
debug!(
832+
%chunk_idx,
833+
"evaluator received duplicate challenge response chunk, ack and ignore"
834+
);
820835
return Ok(());
821836
}
822837
None => {
@@ -847,7 +862,7 @@ async fn handle_recv_challenge_response_msg<S: StateMut>(
847862
post_handle_challenge_response(root_state, state, actions).await
848863
}
849864
step if step.phase() > StepPhase::WaitingForChallengeResponse => {
850-
warn!("evaluator received challenge response chunk after completion, ack and ignore");
865+
debug!("evaluator received challenge response chunk after completion, ack and ignore");
851866
Ok(())
852867
}
853868
_ => Err(SMError::UnexpectedInput),

crates/cac/protocol/src/evaluator/tests.rs

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -396,6 +396,10 @@ async fn duplicate_challenge_response_chunk_is_ack_and_ignore() {
396396
// Mark first challenge index's chunk as already received.
397397
let first_challenge_idx = challenge_indices[0].get() - 1;
398398
remaining[first_challenge_idx] = false;
399+
state
400+
.put_challenge_indices(&challenge_indices)
401+
.await
402+
.unwrap();
399403
state
400404
.put_root_state(&EvaluatorState {
401405
config: None,
@@ -422,6 +426,41 @@ async fn duplicate_challenge_response_chunk_is_ack_and_ignore() {
422426
assert!(actions.is_empty(), "should produce no actions");
423427
}
424428

429+
#[tokio::test]
430+
async fn unchallenged_in_range_challenge_response_chunk_is_invalid() {
431+
let mut state = StoredEvaluatorState::default();
432+
let challenge_indices = ChallengeIndices::new(|i| Index::new((i * 2) + 1).unwrap());
433+
let remaining = get_remaining_challenge_response_chunks(&challenge_indices);
434+
state
435+
.put_challenge_indices(&challenge_indices)
436+
.await
437+
.unwrap();
438+
state
439+
.put_root_state(&EvaluatorState {
440+
config: None,
441+
step: Step::WaitingForChallengeResponse {
442+
header: false,
443+
remaining_chunks: remaining,
444+
},
445+
})
446+
.await
447+
.unwrap();
448+
449+
let mut actions = Vec::new();
450+
let result = handle_event(
451+
&mut state,
452+
Input::RecvChallengeResponseMsgChunk(dummy_challenge_response_chunk(2)),
453+
&mut actions,
454+
)
455+
.await;
456+
457+
assert!(
458+
matches!(result, Err(crate::error::SMError::InvalidInputData)),
459+
"unchallenged in-range chunk must be rejected, got: {result:?}"
460+
);
461+
assert!(actions.is_empty(), "should produce no actions");
462+
}
463+
425464
#[tokio::test]
426465
async fn challenge_response_chunk_after_verifying_is_ack_and_ignore() {
427466
let mut state = StoredEvaluatorState::default();

crates/cac/protocol/src/garbler/stf.rs

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -143,7 +143,7 @@ pub(crate) async fn handle_event<S: StateMut>(
143143
}
144144
// ack on all steps after WaitingForChallenge
145145
step if step.phase() > StepPhase::WaitingForChallenge => {
146-
warn!("garbler received challenge after completion, ack and ignore");
146+
debug!("garbler received challenge after completion, ack and ignore");
147147
return Ok(());
148148
}
149149
_ => return Err(SMError::unexpected_input()),
@@ -175,7 +175,7 @@ pub(crate) async fn handle_event<S: StateMut>(
175175
emit(actions, Action::TransferGarblingTable(*seed));
176176
}
177177
step if step.phase() > StepPhase::TransferringGarblingTables => {
178-
warn!("garbler received table transfer request after completion, ack and ignore");
178+
debug!("garbler received table transfer request after completion, ack and ignore");
179179
return Ok(());
180180
}
181181
_ => return Err(SMError::unexpected_input()),
@@ -212,7 +212,7 @@ pub(crate) async fn handle_event<S: StateMut>(
212212
}
213213
}
214214
step if step.phase() > StepPhase::TransferringGarblingTables => {
215-
warn!("garbler received table transfer receipt after completion, ack and ignore");
215+
debug!("garbler received table transfer receipt after completion, ack and ignore");
216216
return Ok(());
217217
}
218218
_ => return Err(SMError::unexpected_input()),
@@ -400,7 +400,7 @@ pub(crate) async fn handle_action_result<S: StateMut>(
400400
}
401401
}
402402
step if step.phase() > StepPhase::SendingCommit => {
403-
warn!("garbler received commit header ack after completion, ignore");
403+
debug!("garbler received commit header ack after completion, ignore");
404404
}
405405
_ => return Err(SMError::unexpected_input()),
406406
}
@@ -434,7 +434,7 @@ pub(crate) async fn handle_action_result<S: StateMut>(
434434
}
435435
}
436436
step if step.phase() > StepPhase::SendingCommit => {
437-
warn!("garbler received commit chunk ack after completion, ignore");
437+
debug!("garbler received commit chunk ack after completion, ignore");
438438
}
439439
_ => return Err(SMError::unexpected_input()),
440440
}
@@ -525,7 +525,7 @@ pub(crate) async fn handle_action_result<S: StateMut>(
525525
// Informational only. We mark a table as transferred once we get corresponding
526526
// [`TableTransferReceiptMsg`](mosaic_cac_types::TableTransferReceiptMsg) from
527527
// evaluator.
528-
info!(%commitment, "garbling table transferred")
528+
debug!(%commitment, "garbling table transferred")
529529
}
530530
_ => return Err(SMError::unexpected_input()),
531531
}
@@ -784,14 +784,14 @@ async fn handle_recv_deposit_adaptor_msg_chunk<S: StateMut>(
784784
let DepositStep::WaitingForAdaptors { chunks } = &mut deposit_state.step else {
785785
// WaitingForAdaptors is first step of deposit state machine. All other steps
786786
// are after it.
787-
warn!("garbler received adaptor chunk after completion, ack and ignore");
787+
debug!("garbler received adaptor chunk after completion, ack and ignore");
788788
return Ok(());
789789
};
790790

791791
let chunk_idx = adaptor_msg_chunk.chunk_index as usize;
792792

793793
if chunks[chunk_idx] {
794-
warn!("garbler received duplicate adaptor chunk, ack and ignore");
794+
debug!("garbler received duplicate adaptor chunk, ack and ignore");
795795
return Ok(());
796796
}
797797

@@ -824,7 +824,7 @@ async fn handle_recv_deposit_adaptor_msg_chunk<S: StateMut>(
824824
}
825825
}
826826
step if step.phase() > StepPhase::SetupComplete => {
827-
warn!("garbler received adaptor chunk after completion, ack and ignore");
827+
debug!("garbler received adaptor chunk after completion, ack and ignore");
828828
return Ok(());
829829
}
830830

0 commit comments

Comments
 (0)