From 1b6633cdccde8c22b9a9b6c09230c99271738844 Mon Sep 17 00:00:00 2001 From: daxpedda Date: Tue, 15 Jul 2025 04:54:43 +0200 Subject: [PATCH] Move Serde De/Serialization to `Group` Implementation (#380) * Move Serde De/Serialization to `Group` implementation * Clean up Serde formats * Fix typo --- Cargo.toml | 1 + src/key_exchange/group/curve25519.rs | 99 ++++++--- src/key_exchange/group/ed25519.rs | 252 +++++++++++++++-------- src/key_exchange/group/elliptic_curve.rs | 43 ++-- src/key_exchange/group/ristretto255.rs | 111 +++++++--- src/key_exchange/shared.rs | 10 +- src/key_exchange/sigma_i/ecdsa.rs | 2 +- src/key_exchange/sigma_i/mod.rs | 18 +- src/key_exchange/tripledh.rs | 5 +- src/keypair.rs | 72 ++----- src/messages.rs | 10 +- src/opaque.rs | 12 +- 12 files changed, 415 insertions(+), 220 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index bcece58..1d98dc5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -24,6 +24,7 @@ serde = [ "curve25519-dalek?/serde", "ecdsa?/serde", "ed25519-dalek?/serde", + "elliptic-curve/serde", "generic-array/serde", "voprf/serde", "zeroize/serde", diff --git a/src/key_exchange/group/curve25519.rs b/src/key_exchange/group/curve25519.rs index bc0b949..e567c89 100644 --- a/src/key_exchange/group/curve25519.rs +++ b/src/key_exchange/group/curve25519.rs @@ -11,10 +11,11 @@ pub use curve25519_dalek; use curve25519_dalek::montgomery::MontgomeryPoint; use curve25519_dalek::scalar; -use curve25519_dalek::traits::Identity; +use curve25519_dalek::traits::IsIdentity; use generic_array::GenericArray; use generic_array::typenum::U32; use rand::{CryptoRng, RngCore}; +use subtle::ConstantTimeEq; use zeroize::Zeroize; use super::Group; @@ -27,22 +28,19 @@ pub struct Curve25519; /// The implementation of such a subgroup for Curve25519 impl Group for Curve25519 { - type Pk = MontgomeryPoint; + type Pk = NonIdentity; type PkLen = U32; type Sk = Scalar; type SkLen = U32; fn serialize_pk(pk: Self::Pk) -> GenericArray { - pk.to_bytes().into() + pk.0.to_bytes().into() } fn deserialize_take_pk(bytes: &mut &[u8]) -> Result { bytes .take_array::("public key") - .ok() - .map(|array| MontgomeryPoint(array.into())) - .filter(|pk| pk != &MontgomeryPoint::identity()) - .ok_or(ProtocolError::SerializationError) + .and_then(|bytes| NonIdentity::from_bytes(bytes.into())) } fn random_sk(rng: &mut R) -> Self::Sk { @@ -59,7 +57,7 @@ impl Group for Curve25519 { } fn public_key(sk: Self::Sk) -> Self::Pk { - MontgomeryPoint::mul_base_clamped(sk.0) + NonIdentity(MontgomeryPoint::mul_base_clamped(sk.0)) } fn serialize_sk(sk: Self::Sk) -> GenericArray { @@ -69,26 +67,81 @@ impl Group for Curve25519 { fn deserialize_take_sk(bytes: &mut &[u8]) -> Result { bytes .take_array::("secret key") - .ok() - .and_then(|bytes| { - let scalar = scalar::clamp_integer(bytes.into()); - (scalar == *bytes).then_some(scalar) - }) - .map(Scalar) - .ok_or(ProtocolError::SerializationError) + .and_then(|bytes| Scalar::from_bytes(bytes.into())) } } -/// Curve25519 scalar. -#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, Zeroize)] -pub struct Scalar([u8; 32]); - impl DiffieHellman for Scalar { - fn diffie_hellman(self, pk: MontgomeryPoint) -> GenericArray { - Curve25519::serialize_pk(pk.mul_clamped(self.0)) + fn diffie_hellman(self, pk: NonIdentity) -> GenericArray { + Curve25519::serialize_pk(NonIdentity(pk.0.mul_clamped(self.0))) } } +/// Non-identity point wrapper for [`MontgomeryPoint`]. +#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] +#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, Zeroize)] +pub struct NonIdentity( + #[cfg_attr(feature = "serde", serde(deserialize_with = "serde_deserialize_pk"))] + MontgomeryPoint, +); + +impl NonIdentity { + fn from_bytes(bytes: [u8; 32]) -> Result { + let point = MontgomeryPoint(bytes); + + if point.is_identity() { + Err(ProtocolError::SerializationError) + } else { + Ok(NonIdentity(point)) + } + } +} + +#[cfg(feature = "serde")] +fn serde_deserialize_pk<'de, D>(deserializer: D) -> Result +where + D: serde::Deserializer<'de>, +{ + use serde::de::{Deserialize, Error}; + + let point = MontgomeryPoint::deserialize(deserializer)?; + + NonIdentity::from_bytes(point.0) + .map(|point| point.0) + .map_err(Error::custom) +} + +/// Curve25519 scalar. +#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] +#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, Zeroize)] +pub struct Scalar( + #[cfg_attr(feature = "serde", serde(deserialize_with = "serde_deserialize_sk"))] [u8; 32], +); + +impl Scalar { + fn from_bytes(bytes: [u8; 32]) -> Result { + let scalar = scalar::clamp_integer(bytes); + + if scalar.ct_eq(&bytes).into() { + Ok(Self(scalar)) + } else { + Err(ProtocolError::SerializationError) + } + } +} + +#[cfg(feature = "serde")] +fn serde_deserialize_sk<'de, D>(deserializer: D) -> Result<[u8; 32], D::Error> +where + D: serde::Deserializer<'de>, +{ + use serde::de::{Deserialize, Error}; + + Scalar::from_bytes(<[u8; 32]>::deserialize(deserializer)?) + .map(|scalar| scalar.0) + .map_err(D::Error::custom) +} + ////////////////////////// // Test Implementations // //===================== // @@ -98,9 +151,9 @@ impl DiffieHellman for Scalar { use crate::serialization::AssertZeroized; #[cfg(test)] -impl AssertZeroized for MontgomeryPoint { +impl AssertZeroized for NonIdentity { fn assert_zeroized(&self) { - assert_eq!(*self, MontgomeryPoint::default()); + assert_eq!(self.0, MontgomeryPoint::default()); } } diff --git a/src/key_exchange/group/ed25519.rs b/src/key_exchange/group/ed25519.rs index ee7fadb..69051c0 100644 --- a/src/key_exchange/group/ed25519.rs +++ b/src/key_exchange/group/ed25519.rs @@ -46,15 +46,9 @@ impl Group for Ed25519 { } fn deserialize_take_pk(bytes: &mut &[u8]) -> Result { - let compressed = bytes - .take_array("public key") - .map(|bytes| CompressedEdwardsY(bytes.into()))?; + let bytes = bytes.take_array("public key")?; - if let Some(point) = compressed.decompress().filter(|point| !point.is_identity()) { - Ok(VerifyingKey { point, compressed }) - } else { - Err(ProtocolError::SerializationError) - } + VerifyingKey::from_bytes(bytes.into()) } fn random_sk(rng: &mut R) -> Self::Sk { @@ -83,56 +77,6 @@ impl Group for Ed25519 { } } -/// Ed25519 verifying key. -// `ed25519_dalek::VerifyingKey` doesn't implement `Zeroize`. -// TODO: remove after https://github.com/dalek-cryptography/curve25519-dalek/pull/747. -// Required for manual implementation of EdDSA. -// TODO: remove after https://github.com/dalek-cryptography/curve25519-dalek/pull/556. -#[derive(Clone, Copy, Debug, Eq, PartialEq, Zeroize)] -pub struct VerifyingKey { - point: EdwardsPoint, - compressed: CompressedEdwardsY, -} - -/// Ed25519 siging key. -// We store the `ExpandedSecret` in memory to avoid computing it on demand and then discarding it -// again. -#[derive(Clone, Copy, Debug, Eq, PartialEq, Zeroize)] -pub struct SigningKey { - // `ed25519_dalek::SigningKey` doesn't implement `Zeroize`. See - // https://github.com/dalek-cryptography/curve25519-dalek/pull/747 - // Required for manual implementation of EdDSA. - // TODO: remove after https://github.com/dalek-cryptography/curve25519-dalek/pull/556. - sk: SecretKey, - verifying_key: VerifyingKey, - // `ed25519_dalek::ExpandedSecret` doesn't implement traits we need. See - // TODO: remove after https://github.com/dalek-cryptography/curve25519-dalek/pull/748 and - // https://github.com/dalek-cryptography/curve25519-dalek/pull/747. - scalar: Scalar, - hash_prefix: [u8; 32], -} - -impl SigningKey { - fn from_bytes(sk: [u8; 32]) -> Self { - let ExpandedSecretKey { - scalar, - hash_prefix, - } = ExpandedSecretKey::from(&sk); - let point = EdwardsPoint::mul_base(&scalar); - let verifying_key = VerifyingKey { - point, - compressed: point.compress(), - }; - - SigningKey { - sk, - verifying_key, - scalar, - hash_prefix, - } - } -} - impl PureEddsaImpl for Ed25519 { type Signature = Signature; type SignatureLen = U64; @@ -278,8 +222,175 @@ fn verify<'a>( } } +/// Ed25519 verifying key. +// `ed25519_dalek::VerifyingKey` doesn't implement `Zeroize`. +// TODO: remove after https://github.com/dalek-cryptography/curve25519-dalek/pull/747. +// Required for manual implementation of EdDSA. +// TODO: remove after https://github.com/dalek-cryptography/curve25519-dalek/pull/556. +#[derive(Clone, Copy, Debug, Eq, PartialEq, Zeroize)] +pub struct VerifyingKey { + point: EdwardsPoint, + compressed: CompressedEdwardsY, +} + +impl VerifyingKey { + fn from_bytes(bytes: [u8; 32]) -> Result { + let compressed = CompressedEdwardsY(bytes); + + if let Some(point) = compressed.decompress().filter(|point| !point.is_identity()) { + Ok(Self { point, compressed }) + } else { + Err(ProtocolError::SerializationError) + } + } +} + +#[cfg(feature = "serde")] +impl<'de> serde::Deserialize<'de> for VerifyingKey { + fn deserialize(deserializer: D) -> Result + where + D: serde::Deserializer<'de>, + { + use core::fmt::{self, Formatter}; + + use serde::de::{Deserialize, Deserializer, Error, SeqAccess, Visitor}; + + struct VerifyingKeyVisitor; + + impl<'de> Visitor<'de> for VerifyingKeyVisitor { + type Value = VerifyingKey; + + fn expecting(&self, formatter: &mut Formatter) -> fmt::Result { + Formatter::write_str(formatter, "tuple struct VerifyingKey") + } + + fn visit_newtype_struct(self, deserializer: D) -> Result + where + D: Deserializer<'de>, + { + let compressed = CompressedEdwardsY::deserialize(deserializer)?; + VerifyingKey::from_bytes(compressed.0).map_err(Error::custom) + } + + fn visit_seq(self, mut seq: A) -> Result + where + A: SeqAccess<'de>, + { + let compressed: CompressedEdwardsY = seq.next_element()?.ok_or_else(|| { + Error::invalid_length(0, &"tuple struct VerifyingKey with 1 element") + })?; + VerifyingKey::from_bytes(compressed.0).map_err(Error::custom) + } + } + + deserializer.deserialize_newtype_struct("VerifyingKey", VerifyingKeyVisitor) + } +} + +#[cfg(feature = "serde")] +impl serde::Serialize for VerifyingKey { + fn serialize(&self, serializer: S) -> Result + where + S: serde::Serializer, + { + serializer.serialize_newtype_struct("VerifyingKey", &self.compressed) + } +} + +/// Ed25519 signing key. +// We store the `ExpandedSecret` in memory to avoid computing it on demand and then discarding it +// again. +#[derive(Clone, Copy, Debug, Eq, PartialEq, Zeroize)] +pub struct SigningKey { + // `ed25519_dalek::SigningKey` doesn't implement `Zeroize`. See + // https://github.com/dalek-cryptography/curve25519-dalek/pull/747 + // Required for manual implementation of EdDSA. + // TODO: remove after https://github.com/dalek-cryptography/curve25519-dalek/pull/556. + sk: SecretKey, + verifying_key: VerifyingKey, + // `ed25519_dalek::ExpandedSecret` doesn't implement traits we need. See + // TODO: remove after https://github.com/dalek-cryptography/curve25519-dalek/pull/748 and + // https://github.com/dalek-cryptography/curve25519-dalek/pull/747. + scalar: Scalar, + hash_prefix: [u8; 32], +} + +impl SigningKey { + fn from_bytes(sk: [u8; 32]) -> Self { + let ExpandedSecretKey { + scalar, + hash_prefix, + } = ExpandedSecretKey::from(&sk); + let point = EdwardsPoint::mul_base(&scalar); + let verifying_key = VerifyingKey { + point, + compressed: point.compress(), + }; + + SigningKey { + sk, + verifying_key, + scalar, + hash_prefix, + } + } +} + +#[cfg(feature = "serde")] +impl<'de> serde::Deserialize<'de> for SigningKey { + fn deserialize(deserializer: D) -> Result + where + D: serde::Deserializer<'de>, + { + use core::fmt::{self, Formatter}; + + use serde::de::{Deserialize, Deserializer, Error, SeqAccess, Visitor}; + + struct SigningKeyVisitor; + + impl<'de> Visitor<'de> for SigningKeyVisitor { + type Value = SigningKey; + + fn expecting(&self, formatter: &mut Formatter) -> fmt::Result { + Formatter::write_str(formatter, "tuple struct SigningKey") + } + + fn visit_newtype_struct(self, deserializer: D) -> Result + where + D: Deserializer<'de>, + { + let sk = Scalar::deserialize(deserializer)?; + Ok(SigningKey::from_bytes(sk.to_bytes())) + } + + fn visit_seq(self, mut seq: A) -> Result + where + A: SeqAccess<'de>, + { + let sk: Scalar = seq.next_element()?.ok_or_else(|| { + Error::invalid_length(0, &"tuple struct SigningKey with 1 element") + })?; + Ok(SigningKey::from_bytes(sk.to_bytes())) + } + } + + deserializer.deserialize_newtype_struct("SigningKey", SigningKeyVisitor) + } +} + +#[cfg(feature = "serde")] +impl serde::Serialize for SigningKey { + fn serialize(&self, serializer: S) -> Result + where + S: serde::Serializer, + { + serializer.serialize_newtype_struct("SigningKey", &self.sk) + } +} + /// Ed25519 Signature. // `ed25519_dalek::Signature` doesn't implement validation with Serde de/serialization. +#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] #[derive(Clone, Copy, Debug, Eq, PartialEq)] #[allow(non_snake_case)] pub struct Signature { @@ -310,31 +421,6 @@ impl Signature { } } -#[cfg(feature = "serde")] -impl<'de> serde::Deserialize<'de> for Signature { - fn deserialize(deserializer: D) -> Result - where - D: serde::Deserializer<'de>, - { - use serde::de::Error; - - Signature::deserialize_take( - &mut (GenericArray::<_, U64>::deserialize(deserializer)?.as_slice()), - ) - .map_err(D::Error::custom) - } -} - -#[cfg(feature = "serde")] -impl serde::Serialize for Signature { - fn serialize(&self, serializer: SK) -> Result - where - SK: serde::Serializer, - { - self.serialize().serialize(serializer) - } -} - impl Zeroize for Signature { fn zeroize(&mut self) { self.R.0 = [0; 32]; diff --git a/src/key_exchange/group/elliptic_curve.rs b/src/key_exchange/group/elliptic_curve.rs index ff9338a..7158b7d 100644 --- a/src/key_exchange/group/elliptic_curve.rs +++ b/src/key_exchange/group/elliptic_curve.rs @@ -86,16 +86,35 @@ where } } +impl DiffieHellman for NonZeroScalar +where + G: CurveArithmetic + voprf::CipherSuite + voprf::Group>, + FieldBytesSize: ModulusSize, + ProjectivePoint: GroupEncoding< + Repr = GenericArray as ModulusSize>::CompressedPointSize>, + > + ToEncodedPoint, +{ + fn diffie_hellman( + self, + pk: NonIdentity, + ) -> GenericArray as ModulusSize>::CompressedPointSize> { + GenericArray::clone_from_slice((pk.0 * self).to_encoded_point(true).as_bytes()) + } +} + /// Wrapper around [`NonIdentity`](point::NonIdentity) to implement [`Zeroize`]. // TODO: remove after https://github.com/RustCrypto/traits/pull/1832. #[derive_where(Clone, Copy)] #[cfg_attr( feature = "serde", derive(serde::Deserialize, serde::Serialize), - serde(bound( - deserialize = "point::NonIdentity>: serde::Deserialize<'de>", - serialize = "point::NonIdentity>: serde::Serialize" - )) + serde( + bound( + deserialize = "point::NonIdentity>: serde::Deserialize<'de>", + serialize = "point::NonIdentity>: serde::Serialize" + ), + transparent + ) )] pub struct NonIdentity(pub point::NonIdentity>); @@ -121,22 +140,6 @@ impl Zeroize for NonIdentity { } } -impl DiffieHellman for NonZeroScalar -where - G: CurveArithmetic + voprf::CipherSuite + voprf::Group>, - FieldBytesSize: ModulusSize, - ProjectivePoint: GroupEncoding< - Repr = GenericArray as ModulusSize>::CompressedPointSize>, - > + ToEncodedPoint, -{ - fn diffie_hellman( - self, - pk: NonIdentity, - ) -> GenericArray as ModulusSize>::CompressedPointSize> { - GenericArray::clone_from_slice((pk.0 * self).to_encoded_point(true).as_bytes()) - } -} - ////////////////////////// // Test Implementations // //===================== // diff --git a/src/key_exchange/group/ristretto255.rs b/src/key_exchange/group/ristretto255.rs index c982189..c04c7b3 100644 --- a/src/key_exchange/group/ristretto255.rs +++ b/src/key_exchange/group/ristretto255.rs @@ -12,13 +12,14 @@ pub use curve25519_dalek; use curve25519_dalek::constants::RISTRETTO_BASEPOINT_POINT; use curve25519_dalek::ristretto::{CompressedRistretto, RistrettoPoint}; use curve25519_dalek::scalar::Scalar; -use curve25519_dalek::traits::Identity; +use curve25519_dalek::traits::IsIdentity; use digest::core_api::BlockSizeUser; use digest::{FixedOutput, HashMarker}; use generic_array::GenericArray; use generic_array::typenum::{IsLess, IsLessOrEqual, U32, U256}; use rand::{CryptoRng, RngCore}; use voprf::Mode; +use zeroize::Zeroize; use super::{Group, STR_OPAQUE_DERIVE_AUTH_KEY_PAIR}; use crate::errors::{InternalError, ProtocolError}; @@ -31,21 +32,20 @@ use crate::serialization::SliceExt; pub struct Ristretto255; impl Group for Ristretto255 { - type Pk = RistrettoPoint; + type Pk = NonIdentity; type PkLen = U32; - type Sk = Scalar; + type Sk = NonZeroScalar; type SkLen = U32; fn serialize_pk(pk: Self::Pk) -> GenericArray { - pk.compress().to_bytes().into() + pk.0.compress().to_bytes().into() } fn deserialize_take_pk(bytes: &mut &[u8]) -> Result { - CompressedRistretto::from_slice(&bytes.take_array::("public key")?) - .map_err(|_| ProtocolError::SerializationError)? + CompressedRistretto(bytes.take_array("public key")?.into()) .decompress() - .filter(|point| point != &RistrettoPoint::identity()) .ok_or(ProtocolError::SerializationError) + .and_then(NonIdentity::from_point) } fn random_sk(rng: &mut R) -> Self::Sk { @@ -53,34 +53,101 @@ impl Group for Ristretto255 { let scalar = Scalar::random(rng); if scalar != Scalar::ZERO { - break scalar; + break NonZeroScalar(scalar); } } } fn derive_scalar(seed: GenericArray) -> Result { voprf::derive_key::(&seed, &STR_OPAQUE_DERIVE_AUTH_KEY_PAIR, Mode::Oprf) + .map(NonZeroScalar) .map_err(InternalError::from) } fn public_key(sk: Self::Sk) -> Self::Pk { - RISTRETTO_BASEPOINT_POINT * sk + NonIdentity(RISTRETTO_BASEPOINT_POINT * sk.0) } fn serialize_sk(sk: Self::Sk) -> GenericArray { - sk.to_bytes().into() + sk.0.to_bytes().into() } fn deserialize_take_sk(bytes: &mut &[u8]) -> Result { - bytes - .take_array::("secret key") - .ok() - .and_then(|bytes| Scalar::from_canonical_bytes(bytes.into()).into()) - .filter(|scalar| scalar != &Scalar::ZERO) + Scalar::from_canonical_bytes(bytes.take_array("secret key")?.into()) + .into_option() .ok_or(ProtocolError::SerializationError) + .and_then(NonZeroScalar::from_scalar) } } +impl DiffieHellman for NonZeroScalar { + fn diffie_hellman(self, pk: NonIdentity) -> GenericArray { + Ristretto255::serialize_pk(NonIdentity(pk.0 * self.0)) + } +} + +/// Non-identity point wrapper for [`RistrettoPoint`]. +#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] +#[derive(Clone, Copy, Debug, Eq, PartialEq, Zeroize)] +pub struct NonIdentity( + #[cfg_attr(feature = "serde", serde(deserialize_with = "serde_deserialize_pk"))] RistrettoPoint, +); + +impl NonIdentity { + fn from_point(point: RistrettoPoint) -> Result { + if point.is_identity() { + Err(ProtocolError::SerializationError) + } else { + Ok(NonIdentity(point)) + } + } +} + +#[cfg(feature = "serde")] +fn serde_deserialize_pk<'de, D>(deserializer: D) -> Result +where + D: serde::Deserializer<'de>, +{ + use serde::de::{Deserialize, Error}; + + let point = RistrettoPoint::deserialize(deserializer)?; + + NonIdentity::from_point(point) + .map(|point| point.0) + .map_err(Error::custom) +} + +/// Non-zero scalar wrapper for [`Scalar`] +#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] +#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, Zeroize)] +pub struct NonZeroScalar( + #[cfg_attr(feature = "serde", serde(deserialize_with = "serde_deserialize_sk"))] Scalar, +); + +impl NonZeroScalar { + fn from_scalar(scalar: Scalar) -> Result { + if scalar == Scalar::ZERO { + Err(ProtocolError::SerializationError) + } else { + Ok(Self(scalar)) + } + } +} + +#[cfg(feature = "serde")] +fn serde_deserialize_sk<'de, D>(deserializer: D) -> Result +where + D: serde::Deserializer<'de>, +{ + use serde::de::{Deserialize, Error}; + + let scalar = Scalar::deserialize(deserializer)?; + + NonZeroScalar::from_scalar(scalar) + .map(|scalar| scalar.0) + .map_err(Error::custom) +} + impl voprf::CipherSuite for Ristretto255 { const ID: &'static str = voprf::Ristretto255::ID; @@ -157,12 +224,6 @@ impl voprf::Group for Ristretto255 { } } -impl DiffieHellman for Scalar { - fn diffie_hellman(self, pk: RistrettoPoint) -> GenericArray { - Ristretto255::serialize_pk(pk * self) - } -} - ////////////////////////// // Test Implementations // //===================== // @@ -172,15 +233,15 @@ impl DiffieHellman for Scalar { use crate::serialization::AssertZeroized; #[cfg(test)] -impl AssertZeroized for RistrettoPoint { +impl AssertZeroized for NonIdentity { fn assert_zeroized(&self) { - assert_eq!(*self, RistrettoPoint::default()); + assert_eq!(self.0, RistrettoPoint::default()); } } #[cfg(test)] -impl AssertZeroized for Scalar { +impl AssertZeroized for NonZeroScalar { fn assert_zeroized(&self) { - assert_eq!(*self, Scalar::default()); + assert_eq!(self.0, Scalar::default()); } } diff --git a/src/key_exchange/shared.rs b/src/key_exchange/shared.rs index 7c1032f..b9eea4d 100644 --- a/src/key_exchange/shared.rs +++ b/src/key_exchange/shared.rs @@ -57,7 +57,10 @@ pub trait DiffieHellman { #[cfg_attr( feature = "serde", derive(serde::Deserialize, serde::Serialize), - serde(bound = "") + serde(bound( + deserialize = "G::Sk: serde::Deserialize<'de>", + serialize = "G::Sk: serde::Serialize" + )) )] #[derive_where(Clone, ZeroizeOnDrop)] #[derive_where(Debug, Eq, Hash, Ord, PartialEq, PartialOrd; G::Sk)] @@ -70,7 +73,10 @@ pub struct Ke1State { #[cfg_attr( feature = "serde", derive(serde::Deserialize, serde::Serialize), - serde(bound = "") + serde(bound( + deserialize = "G::Pk: serde::Deserialize<'de>", + serialize = "G::Pk: serde::Serialize" + )) )] #[derive_where(Clone, ZeroizeOnDrop)] #[derive_where(Debug, Eq, Hash, Ord, PartialEq, PartialOrd; G::Pk)] diff --git a/src/key_exchange/sigma_i/ecdsa.rs b/src/key_exchange/sigma_i/ecdsa.rs index ae31b22..d3a9b7b 100644 --- a/src/key_exchange/sigma_i/ecdsa.rs +++ b/src/key_exchange/sigma_i/ecdsa.rs @@ -136,7 +136,7 @@ where #[cfg_attr( feature = "serde", derive(serde::Deserialize, serde::Serialize), - serde(bound = "") + serde(bound = "", transparent) )] pub struct Signature(pub ecdsa::Signature) where diff --git a/src/key_exchange/sigma_i/mod.rs b/src/key_exchange/sigma_i/mod.rs index 0a39cdd..19f6160 100644 --- a/src/key_exchange/sigma_i/mod.rs +++ b/src/key_exchange/sigma_i/mod.rs @@ -144,10 +144,14 @@ pub trait SignatureProtocol { #[cfg_attr( feature = "serde", derive(serde::Deserialize, serde::Serialize), - serde(bound(deserialize = "'de: 'a", serialize = "")) + serde(bound( + deserialize = "'de: 'a, as Group>::Pk: serde::Deserialize<'de>, KE::Pk: \ + serde::Deserialize<'de>", + serialize = " as Group>::Pk: serde::Serialize, KE::Pk: serde::Serialize" + )) )] #[derive_where(Clone, ZeroizeOnDrop)] -#[derive_where(Debug, Eq, Hash, PartialEq; PublicKey>, PublicKey)] +#[derive_where(Debug, Eq, Hash, PartialEq; as Group>::Pk, KE::Pk)] pub struct Ke2Builder<'a, CS: CipherSuite, KE: Group> { transcript: Message<'a, CS, KE>, server_nonce: GenericArray, @@ -166,8 +170,10 @@ pub struct Ke2Builder<'a, CS: CipherSuite, KE: Group> { feature = "serde", derive(serde::Deserialize, serde::Serialize), serde(bound( - deserialize = "SIG::VerifyState: serde::Deserialize<'de>", - serialize = "SIG::VerifyState: serde::Serialize" + deserialize = "::Pk: serde::Deserialize<'de>, SIG::VerifyState: serde::Deserialize<'de>", + serialize = "::Pk: serde::Serialize, SIG::VerifyState: \ + serde::Serialize" )) )] #[derive_where(Clone, ZeroizeOnDrop)] @@ -184,8 +190,8 @@ pub struct Ke2State { feature = "serde", derive(serde::Deserialize, serde::Serialize), serde(bound( - deserialize = "SIG::Signature: serde::Deserialize<'de>", - serialize = "SIG::Signature: serde::Serialize" + deserialize = "KE::Pk: serde::Deserialize<'de>, SIG::Signature: serde::Deserialize<'de>", + serialize = "KE::Pk: serde::Serialize, SIG::Signature: serde::Serialize" )) )] #[derive_where(Clone, ZeroizeOnDrop)] diff --git a/src/key_exchange/tripledh.rs b/src/key_exchange/tripledh.rs index 673ef07..96bc6fc 100644 --- a/src/key_exchange/tripledh.rs +++ b/src/key_exchange/tripledh.rs @@ -95,7 +95,10 @@ where #[cfg_attr( feature = "serde", derive(serde::Deserialize, serde::Serialize), - serde(bound = "") + serde(bound( + deserialize = "G::Pk: serde::Deserialize<'de>", + serialize = "G::Pk: serde::Serialize" + )) )] #[derive_where(Clone, ZeroizeOnDrop)] #[derive_where(Debug, Eq, Hash, Ord, PartialEq, PartialOrd; G::Pk)] diff --git a/src/keypair.rs b/src/keypair.rs index d2a7fc1..7cb21cb 100644 --- a/src/keypair.rs +++ b/src/keypair.rs @@ -27,8 +27,8 @@ use crate::serialization::SliceExt; feature = "serde", derive(serde::Deserialize, serde::Serialize), serde(bound( - deserialize = "SK: serde::Deserialize<'de>", - serialize = "SK: serde::Serialize" + deserialize = "G::Pk: serde::Deserialize<'de>, SK: serde::Deserialize<'de>", + serialize = "G::Pk: serde::Serialize, SK: serde::Serialize" )) )] #[derive_where(Clone)] @@ -83,6 +83,14 @@ impl KeyPair { } /// Wrapper around a Key to enforce that it's a private one. +#[cfg_attr( + feature = "serde", + derive(serde::Deserialize, serde::Serialize), + serde(bound( + deserialize = "G::Sk: serde::Deserialize<'de>", + serialize = "G::Sk: serde::Serialize" + )) +)] #[derive_where(Clone, ZeroizeOnDrop)] #[derive_where(Debug, Eq, Hash, Ord, PartialEq, PartialOrd; G::Sk)] pub struct PrivateKey(G::Sk); @@ -173,33 +181,15 @@ impl PrivateKeySerialization for PrivateKey { } } -#[cfg(feature = "serde")] -impl<'de, G: Group> serde::Deserialize<'de> for PrivateKey { - fn deserialize(deserializer: D) -> Result - where - D: serde::Deserializer<'de>, - { - use serde::de::Error; - - G::deserialize_take_sk( - &mut (GenericArray::<_, G::SkLen>::deserialize(deserializer)?.as_slice()), - ) - .map(Self) - .map_err(D::Error::custom) - } -} - -#[cfg(feature = "serde")] -impl serde::Serialize for PrivateKey { - fn serialize(&self, serializer: SK) -> Result - where - SK: serde::Serializer, - { - G::serialize_sk(self.0).serialize(serializer) - } -} - /// Wrapper around a Key to enforce that it's a public one. +#[cfg_attr( + feature = "serde", + derive(serde::Deserialize, serde::Serialize), + serde(bound( + deserialize = "G::Pk: serde::Deserialize<'de>", + serialize = "G::Pk: serde::Serialize" + )) +)] #[derive_where(Clone, ZeroizeOnDrop)] #[derive_where(Debug, Eq, Hash, Ord, PartialEq, PartialOrd; G::Pk)] pub struct PublicKey(G::Pk); @@ -237,32 +227,6 @@ impl PublicKey { } } -#[cfg(feature = "serde")] -impl<'de, G: Group> serde::Deserialize<'de> for PublicKey { - fn deserialize(deserializer: D) -> Result - where - D: serde::Deserializer<'de>, - { - use serde::de::Error; - - G::deserialize_take_pk( - &mut (GenericArray::<_, G::PkLen>::deserialize(deserializer)?.as_slice()), - ) - .map(Self) - .map_err(D::Error::custom) - } -} - -#[cfg(feature = "serde")] -impl serde::Serialize for PublicKey { - fn serialize(&self, serializer: SK) -> Result - where - SK: serde::Serializer, - { - G::serialize_pk(self.0).serialize(serializer) - } -} - /// Default OPRF seed container. #[cfg_attr( feature = "serde", diff --git a/src/messages.rs b/src/messages.rs index 74b6c71..b9e18a3 100644 --- a/src/messages.rs +++ b/src/messages.rs @@ -58,7 +58,10 @@ pub struct RegistrationRequest { #[cfg_attr( feature = "serde", derive(serde::Deserialize, serde::Serialize), - serde(bound = "") + serde(bound( + deserialize = " as Group>::Pk: serde::Deserialize<'de>", + serialize = " as Group>::Pk: serde::Serialize" + )) )] #[derive_where(Clone)] #[derive_where(Debug, Eq, Hash, Ord, PartialEq, PartialOrd; voprf::EvaluationElement, as Group>::Pk)] @@ -74,7 +77,10 @@ pub struct RegistrationResponse { #[cfg_attr( feature = "serde", derive(serde::Deserialize, serde::Serialize), - serde(bound = "") + serde(bound( + deserialize = " as Group>::Pk: serde::Deserialize<'de>", + serialize = " as Group>::Pk: serde::Serialize" + )) )] #[derive_where(Clone, ZeroizeOnDrop)] #[derive_where(Debug, Eq, Hash, Ord, PartialEq, PartialOrd; as Group>::Pk)] diff --git a/src/opaque.rs b/src/opaque.rs index c164a18..da0f14b 100644 --- a/src/opaque.rs +++ b/src/opaque.rs @@ -62,8 +62,11 @@ const STR_OPAQUE_DERIVE_KEY_PAIR: &[u8; 20] = b"OPAQUE-DeriveKeyPair"; feature = "serde", derive(serde::Deserialize, serde::Serialize), serde(bound( - deserialize = "SK: serde::Deserialize<'de>, OS: serde::Deserialize<'de>", - serialize = "SK: serde::Serialize, OS: serde::Serialize" + deserialize = " as Group>::Pk: serde::Deserialize<'de>, as \ + Group>::Sk: serde::Deserialize<'de>, SK: serde::Deserialize<'de>, OS: \ + serde::Deserialize<'de>", + serialize = " as Group>::Pk: serde::Serialize, as Group>::Sk: \ + serde::Serialize, SK: serde::Serialize, OS: serde::Serialize" )) )] #[derive_where(Clone)] @@ -99,7 +102,10 @@ pub struct ClientRegistration { #[cfg_attr( feature = "serde", derive(serde::Deserialize, serde::Serialize), - serde(bound = "") + serde(bound( + deserialize = " as Group>::Pk: serde::Deserialize<'de>", + serialize = " as Group>::Pk: serde::Serialize" + )) )] #[derive_where(Clone, ZeroizeOnDrop)] #[derive_where(Debug, Eq, Hash, Ord, PartialEq, PartialOrd; as Group>::Pk)]