Establishes the integration pattern for lumbda's future cuda primitive
across Python / C / asm tiers without dragging the CUDA toolchain into
lumbda's core build.
Shape: leaf binary that every tier spawns via its existing process-
spawn primitive & talks to through S-expression input + output
portals. Asm tier inherits via fork + execve syscalls; no libcudart
linkage; no DKMS dependency at lumbda build time.
Files:
shake256-fanout.cu self-contained CUDA SHAKE256 fan-out, Keccak
permutation derived from FIPS 202 reference
(tiny-sha3 lineage, CC0 → re-licensed AGPLv3)
Makefile nvcc build + make test + make bench
test_roundtrip.py validates output byte-identical to
hashlib.shake_256
bench.py device vs host throughput at N = 1k / 10k / 100k
lumbda-call.lsp reference Scheme wrapper showing the
(cuda-shake-fanout inputs out-bytes) API shape
lumbda's core would dispatch to per-tier
README.md full integration story, wire contract, the
three changes each tier needs (~20 LoC each),
generalization path for other CUDA primitives
Tested on 3090-ai (RTX 3090):
make test → PASS — 4 / 4 hashes byte-identical to hashlib.shake_256
Honest bench (32-byte inputs):
N host (Python hashlib) device (kernel launch dominated)
1,000 0.6 ms 188.1 ms
10,000 5.9 ms 195.7 ms
100,000 58.7 ms 313.8 ms
Useful primitive when inputs are larger (KB+) or N reaches millions;
honest about the launch-overhead break-even point. This is the
reference, not the win — the win is locking the API shape so each
tier registers under one stable name.
Provenance: extracted as the generic pattern from
~/git/www.foxhop.net/ecdsa/cuda/sim_gpu.cu where on-device SHAKE
delivered 2.6× memory compression for batched reversible-circuit
simulation. Re-shipping the primitive back to the lumbda repo so the
ecosystem inherits the work.
39 lines
1.5 KiB
Makefile
39 lines
1.5 KiB
Makefile
# shake256-fanout — Makefile.
|
|
#
|
|
# Builds the reference cuda fan-out worker. Each lumbda tier (Python,
|
|
# C, asm) spawns this binary via its existing process-spawn primitive
|
|
# & talks to it through input + output portal files. No tier links
|
|
# against libcudart directly — the CUDA toolchain dependency stays
|
|
# isolated to this directory.
|
|
#
|
|
# Build:
|
|
# make all — compile shake256-fanout (needs nvcc)
|
|
# make test — round-trip test (host + device produce identical
|
|
# SHAKE256 outputs over a small synthetic input set)
|
|
# make bench — bench device vs host throughput at N = 100k
|
|
|
|
NVCC ?= nvcc
|
|
NVCCFLAGS ?= -O3 -arch=sm_86 -Xcompiler="-O3 -Wall -Wextra"
|
|
NVCC_PATH ?= $(shell which nvcc 2>/dev/null || echo /usr/local/cuda/bin/nvcc)
|
|
|
|
all: shake256-fanout
|
|
|
|
shake256-fanout: shake256-fanout.cu
|
|
$(NVCC) $(NVCCFLAGS) -o $@ $<
|
|
|
|
# round-trip: feed (cuda-shake-fanout (output-bytes 32) (inputs ...))
|
|
# through the binary, compare against an external SHAKE256 reference
|
|
# (Python hashlib.shake_256).
|
|
test: shake256-fanout test_roundtrip.py
|
|
@printf '(cuda-shake-fanout\n (output-bytes 32)\n (inputs\n' > /tmp/cf-in.portal
|
|
@printf ' "00"\n "01"\n "deadbeef"\n "%s"\n' \
|
|
"$$(python3 -c 'print("ab" * 100)')" >> /tmp/cf-in.portal
|
|
@printf '))\n' >> /tmp/cf-in.portal
|
|
./shake256-fanout /tmp/cf-in.portal /tmp/cf-out.portal
|
|
python3 test_roundtrip.py /tmp/cf-in.portal /tmp/cf-out.portal
|
|
|
|
bench: shake256-fanout bench.py
|
|
python3 bench.py ./shake256-fanout
|
|
|
|
clean:
|
|
rm -f shake256-fanout /tmp/cf-in.portal /tmp/cf-out.portal
|