openttt 0.2.7 → 0.2.8

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "openttt",
3
- "version": "0.2.7",
3
+ "version": "0.2.8",
4
4
  "description": "OpenTTT — TLS-grade transaction ordering for DeFi. Time + Logic + Sync.",
5
5
  "license": "BSL-1.1",
6
6
  "repository": {
@@ -30,7 +30,50 @@
30
30
  }
31
31
  },
32
32
  "files": [
33
- "dist",
33
+ "dist/ct_log.js",
34
+ "dist/ct_log.d.ts",
35
+ "dist/dynamic_fee.js",
36
+ "dist/dynamic_fee.d.ts",
37
+ "dist/errors.js",
38
+ "dist/errors.d.ts",
39
+ "dist/evm_connector.js",
40
+ "dist/evm_connector.d.ts",
41
+ "dist/http_client.js",
42
+ "dist/http_client.d.ts",
43
+ "dist/index.js",
44
+ "dist/index.d.ts",
45
+ "dist/integrity_client.js",
46
+ "dist/integrity_client.d.ts",
47
+ "dist/logger.js",
48
+ "dist/logger.d.ts",
49
+ "dist/networks.js",
50
+ "dist/networks.d.ts",
51
+ "dist/osnma_source.js",
52
+ "dist/osnma_source.d.ts",
53
+ "dist/pool_registry.js",
54
+ "dist/pool_registry.d.ts",
55
+ "dist/pot_signer.js",
56
+ "dist/pot_signer.d.ts",
57
+ "dist/protocol_fee.js",
58
+ "dist/protocol_fee.d.ts",
59
+ "dist/revenue_tiers.js",
60
+ "dist/revenue_tiers.d.ts",
61
+ "dist/signer.js",
62
+ "dist/signer.d.ts",
63
+ "dist/time_synthesis.js",
64
+ "dist/time_synthesis.d.ts",
65
+ "dist/trust_store.js",
66
+ "dist/trust_store.d.ts",
67
+ "dist/ttt_builder.js",
68
+ "dist/ttt_builder.d.ts",
69
+ "dist/ttt_client.js",
70
+ "dist/ttt_client.d.ts",
71
+ "dist/types.js",
72
+ "dist/types.d.ts",
73
+ "dist/v4_hook.js",
74
+ "dist/v4_hook.d.ts",
75
+ "dist/x402_enforcer.js",
76
+ "dist/x402_enforcer.d.ts",
34
77
  "README.md"
35
78
  ],
