arcis-interface 0.9.6

Defines the data interface and core types for Arcis circuits.
Documentation
/// Represents the kind of scalar value (signed vs unsigned integer).
///
/// This enum distinguishes between signed and unsigned integer types in circuit interfaces,
/// allowing the system to properly serialize/deserialize values and generate correct Rust types.
///
/// # Examples
///
/// ```
/// use arcis_interface::{Value, ScalarKind};
///
/// // Unsigned 32-bit integer (u32)
/// let unsigned = Value::Scalar {
///     size_in_bits: 32,
///     kind: ScalarKind::Unsigned
/// };
///
/// // Signed 32-bit integer (i32)
/// let signed = Value::Scalar {
///     size_in_bits: 32,
///     kind: ScalarKind::Signed
/// };
/// ```
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub enum ScalarKind {
    /// Unsigned integer type (u8, u16, u32, u64, u128).
    ///
    /// This is the default for backward compatibility with existing circuits
    /// that were created before signed integer support was added.
    #[default]
    Unsigned,

    /// Signed integer type (i8, i16, i32, i64, i128).
    ///
    /// Signed integers use two's complement representation in the MPC protocol.
    Signed,
}

/// Circuit interface value types.
///
/// Represents all possible types that can be used as inputs or outputs in Arcium circuits.
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum Value {
    MScalar {
        size_in_bits: usize,
    },
    MFloat {
        size_in_bits: usize,
    },
    MBool,
    /// Plaintext scalar value (integer).
    ///
    /// # Fields
    /// * `size_in_bits` - Bit width of the scalar (8, 16, 32, 64, or 128)
    /// * `kind` - Whether the scalar is signed or unsigned
    ///
    /// # Examples
    /// * `Scalar { size_in_bits: 32, kind: ScalarKind::Unsigned }` represents u32
    /// * `Scalar { size_in_bits: 64, kind: ScalarKind::Signed }` represents i64
    Scalar {
        size_in_bits: usize,
        kind: ScalarKind,
    },
    Float {
        size_in_bits: usize,
    },
    Bool,
    Ciphertext {
        size_in_bits: usize,
    },
    ArcisX25519Pubkey,
    Point,
    Array(Vec<Value>),
    Tuple(Vec<Value>),
    Struct(Vec<Value>),
}

impl Value {
    /// Returns the number of scalar field elements this value occupies.
    ///
    /// For primitive types (Scalar, Bool, Float, etc.), this returns 1.
    /// For composite types (Array, Tuple, Struct), this recursively counts all scalar fields.
    ///
    /// # Examples
    ///
    /// ```
    /// use arcis_interface::{Value, ScalarKind};
    ///
    /// let scalar = Value::Scalar { size_in_bits: 32, kind: ScalarKind::Unsigned };
    /// assert_eq!(scalar.size_in_scalars(), 1);
    ///
    /// let tuple = Value::Tuple(vec![
    ///     Value::Scalar { size_in_bits: 32, kind: ScalarKind::Unsigned },
    ///     Value::Bool,
    /// ]);
    /// assert_eq!(tuple.size_in_scalars(), 2);
    /// ```
    pub fn size_in_scalars(&self) -> usize {
        match self {
            Self::MScalar { .. } => 1,
            Self::MFloat { .. } => 1,
            Self::Scalar { .. } => 1,
            Self::Float { .. } => 1,
            Self::MBool { .. } => 1,
            Self::Bool { .. } => 1,
            Self::Ciphertext { .. } => 1,
            Self::ArcisX25519Pubkey => 1,
            Self::Point => 1,
            Self::Array(c) | Self::Tuple(c) | Self::Struct(c) => {
                c.iter().fold(0, |acc, x| acc + x.size_in_scalars())
            }
        }
    }

    /// Flattens composite types into a vector of primitive values.
    ///
    /// For primitive types, returns a single-element vector containing self.
    /// For composite types (Array, Tuple, Struct), recursively flattens all nested values
    /// into a flat vector of primitives.
    ///
    /// # Examples
    ///
    /// ```
    /// use arcis_interface::{Value, ScalarKind};
    ///
    /// let scalar = Value::Scalar { size_in_bits: 32, kind: ScalarKind::Unsigned };
    /// assert_eq!(scalar.flatten().len(), 1);
    ///
    /// let tuple = Value::Tuple(vec![
    ///     Value::Scalar { size_in_bits: 32, kind: ScalarKind::Unsigned },
    ///     Value::Tuple(vec![Value::Bool, Value::Bool]),
    /// ]);
    /// assert_eq!(tuple.flatten().len(), 3); // u32, bool, bool
    /// ```
    pub fn flatten(&self) -> Vec<Value> {
        match self {
            Self::Array(c) | Self::Tuple(c) | Self::Struct(c) => {
                let mut v = Vec::new();
                for a in c {
                    v.extend(a.flatten());
                }
                v
            }
            _ => vec![self.clone()],
        }
    }
}

#[derive(Debug, serde::Serialize)]
pub struct CircuitInterface {
    pub name: String,
    pub inputs: Vec<Value>,
    pub outputs: Vec<Value>,
}

impl CircuitInterface {
    pub fn new(name: String, inputs: Vec<Value>, outputs: Vec<Value>) -> Self {
        Self {
            name,
            inputs,
            outputs,
        }
    }

    pub fn serialize(&self) -> Result<String, serde_json::Error> {
        serde_json::to_string(self)
    }

    pub fn from_json(input: &str) -> Result<Self, serde_json::Error> {
        serde_json::from_str(input)
    }
}