Skip to main content

arcis_interface/
types.rs

1/// Represents the kind of scalar value (signed vs unsigned integer).
2///
3/// This enum distinguishes between signed and unsigned integer types in circuit interfaces,
4/// allowing the system to properly serialize/deserialize values and generate correct Rust types.
5///
6/// # Examples
7///
8/// ```
9/// use arcis_interface::{Value, ScalarKind};
10///
11/// // Unsigned 32-bit integer (u32)
12/// let unsigned = Value::Scalar {
13///     size_in_bits: 32,
14///     kind: ScalarKind::Unsigned
15/// };
16///
17/// // Signed 32-bit integer (i32)
18/// let signed = Value::Scalar {
19///     size_in_bits: 32,
20///     kind: ScalarKind::Signed
21/// };
22/// ```
23#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
24pub enum ScalarKind {
25    /// Unsigned integer type (u8, u16, u32, u64, u128).
26    ///
27    /// This is the default for backward compatibility with existing circuits
28    /// that were created before signed integer support was added.
29    #[default]
30    Unsigned,
31
32    /// Signed integer type (i8, i16, i32, i64, i128).
33    ///
34    /// Signed integers use two's complement representation in the MPC protocol.
35    Signed,
36}
37
38/// Circuit interface value types.
39///
40/// Represents all possible types that can be used as inputs or outputs in Arcium circuits.
41#[derive(Debug, Clone, PartialEq, Eq)]
42pub enum Value {
43    MScalar {
44        size_in_bits: usize,
45    },
46    MFloat {
47        size_in_bits: usize,
48    },
49    MBool,
50    /// Plaintext scalar value (integer).
51    ///
52    /// # Fields
53    /// * `size_in_bits` - Bit width of the scalar (8, 16, 32, 64, or 128)
54    /// * `kind` - Whether the scalar is signed or unsigned
55    ///
56    /// # Examples
57    /// * `Scalar { size_in_bits: 32, kind: ScalarKind::Unsigned }` represents u32
58    /// * `Scalar { size_in_bits: 64, kind: ScalarKind::Signed }` represents i64
59    Scalar {
60        size_in_bits: usize,
61        kind: ScalarKind,
62    },
63    Float {
64        size_in_bits: usize,
65    },
66    Bool,
67    Ciphertext {
68        size_in_bits: usize,
69    },
70    ArcisX25519Pubkey,
71    Point,
72    Array(Vec<Value>),
73    Tuple(Vec<Value>),
74    Struct(Vec<Value>),
75}
76
77impl Value {
78    /// Returns the number of scalar field elements this value occupies.
79    ///
80    /// For primitive types (Scalar, Bool, Float, etc.), this returns 1.
81    /// For composite types (Array, Tuple, Struct), this recursively counts all scalar fields.
82    ///
83    /// # Examples
84    ///
85    /// ```
86    /// use arcis_interface::{Value, ScalarKind};
87    ///
88    /// let scalar = Value::Scalar { size_in_bits: 32, kind: ScalarKind::Unsigned };
89    /// assert_eq!(scalar.size_in_scalars(), 1);
90    ///
91    /// let tuple = Value::Tuple(vec![
92    ///     Value::Scalar { size_in_bits: 32, kind: ScalarKind::Unsigned },
93    ///     Value::Bool,
94    /// ]);
95    /// assert_eq!(tuple.size_in_scalars(), 2);
96    /// ```
97    pub fn size_in_scalars(&self) -> usize {
98        match self {
99            Self::MScalar { .. } => 1,
100            Self::MFloat { .. } => 1,
101            Self::Scalar { .. } => 1,
102            Self::Float { .. } => 1,
103            Self::MBool { .. } => 1,
104            Self::Bool { .. } => 1,
105            Self::Ciphertext { .. } => 1,
106            Self::ArcisX25519Pubkey => 1,
107            Self::Point => 1,
108            Self::Array(c) | Self::Tuple(c) | Self::Struct(c) => {
109                c.iter().fold(0, |acc, x| acc + x.size_in_scalars())
110            }
111        }
112    }
113
114    /// Flattens composite types into a vector of primitive values.
115    ///
116    /// For primitive types, returns a single-element vector containing self.
117    /// For composite types (Array, Tuple, Struct), recursively flattens all nested values
118    /// into a flat vector of primitives.
119    ///
120    /// # Examples
121    ///
122    /// ```
123    /// use arcis_interface::{Value, ScalarKind};
124    ///
125    /// let scalar = Value::Scalar { size_in_bits: 32, kind: ScalarKind::Unsigned };
126    /// assert_eq!(scalar.flatten().len(), 1);
127    ///
128    /// let tuple = Value::Tuple(vec![
129    ///     Value::Scalar { size_in_bits: 32, kind: ScalarKind::Unsigned },
130    ///     Value::Tuple(vec![Value::Bool, Value::Bool]),
131    /// ]);
132    /// assert_eq!(tuple.flatten().len(), 3); // u32, bool, bool
133    /// ```
134    pub fn flatten(&self) -> Vec<Value> {
135        match self {
136            Self::Array(c) | Self::Tuple(c) | Self::Struct(c) => {
137                let mut v = Vec::new();
138                for a in c {
139                    v.extend(a.flatten());
140                }
141                v
142            }
143            _ => vec![self.clone()],
144        }
145    }
146}
147
148#[derive(Debug, serde::Serialize)]
149pub struct CircuitInterface {
150    pub name: String,
151    pub inputs: Vec<Value>,
152    pub outputs: Vec<Value>,
153}
154
155impl CircuitInterface {
156    pub fn new(name: String, inputs: Vec<Value>, outputs: Vec<Value>) -> Self {
157        Self {
158            name,
159            inputs,
160            outputs,
161        }
162    }
163
164    pub fn serialize(&self) -> Result<String, serde_json::Error> {
165        serde_json::to_string(self)
166    }
167
168    pub fn from_json(input: &str) -> Result<Self, serde_json::Error> {
169        serde_json::from_str(input)
170    }
171}