use crate::types::{CircuitInterface, ScalarKind, Value};
use serde::{
de::{self, MapAccess, Visitor},
Deserialize,
Deserializer,
Serialize,
};
use serde_json::{json, Value as JsonValue};
use std::fmt;
#[derive(Serialize, Deserialize, Debug)]
pub struct ManticoreInterface {
pub inputs: Vec<String>,
pub outputs: Vec<String>,
}
impl ManticoreInterface {
pub fn new(inputs: Vec<String>, outputs: Vec<String>) -> Self {
Self { 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)
}
}
impl<'de> Deserialize<'de> for CircuitInterface {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
enum Field {
Name,
Inputs,
Outputs,
}
impl<'de> Deserialize<'de> for Field {
fn deserialize<D>(deserializer: D) -> Result<Field, D::Error>
where
D: Deserializer<'de>,
{
struct FieldVisitor;
impl Visitor<'_> for FieldVisitor {
type Value = Field;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("`name`, `inputs`, or `outputs`")
}
fn visit_str<E>(self, value: &str) -> Result<Field, E>
where
E: de::Error,
{
match value {
"name" => Ok(Field::Name),
"inputs" => Ok(Field::Inputs),
"outputs" => Ok(Field::Outputs),
_ => Err(de::Error::unknown_field(value, FIELDS)),
}
}
}
deserializer.deserialize_identifier(FieldVisitor)
}
}
struct CircuitInterfaceVisitor;
impl<'de> Visitor<'de> for CircuitInterfaceVisitor {
type Value = CircuitInterface;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("struct CircuitInterface")
}
fn visit_map<V>(self, mut map: V) -> Result<CircuitInterface, V::Error>
where
V: MapAccess<'de>,
{
let mut name = None;
let mut inputs = None;
let mut outputs = None;
while let Some(key) = map.next_key()? {
match key {
Field::Name => {
if name.is_some() {
return Err(de::Error::duplicate_field("name"));
}
name = Some(map.next_value()?);
}
Field::Inputs => {
if inputs.is_some() {
return Err(de::Error::duplicate_field("inputs"));
}
inputs = Some(map.next_value()?);
}
Field::Outputs => {
if outputs.is_some() {
return Err(de::Error::duplicate_field("outputs"));
}
outputs = Some(map.next_value()?);
}
}
}
let name = name.ok_or_else(|| de::Error::missing_field("name"))?;
let inputs = inputs.ok_or_else(|| de::Error::missing_field("inputs"))?;
let outputs = outputs.ok_or_else(|| de::Error::missing_field("output"))?;
Ok(CircuitInterface {
name,
inputs,
outputs,
})
}
}
const FIELDS: &[&str] = &["name", "inputs", "outputs"];
deserializer.deserialize_struct("CircuitInterface", FIELDS, CircuitInterfaceVisitor)
}
}
impl Value {
fn get_scalar_type_name(size_in_bits: usize, kind: ScalarKind) -> &'static str {
match kind {
ScalarKind::Unsigned => match size_in_bits {
8 => "u8",
16 => "u16",
32 => "u32",
64 => "u64",
128 => "u128",
_ => "scalar",
},
ScalarKind::Signed => match size_in_bits {
8 => "i8",
16 => "i16",
32 => "i32",
64 => "i64",
128 => "i128",
_ => "signed_integer",
},
}
}
}
impl Serialize for Value {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
let json_value = match self {
Value::MScalar { size_in_bits } => json!({
"type": "mscalar",
"size_in_bits": size_in_bits
}),
Value::MFloat { size_in_bits } => json!({
"type": "mfloat",
"size_in_bits": size_in_bits
}),
Value::MBool => json!({
"type": "mbool"
}),
Value::Scalar { size_in_bits, kind } => json!({
"type": Value::get_scalar_type_name(*size_in_bits, *kind),
"size_in_bits": size_in_bits
}),
Value::Float { size_in_bits } => json!({
"type": "float",
"size_in_bits": size_in_bits
}),
Value::Bool => json!({
"type": "bool"
}),
Value::Ciphertext { size_in_bits } => json!({
"type": "ciphertext",
"size_in_bits": size_in_bits
}),
Value::ArcisX25519Pubkey => json!({
"type": "arcis_x25519_pubkey",
}),
Value::Point => json!({
"type": "point"
}),
Value::UnsynchronizedBools { count } => json!({
"type": "unsynchronized_bools",
"count": count
}),
Value::AesCiphertextByte => json!({
"type": "aes_ciphertext_byte"
}),
Value::Array(vec) => json!({
"type": "array",
"content": vec
}),
Value::Tuple(vec) => json!({
"type": "tuple",
"content": vec
}),
Value::Struct(vec) => json!({
"type": "struct",
"content": vec
}),
};
json_value.serialize(serializer)
}
}
impl<'de> Deserialize<'de> for Value {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
let json_value = JsonValue::deserialize(deserializer)?;
match json_value {
JsonValue::Object(map) => {
let type_ = map
.get("type")
.and_then(JsonValue::as_str)
.ok_or_else(|| serde::de::Error::missing_field("type"))?;
match type_ {
"mscalar" => {
let size_in_bits = map
.get("size_in_bits")
.and_then(JsonValue::as_u64)
.ok_or_else(|| serde::de::Error::missing_field("size_in_bits"))?;
Ok(Value::MScalar {
size_in_bits: size_in_bits as usize,
})
}
"mfloat" => {
let size_in_bits = map
.get("size_in_bits")
.and_then(JsonValue::as_u64)
.ok_or_else(|| serde::de::Error::missing_field("size_in_bits"))?;
Ok(Value::MFloat {
size_in_bits: size_in_bits as usize,
})
}
"mbool" => Ok(Value::MBool),
"u8" => Ok(Value::Scalar {
size_in_bits: 8,
kind: ScalarKind::Unsigned,
}),
"u16" => Ok(Value::Scalar {
size_in_bits: 16,
kind: ScalarKind::Unsigned,
}),
"u32" => Ok(Value::Scalar {
size_in_bits: 32,
kind: ScalarKind::Unsigned,
}),
"u64" => Ok(Value::Scalar {
size_in_bits: 64,
kind: ScalarKind::Unsigned,
}),
"u128" => Ok(Value::Scalar {
size_in_bits: 128,
kind: ScalarKind::Unsigned,
}),
"i8" => Ok(Value::Scalar {
size_in_bits: 8,
kind: ScalarKind::Signed,
}),
"i16" => Ok(Value::Scalar {
size_in_bits: 16,
kind: ScalarKind::Signed,
}),
"i32" => Ok(Value::Scalar {
size_in_bits: 32,
kind: ScalarKind::Signed,
}),
"i64" => Ok(Value::Scalar {
size_in_bits: 64,
kind: ScalarKind::Signed,
}),
"i128" => Ok(Value::Scalar {
size_in_bits: 128,
kind: ScalarKind::Signed,
}),
"scalar" => {
let size_in_bits = map
.get("size_in_bits")
.and_then(JsonValue::as_u64)
.ok_or_else(|| serde::de::Error::missing_field("size_in_bits"))?;
Ok(Value::Scalar {
size_in_bits: size_in_bits as usize,
kind: ScalarKind::Unsigned,
})
}
"signed_integer" => {
let size_in_bits = map
.get("size_in_bits")
.and_then(JsonValue::as_u64)
.ok_or_else(|| serde::de::Error::missing_field("size_in_bits"))?;
Ok(Value::Scalar {
size_in_bits: size_in_bits as usize,
kind: ScalarKind::Signed,
})
}
"ciphertext" => {
let size_in_bits = map
.get("size_in_bits")
.and_then(JsonValue::as_u64)
.ok_or_else(|| serde::de::Error::missing_field("size_in_bits"))?;
Ok(Value::Ciphertext {
size_in_bits: size_in_bits as usize,
})
}
"arcis_x25519_pubkey" => Ok(Value::ArcisX25519Pubkey),
"point" => Ok(Value::Point),
"unsynchronized_bools" => {
let count = map
.get("count")
.and_then(JsonValue::as_u64)
.ok_or_else(|| serde::de::Error::missing_field("count"))?;
Ok(Value::UnsynchronizedBools {
count: count as usize,
})
}
"float" => {
let size_in_bits = map
.get("size_in_bits")
.and_then(JsonValue::as_u64)
.ok_or_else(|| serde::de::Error::missing_field("size_in_bits"))?;
Ok(Value::Float {
size_in_bits: size_in_bits as usize,
})
}
"bool" => Ok(Value::Bool),
"aes_ciphertext_byte" => Ok(Value::AesCiphertextByte),
"array" | "tuple" | "struct" => {
let content = map
.get("content")
.ok_or_else(|| serde::de::Error::missing_field("content"))?;
let vec: Vec<Value> =
serde_json::from_value(content.clone()).map_err(|e| {
serde::de::Error::custom(format!(
"Failed to deserialize content: {}",
e
))
})?;
match type_ {
"array" => Ok(Value::Array(vec)),
"tuple" => Ok(Value::Tuple(vec)),
"struct" => Ok(Value::Struct(vec)),
_ => unreachable!(),
}
}
_ => Err(serde::de::Error::unknown_variant(
type_,
&[
"mscalar",
"mfloat",
"mbool",
"u8",
"u16",
"u32",
"u64",
"u128",
"i8",
"i16",
"i32",
"i64",
"i128",
"scalar",
"signed_integer",
"float",
"bool",
"array",
"tuple",
"struct",
"ciphertext",
"arcis_x25519_pubkey",
"point",
"unsynchronized_bools",
"aes_ciphertext_byte",
],
)),
}
}
_ => Err(serde::de::Error::invalid_type(
serde::de::Unexpected::Other("non-object"),
&"object",
)),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use serde_json::json;
#[test]
fn test_mscalar_serialization() {
let value = Value::MScalar { size_in_bits: 32 };
let serialized = serde_json::to_value(value).unwrap();
assert_eq!(
serialized,
json!({
"type": "mscalar",
"size_in_bits": 32
})
);
}
#[test]
fn test_unsynchronized_bools_round_trips() {
let value = Value::UnsynchronizedBools { count: 1568 };
let serialized = serde_json::to_value(value.clone()).unwrap();
assert_eq!(
serialized,
json!({
"type": "unsynchronized_bools",
"count": 1568
})
);
assert_eq!(serde_json::from_value::<Value>(serialized).unwrap(), value);
}
#[test]
fn test_aes_ciphertext_byte_round_trips() {
let value = Value::AesCiphertextByte;
let serialized = serde_json::to_value(value.clone()).unwrap();
assert_eq!(serialized, json!({ "type": "aes_ciphertext_byte" }));
assert_eq!(serde_json::from_value::<Value>(serialized).unwrap(), value);
}
#[test]
fn test_unsynchronized_bools_is_one_value() {
assert_eq!(
Value::UnsynchronizedBools { count: 1568 }.size_in_scalars(),
1
);
}
#[test]
fn test_mbool_serialization() {
let value = Value::MBool;
let serialized = serde_json::to_value(value).unwrap();
assert_eq!(
serialized,
json!({
"type": "mbool"
})
);
}
#[test]
fn test_bool_serialization() {
let value = Value::Bool;
let serialized = serde_json::to_value(value).unwrap();
assert_eq!(
serialized,
json!({
"type": "bool"
})
);
}
#[test]
fn test_array_serialization() {
let value = Value::Array(vec![
Value::Scalar {
size_in_bits: 60,
kind: ScalarKind::Unsigned,
},
Value::Bool,
]);
let serialized = serde_json::to_value(value).unwrap();
assert_eq!(
serialized,
json!({
"type": "array",
"content": [
{
"type": "scalar",
"size_in_bits": 60
},
{
"type": "bool"
}
]
})
);
}
#[test]
fn test_nested_structure_serialization() {
let value = Value::Struct(vec![
Value::Tuple(vec![Value::MScalar { size_in_bits: 32 }, Value::MBool]),
Value::Array(vec![
Value::Scalar {
size_in_bits: 64,
kind: ScalarKind::Unsigned,
},
Value::Bool,
]),
]);
let serialized = serde_json::to_string(&value).unwrap();
let deserialized: Value = serde_json::from_str(&serialized).unwrap();
assert_eq!(value, deserialized);
}
#[test]
fn test_mscalar_deserialization() {
let json = r#"{"type": "mscalar", "size_in_bits": 32}"#;
let deserialized: Value = serde_json::from_str(json).unwrap();
assert_eq!(deserialized, Value::MScalar { size_in_bits: 32 });
}
#[test]
fn test_array_deserialization() {
let json = r#"
{
"type": "array",
"content": [
{"type": "scalar", "size_in_bits": 64},
{"type": "bool"}
]
}"#;
let deserialized: Value = serde_json::from_str(json).unwrap();
assert_eq!(
deserialized,
Value::Array(vec![
Value::Scalar {
size_in_bits: 64,
kind: ScalarKind::Unsigned,
},
Value::Bool,
])
);
}
#[test]
fn test_invalid_type_deserialization() {
let json = r#"{"type": "invalid_type"}"#;
let result: Result<Value, _> = serde_json::from_str(json);
assert!(result.is_err());
}
#[test]
fn test_missing_size_in_bits_deserialization() {
let json = r#"{"type": "mscalar"}"#;
let result: Result<Value, _> = serde_json::from_str(json);
assert!(result.is_err());
}
#[test]
fn test_plaintext_type_serialization() {
let test_cases = [
(
Value::Scalar {
size_in_bits: 8,
kind: ScalarKind::Unsigned,
},
"u8",
),
(
Value::Scalar {
size_in_bits: 16,
kind: ScalarKind::Unsigned,
},
"u16",
),
(
Value::Scalar {
size_in_bits: 32,
kind: ScalarKind::Unsigned,
},
"u32",
),
(
Value::Scalar {
size_in_bits: 64,
kind: ScalarKind::Unsigned,
},
"u64",
),
(
Value::Scalar {
size_in_bits: 128,
kind: ScalarKind::Unsigned,
},
"u128",
),
(
Value::Scalar {
size_in_bits: 24,
kind: ScalarKind::Unsigned,
},
"scalar",
),
];
for (value, expected_type) in test_cases {
let serialized = serde_json::to_value(&value).unwrap();
let expected = match &value {
Value::Scalar { size_in_bits, .. } => json!({
"type": expected_type,
"size_in_bits": size_in_bits
}),
Value::Bool => json!({
"type": expected_type
}),
_ => unreachable!(),
};
assert_eq!(serialized, expected);
let json = serde_json::to_string(&expected).unwrap();
let deserialized: Value = serde_json::from_str(&json).unwrap();
assert_eq!(deserialized, value);
}
}
#[test]
fn test_signed_integer_serialization() {
let test_cases = [
(
Value::Scalar {
size_in_bits: 8,
kind: ScalarKind::Signed,
},
"i8",
),
(
Value::Scalar {
size_in_bits: 16,
kind: ScalarKind::Signed,
},
"i16",
),
(
Value::Scalar {
size_in_bits: 32,
kind: ScalarKind::Signed,
},
"i32",
),
(
Value::Scalar {
size_in_bits: 64,
kind: ScalarKind::Signed,
},
"i64",
),
(
Value::Scalar {
size_in_bits: 128,
kind: ScalarKind::Signed,
},
"i128",
),
(
Value::Scalar {
size_in_bits: 24,
kind: ScalarKind::Signed,
},
"signed_integer",
),
];
for (value, expected_type) in test_cases {
let serialized = serde_json::to_value(&value).unwrap();
let expected = json!({
"type": expected_type,
"size_in_bits": match &value {
Value::Scalar { size_in_bits, .. } => size_in_bits,
_ => unreachable!(),
}
});
assert_eq!(serialized, expected);
let json = serde_json::to_string(&expected).unwrap();
let deserialized: Value = serde_json::from_str(&json).unwrap();
assert_eq!(deserialized, value);
}
}
#[test]
fn test_backward_compatibility() {
let old_json_cases = [
(r#"{"type": "u8", "size_in_bits": 8}"#, 8),
(r#"{"type": "u16", "size_in_bits": 16}"#, 16),
(r#"{"type": "u32", "size_in_bits": 32}"#, 32),
(r#"{"type": "u64", "size_in_bits": 64}"#, 64),
(r#"{"type": "u128", "size_in_bits": 128}"#, 128),
(r#"{"type": "scalar", "size_in_bits": 24}"#, 24),
];
for (json, expected_size) in old_json_cases {
let deserialized: Value = serde_json::from_str(json).unwrap();
assert_eq!(
deserialized,
Value::Scalar {
size_in_bits: expected_size,
kind: ScalarKind::Unsigned
}
);
}
}
#[test]
fn test_mixed_signed_unsigned_serialization() {
let unsigned = Value::Scalar {
size_in_bits: 32,
kind: ScalarKind::Unsigned,
};
let signed = Value::Scalar {
size_in_bits: 32,
kind: ScalarKind::Signed,
};
let unsigned_json = serde_json::to_value(&unsigned).unwrap();
let signed_json = serde_json::to_value(&signed).unwrap();
assert_eq!(
unsigned_json,
json!({
"type": "u32",
"size_in_bits": 32
})
);
assert_eq!(
signed_json,
json!({
"type": "i32",
"size_in_bits": 32
})
);
assert_ne!(unsigned_json, signed_json);
}
}