The Cult Carpenter🩸🩸🩸 (@WScrypto82) header
The Cult Carpenter🩸🩸🩸 (@WScrypto82) profile picture
United Kingdom
Joined February 2019
Photo by The Cult Carpenter🩸🩸🩸 (@WScrypto82)Photo by The Cult Carpenter🩸🩸🩸 (@WScrypto82)Photo by The Cult Carpenter🩸🩸🩸 (@WScrypto82)Photo by The Cult Carpenter🩸🩸🩸 (@WScrypto82)Photo by The Cult Carpenter🩸🩸🩸 (@WScrypto82)Photo by The Cult Carpenter🩸🩸🩸 (@WScrypto82)Photo by The Cult Carpenter🩸🩸🩸 (@WScrypto82)Photo by The Cult Carpenter🩸🩸🩸 (@WScrypto82)Photo by The Cult Carpenter🩸🩸🩸 (@WScrypto82)Photo by The Cult Carpenter🩸🩸🩸 (@WScrypto82)
The Cult Carpenter🩸🩸🩸 retweeted
Not many people talk about it, but the $Cult DAO @ModulusZK ecosystem has been quietly building for years without the usual VC circus. While the built is quiet the community has been loud about it since '22. That's when $CULT started as a fully decentralized funding DAO. No team keys, community proposes and votes, 0.4% tax feeds a treasury that invests in other decentralized projects. Now @MrOmodulus & team are working on our own chain, @ModulusZK, where $CULT is the gas token. Imagine #ZK in a completely new way. Compiling first-order logic #zkFOL straight into polynomials instead of routing everything through a traditional VM, aiming for cheaper and simpler proofs. There’s also $MOD token for specific utilities in the works. It’s still early, community-driven and worth keeping an eye on if you’re looking for something groundbreaking that’s been grinding in the background.
Which project is secretly building an empire right now?
1
10
27
398
The Cult Carpenter🩸🩸🩸 retweeted
Replying to @nkrbln
@nkrbln much respect for the follow. You should comnect with @MrOmodulus to find out concretely what @ModulusZK is building. $CULT Notably, you can check out the paper draft as it is viable, on github, for review ⬇️⬇️⬇️
We’re pleased to report that @moduluszk's zkFOL tech stack is now public for review at github.com/zkFOL/zkfol/.   The paper draft is also online at github.com/zkFOL/zkfol/blob/… Our docs and website have been updated inline.
5
33
381
The Cult Carpenter🩸🩸🩸 retweeted
After the Binance HACK, the queue for building on @ModulusZK should be 5.6Billion Miles long. Developers in all Industries MUST see the NEED for the Tech developed by @MrOmodulus and his Incredible Team. "Can't beat a physical vault" @wearecultdao
Removing the VM makes this impossible. Only @moduluszk is doing this.
1
11
34
481
The Cult Carpenter🩸🩸🩸 retweeted
Removing the VM makes this impossible. Only @moduluszk is doing this.
The Binance $5.6B drain is a masterclass in modern EVM exploitation. It wasn't a complex logic bug. It was an EIP-7702 delegation hijack: 1. Setup: Attacker funds 0x7c86 via Tornado Cash, deploys a sweep contract (0x63e8), and runs three live dry-runs on external wallets. 2. Execution: Attacker submits an EIP-7702 batch with 50 pre-signed authorizations (nonce n to n+49) to hit Binance 14's moving nonce window. 3. One authorization hits. Instantly, Binance 14 (an EOA) is reprogrammed to run the attacker's contract bytecode. 4. Execution looks totally organic: Binance 14 sweeps itself clean. Internal threshold alerts don't trigger because, from the nodes' perspective, the hot wallet is just executing its own transaction. 5. Binance 16 immediately auto-refills 28,000 ETH due to automated treasury rebalance scripts, feeding the exploit loop. The cold truth: you cannot forge an EIP-7702 delegation list. For this to execute, the attacker already held the raw private key or unconstrained signing access to Binance 14's HSM/KMS. But hey, 5.64 billion drained across ETH, BTC, and Tron. 2.54 billion frozen by Tether, Circle, Ripple, and World Liberty within hours. Code is law until the stablecoin admin keys log in. Binance got bailed out by the very centralized choke points the cypherpunks warned you about. Hardware wallets leak your home address. Centralized exchanges leak the keys to the kingdom. Self-custody on native, non-delegated chains remains the only honest baseline. At least you know what to avoid.
8
50
5
117
4,129
The Cult Carpenter🩸🩸🩸 retweeted
The $6.3B Binance hack shows how even top exchanges remain vulnerable when systems can approve unauthorized withdrawals after a compromise. No private-key leak reported, yet hot wallets were drained in ~20 minutes. This is exactly the class of gap @ModulusZK is built to close. On #Moduluszk , the contract IS the specification: First-order logic predicates #zkFOL no bytecode no VM no execution layer between intent and enforcement. A transition only happens if it can be proved. Defects refuse rather than lose funds. That architectural difference is still heavily overlooked while the industry keeps patching the same traditional models. Curious how @binance, @cz_binance, @heyibinance, @_RichardTeng, and the broader team think about verifiable-by-construction approaches for future infrastructure. Worth a look? @ModulusZK moduluszk.io documentation: docs.moduluszk.io/ github: github.com/zkFOL/zkfol
7
15
164
The Cult Carpenter🩸🩸🩸 retweeted
We think the EVM is doing too much work in ZK. Modulus is exploring another route: express computation as logic and prove that directly. zkFOL is already public: github.com/zkFOL/zkfol Working toward proofs that cost less and reveal less.
2
23
68
762
The Cult Carpenter🩸🩸🩸 retweeted
Replying to @yasu0x1
Allow us to demonstrate
2
15
56
719
The Cult Carpenter🩸🩸🩸 retweeted
#AI agents are starting to move real money. @Mastercard is exploring agent payments. @ethereum now has #ZK -powered private #API payments. But here's the trillion-dollar question: Who verifies that an AI agent was actually AUTHORIZED to do what it did? Imagine an agent that MUST prove its actions satisfy predefined rules before execution. That's why we are watching @ModulusZK and its first-order-logic research.#zkFOL Not just faster transactions. Provable rules. Verifiable actions. Less blind trust. Could this be where AI meets the next generation of blockchain infrastructure? documentation moduluszk.io $CULT #AI #ZK #zkFOL credit: @Thecultknight
10
1
27
477
The Cult Carpenter🩸🩸🩸 retweeted
What if smart contracts were defined by mathematical logic instead of traditional code? 👀 That's the vision behind @ModulusZK. 🧠 First-order logic 🔐 Zero-knowledge proofs ⚡ Verifiable execution 🔥 $CULT as gas token From logic to proof to real-world utility. #CULT #ZK #DeFi
1
7
15
193
The Cult Carpenter🩸🩸🩸 retweeted
Replying to @VitalikButerin
@VitalikButerin "The speed race is won. #Security is now the priority." But what if we’re still asking the wrong question? Instead of proving that arbitrary code executed correctly… what if every transaction had to satisfy mathematically defined rules from the start; With the contract being the specification? That’s the approach of @ModulusZK #zkFOL: first-order logic compiled directly into cryptographic proofs. No virtual machine. No bytecode. No gap between intent and enforcement. $CULT = gas token. The next breakthrough may not be a faster EVM. It may be a world beyond the VM. Agree or disagree? #ZK #Ethereum #CULT credits: @Thecultknight
4
13
98
The Cult Carpenter🩸🩸🩸 retweeted
Replying to @Zac_Aztec
Thanks, have a look closer at the arithmetisation / front end logic of the system. That's where the magic happens. The back end we bind to is where a lot of your commentary lives, and this is Zinc+ which Nethermind are aware they have some way to go still in optimisations.
12
1
52
750
Dear Benedikt @benediktbuenz, we have open-sourced zkFOL, an implementation of a shallow compositional arithmetisation of first-order logic into polynomial constraints (truth maps to 0, conjunction and universal quantification to addition, disjunction and existential quantification to multiplication), with no intermediate bytecode or zkVM. The construction follows Gabbay’s ePrint 2024/954 (eprint.iacr.org/2024/954). Public materials: repo github.com/zkFOL/zkfol, docs docs.moduluszk.io, site moduluszk.io. We would welcome technical feedback on the soundness of the shallow translation, the compiler from predicates to constraints, and its relation to existing succinct proof systems. No endorsement is sought.” @MrOmodulus @wearecultdao
1
6
19
257
The Cult Carpenter🩸🩸🩸 retweeted
Would love for @Zac_Aztec to have a look at zkFOL’s results
We’re pleased to report that @moduluszk's zkFOL tech stack is now public for review at github.com/zkFOL/zkfol/.   The paper draft is also online at github.com/zkFOL/zkfol/blob/… Our docs and website have been updated inline.
7
32
5
104
3,416
The Cult Carpenter🩸🩸🩸 retweeted
Replying to @scottmelker
He got the idea from Dr. Jamie Gabbay who's working on this at @ModulusZK with @MrOmodulus. Suggest you to check it out here -> moduluszk.io/
5
17
99
Hi Albert @0xAlbertG , following your work on Zinc and Zinc+ at Nethermind. We’ve open-sourced zkFOL (moduluszk.io): a direct arithmetisation of first-order logic predicates into polynomial constraints — no bytecode, no zkVM. It builds on Gabbay’s ePrint 2024/954 and is, to our knowledge, the first stack to verify Zinc+ proofs on-chain. Public materials: • Repo: github.com/zkFOL/zkfol • Paper draft + docs linked in the repo We’re looking for technical feedback (especially on the arithmetisation approach and how it sits alongside Zinc/Zinc+) rather than an endorsement. Would appreciate a look if you’re interested. Thanks! @MrOmodulus @wearecultdao
7
19
246
The Cult Carpenter🩸🩸🩸 retweeted
Replying to @IOHK_Charles
@IOHK_Charles In May 2025 you reviewed Gabbay's paper, built a Lean EDSL on it, and said the computational complexity wasn't practical. Fair challenge, and @ModulusZK took it seriously. They kept building with no funding, no help, no attention, only got ignored and still gets ignored and zkFOL now proves in milliseconds on a normal CPU, benchmarked against RISC Zero and SP1. Would genuinely love your take on whether this answers your concern: github.com/zkFOL/zkfo
I reviewed the paper and wrote an EDSL in Lean based on it. My implementation demonstrates how first-order logic compiles directly to polynomial constraints, providing the missing link between high-level cryptocurrency invariants and low-level zkSNARK circuits. By mapping logical formulas to R1CS, developers can specify complex financial systems declaratively while achieving cryptographic verifiability. The core insight: monetary invariants are logical statements. "Total supply remains constant" becomes ∀tx. sum(inputs) = sum(outputs). "No double spending" becomes ∀coin. spent(coin) ⇒ ¬spendable(coin). These specifications compile automatically to polynomial constraints, eliminating manual circuit construction—the primary barrier to zkEVM adoption. The polynomial semantics handles the full complexity of financial logic. Negation through sign gadgets enables expressing invalidity conditions—quantifiers over finite domains model transaction batches. The sparse polynomial representation keeps verification costs manageable even for complex state transitions. Most critically, conjunction's additive compilation means combining multiple invariants doesn't compound proof complexity, essential for composable financial protocols. The R1CS output integrates directly with existing zkSNARK toolchains (Groth16, PLONK, Halo2). A balance check requiring hundreds of hand-written constraints reduces to a single logical formula. The compiler handles witness generation, wire allocation, and constraint optimization automatically. Here's the code: -- ArithFOL.lean — Lean 4 EDSL for Gabbay-style arithmetised first-order logic -- Author: Charles Hoskinson License: MIT -- -- * Full polynomial semantics (truth ≙ 0) + complete R1CS compiler. -- * Extra Poly utilities (pow / evaluate / degree / leadingCoeff / isZero / isConst). -- * Pretty R1CS printer and runnable examples at bottom. -- --------------------------------------------------------------------------- import Std.Data.RBMap.Lemmas open Std (RBMap) /-! ### Signature --------------------------------------------------------- -/ structure FuncSymbol where name : String := "" ; arity : Nat := 0 structure PredSymbol where name : String := "" ; arity : Nat := 0 /-! ### Syntax: de-Bruijn terms & formulas -------------------------------- -/ inductive Term : Nat → Type | var {n} : Fin n → Term n | const {n} : Rat → Term n | indet {n} : Term n -- distinguished X | add {n} : Term n → Term n → Term n | mul {n} : Term n → Term n → Term n | neg {n} : Term n → Term n | func {n} : (f : FuncSymbol) → (Fin f.arity → Term n) → Term n inductive Formula : Nat → Type | top {n} : Formula n | bot {n} : Formula n | eq {n} (t u : Term n) : Formula n | pred {n} (P : PredSymbol) (args : Fin P.arity → Term n) : Formula n | and {n} (φ ψ : Formula n) : Formula n | or {n} (φ ψ : Formula n) : Formula n | forall {n} (φ : Formula (n+1)) : Formula n | exists {n} (φ : Formula (n+1)) : Formula n | notG {n} (φ : Formula n) : Formula n -- sign-gadget ¬φ /-! ### Polynomial datatype ----------------------------------------------- -/ structure Poly where coeffs : RBMap Nat Rat compare deriving Repr, DecidableEq namespace Poly def zero : Poly := ⟨RBMap.empty⟩ def const (q : Rat) : Poly := if q = 0 then zero else ⟨RBMap.ofList [(0,q)]⟩ def X : Poly := ⟨RBMap.ofList [(1,1)]⟩ @[inline] def clean (m : RBMap Nat Rat compare) := m.fold (init:=RBMap.empty) (fun acc k v => if v=0 then acc else acc.insert k v) @[inline] def add (p q : Poly) : Poly := ⟨clean <| p.coeffs.fold (init:=q.coeffs) (fun m k v => m.insert k (v + m.findD k 0))⟩ @[inline] def neg (p : Poly) : Poly := ⟨p.coeffs.fold (init:=RBMap.empty) (fun m k v => m.insert k (-v))⟩ @[inline] def mul (p q : Poly) : Poly := ⟨clean <| p.coeffs.fold (init:=RBMap.empty) (fun acc kp vp => q.coeffs.fold (init:=acc) (fun acc2 kq vq => let k := kp+kq let c := acc2.findD k 0 + vp*vq if c = 0 then acc2.erase k else acc2.insert k c))⟩ @[inline] def square (p : Poly) : Poly := p.mul p @[inline] def pow (p : Poly) : Nat → Poly | 0 => const 1 | 1 => p | n+1 => let q := pow p (n/2) let q2 := q.mul q if n % 2 = 0 then q2 else q2.mul p @[inline] def ratPow : Rat → Nat → Rat | _, 0 => 1 | r, 1 => r | r, n+1 => let half := ratPow r (n/2) let sq := half*half if n%2=0 then sq else sq*r @[inline] def evaluate (p : Poly) (x : Rat) : Rat := if x = 0 then p.coeffs.findD 0 0 else if x = 1 then p.coeffs.fold (init:=0) (fun acc _ v => acc+v) else p.coeffs.fold (init:=0) (fun acc k v => acc + v * ratPow x k) @[inline] def degree (p : Poly) : Option Nat := p.coeffs.fold (init:=none) (fun o k _ => match o with | none => some k | some d => some (max d k)) @[inline] def leadingCoeff (p : Poly) : Option Rat := match p.degree with | none => none | some d => p.coeffs.find? d @[inline] def isZero (p : Poly) : Bool := p.coeffs.isEmpty @[inline] def isConst (p : Poly) : Option Rat := if p.isZero then some 0 else if p.coeffs.size = 1 ∧ p.coeffs.min?.map (·.1) = some 0 then some (p.coeffs.findD 0 0) else none @[inline] def compose (p q : Poly) : Poly := p.coeffs.fold (init:=Poly.zero) (fun acc k c => acc.add (Poly.const c).mul (q.pow k)) end Poly /-! ### Environment -------------------------------------------------------- -/ structure Env (n : Nat) where varVal : Fin n → Rat domain : List Rat namespace Env def extend {n} (e : Env n) (a : Rat) : Env (n+1) := { varVal := fun | ⟨0,_⟩ => a | ⟨i+1,h⟩ => e.varVal ⟨i, Nat.lt_of_succ_lt_succ h⟩, domain := e.domain } end Env /-! ### Interpretation ----------------------------------------------------- -/ mutual def interpTerm {n} (ρ : Env n) : Term n → Poly | .var i => Poly.const (ρ.varVal i) | .const q => Poly.const q | .indet => Poly.X | .add s t => (interpTerm ρ s).add (interpTerm ρ t) | .mul s t => (interpTerm ρ s).mul (interpTerm ρ t) | .neg t => Poly.neg (interpTerm ρ t) | .func _ _ => Poly.zero def liftTerm {k} : Term k → Term (k+1) | .var i => .var ⟨i.val+1, Nat.succ_lt_succ i.isLt⟩ | .const q => .const q | .indet => .indet | .add s t => .add (liftTerm s) (liftTerm t) | .mul s t => .mul (liftTerm s) (liftTerm t) | .neg t => .neg (liftTerm t) | .func f as => .func f (fun i => liftTerm (as i)) def liftFormula {k} : Formula k → Formula (k+1) | .top => .top | .bot => .bot | .eq t u => .eq (liftTerm t) (liftTerm u) | .pred P as => .pred P (fun i => liftTerm (as i)) | .and φ ψ => .and (liftFormula φ) (liftFormula ψ) | .or φ ψ => .or (liftFormula φ) (liftFormula ψ) | .forall φ => .forall (liftFormula φ) | .exists φ => .exists (liftFormula φ) | .notG φ => .notG (liftFormula φ) def interpFormula {n} (ρ : Env n) : Formula n → Poly | .top => Poly.zero | .bot => Poly.const 1 | .eq t u => (interpTerm ρ t).add (Poly.neg (interpTerm ρ u)) |> Poly.square | .pred _ _ => Poly.const 1 | .and φ ψ => let p := interpFormula ρ φ let q := interpFormula ρ ψ p.square.add q.square | .or φ ψ => (interpFormula ρ φ).mul (interpFormula ρ ψ) | .forall φ => ρ.domain.foldl (init:=Poly.zero) fun acc a => acc.add ((interpFormula (ρ.extend a) φ).square) | .exists φ => match ρ.domain with | [] => Poly.const 1 | a :: _ => interpFormula (ρ.extend a) φ -- naive witness | .notG φ => let φ' := liftFormula φ let b : Term (n+1) := .var ⟨0, Nat.zero_lt_succ n⟩ let boolB := Formula.eq (.mul b (.add b (.const (-1)))) (.const 0) let conj0 := Formula.and (Formula.eq b (.const 0)) φ' let conj1 := Formula.and (Formula.eq b (.const 1)) Formula.top let gadget := Formula.and boolB (Formula.or conj0 conj1) let p0 := interpFormula (ρ.extend 0) gadget let p1 := interpFormula (ρ.extend 1) gadget p0.mul p1 end /-! ### R1CS infrastructure ---------------------------------------------- -/ structure Wire where id : Nat deriving Repr, DecidableEq, Ord instance : Ord Wire := ⟨fun a b => compare a.id b.id⟩ namespace Wire def X : Wire := ⟨0⟩ def one : Wire := ⟨1⟩ def zero : Wire := ⟨2⟩ end Wire structure Constraint where A B C : RBMap Wire Rat compare deriving Repr structure Ctx where next : Nat := 3 -- after reserved rows : List Constraint := [] powers : RBMap Nat Wire compare := {} polyWires : RBMap Poly Wire compare := {} namespace Ctx def fresh : StateM Ctx Wire := do let s ← get; set {s with next := s.next+1}; pure ⟨s.next⟩ def push (row : Constraint) : StateM Ctx Unit := modify fun s => {s with rows := row :: s.rows} -- wires for X^k, cached partial def getPower (k : Nat) : StateM Ctx Wire := do let s ← get; match s.powers.find? k with | some w => pure w | none => if k=0 then pure Wire.one else if k=1 then pure Wire.X else let wPrev ← getPower (k-1) let wk ← fresh push {A := RBMap.singleton Wire.X 1, B := RBMap.singleton wPrev 1, C := RBMap.singleton wk 1} modify fun s => {s with powers := s.powers.insert k wk} pure wk -- wires for arbitrary polynomial value partial def getPolyWire (p : Poly) : StateM Ctx Wire := do let s ← get; match s.polyWires.find? p with | some w => pure w | none => match p.isConst with | some 0 => pure Wire.zero | some 1 => pure Wire.one | _ => let w ← fresh compilePolyDef p w modify fun s => {s with polyWires := s.polyWires.insert p w} pure w -- emit rows for Σ c_k X^k = w partial def compilePolyDef (p : Poly) (w : Wire) : StateM Ctx Unit := do let mut lin := RBMap.singleton w (-1) for ⟨k,c⟩ in p.coeffs.toList do let wk ← getPower k lin := lin.insert wk (c + lin.findD wk 0) push {A := lin, B := RBMap.singleton Wire.one 1, C := RBMap.empty} end Ctx /-- compile equality p=0 into rows -/ private def compilePolyEq (p : Poly) : StateM Ctx Unit := do if p.isZero then return () let w ← Ctx.getPolyWire p Ctx.push {A := RBMap.singleton w 1, B := RBMap.singleton Wire.one 1, C := RBMap.empty} /-- substitute concrete a into a 1-bound formula (for ∀/∃ instantiation) -/ def substFormula {n} (φ : Formula (n+1)) (a : Rat) : Formula n := Formula.eq (Term.const ((interpFormula ⟨fun _ => a, []⟩ φ).evaluate 0)) (Term.const 0) /-! full compilation ------------------------------------------------------ -/ open Ctx mutual partial def compileFormula (φ : Formula 0) (env : Env 0) : StateM Ctx Unit := match φ with | .top => return () | .bot => compilePolyEq (Poly.const 1) | .eq t u => let diff := (interpTerm env t).add (Poly.neg (interpTerm env u)) compilePolyEq diff | .pred _ _ => compilePolyEq (Poly.const 1) | .and φ ψ => compileFormula φ env >> compileFormula ψ env | .or φ ψ => -- enforce wφ · wψ = 0 let pφ := interpFormula env φ; let pψ := interpFormula env ψ let wφ ← getPolyWire pφ; let wψ ← getPolyWire pψ push {A := RBMap.singleton wφ 1, B := RBMap.singleton wψ 1, C := RBMap.empty} | .forall φ => -- all instantiations must be 0 for a in env.domain do compileFormula (substFormula φ a) env | .exists φ => -- naive witness = first element match env.domain with | [] => compilePolyEq (Poly.const 1) | a :: _ => compileFormula (substFormula φ a) env | .notG φ => compilePolyEq (interpFormula env (.notG φ)) end /-- Public entry: compile closed formula to R1CS rows. -/ def compileFormulaToR1CS (φ : Formula 0) (domain : List Rat := []) : List Constraint := let env : Env 0 := ⟨fun _ => 0, domain⟩ ((compileFormula φ env).run {}).2.rows.reverse /-! ### Pretty printer & validation -------------------------------------- -/ namespace Constraint def termStr (w : Wire) (c : Rat) : String := let wS := if w = Wire.X then "X" else if w = Wire.one then "1" else if w = Wire.zero then "0" else s!"w{w.id}" if c = 1 then wS else if c = -1 then s!"-{wS}" else s!"{c}·{wS}" def sideStr (m : RBMap Wire Rat compare) : String := if m.isEmpty then "0" else String.intercalate " + " (m.toList.map (fun (w,c) => termStr w c)) def toString (c : Constraint) : String := s!"({sideStr c.A}) × ({sideStr c.B}) = {sideStr c.C}" end Constraint def validateR1CS (rows : List Constraint) (w : Wire → Rat) : Bool := rows.all fun c => let eval (m : RBMap Wire Rat compare) := m.fold (init:=0) fun acc i coeff => acc + coeff * w i eval c.A * eval c.B = eval c.C ------------------- Give my regards to Gabbay> I enjoyed reading the paper and wish you guys well with your project
1
13
37
340
The Cult Carpenter🩸🩸🩸 retweeted
Nullum est iam dictum quod non sit dictum prius @IOHK_Charles reviewed Dr. Murdoch Jamie Gabbay’s work on arithmetising first-order logic into polynomial constraints (the foundation of #zkFOL ), built a Lean EDSL around it in 2025, and judged the complexity IMPRACTICAL. Now he’s developing a new #Cardano language described as “the first of its kind” that enables intents and proof-carrying data via Groth16 proofs... THE EXACT toolchain Gabbay’s approach feeds into (R1CS → Groth16/PLONK/etc.). #zkFOL (by @ModulusZK ) is the DIRECT PUBLIC IMPLEMENTATION of that FOL-to-polynomials idea: Contracts as logical predicates, No bytecode/VM, state transitions only when proved. @IOHK_Charles ' announcement lands right as that stack goes public with strong desktop-CPU benchmarks against zkVMs. find the 2024 research paper here: eprint.iacr.org/2024/954 find documentation here: docs.moduluszk.io/ github: github.com/zkFOL/zkfol PROOF of REWIEW: Post ID: 1925621350695108951 Date: May 22, 2025 @Justin_Bons @CryptoHayes @cobie @zachxbt @WatcherGuru @TheBlockCo @CoinDesk @WuBlockchain @tier10k @scottmelker @sassal0x @HsakaTrades @lookonchain @DecryptMedia @DLNews @BeInCrypto @CryptoSlate @Bankless @nic__carter @CoryKlippsten @unusual_whales
I reviewed the paper and wrote an EDSL in Lean based on it. My implementation demonstrates how first-order logic compiles directly to polynomial constraints, providing the missing link between high-level cryptocurrency invariants and low-level zkSNARK circuits. By mapping logical formulas to R1CS, developers can specify complex financial systems declaratively while achieving cryptographic verifiability. The core insight: monetary invariants are logical statements. "Total supply remains constant" becomes ∀tx. sum(inputs) = sum(outputs). "No double spending" becomes ∀coin. spent(coin) ⇒ ¬spendable(coin). These specifications compile automatically to polynomial constraints, eliminating manual circuit construction—the primary barrier to zkEVM adoption. The polynomial semantics handles the full complexity of financial logic. Negation through sign gadgets enables expressing invalidity conditions—quantifiers over finite domains model transaction batches. The sparse polynomial representation keeps verification costs manageable even for complex state transitions. Most critically, conjunction's additive compilation means combining multiple invariants doesn't compound proof complexity, essential for composable financial protocols. The R1CS output integrates directly with existing zkSNARK toolchains (Groth16, PLONK, Halo2). A balance check requiring hundreds of hand-written constraints reduces to a single logical formula. The compiler handles witness generation, wire allocation, and constraint optimization automatically. Here's the code: -- ArithFOL.lean — Lean 4 EDSL for Gabbay-style arithmetised first-order logic -- Author: Charles Hoskinson License: MIT -- -- * Full polynomial semantics (truth ≙ 0) + complete R1CS compiler. -- * Extra Poly utilities (pow / evaluate / degree / leadingCoeff / isZero / isConst). -- * Pretty R1CS printer and runnable examples at bottom. -- --------------------------------------------------------------------------- import Std.Data.RBMap.Lemmas open Std (RBMap) /-! ### Signature --------------------------------------------------------- -/ structure FuncSymbol where name : String := "" ; arity : Nat := 0 structure PredSymbol where name : String := "" ; arity : Nat := 0 /-! ### Syntax: de-Bruijn terms & formulas -------------------------------- -/ inductive Term : Nat → Type | var {n} : Fin n → Term n | const {n} : Rat → Term n | indet {n} : Term n -- distinguished X | add {n} : Term n → Term n → Term n | mul {n} : Term n → Term n → Term n | neg {n} : Term n → Term n | func {n} : (f : FuncSymbol) → (Fin f.arity → Term n) → Term n inductive Formula : Nat → Type | top {n} : Formula n | bot {n} : Formula n | eq {n} (t u : Term n) : Formula n | pred {n} (P : PredSymbol) (args : Fin P.arity → Term n) : Formula n | and {n} (φ ψ : Formula n) : Formula n | or {n} (φ ψ : Formula n) : Formula n | forall {n} (φ : Formula (n+1)) : Formula n | exists {n} (φ : Formula (n+1)) : Formula n | notG {n} (φ : Formula n) : Formula n -- sign-gadget ¬φ /-! ### Polynomial datatype ----------------------------------------------- -/ structure Poly where coeffs : RBMap Nat Rat compare deriving Repr, DecidableEq namespace Poly def zero : Poly := ⟨RBMap.empty⟩ def const (q : Rat) : Poly := if q = 0 then zero else ⟨RBMap.ofList [(0,q)]⟩ def X : Poly := ⟨RBMap.ofList [(1,1)]⟩ @[inline] def clean (m : RBMap Nat Rat compare) := m.fold (init:=RBMap.empty) (fun acc k v => if v=0 then acc else acc.insert k v) @[inline] def add (p q : Poly) : Poly := ⟨clean <| p.coeffs.fold (init:=q.coeffs) (fun m k v => m.insert k (v + m.findD k 0))⟩ @[inline] def neg (p : Poly) : Poly := ⟨p.coeffs.fold (init:=RBMap.empty) (fun m k v => m.insert k (-v))⟩ @[inline] def mul (p q : Poly) : Poly := ⟨clean <| p.coeffs.fold (init:=RBMap.empty) (fun acc kp vp => q.coeffs.fold (init:=acc) (fun acc2 kq vq => let k := kp+kq let c := acc2.findD k 0 + vp*vq if c = 0 then acc2.erase k else acc2.insert k c))⟩ @[inline] def square (p : Poly) : Poly := p.mul p @[inline] def pow (p : Poly) : Nat → Poly | 0 => const 1 | 1 => p | n+1 => let q := pow p (n/2) let q2 := q.mul q if n % 2 = 0 then q2 else q2.mul p @[inline] def ratPow : Rat → Nat → Rat | _, 0 => 1 | r, 1 => r | r, n+1 => let half := ratPow r (n/2) let sq := half*half if n%2=0 then sq else sq*r @[inline] def evaluate (p : Poly) (x : Rat) : Rat := if x = 0 then p.coeffs.findD 0 0 else if x = 1 then p.coeffs.fold (init:=0) (fun acc _ v => acc+v) else p.coeffs.fold (init:=0) (fun acc k v => acc + v * ratPow x k) @[inline] def degree (p : Poly) : Option Nat := p.coeffs.fold (init:=none) (fun o k _ => match o with | none => some k | some d => some (max d k)) @[inline] def leadingCoeff (p : Poly) : Option Rat := match p.degree with | none => none | some d => p.coeffs.find? d @[inline] def isZero (p : Poly) : Bool := p.coeffs.isEmpty @[inline] def isConst (p : Poly) : Option Rat := if p.isZero then some 0 else if p.coeffs.size = 1 ∧ p.coeffs.min?.map (·.1) = some 0 then some (p.coeffs.findD 0 0) else none @[inline] def compose (p q : Poly) : Poly := p.coeffs.fold (init:=Poly.zero) (fun acc k c => acc.add (Poly.const c).mul (q.pow k)) end Poly /-! ### Environment -------------------------------------------------------- -/ structure Env (n : Nat) where varVal : Fin n → Rat domain : List Rat namespace Env def extend {n} (e : Env n) (a : Rat) : Env (n+1) := { varVal := fun | ⟨0,_⟩ => a | ⟨i+1,h⟩ => e.varVal ⟨i, Nat.lt_of_succ_lt_succ h⟩, domain := e.domain } end Env /-! ### Interpretation ----------------------------------------------------- -/ mutual def interpTerm {n} (ρ : Env n) : Term n → Poly | .var i => Poly.const (ρ.varVal i) | .const q => Poly.const q | .indet => Poly.X | .add s t => (interpTerm ρ s).add (interpTerm ρ t) | .mul s t => (interpTerm ρ s).mul (interpTerm ρ t) | .neg t => Poly.neg (interpTerm ρ t) | .func _ _ => Poly.zero def liftTerm {k} : Term k → Term (k+1) | .var i => .var ⟨i.val+1, Nat.succ_lt_succ i.isLt⟩ | .const q => .const q | .indet => .indet | .add s t => .add (liftTerm s) (liftTerm t) | .mul s t => .mul (liftTerm s) (liftTerm t) | .neg t => .neg (liftTerm t) | .func f as => .func f (fun i => liftTerm (as i)) def liftFormula {k} : Formula k → Formula (k+1) | .top => .top | .bot => .bot | .eq t u => .eq (liftTerm t) (liftTerm u) | .pred P as => .pred P (fun i => liftTerm (as i)) | .and φ ψ => .and (liftFormula φ) (liftFormula ψ) | .or φ ψ => .or (liftFormula φ) (liftFormula ψ) | .forall φ => .forall (liftFormula φ) | .exists φ => .exists (liftFormula φ) | .notG φ => .notG (liftFormula φ) def interpFormula {n} (ρ : Env n) : Formula n → Poly | .top => Poly.zero | .bot => Poly.const 1 | .eq t u => (interpTerm ρ t).add (Poly.neg (interpTerm ρ u)) |> Poly.square | .pred _ _ => Poly.const 1 | .and φ ψ => let p := interpFormula ρ φ let q := interpFormula ρ ψ p.square.add q.square | .or φ ψ => (interpFormula ρ φ).mul (interpFormula ρ ψ) | .forall φ => ρ.domain.foldl (init:=Poly.zero) fun acc a => acc.add ((interpFormula (ρ.extend a) φ).square) | .exists φ => match ρ.domain with | [] => Poly.const 1 | a :: _ => interpFormula (ρ.extend a) φ -- naive witness | .notG φ => let φ' := liftFormula φ let b : Term (n+1) := .var ⟨0, Nat.zero_lt_succ n⟩ let boolB := Formula.eq (.mul b (.add b (.const (-1)))) (.const 0) let conj0 := Formula.and (Formula.eq b (.const 0)) φ' let conj1 := Formula.and (Formula.eq b (.const 1)) Formula.top let gadget := Formula.and boolB (Formula.or conj0 conj1) let p0 := interpFormula (ρ.extend 0) gadget let p1 := interpFormula (ρ.extend 1) gadget p0.mul p1 end /-! ### R1CS infrastructure ---------------------------------------------- -/ structure Wire where id : Nat deriving Repr, DecidableEq, Ord instance : Ord Wire := ⟨fun a b => compare a.id b.id⟩ namespace Wire def X : Wire := ⟨0⟩ def one : Wire := ⟨1⟩ def zero : Wire := ⟨2⟩ end Wire structure Constraint where A B C : RBMap Wire Rat compare deriving Repr structure Ctx where next : Nat := 3 -- after reserved rows : List Constraint := [] powers : RBMap Nat Wire compare := {} polyWires : RBMap Poly Wire compare := {} namespace Ctx def fresh : StateM Ctx Wire := do let s ← get; set {s with next := s.next+1}; pure ⟨s.next⟩ def push (row : Constraint) : StateM Ctx Unit := modify fun s => {s with rows := row :: s.rows} -- wires for X^k, cached partial def getPower (k : Nat) : StateM Ctx Wire := do let s ← get; match s.powers.find? k with | some w => pure w | none => if k=0 then pure Wire.one else if k=1 then pure Wire.X else let wPrev ← getPower (k-1) let wk ← fresh push {A := RBMap.singleton Wire.X 1, B := RBMap.singleton wPrev 1, C := RBMap.singleton wk 1} modify fun s => {s with powers := s.powers.insert k wk} pure wk -- wires for arbitrary polynomial value partial def getPolyWire (p : Poly) : StateM Ctx Wire := do let s ← get; match s.polyWires.find? p with | some w => pure w | none => match p.isConst with | some 0 => pure Wire.zero | some 1 => pure Wire.one | _ => let w ← fresh compilePolyDef p w modify fun s => {s with polyWires := s.polyWires.insert p w} pure w -- emit rows for Σ c_k X^k = w partial def compilePolyDef (p : Poly) (w : Wire) : StateM Ctx Unit := do let mut lin := RBMap.singleton w (-1) for ⟨k,c⟩ in p.coeffs.toList do let wk ← getPower k lin := lin.insert wk (c + lin.findD wk 0) push {A := lin, B := RBMap.singleton Wire.one 1, C := RBMap.empty} end Ctx /-- compile equality p=0 into rows -/ private def compilePolyEq (p : Poly) : StateM Ctx Unit := do if p.isZero then return () let w ← Ctx.getPolyWire p Ctx.push {A := RBMap.singleton w 1, B := RBMap.singleton Wire.one 1, C := RBMap.empty} /-- substitute concrete a into a 1-bound formula (for ∀/∃ instantiation) -/ def substFormula {n} (φ : Formula (n+1)) (a : Rat) : Formula n := Formula.eq (Term.const ((interpFormula ⟨fun _ => a, []⟩ φ).evaluate 0)) (Term.const 0) /-! full compilation ------------------------------------------------------ -/ open Ctx mutual partial def compileFormula (φ : Formula 0) (env : Env 0) : StateM Ctx Unit := match φ with | .top => return () | .bot => compilePolyEq (Poly.const 1) | .eq t u => let diff := (interpTerm env t).add (Poly.neg (interpTerm env u)) compilePolyEq diff | .pred _ _ => compilePolyEq (Poly.const 1) | .and φ ψ => compileFormula φ env >> compileFormula ψ env | .or φ ψ => -- enforce wφ · wψ = 0 let pφ := interpFormula env φ; let pψ := interpFormula env ψ let wφ ← getPolyWire pφ; let wψ ← getPolyWire pψ push {A := RBMap.singleton wφ 1, B := RBMap.singleton wψ 1, C := RBMap.empty} | .forall φ => -- all instantiations must be 0 for a in env.domain do compileFormula (substFormula φ a) env | .exists φ => -- naive witness = first element match env.domain with | [] => compilePolyEq (Poly.const 1) | a :: _ => compileFormula (substFormula φ a) env | .notG φ => compilePolyEq (interpFormula env (.notG φ)) end /-- Public entry: compile closed formula to R1CS rows. -/ def compileFormulaToR1CS (φ : Formula 0) (domain : List Rat := []) : List Constraint := let env : Env 0 := ⟨fun _ => 0, domain⟩ ((compileFormula φ env).run {}).2.rows.reverse /-! ### Pretty printer & validation -------------------------------------- -/ namespace Constraint def termStr (w : Wire) (c : Rat) : String := let wS := if w = Wire.X then "X" else if w = Wire.one then "1" else if w = Wire.zero then "0" else s!"w{w.id}" if c = 1 then wS else if c = -1 then s!"-{wS}" else s!"{c}·{wS}" def sideStr (m : RBMap Wire Rat compare) : String := if m.isEmpty then "0" else String.intercalate " + " (m.toList.map (fun (w,c) => termStr w c)) def toString (c : Constraint) : String := s!"({sideStr c.A}) × ({sideStr c.B}) = {sideStr c.C}" end Constraint def validateR1CS (rows : List Constraint) (w : Wire → Rat) : Bool := rows.all fun c => let eval (m : RBMap Wire Rat compare) := m.fold (init:=0) fun acc i coeff => acc + coeff * w i eval c.A * eval c.B = eval c.C ------------------- Give my regards to Gabbay> I enjoyed reading the paper and wish you guys well with your project
2
11
2
25
506
The Cult Carpenter🩸🩸🩸 retweeted
Sounds familiar
CARDANO $ADA FOUNDER CHARLES HOSKINSON IS DEVELOPING A NEW PROGRAMMING LANGUAGE FOR THE NETWORK TO ENABLE SMART CONTRACTS TO EXECUTE TRANSACTIONS AND VERIFY CONDITIONS USING CRYPTOGRAPHIC PROOFS
4
15
3
74
2,619
The Cult Carpenter🩸🩸🩸 retweeted
Replying to @MrOmodulus
@MrOmodulus given you’re actively seeking technical review of the #zkFOL compiler and proving stack, worth a look at @zksecurityXYZ’s zkao v3. Their AI auditor focused on cryptographic codebases (compiler soundness, constraint generation, polynomial/proving paths, etc.). xitter.gq/zksecurityXYZ/status/2… Repo is public, so easy to point it at the crypto-critical parts. Pay-as-you-go credits, fraction of a full audit.
We're proud to announce the release of zkao version 3, the most powerful zkao update we've released so far. If you have a codebase that implements cryptography, now is the time to let zkao find bugs in it. Go to zkao.io to request access today.
1
6
19
249
The Cult Carpenter🩸🩸🩸 retweeted
This still is a core bottleneck you are describing. @ModulusZK’s zkFOL attacks the root cause. Applications are written as first-order logic #zkFOL predicates that compile directly to polynomial constraints. No bytecode, no virtual machine to emulate, and no intermediate circuit layer. The statement itself is what gets proved, which collapses the witness size and the dominant cost of most #zkVM s and custom circuits. Project benchmarks (same machine, same fib(10,000) fast-doubling workload) show multi-hundred- to multi-thousand-fold improvements in prove time and dramatic drops in memory versus systems like RISC Zero and SP1. That shifts more proofs onto ordinary CPUs instead of requiring specialized GPU fleets, directly addressing the “hours on expensive hardware” problem for logic-heavy use cases. Because the predicate is the contract, invalid transitions simply refuse rather than execute incorrectly, turning a class of safety failures into liveness failures. Documentation (architecture, against-zkVMs comparison, core concepts, and performance notes): docs.moduluszk.io/ Code and ways to try the compiler: github.com/zkFOL/zkfol/
Gn Frens 💤 ZKML sounds cool until you realize generating proofs take hours on expensive hardwares while verification is instant. Networks like @cysic_xyz are building the Prover infra to solve this We can’t scale ZK without solving this
1
12
111