Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion crates/stoffel-vm/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ libc = "0.2"
stoffelmpc-mpc = { version = "0.1.0", git = "https://github.com/Stoffel-Labs/mpc-protocols.git", branch = "dev" }
stoffelnet = { version = "0.1.0", git = "https://github.com/Stoffel-Labs/stoffel-networking.git" }
stoffel-vm-types = { version = "0.1.0", path = "../stoffel-vm-types" }
stoffel-mpc-coordinator = { version = "0.1.0", git = "https://github.com/Stoffel-Labs/stoffel-mpc-coordinator.git", rev = "dfb4f795ba701369229915eff2cf3dc70d371380" }
stoffel-mpc-coordinator = { version = "0.1.0", git = "https://github.com/Stoffel-Labs/stoffel-mpc-coordinator.git", rev = "914e59410a416112422d71e79680c4e05915cfd4" }
alloy = "1.7.3"
alloy-primitives = "1.5.7"
x509-parser = "0.18.1"
Expand Down
121 changes: 54 additions & 67 deletions crates/stoffel-vm/src/bin/stoffel-run.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,10 @@ use std::collections::HashSet;
use std::fs::File;
use std::sync::Arc;
use std::time::Duration;
use stoffel_mpc_coordinator::off_chain::node_rpc::{NodeRPCClient, NodeRPCServer};
use stoffel_mpc_coordinator::off_chain::OffChainCoordinator;
use stoffel_mpc_coordinator::on_chain;
use stoffel_mpc_coordinator::Coordinator;
Copy link

Copilot AI Apr 28, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Coordinator is imported but not used anywhere in this file (the only match is the use statement). This triggers an unused_imports warning in clippy; remove the import (or reference the trait explicitly if it’s required for method resolution).

Suggested change
use stoffel_mpc_coordinator::Coordinator;

