mirror of
https://github.com/luxfi/crypto.git
synced 2026-07-27 01:54:50 +00:00
crypto: brand-neutral DSTs, env vars, and Rust c-abi link names
Domain separation tags and identifiers in cryptographic code must be
readable in a scientific paper without product context. Strip the Lux
brand from in-code crypto identifiers; algorithm names ARE the namespace.
DSTs (golden vectors regenerated):
pedersen NewGenerators: LUX_PEDERSEN_{G,H} -> PEDERSEN_{G,H}_V1
pedersen NewGeneratorsFromSeed: LUX_PEDERSEN_SEEDED_GEN_V1 -> PEDERSEN_SEEDED_GEN_V1
pedersen golden G/H test vectors recomputed for the new DST.
Env vars (one canonical name only — no deprecated alias):
backend.envBackend: drop LUX_CRYPTO_BACKEND fallback, CRYPTO_BACKEND only
rust/build.rs: drop LUX_CRYPTO_DIR / LUX_CRYPTO_BUILD_DIR fallbacks
Rust c-abi link names:
lux-crypto-keccak: extern "C" name keccak256 (was lux_keccak256)
lux-crypto-secp256k1: secp256k1_ecrecover{,_batch} (was lux_*)
lux-crypto umbrella: drop all #[link_name = "lux_*"] attrs;
the canonical luxcpp/crypto C-ABI exports brand-neutral symbols
directly, the Rust function names mirror them one-for-one.
Go cgo aliases:
hash/blake3/blake3_c.go: drop the four #define aliases that mapped
crypto_* -> lux_crypto_*; the C header now declares brand-neutral
names directly.
Tests passing:
lux/crypto: 50 packages ok, 0 fail (GOWORK=off go test ./... -short)
rust workspace: 18 tests across 3 crates (CRYPTO_BUILD_DIR=... cargo test --release)
This commit is contained in:
+2
-11
@@ -15,7 +15,6 @@
|
||||
package backend
|
||||
|
||||
import (
|
||||
"log"
|
||||
"os"
|
||||
"strings"
|
||||
"sync/atomic"
|
||||
@@ -69,17 +68,9 @@ func Parse(s string) (Backend, bool) {
|
||||
|
||||
var current uint32 // atomic Backend
|
||||
|
||||
// envBackend reads CRYPTO_BACKEND, falling back to deprecated LUX_CRYPTO_BACKEND
|
||||
// for one transition release. The deprecated read is removed in v2.
|
||||
// envBackend reads CRYPTO_BACKEND from the environment.
|
||||
func envBackend() (string, bool) {
|
||||
if v, ok := os.LookupEnv("CRYPTO_BACKEND"); ok {
|
||||
return v, true
|
||||
}
|
||||
if v, ok := os.LookupEnv("LUX_CRYPTO_BACKEND"); ok {
|
||||
log.Println("LUX_CRYPTO_BACKEND is deprecated; use CRYPTO_BACKEND")
|
||||
return v, true
|
||||
}
|
||||
return "", false
|
||||
return os.LookupEnv("CRYPTO_BACKEND")
|
||||
}
|
||||
|
||||
func init() {
|
||||
|
||||
@@ -103,49 +103,3 @@ func TestEnvOverride(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestEnvOverrideDeprecatedFallback(t *testing.T) {
|
||||
// Saved current state.
|
||||
prev := Default()
|
||||
t.Cleanup(func() { SetDefault(prev) })
|
||||
|
||||
// Ensure neither env is set in the parent shell when this case starts.
|
||||
prevNew, hasNew := os.LookupEnv("CRYPTO_BACKEND")
|
||||
prevOld, hasOld := os.LookupEnv("LUX_CRYPTO_BACKEND")
|
||||
os.Unsetenv("CRYPTO_BACKEND")
|
||||
os.Unsetenv("LUX_CRYPTO_BACKEND")
|
||||
t.Cleanup(func() {
|
||||
if hasNew {
|
||||
os.Setenv("CRYPTO_BACKEND", prevNew)
|
||||
} else {
|
||||
os.Unsetenv("CRYPTO_BACKEND")
|
||||
}
|
||||
if hasOld {
|
||||
os.Setenv("LUX_CRYPTO_BACKEND", prevOld)
|
||||
} else {
|
||||
os.Unsetenv("LUX_CRYPTO_BACKEND")
|
||||
}
|
||||
})
|
||||
|
||||
// Deprecated LUX_CRYPTO_BACKEND must still be honored for one transition
|
||||
// release.
|
||||
t.Setenv("LUX_CRYPTO_BACKEND", "vanilla")
|
||||
if v, ok := envBackend(); ok {
|
||||
if b, parsed := Parse(v); parsed {
|
||||
SetDefault(b)
|
||||
}
|
||||
}
|
||||
if got := Default(); got != Vanilla {
|
||||
t.Errorf("deprecated env: Default() = %v; want Vanilla", got)
|
||||
}
|
||||
|
||||
// New name wins when both are set.
|
||||
t.Setenv("CRYPTO_BACKEND", "cgo")
|
||||
if v, ok := envBackend(); ok {
|
||||
if b, parsed := Parse(v); parsed {
|
||||
SetDefault(b)
|
||||
}
|
||||
}
|
||||
if got := Default(); got != CGo {
|
||||
t.Errorf("new name wins: Default() = %v; want CGo", got)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,14 +15,8 @@ package blake3
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
// C API from luxcpp/crypto
|
||||
// C API from luxcpp/crypto (brand-neutral symbols).
|
||||
#include <lux/crypto/crypto.h>
|
||||
|
||||
// Short aliases for Go code readability (hides lux_crypto_ prefix)
|
||||
#define crypto_gpu_available lux_crypto_gpu_available
|
||||
#define crypto_get_backend lux_crypto_get_backend
|
||||
#define crypto_blake3 lux_crypto_blake3
|
||||
#define crypto_batch_hash lux_crypto_batch_hash
|
||||
*/
|
||||
import "C"
|
||||
|
||||
|
||||
@@ -41,11 +41,11 @@ func NewGenerators(rng io.Reader) (*Generators, error) {
|
||||
if _, err := rng.Read(hBytes); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
g, err := bn254.HashToG1(gBytes, []byte("LUX_PEDERSEN_G"))
|
||||
g, err := bn254.HashToG1(gBytes, []byte("PEDERSEN_G_V1"))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
h, err := bn254.HashToG1(hBytes, []byte("LUX_PEDERSEN_H"))
|
||||
h, err := bn254.HashToG1(hBytes, []byte("PEDERSEN_H_V1"))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@ import (
|
||||
// SeededGenDST is the domain separation tag used by NewGeneratorsFromSeed.
|
||||
// It is exported so cross-language KAT generators (C++, Rust) can replicate
|
||||
// the derivation byte-for-byte.
|
||||
const SeededGenDST = "LUX_PEDERSEN_SEEDED_GEN_V1"
|
||||
const SeededGenDST = "PEDERSEN_SEEDED_GEN_V1"
|
||||
|
||||
// NewGeneratorsFromSeed deterministically derives the Pedersen generators
|
||||
// (G, H) from a 32-byte seed using RFC 9380 hash-to-curve (SVDW map) on
|
||||
|
||||
@@ -133,8 +133,8 @@ func TestNewGeneratorsFromSeed_GoldenVector(t *testing.T) {
|
||||
gotG := affineHex(&gA)
|
||||
gotH := affineHex(&hA)
|
||||
|
||||
const wantG = "afba7c7a97100c5eb0ec96758698779b5d8d38d228bcdb7c85a4c1626ea5247a"
|
||||
const wantH = "abc19b5bad508d8e7b944a37812a342cdbaa5946f0b3fd854805820c006c6110"
|
||||
const wantG = "c563aa8a283f268b65b4210a0a78ee1341f76b59d94c1ac626effe1a5aa0c6b7"
|
||||
const wantH = "e9ebf4392683dcb418584dd8ecd1e1dd16b486147e676dbf4b62779a340f3186"
|
||||
|
||||
if gotG != wantG {
|
||||
t.Fatalf("golden G mismatch (derivation regression):\n got=%s\nwant=%s", gotG, wantG)
|
||||
|
||||
@@ -22,8 +22,7 @@ extern "C" {
|
||||
/// The C-ABI declaration in `lux/crypto/keccak.h` returns `void`; we mirror
|
||||
/// that exactly. Caller must guarantee `output` points to at least 32
|
||||
/// writable bytes.
|
||||
#[link_name = "lux_keccak256"]
|
||||
fn lux_keccak256(input: *const u8, input_len: usize, output: *mut u8);
|
||||
fn keccak256(input: *const u8, input_len: usize, output: *mut u8);
|
||||
}
|
||||
|
||||
/// Length of a keccak256 digest in bytes.
|
||||
@@ -39,7 +38,7 @@ pub fn hash(input: &[u8]) -> [u8; DIGEST_LEN] {
|
||||
// SAFETY: `input.as_ptr()` is valid for `input.len()` bytes (read-only)
|
||||
// and `out.as_mut_ptr()` is valid for `DIGEST_LEN` bytes (write).
|
||||
unsafe {
|
||||
lux_keccak256(input.as_ptr(), input.len(), out.as_mut_ptr());
|
||||
keccak256(input.as_ptr(), input.len(), out.as_mut_ptr());
|
||||
}
|
||||
out
|
||||
}
|
||||
@@ -51,7 +50,7 @@ pub fn hash(input: &[u8]) -> [u8; DIGEST_LEN] {
|
||||
pub fn hash_into<'a>(input: &[u8], output: &'a mut [u8; DIGEST_LEN]) -> &'a [u8; DIGEST_LEN] {
|
||||
// SAFETY: pointers are valid for the durations of the call.
|
||||
unsafe {
|
||||
lux_keccak256(input.as_ptr(), input.len(), output.as_mut_ptr());
|
||||
keccak256(input.as_ptr(), input.len(), output.as_mut_ptr());
|
||||
}
|
||||
output
|
||||
}
|
||||
|
||||
@@ -92,8 +92,7 @@ impl Error {
|
||||
extern "C" {
|
||||
/// Recover the 64-byte uncompressed public key (X || Y, big-endian) from
|
||||
/// `(hash, r, s, v)` where `v` is the recovery id 0 or 1.
|
||||
#[link_name = "lux_secp256k1_ecrecover"]
|
||||
fn lux_secp256k1_ecrecover(
|
||||
fn secp256k1_ecrecover(
|
||||
hash: *const u8,
|
||||
r: *const u8,
|
||||
s: *const u8,
|
||||
@@ -103,8 +102,7 @@ extern "C" {
|
||||
|
||||
/// Batch ecrecover. `inputs` is `n * 97` bytes (`hash || r || s || v`).
|
||||
/// `pubkey_out` is `n * 64` bytes; `status_out` is `n` bytes.
|
||||
#[link_name = "lux_secp256k1_ecrecover_batch"]
|
||||
fn lux_secp256k1_ecrecover_batch(
|
||||
fn secp256k1_ecrecover_batch(
|
||||
inputs: *const u8,
|
||||
n: usize,
|
||||
pubkey_out: *mut u8,
|
||||
@@ -135,7 +133,7 @@ pub fn ecrecover(
|
||||
let mut out = [0u8; PUBKEY_LEN];
|
||||
// SAFETY: All pointers are valid for the call's duration; v is a copy.
|
||||
let rc = unsafe {
|
||||
lux_secp256k1_ecrecover(hash.as_ptr(), r.as_ptr(), s.as_ptr(), v, out.as_mut_ptr())
|
||||
secp256k1_ecrecover(hash.as_ptr(), r.as_ptr(), s.as_ptr(), v, out.as_mut_ptr())
|
||||
};
|
||||
if rc == 0 {
|
||||
Ok(out)
|
||||
@@ -162,7 +160,7 @@ pub fn ecrecover_batch(inputs: &[u8]) -> Result<(Vec<u8>, Vec<u8>), Error> {
|
||||
let mut statuses = vec![0u8; n];
|
||||
// SAFETY: We have shown the buffers are sized to the C-ABI contract.
|
||||
let rc = unsafe {
|
||||
lux_secp256k1_ecrecover_batch(
|
||||
secp256k1_ecrecover_batch(
|
||||
inputs.as_ptr(),
|
||||
n,
|
||||
pubkeys.as_mut_ptr(),
|
||||
|
||||
@@ -22,8 +22,6 @@ description = "Umbrella crate for Lux crypto. Re-exports per-algorithm crates th
|
||||
# contains `include/lux/crypto/*.h` and `lib/lib<alg>_cpu.a`.
|
||||
# - Or, set `CRYPTO_BUILD_DIR` to the cmake build directory containing
|
||||
# `<alg>/lib<alg>_cpu.a`.
|
||||
# - Deprecated names `LUX_CRYPTO_DIR` / `LUX_CRYPTO_BUILD_DIR` are read for
|
||||
# one release with a deprecation warning.
|
||||
#
|
||||
# Brand-neutral naming: NO -sys suffix. We author the C/C++ ourselves at
|
||||
# luxcpp/crypto; this is not a wrapper around third-party FFI. One crate
|
||||
|
||||
@@ -10,17 +10,6 @@
|
||||
use std::env;
|
||||
use std::path::PathBuf;
|
||||
|
||||
fn read_env_with_legacy(new_name: &str, legacy_name: &str) -> Option<String> {
|
||||
if let Ok(v) = env::var(new_name) {
|
||||
return Some(v);
|
||||
}
|
||||
if let Ok(v) = env::var(legacy_name) {
|
||||
println!("cargo:warning={legacy_name} is deprecated; use {new_name}");
|
||||
return Some(v);
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
/// Each first-party algorithm corresponds to:
|
||||
/// - a build subdirectory `build-canonical/<dir>/`
|
||||
/// - a static archive named `lib<lib>_cpu.a`
|
||||
@@ -34,8 +23,8 @@ const ALGS: &[(&str, &str)] = &[
|
||||
];
|
||||
|
||||
fn main() {
|
||||
let crypto_dir = read_env_with_legacy("CRYPTO_DIR", "LUX_CRYPTO_DIR");
|
||||
let build_dir = read_env_with_legacy("CRYPTO_BUILD_DIR", "LUX_CRYPTO_BUILD_DIR");
|
||||
let crypto_dir = env::var("CRYPTO_DIR").ok();
|
||||
let build_dir = env::var("CRYPTO_BUILD_DIR").ok();
|
||||
|
||||
let manifest_dir = PathBuf::from(env::var("CARGO_MANIFEST_DIR").unwrap());
|
||||
|
||||
@@ -54,8 +43,6 @@ fn main() {
|
||||
println!("cargo:rerun-if-changed=src/lib.rs");
|
||||
println!("cargo:rerun-if-env-changed=CRYPTO_DIR");
|
||||
println!("cargo:rerun-if-env-changed=CRYPTO_BUILD_DIR");
|
||||
println!("cargo:rerun-if-env-changed=LUX_CRYPTO_DIR");
|
||||
println!("cargo:rerun-if-env-changed=LUX_CRYPTO_BUILD_DIR");
|
||||
|
||||
for (subdir, lib) in ALGS {
|
||||
let lib_path = base.join(subdir);
|
||||
|
||||
@@ -58,14 +58,12 @@ impl Secp256k1Status {
|
||||
}
|
||||
|
||||
// The canonical luxcpp/crypto C header declares brand-neutral symbols
|
||||
// (`secp256k1_ecrecover`, `mldsa_*`, etc.). The current static archives at
|
||||
// `build-canonical/<alg>/lib<alg>_cpu.a` still export those symbols with a
|
||||
// `lux_` prefix until the next rebuild. We map both via `#[link_name]` so the
|
||||
// Rust call surface stays brand-neutral and consumers see one canonical name.
|
||||
// (`secp256k1_ecrecover`, `mldsa_*`, etc.). The static archives at
|
||||
// `build-canonical/<alg>/lib<alg>_cpu.a` export the same names. The Rust
|
||||
// call surface mirrors them one-for-one.
|
||||
extern "C" {
|
||||
/// Recover the 64-byte uncompressed public key from (hash, r, s, v).
|
||||
/// Returns one of the `Secp256k1Status` codes as `c_int`.
|
||||
#[link_name = "lux_secp256k1_ecrecover"]
|
||||
pub fn secp256k1_ecrecover(
|
||||
hash: *const u8,
|
||||
r: *const u8,
|
||||
@@ -76,7 +74,6 @@ extern "C" {
|
||||
|
||||
/// Batch ecrecover. inputs is n * 97 bytes (hash || r || s || v).
|
||||
/// pubkey_out is n * 64 bytes; status_out is n bytes.
|
||||
#[link_name = "lux_secp256k1_ecrecover_batch"]
|
||||
pub fn secp256k1_ecrecover_batch(
|
||||
inputs: *const u8,
|
||||
n: usize,
|
||||
@@ -146,14 +143,12 @@ pub mod mldsa {
|
||||
use super::{c_int, CryptoStatus, NistMode};
|
||||
|
||||
extern "C" {
|
||||
#[link_name = "lux_mldsa_keygen"]
|
||||
fn mldsa_keygen(
|
||||
mode: c_int,
|
||||
seed: *const u8,
|
||||
pk: *mut u8,
|
||||
sk: *mut u8,
|
||||
) -> c_int;
|
||||
#[link_name = "lux_mldsa_sign"]
|
||||
fn mldsa_sign(
|
||||
mode: c_int,
|
||||
sk: *const u8,
|
||||
@@ -162,7 +157,6 @@ pub mod mldsa {
|
||||
sig: *mut u8,
|
||||
sig_len: *mut usize,
|
||||
) -> c_int;
|
||||
#[link_name = "lux_mldsa_verify"]
|
||||
fn mldsa_verify(
|
||||
mode: c_int,
|
||||
pk: *const u8,
|
||||
@@ -251,21 +245,18 @@ pub mod mlkem {
|
||||
use super::{c_int, CryptoStatus, NistMode};
|
||||
|
||||
extern "C" {
|
||||
#[link_name = "lux_mlkem_keygen"]
|
||||
fn mlkem_keygen(
|
||||
mode: c_int,
|
||||
seed: *const u8,
|
||||
pk: *mut u8,
|
||||
sk: *mut u8,
|
||||
) -> c_int;
|
||||
#[link_name = "lux_mlkem_encap"]
|
||||
fn mlkem_encap(
|
||||
mode: c_int,
|
||||
pk: *const u8,
|
||||
ct: *mut u8,
|
||||
ss: *mut u8,
|
||||
) -> c_int;
|
||||
#[link_name = "lux_mlkem_decap"]
|
||||
fn mlkem_decap(
|
||||
mode: c_int,
|
||||
sk: *const u8,
|
||||
@@ -334,14 +325,12 @@ pub mod slhdsa {
|
||||
use super::{c_int, CryptoStatus, NistMode};
|
||||
|
||||
extern "C" {
|
||||
#[link_name = "lux_slhdsa_keygen"]
|
||||
fn slhdsa_keygen(
|
||||
mode: c_int,
|
||||
seed: *const u8,
|
||||
pk: *mut u8,
|
||||
sk: *mut u8,
|
||||
) -> c_int;
|
||||
#[link_name = "lux_slhdsa_sign"]
|
||||
fn slhdsa_sign(
|
||||
mode: c_int,
|
||||
sk: *const u8,
|
||||
@@ -350,7 +339,6 @@ pub mod slhdsa {
|
||||
sig: *mut u8,
|
||||
sig_len: *mut usize,
|
||||
) -> c_int;
|
||||
#[link_name = "lux_slhdsa_verify"]
|
||||
fn slhdsa_verify(
|
||||
mode: c_int,
|
||||
pk: *const u8,
|
||||
@@ -433,16 +421,13 @@ pub mod ed25519 {
|
||||
use super::{c_int, CryptoStatus};
|
||||
|
||||
extern "C" {
|
||||
#[link_name = "lux_ed25519_keygen"]
|
||||
fn ed25519_keygen(seed: *const u8, sk: *mut u8, pk: *mut u8) -> c_int;
|
||||
#[link_name = "lux_ed25519_sign"]
|
||||
fn ed25519_sign(
|
||||
sk: *const u8,
|
||||
msg: *const u8,
|
||||
msg_len: usize,
|
||||
sig: *mut u8,
|
||||
) -> c_int;
|
||||
#[link_name = "lux_ed25519_verify"]
|
||||
fn ed25519_verify(
|
||||
pk: *const u8,
|
||||
msg: *const u8,
|
||||
@@ -486,7 +471,6 @@ pub mod ed25519 {
|
||||
pub mod keccak256 {
|
||||
extern "C" {
|
||||
// The C ABI declares this as `void` in lux/crypto/keccak.h.
|
||||
#[link_name = "lux_keccak256"]
|
||||
fn keccak256(input: *const u8, input_len: usize, output: *mut u8);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user