NoiseSecretStream
Noise-encrypted duplex stream used for Holepunch peer transports.
Secretstream wraps a transport stream in a Noise handshake plus libsodium secretstream encryption. It is the encrypted stream layer used underneath Hyperswarm and related peer transports. For the upstream package, source, and release notes, see the @hyperswarm/secret-stream repository.
Install
npm i hyperswarm-secret-streamQuickstart
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
Constructor and lifecycle
new SecretStream(isInitiator, [rawStream], [options])
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 | {} |
- Throws: if
isInitiatoris not a boolean.
s.start(rawStream, [options])
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 | {} | Stream options (the same shape as the constructor's). |
- Returns:
void
const s = new SecretStream({
autoStart: false // call start manually
})
// ... do async stuff or destroy the stream
s.start(rawStream, {
... options from above
})await s.flush()
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>—trueonce flushed, orfalseif the stream never opened or was destroyed first.
await stream.flush()Stream configuration
s.setTimeout(ms)
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
stream.setTimeout(15000)s.setKeepAlive(ms)
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
stream.setKeepAlive(5000)s.sendKeepAlive()
A convenience method that sends an empty message.
- Returns:
void
stream.sendKeepAlive()Ordered stream I/O
s.write(data)
Writes an ordered payload to be encrypted and sent through the duplex stream, returning the usual writable-stream backpressure boolean.
s.end()
Ends the stream, optionally writing a final ordered payload, following standard writable-stream behavior.
s.on('data', listener)
Receives ordered decrypted payloads as Buffer instances.
Unordered messages
await s.send(buffer)
Sends an encrypted unordered message, see udx-native 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 | The message to encrypt and send. |
- Returns:
Promise<void>— Resolves once the message has been sent.
await stream.send(Buffer.from('ping'))s.trySend(buffer)
Same as send(buffer) but does not return a promise.
| Parameter | Type | Description |
|---|---|---|
buffer | Buffer | The message to encrypt and send. |
- Returns:
void
stream.trySend(Buffer.from('ping'))s.on('message', onmessage)
Emmitted when an unordered message is received
Utility methods
s.alloc(len)
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— A writable buffer oflenbytes to fill and thenwrite().
const buf = stream.alloc(4)
buf.write('ping')
stream.write(buf)s.toJSON()
Returns a diagnostic object containing connection state, keys, and any serializable raw-stream metadata.
- Returns:
object— A snapshot withisInitiator,publicKey,remotePublicKey,connected,destroying,destroyed, andrawStream.
console.log(JSON.stringify(stream))Static helpers
keyPair = SecretStream.keyPair([seed])
Generate a ed25519 key pair.
NoiseSecretStream.id(handshakeHash, isInitiator, id)
Derives a 32-byte stream identity from the completed handshake hash, choosing the initiator/responder namespace via isInitiator.
| Parameter | Type | Description |
|---|---|---|
handshakeHash | 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 | Optional 32-byte buffer to write the id into; a new one is allocated when omitted. |
- Returns:
Buffer— The 32-byte stream id.
const id = SecretStream.id(stream.handshakeHash, stream.isInitiator)Public properties
s.isInitiator
true on the dialing side and false on the accepting side.
- Returns:
boolean
s.rawStream
The wrapped transport stream, or a bridge stream when no raw stream was supplied up front.
- Returns:
object
s.publicKey
Get the local public key.
- Returns:
Buffer
s.remotePublicKey
Get the remote's public key. Populated after open is emitted.
- Returns:
Buffer
s.handshakeHash
Get the unique hash of this handshake. Populated after open is emitted.
- Returns:
Buffer
s.connected
true once the handshake is complete and the stream has emitted connect.
- Returns:
boolean
s.keepAlive
Get the interval (in milliseconds) at which keep-alive messages are sent (0 means none are sent).
- Returns:
number
s.timeout
The configured idle-timeout interval in milliseconds.
- Returns:
number
s.enableSend
true when unordered send(...) and trySend(...) support is enabled.
- Returns:
boolean
s.opened
A promise that resolves to true when the handshake succeeds, or false if the stream closes before opening.
- Returns:
Promise<boolean>
s.rawBytesWritten
The number of bytes (measured after encryption) written.
- Returns:
number
s.rawBytesRead
The number of bytes (measured before decryption) received.
- Returns:
number
s.userData
An arbitrary user-controlled field that higher-level protocols often use to attach transport metadata.
- Returns:
*
Events
s.on('connect', onconnect)
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)
Fires when the Noise handshake keys and hash have been established.
Types
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 | — | The transmit (encryption) session key. |
rx | Buffer | — | The receive (decryption) session key. |
hash | Buffer | — | The unique hash of the handshake. |
publicKey | Buffer | — | The local public key used in the handshake. |
remotePublicKey | Buffer | — | The remote peer's public key. |
KeyPair
An ed25519 key pair, as produced by {@link NoiseSecretStream.keyPair}.
| Property | Type | Default | Description |
|---|---|---|---|
publicKey | Buffer | — | The 32-byte public key. |
secretKey | Buffer | — | The 64-byte secret key. |
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 | — | The remote peer's public key, set if the handshake pattern requires it. |
keyPair | KeyPair|Promise<KeyPair> | — | The local key pair, or a promise resolving to one (the stream waits for it and auto-destroys if it errors). |
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). |
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
- Hyperswarm—the peer-discovery and connection layer that typically hands sockets to Secretstream.
- HyperDHT—lower-level DHT whose direct keyed connections are also wrapped in Secretstream.
- Protomux—multiplex higher-level protocols across one framed encrypted stream.
- Upstream @hyperswarm/secret-stream repository—source, releases, and implementation details.