Skip to content

Stoffel-Labs/mpc-protocols

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

πŸš€ Stoffel MPC Protocols

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 Network trait
  • Reusable common sub-protocols (rbc,secret sharing,etc)
  • Shared arithmetic layers (field, fixed-point, integer)
  • Explicit protocol routing via compact SessionIds

HoneyBadgerMPC 🦑

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.


✨ Features

Included Protocols

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

πŸ“¦ Crate Structure

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:

HoneyBadgerMPCNode<F, R>

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 SessionId fields

πŸƒ How to Run

Running MPC requires:

  1. Start N HoneyBadgerMPCNode instances(Minimum 5 to get the benefit of batch reconstruction)
  2. Connect them with a StoffelNet‐compatible network (Network trait)
  3. Spawn a processing loop for each node
  4. Send messages into the network
  5. Call MPC operations like multiplication, fixed-point division, etc.

β–Ά Minimal Example: Running a 5-Party Secure Multiplication

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.


πŸ§ͺ Running Tests

Run everything:

cargo test

Run a specific test:

cargo test test_session_id

See logs:

RUST_LOG=info cargo test -- --nocapture

πŸ”Œ Running Preprocessing

let 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

πŸ“š Reference Papers