36
79
  "scripts": {
@@ -1,59 +0,0 @@
1
- export declare enum AdaptiveMode {
2
- TURBO = "TURBO",// 50ms — Valid sequence, low latency
3
- FULL = "FULL"
4
- }
5
- export interface TTTRecord {
6
- time: number;
7
- txOrder: string[];
8
- grgPayload: Uint8Array[];
9
- }
10
- export interface Block {
11
- timestamp: number;
12
- txs: string[];
13
- data: Uint8Array;
14
- }
15
- /** Tier-based dynamic tolerance (ms) — auditor-requested upgrade */
16
- export declare const TIER_TOLERANCE_MS: Record<string, number>;
17
- export declare class AdaptiveSwitch {
18
- private windowSize;
19
- private threshold;
20
- private history;
21
- private currentMode;
22
- private minBlocks;
23
- private penaltyCooldown;
24
- private consecutiveFailures;
25
- private turboEntryThreshold;
26
- private turboMaintainThreshold;
27
- private tolerance;
28
- constructor(options?: {
29
- tolerance?: number;
30
- });
31
- /**
32
- * Core TTT mechanism: switches between Turbo/Full mode based on timestamp ordering match rate.
33
- */
34
- verifyBlock(block: Block, tttRecord: TTTRecord, chainId: number, poolAddress: string, tier?: string): AdaptiveMode;
35
- /**
36
- * Return fee discount rate based on current mode.
37
- * TURBO: 20% discount (incentivizes profitability).
38
- * FULL: No discount.
39
- */
40
- getFeeDiscount(): number;
41
- /**
42
- * Get current adaptive mode.
43
- */
44
- getCurrentMode(): AdaptiveMode;
45
- /**
46
- * Reset history (for testing).
47
- */
48
- reset(): void;
49
- /**
50
- * Serialize internal state to JSON for persistence across restarts.
51
- * Allows operators to avoid re-learning over 20 blocks after a restart.
52
- */
53
- serialize(): string;
54
- /**
55
- * Reconstruct an AdaptiveSwitch from previously serialized JSON state.
56
- */
57
- static deserialize(json: string): AdaptiveSwitch;
58
- private compareTransactionOrder;
59
- }
@@ -1,145 +0,0 @@
1
- "use strict";
2
- // sdk/src/adaptive_switch.ts — Adaptive Mode Switcher
3
- // Turbo (50ms) vs Full (127ms)
4
- Object.defineProperty(exports, "__esModule", { value: true });
5
- exports.AdaptiveSwitch = exports.TIER_TOLERANCE_MS = exports.AdaptiveMode = void 0;
6
- const grg_inverse_1 = require("./grg_inverse");
7
- const logger_1 = require("./logger");
8
- var AdaptiveMode;
9
- (function (AdaptiveMode) {
10
- AdaptiveMode["TURBO"] = "TURBO";
11
- AdaptiveMode["FULL"] = "FULL";
12
- })(AdaptiveMode || (exports.AdaptiveMode = AdaptiveMode = {}));
13
- // const TOLERANCE = 100; // 100ms tolerance for GEO-sat operator sync (now configurable via constructor)
14
- /** Tier-based dynamic tolerance (ms) — auditor-requested upgrade */
15
- exports.TIER_TOLERANCE_MS = {
16
- T0_epoch: 2000, // 6.4min tick → 2s tolerance
17
- T1_block: 200, // 2s tick → 200ms
18
- T2_slot: 500, // 12s tick → 500ms
19
- T3_micro: 10, // 100ms tick → 10ms (10%)
20
- };
21
- class AdaptiveSwitch {
22
- windowSize = 20; // B1-9: Updated from 10 to 20
23
- threshold = 0.9; // B1-9: Updated from 0.8 to 0.9
24
- history = [];
25
- currentMode = AdaptiveMode.FULL;
26
- minBlocks = 20; // B1-9: Minimum blocks for TURBO transition
27
- penaltyCooldown = 0; // B1-9: Penalty cooldown (P2-1: increased to 20 + exponential backoff)
28
- consecutiveFailures = 0; // P2-1: Track consecutive failures for exponential backoff
29
- turboEntryThreshold = 0.95; // P2-2: Hysteresis — stricter entry
30
- turboMaintainThreshold = 0.85; // P2-2: Hysteresis — relaxed maintenance
31
- tolerance;
32
- constructor(options) {
33
- this.tolerance = options?.tolerance ?? 100;
34
- }
35
- /**
36
- * Core TTT mechanism: switches between Turbo/Full mode based on timestamp ordering match rate.
37
- */
38
- verifyBlock(block, tttRecord, chainId, poolAddress, tier) {
39
- // 1. Check timestamp ordering and time match
40
- const orderMatch = this.compareTransactionOrder(block.txs, tttRecord.txOrder);
41
- const tolerance = tier ? (exports.TIER_TOLERANCE_MS[tier] ?? this.tolerance) : this.tolerance;
42
- const timeMatch = Math.abs(block.timestamp - tttRecord.time) < tolerance;
43
- let sequenceOk = orderMatch && timeMatch;
44
- // B1-1: Do not skip GrgInverse.verify() in TURBO mode
45
- // We check integrity regardless of mode
46
- const integrityOk = grg_inverse_1.GrgInverse.verify(block.data, tttRecord.grgPayload, chainId, poolAddress);
47
- if (!integrityOk) {
48
- logger_1.logger.error(`[AdaptiveSwitch] GRG integrity check FAILED`);
49
- sequenceOk = false; // Mark as false if integrity fails
50
- if (this.currentMode === AdaptiveMode.TURBO) {
51
- logger_1.logger.warn(`[AdaptiveSwitch] TURBO integrity failure: Penalty cooldown applied`);
52
- // P2-1: Exponential backoff — 20 * 2^(consecutiveFailures), capped at 320
53
- this.consecutiveFailures = Math.min(this.consecutiveFailures + 1, 4);
54
- this.penaltyCooldown = 20 * Math.pow(2, this.consecutiveFailures - 1); // 20, 40, 80, 160, 320
55
- }
56
- }
57
- // 2. Update history (Sliding Window)
58
- this.history.push(sequenceOk);
59
- if (this.history.length > this.windowSize) {
60
- this.history.shift();
61
- }
62
- if (this.penaltyCooldown > 0) {
63
- this.penaltyCooldown--;
64
- }
65
- // 3. Calculate match rate and switch mode
66
- const matchCount = this.history.filter(h => h).length;
67
- const matchRate = this.history.length > 0 ? matchCount / this.history.length : 0;
68
- // P2-2: Hysteresis — different thresholds for entering vs maintaining TURBO
69
- const effectiveThreshold = this.currentMode === AdaptiveMode.TURBO
70
- ? this.turboMaintainThreshold // 85% to stay in TURBO
71
- : this.turboEntryThreshold; // 95% to enter TURBO
72
- if (this.history.length >= this.minBlocks && matchRate >= effectiveThreshold && this.penaltyCooldown === 0) {
73
- if (this.currentMode === AdaptiveMode.FULL) {
74
- logger_1.logger.info(`[AdaptiveSwitch] Switching to TURBO mode (Match rate: ${(matchRate * 100).toFixed(1)}%, Entry threshold: ${(this.turboEntryThreshold * 100).toFixed(0)}%)`);
75
- }
76
- this.currentMode = AdaptiveMode.TURBO;
77
- this.consecutiveFailures = 0; // P2-1: Reset on successful TURBO
78
- }
79
- else {
80
- if (this.currentMode === AdaptiveMode.TURBO) {
81
- logger_1.logger.warn(`[AdaptiveSwitch] Switching to FULL mode (Match rate: ${(matchRate * 100).toFixed(1)}%, Maintain threshold: ${(this.turboMaintainThreshold * 100).toFixed(0)}%, Cooldown: ${this.penaltyCooldown})`);
82
- }
83
- this.currentMode = AdaptiveMode.FULL;
84
- }
85
- return this.currentMode;
86
- }
87
- /**
88
- * Return fee discount rate based on current mode.
89
- * TURBO: 20% discount (incentivizes profitability).
90
- * FULL: No discount.
91
- */
92
- getFeeDiscount() {
93
- return this.currentMode === AdaptiveMode.TURBO ? 0.2 : 0.0;
94
- }
95
- /**
96
- * Get current adaptive mode.
97
- */
98
- getCurrentMode() {
99
- return this.currentMode;
100
- }
101
- /**
102
- * Reset history (for testing).
103
- */
104
- reset() {
105
- this.history = [];
106
- this.currentMode = AdaptiveMode.FULL;
107
- this.penaltyCooldown = 0;
108
- this.consecutiveFailures = 0;
109
- }
110
- /**
111
- * Serialize internal state to JSON for persistence across restarts.
112
- * Allows operators to avoid re-learning over 20 blocks after a restart.
113
- */
114
- serialize() {
115
- return JSON.stringify({
116
- history: this.history,
117
- currentMode: this.currentMode,
118
- consecutiveFailures: this.consecutiveFailures,
119
- penaltyCooldown: this.penaltyCooldown,
120
- tolerance: this.tolerance,
121
- });
122
- }
123
- /**
124
- * Reconstruct an AdaptiveSwitch from previously serialized JSON state.
125
- */
126
- static deserialize(json) {
127
- const data = JSON.parse(json);
128
- const instance = new AdaptiveSwitch({ tolerance: data.tolerance ?? 100 });
129
- instance.history = data.history;
130
- instance.currentMode = data.currentMode;
131
- instance.consecutiveFailures = data.consecutiveFailures;
132
- instance.penaltyCooldown = data.penaltyCooldown;
133
- return instance;
134
- }
135
- compareTransactionOrder(blockTxs, expectedOrder) {
136
- if (blockTxs.length !== expectedOrder.length)
137
- return false;
138
- for (let i = 0; i < blockTxs.length; i++) {
139
- if (blockTxs[i] !== expectedOrder[i])
140
- return false;
141
- }
142
- return true;
143
- }
144
- }
145
- exports.AdaptiveSwitch = AdaptiveSwitch;
@@ -1,61 +0,0 @@
1
- import { TimeSynthesis } from "./time_synthesis";
2
- import { EVMConnector } from "./evm_connector";
3
- import { AutoMintConfig, MintResult } from "./types";
4
- /**
5
- * AutoMintEngine - Automatic TTT minting engine.
6
- * Combines time synthesis, dynamic fee calculation, and EVM minting into a single loop.
7
- */
8
- export declare class AutoMintEngine {
9
- private config;
10
- private timeSynthesis;
11
- private feeEngine;
12
- private evmConnector;
13
- private feeCollector;
14
- private timer;
15
- private isRunning;
16
- private isProcessing;
17
- private onMintCallback?;
18
- private onFailureCallback?;
19
- private onLatencyCallback?;
20
- private cachedSigner;
21
- private consecutiveFailures;
22
- private maxConsecutiveFailures;
23
- private potSigner;
24
- /** Monotonic counter appended to tokenId hash to prevent collision when two mints share the same nanosecond timestamp. */
25
- private mintNonce;
26
- /** Fire the GRG >50ms performance warning at most once per engine session. */
27
- private warnedGrgSlow;
28
- constructor(config: AutoMintConfig);
29
- getEvmConnector(): EVMConnector;
30
- getTimeSynthesis(): TimeSynthesis;
31
- setOnMint(callback: (result: MintResult) => void): void;
32
- setOnFailure(callback: (error: Error) => void): void;
33
- setOnLatency(callback: (ms: number) => void): void;
34
- /**
35
- * Initialize the engine (RPC connection and contract setup).
36
- */
37
- initialize(): Promise<void>;
38
- /**
39
- * Start the automatic minting loop.
40
- */
41
- start(): void;
42
- /**
43
- * Stop the automatic minting loop.
44
- */
45
- stop(): void;
46
- /**
47
- * Resume the minting loop after a circuit breaker trip.
48
- * Resets the consecutive failure counter and restarts the loop.
49
- */
50
- resume(): void;
51
- /**
52
- * Sleep helper for retry backoff.
53
- */
54
- private sleep;
55
- /**
56
- * Execute a single mint tick.
57
- * Time synthesis -> tokenId generation -> EVM mint call -> fee calculation/deduction.
58
- */
59
- mintTick(): Promise<void>;
60
- private signFeeMessage;
61
- }
package/dist/auto_mint.js DELETED
@@ -1,330 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.AutoMintEngine = void 0;
4
- const ethers_1 = require("ethers");
5
- const time_synthesis_1 = require("./time_synthesis");
6
- const dynamic_fee_1 = require("./dynamic_fee");
7
- const evm_connector_1 = require("./evm_connector");
8
- const protocol_fee_1 = require("./protocol_fee");
9
- const pot_signer_1 = require("./pot_signer");
10
- const grg_forward_1 = require("./grg_forward");
11
- const types_1 = require("./types");
12
- const logger_1 = require("./logger");
13
- const errors_1 = require("./errors");
14
- /** Maximum retry attempts for RPC-dependent operations within a single tick */
15
- const MINT_TICK_MAX_RETRIES = 3;
16
- /** Backoff durations in ms for each retry attempt (1s, 2s, 4s) */
17
- const MINT_TICK_BACKOFF_MS = [1000, 2000, 4000];
18
- /**
19
- * AutoMintEngine - Automatic TTT minting engine.
20
- * Combines time synthesis, dynamic fee calculation, and EVM minting into a single loop.
21
- */
22
- class AutoMintEngine {
23
- config;
24
- timeSynthesis;
25
- feeEngine;
26
- evmConnector;
27
- feeCollector = null;
28
- timer = null;
29
- isRunning = false;
30
- isProcessing = false;
31
- onMintCallback;
32
- onFailureCallback;
33
- onLatencyCallback;
34
- cachedSigner = null;
35
- consecutiveFailures = 0;
36
- maxConsecutiveFailures = 5;
37
- potSigner = null;
38
- /** Monotonic counter appended to tokenId hash to prevent collision when two mints share the same nanosecond timestamp. */
39
- mintNonce = BigInt(Date.now());
40
- /** Fire the GRG >50ms performance warning at most once per engine session. */
41
- warnedGrgSlow = false;
42
- constructor(config) {
43
- this.config = config;
44
- this.timeSynthesis = new time_synthesis_1.TimeSynthesis({ sources: config.timeSources });
45
- this.feeEngine = new dynamic_fee_1.DynamicFeeEngine({
46
- cacheDurationMs: 5000,
47
- fallbackPriceUsd: config.fallbackPriceUsd || 10000n,
48
- });
49
- this.evmConnector = new evm_connector_1.EVMConnector();
50
- if (config.signer) {
51
- this.cachedSigner = config.signer;
52
- }
53
- // Initialize Ed25519 PoT signer for non-repudiation
54
- this.potSigner = config.potSignerKeyPath
55
- ? pot_signer_1.PotSigner.createOrLoad(config.potSignerKeyPath)
56
- : new pot_signer_1.PotSigner();
57
- }
58
- getEvmConnector() {
59
- return this.evmConnector;
60
- }
61
- getTimeSynthesis() {
62
- return this.timeSynthesis;
63
- }
64
- setOnMint(callback) {
65
- this.onMintCallback = callback;
66
- }
67
- setOnFailure(callback) {
68
- this.onFailureCallback = callback;
69
- }
70
- setOnLatency(callback) {
71
- this.onLatencyCallback = callback;
72
- }
73
- /**
74
- * Initialize the engine (RPC connection and contract setup).
75
- */
76
- async initialize() {
77
- try {
78
- const signerOrKey = this.config.signer || this.config.privateKey;
79
- if (!signerOrKey)
80
- throw new errors_1.TTTConfigError(errors_1.ERROR_CODES.CONFIG_MISSING_SIGNER, "[AutoMint] Signer or Private Key is required", "Missing both 'signer' and 'privateKey' in config", "Provide a valid ethers.Signer or a private key string in your configuration.");
81
- await this.evmConnector.connect(this.config.rpcUrl, signerOrKey);
82
- await this.feeEngine.connect(this.config.rpcUrl);
83
- this.cachedSigner = this.evmConnector.getSigner();
84
- const tttAbi = [
85
- "function mint(address to, uint256 amount, bytes32 grgHash) external returns (bool)",
86
- "function burn(uint256 amount, bytes32 grgHash, uint256 tier) external",
87
- "function balanceOf(address account, uint256 id) external view returns (uint256)",
88
- "event TTTMinted(address indexed to, uint256 indexed tokenId, uint256 amount)",
89
- "event TTTBurned(address indexed from, uint256 indexed tokenId, uint256 amount, uint256 tier)",
90
- // CT Log equivalent: every PoT is publicly auditable on-chain
91
- evm_connector_1.EVMConnector.POT_ANCHORED_EVENT_ABI
92
- ];
93
- this.evmConnector.attachContract(this.config.contractAddress, tttAbi);
94
- if (this.config.feeCollectorAddress) {
95
- this.feeCollector = new protocol_fee_1.ProtocolFeeCollector(this.config.chainId, this.config.feeCollectorAddress, this.evmConnector, this.config.protocolFeeRecipient);
96
- await this.feeCollector.validateChainId();
97
- }
98
- }
99
- catch (error) {
100
- // State rollback: Ensure connections are closed or reset
101
- this.evmConnector = new evm_connector_1.EVMConnector();
102
- this.cachedSigner = null;
103
- this.feeCollector = null;
104
- logger_1.logger.error(`[AutoMint] Initialization failed, state rolled back: ${error instanceof Error ? error.message : error}`);
105
- throw error;
106
- }
107
- }
108
- /**
109
- * Start the automatic minting loop.
110
- */
111
- start() {
112
- if (this.isRunning)
113
- return;
114
- // Clear existing timer if any
115
- if (this.timer) {
116
- clearInterval(this.timer);
117
- this.timer = null;
118
- }
119
- const interval = types_1.TierIntervals[this.config.tier];
120
- this.isRunning = true;
121
- this.timer = setInterval(async () => {
122
- if (this.isProcessing)
123
- return;
124
- this.isProcessing = true;
125
- const tickStart = Date.now();
126
- try {
127
- await this.mintTick();
128
- this.consecutiveFailures = 0;
129
- // H2: Report latency to TTTClient
130
- if (this.onLatencyCallback) {
131
- this.onLatencyCallback(Date.now() - tickStart);
132
- }
133
- }
134
- catch (error) {
135
- this.consecutiveFailures++;
136
- // H2: Report failure to TTTClient
137
- if (this.onFailureCallback) {
138
- this.onFailureCallback(error instanceof Error ? error : new Error(String(error)));
139
- }
140
- logger_1.logger.error(`[AutoMint] Tick execution failed (${this.consecutiveFailures}/${this.maxConsecutiveFailures}): ${error instanceof Error ? error.message : error}`);
141
- if (this.consecutiveFailures >= this.maxConsecutiveFailures) {
142
- logger_1.logger.error(`[AutoMint] Circuit breaker triggered: ${this.consecutiveFailures} consecutive failures. Stopping engine to prevent DoS.`);
143
- this.stop();
144
- }
145
- }
146
- finally {
147
- this.isProcessing = false;
148
- }
149
- }, interval);
150
- logger_1.logger.info(`[AutoMint] Loop started for tier ${this.config.tier} (${interval}ms)`);
151
- }
152
- /**
153
- * Stop the automatic minting loop.
154
- */
155
- stop() {
156
- if (this.timer) {
157
- clearInterval(this.timer);
158
- this.timer = null;
159
- }
160
- this.isRunning = false;
161
- logger_1.logger.info(`[AutoMint] Loop stopped`);
162
- }
163
- /**
164
- * Resume the minting loop after a circuit breaker trip.
165
- * Resets the consecutive failure counter and restarts the loop.
166
- */
167
- resume() {
168
- this.consecutiveFailures = 0;
169
- logger_1.logger.info(`[AutoMint] Consecutive failures reset, resuming...`);
170
- this.start();
171
- }
172
- /**
173
- * Sleep helper for retry backoff.
174
- */
175
- sleep(ms) {
176
- return new Promise(resolve => setTimeout(resolve, ms));
177
- }
178
- /**
179
- * Execute a single mint tick.
180
- * Time synthesis -> tokenId generation -> EVM mint call -> fee calculation/deduction.
181
- */
182
- async mintTick() {
183
- // 1. Time Synthesis
184
- const synthesized = await this.timeSynthesis.synthesize();
185
- if (!synthesized) {
186
- logger_1.logger.warn(`[AutoMint] Time synthesis returned null/undefined, skipping tick`);
187
- return;
188
- }
189
- // Fix-12: Integrity check
190
- if (synthesized.confidence === 0 || synthesized.stratum >= 16) {
191
- throw new errors_1.TTTTimeSynthesisError(errors_1.ERROR_CODES.TIME_SYNTHESIS_INTEGRITY_FAILED, `[AutoMint] Synthesis integrity check failed`, `confidence=${synthesized.confidence}, stratum=${synthesized.stratum}`, `Check NTP sources or network connectivity.`);
192
- }
193
- // 1-1. PoT Generation & Validation (W1-1)
194
- const pot = await this.timeSynthesis.generateProofOfTime();
195
- if (pot.confidence < 0.5) {
196
- throw new errors_1.TTTTimeSynthesisError(errors_1.ERROR_CODES.TIME_SYNTHESIS_INSUFFICIENT_CONFIDENCE, `[PoT] Insufficient confidence`, `Calculated confidence ${pot.confidence} is below required 0.5`, `Ensure more NTP sources are reachable or decrease uncertainty.`);
197
- }
198
- // Deterministic potHash via ABI.encode — field order is fixed,
199
- // independent of JS engine key ordering. External verifiers can
200
- // reproduce this hash from the same PoT fields.
201
- const nonceHash = ethers_1.ethers.keccak256(ethers_1.ethers.toUtf8Bytes(pot.nonce));
202
- const potHash = ethers_1.ethers.keccak256(ethers_1.ethers.AbiCoder.defaultAbiCoder().encode(["uint64", "uint64", "uint8", "uint8", "uint32", "bytes32"], [
203
- pot.timestamp,
204
- pot.expiresAt,
205
- pot.sources,
206
- pot.stratum,
207
- Math.round(pot.confidence * 1_000_000),
208
- nonceHash
209
- ]));
210
- // 1-2. Ed25519 issuer signature for non-repudiation
211
- if (this.potSigner) {
212
- pot.issuerSignature = this.potSigner.signPot(potHash);
213
- logger_1.logger.info(`[AutoMint] PoT signed by issuer ${this.potSigner.getPubKeyHex().substring(0, 16)}...`);
214
- }
215
- // 2. Generate tokenId (keccak256)
216
- // Unique ID based on chainId, poolAddress, timestamp, and a monotonic nonce
217
- // to prevent collision if two mints occur at the same nanosecond timestamp.
218
- const nonceSuffix = this.mintNonce;
219
- this.mintNonce++;
220
- const tokenId = ethers_1.ethers.keccak256(ethers_1.ethers.AbiCoder.defaultAbiCoder().encode(["uint256", "address", "uint64", "uint256"], [BigInt(this.config.chainId), this.config.poolAddress, synthesized.timestamp, nonceSuffix]));
221
- // 3. Fee calculation
222
- const feeCalculation = await this.feeEngine.calculateMintFee(this.config.tier);
223
- // 4. EVM mint call — run GRG integrity pipeline
224
- const grgPayload = ethers_1.ethers.AbiCoder.defaultAbiCoder().encode(["bytes32", "bytes32", "uint64", "uint8"], [tokenId, potHash, synthesized.timestamp, pot.sources]);
225
- const grgStart = Date.now();
226
- const grgShards = grg_forward_1.GrgForward.encode(ethers_1.ethers.getBytes(grgPayload), this.config.chainId, this.config.poolAddress);
227
- const grgElapsed = Date.now() - grgStart;
228
- logger_1.logger.info(`[AutoMint] GRG pipeline completed in ${grgElapsed}ms`);
229
- if (grgElapsed > 50 && !this.warnedGrgSlow) {
230
- this.warnedGrgSlow = true;
231
- logger_1.logger.warn(`[AutoMint] GRG pipeline took ${grgElapsed}ms (>50ms threshold). Consider offloading to a Worker Thread for T3_micro tiers.`);
232
- }
233
- // On-chain hash = keccak256 of concatenated GRG-encoded shards
234
- const grgHash = ethers_1.ethers.keccak256(ethers_1.ethers.concat(grgShards));
235
- // Recipient address (defaults to signer address)
236
- if (!this.cachedSigner) {
237
- throw new errors_1.TTTSignerError(errors_1.ERROR_CODES.SIGNER_NOT_INITIALIZED, "[AutoMint] Signer not initialized", "cachedSigner is null", "Initialize the engine before calling mintTick().");
238
- }
239
- const recipient = await this.cachedSigner.getAddress();
240
- logger_1.logger.info(`[AutoMint] Executing mint: tokenId=${tokenId.substring(0, 10)}... amount=${feeCalculation.tttAmount}`);
241
- // Retry loop for RPC-dependent mint operation (max 3 attempts, backoff 1s/2s/4s)
242
- let receipt;
243
- let lastError = null;
244
- for (let attempt = 0; attempt < MINT_TICK_MAX_RETRIES; attempt++) {
245
- try {
246
- receipt = await this.evmConnector.mintTTT(recipient, feeCalculation.tttAmount, grgHash, potHash);
247
- lastError = null;
248
- break;
249
- }
250
- catch (err) {
251
- lastError = err instanceof Error ? err : new Error(String(err));
252
- if (attempt < MINT_TICK_MAX_RETRIES - 1) {
253
- const backoff = MINT_TICK_BACKOFF_MS[attempt];
254
- logger_1.logger.warn(`[AutoMint] Mint attempt ${attempt + 1}/${MINT_TICK_MAX_RETRIES} failed, retrying in ${backoff}ms: ${lastError.message}`);
255
- await this.sleep(backoff);
256
- }
257
- }
258
- }
259
- if (lastError || !receipt) {
260
- throw lastError || new Error("[AutoMint] Mint failed after all retries");
261
- }
262
- // 5. Fee deduction/recording (handled by contract or tracked at SDK level)
263
- // W2-3: Actual ProtocolFeeCollector call
264
- let actualFeePaid = feeCalculation.protocolFeeUsd;
265
- if (this.feeCollector && this.config.feeCollectorAddress) {
266
- try {
267
- // NOTE: Single-threaded JS guarantees atomicity between nonce generation,
268
- // signing, and collection below. If running multiple AutoMintEngine instances
269
- // (e.g., worker_threads or cluster), a separate nonce manager with locking is required.
270
- // Sequential nonce: query contract for current nonce, matching ProtocolFee.sol's require(nonces[msg.sender] == nonce)
271
- const feeContract = new ethers_1.ethers.Contract(this.config.feeCollectorAddress, ["function getNonce(address) external view returns (uint256)"], this.evmConnector.getProvider());
272
- const nonce = BigInt(await feeContract.getNonce(recipient));
273
- const deadline = Math.floor(Date.now() / 1000) + 3600; // 1 hour validity
274
- const signature = await this.signFeeMessage(feeCalculation, nonce, deadline);
275
- const user = recipient;
276
- await this.feeCollector.collectMintFee(feeCalculation, signature, user, nonce, deadline);
277
- }
278
- catch (feeError) {
279
- logger_1.logger.error(`[AutoMint] Fee collection failed but mint was successful: ${feeError instanceof Error ? feeError.message : feeError}`);
280
- // Reset to 0 so downstream (onMint callback, ledger) does not record a fee that was never collected
281
- actualFeePaid = 0n;
282
- }
283
- }
284
- // CT Log equivalent: log PoT anchor info for subgraph indexers
285
- logger_1.logger.info(`[AutoMint] PoTAnchored: timestamp=${synthesized.timestamp}, grgHash=${grgHash}, stratum=${synthesized.stratum}, potHash=${potHash}`);
286
- logger_1.logger.info(`[AutoMint] Mint success: tx=${receipt.hash}, feePaid=${actualFeePaid} (USDC eq)`);
287
- if (this.onMintCallback) {
288
- this.onMintCallback({
289
- tokenId: tokenId,
290
- grgHash: grgHash,
291
- timestamp: synthesized.timestamp,
292
- txHash: receipt.hash,
293
- protocolFeePaid: actualFeePaid,
294
- proofOfTime: pot
295
- });
296
- }
297
- }
298
- async signFeeMessage(feeCalc, nonce, deadline) {
299
- if (!this.cachedSigner) {
300
- throw new errors_1.TTTSignerError(errors_1.ERROR_CODES.SIGNER_NOT_INITIALIZED, "[AutoMint] Signer not initialized", "cachedSigner is null", "Ensure initialize() was called successfully.");
301
- }
302
- // Type casting to handle signTypedData if available on the signer (Wallet supports it)
303
- const signer = this.cachedSigner;
304
- if (typeof signer.signTypedData !== 'function') {
305
- throw new errors_1.TTTSignerError(errors_1.ERROR_CODES.SIGNER_NO_EIP712, "[AutoMint] Provided signer does not support signTypedData (EIP-712)", `Signer type ${signer.constructor.name} missing signTypedData`, "Use a Wallet or a signer that implements EIP-712 signTypedData.");
306
- }
307
- const domain = {
308
- name: "OpenTTT_ProtocolFee",
309
- version: "1",
310
- chainId: this.config.chainId,
311
- verifyingContract: this.config.feeCollectorAddress
312
- };
313
- const types = {
314
- CollectFee: [
315
- { name: "token", type: "address" },
316
- { name: "amount", type: "uint256" },
317
- { name: "nonce", type: "uint256" },
318
- { name: "deadline", type: "uint256" }
319
- ]
320
- };
321
- const value = {
322
- token: ethers_1.ethers.getAddress(feeCalc.feeTokenAddress),
323
- amount: feeCalc.protocolFeeUsd,
324
- nonce: nonce,
325
- deadline: deadline
326
- };
327
- return await signer.signTypedData(domain, types, value);
328
- }
329
- }
330
- exports.AutoMintEngine = AutoMintEngine;
package/dist/golay.d.ts DELETED
@@ -1,7 +0,0 @@
1
- export interface GolayDecodeResult {
2
- data: Uint8Array;
3
- corrected: number;
4
- uncorrectable: boolean;
5
- }
6
- export declare function golayEncode(data: Uint8Array): Uint8Array;
7
- export declare function golayDecode(encoded: Uint8Array): GolayDecodeResult;
package/dist/golay.js DELETED
@@ -1,139 +0,0 @@
1
- "use strict";
2
- // sdk/src/golay.ts
3
- // Golay(24,12) Extended Binary Golay Code
4
- // Corrects up to 3 bit errors, detects 4 bit errors.
5
- Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.golayEncode = golayEncode;
7
- exports.golayDecode = golayDecode;
8
- // Standard Golay Parity Matrix P (12x12) - Systematic Form [I12 | P]
9
- // Every row has weight 7.
10
- // Verified: P*P^T = I (mod 2), all rows weight 7.
11
- const P = [
12
- 0xC75, 0x49F, 0xD4B, 0x6E3, 0x9B3, 0xB66,
13
- 0xECC, 0x1ED, 0x3DA, 0x7B4, 0xB1D, 0xE3A
14
- ];
15
- // P^T (transpose of P) — required for second syndrome computation.
16
- // P is NOT symmetric, so s2 = s*P^T must use this separate matrix.
17
- const PT = [
18
- 0xAE3, 0xF25, 0x16F, 0x2DE, 0x5BC, 0xB78,
19
- 0x9D5, 0xC8F, 0x63B, 0xC76, 0x7C9, 0xF92
20
- ];
21
- const UNIT_VECTORS = [
22
- 0x800, 0x400, 0x200, 0x100, 0x080, 0x040,
23
- 0x020, 0x010, 0x008, 0x004, 0x002, 0x001
24
- ];
25
- function weight(n) {
26
- let count = 0;
27
- let temp = n & 0xFFF;
28
- while (temp > 0) {
29
- temp &= (temp - 1);
30
- count++;
31
- }
32
- return count;
33
- }
34
- function multiplyP(v) {
35
- let res = 0;
36
- for (let i = 0; i < 12; i++) {
37
- if ((v >> (11 - i)) & 1) {
38
- res ^= P[i];
39
- }
40
- }
41
- return res & 0xFFF;
42
- }
43
- function multiplyPT(v) {
44
- let res = 0;
45
- for (let i = 0; i < 12; i++) {
46
- if ((v >> (11 - i)) & 1) {
47
- res ^= PT[i];
48
- }
49
- }
50
- return res & 0xFFF;
51
- }
52
- function encodeWord(msg) {
53
- const parity = multiplyP(msg & 0xFFF);
54
- return ((msg & 0xFFF) << 12) | parity;
55
- }
56
- function decodeWord(received) {
57
- let r_m = (received >> 12) & 0xFFF;
58
- const r_p = received & 0xFFF;
59
- const s = multiplyP(r_m) ^ r_p;
60
- if (s === 0)
61
- return { msg: r_m, corrected: 0, uncorrectable: false };
62
- if (weight(s) <= 3) {
63
- return { msg: r_m, corrected: weight(s), uncorrectable: false };
64
- }
65
- for (let i = 0; i < 12; i++) {
66
- if (weight(s ^ P[i]) <= 2) {
67
- return { msg: r_m ^ UNIT_VECTORS[i], corrected: weight(s ^ P[i]) + 1, uncorrectable: false };
68
- }
69
- }
70
- const s2 = multiplyPT(s);
71
- if (weight(s2) <= 3) {
72
- return { msg: r_m ^ s2, corrected: weight(s2), uncorrectable: false };
73
- }
74
- for (let i = 0; i < 12; i++) {
75
- if (weight(s2 ^ PT[i]) <= 2) {
76
- const error_m = s2 ^ PT[i];
77
- return { msg: r_m ^ error_m, corrected: weight(s2 ^ PT[i]) + 1, uncorrectable: false };
78
- }
79
- }
80
- return { msg: r_m, corrected: 0, uncorrectable: true };
81
- }
82
- function golayEncode(data) {
83
- const out = new Uint8Array(Math.ceil(data.length / 3) * 6);
84
- let outIdx = 0;
85
- for (let i = 0; i < data.length; i += 3) {
86
- const b1 = data[i];
87
- const b2 = i + 1 < data.length ? data[i + 1] : 0;
88
- const b3 = i + 2 < data.length ? data[i + 2] : 0;
89
- const w1 = (b1 << 4) | (b2 >> 4);
90
- const c1 = encodeWord(w1);
91
- out[outIdx++] = (c1 >> 16) & 0xFF;
92
- out[outIdx++] = (c1 >> 8) & 0xFF;
93
- out[outIdx++] = c1 & 0xFF;
94
- if (i + 1 < data.length) {
95
- const w2 = ((b2 & 0x0F) << 8) | b3;
96
- const c2 = encodeWord(w2);
97
- out[outIdx++] = (c2 >> 16) & 0xFF;
98
- out[outIdx++] = (c2 >> 8) & 0xFF;
99
- out[outIdx++] = c2 & 0xFF;
100
- }
101
- }
102
- return out;
103
- }
104
- function golayDecode(encoded) {
105
- if (encoded.length % 6 !== 0) {
106
- throw new Error("Invalid Golay encoded data: length must be multiple of 6");
107
- }
108
- const outLen = Math.floor(encoded.length / 2);
109
- const out = new Uint8Array(outLen);
110
- let outIdx = 0;
111
- let totalCorrected = 0;
112
- let anyUncorrectable = false;
113
- for (let i = 0; i < encoded.length; i += 6) {
114
- const c1 = (encoded[i] << 16) | (encoded[i + 1] << 8) | encoded[i + 2];
115
- const res1 = decodeWord(c1);
116
- totalCorrected += res1.corrected;
117
- if (res1.uncorrectable)
118
- anyUncorrectable = true;
119
- if (outIdx < outLen)
120
- out[outIdx++] = (res1.msg >> 4) & 0xFF;
121
- const b2_high = (res1.msg & 0x0F) << 4;
122
- if (i + 3 < encoded.length) {
123
- const c2 = (encoded[i + 3] << 16) | (encoded[i + 4] << 8) | encoded[i + 5];
124
- const res2 = decodeWord(c2);
125
- totalCorrected += res2.corrected;
126
- if (res2.uncorrectable)
127
- anyUncorrectable = true;
128
- if (outIdx < outLen)
129
- out[outIdx++] = b2_high | (res2.msg >> 8);
130
- if (outIdx < outLen)
131
- out[outIdx++] = res2.msg & 0xFF;
132
- }
133
- else {
134
- if (outIdx < outLen)
135
- out[outIdx++] = b2_high;
136
- }
137
- }
138
- return { data: out, corrected: totalCorrected, uncorrectable: anyUncorrectable };
139
- }
@@ -1,7 +0,0 @@
1
- export declare class GrgForward {
2
- static golombEncode(data: Uint8Array, m?: number): Uint8Array;
3
- static redstuffEncode(data: Uint8Array, shards?: number, parity?: number): Uint8Array[];
4
- static deriveHmacKey(chainId: number, poolAddress: string): Buffer;
5
- static golayEncodeWrapper(data: Uint8Array, hmacKey: Buffer): Uint8Array;
6
- static encode(data: Uint8Array, chainId: number, poolAddress: string): Uint8Array[];
7
- }
@@ -1,68 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.GrgForward = void 0;
4
- // sdk/src/grg_forward.ts
5
- const crypto_1 = require("crypto");
6
- const ethers_1 = require("ethers");
7
- const golay_1 = require("./golay");
8
- const reed_solomon_1 = require("./reed_solomon");
9
- class GrgForward {
10
- static golombEncode(data, m = 16) {
11
- if (m < 2)
12
- throw new Error("[GRG] Golomb parameter m must be >= 2");
13
- const k = Math.log2(m);
14
- if (!Number.isInteger(k))
15
- throw new Error("M must be power of 2");
16
- const bits = [];
17
- for (const byte of data) {
18
- const q = Math.floor(byte / m);
19
- const r = byte % m;
20
- for (let i = 0; i < q; i++)
21
- bits.push(1);
22
- bits.push(0);
23
- for (let i = k - 1; i >= 0; i--)
24
- bits.push((r >> i) & 1);
25
- }
26
- const out = new Uint8Array(Math.ceil(bits.length / 8));
27
- for (let i = 0; i < bits.length; i++) {
28
- if (bits[i])
29
- out[i >> 3] |= (0x80 >> (i & 7));
30
- }
31
- return out;
32
- }
33
- static redstuffEncode(data, shards = 4, parity = 2) {
34
- return reed_solomon_1.ReedSolomon.encode(data, shards, parity);
35
- }
36
- static deriveHmacKey(chainId, poolAddress) {
37
- if (chainId === undefined || chainId === null || !poolAddress) {
38
- throw new Error("[GRG] chainId and poolAddress are required for HMAC key derivation. No default key is allowed.");
39
- }
40
- const packed = (0, ethers_1.keccak256)(ethers_1.AbiCoder.defaultAbiCoder().encode(["uint256", "address"], [chainId, poolAddress]));
41
- return Buffer.from(packed.slice(2), "hex");
42
- }
43
- static golayEncodeWrapper(data, hmacKey) {
44
- const encoded = (0, golay_1.golayEncode)(data);
45
- const mac = (0, crypto_1.createHmac)("sha256", hmacKey).update(Buffer.from(encoded)).digest();
46
- const checksum = mac.subarray(0, 8);
47
- const final = new Uint8Array(encoded.length + 8);
48
- final.set(encoded);
49
- final.set(checksum, encoded.length);
50
- return final;
51
- }
52
- static encode(data, chainId, poolAddress) {
53
- if (data.length === 0) {
54
- throw new Error("[GRG] Cannot encode empty input — roundtrip identity violation");
55
- }
56
- const compressed = this.golombEncode(data);
57
- const withLen = new Uint8Array(4 + compressed.length);
58
- withLen[0] = (data.length >> 24) & 0xFF;
59
- withLen[1] = (data.length >> 16) & 0xFF;
60
- withLen[2] = (data.length >> 8) & 0xFF;
61
- withLen[3] = data.length & 0xFF;
62
- withLen.set(compressed, 4);
63
- const shards = this.redstuffEncode(withLen);
64
- const hmacKey = this.deriveHmacKey(chainId, poolAddress);
65
- return shards.map(s => this.golayEncodeWrapper(s, hmacKey));
66
- }
67
- }
68
- exports.GrgForward = GrgForward;
@@ -1,7 +0,0 @@
1
- export declare class GrgInverse {
2
- private static readonly MAX_GOLOMB_Q;
3
- static golayDecodeWrapper(data: Uint8Array, hmacKey: Buffer): Uint8Array;
4
- static redstuffDecode(shards: (Uint8Array | null)[], dataShardCount?: number, parityShardCount?: number): Uint8Array;
5
- static golombDecode(data: Uint8Array, m?: number, originalLength?: number): Uint8Array;
6
- static verify(data: Uint8Array, originalShards: Uint8Array[], chainId: number, poolAddress: string): boolean;
7
- }
@@ -1,93 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.GrgInverse = void 0;
4
- // sdk/src/grg_inverse.ts
5
- const crypto_1 = require("crypto");
6
- const golay_1 = require("./golay");
7
- const grg_forward_1 = require("./grg_forward");
8
- const logger_1 = require("./logger");
9
- const reed_solomon_1 = require("./reed_solomon");
10
- class GrgInverse {
11
- static MAX_GOLOMB_Q = 1000000;
12
- static golayDecodeWrapper(data, hmacKey) {
13
- if (data.length < 8)
14
- throw new Error("GRG shard too short for checksum");
15
- const encoded = data.subarray(0, data.length - 8);
16
- const checksum = data.subarray(data.length - 8);
17
- const mac = (0, crypto_1.createHmac)("sha256", hmacKey).update(Buffer.from(encoded)).digest();
18
- const expected = mac.subarray(0, 8);
19
- if (!Buffer.from(checksum).equals(Buffer.from(expected))) {
20
- throw new Error("GRG tamper detected: HMAC-SHA256 checksum mismatch");
21
- }
22
- const res = (0, golay_1.golayDecode)(encoded);
23
- if (res.uncorrectable) {
24
- throw new Error("GRG tamper detected: uncorrectable bit errors in Golay codeword");
25
- }
26
- return res.data;
27
- }
28
- static redstuffDecode(shards, dataShardCount = 4, parityShardCount = 2) {
29
- return reed_solomon_1.ReedSolomon.decode(shards, dataShardCount, parityShardCount);
30
- }
31
- static golombDecode(data, m = 16, originalLength) {
32
- if (m < 2)
33
- throw new Error("[GRG] Golomb parameter m must be >= 2");
34
- const k = Math.log2(m);
35
- const totalBits = data.length * 8;
36
- const readBit = (pos) => (data[pos >> 3] >> (7 - (pos & 7))) & 1;
37
- const result = [];
38
- let i = 0;
39
- while (i < totalBits) {
40
- if (originalLength !== undefined && result.length >= originalLength)
41
- break;
42
- let q = 0;
43
- while (i < totalBits && readBit(i) === 1) {
44
- q++;
45
- i++;
46
- if (q > this.MAX_GOLOMB_Q)
47
- throw new Error(`[GRG] Golomb decode: unary run exceeds ${this.MAX_GOLOMB_Q} — malformed or malicious input`);
48
- }
49
- if (i < totalBits && readBit(i) === 0)
50
- i++;
51
- if (i + k > totalBits)
52
- break;
53
- let r = 0;
54
- for (let j = 0; j < k; j++)
55
- r = (r << 1) | readBit(i + j);
56
- result.push(q * m + r);
57
- i += k;
58
- }
59
- return new Uint8Array(result);
60
- }
61
- static verify(data, originalShards, chainId, poolAddress) {
62
- try {
63
- const hmacKey = grg_forward_1.GrgForward.deriveHmacKey(chainId, poolAddress);
64
- const decodedShards = originalShards.map(s => {
65
- try {
66
- return this.golayDecodeWrapper(s, hmacKey);
67
- }
68
- catch {
69
- return null;
70
- }
71
- });
72
- const withLen = this.redstuffDecode(decodedShards);
73
- if (withLen.length < 4)
74
- return false;
75
- const origLen = (withLen[0] << 24) | (withLen[1] << 16) | (withLen[2] << 8) | withLen[3];
76
- const compressed = withLen.subarray(4);
77
- const decoded = this.golombDecode(compressed);
78
- const final = decoded.subarray(0, origLen);
79
- if (final.length !== data.length)
80
- return false;
81
- for (let i = 0; i < data.length; i++) {
82
- if (final[i] !== data[i])
83
- return false;
84
- }
85
- return true;
86
- }
87
- catch (e) {
88
- logger_1.logger.warn(`[GRG Inverse] Verification failed: ${e}`);
89
- return false;
90
- }
91
- }
92
- }
93
- exports.GrgInverse = GrgInverse;
@@ -1,5 +0,0 @@
1
- export declare class GrgPipeline {
2
- static readonly MAX_INPUT_SIZE: number;
3
- static processForward(data: Uint8Array, chainId: number, poolAddress: string): Uint8Array[];
4
- static processInverse(shards: (Uint8Array | null)[], originalLength: number, chainId: number, poolAddress: string): Uint8Array;
5
- }
@@ -1,55 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.GrgPipeline = void 0;
4
- // sdk/src/grg_pipeline.ts
5
- const grg_forward_1 = require("./grg_forward");
6
- const grg_inverse_1 = require("./grg_inverse");
7
- const logger_1 = require("./logger");
8
- class GrgPipeline {
9
- static MAX_INPUT_SIZE = 100 * 1024 * 1024; // 100 MB
10
- static processForward(data, chainId, poolAddress) {
11
- if (data.length > this.MAX_INPUT_SIZE) {
12
- throw new Error(`[GRG] Input size ${data.length} exceeds MAX_INPUT_SIZE ${this.MAX_INPUT_SIZE}`);
13
- }
14
- logger_1.logger.info("Starting GRG forward pipeline...");
15
- try {
16
- const shards = grg_forward_1.GrgForward.encode(data, chainId, poolAddress);
17
- logger_1.logger.info(`GRG forward pipeline complete. Generated ${shards.length} shards.`);
18
- return shards;
19
- }
20
- catch (error) {
21
- logger_1.logger.error(`GRG forward pipeline failed: ${error}`);
22
- throw error;
23
- }
24
- }
25
- static processInverse(shards, originalLength, chainId, poolAddress) {
26
- logger_1.logger.info("Starting GRG inverse pipeline...");
27
- try {
28
- const hmacKey = grg_forward_1.GrgForward.deriveHmacKey(chainId, poolAddress);
29
- const decodedShards = shards.map(s => {
30
- try {
31
- return s ? grg_inverse_1.GrgInverse.golayDecodeWrapper(s, hmacKey) : null;
32
- }
33
- catch (e) {
34
- logger_1.logger.warn(`Golay decode failed for a shard: ${e}`);
35
- return null;
36
- }
37
- });
38
- const withLen = grg_inverse_1.GrgInverse.redstuffDecode(decodedShards);
39
- const decodedLength = (withLen[0] << 24) | (withLen[1] << 16) | (withLen[2] << 8) | withLen[3];
40
- const compressed = withLen.subarray(4);
41
- const decompressed = grg_inverse_1.GrgInverse.golombDecode(compressed);
42
- const final = decompressed.subarray(0, decodedLength);
43
- if (final.length !== originalLength) {
44
- throw new Error(`[GRG] Length mismatch in inverse: expected ${originalLength}, got ${final.length}`);
45
- }
46
- logger_1.logger.info("GRG inverse pipeline complete.");
47
- return final;
48
- }
49
- catch (error) {
50
- logger_1.logger.error(`GRG inverse pipeline failed: ${error}`);
51
- throw error;
52
- }
53
- }
54
- }
55
- exports.GrgPipeline = GrgPipeline;
@@ -1,13 +0,0 @@
1
- export declare class ReedSolomon {
2
- private static expTable;
3
- private static logTable;
4
- private static initialized;
5
- private static vandermondeCache;
6
- static init(): void;
7
- static mul(a: number, b: number): number;
8
- static div(a: number, b: number): number;
9
- static invertMatrix(matrix: number[][]): number[][];
10
- static buildVandermonde(rows: number, cols: number): number[][];
11
- static encode(data: Uint8Array, dataShards?: number, parityShards?: number): Uint8Array[];
12
- static decode(shards: (Uint8Array | null)[], dataShards?: number, parityShards?: number): Uint8Array;
13
- }
@@ -1,170 +0,0 @@
1
- "use strict";
2
- // sdk/src/reed_solomon.ts
3
- // Reed-Solomon GF(2^8) erasure coding
4
- Object.defineProperty(exports, "__esModule", { value: true });
5
- exports.ReedSolomon = void 0;
6
- class ReedSolomon {
7
- static expTable = new Uint8Array(256);
8
- static logTable = new Uint8Array(256);
9
- static initialized = false;
10
- static vandermondeCache = new Map();
11
- static init() {
12
- if (this.initialized)
13
- return;
14
- let x = 1;
15
- for (let i = 0; i < 255; i++) {
16
- this.expTable[i] = x;
17
- this.logTable[x] = i;
18
- x <<= 1;
19
- if (x & 0x100) {
20
- x ^= 0x11D; // x^8 + x^4 + x^3 + x^2 + 1
21
- }
22
- }
23
- this.expTable[255] = this.expTable[0];
24
- this.logTable[0] = 0;
25
- this.initialized = true;
26
- }
27
- static mul(a, b) {
28
- if (a === 0 || b === 0)
29
- return 0;
30
- return this.expTable[(this.logTable[a] + this.logTable[b]) % 255];
31
- }
32
- static div(a, b) {
33
- if (b === 0)
34
- throw new Error("Division by zero");
35
- if (a === 0)
36
- return 0;
37
- return this.expTable[(this.logTable[a] - this.logTable[b] + 255) % 255];
38
- }
39
- static invertMatrix(matrix) {
40
- const n = matrix.length;
41
- const aug = [];
42
- for (let i = 0; i < n; i++) {
43
- aug[i] = [];
44
- for (let j = 0; j < n; j++)
45
- aug[i][j] = matrix[i][j];
46
- for (let j = 0; j < n; j++)
47
- aug[i][j + n] = (i === j) ? 1 : 0;
48
- }
49
- for (let i = 0; i < n; i++) {
50
- let pivot = i;
51
- while (pivot < n && aug[pivot][i] === 0)
52
- pivot++;
53
- if (pivot === n)
54
- throw new Error("Singular matrix");
55
- if (pivot !== i) {
56
- const temp = aug[i];
57
- aug[i] = aug[pivot];
58
- aug[pivot] = temp;
59
- }
60
- const pivotVal = aug[i][i];
61
- if (pivotVal !== 1) {
62
- for (let j = i; j < 2 * n; j++)
63
- aug[i][j] = this.div(aug[i][j], pivotVal);
64
- }
65
- for (let j = 0; j < n; j++) {
66
- if (i !== j && aug[j][i] !== 0) {
67
- const factor = aug[j][i];
68
- for (let k = i; k < 2 * n; k++)
69
- aug[j][k] ^= this.mul(factor, aug[i][k]);
70
- }
71
- }
72
- }
73
- const inv = [];
74
- for (let i = 0; i < n; i++) {
75
- inv[i] = [];
76
- for (let j = 0; j < n; j++)
77
- inv[i][j] = aug[i][j + n];
78
- }
79
- return inv;
80
- }
81
- static buildVandermonde(rows, cols) {
82
- const cacheKey = `${rows}-${cols}`;
83
- const cached = this.vandermondeCache.get(cacheKey);
84
- if (cached)
85
- return cached;
86
- const V = [];
87
- for (let r = 0; r < rows; r++) {
88
- V[r] = [];
89
- const x = r + 1;
90
- for (let c = 0; c < cols; c++) {
91
- V[r][c] = c === 0 ? 1 : this.mul(V[r][c - 1], x);
92
- }
93
- }
94
- const V_top = [];
95
- for (let i = 0; i < cols; i++)
96
- V_top.push([...V[i]]);
97
- const V_top_inv = this.invertMatrix(V_top);
98
- const G = [];
99
- for (let r = 0; r < rows; r++) {
100
- G[r] = [];
101
- for (let c = 0; c < cols; c++) {
102
- let val = 0;
103
- for (let k = 0; k < cols; k++)
104
- val ^= this.mul(V[r][k], V_top_inv[k][c]);
105
- G[r][c] = val;
106
- }
107
- }
108
- this.vandermondeCache.set(cacheKey, G);
109
- return G;
110
- }
111
- static encode(data, dataShards = 4, parityShards = 2) {
112
- this.init();
113
- const totalShards = dataShards + parityShards;
114
- const rawShardSize = Math.ceil(data.length / dataShards);
115
- const shardSize = Math.ceil(rawShardSize / 3) * 3;
116
- const matrix = this.buildVandermonde(totalShards, dataShards);
117
- const shards = [];
118
- for (let i = 0; i < totalShards; i++)
119
- shards.push(new Uint8Array(shardSize));
120
- for (let i = 0; i < dataShards; i++) {
121
- shards[i].set(data.subarray(i * shardSize, Math.min((i + 1) * shardSize, data.length)));
122
- }
123
- for (let c = 0; c < shardSize; c++) {
124
- for (let r = dataShards; r < totalShards; r++) {
125
- let val = 0;
126
- for (let j = 0; j < dataShards; j++)
127
- val ^= this.mul(matrix[r][j], shards[j][c]);
128
- shards[r][c] = val;
129
- }
130
- }
131
- return shards;
132
- }
133
- static decode(shards, dataShards = 4, parityShards = 2) {
134
- this.init();
135
- const totalShards = dataShards + parityShards;
136
- if (shards.length !== totalShards) {
137
- throw new Error(`[RS] Expected ${totalShards} shards, got ${shards.length}`);
138
- }
139
- const presentIndices = [];
140
- const presentShards = [];
141
- for (let i = 0; i < totalShards; i++) {
142
- if (shards[i] !== null && shards[i] !== undefined) {
143
- presentIndices.push(i);
144
- presentShards.push(shards[i]);
145
- if (presentIndices.length === dataShards)
146
- break;
147
- }
148
- }
149
- if (presentIndices.length < dataShards) {
150
- throw new Error(`[RS] Not enough shards for recovery: need ${dataShards}, got ${presentIndices.length}`);
151
- }
152
- const shardSize = presentShards[0].length;
153
- const origMatrix = this.buildVandermonde(totalShards, dataShards);
154
- const subMatrix = [];
155
- for (let i = 0; i < dataShards; i++)
156
- subMatrix.push([...origMatrix[presentIndices[i]]]);
157
- const invMatrix = this.invertMatrix(subMatrix);
158
- const result = new Uint8Array(shardSize * dataShards);
159
- for (let c = 0; c < shardSize; c++) {
160
- for (let r = 0; r < dataShards; r++) {
161
- let val = 0;
162
- for (let j = 0; j < dataShards; j++)
163
- val ^= this.mul(invMatrix[r][j], presentShards[j][c]);
164
- result[r * shardSize + c] = val;
165
- }
166
- }
167
- return result;
168
- }
169
- }
170
- exports.ReedSolomon = ReedSolomon;