From e63bf0f7bc7912572ee6ef2c1cbb92b5ab645940 Mon Sep 17 00:00:00 2001 From: achingbrain Date: Thu, 23 Nov 2023 17:51:42 +0000 Subject: [PATCH 1/2] fix: use node.js crypto for x25519 keys MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Using node crypto to do X25519 key operations instead of `@noble/curves` yields a nice little performance bump which translates to slightly lower latencies when opening connections. Running the `benchmark.js` file: Before: ```console % node ./benchmark.js Initializing handshake benchmark Init complete, running benchmark handshake x 124 ops/sec ±0.47% (84 runs sampled) ``` After: ```console % node ./benchmark.js Initializing handshake benchmark Init complete, running benchmark handshake x 314 ops/sec ±0.99% (87 runs sampled) ``` --- package.json | 1 - src/crypto/index.ts | 66 ++++++++++++++++++++++ src/encoder.ts | 15 ++--- src/handshake-xx.ts | 7 ++- src/handshakes/abstract-handshake.ts | 19 ++++--- src/handshakes/xx.ts | 11 ++-- src/noise.ts | 3 +- src/nonce.ts | 3 +- src/proto/payload.ts | 38 +++++++------ test/xx-handshake.spec.ts | 84 +++++++++++++++++----------- 10 files changed, 165 insertions(+), 82 deletions(-) diff --git a/package.json b/package.json index a745433..f57d80e 100644 --- a/package.json +++ b/package.json @@ -55,7 +55,6 @@ "clean": "aegir clean", "dep-check": "aegir dep-check", "build": "aegir build", - "prebuild": "mkdirp dist/src && cp -R src/proto dist/src", "lint": "aegir lint", "lint:fix": "aegir lint --fix", "test": "aegir test", diff --git a/src/crypto/index.ts b/src/crypto/index.ts index 3836510..64e1678 100644 --- a/src/crypto/index.ts +++ b/src/crypto/index.ts @@ -1,13 +1,17 @@ import crypto from 'node:crypto' import { newInstance, ChaCha20Poly1305 } from '@chainsafe/as-chacha20poly1305' import { digest } from '@chainsafe/as-sha256' +import { concat as uint8ArrayConcat } from 'uint8arrays/concat' import { isElectronMain } from 'wherearewe' import { pureJsCrypto } from './js.js' +import type { KeyPair } from '../@types/libp2p.js' import type { ICryptoInterface } from '../crypto.js' const ctx = newInstance() const asImpl = new ChaCha20Poly1305(ctx) const CHACHA_POLY1305 = 'chacha20-poly1305' +const PKCS8_PREFIX = Buffer.from([0x30, 0x2e, 0x02, 0x01, 0x00, 0x30, 0x05, 0x06, 0x03, 0x2b, 0x65, 0x6e, 0x04, 0x22, 0x04, 0x20]) +const X25519_PREFIX = Buffer.from([0x30, 0x2a, 0x30, 0x05, 0x06, 0x03, 0x2b, 0x65, 0x6e, 0x03, 0x21, 0x00]) const nodeCrypto: Pick = { hashSHA256 (data) { return crypto.createHash('sha256').update(data).digest() @@ -76,6 +80,68 @@ export const defaultCrypto: ICryptoInterface = { return asCrypto.chaCha20Poly1305Decrypt(ciphertext, nonce, ad, k, dst) } return nodeCrypto.chaCha20Poly1305Decrypt(ciphertext, nonce, ad, k, dst) + }, + generateX25519KeyPair (): KeyPair { + const { publicKey, privateKey } = crypto.generateKeyPairSync('x25519', { + publicKeyEncoding: { + type: 'spki', + format: 'der' + }, + privateKeyEncoding: { + type: 'pkcs8', + format: 'der' + } + }) + + return { + publicKey: publicKey.subarray(X25519_PREFIX.length), + privateKey: privateKey.subarray(PKCS8_PREFIX.length) + } + }, + generateX25519KeyPairFromSeed (seed: Uint8Array): KeyPair { + const privateKey = crypto.createPrivateKey({ + key: Buffer.concat([ + PKCS8_PREFIX, + seed + ], PKCS8_PREFIX.byteLength + seed.byteLength), + type: 'pkcs8', + format: 'der' + }) + + const publicKey = crypto.createPublicKey(privateKey) + .export({ + type: 'spki', + format: 'der' + }).subarray(X25519_PREFIX.length) + + return { + publicKey, + privateKey: seed + } + }, + generateX25519SharedKey (privateKey: Uint8Array, publicKey: Uint8Array): Uint8Array { + publicKey = uint8ArrayConcat([ + X25519_PREFIX, + publicKey + ], X25519_PREFIX.byteLength + publicKey.byteLength) + + privateKey = uint8ArrayConcat([ + PKCS8_PREFIX, + privateKey + ], PKCS8_PREFIX.byteLength + privateKey.byteLength) + + return crypto.diffieHellman({ + publicKey: crypto.createPublicKey({ + key: Buffer.from(publicKey, publicKey.byteOffset, publicKey.byteLength), + type: 'spki', + format: 'der' + }), + privateKey: crypto.createPrivateKey({ + key: Buffer.from(privateKey, privateKey.byteOffset, privateKey.byteLength), + type: 'pkcs8', + format: 'der' + }) + }) } } diff --git a/src/encoder.ts b/src/encoder.ts index f1f963f..c149b4c 100644 --- a/src/encoder.ts +++ b/src/encoder.ts @@ -1,19 +1,12 @@ +import { alloc as uint8ArrayAlloc, allocUnsafe as uint8ArrayAllocUnsafe } from 'uint8arrays/alloc' import { concat as uint8ArrayConcat } from 'uint8arrays/concat' import type { bytes } from './@types/basic.js' import type { MessageBuffer } from './@types/handshake.js' import type { LengthDecoderFunction } from 'it-length-prefixed' import type { Uint8ArrayList } from 'uint8arraylist' -const allocUnsafe = (len: number): Uint8Array => { - if (globalThis.Buffer) { - return globalThis.Buffer.allocUnsafe(len) - } - - return new Uint8Array(len) -} - export const uint16BEEncode = (value: number): Uint8Array => { - const target = allocUnsafe(2) + const target = uint8ArrayAllocUnsafe(2) new DataView(target.buffer, target.byteOffset, target.byteLength).setUint16(0, value, false) return target } @@ -52,7 +45,7 @@ export function decode0 (input: bytes): MessageBuffer { return { ne: input.subarray(0, 32), ciphertext: input.subarray(32, input.length), - ns: new Uint8Array(0) + ns: uint8ArrayAlloc(0) } } @@ -74,7 +67,7 @@ export function decode2 (input: bytes): MessageBuffer { } return { - ne: new Uint8Array(0), + ne: uint8ArrayAlloc(0), ns: input.subarray(0, 48), ciphertext: input.subarray(48, input.length) } diff --git a/src/handshake-xx.ts b/src/handshake-xx.ts index 92a6cf6..3b547dc 100644 --- a/src/handshake-xx.ts +++ b/src/handshake-xx.ts @@ -1,4 +1,5 @@ import { InvalidCryptoExchangeError, UnexpectedPeerError } from '@libp2p/interface/errors' +import { alloc as uint8ArrayAlloc } from 'uint8arrays/alloc' import { decode0, decode1, decode2, encode0, encode1, encode2 } from './encoder.js' import { XX } from './handshakes/xx.js' import { @@ -63,7 +64,7 @@ export class XXHandshake implements IHandshake { logLocalStaticKeys(this.session.hs.s) if (this.isInitiator) { logger.trace('Stage 0 - Initiator starting to send first message.') - const messageBuffer = this.xx.sendMessage(this.session, new Uint8Array(0)) + const messageBuffer = this.xx.sendMessage(this.session, uint8ArrayAlloc(0)) await this.connection.write(encode0(messageBuffer)) logger.trace('Stage 0 - Initiator finished sending first message.') logLocalEphemeralKeys(this.session.hs.e) @@ -144,13 +145,13 @@ export class XXHandshake implements IHandshake { public encrypt (plaintext: Uint8Array, session: NoiseSession): bytes { const cs = this.getCS(session) - return this.xx.encryptWithAd(cs, new Uint8Array(0), plaintext) + return this.xx.encryptWithAd(cs, uint8ArrayAlloc(0), plaintext) } public decrypt (ciphertext: Uint8Array, session: NoiseSession, dst?: Uint8Array): { plaintext: bytes, valid: boolean } { const cs = this.getCS(session, false) - return this.xx.decryptWithAd(cs, new Uint8Array(0), ciphertext, dst) + return this.xx.decryptWithAd(cs, uint8ArrayAlloc(0), ciphertext, dst) } public getRemoteStaticKey (): bytes { diff --git a/src/handshakes/abstract-handshake.ts b/src/handshakes/abstract-handshake.ts index 714f814..308d298 100644 --- a/src/handshakes/abstract-handshake.ts +++ b/src/handshakes/abstract-handshake.ts @@ -1,4 +1,5 @@ import { fromString as uint8ArrayFromString } from 'uint8arrays' +import { alloc as uint8ArrayAlloc } from 'uint8arrays/alloc' import { concat as uint8ArrayConcat } from 'uint8arrays/concat' import { equals as uint8ArrayEquals } from 'uint8arrays/equals' import { logger } from '../logger.js' @@ -44,7 +45,7 @@ export abstract class AbstractHandshake { } protected createEmptyKey (): bytes32 { - return new Uint8Array(32) + return uint8ArrayAlloc(32) } protected isEmptyKey (k: bytes32): boolean { @@ -82,7 +83,7 @@ export abstract class AbstractHandshake { } } else { return { - plaintext: new Uint8Array(0), + plaintext: uint8ArrayAlloc(0), valid: false } } @@ -112,7 +113,7 @@ export abstract class AbstractHandshake { } catch (e) { const err = e as Error logger.error(err) - return new Uint8Array(32) + return uint8ArrayAlloc(32) } } @@ -150,16 +151,16 @@ export abstract class AbstractHandshake { protected hashProtocolName (protocolName: Uint8Array): bytes32 { if (protocolName.length <= 32) { - const h = new Uint8Array(32) + const h = uint8ArrayAlloc(32) h.set(protocolName) return h } else { - return this.getHash(protocolName, new Uint8Array(0)) + return this.getHash(protocolName, uint8ArrayAlloc(0)) } } protected split (ss: SymmetricState): SplitState { - const [tempk1, tempk2] = this.crypto.getHKDF(ss.ck, new Uint8Array(0)) + const [tempk1, tempk2] = this.crypto.getHKDF(ss.ck, uint8ArrayAlloc(0)) const cs1 = this.initializeKey(tempk1) const cs2 = this.initializeKey(tempk2) @@ -167,14 +168,14 @@ export abstract class AbstractHandshake { } protected writeMessageRegular (cs: CipherState, payload: bytes): MessageBuffer { - const ciphertext = this.encryptWithAd(cs, new Uint8Array(0), payload) + const ciphertext = this.encryptWithAd(cs, uint8ArrayAlloc(0), payload) const ne = this.createEmptyKey() - const ns = new Uint8Array(0) + const ns = uint8ArrayAlloc(0) return { ne, ns, ciphertext } } protected readMessageRegular (cs: CipherState, message: MessageBuffer): DecryptedResult { - return this.decryptWithAd(cs, new Uint8Array(0), message.ciphertext) + return this.decryptWithAd(cs, uint8ArrayAlloc(0), message.ciphertext) } } diff --git a/src/handshakes/xx.ts b/src/handshakes/xx.ts index 44d26fa..6107738 100644 --- a/src/handshakes/xx.ts +++ b/src/handshakes/xx.ts @@ -1,3 +1,4 @@ +import { alloc as uint8ArrayAlloc } from 'uint8arrays/alloc' import { isValidPublicKey } from '../utils.js' import { AbstractHandshake, type DecryptedResult } from './abstract-handshake.js' import type { bytes32, bytes } from '../@types/basic.js' @@ -9,7 +10,7 @@ export class XX extends AbstractHandshake { const name = 'Noise_XX_25519_ChaChaPoly_SHA256' const ss = this.initializeSymmetric(name) this.mixHash(ss, prologue) - const re = new Uint8Array(32) + const re = uint8ArrayAlloc(32) return { ss, s, rs, psk, re } } @@ -18,13 +19,13 @@ export class XX extends AbstractHandshake { const name = 'Noise_XX_25519_ChaChaPoly_SHA256' const ss = this.initializeSymmetric(name) this.mixHash(ss, prologue) - const re = new Uint8Array(32) + const re = uint8ArrayAlloc(32) return { ss, s, rs, psk, re } } private writeMessageA (hs: HandshakeState, payload: bytes, e?: KeyPair): MessageBuffer { - const ns = new Uint8Array(0) + const ns = uint8ArrayAlloc(0) if (e !== undefined) { hs.e = e @@ -113,7 +114,7 @@ export class XX extends AbstractHandshake { public initSession (initiator: boolean, prologue: bytes32, s: KeyPair): NoiseSession { const psk = this.createEmptyKey() - const rs = new Uint8Array(32) // no static key yet + const rs = uint8ArrayAlloc(32) // no static key yet let hs if (initiator) { @@ -164,7 +165,7 @@ export class XX extends AbstractHandshake { } public recvMessage (session: NoiseSession, message: MessageBuffer): DecryptedResult { - let plaintext: bytes = new Uint8Array(0) + let plaintext: bytes = uint8ArrayAlloc(0) let valid = false if (session.mc === 0) { ({ plaintext, valid } = this.readMessageA(session.hs, message)) diff --git a/src/noise.ts b/src/noise.ts index 9a57813..3b52bd2 100644 --- a/src/noise.ts +++ b/src/noise.ts @@ -2,6 +2,7 @@ import { decode } from 'it-length-prefixed' import { lpStream, type LengthPrefixedStream } from 'it-length-prefixed-stream' import { duplexPair } from 'it-pair/duplex' import { pipe } from 'it-pipe' +import { alloc as uint8ArrayAlloc } from 'uint8arrays/alloc' import { NOISE_MSG_MAX_LENGTH_BYTES } from './constants.js' import { defaultCrypto } from './crypto/index.js' import { decryptStream, encryptStream } from './crypto/streaming.js' @@ -59,7 +60,7 @@ export class Noise implements INoiseConnection { } else { this.staticKeys = this.crypto.generateX25519KeyPair() } - this.prologue = prologueBytes ?? new Uint8Array(0) + this.prologue = prologueBytes ?? uint8ArrayAlloc(0) } /** diff --git a/src/nonce.ts b/src/nonce.ts index fab31ac..e19183d 100644 --- a/src/nonce.ts +++ b/src/nonce.ts @@ -1,3 +1,4 @@ +import { alloc as uint8ArrayAlloc } from 'uint8arrays/alloc' import type { bytes, uint64 } from './@types/basic.js' export const MIN_NONCE = 0 @@ -22,7 +23,7 @@ export class Nonce { constructor (n = MIN_NONCE) { this.n = n - this.bytes = new Uint8Array(12) + this.bytes = uint8ArrayAlloc(12) this.view = new DataView(this.bytes.buffer, this.bytes.byteOffset, this.bytes.byteLength) this.view.setUint32(4, n, true) } diff --git a/src/proto/payload.ts b/src/proto/payload.ts index 50acd62..5f8d510 100644 --- a/src/proto/payload.ts +++ b/src/proto/payload.ts @@ -4,8 +4,8 @@ /* eslint-disable @typescript-eslint/no-unnecessary-boolean-literal-compare */ /* eslint-disable @typescript-eslint/no-empty-interface */ -import { encodeMessage, decodeMessage, message } from 'protons-runtime' -import type { Codec } from 'protons-runtime' +import { type Codec, decodeMessage, encodeMessage, message } from 'protons-runtime' +import { alloc as uint8ArrayAlloc } from 'uint8arrays/alloc' import type { Uint8ArrayList } from 'uint8arraylist' export interface NoiseExtensions { @@ -43,12 +43,14 @@ export namespace NoiseExtensions { const tag = reader.uint32() switch (tag >>> 3) { - case 1: + case 1: { obj.webtransportCerthashes.push(reader.bytes()) break - default: + } + default: { reader.skipType(tag & 7) break + } } } @@ -84,21 +86,19 @@ export namespace NoiseHandshakePayload { w.fork() } - if (opts.writeDefaults === true || (obj.identityKey != null && obj.identityKey.byteLength > 0)) { + if ((obj.identityKey != null && obj.identityKey.byteLength > 0)) { w.uint32(10) - w.bytes(obj.identityKey ?? new Uint8Array(0)) + w.bytes(obj.identityKey) } - if (opts.writeDefaults === true || (obj.identitySig != null && obj.identitySig.byteLength > 0)) { + if ((obj.identitySig != null && obj.identitySig.byteLength > 0)) { w.uint32(18) - w.bytes(obj.identitySig ?? new Uint8Array(0)) + w.bytes(obj.identitySig) } if (obj.extensions != null) { w.uint32(34) - NoiseExtensions.codec().encode(obj.extensions, w, { - writeDefaults: false - }) + NoiseExtensions.codec().encode(obj.extensions, w) } if (opts.lengthDelimited !== false) { @@ -106,8 +106,8 @@ export namespace NoiseHandshakePayload { } }, (reader, length) => { const obj: any = { - identityKey: new Uint8Array(0), - identitySig: new Uint8Array(0) + identityKey: uint8ArrayAlloc(0), + identitySig: uint8ArrayAlloc(0) } const end = length == null ? reader.len : reader.pos + length @@ -116,18 +116,22 @@ export namespace NoiseHandshakePayload { const tag = reader.uint32() switch (tag >>> 3) { - case 1: + case 1: { obj.identityKey = reader.bytes() break - case 2: + } + case 2: { obj.identitySig = reader.bytes() break - case 4: + } + case 4: { obj.extensions = NoiseExtensions.codec().decode(reader, reader.uint32()) break - default: + } + default: { reader.skipType(tag & 7) break + } } } diff --git a/test/xx-handshake.spec.ts b/test/xx-handshake.spec.ts index 7223e76..ef2c000 100644 --- a/test/xx-handshake.spec.ts +++ b/test/xx-handshake.spec.ts @@ -3,7 +3,7 @@ import { assert, expect } from 'aegir/chai' import { lpStream } from 'it-length-prefixed-stream' import { duplexPair } from 'it-pair/duplex' import { equals as uint8ArrayEquals } from 'uint8arrays/equals' -import { pureJsCrypto } from '../src/crypto/js.js' +import { defaultCrypto } from '../src/crypto/index.js' import { XXHandshake } from '../src/handshake-xx.js' import { getPayload } from '../src/utils.js' import { createPeerIdsFromFixtures } from './fixtures/peer.js' @@ -23,25 +23,31 @@ describe('XX Handshake', () => { const connectionTo = lpStream(duplex[1]) const prologue = Buffer.alloc(0) - const staticKeysInitiator = pureJsCrypto.generateX25519KeyPair() - const staticKeysResponder = pureJsCrypto.generateX25519KeyPair() + const staticKeysInitiator = defaultCrypto.generateX25519KeyPair() + const staticKeysResponder = defaultCrypto.generateX25519KeyPair() const initPayload = await getPayload(peerA, staticKeysInitiator.publicKey) - const handshakeInitator = new XXHandshake(true, initPayload, prologue, pureJsCrypto, staticKeysInitiator, connectionFrom, peerB) + const handshakeInitiator = new XXHandshake(true, initPayload, prologue, defaultCrypto, staticKeysInitiator, connectionFrom, peerB) const respPayload = await getPayload(peerB, staticKeysResponder.publicKey) - const handshakeResponder = new XXHandshake(false, respPayload, prologue, pureJsCrypto, staticKeysResponder, connectionTo, peerA) + const handshakeResponder = new XXHandshake(false, respPayload, prologue, defaultCrypto, staticKeysResponder, connectionTo, peerA) - await handshakeInitator.propose() - await handshakeResponder.propose() + await Promise.all([ + handshakeInitiator.propose(), + handshakeResponder.propose() + ]) - await handshakeResponder.exchange() - await handshakeInitator.exchange() + await Promise.all([ + handshakeResponder.exchange(), + handshakeInitiator.exchange() + ]) - await handshakeInitator.finish() - await handshakeResponder.finish() + await Promise.all([ + handshakeInitiator.finish(), + handshakeResponder.finish() + ]) - const sessionInitator = handshakeInitator.session + const sessionInitator = handshakeInitiator.session const sessionResponder = handshakeResponder.session // Test shared key @@ -53,7 +59,7 @@ describe('XX Handshake', () => { } // Test encryption and decryption - const encrypted = handshakeInitator.encrypt(Buffer.from('encryptthis'), handshakeInitator.session) + const encrypted = handshakeInitiator.encrypt(Buffer.from('encryptthis'), handshakeInitiator.session) const { plaintext: decrypted, valid } = handshakeResponder.decrypt(encrypted, handshakeResponder.session) assert(uint8ArrayEquals(decrypted, Buffer.from('encryptthis'))) assert(valid) @@ -70,20 +76,24 @@ describe('XX Handshake', () => { const connectionTo = lpStream(duplex[1]) const prologue = Buffer.alloc(0) - const staticKeysInitiator = pureJsCrypto.generateX25519KeyPair() - const staticKeysResponder = pureJsCrypto.generateX25519KeyPair() + const staticKeysInitiator = defaultCrypto.generateX25519KeyPair() + const staticKeysResponder = defaultCrypto.generateX25519KeyPair() const initPayload = await getPayload(peerA, staticKeysInitiator.publicKey) - const handshakeInitator = new XXHandshake(true, initPayload, prologue, pureJsCrypto, staticKeysInitiator, connectionFrom, fakePeer) + const handshakeInitiator = new XXHandshake(true, initPayload, prologue, defaultCrypto, staticKeysInitiator, connectionFrom, fakePeer) const respPayload = await getPayload(peerB, staticKeysResponder.publicKey) - const handshakeResponder = new XXHandshake(false, respPayload, prologue, pureJsCrypto, staticKeysResponder, connectionTo, peerA) + const handshakeResponder = new XXHandshake(false, respPayload, prologue, defaultCrypto, staticKeysResponder, connectionTo, peerA) - await handshakeInitator.propose() - await handshakeResponder.propose() + await Promise.all([ + handshakeInitiator.propose(), + handshakeResponder.propose() + ]) - await handshakeResponder.exchange() - await handshakeInitator.exchange() + await Promise.all([ + handshakeResponder.exchange(), + handshakeInitiator.exchange() + ]) assert(false, 'Should throw exception') } catch (e) { @@ -99,23 +109,29 @@ describe('XX Handshake', () => { const connectionTo = lpStream(duplex[1]) const prologue = Buffer.alloc(0) - const staticKeysInitiator = pureJsCrypto.generateX25519KeyPair() - const staticKeysResponder = pureJsCrypto.generateX25519KeyPair() + const staticKeysInitiator = defaultCrypto.generateX25519KeyPair() + const staticKeysResponder = defaultCrypto.generateX25519KeyPair() const initPayload = await getPayload(peerA, staticKeysInitiator.publicKey) - const handshakeInitator = new XXHandshake(true, initPayload, prologue, pureJsCrypto, staticKeysInitiator, connectionFrom, peerB) + const handshakeInitiator = new XXHandshake(true, initPayload, prologue, defaultCrypto, staticKeysInitiator, connectionFrom, peerB) const respPayload = await getPayload(peerB, staticKeysResponder.publicKey) - const handshakeResponder = new XXHandshake(false, respPayload, prologue, pureJsCrypto, staticKeysResponder, connectionTo, fakePeer) - - await handshakeInitator.propose() - await handshakeResponder.propose() - - await handshakeResponder.exchange() - await handshakeInitator.exchange() - - await handshakeInitator.finish() - await handshakeResponder.finish() + const handshakeResponder = new XXHandshake(false, respPayload, prologue, defaultCrypto, staticKeysResponder, connectionTo, fakePeer) + + await Promise.all([ + handshakeInitiator.propose(), + handshakeResponder.propose() + ]) + + await Promise.all([ + handshakeResponder.exchange(), + handshakeInitiator.exchange() + ]) + + await Promise.all([ + handshakeInitiator.finish(), + handshakeResponder.finish() + ]) assert(false, 'Should throw exception') } catch (e) { From 21a47189fa85af7e9bc1d55c1066727883bb0993 Mon Sep 17 00:00:00 2001 From: achingbrain Date: Fri, 24 Nov 2023 09:49:21 +0000 Subject: [PATCH 2/2] chore: prefer Buffer in node --- src/crypto/index.ts | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/crypto/index.ts b/src/crypto/index.ts index 64e1678..946799c 100644 --- a/src/crypto/index.ts +++ b/src/crypto/index.ts @@ -1,7 +1,6 @@ import crypto from 'node:crypto' import { newInstance, ChaCha20Poly1305 } from '@chainsafe/as-chacha20poly1305' import { digest } from '@chainsafe/as-sha256' -import { concat as uint8ArrayConcat } from 'uint8arrays/concat' import { isElectronMain } from 'wherearewe' import { pureJsCrypto } from './js.js' import type { KeyPair } from '../@types/libp2p.js' @@ -120,12 +119,12 @@ export const defaultCrypto: ICryptoInterface = { } }, generateX25519SharedKey (privateKey: Uint8Array, publicKey: Uint8Array): Uint8Array { - publicKey = uint8ArrayConcat([ + publicKey = Buffer.concat([ X25519_PREFIX, publicKey ], X25519_PREFIX.byteLength + publicKey.byteLength) - privateKey = uint8ArrayConcat([ + privateKey = Buffer.concat([ PKCS8_PREFIX, privateKey ], PKCS8_PREFIX.byteLength + privateKey.byteLength)