Midnight’s March 2026 mainnet arrival changes the standard for Compact applications. A privacy contract is no longer interesting because it can produce one valid zero knowledge proof in a controlled demonstration. It needs to survive the much harder question: can the team show, with repeatable evidence, that every permitted combination of public inputs, private witnesses, prior state commitments and disclosure choices behaves as intended?

That question matters because Midnight is built around mixed public and private transaction data, with zero knowledge proofs used for selective disclosure. The Block reported that Midnight generated its genesis block on March 17, 2026, before its public debut on March 30, while CoinDesk had earlier described the intended rollout as a late March federated mainnet launch. Compact is central to that production environment because it is the application layer where developers decide what stays private, what becomes public and what a user must prove.

A proof that verifies is necessary. It is not sufficient.

A serious test program must establish at least five things:

  1. Valid witnesses create valid state transitions.
  2. Invalid witnesses fail without leaking their contents.
  3. Authorization is distinct from arithmetic or policy constraints.
  4. State changes are bound to the correct prior commitment.
  5. Disclosure occurs only through the paths the contract permits.

The practical consequence is simple: do not test a Compact contract as a black box that returns “proof accepted.” Test it as a system with a private input boundary, a proving boundary, a verification boundary and a public state boundary.

a two point timeline chart titled “Midnight mainnet rollout milestones.” Use one series named “Mainnet milestones.” Plot March 17, 2026 as “Genesis block generated” and March 30, 2026 as “Public

The right unit of testing is the transition, not the proof

A private contract interaction is a proposed transition from one committed state to another. The proof is evidence that the transition obeys the contract’s rules. It is not the rule itself.

For a typical Compact application, model the transition as five components:

  • Public inputs: identifiers, public configuration, epoch or expiry values, a disclosed amount, an asset type, a recipient commitment, or a policy version.
  • Private witness: balances, identity claims, secret keys, membership paths, unblinded amounts, credentials or other data the prover possesses but does not publish.
  • Prior state commitment: the root, note commitment, nullifier set or other public anchor that establishes what state the proof is allowed to consume.
  • Transition constraints: the rules that connect old state, witness and inputs to the proposed result.
  • Disclosure output: the narrow public facts the application intentionally reveals, such as a compliance result, a threshold assertion or a new commitment.

The test objective is therefore not “generate proof.” It is:

Given a known public context and a controlled private witness, does the contract permit exactly the valid transition, reject every invalid transition, and expose no unintended information?

That framing prevents a common mistake. Teams often retain a handful of happy path private fixtures, feed them to a prover, confirm verification succeeds and call the privacy feature tested. In reality, those fixtures prove only that some witness exists for some case. They do not demonstrate that the contract rejects an expired credential, a witness for the wrong state root, an unauthorized signer or a private amount that exceeds a limit.

NEVER LEAVES PROVER ENVIRONMENTPOLICY, RECIPIENT, EXPIRYPRIVATE WITNESSR0 AND SPENT SETPROOF PLUS PUBLIC OUTPUTSTHRESHOLD RESULTPUBLICINPUTSpolicy,recipient,expiryPRIVATEWITNESScredential,key,balancePRIORPUBLICSTATEroot R0 andspent setTRANSITIONPROVERcompactcontractconstraintsVERIFIERAND LEDGERaccept orreject,write R1AUTHORIZEDDISCLOSUREthresholdresult only
Figure 2 - How private witnesses produce verifiable state transitions without leaving the prover

Define the witness boundary before writing fixtures

The first artifact in a production test harness should be a witness classification sheet. It is a small document, but it forces design discipline.

For every input to every contract entry point, classify it as one of these:

Class Examples May appear in a normal test log? May be retained in an audit package?
Public input Policy ID, commitment root, disclosed flag Yes Yes
Derived public value New commitment, nullifier, event digest Yes Yes
Private witness Secret key, balance, identity attribute No Only under tightly controlled encrypted retention rules
Test-only secret Deterministic test seed, synthetic credential key No Usually no
Disclosure artifact Signed attestation, selective disclosure receipt Usually yes, if intended Yes, with policy controls

This distinction should shape your repository structure. A secure harness does not put raw witnesses in the same fixture directory as public transaction inputs. It uses separate stores and separate access rules.

