Pitfall
Unauthenticated or Unencrypted Point-to-Point Channels
What can go wrong. Many MPC protocols such as GG18 and GG20 assume the presence of confidential and authenticated P2P channels. The deployment must realize that assumption, typically through mutual TLS, signed/encrypted application-level messages, or a noise-protocol handshake. Implementations that hand-roll channel security (raw TCP, ad-hoc JSON over HTTP, or implicit trust in a central coordinator that re-signs messages) routinely fail to provide these guarantees.
Security implication. Without per-message authentication, a network attacker can impersonate parties and inject messages honest parties attribute to the wrong source; the victim of the attribution is then blamed for protocol violations it did not commit. Without confidentiality, intermediate values that the ideal functionality hides leak to the network, and downstream secret-dependent computations become vulnerable to offline analysis. In threshold signing this translates to rogue messages causing spurious aborts, silent share exposure, and key-extraction attacks that exploit observed intermediate values.
How to avoid. Instantiate the point-to-point channels with “standard secure channel implementations”, such as mutual TLS or QUIC between each pair of parties. Ensure that the certificates of each party is pinned or issued by a trusted authority.
Example
axelarnetwork/tofnd accepts spoofed from field on the wire
(Issue #60)
Axelar’s
tofnd is a Rust daemon implementing GG20
(Gennaro–Goldfeder, 2020), a threshold-ECDSA protocol widely deployed in MPC wallet
implementations. Each message is wrapped in a TrafficIn envelope that carries both a
transport-level sender identity (from_party_uid) and an inner MsgMeta with a
protocol-level sender index (from: usize). As reported in Issue #60,
the inner from field is unauthenticated: a malicious party can edit it in the
binary payload and send messages on behalf of any other party.
The vulnerable handler discarded the transport identity and passed the raw payload straight to the cryptographic core (source):
1// FILE: src/gg20/protocol.rs — axelarnetwork/tofnd (pre-fix, lines 106–117)
2while protocol.expecting_more_msgs_this_round() {
3 let traffic = chan.receiver.next().await.ok_or(...)?;
4 let traffic = traffic.unwrap();
5 // Only `traffic.payload` is forwarded to tofn; the transport-level
6 // `traffic.from_party_uid` is discarded. tofn then trusts the inner
7 // `MsgMeta { from: usize, ... }` self-attribution.
8 protocol.set_msg_in(&traffic.payload)?;
9}
A malicious party Alice with subshares {0, 1} could craft a message with
MsgMeta::from = 2 (Bob’s subshare index), and no consistency check linked that index
back to the transport-authenticated from_party_uid. The fix is split across two
repos: tofn (the cryptographic library tofnd wraps) had to first expose the from
field in its public API (Issue #42)
so tofnd could then enforce from_party_uid == MsgMeta::from before dispatch.
Example
coinbase/kryptology GG20 DKG ships secret shares unencrypted
(Issue #29)
GG20’s joint key-generation procedure (inherited from GG18) assumes the Round 2 P2P delivery of each Shamir share $x_{ij}$ runs over a confidential point-to-point channel. The GG18/GG20 papers assume this private channel abstractly and leave its instantiation to the deployment; Paillier encryption enters only in the signing-phase MtA, never for the keygen shares. The Coinbase library’s GG20 implementation provides no confidentiality of its own and returns the share as a bare struct field (source):
1// FILE: pkg/tecdsa/gg20/participant/dkg_round2.go — coinbase/kryptology
2
3type DkgRound2P2PSend struct {
4 xij *v1.ShamirShare // raw share — no encryption applied
5}
6// ...
7p2PSend[id] = &DkgRound2P2PSend{ xij: dp.state.X[id-1] }