diff --git a/benchmarks/benchmark.js b/benchmarks/benchmark.js index d45c6d9..ed9c8d3 100644 --- a/benchmarks/benchmark.js +++ b/benchmarks/benchmark.js @@ -1,19 +1,19 @@ /* eslint-disable */ -import { Noise } from '../dist/src/index.js' +import { noise } from '../dist/src/index.js' import benchmark from 'benchmark' import { duplexPair } from 'it-pair/duplex' import { createFromJSON } from '@libp2p/peer-id-factory' const bench = async function () { console.log('Initializing handshake benchmark') - const initiator = new Noise() + const initiator = noise()() const initiatorPeer = await createFromJSON({ id: '12D3KooWH45PiqBjfnEfDfCD6TqJrpqTBJvQDwGHvjGpaWwms46D', privKey: 'CAESYBtKXrMwawAARmLScynQUuSwi/gGSkwqDPxi15N3dqDHa4T4iWupkMe5oYGwGH3Hyfvd/QcgSTqg71oYZJadJ6prhPiJa6mQx7mhgbAYfcfJ+939ByBJOqDvWhhklp0nqg==', pubKey: 'CAESIGuE+IlrqZDHuaGBsBh9x8n73f0HIEk6oO9aGGSWnSeq' }) - const responder = new Noise() + const responder = noise()() const responderPeer = await createFromJSON({ id: '12D3KooWP63uzL78BRMpkQ7augMdNi1h3VBrVWZucKjyhzGVaSi1', privKey: 'CAESYPxO3SHyfc2578hDmfkGGBY255JjiLuVavJWy+9ivlpsxSyVKf36ipyRGL6szGzHuFs5ceEuuGVrPMg/rW2Ch1bFLJUp/fqKnJEYvqzMbMe4Wzlx4S64ZWs8yD+tbYKHVg==', diff --git a/package.json b/package.json index cb822c5..86f35f7 100644 --- a/package.json +++ b/package.json @@ -76,8 +76,7 @@ "@libp2p/logger": "^2.0.5", "@libp2p/peer-id": "^2.0.0", "@stablelib/chacha20poly1305": "^1.0.1", - "@stablelib/hkdf": "^1.0.1", - "@stablelib/sha256": "^1.0.1", + "@noble/hashes": "^1.3.0", "@stablelib/x25519": "^1.0.3", "it-length-prefixed": "^9.0.1", "it-pair": "^2.0.2", diff --git a/src/crypto/stablelib.ts b/src/crypto/js.ts similarity index 85% rename from src/crypto/stablelib.ts rename to src/crypto/js.ts index 13af52e..4bbcdee 100644 --- a/src/crypto/stablelib.ts +++ b/src/crypto/js.ts @@ -1,21 +1,19 @@ -import { HKDF } from '@stablelib/hkdf' import * as x25519 from '@stablelib/x25519' -import { SHA256, hash } from '@stablelib/sha256' +import { sha256 } from '@noble/hashes/sha256' +import { hkdf } from '@noble/hashes/hkdf' import { ChaCha20Poly1305 } from '@stablelib/chacha20poly1305' import type { bytes32, bytes } from '../@types/basic.js' import type { Hkdf } from '../@types/handshake.js' import type { KeyPair } from '../@types/libp2p.js' import type { ICryptoInterface } from '../crypto.js' -export const stablelib: ICryptoInterface = { +export const pureJsCrypto: ICryptoInterface = { hashSHA256 (data: Uint8Array): Uint8Array { - return hash(data) + return sha256(data) }, getHKDF (ck: bytes32, ikm: Uint8Array): Hkdf { - const hkdf = new HKDF(SHA256, ikm, ck) - const okmU8Array = hkdf.expand(96) - const okm = okmU8Array + const okm = hkdf(sha256, ikm, ck, undefined, 96) const k1 = okm.subarray(0, 32) const k2 = okm.subarray(32, 64) diff --git a/src/index.ts b/src/index.ts index 8276caa..ebb27b2 100644 --- a/src/index.ts +++ b/src/index.ts @@ -2,8 +2,8 @@ import type { ConnectionEncrypter } from '@libp2p/interface-connection-encrypter import { Noise } from './noise.js' import type { NoiseInit } from './noise.js' import type { NoiseExtensions } from './proto/payload.js' -export * from './crypto.js' -export * from './crypto/stablelib.js' +export type { ICryptoInterface } from './crypto.js' +export { pureJsCrypto } from './crypto/js.js' export function noise (init: NoiseInit = {}): () => ConnectionEncrypter { return () => new Noise(init) diff --git a/src/noise.ts b/src/noise.ts index 850107a..8a2c576 100644 --- a/src/noise.ts +++ b/src/noise.ts @@ -10,7 +10,7 @@ import type { IHandshake } from './@types/handshake-interface.js' import type { INoiseConnection, KeyPair } from './@types/libp2p.js' import { NOISE_MSG_MAX_LENGTH_BYTES } from './constants.js' import type { ICryptoInterface } from './crypto.js' -import { stablelib } from './crypto/stablelib.js' +import { pureJsCrypto } from './crypto/js.js' import { decryptStream, encryptStream } from './crypto/streaming.js' import { uint16BEDecode, uint16BEEncode } from './encoder.js' import { XXHandshake } from './handshake-xx.js' @@ -49,7 +49,7 @@ export class Noise implements INoiseConnection { constructor (init: NoiseInit = {}) { const { staticNoiseKey, extensions, crypto, prologueBytes, metrics } = init - this.crypto = crypto ?? stablelib + this.crypto = crypto ?? pureJsCrypto this.extensions = extensions this.metrics = metrics ? registerMetrics(metrics) : undefined diff --git a/test/handshakes/xx.spec.ts b/test/handshakes/xx.spec.ts index 7c0b3fa..4918d62 100644 --- a/test/handshakes/xx.spec.ts +++ b/test/handshakes/xx.spec.ts @@ -4,7 +4,7 @@ import { toString as uint8ArrayToString } from 'uint8arrays/to-string' import { equals as uint8ArrayEquals } from 'uint8arrays/equals' import type { KeyPair } from '../../src/@types/libp2p.js' import type { NoiseSession } from '../../src/@types/handshake.js' -import { stablelib } from '../../src/crypto/stablelib.js' +import { pureJsCrypto } from '../../src/crypto/js.js' import { XX } from '../../src/handshakes/xx.js' import { createHandshakePayload, getHandshakePayload } from '../../src/utils.js' import { generateEd25519Keys } from '../utils.js' @@ -14,9 +14,9 @@ describe('XX Handshake', () => { it('Test creating new XX session', async () => { try { - const xx = new XX(stablelib) + const xx = new XX(pureJsCrypto) - const kpInitiator: KeyPair = stablelib.generateX25519KeyPair() + const kpInitiator: KeyPair = pureJsCrypto.generateX25519KeyPair() xx.initSession(true, prologue, kpInitiator) } catch (e) { @@ -31,15 +31,15 @@ describe('XX Handshake', () => { const ck = Buffer.alloc(32) ckBytes.copy(ck) - const [k1, k2, k3] = stablelib.getHKDF(ck, ikm) + const [k1, k2, k3] = pureJsCrypto.getHKDF(ck, ikm) expect(uint8ArrayToString(k1, 'hex')).to.equal('cc5659adff12714982f806e2477a8d5ddd071def4c29bb38777b7e37046f6914') expect(uint8ArrayToString(k2, 'hex')).to.equal('a16ada915e551ab623f38be674bb4ef15d428ae9d80688899c9ef9b62ef208fa') expect(uint8ArrayToString(k3, 'hex')).to.equal('ff67bf9727e31b06efc203907e6786667d2c7a74ac412b4d31a80ba3fd766f68') }) async function doHandshake (xx: XX): Promise<{ nsInit: NoiseSession, nsResp: NoiseSession }> { - const kpInit = stablelib.generateX25519KeyPair() - const kpResp = stablelib.generateX25519KeyPair() + const kpInit = pureJsCrypto.generateX25519KeyPair() + const kpResp = pureJsCrypto.generateX25519KeyPair() // initiator setup const libp2pInitKeys = await generateEd25519Keys() @@ -107,7 +107,7 @@ describe('XX Handshake', () => { it('Test handshake', async () => { try { - const xx = new XX(stablelib) + const xx = new XX(pureJsCrypto) await doHandshake(xx) } catch (e) { const err = e as Error @@ -117,7 +117,7 @@ describe('XX Handshake', () => { it('Test symmetric encrypt and decrypt', async () => { try { - const xx = new XX(stablelib) + const xx = new XX(pureJsCrypto) const { nsInit, nsResp } = await doHandshake(xx) const ad = Buffer.from('authenticated') const message = Buffer.from('HelloCrypto') @@ -139,7 +139,7 @@ describe('XX Handshake', () => { }) it('Test multiple messages encryption and decryption', async () => { - const xx = new XX(stablelib) + const xx = new XX(pureJsCrypto) const { nsInit, nsResp } = await doHandshake(xx) const ad = Buffer.from('authenticated') const message = Buffer.from('ethereum1') diff --git a/test/noise.spec.ts b/test/noise.spec.ts index e309b6e..c3cc608 100644 --- a/test/noise.spec.ts +++ b/test/noise.spec.ts @@ -9,7 +9,7 @@ import { toString as uint8ArrayToString } from 'uint8arrays/to-string' import { fromString as uint8ArrayFromString } from 'uint8arrays/from-string' import sinon from 'sinon' import { NOISE_MSG_MAX_LENGTH_BYTES } from '../src/constants.js' -import { stablelib } from '../src/crypto/stablelib.js' +import { pureJsCrypto } from '../src/crypto/js.js' import { decode0, decode2, encode1, uint16BEDecode, uint16BEEncode } from '../src/encoder.js' import { XX } from '../src/handshakes/xx.js' import { XXHandshake } from '../src/handshake-xx.js' @@ -68,11 +68,11 @@ describe('Noise', () => { } ) const prologue = Buffer.alloc(0) - const staticKeys = stablelib.generateX25519KeyPair() - const xx = new XX(stablelib) + const staticKeys = pureJsCrypto.generateX25519KeyPair() + const xx = new XX(pureJsCrypto) const payload = await getPayload(remotePeer, staticKeys.publicKey) - const handshake = new XXHandshake(false, payload, prologue, stablelib, staticKeys, wrapped, localPeer, xx) + const handshake = new XXHandshake(false, payload, prologue, pureJsCrypto, staticKeys, wrapped, localPeer, xx) let receivedMessageBuffer = decode0((await wrapped.readLP()).slice()) // The first handshake message contains the initiator's ephemeral public key @@ -132,9 +132,9 @@ describe('Noise', () => { it('should working without remote peer provided in incoming connection', async () => { try { - const staticKeysInitiator = stablelib.generateX25519KeyPair() + const staticKeysInitiator = pureJsCrypto.generateX25519KeyPair() const noiseInit = new Noise({ staticNoiseKey: staticKeysInitiator.privateKey }) - const staticKeysResponder = stablelib.generateX25519KeyPair() + const staticKeysResponder = pureJsCrypto.generateX25519KeyPair() const noiseResp = new Noise({ staticNoiseKey: staticKeysResponder.privateKey }) const [inboundConnection, outboundConnection] = duplexPair() @@ -165,9 +165,9 @@ describe('Noise', () => { it('should accept and return Noise extension from remote peer', async () => { try { const certhashInit = Buffer.from('certhash data from init') - const staticKeysInitiator = stablelib.generateX25519KeyPair() + const staticKeysInitiator = pureJsCrypto.generateX25519KeyPair() const noiseInit = new Noise({ staticNoiseKey: staticKeysInitiator.privateKey, extensions: { webtransportCerthashes: [certhashInit] } }) - const staticKeysResponder = stablelib.generateX25519KeyPair() + const staticKeysResponder = pureJsCrypto.generateX25519KeyPair() const certhashResp = Buffer.from('certhash data from respon') const noiseResp = new Noise({ staticNoiseKey: staticKeysResponder.privateKey, extensions: { webtransportCerthashes: [certhashResp] } }) @@ -187,8 +187,8 @@ describe('Noise', () => { it('should accept a prologue', async () => { try { - const noiseInit = new Noise({ staticNoiseKey: undefined, crypto: stablelib, prologueBytes: Buffer.from('Some prologue') }) - const noiseResp = new Noise({ staticNoiseKey: undefined, crypto: stablelib, prologueBytes: Buffer.from('Some prologue') }) + const noiseInit = new Noise({ staticNoiseKey: undefined, crypto: pureJsCrypto, prologueBytes: Buffer.from('Some prologue') }) + const noiseResp = new Noise({ staticNoiseKey: undefined, crypto: pureJsCrypto, prologueBytes: Buffer.from('Some prologue') }) const [inboundConnection, outboundConnection] = duplexPair() const [outbound, inbound] = await Promise.all([ diff --git a/test/xx-handshake.spec.ts b/test/xx-handshake.spec.ts index 16e8b74..af4f4d0 100644 --- a/test/xx-handshake.spec.ts +++ b/test/xx-handshake.spec.ts @@ -4,7 +4,7 @@ import { assert, expect } from 'aegir/chai' import { duplexPair } from 'it-pair/duplex' import { pbStream } from 'it-pb-stream' import { equals as uint8ArrayEquals } from 'uint8arrays/equals' -import { stablelib } from '../src/crypto/stablelib.js' +import { pureJsCrypto } from '../src/crypto/js.js' import { XXHandshake } from '../src/handshake-xx.js' import { getPayload } from '../src/utils.js' import { createPeerIdsFromFixtures } from './fixtures/peer.js' @@ -23,14 +23,14 @@ describe('XX Handshake', () => { const connectionTo = pbStream(duplex[1]) const prologue = Buffer.alloc(0) - const staticKeysInitiator = stablelib.generateX25519KeyPair() - const staticKeysResponder = stablelib.generateX25519KeyPair() + const staticKeysInitiator = pureJsCrypto.generateX25519KeyPair() + const staticKeysResponder = pureJsCrypto.generateX25519KeyPair() const initPayload = await getPayload(peerA, staticKeysInitiator.publicKey) - const handshakeInitator = new XXHandshake(true, initPayload, prologue, stablelib, staticKeysInitiator, connectionFrom, peerB) + const handshakeInitator = new XXHandshake(true, initPayload, prologue, pureJsCrypto, staticKeysInitiator, connectionFrom, peerB) const respPayload = await getPayload(peerB, staticKeysResponder.publicKey) - const handshakeResponder = new XXHandshake(false, respPayload, prologue, stablelib, staticKeysResponder, connectionTo, peerA) + const handshakeResponder = new XXHandshake(false, respPayload, prologue, pureJsCrypto, staticKeysResponder, connectionTo, peerA) await handshakeInitator.propose() await handshakeResponder.propose() @@ -70,14 +70,14 @@ describe('XX Handshake', () => { const connectionTo = pbStream(duplex[1]) const prologue = Buffer.alloc(0) - const staticKeysInitiator = stablelib.generateX25519KeyPair() - const staticKeysResponder = stablelib.generateX25519KeyPair() + const staticKeysInitiator = pureJsCrypto.generateX25519KeyPair() + const staticKeysResponder = pureJsCrypto.generateX25519KeyPair() const initPayload = await getPayload(peerA, staticKeysInitiator.publicKey) - const handshakeInitator = new XXHandshake(true, initPayload, prologue, stablelib, staticKeysInitiator, connectionFrom, fakePeer) + const handshakeInitator = new XXHandshake(true, initPayload, prologue, pureJsCrypto, staticKeysInitiator, connectionFrom, fakePeer) const respPayload = await getPayload(peerB, staticKeysResponder.publicKey) - const handshakeResponder = new XXHandshake(false, respPayload, prologue, stablelib, staticKeysResponder, connectionTo, peerA) + const handshakeResponder = new XXHandshake(false, respPayload, prologue, pureJsCrypto, staticKeysResponder, connectionTo, peerA) await handshakeInitator.propose() await handshakeResponder.propose() @@ -99,14 +99,14 @@ describe('XX Handshake', () => { const connectionTo = pbStream(duplex[1]) const prologue = Buffer.alloc(0) - const staticKeysInitiator = stablelib.generateX25519KeyPair() - const staticKeysResponder = stablelib.generateX25519KeyPair() + const staticKeysInitiator = pureJsCrypto.generateX25519KeyPair() + const staticKeysResponder = pureJsCrypto.generateX25519KeyPair() const initPayload = await getPayload(peerA, staticKeysInitiator.publicKey) - const handshakeInitator = new XXHandshake(true, initPayload, prologue, stablelib, staticKeysInitiator, connectionFrom, peerB) + const handshakeInitator = new XXHandshake(true, initPayload, prologue, pureJsCrypto, staticKeysInitiator, connectionFrom, peerB) const respPayload = await getPayload(peerB, staticKeysResponder.publicKey) - const handshakeResponder = new XXHandshake(false, respPayload, prologue, stablelib, staticKeysResponder, connectionTo, fakePeer) + const handshakeResponder = new XXHandshake(false, respPayload, prologue, pureJsCrypto, staticKeysResponder, connectionTo, fakePeer) await handshakeInitator.propose() await handshakeResponder.propose()