The Keelung zkDSL

T.-G. Lua, T.-C. Lin,
P.-C. Kuo, & C.-M. Cheng

zk-SNARK

  • A Backronym (I guess?) for zero-knowledge Succinct Noninteractive ARguments of Knowledge
    • Succinctness \(\Rightarrow\) scalability
    • Zero knowledge \(\Rightarrow\) privacy
  • Today: Many (efficient) constructions
    • Some based on pairing; some PQ
    • De facto standards emerging?
  • Tomorrow: zk everything\(^{\text{TM}}\)?

Developing zkApp

  1. Learn some math behind R1CS or other zk IR
  2. Design & implement your zk circuit
    • Using ZoKrates, Circom, Cairo, \(\ldots\)
    • Labor intensive & error prone
  3. Something goes wrong
    • Learn more math
    • Revise zk circuit or Go to Step 2
  4. Compile, test, deploy your zkApp
    • Repeat 2&3 if something bad happens again

Ideal zkApp development

  • Write a program \(P:X\times\color{red}W\color{black}\rightarrow Y\) in your favorite programming language to express business logic
    • In our case, it happens to be Haskell\(\color{red}\heartsuit\color{black}\), a safe and reliable programming language
  • Optionally preprocess \(P\)
  • Given public input \(x\in X\), public output \(y\in Y\), witness \(\color{red}w\color{black}\in\color{red}W\color{black}\), generate proof \(\pi\) that \(y=P(x,\color{red}w\color{black})\)

Introducing Keelung

  • A DSL for zkApp embedded in Haskell
    • Inspired by SnĂ„rkl (Stewart-Merten-Leland@PADL'18)
  • Significantly raising abstraction level
  • Error checking by advanced type system
  • Leveraging Haskell's mature ecosystem and tooling
  • Keelung's compilation pipeline
    • Elaboration \(\rightarrow\) Type erasure \(\rightarrow\) Rewriting \(\rightarrow\) Compilation to constraints \(\rightarrow\) Optimization \(\rightarrow\) Circuit

Example: Authentication path in a Merkle tree

In ZoKrates

  • Witness contains array of arrays of hash values along authentication path
  • Well-known trick to include the indices of these hash values at each level
    • Not strictly necessarily but for easy programming
    • Will expand to nested if-then-else in R1CS anyway
    field mut digest = leaf;

    for u32 i in 0..DEPTH {
        assert(path[i][indices[i]] == digest);
        digest = hash(path[i]);
    }
    assert(digest == root);

\(\text{\tt fold}\) to rescue in Keelung

\(\text{\tt foldl :: Foldable t => (b -> a -> b) -> b -> t a -> b}\)

merkleProof :: Int -> Number -> Comp ()
merkleProof depth root = do
  leaf <- inputNum
  path <- inputs2 depth 2
  digest <- foldlM (\digest p -> do
                      assert (digest `existsIn` p)
                      hash p)
                   leaf
                   path
  assert (digest `Eq` root)

Thank you!

Questions or comments?

Keelung

By Chen-Mou Cheng