arcium-primitives 0.8.2

Arcium primitives
Documentation
//! Pre-#748 ("Rework serialization") serde encodings for [`InPlaceCodec`]-backed leaf types and
//! the authenticated share/key/DaBit types built on them.

use std::sync::Arc;

use serde::{de::Error as DeError, Deserialize, Deserializer, Serialize, Serializer};

use crate::{
    algebra::{
        elliptic_curve::{Curve, Point},
        field::{FieldElement, FieldExtension, SubfieldElement},
    },
    correlated_randomness::dabits::DaBit,
    sharing::authenticated::{PairwiseAuthKey, PairwiseAuthShare},
    utils::codec::InPlaceCodec,
};

/// A type whose pre-#748 wire encoding can be recovered (and reproduced).
pub trait LegacyBytes: Sized {
    fn legacy_serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error>;
    fn legacy_deserialize<'de, D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error>;
}

/// `#[serde(with = "…utils::codec::legacy")]` entry point.
pub fn serialize<T: LegacyBytes, S: Serializer>(
    value: &T,
    serializer: S,
) -> Result<S::Ok, S::Error> {
    value.legacy_serialize(serializer)
}

/// `#[serde(with = "…utils::codec::legacy")]` entry point (also usable standalone as
/// `#[serde(deserialize_with = "…utils::codec::legacy::deserialize")]` on read-only mirror types).
pub fn deserialize<'de, T: LegacyBytes, D: Deserializer<'de>>(
    deserializer: D,
) -> Result<T, D::Error> {
    T::legacy_deserialize(deserializer)
}

/// Adapter giving a [`LegacyBytes`] value plain `Serialize`/`Deserialize` impls, so derived
/// container encodings (e.g. `Vec`'s, tuples') can be reused as-is instead of hand-rolling
/// `SeqAccess` visitors.
struct Legacy<T>(T);

impl<T: LegacyBytes> Serialize for Legacy<&T> {
    fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
        self.0.legacy_serialize(serializer)
    }
}

impl<'de, T: LegacyBytes> Deserialize<'de> for Legacy<T> {
    fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
        T::legacy_deserialize(deserializer).map(Legacy)
    }
}

/// Field elements were `serde_bytes`-encoded canonical little-endian bytes.
impl<F: FieldExtension> LegacyBytes for SubfieldElement<F> {
    fn legacy_serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
        serde_bytes::serialize(AsRef::<[u8]>::as_ref(&self.to_le_bytes()), serializer)
    }

    fn legacy_deserialize<'de, D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
        let bytes: &[u8] = serde_bytes::deserialize(deserializer)?;
        Self::from_le_bytes(bytes).map_err(DeError::custom)
    }
}

/// Same encoding as [`SubfieldElement`] -- see its doc comment for why `to_le_bytes`, not
/// `InPlaceCodec`.
impl<F: FieldExtension> LegacyBytes for FieldElement<F> {
    fn legacy_serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
        serde_bytes::serialize(AsRef::<[u8]>::as_ref(&self.to_le_bytes()), serializer)
    }

    fn legacy_deserialize<'de, D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
        let bytes: &[u8] = serde_bytes::deserialize(deserializer)?;
        Self::from_le_bytes(bytes).map_err(DeError::custom)
    }
}

/// Points were `serde_bytes`-encoded `GroupEncoding::to_bytes()` output. `InPlaceCodec` is the only
/// public route to those bytes, and it reverses them for big-endian curves, so undo that to
/// recover the original ordering.
impl<C: Curve> LegacyBytes for Point<C> {
    fn legacy_serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
        let mut bytes = self.to_inplace_bytes();
        if C::POINT_BIG_ENDIAN {
            bytes.reverse();
        }
        serde_bytes::serialize(bytes.as_slice(), serializer)
    }

    fn legacy_deserialize<'de, D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
        let bytes: &[u8] = serde_bytes::deserialize(deserializer)?;
        let mut bytes = bytes.to_vec();
        if C::POINT_BIG_ENDIAN {
            bytes.reverse();
        }
        Self::read_le_bytes(&bytes).map_err(DeError::custom)
    }
}

