Ironwood security assurance

Audit status

An implementation-first view of formal verification, third-party audits, results, detailed findings, remediation, and publication work.

OverallClear (Preliminary)
3 Active
5 Clear (preliminary)
4 Clear (final)
Current view

Current audits and formal verification

Current Ironwood implementation and assurance workstreams
Audit typeResource auditedTeam auditingResultStatusPublic record
Formal verificationhalo2 proof-system verification
NU6.3halo2OrchardIronwood
Team auditingSean Bowe (lead) · Project Tachyon · zkSecurity · Zcash Open Development LabResultProof-system knowledge-soundness analysis for the Orchard and Ironwood use of halo2 is in progress.ActivePublic recordIronwood formal-verification repositoryProject Tachyon explanation
Review details

Do not read this status as a completed end-to-end proof of the deployed implementation. Stay tuned for a report about the analysis performed by Project Tachyon.

Formal verificationOrchard Action circuit in Lean/Clean
NU6.3OrchardIronwoodhalo2
Team auditingzkSecurityResultSoundness and completeness proofs are complete; broader theorem scope and production correspondence continue.Clear (Preliminary)Public recordOrchard in CleanClean Orchard repositoryVerification plan
Review details

The current report identifies two limitations: the model was not yet mechanically checked against the production halo2 constraint system, and not every lower-level specification or interface received human review. zkSecurity and Project Tachyon are working to lift both limitations.

Cryptographic auditOrchard and Ironwood circuit changes26 June - 10 July 2026
NU6.3NU6.2OrchardIronwoodhalo2
Team auditingZellicResultDraft report: 1 Low · 2 Informational; no significant findings. Remediation language is being finalized.Clear (Preliminary)Public recordPendingZellic publications
3 findings
Executive summary: 0 Critical · 0 High · 0 Medium · 1 Low · 2 Informational

Draft report, revision f9da45c-dirty, dated 15 July 2026. Finding 3.1's table currently says Severity High / Impact Low even though the executive summary counts it as Low; the final classification and remediation remain pending.

FindingSeverity / scopeDispositionDetail
3.1rcm_v3 depends on implementation-specific field serializationSeverity / scopeExecutive summary: Low; finding table: High severity / Low impactDispositionTBDThe version-3 note trapdoor feeds field representations into its PRF even though the field trait does not promise a stable byte order. Zellic recommends an explicit encoding or a pinned test vector.
3.2Bundle commitment accepts incompatible V6 pool restrictionsSeverity / scopeInformationalDispositionAcknowledgedA caller can perform wasted client-side work using pre-NU6.3 restrictions with a V6 bundle even though the resulting transaction will be rejected on chain.
3.3Verifying-key circuit version is not checked against the bundleSeverity / scopeInformationalDispositionTBDThe draft recommends carrying the circuit version with the bundle and verifying that it matches the proving or verifying key instead of relying on a feature-specific check.
Independent reviewOrchard, halo2, and ZebraCompleted July 2026
NU6.3Orchardhalo2Zebra
Team auditingOtterSecResultNo soundness issue identified; Zebra P2P, reliability, hardening, and optimization findings remain.Clear (Preliminary)Public recordDrafting
26 review notes
Final severities, remediation dispositions, and report wording are pending.

The review is complete, but the final report has not yet been delivered. The notes below are the current private review record and may be regrouped or reclassified in the final report.

