From 874f8201c157a76a5fd9d3828c1f44358bce2f48 Mon Sep 17 00:00:00 2001 From: Alex Potsides Date: Wed, 8 Feb 2023 11:29:37 +0100 Subject: [PATCH] fix: derive ed25519 public key from private key using node crypto (#300) Create a private key object from the raw `Ed25519` private key and export it as a JWK to obtain the public key. Fixes #295 --- src/keys/ed25519.ts | 23 +++++++++++++++++++---- test/keys/ed25519.spec.ts | 9 +++++++++ 2 files changed, 28 insertions(+), 4 deletions(-) diff --git a/src/keys/ed25519.ts b/src/keys/ed25519.ts index 5232b75ab0..f643e3d7c2 100644 --- a/src/keys/ed25519.ts +++ b/src/keys/ed25519.ts @@ -13,10 +13,25 @@ const SIGNATURE_BYTE_LENGTH = 64 export { PUBLIC_KEY_BYTE_LENGTH as publicKeyLength } export { PRIVATE_KEY_BYTE_LENGTH as privateKeyLength } -function derivePublicKey (privateKey: Uint8Array) { - const hash = crypto.createHash('sha512') - hash.update(privateKey) - return hash.digest().subarray(32) +function derivePublicKey (privateKey: Uint8Array): Uint8Array { + const keyObject = crypto.createPrivateKey({ + format: 'jwk', + key: { + crv: 'Ed25519', + x: '', + d: uint8arrayToString(privateKey, 'base64url'), + kty: 'OKP' + } + }) + const jwk = keyObject.export({ + format: 'jwk' + }) + + if (jwk.x == null || jwk.x === '') { + throw new Error('Could not export JWK public key') + } + + return uint8arrayFromString(jwk.x, 'base64url') } export async function generateKey () { diff --git a/test/keys/ed25519.spec.ts b/test/keys/ed25519.spec.ts index 7b9579a7c4..8e8499e1f8 100644 --- a/test/keys/ed25519.spec.ts +++ b/test/keys/ed25519.spec.ts @@ -148,6 +148,15 @@ describe('ed25519', function () { expect(valid).to.eql(true) }) + it('sign and verify from seed', async () => { + const seed = new Uint8Array(32).fill(1) + const seededkey = await crypto.keys.generateKeyPairFromSeed('Ed25519', seed) + const data = uint8ArrayFromString('hello world') + const sig = await seededkey.sign(data) + const valid = await seededkey.public.verify(data, sig) + expect(valid).to.eql(true) + }) + it('fails to verify for different data', async () => { const data = uint8ArrayFromString('hello world') const sig = await key.sign(data)