This commit is contained in:
Raven Scott
2026-05-20 23:36:32 -04:00
parent a020270cb1
commit be94546cd3
218 changed files with 9189 additions and 3078 deletions
@@ -1,34 +1,92 @@
# hyper-p2p-encrypted-topic
Production module: Topic encryption demo.
Register topics with a `keyHint`, derive a symmetric key, XOR-encrypt payloads; gossip topic registration (hint only).
**Protocol:** `encrypted-topic/v1`
**Category:** trust-security · **Protocol:** `encrypted-topic/v1` · **Exports:** `HyperP2PEncryptedTopic`, `PROTOCOL`, `deriveKey`, `xorCrypt`
## When to use
Topic-scoped payload crypto.
Lightweight obfuscation keyed by shared hint on a mesh (not a substitute for Noise).
## When not to use
Production AEAD.
Production confidentiality without real AEAD/Noise.
## Quick start
```js
const { HyperP2PEncryptedTopic } = require('hyper-p2p-encrypted-topic')
const m = new HyperP2PEncryptedTopic()
m.registerTopic('t','hint')
await m.ready()
await m.close()
const enc = new HyperP2PEncryptedTopic({ topic: 'secure' })
await enc.ready()
enc.registerTopic('private-feed', 'shared-secret-hint')
const cipher = enc.encryptPayload('private-feed', 'hello')
console.log(enc.decryptPayload('private-feed', cipher).toString())
await enc.close()
```
## Docs
- [docs/api.md](docs/api.md)
- [docs/architecture.md](docs/architecture.md)
- [docs/api.md](docs/api.md) · [docs/architecture.md](docs/architecture.md)
## Test
```bash
npm install && npm test
npm test
```
## API
| Member | Description |
|--------|-------------|
| `new HyperP2PEncryptedTopic(opts?)` | `topic`, `keyPair`. |
| `registerTopic(topicId, keyHint)` | `key = hash(keyHint)`; gossips `topic-register`. |
| `encryptPayload(topicId, data)` | Buffer or encodable; returns cipher buffer. |
| `decryptPayload(topicId, buf)` | XOR decrypt; requires registered topic. |
| `deriveKey(hint)` / `xorCrypt(keyBuf, dataBuf)` | Low-level helpers (exported). |
| `getStats()` | `{ registered, encrypted, decrypted, gossipIn, gossipOut, topics, protocol }`. |
| `ready()` / `close()` | Swarm lifecycle. |
**Events:** `registered`, `closed`. Remote register fills map if `topicId` new.
## Architecture
```
_topics Map(topicId -> { keyHint, key, registeredAt })
deriveKey: hypercore-crypto.hash(b4a.from(String(hint)))
xorCrypt: repeating-key XOR byte-wise
```
Peers must use same `keyHint` for a `topicId` to decrypt. Gossip shares hint, not key bytes.
## Wire table
| `type` | Fields | Direction |
|--------|--------|-----------|
| `topic-register` | `topicId`, `keyHint` | Any → all |
## Errors
- Unregistered `topicId` on encrypt/decrypt throws `topic not registered`.
- `decryptPayload`: non-buffer input throws.
- Empty `topicId` / `keyHint` on register.
## Composition
- XOR is not AEAD—layer Noise or app crypto for real secrecy.
- Same `keyHint` across peers required; rotate via `hyper-p2p-key-rotation` on hint strings.
- Gossip does not re-broadcast ciphertext—only registration.
## Example
```js
const { HyperP2PEncryptedTopic } = require('hyper-p2p-encrypted-topic')
const enc = new HyperP2PEncryptedTopic({ topic: process.argv[2] })
await enc.ready()
enc.registerTopic('private-feed', 'shared-secret-hint')
const cipher = enc.encryptPayload('private-feed', 'hello')
const plain = enc.decryptPayload('private-feed', cipher)
console.log(plain.toString())
await enc.close()
```
@@ -1,26 +1,91 @@
# API: hyper-p2p-encrypted-topic
**Protocol:** `encrypted-topic/v1` · **Export:** `HyperP2PEncryptedTopic`
**Protocol:** `encrypted-topic/v1` · **Export:** `HyperP2PEncryptedTopic`, `PROTOCOL`, `deriveKey`, `xorCrypt`
## Overview
Registers logical topics with a `keyHint`, derives a symmetric key via `hypercore-crypto.hash`, and XOR-encrypts payloads. Gossips `topic-register` so peers learn hints (not raw keys — key re-derived locally).
## Constructor
| Option | Type | Default | Description |
|--------|------|---------|-------------|
| `topic` | `string` \| `Buffer` | `null` | Swarm topic |
| `keyPair` | `KeyPair` | random | Swarm identity |
## Methods
### `registerTopic(...)`
### `registerTopic(topicId, keyHint)`
Domain API.
- **Returns:** `{ topicId, keyHint, key, registeredAt }`
- **Throws:** `assertNonEmpty` on both args
- **Gossip:** `{ type: 'topic-register', topicId, keyHint }`
- **Emits:** `registered` `{ topicId, keyHint }`
### `encryptPayload(...)`
### `encryptPayload(topicId, data)`
Domain API.
- **Returns:** Buffer cipher
- **Throws:** `topic not registered: ${topicId}`
### `decryptPayload(...)`
### `decryptPayload(topicId, buf)`
Domain API.
- **Returns:** plain Buffer
- **Throws:** `buf must be a buffer`; `topic not registered: ${topicId}`
### `ready()` / `close()`
### `getStats()` / `ready()` / `close()`
Standard swarm.
Lifecycle helpers.
## Events
| Event | Payload |
|-------|---------|
| `registered` | `{ topicId, keyHint }` |
| `closed` | — |
## getStats()
`registered`, `encrypted`, `decrypted`, `gossipIn`, `gossipOut`, `topics`, `protocol`.
## Wire
| type | fields | behavior |
|------|--------|----------|
| `topic-register` | `topicId`, `keyHint` | Insert topic if unknown; derive key |
## Errors
Registration and buffer errors above. Uses `assertNonEmpty` from shared errors.
See [`../../_shared/ERROR_CODES.md`](../../_shared/ERROR_CODES.md).
## P2P
Joins Hyperswarm when `topic` is set.
XOR is not authenticated encryption — use for obfuscation/lightweight topic privacy only.
## Testing
```bash
cd modules/trust-security/hyper-p2p-encrypted-topic && npm test
```
## Composition
`hyper-p2p-topic-announcer`, `hyper-p2p-key-rotation`, `hyper-p2p-session-rotation`.
## Example
See [`examples/basic.js`](../examples/basic.js).
## Remote merge rules
- `topic-register` only inserts when `topicId` not already local
- Remote peers re-derive `key` from gossiped `keyHint` (never send raw key)
## Lifecycle
Encrypt/decrypt increment `encrypted` / `decrypted` stats per operation.
## See also
[`docs/architecture.md`](architecture.md), [`../../MODULE_CATEGORIES.md`](../../MODULE_CATEGORIES.md).
@@ -1,11 +1,22 @@
# Architecture: hyper-p2p-encrypted-topic
**Protocol:** `encrypted-topic/v1` · **Category:** trust-security
## Wire messages
| type | fields | direction | behavior |
|------|--------|-----------|----------|
| `topic-register` | topicId, keyHint | gossip | Register |
| type | direction | fields | behavior |
|------|-----------|--------|----------|
| `topic-register` | gossip | `topicId`, `keyHint` | Store topic; `deriveKey(keyHint)` locally |
## State
## State model
In-memory structures; gossip via `initModuleSwarm` / `gossipSend` when P2P enabled.
`_topics`: Map topicId → `{ topicId, keyHint, key, registeredAt }`.
## Helpers
- `deriveKey(hint)``crypto.hash(b4a.from(String(hint)))`
- `xorCrypt(keyBuf, dataBuf)` — byte XOR stream cipher
## Composition
`hyper-p2p-key-rotation`, `hyper-p2p-topic-announcer`.