# Version hash is not correctly enforced in code unpacker

In zkSync's code unpacker circuit, the version-hash constraint was inverted, so the version hash was never actually enforced against queue-sourced chunks.

- Payout: Contest reward
- Severity: medium
- Program: zkSync
- Credited: xuwinnie
- Disclosed: 2024-02-29
- Write-up quality: 6/10
- Original: https://github.com/code-423n4/2023-10-zksync-findings/issues/716
- Library page: https://bugbountylibrary.com/r/c4%3A2023-10-zksync%3AM-10
- Tags: domain:web3 impact:integrity kind:contest platform:code4rena sev:medium tech:solidity technique:source-review vuln:business-logic

**Target:** zkSync Era code unpacker ZK circuit (constraint system)
**Root cause:** conditionally_enforce_true was called with arguments swapped: version_hash_matches.conditionally_enforce_true(cs, state_get_from_queue) enforces 'if version hash matches then must be from queue', instead of 'if from queue then version hash must match', leaving the version hash unconstrained.
**Steps:**
1. Read code unpacker: `let version_hash_matches = UInt16::equals(cs, &chunks[1], &versioned_hash_top_16_bits);`
2. Observe next line: `state.state_get_from_queue.conditionally_enforce_true(cs, version_hash_matches);`
3. Inspect conditionally_enforce_true: enforces (1 - self) * should_enforce == 0, i.e. self==true implies should_enforce==true
4. Conclude constraint only forces queue-flag when hash matches, not hash when from queue; incorrect version hash passes
5. Fix: `version_hash_matches.conditionally_enforce_true(cs, state.state_get_from_queue);`
**How found:** Code review of the circuit's constraint wiring; noticed the boolean arguments to conditionally_enforce_true were in the wrong order relative to the intended implication.
**Insight:** When auditing ZK circuits, verify the direction of conditional constraints: conditionally_enforce_true(a, b) enforces a=>b, so check which operand is the guard versus the obligation.
