mirror of
https://github.com/luxfi/crypto.git
synced 2026-07-27 01:54:50 +00:00
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 accel@v1.1.9/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 <dev@hanzo.ai>
51 lines
2.0 KiB
Go
51 lines
2.0 KiB
Go
// Copyright (C) 2024-2026, Lux Industries Inc. All rights reserved.
|
|
// See the file LICENSE for licensing terms.
|
|
|
|
//go:build !cgo
|
|
|
|
// gpu_nocgo.go — pure-Go CPU public surface for HQC's hot GF(2)^N
|
|
// operations. Activates when CGO is disabled (no PQClean / accel
|
|
// linkage).
|
|
//
|
|
// This is NOT a stub. The heavy lifting (bit-sliced Karatsuba
|
|
// multiplication, reduction mod X^N - 1, constant-time base_mul) lives
|
|
// in gpu_polymul_purego.go, which is tag-neutral so the SAME pure-Go
|
|
// implementation also backs the cgo build's fallback (see gpu_cgo.go).
|
|
// This file only exposes the public !cgo entry points:
|
|
//
|
|
// GF2Polymul(mode, c, a, b) c(x) = a(x) * b(x) mod (X^n - 1)
|
|
// GF2Add(c, a, b) c[i] = a[i] ^ b[i] (constant time)
|
|
//
|
|
// Determinism / constant-time guarantees and references are documented
|
|
// on the shared helpers in gpu_polymul_purego.go.
|
|
//
|
|
// --- Batch GPU dispatchers ------------------------------------------
|
|
//
|
|
// batchEncapsulateGPU / batchDecapsulateGPU are defined in gpu.go.
|
|
// Without cgo, accel/ops/code's stub surface returns
|
|
// code.ErrNativeHQCUnavailable, and crypto/hqc's caller falls back to
|
|
// the single-item CPU path (which itself is cgo-only and will hit
|
|
// backend_stub.go's ErrBackendNotWired unless built with
|
|
// -tags=hqc_pqclean).
|
|
|
|
package hqc
|
|
|
|
// GF2Add computes c[i] = a[i] ^ b[i] over GF(2)^N. Constant-time on
|
|
// secret inputs (no branches, no secret-indexed loads). Operates over
|
|
// whatever slice length the caller provides — typically VecNSize64.
|
|
//
|
|
// Used by HQC's encapsulation step (PKE.Encrypt: u = r1 + h*r2 + e).
|
|
func GF2Add(c, a, b []uint64) {
|
|
gf2AddGo(c, a, b)
|
|
}
|
|
|
|
// GF2Polymul computes c(x) = a(x) * b(x) mod (X^n - 1) in GF(2)[X]
|
|
// for ONE polynomial. All three buffers must be length VecNSize64.
|
|
//
|
|
// Implementation: bit-sliced Karatsuba recursion with the mul1 base
|
|
// case, identical to PQClean's vect_mul (reference C code). See
|
|
// gpu_polymul_purego.go.
|
|
func GF2Polymul(mode Mode, c, a, b []uint64) error {
|
|
return polymulGo(mode, c, a, b)
|
|
}
|