functionalscript 0.28.0 → 0.29.1

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.
@@ -16,7 +16,7 @@ const installBun = installOnWindowsArm({
16
16
  });
17
17
  export const bunSteps = (extra) => (v, a) => clean([
18
18
  installBun(v)(a),
19
- test({ run: 'bun install' }),
19
+ test({ run: 'bun install --frozen-lockfile' }),
20
20
  test({ run: 'bun test --timeout 20000' }),
21
21
  ...extra,
22
22
  ]);
@@ -34,10 +34,11 @@ export const nodeVersions = Object.fromEntries(node.others.map(v => [
34
34
  `node${major(v)}`,
35
35
  ubuntu(nodeSteps(v))
36
36
  ]));
37
+ const tsgoName = `@typescript/native-preview@${tsgo}`;
37
38
  export const nodeMainSteps = (extra) => nodeTests(node.default)([
38
39
  // TypeScript Preview
39
- install({ run: `npm install -g @typescript/native-preview@${tsgo}` }),
40
- test({ run: 'tsgo' }),
40
+ install({ run: `npm cache add ${tsgoName}` }),
41
+ test({ run: `npx npm:${tsgoName}` }),
41
42
  // extra
42
43
  ...extra,
43
44
  ]);
@@ -130,6 +130,8 @@ const runModule = ({ result, test }) => (k, v) => (ts) => {
130
130
  .step(delta => pure(mergeState(ts, delta)));
131
131
  };
132
132
  const { entries } = Object;
133
+ const proofEntries = (moduleMap) => entries(moduleMap)
134
+ .flatMap(([k, v]) => v.proof !== undefined ? [[k, v.proof]] : []);
133
135
  /**
134
136
  * Runs all test modules in `moduleMap` whose names pass `isTest`, accumulates
135
137
  * pass/fail/time via `reporter`, and returns an exit code (0 = all passed,
@@ -137,8 +139,7 @@ const { entries } = Object;
137
139
  */