Copilot uses AI. Check for mistakes.
use stoffel_mpc_coordinator::Round;
use stoffel_mpc_coordinator::off_chain::{FakeOffChainCoordinatorClient, FakeNodeRPCClient, FakeNodeRPCServer};
use stoffel_vm::core_vm::VirtualMachine;
#[cfg(any(feature = "honeybadger", feature = "avss"))]
use stoffel_vm::net::curve::{field_from_i64, field_to_i64, SupportedMpcField};
Expand Down Expand Up @@ -2146,27 +2146,27 @@ async fn main() {
.as_ref()
.expect("--wallet-sk required for on-chain client mode");
let provider = on_chain::ws_connect(eth_addr, wallet).await;
let mut coord =
let mut coord: on_chain::FakeOnChainCoordinator<_> =
on_chain::setup_coord(provider, contract, t as u64, 1, key_der.clone()).await;
let signer = PrivateKeySigner::from_str(wallet).unwrap();
let client_addr = signer.address();

coord.wait_for_pp().await.unwrap();
coord.wait_for_input_mask_init().await.unwrap();
coord.wait_for_round(Round::Preprocessing).await.unwrap();
coord.wait_for_round(Round::InputMaskReservation).await.unwrap();
coord.reserve_mask_index(reserved_index).await.unwrap();
eprintln!(
"[on-chain client] obtained reserved index {}",
reserved_index
);

let base_nonce = coord.base_nonce().await;
let sig = on_chain::generate_client_sig(base_nonce, reserved_index, signer).await;
let sig = on_chain::generate_client_sig(base_nonce, reserved_index, signer).await.expect("signing failed");

let rpc_addrs: Vec<(String, u16)> = server_addrs
.iter()
.map(|a| (a.ip().to_string(), a.port()))
.collect();
let node_rpc_client = on_chain::node_rpc::NodeRPCClient::start_rpc_client(
let node_rpc_client = on_chain::FakeNodeRPCClient::start_rpc_client(
t,
rpc_addrs,
cert_der.unwrap(),
Expand All @@ -2178,26 +2178,27 @@ async fn main() {
.await
.unwrap();

coord.wait_for_input().await.unwrap();
coord.wait_for_round(Round::InputCollection).await.unwrap();
let masked = mask + ark_bls12_381::Fr::from(input_values[0] as u64);
coord
.send_masked_input(masked, reserved_index)
.await
.unwrap();

coord.wait_for_mpc().await.unwrap();
coord.wait_for_outputs().await.unwrap();
coord.wait_for_round(Round::MPCExecution).await.unwrap();
coord.wait_for_round(Round::OutputDistribution).await.unwrap();
let outputs = coord.obtain_outputs().await.unwrap();
println!("outputs: {}", format_coordinator_outputs(&outputs));
coord.wait_for_round(Round::ProgramFinished).await.unwrap();
return;
} else {
// Off-chain client mode
let cert = cert_der.clone().expect("--cert required in client mode");
let key = key_der.clone().expect("--key required in client mode");

let ca = coord_addr.as_ref().unwrap();
let mut coord: OffChainCoordinator<ark_bls12_381::Fr> =
OffChainCoordinator::start_rpc_client(
let mut coord =
FakeOffChainCoordinatorClient::start_rpc_client(
&ca.0,
ca.1,
timestamp.expect("--timestamp required in client mode"),
Expand All @@ -2206,37 +2207,38 @@ async fn main() {
cert,
key,
)
.await;
.await.unwrap();

coord.wait_for_pp().await.unwrap();
coord.wait_for_input_mask_init().await.unwrap();
coord.wait_for_round(Round::Preprocessing).await.unwrap();
coord.wait_for_round(Round::InputMaskReservation).await.unwrap();
coord.reserve_mask_index(reserved_index).await.unwrap();

let rpc_addrs: Vec<(String, u16)> = server_addrs
.iter()
.map(|a| (a.ip().to_string(), a.port()))
.collect();
let node_rpc_client: NodeRPCClient<ark_bls12_381::Fr> =
NodeRPCClient::start_rpc_client(
let node_rpc_client =
FakeNodeRPCClient::start_rpc_client(
t,
rpc_addrs,
cert_der.unwrap(),
key_der.unwrap(),
)
.await;
.await.unwrap();
let mask = node_rpc_client.receive_mask().await.unwrap();

coord.wait_for_input().await.unwrap();
coord.wait_for_round(Round::InputCollection).await.unwrap();
let masked = mask + ark_bls12_381::Fr::from(input_values[0] as u64);
coord
.send_masked_input(masked, reserved_index)
.await
.unwrap();

coord.wait_for_mpc().await.unwrap();
coord.wait_for_outputs().await.unwrap();
coord.wait_for_round(Round::MPCExecution).await.unwrap();
coord.wait_for_round(Round::OutputDistribution).await.unwrap();
let outputs = coord.obtain_outputs().await.unwrap();
println!("outputs: {}", format_coordinator_outputs(&outputs));
coord.wait_for_round(Round::ProgramFinished).await.unwrap();
return;
}
}
Expand Down Expand Up @@ -2710,15 +2712,10 @@ async fn main() {
.as_ref()
.expect("--wallet-sk required for on-chain coordinator");
let provider = on_chain::ws_connect(eth_addr, wallet).await;
let mut coord_instance =
let coord_instance =
on_chain::setup_coord(provider, contract, t as u64, 1, None).await;
let coord_for_rpc = coord_instance.coord();

// Grant roles (leader only)
if as_leader {
coord_instance.grant_roles(node_ids.clone()).await.unwrap();
}

// Parse expected client addresses (on-chain uses Ethereum addresses)
let input_addrs: Vec<Address> = expected_clients
.iter()
Expand All @@ -2740,9 +2737,10 @@ async fn main() {

// Coordinator preprocessing trigger
if as_leader {
coord_instance.trigger_pp().await.unwrap();
coord_instance.reset_coord().await.unwrap();
coord_instance.start_preprocessing().await.unwrap();
}
coord_instance.wait_for_pp().await.unwrap();
coord_instance.wait_for_round(Round::Preprocessing).await.unwrap();

// Setup HB engine (BLS12-381 only for on-chain coordinator)
let engine =
Expand Down Expand Up @@ -2801,9 +2799,9 @@ async fn main() {
}

if as_leader {
coord_instance.init_input_masks().await.unwrap();
coord_instance.reserve_input_masks().await.unwrap();
}
coord_instance.wait_for_input_mask_init().await.unwrap();
coord_instance.wait_for_round(Round::InputMaskReservation).await.unwrap();

let client_to_index = coord_instance
.wait_for_indices(input_addrs.len() as u64)
Expand Down Expand Up @@ -2847,24 +2845,10 @@ async fn main() {
});
}

// On-chain client auth
for addr in &input_addrs {
if coord_instance.wait_for_client_auth(*addr).await.unwrap() {
node_rpc.add_auth_status(*addr).await.unwrap_or_else(|e| {
eprintln!("add_auth_status: {:?}", e);
exit(13);
});
eprintln!("[party {}] client {:?} authenticated", my_id, addr);
} else {
eprintln!("[party {}] client {:?} auth failed", my_id, addr);
exit(13);
}
}

if as_leader {
coord_instance.trigger_input().await.unwrap();
coord_instance.collect_inputs().await.unwrap();
}
coord_instance.wait_for_input().await.unwrap();
coord_instance.wait_for_round(Round::InputCollection).await.unwrap();

let client_inputs = coord_instance
.wait_for_inputs(input_addrs.len() as u64, mask_shares)
Expand All @@ -2877,9 +2861,9 @@ async fn main() {

// MPC execution phase
if as_leader {
coord_instance.trigger_mpc().await.unwrap();
coord_instance.start_mpc().await.unwrap();
}
coord_instance.wait_for_mpc().await.unwrap();
coord_instance.wait_for_round(Round::MPCExecution).await.unwrap();

eprintln!("Starting VM execution of '{}'...", agreed_entry);

Expand All @@ -2896,9 +2880,9 @@ async fn main() {

if !output_share.is_empty() {
if as_leader {
coord_instance.trigger_outputs().await.unwrap();
coord_instance.send_output().await.unwrap();
}
coord_instance.wait_for_outputs().await.unwrap();
coord_instance.wait_for_round(Round::OutputDistribution).await.unwrap();

let ids_and_addrs = node_rpc.ids_and_addrs().await;
for client_addr in input_addrs.iter() {
Expand Down Expand Up @@ -2939,12 +2923,12 @@ async fn main() {
// =====================================================================

// Off-chain coordinator initialization (both leader and party modes)
let mut coord_opt: Option<OffChainCoordinator<ark_bls12_381::Fr>> = None;
let mut node_rpc_opt: Option<NodeRPCServer<ark_bls12_381::Fr>> = None;
let mut coord_opt: Option<FakeOffChainCoordinatorClient> = None;
let mut node_rpc_opt: Option<FakeNodeRPCServer> = None;
let mut input_ids: Vec<Vec<u8>> = Vec::new();

if let Some(ref ca) = coord_addr {
let coord = OffChainCoordinator::start_rpc_client(
let coord = FakeOffChainCoordinatorClient::start_rpc_client(
&ca.0,
ca.1,
timestamp.expect("--timestamp required"),
Expand All @@ -2953,7 +2937,7 @@ async fn main() {
cert_der.clone().expect("--cert required"),
key_der.clone().expect("--key required"),
)
.await;
.await.unwrap();
coord_opt = Some(coord);

input_ids = expected_clients
Expand All @@ -2962,13 +2946,13 @@ async fn main() {
.collect();

if let Some(ref rpc) = rpc_addr {
let node_rpc = NodeRPCServer::start(
let node_rpc = FakeNodeRPCServer::start(
&rpc.0,
rpc.1,
cert_der.clone().unwrap(),
key_der.clone().unwrap(),
)
.await;
.await.unwrap();
node_rpc_opt = Some(node_rpc);
}
}
Expand Down Expand Up @@ -3010,9 +2994,10 @@ async fn main() {
// Phase 1: Coordinator preprocessing trigger
if let Some(ref mut coord) = coord_opt {
if as_leader {
coord.trigger_pp().await.unwrap();
coord.reset_coord().await.unwrap();
coord.start_preprocessing().await.unwrap();
}
coord.wait_for_pp().await.unwrap();
coord.wait_for_round(Round::Preprocessing).await.unwrap();
}

// Phase 2: Create MPC engine + preprocessing + coordinator input phases
Expand Down Expand Up @@ -3107,9 +3092,9 @@ async fn main() {
}

if as_leader {
coord.init_input_masks().await.unwrap();
coord.reserve_input_masks().await.unwrap();
}
coord.wait_for_input_mask_init().await.unwrap();
coord.wait_for_round(Round::InputMaskReservation).await.unwrap();

let client_to_index = coord
.wait_for_indices(input_ids.len() as u64)
Expand Down Expand Up @@ -3154,9 +3139,9 @@ async fn main() {
}

if as_leader {
coord.trigger_input().await.unwrap();
coord.collect_inputs().await.unwrap();
}
coord.wait_for_input().await.unwrap();
coord.wait_for_round(Round::InputCollection).await.unwrap();

let client_inputs = coord
.wait_for_inputs(input_ids.len() as u64, mask_shares)
Expand Down Expand Up @@ -3244,9 +3229,9 @@ async fn main() {
// Coordinator: signal MPC execution phase
if let Some(ref mut coord) = coord_opt {
if as_leader {
coord.trigger_mpc().await.unwrap();
coord.start_mpc().await.unwrap();
}
coord.wait_for_mpc().await.unwrap();
coord.wait_for_round(Round::MPCExecution).await.unwrap();
}

eprintln!("Starting VM execution of '{}'...", agreed_entry);
Expand All @@ -3266,9 +3251,9 @@ async fn main() {

if !output_share.is_empty() {
if as_leader {
coord.trigger_outputs().await.unwrap();
coord.send_output().await.unwrap();
}
coord.wait_for_outputs().await.unwrap();
coord.wait_for_round(Round::OutputDistribution).await.unwrap();
for cid in input_ids.iter() {
let share: RobustShare<ark_bls12_381::Fr> =
ark_serialize::CanonicalDeserialize::deserialize_compressed(
Expand All @@ -3294,6 +3279,8 @@ async fn main() {
}
}
}

coord.wait_for_round(Round::ProgramFinished).await.unwrap();
} else {
// No coordinator — auto-reveal as before
let result = if let Value::Share(ty, ref sd) = result {
Expand Down
2 changes: 2 additions & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,7 @@ services:
environment:
- STOFFEL_ROLE=client
- STOFFEL_INPUTS=15
- STOFFEL_CLIENT_INDEX=0
- STOFFEL_SERVERS=172.28.0.10:16180,172.28.0.11:16181,172.28.0.12:16182,172.28.0.13:16183,172.28.0.14:16184
- STOFFEL_N_PARTIES=5
- STOFFEL_THRESHOLD=1
Expand Down Expand Up @@ -244,6 +245,7 @@ services:
environment:
- STOFFEL_ROLE=client
- STOFFEL_INPUTS=25
- STOFFEL_CLIENT_INDEX=1
- STOFFEL_SERVERS=172.28.0.10:16180,172.28.0.11:16181,172.28.0.12:16182,172.28.0.13:16183,172.28.0.14:16184
- STOFFEL_N_PARTIES=5
- STOFFEL_THRESHOLD=1
Expand Down
Loading