@libp2p/noise 12.0.1 → 16.1.4-8484de8a2

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 (127) hide show
  1. package/README.md +95 -0
  2. package/dist/index.min.js +16 -20
  3. package/dist/index.min.js.map +7 -0
  4. package/dist/src/constants.d.ts +1 -0
  5. package/dist/src/constants.d.ts.map +1 -1
  6. package/dist/src/constants.js +1 -0
  7. package/dist/src/constants.js.map +1 -1
  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.map +1 -1
  17. package/dist/src/crypto/js.js +18 -17
  18. package/dist/src/crypto/js.js.map +1 -1
  19. package/dist/src/crypto.d.ts +11 -10
  20. package/dist/src/crypto.d.ts.map +1 -1
  21. package/dist/src/crypto.js +10 -1
  22. package/dist/src/crypto.js.map +1 -1
  23. package/dist/src/encoder.d.ts +5 -10
  24. package/dist/src/encoder.d.ts.map +1 -1
  25. package/dist/src/encoder.js +10 -51
  26. package/dist/src/encoder.js.map +1 -1
  27. package/dist/src/errors.d.ts +6 -0
  28. package/dist/src/errors.d.ts.map +1 -0
  29. package/dist/src/errors.js +9 -0
  30. package/dist/src/errors.js.map +1 -0
  31. package/dist/src/index.d.ts +50 -5
  32. package/dist/src/index.d.ts.map +1 -1
  33. package/dist/src/index.js +38 -1
  34. package/dist/src/index.js.map +1 -1
  35. package/dist/src/logger.d.ts +9 -10
  36. package/dist/src/logger.d.ts.map +1 -1
  37. package/dist/src/logger.js +39 -28
  38. package/dist/src/logger.js.map +1 -1
  39. package/dist/src/metrics.d.ts +1 -1
  40. package/dist/src/metrics.d.ts.map +1 -1
  41. package/dist/src/noise.d.ts +33 -30
  42. package/dist/src/noise.d.ts.map +1 -1
  43. package/dist/src/noise.js +122 -78
  44. package/dist/src/noise.js.map +1 -1
  45. package/dist/src/nonce.d.ts +2 -3
  46. package/dist/src/nonce.d.ts.map +1 -1
  47. package/dist/src/nonce.js +3 -2
  48. package/dist/src/nonce.js.map +1 -1
  49. package/dist/src/performHandshake.d.ts +5 -0
  50. package/dist/src/performHandshake.d.ts.map +1 -0
  51. package/dist/src/performHandshake.js +69 -0
  52. package/dist/src/performHandshake.js.map +1 -0
  53. package/dist/src/proto/payload.d.ts +4 -3
  54. package/dist/src/proto/payload.d.ts.map +1 -1
  55. package/dist/src/proto/payload.js +48 -29
  56. package/dist/src/proto/payload.js.map +1 -1
  57. package/dist/src/protocol.d.ts +71 -0
  58. package/dist/src/protocol.d.ts.map +1 -0
  59. package/dist/src/protocol.js +257 -0
  60. package/dist/src/protocol.js.map +1 -0
  61. package/dist/src/types.d.ts +98 -0
  62. package/dist/src/types.d.ts.map +1 -0
  63. package/dist/src/types.js +2 -0
  64. package/dist/src/types.js.map +1 -0
  65. package/dist/src/utils.d.ts +10 -19
  66. package/dist/src/utils.d.ts.map +1 -1
  67. package/dist/src/utils.js +159 -57
  68. package/dist/src/utils.js.map +1 -1
  69. package/package.json +43 -48
  70. package/src/constants.ts +1 -0
  71. package/src/crypto/index.browser.ts +3 -0
  72. package/src/crypto/index.ts +219 -0
  73. package/src/crypto/js.ts +25 -27
  74. package/src/crypto.ts +21 -10
  75. package/src/encoder.ts +10 -67
  76. package/src/errors.ts +10 -0
  77. package/src/index.ts +54 -6
  78. package/src/logger.ts +46 -32
  79. package/src/metrics.ts +1 -1
  80. package/src/noise.ts +176 -131
  81. package/src/nonce.ts +7 -7
  82. package/src/performHandshake.ts +91 -0
  83. package/src/proto/payload.proto +2 -1
  84. package/src/proto/payload.ts +53 -31
  85. package/src/protocol.ts +313 -0
  86. package/src/types.ts +105 -0
  87. package/src/utils.ts +189 -79
  88. package/dist/src/@types/basic.d.ts +0 -5
  89. package/dist/src/@types/basic.d.ts.map +0 -1
  90. package/dist/src/@types/basic.js +0 -2
  91. package/dist/src/@types/basic.js.map +0 -1
  92. package/dist/src/@types/handshake-interface.d.ts +0 -15
  93. package/dist/src/@types/handshake-interface.d.ts.map +0 -1
  94. package/dist/src/@types/handshake-interface.js +0 -2
  95. package/dist/src/@types/handshake-interface.js.map +0 -1
  96. package/dist/src/@types/handshake.d.ts +0 -40
  97. package/dist/src/@types/handshake.d.ts.map +0 -1
  98. package/dist/src/@types/handshake.js +0 -2
  99. package/dist/src/@types/handshake.js.map +0 -1
  100. package/dist/src/@types/libp2p.d.ts +0 -10
  101. package/dist/src/@types/libp2p.d.ts.map +0 -1
  102. package/dist/src/@types/libp2p.js +0 -2
  103. package/dist/src/@types/libp2p.js.map +0 -1
  104. package/dist/src/crypto/streaming.d.ts +0 -7
  105. package/dist/src/crypto/streaming.d.ts.map +0 -1
  106. package/dist/src/crypto/streaming.js +0 -50
  107. package/dist/src/crypto/streaming.js.map +0 -1
  108. package/dist/src/handshake-xx.d.ts +0 -33
  109. package/dist/src/handshake-xx.d.ts.map +0 -1
  110. package/dist/src/handshake-xx.js +0 -139
  111. package/dist/src/handshake-xx.js.map +0 -1
  112. package/dist/src/handshakes/abstract-handshake.d.ts +0 -36
  113. package/dist/src/handshakes/abstract-handshake.d.ts.map +0 -1
  114. package/dist/src/handshakes/abstract-handshake.js +0 -140
  115. package/dist/src/handshakes/abstract-handshake.js.map +0 -1
  116. package/dist/src/handshakes/xx.d.ts +0 -18
  117. package/dist/src/handshakes/xx.d.ts.map +0 -1
  118. package/dist/src/handshakes/xx.js +0 -161
  119. package/dist/src/handshakes/xx.js.map +0 -1
  120. package/src/@types/basic.ts +0 -5
  121. package/src/@types/handshake-interface.ts +0 -12
  122. package/src/@types/handshake.ts +0 -48
  123. package/src/@types/libp2p.ts +0 -10
  124. package/src/crypto/streaming.ts +0 -58
  125. package/src/handshake-xx.ts +0 -177
  126. package/src/handshakes/abstract-handshake.ts +0 -180
  127. package/src/handshakes/xx.ts +0 -184
