11use std:: marker:: PhantomData ;
2- use std:: { cell:: RefCell , sync:: Arc } ;
2+ use std:: sync:: atomic:: { AtomicU64 , Ordering } ;
3+ use std:: sync:: Arc ;
34
45use aes_gcm:: { aead:: AeadInPlace , Aes128Gcm } ;
5- use rand:: { prelude:: SmallRng , rng, Rng , SeedableRng } ;
6+ use once_cell:: sync:: Lazy ;
7+ use rand:: { rng, Rng } ;
68
79use crate :: transport:: crypto:: TransportPublicKey ;
810
@@ -20,11 +22,25 @@ const TAG_SIZE: usize = 16;
2022pub ( super ) const MAX_DATA_SIZE : usize = MAX_PACKET_SIZE - NONCE_SIZE - TAG_SIZE ;
2123const UDP_HEADER_SIZE : usize = 8 ;
2224
23- thread_local ! {
24- // This must be very fast, but doesn't need to be cryptographically secure.
25- static RNG : RefCell <SmallRng > = RefCell :: new(
26- SmallRng :: from_rng( & mut rng( ) )
27- ) ;
25+ /// Counter-based nonce generation for AES-GCM.
26+ /// Uses 8 bytes from an atomic counter + 4 random bytes generated at startup.
27+ /// This is ~5.5x faster than random nonce generation while maintaining uniqueness.
28+ static NONCE_COUNTER : AtomicU64 = AtomicU64 :: new ( 0 ) ;
29+
30+ /// Random prefix generated once at startup to ensure nonce uniqueness across process restarts.
31+ static NONCE_RANDOM_PREFIX : Lazy < [ u8 ; 4 ] > = Lazy :: new ( || rng ( ) . random ( ) ) ;
32+
33+ /// Generate a unique 12-byte nonce using counter + random prefix.
34+ /// This is faster than random generation while ensuring uniqueness.
35+ #[ inline]
36+ fn generate_nonce ( ) -> [ u8 ; NONCE_SIZE ] {
37+ let counter = NONCE_COUNTER . fetch_add ( 1 , Ordering :: Relaxed ) ;
38+ let mut nonce = [ 0u8 ; NONCE_SIZE ] ;
39+ // First 4 bytes: random prefix (ensures uniqueness across restarts)
40+ nonce[ ..4 ] . copy_from_slice ( & * NONCE_RANDOM_PREFIX ) ;
41+ // Last 8 bytes: counter (ensures uniqueness within this process)
42+ nonce[ 4 ..] . copy_from_slice ( & counter. to_le_bytes ( ) ) ;
43+ nonce
2844}
2945
3046struct AssertSize < const N : usize > ;
@@ -148,7 +164,7 @@ impl<const N: usize> PacketData<Plaintext, N> {
148164 _check_valid_size :: < N > ( ) ;
149165 debug_assert ! ( self . size <= MAX_DATA_SIZE ) ;
150166
151- let nonce: [ u8 ; NONCE_SIZE ] = RNG . with ( |rng| rng . borrow_mut ( ) . random ( ) ) ;
167+ let nonce = generate_nonce ( ) ;
152168
153169 let mut buffer = [ 0u8 ; N ] ;
154170 buffer[ ..NONCE_SIZE ] . copy_from_slice ( & nonce) ;
0 commit comments