Files
pse.dev/content/articles/summon-major-update.md
Kalidou Diagne 31763f7662 feat: PageSpeed Insights improvements (#545)
* feat: PageSpeed Insights improvements
2025-09-01 06:01:00 +02:00

162 lines
4.8 KiB
Markdown
Raw Permalink Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
title: Summon Major Update
image: "/articles/summon-major-update/cover.webp"
tldr: Im excited to share the biggest Summon update yet. 🎉
authors: ["Andrew Morris"]
date: 2025-05-21
tags:
[
summon,
mpc,
typescript,
privacy,
developer-tools,
release-notes,
circuits,
cryptography,
compiler,
]
projects: ["mpc-framework"]
canonical: "https://mpc.pse.dev/blog/summon-major-update"
---
Im excited to share the biggest Summon update yet. 🎉
## Wait - What's Summon?
[Summon](https://github.com/privacy-scaling-explorations/summon) is a dialect of TypeScript for generating boolean circuits! We use this to great effect in [MPC Framework](https://mpc.pse.dev/), since it requires the computation inside the MPC cryptography to be a boolean circuit. It's so much more than a TypeScript library - it's a very special runtime that transforms branching (`if/else/for/while/switch`) into flat circuitry.
## 1 · Streamlined IO with `Summon.IO`
### Before
```js
export default function main(a: number, b: number) {
const plus = a + b
const gt = a > b
return [plus, gt]
}
// and separately provide mpcSettings:
const mpcSettings = [
{
name: "alice",
inputs: ["a"],
outputs: ["main[0]", "main[1]"],
},
{
name: "bob",
inputs: ["b"],
outputs: ["main[0]", "main[1]"],
},
]
```
### After
```js
default function main(io: Summon.IO) {
const a = io.input('alice', 'a', summon.number());
const b = io.input('bob', 'b', summon.number());
io.outputPublic('plus', a + b);
io.outputPublic('gt', a > b);
}
// mpcSettings is generated automatically
```
_Shorter, selfcontained, and each output has a real name._
Per-party outputs are also coming, and will fit neatly into this API: `io.output(partyName, outputName, value)`.
Type information is available via [`summon.d.ts`](https://github.com/privacy-scaling-explorations/summon/blob/main/summon.d.ts):
![intellisense demo](/articles/summon-major-update/intellisense-light.webp)
## 2 · Typed Inputs (now with `bool`)
The third argument of `io.input` specifies the type:
![number example](/articles/summon-major-update/number-example-light.webp)
![bool example](/articles/summon-major-update/bool-example-light.webp)
`bool`s now work properly, so you can pass `true`/`false` instead of `1`/`0`. This is both better devX and removes unnecessary bits.
Output bools are also new, decoding correctly as `true`/`false` (the values you get out of `await session.output()`).
This also sets us up to support arrays/etc and grow into comprehensive typing à la [zod](https://zod.dev/?id=basic-usage) or [iots](https://github.com/gcanti/io-ts/blob/master/index.md).
## 3 · Public Inputs
Need a single program that adapts to many input sizes/participants? Public inputs let you accept these at **compile time**:
```js
const N = io.inputPublic("N", summon.number())
let votes: boolean[] = []
for (let i = 0; i < N; i++) {
const vote = io.input(`party${i}`, `vote${i}`, summon.bool())
votes.push(vote)
}
```
Pass them via CLI:
```bash
summonc program.ts \
--public-inputs '{ "N": 10 }' \
--boolify-width 8
```
or the `summon-ts` API:
```js
const { circuit } = summon.compile({
path: "program.ts",
boolifyWidth: 8,
publicInputs: { N: 10 },
files: {
/* ... */
},
})
```
See it in action: **JumboSwap** [circuit](https://github.com/privacy-scaling-explorations/jumboswap/blob/3f81b87/src/circuit/main.ts).
## 4 · Faster Branch Merging
Merging has to occur whenever your program branches on signals:
```js
const value = cond ? x : y
```
Circuits can't evaluate only one side of this like CPUs do, so the Summon compiler has to emit wires for both branches and then merge them together like this:
```js
value = merge(condA, x, condB, y)
// = (condA * x) + (condB * y) // old method
// = (condA * x) XOR (condB * y) // new method
```
So, `+` became `XOR` which is great because `XOR` is almost free, but why is this allowed?
The key is that `condA` and `condB` cannot be true simultaneously. In this example we have `condB == !condA`, but we don't have to rely on that. These conditions are _always_ non-overlapping - there is only ever one "real" branch with `cond == 1`. This means each bit of the addition cannot produce a carry and is equivalent to `XOR`, because `XOR` is 1-bit addition.
This caused some real speedups in our demos:
- [**JumboSwap**](https://mpc.pse.dev/apps/jumboswap): ≈4× faster
- [**LizardSpock**](https://mpc.pse.dev/apps/lizard-spock): ≈20% faster
## Join Us!
- [Telegram group](https://t.me/+FKnOHTkvmX02ODVl)
- [Discord](https://discord.gg/btXAmwzYJS) (Channel name: 🔮-mpc-framework)
- [Github Repo](https://github.com/privacy-scaling-explorations/mpc-framework) ⭐️
- [Website](https://mpc.pse.dev)
Thanks for building privacypreserving magic with us! 🪄