{"_id":"@corvidlabs/ts-algochat","_rev":"4-42fff9dbc507c1bd551f5212d3c294cd","name":"@corvidlabs/ts-algochat","dist-tags":{"latest":"0.4.0"},"versions":{"0.1.1":{"name":"@corvidlabs/ts-algochat","version":"0.1.1","keywords":["algorand","encryption","messaging","blockchain","chacha20","x25519","end-to-end","crypto"],"author":{"name":"CorvidLabs"},"license":"MIT","_id":"@corvidlabs/ts-algochat@0.1.1","maintainers":[{"name":"gasparzinho","email":"bruno.placides@proton.me"}],"homepage":"https://github.com/CorvidLabs/ts-algochat#readme","bugs":{"url":"https://github.com/CorvidLabs/ts-algochat/issues"},"dist":{"shasum":"9753915288c5cda2bf5565e101a9d895f87100f3","tarball":"https://registry.npmjs.org/@corvidlabs/ts-algochat/-/ts-algochat-0.1.1.tgz","fileCount":198,"integrity":"sha512-lw98bp5AWxCmowjvZP/juJxPpNmMS79Jl/NOMQ/7jesM2v9sx1VzWE1bdIbLExvSaQXSMkrag36nym5bPH8wPw==","signatures":[{"sig":"MEYCIQCT8p0ifre+4XkCz1N+CaXU7sIkKEqedOiHBn5kld9auAIhAPaqOBANKEqJahe03yQ+Xe/akUGVTU10Mg6h0Fv+dKFR","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":583620},"main":"dist/index.js","type":"module","types":"dist/index.d.ts","engines":{"node":">=18.0.0"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"}},"gitHead":"dee40710073e3a7b8e11f771c0a98a5872fee3d9","scripts":{"dev":"bun run tsc --watch","test":"bun test","build":"bun run tsc","clean":"rm -rf dist","prepublishOnly":"bun run build"},"_npmUser":{"name":"gasparzinho","email":"bruno.placides@proton.me"},"repository":{"url":"git+https://github.com/CorvidLabs/ts-algochat.git","type":"git"},"_npmVersion":"10.9.3","description":"TypeScript implementation of the AlgoChat protocol for encrypted messaging on Algorand","directories":{},"_nodeVersion":"22.20.0","dependencies":{"algosdk":"^3.0.0","@noble/curves":"^1.7.0","@noble/hashes":"^1.6.0","@noble/ciphers":"^1.0.0"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"packageManager":"bun@1.3.6","devDependencies":{"@types/bun":"^1.1.0","typescript":"^5.7.0"},"_npmOperationalInternal":{"tmp":"tmp/ts-algochat_0.1.1_1769365091285_0.05783034135570064","host":"s3://npm-registry-packages-npm-production"}},"0.2.0":{"name":"@corvidlabs/ts-algochat","version":"0.2.0","keywords":["algorand","encryption","messaging","blockchain","chacha20","x25519","end-to-end","crypto"],"author":{"name":"CorvidLabs"},"license":"MIT","_id":"@corvidlabs/ts-algochat@0.2.0","maintainers":[{"name":"gasparzinho","email":"bruno.placides@proton.me"}],"homepage":"https://github.com/CorvidLabs/ts-algochat#readme","bugs":{"url":"https://github.com/CorvidLabs/ts-algochat/issues"},"dist":{"shasum":"d3cf50bce5de1b8aa879f0dedb9caaf0c7d1840b","tarball":"https://registry.npmjs.org/@corvidlabs/ts-algochat/-/ts-algochat-0.2.0.tgz","fileCount":238,"integrity":"sha512-d13wBrBrWVMMs4lkZkydqP2v60kb66PtO+Ds+qOUSzEiMZKIEda1t0+JDGFAgqri0Co01oLY/8TR4ALcpiisXw==","signatures":[{"sig":"MEQCIEl6ss7It3irnthwkW2bnOc3bKO+8OMFOWIs9suRiQkJAiAGwWOCSQTIDVzfz3t0MviSmmSCctRU7bidInG3xruGkQ==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":702587},"main":"dist/index.js","type":"module","types":"dist/index.d.ts","engines":{"node":">=18.0.0"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"}},"gitHead":"0e060365f5d5726cd0499329144a2cc715424243","scripts":{"dev":"bun run tsc --watch","test":"bun test","build":"bun run tsc","clean":"rm -rf dist","prepublishOnly":"bun run build"},"_npmUser":{"name":"gasparzinho","email":"bruno.placides@proton.me"},"repository":{"url":"git+https://github.com/CorvidLabs/ts-algochat.git","type":"git"},"_npmVersion":"10.9.3","description":"TypeScript implementation of the AlgoChat protocol for encrypted messaging on Algorand","directories":{},"_nodeVersion":"22.20.0","dependencies":{"algosdk":"^3.0.0","@noble/curves":"^1.7.0","@noble/hashes":"^1.6.0","@noble/ciphers":"^1.0.0"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"packageManager":"bun@1.3.6","devDependencies":{"@types/bun":"^1.1.0","typescript":"^5.7.0"},"_npmOperationalInternal":{"tmp":"tmp/ts-algochat_0.2.0_1769646631090_0.9830338746420875","host":"s3://npm-registry-packages-npm-production"}},"0.3.0":{"name":"@corvidlabs/ts-algochat","version":"0.3.0","keywords":["algorand","encryption","messaging","blockchain","chacha20","x25519","end-to-end","crypto"],"author":{"name":"CorvidLabs"},"license":"MIT","_id":"@corvidlabs/ts-algochat@0.3.0","maintainers":[{"name":"gasparzinho","email":"bruno.placides@proton.me"}],"homepage":"https://github.com/CorvidLabs/ts-algochat#readme","bugs":{"url":"https://github.com/CorvidLabs/ts-algochat/issues"},"dist":{"shasum":"c11e32257ff524bae4a5723c4eef49c418333ba4","tarball":"https://registry.npmjs.org/@corvidlabs/ts-algochat/-/ts-algochat-0.3.0.tgz","fileCount":238,"integrity":"sha512-M8uTtZW+yuxWw077lMecGB/bqmHRXxAp9Uw/MF9PWg9YCHfXzLj58jdp9HVLjiXyMkBf9QNamAMQbFY/LoMqog==","signatures":[{"sig":"MEYCIQDthsbvzZPzFnvQlMrghZJkoC8Ak7O30U2Y6LPHzkuNtQIhAMxlr5dwzXN9v2B4jmWS/gL05ZGRpLxGx2OWmWnfl4Pl","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":726956},"main":"dist/index.js","type":"module","types":"dist/index.d.ts","engines":{"node":">=18.0.0"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"}},"gitHead":"051e928818f37204f2a9260c57b4b79fe927bff0","scripts":{"dev":"bun run tsc --watch","test":"bun test","build":"bun run tsc","clean":"rm -rf dist","prepublishOnly":"bun run build"},"_npmUser":{"name":"gasparzinho","email":"bruno.placides@proton.me"},"repository":{"url":"git+https://github.com/CorvidLabs/ts-algochat.git","type":"git"},"_npmVersion":"10.9.4","description":"TypeScript implementation of the AlgoChat protocol for encrypted messaging on Algorand","directories":{},"_nodeVersion":"22.22.0","dependencies":{"algosdk":"^3.0.0","@noble/curves":"^1.7.0","@noble/hashes":"^1.6.0","@noble/ciphers":"^1.0.0"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"packageManager":"bun@1.3.6","devDependencies":{"@types/bun":"^1.1.0","typescript":"^5.7.0"},"_npmOperationalInternal":{"tmp":"tmp/ts-algochat_0.3.0_1770433005780_0.5977784331521176","host":"s3://npm-registry-packages-npm-production"}},"0.4.0":{"name":"@corvidlabs/ts-algochat","version":"0.4.0","description":"TypeScript implementation of the AlgoChat protocol for encrypted messaging on Algorand","type":"module","main":"dist/index.js","types":"dist/index.d.ts","exports":{".":{"import":"./dist/index.js","types":"./dist/index.d.ts"}},"scripts":{"build":"bun run tsc","dev":"bun run tsc --watch","test":"bun test","clean":"rm -rf dist","prepublishOnly":"bun run build"},"packageManager":"bun@1.3.6","dependencies":{"@noble/ciphers":"^1.0.0","@noble/curves":"^1.7.0","@noble/hashes":"^1.6.0","algosdk":"^3.0.0"},"devDependencies":{"@types/bun":"^1.1.0","typescript":"^5.7.0"},"keywords":["algorand","encryption","messaging","blockchain","chacha20","x25519","end-to-end","crypto"],"author":{"name":"CorvidLabs"},"license":"MIT","repository":{"type":"git","url":"git+https://github.com/CorvidLabs/ts-algochat.git"},"homepage":"https://github.com/CorvidLabs/ts-algochat#readme","bugs":{"url":"https://github.com/CorvidLabs/ts-algochat/issues"},"engines":{"node":">=18.0.0"},"publishConfig":{"access":"public"},"_id":"@corvidlabs/ts-algochat@0.4.0","gitHead":"cfb002a6c29026650b27c7856372f0e97fd82d75","_nodeVersion":"22.22.0","_npmVersion":"10.9.4","dist":{"integrity":"sha512-vkzjsSWL6niKOnsU8Vd6tbDjWcHJOUE5Mqwjme80pWLHrRVU9K3F5msb9YMnOUGIqC8l2WquSGqTIlAb9e9Dlg==","shasum":"b5ec622e3950164f37cb2de016e61f5bc3f42067","tarball":"https://registry.npmjs.org/@corvidlabs/ts-algochat/-/ts-algochat-0.4.0.tgz","fileCount":263,"unpackedSize":945377,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIBvzOaYnN7vELSudVdNt2ITWLD/J22IVt7t+WBYbZyngAiEA56NZm1pkQoPcZDBDf1vhtRVCbQi7jjNFqt6hFjIQmnU="}]},"_npmUser":{"name":"gasparzinho","email":"bruno.placides@proton.me"},"directories":{},"maintainers":[{"name":"gasparzinho","email":"bruno.placides@proton.me"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/ts-algochat_0.4.0_1774114789673_0.4356481329510531"},"_hasShrinkwrap":false}},"time":{"created":"2026-01-25T18:18:11.228Z","modified":"2026-03-21T17:39:49.999Z","0.1.1":"2026-01-25T18:18:11.461Z","0.2.0":"2026-01-29T00:30:31.319Z","0.3.0":"2026-02-07T02:56:45.962Z","0.4.0":"2026-03-21T17:39:49.890Z"},"bugs":{"url":"https://github.com/CorvidLabs/ts-algochat/issues"},"author":{"name":"CorvidLabs"},"license":"MIT","homepage":"https://github.com/CorvidLabs/ts-algochat#readme","keywords":["algorand","encryption","messaging","blockchain","chacha20","x25519","end-to-end","crypto"],"repository":{"type":"git","url":"git+https://github.com/CorvidLabs/ts-algochat.git"},"description":"TypeScript implementation of the AlgoChat protocol for encrypted messaging on Algorand","maintainers":[{"name":"gasparzinho","email":"bruno.placides@proton.me"}],"readme":"# ts-algochat\n\n[![CI](https://img.shields.io/github/actions/workflow/status/CorvidLabs/ts-algochat/ci.yml?label=CI&branch=main)](https://github.com/CorvidLabs/ts-algochat/actions/workflows/ci.yml)\n[![npm](https://img.shields.io/npm/v/@corvidlabs/ts-algochat)](https://www.npmjs.com/package/@corvidlabs/ts-algochat)\n[![License](https://img.shields.io/github/license/CorvidLabs/ts-algochat)](https://github.com/CorvidLabs/ts-algochat/blob/main/LICENSE)\n[![Version](https://img.shields.io/github/v/release/CorvidLabs/ts-algochat?display_name=tag)](https://github.com/CorvidLabs/ts-algochat/releases)\n\n> **Pre-1.0 Notice**: This library is under active development. The API may change between minor versions until 1.0.\n\nTypeScript implementation of the AlgoChat protocol for encrypted messaging on Algorand.\n\n## Features\n\n- **End-to-End Encryption** - X25519 + ChaCha20-Poly1305\n- **Forward Secrecy** - Per-message ephemeral keys\n- **PSK Mode (v1.1)** - Hybrid ECDH + pre-shared key ratcheting for quantum defense-in-depth\n- **Bidirectional Decryption** - Sender can decrypt own messages\n- **Reply Support** - Thread conversations with context\n- **Minimal Dependencies** - Uses @noble crypto libraries (audited) + algosdk\n- **TypeScript First** - Full type safety\n\n## Security Properties\n\n| Property | Status |\n|----------|--------|\n| Message content confidentiality | Protected (E2EE) |\n| Message integrity | Protected (authenticated encryption) |\n| Forward secrecy | Protected (ephemeral keys per message) |\n| Replay attacks | Protected (blockchain uniqueness + PSK counter) |\n| Quantum resistance (key exchange) | Optional (PSK mode provides defense-in-depth) |\n| PSK session forward secrecy | Optional (100-message session boundaries in PSK mode) |\n| Metadata privacy | **Not protected** (addresses, timing visible) |\n| Traffic analysis | **Not protected** |\n\n## Installation\n\n```bash\n# npm\nnpm install @corvidlabs/ts-algochat\n\n# bun\nbun add @corvidlabs/ts-algochat\n\n# pnpm\npnpm add @corvidlabs/ts-algochat\n```\n\n## Quick Start\n\n```typescript\nimport {\n    AlgorandService,\n    createChatAccountFromMnemonic,\n} from '@corvidlabs/ts-algochat';\n\n// Initialize service\nconst service = new AlgorandService({\n    algodToken: '',\n    algodServer: 'https://testnet-api.algonode.cloud',\n    indexerToken: '',\n    indexerServer: 'https://testnet-idx.algonode.cloud',\n});\n\n// Create account from mnemonic\nconst account = createChatAccountFromMnemonic('your 25 word mnemonic...');\n\n// Discover recipient's encryption key\nconst recipientKey = await service.discoverPublicKey('RECIPIENT_ADDRESS');\n\n// Send encrypted message\nconst result = await service.sendMessage(\n    account,\n    'RECIPIENT_ADDRESS',\n    recipientKey,\n    'Hello from AlgoChat!'\n);\n\nconsole.log('Transaction ID:', result.txid);\n\n// Fetch messages\nconst messages = await service.fetchMessages(account, 'RECIPIENT_ADDRESS');\n```\n\n## API Reference\n\n### Account Management\n\n```typescript\n// Create from mnemonic\nconst account = createChatAccountFromMnemonic('word1 word2 ...');\n\n// Generate new account\nconst newAccount = createRandomChatAccount();\nconsole.log('Address:', newAccount.address);\nconsole.log('Mnemonic:', newAccount.mnemonic);\n\n// Validate mnemonic\nif (validateMnemonic('word1 word2 ...')) {\n    // Valid 25-word mnemonic\n}\n\n// Validate address\nif (validateAddress('ALGO...')) {\n    // Valid Algorand address\n}\n```\n\n### Sending Messages\n\n```typescript\n// Simple message\nawait service.sendMessage(account, recipient, recipientKey, 'Hello!');\n\n// Reply to a message\nawait service.sendReply(account, recipient, recipientKey, 'Reply text', {\n    txid: 'original-tx-id',\n    preview: 'Original message preview...',\n});\n```\n\n### Fetching Messages\n\n```typescript\n// Get all messages with an address\nconst messages = await service.fetchMessages(account, 'ADDRESS');\n\n// Get all conversations\nconst conversations = await service.fetchConversations(account);\n\n// Discover public key\nconst pubKey = await service.discoverPublicKey('ADDRESS');\n```\n\n### Low-Level Crypto\n\n```typescript\nimport {\n    deriveEncryptionKeys,\n    encryptMessage,\n    decryptMessage,\n    encodeEnvelope,\n    decodeEnvelope,\n} from '@corvidlabs/ts-algochat';\n\n// Derive keys from seed\nconst keys = deriveEncryptionKeys(seed);\n\n// Encrypt message\nconst envelope = encryptMessage(\n    'Hello!',\n    senderPublicKey,\n    recipientPublicKey\n);\n\n// Encode for transmission\nconst bytes = encodeEnvelope(envelope);\n\n// Decode received envelope\nconst decoded = decodeEnvelope(bytes);\n\n// Decrypt message\nconst content = decryptMessage(decoded, myPrivateKey, myPublicKey);\n```\n\n## Types\n\n```typescript\ninterface ChatAccount {\n    address: string;\n    publicKey: Uint8Array;\n    privateKey: Uint8Array;\n    encryptionKeys: X25519KeyPair;\n    mnemonic?: string;\n}\n\ninterface Message {\n    id: string;\n    sender: string;\n    recipient: string;\n    content: string;\n    timestamp: Date;\n    confirmedRound: number;\n    direction: 'sent' | 'received';\n    replyContext?: ReplyContext;\n}\n\ninterface Conversation {\n    participant: string;\n    participantPublicKey?: Uint8Array;\n    messages: Message[];\n    lastMessage?: Message;\n}\n```\n\n## Protocol\n\nThis library implements the [AlgoChat Protocol v1](https://github.com/CorvidLabs/protocol-algochat) and the PSK v1.1 extension.\n\n### Wire Format (v1.0 Standard)\n\n```\n[version: 1][protocol: 1][sender_pubkey: 32][ephemeral_pubkey: 32][nonce: 12][encrypted_sender_key: 48][ciphertext: variable]\n```\n\n### Wire Format (v1.1 PSK)\n\n```\n[version: 1][protocol: 2][ratchet_counter: 4][sender_pubkey: 32][ephemeral_pubkey: 32][nonce: 12][encrypted_sender_key: 48][ciphertext: variable]\n```\n\n### Cryptographic Primitives\n\n| Function | Algorithm |\n|----------|-----------|\n| Key Agreement | X25519 ECDH |\n| Encryption | ChaCha20-Poly1305 |\n| Key Derivation | HKDF-SHA256 |\n\n## PSK v1.1 Protocol\n\nThe PSK (Pre-Shared Key) v1.1 protocol adds an additional layer of authentication and security on top of standard ECDH encryption by incorporating a pre-shared key into the key derivation process.\n\n### Features\n\n- **Two-level key ratchet** - Session keys derived per 100 messages, position keys per message\n- **Hybrid encryption** - Combines ECDH forward secrecy with PSK authentication\n- **Replay protection** - Counter-based sliding window prevents message replay\n- **Out-of-band key exchange** - URI scheme for sharing PSK keys (QR code compatible)\n\n### Quantum Defense-in-Depth\n\nPSK mode provides defense against future quantum attacks through **hybrid key derivation**:\n\n```\nsymmetricKey = HKDF(\n  ikm = ephemeralECDH || currentPSK,\n  salt = ephemeralPublicKey,\n  info = \"algochat-psk-v1\" || senderPubKey || recipientPubKey\n)\n```\n\nThe encryption key is derived from **both** the ephemeral ECDH shared secret and the ratcheted PSK, concatenated before HKDF. This means an attacker must break **both** layers:\n\n1. **ECDH only broken** (quantum computer): Attacker still needs the PSK\n2. **PSK only compromised**: Attacker still cannot break ECDH (per-message ephemeral keys)\n3. **Both compromised**: Only then can messages be decrypted\n\nThis hybrid approach ensures that even if quantum computers eventually break X25519 ECDH, messages encrypted with PSK mode remain secure as long as the pre-shared key was exchanged securely.\n\n### Two-Level Ratcheting\n\nPSK mode derives per-message keys using a two-level ratchet:\n\n1. **Session derivation**: `sessionPSK = HKDF(initialPSK, sessionIndex)` where `sessionIndex = counter / 100`\n2. **Position derivation**: `currentPSK = HKDF(sessionPSK, position)` where `position = counter % 100`\n\nThis creates 100-message session boundaries. Compromising a session PSK exposes at most 100 messages.\n\n### Exchange URI Format\n\nPSK exchange URIs are designed for QR code sharing:\n\n```\nalgochat-psk://v1?addr=<algorand_address>&psk=<base64url>&label=<optional>\n```\n\nUse any QR library (e.g., `qrcode`) to encode the URI for easy scanning between devices.\n\n### Usage\n\n```typescript\nimport {\n    derivePSKAtCounter,\n    encryptPSKMessage,\n    decryptPSKMessage,\n    encodePSKEnvelope,\n    decodePSKEnvelope,\n    isPSKMessage,\n    createPSKState,\n    advanceSendCounter,\n    validateCounter,\n    recordReceive,\n    createPSKExchangeURI,\n    parsePSKExchangeURI,\n} from '@corvidlabs/ts-algochat';\n\n// Derive PSK for a specific counter\nconst psk = derivePSKAtCounter(sharedSecret, counter);\n\n// Encrypt a PSK message\nconst envelope = encryptPSKMessage(\n    'Hello with PSK!',\n    senderPublicKey,\n    recipientPublicKey,\n    psk,\n    counter,\n);\n\n// Encode for transmission\nconst bytes = encodePSKEnvelope(envelope);\n\n// Check if received data is a PSK message\nif (isPSKMessage(bytes)) {\n    const decoded = decodePSKEnvelope(bytes);\n    const content = decryptPSKMessage(decoded, myPrivateKey, myPublicKey, psk);\n}\n\n// Counter state management\nlet state = createPSKState();\nconst { counter: sendCounter, state: newState } = advanceSendCounter(state);\nstate = newState;\n\n// Exchange URI for out-of-band key sharing\nconst uri = createPSKExchangeURI('ALGO_ADDRESS', pskBytes, 'My Chat');\nconst parsed = parsePSKExchangeURI(uri);\n```\n\n## Testing\n\n```bash\nbun test\n```\n\n## Cross-Implementation Compatibility\n\nThis implementation is fully compatible with:\n- [swift-algochat](https://github.com/CorvidLabs/swift-algochat) (Swift)\n- [rs-algochat](https://github.com/CorvidLabs/rs-algochat) (Rust)\n- [py-algochat](https://github.com/CorvidLabs/py-algochat) (Python)\n- [kt-algochat](https://github.com/CorvidLabs/kt-algochat) (Kotlin)\n\n## License\n\nMIT License - See [LICENSE](LICENSE) for details.\n","readmeFilename":"README.md"}