use core::{
fmt::{self, Debug},
hash::{Hash, Hasher},
};
use alloc::vec::Vec;
use crate::{
serialization::SerializableScalar, Ciphersuite, Error, Field, FieldError, Group, Scalar,
};
#[derive(Copy, Clone, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "serde", serde(bound = "C: Ciphersuite"))]
#[cfg_attr(feature = "serde", serde(try_from = "SerializableScalar<C>"))]
#[cfg_attr(feature = "serde", serde(into = "SerializableScalar<C>"))]
pub struct Identifier<C: Ciphersuite>(SerializableScalar<C>);
impl<C> Identifier<C>
where
C: Ciphersuite,
{
#[cfg_attr(feature = "internals", visibility::make(pub))]
#[cfg_attr(docsrs, doc(cfg(feature = "internals")))]
pub(crate) fn new(scalar: Scalar<C>) -> Result<Self, Error<C>> {
if scalar == <<C::Group as Group>::Field>::zero() {
Err(FieldError::InvalidZeroScalar.into())
} else {
Ok(Self(SerializableScalar(scalar)))
}
}
#[cfg_attr(feature = "internals", visibility::make(pub))]
#[cfg_attr(docsrs, doc(cfg(feature = "internals")))]
pub(crate) fn to_scalar(&self) -> Scalar<C> {
self.0 .0
}
pub fn derive(s: &[u8]) -> Result<Self, Error<C>> {
let scalar = C::HID(s).ok_or(Error::IdentifierDerivationNotSupported)?;
Self::new(scalar)
}
pub fn serialize(&self) -> Vec<u8> {
self.0.serialize()
}
pub fn deserialize(bytes: &[u8]) -> Result<Self, Error<C>> {
Ok(Self(SerializableScalar::deserialize(bytes)?))
}
}
#[cfg(feature = "serde")]
impl<C> TryFrom<SerializableScalar<C>> for Identifier<C>
where
C: Ciphersuite,
{
type Error = Error<C>;
fn try_from(s: SerializableScalar<C>) -> Result<Self, Self::Error> {
Self::new(s.0)
}
}
#[cfg(feature = "serde")]
impl<C> From<Identifier<C>> for SerializableScalar<C>
where
C: Ciphersuite,
{
fn from(i: Identifier<C>) -> Self {
i.0
}
}
impl<C> Eq for Identifier<C> where C: Ciphersuite {}
impl<C> Debug for Identifier<C>
where
C: Ciphersuite,
{
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_tuple("Identifier")
.field(&hex::encode(self.serialize()))
.finish()
}
}
#[allow(clippy::derived_hash_with_manual_eq)]
impl<C> Hash for Identifier<C>
where
C: Ciphersuite,
{
fn hash<H: Hasher>(&self, state: &mut H) {
self.serialize().hash(state)
}
}
impl<C> Ord for Identifier<C>
where
C: Ciphersuite,
{
fn cmp(&self, other: &Self) -> core::cmp::Ordering {
let serialized_self =
<<C::Group as Group>::Field>::little_endian_serialize(&self.to_scalar());
let serialized_other =
<<C::Group as Group>::Field>::little_endian_serialize(&other.to_scalar());
serialized_self
.as_ref()
.iter()
.rev()
.cmp(serialized_other.as_ref().iter().rev())
}
}
impl<C> PartialOrd for Identifier<C>
where
C: Ciphersuite,
{
fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
Some(self.cmp(other))
}
}
impl<C> TryFrom<u16> for Identifier<C>
where
C: Ciphersuite,
{
type Error = Error<C>;
fn try_from(n: u16) -> Result<Identifier<C>, Self::Error> {
if n == 0 {
Err(FieldError::InvalidZeroScalar.into())
} else {
let one = <<C::Group as Group>::Field>::one();
let mut sum = <<C::Group as Group>::Field>::one();
let bits = (n.to_be_bytes().len() as u32) * 8;
for i in (0..(bits - n.leading_zeros() - 1)).rev() {
sum = sum + sum;
if n & (1 << i) != 0 {
sum = sum + one;
}
}
Self::new(sum)
}
}
}