Open this lesson in your favourite AI. It'll walk you through the why, explain the demo, and quiz you on the try-it list.
A protocol is only 'secure' in the threat model it was designed for. Semi-honest (aka honest-but-curious) means parties follow the protocol exactly but try to learn extra from the transcript — this is a weak assumption useful when participants have business incentives not to cheat. Malicious means parties can deviate arbitrarily — send wrong messages, abort mid-round, collude. Covert is a middle ground: a cheater gets caught with probability at least 1/2 but not always. Production MPC almost always targets malicious security today because semi-honest schemes catastrophically fail against a single dishonest input.
Watch a naive additive-sharing reconstruction collapse against one malicious party. In semi-honest land this code is 'correct' and hilariously wrong under the first lie.
Use these three in order. Each builds on the one before.
In plain language, explain the three MPC threat models (semi-honest, malicious, covert). Give one concrete, plausible scenario where each is the right assumption and one where it's reckless.
Walk me through how a single malicious party can break a semi-honest additive-sharing reconstruction. What changes in the protocol — specifically, what extra messages or authenticators — do you need to upgrade it to malicious security? Name the cryptographic objects involved, not just 'add MACs'.
I'm designing an MPC protocol for [describe the deployment — e.g. a consortium of 5 banks running AML checks]. The parties are under contract and subject to audits. Given these non-cryptographic controls, argue for or against picking semi-honest security. What's my blast radius if a single bank goes rogue, and does contract law actually close the gap?
# Three parties hold additive shares of a secret x such that s1+s2+s3 = x mod p.
# Semi-honest reconstruction: every party sends their share, sum them up.
P = 2**127 - 1 # large prime
def additive_share(x: int, n: int = 3) -> list[int]:
import secrets
shares = [secrets.randbelow(P) for _ in range(n - 1)]
shares.append((x - sum(shares)) % P)
return shares
def reconstruct(shares: list[int]) -> int:
return sum(shares) % P
# Honest case: works perfectly.
true_secret = 42
shares = additive_share(true_secret)
print("honest:", reconstruct(shares)) # -> 42
# MALICIOUS CASE: party 3 lies and sends shares[2] + 1000.
shares[2] = (shares[2] + 1000) % P
print("malicious:", reconstruct(shares)) # -> 1042, a silent, undetected forgery.
# Nobody can tell who lied, and nobody even knows the result is wrong.
# This is why real protocols ship MACs or ZK proofs.python3 main.py