Skip to main content

primitives/types/identifiers/
session_id.rs

1use aes::cipher::generic_array::GenericArray;
2use derive_more::derive::{AsMut, AsRef, IntoIterator};
3use hybrid_array::Array;
4use serde::{Deserialize, Serialize};
5#[cfg(any(test, feature = "dev"))]
6use typenum::Unsigned;
7use typenum::U16;
8use wincode::{SchemaRead, SchemaWrite};
9
10#[cfg(any(test, feature = "dev"))]
11use crate::random::{CryptoRngCore, Random};
12use crate::{
13    constants::CollisionResistanceBytes,
14    hashing::{self, Digest},
15    random::Seed,
16    transcripts::Transcript,
17};
18
19/// The type of a session identifier, commonly used by protocols to achieve UC
20/// security in the CRS model. It should be unique for each protocol execution.
21/// We make it be random by:
22/// - Sampling an original Session ID via a distributed protocol (or via local sampling in tests).
23/// - Refreshing it upon each protocol execution by mixig it with the protocol transcript.
24#[derive(
25    Default,
26    Copy,
27    AsRef,
28    AsMut,
29    Clone,
30    Serialize,
31    Deserialize,
32    SchemaRead,
33    SchemaWrite,
34    PartialEq,
35    IntoIterator,
36)]
37#[into_iterator(owned, ref, ref_mut)]
38#[repr(transparent)]
39pub struct SessionId(Array<u8, CollisionResistanceBytes>);
40
41impl SessionId {
42    /// Refreshes the session ID.
43    pub fn refresh_with<T: AsRef<[u8]> + ?Sized>(&mut self, tag: &T) {
44        self.0 = hashing::hash(&[self.as_ref(), tag.as_ref()]);
45    }
46
47    /// Refreshes the session ID by extracting randomness from a given transcript.
48    pub fn refresh_from<T: Transcript>(transcript: &mut T) -> SessionId {
49        SessionId(transcript.extract(b"new_session_id").into())
50    }
51}
52
53// ---------- Conversions ----------- //
54
55impl AsRef<[u8]> for SessionId {
56    fn as_ref(&self) -> &[u8] {
57        &self.0
58    }
59}
60
61impl std::ops::Deref for SessionId {
62    type Target = [u8; 32];
63
64    fn deref(&self) -> &[u8; 32] {
65        self.0.as_ref()
66    }
67}
68
69impl From<Digest> for SessionId {
70    fn from(value: Digest) -> Self {
71        SessionId(value)
72    }
73}
74
75impl From<SessionId> for [u8; 32] {
76    fn from(session_id: SessionId) -> [u8; 32] {
77        session_id.0.into()
78    }
79}
80
81impl<'sid> From<&'sid SessionId> for &'sid [u8; 32] {
82    fn from(session_id: &'sid SessionId) -> &'sid [u8; 32] {
83        (&session_id.0).into()
84    }
85}
86
87impl From<&SessionId> for u32 {
88    fn from(session_id: &SessionId) -> u32 {
89        u32::from_le_bytes(session_id.0[0..4].try_into().unwrap())
90    }
91}
92
93impl From<&SessionId> for [u8; 16] {
94    fn from(session_id: &SessionId) -> [u8; 16] {
95        let mut hash = [0; 16];
96        hashing::hash_into([session_id], &mut hash);
97        hash
98    }
99}
100
101impl From<&SessionId> for GenericArray<u8, U16> {
102    fn from(session_id: &SessionId) -> GenericArray<u8, U16> {
103        let mut hash = GenericArray::<u8, U16>::default();
104        hashing::hash_into([session_id], &mut hash);
105        hash
106    }
107}
108
109// ------ Generation ------ //
110
111/// Trait to gate the SessionId generation to:
112/// - Random sampling or hashing in dev/tests.
113/// - Running `drand` in production.
114pub trait SessionIdGenerator {
115    /// Generates a new session ID from a given seed.
116    fn generate_session_id_from(&self, seed: Seed) -> SessionId {
117        SessionId(seed.into())
118    }
119}
120
121#[cfg(any(test, feature = "dev"))]
122impl Random for SessionId {
123    fn random(mut rng: impl CryptoRngCore) -> Self {
124        let mut bytes = Array([0; CollisionResistanceBytes::USIZE]);
125        rng.fill_bytes(&mut bytes);
126        SessionId(bytes)
127    }
128}
129
130#[cfg(any(test, feature = "dev"))]
131impl SessionId {
132    /// Generates a new session ID by hashing the given seed.
133    pub fn from_hashed_seed(seed: &[u8]) -> SessionId {
134        let mut bytes = Array([0; CollisionResistanceBytes::USIZE]);
135        hashing::hash_into([seed], &mut bytes);
136        SessionId(bytes)
137    }
138}
139
140// --------- Display -------- //
141
142#[cfg(not(any(test, feature = "dev")))]
143impl std::fmt::Display for SessionId {
144    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
145        write!(f, "SessionId({})", hex::encode(self.0))
146    }
147}
148
149#[cfg(not(any(test, feature = "dev")))]
150impl std::fmt::Debug for SessionId {
151    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
152        write!(f, "SessionId({})", hex::encode(self.0))
153    }
154}
155
156#[cfg(any(test, feature = "dev"))]
157impl std::fmt::Display for SessionId {
158    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
159        write!(f, "SessionId({}...)", &hex::encode(self.0)[0..6])
160    }
161}
162
163#[cfg(any(test, feature = "dev"))]
164impl std::fmt::Debug for SessionId {
165    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
166        write!(f, "SessionId({}...)", &hex::encode(self.0)[0..6])
167    }
168}