BoringSSL Provider
The Dyber BoringSSL integration provides hardware-accelerated post-quantum cryptography for the millions of applications built on BoringSSL — including Chromium, Android, gRPC, and major cloud-native infrastructure. Unlike OpenSSL's provider model, BoringSSL uses direct API integration, giving you explicit control over PQC operations with the full performance of the QUAC 100 accelerator.
Overview #
BoringSSL is Google's fork of OpenSSL, used as the TLS library for Chromium, Android, CloudFlare's infrastructure, and gRPC. It deliberately removes OpenSSL's provider/engine interfaces in favor of a streamlined, opinionated API surface. The Dyber BoringSSL integration provides a native C library (libquac100_boringssl) that implements ML-KEM, ML-DSA, and QRNG operations through direct function calls and optional EVP method registration, delivering QUAC 100 hardware acceleration without requiring BoringSSL source modifications for most use cases.
| Feature | Description |
|---|---|
| Library Name | libquac100_boringssl.so / quac100_boringssl.dll |
| Header | quac100_boringssl.h |
| BoringSSL Version | Latest (from boringssl.googlesource.com) |
| ML-KEM Support | ML-KEM-512, ML-KEM-768, ML-KEM-1024 (FIPS 203) |
| ML-DSA Support | ML-DSA-44, ML-DSA-65, ML-DSA-87 (FIPS 204) |
| QRNG | Hardware quantum random — 500 Mbps conditioned throughput |
| TLS Hybrid Groups | X25519_ML-KEM-768, P-384_ML-KEM-1024, X25519_ML-KEM-512 |
| ASN.1 Encoding | DER/PEM via BoringSSL CBS/CBB primitives |
| Hardware Acceleration | 1.4M+ ops/sec with QUAC 100 PCIe card |
| Software Fallback | Automatic software simulation when hardware unavailable |
| Build System | CMake 3.16+, GN (Chromium), Make |
| C Standard | C11 (GCC 9+, Clang 10+, MSVC 2019+) |
Architecture & Integration Model #
The BoringSSL integration is a shared library that sits alongside BoringSSL, providing PQC functions through a clean C API. Applications call QUAC functions directly for post-quantum operations while continuing to use BoringSSL for classical cryptography. The library automatically detects and uses QUAC 100 hardware when available, falling back to software simulation for development and testing.
| Source File | Purpose |
|---|---|
quac100_boringssl.h | Public header — all API declarations, constants, key sizes, error codes |
quac100_boringssl.c | Core initialization, hardware detection, secure memory, self-test, benchmarks |
quac100_kem.c | ML-KEM implementation — keygen, encapsulate, decapsulate for all parameter sets |
quac100_sig.c | ML-DSA implementation — keygen, sign, verify, plus prehash variants (HashML-DSA) |
quac100_rand.c | QRNG integration — buffered/unbuffered random, health monitoring, entropy seeding |
quac100_evp.c | EVP_PKEY integration layer — wraps PQC keys in BoringSSL's EVP interface |
quac100_tls.c | TLS 1.3 hybrid key exchange — X25519+ML-KEM, P-384+ML-KEM group negotiation |
quac100_asn1.c | ASN.1/DER/PEM encoding using BoringSSL's CBS/CBB (SubjectPublicKeyInfo, PKCS#8) |
quac100_engine.c | Legacy ENGINE shim for older BoringSSL builds that still support ENGINE API |
┌─────────────────────────────────────────────────────────────â”
│ Application (Chromium, gRPC, Envoy, custom app) │
├─────────────┬───────────────────────┬───────────────────────┤
│ BoringSSL │ libquac100_boringssl │ QUAC EVP Methods │
│ (classical)│ (PQC direct API) │ (optional wrappers) │
├─────────────┴───────────────────────┴───────────────────────┤
│ QUAC 100 SDK (libquac100 — PCIe driver interface) │
├─────────────────────────────────────────────────────────────┤
│ QUAC 100 Hardware (PCIe Gen4 x16 Accelerator) │
└─────────────────────────────────────────────────────────────┘
BoringSSL vs OpenSSL Integration #
BoringSSL and OpenSSL have fundamentally different extensibility models. Understanding the difference is critical for choosing the right integration path.
| Feature | OpenSSL 3.x Provider | BoringSSL Integration |
|---|---|---|
| Integration Model | Dynamic provider (loaded at runtime) | Direct API (linked at compile time) |
| EVP Support | Full EVP_PKEY with automatic dispatch | Limited EVP wrapper; prefer direct calls |
| Algorithm Registration | Automatic via provider query | Manual — call QUAC_EVP_register() |
| TLS Groups | Provider-registered groups | Requires BoringSSL source patches for full TLS |
| Configuration | openssl.cnf directives | Compile-time flags + runtime QUAC_init() |
| Drop-in Replacement | Yes — zero code changes | Partial — direct calls for PQC, transparent for classical |
| Chromium Compatible | No | Yes |
| Android Compatible | No (Android uses BoringSSL) | Yes |
| gRPC Compatible | No (gRPC uses BoringSSL) | Yes |
Building & Installation #
Prerequisites
| Requirement | Version | Notes |
|---|---|---|
| BoringSSL | Latest | Clone from boringssl.googlesource.com/boringssl |
| CMake | 3.16+ | Build system generator |
| C Compiler | GCC 9+, Clang 10+, MSVC 2019+ | C11 standard required |
| QUAC 100 SDK | 1.0+ | Optional — enables hardware acceleration |
| Go | 1.18+ | Required by BoringSSL's build for peg |
Build from Source
# Clone BoringSSL (if not already available)
$ git clone https://boringssl.googlesource.com/boringssl
$ cd boringssl && mkdir build && cd build
$ cmake .. && make -j$(nproc)
$ cd ../..
# Build QUAC BoringSSL integration
$ cd quantacore-sdk/integrations/boringssl
$ mkdir build && cd build
# Without hardware (software-only)
$ cmake .. -DBORINGSSL_ROOT=/path/to/boringssl
$ make -j$(nproc)
# With QUAC 100 hardware acceleration
$ cmake .. \
-DBORINGSSL_ROOT=/path/to/boringssl \
-DQUAC_SDK_PATH=/opt/quantacore-sdk
$ make -j$(nproc)
# Install
$ sudo make install
GN Build (Chromium Integration)
For Chromium or other GN-based projects, a BUILD.gn file is provided:
# In your GN project, add to deps:
deps += [ "//third_party/quac100_boringssl" ]
# Copy integration files to third_party/quac100_boringssl/
$ cp quantacore-sdk/integrations/boringssl/* \
chromium/src/third_party/quac100_boringssl/
Verify Installation
# Check library
$ ls /usr/local/lib/libquac100_boringssl.so
$ ls /usr/local/include/quac100_boringssl.h
# Verify with pkg-config
$ pkg-config --libs quac100-boringssl
-lquac100_boringssl -lssl -lcrypto -lpthread
Initialization & Configuration #
All QUAC functions require initialization before use. The library automatically detects QUAC 100 hardware via PCIe enumeration and falls back to software simulation if unavailable.
#include "quac100_boringssl.h"
int main(void) {
/* Basic init — auto-detect hardware, fallback to software */
int ret = QUAC_init();
if (ret != QUAC_SUCCESS) {
fprintf(stderr, "Init failed: %s\n", QUAC_get_error_string(ret));
return 1;
}
/* Check hardware status */
if (QUAC_is_hardware_available()) {
printf("QUAC 100 hardware acceleration: ENABLED\n");
} else {
printf("Running in software simulation mode\n");
}
printf("Library version: %s\n", QUAC_version_string());
/* ... use QUAC functions ... */
QUAC_cleanup();
return 0;
}
Extended Initialization
/* Require hardware — fail if not available */
ret = QUAC_init_ex(
1, /* use_hardware: 1 = require, 0 = allow fallback */
0 /* device_index: 0 = first QUAC device */
);
/* Multi-device: target second QUAC 100 card */
ret = QUAC_init_ex(1, 1); /* device_index = 1 */
ML-KEM Key Encapsulation #
ML-KEM (Module-Lattice Key Encapsulation Mechanism, FIPS 203) is the primary key exchange primitive for post-quantum TLS. The BoringSSL integration supports all three parameter sets with both hardware-accelerated and software paths.
Key Sizes
| Parameter Set | Security Level | Public Key | Secret Key | Ciphertext | Shared Secret |
|---|---|---|---|---|---|
| ML-KEM-512 | NIST Level 1 | 800 B | 1,632 B | 768 B | 32 B |
| ML-KEM-768 | NIST Level 3 | 1,184 B | 2,400 B | 1,088 B | 32 B |
| ML-KEM-1024 | NIST Level 5 | 1,568 B | 3,168 B | 1,568 B | 32 B |
Complete KEM Example
#include "quac100_boringssl.h"
/* Allocate buffers using compile-time constants */
uint8_t pk[QUAC_ML_KEM_768_PUBLIC_KEY_BYTES]; /* 1184 bytes */
uint8_t sk[QUAC_ML_KEM_768_SECRET_KEY_BYTES]; /* 2400 bytes */
uint8_t ct[QUAC_ML_KEM_768_CIPHERTEXT_BYTES]; /* 1088 bytes */
uint8_t ss_sender[32], ss_receiver[32];
/* Generate keypair (receiver side) */
int ret = QUAC_KEM_keypair(QUAC_KEM_ML_KEM_768, pk, sk);
assert(ret == QUAC_SUCCESS);
/* Encapsulate (sender side — produces ciphertext + shared secret) */
ret = QUAC_KEM_encaps(QUAC_KEM_ML_KEM_768, ct, ss_sender, pk);
assert(ret == QUAC_SUCCESS);
/* Decapsulate (receiver side — recovers shared secret from ciphertext) */
ret = QUAC_KEM_decaps(QUAC_KEM_ML_KEM_768, ss_receiver, ct, sk);
assert(ret == QUAC_SUCCESS);
/* ss_sender == ss_receiver (32-byte shared secret) */
assert(memcmp(ss_sender, ss_receiver, 32) == 0);
Dynamic Size Queries
/* Query sizes at runtime for algorithm-agnostic code */
size_t pk_len = QUAC_KEM_public_key_bytes(QUAC_KEM_ML_KEM_768); /* 1184 */
size_t sk_len = QUAC_KEM_secret_key_bytes(QUAC_KEM_ML_KEM_768); /* 2400 */
size_t ct_len = QUAC_KEM_ciphertext_bytes(QUAC_KEM_ML_KEM_768); /* 1088 */
size_t ss_len = QUAC_KEM_shared_secret_bytes(QUAC_KEM_ML_KEM_768); /* 32 */
ML-DSA Digital Signatures #
ML-DSA (Module-Lattice Digital Signature Algorithm, FIPS 204) provides quantum-resistant digital signatures for certificate authentication, code signing, and document integrity verification.
Key & Signature Sizes
| Parameter Set | Security Level | Public Key | Secret Key | Signature |
|---|---|---|---|---|
| ML-DSA-44 | NIST Level 2 | 1,312 B | 2,560 B | 2,420 B |
| ML-DSA-65 | NIST Level 3 | 1,952 B | 4,032 B | 3,309 B |
| ML-DSA-87 | NIST Level 5 | 2,592 B | 4,896 B | 4,627 B |
Sign & Verify Example
uint8_t pk[QUAC_ML_DSA_65_PUBLIC_KEY_BYTES]; /* 1952 bytes */
uint8_t sk[QUAC_ML_DSA_65_SECRET_KEY_BYTES]; /* 4032 bytes */
uint8_t sig[QUAC_ML_DSA_65_SIGNATURE_BYTES]; /* 3309 bytes */
size_t sig_len;
/* Generate signing keypair */
int ret = QUAC_SIG_keypair(QUAC_SIG_ML_DSA_65, pk, sk);
/* Sign a message */
const uint8_t *msg = (uint8_t *)"Post-quantum signatures with QUAC 100";
size_t msg_len = strlen((char *)msg);
ret = QUAC_sign(QUAC_SIG_ML_DSA_65, sig, &sig_len, msg, msg_len, sk);
assert(ret == QUAC_SUCCESS);
/* Verify signature */
ret = QUAC_verify(QUAC_SIG_ML_DSA_65, sig, sig_len, msg, msg_len, pk);
if (ret == QUAC_SUCCESS) {
printf("Signature valid ✓\n");
} else if (ret == QUAC_ERROR_VERIFICATION_FAILED) {
printf("Signature invalid ✗\n");
}
/* Prehash variant (HashML-DSA) for large messages */
ret = QUAC_sign_prehash(QUAC_SIG_ML_DSA_65, sig, &sig_len, hash, hash_len, sk);
ret = QUAC_verify_prehash(QUAC_SIG_ML_DSA_65, sig, sig_len, hash, hash_len, pk);
QRNG Random Generation #
The QUAC 100 includes a hardware quantum random number generator delivering 500 Mbps of conditioned true random data. The BoringSSL integration provides a buffered interface that seamlessly replaces BoringSSL's RAND_bytes() for applications requiring quantum entropy.
/* Generate random bytes (buffered, high-throughput) */
uint8_t random_data[64];
int ret = QUAC_random_bytes(random_data, sizeof(random_data));
/* Add application entropy (mix with hardware source) */
uint8_t app_seed[32] = { /* application-specific entropy */ };
QUAC_random_seed(app_seed, sizeof(app_seed));
/* Health monitoring */
if (!QUAC_random_health_check()) {
fprintf(stderr, "WARNING: QRNG health degraded — check hardware\n");
}
/* High-throughput unbuffered (hardware-only, bypasses DRBG) */
uint8_t bulk[1024 * 1024]; /* 1 MB */
ret = QUAC_random_bytes_unbuffered(bulk, sizeof(bulk));
TLS 1.3 Hybrid Key Exchange #
Hybrid key exchange combines a classical algorithm (X25519 or ECDH P-384) with a post-quantum KEM (ML-KEM) in a single TLS 1.3 handshake. This provides security against both classical and quantum adversaries — if either component remains secure, the connection is safe.
Supported Hybrid Groups
| Group | Group ID | Classical | PQC | Combined PK Size | Use Case |
|---|---|---|---|---|---|
| X25519_ML-KEM-768 | 0x6399 | X25519 | ML-KEM-768 | 1,216 B | Recommended default |
| P-384_ML-KEM-1024 | 0x639A | ECDH P-384 | ML-KEM-1024 | 1,665 B | High-security government |
| X25519_ML-KEM-512 | 0x639B | X25519 | ML-KEM-512 | 832 B | Bandwidth-constrained |
Hybrid Key Exchange API
/* Create hybrid context */
QUAC_HYBRID_CTX *ctx = QUAC_hybrid_ctx_new(QUAC_GROUP_X25519_ML_KEM_768);
/* Generate our keypair (classical + PQC combined) */
int ret = QUAC_hybrid_generate_keypair(ctx);
/* Export our public key to send to peer */
uint8_t my_public[2048];
size_t my_public_len = sizeof(my_public);
ret = QUAC_hybrid_get_public_key(ctx, my_public, &my_public_len);
/* my_public_len == 1216 for X25519_ML-KEM-768 */
/* Set peer's public key (received from TLS handshake) */
ret = QUAC_hybrid_set_peer_public_key(ctx, peer_public, peer_public_len);
/* Derive shared secret */
uint8_t shared_secret[64];
size_t ss_len = sizeof(shared_secret);
ret = QUAC_hybrid_derive(ctx, shared_secret, &ss_len);
/* ss_len == 64 (32 from X25519 + 32 from ML-KEM-768) */
/* Cleanup — secure zeroization of all key material */
QUAC_hybrid_ctx_free(ctx);
TLS Group Registration
/* Register hybrid groups for use in TLS handshakes */
QUAC_TLS_register_groups();
/* Query supported groups */
quac_tls_group_t groups[8];
size_t count = 8;
QUAC_TLS_get_groups(groups, &count);
/* Check individual group support */
if (QUAC_TLS_group_is_supported(QUAC_GROUP_X25519_ML_KEM_768)) {
printf("X25519_ML-KEM-768 available\n");
}
EVP Integration Layer #
For applications that prefer BoringSSL's EVP_PKEY interface, optional EVP wrappers let you create PQC keys as EVP objects. This enables interoperability with existing key management code that expects EVP_PKEY* handles.
/* Register QUAC algorithms with BoringSSL EVP system */
QUAC_EVP_register();
/* Create EVP_PKEY from ML-KEM keys */
EVP_PKEY *kem_key = QUAC_EVP_PKEY_new_kem(QUAC_KEM_ML_KEM_768, pk, sk);
/* Create EVP_PKEY from ML-DSA keys */
EVP_PKEY *sig_key = QUAC_EVP_PKEY_new_sig(QUAC_SIG_ML_DSA_65, pk, sk);
/* Extract raw keys back from EVP_PKEY */
uint8_t raw_pk[QUAC_KEM_MAX_PUBLIC_KEY_BYTES];
uint8_t raw_sk[QUAC_KEM_MAX_SECRET_KEY_BYTES];
size_t pk_len, sk_len;
QUAC_EVP_PKEY_get_raw_keys(kem_key, raw_pk, &pk_len, raw_sk, &sk_len);
/* Use with existing EVP-based code */
EVP_PKEY_free(kem_key);
EVP_PKEY_free(sig_key);
ASN.1 Key Encoding #
Serialize PQC keys to standard DER and PEM formats for storage, transmission, and interoperability. Uses BoringSSL's native CBS/CBB primitives for encoding efficiency.
/* Encode public key to DER (SubjectPublicKeyInfo) */
uint8_t der[2048];
size_t der_len = sizeof(der);
ret = QUAC_encode_public_key_der(QUAC_KEM_ML_KEM_768, pk, pk_len, der, &der_len);
/* Decode public key from DER */
int alg;
uint8_t decoded_pk[QUAC_KEM_MAX_PUBLIC_KEY_BYTES];
size_t decoded_len = sizeof(decoded_pk);
ret = QUAC_decode_public_key_der(der, der_len, &alg, decoded_pk, &decoded_len);
/* Encode to PEM for human-readable output */
char pem[4096];
size_t pem_len = sizeof(pem);
ret = QUAC_encode_public_key_pem(QUAC_KEM_ML_KEM_768, pk, pk_len, pem, &pem_len);
/* Output: -----BEGIN ML-KEM PUBLIC KEY-----\n<base64>\n-----END ML-KEM PUBLIC KEY----- */
/* Private keys (PKCS#8 format) */
ret = QUAC_encode_private_key_der(QUAC_SIG_ML_DSA_65, sk, sk_len, der, &der_len);
ret = QUAC_encode_private_key_pem(QUAC_SIG_ML_DSA_65, sk, sk_len, pem, &pem_len);
Integration Patterns #
Pattern 1: Direct API (Simplest)
Call QUAC functions directly alongside BoringSSL — the simplest and most performant approach:
#include "quac100_boringssl.h"
int main() {
QUAC_init();
/* PQC operations via QUAC */
uint8_t pk[QUAC_ML_KEM_768_PUBLIC_KEY_BYTES];
uint8_t sk[QUAC_ML_KEM_768_SECRET_KEY_BYTES];
QUAC_KEM_keypair(QUAC_KEM_ML_KEM_768, pk, sk);
/* Classical operations via BoringSSL */
uint8_t aes_key[32];
RAND_bytes(aes_key, sizeof(aes_key));
QUAC_cleanup();
}
Pattern 2: Unified Wrapper
Create a wrapper that routes operations to QUAC (PQC) or BoringSSL (classical) based on algorithm type:
/* my_crypto.h — unified interface */
typedef struct {
int type; /* 0=classical, 1=PQC */
union {
EVP_PKEY *classical;
struct { int alg; uint8_t *pk; uint8_t *sk; } pqc;
};
} MY_KEYPAIR;
MY_KEYPAIR *my_generate_keypair(const char *algorithm);
int my_sign(MY_KEYPAIR *key, const uint8_t *msg, ...);
int my_verify(MY_KEYPAIR *key, const uint8_t *msg, ...);
Pattern 3: Modified BoringSSL Build
For fully transparent PQC, patch BoringSSL source to call QUAC functions internally. Key files to modify:
| File | Modification |
|---|---|
crypto/evp/evp.c | Add ML-KEM/ML-DSA to EVP_PKEY types |
ssl/ssl_key_share.cc | Add hybrid group key share implementations |
ssl/internal.h | Define SSL_GROUP_X25519_MLKEM768 constants |
include/openssl/nid.h | Add NIDs for PQC algorithms |
NGINX & Envoy Proxy #
For TLS termination proxies that use BoringSSL, the QUAC integration enables PQC key exchange at the edge:
Envoy Proxy (BoringSSL-based)
// Envoy filter — quac100_envoy_filter.cc
static int pqc_ssl_ctx_setup(SSL_CTX *ctx) {
/* Initialize QUAC */
QUAC_init();
QUAC_TLS_register_groups();
/* Configure hybrid groups — PQC preferred, classical fallback */
SSL_CTX_set1_groups_list(ctx, "X25519_MLKEM768:X25519:P-256");
return 1;
}
NGINX with BoringSSL
# Build NGINX against BoringSSL with QUAC integration
$ ./configure \
--with-openssl=/path/to/boringssl \
--with-cc-opt="-I/usr/local/include" \
--with-ld-opt="-L/usr/local/lib -lquac100_boringssl"
# nginx.conf — enable PQC groups
ssl_ecdh_curve X25519_MLKEM768:X25519:P-256;
ssl_protocols TLSv1.3;
Chromium & gRPC #
BoringSSL is the TLS library for both Chromium and gRPC. The QUAC integration enables PQC for these critical infrastructure components.
Chromium Integration
// third_party/quac100_boringssl/BUILD.gn
static_library("quac100_boringssl") {
sources = [
"quac100_boringssl.c",
"quac100_kem.c",
"quac100_sig.c",
"quac100_rand.c",
"quac100_evp.c",
"quac100_tls.c",
"quac100_asn1.c",
]
deps = [ "//third_party/boringssl" ]
}
gRPC Channel with PQC
// gRPC C++ — configure PQC channel credentials
#include <grpcpp/grpcpp.h>
#include "quac100_boringssl.h"
auto channel_creds = grpc::SslCredentials(grpc::SslCredentialsOptions());
// Enable PQC on the underlying SSL_CTX
grpc::experimental::SetSslRootCertRequestType(
grpc::experimental::GRPC_SSL_CERTIFICATE_REQUEST_TYPE);
// QUAC groups are registered automatically via QUAC_init()
auto channel = grpc::CreateChannel("server:443", channel_creds);
PQC TLS Client Example #
A complete PQC TLS client demonstrating hybrid key exchange with ML-KEM and ML-DSA certificate verification. Source: examples/pqc_client.c
/* Build and run the PQC TLS client */
$ cd quantacore-sdk/integrations/boringssl/build
$ make pqc_client
/* Connect to a PQC-enabled server */
$ ./pqc_client -h example.com -p 443 -v
QUAC 100 PQC TLS Client v1.0.0
Connecting to example.com:443/
Hardware acceleration: ENABLED
TCP connected.
Performing TLS handshake...
Connection Information:
TLS Version: TLSv1.3
Cipher: TLS_AES_256_GCM_SHA384
Key Exchange: X25519_ML-KEM-768 (hybrid)
Session: New
/* Skip cert verification for testing */
$ ./pqc_client -h localhost -p 8443 -k
Key client configuration in code:
/* Create SSL context for TLS 1.3 */
SSL_CTX *ctx = SSL_CTX_new(TLS_client_method());
SSL_CTX_set_min_proto_version(ctx, TLS1_3_VERSION);
/* Enable QUAC PQC support */
quac100_ssl_ctx_enable_pqc(ctx);
/* Set group preference: hybrid first, then classical fallback */
SSL_CTX_set1_groups_list(ctx,
"X25519_MLKEM768:P256_MLKEM768:MLKEM768:X25519:P-256");
PQC TLS Server Example #
A PQC TLS server with auto-generated ML-DSA certificates. Source: examples/pqc_server.c
/* Build and run with auto-generated ML-DSA cert */
$ ./pqc_server -g -p 8443 -v
QUAC 100 PQC TLS Server v1.0.0
Hardware acceleration: ENABLED
Generating ML-DSA-65 certificate...
Certificate generated successfully.
Listening on port 8443
Test: curl -k https://localhost:8443
/* Run with existing PEM certificate */
$ ./pqc_server -c cert.pem -k key.pem -p 443
/* Use ML-DSA-87 (Level 5) for maximum security */
$ ./pqc_server -g -l 87 -p 8443
The server generates an ML-DSA self-signed certificate at startup, configures hybrid key exchange groups, and serves an HTML page showing the PQC connection details including the negotiated key exchange algorithm and cipher suite.
Algorithm Selection Guide #
ML-KEM — When to Use Each Variant
| Variant | Security | Bandwidth | Best For |
|---|---|---|---|
| ML-KEM-512 | Level 1 | Lowest | IoT, embedded, bandwidth-constrained environments |
| ML-KEM-768 | Level 3 | Medium | General purpose — TLS, VPN, most server workloads |
| ML-KEM-1024 | Level 5 | Highest | Government, military, long-term confidential data |
ML-DSA — When to Use Each Variant
| Variant | Security | Signature Size | Best For |
|---|---|---|---|
| ML-DSA-44 | Level 2 | 2,420 B | High-volume verification, fast signature checks |
| ML-DSA-65 | Level 3 | 3,309 B | Balanced — certificates, code signing, general auth |
| ML-DSA-87 | Level 5 | 4,627 B | Maximum security — root certificates, long-lived keys |
Performance Benchmarks #
Hardware-accelerated vs software performance for the BoringSSL integration:
| Algorithm | Operation | Software (ops/s) | Hardware (ops/s) | Speedup |
|---|---|---|---|---|
| ML-KEM-768 | Keygen | ~10,000 | ~500,000 | 50× |
| ML-KEM-768 | Encapsulate | ~15,000 | ~700,000 | 47× |
| ML-KEM-768 | Decapsulate | ~12,000 | ~600,000 | 50× |
| ML-DSA-65 | Sign | ~5,000 | ~200,000 | 40× |
| ML-DSA-65 | Verify | ~8,000 | ~300,000 | 38× |
| QRNG | Generate | ~50 MB/s | ~125 MB/s | 2.5× |
Run Your Own Benchmarks
/* Programmatic benchmarking */
quac_benchmark_result_t results[10];
size_t result_count = 10;
int ret = QUAC_benchmark(QUAC_KEM_ML_KEM_768, 3, results, &result_count);
for (size_t i = 0; i < result_count; i++) {
printf("%s %s: %.0f ops/sec (%.2f µs/op)\n",
results[i].algorithm,
results[i].operation,
results[i].ops_per_second,
results[i].microseconds_per_op);
}
/* Command-line benchmark tool */
$ ./bench_quac100_boringssl --algo ml-kem-768 --duration 5
FIPS Self-Test & Integrity #
For FIPS 140-3 compliance, the library includes Known Answer Tests (KAT) and module integrity verification:
/* Run all FIPS self-tests (KATs for ML-KEM and ML-DSA) */
int ret = QUAC_self_test();
if (ret != QUAC_SUCCESS) {
fprintf(stderr, "FIPS self-test FAILED: %s\n", QUAC_get_error_string(ret));
exit(1);
}
printf("FIPS self-test: PASSED ✓\n");
/* Verify module binary integrity (HMAC check) */
ret = QUAC_integrity_check();
if (ret != QUAC_SUCCESS) {
fprintf(stderr, "Integrity check FAILED — library may be tampered\n");
exit(1);
}
QUAC_init() in FIPS mode. If any KAT fails, the library enters an error state and refuses all cryptographic operations until restarted.
Thread Safety #
All public API functions are thread-safe after QUAC_init() completes. Internal state is protected by pthread mutexes, and hardware operations are serialized through the QUAC 100 driver's DMA queue.
| Function Category | Thread Safety | Notes |
|---|---|---|
Initialization (QUAC_init) | Call once from main thread | Protected by mutex; safe to call multiple times (idempotent) |
| KEM operations | Fully thread-safe | Concurrent keygen/encaps/decaps from any thread |
| Signature operations | Fully thread-safe | Concurrent sign/verify from any thread |
| QRNG | Fully thread-safe | Per-thread buffering for maximum throughput |
| Hybrid TLS contexts | Per-context thread safety | Each QUAC_HYBRID_CTX must be used by one thread at a time |
Cleanup (QUAC_cleanup) | Call once from main thread | After all worker threads have finished |
Error Handling #
All functions return integer status codes. Use QUAC_get_error_string() for human-readable messages:
| Code | Constant | Description |
|---|---|---|
0 | QUAC_SUCCESS | Operation completed successfully |
-1 | QUAC_ERROR_INVALID_ALGORITHM | Unknown or unsupported algorithm identifier |
-2 | QUAC_ERROR_INVALID_KEY | NULL key pointer or malformed key data |
-3 | QUAC_ERROR_INVALID_SIGNATURE | Signature format error (wrong length, all zeros) |
-4 | QUAC_ERROR_INVALID_CIPHERTEXT | Ciphertext format error |
-5 | QUAC_ERROR_BUFFER_TOO_SMALL | Output buffer too small for result |
-6 | QUAC_ERROR_HARDWARE_UNAVAILABLE | Hardware required but not detected |
-7 | QUAC_ERROR_INTERNAL | Internal library error (SDK mismatch, driver failure) |
-8 | QUAC_ERROR_NOT_INITIALIZED | Called before QUAC_init() |
-9 | QUAC_ERROR_MEMORY_ALLOCATION | Memory allocation failed |
-10 | QUAC_ERROR_VERIFICATION_FAILED | Signature verification failed (signature invalid) |
Troubleshooting #
Hardware Not Detected
$ lspci | grep QUAC # Check PCIe device present
$ lsmod | grep quac100 # Check kernel driver loaded
$ ls -la /dev/quac* # Check device permissions
$ pkg-config --exists quac100 # Check SDK installation
Initialization Failures
| Error | Cause | Solution |
|---|---|---|
HARDWARE_UNAVAILABLE | No QUAC device or driver not loaded | Install driver, check PCIe seating, or use QUAC_init_ex(0, 0) for software fallback |
INTERNAL | SDK version mismatch with driver | Update SDK and driver to matching versions |
NOT_INITIALIZED | Called API before QUAC_init() | Ensure init is called once at application startup |
Debug Logging
# Enable verbose logging via environment variable
$ export QUAC_LOG_LEVEL=debug
$ ./my_app 2>&1 | grep "QUAC"
# Check if hardware path is being used
$ QUAC_LOG_LEVEL=info ./my_app 2>&1 | grep "hardware"
[QUAC] Using hardware acceleration on device 0
Build Issues
| Error | Solution |
|---|---|
openssl/ssl.h: No such file | Set -DBORINGSSL_ROOT=/path/to/boringssl in CMake |
undefined reference to QUAC_* | Link with -lquac100_boringssl |
quac100/quac.h: No such file | Set -DQUAC_SDK_PATH=/opt/quantacore-sdk for hardware support |
| BoringSSL CBS/CBB errors | Ensure BoringSSL is built before the integration library |