@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/src/noise.ts ADDED
@@ -0,0 +1,237 @@
1
+ import { publicKeyFromProtobuf } from '@libp2p/crypto/keys'
2
+ import { InvalidCryptoExchangeError, serviceCapabilities } from '@libp2p/interface'
3
+ import { peerIdFromPublicKey } from '@libp2p/peer-id'
4
+ import { lpStream } from '@libp2p/utils'
5
+ import { alloc as uint8ArrayAlloc } from 'uint8arrays/alloc'
6
+ import { NOISE_MSG_MAX_LENGTH_BYTES } from './constants.js'
7
+ import { defaultCrypto } from './crypto/index.js'
8
+ import { wrapCrypto } from './crypto.js'
9
+ import { uint16BEDecode, uint16BEEncode } from './encoder.js'
10
+ import { registerMetrics } from './metrics.js'
11
+ import { performHandshakeInitiator, performHandshakeResponder } from './performHandshake.js'
12
+ import { toMessageStream } from './utils.ts'
13
+ import type { ICryptoInterface } from './crypto.js'
14
+ import type { NoiseComponents } from './index.js'
15
+ import type { MetricsRegistry } from './metrics.js'
16
+ import type { HandshakeResult, ICrypto, INoiseConnection, INoiseExtensions, KeyPair } from './types.js'
17
+ import type { SecuredConnection, PrivateKey, PublicKey, StreamMuxerFactory, SecureConnectionOptions, Logger, MessageStream } from '@libp2p/interface'
18
+ import type { LengthPrefixedStream } from '@libp2p/utils'
19
+
20
+ export interface NoiseExtensions {
21
+ webtransportCerthashes: Uint8Array[]
22
+ }
23
+
24
+ export interface NoiseInit {
25
+ /**
26
+ * x25519 private key, reuse for faster handshakes
27
+ */
28
+ staticNoiseKey?: Uint8Array
29
+ extensions?: Partial<NoiseExtensions>
30
+ crypto?: ICryptoInterface
31
+ prologueBytes?: Uint8Array
32
+ }
33
+
34
+ export class Noise implements INoiseConnection {
35
+ public protocol = '/noise'
36
+ public crypto: ICrypto
37
+
38
+ private readonly prologue: Uint8Array
39
+ private readonly staticKey: KeyPair
40
+ private readonly extensions?: NoiseExtensions
41
+ private readonly metrics?: MetricsRegistry
42
+ private readonly components: NoiseComponents
43
+ private readonly log: Logger
44
+
45
+ constructor (components: NoiseComponents, init: NoiseInit = {}) {
46
+ const { staticNoiseKey, extensions, crypto, prologueBytes } = init
47
+ const { metrics } = components
48
+
49
+ this.components = components
50
+ this.log = components.logger.forComponent('libp2p:noise')
51
+ const _crypto = crypto ?? defaultCrypto
52
+ this.crypto = wrapCrypto(_crypto)
53
+ this.extensions = {
54
+ webtransportCerthashes: [],
55
+ ...extensions
56
+ }
57
+ this.metrics = metrics ? registerMetrics(metrics) : undefined
58
+
59
+ if (staticNoiseKey) {
60
+ // accepts x25519 private key of length 32
61
+ this.staticKey = _crypto.generateX25519KeyPairFromSeed(staticNoiseKey)
62
+ } else {
63
+ this.staticKey = _crypto.generateX25519KeyPair()
64
+ }
65
+ this.prologue = prologueBytes ?? uint8ArrayAlloc(0)
66
+ }
67
+
68
+ readonly [Symbol.toStringTag] = '@libp2p/noise'
69
+
70
+ readonly [serviceCapabilities]: string[] = [
71
+ '@libp2p/connection-encryption',
72
+ '@libp2p/noise'
73
+ ]
74
+
75
+ /**
76
+ * Encrypt outgoing data to the remote party (handshake as initiator)
77
+ *
78
+ * @param connection - streaming iterable duplex that will be encrypted
79
+ * @param options
80
+ * @param options.remotePeer - PeerId of the remote peer. Used to validate the integrity of the remote peer
81
+ * @param options.signal - Used to abort the operation
82
+ */
83
+ async secureOutbound (connection: MessageStream, options?: SecureConnectionOptions): Promise<SecuredConnection<INoiseExtensions>> {
84
+ const log = connection.log?.newScope('noise') ?? this.log
85
+ const wrappedConnection = lpStream(connection, {
86
+ lengthEncoder: uint16BEEncode,
87
+ lengthDecoder: uint16BEDecode,
88
+ maxDataLength: NOISE_MSG_MAX_LENGTH_BYTES
89
+ })
90
+
91
+ const handshake = await this.performHandshakeInitiator(
92
+ wrappedConnection,
93
+ this.components.privateKey,
94
+ log,
95
+ options?.remotePeer?.publicKey,
96
+ options
97
+ )
98
+ const publicKey = publicKeyFromProtobuf(handshake.payload.identityKey)
99
+
100
+ return {
101
+ connection: toMessageStream(wrappedConnection.unwrap(), handshake, this.metrics),
102
+ remoteExtensions: handshake.payload.extensions,
103
+ remotePeer: peerIdFromPublicKey(publicKey),
104
+ streamMuxer: options?.skipStreamMuxerNegotiation === true ? undefined : this.getStreamMuxer(handshake.payload.extensions?.streamMuxers)
105
+ }
106
+ }
107
+
108
+ private getStreamMuxer (protocols?: string[]): StreamMuxerFactory | undefined {
109
+ if (protocols == null || protocols.length === 0) {
110
+ return
111
+ }
112
+
113
+ const streamMuxers = this.components.upgrader.getStreamMuxers()
114
+
115
+ if (streamMuxers != null) {
116
+ for (const protocol of protocols) {
117
+ const streamMuxer = streamMuxers.get(protocol)
118
+
119
+ if (streamMuxer != null) {
120
+ return streamMuxer
121
+ }
122
+ }
123
+ }
124
+
125
+ if (protocols.length) {
126
+ throw new InvalidCryptoExchangeError('Early muxer negotiation was requested but the initiator and responder had no common muxers')
127
+ }
128
+ }
129
+
130
+ /**
131
+ * Decrypt incoming data (handshake as responder).
132
+ *
133
+ * @param connection - streaming iterable duplex that will be encrypted
134
+ * @param options
135
+ * @param options.remotePeer - PeerId of the remote peer. Used to validate the integrity of the remote peer
136
+ * @param options.signal - Used to abort the operation
137
+ */
138
+ async secureInbound (connection: MessageStream, options?: SecureConnectionOptions): Promise<SecuredConnection<INoiseExtensions>> {
139
+ const log = connection.log?.newScope('noise') ?? this.log
140
+ const wrappedConnection = lpStream(connection, {
141
+ lengthEncoder: uint16BEEncode,
142
+ lengthDecoder: uint16BEDecode,
143
+ maxDataLength: NOISE_MSG_MAX_LENGTH_BYTES
144
+ })
145
+
146
+ const handshake = await this.performHandshakeResponder(
147
+ wrappedConnection,
148
+ this.components.privateKey,
149
+ log,
150
+ options?.remotePeer?.publicKey,
151
+ options
152
+ )
153
+ const publicKey = publicKeyFromProtobuf(handshake.payload.identityKey)
154
+
155
+ return {
156
+ connection: toMessageStream(wrappedConnection.unwrap(), handshake, this.metrics),
157
+ remoteExtensions: handshake.payload.extensions,
158
+ remotePeer: peerIdFromPublicKey(publicKey),
159
+ streamMuxer: options?.skipStreamMuxerNegotiation === true ? undefined : this.getStreamMuxer(handshake.payload.extensions?.streamMuxers)
160
+ }
161
+ }
162
+
163
+ /**
164
+ * Perform XX handshake as initiator.
165
+ */
166
+ private async performHandshakeInitiator (
167
+ connection: LengthPrefixedStream,
168
+ // TODO: pass private key in noise constructor via Components
169
+ privateKey: PrivateKey,
170
+ log: Logger,
171
+ remoteIdentityKey?: PublicKey,
172
+ options?: SecureConnectionOptions
173
+ ): Promise<HandshakeResult> {
174
+ let result: HandshakeResult
175
+ const streamMuxers = options?.skipStreamMuxerNegotiation === true ? [] : [...this.components.upgrader.getStreamMuxers().keys()]
176
+
177
+ try {
178
+ result = await performHandshakeInitiator({
179
+ connection,
180
+ privateKey,
181
+ remoteIdentityKey,
182
+ log: log.newScope('xxhandshake'),
183
+ crypto: this.crypto,
184
+ prologue: this.prologue,
185
+ s: this.staticKey,
186
+ extensions: {
187
+ streamMuxers,
188
+ webtransportCerthashes: [],
189
+ ...this.extensions
190
+ }
191
+ }, options)
192
+ this.metrics?.xxHandshakeSuccesses.increment()
193
+ } catch (e: unknown) {
194
+ this.metrics?.xxHandshakeErrors.increment()
195
+ throw e
196
+ }
197
+
198
+ return result
199
+ }
200
+
201
+ /**
202
+ * Perform XX handshake as responder.
203
+ */
204
+ private async performHandshakeResponder (
205
+ connection: LengthPrefixedStream,
206
+ privateKey: PrivateKey,
207
+ log: Logger,
208
+ remoteIdentityKey?: PublicKey,
209
+ options?: SecureConnectionOptions
210
+ ): Promise<HandshakeResult> {
211
+ let result: HandshakeResult
212
+ const streamMuxers = options?.skipStreamMuxerNegotiation === true ? [] : [...this.components.upgrader.getStreamMuxers().keys()]
213
+
214
+ try {
215
+ result = await performHandshakeResponder({
216
+ connection,
217
+ privateKey,
218
+ remoteIdentityKey,
219
+ log: log.newScope('xxhandshake'),
220
+ crypto: this.crypto,
221
+ prologue: this.prologue,
222
+ s: this.staticKey,
223
+ extensions: {
224
+ streamMuxers,
225
+ webtransportCerthashes: [],
226
+ ...this.extensions
227
+ }
228
+ }, options)
229
+ this.metrics?.xxHandshakeSuccesses.increment()
230
+ } catch (e: unknown) {
231
+ this.metrics?.xxHandshakeErrors.increment()
232
+ throw e
233
+ }
234
+
235
+ return result
236
+ }
237
+ }
package/src/nonce.ts ADDED
@@ -0,0 +1,49 @@
1
+ import { alloc as uint8ArrayAlloc } from 'uint8arrays/alloc'
2
+
3
+ export const MIN_NONCE = 0
4
+ // For performance reasons, the nonce is represented as a JS `number`
5
+ // Although JS `number` can safely represent integers up to 2 ** 53 - 1, we choose to only use
6
+ // 4 bytes to store the data for performance reason.
7
+ // This is a slight deviation from the noise spec, which describes the max nonce as 2 ** 64 - 2
8
+ // The effect is that this implementation will need a new handshake to be performed after fewer messages are exchanged than other implementations with full uint64 nonces.
9
+ // this MAX_NONCE is still a large number of messages, so the practical effect of this is negligible.
10
+ export const MAX_NONCE = 0xffffffff
11
+
12
+ const ERR_MAX_NONCE = 'Cipher state has reached maximum n, a new handshake must be performed'
13
+
14
+ /**
15
+ * The nonce is an uint that's increased over time.
16
+ * Maintaining different representations help improve performance.
17
+ */
18
+ export class Nonce {
19
+ private n: number
20
+ private readonly bytes: Uint8Array
21
+ private readonly view: DataView
22
+
23
+ constructor (n = MIN_NONCE) {
24
+ this.n = n
25
+ this.bytes = uint8ArrayAlloc(12)
26
+ this.view = new DataView(this.bytes.buffer, this.bytes.byteOffset, this.bytes.byteLength)
27
+ this.view.setUint32(4, n, true)
28
+ }
29
+
30
+ increment (): void {
31
+ this.n++
32
+ // Even though we're treating the nonce as 8 bytes, RFC7539 specifies 12 bytes for a nonce.
33
+ this.view.setUint32(4, this.n, true)
34
+ }
35
+
36
+ getBytes (): Uint8Array {
37
+ return this.bytes
38
+ }
39
+
40
+ getUint64 (): number {
41
+ return this.n
42
+ }
43
+
44
+ assertValue (): void {
45
+ if (this.n > MAX_NONCE) {
46
+ throw new Error(ERR_MAX_NONCE)
47
+ }
48
+ }
49
+ }
@@ -0,0 +1,91 @@
1
+ import {
2
+ logLocalStaticKeys,
3
+ logLocalEphemeralKeys,
4
+ logRemoteEphemeralKey,
5
+ logRemoteStaticKey,
6
+ logCipherState
7
+ } from './logger.js'
8
+ import { ZEROLEN, XXHandshakeState } from './protocol.js'
9
+ import { createHandshakePayload, decodeHandshakePayload } from './utils.js'
10
+ import type { HandshakeResult, HandshakeParams } from './types.js'
11
+ import type { AbortOptions } from '@libp2p/interface'
12
+
13
+ export async function performHandshakeInitiator (init: HandshakeParams, options?: AbortOptions): Promise<HandshakeResult> {
14
+ const { log, connection, crypto, privateKey, prologue, s, remoteIdentityKey, extensions } = init
15
+
16
+ const payload = await createHandshakePayload(privateKey, s.publicKey, extensions)
17
+ const xx = new XXHandshakeState({
18
+ crypto,
19
+ protocolName: 'Noise_XX_25519_ChaChaPoly_SHA256',
20
+ initiator: true,
21
+ prologue,
22
+ s
23
+ })
24
+
25
+ logLocalStaticKeys(xx.s, log)
26
+ log.trace('Stage 0 - Initiator starting to send first message.')
27
+ await connection.write(xx.writeMessageA(ZEROLEN), options)
28
+ log.trace('Stage 0 - Initiator finished sending first message.')
29
+ logLocalEphemeralKeys(xx.e, log)
30
+
31
+ log.trace('Stage 1 - Initiator waiting to receive first message from responder...')
32
+ const plaintext = xx.readMessageB(await connection.read(options))
33
+ log.trace('Stage 1 - Initiator received the message.')
34
+ logRemoteEphemeralKey(xx.re, log)
35
+ logRemoteStaticKey(xx.rs, log)
36
+
37
+ log.trace("Initiator going to check remote's signature...")
38
+ const receivedPayload = await decodeHandshakePayload(plaintext, xx.rs, remoteIdentityKey)
39
+ log.trace('All good with the signature!')
40
+
41
+ log.trace('Stage 2 - Initiator sending third handshake message.')
42
+ await connection.write(xx.writeMessageC(payload), options)
43
+ log.trace('Stage 2 - Initiator sent message with signed payload.')
44
+
45
+ const [cs1, cs2] = xx.ss.split()
46
+ logCipherState(cs1, cs2, log)
47
+
48
+ return {
49
+ payload: receivedPayload,
50
+ encrypt: (plaintext) => cs1.encryptWithAd(ZEROLEN, plaintext),
51
+ decrypt: (ciphertext, dst) => cs2.decryptWithAd(ZEROLEN, ciphertext, dst)
52
+ }
53
+ }
54
+
55
+ export async function performHandshakeResponder (init: HandshakeParams, options?: AbortOptions): Promise<HandshakeResult> {
56
+ const { log, connection, crypto, privateKey, prologue, s, remoteIdentityKey, extensions } = init
57
+
58
+ const payload = await createHandshakePayload(privateKey, s.publicKey, extensions)
59
+ const xx = new XXHandshakeState({
60
+ crypto,
61
+ protocolName: 'Noise_XX_25519_ChaChaPoly_SHA256',
62
+ initiator: false,
63
+ prologue,
64
+ s
65
+ })
66
+
67
+ logLocalStaticKeys(xx.s, log)
68
+ log.trace('Stage 0 - Responder waiting to receive first message.')
69
+ xx.readMessageA(await connection.read(options))
70
+ log.trace('Stage 0 - Responder received first message.')
71
+ logRemoteEphemeralKey(xx.re, log)
72
+
73
+ log.trace('Stage 1 - Responder sending out first message with signed payload and static key.')
74
+ await connection.write(xx.writeMessageB(payload), options)
75
+ log.trace('Stage 1 - Responder sent the second handshake message with signed payload.')
76
+ logLocalEphemeralKeys(xx.e, log)
77
+
78
+ log.trace('Stage 2 - Responder waiting for third handshake message...')
79
+ const plaintext = xx.readMessageC(await connection.read(options))
80
+ log.trace('Stage 2 - Responder received the message, finished handshake.')
81
+ const receivedPayload = await decodeHandshakePayload(plaintext, xx.rs, remoteIdentityKey)
82
+
83
+ const [cs1, cs2] = xx.ss.split()
84
+ logCipherState(cs1, cs2, log)
85
+
86
+ return {
87
+ payload: receivedPayload,
88
+ encrypt: (plaintext) => cs2.encryptWithAd(ZEROLEN, plaintext),
89
+ decrypt: (ciphertext, dst) => cs1.decryptWithAd(ZEROLEN, ciphertext, dst)
90
+ }
91
+ }
@@ -0,0 +1,12 @@
1
+ syntax = "proto3";
2
+
3
+ message NoiseExtensions {
4
+ repeated bytes webtransport_certhashes = 1;
5
+ repeated string stream_muxers = 2;
6
+ }
7
+
8
+ message NoiseHandshakePayload {
9
+ bytes identity_key = 1;
10
+ bytes identity_sig = 2;
11
+ optional NoiseExtensions extensions = 4;
12
+ }
@@ -0,0 +1,170 @@
1
+ import { decodeMessage, encodeMessage, MaxLengthError, message } from 'protons-runtime'
2
+ import { alloc as uint8ArrayAlloc } from 'uint8arrays/alloc'
3
+ import type { Codec, DecodeOptions } from 'protons-runtime'
4
+ import type { Uint8ArrayList } from 'uint8arraylist'
5
+
6
+ export interface NoiseExtensions {
7
+ webtransportCerthashes: Uint8Array[]
8
+ streamMuxers: string[]
9
+ }
10
+
11
+ export namespace NoiseExtensions {
12
+ let _codec: Codec<NoiseExtensions>
13
+
14
+ export const codec = (): Codec<NoiseExtensions> => {
15
+ if (_codec == null) {
16
+ _codec = message<NoiseExtensions>((obj, w, opts = {}) => {
17
+ if (opts.lengthDelimited !== false) {
18
+ w.fork()
19
+ }
20
+
21
+ if (obj.webtransportCerthashes != null) {
22
+ for (const value of obj.webtransportCerthashes) {
23
+ w.uint32(10)
24
+ w.bytes(value)
25
+ }
26
+ }
27
+
28
+ if (obj.streamMuxers != null) {
29
+ for (const value of obj.streamMuxers) {
30
+ w.uint32(18)
31
+ w.string(value)
32
+ }
33
+ }
34
+
35
+ if (opts.lengthDelimited !== false) {
36
+ w.ldelim()
37
+ }
38
+ }, (reader, length, opts = {}) => {
39
+ const obj: any = {
40
+ webtransportCerthashes: [],
41
+ streamMuxers: []
42
+ }
43
+
44
+ const end = length == null ? reader.len : reader.pos + length
45
+
46
+ while (reader.pos < end) {
47
+ const tag = reader.uint32()
48
+
49
+ switch (tag >>> 3) {
50
+ case 1: {
51
+ if (opts.limits?.webtransportCerthashes != null && obj.webtransportCerthashes.length === opts.limits.webtransportCerthashes) {
52
+ throw new MaxLengthError('Decode error - map field "webtransportCerthashes" had too many elements')
53
+ }
54
+
55
+ obj.webtransportCerthashes.push(reader.bytes())
56
+ break
57
+ }
58
+ case 2: {
59
+ if (opts.limits?.streamMuxers != null && obj.streamMuxers.length === opts.limits.streamMuxers) {
60
+ throw new MaxLengthError('Decode error - map field "streamMuxers" had too many elements')
61
+ }
62
+
63
+ obj.streamMuxers.push(reader.string())
64
+ break
65
+ }
66
+ default: {
67
+ reader.skipType(tag & 7)
68
+ break
69
+ }
70
+ }
71
+ }
72
+
73
+ return obj
74
+ })
75
+ }
76
+
77
+ return _codec
78
+ }
79
+
80
+ export const encode = (obj: Partial<NoiseExtensions>): Uint8Array => {
81
+ return encodeMessage(obj, NoiseExtensions.codec())
82
+ }
83
+
84
+ export const decode = (buf: Uint8Array | Uint8ArrayList, opts?: DecodeOptions<NoiseExtensions>): NoiseExtensions => {
85
+ return decodeMessage(buf, NoiseExtensions.codec(), opts)
86
+ }
87
+ }
88
+
89
+ export interface NoiseHandshakePayload {
90
+ identityKey: Uint8Array
91
+ identitySig: Uint8Array
92
+ extensions?: NoiseExtensions
93
+ }
94
+
95
+ export namespace NoiseHandshakePayload {
96
+ let _codec: Codec<NoiseHandshakePayload>
97
+
98
+ export const codec = (): Codec<NoiseHandshakePayload> => {
99
+ if (_codec == null) {
100
+ _codec = message<NoiseHandshakePayload>((obj, w, opts = {}) => {
101
+ if (opts.lengthDelimited !== false) {
102
+ w.fork()
103
+ }
104
+
105
+ if ((obj.identityKey != null && obj.identityKey.byteLength > 0)) {
106
+ w.uint32(10)
107
+ w.bytes(obj.identityKey)
108
+ }
109
+
110
+ if ((obj.identitySig != null && obj.identitySig.byteLength > 0)) {
111
+ w.uint32(18)
112
+ w.bytes(obj.identitySig)
113
+ }
114
+
115
+ if (obj.extensions != null) {
116
+ w.uint32(34)
117
+ NoiseExtensions.codec().encode(obj.extensions, w)
118
+ }
119
+
120
+ if (opts.lengthDelimited !== false) {
121
+ w.ldelim()
122
+ }
123
+ }, (reader, length, opts = {}) => {
124
+ const obj: any = {
125
+ identityKey: uint8ArrayAlloc(0),
126
+ identitySig: uint8ArrayAlloc(0)
127
+ }
128
+
129
+ const end = length == null ? reader.len : reader.pos + length
130
+
131
+ while (reader.pos < end) {
132
+ const tag = reader.uint32()
133
+
134
+ switch (tag >>> 3) {
135
+ case 1: {
136
+ obj.identityKey = reader.bytes()
137
+ break
138
+ }
139
+ case 2: {
140
+ obj.identitySig = reader.bytes()
141
+ break
142
+ }
143
+ case 4: {
144
+ obj.extensions = NoiseExtensions.codec().decode(reader, reader.uint32(), {
145
+ limits: opts.limits?.extensions
146
+ })
147
+ break
148
+ }
149
+ default: {
150
+ reader.skipType(tag & 7)
151
+ break
152
+ }
153
+ }
154
+ }
155
+
156
+ return obj
157
+ })
158
+ }
159
+
160
+ return _codec
161
+ }
162
+
163
+ export const encode = (obj: Partial<NoiseHandshakePayload>): Uint8Array => {
164
+ return encodeMessage(obj, NoiseHandshakePayload.codec())
165
+ }
166
+
167
+ export const decode = (buf: Uint8Array | Uint8ArrayList, opts?: DecodeOptions<NoiseHandshakePayload>): NoiseHandshakePayload => {
168
+ return decodeMessage(buf, NoiseHandshakePayload.codec(), opts)
169
+ }
170
+ }