arcium-core-utils 0.8.0

Arcium core utils
Documentation
//! Compile-time protocol suite selection.
//!
//! An [`MpcConfig`] bundles the elliptic curve and the standalone MPC field that circuits and the
//! online phase are instantiated with. The curve fixes the point/scalar/base-field backends; the
//! MPC field is the additional prime-field-like backend historically hardcoded to `Mersenne107`.

use std::{fmt::Debug, hash::Hash};

use primitives::{
    algebra::{
        elliptic_curve::{Curve, Curve25519Ristretto},
        field::{mersenne::Mersenne107, PrimeFieldExtension, SubfieldElement},
    },
    sharing::FieldShare,
    types::identifiers::Named,
};

/// Compile-time protocol suite: the elliptic curve and the standalone MPC field.
///
/// Adding a new MPC field backend means providing a `PrimeFieldExtension` (a `FieldExtension`
/// with `Subfield = Self`, so `FieldShare` secrets are full field elements) with a unique
/// [`Named`](primitives::types::identifiers::Named) name, plus a config type selecting it. Only
/// dealer-generated (`dev`) preprocessing is available for fields without a production
/// preprocessing backend.
pub trait MpcConfig:
    'static + Sized + Send + Sync + Unpin + Copy + Default + Debug + Eq + Hash
{
    type Curve: Curve + Named;
    type Field: PrimeFieldExtension;
}

/// Production suite: Ristretto25519 + Mersenne107.
#[derive(Copy, Clone, Default, Debug, PartialEq, Eq, Hash)]
pub struct DefaultConfig;

impl MpcConfig for DefaultConfig {
    type Curve = Curve25519Ristretto;
    type Field = Mersenne107;
}

/// Test/dev suite: Ristretto25519 + `Gf2_128Field` (full 128-bit binary secrets). Only
/// dealer-generated preprocessing exists for this field.
#[cfg(any(test, feature = "dev"))]
#[derive(Copy, Clone, Default, Debug, PartialEq, Eq, Hash)]
pub struct Gf2_128Config;

#[cfg(any(test, feature = "dev"))]
impl MpcConfig for Gf2_128Config {
    type Curve = Curve25519Ristretto;
    type Field = primitives::algebra::field::binary::Gf2_128Field;
}

pub type CurveOf<Cfg> = <Cfg as MpcConfig>::Curve;
pub type MpcFieldOf<Cfg> = <Cfg as MpcConfig>::Field;
pub type ScalarFieldOf<Cfg> = <CurveOf<Cfg> as Curve>::Scalar;
pub type BaseFieldOf<Cfg> = <CurveOf<Cfg> as Curve>::BaseField;
pub type MpcFieldElement<Cfg> = SubfieldElement<MpcFieldOf<Cfg>>;
pub type MpcFieldShare<Cfg> = FieldShare<MpcFieldOf<Cfg>>;

/// Fixed-width identifier of a [`Named`] type (curve or MPC field), embedded in the serialized
/// circuit format: the name as UTF-8, zero-padded to 32 bytes.
pub fn name_tag<T: Named>() -> [u8; 32] {
    let name = T::get_name();
    let bytes = name.as_bytes();
    assert!(
        bytes.len() <= 32,
        "name {name:?} exceeds the 32-byte circuit tag"
    );
    let mut tag = [0u8; 32];
    tag[..bytes.len()].copy_from_slice(bytes);
    tag
}

/// Best-effort inverse of [`name_tag`] for error messages.
pub fn tag_name(tag: &[u8; 32]) -> String {
    let end = tag.iter().position(|b| *b == 0).unwrap_or(32);
    String::from_utf8_lossy(&tag[..end]).into_owned()
}