From 59d02e197c213a2c543e5aac0db3863a20092f9c Mon Sep 17 00:00:00 2001 From: kamal Date: Thu, 2 Apr 2026 20:51:27 +0000 Subject: [PATCH] Add Zig --- Zig.md | 128 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 Zig.md diff --git a/Zig.md b/Zig.md new file mode 100644 index 0000000..2af883a --- /dev/null +++ b/Zig.md @@ -0,0 +1,128 @@ +# soliton-zig + +Zig wrapper for [libsoliton](https://git.lo.sh/lo/libsoliton) — a pure-Rust post-quantum cryptographic library. Consumes the C ABI via `@cImport`. + +## Build + +Requires `libsoliton_capi` built from the workspace: + +```bash +# From the workspace root +cargo build --release -p libsoliton_capi + +# Run Zig tests +cd soliton_zig +zig build test +``` + +The build script links against `../target/release/libsoliton_capi.so` and includes the header from `../soliton_capi/soliton.h`. + +## Usage + +Add as a Zig dependency in `build.zig.zon`: + +```zig +.dependencies = .{ + .soliton = .{ + .url = "https://git.lo.sh/lo/libsoliton/archive/v0.1.0.tar.gz", + .hash = "...", + }, +}, +``` + +```zig +const soliton = @import("soliton"); + +// Identity +var id = try soliton.Identity.generate(); +defer id.deinit(); + +var fp: [32]u8 = undefined; +try id.fingerprint(&fp); + +var sig = try id.sign("hello"); +defer sig.deinit(); +try id.verify("hello", sig.slice()); + +// Auth +var challenge = try soliton.authChallenge(&id.public_key); +defer challenge.ct.deinit(); + +var proof: [32]u8 = undefined; +try soliton.authRespond(&id.secret_key, challenge.ct.slice(), &proof); +assert(soliton.authVerify(&challenge.token, &proof)); + +// Primitives +var hash: [32]u8 = undefined; +try soliton.sha3_256("abc", &hash); + +var tag: [32]u8 = undefined; +try soliton.hmacSha3_256(key, data, &tag); + +var okm: [64]u8 = undefined; +try soliton.hkdfSha3_256(salt, ikm, info, &okm); + +// AEAD +var ct = try soliton.aeadEncrypt(&key, &nonce, plaintext, aad); +defer ct.deinit(); +var pt = try soliton.aeadDecrypt(&key, &nonce, ct.slice(), aad); +defer pt.deinit(); + +// X-Wing +var kp = try soliton.xwingKeygen(); +defer kp.deinit(); + +// KEX +var spk_sig = try soliton.kexSignPrekey(&bob.secret_key, &spk.pk); +defer spk_sig.deinit(); + +var initiated = try soliton.kexInitiate(...); +defer initiated.deinit(); + +var received = try soliton.kexReceive(...); +defer received.deinit(); + +// Ratchet +var alice_r = try soliton.Ratchet.initAlice(root_key, chain_key, ...); +defer alice_r.deinit(); + +var msg = try alice_r.encrypt("hello"); +defer msg.deinit(); + +// Serialize +var result = try alice_r.toBytes(); +defer result.blob.deinit(); +// result.epoch for anti-rollback storage + +// Storage +var ring = try soliton.KeyRing.init(&key, 1); +defer ring.deinit(); +var blob = try ring.encryptBlob("channel", "segment", plaintext); +defer blob.deinit(); + +// Streaming AEAD +var enc = try soliton.StreamEncryptor.init(&key, null, false); +defer enc.deinit(); +var hdr: [soliton.STREAM_HEADER_SIZE]u8 = undefined; +try enc.header(&hdr); +const written = try enc.encryptChunk(data, true, &out_buf); + +// Call Keys +var keys = try alice_r.deriveCallKeys(&kem_ss, &call_id); +defer keys.deinit(); +var send: [32]u8 = undefined; +try keys.sendKey(&send); + +// Verification +var phrase = try soliton.verificationPhrase(&pk_a, &pk_b); +defer phrase.deinit(); + +// Argon2id +try soliton.argon2id(password, &salt, 65536, 3, 4, &out); +``` + +## API + +All functions return `Error!T` where `Error` maps 1:1 to the CAPI error codes. Opaque types (`Identity`, `Ratchet`, `KeyRing`, `StreamEncryptor`, `StreamDecryptor`, `CallKeys`, `XWingKeyPair`) must be `deinit()`'d for cleanup and zeroization. `Buf` wraps library-allocated buffers and is freed via `deinit()`. + +All constants from `soliton.h` are re-exported (`PUBLIC_KEY_SIZE`, `SECRET_KEY_SIZE`, `XWING_PK_SIZE`, etc.).