@@ -1,15 +1,11 @@
1
- /* eslint-disable import/export */
2
- /* eslint-disable complexity */
3
- /* eslint-disable @typescript-eslint/no-namespace */
4
- /* eslint-disable @typescript-eslint/no-unnecessary-boolean-literal-compare */
5
- /* eslint-disable @typescript-eslint/no-empty-interface */
6
-
7
- import { encodeMessage, decodeMessage, message } from 'protons-runtime'
8
- import type { Codec } from 'protons-runtime'
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'
9
4
  import type { Uint8ArrayList } from 'uint8arraylist'
10
5
 
11
6
  export interface NoiseExtensions {
12
7
  webtransportCerthashes: Uint8Array[]
8
+ streamMuxers: string[]
13
9
  }
14
10
 
15
11
  export namespace NoiseExtensions {
@@ -29,12 +25,20 @@ export namespace NoiseExtensions {
29
25
  }
30
26
  }
31
27
 
28
+ if (obj.streamMuxers != null) {
29
+ for (const value of obj.streamMuxers) {
30
+ w.uint32(18)
31
+ w.string(value)
32
+ }
33
+ }
34
+
32
35
  if (opts.lengthDelimited !== false) {
33
36
  w.ldelim()
34
37
  }
35
- }, (reader, length) => {
38
+ }, (reader, length, opts = {}) => {
36
39
  const obj: any = {
37
- webtransportCerthashes: []
40
+ webtransportCerthashes: [],
41
+ streamMuxers: []
38
42
  }
39
43
 
40
44
  const end = length == null ? reader.len : reader.pos + length
@@ -43,12 +47,26 @@ export namespace NoiseExtensions {
43
47
  const tag = reader.uint32()
44
48
 
45
49
  switch (tag >>> 3) {
46
- case 1:
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
+
47
55
  obj.webtransportCerthashes.push(reader.bytes())
48
56
  break
49
- default:
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: {
50
67
  reader.skipType(tag & 7)
51
68
  break
69
+ }
52
70
  }
53
71
  }
54
72
 
@@ -63,8 +81,8 @@ export namespace NoiseExtensions {
63
81
  return encodeMessage(obj, NoiseExtensions.codec())
64
82
  }
65
83
 
66
- export const decode = (buf: Uint8Array | Uint8ArrayList): NoiseExtensions => {
67
- return decodeMessage(buf, NoiseExtensions.codec())
84
+ export const decode = (buf: Uint8Array | Uint8ArrayList, opts?: DecodeOptions<NoiseExtensions>): NoiseExtensions => {
85
+ return decodeMessage(buf, NoiseExtensions.codec(), opts)
68
86
  }
69
87
  }
70
88
 
@@ -84,30 +102,28 @@ export namespace NoiseHandshakePayload {
84
102
  w.fork()
85
103
  }
86
104
 
87
- if (opts.writeDefaults === true || (obj.identityKey != null && obj.identityKey.byteLength > 0)) {
105
+ if ((obj.identityKey != null && obj.identityKey.byteLength > 0)) {
88
106
  w.uint32(10)
89
- w.bytes(obj.identityKey ?? new Uint8Array(0))
107
+ w.bytes(obj.identityKey)
90
108
  }
91
109
 
92
- if (opts.writeDefaults === true || (obj.identitySig != null && obj.identitySig.byteLength > 0)) {
110
+ if ((obj.identitySig != null && obj.identitySig.byteLength > 0)) {
93
111
  w.uint32(18)
94
- w.bytes(obj.identitySig ?? new Uint8Array(0))
112
+ w.bytes(obj.identitySig)
95
113
  }
96
114
 
97
115
  if (obj.extensions != null) {
98
116
  w.uint32(34)
99
- NoiseExtensions.codec().encode(obj.extensions, w, {
100
- writeDefaults: false
101
- })
117
+ NoiseExtensions.codec().encode(obj.extensions, w)
102
118
  }
103
119
 
104
120
  if (opts.lengthDelimited !== false) {
105
121
  w.ldelim()
106
122
  }
107
- }, (reader, length) => {
123
+ }, (reader, length, opts = {}) => {
108
124
  const obj: any = {
109
- identityKey: new Uint8Array(0),
110
- identitySig: new Uint8Array(0)
125
+ identityKey: uint8ArrayAlloc(0),
126
+ identitySig: uint8ArrayAlloc(0)
111
127
  }
112
128
 
113
129
  const end = length == null ? reader.len : reader.pos + length
@@ -116,18 +132,24 @@ export namespace NoiseHandshakePayload {
116
132
  const tag = reader.uint32()
117
133
 
118
134
  switch (tag >>> 3) {
119
- case 1:
135
+ case 1: {
120
136
  obj.identityKey = reader.bytes()
121
137
  break
122
- case 2:
138
+ }
139
+ case 2: {
123
140
  obj.identitySig = reader.bytes()
124
141
  break
125
- case 4:
126
- obj.extensions = NoiseExtensions.codec().decode(reader, reader.uint32())
142
+ }
143
+ case 4: {
144
+ obj.extensions = NoiseExtensions.codec().decode(reader, reader.uint32(), {
145
+ limits: opts.limits?.extensions
146
+ })
127
147
  break
128
- default:
148
+ }
149
+ default: {
129
150
  reader.skipType(tag & 7)
130
151
  break
152
+ }
131
153
  }
132
154
  }
133
155
 
@@ -142,7 +164,7 @@ export namespace NoiseHandshakePayload {
142
164
  return encodeMessage(obj, NoiseHandshakePayload.codec())
143
165
  }
144
166
 
145
- export const decode = (buf: Uint8Array | Uint8ArrayList): NoiseHandshakePayload => {
146
- return decodeMessage(buf, NoiseHandshakePayload.codec())
167
+ export const decode = (buf: Uint8Array | Uint8ArrayList, opts?: DecodeOptions<NoiseHandshakePayload>): NoiseHandshakePayload => {
168
+ return decodeMessage(buf, NoiseHandshakePayload.codec(), opts)
147
169
  }
148
170
  }
@@ -0,0 +1,313 @@
1
+ import { Uint8ArrayList } from 'uint8arraylist'
2
+ import { fromString as uint8ArrayFromString } from 'uint8arrays'
3
+ import { alloc as uint8ArrayAlloc } from 'uint8arrays/alloc'
4
+ import { InvalidCryptoExchangeError } from './errors.js'
5
+ import { Nonce } from './nonce.js'
6
+ import type { ICipherState, ISymmetricState, IHandshakeState, KeyPair, ICrypto } from './types.js'
7
+
8
+ // Code in this file is a direct translation of a subset of the noise protocol https://noiseprotocol.org/noise.html,
9
+ // agnostic to libp2p's usage of noise
10
+
11
+ export const ZEROLEN = uint8ArrayAlloc(0)
12
+
13
+ interface ICipherStateWithKey extends ICipherState {
14
+ k: Uint8Array
15
+ }
16
+
17
+ export class CipherState implements ICipherState {
18
+ public k?: Uint8Array
19
+ public n: Nonce
20
+ private readonly crypto: ICrypto
21
+
22
+ constructor (crypto: ICrypto, k: Uint8Array | undefined = undefined, n = 0) {
23
+ this.crypto = crypto
24
+ this.k = k
25
+ this.n = new Nonce(n)
26
+ }
27
+
28
+ public hasKey (): this is ICipherStateWithKey {
29
+ return Boolean(this.k)
30
+ }
31
+
32
+ public encryptWithAd (ad: Uint8Array, plaintext: Uint8Array | Uint8ArrayList): Uint8Array | Uint8ArrayList {
33
+ if (!this.hasKey()) {
34
+ return plaintext
35
+ }
36
+
37
+ this.n.assertValue()
38
+ const e = this.crypto.encrypt(plaintext, this.n.getBytes(), ad, this.k)
39
+ this.n.increment()
40
+
41
+ return e
42
+ }
43
+
44
+ public decryptWithAd (ad: Uint8Array, ciphertext: Uint8Array | Uint8ArrayList, dst?: Uint8Array): Uint8Array | Uint8ArrayList {
45
+ if (!this.hasKey()) {
46
+ return ciphertext
47
+ }
48
+
49
+ this.n.assertValue()
50
+ const plaintext = this.crypto.decrypt(ciphertext, this.n.getBytes(), ad, this.k, dst)
51
+ this.n.increment()
52
+
53
+ return plaintext
54
+ }
55
+ }
56
+
57
+ export class SymmetricState implements ISymmetricState {
58
+ public cs: CipherState
59
+ public ck: Uint8Array
60
+ public h: Uint8Array
61
+ private readonly crypto: ICrypto
62
+
63
+ constructor (crypto: ICrypto, protocolName: string) {
64
+ this.crypto = crypto
65
+
66
+ const protocolNameBytes = uint8ArrayFromString(protocolName, 'utf-8')
67
+ this.h = hashProtocolName(crypto, protocolNameBytes)
68
+
69
+ this.ck = this.h
70
+ this.cs = new CipherState(crypto)
71
+ }
72
+
73
+ public mixKey (ikm: Uint8Array): void {
74
+ const [ck, tempK] = this.crypto.hkdf(this.ck, ikm)
75
+ this.ck = ck
76
+ this.cs = new CipherState(this.crypto, tempK)
77
+ }
78
+
79
+ public mixHash (data: Uint8Array | Uint8ArrayList): void {
80
+ this.h = this.crypto.hash(new Uint8ArrayList(this.h, data))
81
+ }
82
+
83
+ public encryptAndHash (plaintext: Uint8Array | Uint8ArrayList): Uint8Array | Uint8ArrayList {
84
+ const ciphertext = this.cs.encryptWithAd(this.h, plaintext)
85
+ this.mixHash(ciphertext)
86
+ return ciphertext
87
+ }
88
+
89
+ public decryptAndHash (ciphertext: Uint8Array | Uint8ArrayList): Uint8Array | Uint8ArrayList {
90
+ const plaintext = this.cs.decryptWithAd(this.h, ciphertext)
91
+ this.mixHash(ciphertext)
92
+ return plaintext
93
+ }
94
+
95
+ public split (): [CipherState, CipherState] {
96
+ const [tempK1, tempK2] = this.crypto.hkdf(this.ck, ZEROLEN)
97
+ return [new CipherState(this.crypto, tempK1), new CipherState(this.crypto, tempK2)]
98
+ }
99
+ }
100
+
101
+ // const MESSAGE_PATTERNS = ['e', 's', 'ee', 'es', 'se', 'ss'] as const
102
+ // type MessagePattern = Array<typeof MESSAGE_PATTERNS[number]>
103
+
104
+ export interface HandshakeStateInit {
105
+ crypto: ICrypto
106
+ protocolName: string
107
+ initiator: boolean
108
+ prologue: Uint8Array
109
+ s?: KeyPair
110
+ e?: KeyPair
111
+ rs?: Uint8Array | Uint8ArrayList
112
+ re?: Uint8Array | Uint8ArrayList
113
+ }
114
+
115
+ export abstract class AbstractHandshakeState implements IHandshakeState {
116
+ public ss: SymmetricState
117
+ public s?: KeyPair
118
+ public e?: KeyPair
119
+ public rs?: Uint8Array | Uint8ArrayList
120
+ public re?: Uint8Array | Uint8ArrayList
121
+ public initiator: boolean
122
+ protected readonly crypto: ICrypto
123
+
124
+ constructor (init: HandshakeStateInit) {
125
+ const { crypto, protocolName, prologue, initiator, s, e, rs, re } = init
126
+ this.crypto = crypto
127
+ this.ss = new SymmetricState(crypto, protocolName)
128
+ this.ss.mixHash(prologue)
129
+ this.initiator = initiator
130
+ this.s = s
131
+ this.e = e
132
+ this.rs = rs
133
+ this.re = re
134
+ }
135
+
136
+ protected writeE (): Uint8Array {
137
+ if (this.e) {
138
+ throw new Error('ephemeral keypair is already set')
139
+ }
140
+ const e = this.crypto.generateKeypair()
141
+ this.ss.mixHash(e.publicKey)
142
+ this.e = e
143
+ return e.publicKey
144
+ }
145
+
146
+ protected writeS (): Uint8Array | Uint8ArrayList {
147
+ if (!this.s) {
148
+ throw new Error('static keypair is not set')
149
+ }
150
+ return this.ss.encryptAndHash(this.s.publicKey)
151
+ }
152
+
153
+ protected writeEE (): void {
154
+ if (!this.e) {
155
+ throw new Error('ephemeral keypair is not set')
156
+ }
157
+ if (!this.re) {
158
+ throw new Error('remote ephemeral public key is not set')
159
+ }
160
+ this.ss.mixKey(this.crypto.dh(this.e, this.re))
161
+ }
162
+
163
+ protected writeES (): void {
164
+ if (this.initiator) {
165
+ if (!this.e) {
166
+ throw new Error('ephemeral keypair is not set')
167
+ }
168
+ if (!this.rs) {
169
+ throw new Error('remote static public key is not set')
170
+ }
171
+ this.ss.mixKey(this.crypto.dh(this.e, this.rs))
172
+ } else {
173
+ if (!this.s) {
174
+ throw new Error('static keypair is not set')
175
+ }
176
+ if (!this.re) {
177
+ throw new Error('remote ephemeral public key is not set')
178
+ }
179
+ this.ss.mixKey(this.crypto.dh(this.s, this.re))
180
+ }
181
+ }
182
+
183
+ protected writeSE (): void {
184
+ if (this.initiator) {
185
+ if (!this.s) {
186
+ throw new Error('static keypair is not set')
187
+ }
188
+ if (!this.re) {
189
+ throw new Error('remote ephemeral public key is not set')
190
+ }
191
+ this.ss.mixKey(this.crypto.dh(this.s, this.re))
192
+ } else {
193
+ if (!this.e) {
194
+ throw new Error('ephemeral keypair is not set')
195
+ }
196
+ if (!this.rs) {
197
+ throw new Error('remote static public key is not set')
198
+ }
199
+ this.ss.mixKey(this.crypto.dh(this.e, this.rs))
200
+ }
201
+ }
202
+
203
+ protected readE (message: Uint8ArrayList, offset = 0): void {
204
+ if (this.re) {
205
+ throw new Error('remote ephemeral public key is already set')
206
+ }
207
+ if (message.byteLength < offset + 32) {
208
+ throw new Error('message is not long enough')
209
+ }
210
+ this.re = message.sublist(offset, offset + 32)
211
+ this.ss.mixHash(this.re)
212
+ }
213
+
214
+ protected readS (message: Uint8ArrayList, offset = 0): number {
215
+ if (this.rs) {
216
+ throw new Error('remote static public key is already set')
217
+ }
218
+ const cipherLength = 32 + (this.ss.cs.hasKey() ? 16 : 0)
219
+ if (message.byteLength < offset + cipherLength) {
220
+ throw new Error('message is not long enough')
221
+ }
222
+ const temp = message.sublist(offset, offset + cipherLength)
223
+ this.rs = this.ss.decryptAndHash(temp)
224
+ return cipherLength
225
+ }
226
+
227
+ protected readEE (): void {
228
+ this.writeEE()
229
+ }
230
+
231
+ protected readES (): void {
232
+ this.writeES()
233
+ }
234
+
235
+ protected readSE (): void {
236
+ this.writeSE()
237
+ }
238
+ }
239
+
240
+ /**
241
+ * A IHandshakeState that's optimized for the XX pattern
242
+ */
243
+ export class XXHandshakeState extends AbstractHandshakeState {
244
+ // e
245
+ writeMessageA (payload: Uint8Array | Uint8ArrayList): Uint8Array | Uint8ArrayList {
246
+ return new Uint8ArrayList(this.writeE(), this.ss.encryptAndHash(payload))
247
+ }
248
+
249
+ // e, ee, s, es
250
+ writeMessageB (payload: Uint8Array | Uint8ArrayList): Uint8Array | Uint8ArrayList {
251
+ const e = this.writeE()
252
+ this.writeEE()
253
+ const encS = this.writeS()
254
+ this.writeES()
255
+
256
+ return new Uint8ArrayList(e, encS, this.ss.encryptAndHash(payload))
257
+ }
258
+
259
+ // s, se
260
+ writeMessageC (payload: Uint8Array | Uint8ArrayList): Uint8Array | Uint8ArrayList {
261
+ const encS = this.writeS()
262
+ this.writeSE()
263
+
264
+ return new Uint8ArrayList(encS, this.ss.encryptAndHash(payload))
265
+ }
266
+
267
+ // e
268
+ readMessageA (message: Uint8ArrayList): Uint8Array | Uint8ArrayList {
269
+ try {
270
+ this.readE(message)
271
+
272
+ return this.ss.decryptAndHash(message.sublist(32))
273
+ } catch (e) {
274
+ throw new InvalidCryptoExchangeError(`handshake stage 0 validation fail: ${(e as Error).message}`)
275
+ }
276
+ }
277
+
278
+ // e, ee, s, es
279
+ readMessageB (message: Uint8ArrayList): Uint8Array | Uint8ArrayList {
280
+ try {
281
+ this.readE(message)
282
+ this.readEE()
283
+ const consumed = this.readS(message, 32)
284
+ this.readES()
285
+
286
+ return this.ss.decryptAndHash(message.sublist(32 + consumed))
287
+ } catch (e) {
288
+ throw new InvalidCryptoExchangeError(`handshake stage 1 validation fail: ${(e as Error).message}`)
289
+ }
290
+ }
291
+
292
+ // s, se
293
+ readMessageC (message: Uint8ArrayList): Uint8Array | Uint8ArrayList {
294
+ try {
295
+ const consumed = this.readS(message)
296
+ this.readSE()
297
+
298
+ return this.ss.decryptAndHash(message.sublist(consumed))
299
+ } catch (e) {
300
+ throw new InvalidCryptoExchangeError(`handshake stage 2 validation fail: ${(e as Error).message}`)
301
+ }
302
+ }
303
+ }
304
+
305
+ function hashProtocolName (crypto: ICrypto, protocolName: Uint8Array): Uint8Array {
306
+ if (protocolName.length <= 32) {
307
+ const h = uint8ArrayAlloc(32)
308
+ h.set(protocolName)
309
+ return h
310
+ } else {
311
+ return crypto.hash(protocolName)
312
+ }
313
+ }
package/src/types.ts ADDED
@@ -0,0 +1,105 @@
1
+ import type { Nonce } from './nonce.js'
2
+ import type { NoiseExtensions, NoiseHandshakePayload } from './proto/payload.js'
3
+ import type { ConnectionEncrypter, Logger, PrivateKey, PublicKey } from '@libp2p/interface'
4
+ import type { LengthPrefixedStream } from '@libp2p/utils'
5
+ import type { Uint8ArrayList } from 'uint8arraylist'
6
+
7
+ /**
8
+ * Crypto functions defined by the noise protocol, abstracted from the
9
+ * underlying implementations
10
+ */
11
+ export interface ICrypto {
12
+ generateKeypair(): KeyPair
13
+ dh(keypair: KeyPair, publicKey: Uint8Array | Uint8ArrayList): Uint8Array
14
+ encrypt(plaintext: Uint8Array | Uint8ArrayList, nonce: Uint8Array, ad: Uint8Array, k: Uint8Array): Uint8ArrayList | Uint8Array
15
+ decrypt(ciphertext: Uint8Array | Uint8ArrayList, nonce: Uint8Array, ad: Uint8Array, k: Uint8Array, dst?: Uint8Array): Uint8ArrayList | Uint8Array
16
+ hash(data: Uint8Array | Uint8ArrayList): Uint8Array
17
+ hkdf(ck: Uint8Array, ikm: Uint8Array): [Uint8Array, Uint8Array, Uint8Array]
18
+ }
19
+
20
+ export interface HandshakeParams {
21
+ log: Logger
22
+ connection: LengthPrefixedStream
23
+ crypto: ICrypto
24
+ privateKey: PrivateKey
25
+ prologue: Uint8Array
26
+ /** static keypair */
27
+ s: KeyPair
28
+ remoteIdentityKey?: PublicKey
29
+ extensions?: NoiseExtensions
30
+ }
31
+
32
+ export interface HandshakeResult {
33
+ payload: NoiseHandshakePayload
34
+ encrypt (plaintext: Uint8Array | Uint8ArrayList): Uint8Array | Uint8ArrayList
35
+ decrypt (ciphertext: Uint8Array | Uint8ArrayList, dst?: Uint8Array): Uint8Array | Uint8ArrayList
36
+ }
37
+
38
+ /**
39
+ * A CipherState object contains k and n variables, which it uses to encrypt and
40
+ * decrypt ciphertext.
41
+ *
42
+ * During the handshake phase each party has a single CipherState, but during
43
+ * the transport phase each party has two CipherState objects: one for sending,
44
+ * and one for receiving.
45
+ */
46
+ export interface ICipherState {
47
+ /**
48
+ * A cipher key of 32 bytes (which may be empty). Empty is a special value
49
+ * which indicates k has not yet been initialized.
50
+ */
51
+ k?: Uint8Array
52
+ /**
53
+ * An 8-byte (64-bit) unsigned integer nonce.
54
+ *
55
+ * For performance reasons, the nonce is represented as a Nonce object
56
+ * The nonce is treated as a uint64, even though the underlying `number` only
57
+ * has 52 safely-available bits.
58
+ */
59
+ n: Nonce
60
+ }
61
+
62
+ /**
63
+ * A SymmetricState object contains a CipherState plus ck and h variables. It is
64
+ * so-named because it encapsulates all the "symmetric crypto" used by Noise.
65
+ *
66
+ * During the handshake phase each party has a single SymmetricState, which can
67
+ * be deleted once the handshake is finished.
68
+ */
69
+ export interface ISymmetricState {
70
+ cs: ICipherState
71
+ /** A chaining key of 32 bytes. */
72
+ ck: Uint8Array
73
+ /** A hash output of 32 bytes. */
74
+ h: Uint8Array
75
+ }
76
+
77
+ /**
78
+ * A HandshakeState object contains a SymmetricState plus DH variables (s, e,
79
+ * rs, re) and a variable representing the handshake pattern.
80
+ *
81
+ * During the handshake phase each party has a single HandshakeState, which can
82
+ * be deleted once the handshake is finished.
83
+ */
84
+ export interface IHandshakeState {
85
+ ss: ISymmetricState
86
+ /** The local static key pair */
87
+ s?: KeyPair
88
+ /** The local ephemeral key pair */
89
+ e?: KeyPair
90
+ /** The remote party's static public key */
91
+ rs?: Uint8Array | Uint8ArrayList
92
+ /** The remote party's ephemeral public key */
93
+ re?: Uint8Array | Uint8ArrayList
94
+ }
95
+
96
+ export interface KeyPair {
97
+ publicKey: Uint8Array
98
+ privateKey: Uint8Array
99
+ }
100
+
101
+ export interface INoiseExtensions {
102
+ webtransportCerthashes: Uint8Array[]
103
+ }
104
+
105
+ export interface INoiseConnection extends ConnectionEncrypter<INoiseExtensions> { }