12
12
//! Some parts copied from https://github.com/uuidjs/uuid/blob/main/src/stringify.js
13
13
//! License MIT
14
14
15
- import { Rand } from "../restate_context" ;
16
- import { ErrorCodes , TerminalError } from "../types/errors" ;
17
- import { CallContexType , RestateGrpcContextImpl } from "../restate_context_impl" ;
18
- import { createHash } from "crypto" ;
15
+ import { Rand } from "../restate_context" ;
16
+ import { ErrorCodes , TerminalError } from "../types/errors" ;
17
+ import {
18
+ CallContexType ,
19
+ RestateGrpcContextImpl ,
20
+ } from "../restate_context_impl" ;
21
+ import { createHash } from "crypto" ;
19
22
20
23
export class RandImpl implements Rand {
21
- private randstate64 : bigint ;
24
+ private randstate256 : [ bigint , bigint , bigint , bigint ] ;
22
25
23
- constructor ( id : Buffer | bigint ) {
24
- if ( typeof id == "bigint" ) {
25
- this . randstate64 = id
26
- } else {
26
+ constructor ( id : Buffer | [ bigint , bigint , bigint , bigint ] ) {
27
+ if ( id instanceof Buffer ) {
27
28
// hash the invocation ID, which is known to contain 74 bits of entropy
28
- const hash = createHash ( 'sha256' )
29
- . update ( id )
30
- . digest ( ) ;
31
-
32
- // seed using first 64 bits of the hash
33
- this . randstate64 = hash . readBigUInt64LE ( 0 ) ;
29
+ const hash = createHash ( "sha256" ) . update ( id ) . digest ( ) ;
30
+
31
+ this . randstate256 = [
32
+ hash . readBigUInt64LE ( 0 ) ,
33
+ hash . readBigUInt64LE ( 8 ) ,
34
+ hash . readBigUInt64LE ( 16 ) ,
35
+ hash . readBigUInt64LE ( 24 ) ,
36
+ ] ;
37
+ } else {
38
+ this . randstate256 = id ;
34
39
}
35
40
}
36
41
37
- static U64_MASK = ( ( 1n << 64n ) - 1n )
42
+ static U64_MASK = ( 1n << 64n ) - 1n ;
38
43
39
- // splitmix64
40
- // https://prng.di.unimi.it/splitmix64 .c - public domain
44
+ // xoshiro256++
45
+ // https://prng.di.unimi.it/xoshiro256plusplus .c - public domain
41
46
u64 ( ) : bigint {
42
- this . randstate64 = ( this . randstate64 + 0x9e3779b97f4a7c15n ) & RandImpl . U64_MASK ;
43
- let next : bigint = this . randstate64 ;
44
- next = ( ( next ^ ( next >> 30n ) ) * 0xbf58476d1ce4e5b9n ) & RandImpl . U64_MASK ;
45
- next = ( ( next ^ ( next >> 27n ) ) * 0x94d049bb133111ebn ) & RandImpl . U64_MASK ;
46
- next = next ^ ( next >> 31n ) ;
47
- return next
47
+ const result : bigint =
48
+ ( RandImpl . rotl (
49
+ ( this . randstate256 [ 0 ] + this . randstate256 [ 3 ] ) & RandImpl . U64_MASK ,
50
+ 23n
51
+ ) +
52
+ this . randstate256 [ 0 ] ) &
53
+ RandImpl . U64_MASK ;
54
+
55
+ const t : bigint = ( this . randstate256 [ 1 ] << 17n ) & RandImpl . U64_MASK ;
56
+
57
+ this . randstate256 [ 2 ] ^= this . randstate256 [ 0 ] ;
58
+ this . randstate256 [ 3 ] ^= this . randstate256 [ 1 ] ;
59
+ this . randstate256 [ 1 ] ^= this . randstate256 [ 2 ] ;
60
+ this . randstate256 [ 0 ] ^= this . randstate256 [ 3 ] ;
61
+
62
+ this . randstate256 [ 2 ] ^= t ;
63
+
64
+ this . randstate256 [ 3 ] = RandImpl . rotl ( this . randstate256 [ 3 ] , 45n ) ;
65
+
66
+ return result ;
48
67
}
49
68
50
- static U53_MASK = ( ( 1n << 53n ) - 1n )
69
+ static rotl ( x : bigint , k : bigint ) : bigint {
70
+ return ( ( x << k ) & RandImpl . U64_MASK ) | ( x >> ( 64n - k ) ) ;
71
+ }
51
72
52
73
checkContext ( ) {
53
74
const context = RestateGrpcContextImpl . callContext . getStore ( ) ;
54
75
if ( context && context . type === CallContexType . SideEffect ) {
55
76
throw new TerminalError (
56
77
`You may not call methods on Rand from within a side effect.` ,
57
- { errorCode : ErrorCodes . INTERNAL }
78
+ { errorCode : ErrorCodes . INTERNAL }
58
79
) ;
59
80
}
60
81
}
61
82
83
+ static U53_MASK = ( 1n << 53n ) - 1n ;
84
+
62
85
public random ( ) : number {
63
- this . checkContext ( )
86
+ this . checkContext ( ) ;
64
87
65
88
// first generate a uint in range [0,2^53), which can be mapped 1:1 to a float64 in [0,1)
66
- const u53 = this . u64 ( ) & RandImpl . U53_MASK
89
+ const u53 = this . u64 ( ) & RandImpl . U53_MASK ;
67
90
// then divide by 2^53, which will simply update the exponent
68
- return Number ( u53 ) / 2 ** 53
91
+ return Number ( u53 ) / 2 ** 53 ;
69
92
}
70
93
71
94
public uuidv4 ( ) : string {
72
- this . checkContext ( )
95
+ this . checkContext ( ) ;
73
96
74
97
const buf = Buffer . alloc ( 16 ) ;
75
98
buf . writeBigUInt64LE ( this . u64 ( ) , 0 ) ;
76
99
buf . writeBigUInt64LE ( this . u64 ( ) , 8 ) ;
77
100
// Per 4.4, set bits for version and `clock_seq_hi_and_reserved`
78
101
buf [ 6 ] = ( buf [ 6 ] & 0x0f ) | 0x40 ;
79
102
buf [ 8 ] = ( buf [ 8 ] & 0x3f ) | 0x80 ;
80
- return uuidStringify ( buf )
103
+ return uuidStringify ( buf ) ;
81
104
}
82
105
}
83
106
@@ -102,16 +125,16 @@ function uuidStringify(arr: Buffer, offset = 0) {
102
125
byteToHex [ arr [ offset + 1 ] ] +
103
126
byteToHex [ arr [ offset + 2 ] ] +
104
127
byteToHex [ arr [ offset + 3 ] ] +
105
- '-' +
128
+ "-" +
106
129
byteToHex [ arr [ offset + 4 ] ] +
107
130
byteToHex [ arr [ offset + 5 ] ] +
108
- '-' +
131
+ "-" +
109
132
byteToHex [ arr [ offset + 6 ] ] +
110
133
byteToHex [ arr [ offset + 7 ] ] +
111
- '-' +
134
+ "-" +
112
135
byteToHex [ arr [ offset + 8 ] ] +
113
136
byteToHex [ arr [ offset + 9 ] ] +
114
- '-' +
137
+ "-" +
115
138
byteToHex [ arr [ offset + 10 ] ] +
116
139
byteToHex [ arr [ offset + 11 ] ] +
117
140
byteToHex [ arr [ offset + 12 ] ] +
0 commit comments