/**
 * Package chacha-drbg implements ChaCha-based digital random byte generator.
 */ import { defaultRandomSource , RandomSource } from "@stablelib/random" ; import { streamXOR , stream } from "@stablelib/chacha" ; import { wipe } from "@stablelib/wipe" ; const RESEED_MAX_BYTES = 1024 * 1024 ; /**
 * ChaCha DRBG.
 */ export class ChaChaDRBG implements RandomSource { isAvailable = false ; isInstantiated = false ; private _key = new Uint8Array ( 32 ) ; private _bytesGenerated = 0 ; private _reseedNonce = new Uint8Array ( [ 1 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ] ) ; private _extractNonce = new Uint8Array ( [ 2 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ] ) ; private _rekeyNonce = new Uint8Array ( [ 3 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ] ) ; constructor ( private _entropySource = defaultRandomSource ) { this . isAvailable = this . _entropySource . isAvailable ; } private _instantiate ( ) { if ( ! this . _entropySource . isAvailable ) { throw new Error ( "ChaChaDRBG: entropy source is not available" ) ; } this . _reseed ( ) ; this . isInstantiated = true ; } private _reseed ( ) { const tmp = this . _entropySource . randomBytes ( 32 ) ; streamXOR ( this . _key , this . _reseedNonce , tmp , tmp ) ; incrementNonce ( this . _reseedNonce ) ; this . _key . set ( tmp ) ; wipe ( tmp ) ; for ( let i = 7 ; i >= 1 ; i -- ) { this . _extractNonce [ i ] = 0 ; this . _rekeyNonce [ i ] = 0 ; } this . _bytesGenerated = 0 ; } rekey ( ) { const tmp = new Uint8Array ( 32 ) ; stream ( tmp , this . _rekeyNonce , tmp ) ; this . _key . set ( tmp ) ; wipe ( tmp ) ; incrementNonce ( this . _rekeyNonce ) ; } private _generate ( length ) { if ( this . _bytesGenerated + length > RESEED_MAX_BYTES ) { this . _reseed ( ) ; } let out = new Uint8Array ( length ) ; stream ( this . _key , this . _extractNonce , out ) ; incrementNonce ( this . _extractNonce ) ; this . _bytesGenerated += out . length ; this . rekey ( ) ; return out ; } randomBytes ( length ) { if ( ! this . isInstantiated ) { this . _instantiate ( ) ; } return this . _generate ( length ) ; } } function incrementNonce ( nonce ) { for ( let i = 7 ; i >= 1 ; i -- ) { nonce [ i ] = nonce [ i ] + 1 & 0xff ; if ( nonce [ i ] !== 0 ) { break ; } } }