@bcts/xid 1.0.0-alpha.12 → 1.0.0-alpha.14
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 +120 -92
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +56 -34
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.mts +56 -34
- package/dist/index.d.mts.map +1 -1
- package/dist/index.iife.js +121 -93
- package/dist/index.iife.js.map +1 -1
- package/dist/index.mjs +117 -95
- package/dist/index.mjs.map +1 -1
- package/package.json +9 -10
- package/src/index.ts +3 -0
- package/src/key.ts +91 -60
- package/src/xid-document.ts +85 -70
package/src/xid-document.ts
CHANGED
|
@@ -6,14 +6,7 @@
|
|
|
6
6
|
* Ported from bc-xid-rust/src/xid_document.rs
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
|
-
import {
|
|
10
|
-
Envelope,
|
|
11
|
-
PrivateKeyBase,
|
|
12
|
-
type PublicKeyBase,
|
|
13
|
-
type EnvelopeEncodable,
|
|
14
|
-
type Signer,
|
|
15
|
-
type EnvelopeEncodableValue,
|
|
16
|
-
} from "@bcts/envelope";
|
|
9
|
+
import { Envelope, type EnvelopeEncodable, type EnvelopeEncodableValue } from "@bcts/envelope";
|
|
17
10
|
import {
|
|
18
11
|
KEY,
|
|
19
12
|
DELEGATE,
|
|
@@ -25,7 +18,15 @@ import {
|
|
|
25
18
|
|
|
26
19
|
// Helper to convert KnownValue to EnvelopeEncodableValue
|
|
27
20
|
const kv = (v: KnownValue): EnvelopeEncodableValue => v as unknown as EnvelopeEncodableValue;
|
|
28
|
-
import {
|
|
21
|
+
import {
|
|
22
|
+
Reference,
|
|
23
|
+
XID,
|
|
24
|
+
type PublicKeys,
|
|
25
|
+
PrivateKeyBase,
|
|
26
|
+
type PrivateKeys,
|
|
27
|
+
type Signer,
|
|
28
|
+
type EncapsulationPublicKey,
|
|
29
|
+
} from "@bcts/components";
|
|
29
30
|
import {
|
|
30
31
|
type ProvenanceMark,
|
|
31
32
|
ProvenanceMarkGenerator,
|
|
@@ -38,7 +39,6 @@ import { Delegate, registerXIDDocumentClass } from "./delegate";
|
|
|
38
39
|
import { Service } from "./service";
|
|
39
40
|
import { Provenance, XIDGeneratorOptions, type XIDGeneratorOptionsValue } from "./provenance";
|
|
40
41
|
import { XIDError } from "./error";
|
|
41
|
-
|
|
42
42
|
// Raw values for predicate matching
|
|
43
43
|
const KEY_RAW = KEY.value();
|
|
44
44
|
const DELEGATE_RAW = DELEGATE.value();
|
|
@@ -51,8 +51,9 @@ const DEREFERENCE_VIA_RAW = DEREFERENCE_VIA.value();
|
|
|
51
51
|
*/
|
|
52
52
|
export type XIDInceptionKeyOptions =
|
|
53
53
|
| { type: "default" }
|
|
54
|
-
| { type: "
|
|
55
|
-
| { type: "privateKeyBase"; privateKeyBase: PrivateKeyBase }
|
|
54
|
+
| { type: "publicKeys"; publicKeys: PublicKeys }
|
|
55
|
+
| { type: "privateKeyBase"; privateKeyBase: PrivateKeyBase }
|
|
56
|
+
| { type: "privateKeys"; privateKeys: PrivateKeys; publicKeys: PublicKeys };
|
|
56
57
|
|
|
57
58
|
/**
|
|
58
59
|
* Options for creating the genesis mark.
|
|
@@ -80,7 +81,8 @@ export type XIDGenesisMarkOptions =
|
|
|
80
81
|
export type XIDSigningOptions =
|
|
81
82
|
| { type: "none" }
|
|
82
83
|
| { type: "inception" }
|
|
83
|
-
| { type: "privateKeyBase"; privateKeyBase: PrivateKeyBase }
|
|
84
|
+
| { type: "privateKeyBase"; privateKeyBase: PrivateKeyBase }
|
|
85
|
+
| { type: "privateKeys"; privateKeys: PrivateKeys };
|
|
84
86
|
|
|
85
87
|
/**
|
|
86
88
|
* Options for verifying the signature on an envelope when loading.
|
|
@@ -134,7 +136,9 @@ export class XIDDocument implements EnvelopeEncodable {
|
|
|
134
136
|
const inceptionKey = XIDDocument.inceptionKeyForOptions(keyOptions);
|
|
135
137
|
const provenance = XIDDocument.genesisMarkWithOptions(markOptions);
|
|
136
138
|
|
|
137
|
-
|
|
139
|
+
// Use the reference from PublicKeys (which uses tagged CBOR hash)
|
|
140
|
+
// XID is created from the digest data of the reference
|
|
141
|
+
const xid = XID.from(inceptionKey.publicKeys().reference().getDigest().toData());
|
|
138
142
|
const doc = new XIDDocument(xid, new Set(), new Map(), new Map(), new Map(), provenance);
|
|
139
143
|
|
|
140
144
|
doc.addKey(inceptionKey);
|
|
@@ -144,13 +148,15 @@ export class XIDDocument implements EnvelopeEncodable {
|
|
|
144
148
|
private static inceptionKeyForOptions(options: XIDInceptionKeyOptions): Key {
|
|
145
149
|
switch (options.type) {
|
|
146
150
|
case "default": {
|
|
147
|
-
const privateKeyBase = PrivateKeyBase.
|
|
151
|
+
const privateKeyBase = PrivateKeyBase.new();
|
|
148
152
|
return Key.newWithPrivateKeyBase(privateKeyBase);
|
|
149
153
|
}
|
|
150
|
-
case "
|
|
151
|
-
return Key.newAllowAll(options.
|
|
154
|
+
case "publicKeys":
|
|
155
|
+
return Key.newAllowAll(options.publicKeys);
|
|
152
156
|
case "privateKeyBase":
|
|
153
157
|
return Key.newWithPrivateKeyBase(options.privateKeyBase);
|
|
158
|
+
case "privateKeys":
|
|
159
|
+
return Key.newWithPrivateKeys(options.privateKeys, options.publicKeys);
|
|
154
160
|
}
|
|
155
161
|
}
|
|
156
162
|
|
|
@@ -229,10 +235,10 @@ export class XIDDocument implements EnvelopeEncodable {
|
|
|
229
235
|
}
|
|
230
236
|
|
|
231
237
|
/**
|
|
232
|
-
* Find a key by its public
|
|
238
|
+
* Find a key by its public keys.
|
|
233
239
|
*/
|
|
234
|
-
|
|
235
|
-
const hashKey =
|
|
240
|
+
findKeyByPublicKeys(publicKeys: PublicKeys): Key | undefined {
|
|
241
|
+
const hashKey = publicKeys.reference().toHex();
|
|
236
242
|
return this._keys.get(hashKey);
|
|
237
243
|
}
|
|
238
244
|
|
|
@@ -251,8 +257,8 @@ export class XIDDocument implements EnvelopeEncodable {
|
|
|
251
257
|
/**
|
|
252
258
|
* Take and remove a key.
|
|
253
259
|
*/
|
|
254
|
-
takeKey(
|
|
255
|
-
const hashKey =
|
|
260
|
+
takeKey(publicKeys: PublicKeys): Key | undefined {
|
|
261
|
+
const hashKey = publicKeys.reference().toHex();
|
|
256
262
|
const key = this._keys.get(hashKey);
|
|
257
263
|
if (key !== undefined) {
|
|
258
264
|
this._keys.delete(hashKey);
|
|
@@ -263,22 +269,23 @@ export class XIDDocument implements EnvelopeEncodable {
|
|
|
263
269
|
/**
|
|
264
270
|
* Remove a key.
|
|
265
271
|
*/
|
|
266
|
-
removeKey(
|
|
267
|
-
if (this.servicesReferenceKey(
|
|
272
|
+
removeKey(publicKeys: PublicKeys): void {
|
|
273
|
+
if (this.servicesReferenceKey(publicKeys)) {
|
|
268
274
|
throw XIDError.stillReferenced("key");
|
|
269
275
|
}
|
|
270
|
-
const hashKey =
|
|
276
|
+
const hashKey = publicKeys.reference().toHex();
|
|
271
277
|
if (!this._keys.delete(hashKey)) {
|
|
272
278
|
throw XIDError.notFound("key");
|
|
273
279
|
}
|
|
274
280
|
}
|
|
275
281
|
|
|
276
282
|
/**
|
|
277
|
-
* Check if the given public
|
|
283
|
+
* Check if the given public keys is the inception signing key.
|
|
278
284
|
*/
|
|
279
|
-
isInceptionKey(
|
|
280
|
-
|
|
281
|
-
|
|
285
|
+
isInceptionKey(publicKeys: PublicKeys): boolean {
|
|
286
|
+
// The XID is derived from the reference of the inception PublicKeys
|
|
287
|
+
const xidReference = publicKeys.reference();
|
|
288
|
+
return bytesEqual(xidReference.getDigest().toData(), this._xid.toData());
|
|
282
289
|
}
|
|
283
290
|
|
|
284
291
|
/**
|
|
@@ -286,7 +293,7 @@ export class XIDDocument implements EnvelopeEncodable {
|
|
|
286
293
|
*/
|
|
287
294
|
inceptionKey(): Key | undefined {
|
|
288
295
|
for (const key of this._keys.values()) {
|
|
289
|
-
if (this.isInceptionKey(key.
|
|
296
|
+
if (this.isInceptionKey(key.publicKeys())) {
|
|
290
297
|
return key;
|
|
291
298
|
}
|
|
292
299
|
}
|
|
@@ -294,10 +301,30 @@ export class XIDDocument implements EnvelopeEncodable {
|
|
|
294
301
|
}
|
|
295
302
|
|
|
296
303
|
/**
|
|
297
|
-
* Get the inception private
|
|
304
|
+
* Get the inception private keys, if available.
|
|
298
305
|
*/
|
|
299
|
-
|
|
300
|
-
return this.inceptionKey()?.
|
|
306
|
+
inceptionPrivateKeys(): PrivateKeys | undefined {
|
|
307
|
+
return this.inceptionKey()?.privateKeys();
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
/**
|
|
311
|
+
* Get the encryption key (encapsulation public key) for this document.
|
|
312
|
+
*
|
|
313
|
+
* Prefers the inception key for encryption. If no inception key is available,
|
|
314
|
+
* falls back to the first key in the document.
|
|
315
|
+
*/
|
|
316
|
+
encryptionKey(): EncapsulationPublicKey | undefined {
|
|
317
|
+
// Prefer the inception key for encryption
|
|
318
|
+
const inceptionKey = this.inceptionKey();
|
|
319
|
+
if (inceptionKey !== undefined) {
|
|
320
|
+
return inceptionKey.publicKeys().encapsulationPublicKey();
|
|
321
|
+
}
|
|
322
|
+
// Fall back to first key
|
|
323
|
+
const firstKey = this._keys.values().next().value;
|
|
324
|
+
if (firstKey !== undefined) {
|
|
325
|
+
return firstKey.publicKeys().encapsulationPublicKey();
|
|
326
|
+
}
|
|
327
|
+
return undefined;
|
|
301
328
|
}
|
|
302
329
|
|
|
303
330
|
/**
|
|
@@ -448,16 +475,16 @@ export class XIDDocument implements EnvelopeEncodable {
|
|
|
448
475
|
}
|
|
449
476
|
|
|
450
477
|
for (const keyRef of service.keyReferences()) {
|
|
451
|
-
|
|
452
|
-
const ref = Reference.
|
|
478
|
+
// keyRef is already a hex representation of a Reference, don't hash again
|
|
479
|
+
const ref = Reference.fromHex(keyRef);
|
|
453
480
|
if (this.findKeyByReference(ref) === undefined) {
|
|
454
481
|
throw XIDError.unknownKeyReference(keyRef, service.uri());
|
|
455
482
|
}
|
|
456
483
|
}
|
|
457
484
|
|
|
458
485
|
for (const delegateRef of service.delegateReferences()) {
|
|
459
|
-
|
|
460
|
-
const ref = Reference.
|
|
486
|
+
// delegateRef is already a hex representation of a Reference, don't hash again
|
|
487
|
+
const ref = Reference.fromHex(delegateRef);
|
|
461
488
|
if (this.findDelegateByReference(ref) === undefined) {
|
|
462
489
|
throw XIDError.unknownDelegateReference(delegateRef, service.uri());
|
|
463
490
|
}
|
|
@@ -471,8 +498,8 @@ export class XIDDocument implements EnvelopeEncodable {
|
|
|
471
498
|
/**
|
|
472
499
|
* Check if any service references the given key.
|
|
473
500
|
*/
|
|
474
|
-
servicesReferenceKey(
|
|
475
|
-
const keyRef =
|
|
501
|
+
servicesReferenceKey(publicKeys: PublicKeys): boolean {
|
|
502
|
+
const keyRef = publicKeys.reference().toHex();
|
|
476
503
|
for (const service of this._services.values()) {
|
|
477
504
|
if (service.keyReferences().has(keyRef)) {
|
|
478
505
|
return true;
|
|
@@ -627,27 +654,33 @@ export class XIDDocument implements EnvelopeEncodable {
|
|
|
627
654
|
);
|
|
628
655
|
}
|
|
629
656
|
|
|
630
|
-
// Apply signing
|
|
657
|
+
// Apply signing (uses sign() which wraps the envelope first)
|
|
658
|
+
// PrivateKeys implements Signer from @bcts/components, which is compatible with envelope's sign()
|
|
631
659
|
switch (signingOptions.type) {
|
|
632
660
|
case "inception": {
|
|
633
661
|
const inceptionKey = this.inceptionKey();
|
|
634
662
|
if (inceptionKey === undefined) {
|
|
635
663
|
throw XIDError.missingInceptionKey();
|
|
636
664
|
}
|
|
637
|
-
const
|
|
638
|
-
if (
|
|
665
|
+
const privateKeys = inceptionKey.privateKeys();
|
|
666
|
+
if (privateKeys === undefined) {
|
|
639
667
|
throw XIDError.missingInceptionKey();
|
|
640
668
|
}
|
|
641
|
-
envelope = (envelope as unknown as {
|
|
642
|
-
privateKeyBase as unknown as Signer,
|
|
643
|
-
);
|
|
669
|
+
envelope = (envelope as unknown as { sign(s: Signer): Envelope }).sign(privateKeys);
|
|
644
670
|
break;
|
|
645
671
|
}
|
|
646
|
-
case "privateKeyBase":
|
|
647
|
-
|
|
648
|
-
|
|
672
|
+
case "privateKeyBase": {
|
|
673
|
+
// Derive PrivateKeys from PrivateKeyBase and use for signing
|
|
674
|
+
const privateKeys = signingOptions.privateKeyBase.ed25519PrivateKeys();
|
|
675
|
+
envelope = (envelope as unknown as { sign(s: Signer): Envelope }).sign(privateKeys);
|
|
676
|
+
break;
|
|
677
|
+
}
|
|
678
|
+
case "privateKeys": {
|
|
679
|
+
envelope = (envelope as unknown as { sign(s: Signer): Envelope }).sign(
|
|
680
|
+
signingOptions.privateKeys,
|
|
649
681
|
);
|
|
650
682
|
break;
|
|
683
|
+
}
|
|
651
684
|
case "none":
|
|
652
685
|
default:
|
|
653
686
|
break;
|
|
@@ -693,13 +726,13 @@ export class XIDDocument implements EnvelopeEncodable {
|
|
|
693
726
|
throw XIDError.missingInceptionKey();
|
|
694
727
|
}
|
|
695
728
|
|
|
696
|
-
// Verify signature
|
|
697
|
-
if (!envelopeExt.hasSignatureFrom(inceptionKey.
|
|
729
|
+
// Verify signature using the PublicKeys (implements Verifier from @bcts/components)
|
|
730
|
+
if (!envelopeExt.hasSignatureFrom(inceptionKey.publicKeys())) {
|
|
698
731
|
throw XIDError.signatureVerificationFailed();
|
|
699
732
|
}
|
|
700
733
|
|
|
701
734
|
// Verify XID matches inception key
|
|
702
|
-
if (!doc.isInceptionKey(inceptionKey.
|
|
735
|
+
if (!doc.isInceptionKey(inceptionKey.publicKeys())) {
|
|
703
736
|
throw XIDError.invalidXid();
|
|
704
737
|
}
|
|
705
738
|
|
|
@@ -791,7 +824,7 @@ export class XIDDocument implements EnvelopeEncodable {
|
|
|
791
824
|
const envelope = this.toEnvelope(XIDPrivateKeyOptions.Omit, XIDGeneratorOptions.Omit, {
|
|
792
825
|
type: "none",
|
|
793
826
|
});
|
|
794
|
-
return (envelope as unknown as {
|
|
827
|
+
return (envelope as unknown as { sign(s: Signer): Envelope }).sign(signingKey);
|
|
795
828
|
}
|
|
796
829
|
|
|
797
830
|
/**
|
|
@@ -834,20 +867,7 @@ export class XIDDocument implements EnvelopeEncodable {
|
|
|
834
867
|
// Register XIDDocument class with Delegate to resolve circular dependency
|
|
835
868
|
registerXIDDocumentClass(XIDDocument);
|
|
836
869
|
|
|
837
|
-
// Helper interface for Verifier
|
|
838
|
-
interface Verifier {
|
|
839
|
-
verify(data: Uint8Array, signature: { data(): Uint8Array }): boolean;
|
|
840
|
-
}
|
|
841
|
-
|
|
842
870
|
// Helper functions
|
|
843
|
-
function hexToBytes(hex: string): Uint8Array {
|
|
844
|
-
const bytes = new Uint8Array(hex.length / 2);
|
|
845
|
-
for (let i = 0; i < hex.length; i += 2) {
|
|
846
|
-
bytes[i / 2] = parseInt(hex.substring(i, i + 2), 16);
|
|
847
|
-
}
|
|
848
|
-
return bytes;
|
|
849
|
-
}
|
|
850
|
-
|
|
851
871
|
function bytesEqual(a: Uint8Array, b: Uint8Array): boolean {
|
|
852
872
|
if (a.length !== b.length) return false;
|
|
853
873
|
for (let i = 0; i < a.length; i++) {
|
|
@@ -855,8 +875,3 @@ function bytesEqual(a: Uint8Array, b: Uint8Array): boolean {
|
|
|
855
875
|
}
|
|
856
876
|
return true;
|
|
857
877
|
}
|
|
858
|
-
|
|
859
|
-
function hashPublicKey(publicKeyBase: PublicKeyBase): Uint8Array {
|
|
860
|
-
// SHA-256 hash of public key to get XID
|
|
861
|
-
return Reference.hash(publicKeyBase.data()).getDigest().toData();
|
|
862
|
-
}
|