@libp2p/noise 1.0.0-049bfa0fa

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (90) hide show
  1. package/README.md +95 -0
  2. package/dist/index.min.js +23 -0
  3. package/dist/index.min.js.map +7 -0
  4. package/dist/src/constants.d.ts +5 -0
  5. package/dist/src/constants.d.ts.map +1 -0
  6. package/dist/src/constants.js +5 -0
  7. package/dist/src/constants.js.map +1 -0
  8. package/dist/src/crypto/index.browser.d.ts +2 -0
  9. package/dist/src/crypto/index.browser.d.ts.map +1 -0
  10. package/dist/src/crypto/index.browser.js +3 -0
  11. package/dist/src/crypto/index.browser.js.map +1 -0
  12. package/dist/src/crypto/index.d.ts +3 -0
  13. package/dist/src/crypto/index.d.ts.map +1 -0
  14. package/dist/src/crypto/index.js +188 -0
  15. package/dist/src/crypto/index.js.map +1 -0
  16. package/dist/src/crypto/js.d.ts +3 -0
  17. package/dist/src/crypto/js.d.ts.map +1 -0
  18. package/dist/src/crypto/js.js +43 -0
  19. package/dist/src/crypto/js.js.map +1 -0
  20. package/dist/src/crypto.d.ts +14 -0
  21. package/dist/src/crypto.d.ts.map +1 -0
  22. package/dist/src/crypto.js +11 -0
  23. package/dist/src/crypto.js.map +1 -0
  24. package/dist/src/encoder.d.ts +10 -0
  25. package/dist/src/encoder.d.ts.map +1 -0
  26. package/dist/src/encoder.js +22 -0
  27. package/dist/src/encoder.js.map +1 -0
  28. package/dist/src/errors.d.ts +6 -0
  29. package/dist/src/errors.d.ts.map +1 -0
  30. package/dist/src/errors.js +9 -0
  31. package/dist/src/errors.js.map +1 -0
  32. package/dist/src/index.d.ts +52 -0
  33. package/dist/src/index.d.ts.map +1 -0
  34. package/dist/src/index.js +43 -0
  35. package/dist/src/index.js.map +1 -0
  36. package/dist/src/logger.d.ts +10 -0
  37. package/dist/src/logger.d.ts.map +1 -0
  38. package/dist/src/logger.js +56 -0
  39. package/dist/src/logger.js.map +1 -0
  40. package/dist/src/metrics.d.ts +4 -0
  41. package/dist/src/metrics.d.ts.map +1 -0
  42. package/dist/src/metrics.js +20 -0
  43. package/dist/src/metrics.js.map +1 -0
  44. package/dist/src/noise.d.ts +58 -0
  45. package/dist/src/noise.d.ts.map +1 -0
  46. package/dist/src/noise.js +174 -0
  47. package/dist/src/noise.js.map +1 -0
  48. package/dist/src/nonce.d.ts +17 -0
  49. package/dist/src/nonce.d.ts.map +1 -0
  50. package/dist/src/nonce.js +42 -0
  51. package/dist/src/nonce.js.map +1 -0
  52. package/dist/src/performHandshake.d.ts +5 -0
  53. package/dist/src/performHandshake.d.ts.map +1 -0
  54. package/dist/src/performHandshake.js +69 -0
  55. package/dist/src/performHandshake.js.map +1 -0
  56. package/dist/src/proto/payload.d.ts +22 -0
  57. package/dist/src/proto/payload.d.ts.map +1 -0
  58. package/dist/src/proto/payload.js +133 -0
  59. package/dist/src/proto/payload.js.map +1 -0
  60. package/dist/src/protocol.d.ts +71 -0
  61. package/dist/src/protocol.d.ts.map +1 -0
  62. package/dist/src/protocol.js +257 -0
  63. package/dist/src/protocol.js.map +1 -0
  64. package/dist/src/types.d.ts +98 -0
  65. package/dist/src/types.d.ts.map +1 -0
  66. package/dist/src/types.js +2 -0
  67. package/dist/src/types.js.map +1 -0
  68. package/dist/src/utils.d.ts +11 -0
  69. package/dist/src/utils.d.ts.map +1 -0
  70. package/dist/src/utils.js +176 -0
  71. package/dist/src/utils.js.map +1 -0
  72. package/package.json +94 -0
  73. package/src/constants.ts +5 -0
  74. package/src/crypto/index.browser.ts +3 -0
  75. package/src/crypto/index.ts +219 -0
  76. package/src/crypto/js.ts +56 -0
  77. package/src/crypto.ts +27 -0
  78. package/src/encoder.ts +24 -0
  79. package/src/errors.ts +10 -0
  80. package/src/index.ts +58 -0
  81. package/src/logger.ts +65 -0
  82. package/src/metrics.ts +32 -0
  83. package/src/noise.ts +237 -0
  84. package/src/nonce.ts +49 -0
  85. package/src/performHandshake.ts +91 -0
  86. package/src/proto/payload.proto +12 -0
  87. package/src/proto/payload.ts +170 -0
  88. package/src/protocol.ts +313 -0
  89. package/src/types.ts +105 -0
  90. package/src/utils.ts +221 -0
