mirror of
https://github.com/luxfi/crypto.git
synced 2026-07-27 01:54:50 +00:00
fix: gofmt -s across repo (CI format check)
This commit is contained in:
@@ -71,14 +71,14 @@ type SignatureConfig struct {
|
|||||||
PreferredType SignatureType `json:"preferredType"`
|
PreferredType SignatureType `json:"preferredType"`
|
||||||
|
|
||||||
// Enable specific signature types
|
// Enable specific signature types
|
||||||
EnableBLS bool `json:"enableBLS"`
|
EnableBLS bool `json:"enableBLS"`
|
||||||
EnableCorona bool `json:"enableCorona"`
|
EnableCorona bool `json:"enableCorona"`
|
||||||
EnableCGGMP21 bool `json:"enableCGGMP21"`
|
EnableCGGMP21 bool `json:"enableCGGMP21"`
|
||||||
|
|
||||||
// Fee configuration (in nLUX - nano LUX)
|
// Fee configuration (in nLUX - nano LUX)
|
||||||
BLSFee uint64 `json:"blsFee"` // 0 = free
|
BLSFee uint64 `json:"blsFee"` // 0 = free
|
||||||
CoronaFee uint64 `json:"coronaFee"` // Premium for enhanced privacy
|
CoronaFee uint64 `json:"coronaFee"` // Premium for enhanced privacy
|
||||||
CGGMP21Fee uint64 `json:"cggmp21Fee"` // Premium for threshold signatures
|
CGGMP21Fee uint64 `json:"cggmp21Fee"` // Premium for threshold signatures
|
||||||
|
|
||||||
// Performance settings
|
// Performance settings
|
||||||
ParallelAggregation bool `json:"parallelAggregation"`
|
ParallelAggregation bool `json:"parallelAggregation"`
|
||||||
|
|||||||
@@ -188,4 +188,3 @@ func TestEnvOverride(t *testing.T) {
|
|||||||
t.Errorf("env override: Default() = %v; want Vanilla", got)
|
t.Errorf("env override: Default() = %v; want Vanilla", got)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -22,10 +22,10 @@ type kat struct {
|
|||||||
Key string `json:"key"`
|
Key string `json:"key"`
|
||||||
ContextString string `json:"context_string"`
|
ContextString string `json:"context_string"`
|
||||||
Cases []struct {
|
Cases []struct {
|
||||||
InputLen int `json:"input_len"`
|
InputLen int `json:"input_len"`
|
||||||
Hash string `json:"hash"`
|
Hash string `json:"hash"`
|
||||||
KeyedHash string `json:"keyed_hash"`
|
KeyedHash string `json:"keyed_hash"`
|
||||||
DeriveKey string `json:"derive_key"`
|
DeriveKey string `json:"derive_key"`
|
||||||
} `json:"cases"`
|
} `json:"cases"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -68,8 +68,8 @@ type rngState struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
rngMu sync.Mutex
|
rngMu sync.Mutex
|
||||||
activeRNG *rngState
|
activeRNG *rngState
|
||||||
)
|
)
|
||||||
|
|
||||||
// installRNG takes the cgo lock and registers `r` as the entropy
|
// installRNG takes the cgo lock and registers `r` as the entropy
|
||||||
@@ -92,12 +92,12 @@ func clearRNG() error {
|
|||||||
return s.err
|
return s.err
|
||||||
}
|
}
|
||||||
|
|
||||||
//export hqcGoRandombytes
|
|
||||||
//
|
|
||||||
// Called from randombytes_shim.c. Reads exactly `n` bytes from the
|
// Called from randombytes_shim.c. Reads exactly `n` bytes from the
|
||||||
// installed RNG into the buffer at `buf`. Returns 0 on full read,
|
// installed RNG into the buffer at `buf`. Returns 0 on full read,
|
||||||
// non-zero on partial read or reader error (PQClean checks the
|
// non-zero on partial read or reader error (PQClean checks the
|
||||||
// return value of randombytes() == 0).
|
// return value of randombytes() == 0).
|
||||||
|
//
|
||||||
|
//export hqcGoRandombytes
|
||||||
func hqcGoRandombytes(buf *C.uint8_t, n C.size_t) C.int {
|
func hqcGoRandombytes(buf *C.uint8_t, n C.size_t) C.int {
|
||||||
if activeRNG == nil {
|
if activeRNG == nil {
|
||||||
// Misuse — no RNG installed. Fail loudly via non-zero return
|
// Misuse — no RNG installed. Fail loudly via non-zero return
|
||||||
|
|||||||
+8
-7
@@ -34,10 +34,11 @@ import (
|
|||||||
// amortises the cgo crossover across slots.
|
// amortises the cgo crossover across slots.
|
||||||
//
|
//
|
||||||
// Measured on Apple M1 Max (HQC-128 encaps):
|
// Measured on Apple M1 Max (HQC-128 encaps):
|
||||||
// 1-item batch: accel = 35 us, direct = 30 us (direct wins)
|
//
|
||||||
// 4-item batch: accel = 110 us, direct = 120 us (parity)
|
// 1-item batch: accel = 35 us, direct = 30 us (direct wins)
|
||||||
// 16-item batch: accel = 410 us, direct = 480 us (accel ~17% win)
|
// 4-item batch: accel = 110 us, direct = 120 us (parity)
|
||||||
// 128-item batch: accel = 1.7 ms, direct = 3.8 ms (accel ~2.2x)
|
// 16-item batch: accel = 410 us, direct = 480 us (accel ~17% win)
|
||||||
|
// 128-item batch: accel = 1.7 ms, direct = 3.8 ms (accel ~2.2x)
|
||||||
//
|
//
|
||||||
// The exact threshold is workload-dependent. We pick 4 (the first
|
// The exact threshold is workload-dependent. We pick 4 (the first
|
||||||
// batch size where accel matches direct) so the API remains useful
|
// batch size where accel matches direct) so the API remains useful
|
||||||
@@ -53,9 +54,9 @@ const batchSizeThreshold = 4
|
|||||||
// OpenMP at the C++ level. That parallelism is independent of whether
|
// OpenMP at the C++ level. That parallelism is independent of whether
|
||||||
// a "real" GPU device is present — the kernels share the same C++
|
// a "real" GPU device is present — the kernels share the same C++
|
||||||
// host loop. We therefore key dispatch on:
|
// host loop. We therefore key dispatch on:
|
||||||
// 1. backend.IsVanilla() is false — i.e. the caller did NOT explicitly
|
// 1. backend.IsVanilla() is false — i.e. the caller did NOT explicitly
|
||||||
// pick the pure-Go fallback.
|
// pick the pure-Go fallback.
|
||||||
// 2. The batch is large enough to amortise the cgo crossover.
|
// 2. The batch is large enough to amortise the cgo crossover.
|
||||||
//
|
//
|
||||||
// We do NOT consult a session handle here — accel/ops/code parallelises via
|
// We do NOT consult a session handle here — accel/ops/code parallelises via
|
||||||
// OpenMP at the C++ level whether or not a Metal/CUDA device exists, so the
|
// OpenMP at the C++ level whether or not a Metal/CUDA device exists, so the
|
||||||
|
|||||||
+3
-3
@@ -153,10 +153,10 @@ func karatsuba(o, a, b []uint64, size int, stack []uint64) {
|
|||||||
ah := a[sizeL:]
|
ah := a[sizeL:]
|
||||||
bh := b[sizeL:]
|
bh := b[sizeL:]
|
||||||
|
|
||||||
karatsuba(o, a, b, sizeL, rest) // o[0:2*sizeL] = a_L * b_L
|
karatsuba(o, a, b, sizeL, rest) // o[0:2*sizeL] = a_L * b_L
|
||||||
karatsuba(tmp2, ah, bh, sizeH, rest) // tmp2 = a_H * b_H
|
karatsuba(tmp2, ah, bh, sizeH, rest) // tmp2 = a_H * b_H
|
||||||
karatsubaAdd1(alh, blh, a, b, sizeL, sizeH)
|
karatsubaAdd1(alh, blh, a, b, sizeL, sizeH)
|
||||||
karatsuba(tmp1, alh, blh, sizeL, rest) // tmp1 = (a_L+a_H)*(b_L+b_H)
|
karatsuba(tmp1, alh, blh, sizeL, rest) // tmp1 = (a_L+a_H)*(b_L+b_H)
|
||||||
karatsubaAdd2(o, tmp1, tmp2, sizeL, sizeH)
|
karatsubaAdd2(o, tmp1, tmp2, sizeL, sizeH)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+5
-5
@@ -18,11 +18,11 @@ import (
|
|||||||
// CPU PQClean reference. The two paths share the same canonical
|
// CPU PQClean reference. The two paths share the same canonical
|
||||||
// kernels via accel/ops/code so the test asserts that:
|
// kernels via accel/ops/code so the test asserts that:
|
||||||
//
|
//
|
||||||
// 1. The GPU batch path returns valid (ct, ss) pairs (decap-able by
|
// 1. The GPU batch path returns valid (ct, ss) pairs (decap-able by
|
||||||
// the canonical PQClean reference).
|
// the canonical PQClean reference).
|
||||||
// 2. The byte layout matches what PQClean produces with the same
|
// 2. The byte layout matches what PQClean produces with the same
|
||||||
// entropy stream — there is no "shifted" or "padded" encoding
|
// entropy stream — there is no "shifted" or "padded" encoding
|
||||||
// difference between the two paths.
|
// difference between the two paths.
|
||||||
//
|
//
|
||||||
// We can't compare against per-item GPU vs per-item CPU directly
|
// We can't compare against per-item GPU vs per-item CPU directly
|
||||||
// because the batch surface takes a flat seed buffer while the
|
// because the batch surface takes a flat seed buffer while the
|
||||||
|
|||||||
+17
-17
@@ -21,17 +21,17 @@
|
|||||||
//
|
//
|
||||||
// Backends:
|
// Backends:
|
||||||
//
|
//
|
||||||
// 1. PQClean cgo (default for non-stub builds). Build with
|
// 1. PQClean cgo (default for non-stub builds). Build with
|
||||||
// `-tags=hqc_pqclean`. Wires the vendored PQClean HQC reference
|
// `-tags=hqc_pqclean`. Wires the vendored PQClean HQC reference
|
||||||
// implementation under crypto/hqc/pqclean/ (public domain). NIST
|
// implementation under crypto/hqc/pqclean/ (public domain). NIST
|
||||||
// KAT vectors verify byte-for-byte — see
|
// KAT vectors verify byte-for-byte — see
|
||||||
// crypto/hqc/backend_pqclean_test.go's TestKAT_HQC{128,192,256}.
|
// crypto/hqc/backend_pqclean_test.go's TestKAT_HQC{128,192,256}.
|
||||||
// 2. Cloudflare CIRCL Go (placeholder; build tag `hqc_circl`).
|
// 2. Cloudflare CIRCL Go (placeholder; build tag `hqc_circl`).
|
||||||
// Activates once CIRCL ships HQC support.
|
// Activates once CIRCL ships HQC support.
|
||||||
// 3. Stub (default). When no backend tag is set, every operation
|
// 3. Stub (default). When no backend tag is set, every operation
|
||||||
// returns ErrBackendNotWired so the package still compiles on
|
// returns ErrBackendNotWired so the package still compiles on
|
||||||
// hosts without cgo. The wire format and parameter constants are
|
// hosts without cgo. The wire format and parameter constants are
|
||||||
// fixed by NIST IR 8528 §4.1 and remain stable across backends.
|
// fixed by NIST IR 8528 §4.1 and remain stable across backends.
|
||||||
package hqc
|
package hqc
|
||||||
|
|
||||||
import (
|
import (
|
||||||
@@ -58,12 +58,12 @@ const (
|
|||||||
|
|
||||||
// Params returns the fixed sizes for the parameter set.
|
// Params returns the fixed sizes for the parameter set.
|
||||||
type Params struct {
|
type Params struct {
|
||||||
Mode Mode
|
Mode Mode
|
||||||
PublicKeySize int
|
PublicKeySize int
|
||||||
PrivateKeySize int
|
PrivateKeySize int
|
||||||
CiphertextSize int
|
CiphertextSize int
|
||||||
SharedSecretSize int
|
SharedSecretSize int
|
||||||
SecurityLevelBits int // NIST PQ category mapped to ≈ AES key bits
|
SecurityLevelBits int // NIST PQ category mapped to ≈ AES key bits
|
||||||
}
|
}
|
||||||
|
|
||||||
// MustParamsFor returns the canonical Params for `mode` or panics on
|
// MustParamsFor returns the canonical Params for `mode` or panics on
|
||||||
|
|||||||
@@ -16,9 +16,9 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
once sync.Once
|
once sync.Once
|
||||||
sess *accel.Session
|
sess *accel.Session
|
||||||
initErr error
|
initErr error
|
||||||
available bool
|
available bool
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -6,7 +6,7 @@
|
|||||||
// - vanilla: golang.org/x/crypto/sha3.NewLegacyKeccak256 (pure Go)
|
// - vanilla: golang.org/x/crypto/sha3.NewLegacyKeccak256 (pure Go)
|
||||||
// - cgo: uses libluxcrypto's optimised C implementation when CGO is on
|
// - cgo: uses libluxcrypto's optimised C implementation when CGO is on
|
||||||
// - gpu: batch-routes through github.com/luxfi/accel for batches that
|
// - gpu: batch-routes through github.com/luxfi/accel for batches that
|
||||||
// exceed the BatchThreshold cutoff
|
// exceed the BatchThreshold cutoff
|
||||||
//
|
//
|
||||||
// The dispatcher honours backend.Default(); see github.com/luxfi/crypto/backend.
|
// The dispatcher honours backend.Default(); see github.com/luxfi/crypto/backend.
|
||||||
package keccak256
|
package keccak256
|
||||||
|
|||||||
+9
-9
@@ -26,12 +26,12 @@ var concurrentBatchThreshold = 8
|
|||||||
//
|
//
|
||||||
// Dispatch ladder:
|
// Dispatch ladder:
|
||||||
//
|
//
|
||||||
// 1. GPU substrate (accel.LatticeOps.MLDSAVerifyBatch) when n >= BatchThreshold
|
// 1. GPU substrate (accel.LatticeOps.MLDSAVerifyBatch) when n >= BatchThreshold
|
||||||
// AND a backend plugin is loaded AND mode is in {44, 65, 87}.
|
// AND a backend plugin is loaded AND mode is in {44, 65, 87}.
|
||||||
// 2. Goroutine-parallel CPU verify when n >= concurrentBatchThreshold.
|
// 2. Goroutine-parallel CPU verify when n >= concurrentBatchThreshold.
|
||||||
// Scales to GOMAXPROCS without GPU substrate. Useful on hosts that
|
// Scales to GOMAXPROCS without GPU substrate. Useful on hosts that
|
||||||
// have CPU cores but no GPU plugin (Linux CI, no-Metal Macs, etc).
|
// have CPU cores but no GPU plugin (Linux CI, no-Metal Macs, etc).
|
||||||
// 3. Serial CPU verify as the floor.
|
// 3. Serial CPU verify as the floor.
|
||||||
//
|
//
|
||||||
// All paths are byte-equal: each path ends in cloudflare/circl's
|
// All paths are byte-equal: each path ends in cloudflare/circl's
|
||||||
// FIPS 204-conformant Verify. The dispatch choice only affects throughput,
|
// FIPS 204-conformant Verify. The dispatch choice only affects throughput,
|
||||||
@@ -131,9 +131,9 @@ var ErrBatchLength = errors.New("mldsa: batch input slices have inconsistent len
|
|||||||
//
|
//
|
||||||
// Dispatch ladder mirrors BatchVerify:
|
// Dispatch ladder mirrors BatchVerify:
|
||||||
//
|
//
|
||||||
// 1. GPU substrate (accel.LatticeOps.MLDSASignBatch).
|
// 1. GPU substrate (accel.LatticeOps.MLDSASignBatch).
|
||||||
// 2. Goroutine-parallel CPU sign.
|
// 2. Goroutine-parallel CPU sign.
|
||||||
// 3. Serial CPU sign.
|
// 3. Serial CPU sign.
|
||||||
//
|
//
|
||||||
// For deterministic-mode signing (FIPS 204 § Algorithm 2 with rnd=0^256),
|
// For deterministic-mode signing (FIPS 204 § Algorithm 2 with rnd=0^256),
|
||||||
// callers can pass nil for randSource. The CPU path passes deterministic=true
|
// callers can pass nil for randSource. The CPU path passes deterministic=true
|
||||||
|
|||||||
@@ -29,8 +29,6 @@ import (
|
|||||||
|
|
||||||
"github.com/cloudflare/circl/sign/mldsa/mldsa44"
|
"github.com/cloudflare/circl/sign/mldsa/mldsa44"
|
||||||
"github.com/luxfi/crypto/backend"
|
"github.com/luxfi/crypto/backend"
|
||||||
|
|
||||||
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// genBatch44 produces n ML-DSA-44 keypairs + signs distinct messages with
|
// genBatch44 produces n ML-DSA-44 keypairs + signs distinct messages with
|
||||||
@@ -223,9 +221,9 @@ func TestMLDSA44_BatchSign_RoundTrip(t *testing.T) {
|
|||||||
// BenchmarkMLDSA44_BatchVerify measures throughput of the ML-DSA-44 batch
|
// BenchmarkMLDSA44_BatchVerify measures throughput of the ML-DSA-44 batch
|
||||||
// verify dispatch ladder. Run with -bench=. to compare:
|
// verify dispatch ladder. Run with -bench=. to compare:
|
||||||
//
|
//
|
||||||
// BenchmarkMLDSA44_BatchVerify/serial-1
|
// BenchmarkMLDSA44_BatchVerify/serial-1
|
||||||
// BenchmarkMLDSA44_BatchVerify/concurrent-8
|
// BenchmarkMLDSA44_BatchVerify/concurrent-8
|
||||||
// BenchmarkMLDSA44_BatchVerify/concurrent-32
|
// BenchmarkMLDSA44_BatchVerify/concurrent-32
|
||||||
func BenchmarkMLDSA44_BatchVerify(b *testing.B) {
|
func BenchmarkMLDSA44_BatchVerify(b *testing.B) {
|
||||||
for _, size := range []int{1, 8, 32, 64} {
|
for _, size := range []int{1, 8, 32, 64} {
|
||||||
b.Run(fmt.Sprintf("n=%d", size), func(b *testing.B) {
|
b.Run(fmt.Sprintf("n=%d", size), func(b *testing.B) {
|
||||||
|
|||||||
@@ -21,8 +21,6 @@ import (
|
|||||||
|
|
||||||
"github.com/cloudflare/circl/sign/mldsa/mldsa87"
|
"github.com/cloudflare/circl/sign/mldsa/mldsa87"
|
||||||
"github.com/luxfi/crypto/backend"
|
"github.com/luxfi/crypto/backend"
|
||||||
|
|
||||||
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func genBatch87(t testing.TB, n int) (pubs []*PublicKey, msgs [][]byte, sigs [][]byte) {
|
func genBatch87(t testing.TB, n int) (pubs []*PublicKey, msgs [][]byte, sigs [][]byte) {
|
||||||
|
|||||||
+6
-6
@@ -50,12 +50,12 @@ func (t DispatchTier) String() string {
|
|||||||
// Provenance is the auditable evidence record for the ML-DSA package.
|
// Provenance is the auditable evidence record for the ML-DSA package.
|
||||||
// See slhdsa.Provenance — same shape, same purpose.
|
// See slhdsa.Provenance — same shape, same purpose.
|
||||||
type Provenance struct {
|
type Provenance struct {
|
||||||
Tier DispatchTier
|
Tier DispatchTier
|
||||||
AccelInitialised bool
|
AccelInitialised bool
|
||||||
DeviceAvailable bool
|
DeviceAvailable bool
|
||||||
PluginStrongSymbol bool
|
PluginStrongSymbol bool
|
||||||
BatchThresholdN int
|
BatchThresholdN int
|
||||||
ConcurrentThresholdN int
|
ConcurrentThresholdN int
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetProvenance returns the current dispatch provenance.
|
// GetProvenance returns the current dispatch provenance.
|
||||||
|
|||||||
@@ -81,27 +81,27 @@ func mlkem_decaps_ct_setup() C.int {
|
|||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
//export mlkem_decaps_ct_pool_size
|
|
||||||
//
|
|
||||||
// Returns the per-sample input width (FIPS 203 ML-KEM-768 ciphertext
|
// Returns the per-sample input width (FIPS 203 ML-KEM-768 ciphertext
|
||||||
// is 1088 bytes). Named "pool_size" for harness API compatibility.
|
// is 1088 bytes). Named "pool_size" for harness API compatibility.
|
||||||
|
//
|
||||||
|
//export mlkem_decaps_ct_pool_size
|
||||||
func mlkem_decaps_ct_pool_size() C.size_t {
|
func mlkem_decaps_ct_pool_size() C.size_t {
|
||||||
return C.size_t(dMlkemCTSize)
|
return C.size_t(dMlkemCTSize)
|
||||||
}
|
}
|
||||||
|
|
||||||
//export mlkem_decaps_ct_input_size
|
|
||||||
//
|
|
||||||
// Same as pool_size — full ciphertext bytes per sample.
|
// Same as pool_size — full ciphertext bytes per sample.
|
||||||
|
//
|
||||||
|
//export mlkem_decaps_ct_input_size
|
||||||
func mlkem_decaps_ct_input_size() C.size_t {
|
func mlkem_decaps_ct_input_size() C.size_t {
|
||||||
return C.size_t(dMlkemCTSize)
|
return C.size_t(dMlkemCTSize)
|
||||||
}
|
}
|
||||||
|
|
||||||
//export mlkem_decaps_ct_copy_valid_ct
|
|
||||||
//
|
|
||||||
// Copies the class-A reference ciphertext into the caller-supplied C
|
// Copies the class-A reference ciphertext into the caller-supplied C
|
||||||
// buffer (must be at least mlkem_decaps_ct_input_size() bytes). Returns
|
// buffer (must be at least mlkem_decaps_ct_input_size() bytes). Returns
|
||||||
// 0 on success. Avoids passing a Go pointer back through cgo (which
|
// 0 on success. Avoids passing a Go pointer back through cgo (which
|
||||||
// would trip Go 1.26's cgocheck=1 unpinned-pointer panic).
|
// would trip Go 1.26's cgocheck=1 unpinned-pointer panic).
|
||||||
|
//
|
||||||
|
//export mlkem_decaps_ct_copy_valid_ct
|
||||||
func mlkem_decaps_ct_copy_valid_ct(dst *C.uint8_t) C.int {
|
func mlkem_decaps_ct_copy_valid_ct(dst *C.uint8_t) C.int {
|
||||||
if len(dMlkemValidCT) == 0 || dst == nil {
|
if len(dMlkemValidCT) == 0 || dst == nil {
|
||||||
return 1
|
return 1
|
||||||
@@ -110,8 +110,6 @@ func mlkem_decaps_ct_copy_valid_ct(dst *C.uint8_t) C.int {
|
|||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
//export mlkem_decaps_ct
|
|
||||||
//
|
|
||||||
// One dudect sample: decapsulate the per-sample bytes. Class A → valid
|
// One dudect sample: decapsulate the per-sample bytes. Class A → valid
|
||||||
// reference ciphertext (FO-accept branch). Class B → caller-random
|
// reference ciphertext (FO-accept branch). Class B → caller-random
|
||||||
// bytes (FO-reject branch via implicit rejection). Output is discarded;
|
// bytes (FO-reject branch via implicit rejection). Output is discarded;
|
||||||
@@ -120,6 +118,8 @@ func mlkem_decaps_ct_copy_valid_ct(dst *C.uint8_t) C.int {
|
|||||||
// Critical: this function MUST be branchless in its dispatch — only
|
// Critical: this function MUST be branchless in its dispatch — only
|
||||||
// the Decaps call may differ between samples. Any data-dependent
|
// the Decaps call may differ between samples. Any data-dependent
|
||||||
// branch here would surface as a harness artifact.
|
// branch here would surface as a harness artifact.
|
||||||
|
//
|
||||||
|
//export mlkem_decaps_ct
|
||||||
func mlkem_decaps_ct(data *C.uint8_t) {
|
func mlkem_decaps_ct(data *C.uint8_t) {
|
||||||
if dMlkemSK == nil {
|
if dMlkemSK == nil {
|
||||||
return
|
return
|
||||||
|
|||||||
@@ -33,9 +33,9 @@ import (
|
|||||||
|
|
||||||
const kKeygenRandSize = 64 // ML-KEM-768 keygen tape per FIPS 203
|
const kKeygenRandSize = 64 // ML-KEM-768 keygen tape per FIPS 203
|
||||||
|
|
||||||
//export mlkem_keygen_ct_setup
|
|
||||||
//
|
|
||||||
// Returns 0 on success.
|
// Returns 0 on success.
|
||||||
|
//
|
||||||
|
//export mlkem_keygen_ct_setup
|
||||||
func mlkem_keygen_ct_setup() C.int {
|
func mlkem_keygen_ct_setup() C.int {
|
||||||
// Smoke test: ensure the underlying API is functional with a
|
// Smoke test: ensure the underlying API is functional with a
|
||||||
// zero tape (the class-A input).
|
// zero tape (the class-A input).
|
||||||
@@ -47,16 +47,16 @@ func mlkem_keygen_ct_setup() C.int {
|
|||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
//export mlkem_keygen_ct_input_size
|
|
||||||
//
|
|
||||||
// Returns the per-sample input width: 64 bytes (the keygen tape).
|
// Returns the per-sample input width: 64 bytes (the keygen tape).
|
||||||
|
//
|
||||||
|
//export mlkem_keygen_ct_input_size
|
||||||
func mlkem_keygen_ct_input_size() C.size_t {
|
func mlkem_keygen_ct_input_size() C.size_t {
|
||||||
return C.size_t(kKeygenRandSize)
|
return C.size_t(kKeygenRandSize)
|
||||||
}
|
}
|
||||||
|
|
||||||
//export mlkem_keygen_ct
|
|
||||||
//
|
|
||||||
// One dudect measurement sample. data points to a 64-byte tape.
|
// One dudect measurement sample. data points to a 64-byte tape.
|
||||||
|
//
|
||||||
|
//export mlkem_keygen_ct
|
||||||
func mlkem_keygen_ct(data *C.uint8_t) {
|
func mlkem_keygen_ct(data *C.uint8_t) {
|
||||||
src := unsafe.Slice((*byte)(unsafe.Pointer(data)), kKeygenRandSize)
|
src := unsafe.Slice((*byte)(unsafe.Pointer(data)), kKeygenRandSize)
|
||||||
r := bytes.NewReader(src)
|
r := bytes.NewReader(src)
|
||||||
|
|||||||
+10
-10
@@ -111,10 +111,10 @@ func buildValidInput(randSrc *[kProofBodyLen + kPubLen]byte) []byte {
|
|||||||
return out
|
return out
|
||||||
}
|
}
|
||||||
|
|
||||||
//export p3q_verify_ct_setup
|
|
||||||
//
|
|
||||||
// Initialise the per-startup pool of valid inputs. Returns 0 on
|
// Initialise the per-startup pool of valid inputs. Returns 0 on
|
||||||
// success, non-zero on failure.
|
// success, non-zero on failure.
|
||||||
|
//
|
||||||
|
//export p3q_verify_ct_setup
|
||||||
func p3q_verify_ct_setup() C.int {
|
func p3q_verify_ct_setup() C.int {
|
||||||
// Register a backend verifier that always accepts. This pins the
|
// Register a backend verifier that always accepts. This pins the
|
||||||
// CT measurement on the precompile dispatch + backend invocation
|
// CT measurement on the precompile dispatch + backend invocation
|
||||||
@@ -134,24 +134,24 @@ func p3q_verify_ct_setup() C.int {
|
|||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
//export p3q_verify_ct_input_size
|
|
||||||
//
|
|
||||||
// Returns the per-sample input size for the C harness scratch buffer.
|
// Returns the per-sample input size for the C harness scratch buffer.
|
||||||
|
//
|
||||||
|
//export p3q_verify_ct_input_size
|
||||||
func p3q_verify_ct_input_size() C.size_t {
|
func p3q_verify_ct_input_size() C.size_t {
|
||||||
return C.size_t(kInputLen)
|
return C.size_t(kInputLen)
|
||||||
}
|
}
|
||||||
|
|
||||||
//export p3q_verify_ct_pool_size
|
|
||||||
//
|
|
||||||
// Returns the number of valid inputs in the per-startup pool.
|
// Returns the number of valid inputs in the per-startup pool.
|
||||||
|
//
|
||||||
|
//export p3q_verify_ct_pool_size
|
||||||
func p3q_verify_ct_pool_size() C.size_t {
|
func p3q_verify_ct_pool_size() C.size_t {
|
||||||
return C.size_t(kValidPool)
|
return C.size_t(kValidPool)
|
||||||
}
|
}
|
||||||
|
|
||||||
//export p3q_verify_ct_copy_pool
|
|
||||||
//
|
|
||||||
// Copies validPool[idx] into the caller-supplied dst buffer
|
// Copies validPool[idx] into the caller-supplied dst buffer
|
||||||
// (kInputLen bytes). Returns 0 on success, non-zero on bounds violation.
|
// (kInputLen bytes). Returns 0 on success, non-zero on bounds violation.
|
||||||
|
//
|
||||||
|
//export p3q_verify_ct_copy_pool
|
||||||
func p3q_verify_ct_copy_pool(idx C.size_t, dst *C.uint8_t) C.int {
|
func p3q_verify_ct_copy_pool(idx C.size_t, dst *C.uint8_t) C.int {
|
||||||
i := int(idx)
|
i := int(idx)
|
||||||
if i < 0 || i >= kValidPool || validPool[i] == nil {
|
if i < 0 || i >= kValidPool || validPool[i] == nil {
|
||||||
@@ -168,8 +168,6 @@ var (
|
|||||||
supplied = uint64(1 << 30) // far above required for kInputLen
|
supplied = uint64(1 << 30) // far above required for kInputLen
|
||||||
)
|
)
|
||||||
|
|
||||||
//export p3q_verify_ct
|
|
||||||
//
|
|
||||||
// One dudect measurement sample.
|
// One dudect measurement sample.
|
||||||
//
|
//
|
||||||
// data points to kInputLen bytes of caller-controlled wire calldata.
|
// data points to kInputLen bytes of caller-controlled wire calldata.
|
||||||
@@ -180,6 +178,8 @@ var (
|
|||||||
// The function MUST be branchless on `data` — any data-dependent
|
// The function MUST be branchless on `data` — any data-dependent
|
||||||
// branch we introduce here pollutes the measurement before Run()
|
// branch we introduce here pollutes the measurement before Run()
|
||||||
// even starts. We only copy data into a fresh slice and dispatch.
|
// even starts. We only copy data into a fresh slice and dispatch.
|
||||||
|
//
|
||||||
|
//export p3q_verify_ct
|
||||||
func p3q_verify_ct(data *C.uint8_t) {
|
func p3q_verify_ct(data *C.uint8_t) {
|
||||||
inputSlice := unsafe.Slice((*byte)(unsafe.Pointer(data)), kInputLen)
|
inputSlice := unsafe.Slice((*byte)(unsafe.Pointer(data)), kInputLen)
|
||||||
input := append([]byte{}, inputSlice...)
|
input := append([]byte{}, inputSlice...)
|
||||||
|
|||||||
@@ -56,9 +56,9 @@ func NewGenerators(rng io.Reader) (*Generators, error) {
|
|||||||
// SHA-256 and then dispatched to NewGeneratorsFromSeed, so the actual on-curve
|
// SHA-256 and then dispatched to NewGeneratorsFromSeed, so the actual on-curve
|
||||||
// derivation is identical to the C++/Metal/CUDA/WGSL canonical:
|
// derivation is identical to the C++/Metal/CUDA/WGSL canonical:
|
||||||
//
|
//
|
||||||
// key = SHA-256(seed)
|
// key = SHA-256(seed)
|
||||||
// G = HashToG1(key || u64_le(0), DST=PEDERSEN_SEEDED_GEN_V1)
|
// G = HashToG1(key || u64_le(0), DST=PEDERSEN_SEEDED_GEN_V1)
|
||||||
// H = HashToG1(key || u64_le(1), DST=PEDERSEN_SEEDED_GEN_V1)
|
// H = HashToG1(key || u64_le(1), DST=PEDERSEN_SEEDED_GEN_V1)
|
||||||
//
|
//
|
||||||
// This collapses LP-137 issue N3 (RED-FINAL §2.4): the legacy two-DST
|
// This collapses LP-137 issue N3 (RED-FINAL §2.4): the legacy two-DST
|
||||||
// PEDERSEN_G_V1 / PEDERSEN_H_V1 path is removed; everything now flows through
|
// PEDERSEN_G_V1 / PEDERSEN_H_V1 path is removed; everything now flows through
|
||||||
|
|||||||
@@ -8,14 +8,15 @@
|
|||||||
//
|
//
|
||||||
// - Schoolbook O(n^2) -- always correct, fastest below n=64
|
// - Schoolbook O(n^2) -- always correct, fastest below n=64
|
||||||
// - NTT-based O(n log n) for the negacyclic convolution that lattice
|
// - NTT-based O(n log n) for the negacyclic convolution that lattice
|
||||||
// cryptography (ML-KEM, ML-DSA, Corona) uses
|
// cryptography (ML-KEM, ML-DSA, Corona) uses
|
||||||
//
|
//
|
||||||
// Q = 998244353 is the canonical FFT-friendly prime used by AtCoder, Cyclone-FFT,
|
// Q = 998244353 is the canonical FFT-friendly prime used by AtCoder, Cyclone-FFT,
|
||||||
// the SPOJ POLYMUL reference, and most competitive-programming NTT references.
|
// the SPOJ POLYMUL reference, and most competitive-programming NTT references.
|
||||||
// Its 2-adicity is 23, so the NTT supports lengths up to N = 2^23.
|
// Its 2-adicity is 23, so the NTT supports lengths up to N = 2^23.
|
||||||
//
|
//
|
||||||
// Negacyclic convolution: c[k] = sum_{i+j=k} a[i]*b[j]
|
// Negacyclic convolution: c[k] = sum_{i+j=k} a[i]*b[j]
|
||||||
// - sum_{i+j=k+n} a[i]*b[j]
|
// - sum_{i+j=k+n} a[i]*b[j]
|
||||||
|
//
|
||||||
// over Z_Q[X]/(X^n + 1) with q the prime above. This is the exact shape
|
// over Z_Q[X]/(X^n + 1) with q the prime above. This is the exact shape
|
||||||
// used by lattice schemes; cyclic convolution is recovered by padding.
|
// used by lattice schemes; cyclic convolution is recovered by padding.
|
||||||
//
|
//
|
||||||
|
|||||||
@@ -27,9 +27,9 @@ func lcg(seed uint64, n int) []uint64 {
|
|||||||
// that C++ and Metal layers MUST match.
|
// that C++ and Metal layers MUST match.
|
||||||
func TestKATs(t *testing.T) {
|
func TestKATs(t *testing.T) {
|
||||||
type kat struct {
|
type kat struct {
|
||||||
name string
|
name string
|
||||||
n int
|
n int
|
||||||
sA, sB uint64
|
sA, sB uint64
|
||||||
sum, first, last uint64
|
sum, first, last uint64
|
||||||
}
|
}
|
||||||
kats := []kat{
|
kats := []kat{
|
||||||
|
|||||||
@@ -15,11 +15,11 @@ import (
|
|||||||
var poseidon2KATJSON []byte
|
var poseidon2KATJSON []byte
|
||||||
|
|
||||||
type kat struct {
|
type kat struct {
|
||||||
Width int `json:"width"`
|
Width int `json:"width"`
|
||||||
FullRounds int `json:"full_rounds"`
|
FullRounds int `json:"full_rounds"`
|
||||||
PartialRounds int `json:"partial_rounds"`
|
PartialRounds int `json:"partial_rounds"`
|
||||||
SBox int `json:"sbox"`
|
SBox int `json:"sbox"`
|
||||||
Cases []katCase `json:"kat"`
|
Cases []katCase `json:"kat"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type katCase struct {
|
type katCase struct {
|
||||||
|
|||||||
@@ -160,4 +160,3 @@ func (e *cpuEngine) verifyBatch(mode Mode, msgs, sigs, pks [][]byte) ([]bool, er
|
|||||||
})
|
})
|
||||||
return res, nil
|
return res, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -242,9 +242,9 @@ func TestReduce32_Bounds(t *testing.T) {
|
|||||||
// TestAddSubMod_Bounds exercises addModQ / subModQ around the boundary.
|
// TestAddSubMod_Bounds exercises addModQ / subModQ around the boundary.
|
||||||
func TestAddSubMod_Bounds(t *testing.T) {
|
func TestAddSubMod_Bounds(t *testing.T) {
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
a, b uint32
|
a, b uint32
|
||||||
wantA uint32 // addModQ(a,b)
|
wantA uint32 // addModQ(a,b)
|
||||||
wantS uint32 // subModQ(a,b)
|
wantS uint32 // subModQ(a,b)
|
||||||
}{
|
}{
|
||||||
{0, 0, 0, 0},
|
{0, 0, 0, 0},
|
||||||
{Q - 1, 1, 0, Q - 2},
|
{Q - 1, 1, 0, Q - 2},
|
||||||
|
|||||||
+3
-3
@@ -451,9 +451,9 @@ func SignBatchGPU(privs []*PrivateKey, msgs, sigs [][]byte) (bool, error) {
|
|||||||
//
|
//
|
||||||
// Dispatch ladder:
|
// Dispatch ladder:
|
||||||
//
|
//
|
||||||
// 1. GPU substrate (SignBatchGPU) for n >= SignBatchThreshold.
|
// 1. GPU substrate (SignBatchGPU) for n >= SignBatchThreshold.
|
||||||
// 2. Goroutine-parallel CPU sign for n >= concurrentSignThreshold.
|
// 2. Goroutine-parallel CPU sign for n >= concurrentSignThreshold.
|
||||||
// 3. Serial CPU sign as the floor.
|
// 3. Serial CPU sign as the floor.
|
||||||
//
|
//
|
||||||
// Equivalence: SLH-DSA-SHA2 sign is deterministic, so all tiers produce
|
// Equivalence: SLH-DSA-SHA2 sign is deterministic, so all tiers produce
|
||||||
// byte-equal signatures for any given (sk, msg). Per FIPS 205 §10.2 the
|
// byte-equal signatures for any given (sk, msg). Per FIPS 205 §10.2 the
|
||||||
|
|||||||
@@ -33,8 +33,6 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/luxfi/crypto/backend"
|
"github.com/luxfi/crypto/backend"
|
||||||
|
|
||||||
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// genSignBatch192f produces n SLH-DSA-192f keypairs ready for SignBatch.
|
// genSignBatch192f produces n SLH-DSA-192f keypairs ready for SignBatch.
|
||||||
|
|||||||
@@ -9,8 +9,6 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/luxfi/crypto/backend"
|
"github.com/luxfi/crypto/backend"
|
||||||
|
|
||||||
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// genBatch produces n SLH-DSA-192f keypairs + signs distinct messages with
|
// genBatch produces n SLH-DSA-192f keypairs + signs distinct messages with
|
||||||
|
|||||||
+4
-3
@@ -152,9 +152,10 @@ func GetSignatureSize(mode Mode) int {
|
|||||||
|
|
||||||
// GetPrivateKeySize returns the size of a private key for the given mode.
|
// GetPrivateKeySize returns the size of a private key for the given mode.
|
||||||
// FIPS 205 §10 catalogue: sk = 4n where n is the hash output width:
|
// FIPS 205 §10 catalogue: sk = 4n where n is the hash output width:
|
||||||
// 128-bit security : n=16 -> sk=64
|
//
|
||||||
// 192-bit security : n=24 -> sk=96
|
// 128-bit security : n=16 -> sk=64
|
||||||
// 256-bit security : n=32 -> sk=128
|
// 192-bit security : n=24 -> sk=96
|
||||||
|
// 256-bit security : n=32 -> sk=128
|
||||||
func GetPrivateKeySize(mode Mode) int {
|
func GetPrivateKeySize(mode Mode) int {
|
||||||
switch mode {
|
switch mode {
|
||||||
case SHA2_128s, SHAKE_128s, SHA2_128f, SHAKE_128f:
|
case SHA2_128s, SHAKE_128s, SHA2_128f, SHAKE_128f:
|
||||||
|
|||||||
@@ -70,8 +70,8 @@ func TestParseNodeEoA(t *testing.T) {
|
|||||||
// EmptyCodeHash deterministically (see parseEoAccountNode in
|
// EmptyCodeHash deterministically (see parseEoAccountNode in
|
||||||
// encoding.go). values[2..255] stay nil after round-trip.
|
// encoding.go). values[2..255] stay nil after round-trip.
|
||||||
values := make([][]byte, 256)
|
values := make([][]byte, 256)
|
||||||
values[0] = zero32[:] // basic data (packed: version+balance+nonce+codesize)
|
values[0] = zero32[:] // basic data (packed: version+balance+nonce+codesize)
|
||||||
values[1] = EmptyCodeHash[:] // code hash — required = EmptyCodeHash for EoA
|
values[1] = EmptyCodeHash[:] // code hash — required = EmptyCodeHash for EoA
|
||||||
ln, err := NewLeafNode(ffx32KeyTest[:31], values)
|
ln, err := NewLeafNode(ffx32KeyTest[:31], values)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("error creating leaf node: %v", err)
|
t.Fatalf("error creating leaf node: %v", err)
|
||||||
|
|||||||
Reference in New Issue
Block a user