How to Sign Transactions with a Key That Never Exists in One Place
A password can be reset. A transfer can sometimes be disputed. Access can be revoked. A private key is harsher: whoever can create a valid signature controls the assets. This article explains how MPC/TSS moves custody from “the key is stored somewhere” to a system where the key is never assembled on any machine, while ordinary blockchain signatures still verify.
In blockchain, the key is the authority
In a conventional backend you have many ways to undo damage: cancel an operation, reverse a payment, reset a password, block an account, call a bank. The system forgives some mistakes because another system sits above it: people, regulators, procedures.
Blockchain does not have that layer. The network does not care who signed the transaction: the owner, a backend service, a compromised CI runner, or an attacker who held the key in memory for 30 milliseconds. If the signature is valid, the funds move.
So the core custody question is not “where can we safely store the private key?” The sharper question is:
Can we build a system where the private key never exists as a whole, but signatures still get produced?
That is the practical meaning of MPC in blockchain custody. Before we get into how a key can “not be assembled,” we need a few terms and then the map where the key actually lives.
MPC is not a product. It is a way to agree on a computation
People say “MPC wallet,” “MPC signature,” and “MPC custody.” That industry shorthand is useful, but imprecise. MPC is a broad class of protocols where several parties jointly compute something without revealing their private inputs to one another. TSS, threshold signature schemes, are the specific custody case: several nodes jointly create one digital signature.
MPC
The broad idea: compute a function together while private inputs stay with the participants. The function might be signing, decryption, key generation, or private analytics.
TSS
The narrow wallet case: there is one public key, nodes hold shares, and the output is one normal signature.
I will use “MPC” in the usual custody sense, but technically we are almost always talking about threshold signatures: distributed authority to create a signature without reconstructing the private key. To see how that authority can be split, start with a single ordinary key.
If you want the math of threshold signatures, go in order: points, discrete logarithms, Schnorr, Shamir, and partial signatures.
If you came for production architecture and already know the basics, jump to why ECDSA hurts more and then to DKG, signer nodes, policy, HSMs, abort scenarios, and the threat model.
If you only need the main takeaway: MPC/TSS does not “hide the key better.” It removes the place where the full private key exists.
key = authority · Schnorr signature · why Shamir is not enough · signature assembly · ECDSA is harder · production · what MPC does not solve
How a signature can exist without assembling the key
First, only mechanics: how an ordinary point on a curve becomes a signature, and why the signing right can be split into shares without assembling the key back together.
A private key is a step number
Technically, a private key is a secret number. For intuition, it is better to treat it as a step number. Imagine a map with a starting point O and one standard step, the generator G. Key arithmetic reduces to one operation: take another step by G. Not coordinate multiplication, not hashing, just a step on the map.
// start at the zero point O, then keep stepping 0G = O // beginning 1G = O + G = G 2G = G + G 3G = 2G + G 4G = 3G + G ... xG = X // after x steps, you land at point X
The entire key pair fits into one line of intuition:
private key x → the step number public key X → the point reached after x steps G → the standard step everyone knows
If you know x, a computer can almost instantly jump from O to X = x·G. The reverse direction is different: standing at X, recovering the step number x is practically impossible. That asymmetry is what signatures live on.
The map does not preserve visible order. Take one more ·G step and you do not land “next door”; you land somewhere that looks unrelated. Neighboring step numbers x and x+1 produce points with no visible relationship. The point itself does not tell you its number or where its neighbor is.
Bottom: the step number, an ordinary line 1, 2, 3, and so on. Every number goes through the same deterministic ·G map and becomes an address in the public field above. Moving along the bottom is ordered; the point above jumps around without visible logic. That is the fog of war: you do not know where a neighboring point is until you compute it.
A step forward and a step backward are both easy on the lower line. Revealing the fog is “god mode”: we draw all points with their numbers. Reality does not give the network that table; for 2²⁵⁶ points there is nowhere to store it. The direct way to learn a point number is brute force. On this tiny map it is instant. On 2²⁵⁶, it is not a strategy.
Teleport forward and the fog of war
You have already seen the forward teleport: know x, and you can jump to X = x·G. Now imagine standing at that public point. You can move from it, step backward, or add a known number of steps. But the point does not say “you are at step 847239…”. Coordinates do not reveal the step number.
X + G = (x + 1) · G // one step forward X - G = (x - 1) · G // one step backward X + 1000G = (x + 1000) · G // jump by a known amount
Subtraction is not forbidden. On an elliptic curve, A - B is just A + (-B). The problem is not taking one step back. The problem is not knowing how many steps lead back to the start.
One step backward is easy.
Finding the step number is practically impossible.
A natural idea is to subtract G one by one until you return to the start, or walk forward from the start until you hit X. That is valid brute force. It works on the toy map. It fails because of the size of the space.
A real secp256k1 group has order close to 2²⁵⁶. That is not “large.” It is astronomically outside brute-force reach, even with trillions of checks per second.
Why forward is fast
When computing a public key, you know x. You can decompose it into binary and jump by powers of two instead of walking step by step:
2G = G + G 4G = 2G + 2G 8G = 4G + 4G // 13 steps? Three doublings and a couple of additions: 13G = 8G + 4G + G
For a huge x, the same idea computes xG in hundreds of operations instead of 2²⁵⁶.
Why backward is not
Backward, you are given only G and X and told to find x. You do not know which powers of two composed x. You can move points, but you cannot read their hidden step number. What remains is search, and the space is 2²⁵⁶.
Forward: known scalar x + known point G → fast scalar mult → X Backward: known point X + known point G → unknown scalar x → discrete log → no known fast algorithm
Naive brute force is the worst simple method, not the best known attack. Baby-step giant-step and Pollard rho reduce generic search to roughly √n ≈ 2¹²⁸ steps. So the practical security of secp256k1 is about 128 bits, not 256. The good news is that 2¹²⁸ is still effectively never.
Choose a secret x. On the left, the computer computes X = x·G with double-and-add. On the right, an attacker searches backward one step at a time. Same result, incomparable cost.
bit length 1
operations ≈ 1
worst case
operations ≈ 1
Forward: about 256 doublings. Backward by naive brute force: up to 2²⁵⁶ ≈ 1.2·10⁷⁷ steps. The best generic attacks are around 2¹²⁸. The gap is not “a thousand times”; it is the gap between milliseconds and never.
“Why does it matter how points look?”
Fair objection: mathematically this is just another coordinate system. The subgroup generated by G is isomorphic to ordinary numbers modulo n. Every point does have a number. The problem is not that the number does not exist.
The problem is that we have no cheap way to convert the point back into that coordinate system.
A point has two descriptions. One is public: coordinates (a, b), easy to verify. The other is secret: X = 12384723…·G, the step number. The map x → X is fast. The reverse map X → x has no known fast algorithm.
Ordinary line
0 — 1 — 2 — 3 — 4 — 5. See point “5” and you know its number immediately. The coordinate is the step number.
Elliptic group
The coordinates are not the step number. They are just large field elements. From them you cannot tell whether this is 4·G, 4,000,000·G, or 2²⁰⁰·G.
Security does not come from mystical chaos. It comes from the absence of visible order: coordinates do not encode the step. If they did, the coordinate would reveal the key and the cryptography would collapse.
Does a finite field mean “wraparound”?
Yes, but carefully. After n steps the sequence returns to the start (nG = O), and key arithmetic happens modulo n: (x + n)·G = x·G. There is a cycle. But ordinary clocks are cyclic too, and their step number is visible. The hard part is that inside the huge cycle, public coordinates do not reveal the order.
Adding participant contributions is easy. That is why Schnorr fits threshold signing so well.
Recovering a hidden multiplier is practically impossible. That is why a public key can be public.
Dividing a distributed secret is hard. That is why threshold ECDSA is more painful than threshold Schnorr.
A Schnorr signature, unpacked step by step
Use Schnorr first, not ECDSA, because the math is cleaner and the threshold idea is visible. The signer picks a one-time random number, the nonce k, and computes:
k = random nonce // one-time material R = k · G // public part of the nonce e = H(R, X, message) // challenge tying everything together s = k + e · x // the only place where key x participates signature = (R, s)
The verifier, the whole network, checks the left and right sides:
s · G == R + e · X
The equality works in three lines:
s · G = (k + e · x) · G = k · G + e · x · G = R + e · X ✓
The verification never touches x directly. It uses only X = x·G, the public point. The network becomes convinced that only the owner of x could have produced the signature, while x remains secret. This linearity, s = k + e·x, is what lets us split the signature into shares.
Same map as Lab 01, but now there are two numbers: the key x and one-time nonce k. Bottom is private: numbers known only to the signer. Top is public: points and values visible to the network. Step through the ceremony and watch two independent formulas land on the same point. That hit is verification.
The last step is the fork that matters. The left side s·G starts from published s and goes through the same ·G map. The right side R + e·X is assembled only from public values. They land on the same point only if s really equals k + e·x. Forging s without x is again the discrete-log problem.
No metaphors here: two machines compute. Adjust secret x and nonce k, then click “Sign” and “Verify.” Left: the signer’s four lines of arithmetic. Right: what the verifier sees and why the equation holds even though it never learns x. The browser demo uses a small multiplicative group mod 467 for visible numbers, while preserving elliptic-curve notation.
The signer writes s = k + e·x, hiding x behind one-time k. The verifier computes s·G and R + e·X. They match only when s was built from the correct x, without revealing that x or making it computable.
Shamir is threshold. But it is a reconstruction threshold
A signature is made by whoever knows x. But we do not want the whole x on one machine. The obvious first answer is to split the key into shares. This is where Shamir helps, but only if we are precise: it solves almost the problem we need, but not exactly.
Shamir Secret Sharing is already threshold cryptography: any m shares out of n can reconstruct the secret; fewer than m learn nothing useful. It is excellent for backups, escrow, and rare recovery procedures.
But Shamir’s default question is different:
Shamir SSS: how many shares are needed to reconstruct the secret? TSS: how many participants are needed to create a signature without reconstructing the secret?
If you use Shamir directly in the daily signing path, the flow becomes:
// classical Shamir in a signing path: 1. collect enough shares 2. reconstruct private key x in one machine's memory 3. sign the transaction 4. erase x
Even if the key lives in memory for 20 milliseconds, that is enough. There is again a single point of compromise: the moment where the whole key exists.
Shamir gives threshold access to a secret.
TSS gives threshold action on behalf of a secret.
The turn that matters: in a threshold signature, participants do not reconstruct the private key. They jointly compute the signature as if the key existed, while the whole key appears nowhere.
Where Lagrange coefficients come from
Before assembling a signature from shares, we need one detail. Shamir shares are values of one polynomial at different points, and the secret is the value at zero, f(0). To recover f(0) from several points, interpolation combines the known values with fixed multipliers. Those multipliers are the Lagrange coefficients λᵢ. They are not “importance weights”; they are polynomial arithmetic.
In Shamir, the secret is:
secret = f(0)
Shares are values at other points:
share₁ = f(1) share₂ = f(2) share₃ = f(3)
Adding two shares directly does not recover the secret. A share is a point on the polynomial. To make the selected shares bring us back to f(0), each share needs the right coefficient.
// simple 2-of-3 scheme, using shares f(1) and f(2): f(0) = 2 · f(1) - 1 · f(2) // therefore: λ₁ = 2 λ₂ = -1
Once the quorum is fixed, the coefficients are fixed too. They depend only on participant indexes, not on the secret. Each signer can compute its own λᵢ from the quorum list. Without the right multipliers, the sum of shares would be a random value, not f(0).
If we compute x = Σ λᵢ·shareᵢ in one place, we have reconstructed the secret. In threshold signing, we use the same weights differently: each signer applies its weight locally inside its partial signature, and x never appears as a separate value.
How one signature is born from shares
Now the main transition. Suppose the private key x is not stored whole but represented as shares across signers. No one knows x, but each signer holds a fragment of signing authority:
signer A → share x₁
signer B → share x₂
signer C → share x₃
// nobody knows x, but together they output s as if they did
Each signer uses its own nonce share, publishes a commitment point Rᵢ, and those points aggregate into a common R:
Rᵢ = kᵢ · G // each signer has its own R = R₁ + R₂ + R₃ // aggregate
The formulas are a teaching skeleton. If one node sees another node's Rᵢ before committing to its own nonce, it may try to influence the final R and therefore e = H(R, X, message). Real threshold Schnorr protocols first bind nonce commitments, then reveal nonce values.
In FROST this includes hiding and binding nonce commitments plus binding factors. For this article the point is enough: commit first, reveal second. A threshold signature is at least a short multi-round protocol, not a single sign(tx) call.
Then each signer computes a partial signature with its key share. λᵢ is the Lagrange coefficient for that signer in the selected quorum.
sᵢ = kᵢ + λᵢ · e · xᵢ // partial signature s = s₁ + s₂ + s₃ // aggregate signature = (R, s) // ordinary Schnorr signature
A partial signature is not a standalone transaction signature. The blockchain cannot verify s₁, s₂, and s₃ separately. They are protocol messages that make sense only inside one signing session and only after aggregation into (R, s).
Publicly, we see points, not private numbers. Points can be added without knowing the hidden scalars inside them. If x = x₁ + x₂, then public points compose the same way:
X₁ = x₁·G, X₂ = x₂·G X₁ + X₂ = x₁·G + x₂·G = (x₁ + x₂)·G = x·G = X
seeing a point ≠ knowing how many G-steps led to it adding points ≠ recovering the private numbers
That is what makes threshold schemes possible: the secret can be split among participants, while the joint public key is still assembled as the sum of their public contributions.
The aggregator can assemble the final signature, but cannot recover the private key from the partial signatures.
To the network, the result looks like one normal signature of the required type. If the chain expects Schnorr, the output is Schnorr. If it expects ECDSA, the output is ECDSA, created by a threshold protocol. Bitcoin or Ethereum do not need to know that internally the signature came from 3 nodes out of 5. That is the main difference from on-chain multisig:
Multisig
The threshold rule lives on-chain, in a script or smart-contract wallet. The network sees that this is not a normal single-sig spend: it is more visible, often more expensive, and chain-specific.
MPC / TSS
The blockchain sees one ordinary signature from one ordinary public key. The threshold, quorum, and signing ceremony remain off-chain.
Schnorr has a standardized threshold protocol, FROST (RFC 9591): a threshold number of participants produces a signature in two rounds. The next lab is not a full FROST spec; it is an interactive model of partial signatures.
Signing authority is represented by shares, Shamir-style. Toggle signers and watch their partial signatures combine into one. Any 2 of 3 produce a valid signature. One does not. The key never appears whole. The arithmetic is real; the parameters are tiny so the mechanics are visible.
The toy interface shows share values only to explain the mechanics. In a real protocol, the aggregator does not see private shareᵢ. It receives commitments, protocol messages, and partial signatures. Those data do not reconstruct the private key; they only assemble the final signature. Each partial signature must also be verified, or a bad node can sabotage the ceremony.
You assemble not the key. You assemble the signature.
This is where intuition often breaks. After Shamir, it is tempting to think through reconstruction: if shares are combined with λᵢ weights to get x, then the key must be assembled somewhere.
The answer is no, if we never compute that sum as a standalone value. Reconstruction Σ λᵢ·shareᵢ = x is the bad path for signing: it creates the key in one memory space. Threshold signing embeds the same sum inside the signature equation.
No share “signs by itself.”
Each share participates in computing one joint signature.
Ordinary Schnorr wants:
s = k + e · x
If the key is Shamir-shared:
x = λ₁·share₁ + λ₂·share₂
The bad path computes that sum first. The good path lets each signer compute only its local contribution:
s₁ = k₁ + e · λ₁ · share₁ // local on signer A s₂ = k₂ + e · λ₂ · share₂ // local on signer B
The aggregator merely adds partial signatures:
s = s₁ + s₂ = (k₁ + e·λ₁·share₁) + (k₂ + e·λ₂·share₂) = (k₁ + k₂) + e · (λ₁·share₁ + λ₂·share₂) = k + e · x
The same Lagrange sum that could reconstruct the key is now hidden inside the signature. It never appears as a separate object. The aggregator holds only s₁, s₂, and their sum s. It cannot extract x, because each partial signature is masked by its own one-time nonce kᵢ.
s = s₁ + s₂ + s₃ does not mean adding finished signatures. These sᵢ are bound to one session: one common R, one public key X, and one message. Pieces from different sessions will not combine.
Look at the two paths: red reconstructs the key in memory; green assembles the signature without materializing the key.
Same quorum {A, B}, same λ values. On the left, shares flow into one place and become the key. On the right, shares stay inside signer nodes; only signature pieces leave. Click step and watch what flows out of each node.
Key difference: on the left, share₁, share₂ are private shares flowing over wires, and the assembly node holds full x. On the right, only s₁, s₂ flow out, masked by nonces; the assembly node holds s, while x appears nowhere.
One question remains: where did the shares come from if the whole key was never generated first? That is DKG, distributed key generation, and it belongs to the production part.
How threshold signatures live in production custody
The toy Schnorr model is clean: shares combine, a signature is born, the key is never assembled. Production adds ECDSA, signer nodes, a coordinator, policy engine, DKG, HSMs, audit trails, and failure handling.
Division over a secret that does not exist whole
We used Schnorr because it exposes the idea. Real custody often has to sign where the format is already fixed: legacy Bitcoin outputs and Ethereum EOA transactions use ECDSA over secp256k1. Bitcoin Taproot uses Schnorr, but a long tail of ECDSA assets and integrations remains.
Schnorr is almost linear. ECDSA puts an inverse nonce inside the signature:
// Schnorr: clean addition s = k + e · x // ECDSA: inversion and multiplication over secrets r = x_coord(k · G) s = k⁻¹ · (H(m) + r · x)
x_coord is the x-coordinate of point k·G, not private key x.
See k⁻¹ and r·x? The protocol has to invert and multiply values distributed among parties, where no node knows the whole value. How do you multiply two secrets if no one knows both?
The keyword is MtA: Multiplicative-to-Additive share conversion. It lets parties turn a product of secret values into additive shares of the result. No participant learns another participant's secret or sees the product whole.
Under the hood, MtA uses homomorphic encryption such as Paillier or Oblivious Transfer. One node encrypts its share, another multiplies the encrypted value by its own share without opening it, and the result is masked with randomness. The parties end up with new shares usable inside the protocol.
Threshold Schnorr is mostly linearity plus careful commitments.
Threshold ECDSA is division, multiplication, and proofs over secrets without revealing those secrets.
That is why ECDSA-MPC grows cryptographic plumbing: pre-signing, zero-knowledge proofs, commitment schemes, Paillier or OT approaches, and identifiable aborts. Protocol families such as GG18, GG20, CMP, CGGMP and implementations such as Taurus multi-party-sig solve this exact problem: produce an ordinary ECDSA signature for secp256k1 without assembling the private key.
What a live MPC system is made of
The math, Schnorr, ECDSA, proofs, commitments, is only part of the work. The rest is engineering: session orchestration, policies, share backups, auditability, failure handling, and evidence of who did what. A signing ceremony is not a single sign(tx) call; it is a short distributed protocol with participants, rounds, and timeouts.
Who owns what
Transaction Builder assembles the raw transaction: recipient, amount, chain id, nonce, gas, fee, memo. Policy Engine decides whether signing is allowed: limits, whitelist, roles, approvals, risk score. Signing Coordinator orchestrates the MPC session: selects quorum, sends requests, tracks rounds and timeouts. Signer Node stores only its own share, validates the request locally, and participates in the protocol. Assembler verifies partial signatures and combines the final signature; it never sees private shares. Broadcaster sends the signed transaction to the network.
Common confusion: the signature nonce k is secret one-time material inside the signature. The transaction nonce is a public account counter in the network transaction. They are different things.
A signer node must not blindly sign everything the coordinator sends. Each node should independently check chain id, asset, amount, recipient, transaction hash, policy decision, session id, request freshness, approvals, and whether the request has already been signed. Otherwise the coordinator becomes too powerful and the system recreates a single point of failure.
The key is not created “somewhere”
The naive model is better than storing a whole key, but still has a hole:
1. create a private key on one machine ← the key existed whole here
2. split it into shares
3. distribute shares
4. delete the original
The correct model is Distributed Key Generation (DKG): nodes jointly produce the public key and their private shares so that the full private key never appears on any machine, not even at birth.
In a good MPC system, the private key is not “created and hidden.”
It never materializes as one object.
How does the common public key X appear if no one knows the full private key? Through Verifiable Secret Sharing (VSS). Each participant generates a private polynomial, privately sends shares to other nodes, and publishes commitments to its coefficients, public contributions such as X₁, X₂, and so on. Other nodes can verify that received shares are consistent without seeing the shares. The common public key is assembled from public contributions: X = X₁ + X₂ + X₃ + …. Later, the blockchain sees this as an ordinary public key.
DKG is not only initial generation. Mature systems also need resharing and key refresh: changing signer membership, refreshing shares, removing a compromised node from the quorum, and sometimes keeping the same public key when the business process requires it.
The rakes you will step on
The most useful engineering section is not “cryptography is beautiful,” but “here is where it hurts.”
MPC/TSS removes the single point of compromise: one memory dump, one signer node, one backup, one CI runner, one engineer account. That is already a lot.
But MPC does not save you if an attacker controls the threshold number of signer nodes, if the policy engine approves a malicious transaction, or if the whole approval path is compromised. MPC distributes signing authority. It is one layer, not the whole defense.
Nonce reuse
Use one k twice and the signature can leak the private key or shares. A nonce is not “just a random number.” It is one-time cryptographic material. Reusing it can burn the key.
ECDSA malleability / Low-S
ECDSA has a mirrored signature form: if (r, s) is valid, (r, n − s) may also be valid. Bitcoin and many secp256k1 integrations require Low-S normalization. The MPC aggregator or signing session must guarantee the final s is in the expected form.
Pre-signing risk
Threshold ECDSA often moves expensive cryptography into pre-signing: precomputed material that makes online signing fast. Convenient, but risky. Pre-signature material must be strictly one time. It cannot be reused, restored from stale backup, desynchronized between nodes, or logged.
Abort attack
A participant can abort late: A and B have sent messages, C observes state and refuses to continue. Mature protocols attach checks and correctness proofs, often zero-knowledge proofs, so a node proves it computed its part correctly without revealing its share. This can distinguish a bad partial signature from a network failure or sabotage.
No illusions: ZKPs and Identifiable Abort reduce room for sabotage and false accusations, but they are not a magic “always find the culprit” button. What can be proven depends on the concrete protocol and threat model.
Network partition
MPC is not a local sign(tx) function. It is a distributed protocol with rounds, commitments, proofs, and timeouts. It inherits the distributed-systems zoo:
timeouts · message ordering · duplicate messages · replay partial failure · version mismatch · clock drift · coordinator crash
Selective failure / malicious coordinator
The coordinator is not necessarily an honest router. It can withhold a message from A to B, trigger a timeout, and later write “node A failed.” Signer nodes must validate the session transcript, keep an auditable trail, and not treat the coordinator as a source of truth.
Domain separation
A node must not sign “some hash.” It must sign a typed context: chain id, asset, address, amount, session id, protocol version, policy decision id. Otherwise cross-chain or cross-protocol replay becomes possible.
Share backup
Losing a share is not “reinstall the service.” Depending on the threshold, it may mean permanent inability to sign. Plan encrypted backups, share recovery, resharing, key rotation, disaster recovery ceremony, and access control for backups.
Logging
Do not log secret protocol messages as ordinary debug. Separate streams:
audit logs: who approved, what was signed, when security logs: aborted sessions, suspicious retries protocol logs: safe metadata only secret material: never
An HSM protects a private key as an object inside a protected device. The key exists; it is locked. MPC/TSS changes the model: the full key exists in no device. These approaches are not mutually exclusive. In practice, TSS shares may live inside HSMs, TEEs such as Intel SGX, or isolated signer services.
MPC ≠ policy
MPC answers exactly one question: how many nodes are needed to create a signature. It does not answer who receives funds, whether the amount is allowed, who approved the transfer, or whether the transfer is legal. That is policy.
MPC solves
How many signers are in the quorum. Where cryptographic authority lives. How to avoid one place holding final signing power.
MPC does NOT solve
Should $500k go to this address? Who approved it? Is this a client address or an attacker? Is the amount normal? Did AML/KYT pass?
MPC protects the private key path.
The policy engine protects the business decision path.
MPC does not replace risk engines, approvals, limits, whitelists, monitoring, or human review. It only ensures the final cryptographic authority is not concentrated in one place. Those are two different layers of defense, and confusing them is a classic mistake.
MPC/TSS removes the single point of compromise and changes the risk model, but it does not replace policy, infrastructure isolation, monitoring, audit, and quorum management.