FindingSeverity / scopeDispositionDetail
Empty-message Sinsemilla underconstraintSeverity / scopehalo2 / OrchardThe same empty-message y-coordinate gap later documented by zkSecurity was identified. OtterSec noted that Orchard never exercises the empty-message case and found no Poseidon issue.
Header-hash caching omits the authentication digestSeverity / scopeZebra block validationCaching and suppression paths keyed only by the header hash can treat blocks with different authentication data as identical. The recommendation is to verify auth_digest before caching or include it in the key.
Mempool source attribution is lostSeverity / scopeZebra P2PTransactions entering Request::Queue can lose their peer source, allowing one peer to consume global inbound concurrency without the per-peer limit applying.
Malformed FindBlocks or FindHeaders responses stall syncSeverity / scopeZebra P2PIncorrect non-empty responses can poison the download set, cancel future downloads, and force a sync retry after about 67 seconds without punishing the peer.
Connection timeouts are not punishedSeverity / scopeZebra P2PNon-ping timeouts fail a request but keep the peer alive, allowing malicious peers to stall requests and monopolize rate-limited slots.
Single-source inventory races can suppress block downloadSeverity / scopeZebra P2PAfter one peer advertises a block, competing advertisements may be discarded; if the first peer stalls, the node can fail to retrieve the block without a fallback source.
Unsolicited notfound messages can evict honest inventorySeverity / scopeZebra node serviceRandom unsolicited missing hashes share the inventory cap with available entries and can evict recent honest advertisements without request-context validation.
ZIP 401 eviction can leave indexer state staleSeverity / scopeZebra node serviceMempool eviction does not emit invalidation events for removed transactions, so gRPC subscribers can retain stale pending state or observe an Added event for a transaction already evicted.
Checkpoint request-limit calculation uses the wrong quantitySeverity / scopeZebra node serviceThe current calculation adds post-checkpoint hashes returned by a peer instead of the intended remaining checkpoint blocks plus the full-verification limit.
FindBlocks loses the peer responsible for a far-ahead hashSeverity / scopeZebra node serviceA later lookahead rejection can be attributed to the peer serving the block rather than the peer that supplied the far-ahead hash.
Invalid transmission-key bytes can panicSeverity / scopeCrypto-adjacentTransmissionKey::try_from unwraps before checking for None, turning invalid note-scanning or wallet-style input into a panic.
Stored crypto-byte deserializers unwrap fallible decodersSeverity / scopeCrypto-adjacentInvalid Jubjub, Pallas/Pasta, Sapling commitment, note commitment, or tree-node bytes can panic instead of producing a serialization error.
Corrupt finalized-state bytes can crash-loop a nodeSeverity / scopeCrypto-adjacentFromDisk readers treat database bytes as trusted and use expect or unwrap across shielded trees, transparent outputs, headers, and transactions, requiring repair or rebuild after corruption.
Identity Orchard binding verification keys are acceptedSeverity / scopeCrypto-adjacentAn identity binding key makes the RedDSA equation degenerate and no longer proves knowledge of a nonzero binding signing key.
halo2 sorting dependency is not exact-version constrainedSeverity / scopeCrypto-adjacentA dependency update that changes region sorting could change the Orchard verifying key rebuilt by Zebra and make historical proofs fail verification.
Mempool gossip can drop unread eventsSeverity / scopeLow-impact review noteThe lossy channel logs lagging consumers but does not reload the state they missed.
Locally mined block advertisement can be suppressedSeverity / scopeLow-impact review noteA broadcast can time out before dispatch while the tip is immediately marked seen, suppressing the committed-tip fallback without a reliable advertisement.
Transaction advertisement ignores the peer relay flagSeverity / scopeLow-impact review noteThe generic broadcast path can choose peers that did not enable transaction relay.
Concurrent invalid-block results may not all be scoredSeverity / scopeLow-impact review noteA reset can cancel outstanding work without draining completed invalid results, leaving only the first observed peer penalized.
Authorized transaction RPCs bypass source attributionSeverity / scopeLow-impact review notesendrawtransaction uses a None source while still consuming shared, unreserved state work, so sustained RPC submissions can delay unrelated users.
Transiently failed peers can remain strandedSeverity / scopeLow-impact review noteA stale last_seen value can make reconnection skip a peer while later gossip is rejected without refreshing that timestamp.
halo2 verifier commitment calculation can be shortenedSeverity / scopeOptimizationDirect multiscalar multiplication over the used instance bases could avoid zero-padding a much larger vector; the review observed roughly 20% improvement for a single Orchard Action.
Root invalidation can leave code assuming a missing non-finalized chainSeverity / scopeFinal review noteAfter root invalidation empties the non-finalized state, a writer path can still assume that a best chain exists. Final severity and disposition await the report.
TrustedChainSync can process a stale queued blockSeverity / scopeFinal review noteA queued block already passed by the secondary finalized database can be committed and immediately pruned, leaving non-finalized state empty and causing update_channels to panic until restart.
Expensive shielded proofs start before cheap state rejectionSeverity / scopeFinal review noteProof jobs can continue after their futures are dropped, letting remote peers consume shared verification capacity with transactions that anchor and nullifier checks would reject quickly.
KnownBlock can read rejected hashes before cleanupSeverity / scopeFinal review noteThe rejected-hash drain runs only in one commit path, so a redelivered rejected block can still be returned as known before cleanup executes.
Independent auditOrchard and halo2Completed July 2026
NU6.2Orchardhalo2
Team auditingzkSecurityResultFinal report: no issue affecting deployed Orchard. 1 Medium · 2 Low · 1 Informational.Clear (Final)Public recordNot publicAudited Orchard 0.14.0 sourceAudited halo2_gadgets 0.5.0 source
4 findings
0 Critical · 0 High · 1 Medium · 2 Low · 1 Informational

