@ceccec/millennium-solutions 9.8.2 → 9.8.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +104 -69
- package/dist/data/baked/answer_gate.json +1 -0
- package/dist/data/baked/answer_verify_arith.json +1 -0
- package/dist/data/baked/answer_verify_arxiv.json +1 -0
- package/dist/data/baked/anti_fake.json +1 -0
- package/dist/data/baked/api_gates.json +1 -0
- package/dist/data/baked/apis_guru_cross.json +1 -0
- package/dist/data/baked/apis_guru_gaps.json +1 -0
- package/dist/data/baked/apis_theorems.json +1 -0
- package/dist/data/baked/coils.json +1 -0
- package/dist/data/baked/constants_check.json +1 -0
- package/dist/data/baked/contradictions.json +1 -0
- package/dist/data/baked/discover.json +1 -0
- package/dist/data/baked/discoveries.json +1 -0
- package/dist/data/baked/entanglements.json +1 -0
- package/dist/data/baked/evidence.json +1 -0
- package/dist/data/baked/hexbit_route.json +1 -0
- package/dist/data/baked/index.json +41 -0
- package/dist/data/baked/leads.json +1 -0
- package/dist/data/baked/leaks.json +1 -0
- package/dist/data/baked/memory_check.json +1 -0
- package/dist/data/baked/memory_derive.json +1 -0
- package/dist/data/baked/metrics_face.json +1 -0
- package/dist/data/baked/package_gates.json +1 -0
- package/dist/data/baked/prefix_check.json +1 -0
- package/dist/data/baked/prose_check.json +1 -0
- package/dist/data/baked/qpu_court_local.json +1 -0
- package/dist/data/baked/qpu_families.json +1 -0
- package/dist/data/baked/recompute.json +1 -0
- package/dist/data/baked/session_report.json +1 -0
- package/dist/data/baked/theorem_only.json +1 -0
- package/dist/data/baked/trinity.json +1 -0
- package/dist/data/discovered.json +480 -0
- package/dist/data/formulas.jsonld +27809 -25985
- package/dist/mcp.bin.js +18 -1
- package/dist/src/0/index.d.ts +1 -0
- package/dist/src/0/index.js +7 -8
- package/dist/src/factor/index.d.ts +58 -0
- package/dist/src/factor/index.js +209 -0
- package/dist/src/factor/verify.d.ts +18 -0
- package/dist/src/factor/verify.js +28 -0
- package/dist/src/mcp/index.d.ts +3602 -110
- package/dist/src/mcp/index.js +141 -4
- package/dist/src/mcp/serve.d.ts +12 -2
- package/dist/src/mcp/serve.js +71 -6
- package/dist/src/mcp/suites.d.ts +1 -0
- package/dist/src/mcp/suites.js +14 -0
- package/dist/src/mirror/index.d.ts +18 -0
- package/dist/src/mirror/index.js +37 -0
- package/dist/src/policy/index.d.ts +8 -0
- package/dist/src/policy/index.js +23 -0
- package/package.json +19 -4
package/dist/mcp.bin.js
CHANGED
|
@@ -3,7 +3,7 @@ import { createInterface } from 'node:readline';
|
|
|
3
3
|
import { readFileSync, existsSync } from 'node:fs';
|
|
4
4
|
import { fileURLToPath } from 'node:url';
|
|
5
5
|
import { dirname, join } from 'node:path';
|
|
6
|
-
import { run, served, withLedger, withFormulas } from './src/mcp/serve.js';
|
|
6
|
+
import { run, served, withLedger, withFormulas, withBake } from './src/mcp/serve.js';
|
|
7
7
|
const here = dirname(fileURLToPath(import.meta.url));
|
|
8
8
|
for (const p of [join(here, 'data', 'discovered.json'), join(here, '..', 'src', 'proof', 'discovered.json')]) {
|
|
9
9
|
if (!existsSync(p))
|
|
@@ -30,6 +30,23 @@ for (const p of [join(here, 'data', 'formulas.jsonld'), join(here, '..', 'public
|
|
|
30
30
|
}
|
|
31
31
|
catch { }
|
|
32
32
|
}
|
|
33
|
+
for (const dir of [join(here, 'data', 'baked')]) {
|
|
34
|
+
const idx = join(dir, 'index.json');
|
|
35
|
+
if (!existsSync(idx))
|
|
36
|
+
continue;
|
|
37
|
+
try {
|
|
38
|
+
const j = JSON.parse(readFileSync(idx, 'utf8'));
|
|
39
|
+
const answers = {};
|
|
40
|
+
for (const n of j.baked) {
|
|
41
|
+
const p = join(dir, n + '.json');
|
|
42
|
+
if (existsSync(p))
|
|
43
|
+
answers[n] = JSON.parse(readFileSync(p, 'utf8')).answer;
|
|
44
|
+
}
|
|
45
|
+
withBake({ stamp: j.stamp, answers, notBaked: j.notBaked });
|
|
46
|
+
break;
|
|
47
|
+
}
|
|
48
|
+
catch { }
|
|
49
|
+
}
|
|
33
50
|
const send = (m) => process.stdout.write(JSON.stringify(m) + '\n');
|
|
34
51
|
const rl = createInterface({ input: process.stdin });
|
|
35
52
|
rl.on('line', (line) => {
|
package/dist/src/0/index.d.ts
CHANGED
package/dist/src/0/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
const BYTE_MASK = 0xff;
|
|
2
|
-
const MASK_32 = 0xffffffffn;
|
|
3
2
|
function mul32(a, b) {
|
|
4
|
-
|
|
3
|
+
const al = a & 0xffff, ah = a >>> 16, bl = b & 0xffff, bh = b >>> 16;
|
|
4
|
+
return (al * bl + ((ah * bl + al * bh) & 0xffff) * 0x10000) >>> 0;
|
|
5
5
|
}
|
|
6
6
|
function hash32(input, seed) {
|
|
7
7
|
let h = (0x811c9dc5 ^ seed) >>> 0;
|
|
@@ -18,13 +18,9 @@ const HEX_BYTE = Array.from({ length: 256 }, (_, i) => i.toString(16).padStart(2
|
|
|
18
18
|
function hexByte(value) {
|
|
19
19
|
return HEX_BYTE[value & BYTE_MASK];
|
|
20
20
|
}
|
|
21
|
+
export const SEEDS = [0, 0x9e3779b9, 0x243f6a88, 0xb7e15162];
|
|
21
22
|
function bytesFromSeed(seed) {
|
|
22
|
-
const words =
|
|
23
|
-
hash32(seed, 0),
|
|
24
|
-
hash32(seed, 0x9e3779b9),
|
|
25
|
-
hash32(seed, 0x243f6a88),
|
|
26
|
-
hash32(seed, 0xb7e15162),
|
|
27
|
-
];
|
|
23
|
+
const words = SEEDS.map((s) => hash32(seed, s));
|
|
28
24
|
return words.flatMap((word) => [
|
|
29
25
|
(word >>> (8 * 3)) & BYTE_MASK,
|
|
30
26
|
(word >>> 16) & BYTE_MASK,
|
|
@@ -33,10 +29,13 @@ function bytesFromSeed(seed) {
|
|
|
33
29
|
]);
|
|
34
30
|
}
|
|
35
31
|
const _uuidCache = new Map();
|
|
32
|
+
const CACHE_LIMIT = 1 << 14;
|
|
36
33
|
export function toUuid(seed) {
|
|
37
34
|
const cached = _uuidCache.get(seed);
|
|
38
35
|
if (cached !== undefined)
|
|
39
36
|
return cached;
|
|
37
|
+
if (_uuidCache.size >= CACHE_LIMIT)
|
|
38
|
+
_uuidCache.clear();
|
|
40
39
|
const bytes = bytesFromSeed(seed);
|
|
41
40
|
bytes[6] = (bytes[6] & 0x0f) | 0x80;
|
|
42
41
|
bytes[8] = (bytes[8] & 0x3f) | 0x80;
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
export declare const TRIAL_BOUND = 1000000n;
|
|
2
|
+
export declare const RHO_BUDGET = 500000;
|
|
3
|
+
export type Factorisation = {
|
|
4
|
+
status: 'FACTORED';
|
|
5
|
+
factors: string[];
|
|
6
|
+
primality: 'every factor proved prime by trial division or by the deterministic test';
|
|
7
|
+
} | {
|
|
8
|
+
status: 'PARTIAL';
|
|
9
|
+
factors: string[];
|
|
10
|
+
cofactor: string;
|
|
11
|
+
cofactorDigits: number;
|
|
12
|
+
cofactorPrimality: 'probable prime by Miller–Rabin, not proved' | 'composite (a witness was found)' | 'composite (split into open pieces, each above the trial bound)';
|
|
13
|
+
blocking: string;
|
|
14
|
+
} | {
|
|
15
|
+
status: 'REFUSED';
|
|
16
|
+
why: string;
|
|
17
|
+
};
|
|
18
|
+
export declare const millerRabin: (n: bigint) => 'PRIME' | 'COMPOSITE';
|
|
19
|
+
export declare const parseInteger: (input: string) => string | null;
|
|
20
|
+
export declare const factor: (input: string) => Factorisation;
|
|
21
|
+
export declare const rho: (n: bigint, budget?: number) => bigint | null;
|
|
22
|
+
export declare const RAYS: readonly number[];
|
|
23
|
+
export declare const renderDigits: (n: bigint, k: number) => number[];
|
|
24
|
+
export declare const parseDigits: (ds: readonly number[], k: number) => bigint;
|
|
25
|
+
export declare const mirrorDigits: (digits: string) => string | null;
|
|
26
|
+
export type WitnessState = {
|
|
27
|
+
coin: 'integer' | 'mirror';
|
|
28
|
+
ray: number;
|
|
29
|
+
radix: number;
|
|
30
|
+
digits: number;
|
|
31
|
+
roundTrip: boolean;
|
|
32
|
+
};
|
|
33
|
+
export type Witness = {
|
|
34
|
+
register: {
|
|
35
|
+
coins: 2;
|
|
36
|
+
rays: 7;
|
|
37
|
+
faces: 14;
|
|
38
|
+
source: 'qpu.lean — the served register, faces = coins × rays';
|
|
39
|
+
};
|
|
40
|
+
coins: {
|
|
41
|
+
integer: Factorisation & {
|
|
42
|
+
n: string;
|
|
43
|
+
};
|
|
44
|
+
mirror: (Factorisation & {
|
|
45
|
+
n: string;
|
|
46
|
+
}) | {
|
|
47
|
+
status: 'UNDEFINED';
|
|
48
|
+
why: string;
|
|
49
|
+
};
|
|
50
|
+
};
|
|
51
|
+
states: WitnessState[];
|
|
52
|
+
agree: boolean;
|
|
53
|
+
failures: string[];
|
|
54
|
+
};
|
|
55
|
+
export declare const factorWitnessed: (input: string) => (Factorisation & {
|
|
56
|
+
n?: string;
|
|
57
|
+
witness?: Witness;
|
|
58
|
+
});
|
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
export const TRIAL_BOUND = 1000000n;
|
|
2
|
+
export const RHO_BUDGET = 500_000;
|
|
3
|
+
const DETERMINISTIC_LIMIT = 3317044064679887385961981n;
|
|
4
|
+
const modPow = (base, exp, mod) => {
|
|
5
|
+
let result = 1n;
|
|
6
|
+
let b = base % mod;
|
|
7
|
+
let e = exp;
|
|
8
|
+
while (e > 0n) {
|
|
9
|
+
if (e & 1n)
|
|
10
|
+
result = (result * b) % mod;
|
|
11
|
+
b = (b * b) % mod;
|
|
12
|
+
e >>= 1n;
|
|
13
|
+
}
|
|
14
|
+
return result;
|
|
15
|
+
};
|
|
16
|
+
const BASES = [2n, 3n, 5n, 7n, 11n, 13n, 17n, 19n, 23n, 29n, 31n, 37n];
|
|
17
|
+
export const millerRabin = (n) => {
|
|
18
|
+
if (n < 2n)
|
|
19
|
+
return 'COMPOSITE';
|
|
20
|
+
for (const p of BASES) {
|
|
21
|
+
if (n === p)
|
|
22
|
+
return 'PRIME';
|
|
23
|
+
if (n % p === 0n)
|
|
24
|
+
return 'COMPOSITE';
|
|
25
|
+
}
|
|
26
|
+
let d = n - 1n;
|
|
27
|
+
let r = 0;
|
|
28
|
+
while ((d & 1n) === 0n) {
|
|
29
|
+
d >>= 1n;
|
|
30
|
+
r++;
|
|
31
|
+
}
|
|
32
|
+
for (const a of BASES) {
|
|
33
|
+
let x = modPow(a, d, n);
|
|
34
|
+
if (x === 1n || x === n - 1n)
|
|
35
|
+
continue;
|
|
36
|
+
let composite = true;
|
|
37
|
+
for (let i = 1; i < r; i++) {
|
|
38
|
+
x = (x * x) % n;
|
|
39
|
+
if (x === n - 1n) {
|
|
40
|
+
composite = false;
|
|
41
|
+
break;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
if (composite)
|
|
45
|
+
return 'COMPOSITE';
|
|
46
|
+
}
|
|
47
|
+
return 'PRIME';
|
|
48
|
+
};
|
|
49
|
+
export const parseInteger = (input) => {
|
|
50
|
+
const t = input.trim().replace(/_/g, '');
|
|
51
|
+
if (/^0b[01]+$/i.test(t))
|
|
52
|
+
return BigInt(t).toString();
|
|
53
|
+
if (/^0x[0-9a-f]+$/i.test(t))
|
|
54
|
+
return BigInt(t).toString();
|
|
55
|
+
if (/^\d+$/.test(t))
|
|
56
|
+
return t;
|
|
57
|
+
return null;
|
|
58
|
+
};
|
|
59
|
+
export const factor = (input) => {
|
|
60
|
+
const digits = parseInteger(input);
|
|
61
|
+
if (digits === null)
|
|
62
|
+
return { status: 'REFUSED', why: 'the input is not a non-negative integer in decimal, 0b binary or 0x hex' };
|
|
63
|
+
let n = BigInt(digits);
|
|
64
|
+
if (n < 2n)
|
|
65
|
+
return { status: 'REFUSED', why: `${n} has no factorisation to give` };
|
|
66
|
+
const found = [];
|
|
67
|
+
const divide = (d) => { while (n % d === 0n) {
|
|
68
|
+
found.push(d.toString());
|
|
69
|
+
n /= d;
|
|
70
|
+
} };
|
|
71
|
+
divide(2n);
|
|
72
|
+
let d = 3n;
|
|
73
|
+
for (; d <= TRIAL_BOUND && d * d <= n; d += 2n)
|
|
74
|
+
divide(d);
|
|
75
|
+
if (n === 1n)
|
|
76
|
+
return { status: 'FACTORED', factors: found, primality: 'every factor proved prime by trial division or by the deterministic test' };
|
|
77
|
+
if (d * d > n)
|
|
78
|
+
return { status: 'FACTORED', factors: [...found, n.toString()], primality: 'every factor proved prime by trial division or by the deterministic test' };
|
|
79
|
+
const primes = [];
|
|
80
|
+
const open = [];
|
|
81
|
+
splitWithRho(n, primes, open);
|
|
82
|
+
const all = [...found, ...primes.map((p) => p.toString())];
|
|
83
|
+
if (open.length === 0)
|
|
84
|
+
return { status: 'FACTORED', factors: all, primality: 'every factor proved prime by trial division or by the deterministic test' };
|
|
85
|
+
const cofactor = open.reduce((acc, v) => acc * v, 1n);
|
|
86
|
+
const cofactorPrimality = open.length > 1
|
|
87
|
+
? 'composite (split into open pieces, each above the trial bound)'
|
|
88
|
+
: millerRabin(cofactor) === 'COMPOSITE' ? 'composite (a witness was found)' : 'probable prime by Miller–Rabin, not proved';
|
|
89
|
+
return { status: 'PARTIAL', factors: all, cofactor: cofactor.toString(), cofactorDigits: cofactor.toString().length, cofactorPrimality,
|
|
90
|
+
blocking: `the cofactor has no factor below ${TRIAL_BOUND} and Pollard rho did not split it within ${RHO_BUDGET} steps; no method in this tree factors it` };
|
|
91
|
+
};
|
|
92
|
+
export const rho = (n, budget = RHO_BUDGET) => {
|
|
93
|
+
if (n % 2n === 0n)
|
|
94
|
+
return 2n;
|
|
95
|
+
const gcd = (a, b) => { while (b) {
|
|
96
|
+
[a, b] = [b, a % b];
|
|
97
|
+
} return a; };
|
|
98
|
+
const diff = (a, b) => (a > b ? a - b : b - a);
|
|
99
|
+
let steps = 0;
|
|
100
|
+
for (let c = 1n; c < 20n; c++) {
|
|
101
|
+
const f = (v) => (v * v + c) % n;
|
|
102
|
+
let y = 2n, x = y, ys = y, g = 1n, q = 1n, r = 1;
|
|
103
|
+
const m = 128;
|
|
104
|
+
while (g === 1n) {
|
|
105
|
+
x = y;
|
|
106
|
+
for (let i = 0; i < r; i++)
|
|
107
|
+
y = f(y);
|
|
108
|
+
let k = 0;
|
|
109
|
+
while (k < r && g === 1n) {
|
|
110
|
+
ys = y;
|
|
111
|
+
for (let i = 0; i < Math.min(m, r - k); i++) {
|
|
112
|
+
y = f(y);
|
|
113
|
+
q = (q * diff(x, y)) % n;
|
|
114
|
+
}
|
|
115
|
+
g = gcd(q, n);
|
|
116
|
+
k += m;
|
|
117
|
+
}
|
|
118
|
+
steps += r;
|
|
119
|
+
r *= 2;
|
|
120
|
+
if (steps > budget)
|
|
121
|
+
return null;
|
|
122
|
+
}
|
|
123
|
+
if (g === n) {
|
|
124
|
+
g = 1n;
|
|
125
|
+
while (g === 1n) {
|
|
126
|
+
ys = f(ys);
|
|
127
|
+
g = gcd(diff(x, ys), n);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
if (g !== n)
|
|
131
|
+
return g;
|
|
132
|
+
}
|
|
133
|
+
return null;
|
|
134
|
+
};
|
|
135
|
+
const splitWithRho = (m, primes, open) => {
|
|
136
|
+
if (m === 1n)
|
|
137
|
+
return;
|
|
138
|
+
const verdict = millerRabin(m);
|
|
139
|
+
if (m < DETERMINISTIC_LIMIT && verdict === 'PRIME') {
|
|
140
|
+
primes.push(m);
|
|
141
|
+
return;
|
|
142
|
+
}
|
|
143
|
+
const d = verdict === 'COMPOSITE' || m >= DETERMINISTIC_LIMIT ? rho(m) : null;
|
|
144
|
+
if (d === null || d === 1n || d === m) {
|
|
145
|
+
open.push(m);
|
|
146
|
+
return;
|
|
147
|
+
}
|
|
148
|
+
splitWithRho(d, primes, open);
|
|
149
|
+
splitWithRho(m / d, primes, open);
|
|
150
|
+
};
|
|
151
|
+
export const RAYS = [1, 2, 3, 4, 5, 6, 7];
|
|
152
|
+
const GLYPHS = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ-_abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
|
|
153
|
+
export const renderDigits = (n, k) => {
|
|
154
|
+
const b = 1n << BigInt(k), out = [];
|
|
155
|
+
let m = n;
|
|
156
|
+
if (m === 0n)
|
|
157
|
+
return [0];
|
|
158
|
+
while (m > 0n) {
|
|
159
|
+
out.unshift(Number(m % b));
|
|
160
|
+
m /= b;
|
|
161
|
+
}
|
|
162
|
+
return out;
|
|
163
|
+
};
|
|
164
|
+
export const parseDigits = (ds, k) => ds.reduce((acc, d) => (acc << BigInt(k)) + BigInt(d), 0n);
|
|
165
|
+
export const mirrorDigits = (digits) => /0/.test(digits) ? null : digits.split('').map((c) => String(10 - Number(c))).join('');
|
|
166
|
+
export const factorWitnessed = (input) => {
|
|
167
|
+
const digits = parseInteger(input);
|
|
168
|
+
const base = factor(input);
|
|
169
|
+
if (digits === null || base.status === 'REFUSED')
|
|
170
|
+
return base;
|
|
171
|
+
const n = BigInt(digits);
|
|
172
|
+
const m = mirrorDigits(digits);
|
|
173
|
+
const states = [];
|
|
174
|
+
const failures = [];
|
|
175
|
+
const coinsOf = m === null ? [['integer', n]] : [['integer', n], ['mirror', BigInt(m)]];
|
|
176
|
+
for (const [coin, v] of coinsOf)
|
|
177
|
+
for (const k of RAYS) {
|
|
178
|
+
const ds = renderDigits(v, k);
|
|
179
|
+
const ok = parseDigits(ds, k) === v && ds.every((d) => d >= 0 && d < (1 << k));
|
|
180
|
+
states.push({ coin, ray: k, radix: 1 << k, digits: ds.length, roundTrip: ok });
|
|
181
|
+
if (!ok)
|
|
182
|
+
failures.push(`${coin} does not survive radix ${1 << k}`);
|
|
183
|
+
}
|
|
184
|
+
const check = (label, r, v) => {
|
|
185
|
+
if (r.status === 'FACTORED') {
|
|
186
|
+
const prod = r.factors.reduce((acc, x) => acc * BigInt(x), 1n);
|
|
187
|
+
if (prod.toString() !== v)
|
|
188
|
+
failures.push(`${label}: the factors do not multiply back`);
|
|
189
|
+
}
|
|
190
|
+
else if (r.status === 'PARTIAL')
|
|
191
|
+
failures.push(`${label}: ${r.cofactorDigits}-digit cofactor left open — ${r.cofactorPrimality}`);
|
|
192
|
+
else
|
|
193
|
+
failures.push(`${label}: ${r.why}`);
|
|
194
|
+
};
|
|
195
|
+
check('integer', base, digits);
|
|
196
|
+
const mirrorFact = m === null
|
|
197
|
+
? { status: 'UNDEFINED', why: 'a digit is 0, and 10 − 0 is not a digit: the mirror coin is undefined, which is stated rather than counted' }
|
|
198
|
+
: { n: m, ...factor(m) };
|
|
199
|
+
if (mirrorFact.status !== 'UNDEFINED')
|
|
200
|
+
check('mirror', mirrorFact, m);
|
|
201
|
+
return {
|
|
202
|
+
...base, n: digits,
|
|
203
|
+
witness: {
|
|
204
|
+
register: { coins: 2, rays: 7, faces: 14, source: 'qpu.lean — the served register, faces = coins × rays' },
|
|
205
|
+
coins: { integer: { n: digits, ...base }, mirror: mirrorFact },
|
|
206
|
+
states, agree: failures.length === 0, failures,
|
|
207
|
+
},
|
|
208
|
+
};
|
|
209
|
+
};
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export type Verification = {
|
|
2
|
+
status: 'VERIFIED';
|
|
3
|
+
n: string;
|
|
4
|
+
factors: string[];
|
|
5
|
+
primality: string;
|
|
6
|
+
why: string;
|
|
7
|
+
} | {
|
|
8
|
+
status: 'PROBABLE';
|
|
9
|
+
n: string;
|
|
10
|
+
factors: string[];
|
|
11
|
+
primality: string;
|
|
12
|
+
why: string;
|
|
13
|
+
} | {
|
|
14
|
+
status: 'REFUSED';
|
|
15
|
+
n: string;
|
|
16
|
+
why: string;
|
|
17
|
+
};
|
|
18
|
+
export declare const verifyFactors: (nIn: string, factorsIn: string[]) => Verification;
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { millerRabin, parseInteger } from './index.js';
|
|
2
|
+
const DETERMINISTIC_LIMIT = 3317044064679887385961981n;
|
|
3
|
+
export const verifyFactors = (nIn, factorsIn) => {
|
|
4
|
+
const n = parseInteger(nIn) ?? nIn;
|
|
5
|
+
if (!/^\d+$/.test(n))
|
|
6
|
+
return { status: 'REFUSED', n, why: 'the integer is not a non-negative integer in decimal, 0b binary or 0x hex' };
|
|
7
|
+
if (factorsIn.length === 0)
|
|
8
|
+
return { status: 'REFUSED', n, why: 'no factors were given' };
|
|
9
|
+
const factors = factorsIn.map((f) => parseInteger(f) ?? f);
|
|
10
|
+
if (!factors.every((f) => /^\d+$/.test(f)))
|
|
11
|
+
return { status: 'REFUSED', n, why: 'a factor is not a non-negative integer in decimal, 0b binary or 0x hex' };
|
|
12
|
+
const values = factors.map((f) => BigInt(f));
|
|
13
|
+
if (values.some((v) => v < 2n))
|
|
14
|
+
return { status: 'REFUSED', n, why: 'a factor is below 2, which proves nothing about a factorisation' };
|
|
15
|
+
const product = values.reduce((acc, v) => acc * v, 1n);
|
|
16
|
+
if (product !== BigInt(n))
|
|
17
|
+
return { status: 'REFUSED', n, why: 'the factors do not multiply to the integer' };
|
|
18
|
+
const unproved = values.filter((v) => v >= DETERMINISTIC_LIMIT);
|
|
19
|
+
const bad = values.filter((v) => millerRabin(v) === 'COMPOSITE');
|
|
20
|
+
if (bad.length)
|
|
21
|
+
return { status: 'REFUSED', n, why: `${bad.length} factor(s) are composite, by a witness the test found, so they are not prime factors` };
|
|
22
|
+
const primality = unproved.length === 0
|
|
23
|
+
? 'every factor proved prime by the deterministic test'
|
|
24
|
+
: `${values.length - unproved.length} factor(s) proved prime; ${unproved.length} factor(s) above 3.3e24 only probably prime`;
|
|
25
|
+
if (unproved.length === 0)
|
|
26
|
+
return { status: 'VERIFIED', n, factors, primality, why: 'the product holds and every factor is proved prime' };
|
|
27
|
+
return { status: 'PROBABLE', n, factors, primality, why: 'the product holds; some factor passed a probabilistic test, which is not a proof' };
|
|
28
|
+
};
|