@t2000/sdk 5.17.0 → 5.19.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 +112 -5
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +21 -6
- package/dist/index.d.ts +21 -6
- package/dist/index.js +112 -5
- 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
|
|
|
@@ -2031,9 +2034,85 @@ async function listModels(opts) {
|
|
|
2031
2034
|
}));
|
|
2032
2035
|
}
|
|
2033
2036
|
var RECEIPT_ANCHORED_SUFFIX = "::anchor::ReceiptAnchored";
|
|
2037
|
+
function normalizeClaims(claims) {
|
|
2038
|
+
if (!claims) {
|
|
2039
|
+
return [];
|
|
2040
|
+
}
|
|
2041
|
+
if (Array.isArray(claims)) {
|
|
2042
|
+
return claims.filter((c) => c.name).map((c) => ({
|
|
2043
|
+
name: c.name,
|
|
2044
|
+
status: c.status ?? "unknown",
|
|
2045
|
+
source: c.source
|
|
2046
|
+
}));
|
|
2047
|
+
}
|
|
2048
|
+
return Object.entries(claims).map(([name, v]) => ({
|
|
2049
|
+
name,
|
|
2050
|
+
status: v?.status ?? "unknown",
|
|
2051
|
+
source: v?.source
|
|
2052
|
+
}));
|
|
2053
|
+
}
|
|
2034
2054
|
function fullnodeUrl(network) {
|
|
2035
2055
|
return network === "testnet" ? "https://fullnode.testnet.sui.io" : "https://fullnode.mainnet.sui.io";
|
|
2036
2056
|
}
|
|
2057
|
+
function jcs(value) {
|
|
2058
|
+
if (value === null) {
|
|
2059
|
+
return "null";
|
|
2060
|
+
}
|
|
2061
|
+
if (typeof value === "boolean") {
|
|
2062
|
+
return value ? "true" : "false";
|
|
2063
|
+
}
|
|
2064
|
+
if (typeof value === "number") {
|
|
2065
|
+
if (!Number.isInteger(value)) {
|
|
2066
|
+
throw new Error("JCS: non-integer number");
|
|
2067
|
+
}
|
|
2068
|
+
return String(value);
|
|
2069
|
+
}
|
|
2070
|
+
if (typeof value === "string") {
|
|
2071
|
+
return JSON.stringify(value);
|
|
2072
|
+
}
|
|
2073
|
+
if (Array.isArray(value)) {
|
|
2074
|
+
return `[${value.map(jcs).join(",")}]`;
|
|
2075
|
+
}
|
|
2076
|
+
const keys = Object.keys(value).sort();
|
|
2077
|
+
return `{${keys.map((k) => `${JSON.stringify(k)}:${jcs(value[k])}`).join(",")}}`;
|
|
2078
|
+
}
|
|
2079
|
+
function verifyReceiptSignature(receipt, signingKeyHex) {
|
|
2080
|
+
try {
|
|
2081
|
+
const sig = receipt.signature;
|
|
2082
|
+
if (sig?.algo !== "ecdsa-secp256k1" || !sig.value) {
|
|
2083
|
+
return false;
|
|
2084
|
+
}
|
|
2085
|
+
const canonical = {
|
|
2086
|
+
api_version: receipt.api_version ?? "",
|
|
2087
|
+
receipt_id: receipt.receipt_id ?? "",
|
|
2088
|
+
chat_id: receipt.chat_id ?? null,
|
|
2089
|
+
workload_id: receipt.workload_id ?? "",
|
|
2090
|
+
workload_keyset_digest: receipt.workload_keyset_digest ?? "",
|
|
2091
|
+
endpoint: receipt.endpoint ?? "",
|
|
2092
|
+
method: receipt.method ?? "",
|
|
2093
|
+
served_at: receipt.served_at ?? 0,
|
|
2094
|
+
event_log: receipt.event_log ?? [],
|
|
2095
|
+
signature: { algo: sig.algo, key_id: sig.key_id ?? "" }
|
|
2096
|
+
};
|
|
2097
|
+
const prehash = sha256.sha256(new TextEncoder().encode(jcs(canonical)));
|
|
2098
|
+
const sigBytes = utils$1.hexToBytes(sig.value);
|
|
2099
|
+
if (sigBytes.length !== 65) {
|
|
2100
|
+
return false;
|
|
2101
|
+
}
|
|
2102
|
+
let v = sigBytes[64];
|
|
2103
|
+
if (v >= 27 && v <= 30) {
|
|
2104
|
+
v -= 27;
|
|
2105
|
+
}
|
|
2106
|
+
if (v > 3) {
|
|
2107
|
+
return false;
|
|
2108
|
+
}
|
|
2109
|
+
const recovered = secp256k1.secp256k1.Signature.fromCompact(sigBytes.slice(0, 64)).addRecoveryBit(v).recoverPublicKey(prehash).toHex(false);
|
|
2110
|
+
const endorsed = utils$1.bytesToHex(utils$1.hexToBytes(signingKeyHex.replace(/^0x/, "")));
|
|
2111
|
+
return recovered.toLowerCase() === endorsed.toLowerCase();
|
|
2112
|
+
} catch {
|
|
2113
|
+
return false;
|
|
2114
|
+
}
|
|
2115
|
+
}
|
|
2037
2116
|
async function verifyReceipt(receiptId, opts = {}) {
|
|
2038
2117
|
const base = opts.apiBase ?? DEFAULT_API_BASE;
|
|
2039
2118
|
const network = opts.network ?? "mainnet";
|
|
@@ -2065,6 +2144,7 @@ async function verifyReceipt(receiptId, opts = {}) {
|
|
|
2065
2144
|
});
|
|
2066
2145
|
const upstreamEv = receipt.event_log.find((e) => e.type === "upstream.verified");
|
|
2067
2146
|
const upstreamOk = upstreamEv?.result === "verified";
|
|
2147
|
+
const claims = normalizeClaims(upstreamEv?.claims);
|
|
2068
2148
|
checks.push({
|
|
2069
2149
|
name: "Confidential upstream",
|
|
2070
2150
|
status: upstreamEv ? upstreamOk ? "pass" : "fail" : "skip",
|
|
@@ -2127,23 +2207,50 @@ async function verifyReceipt(receiptId, opts = {}) {
|
|
|
2127
2207
|
});
|
|
2128
2208
|
}
|
|
2129
2209
|
}
|
|
2210
|
+
let signatureForged = false;
|
|
2211
|
+
let sigStatus = "skip";
|
|
2212
|
+
let sigDetail = "no signature on receipt";
|
|
2213
|
+
if (receipt.signature?.value) {
|
|
2214
|
+
try {
|
|
2215
|
+
const model = opts.model ?? "phala/glm-5.2";
|
|
2216
|
+
const res = await fetch(
|
|
2217
|
+
`${base}/aci/attestation?model=${encodeURIComponent(model)}`
|
|
2218
|
+
);
|
|
2219
|
+
const att = res.ok ? await res.json() : null;
|
|
2220
|
+
if (!att?.signingKey) {
|
|
2221
|
+
sigDetail = "could not fetch the attested keyset to check the signature";
|
|
2222
|
+
} else if (att.workloadId && att.workloadId !== workloadId) {
|
|
2223
|
+
sigDetail = `attested keyset is for a different workload \u2014 pass --model for ${workloadId}`;
|
|
2224
|
+
} else {
|
|
2225
|
+
const ok = verifyReceiptSignature(receipt, att.signingKey);
|
|
2226
|
+
sigStatus = ok ? "pass" : "fail";
|
|
2227
|
+
signatureForged = !ok;
|
|
2228
|
+
sigDetail = ok ? `signed by the attested receipt key (${receipt.signature.key_id ?? "key"})` : "signature does NOT recover the attested receipt key \u2014 forged/altered";
|
|
2229
|
+
}
|
|
2230
|
+
} catch {
|
|
2231
|
+
sigDetail = "signature check errored";
|
|
2232
|
+
}
|
|
2233
|
+
}
|
|
2130
2234
|
checks.push({
|
|
2131
2235
|
name: "Receipt signature",
|
|
2132
|
-
status:
|
|
2133
|
-
detail:
|
|
2134
|
-
trust: "roadmap"
|
|
2236
|
+
status: sigStatus,
|
|
2237
|
+
detail: sigDetail,
|
|
2238
|
+
trust: sigStatus === "skip" ? "roadmap" : "trustless"
|
|
2135
2239
|
});
|
|
2136
2240
|
return {
|
|
2137
2241
|
receiptId,
|
|
2138
|
-
verified: Boolean(wireHash && workloadId) && anchorVerified,
|
|
2242
|
+
verified: Boolean(wireHash && workloadId) && anchorVerified && !signatureForged,
|
|
2139
2243
|
anchorVerified,
|
|
2140
2244
|
checks,
|
|
2141
2245
|
wireHash,
|
|
2142
2246
|
workloadId,
|
|
2143
2247
|
upstream: upstreamEv ? {
|
|
2144
2248
|
provider: upstreamEv.provider ?? upstreamEv.upstream_name,
|
|
2249
|
+
modelId: upstreamEv.model_id,
|
|
2145
2250
|
result: upstreamEv.result,
|
|
2146
|
-
tcbStatus: upstreamEv.tcb_status
|
|
2251
|
+
tcbStatus: upstreamEv.tcb_status,
|
|
2252
|
+
sessionId: upstreamEv.session_id,
|
|
2253
|
+
claims: claims.length > 0 ? claims : void 0
|
|
2147
2254
|
} : void 0,
|
|
2148
2255
|
anchor
|
|
2149
2256
|
};
|