tl;dr: The good: Audit went well. Lúcás Meier’s Cait-Sith threshold ECDSA protocol seems like a reasonable, conservative choice. The bad: Near’s MPC currently works in a 5 out of 8 setting, without any proactive refresh.
Notes
Good
- MPC’s configuration is transparent, on-chain $\Rightarrow$ can monitor for suspicious membership changes
- “uses the Cait-Sith protocol in a secure manner”1
- “we did not identify any issues related to Beaver triple or nonce reuse that could compromise the security of a shared key”1
- NEAR currently only uses Cait-Sith on mainnet (May 1st, 2026)
- (The MPC committee can change this over time, of course.)
Unclear
- There is a proof for Cait-Sith but it’s in a new framework called MPS2 which is claimed to be UC-like3
- ❓ No audit for the robust threshold ECDSA scheme by Damgård et al.4
Somewhat concerning
- Claude Code identified four unaddressed items from the Trails of Bits audit; they are not high-severity though:
- #4 Ciphertext swapping (DB AAD missing) – Informational, Cryptography
- #5 Hash function used as KDF (derive_tweak) – Informational, Cryptography
- #6 P2P identity misbinding (duplicate p2p public keys) – Medium, Data Validation
- #10 AES-GCM nonce reuse (96-bit random, no rotation) – Medium, Cryptography
- NEAR modified the Cait-Sith scheme1
- multiplicative rerandomization of pre-signatures
Concerning
- TEE-backed MPC nodes are off on mainnet (as of May 1st, 2026)
- No robustness and no identifiable abort (AFACCT)
- a malicious participant who deviates can make signing fail (abort the protocol) and do so without being identifiable by honest parties $\Rightarrow$ 1 participant can DoS
- NEAR had a lot of GitHub CI security issues in the Trail of Bits report (#12, #13, #141)
- #14 could’ve allowed an attacker to release a completely malicious binary (was rated “difficult” though)
Deeply concerning
- 5 out of 8 secret-sharing on mainnet (see here)
- The Ronin Bridge attack compromised exactly $t=5$ out of $n=9$
- No proactive refresh, even though re-sharing (for nodes leaving and joining) is implemented and would be trivial to call periodically
- Without proactive refresh, an attacker can slowly take its time and compromise all 5 keys
- The last re-sharing (and thus refresh) was on March 3rd, 2026
- $\Rightarrow$ any progress an attacker made in the last 2 months (as of May 1st, 2026) is still good progress
- Why not? Because proactive refresh must invalidate the ECDSA pre-signatures, which lowers performance.
- The Cait-Sith threshold ECDSA library was not part of the audit; only its use by NEAR’s MPC node implementation was audited1
- This library may not have been production-ready.
Resources
Links and notes
- NEAR actually implemented two different threshold ECDSA protocols: Cait-Sith5 and Damgård et al.4
- Documentation on Cait-Sith library and design
- Near MPC repo
MPC node operators
Operators:
- lacksandtech.near,
- mpc-lgns.near,
- multichain-mainnet-aurora.near,
- near-mpc-staking4all-01.near,
- nodemonster.near,
- n1-multichain.near,
- everstake-mpc-1.near,
- stakin-mpc.near
NEAR-affiliated names visible:
- n1-multichain.near (NEAR One)
- multichain-mainnet-aurora.near (Aurora)
The rest are independent operators (Everstake, Stakin, etc.).
Why no proactive refresh?
First, Beaver triple secret sharing do not need to be refreshed: theft of such sharings do not lead to signature forgeries. Furthermore, $t$-out-of-$n$ secret-shared beaver triples continue to be usable after refresh.
Second, recall that a pre-signature for $k \cdot G$ is a secret sharing:
\[([k]_i, [k\cdot \sk]_i)_{i\in[n]},\]where $[k]_i$ is player $i$’s ($t$-out-of-$n$) share of the nonce $k$ (and, similarly, $[k\cdot \sk]_i$ is $k\cdot \sk$’s share).
While pre-signatures are indifferent to the secret-sharing of $\sk$ changing, theft of $t$ pre-signature shares would lead to recovery of the $\sk$: the adversary can reconstruct $k$ and $k\cdot \sk$ and then obtain $\sk$.
Hence, for refresh to be meaningful, pre-signatures have to be securely erased/discarded and new ones need to be generated.
Why presignature rerandomization exists
tl;dr: Rerandomization adapts a master-key presignature to sign under $\mathsf{sk} + e$ in 1 online round, with a guardrail against accidental presignature reuse.
NEAR’s MPC supports additive HD key derivation: derived keys are:
\[\mathsf{sk}_{\mathsf{app}} = \mathsf{sk} + e\]where $e = H(\mathsf{account_id}, \mathsf{path})$ is public.
But cached presignatures $(R, [k]_i, [\sigma]_i)$ are generated with respect to the master $\mathsf{sk}$ (i.e. $\sigma = k \cdot \mathsf{sk}$).
To sign for $\mathsf{sk}_{\mathsf{app}}$ instead of $\mathsf{sk}$, each party must locally adjust their $\sigma$-share to:
\[[\sigma_{\mathsf{app}}]_i = [\sigma]_i + [k]_i \cdot e\]This $\sigma$-adjustment is why rerandomization exists.
NEAR additionally multiplies through by a public scalar $\delta = \mathsf{HKDF}(\mathsf{pk}, \mathsf{tweak}, \mathsf{msg_hash}, R, \mathsf{participants}, \mathsf{entropy})$, yielding:
\[\bigl(\delta R, \delta [k]_i,\ \delta ([\sigma]_i + [k]_i \cdot e)\bigr)\]This multiplicative step is not needed for nonce freshness: each signing request already consumes a fresh presignature (crates/node/src/providers/ecdsa/sign.rs:73, take_owned()), so the underlying $k$ is already per-request.
What $\delta$ buys is defense-in-depth: if a bug or retry path ever served the same presignature twice across different $(\mathsf{msg}, \mathsf{tweak})$ pairs, which would normally leak $\mathsf{sk}$, the request-bound $\delta$ ensures the effective nonces still differ. ToB’s audit1 also notes NEAR picked the multiplicative form (vs. Groth–Shoup’s additive6) because the security proof was easier to write that way.
Was not able to find the proof in their repo.
Script: Fetch all MPC participants
curl -s -X POST https://rpc.mainnet.near.org -H "Content-Type: application/json" -d '{
"jsonrpc":"2.0","id":"1","method":"query",
"params":{"request_type":"call_function","finality":"final",
"account_id":"v1.signer","method_name":"state","args_base64":"e30="}
}' | jq -r '.result.result | implode' | jq .
Script: MPC membership over time
Based on visible on-chain history, no pure refresh (same set) has happened on mainnet. Every reshare was triggered by a membership change.
Here’s what each epoch’s vote_new_parameters proposal actually contained (winning proposals only, ordered by epoch):
| Epoch | Finalized | n / threshold | Membership delta from previous |
|---|---|---|---|
| 3 | 2025-08-25 | 8 / 5 | (earliest vote_new_parameters call against this contract — see note) |
| 4 | 2025-09-17 | 10 / 7 | + everstake-mpc-1.near, + stakin-mpc.near |
| 5 | 2025-11-21 | 9 / 6 | − lifted-mainnet.near |
| 6 | 2026-03-03 | 8 / 5 | − chain-signatures-hot.near ← current |
Run this vibe-coded script to reproduce these results.
References
For cited works, see below 👇👇
-
NEAR One MPC Chain Signatures, by Fredrik Dahlgren, Marc Ilunga, and Jim Miller, 2025, [URL] ↩ ↩2 ↩3 ↩4 ↩5 ↩6
-
Towards Modular Foundations for Protocol Security, by Lúcás Críostóir Meier, in Cryptology ePrint Archive, Paper 2023/187, 2023, [URL] ↩
-
Cait-Sith: Overview, Lucas Meier, April 16th, 2023 ↩
-
Fast Threshold {ECDSA} with Honest Majority, by Ivan Damgård and Thomas Pelle Jakobsen and Jesper Buus Nielsen and Jakob Illeborg Pagter and Michael Bæksvang Østergård, in Cryptology {ePrint} Archive, Paper 2020/501, 2020, [URL] ↩ ↩2
-
Cait-Sith threshold ECDSA signatures, by Lúcás Meier, GitHub repo ↩
-
On the security of ECDSA with additive key derivation and presignatures, by Jens Groth and Victor Shoup, in Cryptology ePrint Archive, Report 2021/1330, 2021, [URL] ↩