primitives/types/identifiers/
session_id.rs

1use aes::cipher::generic_array::GenericArray;
2use derive_more::derive::{AsMut, AsRef, IntoIterator};
3use hybrid_array::Array;
4#[cfg(any(test, feature = "dev"))]
5use rand::{distributions::Standard, prelude::Distribution, Rng};
6use serde::{Deserialize, Serialize};
7#[cfg(any(test, feature = "dev"))]
8use typenum::Unsigned;
9use typenum::U16;
10
11use crate::{
12    constants::CollisionResistanceBytes,
13    hashing::{self, Digest},
14    random::{derive_rng::DeriveRng, 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)]
25pub struct SessionId(Array<u8, CollisionResistanceBytes>);
26
27impl SessionId {
28    /// Refreshes the session ID on its own.
29    pub fn refresh(&mut self) {
30        self.0 = hashing::hash(&[self.as_ref(), b"sid_refresh"]);
31    }
32
33    /// Refreshes the session ID.
34    pub fn refresh_with<T: AsRef<[u8]> + ?Sized>(&mut self, tag: &T) {
35        self.0 = hashing::hash(&[self.as_ref(), tag.as_ref()]);
36    }
37
38    /// Refreshes the session ID by extracting randomness from a given transcript.
39    pub fn refresh_from<T: Transcript>(&mut self, transcript: &mut T) {
40        transcript.extract(b"new_session_id", &mut self.0);
41    }
42}
43
44impl DeriveRng for SessionId {}
45
46// ---------- Conversions ----------- //
47
48impl AsRef<[u8]> for SessionId {
49    fn as_ref(&self) -> &[u8] {
50        &self.0
51    }
52}
53
54impl From<Digest> for SessionId {
55    fn from(value: Digest) -> Self {
56        SessionId(value)
57    }
58}
59
60impl From<SessionId> for [u8; 32] {
61    fn from(session_id: SessionId) -> [u8; 32] {
62        session_id.0.into()
63    }
64}
65
66impl<'sid> From<&'sid SessionId> for &'sid [u8; 32] {
67    fn from(session_id: &'sid SessionId) -> &'sid [u8; 32] {
68        (&session_id.0).into()
69    }
70}
71
72impl From<&SessionId> for u32 {
73    fn from(session_id: &SessionId) -> u32 {
74        u32::from_le_bytes(session_id.0[0..4].try_into().unwrap())
75    }
76}
77
78impl From<&SessionId> for [u8; 16] {
79    fn from(session_id: &SessionId) -> [u8; 16] {
80        let mut hash = [0; 16];
81        hashing::hash_into([session_id], &mut hash);
82        hash
83    }
84}
85
86impl From<&SessionId> for GenericArray<u8, U16> {
87    fn from(session_id: &SessionId) -> GenericArray<u8, U16> {
88        let mut hash = GenericArray::<u8, U16>::default();
89        hashing::hash_into([session_id], &mut hash);
90        hash
91    }
92}
93
94// ------ Generation ------ //
95
96pub trait SessionIdGenerator {
97    /// Generates a new session ID from a given seed.
98    fn generate_session_id_from(&self, seed: Seed) -> SessionId {
99        SessionId(seed.into())
100    }
101}
102
103#[cfg(any(test, feature = "dev"))]
104impl Distribution<SessionId> for Standard {
105    fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> SessionId {
106        let mut bytes = Array([0; CollisionResistanceBytes::USIZE]);
107        rng.fill_bytes(&mut bytes);
108        SessionId(bytes)
109    }
110}
111
112#[cfg(any(test, feature = "dev"))]
113impl SessionId {
114    /// Generates a new session ID by hashing the given seed.
115    pub fn from_hashed_seed(seed: &[u8]) -> SessionId {
116        let mut bytes = Array([0; CollisionResistanceBytes::USIZE]);
117        hashing::hash_into([seed], &mut bytes);
118        SessionId(bytes)
119    }
120}
121
122// --------- Display -------- //
123
124#[cfg(not(any(test, feature = "dev")))]
125impl std::fmt::Display for SessionId {
126    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
127        write!(f, "SessionId({})", hex::encode(self.0))
128    }
129}
130
131#[cfg(not(any(test, feature = "dev")))]
132impl std::fmt::Debug for SessionId {
133    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
134        write!(f, "SessionId({})", hex::encode(self.0))
135    }
136}
137
138#[cfg(any(test, feature = "dev"))]
139impl std::fmt::Display for SessionId {
140    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
141        write!(f, "SessionId({}...)", &hex::encode(self.0)[0..6])
142    }
143}
144
145#[cfg(any(test, feature = "dev"))]
146impl std::fmt::Debug for SessionId {
147    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
148        write!(f, "SessionId({}...)", &hex::encode(self.0)[0..6])
149    }
150}