Function
Keys are generated once. Downloading the engine takes about 40 seconds.
What the compiler does
It turns your function into a fixed sequence of arithmetic on encrypted values. Every step is decided before anything runs, because on ciphertext there is nothing to look at and branch on.
What you write
let s = a;
if (a > b) {
s = a * 2;
} else {
s = b * 3;
}
→
What runs
c = a > b t = a * 2 e = b * 3 s = merge(c, t, e)
Both sides are computed, then merged into one value per variable. Variables the branch never touched are left alone. The cost is that you pay for both paths — deep nesting multiplies work, so arithmetic beats nesting.
What it supports
| Category | Supported |
|---|---|
secret · public |
Default is secret. Public values fold into the circuit as constants — use them for loop counts and thresholds. |
i8 i16 i32 i64 · u8 … u64 · bool · f64 |
Written as a: i32. Omit it and the parameter is i32. |
+ - * / % · < <= > >= == != · & | ^ ~ << >> · && || ! |
Plus ternary, increment, and compound assignment. |
if / else · for |
Loops unroll, so the iteration count must be a public value. |
min max abs select |
Math.min, Math.max, Math.abs, Math.floor, Math.ceil, Math.round, Math.trunc |
Unicode |
Korean and other non-Latin variable names work, the same as in JavaScript. |
What it rejects
| Rejected | Why |
|---|---|
for (i < secret) |
The stopping point is unknown. Put a public upper bound and decide inside the loop. |
arr[secret] |
The index is unknown, so every slot would have to be read. |
| Strings · objects · closures | They do not lower to arithmetic. Rejected with a line number. |
The compiler never calls the engine directly — it calls a fixed set of operation names. Swapping the FHE backend means writing one adapter, not touching the compiler.
Result
—
Circuit operations
Run it to see which operations were called and how many times