# NoiseSecretStream



<Status level="stable" />

`Secretstream` wraps a transport stream in a Noise handshake plus libsodium `secretstream` encryption. It is the encrypted stream layer used underneath [Hyperswarm](/p2p/reference/building-blocks/hyperswarm) and related peer transports. For the upstream package, source, and release notes, see the [@hyperswarm/secret-stream repository](https://github.com/holepunchto/hyperswarm-secret-stream).

## Install [#install]

```sh
npm i @hyperswarm/secret-stream
```

## Quickstart [#quickstart]

```js
import SecretStream from '@hyperswarm/secret-stream'

const a = new SecretStream(true)
const b = new SecretStream(false)

a.rawStream.pipe(b.rawStream).pipe(a.rawStream)

a.write(Buffer.from('hello encrypted world'))

b.on('data', (data) => {
  console.log(data.toString())
})
```

## API Reference [#api-reference]

### Constructor and lifecycle [#constructor-and-lifecycle]

#### `new SecretStream(isInitiator, [rawStream], [options])` [#new-secretstreamisinitiator-rawstream-options]

[src](https://github.com/holepunchto/hyperswarm-secret-stream/blob/v6.9.2/index.js#L16)

Make a new stream. `isInitiator` is a boolean indication whether you are the client or the server. `rawStream` can be set to an underlying transport stream you want to run the noise stream over.

| Parameter     | Type                                          | Default |
| ------------- | --------------------------------------------- | ------- |
| `isInitiator` | `boolean`                                     | —       |
| `rawStream`   | `object`                                      | —       |
| `options`     | [`SecretStreamOptions`](#secretstreamoptions) | `{}`    |

* Throws: if `isInitiator` is not a boolean.

#### `s.start(rawStream, [options])` [#sstartrawstream-options]

[src](https://github.com/holepunchto/hyperswarm-secret-stream/blob/v6.9.2/index.js#L123)

Start a SecretStream from a rawStream asynchrously.

| Parameter   | Type                                          | Default | Description                                                                                            |
| ----------- | --------------------------------------------- | ------- | ------------------------------------------------------------------------------------------------------ |
| `rawStream` | `object`                                      | —       | The underlying transport stream. If omitted, an internal stream is created and exposed as `rawStream`. |
| `options`   | [`SecretStreamOptions`](#secretstreamoptions) | `{}`    | Stream options (the same shape as the constructor's).                                                  |

* Returns: `void`

```js
const s = new SecretStream(true, null, {
  autoStart: false // call start manually
})

// ... do async stuff or destroy the stream

s.start(rawStream, {
  ... options from above
})
```

#### `await s.flush()` [#await-sflush]

[src](https://github.com/holepunchto/hyperswarm-secret-stream/blob/v6.9.2/index.js#L155)

Resolves to `true` when pending encrypted writes and the underlying raw stream have flushed successfully, or `false` if the stream closed before that happened.

* Returns: [`Promise<boolean>`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise) — `true` once flushed, or `false` if the stream never opened or was destroyed first.

```js
await stream.flush()
```

### Stream configuration [#stream-configuration]

#### `s.setTimeout(ms)` [#ssettimeoutms]

[src](https://github.com/holepunchto/hyperswarm-secret-stream/blob/v6.9.2/index.js#L93)

Set the stream timeout. If no data is received within a `ms` window, the stream is auto destroyed.

| Parameter | Type     | Description                                       |
| --------- | -------- | ------------------------------------------------- |
| `ms`      | `number` | The idle timeout in milliseconds (0 disables it). |

* Returns: `void`

```js
stream.setTimeout(15000)
```

#### `s.setKeepAlive(ms)` [#ssetkeepalivems]

[src](https://github.com/holepunchto/hyperswarm-secret-stream/blob/v6.9.2/index.js#L105)

Send a heartbeat (empty message) every time the socket is idle for `ms` milliseconds. Note: If one side calls `s.setKeepAlive()` and the other does not, then the empty messages will be passed through to the piped stream.

| Parameter | Type     | Description                                              |
| --------- | -------- | -------------------------------------------------------- |
| `ms`      | `number` | The keep-alive interval in milliseconds (0 disables it). |

* Returns: `void`

```js
stream.setKeepAlive(5000)
```

#### `s.sendKeepAlive()` [#ssendkeepalive]

[src](https://github.com/holepunchto/hyperswarm-secret-stream/blob/v6.9.2/index.js#L118)

A convenience method that sends an empty message.

* Returns: `void`

```js
stream.sendKeepAlive()
```

### Ordered stream I/O [#ordered-stream-io]

#### `s.write(data)` [#swritedata]

Writes an ordered payload to be encrypted and sent through the duplex stream, returning the usual writable-stream backpressure boolean.

#### `s.end()` [#send]

Ends the stream, optionally writing a final ordered payload, following standard writable-stream behavior.

#### `s.on('data', listener)` [#sondata-listener]

Receives ordered decrypted payloads as `Buffer` instances.

### Unordered messages [#unordered-messages]

#### `await s.send(buffer)` [#await-ssendbuffer]

[src](https://github.com/holepunchto/hyperswarm-secret-stream/blob/v6.9.2/index.js#L564)

Sends an encrypted unordered message, see [udx-native](https://github.com/holepunchto/udx-native/tree/main?tab=readme-ov-file#await-streamsendbuffer) for details. This method silently fails if called before the handshake is complete, or if the underlying `rawStream` is not a UDX stream (not capable of UDP).

| Parameter | Type                                                        | Description                      |
| --------- | ----------------------------------------------------------- | -------------------------------- |
| `buffer`  | [`Buffer`](https://nodejs.org/api/buffer.html#class-buffer) | The message to encrypt and send. |

* Returns: [`Promise<void>`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise) — Resolves once the message has been sent.

```js
await stream.send(Buffer.from('ping'))
```

#### `s.trySend(buffer)` [#strysendbuffer]

[src](https://github.com/holepunchto/hyperswarm-secret-stream/blob/v6.9.2/index.js#L572)

Same as `send(buffer)` but does not return a promise.

| Parameter | Type                                                        | Description                      |
| --------- | ----------------------------------------------------------- | -------------------------------- |
| `buffer`  | [`Buffer`](https://nodejs.org/api/buffer.html#class-buffer) | The message to encrypt and send. |

* Returns: `void`

```js
stream.trySend(Buffer.from('ping'))
```

#### `s.on('message', onmessage)` [#sonmessage-onmessage]

[src](https://github.com/holepunchto/hyperswarm-secret-stream/blob/v6.9.2/index.js#L600)

Emmitted when an unordered message is received

### Utility methods [#utility-methods]

#### `s.alloc(len)` [#salloclen]

[src](https://github.com/holepunchto/hyperswarm-secret-stream/blob/v6.9.2/index.js#L603)

Returns a writable payload slice backed by a preallocated encrypted output buffer. Write into it, then pass it to `stream.write(...)`.

| Parameter | Type     | Description                                |
| --------- | -------- | ------------------------------------------ |
| `len`     | `number` | The number of plaintext bytes to allocate. |

* Returns: [`Buffer`](https://nodejs.org/api/buffer.html#class-buffer) — A writable buffer of `len` bytes to fill and then `write()`.

```js
const buf = stream.alloc(4)
buf.write('ping')
stream.write(buf)
```

#### `s.toJSON()` [#stojson]

[src](https://github.com/holepunchto/hyperswarm-secret-stream/blob/v6.9.2/index.js#L610)

Returns a diagnostic object containing connection state, keys, and any serializable raw-stream metadata.

* Returns: `object` — A snapshot with `isInitiator`, `publicKey`, `remotePublicKey`, `connected`, `destroying`, `destroyed`, and `rawStream`.

```js
console.log(JSON.stringify(stream))
```

### Static helpers [#static-helpers]

#### `keyPair = SecretStream.keyPair([seed])` [#keypair--secretstreamkeypairseed]

Generate a ed25519 key pair.

#### `NoiseSecretStream.id(handshakeHash, isInitiator, id)` [#noisesecretstreamidhandshakehash-isinitiator-id]

[src](https://github.com/holepunchto/hyperswarm-secret-stream/blob/v6.9.2/index.js#L89)

Derives a 32-byte stream identity from the completed handshake hash, choosing the initiator/responder namespace via `isInitiator`.

| Parameter       | Type                                                        | Description                                                                        |
| --------------- | ----------------------------------------------------------- | ---------------------------------------------------------------------------------- |
| `handshakeHash` | [`Buffer`](https://nodejs.org/api/buffer.html#class-buffer) | The handshake hash to derive the id from.                                          |
| `isInitiator`   | `boolean`                                                   | Whether to derive the initiator's id (`true`) or the responder's (`false`).        |
| `id`            | [`Buffer`](https://nodejs.org/api/buffer.html#class-buffer) | Optional 32-byte buffer to write the id into; a new one is allocated when omitted. |

* Returns: [`Buffer`](https://nodejs.org/api/buffer.html#class-buffer) — The 32-byte stream id.

```js
const id = SecretStream.id(stream.handshakeHash, stream.isInitiator)
```

### Public properties [#public-properties]

#### `s.isInitiator` [#sisinitiator]

[src](https://github.com/holepunchto/hyperswarm-secret-stream/blob/v6.9.2/index.js#L24)

`true` on the dialing side and `false` on the accepting side.

* Returns: `boolean`

#### `s.rawStream` [#srawstream]

[src](https://github.com/holepunchto/hyperswarm-secret-stream/blob/v6.9.2/index.js#L25)

The wrapped transport stream, or a bridge stream when no raw stream was supplied up front.

* Returns: `object`

#### `s.publicKey` [#spublickey]

[src](https://github.com/holepunchto/hyperswarm-secret-stream/blob/v6.9.2/index.js#L27)

Get the local public key.

* Returns: [`Buffer`](https://nodejs.org/api/buffer.html#class-buffer)

#### `s.remotePublicKey` [#sremotepublickey]

[src](https://github.com/holepunchto/hyperswarm-secret-stream/blob/v6.9.2/index.js#L28)

Get the remote's public key. Populated after `open` is emitted.

* Returns: [`Buffer`](https://nodejs.org/api/buffer.html#class-buffer)

#### `s.handshakeHash` [#shandshakehash]

[src](https://github.com/holepunchto/hyperswarm-secret-stream/blob/v6.9.2/index.js#L29)

Get the unique hash of this handshake. Populated after `open` is emitted.

* Returns: [`Buffer`](https://nodejs.org/api/buffer.html#class-buffer)

#### `s.connected` [#sconnected]

[src](https://github.com/holepunchto/hyperswarm-secret-stream/blob/v6.9.2/index.js#L30)

`true` once the handshake is complete and the stream has emitted `connect`.

* Returns: `boolean`

#### `s.keepAlive` [#skeepalive]

[src](https://github.com/holepunchto/hyperswarm-secret-stream/blob/v6.9.2/index.js#L31)

Get the interval (in milliseconds) at which keep-alive messages are sent (0 means none are sent).

* Returns: `number`

#### `s.timeout` [#stimeout]

[src](https://github.com/holepunchto/hyperswarm-secret-stream/blob/v6.9.2/index.js#L32)

The configured idle-timeout interval in milliseconds.

* Returns: `number`

#### `s.enableSend` [#senablesend]

[src](https://github.com/holepunchto/hyperswarm-secret-stream/blob/v6.9.2/index.js#L33)

`true` when unordered `send(...)` and `trySend(...)` support is enabled.

* Returns: `boolean`

#### `s.opened` [#sopened]

[src](https://github.com/holepunchto/hyperswarm-secret-stream/blob/v6.9.2/index.js#L39)

A promise that resolves to `true` when the handshake succeeds, or `false` if the stream closes before opening.

* Returns: [`Promise<boolean>`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise)

#### `s.rawBytesWritten` [#srawbyteswritten]

[src](https://github.com/holepunchto/hyperswarm-secret-stream/blob/v6.9.2/index.js#L43)

The number of bytes (measured after encryption) written.

* Returns: `number`

#### `s.rawBytesRead` [#srawbytesread]

[src](https://github.com/holepunchto/hyperswarm-secret-stream/blob/v6.9.2/index.js#L44)

The number of bytes (measured before decryption) received.

* Returns: `number`

#### `s.userData` [#suserdata]

[src](https://github.com/holepunchto/hyperswarm-secret-stream/blob/v6.9.2/index.js#L36)

An arbitrary user-controlled field that higher-level protocols often use to attach transport metadata.

* Returns: `*`

### Events [#events]

#### `s.on('connect', onconnect)` [#sonconnect-onconnect]

[src](https://github.com/holepunchto/hyperswarm-secret-stream/blob/v6.9.2/index.js#L517)

Emitted when the handshake is fully done. It is safe to write to the stream immediately though, as data is buffered internally before the handshake has been completed.

#### `s.on('handshake', listener)` [#sonhandshake-listener]

[src](https://github.com/holepunchto/hyperswarm-secret-stream/blob/v6.9.2/index.js#L390)

Fires when the Noise handshake keys and hash have been established.

## Types [#types]

### Handshake [#handshake]

A precomputed Noise handshake to reuse instead of performing one over the
stream. Pass it as `opts.handshake` to adopt the result of a handshake done
elsewhere.

| Property          | Type                                                        | Default | Description                                 |
| ----------------- | ----------------------------------------------------------- | ------- | ------------------------------------------- |
| `tx`              | [`Buffer`](https://nodejs.org/api/buffer.html#class-buffer) | —       | The transmit (encryption) session key.      |
| `rx`              | [`Buffer`](https://nodejs.org/api/buffer.html#class-buffer) | —       | The receive (decryption) session key.       |
| `hash`            | [`Buffer`](https://nodejs.org/api/buffer.html#class-buffer) | —       | The unique hash of the handshake.           |
| `publicKey`       | [`Buffer`](https://nodejs.org/api/buffer.html#class-buffer) | —       | The local public key used in the handshake. |
| `remotePublicKey` | [`Buffer`](https://nodejs.org/api/buffer.html#class-buffer) | —       | The remote peer's public key.               |

### KeyPair [#keypair]

An ed25519 key pair, as produced by \{@link NoiseSecretStream.keyPair}.

| Property    | Type                                                        | Default | Description             |
| ----------- | ----------------------------------------------------------- | ------- | ----------------------- |
| `publicKey` | [`Buffer`](https://nodejs.org/api/buffer.html#class-buffer) | —       | The 32-byte public key. |
| `secretKey` | [`Buffer`](https://nodejs.org/api/buffer.html#class-buffer) | —       | The 64-byte secret key. |

### SecretStreamOptions [#secretstreamoptions]

Options for creating a `SecretStream` (also accepted by `start()`).

| Property                 | Type                                                        | Default | Description                                                                                                                                                                                                            |
| ------------------------ | ----------------------------------------------------------- | ------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `pattern`                | `string`                                                    | `XX`    | Which Noise handshake pattern to use.                                                                                                                                                                                  |
| `remotePublicKey`        | [`Buffer`](https://nodejs.org/api/buffer.html#class-buffer) | —       | The remote peer's public key, set if the handshake pattern requires it.                                                                                                                                                |
| `keyPair`                | [`KeyPair\|Promise<KeyPair>`](#keypair)                     | —       | The local key pair, or a promise resolving to one (the stream waits for it and auto-destroys if it errors).                                                                                                            |
| `handshake`              | [`Handshake`](#handshake)                                   | —       | A handshake performed elsewhere to adopt instead of handshaking over the stream.                                                                                                                                       |
| `keepAlive`              | `number`                                                    | `0`     | Send a keep-alive (empty message) when idle for this many milliseconds (0 disables).                                                                                                                                   |
| `filterZeroByteMessages` | `boolean`                                                   | `false` | Drop zero-byte messages before they reach the message handler. Also on whenever `keepAlive` is set, so existing keep-alive users keep filtering by default; set this explicitly to filter without enabling keep-alive. |
| `autoStart`              | `boolean`                                                   | `true`  | Start the stream automatically; set false to call `start()` manually.                                                                                                                                                  |
| `enableSend`             | `boolean`                                                   | `true`  | (advanced) Set false to disable the unordered send API.                                                                                                                                                                |

## See also [#see-also]

* [Hyperswarm](/p2p/reference/building-blocks/hyperswarm)—the peer-discovery and connection layer that typically hands sockets to Secretstream.
* [HyperDHT](/p2p/reference/building-blocks/hyperdht)—lower-level DHT whose direct keyed connections are also wrapped in Secretstream.
* [Protomux](/p2p/reference/helpers/protomux)—multiplex higher-level protocols across one framed encrypted stream.
* [Upstream @hyperswarm/secret-stream repository](https://github.com/holepunchto/hyperswarm-secret-stream)—source, releases, and implementation details.
