Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 18 additions & 17 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,11 @@ jobs:
timeout-minutes: 10
strategy:
matrix:
node-version: [20.x]
node-version: [24.x]
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v3
uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node-version }}
- run: npm install
Expand All @@ -24,11 +24,11 @@ jobs:
timeout-minutes: 10
strategy:
matrix:
node-version: [18.x, 20.x]
node-version: [20.x, 22.x, 24.x]
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v3
uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node-version }}
- run: npm install
Expand All @@ -40,11 +40,11 @@ jobs:
timeout-minutes: 10
strategy:
matrix:
node-version: [20.x]
node-version: [24.x]
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v3
uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node-version }}
- run: npm install
Expand All @@ -56,18 +56,19 @@ jobs:
timeout-minutes: 10
strategy:
matrix:
node-version: [20.x]
node-version: [24.x]
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v3
uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node-version }}
- run: npm install
- name: Generate coverage report
run: npm run coverage-ci
# - name: Upload coverage to Codecov
# uses: codecov/codecov-action@v2
# with:
# file: ./coverage/lcov.info
# fail_ci_if_error: true
- name: Upload coverage to Codecov
uses: codecov/codecov-action@v4
with:
file: ./coverage/lcov.info
fail_ci_if_error: true
token: ${{ secrets.CODECOV_TOKEN }}
95 changes: 68 additions & 27 deletions lib/helpers.js
Original file line number Diff line number Diff line change
@@ -1,25 +1,37 @@
/*!
* Copyright (c) 2023 Digital Bazaar, Inc. All rights reserved.
* Copyright (c) 2023-2025 Digital Bazaar, Inc. All rights reserved.
*/
import {
X25519KeyAgreementKey2019
} from '@digitalbazaar/x25519-key-agreement-key-2019';
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([
['Ed25519VerificationKey2020', ED25519_KEY_2020_CONTEXT_URL],
['Ed25519VerificationKey2018', ED25519_KEY_2018_CONTEXT_URL],
['Multikey', MULTIKEY_CONTEXT_V1_URL],
[X25519KeyAgreementKey2020.suite, X25519KeyAgreementKey2020.SUITE_CONTEXT],
[X25519KeyAgreementKey2019.suite, X25519KeyAgreementKey2019.SUITE_CONTEXT]
[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]
]);

/**
Expand Down Expand Up @@ -61,25 +73,32 @@ export function setKeyPairId({keyPair, did}) {
`${did}#${keyPair.publicKeyMultibase}`;
}

export function getKeyAgreementKeyPair({contexts, verificationPublicKey}) {
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 'Ed25519VerificationKey2018': {
keyAgreementKeyPair = X25519KeyAgreementKey2019
.fromEd25519VerificationKey2018({keyPair: verificationPublicKey});
contexts.push(X25519KeyAgreementKey2019.SUITE_CONTEXT);
break;
}
case 'Ed25519VerificationKey2020': {
case ED25519_KEY_2020_TYPE: {
keyAgreementKeyPair = X25519KeyAgreementKey2020
.fromEd25519VerificationKey2020({keyPair: verificationPublicKey});
contexts.push(X25519KeyAgreementKey2020.SUITE_CONTEXT);
break;
}
case 'Multikey': {
case MULTIKEY_TYPE: {
// FIXME: Add keyAgreementKeyPair interface for Multikey.
break;
}
Expand All @@ -89,6 +108,29 @@ export function getKeyAgreementKeyPair({contexts, verificationPublicKey}) {
"${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};
}

Expand All @@ -102,15 +144,15 @@ export function getMultibaseMultikeyHeader({value}) {
export function addKeyAgreementKeyContext({contexts, keyAgreementKeyPair}) {
const {type} = keyAgreementKeyPair;
switch(type) {
case 'X25519KeyAgreementKey2019': {
if(!contexts.includes(X25519KeyAgreementKey2019.SUITE_CONTEXT)) {
contexts.push(X25519KeyAgreementKey2019.SUITE_CONTEXT);
case X25519_2019_TYPE: {
if(!contexts.includes(X25519_2019_CONTEXT_URL)) {
contexts.push(X25519_2019_CONTEXT_URL);
}
break;
}
case 'X25519KeyAgreementKey2020': {
if(!contexts.includes(X25519KeyAgreementKey2020.SUITE_CONTEXT)) {
contexts.push(X25519KeyAgreementKey2020.SUITE_CONTEXT);
case X25519_2020_TYPE: {
if(!contexts.includes(X25519_2020_CONTEXT_URL)) {
contexts.push(X25519_2020_CONTEXT_URL);
}
break;
}
Expand All @@ -131,8 +173,7 @@ export async function getKeyPair({
}
const {type} = keyPair;
let keyAgreementKeyPair;
if(type === 'X25519KeyAgreementKey2020' ||
type === 'X25519KeyAgreementKey2019') {
if(type === X25519_2020_TYPE || type === X25519_2019_TYPE) {
keyAgreementKeyPair = keyPair;
keyPair = null;
}
Expand Down
11 changes: 6 additions & 5 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,21 +24,22 @@
],
"dependencies": {
"@digitalbazaar/did-io": "^2.0.0",
"@digitalbazaar/x25519-key-agreement-key-2019": "^6.0.0",
"@digitalbazaar/ed25519-multikey": "^1.3.1",
"@digitalbazaar/x25519-key-agreement-key-2020": "^3.0.0"
},
"devDependencies": {
"@digitalbazaar/bls12-381-multikey": "^1.1.1",
"@digitalbazaar/bls12-381-multikey": "^2.1.0",
"@digitalbazaar/ecdsa-multikey": "^1.1.1",
"@digitalbazaar/ed25519-verification-key-2018": "^4.0.0",
"@digitalbazaar/ed25519-verification-key-2020": "^4.0.0",
"@digitalbazaar/x25519-key-agreement-key-2019": "^6.0.0",
"c8": "^7.11.3",
"chai": "^4.3.6",
"cross-env": "^7.0.3",
"eslint": "^8.37.0",
"eslint-config-digitalbazaar": "^4.2.0",
"eslint-plugin-jsdoc": "^40.1.1",
"eslint-plugin-unicorn": "^46.0.0",
"eslint-config-digitalbazaar": "^5.2.0",
"eslint-plugin-jsdoc": "^50.8.0",
"eslint-plugin-unicorn": "^56.0.1",
"karma": "^6.3.20",
"karma-babel-preprocessor": "^8.0.2",
"karma-chai": "^0.1.0",
Expand Down