The report has been received privately. A public report URL is pending. The formal-model correspondence limitations are tracked separately under Formal verification.

FindingSeverity / scopeDispositionDetail
#00Empty Sinsemilla input leaves the output y-coordinate unconstrainedSeverity / scopeMediumDispositionNo ImpactAn empty Sinsemilla message can produce an underconstrained output point. Orchard never hashes empty Sinsemilla messages, so the report concludes that deployed Orchard is unaffected.
#01Full-width fixed-base multiplication does not bind a reused scalarSeverity / scopeLowDispositionNo ImpactThe API can be misread as enforcing equality across two multiplications that reuse a scalar witness. The audited Orchard circuit uses the gadget only for the existential relation it actually enforces.
#02PCZT output verification does not authenticate ciphertextSeverity / scopeLowDispositionReportedThe helpers authenticate note metadata against the note commitment but do not prove that the attached ciphertext encrypts that note. This is a signer and wallet risk, not a consensus issue.
#03Low-level proof verification accepts trailing bytesSeverity / scopeInformationalDispositionReportedLow-level verification consumes the expected halo2 transcript elements without requiring the byte slice to end there. Higher-level strict bundle construction already checks canonical proof size.
Application auditlibrustzcash Ironwood updates22 June - 2 July 2026
NU6.3librustzcashOrchardIronwoodV6 tx
Team auditingZellicResultDraft report: 4 Low · 1 Informational; no significant findings. Final dispositions are pending.Clear (Preliminary)Public recordPendingAudited implementationZellic publications
5 findings
0 Critical · 0 High · 0 Medium · 4 Low · 1 Informational

Draft report, revision 8dce8ba-dirty, dated 13 July 2026. Every remediation field is still TBD. Project notes say ZIP 233 has since been removed from V6 compilation; that disposition still needs to be reconciled into the final report.

FindingSeverity / scopeDispositionDetail
3.1ZIP 233 burn amounts can be silently dropped and paid to the minerSeverity / scopeLowDispositionTBDA build configuration can accept a burn request without encoding it, leaving the value in the fee. The audited draft predates the project's removal of ZIP 233 from V6 compilation.
3.2An empty witness slice panics merkle_path_from_sliceSeverity / scopeLowDispositionTBDA public helper can index an empty, potentially untrusted witness slice and panic instead of returning an error.
3.3An empty transparent bundle has a non-canonical digestSeverity / scopeLowDispositionTBDA present-but-empty transparent bundle serializes like an absent bundle but can produce a different txid and sighash, breaking canonical transaction identity.
3.4Orchard-only change can bypass a version check and panicSeverity / scopeLowDispositionTBDAn Orchard builder holding only a change output can reach txid computation for a transaction version that does not support Orchard and panic instead of returning a compatibility error.
3.5NU7 without ZIP 233 can build invalid V6 transactionsSeverity / scopeInformationalDispositionTBDFeature combinations can disagree about V6 validity and header handling. Project notes say ZIP 233 is now removed from V6 code paths; the final report has not yet recorded that disposition.
Node auditZebra and Zakura Ironwood updates23 June - 6 July 2026
NU6.3ZebraZakuraIronwood
Team auditingZellicResultFindings are largely addressed; one inherited Zebra P2P head-of-line blocking issue remains open.Clear (Preliminary)Public recordPendingZakura implementationAudited Zebra implementationZellic publications
7 findings
0 Critical · 4 High · 1 Medium · 2 Low · 0 Informational

Draft report revision 09dbc6a, dated 6 July 2026. The audited handoff was early: Orchard was near the final update, librustzcash was close, and the Zebra/Zakura implementation drifted the most as the specification and production configuration changed.

