Files
crypto/hqc/randombytes_shim_native.c
zooqueenandHanzo Dev f249aa4011 hqc: decouple cgo build from native HQC lib (bump accel v1.2.4); fix HQC PQClean CI
Root cause of the never-passing 'HQC PQClean cgo e2e (NIST KAT
roundtrip)' job, in two layers:

1. The lux-build runner had no C compiler (gcc/cc/clang absent), so cgo
   aborted before any code ran. Fixed in prior commits by installing
   build-essential + selecting an available CC.

2. With a compiler present, the cgo build then failed on
   [email protected]/ops/code/code_cpu.go's '#include "lux/gpu/hqc.h"' and
   '-lluxgpu_hqc' — the native HQC library (built from luxfi/mlx) that
   is NOT present in CI (nor in most consumers). accel v1.1.9 gated that
   native path on '//go:build cgo', so every cgo build hard-required the
   native lib/header.

Fix: bump github.com/luxfi/accel v1.1.9 -> v1.2.4, which gates the
native path behind '-tags=lux_hqc_native' and otherwise returns
code.ErrNativeHQCUnavailable (documented: 'callers should fall back to
their own CPU KEM path'). crypto/hqc now honours that contract:

- gpu.go: batchEncapsulateGPU/batchDecapsulateGPU treat
  ErrNativeHQCUnavailable as 'declined' (return false,nil) so callers
  fall back to the per-item PQClean path. Secret buffers are zeroised on
  the decline path.
- gpu_cgo.go: GF2Polymul falls back to the pure-Go Karatsuba path on
  ErrNativeHQCUnavailable. Removed the duplicated vecNSize64 /
  redMaskForMode / GF2Add (now shared).
- gpu_polymul_purego.go (new, tag-neutral): the canonical pure-Go,
  PQClean-byte-identical GF(2)^N polymul (Karatsuba + reduce + base_mul),
  extracted from gpu_nocgo.go so BOTH builds share one implementation.
- gpu_nocgo.go: trimmed to the thin !cgo public wrappers over the shared
  helpers.
- randombytes_shim.c: split. Default (hqc_pqclean, no native) forwards
  randombytes -> hqcGoRandombytes only; the native seed-buffer dispatch
  (which references lux_hqc_randombytes / lux_hqc_seed_has_bytes from the
  native lib) moves to randombytes_shim_native.c, gated on lux_hqc_native.
  Previously the default build referenced those native-only symbols
  unconditionally, which would not link without the native lib.

NOT a crypto/KAT regression: the NIST KAT roundtrip (TestKAT_HQC128/192/
256), TestRoundTrip_AllModes, TestDeterminism, and the GF2 polymul
known-answer vectors all pass byte-for-byte. The GPU batch tests skip
gracefully when the native kernel is absent (their existing t.Skip path).

Verified: CGO_ENABLED=1 go test -tags=hqc_pqclean ./hqc/ passes from a
clean cache; cgo (with/without hqc_pqclean) and nocgo builds all green;
broader suite unchanged (only pre-existing pkg-config failures in cgo/
and hash/poseidon2 remain, unrelated).

Co-authored-by: Hanzo Dev <[email protected]>
2026-06-07 00:19:52 -07:00

47 lines
1.8 KiB
C

//go:build hqc_pqclean && lux_hqc_native
/*
* randombytes_shim_native.c — PQClean randombytes() bridge (native build).
*
* Compiled only with the `lux_hqc_native` build tag, i.e. when the
* luxgpu_hqc static library (built from luxfi/mlx) is linked in and
* accel's native HQC batch kernels are active. It dispatches between
* two entropy sources, in order:
*
* 1. If the C++ batch kernel has installed a per-slot TLS seed
* buffer (lux_hqc_install_seed), bytes are served from there via
* lux_hqc_randombytes. This keeps the batch path byte-identical
* to the direct path.
*
* 2. Otherwise, bytes are read from a Go-side io.Reader via the
* cgo-exported hqcGoRandombytes callback (the direct single-op
* path: backend_pqclean.go's installRNG + lock).
*
* lux_hqc_randombytes / lux_hqc_seed_has_bytes are provided by accel's
* code_cpu_randombytes.go (which is itself gated on lux_hqc_native), so
* the externs below resolve only in this tag combination.
*
* Determinism contract: every call consumes exactly `n` bytes from the
* active source, in call order — load-bearing for the HQC precompile.
*
* Note: this shim deliberately uses the SAME `randombytes` symbol as
* the luxgpu_hqc static library (which marks its definition weak). At
* link time, this strong definition wins.
*/
#include <stdint.h>
#include <stddef.h>
/* Forward declaration of the cgo-exported Go callback. */
extern int hqcGoRandombytes(uint8_t *buf, size_t n);
/* Provided by the luxgpu_hqc library / accel native randombytes TU. */
extern int lux_hqc_randombytes(uint8_t *out, size_t n);
extern int lux_hqc_seed_has_bytes(void);
int randombytes(uint8_t *output, size_t n) {
if (lux_hqc_seed_has_bytes()) {
return lux_hqc_randombytes(output, n);
}
return hqcGoRandombytes(output, n);
}