This repository provides a fully-asynchronous, robust collection of MPC (Multi-Party Computation) protocols designed to run inside the StoffelVM runtime and the StoffelNet networking layer. However, it can also be used independently.
The repository is designed as a general-purpose foundation for hosting multiple MPC protocol families that share common networking, preprocessing, and arithmetic components. This repository is intended to serve as a collection of MPC protocols, not a single fixed construction.
At present, HoneyBadgerMPC is the only fully integrated end-to-end MPC protocol. However, the architecture is deliberately modular so that additional MPC protocols can be added over time without rewriting core components.
Key design goals:
- Protocol-agnostic networking via the
Networktrait - Reusable common sub-protocols (rbc,secret sharing,etc)
- Shared arithmetic layers (field, fixed-point, integer)
- Explicit protocol routing via compact
SessionIds
It includes implementations for HoneyBadgerMPC like random sharing protocols, preprocessing, Beaver triples, fixed-point arithmetic, integer arithmetic, and robust reconstruction procedures.
The core engine is built around the HoneyBadgerMPCNode, which orchestrates all subprotocols using an asynchronous message-passing model.
| Category | Protocol | Status |
|---|---|---|
| Preprocessing | Shamir Random Share (RanSha) | β Implemented |
| Preprocessing | Double Sharing / Random Double Sharing (DouSha / RanDouSha) | β Implemented |
| Preprocessing | Beaver Triple Generation | β Implemented |
| Preprocessing | Random Bit / PRandBit / PRandInt | β Implemented |
| Arithmetic | Secure Beaver Multiplication | β Implemented |
| Arithmetic | Fixed-Point Mul / DivWithConst / Trunc | β Implemented |
| I/O | Distributed Input / Output (via RBC) | β Implemented |
| Reconstruction | Robust Interpolation | β Implemented |
| Reconstruction | Batch Reconstruction | β Implemented |
| Complete MPC | HoneyBadgerMPC Core | β Implemented |
mod.rs exposes the following modules:
robust_interpolate/ # RS-based robust interpolation (HBMPC Fig.1)
batch_recon/ # Batch reconstruction (HBMPC Fig.2)
ran_dou_sha/ # Random double sharing (HBMPC Fig.3)
share_gen/ # Random share generation
double_share/ # Basic double-share generation
triple_gen/ # Beaver triple generator
fpmul/ # Fixed-point arithmetic protocols
input/, output/ # MPC I/O protocols via RBC
mul/ # Secure Beaver multiplication
preprocessing/ # Preprocessing store management
share_gen/ # Random Shamir share generation
All modules plug into:
A node capable of:
- Running preprocessing (random shares, doubles, triples, PRandBit, PRandInt)
- Performing secure arithmetic operations
- Handling RBC-based input and output
- Routing messages using compact
SessionIdfields
Running MPC requires:
- Start
NHoneyBadgerMPCNode instances(Minimum5to get the benefit of batch reconstruction) - Connect them with a StoffelNetβcompatible network (
Networktrait) - Spawn a processing loop for each node
- Send messages into the network
- Call MPC operations like multiplication, fixed-point division, etc.
Replace FakeNetwork with any Network implementation (FakeNetwork, StoffelNet, etc.):
#[tokio::test]
async fn test_mul() {
let n = 5;
let t = 1;
let mut rng = test_rng();
let session_id = SessionId::new(ProtocolType::Mul, 0, 0, 0, 111);
// ---------------- Network ----------------
let config = FakeNetworkConfig::new(500);
let (network, receivers, _) = FakeNetwork::new(n, Some(vec![]), config);
let network: Arc<FakeNetwork> = Arc::new(network);
// ---------------- Inputs ----------------
let x = Fr::rand(&mut rng);
let y = Fr::rand(&mut rng);
let xs = RobustShare::compute_shares(x, n, t, None, &mut rng).unwrap();
let ys = RobustShare::compute_shares(y, n, t, None, &mut rng).unwrap();
// ---------------- Nodes ----------------
let nodes = create_global_nodes::<Fr, Avid, RobustShare<Fr>, FakeNetwork>(
n, t, 2, //No of beaver triples needed, 2 in this case for one multiplication
111, //Instance-ID
);
// ---------------- Process messages ----------------
receive::<Fr, Avid, RobustShare<Fr>, FakeNetwork>(receivers, nodes.clone(), network.clone());
// ---------------- Run MPC ----------------
let handles: Vec<_> = (0..n)
.map(|pid| {
let mut node = nodes[pid].clone();
let net = network.clone();
let x = vec![xs[pid].clone()];
let y = vec![ys[pid].clone()];
tokio::spawn(async move {
node.mul(x, y, net).await.expect("mul failed");
})
})
.collect();
futures::future::join_all(handles).await;
tokio::time::sleep(std::time::Duration::from_millis(200)).await;
// ---------------- Collect & Check ----------------
let shares: Vec<_> = (0..n)
.map(|pid| {
let node = nodes[pid].clone();
async move {
let binding = node.operations.mul.mult_storage.lock().await;
let storage = binding
.get(&session_id)
.expect("missing session")
.lock()
.await;
storage.protocol_output[0].clone()
}
})
.collect::<futures::stream::FuturesOrdered<_>>()
.collect()
.await;
let (_, z) = RobustShare::recover_secret(&shares[..=2 * t], n).unwrap();
assert_eq!(z, x * y);
}
pub fn create_global_nodes<F: PrimeField, R: RBC + 'static, S, N>(
n_parties: usize,
t: usize,
n_triples: usize,
instance_id: u32,
) -> Vec<HoneyBadgerMPCNode<F, R>>
where
N: Network + Send + Sync + 'static,
S: SecretSharingScheme<F>,
HoneyBadgerMPCNode<F, R>: MPCProtocol<F, S, N, MPCOpts = HoneyBadgerMPCNodeOpts>,
{
let parameters =
HoneyBadgerMPCNodeOpts::new(n_parties, t, n_triples, 0, instance_id, 0, 0, 0, 0);
(0..n_parties)
.map(|id| HoneyBadgerMPCNode::setup(id, parameters.clone(), vec![]).unwrap())
.collect()
}
pub fn receive<F, R, S, N>(
mut receivers: Vec<Receiver<Vec<u8>>>,
mut nodes: Vec<HoneyBadgerMPCNode<F, R>>,
net: Arc<N>,
) where
F: PrimeField,
R: RBC + 'static,
N: Network + Send + Sync + 'static,
S: SecretSharingScheme<F>,
HoneyBadgerMPCNode<F, R>: MPCProtocol<F, S, N>,
{
assert_eq!(
receivers.len(),
nodes.len(),
"Each node must have a receiver"
);
for i in 0..receivers.len() {
let mut rx = receivers.remove(0);
let mut node = nodes.remove(0);
let net_clone = net.clone();
tokio::spawn(async move {
while let Some(raw_msg) = rx.recv().await {
if let Err(e) = node.process(raw_msg, net_clone.clone()).await {
tracing::error!("Node {i} failed to process message: {e:?}");
}
}
tracing::info!("Receiver task for node {i} ended");
});
}
}For more examples check out the tests.
cargo testcargo test test_session_idRUST_LOG=info cargo test -- --nocapturelet mut rng = StdRng::from_entropy();
node.run_preprocessing(net.clone(), &mut rng).await?;This generates:
- Random Shamir shares
- Double shares
- Random double shares
- Beaver triples
- PRandBit outputs
- PRandInt outputs
- HoneyBadgerMPC β https://eprint.iacr.org/2019/883
- Fixed-Point Secure Computation β https://ifca.ai/pub/fc10/31_47.pdf