1use core::{
4 fmt::{self, Debug},
5 hash::{Hash, Hasher},
6};
7
8use alloc::vec::Vec;
9
10use crate::{
11 serialization::SerializableScalar, Ciphersuite, Error, Field, FieldError, Group, Scalar,
12};
13
14#[derive(Copy, Clone, PartialEq)]
20#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
21#[cfg_attr(feature = "serde", serde(bound = "C: Ciphersuite"))]
22#[cfg_attr(feature = "serde", serde(try_from = "SerializableScalar<C>"))]
25#[cfg_attr(feature = "serde", serde(into = "SerializableScalar<C>"))]
26pub struct Identifier<C: Ciphersuite>(SerializableScalar<C>);
27
28impl<C> Identifier<C>
29where
30 C: Ciphersuite,
31{
32 #[cfg_attr(feature = "internals", visibility::make(pub))]
34 #[cfg_attr(docsrs, doc(cfg(feature = "internals")))]
35 pub(crate) fn new(scalar: Scalar<C>) -> Result<Self, Error<C>> {
36 if scalar == <<C::Group as Group>::Field>::zero() {
37 Err(FieldError::InvalidZeroScalar.into())
38 } else {
39 Ok(Self(SerializableScalar(scalar)))
40 }
41 }
42
43 #[cfg_attr(feature = "internals", visibility::make(pub))]
45 #[cfg_attr(docsrs, doc(cfg(feature = "internals")))]
46 pub(crate) fn to_scalar(&self) -> Scalar<C> {
47 self.0 .0
48 }
49
50 pub fn derive(s: &[u8]) -> Result<Self, Error<C>> {
60 let scalar = C::HID(s).ok_or(Error::IdentifierDerivationNotSupported)?;
61 Self::new(scalar)
62 }
63
64 pub fn serialize(&self) -> Vec<u8> {
66 self.0.serialize()
67 }
68
69 pub fn deserialize(bytes: &[u8]) -> Result<Self, Error<C>> {
72 Self::new(SerializableScalar::deserialize(bytes)?.0)
73 }
74}
75
76#[cfg(feature = "serde")]
77impl<C> TryFrom<SerializableScalar<C>> for Identifier<C>
78where
79 C: Ciphersuite,
80{
81 type Error = Error<C>;
82
83 fn try_from(s: SerializableScalar<C>) -> Result<Self, Self::Error> {
84 Self::new(s.0)
85 }
86}
87
88#[cfg(feature = "serde")]
89impl<C> From<Identifier<C>> for SerializableScalar<C>
90where
91 C: Ciphersuite,
92{
93 fn from(i: Identifier<C>) -> Self {
94 i.0
95 }
96}
97
98impl<C> Eq for Identifier<C> where C: Ciphersuite {}
99
100impl<C> Debug for Identifier<C>
101where
102 C: Ciphersuite,
103{
104 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
105 f.debug_tuple("Identifier")
106 .field(&hex::encode(self.serialize()))
107 .finish()
108 }
109}
110
111#[allow(clippy::derived_hash_with_manual_eq)]
112impl<C> Hash for Identifier<C>
113where
114 C: Ciphersuite,
115{
116 fn hash<H: Hasher>(&self, state: &mut H) {
117 self.serialize().hash(state)
118 }
119}
120
121impl<C> Ord for Identifier<C>
122where
123 C: Ciphersuite,
124{
125 fn cmp(&self, other: &Self) -> core::cmp::Ordering {
126 let serialized_self =
127 <<C::Group as Group>::Field>::little_endian_serialize(&self.to_scalar());
128 let serialized_other =
129 <<C::Group as Group>::Field>::little_endian_serialize(&other.to_scalar());
130 serialized_self
132 .as_ref()
133 .iter()
134 .rev()
135 .cmp(serialized_other.as_ref().iter().rev())
136 }
137}
138
139impl<C> PartialOrd for Identifier<C>
140where
141 C: Ciphersuite,
142{
143 fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
144 Some(self.cmp(other))
145 }
146}
147
148impl<C> TryFrom<u16> for Identifier<C>
149where
150 C: Ciphersuite,
151{
152 type Error = Error<C>;
153
154 fn try_from(n: u16) -> Result<Identifier<C>, Self::Error> {
155 if n == 0 {
156 Err(FieldError::InvalidZeroScalar.into())
157 } else {
158 let one = <<C::Group as Group>::Field>::one();
161 let mut sum = <<C::Group as Group>::Field>::one();
162
163 let bits = (n.to_be_bytes().len() as u32) * 8;
164 for i in (0..(bits - n.leading_zeros() - 1)).rev() {
165 sum = sum + sum;
166 if n & (1 << i) != 0 {
167 sum = sum + one;
168 }
169 }
170 Self::new(sum)
171 }
172 }
173}