不存在的密钥:浏览器中的门限签名仪式
The key that never exists: a threshold signing ceremony in the browser

原始链接: https://808bits.com/articles/threshold-signing-ceremony-in-your-browser/

本文介绍了 **zig-mpc**,这是一个开源库,通过实施门限密码学(threshold cryptography)来消除传统私钥固有的单点故障风险。通过使用多方计算(MPC),该系统生成的加密密钥从未以完整形式存在。 取而代之的是,三个参与方(Alice、Bob 和 Carol)通过分布式密钥生成(DKG)过程来创建各自的密钥分片。从代数角度看,每一方都会贡献一个秘密多项式;当它们结合时,会形成一个任何单方都无法完全掌握的群体秘密。这确保了只有在预设门限数量的参与方(例如三人中的两人)协作时,才能生成签名。 该项目提供了一个基于浏览器、仅在本地运行的模拟环境,用户可以使用真实、生产就绪的线路格式来观察协议的运行轮次,包括承诺(commitment)、分发(sharing)和验证(verification)。它通过 FROST 协议支持主流方案,如 Ed25519(Solana/Cardano)和 BIP-340(Bitcoin Taproot)。由于输出结果是标准签名,因此门限结构对区块链而言是不可见的。虽然该库目前未经审计且仅供教育使用,但它为现代密钥托管提供了一个透明、安全的框架,使密钥在诞生、持有和使用时均以碎片形式存在。

Hacker News新内容 | 过往 | 评论 | 提问 | 展示 | 招聘 | 提交登录不存在的密钥:浏览器中的门限签名仪式 (808bits.com)5 分 | meehow 发布于 1 小时前 | 隐藏 | 过往 | 收藏 | 讨论 帮助 指南 | 常见问题 | 列表 | API | 安全 | 法律 | 申请 YC | 联系 搜索:
相关文章

原文

A cryptographic key is a single point of failure. Whoever holds it holds everything, and most custody disasters reduce to that. Threshold cryptography asks a different question: what if the key never exists in one place, not even at birth?

On this page, three keyholders - alice, bob and carol - create one key together. Any two of them can sign; nobody ever holds the whole key, and there is no trusted dealer who makes it and splits it. The key is born already in pieces.

Everything below is real cryptography, compiled from Zig to WebAssembly and running locally in your tab; the library, zig-mpc, is on GitHub. Pick a curve and press Begin the ceremony; the page explains each step as you go.

Choose a key

Scheme

The cast is fixed: alice is party 1, bob is party 2, carol is party 3, and the threshold is 2 - any two can sign, any one alone can do nothing. In production each party is a separate machine; this page plays all three and shows you exactly which bytes would cross the network.

Two pieces of jargon before the rounds start. MPC is secure multi-party computation: several parties jointly compute a result without revealing their inputs to each other. It is what “MPC wallet” vendors sell, usually behind an API. A key ceremony is custody’s name for the formal procedure where key material gets created or used, traditionally in a vault with witnesses and dual controls. The one on this page is the real protocol, minus the vault.

The ceremony is identical for all three schemes; only the curve and the final signature format differ. Ed25519 and BIP-340 sign with FROST (Flexible Round-Optimized Schnorr Threshold signatures, RFC 9591), and the same distributed key generation (DKG) also feeds threshold ECDSA (CGGMP24) for chains that require it.

Every byte shown is a real protocol message, in the same wire format the zmpc CLI exchanges between machines. Nothing you type or click leaves the page: no server, no analytics. It fetches one wasm file and then goes quiet.

Grow a key that never exists whole

Distributed key generation: three rounds plus a finalize, one command per machine per round with the CLI. Each round reads the frames that arrived and produces new ones, and the page delivers them the way you would between machines: a broadcast frame (…-t0) is copied to both other parties, a p2p frame (…-tN) goes to party N only.

The shape of the trick is worth stating before you click. Each party invents its own secret polynomial and hands the others single points on it. Add three polynomials together and you get a group secret nobody chose and nobody knows; each party’s share is just its own stack of points. Commitments in round 1 stop anyone from picking their polynomial after seeing the others, and verification in round 3 catches anyone who dealt inconsistent points. Cheating does not corrupt the key; it aborts the ceremony and names the cheater.

If you know Shamir’s secret sharing, the algebra is familiar (polynomials, points, interpolation) but the trust model is not. Shamir needs a dealer who holds the whole secret before splitting it, and using the secret means putting it back together, so the key exists whole at birth and at every use. Here each party deals only its own contribution, and reconstruction never happens, at generation or at signing.

The rounds unlock once you begin the ceremony above.

Sign with any two

Signing is FROST: two rounds plus an aggregation, zmpc sign commit / share / aggregate in the CLI. Pick which two sit at the table; the third stays home and learns nothing, not even that a signature happened. Every signer must hold the same message bytes and a fresh signing-session id.

The output is an ordinary signature. A Bitcoin node or a Solana validator verifies it with the standard algorithm against the group public key; no verifier can tell a ceremony happened. The threshold structure is invisible on-chain, so it works today on chains that have never heard of FROST.

Unlocks once the key above exists.

Try to break it

Each experiment below runs a fresh signing session with one thing wrong: a bit flipped in transit, a message swapped at verification, a party signing below the threshold with its genuine share.

Sign alone

Below the threshold: one party runs the entire signing protocol by itself, honestly, with its genuine share.

Unlocks once the key exists - the experiments need real shares to attack.

The third experiment is the one to sit with. Alice’s lone attempt fails even though every protocol step runs without complaint: one point does not determine a degree-1 polynomial, so her signature simply does not verify. The threshold is enforced by algebra, not by an if-statement anyone could patch out.

Each experiment’s message for the impossible outcome reads “that is a bug”. If you ever see it, please file an issue.

Under the hood

This page embeds zmpc.wasm (about 230 KB), the WebAssembly build of zig-mpc, written in Zig, compiled to wasm32-freestanding, no emscripten and no JS crypto. The primitives are not rolled: group arithmetic comes from std.crypto.ecc, field math from std.crypto.ff, SHA-2 and HMAC from the same place. zig-mpc adds the protocol layer, zeroes consumed secrets, and compares secret data in constant time. The JavaScript on this page moves bytes in and out of linear memory and draws tables.

The DKG and FROST rounds running here are the same functions the zmpc CLI runs, and the frames are byte-compatible with it: a keyshare.zmpc generated on this page works in a CLI signing session between real machines, and vice versa. On real hardware the same ceremony is one process per party, one command per round:

zmpc init --dir p1 --suite ed25519 --party 1 --n 3 --threshold 2
zmpc dkg round1 --dir p1     # ... deliver frames to the other machines ...
zmpc dkg round2 --dir p1
zmpc dkg round3 --dir p1
zmpc dkg finalize --dir p1   # -> artifacts/keyshare.zmpc, prints the public key

Everything is in the repo, with no dependencies beyond the Zig standard library: zig build produces the CLI, zig build wasm the module this page just loaded. The FROST implementation reproduces the RFC 9591 test vectors byte for byte, the Taproot mode passes all 19 official BIP-340 vectors, and the library also does threshold ECDSA (CGGMP24, end to end), proactive share refresh, and BIP-32/SLIP-10 HD derivation.

Two caveats. The point of MPC is that each party is a separate machine and the shares never meet; this tab plays all three parties so you can watch the messages. And zig-mpc is unaudited, pre-production software. It exists so you can see how a signing ceremony works, byte by byte. Do not put keys you care about anywhere near it yet; the repository’s roadmap spells out what has to happen first.

联系我们 contact @ memedata.com