The Thesis
You can’t build private applications if every input is public.
Midnight solves this by separating where data is used from where data is stored.
Witnesses are the mechanism that makes that possible:
Private data stays local
Computation happens in a circuit
The network only verifies the result
No leakage. No exposure. Just proof.
Technical Architecture
Midnight extends a Substrate-based execution environment with a zero-knowledge circuit model, where smart contracts (written in Compact) define logic, but not all data.
Some data is intentionally missing.
That missing piece is filled at execution time through witnesses.
A witness is not a function in the traditional sense. It’s a declaration:
witness secretKey(): Bytes<32>;There is no implementation in the contract.
The contract only defines:
what it needs
what type it expects
The actual value is injected at runtime from the DApp layer (TypeScript), just before proof generation.
This creates a split execution model:
On-chain → deterministic logic + verification
Off-chain → private data provisioning
What a Witness Actually Does
They allow your circuit to access private data without publishing it.
The flow looks like this:
You call:
contract.callTx.post("Hello")The circuit executes locally.
At some point, it needs a value:
localSecretKey()That call doesn’t resolve on-chain.
It jumps to your TypeScript implementation.
The Bridge Between Contract and Reality
Here’s what the contract says:
witness localSecretKey(): Bytes<32>;Here’s what your DApp provides:
A function implementation
Access to private state
A return value used inside the circuit
The circuit doesn’t know where the data came from.
It only knows:
“I asked for 32 bytes. I got 32 bytes.”
That value:
enters the ZK circuit
participates in computation
gets locked inside the proof
And then disappears.
Why Witnesses Exist
Consider a simple constraint:
You want to prove ownership of a key.
But:
you cannot reveal the key
you cannot store it on-chain
Without witnesses, you’re stuck.
With witnesses:
the key is fetched locally
used inside the circuit
never exposed
The proof confirms:
“This user knows a valid key”
Without revealing:
“Which key”
That’s the entire point.
The Circuit Doesn’t Trust You
Here’s the part most people miss.
Witnesses are not trusted.
They run on the user’s machine.
That means:
Anyone can modify their witness implementation
So the contract must defend itself.
Example pattern:
Witness provides a secret key
Circuit derives a public key
Circuit compares it to stored state
If it doesn’t match:
the assertion fails
the proof becomes invalid
the transaction is rejected
The system doesn’t trust inputs.
It verifies outcomes.
The disclose() Boundary
By default, everything coming from a witness is private.
If you try to store it:
balance = getBalance(); // ❌Compilation fails.
You must explicitly say:
balance = disclose(getBalance()); // ✅This is not syntax noise.
It’s a security boundary.
The compiler tracks:
where private data flows
where it becomes public
Nothing is leaked accidentally.
Private State: Where Witness Data Lives
Witnesses don’t just return values.
They interact with private state stored locally.
This state:
lives in encrypted storage (LevelDB)
persists across sessions
never leaves the user’s machine
Each contract instance:
has its own private state
scoped by contract address
This allows:
user-specific secrets
per-contract isolation
persistent private logic
How Witnesses Fit Into the Transaction Flow
Now connect this to what you already learned about transactions.
The full lifecycle becomes:
Circuit executes locally
Witness is called → private data injected
Circuit computes new state
Unproven transaction is created
Proof server generates ZK proof
Proven transaction is submitted
Network verifies proof
At no point:
is the private data broadcast
is it stored on-chain
is it visible to validators
It exists briefly:
in memory
inside the proving process
Then it’s gone.
The “Why” (Market Fit)
Most blockchains force a trade-off:
transparency vs privacy
Midnight removes that constraint.
Witnesses enable:
private identity systems
confidential financial applications
selective disclosure systems
They solve a real limitation:
You can’t build privacy-preserving applications if all inputs are public.
Witnesses make private inputs first-class citizens in smart contract execution.
Contextual Analysis
Compared to traditional models:
Ethereum
All inputs are public
Execution is replicated
Midnight
Inputs can be private
Execution is proven, not replayed
Witnesses are the missing abstraction that enables this shift.
Without them:
Midnight would behave like any other chain
With them:
It becomes a privacy-first computation layer
Roadmap & Hurdles
Witnesses introduce new responsibilities:
Strengths
Strong data privacy guarantees
Flexible off-chain data integration
Reduced on-chain exposure
Constraints
Developers must manage private state correctly
Security depends on proper validation logic
Debugging becomes less straightforward
The challenge is not tooling.
It’s mindset.
You are no longer writing fully deterministic on-chain programs.
You are designing:
partially local
partially provable
fully verifiable systems
Final Take
Your contract doesn’t need to know everything.
It just needs to prove enough.
Witnesses are how private data enters the system, does its job, and disappears without a trace.
Not hidden.
Not encrypted on-chain.
Never there in the first place.

Discussion
Join the conversation
Connect your wallet to share your thoughts and engage with the community
No comments yet
Connect your wallet to be the first to comment!