mirror of
https://github.com/luxfi/kms.git
synced 2026-07-27 03:38:31 +00:00
fix(deps): post-re-tag coherent luxfi set (geth v1.17.12), re-vendor
luxfi/geth wiped its v1.16.x line (v1.16.98 gone) in the ecosystem
re-tag, breaking 'go mod download' at Dockerfile:27. Move to the coherent
set crypto v1.19.27 -> geth v1.17.12 (both proxy-resolvable), regenerate
go.sum against the public proxy (matches the Dockerfile's proxy fetch),
and re-vendor so the in-tree vendor/ stays consistent. Pairs with the
already-landed KMS<->MPC ZAP wire fix (7377ad6) so a tagged release both
builds and signs against mpcd.
Co-authored-by: Hanzo Dev <dev@hanzo.ai>
This commit is contained in:
@@ -8,7 +8,7 @@ require (
|
||||
github.com/luxfi/go-bip39 v1.1.2
|
||||
github.com/luxfi/ids v1.2.15
|
||||
github.com/luxfi/keys v1.1.0
|
||||
github.com/luxfi/log v1.4.1
|
||||
github.com/luxfi/log v1.4.3
|
||||
github.com/luxfi/zap v0.7.2
|
||||
github.com/luxfi/zapdb v1.10.0
|
||||
golang.org/x/crypto v0.52.0
|
||||
@@ -19,14 +19,18 @@ require (
|
||||
|
||||
require (
|
||||
filippo.io/hpke v0.4.0 // indirect
|
||||
github.com/bits-and-blooms/bitset v1.24.4 // indirect
|
||||
github.com/btcsuite/btcd/btcutil v1.1.6 // indirect
|
||||
github.com/cenkalti/backoff v2.2.1+incompatible // indirect
|
||||
github.com/cespare/xxhash/v2 v2.3.0 // indirect
|
||||
github.com/consensys/gnark-crypto v0.20.1 // indirect
|
||||
github.com/crate-crypto/go-eth-kzg v1.5.0 // indirect
|
||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
|
||||
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.4.1 // indirect
|
||||
github.com/dgraph-io/ristretto/v2 v2.4.0 // indirect
|
||||
github.com/dustin/go-humanize v1.0.1 // indirect
|
||||
github.com/emicklei/go-restful/v3 v3.12.2 // indirect
|
||||
github.com/ethereum/c-kzg-4844/v2 v2.1.7 // indirect
|
||||
github.com/fxamacker/cbor/v2 v2.9.1 // indirect
|
||||
github.com/go-ini/ini v1.67.0 // indirect
|
||||
github.com/go-logr/logr v1.4.3 // indirect
|
||||
@@ -43,38 +47,40 @@ require (
|
||||
github.com/holiman/uint256 v1.3.2 // indirect
|
||||
github.com/josharian/intern v1.0.0 // indirect
|
||||
github.com/json-iterator/go v1.1.12 // indirect
|
||||
github.com/klauspost/compress v1.18.5 // indirect
|
||||
github.com/klauspost/compress v1.18.6 // indirect
|
||||
github.com/klauspost/cpuid/v2 v2.3.0 // indirect
|
||||
github.com/klauspost/crc32 v1.3.0 // indirect
|
||||
github.com/luxfi/accel v1.1.9 // indirect
|
||||
github.com/luxfi/accel v1.2.4 // indirect
|
||||
github.com/luxfi/address v1.0.1 // indirect
|
||||
github.com/luxfi/age v1.5.0 // indirect
|
||||
github.com/luxfi/cache v1.2.1 // indirect
|
||||
github.com/luxfi/constants v1.5.8 // indirect
|
||||
github.com/luxfi/container v0.0.4 // indirect
|
||||
github.com/luxfi/crypto v1.19.17 // indirect
|
||||
github.com/luxfi/crypto v1.19.27 // indirect
|
||||
github.com/luxfi/crypto/ipa v1.2.4 // indirect
|
||||
github.com/luxfi/formatting v1.0.1 // indirect
|
||||
github.com/luxfi/geth v1.16.98 // indirect
|
||||
github.com/luxfi/geth v1.17.12 // indirect
|
||||
github.com/luxfi/go-bip32 v1.0.2 // indirect
|
||||
github.com/luxfi/math v1.4.1 // indirect
|
||||
github.com/luxfi/math/big v0.1.0 // indirect
|
||||
github.com/luxfi/mdns v0.1.1 // indirect
|
||||
github.com/luxfi/metric v1.5.7 // indirect
|
||||
github.com/luxfi/metric v1.5.8 // indirect
|
||||
github.com/luxfi/mock v0.1.1 // indirect
|
||||
github.com/luxfi/proto v1.0.0 // indirect
|
||||
github.com/luxfi/pq v1.0.3 // indirect
|
||||
github.com/luxfi/proto v1.3.4 // indirect
|
||||
github.com/luxfi/sampler v1.1.0 // indirect
|
||||
github.com/luxfi/tls v1.0.3 // indirect
|
||||
github.com/luxfi/vm v1.2.0 // indirect
|
||||
github.com/luxfi/vm v1.2.3 // indirect
|
||||
github.com/mailru/easyjson v0.7.7 // indirect
|
||||
github.com/mattn/go-colorable v0.1.14 // indirect
|
||||
github.com/mattn/go-isatty v0.0.20 // indirect
|
||||
github.com/mattn/go-colorable v0.1.15 // indirect
|
||||
github.com/mattn/go-isatty v0.0.22 // indirect
|
||||
github.com/miekg/dns v1.1.72 // indirect
|
||||
github.com/minio/crc64nvme v1.1.1 // indirect
|
||||
github.com/minio/md5-simd v1.1.2 // indirect
|
||||
github.com/minio/minio-go/v7 v7.0.100 // indirect
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||
github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee // indirect
|
||||
github.com/mr-tron/base58 v1.2.0 // indirect
|
||||
github.com/mr-tron/base58 v1.3.0 // indirect
|
||||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
|
||||
github.com/onsi/ginkgo/v2 v2.28.1 // indirect
|
||||
github.com/onsi/gomega v1.39.1 // indirect
|
||||
@@ -93,7 +99,7 @@ require (
|
||||
go.uber.org/mock v0.6.0 // indirect
|
||||
go.yaml.in/yaml/v2 v2.4.4 // indirect
|
||||
go.yaml.in/yaml/v3 v3.0.4 // indirect
|
||||
golang.org/x/exp v0.0.0-20260312153236-7ab1446f8b90 // indirect
|
||||
golang.org/x/exp v0.0.0-20260529124908-c761662dc8c9 // indirect
|
||||
golang.org/x/mod v0.36.0 // indirect
|
||||
golang.org/x/net v0.55.0 // indirect
|
||||
golang.org/x/oauth2 v0.36.0 // indirect
|
||||
|
||||
@@ -1,10 +1,8 @@
|
||||
c2sp.org/CCTV/age v0.0.0-20251208015420-e9274a7bdbfd h1:ZLsPO6WdZ5zatV4UfVpr7oAwLGRZ+sebTUruuM4Ra3M=
|
||||
c2sp.org/CCTV/age v0.0.0-20251208015420-e9274a7bdbfd/go.mod h1:SrHC2C7r5GkDk8R+NFVzYy/sdj0Ypg9htaPXQq5Cqeo=
|
||||
filippo.io/hpke v0.4.0 h1:p575VVQ6ted4pL+it6M00V/f2qTZITO0zgmdKCkd5+A=
|
||||
filippo.io/hpke v0.4.0/go.mod h1:EmAN849/P3qdeK+PCMkDpDm83vRHM5cDipBJ8xbQLVY=
|
||||
github.com/Masterminds/semver/v3 v3.4.0 h1:Zog+i5UMtVoCU8oKka5P7i9q9HgrJeGzI9SA1Xbatp0=
|
||||
github.com/Masterminds/semver/v3 v3.4.0/go.mod h1:4V+yj/TJE1HU9XfppCwVMZq3I84lprf4nC11bSS5beM=
|
||||
github.com/aead/siphash v1.0.1/go.mod h1:Nywa3cDsYNNK3gaciGTWPwHt0wlpNV15vwmswBAUSII=
|
||||
github.com/bits-and-blooms/bitset v1.24.4 h1:95H15Og1clikBrKr/DuzMXkQzECs1M6hhoGXLwLQOZE=
|
||||
github.com/bits-and-blooms/bitset v1.24.4/go.mod h1:7hO7Gc7Pp1vODcmWvKMRA9BNmbv6a/7QIWpPxHddWR8=
|
||||
github.com/btcsuite/btcd v0.20.1-beta/go.mod h1:wVuoA8VJLEcwgqHBwHmzLRazpKxTv13Px/pDuV7OomQ=
|
||||
github.com/btcsuite/btcd v0.22.0-beta.0.20220111032746-97732e52810c/go.mod h1:tjmYdS6MLJ5/s0Fj4DbLgSbDHbEqLJrtnHecBFkdz5M=
|
||||
github.com/btcsuite/btcd v0.23.5-0.20231215221805-96c9fd8078fd/go.mod h1:nm3Bko6zh6bWP60UxwoT5LzdGJsQJaPo6HjduXq9p6A=
|
||||
@@ -34,6 +32,10 @@ github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UF
|
||||
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||
github.com/cloudflare/circl v1.6.3 h1:9GPOhQGF9MCYUeXyMYlqTR6a5gTrgR/fBLXvUgtVcg8=
|
||||
github.com/cloudflare/circl v1.6.3/go.mod h1:2eXP6Qfat4O/Yhh8BznvKnJ+uzEoTQ6jVKJRn81BiS4=
|
||||
github.com/consensys/gnark-crypto v0.20.1 h1:PXDUBvk8AzhvWowHLWBEAfUQcV1/aZgWIqD6eMpXmDg=
|
||||
github.com/consensys/gnark-crypto v0.20.1/go.mod h1:RBWrSgy+IDbGR69RRV313th3M/aZU1ubk2om+qHuTSc=
|
||||
github.com/crate-crypto/go-eth-kzg v1.5.0 h1:FYRiJMJG2iv+2Dy3fi14SVGjcPteZ5HAAUe4YWlJygc=
|
||||
github.com/crate-crypto/go-eth-kzg v1.5.0/go.mod h1:J9/u5sWfznSObptgfa92Jq8rTswn6ahQWEuiLHOjCUI=
|
||||
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
||||
github.com/davecgh/go-spew v0.0.0-20171005155431-ecdeabc65495/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
@@ -41,20 +43,18 @@ github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs
|
||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
|
||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/decred/dcrd/crypto/blake256 v1.0.0/go.mod h1:sQl2p6Y26YV+ZOcSTP6thNdn47hh8kt6rqSlvmrXFAc=
|
||||
github.com/decred/dcrd/crypto/blake256 v1.1.0 h1:zPMNGQCm0g4QTY27fOCorQW7EryeQ/U0x++OzVrdms8=
|
||||
github.com/decred/dcrd/crypto/blake256 v1.1.0/go.mod h1:2OfgNZ5wDpcsFmHmCK5gZTPcCXqlm2ArzUIkw9czNJo=
|
||||
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1/go.mod h1:hyedUtir6IdtD/7lIxGeCxkaw7y45JueMRL4DIyJDKs=
|
||||
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.4.1 h1:5RVFMOWjMyRy8cARdy79nAmgYw3hK/4HUq48LQ6Wwqo=
|
||||
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.4.1/go.mod h1:ZXNYxsqcloTdSy/rNShjYzMhyjf0LaoftYK0p+A3h40=
|
||||
github.com/decred/dcrd/lru v1.0.0/go.mod h1:mxKOwFd7lFjN2GZYsiz/ecgqR6kkYAl+0pz0tEMk218=
|
||||
github.com/dgraph-io/ristretto/v2 v2.4.0 h1:I/w09yLjhdcVD2QV192UJcq8dPBaAJb9pOuMyNy0XlU=
|
||||
github.com/dgraph-io/ristretto/v2 v2.4.0/go.mod h1:0KsrXtXvnv0EqnzyowllbVJB8yBonswa2lTCK2gGo9E=
|
||||
github.com/dgryski/go-farm v0.0.0-20240924180020-3414d57e47da h1:aIftn67I1fkbMa512G+w+Pxci9hJPB8oMnkcP3iZF38=
|
||||
github.com/dgryski/go-farm v0.0.0-20240924180020-3414d57e47da/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw=
|
||||
github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY=
|
||||
github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=
|
||||
github.com/emicklei/go-restful/v3 v3.12.2 h1:DhwDP0vY3k8ZzE0RunuJy8GhNpPL6zqLkDf9B/a0/xU=
|
||||
github.com/emicklei/go-restful/v3 v3.12.2/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc=
|
||||
github.com/ethereum/c-kzg-4844/v2 v2.1.7 h1:aat3CuITdDbPC6pmEGRT0zJ5eOxzrZj8TJT5z7Xk//M=
|
||||
github.com/ethereum/c-kzg-4844/v2 v2.1.7/go.mod h1:8HMkUZ5JRv4hpw/XUrYWSQNAUzhHMg2UDb/U+5m+XNw=
|
||||
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
||||
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
|
||||
github.com/fxamacker/cbor/v2 v2.9.1 h1:2rWm8B193Ll4VdjsJY28jxs70IdDsHRWgQYAI80+rMQ=
|
||||
@@ -76,8 +76,6 @@ github.com/go-openapi/jsonreference v0.20.2/go.mod h1:Bl1zwGIM8/wsvqjsOQLJ/SH+En
|
||||
github.com/go-openapi/swag v0.22.3/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14=
|
||||
github.com/go-openapi/swag v0.23.0 h1:vsEVJDUo2hPJ2tu0/Xc+4noaxyEffXNIs3cOULZ+GrE=
|
||||
github.com/go-openapi/swag v0.23.0/go.mod h1:esZ8ITTYEsH1V2trKHjAN8Ai7xHb8RV+YSZ577vPjgQ=
|
||||
github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI=
|
||||
github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8=
|
||||
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
|
||||
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
|
||||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
@@ -95,11 +93,7 @@ github.com/google/gnostic-models v0.7.0/go.mod h1:whL5G0m6dmc5cPxKc5bdKdEN3UjI7O
|
||||
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
|
||||
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
|
||||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||
github.com/google/pprof v0.0.0-20260302011040-a15ffb7f9dcc h1:VBbFa1lDYWEeV5FZKUiYKYT0VxCp9twUmmaq9eb8sXw=
|
||||
github.com/google/pprof v0.0.0-20260302011040-a15ffb7f9dcc/go.mod h1:MxpfABSjhmINe3F1It9d+8exIHFvUqtLIRCdOGNXqiI=
|
||||
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
||||
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/gorilla/rpc v1.2.1 h1:yC+LMV5esttgpVvNORL/xX4jvTTEUE30UZhZ5JF7K9k=
|
||||
@@ -120,22 +114,19 @@ github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHm
|
||||
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
|
||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||
github.com/kkdai/bstream v0.0.0-20161212061736-f391b8402d23/go.mod h1:J+Gs4SYgM6CZQHDETBtE9HaSEkGmuNXF86RwHhHUvq4=
|
||||
github.com/klauspost/compress v1.18.5 h1:/h1gH5Ce+VWNLSWqPzOVn6XBO+vJbCNGvjoaGBFW2IE=
|
||||
github.com/klauspost/compress v1.18.5/go.mod h1:cwPg85FWrGar70rWktvGQj8/hthj3wpl0PGDogxkrSQ=
|
||||
github.com/klauspost/compress v1.18.6 h1:2jupLlAwFm95+YDR+NwD2MEfFO9d4z4Prjl1XXDjuao=
|
||||
github.com/klauspost/compress v1.18.6/go.mod h1:cwPg85FWrGar70rWktvGQj8/hthj3wpl0PGDogxkrSQ=
|
||||
github.com/klauspost/cpuid/v2 v2.0.1/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
|
||||
github.com/klauspost/cpuid/v2 v2.3.0 h1:S4CRMLnYUhGeDFDqkGriYKdfoFlDnMtqTiI/sFzhA9Y=
|
||||
github.com/klauspost/cpuid/v2 v2.3.0/go.mod h1:hqwkgyIinND0mEev00jJYCxPNVRVXFQeu1XKlok6oO0=
|
||||
github.com/klauspost/crc32 v1.3.0 h1:sSmTt3gUt81RP655XGZPElI0PelVTZ6YwCRnPSupoFM=
|
||||
github.com/klauspost/crc32 v1.3.0/go.mod h1:D7kQaZhnkX/Y0tstFGf8VUzv2UofNGqCjnC3zdHB0Hw=
|
||||
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
|
||||
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
|
||||
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
|
||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||
github.com/luxfi/accel v1.1.9 h1:Tsk6gXj2uKE19501bD0ajRYdeCHIlTGb6jYyLc+F8hc=
|
||||
github.com/luxfi/accel v1.1.9/go.mod h1:K00BcnLzEYMPHwCFq8Tf/450ApmTs9xBVvYOnofJCkc=
|
||||
github.com/luxfi/accel v1.2.4 h1:5VbIHyEvvfobn2zBiTFODxDw1CeqxCepZOLlvkuf9yQ=
|
||||
github.com/luxfi/accel v1.2.4/go.mod h1:ISIwAX+ZfsL/S5nsP2JvfldXN6Nc+QzoWf6Jtaq+xsQ=
|
||||
github.com/luxfi/address v1.0.1 h1:Sc4keyuVzBIvHr7uVeYZf2/WY9YDGUgDi/iiWenj49g=
|
||||
github.com/luxfi/address v1.0.1/go.mod h1:5j3Eh66v9zvv1GbNdZwt+23krV8JlSDaRzmWZU8ZRM0=
|
||||
github.com/luxfi/age v1.5.0 h1:G69HbSV4R3vKEH9B0CulnRaMdSdf4RalMgP8xKmxHeI=
|
||||
@@ -146,52 +137,54 @@ github.com/luxfi/constants v1.5.8 h1:iNP9AWNUcM4Tps7jYnx49CwtCWAC9mYRxJfGou2za0g
|
||||
github.com/luxfi/constants v1.5.8/go.mod h1:Pu5jWHdnUtQRbWC43yTUjU/pbIIKMDOd2a2yroSfo48=
|
||||
github.com/luxfi/container v0.0.4 h1:BXhF82WyfqVP5mjlNcr7tP0Fcnvl0Ap1rkiu+rq5XuM=
|
||||
github.com/luxfi/container v0.0.4/go.mod h1:Z3SpmMF5d4t77MM0nHYXURpn+EMVaeu1fhbd/3BGaek=
|
||||
github.com/luxfi/crypto v1.19.17 h1:l2LLu7UFyICtJVfraLDLRi+lFGiDXKHSL18M9/m1gsQ=
|
||||
github.com/luxfi/crypto v1.19.17/go.mod h1:INjdZtke85k8hX/QAmTMAY8bbZ4gzGZQLqURg3xf6Gk=
|
||||
github.com/luxfi/crypto v1.19.27 h1:K4l9nsnB0t61zHO5u8si06zVzW5WTjWW+/6+KRb/bfo=
|
||||
github.com/luxfi/crypto v1.19.27/go.mod h1:0DCU62kX8+zhYU2qeM07A4pifJyPkPujnUOfgc8TOFQ=
|
||||
github.com/luxfi/crypto/ipa v1.2.4 h1:6xfwhI9/HrcDkF3Ti5/NxsNQIWbwYDJmRSNIHRQ/xfU=
|
||||
github.com/luxfi/crypto/ipa v1.2.4/go.mod h1:43J6f6rcfUMrZt4cQectMOZb6Ps+fAEj8ZTPC3Kk+gE=
|
||||
github.com/luxfi/formatting v1.0.1 h1:ZnE1rAdEUds9yAegdVdGDOBGN6hLMPOv6E03Fp8IEYo=
|
||||
github.com/luxfi/formatting v1.0.1/go.mod h1:mYzNf5DJOiqSSKUPzNj5dKy4tstFbN3pZlkI5716eKc=
|
||||
github.com/luxfi/geth v1.16.98 h1:w187TtKuGStf3tm2bshuHVKBv2Frjx0lT54kQVXyNHA=
|
||||
github.com/luxfi/geth v1.16.98/go.mod h1:6kEzSExdk9CPQDPXALt6P3HfQqBq7KF1Jrrv9gBpxbU=
|
||||
github.com/luxfi/geth v1.17.12 h1:UP/fhpcfbGPTrkOCwX3d88Oc3jVm5gTOgfjgq+lek6s=
|
||||
github.com/luxfi/geth v1.17.12/go.mod h1:3vQfQJd9JC+AVBjxNXa9PYQOqpbE2dKu8E3jqhPZ3LU=
|
||||
github.com/luxfi/go-bip32 v1.0.2 h1:7vFbb+Wr4Z499q2tuCLdd7wWjtn8sH+HWBlx76mhH9Y=
|
||||
github.com/luxfi/go-bip32 v1.0.2/go.mod h1:bc7/LXDKAJQZ/F0Xjf5yXaTZxY9/ssLb4FC+Hxn/cDk=
|
||||
github.com/luxfi/go-bip39 v1.1.2 h1:p+wLMPGs6MLQh7q0YIsmy2EhHL7LHiELEGTJko6t/Jg=
|
||||
github.com/luxfi/go-bip39 v1.1.2/go.mod h1:96de9VkR2kY/ASAnhMtvt3TSh+PZkAFAngNj0GjRGDo=
|
||||
github.com/luxfi/ids v1.2.15 h1:omE+E4+0Poj9DzM11ejSFgteaSQ3KDHi5g54iH6jcxI=
|
||||
github.com/luxfi/ids v1.2.15/go.mod h1:Fj73K5xcblvdE0SxU/ip+jE8VqNdu+80548su5KJ7xI=
|
||||
github.com/luxfi/keys v1.1.0 h1:a4UkVVg6G09XC7vPtXKxEGwVt50GNPjEvq2pkjYZW2k=
|
||||
github.com/luxfi/keys v1.1.0 h1:/3mQflSCTMy/bTGbYXh2xJ+NhYDKRoBMimYpj2/d3XM=
|
||||
github.com/luxfi/keys v1.1.0/go.mod h1:U3tZNDmv3nXkPoZwLtq9RNjwyN0XyoN29worigfT+c0=
|
||||
github.com/luxfi/log v1.4.1 h1:rIfFRodb9jrD/w7KayaUk0Oc+37PaQQdKEEMJCjR8gw=
|
||||
github.com/luxfi/log v1.4.1/go.mod h1:64IE3xRMJcpkQwnPUfJw3pDj7wU0kRS7BZ9wM7R72jk=
|
||||
github.com/luxfi/log v1.4.3 h1:xkUKRWvQ4ZwvlUC2e0/RTtHYZOYSMvSQ9W9lbjwBmiI=
|
||||
github.com/luxfi/log v1.4.3/go.mod h1:myIkufyiQomSQH34K981kbz6cG4WUoerRUh7F4XhlQI=
|
||||
github.com/luxfi/math v1.4.1 h1:1t9bCCsEqnl9yIKrShlbs80DBKyYTWdnzkVfBqEeO7Q=
|
||||
github.com/luxfi/math v1.4.1/go.mod h1:QvbRxauQyE1w4lvbcLSe6c8yeJz2Zj1Bq1rayGgs2tA=
|
||||
github.com/luxfi/math/big v0.1.0 h1:Vz4c0RsZVPdIKPsHPgAJChH/R3p15WHRUz7LkLf+NIQ=
|
||||
github.com/luxfi/math/big v0.1.0/go.mod h1:BuxSu22RbO93xBLk5Eam5nldFponoJ73xDFz4uJ3Huk=
|
||||
github.com/luxfi/mdns v0.1.1 h1:g2eRr9AXcziPkkcd24M+Qu9ApEpoKKjfI79QSNqv0rQ=
|
||||
github.com/luxfi/mdns v0.1.1/go.mod h1:dbp5f3h3aE7CGzwbaWzBM9cwdcekhmSrWhQevgYhhNA=
|
||||
github.com/luxfi/metric v1.5.7 h1:LoSPEUpak2SLcynF+LT2cXjl9ECp4nY+Lia9zudmDv4=
|
||||
github.com/luxfi/metric v1.5.7/go.mod h1:CMguEhyuLi4YUWyXimJ+UHply99BDFrL0pxedB7rBqM=
|
||||
github.com/luxfi/metric v1.5.8 h1:axPwfq+erOlIue7IJp5g+hMcMtVhYHja9gJAaT3+KNA=
|
||||
github.com/luxfi/metric v1.5.8/go.mod h1:fO2giazkg4NDtr72JM/QXJBYebplAMeWC1JoZyNDvKw=
|
||||
github.com/luxfi/mock v0.1.1 h1:0HEtIjg1J6CWz+IUyP6rsGqNWTcmxjFnSQIhaDuARwY=
|
||||
github.com/luxfi/mock v0.1.1/go.mod h1:jo35akl3Vtd8LbzDts8VJ0jmSVycrd1/eBi6g6t5hKU=
|
||||
github.com/luxfi/pq v1.0.3 h1:pFlQm1+5FuKTDUh2y/23bXWkN4I2Rc5iuxJypwDFFMs=
|
||||
github.com/luxfi/pq v1.0.3 h1:ksw1dmfTR0dqqNMRS7BjGcprCO2Fhc+3Iiq2/NMuONw=
|
||||
github.com/luxfi/pq v1.0.3/go.mod h1:8bppZcRElfrVt0n3nYCZW3iX1TvhvzNbdjNdK1irgIE=
|
||||
github.com/luxfi/proto v1.0.0 h1:nlxv4lt/i75XDB2Q3nTqC1o0RDPmJ9K9CJ8UyYvceak=
|
||||
github.com/luxfi/proto v1.0.0/go.mod h1:pZLKsCmhiPtmm3z7ezBbnsYT2m79q+cFSmzxvuBeANE=
|
||||
github.com/luxfi/proto v1.3.4 h1:dNrdQ/414Pe9otIekVUmQ9QLqemaMFK43H4N3DIbuzQ=
|
||||
github.com/luxfi/proto v1.3.4/go.mod h1:S80KrTzISCktptit/pWLzk6nHgagjJS86qbQL6gHutE=
|
||||
github.com/luxfi/sampler v1.1.0 h1:u3iRDl7V06ARh0e85h3HT+aZ1saCFo2yMMsh+dCJbqk=
|
||||
github.com/luxfi/sampler v1.1.0/go.mod h1:kJa53S3tC9+VSbuV3RFu68MmbCCBlr2UM39LOClQ/Hs=
|
||||
github.com/luxfi/tls v1.0.3 h1:rK3nxSAxrUOOSHOZnKChwV4f6UJ+cfOl8KWJXAQx/SI=
|
||||
github.com/luxfi/tls v1.0.3/go.mod h1:dQqSiGE7YxXUxOwICoReUuIitBms9DYOaCeteBwmIWw=
|
||||
github.com/luxfi/vm v1.2.0 h1:jTwQRHdC9VmyRZTPSn+IqjMju7f6xlxLc6P9CEg+Y2M=
|
||||
github.com/luxfi/vm v1.2.0/go.mod h1:qasVIBRerVQuvy9vFGrX3H8X8pPMPG5un/KbZSyq5YY=
|
||||
github.com/luxfi/vm v1.2.3 h1:IdfB02OtDmdy/YNxaIR8DquPp5Aq0fi5QXBqGHoRkug=
|
||||
github.com/luxfi/vm v1.2.3/go.mod h1:ZXmw1sKA6GL3Ma3BfYUv5Fzvx3aWu2QMtkxF3lL/3R4=
|
||||
github.com/luxfi/zap v0.7.2 h1:YecWTWNE5PPJXL56sLIkzS8b23bprUwZ5lPAQuLUtTE=
|
||||
github.com/luxfi/zap v0.7.2/go.mod h1:1k+nwT+JW802YzuPAuf7CxMSGr/qxvbGgGwi5k6X9Ok=
|
||||
github.com/luxfi/zapdb v1.10.0 h1:1lLHEmkyC0BucnA/zjQYsMkUVxuEo2vQkEaQGjYfuuc=
|
||||
github.com/luxfi/zapdb v1.10.0/go.mod h1:Qukh3hDRD0MnxA6z+a28JTnXhN85AiLLgp6TYr4QAMc=
|
||||
github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0=
|
||||
github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
|
||||
github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE=
|
||||
github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8=
|
||||
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
|
||||
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
||||
github.com/mattn/go-colorable v0.1.15 h1:+u9SLTRGnXv73cEsnsmoZBom+dMU88B2M0aDcWy0/jY=
|
||||
github.com/mattn/go-colorable v0.1.15/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8=
|
||||
github.com/mattn/go-isatty v0.0.22 h1:j8l17JJ9i6VGPUFUYoTUKPSgKe/83EYU2zBC7YNKMw4=
|
||||
github.com/mattn/go-isatty v0.0.22/go.mod h1:ZXfXG4SQHsB/w3ZeOYbR0PrPwLy+n6xiMrJlRFqopa4=
|
||||
github.com/miekg/dns v1.1.27/go.mod h1:KNUDUusw/aVsxyTYZM1oqvCicbwhgbNgztCETuNZ7xM=
|
||||
github.com/miekg/dns v1.1.72 h1:vhmr+TF2A3tuoGNkLDFK9zi36F2LS+hKTRW0Uf8kbzI=
|
||||
github.com/miekg/dns v1.1.72/go.mod h1:+EuEPhdHOsfk6Wk5TT2CzssZdqkmFhf8r+aVyDEToIs=
|
||||
@@ -207,8 +200,8 @@ github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJ
|
||||
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
|
||||
github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee h1:W5t00kpgFdJifH4BDsTlE89Zl93FEloxaWZfGcifgq8=
|
||||
github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
|
||||
github.com/mr-tron/base58 v1.2.0 h1:T/HDJBh4ZCPbU39/+c3rRvE0uKBQlU27+QI8LJ4t64o=
|
||||
github.com/mr-tron/base58 v1.2.0/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc=
|
||||
github.com/mr-tron/base58 v1.3.0 h1:K6Y13R2h+dku0wOqKtecgRnBUBPrZzLZy5aIj8lCcJI=
|
||||
github.com/mr-tron/base58 v1.3.0/go.mod h1:2BuubE67DCSWwVfx37JWNG8emOC0sHEU4/HpcYgCLX8=
|
||||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA=
|
||||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
|
||||
github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
|
||||
@@ -216,23 +209,17 @@ github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+W
|
||||
github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||
github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk=
|
||||
github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY=
|
||||
github.com/onsi/ginkgo/v2 v2.28.1 h1:S4hj+HbZp40fNKuLUQOYLDgZLwNUVn19N3Atb98NCyI=
|
||||
github.com/onsi/ginkgo/v2 v2.28.1/go.mod h1:CLtbVInNckU3/+gC8LzkGUb9oF+e8W8TdUsxPwvdOgE=
|
||||
github.com/onsi/gomega v1.4.1/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA=
|
||||
github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
|
||||
github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
|
||||
github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
|
||||
github.com/onsi/gomega v1.39.1 h1:1IJLAad4zjPn2PsnhH70V4DKRFlrCzGBNrNaru+Vf28=
|
||||
github.com/onsi/gomega v1.39.1/go.mod h1:hL6yVALoTOxeWudERyfppUcZXjMwIMLnuSfruD2lcfg=
|
||||
github.com/philhofer/fwd v1.2.0 h1:e6DnBTl7vGY+Gz322/ASL4Gyp1FspeMvx1RNDoToZuM=
|
||||
github.com/philhofer/fwd v1.2.0/go.mod h1:RqIHx9QI14HlwKwm98g9Re5prTQ6LdeRQn+gXJFxsJM=
|
||||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
|
||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ=
|
||||
github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc=
|
||||
github.com/rs/xid v1.6.0 h1:fV591PaemRlL6JfRxGDEPl69wICngIQ3shQtzfy2gxU=
|
||||
github.com/rs/xid v1.6.0/go.mod h1:7XoLgs4eV+QndskICGsho+ADou8ySMSjJKDIan90Nz0=
|
||||
github.com/spf13/pflag v1.0.10 h1:4EBh2KAYBwaONj6b2Ye1GiHfwjqyROoF4RwYO+vPwFk=
|
||||
@@ -240,7 +227,6 @@ github.com/spf13/pflag v1.0.10/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3A
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
||||
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
|
||||
github.com/stretchr/objx v0.5.3 h1:jmXUvGomnU1o3W/V5h2VEradbpJDwGrzugQQvL0POH4=
|
||||
github.com/stretchr/objx v0.5.3/go.mod h1:rDQraq+vQZU7Fde9LOZLr8Tax6zZvy4kuNKF+QYS+U0=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
@@ -248,8 +234,6 @@ github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/
|
||||
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
||||
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
||||
github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
|
||||
github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
|
||||
github.com/supranational/blst v0.3.16 h1:bTDadT+3fK497EvLdWRQEjiGnUtzJ7jjIUMF0jqwYhE=
|
||||
github.com/supranational/blst v0.3.16/go.mod h1:jZJtfjgudtNl4en1tzwPIV3KjUnQUvG3/j+w+fVonLw=
|
||||
github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7/go.mod h1:q4W45IWZaF22tdD+VEXcAWRA037jwmWEB5VWYORlTpc=
|
||||
@@ -279,8 +263,8 @@ golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8U
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.52.0 h1:RMs7fP2rXdep0CftQlK8Uf+kibLm7qkCcradZWYz988=
|
||||
golang.org/x/crypto v0.52.0/go.mod h1:1QgfPxDqh0T2M/elOJtp9RvuR95kVjir0e6/BvEmGbc=
|
||||
golang.org/x/exp v0.0.0-20260312153236-7ab1446f8b90 h1:jiDhWWeC7jfWqR9c/uplMOqJ0sbNlNWv0UkzE0vX1MA=
|
||||
golang.org/x/exp v0.0.0-20260312153236-7ab1446f8b90/go.mod h1:xE1HEv6b+1SCZ5/uscMRjUBKtIxworgEcEi+/n9NQDQ=
|
||||
golang.org/x/exp v0.0.0-20260529124908-c761662dc8c9 h1:4d4PbuBNwaxMXkXI8yiIYjydtMU+04RHeuSxJdgKftM=
|
||||
golang.org/x/exp v0.0.0-20260529124908-c761662dc8c9/go.mod h1:d2fgXJLVs4dYDHUk5lwMIfzRzSrWCfGZb0ZqeLa/Vcw=
|
||||
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
|
||||
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
@@ -317,7 +301,6 @@ golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7w
|
||||
golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200814200057-3d37ad5750ed/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.45.0 h1:dO4czNzziLiiXplLQgBCEpCvXQ3dnkn0SdaZSYdQ+FY=
|
||||
golang.org/x/sys v0.45.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=
|
||||
golang.org/x/term v0.43.0 h1:S4RLU2sB31O/NCl+zFN9Aru9A/Cq2aqKpTZJ6B+DwT4=
|
||||
@@ -351,7 +334,6 @@ google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2
|
||||
google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE=
|
||||
google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
||||
gopkg.in/evanphx/json-patch.v4 v4.12.0 h1:n6jtcsulIzXPJaxegRbvFNNrZDjbij7ny3gmSPG+6V4=
|
||||
gopkg.in/evanphx/json-patch.v4 v4.12.0/go.mod h1:p8EYWUEYMpynmqDbY58zCKCFZw8pRWMG4EsWvDvM72M=
|
||||
|
||||
@@ -1,2 +1,3 @@
|
||||
* -text
|
||||
*.bin -text -diff
|
||||
*.md text eol=lf
|
||||
|
||||
+700
-700
File diff suppressed because it is too large
Load Diff
+78
-78
@@ -1,79 +1,79 @@
|
||||
# Finite State Entropy
|
||||
|
||||
This package provides Finite State Entropy encoding and decoding.
|
||||
|
||||
Finite State Entropy (also referenced as [tANS](https://en.wikipedia.org/wiki/Asymmetric_numeral_systems#tANS))
|
||||
encoding provides a fast near-optimal symbol encoding/decoding
|
||||
for byte blocks as implemented in [zstandard](https://github.com/facebook/zstd).
|
||||
|
||||
This can be used for compressing input with a lot of similar input values to the smallest number of bytes.
|
||||
This does not perform any multi-byte [dictionary coding](https://en.wikipedia.org/wiki/Dictionary_coder) as LZ coders,
|
||||
but it can be used as a secondary step to compressors (like Snappy) that does not do entropy encoding.
|
||||
|
||||
* [Godoc documentation](https://godoc.org/github.com/klauspost/compress/fse)
|
||||
|
||||
## News
|
||||
|
||||
* Feb 2018: First implementation released. Consider this beta software for now.
|
||||
|
||||
# Usage
|
||||
|
||||
This package provides a low level interface that allows to compress single independent blocks.
|
||||
|
||||
Each block is separate, and there is no built in integrity checks.
|
||||
This means that the caller should keep track of block sizes and also do checksums if needed.
|
||||
|
||||
Compressing a block is done via the [`Compress`](https://godoc.org/github.com/klauspost/compress/fse#Compress) function.
|
||||
You must provide input and will receive the output and maybe an error.
|
||||
|
||||
These error values can be returned:
|
||||
|
||||
| Error | Description |
|
||||
|---------------------|-----------------------------------------------------------------------------|
|
||||
| `<nil>` | Everything ok, output is returned |
|
||||
| `ErrIncompressible` | Returned when input is judged to be too hard to compress |
|
||||
| `ErrUseRLE` | Returned from the compressor when the input is a single byte value repeated |
|
||||
| `(error)` | An internal error occurred. |
|
||||
|
||||
As can be seen above there are errors that will be returned even under normal operation so it is important to handle these.
|
||||
|
||||
To reduce allocations you can provide a [`Scratch`](https://godoc.org/github.com/klauspost/compress/fse#Scratch) object
|
||||
that can be re-used for successive calls. Both compression and decompression accepts a `Scratch` object, and the same
|
||||
object can be used for both.
|
||||
|
||||
Be aware, that when re-using a `Scratch` object that the *output* buffer is also re-used, so if you are still using this
|
||||
you must set the `Out` field in the scratch to nil. The same buffer is used for compression and decompression output.
|
||||
|
||||
Decompressing is done by calling the [`Decompress`](https://godoc.org/github.com/klauspost/compress/fse#Decompress) function.
|
||||
You must provide the output from the compression stage, at exactly the size you got back. If you receive an error back
|
||||
your input was likely corrupted.
|
||||
|
||||
It is important to note that a successful decoding does *not* mean your output matches your original input.
|
||||
There are no integrity checks, so relying on errors from the decompressor does not assure your data is valid.
|
||||
|
||||
For more detailed usage, see examples in the [godoc documentation](https://godoc.org/github.com/klauspost/compress/fse#pkg-examples).
|
||||
|
||||
# Performance
|
||||
|
||||
A lot of factors are affecting speed. Block sizes and compressibility of the material are primary factors.
|
||||
All compression functions are currently only running on the calling goroutine so only one core will be used per block.
|
||||
|
||||
The compressor is significantly faster if symbols are kept as small as possible. The highest byte value of the input
|
||||
is used to reduce some of the processing, so if all your input is above byte value 64 for instance, it may be
|
||||
beneficial to transpose all your input values down by 64.
|
||||
|
||||
With moderate block sizes around 64k speed are typically 200MB/s per core for compression and
|
||||
around 300MB/s decompression speed.
|
||||
|
||||
The same hardware typically does Huffman (deflate) encoding at 125MB/s and decompression at 100MB/s.
|
||||
|
||||
# Plans
|
||||
|
||||
At one point, more internals will be exposed to facilitate more "expert" usage of the components.
|
||||
|
||||
A streaming interface is also likely to be implemented. Likely compatible with [FSE stream format](https://github.com/Cyan4973/FiniteStateEntropy/blob/dev/programs/fileio.c#L261).
|
||||
|
||||
# Contributing
|
||||
|
||||
Contributions are always welcome. Be aware that adding public functions will require good justification and breaking
|
||||
# Finite State Entropy
|
||||
|
||||
This package provides Finite State Entropy encoding and decoding.
|
||||
|
||||
Finite State Entropy (also referenced as [tANS](https://en.wikipedia.org/wiki/Asymmetric_numeral_systems#tANS))
|
||||
encoding provides a fast near-optimal symbol encoding/decoding
|
||||
for byte blocks as implemented in [zstandard](https://github.com/facebook/zstd).
|
||||
|
||||
This can be used for compressing input with a lot of similar input values to the smallest number of bytes.
|
||||
This does not perform any multi-byte [dictionary coding](https://en.wikipedia.org/wiki/Dictionary_coder) as LZ coders,
|
||||
but it can be used as a secondary step to compressors (like Snappy) that does not do entropy encoding.
|
||||
|
||||
* [Godoc documentation](https://godoc.org/github.com/klauspost/compress/fse)
|
||||
|
||||
## News
|
||||
|
||||
* Feb 2018: First implementation released. Consider this beta software for now.
|
||||
|
||||
# Usage
|
||||
|
||||
This package provides a low level interface that allows to compress single independent blocks.
|
||||
|
||||
Each block is separate, and there is no built in integrity checks.
|
||||
This means that the caller should keep track of block sizes and also do checksums if needed.
|
||||
|
||||
Compressing a block is done via the [`Compress`](https://godoc.org/github.com/klauspost/compress/fse#Compress) function.
|
||||
You must provide input and will receive the output and maybe an error.
|
||||
|
||||
These error values can be returned:
|
||||
|
||||
| Error | Description |
|
||||
|---------------------|-----------------------------------------------------------------------------|
|
||||
| `<nil>` | Everything ok, output is returned |
|
||||
| `ErrIncompressible` | Returned when input is judged to be too hard to compress |
|
||||
| `ErrUseRLE` | Returned from the compressor when the input is a single byte value repeated |
|
||||
| `(error)` | An internal error occurred. |
|
||||
|
||||
As can be seen above there are errors that will be returned even under normal operation so it is important to handle these.
|
||||
|
||||
To reduce allocations you can provide a [`Scratch`](https://godoc.org/github.com/klauspost/compress/fse#Scratch) object
|
||||
that can be re-used for successive calls. Both compression and decompression accepts a `Scratch` object, and the same
|
||||
object can be used for both.
|
||||
|
||||
Be aware, that when re-using a `Scratch` object that the *output* buffer is also re-used, so if you are still using this
|
||||
you must set the `Out` field in the scratch to nil. The same buffer is used for compression and decompression output.
|
||||
|
||||
Decompressing is done by calling the [`Decompress`](https://godoc.org/github.com/klauspost/compress/fse#Decompress) function.
|
||||
You must provide the output from the compression stage, at exactly the size you got back. If you receive an error back
|
||||
your input was likely corrupted.
|
||||
|
||||
It is important to note that a successful decoding does *not* mean your output matches your original input.
|
||||
There are no integrity checks, so relying on errors from the decompressor does not assure your data is valid.
|
||||
|
||||
For more detailed usage, see examples in the [godoc documentation](https://godoc.org/github.com/klauspost/compress/fse#pkg-examples).
|
||||
|
||||
# Performance
|
||||
|
||||
A lot of factors are affecting speed. Block sizes and compressibility of the material are primary factors.
|
||||
All compression functions are currently only running on the calling goroutine so only one core will be used per block.
|
||||
|
||||
The compressor is significantly faster if symbols are kept as small as possible. The highest byte value of the input
|
||||
is used to reduce some of the processing, so if all your input is above byte value 64 for instance, it may be
|
||||
beneficial to transpose all your input values down by 64.
|
||||
|
||||
With moderate block sizes around 64k speed are typically 200MB/s per core for compression and
|
||||
around 300MB/s decompression speed.
|
||||
|
||||
The same hardware typically does Huffman (deflate) encoding at 125MB/s and decompression at 100MB/s.
|
||||
|
||||
# Plans
|
||||
|
||||
At one point, more internals will be exposed to facilitate more "expert" usage of the components.
|
||||
|
||||
A streaming interface is also likely to be implemented. Likely compatible with [FSE stream format](https://github.com/Cyan4973/FiniteStateEntropy/blob/dev/programs/fileio.c#L261).
|
||||
|
||||
# Contributing
|
||||
|
||||
Contributions are always welcome. Be aware that adding public functions will require good justification and breaking
|
||||
changes will likely not be accepted. If in doubt open an issue before writing the PR.
|
||||
+89
-89
@@ -1,89 +1,89 @@
|
||||
# Huff0 entropy compression
|
||||
|
||||
This package provides Huff0 encoding and decoding as used in zstd.
|
||||
|
||||
[Huff0](https://github.com/Cyan4973/FiniteStateEntropy#new-generation-entropy-coders),
|
||||
a Huffman codec designed for modern CPU, featuring OoO (Out of Order) operations on multiple ALU
|
||||
(Arithmetic Logic Unit), achieving extremely fast compression and decompression speeds.
|
||||
|
||||
This can be used for compressing input with a lot of similar input values to the smallest number of bytes.
|
||||
This does not perform any multi-byte [dictionary coding](https://en.wikipedia.org/wiki/Dictionary_coder) as LZ coders,
|
||||
but it can be used as a secondary step to compressors (like Snappy) that does not do entropy encoding.
|
||||
|
||||
* [Godoc documentation](https://godoc.org/github.com/klauspost/compress/huff0)
|
||||
|
||||
## News
|
||||
|
||||
This is used as part of the [zstandard](https://github.com/klauspost/compress/tree/master/zstd#zstd) compression and decompression package.
|
||||
|
||||
This ensures that most functionality is well tested.
|
||||
|
||||
# Usage
|
||||
|
||||
This package provides a low level interface that allows to compress single independent blocks.
|
||||
|
||||
Each block is separate, and there is no built in integrity checks.
|
||||
This means that the caller should keep track of block sizes and also do checksums if needed.
|
||||
|
||||
Compressing a block is done via the [`Compress1X`](https://godoc.org/github.com/klauspost/compress/huff0#Compress1X) and
|
||||
[`Compress4X`](https://godoc.org/github.com/klauspost/compress/huff0#Compress4X) functions.
|
||||
You must provide input and will receive the output and maybe an error.
|
||||
|
||||
These error values can be returned:
|
||||
|
||||
| Error | Description |
|
||||
|---------------------|-----------------------------------------------------------------------------|
|
||||
| `<nil>` | Everything ok, output is returned |
|
||||
| `ErrIncompressible` | Returned when input is judged to be too hard to compress |
|
||||
| `ErrUseRLE` | Returned from the compressor when the input is a single byte value repeated |
|
||||
| `ErrTooBig` | Returned if the input block exceeds the maximum allowed size (128 Kib) |
|
||||
| `(error)` | An internal error occurred. |
|
||||
|
||||
|
||||
As can be seen above some of there are errors that will be returned even under normal operation so it is important to handle these.
|
||||
|
||||
To reduce allocations you can provide a [`Scratch`](https://godoc.org/github.com/klauspost/compress/huff0#Scratch) object
|
||||
that can be re-used for successive calls. Both compression and decompression accepts a `Scratch` object, and the same
|
||||
object can be used for both.
|
||||
|
||||
Be aware, that when re-using a `Scratch` object that the *output* buffer is also re-used, so if you are still using this
|
||||
you must set the `Out` field in the scratch to nil. The same buffer is used for compression and decompression output.
|
||||
|
||||
The `Scratch` object will retain state that allows to re-use previous tables for encoding and decoding.
|
||||
|
||||
## Tables and re-use
|
||||
|
||||
Huff0 allows for reusing tables from the previous block to save space if that is expected to give better/faster results.
|
||||
|
||||
The Scratch object allows you to set a [`ReusePolicy`](https://godoc.org/github.com/klauspost/compress/huff0#ReusePolicy)
|
||||
that controls this behaviour. See the documentation for details. This can be altered between each block.
|
||||
|
||||
Do however note that this information is *not* stored in the output block and it is up to the users of the package to
|
||||
record whether [`ReadTable`](https://godoc.org/github.com/klauspost/compress/huff0#ReadTable) should be called,
|
||||
based on the boolean reported back from the CompressXX call.
|
||||
|
||||
If you want to store the table separate from the data, you can access them as `OutData` and `OutTable` on the
|
||||
[`Scratch`](https://godoc.org/github.com/klauspost/compress/huff0#Scratch) object.
|
||||
|
||||
## Decompressing
|
||||
|
||||
The first part of decoding is to initialize the decoding table through [`ReadTable`](https://godoc.org/github.com/klauspost/compress/huff0#ReadTable).
|
||||
This will initialize the decoding tables.
|
||||
You can supply the complete block to `ReadTable` and it will return the data part of the block
|
||||
which can be given to the decompressor.
|
||||
|
||||
Decompressing is done by calling the [`Decompress1X`](https://godoc.org/github.com/klauspost/compress/huff0#Scratch.Decompress1X)
|
||||
or [`Decompress4X`](https://godoc.org/github.com/klauspost/compress/huff0#Scratch.Decompress4X) function.
|
||||
|
||||
For concurrently decompressing content with a fixed table a stateless [`Decoder`](https://godoc.org/github.com/klauspost/compress/huff0#Decoder) can be requested which will remain correct as long as the scratch is unchanged. The capacity of the provided slice indicates the expected output size.
|
||||
|
||||
You must provide the output from the compression stage, at exactly the size you got back. If you receive an error back
|
||||
your input was likely corrupted.
|
||||
|
||||
It is important to note that a successful decoding does *not* mean your output matches your original input.
|
||||
There are no integrity checks, so relying on errors from the decompressor does not assure your data is valid.
|
||||
|
||||
# Contributing
|
||||
|
||||
Contributions are always welcome. Be aware that adding public functions will require good justification and breaking
|
||||
changes will likely not be accepted. If in doubt open an issue before writing the PR.
|
||||
# Huff0 entropy compression
|
||||
|
||||
This package provides Huff0 encoding and decoding as used in zstd.
|
||||
|
||||
[Huff0](https://github.com/Cyan4973/FiniteStateEntropy#new-generation-entropy-coders),
|
||||
a Huffman codec designed for modern CPU, featuring OoO (Out of Order) operations on multiple ALU
|
||||
(Arithmetic Logic Unit), achieving extremely fast compression and decompression speeds.
|
||||
|
||||
This can be used for compressing input with a lot of similar input values to the smallest number of bytes.
|
||||
This does not perform any multi-byte [dictionary coding](https://en.wikipedia.org/wiki/Dictionary_coder) as LZ coders,
|
||||
but it can be used as a secondary step to compressors (like Snappy) that does not do entropy encoding.
|
||||
|
||||
* [Godoc documentation](https://godoc.org/github.com/klauspost/compress/huff0)
|
||||
|
||||
## News
|
||||
|
||||
This is used as part of the [zstandard](https://github.com/klauspost/compress/tree/master/zstd#zstd) compression and decompression package.
|
||||
|
||||
This ensures that most functionality is well tested.
|
||||
|
||||
# Usage
|
||||
|
||||
This package provides a low level interface that allows to compress single independent blocks.
|
||||
|
||||
Each block is separate, and there is no built in integrity checks.
|
||||
This means that the caller should keep track of block sizes and also do checksums if needed.
|
||||
|
||||
Compressing a block is done via the [`Compress1X`](https://godoc.org/github.com/klauspost/compress/huff0#Compress1X) and
|
||||
[`Compress4X`](https://godoc.org/github.com/klauspost/compress/huff0#Compress4X) functions.
|
||||
You must provide input and will receive the output and maybe an error.
|
||||
|
||||
These error values can be returned:
|
||||
|
||||
| Error | Description |
|
||||
|---------------------|-----------------------------------------------------------------------------|
|
||||
| `<nil>` | Everything ok, output is returned |
|
||||
| `ErrIncompressible` | Returned when input is judged to be too hard to compress |
|
||||
| `ErrUseRLE` | Returned from the compressor when the input is a single byte value repeated |
|
||||
| `ErrTooBig` | Returned if the input block exceeds the maximum allowed size (128 Kib) |
|
||||
| `(error)` | An internal error occurred. |
|
||||
|
||||
|
||||
As can be seen above some of there are errors that will be returned even under normal operation so it is important to handle these.
|
||||
|
||||
To reduce allocations you can provide a [`Scratch`](https://godoc.org/github.com/klauspost/compress/huff0#Scratch) object
|
||||
that can be re-used for successive calls. Both compression and decompression accepts a `Scratch` object, and the same
|
||||
object can be used for both.
|
||||
|
||||
Be aware, that when re-using a `Scratch` object that the *output* buffer is also re-used, so if you are still using this
|
||||
you must set the `Out` field in the scratch to nil. The same buffer is used for compression and decompression output.
|
||||
|
||||
The `Scratch` object will retain state that allows to re-use previous tables for encoding and decoding.
|
||||
|
||||
## Tables and re-use
|
||||
|
||||
Huff0 allows for reusing tables from the previous block to save space if that is expected to give better/faster results.
|
||||
|
||||
The Scratch object allows you to set a [`ReusePolicy`](https://godoc.org/github.com/klauspost/compress/huff0#ReusePolicy)
|
||||
that controls this behaviour. See the documentation for details. This can be altered between each block.
|
||||
|
||||
Do however note that this information is *not* stored in the output block and it is up to the users of the package to
|
||||
record whether [`ReadTable`](https://godoc.org/github.com/klauspost/compress/huff0#ReadTable) should be called,
|
||||
based on the boolean reported back from the CompressXX call.
|
||||
|
||||
If you want to store the table separate from the data, you can access them as `OutData` and `OutTable` on the
|
||||
[`Scratch`](https://godoc.org/github.com/klauspost/compress/huff0#Scratch) object.
|
||||
|
||||
## Decompressing
|
||||
|
||||
The first part of decoding is to initialize the decoding table through [`ReadTable`](https://godoc.org/github.com/klauspost/compress/huff0#ReadTable).
|
||||
This will initialize the decoding tables.
|
||||
You can supply the complete block to `ReadTable` and it will return the data part of the block
|
||||
which can be given to the decompressor.
|
||||
|
||||
Decompressing is done by calling the [`Decompress1X`](https://godoc.org/github.com/klauspost/compress/huff0#Scratch.Decompress1X)
|
||||
or [`Decompress4X`](https://godoc.org/github.com/klauspost/compress/huff0#Scratch.Decompress4X) function.
|
||||
|
||||
For concurrently decompressing content with a fixed table a stateless [`Decoder`](https://godoc.org/github.com/klauspost/compress/huff0#Decoder) can be requested which will remain correct as long as the scratch is unchanged. The capacity of the provided slice indicates the expected output size.
|
||||
|
||||
You must provide the output from the compression stage, at exactly the size you got back. If you receive an error back
|
||||
your input was likely corrupted.
|
||||
|
||||
It is important to note that a successful decoding does *not* mean your output matches your original input.
|
||||
There are no integrity checks, so relying on errors from the decompressor does not assure your data is valid.
|
||||
|
||||
# Contributing
|
||||
|
||||
Contributions are always welcome. Be aware that adding public functions will require good justification and breaking
|
||||
changes will likely not be accepted. If in doubt open an issue before writing the PR.
|
||||
|
||||
+1
-1
@@ -51,7 +51,7 @@
|
||||
//
|
||||
// The d variable is implicitly R_DST - R_DBASE, and len(dst)-d is R_DEND - R_DST.
|
||||
// The s variable is implicitly R_SRC - R_SBASE, and len(src)-s is R_SEND - R_SRC.
|
||||
TEXT ·s2Decode(SB), NOSPLIT, $48-56
|
||||
TEXT ·s2Decode(SB), NOSPLIT, $56-56
|
||||
// Initialize R_SRC, R_DST and R_DBASE-R_SEND.
|
||||
MOVQ dst_base+0(FP), R_DBASE
|
||||
MOVQ dst_len+8(FP), R_DLEN
|
||||
|
||||
+16
-12
@@ -23,12 +23,12 @@ func encodeBlockBest(dst, src []byte, dict *Dict) (d int) {
|
||||
// Initialize the hash tables.
|
||||
const (
|
||||
// Long hash matches.
|
||||
lTableBits = 19
|
||||
maxLTableSize = 1 << lTableBits
|
||||
lTableBits = bestLongTableBits
|
||||
maxLTableSize = bestLongTableSize
|
||||
|
||||
// Short hash matches.
|
||||
sTableBits = 16
|
||||
maxSTableSize = 1 << sTableBits
|
||||
sTableBits = bestShortTableBits
|
||||
maxSTableSize = bestShortTableSize
|
||||
|
||||
inputMargin = 8 + 2
|
||||
|
||||
@@ -44,8 +44,10 @@ func encodeBlockBest(dst, src []byte, dict *Dict) (d int) {
|
||||
}
|
||||
sLimitDict := min(len(src)-inputMargin, MaxDictSrcOffset-inputMargin)
|
||||
|
||||
var lTable [maxLTableSize]uint64
|
||||
var sTable [maxSTableSize]uint64
|
||||
tbl := getBestTables()
|
||||
lTable := &tbl.lTable
|
||||
sTable := &tbl.sTable
|
||||
defer bestTablePool.Put(tbl)
|
||||
|
||||
// Bail if we can't compress to at least this.
|
||||
dstLimit := len(src) - 5
|
||||
@@ -456,12 +458,12 @@ func encodeBlockBestSnappy(dst, src []byte) (d int) {
|
||||
// Initialize the hash tables.
|
||||
const (
|
||||
// Long hash matches.
|
||||
lTableBits = 19
|
||||
maxLTableSize = 1 << lTableBits
|
||||
lTableBits = bestLongTableBits
|
||||
maxLTableSize = bestLongTableSize
|
||||
|
||||
// Short hash matches.
|
||||
sTableBits = 16
|
||||
maxSTableSize = 1 << sTableBits
|
||||
sTableBits = bestShortTableBits
|
||||
maxSTableSize = bestShortTableSize
|
||||
|
||||
inputMargin = 8 + 2
|
||||
)
|
||||
@@ -474,8 +476,10 @@ func encodeBlockBestSnappy(dst, src []byte) (d int) {
|
||||
return 0
|
||||
}
|
||||
|
||||
var lTable [maxLTableSize]uint64
|
||||
var sTable [maxSTableSize]uint64
|
||||
tbl := getBestTables()
|
||||
lTable := &tbl.lTable
|
||||
sTable := &tbl.sTable
|
||||
defer bestTablePool.Put(tbl)
|
||||
|
||||
// Bail if we can't compress to at least this.
|
||||
dstLimit := len(src) - 5
|
||||
|
||||
+24
-18
@@ -59,16 +59,18 @@ func encodeBlockBetterGo(dst, src []byte) (d int) {
|
||||
// Initialize the hash tables.
|
||||
const (
|
||||
// Long hash matches.
|
||||
lTableBits = 17
|
||||
maxLTableSize = 1 << lTableBits
|
||||
lTableBits = betterLongTableBits
|
||||
maxLTableSize = betterLongTableSize
|
||||
|
||||
// Short hash matches.
|
||||
sTableBits = 14
|
||||
maxSTableSize = 1 << sTableBits
|
||||
sTableBits = betterShortTableBits
|
||||
maxSTableSize = betterShortTableSize
|
||||
)
|
||||
|
||||
var lTable [maxLTableSize]uint32
|
||||
var sTable [maxSTableSize]uint32
|
||||
tbl := getBetterTables()
|
||||
lTable := &tbl.lTable
|
||||
sTable := &tbl.sTable
|
||||
defer betterTablePool.Put(tbl)
|
||||
|
||||
// Bail if we can't compress to at least this.
|
||||
dstLimit := len(src) - len(src)>>5 - 6
|
||||
@@ -317,16 +319,18 @@ func encodeBlockBetterSnappyGo(dst, src []byte) (d int) {
|
||||
// Initialize the hash tables.
|
||||
const (
|
||||
// Long hash matches.
|
||||
lTableBits = 16
|
||||
maxLTableSize = 1 << lTableBits
|
||||
lTableBits = betterSnappyLongTableBits
|
||||
maxLTableSize = betterSnappyLongTableSize
|
||||
|
||||
// Short hash matches.
|
||||
sTableBits = 14
|
||||
maxSTableSize = 1 << sTableBits
|
||||
sTableBits = betterShortTableBits
|
||||
maxSTableSize = betterShortTableSize
|
||||
)
|
||||
|
||||
var lTable [maxLTableSize]uint32
|
||||
var sTable [maxSTableSize]uint32
|
||||
tbl := getBetterSnappyTables()
|
||||
lTable := &tbl.lTable
|
||||
sTable := &tbl.sTable
|
||||
defer betterSnappyTablePool.Put(tbl)
|
||||
|
||||
// Bail if we can't compress to at least this.
|
||||
dstLimit := len(src) - len(src)>>5 - 6
|
||||
@@ -902,12 +906,12 @@ func encodeBlockBetterDict(dst, src []byte, dict *Dict) (d int) {
|
||||
// Initialize the hash tables.
|
||||
const (
|
||||
// Long hash matches.
|
||||
lTableBits = 17
|
||||
maxLTableSize = 1 << lTableBits
|
||||
lTableBits = betterLongTableBits
|
||||
maxLTableSize = betterLongTableSize
|
||||
|
||||
// Short hash matches.
|
||||
sTableBits = 14
|
||||
maxSTableSize = 1 << sTableBits
|
||||
sTableBits = betterShortTableBits
|
||||
maxSTableSize = betterShortTableSize
|
||||
|
||||
maxAhead = 8 // maximum bytes ahead without checking sLimit
|
||||
|
||||
@@ -921,8 +925,10 @@ func encodeBlockBetterDict(dst, src []byte, dict *Dict) (d int) {
|
||||
|
||||
dict.initBetter()
|
||||
|
||||
var lTable [maxLTableSize]uint32
|
||||
var sTable [maxSTableSize]uint32
|
||||
tbl := getBetterTables()
|
||||
lTable := &tbl.lTable
|
||||
sTable := &tbl.sTable
|
||||
defer betterTablePool.Put(tbl)
|
||||
|
||||
// Bail if we can't compress to at least this.
|
||||
dstLimit := len(src) - len(src)>>5 - 6
|
||||
|
||||
+65
@@ -0,0 +1,65 @@
|
||||
package s2
|
||||
|
||||
import "sync"
|
||||
|
||||
// Table size constants
|
||||
const (
|
||||
betterLongTableBits = 17
|
||||
betterLongTableSize = 1 << betterLongTableBits // 131072
|
||||
|
||||
betterShortTableBits = 14
|
||||
betterShortTableSize = 1 << betterShortTableBits // 16384
|
||||
|
||||
betterSnappyLongTableBits = 16
|
||||
betterSnappyLongTableSize = 1 << betterSnappyLongTableBits // 65536
|
||||
|
||||
bestLongTableBits = 19
|
||||
bestLongTableSize = 1 << bestLongTableBits // 524288
|
||||
|
||||
bestShortTableBits = 16
|
||||
bestShortTableSize = 1 << bestShortTableBits // 65536
|
||||
)
|
||||
|
||||
type betterTables struct {
|
||||
lTable [betterLongTableSize]uint32
|
||||
sTable [betterShortTableSize]uint32
|
||||
}
|
||||
|
||||
var betterTablePool = sync.Pool{New: func() interface{} { return &betterTables{} }}
|
||||
|
||||
// betterSnappyTables holds better-snappy compression hash tables.
|
||||
type betterSnappyTables struct {
|
||||
lTable [betterSnappyLongTableSize]uint32
|
||||
sTable [betterShortTableSize]uint32
|
||||
}
|
||||
|
||||
var betterSnappyTablePool = sync.Pool{New: func() interface{} { return &betterSnappyTables{} }}
|
||||
|
||||
// bestTables holds best compression hash tables.
|
||||
type bestTables struct {
|
||||
lTable [bestLongTableSize]uint64
|
||||
sTable [bestShortTableSize]uint64
|
||||
}
|
||||
|
||||
var bestTablePool = sync.Pool{New: func() interface{} { return &bestTables{} }}
|
||||
|
||||
// getBetterTables gets a zeroed betterTables from the pool.
|
||||
func getBetterTables() *betterTables {
|
||||
t := betterTablePool.Get().(*betterTables)
|
||||
*t = betterTables{}
|
||||
return t
|
||||
}
|
||||
|
||||
// getBetterSnappyTables gets a zeroed betterSnappyTables from the pool.
|
||||
func getBetterSnappyTables() *betterSnappyTables {
|
||||
t := betterSnappyTablePool.Get().(*betterSnappyTables)
|
||||
*t = betterSnappyTables{}
|
||||
return t
|
||||
}
|
||||
|
||||
// getBestTables gets a zeroed bestTables from the pool.
|
||||
func getBestTables() *bestTables {
|
||||
t := bestTablePool.Get().(*bestTables)
|
||||
*t = bestTables{}
|
||||
return t
|
||||
}
|
||||
+44
@@ -75,6 +75,19 @@ lux/accel/
|
||||
- Kyber encapsulation/decapsulation
|
||||
- Dilithium signing/verification
|
||||
- Polynomial NTT/iNTT
|
||||
- ML-DSA batched verify / sign (FIPS 204; modes 2/3/5 = ML-DSA-44/65/87) —
|
||||
routes through `LatticeOps.MLDSAVerifyBatch` / `MLDSASignBatch` (C ABI:
|
||||
`lux_mldsa_verify_batch`, `lux_mldsa_sign_batch`). Stubs return
|
||||
LUX_NO_BACKEND when libluxaccel has no impl; Go-side callers (Pulsar)
|
||||
fall back to per-element CPU verify.
|
||||
- `LatticeNTTMLDSABatch` — in-place forward / inverse NTT over
|
||||
Z_q[X]/(X^256+1), q=8380417 (ML-DSA prime), batched across N polynomials.
|
||||
C ABI `lux_lattice_ntt_mldsa_batch`. CPU oracle in
|
||||
`ops/lattice/mldsa_ntt.go` is byte-equal to PQCLEAN_MLDSA65_CLEAN_ntt
|
||||
(the same body GPU plugins ship under lux-private/gpu-kernels/ops/
|
||||
lattice/ntt_mldsa/). `accel.MLDSABatchThreshold = 8` — below this the
|
||||
Go top-level dispatch returns ErrNotSupported so consumers route to
|
||||
the per-poly CPU path.
|
||||
|
||||
### DEX (`ops/dex`)
|
||||
- Constant product swaps
|
||||
@@ -220,6 +233,37 @@ go build -tags=accel ./...
|
||||
# Enables GPU implementations in ops/*
|
||||
```
|
||||
|
||||
### With lux_accel_real tag (link libluxaccel)
|
||||
|
||||
The capi layer at `internal/capi/` has TWO mutually-exclusive build
|
||||
files. Selector: `lux_accel_real`.
|
||||
|
||||
| Build | File compiled | C symbols resolved by |
|
||||
|---|---|---|
|
||||
| `go build ./...` (default) | `stub_default.go` | in-tree stub bodies returning `LUX_NO_BACKEND` |
|
||||
| `go build -tags lux_accel_real ./...` | `real.go` | `-lluxaccel` → `libluxaccel.{so,dylib}` |
|
||||
|
||||
```bash
|
||||
# Real build (Linux/CUDA, Spark GB10, etc.)
|
||||
CGO_LDFLAGS="-L/usr/local/lib -lluxaccel" \
|
||||
LD_LIBRARY_PATH=/usr/local/lib \
|
||||
go build -tags lux_accel_real ./...
|
||||
|
||||
# Real build (Apple Silicon / Metal)
|
||||
CGO_LDFLAGS="-L/opt/homebrew/lib -lluxaccel" \
|
||||
DYLD_LIBRARY_PATH=/opt/homebrew/lib \
|
||||
go build -tags lux_accel_real ./...
|
||||
```
|
||||
|
||||
The earlier scheme used `__attribute__((weak))` on every C stub to
|
||||
allow the loader to override at runtime via `LD_PRELOAD`. Modern
|
||||
linkers (with `--as-needed` default) resolve the references against
|
||||
the in-Go-object weak stubs and drop the `DT_NEEDED` for libluxaccel.
|
||||
Result: GPU paths silently ran on CPU. An audit on a Spark GB10
|
||||
host (2026-06-05) caught this — full ML-DSA bench ran at SM% 9-10%
|
||||
and 16 W. The build-tag flip is the fix: stub bodies and link
|
||||
directive can never both be in one build.
|
||||
|
||||
## Related
|
||||
|
||||
- `lux/gpu` - Low-level GPU array operations
|
||||
|
||||
+239
@@ -455,6 +455,245 @@ func DilithiumVerify(msg, sig, pk []byte) (bool, error) {
|
||||
return session.Lattice().DilithiumVerify(msgTensor.Untyped(), sigTensor.Untyped(), pkTensor.Untyped())
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
// ML-DSA (FIPS 204) batched operations
|
||||
// =============================================================================
|
||||
|
||||
// mldsaSizes returns (pk_bytes, sk_bytes, sig_bytes) for a FIPS 204 mode in
|
||||
// {MLDSAMode44, MLDSAMode65, MLDSAMode87}. Returns (0, 0, 0) for unknown modes.
|
||||
func mldsaSizes(mode int) (pk, sk, sig int) {
|
||||
switch mode {
|
||||
case MLDSAMode44:
|
||||
return MLDSA44PublicKeySize, MLDSA44SecretKeySize, MLDSA44SignatureSize
|
||||
case MLDSAMode65:
|
||||
return MLDSA65PublicKeySize, MLDSA65SecretKeySize, MLDSA65SignatureSize
|
||||
case MLDSAMode87:
|
||||
return MLDSA87PublicKeySize, MLDSA87SecretKeySize, MLDSA87SignatureSize
|
||||
default:
|
||||
return 0, 0, 0
|
||||
}
|
||||
}
|
||||
|
||||
// MLDSAVerifyBatch verifies n ML-DSA signatures at the given FIPS 204 mode
|
||||
// in {MLDSAMode44, MLDSAMode65, MLDSAMode87}. msgs, sigs, pks are flattened
|
||||
// byte slices in row-major order with the per-mode widths. results[i] is set
|
||||
// to true iff sigs[i] verifies under pks[i] for msgs[i]. The msgWidth
|
||||
// argument pins the per-message tensor stride (callers MUST pad to a fixed
|
||||
// width — the FIPS 204 verifier hashes the full padded width into mu).
|
||||
//
|
||||
// Returns ErrNotSupported when the GPU substrate or libluxaccel impl has
|
||||
// not yet shipped the operation — callers should fall through to the
|
||||
// per-element CPU verify path. Returns ErrBatchSizeMismatch on shape
|
||||
// mismatch, ErrInvalidArgument on unknown mode.
|
||||
func MLDSAVerifyBatch(mode int, msgs, sigs, pks [][]byte, msgWidth int) ([]bool, error) {
|
||||
n := len(msgs)
|
||||
if n == 0 || n != len(sigs) || n != len(pks) {
|
||||
return nil, ErrBatchSizeMismatch
|
||||
}
|
||||
pkSize, _, sigSize := mldsaSizes(mode)
|
||||
if pkSize == 0 {
|
||||
return nil, ErrInvalidArgument
|
||||
}
|
||||
if !Available() || n < MLDSABatchThreshold {
|
||||
return nil, ErrNotSupported
|
||||
}
|
||||
|
||||
session, err := DefaultSession()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
msgFlat, err := flattenFixed(msgs, msgWidth)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
sigFlat, err := flattenFixed(sigs, sigSize)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
pkFlat, err := flattenFixed(pks, pkSize)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
msgTensor, err := NewTensorWithData[uint8](session, []int{n, msgWidth}, msgFlat)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer msgTensor.Close()
|
||||
|
||||
sigTensor, err := NewTensorWithData[uint8](session, []int{n, sigSize}, sigFlat)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer sigTensor.Close()
|
||||
|
||||
pkTensor, err := NewTensorWithData[uint8](session, []int{n, pkSize}, pkFlat)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer pkTensor.Close()
|
||||
|
||||
resTensor, err := NewTensor[uint8](session, []int{n})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer resTensor.Close()
|
||||
|
||||
if err := session.Lattice().MLDSAVerifyBatch(mode, msgTensor.Untyped(), sigTensor.Untyped(), pkTensor.Untyped(), resTensor.Untyped()); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
raw, err := resTensor.ToSlice()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
out := make([]bool, n)
|
||||
for i, b := range raw {
|
||||
out[i] = b != 0
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
// MLDSASignBatch signs n messages with ML-DSA at the given FIPS 204 mode
|
||||
// in {MLDSAMode44, MLDSAMode65, MLDSAMode87}. msgs and sks are flattened
|
||||
// byte slices in row-major order; the returned [][]byte is one sig per
|
||||
// input.
|
||||
//
|
||||
// Returns ErrNotSupported when the substrate has not shipped the op.
|
||||
func MLDSASignBatch(mode int, msgs, sks [][]byte, msgWidth int) ([][]byte, error) {
|
||||
n := len(msgs)
|
||||
if n == 0 || n != len(sks) {
|
||||
return nil, ErrBatchSizeMismatch
|
||||
}
|
||||
_, skSize, sigSize := mldsaSizes(mode)
|
||||
if skSize == 0 {
|
||||
return nil, ErrInvalidArgument
|
||||
}
|
||||
if !Available() || n < MLDSABatchThreshold {
|
||||
return nil, ErrNotSupported
|
||||
}
|
||||
|
||||
session, err := DefaultSession()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
msgFlat, err := flattenFixed(msgs, msgWidth)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
skFlat, err := flattenFixed(sks, skSize)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
msgTensor, err := NewTensorWithData[uint8](session, []int{n, msgWidth}, msgFlat)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer msgTensor.Close()
|
||||
|
||||
skTensor, err := NewTensorWithData[uint8](session, []int{n, skSize}, skFlat)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer skTensor.Close()
|
||||
|
||||
sigTensor, err := NewTensor[uint8](session, []int{n, sigSize})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer sigTensor.Close()
|
||||
|
||||
if err := session.Lattice().MLDSASignBatch(mode, msgTensor.Untyped(), skTensor.Untyped(), sigTensor.Untyped()); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
flat, err := sigTensor.ToSlice()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
out := make([][]byte, n)
|
||||
for i := 0; i < n; i++ {
|
||||
sig := make([]byte, sigSize)
|
||||
copy(sig, flat[i*sigSize:(i+1)*sigSize])
|
||||
out[i] = sig
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
// LatticeNTTMLDSABatch performs the in-place forward (inverse=false) or
|
||||
// inverse (inverse=true) Number-Theoretic Transform over Z_q[X]/(X^256 + 1)
|
||||
// with q = 8380417 (the FIPS 204 ML-DSA prime), batched across n=len(polys)
|
||||
// polynomials. Each polys[i] MUST have length MLDSANTTPolyLen (256). The
|
||||
// transform writes back into the input slice.
|
||||
//
|
||||
// Byte-equal to PQCLEAN_MLDSA65_CLEAN_ntt (forward). The dispatcher
|
||||
// engages the GPU substrate only when len(polys) >= MLDSABatchThreshold
|
||||
// (default 8); below threshold ErrNotSupported is returned so callers
|
||||
// route to the per-poly CPU oracle.
|
||||
func LatticeNTTMLDSABatch(polys [][]int32, inverse bool) error {
|
||||
n := len(polys)
|
||||
if n == 0 {
|
||||
return ErrBatchSizeMismatch
|
||||
}
|
||||
for i, p := range polys {
|
||||
if len(p) != MLDSANTTPolyLen {
|
||||
_ = i
|
||||
return ErrShapeMismatch
|
||||
}
|
||||
}
|
||||
if !Available() || n < MLDSABatchThreshold {
|
||||
return ErrNotSupported
|
||||
}
|
||||
|
||||
session, err := DefaultSession()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Flatten into a single [n*256]int32 backing buffer; cgo will see
|
||||
// the contiguous bytes once it lands on the C side. We read back
|
||||
// via ToSlice() into the same flat buffer, then deinterleave.
|
||||
flat := make([]int32, n*MLDSANTTPolyLen)
|
||||
for i, p := range polys {
|
||||
copy(flat[i*MLDSANTTPolyLen:(i+1)*MLDSANTTPolyLen], p)
|
||||
}
|
||||
|
||||
tensor, err := NewTensorWithData[int32](session, []int{n, MLDSANTTPolyLen}, flat)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer tensor.Close()
|
||||
|
||||
if err := session.Lattice().LatticeNTTMLDSABatch(tensor.Untyped(), inverse); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
out, err := tensor.ToSlice()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for i := 0; i < n; i++ {
|
||||
copy(polys[i], out[i*MLDSANTTPolyLen:(i+1)*MLDSANTTPolyLen])
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// flattenFixed concatenates a [][]byte where every row MUST be exactly
|
||||
// `width` bytes. Returns ErrShapeMismatch on any width violation.
|
||||
func flattenFixed(rows [][]byte, width int) ([]byte, error) {
|
||||
out := make([]byte, len(rows)*width)
|
||||
for i, r := range rows {
|
||||
if len(r) != width {
|
||||
return nil, ErrShapeMismatch
|
||||
}
|
||||
copy(out[i*width:(i+1)*width], r)
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
// ZK Operations (NTT, MSM)
|
||||
// =============================================================================
|
||||
|
||||
+1
-1
@@ -8,7 +8,7 @@
|
||||
// package; it CGO-routes to the lux_crypto_<alg> static libraries.
|
||||
//
|
||||
// Phase 1: secp256k1 (ecrecover, address derivation). Future phases add
|
||||
// bls12381, mldsa, mlkem, slhdsa, corona, frost, cggmp21, sha256,
|
||||
// bls12381, mldsa, mlkem, slhdsa, ringtail, frost, cggmp21, sha256,
|
||||
// blake2b, blake3, kzg, hpke, ipa, lamport, ecies, etc.
|
||||
//
|
||||
// Build matrix:
|
||||
|
||||
+2
-2
@@ -65,8 +65,8 @@ func CryptoSecp256k1Ecrecover(hash, r, s []byte, v byte) ([]byte, error) {
|
||||
// (hash || r || s || v_byte) tuples, 97 bytes each.
|
||||
//
|
||||
// Returns:
|
||||
// * pubkeys: n*64 bytes, recovered uncompressed public keys
|
||||
// * statuses: n bytes, 0 on success, nonzero error code per tuple
|
||||
// - pubkeys: n*64 bytes, recovered uncompressed public keys
|
||||
// - statuses: n bytes, 0 on success, nonzero error code per tuple
|
||||
func CryptoSecp256k1EcrecoverBatch(inputs []byte) (pubkeys, statuses []byte, err error) {
|
||||
if len(inputs) == 0 {
|
||||
return nil, nil, nil
|
||||
|
||||
+27
@@ -85,3 +85,30 @@ func NTTInverse(_, _ []uint64, _ uint64) error {
|
||||
func MSM(_, _ [][]byte) ([]byte, error) {
|
||||
return nil, ErrNotSupported
|
||||
}
|
||||
|
||||
// MLDSAVerifyBatch returns ErrNotSupported in non-CGO builds.
|
||||
func MLDSAVerifyBatch(_ int, _, _, _ [][]byte, _ int) ([]bool, error) {
|
||||
return nil, ErrNotSupported
|
||||
}
|
||||
|
||||
// MLDSASignBatch returns ErrNotSupported in non-CGO builds.
|
||||
func MLDSASignBatch(_ int, _, _ [][]byte, _ int) ([][]byte, error) {
|
||||
return nil, ErrNotSupported
|
||||
}
|
||||
|
||||
// LatticeNTTMLDSABatch returns ErrNotSupported in non-CGO builds.
|
||||
func LatticeNTTMLDSABatch(polys [][]int32, _ bool) error {
|
||||
// Validate the batch shape before the (absent) GPU dispatch decision,
|
||||
// matching the cgo path so callers get the same error regardless of
|
||||
// build: a wrong-length poly is ErrShapeMismatch, empty is
|
||||
// ErrBatchSizeMismatch; otherwise no backend → ErrNotSupported.
|
||||
if len(polys) == 0 {
|
||||
return ErrBatchSizeMismatch
|
||||
}
|
||||
for _, p := range polys {
|
||||
if len(p) != MLDSANTTPolyLen {
|
||||
return ErrShapeMismatch
|
||||
}
|
||||
}
|
||||
return ErrNotSupported
|
||||
}
|
||||
|
||||
+33
-1
@@ -21,13 +21,45 @@ const (
|
||||
KyberSharedKeySize = 32
|
||||
)
|
||||
|
||||
// Dilithium sizes (ML-DSA-65)
|
||||
// Dilithium sizes (ML-DSA-65). The DilithiumSecretKeySize=4016 constant
|
||||
// predates the FIPS 204 final fix that pinned the ML-DSA-65 secret key
|
||||
// at 4032 bytes; new code should prefer the MLDSA* sizes below.
|
||||
const (
|
||||
DilithiumPublicKeySize = 1952
|
||||
DilithiumSecretKeySize = 4016
|
||||
DilithiumSignatureSize = 3309
|
||||
)
|
||||
|
||||
// ML-DSA / FIPS 204 sizes per NIST level. Mode encoding matches the
|
||||
// luxcpp/crypto/mldsa C ABI: 2 = ML-DSA-44, 3 = ML-DSA-65, 5 = ML-DSA-87.
|
||||
const (
|
||||
// Mode IDs.
|
||||
MLDSAMode44 = 2
|
||||
MLDSAMode65 = 3
|
||||
MLDSAMode87 = 5
|
||||
|
||||
// Per-mode tensor widths (FIPS 204).
|
||||
MLDSA44PublicKeySize = 1312
|
||||
MLDSA44SecretKeySize = 2560
|
||||
MLDSA44SignatureSize = 2420
|
||||
|
||||
MLDSA65PublicKeySize = 1952
|
||||
MLDSA65SecretKeySize = 4032
|
||||
MLDSA65SignatureSize = 3309
|
||||
|
||||
MLDSA87PublicKeySize = 2592
|
||||
MLDSA87SecretKeySize = 4896
|
||||
MLDSA87SignatureSize = 4627
|
||||
|
||||
// ML-DSA NTT poly width (FIPS 204 fixed at N = 256).
|
||||
MLDSANTTPolyLen = 256
|
||||
|
||||
// MLDSABatchThreshold: minimum batch size at which the GPU
|
||||
// dispatch path is engaged. Below this, callers should fall
|
||||
// through to the per-element CPU oracle to amortise launch cost.
|
||||
MLDSABatchThreshold = 8
|
||||
)
|
||||
|
||||
var (
|
||||
// ErrNoBackends indicates no GPU backends are available.
|
||||
ErrNoBackends = errors.New("accel: no GPU backends available")
|
||||
|
||||
+47
-24
@@ -14,15 +14,21 @@
|
||||
package capi
|
||||
|
||||
/*
|
||||
// System and homebrew paths for headers
|
||||
#cgo CFLAGS: -I/usr/local/include -I/opt/homebrew/include -I${SRCDIR}/../../include
|
||||
|
||||
// Fallback to vendored header shipped with this module — works in any
|
||||
// fresh-clone / CI environment without luxcpp pre-installed. The vendored
|
||||
// header declares the C ABI; the stub.go file provides weak symbols so
|
||||
// builds succeed even when libluxaccel is not linked.
|
||||
// Header search order — VENDORED FIRST.
|
||||
//
|
||||
// The vendored c_api.h shipped under ${SRCDIR}/include is the single
|
||||
// source of truth for the C ABI. Putting it first guarantees that every
|
||||
// declaration (including ones added since the last luxcpp install) is
|
||||
// visible to cgo regardless of what version of the public luxcpp header
|
||||
// is sitting in /usr/local/include or /opt/homebrew/include. The stub.go
|
||||
// file provides matching weak symbols so builds succeed even when
|
||||
// libluxaccel is not linked.
|
||||
#cgo CFLAGS: -I${SRCDIR}/include
|
||||
|
||||
// Optional installed headers (older snapshots are tolerated — they
|
||||
// supply nothing the vendored header doesn't already declare).
|
||||
#cgo CFLAGS: -I/usr/local/include -I/opt/homebrew/include -I${SRCDIR}/../../include
|
||||
|
||||
// Fallback to local luxcpp install (relative to this file)
|
||||
#cgo CFLAGS: -I${SRCDIR}/../../../../luxcpp/install/include
|
||||
|
||||
@@ -505,29 +511,46 @@ func SLHDSAVerifyBatch(session *Session, mode int, msgs, sigs, pks, results *Ten
|
||||
// The results tensor is populated with one uint8 per signature (1 = valid,
|
||||
// 0 = invalid).
|
||||
//
|
||||
// Until the lux-accel C-API exposes lux_mldsa_verify_batch (in development),
|
||||
// this returns ErrNotSupported so the Go-side dispatcher falls back to its
|
||||
// per-element verify path. The function is wired here so consumers can call
|
||||
// it before the substrate ships without breaking the build.
|
||||
// The C ABI symbol `lux_mldsa_verify_batch` is declared in c_api.h and
|
||||
// resolved at link time. When libluxaccel ships an implementation it
|
||||
// runs FIPS 204 batched verify on the active backend; when no native
|
||||
// library is linked the weak-symbol stub in stub.go returns
|
||||
// LUX_NO_BACKEND, which surfaces here as ErrNoBackends. Either way,
|
||||
// callers see the Go-level error and can fall through to the per-
|
||||
// element CPU verify path — the substrate boundary is the wire, not a
|
||||
// stub.
|
||||
func MLDSAVerifyBatch(session *Session, mode int, msgs, sigs, pks, results *Tensor) error {
|
||||
_ = session
|
||||
_ = mode
|
||||
_ = msgs
|
||||
_ = sigs
|
||||
_ = pks
|
||||
_ = results
|
||||
return ErrNotSupported
|
||||
status := C.lux_mldsa_verify_batch(session.handle, C.int(mode), msgs.handle, sigs.handle, pks.handle, results.handle)
|
||||
return statusToError(status)
|
||||
}
|
||||
|
||||
// MLDSASignBatch batch-signs ML-DSA / Dilithium (FIPS 204) messages.
|
||||
// mode as for MLDSAVerifyBatch. See doc on MLDSAVerifyBatch for ABI status.
|
||||
func MLDSASignBatch(session *Session, mode int, msgs, sks, sigs *Tensor) error {
|
||||
_ = session
|
||||
_ = mode
|
||||
_ = msgs
|
||||
_ = sks
|
||||
_ = sigs
|
||||
return ErrNotSupported
|
||||
status := C.lux_mldsa_sign_batch(session.handle, C.int(mode), msgs.handle, sks.handle, sigs.handle)
|
||||
return statusToError(status)
|
||||
}
|
||||
|
||||
// LatticeNTTMLDSABatch performs the in-place forward (inverse=false) or
|
||||
// inverse (inverse=true) Number-Theoretic Transform over Z_q[X]/(X^256 + 1)
|
||||
// with q = 8380417 (the ML-DSA prime), batched across n polynomials.
|
||||
//
|
||||
// The polys tensor MUST be LUX_DTYPE_I32 with shape [n, 256]; the transform
|
||||
// is in-place. Byte-equal to PQCLEAN_MLDSA65_CLEAN_ntt for the forward
|
||||
// direction; the inverse direction (when implemented by the backend) is
|
||||
// the matching PQCLEAN_MLDSA65_CLEAN_invntt_tomont.
|
||||
//
|
||||
// When libluxaccel has not linked an implementation, the weak stub
|
||||
// returns LUX_NO_BACKEND which surfaces as ErrNoBackends — callers
|
||||
// then route to their per-poly CPU NTT (Pulsar does this via the
|
||||
// luxfi/lattice/v7 dispatcher).
|
||||
func LatticeNTTMLDSABatch(session *Session, polys *Tensor, inverse bool) error {
|
||||
var inv C.int
|
||||
if inverse {
|
||||
inv = 1
|
||||
}
|
||||
status := C.lux_lattice_ntt_mldsa_batch(session.handle, polys.handle, inv)
|
||||
return statusToError(status)
|
||||
}
|
||||
|
||||
// FHE operations
|
||||
|
||||
-28
@@ -1,28 +0,0 @@
|
||||
//go:build cgo && accel_native && darwin
|
||||
|
||||
// Package capi — opt-in native-library link directives.
|
||||
//
|
||||
// Default builds resolve every C symbol against the weak stubs in
|
||||
// stub.go, which keeps the binary buildable on hosts where libluxaccel
|
||||
// is not installed. Building with `-tags=accel_native` switches the
|
||||
// link to the real libluxaccel, at which point the weak stubs are
|
||||
// overridden and accel.Available() reflects the real backend count
|
||||
// (Metal on Apple Silicon, CUDA on Linux/NVIDIA).
|
||||
//
|
||||
// Required host install:
|
||||
// /opt/homebrew/lib/libluxaccel.dylib (or /usr/local/lib on Intel)
|
||||
// Plus a Metal plugin at one of:
|
||||
// /opt/homebrew/lib/lux/plugins/lux_metal.plugin
|
||||
// ~/.lux/plugins/lux_metal.plugin
|
||||
// $LUX_PLUGIN_PATH/lux_metal.plugin
|
||||
//
|
||||
// libluxaccel is self-contained: it does not require linking against
|
||||
// libluxgpu or libluxcrypto at the Go consumer site. The luxcpp build
|
||||
// links those statically into libluxaccel before install.
|
||||
|
||||
package capi
|
||||
|
||||
/*
|
||||
#cgo darwin LDFLAGS: -lluxaccel
|
||||
*/
|
||||
import "C"
|
||||
-18
@@ -1,18 +0,0 @@
|
||||
//go:build cgo && accel_native && linux
|
||||
|
||||
// Package capi — opt-in native-library link directives (Linux).
|
||||
// See capi_native_darwin.go for the policy. Required host install:
|
||||
// /usr/local/lib/libluxaccel.so
|
||||
// Plus a CUDA plugin under the configured LUX_PLUGIN_PATH.
|
||||
//
|
||||
// libluxaccel.so is self-contained: it does not require linking
|
||||
// against libluxgpu or libluxcrypto at the Go consumer site. The
|
||||
// luxcpp build links those statically into libluxaccel.so before
|
||||
// install.
|
||||
|
||||
package capi
|
||||
|
||||
/*
|
||||
#cgo linux LDFLAGS: -lluxaccel
|
||||
*/
|
||||
import "C"
|
||||
+73
@@ -241,6 +241,79 @@ LUX_API lux_status lux_dilithium_sign(lux_session session, lux_tensor msg,
|
||||
LUX_API lux_status lux_dilithium_verify(lux_session session, lux_tensor msg,
|
||||
lux_tensor sig, lux_tensor pk, int* valid);
|
||||
|
||||
// =============================================================================
|
||||
// ML-DSA / Dilithium (FIPS 204) operations
|
||||
// =============================================================================
|
||||
//
|
||||
// ML-DSA is a module-lattice signature scheme (FIPS 204, formerly Dilithium).
|
||||
// The mode encoding follows the luxcpp/crypto/mldsa C ABI:
|
||||
// 2 -> ML-DSA-44 (NIST L2)
|
||||
// 3 -> ML-DSA-65 (NIST L3) <-- canonical for Pulsar threshold profile
|
||||
// 5 -> ML-DSA-87 (NIST L5)
|
||||
//
|
||||
// Per FIPS 204, key / signature widths per mode:
|
||||
// ML-DSA-44 : pk=1312 sk=2560 sig=2420
|
||||
// ML-DSA-65 : pk=1952 sk=4032 sig=3309
|
||||
// ML-DSA-87 : pk=2592 sk=4896 sig=4627
|
||||
//
|
||||
// Tensor shapes (n = batch size):
|
||||
// msgs : LUX_DTYPE_U8, shape [n, msg_width]
|
||||
// sigs : LUX_DTYPE_U8, shape [n, sig_bytes]
|
||||
// sks : LUX_DTYPE_U8, shape [n, sk_bytes]
|
||||
// pks : LUX_DTYPE_U8, shape [n, pk_bytes]
|
||||
// results : LUX_DTYPE_U8, shape [n] (1 = valid, 0 = invalid)
|
||||
//
|
||||
// Verify is deterministic per FIPS 204: GPU and CPU paths produce byte-
|
||||
// identical accept/reject decisions per element. The results vector is dense
|
||||
// (no early abort) so callers can audit per-signer failures.
|
||||
//
|
||||
// Sign in hedged mode is deterministic when the deterministic flag is set
|
||||
// at the caller boundary; the per-mode implementation MUST select the same
|
||||
// hedging mode as the caller-side CPU reference (PQClean ML-DSA-{44,65,87})
|
||||
// to remain byte-equal for KAT.
|
||||
//
|
||||
// Until the libluxaccel implementation links these symbols against the
|
||||
// PQClean reference (or the per-backend GPU plugin registers a strong
|
||||
// override), the weak-symbol stubs in `internal/capi/stub.go` return
|
||||
// LUX_NO_BACKEND. The Go-side dispatcher (LatticeOps.MLDSAVerifyBatch /
|
||||
// MLDSASignBatch) then falls back to its per-element CPU verify path,
|
||||
// which is byte-equivalent by construction (same FIPS 204 spec, same
|
||||
// NIST KATs pass on both sides).
|
||||
|
||||
LUX_API lux_status lux_mldsa_sign_batch(lux_session session, int mode,
|
||||
lux_tensor msgs, lux_tensor sks,
|
||||
lux_tensor sigs);
|
||||
LUX_API lux_status lux_mldsa_verify_batch(lux_session session, int mode,
|
||||
lux_tensor msgs, lux_tensor sigs,
|
||||
lux_tensor pks, lux_tensor results);
|
||||
|
||||
// =============================================================================
|
||||
// Lattice NTT batched primitives (FIPS 204 ML-DSA-65 forward / inverse)
|
||||
// =============================================================================
|
||||
//
|
||||
// `lux_lattice_ntt_mldsa_batch` performs the in-place forward Number-Theoretic
|
||||
// Transform over Z_q[X]/(X^256 + 1) with q = 8380417 (the ML-DSA prime),
|
||||
// batched across `n` polynomials. Byte-equal to PQCLEAN_MLDSA65_CLEAN_ntt
|
||||
// (Cooley-Tukey butterflies in Montgomery domain, 8 levels, 256-entry zeta
|
||||
// table shared across all backends — see lux-private/gpu-kernels/ops/lattice/
|
||||
// ntt_mldsa/op.yaml).
|
||||
//
|
||||
// Pulsar's Round-2 dispatches 22 forward NTTs per party-attempt, which fits
|
||||
// the `batch ≥ 8` GPU-dispatch threshold cleanly. Below that threshold the
|
||||
// Go-side dispatcher MUST route to its per-poly CPU path to amortise the
|
||||
// kernel-launch cost (see `ops/lattice/lattice.go` for the threshold logic).
|
||||
//
|
||||
// Tensor shape:
|
||||
// polys : LUX_DTYPE_I32, shape [n, 256] — in-place forward NTT
|
||||
//
|
||||
// `inverse` selects forward (0) vs inverse (non-zero) NTT. The forward path
|
||||
// is the load-bearing one for Pulsar; the inverse path is exposed for
|
||||
// symmetric polymul use-cases.
|
||||
|
||||
LUX_API lux_status lux_lattice_ntt_mldsa_batch(lux_session session,
|
||||
lux_tensor polys,
|
||||
int inverse);
|
||||
|
||||
// =============================================================================
|
||||
// SLH-DSA / Magnetar (FIPS 205) operations
|
||||
// =============================================================================
|
||||
|
||||
+43
@@ -0,0 +1,43 @@
|
||||
//go:build cgo && lux_accel_real
|
||||
|
||||
// Package capi real-build link directives.
|
||||
//
|
||||
// One and only one of `stub_default.go` or `real.go` is in any given
|
||||
// build. The selector is the `lux_accel_real` build tag — see the
|
||||
// header comment on stub_default.go for the design rationale.
|
||||
//
|
||||
// This file holds exactly two things:
|
||||
//
|
||||
// 1. `#cgo LDFLAGS: -lluxaccel` — link the binary against the real
|
||||
// native library. Combined with the `-L` search paths and rpaths
|
||||
// already declared in capi.go, the dynamic loader finds
|
||||
// libluxaccel.{so,dylib} at one of:
|
||||
//
|
||||
// /usr/local/lib (canonical Linux install)
|
||||
// /opt/homebrew/lib (Apple Silicon Homebrew)
|
||||
// ${SRCDIR}/../../../../luxcpp/install/lib (local checkout)
|
||||
//
|
||||
// 2. `#include <lux/accel/c_api.h>` — declares every `lux_*` entry
|
||||
// point as a normal (non-weak) extern. capi.go calls these from
|
||||
// Go via cgo wrappers; under this build tag the wrappers resolve
|
||||
// directly to libluxaccel's strong definitions, with no stub
|
||||
// bodies anywhere in the binary.
|
||||
//
|
||||
// Required host install (verified at boot via accel.Available()):
|
||||
//
|
||||
// Linux : /usr/local/lib/libluxaccel.so.0.1.2 (plus CUDA plugin
|
||||
// under $LUX_PLUGIN_PATH or /usr/local/lib/lux/plugins/)
|
||||
// Darwin : /opt/homebrew/lib/libluxaccel.dylib (plus Metal plugin
|
||||
// under /opt/homebrew/lib/lux/plugins/ or ~/.lux/plugins/)
|
||||
//
|
||||
// libluxaccel is self-contained: it links libluxgpu + libluxcrypto
|
||||
// statically at build time inside luxcpp. Go consumers only need
|
||||
// `-lluxaccel`.
|
||||
package capi
|
||||
|
||||
/*
|
||||
#cgo LDFLAGS: -lluxaccel
|
||||
|
||||
#include <lux/accel/c_api.h>
|
||||
*/
|
||||
import "C"
|
||||
-100
@@ -1,100 +0,0 @@
|
||||
//go:build cgo && !accel_native
|
||||
|
||||
// Package capi stub implementations.
|
||||
// When the real libluxaccel is not installed, these weak-symbol C functions
|
||||
// provide default implementations that return LUX_NO_BACKEND so the build
|
||||
// succeeds without the native library.
|
||||
//
|
||||
// The accel_native build tag REMOVES this file from the build. That makes
|
||||
// every C symbol referenced by capi.go unresolved, which forces the linker
|
||||
// to pull in libluxaccel from -lluxaccel (the directive in
|
||||
// capi_native_{linux,darwin}.go). Without this gating, modern linkers
|
||||
// (with --as-needed default) see the weak stubs resolve the symbols and
|
||||
// drop libluxaccel from the binary's DT_NEEDED — at which point
|
||||
// accel.Init() returns "no backends" because the real plugin-discovery
|
||||
// code never runs.
|
||||
package capi
|
||||
|
||||
/*
|
||||
#include <lux/accel/c_api.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
// Weak-symbol stubs: overridden by real libluxaccel when linked.
|
||||
|
||||
__attribute__((weak)) const char* lux_version(void) { return "stub-0.0.0"; }
|
||||
__attribute__((weak)) const char* lux_get_error(void) { return "no accel library"; }
|
||||
|
||||
__attribute__((weak)) lux_status lux_init(void) { return LUX_NO_BACKEND; }
|
||||
__attribute__((weak)) void lux_shutdown(void) {}
|
||||
|
||||
__attribute__((weak)) lux_status lux_load_backend(const char* p) { return LUX_NO_BACKEND; }
|
||||
__attribute__((weak)) int lux_backend_count(void) { return 0; }
|
||||
__attribute__((weak)) lux_backend_type lux_backend_type_at(int i) { return 0; }
|
||||
__attribute__((weak)) int lux_device_count(lux_backend_type b) { return 0; }
|
||||
__attribute__((weak)) lux_status lux_get_device_info(lux_backend_type b, int i, lux_device_info* o) {
|
||||
if (o) memset(o, 0, sizeof(*o));
|
||||
return LUX_NO_BACKEND;
|
||||
}
|
||||
|
||||
__attribute__((weak)) lux_status lux_session_create(lux_session* s) { if(s)*s=NULL; return LUX_NO_BACKEND; }
|
||||
__attribute__((weak)) lux_status lux_session_create_with_backend(lux_backend_type b, lux_session* s) { if(s)*s=NULL; return LUX_NO_BACKEND; }
|
||||
__attribute__((weak)) lux_status lux_session_create_with_device(lux_backend_type b, int d, lux_session* s) { if(s)*s=NULL; return LUX_NO_BACKEND; }
|
||||
__attribute__((weak)) void lux_session_destroy(lux_session s) {}
|
||||
__attribute__((weak)) lux_status lux_session_sync(lux_session s) { return LUX_NO_BACKEND; }
|
||||
|
||||
__attribute__((weak)) lux_status lux_tensor_create(lux_session s, lux_dtype d, const size_t* sh, size_t nd, lux_tensor* t) { if(t)*t=NULL; return LUX_NO_BACKEND; }
|
||||
__attribute__((weak)) lux_status lux_tensor_create_with_data(lux_session s, lux_dtype d, const size_t* sh, size_t nd, const void* data, size_t len, lux_tensor* t) { if(t)*t=NULL; return LUX_NO_BACKEND; }
|
||||
__attribute__((weak)) void lux_tensor_destroy(lux_tensor t) {}
|
||||
__attribute__((weak)) size_t lux_tensor_ndim(lux_tensor t) { return 0; }
|
||||
__attribute__((weak)) size_t lux_tensor_shape(lux_tensor t, size_t d) { return 0; }
|
||||
__attribute__((weak)) size_t lux_tensor_numel(lux_tensor t) { return 0; }
|
||||
__attribute__((weak)) size_t lux_tensor_bytes(lux_tensor t) { return 0; }
|
||||
__attribute__((weak)) lux_dtype lux_tensor_dtype(lux_tensor t) { return 0; }
|
||||
__attribute__((weak)) lux_status lux_tensor_to_host(lux_tensor t, void* d, size_t n) { return LUX_NO_BACKEND; }
|
||||
__attribute__((weak)) lux_status lux_tensor_from_host(lux_tensor t, const void* d, size_t n) { return LUX_NO_BACKEND; }
|
||||
|
||||
// ML ops
|
||||
__attribute__((weak)) lux_status lux_matmul(lux_session s, lux_tensor a, lux_tensor b, lux_tensor c) { return LUX_NO_BACKEND; }
|
||||
__attribute__((weak)) lux_status lux_relu(lux_session s, lux_tensor i, lux_tensor o) { return LUX_NO_BACKEND; }
|
||||
__attribute__((weak)) lux_status lux_gelu(lux_session s, lux_tensor i, lux_tensor o) { return LUX_NO_BACKEND; }
|
||||
__attribute__((weak)) lux_status lux_softmax(lux_session s, lux_tensor i, lux_tensor o, int ax) { return LUX_NO_BACKEND; }
|
||||
__attribute__((weak)) lux_status lux_layer_norm(lux_session s, lux_tensor i, lux_tensor g, lux_tensor b, lux_tensor o, float e) { return LUX_NO_BACKEND; }
|
||||
__attribute__((weak)) lux_status lux_attention(lux_session s, lux_tensor q, lux_tensor k, lux_tensor v, lux_tensor o, float sc) { return LUX_NO_BACKEND; }
|
||||
|
||||
// Crypto ops
|
||||
__attribute__((weak)) lux_status lux_sha256(lux_session s, lux_tensor i, lux_tensor o) { return LUX_NO_BACKEND; }
|
||||
__attribute__((weak)) lux_status lux_keccak256(lux_session s, lux_tensor i, lux_tensor o) { return LUX_NO_BACKEND; }
|
||||
__attribute__((weak)) lux_status lux_poseidon(lux_session s, lux_tensor i, lux_tensor o) { return LUX_NO_BACKEND; }
|
||||
__attribute__((weak)) lux_status lux_ecdsa_verify_batch(lux_session s, lux_tensor m, lux_tensor sg, lux_tensor pk, lux_tensor r) { return LUX_NO_BACKEND; }
|
||||
__attribute__((weak)) lux_status lux_ed25519_verify_batch(lux_session s, lux_tensor m, lux_tensor sg, lux_tensor pk, lux_tensor r) { return LUX_NO_BACKEND; }
|
||||
__attribute__((weak)) lux_status lux_bls_verify_batch(lux_session s, lux_tensor m, lux_tensor sg, lux_tensor pk, lux_tensor r) { return LUX_NO_BACKEND; }
|
||||
__attribute__((weak)) lux_status lux_merkle_root(lux_session s, lux_tensor l, lux_tensor r) { return LUX_NO_BACKEND; }
|
||||
|
||||
// ZK ops
|
||||
__attribute__((weak)) lux_status lux_ntt(lux_session s, lux_tensor i, lux_tensor o, lux_tensor rt, uint64_t m) { return LUX_NO_BACKEND; }
|
||||
__attribute__((weak)) lux_status lux_intt(lux_session s, lux_tensor i, lux_tensor o, lux_tensor ir, uint64_t m) { return LUX_NO_BACKEND; }
|
||||
__attribute__((weak)) lux_status lux_msm(lux_session s, lux_tensor sc, lux_tensor ba, lux_tensor r) { return LUX_NO_BACKEND; }
|
||||
__attribute__((weak)) lux_status lux_poly_mul(lux_session s, lux_tensor a, lux_tensor b, lux_tensor c, uint64_t m) { return LUX_NO_BACKEND; }
|
||||
|
||||
// Lattice/PQC ops
|
||||
__attribute__((weak)) lux_status lux_kyber_keygen(lux_session s, lux_tensor pk, lux_tensor sk) { return LUX_NO_BACKEND; }
|
||||
__attribute__((weak)) lux_status lux_kyber_encaps(lux_session s, lux_tensor pk, lux_tensor ct, lux_tensor ss) { return LUX_NO_BACKEND; }
|
||||
__attribute__((weak)) lux_status lux_kyber_decaps(lux_session s, lux_tensor ct, lux_tensor sk, lux_tensor ss) { return LUX_NO_BACKEND; }
|
||||
__attribute__((weak)) lux_status lux_dilithium_sign(lux_session s, lux_tensor m, lux_tensor sk, lux_tensor sg) { return LUX_NO_BACKEND; }
|
||||
__attribute__((weak)) lux_status lux_dilithium_verify(lux_session s, lux_tensor m, lux_tensor sg, lux_tensor pk, int* v) { if(v)*v=0; return LUX_NO_BACKEND; }
|
||||
__attribute__((weak)) lux_status lux_slhdsa_sign_batch(lux_session s, int mode, lux_tensor m, lux_tensor sk, lux_tensor sg) { return LUX_NO_BACKEND; }
|
||||
__attribute__((weak)) lux_status lux_slhdsa_verify_batch(lux_session s, int mode, lux_tensor m, lux_tensor sg, lux_tensor pk, lux_tensor r) { return LUX_NO_BACKEND; }
|
||||
|
||||
// FHE ops
|
||||
__attribute__((weak)) lux_status lux_bfv_encrypt(lux_session s, lux_tensor p, lux_tensor pk, lux_tensor c) { return LUX_NO_BACKEND; }
|
||||
__attribute__((weak)) lux_status lux_bfv_decrypt(lux_session s, lux_tensor c, lux_tensor sk, lux_tensor p) { return LUX_NO_BACKEND; }
|
||||
__attribute__((weak)) lux_status lux_bfv_add(lux_session s, lux_tensor a, lux_tensor b, lux_tensor r) { return LUX_NO_BACKEND; }
|
||||
__attribute__((weak)) lux_status lux_bfv_multiply(lux_session s, lux_tensor a, lux_tensor b, lux_tensor rk, lux_tensor r) { return LUX_NO_BACKEND; }
|
||||
|
||||
// DEX ops
|
||||
__attribute__((weak)) lux_status lux_constant_product_swap(lux_session s, lux_tensor rx, lux_tensor ry, lux_tensor ai, int d, lux_tensor ao, float f) { return LUX_NO_BACKEND; }
|
||||
__attribute__((weak)) lux_status lux_compute_twap(lux_session s, lux_tensor p, lux_tensor ts, uint64_t st, uint64_t en, lux_tensor tw) { return LUX_NO_BACKEND; }
|
||||
__attribute__((weak)) lux_status lux_match_orders(lux_session s, lux_tensor bi, lux_tensor ak, lux_tensor mt, lux_tensor pr, lux_tensor am) { return LUX_NO_BACKEND; }
|
||||
*/
|
||||
import "C"
|
||||
+126
@@ -0,0 +1,126 @@
|
||||
//go:build cgo && !lux_accel_real
|
||||
|
||||
// Package capi default-build stub implementations.
|
||||
//
|
||||
// One and only one of `stub_default.go` or `real.go` is in any given
|
||||
// build. The selector is the `lux_accel_real` build tag:
|
||||
//
|
||||
// go build ./... # this file is compiled,
|
||||
// # every C entry returns
|
||||
// # LUX_NO_BACKEND. Portable
|
||||
// # CPU-only binary.
|
||||
//
|
||||
// go build -tags lux_accel_real ./... # real.go is compiled instead,
|
||||
// # binary links -lluxaccel and
|
||||
// # dispatches to the native
|
||||
// # CUDA / Metal plugin.
|
||||
//
|
||||
// History: an earlier revision used `__attribute__((weak))` on every
|
||||
// stub and tried to override at link time when libluxaccel was present.
|
||||
// Modern linkers with --as-needed default resolved the references
|
||||
// against the weak stubs (already in the Go object) and dropped the
|
||||
// DT_NEEDED entry for libluxaccel entirely. Result: GPU paths silently
|
||||
// ran on CPU. Audit on a Spark GB10 host (2026-06-05) measured 9-10%
|
||||
// SM during a full ML-DSA bench that was supposed to be GPU-accelerated.
|
||||
// The build-tag split removes the weak-symbol ambiguity: either the
|
||||
// stub bodies compile, or the link to the real library does — never
|
||||
// both.
|
||||
//
|
||||
// All stubs return LUX_NO_BACKEND. The Go-side ops dispatcher (see
|
||||
// `crypto/backend.Resolve` in luxfi/crypto and `ops/lattice/lattice.go`
|
||||
// in this module) maps LUX_NO_BACKEND to a per-element CPU fallback,
|
||||
// so default-tag binaries remain functionally complete — just slower.
|
||||
package capi
|
||||
|
||||
/*
|
||||
#include <lux/accel/c_api.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
static const char* _stub_version(void) { return "stub-0.0.0"; }
|
||||
static const char* _stub_error(void) { return "no accel library (built without -tags lux_accel_real)"; }
|
||||
|
||||
lux_status lux_init(void) { return LUX_NO_BACKEND; }
|
||||
void lux_shutdown(void) {}
|
||||
const char* lux_version(void) { return _stub_version(); }
|
||||
const char* lux_get_error(void) { return _stub_error(); }
|
||||
|
||||
lux_status lux_load_backend(const char* p) { (void)p; return LUX_NO_BACKEND; }
|
||||
int lux_backend_count(void) { return 0; }
|
||||
lux_backend_type lux_backend_type_at(int i){ (void)i; return 0; }
|
||||
int lux_device_count(lux_backend_type b) { (void)b; return 0; }
|
||||
lux_status lux_get_device_info(lux_backend_type b, int i, lux_device_info* o) {
|
||||
(void)b; (void)i;
|
||||
if (o) memset(o, 0, sizeof(*o));
|
||||
return LUX_NO_BACKEND;
|
||||
}
|
||||
|
||||
lux_status lux_session_create(lux_session* s) { if(s)*s=NULL; return LUX_NO_BACKEND; }
|
||||
lux_status lux_session_create_with_backend(lux_backend_type b, lux_session* s) { (void)b; if(s)*s=NULL; return LUX_NO_BACKEND; }
|
||||
lux_status lux_session_create_with_device(lux_backend_type b, int d, lux_session* s) { (void)b; (void)d; if(s)*s=NULL; return LUX_NO_BACKEND; }
|
||||
void lux_session_destroy(lux_session s) { (void)s; }
|
||||
lux_status lux_session_sync(lux_session s) { (void)s; return LUX_NO_BACKEND; }
|
||||
lux_status lux_session_get_device_info(lux_session s, lux_device_info* o) {
|
||||
(void)s;
|
||||
if (o) memset(o, 0, sizeof(*o));
|
||||
return LUX_NO_BACKEND;
|
||||
}
|
||||
|
||||
lux_status lux_tensor_create(lux_session s, lux_dtype d, const size_t* sh, size_t nd, lux_tensor* t) { (void)s; (void)d; (void)sh; (void)nd; if(t)*t=NULL; return LUX_NO_BACKEND; }
|
||||
lux_status lux_tensor_create_with_data(lux_session s, lux_dtype d, const size_t* sh, size_t nd, const void* data, size_t len, lux_tensor* t) { (void)s; (void)d; (void)sh; (void)nd; (void)data; (void)len; if(t)*t=NULL; return LUX_NO_BACKEND; }
|
||||
void lux_tensor_destroy(lux_tensor t) { (void)t; }
|
||||
size_t lux_tensor_ndim(lux_tensor t) { (void)t; return 0; }
|
||||
size_t lux_tensor_shape(lux_tensor t, size_t d) { (void)t; (void)d; return 0; }
|
||||
size_t lux_tensor_numel(lux_tensor t) { (void)t; return 0; }
|
||||
size_t lux_tensor_bytes(lux_tensor t) { (void)t; return 0; }
|
||||
lux_dtype lux_tensor_dtype(lux_tensor t) { (void)t; return 0; }
|
||||
lux_status lux_tensor_to_host(lux_tensor t, void* d, size_t n) { (void)t; (void)d; (void)n; return LUX_NO_BACKEND; }
|
||||
lux_status lux_tensor_from_host(lux_tensor t, const void* d, size_t n) { (void)t; (void)d; (void)n; return LUX_NO_BACKEND; }
|
||||
|
||||
// ML ops
|
||||
lux_status lux_matmul(lux_session s, lux_tensor a, lux_tensor b, lux_tensor c) { (void)s; (void)a; (void)b; (void)c; return LUX_NO_BACKEND; }
|
||||
lux_status lux_relu(lux_session s, lux_tensor i, lux_tensor o) { (void)s; (void)i; (void)o; return LUX_NO_BACKEND; }
|
||||
lux_status lux_gelu(lux_session s, lux_tensor i, lux_tensor o) { (void)s; (void)i; (void)o; return LUX_NO_BACKEND; }
|
||||
lux_status lux_softmax(lux_session s, lux_tensor i, lux_tensor o, int ax) { (void)s; (void)i; (void)o; (void)ax; return LUX_NO_BACKEND; }
|
||||
lux_status lux_layer_norm(lux_session s, lux_tensor i, lux_tensor g, lux_tensor b, lux_tensor o, float e) { (void)s; (void)i; (void)g; (void)b; (void)o; (void)e; return LUX_NO_BACKEND; }
|
||||
lux_status lux_attention(lux_session s, lux_tensor q, lux_tensor k, lux_tensor v, lux_tensor o, float sc) { (void)s; (void)q; (void)k; (void)v; (void)o; (void)sc; return LUX_NO_BACKEND; }
|
||||
|
||||
// Crypto ops
|
||||
lux_status lux_sha256(lux_session s, lux_tensor i, lux_tensor o) { (void)s; (void)i; (void)o; return LUX_NO_BACKEND; }
|
||||
lux_status lux_keccak256(lux_session s, lux_tensor i, lux_tensor o) { (void)s; (void)i; (void)o; return LUX_NO_BACKEND; }
|
||||
lux_status lux_poseidon(lux_session s, lux_tensor i, lux_tensor o) { (void)s; (void)i; (void)o; return LUX_NO_BACKEND; }
|
||||
lux_status lux_ecdsa_verify_batch(lux_session s, lux_tensor m, lux_tensor sg, lux_tensor pk, lux_tensor r) { (void)s; (void)m; (void)sg; (void)pk; (void)r; return LUX_NO_BACKEND; }
|
||||
lux_status lux_ed25519_verify_batch(lux_session s, lux_tensor m, lux_tensor sg, lux_tensor pk, lux_tensor r) { (void)s; (void)m; (void)sg; (void)pk; (void)r; return LUX_NO_BACKEND; }
|
||||
lux_status lux_bls_verify_batch(lux_session s, lux_tensor m, lux_tensor sg, lux_tensor pk, lux_tensor r) { (void)s; (void)m; (void)sg; (void)pk; (void)r; return LUX_NO_BACKEND; }
|
||||
lux_status lux_merkle_root(lux_session s, lux_tensor l, lux_tensor r) { (void)s; (void)l; (void)r; return LUX_NO_BACKEND; }
|
||||
|
||||
// ZK ops
|
||||
lux_status lux_ntt(lux_session s, lux_tensor i, lux_tensor o, lux_tensor rt, uint64_t m) { (void)s; (void)i; (void)o; (void)rt; (void)m; return LUX_NO_BACKEND; }
|
||||
lux_status lux_intt(lux_session s, lux_tensor i, lux_tensor o, lux_tensor ir, uint64_t m) { (void)s; (void)i; (void)o; (void)ir; (void)m; return LUX_NO_BACKEND; }
|
||||
lux_status lux_msm(lux_session s, lux_tensor sc, lux_tensor ba, lux_tensor r) { (void)s; (void)sc; (void)ba; (void)r; return LUX_NO_BACKEND; }
|
||||
lux_status lux_poly_mul(lux_session s, lux_tensor a, lux_tensor b, lux_tensor c, uint64_t m) { (void)s; (void)a; (void)b; (void)c; (void)m; return LUX_NO_BACKEND; }
|
||||
|
||||
// Lattice / PQC ops
|
||||
lux_status lux_kyber_keygen(lux_session s, lux_tensor pk, lux_tensor sk) { (void)s; (void)pk; (void)sk; return LUX_NO_BACKEND; }
|
||||
lux_status lux_kyber_encaps(lux_session s, lux_tensor pk, lux_tensor ct, lux_tensor ss) { (void)s; (void)pk; (void)ct; (void)ss; return LUX_NO_BACKEND; }
|
||||
lux_status lux_kyber_decaps(lux_session s, lux_tensor ct, lux_tensor sk, lux_tensor ss) { (void)s; (void)ct; (void)sk; (void)ss; return LUX_NO_BACKEND; }
|
||||
lux_status lux_dilithium_sign(lux_session s, lux_tensor m, lux_tensor sk, lux_tensor sg) { (void)s; (void)m; (void)sk; (void)sg; return LUX_NO_BACKEND; }
|
||||
lux_status lux_dilithium_verify(lux_session s, lux_tensor m, lux_tensor sg, lux_tensor pk, int* v) { (void)s; (void)m; (void)sg; (void)pk; if(v)*v=0; return LUX_NO_BACKEND; }
|
||||
lux_status lux_slhdsa_sign_batch(lux_session s, int mode, lux_tensor m, lux_tensor sk, lux_tensor sg) { (void)s; (void)mode; (void)m; (void)sk; (void)sg; return LUX_NO_BACKEND; }
|
||||
lux_status lux_slhdsa_verify_batch(lux_session s, int mode, lux_tensor m, lux_tensor sg, lux_tensor pk, lux_tensor r) { (void)s; (void)mode; (void)m; (void)sg; (void)pk; (void)r; return LUX_NO_BACKEND; }
|
||||
lux_status lux_mldsa_sign_batch(lux_session s, int mode, lux_tensor m, lux_tensor sk, lux_tensor sg) { (void)s; (void)mode; (void)m; (void)sk; (void)sg; return LUX_NO_BACKEND; }
|
||||
lux_status lux_mldsa_verify_batch(lux_session s, int mode, lux_tensor m, lux_tensor sg, lux_tensor pk, lux_tensor r) { (void)s; (void)mode; (void)m; (void)sg; (void)pk; (void)r; return LUX_NO_BACKEND; }
|
||||
lux_status lux_lattice_ntt_mldsa_batch(lux_session s, lux_tensor polys, int inv) { (void)s; (void)polys; (void)inv; return LUX_NO_BACKEND; }
|
||||
|
||||
// FHE ops
|
||||
lux_status lux_bfv_encrypt(lux_session s, lux_tensor p, lux_tensor pk, lux_tensor c) { (void)s; (void)p; (void)pk; (void)c; return LUX_NO_BACKEND; }
|
||||
lux_status lux_bfv_decrypt(lux_session s, lux_tensor c, lux_tensor sk, lux_tensor p) { (void)s; (void)c; (void)sk; (void)p; return LUX_NO_BACKEND; }
|
||||
lux_status lux_bfv_add(lux_session s, lux_tensor a, lux_tensor b, lux_tensor r) { (void)s; (void)a; (void)b; (void)r; return LUX_NO_BACKEND; }
|
||||
lux_status lux_bfv_multiply(lux_session s, lux_tensor a, lux_tensor b, lux_tensor rk, lux_tensor r) { (void)s; (void)a; (void)b; (void)rk; (void)r; return LUX_NO_BACKEND; }
|
||||
|
||||
// DEX ops
|
||||
lux_status lux_constant_product_swap(lux_session s, lux_tensor rx, lux_tensor ry, lux_tensor ai, int d, lux_tensor ao, float f) { (void)s; (void)rx; (void)ry; (void)ai; (void)d; (void)ao; (void)f; return LUX_NO_BACKEND; }
|
||||
lux_status lux_compute_twap(lux_session s, lux_tensor p, lux_tensor ts, uint64_t st, uint64_t en, lux_tensor tw) { (void)s; (void)p; (void)ts; (void)st; (void)en; (void)tw; return LUX_NO_BACKEND; }
|
||||
lux_status lux_match_orders(lux_session s, lux_tensor bi, lux_tensor ak, lux_tensor mt, lux_tensor pr, lux_tensor am) { (void)s; (void)bi; (void)ak; (void)mt; (void)pr; (void)am; return LUX_NO_BACKEND; }
|
||||
*/
|
||||
import "C"
|
||||
+3
@@ -119,6 +119,9 @@ func (o *stubLatticeOps) PolynomialINTT(input, output *UntypedTensor, q uint32)
|
||||
}
|
||||
func (o *stubLatticeOps) PolynomialMul(a, b, c *UntypedTensor, q uint32) error { return ErrNoBackends }
|
||||
func (o *stubLatticeOps) PolynomialAdd(a, b, c *UntypedTensor, q uint32) error { return ErrNoBackends }
|
||||
func (o *stubLatticeOps) LatticeNTTMLDSABatch(polys *UntypedTensor, inverse bool) error {
|
||||
return ErrNoBackends
|
||||
}
|
||||
|
||||
type stubFHEOps struct{}
|
||||
|
||||
|
||||
+70
-33
@@ -20,6 +20,38 @@ import (
|
||||
// CKKSAdd, CKKSMultiply, CKKSRescale, CKKSRotate, Bootstrap
|
||||
// DEX: ConstantProductSwapBatch, MatchOrdersWithPriority, ComputeLiquidity,
|
||||
// ComputePositionValue, CalculateFees, BatchSettlement
|
||||
//
|
||||
// Red CRITICAL Probe 9 — sentinel mismatch propagation contract:
|
||||
// =================================================================
|
||||
// The internal `capi` package and the public `accel` package each
|
||||
// declare their own `ErrInvalidArgument` (etc.) sentinels — they are
|
||||
// DISTINCT `errors.New(...)` values. A consumer that calls
|
||||
//
|
||||
// err := sess.Lattice().MLDSAVerifyBatch(...)
|
||||
// if errors.Is(err, accel.ErrInvalidArgument) { ... hard error ... }
|
||||
//
|
||||
// will see `errors.Is(...) == false` if the cgo path returns the capi
|
||||
// sentinel unwrapped — because errors.Is uses pointer-equality at the
|
||||
// leaves of the unwrap chain and capi.ErrInvalidArgument is not
|
||||
// accel.ErrInvalidArgument. This silently routes every "hard error"
|
||||
// case to the recoverable-error branch (CPU fallback), defeating the
|
||||
// entire M-1 propagation chain landed in:
|
||||
//
|
||||
// * lux/accel/ops/crypto/crypto_gpu.go:159 (SigMLDSA65)
|
||||
// * lux/crypto/slhdsa/gpu.go:276, 479 (SLH-DSA verify/sign)
|
||||
// * lux/crypto/pq/mldsa/gpu/gpu_cgo.go (ML-DSA verify/sign)
|
||||
// * lux/crypto/mldsa/gpu.go (batchVerifyGPU/batchSignGPU)
|
||||
// * lux/precompile/mldsa/contract.go:401 (precompile fail-closed)
|
||||
// * lux/precompile/ai/ai_mining.go (AI mining fail-closed)
|
||||
//
|
||||
// The fix is `translateCapiError` (session_c.go:22-41), already
|
||||
// applied to the NewSession* paths but NOT to the per-op cgo methods
|
||||
// in this file. Every method that returned `capi.*(...)` unwrapped
|
||||
// is now wrapped through translateCapiError so the public accel
|
||||
// surface emits the accel.* sentinel that consumers errors.Is against.
|
||||
//
|
||||
// One sentinel, one source of truth, one propagation path. Adding a
|
||||
// new cgo-routed op? Wrap the return through translateCapiError.
|
||||
|
||||
// cgoMLOps implements MLOps using CGO.
|
||||
type cgoMLOps struct {
|
||||
@@ -27,7 +59,7 @@ type cgoMLOps struct {
|
||||
}
|
||||
|
||||
func (o *cgoMLOps) MatMul(a, b, c *UntypedTensor) error {
|
||||
return capi.MatMul(o.session, getCAPITensor(a), getCAPITensor(b), getCAPITensor(c))
|
||||
return translateCapiError(capi.MatMul(o.session, getCAPITensor(a), getCAPITensor(b), getCAPITensor(c)))
|
||||
}
|
||||
|
||||
func (o *cgoMLOps) MatMulTranspose(a, b, c *UntypedTensor, transposeA, transposeB bool) error {
|
||||
@@ -35,23 +67,23 @@ func (o *cgoMLOps) MatMulTranspose(a, b, c *UntypedTensor, transposeA, transpose
|
||||
}
|
||||
|
||||
func (o *cgoMLOps) ReLU(input, output *UntypedTensor) error {
|
||||
return capi.ReLU(o.session, getCAPITensor(input), getCAPITensor(output))
|
||||
return translateCapiError(capi.ReLU(o.session, getCAPITensor(input), getCAPITensor(output)))
|
||||
}
|
||||
|
||||
func (o *cgoMLOps) GELU(input, output *UntypedTensor) error {
|
||||
return capi.GELU(o.session, getCAPITensor(input), getCAPITensor(output))
|
||||
return translateCapiError(capi.GELU(o.session, getCAPITensor(input), getCAPITensor(output)))
|
||||
}
|
||||
|
||||
func (o *cgoMLOps) Softmax(input, output *UntypedTensor, axis int) error {
|
||||
return capi.Softmax(o.session, getCAPITensor(input), getCAPITensor(output), axis)
|
||||
return translateCapiError(capi.Softmax(o.session, getCAPITensor(input), getCAPITensor(output), axis))
|
||||
}
|
||||
|
||||
func (o *cgoMLOps) LayerNorm(input, gamma, beta, output *UntypedTensor, eps float32) error {
|
||||
return capi.LayerNorm(o.session, getCAPITensor(input), getCAPITensor(gamma), getCAPITensor(beta), getCAPITensor(output), eps)
|
||||
return translateCapiError(capi.LayerNorm(o.session, getCAPITensor(input), getCAPITensor(gamma), getCAPITensor(beta), getCAPITensor(output), eps))
|
||||
}
|
||||
|
||||
func (o *cgoMLOps) Attention(q, k, v, output *UntypedTensor, scale float32) error {
|
||||
return capi.Attention(o.session, getCAPITensor(q), getCAPITensor(k), getCAPITensor(v), getCAPITensor(output), scale)
|
||||
return translateCapiError(capi.Attention(o.session, getCAPITensor(q), getCAPITensor(k), getCAPITensor(v), getCAPITensor(output), scale))
|
||||
}
|
||||
|
||||
func (o *cgoMLOps) Conv2D(input, kernel, output *UntypedTensor, stride, padding [2]int) error {
|
||||
@@ -92,27 +124,27 @@ type cgoCryptoOps struct {
|
||||
}
|
||||
|
||||
func (o *cgoCryptoOps) SHA256(input, output *UntypedTensor) error {
|
||||
return capi.SHA256(o.session, getCAPITensor(input), getCAPITensor(output))
|
||||
return translateCapiError(capi.SHA256(o.session, getCAPITensor(input), getCAPITensor(output)))
|
||||
}
|
||||
|
||||
func (o *cgoCryptoOps) Keccak256(input, output *UntypedTensor) error {
|
||||
return capi.Keccak256(o.session, getCAPITensor(input), getCAPITensor(output))
|
||||
return translateCapiError(capi.Keccak256(o.session, getCAPITensor(input), getCAPITensor(output)))
|
||||
}
|
||||
|
||||
func (o *cgoCryptoOps) Poseidon(input, output *UntypedTensor) error {
|
||||
return capi.Poseidon(o.session, getCAPITensor(input), getCAPITensor(output))
|
||||
return translateCapiError(capi.Poseidon(o.session, getCAPITensor(input), getCAPITensor(output)))
|
||||
}
|
||||
|
||||
func (o *cgoCryptoOps) ECDSAVerifyBatch(messages, signatures, pubkeys, results *UntypedTensor) error {
|
||||
return capi.ECDSAVerifyBatch(o.session, getCAPITensor(messages), getCAPITensor(signatures), getCAPITensor(pubkeys), getCAPITensor(results))
|
||||
return translateCapiError(capi.ECDSAVerifyBatch(o.session, getCAPITensor(messages), getCAPITensor(signatures), getCAPITensor(pubkeys), getCAPITensor(results)))
|
||||
}
|
||||
|
||||
func (o *cgoCryptoOps) Ed25519VerifyBatch(messages, signatures, pubkeys, results *UntypedTensor) error {
|
||||
return capi.Ed25519VerifyBatch(o.session, getCAPITensor(messages), getCAPITensor(signatures), getCAPITensor(pubkeys), getCAPITensor(results))
|
||||
return translateCapiError(capi.Ed25519VerifyBatch(o.session, getCAPITensor(messages), getCAPITensor(signatures), getCAPITensor(pubkeys), getCAPITensor(results)))
|
||||
}
|
||||
|
||||
func (o *cgoCryptoOps) BLSVerifyBatch(messages, signatures, pubkeys, results *UntypedTensor) error {
|
||||
return capi.BLSVerifyBatch(o.session, getCAPITensor(messages), getCAPITensor(signatures), getCAPITensor(pubkeys), getCAPITensor(results))
|
||||
return translateCapiError(capi.BLSVerifyBatch(o.session, getCAPITensor(messages), getCAPITensor(signatures), getCAPITensor(pubkeys), getCAPITensor(results)))
|
||||
}
|
||||
|
||||
func (o *cgoCryptoOps) BLSAggregate(signatures, aggregated *UntypedTensor) error {
|
||||
@@ -120,7 +152,7 @@ func (o *cgoCryptoOps) BLSAggregate(signatures, aggregated *UntypedTensor) error
|
||||
}
|
||||
|
||||
func (o *cgoCryptoOps) MerkleRoot(leaves, root *UntypedTensor) error {
|
||||
return capi.MerkleRoot(o.session, getCAPITensor(leaves), getCAPITensor(root))
|
||||
return translateCapiError(capi.MerkleRoot(o.session, getCAPITensor(leaves), getCAPITensor(root)))
|
||||
}
|
||||
|
||||
func (o *cgoCryptoOps) MerkleBatch(leavesSet, roots *UntypedTensor) error {
|
||||
@@ -137,15 +169,15 @@ type cgoZKOps struct {
|
||||
}
|
||||
|
||||
func (o *cgoZKOps) NTT(input, output, roots *UntypedTensor, modulus uint64) error {
|
||||
return capi.NTT(o.session, getCAPITensor(input), getCAPITensor(output), getCAPITensor(roots), modulus)
|
||||
return translateCapiError(capi.NTT(o.session, getCAPITensor(input), getCAPITensor(output), getCAPITensor(roots), modulus))
|
||||
}
|
||||
|
||||
func (o *cgoZKOps) INTT(input, output, invRoots *UntypedTensor, modulus uint64) error {
|
||||
return capi.INTT(o.session, getCAPITensor(input), getCAPITensor(output), getCAPITensor(invRoots), modulus)
|
||||
return translateCapiError(capi.INTT(o.session, getCAPITensor(input), getCAPITensor(output), getCAPITensor(invRoots), modulus))
|
||||
}
|
||||
|
||||
func (o *cgoZKOps) MSM(scalars, bases, result *UntypedTensor) error {
|
||||
return capi.MSM(o.session, getCAPITensor(scalars), getCAPITensor(bases), getCAPITensor(result))
|
||||
return translateCapiError(capi.MSM(o.session, getCAPITensor(scalars), getCAPITensor(bases), getCAPITensor(result)))
|
||||
}
|
||||
|
||||
func (o *cgoZKOps) MSMBatch(scalars, bases, results *UntypedTensor) error {
|
||||
@@ -153,7 +185,7 @@ func (o *cgoZKOps) MSMBatch(scalars, bases, results *UntypedTensor) error {
|
||||
}
|
||||
|
||||
func (o *cgoZKOps) PolyMul(a, b, c *UntypedTensor, modulus uint64) error {
|
||||
return capi.PolyMul(o.session, getCAPITensor(a), getCAPITensor(b), getCAPITensor(c), modulus)
|
||||
return translateCapiError(capi.PolyMul(o.session, getCAPITensor(a), getCAPITensor(b), getCAPITensor(c), modulus))
|
||||
}
|
||||
|
||||
func (o *cgoZKOps) PolyEval(coeffs, points, results *UntypedTensor, modulus uint64) error {
|
||||
@@ -190,7 +222,7 @@ type cgoLatticeOps struct {
|
||||
}
|
||||
|
||||
func (o *cgoLatticeOps) KyberKeyGen(pk, sk *UntypedTensor) error {
|
||||
return capi.KyberKeyGen(o.session, getCAPITensor(pk), getCAPITensor(sk))
|
||||
return translateCapiError(capi.KyberKeyGen(o.session, getCAPITensor(pk), getCAPITensor(sk)))
|
||||
}
|
||||
|
||||
func (o *cgoLatticeOps) KyberKeyGenBatch(pk, sk *UntypedTensor) error {
|
||||
@@ -198,7 +230,7 @@ func (o *cgoLatticeOps) KyberKeyGenBatch(pk, sk *UntypedTensor) error {
|
||||
}
|
||||
|
||||
func (o *cgoLatticeOps) KyberEncaps(pk, ct, ss *UntypedTensor) error {
|
||||
return capi.KyberEncaps(o.session, getCAPITensor(pk), getCAPITensor(ct), getCAPITensor(ss))
|
||||
return translateCapiError(capi.KyberEncaps(o.session, getCAPITensor(pk), getCAPITensor(ct), getCAPITensor(ss)))
|
||||
}
|
||||
|
||||
func (o *cgoLatticeOps) KyberEncapsBatch(pk, ct, ss *UntypedTensor) error {
|
||||
@@ -206,7 +238,7 @@ func (o *cgoLatticeOps) KyberEncapsBatch(pk, ct, ss *UntypedTensor) error {
|
||||
}
|
||||
|
||||
func (o *cgoLatticeOps) KyberDecaps(ct, sk, ss *UntypedTensor) error {
|
||||
return capi.KyberDecaps(o.session, getCAPITensor(ct), getCAPITensor(sk), getCAPITensor(ss))
|
||||
return translateCapiError(capi.KyberDecaps(o.session, getCAPITensor(ct), getCAPITensor(sk), getCAPITensor(ss)))
|
||||
}
|
||||
|
||||
func (o *cgoLatticeOps) KyberDecapsBatch(ct, sk, ss *UntypedTensor) error {
|
||||
@@ -218,7 +250,7 @@ func (o *cgoLatticeOps) DilithiumKeyGen(pk, sk *UntypedTensor) error {
|
||||
}
|
||||
|
||||
func (o *cgoLatticeOps) DilithiumSign(msg, sk, sig *UntypedTensor) error {
|
||||
return capi.DilithiumSign(o.session, getCAPITensor(msg), getCAPITensor(sk), getCAPITensor(sig))
|
||||
return translateCapiError(capi.DilithiumSign(o.session, getCAPITensor(msg), getCAPITensor(sk), getCAPITensor(sig)))
|
||||
}
|
||||
|
||||
func (o *cgoLatticeOps) DilithiumSignBatch(msgs, sk, sigs *UntypedTensor) error {
|
||||
@@ -226,7 +258,8 @@ func (o *cgoLatticeOps) DilithiumSignBatch(msgs, sk, sigs *UntypedTensor) error
|
||||
}
|
||||
|
||||
func (o *cgoLatticeOps) DilithiumVerify(msg, sig, pk *UntypedTensor) (bool, error) {
|
||||
return capi.DilithiumVerify(o.session, getCAPITensor(msg), getCAPITensor(sig), getCAPITensor(pk))
|
||||
ok, err := capi.DilithiumVerify(o.session, getCAPITensor(msg), getCAPITensor(sig), getCAPITensor(pk))
|
||||
return ok, translateCapiError(err)
|
||||
}
|
||||
|
||||
func (o *cgoLatticeOps) DilithiumVerifyBatch(msgs, sigs, pks, results *UntypedTensor) error {
|
||||
@@ -234,19 +267,19 @@ func (o *cgoLatticeOps) DilithiumVerifyBatch(msgs, sigs, pks, results *UntypedTe
|
||||
}
|
||||
|
||||
func (o *cgoLatticeOps) MLDSAVerifyBatch(mode int, msgs, sigs, pks, results *UntypedTensor) error {
|
||||
return capi.MLDSAVerifyBatch(o.session, mode, getCAPITensor(msgs), getCAPITensor(sigs), getCAPITensor(pks), getCAPITensor(results))
|
||||
return translateCapiError(capi.MLDSAVerifyBatch(o.session, mode, getCAPITensor(msgs), getCAPITensor(sigs), getCAPITensor(pks), getCAPITensor(results)))
|
||||
}
|
||||
|
||||
func (o *cgoLatticeOps) MLDSASignBatch(mode int, msgs, sks, sigs *UntypedTensor) error {
|
||||
return capi.MLDSASignBatch(o.session, mode, getCAPITensor(msgs), getCAPITensor(sks), getCAPITensor(sigs))
|
||||
return translateCapiError(capi.MLDSASignBatch(o.session, mode, getCAPITensor(msgs), getCAPITensor(sks), getCAPITensor(sigs)))
|
||||
}
|
||||
|
||||
func (o *cgoLatticeOps) SLHDSASignBatch(mode int, msgs, sks, sigs *UntypedTensor) error {
|
||||
return capi.SLHDSASignBatch(o.session, mode, getCAPITensor(msgs), getCAPITensor(sks), getCAPITensor(sigs))
|
||||
return translateCapiError(capi.SLHDSASignBatch(o.session, mode, getCAPITensor(msgs), getCAPITensor(sks), getCAPITensor(sigs)))
|
||||
}
|
||||
|
||||
func (o *cgoLatticeOps) SLHDSAVerifyBatch(mode int, msgs, sigs, pks, results *UntypedTensor) error {
|
||||
return capi.SLHDSAVerifyBatch(o.session, mode, getCAPITensor(msgs), getCAPITensor(sigs), getCAPITensor(pks), getCAPITensor(results))
|
||||
return translateCapiError(capi.SLHDSAVerifyBatch(o.session, mode, getCAPITensor(msgs), getCAPITensor(sigs), getCAPITensor(pks), getCAPITensor(results)))
|
||||
}
|
||||
|
||||
func (o *cgoLatticeOps) PolynomialNTT(input, output *UntypedTensor, q uint32) error {
|
||||
@@ -265,13 +298,17 @@ func (o *cgoLatticeOps) PolynomialAdd(a, b, c *UntypedTensor, q uint32) error {
|
||||
return ErrNotSupported
|
||||
}
|
||||
|
||||
func (o *cgoLatticeOps) LatticeNTTMLDSABatch(polys *UntypedTensor, inverse bool) error {
|
||||
return translateCapiError(capi.LatticeNTTMLDSABatch(o.session, getCAPITensor(polys), inverse))
|
||||
}
|
||||
|
||||
// cgoFHEOps implements FHEOps using CGO.
|
||||
type cgoFHEOps struct {
|
||||
session *capi.Session
|
||||
}
|
||||
|
||||
func (o *cgoFHEOps) BFVEncrypt(plaintext, pk, ciphertext *UntypedTensor) error {
|
||||
return capi.BFVEncrypt(o.session, getCAPITensor(plaintext), getCAPITensor(pk), getCAPITensor(ciphertext))
|
||||
return translateCapiError(capi.BFVEncrypt(o.session, getCAPITensor(plaintext), getCAPITensor(pk), getCAPITensor(ciphertext)))
|
||||
}
|
||||
|
||||
func (o *cgoFHEOps) BFVEncryptBatch(plaintexts, pk, ciphertexts *UntypedTensor) error {
|
||||
@@ -279,15 +316,15 @@ func (o *cgoFHEOps) BFVEncryptBatch(plaintexts, pk, ciphertexts *UntypedTensor)
|
||||
}
|
||||
|
||||
func (o *cgoFHEOps) BFVDecrypt(ciphertext, sk, plaintext *UntypedTensor) error {
|
||||
return capi.BFVDecrypt(o.session, getCAPITensor(ciphertext), getCAPITensor(sk), getCAPITensor(plaintext))
|
||||
return translateCapiError(capi.BFVDecrypt(o.session, getCAPITensor(ciphertext), getCAPITensor(sk), getCAPITensor(plaintext)))
|
||||
}
|
||||
|
||||
func (o *cgoFHEOps) BFVAdd(ct1, ct2, result *UntypedTensor) error {
|
||||
return capi.BFVAdd(o.session, getCAPITensor(ct1), getCAPITensor(ct2), getCAPITensor(result))
|
||||
return translateCapiError(capi.BFVAdd(o.session, getCAPITensor(ct1), getCAPITensor(ct2), getCAPITensor(result)))
|
||||
}
|
||||
|
||||
func (o *cgoFHEOps) BFVMultiply(ct1, ct2, relinKey, result *UntypedTensor) error {
|
||||
return capi.BFVMultiply(o.session, getCAPITensor(ct1), getCAPITensor(ct2), getCAPITensor(relinKey), getCAPITensor(result))
|
||||
return translateCapiError(capi.BFVMultiply(o.session, getCAPITensor(ct1), getCAPITensor(ct2), getCAPITensor(relinKey), getCAPITensor(result)))
|
||||
}
|
||||
|
||||
func (o *cgoFHEOps) BFVMultiplyPlain(ct, plain, result *UntypedTensor) error {
|
||||
@@ -332,7 +369,7 @@ type cgoDEXOps struct {
|
||||
}
|
||||
|
||||
func (o *cgoDEXOps) ConstantProductSwap(reserveX, reserveY, amountIn *UntypedTensor, xToY bool, amountOut *UntypedTensor, fee float32) error {
|
||||
return capi.ConstantProductSwap(o.session, getCAPITensor(reserveX), getCAPITensor(reserveY), getCAPITensor(amountIn), getCAPITensor(amountOut), xToY, fee)
|
||||
return translateCapiError(capi.ConstantProductSwap(o.session, getCAPITensor(reserveX), getCAPITensor(reserveY), getCAPITensor(amountIn), getCAPITensor(amountOut), xToY, fee))
|
||||
}
|
||||
|
||||
func (o *cgoDEXOps) ConstantProductSwapBatch(reserves, swaps, amounts *UntypedTensor, fee float32) error {
|
||||
@@ -340,11 +377,11 @@ func (o *cgoDEXOps) ConstantProductSwapBatch(reserves, swaps, amounts *UntypedTe
|
||||
}
|
||||
|
||||
func (o *cgoDEXOps) ComputeTWAP(prices, timestamps *UntypedTensor, start, end uint64, twap *UntypedTensor) error {
|
||||
return capi.ComputeTWAP(o.session, getCAPITensor(prices), getCAPITensor(timestamps), getCAPITensor(twap), start, end)
|
||||
return translateCapiError(capi.ComputeTWAP(o.session, getCAPITensor(prices), getCAPITensor(timestamps), getCAPITensor(twap), start, end))
|
||||
}
|
||||
|
||||
func (o *cgoDEXOps) MatchOrders(bids, asks, matches, prices, amounts *UntypedTensor) error {
|
||||
return capi.MatchOrders(o.session, getCAPITensor(bids), getCAPITensor(asks), getCAPITensor(matches), getCAPITensor(prices), getCAPITensor(amounts))
|
||||
return translateCapiError(capi.MatchOrders(o.session, getCAPITensor(bids), getCAPITensor(asks), getCAPITensor(matches), getCAPITensor(prices), getCAPITensor(amounts)))
|
||||
}
|
||||
|
||||
func (o *cgoDEXOps) MatchOrdersWithPriority(bids, asks, matches *UntypedTensor) error {
|
||||
|
||||
+14
@@ -135,4 +135,18 @@ type LatticeOps interface {
|
||||
|
||||
// PolynomialAdd adds polynomials.
|
||||
PolynomialAdd(a, b, c *UntypedTensor, q uint32) error
|
||||
|
||||
// LatticeNTTMLDSABatch performs the in-place forward (inverse=false) or
|
||||
// inverse (inverse=true) NTT over Z_q[X]/(X^256 + 1) with q = 8380417 (the
|
||||
// ML-DSA / FIPS 204 prime), batched across N polynomials.
|
||||
//
|
||||
// Tensor shape:
|
||||
// polys : LUX_DTYPE_I32, shape [N, 256] — in-place transform
|
||||
//
|
||||
// Byte-equal to PQCLEAN_MLDSA65_CLEAN_ntt (forward) and
|
||||
// PQCLEAN_MLDSA65_CLEAN_invntt_tomont (inverse). Pulsar Round-2 fits the
|
||||
// batch=22 dispatch shape; below the GPU-dispatch threshold the caller
|
||||
// MUST route to the per-poly CPU oracle (the threshold gating lives in
|
||||
// the consumer, not in this primitive).
|
||||
LatticeNTTMLDSABatch(polys *UntypedTensor, inverse bool) error
|
||||
}
|
||||
|
||||
+9
-2
@@ -308,7 +308,13 @@ func (h *cgoSessionHandle) dex() DEXOps { return h.dexOps }
|
||||
func (h *cgoSessionHandle) createTensor(dtype DType, shape []int) (tensorHandle, error) {
|
||||
t, err := capi.CreateTensor(h.session, int(dtype), shape)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
// Red CRITICAL Probe 9: translate the capi sentinel into the
|
||||
// public accel sentinel so consumers using errors.Is against
|
||||
// accel.ErrInvalidArgument match. Without translateCapiError
|
||||
// the bare capi.ErrInvalidArgument leaks out and errors.Is
|
||||
// returns false (distinct errors.New sentinels at distinct
|
||||
// pointers) → silent CPU fallback in M-1 consumers.
|
||||
return nil, translateCapiError(err)
|
||||
}
|
||||
return &cgoTensorHandle{tensor: t}, nil
|
||||
}
|
||||
@@ -316,7 +322,8 @@ func (h *cgoSessionHandle) createTensor(dtype DType, shape []int) (tensorHandle,
|
||||
func (h *cgoSessionHandle) createTensorWithData(dtype DType, shape []int, data []byte) (tensorHandle, error) {
|
||||
t, err := capi.CreateTensorWithData(h.session, int(dtype), shape, data)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
// Red CRITICAL Probe 9: see createTensor above.
|
||||
return nil, translateCapiError(err)
|
||||
}
|
||||
return &cgoTensorHandle{tensor: t}, nil
|
||||
}
|
||||
|
||||
+2
-2
@@ -78,8 +78,8 @@ type VMSession struct {
|
||||
memCap int64
|
||||
|
||||
// Underlying GPU session. May be shared (pointer to default) or owned.
|
||||
sess *Session
|
||||
owned bool
|
||||
sess *Session
|
||||
owned bool
|
||||
|
||||
// Serialized dispatch queue. Each op runs while holding qMu, guaranteeing
|
||||
// FIFO ordering within this VMSession.
|
||||
|
||||
+2
-2
@@ -74,8 +74,8 @@ REPLICATE_AGE_RECIPIENTS_FALLBACK=age1pq1... # comma-separated, multi-recipi
|
||||
### E. Operator CRD
|
||||
|
||||
```yaml
|
||||
apiVersion: lux.network/v1
|
||||
kind: ReplicateConfig
|
||||
apiVersion: liquidity.io/v1
|
||||
kind: LiquidReplicate
|
||||
spec:
|
||||
encryption:
|
||||
kem: xwing # enum: hpke-mlkem768x25519 | xwing
|
||||
|
||||
+23
-20
@@ -1,32 +1,35 @@
|
||||
|
||||
|
||||
__pycache__/
|
||||
.DS_Store
|
||||
.next/
|
||||
.pnpm-store/
|
||||
*.log
|
||||
**/__pycache__/
|
||||
**/dist/
|
||||
**/node_modules/
|
||||
**/target/
|
||||
# hygiene (untrack node_modules, block common build output)
|
||||
# mlkem dudect build artifacts
|
||||
AGENTS.md
|
||||
build/
|
||||
CLAUDE.md
|
||||
coverage/
|
||||
dist/
|
||||
GEMINI.md
|
||||
GROK.md
|
||||
QWEN.md
|
||||
grpc-server.log
|
||||
|
||||
# hygiene (untrack node_modules, block common build output)
|
||||
node_modules/
|
||||
**/node_modules/
|
||||
.pnpm-store/
|
||||
dist/
|
||||
build/
|
||||
.next/
|
||||
coverage/
|
||||
playwright-report/
|
||||
test-results/
|
||||
*.log
|
||||
tmp/
|
||||
.DS_Store
|
||||
|
||||
# mlkem dudect build artifacts
|
||||
mlkem/ct/dudect/dudect/
|
||||
mlkem/ct/dudect/dudect_decaps
|
||||
mlkem/ct/dudect/dudect_encaps
|
||||
mlkem/ct/dudect/dudect_keygen
|
||||
mlkem/ct/dudect/dudect/
|
||||
mlkem/ct/dudect/libmlkem_*.dylib
|
||||
mlkem/ct/dudect/libmlkem_*.so
|
||||
mlkem/ct/dudect/libmlkem_*.h
|
||||
mlkem/ct/dudect/libmlkem_*.so
|
||||
mlkem/ct/dudect/results/
|
||||
node_modules/
|
||||
playwright-report/
|
||||
QWEN.md
|
||||
target/
|
||||
test-results/
|
||||
tmp/
|
||||
*.eco
|
||||
|
||||
+15
-1
@@ -1,6 +1,6 @@
|
||||
# Lux Post-Quantum Cryptography Makefile
|
||||
|
||||
.PHONY: all test bench clean fmt lint install-deps verify build
|
||||
.PHONY: all test bench clean fmt lint install-deps verify build gen_kats
|
||||
|
||||
# Go parameters
|
||||
GOCMD=go
|
||||
@@ -86,6 +86,20 @@ clean:
|
||||
rm -f coverage.out
|
||||
@echo "✅ Clean complete"
|
||||
|
||||
# Regenerate KAT vector files for crypto/pq/mldsa.
|
||||
#
|
||||
# The generator is deterministic: a second run produces byte-identical
|
||||
# output. The kats package itself has a TestRegen_Deterministic guard
|
||||
# that asserts the checked-in vectors_mldsa{44,65,87}.go files match a
|
||||
# fresh `go run`. After running this target, commit the regenerated
|
||||
# files; the test suite then proves they round-trip.
|
||||
gen_kats:
|
||||
@echo "Regenerating ML-DSA KAT vectors..."
|
||||
GOWORK=off $(GOCMD) run ./pq/mldsa/kats/internal/gen -out pq/mldsa/kats
|
||||
@echo "Validating regenerated vectors..."
|
||||
GOWORK=off $(GOTEST) -count=1 ./pq/mldsa/kats/...
|
||||
@echo "✅ KAT vectors regenerated and validated"
|
||||
|
||||
# Install CI tools
|
||||
install-tools:
|
||||
@echo "🛠️ Installing CI tools..."
|
||||
|
||||
+87
-33
@@ -145,6 +145,23 @@ func PublicKeyToCompressedBytes(pk *PublicKey) []byte {
|
||||
}
|
||||
|
||||
func PublicKeyFromCompressedBytes(pkBytes []byte) (*PublicKey, error) {
|
||||
if len(pkBytes) != PublicKeyLen {
|
||||
return nil, ErrFailedPublicKeyDecompress
|
||||
}
|
||||
// HIGH-1: reject the malformed "infinity bit set, compression bit clear"
|
||||
// encoding (top byte b[0]&0xC0 == 0x40) BEFORE handing the buffer to CIRCL's
|
||||
// SetBytes. In that branch SetBytes treats the input as UNCOMPRESSED
|
||||
// (length G1Size=96) and slices b[1:96] on this canonical 48-byte compressed
|
||||
// buffer → slice-bounds-out-of-range PANIC (ecc/bls12381/g1.go:53). On a
|
||||
// CGO_ENABLED=0 (purego) node — the canonical image — that is an
|
||||
// unauthenticated, consensus-halting DoS via any PoP / peer-handshake / warp
|
||||
// BLS field. The CGO/blst path returns an error for this input (never
|
||||
// panics); rejecting it here in-band restores parity. The canonical
|
||||
// compressed-infinity form (0xc0) falls through to Validate() below, which
|
||||
// already rejects the identity point — so this guard is additive.
|
||||
if pkBytes[0]&0xC0 == 0x40 {
|
||||
return nil, ErrFailedPublicKeyDecompress
|
||||
}
|
||||
pk := new(blssign.PublicKey[blssign.KeyG1SigG2])
|
||||
if err := pk.UnmarshalBinary(pkBytes); err != nil {
|
||||
return nil, ErrFailedPublicKeyDecompress
|
||||
@@ -161,7 +178,16 @@ func PublicKeyToUncompressedBytes(key *PublicKey) []byte {
|
||||
|
||||
func PublicKeyFromValidUncompressedBytes(pkBytes []byte) *PublicKey {
|
||||
pk := new(blssign.PublicKey[blssign.KeyG1SigG2])
|
||||
_ = pk.UnmarshalBinary(pkBytes)
|
||||
if err := pk.UnmarshalBinary(pkBytes); err != nil {
|
||||
return nil
|
||||
}
|
||||
// Identity rejection lives at the ONE deserialization boundary (RESIDUAL C):
|
||||
// Validate() = !IsIdentity() && IsOnG1(), so an identity (or off-curve) key
|
||||
// never escapes a constructor. Downstream Verify therefore does NOT re-check
|
||||
// for the identity point — the check belongs here, once.
|
||||
if !pk.Validate() {
|
||||
return nil
|
||||
}
|
||||
return &PublicKey{pk: pk}
|
||||
}
|
||||
|
||||
@@ -192,36 +218,32 @@ func AggregatePublicKeys(pks []*PublicKey) (*PublicKey, error) {
|
||||
if err := result.UnmarshalBinary(agg.BytesCompressed()); err != nil {
|
||||
return nil, ErrFailedPublicKeyAggregation
|
||||
}
|
||||
// Defence in depth: reject an aggregate that is the IDENTITY (point at
|
||||
// infinity). Each INPUT key is a valid non-identity subgroup point (the
|
||||
// constructors call Validate), and the sum of subgroup points stays on-curve and
|
||||
// in-subgroup — but it can still be the identity when the inputs sum to zero (the
|
||||
// canonical rogue-key shape: pk + (-pk) = O). An identity aggregate public key
|
||||
// makes Verify trivially accept the identity signature (a forgery enabler).
|
||||
// Proof-of-possession at registration already prevents an attacker contributing a
|
||||
// key it cannot produce, but the verifier must NOT depend on that being enforced
|
||||
// everywhere: Validate() = !IsIdentity() && IsOnG1() fails the aggregate closed.
|
||||
if !result.Validate() {
|
||||
return nil, ErrFailedPublicKeyAggregation
|
||||
}
|
||||
return &PublicKey{pk: result}, nil
|
||||
}
|
||||
|
||||
// isIdentityG1 checks if a public key is the identity point (point at infinity).
|
||||
// Returns true if the key is the identity, false otherwise.
|
||||
func isIdentityG1(pk *blssign.PublicKey[blssign.KeyG1SigG2]) bool {
|
||||
// Serialize the public key and check if it's all zeros (compressed identity)
|
||||
pkBytes, err := pk.MarshalBinary()
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
// BLS12-381 G1 compressed identity point is a specific encoding
|
||||
// Check if it matches the identity point encoding
|
||||
for _, b := range pkBytes {
|
||||
if b != 0 {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func Verify(pk *PublicKey, sig *Signature, msg []byte) bool {
|
||||
if pk == nil || pk.pk == nil || sig == nil {
|
||||
return false
|
||||
}
|
||||
// Check that public key is not the identity point (zero-key)
|
||||
// Identity point verification would trivially pass for any signature
|
||||
if isIdentityG1(pk.pk) {
|
||||
return false
|
||||
}
|
||||
// The identity (zero) public key is rejected at the deserialization boundary
|
||||
// (PublicKeyFromCompressedBytes / PublicKeyFromValidUncompressedBytes call
|
||||
// Validate() = !IsIdentity() && IsOnG1()), so a *PublicKey reaching Verify is
|
||||
// already a valid non-identity G1 point. Re-checking here was redundant — and
|
||||
// the old all-zero byte test was WRONG anyway (canonical compressed-G1
|
||||
// infinity is 0xc0||zeros, not 0x00||zeros) — so it is removed (RESIDUAL C):
|
||||
// identity rejection belongs at decode, in one place.
|
||||
return blssign.Verify(pk.pk, msg, sig.sig)
|
||||
}
|
||||
|
||||
@@ -231,10 +253,7 @@ func VerifyProofOfPossession(pk *PublicKey, sig *Signature, msg []byte) bool {
|
||||
if pk == nil || pk.pk == nil || sig == nil {
|
||||
return false
|
||||
}
|
||||
// Check that public key is not the identity point (zero-key)
|
||||
if isIdentityG1(pk.pk) {
|
||||
return false
|
||||
}
|
||||
// Identity (zero) pubkey already rejected at decode (Validate); see Verify.
|
||||
|
||||
// Parse the signature as a G2 point
|
||||
var sigPoint bls12381.G2
|
||||
@@ -287,12 +306,47 @@ func SignatureFromBytes(sigBytes []byte) (*Signature, error) {
|
||||
if len(sigBytes) != SignatureLen {
|
||||
return nil, ErrFailedSignatureDecompress
|
||||
}
|
||||
for _, b := range sigBytes {
|
||||
if b != 0 {
|
||||
return &Signature{sig: sigBytes}, nil
|
||||
}
|
||||
// HIGH-1: reject the malformed "infinity bit set, compression bit clear"
|
||||
// encoding (top byte b[0]&0xC0 == 0x40) BEFORE SetBytes. In that branch
|
||||
// CIRCL treats the input as UNCOMPRESSED (length G2Size=192) and slices
|
||||
// b[1:192] on this canonical 96-byte compressed buffer → slice-bounds-out-of-
|
||||
// range PANIC (ecc/bls12381/g2.go:53). On a CGO_ENABLED=0 (purego) node that
|
||||
// is an unauthenticated, consensus-halting DoS via any peer/warp/quasar BLS
|
||||
// signature field. blst's Uncompress returns an error for this input (never
|
||||
// panics); rejecting it here in-band restores parity. The canonical
|
||||
// compressed-infinity form (0xc0) falls through to the IsIdentity() check
|
||||
// below — so this guard is additive, not a replacement.
|
||||
if sigBytes[0]&0xC0 == 0x40 {
|
||||
return nil, ErrFailedSignatureDecompress
|
||||
}
|
||||
return nil, ErrFailedSignatureDecompress
|
||||
// Validate that the bytes decode to a point that is on-curve AND in the
|
||||
// prime-order r-torsion subgroup of G2 — the exact contract the CGO/blst
|
||||
// path enforces with Uncompress + SigValidate(false). CIRCL's
|
||||
// bls12381.G2.SetBytes performs both checks: it decodes the compressed
|
||||
// point and then calls IsOnG2() (= isValidProjective && isOnCurve &&
|
||||
// isRTorsion) before returning, rejecting any input that is not a valid
|
||||
// subgroup element. Without this, a length-96 non-zero blob that is not a
|
||||
// real signature point would be accepted here (the prior byte-loop only
|
||||
// rejected all-zero), diverging from blst and admitting garbage signatures
|
||||
// into the verifier.
|
||||
var g bls12381.G2
|
||||
if err := g.SetBytes(sigBytes); err != nil {
|
||||
return nil, ErrFailedSignatureDecompress
|
||||
}
|
||||
// Reject the G2 identity (point at infinity) — symmetric with the pubkey
|
||||
// identity guard at decode (Validate, INFO-4). CIRCL's SetBytes accepts a well-formed
|
||||
// infinity encoding (0xc0 || zeros) and returns at the isInfinity branch BEFORE
|
||||
// IsOnG2, so without this the identity signature would deserialize cleanly; blst
|
||||
// SigValidate(false) likewise skips the infinity check. The identity sig does
|
||||
// not forge against a real key, but accepting it is an asymmetry with the pubkey
|
||||
// path and admits a degenerate point into the verifier — reject it here.
|
||||
if g.IsIdentity() {
|
||||
return nil, ErrFailedSignatureDecompress
|
||||
}
|
||||
// Store the validated compressed bytes; blssign.Signature is the raw
|
||||
// compressed form and blssign.Verify re-derives the point internally, so we
|
||||
// keep the canonical wire bytes (round-trips through SignatureToBytes).
|
||||
return &Signature{sig: sigBytes}, nil
|
||||
}
|
||||
|
||||
func AggregateSignatures(sigs []*Signature) (*Signature, error) {
|
||||
|
||||
+41
-26
@@ -162,7 +162,16 @@ func PublicKeyToUncompressedBytes(key *PublicKey) []byte {
|
||||
// are valid.
|
||||
func PublicKeyFromValidUncompressedBytes(pkBytes []byte) *PublicKey {
|
||||
pk := new(blst.P1Affine)
|
||||
pk.Deserialize(pkBytes)
|
||||
if pk.Deserialize(pkBytes) == nil {
|
||||
return nil
|
||||
}
|
||||
// Identity rejection lives at the ONE deserialization boundary (RESIDUAL C):
|
||||
// KeyValidate() rejects the infinity point (and off-curve / wrong-subgroup),
|
||||
// so an identity key never escapes a constructor. Downstream Verify therefore
|
||||
// does NOT re-check for the identity point — the check belongs here, once.
|
||||
if !pk.KeyValidate() {
|
||||
return nil
|
||||
}
|
||||
return &PublicKey{pk: pk}
|
||||
}
|
||||
|
||||
@@ -183,22 +192,20 @@ func AggregatePublicKeys(pks []*PublicKey) (*PublicKey, error) {
|
||||
}
|
||||
}
|
||||
|
||||
return &PublicKey{pk: agg.ToAffine()}, nil
|
||||
}
|
||||
|
||||
// isIdentityG1 checks if a public key is the identity point (point at infinity).
|
||||
// Returns true if the key is the identity, false otherwise.
|
||||
func isIdentityG1(pk *blst.P1Affine) bool {
|
||||
// Check if the point is at infinity using blst's built-in check
|
||||
// The identity point in G1 is represented as all zeros in compressed form
|
||||
pkBytes := pk.Compress()
|
||||
// Check for all-zero bytes (identity point encoding)
|
||||
for _, b := range pkBytes {
|
||||
if b != 0 {
|
||||
return false
|
||||
}
|
||||
// Defence in depth: reject an aggregate that is the IDENTITY (point at
|
||||
// infinity). Each INPUT key is a valid non-identity subgroup point (the
|
||||
// constructors call KeyValidate), and the sum of subgroup points stays on-curve
|
||||
// and in-subgroup — but it can still be the identity when the inputs sum to zero
|
||||
// (the canonical rogue-key shape: pk + (-pk) = O). An identity aggregate public
|
||||
// key makes Verify trivially accept the identity signature (a forgery enabler).
|
||||
// blst's KeyValidate rejects the infinity point (and off-curve / wrong-subgroup),
|
||||
// matching the purego path's result.Validate() — fail the aggregate closed rather
|
||||
// than depend on proof-of-possession being enforced upstream everywhere.
|
||||
out := agg.ToAffine()
|
||||
if !out.KeyValidate() {
|
||||
return nil, ErrFailedPublicKeyAggregation
|
||||
}
|
||||
return true
|
||||
return &PublicKey{pk: out}, nil
|
||||
}
|
||||
|
||||
// Verify the [sig] of [msg] against the [pk].
|
||||
@@ -206,11 +213,13 @@ func Verify(pk *PublicKey, sig *Signature, msg []byte) bool {
|
||||
if pk == nil || pk.pk == nil || sig == nil || sig.sig == nil {
|
||||
return false
|
||||
}
|
||||
// Check that public key is not the identity point (zero-key)
|
||||
// Identity point verification would trivially pass for any signature
|
||||
if isIdentityG1(pk.pk) {
|
||||
return false
|
||||
}
|
||||
// The identity (zero) public key is rejected at the deserialization boundary
|
||||
// (PublicKeyFromCompressedBytes / PublicKeyFromValidUncompressedBytes call
|
||||
// KeyValidate(), which rejects the infinity point), so a *PublicKey reaching
|
||||
// Verify is already a valid non-identity G1 point. Re-checking here was
|
||||
// redundant — and the old all-zero byte test was WRONG anyway (blst Compress()
|
||||
// of the identity is 0xc0||zeros, not 0x00||zeros, so it never actually
|
||||
// matched) — removed (RESIDUAL C): identity rejection belongs at decode, once.
|
||||
return sig.sig.Verify(true, pk.pk, false, msg, dstSignature)
|
||||
}
|
||||
|
||||
@@ -219,10 +228,7 @@ func VerifyProofOfPossession(pk *PublicKey, sig *Signature, msg []byte) bool {
|
||||
if pk == nil || pk.pk == nil || sig == nil || sig.sig == nil {
|
||||
return false
|
||||
}
|
||||
// Check that public key is not the identity point (zero-key)
|
||||
if isIdentityG1(pk.pk) {
|
||||
return false
|
||||
}
|
||||
// Identity (zero) pubkey already rejected at decode (KeyValidate); see Verify.
|
||||
return sig.sig.Verify(true, pk.pk, false, msg, dstPoP)
|
||||
}
|
||||
|
||||
@@ -247,7 +253,16 @@ func SignatureFromBytes(sigBytes []byte) (*Signature, error) {
|
||||
return nil, ErrFailedSignatureDecompress
|
||||
}
|
||||
|
||||
if !sig.SigValidate(false) {
|
||||
// SigValidate(true) checks BOTH r-torsion subgroup membership AND rejects the
|
||||
// G2 identity (point at infinity) — go_p2_affine_validate(p, infcheck=true) is
|
||||
// `if is_inf(p) return false; return in_g2(p)`. The prior SigValidate(false)
|
||||
// skipped the infinity check, accepting the identity signature (INFO-4); this
|
||||
// makes the blst path symmetric with the purego SignatureFromBytes identity
|
||||
// reject and with the pubkey identity guard at decode (KeyValidate). The
|
||||
// identity sig does not forge
|
||||
// against a real key, but admitting a degenerate point into the verifier is an
|
||||
// asymmetry worth closing.
|
||||
if !sig.SigValidate(true) {
|
||||
return nil, ErrInvalidSignature
|
||||
}
|
||||
|
||||
|
||||
+34
@@ -0,0 +1,34 @@
|
||||
// Copyright (C) 2020-2025, Lux Industries Inc. All rights reserved.
|
||||
// See the file LICENSE for licensing terms.
|
||||
|
||||
package hash
|
||||
|
||||
import (
|
||||
// Ethereum Keccak-256 (0x01 domain pad), NOT FIPS-202 SHA3-256 (0x06 pad).
|
||||
// NewLegacyKeccak256 is the legacy (pre-standardization) Keccak that every
|
||||
// Lux GPU backend and EVM-compatible consumer hashes against; sha3.Sum256
|
||||
// would diverge byte-for-byte. Do not swap it.
|
||||
"golang.org/x/crypto/sha3"
|
||||
)
|
||||
|
||||
// KeccakSize is the byte length of a Keccak-256 digest.
|
||||
const KeccakSize = 32
|
||||
|
||||
// ComputeKeccak256Array computes the Ethereum Keccak-256 hash of the
|
||||
// concatenation of the input byte slices.
|
||||
func ComputeKeccak256Array(data ...[]byte) [KeccakSize]byte {
|
||||
h := sha3.NewLegacyKeccak256()
|
||||
for _, b := range data {
|
||||
h.Write(b)
|
||||
}
|
||||
var out [KeccakSize]byte
|
||||
h.Sum(out[:0])
|
||||
return out
|
||||
}
|
||||
|
||||
// ComputeKeccak256 computes the Ethereum Keccak-256 hash of the concatenation
|
||||
// of the input byte slices.
|
||||
func ComputeKeccak256(data ...[]byte) []byte {
|
||||
out := ComputeKeccak256Array(data...)
|
||||
return out[:]
|
||||
}
|
||||
+3
-3
@@ -16,9 +16,9 @@ import (
|
||||
)
|
||||
|
||||
var (
|
||||
once sync.Once
|
||||
sess *accel.Session
|
||||
initErr error
|
||||
once sync.Once
|
||||
sess *accel.Session
|
||||
initErr error
|
||||
available bool
|
||||
)
|
||||
|
||||
|
||||
+31
-11
@@ -26,12 +26,12 @@ var concurrentBatchThreshold = 8
|
||||
//
|
||||
// Dispatch ladder:
|
||||
//
|
||||
// 1. GPU substrate (accel.LatticeOps.MLDSAVerifyBatch) when n >= BatchThreshold
|
||||
// AND a backend plugin is loaded AND mode is in {44, 65, 87}.
|
||||
// 2. Goroutine-parallel CPU verify when n >= concurrentBatchThreshold.
|
||||
// Scales to GOMAXPROCS without GPU substrate. Useful on hosts that
|
||||
// have CPU cores but no GPU plugin (Linux CI, no-Metal Macs, etc).
|
||||
// 3. Serial CPU verify as the floor.
|
||||
// 1. GPU substrate (accel.LatticeOps.MLDSAVerifyBatch) when n >= BatchThreshold
|
||||
// AND a backend plugin is loaded AND mode is in {44, 65, 87}.
|
||||
// 2. Goroutine-parallel CPU verify when n >= concurrentBatchThreshold.
|
||||
// Scales to GOMAXPROCS without GPU substrate. Useful on hosts that
|
||||
// have CPU cores but no GPU plugin (Linux CI, no-Metal Macs, etc).
|
||||
// 3. Serial CPU verify as the floor.
|
||||
//
|
||||
// All paths are byte-equal: each path ends in cloudflare/circl's
|
||||
// FIPS 204-conformant Verify. The dispatch choice only affects throughput,
|
||||
@@ -56,9 +56,21 @@ func BatchVerify(pubs []*PublicKey, msgs [][]byte, sigs [][]byte) []bool {
|
||||
}
|
||||
|
||||
// Tier 1: GPU substrate.
|
||||
//
|
||||
// Red M-1: batchVerifyGPU returns (false, accel.ErrInvalidArgument) when
|
||||
// the C ABI rejects the input as malformed (length / count cap, null
|
||||
// ptr). The CPU oracle may accept what GPU rejects → consensus split.
|
||||
// Panic here — BatchVerify returns no error, and a contract-violating
|
||||
// input deserves the same shape as the existing length-mismatch /
|
||||
// mixed-mode panics above. Recoverable GPU errors (NotSupported,
|
||||
// OutOfMemory, kernel failure) return (false, nil) and fall through.
|
||||
if n >= BatchThreshold {
|
||||
if _, ok := modeToCAPI(mode); ok {
|
||||
if ok, err := batchVerifyGPU(pubs, msgs, sigs, out); ok && err == nil {
|
||||
ok, err := batchVerifyGPU(pubs, msgs, sigs, out)
|
||||
if err != nil {
|
||||
panic("mldsa.BatchVerify: GPU dispatch rejected input as malformed: " + err.Error())
|
||||
}
|
||||
if ok {
|
||||
return out
|
||||
}
|
||||
}
|
||||
@@ -131,9 +143,9 @@ var ErrBatchLength = errors.New("mldsa: batch input slices have inconsistent len
|
||||
//
|
||||
// Dispatch ladder mirrors BatchVerify:
|
||||
//
|
||||
// 1. GPU substrate (accel.LatticeOps.MLDSASignBatch).
|
||||
// 2. Goroutine-parallel CPU sign.
|
||||
// 3. Serial CPU sign.
|
||||
// 1. GPU substrate (accel.LatticeOps.MLDSASignBatch).
|
||||
// 2. Goroutine-parallel CPU sign.
|
||||
// 3. Serial CPU sign.
|
||||
//
|
||||
// For deterministic-mode signing (FIPS 204 § Algorithm 2 with rnd=0^256),
|
||||
// callers can pass nil for randSource. The CPU path passes deterministic=true
|
||||
@@ -156,9 +168,17 @@ func BatchSign(randSource io.Reader, privs []*PrivateKey, msgs [][]byte) ([][]by
|
||||
}
|
||||
|
||||
// Tier 1: GPU substrate.
|
||||
//
|
||||
// Red M-1: batchSignGPU returns (false, accel.ErrInvalidArgument) on
|
||||
// malformed input. Propagate as a real error here (BatchSign already
|
||||
// returns error); other GPU errors fall through to CPU silently.
|
||||
if n >= BatchThreshold {
|
||||
if _, ok := modeToCAPI(mode); ok {
|
||||
if ok, err := batchSignGPU(privs, msgs, sigs); ok && err == nil {
|
||||
ok, err := batchSignGPU(privs, msgs, sigs)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if ok {
|
||||
return sigs, nil
|
||||
}
|
||||
}
|
||||
|
||||
+29
-4
@@ -39,6 +39,8 @@
|
||||
package mldsa
|
||||
|
||||
import (
|
||||
"errors"
|
||||
|
||||
"github.com/luxfi/accel"
|
||||
"github.com/luxfi/crypto/backend"
|
||||
"github.com/luxfi/crypto/internal/gpuhost"
|
||||
@@ -66,14 +68,21 @@ func modeToCAPI(m Mode) (int, bool) {
|
||||
// API enforces this; this entrypoint is internal and trusts the contract).
|
||||
//
|
||||
// Returns (true, nil) when the GPU path produced `out`. Returns (false, nil)
|
||||
// in any of these cases:
|
||||
// in any of these cases (caller may fall back to CPU):
|
||||
//
|
||||
// - CRYPTO_BACKEND is not GPU
|
||||
// - gpuhost has no accel session
|
||||
// - the mode is not wired for GPU dispatch
|
||||
// - the substrate returns NotSupported (no plugin loaded)
|
||||
// - any tensor allocation or kernel dispatch failed (we fall through
|
||||
// silently to CPU; the caller's per-element loop is the safety net)
|
||||
// - tensor allocation failed (OutOfMemory) or kernel dispatch failed
|
||||
//
|
||||
// Returns (false, accel.ErrInvalidArgument) when the C ABI rejects the input
|
||||
// as malformed (msg_len > LUX_GPU_MLDSA_MSG_LEN_CAP, count > UINT32_MAX, null
|
||||
// pointer with non-zero length). The CPU oracle (cloudflare/circl) may accept
|
||||
// what the GPU wrapper rejects (FIPS 204 allows arbitrary-length messages),
|
||||
// so silently falling back would produce a verdict on one backend and not the
|
||||
// other across the same input — consensus split. Red M-1 contract: callers
|
||||
// MUST propagate ErrInvalidArgument as a hard error, never silently fall back.
|
||||
//
|
||||
// `out` is only written when the function returns (true, nil).
|
||||
func batchVerifyGPU(pubs []*PublicKey, msgs [][]byte, sigs [][]byte, out []bool) (bool, error) {
|
||||
@@ -160,11 +169,22 @@ func batchVerifyGPU(pubs []*PublicKey, msgs [][]byte, sigs [][]byte, out []bool)
|
||||
// Try the new mode-aware MLDSAVerifyBatch first. When ML-DSA-65 is in use
|
||||
// fall back to the legacy DilithiumVerifyBatch for substrates that only
|
||||
// publish the Dilithium3 kernel (the original wiring).
|
||||
//
|
||||
// Red M-1: ErrInvalidArgument is a HARD error. The GPU wrapper rejected
|
||||
// the input as violating the contract (length cap, count cap, null with
|
||||
// non-zero len). The CPU oracle may accept what the GPU wrapper rejects
|
||||
// → consensus split between CPU-only and GPU-accelerated verifiers. Do
|
||||
// not silently fall back; surface the error so the caller can panic /
|
||||
// reject the batch. Other errors (NotSupported, OutOfMemory, kernel
|
||||
// failure) are recoverable — CPU fallback is correct for those.
|
||||
dispatchErr := sess.Lattice().MLDSAVerifyBatch(capiMode, mT.Untyped(), sT.Untyped(), pT.Untyped(), rT.Untyped())
|
||||
if dispatchErr != nil && mode == MLDSA65 {
|
||||
if dispatchErr != nil && mode == MLDSA65 && !errors.Is(dispatchErr, accel.ErrInvalidArgument) {
|
||||
dispatchErr = sess.Lattice().DilithiumVerifyBatch(mT.Untyped(), sT.Untyped(), pT.Untyped(), rT.Untyped())
|
||||
}
|
||||
if dispatchErr != nil {
|
||||
if errors.Is(dispatchErr, accel.ErrInvalidArgument) {
|
||||
return false, dispatchErr
|
||||
}
|
||||
return false, nil
|
||||
}
|
||||
bytes, err := rT.ToSlice()
|
||||
@@ -257,7 +277,12 @@ func batchSignGPU(privs []*PrivateKey, msgs [][]byte, sigs [][]byte) (bool, erro
|
||||
}
|
||||
defer sigT.Close()
|
||||
|
||||
// Red M-1: ErrInvalidArgument is a HARD error (see batchVerifyGPU). Other
|
||||
// errors silently fall back to CPU.
|
||||
if err := sess.Lattice().MLDSASignBatch(capiMode, mT.Untyped(), skT.Untyped(), sigT.Untyped()); err != nil {
|
||||
if errors.Is(err, accel.ErrInvalidArgument) {
|
||||
return false, err
|
||||
}
|
||||
return false, nil
|
||||
}
|
||||
|
||||
|
||||
+6
-6
@@ -50,12 +50,12 @@ func (t DispatchTier) String() string {
|
||||
// Provenance is the auditable evidence record for the ML-DSA package.
|
||||
// See slhdsa.Provenance — same shape, same purpose.
|
||||
type Provenance struct {
|
||||
Tier DispatchTier
|
||||
AccelInitialised bool
|
||||
DeviceAvailable bool
|
||||
PluginStrongSymbol bool
|
||||
BatchThresholdN int
|
||||
ConcurrentThresholdN int
|
||||
Tier DispatchTier
|
||||
AccelInitialised bool
|
||||
DeviceAvailable bool
|
||||
PluginStrongSymbol bool
|
||||
BatchThresholdN int
|
||||
ConcurrentThresholdN int
|
||||
}
|
||||
|
||||
// GetProvenance returns the current dispatch provenance.
|
||||
|
||||
+1
-1
@@ -15,7 +15,7 @@ require (
|
||||
github.com/stretchr/testify v1.9.0
|
||||
github.com/luxfi/geth v1.16.34
|
||||
github.com/luxfi/lattice/v6 v6.1.1
|
||||
github.com/luxfi/corona v0.1.0
|
||||
github.com/luxfi/corona v0.7.6
|
||||
)
|
||||
|
||||
replace (
|
||||
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
geth (luxfi/geth)
|
||||
Copyright (c) 2020-2025 Lux Industries Inc.
|
||||
|
||||
This product includes software from go-ethereum (https://github.com/ethereum/go-ethereum), licensed under LGPL-3.0:
|
||||
|
||||
Copyright 2013-2025 The go-ethereum Authors
|
||||
|
||||
The go-ethereum library files retain their original GNU Lesser General Public
|
||||
License v3.0 (see COPYING.LESSER); the standalone command-line binaries retain
|
||||
the GNU General Public License v3.0 (see COPYING). Lux modifications are
|
||||
contributed under the same terms.
|
||||
+6
-5
@@ -1,12 +1,13 @@
|
||||
// Copyright (C) 2019-2025, Lux Industries Inc. All rights reserved.
|
||||
// See the file LICENSE for licensing terms.
|
||||
|
||||
// zap.go — load a BIP-39 mnemonic from KMS over native ZAP.
|
||||
// zap.go — load a BIP-39 mnemonic from Liquid KMS over native ZAP.
|
||||
//
|
||||
// This file is the one canonical path every Lux-derived service uses
|
||||
// to resolve the bootstrap mnemonic: luxd, netrunner, lux/cli, and any
|
||||
// descending L1's bootstrap. No file mount, no projected volume, no
|
||||
// per-consumer copy of the env-vs-KMS precedence chain.
|
||||
// descending L1's bootstrap (liquidity/network-bootstrap, hanzo-bootstrap,
|
||||
// zoo-bootstrap, …). No file mount, no projected volume, no per-consumer
|
||||
// copy of the env-vs-KMS precedence chain.
|
||||
//
|
||||
// Separation of concerns:
|
||||
//
|
||||
@@ -20,7 +21,7 @@
|
||||
// Precedence (env wins; KMS is the production fallback):
|
||||
//
|
||||
// 1. MNEMONIC env var local dev + CI test seam
|
||||
// 2. KMS at (addr, env, path) native ZAP from KMS
|
||||
// 2. KMS at (addr, env, path) native ZAP from Liquid KMS
|
||||
|
||||
package keys
|
||||
|
||||
@@ -74,7 +75,7 @@ var dialKMS = func(ctx context.Context, addr string, identity *ServiceIdentity)
|
||||
// `addr` and reads the secret at `path` under `env`.
|
||||
//
|
||||
// ctx cancellable context
|
||||
// addr KMS host:port (e.g. "kms.default.svc:9999")
|
||||
// addr KMS host:port (e.g. "kms.internal.svc:9999")
|
||||
// env KMS env scope ("mainnet" | "testnet" | "devnet")
|
||||
// path KMS secret path (e.g. "/mnemonic" or "/foo/master")
|
||||
// identity ServiceIdentity to sign the secret-opcode envelope. May
|
||||
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
BSD 3-Clause License
|
||||
|
||||
Copyright (c) 2024, Lux Partners Limited
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
3. Neither the name of the copyright holder nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
# Licensing
|
||||
|
||||
This repository is licensed under the **BSD 3-Clause License** (see
|
||||
[LICENSE](LICENSE)). It belongs to the **public** tier of the Lux
|
||||
three-tier IP strategy: anyone may use, fork, or redistribute it,
|
||||
including for commercial purposes, subject to the BSD-3 terms.
|
||||
|
||||
For the canonical Lux IP and licensing strategy, see:
|
||||
<https://github.com/luxfi/.github/blob/main/profile/README.md>
|
||||
|
||||
For commercial inquiries that go beyond BSD-3 (e.g. private moat
|
||||
acceleration kernels), contact `licensing@lux.network`.
|
||||
+37
@@ -0,0 +1,37 @@
|
||||
# LLM.md - Hanzo Log
|
||||
|
||||
## Overview
|
||||
Go module: github.com/luxfi/log
|
||||
|
||||
## Tech Stack
|
||||
- **Language**: Go
|
||||
|
||||
## Build & Run
|
||||
```bash
|
||||
go build ./...
|
||||
go test ./...
|
||||
```
|
||||
|
||||
## Structure
|
||||
```
|
||||
log/
|
||||
LICENSE
|
||||
README.md
|
||||
array.go
|
||||
benchmark_test.go
|
||||
console.go
|
||||
context.go
|
||||
ctx.go
|
||||
encoder.go
|
||||
encoder_json.go
|
||||
error_marshal_test.go
|
||||
event.go
|
||||
factory.go
|
||||
fields.go
|
||||
fixtures_test.go
|
||||
geth.go
|
||||
```
|
||||
|
||||
## Key Files
|
||||
- `README.md` -- Project documentation
|
||||
- `go.mod` -- Go module definition
|
||||
+4
-7
@@ -101,9 +101,9 @@ type ConsoleWriter struct {
|
||||
// NewConsoleWriter creates and initializes a new ConsoleWriter.
|
||||
func NewConsoleWriter(options ...func(w *ConsoleWriter)) ConsoleWriter {
|
||||
w := ConsoleWriter{
|
||||
Out: os.Stdout,
|
||||
TimeFormat: consoleDefaultTimeFormat,
|
||||
PartsOrder: consoleDefaultPartsOrder(),
|
||||
Out: os.Stdout,
|
||||
TimeFormat: consoleDefaultTimeFormat,
|
||||
PartsOrder: consoleDefaultPartsOrder(),
|
||||
}
|
||||
|
||||
for _, opt := range options {
|
||||
@@ -120,10 +120,7 @@ func NewConsoleWriter(options ...func(w *ConsoleWriter)) ConsoleWriter {
|
||||
|
||||
// Write transforms the JSON input with formatters and appends to w.Out.
|
||||
func (w ConsoleWriter) Write(p []byte) (n int, err error) {
|
||||
// Fix color on Windows
|
||||
if w.Out == os.Stdout || w.Out == os.Stderr {
|
||||
w.Out = colorable.NewColorable(w.Out.(*os.File))
|
||||
}
|
||||
// Note: colorable wrapping is done once in NewConsoleWriter, not on every Write
|
||||
|
||||
if w.PartsOrder == nil {
|
||||
w.PartsOrder = consoleDefaultPartsOrder()
|
||||
|
||||
+4
-1
@@ -8,7 +8,10 @@ import (
|
||||
var disabledLogger Logger
|
||||
|
||||
func init() {
|
||||
SetGlobalLevel(TraceLevel)
|
||||
// Global level defaults to DebugLevel (zero value of Level = 0).
|
||||
// Applications that want trace output must call SetGlobalLevel(TraceLevel).
|
||||
// Do NOT reset to TraceLevel here -- it causes debug spam from dependency
|
||||
// init() functions before the application configures its own log level.
|
||||
disabledLogger = Noop()
|
||||
}
|
||||
|
||||
|
||||
+43
-37
@@ -87,7 +87,8 @@ type factory struct {
|
||||
|
||||
// factoryLogger wraps a Logger with factory-managed level controls.
|
||||
type factoryLogger struct {
|
||||
Logger
|
||||
Logger // current logger with level applied
|
||||
baseLogger Logger // base logger without level (for SetLogLevel)
|
||||
level Level
|
||||
displayLevel Level
|
||||
name string
|
||||
@@ -120,7 +121,7 @@ func (f *factory) Make(name string) (Logger, error) {
|
||||
return Noop(), nil
|
||||
}
|
||||
|
||||
// Return existing logger if already created
|
||||
// Return existing logger if already created (reflects any SetLogLevel changes)
|
||||
if l, exists := f.loggers[name]; exists {
|
||||
return l.Logger, nil
|
||||
}
|
||||
@@ -179,12 +180,13 @@ func (f *factory) Make(name string) (Logger, error) {
|
||||
w = io.MultiWriter(writers...)
|
||||
}
|
||||
|
||||
// Create logger
|
||||
logger := NewWriter(w).With().Timestamp().Str("logger", name).Logger()
|
||||
logger = logger.Level(f.config.LogLevel)
|
||||
// Create logger - store base logger separately so SetLogLevel can recreate with new level
|
||||
baseLogger := NewWriter(w).With().Timestamp().Str("logger", name).Logger()
|
||||
logger := baseLogger.Level(f.config.LogLevel)
|
||||
|
||||
fl := &factoryLogger{
|
||||
Logger: logger,
|
||||
baseLogger: baseLogger,
|
||||
level: f.config.LogLevel,
|
||||
displayLevel: f.config.DisplayLevel,
|
||||
name: name,
|
||||
@@ -192,7 +194,7 @@ func (f *factory) Make(name string) (Logger, error) {
|
||||
}
|
||||
f.loggers[name] = fl
|
||||
|
||||
return logger, nil
|
||||
return fl.Logger, nil
|
||||
}
|
||||
|
||||
// MakeChain creates a logger for a blockchain.
|
||||
@@ -220,6 +222,10 @@ func (f *factory) SetLogLevel(name string, level Level) {
|
||||
|
||||
if l, exists := f.loggers[name]; exists {
|
||||
l.level = level
|
||||
// Recreate logger with new level using the base logger
|
||||
if l.baseLogger != nil {
|
||||
l.Logger = l.baseLogger.Level(level)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -269,37 +275,37 @@ func (f *factory) Close() {
|
||||
// NoLog is a no-op logger for use in tests or when logging is disabled.
|
||||
type NoLog struct{}
|
||||
|
||||
func (NoLog) Output(io.Writer) Logger { return Noop() }
|
||||
func (NoLog) With() Context { return Context{} }
|
||||
func (NoLog) Level(Level) Logger { return Noop() }
|
||||
func (NoLog) GetLevel() Level { return Disabled }
|
||||
func (NoLog) New(...interface{}) Logger { return Noop() }
|
||||
func (NoLog) Sample(Sampler) Logger { return Noop() }
|
||||
func (NoLog) Hook(...Hook) Logger { return Noop() }
|
||||
func (NoLog) Trace(string, ...interface{}) {}
|
||||
func (NoLog) Debug(string, ...interface{}) {}
|
||||
func (NoLog) Info(string, ...interface{}) {}
|
||||
func (NoLog) Warn(string, ...interface{}) {}
|
||||
func (NoLog) Error(string, ...interface{}) {}
|
||||
func (NoLog) Fatal(string, ...interface{}) {}
|
||||
func (NoLog) Panic(string, ...interface{}) {}
|
||||
func (NoLog) Crit(string, ...interface{}) {}
|
||||
func (NoLog) Verbo(string, ...interface{}) {}
|
||||
func (NoLog) Output(io.Writer) Logger { return Noop() }
|
||||
func (NoLog) With() Context { return Context{} }
|
||||
func (NoLog) Level(Level) Logger { return Noop() }
|
||||
func (NoLog) GetLevel() Level { return Disabled }
|
||||
func (NoLog) New(...interface{}) Logger { return Noop() }
|
||||
func (NoLog) Sample(Sampler) Logger { return Noop() }
|
||||
func (NoLog) Hook(...Hook) Logger { return Noop() }
|
||||
func (NoLog) Trace(string, ...interface{}) {}
|
||||
func (NoLog) Debug(string, ...interface{}) {}
|
||||
func (NoLog) Info(string, ...interface{}) {}
|
||||
func (NoLog) Warn(string, ...interface{}) {}
|
||||
func (NoLog) Error(string, ...interface{}) {}
|
||||
func (NoLog) Fatal(string, ...interface{}) {}
|
||||
func (NoLog) Panic(string, ...interface{}) {}
|
||||
func (NoLog) Crit(string, ...interface{}) {}
|
||||
func (NoLog) Verbo(string, ...interface{}) {}
|
||||
func (NoLog) Log(Level, string, ...interface{}) {}
|
||||
func (NoLog) TraceEvent() *Event { return nil }
|
||||
func (NoLog) DebugEvent() *Event { return nil }
|
||||
func (NoLog) InfoEvent() *Event { return nil }
|
||||
func (NoLog) WarnEvent() *Event { return nil }
|
||||
func (NoLog) ErrorEvent() *Event { return nil }
|
||||
func (NoLog) FatalEvent() *Event { return nil }
|
||||
func (NoLog) PanicEvent() *Event { return nil }
|
||||
func (NoLog) Err(error) *Event { return nil }
|
||||
func (NoLog) WithLevel(Level) *Event { return nil }
|
||||
func (NoLog) LogEvent() *Event { return nil }
|
||||
func (NoLog) Print(...interface{}) {}
|
||||
func (NoLog) Printf(string, ...interface{}) {}
|
||||
func (NoLog) Write(p []byte) (int, error) { return len(p), nil }
|
||||
func (NoLog) SetLogLevel(string) error { return nil }
|
||||
func (NoLog) TraceEvent() *Event { return nil }
|
||||
func (NoLog) DebugEvent() *Event { return nil }
|
||||
func (NoLog) InfoEvent() *Event { return nil }
|
||||
func (NoLog) WarnEvent() *Event { return nil }
|
||||
func (NoLog) ErrorEvent() *Event { return nil }
|
||||
func (NoLog) FatalEvent() *Event { return nil }
|
||||
func (NoLog) PanicEvent() *Event { return nil }
|
||||
func (NoLog) Err(error) *Event { return nil }
|
||||
func (NoLog) WithLevel(Level) *Event { return nil }
|
||||
func (NoLog) LogEvent() *Event { return nil }
|
||||
func (NoLog) Print(...interface{}) {}
|
||||
func (NoLog) Printf(string, ...interface{}) {}
|
||||
func (NoLog) Write(p []byte) (int, error) { return len(p), nil }
|
||||
func (NoLog) SetLogLevel(string) error { return nil }
|
||||
func (NoLog) RecoverAndPanic(fn func()) {
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
@@ -308,7 +314,7 @@ func (NoLog) RecoverAndPanic(fn func()) {
|
||||
}()
|
||||
fn()
|
||||
}
|
||||
func (NoLog) IsZero() bool { return true }
|
||||
func (NoLog) IsZero() bool { return true }
|
||||
func (NoLog) Enabled(context.Context, slog.Level) bool { return false }
|
||||
|
||||
// ToLevel parses a level string and returns the corresponding Level.
|
||||
|
||||
+41
-35
@@ -6,6 +6,7 @@ package log
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"runtime"
|
||||
"strconv"
|
||||
"time"
|
||||
)
|
||||
@@ -26,51 +27,57 @@ type Field struct {
|
||||
}
|
||||
|
||||
// Field constructors for geth-style logging
|
||||
func String(key, val string) Field { return Field{Key: key, Value: val} }
|
||||
func Stringer(key string, val fmt.Stringer) Field { return Field{Key: key, Value: val} }
|
||||
func Int(key string, val int) Field { return Field{Key: key, Value: val} }
|
||||
func Int8(key string, val int8) Field { return Field{Key: key, Value: val} }
|
||||
func Int16(key string, val int16) Field { return Field{Key: key, Value: val} }
|
||||
func Int32(key string, val int32) Field { return Field{Key: key, Value: val} }
|
||||
func Int64(key string, val int64) Field { return Field{Key: key, Value: val} }
|
||||
func Uint(key string, val uint) Field { return Field{Key: key, Value: val} }
|
||||
func Uint8(key string, val uint8) Field { return Field{Key: key, Value: val} }
|
||||
func Uint16(key string, val uint16) Field { return Field{Key: key, Value: val} }
|
||||
func Uint32(key string, val uint32) Field { return Field{Key: key, Value: val} }
|
||||
func Uint64(key string, val uint64) Field { return Field{Key: key, Value: val} }
|
||||
func Float32(key string, val float32) Field { return Field{Key: key, Value: val} }
|
||||
func Float64(key string, val float64) Field { return Field{Key: key, Value: val} }
|
||||
func Bool(key string, val bool) Field { return Field{Key: key, Value: val} }
|
||||
func String(key, val string) Field { return Field{Key: key, Value: val} }
|
||||
func Stringer(key string, val fmt.Stringer) Field { return Field{Key: key, Value: val} }
|
||||
func Int(key string, val int) Field { return Field{Key: key, Value: val} }
|
||||
func Int8(key string, val int8) Field { return Field{Key: key, Value: val} }
|
||||
func Int16(key string, val int16) Field { return Field{Key: key, Value: val} }
|
||||
func Int32(key string, val int32) Field { return Field{Key: key, Value: val} }
|
||||
func Int64(key string, val int64) Field { return Field{Key: key, Value: val} }
|
||||
func Uint(key string, val uint) Field { return Field{Key: key, Value: val} }
|
||||
func Uint8(key string, val uint8) Field { return Field{Key: key, Value: val} }
|
||||
func Uint16(key string, val uint16) Field { return Field{Key: key, Value: val} }
|
||||
func Uint32(key string, val uint32) Field { return Field{Key: key, Value: val} }
|
||||
func Uint64(key string, val uint64) Field { return Field{Key: key, Value: val} }
|
||||
func Float32(key string, val float32) Field { return Field{Key: key, Value: val} }
|
||||
func Float64(key string, val float64) Field { return Field{Key: key, Value: val} }
|
||||
func Bool(key string, val bool) Field { return Field{Key: key, Value: val} }
|
||||
func Duration(key string, val time.Duration) Field { return Field{Key: key, Value: val} }
|
||||
func Time(key string, val time.Time) Field { return Field{Key: key, Value: val} }
|
||||
func Err(err error) Field { return Field{Key: ErrorFieldName, Value: err} }
|
||||
func NamedErr(key string, err error) Field { return Field{Key: key, Value: err} }
|
||||
func Any(key string, val interface{}) Field { return Field{Key: key, Value: val} }
|
||||
func Binary(key string, val []byte) Field { return Field{Key: key, Value: val} }
|
||||
func ByteString(key string, val []byte) Field { return Field{Key: key, Value: string(val)} }
|
||||
func Time(key string, val time.Time) Field { return Field{Key: key, Value: val} }
|
||||
func Err(err error) Field { return Field{Key: ErrorFieldName, Value: err} }
|
||||
func NamedErr(key string, err error) Field { return Field{Key: key, Value: err} }
|
||||
func Any(key string, val interface{}) Field { return Field{Key: key, Value: val} }
|
||||
func Binary(key string, val []byte) Field { return Field{Key: key, Value: val} }
|
||||
func ByteString(key string, val []byte) Field { return Field{Key: key, Value: string(val)} }
|
||||
|
||||
// Slice field constructors
|
||||
func Strings(key string, val []string) Field { return Field{Key: key, Value: val} }
|
||||
func Ints(key string, val []int) Field { return Field{Key: key, Value: val} }
|
||||
func Int64s(key string, val []int64) Field { return Field{Key: key, Value: val} }
|
||||
func Uint64s(key string, val []uint64) Field { return Field{Key: key, Value: val} }
|
||||
func Float64s(key string, val []float64) Field { return Field{Key: key, Value: val} }
|
||||
func Bools(key string, val []bool) Field { return Field{Key: key, Value: val} }
|
||||
func Strings(key string, val []string) Field { return Field{Key: key, Value: val} }
|
||||
func Ints(key string, val []int) Field { return Field{Key: key, Value: val} }
|
||||
func Int64s(key string, val []int64) Field { return Field{Key: key, Value: val} }
|
||||
func Uint64s(key string, val []uint64) Field { return Field{Key: key, Value: val} }
|
||||
func Float64s(key string, val []float64) Field { return Field{Key: key, Value: val} }
|
||||
func Bools(key string, val []bool) Field { return Field{Key: key, Value: val} }
|
||||
func Durations(key string, val []time.Duration) Field { return Field{Key: key, Value: val} }
|
||||
func Times(key string, val []time.Time) Field { return Field{Key: key, Value: val} }
|
||||
func Times(key string, val []time.Time) Field { return Field{Key: key, Value: val} }
|
||||
|
||||
// Short-form aliases (matching chaining API style)
|
||||
func Str(key, val string) Field { return String(key, val) }
|
||||
func Dur(key string, val time.Duration) Field { return Duration(key, val) }
|
||||
func AnErr(key string, err error) Field { return NamedErr(key, err) }
|
||||
func Str(key, val string) Field { return String(key, val) }
|
||||
func Dur(key string, val time.Duration) Field { return Duration(key, val) }
|
||||
func AnErr(key string, err error) Field { return NamedErr(key, err) }
|
||||
|
||||
// Stack returns a Field with the current stack trace.
|
||||
func Stack(key string) Field {
|
||||
return Field{Key: key, Value: "stack"} // Placeholder, actual stack in event
|
||||
buf := make([]byte, 4096)
|
||||
n := runtime.Stack(buf, false)
|
||||
return Field{Key: key, Value: string(buf[:n])}
|
||||
}
|
||||
|
||||
// defaultLogger is the global logger for geth-style functions
|
||||
var defaultLogger = NewWriter(os.Stderr).With().Timestamp().Logger()
|
||||
// defaultLogger is the global logger for geth-style functions.
|
||||
// Default level is Info — debug/trace messages are suppressed unless
|
||||
// explicitly enabled via SetDefault() or SetGlobalLevel(DebugLevel).
|
||||
// This prevents dependency init() functions from spamming stderr
|
||||
// with debug output before the application configures logging.
|
||||
var defaultLogger = NewWriter(os.Stderr).With().Timestamp().Logger().Level(InfoLevel)
|
||||
|
||||
// SetDefault sets the default logger for geth-style functions
|
||||
func SetDefault(l Logger) {
|
||||
@@ -268,4 +275,3 @@ func NewTestLogger(level ...Level) Logger {
|
||||
}
|
||||
return l
|
||||
}
|
||||
|
||||
|
||||
+1
@@ -1,3 +1,4 @@
|
||||
//go:build go1.12
|
||||
// +build go1.12
|
||||
|
||||
package log
|
||||
|
||||
+33
-33
@@ -593,39 +593,39 @@ func (l *logger) should(lvl Level) bool {
|
||||
|
||||
type noopLogger struct{}
|
||||
|
||||
func (noopLogger) Trace(string, ...interface{}) {}
|
||||
func (noopLogger) Debug(string, ...interface{}) {}
|
||||
func (noopLogger) Info(string, ...interface{}) {}
|
||||
func (noopLogger) Warn(string, ...interface{}) {}
|
||||
func (noopLogger) Error(string, ...interface{}) {}
|
||||
func (noopLogger) Fatal(string, ...interface{}) {}
|
||||
func (noopLogger) Panic(string, ...interface{}) {}
|
||||
func (noopLogger) Crit(string, ...interface{}) {}
|
||||
func (noopLogger) Verbo(string, ...interface{}) {}
|
||||
func (noopLogger) Log(Level, string, ...interface{}) {}
|
||||
func (n noopLogger) With() Context { return Context{} }
|
||||
func (n noopLogger) New(...interface{}) Logger { return n }
|
||||
func (n noopLogger) Output(io.Writer) Logger { return n }
|
||||
func (n noopLogger) Level(Level) Logger { return n }
|
||||
func (noopLogger) GetLevel() Level { return Disabled }
|
||||
func (noopLogger) IsZero() bool { return true }
|
||||
func (noopLogger) Enabled(context.Context, slog.Level) bool { return false }
|
||||
func (noopLogger) Sample(Sampler) Logger { return Noop() }
|
||||
func (noopLogger) Hook(...Hook) Logger { return Noop() }
|
||||
func (noopLogger) TraceEvent() *Event { return nil }
|
||||
func (noopLogger) DebugEvent() *Event { return nil }
|
||||
func (noopLogger) InfoEvent() *Event { return nil }
|
||||
func (noopLogger) WarnEvent() *Event { return nil }
|
||||
func (noopLogger) ErrorEvent() *Event { return nil }
|
||||
func (noopLogger) FatalEvent() *Event { return nil }
|
||||
func (noopLogger) PanicEvent() *Event { return nil }
|
||||
func (noopLogger) Err(error) *Event { return nil }
|
||||
func (noopLogger) WithLevel(Level) *Event { return nil }
|
||||
func (noopLogger) LogEvent() *Event { return nil }
|
||||
func (noopLogger) Print(...interface{}) {}
|
||||
func (noopLogger) Printf(string, ...interface{}) {}
|
||||
func (noopLogger) Write(p []byte) (int, error) { return len(p), nil }
|
||||
func (noopLogger) SetLogLevel(string) error { return nil }
|
||||
func (noopLogger) Trace(string, ...interface{}) {}
|
||||
func (noopLogger) Debug(string, ...interface{}) {}
|
||||
func (noopLogger) Info(string, ...interface{}) {}
|
||||
func (noopLogger) Warn(string, ...interface{}) {}
|
||||
func (noopLogger) Error(string, ...interface{}) {}
|
||||
func (noopLogger) Fatal(string, ...interface{}) {}
|
||||
func (noopLogger) Panic(string, ...interface{}) {}
|
||||
func (noopLogger) Crit(string, ...interface{}) {}
|
||||
func (noopLogger) Verbo(string, ...interface{}) {}
|
||||
func (noopLogger) Log(Level, string, ...interface{}) {}
|
||||
func (n noopLogger) With() Context { return Context{} }
|
||||
func (n noopLogger) New(...interface{}) Logger { return n }
|
||||
func (n noopLogger) Output(io.Writer) Logger { return n }
|
||||
func (n noopLogger) Level(Level) Logger { return n }
|
||||
func (noopLogger) GetLevel() Level { return Disabled }
|
||||
func (noopLogger) IsZero() bool { return true }
|
||||
func (noopLogger) Enabled(context.Context, slog.Level) bool { return false }
|
||||
func (noopLogger) Sample(Sampler) Logger { return Noop() }
|
||||
func (noopLogger) Hook(...Hook) Logger { return Noop() }
|
||||
func (noopLogger) TraceEvent() *Event { return nil }
|
||||
func (noopLogger) DebugEvent() *Event { return nil }
|
||||
func (noopLogger) InfoEvent() *Event { return nil }
|
||||
func (noopLogger) WarnEvent() *Event { return nil }
|
||||
func (noopLogger) ErrorEvent() *Event { return nil }
|
||||
func (noopLogger) FatalEvent() *Event { return nil }
|
||||
func (noopLogger) PanicEvent() *Event { return nil }
|
||||
func (noopLogger) Err(error) *Event { return nil }
|
||||
func (noopLogger) WithLevel(Level) *Event { return nil }
|
||||
func (noopLogger) LogEvent() *Event { return nil }
|
||||
func (noopLogger) Print(...interface{}) {}
|
||||
func (noopLogger) Printf(string, ...interface{}) {}
|
||||
func (noopLogger) Write(p []byte) (int, error) { return len(p), nil }
|
||||
func (noopLogger) SetLogLevel(string) error { return nil }
|
||||
func (noopLogger) RecoverAndPanic(fn func()) {
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
|
||||
+1
@@ -1,3 +1,4 @@
|
||||
//go:build !go1.12
|
||||
// +build !go1.12
|
||||
|
||||
package log
|
||||
|
||||
+170
-2
@@ -1,9 +1,14 @@
|
||||
package log
|
||||
|
||||
import (
|
||||
"math/rand"
|
||||
"hash/fnv"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
crand "crypto/rand"
|
||||
"encoding/binary"
|
||||
"math/rand/v2"
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -13,8 +18,30 @@ var (
|
||||
Sometimes = RandomSampler(100)
|
||||
// Rarely samples log every ~ 1000 events.
|
||||
Rarely = RandomSampler(1000)
|
||||
|
||||
// globalRand is a thread-safe random source
|
||||
globalRand = newLockedRand()
|
||||
)
|
||||
|
||||
// lockedRand is a thread-safe random number generator
|
||||
type lockedRand struct {
|
||||
mu sync.Mutex
|
||||
rng *rand.Rand
|
||||
}
|
||||
|
||||
func newLockedRand() *lockedRand {
|
||||
var seed [8]byte
|
||||
_, _ = crand.Read(seed[:])
|
||||
src := rand.NewPCG(binary.LittleEndian.Uint64(seed[:]), binary.LittleEndian.Uint64(seed[:]))
|
||||
return &lockedRand{rng: rand.New(src)}
|
||||
}
|
||||
|
||||
func (r *lockedRand) Intn(n int) int {
|
||||
r.mu.Lock()
|
||||
defer r.mu.Unlock()
|
||||
return r.rng.IntN(n)
|
||||
}
|
||||
|
||||
// Sampler defines an interface to a log sampler.
|
||||
type Sampler interface {
|
||||
// Sample returns true if the event should be part of the sample, false if
|
||||
@@ -31,7 +58,7 @@ func (s RandomSampler) Sample(lvl Level) bool {
|
||||
if s <= 0 {
|
||||
return false
|
||||
}
|
||||
if rand.Intn(int(s)) != 0 {
|
||||
if globalRand.Intn(int(s)) != 0 {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
@@ -135,3 +162,144 @@ func (s LevelSampler) Sample(lvl Level) bool {
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// DedupSampler suppresses duplicate log messages within a time window.
|
||||
// After the window expires, it emits a summary of suppressed messages.
|
||||
type DedupSampler struct {
|
||||
// Window is the deduplication time window. Defaults to 1 minute.
|
||||
Window time.Duration
|
||||
// MaxKeys is the maximum number of unique messages to track. Defaults to 1000.
|
||||
MaxKeys int
|
||||
|
||||
mu sync.Mutex
|
||||
seen map[uint64]*dedupEntry
|
||||
cleanup int64 // next cleanup time (unix nano)
|
||||
}
|
||||
|
||||
type dedupEntry struct {
|
||||
count int64
|
||||
firstAt int64
|
||||
lastAt int64
|
||||
lastEmit int64
|
||||
}
|
||||
|
||||
// NewDedupSampler creates a dedup sampler with the given window.
|
||||
func NewDedupSampler(window time.Duration) *DedupSampler {
|
||||
if window <= 0 {
|
||||
window = time.Minute
|
||||
}
|
||||
return &DedupSampler{
|
||||
Window: window,
|
||||
MaxKeys: 1000,
|
||||
seen: make(map[uint64]*dedupEntry),
|
||||
}
|
||||
}
|
||||
|
||||
// SampleMsg returns true if this message should be logged.
|
||||
// It tracks message hashes and suppresses duplicates within the window.
|
||||
func (s *DedupSampler) SampleMsg(lvl Level, msg string) bool {
|
||||
return s.SampleMsgWithKey(lvl, msg, "")
|
||||
}
|
||||
|
||||
// SampleMsgWithKey allows specifying a custom dedup key instead of using msg.
|
||||
func (s *DedupSampler) SampleMsgWithKey(lvl Level, msg, key string) bool {
|
||||
if key == "" {
|
||||
key = msg
|
||||
}
|
||||
|
||||
// Hash the level + message for dedup key
|
||||
h := fnv.New64a()
|
||||
h.Write([]byte{byte(lvl)})
|
||||
h.Write([]byte(key))
|
||||
hash := h.Sum64()
|
||||
|
||||
now := TimestampFunc().UnixNano()
|
||||
windowNano := s.Window.Nanoseconds()
|
||||
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
|
||||
// Lazy init
|
||||
if s.seen == nil {
|
||||
s.seen = make(map[uint64]*dedupEntry)
|
||||
}
|
||||
|
||||
// Periodic cleanup of old entries
|
||||
if now > s.cleanup {
|
||||
s.cleanupLocked(now, windowNano)
|
||||
s.cleanup = now + windowNano
|
||||
}
|
||||
|
||||
entry, exists := s.seen[hash]
|
||||
if !exists {
|
||||
// First time seeing this message
|
||||
if len(s.seen) >= s.MaxKeys {
|
||||
// Evict oldest entry if at capacity
|
||||
s.evictOldestLocked()
|
||||
}
|
||||
s.seen[hash] = &dedupEntry{
|
||||
count: 1,
|
||||
firstAt: now,
|
||||
lastAt: now,
|
||||
lastEmit: now,
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// Update stats
|
||||
entry.count++
|
||||
entry.lastAt = now
|
||||
|
||||
// Check if window has expired since last emit
|
||||
if now-entry.lastEmit >= windowNano {
|
||||
entry.lastEmit = now
|
||||
return true
|
||||
}
|
||||
|
||||
// Suppress this message
|
||||
return false
|
||||
}
|
||||
|
||||
// Sample implements the Sampler interface (always returns true for non-dedup use).
|
||||
func (s *DedupSampler) Sample(lvl Level) bool {
|
||||
return true
|
||||
}
|
||||
|
||||
// GetSuppressedCount returns the count of suppressed messages for a key.
|
||||
func (s *DedupSampler) GetSuppressedCount(lvl Level, msg string) int64 {
|
||||
h := fnv.New64a()
|
||||
h.Write([]byte{byte(lvl)})
|
||||
h.Write([]byte(msg))
|
||||
hash := h.Sum64()
|
||||
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
|
||||
if entry, exists := s.seen[hash]; exists {
|
||||
return entry.count - 1 // exclude the one we emitted
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (s *DedupSampler) cleanupLocked(now, windowNano int64) {
|
||||
cutoff := now - windowNano
|
||||
for hash, entry := range s.seen {
|
||||
if entry.lastAt < cutoff {
|
||||
delete(s.seen, hash)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (s *DedupSampler) evictOldestLocked() {
|
||||
var oldestHash uint64
|
||||
var oldestTime int64 = 1<<63 - 1
|
||||
for hash, entry := range s.seen {
|
||||
if entry.lastAt < oldestTime {
|
||||
oldestTime = entry.lastAt
|
||||
oldestHash = hash
|
||||
}
|
||||
}
|
||||
if oldestHash != 0 {
|
||||
delete(s.seen, oldestHash)
|
||||
}
|
||||
}
|
||||
|
||||
+60
-27
@@ -271,18 +271,20 @@ func LevelString(l slog.Level) string {
|
||||
|
||||
// GlogHandler is a log handler that mimics glog behavior.
|
||||
type GlogHandler struct {
|
||||
origin slog.Handler
|
||||
verbosity slog.Level
|
||||
vmodule map[string]slog.Level
|
||||
mu sync.RWMutex
|
||||
origin slog.Handler
|
||||
verbosity slog.Level
|
||||
vmodule map[string]slog.Level
|
||||
patternCache map[string]*regexp.Regexp // cached compiled patterns
|
||||
mu sync.RWMutex
|
||||
}
|
||||
|
||||
// NewGlogHandler creates a GlogHandler wrapping the given handler.
|
||||
func NewGlogHandler(h slog.Handler) *GlogHandler {
|
||||
return &GlogHandler{
|
||||
origin: h,
|
||||
verbosity: slogLevelInfo,
|
||||
vmodule: make(map[string]slog.Level),
|
||||
origin: h,
|
||||
verbosity: slogLevelInfo,
|
||||
vmodule: make(map[string]slog.Level),
|
||||
patternCache: make(map[string]*regexp.Regexp),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -299,6 +301,7 @@ func (h *GlogHandler) Vmodule(pattern string) error {
|
||||
defer h.mu.Unlock()
|
||||
|
||||
h.vmodule = make(map[string]slog.Level)
|
||||
h.patternCache = make(map[string]*regexp.Regexp)
|
||||
if pattern == "" {
|
||||
return nil
|
||||
}
|
||||
@@ -320,6 +323,10 @@ func (h *GlogHandler) Vmodule(pattern string) error {
|
||||
}
|
||||
}
|
||||
h.vmodule[module] = level
|
||||
// Precompile pattern regex
|
||||
if re, err := compilePattern(module); err == nil {
|
||||
h.patternCache[module] = re
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -328,13 +335,15 @@ func (h *GlogHandler) Handle(ctx context.Context, r slog.Record) error {
|
||||
h.mu.RLock()
|
||||
verbosity := h.verbosity
|
||||
vmodule := h.vmodule
|
||||
patternCache := h.patternCache
|
||||
h.mu.RUnlock()
|
||||
|
||||
if len(vmodule) > 0 {
|
||||
_, file, _, ok := runtime.Caller(6)
|
||||
if ok {
|
||||
for pattern, level := range vmodule {
|
||||
if matched, _ := matchPattern(pattern, file); matched && r.Level >= level {
|
||||
re := patternCache[pattern]
|
||||
if re != nil && re.MatchString(file) && r.Level >= level {
|
||||
return h.origin.Handle(ctx, r)
|
||||
}
|
||||
}
|
||||
@@ -347,15 +356,12 @@ func (h *GlogHandler) Handle(ctx context.Context, r slog.Record) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func matchPattern(pattern, file string) (bool, error) {
|
||||
pattern = strings.ReplaceAll(pattern, ".", "\\.")
|
||||
pattern = strings.ReplaceAll(pattern, "*", ".*")
|
||||
pattern = strings.ReplaceAll(pattern, "/", "\\/")
|
||||
re, err := regexp.Compile(pattern)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
return re.MatchString(file), nil
|
||||
// compilePattern converts a vmodule pattern to a compiled regex.
|
||||
func compilePattern(pattern string) (*regexp.Regexp, error) {
|
||||
escaped := strings.ReplaceAll(pattern, ".", "\\.")
|
||||
escaped = strings.ReplaceAll(escaped, "*", ".*")
|
||||
escaped = strings.ReplaceAll(escaped, "/", "\\/")
|
||||
return regexp.Compile(escaped)
|
||||
}
|
||||
|
||||
func (h *GlogHandler) Enabled(ctx context.Context, level slog.Level) bool {
|
||||
@@ -372,12 +378,17 @@ func (h *GlogHandler) WithAttrs(attrs []slog.Attr) slog.Handler {
|
||||
for k, v := range h.vmodule {
|
||||
vmodule[k] = v
|
||||
}
|
||||
patternCache := make(map[string]*regexp.Regexp, len(h.patternCache))
|
||||
for k, v := range h.patternCache {
|
||||
patternCache[k] = v
|
||||
}
|
||||
h.mu.RUnlock()
|
||||
|
||||
return &GlogHandler{
|
||||
origin: h.origin.WithAttrs(attrs),
|
||||
verbosity: verbosity,
|
||||
vmodule: vmodule,
|
||||
origin: h.origin.WithAttrs(attrs),
|
||||
verbosity: verbosity,
|
||||
vmodule: vmodule,
|
||||
patternCache: patternCache,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -388,12 +399,17 @@ func (h *GlogHandler) WithGroup(name string) slog.Handler {
|
||||
for k, v := range h.vmodule {
|
||||
vmodule[k] = v
|
||||
}
|
||||
patternCache := make(map[string]*regexp.Regexp, len(h.patternCache))
|
||||
for k, v := range h.patternCache {
|
||||
patternCache[k] = v
|
||||
}
|
||||
h.mu.RUnlock()
|
||||
|
||||
return &GlogHandler{
|
||||
origin: h.origin.WithGroup(name),
|
||||
verbosity: verbosity,
|
||||
vmodule: vmodule,
|
||||
origin: h.origin.WithGroup(name),
|
||||
verbosity: verbosity,
|
||||
vmodule: vmodule,
|
||||
patternCache: patternCache,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -438,7 +454,24 @@ func (h *TerminalHandler) Enabled(_ context.Context, level slog.Level) bool {
|
||||
}
|
||||
|
||||
func (h *TerminalHandler) WithGroup(name string) slog.Handler {
|
||||
panic("not implemented")
|
||||
// Create a new handler with the group prefix applied to attribute keys
|
||||
return &TerminalHandler{
|
||||
wr: h.wr,
|
||||
lvl: h.lvl,
|
||||
useColor: h.useColor,
|
||||
attrs: h.attrs,
|
||||
fieldPadding: make(map[string]int),
|
||||
Prefix: func(r slog.Record) string {
|
||||
prefix := ""
|
||||
if h.Prefix != nil {
|
||||
prefix = h.Prefix(r)
|
||||
}
|
||||
if name != "" {
|
||||
prefix = prefix + name + "."
|
||||
}
|
||||
return prefix
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func (h *TerminalHandler) WithAttrs(attrs []slog.Attr) slog.Handler {
|
||||
@@ -818,10 +851,10 @@ func DiscardHandler() slog.Handler {
|
||||
|
||||
type discardHandler struct{}
|
||||
|
||||
func (h *discardHandler) Handle(_ context.Context, r slog.Record) error { return nil }
|
||||
func (h *discardHandler) Handle(_ context.Context, r slog.Record) error { return nil }
|
||||
func (h *discardHandler) Enabled(_ context.Context, level slog.Level) bool { return false }
|
||||
func (h *discardHandler) WithGroup(name string) slog.Handler { return h }
|
||||
func (h *discardHandler) WithAttrs(attrs []slog.Attr) slog.Handler { return h }
|
||||
func (h *discardHandler) WithGroup(name string) slog.Handler { return h }
|
||||
func (h *discardHandler) WithAttrs(attrs []slog.Attr) slog.Handler { return h }
|
||||
|
||||
// TerminalStringer is an interface for custom terminal serialization.
|
||||
type TerminalStringer interface {
|
||||
|
||||
+1
-1
@@ -73,5 +73,5 @@ GOWORK=off go test ./...
|
||||
* [`lattice/v7/ring`](https://github.com/luxfi/lattice/tree/main/ring)
|
||||
— canonical Lattigo-derived NTT/Montgomery body that this module
|
||||
delegates to.
|
||||
* [`luxcpp/crypto/corona`](https://github.com/luxcpp/crypto/tree/main/corona)
|
||||
* [`luxcpp/crypto/ringtail`](https://github.com/luxcpp/crypto/tree/main/ringtail)
|
||||
— native C++ Montgomery NTT that Phase 6 mirrors as `math` C++.
|
||||
|
||||
+329
@@ -0,0 +1,329 @@
|
||||
// Copyright (C) 2019-2026, Lux Industries Inc. All rights reserved.
|
||||
// See the file LICENSE for licensing terms.
|
||||
|
||||
// ZAP-native metric exporter — the default metric transport.
|
||||
//
|
||||
// Metric families serialize to JSON inside a luxfi/zap envelope and ship
|
||||
// over TCP to a ZAP-aware o11y collector (hanzo/o11y has a matching
|
||||
// receiver). Zero google.golang.org/protobuf, zero OTLP, zero gRPC.
|
||||
//
|
||||
// Wire layout per export call:
|
||||
//
|
||||
// zap envelope, MsgType=MsgMetricBatch
|
||||
// └─ root object
|
||||
// └─ FieldPayload (bytes): JSON-encoded MetricBatch
|
||||
//
|
||||
// MetricBatch carries app/resource attributes + a list of MetricFamily
|
||||
// rows (same shape as the in-process gatherer.Gather() output).
|
||||
//
|
||||
// Mirrors luxfi/trace/exporter_zap.go (MsgSpanBatch=1). The two
|
||||
// transports share the same ZAP node + collector endpoint by convention
|
||||
// (the o11y collector binds :4317 and routes by MsgType in the envelope
|
||||
// flags field).
|
||||
|
||||
package metric
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"math"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/luxfi/zap"
|
||||
)
|
||||
|
||||
// MsgMetricBatch is the ZAP MsgType that carries a MetricBatch payload.
|
||||
//
|
||||
// Stable wire ID for the metric transport on the ZAP bus. Append-only —
|
||||
// renumbering breaks every deployed collector in lockstep. Coordinates
|
||||
// with luxfi/trace.MsgSpanBatch (=1); collectors switch on the
|
||||
// MsgType-in-flags-upper-byte to route to the right ingest path.
|
||||
const MsgMetricBatch uint16 = 2
|
||||
|
||||
// MetricBatch is the JSON shape that rides inside the ZAP envelope's
|
||||
// payload field. One batch per Export call (typically one Gather()
|
||||
// snapshot per scrape interval).
|
||||
type MetricBatch struct {
|
||||
AppName string `json:"appName,omitempty"`
|
||||
Version string `json:"version,omitempty"`
|
||||
Resource map[string]string `json:"resource,omitempty"`
|
||||
TimestampNs int64 `json:"timestampNs"`
|
||||
Families []MetricFamilyWire `json:"families"`
|
||||
}
|
||||
|
||||
// MetricFamilyWire is the JSON-stable wire shape of a MetricFamily.
|
||||
// Mirrors metric.MetricFamily but pins the field names so the collector
|
||||
// side can decode without depending on this package's Go types.
|
||||
type MetricFamilyWire struct {
|
||||
Name string `json:"name"`
|
||||
Help string `json:"help,omitempty"`
|
||||
Type string `json:"type"`
|
||||
Metrics []MetricWire `json:"metrics"`
|
||||
}
|
||||
|
||||
// MetricWire is the JSON-stable wire shape of a single Metric.
|
||||
type MetricWire struct {
|
||||
Labels map[string]string `json:"labels,omitempty"`
|
||||
Value *float64 `json:"value,omitempty"` // counter/gauge
|
||||
SampleCount *uint64 `json:"sampleCount,omitempty"` // histogram/summary
|
||||
SampleSum *float64 `json:"sampleSum,omitempty"` // histogram/summary
|
||||
Buckets []BucketWire `json:"buckets,omitempty"` // histogram
|
||||
Quantiles []QuantileWire `json:"quantiles,omitempty"` // summary
|
||||
}
|
||||
|
||||
type BucketWire struct {
|
||||
UpperBound float64 `json:"upperBound"`
|
||||
CumulativeCount uint64 `json:"cumulativeCount"`
|
||||
}
|
||||
|
||||
type QuantileWire struct {
|
||||
Quantile float64 `json:"quantile"`
|
||||
Value float64 `json:"value"`
|
||||
}
|
||||
|
||||
// ZAPExporterConfig configures the ZAP-native exporter.
|
||||
type ZAPExporterConfig struct {
|
||||
// Endpoint is the collector address (host:port). Defaults to
|
||||
// "127.0.0.1:4317" (the canonical o11y ZAP port).
|
||||
Endpoint string
|
||||
|
||||
// AppName + Version land in every emitted batch's metadata.
|
||||
AppName string
|
||||
Version string
|
||||
|
||||
// Resource attributes shipped with every batch (e.g., k8s namespace,
|
||||
// pod name, network ID).
|
||||
Resource map[string]string
|
||||
|
||||
// Logger — defaults to slog.Default().
|
||||
Logger *slog.Logger
|
||||
}
|
||||
|
||||
// ZAPExporter ships metric families over a luxfi/zap connection.
|
||||
//
|
||||
// Fire-and-forget by design: tracing and metrics MUST NEVER block the
|
||||
// host process. Send failures invalidate the cached connection and
|
||||
// trigger a reconnect on the next Export call; no batches are buffered
|
||||
// in memory.
|
||||
type ZAPExporter struct {
|
||||
cfg ZAPExporterConfig
|
||||
|
||||
mu sync.Mutex
|
||||
node *zap.Node
|
||||
serverID string
|
||||
closed bool
|
||||
}
|
||||
|
||||
// NewZAPExporter constructs a metric exporter that ships over ZAP.
|
||||
//
|
||||
// Returns the exporter even if the initial connect fails — the next
|
||||
// Export call will retry. This matches the trace exporter's posture:
|
||||
// fire-and-forget means startup never fails on collector reachability.
|
||||
func NewZAPExporter(cfg ZAPExporterConfig) (*ZAPExporter, error) {
|
||||
if cfg.Endpoint == "" {
|
||||
cfg.Endpoint = "127.0.0.1:4317"
|
||||
}
|
||||
if cfg.Logger == nil {
|
||||
cfg.Logger = slog.Default()
|
||||
}
|
||||
|
||||
node := zap.NewNode(zap.NodeConfig{
|
||||
NodeID: fmt.Sprintf("metric-%s", cfg.AppName),
|
||||
ServiceType: "_o11y._tcp",
|
||||
Port: 0,
|
||||
Logger: cfg.Logger,
|
||||
NoDiscovery: true,
|
||||
})
|
||||
if err := node.Start(); err != nil {
|
||||
return nil, fmt.Errorf("metric zap exporter start: %w", err)
|
||||
}
|
||||
|
||||
e := &ZAPExporter{
|
||||
cfg: cfg,
|
||||
node: node,
|
||||
}
|
||||
if err := e.connect(); err != nil {
|
||||
// Log and continue — exporter retries on first export.
|
||||
cfg.Logger.Debug("metric zap exporter: initial connect failed (will retry on export)",
|
||||
"endpoint", cfg.Endpoint, "err", err)
|
||||
}
|
||||
return e, nil
|
||||
}
|
||||
|
||||
// connect dials the collector and caches the peer ID.
|
||||
//
|
||||
// Idempotent under the mutex — called from NewZAPExporter and from
|
||||
// Export when an earlier connect failed.
|
||||
func (e *ZAPExporter) connect() error {
|
||||
if err := e.node.ConnectDirect(e.cfg.Endpoint); err != nil {
|
||||
return err
|
||||
}
|
||||
peers := e.node.Peers()
|
||||
if len(peers) == 0 {
|
||||
return fmt.Errorf("metric zap exporter: connected but no peer ID for %s", e.cfg.Endpoint)
|
||||
}
|
||||
e.serverID = peers[0]
|
||||
return nil
|
||||
}
|
||||
|
||||
// Export serializes families to JSON, wraps them in a ZAP envelope, and
|
||||
// fires them over the cached connection. Fire-and-forget — no response
|
||||
// is expected, no waiting on the collector.
|
||||
func (e *ZAPExporter) Export(ctx context.Context, families []*MetricFamily) error {
|
||||
if len(families) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
e.mu.Lock()
|
||||
defer e.mu.Unlock()
|
||||
|
||||
if e.closed {
|
||||
return fmt.Errorf("metric zap exporter: shut down")
|
||||
}
|
||||
if e.serverID == "" {
|
||||
if err := e.connect(); err != nil {
|
||||
e.cfg.Logger.Debug("metric zap exporter: connect retry failed; dropping batch",
|
||||
"endpoint", e.cfg.Endpoint, "err", err)
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
batch := MetricBatch{
|
||||
AppName: e.cfg.AppName,
|
||||
Version: e.cfg.Version,
|
||||
Resource: e.cfg.Resource,
|
||||
TimestampNs: time.Now().UnixNano(),
|
||||
Families: make([]MetricFamilyWire, 0, len(families)),
|
||||
}
|
||||
for _, fam := range families {
|
||||
batch.Families = append(batch.Families, translateFamily(fam))
|
||||
}
|
||||
|
||||
payload, err := json.Marshal(&batch)
|
||||
if err != nil {
|
||||
return fmt.Errorf("metric zap exporter: marshal batch: %w", err)
|
||||
}
|
||||
|
||||
wire, err := encodeMetricBatch(payload)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
msg, err := zap.Parse(wire)
|
||||
if err != nil {
|
||||
return fmt.Errorf("metric zap exporter: parse outgoing: %w", err)
|
||||
}
|
||||
|
||||
if err := e.node.Send(ctx, e.serverID, msg); err != nil {
|
||||
// Connection died — invalidate and let the next call reconnect.
|
||||
e.serverID = ""
|
||||
e.cfg.Logger.Debug("metric zap exporter: send failed; will reconnect", "err", err)
|
||||
return nil
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// ExportGatherer is the convenience entry point — calls Gather() on the
|
||||
// supplied Gatherer and ships the resulting families. Use this when
|
||||
// driving the exporter from a scrape loop.
|
||||
func (e *ZAPExporter) ExportGatherer(ctx context.Context, g Gatherer) error {
|
||||
families, err := g.Gather()
|
||||
if err != nil {
|
||||
return fmt.Errorf("metric zap exporter: gather: %w", err)
|
||||
}
|
||||
return e.Export(ctx, families)
|
||||
}
|
||||
|
||||
// Shutdown closes the ZAP node. Safe to call multiple times.
|
||||
func (e *ZAPExporter) Shutdown(_ context.Context) error {
|
||||
e.mu.Lock()
|
||||
defer e.mu.Unlock()
|
||||
if e.closed {
|
||||
return nil
|
||||
}
|
||||
e.closed = true
|
||||
e.node.Stop()
|
||||
return nil
|
||||
}
|
||||
|
||||
// translateFamily converts an in-process MetricFamily into the JSON
|
||||
// wire shape. Maps MetricType → string label, label slices → maps, and
|
||||
// only emits the value fields that match the metric type.
|
||||
func translateFamily(fam *MetricFamily) MetricFamilyWire {
|
||||
out := MetricFamilyWire{
|
||||
Name: fam.Name,
|
||||
Help: fam.Help,
|
||||
Type: fam.Type.String(),
|
||||
Metrics: make([]MetricWire, 0, len(fam.Metrics)),
|
||||
}
|
||||
for _, m := range fam.Metrics {
|
||||
mw := MetricWire{}
|
||||
if len(m.Labels) > 0 {
|
||||
mw.Labels = make(map[string]string, len(m.Labels))
|
||||
for _, lp := range m.Labels {
|
||||
mw.Labels[lp.Name] = lp.Value
|
||||
}
|
||||
}
|
||||
switch fam.Type {
|
||||
case MetricTypeCounter, MetricTypeGauge:
|
||||
v := m.Value.Value
|
||||
mw.Value = &v
|
||||
case MetricTypeHistogram:
|
||||
c := m.Value.SampleCount
|
||||
s := m.Value.SampleSum
|
||||
mw.SampleCount = &c
|
||||
mw.SampleSum = &s
|
||||
if len(m.Value.Buckets) > 0 {
|
||||
// Drop the trailing +Inf bucket. JSON can't represent
|
||||
// +Inf as a number and the +Inf bucket count is always
|
||||
// equal to SampleCount — it's already on the wire.
|
||||
mw.Buckets = make([]BucketWire, 0, len(m.Value.Buckets))
|
||||
for _, b := range m.Value.Buckets {
|
||||
if math.IsInf(b.UpperBound, +1) {
|
||||
continue
|
||||
}
|
||||
mw.Buckets = append(mw.Buckets, BucketWire{
|
||||
UpperBound: b.UpperBound,
|
||||
CumulativeCount: b.CumulativeCount,
|
||||
})
|
||||
}
|
||||
}
|
||||
case MetricTypeSummary:
|
||||
c := m.Value.SampleCount
|
||||
s := m.Value.SampleSum
|
||||
mw.SampleCount = &c
|
||||
mw.SampleSum = &s
|
||||
if len(m.Value.Quantiles) > 0 {
|
||||
mw.Quantiles = make([]QuantileWire, len(m.Value.Quantiles))
|
||||
for i, q := range m.Value.Quantiles {
|
||||
mw.Quantiles[i] = QuantileWire{
|
||||
Quantile: q.Quantile,
|
||||
Value: q.Value,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
out.Metrics = append(out.Metrics, mw)
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
// encodeMetricBatch wraps a JSON payload in a ZAP envelope tagged
|
||||
// MsgMetricBatch.
|
||||
//
|
||||
// Wire shape:
|
||||
//
|
||||
// zap header (16) + root object { bytes payload @ offset 0 }
|
||||
//
|
||||
// MsgMetricBatch goes in the upper 8 bits of the ZAP flags field —
|
||||
// same convention luxfi/trace uses for MsgSpanBatch.
|
||||
func encodeMetricBatch(payload []byte) ([]byte, error) {
|
||||
const envelopeSize = 16
|
||||
b := zap.NewBuilder(envelopeSize + 64 + len(payload))
|
||||
root := b.StartObject(envelopeSize)
|
||||
root.SetBytes(0, payload)
|
||||
root.FinishAsRoot()
|
||||
return b.FinishWithFlags(MsgMetricBatch << 8), nil
|
||||
}
|
||||
+6
-6
@@ -254,7 +254,7 @@
|
||||
</div>
|
||||
<div class="legend-item">
|
||||
<div class="legend-color" style="background: #f093fb;"></div>
|
||||
<span>Corona</span>
|
||||
<span>Ringtail</span>
|
||||
</div>
|
||||
<div class="legend-item">
|
||||
<div class="legend-color" style="background: #4facfe;"></div>
|
||||
@@ -340,7 +340,7 @@
|
||||
<td>Level 5</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><strong>Corona (Hybrid)</strong></td>
|
||||
<td><strong>Ringtail (Hybrid)</strong></td>
|
||||
<td class="good">6,780</td>
|
||||
<td class="good">0.15 ms</td>
|
||||
<td class="good">99.97%</td>
|
||||
@@ -435,7 +435,7 @@
|
||||
tension: 0.4
|
||||
},
|
||||
{
|
||||
label: 'Corona',
|
||||
label: 'Ringtail',
|
||||
data: Array(20).fill(0).map(() => 6500 + Math.random() * 500),
|
||||
borderColor: '#f093fb',
|
||||
tension: 0.4
|
||||
@@ -456,7 +456,7 @@
|
||||
const verificationChart = new Chart(verificationCtx, {
|
||||
type: 'bar',
|
||||
data: {
|
||||
labels: ['BLS', 'ML-DSA', 'SLH-DSA', 'Corona', 'Verkle'],
|
||||
labels: ['BLS', 'ML-DSA', 'SLH-DSA', 'Ringtail', 'Verkle'],
|
||||
datasets: [{
|
||||
label: 'Average Verification Time',
|
||||
data: [0.08, 0.12, 0.47, 0.15, 0.05],
|
||||
@@ -488,7 +488,7 @@
|
||||
const gasChart = new Chart(gasCtx, {
|
||||
type: 'doughnut',
|
||||
data: {
|
||||
labels: ['BLS', 'ML-DSA', 'SLH-DSA', 'Corona', 'Verkle', 'Other'],
|
||||
labels: ['BLS', 'ML-DSA', 'SLH-DSA', 'Ringtail', 'Verkle', 'Other'],
|
||||
datasets: [{
|
||||
data: [25, 30, 10, 20, 10, 5],
|
||||
backgroundColor: [
|
||||
@@ -556,7 +556,7 @@
|
||||
dataset.data.shift();
|
||||
const base = dataset.label === 'BLS' ? 12000 :
|
||||
dataset.label === 'ML-DSA' ? 8000 :
|
||||
dataset.label === 'Corona' ? 6500 : 18000;
|
||||
dataset.label === 'Ringtail' ? 6500 : 18000;
|
||||
dataset.data.push(base + Math.random() * 1000);
|
||||
});
|
||||
signatureChart.update('none');
|
||||
|
||||
+1
-1
@@ -57,7 +57,7 @@ import (
|
||||
// TLS handshake completes. PubKey + Sig are opaque bytes from
|
||||
// zap's perspective; the AttestationVerifier owns the format
|
||||
// (FIPS 204 ML-DSA-65 pubkey 1952 bytes, signature 3293 bytes
|
||||
// for this network; ML-DSA-87 with different byte counts for
|
||||
// for Liquid; ML-DSA-87 with different byte counts for
|
||||
// high-value Zoo chains).
|
||||
type Attestation struct {
|
||||
// PubKey is the peer's strict-PQ public key. The verifier
|
||||
|
||||
+19
-7
@@ -5,13 +5,13 @@ package colorable
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
syscall "golang.org/x/sys/windows"
|
||||
"io"
|
||||
"math"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
syscall "golang.org/x/sys/windows"
|
||||
"unsafe"
|
||||
|
||||
"github.com/mattn/go-isatty"
|
||||
@@ -93,6 +93,7 @@ type writer struct {
|
||||
handle syscall.Handle
|
||||
althandle syscall.Handle
|
||||
oldattr word
|
||||
curattr word
|
||||
oldpos coord
|
||||
rest bytes.Buffer
|
||||
mutex sync.Mutex
|
||||
@@ -112,7 +113,7 @@ func NewColorable(file *os.File) io.Writer {
|
||||
var csbi consoleScreenBufferInfo
|
||||
handle := syscall.Handle(file.Fd())
|
||||
procGetConsoleScreenBufferInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&csbi)))
|
||||
return &writer{out: file, handle: handle, oldattr: csbi.attributes, oldpos: coord{0, 0}}
|
||||
return &writer{out: file, handle: handle, oldattr: csbi.attributes, curattr: csbi.attributes, oldpos: coord{0, 0}}
|
||||
}
|
||||
return file
|
||||
}
|
||||
@@ -438,7 +439,11 @@ func (w *writer) Write(data []byte) (n int, err error) {
|
||||
w.mutex.Lock()
|
||||
defer w.mutex.Unlock()
|
||||
var csbi consoleScreenBufferInfo
|
||||
procGetConsoleScreenBufferInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&csbi)))
|
||||
|
||||
if w.rest.Len() == 0 && bytes.IndexByte(data, 0x1b) == -1 {
|
||||
w.out.Write(data)
|
||||
return len(data), nil
|
||||
}
|
||||
|
||||
handle := w.handle
|
||||
|
||||
@@ -517,7 +522,7 @@ loop:
|
||||
w.rest.Reset()
|
||||
break
|
||||
}
|
||||
buf.Write([]byte(string(c)))
|
||||
buf.WriteByte(c)
|
||||
}
|
||||
if m == 0 {
|
||||
break loop
|
||||
@@ -678,11 +683,11 @@ loop:
|
||||
procFillConsoleOutputCharacter.Call(uintptr(handle), uintptr(' '), uintptr(n), *(*uintptr)(unsafe.Pointer(&cursor)), uintptr(unsafe.Pointer(&written)))
|
||||
procFillConsoleOutputAttribute.Call(uintptr(handle), uintptr(csbi.attributes), uintptr(n), *(*uintptr)(unsafe.Pointer(&cursor)), uintptr(unsafe.Pointer(&written)))
|
||||
case 'm':
|
||||
procGetConsoleScreenBufferInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&csbi)))
|
||||
attr := csbi.attributes
|
||||
attr := w.curattr
|
||||
cs := buf.String()
|
||||
if cs == "" {
|
||||
procSetConsoleTextAttribute.Call(uintptr(handle), uintptr(w.oldattr))
|
||||
w.curattr = w.oldattr
|
||||
continue
|
||||
}
|
||||
token := strings.Split(cs, ";")
|
||||
@@ -814,9 +819,12 @@ loop:
|
||||
attr |= backgroundBlue
|
||||
}
|
||||
}
|
||||
procSetConsoleTextAttribute.Call(uintptr(handle), uintptr(attr))
|
||||
}
|
||||
}
|
||||
if attr != w.curattr {
|
||||
procSetConsoleTextAttribute.Call(uintptr(handle), uintptr(attr))
|
||||
w.curattr = attr
|
||||
}
|
||||
case 'h':
|
||||
var ci consoleCursorInfo
|
||||
cs := buf.String()
|
||||
@@ -834,6 +842,8 @@ loop:
|
||||
w.althandle = syscall.Handle(h)
|
||||
if w.althandle != 0 {
|
||||
handle = w.althandle
|
||||
procGetConsoleScreenBufferInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&csbi)))
|
||||
w.curattr = csbi.attributes
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -853,6 +863,8 @@ loop:
|
||||
syscall.CloseHandle(w.althandle)
|
||||
w.althandle = 0
|
||||
handle = w.handle
|
||||
procGetConsoleScreenBufferInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&csbi)))
|
||||
w.curattr = csbi.attributes
|
||||
}
|
||||
}
|
||||
case 's':
|
||||
|
||||
+2
-2
@@ -1,5 +1,5 @@
|
||||
//go:build (appengine || js || nacl || tinygo || wasm) && !windows
|
||||
// +build appengine js nacl tinygo wasm
|
||||
//go:build (appengine || js || nacl || tinygo || wasm || wasip1 || wasip2) && !windows
|
||||
// +build appengine js nacl tinygo wasm wasip1 wasip2
|
||||
// +build !windows
|
||||
|
||||
package isatty
|
||||
|
||||
+13
-2
@@ -31,6 +31,10 @@ func init() {
|
||||
if procGetFileInformationByHandleEx.Find() != nil {
|
||||
procGetFileInformationByHandleEx = nil
|
||||
}
|
||||
// Check if NtQueryObject is available.
|
||||
if procNtQueryObject.Find() != nil {
|
||||
procNtQueryObject = nil
|
||||
}
|
||||
}
|
||||
|
||||
// IsTerminal return true if the file descriptor is terminal.
|
||||
@@ -43,6 +47,7 @@ func IsTerminal(fd uintptr) bool {
|
||||
// Check pipe name is used for cygwin/msys2 pty.
|
||||
// Cygwin/MSYS2 PTY has a name like:
|
||||
// \{cygwin,msys}-XXXXXXXXXXXXXXXX-ptyN-{from,to}-master
|
||||
// On Windows 7 a trailing suffix (e.g. "-nat") may be appended.
|
||||
func isCygwinPipeName(name string) bool {
|
||||
token := strings.Split(name, "-")
|
||||
if len(token) < 5 {
|
||||
@@ -72,13 +77,19 @@ func isCygwinPipeName(name string) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
for _, t := range token[5:] {
|
||||
if t == "" {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
// getFileNameByHandle use the undocomented ntdll NtQueryObject to get file full name from file handler
|
||||
// getFileNameByHandle use the undocumented ntdll NtQueryObject to get file full name from file handler
|
||||
// since GetFileInformationByHandleEx is not available under windows Vista and still some old fashion
|
||||
// guys are using Windows XP, this is a workaround for those guys, it will also work on system from
|
||||
// Windows vista to 10
|
||||
// Windows Vista to 10
|
||||
// see https://stackoverflow.com/a/18792477 for details
|
||||
func getFileNameByHandle(fd uintptr) (string, error) {
|
||||
if procNtQueryObject == nil {
|
||||
|
||||
+1
@@ -3,6 +3,7 @@ MIT License
|
||||
Copyright (c) 2017 Denis Subbotin
|
||||
Copyright (c) 2017 Nika Jones
|
||||
Copyright (c) 2017 Philip Schlump
|
||||
Copyright (c) 2020 Peter 'ribasushi' Rabbitson
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
|
||||
+5
-1
@@ -1,6 +1,7 @@
|
||||
package base58
|
||||
|
||||
// Alphabet is a a b58 alphabet.
|
||||
// Alphabet is a a b58 alphabet.\
|
||||
// Deprecated: use github.com/mr-tron/base58.Alphabet instead.
|
||||
type Alphabet struct {
|
||||
decode [128]int8
|
||||
encode [58]byte
|
||||
@@ -9,6 +10,7 @@ type Alphabet struct {
|
||||
// NewAlphabet creates a new alphabet from the passed string.
|
||||
//
|
||||
// It panics if the passed string is not 58 bytes long or isn't valid ASCII.
|
||||
// Deprecated: use github.com/mr-tron/base58.NewAlphabet instead.
|
||||
func NewAlphabet(s string) *Alphabet {
|
||||
if len(s) != 58 {
|
||||
panic("base58 alphabets must be 58 bytes long")
|
||||
@@ -25,7 +27,9 @@ func NewAlphabet(s string) *Alphabet {
|
||||
}
|
||||
|
||||
// BTCAlphabet is the bitcoin base58 alphabet.
|
||||
// Deprecated: use github.com/mr-tron/base58.BTCAlphabet instead.
|
||||
var BTCAlphabet = NewAlphabet("123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz")
|
||||
|
||||
// FlickrAlphabet is the flickr base58 alphabet.
|
||||
// Deprecated: use github.com/mr-tron/base58.FlickrAlphabet instead.
|
||||
var FlickrAlphabet = NewAlphabet("123456789abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ")
|
||||
|
||||
+12
@@ -11,23 +11,27 @@ var (
|
||||
)
|
||||
|
||||
// Encode encodes the passed bytes into a base58 encoded string.
|
||||
// Deprecated: use github.com/mr-tron/base58.Encode instead.
|
||||
func Encode(bin []byte) string {
|
||||
return FastBase58Encoding(bin)
|
||||
}
|
||||
|
||||
// EncodeAlphabet encodes the passed bytes into a base58 encoded string with the
|
||||
// passed alphabet.
|
||||
// Deprecated: use github.com/mr-tron/base58.EncodeAlphabet instead.
|
||||
func EncodeAlphabet(bin []byte, alphabet *Alphabet) string {
|
||||
return FastBase58EncodingAlphabet(bin, alphabet)
|
||||
}
|
||||
|
||||
// FastBase58Encoding encodes the passed bytes into a base58 encoded string.
|
||||
// Deprecated: use github.com/mr-tron/base58.FastBase58Encoding instead.
|
||||
func FastBase58Encoding(bin []byte) string {
|
||||
return FastBase58EncodingAlphabet(bin, BTCAlphabet)
|
||||
}
|
||||
|
||||
// FastBase58EncodingAlphabet encodes the passed bytes into a base58 encoded
|
||||
// string with the passed alphabet.
|
||||
// Deprecated: use github.com/mr-tron/base58.FastBase58EncodingAlphabet instead.
|
||||
func FastBase58EncodingAlphabet(bin []byte, alphabet *Alphabet) string {
|
||||
zero := alphabet.encode[0]
|
||||
|
||||
@@ -80,12 +84,14 @@ func FastBase58EncodingAlphabet(bin []byte, alphabet *Alphabet) string {
|
||||
|
||||
// TrivialBase58Encoding encodes the passed bytes into a base58 encoded string
|
||||
// (inefficiently).
|
||||
// Deprecated: use github.com/mr-tron/base58.FastBase58Encoding instead.
|
||||
func TrivialBase58Encoding(a []byte) string {
|
||||
return TrivialBase58EncodingAlphabet(a, BTCAlphabet)
|
||||
}
|
||||
|
||||
// TrivialBase58EncodingAlphabet encodes the passed bytes into a base58 encoded
|
||||
// string (inefficiently) with the passed alphabet.
|
||||
// Deprecated: use github.com/mr-tron/base58.FastBase58EncodingAlphabet instead.
|
||||
func TrivialBase58EncodingAlphabet(a []byte, alphabet *Alphabet) string {
|
||||
zero := alphabet.encode[0]
|
||||
idx := len(a)*138/100 + 1
|
||||
@@ -108,22 +114,26 @@ func TrivialBase58EncodingAlphabet(a []byte, alphabet *Alphabet) string {
|
||||
}
|
||||
|
||||
// Decode decodes the base58 encoded bytes.
|
||||
// Deprecated: use github.com/mr-tron/base58.Decode instead.
|
||||
func Decode(str string) ([]byte, error) {
|
||||
return FastBase58Decoding(str)
|
||||
}
|
||||
|
||||
// DecodeAlphabet decodes the base58 encoded bytes using the given b58 alphabet.
|
||||
// Deprecated: use github.com/mr-tron/base58.DecodeAlphabet instead.
|
||||
func DecodeAlphabet(str string, alphabet *Alphabet) ([]byte, error) {
|
||||
return FastBase58DecodingAlphabet(str, alphabet)
|
||||
}
|
||||
|
||||
// FastBase58Decoding decodes the base58 encoded bytes.
|
||||
// Deprecated: use github.com/mr-tron/base58.Decode instead.
|
||||
func FastBase58Decoding(str string) ([]byte, error) {
|
||||
return FastBase58DecodingAlphabet(str, BTCAlphabet)
|
||||
}
|
||||
|
||||
// FastBase58DecodingAlphabet decodes the base58 encoded bytes using the given
|
||||
// b58 alphabet.
|
||||
// Deprecated: use github.com/mr-tron/base58.FastBase58DecodingAlphabet instead.
|
||||
func FastBase58DecodingAlphabet(str string, alphabet *Alphabet) ([]byte, error) {
|
||||
if len(str) == 0 {
|
||||
return nil, fmt.Errorf("zero length string")
|
||||
@@ -227,12 +237,14 @@ func FastBase58DecodingAlphabet(str string, alphabet *Alphabet) ([]byte, error)
|
||||
}
|
||||
|
||||
// TrivialBase58Decoding decodes the base58 encoded bytes (inefficiently).
|
||||
// Deprecated: use github.com/mr-tron/base58.Decode instead.
|
||||
func TrivialBase58Decoding(str string) ([]byte, error) {
|
||||
return TrivialBase58DecodingAlphabet(str, BTCAlphabet)
|
||||
}
|
||||
|
||||
// TrivialBase58DecodingAlphabet decodes the base58 encoded bytes
|
||||
// (inefficiently) using the given b58 alphabet.
|
||||
// Deprecated: use github.com/mr-tron/base58.FastBase58DecodingAlphabet instead.
|
||||
func TrivialBase58DecodingAlphabet(str string, alphabet *Alphabet) ([]byte, error) {
|
||||
zero := alphabet.encode[0]
|
||||
|
||||
|
||||
Vendored
+31
-19
@@ -4,6 +4,8 @@ filippo.io/hpke
|
||||
filippo.io/hpke/crypto
|
||||
filippo.io/hpke/crypto/ecdh
|
||||
filippo.io/hpke/internal/byteorder
|
||||
# github.com/bits-and-blooms/bitset v1.24.4
|
||||
## explicit; go 1.16
|
||||
# github.com/btcsuite/btcd/btcutil v1.1.6
|
||||
## explicit; go 1.16
|
||||
github.com/btcsuite/btcd/btcutil/bech32
|
||||
@@ -45,6 +47,10 @@ github.com/cloudflare/circl/sign/mldsa/mldsa87/internal
|
||||
github.com/cloudflare/circl/simd/keccakf1600
|
||||
github.com/cloudflare/circl/xof
|
||||
github.com/cloudflare/circl/xof/k12
|
||||
# github.com/consensys/gnark-crypto v0.20.1
|
||||
## explicit; go 1.25.7
|
||||
# github.com/crate-crypto/go-eth-kzg v1.5.0
|
||||
## explicit; go 1.22
|
||||
# github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc
|
||||
## explicit
|
||||
github.com/davecgh/go-spew/spew
|
||||
@@ -64,6 +70,8 @@ github.com/dustin/go-humanize
|
||||
## explicit; go 1.13
|
||||
github.com/emicklei/go-restful/v3
|
||||
github.com/emicklei/go-restful/v3/log
|
||||
# github.com/ethereum/c-kzg-4844/v2 v2.1.7
|
||||
## explicit; go 1.19
|
||||
# github.com/fxamacker/cbor/v2 v2.9.1
|
||||
## explicit; go 1.20
|
||||
github.com/fxamacker/cbor/v2
|
||||
@@ -125,7 +133,7 @@ github.com/josharian/intern
|
||||
# github.com/json-iterator/go v1.1.12
|
||||
## explicit; go 1.12
|
||||
github.com/json-iterator/go
|
||||
# github.com/klauspost/compress v1.18.5
|
||||
# github.com/klauspost/compress v1.18.6
|
||||
## explicit; go 1.24
|
||||
github.com/klauspost/compress
|
||||
github.com/klauspost/compress/fse
|
||||
@@ -144,8 +152,8 @@ github.com/klauspost/cpuid/v2
|
||||
# github.com/klauspost/crc32 v1.3.0
|
||||
## explicit; go 1.23.0
|
||||
github.com/klauspost/crc32
|
||||
# github.com/luxfi/accel v1.1.9
|
||||
## explicit; go 1.26.3
|
||||
# github.com/luxfi/accel v1.2.4
|
||||
## explicit; go 1.26.4
|
||||
github.com/luxfi/accel
|
||||
github.com/luxfi/accel/internal/capi
|
||||
# github.com/luxfi/address v1.0.1
|
||||
@@ -167,8 +175,8 @@ github.com/luxfi/constants
|
||||
# github.com/luxfi/container v0.0.4
|
||||
## explicit; go 1.25.5
|
||||
github.com/luxfi/container
|
||||
# github.com/luxfi/crypto v1.19.17
|
||||
## explicit; go 1.26.3
|
||||
# github.com/luxfi/crypto v1.19.27
|
||||
## explicit; go 1.26.4
|
||||
github.com/luxfi/crypto
|
||||
github.com/luxfi/crypto/backend
|
||||
github.com/luxfi/crypto/bls
|
||||
@@ -185,11 +193,13 @@ github.com/luxfi/crypto/secp256k1/libsecp256k1/include
|
||||
github.com/luxfi/crypto/secp256k1/libsecp256k1/src
|
||||
github.com/luxfi/crypto/secp256k1/libsecp256k1/src/modules/recovery
|
||||
github.com/luxfi/crypto/secret
|
||||
# github.com/luxfi/crypto/ipa v1.2.4
|
||||
## explicit; go 1.18
|
||||
# github.com/luxfi/formatting v1.0.1
|
||||
## explicit; go 1.25.5
|
||||
github.com/luxfi/formatting
|
||||
# github.com/luxfi/geth v1.16.98
|
||||
## explicit; go 1.26.3
|
||||
# github.com/luxfi/geth v1.17.12
|
||||
## explicit; go 1.26.4
|
||||
github.com/luxfi/geth/common
|
||||
github.com/luxfi/geth/common/hexutil
|
||||
# github.com/luxfi/go-bip32 v1.0.2
|
||||
@@ -205,8 +215,8 @@ github.com/luxfi/ids
|
||||
# github.com/luxfi/keys v1.1.0
|
||||
## explicit; go 1.26.3
|
||||
github.com/luxfi/keys
|
||||
# github.com/luxfi/log v1.4.1
|
||||
## explicit; go 1.24.9
|
||||
# github.com/luxfi/log v1.4.3
|
||||
## explicit; go 1.26.3
|
||||
github.com/luxfi/log
|
||||
github.com/luxfi/log/internal/json
|
||||
# github.com/luxfi/math v1.4.1
|
||||
@@ -221,14 +231,16 @@ github.com/luxfi/math/big
|
||||
# github.com/luxfi/mdns v0.1.1
|
||||
## explicit; go 1.26.3
|
||||
github.com/luxfi/mdns
|
||||
# github.com/luxfi/metric v1.5.7
|
||||
# github.com/luxfi/metric v1.5.8
|
||||
## explicit; go 1.26.3
|
||||
github.com/luxfi/metric
|
||||
github.com/luxfi/metric/client
|
||||
# github.com/luxfi/mock v0.1.1
|
||||
## explicit; go 1.25.5
|
||||
github.com/luxfi/mock/gomock
|
||||
# github.com/luxfi/proto v1.0.0
|
||||
# github.com/luxfi/pq v1.0.3
|
||||
## explicit; go 1.23.0
|
||||
# github.com/luxfi/proto v1.3.4
|
||||
## explicit; go 1.26.3
|
||||
github.com/luxfi/proto/p/signer
|
||||
# github.com/luxfi/sampler v1.1.0
|
||||
@@ -237,8 +249,8 @@ github.com/luxfi/sampler
|
||||
# github.com/luxfi/tls v1.0.3
|
||||
## explicit; go 1.25.5
|
||||
github.com/luxfi/tls
|
||||
# github.com/luxfi/vm v1.2.0
|
||||
## explicit; go 1.26.3
|
||||
# github.com/luxfi/vm v1.2.3
|
||||
## explicit; go 1.26.4
|
||||
github.com/luxfi/vm/components/verify
|
||||
# github.com/luxfi/zap v0.7.2
|
||||
## explicit; go 1.26.3
|
||||
@@ -259,11 +271,11 @@ github.com/luxfi/zapdb/y
|
||||
github.com/mailru/easyjson/buffer
|
||||
github.com/mailru/easyjson/jlexer
|
||||
github.com/mailru/easyjson/jwriter
|
||||
# github.com/mattn/go-colorable v0.1.14
|
||||
# github.com/mattn/go-colorable v0.1.15
|
||||
## explicit; go 1.18
|
||||
github.com/mattn/go-colorable
|
||||
# github.com/mattn/go-isatty v0.0.20
|
||||
## explicit; go 1.15
|
||||
# github.com/mattn/go-isatty v0.0.22
|
||||
## explicit; go 1.21
|
||||
github.com/mattn/go-isatty
|
||||
# github.com/miekg/dns v1.1.72
|
||||
## explicit; go 1.24.0
|
||||
@@ -296,8 +308,8 @@ github.com/modern-go/concurrent
|
||||
# github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee
|
||||
## explicit; go 1.12
|
||||
github.com/modern-go/reflect2
|
||||
# github.com/mr-tron/base58 v1.2.0
|
||||
## explicit; go 1.12
|
||||
# github.com/mr-tron/base58 v1.3.0
|
||||
## explicit; go 1.11
|
||||
github.com/mr-tron/base58/base58
|
||||
# github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822
|
||||
## explicit
|
||||
@@ -384,7 +396,7 @@ golang.org/x/crypto/pbkdf2
|
||||
golang.org/x/crypto/ripemd160
|
||||
golang.org/x/crypto/scrypt
|
||||
golang.org/x/crypto/sha3
|
||||
# golang.org/x/exp v0.0.0-20260312153236-7ab1446f8b90
|
||||
# golang.org/x/exp v0.0.0-20260529124908-c761662dc8c9
|
||||
## explicit; go 1.25.0
|
||||
golang.org/x/exp/constraints
|
||||
# golang.org/x/mod v0.36.0
|
||||
|
||||
Reference in New Issue
Block a user