primitives/types/identifiers/
session_id.rs1use 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#[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 pub fn refresh(&mut self) {
30 self.0 = hashing::hash(&[self.as_ref(), b"sid_refresh"]);
31 }
32
33 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 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
46impl 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
94pub trait SessionIdGenerator {
97 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 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#[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}