@t2000/sdk 5.17.0 → 5.18.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.cjs +90 -4
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +3 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.js +90 -4
- package/dist/index.js.map +1 -1
- package/package.json +3 -1
package/dist/index.cjs
CHANGED
|
@@ -13,6 +13,9 @@ var cryptography = require('@mysten/sui/cryptography');
|
|
|
13
13
|
var promises = require('fs/promises');
|
|
14
14
|
var path = require('path');
|
|
15
15
|
var os = require('os');
|
|
16
|
+
var secp256k1 = require('@noble/curves/secp256k1');
|
|
17
|
+
var sha256 = require('@noble/hashes/sha256');
|
|
18
|
+
var utils$1 = require('@noble/hashes/utils');
|
|
16
19
|
var fs = require('fs');
|
|
17
20
|
var suins = require('@mysten/suins');
|
|
18
21
|
|
|
@@ -2034,6 +2037,65 @@ var RECEIPT_ANCHORED_SUFFIX = "::anchor::ReceiptAnchored";
|
|
|
2034
2037
|
function fullnodeUrl(network) {
|
|
2035
2038
|
return network === "testnet" ? "https://fullnode.testnet.sui.io" : "https://fullnode.mainnet.sui.io";
|
|
2036
2039
|
}
|
|
2040
|
+
function jcs(value) {
|
|
2041
|
+
if (value === null) {
|
|
2042
|
+
return "null";
|
|
2043
|
+
}
|
|
2044
|
+
if (typeof value === "boolean") {
|
|
2045
|
+
return value ? "true" : "false";
|
|
2046
|
+
}
|
|
2047
|
+
if (typeof value === "number") {
|
|
2048
|
+
if (!Number.isInteger(value)) {
|
|
2049
|
+
throw new Error("JCS: non-integer number");
|
|
2050
|
+
}
|
|
2051
|
+
return String(value);
|
|
2052
|
+
}
|
|
2053
|
+
if (typeof value === "string") {
|
|
2054
|
+
return JSON.stringify(value);
|
|
2055
|
+
}
|
|
2056
|
+
if (Array.isArray(value)) {
|
|
2057
|
+
return `[${value.map(jcs).join(",")}]`;
|
|
2058
|
+
}
|
|
2059
|
+
const keys = Object.keys(value).sort();
|
|
2060
|
+
return `{${keys.map((k) => `${JSON.stringify(k)}:${jcs(value[k])}`).join(",")}}`;
|
|
2061
|
+
}
|
|
2062
|
+
function verifyReceiptSignature(receipt, signingKeyHex) {
|
|
2063
|
+
try {
|
|
2064
|
+
const sig = receipt.signature;
|
|
2065
|
+
if (sig?.algo !== "ecdsa-secp256k1" || !sig.value) {
|
|
2066
|
+
return false;
|
|
2067
|
+
}
|
|
2068
|
+
const canonical = {
|
|
2069
|
+
api_version: receipt.api_version ?? "",
|
|
2070
|
+
receipt_id: receipt.receipt_id ?? "",
|
|
2071
|
+
chat_id: receipt.chat_id ?? null,
|
|
2072
|
+
workload_id: receipt.workload_id ?? "",
|
|
2073
|
+
workload_keyset_digest: receipt.workload_keyset_digest ?? "",
|
|
2074
|
+
endpoint: receipt.endpoint ?? "",
|
|
2075
|
+
method: receipt.method ?? "",
|
|
2076
|
+
served_at: receipt.served_at ?? 0,
|
|
2077
|
+
event_log: receipt.event_log ?? [],
|
|
2078
|
+
signature: { algo: sig.algo, key_id: sig.key_id ?? "" }
|
|
2079
|
+
};
|
|
2080
|
+
const prehash = sha256.sha256(new TextEncoder().encode(jcs(canonical)));
|
|
2081
|
+
const sigBytes = utils$1.hexToBytes(sig.value);
|
|
2082
|
+
if (sigBytes.length !== 65) {
|
|
2083
|
+
return false;
|
|
2084
|
+
}
|
|
2085
|
+
let v = sigBytes[64];
|
|
2086
|
+
if (v >= 27 && v <= 30) {
|
|
2087
|
+
v -= 27;
|
|
2088
|
+
}
|
|
2089
|
+
if (v > 3) {
|
|
2090
|
+
return false;
|
|
2091
|
+
}
|
|
2092
|
+
const recovered = secp256k1.secp256k1.Signature.fromCompact(sigBytes.slice(0, 64)).addRecoveryBit(v).recoverPublicKey(prehash).toHex(false);
|
|
2093
|
+
const endorsed = utils$1.bytesToHex(utils$1.hexToBytes(signingKeyHex.replace(/^0x/, "")));
|
|
2094
|
+
return recovered.toLowerCase() === endorsed.toLowerCase();
|
|
2095
|
+
} catch {
|
|
2096
|
+
return false;
|
|
2097
|
+
}
|
|
2098
|
+
}
|
|
2037
2099
|
async function verifyReceipt(receiptId, opts = {}) {
|
|
2038
2100
|
const base = opts.apiBase ?? DEFAULT_API_BASE;
|
|
2039
2101
|
const network = opts.network ?? "mainnet";
|
|
@@ -2127,15 +2189,39 @@ async function verifyReceipt(receiptId, opts = {}) {
|
|
|
2127
2189
|
});
|
|
2128
2190
|
}
|
|
2129
2191
|
}
|
|
2192
|
+
let signatureForged = false;
|
|
2193
|
+
let sigStatus = "skip";
|
|
2194
|
+
let sigDetail = "no signature on receipt";
|
|
2195
|
+
if (receipt.signature?.value) {
|
|
2196
|
+
try {
|
|
2197
|
+
const model = opts.model ?? "phala/glm-5.2";
|
|
2198
|
+
const res = await fetch(
|
|
2199
|
+
`${base}/aci/attestation?model=${encodeURIComponent(model)}`
|
|
2200
|
+
);
|
|
2201
|
+
const att = res.ok ? await res.json() : null;
|
|
2202
|
+
if (!att?.signingKey) {
|
|
2203
|
+
sigDetail = "could not fetch the attested keyset to check the signature";
|
|
2204
|
+
} else if (att.workloadId && att.workloadId !== workloadId) {
|
|
2205
|
+
sigDetail = `attested keyset is for a different workload \u2014 pass --model for ${workloadId}`;
|
|
2206
|
+
} else {
|
|
2207
|
+
const ok = verifyReceiptSignature(receipt, att.signingKey);
|
|
2208
|
+
sigStatus = ok ? "pass" : "fail";
|
|
2209
|
+
signatureForged = !ok;
|
|
2210
|
+
sigDetail = ok ? `signed by the attested receipt key (${receipt.signature.key_id ?? "key"})` : "signature does NOT recover the attested receipt key \u2014 forged/altered";
|
|
2211
|
+
}
|
|
2212
|
+
} catch {
|
|
2213
|
+
sigDetail = "signature check errored";
|
|
2214
|
+
}
|
|
2215
|
+
}
|
|
2130
2216
|
checks.push({
|
|
2131
2217
|
name: "Receipt signature",
|
|
2132
|
-
status:
|
|
2133
|
-
detail:
|
|
2134
|
-
trust: "roadmap"
|
|
2218
|
+
status: sigStatus,
|
|
2219
|
+
detail: sigDetail,
|
|
2220
|
+
trust: sigStatus === "skip" ? "roadmap" : "trustless"
|
|
2135
2221
|
});
|
|
2136
2222
|
return {
|
|
2137
2223
|
receiptId,
|
|
2138
|
-
verified: Boolean(wireHash && workloadId) && anchorVerified,
|
|
2224
|
+
verified: Boolean(wireHash && workloadId) && anchorVerified && !signatureForged,
|
|
2139
2225
|
anchorVerified,
|
|
2140
2226
|
checks,
|
|
2141
2227
|
wireHash,
|