test-algochat

February 11, 2026 · View on GitHub

Cross-implementation test suite for the AlgoChat protocol.

Overview

This repository contains comprehensive tests to verify that all AlgoChat implementations are fully compatible with each other. The test suite validates encryption, decryption, and envelope encoding/decoding across all supported languages.

Supported Implementations

LanguageRepositoryStatus
Swiftswift-algochat
TypeScriptts-algochat
Pythonpy-algochat
Rustrs-algochat
Kotlinkt-algochat

Quick Start

# Clone with submodules (required for Python, Rust, and Kotlin implementations)
git clone --recurse-submodules https://github.com/CorvidLabs/test-algochat.git
cd test-algochat

# If you already cloned without --recurse-submodules:
git submodule update --init --recursive

# Run all offline crypto tests
./tests/run-all.sh crypto

# Run with localnet integration tests
algokit localnet start
./tests/run-all.sh all
algokit localnet stop

Git Submodules

This repository uses git submodules to include the Python, Rust, Kotlin, and TypeScript implementation repositories:

SubmodulePathRepository
py-algochatpy-algochat/CorvidLabs/py-algochat
rs-algochatrs-algochat/CorvidLabs/rs-algochat
kt-algochatkt-algochat/CorvidLabs/kt-algochat
ts-algochatts-algochat/CorvidLabs/ts-algochat

You must initialize submodules before running Python, Rust, or Kotlin tests. If the submodule directories are empty, run:

git submodule update --init --recursive

To pull the latest changes from all submodules:

git submodule update --remote --merge

Prerequisites

  • Swift 6.0+ - swift --version
  • Bun - bun --version
  • Python 3.10+ - python3 --version
  • Rust - cargo --version (optional)
  • Kotlin/JDK 17+ - java --version (optional)
  • AlgoKit - algokit --version (for localnet tests)

Test Coverage

Message Types (20 total)

  • Basic strings: empty, single char, whitespace, numbers, punctuation, newlines
  • Emoji: simple emoji, ZWJ sequences (family emoji)
  • International scripts: Chinese, Arabic, Japanese, Korean, Cyrillic, accented characters
  • Structured content: JSON, HTML, URLs, code snippets
  • Size limits: long text (~500 chars), max payload (882 bytes)

Test Matrix

Each implementation is tested for:

  1. Key derivation - HKDF-SHA256 produces identical keys from the same seed
  2. Encryption - Messages encrypt to valid envelopes
  3. Decryption - Messages decrypt correctly
  4. Bidirectional - Senders can decrypt their own messages
  5. Cross-implementation - Each implementation can decrypt envelopes from all others

PSK v1.1 Protocol Tests

TestDescription
Ratchet vectorsHKDF derivation matches reference (session/position/counter)
Envelope encode/decodePSK envelope wire format round-trip (130-byte header)
Encrypt/decryptPSK message encryption and decryption
BidirectionalSender can decrypt own PSK messages
Cross-implementationEach implementation decrypts PSK envelopes from all others

PSK Ratchet Test Vectors

Initial PSK: 32 bytes of 0xAA

CounterSessionPositionExpected PSK
0002918fd48...
990995b48a50a...
100107a15d3ad...

Running Tests

Crypto Tests (Offline)

# Swift
swift run TestAlgoChat crypto

# TypeScript
bun test ts/crypto.test.ts

# Both (with cross-verification)
./tests/run-all.sh crypto

Localnet Tests (Integration)

# Start localnet
algokit localnet start

# Run tests
./tests/run-all.sh localnet

# Stop localnet
algokit localnet stop

Test Vectors

Test vectors are defined in test-vectors.json and include:

Alice's seed:

0000000000000000000000000000000000000000000000000000000000000001

Bob's seed:

0000000000000000000000000000000000000000000000000000000000000002

Keys are derived using HKDF-SHA256 with:

  • Salt: AlgoChat-v1-encryption
  • Info: x25519-key

Expected X25519 public keys:

  • Alice: a04407c78ff19a0bbd578588d6100bca4ed7f89acfc600666dbab1d36061c064
  • Bob: b43231dc85ba0781ad3df9b8f8458a5e6f4c1030d0526ace9540300e0398ae03

Protocol Specification

