use super::protocol_ids::derive_protocol_instance_id_u32;
use serde::{Deserialize, Serialize};
use stoffel_vm_types::core_types::DEFAULT_FIXED_POINT_FRACTIONAL_BITS;
use stoffel_vm_types::core_types::DEFAULT_FIXED_POINT_TOTAL_BITS;
use stoffelmpc_mpc::honeybadger::HoneyBadgerMPCNodeOpts;
const DEFAULT_MIN_PARTIES: usize = 5;
const DEFAULT_THRESHOLD: usize = 1;
const DEFAULT_SECURITY_PARAMETER_K: usize = 8;
const DEFAULT_PROTOCOL_TIMEOUT_SECONDS: u64 = 600;
#[allow(dead_code)]
fn derive_prandbit_count(n_random_shares: usize) -> usize {
std::cmp::max(n_random_shares, DEFAULT_FIXED_POINT_FRACTIONAL_BITS)
}
#[allow(dead_code)]
fn derive_prandint_count(n_triples: usize, n_random_shares: usize) -> usize {
std::cmp::max(n_triples.max(1), n_random_shares.max(1))
}
pub fn honeybadger_protocol_instance_id(instance_id: u64) -> u32 {
derive_protocol_instance_id_u32(b"honeybadger", instance_id)
}
pub fn honeybadger_protocol_timeout() -> std::time::Duration {
let seconds = std::env::var("STOFFEL_MPC_PROTOCOL_TIMEOUT_SECONDS")
.ok()
.and_then(|value| value.parse::<u64>().ok())
.filter(|value| *value > 0)
.unwrap_or(DEFAULT_PROTOCOL_TIMEOUT_SECONDS);
std::time::Duration::from_secs(seconds)
}
pub fn avss_protocol_instance_id(instance_id: u64) -> u32 {
derive_protocol_instance_id_u32(b"avss", instance_id)
}
pub fn default_node_opts(
instance_id: u64,
n_triples: usize,
n_random_shares: usize,
) -> HoneyBadgerMPCNodeOpts {
honeybadger_node_opts(
DEFAULT_MIN_PARTIES,
DEFAULT_THRESHOLD,
n_triples,
n_random_shares,
instance_id,
)
.expect("default_node_opts should never fail with valid defaults")
}
pub fn honeybadger_node_opts(
n_parties: usize,
threshold: usize,
n_triples: usize,
n_random_shares: usize,
instance_id: u64,
) -> Result<HoneyBadgerMPCNodeOpts, String> {
honeybadger_node_opts_with_truncation(
n_parties,
threshold,
n_triples,
n_random_shares,
0,
0,
instance_id,
)
}
pub fn honeybadger_node_opts_with_truncation(
n_parties: usize,
threshold: usize,
n_triples: usize,
n_random_shares: usize,
n_prandbit: usize,
n_prandint: usize,
instance_id: u64,
) -> Result<HoneyBadgerMPCNodeOpts, String> {
validate_honeybadger_topology(n_parties, threshold)?;
let l = DEFAULT_FIXED_POINT_TOTAL_BITS;
let k = DEFAULT_SECURITY_PARAMETER_K;
HoneyBadgerMPCNodeOpts::new(
n_parties,
threshold,
n_triples,
n_random_shares,
honeybadger_protocol_instance_id(instance_id),
n_prandbit,
n_prandint,
l,
k,
honeybadger_protocol_timeout(),
)
.map_err(|e| format!("Failed to create HoneyBadger node options: {:?}", e))
}
fn validate_honeybadger_topology(n_parties: usize, threshold: usize) -> Result<(), String> {
let required = threshold
.checked_mul(3)
.and_then(|value| value.checked_add(1))
.ok_or_else(|| format!("HoneyBadger threshold {threshold} is too large"))?;
if n_parties < required {
return Err(format!(
"HoneyBadger requires n_parties ({n_parties}) >= 3 * threshold ({threshold}) + 1 ({required})"
));
}
Ok(())
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum NetEnvelope {
Handshake { role: String, id: usize },
HoneyBadger(Vec<u8>),
}
impl NetEnvelope {
pub fn serialize(&self) -> Vec<u8> {
bincode::serialize(self).expect("envelope serialization should not fail")
}
pub fn try_deserialize(bytes: &[u8]) -> Result<Self, bincode::Error> {
bincode::deserialize(bytes)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn honeybadger_node_opts_accepts_full_width_vm_instance_ids() {
honeybadger_node_opts(5, 1, 0, 0, u64::from(u32::MAX) + 1)
.expect("full-width VM instance ids must be projected into the protocol domain");
}
#[test]
fn honeybadger_node_opts_requires_bft_topology() {
let err =
honeybadger_node_opts(3, 1, 0, 0, 1).expect_err("HoneyBadger must reject n < 3t + 1");
assert!(
err.contains("HoneyBadger requires n_parties (3) >= 3 * threshold (1) + 1 (4)"),
"unexpected error: {err}"
);
honeybadger_node_opts(4, 1, 0, 0, 1)
.expect("n = 3t + 1 should be accepted for HoneyBadger");
}
#[test]
fn honeybadger_protocol_instance_id_is_stable() {
let instance_id = u64::MAX - 9;
assert_eq!(
honeybadger_protocol_instance_id(instance_id),
honeybadger_protocol_instance_id(instance_id)
);
}
}