Nillion (@nillion): Covenants Explained
Estimated coin impact
Scores are not price-change percentages. High impact means a score of +70 or more, or -70 or less.
Impact unavailable
Covenants Explained You’ve built the auction contract. Bids come in, the clock runs down, the highest bid wins. Except every bid is readable the moment it’s submitted, so the last bidder always wins by one wei. You could hash the bids and have people reveal later, now you need a reveal phase, and a plan for everyone who doesn’t show up, and a way to explain to your users why their deposit is locked in a contract waiting on a stranger. The same problem shows up everywhere onchain. A stop-loss sits in the clear until it fires. A vault rebalancing logic is readable the moment it's deployed. Anything you want to happen later has to be published now, in full, to everyone. Commit-reveal is the usual answer and it’s a bad one. It makes users come back, and it fails when they don’t. Covenants are the alternative. Dusk is the first place you can build with them, live on testnet on September 28th. What a Covenant is A Covenant is an encrypted instruction that opens itself when a condition is met. You seal a payload, a bid, an order, payout, or disclosure, bind it to a condition, and post it onchain. The payload is split across a committee of nodes you select. When the condition is satisfied, those nodes publish their shares, the payload is reconstructed, and your contract receives it through a settlement hook. Nobody comes back to reveal anything. The author commits once and is done. The Flow Seal. Your payload gets a 32-byte nonce appended, and the protocol commits to keccak256(payload || nonce). The nonce matters more than it looks: market instructions are small and predictable, and without it a commitment to “sell 100 ETH” is guessable by brute force. Plaintext caps at 2048 bytes, so with the nonce you have 2016 bytes to work with. That’s an instruction or a reference, not a document. Anything larger goes in as a pointer, hash, CID, or encrypted key. The commitment does one job and it’s worth being precise about which: it fixes the instruction in place. Once posted, you cannot quietly swap the payload for a different one later. It doesn’t hide the payload, the encrypted layers do that, and it's computationally hiding rather than information theoretically hiding, which is exactly why the nonce is there. Split. The full payload || nonce is split across your selected committee using Shamir secret sharing over GF(2⁸), k-of-m. Each share is a point on the polynomial, formatted as x || y-bytes where x = slot + 1. Reconstruction happens at x = 0 by Lagrange interpolation, which is why x is never zero. In production the Shamir coefficients come from true randomness, which gives information-theoretic secrecy below k. That’s a stronger statement than “computationally hard”: with k-1 shares in hand, the shares themselves reveal nothing about the plaintext. Not a difficult problem, no information. Each node receives only the layer addressed to it. No node ever holds the full payload, and the committee as a whole never holds it either until enough of them choose to publish. Post. The trigger market contract takes the selected committee, the threshold k, the encrypted layers, the commitment to payload || nonce, the condition mode, the public condition record if there is one, trigger metadata, expiry configuration, and an optional hook. The post commits to the payload without exposing it. It emits TriggerPosted, which is the event nodes index to find out whether they’re on a committee, and it returns a triggerId. That triggerId is your integration point, and it’s where application design starts. The protocol tracks the Covenant. Your app has to know which auction, payout, or position it belongs to, what state should change when it resolves, and what should happen if it expires instead. Watch. Nodes index TriggerPosted, check whether they’re on the committee, open their own layer, and watch the condition. For a time window that’s checking when the trigger becomes eligible. For a price condition it’s following the configured feed and evaluating the threshold. Reveal. When the condition is satisfied, nodes call post_share, or post_shares_batched where efficiency matters. Each emits SharePosted. One share reveals nothing on its own. This is the part that makes a Covenant different from an encrypted message you hold the key to. After posting, you’ve committed. The reveal path runs on the committee observing the condition, not on you deciding to release anything. Below k shares, the payload stays sealed even if you want it open. Reconstruct. Once k valid shares are onchain, anyone can fetch the SharePosted events, combine a valid set, and reconstruct the plaintext locally. There’s a reconstructor payment path. The reconstructed plaintext has to hash to the commitment posted with the Covenant. If keccak256(payload || nonce) doesn’t match, the result isn’t accepted. That check is what makes reconstruction permissionless without being forgeable, anyone can do the work, nobody can substitute a different answer. Resolution happens once. After a trigger resolves, the protocol treats it as complete and the revealed plaintext is the source of truth. The author cannot cancel at this stage and cannot withhold the result: the shares are already public, and the system doesn’t depend on the author ever coming back online. Settle. Post_result emits TriggerResolved and calls your hook with the triggerId and plaintext. Strip the 32-byte nonce, decode, update state. Conditions in Dusk One price threshold, one time window, or both together. A price condition is an asset, a comparator, and a threshold; supported comparators are >= and <=. Time windows use Unix timestamps and must satisfy 0 < t1 < t2. Prices parse as exact decimal values, never floats. That’s deliberate: the condition is on the protocol path, and protocol behaviour can’t depend on floating-point rounding. Two nodes evaluating the same threshold have to reach the same answer. That's a narrow vocabulary and it's deliberate. No arbitrary logic, no multi-asset conditions, no external feeds. Nightside widens it; Dusk ships the part that works. Public or private, and what private actually buys you This is the most consequential choice you'll make, so here it is without spin. Public. The 52-byte record sits onchain in the clear. Anyone can audit the rule. Use this when the trigger needs to be verifiable, an auction close, a scheduled disclosure, a published threshold. Private. The condition is sealed inside the encrypted layers. The chain never sees it. Private mode hides the condition from the public. It does not prevent early reveal. Nothing onchain checks a private condition, because nothing onchain can read it. Any k of your selected nodes can reconstruct the payload whenever they choose, whether or not the condition ever became true. What the chain enforces is who can post a share and when a trigger expires. It does not enforce that the condition was real. So private mode buys secrecy from the public and nothing from your committee. Your trust is exactly as good as the nodes you picked. There’s a second consequence: a contract can't verify a condition it can’t read, so onchain logic has no way to independently confirm a private condition was satisfied as written. At Neon, conditions become private at the nodes themselves, they can establish that a condition has been met without ever ewing what it says. Choosing a committee You pick the committee, which makes committee selection part of your app’s trust and liveness design rather than an implementation detail. Dusk supports up to maxM = 16. Current testnet guidance is a practical shape like m = 3, k = 2 against nodes that are actually running. The two numbers pull against each other. A high k means more nodes have to collude before your payload can be opened early, better confidentiality. One thing to get right. The committee you seal against must be the committee you post against. Seal to one set and post to another and the encrypted layers won’t match the selected nodes. Looking end to end A sealed bid auction is the clearest example. The auction contract defines the bid format and creates a Covenant per bid. The bidder commits onchain; the post exposes nothing. Nodes hold encrypted shares and no single node can reconstruct a bid. At close, the condition is satisfied and nodes publish shares. Once k are available, each bid is reconstructed and checked against its commitment. The hook fires, your contract strips the nonce, decodes the bid, maps triggerId back to the auction, and records it. Don't assume reveals arrive in order. Record each bid safely as it lands and pick the winner in your own logic once the reveal path completes. The same shape covers confidential stops, prediction markets, schedules disclosures, dead-man’s switches, and parametric payouts. Commit to private data Bind it to a condition Split reveal across a committee Publish shares when condition holds Reconstruct at k Pass plaintext into your logic Build it Dusk is on Sepolia now and hits Ethereum mainnet late September, with the SDK shipping alongside it. Join our Discord and help shape it.