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
- Learn some math behind R1CS or other zk IR
- Design & implement your zk circuit
- Using ZoKrates, Circom, Cairo, \(\ldots\)
- Labor intensive & error prone
- Something goes wrong
- Learn more math
- Revise zk circuit or Go to Step 2
- 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
Keelung
- 119