@bcts/xid 1.0.0-alpha.12 → 1.0.0-alpha.13
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 +108 -92
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +49 -34
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.mts +49 -34
- package/dist/index.d.mts.map +1 -1
- package/dist/index.iife.js +109 -93
- package/dist/index.iife.js.map +1 -1
- package/dist/index.mjs +105 -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 +64 -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,14 @@ 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
|
+
} from "@bcts/components";
|
|
29
29
|
import {
|
|
30
30
|
type ProvenanceMark,
|
|
31
31
|
ProvenanceMarkGenerator,
|
|
@@ -38,7 +38,6 @@ import { Delegate, registerXIDDocumentClass } from "./delegate";
|
|
|
38
38
|
import { Service } from "./service";
|
|
39
39
|
import { Provenance, XIDGeneratorOptions, type XIDGeneratorOptionsValue } from "./provenance";
|
|
40
40
|
import { XIDError } from "./error";
|
|
41
|
-
|
|
42
41
|
// Raw values for predicate matching
|
|
43
42
|
const KEY_RAW = KEY.value();
|
|
44
43
|
const DELEGATE_RAW = DELEGATE.value();
|
|
@@ -51,8 +50,9 @@ const DEREFERENCE_VIA_RAW = DEREFERENCE_VIA.value();
|
|
|
51
50
|
*/
|
|
52
51
|
export type XIDInceptionKeyOptions =
|
|
53
52
|
| { type: "default" }
|
|
54
|
-
| { type: "
|
|
55
|
-
| { type: "privateKeyBase"; privateKeyBase: PrivateKeyBase }
|
|
53
|
+
| { type: "publicKeys"; publicKeys: PublicKeys }
|
|
54
|
+
| { type: "privateKeyBase"; privateKeyBase: PrivateKeyBase }
|
|
55
|
+
| { type: "privateKeys"; privateKeys: PrivateKeys; publicKeys: PublicKeys };
|
|
56
56
|
|
|
57
57
|
/**
|
|
58
58
|
* Options for creating the genesis mark.
|
|
@@ -80,7 +80,8 @@ export type XIDGenesisMarkOptions =
|
|
|
80
80
|
export type XIDSigningOptions =
|
|
81
81
|
| { type: "none" }
|
|
82
82
|
| { type: "inception" }
|
|
83
|
-
| { type: "privateKeyBase"; privateKeyBase: PrivateKeyBase }
|
|
83
|
+
| { type: "privateKeyBase"; privateKeyBase: PrivateKeyBase }
|
|
84
|
+
| { type: "privateKeys"; privateKeys: PrivateKeys };
|
|
84
85
|
|
|
85
86
|
/**
|
|
86
87
|
* Options for verifying the signature on an envelope when loading.
|
|
@@ -134,7 +135,9 @@ export class XIDDocument implements EnvelopeEncodable {
|
|
|
134
135
|
const inceptionKey = XIDDocument.inceptionKeyForOptions(keyOptions);
|
|
135
136
|
const provenance = XIDDocument.genesisMarkWithOptions(markOptions);
|
|
136
137
|
|
|
137
|
-
|
|
138
|
+
// Use the reference from PublicKeys (which uses tagged CBOR hash)
|
|
139
|
+
// XID is created from the digest data of the reference
|
|
140
|
+
const xid = XID.from(inceptionKey.publicKeys().reference().getDigest().toData());
|
|
138
141
|
const doc = new XIDDocument(xid, new Set(), new Map(), new Map(), new Map(), provenance);
|
|
139
142
|
|
|
140
143
|
doc.addKey(inceptionKey);
|
|
@@ -144,13 +147,15 @@ export class XIDDocument implements EnvelopeEncodable {
|
|
|
144
147
|
private static inceptionKeyForOptions(options: XIDInceptionKeyOptions): Key {
|
|
145
148
|
switch (options.type) {
|
|
146
149
|
case "default": {
|
|
147
|
-
const privateKeyBase = PrivateKeyBase.
|
|
150
|
+
const privateKeyBase = PrivateKeyBase.new();
|
|
148
151
|
return Key.newWithPrivateKeyBase(privateKeyBase);
|
|
149
152
|
}
|
|
150
|
-
case "
|
|
151
|
-
return Key.newAllowAll(options.
|
|
153
|
+
case "publicKeys":
|
|
154
|
+
return Key.newAllowAll(options.publicKeys);
|
|
152
155
|
case "privateKeyBase":
|
|
153
156
|
return Key.newWithPrivateKeyBase(options.privateKeyBase);
|
|
157
|
+
case "privateKeys":
|
|
158
|
+
return Key.newWithPrivateKeys(options.privateKeys, options.publicKeys);
|
|
154
159
|
}
|
|
155
160
|
}
|
|
156
161
|
|
|
@@ -229,10 +234,10 @@ export class XIDDocument implements EnvelopeEncodable {
|
|
|
229
234
|
}
|
|
230
235
|
|
|
231
236
|
/**
|
|
232
|
-
* Find a key by its public
|
|
237
|
+
* Find a key by its public keys.
|
|
233
238
|
*/
|
|
234
|
-
|
|
235
|
-
const hashKey =
|
|
239
|
+
findKeyByPublicKeys(publicKeys: PublicKeys): Key | undefined {
|
|
240
|
+
const hashKey = publicKeys.reference().toHex();
|
|
236
241
|
return this._keys.get(hashKey);
|
|
237
242
|
}
|
|
238
243
|
|
|
@@ -251,8 +256,8 @@ export class XIDDocument implements EnvelopeEncodable {
|
|
|
251
256
|
/**
|
|
252
257
|
* Take and remove a key.
|
|
253
258
|
*/
|
|
254
|
-
takeKey(
|
|
255
|
-
const hashKey =
|
|
259
|
+
takeKey(publicKeys: PublicKeys): Key | undefined {
|
|
260
|
+
const hashKey = publicKeys.reference().toHex();
|
|
256
261
|
const key = this._keys.get(hashKey);
|
|
257
262
|
if (key !== undefined) {
|
|
258
263
|
this._keys.delete(hashKey);
|
|
@@ -263,22 +268,23 @@ export class XIDDocument implements EnvelopeEncodable {
|
|
|
263
268
|
/**
|
|
264
269
|
* Remove a key.
|
|
265
270
|
*/
|
|
266
|
-
removeKey(
|
|
267
|
-
if (this.servicesReferenceKey(
|
|
271
|
+
removeKey(publicKeys: PublicKeys): void {
|
|
272
|
+
if (this.servicesReferenceKey(publicKeys)) {
|
|
268
273
|
throw XIDError.stillReferenced("key");
|
|
269
274
|
}
|
|
270
|
-
const hashKey =
|
|
275
|
+
const hashKey = publicKeys.reference().toHex();
|
|
271
276
|
if (!this._keys.delete(hashKey)) {
|
|
272
277
|
throw XIDError.notFound("key");
|
|
273
278
|
}
|
|
274
279
|
}
|
|
275
280
|
|
|
276
281
|
/**
|
|
277
|
-
* Check if the given public
|
|
282
|
+
* Check if the given public keys is the inception signing key.
|
|
278
283
|
*/
|
|
279
|
-
isInceptionKey(
|
|
280
|
-
|
|
281
|
-
|
|
284
|
+
isInceptionKey(publicKeys: PublicKeys): boolean {
|
|
285
|
+
// The XID is derived from the reference of the inception PublicKeys
|
|
286
|
+
const xidReference = publicKeys.reference();
|
|
287
|
+
return bytesEqual(xidReference.getDigest().toData(), this._xid.toData());
|
|
282
288
|
}
|
|
283
289
|
|
|
284
290
|
/**
|
|
@@ -286,7 +292,7 @@ export class XIDDocument implements EnvelopeEncodable {
|
|
|
286
292
|
*/
|
|
287
293
|
inceptionKey(): Key | undefined {
|
|
288
294
|
for (const key of this._keys.values()) {
|
|
289
|
-
if (this.isInceptionKey(key.
|
|
295
|
+
if (this.isInceptionKey(key.publicKeys())) {
|
|
290
296
|
return key;
|
|
291
297
|
}
|
|
292
298
|
}
|
|
@@ -294,10 +300,10 @@ export class XIDDocument implements EnvelopeEncodable {
|
|
|
294
300
|
}
|
|
295
301
|
|
|
296
302
|
/**
|
|
297
|
-
* Get the inception private
|
|
303
|
+
* Get the inception private keys, if available.
|
|
298
304
|
*/
|
|
299
|
-
|
|
300
|
-
return this.inceptionKey()?.
|
|
305
|
+
inceptionPrivateKeys(): PrivateKeys | undefined {
|
|
306
|
+
return this.inceptionKey()?.privateKeys();
|
|
301
307
|
}
|
|
302
308
|
|
|
303
309
|
/**
|
|
@@ -448,16 +454,16 @@ export class XIDDocument implements EnvelopeEncodable {
|
|
|
448
454
|
}
|
|
449
455
|
|
|
450
456
|
for (const keyRef of service.keyReferences()) {
|
|
451
|
-
|
|
452
|
-
const ref = Reference.
|
|
457
|
+
// keyRef is already a hex representation of a Reference, don't hash again
|
|
458
|
+
const ref = Reference.fromHex(keyRef);
|
|
453
459
|
if (this.findKeyByReference(ref) === undefined) {
|
|
454
460
|
throw XIDError.unknownKeyReference(keyRef, service.uri());
|
|
455
461
|
}
|
|
456
462
|
}
|
|
457
463
|
|
|
458
464
|
for (const delegateRef of service.delegateReferences()) {
|
|
459
|
-
|
|
460
|
-
const ref = Reference.
|
|
465
|
+
// delegateRef is already a hex representation of a Reference, don't hash again
|
|
466
|
+
const ref = Reference.fromHex(delegateRef);
|
|
461
467
|
if (this.findDelegateByReference(ref) === undefined) {
|
|
462
468
|
throw XIDError.unknownDelegateReference(delegateRef, service.uri());
|
|
463
469
|
}
|
|
@@ -471,8 +477,8 @@ export class XIDDocument implements EnvelopeEncodable {
|
|
|
471
477
|
/**
|
|
472
478
|
* Check if any service references the given key.
|
|
473
479
|
*/
|
|
474
|
-
servicesReferenceKey(
|
|
475
|
-
const keyRef =
|
|
480
|
+
servicesReferenceKey(publicKeys: PublicKeys): boolean {
|
|
481
|
+
const keyRef = publicKeys.reference().toHex();
|
|
476
482
|
for (const service of this._services.values()) {
|
|
477
483
|
if (service.keyReferences().has(keyRef)) {
|
|
478
484
|
return true;
|
|
@@ -627,27 +633,33 @@ export class XIDDocument implements EnvelopeEncodable {
|
|
|
627
633
|
);
|
|
628
634
|
}
|
|
629
635
|
|
|
630
|
-
// Apply signing
|
|
636
|
+
// Apply signing (uses sign() which wraps the envelope first)
|
|
637
|
+
// PrivateKeys implements Signer from @bcts/components, which is compatible with envelope's sign()
|
|
631
638
|
switch (signingOptions.type) {
|
|
632
639
|
case "inception": {
|
|
633
640
|
const inceptionKey = this.inceptionKey();
|
|
634
641
|
if (inceptionKey === undefined) {
|
|
635
642
|
throw XIDError.missingInceptionKey();
|
|
636
643
|
}
|
|
637
|
-
const
|
|
638
|
-
if (
|
|
644
|
+
const privateKeys = inceptionKey.privateKeys();
|
|
645
|
+
if (privateKeys === undefined) {
|
|
639
646
|
throw XIDError.missingInceptionKey();
|
|
640
647
|
}
|
|
641
|
-
envelope = (envelope as unknown as {
|
|
642
|
-
privateKeyBase as unknown as Signer,
|
|
643
|
-
);
|
|
648
|
+
envelope = (envelope as unknown as { sign(s: Signer): Envelope }).sign(privateKeys);
|
|
644
649
|
break;
|
|
645
650
|
}
|
|
646
|
-
case "privateKeyBase":
|
|
647
|
-
|
|
648
|
-
|
|
651
|
+
case "privateKeyBase": {
|
|
652
|
+
// Derive PrivateKeys from PrivateKeyBase and use for signing
|
|
653
|
+
const privateKeys = signingOptions.privateKeyBase.ed25519PrivateKeys();
|
|
654
|
+
envelope = (envelope as unknown as { sign(s: Signer): Envelope }).sign(privateKeys);
|
|
655
|
+
break;
|
|
656
|
+
}
|
|
657
|
+
case "privateKeys": {
|
|
658
|
+
envelope = (envelope as unknown as { sign(s: Signer): Envelope }).sign(
|
|
659
|
+
signingOptions.privateKeys,
|
|
649
660
|
);
|
|
650
661
|
break;
|
|
662
|
+
}
|
|
651
663
|
case "none":
|
|
652
664
|
default:
|
|
653
665
|
break;
|
|
@@ -693,13 +705,13 @@ export class XIDDocument implements EnvelopeEncodable {
|
|
|
693
705
|
throw XIDError.missingInceptionKey();
|
|
694
706
|
}
|
|
695
707
|
|
|
696
|
-
// Verify signature
|
|
697
|
-
if (!envelopeExt.hasSignatureFrom(inceptionKey.
|
|
708
|
+
// Verify signature using the PublicKeys (implements Verifier from @bcts/components)
|
|
709
|
+
if (!envelopeExt.hasSignatureFrom(inceptionKey.publicKeys())) {
|
|
698
710
|
throw XIDError.signatureVerificationFailed();
|
|
699
711
|
}
|
|
700
712
|
|
|
701
713
|
// Verify XID matches inception key
|
|
702
|
-
if (!doc.isInceptionKey(inceptionKey.
|
|
714
|
+
if (!doc.isInceptionKey(inceptionKey.publicKeys())) {
|
|
703
715
|
throw XIDError.invalidXid();
|
|
704
716
|
}
|
|
705
717
|
|
|
@@ -791,7 +803,7 @@ export class XIDDocument implements EnvelopeEncodable {
|
|
|
791
803
|
const envelope = this.toEnvelope(XIDPrivateKeyOptions.Omit, XIDGeneratorOptions.Omit, {
|
|
792
804
|
type: "none",
|
|
793
805
|
});
|
|
794
|
-
return (envelope as unknown as {
|
|
806
|
+
return (envelope as unknown as { sign(s: Signer): Envelope }).sign(signingKey);
|
|
795
807
|
}
|
|
796
808
|
|
|
797
809
|
/**
|
|
@@ -834,20 +846,7 @@ export class XIDDocument implements EnvelopeEncodable {
|
|
|
834
846
|
// Register XIDDocument class with Delegate to resolve circular dependency
|
|
835
847
|
registerXIDDocumentClass(XIDDocument);
|
|
836
848
|
|
|
837
|
-
// Helper interface for Verifier
|
|
838
|
-
interface Verifier {
|
|
839
|
-
verify(data: Uint8Array, signature: { data(): Uint8Array }): boolean;
|
|
840
|
-
}
|
|
841
|
-
|
|
842
849
|
// 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
850
|
function bytesEqual(a: Uint8Array, b: Uint8Array): boolean {
|
|
852
851
|
if (a.length !== b.length) return false;
|
|
853
852
|
for (let i = 0; i < a.length; i++) {
|
|
@@ -855,8 +854,3 @@ function bytesEqual(a: Uint8Array, b: Uint8Array): boolean {
|
|
|
855
854
|
}
|
|
856
855
|
return true;
|
|
857
856
|
}
|
|
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
|
-
}
|