package/package.json ADDED
@@ -0,0 +1,94 @@
1
+ {
2
+ "name": "@libp2p/noise",
3
+ "version": "1.0.0-049bfa0fa",
4
+ "description": "Noise libp2p handshake for js-libp2p",
5
+ "author": "ChainSafe <info@chainsafe.io>",
6
+ "license": "Apache-2.0 OR MIT",
7
+ "homepage": "https://github.com/libp2p/js-libp2p/tree/main/packages/connection-encrypter-noise#readme",
8
+ "repository": {
9
+ "type": "git",
10
+ "url": "git+https://github.com/libp2p/js-libp2p.git"
11
+ },
12
+ "bugs": {
13
+ "url": "https://github.com/libp2p/js-libp2p/issues"
14
+ },
15
+ "publishConfig": {
16
+ "access": "public",
17
+ "provenance": true
18
+ },
19
+ "keywords": [
20
+ "crypto",
21
+ "libp2p",
22
+ "noise"
23
+ ],
24
+ "type": "module",
25
+ "types": "./dist/src/index.d.ts",
26
+ "files": [
27
+ "src",
28
+ "dist",
29
+ "!dist/test",
30
+ "!**/*.tsbuildinfo"
31
+ ],
32
+ "exports": {
33
+ ".": {
34
+ "types": "./dist/src/index.d.ts",
35
+ "import": "./dist/src/index.js"
36
+ }
37
+ },
38
+ "scripts": {
39
+ "bench": "node benchmarks/benchmark.js",
40
+ "clean": "aegir clean",
41
+ "dep-check": "aegir dep-check",
42
+ "build": "aegir build",
43
+ "lint": "aegir lint",
44
+ "lint:fix": "aegir lint --fix",
45
+ "test": "aegir test",
46
+ "test:node": "aegir test -t node",
47
+ "test:browser": "aegir test -t browser -t webworker",
48
+ "test:electron-main": "aegir test -t electron-main",
49
+ "test:interop": "aegir test -t node -f dist/test/interop.js",
50
+ "docs": "aegir docs",
51
+ "proto:gen": "protons ./src/proto/payload.proto",
52
+ "prepublish": "npm run build"
53
+ },
54
+ "dependencies": {
55
+ "@chainsafe/as-chacha20poly1305": "^0.1.0",
56
+ "@chainsafe/as-sha256": "^1.2.0",
57
+ "@libp2p/crypto": "5.1.9-049bfa0fa",
58
+ "@libp2p/interface": "3.0.0-049bfa0fa",
59
+ "@libp2p/peer-id": "6.0.0-049bfa0fa",
60
+ "@libp2p/utils": "7.0.0-049bfa0fa",
61
+ "@noble/ciphers": "^1.3.0",
62
+ "@noble/curves": "^1.9.7",
63
+ "@noble/hashes": "^1.8.0",
64
+ "protons-runtime": "^5.6.0",
65
+ "uint8arraylist": "^2.4.8",
66
+ "uint8arrays": "^5.1.0",
67
+ "wherearewe": "^2.0.1"
68
+ },
69
+ "devDependencies": {
70
+ "@libp2p/daemon-client": "10.0.0-049bfa0fa",
71
+ "@libp2p/daemon-server": "9.0.0-049bfa0fa",
72
+ "@libp2p/interface-compliance-tests": "7.0.0-049bfa0fa",
73
+ "@libp2p/interop": "14.0.0-049bfa0fa",
74
+ "@libp2p/logger": "6.0.0-049bfa0fa",
75
+ "@libp2p/tcp": "11.0.0-049bfa0fa",
76
+ "@libp2p/yamux": "8.0.0-049bfa0fa",
77
+ "@multiformats/multiaddr": "^13.0.1",
78
+ "@types/sinon": "^17.0.4",
79
+ "aegir": "^47.0.22",
80
+ "execa": "^9.6.0",
81
+ "go-libp2p": "^1.6.0",
82
+ "iso-random-stream": "^2.0.2",
83
+ "libp2p": "3.0.0-049bfa0fa",
84
+ "mkdirp": "^3.0.1",
85
+ "multiformats": "^13.4.0",
86
+ "p-defer": "^4.0.1",
87
+ "protons": "^7.7.0",
88
+ "sinon": "^21.0.0",
89
+ "sinon-ts": "^2.0.0"
90
+ },
91
+ "browser": {
92
+ "./dist/src/crypto/index.js": "./dist/src/crypto/index.browser.js"
93
+ }
94
+ }
@@ -0,0 +1,5 @@
1
+ export const NOISE_MSG_MAX_LENGTH_BYTES = 65535
2
+ export const NOISE_MSG_MAX_LENGTH_BYTES_WITHOUT_TAG = NOISE_MSG_MAX_LENGTH_BYTES - 16
3
+
4
+ export const DUMP_SESSION_KEYS = Boolean(globalThis.process?.env?.DUMP_SESSION_KEYS)
5
+ export const CHACHA_TAG_LENGTH = 16
@@ -0,0 +1,3 @@
1
+ import { pureJsCrypto } from './js.js'
2
+
3
+ export const defaultCrypto = pureJsCrypto
@@ -0,0 +1,219 @@
1
+ import crypto from 'node:crypto'
2
+ import { newInstance, ChaCha20Poly1305 } from '@chainsafe/as-chacha20poly1305'
3
+ import { digest } from '@chainsafe/as-sha256'
4
+ import { Uint8ArrayList } from 'uint8arraylist'
5
+ import { isElectronMain } from 'wherearewe'
6
+ import { pureJsCrypto } from './js.js'
7
+ import type { ICryptoInterface } from '../crypto.js'
8
+ import type { KeyPair } from '../types.js'
9
+
10
+ const ctx = newInstance()
11
+ const asImpl = new ChaCha20Poly1305(ctx)
12
+ const CHACHA_POLY1305 = 'chacha20-poly1305'
13
+ const PKCS8_PREFIX = Buffer.from([0x30, 0x2e, 0x02, 0x01, 0x00, 0x30, 0x05, 0x06, 0x03, 0x2b, 0x65, 0x6e, 0x04, 0x22, 0x04, 0x20])
14
+ const X25519_PREFIX = Buffer.from([0x30, 0x2a, 0x30, 0x05, 0x06, 0x03, 0x2b, 0x65, 0x6e, 0x03, 0x21, 0x00])
15
+ const nodeCrypto: Pick<ICryptoInterface, 'hashSHA256' | 'chaCha20Poly1305Encrypt' | 'chaCha20Poly1305Decrypt'> = {
16
+ hashSHA256 (data) {
17
+ const hash = crypto.createHash('sha256')
18
+
19
+ if (data instanceof Uint8Array) {
20
+ return hash.update(data).digest()
21
+ }
22
+
23
+ for (const buf of data) {
24
+ hash.update(buf)
25
+ }
26
+
27
+ return hash.digest()
28
+ },
29
+
30
+ chaCha20Poly1305Encrypt (plaintext, nonce, ad, k) {
31
+ const cipher = crypto.createCipheriv(CHACHA_POLY1305, k, nonce, {
32
+ authTagLength: 16
33
+ })
34
+ cipher.setAAD(ad, { plaintextLength: plaintext.byteLength })
35
+
36
+ if (plaintext instanceof Uint8Array) {
37
+ const updated = cipher.update(plaintext)
38
+ const final = cipher.final()
39
+ const tag = cipher.getAuthTag()
40
+
41
+ return Buffer.concat([updated, final, tag], updated.byteLength + final.byteLength + tag.byteLength)
42
+ }
43
+
44
+ const output = new Uint8ArrayList()
45
+
46
+ for (const buf of plaintext) {
47
+ output.append(cipher.update(buf))
48
+ }
49
+
50
+ const final = cipher.final()
51
+
52
+ if (final.byteLength > 0) {
53
+ output.append(final)
54
+ }
55
+
56
+ output.append(cipher.getAuthTag())
57
+
58
+ return output
59
+ },
60
+
61
+ chaCha20Poly1305Decrypt (ciphertext, nonce, ad, k, _dst) {
62
+ const authTag = ciphertext.subarray(ciphertext.length - 16)
63
+ const decipher = crypto.createDecipheriv(CHACHA_POLY1305, k, nonce, {
64
+ authTagLength: 16
65
+ })
66
+
67
+ let text: Uint8Array | Uint8ArrayList
68
+
69
+ if (ciphertext instanceof Uint8Array) {
70
+ text = ciphertext.subarray(0, ciphertext.length - 16)
71
+ } else {
72
+ text = ciphertext.sublist(0, ciphertext.length - 16)
73
+ }
74
+
75
+ decipher.setAAD(ad, {
76
+ plaintextLength: text.byteLength
77
+ })
78
+ decipher.setAuthTag(authTag)
79
+
80
+ if (text instanceof Uint8Array) {
81
+ const output = decipher.update(text)
82
+ const final = decipher.final()
83
+
84
+ if (final.byteLength > 0) {
85
+ return Buffer.concat([output, final], output.byteLength + final.byteLength)
86
+ }
87
+
88
+ return output
89
+ }
90
+
91
+ const output = new Uint8ArrayList()
92
+
93
+ for (const buf of text) {
94
+ output.append(decipher.update(buf))
95
+ }
96
+
97
+ const final = decipher.final()
98
+
99
+ if (final.byteLength > 0) {
100
+ output.append(final)
101
+ }
102
+
103
+ return output
104
+ }
105
+ }
106
+
107
+ const asCrypto: Pick<ICryptoInterface, 'hashSHA256' | 'chaCha20Poly1305Encrypt' | 'chaCha20Poly1305Decrypt'> = {
108
+ hashSHA256 (data) {
109
+ return digest(data.subarray())
110
+ },
111
+ chaCha20Poly1305Encrypt (plaintext, nonce, ad, k) {
112
+ return asImpl.seal(k, nonce, plaintext.subarray(), ad)
113
+ },
114
+ chaCha20Poly1305Decrypt (ciphertext, nonce, ad, k, dst) {
115
+ const plaintext = asImpl.open(k, nonce, ciphertext.subarray(), ad, dst)
116
+ if (!plaintext) {
117
+ throw new Error('Invalid chacha20poly1305 decryption')
118
+ }
119
+ return plaintext
120
+ }
121
+ }
122
+
123
+ // benchmarks show that for chacha20poly1305
124
+ // the as implementation is faster for smaller payloads(<1200)
125
+ // and the node implementation is faster for larger payloads
126
+ export const defaultCrypto: ICryptoInterface = {
127
+ ...pureJsCrypto,
128
+ hashSHA256 (data) {
129
+ return nodeCrypto.hashSHA256(data)
130
+ },
131
+ chaCha20Poly1305Encrypt (plaintext, nonce, ad, k) {
132
+ if (plaintext.byteLength < 1200) {
133
+ return asCrypto.chaCha20Poly1305Encrypt(plaintext, nonce, ad, k)
134
+ }
135
+ return nodeCrypto.chaCha20Poly1305Encrypt(plaintext, nonce, ad, k)
136
+ },
137
+ chaCha20Poly1305Decrypt (ciphertext, nonce, ad, k, dst) {
138
+ if (ciphertext.byteLength < 1200) {
139
+ return asCrypto.chaCha20Poly1305Decrypt(ciphertext, nonce, ad, k, dst)
140
+ }
141
+ return nodeCrypto.chaCha20Poly1305Decrypt(ciphertext, nonce, ad, k, dst)
142
+ },
143
+ generateX25519KeyPair (): KeyPair {
144
+ const { publicKey, privateKey } = crypto.generateKeyPairSync('x25519', {
145
+ publicKeyEncoding: {
146
+ type: 'spki',
147
+ format: 'der'
148
+ },
149
+ privateKeyEncoding: {
150
+ type: 'pkcs8',
151
+ format: 'der'
152
+ }
153
+ })
154
+
155
+ return {
156
+ publicKey: publicKey.subarray(X25519_PREFIX.length),
157
+ privateKey: privateKey.subarray(PKCS8_PREFIX.length)
158
+ }
159
+ },
160
+ generateX25519KeyPairFromSeed (seed: Uint8Array): KeyPair {
161
+ const privateKey = crypto.createPrivateKey({
162
+ key: Buffer.concat([
163
+ PKCS8_PREFIX,
164
+ seed
165
+ ], PKCS8_PREFIX.byteLength + seed.byteLength),
166
+ type: 'pkcs8',
167
+ format: 'der'
168
+ })
169
+
170
+ const publicKey = crypto.createPublicKey(privateKey)
171
+ .export({
172
+ type: 'spki',
173
+ format: 'der'
174
+ }).subarray(X25519_PREFIX.length)
175
+
176
+ return {
177
+ publicKey,
178
+ privateKey: seed
179
+ }
180
+ },
181
+ generateX25519SharedKey (privateKey: Uint8Array | Uint8ArrayList, publicKey: Uint8Array | Uint8ArrayList): Uint8Array {
182
+ if (publicKey instanceof Uint8Array) {
183
+ publicKey = Buffer.concat([
184
+ X25519_PREFIX,
185
+ publicKey
186
+ ], X25519_PREFIX.byteLength + publicKey.byteLength)
187
+ } else {
188
+ publicKey = new Uint8ArrayList(X25519_PREFIX, publicKey).subarray()
189
+ }
190
+
191
+ if (privateKey instanceof Uint8Array) {
192
+ privateKey = Buffer.concat([
193
+ PKCS8_PREFIX,
194
+ privateKey
195
+ ], PKCS8_PREFIX.byteLength + privateKey.byteLength)
196
+ } else {
197
+ privateKey = new Uint8ArrayList(PKCS8_PREFIX, privateKey).subarray()
198
+ }
199
+
200
+ return crypto.diffieHellman({
201
+ publicKey: crypto.createPublicKey({
202
+ key: Buffer.from(publicKey.buffer, publicKey.byteOffset, publicKey.byteLength),
203
+ type: 'spki',
204
+ format: 'der'
205
+ }),
206
+ privateKey: crypto.createPrivateKey({
207
+ key: Buffer.from(privateKey.buffer, privateKey.byteOffset, privateKey.byteLength),
208
+ type: 'pkcs8',
209
+ format: 'der'
210
+ })
211
+ })
212
+ }
213
+ }
214
+
215
+ // no chacha20-poly1305 in electron https://github.com/electron/electron/issues/24024
216
+ if (isElectronMain) {
217
+ defaultCrypto.chaCha20Poly1305Encrypt = asCrypto.chaCha20Poly1305Encrypt
218
+ defaultCrypto.chaCha20Poly1305Decrypt = asCrypto.chaCha20Poly1305Decrypt
219
+ }
@@ -0,0 +1,56 @@
1
+ import { chacha20poly1305 } from '@noble/ciphers/chacha'
2
+ import { x25519 } from '@noble/curves/ed25519'
3
+ import { extract, expand } from '@noble/hashes/hkdf'
4
+ import { sha256 } from '@noble/hashes/sha2'
5
+ import type { ICryptoInterface } from '../crypto.js'
6
+ import type { KeyPair } from '../types.js'
7
+ import type { Uint8ArrayList } from 'uint8arraylist'
8
+
9
+ export const pureJsCrypto: ICryptoInterface = {
10
+ hashSHA256 (data: Uint8Array | Uint8ArrayList): Uint8Array {
11
+ return sha256(data.subarray())
12
+ },
13
+
14
+ getHKDF (ck: Uint8Array, ikm: Uint8Array): [Uint8Array, Uint8Array, Uint8Array] {
15
+ const prk = extract(sha256, ikm, ck)
16
+ const okmU8Array = expand(sha256, prk, undefined, 96)
17
+ const okm = okmU8Array
18
+
19
+ const k1 = okm.subarray(0, 32)
20
+ const k2 = okm.subarray(32, 64)
21
+ const k3 = okm.subarray(64, 96)
22
+
23
+ return [k1, k2, k3]
24
+ },
25
+
26
+ generateX25519KeyPair (): KeyPair {
27
+ const secretKey = x25519.utils.randomSecretKey()
28
+ const publicKey = x25519.getPublicKey(secretKey)
29
+
30
+ return {
31
+ publicKey,
32
+ privateKey: secretKey
33
+ }
34
+ },
35
+
36
+ generateX25519KeyPairFromSeed (seed: Uint8Array): KeyPair {
37
+ const publicKey = x25519.getPublicKey(seed)
38
+
39
+ return {
40
+ publicKey,
41
+ privateKey: seed
42
+ }
43
+ },
44
+
45
+ generateX25519SharedKey (privateKey: Uint8Array | Uint8ArrayList, publicKey: Uint8Array | Uint8ArrayList): Uint8Array {
46
+ return x25519.getSharedSecret(privateKey.subarray(), publicKey.subarray())
47
+ },
48
+
49
+ chaCha20Poly1305Encrypt (plaintext: Uint8Array | Uint8ArrayList, nonce: Uint8Array, ad: Uint8Array, k: Uint8Array): Uint8Array {
50
+ return chacha20poly1305(k, nonce, ad).encrypt(plaintext.subarray())
51
+ },
52
+
53
+ chaCha20Poly1305Decrypt (ciphertext: Uint8Array | Uint8ArrayList, nonce: Uint8Array, ad: Uint8Array, k: Uint8Array, dst?: Uint8Array): Uint8Array {
54
+ return chacha20poly1305(k, nonce, ad).decrypt(ciphertext.subarray(), dst)
55
+ }
56
+ }
package/src/crypto.ts ADDED
@@ -0,0 +1,27 @@
1
+ import type { ICrypto, KeyPair } from './types.js'
2
+ import type { Uint8ArrayList } from 'uint8arraylist'
3
+
4
+ /** Underlying crypto implementation, meant to be overridable */
5
+ export interface ICryptoInterface {
6
+ hashSHA256(data: Uint8Array | Uint8ArrayList): Uint8Array
7
+
8
+ getHKDF(ck: Uint8Array, ikm: Uint8Array): [Uint8Array, Uint8Array, Uint8Array]
9
+
10
+ generateX25519KeyPair(): KeyPair
11
+ generateX25519KeyPairFromSeed(seed: Uint8Array): KeyPair
12
+ generateX25519SharedKey(privateKey: Uint8Array | Uint8ArrayList, publicKey: Uint8Array | Uint8ArrayList): Uint8Array
13
+
14
+ chaCha20Poly1305Encrypt(plaintext: Uint8Array | Uint8ArrayList, nonce: Uint8Array, ad: Uint8Array, k: Uint8Array): Uint8ArrayList | Uint8Array
15
+ chaCha20Poly1305Decrypt(ciphertext: Uint8Array | Uint8ArrayList, nonce: Uint8Array, ad: Uint8Array, k: Uint8Array, dst?: Uint8Array): Uint8ArrayList | Uint8Array
16
+ }
17
+
18
+ export function wrapCrypto (crypto: ICryptoInterface): ICrypto {
19
+ return {
20
+ generateKeypair: crypto.generateX25519KeyPair,
21
+ dh: (keypair, publicKey) => crypto.generateX25519SharedKey(keypair.privateKey, publicKey).subarray(0, 32),
22
+ encrypt: crypto.chaCha20Poly1305Encrypt,
23
+ decrypt: crypto.chaCha20Poly1305Decrypt,
24
+ hash: crypto.hashSHA256,
25
+ hkdf: crypto.getHKDF
26
+ }
27
+ }
package/src/encoder.ts ADDED
@@ -0,0 +1,24 @@
1
+ import { allocUnsafe as uint8ArrayAllocUnsafe } from 'uint8arrays/alloc'
2
+ import type { Uint8ArrayList } from 'uint8arraylist'
3
+
4
+ export const uint16BEEncode = (value: number): Uint8Array => {
5
+ const target = uint8ArrayAllocUnsafe(2)
6
+ target[0] = value >> 8
7
+ target[1] = value
8
+ return target
9
+ }
10
+ uint16BEEncode.bytes = 2
11
+
12
+ export const uint16BEDecode = (data: Uint8Array | Uint8ArrayList): number => {
13
+ if (data.length < 2) { throw RangeError('Could not decode int16BE') }
14
+
15
+ if (data instanceof Uint8Array) {
16
+ let value = 0
17
+ value += data[0] << 8
18
+ value += data[1]
19
+ return value
20
+ }
21
+
22
+ return data.getUint16(0)
23
+ }
24
+ uint16BEDecode.bytes = 2
package/src/errors.ts ADDED
@@ -0,0 +1,10 @@
1
+ export class InvalidCryptoExchangeError extends Error {
2
+ public code: string
3
+
4
+ constructor (message = 'Invalid crypto exchange') {
5
+ super(message)
6
+ this.code = InvalidCryptoExchangeError.code
7
+ }
8
+
9
+ static readonly code = 'ERR_INVALID_CRYPTO_EXCHANGE'
10
+ }
package/src/index.ts ADDED
@@ -0,0 +1,58 @@
1
+ /**
2
+ * @packageDocumentation
3
+ *
4
+ * This repository contains TypeScript implementation of noise protocol, an encryption protocol used in libp2p.
5
+ *
6
+ * ## Usage
7
+ *
8
+ * Install with `yarn add @libp2p/noise` or `npm i @libp2p/noise`.
9
+ *
10
+ * Example of using default noise configuration and passing it to the libp2p config:
11
+ *
12
+ * ```ts
13
+ * import {createLibp2p} from "libp2p"
14
+ * import {noise} from "@libp2p/noise"
15
+ *
16
+ * //custom noise configuration, pass it instead of `noise()`
17
+ * //x25519 private key
18
+ * const n = noise({ staticNoiseKey });
19
+ *
20
+ * const libp2p = await createLibp2p({
21
+ * connectionEncrypters: [noise()],
22
+ * //... other options
23
+ * })
24
+ * ```
25
+ *
26
+ * See the [NoiseInit](https://github.com/ChainSafe/js-libp2p-noise/blob/master/src/noise.ts#L22-L30) interface for noise configuration options.
27
+ *
28
+ * ## API
29
+ *
30
+ * This module exposes an implementation of the [ConnectionEncrypter](https://libp2p.github.io/js-libp2p/interfaces/_libp2p_interface.ConnectionEncrypter.html) interface.
31
+ *
32
+ * ## Bring your own crypto
33
+ *
34
+ * You can provide a custom crypto implementation (instead of the default, based on [@noble](https://paulmillr.com/noble/)) by adding a `crypto` field to the init argument passed to the `Noise` factory.
35
+ *
36
+ * The implementation must conform to the `ICryptoInterface`, defined in <https://github.com/ChainSafe/js-libp2p-noise/blob/master/src/crypto.ts>
37
+ */
38
+
39
+ import { Noise } from './noise.js'
40
+ import type { NoiseInit, NoiseExtensions } from './noise.js'
41
+ import type { KeyPair } from './types.js'
42
+ import type { ComponentLogger, ConnectionEncrypter, Metrics, PeerId, PrivateKey, Upgrader } from '@libp2p/interface'
43
+
44
+ export { pureJsCrypto } from './crypto/js.js'
45
+ export type { ICryptoInterface } from './crypto.js'
46
+ export type { NoiseInit, NoiseExtensions, KeyPair }
47
+
48
+ export interface NoiseComponents {
49
+ peerId: PeerId
50
+ privateKey: PrivateKey
51
+ logger: ComponentLogger
52
+ upgrader: Upgrader
53
+ metrics?: Metrics
54
+ }
55
+
56
+ export function noise (init: NoiseInit = {}): (components: NoiseComponents) => ConnectionEncrypter<NoiseExtensions> {
57
+ return (components: NoiseComponents) => new Noise(components, init)
58
+ }
package/src/logger.ts ADDED
@@ -0,0 +1,65 @@
1
+ import { toString as uint8ArrayToString } from 'uint8arrays/to-string'
2
+ import { DUMP_SESSION_KEYS } from './constants.js'
3
+ import type { CipherState } from './protocol.js'
4
+ import type { KeyPair } from './types.js'
5
+ import type { Logger } from '@libp2p/interface'
6
+ import type { Uint8ArrayList } from 'uint8arraylist'
7
+
8
+ export function logLocalStaticKeys (s: KeyPair | undefined, keyLogger: Logger): void {
9
+ if (!keyLogger.enabled || !DUMP_SESSION_KEYS) {
10
+ return
11
+ }
12
+
13
+ if (s) {
14
+ keyLogger(`LOCAL_STATIC_PUBLIC_KEY ${uint8ArrayToString(s.publicKey, 'hex')}`)
15
+ keyLogger(`LOCAL_STATIC_PRIVATE_KEY ${uint8ArrayToString(s.privateKey, 'hex')}`)
16
+ } else {
17
+ keyLogger('Missing local static keys.')
18
+ }
19
+ }
20
+
21
+ export function logLocalEphemeralKeys (e: KeyPair | undefined, keyLogger: Logger): void {
22
+ if (!keyLogger.enabled || !DUMP_SESSION_KEYS) {
23
+ return
24
+ }
25
+
26
+ if (e) {
27
+ keyLogger(`LOCAL_PUBLIC_EPHEMERAL_KEY ${uint8ArrayToString(e.publicKey, 'hex')}`)
28
+ keyLogger(`LOCAL_PRIVATE_EPHEMERAL_KEY ${uint8ArrayToString(e.privateKey, 'hex')}`)
29
+ } else {
30
+ keyLogger('Missing local ephemeral keys.')
31
+ }
32
+ }
33
+
34
+ export function logRemoteStaticKey (rs: Uint8Array | Uint8ArrayList | undefined, keyLogger: Logger): void {
35
+ if (!keyLogger.enabled || !DUMP_SESSION_KEYS) {
36
+ return
37
+ }
38
+
39
+ if (rs) {
40
+ keyLogger(`REMOTE_STATIC_PUBLIC_KEY ${uint8ArrayToString(rs.subarray(), 'hex')}`)
41
+ } else {
42
+ keyLogger('Missing remote static public key.')
43
+ }
44
+ }
45
+
46
+ export function logRemoteEphemeralKey (re: Uint8Array | Uint8ArrayList | undefined, keyLogger: Logger): void {
47
+ if (!keyLogger.enabled || !DUMP_SESSION_KEYS) {
48
+ return
49
+ }
50
+
51
+ if (re) {
52
+ keyLogger(`REMOTE_EPHEMERAL_PUBLIC_KEY ${uint8ArrayToString(re.subarray(), 'hex')}`)
53
+ } else {
54
+ keyLogger('Missing remote ephemeral keys.')
55
+ }
56
+ }
57
+
58
+ export function logCipherState (cs1: CipherState, cs2: CipherState, keyLogger: Logger): void {
59
+ if (!keyLogger.enabled || !DUMP_SESSION_KEYS) {
60
+ return
61
+ }
62
+
63
+ keyLogger(`CIPHER_STATE_1 ${cs1.n.getUint64()} ${cs1.k && uint8ArrayToString(cs1.k, 'hex')}`)
64
+ keyLogger(`CIPHER_STATE_2 ${cs2.n.getUint64()} ${cs2.k && uint8ArrayToString(cs2.k, 'hex')}`)
65
+ }
package/src/metrics.ts ADDED
@@ -0,0 +1,32 @@
1
+ import type { Counter, Metrics } from '@libp2p/interface'
2
+
3
+ export type MetricsRegistry = Record<string, Counter>
4
+
5
+ export function registerMetrics (metrics: Metrics): MetricsRegistry {
6
+ return {
7
+ xxHandshakeSuccesses: metrics.registerCounter(
8
+ 'libp2p_noise_xxhandshake_successes_total', {
9
+ help: 'Total count of noise xxHandshakes successes_'
10
+ }),
11
+
12
+ xxHandshakeErrors: metrics.registerCounter(
13
+ 'libp2p_noise_xxhandshake_error_total', {
14
+ help: 'Total count of noise xxHandshakes errors'
15
+ }),
16
+
17
+ encryptedPackets: metrics.registerCounter(
18
+ 'libp2p_noise_encrypted_packets_total', {
19
+ help: 'Total count of noise encrypted packets successfully'
20
+ }),
21
+
22
+ decryptedPackets: metrics.registerCounter(
23
+ 'libp2p_noise_decrypted_packets_total', {
24
+ help: 'Total count of noise decrypted packets'
25
+ }),
26
+
27
+ decryptErrors: metrics.registerCounter(
28
+ 'libp2p_noise_decrypt_errors_total', {
29
+ help: 'Total count of noise decrypt errors'
30
+ })
31
+ }
32
+ }