Language Bindings
The QuantaCore SDK provides native language bindings for Rust, Python, Java, Go, C#, and Node.js. Each binding is designed to feel idiomatic in its target language — Rust bindings leverage the ownership model, Python bindings follow PEP conventions, Java bindings use standard patterns with AutoCloseable resources, and Go bindings are goroutine-safe. All bindings are thin wrappers over the native C library with minimal overhead.
Overview #
| Language | Package | FFI Method | Min Version | Overhead |
|---|---|---|---|---|
| Rust | quac100 crate | bindgen + safe wrappers | 1.70+ | ~50 ns |
| Python | quac100 (pip) | ctypes / cffi | 3.8+ | ~200 ns |
| Java | com.dyber:quac100 | JNI | JDK 11+ | ~300 ns |
| Go | github.com/dyber-inc/quac100-go | CGO | 1.20+ | ~150 ns |
| C# / .NET | Dyber.Quac100 (NuGet) | P/Invoke | .NET 6+ | ~250 ns |
| Node.js | quac100 (npm) | N-API | Node 18+ | ~350 ns |
Overhead values represent the FFI boundary crossing cost per call. Actual cryptographic operation latency is dominated by the hardware execution time (typically 1–5 μs for PQC operations), making the binding overhead negligible in practice.
Rust #
The Rust bindings provide a safe, zero-cost abstraction over the C API. Key material is managed through Rust's ownership system — keys implement Drop for automatic zeroization, and the type system prevents use-after-free at compile time.
use quac100::{Device, Algorithm, Result};
fn main() -> Result<()> {
quac100::init()?;
let device = Device::open(0)?;
// Generate ML-KEM-768 key pair
let keypair = device.kem_keygen(Algorithm::Kyber768)?;
// Encapsulate / decapsulate
let (ciphertext, sender_secret) = keypair.public_key().encapsulate()?;
let receiver_secret = keypair.decapsulate(&ciphertext)?;
assert_eq!(sender_secret.as_ref(), receiver_secret.as_ref());
println!("Key exchange successful!");
quac100::shutdown()?;
Ok(())
} // keypair automatically zeroized when dropped
The crate supports async/await via the optional tokio feature. When enabled, all cryptographic operations return futures that can be awaited in async contexts. The zeroize crate ensures all key material is securely erased when values go out of scope.
Python #
import quac100
quac100.init()
device = quac100.Device(0)
# Key exchange
keypair = device.kem_keygen(quac100.Algorithm.KYBER_768)
ciphertext, shared_secret = keypair.encapsulate()
recovered = keypair.decapsulate(ciphertext)
assert shared_secret == recovered
print("Key exchange successful!")
# Digital signature
sig_key = device.sign_keygen(quac100.Algorithm.DILITHIUM_3)
signature = sig_key.sign(b"Hello, PQC!")
valid = sig_key.verify(b"Hello, PQC!", signature)
print(f"Signature valid: {valid}")
# QRNG random bytes
random_data = device.random_bytes(32)
quac100.shutdown()
The Python package installs via pip install quac100 and includes pre-built wheels for Linux (x86_64, aarch64) and Windows (x64). The package uses ctypes for FFI, requiring no compilation on the user's machine. Context manager support enables with blocks for automatic cleanup.
Java #
import com.dyber.quac100.*;
public class PqcDemo {
public static void main(String[] args) throws Exception {
Quac100.init();
try (Device device = new Device(0)) {
// Key exchange
KEMKeyPair keypair = device.kemKeygen(Algorithm.KYBER_768);
EncapsulationResult result = keypair.encapsulate();
byte[] recovered = keypair.decapsulate(result.getCiphertext());
assert Arrays.equals(result.getSharedSecret(), recovered);
// Digital signature
SignKeyPair sigKey = device.signKeygen(Algorithm.DILITHIUM_3);
byte[] signature = sigKey.sign("Hello, PQC!".getBytes());
boolean valid = sigKey.verify("Hello, PQC!".getBytes(), signature);
System.out.println("Valid: " + valid);
}
Quac100.shutdown();
}
}
The Java bindings use JNI for native library access. The Device class implements AutoCloseable, enabling try-with-resources blocks that guarantee proper cleanup. Maven and Gradle dependencies include the JNI shared library for supported platforms.
Go #
package main
import (
"fmt"
quac "github.com/dyber-inc/quac100-go"
)
func main() {
quac.Init()
defer quac.Shutdown()
device, _ := quac.OpenDevice(0)
defer device.Close()
// Key exchange
keypair, _ := device.KEMKeygen(quac.Kyber768)
ct, ss, _ := keypair.Encapsulate()
recovered, _ := keypair.Decapsulate(ct)
fmt.Printf("Secrets match: %v\n", bytes.Equal(ss, recovered))
// QRNG
random, _ := device.RandomBytes(32)
fmt.Printf("Random: %x\n", random[:8])
}
The Go module uses CGO to bridge to the native library. All exported functions are safe for concurrent use by multiple goroutines — the underlying C library handles thread synchronization internally.
C# / .NET #
using Dyber.Quac100;
Quac100.Init();
using var device = new Device(0);
var keypair = device.KemKeygen(Algorithm.Kyber768);
var (ciphertext, secret) = keypair.Encapsulate();
var recovered = keypair.Decapsulate(ciphertext);
Console.WriteLine($"Match: {secret.SequenceEqual(recovered)}");
Quac100.Shutdown();
The NuGet package includes native libraries for Windows and Linux. P/Invoke marshaling is handled by auto-generated bindings. The Device class implements IDisposable with guaranteed key zeroization in the finalizer.
Node.js #
const quac = require('quac100');
async function main() {
await quac.init();
const device = await quac.openDevice(0);
const keypair = await device.kemKeygen(quac.Algorithm.KYBER_768);
const { ciphertext, sharedSecret } = await keypair.encapsulate();
const recovered = await keypair.decapsulate(ciphertext);
console.log('Match:', Buffer.compare(sharedSecret, recovered) === 0);
await device.close();
quac.shutdown();
}
main();
The Node.js package uses N-API for stable ABI across Node versions. All operations return Promises for natural use with async/await. The npm package includes prebuilt binaries — no native compilation required.
Memory Safety #
All language bindings guarantee secure memory handling regardless of the target language's memory model. Key material is stored in C-allocated memory managed by the native library. When binding objects are garbage-collected or dropped, the native finalizer triggers constant-time zeroization before freeing memory. For languages with non-deterministic finalization (Java, Python, C#), the bindings also provide explicit close()/destroy() methods for immediate cleanup.
Async Support #
Async APIs are available in Rust (tokio), Python (asyncio), Node.js (Promises), and C# (Task). Async operations submit work to the QUAC 100 command queue and yield control back to the runtime while waiting for hardware completion, enabling high concurrency without thread-per-operation overhead.
# Python async example
import asyncio, quac100
async def batch_keygen():
device = quac100.AsyncDevice(0)
tasks = [device.kem_keygen_async(quac100.Algorithm.KYBER_768) for _ in range(1000)]
keypairs = await asyncio.gather(*tasks)
print(f"Generated {len(keypairs)} key pairs")
Packaging & Distribution #
All language packages include pre-built native libraries for Linux (x86_64, aarch64) and Windows (x64). Source builds are supported for platforms without pre-built binaries. Each package follows its ecosystem's standard distribution mechanism: crates.io for Rust, PyPI for Python, Maven Central for Java, proxy.golang.org for Go, NuGet for .NET, and npm for Node.js.
Was this page helpful? Send feedback