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