-
-
Save denniswon/32ba5dad6d44ee72de34710735a8d03e to your computer and use it in GitHub Desktop.
| --- | |
| Newton Privacy Layer vs Fairblock: Technical Comparison Analysis | |
| ★ Insight ───────────────────────────────────── | |
| This comparison covers two fundamentally different approaches to onchain privacy: | |
| - Newton extends an existing EigenLayer AVS (policy evaluation) with privacy primitives — privacy is an add-on to an existing | |
| validator network | |
| - Fairblock is a purpose-built privacy infrastructure chain (FairyRing) that exports cryptographic services to other chains | |
| - The cryptographic primitives overlap significantly (threshold DKG, IBE-like schemes), but the trust models and integration patterns | |
| diverge sharply | |
| ───────────────────────────────────────────────── | |
| --- | |
| 1. Architecture Overview | |
| Newton Privacy Layer | |
| ┌──────────────────┬───────────────────────────────────────────────────────────────────────────────┐ | |
| │ Component │ Description │ | |
| ├──────────────────┼───────────────────────────────────────────────────────────────────────────────┤ | |
| │ Secure Envelope │ HPKE (RFC 9180) encryption with AAD context binding (X25519/ChaCha20Poly1305) │ | |
| ├──────────────────┼───────────────────────────────────────────────────────────────────────────────┤ | |
| │ Authorization │ Offchain Ed25519 consent signatures validated by gateway │ | |
| ├──────────────────┼───────────────────────────────────────────────────────────────────────────────┤ | |
| │ Operator Network │ Existing EigenLayer AVS operators hold threshold key shares │ | |
| ├──────────────────┼───────────────────────────────────────────────────────────────────────────────┤ | |
| │ Gateway │ Trusted intermediary (Phase 1.5) → replaced by threshold DKG (Phase 2) │ | |
| ├──────────────────┼───────────────────────────────────────────────────────────────────────────────┤ | |
| │ Storage │ Encrypted data refs stored in gateway PostgreSQL (encrypted_data_refs table) │ | |
| └──────────────────┴───────────────────────────────────────────────────────────────────────────────┘ | |
| Data Flow (Phase 1.5 — current target): | |
| Client → HPKE encrypt to gateway pubkey → store encrypted envelope in DB | |
| → createTask with encrypted_data_refs | |
| → Gateway decrypts (single trusted party) | |
| → Operators evaluate policy on plaintext | |
| → BLS aggregate signatures → respond on-chain | |
| Data Flow (Phase 2 — future): | |
| Client → HPKE encrypt to threshold pubkey (DKG-derived) | |
| → Prepare Phase: each operator produces partial decryption | |
| → t-of-n threshold decryption reconstructs plaintext | |
| → Operators evaluate policy → BLS sign → aggregate | |
| Fairblock | |
| ┌───────────────────┬───────────────────────────────────────────────────────────────────────┐ | |
| │ Component │ Description │ | |
| ├───────────────────┼───────────────────────────────────────────────────────────────────────┤ | |
| │ FairyRing │ Cosmos SDK app-chain for decryption key management │ | |
| ├───────────────────┼───────────────────────────────────────────────────────────────────────┤ | |
| │ x/keyshare module │ Manages DKG, validator keyshare submission, aggregation │ | |
| ├───────────────────┼───────────────────────────────────────────────────────────────────────┤ | |
| │ x/pep module │ Pre-execution privacy: stores encrypted txs, decrypts at target block │ | |
| ├───────────────────┼───────────────────────────────────────────────────────────────────────┤ | |
| │ FairyPort │ IBC/cross-chain relayer for key distribution │ | |
| ├───────────────────┼───────────────────────────────────────────────────────────────────────┤ | |
| │ FairyKits │ Integration SDKs for Cosmos, EVM, RustVM chains │ | |
| ├───────────────────┼───────────────────────────────────────────────────────────────────────┤ | |
| │ Encryption SDK │ Client-side browser encryption (no third-party dependency) │ | |
| └───────────────────┴───────────────────────────────────────────────────────────────────────┘ | |
| Data Flow: | |
| Client → encrypt tx with Master Public Key + condition ID (e.g. block height) | |
| → submit encrypted tx to destination chain (stored in x/pep) | |
| → FairyRing validators monitor conditions | |
| → When condition met: validators submit keyshares | |
| → On-chain aggregation (2/3+1 threshold) | |
| → Aggregated key relayed to destination chain | |
| → x/pep decrypts + executes tx at BeginBlock | |
| --- | |
| 2. Cryptographic Primitives Comparison | |
| ┌─────────────────┬──────────────────────────────────────────────────┬───────────────────────────────────────────────────────────┐ | |
| │ Dimension │ Newton Privacy Layer │ Fairblock │ | |
| ├─────────────────┼──────────────────────────────────────────────────┼───────────────────────────────────────────────────────────┤ | |
| │ Core Encryption │ HPKE (X25519, HKDF-SHA256, ChaCha20Poly1305) per │ Threshold IBE (Boneh-Franklin on BLS12-381) + hybrid │ | |
| │ │ RFC 9180 │ ChaCha20Poly1305 │ | |
| ├─────────────────┼──────────────────────────────────────────────────┼───────────────────────────────────────────────────────────┤ | |
| │ Key Exchange │ X25519 Diffie-Hellman (DHKEM) │ Identity-Based Encryption (condition = "identity") │ | |
| ├─────────────────┼──────────────────────────────────────────────────┼───────────────────────────────────────────────────────────┤ | |
| │ Threshold │ Pedersen DKG (Phase 2, planned) │ Joint Feldman DKG (implemented, live) │ | |
| │ Scheme │ │ │ | |
| ├─────────────────┼──────────────────────────────────────────────────┼───────────────────────────────────────────────────────────┤ | |
| │ Signature │ Ed25519 (authorization) + BLS (attestation) │ Cosmos validator signatures │ | |
| ├─────────────────┼──────────────────────────────────────────────────┼───────────────────────────────────────────────────────────┤ | |
| │ Advanced │ MPC computation + ZK selective disclosure (Phase │ FHE (CKKS), SPDZ MPC, Twisted ElGamal, witness encryption │ | |
| │ (future) │ 3) │ │ | |
| ├─────────────────┼──────────────────────────────────────────────────┼───────────────────────────────────────────────────────────┤ | |
| │ AAD Binding │ Secure Envelope binds ciphertext to │ Condition ID binds to block height/price/event │ | |
| │ │ domain/policy/chain │ │ | |
| └─────────────────┴──────────────────────────────────────────────────┴───────────────────────────────────────────────────────────┘ | |
| ★ Insight ───────────────────────────────────── | |
| IBE vs HPKE is the key architectural divergence: | |
| - Fairblock's IBE allows encrypting to a condition (block height, price, event) without knowing the decryption key in advance — the | |
| key is derived later by validators. This enables batch decryption: one key decrypts ALL txs for that condition, saving N×S bandwidth | |
| to just S. | |
| - Newton's HPKE encrypts to a specific public key (gateway or threshold group). Decryption requires the key holder to actively | |
| participate. Each envelope must be decrypted individually. | |
| - Fairblock's IBE approach is provably more bandwidth-efficient for batch scenarios (their ePrint paper shows 99.6% bandwidth savings | |
| vs standard threshold decryption for 1000 messages). | |
| ───────────────────────────────────────────────── | |
| --- | |
| 3. Trust Model Comparison | |
| ┌─────────────────┬─────────────────────────────────────────────┬─────────────────────────────────────────────────────────────────┐ | |
| │ Dimension │ Newton │ Fairblock │ | |
| ├─────────────────┼─────────────────────────────────────────────┼─────────────────────────────────────────────────────────────────┤ | |
| │ Phase 1.5 │ Gateway is a single trusted decryptor — │ N/A (already threshold from start) │ | |
| │ (current) │ full plaintext access │ │ | |
| ├─────────────────┼─────────────────────────────────────────────┼─────────────────────────────────────────────────────────────────┤ | |
| │ Phase 2 │ t-of-n threshold — no single operator sees │ 2/3+1 validator threshold for key aggregation │ | |
| │ (planned) │ plaintext │ │ | |
| ├─────────────────┼─────────────────────────────────────────────┼─────────────────────────────────────────────────────────────────┤ | |
| │ Validator Set │ EigenLayer restaked operators (ETH economic │ Cosmos SDK validators (staked FAIRY tokens) │ | |
| │ │ security) │ │ | |
| ├─────────────────┼─────────────────────────────────────────────┼─────────────────────────────────────────────────────────────────┤ | |
| │ Slashing │ EigenLayer slashing conditions │ Custom slashing: slash_fraction_no_keyshare, │ | |
| │ │ │ slash_fraction_wrong_keyshare │ | |
| ├─────────────────┼─────────────────────────────────────────────┼─────────────────────────────────────────────────────────────────┤ | |
| │ Key Custody │ Operators hold HPKE key shares (Phase 2) │ Share Generation Client creates MSK each epoch, splits to │ | |
| │ │ │ validators, destroys MSK │ | |
| ├─────────────────┼─────────────────────────────────────────────┼─────────────────────────────────────────────────────────────────┤ | |
| │ Compliance │ Offchain Ed25519 consent signatures; audit │ Selective per-transaction disclosure; OFAC/MiCA compatible │ | |
| │ │ trail │ │ | |
| └─────────────────┴─────────────────────────────────────────────┴─────────────────────────────────────────────────────────────────┘ | |
| Newton's trust evolution: | |
| - Phase 1.5: Centralized trust — gateway sees all plaintext (stepping stone) | |
| - Phase 2: Threshold trust — t-of-n operators, no single party decrypts | |
| - Phase 3: MPC + ZK — computation on encrypted data, selective disclosure | |
| Fairblock's trust model: | |
| - Threshold from day one — 2/3+1 validators must collude to compromise | |
| - Epoch-based key rotation — MSK destroyed after distribution | |
| - On-chain aggregation — key reconstruction happens transparently on FairyRing | |
| --- | |
| 4. Decryption Model Comparison | |
| ┌──────────────────┬──────────────────────────────────────────────────────┬──────────────────────────────────────────────────────┐ | |
| │ Dimension │ Newton │ Fairblock │ | |
| ├──────────────────┼──────────────────────────────────────────────────────┼──────────────────────────────────────────────────────┤ | |
| │ Trigger │ Task creation (explicit RPC call) │ Condition satisfaction (block height, price, event, │ | |
| │ │ │ ZK proof) │ | |
| ├──────────────────┼──────────────────────────────────────────────────────┼──────────────────────────────────────────────────────┤ | |
| │ Granularity │ Per-envelope (each encrypted data ref decrypted │ Per-condition (one key decrypts ALL txs under that │ | |
| │ │ individually) │ condition) │ | |
| ├──────────────────┼──────────────────────────────────────────────────────┼──────────────────────────────────────────────────────┤ | |
| │ Timing │ On-demand during Prepare Phase │ Automatic at BeginBlock when condition met │ | |
| ├──────────────────┼──────────────────────────────────────────────────────┼──────────────────────────────────────────────────────┤ | |
| │ Bandwidth │ O(N × t) for N envelopes with t-of-n threshold │ O(S) for S validators, regardless of N encrypted txs │ | |
| ├──────────────────┼──────────────────────────────────────────────────────┼──────────────────────────────────────────────────────┤ | |
| │ Privacy Window │ Until operator decrypts during task evaluation │ Until condition is satisfied (can be indefinite) │ | |
| ├──────────────────┼──────────────────────────────────────────────────────┼──────────────────────────────────────────────────────┤ | |
| │ Who Sees │ Operators (during policy evaluation) │ Destination chain (after BeginBlock decryption) │ | |
| │ Plaintext │ │ │ | |
| └──────────────────┴──────────────────────────────────────────────────────┴──────────────────────────────────────────────────────┘ | |
| ★ Insight ───────────────────────────────────── | |
| Fairblock's conditional decryption is fundamentally more expressive. Newton decrypts when someone requests it (consent-gated). | |
| Fairblock decrypts when arbitrary on-chain conditions are met — block height, price feeds, ZK proof verification, governance vote | |
| deadlines. This enables use cases like sealed-bid auctions and MEV protection that Newton's consent model doesn't naturally support. | |
| However, Newton's consent model is more suited for compliance-oriented privacy — user controls who sees their data and when. | |
| Fairblock's condition-based model is more suited for market fairness (everyone's data revealed simultaneously). | |
| ───────────────────────────────────────────────── | |
| --- | |
| 5. Cross-Chain & Integration | |
| ┌─────────────────┬───────────────────────────────────────────────────┬──────────────────────────────────────────────────────────┐ | |
| │ Dimension │ Newton │ Fairblock │ | |
| ├─────────────────┼───────────────────────────────────────────────────┼──────────────────────────────────────────────────────────┤ | |
| │ Native Chain │ No own chain — runs on EigenLayer (Ethereum) │ FairyRing (Cosmos SDK app-chain) │ | |
| ├─────────────────┼───────────────────────────────────────────────────┼──────────────────────────────────────────────────────────┤ | |
| │ EVM Support │ Native (ECS Fargate services on Ethereum/L2s) │ Via FairyKits + precompiles embedded in EVM │ | |
| ├─────────────────┼───────────────────────────────────────────────────┼──────────────────────────────────────────────────────────┤ | |
| │ Cosmos Support │ Not supported │ Native via x/pep module + IBC │ | |
| ├─────────────────┼───────────────────────────────────────────────────┼──────────────────────────────────────────────────────────┤ | |
| │ Solana Support │ Not supported │ Planned │ | |
| ├─────────────────┼───────────────────────────────────────────────────┼──────────────────────────────────────────────────────────┤ | |
| │ Cross-Chain │ Newton's multichain architecture (source → │ FairyPort (IBC relayer) + direct FairyKit integration │ | |
| │ Relay │ destination chains) │ │ | |
| ├─────────────────┼───────────────────────────────────────────────────┼──────────────────────────────────────────────────────────┤ | |
| │ Integration │ SDK extension (@newton-protocol/sdk) + RPC calls │ FairyKit deployment + module integration or precompile │ | |
| │ Effort │ │ │ | |
| ├─────────────────┼───────────────────────────────────────────────────┼──────────────────────────────────────────────────────────┤ | |
| │ User Experience │ Encrypt via SDK, submit via RPC │ Encrypt in browser with Encryption SDK, submit to │ | |
| │ │ │ destination chain directly │ | |
| └─────────────────┴───────────────────────────────────────────────────┴──────────────────────────────────────────────────────────┘ | |
| --- | |
| 6. Product & Use Case Comparison | |
| ┌────────────────────────────┬─────────────────────────────────────────────────┬──────────────────────────────────────────────────┐ | |
| │ Use Case │ Newton │ Fairblock │ | |
| ├────────────────────────────┼─────────────────────────────────────────────────┼──────────────────────────────────────────────────┤ | |
| │ Private policy evaluation │ Core use case — privacy for Rego policy inputs │ Not applicable │ | |
| ├────────────────────────────┼─────────────────────────────────────────────────┼──────────────────────────────────────────────────┤ | |
| │ Sealed-bid auctions │ Not natively supported │ Core use case — condition-based reveal │ | |
| ├────────────────────────────┼─────────────────────────────────────────────────┼──────────────────────────────────────────────────┤ | |
| │ MEV/frontrunning │ Not designed for this │ Core use case — pre-execution encryption │ | |
| │ protection │ │ │ | |
| ├────────────────────────────┼─────────────────────────────────────────────────┼──────────────────────────────────────────────────┤ | |
| │ Private governance │ Possible via privacy extension │ Native support via encrypted votes │ | |
| ├────────────────────────────┼─────────────────────────────────────────────────┼──────────────────────────────────────────────────┤ | |
| │ Confidential stablecoins │ Not in scope │ StableTrust product (Twisted ElGamal + FHE) │ | |
| ├────────────────────────────┼─────────────────────────────────────────────────┼──────────────────────────────────────────────────┤ | |
| │ Compliance/KYC privacy │ Core design — consent-gated selective │ Supported via post-execution selective │ | |
| │ │ disclosure │ disclosure │ | |
| ├────────────────────────────┼─────────────────────────────────────────────────┼──────────────────────────────────────────────────┤ | |
| │ DeFi order privacy │ Possible but not primary │ Protected Trading product │ | |
| ├────────────────────────────┼─────────────────────────────────────────────────┼──────────────────────────────────────────────────┤ | |
| │ Private AI inference │ Not in scope │ Planned (FHE + MPC) │ | |
| └────────────────────────────┴─────────────────────────────────────────────────┴──────────────────────────────────────────────────┘ | |
| --- | |
| 7. Maturity & Implementation Status | |
| ┌────────────────────────────┬──────────────────────────────────────────────────┬─────────────────────────────────────────────────┐ | |
| │ Dimension │ Newton │ Fairblock │ | |
| ├────────────────────────────┼──────────────────────────────────────────────────┼─────────────────────────────────────────────────┤ | |
| │ Phase 1 (Foundation) │ 88% complete — HPKE, Ed25519, Secure Envelope, │ ✅ Live — IBE, DKG, keyshare aggregation, │ | |
| │ │ DB storage │ public testnet │ | |
| ├────────────────────────────┼──────────────────────────────────────────────────┼─────────────────────────────────────────────────┤ | |
| │ Phase 1.5 (Gateway │ 25% complete — gateway as trusted decryptor │ N/A (skipped centralized step entirely) │ | |
| │ Decryption) │ │ │ | |
| ├────────────────────────────┼──────────────────────────────────────────────────┼─────────────────────────────────────────────────┤ | |
| │ Phase 2 (Threshold DKG) │ 0% — Pedersen DKG, threshold decryption planned │ ✅ Live — Joint Feldman DKG with validator key │ | |
| │ │ │ shares │ | |
| ├────────────────────────────┼──────────────────────────────────────────────────┼─────────────────────────────────────────────────┤ | |
| │ Phase 3 (MPC/ZK) │ 0% — MPC framework, ZK selective disclosure │ In progress — CKKS FHE, SPDZ, confidential │ | |
| │ │ planned │ transfers │ | |
| ├────────────────────────────┼──────────────────────────────────────────────────┼─────────────────────────────────────────────────┤ | |
| │ Phase 4 (Ecosystem) │ 0% — L2 deployment, operator onboarding planned │ Active — Arbitrum, CoW Swap, AltLayer │ | |
| │ │ │ integrations │ | |
| ├────────────────────────────┼──────────────────────────────────────────────────┼─────────────────────────────────────────────────┤ | |
| │ Funding │ Self-funded (Magic Labs / Newton Foundation) │ $2.5M pre-seed (Galileo, Lemniscap, Dialectic, │ | |
| │ │ │ etc.) │ | |
| ├────────────────────────────┼──────────────────────────────────────────────────┼─────────────────────────────────────────────────┤ | |
| │ Team/Origin │ Extension of existing Newton Prover AVS │ Academic research from U of Waterloo (ePrint │ | |
| │ │ │ 2022/1066) │ | |
| └────────────────────────────┴──────────────────────────────────────────────────┴─────────────────────────────────────────────────┘ | |
| --- | |
| 8. Pros & Cons | |
| Newton Privacy Layer | |
| Pros: | |
| 1. Leverages existing infrastructure — EigenLayer economic security, existing operator set, existing BLS aggregation. No need to | |
| bootstrap a new validator set. | |
| 2. Compliance-first design — consent-based authorization with Ed25519 signatures and audit trails is naturally suited for regulated | |
| use cases (KYC/AML). | |
| 3. Progressive decentralization — pragmatic phased approach (gateway → threshold → MPC) reduces initial complexity and time-to-market. | |
| 4. Standards-based cryptography — HPKE (RFC 9180) is a well-audited, widely-implemented standard. No novel cryptographic assumptions. | |
| 5. Deep integration with policy evaluation — privacy is not a standalone product but an enhancement to an existing product with users | |
| (Rego policy engine). | |
| 6. Ethereum-native — no bridging, no Cosmos dependencies, no additional token. | |
| Cons: | |
| 1. Phase 1.5 is centralized — gateway as single decryptor is a significant trust assumption. One compromise exposes all privacy data. | |
| 2. No conditional decryption — decrypt-on-demand model doesn't support time-locked or condition-gated reveals (sealed auctions, MEV | |
| protection). | |
| 3. Per-envelope decryption overhead — each encrypted ref must be decrypted individually; no batch efficiency like IBE provides. | |
| 4. Narrow use case — primarily designed for private policy inputs. Not a general-purpose privacy layer for DeFi, governance, or | |
| stablecoins. | |
| 5. DKG not yet implemented — Phase 2 threshold operations are planned but 0% complete. The real decentralization story is still | |
| theoretical. | |
| 6. No own execution layer — depends on ECS Fargate infrastructure and gateway availability. Not censorship-resistant at the protocol | |
| level. | |
| Fairblock | |
| Pros: | |
| 1. Threshold from genesis — never had a centralized decryption phase. 2/3+1 validator threshold from day one. | |
| 2. IBE bandwidth efficiency — one decryption key covers ALL transactions under a condition. 99.6% bandwidth savings vs per-tx | |
| threshold decryption (proven in ePrint paper). | |
| 3. Expressive decryption conditions — block height, price, events, ZK proofs, custom conditions. Enables sealed auctions, MEV | |
| protection, private governance natively. | |
| 4. Multimodal cryptography — IBE, FHE (CKKS), MPC (SPDZ), witness encryption, Twisted ElGamal — selects the right tool per use case. | |
| 5. Purpose-built chain — FairyRing optimized for cryptographic operations with native BeginBlock decryption and execution. | |
| 6. Broad ecosystem — Cosmos, EVM (Arbitrum), rollups (AltLayer), CoW Swap integration, Solana planned. | |
| 7. Academic foundation — published research (ePrint 2022/1066), formal security analysis. | |
| Cons: | |
| 1. Requires own chain — FairyRing is an additional trust assumption and infrastructure dependency. Users/apps depend on Cosmos | |
| validator liveness. | |
| 2. New token requirement — validators stake FAIRY tokens; adds token economics complexity and bootstrapping challenge. | |
| 3. Cross-chain latency — IBC/FairyPort relaying introduces latency between condition satisfaction and destination chain execution. | |
| 4. Not Ethereum-native — EVM support via precompiles/FairyKits, but it's fundamentally a Cosmos-first architecture. Ethereum | |
| integration is bolt-on. | |
| 5. Centralized key generation step — Share Generation Client creates full MSK before splitting. If compromised during this brief | |
| window, all keys are exposed (mitigated by destroying MSK after distribution, but the window exists). | |
| 6. Complexity — multimodal cryptography means larger attack surface and more code to audit across IBE, FHE, MPC, and ZK subsystems. | |
| 7. No consent-based model — condition-gated decryption means data is revealed when conditions are met, regardless of whether the data | |
| owner still wants disclosure. Less suited for user-sovereign privacy. | |
| --- | |
| 9. What We Can Learn from Fairblock | |
| Architectural Lessons | |
| 1. Skip the centralized stepping stone. Fairblock launched with threshold DKG from day one. Our Phase 1.5 (gateway as trusted | |
| decryptor) is a pragmatic shortcut, but it introduces a real vulnerability window and delays the trust-minimized story. Consider | |
| accelerating Phase 2 DKG to reduce time spent in the centralized trust model. | |
| 2. Conditional decryption is a powerful primitive. Newton's consent-based model ("user signs to authorize decryption") is great for | |
| compliance but limited for market fairness use cases. Consider adding condition-gated decryption as a complementary mode — e.g., | |
| "decrypt this data at block height X" or "decrypt when price oracle reports Y." This could open sealed-auction and MEV-protection use | |
| cases without building a separate product. | |
| 3. Batch decryption via IBE. Our per-envelope HPKE decryption scales as O(N×t). Fairblock's IBE allows one key to decrypt all N | |
| envelopes under the same condition. If we ever need to decrypt many privacy envelopes simultaneously (e.g., batch policy evaluation), | |
| IBE-style schemes would be significantly more efficient. Worth evaluating for Phase 3. | |
| 4. On-chain key aggregation. Fairblock aggregates keyshares on-chain (in the x/keyshare module), making the process transparent and | |
| verifiable. Our Phase 2 plans to aggregate partial decryptions off-chain during the Prepare Phase. Consider whether some aggregation | |
| should be verifiable on-chain for auditability. | |
| 5. Epoch-based key rotation with MSK destruction. Fairblock's pattern of creating a new MSK each epoch, splitting it, and destroying | |
| the original is a clean forward-secrecy model. Our Phase 2 key rotation (NEWT-174/NEWT-189) should adopt a similar | |
| destroy-after-distribution pattern. | |
| 6. Validator slashing for privacy failures. Fairblock slashes validators who fail to submit keyshares or submit wrong ones | |
| (slash_fraction_no_keyshare, slash_fraction_wrong_keyshare). Our EigenLayer operators don't currently have privacy-specific slashing | |
| conditions. Phase 2 should define slashing for operators who fail to provide partial decryptions or provide incorrect ones. | |
| Product Lessons | |
| 7. Confidential stablecoins are a market opportunity. Fairblock's StableTrust product targets a clear institutional need. Newton's | |
| privacy layer could potentially be extended to support private transfer amounts in policy evaluation (e.g., "approve this transfer | |
| without revealing the amount to validators"). | |
| 8. Client-side encryption SDK. Fairblock emphasizes that encryption happens entirely in the browser with no third-party dependency. | |
| Our Newton SDK (NEWT-182) should similarly ensure all HPKE encryption is client-local with no server round-trips for the encryption | |
| step. | |
| 9. Precompile-based integration for EVMs. Fairblock embeds cryptographic operations as EVM precompiles, making integration as simple | |
| as calling a contract. For Phase 4 L2 deployment, consider whether Newton privacy operations could be offered as precompiles rather | |
| than requiring SDK integration. | |
| What NOT to Copy | |
| 10. Don't build a separate chain. Fairblock's FairyRing adds significant infrastructure and token economics overhead. Newton's | |
| strength is being Ethereum-native on EigenLayer — no bridging, no new token, no Cosmos dependency. Keep it that way. | |
| 11. Don't over-generalize. Fairblock tries to be everything (IBE + FHE + MPC + ZK + witness encryption). Newton should stay focused on | |
| consent-gated privacy for policy evaluation and expand narrowly to compliance use cases rather than trying to cover sealed auctions, | |
| MEV protection, and confidential stablecoins simultaneously. | |
| --- | |
| 10. Strategic Positioning | |
| ┌─────────────────────────────────────────────┐ | |
| │ PRIVACY DESIGN SPECTRUM │ | |
| │ │ | |
| User-Sovereign │ Newton ◄────────────────► Fairblock │ | |
| (Consent-Based) │ "I choose who sees" "Conditions decide"│ | |
| │ │ | |
| Compliance-First │ Newton ████████████░░ Fairblock ████░░░░ │ | |
| │ │ | |
| Market Fairness │ Newton ███░░░░░░░░░░ Fairblock █████████ │ | |
| │ │ | |
| Ethereum-Native │ Newton ██████████████ Fairblock ███░░░░░ │ | |
| │ │ | |
| Multi-Ecosystem │ Newton ███░░░░░░░░░░ Fairblock █████████ │ | |
| │ │ | |
| Production Ready │ Newton ████░░░░░░░░░ Fairblock ████████░ │ | |
| └─────────────────────────────────────────────┘ | |
| Bottom line: Newton and Fairblock occupy complementary niches. Newton is consent-based, compliance-first, Ethereum-native privacy for | |
| policy evaluation. Fairblock is condition-based, market-fairness-first, multi-ecosystem privacy for DeFi/trading. The biggest | |
| actionable takeaways for Newton are: (1) accelerate Phase 2 DKG to exit the centralized trust model, (2) consider adding conditional | |
| decryption as a complementary mode, and (3) adopt epoch-based key rotation with MSK destruction from the start. |
⏺ Memory file updated. Here's what changed:
Phase 2 section completely rewritten to reflect the Linear sync:
- 11 tickets across 4 sub-phases (was 7 flat tickets with no structure)
- Architecture decisions summary (FROST over Pedersen, Ristretto255, merged Prepare phase)
- Per-sub-phase tables with due dates, blocking relationships, and exit criteria
- Dependency graph showing the critical path: NEWT-638 → NEWT-176 → NEWT-178 → NEWT-630 → NEWT-629
- 4 new tickets captured: NEWT-638 (HPKE augmentation), NEWT-639 (EpochRegistry), NEWT-640 (PrivacySlasher),
NEWT-641 (DleqVerifier) - Key files that change section (from THRESHOLD_DKG.md)
- Technical risk items section highlighting the HPKE crate augmentation as highest risk
Other updates:
- Phase summary row updated: "Pedersen DKG" → "FROST DKG", "0/7" → "0/11"
- PR #424 added to open PRs
- Date bumped to 2026-03-08
- Removed the separate "Linear Issue Status" table (redundant with per-phase tables)
★ Insight ─────────────────────────────────────
The memory file now serves as a single source of truth linking Linear tickets to the docs/THRESHOLD_DKG.md
research synthesis. The dependency graph makes the critical path clear — NEWT-638 (HPKE crate augmentation) is the
gating item for the entire Phase 2A MVP, since threshold decryption can't work without open_with_precomputed_dh.
This is why it was created as a separate ticket rather than bundled into NEWT-176.
─────────────────────────────────────────────────
✻ Crunched for 5m 40s
❯ /claude-supermemory:super-save phase 2 plan of newton privacy layer for threshold dkg research and implementation
⏺ Let me save this Phase 2 Threshold DKG plan to Supermemory.
⏺ Bash(node "/Users/denniswon/.claude/plugins/cache/supermemory-plugins/claude-supermemory/0.0.1/scripts/save-projec
t-memory.cjs" "[SAVE:denniswon:2026-03-09]…)
⎿ Project knowledge saved: newton-prover-avs
ID: 9cHSozFhnpr4V62M8z1tGQ
⏺ Saved to Supermemory (ID: 9cHSozFhnpr4V62M8z1tGQ). The Phase 2 Threshold DKG execution plan — architecture
decisions, 4 sub-phase timeline, all 11 Linear tickets, dependency graph, and technical risks — is now persisted
across sessions.
PR created: https://github.com/newt-foundation/newton-prover-avs/pull/426
★ Insight ─────────────────────────────────────
Threshold decryption integration architecture: The key design choice here is the fallback pattern — when threshold
prerequisites aren't met (no threshold_ctx, insufficient partials, deserialization failure), the gateway
seamlessly falls back to centralized HPKE decryption (Phase 1 behavior). This means the feature can be deployed
without breaking existing privacy flows. Operators without threshold key shares simply don't return
partial_decryption data, and the gateway handles this gracefully.
Wire type separation: The PartialDecryptionData (serde-friendly Vec fields) vs dkg::PartialDecryption (curve
point/scalar types) split is intentional — JSON-RPC can't natively serialize Edwards points, so the wire format
uses raw bytes with From/TryFrom conversions at the boundary. This keeps crypto types out of the network layer.
─────────────────────────────────────────────────
Here's a summary of what NEWT-178 now covers across the two commits:
┌──────────┬─────────┬───────────────────────────────────────────────────────────────────────────────────┐
│ Commit │ Layer │ What │
├──────────┼─────────┼───────────────────────────────────────────────────────────────────────────────────┤
│ b23496c1 │ Layer 1 │ Decouple privacy data from policyTaskData — separate privacy_data channel │
├──────────┼─────────┼───────────────────────────────────────────────────────────────────────────────────┤
│ a93aad57 │ Layer 2 │ Threshold decryption integration — operator partial DH + gateway Lagrange combine │
└──────────┴─────────┴───────────────────────────────────────────────────────────────────────────────────┘
Remaining for full Phase 2 completion (separate tickets):
- NEWT-630: E2E test for threshold privacy + two-phase consensus
- NEWT-629: Gateway threshold config loading from DKG ceremony output (Phase 2C)
- Phase 2B: PSS epoch rotation, EpochRegistry contract
- Phase 2C: FROST ceremony replacing trusted dealer
Current Status: Phase 2 Threshold DKG
Branch/PR Stack (bottom to top)
main
└── #421 privacy-data-flow-fix ← fix: privacy data via separate channel
└── #422 multichain-routing-e2e-options ← feat: two-phase + attestation E2E options
└── #423 unified-e2e-runner ← feat: unified E2E with scenario presets
└── #424 phase2-threshold-dkg-docs ← docs: THRESHOLD_DKG.md
└── threshold-dkg ← empty (merge point, no PR yet)
└── #425 threshold-dkg-phase2a ← NEWT-176: Feldman VSS + DLEQ primitives
└── #426 threshold-consensus-integration ← NEWT-178: Two-Phase Consensus wiring
What's Implemented (3 commits, 3 branches)
Commit: 9ecf60ba
Branch: threshold-dkg-phase2a (PR #425)
Linear Ticket: NEWT-176
What: DKG primitives: crates/core/src/dkg/ — Feldman VSS, DLEQ proofs, Lagrange interpolation,
threshold_decrypt(),
compute_partial_decryption(), ThresholdConfig, KeyShare, unit tests
────────────────────────────────────────
Commit: b23496c1
Branch: threshold-consensus-integration (PR #426)
Linear Ticket: NEWT-178 (Layer 1)
What: Decouple privacy data from policyTaskData — separate ConsensusCommitRequest.privacy_data channel
────────────────────────────────────────
Commit: a93aad57
Branch: threshold-consensus-integration (PR #426)
Linear Ticket: NEWT-178 (Layer 2)
What: Wire threshold decryption into Two-Phase Consensus: operator computes partial DH in Prepare, gateway
combines
via Lagrange + fallback to centralized
Linear Ticket Status
┌──────────┬───────────────────────────────────┬─────────────┬────────────────────────────────────────────────┐
│ Ticket │ Title │ Status │ Notes │
├──────────┼───────────────────────────────────┼─────────────┼────────────────────────────────────────────────┤
│ │ HPKE crate augmentation — │ │ Implemented in │
│ NEWT-638 │ open_with_precomputed_dh │ Done │ crates/core/src/crypto/threshold.rs (post-DH │
│ │ │ │ pipeline) │
├──────────┼───────────────────────────────────┼─────────────┼────────────────────────────────────────────────┤
│ NEWT-176 │ Threshold decryption (t-of-n) — │ In Review │ Core DKG primitives, feature-gated behind │
│ │ Feldman VSS + DLEQ │ (PR #425) │ threshold │
├──────────┼───────────────────────────────────┼─────────────┼────────────────────────────────────────────────┤
│ NEWT-178 │ Threshold Decryption for │ In Review │ Operator + gateway wiring, fallback to │
│ │ Two-Phase Consensus │ (PR #426) │ centralized │
├──────────┼───────────────────────────────────┼─────────────┼────────────────────────────────────────────────┤
│ NEWT-177 │ DKG protocol — FROST on │ Backlog │ Phase 2C — full FROST ceremony replacing │
│ │ Ristretto255 │ │ trusted dealer │
├──────────┼───────────────────────────────────┼─────────────┼────────────────────────────────────────────────┤
│ NEWT-628 │ Epoch-based key rotation with PSS │ Backlog │ Phase 2B │
├──────────┼───────────────────────────────────┼─────────────┼────────────────────────────────────────────────┤
│ NEWT-630 │ On-chain aggregation commitments │ Backlog │ Phase 2C — depends on NEWT-178 │
├──────────┼───────────────────────────────────┼─────────────┼────────────────────────────────────────────────┤
│ NEWT-629 │ Privacy-specific operator │ Backlog │ Phase 2D — depends on NEWT-630 + NEWT-628 │
│ │ slashing │ │ │
└──────────┴───────────────────────────────────┴─────────────┴────────────────────────────────────────────────┘
What's NOT Done Yet
Phase 2A remaining:
- E2E test for threshold privacy + two-phase consensus — verifies the full pipeline with a trusted dealer
distributing shares, operators computing partials, gateway combining - Gateway threshold config loading — threshold_ctx is hardcoded to None; needs to be populated from a config file
or DKG ceremony output - Operator non-RPC path — core.rs:fetch_policy_data() (non-two-phase operator flow) doesn't have enc_point +
key_share wiring yet
Phase 2B (Weeks 5-7): PSS epoch rotation, EpochRegistry contract, destruction attestation
Phase 2C (Weeks 8-10): Full FROST ceremony (replace trusted dealer), on-chain Merkle root commitments, EigenDA
share storage
Phase 2D (Weeks 11-12): PrivacySlasher contract, DleqVerifier library (EIP-196), liveness slashing
Dependency Graph — Progress Overlay
NEWT-638 ✅ → NEWT-176 🔄 → NEWT-178 🔄 → NEWT-630 ⬜ → NEWT-629 ⬜
NEWT-177 ⬜ ──────────────↗ ↗
NEWT-177 ⬜ → NEWT-628 ⬜ ─────────────────────────↗
✅ = Done, 🔄 = In Review, ⬜ = Backlog
Recommended Next Steps (in order)
- Get PRs #421 → #422 → #423 → #424 merged — these are the base of the stack and need to land on main before the
DKG PRs can merge - Write Phase 2A E2E test — trusted dealer distributes Feldman VSS shares to 3 operators, run threshold privacy +
two-phase consensus E2E, verify decryption works - Add gateway threshold config loading — load ThresholdDecryptionContext from a JSON config file (operator public
shares, threshold params) so the gateway can actually use threshold mode - Update Linear tickets — mark NEWT-638 as Done, move NEWT-176 and NEWT-178 to In Review
- Phase 2B kickoff — NEWT-628 (PSS rotation) and NEWT-639 (EpochRegistry contract) can start once 2A is merged
★ Insight ─────────────────────────────────────
Phase 2A is architecturally complete — all the crypto primitives (Feldman VSS, DLEQ proofs, Lagrange
interpolation) and the Two-Phase Consensus wiring (operator partial DH + gateway combine + fallback) are
implemented and compiling. What remains is operationalization: config loading, E2E testing, and getting the base
PR stack merged. The critical path blocker is the 6-PR stack depth — PRs #421-#424 need to land before the DKG
code can reach main.
The fallback pattern is key to safe rollout: even after deploying threshold code, the gateway falls back to
centralized HPKE decryption when threshold_ctx is None or insufficient partials arrive. This means threshold mode
can be enabled per-deployment without breaking existing privacy flows.
─────────────────────────────────────────────────
★ Insight ─────────────────────────────────────
Three fixes applied to get clean compilation:
- Vec → &[u8; 32] (line 194): hex::decode returns Vec, but montgomery_to_edwards expects a fixed-size
array reference. The .as_slice().try_into() pattern is idiomatic Rust for this conversion — TryFrom<&[u8]> for
&[u8; N] checks length at runtime and returns an error if it doesn't match. - Ambiguous AsRef (line 422): alloy::primitives::FixedBytes<32> (returned by keccak256) implements both
AsRef<[u8; 32]> and AsRef<[u8]>. hex::encode accepts AsRef<[u8]>, but the compiler can't choose between the two
AsRef impls. Using .as_slice() explicitly selects the &[u8] variant. - Dead imports: ed25519_to_x25519_public, reqwest::Client, serde_json::Value, and uuid::Uuid were imported but
unused. The test utilities use the privacy module's upload_encrypted_data (which owns the HTTP client internally)
rather than constructing one directly.
─────────────────────────────────────────────────
Here's a summary of everything delivered:
File: integration-tests/src/threshold.rs
Change: New — DKG ceremony, threshold envelope creation, smoke test, full E2E runner (~467 lines)
────────────────────────────────────────
File: integration-tests/tests/threshold_e2e.rs
Change: New — test harness on port 8086
────────────────────────────────────────
File: integration-tests/src/lib.rs
Change: Added pub mod threshold;
────────────────────────────────────────
File: integration-tests/Cargo.toml
Change: Added threshold feature to core/gateway/operator deps
────────────────────────────────────────
File: crates/gateway/tests/{send_task,secrets_encrypted,chain_routing,watcher_endpoint}.rs
Change: Added #[cfg(feature = "threshold")] threshold: None
────────────────────────────────────────
File: Makefile
Change: Added threshold-e2e target with TWO_PHASE_CONSENSUS=true PRIVACY_ENABLED=true
Run with: make threshold-e2e
★ Insight ─────────────────────────────────────
Threshold decryption and multichain routing are orthogonal concerns. Threshold is about who decrypts (centralized
gateway vs distributed operators). Multichain routing is about where tasks go (which chain's ChainService handles
the task). The threshold code path in sync.rs (extract_enc_point_for_threshold, try_threshold_decrypt) is
identical regardless of which chain the task targets — it operates on the ChainServiceCtx.threshold_ctx which is
cloned from the gateway-level config to every chain service.
─────────────────────────────────────────────────
My recommendation: skip integration into multichain-routing-e2e for now. Here's why:
- Config construction mismatch: multichain-routing-e2e uses MultichainRoutingConfig →
MultiChainConfig::from_network() → Gateway::from_multi_chain_config(). Injecting ThresholdGatewayConfig into that
pipeline requires modifying MultichainRoutingConfig and the MultiChainConfig builder — nontrivial plumbing for a
feature that's still Phase 2A. - Encryption target changes: Privacy in multichain-routing encrypts to the gateway's ECDSA-derived HPKE key.
Threshold encrypts to the DKG master public key. These are different keys with different derivation paths.
Supporting both in one test means conditional encryption logic and more config branching. - No new code path exercised: The threshold logic in sync.rs doesn't branch on chain_id or multichain mode. If
threshold works for chain 31337, it works identically for chain 31338 — the same threshold_ctx is shared across
all ChainService instances. - Phase 2C is the right time: When FROST DKG replaces the trusted dealer, the DKG ceremony itself becomes
multichain-aware (operators on different chains participate). That's when integrating into multichain-routing-e2e
makes architectural sense.
What threshold-e2e tests (the current spec)
The test runs two phases:
Phase A — In-process crypto smoke test (no infrastructure)
- Runs 2-of-3 Feldman VSS DKG ceremony
- Encrypts test data ({"kyc_verified": true, "risk_score": 42}) to the threshold MPK
- Computes 2 partial decryptions from shares 1 and 3 (any 2-of-3 subset)
- Combines via Lagrange interpolation and verifies decrypted plaintext matches original
- Validates the full crypto pipeline works correctly before touching any infrastructure
Phase B — Full E2E with gateway + operator (requires anvil + Postgres)
- Runs 1-of-1 DKG ceremony (single operator can satisfy threshold)
- Injects ThresholdGatewayConfig into gateway and ThresholdOperatorConfig into operator
- Starts operator with key share on port 127.0.0.1:9013
- Starts gateway on port 8086 with threshold decryption context
- Encrypts privacy data to threshold MPK (not gateway's centralized key)
- Uploads encrypted data via newt_uploadEncryptedData
- Computes dual Ed25519 signatures (user + app) for privacy authorization
- Submits task with encrypted_data_refs + use_two_phase = true
- Verifies: task succeeds, BLS aggregation response is valid
- During Prepare phase: operator receives enc_point, computes partial DH + DLEQ proof
- During Commit: gateway combines partials, decrypts privacy data, passes via ConsensusCommitRequest.privacy_data
Run with: make threshold-e2e
SDK Privacy PRs — Protocol Alignment Analysis
PR #115 (feature/sdk-privacy-module) — HPKE Encryption
┌────────────────────────────────────┬────────┬───────────────────────────────────────────────────────────────────────────────┐
│ Check │ Status │ Detail │
├────────────────────────────────────┼────────┼───────────────────────────────────────────────────────────────────────────────┤
│ HPKE suite │ Match │ Both: X25519 KEM + HKDF-SHA256 + ChaCha20-Poly1305, Base mode │
├────────────────────────────────────┼────────┼───────────────────────────────────────────────────────────────────────────────┤
│ HPKE info param │ Match │ Both pass empty bytes (&[] / new Uint8Array(0)) │
├────────────────────────────────────┼────────┼───────────────────────────────────────────────────────────────────────────────┤
│ AAD computation │ Match │ Both: keccak256(encodePacked(policy_client_bytes, chain_id_be_u64)), strip 0x │
│ │ │ prefix │
├────────────────────────────────────┼────────┼───────────────────────────────────────────────────────────────────────────────┤
│ SecureEnvelope fields │ Match │ Identical: enc, ciphertext, policy_client, chain_id, recipient_pubkey │
├────────────────────────────────────┼────────┼───────────────────────────────────────────────────────────────────────────────┤
│ UploadEncryptedDataRpcRequest │ Match │ All 7 fields match Rust's UploadEncryptedDataRequest including required │
│ fields │ │ chain_id │
├────────────────────────────────────┼────────┼───────────────────────────────────────────────────────────────────────────────┤
│ chain_id required (not optional) │ Match │ Both sides: required u64/number per PR #421 fix │
└────────────────────────────────────┴────────┴───────────────────────────────────────────────────────────────────────────────┘
★ Insight ─────────────────────────────────────
The AAD computation is the most critical interop point. If SDK and Rust compute different AAD, the gateway cannot decrypt what the
SDK encrypts. Both implementations: (1) strip 0x prefix from policy_client, (2) decode to raw address bytes (20 bytes), (3)
encode chain_id as big-endian u64 (8 bytes), (4) concatenate, (5) keccak256. The SDK uses DataView.setUint32 twice for the u64 to
avoid BigInt — clever and correct.
─────────────────────────────────────────────────
PR #116 (feature/sdk-privacy-apis) — Dual Signatures + Key Generation
┌───────────────────────────────────────┬────────────┬────────────────────────────────────────────────────────────────────────┐
│ Check │ Status │ Detail │
├───────────────────────────────────────┼────────────┼────────────────────────────────────────────────────────────────────────┤
│ User message construction │ Match │ Both: encodePacked(policy_client, intent_hash, ref_id_1, ref_id_2, │
│ │ │ ...) where ref_ids are UTF-8 bytes │
├───────────────────────────────────────┼────────────┼────────────────────────────────────────────────────────────────────────┤
│ App message construction │ Match │ Both: encodePacked(policy_client, intent_hash, user_signature_bytes) │
├───────────────────────────────────────┼────────────┼────────────────────────────────────────────────────────────────────────┤
│ Digest computation │ Match │ Both: keccak256(message) then Ed25519 sign the 32-byte digest │
├───────────────────────────────────────┼────────────┼────────────────────────────────────────────────────────────────────────┤
│ Ed25519 sign/verify │ Compatible │ Rust: ed25519_dalek, SDK: @noble/curves/ed25519 — both implement │
│ │ │ standard Ed25519 (RFC 8032) │
├───────────────────────────────────────┼────────────┼────────────────────────────────────────────────────────────────────────┤
│ Key zeroing │ Match │ Both zeroize private key bytes after use │
├───────────────────────────────────────┼────────────┼────────────────────────────────────────────────────────────────────────┤
│ SubmitEvaluationRequestParams privacy │ Match │ encryptedDataRefs, userSignature, appSignature — all optional, │
│ fields │ │ matching Rust's CreateTaskRequest │
└───────────────────────────────────────┴────────────┴────────────────────────────────────────────────────────────────────────┘
PR #117 (feature/sdk-privacy-docs) — Documentation
┌─────────────────────────────────────┬─────────┬─────────────────────────────────────────────────────────────────────┐
│ Check │ Status │ Detail │
├─────────────────────────────────────┼─────────┼─────────────────────────────────────────────────────────────────────┤
│ Architecture diagram (README.md) │ Correct │ Shows gateway decrypts, broadcasts plaintext to operators │
├─────────────────────────────────────┼─────────┼─────────────────────────────────────────────────────────────────────┤
│ Signature scheme docs (concepts.md) │ Correct │ Accurately describes user + app dual-signature construction │
├─────────────────────────────────────┼─────────┼─────────────────────────────────────────────────────────────────────┤
│ AAD binding explanation │ Correct │ Correctly explains keccak256(encodePacked(policy_client, chain_id)) │
├─────────────────────────────────────┼─────────┼─────────────────────────────────────────────────────────────────────┤
│ Phase 1 limitations │ Correct │ Documents centralized gateway trust point, Phase 2 threshold DKG │
└─────────────────────────────────────┴─────────┴─────────────────────────────────────────────────────────────────────┘
Issues Found
- Stale doc: "merged into evaluation context" (PR #117, examples.md)
The last line of Example 4 in examples.md:
"The Rego policy receives all decrypted data merged into its evaluation context, so it can cross-reference identity and financial
information in a single evaluation pass."
After PR #421, privacy data is namespaced under data.data.privacy in the Rego context — it is NOT flat-merged into policyTaskData.
Data flows through the separate ConsensusCommitRequest.privacy_data channel. The statement should say something like: "The Rego
policy receives all decrypted data under data.data.privacy in the evaluation context."
Severity: Low — describes the internal data layout that SDK consumers don't directly control, but it could mislead Rego policy
authors about where to find privacy fields.
- recipient_pubkey naming confusion (both SDK and Rust)
In UploadEncryptedDataRequest/UploadEncryptedDataRpcRequest, the field recipient_pubkey actually receives the sender's
(uploader's) Ed25519 public key — used by the gateway to verify the envelope signature. The Rust doc comment says "Recipient
operator Ed25519 public key" which is inaccurate.
In the SDK: recipient_pubkey: senderPublicKey — the variable name makes the confusion explicit.
Meanwhile, SecureEnvelope.recipient_pubkey stores the gateway's X25519 key (the actual encryption recipient).
Two fields named recipient_pubkey meaning different things in different structs.
Severity: Low — functionally correct (SDK and Rust agree on what goes where), but naming is misleading. Should be renamed to
sender_pubkey or signer_pubkey on the upload request to distinguish from the envelope's recipient_pubkey. This should be a
coordinated rename across both repos.
- Missing user_pubkey/app_pubkey in CreateTaskRequest (known gap)
The Rust validate_privacy_signatures() requires user_pubkey: &[u8; 32] and app_pubkey: &[u8; 32], but:
- CreateTaskRequest only has user_signature and app_signature — no public key fields
- validate_privacy_signatures is not yet called from the task creation handler in sync.rs
- The SDK's SubmitEvaluationRequestParams also has no public key fields
When the gateway enforces signature validation (presumably before production launch), either:
- Both Rust CreateTaskRequest and SDK SubmitEvaluationRequestParams will need user_pubkey and app_pubkey fields added
- OR the gateway derives user_pubkey from the upload record's recipient_pubkey (stored during uploadEncryptedData) and adds
app_pubkey to the request only
The SDK already computes and returns both public keys from signPrivacyAuthorization() (userPublicKey, appPublicKey), so the data
is available — it just doesn't flow into the task submission request yet.
Severity: Medium — not broken today (validation isn't enforced), but will require a coordinated SDK + gateway change before
signature enforcement goes live. Track this.
- SendTaskRequest missing privacy fields (Rust side)
CreateTaskRequest (sync path) has encrypted_data_refs, user_signature, app_signature, but SendTaskRequest (async path, line 56 of
types/mod.rs) does NOT have these fields. Privacy-enabled tasks won't work through the async newt_sendTask endpoint.
Severity: Low for Phase 1 (privacy tasks use the sync path), but should be addressed when expanding privacy support to the async
path.
Summary
Phase 1 SDK-Protocol alignment is solid. The three critical interop points all match:
- HPKE encryption (suite, AAD, info, envelope format) — exact match
- Dual-signature scheme (message construction, digest, Ed25519 compat) — exact match
- RPC request types (UploadEncryptedDataRpcRequest, privacy fields on task creation) — exact match
The four issues found are all low-to-medium severity future work items, not blocking for Phase 1. The most actionable one is the
stale doc in examples.md (issue #1), which can be fixed in PR #117 before merge. The recipient_pubkey rename (issue #2) and
missing public keys for signature enforcement (issue #3) should be tracked as follow-up work.
★ Insight ─────────────────────────────────────
The SDK is slightly ahead of the gateway in one respect: it implements and returns the dual-signature public keys
(signPrivacyAuthorization returns userPublicKey and appPublicKey), but neither the gateway's CreateTaskRequest nor the SDK's
SubmitEvaluationRequestParams sends them. When the gateway wires validate_privacy_signatures into the task creation handler, both
sides need to add the pubkey fields — but the SDK already has the data ready.
─────────────────────────────────────────────────
Pushed 727f739. All deferred items are now done:
┌──────────────────────────────────┬───────────────────────────────────────────────────────────────────┬──────────────────────────────┐
│ Item │ Fix │ File │
├──────────────────────────────────┼───────────────────────────────────────────────────────────────────┼──────────────────────────────┤
│ Privacy methods undocumented │ Added full section with 6 methods, signatures, params, examples │ sdk-reference.mdx │
├──────────────────────────────────┼───────────────────────────────────────────────────────────────────┼──────────────────────────────┤
│ Privacy types missing │ Added 6 expandable type definitions │ sdk-reference.mdx │
├──────────────────────────────────┼───────────────────────────────────────────────────────────────────┼──────────────────────────────┤
│ precomputePolicyId missing │ Added optional blockTimestamp?: bigint, made expireAfter optional │ sdk-reference.mdx │
│ params │ │ │
├──────────────────────────────────┼───────────────────────────────────────────────────────────────────┼──────────────────────────────┤
│ any types in signatures │ Changed to unknown in evaluateIntentDirect and │ sdk-reference.mdx │
│ │ AggregationResponse │ │
├──────────────────────────────────┼───────────────────────────────────────────────────────────────────┼──────────────────────────────┤
│ console.log leak │ Removed all 3 console statements, added no-op handlers │ task-events.ts │
├──────────────────────────────────┼───────────────────────────────────────────────────────────────────┼──────────────────────────────┤
│ wasmArgs wrong level │ Removed invalid top-level wasmArgs from example │ frontend-sdk-integration.mdx │
├──────────────────────────────────┼───────────────────────────────────────────────────────────────────┼──────────────────────────────┤
│ Stale gateway URL in JSDoc │ Updated to gateway.testnet.newton.xyz │ task-events.ts │
└──────────────────────────────────┴───────────────────────────────────────────────────────────────────┴──────────────────────────────┘
Zero deferred items remaining.
What's Next for Phase 2
The next item to tackle is the Phase 2A gateway/operator integration gaps — the 5 remaining pieces that wire the
threshold decryption crypto (already code-complete in PRs #426-429) into the actual runtime.
However, these integration items depend on PRs #426-429 being merged to main first. So there's a fork:
Option A: Wait for PR merge, then integrate (recommended)
The PRs need reviewer attention. Once #426 merges, the integration work can start on a new branch off main. The 5 items
are:
┌─────┬────────────────────────────┬───────────────────────────────────────────────────────────┬─────────────────────┐
│ # │ Item │ Why It's Next │ Effort │
├─────┼────────────────────────────┼───────────────────────────────────────────────────────────┼─────────────────────┤
│ │ enc_point in │ Without this, the gateway can't send the HPKE │ Small — add one │
│ 1 │ ConsensusPrepareRequest │ encapsulated key to operators during Prepare phase — │ field to the RPC │
│ │ │ operators have nothing to compute partial decryptions on │ request type │
├─────┼────────────────────────────┼───────────────────────────────────────────────────────────┼─────────────────────┤
│ │ Threshold context on │ Gateway needs ThresholdDecryptionContext (MPK + operator │ Medium — config │
│ 2 │ ChainService │ public shares) loaded per-chain at startup so the │ loading + per-chain │
│ │ │ threshold decrypt path in sync.rs can actually run │ init │
├─────┼────────────────────────────┼───────────────────────────────────────────────────────────┼─────────────────────┤
│ │ Operator keyshare loading │ Operator must load ThresholdOperatorConfig from TOML and │ Small — config │
│ 3 │ at startup │ hold KeyShare in memory for partial decryption │ wiring in │
│ │ │ │ builder.rs │
├─────┼────────────────────────────┼───────────────────────────────────────────────────────────┼─────────────────────┤
│ │ newt_getPrivacyPublicKey │ RPC must return threshold MPK instead of gateway's │ Small — conditional │
│ 4 │ switch │ individual key when threshold is configured, so clients │ return │
│ │ │ encrypt to the right key │ │
├─────┼────────────────────────────┼───────────────────────────────────────────────────────────┼─────────────────────┤
│ │ Single-phase consensus │ Privacy tasks using single-phase mode have no Prepare │ Design decision — │
│ 5 │ decision │ phase. Need to either add a decrypt round or reject │ small code either │
│ │ │ privacy+single-phase │ way │
└─────┴────────────────────────────┴───────────────────────────────────────────────────────────┴─────────────────────┘
These are all in the newton-prover-avs repo and collectively complete NEWT-178 (the parent issue "Threshold Decryption
for Two-Phase Consensus").
Option B: Start Phase 2B (Epoch/PSS) in parallel
If you want to keep moving while PRs are in review, Phase 2B work is independent at the Solidity contract level —
EpochRegistry.sol (NEWT-639) can be designed and written without waiting for the Rust PRs to merge. This is net-new
contract code with no dependencies on the threshold Rust crate.
EXPANSION_COMPLETE
The analysis reveals something important: the 5 integration items I originally identified are already implemented on the
feature branches. The actual gaps are more subtle but critical:
┌──────────────────────────────────────────────┬─────────────────────────────────────────────────────────┐
│ Original Assumption │ Reality │
├──────────────────────────────────────────────┼─────────────────────────────────────────────────────────┤
│ enc_point in ConsensusPrepareRequest missing │ Already wired (rpc_server.rs:178, common.rs:366-396) │
├──────────────────────────────────────────────┼─────────────────────────────────────────────────────────┤
│ Threshold context on ChainService missing │ Already loaded (handler/mod.rs:638-663, cloned at 1419) │
├──────────────────────────────────────────────┼─────────────────────────────────────────────────────────┤
│ Operator keyshare loading missing │ Already done (builder.rs:247-270, core.rs:75) │
├──────────────────────────────────────────────┼─────────────────────────────────────────────────────────┤
│ Full threshold decrypt pipeline missing │ Already wired (sync.rs:845-960, 1375-1545) │
├──────────────────────────────────────────────┼─────────────────────────────────────────────────────────┤
│ E2E test missing │ Already exists (threshold.rs, threshold_e2e.rs) │
└──────────────────────────────────────────────┴─────────────────────────────────────────────────────────┘
The real gaps are:
- newt_getPrivacyPublicKey always returns centralized key — clients encrypt to wrong key when threshold is configured
- No validation rejecting privacy+single-phase+threshold — silent decryption failure
- Multi-envelope threshold only handles first envelope — rest silently ignored
- Threshold→centralized fallback is useless — different keys, both fail (should remove misleading fallback)
- No Prometheus metric for threshold decrypt path
Linear vs Research Sync Analysis
Here's what I found by comparing the 7 Linear tickets against docs/THRESHOLD_DKG.md:
Sync Issues Found
┌────────────────┬──────────────────────────────────────────────────────────────────────┬───────────────────────────────────────┐
│ Issue │ Problem │ Action Needed │
├────────────────┼──────────────────────────────────────────────────────────────────────┼───────────────────────────────────────┤
│ NEWT-177 │ Describes Pedersen DKG (4 phases, ark-ec/blstrs), but research │ Update description to FROST │
│ │ recommends FROST DKG (2 rounds, frost-ristretto255) on Ristretto255 │ │
├────────────────┼──────────────────────────────────────────────────────────────────────┼───────────────────────────────────────┤
│ NEWT-177 │ References G1Point/BLS12-381 types, not Ristretto255 │ Update types to Ristretto255 │
├────────────────┼──────────────────────────────────────────────────────────────────────┼───────────────────────────────────────┤
│ NEWT-629 │ Labeled "[Privacy P3]" but belongs in Phase 2 sub-phase 2D │ Rename prefix to "[Privacy P2D]" │
├────────────────┼──────────────────────────────────────────────────────────────────────┼───────────────────────────────────────┤
│ NEWT-630 │ Labeled "[Privacy P4]" but belongs in Phase 2 sub-phase 2C │ Rename prefix to "[Privacy P2C]" │
├────────────────┼──────────────────────────────────────────────────────────────────────┼───────────────────────────────────────┤
│ All 4 original │ Due dates set to Feb 2026 (past) │ Clear or reset │
│ tickets │ │ │
├────────────────┼──────────────────────────────────────────────────────────────────────┼───────────────────────────────────────┤
│ NEWT-628, 629, │ No assignee │ Assign to dennis.won │
│ 630 │ │ │
├────────────────┼──────────────────────────────────────────────────────────────────────┼───────────────────────────────────────┤
│ Missing │ No ticket for HPKE crate augmentation (open_with_precomputed_dh) │ Create new ticket │
├────────────────┼──────────────────────────────────────────────────────────────────────┼───────────────────────────────────────┤
│ Missing │ No ticket for DLEQ proof module │ Covered implicitly in NEWT-176 but │
│ │ │ deserves explicit sub-task │
├────────────────┼──────────────────────────────────────────────────────────────────────┼───────────────────────────────────────┤
│ Missing │ No ticket for EpochRegistry contract │ Create new ticket under NEWT-628 │
├────────────────┼──────────────────────────────────────────────────────────────────────┼───────────────────────────────────────┤
│ Missing │ No ticket for PrivacySlasher contract │ Create new ticket under NEWT-629 │
├────────────────┼──────────────────────────────────────────────────────────────────────┼───────────────────────────────────────┤
│ NEWT-174 vs │ │ NEWT-174 = Rust implementation; │
│ NEWT-628 │ Significant overlap (both describe PSS, epoch rotation) │ NEWT-628 = full spec including │
│ │ │ contract │
└────────────────┴──────────────────────────────────────────────────────────────────────┴───────────────────────────────────────┘
★ Insight ─────────────────────────────────────
Why FROST over Pedersen: The original Linear tickets were written before the research deep-dive. Pedersen DKG (NEWT-177's current
spec) has 3-4 rounds and requires a separate complaint/dispute phase. FROST DKG (RFC 9591) achieves the same security in 2 rounds
with built-in proof-of-knowledge, and has a production Rust crate (frost-ristretto255) from the ZCash Foundation. The X25519 clamping
issue (which breaks Shamir) makes Ristretto255 mandatory regardless of which DKG protocol we use.
─────────────────────────────────────────────────
Detailed Execution Plan
Sub-Phase 2A: MVP Threshold Decrypt (3-4 weeks)
Goal: Trusted dealer Feldman VSS, threshold decryption with DLEQ proofs, E2E test on local anvil.
Linear tickets: NEWT-177 (partial), NEWT-176
Week 1: Crypto Foundation
┌───────────────────────────────┬────────────────────────────────────┬──────────────────────────────────────────────────────────┐
│ Task │ Files │ Details │
├───────────────────────────────┼────────────────────────────────────┼──────────────────────────────────────────────────────────┤
│ Add vsss-rs and │ crates/core/Cargo.toml │ Feature-gate behind privacy-threshold │
│ curve25519-dalek v4 deps │ │ │
├───────────────────────────────┼────────────────────────────────────┼──────────────────────────────────────────────────────────┤
│ Implement Feldman VSS dealer │ crates/core/src/dkg/keyshare.rs │ generate_shares(secret, threshold, n) -> Vec + │
│ │ (new) │ verification vector │
├───────────────────────────────┼────────────────────────────────────┼──────────────────────────────────────────────────────────┤
│ Implement DLEQ proofs │ crates/core/src/dkg/dleq.rs (new) │ prove(sk_i, enc_point) -> DleqProof, verify(pk_i, │
│ │ │ enc_point, D_i, proof) -> bool │
├───────────────────────────────┼────────────────────────────────────┼──────────────────────────────────────────────────────────┤
│ Ristretto255 <-> Montgomery │ crates/core/src/dkg/convert.rs │ ristretto_to_montgomery() for HPKE compatibility │
│ conversion │ (new) │ │
├───────────────────────────────┼────────────────────────────────────┼──────────────────────────────────────────────────────────┤
│ Unit tests for all crypto │ crates/core/src/dkg/mod.rs │ Round-trip VSS, DLEQ verification, conversion │
│ primitives │ │ correctness │
└───────────────────────────────┴────────────────────────────────────┴──────────────────────────────────────────────────────────┘
Week 2: HPKE Threshold Path
┌────────────────────────────────┬────────────────────────────────────┬──────────────────────────────────────────────────────────┐
│ Task │ Files │ Details │
├────────────────────────────────┼────────────────────────────────────┼──────────────────────────────────────────────────────────┤
│ Fork/augment hpke crate │ crates/core/src/crypto/hpke.rs │ Add open_with_precomputed_dh(shared_secret, enc, ct, │
│ │ │ aad) that skips KEM │
├────────────────────────────────┼────────────────────────────────────┼──────────────────────────────────────────────────────────┤
│ Implement │ │ Accepts Vec<(OperatorId, PartialDecryption, DleqProof)>, │
│ decrypt_envelopes_threshold() │ crates/core/src/crypto/envelope.rs │ verifies proofs, Lagrange-interpolates, calls │
│ │ │ open_with_precomputed_dh │
├────────────────────────────────┼────────────────────────────────────┼──────────────────────────────────────────────────────────┤
│ Threshold decryption │ crates/core/src/dkg/tests/ │ Encrypt with MPK.to_montgomery(), decrypt with t-of-n │
│ integration test │ │ partials │
└────────────────────────────────┴────────────────────────────────────┴──────────────────────────────────────────────────────────┘
Week 3: Operator + Gateway Integration
┌───────────────────────────────────────┬─────────────────────────────────────┬──────────────────────────────────────────────────┐
│ Task │ Files │ Details │
├───────────────────────────────────────┼─────────────────────────────────────┼──────────────────────────────────────────────────┤
│ DkgConfig on operator │ crates/operator/src/config.rs │ keyshare_path, threshold, epoch_id │
├───────────────────────────────────────┼─────────────────────────────────────┼──────────────────────────────────────────────────┤
│ Keyshare loading at operator startup │ crates/operator/src/builder.rs │ Load from encrypted keystore file │
├───────────────────────────────────────┼─────────────────────────────────────┼──────────────────────────────────────────────────┤
│ newt_partialDecrypt RPC handler │ crates/operator/src/core.rs │ Compute D_i = s_i * enc_ristretto, generate DLEQ │
│ │ │ proof, return PartialDecryptionResponse │
├───────────────────────────────────────┼─────────────────────────────────────┼──────────────────────────────────────────────────┤
│ partial_decryption + dleq_proof on │ crates/aggregator/src/rpc_server.rs │ New optional fields │
│ ConsensusPrepareResponse │ │ │
├───────────────────────────────────────┼─────────────────────────────────────┼──────────────────────────────────────────────────┤
│ Gateway threshold decryption path │ crates/gateway/src/rpc/api/sync.rs │ In Prepare phase: collect partials, verify DLEQ, │
│ │ │ Lagrange-combine, decrypt │
├───────────────────────────────────────┼─────────────────────────────────────┼──────────────────────────────────────────────────┤
│ Threshold MPK on ChainService │ crates/gateway/src/handler/mod.rs │ Replace single HPKE key with epoch-aware MPK │
└───────────────────────────────────────┴─────────────────────────────────────┴──────────────────────────────────────────────────┘
Week 4: E2E Test + Polish
┌──────────────────────────────┬───────────────────────────────────────┬─────────────────────────────────────────────────────────┐
│ Task │ Files │ Details │
├──────────────────────────────┼───────────────────────────────────────┼─────────────────────────────────────────────────────────┤
│ Trusted dealer test fixture │ integration-tests/src/threshold.rs │ Generate VSS shares for N operators, distribute via │
│ generator │ (new) │ config files │
├──────────────────────────────┼───────────────────────────────────────┼─────────────────────────────────────────────────────────┤
│ Threshold privacy E2E test │ integration-tests/tests/e2e.rs │ make e2e scenario=threshold-privacy — encrypt to MPK, 2 │
│ │ │ operators partial-decrypt, gateway combines │
├──────────────────────────────┼───────────────────────────────────────┼─────────────────────────────────────────────────────────┤
│ newt_getPrivacyPublicKey │ crates/gateway/src/rpc/api/privacy.rs │ Epoch-aware: returns current epoch's MPK │
│ returns MPK │ │ │
├──────────────────────────────┼───────────────────────────────────────┼─────────────────────────────────────────────────────────┤
│ Metrics for threshold │ crates/metrics/src/lib.rs │ privacy_threshold_decrypt_duration, │
│ decryption │ │ privacy_dleq_verify_count │
└──────────────────────────────┴───────────────────────────────────────┴─────────────────────────────────────────────────────────┘
Exit criteria: Local anvil E2E passes with t=2, n=3 threshold decrypt using Feldman VSS dealer-generated shares.
Sub-Phase 2B: Epoch Rotation + PSS (2-3 weeks)
Goal: Epoch-based key rotation via PSS, EpochRegistry contract, old share destruction attestation.
Linear tickets: NEWT-628, NEWT-174
Week 5: PSS Protocol
┌───────────────────────────┬─────────────────────────────────────┬─────────────────────────────────────────────────────────────┐
│ Task │ Files │ Details │
├───────────────────────────┼─────────────────────────────────────┼─────────────────────────────────────────────────────────────┤
│ PSS refresh protocol │ crates/core/src/dkg/pss.rs (new) │ Each operator generates zero-secret polynomial, │
│ │ │ redistributes shares │
├───────────────────────────┼─────────────────────────────────────┼─────────────────────────────────────────────────────────────┤
│ EpochMetadata types │ crates/core/src/dkg/epoch.rs (new) │ EpochMetadata, `EpochStatus::Active │
├───────────────────────────┼─────────────────────────────────────┼─────────────────────────────────────────────────────────────┤
│ Epoch-aware keyshare │ crates/operator/src/keystore.rs │ Store multiple epoch shares, zeroize expired shares via │
│ storage │ (new) │ zeroize crate │
├───────────────────────────┼─────────────────────────────────────┼─────────────────────────────────────────────────────────────┤
│ Destruction attestation │ crates/operator/src/core.rs │ Ed25519-sign (epoch_id, "destroyed"), submit to gateway │
└───────────────────────────┴─────────────────────────────────────┴─────────────────────────────────────────────────────────────┘
Week 6: EpochRegistry Contract
┌──────────────────────────┬─────────────────────────────────────────┬───────────────────────────────────────────────────────────┐
│ Task │ Files │ Details │
├──────────────────────────┼─────────────────────────────────────────┼───────────────────────────────────────────────────────────┤
│ │ contracts/src/core/EpochRegistry.sol │ registerEpoch(epochId, mpk, operatorSetHash, threshold), │
│ EpochRegistry.sol │ (new) │ getCurrentEpoch(), recordDestruction(epochId, │
│ │ │ operatorSig) │
├──────────────────────────┼─────────────────────────────────────────┼───────────────────────────────────────────────────────────┤
│ Forge tests for │ contracts/test/EpochRegistry.t.sol │ Epoch transitions, grace period expiry, destruction │
│ EpochRegistry │ (new) │ recording │
├──────────────────────────┼─────────────────────────────────────────┼───────────────────────────────────────────────────────────┤
│ Rust bindings + make │ crates/core/src/generated/ │ Auto-generated │
│ generate-bindings │ │ │
├──────────────────────────┼─────────────────────────────────────────┼───────────────────────────────────────────────────────────┤
│ Gateway epoch │ crates/gateway/src/dkg/coordinator.rs │ Trigger rotation at epoch boundary (block-based), │
│ coordinator │ (new) │ orchestrate PSS, publish MPK │
└──────────────────────────┴─────────────────────────────────────────┴───────────────────────────────────────────────────────────┘
Week 7: Integration + E2E
┌──────────────────────────────┬───────────────────────────────────────┬────────────────────────────────────────────────────────┐
│ Task │ Files │ Details │
├──────────────────────────────┼───────────────────────────────────────┼────────────────────────────────────────────────────────┤
│ │ integration-tests/tests/epoch.rs │ Rotate 3 epochs, verify: old shares zeroed, new MPK │
│ Epoch rotation E2E test │ (new) │ works, grace period decryption works, expired epoch │
│ │ │ fails │
├──────────────────────────────┼───────────────────────────────────────┼────────────────────────────────────────────────────────┤
│ newt_getPrivacyPublicKey │ crates/gateway/src/rpc/api/privacy.rs │ Return {mpk, epoch_id, expires_at_block} │
│ epoch-aware │ │ │
├──────────────────────────────┼───────────────────────────────────────┼────────────────────────────────────────────────────────┤
│ Emergency rotation admin │ crates/cli/src/commands/ │ make admin command=rotate_epoch │
│ command │ │ │
└──────────────────────────────┴───────────────────────────────────────┴────────────────────────────────────────────────────────┘
Exit criteria: Epoch rotation works on local anvil. Old epoch shares zeroed. Grace period decryption verified. Forward secrecy
integration test passes.
Sub-Phase 2C: Full FROST DKG + On-Chain Commitments (2-3 weeks)
Goal: Replace trusted dealer with trustless FROST DKG ceremony. Add on-chain decryption commitments.
Linear tickets: NEWT-177 (full), NEWT-630
Week 8-9: FROST DKG Ceremony
┌────────────────────────────────────┬───────────────────────────────────────┬───────────────────────────────────────────────────┐
│ Task │ Files │ Details │
├────────────────────────────────────┼───────────────────────────────────────┼───────────────────────────────────────────────────┤
│ Add frost-ristretto255 dep │ crates/core/Cargo.toml │ Feature-gate behind frost-dkg │
├────────────────────────────────────┼───────────────────────────────────────┼───────────────────────────────────────────────────┤
│ FROST Round 1 (commitments + PoK) │ crates/core/src/dkg/frost.rs (new) │ Wraps frost-ristretto255 API │
├────────────────────────────────────┼───────────────────────────────────────┼───────────────────────────────────────────────────┤
│ FROST Round 2 (share distribution) │ crates/core/src/dkg/frost.rs │ Encrypted share delivery via existing HPKE │
├────────────────────────────────────┼───────────────────────────────────────┼───────────────────────────────────────────────────┤
│ DKG ceremony coordinator service │ crates/gateway/src/dkg/coordinator.rs │ Orchestrate 2-round ceremony across operators via │
│ │ │ HTTP/JSON-RPC │
├────────────────────────────────────┼───────────────────────────────────────┼───────────────────────────────────────────────────┤
│ Operator DKG participation handler │ crates/operator/src/builder.rs │ newt_dkgRound1, newt_dkgRound2 RPC handlers │
├────────────────────────────────────┼───────────────────────────────────────┼───────────────────────────────────────────────────┤
│ DKG ceremony trigger on operator │ crates/gateway/src/handler/mod.rs │ Listen for OperatorAddedToOperatorSet events │
│ set change │ │ │
└────────────────────────────────────┴───────────────────────────────────────┴───────────────────────────────────────────────────┘
Week 9-10: On-Chain Commitments
┌────────────────────────────────────┬────────────────────────────────────────────────┬──────────────────────────────────────────┐
│ Task │ Files │ Details │
├────────────────────────────────────┼────────────────────────────────────────────────┼──────────────────────────────────────────┤
│ DecryptionCommitment type │ crates/core/src/dkg/commitment.rs (new) │ compute(epoch_id, task_id, partials, │
│ │ │ result) -> H256 │
├────────────────────────────────────┼────────────────────────────────────────────────┼──────────────────────────────────────────┤
│ Add decryption_commitment to │ contracts/src/core/NewtonProverTaskManager.sol │ New bytes32 field in response struct │
│ TaskResponseMetadata │ │ │
├────────────────────────────────────┼────────────────────────────────────────────────┼──────────────────────────────────────────┤
│ Gateway emits commitment on-chain │ crates/gateway/src/rpc/api/sync.rs │ Compute commitment alongside BLS │
│ │ │ aggregation │
├────────────────────────────────────┼────────────────────────────────────────────────┼──────────────────────────────────────────┤
│ Share Merkle root for EigenDA │ crates/core/src/dkg/commitment.rs │ Merkle tree of (operatorId, D_i, pi_i) │
│ │ │ tuples │
├────────────────────────────────────┼────────────────────────────────────────────────┼──────────────────────────────────────────┤
│ Challenger decryption verification │ crates/challenger/src/lib.rs │ challengeDecryptionAggregation path │
└────────────────────────────────────┴────────────────────────────────────────────────┴──────────────────────────────────────────┘
Exit criteria: FROST DKG ceremony completes with 5 operators on local anvil. On-chain commitment stored and verifiable.
Sub-Phase 2D: Privacy Slashing (2 weeks)
Goal: Implement PrivacySlasher contract and off-chain detection for wrong-keyshare and no-keyshare violations.
Linear tickets: NEWT-629
Week 11: PrivacySlasher Contract
┌─────────────────────────┬───────────────────────────────────────────┬──────────────────────────────────────────────────────────┐
│ Task │ Files │ Details │
├─────────────────────────┼───────────────────────────────────────────┼──────────────────────────────────────────────────────────┤
│ │ contracts/src/core/PrivacySlasher.sol │ reportMissedPartialDecryption(operator, epochId, │
│ PrivacySlasher.sol │ (new) │ taskId), reportInvalidPartialDecryption(operator, │
│ │ │ partial, dleqProof) │
├─────────────────────────┼───────────────────────────────────────────┼──────────────────────────────────────────────────────────┤
│ DLEQ on-chain │ contracts/src/libraries/DleqVerifier.sol │ Verify DLEQ proofs using EIP-196 precompiles (~40k gas) │
│ verification │ (new) │ │
├─────────────────────────┼───────────────────────────────────────────┼──────────────────────────────────────────────────────────┤
│ Integration with │ │ │
│ EigenLayer │ contracts/src/core/PrivacySlasher.sol │ fulfillSlashingRequest() call │
│ InstantSlasher │ │ │
├─────────────────────────┼───────────────────────────────────────────┼──────────────────────────────────────────────────────────┤
│ Forge tests │ contracts/test/PrivacySlasher.t.sol (new) │ Invalid partial -> slash, missed deadline -> slash, │
│ │ │ duplicate report -> revert │
└─────────────────────────┴───────────────────────────────────────────┴──────────────────────────────────────────────────────────┘
Week 12: Off-Chain Detection + E2E
┌─────────────────────────────────┬────────────────────────────────────────────────┬─────────────────────────────────────────────┐
│ Task │ Files │ Details │
├─────────────────────────────────┼────────────────────────────────────────────────┼─────────────────────────────────────────────┤
│ PartialDecryptionTracker │ crates/gateway/src/dkg/tracker.rs (new) │ Track requested vs received partials, │
│ │ │ detect timeouts │
├─────────────────────────────────┼────────────────────────────────────────────────┼─────────────────────────────────────────────┤
│ Gateway reports missed/invalid │ crates/chainio/src/avs/writer.rs │ report_missed_partial(), │
│ partials │ │ report_invalid_partial() │
├─────────────────────────────────┼────────────────────────────────────────────────┼─────────────────────────────────────────────┤
│ Slashing E2E test │ integration-tests/tests/privacy_slashing.rs │ Simulate operator submitting invalid DLEQ │
│ │ (new) │ proof, verify slash │
├─────────────────────────────────┼────────────────────────────────────────────────┼─────────────────────────────────────────────┤
│ Dispute window integration │ contracts/src/core/PrivacySlasher.sol │ 100-block window consistent with existing │
│ │ │ challenger │
└─────────────────────────────────┴────────────────────────────────────────────────┴─────────────────────────────────────────────┘
Exit criteria: Invalid DLEQ proof triggers on-chain slash on local anvil. Missed deadline detection works.
Missing Linear Tickets
Based on the analysis, we need these new tickets:
┌────────────────────────┬──────────┬───────────┬────────────────────────────────────────────────────────────────────────────────┐
│ New Ticket │ Parent │ Sub-Phase │ Description │
├────────────────────────┼──────────┼───────────┼────────────────────────────────────────────────────────────────────────────────┤
│ HPKE crate │ NEWT-176 │ 2A │ Fork/augment hpke crate with open_with_precomputed_dh for threshold path │
│ augmentation │ │ │ │
├────────────────────────┼──────────┼───────────┼────────────────────────────────────────────────────────────────────────────────┤
│ EpochRegistry contract │ NEWT-628 │ 2B │ Solidity contract for epoch lifecycle, MPK publication, destruction │
│ │ │ │ attestation │
├────────────────────────┼──────────┼───────────┼────────────────────────────────────────────────────────────────────────────────┤
│ PrivacySlasher │ NEWT-629 │ 2D │ Solidity contract for privacy-specific slashing via EigenLayer │
│ contract │ │ │ │
├────────────────────────┼──────────┼───────────┼────────────────────────────────────────────────────────────────────────────────┤
│ DleqVerifier library │ NEWT-629 │ 2D │ Solidity library for on-chain DLEQ proof verification via EIP-196 │
└────────────────────────┴──────────┴───────────┴────────────────────────────────────────────────────────────────────────────────┘
Tickets That Need Updates
┌─────────────────┬──────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
│ Ticket │ Update Needed │
├─────────────────┼──────────────────────────────────────────────────────────────────────────────────────────────────────────────┤
│ NEWT-177 │ Update description: Pedersen DKG -> FROST DKG (RFC 9591), ark-ec -> frost-ristretto255, G1Point -> │
│ │ RistrettoPoint, 4 phases -> 2 rounds │
├─────────────────┼──────────────────────────────────────────────────────────────────────────────────────────────────────────────┤
│ NEWT-177 │ Clear stale due date (was Feb 7) │
├─────────────────┼──────────────────────────────────────────────────────────────────────────────────────────────────────────────┤
│ NEWT-176 │ Clear stale due date (was Feb 10) │
├─────────────────┼──────────────────────────────────────────────────────────────────────────────────────────────────────────────┤
│ NEWT-178 │ Clear stale due date (was Feb 13), update to reference FROST not Pedersen │
├─────────────────┼──────────────────────────────────────────────────────────────────────────────────────────────────────────────┤
│ NEWT-174 │ Clear stale due date (was Feb 13) │
├─────────────────┼──────────────────────────────────────────────────────────────────────────────────────────────────────────────┤
│ NEWT-629 │ Rename "[Privacy P3]" -> "[Privacy P2D]" to match sub-phase numbering │
├─────────────────┼──────────────────────────────────────────────────────────────────────────────────────────────────────────────┤
│ NEWT-630 │ Rename "[Privacy P4]" -> "[Privacy P2C]" to match sub-phase numbering │
├─────────────────┼──────────────────────────────────────────────────────────────────────────────────────────────────────────────┤
│ NEWT-628, 629, │ Assign to dennis.won │
│ 630 │ │
└─────────────────┴──────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
★ Insight ─────────────────────────────────────
Sub-phase dependencies matter: 2A (MVP) is the critical path — everything else builds on it. 2B (rotation) and 2C (full DKG) can
partially overlap because they modify different subsystems: 2B is operator keystore + EpochRegistry contract, while 2C is the DKG
ceremony coordinator + on-chain commitments. 2D (slashing) must wait for both because it verifies DLEQ proofs (from 2A) in an epoch
context (from 2B).
The hpke crate augmentation is the single biggest technical risk — the standard HPKE API doesn't expose a open_with_precomputed_dh
entry point. We either need an upstream PR to the hpke crate (uncertain timeline) or a minimal fork. This should be spiked in week 1.
─────────────────────────────────────────────────