Skip to main content

stoffel/
types.rs

1//! Common SDK value and identifier types.
2//!
3//! `Value` is the SDK payload type used by local execution and client handles.
4//! The crypto wrapper types are intentionally small handles around protocol data
5//! owned by the VM and MPC protocol crates.
6
7use std::collections::BTreeMap;
8use std::fmt;
9
10use serde::{Deserialize, Serialize};
11use stoffel_vm_types::core_types::ShareType;
12
13use crate::config::MpcBackend;
14use crate::error::{Error, Result};
15
16pub type PartyId = usize;
17pub type ClientId = stoffelnet::network_utils::ClientId;
18pub type Round = stoffel_mpc_coordinator_shared::Round;
19pub type MaskIndex = u64;
20
21/// SDK-level scalar type expected by a typed client input or output.
22#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
23#[serde(rename_all = "snake_case")]
24pub enum ClientValueType {
25    Integer,
26    Boolean,
27    FixedPoint,
28}
29
30impl ClientValueType {
31    pub fn is_compatible_with_share_type(self, share_type: ShareType) -> bool {
32        match (self, share_type) {
33            (ClientValueType::Boolean, ShareType::SecretInt { bit_length: 1 }) => true,
34            (ClientValueType::Integer, ShareType::SecretInt { bit_length }) => bit_length > 1,
35            (ClientValueType::Integer, ShareType::SecretUInt { .. }) => true,
36            (ClientValueType::FixedPoint, ShareType::SecretFixedPoint { .. }) => true,
37            _ => false,
38        }
39    }
40}
41
42/// A Rust scalar that can be used as a typed client input.
43pub trait ClientInputValue {
44    const VALUE_TYPE: ClientValueType;
45
46    fn into_sdk_value(self) -> Value;
47}
48
49/// A Rust scalar that can be decoded from typed client output.
50pub trait ClientOutputValue: Sized {
51    const VALUE_TYPE: ClientValueType;
52
53    fn try_from_sdk_value(value: Value) -> Result<Self>;
54}
55
56/// Compile-time typed client input payload.
57///
58/// Implement this trait for domain structs when tuple inputs are not expressive
59/// enough. The SDK still validates the declared Rust type shape against the
60/// loaded program manifest before network submission.
61pub trait TypedClientInputs {
62    fn into_values(self) -> Vec<Value>;
63
64    fn value_types() -> Vec<ClientValueType>;
65}
66
67/// Compile-time typed client output payload.
68///
69/// Implement this trait for domain structs when tuple outputs are not
70/// expressive enough.
71pub trait TypedClientOutputs: Sized {
72    fn from_values(values: Vec<Value>) -> Result<Self>;
73
74    fn value_types() -> Vec<ClientValueType>;
75}
76
77/// Positional arguments for direct program execution.
78///
79/// Rust does not support variadic methods, so the SDK accepts `()`, one scalar
80/// value, or tuples of scalar values:
81///
82/// ```
83/// # use stoffel::prelude::*;
84/// # fn example(program: &StoffelRuntime) -> stoffel::Result<()> {
85/// let result = program.execute("main", (40_i64, 2_i64))?;
86/// # let _ = result;
87/// # Ok(())
88/// # }
89/// ```
90pub trait ProgramArgs {
91    fn into_values(self) -> Vec<Value>;
92}
93
94/// Generated program metadata emitted by `stoffel-bindgen`.
95///
96/// This marker trait lets application code carry the bytecode manifest's
97/// backend, curve, and client IO shape at the Rust type level. Builders can use
98/// it to select the program backend without hand-written backend/curve literals,
99/// and clients can validate generated bindings against the loaded bytecode
100/// before submitting network inputs.
101pub trait GeneratedProgramManifest {
102    const BACKEND: MpcBackend;
103
104    fn client_input_types(client_slot: u64) -> Option<&'static [ClientValueType]>;
105
106    fn client_output_types(client_slot: u64) -> Option<&'static [ClientValueType]>;
107}
108
109/// Public SDK value type.
110#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
111pub enum Value {
112    I64(i64),
113    U64(u64),
114    Bool(bool),
115    Float(f64),
116    String(String),
117    Bytes(Vec<u8>),
118    List(Vec<Value>),
119    Object(BTreeMap<String, Value>),
120    Unit,
121}
122
123#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
124pub struct ValueSummary {
125    pub kind: String,
126    pub item_count: Option<usize>,
127    pub byte_len: Option<usize>,
128}
129
130impl Value {
131    pub fn kind(&self) -> &'static str {
132        match self {
133            Value::I64(_) => "i64",
134            Value::U64(_) => "u64",
135            Value::Bool(_) => "bool",
136            Value::Float(_) => "float",
137            Value::String(_) => "string",
138            Value::Bytes(_) => "bytes",
139            Value::List(_) => "list",
140            Value::Object(_) => "object",
141            Value::Unit => "unit",
142        }
143    }
144
145    pub fn summary(&self) -> ValueSummary {
146        ValueSummary {
147            kind: self.kind().to_owned(),
148            item_count: match self {
149                Value::List(values) => Some(values.len()),
150                Value::Object(fields) => Some(fields.len()),
151                _ => None,
152            },
153            byte_len: match self {
154                Value::Bytes(bytes) => Some(bytes.len()),
155                Value::String(value) => Some(value.len()),
156                _ => None,
157            },
158        }
159    }
160
161    pub fn as_i64(&self) -> Option<i64> {
162        match self {
163            Value::I64(value) => Some(*value),
164            _ => None,
165        }
166    }
167
168    pub fn as_u64(&self) -> Option<u64> {
169        match self {
170            Value::U64(value) => Some(*value),
171            _ => None,
172        }
173    }
174
175    pub fn as_bool(&self) -> Option<bool> {
176        match self {
177            Value::Bool(value) => Some(*value),
178            _ => None,
179        }
180    }
181
182    pub fn as_f64(&self) -> Option<f64> {
183        match self {
184            Value::Float(value) => Some(*value),
185            _ => None,
186        }
187    }
188
189    pub fn as_str(&self) -> Option<&str> {
190        match self {
191            Value::String(value) => Some(value),
192            _ => None,
193        }
194    }
195
196    pub fn as_bytes(&self) -> Option<&[u8]> {
197        match self {
198            Value::Bytes(value) => Some(value),
199            _ => None,
200        }
201    }
202
203    pub fn as_list(&self) -> Option<&[Value]> {
204        match self {
205            Value::List(values) => Some(values),
206            _ => None,
207        }
208    }
209
210    pub fn as_object(&self) -> Option<&BTreeMap<String, Value>> {
211        match self {
212            Value::Object(fields) => Some(fields),
213            _ => None,
214        }
215    }
216
217    pub fn is_unit(&self) -> bool {
218        matches!(self, Value::Unit)
219    }
220
221    pub fn into_string(self) -> Option<String> {
222        match self {
223            Value::String(value) => Some(value),
224            _ => None,
225        }
226    }
227
228    pub fn into_bytes(self) -> Option<Vec<u8>> {
229        match self {
230            Value::Bytes(value) => Some(value),
231            _ => None,
232        }
233    }
234
235    pub fn into_list(self) -> Option<Vec<Value>> {
236        match self {
237            Value::List(values) => Some(values),
238            _ => None,
239        }
240    }
241
242    pub fn into_object(self) -> Option<BTreeMap<String, Value>> {
243        match self {
244            Value::Object(fields) => Some(fields),
245            _ => None,
246        }
247    }
248
249    pub(crate) fn from_vm_value(value: stoffel_vm_types::core_types::Value) -> Option<Self> {
250        match value {
251            stoffel_vm_types::core_types::Value::I64(value) => Some(Value::I64(value)),
252            stoffel_vm_types::core_types::Value::I32(value) => Some(Value::I64(i64::from(value))),
253            stoffel_vm_types::core_types::Value::I16(value) => Some(Value::I64(i64::from(value))),
254            stoffel_vm_types::core_types::Value::I8(value) => Some(Value::I64(i64::from(value))),
255            stoffel_vm_types::core_types::Value::U64(value) => Some(Value::U64(value)),
256            stoffel_vm_types::core_types::Value::U32(value) => Some(Value::U64(u64::from(value))),
257            stoffel_vm_types::core_types::Value::U16(value) => Some(Value::U64(u64::from(value))),
258            stoffel_vm_types::core_types::Value::U8(value) => Some(Value::U64(u64::from(value))),
259            stoffel_vm_types::core_types::Value::Bool(value) => Some(Value::Bool(value)),
260            stoffel_vm_types::core_types::Value::Float(value) => Some(Value::Float(value.value())),
261            stoffel_vm_types::core_types::Value::String(value) => Some(Value::String(value)),
262            stoffel_vm_types::core_types::Value::Unit => Some(Value::Unit),
263            _ => None,
264        }
265    }
266}
267
268impl fmt::Display for Value {
269    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
270        match self {
271            Value::I64(value) => write!(f, "{value}"),
272            Value::U64(value) => write!(f, "{value}"),
273            Value::Bool(value) => write!(f, "{value}"),
274            Value::Float(value) => write!(f, "{value}"),
275            Value::String(value) => write!(f, "{value}"),
276            Value::Bytes(value) => write!(f, "0x{}", hex_encode(value)),
277            Value::List(values) => {
278                write!(f, "[")?;
279                for (index, value) in values.iter().enumerate() {
280                    if index > 0 {
281                        write!(f, ", ")?;
282                    }
283                    write!(f, "{value}")?;
284                }
285                write!(f, "]")
286            }
287            Value::Object(fields) => {
288                write!(f, "{{")?;
289                for (index, (name, value)) in fields.iter().enumerate() {
290                    if index > 0 {
291                        write!(f, ", ")?;
292                    }
293                    write!(f, "{name}: {value}")?;
294                }
295                write!(f, "}}")
296            }
297            Value::Unit => write!(f, "()"),
298        }
299    }
300}
301
302fn hex_encode(bytes: &[u8]) -> String {
303    const HEX: &[u8; 16] = b"0123456789abcdef";
304    let mut out = String::with_capacity(bytes.len() * 2);
305    for byte in bytes {
306        out.push(HEX[(byte >> 4) as usize] as char);
307        out.push(HEX[(byte & 0x0f) as usize] as char);
308    }
309    out
310}
311
312macro_rules! value_from_int {
313    ($($ty:ty),* $(,)?) => {
314        $(
315            impl From<$ty> for Value {
316                fn from(value: $ty) -> Self {
317                    Value::I64(value as i64)
318                }
319            }
320        )*
321    };
322}
323
324value_from_int!(i8, i16, i32, i64, isize);
325
326macro_rules! value_from_uint {
327    ($($ty:ty),* $(,)?) => {
328        $(
329            impl From<$ty> for Value {
330                fn from(value: $ty) -> Self {
331                    Value::U64(value as u64)
332                }
333            }
334        )*
335    };
336}
337
338value_from_uint!(u8, u16, u32, u64, usize);
339
340macro_rules! client_integer_input {
341    ($($ty:ty),* $(,)?) => {
342        $(
343            impl ClientInputValue for $ty {
344                const VALUE_TYPE: ClientValueType = ClientValueType::Integer;
345
346                fn into_sdk_value(self) -> Value {
347                    Value::from(self)
348                }
349            }
350        )*
351    };
352}
353
354client_integer_input!(i8, i16, i32, i64, isize, u8, u16, u32, u64, usize);
355
356impl From<bool> for Value {
357    fn from(value: bool) -> Self {
358        Value::Bool(value)
359    }
360}
361
362impl ClientInputValue for bool {
363    const VALUE_TYPE: ClientValueType = ClientValueType::Boolean;
364
365    fn into_sdk_value(self) -> Value {
366        Value::Bool(self)
367    }
368}
369
370impl From<f64> for Value {
371    fn from(value: f64) -> Self {
372        Value::Float(value)
373    }
374}
375
376impl ClientInputValue for f64 {
377    const VALUE_TYPE: ClientValueType = ClientValueType::FixedPoint;
378
379    fn into_sdk_value(self) -> Value {
380        Value::Float(self)
381    }
382}
383
384impl From<f32> for Value {
385    fn from(value: f32) -> Self {
386        Value::Float(f64::from(value))
387    }
388}
389
390impl ClientInputValue for f32 {
391    const VALUE_TYPE: ClientValueType = ClientValueType::FixedPoint;
392
393    fn into_sdk_value(self) -> Value {
394        Value::Float(f64::from(self))
395    }
396}
397
398impl From<&str> for Value {
399    fn from(value: &str) -> Self {
400        Value::String(value.to_owned())
401    }
402}
403
404impl From<&String> for Value {
405    fn from(value: &String) -> Self {
406        Value::String(value.clone())
407    }
408}
409
410impl From<String> for Value {
411    fn from(value: String) -> Self {
412        Value::String(value)
413    }
414}
415
416impl From<BTreeMap<String, Value>> for Value {
417    fn from(value: BTreeMap<String, Value>) -> Self {
418        Value::Object(value)
419    }
420}
421
422impl From<&[u8]> for Value {
423    fn from(value: &[u8]) -> Self {
424        Value::Bytes(value.to_vec())
425    }
426}
427
428impl<const N: usize> From<[u8; N]> for Value {
429    fn from(value: [u8; N]) -> Self {
430        Value::Bytes(value.to_vec())
431    }
432}
433
434impl From<Vec<u8>> for Value {
435    fn from(value: Vec<u8>) -> Self {
436        Value::Bytes(value)
437    }
438}
439
440impl From<Vec<Value>> for Value {
441    fn from(value: Vec<Value>) -> Self {
442        Value::List(value)
443    }
444}
445
446impl From<()> for Value {
447    fn from((): ()) -> Self {
448        Value::Unit
449    }
450}
451
452fn value_type_error(expected: &'static str, actual: &Value) -> Error {
453    Error::InvalidInput(format!(
454        "expected {expected} SDK value, got {}",
455        actual.kind()
456    ))
457}
458
459macro_rules! try_from_value_copy {
460    ($target:ty, $variant:ident, $expected:literal) => {
461        impl TryFrom<Value> for $target {
462            type Error = Error;
463
464            fn try_from(value: Value) -> Result<Self> {
465                <$target>::try_from(&value)
466            }
467        }
468
469        impl TryFrom<&Value> for $target {
470            type Error = Error;
471
472            fn try_from(value: &Value) -> Result<Self> {
473                match value {
474                    Value::$variant(value) => Ok(*value),
475                    actual => Err(value_type_error($expected, actual)),
476                }
477            }
478        }
479    };
480}
481
482try_from_value_copy!(f64, Float, "float");
483
484macro_rules! try_from_signed_integer_value {
485    ($($target:ty),* $(,)?) => {
486        $(
487            impl TryFrom<Value> for $target {
488                type Error = Error;
489
490                fn try_from(value: Value) -> Result<Self> {
491                    <$target>::try_from(&value)
492                }
493            }
494
495            impl TryFrom<&Value> for $target {
496                type Error = Error;
497
498                fn try_from(value: &Value) -> Result<Self> {
499                    match value {
500                        Value::I64(value) => <$target>::try_from(*value).map_err(|_| {
501                            Error::InvalidInput(format!("{value} is out of range for {}", stringify!($target)))
502                        }),
503                        Value::U64(value) => <$target>::try_from(*value).map_err(|_| {
504                            Error::InvalidInput(format!("{value} is out of range for {}", stringify!($target)))
505                        }),
506                        actual => Err(value_type_error(stringify!($target), actual)),
507                    }
508                }
509            }
510        )*
511    };
512}
513
514macro_rules! try_from_unsigned_integer_value {
515    ($($target:ty),* $(,)?) => {
516        $(
517            impl TryFrom<Value> for $target {
518                type Error = Error;
519
520                fn try_from(value: Value) -> Result<Self> {
521                    <$target>::try_from(&value)
522                }
523            }
524
525            impl TryFrom<&Value> for $target {
526                type Error = Error;
527
528                fn try_from(value: &Value) -> Result<Self> {
529                    match value {
530                        Value::U64(value) => <$target>::try_from(*value).map_err(|_| {
531                            Error::InvalidInput(format!("{value} is out of range for {}", stringify!($target)))
532                        }),
533                        Value::I64(value) => <$target>::try_from(*value).map_err(|_| {
534                            Error::InvalidInput(format!("{value} is out of range for {}", stringify!($target)))
535                        }),
536                        actual => Err(value_type_error(stringify!($target), actual)),
537                    }
538                }
539            }
540        )*
541    };
542}
543
544try_from_signed_integer_value!(i8, i16, i32, i64);
545try_from_unsigned_integer_value!(u8, u16, u32, u64);
546
547impl TryFrom<Value> for bool {
548    type Error = Error;
549
550    fn try_from(value: Value) -> Result<Self> {
551        bool::try_from(&value)
552    }
553}
554
555impl TryFrom<&Value> for bool {
556    type Error = Error;
557
558    fn try_from(value: &Value) -> Result<Self> {
559        match value {
560            Value::Bool(value) => Ok(*value),
561            Value::U64(0) | Value::I64(0) => Ok(false),
562            Value::U64(1) | Value::I64(1) => Ok(true),
563            actual => Err(value_type_error("bool or integer 0/1", actual)),
564        }
565    }
566}
567
568macro_rules! client_integer_output {
569    ($($ty:ty),* $(,)?) => {
570        $(
571            impl ClientOutputValue for $ty {
572                const VALUE_TYPE: ClientValueType = ClientValueType::Integer;
573
574                fn try_from_sdk_value(value: Value) -> Result<Self> {
575                    <$ty>::try_from(value)
576                }
577            }
578        )*
579    };
580}
581
582client_integer_output!(i8, i16, i32, i64, u8, u16, u32, u64);
583
584impl ClientOutputValue for bool {
585    const VALUE_TYPE: ClientValueType = ClientValueType::Boolean;
586
587    fn try_from_sdk_value(value: Value) -> Result<Self> {
588        bool::try_from(value)
589    }
590}
591
592impl ClientOutputValue for f64 {
593    const VALUE_TYPE: ClientValueType = ClientValueType::FixedPoint;
594
595    fn try_from_sdk_value(value: Value) -> Result<Self> {
596        f64::try_from(value)
597    }
598}
599
600impl TypedClientInputs for () {
601    fn into_values(self) -> Vec<Value> {
602        Vec::new()
603    }
604
605    fn value_types() -> Vec<ClientValueType> {
606        Vec::new()
607    }
608}
609
610impl ProgramArgs for () {
611    fn into_values(self) -> Vec<Value> {
612        Vec::new()
613    }
614}
615
616impl<T> TypedClientInputs for T
617where
618    T: ClientInputValue,
619{
620    fn into_values(self) -> Vec<Value> {
621        vec![self.into_sdk_value()]
622    }
623
624    fn value_types() -> Vec<ClientValueType> {
625        vec![T::VALUE_TYPE]
626    }
627}
628
629macro_rules! program_arg_scalar {
630    ($($ty:ty),* $(,)?) => {
631        $(
632            impl ProgramArgs for $ty {
633                fn into_values(self) -> Vec<Value> {
634                    vec![self.into()]
635                }
636            }
637        )*
638    };
639}
640
641program_arg_scalar!(
642    i8, i16, i32, i64, isize,
643    u8, u16, u32, u64, usize,
644    bool, f32, f64,
645    String, &str, Value,
646    Vec<u8>, &[u8], Vec<Value>, BTreeMap<String, Value>,
647);
648
649impl<const N: usize> ProgramArgs for [u8; N] {
650    fn into_values(self) -> Vec<Value> {
651        vec![self.into()]
652    }
653}
654
655impl ProgramArgs for &String {
656    fn into_values(self) -> Vec<Value> {
657        vec![self.into()]
658    }
659}
660
661impl TypedClientOutputs for () {
662    fn from_values(values: Vec<Value>) -> Result<Self> {
663        if values.is_empty() {
664            Ok(())
665        } else {
666            Err(Error::InvalidInput(format!(
667                "expected 0 typed outputs, got {}",
668                values.len()
669            )))
670        }
671    }
672
673    fn value_types() -> Vec<ClientValueType> {
674        Vec::new()
675    }
676}
677
678impl<T> TypedClientOutputs for T
679where
680    T: ClientOutputValue,
681{
682    fn from_values(values: Vec<Value>) -> Result<Self> {
683        let [value]: [Value; 1] = values.try_into().map_err(|values: Vec<Value>| {
684            Error::InvalidInput(format!("expected 1 typed output, got {}", values.len()))
685        })?;
686        T::try_from_sdk_value(value)
687    }
688
689    fn value_types() -> Vec<ClientValueType> {
690        vec![T::VALUE_TYPE]
691    }
692}
693
694macro_rules! typed_client_tuple {
695    ($(($($type_name:ident $value_name:ident),+)),+ $(,)?) => {
696        $(
697            impl<$($type_name),+> TypedClientInputs for ($($type_name,)+)
698            where
699                $($type_name: ClientInputValue),+
700            {
701                fn into_values(self) -> Vec<Value> {
702                    let ($($value_name,)+) = self;
703                    vec![$($value_name.into_sdk_value()),+]
704                }
705
706                fn value_types() -> Vec<ClientValueType> {
707                    vec![$($type_name::VALUE_TYPE),+]
708                }
709            }
710
711            impl<$($type_name),+> TypedClientOutputs for ($($type_name,)+)
712            where
713                $($type_name: ClientOutputValue),+
714            {
715                fn from_values(values: Vec<Value>) -> Result<Self> {
716                    let expected = Self::value_types().len();
717                    let actual = values.len();
718                    if actual != expected {
719                        return Err(Error::InvalidInput(format!(
720                            "expected {expected} typed outputs, got {actual}"
721                        )));
722                    }
723                    let mut values = values.into_iter();
724                    Ok((
725                        $(
726                            $type_name::try_from_sdk_value(values.next().expect("length checked"))?,
727                        )+
728                    ))
729                }
730
731                fn value_types() -> Vec<ClientValueType> {
732                    vec![$($type_name::VALUE_TYPE),+]
733                }
734            }
735
736            impl<$($type_name),+> ProgramArgs for ($($type_name,)+)
737            where
738                $($type_name: Into<Value>),+
739            {
740                fn into_values(self) -> Vec<Value> {
741                    let ($($value_name,)+) = self;
742                    vec![$($value_name.into()),+]
743                }
744            }
745        )+
746    };
747}
748
749typed_client_tuple!(
750    (A a, B b),
751    (A a, B b, C c),
752    (A a, B b, C c, D d),
753    (A a, B b, C c, D d, E e),
754    (A a, B b, C c, D d, E e, F f),
755    (A a, B b, C c, D d, E e, F f, G g),
756    (A a, B b, C c, D d, E e, F f, G g, H h),
757);
758
759impl TryFrom<Value> for String {
760    type Error = Error;
761
762    fn try_from(value: Value) -> Result<Self> {
763        match value {
764            Value::String(value) => Ok(value),
765            actual => Err(value_type_error("string", &actual)),
766        }
767    }
768}
769
770impl TryFrom<&Value> for String {
771    type Error = Error;
772
773    fn try_from(value: &Value) -> Result<Self> {
774        match value {
775            Value::String(value) => Ok(value.clone()),
776            actual => Err(value_type_error("string", actual)),
777        }
778    }
779}
780
781impl<'a> TryFrom<&'a Value> for &'a str {
782    type Error = Error;
783
784    fn try_from(value: &'a Value) -> Result<Self> {
785        match value {
786            Value::String(value) => Ok(value),
787            actual => Err(value_type_error("string", actual)),
788        }
789    }
790}
791
792impl TryFrom<Value> for Vec<u8> {
793    type Error = Error;
794
795    fn try_from(value: Value) -> Result<Self> {
796        match value {
797            Value::Bytes(value) => Ok(value),
798            actual => Err(value_type_error("bytes", &actual)),
799        }
800    }
801}
802
803impl TryFrom<&Value> for Vec<u8> {
804    type Error = Error;
805
806    fn try_from(value: &Value) -> Result<Self> {
807        match value {
808            Value::Bytes(value) => Ok(value.clone()),
809            actual => Err(value_type_error("bytes", actual)),
810        }
811    }
812}
813
814impl<'a> TryFrom<&'a Value> for &'a [u8] {
815    type Error = Error;
816
817    fn try_from(value: &'a Value) -> Result<Self> {
818        match value {
819            Value::Bytes(value) => Ok(value),
820            actual => Err(value_type_error("bytes", actual)),
821        }
822    }
823}
824
825impl TryFrom<Value> for Vec<Value> {
826    type Error = Error;
827
828    fn try_from(value: Value) -> Result<Self> {
829        match value {
830            Value::List(values) => Ok(values),
831            actual => Err(value_type_error("list", &actual)),
832        }
833    }
834}
835
836impl<'a> TryFrom<&'a Value> for &'a [Value] {
837    type Error = Error;
838
839    fn try_from(value: &'a Value) -> Result<Self> {
840        match value {
841            Value::List(values) => Ok(values),
842            actual => Err(value_type_error("list", actual)),
843        }
844    }
845}
846
847impl TryFrom<Value> for () {
848    type Error = Error;
849
850    fn try_from(value: Value) -> Result<Self> {
851        match value {
852            Value::Unit => Ok(()),
853            actual => Err(value_type_error("unit", &actual)),
854        }
855    }
856}
857
858impl TryFrom<&Value> for () {
859    type Error = Error;
860
861    fn try_from(value: &Value) -> Result<Self> {
862        match value {
863            Value::Unit => Ok(()),
864            actual => Err(value_type_error("unit", actual)),
865        }
866    }
867}
868
869#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
870pub struct Share {
871    pub key_name: String,
872    #[serde(default, skip_serializing_if = "Option::is_none")]
873    pub data: Option<Vec<u8>>,
874    #[serde(default, skip_serializing_if = "Vec::is_empty")]
875    pub commitments: Vec<Vec<u8>>,
876}
877
878impl Share {
879    pub fn new(key_name: impl Into<String>) -> Self {
880        Self {
881            key_name: key_name.into(),
882            data: None,
883            commitments: Vec::new(),
884        }
885    }
886
887    pub fn opaque(key_name: impl Into<String>, data: impl Into<Vec<u8>>) -> Self {
888        Self {
889            key_name: key_name.into(),
890            data: Some(data.into()),
891            commitments: Vec::new(),
892        }
893    }
894
895    pub fn feldman(
896        key_name: impl Into<String>,
897        data: impl Into<Vec<u8>>,
898        commitments: impl IntoIterator<Item = impl Into<Vec<u8>>>,
899    ) -> Self {
900        Self {
901            key_name: key_name.into(),
902            data: Some(data.into()),
903            commitments: commitments.into_iter().map(Into::into).collect(),
904        }
905    }
906
907    pub fn key_name(&self) -> &str {
908        &self.key_name
909    }
910
911    pub fn data(&self) -> Option<&[u8]> {
912        self.data.as_deref()
913    }
914
915    pub fn commitments(&self) -> &[Vec<u8>] {
916        &self.commitments
917    }
918
919    pub fn commitment(&self, index: usize) -> Option<&[u8]> {
920        self.commitments.get(index).map(Vec::as_slice)
921    }
922
923    pub fn commitment_count(&self) -> usize {
924        self.commitments.len()
925    }
926
927    pub fn has_commitments(&self) -> bool {
928        !self.commitments.is_empty()
929    }
930
931    pub fn is_feldman(&self) -> bool {
932        self.has_commitments()
933    }
934
935    pub fn is_opaque(&self) -> bool {
936        !self.has_commitments()
937    }
938
939    pub fn public_key(&self) -> Option<PublicKey> {
940        self.commitment(0)
941            .map(|bytes| PublicKey::new(self.key_name.clone(), bytes.to_vec()))
942    }
943}
944
945#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
946pub struct PublicKey {
947    pub key_name: String,
948    pub bytes: Vec<u8>,
949}
950
951impl PublicKey {
952    pub fn new(key_name: impl Into<String>, bytes: impl Into<Vec<u8>>) -> Self {
953        Self {
954            key_name: key_name.into(),
955            bytes: bytes.into(),
956        }
957    }
958
959    pub fn key_name(&self) -> &str {
960        &self.key_name
961    }
962
963    pub fn as_bytes(&self) -> &[u8] {
964        &self.bytes
965    }
966
967    pub fn into_bytes(self) -> Vec<u8> {
968        self.bytes
969    }
970}
971
972#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
973pub struct FieldElement(pub Vec<u8>);
974
975impl FieldElement {
976    pub fn from_bytes(bytes: impl Into<Vec<u8>>) -> Self {
977        Self(bytes.into())
978    }
979
980    pub fn as_bytes(&self) -> &[u8] {
981        &self.0
982    }
983
984    pub fn into_bytes(self) -> Vec<u8> {
985        self.0
986    }
987}
988
989impl From<Vec<u8>> for FieldElement {
990    fn from(bytes: Vec<u8>) -> Self {
991        Self::from_bytes(bytes)
992    }
993}
994
995impl From<&[u8]> for FieldElement {
996    fn from(bytes: &[u8]) -> Self {
997        Self::from_bytes(bytes)
998    }
999}
1000
1001#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
1002pub struct GroupElement(pub Vec<u8>);
1003
1004impl GroupElement {
1005    pub fn from_bytes(bytes: impl Into<Vec<u8>>) -> Self {
1006        Self(bytes.into())
1007    }
1008
1009    pub fn as_bytes(&self) -> &[u8] {
1010        &self.0
1011    }
1012
1013    pub fn into_bytes(self) -> Vec<u8> {
1014        self.0
1015    }
1016}
1017
1018impl From<Vec<u8>> for GroupElement {
1019    fn from(bytes: Vec<u8>) -> Self {
1020        Self::from_bytes(bytes)
1021    }
1022}
1023
1024impl From<&[u8]> for GroupElement {
1025    fn from(bytes: &[u8]) -> Self {
1026        Self::from_bytes(bytes)
1027    }
1028}