AlgoChat uses:

  • X25519 for key agreement
  • ChaCha20-Poly1305 for authenticated encryption
  • HKDF-SHA256 for key derivation

Envelope Format (126-byte header + ciphertext)

OffsetSizeField
01Version (0x01)
11Protocol ID (0x01)
2-3332Sender public key
34-6532Ephemeral public key
66-7712Nonce
78-12548Encrypted sender key
126+varCiphertext + 16-byte tag

PSK v1.1 Protocol

AlgoChat PSK adds pre-shared key support with a two-level ratchet:

  • Session PSK - Derived from initial PSK + session index (counter / 100)
  • Position PSK - Derived from session PSK + position (counter % 100)
  • Hybrid encryption - IKM = sharedSecret || currentPSK

PSK Envelope Format (130-byte header + ciphertext)

OffsetSizeField
01Version (0x01)
11Protocol ID (0x02)
2-54Ratchet counter (big-endian uint32)
6-3732Sender public key
38-6932Ephemeral public key
70-8112Nonce
82-12948Encrypted sender key
130+varCiphertext + 16-byte tag

PSK HKDF Parameters

ParameterValue
Session saltAlgoChat-PSK-Session
Position saltAlgoChat-PSK-Position
Hybrid info prefixAlgoChatV1-PSK
Sender key info prefixAlgoChatV1-PSK-SenderKey
Session size100 counters
Counter window200

PSK Ratchet Test Vectors (initial PSK = 32 bytes of 0xAA)

CounterExpected PSK
Session 0a031707ea9e9e50bd8ea4eb9a2bd368465ea1aff14caab293d38954b4717e888
Session 1994cffbb4f84fa5410d44574bb9fa7408a8c2f1ed2b3a00f5168fc74c71f7cea
Counter 02918fd486b9bd024d712f6234b813c0f4167237d60c2c1fca37326b20497c165
Counter 995b48a50a25261f6b63fe9c867b46be46de4d747c3477db6290045ba519a4d38b
Counter 1007a15d3add6a28858e6a1f1ea0d22bdb29b7e129a1330c4908d9b46a460992694

Running PSK Tests

# Swift PSK tests
swift run TestAlgoChat psk

# TypeScript PSK tests
bun test ts/crypto.test.ts --grep "PSK"

# All tests (includes PSK)
./tests/run-all.sh crypto

File Structure

test-algochat/
├── Package.swift              # Swift package
├── package.json               # TypeScript dependencies
├── test-vectors.json          # Shared test vectors
├── Sources/
│   └── TestAlgoChat/
│       ├── main.swift         # Swift CLI test runner
│       └── TestVectors.swift  # Shared test data
├── ts/
│   ├── test-vectors.ts        # TypeScript test vectors
│   ├── crypto.test.ts         # Crypto compatibility tests
│   └── localnet.test.ts       # Integration tests
├── tests/
│   └── run-all.sh             # Master test runner
└── .github/
    └── workflows/
        └── ci.yml             # GitHub Actions CI

Generated Artifacts

During test runs, these directories are created:

DirectoryDescription
test-envelopes-swift/Swift-encrypted envelopes (20 messages)
test-envelopes-ts/TypeScript-encrypted envelopes (20 messages)
test-envelopes-python/Python-encrypted envelopes (20 messages)
test-envelopes-swift-psk/Swift PSK-encrypted envelopes (20 messages)
test-envelopes-ts-psk/TypeScript PSK-encrypted envelopes (20 messages)
test-envelopes-py-psk/Python PSK-encrypted envelopes (20 messages)
test-envelopes-rs-psk/Rust PSK-encrypted envelopes (20 messages)
test-envelopes-kt-psk/Kotlin PSK-encrypted envelopes (20 messages)

CI/CD

GitHub Actions runs:

  1. Swift tests on macOS
  2. TypeScript tests on Ubuntu
  3. Python tests on Ubuntu (3.10, 3.11, 3.12)
  4. Rust tests on Ubuntu
  5. Kotlin tests on Ubuntu
  6. Cross-implementation verification

Troubleshooting

Swift build fails

swift package clean
swift package resolve
swift build

TypeScript import errors

cd node_modules/ts-algochat
bun install && bun run build
cd -
bun install

Localnet connection fails

algokit localnet status
algokit localnet stop
algokit localnet start

License

MIT