ergotree_ir/serialization/
data.rs

1use sigma_util::AsVecU8;
2
3use crate::chain::ergo_box::ErgoBox;
4use crate::mir::avl_tree_data::AvlTreeData;
5use crate::mir::constant::Literal;
6use crate::mir::constant::TryExtractFromError;
7use crate::mir::constant::TryExtractInto;
8use crate::mir::value::CollKind;
9use crate::mir::value::NativeColl;
10use crate::serialization::SigmaSerializationError;
11use crate::serialization::SigmaSerializeResult;
12use crate::serialization::{
13    sigma_byte_reader::SigmaByteRead, SigmaParsingError, SigmaSerializable,
14};
15use crate::sigma_protocol::{sigma_boolean::SigmaBoolean, sigma_boolean::SigmaProp};
16use crate::types::stuple;
17use crate::types::stype::SType;
18use ergo_chain_types::EcPoint;
19
20use super::sigma_byte_writer::SigmaByteWrite;
21use std::convert::TryInto;
22use std::sync::Arc;
23
24/// Used to serialize and parse `Literal` and `Value`.
25pub struct DataSerializer {}
26
27impl DataSerializer {
28    pub fn sigma_serialize<W: SigmaByteWrite>(c: &Literal, w: &mut W) -> SigmaSerializeResult {
29        // for reference see http://github.com/ScorexFoundation/sigmastate-interpreter/blob/25251c1313b0131835f92099f02cef8a5d932b5e/sigmastate/src/main/scala/sigmastate/serialization/DataSerializer.scala#L26-L26
30        Ok(match c {
31            Literal::Unit => (),
32            Literal::Boolean(v) => w.put_u8(u8::from(*v))?,
33            Literal::Byte(v) => w.put_i8(*v)?,
34            Literal::Short(v) => w.put_i16(*v)?,
35            Literal::Int(v) => w.put_i32(*v)?,
36            Literal::Long(v) => w.put_i64(*v)?,
37            Literal::BigInt(v) => {
38                let bytes = v.to_signed_bytes_be();
39                w.put_u16(bytes.len() as u16)?;
40                w.write_all(&bytes)?
41            }
42            Literal::GroupElement(ecp) => ecp.sigma_serialize(w)?,
43            Literal::SigmaProp(s) => s.value().sigma_serialize(w)?,
44            Literal::AvlTree(a) => a.sigma_serialize(w)?,
45            Literal::CBox(b) => b.sigma_serialize(w)?,
46            Literal::Coll(ct) => match ct {
47                CollKind::NativeColl(NativeColl::CollByte(b)) => {
48                    w.put_usize_as_u16_unwrapped(b.len())?;
49                    w.write_all(b.clone().as_vec_u8().as_slice())?
50                }
51                CollKind::WrappedColl {
52                    elem_tpe: SType::SBoolean,
53                    items: v,
54                } => {
55                    w.put_usize_as_u16_unwrapped(v.len())?;
56                    let maybe_bools: Result<Vec<bool>, TryExtractFromError> = v
57                        .clone()
58                        .iter()
59                        .cloned()
60                        .map(|i| i.try_extract_into::<bool>())
61                        .collect();
62                    w.put_bits(maybe_bools?.as_slice())?
63                }
64                CollKind::WrappedColl {
65                    elem_tpe: _,
66                    items: v,
67                } => {
68                    w.put_usize_as_u16_unwrapped(v.len())?;
69                    v.iter()
70                        .try_for_each(|e| DataSerializer::sigma_serialize(e, w))?
71                }
72            },
73            Literal::Tup(items) => items
74                .iter()
75                .try_for_each(|i| DataSerializer::sigma_serialize(i, w))?,
76            // unsupported, see
77            // https://github.com/ScorexFoundation/sigmastate-interpreter/issues/659
78            Literal::Opt(_) => {
79                return Err(SigmaSerializationError::NotSupported(
80                    "Option serialization is not supported".to_string(),
81                ));
82            }
83        })
84    }
85
86    pub fn sigma_parse<R: SigmaByteRead>(
87        tpe: &SType,
88        r: &mut R,
89    ) -> Result<Literal, SigmaParsingError> {
90        // for reference see http://github.com/ScorexFoundation/sigmastate-interpreter/blob/25251c1313b0131835f92099f02cef8a5d932b5e/sigmastate/src/main/scala/sigmastate/serialization/DataSerializer.scala#L84-L84
91        use SType::*;
92        Ok(match tpe {
93            SBoolean => Literal::Boolean(r.get_u8()? != 0),
94            SByte => Literal::Byte(r.get_i8()?),
95            SShort => Literal::Short(r.get_i16()?),
96            SInt => Literal::Int(r.get_i32()?),
97            SLong => Literal::Long(r.get_i64()?),
98            SBigInt => {
99                let size = r.get_u16()?;
100                if size > 32 {
101                    return Err(SigmaParsingError::ValueOutOfBounds(format!(
102                        "serialized BigInt size {0} bytes exceeds 32",
103                        size
104                    )));
105                }
106                let mut buf = vec![0u8; size as usize];
107                r.read_exact(&mut buf)?;
108                match buf.as_slice().try_into() {
109                    Ok(x) => Literal::BigInt(x),
110                    Err(e) => return Err(SigmaParsingError::ValueOutOfBounds(e)),
111                }
112            }
113            SUnit => Literal::Unit,
114            SGroupElement => Literal::GroupElement(Arc::new(EcPoint::sigma_parse(r)?)),
115            SSigmaProp => {
116                Literal::SigmaProp(Box::new(SigmaProp::new(SigmaBoolean::sigma_parse(r)?)))
117            }
118            SColl(elem_type) if **elem_type == SByte => {
119                let len = r.get_u16()? as usize;
120                let mut buf = vec![0u8; len];
121                r.read_exact(&mut buf)?;
122                Literal::Coll(CollKind::NativeColl(NativeColl::CollByte(
123                    buf.into_iter().map(|v| v as i8).collect(),
124                )))
125            }
126            SColl(elem_type) if **elem_type == SBoolean => {
127                let len = r.get_u16()? as usize;
128                let bools = r.get_bits(len)?;
129                Literal::Coll(CollKind::WrappedColl {
130                    elem_tpe: (**elem_type).clone(),
131                    items: bools.into_iter().map(|b| b.into()).collect(),
132                })
133            }
134            SColl(elem_type) => {
135                let len = r.get_u16()? as usize;
136                let elems = (0..len)
137                    .map(|_| DataSerializer::sigma_parse(elem_type, r))
138                    .collect::<Result<Arc<[_]>, SigmaParsingError>>()?;
139                Literal::Coll(CollKind::WrappedColl {
140                    elem_tpe: (**elem_type).clone(),
141                    items: elems,
142                })
143            }
144            STuple(stuple::STuple { items: types }) => {
145                let mut items = Vec::new();
146                types.iter().try_for_each(|tpe| {
147                    DataSerializer::sigma_parse(tpe, r).map(|v| items.push(v))
148                })?;
149                // we get the tuple item value for each tuple item type,
150                // since items types quantity has checked bounds, we can be sure that items count
151                // is correct
152                Literal::Tup(items.try_into()?)
153            }
154            SBox => Literal::CBox(Arc::new(ErgoBox::sigma_parse(r)?).into()),
155            SAvlTree => Literal::AvlTree(Box::new(AvlTreeData::sigma_parse(r)?)),
156            STypeVar(_) => return Err(SigmaParsingError::NotSupported("TypeVar data")),
157            SAny => return Err(SigmaParsingError::NotSupported("SAny data")),
158            SOption(_) => return Err(SigmaParsingError::NotSupported("SOption data")),
159            SFunc(_) => return Err(SigmaParsingError::NotSupported("SFunc data")),
160            SContext => return Err(SigmaParsingError::NotSupported("SContext data")),
161            SHeader => return Err(SigmaParsingError::NotSupported("SHeader data")),
162            SPreHeader => return Err(SigmaParsingError::NotSupported("SPreHeader data")),
163            SGlobal => return Err(SigmaParsingError::NotSupported("SGlobal data")),
164        })
165    }
166}