A workable arrangement has four fixture layers:

  1. Public scenario fixtures These contain public inputs, expected public outputs, expected rejection class, contract version and state reference. They should be safe to review in pull requests.

  2. Private witness generators These create synthetic credentials, secret keys, note openings and membership paths. In most cases, generation is better than static storage. Generated witnesses reduce the risk that a long lived test secret becomes a copied development secret.

  3. Encrypted edge case corpus Some regressions require a precise witness that once exposed a defect. Retain it only if there is a defensible need, encrypt it, restrict access and document its provenance.

  4. Commitment manifests These record hashes of public fixtures, circuit artifacts, contract source, compiler version and expected public outputs. They are the bridge between an internal test run and an external audit.

A fixture should never contain a real customer attribute, a production secret or an unredacted identity document. Synthetic data is not merely a compliance convenience. It lets teams share, replay and shrink test cases without turning debugging into a privacy incident.

The test runner should receive a witness handle, not necessarily the witness itself. The handle can resolve to an in memory generator, an encrypted local test vault or a hardware protected secret store. The runner records that the witness class was used and that the expected behavior occurred. It does not print the private values that made the behavior occur.

Make observability privacy preserving

Private contracts create an uncomfortable testing problem. The exact fact needed to explain a failure may also be the fact the system is designed not to disclose.

The solution is to distinguish external rejection behavior from internal diagnostic behavior.

External behavior should be deliberately narrow. A user or public observer may learn that a transaction was not accepted, but should not automatically learn whether the cause was a low balance, an invalid credential attribute, a revoked membership path or an incorrect secret.

Internal diagnostics can be richer, but only inside a protected testing environment. A test harness may record a structured classification such as:

  • PROVER_WITNESS_UNSATISFIED
  • AUTHORIZATION_DENIED
  • STATE_REFERENCE_STALE
  • PROOF_ENCODING_INVALID
  • VERIFIER_REJECTED
  • DISCLOSURE_POLICY_DENIED

Those labels should be treated as test telemetry, not necessarily as messages for end users or public nodes. The actual taxonomy will depend on the runtime and client architecture, but the discipline is universal: define the classifications before writing tests, then verify that each test reaches the intended classification.

REDACTED CLASSIFICATION ONLYPROTECTED TESTING ENVIRONMENTREDACTED CLASSIFICATIONPUBLIC RESULT ONLYPUBLICUSERRESPONSEtransactionaccepted ornot acceptedPROTECTEDTESTTELEMETRYscenario ID;expected andactualSECRETMATERIAL🔒 witnessvalues;identity
Figure 3 - how private contract tests retain useful diagnostics without exposing witness material

A useful test result has two outputs:

  • a machine readable assertion record, such as expected and actual outcome class;
  • a human readable redacted report, which identifies the scenario, contract build and failed rule without printing secret values.

For example, a failed test could say:

Scenario withdrawal.limit.exceeded.017 correctly failed in the amount constraint family. Public root and policy version matched the fixture manifest. No witness values retained.

That gives developers and auditors a meaningful result while preserving the witness boundary.

Negative testing means changing one cause at a time

A privacy contract audit is often won or lost in negative cases. The team must prove that invalid witnesses fail for the right reason, not just that something eventually returns an error.

The key method is single fault mutation. Begin with a passing scenario. Change exactly one relevant element. Keep every other input, state reference and authorization condition stable.

Consider a private transfer that requires:

  • a valid credential;
  • an authorized signer;
  • a private balance at least equal to the transferred amount;
  • an unspent note under the current commitment root;
  • a recipient permitted by policy;
  • a disclosure option compatible with the policy.

From one valid fixture, create separate negative cases:

Mutation Expected class What it proves
Increase the private transfer amount above balance Witness or constraint failure Conservation and balance rules bind to the witness
Replace credential with an expired one Constraint or policy failure Expiry is enforced in the proof relation
Use a valid credential from an unauthorized issuer Authorization failure Valid data is not mistaken for authorized data
Reuse an already spent note State transition failure Nullifier or spent state is enforced
Use an old state root after a conflicting transition State reference failure Proof is bound to a permitted state snapshot
Alter proof bytes after generation Verification failure Verification rejects tampered proof encoding
Request an unpermitted disclosure field Disclosure policy failure Selective disclosure is constrained, not optional

