openttt 0.2.6 → 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/LICENSE +1 -1
- package/README.md +25 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/osnma_source.d.ts +82 -0
- package/dist/osnma_source.js +169 -0
- package/dist/time_synthesis.d.ts +1 -1
- package/dist/time_synthesis.js +1 -1
- package/dist/types.d.ts +1 -1
- package/package.json +47 -3
- package/dist/adaptive_switch.d.ts +0 -59
- package/dist/adaptive_switch.js +0 -145
- package/dist/auto_mint.d.ts +0 -61
- package/dist/auto_mint.js +0 -330
- package/dist/golay.d.ts +0 -7
- package/dist/golay.js +0 -139
- package/dist/grg_forward.d.ts +0 -7
- package/dist/grg_forward.js +0 -68
- package/dist/grg_inverse.d.ts +0 -7
- package/dist/grg_inverse.js +0 -93
- package/dist/grg_pipeline.d.ts +0 -5
- package/dist/grg_pipeline.js +0 -55
- package/dist/reed_solomon.d.ts +0 -13
- package/dist/reed_solomon.js +0 -170
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
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
|
-
}
|
package/dist/grg_forward.d.ts
DELETED
|
@@ -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
|
-
}
|
package/dist/grg_forward.js
DELETED
|
@@ -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;
|
package/dist/grg_inverse.d.ts
DELETED
|
@@ -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
|
-
}
|
package/dist/grg_inverse.js
DELETED
|
@@ -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;
|
package/dist/grg_pipeline.d.ts
DELETED
|
@@ -1,5 +0,0 @@
|
|
|
1
|
-
export declare class GrgPipeline {
|
|
2
|
-
private static readonly MAX_INPUT_SIZE;
|
|
3
|
-
static processForward(data: Uint8Array, chainId: number, poolAddress: string): Uint8Array[];
|
|
4
|
-
static processInverse(shards: (Uint8Array | null)[], originalLength: number, chainId: number, poolAddress: string): Uint8Array;
|
|
5
|
-
}
|