15
15
import { Chacha20 } from 'ts-chacha20' ;
16
16
import { Utils } from '../lib/utils' ;
17
17
18
- export type PRNGSeed = SodiumRNGSeed | Gen5RNGSeed ;
18
+ export type PRNGSeed = `${ 'sodium' | 'gen5' | number } ,${ string } ` ;
19
19
export type SodiumRNGSeed = [ 'sodium' , string ] ;
20
20
/** 64-bit big-endian [high -> low] int */
21
21
export type Gen5RNGSeed = [ number , number , number , number ] ;
@@ -44,15 +44,27 @@ export class PRNG {
44
44
/** Creates a new source of randomness for the given seed. */
45
45
constructor ( seed : PRNGSeed | null = null , initialSeed ?: PRNGSeed ) {
46
46
if ( ! seed ) seed = PRNG . generateSeed ( ) ;
47
- this . startingSeed = initialSeed || [ ...seed ] ; // make a copy
47
+ if ( Array . isArray ( seed ) ) {
48
+ // compat for old inputlogs
49
+ seed = seed . join ( ',' ) as PRNGSeed ;
50
+ }
51
+ if ( typeof seed !== 'string' ) {
52
+ throw new Error ( `PRNG: Seed ${ seed } must be a string` ) ;
53
+ }
54
+ this . startingSeed = initialSeed ?? seed ;
48
55
this . setSeed ( seed ) ;
49
56
}
50
57
51
58
setSeed ( seed : PRNGSeed ) {
52
- if ( seed [ 0 ] === 'sodium' ) {
53
- this . rng = new SodiumRNG ( seed ) ;
59
+ if ( seed . startsWith ( 'sodium,' ) ) {
60
+ this . rng = new SodiumRNG ( seed . split ( ',' ) as SodiumRNGSeed ) ;
61
+ } else if ( seed . startsWith ( 'gen5,' ) ) {
62
+ const gen5Seed = [ seed . slice ( 5 , 9 ) , seed . slice ( 9 , 13 ) , seed . slice ( 13 , 17 ) , seed . slice ( 17 , 21 ) ] ;
63
+ this . rng = new Gen5RNG ( gen5Seed . map ( n => parseInt ( n , 16 ) ) as Gen5RNGSeed ) ;
64
+ } else if ( / [ 0 - 9 ] / . test ( seed . charAt ( 0 ) ) ) {
65
+ this . rng = new Gen5RNG ( seed . split ( ',' ) . map ( Number ) as Gen5RNGSeed ) ;
54
66
} else {
55
- this . rng = new Gen5RNG ( seed as Gen5RNGSeed ) ;
67
+ throw new Error ( `Unrecognized RNG seed ${ seed } ` ) ;
56
68
}
57
69
}
58
70
getSeed ( ) : PRNGSeed {
@@ -145,15 +157,14 @@ export class PRNG {
145
157
}
146
158
}
147
159
148
- static generateSeed ( ) : SodiumRNGSeed {
149
- return [
150
- 'sodium' ,
151
- // 32 bits each, 128 bits total (16 bytes)
152
- Math . trunc ( Math . random ( ) * 2 ** 32 ) . toString ( 16 ) . padStart ( 8 , '0' ) +
153
- Math . trunc ( Math . random ( ) * 2 ** 32 ) . toString ( 16 ) . padStart ( 8 , '0' ) +
154
- Math . trunc ( Math . random ( ) * 2 ** 32 ) . toString ( 16 ) . padStart ( 8 , '0' ) +
155
- Math . trunc ( Math . random ( ) * 2 ** 32 ) . toString ( 16 ) . padStart ( 8 , '0' ) ,
156
- ] ;
160
+ static generateSeed ( ) : PRNGSeed {
161
+ return PRNG . convertSeed ( SodiumRNG . generateSeed ( ) ) ;
162
+ }
163
+ static convertSeed ( seed : SodiumRNGSeed | Gen5RNGSeed ) : PRNGSeed {
164
+ return seed . join ( ',' ) as PRNGSeed ;
165
+ }
166
+ static get ( prng ?: PRNG | PRNGSeed | null ) {
167
+ return prng && typeof prng !== 'string' && ! Array . isArray ( prng ) ? prng : new PRNG ( prng as PRNGSeed ) ;
157
168
}
158
169
}
159
170
@@ -180,8 +191,8 @@ export class SodiumRNG implements RNG {
180
191
Utils . bufWriteHex ( seedBuf , seed [ 1 ] . padEnd ( 64 , '0' ) ) ;
181
192
this . seed = seedBuf ;
182
193
}
183
- getSeed ( ) : SodiumRNGSeed {
184
- return [ ' sodium' , Utils . bufReadHex ( this . seed ) ] ;
194
+ getSeed ( ) : PRNGSeed {
195
+ return ` sodium, ${ Utils . bufReadHex ( this . seed ) } ` ;
185
196
}
186
197
187
198
next ( ) {
@@ -197,6 +208,17 @@ export class SodiumRNG implements RNG {
197
208
// alternative, probably slower (TODO: benchmark)
198
209
// return parseInt(Utils.bufReadHex(buf, 32, 36), 16);
199
210
}
211
+
212
+ static generateSeed ( ) : SodiumRNGSeed {
213
+ return [
214
+ 'sodium' ,
215
+ // 32 bits each, 128 bits total (16 bytes)
216
+ Math . trunc ( Math . random ( ) * 2 ** 32 ) . toString ( 16 ) . padStart ( 8 , '0' ) +
217
+ Math . trunc ( Math . random ( ) * 2 ** 32 ) . toString ( 16 ) . padStart ( 8 , '0' ) +
218
+ Math . trunc ( Math . random ( ) * 2 ** 32 ) . toString ( 16 ) . padStart ( 8 , '0' ) +
219
+ Math . trunc ( Math . random ( ) * 2 ** 32 ) . toString ( 16 ) . padStart ( 8 , '0' ) ,
220
+ ] ;
221
+ }
200
222
}
201
223
202
224
/**
@@ -210,8 +232,8 @@ export class Gen5RNG implements RNG {
210
232
this . seed = [ ...seed || Gen5RNG . generateSeed ( ) ] ;
211
233
}
212
234
213
- getSeed ( ) {
214
- return this . seed ;
235
+ getSeed ( ) : PRNGSeed {
236
+ return this . seed . join ( ',' ) as PRNGSeed ;
215
237
}
216
238
217
239
next ( ) : number {
0 commit comments