138
140
  export const runModuleMap = (reporter) => (moduleMap) => {
139
141
  const { summary } = reporter;
140
- const modules = entries(moduleMap)
141
- .flatMap(([k, v]) => v.proof !== undefined ? [[k, v.proof]] : []);
142
+ const modules = proofEntries(moduleMap);
142
143
  return all(...modules.map(([k, v]) => runModule(reporter)(k, v)(zero)))
143
144
  .step(m => pure(m.reduce(mergeState, zero)))
144
145
  .step(ts => summary(ts.pass, ts.fail, ts.time)
@@ -155,8 +156,7 @@ export const testAll = (reporter) => options => loadModuleMap(options.env).step(
155
156
  * `ctx`. Delegates to `registerModule` for each matching entry.
156
157
  */
157
158
  const registerModuleMap = (ctx, star) => (moduleMap) => {
158
- const modules = entries(moduleMap)
159
- .flatMap(([k, v]) => v.proof !== undefined ? [[k, v.proof]] : []);
159
+ const modules = proofEntries(moduleMap);
160
160
  if (modules.length === 0) {
161
161
  return pure(undefined);
162
162
  }
@@ -1,3 +1,4 @@
1
1
  export declare const proof: {
2
2
  range: () => void;
3
+ oneThrowsOnEmpty: () => void;
3
4
  };
@@ -1,4 +1,4 @@
1
- import { range } from "./module.f.js";
1
+ import { one, range } from "./module.f.js";
2
2
  import { stringify as jsonStringify } from "../../json/module.f.js";
3
3
  import { sort } from "../../types/object/module.f.js";
4
4
  const stringify = jsonStringify(sort);
@@ -8,5 +8,17 @@ export const proof = {
8
8
  if (r !== '[65,65]') {
9
9
  throw r;
10
10
  }
11
- }
11
+ },
12
+ oneThrowsOnEmpty: () => {
13
+ let threw = false;
14
+ try {
15
+ one('');
16
+ }
17
+ catch (_) {
18
+ threw = true;
19
+ }
20
+ if (!threw) {
21
+ throw 'expected throw';
22
+ }
23
+ },
12
24
  };
@@ -26,7 +26,13 @@ export type PrimeField = {
26
26
  readonly pow3: Unary;
27
27
  /** Reduces an arbitrary `bigint` into `[0, p)`. */
28
28
  readonly reduce: Unary;
29
- /** Euler criterion: `true` when `x` is a quadratic residue mod `p`. */
29
+ /**
30
+ * `true` when `x` is a square modulo `p`, including `0`.
31
+ *
32
+ * Nonzero values are tested with Euler's criterion:
33
+ * `x^((p - 1) / 2) === 1 (mod p)`.
34
+ * For `p === 2n`, both field elements are squares.
35
+ */
30
36
  readonly quadRes: (x: bigint) => boolean;
31
37
  };
32
38
  /**
@@ -42,12 +42,19 @@ export const prime_field = (p) => {
42
42
  const r = x % p;
43
43
  return r < 0n ? add(p)(r) : r;
44
44
  };
45
- const half = (p - 1n) / 2n;
46
- const quadRes = (x) => pow(half)(reduce(x)) === 1n;
45
+ const max = p - 1n;
46
+ // Euler's exponent is `(p - 1) / 2`; use `max`, not `p`, so `p === 2n`
47
+ // gives exponent `0n` instead of `1n`.
48
+ // 0 is a square mod p; Euler's criterion needs a separate case because 0^e = 0.
49
+ const powHalf = pow(max >> 1n);
50
+ const quadRes = (x) => {
51
+ const v = reduce(x);
52
+ return v === 0n || powHalf(v) === 1n;
53
+ };
47
54
  return {
48
55
  p,
49
56
  middle,
50
- max: p - 1n,
57
+ max,
51
58
  neg: a => a === 0n ? 0n : p - a,
52
59
  sub,
53
60
  add,
@@ -153,12 +153,25 @@ export const proof = {
153
153
  }
154
154
  },
155
155
  quadRes: () => {
156
+ if (!f.quadRes(0n)) {
157
+ throw 0n;
158
+ }
156
159
  if (!f.quadRes(1n)) {
157
160
  throw 1n;
158
161
  }
162
+ if (!f.quadRes(p)) {
163
+ throw p;
164
+ }
159
165
  if (f.quadRes(3n)) {
160
166
  throw 3n;
161
167
  }
168
+ const f2 = prime_field(2n);
169
+ if (!f2.quadRes(0n)) {
170
+ throw '0 mod 2';
171
+ }
172
+ if (!f2.quadRes(1n)) {
173
+ throw '1 mod 2';
174
+ }
162
175
  },
163
176
  modSqrt: () => {
164
177
  const root = modSqrt(f);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "functionalscript",
3
- "version": "0.28.0",
3
+ "version": "0.29.1",
4
4
  "type": "module",
5
5
  "files": [
6
6
  "**/*.js",
@@ -13,12 +13,12 @@
13
13
  "cov": "node --test --experimental-test-coverage --test-coverage-include=**/module.f.ts",
14
14
  "start": "node ./fs/fjs/module.ts",
15
15
  "ci-update": "node ./fs/fjs/module.ts ci",
16
- "update": "npx npm-check-updates -u && npm install && deno install && npm run ci-update",
16
+ "update": "npx npm-check-updates -u && npm install && deno install && bun install && npm run ci-update",
17
17
  "index-html": "node ./fs/fjs/module.ts r ./fs/website/module.f.ts",
18
- "website": "npm run prepack &&npm run index-html"
18
+ "website": "npm run prepack && npm run index-html"
19
19
  },
20
20
  "engines": {
21
- "node": ">=24"
21
+ "node": ">=22"
22
22
  },
23
23
  "bin": {
24
24
  "fjs": "fs/fjs/module.js"