@totemsdk/txpow 1.0.2 → 1.1.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.
Files changed (61) hide show
  1. package/LICENSE +202 -21
  2. package/NOTICE +60 -0
  3. package/dist/admission/challenge.js +14 -21
  4. package/dist/admission/commitment.js +9 -13
  5. package/dist/admission/index.js +6 -34
  6. package/dist/admission/mine.js +14 -17
  7. package/dist/admission/template.js +32 -47
  8. package/dist/admission/types.js +2 -5
  9. package/dist/admission/verify.js +12 -15
  10. package/dist/calibrate.js +4 -8
  11. package/dist/cjs/admission/challenge.d.ts +66 -0
  12. package/dist/cjs/admission/challenge.js +155 -0
  13. package/dist/cjs/admission/commitment.d.ts +34 -0
  14. package/dist/cjs/admission/commitment.js +73 -0
  15. package/dist/cjs/admission/index.d.ts +14 -0
  16. package/dist/cjs/admission/index.js +42 -0
  17. package/dist/cjs/admission/mine.d.ts +60 -0
  18. package/dist/cjs/admission/mine.js +146 -0
  19. package/dist/cjs/admission/template.d.ts +138 -0
  20. package/dist/cjs/admission/template.js +247 -0
  21. package/dist/cjs/admission/types.d.ts +224 -0
  22. package/dist/cjs/admission/types.js +24 -0
  23. package/dist/cjs/admission/verify.d.ts +50 -0
  24. package/dist/cjs/admission/verify.js +156 -0
  25. package/dist/cjs/calibrate.d.ts +35 -0
  26. package/dist/cjs/calibrate.js +68 -0
  27. package/dist/cjs/constants.d.ts +27 -0
  28. package/dist/cjs/constants.js +47 -0
  29. package/dist/cjs/difficulty.d.ts +44 -0
  30. package/dist/cjs/difficulty.js +111 -0
  31. package/dist/cjs/index.d.ts +28 -0
  32. package/dist/cjs/index.js +88 -0
  33. package/dist/cjs/magic.d.ts +19 -0
  34. package/dist/cjs/magic.js +35 -0
  35. package/dist/cjs/mine-wasm.d.ts +69 -0
  36. package/dist/cjs/mine-wasm.js +214 -0
  37. package/dist/cjs/mine.d.ts +131 -0
  38. package/dist/cjs/mine.js +407 -0
  39. package/dist/cjs/package.json +1 -0
  40. package/dist/cjs/serialization.d.ts +106 -0
  41. package/dist/cjs/serialization.js +160 -0
  42. package/dist/cjs/verify.d.ts +76 -0
  43. package/dist/cjs/verify.js +232 -0
  44. package/dist/cjs/wasm/miner.wasm +0 -0
  45. package/dist/cjs/workers/browser.worker.d.ts +26 -0
  46. package/dist/cjs/workers/browser.worker.js +63 -0
  47. package/dist/cjs/workers/node.worker.d.ts +33 -0
  48. package/dist/cjs/workers/node.worker.js +47 -0
  49. package/dist/constants.js +5 -8
  50. package/dist/difficulty.d.ts +24 -0
  51. package/dist/difficulty.js +54 -6
  52. package/dist/index.d.ts +1 -1
  53. package/dist/index.js +9 -62
  54. package/dist/magic.js +12 -15
  55. package/dist/mine-wasm.js +8 -15
  56. package/dist/mine.js +23 -31
  57. package/dist/serialization.js +28 -34
  58. package/dist/verify.js +15 -20
  59. package/dist/workers/browser.worker.js +4 -6
  60. package/dist/workers/node.worker.js +2 -3
  61. package/package.json +34 -15
