@continuonai/rcan-ts 1.2.0 → 1.2.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.
package/dist/index.mjs CHANGED
@@ -97,7 +97,7 @@ var RobotURI = class _RobotURI {
97
97
 
98
98
  // src/version.ts
99
99
  var SPEC_VERSION = "2.2.0";
100
- var SDK_VERSION = "1.2.0";
100
+ var SDK_VERSION = "1.2.1";
101
101
  function validateVersionCompat(incomingVersion, localVersion = SPEC_VERSION) {
102
102
  const parseParts = (v) => {
103
103
  const parts = v.split(".");
@@ -276,7 +276,6 @@ var RCANMessage = class _RCANMessage {
276
276
  if (this.mediaChunks !== void 0) obj.mediaChunks = this.mediaChunks;
277
277
  if (this.firmwareHash !== void 0) obj.firmwareHash = this.firmwareHash;
278
278
  if (this.attestationRef !== void 0) obj.attestationRef = this.attestationRef;
279
- if (this.pqSig !== void 0) obj.pqSig = this.pqSig;
280
279
  return obj;
281
280
  }
282
281
  /** Serialize to JSON string */
@@ -3103,21 +3102,15 @@ function fromBase64url(b64) {
3103
3102
  return bytes;
3104
3103
  }
3105
3104
  async function sha256hex(data) {
3106
- const g = typeof globalThis !== "undefined" ? globalThis : {};
3107
- const webcrypto = g.crypto;
3108
- const subtle = webcrypto?.subtle;
3109
- if (subtle) {
3110
- const buf = await subtle.digest("SHA-256", data);
3105
+ if (typeof crypto !== "undefined" && crypto.subtle) {
3106
+ const buf = await crypto.subtle.digest("SHA-256", data.buffer);
3111
3107
  return Array.from(new Uint8Array(buf)).map((b) => b.toString(16).padStart(2, "0")).join("").slice(0, 8);
3112
3108
  }
3113
- const nodeCrypto = await import("crypto").catch(() => null);
3114
- if (nodeCrypto) {
3115
- return nodeCrypto.createHash("sha256").update(data).digest("hex").slice(0, 8);
3116
- }
3117
- throw new Error("No SHA-256 implementation available");
3109
+ const { createHash } = __require("crypto");
3110
+ return createHash("sha256").update(data).digest("hex").slice(0, 8);
3118
3111
  }
3119
3112
  var _mlDsaModule;
3120
- async function requireNoblePostQuantum() {
3113
+ async function requireMlDsa() {
3121
3114
  if (_mlDsaModule) return _mlDsaModule;
3122
3115
  if (typeof __require !== "undefined") {
3123
3116
  try {
@@ -3131,7 +3124,7 @@ async function requireNoblePostQuantum() {
3131
3124
  return _mlDsaModule;
3132
3125
  } catch {
3133
3126
  throw new Error(
3134
- "ML-DSA signing requires @noble/post-quantum. Install with: npm install @noble/post-quantum"
3127
+ "ML-DSA-65 signing requires @noble/post-quantum. Install with: npm install @noble/post-quantum"
3135
3128
  );
3136
3129
  }
3137
3130
  }
@@ -3144,23 +3137,16 @@ var MLDSAKeyPair = class _MLDSAKeyPair {
3144
3137
  this.publicKey = data.publicKey;
3145
3138
  this.secretKey = data.secretKey;
3146
3139
  }
3147
- /** Generate a new ML-DSA-65 key pair. */
3148
3140
  static async generate() {
3149
- const { ml_dsa65 } = await requireNoblePostQuantum();
3150
- const kp = ml_dsa65.keygen();
3141
+ const m = await requireMlDsa();
3142
+ const kp = m.ml_dsa65.keygen();
3151
3143
  const keyId = await sha256hex(kp.publicKey);
3152
- return new _MLDSAKeyPair({
3153
- publicKey: kp.publicKey,
3154
- secretKey: kp.secretKey,
3155
- keyId
3156
- });
3144
+ return new _MLDSAKeyPair({ publicKey: kp.publicKey, secretKey: kp.secretKey, keyId });
3157
3145
  }
3158
- /** Build a verify-only key pair from raw public key bytes. */
3159
3146
  static async fromPublicKey(publicKey) {
3160
3147
  const keyId = await sha256hex(publicKey);
3161
3148
  return new _MLDSAKeyPair({ publicKey, keyId });
3162
3149
  }
3163
- /** Build a full key pair from saved bytes (public + secret). */
3164
3150
  static async fromKeyMaterial(publicKey, secretKey) {
3165
3151
  const keyId = await sha256hex(publicKey);
3166
3152
  return new _MLDSAKeyPair({ publicKey, secretKey, keyId });
@@ -3168,82 +3154,68 @@ var MLDSAKeyPair = class _MLDSAKeyPair {
3168
3154
  get hasPrivateKey() {
3169
3155
  return this.secretKey !== void 0;
3170
3156
  }
3171
- /** Sign raw bytes; returns ML-DSA-65 signature (3309 bytes). */
3172
3157
  async signBytes(data) {
3173
- if (!this.secretKey) {
3174
- throw new Error("Cannot sign: MLDSAKeyPair has no private key (verify-only)");
3175
- }
3176
- const { ml_dsa65 } = await requireNoblePostQuantum();
3177
- return ml_dsa65.sign(data, this.secretKey);
3158
+ if (!this.secretKey) throw new Error("Cannot sign: MLDSAKeyPair has no private key (verify-only)");
3159
+ const m = await requireMlDsa();
3160
+ return m.ml_dsa65.sign(data, this.secretKey);
3178
3161
  }
3179
- /**
3180
- * Verify an ML-DSA-65 signature.
3181
- * @returns true if valid
3182
- * @throws {Error} on invalid signature
3183
- */
3184
3162
  async verifyBytes(data, signature) {
3185
- const { ml_dsa65 } = await requireNoblePostQuantum();
3186
- const ok = ml_dsa65.verify(signature, data, this.publicKey);
3187
- if (!ok) throw new Error("ML-DSA signature verification failed");
3163
+ const m = await requireMlDsa();
3164
+ const ok = m.ml_dsa65.verify(signature, data, this.publicKey);
3165
+ if (!ok) throw new Error("ML-DSA-65 signature verification failed");
3188
3166
  }
3189
3167
  toString() {
3190
- const mode = this.hasPrivateKey ? "private+public" : "public-only";
3191
- return `MLDSAKeyPair(keyId=${this.keyId}, alg=ML-DSA-65, ${mode})`;
3168
+ return `MLDSAKeyPair(keyId=${this.keyId}, alg=ML-DSA-65, ${this.hasPrivateKey ? "private+public" : "public-only"})`;
3192
3169
  }
3193
3170
  };
3194
3171
  function canonicalMessageBytes(msg) {
3195
- const m = msg;
3196
3172
  const payload = {
3197
3173
  rcan: msg.rcan,
3198
- msg_id: m["msgId"] ?? m["msg_id"] ?? "",
3174
+ msg_id: msg["msgId"] ?? "",
3199
3175
  timestamp: msg.timestamp,
3200
3176
  cmd: msg.cmd,
3201
3177
  target: msg.target,
3202
3178
  params: msg.params
3203
3179
  };
3204
- const sorted = JSON.stringify(
3205
- Object.fromEntries(Object.entries(payload).sort()),
3206
- null,
3207
- void 0
3180
+ return new TextEncoder().encode(
3181
+ JSON.stringify(Object.fromEntries(Object.entries(payload).sort()))
3208
3182
  );
3209
- return new TextEncoder().encode(sorted);
3210
3183
  }
3211
- async function addPQSignature(msg, keypair) {
3184
+ async function signMessage(msg, keypair) {
3212
3185
  const payload = canonicalMessageBytes(msg);
3213
3186
  const rawSig = await keypair.signBytes(payload);
3214
- const block = {
3187
+ msg["signature"] = {
3215
3188
  alg: "ml-dsa-65",
3216
3189
  kid: keypair.keyId,
3217
3190
  sig: toBase64url(rawSig)
3218
3191
  };
3219
- msg["pqSig"] = block;
3220
3192
  return msg;
3221
3193
  }
3222
- async function verifyPQSignature(msg, trustedKeys, requirePQ = false) {
3223
- const pqSig = msg["pqSig"];
3224
- if (!pqSig) {
3225
- if (requirePQ) {
3226
- throw new Error("ML-DSA signature (pqSig) required but missing from message");
3227
- }
3228
- return;
3229
- }
3230
- if (pqSig.alg !== "ml-dsa-65") {
3231
- throw new Error(`Unsupported PQ signature algorithm: ${pqSig.alg}`);
3194
+ async function verifyMessage(msg, trustedKeys) {
3195
+ const sig = msg.signature;
3196
+ if (!sig) throw new Error("Message is unsigned \u2014 signature field missing");
3197
+ if (sig.alg !== "ml-dsa-65") {
3198
+ throw new Error(
3199
+ `Unsupported signature algorithm: ${sig.alg}. RCAN v2.2 requires ml-dsa-65 (Ed25519 is deprecated).`
3200
+ );
3232
3201
  }
3233
- const matched = trustedKeys.find((k) => k.keyId === pqSig.kid);
3202
+ const matched = trustedKeys.find((k) => k.keyId === sig.kid);
3234
3203
  if (!matched) {
3235
3204
  throw new Error(
3236
- `No trusted ML-DSA key with kid=${pqSig.kid}. Known kids: [${trustedKeys.map((k) => k.keyId).join(", ")}]`
3205
+ `No trusted ML-DSA-65 key with kid=${sig.kid}. Known kids: [${trustedKeys.map((k) => k.keyId).join(", ")}]`
3237
3206
  );
3238
3207
  }
3239
3208
  let rawSig;
3240
3209
  try {
3241
- rawSig = fromBase64url(pqSig.sig);
3210
+ rawSig = fromBase64url(sig.sig);
3242
3211
  } catch (e) {
3243
- throw new Error(`Invalid base64url ML-DSA signature: ${e}`);
3212
+ throw new Error(`Invalid base64url sig: ${e}`);
3244
3213
  }
3245
- const payload = canonicalMessageBytes(msg);
3246
- await matched.verifyBytes(payload, rawSig);
3214
+ await matched.verifyBytes(canonicalMessageBytes(msg), rawSig);
3215
+ }
3216
+ var addPQSignature = signMessage;
3217
+ async function verifyPQSignature(msg, trustedKeys, _requirePQ = true) {
3218
+ return verifyMessage(msg, trustedKeys);
3247
3219
  }
3248
3220
 
3249
3221
  // src/index.ts
@@ -3371,6 +3343,7 @@ export {
3371
3343
  parseM2mTrustedToken,
3372
3344
  roleFromJwtLevel,
3373
3345
  selectTransport,
3346
+ signMessage,
3374
3347
  validateAuthorityAccess,
3375
3348
  validateCompetitionScope,
3376
3349
  validateConfig,
@@ -3393,6 +3366,7 @@ export {
3393
3366
  validateVersionCompat,
3394
3367
  verifyM2mTrustedToken,
3395
3368
  verifyM2mTrustedTokenClaims,
3369
+ verifyMessage,
3396
3370
  verifyPQSignature
3397
3371
  };
3398
3372
  //# sourceMappingURL=index.mjs.map