Fix Citadel security audit findings#137
Conversation
be3ddc1 to
51c201e
Compare
xevisalle
left a comment
There was a problem hiding this comment.
I left several comments. In general I see several protocol changes that should be explained. Also, I think the specification needs to be updated accordingly before touching the code.
| const MERKLE_ARITY: usize = 4; | ||
| const DEPTH: usize = 16; // the depth of LicenseCircuit's Merkle tree | ||
| const ROOT_HISTORY_SIZE: usize = 8; | ||
| const MAX_SESSIONS: usize = 1 << DEPTH; |
There was a problem hiding this comment.
I don't get this. Why is 2^16 the max number of sessions?
There was a problem hiding this comment.
I don't get this. Why is 2^16 the max number of sessions?
This was done as a defensive state bound, but tying it to the Merkle depth was arbitrary and way too constraining. I agree it should be removed
| const CIRCUIT_MARKER_PATH: &str = "../target/license-circuit-build-id"; | ||
| const CIRCUIT_BUILD_ID: &str = "zk-citadel-license-circuit"; | ||
| const OUT_DIR_VERIFIER_FILENAME: &str = "license_verifier"; | ||
| const CIRCUIT_BUILD_DOMAIN: &[u8] = b"zk-citadel-license-circuit-v2"; |
There was a problem hiding this comment.
why v2?
We don't really need to version the build ID as is. The fingerprint is opaque and checked by exact equality, and we do not support both the old static marker and this source derived format. I'll replace v2 with a descriptive source fingerprint domain.
| ]; | ||
|
|
||
| #[tokio::main] | ||
| async fn main() { |
There was a problem hiding this comment.
what are the advantages of all these changes to the contract built?
There was a problem hiding this comment.
what are the advantages of all these changes to the contract built?
Prior setup files could be reused after circuit source changes because the marker was static. These changes make Cargo track the circuit sources, regenerating the prover/verifier together, embedding the verifier produced by the build and expose the fingerprints so wallets can reject mismatched artifacts.
It gives stronger guarantees
| /// Optional exact root freshness check for this policy. | ||
| pub expected_root: Option<BlsScalar>, | ||
| /// Optional exact binding data expected by this policy. | ||
| pub expected_binding_data: Option<[BlsScalar; 4]>, |
There was a problem hiding this comment.
what's this?
It was intended to enforce profile defined accounts or channel binding. binding_data is currently not committed though by the proof or session transcript, so checking it alone does not provide any cryptographic binding. Question is if we want to do it or not, as it was flagged as a risk area
| assert_not_identity(composer, eight_p); | ||
| // The cofactor map [8] has the prime-order subgroup as its image. Proving | ||
| // point = [8]Q for an on-curve Q excludes hidden torsion components. | ||
| let inv_eight = JubJubScalar::from(8u64).invert().unwrap(); |
There was a problem hiding this comment.
isn't this underconstrained? and, what's the reason of the added complexity?
There was a problem hiding this comment.
isn't this underconstrained? and, what's the reason of the added complexity?
This was added because the old check didn't catch all invalid points. It rejected points that were fully low order, but not a valid point with a low-order part added. The test covers that case.
As I understand it, Q isn't underconstrained because the circuit checks that it is on the curve and that [8]Q = P. But I'm not attached to this implementation. If there is a simpler or more standard way to do the subgroup check here, I'd rather use that. This came about from the audit by the way
Summary
contract/build.rs, embed the verifier fromOUT_DIR, and test metadata/verifier consistency.Verification
cargo fmt --all -- --checkcargo test -p zk-citadel --release --features zkcargo clippy -p zk-citadel --all-targets --features zk --release -- -D warningscargo test -p zk-citadel-wallet --releasecargo clippy -p zk-citadel-wallet --all-targets --release -- -D warningsmake contractmake test-contractcargo clippy -p license-contract --all-targets --release -- -D warnings0958b47: no PR-blocking security or correctness findings.controlecentrum review-pr dusk-network/citadel#137 --mode deep --blind --head-sha 0958b47 --budget-minutes 20with GPT 5.5 xhigh: final verdictCOMMENT, 0 validated findings.Notes