@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 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: "skip",
2133
- detail: receipt.signature ? "present (local recompute via RedPill keyset canonicalization = roadmap)" : "no signature on receipt",
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,