/// Batches were plain `Vec`s: a length, then each element in its own legacy encoding.
impl<T: LegacyBytes> LegacyBytes for Vec<T> {
    fn legacy_serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
        serializer.collect_seq(self.iter().map(Legacy))
    }

    fn legacy_deserialize<'de, D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
        Ok(Vec::<Legacy<T>>::deserialize(deserializer)?
            .into_iter()
            .map(|w| w.0)
            .collect())
    }
}

/// Same wire shape as `Vec<T>` (a length then each element) — used for `Wire`'s `Arc<[T]>` fields.
impl<T: LegacyBytes> LegacyBytes for Arc<[T]> {
    fn legacy_serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
        serializer.collect_seq(self.iter().map(Legacy))
    }

    fn legacy_deserialize<'de, D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
        Ok(Vec::<T>::legacy_deserialize(deserializer)?.into())
    }
}

/// `alpha` (through `Arc`) then `beta`, each in its own legacy encoding.
impl<A: LegacyBytes, B: LegacyBytes> LegacyBytes for PairwiseAuthKey<A, B> {
    fn legacy_serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
        use serde::ser::SerializeTuple;
        let mut tup = serializer.serialize_tuple(2)?;
        tup.serialize_element(&Legacy(&*self.alpha))?;
        tup.serialize_element(&Legacy(&self.beta))?;
        tup.end()
    }

    fn legacy_deserialize<'de, D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
        let (alpha, beta) = <(Legacy<A>, Legacy<B>)>::deserialize(deserializer)?;
        Ok(PairwiseAuthKey::new(Arc::new(alpha.0), beta.0))
    }
}

/// `value`, then `macs` and `keys` as independently-length-prefixed sequences (unlike the current
/// packed single-blob format — see the module docs).
impl<V: LegacyBytes, A: LegacyBytes, B: LegacyBytes> LegacyBytes for PairwiseAuthShare<V, A, B> {
    fn legacy_serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
        use serde::ser::SerializeTuple;
        let mut tup = serializer.serialize_tuple(3)?;
        tup.serialize_element(&Legacy(&self.value))?;
        tup.serialize_element(&self.macs.iter().map(Legacy).collect::<Vec<_>>())?;
        tup.serialize_element(&self.keys.iter().map(Legacy).collect::<Vec<_>>())?;
        tup.end()
    }

    fn legacy_deserialize<'de, D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
        let (value, macs, keys) = <(
            Legacy<V>,
            Vec<Legacy<B>>,
            Vec<Legacy<PairwiseAuthKey<A, B>>>,
        )>::deserialize(deserializer)?;
        // Not `try_new`: a trusted-dealer share legitimately has zero macs/keys and must still
        // deserialize successfully, matching the current-format `Deserialize` impl's behavior.
        Ok(PairwiseAuthShare {
            value: value.0,
            macs: macs.into_iter().map(|m| m.0).collect(),
            keys: keys.into_iter().map(|k| k.0).collect(),
        })
    }
}

/// `bit` then `field`, each in its own legacy encoding.
impl<F: FieldExtension> LegacyBytes for DaBit<F>
where
    crate::sharing::BitShare: LegacyBytes,
    crate::sharing::FieldShare<F>: LegacyBytes,
{
    fn legacy_serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
        use serde::ser::SerializeTuple;
        let mut tup = serializer.serialize_tuple(2)?;
        tup.serialize_element(&Legacy(&self.bit))?;
        tup.serialize_element(&Legacy(&self.field))?;
        tup.end()
    }

    fn legacy_deserialize<'de, D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
        let (bit, field) = <(
            Legacy<crate::sharing::BitShare>,
            Legacy<crate::sharing::FieldShare<F>>,
        )>::deserialize(deserializer)?;
        Ok(DaBit::new(bit.0, field.0))
    }
}