The categories can overlap in a real proving system. An unauthorized issuer might be encoded as a circuit constraint. A stale state reference could be rejected at transaction admission rather than proof creation. That is acceptable if the expected layer is defined clearly and consistently.

What matters is that the test author does not accept any generic “failed” result. If a malformed proof is used to test authorization, then a failure says nothing about authorization. If an expired credential is paired with an invalid signature, a rejection does not establish that expiration logic works. Each negative case needs a clean causal claim.

PROOFRELATIONSATISFIED?No: Witness,constraint,or policyAUTHORIZATIONPERMITTED?No:AuthorizationfailureSPENTSTATEACCEPTABLE?No: StatetransitionfailureSTATEREFERENCEPERMITTED?No: StatereferencefailureVERIFICATIONSUCCEEDED?No:VerificationfailureDISCLOSUREMATCHEDPOLICY?No:DisclosurepolicyACCEPTEDTRANSITIONAllapplicablechecks
Figure 4 - how to assign each failed private contract interaction to one clean causal layer

Reproducibility is about artifacts, not identical proofs

Teams should expect proof generation to involve randomness. Therefore, demanding that two proof runs always produce identical proof bytes can be a bad test requirement. It can accidentally drive a system toward unsafe randomness practices or create brittle tests.

The reproducibility target should instead be the full proving environment:

  • Compact source commit;
  • dependency lockfile;
  • compiler and runtime version;
  • circuit or constraint artifact hash;
  • proving and verification key hashes;
  • public fixture hash;
  • witness generator version;
  • protocol parameters;
  • transaction serialization version;
  • expected public outputs;
  • verifier result.

A build is reproducible when an independent environment can reconstruct the same contract artifact, derive the same public commitments from the same approved test scenario and verify the expected acceptance or rejection outcome.

For selected test vectors, controlled deterministic randomness may be appropriate inside an isolated test environment. If used, it must be visibly labeled test-only and must never migrate into production proving logic. The goal is reproducible diagnostics, not a production shortcut.

A strong release gate runs the same public fixture suite against two independently built environments. If their circuit artifact hashes differ, stop. If the hashes agree but one environment accepts a vector the other rejects, stop. If both accept but produce different intended public commitments, stop.

Use property tests to cover combinations humans will not enumerate

Example based tests are essential, but they cannot cover the combinatorial space implied by private witnesses and public inputs. This is where property based testing earns its place.

Instead of hand writing 500 transactions, write generators for:

  • valid and invalid credential lifecycles;
  • balances near zero, at a limit and just over a limit;
  • state trees of different depths and membership positions;
  • authorization sets with one, many or revoked issuers;
  • disclosure requests with permitted and prohibited fields;
  • transaction sequences that create conflicts, retries and double spends.

Then state properties that must remain true regardless of the generated data.

Examples:

Conservation property: For any accepted private transfer, the sum of consumed private value equals the sum of created private value plus any explicitly permitted fee or burn.

Authorization property: Replacing only the actor authorization with an unauthorized authorization must not produce an accepted transition.

Binding property: A proof generated for state commitment R0 must not be usable to consume a note under an incompatible state commitment R1.

Disclosure minimality property: Adding a request for an unpermitted disclosure must never increase the accepted public output set.

Replay resistance property: Repeating an already accepted spend must not create a second accepted state transition.

Noninterference property: Altering an irrelevant private field should not alter public outputs, except where the contract explicitly commits to that field.

That final property is especially useful. It tests whether a supposedly private field has leaked into an event, commitment construction or public branch condition. It does not prove the absence of all metadata leakage, but it can expose accidental coupling early.

When a generator finds a failing case, shrinking must respect the witness boundary. Store the minimal public scenario and an encrypted or regenerable witness recipe. Do not automatically dump the final private witness into continuous integration logs.

Treat testnet to mainnet drift as a release risk

A testnet result is evidence about a particular environment. It is not automatically evidence about mainnet.

Midnight’s production rollout makes this distinction more important because contract behavior can depend on protocol settings, deployed artifacts, client versions, network admission rules, fees, state synchronization behavior and infrastructure topology. CoinDesk’s 2025 research described Midnight’s rollout as a staged process, including a federated mainnet phase and a later incentivized testnet phase. That staged model is a reminder that environment assumptions need explicit tracking.

