VoiceCat .NET rewrite
The first slice targets .NET 10: protobuf, control framing, voice headers, and media encryption, TLS 1.3, persisted TOFU pins, and server credentials. Server/client state, audio, and UI migration are next. The existing C++ implementation remains the conformance oracle.
From the repository root:
dotnet restore dotnet/VoiceCat.slnx --locked-mode
dotnet build dotnet/VoiceCat.slnx -c Release --no-restore
dotnet test dotnet/VoiceCat.slnx -c Release --no-build
Dependencies are pinned in project files and lock files. Generated protobuf is build
output; the schema remains core/proto/voicecat.proto. Production dependencies are
Google.Protobuf (BSD-3-Clause), BouncyCastle.Cryptography (MIT), and the build-only
Grpc.Tools (Apache-2.0). No GPL/LGPL dependencies are permitted.
C# conventions
Use file-scoped namespaces, standard .NET naming, immutable values where useful, and spans for binary data. Invalid arguments throw; invalid network packets use parsing results or protocol exceptions. Async APIs accept cancellation tokens.
Comments explain constraints that cannot be made clear in code. Avoid banners,
implementation history, and narration. Keep durable design explanations in docs/.
Regenerating C++ fixtures
The optional oracle target calls the existing C++ protobuf, header serializer, and libsodium media implementation. From the root, with the development dependencies:
cmake --preset dev -DVOICECAT_BUILD_DOTNET_ORACLE=ON
cmake --build --preset dev --target voicecat-dotnet-oracle
New-Item -ItemType Directory -Force dotnet/tests/VoiceCat.Tests/Fixtures
./build/dev/bin/voicecat-dotnet-oracle.exe dotnet/tests/VoiceCat.Tests/Fixtures/cpp-wire.json
git diff -- dotnet/tests/VoiceCat.Tests/Fixtures/cpp-wire.json
On Linux/macOS, omit .exe and create the directory with mkdir -p.
The oracle writes deterministic JSON directly, avoiding shell output encoding.
Fixtures contain a framed ClientHello and media packets at counters 0, 1, 65535,
and 65536. Keys contain bytes 0–31; payload bytes count upward from zero. The
20-byte header has type 1, marker flag, codec 0, SSRC 0xcafebabe, timestamp 960.
Both managed crypto backends must match these bytes.
TLS interoperability
The optional TLS oracle uses the existing mbedTLS context and libsodium media crypto. The test authenticates an encrypted challenge in both directions, proving exporter compatibility without sending raw keys. It also loads the C++ server's credential files.
cmake --build --preset dev --target voicecat-dotnet-tls-oracle
$env:VOICECAT_TLS_ORACLE = (Resolve-Path build/dev/bin/voicecat-dotnet-tls-oracle.exe).Path
dotnet test dotnet/VoiceCat.slnx -c Release --no-restore
On Linux/macOS, set VOICECAT_TLS_ORACLE to the absolute executable path without
.exe. Without that variable, only this native interoperability test is skipped;
managed TLS loopback, rejection, persistence, and wire tests still run. CI's C++
conformance job requires the native test. See docs/api-dotnet.md for ownership
and certificate acceptance requirements.
Next checkpoint
Port codec/DSP wrappers and their native packaging per Phase 3 of the porting plan. The managed server follows, tested first with the existing C++ CLI.