@continuonai/rcan-ts 1.1.0 → 1.2.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/browser.d.mts +90 -3
- package/dist/browser.mjs +169 -4
- package/dist/browser.mjs.map +1 -1
- package/dist/index.d.mts +90 -3
- package/dist/index.d.ts +90 -3
- package/dist/index.js +173 -5
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +169 -4
- package/dist/index.mjs.map +1 -1
- package/dist/rcan-validate.js +7 -2
- package/dist/rcan.iife.js +16 -3
- package/package.json +28 -5
package/dist/index.d.mts
CHANGED
|
@@ -114,6 +114,12 @@ interface SignatureBlock {
|
|
|
114
114
|
kid: string;
|
|
115
115
|
sig: string;
|
|
116
116
|
}
|
|
117
|
+
/** v2.2: Post-quantum (ML-DSA-65) signature block */
|
|
118
|
+
interface PQSignatureBlock {
|
|
119
|
+
alg: "ml-dsa-65";
|
|
120
|
+
kid: string;
|
|
121
|
+
sig: string;
|
|
122
|
+
}
|
|
117
123
|
interface RCANMessageData {
|
|
118
124
|
rcan?: string;
|
|
119
125
|
/** v1.5: explicit protocol version field (defaults to SPEC_VERSION) */
|
|
@@ -152,6 +158,8 @@ interface RCANMessageData {
|
|
|
152
158
|
firmwareHash?: string;
|
|
153
159
|
/** v2.1: URI to sender's SBOM attestation endpoint (envelope field 14). Required at L2+. */
|
|
154
160
|
attestationRef?: string;
|
|
161
|
+
/** v2.2: ML-DSA-65 post-quantum signature block (field 16, FIPS 204). Hybrid mode alongside Ed25519. */
|
|
162
|
+
pqSig?: PQSignatureBlock | undefined;
|
|
155
163
|
[key: string]: unknown;
|
|
156
164
|
}
|
|
157
165
|
declare class RCANMessageError extends Error {
|
|
@@ -188,6 +196,8 @@ declare class RCANMessage {
|
|
|
188
196
|
readonly firmwareHash: string | undefined;
|
|
189
197
|
/** v2.1: URI to sender's SBOM attestation endpoint */
|
|
190
198
|
readonly attestationRef: string | undefined;
|
|
199
|
+
/** v2.2: ML-DSA-65 post-quantum signature (field 16, FIPS 204). Hybrid alongside Ed25519. */
|
|
200
|
+
readonly pqSig: PQSignatureBlock | undefined;
|
|
191
201
|
constructor(data: RCANMessageData);
|
|
192
202
|
/** Whether this message has a signature block */
|
|
193
203
|
get isSigned(): boolean;
|
|
@@ -755,9 +765,9 @@ declare function makeTransparencyMessage(ruri: string, disclosure: string, deleg
|
|
|
755
765
|
* §3.5 — Protocol Version Compatibility
|
|
756
766
|
*/
|
|
757
767
|
/** The RCAN spec version this SDK implements. */
|
|
758
|
-
declare const SPEC_VERSION = "2.
|
|
768
|
+
declare const SPEC_VERSION = "2.2.0";
|
|
759
769
|
/** The SDK release version. */
|
|
760
|
-
declare const SDK_VERSION = "1.
|
|
770
|
+
declare const SDK_VERSION = "1.2.0";
|
|
761
771
|
/**
|
|
762
772
|
* Validate version compatibility.
|
|
763
773
|
*
|
|
@@ -1852,6 +1862,83 @@ declare function verifyM2mTrustedToken(token: string, targetRrn: string, options
|
|
|
1852
1862
|
skipRevocationCheck?: boolean;
|
|
1853
1863
|
}): Promise<M2MTrustedClaims>;
|
|
1854
1864
|
|
|
1865
|
+
/**
|
|
1866
|
+
* RCAN v2.2 Post-Quantum Hybrid Signing — ML-DSA-65 (NIST FIPS 204)
|
|
1867
|
+
*
|
|
1868
|
+
* Provides MLDSAKeyPair for post-quantum signing alongside the existing
|
|
1869
|
+
* Ed25519 SignatureBlock. In hybrid mode a message carries both:
|
|
1870
|
+
* - `signature` — Ed25519 SignatureBlock (backward-compat with v2.1)
|
|
1871
|
+
* - `pqSig` — MLDSASignatureBlock (new in v2.2)
|
|
1872
|
+
*
|
|
1873
|
+
* Key sizes (ML-DSA-65, NIST security level 3):
|
|
1874
|
+
* Public key: 1952 bytes
|
|
1875
|
+
* Private key: 4032 bytes
|
|
1876
|
+
* Signature: 3309 bytes
|
|
1877
|
+
*
|
|
1878
|
+
* Requires: @noble/post-quantum (npm install @noble/post-quantum)
|
|
1879
|
+
*
|
|
1880
|
+
* Spec: https://rcan.dev/spec#section-7-2
|
|
1881
|
+
*/
|
|
1882
|
+
|
|
1883
|
+
/** @deprecated use PQSignatureBlock */
|
|
1884
|
+
type MLDSASignatureBlock = PQSignatureBlock;
|
|
1885
|
+
interface MLDSAKeyPairData {
|
|
1886
|
+
/** Public key bytes (1952 bytes) */
|
|
1887
|
+
publicKey: Uint8Array;
|
|
1888
|
+
/** Private key bytes (4032 bytes). Absent for verify-only key pairs. */
|
|
1889
|
+
secretKey?: Uint8Array;
|
|
1890
|
+
/** 8-char hex key ID */
|
|
1891
|
+
keyId: string;
|
|
1892
|
+
}
|
|
1893
|
+
/**
|
|
1894
|
+
* An ML-DSA-65 (CRYSTALS-Dilithium, NIST FIPS 204) key pair.
|
|
1895
|
+
*
|
|
1896
|
+
* Immutable value object. Build via {@link MLDSAKeyPair.generate} or
|
|
1897
|
+
* {@link MLDSAKeyPair.fromPublicKey}.
|
|
1898
|
+
*/
|
|
1899
|
+
declare class MLDSAKeyPair {
|
|
1900
|
+
readonly keyId: string;
|
|
1901
|
+
readonly publicKey: Uint8Array;
|
|
1902
|
+
readonly secretKey: Uint8Array | undefined;
|
|
1903
|
+
private constructor();
|
|
1904
|
+
/** Generate a new ML-DSA-65 key pair. */
|
|
1905
|
+
static generate(): Promise<MLDSAKeyPair>;
|
|
1906
|
+
/** Build a verify-only key pair from raw public key bytes. */
|
|
1907
|
+
static fromPublicKey(publicKey: Uint8Array): Promise<MLDSAKeyPair>;
|
|
1908
|
+
/** Build a full key pair from saved bytes (public + secret). */
|
|
1909
|
+
static fromKeyMaterial(publicKey: Uint8Array, secretKey: Uint8Array): Promise<MLDSAKeyPair>;
|
|
1910
|
+
get hasPrivateKey(): boolean;
|
|
1911
|
+
/** Sign raw bytes; returns ML-DSA-65 signature (3309 bytes). */
|
|
1912
|
+
signBytes(data: Uint8Array): Promise<Uint8Array>;
|
|
1913
|
+
/**
|
|
1914
|
+
* Verify an ML-DSA-65 signature.
|
|
1915
|
+
* @returns true if valid
|
|
1916
|
+
* @throws {Error} on invalid signature
|
|
1917
|
+
*/
|
|
1918
|
+
verifyBytes(data: Uint8Array, signature: Uint8Array): Promise<void>;
|
|
1919
|
+
toString(): string;
|
|
1920
|
+
}
|
|
1921
|
+
/**
|
|
1922
|
+
* Add an ML-DSA-65 signature (`pqSig`) to an RCAN message.
|
|
1923
|
+
*
|
|
1924
|
+
* This is the v2.2 hybrid complement to the existing Ed25519 signature.
|
|
1925
|
+
* Call {@link signMessageEd25519} (or the existing signing path) first to set
|
|
1926
|
+
* `signature`, then call this to append `pqSig`.
|
|
1927
|
+
*
|
|
1928
|
+
* @param msg RCAN message (mutated in place — sets `pqSig`)
|
|
1929
|
+
* @param keypair ML-DSA-65 key pair with private key
|
|
1930
|
+
* @returns The same message cast to include `pqSig`
|
|
1931
|
+
*/
|
|
1932
|
+
declare function addPQSignature(msg: RCANMessage, keypair: MLDSAKeyPair): Promise<RCANMessage>;
|
|
1933
|
+
/**
|
|
1934
|
+
* Verify the ML-DSA-65 signature (`pqSig`) on an RCAN message.
|
|
1935
|
+
*
|
|
1936
|
+
* @param msg Message with a `pqSig` field
|
|
1937
|
+
* @param trustedKeys Trusted ML-DSA public key pairs
|
|
1938
|
+
* @param requirePQ If true, raise when `pqSig` is absent (for post-2028 hard mode)
|
|
1939
|
+
*/
|
|
1940
|
+
declare function verifyPQSignature(msg: RCANMessage, trustedKeys: MLDSAKeyPair[], requirePQ?: boolean): Promise<void>;
|
|
1941
|
+
|
|
1855
1942
|
/**
|
|
1856
1943
|
* rcan-ts — Official TypeScript SDK for RCAN v1.6
|
|
1857
1944
|
* Robot Communication and Accountability Network
|
|
@@ -1864,4 +1951,4 @@ declare const VERSION = "0.6.0";
|
|
|
1864
1951
|
/** @deprecated Use SPEC_VERSION from ./version instead */
|
|
1865
1952
|
declare const RCAN_VERSION = "1.6";
|
|
1866
1953
|
|
|
1867
|
-
export { AUTHORITY_ERROR_CODES, type ApprovalStatus, AuditChain, AuditError, type AuditExportRequest, type AuthorityAccessPayload, type AuthorityAccessPayloadWire, type AuthorityDataCategory, type AuthorityResponseData, type AuthorityResponsePayload, COMPETITION_SCOPE_LEVEL, CONTRIBUTE_SCOPE_LEVEL, type CachedKey, type ChainVerifyResult, ClockDriftError, type ClockSyncStatus, CommitmentRecord, type CommitmentRecordData, type CommitmentRecordJSON, type CompetitionBadge, type CompetitionEnter, type CompetitionFormat, type CompetitionScore, type ComputeResource, ConfidenceGate, type ConsentRequestParams, type ConsentResponseParams, type ConsentType, type ContributeCancel, type ContributeRequest, type ContributeResult, DEFAULT_LOA_POLICY, DataCategory, type DelegationHop, FIRMWARE_MANIFEST_PATH, FaultCode, type FaultReportParams, type FaultSeverity, type FederationSyncPayload, FederationSyncType, type FirmwareComponent, FirmwareIntegrityError, type FirmwareManifest, type FirmwareManifestWire, GateError, HiTLGate, type IdentityRecord, type JWKEntry, type JWKSDocument, KeyStore, LevelOfAssurance, type ListResult, type LoaPolicy, M2MAuthError, type M2MPeerClaims, type M2MTrustedClaims, M2M_TRUSTED_ISSUER, type MediaChunk, MediaEncoding, MessageType, NodeClient, type OfflineCommandResult, OfflineModeManager, type OfflineState, PRODUCTION_LOA_POLICY, type PendingApproval, type PersonalResearchResult, QoSAckTimeoutError, QoSLevel, QoSManager, type QoSResult, type QoSSendOptions, RCANAddressError, type RCANAgentConfig, type RCANConfig, RCANConfigAuthorizationError, RCANDelegationChainError, RCANError, RCANGateError, RCANMessage, type RCANMessageData, type RCANMessageEnvelope, RCANMessageError, type RCANMetadata, RCANNodeError, RCANNodeNotFoundError, RCANNodeSyncError, RCANNodeTrustError, RCANRegistryError, type RCANRegistryNode, RCANReplayAttackError, type RCANResolveResult, RCANSignatureError, RCANValidationError, RCANVersionIncompatibleError, RCAN_VERSION, ROLE_JWT_LEVEL, RRF_REVOCATION_CACHE_TTL_MS, RRF_REVOCATION_URL, type RegistrationResult, RegistryClient, type RegistryIdentity, RegistryTier, ReplayCache, type ReplayCheckResult, type ReplayableMessage, type ResearchMetrics, RevocationCache$1 as RevocationCache, type RevocationStatus, type RevocationStatusValue, type Robot, type RobotRegistration, RobotURI, RobotURIError, type RobotURIOptions, Role, type RunType, SAFETY_MESSAGE_TYPE, SCOPE_MIN_ROLE, SDK_VERSION, SPEC_VERSION, type SafetyEvent, type SafetyMessage, type ScopeValidationResult, type SeasonStanding, type SenderType, type SignatureBlock, type StandingEntry, type StreamChunk, type TrainingConsentRequestParams, type TransparencyMessage, TransportEncoding, TransportError, TrustAnchorCache, VERSION, type ValidationResult, type WorkUnitStatus, addDelegationHop, addMediaInline, addMediaRef, assertClockSynced, authorityAccessFromWire, authorityAccessToWire, canonicalManifestJson, checkClockSync, checkRevocation, decodeBleFrames, decodeCompact, decodeMinimal, encodeBleFrames, encodeCompact, encodeMinimal, extractIdentityFromJwt, extractLoaFromJwt, extractRoleFromJwt, fetchCanonicalSchema, fetchRRFRevocations, isAuthorityRequestValid, isM2mTrustedRevoked, isPreemptedBy, isSafetyMessage, makeCloudRelayMessage, makeCompetitionEnter, makeCompetitionScore, makeConfigUpdate, makeConsentDeny, makeConsentGrant, makeConsentRequest, makeContributeCancel, makeContributeRequest, makeContributeResult, makeEstopMessage, makeEstopWithQoS, makeFaultReport, makeFederationSync, makeKeyRotationMessage, makePersonalResearchResult, makeResumeMessage, makeRevocationBroadcast, makeSeasonStanding, makeStopMessage, makeStreamChunk, makeTrainingConsentDeny, makeTrainingConsentGrant, makeTrainingConsentRequest, makeTrainingDataMessage, makeTransparencyMessage, manifestFromWire, manifestToWire, parseM2mPeerToken, parseM2mTrustedToken, roleFromJwtLevel, selectTransport, validateAuthorityAccess, validateCompetitionScope, validateConfig, validateConfigAgainstSchema, validateConfigUpdate, validateConsentMessage, validateContributeScope, validateCrossRegistryCommand, validateDelegationChain, validateLoaForScope, validateManifest, validateMediaChunks, validateMessage, validateNodeAgainstSchema, validateReplay, validateRoleForScope, validateSafetyMessage, validateTrainingDataMessage, validateURI, validateVersionCompat, verifyM2mTrustedToken, verifyM2mTrustedTokenClaims };
|
|
1954
|
+
export { AUTHORITY_ERROR_CODES, type ApprovalStatus, AuditChain, AuditError, type AuditExportRequest, type AuthorityAccessPayload, type AuthorityAccessPayloadWire, type AuthorityDataCategory, type AuthorityResponseData, type AuthorityResponsePayload, COMPETITION_SCOPE_LEVEL, CONTRIBUTE_SCOPE_LEVEL, type CachedKey, type ChainVerifyResult, ClockDriftError, type ClockSyncStatus, CommitmentRecord, type CommitmentRecordData, type CommitmentRecordJSON, type CompetitionBadge, type CompetitionEnter, type CompetitionFormat, type CompetitionScore, type ComputeResource, ConfidenceGate, type ConsentRequestParams, type ConsentResponseParams, type ConsentType, type ContributeCancel, type ContributeRequest, type ContributeResult, DEFAULT_LOA_POLICY, DataCategory, type DelegationHop, FIRMWARE_MANIFEST_PATH, FaultCode, type FaultReportParams, type FaultSeverity, type FederationSyncPayload, FederationSyncType, type FirmwareComponent, FirmwareIntegrityError, type FirmwareManifest, type FirmwareManifestWire, GateError, HiTLGate, type IdentityRecord, type JWKEntry, type JWKSDocument, KeyStore, LevelOfAssurance, type ListResult, type LoaPolicy, M2MAuthError, type M2MPeerClaims, type M2MTrustedClaims, M2M_TRUSTED_ISSUER, MLDSAKeyPair, type MLDSAKeyPairData, type MLDSASignatureBlock, type MediaChunk, MediaEncoding, MessageType, NodeClient, type OfflineCommandResult, OfflineModeManager, type OfflineState, PRODUCTION_LOA_POLICY, type PendingApproval, type PersonalResearchResult, QoSAckTimeoutError, QoSLevel, QoSManager, type QoSResult, type QoSSendOptions, RCANAddressError, type RCANAgentConfig, type RCANConfig, RCANConfigAuthorizationError, RCANDelegationChainError, RCANError, RCANGateError, RCANMessage, type RCANMessageData, type RCANMessageEnvelope, RCANMessageError, type RCANMetadata, RCANNodeError, RCANNodeNotFoundError, RCANNodeSyncError, RCANNodeTrustError, RCANRegistryError, type RCANRegistryNode, RCANReplayAttackError, type RCANResolveResult, RCANSignatureError, RCANValidationError, RCANVersionIncompatibleError, RCAN_VERSION, ROLE_JWT_LEVEL, RRF_REVOCATION_CACHE_TTL_MS, RRF_REVOCATION_URL, type RegistrationResult, RegistryClient, type RegistryIdentity, RegistryTier, ReplayCache, type ReplayCheckResult, type ReplayableMessage, type ResearchMetrics, RevocationCache$1 as RevocationCache, type RevocationStatus, type RevocationStatusValue, type Robot, type RobotRegistration, RobotURI, RobotURIError, type RobotURIOptions, Role, type RunType, SAFETY_MESSAGE_TYPE, SCOPE_MIN_ROLE, SDK_VERSION, SPEC_VERSION, type SafetyEvent, type SafetyMessage, type ScopeValidationResult, type SeasonStanding, type SenderType, type SignatureBlock, type StandingEntry, type StreamChunk, type TrainingConsentRequestParams, type TransparencyMessage, TransportEncoding, TransportError, TrustAnchorCache, VERSION, type ValidationResult, type WorkUnitStatus, addDelegationHop, addMediaInline, addMediaRef, addPQSignature, assertClockSynced, authorityAccessFromWire, authorityAccessToWire, canonicalManifestJson, checkClockSync, checkRevocation, decodeBleFrames, decodeCompact, decodeMinimal, encodeBleFrames, encodeCompact, encodeMinimal, extractIdentityFromJwt, extractLoaFromJwt, extractRoleFromJwt, fetchCanonicalSchema, fetchRRFRevocations, isAuthorityRequestValid, isM2mTrustedRevoked, isPreemptedBy, isSafetyMessage, makeCloudRelayMessage, makeCompetitionEnter, makeCompetitionScore, makeConfigUpdate, makeConsentDeny, makeConsentGrant, makeConsentRequest, makeContributeCancel, makeContributeRequest, makeContributeResult, makeEstopMessage, makeEstopWithQoS, makeFaultReport, makeFederationSync, makeKeyRotationMessage, makePersonalResearchResult, makeResumeMessage, makeRevocationBroadcast, makeSeasonStanding, makeStopMessage, makeStreamChunk, makeTrainingConsentDeny, makeTrainingConsentGrant, makeTrainingConsentRequest, makeTrainingDataMessage, makeTransparencyMessage, manifestFromWire, manifestToWire, parseM2mPeerToken, parseM2mTrustedToken, roleFromJwtLevel, selectTransport, validateAuthorityAccess, validateCompetitionScope, validateConfig, validateConfigAgainstSchema, validateConfigUpdate, validateConsentMessage, validateContributeScope, validateCrossRegistryCommand, validateDelegationChain, validateLoaForScope, validateManifest, validateMediaChunks, validateMessage, validateNodeAgainstSchema, validateReplay, validateRoleForScope, validateSafetyMessage, validateTrainingDataMessage, validateURI, validateVersionCompat, verifyM2mTrustedToken, verifyM2mTrustedTokenClaims, verifyPQSignature };
|
package/dist/index.d.ts
CHANGED
|
@@ -114,6 +114,12 @@ interface SignatureBlock {
|
|
|
114
114
|
kid: string;
|
|
115
115
|
sig: string;
|
|
116
116
|
}
|
|
117
|
+
/** v2.2: Post-quantum (ML-DSA-65) signature block */
|
|
118
|
+
interface PQSignatureBlock {
|
|
119
|
+
alg: "ml-dsa-65";
|
|
120
|
+
kid: string;
|
|
121
|
+
sig: string;
|
|
122
|
+
}
|
|
117
123
|
interface RCANMessageData {
|
|
118
124
|
rcan?: string;
|
|
119
125
|
/** v1.5: explicit protocol version field (defaults to SPEC_VERSION) */
|
|
@@ -152,6 +158,8 @@ interface RCANMessageData {
|
|
|
152
158
|
firmwareHash?: string;
|
|
153
159
|
/** v2.1: URI to sender's SBOM attestation endpoint (envelope field 14). Required at L2+. */
|
|
154
160
|
attestationRef?: string;
|
|
161
|
+
/** v2.2: ML-DSA-65 post-quantum signature block (field 16, FIPS 204). Hybrid mode alongside Ed25519. */
|
|
162
|
+
pqSig?: PQSignatureBlock | undefined;
|
|
155
163
|
[key: string]: unknown;
|
|
156
164
|
}
|
|
157
165
|
declare class RCANMessageError extends Error {
|
|
@@ -188,6 +196,8 @@ declare class RCANMessage {
|
|
|
188
196
|
readonly firmwareHash: string | undefined;
|
|
189
197
|
/** v2.1: URI to sender's SBOM attestation endpoint */
|
|
190
198
|
readonly attestationRef: string | undefined;
|
|
199
|
+
/** v2.2: ML-DSA-65 post-quantum signature (field 16, FIPS 204). Hybrid alongside Ed25519. */
|
|
200
|
+
readonly pqSig: PQSignatureBlock | undefined;
|
|
191
201
|
constructor(data: RCANMessageData);
|
|
192
202
|
/** Whether this message has a signature block */
|
|
193
203
|
get isSigned(): boolean;
|
|
@@ -755,9 +765,9 @@ declare function makeTransparencyMessage(ruri: string, disclosure: string, deleg
|
|
|
755
765
|
* §3.5 — Protocol Version Compatibility
|
|
756
766
|
*/
|
|
757
767
|
/** The RCAN spec version this SDK implements. */
|
|
758
|
-
declare const SPEC_VERSION = "2.
|
|
768
|
+
declare const SPEC_VERSION = "2.2.0";
|
|
759
769
|
/** The SDK release version. */
|
|
760
|
-
declare const SDK_VERSION = "1.
|
|
770
|
+
declare const SDK_VERSION = "1.2.0";
|
|
761
771
|
/**
|
|
762
772
|
* Validate version compatibility.
|
|
763
773
|
*
|
|
@@ -1852,6 +1862,83 @@ declare function verifyM2mTrustedToken(token: string, targetRrn: string, options
|
|
|
1852
1862
|
skipRevocationCheck?: boolean;
|
|
1853
1863
|
}): Promise<M2MTrustedClaims>;
|
|
1854
1864
|
|
|
1865
|
+
/**
|
|
1866
|
+
* RCAN v2.2 Post-Quantum Hybrid Signing — ML-DSA-65 (NIST FIPS 204)
|
|
1867
|
+
*
|
|
1868
|
+
* Provides MLDSAKeyPair for post-quantum signing alongside the existing
|
|
1869
|
+
* Ed25519 SignatureBlock. In hybrid mode a message carries both:
|
|
1870
|
+
* - `signature` — Ed25519 SignatureBlock (backward-compat with v2.1)
|
|
1871
|
+
* - `pqSig` — MLDSASignatureBlock (new in v2.2)
|
|
1872
|
+
*
|
|
1873
|
+
* Key sizes (ML-DSA-65, NIST security level 3):
|
|
1874
|
+
* Public key: 1952 bytes
|
|
1875
|
+
* Private key: 4032 bytes
|
|
1876
|
+
* Signature: 3309 bytes
|
|
1877
|
+
*
|
|
1878
|
+
* Requires: @noble/post-quantum (npm install @noble/post-quantum)
|
|
1879
|
+
*
|
|
1880
|
+
* Spec: https://rcan.dev/spec#section-7-2
|
|
1881
|
+
*/
|
|
1882
|
+
|
|
1883
|
+
/** @deprecated use PQSignatureBlock */
|
|
1884
|
+
type MLDSASignatureBlock = PQSignatureBlock;
|
|
1885
|
+
interface MLDSAKeyPairData {
|
|
1886
|
+
/** Public key bytes (1952 bytes) */
|
|
1887
|
+
publicKey: Uint8Array;
|
|
1888
|
+
/** Private key bytes (4032 bytes). Absent for verify-only key pairs. */
|
|
1889
|
+
secretKey?: Uint8Array;
|
|
1890
|
+
/** 8-char hex key ID */
|
|
1891
|
+
keyId: string;
|
|
1892
|
+
}
|
|
1893
|
+
/**
|
|
1894
|
+
* An ML-DSA-65 (CRYSTALS-Dilithium, NIST FIPS 204) key pair.
|
|
1895
|
+
*
|
|
1896
|
+
* Immutable value object. Build via {@link MLDSAKeyPair.generate} or
|
|
1897
|
+
* {@link MLDSAKeyPair.fromPublicKey}.
|
|
1898
|
+
*/
|
|
1899
|
+
declare class MLDSAKeyPair {
|
|
1900
|
+
readonly keyId: string;
|
|
1901
|
+
readonly publicKey: Uint8Array;
|
|
1902
|
+
readonly secretKey: Uint8Array | undefined;
|
|
1903
|
+
private constructor();
|
|
1904
|
+
/** Generate a new ML-DSA-65 key pair. */
|
|
1905
|
+
static generate(): Promise<MLDSAKeyPair>;
|
|
1906
|
+
/** Build a verify-only key pair from raw public key bytes. */
|
|
1907
|
+
static fromPublicKey(publicKey: Uint8Array): Promise<MLDSAKeyPair>;
|
|
1908
|
+
/** Build a full key pair from saved bytes (public + secret). */
|
|
1909
|
+
static fromKeyMaterial(publicKey: Uint8Array, secretKey: Uint8Array): Promise<MLDSAKeyPair>;
|
|
1910
|
+
get hasPrivateKey(): boolean;
|
|
1911
|
+
/** Sign raw bytes; returns ML-DSA-65 signature (3309 bytes). */
|
|
1912
|
+
signBytes(data: Uint8Array): Promise<Uint8Array>;
|
|
1913
|
+
/**
|
|
1914
|
+
* Verify an ML-DSA-65 signature.
|
|
1915
|
+
* @returns true if valid
|
|
1916
|
+
* @throws {Error} on invalid signature
|
|
1917
|
+
*/
|
|
1918
|
+
verifyBytes(data: Uint8Array, signature: Uint8Array): Promise<void>;
|
|
1919
|
+
toString(): string;
|
|
1920
|
+
}
|
|
1921
|
+
/**
|
|
1922
|
+
* Add an ML-DSA-65 signature (`pqSig`) to an RCAN message.
|
|
1923
|
+
*
|
|
1924
|
+
* This is the v2.2 hybrid complement to the existing Ed25519 signature.
|
|
1925
|
+
* Call {@link signMessageEd25519} (or the existing signing path) first to set
|
|
1926
|
+
* `signature`, then call this to append `pqSig`.
|
|
1927
|
+
*
|
|
1928
|
+
* @param msg RCAN message (mutated in place — sets `pqSig`)
|
|
1929
|
+
* @param keypair ML-DSA-65 key pair with private key
|
|
1930
|
+
* @returns The same message cast to include `pqSig`
|
|
1931
|
+
*/
|
|
1932
|
+
declare function addPQSignature(msg: RCANMessage, keypair: MLDSAKeyPair): Promise<RCANMessage>;
|
|
1933
|
+
/**
|
|
1934
|
+
* Verify the ML-DSA-65 signature (`pqSig`) on an RCAN message.
|
|
1935
|
+
*
|
|
1936
|
+
* @param msg Message with a `pqSig` field
|
|
1937
|
+
* @param trustedKeys Trusted ML-DSA public key pairs
|
|
1938
|
+
* @param requirePQ If true, raise when `pqSig` is absent (for post-2028 hard mode)
|
|
1939
|
+
*/
|
|
1940
|
+
declare function verifyPQSignature(msg: RCANMessage, trustedKeys: MLDSAKeyPair[], requirePQ?: boolean): Promise<void>;
|
|
1941
|
+
|
|
1855
1942
|
/**
|
|
1856
1943
|
* rcan-ts — Official TypeScript SDK for RCAN v1.6
|
|
1857
1944
|
* Robot Communication and Accountability Network
|
|
@@ -1864,4 +1951,4 @@ declare const VERSION = "0.6.0";
|
|
|
1864
1951
|
/** @deprecated Use SPEC_VERSION from ./version instead */
|
|
1865
1952
|
declare const RCAN_VERSION = "1.6";
|
|
1866
1953
|
|
|
1867
|
-
export { AUTHORITY_ERROR_CODES, type ApprovalStatus, AuditChain, AuditError, type AuditExportRequest, type AuthorityAccessPayload, type AuthorityAccessPayloadWire, type AuthorityDataCategory, type AuthorityResponseData, type AuthorityResponsePayload, COMPETITION_SCOPE_LEVEL, CONTRIBUTE_SCOPE_LEVEL, type CachedKey, type ChainVerifyResult, ClockDriftError, type ClockSyncStatus, CommitmentRecord, type CommitmentRecordData, type CommitmentRecordJSON, type CompetitionBadge, type CompetitionEnter, type CompetitionFormat, type CompetitionScore, type ComputeResource, ConfidenceGate, type ConsentRequestParams, type ConsentResponseParams, type ConsentType, type ContributeCancel, type ContributeRequest, type ContributeResult, DEFAULT_LOA_POLICY, DataCategory, type DelegationHop, FIRMWARE_MANIFEST_PATH, FaultCode, type FaultReportParams, type FaultSeverity, type FederationSyncPayload, FederationSyncType, type FirmwareComponent, FirmwareIntegrityError, type FirmwareManifest, type FirmwareManifestWire, GateError, HiTLGate, type IdentityRecord, type JWKEntry, type JWKSDocument, KeyStore, LevelOfAssurance, type ListResult, type LoaPolicy, M2MAuthError, type M2MPeerClaims, type M2MTrustedClaims, M2M_TRUSTED_ISSUER, type MediaChunk, MediaEncoding, MessageType, NodeClient, type OfflineCommandResult, OfflineModeManager, type OfflineState, PRODUCTION_LOA_POLICY, type PendingApproval, type PersonalResearchResult, QoSAckTimeoutError, QoSLevel, QoSManager, type QoSResult, type QoSSendOptions, RCANAddressError, type RCANAgentConfig, type RCANConfig, RCANConfigAuthorizationError, RCANDelegationChainError, RCANError, RCANGateError, RCANMessage, type RCANMessageData, type RCANMessageEnvelope, RCANMessageError, type RCANMetadata, RCANNodeError, RCANNodeNotFoundError, RCANNodeSyncError, RCANNodeTrustError, RCANRegistryError, type RCANRegistryNode, RCANReplayAttackError, type RCANResolveResult, RCANSignatureError, RCANValidationError, RCANVersionIncompatibleError, RCAN_VERSION, ROLE_JWT_LEVEL, RRF_REVOCATION_CACHE_TTL_MS, RRF_REVOCATION_URL, type RegistrationResult, RegistryClient, type RegistryIdentity, RegistryTier, ReplayCache, type ReplayCheckResult, type ReplayableMessage, type ResearchMetrics, RevocationCache$1 as RevocationCache, type RevocationStatus, type RevocationStatusValue, type Robot, type RobotRegistration, RobotURI, RobotURIError, type RobotURIOptions, Role, type RunType, SAFETY_MESSAGE_TYPE, SCOPE_MIN_ROLE, SDK_VERSION, SPEC_VERSION, type SafetyEvent, type SafetyMessage, type ScopeValidationResult, type SeasonStanding, type SenderType, type SignatureBlock, type StandingEntry, type StreamChunk, type TrainingConsentRequestParams, type TransparencyMessage, TransportEncoding, TransportError, TrustAnchorCache, VERSION, type ValidationResult, type WorkUnitStatus, addDelegationHop, addMediaInline, addMediaRef, assertClockSynced, authorityAccessFromWire, authorityAccessToWire, canonicalManifestJson, checkClockSync, checkRevocation, decodeBleFrames, decodeCompact, decodeMinimal, encodeBleFrames, encodeCompact, encodeMinimal, extractIdentityFromJwt, extractLoaFromJwt, extractRoleFromJwt, fetchCanonicalSchema, fetchRRFRevocations, isAuthorityRequestValid, isM2mTrustedRevoked, isPreemptedBy, isSafetyMessage, makeCloudRelayMessage, makeCompetitionEnter, makeCompetitionScore, makeConfigUpdate, makeConsentDeny, makeConsentGrant, makeConsentRequest, makeContributeCancel, makeContributeRequest, makeContributeResult, makeEstopMessage, makeEstopWithQoS, makeFaultReport, makeFederationSync, makeKeyRotationMessage, makePersonalResearchResult, makeResumeMessage, makeRevocationBroadcast, makeSeasonStanding, makeStopMessage, makeStreamChunk, makeTrainingConsentDeny, makeTrainingConsentGrant, makeTrainingConsentRequest, makeTrainingDataMessage, makeTransparencyMessage, manifestFromWire, manifestToWire, parseM2mPeerToken, parseM2mTrustedToken, roleFromJwtLevel, selectTransport, validateAuthorityAccess, validateCompetitionScope, validateConfig, validateConfigAgainstSchema, validateConfigUpdate, validateConsentMessage, validateContributeScope, validateCrossRegistryCommand, validateDelegationChain, validateLoaForScope, validateManifest, validateMediaChunks, validateMessage, validateNodeAgainstSchema, validateReplay, validateRoleForScope, validateSafetyMessage, validateTrainingDataMessage, validateURI, validateVersionCompat, verifyM2mTrustedToken, verifyM2mTrustedTokenClaims };
|
|
1954
|
+
export { AUTHORITY_ERROR_CODES, type ApprovalStatus, AuditChain, AuditError, type AuditExportRequest, type AuthorityAccessPayload, type AuthorityAccessPayloadWire, type AuthorityDataCategory, type AuthorityResponseData, type AuthorityResponsePayload, COMPETITION_SCOPE_LEVEL, CONTRIBUTE_SCOPE_LEVEL, type CachedKey, type ChainVerifyResult, ClockDriftError, type ClockSyncStatus, CommitmentRecord, type CommitmentRecordData, type CommitmentRecordJSON, type CompetitionBadge, type CompetitionEnter, type CompetitionFormat, type CompetitionScore, type ComputeResource, ConfidenceGate, type ConsentRequestParams, type ConsentResponseParams, type ConsentType, type ContributeCancel, type ContributeRequest, type ContributeResult, DEFAULT_LOA_POLICY, DataCategory, type DelegationHop, FIRMWARE_MANIFEST_PATH, FaultCode, type FaultReportParams, type FaultSeverity, type FederationSyncPayload, FederationSyncType, type FirmwareComponent, FirmwareIntegrityError, type FirmwareManifest, type FirmwareManifestWire, GateError, HiTLGate, type IdentityRecord, type JWKEntry, type JWKSDocument, KeyStore, LevelOfAssurance, type ListResult, type LoaPolicy, M2MAuthError, type M2MPeerClaims, type M2MTrustedClaims, M2M_TRUSTED_ISSUER, MLDSAKeyPair, type MLDSAKeyPairData, type MLDSASignatureBlock, type MediaChunk, MediaEncoding, MessageType, NodeClient, type OfflineCommandResult, OfflineModeManager, type OfflineState, PRODUCTION_LOA_POLICY, type PendingApproval, type PersonalResearchResult, QoSAckTimeoutError, QoSLevel, QoSManager, type QoSResult, type QoSSendOptions, RCANAddressError, type RCANAgentConfig, type RCANConfig, RCANConfigAuthorizationError, RCANDelegationChainError, RCANError, RCANGateError, RCANMessage, type RCANMessageData, type RCANMessageEnvelope, RCANMessageError, type RCANMetadata, RCANNodeError, RCANNodeNotFoundError, RCANNodeSyncError, RCANNodeTrustError, RCANRegistryError, type RCANRegistryNode, RCANReplayAttackError, type RCANResolveResult, RCANSignatureError, RCANValidationError, RCANVersionIncompatibleError, RCAN_VERSION, ROLE_JWT_LEVEL, RRF_REVOCATION_CACHE_TTL_MS, RRF_REVOCATION_URL, type RegistrationResult, RegistryClient, type RegistryIdentity, RegistryTier, ReplayCache, type ReplayCheckResult, type ReplayableMessage, type ResearchMetrics, RevocationCache$1 as RevocationCache, type RevocationStatus, type RevocationStatusValue, type Robot, type RobotRegistration, RobotURI, RobotURIError, type RobotURIOptions, Role, type RunType, SAFETY_MESSAGE_TYPE, SCOPE_MIN_ROLE, SDK_VERSION, SPEC_VERSION, type SafetyEvent, type SafetyMessage, type ScopeValidationResult, type SeasonStanding, type SenderType, type SignatureBlock, type StandingEntry, type StreamChunk, type TrainingConsentRequestParams, type TransparencyMessage, TransportEncoding, TransportError, TrustAnchorCache, VERSION, type ValidationResult, type WorkUnitStatus, addDelegationHop, addMediaInline, addMediaRef, addPQSignature, assertClockSynced, authorityAccessFromWire, authorityAccessToWire, canonicalManifestJson, checkClockSync, checkRevocation, decodeBleFrames, decodeCompact, decodeMinimal, encodeBleFrames, encodeCompact, encodeMinimal, extractIdentityFromJwt, extractLoaFromJwt, extractRoleFromJwt, fetchCanonicalSchema, fetchRRFRevocations, isAuthorityRequestValid, isM2mTrustedRevoked, isPreemptedBy, isSafetyMessage, makeCloudRelayMessage, makeCompetitionEnter, makeCompetitionScore, makeConfigUpdate, makeConsentDeny, makeConsentGrant, makeConsentRequest, makeContributeCancel, makeContributeRequest, makeContributeResult, makeEstopMessage, makeEstopWithQoS, makeFaultReport, makeFederationSync, makeKeyRotationMessage, makePersonalResearchResult, makeResumeMessage, makeRevocationBroadcast, makeSeasonStanding, makeStopMessage, makeStreamChunk, makeTrainingConsentDeny, makeTrainingConsentGrant, makeTrainingConsentRequest, makeTrainingDataMessage, makeTransparencyMessage, manifestFromWire, manifestToWire, parseM2mPeerToken, parseM2mTrustedToken, roleFromJwtLevel, selectTransport, validateAuthorityAccess, validateCompetitionScope, validateConfig, validateConfigAgainstSchema, validateConfigUpdate, validateConsentMessage, validateContributeScope, validateCrossRegistryCommand, validateDelegationChain, validateLoaForScope, validateManifest, validateMediaChunks, validateMessage, validateNodeAgainstSchema, validateReplay, validateRoleForScope, validateSafetyMessage, validateTrainingDataMessage, validateURI, validateVersionCompat, verifyM2mTrustedToken, verifyM2mTrustedTokenClaims, verifyPQSignature };
|
package/dist/index.js
CHANGED
|
@@ -50,6 +50,7 @@ __export(index_exports, {
|
|
|
50
50
|
LevelOfAssurance: () => LevelOfAssurance,
|
|
51
51
|
M2MAuthError: () => M2MAuthError,
|
|
52
52
|
M2M_TRUSTED_ISSUER: () => M2M_TRUSTED_ISSUER,
|
|
53
|
+
MLDSAKeyPair: () => MLDSAKeyPair,
|
|
53
54
|
MediaEncoding: () => MediaEncoding,
|
|
54
55
|
MessageType: () => MessageType,
|
|
55
56
|
NodeClient: () => NodeClient,
|
|
@@ -96,6 +97,7 @@ __export(index_exports, {
|
|
|
96
97
|
addDelegationHop: () => addDelegationHop,
|
|
97
98
|
addMediaInline: () => addMediaInline,
|
|
98
99
|
addMediaRef: () => addMediaRef,
|
|
100
|
+
addPQSignature: () => addPQSignature,
|
|
99
101
|
assertClockSynced: () => assertClockSynced,
|
|
100
102
|
authorityAccessFromWire: () => authorityAccessFromWire,
|
|
101
103
|
authorityAccessToWire: () => authorityAccessToWire,
|
|
@@ -170,7 +172,8 @@ __export(index_exports, {
|
|
|
170
172
|
validateURI: () => validateURI,
|
|
171
173
|
validateVersionCompat: () => validateVersionCompat,
|
|
172
174
|
verifyM2mTrustedToken: () => verifyM2mTrustedToken,
|
|
173
|
-
verifyM2mTrustedTokenClaims: () => verifyM2mTrustedTokenClaims
|
|
175
|
+
verifyM2mTrustedTokenClaims: () => verifyM2mTrustedTokenClaims,
|
|
176
|
+
verifyPQSignature: () => verifyPQSignature
|
|
174
177
|
});
|
|
175
178
|
module.exports = __toCommonJS(index_exports);
|
|
176
179
|
|
|
@@ -265,8 +268,8 @@ var RobotURI = class _RobotURI {
|
|
|
265
268
|
};
|
|
266
269
|
|
|
267
270
|
// src/version.ts
|
|
268
|
-
var SPEC_VERSION = "2.
|
|
269
|
-
var SDK_VERSION = "1.
|
|
271
|
+
var SPEC_VERSION = "2.2.0";
|
|
272
|
+
var SDK_VERSION = "1.2.0";
|
|
270
273
|
function validateVersionCompat(incomingVersion, localVersion = SPEC_VERSION) {
|
|
271
274
|
const parseParts = (v) => {
|
|
272
275
|
const parts = v.split(".");
|
|
@@ -364,6 +367,8 @@ var RCANMessage = class _RCANMessage {
|
|
|
364
367
|
firmwareHash;
|
|
365
368
|
/** v2.1: URI to sender's SBOM attestation endpoint */
|
|
366
369
|
attestationRef;
|
|
370
|
+
/** v2.2: ML-DSA-65 post-quantum signature (field 16, FIPS 204). Hybrid alongside Ed25519. */
|
|
371
|
+
pqSig;
|
|
367
372
|
constructor(data) {
|
|
368
373
|
if (!data.cmd || data.cmd.trim() === "") {
|
|
369
374
|
throw new RCANMessageError("'cmd' is required");
|
|
@@ -394,6 +399,7 @@ var RCANMessage = class _RCANMessage {
|
|
|
394
399
|
this.mediaChunks = data.mediaChunks;
|
|
395
400
|
this.firmwareHash = data.firmwareHash;
|
|
396
401
|
this.attestationRef = data.attestationRef;
|
|
402
|
+
this.pqSig = data.pqSig;
|
|
397
403
|
if (this.signature !== void 0 && this.signature["sig"] === "pending") {
|
|
398
404
|
throw new RCANMessageError(
|
|
399
405
|
"signature.sig:'pending' is not valid in RCAN v2.1. Sign the message before sending."
|
|
@@ -442,6 +448,7 @@ var RCANMessage = class _RCANMessage {
|
|
|
442
448
|
if (this.mediaChunks !== void 0) obj.mediaChunks = this.mediaChunks;
|
|
443
449
|
if (this.firmwareHash !== void 0) obj.firmwareHash = this.firmwareHash;
|
|
444
450
|
if (this.attestationRef !== void 0) obj.attestationRef = this.attestationRef;
|
|
451
|
+
if (this.pqSig !== void 0) obj.pqSig = this.pqSig;
|
|
445
452
|
return obj;
|
|
446
453
|
}
|
|
447
454
|
/** Serialize to JSON string */
|
|
@@ -486,7 +493,8 @@ var RCANMessage = class _RCANMessage {
|
|
|
486
493
|
transportEncoding: obj.transportEncoding,
|
|
487
494
|
mediaChunks: obj.mediaChunks,
|
|
488
495
|
firmwareHash: obj.firmwareHash,
|
|
489
|
-
attestationRef: obj.attestationRef
|
|
496
|
+
attestationRef: obj.attestationRef,
|
|
497
|
+
pqSig: obj.pqSig
|
|
490
498
|
});
|
|
491
499
|
}
|
|
492
500
|
};
|
|
@@ -3253,6 +3261,163 @@ async function verifyM2mTrustedToken(token, targetRrn, options) {
|
|
|
3253
3261
|
return claims;
|
|
3254
3262
|
}
|
|
3255
3263
|
|
|
3264
|
+
// src/pqSigning.ts
|
|
3265
|
+
function toBase64url(bytes) {
|
|
3266
|
+
let binary = "";
|
|
3267
|
+
for (let i = 0; i < bytes.length; i++) binary += String.fromCharCode(bytes[i]);
|
|
3268
|
+
return btoa(binary).replace(/\+/g, "-").replace(/\//g, "_").replace(/=/g, "");
|
|
3269
|
+
}
|
|
3270
|
+
function fromBase64url(b64) {
|
|
3271
|
+
const padded = b64.replace(/-/g, "+").replace(/_/g, "/");
|
|
3272
|
+
const binary = atob(padded);
|
|
3273
|
+
const bytes = new Uint8Array(binary.length);
|
|
3274
|
+
for (let i = 0; i < binary.length; i++) bytes[i] = binary.charCodeAt(i);
|
|
3275
|
+
return bytes;
|
|
3276
|
+
}
|
|
3277
|
+
async function sha256hex(data) {
|
|
3278
|
+
const g = typeof globalThis !== "undefined" ? globalThis : {};
|
|
3279
|
+
const webcrypto = g.crypto;
|
|
3280
|
+
const subtle = webcrypto?.subtle;
|
|
3281
|
+
if (subtle) {
|
|
3282
|
+
const buf = await subtle.digest("SHA-256", data);
|
|
3283
|
+
return Array.from(new Uint8Array(buf)).map((b) => b.toString(16).padStart(2, "0")).join("").slice(0, 8);
|
|
3284
|
+
}
|
|
3285
|
+
const nodeCrypto = await import("crypto").catch(() => null);
|
|
3286
|
+
if (nodeCrypto) {
|
|
3287
|
+
return nodeCrypto.createHash("sha256").update(data).digest("hex").slice(0, 8);
|
|
3288
|
+
}
|
|
3289
|
+
throw new Error("No SHA-256 implementation available");
|
|
3290
|
+
}
|
|
3291
|
+
var _mlDsaModule;
|
|
3292
|
+
async function requireNoblePostQuantum() {
|
|
3293
|
+
if (_mlDsaModule) return _mlDsaModule;
|
|
3294
|
+
if (typeof require !== "undefined") {
|
|
3295
|
+
try {
|
|
3296
|
+
_mlDsaModule = require("@noble/post-quantum/ml-dsa.js");
|
|
3297
|
+
return _mlDsaModule;
|
|
3298
|
+
} catch {
|
|
3299
|
+
}
|
|
3300
|
+
}
|
|
3301
|
+
try {
|
|
3302
|
+
_mlDsaModule = await import("@noble/post-quantum/ml-dsa.js");
|
|
3303
|
+
return _mlDsaModule;
|
|
3304
|
+
} catch {
|
|
3305
|
+
throw new Error(
|
|
3306
|
+
"ML-DSA signing requires @noble/post-quantum. Install with: npm install @noble/post-quantum"
|
|
3307
|
+
);
|
|
3308
|
+
}
|
|
3309
|
+
}
|
|
3310
|
+
var MLDSAKeyPair = class _MLDSAKeyPair {
|
|
3311
|
+
keyId;
|
|
3312
|
+
publicKey;
|
|
3313
|
+
secretKey;
|
|
3314
|
+
constructor(data) {
|
|
3315
|
+
this.keyId = data.keyId;
|
|
3316
|
+
this.publicKey = data.publicKey;
|
|
3317
|
+
this.secretKey = data.secretKey;
|
|
3318
|
+
}
|
|
3319
|
+
/** Generate a new ML-DSA-65 key pair. */
|
|
3320
|
+
static async generate() {
|
|
3321
|
+
const { ml_dsa65 } = await requireNoblePostQuantum();
|
|
3322
|
+
const kp = ml_dsa65.keygen();
|
|
3323
|
+
const keyId = await sha256hex(kp.publicKey);
|
|
3324
|
+
return new _MLDSAKeyPair({
|
|
3325
|
+
publicKey: kp.publicKey,
|
|
3326
|
+
secretKey: kp.secretKey,
|
|
3327
|
+
keyId
|
|
3328
|
+
});
|
|
3329
|
+
}
|
|
3330
|
+
/** Build a verify-only key pair from raw public key bytes. */
|
|
3331
|
+
static async fromPublicKey(publicKey) {
|
|
3332
|
+
const keyId = await sha256hex(publicKey);
|
|
3333
|
+
return new _MLDSAKeyPair({ publicKey, keyId });
|
|
3334
|
+
}
|
|
3335
|
+
/** Build a full key pair from saved bytes (public + secret). */
|
|
3336
|
+
static async fromKeyMaterial(publicKey, secretKey) {
|
|
3337
|
+
const keyId = await sha256hex(publicKey);
|
|
3338
|
+
return new _MLDSAKeyPair({ publicKey, secretKey, keyId });
|
|
3339
|
+
}
|
|
3340
|
+
get hasPrivateKey() {
|
|
3341
|
+
return this.secretKey !== void 0;
|
|
3342
|
+
}
|
|
3343
|
+
/** Sign raw bytes; returns ML-DSA-65 signature (3309 bytes). */
|
|
3344
|
+
async signBytes(data) {
|
|
3345
|
+
if (!this.secretKey) {
|
|
3346
|
+
throw new Error("Cannot sign: MLDSAKeyPair has no private key (verify-only)");
|
|
3347
|
+
}
|
|
3348
|
+
const { ml_dsa65 } = await requireNoblePostQuantum();
|
|
3349
|
+
return ml_dsa65.sign(data, this.secretKey);
|
|
3350
|
+
}
|
|
3351
|
+
/**
|
|
3352
|
+
* Verify an ML-DSA-65 signature.
|
|
3353
|
+
* @returns true if valid
|
|
3354
|
+
* @throws {Error} on invalid signature
|
|
3355
|
+
*/
|
|
3356
|
+
async verifyBytes(data, signature) {
|
|
3357
|
+
const { ml_dsa65 } = await requireNoblePostQuantum();
|
|
3358
|
+
const ok = ml_dsa65.verify(signature, data, this.publicKey);
|
|
3359
|
+
if (!ok) throw new Error("ML-DSA signature verification failed");
|
|
3360
|
+
}
|
|
3361
|
+
toString() {
|
|
3362
|
+
const mode = this.hasPrivateKey ? "private+public" : "public-only";
|
|
3363
|
+
return `MLDSAKeyPair(keyId=${this.keyId}, alg=ML-DSA-65, ${mode})`;
|
|
3364
|
+
}
|
|
3365
|
+
};
|
|
3366
|
+
function canonicalMessageBytes(msg) {
|
|
3367
|
+
const m = msg;
|
|
3368
|
+
const payload = {
|
|
3369
|
+
rcan: msg.rcan,
|
|
3370
|
+
msg_id: m["msgId"] ?? m["msg_id"] ?? "",
|
|
3371
|
+
timestamp: msg.timestamp,
|
|
3372
|
+
cmd: msg.cmd,
|
|
3373
|
+
target: msg.target,
|
|
3374
|
+
params: msg.params
|
|
3375
|
+
};
|
|
3376
|
+
const sorted = JSON.stringify(
|
|
3377
|
+
Object.fromEntries(Object.entries(payload).sort()),
|
|
3378
|
+
null,
|
|
3379
|
+
void 0
|
|
3380
|
+
);
|
|
3381
|
+
return new TextEncoder().encode(sorted);
|
|
3382
|
+
}
|
|
3383
|
+
async function addPQSignature(msg, keypair) {
|
|
3384
|
+
const payload = canonicalMessageBytes(msg);
|
|
3385
|
+
const rawSig = await keypair.signBytes(payload);
|
|
3386
|
+
const block = {
|
|
3387
|
+
alg: "ml-dsa-65",
|
|
3388
|
+
kid: keypair.keyId,
|
|
3389
|
+
sig: toBase64url(rawSig)
|
|
3390
|
+
};
|
|
3391
|
+
msg["pqSig"] = block;
|
|
3392
|
+
return msg;
|
|
3393
|
+
}
|
|
3394
|
+
async function verifyPQSignature(msg, trustedKeys, requirePQ = false) {
|
|
3395
|
+
const pqSig = msg["pqSig"];
|
|
3396
|
+
if (!pqSig) {
|
|
3397
|
+
if (requirePQ) {
|
|
3398
|
+
throw new Error("ML-DSA signature (pqSig) required but missing from message");
|
|
3399
|
+
}
|
|
3400
|
+
return;
|
|
3401
|
+
}
|
|
3402
|
+
if (pqSig.alg !== "ml-dsa-65") {
|
|
3403
|
+
throw new Error(`Unsupported PQ signature algorithm: ${pqSig.alg}`);
|
|
3404
|
+
}
|
|
3405
|
+
const matched = trustedKeys.find((k) => k.keyId === pqSig.kid);
|
|
3406
|
+
if (!matched) {
|
|
3407
|
+
throw new Error(
|
|
3408
|
+
`No trusted ML-DSA key with kid=${pqSig.kid}. Known kids: [${trustedKeys.map((k) => k.keyId).join(", ")}]`
|
|
3409
|
+
);
|
|
3410
|
+
}
|
|
3411
|
+
let rawSig;
|
|
3412
|
+
try {
|
|
3413
|
+
rawSig = fromBase64url(pqSig.sig);
|
|
3414
|
+
} catch (e) {
|
|
3415
|
+
throw new Error(`Invalid base64url ML-DSA signature: ${e}`);
|
|
3416
|
+
}
|
|
3417
|
+
const payload = canonicalMessageBytes(msg);
|
|
3418
|
+
await matched.verifyBytes(payload, rawSig);
|
|
3419
|
+
}
|
|
3420
|
+
|
|
3256
3421
|
// src/index.ts
|
|
3257
3422
|
var VERSION = "0.6.0";
|
|
3258
3423
|
var RCAN_VERSION = "1.6";
|
|
@@ -3278,6 +3443,7 @@ var RCAN_VERSION = "1.6";
|
|
|
3278
3443
|
LevelOfAssurance,
|
|
3279
3444
|
M2MAuthError,
|
|
3280
3445
|
M2M_TRUSTED_ISSUER,
|
|
3446
|
+
MLDSAKeyPair,
|
|
3281
3447
|
MediaEncoding,
|
|
3282
3448
|
MessageType,
|
|
3283
3449
|
NodeClient,
|
|
@@ -3324,6 +3490,7 @@ var RCAN_VERSION = "1.6";
|
|
|
3324
3490
|
addDelegationHop,
|
|
3325
3491
|
addMediaInline,
|
|
3326
3492
|
addMediaRef,
|
|
3493
|
+
addPQSignature,
|
|
3327
3494
|
assertClockSynced,
|
|
3328
3495
|
authorityAccessFromWire,
|
|
3329
3496
|
authorityAccessToWire,
|
|
@@ -3398,6 +3565,7 @@ var RCAN_VERSION = "1.6";
|
|
|
3398
3565
|
validateURI,
|
|
3399
3566
|
validateVersionCompat,
|
|
3400
3567
|
verifyM2mTrustedToken,
|
|
3401
|
-
verifyM2mTrustedTokenClaims
|
|
3568
|
+
verifyM2mTrustedTokenClaims,
|
|
3569
|
+
verifyPQSignature
|
|
3402
3570
|
});
|
|
3403
3571
|
//# sourceMappingURL=index.js.map
|