The verifier determines whether execution properly invoked the halt syscall by checking if public_values.next_pc == 0, as implemented here:
| for(i, shard_proof)in proof.0.iter().enumerate(){ |
| let public_values = PublicValues::from_vec(&shard_proof.public_values); |
| // Verify shard transitions |
| if i == 0{ |
| // If it's the first shard, index should be 1. |
| if public_values.shard != BabyBear::one(){ |
| returnErr(MachineVerificationError::InvalidPublicValues( |
| "first shard not 1", |
| )); |
| } |
| if public_values.start_pc != vk.vk.pc_start{ |
| returnErr(MachineVerificationError::InvalidPublicValues( |
| "wrong pc_start", |
| )); |
| } |
| }else{ |
| let prev_shard_proof = &proof.0[i - 1]; |
| let prev_public_values = PublicValues::from_vec(&prev_shard_proof.public_values); |
| // For non-first shards, the index should be the previous index + 1. |
| if public_values.shard != prev_public_values.shard + BabyBear::one(){ |
| returnErr(MachineVerificationError::InvalidPublicValues( |
| "non incremental shard index", |
| )); |
| } |
| // Start pc should be what the next pc declared in the previous shard was. |
| if public_values.start_pc != prev_public_values.next_pc{ |
| returnErr(MachineVerificationError::InvalidPublicValues("pc mismatch")); |
| } |
| // Digests and exit code should be the same in all shards. |
| if public_values.committed_value_digest != prev_public_values.committed_value_digest |
| || public_values.deferred_proofs_digest |
| != prev_public_values.deferred_proofs_digest |
| || public_values.exit_code != prev_public_values.exit_code |
| { |
| returnErr(MachineVerificationError::InvalidPublicValues( |
| "digest or exit code mismatch", |
| )); |
| } |
| // The last shard should be halted. Halt is signaled with next_pc == 0. |
| if i == proof.0.len() - 1 && public_values.next_pc != BabyBear::zero(){ |
| returnErr(MachineVerificationError::InvalidPublicValues( |
However, this check is located inside the else branch for i = 0, and is therefore skipped entirely when the proof contains only one shard.
This issue is disclosed with the permission of @johnchandlerburnham.
The verifier determines whether execution properly invoked the halt syscall by checking if public_values.next_pc == 0, as implemented here:
sphinx/prover/src/verify.rs
Lines 54 to 94 in 8a39b95
However, this check is located inside the else branch for i = 0, and is therefore skipped entirely when the proof contains only one shard.