UNPKG

js-randomness-predictor

Version:

Predict Math.random output in Node, Deno, Bun, Chrome, Firefox, and Safari

5 lines (4 loc) 11.2 kB
import*as w from"z3-solver-jsrp";import B from"./exportResults.js";import E from"./getCurrentNodeJsMajorVersion.js";import{E as x,D as g,a as I,b as q,V as S}from"./types-ruK-I6EJ.js";import"node:fs";import"node:path";class p extends Error{constructor(t){t=t===void 0?"Cannot solve state. Unable to make accurate predictions.":t,super(t),this.name="UnsatError",Object.setPrototypeOf(this,new.target.prototype)}}class N extends Error{constructor(t){super(t),this.name="InsufficientSequenceLengthError",Object.setPrototypeOf(this,new.target.prototype)}}class _ extends Error{constructor(t){super(t),this.name="SequenceNotFoundError",Object.setPrototypeOf(this,new.target.prototype)}}class v extends Error{constructor(t){super(t),this.name="UnexpectedRuntimeError",Object.setPrototypeOf(this,new.target.prototype)}}function f(s){return s&0xffffffffffffffffn}class a{constructor(){}static symbolic(t){let e=t[0];e=e.xor(e.shl(23)),e=e.xor(e.lshr(17)),e=e.xor(t[1]),e=e.xor(t[1].lshr(26)),t[0]=t[1],t[1]=e}static symbolicArithmeticShiftRight(t){let e=t[0];e=e.xor(e.shl(23)),e=e.xor(e.shr(17)),e=e.xor(t[1]),e=e.xor(t[1].shr(26)),t[0]=t[1],t[1]=e}static concreteBackwards(t){let e=t[1]^t[0]>>26n^t[0];e=f(e^e>>17n^e>>34n^e>>51n),e=f(e^e<<23n^e<<46n),t[1]=t[0],t[0]=e}static concrete(t){let e=t[0];e^=f(e<<23n),e^=f(e>>17n),e^=t[1],e^=f(t[1]>>26n),t[0]=t[1],t[1]=e}static concreteArithmeticShiftRight(t){let e=f(t[0]);e^=f(e<<23n),e^=this.#n(e,17n),e^=t[1],e^=this.#n(t[1],26n),t[0]=t[1],t[1]=f(e)}static#n(t,e){const n=f(t>>e);if((t&1n<<63n)===0n)return n;const i=(1n<<e)-1n<<64n-e;return n|i}}class M{sequence;#n=Math.pow(2,53);#t=[0n,0n];constructor(t){this.sequence=t}async predictNext(){this.#t[0]===0n&&this.#t[1]===0n&&await this.#e();const t=this.#i(this.#t[0]);return a.concreteBackwards(this.#t),t}async#e(){try{const{Context:t}=await w.init(),e=t("main"),n=new e.Solver,o=e.BitVec.const("ss0",64),i=e.BitVec.const("ss1",64),r=[o,i],h=[...this.sequence].reverse();for(const u of h){a.symbolic(r);const l=this.#s(u);n.add(r[0].lshr(11).eq(e.BitVec.val(l,64)))}if(await n.check()!=="sat")throw new p;const c=n.model();this.#t=[c.get(o).value(),c.get(i).value()]}catch(t){return Promise.reject(t)}}#s(t){const e=Math.floor(t*this.#n);return BigInt(e)}#i(t){return Number(t>>11n)/this.#n}}class A{sequence;#n=0x1fffffffffffffn;#t=Math.pow(2,53);#e=[0n,0n];constructor(t){this.sequence=t}async predictNext(){return this.#e[0]===0n&&this.#e[1]===0n&&await this.#s(),a.concrete(this.#e),this.#r(f(this.#e[0]+this.#e[1]))}async#s(){try{const{Context:t}=await w.init(),e=t("main"),n=new e.Solver,o=e.BitVec.const("ss0",64),i=e.BitVec.const("ss1",64),r=[o,i];for(const u of this.sequence){a.symbolic(r);const l=this.#i(u),y=r[0].add(r[1]).and(e.BitVec.val(this.#n,64));n.add(y.eq(e.BitVec.val(l,64)))}if(await n.check()!=="sat")throw new p;const h=n.model(),c=[h.get(o).value(),h.get(i).value()];for(const u of this.sequence)a.concrete(c);this.#e=c}catch(t){return Promise.reject(t)}}#i(t){return BigInt(Math.floor(t*this.#t))}#r(t){return Number(t&this.#n)/this.#t}}class d{constructor(){}static isDeno(){return typeof globalThis.Deno<"u"&&typeof Deno.version<"u"&&typeof Deno.version.deno=="string"}static isBun(){return typeof globalThis.Bun<"u"&&typeof Bun.version<"u"&&typeof process.versions.bun=="string"}static isNode(){return!this.isDeno()&&!this.isBun()&&typeof process.versions.node<"u"&&typeof process.versions.node=="string"}static isFirefox(){return typeof window<"u"&&navigator.userAgent.indexOf("Firefox")>-1}static isChrome(){return typeof window!==void 0&&navigator.userAgent.indexOf("Chrome")>-1}static isSafari(){return typeof window!==void 0&&navigator.userAgent.indexOf("Safari")>-1}static type(){if(this.isNode())return"node";if(this.isDeno())return"deno";if(this.isBun())return"bun";if(this.isChrome())return"chrome";if(this.isSafari())return"safari";if(this.isFirefox())return"firefox";throw new v}}class V{sequence;#n=64;#t=4;#e=0x000fffffffffffffn;#s=0x3ff0000000000000n;#i=Math.pow(2,53);#r=this.#h();#c;#o=[0n,0n];constructor(t){if(t&&t.length>=this.#n)throw new Error(`sequence.length must be less than '${this.#n}', got '${t.length}'`);if(!t){if(!d.isNode())throw new v("Expected NodeJS runtime! Unable to auto-generate sequence, please provide one.");t=Array.from({length:this.#t},Math.random)}this.sequence=t,this.#c=this.#a()}async predictNext(){this.#o[0]===0n&&this.#o[1]===0n&&await this.#u();const t=this.#c.toDouble(this.#o);return a.concreteBackwards(this.#o),t}setNodeVersion(t){this.#r=t,this.#c=this.#a()}#h(){const[t,e,n]=process.versions.node.split(".").map(Number);return{major:t,minor:e,patch:n}}#a(){const{major:t}=this.#r;return t<=11?{recoverMantissa:e=>{const n=Buffer.alloc(8);return n.writeDoubleLE(e+1,0),n.readBigUInt64LE(0)&this.#e},toDouble:e=>{const n=e[0]+e[1],o=Buffer.alloc(8);return o.writeBigUInt64LE(n&this.#e|this.#s,0),o.readDoubleLE(0)-1},constrainMantissa:(e,n,o,i)=>{const r=n[0].add(n[1]).and(i.BitVec.val(this.#e,64));o.add(r.eq(i.BitVec.val(e,64)))}}:t<=23?{recoverMantissa:e=>{const n=Buffer.alloc(8);return n.writeDoubleLE(e+1,0),n.readBigUInt64LE(0)&this.#e},toDouble:e=>{const n=Buffer.alloc(8);return n.writeBigUInt64LE(e[0]>>12n|this.#s,0),n.readDoubleLE(0)-1},constrainMantissa:(e,n,o,i)=>{o.add(n[0].lshr(12).eq(i.BitVec.val(e,64)))}}:{recoverMantissa:e=>{const n=Math.floor(e*this.#i);return BigInt(n)},toDouble:e=>Number(e[0]>>11n)/this.#i,constrainMantissa:(e,n,o,i)=>{o.add(n[0].lshr(11).eq(i.BitVec.val(e,64)))}}}async#u(){try{const{Context:t}=await w.init(),e=t("main"),n=new e.Solver,o=e.BitVec.const("ss0",64),i=e.BitVec.const("ss1",64),r=[o,i],h=[...this.sequence].reverse();for(const u of h){a.symbolic(r);const l=this.#c.recoverMantissa(u);this.#c.constrainMantissa(l,r,n,e)}if(await n.check()!=="sat")throw new p;const c=n.model();this.#o=[c.get(o).value(),c.get(i).value()]}catch(t){return Promise.reject(t)}}}class T{sequence;#n=6;#t=[0n,0n];#e;#s;#i=0x1fffffffffffffn;#r=Math.pow(2,53);constructor(t){if(t.length<this.#n)throw new N(`sequence length must be >= 6 : got ${t.length}`);this.#e=e=>a.symbolicArithmeticShiftRight(e),this.#s=e=>a.concreteArithmeticShiftRight(e),this.sequence=t}async predictNext(){return this.#t[0]===0n&&this.#t[1]===0n&&await this.#c(()=>this.#o(),()=>(this.#e=t=>a.symbolic(t),this.#s=t=>a.concrete(t),this.#o())),this.#s(this.#t),this.#a(f(this.#t[0]+this.#t[1]))}async#c(t,e){try{return await t()}catch{return await e()}}async#o(){try{const{Context:t}=await w.init(),e=t("main"),n=new e.Solver,o=e.BitVec.const("ss0",64),i=e.BitVec.const("ss1",64),r=[o,i];for(const u of this.sequence){this.#e(r);const l=this.#h(u),y=r[0].add(r[1]).and(e.BitVec.val(this.#i,64));n.add(y.eq(e.BitVec.val(l,64)))}if(await n.check()!=="sat")throw new p;const h=n.model(),c=[h.get(o).value(),h.get(i).value()];for(const u of this.sequence)this.#s(c);this.#t=c}catch(t){return Promise.reject(t)}}#h(t){return BigInt(Math.floor(t*this.#r))}#a(t){return Number(t&this.#i)/this.#r}}function b(s=1){const t=[];for(let e=0;e<s;e++)t.push(Math.random());return t}class R{sequence;#n=6;#t=[0n,0n];#e=t=>a.symbolic(t);#s=t=>a.concrete(t);#i=0x1fffffffffffffn;#r=Math.pow(2,53);constructor(t){if(t&&t.length<this.#n)throw new N(`sequence length must be >= 6 : got ${t.length}`);if(!t){if(!d.isBun())throw new v("Expected Bun runtime! Unable to auto-generate sequence, please provide one.");t=b(this.#n)}this.sequence=t}async predictNext(){return this.#t[0]===0n&&this.#t[1]===0n&&await this.#c(()=>this.#o(),()=>(this.#e=t=>a.symbolicArithmeticShiftRight(t),this.#s=t=>a.concreteArithmeticShiftRight(t),this.#o())),this.#s(this.#t),this.#a(f(this.#t[0]+this.#t[1]))}async#c(t,e){try{return await t()}catch{return await e()}}async#o(){try{const{Context:t}=await w.init(),e=t("main"),n=new e.Solver,o=e.BitVec.const("ss0",64),i=e.BitVec.const("ss1",64),r=[o,i];for(const u of this.sequence){this.#e(r);const l=this.#h(u),y=r[0].add(r[1]).and(e.BitVec.val(this.#i,64));n.add(y.eq(e.BitVec.val(l,64)))}if(await n.check()!=="sat")throw new p;const h=n.model(),c=[h.get(o).value(),h.get(i).value()];for(const u of this.sequence)this.#s(c);this.#t=c}catch(t){return Promise.reject(t)}}#h(t){return BigInt(Math.floor(t*this.#r))}#a(t){return Number(t&this.#i)/this.#r}}class C{sequence;#n=Math.pow(2,53);#t=[0n,0n];constructor(t){if(!t){if(!d.isDeno())throw new v("Expected Deno runtime! Unable to auto-generate sequence, please provide one.");t=Array.from({length:4},Math.random)}this.sequence=t}async predictNext(){this.#t[0]===0n&&this.#t[1]===0n&&await this.#e();const t=this.#i(this.#t[0]);return a.concreteBackwards(this.#t),t}async#e(){try{const{Context:t}=await w.init(),e=t("main"),n=new e.Solver,o=e.BitVec.const("ss0",64),i=e.BitVec.const("ss1",64),r=[o,i],h=[...this.sequence].reverse();for(const u of h){a.symbolic(r);const l=this.#s(u);n.add(r[0].lshr(11).eq(e.BitVec.val(l,64)))}if(await n.check()!=="sat")throw new p;const c=n.model();this.#t=[c.get(o).value(),c.get(i).value()]}catch(t){return Promise.reject(t)}}#s(t){const e=Math.floor(t*this.#n);return BigInt(e)}#i(t){return Number(t>>11n)/this.#n}}const m={node:s=>new V(s),firefox:s=>new A(s),chrome:s=>new M(s),safari:s=>new T(s),bun:s=>new R(s),deno:s=>new C(s)};m.node,m.firefox,m.chrome,m.safari,m.bun,m.deno;async function P(s){try{if(!s.sequence&&d.type()!==s.environment)throw new _(`'--sequence' is required when '--environment' is '${s.environment}' and '${x}' is '${d.type()}'`);if(d.isNode()&&s.environment==="node"&&s.envVersion&&!s.sequence&&s.envVersion!==E())throw new _(`'--sequence' is required when '--environment' is '${s.environment}' and '--env-version' is different than your current Node.js version! Current Node version is '${E()}' but --env-version is '${s.envVersion}'`);const t={actual:"You'll need to get this yourself via the same way you generated the sequence",sequence:s.sequence?s.sequence:b(g[s.environment]),isCorrect:void 0,predictions:[],_warnings:[],_info:[]},e=d.isNode()&&E()===s.envVersion;let n=s.predictions!==void 0?s.predictions:I;if(q[s.environment]==="v8"&&n+t.sequence.length>S){if(t.sequence.length>=S)throw new Error(`Sequence too large! Sequence length must be less than '${S}', got '${t.sequence.length}'`);const i=S-t.sequence.length;n=i,t._warnings.push(`Exceeded max predictions! - For a sequence length of '${t.sequence.length}', max number of predictions allowed is '${i}'. - Truncated number of predictions to '${i}'. - Why? See here : https://github.com/matthewoestreich/js-randomness-predictor/blob/main/.github/KNOWN_ISSUES.md#random-number-pool-exhaustion`)}if(process.env.JSRP_DRY_RUN==="1")return t;const o=m[s.environment](t.sequence);if(d.isNode()&&s.envVersion&&s.environment==="node"&&!e){const i={major:Number(s.envVersion),minor:0,patch:0};o.setNodeVersion?.(i)}for(let i=0;i<n;i++){const r=await o.predictNext();t.predictions.push(r)}if(!s.sequence)switch(s.environment){case"node":{d.isNode()&&(!s.envVersion||e)&&(t.actual=b(n));break}case"deno":{d.isDeno()&&(t.actual=b(n));break}case"bun":{d.isBun()&&(t.actual=b(n));break}}return Array.isArray(t.actual)&&(t.isCorrect=t.actual.every((i,r)=>i===t.predictions[r])),s.export&&B(s,t),t}catch(t){return Promise.reject(t)}}export{P as runPredictor};