-
Notifications
You must be signed in to change notification settings - Fork 12
Expand file tree
/
Copy pathhelpers.js
More file actions
181 lines (161 loc) · 5.74 KB
/
Copy pathhelpers.js
File metadata and controls
181 lines (161 loc) · 5.74 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
/*!
* Copyright (c) 2023-2025 Digital Bazaar, Inc. All rights reserved.
*/
import * as base58btc from 'base58-universal';
import * as Ed25519Multikey from '@digitalbazaar/ed25519-multikey';
import {
X25519KeyAgreementKey2020
} from '@digitalbazaar/x25519-key-agreement-key-2020';
const ED25519_KEY_2018_TYPE = 'Ed25519VerificationKey2018';
const ED25519_KEY_2018_CONTEXT_URL =
'https://w3id.org/security/suites/ed25519-2018/v1';
const ED25519_KEY_2020_TYPE = 'Ed25519VerificationKey2020';
const ED25519_KEY_2020_CONTEXT_URL =
'https://w3id.org/security/suites/ed25519-2020/v1';
const MULTIKEY_TYPE = 'Multikey';
const MULTIKEY_CONTEXT_V1_URL = 'https://w3id.org/security/multikey/v1';
const X25519_2019_TYPE = 'X25519KeyAgreementKey2019';
const X25519_2019_CONTEXT_URL =
'https://w3id.org/security/suites/x25519-2019/v1';
const X25519_2020_TYPE = 'X25519KeyAgreementKey2020';
const X25519_2020_CONTEXT_URL =
'https://w3id.org/security/suites/x25519-2020/v1';
const contextsBySuite = new Map([
[ED25519_KEY_2020_TYPE, ED25519_KEY_2020_CONTEXT_URL],
[ED25519_KEY_2018_TYPE, ED25519_KEY_2018_CONTEXT_URL],
[MULTIKEY_TYPE, MULTIKEY_CONTEXT_V1_URL],
[X25519_2020_TYPE, X25519_2020_CONTEXT_URL],
[X25519_2019_TYPE, X25519_2019_CONTEXT_URL]
]);
/**
* Returns the public key object for a given key id fragment.
*
* @param {object} options - Options hashmap.
* @param {object} options.didDocument - The DID Document to use when generating
* the id.
* @param {string} options.keyIdFragment - The key identifier fragment.
*
* @returns {object} Returns the public key node, with `@context`.
*/
export function getKey({didDocument, keyIdFragment}) {
// Determine if the key id fragment belongs to the "main" public key,
// or the keyAgreement key
const keyId = didDocument.id + '#' + keyIdFragment;
let publicKey;
if(didDocument.verificationMethod?.[0].id === keyId) {
// Return the public key node for the main public key
publicKey = didDocument.verificationMethod[0];
} else {
// Return the public key node for the X25519 key-agreement key
publicKey = didDocument.keyAgreement[0];
}
return {
'@context': contextsBySuite.get(publicKey.type),
...publicKey
};
}
export function getDid({keyPair}) {
return keyPair.fingerprint ? `did:key:${keyPair.fingerprint()}` :
`did:key:${keyPair.publicKeyMultibase}`;
}
export function setKeyPairId({keyPair, did}) {
keyPair.id = keyPair.fingerprint ? `${did}#${keyPair.fingerprint()}` :
`${did}#${keyPair.publicKeyMultibase}`;
}
export async function getKeyAgreementKeyPair({
contexts, verificationPublicKey
}) {
// The KAK pair will use the source key's controller, but may generate
// its own .id
let keyAgreementKeyPair;
// note: a future x25519-multikey lib should handle all key types here
let is2019 = false;
if(verificationPublicKey.type === ED25519_KEY_2018_TYPE) {
is2019 = true;
contexts.push(X25519_2019_CONTEXT_URL);
// convert to `ED25519_KEY_2020_TYPE` for conversion below
verificationPublicKey = await Ed25519Multikey.from(verificationPublicKey);
verificationPublicKey.type = ED25519_KEY_2020_TYPE;
} else if(verificationPublicKey.type === ED25519_KEY_2020_TYPE) {
contexts.push(X25519_2020_CONTEXT_URL);
}
switch(verificationPublicKey.type) {
case ED25519_KEY_2020_TYPE: {
keyAgreementKeyPair = X25519KeyAgreementKey2020
.fromEd25519VerificationKey2020({keyPair: verificationPublicKey});
break;
}
case MULTIKEY_TYPE: {
// FIXME: Add keyAgreementKeyPair interface for Multikey.
break;
}
default: {
throw new Error(
`Cannot derive key agreement key from verification key type
"${verificationPublicKey.type}".`);
}
}
if(is2019) {
// modify 2020 x25519 key pair for 2019 legacy use...
// update `type` and add `publicKeyBase58`
keyAgreementKeyPair.type = X25519_2019_TYPE;
const {publicKeyMultibase} = keyAgreementKeyPair;
const multikey = base58btc.decode(publicKeyMultibase.slice(1));
keyAgreementKeyPair.publicKeyBase58 = base58btc.encode(multikey.slice(2));
// update `export` to output 2019 legacy version
const previousExport = keyAgreementKeyPair.export;
keyAgreementKeyPair.export = (...args) => {
const exported = previousExport.apply(keyAgreementKeyPair, args);
if(exported['@context']) {
exported['@context'] = X25519_2019_CONTEXT_URL;
}
delete exported.publicKeyMultibase;
exported.publicKeyBase58 = keyAgreementKeyPair.publicKeyBase58;
return exported;
};
}
return {keyAgreementKeyPair};
}
export function getMultibaseMultikeyHeader({value}) {
if(!value) {
throw new TypeError('"publicKeyMultibase" must be a string.');
}
return value.slice(0, 4);
}
export function addKeyAgreementKeyContext({contexts, keyAgreementKeyPair}) {
const {type} = keyAgreementKeyPair;
switch(type) {
case X25519_2019_TYPE: {
if(!contexts.includes(X25519_2019_CONTEXT_URL)) {
contexts.push(X25519_2019_CONTEXT_URL);
}
break;
}
case X25519_2020_TYPE: {
if(!contexts.includes(X25519_2020_CONTEXT_URL)) {
contexts.push(X25519_2020_CONTEXT_URL);
}
break;
}
default: {
throw new Error(`Unsupported key agreement key type, "${type}".`);
}
}
}
export async function getKeyPair({
fromMultibase, publicKeyMultibase, publicKeyDescription
} = {}) {
let keyPair;
if(fromMultibase && publicKeyMultibase) {
keyPair = await fromMultibase({publicKeyMultibase});
} else {
keyPair = publicKeyDescription;
}
const {type} = keyPair;
let keyAgreementKeyPair;
if(type === X25519_2020_TYPE || type === X25519_2019_TYPE) {
keyAgreementKeyPair = keyPair;
keyPair = null;
}
return {keyPair, keyAgreementKeyPair};
}