openttt 0.1.0 → 0.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.
@@ -19,6 +19,7 @@ export declare class AutoMintEngine {
19
19
  private cachedSigner;
20
20
  private consecutiveFailures;
21
21
  private maxConsecutiveFailures;
22
+ private potSigner;
22
23
  constructor(config: AutoMintConfig);
23
24
  getEvmConnector(): EVMConnector;
24
25
  setOnMint(callback: (result: MintResult) => void): void;
package/dist/auto_mint.js CHANGED
@@ -7,6 +7,7 @@ const time_synthesis_1 = require("./time_synthesis");
7
7
  const dynamic_fee_1 = require("./dynamic_fee");
8
8
  const evm_connector_1 = require("./evm_connector");
9
9
  const protocol_fee_1 = require("./protocol_fee");
10
+ const pot_signer_1 = require("./pot_signer");
10
11
  const types_1 = require("./types");
11
12
  const logger_1 = require("./logger");
12
13
  const errors_1 = require("./errors");
@@ -29,6 +30,7 @@ class AutoMintEngine {
29
30
  cachedSigner = null;
30
31
  consecutiveFailures = 0;
31
32
  maxConsecutiveFailures = 5;
33
+ potSigner = null;
32
34
  constructor(config) {
33
35
  this.config = config;
34
36
  this.timeSynthesis = new time_synthesis_1.TimeSynthesis({ sources: config.timeSources });
@@ -40,6 +42,8 @@ class AutoMintEngine {
40
42
  if (config.signer) {
41
43
  this.cachedSigner = config.signer;
42
44
  }
45
+ // Initialize Ed25519 PoT signer for non-repudiation
46
+ this.potSigner = new pot_signer_1.PotSigner();
43
47
  }
44
48
  getEvmConnector() {
45
49
  return this.evmConnector;
@@ -162,6 +166,11 @@ class AutoMintEngine {
162
166
  throw new errors_1.TTTTimeSynthesisError(`[PoT] Insufficient confidence`, `Calculated confidence ${pot.confidence} is below required 0.5`, `Ensure more NTP sources are reachable or decrease uncertainty.`);
163
167
  }
164
168
  const potHash = ethers_1.ethers.keccak256(ethers_1.ethers.toUtf8Bytes(JSON.stringify(pot, (key, value) => typeof value === 'bigint' ? value.toString() : value)));
169
+ // 1-2. Ed25519 issuer signature for non-repudiation
170
+ if (this.potSigner) {
171
+ pot.issuerSignature = this.potSigner.signPot(potHash);
172
+ logger_1.logger.info(`[AutoMint] PoT signed by issuer ${this.potSigner.getPubKeyHex().substring(0, 16)}...`);
173
+ }
165
174
  // 2. tokenId 생성 (keccak256)
166
175
  // chainId, poolAddress, timestamp 기반 유니크 ID
167
176
  const tokenId = ethers_1.ethers.keccak256(ethers_1.ethers.AbiCoder.defaultAbiCoder().encode(["uint256", "address", "uint64"], [BigInt(this.config.chainId), this.config.poolAddress, synthesized.timestamp]));
@@ -1,6 +1,11 @@
1
1
  export declare class GrgForward {
2
2
  static golombEncode(data: Uint8Array, m?: number): Uint8Array;
3
3
  static redstuffEncode(data: Uint8Array, shards?: number, parity?: number): Uint8Array[];
4
- static golayEncodeWrapper(data: Uint8Array): Uint8Array;
5
- static encode(data: Uint8Array): Uint8Array[];
4
+ /**
5
+ * Derives an HMAC key from GRG payload context (chainId + poolAddress).
6
+ * Falls back to a static domain-separation key when no context is provided.
7
+ */
8
+ static deriveHmacKey(chainId?: number, poolAddress?: string): Buffer;
9
+ static golayEncodeWrapper(data: Uint8Array, hmacKey?: Buffer): Uint8Array;
10
+ static encode(data: Uint8Array, chainId?: number, poolAddress?: string): Uint8Array[];
6
11
  }
@@ -2,6 +2,7 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.GrgForward = void 0;
4
4
  const crypto_1 = require("crypto");
5
+ const ethers_1 = require("ethers");
5
6
  const golay_1 = require("./golay");
6
7
  const reed_solomon_1 = require("./reed_solomon");
7
8
  class GrgForward {
@@ -28,18 +29,31 @@ class GrgForward {
28
29
  static redstuffEncode(data, shards = 4, parity = 2) {
29
30
  return reed_solomon_1.ReedSolomon.encode(data, shards, parity);
30
31
  }
32
+ /**
33
+ * Derives an HMAC key from GRG payload context (chainId + poolAddress).
34
+ * Falls back to a static domain-separation key when no context is provided.
35
+ */
36
+ static deriveHmacKey(chainId, poolAddress) {
37
+ if (chainId !== undefined && poolAddress) {
38
+ const packed = (0, ethers_1.keccak256)(ethers_1.AbiCoder.defaultAbiCoder().encode(["uint256", "address"], [chainId, poolAddress]));
39
+ return Buffer.from(packed.slice(2), "hex"); // 32 bytes
40
+ }
41
+ // Default domain-separation key when no context is available
42
+ return Buffer.from("grg-integrity-hmac-default-key-v1");
43
+ }
31
44
  // 3. Golay(24,12) Error Correction Encoding
32
- static golayEncodeWrapper(data) {
45
+ static golayEncodeWrapper(data, hmacKey) {
33
46
  const encoded = (0, golay_1.golayEncode)(data);
34
- // 🔱 Integrity: Append 8-byte SHA-256 hash of the encoded shard (B1-5: 4 -> 8 bytes)
35
- const hash = (0, crypto_1.createHash)("sha256").update(Buffer.from(encoded)).digest();
36
- const checksum = hash.subarray(0, 8);
47
+ // 🔱 Integrity: Append 8-byte HMAC-SHA256 of the encoded shard (keyed hash)
48
+ const key = hmacKey || this.deriveHmacKey();
49
+ const mac = (0, crypto_1.createHmac)("sha256", key).update(Buffer.from(encoded)).digest();
50
+ const checksum = mac.subarray(0, 8);
37
51
  const final = new Uint8Array(encoded.length + 8);
38
52
  final.set(encoded);
39
53
  final.set(checksum, encoded.length);
40
54
  return final;
41
55
  }
42
- static encode(data) {
56
+ static encode(data, chainId, poolAddress) {
43
57
  // R3-P0-3: Reject empty input — roundtrip breaks ([] → [0])
44
58
  if (data.length === 0) {
45
59
  throw new Error("[GRG] Cannot encode empty input — roundtrip identity violation");
@@ -53,7 +67,8 @@ class GrgForward {
53
67
  withLen[3] = data.length & 0xFF;
54
68
  withLen.set(compressed, 4);
55
69
  const shards = this.redstuffEncode(withLen);
56
- return shards.map(s => this.golayEncodeWrapper(s));
70
+ const hmacKey = this.deriveHmacKey(chainId, poolAddress);
71
+ return shards.map(s => this.golayEncodeWrapper(s, hmacKey));
57
72
  }
58
73
  }
59
74
  exports.GrgForward = GrgForward;
@@ -1,7 +1,7 @@
1
1
  export declare class GrgInverse {
2
- static golayDecodeWrapper(data: Uint8Array): Uint8Array;
2
+ static golayDecodeWrapper(data: Uint8Array, hmacKey?: Buffer): Uint8Array;
3
3
  static redstuffDecode(shards: (Uint8Array | null)[], dataShardCount?: number, parityShardCount?: number): Uint8Array;
4
4
  private static readonly MAX_GOLOMB_Q;
5
5
  static golombDecode(data: Uint8Array, m?: number): Uint8Array;
6
- static verify(data: Uint8Array, originalShards: Uint8Array[]): boolean;
6
+ static verify(data: Uint8Array, originalShards: Uint8Array[], chainId?: number, poolAddress?: string): boolean;
7
7
  }
@@ -3,21 +3,23 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.GrgInverse = void 0;
4
4
  const crypto_1 = require("crypto");
5
5
  const golay_1 = require("./golay");
6
+ const grg_forward_1 = require("./grg_forward");
6
7
  const logger_1 = require("./logger");
7
8
  const reed_solomon_1 = require("./reed_solomon");
8
9
  class GrgInverse {
9
10
  // 1. Golay Decoding & Integrity Check 🔱
10
- static golayDecodeWrapper(data) {
11
+ static golayDecodeWrapper(data, hmacKey) {
11
12
  if (data.length < 8)
12
13
  throw new Error("GRG shard too short for checksum");
13
14
  // Split data and checksum (last 8 bytes)
14
15
  const encoded = data.subarray(0, data.length - 8);
15
16
  const checksum = data.subarray(data.length - 8);
16
- // Verify SHA-256 Checksum (B1-5: 4 -> 8 bytes)
17
- const hash = (0, crypto_1.createHash)("sha256").update(Buffer.from(encoded)).digest();
18
- const expected = hash.subarray(0, 8);
17
+ // Verify HMAC-SHA256 Checksum (keyed hash, B1-5: 8 bytes truncated)
18
+ const key = hmacKey || grg_forward_1.GrgForward.deriveHmacKey();
19
+ const mac = (0, crypto_1.createHmac)("sha256", key).update(Buffer.from(encoded)).digest();
20
+ const expected = mac.subarray(0, 8);
19
21
  if (!Buffer.from(checksum).equals(Buffer.from(expected))) {
20
- throw new Error("GRG tamper detected: SHA-256 checksum mismatch");
22
+ throw new Error("GRG tamper detected: HMAC-SHA256 checksum mismatch");
21
23
  }
22
24
  // Proceed to Golay decode
23
25
  const res = (0, golay_1.golayDecode)(encoded);
@@ -62,11 +64,12 @@ class GrgInverse {
62
64
  }
63
65
  return new Uint8Array(result);
64
66
  }
65
- static verify(data, originalShards) {
67
+ static verify(data, originalShards, chainId, poolAddress) {
66
68
  try {
69
+ const hmacKey = grg_forward_1.GrgForward.deriveHmacKey(chainId, poolAddress);
67
70
  const decodedShards = originalShards.map(s => {
68
71
  try {
69
- return this.golayDecodeWrapper(s);
72
+ return this.golayDecodeWrapper(s, hmacKey);
70
73
  }
71
74
  catch {
72
75
  return null;
package/dist/index.d.ts CHANGED
@@ -19,3 +19,4 @@ export * from "./signer";
19
19
  export * from "./networks";
20
20
  export * from "./reed_solomon";
21
21
  export * from "./errors";
22
+ export * from "./pot_signer";
package/dist/index.js CHANGED
@@ -36,3 +36,4 @@ __exportStar(require("./signer"), exports);
36
36
  __exportStar(require("./networks"), exports);
37
37
  __exportStar(require("./reed_solomon"), exports);
38
38
  __exportStar(require("./errors"), exports);
39
+ __exportStar(require("./pot_signer"), exports);
@@ -0,0 +1,29 @@
1
+ export interface PotSignature {
2
+ issuerPubKey: string;
3
+ signature: string;
4
+ issuedAt: bigint;
5
+ }
6
+ export declare class PotSigner {
7
+ private privateKey;
8
+ private publicKey;
9
+ private pubKeyHex;
10
+ constructor(privateKeyHex?: string);
11
+ /** Returns the hex-encoded SPKI DER public key */
12
+ getPubKeyHex(): string;
13
+ /** Returns the hex-encoded PKCS8 DER private key (for persistence) */
14
+ getPrivateKeyHex(): string;
15
+ /**
16
+ * Sign a PoT hash with Ed25519.
17
+ * @param potHash - hex string (with or without 0x prefix) of the PoT hash
18
+ * @returns PotSignature with issuerPubKey, signature, and issuedAt
19
+ */
20
+ signPot(potHash: string): PotSignature;
21
+ /**
22
+ * Verify a PotSignature against a PoT hash.
23
+ * @param potHash - hex string (with or without 0x prefix)
24
+ * @param potSig - the PotSignature to verify
25
+ * @param expectedPubKey - optional: reject if issuerPubKey doesn't match
26
+ * @returns true if signature is valid
27
+ */
28
+ static verifyPotSignature(potHash: string, potSig: PotSignature, expectedPubKey?: string): boolean;
29
+ }
@@ -0,0 +1,73 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.PotSigner = void 0;
4
+ // sdk/src/pot_signer.ts — Ed25519 signing for Proof of Time (Non-repudiation)
5
+ // Uses Node.js built-in crypto.sign/verify with Ed25519
6
+ const crypto_1 = require("crypto");
7
+ class PotSigner {
8
+ privateKey;
9
+ publicKey;
10
+ pubKeyHex;
11
+ constructor(privateKeyHex) {
12
+ if (privateKeyHex) {
13
+ // Import existing key from PKCS8 DER hex
14
+ const keyBuffer = Buffer.from(privateKeyHex, 'hex');
15
+ this.privateKey = (0, crypto_1.createPrivateKey)({ key: keyBuffer, format: 'der', type: 'pkcs8' });
16
+ this.publicKey = (0, crypto_1.createPublicKey)(this.privateKey);
17
+ }
18
+ else {
19
+ // Generate new Ed25519 keypair
20
+ const { privateKey, publicKey } = (0, crypto_1.generateKeyPairSync)('ed25519');
21
+ this.privateKey = privateKey;
22
+ this.publicKey = publicKey;
23
+ }
24
+ this.pubKeyHex = this.publicKey.export({ type: 'spki', format: 'der' }).toString('hex');
25
+ }
26
+ /** Returns the hex-encoded SPKI DER public key */
27
+ getPubKeyHex() {
28
+ return this.pubKeyHex;
29
+ }
30
+ /** Returns the hex-encoded PKCS8 DER private key (for persistence) */
31
+ getPrivateKeyHex() {
32
+ return this.privateKey.export({ type: 'pkcs8', format: 'der' }).toString('hex');
33
+ }
34
+ /**
35
+ * Sign a PoT hash with Ed25519.
36
+ * @param potHash - hex string (with or without 0x prefix) of the PoT hash
37
+ * @returns PotSignature with issuerPubKey, signature, and issuedAt
38
+ */
39
+ signPot(potHash) {
40
+ const data = Buffer.from(potHash.startsWith('0x') ? potHash.slice(2) : potHash, 'hex');
41
+ const sig = (0, crypto_1.sign)(null, data, this.privateKey);
42
+ return {
43
+ issuerPubKey: this.pubKeyHex,
44
+ signature: sig.toString('hex'),
45
+ issuedAt: BigInt(Math.floor(Date.now() / 1000)),
46
+ };
47
+ }
48
+ /**
49
+ * Verify a PotSignature against a PoT hash.
50
+ * @param potHash - hex string (with or without 0x prefix)
51
+ * @param potSig - the PotSignature to verify
52
+ * @param expectedPubKey - optional: reject if issuerPubKey doesn't match
53
+ * @returns true if signature is valid
54
+ */
55
+ static verifyPotSignature(potHash, potSig, expectedPubKey) {
56
+ if (expectedPubKey && potSig.issuerPubKey !== expectedPubKey)
57
+ return false;
58
+ try {
59
+ const data = Buffer.from(potHash.startsWith('0x') ? potHash.slice(2) : potHash, 'hex');
60
+ const sigBuffer = Buffer.from(potSig.signature, 'hex');
61
+ const pubKey = (0, crypto_1.createPublicKey)({
62
+ key: Buffer.from(potSig.issuerPubKey, 'hex'),
63
+ format: 'der',
64
+ type: 'spki',
65
+ });
66
+ return (0, crypto_1.verify)(null, data, pubKey, sigBuffer);
67
+ }
68
+ catch {
69
+ return false;
70
+ }
71
+ }
72
+ }
73
+ exports.PotSigner = PotSigner;
@@ -13,6 +13,9 @@ export declare class NTPSource implements TimeSource {
13
13
  }
14
14
  export declare class TimeSynthesis {
15
15
  private sources;
16
+ private usedNonces;
17
+ private readonly MAX_NONCE_CACHE;
18
+ private readonly NONCE_TTL_MS;
16
19
  constructor(config?: {
17
20
  sources?: string[];
18
21
  });
@@ -24,6 +27,8 @@ export declare class TimeSynthesis {
24
27
  generateProofOfTime(): Promise<ProofOfTime>;
25
28
  /**
26
29
  * Verify Proof of Time integrity.
30
+ * Fix 2: Checks expiration and nonce replay.
31
+ * Fix 3: Uses sourceReadings (renamed from signatures).
27
32
  */
28
33
  verifyProofOfTime(pot: ProofOfTime): boolean;
29
34
  /**
@@ -40,6 +45,7 @@ export declare class TimeSynthesis {
40
45
  static deserializeFromJSON(json: string): ProofOfTime;
41
46
  /**
42
47
  * Serializes PoT to compact binary format.
48
+ * Layout: header(19) + nonce(1+N) + expiresAt(8) + readings(variable)
43
49
  */
44
50
  static serializeToBinary(pot: ProofOfTime): Buffer;
45
51
  /**
@@ -34,6 +34,7 @@ var __importStar = (this && this.__importStar) || (function () {
34
34
  })();
35
35
  Object.defineProperty(exports, "__esModule", { value: true });
36
36
  exports.TimeSynthesis = exports.NTPSource = void 0;
37
+ const crypto = __importStar(require("crypto"));
37
38
  const dgram = __importStar(require("dgram"));
38
39
  const buffer_1 = require("buffer");
39
40
  const ethers_1 = require("ethers");
@@ -132,6 +133,10 @@ class NTPSource {
132
133
  exports.NTPSource = NTPSource;
133
134
  class TimeSynthesis {
134
135
  sources = [];
136
+ // Fix 2: Bounded nonce replay cache (max 10K entries, 60s TTL) — same pattern as protocol_fee.ts
137
+ usedNonces = new Map();
138
+ MAX_NONCE_CACHE = 10000;
139
+ NONCE_TTL_MS = 60000; // 60 seconds
135
140
  constructor(config) {
136
141
  const sourceNames = config?.sources || ['nist', 'kriss', 'google'];
137
142
  for (const s of sourceNames) {
@@ -233,18 +238,23 @@ class TimeSynthesis {
233
238
  finalUncertainty = readings[mid].uncertainty;
234
239
  finalStratum = readings[mid].stratum;
235
240
  }
236
- const signatures = readings.map(r => ({
241
+ const sourceReadings = readings.map(r => ({
237
242
  source: r.source,
238
243
  timestamp: r.timestamp,
239
244
  uncertainty: r.uncertainty
240
245
  }));
246
+ // Fix 2: PoT nonce + expiration for replay protection
247
+ const nonce = crypto.randomBytes(16).toString("hex");
248
+ const expiresAt = BigInt(Date.now()) + 60000n; // +60 seconds
241
249
  const pot = {
242
250
  timestamp: finalTimestamp,
243
251
  uncertainty: finalUncertainty,
244
252
  sources: readings.length,
245
253
  stratum: finalStratum,
246
254
  confidence: readings.length / this.sources.length,
247
- signatures
255
+ sourceReadings,
256
+ nonce,
257
+ expiresAt,
248
258
  };
249
259
  // Verification Logic: Ensure all source timestamps are within tolerance of synthesized median
250
260
  if (!this.verifyProofOfTime(pot)) {
@@ -254,17 +264,44 @@ class TimeSynthesis {
254
264
  }
255
265
  /**
256
266
  * Verify Proof of Time integrity.
267
+ * Fix 2: Checks expiration and nonce replay.
268
+ * Fix 3: Uses sourceReadings (renamed from signatures).
257
269
  */
258
270
  verifyProofOfTime(pot) {
259
271
  const TOLERANCE_NS = 100000000n; // 100ms
260
- if (pot.signatures.length === 0)
272
+ if (pot.sourceReadings.length === 0)
261
273
  return false;
262
274
  if (pot.confidence <= 0)
263
275
  return false;
264
- for (const sig of pot.signatures) {
276
+ // Fix 2: Expiration check
277
+ if (BigInt(Date.now()) > pot.expiresAt) {
278
+ logger_1.logger.warn(`[TimeSynthesis] PoT expired at ${pot.expiresAt}`);
279
+ return false;
280
+ }
281
+ // Fix 2: Nonce replay protection with bounded cache + TTL cleanup
282
+ const now = Date.now();
283
+ // TTL cleanup pass (evict expired entries)
284
+ if (this.usedNonces.size > this.MAX_NONCE_CACHE / 2) {
285
+ for (const [k, ts] of this.usedNonces) {
286
+ if (now - ts > this.NONCE_TTL_MS)
287
+ this.usedNonces.delete(k);
288
+ }
289
+ }
290
+ if (this.usedNonces.has(pot.nonce)) {
291
+ logger_1.logger.warn(`[TimeSynthesis] Duplicate nonce detected: ${pot.nonce}`);
292
+ return false;
293
+ }
294
+ if (this.usedNonces.size >= this.MAX_NONCE_CACHE) {
295
+ // Evict oldest entry
296
+ const oldest = this.usedNonces.keys().next().value;
297
+ if (oldest !== undefined)
298
+ this.usedNonces.delete(oldest);
299
+ }
300
+ this.usedNonces.set(pot.nonce, now);
301
+ for (const sig of pot.sourceReadings) {
265
302
  const diff = sig.timestamp > pot.timestamp ? sig.timestamp - pot.timestamp : pot.timestamp - sig.timestamp;
266
303
  if (diff > TOLERANCE_NS) {
267
- logger_1.logger.warn(`[TimeSynthesis] Signature from ${sig.source} outside tolerance: ${diff}ns`);
304
+ logger_1.logger.warn(`[TimeSynthesis] Reading from ${sig.source} outside tolerance: ${diff}ns`);
268
305
  return false;
269
306
  }
270
307
  }
@@ -296,7 +333,8 @@ class TimeSynthesis {
296
333
  return {
297
334
  ...data,
298
335
  timestamp: BigInt(data.timestamp),
299
- signatures: data.signatures.map((s) => ({
336
+ expiresAt: BigInt(data.expiresAt),
337
+ sourceReadings: data.sourceReadings.map((s) => ({
300
338
  ...s,
301
339
  timestamp: BigInt(s.timestamp)
302
340
  }))
@@ -304,11 +342,14 @@ class TimeSynthesis {
304
342
  }
305
343
  /**
306
344
  * Serializes PoT to compact binary format.
345
+ * Layout: header(19) + nonce(1+N) + expiresAt(8) + readings(variable)
307
346
  */
308
347
  static serializeToBinary(pot) {
309
- // Header: timestamp(8), uncertainty(4), sources(1), stratum(1), confidence(4), sigCount(1) = 19 bytes
310
- let size = 19;
311
- for (const sig of pot.signatures) {
348
+ const nonceBytes = buffer_1.Buffer.from(pot.nonce, "utf8");
349
+ // Header: timestamp(8) + uncertainty(4) + sources(1) + stratum(1) + confidence(4) + readingCount(1) = 19
350
+ // + nonceLen(1) + nonce(N) + expiresAt(8)
351
+ let size = 19 + 1 + nonceBytes.length + 8;
352
+ for (const sig of pot.sourceReadings) {
312
353
  size += 1 + sig.source.length + 8 + 4; // nameLen(1) + name(N) + ts(8) + unc(4)
313
354
  }
314
355
  const buf = buffer_1.Buffer.alloc(size);
@@ -323,9 +364,17 @@ class TimeSynthesis {
323
364
  offset += 1;
324
365
  buf.writeFloatBE(pot.confidence, offset);
325
366
  offset += 4;
326
- buf.writeUInt8(pot.signatures.length, offset);
367
+ buf.writeUInt8(pot.sourceReadings.length, offset);
368
+ offset += 1;
369
+ // Nonce
370
+ buf.writeUInt8(nonceBytes.length, offset);
327
371
  offset += 1;
328
- for (const sig of pot.signatures) {
372
+ nonceBytes.copy(buf, offset);
373
+ offset += nonceBytes.length;
374
+ // ExpiresAt
375
+ buf.writeBigUInt64BE(pot.expiresAt, offset);
376
+ offset += 8;
377
+ for (const sig of pot.sourceReadings) {
329
378
  buf.writeUInt8(sig.source.length, offset);
330
379
  offset += 1;
331
380
  buf.write(sig.source, offset);
@@ -354,7 +403,15 @@ class TimeSynthesis {
354
403
  offset += 4;
355
404
  const sigCount = buf.readUInt8(offset);
356
405
  offset += 1;
357
- const signatures = [];
406
+ // Nonce
407
+ const nonceLen = buf.readUInt8(offset);
408
+ offset += 1;
409
+ const nonce = buf.toString('utf8', offset, offset + nonceLen);
410
+ offset += nonceLen;
411
+ // ExpiresAt
412
+ const expiresAt = buf.readBigUInt64BE(offset);
413
+ offset += 8;
414
+ const sourceReadings = [];
358
415
  for (let i = 0; i < sigCount; i++) {
359
416
  const nameLen = buf.readUInt8(offset);
360
417
  offset += 1;
@@ -364,9 +421,9 @@ class TimeSynthesis {
364
421
  offset += 8;
365
422
  const unc = buf.readFloatBE(offset);
366
423
  offset += 4;
367
- signatures.push({ source, timestamp: ts, uncertainty: unc });
424
+ sourceReadings.push({ source, timestamp: ts, uncertainty: unc });
368
425
  }
369
- return { timestamp, uncertainty, sources, stratum, confidence, signatures };
426
+ return { timestamp, uncertainty, sources, stratum, confidence, sourceReadings, nonce, expiresAt };
370
427
  }
371
428
  }
372
429
  exports.TimeSynthesis = TimeSynthesis;
package/dist/types.d.ts CHANGED
@@ -1,6 +1,7 @@
1
1
  import { Signer } from "ethers";
2
2
  import { SignerConfig } from "./signer";
3
3
  import { NetworkConfig } from "./networks";
4
+ import { PotSignature } from "./pot_signer";
4
5
  export type TierType = "T0_epoch" | "T1_block" | "T2_slot" | "T3_micro";
5
6
  export declare const TierIntervals: Record<TierType, number>;
6
7
  /**
@@ -133,9 +134,13 @@ export interface ProofOfTime {
133
134
  sources: number;
134
135
  stratum: number;
135
136
  confidence: number;
136
- signatures: {
137
+ sourceReadings: {
137
138
  source: string;
138
139
  timestamp: bigint;
139
140
  uncertainty: number;
140
141
  }[];
142
+ nonce: string;
143
+ expiresAt: bigint;
144
+ issuerSignature?: PotSignature;
141
145
  }
146
+ export type { PotSignature } from "./pot_signer";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "openttt",
3
- "version": "0.1.0",
3
+ "version": "0.1.1",
4
4
  "description": "OpenTTT — TLS-grade transaction ordering for DeFi. Time + Logic + Sync.",
5
5
  "license": "BSL-1.1",
6
6
  "repository": {