For each release candidate, produce a drift checklist:

  • Is the Compact source commit identical to the audited commit?
  • Are the compiler, runtime and constraint artifact hashes identical?
  • Are verification keys identical and correctly registered?
  • Are transaction serialization and network parameters unchanged?
  • Do state query and submission clients return the same canonical data shapes?
  • Has the fee or capacity model changed in a way that affects admissibility?
  • Does the deployed contract use the expected policy configuration?
  • Do public outputs and disclosure receipts match the approved schema?

Run a differential suite before deployment. The same approved public fixtures should be exercised on the final testnet configuration and on a mainnet shadow environment that uses synthetic witnesses and isolated funds. The purpose is not to move testnet secrets onto mainnet. It is to show that the production artifacts and interfaces preserve the behavior already audited.

EXERCISE SAME APPROVED FIXTURESMATCHING ARTIFACTS AND INTERFACESEXERCISE SAME APPROVEDMATCHING ARTIFACTSTESTNETQUALIFICATIONpropertysuite;negativeDIFFERENTIALDRIFTCHECKSfinaltestnet vs.mainnetMAINNETRELEASEEVIDENCEmanifest,differentialreportThe mainnet shadow environment uses synthetic witnesses and isolated funds; testnet secrets are not moved o...
Figure 5 - how testnet qualification and drift checks produce evidence for a safe mainnet release

Build an auditor’s evidence package without handing over secrets

An auditor needs evidence that testing happened, that the deployed artifact matches the reviewed artifact and that failures were classified correctly. The auditor does not automatically need every raw private witness.

A useful evidence package includes:

  1. Scope statement Contract functions, policy assumptions, disclosure paths, assets, user roles and excluded components.

  2. Artifact manifest Source commit, dependency hashes, compiler version, contract artifact hash, proving and verification key hashes and deployment transaction reference.

  3. Threat model What the contract is expected to protect, what remains public, who may disclose what and which actors are trusted.

  4. Test plan and coverage map Every entry point mapped to happy path tests, boundary tests, negative tests, property tests and stateful sequence tests.

  5. Redacted test transcripts Scenario ID, public fixture hash, commitment references, expected outcome class, actual outcome class, artifact hashes and timestamp. No raw witness values.

  6. Witness handling policy How synthetic witnesses are generated, where any encrypted regression corpus is stored, who can decrypt it and when it is destroyed.

  7. Deployment comparison report Evidence that audited artifacts equal deployed artifacts, plus documented explanations for any approved difference.

  8. Open findings register Known limitations, unresolved edge cases, accepted risks and remediation commitments.

Transcript retention requires its own policy. Retain public manifests and redacted classifications for the period required by engineering, governance and regulatory needs. Retain raw private witness material only when necessary to reproduce a material defect, under encryption and explicit access control. If a witness can be regenerated from a protected seed, retain the recipe and controls rather than the raw data.

The governing principle is straightforward: an audit package should let an independent reviewer reproduce the claim, not unnecessarily reconstruct the secret.

The new definition of done

Midnight’s mainnet makes privacy application quality measurable in a more demanding way. The relevant question is no longer whether a Compact contract can make a valid proof. The relevant question is whether the team can demonstrate correct behavior across the contract’s full transition space, including invalid witnesses, stale commitments, unauthorized actors and prohibited disclosures.

A contract is ready when its team can answer:

  • What is public?
  • What remains only in the witness?
  • Which failures occur before proving, during proving, at authorization, at state admission and at verification?
  • What information does each failure reveal?
  • Can the deployed artifact be tied to the tested artifact?
  • Can an auditor review the evidence without receiving private user data?

If those answers are documented, automated and reproducible, zero knowledge proof generation stops being a demo milestone. It becomes what mainnet software needs it to be: one component in an engineering system that can be tested, reviewed and trusted.

#Midnight#Compact#zero knowledge#privacy#mainnet#smart contracts#testing#auditing
About Jared Zimmerman
Jared Zimmerman writes the long technical pieces at Midnight Signal: zero-knowledge proof systems, the Compact toolchain, partner-chain consensus, and what selective disclosure means in practice rather than in a whitepaper. He reads the specifications and the code, and prefers a diagram to an adjective.