@certivu/cli 1.1.0
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/dist/index.js +1707 -0
- package/package.json +25 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,1707 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";
|
|
3
|
+
var __create = Object.create;
|
|
4
|
+
var __defProp = Object.defineProperty;
|
|
5
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
6
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
7
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
8
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
9
|
+
var __copyProps = (to, from, except, desc) => {
|
|
10
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
11
|
+
for (let key of __getOwnPropNames(from))
|
|
12
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
13
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
14
|
+
}
|
|
15
|
+
return to;
|
|
16
|
+
};
|
|
17
|
+
var __toESM = (mod2, isNodeMode, target) => (target = mod2 != null ? __create(__getProtoOf(mod2)) : {}, __copyProps(
|
|
18
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
19
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
20
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
21
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
22
|
+
isNodeMode || !mod2 || !mod2.__esModule ? __defProp(target, "default", { value: mod2, enumerable: true }) : target,
|
|
23
|
+
mod2
|
|
24
|
+
));
|
|
25
|
+
|
|
26
|
+
// src/config.ts
|
|
27
|
+
var import_node_fs = require("fs");
|
|
28
|
+
var import_node_os = require("os");
|
|
29
|
+
var import_node_path = require("path");
|
|
30
|
+
var CONFIG_PATH = (0, import_node_path.join)((0, import_node_os.homedir)(), ".config", "certivu", "config.json");
|
|
31
|
+
async function loadConfig() {
|
|
32
|
+
const fromEnv = {
|
|
33
|
+
...process.env.CERTIVU_API_KEY ? { apiKey: process.env.CERTIVU_API_KEY } : {},
|
|
34
|
+
...process.env.CERTIVU_GENERATOR_ID ? { generatorId: process.env.CERTIVU_GENERATOR_ID } : {},
|
|
35
|
+
...process.env.CERTIVU_PRIVATE_KEY ? { privateKey: process.env.CERTIVU_PRIVATE_KEY } : {},
|
|
36
|
+
...process.env.CERTIVU_BASE_URL ? { baseUrl: process.env.CERTIVU_BASE_URL } : {}
|
|
37
|
+
};
|
|
38
|
+
let fromFile = {};
|
|
39
|
+
try {
|
|
40
|
+
const raw = (0, import_node_fs.readFileSync)(CONFIG_PATH, "utf8");
|
|
41
|
+
fromFile = JSON.parse(raw);
|
|
42
|
+
} catch {
|
|
43
|
+
}
|
|
44
|
+
const merged = {};
|
|
45
|
+
const apiKey = fromEnv.apiKey ?? fromFile.apiKey;
|
|
46
|
+
const generatorId = fromEnv.generatorId ?? fromFile.generatorId;
|
|
47
|
+
const privateKey = fromEnv.privateKey ?? fromFile.privateKey;
|
|
48
|
+
const baseUrl = fromEnv.baseUrl ?? fromFile.baseUrl ?? "https://api.certivu.ai";
|
|
49
|
+
if (apiKey) merged.apiKey = apiKey;
|
|
50
|
+
if (generatorId) merged.generatorId = generatorId;
|
|
51
|
+
if (privateKey) merged.privateKey = privateKey;
|
|
52
|
+
merged.baseUrl = baseUrl;
|
|
53
|
+
return merged;
|
|
54
|
+
}
|
|
55
|
+
async function saveConfig(updates) {
|
|
56
|
+
const existing = await loadConfig();
|
|
57
|
+
const merged = { ...existing, ...updates };
|
|
58
|
+
(0, import_node_fs.mkdirSync)((0, import_node_path.dirname)(CONFIG_PATH), { recursive: true });
|
|
59
|
+
(0, import_node_fs.writeFileSync)(CONFIG_PATH, JSON.stringify(merged, null, 2), "utf8");
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// src/ui.ts
|
|
63
|
+
var c = {
|
|
64
|
+
reset: "\x1B[0m",
|
|
65
|
+
bold: "\x1B[1m",
|
|
66
|
+
dim: "\x1B[2m",
|
|
67
|
+
green: "\x1B[32m",
|
|
68
|
+
red: "\x1B[31m",
|
|
69
|
+
yellow: "\x1B[33m",
|
|
70
|
+
cyan: "\x1B[36m",
|
|
71
|
+
white: "\x1B[37m",
|
|
72
|
+
gray: "\x1B[90m"
|
|
73
|
+
};
|
|
74
|
+
var isTTY = process.stdout.isTTY;
|
|
75
|
+
var paint = (code, text) => isTTY ? `${code}${text}${c.reset}` : text;
|
|
76
|
+
var ok = (msg) => paint(c.green + c.bold, `\u2713 ${msg}`);
|
|
77
|
+
var err = (msg) => paint(c.red + c.bold, `\u2717 ${msg}`);
|
|
78
|
+
var warn = (msg) => paint(c.yellow, `\u26A0 ${msg}`);
|
|
79
|
+
var label = (s) => paint(c.gray, s.padEnd(12));
|
|
80
|
+
var value = (s) => paint(c.white, s);
|
|
81
|
+
var dim = (s) => paint(c.dim, s);
|
|
82
|
+
var bold = (s) => paint(c.bold, s);
|
|
83
|
+
var amber = (s) => paint(c.yellow + c.bold, s);
|
|
84
|
+
function row(key, val) {
|
|
85
|
+
console.log(` ${label(key)}${value(val)}`);
|
|
86
|
+
}
|
|
87
|
+
function die(msg, code = 1) {
|
|
88
|
+
console.error(err(msg));
|
|
89
|
+
process.exit(code);
|
|
90
|
+
}
|
|
91
|
+
function confidenceBadge(confidence) {
|
|
92
|
+
switch (confidence) {
|
|
93
|
+
case "high":
|
|
94
|
+
return paint(c.green + c.bold, "HIGH");
|
|
95
|
+
case "medium":
|
|
96
|
+
return paint(c.yellow + c.bold, "MEDIUM");
|
|
97
|
+
case "low":
|
|
98
|
+
return paint(c.yellow, "LOW");
|
|
99
|
+
default:
|
|
100
|
+
return paint(c.gray, "NONE");
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
// src/commands/config.ts
|
|
105
|
+
var VALID_KEYS = ["api-key", "generator-id", "private-key", "base-url"];
|
|
106
|
+
var KEY_MAP = {
|
|
107
|
+
"api-key": "apiKey",
|
|
108
|
+
"generator-id": "generatorId",
|
|
109
|
+
"private-key": "privateKey",
|
|
110
|
+
"base-url": "baseUrl"
|
|
111
|
+
};
|
|
112
|
+
async function configCommand(sub, key, value2) {
|
|
113
|
+
if (sub === "set") {
|
|
114
|
+
if (!key || !value2) die("Usage: certivu config set <key> <value>");
|
|
115
|
+
if (!VALID_KEYS.includes(key)) {
|
|
116
|
+
die(`Unknown config key: ${key}
|
|
117
|
+
Valid keys: ${VALID_KEYS.join(", ")}`);
|
|
118
|
+
}
|
|
119
|
+
const field = KEY_MAP[key];
|
|
120
|
+
await saveConfig({ [field]: value2 });
|
|
121
|
+
console.log(ok(`Saved ${key}`));
|
|
122
|
+
return;
|
|
123
|
+
}
|
|
124
|
+
if (sub === "get" || sub === void 0) {
|
|
125
|
+
const config = await loadConfig();
|
|
126
|
+
row("api-key", config.apiKey ? `${config.apiKey.slice(0, 12)}...` : "(not set)");
|
|
127
|
+
row("generator-id", config.generatorId ?? "(not set)");
|
|
128
|
+
row("private-key", config.privateKey ? "(set)" : "(not set)");
|
|
129
|
+
row("base-url", config.baseUrl ?? "https://api.certivu.ai");
|
|
130
|
+
return;
|
|
131
|
+
}
|
|
132
|
+
die(`Unknown config subcommand: ${sub}
|
|
133
|
+
Usage: certivu config [get|set <key> <value>]`);
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
// src/commands/sign.ts
|
|
137
|
+
var import_node_fs2 = require("fs");
|
|
138
|
+
|
|
139
|
+
// ../../packages/sdk/dist/index.js
|
|
140
|
+
var nc = __toESM(require("crypto"));
|
|
141
|
+
async function getAuditLog(baseUrl, apiKey, options = {}) {
|
|
142
|
+
const page = options.page ?? 1;
|
|
143
|
+
const limit = options.limit ?? 20;
|
|
144
|
+
const res = await fetch(`${baseUrl}/v1/audit?page=${page}&limit=${limit}`, {
|
|
145
|
+
headers: { Authorization: `Bearer ${apiKey}` }
|
|
146
|
+
});
|
|
147
|
+
if (!res.ok) {
|
|
148
|
+
const err2 = await res.json().catch(() => ({}));
|
|
149
|
+
throw new Error(err2.error ?? `HTTP ${res.status}`);
|
|
150
|
+
}
|
|
151
|
+
return res.json();
|
|
152
|
+
}
|
|
153
|
+
var U32_MASK64 = /* @__PURE__ */ BigInt(2 ** 32 - 1);
|
|
154
|
+
var _32n = /* @__PURE__ */ BigInt(32);
|
|
155
|
+
function fromBig(n, le = false) {
|
|
156
|
+
if (le)
|
|
157
|
+
return { h: Number(n & U32_MASK64), l: Number(n >> _32n & U32_MASK64) };
|
|
158
|
+
return { h: Number(n >> _32n & U32_MASK64) | 0, l: Number(n & U32_MASK64) | 0 };
|
|
159
|
+
}
|
|
160
|
+
function split(lst, le = false) {
|
|
161
|
+
const len = lst.length;
|
|
162
|
+
let Ah = new Uint32Array(len);
|
|
163
|
+
let Al = new Uint32Array(len);
|
|
164
|
+
for (let i = 0; i < len; i++) {
|
|
165
|
+
const { h, l } = fromBig(lst[i], le);
|
|
166
|
+
[Ah[i], Al[i]] = [h, l];
|
|
167
|
+
}
|
|
168
|
+
return [Ah, Al];
|
|
169
|
+
}
|
|
170
|
+
var rotlSH = (h, l, s) => h << s | l >>> 32 - s;
|
|
171
|
+
var rotlSL = (h, l, s) => l << s | h >>> 32 - s;
|
|
172
|
+
var rotlBH = (h, l, s) => l << s - 32 | h >>> 64 - s;
|
|
173
|
+
var rotlBL = (h, l, s) => h << s - 32 | l >>> 64 - s;
|
|
174
|
+
function isBytes(a) {
|
|
175
|
+
return a instanceof Uint8Array || ArrayBuffer.isView(a) && a.constructor.name === "Uint8Array";
|
|
176
|
+
}
|
|
177
|
+
function anumber(n) {
|
|
178
|
+
if (!Number.isSafeInteger(n) || n < 0)
|
|
179
|
+
throw new Error("positive integer expected, got " + n);
|
|
180
|
+
}
|
|
181
|
+
function abytes(b, ...lengths) {
|
|
182
|
+
if (!isBytes(b))
|
|
183
|
+
throw new Error("Uint8Array expected");
|
|
184
|
+
if (lengths.length > 0 && !lengths.includes(b.length))
|
|
185
|
+
throw new Error("Uint8Array expected of length " + lengths + ", got length=" + b.length);
|
|
186
|
+
}
|
|
187
|
+
function aexists(instance, checkFinished = true) {
|
|
188
|
+
if (instance.destroyed)
|
|
189
|
+
throw new Error("Hash instance has been destroyed");
|
|
190
|
+
if (checkFinished && instance.finished)
|
|
191
|
+
throw new Error("Hash#digest() has already been called");
|
|
192
|
+
}
|
|
193
|
+
function aoutput(out, instance) {
|
|
194
|
+
abytes(out);
|
|
195
|
+
const min = instance.outputLen;
|
|
196
|
+
if (out.length < min) {
|
|
197
|
+
throw new Error("digestInto() expects output buffer of length at least " + min);
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
function u32(arr) {
|
|
201
|
+
return new Uint32Array(arr.buffer, arr.byteOffset, Math.floor(arr.byteLength / 4));
|
|
202
|
+
}
|
|
203
|
+
function clean(...arrays) {
|
|
204
|
+
for (let i = 0; i < arrays.length; i++) {
|
|
205
|
+
arrays[i].fill(0);
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
var isLE = /* @__PURE__ */ (() => new Uint8Array(new Uint32Array([287454020]).buffer)[0] === 68)();
|
|
209
|
+
function byteSwap(word) {
|
|
210
|
+
return word << 24 & 4278190080 | word << 8 & 16711680 | word >>> 8 & 65280 | word >>> 24 & 255;
|
|
211
|
+
}
|
|
212
|
+
function byteSwap32(arr) {
|
|
213
|
+
for (let i = 0; i < arr.length; i++) {
|
|
214
|
+
arr[i] = byteSwap(arr[i]);
|
|
215
|
+
}
|
|
216
|
+
return arr;
|
|
217
|
+
}
|
|
218
|
+
var swap32IfBE = isLE ? (u) => u : byteSwap32;
|
|
219
|
+
var hasHexBuiltin = /* @__PURE__ */ (() => typeof Uint8Array.from([]).toHex === "function" && typeof Uint8Array.fromHex === "function")();
|
|
220
|
+
var hexes = /* @__PURE__ */ Array.from({ length: 256 }, (_, i) => i.toString(16).padStart(2, "0"));
|
|
221
|
+
function bytesToHex(bytes) {
|
|
222
|
+
abytes(bytes);
|
|
223
|
+
if (hasHexBuiltin)
|
|
224
|
+
return bytes.toHex();
|
|
225
|
+
let hex = "";
|
|
226
|
+
for (let i = 0; i < bytes.length; i++) {
|
|
227
|
+
hex += hexes[bytes[i]];
|
|
228
|
+
}
|
|
229
|
+
return hex;
|
|
230
|
+
}
|
|
231
|
+
function utf8ToBytes(str) {
|
|
232
|
+
if (typeof str !== "string")
|
|
233
|
+
throw new Error("string expected");
|
|
234
|
+
return new Uint8Array(new TextEncoder().encode(str));
|
|
235
|
+
}
|
|
236
|
+
function toBytes(data) {
|
|
237
|
+
if (typeof data === "string")
|
|
238
|
+
data = utf8ToBytes(data);
|
|
239
|
+
abytes(data);
|
|
240
|
+
return data;
|
|
241
|
+
}
|
|
242
|
+
var Hash = class {
|
|
243
|
+
};
|
|
244
|
+
function createHasher(hashCons) {
|
|
245
|
+
const hashC = (msg) => hashCons().update(toBytes(msg)).digest();
|
|
246
|
+
const tmp = hashCons();
|
|
247
|
+
hashC.outputLen = tmp.outputLen;
|
|
248
|
+
hashC.blockLen = tmp.blockLen;
|
|
249
|
+
hashC.create = () => hashCons();
|
|
250
|
+
return hashC;
|
|
251
|
+
}
|
|
252
|
+
var _0n = BigInt(0);
|
|
253
|
+
var _1n = BigInt(1);
|
|
254
|
+
var _2n = BigInt(2);
|
|
255
|
+
var _7n = BigInt(7);
|
|
256
|
+
var _256n = BigInt(256);
|
|
257
|
+
var _0x71n = BigInt(113);
|
|
258
|
+
var SHA3_PI = [];
|
|
259
|
+
var SHA3_ROTL = [];
|
|
260
|
+
var _SHA3_IOTA = [];
|
|
261
|
+
for (let round = 0, R = _1n, x = 1, y = 0; round < 24; round++) {
|
|
262
|
+
[x, y] = [y, (2 * x + 3 * y) % 5];
|
|
263
|
+
SHA3_PI.push(2 * (5 * y + x));
|
|
264
|
+
SHA3_ROTL.push((round + 1) * (round + 2) / 2 % 64);
|
|
265
|
+
let t = _0n;
|
|
266
|
+
for (let j = 0; j < 7; j++) {
|
|
267
|
+
R = (R << _1n ^ (R >> _7n) * _0x71n) % _256n;
|
|
268
|
+
if (R & _2n)
|
|
269
|
+
t ^= _1n << (_1n << /* @__PURE__ */ BigInt(j)) - _1n;
|
|
270
|
+
}
|
|
271
|
+
_SHA3_IOTA.push(t);
|
|
272
|
+
}
|
|
273
|
+
var IOTAS = split(_SHA3_IOTA, true);
|
|
274
|
+
var SHA3_IOTA_H = IOTAS[0];
|
|
275
|
+
var SHA3_IOTA_L = IOTAS[1];
|
|
276
|
+
var rotlH = (h, l, s) => s > 32 ? rotlBH(h, l, s) : rotlSH(h, l, s);
|
|
277
|
+
var rotlL = (h, l, s) => s > 32 ? rotlBL(h, l, s) : rotlSL(h, l, s);
|
|
278
|
+
function keccakP(s, rounds = 24) {
|
|
279
|
+
const B = new Uint32Array(5 * 2);
|
|
280
|
+
for (let round = 24 - rounds; round < 24; round++) {
|
|
281
|
+
for (let x = 0; x < 10; x++)
|
|
282
|
+
B[x] = s[x] ^ s[x + 10] ^ s[x + 20] ^ s[x + 30] ^ s[x + 40];
|
|
283
|
+
for (let x = 0; x < 10; x += 2) {
|
|
284
|
+
const idx1 = (x + 8) % 10;
|
|
285
|
+
const idx0 = (x + 2) % 10;
|
|
286
|
+
const B0 = B[idx0];
|
|
287
|
+
const B1 = B[idx0 + 1];
|
|
288
|
+
const Th = rotlH(B0, B1, 1) ^ B[idx1];
|
|
289
|
+
const Tl = rotlL(B0, B1, 1) ^ B[idx1 + 1];
|
|
290
|
+
for (let y = 0; y < 50; y += 10) {
|
|
291
|
+
s[x + y] ^= Th;
|
|
292
|
+
s[x + y + 1] ^= Tl;
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
let curH = s[2];
|
|
296
|
+
let curL = s[3];
|
|
297
|
+
for (let t = 0; t < 24; t++) {
|
|
298
|
+
const shift = SHA3_ROTL[t];
|
|
299
|
+
const Th = rotlH(curH, curL, shift);
|
|
300
|
+
const Tl = rotlL(curH, curL, shift);
|
|
301
|
+
const PI = SHA3_PI[t];
|
|
302
|
+
curH = s[PI];
|
|
303
|
+
curL = s[PI + 1];
|
|
304
|
+
s[PI] = Th;
|
|
305
|
+
s[PI + 1] = Tl;
|
|
306
|
+
}
|
|
307
|
+
for (let y = 0; y < 50; y += 10) {
|
|
308
|
+
for (let x = 0; x < 10; x++)
|
|
309
|
+
B[x] = s[y + x];
|
|
310
|
+
for (let x = 0; x < 10; x++)
|
|
311
|
+
s[y + x] ^= ~B[(x + 2) % 10] & B[(x + 4) % 10];
|
|
312
|
+
}
|
|
313
|
+
s[0] ^= SHA3_IOTA_H[round];
|
|
314
|
+
s[1] ^= SHA3_IOTA_L[round];
|
|
315
|
+
}
|
|
316
|
+
clean(B);
|
|
317
|
+
}
|
|
318
|
+
var Keccak = class _Keccak extends Hash {
|
|
319
|
+
constructor(blockLen, suffix, outputLen, enableXOF = false, rounds = 24) {
|
|
320
|
+
super();
|
|
321
|
+
this.pos = 0;
|
|
322
|
+
this.posOut = 0;
|
|
323
|
+
this.finished = false;
|
|
324
|
+
this.destroyed = false;
|
|
325
|
+
this.enableXOF = false;
|
|
326
|
+
this.blockLen = blockLen;
|
|
327
|
+
this.suffix = suffix;
|
|
328
|
+
this.outputLen = outputLen;
|
|
329
|
+
this.enableXOF = enableXOF;
|
|
330
|
+
this.rounds = rounds;
|
|
331
|
+
anumber(outputLen);
|
|
332
|
+
if (!(0 < blockLen && blockLen < 200))
|
|
333
|
+
throw new Error("only keccak-f1600 function is supported");
|
|
334
|
+
this.state = new Uint8Array(200);
|
|
335
|
+
this.state32 = u32(this.state);
|
|
336
|
+
}
|
|
337
|
+
clone() {
|
|
338
|
+
return this._cloneInto();
|
|
339
|
+
}
|
|
340
|
+
keccak() {
|
|
341
|
+
swap32IfBE(this.state32);
|
|
342
|
+
keccakP(this.state32, this.rounds);
|
|
343
|
+
swap32IfBE(this.state32);
|
|
344
|
+
this.posOut = 0;
|
|
345
|
+
this.pos = 0;
|
|
346
|
+
}
|
|
347
|
+
update(data) {
|
|
348
|
+
aexists(this);
|
|
349
|
+
data = toBytes(data);
|
|
350
|
+
abytes(data);
|
|
351
|
+
const { blockLen, state } = this;
|
|
352
|
+
const len = data.length;
|
|
353
|
+
for (let pos = 0; pos < len; ) {
|
|
354
|
+
const take = Math.min(blockLen - this.pos, len - pos);
|
|
355
|
+
for (let i = 0; i < take; i++)
|
|
356
|
+
state[this.pos++] ^= data[pos++];
|
|
357
|
+
if (this.pos === blockLen)
|
|
358
|
+
this.keccak();
|
|
359
|
+
}
|
|
360
|
+
return this;
|
|
361
|
+
}
|
|
362
|
+
finish() {
|
|
363
|
+
if (this.finished)
|
|
364
|
+
return;
|
|
365
|
+
this.finished = true;
|
|
366
|
+
const { state, suffix, pos, blockLen } = this;
|
|
367
|
+
state[pos] ^= suffix;
|
|
368
|
+
if ((suffix & 128) !== 0 && pos === blockLen - 1)
|
|
369
|
+
this.keccak();
|
|
370
|
+
state[blockLen - 1] ^= 128;
|
|
371
|
+
this.keccak();
|
|
372
|
+
}
|
|
373
|
+
writeInto(out) {
|
|
374
|
+
aexists(this, false);
|
|
375
|
+
abytes(out);
|
|
376
|
+
this.finish();
|
|
377
|
+
const bufferOut = this.state;
|
|
378
|
+
const { blockLen } = this;
|
|
379
|
+
for (let pos = 0, len = out.length; pos < len; ) {
|
|
380
|
+
if (this.posOut >= blockLen)
|
|
381
|
+
this.keccak();
|
|
382
|
+
const take = Math.min(blockLen - this.posOut, len - pos);
|
|
383
|
+
out.set(bufferOut.subarray(this.posOut, this.posOut + take), pos);
|
|
384
|
+
this.posOut += take;
|
|
385
|
+
pos += take;
|
|
386
|
+
}
|
|
387
|
+
return out;
|
|
388
|
+
}
|
|
389
|
+
xofInto(out) {
|
|
390
|
+
if (!this.enableXOF)
|
|
391
|
+
throw new Error("XOF is not possible for this instance");
|
|
392
|
+
return this.writeInto(out);
|
|
393
|
+
}
|
|
394
|
+
xof(bytes) {
|
|
395
|
+
anumber(bytes);
|
|
396
|
+
return this.xofInto(new Uint8Array(bytes));
|
|
397
|
+
}
|
|
398
|
+
digestInto(out) {
|
|
399
|
+
aoutput(out, this);
|
|
400
|
+
if (this.finished)
|
|
401
|
+
throw new Error("digest() was already called");
|
|
402
|
+
this.writeInto(out);
|
|
403
|
+
this.destroy();
|
|
404
|
+
return out;
|
|
405
|
+
}
|
|
406
|
+
digest() {
|
|
407
|
+
return this.digestInto(new Uint8Array(this.outputLen));
|
|
408
|
+
}
|
|
409
|
+
destroy() {
|
|
410
|
+
this.destroyed = true;
|
|
411
|
+
clean(this.state);
|
|
412
|
+
}
|
|
413
|
+
_cloneInto(to) {
|
|
414
|
+
const { blockLen, suffix, outputLen, rounds, enableXOF } = this;
|
|
415
|
+
to || (to = new _Keccak(blockLen, suffix, outputLen, enableXOF, rounds));
|
|
416
|
+
to.state32.set(this.state32);
|
|
417
|
+
to.pos = this.pos;
|
|
418
|
+
to.posOut = this.posOut;
|
|
419
|
+
to.finished = this.finished;
|
|
420
|
+
to.rounds = rounds;
|
|
421
|
+
to.suffix = suffix;
|
|
422
|
+
to.outputLen = outputLen;
|
|
423
|
+
to.enableXOF = enableXOF;
|
|
424
|
+
to.destroyed = this.destroyed;
|
|
425
|
+
return to;
|
|
426
|
+
}
|
|
427
|
+
};
|
|
428
|
+
var gen = (suffix, blockLen, outputLen) => createHasher(() => new Keccak(blockLen, suffix, outputLen));
|
|
429
|
+
var sha3_256 = /* @__PURE__ */ (() => gen(6, 136, 256 / 8))();
|
|
430
|
+
function hash(content) {
|
|
431
|
+
const bytes = typeof content === "string" ? new TextEncoder().encode(content) : content;
|
|
432
|
+
return `sha3-256:${bytesToHex(sha3_256(bytes))}`;
|
|
433
|
+
}
|
|
434
|
+
function canonicalJson(obj) {
|
|
435
|
+
return JSON.stringify(obj, Object.keys(obj).sort());
|
|
436
|
+
}
|
|
437
|
+
function anumber2(n) {
|
|
438
|
+
if (!Number.isSafeInteger(n) || n < 0)
|
|
439
|
+
throw new Error("positive integer expected, got " + n);
|
|
440
|
+
}
|
|
441
|
+
function isBytes2(a) {
|
|
442
|
+
return a instanceof Uint8Array || ArrayBuffer.isView(a) && a.constructor.name === "Uint8Array";
|
|
443
|
+
}
|
|
444
|
+
function abytes2(b, ...lengths) {
|
|
445
|
+
if (!isBytes2(b))
|
|
446
|
+
throw new Error("Uint8Array expected");
|
|
447
|
+
if (lengths.length > 0 && !lengths.includes(b.length))
|
|
448
|
+
throw new Error("Uint8Array expected of length " + lengths + ", got length=" + b.length);
|
|
449
|
+
}
|
|
450
|
+
function aexists2(instance, checkFinished = true) {
|
|
451
|
+
if (instance.destroyed)
|
|
452
|
+
throw new Error("Hash instance has been destroyed");
|
|
453
|
+
if (checkFinished && instance.finished)
|
|
454
|
+
throw new Error("Hash#digest() has already been called");
|
|
455
|
+
}
|
|
456
|
+
function aoutput2(out, instance) {
|
|
457
|
+
abytes2(out);
|
|
458
|
+
const min = instance.outputLen;
|
|
459
|
+
if (out.length < min) {
|
|
460
|
+
throw new Error("digestInto() expects output buffer of length at least " + min);
|
|
461
|
+
}
|
|
462
|
+
}
|
|
463
|
+
var U32_MASK642 = /* @__PURE__ */ BigInt(2 ** 32 - 1);
|
|
464
|
+
var _32n2 = /* @__PURE__ */ BigInt(32);
|
|
465
|
+
function fromBig2(n, le = false) {
|
|
466
|
+
if (le)
|
|
467
|
+
return { h: Number(n & U32_MASK642), l: Number(n >> _32n2 & U32_MASK642) };
|
|
468
|
+
return { h: Number(n >> _32n2 & U32_MASK642) | 0, l: Number(n & U32_MASK642) | 0 };
|
|
469
|
+
}
|
|
470
|
+
function split2(lst, le = false) {
|
|
471
|
+
let Ah = new Uint32Array(lst.length);
|
|
472
|
+
let Al = new Uint32Array(lst.length);
|
|
473
|
+
for (let i = 0; i < lst.length; i++) {
|
|
474
|
+
const { h, l } = fromBig2(lst[i], le);
|
|
475
|
+
[Ah[i], Al[i]] = [h, l];
|
|
476
|
+
}
|
|
477
|
+
return [Ah, Al];
|
|
478
|
+
}
|
|
479
|
+
var rotlSH2 = (h, l, s) => h << s | l >>> 32 - s;
|
|
480
|
+
var rotlSL2 = (h, l, s) => l << s | h >>> 32 - s;
|
|
481
|
+
var rotlBH2 = (h, l, s) => l << s - 32 | h >>> 64 - s;
|
|
482
|
+
var rotlBL2 = (h, l, s) => h << s - 32 | l >>> 64 - s;
|
|
483
|
+
var crypto2 = nc && typeof nc === "object" && "webcrypto" in nc ? nc.webcrypto : nc && typeof nc === "object" && "randomBytes" in nc ? nc : void 0;
|
|
484
|
+
var u322 = (arr) => new Uint32Array(arr.buffer, arr.byteOffset, Math.floor(arr.byteLength / 4));
|
|
485
|
+
var isLE2 = /* @__PURE__ */ (() => new Uint8Array(new Uint32Array([287454020]).buffer)[0] === 68)();
|
|
486
|
+
var byteSwap2 = (word) => word << 24 & 4278190080 | word << 8 & 16711680 | word >>> 8 & 65280 | word >>> 24 & 255;
|
|
487
|
+
function byteSwap322(arr) {
|
|
488
|
+
for (let i = 0; i < arr.length; i++) {
|
|
489
|
+
arr[i] = byteSwap2(arr[i]);
|
|
490
|
+
}
|
|
491
|
+
}
|
|
492
|
+
function utf8ToBytes2(str) {
|
|
493
|
+
if (typeof str !== "string")
|
|
494
|
+
throw new Error("utf8ToBytes expected string, got " + typeof str);
|
|
495
|
+
return new Uint8Array(new TextEncoder().encode(str));
|
|
496
|
+
}
|
|
497
|
+
function toBytes2(data) {
|
|
498
|
+
if (typeof data === "string")
|
|
499
|
+
data = utf8ToBytes2(data);
|
|
500
|
+
abytes2(data);
|
|
501
|
+
return data;
|
|
502
|
+
}
|
|
503
|
+
function concatBytes(...arrays) {
|
|
504
|
+
let sum = 0;
|
|
505
|
+
for (let i = 0; i < arrays.length; i++) {
|
|
506
|
+
const a = arrays[i];
|
|
507
|
+
abytes2(a);
|
|
508
|
+
sum += a.length;
|
|
509
|
+
}
|
|
510
|
+
const res = new Uint8Array(sum);
|
|
511
|
+
for (let i = 0, pad = 0; i < arrays.length; i++) {
|
|
512
|
+
const a = arrays[i];
|
|
513
|
+
res.set(a, pad);
|
|
514
|
+
pad += a.length;
|
|
515
|
+
}
|
|
516
|
+
return res;
|
|
517
|
+
}
|
|
518
|
+
var Hash2 = class {
|
|
519
|
+
clone() {
|
|
520
|
+
return this._cloneInto();
|
|
521
|
+
}
|
|
522
|
+
};
|
|
523
|
+
function wrapConstructor(hashCons) {
|
|
524
|
+
const hashC = (msg) => hashCons().update(toBytes2(msg)).digest();
|
|
525
|
+
const tmp = hashCons();
|
|
526
|
+
hashC.outputLen = tmp.outputLen;
|
|
527
|
+
hashC.blockLen = tmp.blockLen;
|
|
528
|
+
hashC.create = () => hashCons();
|
|
529
|
+
return hashC;
|
|
530
|
+
}
|
|
531
|
+
function wrapXOFConstructorWithOpts(hashCons) {
|
|
532
|
+
const hashC = (msg, opts) => hashCons(opts).update(toBytes2(msg)).digest();
|
|
533
|
+
const tmp = hashCons({});
|
|
534
|
+
hashC.outputLen = tmp.outputLen;
|
|
535
|
+
hashC.blockLen = tmp.blockLen;
|
|
536
|
+
hashC.create = (opts) => hashCons(opts);
|
|
537
|
+
return hashC;
|
|
538
|
+
}
|
|
539
|
+
function randomBytes(bytesLength = 32) {
|
|
540
|
+
if (crypto2 && typeof crypto2.getRandomValues === "function") {
|
|
541
|
+
return crypto2.getRandomValues(new Uint8Array(bytesLength));
|
|
542
|
+
}
|
|
543
|
+
if (crypto2 && typeof crypto2.randomBytes === "function") {
|
|
544
|
+
return crypto2.randomBytes(bytesLength);
|
|
545
|
+
}
|
|
546
|
+
throw new Error("crypto.getRandomValues must be defined");
|
|
547
|
+
}
|
|
548
|
+
var SHA3_PI2 = [];
|
|
549
|
+
var SHA3_ROTL2 = [];
|
|
550
|
+
var _SHA3_IOTA2 = [];
|
|
551
|
+
var _0n2 = /* @__PURE__ */ BigInt(0);
|
|
552
|
+
var _1n2 = /* @__PURE__ */ BigInt(1);
|
|
553
|
+
var _2n2 = /* @__PURE__ */ BigInt(2);
|
|
554
|
+
var _7n2 = /* @__PURE__ */ BigInt(7);
|
|
555
|
+
var _256n2 = /* @__PURE__ */ BigInt(256);
|
|
556
|
+
var _0x71n2 = /* @__PURE__ */ BigInt(113);
|
|
557
|
+
for (let round = 0, R = _1n2, x = 1, y = 0; round < 24; round++) {
|
|
558
|
+
[x, y] = [y, (2 * x + 3 * y) % 5];
|
|
559
|
+
SHA3_PI2.push(2 * (5 * y + x));
|
|
560
|
+
SHA3_ROTL2.push((round + 1) * (round + 2) / 2 % 64);
|
|
561
|
+
let t = _0n2;
|
|
562
|
+
for (let j = 0; j < 7; j++) {
|
|
563
|
+
R = (R << _1n2 ^ (R >> _7n2) * _0x71n2) % _256n2;
|
|
564
|
+
if (R & _2n2)
|
|
565
|
+
t ^= _1n2 << (_1n2 << /* @__PURE__ */ BigInt(j)) - _1n2;
|
|
566
|
+
}
|
|
567
|
+
_SHA3_IOTA2.push(t);
|
|
568
|
+
}
|
|
569
|
+
var [SHA3_IOTA_H2, SHA3_IOTA_L2] = /* @__PURE__ */ split2(_SHA3_IOTA2, true);
|
|
570
|
+
var rotlH2 = (h, l, s) => s > 32 ? rotlBH2(h, l, s) : rotlSH2(h, l, s);
|
|
571
|
+
var rotlL2 = (h, l, s) => s > 32 ? rotlBL2(h, l, s) : rotlSL2(h, l, s);
|
|
572
|
+
function keccakP2(s, rounds = 24) {
|
|
573
|
+
const B = new Uint32Array(5 * 2);
|
|
574
|
+
for (let round = 24 - rounds; round < 24; round++) {
|
|
575
|
+
for (let x = 0; x < 10; x++)
|
|
576
|
+
B[x] = s[x] ^ s[x + 10] ^ s[x + 20] ^ s[x + 30] ^ s[x + 40];
|
|
577
|
+
for (let x = 0; x < 10; x += 2) {
|
|
578
|
+
const idx1 = (x + 8) % 10;
|
|
579
|
+
const idx0 = (x + 2) % 10;
|
|
580
|
+
const B0 = B[idx0];
|
|
581
|
+
const B1 = B[idx0 + 1];
|
|
582
|
+
const Th = rotlH2(B0, B1, 1) ^ B[idx1];
|
|
583
|
+
const Tl = rotlL2(B0, B1, 1) ^ B[idx1 + 1];
|
|
584
|
+
for (let y = 0; y < 50; y += 10) {
|
|
585
|
+
s[x + y] ^= Th;
|
|
586
|
+
s[x + y + 1] ^= Tl;
|
|
587
|
+
}
|
|
588
|
+
}
|
|
589
|
+
let curH = s[2];
|
|
590
|
+
let curL = s[3];
|
|
591
|
+
for (let t = 0; t < 24; t++) {
|
|
592
|
+
const shift = SHA3_ROTL2[t];
|
|
593
|
+
const Th = rotlH2(curH, curL, shift);
|
|
594
|
+
const Tl = rotlL2(curH, curL, shift);
|
|
595
|
+
const PI = SHA3_PI2[t];
|
|
596
|
+
curH = s[PI];
|
|
597
|
+
curL = s[PI + 1];
|
|
598
|
+
s[PI] = Th;
|
|
599
|
+
s[PI + 1] = Tl;
|
|
600
|
+
}
|
|
601
|
+
for (let y = 0; y < 50; y += 10) {
|
|
602
|
+
for (let x = 0; x < 10; x++)
|
|
603
|
+
B[x] = s[y + x];
|
|
604
|
+
for (let x = 0; x < 10; x++)
|
|
605
|
+
s[y + x] ^= ~B[(x + 2) % 10] & B[(x + 4) % 10];
|
|
606
|
+
}
|
|
607
|
+
s[0] ^= SHA3_IOTA_H2[round];
|
|
608
|
+
s[1] ^= SHA3_IOTA_L2[round];
|
|
609
|
+
}
|
|
610
|
+
B.fill(0);
|
|
611
|
+
}
|
|
612
|
+
var Keccak2 = class _Keccak2 extends Hash2 {
|
|
613
|
+
constructor(blockLen, suffix, outputLen, enableXOF = false, rounds = 24) {
|
|
614
|
+
super();
|
|
615
|
+
this.blockLen = blockLen;
|
|
616
|
+
this.suffix = suffix;
|
|
617
|
+
this.outputLen = outputLen;
|
|
618
|
+
this.enableXOF = enableXOF;
|
|
619
|
+
this.rounds = rounds;
|
|
620
|
+
this.pos = 0;
|
|
621
|
+
this.posOut = 0;
|
|
622
|
+
this.finished = false;
|
|
623
|
+
this.destroyed = false;
|
|
624
|
+
anumber2(outputLen);
|
|
625
|
+
if (0 >= this.blockLen || this.blockLen >= 200)
|
|
626
|
+
throw new Error("Sha3 supports only keccak-f1600 function");
|
|
627
|
+
this.state = new Uint8Array(200);
|
|
628
|
+
this.state32 = u322(this.state);
|
|
629
|
+
}
|
|
630
|
+
keccak() {
|
|
631
|
+
if (!isLE2)
|
|
632
|
+
byteSwap322(this.state32);
|
|
633
|
+
keccakP2(this.state32, this.rounds);
|
|
634
|
+
if (!isLE2)
|
|
635
|
+
byteSwap322(this.state32);
|
|
636
|
+
this.posOut = 0;
|
|
637
|
+
this.pos = 0;
|
|
638
|
+
}
|
|
639
|
+
update(data) {
|
|
640
|
+
aexists2(this);
|
|
641
|
+
const { blockLen, state } = this;
|
|
642
|
+
data = toBytes2(data);
|
|
643
|
+
const len = data.length;
|
|
644
|
+
for (let pos = 0; pos < len; ) {
|
|
645
|
+
const take = Math.min(blockLen - this.pos, len - pos);
|
|
646
|
+
for (let i = 0; i < take; i++)
|
|
647
|
+
state[this.pos++] ^= data[pos++];
|
|
648
|
+
if (this.pos === blockLen)
|
|
649
|
+
this.keccak();
|
|
650
|
+
}
|
|
651
|
+
return this;
|
|
652
|
+
}
|
|
653
|
+
finish() {
|
|
654
|
+
if (this.finished)
|
|
655
|
+
return;
|
|
656
|
+
this.finished = true;
|
|
657
|
+
const { state, suffix, pos, blockLen } = this;
|
|
658
|
+
state[pos] ^= suffix;
|
|
659
|
+
if ((suffix & 128) !== 0 && pos === blockLen - 1)
|
|
660
|
+
this.keccak();
|
|
661
|
+
state[blockLen - 1] ^= 128;
|
|
662
|
+
this.keccak();
|
|
663
|
+
}
|
|
664
|
+
writeInto(out) {
|
|
665
|
+
aexists2(this, false);
|
|
666
|
+
abytes2(out);
|
|
667
|
+
this.finish();
|
|
668
|
+
const bufferOut = this.state;
|
|
669
|
+
const { blockLen } = this;
|
|
670
|
+
for (let pos = 0, len = out.length; pos < len; ) {
|
|
671
|
+
if (this.posOut >= blockLen)
|
|
672
|
+
this.keccak();
|
|
673
|
+
const take = Math.min(blockLen - this.posOut, len - pos);
|
|
674
|
+
out.set(bufferOut.subarray(this.posOut, this.posOut + take), pos);
|
|
675
|
+
this.posOut += take;
|
|
676
|
+
pos += take;
|
|
677
|
+
}
|
|
678
|
+
return out;
|
|
679
|
+
}
|
|
680
|
+
xofInto(out) {
|
|
681
|
+
if (!this.enableXOF)
|
|
682
|
+
throw new Error("XOF is not possible for this instance");
|
|
683
|
+
return this.writeInto(out);
|
|
684
|
+
}
|
|
685
|
+
xof(bytes) {
|
|
686
|
+
anumber2(bytes);
|
|
687
|
+
return this.xofInto(new Uint8Array(bytes));
|
|
688
|
+
}
|
|
689
|
+
digestInto(out) {
|
|
690
|
+
aoutput2(out, this);
|
|
691
|
+
if (this.finished)
|
|
692
|
+
throw new Error("digest() was already called");
|
|
693
|
+
this.writeInto(out);
|
|
694
|
+
this.destroy();
|
|
695
|
+
return out;
|
|
696
|
+
}
|
|
697
|
+
digest() {
|
|
698
|
+
return this.digestInto(new Uint8Array(this.outputLen));
|
|
699
|
+
}
|
|
700
|
+
destroy() {
|
|
701
|
+
this.destroyed = true;
|
|
702
|
+
this.state.fill(0);
|
|
703
|
+
}
|
|
704
|
+
_cloneInto(to) {
|
|
705
|
+
const { blockLen, suffix, outputLen, rounds, enableXOF } = this;
|
|
706
|
+
to || (to = new _Keccak2(blockLen, suffix, outputLen, enableXOF, rounds));
|
|
707
|
+
to.state32.set(this.state32);
|
|
708
|
+
to.pos = this.pos;
|
|
709
|
+
to.posOut = this.posOut;
|
|
710
|
+
to.finished = this.finished;
|
|
711
|
+
to.rounds = rounds;
|
|
712
|
+
to.suffix = suffix;
|
|
713
|
+
to.outputLen = outputLen;
|
|
714
|
+
to.enableXOF = enableXOF;
|
|
715
|
+
to.destroyed = this.destroyed;
|
|
716
|
+
return to;
|
|
717
|
+
}
|
|
718
|
+
};
|
|
719
|
+
var gen2 = (suffix, blockLen, outputLen) => wrapConstructor(() => new Keccak2(blockLen, suffix, outputLen));
|
|
720
|
+
var sha3_224 = /* @__PURE__ */ gen2(6, 144, 224 / 8);
|
|
721
|
+
var sha3_2562 = /* @__PURE__ */ gen2(6, 136, 256 / 8);
|
|
722
|
+
var sha3_384 = /* @__PURE__ */ gen2(6, 104, 384 / 8);
|
|
723
|
+
var sha3_512 = /* @__PURE__ */ gen2(6, 72, 512 / 8);
|
|
724
|
+
var keccak_224 = /* @__PURE__ */ gen2(1, 144, 224 / 8);
|
|
725
|
+
var keccak_256 = /* @__PURE__ */ gen2(1, 136, 256 / 8);
|
|
726
|
+
var keccak_384 = /* @__PURE__ */ gen2(1, 104, 384 / 8);
|
|
727
|
+
var keccak_512 = /* @__PURE__ */ gen2(1, 72, 512 / 8);
|
|
728
|
+
var genShake = (suffix, blockLen, outputLen) => wrapXOFConstructorWithOpts((opts = {}) => new Keccak2(blockLen, suffix, opts.dkLen === void 0 ? outputLen : opts.dkLen, true));
|
|
729
|
+
var shake128 = /* @__PURE__ */ genShake(31, 168, 128 / 8);
|
|
730
|
+
var shake256 = /* @__PURE__ */ genShake(31, 136, 256 / 8);
|
|
731
|
+
var ensureBytes = abytes2;
|
|
732
|
+
var randomBytes2 = randomBytes;
|
|
733
|
+
function equalBytes(a, b) {
|
|
734
|
+
if (a.length !== b.length)
|
|
735
|
+
return false;
|
|
736
|
+
let diff = 0;
|
|
737
|
+
for (let i = 0; i < a.length; i++)
|
|
738
|
+
diff |= a[i] ^ b[i];
|
|
739
|
+
return diff === 0;
|
|
740
|
+
}
|
|
741
|
+
function splitCoder(...lengths) {
|
|
742
|
+
const getLength = (c2) => typeof c2 === "number" ? c2 : c2.bytesLen;
|
|
743
|
+
const bytesLen = lengths.reduce((sum, a) => sum + getLength(a), 0);
|
|
744
|
+
return {
|
|
745
|
+
bytesLen,
|
|
746
|
+
encode: (bufs) => {
|
|
747
|
+
const res = new Uint8Array(bytesLen);
|
|
748
|
+
for (let i = 0, pos = 0; i < lengths.length; i++) {
|
|
749
|
+
const c2 = lengths[i];
|
|
750
|
+
const l = getLength(c2);
|
|
751
|
+
const b = typeof c2 === "number" ? bufs[i] : c2.encode(bufs[i]);
|
|
752
|
+
ensureBytes(b, l);
|
|
753
|
+
res.set(b, pos);
|
|
754
|
+
if (typeof c2 !== "number")
|
|
755
|
+
b.fill(0);
|
|
756
|
+
pos += l;
|
|
757
|
+
}
|
|
758
|
+
return res;
|
|
759
|
+
},
|
|
760
|
+
decode: (buf) => {
|
|
761
|
+
ensureBytes(buf, bytesLen);
|
|
762
|
+
const res = [];
|
|
763
|
+
for (const c2 of lengths) {
|
|
764
|
+
const l = getLength(c2);
|
|
765
|
+
const b = buf.subarray(0, l);
|
|
766
|
+
res.push(typeof c2 === "number" ? b : c2.decode(b));
|
|
767
|
+
buf = buf.subarray(l);
|
|
768
|
+
}
|
|
769
|
+
return res;
|
|
770
|
+
}
|
|
771
|
+
};
|
|
772
|
+
}
|
|
773
|
+
function vecCoder(c2, vecLen) {
|
|
774
|
+
const bytesLen = vecLen * c2.bytesLen;
|
|
775
|
+
return {
|
|
776
|
+
bytesLen,
|
|
777
|
+
encode: (u) => {
|
|
778
|
+
if (u.length !== vecLen)
|
|
779
|
+
throw new Error(`vecCoder.encode: wrong length=${u.length}. Expected: ${vecLen}`);
|
|
780
|
+
const res = new Uint8Array(bytesLen);
|
|
781
|
+
for (let i = 0, pos = 0; i < u.length; i++) {
|
|
782
|
+
const b = c2.encode(u[i]);
|
|
783
|
+
res.set(b, pos);
|
|
784
|
+
b.fill(0);
|
|
785
|
+
pos += b.length;
|
|
786
|
+
}
|
|
787
|
+
return res;
|
|
788
|
+
},
|
|
789
|
+
decode: (a) => {
|
|
790
|
+
ensureBytes(a, bytesLen);
|
|
791
|
+
const r = [];
|
|
792
|
+
for (let i = 0; i < a.length; i += c2.bytesLen)
|
|
793
|
+
r.push(c2.decode(a.subarray(i, i + c2.bytesLen)));
|
|
794
|
+
return r;
|
|
795
|
+
}
|
|
796
|
+
};
|
|
797
|
+
}
|
|
798
|
+
function cleanBytes(...list) {
|
|
799
|
+
for (const t of list) {
|
|
800
|
+
if (Array.isArray(t))
|
|
801
|
+
for (const b of t)
|
|
802
|
+
b.fill(0);
|
|
803
|
+
else
|
|
804
|
+
t.fill(0);
|
|
805
|
+
}
|
|
806
|
+
}
|
|
807
|
+
function getMask(bits) {
|
|
808
|
+
return (1 << bits) - 1;
|
|
809
|
+
}
|
|
810
|
+
function bitReversal(n, bits = 8) {
|
|
811
|
+
const padded = n.toString(2).padStart(8, "0");
|
|
812
|
+
const sliced = padded.slice(-bits).padStart(7, "0");
|
|
813
|
+
const revrsd = sliced.split("").reverse().join("");
|
|
814
|
+
return Number.parseInt(revrsd, 2);
|
|
815
|
+
}
|
|
816
|
+
var genCrystals = (opts) => {
|
|
817
|
+
const { newPoly: newPoly2, N: N2, Q: Q2, F: F2, ROOT_OF_UNITY: ROOT_OF_UNITY2, brvBits, isKyber } = opts;
|
|
818
|
+
const mod2 = (a, modulo = Q2) => {
|
|
819
|
+
const result = a % modulo | 0;
|
|
820
|
+
return (result >= 0 ? result | 0 : modulo + result | 0) | 0;
|
|
821
|
+
};
|
|
822
|
+
const smod2 = (a, modulo = Q2) => {
|
|
823
|
+
const r = mod2(a, modulo) | 0;
|
|
824
|
+
return (r > modulo >> 1 ? r - modulo | 0 : r) | 0;
|
|
825
|
+
};
|
|
826
|
+
function getZettas() {
|
|
827
|
+
const out = newPoly2(N2);
|
|
828
|
+
for (let i = 0; i < N2; i++) {
|
|
829
|
+
const b = bitReversal(i, brvBits);
|
|
830
|
+
const p = BigInt(ROOT_OF_UNITY2) ** BigInt(b) % BigInt(Q2);
|
|
831
|
+
out[i] = Number(p) | 0;
|
|
832
|
+
}
|
|
833
|
+
return out;
|
|
834
|
+
}
|
|
835
|
+
const nttZetas = getZettas();
|
|
836
|
+
const LEN1 = isKyber ? 128 : N2;
|
|
837
|
+
const LEN2 = isKyber ? 1 : 0;
|
|
838
|
+
const NTT2 = {
|
|
839
|
+
encode: (r) => {
|
|
840
|
+
for (let k = 1, len = 128; len > LEN2; len >>= 1) {
|
|
841
|
+
for (let start = 0; start < N2; start += 2 * len) {
|
|
842
|
+
const zeta = nttZetas[k++];
|
|
843
|
+
for (let j = start; j < start + len; j++) {
|
|
844
|
+
const t = mod2(zeta * r[j + len]);
|
|
845
|
+
r[j + len] = mod2(r[j] - t) | 0;
|
|
846
|
+
r[j] = mod2(r[j] + t) | 0;
|
|
847
|
+
}
|
|
848
|
+
}
|
|
849
|
+
}
|
|
850
|
+
return r;
|
|
851
|
+
},
|
|
852
|
+
decode: (r) => {
|
|
853
|
+
for (let k = LEN1 - 1, len = 1 + LEN2; len < LEN1 + LEN2; len <<= 1) {
|
|
854
|
+
for (let start = 0; start < N2; start += 2 * len) {
|
|
855
|
+
const zeta = nttZetas[k--];
|
|
856
|
+
for (let j = start; j < start + len; j++) {
|
|
857
|
+
const t = r[j];
|
|
858
|
+
r[j] = mod2(t + r[j + len]);
|
|
859
|
+
r[j + len] = mod2(zeta * (r[j + len] - t));
|
|
860
|
+
}
|
|
861
|
+
}
|
|
862
|
+
}
|
|
863
|
+
for (let i = 0; i < r.length; i++)
|
|
864
|
+
r[i] = mod2(F2 * r[i]);
|
|
865
|
+
return r;
|
|
866
|
+
}
|
|
867
|
+
};
|
|
868
|
+
const bitsCoder2 = (d, c2) => {
|
|
869
|
+
const mask = getMask(d);
|
|
870
|
+
const bytesLen = d * (N2 / 8);
|
|
871
|
+
return {
|
|
872
|
+
bytesLen,
|
|
873
|
+
encode: (poly) => {
|
|
874
|
+
const r = new Uint8Array(bytesLen);
|
|
875
|
+
for (let i = 0, buf = 0, bufLen = 0, pos = 0; i < poly.length; i++) {
|
|
876
|
+
buf |= (c2.encode(poly[i]) & mask) << bufLen;
|
|
877
|
+
bufLen += d;
|
|
878
|
+
for (; bufLen >= 8; bufLen -= 8, buf >>= 8)
|
|
879
|
+
r[pos++] = buf & getMask(bufLen);
|
|
880
|
+
}
|
|
881
|
+
return r;
|
|
882
|
+
},
|
|
883
|
+
decode: (bytes) => {
|
|
884
|
+
const r = newPoly2(N2);
|
|
885
|
+
for (let i = 0, buf = 0, bufLen = 0, pos = 0; i < bytes.length; i++) {
|
|
886
|
+
buf |= bytes[i] << bufLen;
|
|
887
|
+
bufLen += 8;
|
|
888
|
+
for (; bufLen >= d; bufLen -= d, buf >>= d)
|
|
889
|
+
r[pos++] = c2.decode(buf & mask);
|
|
890
|
+
}
|
|
891
|
+
return r;
|
|
892
|
+
}
|
|
893
|
+
};
|
|
894
|
+
};
|
|
895
|
+
return { mod: mod2, smod: smod2, nttZetas, NTT: NTT2, bitsCoder: bitsCoder2 };
|
|
896
|
+
};
|
|
897
|
+
var createXofShake = (shake) => (seed, blockLen) => {
|
|
898
|
+
if (!blockLen)
|
|
899
|
+
blockLen = shake.blockLen;
|
|
900
|
+
const _seed = new Uint8Array(seed.length + 2);
|
|
901
|
+
_seed.set(seed);
|
|
902
|
+
const seedLen = seed.length;
|
|
903
|
+
const buf = new Uint8Array(blockLen);
|
|
904
|
+
let h = shake.create({});
|
|
905
|
+
let calls = 0;
|
|
906
|
+
let xofs = 0;
|
|
907
|
+
return {
|
|
908
|
+
stats: () => ({ calls, xofs }),
|
|
909
|
+
get: (x, y) => {
|
|
910
|
+
_seed[seedLen + 0] = x;
|
|
911
|
+
_seed[seedLen + 1] = y;
|
|
912
|
+
h.destroy();
|
|
913
|
+
h = shake.create({}).update(_seed);
|
|
914
|
+
calls++;
|
|
915
|
+
return () => {
|
|
916
|
+
xofs++;
|
|
917
|
+
return h.xofInto(buf);
|
|
918
|
+
};
|
|
919
|
+
},
|
|
920
|
+
clean: () => {
|
|
921
|
+
h.destroy();
|
|
922
|
+
buf.fill(0);
|
|
923
|
+
_seed.fill(0);
|
|
924
|
+
}
|
|
925
|
+
};
|
|
926
|
+
};
|
|
927
|
+
var XOF128 = /* @__PURE__ */ createXofShake(shake128);
|
|
928
|
+
var XOF256 = /* @__PURE__ */ createXofShake(shake256);
|
|
929
|
+
var N = 256;
|
|
930
|
+
var Q = 8380417;
|
|
931
|
+
var ROOT_OF_UNITY = 1753;
|
|
932
|
+
var F = 8347681;
|
|
933
|
+
var D = 13;
|
|
934
|
+
var GAMMA2_1 = Math.floor((Q - 1) / 88) | 0;
|
|
935
|
+
var GAMMA2_2 = Math.floor((Q - 1) / 32) | 0;
|
|
936
|
+
var PARAMS = {
|
|
937
|
+
2: { K: 4, L: 4, D, GAMMA1: 2 ** 17, GAMMA2: GAMMA2_1, TAU: 39, ETA: 2, OMEGA: 80 },
|
|
938
|
+
3: { K: 6, L: 5, D, GAMMA1: 2 ** 19, GAMMA2: GAMMA2_2, TAU: 49, ETA: 4, OMEGA: 55 },
|
|
939
|
+
5: { K: 8, L: 7, D, GAMMA1: 2 ** 19, GAMMA2: GAMMA2_2, TAU: 60, ETA: 2, OMEGA: 75 }
|
|
940
|
+
};
|
|
941
|
+
var newPoly = (n) => new Int32Array(n);
|
|
942
|
+
var { mod, smod, NTT, bitsCoder } = genCrystals({
|
|
943
|
+
N,
|
|
944
|
+
Q,
|
|
945
|
+
F,
|
|
946
|
+
ROOT_OF_UNITY,
|
|
947
|
+
newPoly,
|
|
948
|
+
isKyber: false,
|
|
949
|
+
brvBits: 8
|
|
950
|
+
});
|
|
951
|
+
var id = (n) => n;
|
|
952
|
+
var polyCoder = (d, compress = id, verify = id) => bitsCoder(d, {
|
|
953
|
+
encode: (i) => compress(verify(i)),
|
|
954
|
+
decode: (i) => verify(compress(i))
|
|
955
|
+
});
|
|
956
|
+
var polyAdd = (a, b) => {
|
|
957
|
+
for (let i = 0; i < a.length; i++)
|
|
958
|
+
a[i] = mod(a[i] + b[i]);
|
|
959
|
+
return a;
|
|
960
|
+
};
|
|
961
|
+
var polySub = (a, b) => {
|
|
962
|
+
for (let i = 0; i < a.length; i++)
|
|
963
|
+
a[i] = mod(a[i] - b[i]);
|
|
964
|
+
return a;
|
|
965
|
+
};
|
|
966
|
+
var polyShiftl = (p) => {
|
|
967
|
+
for (let i = 0; i < N; i++)
|
|
968
|
+
p[i] <<= D;
|
|
969
|
+
return p;
|
|
970
|
+
};
|
|
971
|
+
var polyChknorm = (p, B) => {
|
|
972
|
+
for (let i = 0; i < N; i++)
|
|
973
|
+
if (Math.abs(smod(p[i])) >= B)
|
|
974
|
+
return true;
|
|
975
|
+
return false;
|
|
976
|
+
};
|
|
977
|
+
var MultiplyNTTs = (a, b) => {
|
|
978
|
+
const c2 = newPoly(N);
|
|
979
|
+
for (let i = 0; i < a.length; i++)
|
|
980
|
+
c2[i] = mod(a[i] * b[i]);
|
|
981
|
+
return c2;
|
|
982
|
+
};
|
|
983
|
+
function RejNTTPoly(xof) {
|
|
984
|
+
const r = newPoly(N);
|
|
985
|
+
for (let j = 0; j < N; ) {
|
|
986
|
+
const b = xof();
|
|
987
|
+
if (b.length % 3)
|
|
988
|
+
throw new Error("RejNTTPoly: unaligned block");
|
|
989
|
+
for (let i = 0; j < N && i <= b.length - 3; i += 3) {
|
|
990
|
+
const t = (b[i + 0] | b[i + 1] << 8 | b[i + 2] << 16) & 8388607;
|
|
991
|
+
if (t < Q)
|
|
992
|
+
r[j++] = t;
|
|
993
|
+
}
|
|
994
|
+
}
|
|
995
|
+
return r;
|
|
996
|
+
}
|
|
997
|
+
var EMPTY = new Uint8Array(0);
|
|
998
|
+
function getDilithium(opts) {
|
|
999
|
+
const { K, L, GAMMA1, GAMMA2, TAU, ETA, OMEGA } = opts;
|
|
1000
|
+
const { CRH_BYTES, TR_BYTES, C_TILDE_BYTES, XOF128: XOF1282, XOF256: XOF2562 } = opts;
|
|
1001
|
+
if (![2, 4].includes(ETA))
|
|
1002
|
+
throw new Error("Wrong ETA");
|
|
1003
|
+
if (![1 << 17, 1 << 19].includes(GAMMA1))
|
|
1004
|
+
throw new Error("Wrong GAMMA1");
|
|
1005
|
+
if (![GAMMA2_1, GAMMA2_2].includes(GAMMA2))
|
|
1006
|
+
throw new Error("Wrong GAMMA2");
|
|
1007
|
+
const BETA = TAU * ETA;
|
|
1008
|
+
const decompose = (r) => {
|
|
1009
|
+
const rPlus = mod(r);
|
|
1010
|
+
const r0 = smod(rPlus, 2 * GAMMA2) | 0;
|
|
1011
|
+
if (rPlus - r0 === Q - 1)
|
|
1012
|
+
return { r1: 0 | 0, r0: r0 - 1 | 0 };
|
|
1013
|
+
const r1 = Math.floor((rPlus - r0) / (2 * GAMMA2)) | 0;
|
|
1014
|
+
return { r1, r0 };
|
|
1015
|
+
};
|
|
1016
|
+
const HighBits = (r) => decompose(r).r1;
|
|
1017
|
+
const LowBits = (r) => decompose(r).r0;
|
|
1018
|
+
const MakeHint = (z, r) => {
|
|
1019
|
+
const res0 = z <= GAMMA2 || z > Q - GAMMA2 || z === Q - GAMMA2 && r === 0 ? 0 : 1;
|
|
1020
|
+
return res0;
|
|
1021
|
+
};
|
|
1022
|
+
const UseHint = (h, r) => {
|
|
1023
|
+
const m = Math.floor((Q - 1) / (2 * GAMMA2));
|
|
1024
|
+
const { r1, r0 } = decompose(r);
|
|
1025
|
+
if (h === 1)
|
|
1026
|
+
return r0 > 0 ? mod(r1 + 1, m) | 0 : mod(r1 - 1, m) | 0;
|
|
1027
|
+
return r1 | 0;
|
|
1028
|
+
};
|
|
1029
|
+
const Power2Round = (r) => {
|
|
1030
|
+
const rPlus = mod(r);
|
|
1031
|
+
const r0 = smod(rPlus, 2 ** D) | 0;
|
|
1032
|
+
return { r1: Math.floor((rPlus - r0) / 2 ** D) | 0, r0 };
|
|
1033
|
+
};
|
|
1034
|
+
const hintCoder = {
|
|
1035
|
+
bytesLen: OMEGA + K,
|
|
1036
|
+
encode: (h) => {
|
|
1037
|
+
if (h === false)
|
|
1038
|
+
throw new Error("hint.encode: hint is false");
|
|
1039
|
+
const res = new Uint8Array(OMEGA + K);
|
|
1040
|
+
for (let i = 0, k = 0; i < K; i++) {
|
|
1041
|
+
for (let j = 0; j < N; j++)
|
|
1042
|
+
if (h[i][j] !== 0)
|
|
1043
|
+
res[k++] = j;
|
|
1044
|
+
res[OMEGA + i] = k;
|
|
1045
|
+
}
|
|
1046
|
+
return res;
|
|
1047
|
+
},
|
|
1048
|
+
decode: (buf) => {
|
|
1049
|
+
const h = [];
|
|
1050
|
+
let k = 0;
|
|
1051
|
+
for (let i = 0; i < K; i++) {
|
|
1052
|
+
const hi = newPoly(N);
|
|
1053
|
+
if (buf[OMEGA + i] < k || buf[OMEGA + i] > OMEGA)
|
|
1054
|
+
return false;
|
|
1055
|
+
for (let j = k; j < buf[OMEGA + i]; j++) {
|
|
1056
|
+
if (j > k && buf[j] <= buf[j - 1])
|
|
1057
|
+
return false;
|
|
1058
|
+
hi[buf[j]] = 1;
|
|
1059
|
+
}
|
|
1060
|
+
k = buf[OMEGA + i];
|
|
1061
|
+
h.push(hi);
|
|
1062
|
+
}
|
|
1063
|
+
for (let j = k; j < OMEGA; j++)
|
|
1064
|
+
if (buf[j] !== 0)
|
|
1065
|
+
return false;
|
|
1066
|
+
return h;
|
|
1067
|
+
}
|
|
1068
|
+
};
|
|
1069
|
+
const ETACoder = polyCoder(ETA === 2 ? 3 : 4, (i) => ETA - i, (i) => {
|
|
1070
|
+
if (!(-ETA <= i && i <= ETA))
|
|
1071
|
+
throw new Error(`malformed key s1/s3 ${i} outside of ETA range [${-ETA}, ${ETA}]`);
|
|
1072
|
+
return i;
|
|
1073
|
+
});
|
|
1074
|
+
const T0Coder = polyCoder(13, (i) => (1 << D - 1) - i);
|
|
1075
|
+
const T1Coder = polyCoder(10);
|
|
1076
|
+
const ZCoder = polyCoder(GAMMA1 === 1 << 17 ? 18 : 20, (i) => smod(GAMMA1 - i));
|
|
1077
|
+
const W1Coder = polyCoder(GAMMA2 === GAMMA2_1 ? 6 : 4);
|
|
1078
|
+
const W1Vec = vecCoder(W1Coder, K);
|
|
1079
|
+
const publicCoder = splitCoder(32, vecCoder(T1Coder, K));
|
|
1080
|
+
const secretCoder = splitCoder(32, 32, TR_BYTES, vecCoder(ETACoder, L), vecCoder(ETACoder, K), vecCoder(T0Coder, K));
|
|
1081
|
+
const sigCoder = splitCoder(C_TILDE_BYTES, vecCoder(ZCoder, L), hintCoder);
|
|
1082
|
+
const CoefFromHalfByte = ETA === 2 ? (n) => n < 15 ? 2 - n % 5 : false : (n) => n < 9 ? 4 - n : false;
|
|
1083
|
+
function RejBoundedPoly(xof) {
|
|
1084
|
+
const r = newPoly(N);
|
|
1085
|
+
for (let j = 0; j < N; ) {
|
|
1086
|
+
const b = xof();
|
|
1087
|
+
for (let i = 0; j < N && i < b.length; i += 1) {
|
|
1088
|
+
const d1 = CoefFromHalfByte(b[i] & 15);
|
|
1089
|
+
const d2 = CoefFromHalfByte(b[i] >> 4 & 15);
|
|
1090
|
+
if (d1 !== false)
|
|
1091
|
+
r[j++] = d1;
|
|
1092
|
+
if (j < N && d2 !== false)
|
|
1093
|
+
r[j++] = d2;
|
|
1094
|
+
}
|
|
1095
|
+
}
|
|
1096
|
+
return r;
|
|
1097
|
+
}
|
|
1098
|
+
const SampleInBall = (seed) => {
|
|
1099
|
+
const pre = newPoly(N);
|
|
1100
|
+
const s = shake256.create({}).update(seed);
|
|
1101
|
+
const buf = new Uint8Array(shake256.blockLen);
|
|
1102
|
+
s.xofInto(buf);
|
|
1103
|
+
const masks = buf.slice(0, 8);
|
|
1104
|
+
for (let i = N - TAU, pos = 8, maskPos = 0, maskBit = 0; i < N; i++) {
|
|
1105
|
+
let b = i + 1;
|
|
1106
|
+
for (; b > i; ) {
|
|
1107
|
+
b = buf[pos++];
|
|
1108
|
+
if (pos < shake256.blockLen)
|
|
1109
|
+
continue;
|
|
1110
|
+
s.xofInto(buf);
|
|
1111
|
+
pos = 0;
|
|
1112
|
+
}
|
|
1113
|
+
pre[i] = pre[b];
|
|
1114
|
+
pre[b] = 1 - ((masks[maskPos] >> maskBit++ & 1) << 1);
|
|
1115
|
+
if (maskBit >= 8) {
|
|
1116
|
+
maskPos++;
|
|
1117
|
+
maskBit = 0;
|
|
1118
|
+
}
|
|
1119
|
+
}
|
|
1120
|
+
return pre;
|
|
1121
|
+
};
|
|
1122
|
+
const polyPowerRound = (p) => {
|
|
1123
|
+
const res0 = newPoly(N);
|
|
1124
|
+
const res1 = newPoly(N);
|
|
1125
|
+
for (let i = 0; i < p.length; i++) {
|
|
1126
|
+
const { r0, r1 } = Power2Round(p[i]);
|
|
1127
|
+
res0[i] = r0;
|
|
1128
|
+
res1[i] = r1;
|
|
1129
|
+
}
|
|
1130
|
+
return { r0: res0, r1: res1 };
|
|
1131
|
+
};
|
|
1132
|
+
const polyUseHint = (u, h) => {
|
|
1133
|
+
for (let i = 0; i < N; i++)
|
|
1134
|
+
u[i] = UseHint(h[i], u[i]);
|
|
1135
|
+
return u;
|
|
1136
|
+
};
|
|
1137
|
+
const polyMakeHint = (a, b) => {
|
|
1138
|
+
const v = newPoly(N);
|
|
1139
|
+
let cnt = 0;
|
|
1140
|
+
for (let i = 0; i < N; i++) {
|
|
1141
|
+
const h = MakeHint(a[i], b[i]);
|
|
1142
|
+
v[i] = h;
|
|
1143
|
+
cnt += h;
|
|
1144
|
+
}
|
|
1145
|
+
return { v, cnt };
|
|
1146
|
+
};
|
|
1147
|
+
const signRandBytes = 32;
|
|
1148
|
+
const seedCoder = splitCoder(32, 64, 32);
|
|
1149
|
+
const internal = {
|
|
1150
|
+
signRandBytes,
|
|
1151
|
+
keygen: (seed = randomBytes2(32)) => {
|
|
1152
|
+
const seedDst = new Uint8Array(32 + 2);
|
|
1153
|
+
seedDst.set(seed);
|
|
1154
|
+
seedDst[32] = K;
|
|
1155
|
+
seedDst[33] = L;
|
|
1156
|
+
const [rho, rhoPrime, K_] = seedCoder.decode(shake256(seedDst, { dkLen: seedCoder.bytesLen }));
|
|
1157
|
+
const xofPrime = XOF2562(rhoPrime);
|
|
1158
|
+
const s1 = [];
|
|
1159
|
+
for (let i = 0; i < L; i++)
|
|
1160
|
+
s1.push(RejBoundedPoly(xofPrime.get(i & 255, i >> 8 & 255)));
|
|
1161
|
+
const s2 = [];
|
|
1162
|
+
for (let i = L; i < L + K; i++)
|
|
1163
|
+
s2.push(RejBoundedPoly(xofPrime.get(i & 255, i >> 8 & 255)));
|
|
1164
|
+
const s1Hat = s1.map((i) => NTT.encode(i.slice()));
|
|
1165
|
+
const t0 = [];
|
|
1166
|
+
const t1 = [];
|
|
1167
|
+
const xof = XOF1282(rho);
|
|
1168
|
+
const t = newPoly(N);
|
|
1169
|
+
for (let i = 0; i < K; i++) {
|
|
1170
|
+
t.fill(0);
|
|
1171
|
+
for (let j = 0; j < L; j++) {
|
|
1172
|
+
const aij = RejNTTPoly(xof.get(j, i));
|
|
1173
|
+
polyAdd(t, MultiplyNTTs(aij, s1Hat[j]));
|
|
1174
|
+
}
|
|
1175
|
+
NTT.decode(t);
|
|
1176
|
+
const { r0, r1 } = polyPowerRound(polyAdd(t, s2[i]));
|
|
1177
|
+
t0.push(r0);
|
|
1178
|
+
t1.push(r1);
|
|
1179
|
+
}
|
|
1180
|
+
const publicKey = publicCoder.encode([rho, t1]);
|
|
1181
|
+
const tr = shake256(publicKey, { dkLen: TR_BYTES });
|
|
1182
|
+
const secretKey = secretCoder.encode([rho, K_, tr, s1, s2, t0]);
|
|
1183
|
+
xof.clean();
|
|
1184
|
+
xofPrime.clean();
|
|
1185
|
+
cleanBytes(rho, rhoPrime, K_, s1, s2, s1Hat, t, t0, t1, tr, seedDst);
|
|
1186
|
+
return { publicKey, secretKey };
|
|
1187
|
+
},
|
|
1188
|
+
sign: (secretKey, msg, random) => {
|
|
1189
|
+
const [rho, _K, tr, s1, s2, t0] = secretCoder.decode(secretKey);
|
|
1190
|
+
const A = [];
|
|
1191
|
+
const xof = XOF1282(rho);
|
|
1192
|
+
for (let i = 0; i < K; i++) {
|
|
1193
|
+
const pv = [];
|
|
1194
|
+
for (let j = 0; j < L; j++)
|
|
1195
|
+
pv.push(RejNTTPoly(xof.get(j, i)));
|
|
1196
|
+
A.push(pv);
|
|
1197
|
+
}
|
|
1198
|
+
xof.clean();
|
|
1199
|
+
for (let i = 0; i < L; i++)
|
|
1200
|
+
NTT.encode(s1[i]);
|
|
1201
|
+
for (let i = 0; i < K; i++) {
|
|
1202
|
+
NTT.encode(s2[i]);
|
|
1203
|
+
NTT.encode(t0[i]);
|
|
1204
|
+
}
|
|
1205
|
+
const mu = shake256.create({ dkLen: CRH_BYTES }).update(tr).update(msg).digest();
|
|
1206
|
+
const rnd = random ? random : new Uint8Array(32);
|
|
1207
|
+
ensureBytes(rnd);
|
|
1208
|
+
const rhoprime = shake256.create({ dkLen: CRH_BYTES }).update(_K).update(rnd).update(mu).digest();
|
|
1209
|
+
ensureBytes(rhoprime, CRH_BYTES);
|
|
1210
|
+
const x256 = XOF2562(rhoprime, ZCoder.bytesLen);
|
|
1211
|
+
main_loop:
|
|
1212
|
+
for (let kappa = 0; ; ) {
|
|
1213
|
+
const y = [];
|
|
1214
|
+
for (let i = 0; i < L; i++, kappa++)
|
|
1215
|
+
y.push(ZCoder.decode(x256.get(kappa & 255, kappa >> 8)()));
|
|
1216
|
+
const z = y.map((i) => NTT.encode(i.slice()));
|
|
1217
|
+
const w = [];
|
|
1218
|
+
for (let i = 0; i < K; i++) {
|
|
1219
|
+
const wi = newPoly(N);
|
|
1220
|
+
for (let j = 0; j < L; j++)
|
|
1221
|
+
polyAdd(wi, MultiplyNTTs(A[i][j], z[j]));
|
|
1222
|
+
NTT.decode(wi);
|
|
1223
|
+
w.push(wi);
|
|
1224
|
+
}
|
|
1225
|
+
const w1 = w.map((j) => j.map(HighBits));
|
|
1226
|
+
const cTilde = shake256.create({ dkLen: C_TILDE_BYTES }).update(mu).update(W1Vec.encode(w1)).digest();
|
|
1227
|
+
const cHat = NTT.encode(SampleInBall(cTilde));
|
|
1228
|
+
const cs1 = s1.map((i) => MultiplyNTTs(i, cHat));
|
|
1229
|
+
for (let i = 0; i < L; i++) {
|
|
1230
|
+
polyAdd(NTT.decode(cs1[i]), y[i]);
|
|
1231
|
+
if (polyChknorm(cs1[i], GAMMA1 - BETA))
|
|
1232
|
+
continue main_loop;
|
|
1233
|
+
}
|
|
1234
|
+
let cnt = 0;
|
|
1235
|
+
const h = [];
|
|
1236
|
+
for (let i = 0; i < K; i++) {
|
|
1237
|
+
const cs2 = NTT.decode(MultiplyNTTs(s2[i], cHat));
|
|
1238
|
+
const r0 = polySub(w[i], cs2).map(LowBits);
|
|
1239
|
+
if (polyChknorm(r0, GAMMA2 - BETA))
|
|
1240
|
+
continue main_loop;
|
|
1241
|
+
const ct0 = NTT.decode(MultiplyNTTs(t0[i], cHat));
|
|
1242
|
+
if (polyChknorm(ct0, GAMMA2))
|
|
1243
|
+
continue main_loop;
|
|
1244
|
+
polyAdd(r0, ct0);
|
|
1245
|
+
const hint = polyMakeHint(r0, w1[i]);
|
|
1246
|
+
h.push(hint.v);
|
|
1247
|
+
cnt += hint.cnt;
|
|
1248
|
+
}
|
|
1249
|
+
if (cnt > OMEGA)
|
|
1250
|
+
continue;
|
|
1251
|
+
x256.clean();
|
|
1252
|
+
const res = sigCoder.encode([cTilde, cs1, h]);
|
|
1253
|
+
cleanBytes(cTilde, cs1, h, cHat, w1, w, z, y, rhoprime, mu, s1, s2, t0, ...A);
|
|
1254
|
+
return res;
|
|
1255
|
+
}
|
|
1256
|
+
throw new Error("Unreachable code path reached, report this error");
|
|
1257
|
+
},
|
|
1258
|
+
verify: (publicKey, msg, sig) => {
|
|
1259
|
+
const [rho, t1] = publicCoder.decode(publicKey);
|
|
1260
|
+
const tr = shake256(publicKey, { dkLen: TR_BYTES });
|
|
1261
|
+
if (sig.length !== sigCoder.bytesLen)
|
|
1262
|
+
return false;
|
|
1263
|
+
const [cTilde, z, h] = sigCoder.decode(sig);
|
|
1264
|
+
if (h === false)
|
|
1265
|
+
return false;
|
|
1266
|
+
for (let i = 0; i < L; i++)
|
|
1267
|
+
if (polyChknorm(z[i], GAMMA1 - BETA))
|
|
1268
|
+
return false;
|
|
1269
|
+
const mu = shake256.create({ dkLen: CRH_BYTES }).update(tr).update(msg).digest();
|
|
1270
|
+
const c2 = NTT.encode(SampleInBall(cTilde));
|
|
1271
|
+
const zNtt = z.map((i) => i.slice());
|
|
1272
|
+
for (let i = 0; i < L; i++)
|
|
1273
|
+
NTT.encode(zNtt[i]);
|
|
1274
|
+
const wTick1 = [];
|
|
1275
|
+
const xof = XOF1282(rho);
|
|
1276
|
+
for (let i = 0; i < K; i++) {
|
|
1277
|
+
const ct12d = MultiplyNTTs(NTT.encode(polyShiftl(t1[i])), c2);
|
|
1278
|
+
const Az = newPoly(N);
|
|
1279
|
+
for (let j = 0; j < L; j++) {
|
|
1280
|
+
const aij = RejNTTPoly(xof.get(j, i));
|
|
1281
|
+
polyAdd(Az, MultiplyNTTs(aij, zNtt[j]));
|
|
1282
|
+
}
|
|
1283
|
+
const wApprox = NTT.decode(polySub(Az, ct12d));
|
|
1284
|
+
wTick1.push(polyUseHint(wApprox, h[i]));
|
|
1285
|
+
}
|
|
1286
|
+
xof.clean();
|
|
1287
|
+
const c22 = shake256.create({ dkLen: C_TILDE_BYTES }).update(mu).update(W1Vec.encode(wTick1)).digest();
|
|
1288
|
+
for (const t of h) {
|
|
1289
|
+
const sum = t.reduce((acc, i) => acc + i, 0);
|
|
1290
|
+
if (!(sum <= OMEGA))
|
|
1291
|
+
return false;
|
|
1292
|
+
}
|
|
1293
|
+
for (const t of z)
|
|
1294
|
+
if (polyChknorm(t, GAMMA1 - BETA))
|
|
1295
|
+
return false;
|
|
1296
|
+
return equalBytes(cTilde, c22);
|
|
1297
|
+
}
|
|
1298
|
+
};
|
|
1299
|
+
const getMessage = (msg, ctx = EMPTY) => {
|
|
1300
|
+
ensureBytes(msg);
|
|
1301
|
+
ensureBytes(ctx);
|
|
1302
|
+
if (ctx.length > 255)
|
|
1303
|
+
throw new Error("context should be less than 255 bytes");
|
|
1304
|
+
return concatBytes(new Uint8Array([0, ctx.length]), ctx, msg);
|
|
1305
|
+
};
|
|
1306
|
+
return {
|
|
1307
|
+
internal,
|
|
1308
|
+
keygen: internal.keygen,
|
|
1309
|
+
signRandBytes: internal.signRandBytes,
|
|
1310
|
+
sign: (secretKey, msg, ctx = EMPTY, random) => {
|
|
1311
|
+
const M = getMessage(msg, ctx);
|
|
1312
|
+
const res = internal.sign(secretKey, M, random);
|
|
1313
|
+
M.fill(0);
|
|
1314
|
+
return res;
|
|
1315
|
+
},
|
|
1316
|
+
verify: (publicKey, msg, sig, ctx = EMPTY) => {
|
|
1317
|
+
return internal.verify(publicKey, getMessage(msg, ctx), sig);
|
|
1318
|
+
}
|
|
1319
|
+
};
|
|
1320
|
+
}
|
|
1321
|
+
var ml_dsa44 = /* @__PURE__ */ getDilithium({
|
|
1322
|
+
...PARAMS[2],
|
|
1323
|
+
CRH_BYTES: 64,
|
|
1324
|
+
TR_BYTES: 64,
|
|
1325
|
+
C_TILDE_BYTES: 32,
|
|
1326
|
+
XOF128,
|
|
1327
|
+
XOF256
|
|
1328
|
+
});
|
|
1329
|
+
var ml_dsa65 = /* @__PURE__ */ getDilithium({
|
|
1330
|
+
...PARAMS[3],
|
|
1331
|
+
CRH_BYTES: 64,
|
|
1332
|
+
TR_BYTES: 64,
|
|
1333
|
+
C_TILDE_BYTES: 48,
|
|
1334
|
+
XOF128,
|
|
1335
|
+
XOF256
|
|
1336
|
+
});
|
|
1337
|
+
var ml_dsa87 = /* @__PURE__ */ getDilithium({
|
|
1338
|
+
...PARAMS[5],
|
|
1339
|
+
CRH_BYTES: 64,
|
|
1340
|
+
TR_BYTES: 64,
|
|
1341
|
+
C_TILDE_BYTES: 64,
|
|
1342
|
+
XOF128,
|
|
1343
|
+
XOF256
|
|
1344
|
+
});
|
|
1345
|
+
function toBase64(bytes) {
|
|
1346
|
+
let binary = "";
|
|
1347
|
+
for (const byte of bytes)
|
|
1348
|
+
binary += String.fromCharCode(byte);
|
|
1349
|
+
return btoa(binary);
|
|
1350
|
+
}
|
|
1351
|
+
function fromBase64(b64) {
|
|
1352
|
+
return Uint8Array.from(atob(b64), (c2) => c2.charCodeAt(0));
|
|
1353
|
+
}
|
|
1354
|
+
function sign(privateKey, message) {
|
|
1355
|
+
const secretKey = fromBase64(privateKey);
|
|
1356
|
+
const msg = new TextEncoder().encode(message);
|
|
1357
|
+
const signature = ml_dsa65.sign(secretKey, msg);
|
|
1358
|
+
return toBase64(signature);
|
|
1359
|
+
}
|
|
1360
|
+
var XMP_NS = "http://ns.adobe.com/xap/1.0/\0";
|
|
1361
|
+
var XMP_NS_BYTES = new TextEncoder().encode(XMP_NS);
|
|
1362
|
+
function toUint8Array(content) {
|
|
1363
|
+
if (typeof content === "string")
|
|
1364
|
+
return new TextEncoder().encode(content);
|
|
1365
|
+
return content;
|
|
1366
|
+
}
|
|
1367
|
+
async function signContent(baseUrl, apiKey, input) {
|
|
1368
|
+
const bytes = toUint8Array(input.content);
|
|
1369
|
+
const contentHash = hash(bytes);
|
|
1370
|
+
const watermarkId = input.watermarkId ?? crypto.randomUUID();
|
|
1371
|
+
const signedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
1372
|
+
const signedPayload = {
|
|
1373
|
+
generator_id: input.generatorId,
|
|
1374
|
+
model: input.model,
|
|
1375
|
+
content_hash: contentHash,
|
|
1376
|
+
watermark_id: watermarkId,
|
|
1377
|
+
signed_at: signedAt
|
|
1378
|
+
};
|
|
1379
|
+
const message = canonicalJson(signedPayload);
|
|
1380
|
+
const signature = sign(input.privateKey, message);
|
|
1381
|
+
const res = await fetch(`${baseUrl}/v1/records`, {
|
|
1382
|
+
method: "POST",
|
|
1383
|
+
headers: {
|
|
1384
|
+
"Content-Type": "application/json",
|
|
1385
|
+
Authorization: `Bearer ${apiKey}`
|
|
1386
|
+
},
|
|
1387
|
+
body: JSON.stringify({
|
|
1388
|
+
watermark_id: watermarkId,
|
|
1389
|
+
generator_id: input.generatorId,
|
|
1390
|
+
model: input.model,
|
|
1391
|
+
content_hash: contentHash,
|
|
1392
|
+
signature,
|
|
1393
|
+
signed_payload: signedPayload
|
|
1394
|
+
})
|
|
1395
|
+
});
|
|
1396
|
+
if (!res.ok) {
|
|
1397
|
+
const err2 = await res.json().catch(() => ({}));
|
|
1398
|
+
throw new Error(err2.error ?? `HTTP ${res.status}`);
|
|
1399
|
+
}
|
|
1400
|
+
return res.json();
|
|
1401
|
+
}
|
|
1402
|
+
function toUint8Array2(content) {
|
|
1403
|
+
if (typeof content === "string")
|
|
1404
|
+
return new TextEncoder().encode(content);
|
|
1405
|
+
return content;
|
|
1406
|
+
}
|
|
1407
|
+
function uint8ToBase64(input) {
|
|
1408
|
+
let binary = "";
|
|
1409
|
+
for (let i = 0; i < input.length; i++) {
|
|
1410
|
+
binary += String.fromCharCode(input[i] ?? 0);
|
|
1411
|
+
}
|
|
1412
|
+
return btoa(binary);
|
|
1413
|
+
}
|
|
1414
|
+
async function verifyContent(baseUrl, apiKey, input) {
|
|
1415
|
+
const bytes = toUint8Array2(input.content);
|
|
1416
|
+
const form = new FormData();
|
|
1417
|
+
form.append("content", new Blob([bytes]), "content");
|
|
1418
|
+
if (input.token)
|
|
1419
|
+
form.append("token", input.token);
|
|
1420
|
+
const res = await fetch(`${baseUrl}/v1/verify`, {
|
|
1421
|
+
method: "POST",
|
|
1422
|
+
headers: { Authorization: `Bearer ${apiKey}` },
|
|
1423
|
+
body: form
|
|
1424
|
+
});
|
|
1425
|
+
if (!res.ok) {
|
|
1426
|
+
const err2 = await res.json().catch(() => ({}));
|
|
1427
|
+
throw new Error(err2.error ?? `HTTP ${res.status}`);
|
|
1428
|
+
}
|
|
1429
|
+
return res.json();
|
|
1430
|
+
}
|
|
1431
|
+
async function verifyBatch(baseUrl, apiKey, items) {
|
|
1432
|
+
const payload = {
|
|
1433
|
+
items: items.map((item) => ({
|
|
1434
|
+
content: uint8ToBase64(toUint8Array2(item.content)),
|
|
1435
|
+
...item.token && { token: item.token }
|
|
1436
|
+
}))
|
|
1437
|
+
};
|
|
1438
|
+
const res = await fetch(`${baseUrl}/v1/verify/batch`, {
|
|
1439
|
+
method: "POST",
|
|
1440
|
+
headers: {
|
|
1441
|
+
"Content-Type": "application/json",
|
|
1442
|
+
Authorization: `Bearer ${apiKey}`
|
|
1443
|
+
},
|
|
1444
|
+
body: JSON.stringify(payload)
|
|
1445
|
+
});
|
|
1446
|
+
if (!res.ok) {
|
|
1447
|
+
const err2 = await res.json().catch(() => ({}));
|
|
1448
|
+
throw new Error(err2.error ?? `HTTP ${res.status}`);
|
|
1449
|
+
}
|
|
1450
|
+
return res.json();
|
|
1451
|
+
}
|
|
1452
|
+
var CertivuClient = class {
|
|
1453
|
+
apiKey;
|
|
1454
|
+
baseUrl;
|
|
1455
|
+
generatorId;
|
|
1456
|
+
privateKey;
|
|
1457
|
+
constructor(config) {
|
|
1458
|
+
this.apiKey = config.apiKey;
|
|
1459
|
+
this.baseUrl = (config.baseUrl ?? "https://api.certivu.ai").replace(/\/$/, "");
|
|
1460
|
+
this.generatorId = config.generatorId;
|
|
1461
|
+
this.privateKey = config.privateKey;
|
|
1462
|
+
}
|
|
1463
|
+
async sign(input) {
|
|
1464
|
+
const generatorId = input.generatorId ?? this.generatorId;
|
|
1465
|
+
const privateKey = input.privateKey ?? this.privateKey;
|
|
1466
|
+
if (!generatorId)
|
|
1467
|
+
throw new Error("generatorId is required for sign (provide in config or input)");
|
|
1468
|
+
if (!privateKey)
|
|
1469
|
+
throw new Error("privateKey is required for sign (provide in config or input)");
|
|
1470
|
+
return signContent(this.baseUrl, this.apiKey, { ...input, generatorId, privateKey });
|
|
1471
|
+
}
|
|
1472
|
+
async verify(input) {
|
|
1473
|
+
return verifyContent(this.baseUrl, this.apiKey, input);
|
|
1474
|
+
}
|
|
1475
|
+
async verifyBatch(items) {
|
|
1476
|
+
return verifyBatch(this.baseUrl, this.apiKey, items);
|
|
1477
|
+
}
|
|
1478
|
+
async getAuditLog(options) {
|
|
1479
|
+
return getAuditLog(this.baseUrl, this.apiKey, options);
|
|
1480
|
+
}
|
|
1481
|
+
async getTokenStatus(token2) {
|
|
1482
|
+
const res = await fetch(`${this.baseUrl}/v1/verify/status/${encodeURIComponent(token2)}`);
|
|
1483
|
+
if (!res.ok) {
|
|
1484
|
+
const err2 = await res.json().catch(() => ({}));
|
|
1485
|
+
throw new Error(err2.error ?? `HTTP ${res.status}`);
|
|
1486
|
+
}
|
|
1487
|
+
return res.json();
|
|
1488
|
+
}
|
|
1489
|
+
};
|
|
1490
|
+
|
|
1491
|
+
// src/commands/sign.ts
|
|
1492
|
+
async function signCommand(filePath, flags) {
|
|
1493
|
+
if (!filePath) die("Usage: certivu sign <file> --model <model>");
|
|
1494
|
+
const config = await loadConfig();
|
|
1495
|
+
const apiKey = flags.apiKey ?? config.apiKey;
|
|
1496
|
+
const generatorId = flags.generatorId ?? config.generatorId;
|
|
1497
|
+
const privateKey = flags.privateKey ?? config.privateKey;
|
|
1498
|
+
if (!apiKey) die("API key required. Set CERTIVU_API_KEY or run: certivu config set api-key <key>");
|
|
1499
|
+
if (!generatorId) die("Generator ID required. Set CERTIVU_GENERATOR_ID or run: certivu config set generator-id <id>");
|
|
1500
|
+
if (!privateKey) die("Private key required. Set CERTIVU_PRIVATE_KEY or run: certivu config set private-key <key>");
|
|
1501
|
+
let content;
|
|
1502
|
+
try {
|
|
1503
|
+
content = new Uint8Array((0, import_node_fs2.readFileSync)(filePath));
|
|
1504
|
+
} catch {
|
|
1505
|
+
die(`Cannot read file: ${filePath}`);
|
|
1506
|
+
}
|
|
1507
|
+
const clientConfig = {
|
|
1508
|
+
apiKey,
|
|
1509
|
+
generatorId,
|
|
1510
|
+
privateKey,
|
|
1511
|
+
...flags.baseUrl || config.baseUrl ? { baseUrl: flags.baseUrl ?? config.baseUrl } : {}
|
|
1512
|
+
};
|
|
1513
|
+
const client = new CertivuClient(clientConfig);
|
|
1514
|
+
let result;
|
|
1515
|
+
try {
|
|
1516
|
+
result = await client.sign({ content, model: flags.model, generatorId, privateKey });
|
|
1517
|
+
} catch (e) {
|
|
1518
|
+
const msg = e instanceof Error ? e.message : String(e);
|
|
1519
|
+
die(`Sign failed: ${msg}`);
|
|
1520
|
+
}
|
|
1521
|
+
console.log(ok("Signed"));
|
|
1522
|
+
row("Token", result.token);
|
|
1523
|
+
row("Record ID", result.record_id);
|
|
1524
|
+
if (result.deduplicated) {
|
|
1525
|
+
console.log(" (content already signed \u2014 existing token returned, no quota consumed)");
|
|
1526
|
+
}
|
|
1527
|
+
}
|
|
1528
|
+
|
|
1529
|
+
// src/commands/status.ts
|
|
1530
|
+
async function statusCommand(token, flags) {
|
|
1531
|
+
if (!token) die("Usage: certivu status <ctv_token>");
|
|
1532
|
+
const config = await loadConfig();
|
|
1533
|
+
const client = new CertivuClient({
|
|
1534
|
+
apiKey: config.apiKey ?? "public",
|
|
1535
|
+
...flags.baseUrl || config.baseUrl ? { baseUrl: flags.baseUrl ?? config.baseUrl } : {}
|
|
1536
|
+
});
|
|
1537
|
+
let status;
|
|
1538
|
+
try {
|
|
1539
|
+
status = await client.getTokenStatus(token);
|
|
1540
|
+
} catch (e) {
|
|
1541
|
+
const msg = e instanceof Error ? e.message : String(e);
|
|
1542
|
+
if (msg.includes("404") || msg.includes("not found")) {
|
|
1543
|
+
die("Token not found \u2014 record may not exist or token is invalid");
|
|
1544
|
+
}
|
|
1545
|
+
die(`Status lookup failed: ${msg}`);
|
|
1546
|
+
}
|
|
1547
|
+
if (status.generator_status === "active") {
|
|
1548
|
+
console.log(ok("Active"));
|
|
1549
|
+
} else {
|
|
1550
|
+
console.log(warn("Generator revoked \u2014 verifications for this token will fail"));
|
|
1551
|
+
}
|
|
1552
|
+
row("Record", status.record_id);
|
|
1553
|
+
row("Model", status.model);
|
|
1554
|
+
row("Signed", status.signed_at);
|
|
1555
|
+
row("Generator", status.generator_status === "active" ? "active" : "REVOKED");
|
|
1556
|
+
row("Org", status.org_id);
|
|
1557
|
+
}
|
|
1558
|
+
|
|
1559
|
+
// src/commands/verify.ts
|
|
1560
|
+
var import_node_fs3 = require("fs");
|
|
1561
|
+
async function verifyCommand(filePath, flags) {
|
|
1562
|
+
if (!filePath) die("Usage: certivu verify <file> [--token <ctv_token>]");
|
|
1563
|
+
const config = await loadConfig();
|
|
1564
|
+
let content;
|
|
1565
|
+
try {
|
|
1566
|
+
content = new Uint8Array((0, import_node_fs3.readFileSync)(filePath));
|
|
1567
|
+
} catch {
|
|
1568
|
+
die(`Cannot read file: ${filePath}`);
|
|
1569
|
+
}
|
|
1570
|
+
const client = new CertivuClient({
|
|
1571
|
+
apiKey: flags.apiKey ?? config.apiKey ?? "public",
|
|
1572
|
+
...flags.baseUrl || config.baseUrl ? { baseUrl: flags.baseUrl ?? config.baseUrl } : {}
|
|
1573
|
+
});
|
|
1574
|
+
let result;
|
|
1575
|
+
try {
|
|
1576
|
+
result = await client.verify({ content, ...flags.token ? { token: flags.token } : {} });
|
|
1577
|
+
} catch (e) {
|
|
1578
|
+
const msg = e instanceof Error ? e.message : String(e);
|
|
1579
|
+
die(`Verify failed: ${msg}`);
|
|
1580
|
+
}
|
|
1581
|
+
if (result.authentic) {
|
|
1582
|
+
console.log(ok(`Authentic \u2014 ${confidenceBadge(result.confidence)} confidence`));
|
|
1583
|
+
if (result.provenance) {
|
|
1584
|
+
row("Org", result.provenance.org);
|
|
1585
|
+
row("Model", result.provenance.model);
|
|
1586
|
+
row("Signed", result.provenance.signed_at);
|
|
1587
|
+
}
|
|
1588
|
+
if (result.token_source) row("Source", result.token_source);
|
|
1589
|
+
} else if (result.tampered) {
|
|
1590
|
+
console.log(err("Tampered \u2014 content has been modified since signing"));
|
|
1591
|
+
row("Reason", result.reason ?? "hash mismatch");
|
|
1592
|
+
} else {
|
|
1593
|
+
console.log(err(`Not verified \u2014 ${result.reason ?? "no provenance found"}`));
|
|
1594
|
+
console.log(" Absence of provenance does not imply human origin.");
|
|
1595
|
+
}
|
|
1596
|
+
const { signals } = result;
|
|
1597
|
+
const signalLine = [
|
|
1598
|
+
signals.watermark_found ? "watermark \u2713" : "watermark \u2717",
|
|
1599
|
+
signals.record_found ? "record \u2713" : "record \u2717",
|
|
1600
|
+
signals.signature_valid ? "signature \u2713" : "signature \u2717"
|
|
1601
|
+
].join(" ");
|
|
1602
|
+
console.log(`
|
|
1603
|
+
Signals: ${signalLine}`);
|
|
1604
|
+
}
|
|
1605
|
+
|
|
1606
|
+
// src/index.ts
|
|
1607
|
+
var VERSION = "1.1.0";
|
|
1608
|
+
var HELP = `
|
|
1609
|
+
${amber("certivu")} \u2014 quantum-resistant AI content trust
|
|
1610
|
+
|
|
1611
|
+
${bold("Usage:")}
|
|
1612
|
+
certivu sign <file> --model <model> [flags]
|
|
1613
|
+
certivu verify <file> [--token <ctv_token>]
|
|
1614
|
+
certivu status <ctv_token>
|
|
1615
|
+
certivu config [get | set <key> <value>]
|
|
1616
|
+
|
|
1617
|
+
${bold("Commands:")}
|
|
1618
|
+
sign Hash, sign, and submit a provenance record for AI-generated content
|
|
1619
|
+
verify Verify content authenticity (free, no API key required)
|
|
1620
|
+
status Lightweight token lookup without re-uploading the image
|
|
1621
|
+
config View or update local configuration
|
|
1622
|
+
|
|
1623
|
+
${bold("Sign flags:")}
|
|
1624
|
+
--model <name> AI model name, e.g. stable-diffusion-xl ${dim("(required)")}
|
|
1625
|
+
--generator-id <id> Override generator ID
|
|
1626
|
+
--private-key <key> Override ML-DSA private key (base64)
|
|
1627
|
+
--api-key <key> Override API key
|
|
1628
|
+
|
|
1629
|
+
${bold("Verify flags:")}
|
|
1630
|
+
--token <ctv_token> Provide token explicitly (extracted automatically if omitted)
|
|
1631
|
+
|
|
1632
|
+
${bold("Global flags:")}
|
|
1633
|
+
--base-url <url> Override API base URL ${dim("(default: https://api.certivu.ai)")}
|
|
1634
|
+
--version, -v Print version
|
|
1635
|
+
--help, -h Print this help
|
|
1636
|
+
|
|
1637
|
+
${bold("Config keys:")}
|
|
1638
|
+
api-key, generator-id, private-key, base-url
|
|
1639
|
+
|
|
1640
|
+
${bold("Environment variables:")}
|
|
1641
|
+
CERTIVU_API_KEY, CERTIVU_GENERATOR_ID, CERTIVU_PRIVATE_KEY, CERTIVU_BASE_URL
|
|
1642
|
+
|
|
1643
|
+
${bold("Examples:")}
|
|
1644
|
+
certivu config set api-key ctv_key_abc123
|
|
1645
|
+
certivu sign ./output.jpg --model stable-diffusion-xl
|
|
1646
|
+
certivu verify ./output.jpg
|
|
1647
|
+
certivu status ctv_7f3kx9mq2...
|
|
1648
|
+
`.trim();
|
|
1649
|
+
function parseArgs(argv) {
|
|
1650
|
+
const [command = "", ...rest] = argv;
|
|
1651
|
+
const positional = [];
|
|
1652
|
+
const flags = {};
|
|
1653
|
+
for (let i = 0; i < rest.length; i++) {
|
|
1654
|
+
const arg = rest[i];
|
|
1655
|
+
if (arg?.startsWith("--")) {
|
|
1656
|
+
const key = arg.slice(2);
|
|
1657
|
+
const next = rest[i + 1];
|
|
1658
|
+
if (next && !next.startsWith("--")) {
|
|
1659
|
+
const camel = key.replace(/-([a-z])/g, (_, c2) => c2.toUpperCase());
|
|
1660
|
+
flags[camel] = next;
|
|
1661
|
+
i++;
|
|
1662
|
+
} else {
|
|
1663
|
+
flags[key] = true;
|
|
1664
|
+
}
|
|
1665
|
+
} else if (arg) {
|
|
1666
|
+
positional.push(arg);
|
|
1667
|
+
}
|
|
1668
|
+
}
|
|
1669
|
+
return { command, positional, flags };
|
|
1670
|
+
}
|
|
1671
|
+
async function main() {
|
|
1672
|
+
const argv = process.argv.slice(2);
|
|
1673
|
+
if (argv.length === 0 || argv[0] === "--help" || argv[0] === "-h") {
|
|
1674
|
+
console.log(HELP);
|
|
1675
|
+
process.exit(0);
|
|
1676
|
+
}
|
|
1677
|
+
if (argv[0] === "--version" || argv[0] === "-v") {
|
|
1678
|
+
console.log(VERSION);
|
|
1679
|
+
process.exit(0);
|
|
1680
|
+
}
|
|
1681
|
+
const { command, positional, flags } = parseArgs(argv);
|
|
1682
|
+
try {
|
|
1683
|
+
switch (command) {
|
|
1684
|
+
case "sign":
|
|
1685
|
+
await signCommand(positional[0] ?? "", flags);
|
|
1686
|
+
break;
|
|
1687
|
+
case "verify":
|
|
1688
|
+
await verifyCommand(positional[0] ?? "", flags);
|
|
1689
|
+
break;
|
|
1690
|
+
case "status":
|
|
1691
|
+
await statusCommand(positional[0] ?? "", flags);
|
|
1692
|
+
break;
|
|
1693
|
+
case "config":
|
|
1694
|
+
await configCommand(positional[0] ?? "get", positional[1], positional[2]);
|
|
1695
|
+
break;
|
|
1696
|
+
default:
|
|
1697
|
+
die(`Unknown command: ${command}
|
|
1698
|
+
Run 'certivu --help' for usage.`);
|
|
1699
|
+
}
|
|
1700
|
+
} catch (e) {
|
|
1701
|
+
const msg = e instanceof Error ? e.message : String(e);
|
|
1702
|
+
die(`Unexpected error: ${msg}`);
|
|
1703
|
+
}
|
|
1704
|
+
}
|
|
1705
|
+
main();
|
|
1706
|
+
/*! noble-hashes - MIT License (c) 2022 Paul Miller (paulmillr.com) */
|
|
1707
|
+
/*! noble-post-quantum - MIT License (c) 2024 Paul Miller (paulmillr.com) */
|