@@ -0,0 +1,224 @@
1
+ /**
2
+ * admission/types.ts — Machine Work Admission core types.
3
+ *
4
+ * Machine Work Admission lets a receiver require a sender to perform bounded
5
+ * computational work before scarce machine resources are allocated. The work
6
+ * searches the nonce space of a real current Minima block candidate, so the
7
+ * same hashes that admit the machine action also search for Minima L1 blocks.
8
+ *
9
+ * The three distinct concepts:
10
+ * - WorkChallenge — the receiver-controlled admission requirement
11
+ * - MachineWorkAction — the domain-separated application action commitment
12
+ * - MachineWorkAdmissionProof — the mined result
13
+ *
14
+ * The TxPoW package knows only "there is an application action represented by
15
+ * canonical bytes". It does NOT know about negotiation, compute, storage, or
16
+ * any particular Edge resource. Domain-specific packages supply the action.
17
+ */
18
+ /** Current Machine Work Admission protocol version. */
19
+ export declare const MACHINE_WORK_ADMISSION_VERSION = 1;
20
+ /** Canonical protocol domain prefix for the commitment hash. */
21
+ export declare const MACHINE_WORK_DOMAIN = "totem.machine-work-admission";
22
+ /**
23
+ * The receiver controls the admission requirement.
24
+ *
25
+ * A challenge must be unique enough to prevent useful pre-mining, must expire,
26
+ * must bind to the intended receiver, and must bind to an application domain.
27
+ * `target` is an absolute cryptographic target: verification is `hash < target`.
28
+ */
29
+ export interface WorkChallenge {
30
+ /** Protocol version. */
31
+ version: number;
32
+ /** Unique challenge identifier (receiver-generated, prevents pre-mining). */
33
+ challengeId: string;
34
+ /** The intended receiver this challenge is bound to. */
35
+ recipient: string;
36
+ /** Application domain (e.g. "totem.negotiation.proposal"). Open-ended. */
37
+ domain: string;
38
+ /** Absolute 32-byte cryptographic target (big-endian 256-bit). */
39
+ target: string;
40
+ /** Receiver-generated random nonce to prevent pre-mining. */
41
+ nonce: string;
42
+ /** Epoch milliseconds when the challenge was issued. */
43
+ issuedAt: number;
44
+ /** Epoch milliseconds after which the challenge is invalid. */
45
+ expiresAt: number;
46
+ /** Optional network identifier (e.g. "mainnet", "testnet"). */
47
+ network?: string;
48
+ }
49
+ /**
50
+ * The application action, represented in a generic domain-separated form.
51
+ *
52
+ * Only a commitment to this action enters the TxPoW header — never the
53
+ * application payload itself. The application remains off-chain.
54
+ */
55
+ export interface MachineWorkAction {
56
+ /** Protocol version. */
57
+ version: number;
58
+ /** Application domain (e.g. "totem.compute.reserve"). Open-ended. */
59
+ domain: string;
60
+ /** The sender performing the work. */
61
+ sender: string;
62
+ /** The intended recipient. */
63
+ recipient: string;
64
+ /** Unique action identifier. */
65
+ actionId: string;
66
+ /** SHA3-256 hex commitment to the application payload (off-chain). */
67
+ payloadHash: string;
68
+ /** Optional domain-specific context (canonicalized into the commitment). */
69
+ context?: Record<string, string>;
70
+ }
71
+ /**
72
+ * A Minima block-candidate work template.
73
+ *
74
+ * This is the chain state a candidate is mined against. It is structurally
75
+ * capable of becoming a legitimate Minima block: block number, block
76
+ * difficulty, super-parents, MMR root/total, magic, and time are all taken
77
+ * from the current chain tip (see TxPoWGenerator.generateTxPoW in Minima).
78
+ */
79
+ export interface MinimaWorkTemplate {
80
+ /** Chain ID (MAIN_NET = 0x00). */
81
+ chainId: string;
82
+ /** Block number = current tip + 1. */
83
+ blockNumber: bigint;
84
+ /** Current block difficulty target (32-byte hex). */
85
+ blockDifficulty: string;
86
+ /** Super-parent hashes at each cascade level (RLE-serialized). */
87
+ superParents: string[];
88
+ /** Current MMR root (32-byte hex). */
89
+ mmrRoot: string;
90
+ /** Current MMR total (sum of all coins). */
91
+ mmrTotal: bigint;
92
+ /** Serialized Magic struct (hex). */
93
+ magic: string;
94
+ /** Candidate timestamp in epoch milliseconds. */
95
+ timeMilli: bigint;
96
+ /** Template identifier (e.g. tip txpowId) for staleness checks. */
97
+ templateId: string;
98
+ /** Epoch milliseconds when the template was captured. */
99
+ capturedAt: number;
100
+ }
101
+ /**
102
+ * Provider abstraction for the current Minima block-candidate template.
103
+ *
104
+ * The TxPoW package remains transport/node-client agnostic: callers inject a
105
+ * provider that fetches the current template from a Minima node, Axia, or a
106
+ * test fixture.
107
+ *
108
+ * `MinimaWorkRelay` is the preferred long-term relay boundary. The legacy
109
+ * `broadcastBlockCandidate` callback is retained as a compatibility/fallback
110
+ * path only — new consumers should use `relay` via `MinimaWorkRelay` and not
111
+ * build around the lossy `candidate: unknown` shape.
112
+ */
113
+ export interface MinimaWorkTemplateProvider {
114
+ /** Fetch the current block-candidate template. */
115
+ getCurrentTemplate(): Promise<MinimaWorkTemplate>;
116
+ /** Optional: fetch the latest template for freshness checks. Falls back to getCurrentTemplate. */
117
+ getLatestTemplate?(): Promise<MinimaWorkTemplate>;
118
+ /** Optional: validate a template before mining against it. */
119
+ validateTemplate?(template: MinimaWorkTemplate): Promise<boolean>;
120
+ /**
121
+ * @deprecated Prefer `MinimaWorkRelay.submitBlock` (complete envelope).
122
+ * Retained for compatibility; only invoked for genuine Minima blocks
123
+ * (Super-0 … Super-31) when no relay is configured.
124
+ */
125
+ broadcastBlockCandidate?(candidate: MachineWorkAdmissionProof): Promise<void>;
126
+ }
127
+ /**
128
+ * Relay boundary for a complete Minima TxPoW envelope.
129
+ *
130
+ * Keeps Minima networking outside core mining logic. A future
131
+ * @totemsdk/minima-rpc or chain-provider adapter may implement this port.
132
+ * Duplicate relay attempts must be safe/idempotent at the integration boundary.
133
+ */
134
+ export interface MinimaWorkRelay {
135
+ /** Submit a complete Minima TxPoW envelope for block relay. */
136
+ submitBlock(envelope: Uint8Array): Promise<void>;
137
+ }
138
+ /**
139
+ * The mined Machine Work Admission proof.
140
+ *
141
+ * Reuses the existing TxPoW types where possible:
142
+ * - `txpow` — serialized TxHeader bytes (SHA3-256 of these is `txpowId`)
143
+ * - `txpowEnvelope` — the COMPLETE Minima TxPoW wire format
144
+ * (header | 0x01 hasBody | body), required for network
145
+ * submission of a genuine Minima block
146
+ * - `txpowId` — SHA3-256(header)
147
+ *
148
+ * `qualifiesAsMinimaBlock`, `isBlock`, and `superLevel` are DERIVED METADATA
149
+ * recorded at mining time. They are never trusted by verification —
150
+ * verification recomputes all of them from the re-derived txpowId and the
151
+ * template's block difficulty.
152
+ */
153
+ export interface MachineWorkAdmissionProof {
154
+ /** Protocol version. */
155
+ version: number;
156
+ /** Hex commitment placed in the TxPoW header's customHash field. */
157
+ actionCommitment: string;
158
+ /** The challenge this proof was mined against. */
159
+ challengeId: string;
160
+ /** The admission target (32-byte hex) the proof satisfies. */
161
+ admissionTarget: string;
162
+ /** Serialized TxHeader bytes (SHA3-256 of these is the TxPoW ID). */
163
+ txpow: string;
164
+ /** Complete Minima TxPoW envelope (header | 0x01 | body) for block relay. */
165
+ txpowEnvelope: string;
166
+ /** SHA3-256(header) — the canonical TxPoW ID. */
167
+ txpowId: string;
168
+ /** The winning nonce. */
169
+ nonce: string;
170
+ /** Epoch milliseconds when the proof was mined. */
171
+ minedAt: number;
172
+ /** Always true for a valid admission proof. */
173
+ qualifiesForAdmission: true;
174
+ /**
175
+ * DERIVED METADATA: true when the mined hash also beats the block difficulty
176
+ * encoded by the candidate template (i.e. a genuine Minima block). Never
177
+ * trusted by verification — it is recomputed from the re-derived txpowId.
178
+ */
179
+ qualifiesAsMinimaBlock: boolean;
180
+ /**
181
+ * DERIVED METADATA: Minima Super level (-1 = not a block, 0..31 = block
182
+ * strength). Never trusted by verification.
183
+ */
184
+ superLevel: number;
185
+ /** DERIVED METADATA: superLevel >= 0. Never trusted by verification. */
186
+ isBlock: boolean;
187
+ /** Template the proof was mined against (for staleness policy). */
188
+ template: MinimaWorkTemplate;
189
+ }
190
+ /**
191
+ * Result of verifying a Machine Work Admission proof.
192
+ *
193
+ * Three distinct claims, never to be confused:
194
+ * A. `valid` — the hash satisfies the challenge target (admission proof).
195
+ * B. `superLevel` / `isBlock` — the hash ALSO satisfies the block difficulty
196
+ * encoded by the candidate template, yielding an exact Minima Super level.
197
+ * C. `broadcastable` — the candidate still corresponds to sufficiently
198
+ * current live Minima state AND can be submitted through the relay.
199
+ *
200
+ * A stale candidate may remain `valid = true` (and `superLevel >= 0`) while
201
+ * `broadcastable = false`.
202
+ *
203
+ * `superLevel === -1 ⇔ isBlock === false`, and
204
+ * `superLevel >= 0 ⇔ isBlock === true`. Verification recomputes these — it
205
+ * never trusts sender-supplied `isBlock`/`superLevel` metadata.
206
+ */
207
+ export interface WorkAdmissionVerification {
208
+ /** Level A: the hash satisfies the challenge target. */
209
+ valid: boolean;
210
+ reason?: string;
211
+ /**
212
+ * Level B: exact Minima Super level of the candidate hash.
213
+ * -1 = not a Minima block; 0..31 = Super-0 … Super-31 block strength.
214
+ */
215
+ superLevel?: number;
216
+ /** Level B: superLevel >= 0 (a genuine Minima block). */
217
+ isBlock?: boolean;
218
+ /**
219
+ * Level C: isBlock AND the template is current AND a live template provider
220
+ * was supplied. Undefined in offline mode (no provider) — offline
221
+ * verification must NOT claim Minima block contribution.
222
+ */
223
+ broadcastable?: boolean;
224
+ }
@@ -0,0 +1,24 @@
1
+ "use strict";
2
+ /**
3
+ * admission/types.ts — Machine Work Admission core types.
4
+ *
5
+ * Machine Work Admission lets a receiver require a sender to perform bounded
6
+ * computational work before scarce machine resources are allocated. The work
7
+ * searches the nonce space of a real current Minima block candidate, so the
8
+ * same hashes that admit the machine action also search for Minima L1 blocks.
9
+ *
10
+ * The three distinct concepts:
11
+ * - WorkChallenge — the receiver-controlled admission requirement
12
+ * - MachineWorkAction — the domain-separated application action commitment
13
+ * - MachineWorkAdmissionProof — the mined result
14
+ *
15
+ * The TxPoW package knows only "there is an application action represented by
16
+ * canonical bytes". It does NOT know about negotiation, compute, storage, or
17
+ * any particular Edge resource. Domain-specific packages supply the action.
18
+ */
19
+ Object.defineProperty(exports, "__esModule", { value: true });
20
+ exports.MACHINE_WORK_DOMAIN = exports.MACHINE_WORK_ADMISSION_VERSION = void 0;
21
+ /** Current Machine Work Admission protocol version. */
22
+ exports.MACHINE_WORK_ADMISSION_VERSION = 1;
23
+ /** Canonical protocol domain prefix for the commitment hash. */
24
+ exports.MACHINE_WORK_DOMAIN = 'totem.machine-work-admission';
@@ -0,0 +1,50 @@
1
+ /**
2
+ * admission/verify.ts — Machine Work Admission verification.
3
+ *
4
+ * Verification NEVER trusts sender-reported hardware speed or self-reported
5
+ * block metadata (`isBlock`, `superLevel`, `qualifiesAsMinimaBlock`,
6
+ * `broadcastable`). It recomputes the canonical action commitment, re-derives
7
+ * the TxPoW ID from the mined header, and checks `txpowId < challenge.target`.
8
+ * It also checks challenge validity (expiry, recipient, domain) and template
9
+ * freshness.
10
+ *
11
+ * Three distinct claims, never to be confused:
12
+ * A. valid — the hash satisfies the challenge target.
13
+ * B. superLevel/isBlock — the exact Minima Super level (-1 or 0..31)
14
+ * computed from blockDifficulty / txpowId.
15
+ * C. broadcastable — isBlock AND the template is current AND a live
16
+ * template provider was supplied.
17
+ *
18
+ * A stale candidate may remain valid = true (and superLevel >= 0) while
19
+ * broadcastable = false. Offline verification (no provider) must NOT claim
20
+ * Minima block contribution — `broadcastable` is left undefined.
21
+ */
22
+ import { type MachineWorkAction, type MachineWorkAdmissionProof, type MinimaWorkTemplate, type MinimaWorkTemplateProvider, type WorkChallenge, type WorkAdmissionVerification } from './types.js';
23
+ export interface VerifyWorkAdmissionOptions {
24
+ /** Override the current time for deterministic testing. */
25
+ now?: number;
26
+ /** Staleness window (ms) within which a template is acceptable for admission. */
27
+ admissionWindowMs?: number;
28
+ /** The latest template, for broadcastability checks. */
29
+ latestTemplate?: MinimaWorkTemplate | null;
30
+ }
31
+ /**
32
+ * Verify a Machine Work Admission proof.
33
+ *
34
+ * The admission target is taken from the validated challenge — never from the
35
+ * proof. `proof.qualifiesAsMinimaBlock`, `proof.superLevel`, and
36
+ * `proof.isBlock` are treated as derived metadata and are NOT trusted; the
37
+ * Super level is recomputed from the re-derived txpowId and the template's
38
+ * block difficulty.
39
+ *
40
+ * @param action The application action the proof claims to commit.
41
+ * @param challenge The challenge the proof claims to satisfy.
42
+ * @param proof The mined proof.
43
+ * @param templateProvider Optional live provider. When supplied, template
44
+ * freshness and broadcastability are checked and
45
+ * `broadcastable` is set. When omitted, verification
46
+ * runs in offline mode and does NOT claim Minima
47
+ * block contribution (`broadcastable` is undefined).
48
+ * @param options Verification options.
49
+ */
50
+ export declare function verifyWorkAdmission(action: MachineWorkAction, challenge: WorkChallenge, proof: MachineWorkAdmissionProof, templateProvider?: MinimaWorkTemplateProvider, options?: VerifyWorkAdmissionOptions): Promise<WorkAdmissionVerification>;
@@ -0,0 +1,156 @@
1
+ "use strict";
2
+ /**
3
+ * admission/verify.ts — Machine Work Admission verification.
4
+ *
5
+ * Verification NEVER trusts sender-reported hardware speed or self-reported
6
+ * block metadata (`isBlock`, `superLevel`, `qualifiesAsMinimaBlock`,
7
+ * `broadcastable`). It recomputes the canonical action commitment, re-derives
8
+ * the TxPoW ID from the mined header, and checks `txpowId < challenge.target`.
9
+ * It also checks challenge validity (expiry, recipient, domain) and template
10
+ * freshness.
11
+ *
12
+ * Three distinct claims, never to be confused:
13
+ * A. valid — the hash satisfies the challenge target.
14
+ * B. superLevel/isBlock — the exact Minima Super level (-1 or 0..31)
15
+ * computed from blockDifficulty / txpowId.
16
+ * C. broadcastable — isBlock AND the template is current AND a live
17
+ * template provider was supplied.
18
+ *
19
+ * A stale candidate may remain valid = true (and superLevel >= 0) while
20
+ * broadcastable = false. Offline verification (no provider) must NOT claim
21
+ * Minima block contribution — `broadcastable` is left undefined.
22
+ */
23
+ Object.defineProperty(exports, "__esModule", { value: true });
24
+ exports.verifyWorkAdmission = verifyWorkAdmission;
25
+ const core_1 = require("@totemsdk/core");
26
+ const commitment_js_1 = require("./commitment.js");
27
+ const challenge_js_1 = require("./challenge.js");
28
+ const template_js_1 = require("./template.js");
29
+ const types_js_1 = require("./types.js");
30
+ function hexToBytes(hex) {
31
+ const h = hex.startsWith('0x') ? hex.slice(2) : hex;
32
+ const out = new Uint8Array(h.length / 2);
33
+ for (let i = 0; i < h.length; i += 2) {
34
+ out[i / 2] = parseInt(h.slice(i, i + 2), 16);
35
+ }
36
+ return out;
37
+ }
38
+ /** Big-endian 256-bit comparison: true if a < b. */
39
+ function isLessThan(a, b) {
40
+ for (let i = 0; i < 32; i++) {
41
+ if (a[i] < b[i])
42
+ return true;
43
+ if (a[i] > b[i])
44
+ return false;
45
+ }
46
+ return false;
47
+ }
48
+ /**
49
+ * Verify a Machine Work Admission proof.
50
+ *
51
+ * The admission target is taken from the validated challenge — never from the
52
+ * proof. `proof.qualifiesAsMinimaBlock`, `proof.superLevel`, and
53
+ * `proof.isBlock` are treated as derived metadata and are NOT trusted; the
54
+ * Super level is recomputed from the re-derived txpowId and the template's
55
+ * block difficulty.
56
+ *
57
+ * @param action The application action the proof claims to commit.
58
+ * @param challenge The challenge the proof claims to satisfy.
59
+ * @param proof The mined proof.
60
+ * @param templateProvider Optional live provider. When supplied, template
61
+ * freshness and broadcastability are checked and
62
+ * `broadcastable` is set. When omitted, verification
63
+ * runs in offline mode and does NOT claim Minima
64
+ * block contribution (`broadcastable` is undefined).
65
+ * @param options Verification options.
66
+ */
67
+ async function verifyWorkAdmission(action, challenge, proof, templateProvider, options) {
68
+ // 1. Structural checks
69
+ if (!proof || typeof proof !== 'object') {
70
+ return { valid: false, reason: 'proof is not an object' };
71
+ }
72
+ if (proof.version !== types_js_1.MACHINE_WORK_ADMISSION_VERSION) {
73
+ return { valid: false, reason: `unsupported proof version ${proof.version}` };
74
+ }
75
+ if (proof.challengeId !== challenge.challengeId) {
76
+ return { valid: false, reason: 'proof challengeId does not match challenge' };
77
+ }
78
+ if (proof.qualifiesForAdmission !== true) {
79
+ return { valid: false, reason: 'proof does not claim admission' };
80
+ }
81
+ // Target manipulation guard: the proof must have been mined against the
82
+ // challenge's exact target. A sender must not be able to mine against a
83
+ // trivially easy target and present it as satisfying a harder challenge.
84
+ if (proof.admissionTarget !== challenge.target) {
85
+ return { valid: false, reason: 'proof admissionTarget does not match challenge target' };
86
+ }
87
+ // 2. Challenge validity (expiry, recipient, domain)
88
+ const challengeCheck = (0, challenge_js_1.validateWorkChallenge)(challenge, {
89
+ recipient: action.recipient,
90
+ domain: action.domain,
91
+ now: options?.now,
92
+ });
93
+ if (!challengeCheck.valid) {
94
+ return { valid: false, reason: challengeCheck.reason };
95
+ }
96
+ // 3. Recompute the canonical commitment — must match the proof
97
+ const expectedCommitment = (0, commitment_js_1.computeActionCommitment)(action, challenge);
98
+ if (expectedCommitment !== proof.actionCommitment) {
99
+ return { valid: false, reason: 'action commitment mismatch' };
100
+ }
101
+ // 4. Re-derive the TxPoW ID from the mined header and check the target
102
+ const headerBytes = hexToBytes(proof.txpow);
103
+ const txpowId = (0, core_1.sha3_256)(headerBytes);
104
+ const txpowIdHex = toHex(txpowId);
105
+ if (txpowIdHex !== proof.txpowId) {
106
+ return { valid: false, reason: 'txpowId does not match mined header' };
107
+ }
108
+ const admissionTarget = hexToBytes(proof.admissionTarget);
109
+ if (!isLessThan(txpowId, admissionTarget)) {
110
+ return { valid: false, reason: 'txpowId does not beat admission target' };
111
+ }
112
+ // 5. Resolve a trusted template. Template fields — notably `blockDifficulty`,
113
+ // which drives the Super-level claim — must come from a freshly-fetched
114
+ // trusted template, never from the prover's copy (RFC-020 H4).
115
+ let trustedTemplate = options?.latestTemplate ?? null;
116
+ if (templateProvider) {
117
+ if (templateProvider.getLatestTemplate) {
118
+ trustedTemplate = await templateProvider.getLatestTemplate();
119
+ }
120
+ else if (options?.latestTemplate) {
121
+ trustedTemplate = options.latestTemplate;
122
+ }
123
+ else {
124
+ trustedTemplate = await templateProvider.getCurrentTemplate();
125
+ }
126
+ }
127
+ // 5a. Template freshness for admission (uses the proof's capture time).
128
+ const freshness = (0, template_js_1.templateFreshness)(proof.template, trustedTemplate, {
129
+ admissionWindowMs: options?.admissionWindowMs,
130
+ now: options?.now,
131
+ });
132
+ if (!freshness.admissionValid) {
133
+ return { valid: false, reason: 'proof template is stale for admission' };
134
+ }
135
+ // 5b. The prover's declared block difficulty must byte-match the trusted
136
+ // template — otherwise a prover could set a max difficulty to fake a
137
+ // Minima block.
138
+ if (trustedTemplate && trustedTemplate.blockDifficulty !== proof.template.blockDifficulty) {
139
+ return { valid: false, reason: 'proof template blockDifficulty does not match the trusted template' };
140
+ }
141
+ // 6. Level B: recompute the exact Minima Super level from the TRUSTED block
142
+ // difficulty and the re-derived txpowId. Without a trusted template we
143
+ // cannot claim Minima block contribution (isBlock = false).
144
+ const superLevel = trustedTemplate ? (0, template_js_1.computeSuperLevel)(txpowId, trustedTemplate.blockDifficulty) : -1;
145
+ const isBlock = trustedTemplate ? superLevel >= 0 : false;
146
+ // 7. Level C: broadcastability requires a live template provider, a current
147
+ // template, and isBlock. Offline mode leaves broadcastable undefined.
148
+ let broadcastable;
149
+ if (templateProvider) {
150
+ broadcastable = isBlock && trustedTemplate !== null && freshness.broadcastable;
151
+ }
152
+ return { valid: true, superLevel, isBlock, broadcastable };
153
+ }
154
+ function toHex(bytes) {
155
+ return Array.from(bytes).map(b => b.toString(16).padStart(2, '0')).join('');
156
+ }
@@ -0,0 +1,35 @@
1
+ /**
2
+ * calibrate.ts — Hash rate measurement and mining cost estimation.
3
+ *
4
+ * calibrateHashRate() measures how many SHA3-256 hashes/sec the current
5
+ * environment can produce. Used by the extension UX to show a warning
6
+ * before starting a mine on slow devices.
7
+ *
8
+ * estimateMiningCost() converts a difficulty target + hash rate into an
9
+ * expected time and confidence label.
10
+ */
11
+ export interface MiningEstimate {
12
+ expectedHashes: bigint;
13
+ expectedSeconds: number;
14
+ confidence: 'fast' | 'normal' | 'slow';
15
+ }
16
+ /**
17
+ * Run 100K trial SHA3-256 hashes and return the measured hash rate (hashes/sec).
18
+ *
19
+ * Call once per session and cache the result — the cost is ~50ms on a
20
+ * typical desktop and ~300ms on a mid-range mobile.
21
+ */
22
+ export declare function calibrateHashRate(): Promise<number>;
23
+ /**
24
+ * Given a difficulty target and a measured hash rate, return the expected
25
+ * number of hashes, expected wall-clock time, and a confidence label.
26
+ *
27
+ * expectedHashes ≈ MAX_HASH / txnDifficulty
28
+ * (geometric distribution: each hash has P(valid) = txnDifficulty / MAX_HASH)
29
+ *
30
+ * Confidence labels:
31
+ * fast < 2 s
32
+ * normal 2 – 15 s
33
+ * slow > 15 s
34
+ */
35
+ export declare function estimateMiningCost(txnDifficulty: Uint8Array, hashRatePerSec: number): MiningEstimate;
@@ -0,0 +1,68 @@
1
+ "use strict";
2
+ /**
3
+ * calibrate.ts — Hash rate measurement and mining cost estimation.
4
+ *
5
+ * calibrateHashRate() measures how many SHA3-256 hashes/sec the current
6
+ * environment can produce. Used by the extension UX to show a warning
7
+ * before starting a mine on slow devices.
8
+ *
9
+ * estimateMiningCost() converts a difficulty target + hash rate into an
10
+ * expected time and confidence label.
11
+ */
12
+ Object.defineProperty(exports, "__esModule", { value: true });
13
+ exports.calibrateHashRate = calibrateHashRate;
14
+ exports.estimateMiningCost = estimateMiningCost;
15
+ const core_1 = require("@totemsdk/core");
16
+ /**
17
+ * Run 100K trial SHA3-256 hashes and return the measured hash rate (hashes/sec).
18
+ *
19
+ * Call once per session and cache the result — the cost is ~50ms on a
20
+ * typical desktop and ~300ms on a mid-range mobile.
21
+ */
22
+ async function calibrateHashRate() {
23
+ const TRIAL_COUNT = 100000;
24
+ const data = new Uint8Array(150).fill(0xab);
25
+ const start = typeof performance !== 'undefined'
26
+ ? performance.now()
27
+ : Date.now();
28
+ for (let i = 0; i < TRIAL_COUNT; i++) {
29
+ (0, core_1.sha3_256)(data);
30
+ }
31
+ const elapsed = (typeof performance !== 'undefined' ? performance.now() : Date.now()) - start;
32
+ return Math.round(TRIAL_COUNT / (elapsed / 1000));
33
+ }
34
+ /**
35
+ * Given a difficulty target and a measured hash rate, return the expected
36
+ * number of hashes, expected wall-clock time, and a confidence label.
37
+ *
38
+ * expectedHashes ≈ MAX_HASH / txnDifficulty
39
+ * (geometric distribution: each hash has P(valid) = txnDifficulty / MAX_HASH)
40
+ *
41
+ * Confidence labels:
42
+ * fast < 2 s
43
+ * normal 2 – 15 s
44
+ * slow > 15 s
45
+ */
46
+ function estimateMiningCost(txnDifficulty, hashRatePerSec) {
47
+ if (hashRatePerSec <= 0) {
48
+ throw new Error('hashRatePerSec must be positive');
49
+ }
50
+ const diffBigInt = txnDifficulty.reduce((acc, b) => (acc << 8n) | BigInt(b), 0n);
51
+ if (diffBigInt === 0n) {
52
+ return { expectedHashes: 0n, expectedSeconds: 0, confidence: 'fast' };
53
+ }
54
+ const MAX_HASH_BIGINT = (2n ** 256n) - 1n;
55
+ const expectedHashes = MAX_HASH_BIGINT / diffBigInt;
56
+ const expectedSeconds = Number(expectedHashes) / hashRatePerSec;
57
+ let confidence;
58
+ if (expectedSeconds < 2) {
59
+ confidence = 'fast';
60
+ }
61
+ else if (expectedSeconds < 15) {
62
+ confidence = 'normal';
63
+ }
64
+ else {
65
+ confidence = 'slow';
66
+ }
67
+ return { expectedHashes, expectedSeconds, confidence };
68
+ }
@@ -0,0 +1,27 @@
1
+ /**
2
+ * constants.ts — TxPoW-level constants matching Minima Java protocol values.
3
+ *
4
+ * ZERO_HASH: 32-byte all-zeros — used for MMRRoot, CustomHash, super-parent slot.
5
+ * MAX_HASH: 32-byte all-0xFF — default mBlockDifficulty / mTxnDifficulty for
6
+ * MEG-side-mined paths. Rejected by checkTxPoWSimple() at block level.
7
+ * TX_POW_MIN_DIFFICULTY: Safe transaction difficulty target.
8
+ * ≈ MAX_HASH / 1,000,000 = Magic.getMinTxPowWork() floor.
9
+ * Local-mining paths MUST use a target ≤ this value.
10
+ * MAIN_NET_CHAIN_ID: 1-byte [0x00] — Java MiniData("0x00") = MAIN_NET chain ID.
11
+ * CASCADE_LEVELS: 32 — number of super-parent slots in a fresh TxPoW header.
12
+ */
13
+ export declare const CASCADE_LEVELS = 32;
14
+ export declare const ZERO_HASH: Uint8Array<ArrayBuffer>;
15
+ export declare const MAX_HASH: Uint8Array;
16
+ /**
17
+ * TX_POW_MIN_DIFFICULTY = floor((2^256 - 1) / 1_000_000)
18
+ *
19
+ * This is the hardcoded floor constant matching Magic.getMinTxPowWork().
20
+ * Any locally mined TxPoW must have mTxnDifficulty ≤ this value to pass
21
+ * TxPoWChecker.checkTxPoWSimple() at block inclusion.
22
+ *
23
+ * Computed: (2n**256n - 1n) / 1_000_000n
24
+ * Hex: 0x000010C6F7A0B5ED8538AACDD46595F0C7AC73E0E9DBF12F70000000000000000
25
+ */
26
+ export declare const TX_POW_MIN_DIFFICULTY: Uint8Array;
27
+ export declare const MAIN_NET_CHAIN_ID: Uint8Array<ArrayBuffer>;
@@ -0,0 +1,47 @@
1
+ "use strict";
2
+ /**
3
+ * constants.ts — TxPoW-level constants matching Minima Java protocol values.
4
+ *
5
+ * ZERO_HASH: 32-byte all-zeros — used for MMRRoot, CustomHash, super-parent slot.
6
+ * MAX_HASH: 32-byte all-0xFF — default mBlockDifficulty / mTxnDifficulty for
7
+ * MEG-side-mined paths. Rejected by checkTxPoWSimple() at block level.
8
+ * TX_POW_MIN_DIFFICULTY: Safe transaction difficulty target.
9
+ * ≈ MAX_HASH / 1,000,000 = Magic.getMinTxPowWork() floor.
10
+ * Local-mining paths MUST use a target ≤ this value.
11
+ * MAIN_NET_CHAIN_ID: 1-byte [0x00] — Java MiniData("0x00") = MAIN_NET chain ID.
12
+ * CASCADE_LEVELS: 32 — number of super-parent slots in a fresh TxPoW header.
13
+ */
14
+ Object.defineProperty(exports, "__esModule", { value: true });
15
+ exports.MAIN_NET_CHAIN_ID = exports.TX_POW_MIN_DIFFICULTY = exports.MAX_HASH = exports.ZERO_HASH = exports.CASCADE_LEVELS = void 0;
16
+ exports.CASCADE_LEVELS = 32;
17
+ exports.ZERO_HASH = new Uint8Array(32);
18
+ exports.MAX_HASH = (() => {
19
+ const b = new Uint8Array(32);
20
+ b.fill(0xff);
21
+ return b;
22
+ })();
23
+ /**
24
+ * TX_POW_MIN_DIFFICULTY = floor((2^256 - 1) / 1_000_000)
25
+ *
26
+ * This is the hardcoded floor constant matching Magic.getMinTxPowWork().
27
+ * Any locally mined TxPoW must have mTxnDifficulty ≤ this value to pass
28
+ * TxPoWChecker.checkTxPoWSimple() at block inclusion.
29
+ *
30
+ * Computed: (2n**256n - 1n) / 1_000_000n
31
+ * Hex: 0x000010C6F7A0B5ED8538AACDD46595F0C7AC73E0E9DBF12F70000000000000000
32
+ */
33
+ exports.TX_POW_MIN_DIFFICULTY = (() => {
34
+ const maxHashBigInt = (2n ** 256n) - 1n;
35
+ const minDiffBigInt = maxHashBigInt / 1000000n;
36
+ let hex = minDiffBigInt.toString(16);
37
+ if (hex.length % 2 !== 0)
38
+ hex = '0' + hex;
39
+ while (hex.length < 64)
40
+ hex = '00' + hex;
41
+ const bytes = new Uint8Array(32);
42
+ for (let i = 0; i < 32; i++) {
43
+ bytes[i] = parseInt(hex.slice(i * 2, i * 2 + 2), 16);
44
+ }
45
+ return bytes;
46
+ })();
47
+ exports.MAIN_NET_CHAIN_ID = new Uint8Array([0x00]);