FindingSeverity / scopeDispositionDetail
3.1Body tip conflated with the header frontier disables watchdog fallbackSeverity / scopeHighDispositionMitigatedThe draft cites commit bce912c5. The affected V2 P2P path is turned off in the later production configuration.
3.2Repeated reconsiderblock panics the state write threadSeverity / scopeHighDispositionFixedFixed in commit cbdd73f9. The same bug existed in upstream Zebra and was fixed there with a similar patch. Merged remediation PR
3.3Post-NU6.3 coinbase accepted non-empty Orchard actionsSeverity / scopeHighDispositionFixedFixed in commit d402f4fa after the Ironwood specification became unambiguous about the rule. Merged remediation PR
3.4Header and body frontier desynchronization can stall catch-upSeverity / scopeHighDispositionFixedFixed in commit 8551e3f9 by repairing continuity assumptions between the stored header frontier and verified body chain. Merged remediation PR
3.5A registry miss globally stalls sync dispatchSeverity / scopeMediumDispositionOpenOne unavailable hash can block unrelated reserve downloads for roughly two minutes. The issue is acknowledged and is also present in upstream Zebra.
3.6Ironwood cross-address error was not assigned a peer scoreSeverity / scopeLowDispositionNot ApplicableThe audited consensus rule was removed after the specification was clarified, so this error no longer exists. Related P2P errors are now scored; the draft cites commit 2bbda9c6.
3.7The mempool rejected Ironwood's activation empty-root anchorSeverity / scopeLowDispositionFixedFixed in commit c45fe95f so the mempool and block paths agree at the activation boundary. Remediation commit
Supporting evidence

Additional assurance

Additional Ironwood assurance work
Audit typeResource auditedTeam auditingResultStatusPublic record
AI-assisted reviewOrchard implementation review passes
NU6.3OrchardIronwoodhalo2
ResultPublic implementation PR records multiple model-assisted and human review passes.Clear (Final)Public recordOrchard pull request #504
AI-assisted reviewZebra multi-agent review and remediation
NU6.3ZebraIronwood
ResultTwo public pull requests document independent review rounds and their fixes.Clear (Final)Public recordZebra pull request #10884Zebra pull request #10886
Continuous testingBatch-versus-single verification equivalence
NU6.3OrchardIronwoodhalo2
ResultDifferential fuzzing continuously checks batched and single shielded verification equivalence.ActivePublic recordRead the Zcash Community Grants proposal
AI-assisted reviewAnthropic Mythos counterfeiting review
NU6.2Orchardhalo2
ResultNo additional counterfeiting vulnerability was reported; no detailed report is public.Clear (Final)Public recordShielded Labs disclosure update
Related Zcash auditSapling audit
Sapling
Team auditingZellicResultA separate Sapling implementation assessment is underway.ActivePublic recordPending
Inherited stack

Earlier audits

These audits were performed for Orchard prior to the recent discovery of a counterfeiting bug.

Earlier audits of the inherited Orchard and halo2 stack
Audit typeResource auditedTeam auditingResultStatusPublic record
Independent auditAI-assisted Zcash ecosystem auditMarch - May 2026
NU6.2ZebrazcashdlibrustzcashOrchardhalo2
Team auditingLeast AuthorityResultRepository-level review before final Ironwood changes; final reports were delivered in May 2026.Clear (Final)Public recordRead the Least Authority overview
Review details
Zebra: 17 · orchard: 11 · halo2: 2 · librustzcash: 7 · zcashd: 10

The public overview provides repository-level severity counts; the underlying reports are not linked there.

Independent auditNU5 Orchard and halo2 auditApril - September 2021
NU5Orchardhalo2librustzcash
Team auditingQEDITResultPre-NU5 review of halo2, Orchard, keys, Pasta curves, and librustzcash interfaces.Clear (Final)Public recordRead the QEDIT report
Review details
0 Critical · 7 Warning · 19 Minor
Independent auditNU5 cryptography review2021
NU5Orchardhalo2
Team auditingNCC GroupResultMulti-phase specification and implementation review; no serious issue was reported.Clear (Final)Public recordRead the NCC Group report

This inventory separates independent audits, formal verification, and other review work. Draft and unpublished reports are included because their findings and remediation status are material; a missing report link means publication is still pending, not that the work did not happen.