From 1d6ec353d81b3b54ecb3d36acc3f24e3f89727a7 Mon Sep 17 00:00:00 2001 From: pavel-raykov Date: Mon, 9 Feb 2026 20:33:28 +0100 Subject: [PATCH 01/13] Minor. --- keystore/admin_test.go | 7 +- keystore/core_keystore_test.go | 3 +- keystore/corekeys/aptoskey/export.go | 47 + keystore/corekeys/aptoskey/export_test.go | 17 + keystore/corekeys/aptoskey/key.go | 87 ++ keystore/corekeys/aptoskey/key_test.go | 19 + keystore/corekeys/cosmoskey/export.go | 47 + keystore/corekeys/cosmoskey/export_test.go | 17 + keystore/corekeys/cosmoskey/key.go | 78 ++ keystore/corekeys/csa.go | 134 -- keystore/corekeys/csa_test.go | 78 -- keystore/corekeys/csakey/export.go | 43 + keystore/corekeys/csakey/export_test.go | 17 + keystore/corekeys/csakey/key_v2.go | 83 ++ keystore/corekeys/csakey/key_v2_test.go | 32 + keystore/corekeys/dkgrecipientkey/export.go | 43 + keystore/corekeys/dkgrecipientkey/key.go | 61 + keystore/corekeys/dkgrecipientkey/key_test.go | 87 ++ keystore/corekeys/ethkey/export.go | 23 + keystore/corekeys/ethkey/export_test.go | 16 + keystore/corekeys/ethkey/key_v2.go | 87 ++ keystore/corekeys/ethkey/key_v2_test.go | 36 + keystore/corekeys/ethkey/models.go | 32 + keystore/corekeys/exporttestutils.go | 41 + keystore/corekeys/models/legacy_key.go | 104 ++ keystore/corekeys/models/models.go | 481 ++++++++ keystore/corekeys/models/models_test.go | 171 +++ keystore/corekeys/ocr2key/cosmos_keyring.go | 118 ++ .../corekeys/ocr2key/cosmos_keyring_test.go | 59 + keystore/corekeys/ocr2key/ed25519_keyring.go | 139 +++ .../corekeys/ocr2key/ed25519_keyring_test.go | 59 + keystore/corekeys/ocr2key/evm_keyring.go | 118 ++ keystore/corekeys/ocr2key/evm_keyring_test.go | 162 +++ keystore/corekeys/ocr2key/export.go | 90 ++ keystore/corekeys/ocr2key/export_test.go | 41 + .../corekeys/ocr2key/generic_key_bundle.go | 190 +++ .../ocr2key/generic_key_bundle_test.go | 154 +++ keystore/corekeys/ocr2key/key_bundle.go | 153 +++ keystore/corekeys/ocr2key/key_bundle_test.go | 63 + keystore/corekeys/ocr2key/offchain_keyring.go | 138 +++ .../corekeys/ocr2key/offchain_keyring_test.go | 68 + keystore/corekeys/ocr2key/solana_keyring.go | 111 ++ .../corekeys/ocr2key/solana_keyring_test.go | 55 + keystore/corekeys/ocr2key/ton_keyring.go | 120 ++ keystore/corekeys/ocr2key/ton_keyring_test.go | 95 ++ keystore/corekeys/ocrkey/config_public_key.go | 72 ++ .../corekeys/ocrkey/config_public_key_test.go | 42 + keystore/corekeys/ocrkey/export.go | 59 + keystore/corekeys/ocrkey/export_test.go | 17 + keystore/corekeys/ocrkey/helpers_test.go | 13 + keystore/corekeys/ocrkey/key_v2.go | 190 +++ keystore/corekeys/ocrkey/key_v2_test.go | 37 + .../corekeys/ocrkey/off_chain_private_key.go | 24 + .../ocrkey/off_chain_private_key_test.go | 20 + .../corekeys/ocrkey/off_chain_public_key.go | 67 + .../ocrkey/off_chain_public_key_test.go | 48 + .../corekeys/ocrkey/on_chain_private_key.go | 25 + .../ocrkey/on_chain_private_key_test.go | 25 + .../corekeys/ocrkey/on_chain_public_key.go | 13 + .../ocrkey/on_chain_public_key_test.go | 22 + .../ocrkey/on_chain_signing_address.go | 69 ++ .../ocrkey/on_chain_signing_address_test.go | 25 + keystore/corekeys/ocrkeybundle.go | 136 -- keystore/corekeys/ocrkeybundle_test.go | 133 -- keystore/corekeys/p2pkey/export.go | 55 + keystore/corekeys/p2pkey/export_test.go | 17 + keystore/corekeys/p2pkey/key_v2.go | 117 ++ keystore/corekeys/p2pkey/key_v2_test.go | 22 + keystore/corekeys/p2pkey/peer_id.go | 96 ++ keystore/corekeys/p2pkey/peer_id_test.go | 72 ++ keystore/corekeys/solkey/export.go | 47 + keystore/corekeys/solkey/export_test.go | 17 + keystore/corekeys/solkey/key.go | 84 ++ keystore/corekeys/starkkey/export.go | 45 + keystore/corekeys/starkkey/export_test.go | 30 + keystore/corekeys/starkkey/key.go | 91 ++ keystore/corekeys/starkkey/ocr2key.go | 188 +++ keystore/corekeys/starkkey/ocr2key_test.go | 202 +++ keystore/corekeys/starkkey/utils.go | 51 + keystore/corekeys/suikey/export.go | 47 + keystore/corekeys/suikey/export_test.go | 17 + keystore/corekeys/suikey/key.go | 107 ++ keystore/corekeys/suikey/key_test.go | 19 + keystore/corekeys/testutils/utils.go | 19 + keystore/corekeys/tonkey/export.go | 49 + keystore/corekeys/tonkey/export_test.go | 17 + keystore/corekeys/tonkey/key.go | 141 +++ keystore/corekeys/tonkey/key_test.go | 142 +++ keystore/corekeys/tronkey/account.go | 178 +++ keystore/corekeys/tronkey/account_test.go | 177 +++ keystore/corekeys/tronkey/export.go | 45 + keystore/corekeys/tronkey/export_test.go | 17 + keystore/corekeys/tronkey/key.go | 84 ++ keystore/corekeys/tronkey/key_test.go | 63 + .../vrfkey/benchmark_vrf_validation_test.go | 26 + keystore/corekeys/vrfkey/crypto.go | 188 +++ keystore/corekeys/vrfkey/crypto_test.go | 29 + keystore/corekeys/vrfkey/export.go | 86 ++ keystore/corekeys/vrfkey/export_test.go | 17 + keystore/corekeys/vrfkey/key_v2.go | 153 +++ keystore/corekeys/vrfkey/key_v2_test.go | 28 + keystore/corekeys/vrfkey/models.go | 73 ++ keystore/corekeys/vrfkey/models_test.go | 32 + keystore/corekeys/vrfkey/proof.go | 67 + keystore/corekeys/vrfkey/proof_test.go | 25 + keystore/corekeys/workflowkey/export.go | 43 + keystore/corekeys/workflowkey/key.go | 129 ++ keystore/corekeys/workflowkey/key_test.go | 116 ++ keystore/go.mod | 262 +++- keystore/go.sum | 1097 +++++++++++++++-- keystore/helpers_test.go | 4 +- keystore/internal/exportutils.go | 84 ++ keystore/keystore.go | 23 +- keystore/scrypt/scrypt.go | 19 + pkg/chains/types/type.go | 120 ++ 115 files changed, 9086 insertions(+), 652 deletions(-) create mode 100644 keystore/corekeys/aptoskey/export.go create mode 100644 keystore/corekeys/aptoskey/export_test.go create mode 100644 keystore/corekeys/aptoskey/key.go create mode 100644 keystore/corekeys/aptoskey/key_test.go create mode 100644 keystore/corekeys/cosmoskey/export.go create mode 100644 keystore/corekeys/cosmoskey/export_test.go create mode 100644 keystore/corekeys/cosmoskey/key.go delete mode 100644 keystore/corekeys/csa.go delete mode 100644 keystore/corekeys/csa_test.go create mode 100644 keystore/corekeys/csakey/export.go create mode 100644 keystore/corekeys/csakey/export_test.go create mode 100644 keystore/corekeys/csakey/key_v2.go create mode 100644 keystore/corekeys/csakey/key_v2_test.go create mode 100644 keystore/corekeys/dkgrecipientkey/export.go create mode 100644 keystore/corekeys/dkgrecipientkey/key.go create mode 100644 keystore/corekeys/dkgrecipientkey/key_test.go create mode 100644 keystore/corekeys/ethkey/export.go create mode 100644 keystore/corekeys/ethkey/export_test.go create mode 100644 keystore/corekeys/ethkey/key_v2.go create mode 100644 keystore/corekeys/ethkey/key_v2_test.go create mode 100644 keystore/corekeys/ethkey/models.go create mode 100644 keystore/corekeys/exporttestutils.go create mode 100644 keystore/corekeys/models/legacy_key.go create mode 100644 keystore/corekeys/models/models.go create mode 100644 keystore/corekeys/models/models_test.go create mode 100644 keystore/corekeys/ocr2key/cosmos_keyring.go create mode 100644 keystore/corekeys/ocr2key/cosmos_keyring_test.go create mode 100644 keystore/corekeys/ocr2key/ed25519_keyring.go create mode 100644 keystore/corekeys/ocr2key/ed25519_keyring_test.go create mode 100644 keystore/corekeys/ocr2key/evm_keyring.go create mode 100644 keystore/corekeys/ocr2key/evm_keyring_test.go create mode 100644 keystore/corekeys/ocr2key/export.go create mode 100644 keystore/corekeys/ocr2key/export_test.go create mode 100644 keystore/corekeys/ocr2key/generic_key_bundle.go create mode 100644 keystore/corekeys/ocr2key/generic_key_bundle_test.go create mode 100644 keystore/corekeys/ocr2key/key_bundle.go create mode 100644 keystore/corekeys/ocr2key/key_bundle_test.go create mode 100644 keystore/corekeys/ocr2key/offchain_keyring.go create mode 100644 keystore/corekeys/ocr2key/offchain_keyring_test.go create mode 100644 keystore/corekeys/ocr2key/solana_keyring.go create mode 100644 keystore/corekeys/ocr2key/solana_keyring_test.go create mode 100644 keystore/corekeys/ocr2key/ton_keyring.go create mode 100644 keystore/corekeys/ocr2key/ton_keyring_test.go create mode 100644 keystore/corekeys/ocrkey/config_public_key.go create mode 100644 keystore/corekeys/ocrkey/config_public_key_test.go create mode 100644 keystore/corekeys/ocrkey/export.go create mode 100644 keystore/corekeys/ocrkey/export_test.go create mode 100644 keystore/corekeys/ocrkey/helpers_test.go create mode 100644 keystore/corekeys/ocrkey/key_v2.go create mode 100644 keystore/corekeys/ocrkey/key_v2_test.go create mode 100644 keystore/corekeys/ocrkey/off_chain_private_key.go create mode 100644 keystore/corekeys/ocrkey/off_chain_private_key_test.go create mode 100644 keystore/corekeys/ocrkey/off_chain_public_key.go create mode 100644 keystore/corekeys/ocrkey/off_chain_public_key_test.go create mode 100644 keystore/corekeys/ocrkey/on_chain_private_key.go create mode 100644 keystore/corekeys/ocrkey/on_chain_private_key_test.go create mode 100644 keystore/corekeys/ocrkey/on_chain_public_key.go create mode 100644 keystore/corekeys/ocrkey/on_chain_public_key_test.go create mode 100644 keystore/corekeys/ocrkey/on_chain_signing_address.go create mode 100644 keystore/corekeys/ocrkey/on_chain_signing_address_test.go delete mode 100644 keystore/corekeys/ocrkeybundle.go delete mode 100644 keystore/corekeys/ocrkeybundle_test.go create mode 100644 keystore/corekeys/p2pkey/export.go create mode 100644 keystore/corekeys/p2pkey/export_test.go create mode 100644 keystore/corekeys/p2pkey/key_v2.go create mode 100644 keystore/corekeys/p2pkey/key_v2_test.go create mode 100644 keystore/corekeys/p2pkey/peer_id.go create mode 100644 keystore/corekeys/p2pkey/peer_id_test.go create mode 100644 keystore/corekeys/solkey/export.go create mode 100644 keystore/corekeys/solkey/export_test.go create mode 100644 keystore/corekeys/solkey/key.go create mode 100644 keystore/corekeys/starkkey/export.go create mode 100644 keystore/corekeys/starkkey/export_test.go create mode 100644 keystore/corekeys/starkkey/key.go create mode 100644 keystore/corekeys/starkkey/ocr2key.go create mode 100644 keystore/corekeys/starkkey/ocr2key_test.go create mode 100644 keystore/corekeys/starkkey/utils.go create mode 100644 keystore/corekeys/suikey/export.go create mode 100644 keystore/corekeys/suikey/export_test.go create mode 100644 keystore/corekeys/suikey/key.go create mode 100644 keystore/corekeys/suikey/key_test.go create mode 100644 keystore/corekeys/testutils/utils.go create mode 100644 keystore/corekeys/tonkey/export.go create mode 100644 keystore/corekeys/tonkey/export_test.go create mode 100644 keystore/corekeys/tonkey/key.go create mode 100644 keystore/corekeys/tonkey/key_test.go create mode 100644 keystore/corekeys/tronkey/account.go create mode 100644 keystore/corekeys/tronkey/account_test.go create mode 100644 keystore/corekeys/tronkey/export.go create mode 100644 keystore/corekeys/tronkey/export_test.go create mode 100644 keystore/corekeys/tronkey/key.go create mode 100644 keystore/corekeys/tronkey/key_test.go create mode 100644 keystore/corekeys/vrfkey/benchmark_vrf_validation_test.go create mode 100644 keystore/corekeys/vrfkey/crypto.go create mode 100644 keystore/corekeys/vrfkey/crypto_test.go create mode 100644 keystore/corekeys/vrfkey/export.go create mode 100644 keystore/corekeys/vrfkey/export_test.go create mode 100644 keystore/corekeys/vrfkey/key_v2.go create mode 100644 keystore/corekeys/vrfkey/key_v2_test.go create mode 100644 keystore/corekeys/vrfkey/models.go create mode 100644 keystore/corekeys/vrfkey/models_test.go create mode 100644 keystore/corekeys/vrfkey/proof.go create mode 100644 keystore/corekeys/vrfkey/proof_test.go create mode 100644 keystore/corekeys/workflowkey/export.go create mode 100644 keystore/corekeys/workflowkey/key.go create mode 100644 keystore/corekeys/workflowkey/key_test.go create mode 100644 keystore/internal/exportutils.go create mode 100644 keystore/scrypt/scrypt.go create mode 100644 pkg/chains/types/type.go diff --git a/keystore/admin_test.go b/keystore/admin_test.go index de8f51abad..17ada42b62 100644 --- a/keystore/admin_test.go +++ b/keystore/admin_test.go @@ -14,6 +14,7 @@ import ( gethcrypto "github.com/ethereum/go-ethereum/crypto" "github.com/smartcontractkit/chainlink-common/keystore" + "github.com/smartcontractkit/chainlink-common/keystore/scrypt" ) func TestKeystore_CreateDeleteReadKeys(t *testing.T) { @@ -114,7 +115,7 @@ func TestKeystore_CreateDeleteReadKeys(t *testing.T) { for _, tt := range tt { t.Run(tt.name, func(t *testing.T) { storage := keystore.NewMemoryStorage() - ks, err := keystore.LoadKeystore(ctx, storage, "test-password", keystore.WithScryptParams(keystore.FastScryptParams)) + ks, err := keystore.LoadKeystore(ctx, storage, "test-password", keystore.WithScryptParams(scrypt.FastScryptParams)) require.NoError(t, err) for _, op := range tt.keyOps { switch op.op { @@ -163,7 +164,7 @@ func TestKeystore_ConcurrentCreateAndRead(t *testing.T) { ctx := context.Background() st := keystore.NewMemoryStorage() - ks, err := keystore.LoadKeystore(ctx, st, "test", keystore.WithScryptParams(keystore.FastScryptParams)) + ks, err := keystore.LoadKeystore(ctx, st, "test", keystore.WithScryptParams(scrypt.FastScryptParams)) require.NoError(t, err) const ( @@ -217,7 +218,7 @@ func TestKeystore_ExportImport(t *testing.T) { t.Run("export and import", func(t *testing.T) { exportParams := keystore.EncryptionParams{ Password: "export-pass", - ScryptParams: keystore.FastScryptParams, + ScryptParams: scrypt.FastScryptParams, } _, err = ks1.CreateKeys(t.Context(), keystore.CreateKeysRequest{ Keys: []keystore.CreateKeyRequest{ diff --git a/keystore/core_keystore_test.go b/keystore/core_keystore_test.go index 6d45f5264c..d6cecabcf7 100644 --- a/keystore/core_keystore_test.go +++ b/keystore/core_keystore_test.go @@ -7,12 +7,13 @@ import ( "github.com/stretchr/testify/require" "github.com/smartcontractkit/chainlink-common/keystore" + "github.com/smartcontractkit/chainlink-common/keystore/scrypt" ) func TestCoreKeystore(t *testing.T) { ctx := t.Context() - ks, err := keystore.LoadKeystore(t.Context(), keystore.NewMemoryStorage(), "test-password", keystore.WithScryptParams(keystore.FastScryptParams)) + ks, err := keystore.LoadKeystore(t.Context(), keystore.NewMemoryStorage(), "test-password", keystore.WithScryptParams(scrypt.FastScryptParams)) require.NoError(t, err) coreKs := keystore.NewCoreKeystore(ks) diff --git a/keystore/corekeys/aptoskey/export.go b/keystore/corekeys/aptoskey/export.go new file mode 100644 index 0000000000..1ba85f6ac9 --- /dev/null +++ b/keystore/corekeys/aptoskey/export.go @@ -0,0 +1,47 @@ +package aptoskey + +import ( + "encoding/hex" + + "github.com/ethereum/go-ethereum/accounts/keystore" + + "github.com/smartcontractkit/chainlink-common/keystore/internal" + "github.com/smartcontractkit/chainlink-common/keystore/scrypt" +) + +const keyTypeIdentifier = "Aptos" + +// FromEncryptedJSON gets key from json and password +func FromEncryptedJSON(keyJSON []byte, password string) (Key, error) { + return internal.FromEncryptedJSON( + keyTypeIdentifier, + keyJSON, + password, + adulteratedPassword, + func(_ internal.EncryptedKeyExport, rawPrivKey internal.Raw) (Key, error) { + return KeyFor(rawPrivKey), nil + }, + ) +} + +// ToEncryptedJSON returns encrypted JSON representing key +func (key Key) ToEncryptedJSON(password string, scryptParams scrypt.ScryptParams) (export []byte, err error) { + return internal.ToEncryptedJSON( + keyTypeIdentifier, + key, + password, + scryptParams, + adulteratedPassword, + func(id string, key Key, cryptoJSON keystore.CryptoJSON) internal.EncryptedKeyExport { + return internal.EncryptedKeyExport{ + KeyType: id, + PublicKey: hex.EncodeToString(key.pubKey), + Crypto: cryptoJSON, + } + }, + ) +} + +func adulteratedPassword(password string) string { + return "aptoskey" + password +} diff --git a/keystore/corekeys/aptoskey/export_test.go b/keystore/corekeys/aptoskey/export_test.go new file mode 100644 index 0000000000..aa1f4cce73 --- /dev/null +++ b/keystore/corekeys/aptoskey/export_test.go @@ -0,0 +1,17 @@ +package aptoskey + +import ( + "testing" +) + +func TestAptosKeys_ExportImport(t *testing.T) { + corekeys2.RunKeyExportImportTestcase(t, createKey, decryptKey) +} + +func createKey() (corekeys2.KeyType, error) { + return New() +} + +func decryptKey(keyJSON []byte, password string) (corekeys2.KeyType, error) { + return FromEncryptedJSON(keyJSON, password) +} diff --git a/keystore/corekeys/aptoskey/key.go b/keystore/corekeys/aptoskey/key.go new file mode 100644 index 0000000000..ed8b98c107 --- /dev/null +++ b/keystore/corekeys/aptoskey/key.go @@ -0,0 +1,87 @@ +package aptoskey + +import ( + "crypto" + "crypto/ed25519" + crypto_rand "crypto/rand" + "fmt" + "io" + + "golang.org/x/crypto/sha3" + + "github.com/smartcontractkit/chainlink-common/keystore/internal" +) + +// Key represents Aptos key +type Key struct { + // TODO: store initial Account() derivation to support key rotation + raw internal.Raw + signFn func(io.Reader, []byte, crypto.SignerOpts) ([]byte, error) + pubKey ed25519.PublicKey +} + +func KeyFor(raw internal.Raw) Key { + privKey := ed25519.NewKeyFromSeed(internal.Bytes(raw)) + pubKey := privKey.Public().(ed25519.PublicKey) + return Key{ + raw: raw, + signFn: privKey.Sign, + pubKey: pubKey, + } +} + +// New creates new Key +func New() (Key, error) { + return newFrom(crypto_rand.Reader) +} + +// MustNewInsecure return Key if no error +func MustNewInsecure(reader io.Reader) Key { + key, err := newFrom(reader) + if err != nil { + panic(err) + } + return key +} + +// newFrom creates new Key from a provided random reader +func newFrom(reader io.Reader) (Key, error) { + pub, priv, err := ed25519.GenerateKey(reader) + if err != nil { + return Key{}, err + } + return Key{ + raw: internal.NewRaw(priv.Seed()), + signFn: priv.Sign, + pubKey: pub, + }, nil +} + +// ID gets Key ID +func (key Key) ID() string { + return key.PublicKeyStr() +} + +// https://github.com/aptos-foundation/AIPs/blob/main/aips/aip-40.md#long +func (key Key) Account() string { + authKey := sha3.Sum256(append([]byte(key.pubKey), 0x00)) + return fmt.Sprintf("%064x", authKey) +} + +// GetPublic get Key's public key +func (key Key) GetPublic() ed25519.PublicKey { + return key.pubKey +} + +// PublicKeyStr returns hex encoded public key +func (key Key) PublicKeyStr() string { + return fmt.Sprintf("%064x", key.pubKey) +} + +// Raw returns the seed from private key +func (key Key) Raw() internal.Raw { return key.raw } + +// Sign is used to sign a message +func (key Key) Sign(msg []byte) ([]byte, error) { + return key.signFn(crypto_rand.Reader, msg, crypto.Hash(0)) // no specific hash function used +} diff --git a/keystore/corekeys/aptoskey/key_test.go b/keystore/corekeys/aptoskey/key_test.go new file mode 100644 index 0000000000..a0a3266566 --- /dev/null +++ b/keystore/corekeys/aptoskey/key_test.go @@ -0,0 +1,19 @@ +package aptoskey + +import ( + "encoding/hex" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + "github.com/smartcontractkit/chainlink-common/keystore/internal" +) + +func TestAptosKey(t *testing.T) { + bytes, err := hex.DecodeString("f0d07ab448018b2754475f9a3b580218b0675a1456aad96ad607c7bbd7d9237b") + require.NoError(t, err) + k := KeyFor(internal.NewRaw(bytes)) + assert.Equal(t, "2acd605efc181e2af8a0b8c0686a5e12578efa1253d15a235fa5e5ad970c4b29", k.PublicKeyStr()) + assert.Equal(t, "69d8b07f5945185873c622ea66873b0e1fb921de7b94d904d3ef9be80770682e", k.Account()) +} diff --git a/keystore/corekeys/cosmoskey/export.go b/keystore/corekeys/cosmoskey/export.go new file mode 100644 index 0000000000..d49ead9772 --- /dev/null +++ b/keystore/corekeys/cosmoskey/export.go @@ -0,0 +1,47 @@ +package cosmoskey + +import ( + "encoding/hex" + + "github.com/ethereum/go-ethereum/accounts/keystore" + + "github.com/smartcontractkit/chainlink-common/keystore/internal" + "github.com/smartcontractkit/chainlink-common/keystore/scrypt" +) + +const keyTypeIdentifier = "Cosmos" + +// FromEncryptedJSON gets key from json and password +func FromEncryptedJSON(keyJSON []byte, password string) (Key, error) { + return internal.FromEncryptedJSON( + keyTypeIdentifier, + keyJSON, + password, + adulteratedPassword, + func(_ internal.EncryptedKeyExport, rawPrivKey internal.Raw) (Key, error) { + return KeyFor(rawPrivKey), nil + }, + ) +} + +// ToEncryptedJSON returns encrypted JSON representing key +func (key Key) ToEncryptedJSON(password string, scryptParams scrypt.ScryptParams) (export []byte, err error) { + return internal.ToEncryptedJSON( + keyTypeIdentifier, + key, + password, + scryptParams, + adulteratedPassword, + func(id string, key Key, cryptoJSON keystore.CryptoJSON) internal.EncryptedKeyExport { + return internal.EncryptedKeyExport{ + KeyType: id, + PublicKey: hex.EncodeToString(key.PublicKey().Bytes()), + Crypto: cryptoJSON, + } + }, + ) +} + +func adulteratedPassword(password string) string { + return "cosmoskey" + password +} diff --git a/keystore/corekeys/cosmoskey/export_test.go b/keystore/corekeys/cosmoskey/export_test.go new file mode 100644 index 0000000000..9abbbbec22 --- /dev/null +++ b/keystore/corekeys/cosmoskey/export_test.go @@ -0,0 +1,17 @@ +package cosmoskey + +import ( + "testing" +) + +func TestCosmosKeys_ExportImport(t *testing.T) { + corekeys2.RunKeyExportImportTestcase(t, createKey, decryptKey) +} + +func createKey() (corekeys2.KeyType, error) { + return New(), nil +} + +func decryptKey(keyJSON []byte, password string) (corekeys2.KeyType, error) { + return FromEncryptedJSON(keyJSON, password) +} diff --git a/keystore/corekeys/cosmoskey/key.go b/keystore/corekeys/cosmoskey/key.go new file mode 100644 index 0000000000..cc4355355b --- /dev/null +++ b/keystore/corekeys/cosmoskey/key.go @@ -0,0 +1,78 @@ +package cosmoskey + +import ( + "crypto/ecdsa" + cryptorand "crypto/rand" + "fmt" + "io" + "math/big" + + "github.com/cosmos/cosmos-sdk/crypto/hd" + "github.com/cosmos/cosmos-sdk/crypto/keyring" + "github.com/ethereum/go-ethereum/crypto" + + cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" + + "github.com/smartcontractkit/chainlink-common/keystore/internal" +) + +var secpSigningAlgo, _ = keyring.NewSigningAlgoFromString(string(hd.Secp256k1Type), []keyring.SignatureAlgo{hd.Secp256k1}) + +func KeyFor(raw internal.Raw) Key { + d := big.NewInt(0).SetBytes(internal.Bytes(raw)) + privKey := secpSigningAlgo.Generate()(d.Bytes()) + return Key{ + raw: raw, + signFn: privKey.Sign, + pubKey: privKey.PubKey(), + } +} + +// Key represents Cosmos key +type Key struct { + raw internal.Raw + signFn func([]byte) ([]byte, error) + pubKey cryptotypes.PubKey +} + +// New creates new Key +func New() Key { + return newFrom(cryptorand.Reader) +} + +// MustNewInsecure return Key +func MustNewInsecure(reader io.Reader) Key { + return newFrom(reader) +} + +func newFrom(reader io.Reader) Key { + rawKey, err := ecdsa.GenerateKey(crypto.S256(), reader) + if err != nil { + panic(err) + } + privKey := secpSigningAlgo.Generate()(rawKey.D.Bytes()) + + return Key{ + raw: internal.NewRaw(rawKey.D.Bytes()), + signFn: privKey.Sign, + pubKey: privKey.PubKey(), + } +} + +func (key Key) ID() string { + return key.PublicKeyStr() +} + +func (key Key) PublicKey() (pubKey cryptotypes.PubKey) { + return key.pubKey +} + +func (key Key) PublicKeyStr() string { + return fmt.Sprintf("%X", key.pubKey.Bytes()) +} + +func (key Key) Raw() internal.Raw { return key.raw } + +func (key Key) Sign(data []byte) ([]byte, error) { + return key.signFn(data) +} diff --git a/keystore/corekeys/csa.go b/keystore/corekeys/csa.go deleted file mode 100644 index 2df114dde1..0000000000 --- a/keystore/corekeys/csa.go +++ /dev/null @@ -1,134 +0,0 @@ -// `corekeys` provides utilities to generate keys that are compatible with the core node -// and can be imported by it. -package corekeys - -import ( - "context" - "encoding/json" - "errors" - "fmt" - - gethkeystore "github.com/ethereum/go-ethereum/accounts/keystore" - "google.golang.org/protobuf/proto" - - "github.com/smartcontractkit/chainlink-common/keystore" - "github.com/smartcontractkit/chainlink-common/keystore/serialization" -) - -var ( - ErrInvalidExportFormat = errors.New("invalid export format") -) - -const ( - TypeCSA = "csa" - nameDefault = "default" - exportFormat = "github.com/smartcontractkit/chainlink-common/keystore/corekeys" -) - -type Store struct { - keystore.Keystore -} - -type Envelope struct { - Type string - Keys []keystore.ExportKeyResponse - ExportFormat string -} - -func NewStore(ks keystore.Keystore) *Store { - return &Store{ - Keystore: ks, - } -} - -// decryptKey decrypts an encrypted key using the provided password and returns the deserialized key. -func decryptKey(encryptedData []byte, password string) (*serialization.Key, error) { - encData := gethkeystore.CryptoJSON{} - err := json.Unmarshal(encryptedData, &encData) - if err != nil { - return nil, fmt.Errorf("could not unmarshal key material into CryptoJSON: %w", err) - } - - decData, err := gethkeystore.DecryptDataV3(encData, password) - if err != nil { - return nil, fmt.Errorf("could not decrypt data: %w", err) - } - - keypb := &serialization.Key{} - err = proto.Unmarshal(decData, keypb) - if err != nil { - return nil, fmt.Errorf("could not unmarshal key into serialization.Key: %w", err) - } - - return keypb, nil -} - -func (ks *Store) GenerateEncryptedCSAKey(ctx context.Context, password string) ([]byte, error) { - path := keystore.NewKeyPath(TypeCSA, nameDefault) - _, err := ks.CreateKeys(ctx, keystore.CreateKeysRequest{ - Keys: []keystore.CreateKeyRequest{ - { - KeyName: path.String(), - KeyType: keystore.Ed25519, - }, - }, - }) - if err != nil { - return nil, fmt.Errorf("failed to generate exportable key: %w", err) - } - - er, err := ks.ExportKeys(ctx, keystore.ExportKeysRequest{ - Keys: []keystore.ExportKeyParam{ - { - KeyName: path.String(), - Enc: keystore.EncryptionParams{ - Password: password, - ScryptParams: keystore.DefaultScryptParams, - }, - }, - }, - }) - if err != nil { - return nil, fmt.Errorf("failed to export key: %w", err) - } - - envelope := Envelope{ - Type: TypeCSA, - Keys: er.Keys, - ExportFormat: exportFormat, - } - - data, err := json.Marshal(&envelope) - if err != nil { - return nil, fmt.Errorf("failed to marshal envelope: %w", err) - } - - return data, nil -} - -func FromEncryptedCSAKey(data []byte, password string) ([]byte, error) { - envelope := Envelope{} - err := json.Unmarshal(data, &envelope) - if err != nil { - return nil, fmt.Errorf("could not unmarshal import data into envelope: %w", err) - } - - if envelope.ExportFormat != exportFormat { - return nil, fmt.Errorf("invalid export format: %w", ErrInvalidExportFormat) - } - - if envelope.Type != TypeCSA { - return nil, fmt.Errorf("invalid key type: expected %s, got %s", TypeCSA, envelope.Type) - } - - if len(envelope.Keys) != 1 { - return nil, fmt.Errorf("expected exactly one key in envelope, got %d", len(envelope.Keys)) - } - - keypb, err := decryptKey(envelope.Keys[0].Data, password) - if err != nil { - return nil, err - } - - return keypb.PrivateKey, nil -} diff --git a/keystore/corekeys/csa_test.go b/keystore/corekeys/csa_test.go deleted file mode 100644 index 2ab94720c2..0000000000 --- a/keystore/corekeys/csa_test.go +++ /dev/null @@ -1,78 +0,0 @@ -package corekeys - -import ( - "crypto/ed25519" - "testing" - - "github.com/stretchr/testify/require" - - "github.com/smartcontractkit/chainlink-common/keystore" -) - -func TestCSAKeyRoundTrip(t *testing.T) { - t.Parallel() - ctx := t.Context() - password := "test-password" - - st := keystore.NewMemoryStorage() - ks, err := keystore.LoadKeystore(ctx, st, "test", - keystore.WithScryptParams(keystore.FastScryptParams), - ) - require.NoError(t, err) - - coreshimKs := NewStore(ks) - - encryptedKey, err := coreshimKs.GenerateEncryptedCSAKey(ctx, password) - require.NoError(t, err) - require.NotEmpty(t, encryptedKey) - - csaKeyPath := keystore.NewKeyPath(TypeCSA, nameDefault) - getKeysResp, err := ks.GetKeys(ctx, keystore.GetKeysRequest{ - KeyNames: []string{csaKeyPath.String()}, - }) - require.NoError(t, err) - require.Len(t, getKeysResp.Keys, 1) - - storedPublicKey := getKeysResp.Keys[0].KeyInfo.PublicKey - require.NotEmpty(t, storedPublicKey) - - privateKey, err := FromEncryptedCSAKey(encryptedKey, password) - require.NoError(t, err) - require.NotEmpty(t, privateKey) - - require.Len(t, privateKey, 64) - - derivedPublicKey := ed25519.PrivateKey(privateKey).Public().(ed25519.PublicKey) - require.Equal(t, storedPublicKey, []byte(derivedPublicKey)) -} - -func TestCSAKeyImportWithWrongPassword(t *testing.T) { - t.Parallel() - ctx := t.Context() - password := "test-password" - wrongPassword := "wrong-password" - - st := keystore.NewMemoryStorage() - ks, err := keystore.LoadKeystore(ctx, st, "test", - keystore.WithScryptParams(keystore.FastScryptParams), - ) - require.NoError(t, err) - - coreshimKs := NewStore(ks) - - encryptedKey, err := coreshimKs.GenerateEncryptedCSAKey(ctx, password) - require.NoError(t, err) - require.NotNil(t, encryptedKey) - - _, err = FromEncryptedCSAKey(encryptedKey, wrongPassword) - require.Error(t, err) - require.Contains(t, err.Error(), "could not decrypt data") -} - -func TestCSAKeyImportInvalidFormat(t *testing.T) { - t.Parallel() - - _, err := FromEncryptedCSAKey([]byte("invalid json"), "password") - require.Error(t, err) - require.Contains(t, err.Error(), "could not unmarshal import data") -} diff --git a/keystore/corekeys/csakey/export.go b/keystore/corekeys/csakey/export.go new file mode 100644 index 0000000000..6d9561d6ec --- /dev/null +++ b/keystore/corekeys/csakey/export.go @@ -0,0 +1,43 @@ +package csakey + +import ( + "github.com/ethereum/go-ethereum/accounts/keystore" + + "github.com/smartcontractkit/chainlink-common/keystore/internal" + "github.com/smartcontractkit/chainlink-common/keystore/scrypt" +) + +const keyTypeIdentifier = "CSA" + +func FromEncryptedJSON(keyJSON []byte, password string) (KeyV2, error) { + return internal.FromEncryptedJSON( + keyTypeIdentifier, + keyJSON, + password, + adulteratedPassword, + func(_ internal.EncryptedKeyExport, rawPrivKey internal.Raw) (KeyV2, error) { + return KeyFor(rawPrivKey), nil + }, + ) +} + +func (k KeyV2) ToEncryptedJSON(password string, scryptParams scrypt.ScryptParams) (export []byte, err error) { + return internal.ToEncryptedJSON( + keyTypeIdentifier, + k, + password, + scryptParams, + adulteratedPassword, + func(id string, key KeyV2, cryptoJSON keystore.CryptoJSON) internal.EncryptedKeyExport { + return internal.EncryptedKeyExport{ + KeyType: id, + PublicKey: key.PublicKeyString(), + Crypto: cryptoJSON, + } + }, + ) +} + +func adulteratedPassword(password string) string { + return "csakey" + password +} diff --git a/keystore/corekeys/csakey/export_test.go b/keystore/corekeys/csakey/export_test.go new file mode 100644 index 0000000000..6c440b2f2e --- /dev/null +++ b/keystore/corekeys/csakey/export_test.go @@ -0,0 +1,17 @@ +package csakey + +import ( + "testing" +) + +func TestCSAKeys_ExportImport(t *testing.T) { + corekeys2.RunKeyExportImportTestcase(t, createKey, decryptKey) +} + +func createKey() (corekeys2.KeyType, error) { + return NewV2() +} + +func decryptKey(keyJSON []byte, password string) (corekeys2.KeyType, error) { + return FromEncryptedJSON(keyJSON, password) +} diff --git a/keystore/corekeys/csakey/key_v2.go b/keystore/corekeys/csakey/key_v2.go new file mode 100644 index 0000000000..acf2ee0798 --- /dev/null +++ b/keystore/corekeys/csakey/key_v2.go @@ -0,0 +1,83 @@ +package csakey + +import ( + "crypto" + "crypto/ed25519" + cryptorand "crypto/rand" + "encoding/hex" + "fmt" + "io" + "math/big" + + "github.com/smartcontractkit/wsrpc/credentials" + + "github.com/smartcontractkit/chainlink-common/keystore/internal" +) + +func KeyFor(raw internal.Raw) KeyV2 { + privKey := ed25519.PrivateKey(internal.Bytes(raw)) + return KeyV2{ + raw: raw, + signer: &privKey, + PublicKey: privKey.Public().(ed25519.PublicKey), + } +} + +type KeyV2 struct { + raw internal.Raw + signer crypto.Signer + + PublicKey ed25519.PublicKey + Version int +} + +func (k KeyV2) StaticSizedPublicKey() (sspk credentials.StaticSizedPublicKey) { + if len(k.PublicKey) != ed25519.PublicKeySize { + panic(fmt.Sprintf("expected ed25519.PublicKey to have len %d but got len %d", ed25519.PublicKeySize, len(k.PublicKey))) + } + copy(sspk[:], k.PublicKey) + return sspk +} + +func NewV2() (KeyV2, error) { + pubKey, privKey, err := ed25519.GenerateKey(cryptorand.Reader) + if err != nil { + return KeyV2{}, err + } + return KeyV2{ + raw: internal.NewRaw(privKey), + signer: &privKey, + PublicKey: pubKey, + Version: 2, + }, nil +} + +func MustNewV2XXXTestingOnly(k *big.Int) KeyV2 { + seed := make([]byte, ed25519.SeedSize) + copy(seed, k.Bytes()) + privKey := ed25519.NewKeyFromSeed(seed) + return KeyV2{ + raw: internal.NewRaw(privKey), + signer: privKey, + PublicKey: privKey.Public().(ed25519.PublicKey), + Version: 2, + } +} + +func (k KeyV2) ID() string { + return k.PublicKeyString() +} + +func (k KeyV2) PublicKeyString() string { + return hex.EncodeToString(k.PublicKey) +} + +func (k KeyV2) Raw() internal.Raw { + return k.raw +} + +func (k KeyV2) Public() crypto.PublicKey { return k.PublicKey } + +func (k KeyV2) Sign(rand io.Reader, message []byte, opts crypto.SignerOpts) (signature []byte, err error) { + return k.signer.Sign(rand, message, opts) +} diff --git a/keystore/corekeys/csakey/key_v2_test.go b/keystore/corekeys/csakey/key_v2_test.go new file mode 100644 index 0000000000..262673939b --- /dev/null +++ b/keystore/corekeys/csakey/key_v2_test.go @@ -0,0 +1,32 @@ +package csakey + +import ( + "crypto/ed25519" + "encoding/hex" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + "github.com/smartcontractkit/chainlink-common/keystore/internal" +) + +func TestCSAKeyV2_FromRawPrivateKey(t *testing.T) { + pubKey, privKey, err := ed25519.GenerateKey(nil) + require.NoError(t, err) + + keyV2 := KeyFor(internal.NewRaw(privKey)) + + assert.Equal(t, pubKey, keyV2.PublicKey) + assert.Equal(t, []byte(privKey), internal.Bytes(keyV2.raw)) + assert.Equal(t, hex.EncodeToString(pubKey), keyV2.PublicKeyString()) +} + +func TestCSAKeyV2_NewV2(t *testing.T) { + keyV2, err := NewV2() + require.NoError(t, err) + + assert.Equal(t, 2, keyV2.Version) + assert.NotNil(t, keyV2.PublicKey) + assert.NotNil(t, keyV2.raw) +} diff --git a/keystore/corekeys/dkgrecipientkey/export.go b/keystore/corekeys/dkgrecipientkey/export.go new file mode 100644 index 0000000000..3dbd916831 --- /dev/null +++ b/keystore/corekeys/dkgrecipientkey/export.go @@ -0,0 +1,43 @@ +package dkgrecipientkey + +import ( + "github.com/ethereum/go-ethereum/accounts/keystore" + + "github.com/smartcontractkit/chainlink-common/keystore/internal" + "github.com/smartcontractkit/chainlink-common/keystore/scrypt" +) + +const keyTypeIdentifier = "DKGRecipient" + +func FromEncryptedJSON(keyJSON []byte, password string) (Key, error) { + return internal.FromEncryptedJSON( + keyTypeIdentifier, + keyJSON, + password, + adulteratedPassword, + func(_ internal.EncryptedKeyExport, rawPrivKey internal.Raw) (Key, error) { + return KeyFor(rawPrivKey), nil + }, + ) +} + +func (k Key) ToEncryptedJSON(password string, scryptParams scrypt.ScryptParams) (export []byte, err error) { + return internal.ToEncryptedJSON( + keyTypeIdentifier, + k, + password, + scryptParams, + adulteratedPassword, + func(id string, key Key, cryptoJSON keystore.CryptoJSON) internal.EncryptedKeyExport { + return internal.EncryptedKeyExport{ + KeyType: id, + PublicKey: key.PublicKeyString(), + Crypto: cryptoJSON, + } + }, + ) +} + +func adulteratedPassword(password string) string { + return "dkgrecipientkey" + password +} diff --git a/keystore/corekeys/dkgrecipientkey/key.go b/keystore/corekeys/dkgrecipientkey/key.go new file mode 100644 index 0000000000..ad28773d99 --- /dev/null +++ b/keystore/corekeys/dkgrecipientkey/key.go @@ -0,0 +1,61 @@ +package dkgrecipientkey + +import ( + cryptorand "crypto/rand" + "encoding/hex" + + "github.com/smartcontractkit/smdkg/dkgocr/dkgocrtypes" + "github.com/smartcontractkit/smdkg/p256keyring" + + "github.com/smartcontractkit/chainlink-common/keystore/internal" +) + +var _ internal.Key = &Key{} +var _ dkgocrtypes.P256Keyring = &Key{} + +type Key struct { + raw internal.Raw + keyRing dkgocrtypes.P256Keyring +} + +func New() (Key, error) { + keyRing, err := p256keyring.New(cryptorand.Reader) + if err != nil { + return Key{}, err + } + rawBytes, err := keyRing.MarshalBinary() + if err != nil { + return Key{}, err + } + + return Key{raw: internal.NewRaw(rawBytes), keyRing: keyRing}, nil +} + +func (k Key) PublicKey() dkgocrtypes.P256ParticipantPublicKey { + return k.keyRing.PublicKey() +} + +func (k Key) PublicKeyString() string { + return hex.EncodeToString(k.keyRing.PublicKey()[:]) +} + +func (k Key) ID() string { + return k.PublicKeyString() +} + +func (k Key) ECDH(publicKey dkgocrtypes.P256ParticipantPublicKey) (dkgocrtypes.P256ECDHSharedSecret, error) { + return k.keyRing.ECDH(publicKey) +} + +func KeyFor(raw internal.Raw) Key { + keyRing := &p256keyring.P256Keyring{} + err := keyRing.UnmarshalBinary(internal.Bytes(raw)) + if err != nil { + panic(err) + } + return Key{raw: raw, keyRing: keyRing} +} + +func (k Key) Raw() internal.Raw { + return k.raw +} diff --git a/keystore/corekeys/dkgrecipientkey/key_test.go b/keystore/corekeys/dkgrecipientkey/key_test.go new file mode 100644 index 0000000000..c80f4c5f08 --- /dev/null +++ b/keystore/corekeys/dkgrecipientkey/key_test.go @@ -0,0 +1,87 @@ +package dkgrecipientkey + +import ( + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + "github.com/smartcontractkit/chainlink-common/keystore/internal" +) + +func TestNew(t *testing.T) { + key, err := New() + require.NoError(t, err) + + assert.NotNil(t, key.PublicKey()) + assert.NotNil(t, key.Raw()) + assert.Equal(t, key.ID(), key.PublicKeyString()) +} + +func TestPublicKey(t *testing.T) { + key, err := New() + require.NoError(t, err) + + pubKey := key.PublicKey() + assert.NotNil(t, pubKey) + assert.Len(t, pubKey, 33) +} + +func TestPublicKeyString(t *testing.T) { + key, err := New() + require.NoError(t, err) + + pubKeyStr := key.PublicKeyString() + assert.NotEmpty(t, pubKeyStr) + assert.Len(t, pubKeyStr, 66) +} + +func TestECDH(t *testing.T) { + key1, err := New() + require.NoError(t, err) + + key2, err := New() + require.NoError(t, err) + + secret1, err := key1.ECDH(key2.PublicKey()) + require.NoError(t, err) + + secret2, err := key2.ECDH(key1.PublicKey()) + require.NoError(t, err) + + assert.Equal(t, secret1, secret2) + assert.NotEmpty(t, secret1) +} + +func TestRaw(t *testing.T) { + key, err := New() + require.NoError(t, err) + + raw := key.Raw() + assert.NotNil(t, raw) + + rawBytes := internal.Bytes(raw) + assert.NotEmpty(t, rawBytes) + + key2 := KeyFor(raw) + assert.Equal(t, key.PublicKeyString(), key2.PublicKeyString()) +} + +func TestKeyUniqueness(t *testing.T) { + key1, err := New() + require.NoError(t, err) + + key2, err := New() + require.NoError(t, err) + + key3, err := New() + require.NoError(t, err) + + assert.NotEqual(t, key1.PublicKey(), key2.PublicKey()) + assert.NotEqual(t, key1.PublicKey(), key3.PublicKey()) + assert.NotEqual(t, key2.PublicKey(), key3.PublicKey()) + + assert.NotEqual(t, key1.PublicKeyString(), key2.PublicKeyString()) + assert.NotEqual(t, key1.PublicKeyString(), key3.PublicKeyString()) + assert.NotEqual(t, key2.PublicKeyString(), key3.PublicKeyString()) +} diff --git a/keystore/corekeys/ethkey/export.go b/keystore/corekeys/ethkey/export.go new file mode 100644 index 0000000000..37bf0f8b8f --- /dev/null +++ b/keystore/corekeys/ethkey/export.go @@ -0,0 +1,23 @@ +package ethkey + +import ( + "github.com/ethereum/go-ethereum/accounts/keystore" + "github.com/google/uuid" + "github.com/pkg/errors" + + "github.com/smartcontractkit/chainlink-common/keystore/scrypt" +) + +func (key KeyV2) ToEncryptedJSON(password string, scryptParams scrypt.ScryptParams) (export []byte, err error) { + // DEV: uuid is derived directly from the address, since it is not stored internally + id, err := uuid.FromBytes(key.Address.Bytes()[:16]) + if err != nil { + return nil, errors.Wrapf(err, "could not generate ethkey UUID") + } + dKey := &keystore.Key{ + Id: id, + Address: key.Address, + PrivateKey: key.getPK(), + } + return keystore.EncryptKey(dKey, password, scryptParams.N, scryptParams.P) +} diff --git a/keystore/corekeys/ethkey/export_test.go b/keystore/corekeys/ethkey/export_test.go new file mode 100644 index 0000000000..96f444f856 --- /dev/null +++ b/keystore/corekeys/ethkey/export_test.go @@ -0,0 +1,16 @@ +package ethkey + +import ( + "testing" +) + +func TestEthKeys_ExportImport(t *testing.T) { + corekeys2.RunKeyExportImportTestcase(t, createKey, func(keyJSON []byte, password string) (kt corekeys2.KeyType, err error) { + t.SkipNow() + return kt, err + }) +} + +func createKey() (corekeys2.KeyType, error) { + return NewV2() +} diff --git a/keystore/corekeys/ethkey/key_v2.go b/keystore/corekeys/ethkey/key_v2.go new file mode 100644 index 0000000000..545827a080 --- /dev/null +++ b/keystore/corekeys/ethkey/key_v2.go @@ -0,0 +1,87 @@ +package ethkey + +import ( + "bytes" + "crypto/ecdsa" + "crypto/rand" + "fmt" + "math/big" + + "github.com/ethereum/go-ethereum/accounts/abi/bind" + "github.com/ethereum/go-ethereum/common" + gethtypes "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/crypto" + + "github.com/smartcontractkit/chainlink-evm/pkg/types" + + "github.com/smartcontractkit/chainlink-common/keystore/internal" +) + +var curve = crypto.S256() + +func KeyFor(raw internal.Raw) KeyV2 { + var privateKey ecdsa.PrivateKey + d := big.NewInt(0).SetBytes(internal.Bytes(raw)) + privateKey.Curve = curve + privateKey.D = d + privateKey.X, privateKey.Y = curve.ScalarBaseMult(d.Bytes()) + k := newKeyV2(&privateKey) + k.raw = raw + return k +} + +type KeyV2 struct { + raw internal.Raw + getPK func() *ecdsa.PrivateKey + Address common.Address + EIP55Address types.EIP55Address +} + +func newKeyV2(privKey *ecdsa.PrivateKey) KeyV2 { + address := crypto.PubkeyToAddress(privKey.PublicKey) + eip55 := types.EIP55AddressFromAddress(address) + return KeyV2{ + getPK: func() *ecdsa.PrivateKey { return privKey }, + Address: address, + EIP55Address: eip55, + } +} + +func NewV2() (KeyV2, error) { + privateKeyECDSA, err := ecdsa.GenerateKey(crypto.S256(), rand.Reader) + if err != nil { + return KeyV2{}, err + } + return FromPrivateKey(privateKeyECDSA), nil +} + +func FromPrivateKey(privKey *ecdsa.PrivateKey) (key KeyV2) { + key = newKeyV2(privKey) + key.raw = internal.NewRaw(privKey.D.Bytes()) + return +} + +func (key KeyV2) ID() string { + return key.Address.Hex() +} + +func (key KeyV2) Raw() internal.Raw { return key.raw } + +func (key KeyV2) Sign(data []byte) ([]byte, error) { return crypto.Sign(data, key.getPK()) } + +// Cmp uses byte-order address comparison to give a stable comparison between two keys +func (key KeyV2) Cmp(key2 KeyV2) int { + return bytes.Compare(key.Address.Bytes(), key2.Address.Bytes()) +} + +func (key KeyV2) SignerFn(chainID *big.Int) bind.SignerFn { + return func(from common.Address, tx *gethtypes.Transaction) (*gethtypes.Transaction, error) { + signer := gethtypes.LatestSignerForChainID(chainID) + h := signer.Hash(tx) + sig, err := key.Sign(h[:]) + if err != nil { + return nil, fmt.Errorf("failed to sign transaction: %w", err) + } + return tx.WithSignature(signer, sig) + } +} diff --git a/keystore/corekeys/ethkey/key_v2_test.go b/keystore/corekeys/ethkey/key_v2_test.go new file mode 100644 index 0000000000..46a4ed47a0 --- /dev/null +++ b/keystore/corekeys/ethkey/key_v2_test.go @@ -0,0 +1,36 @@ +package ethkey + +import ( + "crypto/ecdsa" + "crypto/rand" + "testing" + + "github.com/ethereum/go-ethereum/crypto" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + "github.com/smartcontractkit/chainlink-evm/pkg/types" + + "github.com/smartcontractkit/chainlink-common/keystore/internal" +) + +func TestEthKeyV2_ToKey(t *testing.T) { + privateKeyECDSA, err := ecdsa.GenerateKey(crypto.S256(), rand.Reader) + require.NoError(t, err) + + k := KeyFor(internal.NewRaw(privateKeyECDSA.D.Bytes())) + + assert.Equal(t, k.getPK(), privateKeyECDSA) + assert.Equal(t, k.getPK().X, privateKeyECDSA.X) + assert.Equal(t, k.getPK().Y, privateKeyECDSA.Y) + assert.Equal(t, types.EIP55AddressFromAddress(crypto.PubkeyToAddress(privateKeyECDSA.PublicKey)).Hex(), k.ID()) +} + +func TestEthKeyV2_NewV2(t *testing.T) { + keyV2, err := NewV2() + require.NoError(t, err) + + assert.NotZero(t, keyV2.Address) + assert.NotNil(t, keyV2.getPK()) + assert.Equal(t, keyV2.Address.Hex(), keyV2.ID()) +} diff --git a/keystore/corekeys/ethkey/models.go b/keystore/corekeys/ethkey/models.go new file mode 100644 index 0000000000..2248b963a4 --- /dev/null +++ b/keystore/corekeys/ethkey/models.go @@ -0,0 +1,32 @@ +package ethkey + +import ( + "time" + + "github.com/smartcontractkit/chainlink-evm/pkg/types" + "github.com/smartcontractkit/chainlink-evm/pkg/utils/big" +) + +type State struct { + ID int32 + Address types.EIP55Address + EVMChainID big.Big + Disabled bool + CreatedAt time.Time + UpdatedAt time.Time + lastUsed time.Time +} + +func (s State) KeyID() string { + return s.Address.Hex() +} + +// lastUsed is an internal field and ought not be persisted to the database or +// exposed outside of the application +func (s State) LastUsed() time.Time { + return s.lastUsed +} + +func (s *State) WasUsed() { + s.lastUsed = time.Now() +} diff --git a/keystore/corekeys/exporttestutils.go b/keystore/corekeys/exporttestutils.go new file mode 100644 index 0000000000..efd17e35db --- /dev/null +++ b/keystore/corekeys/exporttestutils.go @@ -0,0 +1,41 @@ +package corekeys + +import ( + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + "github.com/smartcontractkit/chainlink-common/keystore/internal" + "github.com/smartcontractkit/chainlink-common/keystore/scrypt" +) + +// KeyType represents a key type for keys testing +type KeyType interface { + ToEncryptedJSON(password string, scryptParams scrypt.ScryptParams) (export []byte, err error) + Raw() internal.Raw + ID() string +} + +// CreateKeyFunc represents a function to create a key +type CreateKeyFunc func() (KeyType, error) + +// DecryptFunc represents a function to decrypt a key +type DecryptFunc func(keyJSON []byte, password string) (KeyType, error) + +// RunKeyExportImportTestcase executes a testcase to validate keys import/export functionality +func RunKeyExportImportTestcase(t *testing.T, createKey CreateKeyFunc, decrypt DecryptFunc) { + key, err := createKey() + require.NoError(t, err) + + json, err := key.ToEncryptedJSON("password", scrypt.FastScryptParams) + require.NoError(t, err) + + assert.NotEmpty(t, json) + + imported, err := decrypt(json, "password") + require.NoError(t, err) + + require.Equal(t, key.ID(), imported.ID()) + require.Equal(t, internal.RawBytes(key), internal.RawBytes(imported)) +} diff --git a/keystore/corekeys/models/legacy_key.go b/keystore/corekeys/models/legacy_key.go new file mode 100644 index 0000000000..bc9aeab104 --- /dev/null +++ b/keystore/corekeys/models/legacy_key.go @@ -0,0 +1,104 @@ +package models + +import ( + "encoding/json" + "slices" + + "github.com/pkg/errors" +) + +type rawLegacyKey []string +type rawLegacyKeys map[string]rawLegacyKey + +type LegacyKeyStorage struct { + legacyRawKeys rawLegacyKeys +} + +func (rlk *rawLegacyKeys) len() (n int) { + for _, v := range *rlk { + n += len(v) + } + return n +} + +func (rlk *rawLegacyKeys) has(name string) bool { + for n := range *rlk { + if n == name { + return true + } + } + return false +} + +func (rlk *rawLegacyKeys) hasValueInField(fieldName, value string) bool { + return slices.Contains((*rlk)[fieldName], value) +} + +// StoreUnsupported will store the raw keys that no longer have support in the node +// it will check if raw json contains keys that have not been added to the key ring +// and stores them internally +func (k *LegacyKeyStorage) StoreUnsupported(allRawKeysJson []byte, keyRing *keyRing) error { + if keyRing == nil { + return errors.New("keyring is nil") + } + supportedKeyRingJson, err := json.Marshal(keyRing.raw()) + if err != nil { + return err + } + + var ( + allKeys = rawLegacyKeys{} + supportedKeys = rawLegacyKeys{} + ) + + err = json.Unmarshal(allRawKeysJson, &allKeys) + if err != nil { + return err + } + err = json.Unmarshal(supportedKeyRingJson, &supportedKeys) + if err != nil { + return err + } + + k.legacyRawKeys = rawLegacyKeys{} + for fName, fValue := range allKeys { + if !supportedKeys.has(fName) { + k.legacyRawKeys[fName] = fValue + continue + } + for _, v := range allKeys[fName] { + if !supportedKeys.hasValueInField(fName, v) { + k.legacyRawKeys[fName] = append(k.legacyRawKeys[fName], v) + } + } + } + + return nil +} + +// UnloadUnsupported will inject the unsupported keys into the raw key ring json +func (k *LegacyKeyStorage) UnloadUnsupported(supportedRawKeyRingJson []byte) ([]byte, error) { + supportedKeys := rawLegacyKeys{} + err := json.Unmarshal(supportedRawKeyRingJson, &supportedKeys) + if err != nil { + return nil, err + } + + for fName, vals := range k.legacyRawKeys { + if !supportedKeys.has(fName) { + supportedKeys[fName] = vals + continue + } + for _, v := range vals { + if !supportedKeys.hasValueInField(fName, v) { + supportedKeys[fName] = append(supportedKeys[fName], v) + } + } + } + + allKeysJson, err := json.Marshal(supportedKeys) + if err != nil { + return nil, err + } + return allKeysJson, nil +} diff --git a/keystore/corekeys/models/models.go b/keystore/corekeys/models/models.go new file mode 100644 index 0000000000..59a668b87a --- /dev/null +++ b/keystore/corekeys/models/models.go @@ -0,0 +1,481 @@ +package models + +import ( + "encoding/json" + "fmt" + "math/big" + "time" + + gethkeystore "github.com/ethereum/go-ethereum/accounts/keystore" + "github.com/ethereum/go-ethereum/common" + "github.com/pkg/errors" + + "github.com/smartcontractkit/chainlink-common/pkg/logger" + + "github.com/smartcontractkit/chainlink-common/keystore/corekeys/aptoskey" + "github.com/smartcontractkit/chainlink-common/keystore/corekeys/cosmoskey" + "github.com/smartcontractkit/chainlink-common/keystore/corekeys/csakey" + "github.com/smartcontractkit/chainlink-common/keystore/corekeys/dkgrecipientkey" + "github.com/smartcontractkit/chainlink-common/keystore/corekeys/ethkey" + "github.com/smartcontractkit/chainlink-common/keystore/corekeys/ocr2key" + "github.com/smartcontractkit/chainlink-common/keystore/corekeys/ocrkey" + "github.com/smartcontractkit/chainlink-common/keystore/corekeys/p2pkey" + "github.com/smartcontractkit/chainlink-common/keystore/corekeys/solkey" + "github.com/smartcontractkit/chainlink-common/keystore/corekeys/starkkey" + "github.com/smartcontractkit/chainlink-common/keystore/corekeys/suikey" + "github.com/smartcontractkit/chainlink-common/keystore/corekeys/tonkey" + "github.com/smartcontractkit/chainlink-common/keystore/corekeys/tronkey" + "github.com/smartcontractkit/chainlink-common/keystore/corekeys/vrfkey" + "github.com/smartcontractkit/chainlink-common/keystore/corekeys/workflowkey" + "github.com/smartcontractkit/chainlink-common/keystore/internal" + "github.com/smartcontractkit/chainlink-common/keystore/scrypt" +) + +type encryptedKeyRing struct { + UpdatedAt time.Time + EncryptedKeys []byte +} + +func (ekr encryptedKeyRing) Decrypt(password string) (*keyRing, error) { + if len(ekr.EncryptedKeys) == 0 { + return NewKeyRing(), nil + } + var cryptoJSON gethkeystore.CryptoJSON + err := json.Unmarshal(ekr.EncryptedKeys, &cryptoJSON) + if err != nil { + return nil, err + } + marshalledRawKeyRingJson, err := gethkeystore.DecryptDataV3(cryptoJSON, adulteratedPassword(password)) + if err != nil { + return nil, err + } + var rawKeys rawKeyRing + err = json.Unmarshal(marshalledRawKeyRingJson, &rawKeys) + if err != nil { + return nil, err + } + ring, err := rawKeys.keys() + if err != nil { + return nil, err + } + + err = rawKeys.LegacyKeys.StoreUnsupported(marshalledRawKeyRingJson, ring) + if err != nil { + return nil, err + } + ring.LegacyKeys = rawKeys.LegacyKeys + + return ring, nil +} + +type keyStates struct { + // Key ID => chain ID => state + KeyIDChainID map[string]map[string]*ethkey.State + // Chain ID => Key ID => state + ChainIDKeyID map[string]map[string]*ethkey.State + All []*ethkey.State +} + +func NewKeyStates() *keyStates { + return &keyStates{ + KeyIDChainID: make(map[string]map[string]*ethkey.State), + ChainIDKeyID: make(map[string]map[string]*ethkey.State), + } +} + +// warning: not thread-safe! caller must sync +// adds or replaces a state +func (ks *keyStates) add(state *ethkey.State) { + cid := state.EVMChainID.String() + kid := state.KeyID() + + keyStates, exists := ks.KeyIDChainID[kid] + if !exists { + keyStates = make(map[string]*ethkey.State) + ks.KeyIDChainID[kid] = keyStates + } + keyStates[cid] = state + + chainStates, exists := ks.ChainIDKeyID[cid] + if !exists { + chainStates = make(map[string]*ethkey.State) + ks.ChainIDKeyID[cid] = chainStates + } + chainStates[kid] = state + + exists = false + for i, existingState := range ks.All { + if existingState.ID == state.ID { + ks.All[i] = state + exists = true + break + } + } + if !exists { + ks.All = append(ks.All, state) + } +} + +// warning: not thread-safe! caller must sync +func (ks *keyStates) get(addr common.Address, chainID *big.Int) *ethkey.State { + chainStates, exists := ks.KeyIDChainID[addr.Hex()] + if !exists { + return nil + } + return chainStates[chainID.String()] +} + +// warning: not thread-safe! caller must sync +func (ks *keyStates) disable(addr common.Address, chainID *big.Int, updatedAt time.Time) { + state := ks.get(addr, chainID) + state.Disabled = true + state.UpdatedAt = updatedAt +} + +// warning: not thread-safe! caller must sync +func (ks *keyStates) enable(addr common.Address, chainID *big.Int, updatedAt time.Time) { + state := ks.get(addr, chainID) + state.Disabled = false + state.UpdatedAt = updatedAt +} + +// warning: not thread-safe! caller must sync +func (ks *keyStates) delete(addr common.Address) { + var chainIDs []*big.Int + for i := len(ks.All) - 1; i >= 0; i-- { + if ks.All[i].Address.Address() == addr { + chainIDs = append(chainIDs, ks.All[i].EVMChainID.ToInt()) + ks.All = append(ks.All[:i], ks.All[i+1:]...) + } + } + for _, cid := range chainIDs { + delete(ks.KeyIDChainID[addr.Hex()], cid.String()) + delete(ks.ChainIDKeyID[cid.String()], addr.Hex()) + } +} + +type keyRing struct { + CSA map[string]csakey.KeyV2 + Eth map[string]ethkey.KeyV2 + OCR map[string]ocrkey.KeyV2 + OCR2 map[string]ocr2key.KeyBundle + P2P map[string]p2pkey.KeyV2 + Cosmos map[string]cosmoskey.Key + Solana map[string]solkey.Key + StarkNet map[string]starkkey.Key + Sui map[string]suikey.Key + Aptos map[string]aptoskey.Key + Tron map[string]tronkey.Key + TON map[string]tonkey.Key + VRF map[string]vrfkey.KeyV2 + Workflow map[string]workflowkey.Key + DKGRecipient map[string]dkgrecipientkey.Key + LegacyKeys LegacyKeyStorage +} + +func NewKeyRing() *keyRing { + return &keyRing{ + CSA: make(map[string]csakey.KeyV2), + Eth: make(map[string]ethkey.KeyV2), + OCR: make(map[string]ocrkey.KeyV2), + OCR2: make(map[string]ocr2key.KeyBundle), + P2P: make(map[string]p2pkey.KeyV2), + Cosmos: make(map[string]cosmoskey.Key), + Solana: make(map[string]solkey.Key), + StarkNet: make(map[string]starkkey.Key), + Sui: make(map[string]suikey.Key), + Aptos: make(map[string]aptoskey.Key), + Tron: make(map[string]tronkey.Key), + TON: make(map[string]tonkey.Key), + VRF: make(map[string]vrfkey.KeyV2), + Workflow: make(map[string]workflowkey.Key), + DKGRecipient: make(map[string]dkgrecipientkey.Key), + } +} + +func (kr *keyRing) Encrypt(password string, scryptParams scrypt.ScryptParams) (ekr encryptedKeyRing, err error) { + marshalledRawKeyRingJson, err := json.Marshal(kr.raw()) + if err != nil { + return ekr, err + } + + marshalledRawKeyRingJson, err = kr.LegacyKeys.UnloadUnsupported(marshalledRawKeyRingJson) + if err != nil { + return encryptedKeyRing{}, err + } + + cryptoJSON, err := gethkeystore.EncryptDataV3( + marshalledRawKeyRingJson, + []byte(adulteratedPassword(password)), + scryptParams.N, + scryptParams.P, + ) + if err != nil { + return ekr, errors.Wrapf(err, "could not encrypt key ring") + } + encryptedKeys, err := json.Marshal(&cryptoJSON) + if err != nil { + return ekr, errors.Wrapf(err, "could not encode cryptoJSON") + } + return encryptedKeyRing{ + EncryptedKeys: encryptedKeys, + }, nil +} + +func (kr *keyRing) raw() (rawKeys rawKeyRing) { + for _, csaKey := range kr.CSA { + rawKeys.CSA = append(rawKeys.CSA, internal.RawBytes(csaKey)) + } + for _, ethKey := range kr.Eth { + rawKeys.Eth = append(rawKeys.Eth, internal.RawBytes(ethKey)) + } + for _, ocrKey := range kr.OCR { + rawKeys.OCR = append(rawKeys.OCR, internal.RawBytes(ocrKey)) + } + for _, ocr2key := range kr.OCR2 { + rawKeys.OCR2 = append(rawKeys.OCR2, internal.RawBytes(ocr2key)) + } + for _, p2pKey := range kr.P2P { + rawKeys.P2P = append(rawKeys.P2P, internal.RawBytes(p2pKey)) + } + for _, cosmoskey := range kr.Cosmos { + rawKeys.Cosmos = append(rawKeys.Cosmos, internal.RawBytes(cosmoskey)) + } + for _, solkey := range kr.Solana { + rawKeys.Solana = append(rawKeys.Solana, internal.RawBytes(solkey)) + } + for _, starkkey := range kr.StarkNet { + rawKeys.StarkNet = append(rawKeys.StarkNet, internal.RawBytes(starkkey)) + } + for _, aptoskey := range kr.Aptos { + rawKeys.Aptos = append(rawKeys.Aptos, internal.RawBytes(aptoskey)) + } + for _, tronkey := range kr.Tron { + rawKeys.Tron = append(rawKeys.Tron, internal.RawBytes(tronkey)) + } + for _, tonkey := range kr.TON { + rawKeys.TON = append(rawKeys.TON, internal.RawBytes(tonkey)) + } + for _, suikey := range kr.Sui { + rawKeys.Sui = append(rawKeys.Sui, internal.RawBytes(suikey)) + } + for _, vrfKey := range kr.VRF { + rawKeys.VRF = append(rawKeys.VRF, internal.RawBytes(vrfKey)) + } + for _, workflowKey := range kr.Workflow { + rawKeys.Workflow = append(rawKeys.Workflow, internal.RawBytes(workflowKey)) + } + for _, dkgRecipientKey := range kr.DKGRecipient { + rawKeys.DKGRecipient = append(rawKeys.DKGRecipient, internal.RawBytes(dkgRecipientKey)) + } + return rawKeys +} + +func (kr *keyRing) logPubKeys(lggr logger.Logger) { + lggr = logger.Named(lggr, "KeyRing") + var csaIDs []string + for _, CSAKey := range kr.CSA { + csaIDs = append(csaIDs, CSAKey.ID()) + } + var ethIDs []string + for _, ETHKey := range kr.Eth { + ethIDs = append(ethIDs, ETHKey.ID()) + } + var ocrIDs []string + for _, OCRKey := range kr.OCR { + ocrIDs = append(ocrIDs, OCRKey.ID()) + } + var ocr2IDs []string + for _, OCR2Key := range kr.OCR2 { + ocr2IDs = append(ocr2IDs, OCR2Key.ID()) + } + var p2pIDs []string + for _, P2PKey := range kr.P2P { + p2pIDs = append(p2pIDs, P2PKey.ID()) + } + var cosmosIDs []string + for _, cosmosKey := range kr.Cosmos { + cosmosIDs = append(cosmosIDs, cosmosKey.ID()) + } + var solanaIDs []string + for _, solanaKey := range kr.Solana { + solanaIDs = append(solanaIDs, solanaKey.ID()) + } + var starknetIDs []string + for _, starkkey := range kr.StarkNet { + starknetIDs = append(starknetIDs, starkkey.ID()) + } + var aptosIDs []string + for _, aptosKey := range kr.Aptos { + aptosIDs = append(aptosIDs, aptosKey.ID()) + } + tronIDs := []string{} + for _, tronKey := range kr.Tron { + tronIDs = append(tronIDs, tronKey.ID()) + } + tonIDs := []string{} + for _, tonKey := range kr.TON { + tonIDs = append(tonIDs, tonKey.ID()) + } + suiIDs := []string{} + for _, suiKey := range kr.Sui { + suiIDs = append(suiIDs, suiKey.ID()) + } + var vrfIDs []string + for _, VRFKey := range kr.VRF { + vrfIDs = append(vrfIDs, VRFKey.ID()) + } + dkgRecipientIDs := []string{} + for _, dkgRecipientKey := range kr.DKGRecipient { + dkgRecipientIDs = append(dkgRecipientIDs, dkgRecipientKey.ID()) + } + workflowIDs := make([]string, len(kr.Workflow)) + i := 0 + for _, workflowKey := range kr.Workflow { + workflowIDs[i] = workflowKey.ID() + i++ + } + if len(csaIDs) > 0 { + lggr.Infow(fmt.Sprintf("Unlocked %d CSA keys", len(csaIDs)), "keys", csaIDs) + } + if len(ethIDs) > 0 { + lggr.Infow(fmt.Sprintf("Unlocked %d ETH keys", len(ethIDs)), "keys", ethIDs) + } + if len(ocrIDs) > 0 { + lggr.Infow(fmt.Sprintf("Unlocked %d OCR keys", len(ocrIDs)), "keys", ocrIDs) + } + if len(ocr2IDs) > 0 { + lggr.Infow(fmt.Sprintf("Unlocked %d OCR2 keys", len(ocr2IDs)), "keys", ocr2IDs) + } + if len(p2pIDs) > 0 { + lggr.Infow(fmt.Sprintf("Unlocked %d P2P keys", len(p2pIDs)), "keys", p2pIDs) + } + if len(cosmosIDs) > 0 { + lggr.Infow(fmt.Sprintf("Unlocked %d Cosmos keys", len(cosmosIDs)), "keys", cosmosIDs) + } + if len(solanaIDs) > 0 { + lggr.Infow(fmt.Sprintf("Unlocked %d Solana keys", len(solanaIDs)), "keys", solanaIDs) + } + if len(starknetIDs) > 0 { + lggr.Infow(fmt.Sprintf("Unlocked %d StarkNet keys", len(starknetIDs)), "keys", starknetIDs) + } + if len(aptosIDs) > 0 { + lggr.Infow(fmt.Sprintf("Unlocked %d Aptos keys", len(aptosIDs)), "keys", aptosIDs) + } + if len(tronIDs) > 0 { + lggr.Infow(fmt.Sprintf("Unlocked %d Tron keys", len(tronIDs)), "keys", tronIDs) + } + if len(tonIDs) > 0 { + lggr.Infow(fmt.Sprintf("Unlocked %d TON keys", len(tonIDs)), "keys", tonIDs) + } + if len(suiIDs) > 0 { + lggr.Infow(fmt.Sprintf("Unlocked %d Sui keys", len(suiIDs)), "keys", suiIDs) + } + if len(vrfIDs) > 0 { + lggr.Infow(fmt.Sprintf("Unlocked %d VRF keys", len(vrfIDs)), "keys", vrfIDs) + } + if len(dkgRecipientIDs) > 0 { + lggr.Infow(fmt.Sprintf("Unlocked %d DKGRecipient keys", len(dkgRecipientIDs)), "keys", dkgRecipientIDs) + } + if len(workflowIDs) > 0 { + lggr.Infow(fmt.Sprintf("Unlocked %d Workflow keys", len(workflowIDs)), "keys", workflowIDs) + } + if len(kr.LegacyKeys.legacyRawKeys) > 0 { + lggr.Infow(fmt.Sprintf("%d keys stored in legacy system", kr.LegacyKeys.legacyRawKeys.len())) + } +} + +// rawKeyRing is an intermediate struct for encrypting / decrypting keyRing +// it holds only the essential key information to avoid adding unnecessary data +// (like public keys) to the database +type rawKeyRing struct { + Eth [][]byte + CSA [][]byte + OCR [][]byte + OCR2 [][]byte + P2P [][]byte + Cosmos [][]byte + Solana [][]byte + StarkNet [][]byte + Sui [][]byte + Aptos [][]byte + Tron [][]byte + TON [][]byte + VRF [][]byte + Workflow [][]byte + DKGRecipient [][]byte + LegacyKeys LegacyKeyStorage `json:"-"` +} + +func (rawKeys rawKeyRing) keys() (*keyRing, error) { + keyRing := NewKeyRing() + for _, rawCSAKey := range rawKeys.CSA { + csaKey := csakey.KeyFor(internal.NewRaw(rawCSAKey)) + keyRing.CSA[csaKey.ID()] = csaKey + } + for _, rawETHKey := range rawKeys.Eth { + ethKey := ethkey.KeyFor(internal.NewRaw(rawETHKey)) + keyRing.Eth[ethKey.ID()] = ethKey + } + for _, rawOCRKey := range rawKeys.OCR { + ocrKey := ocrkey.KeyFor(internal.NewRaw(rawOCRKey)) + keyRing.OCR[ocrKey.ID()] = ocrKey + } + for _, rawOCR2Key := range rawKeys.OCR2 { + if ocr2Key := ocr2key.KeyFor(internal.NewRaw(rawOCR2Key)); ocr2Key != nil { + keyRing.OCR2[ocr2Key.ID()] = ocr2Key + } + } + for _, rawP2PKey := range rawKeys.P2P { + p2pKey := p2pkey.KeyFor(internal.NewRaw(rawP2PKey)) + keyRing.P2P[p2pKey.ID()] = p2pKey + } + for _, rawCosmosKey := range rawKeys.Cosmos { + cosmosKey := cosmoskey.KeyFor(internal.NewRaw(rawCosmosKey)) + keyRing.Cosmos[cosmosKey.ID()] = cosmosKey + } + for _, rawSolKey := range rawKeys.Solana { + solKey := solkey.KeyFor(internal.NewRaw(rawSolKey)) + keyRing.Solana[solKey.ID()] = solKey + } + for _, rawStarkNetKey := range rawKeys.StarkNet { + starkKey := starkkey.KeyFor(internal.NewRaw(rawStarkNetKey)) + keyRing.StarkNet[starkKey.ID()] = starkKey + } + for _, rawAptosKey := range rawKeys.Aptos { + aptosKey := aptoskey.KeyFor(internal.NewRaw(rawAptosKey)) + keyRing.Aptos[aptosKey.ID()] = aptosKey + } + for _, rawTronKey := range rawKeys.Tron { + tronKey := tronkey.KeyFor(internal.NewRaw(rawTronKey)) + keyRing.Tron[tronKey.ID()] = tronKey + } + for _, rawTONKey := range rawKeys.TON { + tonKey := tonkey.KeyFor(internal.NewRaw(rawTONKey)) + keyRing.TON[tonKey.ID()] = tonKey + } + for _, rawSuiKey := range rawKeys.Sui { + suiKey := suikey.KeyFor(internal.NewRaw(rawSuiKey)) + keyRing.Sui[suiKey.ID()] = suiKey + } + for _, rawVRFKey := range rawKeys.VRF { + vrfKey := vrfkey.KeyFor(internal.NewRaw(rawVRFKey)) + keyRing.VRF[vrfKey.ID()] = vrfKey + } + for _, rawWorkflowKey := range rawKeys.Workflow { + workflowKey := workflowkey.KeyFor(internal.NewRaw(rawWorkflowKey)) + keyRing.Workflow[workflowKey.ID()] = workflowKey + } + for _, rawDKGRecipientKey := range rawKeys.DKGRecipient { + dkgRecipientKey := dkgrecipientkey.KeyFor(internal.NewRaw(rawDKGRecipientKey)) + keyRing.DKGRecipient[dkgRecipientKey.ID()] = dkgRecipientKey + } + + keyRing.LegacyKeys = rawKeys.LegacyKeys + return keyRing, nil +} + +// adulteration prevents the password from getting used in the wrong place +func adulteratedPassword(password string) string { + return "master-password-" + password +} diff --git a/keystore/corekeys/models/models_test.go b/keystore/corekeys/models/models_test.go new file mode 100644 index 0000000000..4c257f4b60 --- /dev/null +++ b/keystore/corekeys/models/models_test.go @@ -0,0 +1,171 @@ +package models + +import ( + "crypto/rand" + "encoding/json" + "math/big" + "testing" + + "github.com/stretchr/testify/require" + + "github.com/smartcontractkit/chainlink-common/keystore/corekeys/cosmoskey" + "github.com/smartcontractkit/chainlink-common/keystore/corekeys/csakey" + "github.com/smartcontractkit/chainlink-common/keystore/corekeys/ethkey" + "github.com/smartcontractkit/chainlink-common/keystore/corekeys/ocr2key" + "github.com/smartcontractkit/chainlink-common/keystore/corekeys/ocrkey" + "github.com/smartcontractkit/chainlink-common/keystore/corekeys/p2pkey" + "github.com/smartcontractkit/chainlink-common/keystore/corekeys/solkey" + "github.com/smartcontractkit/chainlink-common/keystore/corekeys/tonkey" + "github.com/smartcontractkit/chainlink-common/keystore/corekeys/tronkey" + "github.com/smartcontractkit/chainlink-common/keystore/corekeys/vrfkey" + "github.com/smartcontractkit/chainlink-common/keystore/internal" + "github.com/smartcontractkit/chainlink-common/keystore/scrypt" + "github.com/smartcontractkit/chainlink-common/pkg/chains/types" +) + +const password = "password" + +func TestKeyRing_Encrypt_Decrypt(t *testing.T) { + csa1, csa2 := csakey.MustNewV2XXXTestingOnly(big.NewInt(1)), csakey.MustNewV2XXXTestingOnly(big.NewInt(2)) + eth1, eth2 := mustNewEthKey(t), mustNewEthKey(t) + ocr := []ocrkey.KeyV2{ + ocrkey.MustNewV2XXXTestingOnly(big.NewInt(1)), + ocrkey.MustNewV2XXXTestingOnly(big.NewInt(2)), + } + var ocr2 []ocr2key.KeyBundle + ocr2Raw := make([][]byte, 0, len(types.SupportedChainTypes)) + for _, chain := range types.SupportedChainTypes { + key := ocr2key.MustNewInsecure(rand.Reader, chain) + ocr2 = append(ocr2, key) + ocr2Raw = append(ocr2Raw, internal.RawBytes(key)) + } + p2p1, p2p2 := p2pkey.MustNewV2XXXTestingOnly(big.NewInt(1)), p2pkey.MustNewV2XXXTestingOnly(big.NewInt(2)) + sol1, sol2 := solkey.MustNewInsecure(rand.Reader), solkey.MustNewInsecure(rand.Reader) + vrf1, vrf2 := vrfkey.MustNewV2XXXTestingOnly(big.NewInt(1)), vrfkey.MustNewV2XXXTestingOnly(big.NewInt(2)) + tk1, tk2 := cosmoskey.MustNewInsecure(rand.Reader), cosmoskey.MustNewInsecure(rand.Reader) + uk1, uk2 := tronkey.MustNewInsecure(rand.Reader), tronkey.MustNewInsecure(rand.Reader) + ton1, ton2 := tonkey.MustNewInsecure(rand.Reader), tonkey.MustNewInsecure(rand.Reader) + originalKeyRingRaw := rawKeyRing{ + CSA: [][]byte{internal.RawBytes(csa1), internal.RawBytes(csa2)}, + Eth: [][]byte{internal.RawBytes(eth1), internal.RawBytes(eth2)}, + OCR: [][]byte{internal.RawBytes(ocr[0]), internal.RawBytes(ocr[1])}, + OCR2: ocr2Raw, + P2P: [][]byte{internal.RawBytes(p2p1), internal.RawBytes(p2p2)}, + Solana: [][]byte{internal.RawBytes(sol1), internal.RawBytes(sol2)}, + VRF: [][]byte{internal.RawBytes(vrf1), internal.RawBytes(vrf2)}, + Cosmos: [][]byte{internal.RawBytes(tk1), internal.RawBytes(tk2)}, + Tron: [][]byte{internal.RawBytes(uk1), internal.RawBytes(uk2)}, + TON: [][]byte{internal.RawBytes(ton1), internal.RawBytes(ton2)}, + } + originalKeyRing, kerr := originalKeyRingRaw.keys() + require.NoError(t, kerr) + + t.Run("test encrypt/decrypt", func(t *testing.T) { + encryptedKr, err := originalKeyRing.Encrypt(password, scrypt.FastScryptParams) + require.NoError(t, err) + decryptedKeyRing, err := encryptedKr.Decrypt(password) + require.NoError(t, err) + // compare cosmos keys + require.Len(t, decryptedKeyRing.Cosmos, 2) + require.Equal(t, originalKeyRing.Cosmos[tk1.ID()].PublicKey(), decryptedKeyRing.Cosmos[tk1.ID()].PublicKey()) + require.Equal(t, originalKeyRing.Cosmos[tk2.ID()].PublicKey(), decryptedKeyRing.Cosmos[tk2.ID()].PublicKey()) + // compare tron keys + require.Len(t, decryptedKeyRing.Tron, 2) + require.Equal(t, originalKeyRing.Tron[uk1.ID()].Base58Address(), decryptedKeyRing.Tron[uk1.ID()].Base58Address()) + require.Equal(t, originalKeyRing.Tron[uk2.ID()].Base58Address(), decryptedKeyRing.Tron[uk2.ID()].Base58Address()) + // compare ton keys + require.Len(t, decryptedKeyRing.TON, 2) + require.Equal(t, originalKeyRing.TON[ton1.ID()].AddressBase64(), decryptedKeyRing.TON[ton1.ID()].AddressBase64()) + require.Equal(t, originalKeyRing.TON[ton2.ID()].AddressBase64(), decryptedKeyRing.TON[ton2.ID()].AddressBase64()) + // compare csa keys + require.Len(t, decryptedKeyRing.CSA, 2) + require.Equal(t, originalKeyRing.CSA[csa1.ID()].PublicKey, decryptedKeyRing.CSA[csa1.ID()].PublicKey) + require.Equal(t, originalKeyRing.CSA[csa2.ID()].PublicKey, decryptedKeyRing.CSA[csa2.ID()].PublicKey) + // compare eth keys + require.Len(t, decryptedKeyRing.Eth, 2) + require.Equal(t, originalKeyRing.Eth[eth1.ID()].Address, decryptedKeyRing.Eth[eth1.ID()].Address) + require.Equal(t, originalKeyRing.Eth[eth2.ID()].Address, decryptedKeyRing.Eth[eth2.ID()].Address) + // compare ocr keys + require.Len(t, decryptedKeyRing.OCR, 2) + require.Equal(t, internal.RawBytes(originalKeyRing.OCR[ocr[0].ID()]), internal.RawBytes(decryptedKeyRing.OCR[ocr[0].ID()])) + require.Equal(t, originalKeyRing.OCR[ocr[0].ID()].OffChainEncryption, decryptedKeyRing.OCR[ocr[0].ID()].OffChainEncryption) + require.Equal(t, internal.RawBytes(originalKeyRing.OCR[ocr[1].ID()]), internal.RawBytes(decryptedKeyRing.OCR[ocr[1].ID()])) + require.Equal(t, originalKeyRing.OCR[ocr[1].ID()].OffChainEncryption, decryptedKeyRing.OCR[ocr[1].ID()].OffChainEncryption) + // compare ocr2 keys + require.Len(t, decryptedKeyRing.OCR2, len(types.SupportedChainTypes)) + for i := range ocr2 { + id := ocr2[i].ID() + require.Equal(t, originalKeyRing.OCR2[id].ID(), decryptedKeyRing.OCR2[id].ID()) + require.Equal(t, ocr2[i].OnChainPublicKey(), decryptedKeyRing.OCR2[id].OnChainPublicKey()) + require.Equal(t, originalKeyRing.OCR2[id].ChainType(), decryptedKeyRing.OCR2[id].ChainType()) + } + // compare p2p keys + require.Len(t, decryptedKeyRing.P2P, 2) + require.Equal(t, originalKeyRing.P2P[p2p1.ID()].PublicKeyHex(), decryptedKeyRing.P2P[p2p1.ID()].PublicKeyHex()) + require.Equal(t, originalKeyRing.P2P[p2p1.ID()].PeerID(), decryptedKeyRing.P2P[p2p1.ID()].PeerID()) + require.Equal(t, originalKeyRing.P2P[p2p2.ID()].PublicKeyHex(), decryptedKeyRing.P2P[p2p2.ID()].PublicKeyHex()) + require.Equal(t, originalKeyRing.P2P[p2p2.ID()].PeerID(), decryptedKeyRing.P2P[p2p2.ID()].PeerID()) + // compare solana keys + require.Len(t, decryptedKeyRing.Solana, 2) + require.Equal(t, originalKeyRing.Solana[sol1.ID()].GetPublic(), decryptedKeyRing.Solana[sol1.ID()].GetPublic()) + // compare vrf keys + require.Len(t, decryptedKeyRing.VRF, 2) + require.Equal(t, originalKeyRing.VRF[vrf1.ID()].PublicKey, decryptedKeyRing.VRF[vrf1.ID()].PublicKey) + require.Equal(t, originalKeyRing.VRF[vrf2.ID()].PublicKey, decryptedKeyRing.VRF[vrf2.ID()].PublicKey) + }) + + t.Run("test legacy system", func(t *testing.T) { + // Add unsupported keys to raw json + rawJson, _ := json.Marshal(originalKeyRing.raw()) + var allKeys = map[string][]string{ + "foo": { + "bar", "biz", + }, + } + err := json.Unmarshal(rawJson, &allKeys) + require.NoError(t, err) + // Add more ocr2 keys + newOCR2Key1 := ocrkey.MustNewV2XXXTestingOnly(big.NewInt(5)) + newOCR2Key2 := ocrkey.MustNewV2XXXTestingOnly(big.NewInt(6)) + allKeys["OCR2"] = append(allKeys["OCR2"], newOCR2Key1.Raw().String()) + allKeys["OCR2"] = append(allKeys["OCR2"], newOCR2Key2.Raw().String()) + + // Add more p2p keys + newP2PKey1 := p2pkey.MustNewV2XXXTestingOnly(big.NewInt(5)) + newP2PKey2 := p2pkey.MustNewV2XXXTestingOnly(big.NewInt(7)) + allKeys["P2P"] = append(allKeys["P2P"], newP2PKey1.Raw().String()) + allKeys["P2P"] = append(allKeys["P2P"], newP2PKey2.Raw().String()) + + // Run legacy system + newRawJson, _ := json.Marshal(allKeys) + err = originalKeyRing.LegacyKeys.StoreUnsupported(newRawJson, originalKeyRing) + require.NoError(t, err) + require.Equal(t, 6, originalKeyRing.LegacyKeys.legacyRawKeys.len()) + marshalledRawKeyRingJson, err := json.Marshal(originalKeyRing.raw()) + require.NoError(t, err) + unloadedKeysJson, err := originalKeyRing.LegacyKeys.UnloadUnsupported(marshalledRawKeyRingJson) + require.NoError(t, err) + var shouldHaveAllKeys = map[string][]string{} + err = json.Unmarshal(unloadedKeysJson, &shouldHaveAllKeys) + require.NoError(t, err) + + // Check if keys where added to the raw json + require.Equal(t, []string{"bar", "biz"}, shouldHaveAllKeys["foo"]) + require.Contains(t, shouldHaveAllKeys["OCR2"], newOCR2Key1.Raw().String()) + require.Contains(t, shouldHaveAllKeys["OCR2"], newOCR2Key2.Raw().String()) + require.Contains(t, shouldHaveAllKeys["P2P"], newP2PKey1.Raw().String()) + require.Contains(t, shouldHaveAllKeys["P2P"], newP2PKey2.Raw().String()) + + // Check error + err = originalKeyRing.LegacyKeys.StoreUnsupported(newRawJson, nil) + require.Error(t, err) + _, err = originalKeyRing.LegacyKeys.UnloadUnsupported(nil) + require.Error(t, err) + }) +} + +func mustNewEthKey(t *testing.T) *ethkey.KeyV2 { + key, err := ethkey.NewV2() + require.NoError(t, err) + return &key +} diff --git a/keystore/corekeys/ocr2key/cosmos_keyring.go b/keystore/corekeys/ocr2key/cosmos_keyring.go new file mode 100644 index 0000000000..d2c8d7ddef --- /dev/null +++ b/keystore/corekeys/ocr2key/cosmos_keyring.go @@ -0,0 +1,118 @@ +package ocr2key + +import ( + "crypto/ed25519" + "encoding/binary" + "io" + + "github.com/hdevalence/ed25519consensus" + "github.com/pkg/errors" + "golang.org/x/crypto/blake2s" + + "github.com/smartcontractkit/chainlink/v2/core/utils" + + "github.com/smartcontractkit/libocr/offchainreporting2/types" + "github.com/smartcontractkit/libocr/offchainreporting2plus/chains/evmutil" + ocrtypes "github.com/smartcontractkit/libocr/offchainreporting2plus/types" +) + +var _ ocrtypes.OnchainKeyring = &cosmosKeyring{} + +type cosmosKeyring struct { + privKey func() ed25519.PrivateKey + pubKey ed25519.PublicKey +} + +func newCosmosKeyring(material io.Reader) (*cosmosKeyring, error) { + pubKey, privKey, err := ed25519.GenerateKey(material) + if err != nil { + return nil, err + } + return &cosmosKeyring{pubKey: pubKey, privKey: func() ed25519.PrivateKey { return privKey }}, nil +} + +func (ckr *cosmosKeyring) PublicKey() ocrtypes.OnchainPublicKey { + return []byte(ckr.pubKey) +} + +func (ckr *cosmosKeyring) reportToSigData(reportCtx ocrtypes.ReportContext, report ocrtypes.Report) ([]byte, error) { + rawReportContext := evmutil.RawReportContext(reportCtx) + h, err := blake2s.New256(nil) + if err != nil { + return nil, err + } + reportLen := make([]byte, 4) + binary.BigEndian.PutUint32(reportLen[0:], uint32(len(report))) + h.Write(reportLen) + h.Write(report) + h.Write(rawReportContext[0][:]) + h.Write(rawReportContext[1][:]) + h.Write(rawReportContext[2][:]) + return h.Sum(nil), nil +} + +func (ckr *cosmosKeyring) Sign(reportCtx ocrtypes.ReportContext, report ocrtypes.Report) ([]byte, error) { + sigData, err := ckr.reportToSigData(reportCtx, report) + if err != nil { + return nil, err + } + return ckr.SignBlob(sigData) +} + +func (ckr *cosmosKeyring) Sign3(digest types.ConfigDigest, seqNr uint64, r ocrtypes.Report) (signature []byte, err error) { + return nil, errors.New("not implemented") +} + +func (ckr *cosmosKeyring) SignBlob(b []byte) ([]byte, error) { + signedMsg := ed25519.Sign(ckr.privKey(), b) + // match on-chain parsing (first 32 bytes are for pubkey, remaining are for signature) + return utils.ConcatBytes(ckr.PublicKey(), signedMsg), nil +} + +func (ckr *cosmosKeyring) Verify(publicKey ocrtypes.OnchainPublicKey, reportCtx ocrtypes.ReportContext, report ocrtypes.Report, signature []byte) bool { + hash, err := ckr.reportToSigData(reportCtx, report) + if err != nil { + return false + } + return ckr.VerifyBlob(publicKey, hash, signature) +} + +func (ckr *cosmosKeyring) Verify3(publicKey ocrtypes.OnchainPublicKey, cd ocrtypes.ConfigDigest, seqNr uint64, r ocrtypes.Report, signature []byte) bool { + return false +} + +func (ckr *cosmosKeyring) VerifyBlob(pubkey ocrtypes.OnchainPublicKey, b, sig []byte) bool { + // Ed25519 signatures are always 64 bytes and the + // public key (always prefixed, see Sign above) is always, + // 32 bytes, so we always require the max signature length. + if len(sig) != ckr.MaxSignatureLength() { + return false + } + if len(pubkey) != ed25519.PublicKeySize { + return false + } + return ed25519consensus.Verify(ed25519.PublicKey(pubkey), b, sig[32:]) +} + +func (ckr *cosmosKeyring) MaxSignatureLength() int { + // Reference: https://pkg.go.dev/crypto/ed25519 + return ed25519.PublicKeySize + ed25519.SignatureSize // 32 + 64 +} + +func (ckr *cosmosKeyring) Marshal() ([]byte, error) { + return ckr.privKey().Seed(), nil +} + +func (ckr *cosmosKeyring) Unmarshal(in []byte) error { + if len(in) != ed25519.SeedSize { + return errors.Errorf("unexpected seed size, got %d want %d", len(in), ed25519.SeedSize) + } + privKey := ed25519.NewKeyFromSeed(in) + ckr.privKey = func() ed25519.PrivateKey { return privKey } + pubKey, ok := privKey.Public().(ed25519.PublicKey) + if !ok { + return errors.New("failed to cast public key to ed25519.PublicKey") + } + ckr.pubKey = pubKey + return nil +} diff --git a/keystore/corekeys/ocr2key/cosmos_keyring_test.go b/keystore/corekeys/ocr2key/cosmos_keyring_test.go new file mode 100644 index 0000000000..9a220be5db --- /dev/null +++ b/keystore/corekeys/ocr2key/cosmos_keyring_test.go @@ -0,0 +1,59 @@ +package ocr2key + +import ( + "bytes" + cryptorand "crypto/rand" + "testing" + + "github.com/stretchr/testify/assert" + + "github.com/stretchr/testify/require" + + ocrtypes "github.com/smartcontractkit/libocr/offchainreporting2plus/types" +) + +func TestCosmosKeyRing_Sign_Verify(t *testing.T) { + kr1, err := newCosmosKeyring(cryptorand.Reader) + require.NoError(t, err) + kr2, err := newCosmosKeyring(cryptorand.Reader) + require.NoError(t, err) + ctx := ocrtypes.ReportContext{} + + t.Run("can verify", func(t *testing.T) { + report := ocrtypes.Report{} + sig, err := kr1.Sign(ctx, report) + require.NoError(t, err) + t.Log(len(sig)) + result := kr2.Verify(kr1.PublicKey(), ctx, report, sig) + require.True(t, result) + }) + + t.Run("invalid sig", func(t *testing.T) { + report := ocrtypes.Report{} + result := kr2.Verify(kr1.PublicKey(), ctx, report, []byte{0x01}) + require.False(t, result) + }) + + t.Run("invalid pubkey", func(t *testing.T) { + report := ocrtypes.Report{} + sig, err := kr1.Sign(ctx, report) + require.NoError(t, err) + result := kr2.Verify([]byte{0x01}, ctx, report, sig) + require.False(t, result) + }) +} + +func TestCosmosKeyRing_Marshalling(t *testing.T) { + kr1, err := newCosmosKeyring(cryptorand.Reader) + require.NoError(t, err) + m, err := kr1.Marshal() + require.NoError(t, err) + kr2 := cosmosKeyring{} + err = kr2.Unmarshal(m) + require.NoError(t, err) + assert.True(t, bytes.Equal(kr1.pubKey, kr2.pubKey)) + assert.True(t, bytes.Equal(kr1.privKey(), kr2.privKey())) + + // Invalid seed size should error + require.Error(t, kr2.Unmarshal([]byte{0x01})) +} diff --git a/keystore/corekeys/ocr2key/ed25519_keyring.go b/keystore/corekeys/ocr2key/ed25519_keyring.go new file mode 100644 index 0000000000..78e4a237aa --- /dev/null +++ b/keystore/corekeys/ocr2key/ed25519_keyring.go @@ -0,0 +1,139 @@ +package ocr2key + +import ( + "bytes" + "crypto/ed25519" + "io" + + "github.com/hdevalence/ed25519consensus" + "github.com/pkg/errors" + "golang.org/x/crypto/blake2b" + + "github.com/smartcontractkit/chainlink/v2/core/utils" + + "github.com/smartcontractkit/libocr/offchainreporting2/types" + "github.com/smartcontractkit/libocr/offchainreporting2plus/chains/evmutil" + ocrtypes "github.com/smartcontractkit/libocr/offchainreporting2plus/types" +) + +var _ ocrtypes.OnchainKeyring = &ed25519Keyring{} + +type ed25519Keyring struct { + privKey func() ed25519.PrivateKey + pubKey ed25519.PublicKey +} + +func newEd25519Keyring(material io.Reader) (*ed25519Keyring, error) { + pubKey, privKey, err := ed25519.GenerateKey(material) + if err != nil { + return nil, err + } + return &ed25519Keyring{pubKey: pubKey, privKey: func() ed25519.PrivateKey { return privKey }}, nil +} + +func (akr *ed25519Keyring) PublicKey() ocrtypes.OnchainPublicKey { + return []byte(akr.pubKey) +} + +func (akr *ed25519Keyring) reportToSigData(reportCtx ocrtypes.ReportContext, report ocrtypes.Report) ([]byte, error) { + rawReportContext := evmutil.RawReportContext(reportCtx) + h, err := blake2b.New256(nil) + if err != nil { + return nil, err + } + // blake2b_256(report_context | report) + h.Write(rawReportContext[0][:]) + h.Write(rawReportContext[1][:]) + h.Write(rawReportContext[2][:]) + h.Write(report) + return h.Sum(nil), nil +} + +func (akr *ed25519Keyring) Sign(reportCtx ocrtypes.ReportContext, report ocrtypes.Report) ([]byte, error) { + sigData, err := akr.reportToSigData(reportCtx, report) + if err != nil { + return nil, err + } + return akr.SignBlob(sigData) +} + +func (akr *ed25519Keyring) reportToSigData3(digest types.ConfigDigest, seqNr uint64, r ocrtypes.Report) ([]byte, error) { + rawReportContext := RawReportContext3(digest, seqNr) + h, err := blake2b.New256(nil) + if err != nil { + return nil, err + } + h.Write(r) + h.Write(rawReportContext[0][:]) + h.Write(rawReportContext[1][:]) + return h.Sum(nil), nil +} + +func (akr *ed25519Keyring) Sign3(digest types.ConfigDigest, seqNr uint64, r ocrtypes.Report) (signature []byte, err error) { + sigData, err := akr.reportToSigData3(digest, seqNr, r) + if err != nil { + return nil, err + } + return akr.SignBlob(sigData) +} + +func (akr *ed25519Keyring) SignBlob(b []byte) ([]byte, error) { + signedMsg := ed25519.Sign(akr.privKey(), b) + // match on-chain parsing (first 32 bytes are for pubkey, remaining are for signature) + return utils.ConcatBytes(akr.PublicKey(), signedMsg), nil +} + +func (akr *ed25519Keyring) Verify(publicKey ocrtypes.OnchainPublicKey, reportCtx ocrtypes.ReportContext, report ocrtypes.Report, signature []byte) bool { + hash, err := akr.reportToSigData(reportCtx, report) + if err != nil { + return false + } + return akr.VerifyBlob(publicKey, hash, signature) +} + +func (akr *ed25519Keyring) Verify3(publicKey ocrtypes.OnchainPublicKey, digest ocrtypes.ConfigDigest, seqNr uint64, r ocrtypes.Report, signature []byte) bool { + sigData, err := akr.reportToSigData3(digest, seqNr, r) + if err != nil { + return false + } + return akr.VerifyBlob(publicKey, sigData, signature) +} + +func (akr *ed25519Keyring) VerifyBlob(pubkey ocrtypes.OnchainPublicKey, b, sig []byte) bool { + // Ed25519 signatures are always 64 bytes and the + // public key (always prefixed, see Sign above) is always, + // 32 bytes, so we always require the max signature length. + if len(sig) != akr.MaxSignatureLength() { + return false + } + if len(pubkey) != ed25519.PublicKeySize { + return false + } + if !bytes.Equal(pubkey, sig[:ed25519.PublicKeySize]) { + return false + } + return ed25519consensus.Verify(ed25519.PublicKey(pubkey), b, sig[ed25519.PublicKeySize:]) +} + +func (akr *ed25519Keyring) MaxSignatureLength() int { + // Reference: https://pkg.go.dev/crypto/ed25519 + return ed25519.PublicKeySize + ed25519.SignatureSize // 32 + 64 +} + +func (akr *ed25519Keyring) Marshal() ([]byte, error) { + return akr.privKey().Seed(), nil +} + +func (akr *ed25519Keyring) Unmarshal(in []byte) error { + if len(in) != ed25519.SeedSize { + return errors.Errorf("unexpected seed size, got %d want %d", len(in), ed25519.SeedSize) + } + privKey := ed25519.NewKeyFromSeed(in) + akr.privKey = func() ed25519.PrivateKey { return privKey } + pubKey, ok := privKey.Public().(ed25519.PublicKey) + if !ok { + return errors.New("failed to cast public key to ed25519.PublicKey") + } + akr.pubKey = pubKey + return nil +} diff --git a/keystore/corekeys/ocr2key/ed25519_keyring_test.go b/keystore/corekeys/ocr2key/ed25519_keyring_test.go new file mode 100644 index 0000000000..064a45abd1 --- /dev/null +++ b/keystore/corekeys/ocr2key/ed25519_keyring_test.go @@ -0,0 +1,59 @@ +package ocr2key + +import ( + "bytes" + cryptorand "crypto/rand" + "testing" + + "github.com/stretchr/testify/assert" + + "github.com/stretchr/testify/require" + + ocrtypes "github.com/smartcontractkit/libocr/offchainreporting2plus/types" +) + +func TestAptosKeyRing_Sign_Verify(t *testing.T) { + kr1, err := newEd25519Keyring(cryptorand.Reader) + require.NoError(t, err) + kr2, err := newEd25519Keyring(cryptorand.Reader) + require.NoError(t, err) + ctx := ocrtypes.ReportContext{} + + t.Run("can verify", func(t *testing.T) { + report := ocrtypes.Report{} + sig, err := kr1.Sign(ctx, report) + require.NoError(t, err) + t.Log(len(sig)) + result := kr2.Verify(kr1.PublicKey(), ctx, report, sig) + require.True(t, result) + }) + + t.Run("invalid sig", func(t *testing.T) { + report := ocrtypes.Report{} + result := kr2.Verify(kr1.PublicKey(), ctx, report, []byte{0x01}) + require.False(t, result) + }) + + t.Run("invalid pubkey", func(t *testing.T) { + report := ocrtypes.Report{} + sig, err := kr1.Sign(ctx, report) + require.NoError(t, err) + result := kr2.Verify([]byte{0x01}, ctx, report, sig) + require.False(t, result) + }) +} + +func TestAptosKeyRing_Marshalling(t *testing.T) { + kr1, err := newEd25519Keyring(cryptorand.Reader) + require.NoError(t, err) + m, err := kr1.Marshal() + require.NoError(t, err) + kr2 := ed25519Keyring{} + err = kr2.Unmarshal(m) + require.NoError(t, err) + assert.True(t, bytes.Equal(kr1.pubKey, kr2.pubKey)) + assert.True(t, bytes.Equal(kr1.privKey(), kr2.privKey())) + + // Invalid seed size should error + require.Error(t, kr2.Unmarshal([]byte{0x01})) +} diff --git a/keystore/corekeys/ocr2key/evm_keyring.go b/keystore/corekeys/ocr2key/evm_keyring.go new file mode 100644 index 0000000000..4121b8c620 --- /dev/null +++ b/keystore/corekeys/ocr2key/evm_keyring.go @@ -0,0 +1,118 @@ +package ocr2key + +import ( + "bytes" + "crypto/ecdsa" + "encoding/binary" + "io" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/crypto" + + "github.com/smartcontractkit/libocr/offchainreporting2/types" + "github.com/smartcontractkit/libocr/offchainreporting2plus/chains/evmutil" + ocrtypes "github.com/smartcontractkit/libocr/offchainreporting2plus/types" +) + +var _ ocrtypes.OnchainKeyring = &evmKeyring{} + +type evmKeyring struct { + privateKey func() *ecdsa.PrivateKey +} + +func newEVMKeyring(material io.Reader) (*evmKeyring, error) { + ecdsaKey, err := ecdsa.GenerateKey(curve, material) + if err != nil { + return nil, err + } + return &evmKeyring{privateKey: func() *ecdsa.PrivateKey { return ecdsaKey }}, nil +} + +// XXX: PublicKey returns the address of the public key not the public key itself +func (ekr *evmKeyring) PublicKey() ocrtypes.OnchainPublicKey { + address := ekr.signingAddress() + return address[:] +} + +func (ekr *evmKeyring) Sign(reportCtx ocrtypes.ReportContext, report ocrtypes.Report) ([]byte, error) { + return ekr.SignBlob(ekr.reportToSigData(reportCtx, report)) +} + +func (ekr *evmKeyring) reportToSigData(reportCtx ocrtypes.ReportContext, report ocrtypes.Report) []byte { + return ReportToSigData(reportCtx, report) +} + +func ReportToSigData(reportCtx ocrtypes.ReportContext, report ocrtypes.Report) []byte { + rawReportContext := evmutil.RawReportContext(reportCtx) + sigData := crypto.Keccak256(report) + sigData = append(sigData, rawReportContext[0][:]...) + sigData = append(sigData, rawReportContext[1][:]...) + sigData = append(sigData, rawReportContext[2][:]...) + return crypto.Keccak256(sigData) +} + +func (ekr *evmKeyring) Sign3(digest types.ConfigDigest, seqNr uint64, r ocrtypes.Report) (signature []byte, err error) { + return ekr.SignBlob(ReportToSigData3(digest, seqNr, r)) +} + +func ReportToSigData3(digest types.ConfigDigest, seqNr uint64, r ocrtypes.Report) []byte { + rawReportContext := RawReportContext3(digest, seqNr) + sigData := crypto.Keccak256(r) + sigData = append(sigData, rawReportContext[0][:]...) + sigData = append(sigData, rawReportContext[1][:]...) + return crypto.Keccak256(sigData) +} + +func RawReportContext3(digest types.ConfigDigest, seqNr uint64) [2][32]byte { + seqNrBytes := [32]byte{} + binary.BigEndian.PutUint64(seqNrBytes[24:], seqNr) + return [2][32]byte{ + digest, + seqNrBytes, + } +} + +func (ekr *evmKeyring) SignBlob(b []byte) (sig []byte, err error) { + return crypto.Sign(b, ekr.privateKey()) +} + +func (ekr *evmKeyring) Verify(publicKey ocrtypes.OnchainPublicKey, reportCtx ocrtypes.ReportContext, report ocrtypes.Report, signature []byte) bool { + hash := ekr.reportToSigData(reportCtx, report) + return ekr.VerifyBlob(publicKey, hash, signature) +} + +func (ekr *evmKeyring) Verify3(publicKey ocrtypes.OnchainPublicKey, cd ocrtypes.ConfigDigest, seqNr uint64, r ocrtypes.Report, signature []byte) bool { + hash := ReportToSigData3(cd, seqNr, r) + return ekr.VerifyBlob(publicKey, hash, signature) +} + +func (ekr *evmKeyring) VerifyBlob(pubkey types.OnchainPublicKey, b, sig []byte) bool { + authorPubkey, err := crypto.SigToPub(b, sig) + if err != nil { + return false + } + authorAddress := crypto.PubkeyToAddress(*authorPubkey) + // no need for constant time compare since neither arg is sensitive + return bytes.Equal(pubkey[:], authorAddress[:]) +} + +func (ekr *evmKeyring) MaxSignatureLength() int { + return 65 +} + +func (ekr *evmKeyring) signingAddress() common.Address { + return crypto.PubkeyToAddress(ekr.privateKey().PublicKey) +} + +func (ekr *evmKeyring) Marshal() ([]byte, error) { + return crypto.FromECDSA(ekr.privateKey()), nil +} + +func (ekr *evmKeyring) Unmarshal(in []byte) error { + privateKey, err := crypto.ToECDSA(in) + if err != nil { + return err + } + ekr.privateKey = func() *ecdsa.PrivateKey { return privateKey } + return nil +} diff --git a/keystore/corekeys/ocr2key/evm_keyring_test.go b/keystore/corekeys/ocr2key/evm_keyring_test.go new file mode 100644 index 0000000000..38df8ac672 --- /dev/null +++ b/keystore/corekeys/ocr2key/evm_keyring_test.go @@ -0,0 +1,162 @@ +package ocr2key + +import ( + "bytes" + cryptorand "crypto/rand" + "math" + "math/rand" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + "github.com/smartcontractkit/libocr/offchainreporting2/types" + ocrtypes "github.com/smartcontractkit/libocr/offchainreporting2plus/types" + + "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" +) + +func TestEVMKeyring_SignVerify(t *testing.T) { + kr1, err := newEVMKeyring(cryptorand.Reader) + require.NoError(t, err) + kr2, err := newEVMKeyring(cryptorand.Reader) + require.NoError(t, err) + + ctx := ocrtypes.ReportContext{} + + t.Run("can verify", func(t *testing.T) { + report := ocrtypes.Report{} + sig, err := kr1.Sign(ctx, report) + require.NoError(t, err) + t.Log(len(sig)) + result := kr2.Verify(kr1.PublicKey(), ctx, report, sig) + assert.True(t, result) + }) + + t.Run("invalid sig", func(t *testing.T) { + report := ocrtypes.Report{} + result := kr2.Verify(kr1.PublicKey(), ctx, report, []byte{0x01}) + assert.False(t, result) + }) + + t.Run("invalid pubkey", func(t *testing.T) { + report := ocrtypes.Report{} + sig, err := kr1.Sign(ctx, report) + require.NoError(t, err) + result := kr2.Verify([]byte{0x01}, ctx, report, sig) + assert.False(t, result) + }) +} + +func TestEVMKeyring_Sign3Verify3(t *testing.T) { + kr1, err := newEVMKeyring(cryptorand.Reader) + require.NoError(t, err) + kr2, err := newEVMKeyring(cryptorand.Reader) + require.NoError(t, err) + + digest, err := types.BytesToConfigDigest(testutils.MustRandBytes(32)) + require.NoError(t, err) + seqNr := rand.Uint64() + r := ocrtypes.Report(testutils.MustRandBytes(rand.Intn(1024))) + + t.Run("can verify", func(t *testing.T) { + sig, err := kr1.Sign3(digest, seqNr, r) + require.NoError(t, err) + t.Log(len(sig)) + result := kr2.Verify3(kr1.PublicKey(), digest, seqNr, r, sig) + assert.True(t, result) + }) + + t.Run("invalid sig", func(t *testing.T) { + result := kr2.Verify3(kr1.PublicKey(), digest, seqNr, r, []byte{0x01}) + assert.False(t, result) + }) + + t.Run("invalid pubkey", func(t *testing.T) { + sig, err := kr1.Sign3(digest, seqNr, r) + require.NoError(t, err) + result := kr2.Verify3([]byte{0x01}, digest, seqNr, r, sig) + assert.False(t, result) + }) +} + +func TestEVMKeyring_Marshalling(t *testing.T) { + kr1, err := newEVMKeyring(cryptorand.Reader) + require.NoError(t, err) + + m, err := kr1.Marshal() + require.NoError(t, err) + + kr2 := evmKeyring{} + err = kr2.Unmarshal(m) + require.NoError(t, err) + + assert.True(t, bytes.Equal(kr1.PublicKey(), kr2.PublicKey())) + assert.True(t, bytes.Equal(kr1.privateKey().D.Bytes(), kr2.privateKey().D.Bytes())) + + // Invalid seed size should error + assert.Error(t, kr2.Unmarshal([]byte{0x01})) +} + +func TestRawReportContext3(t *testing.T) { + testCases := []struct { + name string + digest [32]byte + seqNr uint64 + expected [2][32]byte + }{ + { + name: "zero values", + digest: [32]byte{}, + seqNr: 0, + expected: [2][32]byte{ + {}, + {}, + }, + }, + { + name: "some digest", + digest: [32]byte{1, 2, 3}, + seqNr: 0, + expected: [2][32]byte{ + {1, 2, 3}, + {}, + }, + }, + { + name: "sequence number set to 1", + digest: [32]byte{}, + seqNr: 1, + expected: [2][32]byte{ + {}, + { + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 1, + }, + }, + }, + { + name: "sequence number set to max uint64", + digest: [32]byte{1, 2, 3}, + seqNr: math.MaxUint64, + expected: [2][32]byte{ + {1, 2, 3}, + { + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + }, + }, + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + actual := RawReportContext3(tc.digest, tc.seqNr) + assert.Equal(t, tc.expected, actual, "unexpected result") + }) + } +} diff --git a/keystore/corekeys/ocr2key/export.go b/keystore/corekeys/ocr2key/export.go new file mode 100644 index 0000000000..a7d3edf419 --- /dev/null +++ b/keystore/corekeys/ocr2key/export.go @@ -0,0 +1,90 @@ +package ocr2key + +import ( + "encoding/hex" + + "github.com/ethereum/go-ethereum/accounts/keystore" + + "github.com/smartcontractkit/chainlink-common/keystore/corekeys/starkkey" + "github.com/smartcontractkit/chainlink-common/keystore/internal" + "github.com/smartcontractkit/chainlink-common/keystore/scrypt" + "github.com/smartcontractkit/chainlink-common/pkg/chains/types" +) + +const keyTypeIdentifier = "OCR2" + +// EncryptedOCRKeyExport represents encrypted OCR key export +type EncryptedOCRKeyExport struct { + KeyType string `json:"keyType"` + ChainType types.ChainType `json:"chainType"` + ID string `json:"id"` + OnchainPublicKey string `json:"onchainPublicKey"` + OffChainPublicKey string `json:"offchainPublicKey"` + ConfigPublicKey string `json:"configPublicKey"` + Crypto keystore.CryptoJSON `json:"crypto"` +} + +func (x EncryptedOCRKeyExport) GetCrypto() keystore.CryptoJSON { + return x.Crypto +} + +// FromEncryptedJSON returns key from encrypted json +func FromEncryptedJSON(keyJSON []byte, password string) (KeyBundle, error) { + return internal.FromEncryptedJSON( + keyTypeIdentifier, + keyJSON, + password, + adulteratedPassword, + func(export EncryptedOCRKeyExport, rawPrivKey internal.Raw) (KeyBundle, error) { + var kb KeyBundle + switch export.ChainType { + case types.EVM: + kb = newKeyBundle(new(evmKeyring)) + case types.Cosmos: + kb = newKeyBundle(new(cosmosKeyring)) + case types.Solana: + kb = newKeyBundle(new(solanaKeyring)) + case types.StarkNet: + kb = newKeyBundle(new(starkkey.OCR2Key)) + case types.Aptos: + kb = newKeyBundle(new(ed25519Keyring)) + case types.Tron: + kb = newKeyBundle(new(evmKeyring)) + case types.TON: + kb = newKeyBundle(new(tonKeyring)) + case types.Sui: + kb = newKeyBundle(new(ed25519Keyring)) + default: + return nil, types.NewErrInvalidChainType(export.ChainType) + } + if err := kb.Unmarshal(internal.Bytes(rawPrivKey)); err != nil { + return nil, err + } + return kb, nil + }, + ) +} + +// ToEncryptedJSON returns encrypted JSON representing key +func ToEncryptedJSON(key KeyBundle, password string, scryptParams scrypt.ScryptParams) (export []byte, err error) { + return internal.ToEncryptedJSON( + keyTypeIdentifier, + key, + password, + scryptParams, + adulteratedPassword, + func(id string, key KeyBundle, cryptoJSON keystore.CryptoJSON) EncryptedOCRKeyExport { + pubKeyConfig := key.ConfigEncryptionPublicKey() + pubKey := key.OffchainPublicKey() + return EncryptedOCRKeyExport{ + KeyType: id, + ChainType: key.ChainType(), + ID: key.ID(), + OnchainPublicKey: key.OnChainPublicKey(), + OffChainPublicKey: hex.EncodeToString(pubKey[:]), + ConfigPublicKey: hex.EncodeToString(pubKeyConfig[:]), + Crypto: cryptoJSON, + } + }, + ) +} diff --git a/keystore/corekeys/ocr2key/export_test.go b/keystore/corekeys/ocr2key/export_test.go new file mode 100644 index 0000000000..fae9c0c562 --- /dev/null +++ b/keystore/corekeys/ocr2key/export_test.go @@ -0,0 +1,41 @@ +package ocr2key + +import ( + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + "github.com/smartcontractkit/chainlink-common/keystore/scrypt" + "github.com/smartcontractkit/chainlink-common/pkg/chains/types" +) + +func TestExport(t *testing.T) { + var tt = []struct { + chain types.ChainType + }{ + {chain: types.EVM}, + {chain: types.Cosmos}, + {chain: types.Solana}, + {chain: types.StarkNet}, + {chain: types.Aptos}, + {chain: types.Tron}, + } + for _, tc := range tt { + t.Run(string(tc.chain), func(t *testing.T) { + kb, err := New(tc.chain) + require.NoError(t, err) + ej, err := ToEncryptedJSON(kb, "blah", scrypt.FastScryptParams) + require.NoError(t, err) + kbAfter, err := FromEncryptedJSON(ej, "blah") + require.NoError(t, err) + assert.Equal(t, kbAfter.ID(), kb.ID()) + assert.Equal(t, kbAfter.PublicKey(), kb.PublicKey()) + assert.Equal(t, kbAfter.OffchainPublicKey(), kb.OffchainPublicKey()) + assert.Equal(t, kbAfter.MaxSignatureLength(), kb.MaxSignatureLength()) + assert.Equal(t, kbAfter.Raw(), kb.Raw()) + assert.Equal(t, kbAfter.ConfigEncryptionPublicKey(), kb.ConfigEncryptionPublicKey()) + assert.Equal(t, kbAfter.ChainType(), kb.ChainType()) + }) + } +} diff --git a/keystore/corekeys/ocr2key/generic_key_bundle.go b/keystore/corekeys/ocr2key/generic_key_bundle.go new file mode 100644 index 0000000000..a7fbb17fb7 --- /dev/null +++ b/keystore/corekeys/ocr2key/generic_key_bundle.go @@ -0,0 +1,190 @@ +package ocr2key + +import ( + "bytes" + cryptorand "crypto/rand" + "crypto/sha256" + "encoding/hex" + "encoding/json" + "io" + + "github.com/pkg/errors" + + ocrtypes "github.com/smartcontractkit/libocr/offchainreporting2plus/types" + + "github.com/smartcontractkit/chainlink-common/keystore/internal" + "github.com/smartcontractkit/chainlink-common/pkg/chains/types" +) + +type ( + keyring interface { + ocrtypes.OnchainKeyring + OCR3SignerVerifier + Marshal() ([]byte, error) + Unmarshal(in []byte) error + } + + keyBundle[K keyring] struct { + keyBundleBase + keyring K + } + + keyBundleRawData struct { + ChainType types.ChainType + OffchainKeyring []byte + Keyring []byte + ID Sha256Hash // tracked to preserve bundle ID in case of migrations + + // old chain specific format for migrating + EVMKeyring []byte `json:",omitempty"` + SolanaKeyring []byte `json:",omitempty"` + CosmosKeyring []byte `json:",omitempty"` + } +) + +func newKeyBundle[K keyring](key K) *keyBundle[K] { + return &keyBundle[K]{keyring: key} +} + +func newKeyBundleRand[K keyring](chain types.ChainType, newKeyring func(material io.Reader) (K, error)) (*keyBundle[K], error) { + return newKeyBundleFrom(chain, newKeyring, cryptorand.Reader, cryptorand.Reader, cryptorand.Reader) +} + +func mustNewKeyBundleInsecure[K keyring](chain types.ChainType, newKeyring func(material io.Reader) (K, error), reader io.Reader) *keyBundle[K] { + key, err := newKeyBundleFrom(chain, newKeyring, reader, reader, reader) + if err != nil { + panic(errors.Wrapf(err, "failed to generate new OCR2-%s Key", chain)) + } + return key +} + +func newKeyBundleFrom[K keyring](chain types.ChainType, newKeyring func(material io.Reader) (K, error), onchainSigningKeyMaterial, onchainEncryptionKeyMaterial, offchainKeyMaterial io.Reader) (*keyBundle[K], error) { + offchainKeyring, err := newOffchainKeyring(onchainSigningKeyMaterial, onchainEncryptionKeyMaterial) + if err != nil { + return nil, err + } + kr, err := newKeyring(onchainSigningKeyMaterial) + if err != nil { + return nil, err + } + k := keyBundle[K]{ + keyBundleBase: keyBundleBase{ + chainType: chain, + offchainKeyring: *offchainKeyring, + }, + keyring: kr, + } + marshalledPrivK, err := k.Marshal() + if err != nil { + return nil, err + } + k.id = sha256.Sum256(marshalledPrivK) + return &k, nil +} + +func (kb *keyBundle[K]) MaxSignatureLength() int { + return kb.keyring.MaxSignatureLength() +} + +func (kb *keyBundle[K]) PublicKey() ocrtypes.OnchainPublicKey { + return kb.keyring.PublicKey() +} + +func (kb *keyBundle[K]) Sign(reportCtx ocrtypes.ReportContext, report ocrtypes.Report) ([]byte, error) { + return kb.keyring.Sign(reportCtx, report) +} + +func (kb *keyBundle[K]) Sign3(digest ocrtypes.ConfigDigest, seqNr uint64, r ocrtypes.Report) (signature []byte, err error) { + return kb.keyring.Sign3(digest, seqNr, r) +} + +func (kb *keyBundle[K]) SignBlob(b []byte) (sig []byte, err error) { + return kb.keyring.SignBlob(b) +} + +func (kb *keyBundle[K]) Verify(publicKey ocrtypes.OnchainPublicKey, reportCtx ocrtypes.ReportContext, report ocrtypes.Report, signature []byte) bool { + return kb.keyring.Verify(publicKey, reportCtx, report, signature) +} + +func (kb *keyBundle[K]) Verify3(publicKey ocrtypes.OnchainPublicKey, cd ocrtypes.ConfigDigest, seqNr uint64, r ocrtypes.Report, signature []byte) bool { + return kb.keyring.Verify3(publicKey, cd, seqNr, r, signature) +} +func (kb *keyBundle[K]) VerifyBlob(pubkey ocrtypes.OnchainPublicKey, b, sig []byte) bool { + return kb.keyring.VerifyBlob(pubkey, b, sig) +} + +// OnChainPublicKey returns public component of the keypair used on chain +func (kb *keyBundle[K]) OnChainPublicKey() string { + return hex.EncodeToString(kb.keyring.PublicKey()) +} + +func (kb *keyBundle[K]) Marshal() ([]byte, error) { + offchainKeyringBytes, err := kb.marshal() + if err != nil { + return nil, err + } + keyringBytes, err := kb.keyring.Marshal() + if err != nil { + return nil, err + } + rawKeyData := keyBundleRawData{ + ChainType: kb.chainType, + OffchainKeyring: offchainKeyringBytes, + Keyring: keyringBytes, + ID: kb.id, // preserve bundle ID + } + return json.Marshal(&rawKeyData) +} + +func (kb *keyBundle[K]) Unmarshal(b []byte) (err error) { + var rawKeyData keyBundleRawData + err = json.Unmarshal(b, &rawKeyData) + if err != nil { + return err + } + if err = rawKeyData.Migrate(b); err != nil { + return err + } + + err = kb.unmarshal(rawKeyData.OffchainKeyring) + if err != nil { + return err + } + + err = kb.keyring.Unmarshal(rawKeyData.Keyring) + if err != nil { + return err + } + kb.chainType = rawKeyData.ChainType + kb.id = rawKeyData.ID + return nil +} + +func (kb *keyBundle[K]) Raw() internal.Raw { + b, err := kb.Marshal() + if err != nil { + panic(err) + } + return internal.NewRaw(b) +} + +// migration code +func (kbraw *keyBundleRawData) Migrate(b []byte) error { + // if key is not stored in Keyring param, use EVM or Solana as Keyring + // for migrating, key will only be marshalled into Keyring + if len(kbraw.Keyring) == 0 { + if len(kbraw.EVMKeyring) != 0 { + kbraw.Keyring = kbraw.EVMKeyring + } else if len(kbraw.SolanaKeyring) != 0 { + kbraw.Keyring = kbraw.SolanaKeyring + } + } + + // if key does not have an ID associated with it (old formats), + // derive the key ID and preserve it + if bytes.Equal(kbraw.ID[:], new(Sha256Hash)[:]) { + kbraw.ID = sha256.Sum256(b) + } + + return nil +} diff --git a/keystore/corekeys/ocr2key/generic_key_bundle_test.go b/keystore/corekeys/ocr2key/generic_key_bundle_test.go new file mode 100644 index 0000000000..fa5e4e0e8a --- /dev/null +++ b/keystore/corekeys/ocr2key/generic_key_bundle_test.go @@ -0,0 +1,154 @@ +package ocr2key + +import ( + cryptorand "crypto/rand" + "encoding/json" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + "github.com/smartcontractkit/chainlink-common/pkg/chains/types" +) + +type ( + XXXOldEVMKeyBundleRawData struct { + ChainType types.ChainType + OffchainKeyring []byte + EVMKeyring []byte + } + XXXOldSolanaKeyBundleRawData struct { + ChainType types.ChainType + OffchainKeyring []byte + SolanaKeyring []byte + } + XXXOldV1GenericKeyBundleRawData struct { + ChainType types.ChainType + OffchainKeyring []byte + Keyring []byte + // missing ID + } +) + +func TestGenericKeyBundle_Migrate_UnmarshalMarshal(t *testing.T) { + // offchain key + offKey, err := newOffchainKeyring(cryptorand.Reader, cryptorand.Reader) + require.NoError(t, err) + offBytes, err := offKey.marshal() + require.NoError(t, err) + + t.Run("EVM", func(t *testing.T) { + // onchain key + onKey, err := newEVMKeyring(cryptorand.Reader) + require.NoError(t, err) + onBytes, err := onKey.Marshal() + require.NoError(t, err) + + // marshal old key format + oldKey := XXXOldEVMKeyBundleRawData{ + ChainType: types.EVM, + OffchainKeyring: offBytes, + EVMKeyring: onBytes, + } + bundleBytes, err := json.Marshal(oldKey) + require.NoError(t, err) + + // test Unmarshal with old raw bundle + bundle := newKeyBundle(&evmKeyring{}) + require.NoError(t, bundle.Unmarshal(bundleBytes)) + newBundleBytes, err := bundle.Marshal() // marshalling migrates to a generic struct + require.NoError(t, err) + + // new bundle == old bundle (only difference is Keyring == Keyring) + var newRawBundle keyBundleRawData + require.NoError(t, json.Unmarshal(newBundleBytes, &newRawBundle)) + assert.Equal(t, oldKey.ChainType, newRawBundle.ChainType) + assert.Equal(t, oldKey.OffchainKeyring, newRawBundle.OffchainKeyring) + assert.Equal(t, oldKey.EVMKeyring, newRawBundle.Keyring) + + // test unmarshalling again to ensure ID has not changed + // the underlying bytes have changed, but ID should be preserved + newBundle := newKeyBundle(&evmKeyring{}) + require.NoError(t, newBundle.Unmarshal(newBundleBytes)) + assert.Equal(t, bundle.ID(), newBundle.ID()) + }) + + t.Run("Solana", func(t *testing.T) { + // onchain key + onKey, err := newSolanaKeyring(cryptorand.Reader) + require.NoError(t, err) + onBytes, err := onKey.Marshal() + require.NoError(t, err) + + // marshal old key format + oldKey := XXXOldSolanaKeyBundleRawData{ + ChainType: types.Solana, + OffchainKeyring: offBytes, + SolanaKeyring: onBytes, + } + bundleBytes, err := json.Marshal(oldKey) + require.NoError(t, err) + + // test Unmarshal with old raw bundle + bundle := newKeyBundle(&solanaKeyring{}) + require.NoError(t, bundle.Unmarshal(bundleBytes)) + newBundleBytes, err := bundle.Marshal() + require.NoError(t, err) + + // new bundle == old bundle (only difference is Keyring == Keyring) + var newRawBundle keyBundleRawData + require.NoError(t, json.Unmarshal(newBundleBytes, &newRawBundle)) + assert.Equal(t, oldKey.ChainType, newRawBundle.ChainType) + assert.Equal(t, oldKey.OffchainKeyring, newRawBundle.OffchainKeyring) + assert.Equal(t, oldKey.SolanaKeyring, newRawBundle.Keyring) + + // test unmarshalling again to ensure ID has not changed + // the underlying bytes have changed, but ID should be preserved + newBundle := newKeyBundle(&solanaKeyring{}) + require.NoError(t, newBundle.Unmarshal(newBundleBytes)) + assert.Equal(t, bundle.ID(), newBundle.ID()) + }) + + t.Run("Cosmos", func(t *testing.T) { + // onchain key + bundle, err := newKeyBundleRand(types.Cosmos, newCosmosKeyring) + require.NoError(t, err) + bundleBytes, err := bundle.Marshal() + require.NoError(t, err) + + // test unmarshalling again to ensure ID has not changed + // the underlying bytes have changed, but ID should be preserved + otherBundle := newKeyBundle(&cosmosKeyring{}) + require.NoError(t, otherBundle.Unmarshal(bundleBytes)) + assert.Equal(t, bundle.ID(), otherBundle.ID()) + }) + + t.Run("MissingID", func(t *testing.T) { + // onchain key + onKey, err := newEVMKeyring(cryptorand.Reader) + require.NoError(t, err) + onBytes, err := onKey.Marshal() + require.NoError(t, err) + + // build key without ID parameter + oldKey := XXXOldV1GenericKeyBundleRawData{ + ChainType: types.EVM, + OffchainKeyring: offBytes, + Keyring: onBytes, + } + bundleBytes, err := json.Marshal(oldKey) + require.NoError(t, err) + + // unmarshal first time to generate ID + bundle := newKeyBundle(&evmKeyring{}) + require.NoError(t, bundle.Unmarshal(bundleBytes)) + + // marshal and unmarshal again + // different bytes generated, ID should not change + newBundleBytes, err := bundle.Marshal() + require.NoError(t, err) + newBundle := newKeyBundle(&evmKeyring{}) + require.NoError(t, newBundle.Unmarshal(newBundleBytes)) + assert.Equal(t, bundle.ID(), newBundle.ID()) + }) +} diff --git a/keystore/corekeys/ocr2key/key_bundle.go b/keystore/corekeys/ocr2key/key_bundle.go new file mode 100644 index 0000000000..e6db7f774f --- /dev/null +++ b/keystore/corekeys/ocr2key/key_bundle.go @@ -0,0 +1,153 @@ +package ocr2key + +import ( + "encoding/hex" + "encoding/json" + "io" + + "github.com/ethereum/go-ethereum/crypto/secp256k1" + + ocrtypes "github.com/smartcontractkit/libocr/offchainreporting2plus/types" + + "github.com/smartcontractkit/chainlink-common/keystore/corekeys/starkkey" + "github.com/smartcontractkit/chainlink-common/keystore/internal" + "github.com/smartcontractkit/chainlink-common/pkg/chains/types" +) + +type Sha256Hash [32]byte + +type OCR3SignerVerifier interface { + SignBlob(b []byte) (sig []byte, err error) + VerifyBlob(publicKey ocrtypes.OnchainPublicKey, b []byte, sig []byte) bool + Sign3(digest ocrtypes.ConfigDigest, seqNr uint64, r ocrtypes.Report) (signature []byte, err error) + Verify3(publicKey ocrtypes.OnchainPublicKey, cd ocrtypes.ConfigDigest, seqNr uint64, r ocrtypes.Report, signature []byte) bool +} + +type KeyBundle interface { + // OnchainKeyring is used for signing reports (groups of observations, verified onchain) + ocrtypes.OnchainKeyring + // offchainKeyring is used for signing observations + ocrtypes.OffchainKeyring + + OCR3SignerVerifier + + ID() string + ChainType() types.ChainType + Marshal() ([]byte, error) + Unmarshal(b []byte) (err error) + Raw() internal.Raw + OnChainPublicKey() string + // Decrypts ciphertext using the encryptionKey from an OCR2 offchainKeyring + NaclBoxOpenAnonymous(ciphertext []byte) (plaintext []byte, err error) +} + +// check generic keybundle for each chain conforms to KeyBundle interface +var _ KeyBundle = &keyBundle[*evmKeyring]{} +var _ KeyBundle = &keyBundle[*cosmosKeyring]{} +var _ KeyBundle = &keyBundle[*solanaKeyring]{} +var _ KeyBundle = &keyBundle[*starkkey.OCR2Key]{} +var _ KeyBundle = &keyBundle[*ed25519Keyring]{} +var _ KeyBundle = &keyBundle[*tonKeyring]{} +var _ KeyBundle = &keyBundle[*ed25519Keyring]{} + +var curve = secp256k1.S256() + +// New returns key bundle based on the chain type +func New(chainType types.ChainType) (KeyBundle, error) { + switch chainType { + case types.EVM: + return newKeyBundleRand(types.EVM, newEVMKeyring) + case types.Cosmos: + return newKeyBundleRand(types.Cosmos, newCosmosKeyring) + case types.Solana: + return newKeyBundleRand(types.Solana, newSolanaKeyring) + case types.StarkNet: + return newKeyBundleRand(types.StarkNet, starkkey.NewOCR2Key) + case types.Aptos: + return newKeyBundleRand(types.Aptos, newEd25519Keyring) + case types.Tron: + return newKeyBundleRand(types.Tron, newEVMKeyring) + case types.TON: + return newKeyBundleRand(types.TON, newTONKeyring) + case types.Sui: + return newKeyBundleRand(types.Sui, newEd25519Keyring) + } + return nil, types.NewErrInvalidChainType(chainType) +} + +// MustNewInsecure returns key bundle based on the chain type or panics +func MustNewInsecure(reader io.Reader, chainType types.ChainType) KeyBundle { + switch chainType { + case types.EVM: + return mustNewKeyBundleInsecure(types.EVM, newEVMKeyring, reader) + case types.Cosmos: + return mustNewKeyBundleInsecure(types.Cosmos, newCosmosKeyring, reader) + case types.Solana: + return mustNewKeyBundleInsecure(types.Solana, newSolanaKeyring, reader) + case types.StarkNet: + return mustNewKeyBundleInsecure(types.StarkNet, starkkey.NewOCR2Key, reader) + case types.Aptos: + return mustNewKeyBundleInsecure(types.Aptos, newEd25519Keyring, reader) + case types.Tron: + return mustNewKeyBundleInsecure(types.Tron, newEVMKeyring, reader) + case types.TON: + return mustNewKeyBundleInsecure(types.TON, newTONKeyring, reader) + case types.Sui: + return mustNewKeyBundleInsecure(types.Sui, newEd25519Keyring, reader) + } + panic(types.NewErrInvalidChainType(chainType)) +} + +type keyBundleBase struct { + offchainKeyring + id Sha256Hash + chainType types.ChainType +} + +func (kb keyBundleBase) ID() string { + return hex.EncodeToString(kb.id[:]) +} + +// ChainType gets the chain type from the key bundle +func (kb keyBundleBase) ChainType() types.ChainType { + return kb.chainType +} + +func KeyFor(raw internal.Raw) (kb KeyBundle) { + var temp struct{ ChainType types.ChainType } + err := json.Unmarshal(internal.Bytes(raw), &temp) + if err != nil { + panic(err) + } + switch temp.ChainType { + case types.EVM: + kb = newKeyBundle(new(evmKeyring)) + case types.Cosmos: + kb = newKeyBundle(new(cosmosKeyring)) + case types.Solana: + kb = newKeyBundle(new(solanaKeyring)) + case types.StarkNet: + kb = newKeyBundle(new(starkkey.OCR2Key)) + case types.Aptos: + kb = newKeyBundle(new(ed25519Keyring)) + case types.Tron: + kb = newKeyBundle(new(evmKeyring)) + case types.TON: + kb = newKeyBundle(new(tonKeyring)) + case types.Sui: + kb = newKeyBundle(new(ed25519Keyring)) + default: + return nil + } + if err := kb.Unmarshal(internal.Bytes(raw)); err != nil { + panic(err) + } + return +} + +// type is added to the beginning of the passwords for OCR key bundles, +// so that the keys can't accidentally be mis-used in the wrong place +func adulteratedPassword(auth string) string { + s := "ocr2key" + auth + return s +} diff --git a/keystore/corekeys/ocr2key/key_bundle_test.go b/keystore/corekeys/ocr2key/key_bundle_test.go new file mode 100644 index 0000000000..cb9faa55ec --- /dev/null +++ b/keystore/corekeys/ocr2key/key_bundle_test.go @@ -0,0 +1,63 @@ +package ocr2key_test + +import ( + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + "github.com/smartcontractkit/chainlink-common/keystore/corekeys/ocr2key" + "github.com/smartcontractkit/chainlink-common/pkg/chains/types" +) + +func assertKeyBundlesNotEqual(t *testing.T, pk1 ocr2key.KeyBundle, pk2 ocr2key.KeyBundle) { + assert.NotEqual(t, pk1.ID(), pk2.ID()) + assert.NotEqual(t, pk1.OffchainPublicKey(), pk2.OffchainPublicKey()) + assert.NotEqual(t, pk1.OnChainPublicKey(), pk2.OnChainPublicKey()) +} + +func TestOCR2Keys_New(t *testing.T) { + t.Parallel() + var keys []ocr2key.KeyBundle + + // create two keys for each chain type + for _, chain := range types.SupportedChainTypes { + pk0, err := ocr2key.New(chain) + require.NoError(t, err) + pk1, err := ocr2key.New(chain) + require.NoError(t, err) + + keys = append(keys, pk0) + keys = append(keys, pk1) + } + + // validate keys are unique + for i := 0; i < len(keys); i++ { + for j := i + 1; j < len(keys); j++ { + assertKeyBundlesNotEqual(t, keys[i], keys[j]) + } + } + + // validate chain types + for i := 0; i < len(keys); i += 2 { + // check key for same chain + require.Equal(t, keys[i].ChainType(), keys[i+1].ChainType()) + + // check 1 key for each chain + for j := i + 2; j < len(keys); j += 2 { + require.NotEqual(t, keys[i].ChainType(), keys[j].ChainType()) + } + } +} + +func TestOCR2KeyBundle_BundleBase(t *testing.T) { + t.Parallel() + + for _, chain := range types.SupportedChainTypes { + kb, err := ocr2key.New(chain) + require.NoError(t, err) + + assert.NotNil(t, kb.ID()) + assert.Equal(t, chain, kb.ChainType()) + } +} diff --git a/keystore/corekeys/ocr2key/offchain_keyring.go b/keystore/corekeys/ocr2key/offchain_keyring.go new file mode 100644 index 0000000000..546dd4991f --- /dev/null +++ b/keystore/corekeys/ocr2key/offchain_keyring.go @@ -0,0 +1,138 @@ +package ocr2key + +import ( + "bytes" + "crypto/ed25519" + "encoding/binary" + "errors" + "io" + + "golang.org/x/crypto/nacl/box" + + "golang.org/x/crypto/curve25519" + + ocrtypes "github.com/smartcontractkit/libocr/offchainreporting2plus/types" +) + +var _ ocrtypes.OffchainKeyring = &offchainKeyring{} + +// offchainKeyring contains the secret keys needed for the OCR nodes to share secrets +// and perform aggregation. +// +// This is currently an ed25519 signing key and a separate encryption key. +// +// All its functions should be thread-safe. +type offchainKeyring struct { + signingKey func() ed25519.PrivateKey + encryptionKey func() *[curve25519.ScalarSize]byte +} + +func newOffchainKeyring(encryptionMaterial, signingMaterial io.Reader) (*offchainKeyring, error) { + _, signingKey, err := ed25519.GenerateKey(signingMaterial) + if err != nil { + return nil, err + } + + encryptionKey := [curve25519.ScalarSize]byte{} + _, err = encryptionMaterial.Read(encryptionKey[:]) + if err != nil { + return nil, err + } + + ok := &offchainKeyring{ + signingKey: func() ed25519.PrivateKey { return signingKey }, + encryptionKey: func() *[32]byte { return &encryptionKey }, + } + _, err = ok.configEncryptionPublicKey() + if err != nil { + return nil, err + } + return ok, nil +} + +// NaclBoxOpenAnonymous decrypts a message that was encrypted using the OCR2 Offchain public key +func (ok *offchainKeyring) NaclBoxOpenAnonymous(ciphertext []byte) (plaintext []byte, err error) { + if len(ciphertext) < box.Overhead { + return nil, errors.New("ciphertext too short") + } + + publicKey := [curve25519.PointSize]byte(ok.ConfigEncryptionPublicKey()) + + decrypted, success := box.OpenAnonymous(nil, ciphertext, &publicKey, ok.encryptionKey()) + if !success { + return nil, errors.New("decryption failed") + } + + return decrypted, nil +} + +// OffchainSign signs message using private key +func (ok *offchainKeyring) OffchainSign(msg []byte) (signature []byte, err error) { + return ed25519.Sign(ok.signingKey(), msg), nil +} + +// ConfigDiffieHellman returns the shared point obtained by multiplying someone's +// public key by a secret scalar ( in this case, the offchain key ring's encryption key.) +func (ok *offchainKeyring) ConfigDiffieHellman(point [curve25519.PointSize]byte) ([curve25519.PointSize]byte, error) { + p, err := curve25519.X25519(ok.encryptionKey()[:], point[:]) + if err != nil { + return [curve25519.PointSize]byte{}, err + } + sharedPoint := [ed25519.PublicKeySize]byte{} + copy(sharedPoint[:], p) + return sharedPoint, nil +} + +// OffchainPublicKey returns the public component of this offchain keyring. +func (ok *offchainKeyring) OffchainPublicKey() ocrtypes.OffchainPublicKey { + var offchainPubKey [ed25519.PublicKeySize]byte + copy(offchainPubKey[:], ok.signingKey().Public().(ed25519.PublicKey)[:]) + return offchainPubKey +} + +// ConfigEncryptionPublicKey returns config public key +func (ok *offchainKeyring) ConfigEncryptionPublicKey() ocrtypes.ConfigEncryptionPublicKey { + cpk, _ := ok.configEncryptionPublicKey() + return cpk +} + +func (ok *offchainKeyring) configEncryptionPublicKey() (ocrtypes.ConfigEncryptionPublicKey, error) { + rv, err := curve25519.X25519(ok.encryptionKey()[:], curve25519.Basepoint) + if err != nil { + return [curve25519.PointSize]byte{}, err + } + var rvFixed [curve25519.PointSize]byte + copy(rvFixed[:], rv) + return rvFixed, nil +} + +func (ok *offchainKeyring) marshal() ([]byte, error) { + buffer := new(bytes.Buffer) + err := binary.Write(buffer, binary.LittleEndian, ok.signingKey()) + if err != nil { + return nil, err + } + err = binary.Write(buffer, binary.LittleEndian, ok.encryptionKey()) + if err != nil { + return nil, err + } + return buffer.Bytes(), nil +} + +func (ok *offchainKeyring) unmarshal(in []byte) error { + buffer := bytes.NewReader(in) + signingKey := make(ed25519.PrivateKey, ed25519.PrivateKeySize) + err := binary.Read(buffer, binary.LittleEndian, &signingKey) + if err != nil { + return err + } + ok.signingKey = func() ed25519.PrivateKey { return signingKey } + encryptionKey := [curve25519.ScalarSize]byte{} + err = binary.Read(buffer, binary.LittleEndian, &encryptionKey) + if err != nil { + return err + } + ok.encryptionKey = func() *[32]byte { return &encryptionKey } + _, err = ok.configEncryptionPublicKey() + return err +} diff --git a/keystore/corekeys/ocr2key/offchain_keyring_test.go b/keystore/corekeys/ocr2key/offchain_keyring_test.go new file mode 100644 index 0000000000..a19050548a --- /dev/null +++ b/keystore/corekeys/ocr2key/offchain_keyring_test.go @@ -0,0 +1,68 @@ +package ocr2key + +import ( + "bytes" + "crypto/ed25519" + cryptorand "crypto/rand" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "golang.org/x/crypto/curve25519" + "golang.org/x/crypto/nacl/box" +) + +func TestOffchainKeyring(t *testing.T) { + kr, err := newOffchainKeyring(cryptorand.Reader, cryptorand.Reader) + require.NoError(t, err) + pubKey := kr.OffchainPublicKey() + assert.True(t, bytes.Equal(kr.signingKey().Public().(ed25519.PublicKey), pubKey[:])) +} + +func TestOffchainKeyring_NaclBoxSealAnonymous(t *testing.T) { + kr, err := newOffchainKeyring(cryptorand.Reader, cryptorand.Reader) + require.NoError(t, err) + + originalMessage := []byte("test") + + encryptedMessage := naclBoxSealAnonymous(t, kr.ConfigEncryptionPublicKey(), originalMessage) + + decryptedMessage, err := kr.NaclBoxOpenAnonymous(encryptedMessage) + if err != nil { + t.Fatal(err) + } + + assert.Equal(t, originalMessage, decryptedMessage) +} + +func TestOffchainKeyring_NaclBoxSealAnonymous_ShortCiphertext(t *testing.T) { + kr, err := newOffchainKeyring(cryptorand.Reader, cryptorand.Reader) + require.NoError(t, err) + + shortMessage := []byte("short") + + _, err = kr.NaclBoxOpenAnonymous(shortMessage) + assert.Equal(t, "ciphertext too short", err.Error()) +} + +func TestOffchainKeyring_NaclBoxSealAnonymous_FailedDecryption(t *testing.T) { + kr, err := newOffchainKeyring(cryptorand.Reader, cryptorand.Reader) + require.NoError(t, err) + + invalid := []byte("invalidEncryptedMessage") + + _, err = kr.NaclBoxOpenAnonymous(invalid) + assert.Equal(t, "decryption failed", err.Error()) +} + +func naclBoxSealAnonymous(t *testing.T, peerPublicKey [curve25519.PointSize]byte, plaintext []byte) []byte { + t.Helper() + + ciphertext, err := box.SealAnonymous(nil, plaintext, &peerPublicKey, cryptorand.Reader) + if err != nil { + t.Fatalf("encryption failed") + return nil + } + + return ciphertext +} diff --git a/keystore/corekeys/ocr2key/solana_keyring.go b/keystore/corekeys/ocr2key/solana_keyring.go new file mode 100644 index 0000000000..be83dc0ecc --- /dev/null +++ b/keystore/corekeys/ocr2key/solana_keyring.go @@ -0,0 +1,111 @@ +package ocr2key + +import ( + "bytes" + "crypto/ecdsa" + "crypto/sha256" + "encoding/binary" + "io" + + "github.com/ethereum/go-ethereum/crypto" + "golang.org/x/crypto/sha3" + + "github.com/smartcontractkit/libocr/offchainreporting2/types" + "github.com/smartcontractkit/libocr/offchainreporting2plus/chains/evmutil" + ocrtypes "github.com/smartcontractkit/libocr/offchainreporting2plus/types" +) + +var _ ocrtypes.OnchainKeyring = &solanaKeyring{} + +type solanaKeyring struct { + privateKey func() *ecdsa.PrivateKey +} + +func newSolanaKeyring(material io.Reader) (*solanaKeyring, error) { + ecdsaKey, err := ecdsa.GenerateKey(curve, material) + if err != nil { + return nil, err + } + return &solanaKeyring{privateKey: func() *ecdsa.PrivateKey { return ecdsaKey }}, nil +} + +// XXX: PublicKey returns the evm-style address of the public key not the public key itself +func (skr *solanaKeyring) PublicKey() ocrtypes.OnchainPublicKey { + address := crypto.PubkeyToAddress(skr.privateKey().PublicKey) + return address[:] +} + +func (skr *solanaKeyring) reportToSigData(reportCtx ocrtypes.ReportContext, report ocrtypes.Report) []byte { + rawReportContext := evmutil.RawReportContext(reportCtx) + h := sha256.New() + h.Write([]byte{uint8(len(report))}) + h.Write(report) + h.Write(rawReportContext[0][:]) + h.Write(rawReportContext[1][:]) + h.Write(rawReportContext[2][:]) + return h.Sum(nil) +} + +func (skr *solanaKeyring) Sign(reportCtx ocrtypes.ReportContext, report ocrtypes.Report) ([]byte, error) { + return skr.SignBlob(skr.reportToSigData(reportCtx, report)) +} + +func (skr *solanaKeyring) Sign3(digest types.ConfigDigest, seqNr uint64, r ocrtypes.Report) (signature []byte, err error) { + bytes, err := skr.reportToSigData3(digest, seqNr, r) + if err != nil { + return nil, err + } + return skr.SignBlob(bytes) +} + +func (skr *solanaKeyring) reportToSigData3(digest types.ConfigDigest, seqNr uint64, r ocrtypes.Report) ([]byte, error) { + rawReportContext := RawReportContext3(digest, seqNr) + h := sha3.NewLegacyKeccak256() + reportLen := uint16(len(r)) //nolint:gosec // max U16 larger than solana transaction size + err := binary.Write(h, binary.LittleEndian, reportLen) + h.Write(r) + h.Write(rawReportContext[0][:]) + h.Write(rawReportContext[1][:]) + return h.Sum(nil), err +} + +func (skr *solanaKeyring) SignBlob(b []byte) (sig []byte, err error) { + return crypto.Sign(b, skr.privateKey()) +} + +func (skr *solanaKeyring) Verify(publicKey ocrtypes.OnchainPublicKey, reportCtx ocrtypes.ReportContext, report ocrtypes.Report, signature []byte) bool { + hash := skr.reportToSigData(reportCtx, report) + return skr.VerifyBlob(publicKey, hash, signature) +} + +func (skr *solanaKeyring) Verify3(publicKey ocrtypes.OnchainPublicKey, cd ocrtypes.ConfigDigest, seqNr uint64, r ocrtypes.Report, signature []byte) bool { + hash, err := skr.reportToSigData3(cd, seqNr, r) + if err != nil { + return false + } + return skr.VerifyBlob(publicKey, hash, signature) +} + +func (skr *solanaKeyring) VerifyBlob(pubkey types.OnchainPublicKey, b, sig []byte) bool { + authorPubkey, err := crypto.SigToPub(b, sig) + if err != nil { + return false + } + authorAddress := crypto.PubkeyToAddress(*authorPubkey) + // no need for constant time compare since neither arg is sensitive + return bytes.Equal(pubkey[:], authorAddress[:]) +} + +func (skr *solanaKeyring) MaxSignatureLength() int { + return 65 +} + +func (skr *solanaKeyring) Marshal() ([]byte, error) { + return crypto.FromECDSA(skr.privateKey()), nil +} + +func (skr *solanaKeyring) Unmarshal(in []byte) error { + privateKey, err := crypto.ToECDSA(in) + skr.privateKey = func() *ecdsa.PrivateKey { return privateKey } + return err +} diff --git a/keystore/corekeys/ocr2key/solana_keyring_test.go b/keystore/corekeys/ocr2key/solana_keyring_test.go new file mode 100644 index 0000000000..e391848a4b --- /dev/null +++ b/keystore/corekeys/ocr2key/solana_keyring_test.go @@ -0,0 +1,55 @@ +package ocr2key + +import ( + "bytes" + cryptorand "crypto/rand" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + ocrtypes "github.com/smartcontractkit/libocr/offchainreporting2plus/types" +) + +func TestSolanaKeyring_Sign_Verify(t *testing.T) { + kr1, err := newSolanaKeyring(cryptorand.Reader) + require.NoError(t, err) + kr2, err := newSolanaKeyring(cryptorand.Reader) + require.NoError(t, err) + ctx := ocrtypes.ReportContext{} + + t.Run("can verify", func(t *testing.T) { + report := ocrtypes.Report{} + sig, err := kr1.Sign(ctx, report) + require.NoError(t, err) + t.Log(len(sig)) + result := kr2.Verify(kr1.PublicKey(), ctx, report, sig) + assert.True(t, result) + }) + + t.Run("invalid sig", func(t *testing.T) { + report := ocrtypes.Report{} + result := kr2.Verify(kr1.PublicKey(), ctx, report, []byte{0x01}) + assert.False(t, result) + }) + + t.Run("invalid pubkey", func(t *testing.T) { + report := ocrtypes.Report{} + sig, err := kr1.Sign(ctx, report) + require.NoError(t, err) + result := kr2.Verify([]byte{0x01}, ctx, report, sig) + assert.False(t, result) + }) +} + +func TestSolanaKeyring_Marshalling(t *testing.T) { + kr1, err := newSolanaKeyring(cryptorand.Reader) + require.NoError(t, err) + m, err := kr1.Marshal() + require.NoError(t, err) + kr2 := solanaKeyring{} + err = kr2.Unmarshal(m) + require.NoError(t, err) + assert.True(t, bytes.Equal(kr1.PublicKey(), kr2.PublicKey())) + assert.True(t, bytes.Equal(kr1.privateKey().D.Bytes(), kr2.privateKey().D.Bytes())) +} diff --git a/keystore/corekeys/ocr2key/ton_keyring.go b/keystore/corekeys/ocr2key/ton_keyring.go new file mode 100644 index 0000000000..f819c04660 --- /dev/null +++ b/keystore/corekeys/ocr2key/ton_keyring.go @@ -0,0 +1,120 @@ +package ocr2key + +import ( + "crypto/ed25519" + "crypto/sha256" + "io" + + "github.com/hdevalence/ed25519consensus" + "github.com/pkg/errors" + "github.com/xssnick/tonutils-go/tvm/cell" + + "github.com/smartcontractkit/chainlink/v2/core/utils" + + "github.com/smartcontractkit/libocr/offchainreporting2/types" + "github.com/smartcontractkit/libocr/offchainreporting2plus/chains/evmutil" + ocrtypes "github.com/smartcontractkit/libocr/offchainreporting2plus/types" +) + +var _ ocrtypes.OnchainKeyring = &tonKeyring{} + +type tonKeyring struct { + privKey func() ed25519.PrivateKey + pubKey ed25519.PublicKey +} + +func newTONKeyring(material io.Reader) (*tonKeyring, error) { + pubKey, privKey, err := ed25519.GenerateKey(material) + if err != nil { + return nil, err + } + return &tonKeyring{pubKey: pubKey, privKey: func() ed25519.PrivateKey { return privKey }}, nil +} + +func (tkr *tonKeyring) PublicKey() ocrtypes.OnchainPublicKey { + return []byte(tkr.pubKey) +} + +func (tkr *tonKeyring) reportToSigData(reportCtx ocrtypes.ReportContext, report ocrtypes.Report) []byte { + rawReportContext := evmutil.RawReportContext(reportCtx) + h := sha256.New() + h.Write([]byte{uint8(len(report))}) //nolint:gosec // assumes len(report) < 256 + h.Write(report) + h.Write(rawReportContext[0][:]) + h.Write(rawReportContext[1][:]) + h.Write(rawReportContext[2][:]) + return h.Sum(nil) +} + +func (tkr *tonKeyring) Sign(reportCtx ocrtypes.ReportContext, report ocrtypes.Report) ([]byte, error) { + sigData := tkr.reportToSigData(reportCtx, report) + return tkr.SignBlob(sigData) +} + +func (tkr *tonKeyring) Sign3(digest types.ConfigDigest, seqNr uint64, r ocrtypes.Report) ([]byte, error) { + bytes := tkr.reportToSigData3(digest, seqNr, r) + return tkr.SignBlob(bytes) +} + +func (tkr *tonKeyring) reportToSigData3(digest types.ConfigDigest, seqNr uint64, report ocrtypes.Report) []byte { + rawReportContext := RawReportContext3(digest, seqNr) + + reportCell, err := cell.FromBOC(report) + if err != nil { + panic(err) + } + + return cell.BeginCell(). + MustStoreRef(reportCell). + MustStoreSlice(rawReportContext[0][:], 256). + MustStoreSlice(rawReportContext[1][:], 256). + EndCell(). + Hash() +} + +func (tkr *tonKeyring) SignBlob(b []byte) ([]byte, error) { + sig := ed25519.Sign(tkr.privKey(), b) + return utils.ConcatBytes(tkr.PublicKey(), sig), nil +} + +func (tkr *tonKeyring) Verify(publicKey ocrtypes.OnchainPublicKey, reportCtx ocrtypes.ReportContext, report ocrtypes.Report, signature []byte) bool { + hash := tkr.reportToSigData(reportCtx, report) + return tkr.VerifyBlob(publicKey, hash, signature) +} + +func (tkr *tonKeyring) Verify3(publicKey ocrtypes.OnchainPublicKey, cd ocrtypes.ConfigDigest, seqNr uint64, r ocrtypes.Report, signature []byte) bool { + hash := tkr.reportToSigData3(cd, seqNr, r) + return tkr.VerifyBlob(publicKey, hash, signature) +} + +func (tkr *tonKeyring) VerifyBlob(pubkey ocrtypes.OnchainPublicKey, b, sig []byte) bool { + if len(sig) != tkr.MaxSignatureLength() { + return false + } + if len(pubkey) != ed25519.PublicKeySize { + return false + } + return ed25519consensus.Verify(ed25519.PublicKey(pubkey), b, sig[32:]) +} + +func (tkr *tonKeyring) MaxSignatureLength() int { + return ed25519.PublicKeySize + ed25519.SignatureSize // 32 + 64 +} + +func (tkr *tonKeyring) Marshal() ([]byte, error) { + return tkr.privKey().Seed(), nil +} + +func (tkr *tonKeyring) Unmarshal(in []byte) error { + if len(in) != ed25519.SeedSize { + return errors.Errorf("unexpected seed size, got %d want %d", len(in), ed25519.SeedSize) + } + privKey := ed25519.NewKeyFromSeed(in) + tkr.privKey = func() ed25519.PrivateKey { return privKey } + pubKey, ok := privKey.Public().(ed25519.PublicKey) + if !ok { + return errors.New("failed to cast public key to ed25519.PublicKey") + } + tkr.pubKey = pubKey + return nil +} diff --git a/keystore/corekeys/ocr2key/ton_keyring_test.go b/keystore/corekeys/ocr2key/ton_keyring_test.go new file mode 100644 index 0000000000..32890a979f --- /dev/null +++ b/keystore/corekeys/ocr2key/ton_keyring_test.go @@ -0,0 +1,95 @@ +package ocr2key + +import ( + "bytes" + cryptorand "crypto/rand" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "github.com/xssnick/tonutils-go/tvm/cell" + + ocrtypes "github.com/smartcontractkit/libocr/offchainreporting2plus/types" +) + +func TestTONKeyring_Sign_Verify(t *testing.T) { + kr1, err := newTONKeyring(cryptorand.Reader) + require.NoError(t, err) + kr2, err := newTONKeyring(cryptorand.Reader) + require.NoError(t, err) + ctx := ocrtypes.ReportContext{} + + t.Run("can verify", func(t *testing.T) { + report := ocrtypes.Report{} + sig, err := kr1.Sign(ctx, report) + require.NoError(t, err) + t.Log(len(sig)) + result := kr2.Verify(kr1.PublicKey(), ctx, report, sig) + assert.True(t, result) + }) + + t.Run("invalid sig", func(t *testing.T) { + report := ocrtypes.Report{} + result := kr2.Verify(kr1.PublicKey(), ctx, report, []byte{0x01}) + assert.False(t, result) + }) + + t.Run("invalid pubkey", func(t *testing.T) { + report := ocrtypes.Report{} + sig, err := kr1.Sign(ctx, report) + require.NoError(t, err) + result := kr2.Verify([]byte{0x01}, ctx, report, sig) + assert.False(t, result) + }) +} + +func TestTONKeyring_Sign3_Verify3(t *testing.T) { + kr1, err := newTONKeyring(cryptorand.Reader) + require.NoError(t, err) + kr2, err := newTONKeyring(cryptorand.Reader) + require.NoError(t, err) + digest := ocrtypes.ConfigDigest{} + + t.Run("can verify", func(t *testing.T) { + report := cell.BeginCell().EndCell().ToBOC() + seqNr := uint64(1) + sig, err := kr1.Sign3(digest, 1, report) + require.NoError(t, err) + t.Log(len(sig)) + + result := kr2.Verify3(kr1.PublicKey(), digest, seqNr, report, sig) + assert.True(t, result) + }) + + t.Run("invalid sig", func(t *testing.T) { + report := cell.BeginCell().EndCell().ToBOC() + seqNr := uint64(1) + result := kr2.Verify3(kr1.PublicKey(), digest, seqNr, report, []byte{0x01}) + assert.False(t, result) + }) + + t.Run("invalid pubkey", func(t *testing.T) { + report := cell.BeginCell().EndCell().ToBOC() + seqNr := uint64(1) + sig, err := kr1.Sign3(digest, 1, report) + require.NoError(t, err) + + result := kr2.Verify3([]byte{0x01}, digest, seqNr, report, sig) + assert.False(t, result) + }) +} + +func TestTONKeyring_Marshalling(t *testing.T) { + kr1, err := newEd25519Keyring(cryptorand.Reader) + require.NoError(t, err) + m, err := kr1.Marshal() + require.NoError(t, err) + kr2 := ed25519Keyring{} + err = kr2.Unmarshal(m) + require.NoError(t, err) + assert.True(t, bytes.Equal(kr1.pubKey, kr2.pubKey)) + assert.True(t, bytes.Equal(kr1.privKey(), kr2.privKey())) + + // Invalid seed size should error + require.Error(t, kr2.Unmarshal([]byte{0x01})) +} diff --git a/keystore/corekeys/ocrkey/config_public_key.go b/keystore/corekeys/ocrkey/config_public_key.go new file mode 100644 index 0000000000..13e85b7793 --- /dev/null +++ b/keystore/corekeys/ocrkey/config_public_key.go @@ -0,0 +1,72 @@ +package ocrkey + +import ( + "database/sql/driver" + "encoding/hex" + "encoding/json" + "fmt" + "strings" + + "github.com/pkg/errors" + "golang.org/x/crypto/curve25519" +) + +const configPublicKeyPrefix = "ocrcfg_" + +// ConfigPublicKey represents the public key for the config decryption keypair +type ConfigPublicKey [curve25519.PointSize]byte + +func (cpk ConfigPublicKey) String() string { + return fmt.Sprintf("%s%s", configPublicKeyPrefix, cpk.Raw()) +} + +func (cpk ConfigPublicKey) Raw() string { + return hex.EncodeToString(cpk[:]) +} + +func (cpk ConfigPublicKey) MarshalJSON() ([]byte, error) { + return json.Marshal(cpk.String()) +} + +func (cpk *ConfigPublicKey) UnmarshalJSON(input []byte) error { + var hexString string + if err := json.Unmarshal(input, &hexString); err != nil { + return err + } + + return cpk.UnmarshalText([]byte(hexString)) +} + +// Scan reads the database value and returns an instance. +func (cpk *ConfigPublicKey) Scan(value any) error { + b, ok := value.([]byte) + if !ok { + return errors.Errorf("unable to convert %v of type %T to ConfigPublicKey", value, value) + } + if len(b) != curve25519.PointSize { + return errors.Errorf("unable to convert blob 0x%x of length %v to ConfigPublicKey", b, len(b)) + } + copy(cpk[:], b) + return nil +} + +// Value returns this instance serialized for database storage. +func (cpk ConfigPublicKey) Value() (driver.Value, error) { + return cpk[:], nil +} + +func (cpk *ConfigPublicKey) UnmarshalText(bs []byte) error { + input := string(bs) + if strings.HasPrefix(input, configPublicKeyPrefix) { + input = string(bs[len(configPublicKeyPrefix):]) + } + + decodedString, err := hex.DecodeString(input) + if err != nil { + return err + } + var result [curve25519.PointSize]byte + copy(result[:], decodedString[:curve25519.PointSize]) + *cpk = result + return nil +} diff --git a/keystore/corekeys/ocrkey/config_public_key_test.go b/keystore/corekeys/ocrkey/config_public_key_test.go new file mode 100644 index 0000000000..f3d257bd1f --- /dev/null +++ b/keystore/corekeys/ocrkey/config_public_key_test.go @@ -0,0 +1,42 @@ +package ocrkey + +import ( + "math/big" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestOCRKey_ConfigPublicKey(t *testing.T) { + k := MustNewV2XXXTestingOnly(big.NewInt(1)) + + t.Run("fails to unmarshal invalid JSON", func(t *testing.T) { + pk := ConfigPublicKey(k.PublicKeyConfig()) + + err := pk.UnmarshalJSON([]byte("")) + + assert.Error(t, err) + }) + + t.Run("returns serialized instance value", func(t *testing.T) { + pk := ConfigPublicKey(k.PublicKeyConfig()) + + v, err := pk.Value() + require.NoError(t, err) + + assert.NotEmpty(t, v) + }) + + t.Run("updates current instance by scanning another instance", func(t *testing.T) { + pk := ConfigPublicKey(k.PublicKeyConfig()) + + k2 := MustNewV2XXXTestingOnly(big.NewInt(1)) + pk2 := ConfigPublicKey(k2.PublicKeyConfig()) + + err := pk.Scan(pk2[:]) + require.NoError(t, err) + + assert.Equal(t, pk2.Raw(), pk.Raw()) + }) +} diff --git a/keystore/corekeys/ocrkey/export.go b/keystore/corekeys/ocrkey/export.go new file mode 100644 index 0000000000..a9c9c884bb --- /dev/null +++ b/keystore/corekeys/ocrkey/export.go @@ -0,0 +1,59 @@ +package ocrkey + +import ( + "github.com/ethereum/go-ethereum/accounts/keystore" + + "github.com/smartcontractkit/chainlink-common/keystore/internal" + "github.com/smartcontractkit/chainlink-common/keystore/scrypt" +) + +const keyTypeIdentifier = "OCR" + +func FromEncryptedJSON(keyJSON []byte, password string) (KeyV2, error) { + return internal.FromEncryptedJSON( + keyTypeIdentifier, + keyJSON, + password, + adulteratedPassword, + func(_ EncryptedOCRKeyExport, rawPrivKey internal.Raw) (KeyV2, error) { + return KeyFor(rawPrivKey), nil + }, + ) +} + +type EncryptedOCRKeyExport struct { + KeyType string `json:"keyType"` + ID string `json:"id"` + OnChainSigningAddress OnChainSigningAddress `json:"onChainSigningAddress"` + OffChainPublicKey OffChainPublicKey `json:"offChainPublicKey"` + ConfigPublicKey ConfigPublicKey `json:"configPublicKey"` + Crypto keystore.CryptoJSON `json:"crypto"` +} + +func (x EncryptedOCRKeyExport) GetCrypto() keystore.CryptoJSON { + return x.Crypto +} + +func (key KeyV2) ToEncryptedJSON(password string, scryptParams scrypt.ScryptParams) (export []byte, err error) { + return internal.ToEncryptedJSON( + keyTypeIdentifier, + key, + password, + scryptParams, + adulteratedPassword, + func(id string, key KeyV2, cryptoJSON keystore.CryptoJSON) EncryptedOCRKeyExport { + return EncryptedOCRKeyExport{ + KeyType: id, + ID: key.ID(), + OnChainSigningAddress: key.OnChainSigning.Address(), + OffChainPublicKey: key.OffChainSigning.PublicKey(), + ConfigPublicKey: key.PublicKeyConfig(), + Crypto: cryptoJSON, + } + }, + ) +} + +func adulteratedPassword(password string) string { + return "ocrkey" + password +} diff --git a/keystore/corekeys/ocrkey/export_test.go b/keystore/corekeys/ocrkey/export_test.go new file mode 100644 index 0000000000..261c3118e8 --- /dev/null +++ b/keystore/corekeys/ocrkey/export_test.go @@ -0,0 +1,17 @@ +package ocrkey + +import ( + "testing" +) + +func TestOCRKeys_ExportImport(t *testing.T) { + corekeys2.RunKeyExportImportTestcase(t, createKey, decryptKey) +} + +func createKey() (corekeys2.KeyType, error) { + return NewV2() +} + +func decryptKey(keyJSON []byte, password string) (corekeys2.KeyType, error) { + return FromEncryptedJSON(keyJSON, password) +} diff --git a/keystore/corekeys/ocrkey/helpers_test.go b/keystore/corekeys/ocrkey/helpers_test.go new file mode 100644 index 0000000000..9634d72177 --- /dev/null +++ b/keystore/corekeys/ocrkey/helpers_test.go @@ -0,0 +1,13 @@ +package ocrkey + +func (kb *KeyV2) ExportedOnChainSigning() *onChainPrivateKey { + return kb.OnChainSigning +} + +func (kb *KeyV2) ExportedOffChainSigning() *offChainPrivateKey { + return kb.OffChainSigning +} + +func (kb *KeyV2) ExportedOffChainEncryption() *[32]byte { + return kb.OffChainEncryption +} diff --git a/keystore/corekeys/ocrkey/key_v2.go b/keystore/corekeys/ocrkey/key_v2.go new file mode 100644 index 0000000000..ff23c8e217 --- /dev/null +++ b/keystore/corekeys/ocrkey/key_v2.go @@ -0,0 +1,190 @@ +package ocrkey + +import ( + "crypto/ecdsa" + "crypto/ed25519" + "crypto/rand" + "crypto/sha256" + "encoding/hex" + "encoding/json" + "log" + "math/big" + + "github.com/ethereum/go-ethereum/crypto/secp256k1" + "github.com/pkg/errors" + "golang.org/x/crypto/curve25519" + + ocrtypes "github.com/smartcontractkit/libocr/offchainreporting/types" + + "github.com/smartcontractkit/chainlink-common/keystore/internal" +) + +var ( + ErrScalarTooBig = errors.Errorf("can't handle scalars greater than %d", curve25519.PointSize) + curve = secp256k1.S256() +) + +type keyBundleRawData struct { + EcdsaD big.Int + Ed25519PrivKey []byte + OffChainEncryption [curve25519.ScalarSize]byte +} + +func KeyFor(raw internal.Raw) KeyV2 { + var key KeyV2 + err := json.Unmarshal(internal.Bytes(raw), &key) + if err != nil { + panic(errors.Wrap(err, "while unmarshalling OCR key")) + } + key.raw = raw + return key +} + +type KeyV2 struct { + raw internal.Raw + OnChainSigning *onChainPrivateKey + OffChainSigning *offChainPrivateKey + OffChainEncryption *[curve25519.ScalarSize]byte +} + +func NewV2() (KeyV2, error) { + ecdsaKey, err := ecdsa.GenerateKey(curve, rand.Reader) + if err != nil { + return KeyV2{}, err + } + + _, offChainPriv, err := ed25519.GenerateKey(rand.Reader) + if err != nil { + return KeyV2{}, err + } + var encryptionPriv [curve25519.ScalarSize]byte + _, err = rand.Reader.Read(encryptionPriv[:]) + if err != nil { + return KeyV2{}, err + } + k := KeyV2{ + OnChainSigning: &onChainPrivateKey{func() *ecdsa.PrivateKey { return ecdsaKey }}, + OffChainSigning: &offChainPrivateKey{func() ed25519.PrivateKey { return offChainPriv }}, + OffChainEncryption: &encryptionPriv, + } + return k, k.initRaw() +} + +func MustNewV2XXXTestingOnly(k *big.Int) KeyV2 { + ecdsaKey := new(ecdsa.PrivateKey) + ecdsaKey.Curve = curve + ecdsaKey.D = k + ecdsaKey.X, ecdsaKey.Y = curve.ScalarBaseMult(k.Bytes()) + var seed [32]byte + copy(seed[:], k.Bytes()) + offChainPriv := ed25519.NewKeyFromSeed(seed[:]) + key := KeyV2{ + OnChainSigning: &onChainPrivateKey{func() *ecdsa.PrivateKey { return ecdsaKey }}, + OffChainSigning: &offChainPrivateKey{func() ed25519.PrivateKey { return offChainPriv }}, + OffChainEncryption: &seed, + } + if err := key.initRaw(); err != nil { + panic(err) + } + return key +} + +func (key KeyV2) ID() string { + sha := sha256.Sum256(internal.Bytes(key.raw)) + return hex.EncodeToString(sha[:]) +} + +func (key KeyV2) Raw() internal.Raw { return key.raw } + +func (key *KeyV2) initRaw() error { + marshalledPrivK, err := json.Marshal(key) + if err != nil { + return err + } + key.raw = internal.NewRaw(marshalledPrivK) + return nil +} + +// SignOnChain returns an ethereum-style ECDSA secp256k1 signature on msg. +func (key KeyV2) SignOnChain(msg []byte) (signature []byte, err error) { + return key.OnChainSigning.Sign(msg) +} + +// SignOffChain returns an EdDSA-Ed25519 signature on msg. +func (key KeyV2) SignOffChain(msg []byte) (signature []byte, err error) { + return key.OffChainSigning.Sign(msg) +} + +// ConfigDiffieHellman returns the shared point obtained by multiplying someone's +// public key by a secret scalar ( in this case, the OffChainEncryption key.) +func (key KeyV2) ConfigDiffieHellman(base *[curve25519.PointSize]byte) ( + sharedPoint *[curve25519.PointSize]byte, err error, +) { + p, err := curve25519.X25519(key.OffChainEncryption[:], base[:]) + if err != nil { + return nil, err + } + sharedPoint = new([ed25519.PublicKeySize]byte) + copy(sharedPoint[:], p) + return sharedPoint, nil +} + +// PublicKeyAddressOnChain returns public component of the keypair used in +// SignOnChain +func (key KeyV2) PublicKeyAddressOnChain() ocrtypes.OnChainSigningAddress { + return ocrtypes.OnChainSigningAddress(key.OnChainSigning.Address()) +} + +// PublicKeyOffChain returns the public component of the keypair used in SignOffChain +func (key KeyV2) PublicKeyOffChain() ocrtypes.OffchainPublicKey { + return ocrtypes.OffchainPublicKey(key.OffChainSigning.PublicKey()) +} + +// PublicKeyConfig returns the public component of the keypair used in ConfigKeyShare +func (key KeyV2) PublicKeyConfig() [curve25519.PointSize]byte { + rv, err := curve25519.X25519(key.OffChainEncryption[:], curve25519.Basepoint) + if err != nil { + log.Println("failure while computing public key: " + err.Error()) + } + var rvFixed [curve25519.PointSize]byte + copy(rvFixed[:], rv) + return rvFixed +} + +func (key KeyV2) GetID() string { + return key.ID() +} + +// MarshalJSON marshals the private keys into json +func (key KeyV2) MarshalJSON() ([]byte, error) { + rawKeyData := keyBundleRawData{ + EcdsaD: *key.OnChainSigning.pk().D, + Ed25519PrivKey: []byte(key.OffChainSigning.pk()), + OffChainEncryption: *key.OffChainEncryption, + } + return json.Marshal(&rawKeyData) +} + +func (key *KeyV2) UnmarshalJSON(b []byte) (err error) { + var rawKeyData keyBundleRawData + err = json.Unmarshal(b, &rawKeyData) + if err != nil { + return err + } + ecdsaDSize := len(rawKeyData.EcdsaD.Bytes()) + if ecdsaDSize > curve25519.PointSize { + return errors.Wrapf(ErrScalarTooBig, "got %d byte ecdsa scalar", ecdsaDSize) + } + + publicKey := ecdsa.PublicKey{Curve: curve} + publicKey.X, publicKey.Y = curve.ScalarBaseMult(rawKeyData.EcdsaD.Bytes()) + privateKey := ecdsa.PrivateKey{ + PublicKey: publicKey, + D: &rawKeyData.EcdsaD, + } + + key.OnChainSigning = &onChainPrivateKey{func() *ecdsa.PrivateKey { return &privateKey }} + key.OffChainSigning = &offChainPrivateKey{func() ed25519.PrivateKey { return rawKeyData.Ed25519PrivKey }} + key.OffChainEncryption = &rawKeyData.OffChainEncryption + return nil +} diff --git a/keystore/corekeys/ocrkey/key_v2_test.go b/keystore/corekeys/ocrkey/key_v2_test.go new file mode 100644 index 0000000000..7457c19840 --- /dev/null +++ b/keystore/corekeys/ocrkey/key_v2_test.go @@ -0,0 +1,37 @@ +package ocrkey_test + +import ( + "math/big" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + "github.com/smartcontractkit/chainlink-common/keystore/internal" + "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/ocrkey" +) + +func assertKeyBundlesNotEqual(t *testing.T, pk1 ocrkey.KeyV2, pk2 ocrkey.KeyV2) { + assert.NotEqual(t, pk1.ID(), pk2.ID()) + assert.NotEqual(t, internal.RawBytes(pk1), internal.RawBytes(pk2)) + assert.NotEqual(t, pk1.ExportedOffChainSigning().PublicKey(), pk2.ExportedOffChainSigning().PublicKey()) + assert.NotEqual(t, pk1.ExportedOffChainEncryption(), pk2.ExportedOffChainEncryption()) +} + +func TestOCRKeys_New(t *testing.T) { + t.Parallel() + pk1, err := ocrkey.NewV2() + require.NoError(t, err) + pk2, err := ocrkey.NewV2() + require.NoError(t, err) + pk3, err := ocrkey.NewV2() + require.NoError(t, err) + assertKeyBundlesNotEqual(t, pk1, pk2) + assertKeyBundlesNotEqual(t, pk1, pk3) + assertKeyBundlesNotEqual(t, pk2, pk3) +} +func TestOCRKeys_Raw_Key(t *testing.T) { + t.Parallel() + key := ocrkey.MustNewV2XXXTestingOnly(big.NewInt(1)) + require.Equal(t, key.ID(), ocrkey.KeyFor(key.Raw()).ID()) +} diff --git a/keystore/corekeys/ocrkey/off_chain_private_key.go b/keystore/corekeys/ocrkey/off_chain_private_key.go new file mode 100644 index 0000000000..413ad13e3f --- /dev/null +++ b/keystore/corekeys/ocrkey/off_chain_private_key.go @@ -0,0 +1,24 @@ +package ocrkey + +import ( + "crypto/ed25519" + + "github.com/pkg/errors" +) + +type offChainPrivateKey struct { + pk func() ed25519.PrivateKey +} + +// Sign returns the signature on msgHash with k +func (k *offChainPrivateKey) Sign(msg []byte) ([]byte, error) { + if k == nil { + return nil, errors.Errorf("attempt to sign with nil key") + } + return ed25519.Sign(k.pk(), msg), nil +} + +// PublicKey returns the public key which commits to k +func (k *offChainPrivateKey) PublicKey() OffChainPublicKey { + return OffChainPublicKey(k.pk().Public().(ed25519.PublicKey)) +} diff --git a/keystore/corekeys/ocrkey/off_chain_private_key_test.go b/keystore/corekeys/ocrkey/off_chain_private_key_test.go new file mode 100644 index 0000000000..a7eadc7286 --- /dev/null +++ b/keystore/corekeys/ocrkey/off_chain_private_key_test.go @@ -0,0 +1,20 @@ +package ocrkey + +import ( + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestOCRKeys_OffChainPrivateKey(t *testing.T) { + t.Parallel() + + k, err := NewV2() + require.NoError(t, err) + + sig, err := k.OffChainSigning.Sign([]byte("hello world")) + + assert.NoError(t, err) + assert.NotEmpty(t, sig) +} diff --git a/keystore/corekeys/ocrkey/off_chain_public_key.go b/keystore/corekeys/ocrkey/off_chain_public_key.go new file mode 100644 index 0000000000..de190f68f7 --- /dev/null +++ b/keystore/corekeys/ocrkey/off_chain_public_key.go @@ -0,0 +1,67 @@ +package ocrkey + +import ( + "crypto/ed25519" + "database/sql/driver" + "encoding/hex" + "encoding/json" + "fmt" + "strings" + + "github.com/pkg/errors" + + "github.com/ethereum/go-ethereum/common" +) + +const offChainPublicKeyPrefix = "ocroff_" + +type OffChainPublicKey ed25519.PublicKey + +func (ocpk OffChainPublicKey) String() string { + return fmt.Sprintf("%s%s", offChainPublicKeyPrefix, ocpk.Raw()) +} + +func (ocpk OffChainPublicKey) Raw() string { + return hex.EncodeToString(ocpk) +} + +func (ocpk OffChainPublicKey) MarshalJSON() ([]byte, error) { + return json.Marshal(ocpk.String()) +} + +func (ocpk *OffChainPublicKey) UnmarshalJSON(input []byte) error { + var hexString string + if err := json.Unmarshal(input, &hexString); err != nil { + return err + } + return ocpk.UnmarshalText([]byte(hexString)) +} + +func (ocpk *OffChainPublicKey) UnmarshalText(bs []byte) error { + input := string(bs) + if strings.HasPrefix(input, offChainPublicKeyPrefix) { + input = string(bs[len(offChainPublicKeyPrefix):]) + } + + result, err := hex.DecodeString(input) + if err != nil { + return err + } + copy(result, result[:common.AddressLength]) + *ocpk = result + return nil +} + +func (ocpk *OffChainPublicKey) Scan(value any) error { + switch v := value.(type) { + case []byte: + *ocpk = v + return nil + default: + return errors.Errorf("invalid public key bytes got %T wanted []byte", v) + } +} + +func (ocpk OffChainPublicKey) Value() (driver.Value, error) { + return []byte(ocpk), nil +} diff --git a/keystore/corekeys/ocrkey/off_chain_public_key_test.go b/keystore/corekeys/ocrkey/off_chain_public_key_test.go new file mode 100644 index 0000000000..372ca8b273 --- /dev/null +++ b/keystore/corekeys/ocrkey/off_chain_public_key_test.go @@ -0,0 +1,48 @@ +package ocrkey_test + +import ( + "encoding/json" + "fmt" + "testing" + + "github.com/stretchr/testify/assert" + + "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/ocrkey" +) + +func TestOCR_OffchainPublicKey_MarshalJSON(t *testing.T) { + t.Parallel() + rawBytes := make([]byte, 32) + rawBytes[31] = 1 + pubKey := ocrkey.OffChainPublicKey(rawBytes) + + pubKeyString := "ocroff_0000000000000000000000000000000000000000000000000000000000000001" + pubKeyJSON := fmt.Sprintf(`"%s"`, pubKeyString) + + result, err := json.Marshal(pubKey) + assert.NoError(t, err) + assert.JSONEq(t, pubKeyJSON, string(result)) +} + +func TestOCR_OffchainPublicKey_UnmarshalJSON_Happy(t *testing.T) { + t.Parallel() + + pubKeyString := "918a65a518c005d6367309bec4b26805f8afabef72cbf9940d9a0fd04ec80b38" + pubKeyJSON := fmt.Sprintf(`"%s"`, pubKeyString) + pubKey := ocrkey.OffChainPublicKey{} + + err := json.Unmarshal([]byte(pubKeyJSON), &pubKey) + assert.NoError(t, err) + assert.Equal(t, pubKeyString, pubKey.Raw()) +} + +func TestOCR_OffchainPublicKey_UnmarshalJSON_Error(t *testing.T) { + t.Parallel() + + pubKeyString := "hello world" + pubKeyJSON := fmt.Sprintf(`"%s"`, pubKeyString) + pubKey := ocrkey.OffChainPublicKey{} + + err := json.Unmarshal([]byte(pubKeyJSON), &pubKey) + assert.Error(t, err) +} diff --git a/keystore/corekeys/ocrkey/on_chain_private_key.go b/keystore/corekeys/ocrkey/on_chain_private_key.go new file mode 100644 index 0000000000..a87b0842d1 --- /dev/null +++ b/keystore/corekeys/ocrkey/on_chain_private_key.go @@ -0,0 +1,25 @@ +package ocrkey + +import ( + "crypto/ecdsa" + + "github.com/ethereum/go-ethereum/crypto" +) + +type onChainPrivateKey struct { + pk func() *ecdsa.PrivateKey +} + +// Sign returns the signature on msgHash with k +func (k *onChainPrivateKey) Sign(msg []byte) (signature []byte, err error) { + sig, err := crypto.Sign(onChainHash(msg), k.pk()) + return sig, err +} + +func (k onChainPrivateKey) Address() OnChainSigningAddress { + return OnChainSigningAddress(crypto.PubkeyToAddress(k.pk().PublicKey)) +} + +func onChainHash(msg []byte) []byte { + return crypto.Keccak256(msg) +} diff --git a/keystore/corekeys/ocrkey/on_chain_private_key_test.go b/keystore/corekeys/ocrkey/on_chain_private_key_test.go new file mode 100644 index 0000000000..8613eb1d40 --- /dev/null +++ b/keystore/corekeys/ocrkey/on_chain_private_key_test.go @@ -0,0 +1,25 @@ +package ocrkey + +import ( + "crypto/ecdsa" + "crypto/rand" + "testing" + + "github.com/ethereum/go-ethereum/crypto" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestOCRKeys_OnChainPrivateKey(t *testing.T) { + t.Parallel() + + pk, err := ecdsa.GenerateKey(crypto.S256(), rand.Reader) + require.NoError(t, err) + + k := onChainPrivateKey{func() *ecdsa.PrivateKey { return pk }} + + sig, err := k.Sign([]byte("hello world")) + + assert.NoError(t, err) + assert.NotEmpty(t, sig) +} diff --git a/keystore/corekeys/ocrkey/on_chain_public_key.go b/keystore/corekeys/ocrkey/on_chain_public_key.go new file mode 100644 index 0000000000..90f54e39cd --- /dev/null +++ b/keystore/corekeys/ocrkey/on_chain_public_key.go @@ -0,0 +1,13 @@ +package ocrkey + +import ( + "crypto/ecdsa" + + "github.com/ethereum/go-ethereum/crypto" +) + +type OnChainPublicKey ecdsa.PublicKey + +func (k OnChainPublicKey) Address() OnChainSigningAddress { + return OnChainSigningAddress(crypto.PubkeyToAddress(ecdsa.PublicKey(k))) +} diff --git a/keystore/corekeys/ocrkey/on_chain_public_key_test.go b/keystore/corekeys/ocrkey/on_chain_public_key_test.go new file mode 100644 index 0000000000..2828fd74db --- /dev/null +++ b/keystore/corekeys/ocrkey/on_chain_public_key_test.go @@ -0,0 +1,22 @@ +package ocrkey + +import ( + "crypto/ecdsa" + "crypto/rand" + "testing" + + "github.com/ethereum/go-ethereum/crypto" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestOCRKeys_OnChainPublicKey(t *testing.T) { + t.Parallel() + + pk, err := ecdsa.GenerateKey(crypto.S256(), rand.Reader) + require.NoError(t, err) + + publicKey := OnChainPublicKey(pk.PublicKey) + + assert.NotEmpty(t, publicKey.Address()) +} diff --git a/keystore/corekeys/ocrkey/on_chain_signing_address.go b/keystore/corekeys/ocrkey/on_chain_signing_address.go new file mode 100644 index 0000000000..871469c93d --- /dev/null +++ b/keystore/corekeys/ocrkey/on_chain_signing_address.go @@ -0,0 +1,69 @@ +package ocrkey + +import ( + "database/sql/driver" + "encoding/json" + "fmt" + "strings" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/hexutil" + "github.com/pkg/errors" + ocrtypes "github.com/smartcontractkit/libocr/offchainreporting/types" +) + +const onChainSigningAddressPrefix = "ocrsad_" + +type OnChainSigningAddress ocrtypes.OnChainSigningAddress + +func (ocsa OnChainSigningAddress) String() string { + address := common.BytesToAddress(ocsa[:]) + return fmt.Sprintf("%s%s", onChainSigningAddressPrefix, address) +} + +func (ocsa OnChainSigningAddress) MarshalJSON() ([]byte, error) { + return json.Marshal(ocsa.String()) +} + +func (ocsa *OnChainSigningAddress) UnmarshalJSON(input []byte) error { + var hexString string + if err := json.Unmarshal(input, &hexString); err != nil { + return err + } + return ocsa.UnmarshalText([]byte(hexString)) +} + +func (ocsa *OnChainSigningAddress) UnmarshalText(bs []byte) error { + input := string(bs) + if strings.HasPrefix(input, onChainSigningAddressPrefix) { + input = string(bs[len(onChainSigningAddressPrefix):]) + } + + result, err := hexutil.Decode(input) + if err != nil { + return err + } + + var onChainSigningAddress common.Address + copy(onChainSigningAddress[:], result[:common.AddressLength]) + *ocsa = OnChainSigningAddress(onChainSigningAddress) + return nil +} + +func (ocsa OnChainSigningAddress) Value() (driver.Value, error) { + byteArray := [common.AddressLength]byte(ocsa) + return byteArray[:], nil +} + +func (ocsa *OnChainSigningAddress) Scan(value any) error { + switch typed := value.(type) { + case []byte: + if len(typed) != common.AddressLength { + return errors.New("wrong number of bytes to scan into address") + } + copy(ocsa[:], typed) + return nil + default: + return errors.Errorf(`unable to convert %v of %T to OnChainSigningAddress`, value, value) + } +} diff --git a/keystore/corekeys/ocrkey/on_chain_signing_address_test.go b/keystore/corekeys/ocrkey/on_chain_signing_address_test.go new file mode 100644 index 0000000000..e45da17f03 --- /dev/null +++ b/keystore/corekeys/ocrkey/on_chain_signing_address_test.go @@ -0,0 +1,25 @@ +package ocrkey_test + +import ( + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/ocrkey" +) + +func TestOCR_OnChainSigningAddress_String(t *testing.T) { + t.Parallel() + + // should contain EIP55CapitalizedAddress + const ocrSigningKey = "ocrsad_0x30762A700F7d836528dfB14DD60Ec2A3aEaA7694" + var address ocrkey.OnChainSigningAddress + + err := address.UnmarshalText([]byte(ocrSigningKey)) + require.NoError(t, err) + _, err = address.Value() + + assert.NoError(t, err) + assert.Equal(t, ocrSigningKey, address.String()) +} diff --git a/keystore/corekeys/ocrkeybundle.go b/keystore/corekeys/ocrkeybundle.go deleted file mode 100644 index 060f852455..0000000000 --- a/keystore/corekeys/ocrkeybundle.go +++ /dev/null @@ -1,136 +0,0 @@ -package corekeys - -import ( - "context" - "encoding/json" - "fmt" - "strings" - - chainselectors "github.com/smartcontractkit/chain-selectors" - "github.com/smartcontractkit/chainlink-common/keystore" - "github.com/smartcontractkit/chainlink-common/keystore/ocr2offchain" -) - -const ( - TypeOCR = "ocr" - PrefixOCR2Onchain = "ocr2_onchain" -) - -type OCRKeyBundle struct { - ChainType string - OffchainSigningKey []byte - OffchainEncryptionKey []byte - OnchainSigningKey []byte -} - -func (ks *Store) GenerateEncryptedOCRKeyBundle(ctx context.Context, chainType string, password string) ([]byte, error) { - _, err := ocr2offchain.CreateOCR2OffchainKeyring(ctx, ks.Keystore, nameDefault) - if err != nil { - return nil, err - } - - var onchainKeyPath keystore.KeyPath - switch chainType { - case chainselectors.FamilyEVM: - path := keystore.NewKeyPath(PrefixOCR2Onchain, nameDefault, chainType) - _, ierr := ks.CreateKeys(ctx, keystore.CreateKeysRequest{ - Keys: []keystore.CreateKeyRequest{ - { - KeyName: path.String(), - KeyType: keystore.ECDSA_S256, - }, - }, - }) - if ierr != nil { - return nil, fmt.Errorf("failed to generate exportable key: %w", ierr) - } - - onchainKeyPath = path - default: - return nil, fmt.Errorf("unsupported chain type: %s", chainType) - } - - er, err := ks.ExportKeys(ctx, keystore.ExportKeysRequest{ - Keys: []keystore.ExportKeyParam{ - { - KeyName: keystore.NewKeyPath(ocr2offchain.PrefixOCR2Offchain, nameDefault, ocr2offchain.OCR2OffchainSigning).String(), - Enc: keystore.EncryptionParams{ - Password: password, - ScryptParams: keystore.DefaultScryptParams, - }, - }, - { - KeyName: keystore.NewKeyPath(ocr2offchain.PrefixOCR2Offchain, nameDefault, ocr2offchain.OCR2OffchainEncryption).String(), - Enc: keystore.EncryptionParams{ - Password: password, - ScryptParams: keystore.DefaultScryptParams, - }, - }, - { - KeyName: onchainKeyPath.String(), - Enc: keystore.EncryptionParams{ - Password: password, - ScryptParams: keystore.DefaultScryptParams, - }, - }, - }, - }) - if err != nil { - return nil, fmt.Errorf("failed to export OCR key bundle: %w", err) - } - - envelope := Envelope{ - Type: TypeOCR, - Keys: er.Keys, - ExportFormat: exportFormat, - } - - data, err := json.Marshal(&envelope) - if err != nil { - return nil, fmt.Errorf("failed to marshal OCR key bundle envelope: %w", err) - } - - return data, nil -} - -func FromEncryptedOCRKeyBundle(data []byte, password string) (*OCRKeyBundle, error) { - envelope := Envelope{} - err := json.Unmarshal(data, &envelope) - if err != nil { - return nil, fmt.Errorf("could not unmarshal import data into envelope: %w", err) - } - - if envelope.ExportFormat != exportFormat { - return nil, fmt.Errorf("invalid export format: %w", ErrInvalidExportFormat) - } - - if envelope.Type != TypeOCR { - return nil, fmt.Errorf("invalid key type: expected %s, got %s", TypeOCR, envelope.Type) - } - - if len(envelope.Keys) != 3 { - return nil, fmt.Errorf("expected exactly three keys in envelope, got %d", len(envelope.Keys)) - } - - bundle := &OCRKeyBundle{} - - for _, key := range envelope.Keys { - keypb, err := decryptKey(key.Data, password) - if err != nil { - return nil, err - } - - if strings.Contains(key.KeyName, ocr2offchain.OCR2OffchainSigning) { - bundle.OffchainSigningKey = keypb.PrivateKey - } else if strings.Contains(key.KeyName, ocr2offchain.OCR2OffchainEncryption) { - bundle.OffchainEncryptionKey = keypb.PrivateKey - } else if strings.Contains(key.KeyName, PrefixOCR2Onchain) { - bundle.OnchainSigningKey = keypb.PrivateKey - // Extract chain type from the key path - keyPath := keystore.NewKeyPathFromString(key.KeyName) - bundle.ChainType = strings.ToLower(keyPath.Base()) - } - } - - return bundle, nil -} diff --git a/keystore/corekeys/ocrkeybundle_test.go b/keystore/corekeys/ocrkeybundle_test.go deleted file mode 100644 index c6ee5a0283..0000000000 --- a/keystore/corekeys/ocrkeybundle_test.go +++ /dev/null @@ -1,133 +0,0 @@ -package corekeys - -import ( - "crypto/ed25519" - "testing" - - "github.com/ethereum/go-ethereum/crypto" - "github.com/stretchr/testify/require" - "golang.org/x/crypto/curve25519" - - chainselectors "github.com/smartcontractkit/chain-selectors" - "github.com/smartcontractkit/chainlink-common/keystore" - "github.com/smartcontractkit/chainlink-common/keystore/ocr2offchain" -) - -func TestOCRKeyBundleRoundTrip(t *testing.T) { - t.Parallel() - ctx := t.Context() - password := "test-password" - chainType := chainselectors.FamilyEVM - - st := keystore.NewMemoryStorage() - ks, err := keystore.LoadKeystore(ctx, st, "test", - keystore.WithScryptParams(keystore.FastScryptParams), - ) - require.NoError(t, err) - - coreshimKs := NewStore(ks) - - encryptedBundle, err := coreshimKs.GenerateEncryptedOCRKeyBundle(ctx, chainType, password) - require.NoError(t, err) - require.NotEmpty(t, encryptedBundle) - - signingKeyPath := keystore.NewKeyPath(ocr2offchain.PrefixOCR2Offchain, nameDefault, ocr2offchain.OCR2OffchainSigning) - encryptionKeyPath := keystore.NewKeyPath(ocr2offchain.PrefixOCR2Offchain, nameDefault, ocr2offchain.OCR2OffchainEncryption) - onchainKeyPath := keystore.NewKeyPath(PrefixOCR2Onchain, nameDefault, chainType) - - getKeysResp, err := ks.GetKeys(ctx, keystore.GetKeysRequest{ - KeyNames: []string{ - signingKeyPath.String(), - encryptionKeyPath.String(), - onchainKeyPath.String(), - }, - }) - require.NoError(t, err) - require.Len(t, getKeysResp.Keys, 3) - - var storedSigningPubKey, storedEncryptionPubKey, storedOnchainPubKey []byte - for _, key := range getKeysResp.Keys { - switch key.KeyInfo.Name { - case signingKeyPath.String(): - storedSigningPubKey = key.KeyInfo.PublicKey - case encryptionKeyPath.String(): - storedEncryptionPubKey = key.KeyInfo.PublicKey - case onchainKeyPath.String(): - storedOnchainPubKey = key.KeyInfo.PublicKey - } - } - - require.NotEmpty(t, storedSigningPubKey) - require.NotEmpty(t, storedEncryptionPubKey) - require.NotEmpty(t, storedOnchainPubKey) - - bundle, err := FromEncryptedOCRKeyBundle(encryptedBundle, password) - require.NoError(t, err) - require.NotNil(t, bundle) - - require.NotEmpty(t, bundle.OffchainSigningKey) - derivedSigningPubKey := ed25519.PrivateKey(bundle.OffchainSigningKey).Public().(ed25519.PublicKey) - require.Equal(t, storedSigningPubKey, []byte(derivedSigningPubKey)) - - var derivedEncryptionPubKey [32]byte - curve25519.ScalarBaseMult(&derivedEncryptionPubKey, (*[32]byte)(bundle.OffchainEncryptionKey)) - require.Equal(t, storedEncryptionPubKey, derivedEncryptionPubKey[:]) - - onchainPrivKey, err := crypto.ToECDSA(bundle.OnchainSigningKey) - require.NoError(t, err) - derivedOnchainPubKey := crypto.FromECDSAPub(&onchainPrivKey.PublicKey) - require.Equal(t, storedOnchainPubKey, derivedOnchainPubKey) -} - -func TestOCRKeyBundleImportWithWrongPassword(t *testing.T) { - t.Parallel() - ctx := t.Context() - password := "test-password" - wrongPassword := "wrong-password" - chainType := chainselectors.FamilyEVM - - st := keystore.NewMemoryStorage() - ks, err := keystore.LoadKeystore(ctx, st, "test", - keystore.WithScryptParams(keystore.FastScryptParams), - ) - require.NoError(t, err) - - coreshimKs := NewStore(ks) - - encryptedBundle, err := coreshimKs.GenerateEncryptedOCRKeyBundle(ctx, chainType, password) - require.NoError(t, err) - require.NotNil(t, encryptedBundle) - - _, err = FromEncryptedOCRKeyBundle(encryptedBundle, wrongPassword) - require.Error(t, err) - require.Contains(t, err.Error(), "could not decrypt data") -} - -func TestOCRKeyBundleImportInvalidFormat(t *testing.T) { - t.Parallel() - - _, err := FromEncryptedOCRKeyBundle([]byte("invalid json"), "password") - require.Error(t, err) - require.Contains(t, err.Error(), "could not unmarshal import data") -} - -func TestOCRKeyBundleInvalidKeyType(t *testing.T) { - t.Parallel() - ctx := t.Context() - password := "test-password" - - st := keystore.NewMemoryStorage() - ks, err := keystore.LoadKeystore(ctx, st, "test", - keystore.WithScryptParams(keystore.FastScryptParams), - ) - require.NoError(t, err) - - coreshimKs := NewStore(ks) - - encryptedCSAKey, err := coreshimKs.GenerateEncryptedCSAKey(ctx, password) - require.NoError(t, err) - - _, err = FromEncryptedOCRKeyBundle(encryptedCSAKey, password) - require.Error(t, err) - require.Contains(t, err.Error(), "invalid key type") -} diff --git a/keystore/corekeys/p2pkey/export.go b/keystore/corekeys/p2pkey/export.go new file mode 100644 index 0000000000..696a97a417 --- /dev/null +++ b/keystore/corekeys/p2pkey/export.go @@ -0,0 +1,55 @@ +package p2pkey + +import ( + "github.com/ethereum/go-ethereum/accounts/keystore" + + "github.com/smartcontractkit/chainlink-common/keystore/internal" + "github.com/smartcontractkit/chainlink-common/keystore/scrypt" +) + +const keyTypeIdentifier = "P2P" + +func FromEncryptedJSON(keyJSON []byte, password string) (KeyV2, error) { + return internal.FromEncryptedJSON( + keyTypeIdentifier, + keyJSON, + password, + adulteratedPassword, + func(_ EncryptedP2PKeyExport, rawPrivKey internal.Raw) (KeyV2, error) { + return KeyFor(rawPrivKey), nil + }, + ) +} + +type EncryptedP2PKeyExport struct { + KeyType string `json:"keyType"` + PublicKey string `json:"publicKey"` + PeerID PeerID `json:"peerID"` + Crypto keystore.CryptoJSON `json:"crypto"` +} + +func (x EncryptedP2PKeyExport) GetCrypto() keystore.CryptoJSON { + return x.Crypto +} + +func (key KeyV2) ToEncryptedJSON(password string, scryptParams scrypt.ScryptParams) (export []byte, err error) { + return internal.ToEncryptedJSON( + keyTypeIdentifier, + key, + password, + scryptParams, + adulteratedPassword, + func(id string, key KeyV2, cryptoJSON keystore.CryptoJSON) EncryptedP2PKeyExport { + return EncryptedP2PKeyExport{ + KeyType: id, + PublicKey: key.PublicKeyHex(), + PeerID: key.PeerID(), + Crypto: cryptoJSON, + } + }, + ) +} + +func adulteratedPassword(password string) string { + return "p2pkey" + password +} diff --git a/keystore/corekeys/p2pkey/export_test.go b/keystore/corekeys/p2pkey/export_test.go new file mode 100644 index 0000000000..ab265a2a29 --- /dev/null +++ b/keystore/corekeys/p2pkey/export_test.go @@ -0,0 +1,17 @@ +package p2pkey + +import ( + "testing" +) + +func TestP2PKeys_ExportImport(t *testing.T) { + corekeys2.RunKeyExportImportTestcase(t, createKey, decryptKey) +} + +func createKey() (corekeys2.KeyType, error) { + return NewV2() +} + +func decryptKey(keyJSON []byte, password string) (corekeys2.KeyType, error) { + return FromEncryptedJSON(keyJSON, password) +} diff --git a/keystore/corekeys/p2pkey/key_v2.go b/keystore/corekeys/p2pkey/key_v2.go new file mode 100644 index 0000000000..be0d739358 --- /dev/null +++ b/keystore/corekeys/p2pkey/key_v2.go @@ -0,0 +1,117 @@ +package p2pkey + +import ( + "bytes" + "crypto" + "crypto/ed25519" + "crypto/rand" + "encoding/hex" + "errors" + "io" + "math/big" + + "github.com/smartcontractkit/libocr/ragep2p/types" + + "github.com/smartcontractkit/chainlink-common/keystore/internal" +) + +var libp2pPBPrefix = []byte{0x08, 0x01, 0x12, 0x40} + +func KeyFor(raw internal.Raw) KeyV2 { + privKey, err := unmarshalPrivateKey(raw) + if err != nil { + panic(err) + } + key, err := fromPrivkey(privKey) + if err != nil { + panic(err) + } + key.raw = raw + return key +} + +func unmarshalPrivateKey(raw internal.Raw) (ed25519.PrivateKey, error) { + b := internal.Bytes((raw)) + if !bytes.HasPrefix(b, libp2pPBPrefix) { + return nil, errors.New("invalid key: missing libp2p protobuf prefix") + } + return b[len(libp2pPBPrefix):], nil +} + +func marshalPrivateKey(key ed25519.PrivateKey) ([]byte, error) { + return bytes.Join([][]byte{libp2pPBPrefix, key}, nil), nil +} + +type KeyV2 struct { + raw internal.Raw + signer crypto.Signer + + peerID PeerID +} + +func fromPrivkey(privKey ed25519.PrivateKey) (KeyV2, error) { + peerID, err := types.PeerIDFromPrivateKey(privKey) + if err != nil { + return KeyV2{}, err + } + return KeyV2{ + signer: privKey, + peerID: PeerID(peerID), + }, nil +} + +func NewV2() (KeyV2, error) { + _, privKey, err := ed25519.GenerateKey(rand.Reader) + if err != nil { + return KeyV2{}, err + } + key, err := fromPrivkey(privKey) + if err != nil { + return KeyV2{}, err + } + marshalledPrivK, err := marshalPrivateKey(privKey) + if err != nil { + return KeyV2{}, err + } + key.raw = internal.NewRaw(marshalledPrivK) + return key, nil +} + +func MustNewV2XXXTestingOnly(k *big.Int) KeyV2 { + seed := make([]byte, ed25519.SeedSize) + copy(seed, k.Bytes()) + pk := ed25519.NewKeyFromSeed(seed) + key, err := fromPrivkey(pk) + if err != nil { + panic(err) + } + marshalledPrivK, err := marshalPrivateKey(pk) + if err != nil { + panic(err) + } + key.raw = internal.NewRaw(marshalledPrivK) + return key +} + +func (key KeyV2) ID() string { + return types.PeerID(key.peerID).String() +} + +func (key KeyV2) Raw() internal.Raw { + return key.raw +} + +func (key KeyV2) PeerID() PeerID { + return key.peerID +} + +func (key KeyV2) PublicKeyHex() string { + pubKeyBytes := key.signer.Public().(ed25519.PublicKey) + return hex.EncodeToString(pubKeyBytes) +} + +func (key KeyV2) Public() crypto.PublicKey { return key.signer.Public() } + +func (key KeyV2) Sign(rand io.Reader, message []byte, opts crypto.SignerOpts) (signature []byte, err error) { + return key.signer.Sign(rand, message, opts) +} diff --git a/keystore/corekeys/p2pkey/key_v2_test.go b/keystore/corekeys/p2pkey/key_v2_test.go new file mode 100644 index 0000000000..8aedb5674d --- /dev/null +++ b/keystore/corekeys/p2pkey/key_v2_test.go @@ -0,0 +1,22 @@ +package p2pkey + +import ( + "crypto/ed25519" + "encoding/hex" + "testing" + + ragep2ptypes "github.com/smartcontractkit/libocr/ragep2p/types" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestP2PKeys_KeyV2(t *testing.T) { + kv2, err := NewV2() + require.NoError(t, err) + + pkv2 := kv2.Public().(ed25519.PublicKey) + + assert.Equal(t, ragep2ptypes.PeerID(kv2.PeerID()).String(), kv2.ID()) + assert.Equal(t, hex.EncodeToString(pkv2), kv2.PublicKeyHex()) +} diff --git a/keystore/corekeys/p2pkey/peer_id.go b/keystore/corekeys/p2pkey/peer_id.go new file mode 100644 index 0000000000..68e919dbbe --- /dev/null +++ b/keystore/corekeys/p2pkey/peer_id.go @@ -0,0 +1,96 @@ +package p2pkey + +import ( + "database/sql/driver" + "encoding/json" + "fmt" + "strings" + + "github.com/pkg/errors" + + "github.com/smartcontractkit/libocr/ragep2p/types" +) + +const peerIDPrefix = "p2p_" + +type PeerID types.PeerID + +func MakePeerID(s string) (PeerID, error) { + var peerID PeerID + return peerID, peerID.UnmarshalString(s) +} + +func (p PeerID) String() string { + // Handle a zero peerID more gracefully, i.e. print it as empty string rather + // than `p2p_` + if p == (PeerID{}) { + return "" + } + return fmt.Sprintf("%s%s", peerIDPrefix, p.Raw()) +} + +func (p PeerID) Raw() string { + return types.PeerID(p).String() +} + +func (p *PeerID) UnmarshalString(s string) error { + return p.UnmarshalText([]byte(s)) +} + +func (p *PeerID) MarshalText() ([]byte, error) { + if *p == (PeerID{}) { + return nil, nil + } + return []byte(p.Raw()), nil +} + +func (p *PeerID) UnmarshalText(bs []byte) error { + input := string(bs) + if strings.HasPrefix(input, peerIDPrefix) { + input = string(bs[len(peerIDPrefix):]) + } + + if input == "" { + return nil + } + + var peerID types.PeerID + err := peerID.UnmarshalText([]byte(input)) + if err != nil { + return errors.Wrapf(err, `PeerID#UnmarshalText("%v")`, input) + } + *p = PeerID(peerID) + return nil +} + +func (p *PeerID) Scan(value any) error { + *p = PeerID{} + switch s := value.(type) { + case string: + if s != "" { + return p.UnmarshalText([]byte(s)) + } + case nil: + default: + return errors.Errorf("PeerID#Scan got %T, expected string", value) + } + return nil +} + +func (p PeerID) Value() (driver.Value, error) { + b, err := types.PeerID(p).MarshalText() + return string(b), err +} + +func (p PeerID) MarshalJSON() ([]byte, error) { + return json.Marshal(p.String()) +} + +func (p *PeerID) UnmarshalJSON(input []byte) error { + var result string + if err := json.Unmarshal(input, &result); err != nil { + return err + } + + return p.UnmarshalText([]byte(result)) +} diff --git a/keystore/corekeys/p2pkey/peer_id_test.go b/keystore/corekeys/p2pkey/peer_id_test.go new file mode 100644 index 0000000000..3d4ad05d5f --- /dev/null +++ b/keystore/corekeys/p2pkey/peer_id_test.go @@ -0,0 +1,72 @@ +package p2pkey + +import ( + "math/big" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestP2PKeys_PeerID(t *testing.T) { + t.Run("make peer ID", func(t *testing.T) { + id, err := MakePeerID("12D3KooWM1111111111111111111111111111111111111111111") + require.NoError(t, err) + _, err = MakePeerID("invalid") + assert.Error(t, err) + + assert.Equal(t, "p2p_12D3KooWM1111111111111111111111111111111111111111111", id.String()) + }) + + t.Run("unmarshals new ID", func(t *testing.T) { + id, err := MakePeerID("12D3KooWM1111111111111111111111111111111111111111111") + require.NoError(t, err) + fakeKey := MustNewV2XXXTestingOnly(big.NewInt(1)) + + err = id.UnmarshalString(fakeKey.ID()) + require.NoError(t, err) + + assert.Equal(t, "p2p_"+fakeKey.ID(), id.String()) + }) + + t.Run("scans new ID", func(t *testing.T) { + id, err := MakePeerID("12D3KooWM1111111111111111111111111111111111111111111") + require.NoError(t, err) + fakeKey := MustNewV2XXXTestingOnly(big.NewInt(1)) + + err = id.Scan(fakeKey.ID()) + require.NoError(t, err) + + assert.Equal(t, "p2p_"+fakeKey.ID(), id.String()) + + err = id.Scan(12) + assert.Error(t, err) + assert.Empty(t, id.String()) + }) +} + +func TestPeerID_marshal(t *testing.T) { + id, err := MakePeerID("p2p_12D3KooWMoejJznyDuEk5aX6GvbjaG12UzeornPCBNzMRqdwrFJw") + require.NoError(t, err) + t.Run("json", func(t *testing.T) { + b, err := id.MarshalJSON() + require.NoError(t, err) + var got PeerID + require.NoError(t, got.UnmarshalJSON(b)) + require.Equal(t, id, got) + }) + t.Run("db", func(t *testing.T) { + v, err := id.Value() + require.NoError(t, err) + var got PeerID + require.NoError(t, got.Scan(v)) + require.Equal(t, id, got) + }) + t.Run("text", func(t *testing.T) { + s, err := id.MarshalText() + require.NoError(t, err) + var got PeerID + require.NoError(t, got.UnmarshalText(s)) + require.Equal(t, id, got) + }) +} diff --git a/keystore/corekeys/solkey/export.go b/keystore/corekeys/solkey/export.go new file mode 100644 index 0000000000..e7a8725b30 --- /dev/null +++ b/keystore/corekeys/solkey/export.go @@ -0,0 +1,47 @@ +package solkey + +import ( + "encoding/hex" + + "github.com/ethereum/go-ethereum/accounts/keystore" + + "github.com/smartcontractkit/chainlink-common/keystore/internal" + "github.com/smartcontractkit/chainlink-common/keystore/scrypt" +) + +const keyTypeIdentifier = "Solana" + +// FromEncryptedJSON gets key from json and password +func FromEncryptedJSON(keyJSON []byte, password string) (Key, error) { + return internal.FromEncryptedJSON( + keyTypeIdentifier, + keyJSON, + password, + adulteratedPassword, + func(_ internal.EncryptedKeyExport, rawPrivKey internal.Raw) (Key, error) { + return KeyFor(rawPrivKey), nil + }, + ) +} + +// ToEncryptedJSON returns encrypted JSON representing key +func (key Key) ToEncryptedJSON(password string, scryptParams scrypt.ScryptParams) (export []byte, err error) { + return internal.ToEncryptedJSON( + keyTypeIdentifier, + key, + password, + scryptParams, + adulteratedPassword, + func(id string, key Key, cryptoJSON keystore.CryptoJSON) internal.EncryptedKeyExport { + return internal.EncryptedKeyExport{ + KeyType: id, + PublicKey: hex.EncodeToString(key.pubKey), + Crypto: cryptoJSON, + } + }, + ) +} + +func adulteratedPassword(password string) string { + return "solkey" + password +} diff --git a/keystore/corekeys/solkey/export_test.go b/keystore/corekeys/solkey/export_test.go new file mode 100644 index 0000000000..4f1b1a0062 --- /dev/null +++ b/keystore/corekeys/solkey/export_test.go @@ -0,0 +1,17 @@ +package solkey + +import ( + "testing" +) + +func TestSolanaKeys_ExportImport(t *testing.T) { + corekeys2.RunKeyExportImportTestcase(t, createKey, decryptKey) +} + +func createKey() (corekeys2.KeyType, error) { + return New() +} + +func decryptKey(keyJSON []byte, password string) (corekeys2.KeyType, error) { + return FromEncryptedJSON(keyJSON, password) +} diff --git a/keystore/corekeys/solkey/key.go b/keystore/corekeys/solkey/key.go new file mode 100644 index 0000000000..e61b8a90ab --- /dev/null +++ b/keystore/corekeys/solkey/key.go @@ -0,0 +1,84 @@ +package solkey + +import ( + "crypto" + "crypto/ed25519" + crypto_rand "crypto/rand" + "io" + + "github.com/gagliardetto/solana-go" + "github.com/mr-tron/base58" + + "github.com/smartcontractkit/chainlink-common/keystore/internal" +) + +func KeyFor(raw internal.Raw) Key { + privKey := ed25519.NewKeyFromSeed(internal.Bytes(raw)) + return Key{ + raw: raw, + signFn: privKey.Sign, + pubKey: privKey.Public().(ed25519.PublicKey), + } +} + +// Key represents Solana key +type Key struct { + raw internal.Raw + signFn func(io.Reader, []byte, crypto.SignerOpts) ([]byte, error) + pubKey ed25519.PublicKey +} + +// New creates new Key +func New() (Key, error) { + return newFrom(crypto_rand.Reader) +} + +// MustNewInsecure return Key if no error +func MustNewInsecure(reader io.Reader) Key { + key, err := newFrom(reader) + if err != nil { + panic(err) + } + return key +} + +func newFrom(reader io.Reader) (Key, error) { + pub, priv, err := ed25519.GenerateKey(reader) + if err != nil { + return Key{}, err + } + return Key{ + raw: internal.NewRaw(priv.Seed()), + signFn: priv.Sign, + pubKey: pub, + }, nil +} + +// ID gets Key ID +func (key Key) ID() string { + return key.PublicKeyStr() +} + +// GetPublic get Key's public key +func (key Key) GetPublic() ed25519.PublicKey { + return key.pubKey +} + +// PublicKeyStr return base58 encoded public key +func (key Key) PublicKeyStr() string { + return base58.Encode(key.pubKey) +} + +// Raw from private key +func (key Key) Raw() internal.Raw { return key.raw } + +// Sign is used to sign a message +func (key Key) Sign(msg []byte) ([]byte, error) { + return key.signFn(crypto_rand.Reader, msg, crypto.Hash(0)) +} + +// PublicKey copies public key slice +func (key Key) PublicKey() (pubKey solana.PublicKey) { + copy(pubKey[:], key.pubKey) + return +} diff --git a/keystore/corekeys/starkkey/export.go b/keystore/corekeys/starkkey/export.go new file mode 100644 index 0000000000..c6eb45c753 --- /dev/null +++ b/keystore/corekeys/starkkey/export.go @@ -0,0 +1,45 @@ +package starkkey + +import ( + "github.com/ethereum/go-ethereum/accounts/keystore" + + "github.com/smartcontractkit/chainlink-common/keystore/internal" + "github.com/smartcontractkit/chainlink-common/keystore/scrypt" +) + +const keyTypeIdentifier = "StarkNet" + +// FromEncryptedJSON gets key from json and password +func FromEncryptedJSON(keyJSON []byte, password string) (Key, error) { + return internal.FromEncryptedJSON( + keyTypeIdentifier, + keyJSON, + password, + adulteratedPassword, + func(_ internal.EncryptedKeyExport, rawPrivKey internal.Raw) (Key, error) { + return KeyFor(rawPrivKey), nil + }, + ) +} + +// ToEncryptedJSON returns encrypted JSON representing key +func ToEncryptedJSON(key Key, password string, scryptParams scrypt.ScryptParams) (export []byte, err error) { + return internal.ToEncryptedJSON( + keyTypeIdentifier, + key, + password, + scryptParams, + adulteratedPassword, + func(id string, key Key, cryptoJSON keystore.CryptoJSON) internal.EncryptedKeyExport { + return internal.EncryptedKeyExport{ + KeyType: id, + PublicKey: key.StarkKeyStr(), + Crypto: cryptoJSON, + } + }, + ) +} + +func adulteratedPassword(password string) string { + return "starkkey" + password +} diff --git a/keystore/corekeys/starkkey/export_test.go b/keystore/corekeys/starkkey/export_test.go new file mode 100644 index 0000000000..0c938ba7b9 --- /dev/null +++ b/keystore/corekeys/starkkey/export_test.go @@ -0,0 +1,30 @@ +package starkkey + +import ( + "testing" + + "github.com/smartcontractkit/chainlink-common/keystore/scrypt" +) + +func TestStarkNetKeys_ExportImport(t *testing.T) { + corekeys2.RunKeyExportImportTestcase(t, createKey, decryptKey) +} + +func createKey() (corekeys2.KeyType, error) { + key, err := New() + return TestWrapped{key}, err +} + +func decryptKey(keyJSON []byte, password string) (corekeys2.KeyType, error) { + key, err := FromEncryptedJSON(keyJSON, password) + return TestWrapped{key}, err +} + +// wrap key to conform to desired test interface +type TestWrapped struct { + Key +} + +func (w TestWrapped) ToEncryptedJSON(password string, scryptParams scrypt.ScryptParams) ([]byte, error) { + return ToEncryptedJSON(w.Key, password, scryptParams) +} diff --git a/keystore/corekeys/starkkey/key.go b/keystore/corekeys/starkkey/key.go new file mode 100644 index 0000000000..c05029041e --- /dev/null +++ b/keystore/corekeys/starkkey/key.go @@ -0,0 +1,91 @@ +package starkkey + +import ( + crypto_rand "crypto/rand" + "fmt" + "io" + "math/big" + + "github.com/NethermindEth/juno/core/felt" + "github.com/NethermindEth/starknet.go/curve" + + "github.com/smartcontractkit/chainlink-common/keystore/internal" + adapters "github.com/smartcontractkit/chainlink-common/pkg/loop/adapters/starknet" +) + +func KeyFor(raw internal.Raw) Key { + k := Key{raw: raw} + var err error + + priv := new(big.Int).SetBytes(internal.Bytes(raw)) + k.signFn = func(hash *big.Int) (x, y *big.Int, err error) { + return curve.Curve.Sign(hash, priv) + } + k.pub.X, k.pub.Y, err = curve.Curve.PrivateToPoint(priv) + if err != nil { + panic(err) // key not generated + } + return k +} + +type PublicKey struct { + X, Y *big.Int +} + +// Key represents Starknet key +type Key struct { + raw internal.Raw + signFn func(*big.Int) (x, y *big.Int, err error) + pub PublicKey +} + +// New creates new Key +func New() (Key, error) { + return newFrom(crypto_rand.Reader) +} + +// MustNewInsecure return Key if no error +func MustNewInsecure(reader io.Reader) Key { + key, err := newFrom(reader) + if err != nil { + panic(err) + } + return key +} + +func newFrom(reader io.Reader) (Key, error) { + return GenerateKey(reader) +} + +// ID gets Key ID +func (key Key) ID() string { + return key.StarkKeyStr() +} + +// StarkKeyStr is the starknet public key associated to the private key +// it is the X component of the ECDSA pubkey and used in the deployment of the account contract +// this func is used in exporting it via CLI and API +func (key Key) StarkKeyStr() string { + return new(felt.Felt).SetBytes(key.pub.X.Bytes()).String() +} + +// Raw from private key +func (key Key) Raw() internal.Raw { return key.raw } + +func (key Key) Sign(hash []byte) ([]byte, error) { + starkHash := new(big.Int).SetBytes(hash) + x, y, err := key.signFn(starkHash) + if err != nil { + return nil, fmt.Errorf("error signing data with curve: %w", err) + } + sig, err := adapters.SignatureFromBigInts(x, y) + if err != nil { + return nil, err + } + return sig.Bytes() +} + +// PublicKey copies public key object +func (key Key) PublicKey() PublicKey { + return key.pub +} diff --git a/keystore/corekeys/starkkey/ocr2key.go b/keystore/corekeys/starkkey/ocr2key.go new file mode 100644 index 0000000000..d0fca19a9a --- /dev/null +++ b/keystore/corekeys/starkkey/ocr2key.go @@ -0,0 +1,188 @@ +package starkkey + +import ( + "bytes" + "io" + "math/big" + + "github.com/pkg/errors" + + "github.com/NethermindEth/juno/core/felt" + "github.com/NethermindEth/starknet.go/curve" + + "github.com/smartcontractkit/libocr/offchainreporting2plus/chains/evmutil" + "github.com/smartcontractkit/libocr/offchainreporting2plus/types" + + "github.com/smartcontractkit/chainlink-common/keystore/internal" +) + +var _ types.OnchainKeyring = &OCR2Key{} + +type OCR2Key struct { + Key +} + +func NewOCR2Key(material io.Reader) (*OCR2Key, error) { + k, err := GenerateKey(material) + + return &OCR2Key{k}, err +} + +func (sk *OCR2Key) PublicKey() types.OnchainPublicKey { + ans := new(felt.Felt).SetBytes(sk.pub.X.Bytes()).Bytes() + return ans[:] +} + +func ReportToSigData(reportCtx types.ReportContext, report types.Report) (*big.Int, error) { + var dataArray []*big.Int + + rawReportContext := rawReportContext(reportCtx) + dataArray = append(dataArray, new(big.Int).SetBytes(rawReportContext[0][:])) + dataArray = append(dataArray, new(big.Int).SetBytes(rawReportContext[1][:])) + dataArray = append(dataArray, new(big.Int).SetBytes(rawReportContext[2][:])) + + // split report into separate felts for hashing + splitReport, err := splitReport(report) + if err != nil { + return &big.Int{}, err + } + for i := range splitReport { + dataArray = append(dataArray, new(big.Int).SetBytes(splitReport[i])) + } + + return curve.ComputeHashOnElements(dataArray), nil +} + +func (sk *OCR2Key) Sign(reportCtx types.ReportContext, report types.Report) ([]byte, error) { + hash, err := ReportToSigData(reportCtx, report) + if err != nil { + return []byte{}, err + } + r, s, err := sk.signFn(hash) + if err != nil { + return []byte{}, err + } + + // enforce s <= N/2 to prevent signature malleability + if s.Cmp(new(big.Int).Rsh(curve.Curve.N, 1)) > 0 { + s.Sub(curve.Curve.N, s) + } + + // encoding: public key (32 bytes) + r (32 bytes) + s (32 bytes) + buff := bytes.NewBuffer([]byte(sk.PublicKey())) + if _, err := buff.Write(padBytes(r.Bytes())); err != nil { + return []byte{}, err + } + if _, err := buff.Write(padBytes(s.Bytes())); err != nil { + return []byte{}, err + } + + out := buff.Bytes() + if len(out) != sk.MaxSignatureLength() { + return []byte{}, errors.Errorf("unexpected signature size, got %d want %d", len(out), sk.MaxSignatureLength()) + } + return out, nil +} + +func (sk *OCR2Key) Sign3(digest types.ConfigDigest, seqNr uint64, r types.Report) (signature []byte, err error) { + return nil, errors.New("not implemented") +} + +func (sk *OCR2Key) SignBlob(b []byte) ([]byte, error) { + return nil, errors.New("not implemented") +} + +func (sk *OCR2Key) Verify(publicKey types.OnchainPublicKey, reportCtx types.ReportContext, report types.Report, signature []byte) bool { + // check valid signature length + if len(signature) != sk.MaxSignatureLength() { + return false + } + + // convert OnchainPublicKey (starkkey) into ecdsa public keys (prepend 2 or 3 to indicate +/- Y coord) + var keys [2]PublicKey + keys[0].X = new(big.Int).SetBytes(publicKey) + keys[0].Y = curve.Curve.GetYCoordinate(keys[0].X) + + // When there is no point with the provided x-coordinate, the GetYCoordinate function returns the nil value. + if keys[0].Y == nil { + return false + } + + keys[1].X = keys[0].X + keys[1].Y = new(big.Int).Mul(keys[0].Y, big.NewInt(-1)) + + hash, err := ReportToSigData(reportCtx, report) + if err != nil { + return false + } + + r := new(big.Int).SetBytes(signature[32:64]) + s := new(big.Int).SetBytes(signature[64:]) + + // Only allow canonical signatures to avoid signature malleability. Verify s <= N/2 + if s.Cmp(new(big.Int).Rsh(curve.Curve.N, 1)) == 1 { + return false + } + + return curve.Curve.Verify(hash, r, s, keys[0].X, keys[0].Y) || curve.Curve.Verify(hash, r, s, keys[1].X, keys[1].Y) +} + +func (sk *OCR2Key) Verify3(publicKey types.OnchainPublicKey, cd types.ConfigDigest, seqNr uint64, r types.Report, signature []byte) bool { + return false +} + +func (sk *OCR2Key) VerifyBlob(pubkey types.OnchainPublicKey, b, sig []byte) bool { + return false +} + +func (sk *OCR2Key) MaxSignatureLength() int { + return 32 + 32 + 32 // publickey + r + s +} + +func (sk *OCR2Key) Marshal() ([]byte, error) { + return padBytes(internal.Bytes(sk.raw)), nil +} + +// https://github.com/NethermindEth/juno/blob/3e71279632d82689e5af03e26693ca5c58a2376e/pkg/crypto/weierstrass/weierstrass.go#L377 +const privateKeyLen = 32 + +func (sk *OCR2Key) Unmarshal(in []byte) error { + // enforce byte length + if len(in) != privateKeyLen { + return errors.Errorf("unexpected seed size, got %d want %d", len(in), privateKeyLen) + } + + sk.Key = KeyFor(internal.NewRaw(in)) + return nil +} + +func splitReport(report types.Report) ([][]byte, error) { + chunkSize := 32 + if len(report)%chunkSize != 0 { + return [][]byte{}, errors.New("invalid report length") + } + + // order is guaranteed by buildReport: + // observation_timestamp + // observers + // observations_len + // observations + // juels_per_fee_coin + // gas_price + slices := [][]byte{} + for i := 0; i < len(report)/chunkSize; i++ { + idx := i * chunkSize + slices = append(slices, report[idx:(idx+chunkSize)]) + } + + return slices, nil +} + +// NOTE: this should sit in the ocr2 package but that causes import cycles +func rawReportContext(repctx types.ReportContext) [3][32]byte { + rawReportContext := evmutil.RawReportContext(repctx) + // NOTE: Ensure extra_hash is 31 bytes with first byte blanked out + // libocr generates a 32 byte extraHash but we need to fit it into a felt + rawReportContext[2][0] = 0 + return rawReportContext +} diff --git a/keystore/corekeys/starkkey/ocr2key_test.go b/keystore/corekeys/starkkey/ocr2key_test.go new file mode 100644 index 0000000000..bd7cd365b3 --- /dev/null +++ b/keystore/corekeys/starkkey/ocr2key_test.go @@ -0,0 +1,202 @@ +package starkkey + +import ( + cryptorand "crypto/rand" + "encoding/hex" + "io" + "math/big" + mathrand "math/rand" + "testing" + + "github.com/NethermindEth/juno/core/felt" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + ocrtypes "github.com/smartcontractkit/libocr/offchainreporting2plus/types" + + "github.com/smartcontractkit/chainlink-common/keystore/internal" +) + +// msg to hash +// [ +// '0x4acf99cb25a4803916f086440c661295b105a485efdc649ac4de9536da25b', // digest +// 1, // epoch_and_round +// 1, // extra_hash +// 1, // timestamp +// '0x00010203000000000000000000000000000000000000000000000000000000', // observers +// 4, // len +// 99, // reports +// 99, +// 99, +// 99, +// 1 juels_per_fee_coin +// ] +// hash 0x1332a8dabaabef63b03438ca50760cb9f5c0292cbf015b2395e50e6157df4e3 +// --> privKey 2137244795266879235401249500471353867704187908407744160927664772020405449078 r 2898571078985034687500959842265381508927681132188252715370774777831313601543 s 1930849708769648077928186998643944706551011476358007177069185543644456022504 pubKey 1118148281956858477519852250235501663092798578871088714409528077622994994907 +// privKey 3571531812827697194985986636869245829152430835021673171507607525908246940354 r 3242770073040892094735101607173275538752888766491356946211654602282309624331 s 2150742645846855766116236144967953798077492822890095121354692808525999221887 pubKey 2445157821578193538289426656074203099996547227497157254541771705133209838679 + +func TestStarknetKeyring_TestVector(t *testing.T) { + var kr1 OCR2Key + bigKey, _ := new(big.Int).SetString("2137244795266879235401249500471353867704187908407744160927664772020405449078", 10) + feltKey, err := new(felt.Felt).SetString(bigKey.String()) + require.NoError(t, err) + bytesKey := feltKey.Bytes() + err = kr1.Unmarshal(bytesKey[:]) + require.NoError(t, err) + // kr2, err := NewOCR2Key(cryptorand.Reader) + // require.NoError(t, err) + + bytes, err := hex.DecodeString("0004acf99cb25a4803916f086440c661295b105a485efdc649ac4de9536da25b") + require.NoError(t, err) + configDigest, err := ocrtypes.BytesToConfigDigest(bytes) + require.NoError(t, err) + + ctx := ocrtypes.ReportContext{ + ReportTimestamp: ocrtypes.ReportTimestamp{ + ConfigDigest: configDigest, + Epoch: 0, + Round: 1, + }, + ExtraHash: [32]byte{ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, + }, + } + + var report []byte + b1 := new(felt.Felt).SetUint64(1).Bytes() + report = append(report, b1[:]...) + b2Bytes, err := hex.DecodeString("00010203000000000000000000000000000000000000000000000000000000") + require.NoError(t, err) + b2 := new(felt.Felt).SetBytes(b2Bytes).Bytes() + report = append(report, b2[:]...) + b3 := new(felt.Felt).SetUint64(4).Bytes() + report = append(report, b3[:]...) + b4 := new(felt.Felt).SetUint64(99).Bytes() + report = append(report, b4[:]...) + report = append(report, b4[:]...) + report = append(report, b4[:]...) + report = append(report, b4[:]...) + report = append(report, b1[:]...) + + // check that report hash matches expected + msg, err := ReportToSigData(ctx, report) + require.NoError(t, err) + + expected, err := new(felt.Felt).SetString("0x1332a8dabaabef63b03438ca50760cb9f5c0292cbf015b2395e50e6157df4e3") + expectedBytes := expected.Bytes() + require.NoError(t, err) + assert.Equal(t, expectedBytes[:], msg.Bytes()) + + // check that signature matches expected + sig, err := kr1.Sign(ctx, report) + require.NoError(t, err) + + pub := new(felt.Felt).SetBytes(sig[0:32]) + r := new(felt.Felt).SetBytes(sig[32:64]) + s := new(felt.Felt).SetBytes(sig[64:]) + + bigPubExpected, _ := new(big.Int).SetString("1118148281956858477519852250235501663092798578871088714409528077622994994907", 10) + feltPubExpected := new(felt.Felt).SetBytes(bigPubExpected.Bytes()) + assert.Equal(t, feltPubExpected, pub) + + bigRExpected, _ := new(big.Int).SetString("2898571078985034687500959842265381508927681132188252715370774777831313601543", 10) + feltRExpected := new(felt.Felt).SetBytes(bigRExpected.Bytes()) + assert.Equal(t, feltRExpected, r) + + // test for malleability + otherS, _ := new(big.Int).SetString("1930849708769648077928186998643944706551011476358007177069185543644456022504", 10) + bigSExpected, _ := new(big.Int).SetString("1687653079896483135769135784451125398975732275358080312084893914240056843079", 10) + + feltSExpected := new(felt.Felt).SetBytes(bigSExpected.Bytes()) + assert.NotEqual(t, otherS, s, "signature not in canonical form") + assert.Equal(t, feltSExpected, s) +} + +func TestStarknetKeyring_Sign_Verify(t *testing.T) { + kr1, err := NewOCR2Key(cryptorand.Reader) + require.NoError(t, err) + kr2, err := NewOCR2Key(cryptorand.Reader) + require.NoError(t, err) + + digest := "00044e5d4f35325e464c87374b13c512f60e09d1236dd902f4bef4c9aedd7300" + bytes, err := hex.DecodeString(digest) + require.NoError(t, err) + configDigest, err := ocrtypes.BytesToConfigDigest(bytes) + require.NoError(t, err) + + ctx := ocrtypes.ReportContext{ + ReportTimestamp: ocrtypes.ReportTimestamp{ + ConfigDigest: configDigest, + Epoch: 1, + Round: 1, + }, + ExtraHash: [32]byte{ + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + }, + } + report := ocrtypes.Report{ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 97, 91, 43, 83, // observations_timestamp + 0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // observers + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, // len + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 73, 150, 2, 210, // observation 1 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 73, 150, 2, 211, // observation 2 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13, 224, 182, 179, 167, 100, 0, 0, // juels per fee coin (1 with 18 decimal places) + } + + t.Run("can verify", func(t *testing.T) { + sig, err := kr1.Sign(ctx, report) + require.NoError(t, err) + result := kr2.Verify(kr1.PublicKey(), ctx, report, sig) + require.True(t, result) + }) + + t.Run("invalid sig", func(t *testing.T) { + result := kr2.Verify(kr1.PublicKey(), ctx, report, []byte{0x01}) + require.False(t, result) + + longSig := [100]byte{} + result = kr2.Verify(kr1.PublicKey(), ctx, report, longSig[:]) + require.False(t, result) + }) + + t.Run("invalid pubkey", func(t *testing.T) { + sig, err := kr1.Sign(ctx, report) + require.NoError(t, err) + + pk := []byte{0x01} + result := kr2.Verify(pk, ctx, report, sig) + require.False(t, result) + + pk = big.NewInt(int64(31337)).Bytes() + result = kr2.Verify(pk, ctx, report, sig) + require.False(t, result) + }) +} + +func TestStarknetKeyring_Marshal(t *testing.T) { + testStarknetKeyringMarshal(t, cryptorand.Reader) +} + +func testStarknetKeyringMarshal(t *testing.T, r io.Reader) { + kr1, err := NewOCR2Key(r) + require.NoError(t, err) + m, err := kr1.Marshal() + require.NoError(t, err) + kr2 := OCR2Key{} + err = kr2.Unmarshal(m) + require.NoError(t, err) + assert.Equal(t, internal.Bytes(kr1.raw), internal.Bytes(kr2.raw)) + + // Invalid seed size should error + require.Error(t, kr2.Unmarshal([]byte{0x01})) +} + +func FuzzStarknetKeyring_Marshal(f *testing.F) { + f.Fuzz(func(t *testing.T, seed int64) { + r := mathrand.New(mathrand.NewSource(seed)) + testStarknetKeyringMarshal(t, r) + }) +} diff --git a/keystore/corekeys/starkkey/utils.go b/keystore/corekeys/starkkey/utils.go new file mode 100644 index 0000000000..99a0016c48 --- /dev/null +++ b/keystore/corekeys/starkkey/utils.go @@ -0,0 +1,51 @@ +package starkkey + +import ( + "crypto/rand" + "errors" + "io" + "math/big" + + "github.com/NethermindEth/starknet.go/curve" + + "github.com/smartcontractkit/chainlink-common/keystore/internal" +) + +// reimplements parts of +// https://github.com/NethermindEth/starknet.go/blob/0bdaab716ce24a521304744a8fbd8e01800c241d/curve/curve.go#L702 +// generate the PK as a pseudo-random number in the interval [1, CurveOrder - 1] +// using io.Reader, and Key struct +func GenerateKey(material io.Reader) (k Key, err error) { + max := new(big.Int).Sub(curve.Curve.N, big.NewInt(1)) + + priv, err := rand.Int(material, max) + if err != nil { + return k, err + } + k.signFn = func(hash *big.Int) (x, y *big.Int, err error) { + return curve.Curve.Sign(hash, priv) + } + + k.pub.X, k.pub.Y, err = curve.Curve.PrivateToPoint(priv) + if err != nil { + return k, err + } + + if !curve.Curve.IsOnCurve(k.pub.X, k.pub.Y) { + return k, errors.New("key gen is not on stark curve") + } + k.raw = internal.NewRaw(padBytes(priv.Bytes())) + + return k, nil +} + +// pad bytes to privateKeyLen +func padBytes(a []byte) []byte { + if len(a) < privateKeyLen { + pad := make([]byte, privateKeyLen-len(a)) + return append(pad, a...) + } + + // return original if length is >= to specified length + return a +} diff --git a/keystore/corekeys/suikey/export.go b/keystore/corekeys/suikey/export.go new file mode 100644 index 0000000000..47171ff8a3 --- /dev/null +++ b/keystore/corekeys/suikey/export.go @@ -0,0 +1,47 @@ +package suikey + +import ( + "encoding/hex" + + "github.com/ethereum/go-ethereum/accounts/keystore" + + "github.com/smartcontractkit/chainlink-common/keystore/internal" + "github.com/smartcontractkit/chainlink-common/keystore/scrypt" +) + +const keyTypeIdentifier = "Sui" + +// FromEncryptedJSON gets key from json and password +func FromEncryptedJSON(keyJSON []byte, password string) (Key, error) { + return internal.FromEncryptedJSON( + keyTypeIdentifier, + keyJSON, + password, + adulteratedPassword, + func(_ internal.EncryptedKeyExport, rawPrivKey internal.Raw) (Key, error) { + return KeyFor(rawPrivKey), nil + }, + ) +} + +// ToEncryptedJSON returns encrypted JSON representing key +func (s Key) ToEncryptedJSON(password string, scryptParams scrypt.ScryptParams) (export []byte, err error) { + return internal.ToEncryptedJSON( + keyTypeIdentifier, + s, + password, + scryptParams, + adulteratedPassword, + func(id string, key Key, cryptoJSON keystore.CryptoJSON) internal.EncryptedKeyExport { + return internal.EncryptedKeyExport{ + KeyType: id, + PublicKey: hex.EncodeToString(key.pubKey), + Crypto: cryptoJSON, + } + }, + ) +} + +func adulteratedPassword(password string) string { + return "suikey" + password +} diff --git a/keystore/corekeys/suikey/export_test.go b/keystore/corekeys/suikey/export_test.go new file mode 100644 index 0000000000..b311d00c96 --- /dev/null +++ b/keystore/corekeys/suikey/export_test.go @@ -0,0 +1,17 @@ +package suikey + +import ( + "testing" +) + +func TestSuiKeys_ExportImport(t *testing.T) { + corekeys2.RunKeyExportImportTestcase(t, createKey, decryptKey) +} + +func createKey() (corekeys2.KeyType, error) { + return New() +} + +func decryptKey(keyJSON []byte, password string) (corekeys2.KeyType, error) { + return FromEncryptedJSON(keyJSON, password) +} diff --git a/keystore/corekeys/suikey/key.go b/keystore/corekeys/suikey/key.go new file mode 100644 index 0000000000..b44258da25 --- /dev/null +++ b/keystore/corekeys/suikey/key.go @@ -0,0 +1,107 @@ +package suikey + +import ( + "crypto" + "crypto/ed25519" + cryptorand "crypto/rand" + "encoding/hex" + "fmt" + "io" + + "golang.org/x/crypto/blake2b" + + "github.com/smartcontractkit/chainlink-common/keystore/internal" +) + +// Ed25519Scheme Ed25519 signature scheme flag +// https://docs.sui.io/concepts/cryptography/transaction-auth/keys-addresses#address-format +const Ed25519Scheme byte = 0x00 + +// Key represents a Sui account +type Key struct { + raw internal.Raw + signFn func(io.Reader, []byte, crypto.SignerOpts) ([]byte, error) + pubKey ed25519.PublicKey +} + +// KeyFor creates an Account from a raw key +func KeyFor(raw internal.Raw) Key { + privKey := ed25519.NewKeyFromSeed(internal.Bytes(raw)) + pubKey := privKey.Public().(ed25519.PublicKey) + return Key{ + raw: raw, + signFn: privKey.Sign, + pubKey: pubKey, + } +} + +// New creates new Key +func New() (Key, error) { + return newFrom(cryptorand.Reader) +} + +// MustNewInsecure returns an Account if no error +func MustNewInsecure(reader io.Reader) Key { + key, err := newFrom(reader) + if err != nil { + panic(err) + } + return key +} + +// newFrom creates a new Account from a provided random reader +func newFrom(reader io.Reader) (Key, error) { + pub, priv, err := ed25519.GenerateKey(reader) + if err != nil { + return Key{}, err + } + return Key{ + raw: internal.NewRaw(priv.Seed()), + signFn: priv.Sign, + pubKey: pub, + }, nil +} + +// ID gets Account ID +func (s Key) ID() string { + return s.PublicKeyStr() +} + +// Address returns the Sui address +// https://docs.sui.io/concepts/cryptography/transaction-auth/keys-addresses#address-format +func (s Key) Address() string { + // Prepend the Ed25519 scheme flag to the public key + flaggedPubKey := make([]byte, 1+len(s.pubKey)) + flaggedPubKey[0] = Ed25519Scheme + copy(flaggedPubKey[1:], s.pubKey) + + // Hash the flagged public key with Blake2b-256 + addressBytes := blake2b.Sum256(flaggedPubKey) + + // Return the full 32-byte address with 0x prefix + return hex.EncodeToString(addressBytes[:]) +} + +// Account is an alias for Address +func (s Key) Account() string { + return s.Address() +} + +// GetPublic gets Account's public key +func (s Key) GetPublic() ed25519.PublicKey { + return s.pubKey +} + +// PublicKeyStr returns hex encoded public key +func (s Key) PublicKeyStr() string { + return fmt.Sprintf("%064x", s.pubKey) +} + +// Raw returns the seed from private key +func (s Key) Raw() internal.Raw { return s.raw } + +// Sign is used to sign a message +func (s Key) Sign(msg []byte) ([]byte, error) { + var noHash crypto.Hash + return s.signFn(cryptorand.Reader, msg, noHash) // no specific hash function used +} diff --git a/keystore/corekeys/suikey/key_test.go b/keystore/corekeys/suikey/key_test.go new file mode 100644 index 0000000000..86b95ffadb --- /dev/null +++ b/keystore/corekeys/suikey/key_test.go @@ -0,0 +1,19 @@ +package suikey + +import ( + "encoding/hex" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + "github.com/smartcontractkit/chainlink-common/keystore/internal" +) + +func TestSuiKey(t *testing.T) { + bytes, err := hex.DecodeString("f0d07ab448018b2754475f9a3b580218b0675a1456aad96ad607c7bbd7d9237b") + require.NoError(t, err) + k := KeyFor(internal.NewRaw(bytes)) + assert.Equal(t, "2acd605efc181e2af8a0b8c0686a5e12578efa1253d15a235fa5e5ad970c4b29", k.PublicKeyStr()) + assert.Equal(t, "28ebc047741ac19f2ff459d4ddb8f0c688415650edb103a22e4c66350dbcaff9", k.Account()) +} diff --git a/keystore/corekeys/testutils/utils.go b/keystore/corekeys/testutils/utils.go new file mode 100644 index 0000000000..2e80048f68 --- /dev/null +++ b/keystore/corekeys/testutils/utils.go @@ -0,0 +1,19 @@ +package testutils + +import ( + "testing" + + "github.com/stretchr/testify/require" + + "github.com/smartcontractkit/chainlink-common/keystore/internal" +) + +func RequireEqualKeys(t *testing.T, a, b interface { + ID() string + Raw() internal.Raw +}) { + t.Helper() + require.Equal(t, a.ID(), b.ID(), "ids be equal") + require.Equal(t, a.Raw(), b.Raw(), "raw bytes must be equal") + require.EqualExportedValues(t, a, b) +} diff --git a/keystore/corekeys/tonkey/export.go b/keystore/corekeys/tonkey/export.go new file mode 100644 index 0000000000..bcb94a011f --- /dev/null +++ b/keystore/corekeys/tonkey/export.go @@ -0,0 +1,49 @@ +package tonkey + +import ( + "encoding/hex" + + "github.com/ethereum/go-ethereum/accounts/keystore" + + "github.com/smartcontractkit/chainlink-common/keystore/internal" + "github.com/smartcontractkit/chainlink-common/keystore/scrypt" +) + +const keyTypeIdentifier = "TON" + +// FromEncryptedJSON gets key from json and password +func FromEncryptedJSON(keyJSON []byte, password string) (Key, error) { + builder := func(_ internal.EncryptedKeyExport, rawPrivKey internal.Raw) (Key, error) { + return KeyFor(rawPrivKey), nil + } + return internal.FromEncryptedJSON( + keyTypeIdentifier, + keyJSON, + password, + adulteratedPassword, + builder, + ) +} + +// ToEncryptedJSON returns encrypted JSON representing key +func (key Key) ToEncryptedJSON(password string, scryptParams scrypt.ScryptParams) ([]byte, error) { + exporter := func(id string, key Key, cryptoJSON keystore.CryptoJSON) internal.EncryptedKeyExport { + return internal.EncryptedKeyExport{ + KeyType: id, + PublicKey: hex.EncodeToString(key.pubKey), + Crypto: cryptoJSON, + } + } + return internal.ToEncryptedJSON( + keyTypeIdentifier, + key, + password, + scryptParams, + adulteratedPassword, + exporter, + ) +} + +func adulteratedPassword(password string) string { + return "tonkey" + password +} diff --git a/keystore/corekeys/tonkey/export_test.go b/keystore/corekeys/tonkey/export_test.go new file mode 100644 index 0000000000..cc9ad9065f --- /dev/null +++ b/keystore/corekeys/tonkey/export_test.go @@ -0,0 +1,17 @@ +package tonkey + +import ( + "testing" +) + +func TestTONKeys_ExportImport(t *testing.T) { + corekeys2.RunKeyExportImportTestcase(t, createKey, decryptKey) +} + +func createKey() (corekeys2.KeyType, error) { + return New() +} + +func decryptKey(keyJSON []byte, password string) (corekeys2.KeyType, error) { + return FromEncryptedJSON(keyJSON, password) +} diff --git a/keystore/corekeys/tonkey/key.go b/keystore/corekeys/tonkey/key.go new file mode 100644 index 0000000000..c371c0b0b2 --- /dev/null +++ b/keystore/corekeys/tonkey/key.go @@ -0,0 +1,141 @@ +package tonkey + +import ( + "context" + "crypto" + "crypto/ed25519" + crypto_rand "crypto/rand" + "encoding/hex" + "fmt" + "io" + "time" + + "github.com/smartcontractkit/chainlink-common/keystore/internal" + + "github.com/xssnick/tonutils-go/address" + "github.com/xssnick/tonutils-go/ton/wallet" +) + +var ( + // defaultWalletVersion is the default wallet configuration used for Highload V3 wallet addresses. + defaultWalletVersion = wallet.ConfigHighloadV3{ + MessageTTL: 120, // 2 minutes TTL + MessageBuilder: func(ctx context.Context, subWalletId uint32) (id uint32, createdAt int64, err error) { + tm := time.Now().Unix() - 30 + return uint32(10000 + tm%(1<<23)), tm, nil + }, + } + + // defaultWorkchain is the default workchain ID for generating wallet addresses. + // revive:disable:var-declaration // explicit 0 for readiness purposes + defaultWorkchain int8 = 0 +) + +// Key represents a TON ed25519 key +type Key struct { + raw internal.Raw + signFn func(io.Reader, []byte, crypto.SignerOpts) ([]byte, error) + pubKey ed25519.PublicKey +} + +// KeyFor loads a Key from a raw seed +func KeyFor(raw internal.Raw) Key { + seed := internal.Bytes(raw) + privKey := ed25519.NewKeyFromSeed(seed) + pubKey := privKey.Public().(ed25519.PublicKey) + + return Key{ + raw: raw, + signFn: privKey.Sign, + pubKey: pubKey, + } +} + +// New creates a new Key using secure randomness +func New() (Key, error) { + reader := crypto_rand.Reader + return newFrom(reader) +} + +// newFrom creates a new Key from a reader +func newFrom(reader io.Reader) (Key, error) { + pub, priv, err := ed25519.GenerateKey(reader) + if err != nil { + return Key{}, err + } + rawSeed := priv.Seed() + return Key{ + raw: internal.NewRaw(rawSeed), + signFn: priv.Sign, + pubKey: pub, + }, nil +} + +// MustNewInsecure creates a Key or panics if an error occurs +func MustNewInsecure(reader io.Reader) Key { + key, err := newFrom(reader) + if err != nil { + panic(err) + } + return key +} + +// ID returns the hex-encoded public key (same as PublicKeyStr) +func (key Key) ID() string { + return key.PublicKeyStr() +} + +// PublicKeyStr returns the hex-encoded public key +func (key Key) PublicKeyStr() string { + return hex.EncodeToString(key.pubKey) +} + +// GetPublic returns the raw ed25519 public key bytes +func (key Key) GetPublic() ed25519.PublicKey { + return key.pubKey +} + +// Raw returns the private key seed +func (key Key) Raw() internal.Raw { + return key.raw +} + +// Sign signs a message using ed25519 +func (key Key) Sign(msg []byte) ([]byte, error) { + rng := crypto_rand.Reader + hash := crypto.Hash(0) + return key.signFn(rng, msg, hash) +} + +// PubkeyToAddressWith returns the TON wallet address for the given wallet version and workchain +func (key Key) PubkeyToAddressWith(version wallet.VersionConfig, workchain int8) (*address.Address, error) { + privKey := ed25519.NewKeyFromSeed(internal.Bytes(key.raw)) + w, err := wallet.FromPrivateKeyWithOptions(nil, privKey, version, wallet.WithWorkchain(workchain)) + if err != nil { + return nil, fmt.Errorf("failed to create wallet: %w", err) + } + return w.WalletAddress(), nil +} + +// PubkeyToAddress returns the wallet v3 address for workchain 0 +func (key Key) PubkeyToAddress() *address.Address { + addr, err := key.PubkeyToAddressWith(defaultWalletVersion, defaultWorkchain) + if err != nil { + panic(fmt.Errorf("failed to get address: %w", err)) + } + return addr +} + +// AddressBase64 returns the user-friendly version of the TON address +// https://docs.ton.org/v3/concepts/dive-into-ton/ton-blockchain/smart-contract-addresses#user-friendly-address +func (key Key) AddressBase64() string { + address := key.PubkeyToAddress() + return address.String() +} + +// RawAddress returns the raw version of the TON address, which includes the workchain +// https://docs.ton.org/v3/concepts/dive-into-ton/ton-blockchain/smart-contract-addresses#raw-address +func (key Key) RawAddress() string { + address := key.PubkeyToAddress() + return address.StringRaw() +} diff --git a/keystore/corekeys/tonkey/key_test.go b/keystore/corekeys/tonkey/key_test.go new file mode 100644 index 0000000000..e8e9ab20ec --- /dev/null +++ b/keystore/corekeys/tonkey/key_test.go @@ -0,0 +1,142 @@ +package tonkey + +import ( + "crypto/ed25519" + "encoding/base64" + "encoding/hex" + "strings" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "github.com/xssnick/tonutils-go/address" + "github.com/xssnick/tonutils-go/ton/wallet" +) + +func TestTONKey(t *testing.T) { + t.Run("Generate new key and verify its components", func(t *testing.T) { + // Generate a new key + key, err := New() + require.NoError(t, err, "Failed to generate new TONKey") + + // Verify key components + assert.NotNil(t, key.pubKey, "Public key should not be nil") + assert.NotNil(t, key.raw, "Private key should not be nil") + + addressBase64 := key.AddressBase64() + + assert.Len(t, addressBase64, 48, "Address in base64 should be 48 chars") + + decodedAddress, err := base64.RawURLEncoding.DecodeString(addressBase64) + if err != nil { + require.NoError(t, err, "Failed to decode addressBase64") + } + + assert.Len(t, decodedAddress, 36, "Decoded address should be 36 bytes") + }) + + t.Run("Generate new key and verify its components", func(t *testing.T) { + // Generate a new key + key, err := New() + require.NoError(t, err, "Failed to generate new TONKey") + + // Verify key components + assert.NotNil(t, key.pubKey, "Public key should not be nil") + assert.NotNil(t, key.raw, "Private key should not be nil") + }) + + t.Run("Signature is valid and verifiable", func(t *testing.T) { + key, err := New() + require.NoError(t, err) + + msg := []byte("test message") + sig, err := key.Sign(msg) + require.NoError(t, err) + + valid := ed25519.Verify(key.GetPublic(), msg, sig) + assert.True(t, valid, "Signature should be valid") + }) + + t.Run("Public key string encoding is consistent", func(t *testing.T) { + key, err := New() + require.NoError(t, err) + + pubKeyStr := key.PublicKeyStr() + decoded, err := hex.DecodeString(pubKeyStr) + require.NoError(t, err) + + assert.Equal(t, []byte(key.GetPublic()), decoded, "Decoded public key should match original") + }) + + t.Run("MustNewInsecure should not panic on valid reader", func(t *testing.T) { + assert.NotPanics(t, func() { + MustNewInsecure(strings.NewReader("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ012345")) // 64 bytes + }) + }) + + t.Run("Custom wallet version and workchain gives valid address", func(t *testing.T) { + key, err := New() + require.NoError(t, err) + + addr, err := key.PubkeyToAddressWith(wallet.V4R1, -1) + require.NoError(t, err) + assert.NotNil(t, addr) + + // Check that the base64 address is decodable and has expected length + decoded, err := base64.RawURLEncoding.DecodeString(addr.String()) + require.NoError(t, err, "base64 address should be valid base64") + assert.Len(t, decoded, 36, "Decoded address should be 36 bytes") + }) + + t.Run("Same key produces different addresses for different wallet versions and workchains", func(t *testing.T) { + key, err := New() + require.NoError(t, err) + + addrV3WC0, err := key.PubkeyToAddressWith(wallet.V3, 0) + require.NoError(t, err) + + addrV4WC0, err := key.PubkeyToAddressWith(wallet.V4R1, 0) + require.NoError(t, err) + + addrV3WC1, err := key.PubkeyToAddressWith(wallet.V3, 1) + require.NoError(t, err) + + addrV3WCMinus1, err := key.PubkeyToAddressWith(wallet.V3, -1) + require.NoError(t, err) + + // Assert addresses are all different + assert.NotEqual(t, addrV3WC0.String(), addrV4WC0.String(), "V3 and V4 addresses should differ") + assert.NotEqual(t, addrV3WC0.String(), addrV3WC1.String(), "Workchain 0 and 1 addresses should differ") + assert.NotEqual(t, addrV3WC0.String(), addrV3WCMinus1.String(), "Workchain 0 and -1 addresses should differ") + }) + + t.Run("RawAddress returns correct non-base64 address", func(t *testing.T) { + key, err := New() + require.NoError(t, err) + + rawAddress := key.RawAddress() + addressBase64 := key.AddressBase64() + + assert.NotEmpty(t, rawAddress, "Raw address should not be empty") + assert.NotEqual(t, addressBase64, rawAddress, "Raw and base64 addresses should differ") + + // Parse raw address and validate + parsed, err := address.ParseRawAddr(rawAddress) + require.NoError(t, err, "Raw address should be parseable") + assert.Equal(t, rawAddress, parsed.StringRaw(), "Parsed raw address should match original") + + // Default workchain is 0 + assert.True(t, strings.HasPrefix(rawAddress, "0:"), "Expected raw address to start with '0:' for default workchain") + }) + + t.Run("KeyFor and Raw produce consistent keys", func(t *testing.T) { + key1, err := New() + require.NoError(t, err) + + raw := key1.Raw() + key2 := KeyFor(raw) + + assert.Equal(t, key1.PublicKeyStr(), key2.PublicKeyStr(), "Restored key should have same public key") + assert.Equal(t, key1.AddressBase64(), key2.AddressBase64(), "Restored key should have same address") + }) +} diff --git a/keystore/corekeys/tronkey/account.go b/keystore/corekeys/tronkey/account.go new file mode 100644 index 0000000000..9c90422d2a --- /dev/null +++ b/keystore/corekeys/tronkey/account.go @@ -0,0 +1,178 @@ +package tronkey + +import ( + "crypto/ecdsa" + "crypto/sha256" + "encoding/hex" + "errors" + "fmt" + "math/big" + + "github.com/ethereum/go-ethereum/crypto" + "github.com/mr-tron/base58" +) + +// Extracted from go-tron sdk: https://github.com/fbsobreira/gotron-sdk + +const ( + // HashLength is the expected length of the hash + HashLength = 32 + // AddressLengthBase58 is the expected length of the address in base58format + AddressLengthBase58 = 34 + // Tron Address Prefix + prefixMainnet = 0x41 + // TronBytePrefix is the hex prefix to address + TronBytePrefix = byte(prefixMainnet) + // Tron address should have 21 bytes (20 bytes + 1 byte prefix) + AddressLength = 21 +) + +// Address represents the 21 byte address of an Tron account. +type Address [AddressLength]byte + +// Bytes get bytes from address +func (a Address) Bytes() []byte { + return a[:] +} + +// Hex get bytes from address in string +func (a Address) Hex() string { + return BytesToHexString(a[:]) +} + +// HexToAddress returns Address with byte values of s. +func HexToAddress(s string) (Address, error) { + addr, err := FromHex(s) + if err != nil { + return Address{}, err + } + // Check if the address starts with '41' and is 21 characters long + if len(addr) != AddressLength || addr[0] != prefixMainnet { + return Address{}, errors.New("invalid Tron address") + } + return Address(addr), nil +} + +// Base58ToAddress returns Address with byte values of s. +func Base58ToAddress(s string) (Address, error) { + addr, err := DecodeCheck(s) + if err != nil { + return Address{}, err + } + return Address(addr), nil +} + +// String implements fmt.Stringer. +// Returns the address as a base58 encoded string. +func (a Address) String() string { + if len(a) == 0 { + return "" + } + + if a[0] == 0 { + return new(big.Int).SetBytes(a.Bytes()).String() + } + return EncodeCheck(a.Bytes()) +} + +// PubkeyToAddress returns address from ecdsa public key +func PubkeyToAddress(p ecdsa.PublicKey) Address { + address := crypto.PubkeyToAddress(p) + + addressTron := make([]byte, 0) + addressTron = append(addressTron, TronBytePrefix) + addressTron = append(addressTron, address.Bytes()...) + return Address(addressTron) +} + +// BytesToHexString encodes bytes as a hex string. +func BytesToHexString(bytes []byte) string { + encode := make([]byte, len(bytes)*2) + hex.Encode(encode, bytes) + return "0x" + string(encode) +} + +// FromHex returns the bytes represented by the hexadecimal string s. +// s may be prefixed with "0x". +func FromHex(s string) ([]byte, error) { + if Has0xPrefix(s) { + s = s[2:] + } + if len(s)%2 == 1 { + s = "0" + s + } + return HexToBytes(s) +} + +// Has0xPrefix validates str begins with '0x' or '0X'. +func Has0xPrefix(str string) bool { + return len(str) >= 2 && str[0] == '0' && (str[1] == 'x' || str[1] == 'X') +} + +// HexToBytes returns the bytes represented by the hexadecimal string str. +func HexToBytes(str string) ([]byte, error) { + return hex.DecodeString(str) +} + +func Encode(input []byte) string { + return base58.Encode(input) +} + +func EncodeCheck(input []byte) string { + h256h0 := sha256.New() + h256h0.Write(input) + h0 := h256h0.Sum(nil) + + h256h1 := sha256.New() + h256h1.Write(h0) + h1 := h256h1.Sum(nil) + + inputCheck := input + inputCheck = append(inputCheck, h1[:4]...) + + return Encode(inputCheck) +} + +func DecodeCheck(input string) ([]byte, error) { + decodeCheck, err := Decode(input) + if err != nil { + return nil, err + } + + if len(decodeCheck) < 4 { + return nil, errors.New("base58 check error") + } + + // tron address should should have 21 bytes (including prefix) + 4 checksum + if len(decodeCheck) != AddressLength+4 { + return nil, fmt.Errorf("invalid address length: %d", len(decodeCheck)) + } + + // check prefix + if decodeCheck[0] != prefixMainnet { + return nil, errors.New("invalid prefix") + } + + decodeData := decodeCheck[:len(decodeCheck)-4] + + h256h0 := sha256.New() + h256h0.Write(decodeData) + h0 := h256h0.Sum(nil) + + h256h1 := sha256.New() + h256h1.Write(h0) + h1 := h256h1.Sum(nil) + + if h1[0] == decodeCheck[len(decodeData)] && + h1[1] == decodeCheck[len(decodeData)+1] && + h1[2] == decodeCheck[len(decodeData)+2] && + h1[3] == decodeCheck[len(decodeData)+3] { + return decodeData, nil + } + + return nil, errors.New("base58 check error") +} + +func Decode(input string) ([]byte, error) { + return base58.Decode(input) +} diff --git a/keystore/corekeys/tronkey/account_test.go b/keystore/corekeys/tronkey/account_test.go new file mode 100644 index 0000000000..9a92801bb1 --- /dev/null +++ b/keystore/corekeys/tronkey/account_test.go @@ -0,0 +1,177 @@ +package tronkey + +import ( + "bytes" + "regexp" + "strings" + "testing" + + "github.com/stretchr/testify/require" +) + +func Test_DecodeBase58(t *testing.T) { + invalidAddresses := []string{ + "TronEnergyioE1Z3ukeRv38sYkv5Jn55bL", + "TronEnergyioNijNo8g3LF2ABKUAae6D2Z", + "TronEnergyio3ZMcXA5hSjrTxaioKGgqyr", + } + + validAddresses := []string{ + "TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t", + "TVj7RNVHy6thbM7BWdSe9G6gXwKhjhdNZS", + "THPvaUhoh2Qn2y9THCZML3H815hhFhn5YC", + } + + for _, addr := range invalidAddresses { + _, err := DecodeCheck(addr) + require.Error(t, err) + } + + for _, addr := range validAddresses { + _, err := DecodeCheck(addr) + require.NoError(t, err) + } +} + +func TestAddress(t *testing.T) { + t.Run("Valid Addresses", func(t *testing.T) { + validAddresses := []string{ + "TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t", + "TVj7RNVHy6thbM7BWdSe9G6gXwKhjhdNZS", + "THPvaUhoh2Qn2y9THCZML3H815hhFhn5YC", + } + + for _, addrStr := range validAddresses { + t.Run(addrStr, func(t *testing.T) { + addr, err := Base58ToAddress(addrStr) + require.NoError(t, err) + require.Equal(t, addrStr, addr.String()) + + decoded, err := DecodeCheck(addrStr) + require.NoError(t, err) + require.True(t, bytes.Equal(decoded, addr.Bytes())) + }) + } + }) + + t.Run("Invalid Addresses", func(t *testing.T) { + invalidAddresses := []string{ + "TronEnergyioE1Z3ukeRv38sYkv5Jn55bL", + "TronEnergyioNijNo8g3LF2ABKUAae6D2Z", + "TronEnergyio3ZMcXA5hSjrTxaioKGgqyr", + } + + for _, addrStr := range invalidAddresses { + t.Run(addrStr, func(t *testing.T) { + _, err := Base58ToAddress(addrStr) + require.Error(t, err) + + _, err = DecodeCheck(addrStr) + require.Error(t, err) + }) + } + }) + + t.Run("Address Conversion", func(t *testing.T) { + addrStr := "TSvT6Bg3siokv3dbdtt9o4oM1CTXmymGn1" + addr, err := Base58ToAddress(addrStr) + require.NoError(t, err) + + t.Run("To Bytes", func(t *testing.T) { + bytes := addr.Bytes() + require.Len(t, bytes, 21) + }) + + t.Run("To Hex", func(t *testing.T) { + hex := addr.Hex() + require.Equal(t, "0x", hex[:2]) + require.Len(t, hex, 44) + }) + }) + + t.Run("Address Validity", func(t *testing.T) { + t.Run("Valid Address", func(t *testing.T) { + addr, err := Base58ToAddress("TSvT6Bg3siokv3dbdtt9o4oM1CTXmymGn1") + require.NoError(t, err) + require.True(t, isValid(addr)) + }) + + t.Run("Zero Address", func(t *testing.T) { + addr := Address{} + require.False(t, isValid(addr)) + }) + }) +} + +func TestHexToAddress(t *testing.T) { + t.Run("Valid Hex Addresses", func(t *testing.T) { + validHexAddresses := []string{ + "41a614f803b6fd780986a42c78ec9c7f77e6ded13c", + "41b2a2e1b2e1b2e1b2e1b2e1b2e1b2e1b2e1b2e1b2", + "41c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3", + } + + for _, hexStr := range validHexAddresses { + t.Run(hexStr, func(t *testing.T) { + addr, err := HexToAddress(hexStr) + require.NoError(t, err) + require.Equal(t, "0x"+hexStr, addr.Hex()) + }) + } + }) + + t.Run("Invalid Hex Addresses", func(t *testing.T) { + invalidHexAddresses := []string{ + "41a614f803b6fd780986a42c78ec9c7f77e6ded13", // Too short + "41b2a2e1b2e1b2e1b2e1b2e1b2e1b2e1b2e1b2e1b2e1b2", // Too long + "41g3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3", // Invalid character 'g' + "c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3c3", // Missing prefix '41' + } + + for _, hexStr := range invalidHexAddresses { + t.Run(hexStr, func(t *testing.T) { + _, err := HexToAddress(hexStr) + require.Error(t, err) + }) + } + }) +} + +// Helper Functions for testing + +// isValid checks if the address is a valid TRON address +func isValid(a Address) bool { + // Check if it's a valid Base58 address + base58Str := a.String() + if isValidBase58Address(base58Str) { + return true + } + + // Check if it's a valid hex address + hexStr := a.Hex() + return isValidHexAddress(strings.TrimPrefix(hexStr, "0x")) +} + +// isValidBase58Address check if a string is a valid Base58 TRON address +func isValidBase58Address(address string) bool { + // Check if the address starts with 'T' and is 34 characters long + if len(address) != 34 || address[0] != 'T' { + return false + } + + // Check if the address contains only valid Base58 characters + validChars := regexp.MustCompile("^[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]+$") + return validChars.MatchString(address) +} + +// isValidHexAddressto check if a string is a valid hex TRON address +func isValidHexAddress(address string) bool { + // Check if the address starts with '41' and is 42 characters long + if len(address) != 42 || address[:2] != "41" { + return false + } + + // Check if the address contains only valid hexadecimal characters + validChars := regexp.MustCompile("^[0-9A-Fa-f]+$") + return validChars.MatchString(address[2:]) // Check the part after '41' +} diff --git a/keystore/corekeys/tronkey/export.go b/keystore/corekeys/tronkey/export.go new file mode 100644 index 0000000000..4e897ce8a9 --- /dev/null +++ b/keystore/corekeys/tronkey/export.go @@ -0,0 +1,45 @@ +package tronkey + +import ( + "github.com/ethereum/go-ethereum/accounts/keystore" + + "github.com/smartcontractkit/chainlink-common/keystore/internal" + "github.com/smartcontractkit/chainlink-common/keystore/scrypt" +) + +const keyTypeIdentifier = "Tron" + +// FromEncryptedJSON gets key from json and password +func FromEncryptedJSON(keyJSON []byte, password string) (Key, error) { + return internal.FromEncryptedJSON( + keyTypeIdentifier, + keyJSON, + password, + adulteratedPassword, + func(_ internal.EncryptedKeyExport, rawPrivKey internal.Raw) (Key, error) { + return KeyFor(rawPrivKey), nil + }, + ) +} + +// ToEncryptedJSON returns encrypted JSON representing key +func (key Key) ToEncryptedJSON(password string, scryptParams scrypt.ScryptParams) (export []byte, err error) { + return internal.ToEncryptedJSON( + keyTypeIdentifier, + key, + password, + scryptParams, + adulteratedPassword, + func(id string, key Key, cryptoJSON keystore.CryptoJSON) internal.EncryptedKeyExport { + return internal.EncryptedKeyExport{ + KeyType: id, + PublicKey: key.PublicKeyStr(), + Crypto: cryptoJSON, + } + }, + ) +} + +func adulteratedPassword(password string) string { + return "tronkey" + password +} diff --git a/keystore/corekeys/tronkey/export_test.go b/keystore/corekeys/tronkey/export_test.go new file mode 100644 index 0000000000..5dd2ad4900 --- /dev/null +++ b/keystore/corekeys/tronkey/export_test.go @@ -0,0 +1,17 @@ +package tronkey + +import ( + "testing" +) + +func TestTronKeys_ExportImport(t *testing.T) { + corekeys2.RunKeyExportImportTestcase(t, createKey, decryptKey) +} + +func createKey() (corekeys2.KeyType, error) { + return New() +} + +func decryptKey(keyJSON []byte, password string) (corekeys2.KeyType, error) { + return FromEncryptedJSON(keyJSON, password) +} diff --git a/keystore/corekeys/tronkey/key.go b/keystore/corekeys/tronkey/key.go new file mode 100644 index 0000000000..817e16442c --- /dev/null +++ b/keystore/corekeys/tronkey/key.go @@ -0,0 +1,84 @@ +package tronkey + +import ( + "crypto/ecdsa" + "crypto/rand" + "encoding/hex" + "io" + "math/big" + + "github.com/ethereum/go-ethereum/crypto" + + "github.com/smartcontractkit/chainlink-common/keystore/internal" +) + +// Tron uses the same elliptic curve cryptography as Ethereum (ECDSA with secp256k1) +var curve = crypto.S256() + +// Key generates a public-private key pair from the raw private key +func KeyFor(raw internal.Raw) Key { + var privKey ecdsa.PrivateKey + d := big.NewInt(0).SetBytes(internal.Bytes(raw)) + privKey.Curve = curve + privKey.D = d + privKey.X, privKey.Y = curve.ScalarBaseMult(d.Bytes()) + return Key{ + raw: raw, + signFn: func(bytes []byte) ([]byte, error) { return crypto.Sign(bytes, &privKey) }, + pubKey: &privKey.PublicKey, + } +} + +type Key struct { + raw internal.Raw + signFn func([]byte) ([]byte, error) + + pubKey *ecdsa.PublicKey +} + +func New() (Key, error) { + return newFrom(rand.Reader) +} + +// MustNewInsecure return Key if no error +// This insecure function is used for testing purposes only +func MustNewInsecure(reader io.Reader) Key { + key, err := newFrom(reader) + if err != nil { + panic(err) + } + return key +} + +func newFrom(reader io.Reader) (Key, error) { + privKeyECDSA, err := ecdsa.GenerateKey(curve, reader) + if err != nil { + return Key{}, err + } + return Key{ + raw: internal.NewRaw(privKeyECDSA.D.Bytes()), + signFn: func(bytes []byte) ([]byte, error) { return crypto.Sign(bytes, privKeyECDSA) }, + pubKey: &privKeyECDSA.PublicKey, + }, nil +} + +func (key Key) ID() string { + return key.Base58Address() +} + +func (key Key) Raw() internal.Raw { return key.raw } + +// Sign is used to sign a message +func (key Key) Sign(msg []byte) ([]byte, error) { return key.signFn(msg) } + +// PublicKeyStr returns the public key as a hexadecimal string +func (key Key) PublicKeyStr() string { + pubKeyBytes := crypto.FromECDSAPub(key.pubKey) + return hex.EncodeToString(pubKeyBytes) +} + +// Base58Address returns the Tron address in Base58 format with checksum +func (key Key) Base58Address() string { + address := PubkeyToAddress(*key.pubKey) + return address.String() +} diff --git a/keystore/corekeys/tronkey/key_test.go b/keystore/corekeys/tronkey/key_test.go new file mode 100644 index 0000000000..9ec74946f9 --- /dev/null +++ b/keystore/corekeys/tronkey/key_test.go @@ -0,0 +1,63 @@ +package tronkey + +import ( + "encoding/hex" + "testing" + + "github.com/ethereum/go-ethereum/crypto" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestTronKeyNewKeyGeneration(t *testing.T) { + t.Run("Generate new key and verify its components", func(t *testing.T) { + // Generate a new key + key, err := New() + require.NoError(t, err, "Failed to generate new TronKey") + + // Verify key components + assert.NotNil(t, key.pubKey, "Public key should not be nil") + assert.NotNil(t, key.raw, "Private key should not be nil") + }) + + t.Run("Multiple key generations produce unique keys", func(t *testing.T) { + key1, err := New() + require.NoError(t, err, "Failed to generate first key") + + key2, err := New() + require.NoError(t, err, "Failed to generate second key") + + assert.NotEqual(t, key1.raw, key2.raw, "Generated private keys should be unique") + assert.NotEqual(t, key1.pubKey, key2.pubKey, "Generated public keys should be unique") + }) +} + +func TestKeyAddress(t *testing.T) { + t.Run("Known private key and expected address", func(t *testing.T) { + // Tests cases from https://developers.tron.network/docs/account + privateKeyHex := "b406adb115b43e103c7b1dc8b5931f63279a5b6b2cf7328638814c43171a2908" + expectedAddress := "TDdcf5iMDkB61oGM27TNak55eVX214thBG" + + privateKeyBytes, err := hex.DecodeString(privateKeyHex) + require.NoError(t, err, "Failed to decode private key hex") + + privateKey, err := crypto.ToECDSA(privateKeyBytes) + require.NoError(t, err, "Failed to convert private key to ECDSA") + + key := Key{pubKey: &privateKey.PublicKey} + + address := key.Base58Address() + require.Equal(t, expectedAddress, address, "Generated address does not match expected address") + }) + + t.Run("Generate new key and check address format", func(t *testing.T) { + newKey, err := New() + if err != nil { + t.Fatalf("Failed to generate new key: %v", err) + } + + newAddress := newKey.Base58Address() + isValid := isValidBase58Address(newAddress) + require.True(t, isValid, "Generated address is not valid") + }) +} diff --git a/keystore/corekeys/vrfkey/benchmark_vrf_validation_test.go b/keystore/corekeys/vrfkey/benchmark_vrf_validation_test.go new file mode 100644 index 0000000000..6a699bb28d --- /dev/null +++ b/keystore/corekeys/vrfkey/benchmark_vrf_validation_test.go @@ -0,0 +1,26 @@ +package vrfkey + +import ( + "math/big" + "testing" + + "github.com/stretchr/testify/require" +) + +// Run with `go test -bench BenchmarkProofValidation` +func BenchmarkProofValidation(b *testing.B) { + key, err := NewV2() + require.NoError(b, err) + var proofs []Proof + for i := 0; b.Loop(); i++ { + p, err := key.GenerateProof(big.NewInt(int64(i))) + require.NoError(b, err, "failed to generate proof number %d", i) + proofs = append(proofs, p) + } + b.ResetTimer() + for i, p := range proofs { + isValid, err := p.VerifyVRFProof() + require.NoError(b, err, "failed to check proof number %d", i) + require.True(b, isValid, "proof number %d is invalid", i) + } +} diff --git a/keystore/corekeys/vrfkey/crypto.go b/keystore/corekeys/vrfkey/crypto.go new file mode 100644 index 0000000000..6c4833d573 --- /dev/null +++ b/keystore/corekeys/vrfkey/crypto.go @@ -0,0 +1,188 @@ +package vrfkey + +import ( + "errors" + "fmt" + "math/big" + + "github.com/ethereum/go-ethereum/common" + "go.dedis.ch/kyber/v3" + + "github.com/smartcontractkit/chainlink-common/pkg/utils/hex" + + "github.com/smartcontractkit/chainlink-evm/pkg/utils" + "github.com/smartcontractkit/chainlink/v2/core/services/signatures/secp256k1" + bm "github.com/smartcontractkit/chainlink/v2/core/utils/big_math" +) + +// This file contains golang re-implementations of functions on the VRF solidity +// contract. They are used to verify correct operation of those functions, and +// also to efficiently compute zInv off-chain, which makes computing the linear +// combination of c*gamma+s*hash onchain much more efficient. + +var ( + // FieldSize is number of elements in secp256k1's base field, i.e. GF(FieldSize) + FieldSize = mustParseBig( + "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F", + ) + Secp256k1Curve = &secp256k1.Secp256k1{} + Generator = Secp256k1Curve.Point().Base() + eulersCriterionPower = bm.Div(bm.Sub(FieldSize, bm.One), bm.Two) + sqrtPower = bm.Div(bm.Add(FieldSize, bm.One), bm.Four) + ErrCGammaEqualsSHash = errors.New("pick a different nonce; c*gamma = s*hash, with this one") + // hashToCurveHashPrefix is domain-separation tag for initial HashToCurve hash. + // Corresponds to HASH_TO_CURVE_HASH_PREFIX in VRF.sol. + hashToCurveHashPrefix = common.BigToHash(bm.One).Bytes() + // scalarFromCurveHashPrefix is a domain-separation tag for the hash taken in + // ScalarFromCurve. Corresponds to SCALAR_FROM_CURVE_POINTS_HASH_PREFIX in + // VRF.sol. + scalarFromCurveHashPrefix = common.BigToHash(bm.Two).Bytes() + // RandomOutputHashPrefix is a domain-separation tag for the hash used to + // compute the final VRF random output + RandomOutputHashPrefix = common.BigToHash(bm.Three).Bytes() +) + +type fieldElt = *big.Int + +// neg(f) is the negation of f in the base field +func neg(f fieldElt) fieldElt { return bm.Sub(FieldSize, f) } + +// projectiveSub(x1, z1, x2, z2) is the projective coordinates of x1/z1 - x2/z2 +func projectiveSub(x1, z1, x2, z2 fieldElt) (fieldElt, fieldElt) { + num1 := bm.Mul(z2, x1) + num2 := neg(bm.Mul(z1, x2)) + return bm.Mod(bm.Add(num1, num2), FieldSize), bm.Mod(bm.Mul(z1, z2), FieldSize) +} + +// projectiveMul(x1, z1, x2, z2) is projective coordinates of (x1/z1)×(x2/z2) +func projectiveMul(x1, z1, x2, z2 fieldElt) (fieldElt, fieldElt) { + return bm.Mul(x1, x2), bm.Mul(z1, z2) +} + +// ProjectiveECAdd(px, py, qx, qy) duplicates the calculation in projective +// coordinates of VRF.sol#projectiveECAdd, so we can reliably get the +// denominator (i.e, z) +func ProjectiveECAdd(p, q kyber.Point) (x, y, z fieldElt) { + px, py := secp256k1.Coordinates(p) + qx, qy := secp256k1.Coordinates(q) + pz, qz := bm.One, bm.One + lx := bm.Sub(qy, py) + lz := bm.Sub(qx, px) + + sx, dx := projectiveMul(lx, lz, lx, lz) + sx, dx = projectiveSub(sx, dx, px, pz) + sx, dx = projectiveSub(sx, dx, qx, qz) + + sy, dy := projectiveSub(px, pz, sx, dx) + sy, dy = projectiveMul(sy, dy, lx, lz) + sy, dy = projectiveSub(sy, dy, py, pz) + + var sz fieldElt + if dx != dy { + sx = bm.Mul(sx, dy) + sy = bm.Mul(sy, dx) + sz = bm.Mul(dx, dy) + } else { + sz = dx + } + return bm.Mod(sx, FieldSize), bm.Mod(sy, FieldSize), bm.Mod(sz, FieldSize) +} + +// IsSquare returns true iff x = y^2 for some y in GF(p) +func IsSquare(x *big.Int) bool { + return bm.Equal(bm.One, bm.Exp(x, eulersCriterionPower, FieldSize)) +} + +// SquareRoot returns a s.t. a^2=x, as long as x is a square +func SquareRoot(x *big.Int) *big.Int { + return bm.Exp(x, sqrtPower, FieldSize) +} + +// YSquared returns x^3+7 mod fieldSize, the right-hand side of the secp256k1 +// curve equation. +func YSquared(x *big.Int) *big.Int { + return bm.Mod(bm.Add(bm.Exp(x, bm.Three, FieldSize), bm.Seven), FieldSize) +} + +// IsCurveXOrdinate returns true iff there is y s.t. y^2=x^3+7 +func IsCurveXOrdinate(x *big.Int) bool { + return IsSquare(YSquared(x)) +} + +// FieldHash hashes xs uniformly into {0, ..., fieldSize-1}. msg is assumed to +// already be a 256-bit hash +func FieldHash(msg []byte) *big.Int { + rv := utils.MustHash(string(msg)).Big() + // Hash recursively until rv < q. P(success per iteration) >= 0.5, so + // number of extra hashes is geometrically distributed, with mean < 1. + for rv.Cmp(FieldSize) >= 0 { + rv = utils.MustHash(string(common.BigToHash(rv).Bytes())).Big() + } + return rv +} + +// linearCombination returns c*p1+s*p2 +func linearCombination(c *big.Int, p1 kyber.Point, + s *big.Int, p2 kyber.Point) kyber.Point { + return Secp256k1Curve.Point().Add( + Secp256k1Curve.Point().Mul(secp256k1.IntToScalar(c), p1), + Secp256k1Curve.Point().Mul(secp256k1.IntToScalar(s), p2)) +} + +// checkCGammaNotEqualToSHash checks c*gamma ≠ s*hash, as required by solidity +// verifier +func checkCGammaNotEqualToSHash(c *big.Int, gamma kyber.Point, s *big.Int, + hash kyber.Point) error { + cGamma := Secp256k1Curve.Point().Mul(secp256k1.IntToScalar(c), gamma) + sHash := Secp256k1Curve.Point().Mul(secp256k1.IntToScalar(s), hash) + if cGamma.Equal(sHash) { + return ErrCGammaEqualsSHash + } + return nil +} + +// HashToCurve is a cryptographic hash function which outputs a secp256k1 point, +// or an error. It passes each candidate x ordinate to ordinates function. +func HashToCurve(p kyber.Point, input *big.Int, ordinates func(x *big.Int), +) (kyber.Point, error) { + if !secp256k1.ValidPublicKey(p) || input.BitLen() > 256 || input.Cmp(bm.Zero) < 0 { + return nil, errors.New("bad input to vrf.HashToCurve") + } + x := FieldHash(append(hashToCurveHashPrefix, append(secp256k1.LongMarshal(p), + utils.Uint256ToBytes32(input)...)...)) + ordinates(x) + for !IsCurveXOrdinate(x) { // Hash recursively until x^3+7 is a square + x.Set(FieldHash(common.BigToHash(x).Bytes())) + ordinates(x) + } + y := SquareRoot(YSquared(x)) + rv := secp256k1.SetCoordinates(x, y) + if bm.Equal(bm.I().Mod(y, bm.Two), bm.One) { // Negate response if y odd + rv = rv.Neg(rv) + } + return rv, nil +} + +// ScalarFromCurve returns a hash for the curve points. Corresponds to the +// hash computed in VRF.sol#ScalarFromCurvePoints +func ScalarFromCurvePoints( + hash, pk, gamma kyber.Point, uWitness [20]byte, v kyber.Point) *big.Int { + if !secp256k1.ValidPublicKey(hash) || !secp256k1.ValidPublicKey(pk) || !secp256k1.ValidPublicKey(gamma) || !secp256k1.ValidPublicKey(v) { + panic("bad arguments to vrf.ScalarFromCurvePoints") + } + // msg will contain abi.encodePacked(hash, pk, gamma, v, uWitness) + msg := scalarFromCurveHashPrefix + for _, p := range []kyber.Point{hash, pk, gamma, v} { + msg = append(msg, secp256k1.LongMarshal(p)...) + } + msg = append(msg, uWitness[:]...) + return bm.I().SetBytes(utils.MustHash(string(msg)).Bytes()) +} + +func mustParseBig(hx string) *big.Int { + n, err := hex.ParseBig(hx) + if err != nil { + panic(fmt.Errorf(`failed to convert "%s" as hex to big.Int`, hx)) + } + return n +} diff --git a/keystore/corekeys/vrfkey/crypto_test.go b/keystore/corekeys/vrfkey/crypto_test.go new file mode 100644 index 0000000000..c81553c99f --- /dev/null +++ b/keystore/corekeys/vrfkey/crypto_test.go @@ -0,0 +1,29 @@ +package vrfkey + +import ( + "math/big" + "testing" + + "github.com/stretchr/testify/assert" + + bm "github.com/smartcontractkit/chainlink/v2/core/utils/big_math" +) + +func TestVRF_IsSquare(t *testing.T) { + assert.True(t, IsSquare(bm.Four)) + minusOneModP := bm.I().Sub(FieldSize, bm.One) + assert.False(t, IsSquare(minusOneModP)) +} + +func TestVRF_SquareRoot(t *testing.T) { + assert.Equal(t, bm.Two, SquareRoot(bm.Four)) +} + +func TestVRF_YSquared(t *testing.T) { + assert.Equal(t, bm.Add(bm.Mul(bm.Two, bm.Mul(bm.Two, bm.Two)), bm.Seven), YSquared(bm.Two)) // 2³+7 +} + +func TestVRF_IsCurveXOrdinate(t *testing.T) { + assert.True(t, IsCurveXOrdinate(big.NewInt(1))) + assert.False(t, IsCurveXOrdinate(big.NewInt(5))) +} diff --git a/keystore/corekeys/vrfkey/export.go b/keystore/corekeys/vrfkey/export.go new file mode 100644 index 0000000000..f6094c594f --- /dev/null +++ b/keystore/corekeys/vrfkey/export.go @@ -0,0 +1,86 @@ +package vrfkey + +import ( + "crypto/ecdsa" + "encoding/json" + + "github.com/ethereum/go-ethereum/accounts/keystore" + "github.com/google/uuid" + "github.com/pkg/errors" + + "github.com/smartcontractkit/chainlink-common/keystore/internal" + "github.com/smartcontractkit/chainlink-common/keystore/scrypt" + "github.com/smartcontractkit/chainlink/v2/core/services/signatures/secp256k1" +) + +func FromEncryptedJSON(keyJSON []byte, password string) (KeyV2, error) { + var export EncryptedVRFKeyExport + if err := json.Unmarshal(keyJSON, &export); err != nil { + return KeyV2{}, err + } + + // NOTE: We do this shuffle to an anonymous struct + // solely to add a throwaway UUID, so we can leverage + // the keystore.DecryptKey from the geth which requires it + // as of 1.10.0. + keyJSON, err := json.Marshal(struct { + Address string `json:"address"` + Crypto keystore.CryptoJSON `json:"crypto"` + Version int `json:"version"` + Id string `json:"id"` + }{ + Address: export.VRFKey.Address, + Crypto: export.VRFKey.Crypto, + Version: export.VRFKey.Version, + Id: uuid.New().String(), + }) + if err != nil { + return KeyV2{}, errors.Wrapf(err, "while marshaling key for decryption") + } + + gethKey, err := keystore.DecryptKey(keyJSON, adulteratedPassword(password)) + if err != nil { + return KeyV2{}, errors.Wrapf(err, "could not decrypt VRF key %s", export.PublicKey.String()) + } + + key := KeyFor(internal.NewRaw(gethKey.PrivateKey.D.Bytes())) + return key, nil +} + +type EncryptedVRFKeyExport struct { + PublicKey secp256k1.PublicKey `json:"PublicKey"` + VRFKey gethKeyStruct `json:"vrf_key"` +} + +func (key KeyV2) ToEncryptedJSON(password string, scryptParams scrypt.ScryptParams) (export []byte, err error) { + cryptoJSON, err := keystore.EncryptKey(key.toGethKey(), adulteratedPassword(password), scryptParams.N, scryptParams.P) + if err != nil { + return nil, errors.Wrapf(err, "failed to encrypt key %s", key.ID()) + } + var gethKey gethKeyStruct + err = json.Unmarshal(cryptoJSON, &gethKey) + if err != nil { + return nil, errors.Wrapf(err, "failed to unmarshal key %s", key.ID()) + } + encryptedOCRKExport := EncryptedVRFKeyExport{ + PublicKey: key.PublicKey, + VRFKey: gethKey, + } + return json.Marshal(encryptedOCRKExport) +} + +func (key KeyV2) toGethKey() *keystore.Key { + return &keystore.Key{ + Address: key.PublicKey.Address(), + PrivateKey: &ecdsa.PrivateKey{D: secp256k1.ToInt(*key.k)}, + } +} + +// passwordPrefix is added to the beginning of the passwords for +// EncryptedVRFKey's, so that VRF keys can't casually be used as ethereum +// keys, and vice-versa. If you want to do that, DON'T. +var passwordPrefix = "don't mix VRF and Ethereum keys!" + +func adulteratedPassword(password string) string { + return passwordPrefix + password +} diff --git a/keystore/corekeys/vrfkey/export_test.go b/keystore/corekeys/vrfkey/export_test.go new file mode 100644 index 0000000000..252458d4fa --- /dev/null +++ b/keystore/corekeys/vrfkey/export_test.go @@ -0,0 +1,17 @@ +package vrfkey + +import ( + "testing" +) + +func TestVRFKeys_ExportImport(t *testing.T) { + corekeys2.RunKeyExportImportTestcase(t, createKey, decryptKey) +} + +func createKey() (corekeys2.KeyType, error) { + return NewV2() +} + +func decryptKey(keyJSON []byte, password string) (corekeys2.KeyType, error) { + return FromEncryptedJSON(keyJSON, password) +} diff --git a/keystore/corekeys/vrfkey/key_v2.go b/keystore/corekeys/vrfkey/key_v2.go new file mode 100644 index 0000000000..aee26bc00c --- /dev/null +++ b/keystore/corekeys/vrfkey/key_v2.go @@ -0,0 +1,153 @@ +package vrfkey + +import ( + "crypto/rand" + "fmt" + "math/big" + + "github.com/ethereum/go-ethereum/common/hexutil" + "github.com/pkg/errors" + "go.dedis.ch/kyber/v3" + + "github.com/smartcontractkit/chainlink-evm/pkg/utils" + + "github.com/smartcontractkit/chainlink-common/keystore/internal" + "github.com/smartcontractkit/chainlink/v2/core/services/signatures/secp256k1" + bm "github.com/smartcontractkit/chainlink/v2/core/utils/big_math" +) + +var suite = secp256k1.NewBlakeKeccackSecp256k1() + +func KeyFor(raw internal.Raw) KeyV2 { + rawKeyInt := new(big.Int).SetBytes(internal.Bytes(raw)) + k := secp256k1.IntToScalar(rawKeyInt) + key, err := keyFromScalar(k) + if err != nil { + panic(err) + } + return key +} + +var _ fmt.GoStringer = &KeyV2{} + +type KeyV2 struct { + k *kyber.Scalar + PublicKey secp256k1.PublicKey +} + +func NewV2() (KeyV2, error) { + k := suite.Scalar().Pick(suite.RandomStream()) + return keyFromScalar(k) +} + +func MustNewV2XXXTestingOnly(k *big.Int) KeyV2 { + rv, err := keyFromScalar(secp256k1.IntToScalar(k)) + if err != nil { + panic(err) + } + return rv +} + +func (key KeyV2) ID() string { + return hexutil.Encode(key.PublicKey[:]) +} + +func (key KeyV2) Raw() internal.Raw { + return internal.NewRaw(secp256k1.ToInt(*key.k).Bytes()) +} + +// GenerateProofWithNonce allows external nonce generation for testing purposes +// +// As with signatures, using nonces which are in any way predictable to an +// adversary will leak your secret key! Most people should use GenerateProof +// instead. +func (key KeyV2) GenerateProofWithNonce(seed, nonce *big.Int) (Proof, error) { + secretKey := secp256k1.ScalarToHash(*key.k).Big() + if !secp256k1.RepresentsScalar(secretKey) || seed.BitLen() > 256 { + return Proof{}, errors.New("badly-formatted key or seed") + } + skAsScalar := secp256k1.IntToScalar(secretKey) + publicKey := Secp256k1Curve.Point().Mul(skAsScalar, nil) + h, err := HashToCurve(publicKey, seed, func(*big.Int) {}) + if err != nil { + return Proof{}, errors.Wrap(err, "vrf.makeProof#HashToCurve") + } + gamma := Secp256k1Curve.Point().Mul(skAsScalar, h) + sm := secp256k1.IntToScalar(nonce) + u := Secp256k1Curve.Point().Mul(sm, Generator) + uWitness := secp256k1.EthereumAddress(u) + v := Secp256k1Curve.Point().Mul(sm, h) + c := ScalarFromCurvePoints(h, publicKey, gamma, uWitness, v) + // (m - c*secretKey) % GroupOrder + s := bm.Mod(bm.Sub(nonce, bm.Mul(c, secretKey)), secp256k1.GroupOrder) + if e := checkCGammaNotEqualToSHash(c, gamma, s, h); e != nil { + return Proof{}, e + } + outputHash := utils.MustHash(string(append(RandomOutputHashPrefix, + secp256k1.LongMarshal(gamma)...))) + rv := Proof{ + PublicKey: publicKey, + Gamma: gamma, + C: c, + S: s, + Seed: seed, + Output: outputHash.Big(), + } + valid, err := rv.VerifyVRFProof() + if !valid || err != nil { + panic("constructed invalid proof") + } + return rv, nil +} + +// GenerateProof returns gamma, plus proof that gamma was constructed from seed +// as mandated from the given secretKey, with public key secretKey*Generator +// +// secretKey and seed must be less than secp256k1 group order. (Without this +// constraint on the seed, the samples and the possible public keys would +// deviate very slightly from uniform distribution.) +func (key KeyV2) GenerateProof(seed *big.Int) (Proof, error) { + for { + nonce, err := rand.Int(rand.Reader, secp256k1.GroupOrder) + if err != nil { + return Proof{}, err + } + proof, err := key.GenerateProofWithNonce(seed, nonce) + switch { + case errors.Is(err, ErrCGammaEqualsSHash): + // This is cryptographically impossible, but if it were ever to happen, we + // should try again with a different nonce. + continue + case err != nil: // Any other error indicates failure + return Proof{}, err + default: + return proof, err // err should be nil + } + } +} + +func (key KeyV2) String() string { + return fmt.Sprintf("VRFKeyV2{PublicKey: %s}", key.PublicKey) +} + +func (key KeyV2) GoString() string { + return key.String() +} + +func keyFromScalar(k kyber.Scalar) (KeyV2, error) { + rawPublicKey, err := secp256k1.ScalarToPublicPoint(k).MarshalBinary() + if err != nil { + return KeyV2{}, errors.Wrapf(err, "could not marshal public key") + } + if len(rawPublicKey) != secp256k1.CompressedPublicKeyLength { + return KeyV2{}, fmt.Errorf("public key %x has wrong length", rawPublicKey) + } + var publicKey secp256k1.PublicKey + if l := copy(publicKey[:], rawPublicKey); l != secp256k1.CompressedPublicKeyLength { + panic(errors.New("failed to copy correct length in serialized public key")) + } + return KeyV2{ + k: &k, + PublicKey: publicKey, + }, nil +} diff --git a/keystore/corekeys/vrfkey/key_v2_test.go b/keystore/corekeys/vrfkey/key_v2_test.go new file mode 100644 index 0000000000..659ba54a94 --- /dev/null +++ b/keystore/corekeys/vrfkey/key_v2_test.go @@ -0,0 +1,28 @@ +package vrfkey + +import ( + "math/big" + "testing" + + "github.com/ethereum/go-ethereum/common/hexutil" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + "github.com/smartcontractkit/chainlink-common/keystore/internal" + "github.com/smartcontractkit/chainlink/v2/core/services/signatures/secp256k1" +) + +func TestVRFKeys_KeyV2(t *testing.T) { + k, err := NewV2() + require.NoError(t, err) + + assert.Equal(t, hexutil.Encode(k.PublicKey[:]), k.ID()) + assert.Equal(t, internal.NewRaw(secp256k1.ToInt(*k.k).Bytes()), k.Raw()) + + t.Run("generates proof", func(t *testing.T) { + p, err := k.GenerateProof(big.NewInt(1)) + + assert.NotZero(t, p) + assert.NoError(t, err) + }) +} diff --git a/keystore/corekeys/vrfkey/models.go b/keystore/corekeys/vrfkey/models.go new file mode 100644 index 0000000000..a72d29f85d --- /dev/null +++ b/keystore/corekeys/vrfkey/models.go @@ -0,0 +1,73 @@ +package vrfkey + +import ( + "database/sql/driver" + "encoding/json" + "fmt" + "os" + "time" + + "github.com/ethereum/go-ethereum/accounts/keystore" + "github.com/pkg/errors" + + "github.com/smartcontractkit/chainlink/v2/core/services/signatures/secp256k1" + "github.com/smartcontractkit/chainlink/v2/core/utils" +) + +// EncryptedVRFKey contains encrypted private key to be serialized to DB +// +// We could re-use geth's key handling, here, but this makes it much harder to +// misuse VRF proving keys as ethereum keys or vice versa. +type EncryptedVRFKey struct { + PublicKey secp256k1.PublicKey + VRFKey gethKeyStruct `json:"vrf_key"` + CreatedAt time.Time `json:"-"` + UpdatedAt time.Time `json:"-"` + DeletedAt *time.Time `json:"-"` +} + +// JSON returns the JSON representation of e, or errors +func (e *EncryptedVRFKey) JSON() ([]byte, error) { + keyJSON, err := json.Marshal(e) + if err != nil { + return nil, errors.Wrapf(err, "could not marshal encrypted key to JSON") + } + return keyJSON, nil +} + +// WriteToDisk writes the JSON representation of e to given file path, and +// ensures the file has appropriate access permissions +func (e *EncryptedVRFKey) WriteToDisk(path string) error { + keyJSON, err := e.JSON() + if err != nil { + return errors.Wrapf(err, "while marshaling key to save to %s", path) + } + userReadWriteOtherNoAccess := os.FileMode(0600) + return utils.WriteFileWithMaxPerms(path, keyJSON, userReadWriteOtherNoAccess) +} + +// Copied from go-ethereum/accounts/keystore/key.go's encryptedKeyJSONV3 +type gethKeyStruct struct { + Address string `json:"address"` + Crypto keystore.CryptoJSON `json:"crypto"` + Version int `json:"version"` +} + +func (k gethKeyStruct) Value() (driver.Value, error) { + return json.Marshal(&k) +} + +func (k *gethKeyStruct) Scan(value any) error { + var toUnmarshal []byte + switch s := value.(type) { + case []byte: + toUnmarshal = s + case string: + toUnmarshal = []byte(s) + default: + return errors.Wrap( + fmt.Errorf("unable to convert %+v of type %T to gethKeyStruct", + value, value), "scan failure") + } + return json.Unmarshal(toUnmarshal, k) +} diff --git a/keystore/corekeys/vrfkey/models_test.go b/keystore/corekeys/vrfkey/models_test.go new file mode 100644 index 0000000000..e603e6aada --- /dev/null +++ b/keystore/corekeys/vrfkey/models_test.go @@ -0,0 +1,32 @@ +package vrfkey + +import ( + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestVRFKeys_Models(t *testing.T) { + kv2, err := NewV2() + require.NoError(t, err) + k := EncryptedVRFKey{ + PublicKey: kv2.PublicKey, + VRFKey: gethKeyStruct{}, + } + + v, err := k.JSON() + assert.NotEmpty(t, v) + require.NoError(t, err) + + vrfk := gethKeyStruct{} + + v2, err := vrfk.Value() + require.NoError(t, err) + err = vrfk.Scan(v2) + require.NoError(t, err) + err = vrfk.Scan("") + require.Error(t, err) + err = vrfk.Scan(1) + require.Error(t, err) +} diff --git a/keystore/corekeys/vrfkey/proof.go b/keystore/corekeys/vrfkey/proof.go new file mode 100644 index 0000000000..689833f939 --- /dev/null +++ b/keystore/corekeys/vrfkey/proof.go @@ -0,0 +1,67 @@ +package vrfkey + +import ( + "errors" + "fmt" + "math/big" + + "go.dedis.ch/kyber/v3" + + "github.com/smartcontractkit/chainlink-evm/pkg/utils" + "github.com/smartcontractkit/chainlink/v2/core/services/signatures/secp256k1" + bm "github.com/smartcontractkit/chainlink/v2/core/utils/big_math" +) + +// Proof represents a proof that Gamma was constructed from the Seed +// according to the process mandated by the PublicKey. +// +// N.B.: The kyber.Point fields must contain secp256k1.secp256k1Point values, C, +// S and Seed must be secp256k1Point, and Output must be at +// most 256 bits. See Proof.WellFormed. +type Proof struct { + PublicKey kyber.Point // secp256k1 public key of private key used in proof + Gamma kyber.Point + C *big.Int + S *big.Int + Seed *big.Int // Seed input to verifiable random function + Output *big.Int // verifiable random function output;, uniform uint256 sample +} + +func (p *Proof) String() string { + return fmt.Sprintf( + "vrf.Proof{PublicKey: %s, Gamma: %s, C: %x, S: %x, Seed: %x, Output: %x}", + p.PublicKey, p.Gamma, p.C, p.S, p.Seed, p.Output) +} + +// WellFormed is true iff p's attributes satisfy basic domain checks +func (p *Proof) WellFormed() bool { + return (secp256k1.ValidPublicKey(p.PublicKey) && + secp256k1.ValidPublicKey(p.Gamma) && secp256k1.RepresentsScalar(p.C) && + secp256k1.RepresentsScalar(p.S) && p.Output.BitLen() <= 256) +} + +// VerifyProof is true iff gamma was generated in the mandated way from the +// given publicKey and seed, and no error was encountered +func (p *Proof) VerifyVRFProof() (bool, error) { + if !p.WellFormed() { + return false, errors.New("badly-formatted proof") + } + h, err := HashToCurve(p.PublicKey, p.Seed, func(*big.Int) {}) + if err != nil { + return false, err + } + err = checkCGammaNotEqualToSHash(p.C, p.Gamma, p.S, h) + if err != nil { + return false, errors.New("c*γ = s*hash (disallowed in solidity verifier)") + } + // publicKey = secretKey*Generator. See GenerateProof for u, v, m, s + // c*secretKey*Generator + (m - c*secretKey)*Generator = m*Generator = u + uPrime := linearCombination(p.C, p.PublicKey, p.S, Generator) + // c*secretKey*h + (m - c*secretKey)*h = m*h = v + vPrime := linearCombination(p.C, p.Gamma, p.S, h) + uWitness := secp256k1.EthereumAddress(uPrime) + cPrime := ScalarFromCurvePoints(h, p.PublicKey, p.Gamma, uWitness, vPrime) + output := utils.MustHash(string(append( + RandomOutputHashPrefix, secp256k1.LongMarshal(p.Gamma)...))) + return bm.Equal(p.C, cPrime) && bm.Equal(p.Output, output.Big()), nil +} diff --git a/keystore/corekeys/vrfkey/proof_test.go b/keystore/corekeys/vrfkey/proof_test.go new file mode 100644 index 0000000000..0a6af4b088 --- /dev/null +++ b/keystore/corekeys/vrfkey/proof_test.go @@ -0,0 +1,25 @@ +package vrfkey + +import ( + "fmt" + "math/big" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestVRF_VerifyProof(t *testing.T) { + sk, err := NewV2() + require.NoError(t, err) + seed, nonce := big.NewInt(2), big.NewInt(3) + p, err := sk.GenerateProofWithNonce(seed, nonce) + require.NoError(t, err, "could not generate proof") + p.Seed = big.NewInt(0).Add(seed, big.NewInt(1)) + valid, err := p.VerifyVRFProof() + require.NoError(t, err, "could not validate proof") + assert.False(t, valid, "invalid proof was found valid") + assert.Equal(t, fmt.Sprintf( + "vrf.Proof{PublicKey: %s, Gamma: %s, C: %x, S: %x, Seed: %x, Output: %x}", + p.PublicKey, p.Gamma, p.C, p.S, p.Seed, p.Output), p.String()) +} diff --git a/keystore/corekeys/workflowkey/export.go b/keystore/corekeys/workflowkey/export.go new file mode 100644 index 0000000000..2b18038b0d --- /dev/null +++ b/keystore/corekeys/workflowkey/export.go @@ -0,0 +1,43 @@ +package workflowkey + +import ( + "github.com/ethereum/go-ethereum/accounts/keystore" + + "github.com/smartcontractkit/chainlink-common/keystore/internal" + "github.com/smartcontractkit/chainlink-common/keystore/scrypt" +) + +const keyTypeIdentifier = "Workflow" + +func FromEncryptedJSON(keyJSON []byte, password string) (Key, error) { + return internal.FromEncryptedJSON( + keyTypeIdentifier, + keyJSON, + password, + adulteratedPassword, + func(_ internal.EncryptedKeyExport, rawPrivKey internal.Raw) (Key, error) { + return KeyFor(rawPrivKey), nil + }, + ) +} + +func (k Key) ToEncryptedJSON(password string, scryptParams scrypt.ScryptParams) (export []byte, err error) { + return internal.ToEncryptedJSON( + keyTypeIdentifier, + k, + password, + scryptParams, + adulteratedPassword, + func(id string, key Key, cryptoJSON keystore.CryptoJSON) internal.EncryptedKeyExport { + return internal.EncryptedKeyExport{ + KeyType: id, + PublicKey: key.PublicKeyString(), + Crypto: cryptoJSON, + } + }, + ) +} + +func adulteratedPassword(password string) string { + return "workflowkey" + password +} diff --git a/keystore/corekeys/workflowkey/key.go b/keystore/corekeys/workflowkey/key.go new file mode 100644 index 0000000000..9874639571 --- /dev/null +++ b/keystore/corekeys/workflowkey/key.go @@ -0,0 +1,129 @@ +package workflowkey + +import ( + "crypto/ed25519" + cryptorand "crypto/rand" + "encoding/hex" + "errors" + "math/big" + + "golang.org/x/crypto/curve25519" + "golang.org/x/crypto/nacl/box" + + "github.com/smartcontractkit/chainlink-common/keystore/internal" +) + +func KeyFor(raw internal.Raw) Key { + privateKey := [32]byte(internal.Bytes(raw)) + return Key{ + raw: raw, + openFn: func(out, ciphertext []byte, publicKey *[32]byte) (message []byte, ok bool) { + return box.OpenAnonymous(nil, ciphertext, publicKey, &privateKey) + }, + publicKey: curve25519PubKeyFromPrivateKey(privateKey), + } +} + +type Key struct { + raw internal.Raw + openFn func(out, ciphertext []byte, publicKey *[32]byte) (message []byte, ok bool) + + publicKey *[curve25519.PointSize]byte +} + +func New() (Key, error) { + publicKey, privateKey, err := box.GenerateKey(cryptorand.Reader) + if err != nil { + return Key{}, err + } + + raw := make([]byte, curve25519.PointSize) + copy(raw, privateKey[:]) + return Key{ + raw: internal.NewRaw(raw), + openFn: func(out, ciphertext []byte, publicKey *[32]byte) (message []byte, ok bool) { + return box.OpenAnonymous(nil, ciphertext, publicKey, privateKey) + }, + publicKey: publicKey, + }, nil +} + +func (k Key) PublicKey() [curve25519.PointSize]byte { + if k.publicKey == nil { + return [curve25519.PointSize]byte{} + } + + return *k.publicKey +} + +func (k Key) PublicKeyString() string { + if k.publicKey == nil { + return "" + } + + return hex.EncodeToString(k.publicKey[:]) +} + +func (k Key) ID() string { + return k.PublicKeyString() +} + +func (k Key) Raw() internal.Raw { return k.raw } + +// Encrypt encrypts a message using the public key +func (k Key) Encrypt(plaintext []byte) ([]byte, error) { + publicKey := k.PublicKey() + if publicKey == [curve25519.PointSize]byte{} { + return nil, errors.New("public key is empty") + } + + encrypted, err := box.SealAnonymous(nil, plaintext, &publicKey, cryptorand.Reader) + if err != nil { + return nil, err + } + + return encrypted, nil +} + +// Decrypt decrypts a message that was encrypted using the private key +func (k Key) Decrypt(ciphertext []byte) (plaintext []byte, err error) { + publicKey := k.PublicKey() + if publicKey == [curve25519.PointSize]byte{} { + return nil, errors.New("public key is empty") + } + + decrypted, success := k.openFn(nil, ciphertext, &publicKey) + if !success { + return nil, errors.New("decryption failed") + } + + return decrypted, nil +} + +func curve25519PubKeyFromPrivateKey(privateKey [curve25519.PointSize]byte) *[curve25519.PointSize]byte { + var publicKey [curve25519.PointSize]byte + + // Derive the public key + curve25519.ScalarBaseMult(&publicKey, &privateKey) + + return &publicKey +} + +func MustNewXXXTestingOnly(k *big.Int) Key { + seed := make([]byte, ed25519.SeedSize) + copy(seed, k.Bytes()) + privKey := ed25519.NewKeyFromSeed(seed) + + var privateKey [32]byte + copy(privateKey[:], privKey.Seed()) + + raw := make([]byte, curve25519.PointSize) + copy(raw, privateKey[:]) + return Key{ + raw: internal.NewRaw(raw), + openFn: func(out, ciphertext []byte, publicKey *[32]byte) (message []byte, ok bool) { + return box.OpenAnonymous(nil, ciphertext, publicKey, &privateKey) + }, + publicKey: curve25519PubKeyFromPrivateKey(privateKey), + } +} diff --git a/keystore/corekeys/workflowkey/key_test.go b/keystore/corekeys/workflowkey/key_test.go new file mode 100644 index 0000000000..c91ba7bd5d --- /dev/null +++ b/keystore/corekeys/workflowkey/key_test.go @@ -0,0 +1,116 @@ +package workflowkey + +import ( + cryptorand "crypto/rand" + "encoding/hex" + "math/big" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "golang.org/x/crypto/nacl/box" + + "github.com/smartcontractkit/chainlink-common/keystore/internal" +) + +func TestNew(t *testing.T) { + key, err := New() + require.NoError(t, err) + + assert.NotNil(t, key.PublicKey) + assert.NotNil(t, key.raw) +} + +func TestPublicKey(t *testing.T) { + key, err := New() + require.NoError(t, err) + + assert.Equal(t, *key.publicKey, key.PublicKey()) +} + +func TestEncryptKeyFromRawPrivateKey(t *testing.T) { + boxPubKey, boxPrivKey, err := box.GenerateKey(cryptorand.Reader) + require.NoError(t, err) + + privKey := make([]byte, 32) + copy(privKey, boxPrivKey[:]) + key := KeyFor(internal.NewRaw(privKey)) + + assert.Equal(t, boxPubKey, key.publicKey) + assert.Equal(t, boxPrivKey[:], internal.Bytes(key.raw)) + + byteBoxPubKey := make([]byte, 32) + copy(byteBoxPubKey, boxPubKey[:]) + + assert.Equal(t, hex.EncodeToString(byteBoxPubKey), key.PublicKeyString()) +} + +func TestPublicKeyStringAndID(t *testing.T) { + key := "my-test-public-key" + var pubkey [32]byte + copy(pubkey[:], key) + k := Key{ + publicKey: &pubkey, + } + + expected := hex.EncodeToString([]byte(key)) + // given the key is a [32]byte we need to ensure the encoded string is 64 character long + for len(expected) < 64 { + expected += "0" + } + + assert.Equal(t, expected, k.PublicKeyString()) + assert.Equal(t, expected, k.ID()) +} + +func TestDecrypt(t *testing.T) { + key, err := New() + require.NoError(t, err) + + secret := []byte("my-secret") + ciphertext, err := key.Encrypt(secret) + require.NoError(t, err) + + plaintext, err := key.Decrypt(ciphertext) + require.NoError(t, err) + + assert.Equal(t, secret, plaintext) +} + +func TestMustNewXXXTestingOnly(t *testing.T) { + tests := []struct { + name string + k *big.Int + wantSuccess bool + }{ + { + name: "generates valid key from big.Int", + k: big.NewInt(1), + wantSuccess: true, + }, + { + name: "panics on nil input", + k: nil, + wantSuccess: false, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if !tt.wantSuccess { + require.Panics(t, func() { MustNewXXXTestingOnly(tt.k) }) + return + } + + key := MustNewXXXTestingOnly(tt.k) + require.NotNil(t, key.raw) + require.NotNil(t, key.publicKey) + + // Verify key generation is deterministic + if tt.k.Cmp(big.NewInt(1)) != 0 { + key1 := MustNewXXXTestingOnly(tt.k) + require.Equal(t, key1.PublicKey(), key.PublicKey()) + } + }) + } +} diff --git a/keystore/go.mod b/keystore/go.mod index 725566a27f..c75e2f4ef7 100644 --- a/keystore/go.mod +++ b/keystore/go.mod @@ -1,25 +1,58 @@ module github.com/smartcontractkit/chainlink-common/keystore -go 1.25.3 +go 1.25.5 + +replace github.com/smartcontractkit/chainlink-common => ../ + +require github.com/smartcontractkit/chainlink-common v0.9.6-0.20260107095648-223976d2b9f1 require ( + github.com/NethermindEth/juno v0.12.5 + github.com/NethermindEth/starknet.go v0.8.0 github.com/aws/aws-sdk-go-v2 v1.41.1 github.com/aws/aws-sdk-go-v2/config v1.28.4 github.com/aws/aws-sdk-go-v2/service/kms v1.49.5 + github.com/cosmos/cosmos-sdk v0.53.5 github.com/ethereum/go-ethereum v1.16.8 + github.com/gagliardetto/solana-go v1.14.0 + github.com/google/uuid v1.6.0 + github.com/hdevalence/ed25519consensus v0.2.0 github.com/jmoiron/sqlx v1.4.0 github.com/lib/pq v1.10.9 - github.com/smartcontractkit/chain-selectors v1.0.67 - github.com/smartcontractkit/chainlink-common v0.9.6-0.20251107154219-ec6d8370ebbf - github.com/smartcontractkit/libocr v0.0.0-20250912173940-f3ab0246e23d - github.com/spf13/cobra v1.8.1 + github.com/mr-tron/base58 v1.2.0 + github.com/pkg/errors v0.9.1 + github.com/smartcontractkit/chainlink-evm v0.3.4-0.20251210110629-10c56e8d2cec + github.com/smartcontractkit/chainlink/v2 v2.32.0 + github.com/smartcontractkit/libocr v0.0.0-20251212213002-0a5e2f907dda + github.com/smartcontractkit/smdkg v0.0.0-20251029093710-c38905e58aeb + github.com/smartcontractkit/wsrpc v0.8.5-0.20250502134807-c57d3d995945 + github.com/spf13/cobra v1.10.1 github.com/stretchr/testify v1.11.1 + github.com/xssnick/tonutils-go v1.14.1 + go.dedis.ch/kyber/v3 v3.1.0 golang.org/x/crypto v0.47.0 - google.golang.org/protobuf v1.36.9 + google.golang.org/protobuf v1.36.11 ) require ( + cosmossdk.io/api v0.9.2 // indirect + cosmossdk.io/collections v1.3.1 // indirect + cosmossdk.io/core v0.11.3 // indirect + cosmossdk.io/errors v1.0.2 // indirect + cosmossdk.io/log v1.6.1 // indirect + cosmossdk.io/math v1.5.3 // indirect + cosmossdk.io/schema v1.1.0 // indirect + cosmossdk.io/store v1.1.2 // indirect + cosmossdk.io/x/tx v0.14.0 // indirect + filippo.io/bigmod v0.1.0 // indirect + filippo.io/edwards25519 v1.1.0 // indirect + filippo.io/nistec v0.0.4 // indirect + github.com/99designs/go-keychain v0.0.0-20191008050251-8e49817e8af4 // indirect + github.com/99designs/keyring v1.2.1 // indirect + github.com/DataDog/zstd v1.5.7 // indirect + github.com/Microsoft/go-winio v0.6.2 // indirect github.com/ProjectZKM/Ziren/crates/go-runtime/zkvm_runtime v0.0.0-20251001021608-1fe7b43fc4d6 // indirect + github.com/VictoriaMetrics/fastcache v1.13.0 // indirect github.com/XSAM/otelsql v0.37.0 // indirect github.com/apache/arrow-go/v18 v18.3.1 // indirect github.com/aws/aws-sdk-go-v2/credentials v1.17.45 // indirect @@ -35,35 +68,102 @@ require ( github.com/aws/smithy-go v1.24.0 // indirect github.com/bahlo/generic-list-go v0.2.0 // indirect github.com/beorn7/perks v1.0.1 // indirect - github.com/bits-and-blooms/bitset v1.20.0 // indirect + github.com/bgentry/speakeasy v0.2.0 // indirect + github.com/bits-and-blooms/bitset v1.24.3 // indirect + github.com/blendle/zapdriver v1.3.1 // indirect + github.com/btcsuite/btcd/btcec/v2 v2.3.5 // indirect github.com/buger/jsonparser v1.1.1 // indirect + github.com/bytedance/gopkg v0.1.3 // indirect + github.com/bytedance/sonic v1.14.2 // indirect + github.com/bytedance/sonic/loader v0.4.0 // indirect github.com/cenkalti/backoff/v5 v5.0.2 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect github.com/cloudevents/sdk-go/binding/format/protobuf/v2 v2.16.1 // indirect github.com/cloudevents/sdk-go/v2 v2.16.1 // indirect - github.com/consensys/gnark-crypto v0.18.0 // indirect + github.com/cloudwego/base64x v0.1.6 // indirect + github.com/cockroachdb/errors v1.12.0 // indirect + github.com/cockroachdb/fifo v0.0.0-20240816210425-c5d0cb0b6fc0 // indirect + github.com/cockroachdb/logtags v0.0.0-20241215232642-bb51bb14a506 // indirect + github.com/cockroachdb/pebble v1.1.5 // indirect + github.com/cockroachdb/redact v1.1.6 // indirect + github.com/cockroachdb/tokenbucket v0.0.0-20250429170803-42689b6311bb // indirect + github.com/cometbft/cometbft v0.38.20 // indirect + github.com/cometbft/cometbft-db v1.0.1 // indirect + github.com/consensys/gnark-crypto v0.18.1 // indirect + github.com/cosmos/btcutil v1.0.5 // indirect + github.com/cosmos/cosmos-db v1.1.3 // indirect + github.com/cosmos/cosmos-proto v1.0.0-beta.5 // indirect + github.com/cosmos/go-bip39 v1.0.0 // indirect + github.com/cosmos/gogoproto v1.7.2 // indirect + github.com/cosmos/ics23/go v0.11.0 // indirect + github.com/cosmos/ledger-cosmos-go v0.16.0 // indirect + github.com/cpuguy83/go-md2man/v2 v2.0.6 // indirect github.com/crate-crypto/go-eth-kzg v1.4.0 // indirect github.com/crate-crypto/go-ipa v0.0.0-20240724233137-53bbb0ceb27a // indirect + github.com/danieljoos/wincred v1.2.1 // indirect github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect - github.com/deckarep/golang-set/v2 v2.6.0 // indirect - github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0 // indirect + github.com/dchest/siphash v1.2.3 // indirect + github.com/deckarep/golang-set/v2 v2.8.0 // indirect + github.com/decred/dcrd/dcrec/secp256k1/v4 v4.4.0 // indirect + github.com/dgraph-io/badger/v4 v4.7.0 // indirect + github.com/dgraph-io/ristretto/v2 v2.2.0 // indirect + github.com/dustin/go-humanize v1.0.1 // indirect + github.com/dvsekhvalnov/jose2go v1.7.0 // indirect + github.com/emicklei/dot v1.6.2 // indirect github.com/ethereum/c-kzg-4844/v2 v2.1.5 // indirect + github.com/ethereum/go-bigmodexpfix v0.0.0-20250911101455-f9e208c548ab // indirect github.com/ethereum/go-verkle v0.2.2 // indirect - github.com/fsnotify/fsnotify v1.8.0 // indirect - github.com/gabriel-vasile/mimetype v1.4.8 // indirect + github.com/fatih/color v1.18.0 // indirect + github.com/ferranbt/fastssz v0.1.4 // indirect + github.com/fsnotify/fsnotify v1.9.0 // indirect + github.com/fxamacker/cbor/v2 v2.9.0 // indirect + github.com/gabriel-vasile/mimetype v1.4.10 // indirect + github.com/gagliardetto/binary v0.8.0 // indirect + github.com/gagliardetto/treeout v0.1.4 // indirect + github.com/getsentry/sentry-go v0.35.1 // indirect + github.com/gin-contrib/sessions v0.0.5 // indirect + github.com/gin-contrib/sse v0.1.0 // indirect + github.com/gin-gonic/gin v1.10.1 // indirect github.com/go-json-experiment/json v0.0.0-20250223041408-d3c622f1b874 // indirect + github.com/go-kit/kit v0.13.0 // indirect + github.com/go-kit/log v0.2.1 // indirect + github.com/go-logfmt/logfmt v0.6.0 // indirect github.com/go-logr/logr v1.4.3 // indirect github.com/go-logr/stdr v1.2.2 // indirect + github.com/go-ole/go-ole v1.3.0 // indirect github.com/go-playground/locales v0.14.1 // indirect github.com/go-playground/universal-translator v0.18.1 // indirect - github.com/go-playground/validator/v10 v10.26.0 // indirect + github.com/go-playground/validator/v10 v10.28.0 // indirect github.com/go-viper/mapstructure/v2 v2.4.0 // indirect github.com/goccy/go-json v0.10.5 // indirect + github.com/godbus/dbus v0.0.0-20190726142602-4481cbc300e2 // indirect + github.com/gofrs/flock v0.12.1 // indirect + github.com/gogo/protobuf v1.3.2 // indirect + github.com/golang-jwt/jwt/v4 v4.5.2 // indirect + github.com/golang-jwt/jwt/v5 v5.2.3 // indirect + github.com/golang/protobuf v1.5.4 // indirect + github.com/golang/snappy v1.0.0 // indirect + github.com/google/btree v1.1.3 // indirect github.com/google/flatbuffers v25.2.10+incompatible // indirect github.com/google/go-cmp v0.7.0 // indirect - github.com/google/uuid v1.6.0 // indirect - github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.3 // indirect + github.com/gorilla/context v1.1.1 // indirect + github.com/gorilla/securecookie v1.1.2 // indirect + github.com/gorilla/sessions v1.2.2 // indirect + github.com/gorilla/websocket v1.5.3 // indirect + github.com/grafana/pyroscope-go v1.2.7 // indirect + github.com/grafana/pyroscope-go/godeltaprof v0.1.9 // indirect + github.com/grpc-ecosystem/grpc-gateway v1.16.0 // indirect + github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.1 // indirect + github.com/gsterjov/go-libsecret v0.0.0-20161001094733-a6f4afe4910c // indirect + github.com/hashicorp/go-bexpr v0.1.10 // indirect + github.com/hashicorp/go-immutable-radix v1.3.1 // indirect + github.com/hashicorp/go-metrics v0.5.4 // indirect + github.com/hashicorp/golang-lru v1.0.2 // indirect + github.com/holiman/billy v0.0.0-20250707135307-f2f9b9aae7db // indirect + github.com/holiman/bloomfilter/v2 v2.0.3 // indirect github.com/holiman/uint256 v1.3.2 // indirect + github.com/huin/goupnp v1.3.0 // indirect + github.com/iancoleman/strcase v0.3.0 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/invopop/jsonschema v0.13.0 // indirect github.com/jackc/chunkreader/v2 v2.0.1 // indirect @@ -74,74 +174,142 @@ require ( github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 // indirect github.com/jackc/pgtype v1.14.4 // indirect github.com/jackc/pgx/v4 v4.18.3 // indirect + github.com/jackpal/go-nat-pmp v1.0.2 // indirect + github.com/jmhodges/levigo v1.0.0 // indirect + github.com/jpillora/backoff v1.0.0 // indirect github.com/json-iterator/go v1.1.12 // indirect - github.com/klauspost/compress v1.18.0 // indirect - github.com/klauspost/cpuid/v2 v2.2.10 // indirect + github.com/klauspost/compress v1.18.1 // indirect + github.com/klauspost/cpuid/v2 v2.3.0 // indirect + github.com/kr/pretty v0.3.1 // indirect + github.com/kr/text v0.2.0 // indirect github.com/leodido/go-urn v1.4.0 // indirect + github.com/linxGnu/grocksdb v1.9.3 // indirect + github.com/logrusorgru/aurora v2.0.3+incompatible // indirect github.com/mailru/easyjson v0.9.0 // indirect github.com/marcboeker/go-duckdb v1.8.5 // indirect + github.com/mattn/go-colorable v0.1.14 // indirect + github.com/mattn/go-isatty v0.0.20 // indirect + github.com/mattn/go-runewidth v0.0.16 // indirect + github.com/minio/sha256-simd v1.0.1 // indirect + github.com/mitchellh/go-testing-interface v1.14.1 // indirect github.com/mitchellh/mapstructure v1.5.1-0.20220423185008-bf980b35cac4 // indirect + github.com/mitchellh/pointerstructure v1.2.0 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect - github.com/mr-tron/base58 v1.2.0 // indirect + github.com/mostynb/zstdpool-freelist v0.0.0-20201229113212-927304c0c3b1 // indirect + github.com/mtibben/percent v0.2.1 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect + github.com/oasisprotocol/curve25519-voi v0.0.0-20230904125328-1f23a7beb09a // indirect + github.com/olekukonko/errors v1.1.0 // indirect + github.com/olekukonko/ll v0.0.9 // indirect + github.com/olekukonko/tablewriter v1.0.9 // indirect github.com/pelletier/go-toml/v2 v2.2.4 // indirect + github.com/petermattis/goid v0.0.0-20240813172612-4fcff4a6cae7 // indirect github.com/pierrec/lz4/v4 v4.1.22 // indirect - github.com/pkg/errors v0.9.1 // indirect + github.com/pion/dtls/v2 v2.2.12 // indirect + github.com/pion/logging v0.2.4 // indirect + github.com/pion/stun/v2 v2.0.0 // indirect + github.com/pion/transport/v2 v2.2.10 // indirect + github.com/pion/transport/v3 v3.0.7 // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect - github.com/prometheus/client_golang v1.22.0 // indirect + github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 // indirect + github.com/prometheus/client_golang v1.23.0 // indirect github.com/prometheus/client_model v0.6.2 // indirect github.com/prometheus/common v0.65.0 // indirect - github.com/prometheus/procfs v0.16.1 // indirect + github.com/prometheus/procfs v0.17.0 // indirect github.com/rivo/uniseg v0.4.7 // indirect + github.com/robfig/cron/v3 v3.0.1 // indirect + github.com/rogpeppe/go-internal v1.14.1 // indirect + github.com/rs/cors v1.11.1 // indirect + github.com/rs/zerolog v1.34.0 // indirect + github.com/russross/blackfriday/v2 v2.1.0 // indirect github.com/santhosh-tekuri/jsonschema/v5 v5.3.1 // indirect + github.com/sasha-s/go-deadlock v0.3.5 // indirect github.com/scylladb/go-reflectx v1.0.1 // indirect github.com/shirou/gopsutil v3.21.11+incompatible // indirect + github.com/shirou/gopsutil/v3 v3.24.3 // indirect github.com/shopspring/decimal v1.4.0 // indirect + github.com/sigurn/crc16 v0.0.0-20211026045750-20ab5afb07e3 // indirect + github.com/smartcontractkit/chain-selectors v1.0.89 // indirect github.com/smartcontractkit/chainlink-common/pkg/chipingress v0.0.10 // indirect - github.com/smartcontractkit/chainlink-protos/cre/go v0.0.0-20251124151448-0448aefdaab9 // indirect + github.com/smartcontractkit/chainlink-framework/chains v0.0.0-20251210101658-1c5c8e4c4f15 // indirect + github.com/smartcontractkit/chainlink-protos/cre/go v0.0.0-20260206000552-087e235a7963 // indirect github.com/smartcontractkit/chainlink-protos/linking-service/go v0.0.0-20251002192024-d2ad9222409b // indirect github.com/smartcontractkit/freeport v0.1.3-0.20250716200817-cb5dfd0e369e // indirect - github.com/spf13/pflag v1.0.6 // indirect + github.com/spf13/cast v1.10.0 // indirect + github.com/spf13/pflag v1.0.10 // indirect + github.com/streamingfast/logging v0.0.0-20230608130331-f22c91403091 // indirect + github.com/stretchr/objx v0.5.2 // indirect github.com/supranational/blst v0.3.16-0.20250831170142-f48500c1fdbe // indirect + github.com/syndtr/goleveldb v1.0.1-0.20220721030215-126854af5e6d // indirect + github.com/tendermint/go-amino v0.16.0 // indirect + github.com/tidwall/btree v1.7.0 // indirect + github.com/tidwall/gjson v1.18.0 // indirect + github.com/tidwall/match v1.1.1 // indirect + github.com/tidwall/pretty v1.2.1 // indirect github.com/tklauser/go-sysconf v0.3.15 // indirect + github.com/tklauser/numcpus v0.10.0 // indirect + github.com/twitchyliquid64/golang-asm v0.15.1 // indirect + github.com/ugorji/go/codec v1.2.12 // indirect + github.com/urfave/cli/v2 v2.27.6 // indirect github.com/wk8/go-ordered-map/v2 v2.1.8 // indirect + github.com/wlynxg/anet v0.0.5 // indirect + github.com/x448/float16 v0.8.4 // indirect + github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1 // indirect github.com/yusufpapurcu/wmi v1.2.4 // indirect github.com/zeebo/xxh3 v1.0.2 // indirect - go.opentelemetry.io/auto/sdk v1.1.0 // indirect + github.com/zondax/golem v0.27.0 // indirect + github.com/zondax/hid v0.9.2 // indirect + github.com/zondax/ledger-go v1.0.1 // indirect + go.dedis.ch/fixbuf v1.0.3 // indirect + go.etcd.io/bbolt v1.4.2 // indirect + go.mongodb.org/mongo-driver v1.17.2 // indirect + go.opentelemetry.io/auto/sdk v1.2.1 // indirect go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.63.0 // indirect - go.opentelemetry.io/otel v1.38.0 // indirect - go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.12.2 // indirect - go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp v0.12.2 // indirect - go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.36.0 // indirect + go.opentelemetry.io/otel v1.39.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.13.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp v0.13.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.37.0 // indirect go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.36.0 // indirect - go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.36.0 // indirect - go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.36.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.37.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.37.0 // indirect go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.36.0 // indirect go.opentelemetry.io/otel/exporters/stdout/stdoutlog v0.13.0 // indirect go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.36.0 // indirect go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.36.0 // indirect - go.opentelemetry.io/otel/log v0.13.0 // indirect - go.opentelemetry.io/otel/metric v1.38.0 // indirect - go.opentelemetry.io/otel/sdk v1.38.0 // indirect - go.opentelemetry.io/otel/sdk/log v0.13.0 // indirect - go.opentelemetry.io/otel/sdk/metric v1.38.0 // indirect - go.opentelemetry.io/otel/trace v1.38.0 // indirect - go.opentelemetry.io/proto/otlp v1.6.0 // indirect + go.opentelemetry.io/otel/log v0.15.0 // indirect + go.opentelemetry.io/otel/metric v1.39.0 // indirect + go.opentelemetry.io/otel/sdk v1.39.0 // indirect + go.opentelemetry.io/otel/sdk/log v0.15.0 // indirect + go.opentelemetry.io/otel/sdk/metric v1.39.0 // indirect + go.opentelemetry.io/otel/trace v1.39.0 // indirect + go.opentelemetry.io/proto/otlp v1.7.0 // indirect go.uber.org/multierr v1.11.0 // indirect - go.uber.org/zap v1.27.0 // indirect - golang.org/x/exp v0.0.0-20250711185948-6ae5c78190dc // indirect - golang.org/x/mod v0.31.0 // indirect - golang.org/x/net v0.48.0 // indirect + go.uber.org/zap v1.27.1 // indirect + go.yaml.in/yaml/v2 v2.4.2 // indirect + golang.org/x/arch v0.17.0 // indirect + golang.org/x/exp v0.0.0-20260112195511-716be5621a96 // indirect + golang.org/x/mod v0.32.0 // indirect + golang.org/x/net v0.49.0 // indirect golang.org/x/sync v0.19.0 // indirect golang.org/x/sys v0.40.0 // indirect - golang.org/x/telemetry v0.0.0-20251203150158-8fff8a5912fc // indirect + golang.org/x/telemetry v0.0.0-20260109210033-bd525da824e2 // indirect + golang.org/x/term v0.39.0 // indirect golang.org/x/text v0.33.0 // indirect - golang.org/x/time v0.12.0 // indirect - golang.org/x/tools v0.40.0 // indirect + golang.org/x/time v0.14.0 // indirect + golang.org/x/tools v0.41.0 // indirect golang.org/x/xerrors v0.0.0-20240903120638-7835f813f4da // indirect - google.golang.org/genproto/googleapis/api v0.0.0-20250707201910-8d1bb00bc6a7 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20250825161204-c5933d9347a5 // indirect - google.golang.org/grpc v1.75.0 // indirect + google.golang.org/genproto v0.0.0-20250603155806-513f23925822 // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20251029180050-ab9386a59fda // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20251029180050-ab9386a59fda // indirect + google.golang.org/grpc v1.78.0 // indirect + gopkg.in/guregu/null.v4 v4.0.0 // indirect + gopkg.in/natefinch/lumberjack.v2 v2.2.1 // indirect + gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect + gotest.tools/v3 v3.5.2 // indirect + pgregory.net/rapid v1.2.0 // indirect + sigs.k8s.io/yaml v1.6.0 // indirect ) + +replace github.com/fbsobreira/gotron-sdk => github.com/smartcontractkit/chainlink-tron/relayer/gotron-sdk v0.0.5-0.20251014124537-af6b1684fe15 diff --git a/keystore/go.sum b/keystore/go.sum index c9f1678f5c..648ff41610 100644 --- a/keystore/go.sum +++ b/keystore/go.sum @@ -1,19 +1,86 @@ +cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cosmossdk.io/api v0.9.2 h1:9i9ptOBdmoIEVEVWLtYYHjxZonlF/aOVODLFaxpmNtg= +cosmossdk.io/api v0.9.2/go.mod h1:CWt31nVohvoPMTlPv+mMNCtC0a7BqRdESjCsstHcTkU= +cosmossdk.io/collections v1.3.1 h1:09e+DUId2brWsNOQ4nrk+bprVmMUaDH9xvtZkeqIjVw= +cosmossdk.io/collections v1.3.1/go.mod h1:ynvkP0r5ruAjbmedE+vQ07MT6OtJ0ZIDKrtJHK7Q/4c= +cosmossdk.io/core v0.11.3 h1:mei+MVDJOwIjIniaKelE3jPDqShCc/F4LkNNHh+4yfo= +cosmossdk.io/core v0.11.3/go.mod h1:9rL4RE1uDt5AJ4Tg55sYyHWXA16VmpHgbe0PbJc6N2Y= +cosmossdk.io/depinject v1.2.1 h1:eD6FxkIjlVaNZT+dXTQuwQTKZrFZ4UrfCq1RKgzyhMw= +cosmossdk.io/depinject v1.2.1/go.mod h1:lqQEycz0H2JXqvOgVwTsjEdMI0plswI7p6KX+MVqFOM= +cosmossdk.io/errors v1.0.2 h1:wcYiJz08HThbWxd/L4jObeLaLySopyyuUFB5w4AGpCo= +cosmossdk.io/errors v1.0.2/go.mod h1:0rjgiHkftRYPj//3DrD6y8hcm40HcPv/dR4R/4efr0k= +cosmossdk.io/log v1.6.1 h1:YXNwAgbDwMEKwDlCdH8vPcoggma48MgZrTQXCfmMBeI= +cosmossdk.io/log v1.6.1/go.mod h1:gMwsWyyDBjpdG9u2avCFdysXqxq28WJapJvu+vF1y+E= +cosmossdk.io/math v1.5.3 h1:WH6tu6Z3AUCeHbeOSHg2mt9rnoiUWVWaQ2t6Gkll96U= +cosmossdk.io/math v1.5.3/go.mod h1:uqcZv7vexnhMFJF+6zh9EWdm/+Ylyln34IvPnBauPCQ= +cosmossdk.io/schema v1.1.0 h1:mmpuz3dzouCoyjjcMcA/xHBEmMChN+EHh8EHxHRHhzE= +cosmossdk.io/schema v1.1.0/go.mod h1:Gb7pqO+tpR+jLW5qDcNOSv0KtppYs7881kfzakguhhI= +cosmossdk.io/store v1.1.2 h1:3HOZG8+CuThREKv6cn3WSohAc6yccxO3hLzwK6rBC7o= +cosmossdk.io/store v1.1.2/go.mod h1:60rAGzTHevGm592kFhiUVkNC9w7gooSEn5iUBPzHQ6A= +cosmossdk.io/x/tx v0.14.0 h1:hB3O25kIcyDW/7kMTLMaO8Ripj3yqs5imceVd6c/heA= +cosmossdk.io/x/tx v0.14.0/go.mod h1:Tn30rSRA1PRfdGB3Yz55W4Sn6EIutr9xtMKSHij+9PM= +filippo.io/bigmod v0.1.0 h1:UNzDk7y9ADKST+axd9skUpBQeW7fG2KrTZyOE4uGQy8= +filippo.io/bigmod v0.1.0/go.mod h1:OjOXDNlClLblvXdwgFFOQFJEocLhhtai8vGLy0JCZlI= filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA= filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4= +filippo.io/nistec v0.0.4 h1:F14ZHT5htWlMnQVPndX9ro9arf56cBhQxq4LnDI491s= +filippo.io/nistec v0.0.4/go.mod h1:PK/lw8I1gQT4hUML4QGaqljwdDaFcMyFKSXN7kjrtKI= +github.com/99designs/go-keychain v0.0.0-20191008050251-8e49817e8af4 h1:/vQbFIOMbk2FiG/kXiLl8BRyzTWDw7gX/Hz7Dd5eDMs= +github.com/99designs/go-keychain v0.0.0-20191008050251-8e49817e8af4/go.mod h1:hN7oaIRCjzsZ2dE+yG5k+rsdt3qcwykqK6HVGcKwsw4= +github.com/99designs/keyring v1.2.1 h1:tYLp1ULvO7i3fI5vE21ReQuj99QFSs7lGm0xWyJo87o= +github.com/99designs/keyring v1.2.1/go.mod h1:fc+wB5KTk9wQ9sDx0kFXB3A0MaeGHM9AwRStKOQ5vOA= +github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358 h1:mFRzDkZVAjdal+s7s0MwaRv9igoPqLRdzOLzw/8Xvq8= +github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358/go.mod h1:chxPXzSsl7ZWRAuOIE23GDNzjWuZquvFlgA8xmpunjU= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/BurntSushi/toml v1.4.0 h1:kuoIxZQy2WRRk1pttg9asf+WVv6tWQuBNVmK8+nqPr0= +github.com/BurntSushi/toml v1.4.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho= +github.com/DataDog/datadog-go v3.2.0+incompatible h1:qSG2N4FghB1He/r2mFrWKCaL7dXCilEuNEeAn20fdD4= +github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= +github.com/DataDog/zstd v1.5.7 h1:ybO8RBeh29qrxIhCA9E8gKY6xfONU9T6G6aP9DTKfLE= +github.com/DataDog/zstd v1.5.7/go.mod h1:g4AWEaM3yOg3HYfnJ3YIawPnVdXJh9QME85blwSAmyw= +github.com/Depado/ginprom v1.8.0 h1:zaaibRLNI1dMiiuj1MKzatm8qrcHzikMlCc1anqOdyo= +github.com/Depado/ginprom v1.8.0/go.mod h1:XBaKzeNBqPF4vxJpNLincSQZeMDnZp1tIbU0FU0UKgg= github.com/Masterminds/semver/v3 v3.1.1/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs= 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/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY= +github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU= +github.com/NethermindEth/juno v0.12.5 h1:a+KYQg8MxzNJIbbqGHq+vU9nTyuWu3acbyXxcUPUDOY= +github.com/NethermindEth/juno v0.12.5/go.mod h1:XonWmZVRwCVHv1gjoVCoTFiZnYObwdukpd3NCsl04bA= +github.com/NethermindEth/starknet.go v0.8.0 h1:mGh7qDWrvuXJPcgGJP31DpifzP6+Ef2gt/BQhaqsV40= +github.com/NethermindEth/starknet.go v0.8.0/go.mod h1:slNA8PxtxA/0LQv0FwHnL3lHFDNhVZfTK6U2gjVb7l8= github.com/ProjectZKM/Ziren/crates/go-runtime/zkvm_runtime v0.0.0-20251001021608-1fe7b43fc4d6 h1:1zYrtlhrZ6/b6SAjLSfKzWtdgqK0U+HtH/VcBWh1BaU= github.com/ProjectZKM/Ziren/crates/go-runtime/zkvm_runtime v0.0.0-20251001021608-1fe7b43fc4d6/go.mod h1:ioLG6R+5bUSO1oeGSDxOV3FADARuMoytZCSX6MEMQkI= +github.com/VictoriaMetrics/fastcache v1.13.0 h1:AW4mheMR5Vd9FkAPUv+NH6Nhw+fmbTMGMsNAoA/+4G0= +github.com/VictoriaMetrics/fastcache v1.13.0/go.mod h1:hHXhl4DA2fTL2HTZDJFXWgW0LNjo6B+4aj2Wmng3TjU= +github.com/VividCortex/gohistogram v1.0.0 h1:6+hBz+qvs0JOrrNhhmR7lFxo5sINxBCGXrdtl/UvroE= +github.com/VividCortex/gohistogram v1.0.0/go.mod h1:Pf5mBqqDxYaXu3hDrrU+w6nw50o/4+TcAqDqk/vUH7g= github.com/XSAM/otelsql v0.37.0 h1:ya5RNw028JW0eJW8Ma4AmoKxAYsJSGuNVbC7F1J457A= github.com/XSAM/otelsql v0.37.0/go.mod h1:LHbCu49iU8p255nCn1oi04oX2UjSoRcUMiKEHo2a5qM= -github.com/andybalholm/brotli v1.1.1 h1:PR2pgnyFznKEugtsUo0xLdDop5SKXd5Qf5ysW+7XdTA= -github.com/andybalholm/brotli v1.1.1/go.mod h1:05ib4cKhjx3OQYUY22hTVd34Bc8upXjOLL2rKwwZBoA= +github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho= +github.com/allegro/bigcache v1.2.1 h1:hg1sY1raCwic3Vnsvje6TT7/pnZba83LeFck5NrFKSc= +github.com/allegro/bigcache v1.2.1/go.mod h1:Cb/ax3seSYIx7SuZdm2G2xzfwmv3TPSk2ucNfQESPXM= +github.com/andybalholm/brotli v1.2.0 h1:ukwgCxwYrmACq68yiUqwIWnGY0cTPox/M94sVwToPjQ= +github.com/andybalholm/brotli v1.2.0/go.mod h1:rzTDkvFWvIrjDXZHkuS16NPggd91W3kUSvPlQ1pLaKY= +github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= github.com/apache/arrow-go/v18 v18.3.1 h1:oYZT8FqONiK74JhlH3WKVv+2NKYoyZ7C2ioD4Dj3ixk= github.com/apache/arrow-go/v18 v18.3.1/go.mod h1:12QBya5JZT6PnBihi5NJTzbACrDGXYkrgjujz3MRQXU= github.com/apache/thrift v0.21.0 h1:tdPmh/ptjE1IJnhbhrcl2++TauVjy242rkV/UzJChnE= github.com/apache/thrift v0.21.0/go.mod h1:W1H8aR/QRtYNvrPeFXBtobyRkd0/YVhTc6i07XIAgDw= +github.com/apapsch/go-jsonmerge/v2 v2.0.0 h1:axGnT1gRIfimI7gJifB699GoE/oq+F2MU7Dml6nw9rQ= +github.com/apapsch/go-jsonmerge/v2 v2.0.0/go.mod h1:lvDnEdqiQrp0O42VQGgmlKpxL1AP2+08jFMw88y4klk= +github.com/aptos-labs/aptos-go-sdk v1.11.0 h1:vIL1hpjECUiu7zMl9Wz6VV8ttXsrDqKUj0HxoeaIER4= +github.com/aptos-labs/aptos-go-sdk v1.11.0/go.mod h1:8YvYwRg93UcG6pTStCpZdYiscCtKh51sYfeLgIy/41c= +github.com/armon/go-metrics v0.4.1/go.mod h1:E6amYzXo6aW1tqzoZGT755KkbgrJsSdpwZ+3JqfkOG4= +github.com/atombender/go-jsonschema v0.16.1-0.20240916205339-a74cd4e2851c h1:cxQVoh6kY+c4b0HUchHjGWBI8288VhH50qxKG3hdEg0= +github.com/atombender/go-jsonschema v0.16.1-0.20240916205339-a74cd4e2851c/go.mod h1:3XzxudkrYVUvbduN/uI2fl4lSrMSzU0+3RCu2mpnfx8= +github.com/avast/retry-go/v4 v4.6.1 h1:VkOLRubHdisGrHnTu89g08aQEWEgRU7LVEop3GbIcMk= +github.com/avast/retry-go/v4 v4.6.1/go.mod h1:V6oF8njAwxJ5gRo1Q7Cxab24xs5NCWZBeaHHBklR8mA= github.com/aws/aws-sdk-go-v2 v1.41.1 h1:ABlyEARCDLN034NhxlRUSZr4l71mh+T5KAeGh6cerhU= github.com/aws/aws-sdk-go-v2 v1.41.1/go.mod h1:MayyLB8y+buD9hZqkCW3kX1AKq07Y5pXxtgB+rRFhz0= github.com/aws/aws-sdk-go-v2/config v1.28.4 h1:qgD0MKmkIzZR2DrAjWJcI9UkndjR+8f6sjUQvXh0mb0= @@ -42,64 +109,253 @@ github.com/aws/aws-sdk-go-v2/service/sts v1.33.0 h1:s7LRgBqhwLaxcocnAniBJp7gaAB+ github.com/aws/aws-sdk-go-v2/service/sts v1.33.0/go.mod h1:9XEUty5v5UAsMiFOBJrNibZgwCeOma73jgGwwhgffa8= github.com/aws/smithy-go v1.24.0 h1:LpilSUItNPFr1eY85RYgTIg5eIEPtvFbskaFcmmIUnk= github.com/aws/smithy-go v1.24.0/go.mod h1:LEj2LM3rBRQJxPZTB4KuzZkaZYnZPnvgIhb4pu07mx0= +github.com/aybabtme/rgbterm v0.0.0-20170906152045-cc83f3b3ce59 h1:WWB576BN5zNSZc/M9d/10pqEx5VHNhaQ/yOVAkmj5Yo= +github.com/aybabtme/rgbterm v0.0.0-20170906152045-cc83f3b3ce59/go.mod h1:q/89r3U2H7sSsE2t6Kca0lfwTK8JdoNGS/yzM/4iH5I= github.com/bahlo/generic-list-go v0.2.0 h1:5sz/EEAK+ls5wF+NeqDpk5+iNdMDXrh3z3nPnH1Wvgk= github.com/bahlo/generic-list-go v0.2.0/go.mod h1:2KvAjgMlE5NNynlg/5iLrrCCZ2+5xWbdbCW3pNTGyYg= +github.com/beevik/ntp v1.5.0 h1:y+uj/JjNwlY2JahivxYvtmv4ehfi3h74fAuABB9ZSM4= +github.com/beevik/ntp v1.5.0/go.mod h1:mJEhBrwT76w9D+IfOEGvuzyuudiW9E52U2BaTrMOYow= +github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= +github.com/benbjohnson/clock v1.3.5 h1:VvXlSJBzZpA/zum6Sj74hxwYI2DIxRWuNIoXAzHZz5o= +github.com/benbjohnson/clock v1.3.5/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= +github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= +github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= -github.com/bits-and-blooms/bitset v1.20.0 h1:2F+rfL86jE2d/bmw7OhqUg2Sj/1rURkBn3MdfoPyRVU= -github.com/bits-and-blooms/bitset v1.20.0/go.mod h1:7hO7Gc7Pp1vODcmWvKMRA9BNmbv6a/7QIWpPxHddWR8= +github.com/bgentry/speakeasy v0.2.0 h1:tgObeVOf8WAvtuAX6DhJ4xks4CFNwPDZiqzGqIHE51E= +github.com/bgentry/speakeasy v0.2.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= +github.com/bits-and-blooms/bitset v1.24.3 h1:Bte86SlO3lwPQqww+7BE9ZuUCKIjfqnG5jtEyqA9y9Y= +github.com/bits-and-blooms/bitset v1.24.3/go.mod h1:7hO7Gc7Pp1vODcmWvKMRA9BNmbv6a/7QIWpPxHddWR8= +github.com/blendle/zapdriver v1.3.1 h1:C3dydBOWYRiOk+B8X9IVZ5IOe+7cl+tGOexN4QqHfpE= +github.com/blendle/zapdriver v1.3.1/go.mod h1:mdXfREi6u5MArG4j9fewC+FGnXaBR+T4Ox4J2u4eHCc= +github.com/block-vision/sui-go-sdk v1.1.2 h1:p9DPfb51mEcTmF0Lx9ORpH+Nh9Rzg4Sv3Pu5gsJZ2AA= +github.com/block-vision/sui-go-sdk v1.1.2/go.mod h1:KlibJnwEpWt8qhQkIPxc/2ZE4kwh0Md6LvMHmW5kemA= +github.com/btcsuite/btcd v0.24.2 h1:aLmxPguqxza+4ag8R1I2nnJjSu2iFn/kqtHTIImswcY= +github.com/btcsuite/btcd v0.24.2/go.mod h1:5C8ChTkl5ejr3WHj8tkQSCmydiMEPB0ZhQhehpq7Dgg= +github.com/btcsuite/btcd/btcec/v2 v2.3.5 h1:dpAlnAwmT1yIBm3exhT1/8iUSD98RDJM5vqJVQDQLiU= +github.com/btcsuite/btcd/btcec/v2 v2.3.5/go.mod h1:m22FrOAiuxl/tht9wIqAoGHcbnCCaPWyauO8y2LGGtQ= +github.com/btcsuite/btcd/btcutil v1.1.6 h1:zFL2+c3Lb9gEgqKNzowKUPQNb8jV7v5Oaodi/AYFd6c= +github.com/btcsuite/btcd/btcutil v1.1.6/go.mod h1:9dFymx8HpuLqBnsPELrImQeTQfKBQqzqGbbV3jK55aE= +github.com/btcsuite/btcd/chaincfg/chainhash v1.1.0 h1:59Kx4K6lzOW5w6nFlA0v5+lk/6sjybR934QNHSJZPTQ= +github.com/btcsuite/btcd/chaincfg/chainhash v1.1.0/go.mod h1:7SFka0XMvUgj3hfZtydOrQY2mwhPclbT2snogU7SQQc= +github.com/btcsuite/btcutil v1.0.3-0.20201208143702-a53e38424cce h1:YtWJF7RHm2pYCvA5t0RPmAaLUhREsKuKd+SLhxFbFeQ= +github.com/btcsuite/btcutil v1.0.3-0.20201208143702-a53e38424cce/go.mod h1:0DVlHczLPewLcPGEIeUEzfOJhqGPQ0mJJRDBtD307+o= +github.com/buger/goterm v1.0.4 h1:Z9YvGmOih81P0FbVtEYTFF6YsSgxSUKEhf/f9bTMXbY= +github.com/buger/goterm v1.0.4/go.mod h1:HiFWV3xnkolgrBV3mY8m0X0Pumt4zg4QhbdOzQtB8tE= github.com/buger/jsonparser v1.1.1 h1:2PnMjfWD7wBILjqQbt530v576A/cAbQvEW9gGIpYMUs= github.com/buger/jsonparser v1.1.1/go.mod h1:6RYKKt7H4d4+iWqouImQ9R2FZql3VbhNgx27UK13J/0= +github.com/bytecodealliance/wasmtime-go/v28 v28.0.0 h1:aBU8cexP2rPZ0Qz488kvn2NXvWZHL2aG1/+n7Iv+xGc= +github.com/bytecodealliance/wasmtime-go/v28 v28.0.0/go.mod h1:4OCU0xAW9ycwtX4nMF4zxwgJBJ5/0eMfJiHB0wAmkV4= +github.com/bytedance/gopkg v0.1.3 h1:TPBSwH8RsouGCBcMBktLt1AymVo2TVsBVCY4b6TnZ/M= +github.com/bytedance/gopkg v0.1.3/go.mod h1:576VvJ+eJgyCzdjS+c4+77QF3p7ubbtiKARP3TxducM= +github.com/bytedance/sonic v1.14.2 h1:k1twIoe97C1DtYUo+fZQy865IuHia4PR5RPiuGPPIIE= +github.com/bytedance/sonic v1.14.2/go.mod h1:T80iDELeHiHKSc0C9tubFygiuXoGzrkjKzX2quAx980= +github.com/bytedance/sonic/loader v0.4.0 h1:olZ7lEqcxtZygCK9EKYKADnpQoYkRQxaeY2NYzevs+o= +github.com/bytedance/sonic/loader v0.4.0/go.mod h1:AR4NYCk5DdzZizZ5djGqQ92eEhCCcdf5x77udYiSJRo= +github.com/cenkalti/backoff v2.2.1+incompatible h1:tNowT99t7UNflLxfYYSlKYsBpXdEet03Pg2g16Swow4= +github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM= +github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8= +github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= github.com/cenkalti/backoff/v5 v5.0.2 h1:rIfFVxEf1QsI7E1ZHfp/B4DF/6QBAUhmgkxc0H7Zss8= github.com/cenkalti/backoff/v5 v5.0.2/go.mod h1:rkhZdG3JZukswDf7f0cwqPNk4K0sa+F97BxZthm/crw= +github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/cespare/cp v1.1.1 h1:nCb6ZLdB7NRaqsm91JtQTAme2SKJzXVsdPIPkyJr1MU= github.com/cespare/cp v1.1.1/go.mod h1:SOGHArjBr4JWaSDEVpWpo/hNg6RoKrls6Oh40hiwW+s= +github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= +github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= +github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= +github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag= +github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I= +github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cloudevents/sdk-go/binding/format/protobuf/v2 v2.16.1 h1:nLaJZcVAnaqch3K83AyzHfY2DmQM18/L7jvkmKSfkpI= github.com/cloudevents/sdk-go/binding/format/protobuf/v2 v2.16.1/go.mod h1:6Q+F2puKpJ6zWv+R02BVnizJICf7++oRT5zwpZQAsbk= github.com/cloudevents/sdk-go/v2 v2.16.1 h1:G91iUdqvl88BZ1GYYr9vScTj5zzXSyEuqbfE63gbu9Q= github.com/cloudevents/sdk-go/v2 v2.16.1/go.mod h1:v/kVOaWjNfbvc6tkhhlkhvLapj8Aa8kvXiH5GiOHCKI= +github.com/cloudwego/base64x v0.1.6 h1:t11wG9AECkCDk5fMSoxmufanudBtJ+/HemLstXDLI2M= +github.com/cloudwego/base64x v0.1.6/go.mod h1:OFcloc187FXDaYHvrNIjxSe8ncn0OOM8gEHfghB2IPU= +github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= github.com/cockroachdb/apd v1.1.0 h1:3LFP3629v+1aKXU5Q37mxmRxX/pIu1nijXydLShEq5I= github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ= -github.com/consensys/gnark-crypto v0.18.0 h1:vIye/FqI50VeAr0B3dx+YjeIvmc3LWz4yEfbWBpTUf0= -github.com/consensys/gnark-crypto v0.18.0/go.mod h1:L3mXGFTe1ZN+RSJ+CLjUt9x7PNdx8ubaYfDROyp2Z8c= +github.com/cockroachdb/datadriven v1.0.3-0.20230413201302-be42291fc80f h1:otljaYPt5hWxV3MUfO5dFPFiOXg9CyG5/kCfayTqsJ4= +github.com/cockroachdb/datadriven v1.0.3-0.20230413201302-be42291fc80f/go.mod h1:a9RdTaap04u637JoCzcUoIcDmvwSUtcUFtT/C3kJlTU= +github.com/cockroachdb/errors v1.12.0 h1:d7oCs6vuIMUQRVbi6jWWWEJZahLCfJpnJSVobd1/sUo= +github.com/cockroachdb/errors v1.12.0/go.mod h1:SvzfYNNBshAVbZ8wzNc/UPK3w1vf0dKDUP41ucAIf7g= +github.com/cockroachdb/fifo v0.0.0-20240816210425-c5d0cb0b6fc0 h1:pU88SPhIFid6/k0egdR5V6eALQYq2qbSmukrkgIh/0A= +github.com/cockroachdb/fifo v0.0.0-20240816210425-c5d0cb0b6fc0/go.mod h1:9/y3cnZ5GKakj/H4y9r9GTjCvAFta7KLgSHPJJYc52M= +github.com/cockroachdb/logtags v0.0.0-20241215232642-bb51bb14a506 h1:ASDL+UJcILMqgNeV5jiqR4j+sTuvQNHdf2chuKj1M5k= +github.com/cockroachdb/logtags v0.0.0-20241215232642-bb51bb14a506/go.mod h1:Mw7HqKr2kdtu6aYGn3tPmAftiP3QPX63LdK/zcariIo= +github.com/cockroachdb/pebble v1.1.5 h1:5AAWCBWbat0uE0blr8qzufZP5tBjkRyy/jWe1QWLnvw= +github.com/cockroachdb/pebble v1.1.5/go.mod h1:17wO9el1YEigxkP/YtV8NtCivQDgoCyBg5c4VR/eOWo= +github.com/cockroachdb/redact v1.1.6 h1:zXJBwDZ84xJNlHl1rMyCojqyIxv+7YUpQiJLQ7n4314= +github.com/cockroachdb/redact v1.1.6/go.mod h1:BVNblN9mBWFyMyqK1k3AAiSxhvhfK2oOZZ2lK+dpvRg= +github.com/cockroachdb/tokenbucket v0.0.0-20250429170803-42689b6311bb h1:3bCgBvB8PbJVMX1ouCcSIxvsqKPYM7gs72o0zC76n9g= +github.com/cockroachdb/tokenbucket v0.0.0-20250429170803-42689b6311bb/go.mod h1:7nc4anLGjupUW/PeY5qiNYsdNXj7zopG+eqsS7To5IQ= +github.com/coder/websocket v1.8.14 h1:9L0p0iKiNOibykf283eHkKUHHrpG7f65OE3BhhO7v9g= +github.com/coder/websocket v1.8.14/go.mod h1:NX3SzP+inril6yawo5CQXx8+fk145lPDC6pumgx0mVg= +github.com/cometbft/cometbft v0.38.20 h1:i9v9rvh3Z4CZvGSWrByAOpiqNq5WLkat3r/tE/B49RU= +github.com/cometbft/cometbft v0.38.20/go.mod h1:UCu8dlHqvkAsmAFmWDRWNZJPlu6ya2fTWZlDrWsivwo= +github.com/cometbft/cometbft-db v1.0.1 h1:SylKuLseMLQKw3+i8y8KozZyJcQSL98qEe2CGMCGTYE= +github.com/cometbft/cometbft-db v1.0.1/go.mod h1:EBrFs1GDRiTqrWXYi4v90Awf/gcdD5ExzdPbg4X8+mk= +github.com/consensys/gnark-crypto v0.18.1 h1:RyLV6UhPRoYYzaFnPQA4qK3DyuDgkTgskDdoGqFt3fI= +github.com/consensys/gnark-crypto v0.18.1/go.mod h1:L3mXGFTe1ZN+RSJ+CLjUt9x7PNdx8ubaYfDROyp2Z8c= +github.com/coreos/go-oidc/v3 v3.11.0 h1:Ia3MxdwpSw702YW0xgfmP1GVCMA9aEFWu12XUZ3/OtI= +github.com/coreos/go-oidc/v3 v3.11.0/go.mod h1:gE3LgjOgFoHi9a4ce4/tJczr0Ai2/BoDhf0r5lltWI0= github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= -github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= +github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= +github.com/cosmos/btcutil v1.0.5 h1:t+ZFcX77LpKtDBhjucvnOH8C2l2ioGsBNEQ3jef8xFk= +github.com/cosmos/btcutil v1.0.5/go.mod h1:IyB7iuqZMJlthe2tkIFL33xPyzbFYP0XVdS8P5lUPis= +github.com/cosmos/cosmos-db v1.1.3 h1:7QNT77+vkefostcKkhrzDK9uoIEryzFrU9eoMeaQOPY= +github.com/cosmos/cosmos-db v1.1.3/go.mod h1:kN+wGsnwUJZYn8Sy5Q2O0vCYA99MJllkKASbs6Unb9U= +github.com/cosmos/cosmos-proto v1.0.0-beta.5 h1:eNcayDLpip+zVLRLYafhzLvQlSmyab+RC5W7ZfmxJLA= +github.com/cosmos/cosmos-proto v1.0.0-beta.5/go.mod h1:hQGLpiIUloJBMdQMMWb/4wRApmI9hjHH05nefC0Ojec= +github.com/cosmos/cosmos-sdk v0.53.5 h1:JPue+SFn2gyDzTV9TYb8mGpuIH3kGt7WbGadulkpTcU= +github.com/cosmos/cosmos-sdk v0.53.5/go.mod h1:AQJx0jpon70WAD4oOs/y+SlST4u7VIwEPR6F8S7JMdo= +github.com/cosmos/go-bip39 v1.0.0 h1:pcomnQdrdH22njcAatO0yWojsUnCO3y2tNoV1cb6hHY= +github.com/cosmos/go-bip39 v1.0.0/go.mod h1:RNJv0H/pOIVgxw6KS7QeX2a0Uo0aKUlfhZ4xuwvCdJw= +github.com/cosmos/gogogateway v1.2.0 h1:Ae/OivNhp8DqBi/sh2A8a1D0y638GpL3tkmLQAiKxTE= +github.com/cosmos/gogogateway v1.2.0/go.mod h1:iQpLkGWxYcnCdz5iAdLcRBSw3h7NXeOkZ4GUkT+tbFI= +github.com/cosmos/gogoproto v1.7.2 h1:5G25McIraOC0mRFv9TVO139Uh3OklV2hczr13KKVHCA= +github.com/cosmos/gogoproto v1.7.2/go.mod h1:8S7w53P1Y1cHwND64o0BnArT6RmdgIvsBuco6uTllsk= +github.com/cosmos/iavl v1.2.2 h1:qHhKW3I70w+04g5KdsdVSHRbFLgt3yY3qTMd4Xa4rC8= +github.com/cosmos/iavl v1.2.2/go.mod h1:GiM43q0pB+uG53mLxLDzimxM9l/5N9UuSY3/D0huuVw= +github.com/cosmos/ics23/go v0.11.0 h1:jk5skjT0TqX5e5QJbEnwXIS2yI2vnmLOgpQPeM5RtnU= +github.com/cosmos/ics23/go v0.11.0/go.mod h1:A8OjxPE67hHST4Icw94hOxxFEJMBG031xIGF/JHNIY0= +github.com/cosmos/ledger-cosmos-go v0.16.0 h1:YKlWPG9NnGZIEUb2bEfZ6zhON1CHlNTg0QKRRGcNEd0= +github.com/cosmos/ledger-cosmos-go v0.16.0/go.mod h1:WrM2xEa8koYoH2DgeIuZXNarF7FGuZl3mrIOnp3Dp0o= +github.com/cpuguy83/go-md2man/v2 v2.0.6 h1:XJtiaUW6dEEqVuZiMTn1ldk455QWwEIsMIJlo5vtkx0= +github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g= github.com/crate-crypto/go-eth-kzg v1.4.0 h1:WzDGjHk4gFg6YzV0rJOAsTK4z3Qkz5jd4RE3DAvPFkg= github.com/crate-crypto/go-eth-kzg v1.4.0/go.mod h1:J9/u5sWfznSObptgfa92Jq8rTswn6ahQWEuiLHOjCUI= github.com/crate-crypto/go-ipa v0.0.0-20240724233137-53bbb0ceb27a h1:W8mUrRp6NOVl3J+MYp5kPMoUZPp7aOYHtaua31lwRHg= github.com/crate-crypto/go-ipa v0.0.0-20240724233137-53bbb0ceb27a/go.mod h1:sTwzHBvIzm2RfVCGNEBZgRyjwK40bVoun3ZnGOCafNM= github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= +github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= +github.com/danieljoos/wincred v1.2.1 h1:dl9cBrupW8+r5250DYkYxocLeZ1Y4vB1kxgtjxw8GQs= +github.com/danieljoos/wincred v1.2.1/go.mod h1:uGaFL9fDn3OLTvzCGulzE+SzjEe5NGlh5FdCcyfPwps= +github.com/danielkov/gin-helmet v0.0.0-20171108135313-1387e224435e h1:5jVSh2l/ho6ajWhSPNN84eHEdq3dp0T7+f6r3Tc6hsk= +github.com/danielkov/gin-helmet v0.0.0-20171108135313-1387e224435e/go.mod h1:IJgIiGUARc4aOr4bOQ85klmjsShkEEfiRc6q/yBSfo8= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 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/deckarep/golang-set/v2 v2.6.0 h1:XfcQbWM1LlMB8BsJ8N9vW5ehnnPVIw0je80NsVHagjM= -github.com/deckarep/golang-set/v2 v2.6.0/go.mod h1:VAky9rY/yGXJOLEDv3OMci+7wtDpOF4IN+y82NBOac4= -github.com/decred/dcrd/crypto/blake256 v1.0.1 h1:7PltbUIQB7u/FfZ39+DGa/ShuMyJ5ilcvdfma9wOH6Y= -github.com/decred/dcrd/crypto/blake256 v1.0.1/go.mod h1:2OfgNZ5wDpcsFmHmCK5gZTPcCXqlm2ArzUIkw9czNJo= -github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0 h1:rpfIENRNNilwHwZeG5+P150SMrnNEcHYvcCuK6dPZSg= -github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0/go.mod h1:v57UDF4pDQJcEfFUCRop3lJL149eHGSe9Jvczhzjo/0= +github.com/dchest/siphash v1.2.3 h1:QXwFc8cFOR2dSa/gE6o/HokBMWtLUaNDVd+22aKHeEA= +github.com/dchest/siphash v1.2.3/go.mod h1:0NvQU092bT0ipiFN++/rXm69QG9tVxLAlQHIXMPAkHc= +github.com/deckarep/golang-set/v2 v2.8.0 h1:swm0rlPCmdWn9mESxKOjWk8hXSqoxOp+ZlfuyaAdFlQ= +github.com/deckarep/golang-set/v2 v2.8.0/go.mod h1:VAky9rY/yGXJOLEDv3OMci+7wtDpOF4IN+y82NBOac4= +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.4.0 h1:NMZiJj8QnKe1LgsbDayM4UoHwbvwDRwnI3hwNaAHRnc= +github.com/decred/dcrd/dcrec/secp256k1/v4 v4.4.0/go.mod h1:ZXNYxsqcloTdSy/rNShjYzMhyjf0LaoftYK0p+A3h40= +github.com/deepmap/oapi-codegen v1.8.2 h1:SegyeYGcdi0jLLrpbCMoJxnUUn8GBXHsvr4rbzjuhfU= +github.com/deepmap/oapi-codegen v1.8.2/go.mod h1:YLgSKSDv/bZQB7N4ws6luhozi3cEdRktEqrX88CvjIw= +github.com/desertbit/timer v0.0.0-20180107155436-c41aec40b27f h1:U5y3Y5UE0w7amNe7Z5G/twsBW0KEalRQXZzf8ufSh9I= +github.com/desertbit/timer v0.0.0-20180107155436-c41aec40b27f/go.mod h1:xH/i4TFMt8koVQZ6WFms69WAsDWr2XsYL3Hkl7jkoLE= +github.com/dgraph-io/badger/v4 v4.7.0 h1:Q+J8HApYAY7UMpL8d9owqiB+odzEc0zn/aqOD9jhc6Y= +github.com/dgraph-io/badger/v4 v4.7.0/go.mod h1:He7TzG3YBy3j4f5baj5B7Zl2XyfNe5bl4Udl0aPemVA= +github.com/dgraph-io/ristretto/v2 v2.2.0 h1:bkY3XzJcXoMuELV8F+vS8kzNgicwQFAaGINAEJdWGOM= +github.com/dgraph-io/ristretto/v2 v2.2.0/go.mod h1:RZrm63UmcBAaYWC1DotLYBmTvgkrs0+XhBd7Npn7/zI= +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/dominikbraun/graph v0.23.0 h1:TdZB4pPqCLFxYhdyMFb1TBdFxp8XLcJfTTBQucVPgCo= +github.com/dominikbraun/graph v0.23.0/go.mod h1:yOjYyogZLY1LSG9E33JWZJiq5k83Qy2C6POAuiViluc= +github.com/doyensec/safeurl v0.2.1 h1:DY15JorEfQsnpBWhBkVQIkaif2jfxCC14PIuGDsjDVs= +github.com/doyensec/safeurl v0.2.1/go.mod h1:wzSXqC/6Z410qHz23jtBWT+wQ8yTxcY0p8bZH/4EZIg= +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/dvsekhvalnov/jose2go v1.7.0 h1:bnQc8+GMnidJZA8zc6lLEAb4xNrIqHwO+9TzqvtQZPo= +github.com/dvsekhvalnov/jose2go v1.7.0/go.mod h1:QsHjhyTlD/lAVqn/NSbVZmSCGeDehTB/mPZadG+mhXU= github.com/emicklei/dot v1.6.2 h1:08GN+DD79cy/tzN6uLCT84+2Wk9u+wvqP+Hkx/dIR8A= github.com/emicklei/dot v1.6.2/go.mod h1:DeV7GvQtIw4h2u73RKBkkFdvVAz0D9fzeJrgPW6gy/s= +github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= +github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= +github.com/esote/minmaxheap v1.0.0 h1:rgA7StnXXpZG6qlM0S7pUmEv1KpWe32rYT4x8J8ntaA= +github.com/esote/minmaxheap v1.0.0/go.mod h1:Ln8+i7fS1k3PLgZI2JAo0iA1as95QnIYiGCrqSJ5FZk= github.com/ethereum/c-kzg-4844/v2 v2.1.5 h1:aVtoLK5xwJ6c5RiqO8g8ptJ5KU+2Hdquf6G3aXiHh5s= github.com/ethereum/c-kzg-4844/v2 v2.1.5/go.mod h1:u59hRTTah4Co6i9fDWtiCjTrblJv0UwsqZKCc0GfgUs= +github.com/ethereum/go-bigmodexpfix v0.0.0-20250911101455-f9e208c548ab h1:rvv6MJhy07IMfEKuARQ9TKojGqLVNxQajaXEp/BoqSk= +github.com/ethereum/go-bigmodexpfix v0.0.0-20250911101455-f9e208c548ab/go.mod h1:IuLm4IsPipXKF7CW5Lzf68PIbZ5yl7FFd74l/E0o9A8= github.com/ethereum/go-ethereum v1.16.8 h1:LLLfkZWijhR5m6yrAXbdlTeXoqontH+Ga2f9igY7law= github.com/ethereum/go-ethereum v1.16.8/go.mod h1:Fs6QebQbavneQTYcA39PEKv2+zIjX7rPUZ14DER46wk= github.com/ethereum/go-verkle v0.2.2 h1:I2W0WjnrFUIzzVPwm8ykY+7pL2d4VhlsePn4j7cnFk8= github.com/ethereum/go-verkle v0.2.2/go.mod h1:M3b90YRnzqKyyzBEWJGqj8Qff4IDeXnzFw0P9bFw3uk= +github.com/expr-lang/expr v1.17.5 h1:i1WrMvcdLF249nSNlpQZN1S6NXuW9WaOfF5tPi3aw3k= +github.com/expr-lang/expr v1.17.5/go.mod h1:8/vRC7+7HBzESEqt5kKpYXxrxkr31SaO8r40VO/1IT4= +github.com/failsafe-go/failsafe-go v0.9.0 h1:w0g7iv48RpQvV3UH1VlgUnLx9frQfCwI7ljnJzqEhYg= +github.com/failsafe-go/failsafe-go v0.9.0/go.mod h1:sX5TZ4HrMLYSzErWeckIHRZWgZj9PbKMAEKOVLFWtfM= +github.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM= +github.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU= +github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= +github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= github.com/ferranbt/fastssz v0.1.4 h1:OCDB+dYDEQDvAgtAGnTSidK1Pe2tW3nFV40XyMkTeDY= github.com/ferranbt/fastssz v0.1.4/go.mod h1:Ea3+oeoRGGLGm5shYAeDgu6PGUlcvQhE2fILyD9+tGg= -github.com/fsnotify/fsnotify v1.8.0 h1:dAwr6QBTBZIkG8roQaJjGof0pp0EeF+tNV7YBP3F/8M= -github.com/fsnotify/fsnotify v1.8.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0= -github.com/gabriel-vasile/mimetype v1.4.8 h1:FfZ3gj38NjllZIeJAmMhr+qKL8Wu+nOoI3GqacKw1NM= -github.com/gabriel-vasile/mimetype v1.4.8/go.mod h1:ByKUIKGjh1ODkGM1asKUbQZOLGrPjydw3hYPU2YU9t8= +github.com/fortytw2/leaktest v1.3.0 h1:u8491cBMTQ8ft8aeV+adlcytMZylmA5nnwwkRZjI8vw= +github.com/fortytw2/leaktest v1.3.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHquHwclZch5g= +github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8= +github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= +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/fsnotify/fsnotify v1.5.4/go.mod h1:OVB6XrOHzAwXMpEM7uPOzcehqUV2UqJxmVXmkdnm1bU= +github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S9k= +github.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0= +github.com/fxamacker/cbor/v2 v2.9.0 h1:NpKPmjDBgUfBms6tr6JZkTHtfFGcMKsw3eGcmD/sapM= +github.com/fxamacker/cbor/v2 v2.9.0/go.mod h1:vM4b+DJCtHn+zz7h3FFp/hDAI9WNWCsZj23V5ytsSxQ= +github.com/gabriel-vasile/mimetype v1.4.10 h1:zyueNbySn/z8mJZHLt6IPw0KoZsiQNszIpU+bX4+ZK0= +github.com/gabriel-vasile/mimetype v1.4.10/go.mod h1:d+9Oxyo1wTzWdyVUPMmXFvp4F9tea18J8ufA774AB3s= +github.com/gagliardetto/binary v0.8.0 h1:U9ahc45v9HW0d15LoN++vIXSJyqR/pWw8DDlhd7zvxg= +github.com/gagliardetto/binary v0.8.0/go.mod h1:2tfj51g5o9dnvsc+fL3Jxr22MuWzYXwx9wEoN0XQ7/c= +github.com/gagliardetto/solana-go v1.14.0 h1:3WfAi70jOOjAJ0deFMjdhFYlLXATF4tOQXsDNWJtOLw= +github.com/gagliardetto/solana-go v1.14.0/go.mod h1:l/qqqIN6qJJPtxW/G1PF4JtcE3Zg2vD2EliZrr9Gn5k= +github.com/gagliardetto/treeout v0.1.4 h1:ozeYerrLCmCubo1TcIjFiOWTTGteOOHND1twdFpgwaw= +github.com/gagliardetto/treeout v0.1.4/go.mod h1:loUefvXTrlRG5rYmJmExNryyBRh8f89VZhmMOyCyqok= +github.com/gagliardetto/utilz v0.1.3 h1:A+asc+6/3a9qNBrgticApj3yW5F7y4TaJd8Ijg+o0zM= +github.com/gagliardetto/utilz v0.1.3/go.mod h1:b+rGFkRHz3HWJD0RYMzat47JyvbTtpE0iEcYTRJTLLA= +github.com/gballet/go-libpcsclite v0.0.0-20191108122812-4678299bea08 h1:f6D9Hr8xV8uYKlyuj8XIruxlh9WjVjdh1gIicAS7ays= +github.com/gballet/go-libpcsclite v0.0.0-20191108122812-4678299bea08/go.mod h1:x7DCsMOv1taUwEWCzT4cmDeAkigA5/QCwUodaVOe8Ww= +github.com/gedex/inflector v0.0.0-20170307190818-16278e9db813 h1:Uc+IZ7gYqAf/rSGFplbWBSHaGolEQlNLgMgSE3ccnIQ= +github.com/gedex/inflector v0.0.0-20170307190818-16278e9db813/go.mod h1:P+oSoE9yhSRvsmYyZsshflcR6ePWYLql6UU1amW13IM= +github.com/getsentry/sentry-go v0.35.1 h1:iopow6UVLE2aXu46xKVIs8Z9D/YZkJrHkgozrxa+tOQ= +github.com/getsentry/sentry-go v0.35.1/go.mod h1:C55omcY9ChRQIUcVcGcs+Zdy4ZpQGvNJ7JYHIoSWOtE= +github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= +github.com/gin-contrib/cors v1.7.2 h1:oLDHxdg8W/XDoN/8zamqk/Drgt4oVZDvaV0YmvVICQw= +github.com/gin-contrib/cors v1.7.2/go.mod h1:SUJVARKgQ40dmrzgXEVxj2m7Ig1v1qIboQkPDTQ9t2E= +github.com/gin-contrib/expvar v0.0.1 h1:IuU5ArEgihz50vG8Onrwz22kJr7Mcvgv9xSSpfU5g+w= +github.com/gin-contrib/expvar v0.0.1/go.mod h1:8o2CznfQi1JjktORdHr2/abg3wSV6OCnXh0yGypvvVw= +github.com/gin-contrib/sessions v0.0.5 h1:CATtfHmLMQrMNpJRgzjWXD7worTh7g7ritsQfmF+0jE= +github.com/gin-contrib/sessions v0.0.5/go.mod h1:vYAuaUPqie3WUSsft6HUlCjlwwoJQs97miaG2+7neKY= +github.com/gin-contrib/size v0.0.0-20230212012657-e14a14094dc4 h1:Z9J0PVIt1PuibOShaOw1jH8hUYz+Ak8NLsR/GI0Hv5I= +github.com/gin-contrib/size v0.0.0-20230212012657-e14a14094dc4/go.mod h1:CEPcgZiz8998l9E8fDm16h8UfHRL7b+5oG0j/0koeVw= +github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE= +github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= +github.com/gin-gonic/gin v1.10.1 h1:T0ujvqyCSqRopADpgPgiTT63DUQVSfojyME59Ei63pQ= +github.com/gin-gonic/gin v1.10.1/go.mod h1:4PMNQiOhvDRa013RKVbsiNwoyezlm2rm0uX/T7kzp5Y= +github.com/go-asn1-ber/asn1-ber v1.5.5 h1:MNHlNMBDgEKD4TcKr36vQN68BA00aDfjIt3/bD50WnA= +github.com/go-asn1-ber/asn1-ber v1.5.5/go.mod h1:hEBeB/ic+5LoWskz+yKT7vGhhPYkProFKoKdwZRWMe0= +github.com/go-errors/errors v1.4.2 h1:J6MZopCL4uSllY1OfXM374weqZFFItUbrImctkmUxIA= +github.com/go-errors/errors v1.4.2/go.mod h1:sIVyrIiJhuEF+Pj9Ebtd6P/rEYROXFi3BopGUQ5a5Og= +github.com/go-jose/go-jose/v4 v4.1.3 h1:CVLmWDhDVRa6Mi/IgCgaopNosCaHz7zrMeF9MlZRkrs= +github.com/go-jose/go-jose/v4 v4.1.3/go.mod h1:x4oUasVrzR7071A4TnHLGSPpNOm2a21K9Kf04k1rs08= github.com/go-json-experiment/json v0.0.0-20250223041408-d3c622f1b874 h1:F8d1AJ6M9UQCavhwmO6ZsrYLfG8zVFWfEfMS2MXPkSY= github.com/go-json-experiment/json v0.0.0-20250223041408-d3c622f1b874/go.mod h1:TiCD2a1pcmjd7YnhGH0f/zKNcCD06B029pHhzV23c2M= +github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-kit/kit v0.13.0 h1:OoneCcHKHQ03LfBpoQCUfCluwd2Vt3ohz+kvbJneZAU= +github.com/go-kit/kit v0.13.0/go.mod h1:phqEHMMUbyrCFCTgH48JueqrM3md2HcAZ8N3XE4FKDg= github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY= +github.com/go-kit/log v0.2.1 h1:MRVx0/zhvdseW+Gza6N9rVzU/IVzaeE1SFI4raAhmBU= +github.com/go-kit/log v0.2.1/go.mod h1:NwTd00d/i8cPZ3xOwwiv2PO5MOcx78fFErGNcVmBjv0= +github.com/go-ldap/ldap/v3 v3.4.6 h1:ert95MdbiG7aWo/oPYp9btL3KJlMPKnP58r09rI8T+A= +github.com/go-ldap/ldap/v3 v3.4.6/go.mod h1:IGMQANNtxpsOzj7uUAMjpGBaOVTC4DYyIy8VsTdxmtc= +github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= +github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= +github.com/go-logfmt/logfmt v0.6.0 h1:wGYYu3uicYdqXVgoYbvnkrPVXkuLM1p1ifugDMEdRi4= +github.com/go-logfmt/logfmt v0.6.0/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI= github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= @@ -114,38 +370,185 @@ github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/o github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY= github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY= github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY= -github.com/go-playground/validator/v10 v10.26.0 h1:SP05Nqhjcvz81uJaRfEV0YBSSSGMc/iMaVtFbr3Sw2k= -github.com/go-playground/validator/v10 v10.26.0/go.mod h1:I5QpIEbmr8On7W0TktmJAumgzX4CA1XNl4ZmDuVHKKo= +github.com/go-playground/validator/v10 v10.28.0 h1:Q7ibns33JjyW48gHkuFT91qX48KG0ktULL6FgHdG688= +github.com/go-playground/validator/v10 v10.28.0/go.mod h1:GoI6I1SjPBh9p7ykNE/yj3fFYbyDOpwMn5KXd+m2hUU= github.com/go-sql-driver/mysql v1.8.1 h1:LedoTUt/eveggdHS9qUFC1EFSa8bU2+1pZjSRpvNJ1Y= github.com/go-sql-driver/mysql v1.8.1/go.mod h1:wEBSXgmK//2ZFJyE+qWnIsVGmvmEKlqwuVSjsCm7DZg= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= github.com/go-viper/mapstructure/v2 v2.4.0 h1:EBsztssimR/CONLSZZ04E8qAkxNYq4Qp9LvH92wZUgs= github.com/go-viper/mapstructure/v2 v2.4.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM= +github.com/go-webauthn/webauthn v0.9.4 h1:YxvHSqgUyc5AK2pZbqkWWR55qKeDPhP8zLDr6lpIc2g= +github.com/go-webauthn/webauthn v0.9.4/go.mod h1:LqupCtzSef38FcxzaklmOn7AykGKhAhr9xlRbdbgnTw= +github.com/go-webauthn/x v0.1.5 h1:V2TCzDU2TGLd0kSZOXdrqDVV5JB9ILnKxA9S53CSBw0= +github.com/go-webauthn/x v0.1.5/go.mod h1:qbzWwcFcv4rTwtCLOZd+icnr6B7oSsAGZJqlt8cukqY= github.com/goccy/go-json v0.10.5 h1:Fq85nIqj+gXn/S5ahsiTlK3TmC85qgirsdTP/+DeaC4= github.com/goccy/go-json v0.10.5/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M= +github.com/goccy/go-yaml v1.12.0 h1:/1WHjnMsI1dlIBQutrvSMGZRQufVO3asrHfTwfACoPM= +github.com/goccy/go-yaml v1.12.0/go.mod h1:wKnAMd44+9JAAnGQpWVEgBzGt3YuTaQ4uXoHvE4m7WU= +github.com/godbus/dbus v0.0.0-20190726142602-4481cbc300e2 h1:ZpnhV/YsD2/4cESfV5+Hoeu/iUR3ruzNvZ+yQfO03a0= +github.com/godbus/dbus v0.0.0-20190726142602-4481cbc300e2/go.mod h1:bBOAhwG1umN6/6ZUMtDFBMQR8jRg9O75tm9K00oMsK4= +github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/gofrs/flock v0.12.1 h1:MTLVXXHf8ekldpJk3AKicLij9MdwOWkZ+a/jHHZby9E= github.com/gofrs/flock v0.12.1/go.mod h1:9zxTsyu5xtJ9DK+1tFZyibEV7y3uwDxPPfbxeeHCoD0= github.com/gofrs/uuid v4.0.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= github.com/gofrs/uuid v4.4.0+incompatible h1:3qXRTX8/NbyulANqlc0lchS1gqAVxRgsuW1YrTJupqA= github.com/gofrs/uuid v4.4.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= +github.com/gogo/googleapis v1.4.1 h1:1Yx4Myt7BxzvUr5ldGSbwYiZG6t9wGBZ+8/fX3Wvtq0= +github.com/gogo/googleapis v1.4.1/go.mod h1:2lpHqI5OcWCtVElxXnPt+s8oJvMpySlOyM6xDCrzib4= +github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= +github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= +github.com/golang-jwt/jwt/v4 v4.5.2 h1:YtQM7lnr8iZ+j5q71MGKkNw9Mn7AjHM68uc9g5fXeUI= +github.com/golang-jwt/jwt/v4 v4.5.2/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= +github.com/golang-jwt/jwt/v5 v5.2.3 h1:kkGXqQOBSDDWRhWNXTFpqGSCMyh/PLnqUvMGJPDJDs0= +github.com/golang-jwt/jwt/v5 v5.2.3/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk= +github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= +github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.0/go.mod h1:Qd/q+1AKNOZr9uGQzbzCmRO6sUih6GTPZv6a1/R87v0= +github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= +github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= +github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= +github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= +github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= +github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= +github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v1.0.0 h1:Oy607GVXHs7RtbggtPBnr2RmDArIsAefDwvrdWvRhGs= github.com/golang/snappy v1.0.0/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/google/btree v1.1.3 h1:CVpQJjYgC4VbzxeGVHfvZrv1ctoYCAI8vbl07Fcxlyg= +github.com/google/btree v1.1.3/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4= github.com/google/flatbuffers v25.2.10+incompatible h1:F3vclr7C3HpB1k9mxCGRMXq6FdUalZ6H/pNX4FP1v0Q= github.com/google/flatbuffers v25.2.10+incompatible/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8= +github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= +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.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= 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/go-tpm v0.9.0 h1:sQF6YqWMi+SCXpsmS3fd21oPy/vSddwZry4JnmltHVk= +github.com/google/go-tpm v0.9.0/go.mod h1:FkNVkc6C+IsvDI9Jw1OveJmxGZUUaKxtrpOS47QWKfU= +github.com/google/gofuzz v0.0.0-20170612174753-24818f796faf/go.mod h1:HP5RmnzzSNb993RKQDq4+1A4ia9nllfqcQFTQJedwGI= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= +github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/orderedcode v0.0.1 h1:UzfcAexk9Vhv8+9pNOgRu41f16lHq725vPwnSeiG/Us= +github.com/google/orderedcode v0.0.1/go.mod h1:iVyU4/qPKHY5h/wSd6rZZCDcLJNxiWO6dvsYES2Sb20= +github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20250317173921-a4b03ec1a45e h1:ijClszYn+mADRFY17kjQEVQ1XRhq2/JR1M3sGqeJoxs= +github.com/google/pprof v0.0.0-20250317173921-a4b03ec1a45e/go.mod h1:boTsfXsheKC2y+lKOCMpSfarhxDeIzfZG1jqGcPl3cA= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= +github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= 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/grpc-ecosystem/grpc-gateway/v2 v2.26.3 h1:5ZPtiqj0JL5oKWmcsq4VMaAW5ukBEgSGXEN89zeH1Jo= -github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.3/go.mod h1:ndYquD05frm2vACXE1nsccT4oJzjhw2arTS2cpUD1PI= +github.com/gorilla/context v1.1.1 h1:AWwleXJkX/nhcU9bZSnZoi3h/qGYqQAGhq6zZe/aQW8= +github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg= +github.com/gorilla/handlers v1.5.2 h1:cLTUSsNkgcwhgRqvCNmdbRWG0A3N4F+M2nWKdScwyEE= +github.com/gorilla/handlers v1.5.2/go.mod h1:dX+xVpaxdSw+q0Qek8SSsl3dfMk3jNddUkMzo0GtH0w= +github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY= +github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ= +github.com/gorilla/securecookie v1.1.2 h1:YCIWL56dvtr73r6715mJs5ZvhtnY73hBvEF8kXD8ePA= +github.com/gorilla/securecookie v1.1.2/go.mod h1:NfCASbcHqRSY+3a8tlWJwsQap2VX5pwzwo4h3eOamfo= +github.com/gorilla/sessions v1.2.2 h1:lqzMYz6bOfvn2WriPUjNByzeXIlVzURcPmgMczkmTjY= +github.com/gorilla/sessions v1.2.2/go.mod h1:ePLdVu+jbEgHH+KWw8I1z2wqd0BAdAQh/8LRvBeoNcQ= +github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg= +github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/grafana/pyroscope-go v1.2.7 h1:VWBBlqxjyR0Cwk2W6UrE8CdcdD80GOFNutj0Kb1T8ac= +github.com/grafana/pyroscope-go v1.2.7/go.mod h1:o/bpSLiJYYP6HQtvcoVKiE9s5RiNgjYTj1DhiddP2Pc= +github.com/grafana/pyroscope-go/godeltaprof v0.1.9 h1:c1Us8i6eSmkW+Ez05d3co8kasnuOY813tbMN8i/a3Og= +github.com/grafana/pyroscope-go/godeltaprof v0.1.9/go.mod h1:2+l7K7twW49Ct4wFluZD3tZ6e0SjanjcUUBPVD/UuGU= +github.com/graph-gophers/dataloader v5.0.0+incompatible h1:R+yjsbrNq1Mo3aPG+Z/EKYrXrXXUNJHOgbRt+U6jOug= +github.com/graph-gophers/dataloader v5.0.0+incompatible/go.mod h1:jk4jk0c5ZISbKaMe8WsVopGB5/15GvGHMdMdPtwlRp4= +github.com/graph-gophers/graphql-go v1.5.0 h1:fDqblo50TEpD0LY7RXk/LFVYEVqo3+tXMNMPSVXA1yc= +github.com/graph-gophers/graphql-go v1.5.0/go.mod h1:YtmJZDLbF1YYNrlNAuiO5zAStUWc3XZT07iGsVqe1Os= +github.com/grpc-ecosystem/go-grpc-middleware v1.4.0 h1:UH//fgunKIs4JdUbpDl1VZCDaL56wXCB/5+wF6uHfaI= +github.com/grpc-ecosystem/go-grpc-middleware v1.4.0/go.mod h1:g5qyo/la0ALbONm6Vbp88Yd8NsDy6rZz+RcrMPxvld8= +github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus v1.0.1 h1:qnpSQwGEnkcRpTqNOIR6bJbR0gAorgP9CSALpRcKoAA= +github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus v1.0.1/go.mod h1:lXGCsh6c22WGtjr+qGHj1otzZpV/1kwTMAqkwZsnWRU= +github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.3.2 h1:sGm2vDRFUrQJO/Veii4h4zG2vvqG6uWNkBHSTqXOZk0= +github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.3.2/go.mod h1:wd1YpapPLivG6nQgbf7ZkG1hhSOXDhhn4MLTknx2aAc= +github.com/grpc-ecosystem/grpc-gateway v1.16.0 h1:gmcG1KaJ57LophUzW0Hy8NmPhnMZb4M0+kPpLofRdBo= +github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.1 h1:X5VWvz21y3gzm9Nw/kaUeku/1+uBhcekkmy4IkffJww= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.1/go.mod h1:Zanoh4+gvIgluNqcfMVTJueD4wSS5hT7zTt4Mrutd90= +github.com/gsterjov/go-libsecret v0.0.0-20161001094733-a6f4afe4910c h1:6rhixN/i8ZofjG1Y75iExal34USq5p+wiN1tpie8IrU= +github.com/gsterjov/go-libsecret v0.0.0-20161001094733-a6f4afe4910c/go.mod h1:NMPJylDgVpX0MLRlPy15sqSwOFv/U1GZ2m21JhFfek0= +github.com/hako/durafmt v0.0.0-20200710122514-c0fb7b4da026 h1:BpJ2o0OR5FV7vrkDYfXYVJQeMNWa8RhklZOpW2ITAIQ= +github.com/hako/durafmt v0.0.0-20200710122514-c0fb7b4da026/go.mod h1:5Scbynm8dF1XAPwIwkGPqzkM/shndPm79Jd1003hTjE= +github.com/hashicorp/go-bexpr v0.1.10 h1:9kuI5PFotCboP3dkDYFr/wi0gg0QVbSNz5oFRpxn4uE= +github.com/hashicorp/go-bexpr v0.1.10/go.mod h1:oxlubA2vC/gFVfX1A6JGp7ls7uCDlfJn732ehYYg+g0= +github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= +github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ= +github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48= +github.com/hashicorp/go-envparse v0.1.0 h1:bE++6bhIsNCPLvgDZkYqo3nA+/PFI51pkrHdmPSDFPY= +github.com/hashicorp/go-envparse v0.1.0/go.mod h1:OHheN1GoygLlAkTlXLXvAdnXdZxy8JUweQ1rAXx1xnc= +github.com/hashicorp/go-hclog v1.6.3 h1:Qr2kF+eVWjTiYmU7Y31tYlP1h0q/X3Nl3tPGdaB11/k= +github.com/hashicorp/go-hclog v1.6.3/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M= +github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-immutable-radix v1.3.1 h1:DKHmCUm2hRBK510BaiZlwvpD40f8bJFeZnpfm2KLowc= +github.com/hashicorp/go-immutable-radix v1.3.1/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-metrics v0.5.4 h1:8mmPiIJkTPPEbAiV97IxdAGNdRdaWwVap1BU6elejKY= +github.com/hashicorp/go-metrics v0.5.4/go.mod h1:CG5yz4NZ/AI/aQt9Ucm/vdBnbh7fvmv4lxZ350i+QQI= +github.com/hashicorp/go-plugin v1.7.0 h1:YghfQH/0QmPNc/AZMTFE3ac8fipZyZECHdDPshfk+mA= +github.com/hashicorp/go-plugin v1.7.0/go.mod h1:BExt6KEaIYx804z8k4gRzRLEvxKVb+kn0NMcihqOqb8= +github.com/hashicorp/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs= +github.com/hashicorp/go-retryablehttp v0.7.7 h1:C8hUCYzor8PIfXHa4UrZkU4VvK8o9ISHxT2Q8+VepXU= +github.com/hashicorp/go-retryablehttp v0.7.7/go.mod h1:pkQpWZeYWskR+D1tR2O5OcBFOxfA7DoAO6xtkuQnHTk= +github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8= +github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v1.0.2 h1:dV3g9Z/unq5DpblPpw+Oqcv4dU/1omnb4Ok8iPY6p1c= +github.com/hashicorp/golang-lru v1.0.2/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= +github.com/hashicorp/golang-lru/v2 v2.0.7 h1:a+bsQ5rvGLjzHuww6tVxozPZFVghXaHOwFs4luLUK2k= +github.com/hashicorp/golang-lru/v2 v2.0.7/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM= +github.com/hashicorp/yamux v0.1.2 h1:XtB8kyFOyHXYVFnwT5C3+Bdo8gArse7j2AQ0DA0Uey8= +github.com/hashicorp/yamux v0.1.2/go.mod h1:C+zze2n6e/7wshOZep2A70/aQU6QBRWJO/G6FT1wIns= +github.com/hasura/go-graphql-client v0.14.5 h1:M9HxxGLCcDZnxJGYyWXAzDYEpommgjW+sUW3V8EaGms= +github.com/hasura/go-graphql-client v0.14.5/go.mod h1:jfSZtBER3or+88Q9vFhWHiFMPppfYILRyl+0zsgPIIw= +github.com/hdevalence/ed25519consensus v0.2.0 h1:37ICyZqdyj0lAZ8P4D1d1id3HqbbG1N3iBb1Tb4rdcU= +github.com/hdevalence/ed25519consensus v0.2.0/go.mod h1:w3BHWjwJbFU29IRHL1Iqkw3sus+7FctEyM4RqDxYNzo= +github.com/holiman/billy v0.0.0-20250707135307-f2f9b9aae7db h1:IZUYC/xb3giYwBLMnr8d0TGTzPKFGNTCGgGLoyeX330= +github.com/holiman/billy v0.0.0-20250707135307-f2f9b9aae7db/go.mod h1:xTEYN9KCHxuYHs+NmrmzFcnvHMzLLNiGFafCb1n3Mfg= +github.com/holiman/bloomfilter/v2 v2.0.3 h1:73e0e/V0tCydx14a0SCYS/EWCxgwLZ18CZcZKVu0fao= +github.com/holiman/bloomfilter/v2 v2.0.3/go.mod h1:zpoh+gs7qcpqrHr3dB55AMiJwo0iURXE7ZOP9L9hSkA= github.com/holiman/uint256 v1.3.2 h1:a9EgMPSC1AAaj1SZL5zIQD3WbwTuHrMGOerLjGmM/TA= github.com/holiman/uint256 v1.3.2/go.mod h1:EOMSn4q6Nyt9P6efbI3bueV4e1b3dGlUCXeiRV4ng7E= +github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= +github.com/huandu/skiplist v1.2.1 h1:dTi93MgjwErA/8idWTzIw4Y1kZsMWx35fmI2c8Rij7w= +github.com/huandu/skiplist v1.2.1/go.mod h1:7v3iFjLcSAzO4fN5B8dvebvo/qsfumiLiDXMrPiHF9w= +github.com/huin/goupnp v1.3.0 h1:UvLUlWDNpoUdYzb2TCn+MuTWtcjXKSza2n6CBdQ0xXc= +github.com/huin/goupnp v1.3.0/go.mod h1:gnGPsThkYa7bFi/KWmEysQRf48l2dvR5bxr2OFckNX8= +github.com/iancoleman/strcase v0.3.0 h1:nTXanmYxhfFAMjZL34Ov6gkzEsSJZ5DbhxWjvSASxEI= +github.com/iancoleman/strcase v0.3.0/go.mod h1:iwCmte+B7n89clKwxIoIXy/HfoL7AsD47ZCWhYzw7ho= +github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= +github.com/imdario/mergo v0.3.16 h1:wwQJbIsHYGMUyLSPrEq1CT16AhnhNJQ51+4fdHUnCl4= +github.com/imdario/mergo v0.3.16/go.mod h1:WBLT9ZmE3lPoWsEzCh9LPo3TiwVN+ZKEjmz+hD27ysY= +github.com/improbable-eng/grpc-web v0.15.0 h1:BN+7z6uNXZ1tQGcNAuaU1YjsLTApzkjt2tzCixLaUPQ= +github.com/improbable-eng/grpc-web v0.15.0/go.mod h1:1sy9HKV4Jt9aEs9JSnkWlRJPuPtwNr0l57L4f878wP8= github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= +github.com/influxdata/influxdb-client-go/v2 v2.4.0 h1:HGBfZYStlx3Kqvsv1h2pJixbCl/jhnFtxpKFAv9Tu5k= +github.com/influxdata/influxdb-client-go/v2 v2.4.0/go.mod h1:vLNHdxTJkIf2mSLvGrpj8TCcISApPoXkaxP8g9uRlW8= +github.com/influxdata/influxdb1-client v0.0.0-20220302092344-a9ab5670611c h1:qSHzRbhzK8RdXOsAdfDgO49TtqC1oZ+acxPrkfTxcCs= +github.com/influxdata/influxdb1-client v0.0.0-20220302092344-a9ab5670611c/go.mod h1:qj24IKcXYK6Iy9ceXlo3Tc+vtHo9lIhSX5JddghvEPo= +github.com/influxdata/line-protocol v0.0.0-20210311194329-9aa0e372d097 h1:vilfsDSy7TDxedi9gyBkMvAirat/oRcL0lFdJBf6tdM= +github.com/influxdata/line-protocol v0.0.0-20210311194329-9aa0e372d097/go.mod h1:xaLFMmpvUxqXtVkUJfg9QmT88cDaCJ3ZKgdZ78oO8Qo= +github.com/influxdata/tdigest v0.0.1 h1:XpFptwYmnEKUqmkcDjrzffswZ3nvNeevbUSLPP/ZzIY= +github.com/influxdata/tdigest v0.0.1/go.mod h1:Z0kXnxzbTC2qrx4NaIzYkE1k66+6oEDQTvL95hQFh5Y= github.com/invopop/jsonschema v0.13.0 h1:KvpoAJWEjR3uD9Kbm2HWJmqsEaHt8lBUpd0qHcIi21E= github.com/invopop/jsonschema v0.13.0/go.mod h1:ffZ5Km5SWWRAIN6wbDXItl95euhFz2uON45H2qjYt+0= github.com/jackc/chunkreader v1.0.0/go.mod h1:RT6O25fNZIuasFJRyZ4R/Y2BbhasbmZXF9QQ7T3kePo= @@ -199,20 +602,41 @@ github.com/jackc/puddle v0.0.0-20190413234325-e4ced69a3a2b/go.mod h1:m4B5Dj62Y0f github.com/jackc/puddle v0.0.0-20190608224051-11cab39313c9/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= github.com/jackc/puddle v1.1.3/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= github.com/jackc/puddle v1.3.0/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= +github.com/jackpal/go-nat-pmp v1.0.2 h1:KzKSgb7qkJvOUTqYl9/Hg/me3pWgBmERKrTGD7BdWus= +github.com/jackpal/go-nat-pmp v1.0.2/go.mod h1:QPH045xvCAeXUZOxsnwmrtiCoxIr9eob+4orBN1SBKc= +github.com/jinzhu/copier v0.4.0 h1:w3ciUoD19shMCRargcpm0cm91ytaBhDvuRpz1ODO/U8= +github.com/jinzhu/copier v0.4.0/go.mod h1:DfbEm0FYsaqBcKcFuvmOZb218JkPGtvSHsKg8S8hyyg= +github.com/jmhodges/levigo v1.0.0 h1:q5EC36kV79HWeTBWsod3mG11EgStG3qArTKcvlksN1U= +github.com/jmhodges/levigo v1.0.0/go.mod h1:Q6Qx+uH3RAqyK4rFQroq9RL7mdkABMcfhEI+nNuzMJQ= github.com/jmoiron/sqlx v1.4.0 h1:1PLqN7S1UYp5t4SrVVnt4nUVNemrDAtxlulVe+Qgm3o= github.com/jmoiron/sqlx v1.4.0/go.mod h1:ZrZ7UsYB/weZdl2Bxg6jCRO9c3YHl8r3ahlKmRT4JLY= +github.com/jonboulle/clockwork v0.5.0 h1:Hyh9A8u51kptdkR+cqRpT1EebBwTn1oK9YfGYbdFz6I= +github.com/jonboulle/clockwork v0.5.0/go.mod h1:3mZlmanh0g2NDKO5TWZVJAfofYk64M7XN3SzBPjZF60= +github.com/jpillora/backoff v1.0.0 h1:uvFg412JmmHBHw7iwprIxkPMI+sGQ4kzOWsMeHnm2EA= +github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= +github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= +github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= +github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= +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/klauspost/asmfmt v1.3.2 h1:4Ri7ox3EwapiOjCki+hw14RyKk201CN4rzyCJRFLpK4= github.com/klauspost/asmfmt v1.3.2/go.mod h1:AG8TuvYojzulgDAMCnYn50l/5QV3Bs/tp6j0HLHbNSE= -github.com/klauspost/compress v1.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zttxdo= -github.com/klauspost/compress v1.18.0/go.mod h1:2Pp+KzxcywXVXMr50+X0Q/Lsb43OQHYWRCY2AiWywWQ= -github.com/klauspost/cpuid/v2 v2.2.10 h1:tBs3QSyvjDyFTq3uoc/9xFpCuOsJQFNPiAhYdw2skhE= -github.com/klauspost/cpuid/v2 v2.2.10/go.mod h1:hqwkgyIinND0mEev00jJYCxPNVRVXFQeu1XKlok6oO0= +github.com/klauspost/compress v1.11.4/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= +github.com/klauspost/compress v1.18.1 h1:bcSGx7UbpBqMChDtsF28Lw6v/G94LPrrbMbdC3JH2co= +github.com/klauspost/compress v1.18.1/go.mod h1:ZQFFVG+MdnR0P+l6wpXgIL4NTtwiKIdBnrBd8Nrxr+0= +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/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +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= @@ -232,98 +656,339 @@ github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lib/pq v1.10.2/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw= github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= +github.com/linxGnu/grocksdb v1.9.3 h1:s1cbPcOd0cU2SKXRG1nEqCOWYAELQjdqg3RVI2MH9ik= +github.com/linxGnu/grocksdb v1.9.3/go.mod h1:QYiYypR2d4v63Wj1adOOfzglnoII0gLj3PNh4fZkcFA= +github.com/logrusorgru/aurora v2.0.3+incompatible h1:tOpm7WcpBTn4fjmVfgpQq0EfczGlG91VSDkswnjF5A8= +github.com/logrusorgru/aurora v2.0.3+incompatible/go.mod h1:7rIyQOR62GCctdiQpZ/zOJlFyk6y+94wXzv6RNZgaR4= +github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I= +github.com/magiconair/properties v1.8.10 h1:s31yESBquKXCV9a/ScB3ESkOjUYYv+X0rg8SYxI99mE= +github.com/magiconair/properties v1.8.10/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= github.com/mailru/easyjson v0.9.0 h1:PrnmzHw7262yW8sTBwxi1PdJA3Iw/EKBa8psRf7d9a4= github.com/mailru/easyjson v0.9.0/go.mod h1:1+xMtQp2MRNVL/V1bOzuP3aP8VNwRW55fQUto+XFtTU= +github.com/manyminds/api2go v0.0.0-20171030193247-e7b693844a6f h1:tVvGiZQFjOXP+9YyGqSA6jE55x1XVxmoPYudncxrZ8U= +github.com/manyminds/api2go v0.0.0-20171030193247-e7b693844a6f/go.mod h1:Z60vy0EZVSu0bOugCHdcN5ZxFMKSpjRgsnh0XKPFqqk= github.com/marcboeker/go-duckdb v1.8.5 h1:tkYp+TANippy0DaIOP5OEfBEwbUINqiFqgwMQ44jME0= github.com/marcboeker/go-duckdb v1.8.5/go.mod h1:6mK7+WQE4P4u5AFLvVBmhFxY5fvhymFptghgJX6B+/8= github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ= github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= +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.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= +github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= +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-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc= github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= github.com/mattn/go-sqlite3 v1.14.22/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y= github.com/mattn/go-sqlite3 v2.0.3+incompatible h1:gXHsfypPkaMZrKbD5209QV9jbUTJKjyR5WD3HYQSd+U= github.com/mattn/go-sqlite3 v2.0.3+incompatible/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= +github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/mfridman/interpolate v0.0.2 h1:pnuTK7MQIxxFz1Gr+rjSIx9u7qVjf5VOoM/u6BbAxPY= +github.com/mfridman/interpolate v0.0.2/go.mod h1:p+7uk6oE07mpE/Ik1b8EckO0O4ZXiGAfshKBWLUM9Xg= +github.com/miekg/dns v1.1.65 h1:0+tIPHzUW0GCge7IiK3guGP57VAw7hoPDfApjkMD1Fc= +github.com/miekg/dns v1.1.65/go.mod h1:Dzw9769uoKVaLuODMDZz9M6ynFU6Em65csPuoi8G0ck= github.com/minio/asm2plan9s v0.0.0-20200509001527-cdd76441f9d8 h1:AMFGa4R4MiIpspGNG7Z948v4n35fFGB3RR3G/ry4FWs= github.com/minio/asm2plan9s v0.0.0-20200509001527-cdd76441f9d8/go.mod h1:mC1jAcsrzbxHt8iiaC+zU4b1ylILSosueou12R++wfY= github.com/minio/c2goasm v0.0.0-20190812172519-36a3d3bbc4f3 h1:+n/aFZefKZp7spd8DFdX7uMikMLXX4oubIzJF4kv/wI= github.com/minio/c2goasm v0.0.0-20190812172519-36a3d3bbc4f3/go.mod h1:RagcQ7I8IeTMnF8JTXieKnO4Z6JCsikNEzj0DwauVzE= -github.com/minio/sha256-simd v1.0.0 h1:v1ta+49hkWZyvaKwrQB8elexRqm6Y0aMLjCNsrYxo6g= -github.com/minio/sha256-simd v1.0.0/go.mod h1:OuYzVNI5vcoYIAmbIvHPl3N3jUzVedXbKy5RFepssQM= +github.com/minio/highwayhash v1.0.3 h1:kbnuUMoHYyVl7szWjSxJnxw11k2U709jqFPPmIUyD6Q= +github.com/minio/highwayhash v1.0.3/go.mod h1:GGYsuwP/fPD6Y9hMiXuapVvlIUEhFhMTh0rxU3ik1LQ= +github.com/minio/sha256-simd v1.0.1 h1:6kaan5IFmwTNynnKKpDHe6FWHohJOHhCPchzK49dzMM= +github.com/minio/sha256-simd v1.0.1/go.mod h1:Pz6AKMiUdngCLpeTL/RJY1M9rUuPMYujV5xJjtbRSN8= +github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= +github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/mitchellh/go-testing-interface v1.14.1 h1:jrgshOhYAUVNMAJiKbEu7EqAwgJJ2JqpQmpLJOu07cU= +github.com/mitchellh/go-testing-interface v1.14.1/go.mod h1:gfgS7OtZj6MA4U1UrDRp04twqAjfvlZyCfX3sDjEym8= +github.com/mitchellh/go-wordwrap v1.0.1 h1:TLuKupo69TCn6TQSyGxwI1EblZZEsQ0vMlAFQflz0v0= +github.com/mitchellh/go-wordwrap v1.0.1/go.mod h1:R62XHJLzvMFRBbcrT7m7WgmE1eOyTSsCt+hzestvNj0= +github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/mitchellh/mapstructure v1.5.1-0.20220423185008-bf980b35cac4 h1:BpfhmLKZf+SjVanKKhCgf3bg+511DmU9eDQTen7LLbY= github.com/mitchellh/mapstructure v1.5.1-0.20220423185008-bf980b35cac4/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/pointerstructure v1.2.0 h1:O+i9nHnXS3l/9Wu7r4NrEdwA2VFTicjUEN1uBnDo34A= +github.com/mitchellh/pointerstructure v1.2.0/go.mod h1:BRAsLI5zgXmw97Lf6s25bs8ohIXc3tViBH44KcwB2g4= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= +github.com/mostynb/zstdpool-freelist v0.0.0-20201229113212-927304c0c3b1 h1:mPMvm6X6tf4w8y7j9YIt6V9jfWhL6QlbEc7CCmeQlWk= +github.com/mostynb/zstdpool-freelist v0.0.0-20201229113212-927304c0c3b1/go.mod h1:ye2e/VUEtE2BHE+G/QcKkcLQVAEJoYRFj5VUOQatCRE= 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/mtibben/percent v0.2.1 h1:5gssi8Nqo8QU/r2pynCm+hBQHpkB/uNK7BJCFogWdzs= +github.com/mtibben/percent v0.2.1/go.mod h1:KG9uO+SZkUp+VkRHsCdYQV3XSZrrSpR3O9ibNBTZrns= 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/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec= -github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY= +github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= +github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= +github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= +github.com/nxadm/tail v1.4.11 h1:8feyoE3OzPrcshW5/MJ4sGESc5cqmGkGCWlco4l0bqY= +github.com/nxadm/tail v1.4.11/go.mod h1:OTaG3NK980DZzxbRq6lEuzgU+mug70nY11sMd4JXXHc= +github.com/oapi-codegen/runtime v1.1.2 h1:P2+CubHq8fO4Q6fV1tqDBZHCwpVpvPg7oKiYzQgXIyI= +github.com/oapi-codegen/runtime v1.1.2/go.mod h1:SK9X900oXmPWilYR5/WKPzt3Kqxn/uS/+lbpREv+eCg= +github.com/oasisprotocol/curve25519-voi v0.0.0-20230904125328-1f23a7beb09a h1:dlRvE5fWabOchtH7znfiFCcOvmIYgOeAS5ifBXBlh9Q= +github.com/oasisprotocol/curve25519-voi v0.0.0-20230904125328-1f23a7beb09a/go.mod h1:hVoHR2EVESiICEMbg137etN/Lx+lSrHPTD39Z/uE+2s= +github.com/oklog/run v1.2.0 h1:O8x3yXwah4A73hJdlrwo/2X6J62gE5qTMusH0dvz60E= +github.com/oklog/run v1.2.0/go.mod h1:mgDbKRSwPhJfesJ4PntqFUbKQRZ50NgmZTSPlFA0YFk= +github.com/olekukonko/errors v1.1.0 h1:RNuGIh15QdDenh+hNvKrJkmxxjV4hcS50Db478Ou5sM= +github.com/olekukonko/errors v1.1.0/go.mod h1:ppzxA5jBKcO1vIpCXQ9ZqgDh8iwODz6OXIGKU8r5m4Y= +github.com/olekukonko/ll v0.0.9 h1:Y+1YqDfVkqMWuEQMclsF9HUR5+a82+dxJuL1HHSRpxI= +github.com/olekukonko/ll v0.0.9/go.mod h1:En+sEW0JNETl26+K8eZ6/W4UQ7CYSrrgg/EdIYT2H8g= +github.com/olekukonko/tablewriter v1.0.9 h1:XGwRsYLC2bY7bNd93Dk51bcPZksWZmLYuaTHR0FqfL8= +github.com/olekukonko/tablewriter v1.0.9/go.mod h1:5c+EBPeSqvXnLLgkm9isDdzR3wjfBkHR9Nhfp3NWrzo= +github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= +github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0= +github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE= +github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU= +github.com/onsi/ginkgo/v2 v2.1.3/go.mod h1:vw5CSIxN1JObi/U8gcbwft7ZxR2dgaR70JSE3/PpL4c= +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.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY= +github.com/onsi/gomega v1.19.0/go.mod h1:LY+I3pBVzYsTBU1AnDwOSxaYi9WoWiqgwooUqq9yPro= +github.com/onsi/gomega v1.36.2 h1:koNYke6TVk6ZmnyHrCXba/T/MoLBXFjeC1PtvYgw0A8= +github.com/onsi/gomega v1.36.2/go.mod h1:DdwyADRjrc825LhMEkD76cHR5+pUnjhUN8GlHlRPHzY= +github.com/opentracing/opentracing-go v1.2.1-0.20220228012449-10b1cf09e00b h1:FfH+VrHHk6Lxt9HdVS0PXzSXFyS2NbZKXv33FYPol0A= +github.com/opentracing/opentracing-go v1.2.1-0.20220228012449-10b1cf09e00b/go.mod h1:AC62GU6hc0BrNm+9RK9VSiwa/EUe1bkIeFORAMcHvJU= +github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY= +github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= +github.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaRUnok+kx1WdO15EQc= +github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ= +github.com/pelletier/go-toml v1.9.5 h1:4yBQzkHv+7BHq2PQUZF3Mx0IYxG7LsP222s7Agd3ve8= +github.com/pelletier/go-toml v1.9.5/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= github.com/pelletier/go-toml/v2 v2.2.4 h1:mye9XuhQ6gvn5h28+VilKrrPoQVanw5PMw/TB0t5Ec4= github.com/pelletier/go-toml/v2 v2.2.4/go.mod h1:2gIqNv+qfxSVS7cM2xJQKtLSTLUE9V8t9Stt+h56mCY= +github.com/peterh/liner v1.1.1-0.20190123174540-a2c9a5303de7 h1:oYW+YCJ1pachXTQmzR3rNLYGGz4g/UgFcjb28p/viDM= +github.com/peterh/liner v1.1.1-0.20190123174540-a2c9a5303de7/go.mod h1:CRroGNssyjTd/qIG2FyxByd2S8JEAZXBl4qUrZf8GS0= +github.com/petermattis/goid v0.0.0-20240813172612-4fcff4a6cae7 h1:Dx7Ovyv/SFnMFw3fD4oEoeorXc6saIiQ23LrGLth0Gw= +github.com/petermattis/goid v0.0.0-20240813172612-4fcff4a6cae7/go.mod h1:pxMtw7cyUw6B2bRH0ZBANSPg+AoSud1I1iyJHI69jH4= github.com/pierrec/lz4/v4 v4.1.22 h1:cKFw6uJDK+/gfw5BcDL0JL5aBsAFdsIT18eRtLj7VIU= github.com/pierrec/lz4/v4 v4.1.22/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4= +github.com/pingcap/errors v0.11.4 h1:lFuQV/oaUMGcD2tqt+01ROSmJs75VG1ToEOkZIZ4nE4= +github.com/pingcap/errors v0.11.4/go.mod h1:Oi8TUi2kEtXXLMJk9l1cGmz20kV3TaQ0usTwv5KuLY8= +github.com/pion/dtls/v2 v2.2.7/go.mod h1:8WiMkebSHFD0T+dIU+UeBaoV7kDhOW5oDCzZ7WZ/F9s= +github.com/pion/dtls/v2 v2.2.12 h1:KP7H5/c1EiVAAKUmXyCzPiQe5+bCJrpOeKg/L05dunk= +github.com/pion/dtls/v2 v2.2.12/go.mod h1:d9SYc9fch0CqK90mRk1dC7AkzzpwJj6u2GU3u+9pqFE= +github.com/pion/logging v0.2.2/go.mod h1:k0/tDVsRCX2Mb2ZEmTqNa7CWsQPc+YYCB7Q+5pahoms= +github.com/pion/logging v0.2.4 h1:tTew+7cmQ+Mc1pTBLKH2puKsOvhm32dROumOZ655zB8= +github.com/pion/logging v0.2.4/go.mod h1:DffhXTKYdNZU+KtJ5pyQDjvOAh/GsNSyv1lbkFbe3so= +github.com/pion/stun/v2 v2.0.0 h1:A5+wXKLAypxQri59+tmQKVs7+l6mMM+3d+eER9ifRU0= +github.com/pion/stun/v2 v2.0.0/go.mod h1:22qRSh08fSEttYUmJZGlriq9+03jtVmXNODgLccj8GQ= +github.com/pion/transport/v2 v2.2.1/go.mod h1:cXXWavvCnFF6McHTft3DWS9iic2Mftcz1Aq29pGcU5g= +github.com/pion/transport/v2 v2.2.4/go.mod h1:q2U/tf9FEfnSBGSW6w5Qp5PFWRLRj3NjLhCCgpRK4p0= +github.com/pion/transport/v2 v2.2.10 h1:ucLBLE8nuxiHfvkFKnkDQRYWYfp8ejf4YBOPfaQpw6Q= +github.com/pion/transport/v2 v2.2.10/go.mod h1:sq1kSLWs+cHW9E+2fJP95QudkzbK7wscs8yYgQToO5E= +github.com/pion/transport/v3 v3.0.1/go.mod h1:UY7kiITrlMv7/IKgd5eTUcaahZx5oUN3l9SzK5f5xE0= +github.com/pion/transport/v3 v3.0.7 h1:iRbMH05BzSNwhILHoBoAPxoB9xQgOaJk+591KC9P1o0= +github.com/pion/transport/v3 v3.0.7/go.mod h1:YleKiTZ4vqNxVwh77Z0zytYi7rXHl7j6uPLGhhz9rwo= +github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= +github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= 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/prometheus/client_golang v1.22.0 h1:rb93p9lokFEsctTys46VnV1kLCDpVZ0a/Y92Vm0Zc6Q= -github.com/prometheus/client_golang v1.22.0/go.mod h1:R7ljNsLXhuQXYZYtw6GAE9AZg8Y7vEW5scdCXrWRXC0= +github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE= +github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 h1:o4JXh1EVt9k/+g42oCprj/FisM4qX9L3sZB3upGN2ZU= +github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE= +github.com/pressly/goose/v3 v3.26.0 h1:KJakav68jdH0WDvoAcj8+n61WqOIaPGgH0bJWS6jpmM= +github.com/pressly/goose/v3 v3.26.0/go.mod h1:4hC1KrritdCxtuFsqgs1R4AU5bWtTAf+cnWvfhf2DNY= +github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= +github.com/prometheus/client_golang v1.4.0/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU= +github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= +github.com/prometheus/client_golang v1.11.1/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0= +github.com/prometheus/client_golang v1.23.0 h1:ust4zpdl9r4trLY/gSjlm07PuiBq2ynaXXlptpfy8Uc= +github.com/prometheus/client_golang v1.23.0/go.mod h1:i/o0R9ByOnHX0McrTMTyhYvKE4haaf2mW08I+jGAjEE= +github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.6.2 h1:oBsgwpGs7iVziMvrGhE53c/GrLUsZdHnqNwqPLxwZyk= github.com/prometheus/client_model v0.6.2/go.mod h1:y3m2F6Gdpfy6Ut/GBsUqTWZqCUvMVzSfMLjcu6wAwpE= +github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4= +github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= +github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc= github.com/prometheus/common v0.65.0 h1:QDwzd+G1twt//Kwj/Ww6E9FQq1iVMmODnILtW1t2VzE= github.com/prometheus/common v0.65.0/go.mod h1:0gZns+BLRQ3V6NdaerOhMbwwRbNh9hkGINtQAsP5GS8= -github.com/prometheus/procfs v0.16.1 h1:hZ15bTNuirocR6u0JZ6BAHHmwS1p8B4P6MRqxtzMyRg= -github.com/prometheus/procfs v0.16.1/go.mod h1:teAbpZRB1iIAJYREa1LsoWUXykVXA1KlTmWl8x/U+Is= +github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= +github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= +github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= +github.com/prometheus/procfs v0.17.0 h1:FuLQ+05u4ZI+SS/w9+BWEM2TXiHKsUQ9TADiRH7DuK0= +github.com/prometheus/procfs v0.17.0/go.mod h1:oPQLaDAMRbA+u8H5Pbfq+dl3VDAvHxMUOVhe0wYB2zw= +github.com/prometheus/prometheus v0.304.2 h1:HhjbaAwet87x8Be19PFI/5W96UMubGy3zt24kayEuh4= +github.com/prometheus/prometheus v0.304.2/go.mod h1:ioGx2SGKTY+fLnJSQCdTHqARVldGNS8OlIe3kvp98so= +github.com/prysmaticlabs/gohashtree v0.0.4-beta h1:H/EbCuXPeTV3lpKeXGPpEV9gsUpkqOOVnWapUyeWro4= +github.com/prysmaticlabs/gohashtree v0.0.4-beta/go.mod h1:BFdtALS+Ffhg3lGQIHv9HDWuHS8cTvHZzrHWxwOtGOs= +github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475 h1:N/ElC8H3+5XpJzTSTfLsJV/mx9Q9g7kxmchpfZyxgzM= +github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= +github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ= github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= +github.com/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs= +github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro= +github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= -github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII= -github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o= +github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= +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/cors v1.11.1 h1:eU3gRzXLRK57F5rKMGMZURNdIG4EoAmX8k94r9wXWHA= +github.com/rs/cors v1.11.1/go.mod h1:XyqrcTp5zjWr1wsJ8PIRZssZ8b/WMcMf71DJnit4EMU= github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ= +github.com/rs/xid v1.6.0/go.mod h1:7XoLgs4eV+QndskICGsho+ADou8ySMSjJKDIan90Nz0= github.com/rs/zerolog v1.13.0/go.mod h1:YbFCdg8HfsridGWAh22vktObvhZbQsZXe4/zB0OKkWU= github.com/rs/zerolog v1.15.0/go.mod h1:xYTKnLHcpfU2225ny5qZjxnj9NvkumZYjJHlAThCjNc= +github.com/rs/zerolog v1.34.0 h1:k43nTLIwcTVQAncfCw4KZ2VY6ukYoZaBPNOE8txlOeY= +github.com/rs/zerolog v1.34.0/go.mod h1:bJsvje4Z08ROH4Nhs5iH600c3IkWhwp44iRc54W6wYQ= +github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/ryanuber/go-glob v1.0.0 h1:iQh3xXAumdQ+4Ufa5b25cRpC5TYKlno6hsv6Cb3pkBk= +github.com/ryanuber/go-glob v1.0.0/go.mod h1:807d1WSdnB0XRJzKNil9Om6lcp/3a0v4qIHxIXzX/Yc= +github.com/sagikazarmark/locafero v0.11.0 h1:1iurJgmM9G3PA/I+wWYIOw/5SyBtxapeHDcg+AAIFXc= +github.com/sagikazarmark/locafero v0.11.0/go.mod h1:nVIGvgyzw595SUSUE6tvCp3YYTeHs15MvlmU87WwIik= +github.com/samber/lo v1.49.1 h1:4BIFyVfuQSEpluc7Fua+j1NolZHiEHEpaSEKdsH0tew= +github.com/samber/lo v1.49.1/go.mod h1:dO6KHFzUKXgP8LDhU0oI8d2hekjXnGOu0DB8Jecxd6o= +github.com/sanity-io/litter v1.5.5 h1:iE+sBxPBzoK6uaEP5Lt3fHNgpKcHXc/A2HGETy0uJQo= +github.com/sanity-io/litter v1.5.5/go.mod h1:9gzJgR2i4ZpjZHsKvUXIRQVk7P+yM3e+jAF7bU2UI5U= github.com/santhosh-tekuri/jsonschema/v5 v5.3.1 h1:lZUw3E0/J3roVtGQ+SCrUrg3ON6NgVqpn3+iol9aGu4= github.com/santhosh-tekuri/jsonschema/v5 v5.3.1/go.mod h1:uToXkOrWAZ6/Oc07xWQrPOhJotwFIyu2bBVN41fcDUY= +github.com/sasha-s/go-deadlock v0.3.5 h1:tNCOEEDG6tBqrNDOX35j/7hL5FcFViG6awUGROb2NsU= +github.com/sasha-s/go-deadlock v0.3.5/go.mod h1:bugP6EGbdGYObIlx7pUZtWqlvo8k9H6vCBBsiChJQ5U= github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= github.com/scylladb/go-reflectx v1.0.1 h1:b917wZM7189pZdlND9PbIJ6NQxfDPfBvUaQ7cjj1iZQ= github.com/scylladb/go-reflectx v1.0.1/go.mod h1:rWnOfDIRWBGN0miMLIcoPt/Dhi2doCMZqwMCJ3KupFc= +github.com/sethvargo/go-retry v0.3.0 h1:EEt31A35QhrcRZtrYFDTBg91cqZVnFL2navjDrah2SE= +github.com/sethvargo/go-retry v0.3.0/go.mod h1:mNX17F0C/HguQMyMyJxcnU471gOZGxCLyYaFyAZraas= github.com/shirou/gopsutil v3.21.11+incompatible h1:+1+c1VGhc88SSonWP6foOcLhvnKlUeu/erjjvaPEYiI= github.com/shirou/gopsutil v3.21.11+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA= +github.com/shirou/gopsutil/v3 v3.24.3 h1:eoUGJSmdfLzJ3mxIhmOAhgKEKgQkeOwKpz1NbhVnuPE= +github.com/shirou/gopsutil/v3 v3.24.3/go.mod h1:JpND7O217xa72ewWz9zN2eIIkPWsDN/3pl0H8Qt0uwg= +github.com/shoenig/go-m1cpu v0.1.6/go.mod h1:1JJMcUBvfNwpq05QDQVAnx3gUHr9IYF7GNg9SUEw2VQ= +github.com/shoenig/test v0.6.4/go.mod h1:byHiCGXqrVaflBLAMq/srcZIHynQPQgeyvkvXnjqq0k= github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4= github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= +github.com/shopspring/decimal v1.3.1/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= github.com/shopspring/decimal v1.4.0 h1:bxl37RwXBklmTi0C79JfXCEBD1cqqHt0bbgBAGFp81k= github.com/shopspring/decimal v1.4.0/go.mod h1:gawqmDU56v4yIKSwfBSFip1HdCCXN8/+DMd9qYNcwME= +github.com/sigurn/crc16 v0.0.0-20211026045750-20ab5afb07e3 h1:aQKxg3+2p+IFXXg97McgDGT5zcMrQoi0EICZs8Pgchs= +github.com/sigurn/crc16 v0.0.0-20211026045750-20ab5afb07e3/go.mod h1:9/etS5gpQq9BJsJMWg1wpLbfuSnkm8dPF6FdW2JXVhA= +github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= -github.com/smartcontractkit/chain-selectors v1.0.67 h1:gxTqP/JC40KDe3DE1SIsIKSTKTZEPyEU1YufO1admnw= -github.com/smartcontractkit/chain-selectors v1.0.67/go.mod h1:xsKM0aN3YGcQKTPRPDDtPx2l4mlTN1Djmg0VVXV40b8= -github.com/smartcontractkit/chainlink-common v0.9.6-0.20251107154219-ec6d8370ebbf h1:7nHbrw7LPFCL/6lOi8AMO84vEZXGWaLxvyGnlmdwvyA= -github.com/smartcontractkit/chainlink-common v0.9.6-0.20251107154219-ec6d8370ebbf/go.mod h1:AgiJcndCiWnUOVmCBX/K3PdST/fvrY1uCqSF65j960w= +github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= +github.com/smartcontractkit/chain-selectors v1.0.89 h1:L9oWZGqQXWyTPnC6ODXgu3b0DFyLmJ9eHv+uJrE9IZY= +github.com/smartcontractkit/chain-selectors v1.0.89/go.mod h1:qy7whtgG5g+7z0jt0nRyii9bLND9m15NZTzuQPkMZ5w= +github.com/smartcontractkit/chainlink-aptos v0.0.0-20251027153600-2b072ff3618e h1:HIgcJV/CyhBntE5gK/8WitVzqD0k8PkuYj+lhfa6B6U= +github.com/smartcontractkit/chainlink-aptos v0.0.0-20251027153600-2b072ff3618e/go.mod h1:iteU0WORHkArACVh/HoY/1bipV4TcNcJdTmom9uIT0E= +github.com/smartcontractkit/chainlink-automation v0.8.1 h1:sTc9LKpBvcKPc1JDYAmgBc2xpDKBco/Q4h4ydl6+UUU= +github.com/smartcontractkit/chainlink-automation v0.8.1/go.mod h1:Iij36PvWZ6blrdC5A/nrQUBuf3MH3JvsBB9sSyc9W08= +github.com/smartcontractkit/chainlink-ccip v0.1.1-solana.0.20251128020529-88d93b01d749 h1:2Cn3OA7vJxXyR/U9JHFGwa8H8YKTPFxNlMrFNb8f46g= +github.com/smartcontractkit/chainlink-ccip v0.1.1-solana.0.20251128020529-88d93b01d749/go.mod h1:pETrvAF8uvkZgtDgI/oRllZZaC4IpPO26tMxh1u9LC4= +github.com/smartcontractkit/chainlink-ccip/ccv/chains/evm v0.0.0-20251229170147-e243de8c69ad h1:1GHqHUo/ZRrJUDNVAGJ9Ff7RTp5NxtMHSykZWVePAbM= +github.com/smartcontractkit/chainlink-ccip/ccv/chains/evm v0.0.0-20251229170147-e243de8c69ad/go.mod h1:Gl35ExaFLinqVhp50+Yq1GnMuHb3fnDtZUFPCtcfV3M= +github.com/smartcontractkit/chainlink-ccip/chains/solana v0.0.0-20250912190424-fd2e35d7deb5 h1:f8ak6g6P2KT4HjUbleU+Bh0gUJXMoGuoriMSyGxxD4M= +github.com/smartcontractkit/chainlink-ccip/chains/solana v0.0.0-20250912190424-fd2e35d7deb5/go.mod h1:Ve1xD71bl193YIZQEoJMmBqLGQJdNs29bwbuObwvbhQ= +github.com/smartcontractkit/chainlink-ccip/chains/solana/gobindings v0.0.0-20250912190424-fd2e35d7deb5 h1:Z4t2ZY+ZyGWxtcXvPr11y4o3CGqhg3frJB5jXkCSvWA= +github.com/smartcontractkit/chainlink-ccip/chains/solana/gobindings v0.0.0-20250912190424-fd2e35d7deb5/go.mod h1:xtZNi6pOKdC3sLvokDvXOhgHzT+cyBqH/gWwvxTxqrg= +github.com/smartcontractkit/chainlink-ccv v0.0.0-20260106165728-3d896e87cc56 h1:M6eS2r11Vbbll/bve5Us17cNYDlgs+dvrggPFVnhrgQ= +github.com/smartcontractkit/chainlink-ccv v0.0.0-20260106165728-3d896e87cc56/go.mod h1:6N8NSPmsy+sxtRBmBUwWlDyxPyauS7HMDzUl/lyJw7Y= github.com/smartcontractkit/chainlink-common/pkg/chipingress v0.0.10 h1:FJAFgXS9oqASnkS03RE1HQwYQQxrO4l46O5JSzxqLgg= github.com/smartcontractkit/chainlink-common/pkg/chipingress v0.0.10/go.mod h1:oiDa54M0FwxevWwyAX773lwdWvFYYlYHHQV1LQ5HpWY= -github.com/smartcontractkit/chainlink-protos/cre/go v0.0.0-20251124151448-0448aefdaab9 h1:QRWXJusIj/IRY5Pl3JclNvDre0cZPd/5NbILwc4RV2M= -github.com/smartcontractkit/chainlink-protos/cre/go v0.0.0-20251124151448-0448aefdaab9/go.mod h1:jUC52kZzEnWF9tddHh85zolKybmLpbQ1oNA4FjOHt1Q= +github.com/smartcontractkit/chainlink-data-streams v0.1.10 h1:YCwQNCcxFuoR714NV5UJ8oNwG/1j2PETUfZFssonTT8= +github.com/smartcontractkit/chainlink-data-streams v0.1.10/go.mod h1:8rUcGhjeXBoTFx2MynWgXiBWzVSB+LXd9JR6m8y2FfQ= +github.com/smartcontractkit/chainlink-evm v0.3.4-0.20251210110629-10c56e8d2cec h1:K8sLjgwPgozQb86LH+aWXqBUJak6VGwSt5YiKbCI/uY= +github.com/smartcontractkit/chainlink-evm v0.3.4-0.20251210110629-10c56e8d2cec/go.mod h1:9VcrUs+H/f9ekkqAdfUd70Pk2dA1Zc3KykJVFBfJNHs= +github.com/smartcontractkit/chainlink-evm/gethwrappers v0.0.0-20251211123524-f0c4fe7cfc0a h1:kVKWRGrSCioMY2lEVIEblerv/KkINIQS2hLUOw2wKOg= +github.com/smartcontractkit/chainlink-evm/gethwrappers v0.0.0-20251211123524-f0c4fe7cfc0a/go.mod h1:oyfOm4k0uqmgZIfxk1elI/59B02shbbJQiiUdPdbMgI= +github.com/smartcontractkit/chainlink-feeds v0.1.2-0.20250227211209-7cd000095135 h1:8u9xUrC+yHrTDexOKDd+jrA6LCzFFHeX1G82oj2fsSI= +github.com/smartcontractkit/chainlink-feeds v0.1.2-0.20250227211209-7cd000095135/go.mod h1:NkvE4iQgiT7dMCP6U3xPELHhWhN5Xr6rHC0axRebyMU= +github.com/smartcontractkit/chainlink-framework/capabilities v0.0.0-20250818175541-3389ac08a563 h1:ACpDbAxG4fa4sA83dbtYcrnlpE/y7thNIZfHxTv2ZLs= +github.com/smartcontractkit/chainlink-framework/capabilities v0.0.0-20250818175541-3389ac08a563/go.mod h1:jP5mrOLFEYZZkl7EiCHRRIMSSHCQsYypm1OZSus//iI= +github.com/smartcontractkit/chainlink-framework/chains v0.0.0-20251210101658-1c5c8e4c4f15 h1:Mf+IRvrXutcKAKpuOxq5Ae+AAw4Z5vc66q1xI7qimZQ= +github.com/smartcontractkit/chainlink-framework/chains v0.0.0-20251210101658-1c5c8e4c4f15/go.mod h1:kGprqyjsz6qFNVszOQoHc24wfvCjyipNZFste/3zcbs= +github.com/smartcontractkit/chainlink-framework/metrics v0.0.0-20251206233640-139a324649d9 h1:TAVreQK5eP63a0zu5Qe34i4pYGGo5x8zgfJ1NVVo6K4= +github.com/smartcontractkit/chainlink-framework/metrics v0.0.0-20251206233640-139a324649d9/go.mod h1:HG/aei0MgBOpsyRLexdKGtOUO8yjSJO3iUu0Uu8KBm4= +github.com/smartcontractkit/chainlink-framework/multinode v0.0.0-20251021173435-e86785845942 h1:T/eCDsUI8EJT4n5zSP4w1mz4RHH+ap8qieA17QYfBhk= +github.com/smartcontractkit/chainlink-framework/multinode v0.0.0-20251021173435-e86785845942/go.mod h1:2JTBNp3FlRdO/nHc4dsc9bfxxMClMO1Qt8sLJgtreBY= +github.com/smartcontractkit/chainlink-protos/billing/go v0.0.0-20251024234028-0988426d98f4 h1:GCzrxDWn3b7jFfEA+WiYRi8CKoegsayiDoJBCjYkneE= +github.com/smartcontractkit/chainlink-protos/billing/go v0.0.0-20251024234028-0988426d98f4/go.mod h1:HHGeDUpAsPa0pmOx7wrByCitjQ0mbUxf0R9v+g67uCA= +github.com/smartcontractkit/chainlink-protos/chainlink-ccv/committee-verifier v0.0.0-20251211142334-5c3421fe2c8d h1:VYoBBNnQpZ5p+enPTl8SkKBRaubqyGpO0ul3B1np++I= +github.com/smartcontractkit/chainlink-protos/chainlink-ccv/committee-verifier v0.0.0-20251211142334-5c3421fe2c8d/go.mod h1:oNFoKHRIerxuaANa8ASNejtHrdsG26LqGtQ2XhSac2g= +github.com/smartcontractkit/chainlink-protos/chainlink-ccv/message-discovery v0.0.0-20251211142334-5c3421fe2c8d h1:pKCyW7BYzO5GThFNlXZY0Azx/yOnI4b5GeuLeU23ie0= +github.com/smartcontractkit/chainlink-protos/chainlink-ccv/message-discovery v0.0.0-20251211142334-5c3421fe2c8d/go.mod h1:ATjAPIVJibHRcIfiG47rEQkUIOoYa6KDvWj3zwCAw6g= +github.com/smartcontractkit/chainlink-protos/chainlink-ccv/verifier v0.0.0-20251211142334-5c3421fe2c8d h1:AJy55QJ/pBhXkZjc7N+ATnWfxrcjq9BI9DmdtdjwDUQ= +github.com/smartcontractkit/chainlink-protos/chainlink-ccv/verifier v0.0.0-20251211142334-5c3421fe2c8d/go.mod h1:5JdppgngCOUS76p61zCinSCgOhPeYQ+OcDUuome5THQ= +github.com/smartcontractkit/chainlink-protos/cre/go v0.0.0-20260206000552-087e235a7963 h1:DCLvEn4KkFzYbK/AYl4vJmf6EHaskPYvGDGdd0kOma0= +github.com/smartcontractkit/chainlink-protos/cre/go v0.0.0-20260206000552-087e235a7963/go.mod h1:Jqt53s27Tr0jDl8mdBXg1xhu6F8Fci8JOuq43tgHOM8= github.com/smartcontractkit/chainlink-protos/linking-service/go v0.0.0-20251002192024-d2ad9222409b h1:QuI6SmQFK/zyUlVWEf0GMkiUYBPY4lssn26nKSd/bOM= github.com/smartcontractkit/chainlink-protos/linking-service/go v0.0.0-20251002192024-d2ad9222409b/go.mod h1:qSTSwX3cBP3FKQwQacdjArqv0g6QnukjV4XuzO6UyoY= +github.com/smartcontractkit/chainlink-protos/node-platform v0.0.0-20260205130626-db2a2aab956b h1:36knUpKHHAZ86K4FGWXtx8i/EQftGdk2bqCoEu/Cha8= +github.com/smartcontractkit/chainlink-protos/node-platform v0.0.0-20260205130626-db2a2aab956b/go.mod h1:dkR2uYg9XYJuT1JASkPzWE51jjFkVb86P7a/yXe5/GM= +github.com/smartcontractkit/chainlink-protos/orchestrator v0.10.0 h1:0eroOyBwmdoGUwUdvMI0/J7m5wuzNnJDMglSOK1sfNY= +github.com/smartcontractkit/chainlink-protos/orchestrator v0.10.0/go.mod h1:m/A3lqD7ms/RsQ9BT5P2uceYY0QX5mIt4KQxT2G6qEo= +github.com/smartcontractkit/chainlink-protos/rmn/v1.6/go v0.0.0-20250131130834-15e0d4cde2a6 h1:L6KJ4kGv/yNNoCk8affk7Y1vAY0qglPMXC/hevV/IsA= +github.com/smartcontractkit/chainlink-protos/rmn/v1.6/go v0.0.0-20250131130834-15e0d4cde2a6/go.mod h1:FRwzI3hGj4CJclNS733gfcffmqQ62ONCkbGi49s658w= +github.com/smartcontractkit/chainlink-protos/storage-service v0.3.0 h1:B7itmjy+CMJ26elVw/cAJqqhBQ3Xa/mBYWK0/rQ5MuI= +github.com/smartcontractkit/chainlink-protos/storage-service v0.3.0/go.mod h1:h6kqaGajbNRrezm56zhx03p0mVmmA2xxj7E/M4ytLUA= +github.com/smartcontractkit/chainlink-protos/svr v1.1.0 h1:79Z9N9dMbMVRGaLoDPAQ+vOwbM+Hnx8tIN2xCPG8H4o= +github.com/smartcontractkit/chainlink-protos/svr v1.1.0/go.mod h1:TcOliTQU6r59DwG4lo3U+mFM9WWyBHGuFkkxQpvSujo= +github.com/smartcontractkit/chainlink-protos/workflows/go v0.0.0-20260205231316-3b9c600dd791 h1:S+yHuhcny3AKOhCekMQa65uUeR/p9rGrUIb8eifkSTY= +github.com/smartcontractkit/chainlink-protos/workflows/go v0.0.0-20260205231316-3b9c600dd791/go.mod h1:GTpDgyK0OObf7jpch6p8N281KxN92wbB8serZhU9yRc= +github.com/smartcontractkit/chainlink-solana v1.1.2-0.20251121223352-370eb61346d6 h1:4cvFf82P3VcNHgqUG0aRBeIMZd+wSX37ha28Gkie9Lk= +github.com/smartcontractkit/chainlink-solana v1.1.2-0.20251121223352-370eb61346d6/go.mod h1:zX8dX6aXjJNkfbpr1AiTzCioma0sHh5CBPZKtqC7plY= +github.com/smartcontractkit/chainlink-sui v0.0.0-20251205161630-88314452254c h1:aNA7J31EuOf755BDgNuhxte5+Z6wucBx/ONGihw2OqA= +github.com/smartcontractkit/chainlink-sui v0.0.0-20251205161630-88314452254c/go.mod h1:zrtmeh3wHL+qXu/vaaR7lZ5TSh00I4JYbpOqqb9bXp0= +github.com/smartcontractkit/chainlink-ton v0.0.0-20251219221624-54a39a031e62 h1:/gnBkA9Ph6+EaWoBuR7FE8UIKfegY7eP3+QhxvVTYxw= +github.com/smartcontractkit/chainlink-ton v0.0.0-20251219221624-54a39a031e62/go.mod h1:z27AgU6fEXkkfmUAzcbEH9u3RKz2oaGy3isb7KK6Z2E= +github.com/smartcontractkit/chainlink-tron/relayer v0.0.11-0.20251014143056-a0c6328c91e9 h1:7Ut0g+Pdm+gcu2J/Xv8OpQOVf7uLGErMX8yhC4b4tIA= +github.com/smartcontractkit/chainlink-tron/relayer v0.0.11-0.20251014143056-a0c6328c91e9/go.mod h1:h9hMs6K4hT1+mjYnJD3/SW1o7yC/sKjNi0Qh8hLfiCE= +github.com/smartcontractkit/chainlink-tron/relayer/gotron-sdk v0.0.5-0.20251014124537-af6b1684fe15 h1:idp/RjsFznR48JWGfZICsrpcl9JTrnMzoUNVz8MhQMI= +github.com/smartcontractkit/chainlink-tron/relayer/gotron-sdk v0.0.5-0.20251014124537-af6b1684fe15/go.mod h1:ea1LESxlSSOgc2zZBqf1RTkXTMthHaspdqUHd7W4lF0= +github.com/smartcontractkit/chainlink/v2 v2.32.0 h1:Fax3JOIAa0uvthgLsd34ktekmSkrDMP2rl0/KFVugcY= +github.com/smartcontractkit/chainlink/v2 v2.32.0/go.mod h1:MIh2RAuTXdC3voDTo5+AtPyJPQfeIH5hkBDZQ0P1tjg= github.com/smartcontractkit/freeport v0.1.3-0.20250716200817-cb5dfd0e369e h1:Hv9Mww35LrufCdM9wtS9yVi/rEWGI1UnjHbcKKU0nVY= github.com/smartcontractkit/freeport v0.1.3-0.20250716200817-cb5dfd0e369e/go.mod h1:T4zH9R8R8lVWKfU7tUvYz2o2jMv1OpGCdpY2j2QZXzU= -github.com/smartcontractkit/libocr v0.0.0-20250912173940-f3ab0246e23d h1:LokA9PoCNb8mm8mDT52c3RECPMRsGz1eCQORq+J3n74= -github.com/smartcontractkit/libocr v0.0.0-20250912173940-f3ab0246e23d/go.mod h1:Acy3BTBxou83ooMESLO90s8PKSu7RvLCzwSTbxxfOK0= -github.com/spf13/cobra v1.8.1 h1:e5/vxKd/rZsfSJMUX1agtjeTDf+qv1/JdBF8gg5k9ZM= -github.com/spf13/cobra v1.8.1/go.mod h1:wHxEcudfqmLYa8iTfL+OuZPbBZkmvliBWKIezN3kD9Y= -github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= -github.com/spf13/pflag v1.0.6 h1:jFzHGLGAlb3ruxLB8MhbI6A8+AQX/2eW4qeyNZXNp2o= -github.com/spf13/pflag v1.0.6/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/smartcontractkit/grpc-proxy v0.0.0-20240830132753-a7e17fec5ab7 h1:12ijqMM9tvYVEm+nR826WsrNi6zCKpwBhuApq127wHs= +github.com/smartcontractkit/grpc-proxy v0.0.0-20240830132753-a7e17fec5ab7/go.mod h1:FX7/bVdoep147QQhsOPkYsPEXhGZjeYx6lBSaSXtZOA= +github.com/smartcontractkit/libocr v0.0.0-20251212213002-0a5e2f907dda h1:OjM+79FRuVZlj0Qd4y+q8Xmz/tEn5y8npqmiQiMMj+w= +github.com/smartcontractkit/libocr v0.0.0-20251212213002-0a5e2f907dda/go.mod h1:oJkBKVn8zoBQm7Feah9CiuEHyCqAhnp1LJBzrvloQtM= +github.com/smartcontractkit/smdkg v0.0.0-20251029093710-c38905e58aeb h1:kLHdQQkijaPGsBbtV2rJgpzVpQ96e7T10pzjNlWfK8U= +github.com/smartcontractkit/smdkg v0.0.0-20251029093710-c38905e58aeb/go.mod h1:4s5hj/nlMF9WV+T5Uhy4n9IYpRpzfJzT+vTKkNT7T+Y= +github.com/smartcontractkit/tdh2/go/ocr2/decryptionplugin v0.0.0-20241009055228-33d0c0bf38de h1:n0w0rKF+SVM+S3WNlup6uabXj2zFlFNfrlsKCMMb/co= +github.com/smartcontractkit/tdh2/go/ocr2/decryptionplugin v0.0.0-20241009055228-33d0c0bf38de/go.mod h1:Sl2MF/Fp3fgJIVzhdGhmZZX2BlnM0oUUyBP4s4xYb6o= +github.com/smartcontractkit/tdh2/go/tdh2 v0.0.0-20251120172354-e8ec0386b06c h1:S1AFIjfHT95ev6gqHKBGy1zj3Tz0fIN3XzkaDUn77wY= +github.com/smartcontractkit/tdh2/go/tdh2 v0.0.0-20251120172354-e8ec0386b06c/go.mod h1:NSc7hgOQbXG3DAwkOdWnZzLTZENXSwDJ7Va1nBp0YU0= +github.com/smartcontractkit/wsrpc v0.8.5-0.20250502134807-c57d3d995945 h1:zxcODLrFytOKmAd8ty8S/XK6WcIEJEgRBaL7sY/7l4Y= +github.com/smartcontractkit/wsrpc v0.8.5-0.20250502134807-c57d3d995945/go.mod h1:m3pdp17i4bD50XgktkzWetcV5yaLsi7Gunbv4ZgN6qg= +github.com/sourcegraph/conc v0.3.1-0.20240121214520-5f936abd7ae8 h1:+jumHNA0Wrelhe64i8F6HNlS8pkoyMv5sreGx2Ry5Rw= +github.com/sourcegraph/conc v0.3.1-0.20240121214520-5f936abd7ae8/go.mod h1:3n1Cwaq1E1/1lhQhtRK2ts/ZwZEhjcQeJQ1RuC6Q/8U= +github.com/spf13/afero v1.15.0 h1:b/YBCLWAJdFWJTN9cLhiXXcD7mzKn9Dm86dNnfyQw1I= +github.com/spf13/afero v1.15.0/go.mod h1:NC2ByUVxtQs4b3sIUphxK0NioZnmxgyCrfzeuq8lxMg= +github.com/spf13/cast v1.10.0 h1:h2x0u2shc1QuLHfxi+cTJvs30+ZAHOGRic8uyGTDWxY= +github.com/spf13/cast v1.10.0/go.mod h1:jNfB8QC9IA6ZuY2ZjDp0KtFO2LZZlg4S/7bzP6qqeHo= +github.com/spf13/cobra v1.10.1 h1:lJeBwCfmrnXthfAupyUTzJ/J4Nc1RsHC/mSRU2dll/s= +github.com/spf13/cobra v1.10.1/go.mod h1:7SmJGaTHFVBY0jW4NXGluQoLvhqFQM+6XSKD+P4XaB0= +github.com/spf13/pflag v1.0.9/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/spf13/pflag v1.0.10 h1:4EBh2KAYBwaONj6b2Ye1GiHfwjqyROoF4RwYO+vPwFk= +github.com/spf13/pflag v1.0.10/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/spf13/viper v1.21.0 h1:x5S+0EU27Lbphp4UKm1C+1oQO+rKx36vfCoaVebLFSU= +github.com/spf13/viper v1.21.0/go.mod h1:P0lhsswPGWD/1lZJ9ny3fYnVqxiegrlNrEmgLjbTCAY= +github.com/stephenlacy/go-ethereum-hdwallet v0.0.0-20230913225845-a4fa94429863 h1:ba4VRWSkRzgdP5hB5OxexIzBXZbSwgcw8bEu06ivGQI= +github.com/stephenlacy/go-ethereum-hdwallet v0.0.0-20230913225845-a4fa94429863/go.mod h1:oPTjPNrRucLv9mU27iNPj6n0CWWcNFhoXFOLVGJwHCA= +github.com/streamingfast/logging v0.0.0-20230608130331-f22c91403091 h1:RN5mrigyirb8anBEtdjtHFIufXdacyTi6i4KBfeNXeo= +github.com/streamingfast/logging v0.0.0-20230608130331-f22c91403091/go.mod h1:VlduQ80JcGJSargkRU4Sg9Xo63wZD/l8A5NC/Uo1/uU= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= @@ -335,22 +1000,76 @@ github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXf github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= +github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= 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.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= 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/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8= +github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU= github.com/supranational/blst v0.3.16-0.20250831170142-f48500c1fdbe h1:nbdqkIGOGfUAD54q1s2YBcBz/WcsxCO9HUQ4aGV5hUw= github.com/supranational/blst v0.3.16-0.20250831170142-f48500c1fdbe/go.mod h1:jZJtfjgudtNl4en1tzwPIV3KjUnQUvG3/j+w+fVonLw= +github.com/syndtr/goleveldb v1.0.1-0.20220721030215-126854af5e6d h1:vfofYNRScrDdvS342BElfbETmL1Aiz3i2t0zfRj16Hs= +github.com/syndtr/goleveldb v1.0.1-0.20220721030215-126854af5e6d/go.mod h1:RRCYJbIwD5jmqPI9XoAFR0OcDxqUctll6zUj/+B4S48= +github.com/tendermint/go-amino v0.16.0 h1:GyhmgQKvqF82e2oZeuMSp9JTN0N09emoSZlb2lyGa2E= +github.com/tendermint/go-amino v0.16.0/go.mod h1:TQU0M1i/ImAo+tYpZi73AU3V/dKeCoMC9Sphe2ZwGME= +github.com/test-go/testify v1.1.4 h1:Tf9lntrKUMHiXQ07qBScBTSA0dhYQlu83hswqelv1iE= +github.com/test-go/testify v1.1.4/go.mod h1:rH7cfJo/47vWGdi4GPj16x3/t1xGOj2YxzmNQzk2ghU= +github.com/theodesp/go-heaps v0.0.0-20190520121037-88e35354fe0a h1:YuO+afVc3eqrjiCUizNCxI53bl/BnPiVwXqLzqYTqgU= +github.com/theodesp/go-heaps v0.0.0-20190520121037-88e35354fe0a/go.mod h1:/sfW47zCZp9FrtGcWyo1VjbgDaodxX9ovZvgLb/MxaA= +github.com/tidwall/btree v1.7.0 h1:L1fkJH/AuEh5zBnnBbmTwQ5Lt+bRJ5A8EWecslvo9iI= +github.com/tidwall/btree v1.7.0/go.mod h1:twD9XRA5jj9VUQGELzDO4HPQTNJsoWWfYEL+EUQ2cKY= +github.com/tidwall/gjson v1.18.0 h1:FIDeeyB800efLX89e5a8Y0BNH+LOngJyGrIWxG2FKQY= +github.com/tidwall/gjson v1.18.0/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= +github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA= +github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM= +github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU= +github.com/tidwall/pretty v1.2.1 h1:qjsOFOWWQl+N3RsoF5/ssm1pHmJJwhjlSbZ51I6wMl4= +github.com/tidwall/pretty v1.2.1/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU= +github.com/tklauser/go-sysconf v0.3.12/go.mod h1:Ho14jnntGE1fpdOqQEEaiKRpvIavV0hSfmBq8nJbHYI= github.com/tklauser/go-sysconf v0.3.15 h1:VE89k0criAymJ/Os65CSn1IXaol+1wrsFHEB8Ol49K4= github.com/tklauser/go-sysconf v0.3.15/go.mod h1:Dmjwr6tYFIseJw7a3dRLJfsHAMXZ3nEnL/aZY+0IuI4= +github.com/tklauser/numcpus v0.6.1/go.mod h1:1XfjsgE2zo8GVw7POkMbHENHzVg3GzmoZ9fESEdAacY= github.com/tklauser/numcpus v0.10.0 h1:18njr6LDBk1zuna922MgdjQuJFjrdppsZG60sHGfjso= github.com/tklauser/numcpus v0.10.0/go.mod h1:BiTKazU708GQTYF4mB+cmlpT2Is1gLk7XVuEeem8LsQ= +github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM= +github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI= +github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08= +github.com/tyler-smith/go-bip39 v1.1.0 h1:5eUemwrMargf3BSLRRCalXT93Ns6pQJIjYQN2nyfOP8= +github.com/tyler-smith/go-bip39 v1.1.0/go.mod h1:gUYDtqQw1JS3ZJ8UWVcGTGqqr6YIN3CWg+kkNaLt55U= +github.com/ugorji/go/codec v1.2.12 h1:9LC83zGrHhuUA9l16C9AHXAqEV/2wBQ4nkvumAE65EE= +github.com/ugorji/go/codec v1.2.12/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= +github.com/ulule/limiter/v3 v3.11.2 h1:P4yOrxoEMJbOTfRJR2OzjL90oflzYPPmWg+dvwN2tHA= +github.com/ulule/limiter/v3 v3.11.2/go.mod h1:QG5GnFOCV+k7lrL5Y8kgEeeflPH3+Cviqlqa8SVSQxI= +github.com/unrolled/secure v1.13.0 h1:sdr3Phw2+f8Px8HE5sd1EHdj1aV3yUwed/uZXChLFsk= +github.com/unrolled/secure v1.13.0/go.mod h1:BmF5hyM6tXczk3MpQkFf1hpKSRqCyhqcbiQtiAF7+40= +github.com/urfave/cli v1.22.14 h1:ebbhrRiGK2i4naQJr+1Xj92HXZCrK7MsyTS/ob3HnAk= +github.com/urfave/cli v1.22.14/go.mod h1:X0eDS6pD6Exaclxm99NJ3FiCDRED7vIHpx2mDOHLvkA= +github.com/urfave/cli/v2 v2.27.6 h1:VdRdS98FNhKZ8/Az8B7MTyGQmpIr36O1EHybx/LaZ4g= +github.com/urfave/cli/v2 v2.27.6/go.mod h1:3Sevf16NykTbInEnD0yKkjDAeZDS0A6bzhBH5hrMvTQ= github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= github.com/wk8/go-ordered-map/v2 v2.1.8 h1:5h/BUHu93oj4gIdvHHHGsScSTMijfx5PeYkE/fJgbpc= github.com/wk8/go-ordered-map/v2 v2.1.8/go.mod h1:5nJHM5DyteebpVlHnWMV0rPz6Zp7+xBAnxjb1X5vnTw= +github.com/wlynxg/anet v0.0.3/go.mod h1:eay5PRQr7fIVAMbTbchTnO9gG65Hg/uYGdc7mguHxoA= +github.com/wlynxg/anet v0.0.5 h1:J3VJGi1gvo0JwZ/P1/Yc/8p63SoW98B5dHkYDmpgvvU= +github.com/wlynxg/anet v0.0.5/go.mod h1:eay5PRQr7fIVAMbTbchTnO9gG65Hg/uYGdc7mguHxoA= +github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM= +github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg= +github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1 h1:gEOO8jv9F4OT7lGCjxCBTO/36wtF6j2nSip77qHd4x4= +github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1/go.mod h1:Ohn+xnUBiLI6FVj/9LpzZWtj1/D6lUovWYBkxHVV3aM= +github.com/xssnick/tonutils-go v1.14.1 h1:zV/iVYl/h3hArS+tPsd9XrSFfGert3r21caMltPSeHg= +github.com/xssnick/tonutils-go v1.14.1/go.mod h1:68xwWjpoGGqiTbLJ0gT63sKu1Z1moCnDLLzA+DKanIg= +github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= github.com/yusufpapurcu/wmi v1.2.4 h1:zFUKzehAFReQwLys1b/iSMl+JQGSCSjtVqQn9bBrPo0= github.com/yusufpapurcu/wmi v1.2.4/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0= @@ -359,24 +1078,47 @@ github.com/zeebo/assert v1.3.0/go.mod h1:Pq9JiuJQpG8JLJdtkwrJESF0Foym2/D9XMU5ciN github.com/zeebo/xxh3 v1.0.2 h1:xZmwmqxHZA8AI603jOQ0tMqmBr9lPeFwGg6d+xy9DC0= github.com/zeebo/xxh3 v1.0.2/go.mod h1:5NWz9Sef7zIDm2JHfFlcQvNekmcEl9ekUZQQKCYaDcA= github.com/zenazn/goji v0.9.0/go.mod h1:7S9M489iMyHBNxwZnk9/EHS098H4/F6TATF2mIxtB1Q= -go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA= -go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A= +github.com/zksync-sdk/zksync2-go v1.1.1-0.20250620124214-2c742ee399c6 h1:VRdX3Gn/I7ITbzUY4ZNfgn65tdQM9Zhf2b7KP0HZllk= +github.com/zksync-sdk/zksync2-go v1.1.1-0.20250620124214-2c742ee399c6/go.mod h1:NWNlQS21isOsSsn+hLRAPpiuv+3P+LcdaZNuRt2T5Yo= +github.com/zondax/golem v0.27.0 h1:IbBjGIXF3SoGOZHsILJvIM/F/ylwJzMcHAcggiqniPw= +github.com/zondax/golem v0.27.0/go.mod h1:AmorCgJPt00L8xN1VrMBe13PSifoZksnQ1Ge906bu4A= +github.com/zondax/hid v0.9.2 h1:WCJFnEDMiqGF64nlZz28E9qLVZ0KSJ7xpc5DLEyma2U= +github.com/zondax/hid v0.9.2/go.mod h1:l5wttcP0jwtdLjqjMMWFVEE7d1zO0jvSPA9OPZxWpEM= +github.com/zondax/ledger-go v1.0.1 h1:Ks/2tz/dOF+dbRynfZ0dEhcdL1lqw43Sa0zMXHpQ3aQ= +github.com/zondax/ledger-go v1.0.1/go.mod h1:j7IgMY39f30apthJYMd1YsHZRqdyu4KbVmUp0nU78X0= +go.dedis.ch/fixbuf v1.0.3 h1:hGcV9Cd/znUxlusJ64eAlExS+5cJDIyTyEG+otu5wQs= +go.dedis.ch/fixbuf v1.0.3/go.mod h1:yzJMt34Wa5xD37V5RTdmp38cz3QhMagdGoem9anUalw= +go.dedis.ch/kyber/v3 v3.0.4/go.mod h1:OzvaEnPvKlyrWyp3kGXlFdp7ap1VC6RkZDTaPikqhsQ= +go.dedis.ch/kyber/v3 v3.0.9/go.mod h1:rhNjUUg6ahf8HEg5HUvVBYoWY4boAafX8tYxX+PS+qg= +go.dedis.ch/kyber/v3 v3.1.0 h1:ghu+kiRgM5JyD9TJ0hTIxTLQlJBR/ehjWvWwYW3XsC0= +go.dedis.ch/kyber/v3 v3.1.0/go.mod h1:kXy7p3STAurkADD+/aZcsznZGKVHEqbtmdIzvPfrs1U= +go.dedis.ch/protobuf v1.0.5/go.mod h1:eIV4wicvi6JK0q/QnfIEGeSFNG0ZeB24kzut5+HaRLo= +go.dedis.ch/protobuf v1.0.7/go.mod h1:pv5ysfkDX/EawiPqcW3ikOxsL5t+BqnV6xHSmE79KI4= +go.dedis.ch/protobuf v1.0.11/go.mod h1:97QR256dnkimeNdfmURz0wAMNVbd1VmLXhG1CrTYrJ4= +go.etcd.io/bbolt v1.4.2 h1:IrUHp260R8c+zYx/Tm8QZr04CX+qWS5PGfPdevhdm1I= +go.etcd.io/bbolt v1.4.2/go.mod h1:Is8rSHO/b4f3XigBC0lL0+4FwAQv3HXEEIgFMuKHceM= +go.mongodb.org/mongo-driver v1.17.2 h1:gvZyk8352qSfzyZ2UMWcpDpMSGEr1eqE4T793SqyhzM= +go.mongodb.org/mongo-driver v1.17.2/go.mod h1:Hy04i7O2kC4RS06ZrhPRqj/u4DTYkFDAAccj+rVKqgQ= +go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64= +go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y= +go.opentelemetry.io/contrib/instrumentation/github.com/gin-gonic/gin/otelgin v0.49.0 h1:1f31+6grJmV3X4lxcEvUy13i5/kfDw1nJZwhd8mA4tg= +go.opentelemetry.io/contrib/instrumentation/github.com/gin-gonic/gin/otelgin v0.49.0/go.mod h1:1P/02zM3OwkX9uki+Wmxw3a5GVb6KUXRsa7m7bOC9Fg= go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.63.0 h1:YH4g8lQroajqUwWbq/tr2QX1JFmEXaDLgG+ew9bLMWo= go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.63.0/go.mod h1:fvPi2qXDqFs8M4B4fmJhE92TyQs9Ydjlg3RvfUp+NbQ= -go.opentelemetry.io/otel v1.38.0 h1:RkfdswUDRimDg0m2Az18RKOsnI8UDzppJAtj01/Ymk8= -go.opentelemetry.io/otel v1.38.0/go.mod h1:zcmtmQ1+YmQM9wrNsTGV/q/uyusom3P8RxwExxkZhjM= -go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.12.2 h1:06ZeJRe5BnYXceSM9Vya83XXVaNGe3H1QqsvqRANQq8= -go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.12.2/go.mod h1:DvPtKE63knkDVP88qpatBj81JxN+w1bqfVbsbCbj1WY= -go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp v0.12.2 h1:tPLwQlXbJ8NSOfZc4OkgU5h2A38M4c9kfHSVc4PFQGs= -go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp v0.12.2/go.mod h1:QTnxBwT/1rBIgAG1goq6xMydfYOBKU6KTiYF4fp5zL8= -go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.36.0 h1:zwdo1gS2eH26Rg+CoqVQpEK1h8gvt5qyU5Kk5Bixvow= -go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.36.0/go.mod h1:rUKCPscaRWWcqGT6HnEmYrK+YNe5+Sw64xgQTOJ5b30= +go.opentelemetry.io/otel v1.39.0 h1:8yPrr/S0ND9QEfTfdP9V+SiwT4E0G7Y5MO7p85nis48= +go.opentelemetry.io/otel v1.39.0/go.mod h1:kLlFTywNWrFyEdH0oj2xK0bFYZtHRYUdv1NklR/tgc8= +go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.13.0 h1:z6lNIajgEBVtQZHjfw2hAccPEBDs+nx58VemmXWa2ec= +go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.13.0/go.mod h1:+kyc3bRx/Qkq05P6OCu3mTEIOxYRYzoIg+JsUp5X+PM= +go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp v0.13.0 h1:zUfYw8cscHHLwaY8Xz3fiJu+R59xBnkgq2Zr1lwmK/0= +go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp v0.13.0/go.mod h1:514JLMCcFLQFS8cnTepOk6I09cKWJ5nGHBxHrMJ8Yfg= +go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.37.0 h1:zG8GlgXCJQd5BU98C0hZnBbElszTmUgCNCfYneaDL0A= +go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.37.0/go.mod h1:hOfBCz8kv/wuq73Mx2H2QnWokh/kHZxkh6SNF2bdKtw= go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.36.0 h1:gAU726w9J8fwr4qRDqu1GYMNNs4gXrU+Pv20/N1UpB4= go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.36.0/go.mod h1:RboSDkp7N292rgu+T0MgVt2qgFGu6qa1RpZDOtpL76w= -go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.36.0 h1:dNzwXjZKpMpE2JhmO+9HsPl42NIXFIFSUSSs0fiqra0= -go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.36.0/go.mod h1:90PoxvaEB5n6AOdZvi+yWJQoE95U8Dhhw2bSyRqnTD0= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.36.0 h1:JgtbA0xkWHnTmYk7YusopJFX6uleBmAuZ8n05NEh8nQ= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.36.0/go.mod h1:179AK5aar5R3eS9FucPy6rggvU0g52cvKId8pv4+v0c= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.37.0 h1:Ahq7pZmv87yiyn3jeFz/LekZmPLLdKejuO3NcK9MssM= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.37.0/go.mod h1:MJTqhM0im3mRLw1i8uGHnCvUEeS7VwRyxlLC78PA18M= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.37.0 h1:EtFWSnwW9hGObjkIdmlnWSydO+Qs8OwzfzXLUPg4xOc= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.37.0/go.mod h1:QjUEoiGCPkvFZ/MjK6ZZfNOS6mfVEVKYE99dFhuN2LI= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.36.0 h1:nRVXXvf78e00EwY6Wp0YII8ww2JVWshZ20HfTlE11AM= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.36.0/go.mod h1:r49hO7CgrxY9Voaj3Xe8pANWtr0Oq916d0XAmOoCZAQ= go.opentelemetry.io/otel/exporters/stdout/stdoutlog v0.13.0 h1:yEX3aC9KDgvYPhuKECHbOlr5GLwH6KTjLJ1sBSkkxkc= @@ -385,106 +1127,203 @@ go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.36.0 h1:rixTyDGXFxRy1x go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.36.0/go.mod h1:dowW6UsM9MKbJq5JTz2AMVp3/5iW5I/TStsk8S+CfHw= go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.36.0 h1:G8Xec/SgZQricwWBJF/mHZc7A02YHedfFDENwJEdRA0= go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.36.0/go.mod h1:PD57idA/AiFD5aqoxGxCvT/ILJPeHy3MjqU/NS7KogY= -go.opentelemetry.io/otel/log v0.13.0 h1:yoxRoIZcohB6Xf0lNv9QIyCzQvrtGZklVbdCoyb7dls= -go.opentelemetry.io/otel/log v0.13.0/go.mod h1:INKfG4k1O9CL25BaM1qLe0zIedOpvlS5Z7XgSbmN83E= -go.opentelemetry.io/otel/metric v1.38.0 h1:Kl6lzIYGAh5M159u9NgiRkmoMKjvbsKtYRwgfrA6WpA= -go.opentelemetry.io/otel/metric v1.38.0/go.mod h1:kB5n/QoRM8YwmUahxvI3bO34eVtQf2i4utNVLr9gEmI= -go.opentelemetry.io/otel/sdk v1.38.0 h1:l48sr5YbNf2hpCUj/FoGhW9yDkl+Ma+LrVl8qaM5b+E= -go.opentelemetry.io/otel/sdk v1.38.0/go.mod h1:ghmNdGlVemJI3+ZB5iDEuk4bWA3GkTpW+DOoZMYBVVg= -go.opentelemetry.io/otel/sdk/log v0.13.0 h1:I3CGUszjM926OphK8ZdzF+kLqFvfRY/IIoFq/TjwfaQ= -go.opentelemetry.io/otel/sdk/log v0.13.0/go.mod h1:lOrQyCCXmpZdN7NchXb6DOZZa1N5G1R2tm5GMMTpDBw= +go.opentelemetry.io/otel/log v0.15.0 h1:0VqVnc3MgyYd7QqNVIldC3dsLFKgazR6P3P3+ypkyDY= +go.opentelemetry.io/otel/log v0.15.0/go.mod h1:9c/G1zbyZfgu1HmQD7Qj84QMmwTp2QCQsZH1aeoWDE4= +go.opentelemetry.io/otel/metric v1.39.0 h1:d1UzonvEZriVfpNKEVmHXbdf909uGTOQjA0HF0Ls5Q0= +go.opentelemetry.io/otel/metric v1.39.0/go.mod h1:jrZSWL33sD7bBxg1xjrqyDjnuzTUB0x1nBERXd7Ftcs= +go.opentelemetry.io/otel/sdk v1.39.0 h1:nMLYcjVsvdui1B/4FRkwjzoRVsMK8uL/cj0OyhKzt18= +go.opentelemetry.io/otel/sdk v1.39.0/go.mod h1:vDojkC4/jsTJsE+kh+LXYQlbL8CgrEcwmt1ENZszdJE= +go.opentelemetry.io/otel/sdk/log v0.15.0 h1:WgMEHOUt5gjJE93yqfqJOkRflApNif84kxoHWS9VVHE= +go.opentelemetry.io/otel/sdk/log v0.15.0/go.mod h1:qDC/FlKQCXfH5hokGsNg9aUBGMJQsrUyeOiW5u+dKBQ= go.opentelemetry.io/otel/sdk/log/logtest v0.13.0 h1:9yio6AFZ3QD9j9oqshV1Ibm9gPLlHNxurno5BreMtIA= go.opentelemetry.io/otel/sdk/log/logtest v0.13.0/go.mod h1:QOGiAJHl+fob8Nu85ifXfuQYmJTFAvcrxL6w5/tu168= -go.opentelemetry.io/otel/sdk/metric v1.38.0 h1:aSH66iL0aZqo//xXzQLYozmWrXxyFkBJ6qT5wthqPoM= -go.opentelemetry.io/otel/sdk/metric v1.38.0/go.mod h1:dg9PBnW9XdQ1Hd6ZnRz689CbtrUp0wMMs9iPcgT9EZA= -go.opentelemetry.io/otel/trace v1.38.0 h1:Fxk5bKrDZJUH+AMyyIXGcFAPah0oRcT+LuNtJrmcNLE= -go.opentelemetry.io/otel/trace v1.38.0/go.mod h1:j1P9ivuFsTceSWe1oY+EeW3sc+Pp42sO++GHkg4wwhs= -go.opentelemetry.io/proto/otlp v1.6.0 h1:jQjP+AQyTf+Fe7OKj/MfkDrmK4MNVtw2NpXsf9fefDI= -go.opentelemetry.io/proto/otlp v1.6.0/go.mod h1:cicgGehlFuNdgZkcALOCh3VE6K/u2tAjzlRhDwmVpZc= +go.opentelemetry.io/otel/sdk/metric v1.39.0 h1:cXMVVFVgsIf2YL6QkRF4Urbr/aMInf+2WKg+sEJTtB8= +go.opentelemetry.io/otel/sdk/metric v1.39.0/go.mod h1:xq9HEVH7qeX69/JnwEfp6fVq5wosJsY1mt4lLfYdVew= +go.opentelemetry.io/otel/trace v1.39.0 h1:2d2vfpEDmCJ5zVYz7ijaJdOF59xLomrvj7bjt6/qCJI= +go.opentelemetry.io/otel/trace v1.39.0/go.mod h1:88w4/PnZSazkGzz/w84VHpQafiU4EtqqlVdxWy+rNOA= +go.opentelemetry.io/proto/otlp v1.7.0 h1:jX1VolD6nHuFzOYso2E73H85i92Mv8JQYk0K9vz09os= +go.opentelemetry.io/proto/otlp v1.7.0/go.mod h1:fSKjH6YJ7HDlwzltzyMj036AJ3ejJLCgCSHGj4efDDo= go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= +go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= +go.uber.org/goleak v1.1.11/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= +go.uber.org/mock v0.6.0 h1:hyF9dfmbgIX5EfOdasqLsWD6xqpNZlXblLB/Dbnwv3Y= +go.uber.org/mock v0.6.0/go.mod h1:KiVJ4BqZJaMj4svdfmHM0AUx4NJYO8ZNpPnZn1Z+BBU= go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4= go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU= +go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= +go.uber.org/ratelimit v0.3.1 h1:K4qVE+byfv/B3tC+4nYWP7v/6SimcO7HzHekoMNBma0= +go.uber.org/ratelimit v0.3.1/go.mod h1:6euWsTB6U/Nb3X++xEUXA8ciPJvr19Q/0h1+oDcJhRk= go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA= go.uber.org/zap v1.9.1/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM= -go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8= -go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= +go.uber.org/zap v1.21.0/go.mod h1:wjWOCqI0f2ZZrJF/UufIOkiC8ii6tm1iqIsLo76RfJw= +go.uber.org/zap v1.27.1 h1:08RqriUEv8+ArZRYSTXy1LeBScaMpVSTBhCeaZYfMYc= +go.uber.org/zap v1.27.1/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= +go.yaml.in/yaml/v2 v2.4.2 h1:DzmwEr2rDGHl7lsFgAHxmNz/1NlQ7xLIrlN2h5d1eGI= +go.yaml.in/yaml/v2 v2.4.2/go.mod h1:081UH+NErpNdqlCXm3TtEran0rJZGxAYx9hb/ELlsPU= +go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc= +go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg= +golang.org/x/arch v0.17.0 h1:4O3dfLzd+lQewptAHqjewQZQDyEdejz3VwgeYwkZneU= +golang.org/x/arch v0.17.0/go.mod h1:bdwinDaKcfZUGpH09BB7ZmOfhalA8lQdzl62l8gGWsk= +golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190123085648-057139ce5d2b/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190411191339-88737f569e3a/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE= golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20200728195943-123391ffb6de/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20201203163018-be400aefbc4c/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.0.0-20220214200702-86341886e292/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/crypto v0.8.0/go.mod h1:mRqEX+O9/h5TFCrQhkgjo2yKi0yYA+9ecGkdQoHrywE= +golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98yw= +golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg= golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU= golang.org/x/crypto v0.20.0/go.mod h1:Xwo95rrVNIoSMx9wa1JroENMToLWn3RNVrTBpLHgZPQ= golang.org/x/crypto v0.47.0 h1:V6e3FRj+n4dbpw86FJ8Fv7XVOql7TEwpHapKoMJ/GO8= golang.org/x/crypto v0.47.0/go.mod h1:ff3Y9VzzKbwSSEzWqJsJVBnWmRwRSHt/6Op5n9bQc4A= -golang.org/x/exp v0.0.0-20250711185948-6ae5c78190dc h1:TS73t7x3KarrNd5qAipmspBDS1rkMcgVG/fS1aRb4Rc= -golang.org/x/exp v0.0.0-20250711185948-6ae5c78190dc/go.mod h1:A+z0yzpGtvnG90cToK5n2tu8UJVP2XUATh+r+sfOOOc= +golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20260112195511-716be5621a96 h1:Z/6YuSHTLOHfNFdb8zVZomZr7cqNgTJvA8+Qz75D8gU= +golang.org/x/exp v0.0.0-20260112195511-716be5621a96/go.mod h1:nzimsREAkjBCIEFtHiYkrJyT+2uy9YZJB7H1k68CXZU= +golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= +golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= 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= +golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= -golang.org/x/mod v0.31.0 h1:HaW9xtz0+kOcWKwli0ZXy79Ix+UW/vOfmWI5QVd2tgI= -golang.org/x/mod v0.31.0/go.mod h1:43JraMp9cGx1Rx3AqioxrbrhNsLl2l/iNAvuBkrezpg= +golang.org/x/mod v0.32.0 h1:9F4d3PHLljb6x//jOyokMv3eX+YDeepZSEo3mFJy93c= +golang.org/x/mod v0.32.0/go.mod h1:SgipZ/3h2Ci89DlEtEXWUk/HteuRin+HHhN+WbNhguU= +golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= +golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk= +golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/net v0.0.0-20220607020251-c690dde0001d/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= +golang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns= golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= +golang.org/x/net v0.14.0/go.mod h1:PpSgVXXLK0OxS0F31C1/tv6XNguvCrnXIDrFMspZIUI= +golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY= golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44= -golang.org/x/net v0.48.0 h1:zyQRTTrjc33Lhh0fBgT/H3oZq9WuvRR5gPC70xpDiQU= -golang.org/x/net v0.48.0/go.mod h1:+ndRgGjkh8FGtu1w1FGbEC31if4VrNVMuKTgcAAnQRY= +golang.org/x/net v0.49.0 h1:eeHFmOGUTtaaPSGNmjBKpbng9MulQsJURQUAfUwY++o= +golang.org/x/net v0.49.0/go.mod h1:/ysNB2EvaqvesRkuLAyjI1ycPZlQHM3q01F02UY/MV8= +golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.32.0 h1:jsCblLleRMDrxMN29H3z/k1KliIvpLgCkE6R8FXXNgY= +golang.org/x/oauth2 v0.32.0/go.mod h1:lzm5WQJQwKZ3nwavOZ3IS5Aulzxi68dUSgRHujetwEA= +golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4= golang.org/x/sync v0.19.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= +golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190124100055-b90733256f2e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201204225414-ed752295db88/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.40.0 h1:DBZZqJ2Rkml6QMQsZywtnjnnGvHza6BTfYFWY9kjEWQ= golang.org/x/sys v0.40.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= -golang.org/x/telemetry v0.0.0-20251203150158-8fff8a5912fc h1:bH6xUXay0AIFMElXG2rQ4uiE+7ncwtiOdPfYK1NK2XA= -golang.org/x/telemetry v0.0.0-20251203150158-8fff8a5912fc/go.mod h1:hKdjCMrbv9skySur+Nek8Hd0uJ0GuxJIoIX2payrIdQ= +golang.org/x/telemetry v0.0.0-20260109210033-bd525da824e2 h1:O1cMQHRfwNpDfDJerqRoE2oD+AFlyid87D40L/OkkJo= +golang.org/x/telemetry v0.0.0-20260109210033-bd525da824e2/go.mod h1:b7fPSJ0pKZ3ccUh8gnTONJxhn3c/PS6tyzQvyqw4iA8= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= +golang.org/x/term v0.7.0/go.mod h1:P32HKFT3hSsZrRxla30E9HqToFYAQPCMs/zFMBUFqPY= golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= +golang.org/x/term v0.11.0/go.mod h1:zC9APTIj3jG3FdV/Ons+XE1riIZXG4aZ4GTHiPZJPIU= +golang.org/x/term v0.16.0/go.mod h1:yn7UURbUtPyrVJPGPq404EukNFxcm/foM+bV/bfcDsY= golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk= +golang.org/x/term v0.39.0 h1:RclSuaJf32jOqZz74CkPA9qFuVTX7vhLlpfj/IGWlqY= +golang.org/x/term v0.39.0/go.mod h1:yxzUCTP/U+FzoxfdKmLaA0RV1WgE0VY7hXBwKtY/4ww= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= @@ -493,51 +1332,109 @@ golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/text v0.12.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/text v0.33.0 h1:B3njUFyqtHDUI5jMn1YIr5B0IE2U0qck04r6d4KPAxE= golang.org/x/text v0.33.0/go.mod h1:LuMebE6+rBincTi9+xWTY8TztLzKHc/9C1uBCG27+q8= -golang.org/x/time v0.12.0 h1:ScB/8o8olJvc+CQPWrK3fPZNfh7qgwCrY0zJmoEQLSE= -golang.org/x/time v0.12.0/go.mod h1:CDIdPxbZBQxdj6cxyCIdrNogrJKMJ7pr37NYpMcMDSg= +golang.org/x/time v0.14.0 h1:MRx4UaLrDotUKUdCIqzPC48t1Y9hANFKIRpNx+Te8PI= +golang.org/x/time v0.14.0/go.mod h1:eL/Oa2bBBK0TkX57Fyni+NgnyQQN4LitPmob2Hjnqw4= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190425163242-31fd60d6bfdc/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190823170909-c4a336ef6a2f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20200103221440-774c71fcf114/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= -golang.org/x/tools v0.40.0 h1:yLkxfA+Qnul4cs9QA3KnlFu0lVmd8JJfoq+E41uSutA= -golang.org/x/tools v0.40.0/go.mod h1:Ik/tzLRlbscWpqqMRjyWYDisX8bG13FrdXp3o4Sr9lc= +golang.org/x/tools v0.41.0 h1:a9b8iMweWG+S0OBnlU36rzLp20z1Rp10w+IY2czHTQc= +golang.org/x/tools v0.41.0/go.mod h1:XSY6eDqxVNiYgezAVqqCeihT4j1U2CCsqvH3WhQpnlg= golang.org/x/xerrors v0.0.0-20190410155217-1f06c39b4373/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20190513163551-3ee3066db522/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20220517211312-f3a8303e98df/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= golang.org/x/xerrors v0.0.0-20240903120638-7835f813f4da h1:noIWHXmPHxILtqtCOPIhSt0ABwskkZKjD3bXGnZGpNY= golang.org/x/xerrors v0.0.0-20240903120638-7835f813f4da/go.mod h1:NDW/Ps6MPRej6fsCIbMTohpP40sJ/P/vI1MoTEGwX90= -gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk= -gonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E= -google.golang.org/genproto/googleapis/api v0.0.0-20250707201910-8d1bb00bc6a7 h1:FiusG7LWj+4byqhbvmB+Q93B/mOxJLN2DTozDuZm4EU= -google.golang.org/genproto/googleapis/api v0.0.0-20250707201910-8d1bb00bc6a7/go.mod h1:kXqgZtrWaf6qS3jZOCnCH7WYfrvFjkC51bM8fz3RsCA= -google.golang.org/genproto/googleapis/rpc v0.0.0-20250825161204-c5933d9347a5 h1:eaY8u2EuxbRv7c3NiGK0/NedzVsCcV6hDuU5qPX5EGE= -google.golang.org/genproto/googleapis/rpc v0.0.0-20250825161204-c5933d9347a5/go.mod h1:M4/wBTSeyLxupu3W3tJtOgB14jILAS/XWPSSa3TAlJc= -google.golang.org/grpc v1.75.0 h1:+TW+dqTd2Biwe6KKfhE5JpiYIBWq865PhKGSXiivqt4= -google.golang.org/grpc v1.75.0/go.mod h1:JtPAzKiq4v1xcAB2hydNlWI2RnF85XXcV0mhKXr2ecQ= -google.golang.org/protobuf v1.36.9 h1:w2gp2mA27hUeUzj9Ex9FBjsBm40zfaDtEWow293U7Iw= -google.golang.org/protobuf v1.36.9/go.mod h1:fuxRtAxBytpl4zzqUh6/eyUujkJdNiuEkXntxiD/uRU= +gonum.org/v1/gonum v0.17.0 h1:VbpOemQlsSMrYmn7T2OUvQ4dqxQXU+ouZFQsZOx50z4= +gonum.org/v1/gonum v0.17.0/go.mod h1:El3tOrEuMpv2UdMrbNlKEh9vd86bmQ6vqIcDwxEOc1E= +google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= +google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20180831171423-11092d34479b/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20250603155806-513f23925822 h1:rHWScKit0gvAPuOnu87KpaYtjK5zBMLcULh7gxkCXu4= +google.golang.org/genproto v0.0.0-20250603155806-513f23925822/go.mod h1:HubltRL7rMh0LfnQPkMH4NPDFEWp0jw3vixw7jEM53s= +google.golang.org/genproto/googleapis/api v0.0.0-20251029180050-ab9386a59fda h1:+2XxjfsAu6vqFxwGBRcHiMaDCuZiqXGDUDVWVtrFAnE= +google.golang.org/genproto/googleapis/api v0.0.0-20251029180050-ab9386a59fda/go.mod h1:fDMmzKV90WSg1NbozdqrE64fkuTv6mlq2zxo9ad+3yo= +google.golang.org/genproto/googleapis/rpc v0.0.0-20251029180050-ab9386a59fda h1:i/Q+bfisr7gq6feoJnS/DlpdwEL4ihp41fvRiM3Ork0= +google.golang.org/genproto/googleapis/rpc v0.0.0-20251029180050-ab9386a59fda/go.mod h1:7i2o+ce6H/6BluujYR+kqX3GKH+dChPTQU19wjRPiGk= +google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= +google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= +google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0= +google.golang.org/grpc v1.78.0 h1:K1XZG/yGDJnzMdd/uZHAkVqJE+xIDOcmdSFZkBUicNc= +google.golang.org/grpc v1.78.0/go.mod h1:I47qjTo4OKbMkjA/aOOwxDIiPSBofUtQUI5EfpWvW7U= +google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= +google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= +google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= +google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= +google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= +google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE= +google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= +gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b/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/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= +gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= +gopkg.in/guregu/null.v4 v4.0.0 h1:1Wm3S1WEA2I26Kq+6vcW+w0gcDo44YKYD7YIEJNHDjg= +gopkg.in/guregu/null.v4 v4.0.0/go.mod h1:YoQhUrADuG3i9WqesrCmpNRwm1ypAgSHYqoOcTu/JrI= gopkg.in/inconshreveable/log15.v2 v2.0.0-20180818164646-67afb5ed74ec/go.mod h1:aPpfJ7XW+gOuirDoZ8gHhLh3kZ1B08FtV2bbmy7Jv3s= +gopkg.in/natefinch/lumberjack.v2 v2.2.1 h1:bBRl1b0OH9s/DuPhuXpNl+VtCaJXFZ5/uEFST95x9zc= +gopkg.in/natefinch/lumberjack.v2 v2.2.1/go.mod h1:YD8tP3GAjkrDg1eZH7EGmyESg/lsYskCTPBJVb9jqSc= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gotest.tools/v3 v3.5.2 h1:7koQfIKdy+I8UTetycgUqXWSDwpgv193Ka+qRsmBY8Q= +gotest.tools/v3 v3.5.2/go.mod h1:LtdLGcnqToBH83WByAAi/wiwSFCArdFIUV/xxN4pcjA= +honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= +nhooyr.io/websocket v1.8.6 h1:s+C3xAMLwGmlI31Nyn/eAehUlZPwfYZu2JXM621Q5/k= +nhooyr.io/websocket v1.8.6/go.mod h1:B70DZP8IakI65RVQ51MsWP/8jndNma26DVA/nFSCgW0= +pgregory.net/rapid v1.2.0 h1:keKAYRcjm+e1F0oAuU5F5+YPAWcyxNNRK2wud503Gnk= +pgregory.net/rapid v1.2.0/go.mod h1:PY5XlDGj0+V1FCq0o192FdRhpKHGTRIWBgqjDBTrq04= +sigs.k8s.io/yaml v1.6.0 h1:G8fkbMSAFqgEFgh4b1wmtzDnioxFCUgTZhlbj5P9QYs= +sigs.k8s.io/yaml v1.6.0/go.mod h1:796bPqUfzR/0jLAl6XjHl3Ck7MiyVv8dbTdyT3/pMf4= diff --git a/keystore/helpers_test.go b/keystore/helpers_test.go index 07a218a4a8..62755fb9ec 100644 --- a/keystore/helpers_test.go +++ b/keystore/helpers_test.go @@ -8,6 +8,8 @@ import ( "testing" "github.com/smartcontractkit/chainlink-common/keystore" + "github.com/smartcontractkit/chainlink-common/keystore/scrypt" + "github.com/stretchr/testify/require" ) @@ -27,7 +29,7 @@ func NewKeystoreTH(t *testing.T) *KeystoreTH { ctx := t.Context() st := keystore.NewMemoryStorage() ks, err := keystore.LoadKeystore(ctx, st, "test", - keystore.WithScryptParams(keystore.FastScryptParams), + keystore.WithScryptParams(scrypt.FastScryptParams), keystore.WithLogger(slog.New(slog.NewTextHandler(os.Stdout, &slog.HandlerOptions{Level: slog.LevelDebug}))), ) require.NoError(t, err) diff --git a/keystore/internal/exportutils.go b/keystore/internal/exportutils.go new file mode 100644 index 0000000000..4deef43e7b --- /dev/null +++ b/keystore/internal/exportutils.go @@ -0,0 +1,84 @@ +package internal + +import ( + "encoding/json" + "fmt" + + "github.com/ethereum/go-ethereum/accounts/keystore" + + "github.com/smartcontractkit/chainlink-common/keystore/scrypt" +) + +type Encrypted interface { + GetCrypto() keystore.CryptoJSON +} + +// EncryptedKeyExport represents a chain specific encrypted key +type EncryptedKeyExport struct { + KeyType string `json:"keyType"` + PublicKey string `json:"publicKey"` + Crypto keystore.CryptoJSON `json:"crypto"` +} + +func (x EncryptedKeyExport) GetCrypto() keystore.CryptoJSON { + return x.Crypto +} + +// FromEncryptedJSON gets key [K] from keyJSON [E] and password +func FromEncryptedJSON[E Encrypted, K any]( + identifier string, + keyJSON []byte, + password string, + passwordFunc func(string) string, + privKeyToKey func(export E, rawPrivKey Raw) (K, error), +) (K, error) { + // unmarshal byte data to [E] Encrypted key export + var export E + if err := json.Unmarshal(keyJSON, &export); err != nil { + return *new(K), err + } + + // decrypt data using prefixed password + privKey, err := keystore.DecryptDataV3(export.GetCrypto(), passwordFunc(password)) + if err != nil { + return *new(K), fmt.Errorf("failed to decrypt %s key: %w", identifier, err) + } + + // convert unmarshalled data and decrypted key to [K] key format + key, err := privKeyToKey(export, NewRaw(privKey)) + if err != nil { + return *new(K), fmt.Errorf("failed to convert %s key to key bundle: %w", identifier, err) + } + + return key, nil +} + +type Key interface { + Raw() Raw +} + +// ToEncryptedJSON returns encrypted JSON [E] representing key [K] +func ToEncryptedJSON[E Encrypted, K Key]( + identifier string, + key K, + password string, + scryptParams scrypt.ScryptParams, + passwordFunc func(string) string, + buildExport func(id string, key K, cryptoJSON keystore.CryptoJSON) E, +) (export []byte, err error) { + // encrypt data using prefixed password + cryptoJSON, err := keystore.EncryptDataV3( + key.Raw().bytes, + []byte(passwordFunc(password)), + scryptParams.N, + scryptParams.P, + ) + if err != nil { + return nil, fmt.Errorf("could not encrypt %s key: %w", identifier, err) + } + + // build [E] export struct using encrypted key, identifier, and original key [K] + encryptedKeyExport := buildExport(identifier, key, cryptoJSON) + + return json.Marshal(encryptedKeyExport) +} diff --git a/keystore/keystore.go b/keystore/keystore.go index d7d2ef2e37..a920715c42 100644 --- a/keystore/keystore.go +++ b/keystore/keystore.go @@ -22,6 +22,7 @@ import ( "google.golang.org/protobuf/proto" "github.com/smartcontractkit/chainlink-common/keystore/internal" + "github.com/smartcontractkit/chainlink-common/keystore/scrypt" "github.com/smartcontractkit/chainlink-common/keystore/serialization" ) @@ -125,22 +126,6 @@ var AllKeyTypes = KeyTypeList{X25519, ECDH_P256, Ed25519, ECDSA_S256} var AllEncryptionKeyTypes = KeyTypeList{X25519, ECDH_P256} var AllDigitalSignatureKeyTypes = KeyTypeList{Ed25519, ECDSA_S256} -type ScryptParams struct { - N int - P int -} - -var ( - DefaultScryptParams = ScryptParams{ - N: gethkeystore.StandardScryptN, - P: gethkeystore.StandardScryptP, - } - FastScryptParams ScryptParams = ScryptParams{ - N: 1 << 14, - P: 1, - } -) - // KeyInfo is the information about a key in the keystore. // Public key may be empty for non-asymmetric key types. type KeyInfo struct { @@ -208,7 +193,7 @@ func newKey(keyType KeyType, privateKey internal.Raw, publicKey []byte, createdA // ScryptParams control CPU/memory cost. type EncryptionParams struct { Password string - ScryptParams ScryptParams + ScryptParams scrypt.ScryptParams } func publicKeyFromPrivateKey(privateKeyBytes internal.Raw, keyType KeyType) ([]byte, error) { @@ -271,7 +256,7 @@ func WithLogger(l *slog.Logger) Option { } } -func WithScryptParams(sp ScryptParams) Option { +func WithScryptParams(sp scrypt.ScryptParams) Option { return func(k *keystore) { k.enc.ScryptParams = sp } @@ -285,7 +270,7 @@ func LoadKeystore(ctx context.Context, storage Storage, password string, opts .. storage: storage, enc: EncryptionParams{ Password: password, - ScryptParams: DefaultScryptParams, + ScryptParams: scrypt.DefaultScryptParams, }, } for _, opt := range opts { diff --git a/keystore/scrypt/scrypt.go b/keystore/scrypt/scrypt.go new file mode 100644 index 0000000000..69fdf15d08 --- /dev/null +++ b/keystore/scrypt/scrypt.go @@ -0,0 +1,19 @@ +package scrypt + +import keystore2 "github.com/ethereum/go-ethereum/accounts/keystore" + +type ScryptParams struct { + N int + P int +} + +var ( + DefaultScryptParams = ScryptParams{ + N: keystore2.StandardScryptN, + P: keystore2.StandardScryptP, + } + FastScryptParams ScryptParams = ScryptParams{ + N: 1 << 14, + P: 1, + } +) diff --git a/pkg/chains/types/type.go b/pkg/chains/types/type.go new file mode 100644 index 0000000000..be0bfd55de --- /dev/null +++ b/pkg/chains/types/type.go @@ -0,0 +1,120 @@ +package types + +import ( + "fmt" + "slices" + "strings" + + "github.com/pkg/errors" +) + +// ChainType denotes the chain or network to work with +type ChainType string + +const ( + // EVM for Ethereum or other chains supporting the EVM + EVM ChainType = "evm" + // Cosmos for the Cosmos chain + Cosmos ChainType = "cosmos" + // Solana for the Solana chain + Solana ChainType = "solana" + // StarkNet for the StarkNet chain + StarkNet ChainType = "starknet" + // Aptos for the Aptos chain + Aptos ChainType = "aptos" + // Tron for the Tron chain + Tron ChainType = "tron" + // TON for the TON chain + TON ChainType = "ton" + // Sui for the Sui chain + Sui ChainType = "sui" + // Offchain is used by the MultichainKeyringAdapter when we are signing for offchain (eg. for DKG). + Offchain ChainType = "offchain" +) + +type ChainTypes []ChainType + +func (c ChainTypes) String() (out string) { + var sb strings.Builder + for i, chain := range c { + if i != 0 { + sb.WriteString(", ") + } + sb.WriteString(string(chain)) + } + return sb.String() +} + +func NewChainType(typ uint8) (ChainType, error) { + switch typ { + case 1: + return EVM, nil + case 2: + return Solana, nil + case 3: + return Cosmos, nil + case 4: + return StarkNet, nil + case 5: + return Aptos, nil + case 6: + return Tron, nil + case 7: + return TON, nil + case 8: + return Sui, nil + case 9: + return Offchain, nil + default: + return "", fmt.Errorf("unexpected chaintype.ChainType: %#v", typ) + } +} + +func (c ChainType) Type() (uint8, error) { + switch c { + case EVM: + return 1, nil + case Solana: + return 2, nil + case Cosmos: + return 3, nil + case StarkNet: + return 4, nil + case Aptos: + return 5, nil + case Tron: + return 6, nil + case TON: + return 7, nil + case Sui: + return 8, nil + case Offchain: + return 9, nil + default: + return 0, fmt.Errorf("unexpected chaintype.ChainType: %#v", c) + } +} + +// SupportedChainTypes contain all chains that are supported +var SupportedChainTypes = ChainTypes{EVM, Cosmos, Solana, StarkNet, Aptos, Tron, TON, Sui} + +// ErrInvalidChainType is an error to indicate an unsupported chain type +var ErrInvalidChainType error + +func init() { + supported := make([]string, 0, len(SupportedChainTypes)) + for _, chainType := range SupportedChainTypes { + supported = append(supported, fmt.Sprintf(`"%s"`, chainType)) + } + ErrInvalidChainType = fmt.Errorf("valid types include: [%s]", strings.Join(supported, ", ")) +} + +// IsSupportedChainType checks to see if the chain is supported +func IsSupportedChainType(chainType ChainType) bool { + return slices.Contains(SupportedChainTypes, chainType) +} + +// NewErrInvalidChainType returns an error wrapping ErrInvalidChainType for an unsupported chain +func NewErrInvalidChainType(chainType ChainType) error { + return errors.Wrapf(ErrInvalidChainType, `unknown chain type "%s"`, chainType) +} From 3b4544591ab050922382e7129ffde61581814acf Mon Sep 17 00:00:00 2001 From: pavel-raykov Date: Tue, 10 Feb 2026 09:13:50 +0100 Subject: [PATCH 02/13] Minor. --- keystore/corekeys/ocr2key/cosmos_keyring.go | 4 +- keystore/corekeys/ocr2key/ed25519_keyring.go | 4 +- keystore/corekeys/ocr2key/key_bundle.go | 6 + keystore/corekeys/ocr2key/ton_keyring.go | 4 +- keystore/corekeys/vrfkey/crypto.go | 4 +- keystore/corekeys/vrfkey/crypto_test.go | 2 +- keystore/corekeys/vrfkey/export.go | 2 +- keystore/corekeys/vrfkey/key_v2.go | 4 +- keystore/corekeys/vrfkey/key_v2_test.go | 2 +- keystore/corekeys/vrfkey/models.go | 7 +- keystore/corekeys/vrfkey/proof.go | 4 +- keystore/corekeys/vrfkey/secp256k1/curve.go | 46 +++ .../corekeys/vrfkey/secp256k1/curve_test.go | 20 + keystore/corekeys/vrfkey/secp256k1/field.go | 169 ++++++++ .../corekeys/vrfkey/secp256k1/field_test.go | 158 ++++++++ keystore/corekeys/vrfkey/secp256k1/point.go | 381 ++++++++++++++++++ .../corekeys/vrfkey/secp256k1/point_test.go | 228 +++++++++++ .../corekeys/vrfkey/secp256k1/public_key.go | 150 +++++++ .../vrfkey/secp256k1/public_key_test.go | 40 ++ keystore/corekeys/vrfkey/secp256k1/scalar.go | 232 +++++++++++ .../corekeys/vrfkey/secp256k1/scalar_test.go | 189 +++++++++ keystore/corekeys/vrfkey/secp256k1/suite.go | 91 +++++ .../corekeys/vrfkey/secp256k1/suite_test.go | 15 + keystore/go.mod | 12 +- keystore/go.sum | 17 +- 25 files changed, 1753 insertions(+), 38 deletions(-) create mode 100644 keystore/corekeys/vrfkey/secp256k1/curve.go create mode 100644 keystore/corekeys/vrfkey/secp256k1/curve_test.go create mode 100644 keystore/corekeys/vrfkey/secp256k1/field.go create mode 100644 keystore/corekeys/vrfkey/secp256k1/field_test.go create mode 100644 keystore/corekeys/vrfkey/secp256k1/point.go create mode 100644 keystore/corekeys/vrfkey/secp256k1/point_test.go create mode 100644 keystore/corekeys/vrfkey/secp256k1/public_key.go create mode 100644 keystore/corekeys/vrfkey/secp256k1/public_key_test.go create mode 100644 keystore/corekeys/vrfkey/secp256k1/scalar.go create mode 100644 keystore/corekeys/vrfkey/secp256k1/scalar_test.go create mode 100644 keystore/corekeys/vrfkey/secp256k1/suite.go create mode 100644 keystore/corekeys/vrfkey/secp256k1/suite_test.go diff --git a/keystore/corekeys/ocr2key/cosmos_keyring.go b/keystore/corekeys/ocr2key/cosmos_keyring.go index d2c8d7ddef..d9622a1462 100644 --- a/keystore/corekeys/ocr2key/cosmos_keyring.go +++ b/keystore/corekeys/ocr2key/cosmos_keyring.go @@ -9,8 +9,6 @@ import ( "github.com/pkg/errors" "golang.org/x/crypto/blake2s" - "github.com/smartcontractkit/chainlink/v2/core/utils" - "github.com/smartcontractkit/libocr/offchainreporting2/types" "github.com/smartcontractkit/libocr/offchainreporting2plus/chains/evmutil" ocrtypes "github.com/smartcontractkit/libocr/offchainreporting2plus/types" @@ -66,7 +64,7 @@ func (ckr *cosmosKeyring) Sign3(digest types.ConfigDigest, seqNr uint64, r ocrty func (ckr *cosmosKeyring) SignBlob(b []byte) ([]byte, error) { signedMsg := ed25519.Sign(ckr.privKey(), b) // match on-chain parsing (first 32 bytes are for pubkey, remaining are for signature) - return utils.ConcatBytes(ckr.PublicKey(), signedMsg), nil + return concatBytes(ckr.PublicKey(), signedMsg), nil } func (ckr *cosmosKeyring) Verify(publicKey ocrtypes.OnchainPublicKey, reportCtx ocrtypes.ReportContext, report ocrtypes.Report, signature []byte) bool { diff --git a/keystore/corekeys/ocr2key/ed25519_keyring.go b/keystore/corekeys/ocr2key/ed25519_keyring.go index 78e4a237aa..bf3e709258 100644 --- a/keystore/corekeys/ocr2key/ed25519_keyring.go +++ b/keystore/corekeys/ocr2key/ed25519_keyring.go @@ -9,8 +9,6 @@ import ( "github.com/pkg/errors" "golang.org/x/crypto/blake2b" - "github.com/smartcontractkit/chainlink/v2/core/utils" - "github.com/smartcontractkit/libocr/offchainreporting2/types" "github.com/smartcontractkit/libocr/offchainreporting2plus/chains/evmutil" ocrtypes "github.com/smartcontractkit/libocr/offchainreporting2plus/types" @@ -80,7 +78,7 @@ func (akr *ed25519Keyring) Sign3(digest types.ConfigDigest, seqNr uint64, r ocrt func (akr *ed25519Keyring) SignBlob(b []byte) ([]byte, error) { signedMsg := ed25519.Sign(akr.privKey(), b) // match on-chain parsing (first 32 bytes are for pubkey, remaining are for signature) - return utils.ConcatBytes(akr.PublicKey(), signedMsg), nil + return concatBytes(akr.PublicKey(), signedMsg), nil } func (akr *ed25519Keyring) Verify(publicKey ocrtypes.OnchainPublicKey, reportCtx ocrtypes.ReportContext, report ocrtypes.Report, signature []byte) bool { diff --git a/keystore/corekeys/ocr2key/key_bundle.go b/keystore/corekeys/ocr2key/key_bundle.go index e6db7f774f..f6ef004086 100644 --- a/keystore/corekeys/ocr2key/key_bundle.go +++ b/keystore/corekeys/ocr2key/key_bundle.go @@ -1,6 +1,7 @@ package ocr2key import ( + "bytes" "encoding/hex" "encoding/json" "io" @@ -151,3 +152,8 @@ func adulteratedPassword(auth string) string { s := "ocr2key" + auth return s } + +// ConcatBytes appends a bunch of byte arrays into a single byte array +func concatBytes(bufs ...[]byte) []byte { + return bytes.Join(bufs, []byte{}) +} diff --git a/keystore/corekeys/ocr2key/ton_keyring.go b/keystore/corekeys/ocr2key/ton_keyring.go index f819c04660..69fbec0d8f 100644 --- a/keystore/corekeys/ocr2key/ton_keyring.go +++ b/keystore/corekeys/ocr2key/ton_keyring.go @@ -9,8 +9,6 @@ import ( "github.com/pkg/errors" "github.com/xssnick/tonutils-go/tvm/cell" - "github.com/smartcontractkit/chainlink/v2/core/utils" - "github.com/smartcontractkit/libocr/offchainreporting2/types" "github.com/smartcontractkit/libocr/offchainreporting2plus/chains/evmutil" ocrtypes "github.com/smartcontractkit/libocr/offchainreporting2plus/types" @@ -74,7 +72,7 @@ func (tkr *tonKeyring) reportToSigData3(digest types.ConfigDigest, seqNr uint64, func (tkr *tonKeyring) SignBlob(b []byte) ([]byte, error) { sig := ed25519.Sign(tkr.privKey(), b) - return utils.ConcatBytes(tkr.PublicKey(), sig), nil + return concatBytes(tkr.PublicKey(), sig), nil } func (tkr *tonKeyring) Verify(publicKey ocrtypes.OnchainPublicKey, reportCtx ocrtypes.ReportContext, report ocrtypes.Report, signature []byte) bool { diff --git a/keystore/corekeys/vrfkey/crypto.go b/keystore/corekeys/vrfkey/crypto.go index 6c4833d573..ebbe78ed42 100644 --- a/keystore/corekeys/vrfkey/crypto.go +++ b/keystore/corekeys/vrfkey/crypto.go @@ -10,9 +10,9 @@ import ( "github.com/smartcontractkit/chainlink-common/pkg/utils/hex" + "github.com/smartcontractkit/chainlink-common/keystore/corekeys/vrfkey/secp256k1" + bm "github.com/smartcontractkit/chainlink-common/pkg/utils/big_math" "github.com/smartcontractkit/chainlink-evm/pkg/utils" - "github.com/smartcontractkit/chainlink/v2/core/services/signatures/secp256k1" - bm "github.com/smartcontractkit/chainlink/v2/core/utils/big_math" ) // This file contains golang re-implementations of functions on the VRF solidity diff --git a/keystore/corekeys/vrfkey/crypto_test.go b/keystore/corekeys/vrfkey/crypto_test.go index c81553c99f..2cf7092b03 100644 --- a/keystore/corekeys/vrfkey/crypto_test.go +++ b/keystore/corekeys/vrfkey/crypto_test.go @@ -6,7 +6,7 @@ import ( "github.com/stretchr/testify/assert" - bm "github.com/smartcontractkit/chainlink/v2/core/utils/big_math" + bm "github.com/smartcontractkit/chainlink-common/pkg/utils/big_math" ) func TestVRF_IsSquare(t *testing.T) { diff --git a/keystore/corekeys/vrfkey/export.go b/keystore/corekeys/vrfkey/export.go index f6094c594f..7d0114896a 100644 --- a/keystore/corekeys/vrfkey/export.go +++ b/keystore/corekeys/vrfkey/export.go @@ -8,9 +8,9 @@ import ( "github.com/google/uuid" "github.com/pkg/errors" + "github.com/smartcontractkit/chainlink-common/keystore/corekeys/vrfkey/secp256k1" "github.com/smartcontractkit/chainlink-common/keystore/internal" "github.com/smartcontractkit/chainlink-common/keystore/scrypt" - "github.com/smartcontractkit/chainlink/v2/core/services/signatures/secp256k1" ) func FromEncryptedJSON(keyJSON []byte, password string) (KeyV2, error) { diff --git a/keystore/corekeys/vrfkey/key_v2.go b/keystore/corekeys/vrfkey/key_v2.go index aee26bc00c..2e81806ac8 100644 --- a/keystore/corekeys/vrfkey/key_v2.go +++ b/keystore/corekeys/vrfkey/key_v2.go @@ -11,9 +11,9 @@ import ( "github.com/smartcontractkit/chainlink-evm/pkg/utils" + "github.com/smartcontractkit/chainlink-common/keystore/corekeys/vrfkey/secp256k1" "github.com/smartcontractkit/chainlink-common/keystore/internal" - "github.com/smartcontractkit/chainlink/v2/core/services/signatures/secp256k1" - bm "github.com/smartcontractkit/chainlink/v2/core/utils/big_math" + bm "github.com/smartcontractkit/chainlink-common/pkg/utils/big_math" ) var suite = secp256k1.NewBlakeKeccackSecp256k1() diff --git a/keystore/corekeys/vrfkey/key_v2_test.go b/keystore/corekeys/vrfkey/key_v2_test.go index 659ba54a94..5da83e4eda 100644 --- a/keystore/corekeys/vrfkey/key_v2_test.go +++ b/keystore/corekeys/vrfkey/key_v2_test.go @@ -8,8 +8,8 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + "github.com/smartcontractkit/chainlink-common/keystore/corekeys/vrfkey/secp256k1" "github.com/smartcontractkit/chainlink-common/keystore/internal" - "github.com/smartcontractkit/chainlink/v2/core/services/signatures/secp256k1" ) func TestVRFKeys_KeyV2(t *testing.T) { diff --git a/keystore/corekeys/vrfkey/models.go b/keystore/corekeys/vrfkey/models.go index a72d29f85d..473bb0e78d 100644 --- a/keystore/corekeys/vrfkey/models.go +++ b/keystore/corekeys/vrfkey/models.go @@ -1,6 +1,7 @@ package vrfkey import ( + "bytes" "database/sql/driver" "encoding/json" "fmt" @@ -10,8 +11,8 @@ import ( "github.com/ethereum/go-ethereum/accounts/keystore" "github.com/pkg/errors" - "github.com/smartcontractkit/chainlink/v2/core/services/signatures/secp256k1" - "github.com/smartcontractkit/chainlink/v2/core/utils" + "github.com/smartcontractkit/chainlink-common/keystore/corekeys/vrfkey/secp256k1" + "github.com/smartcontractkit/chainlink-common/keystore/internal/atomicfile" ) // EncryptedVRFKey contains encrypted private key to be serialized to DB @@ -43,7 +44,7 @@ func (e *EncryptedVRFKey) WriteToDisk(path string) error { return errors.Wrapf(err, "while marshaling key to save to %s", path) } userReadWriteOtherNoAccess := os.FileMode(0600) - return utils.WriteFileWithMaxPerms(path, keyJSON, userReadWriteOtherNoAccess) + return atomicfile.WriteFile(path, bytes.NewReader(keyJSON), userReadWriteOtherNoAccess) } // Copied from go-ethereum/accounts/keystore/key.go's encryptedKeyJSONV3 diff --git a/keystore/corekeys/vrfkey/proof.go b/keystore/corekeys/vrfkey/proof.go index 689833f939..6ed1ca6439 100644 --- a/keystore/corekeys/vrfkey/proof.go +++ b/keystore/corekeys/vrfkey/proof.go @@ -7,9 +7,9 @@ import ( "go.dedis.ch/kyber/v3" + "github.com/smartcontractkit/chainlink-common/keystore/corekeys/vrfkey/secp256k1" + bm "github.com/smartcontractkit/chainlink-common/pkg/utils/big_math" "github.com/smartcontractkit/chainlink-evm/pkg/utils" - "github.com/smartcontractkit/chainlink/v2/core/services/signatures/secp256k1" - bm "github.com/smartcontractkit/chainlink/v2/core/utils/big_math" ) // Proof represents a proof that Gamma was constructed from the Seed diff --git a/keystore/corekeys/vrfkey/secp256k1/curve.go b/keystore/corekeys/vrfkey/secp256k1/curve.go new file mode 100644 index 0000000000..70187e6873 --- /dev/null +++ b/keystore/corekeys/vrfkey/secp256k1/curve.go @@ -0,0 +1,46 @@ +// Package secp256k1 is an implementation of the kyber.{Group,Point,Scalar} +// ////////////////////////////////////////////////////////////////////////////// +// +// XXX: Do not use in production until this code has been audited. +// +// ////////////////////////////////////////////////////////////////////////////// +// interfaces, based on btcd/btcec and kyber/group/mod +// +// XXX: NOT CONSTANT TIME! +package secp256k1 + +import ( + "math/big" + + secp256k1BTCD "github.com/btcsuite/btcd/btcec/v2" + + "go.dedis.ch/kyber/v3" +) + +// Secp256k1 represents the secp256k1 group. +// There are no parameters and no initialization is required +// because it supports only this one specific curve. +type Secp256k1 struct{} + +// s256 is the btcec representation of secp256k1. +var s256 *secp256k1BTCD.KoblitzCurve = secp256k1BTCD.S256() + +// String returns the name of the curve +func (*Secp256k1) String() string { return "Secp256k1" } + +var egScalar kyber.Scalar = newScalar(big.NewInt(0)) +var egPoint kyber.Point = &secp256k1Point{newFieldZero(), newFieldZero()} + +// ScalarLen returns the length of a marshalled Scalar +func (*Secp256k1) ScalarLen() int { return egScalar.MarshalSize() } + +// Scalar creates a new Scalar for the prime-order group on the secp256k1 curve +func (*Secp256k1) Scalar() kyber.Scalar { return newScalar(big.NewInt(0)) } + +// PointLen returns the length of a marshalled Point +func (*Secp256k1) PointLen() int { return egPoint.MarshalSize() } + +// Point returns a new secp256k1 point +func (*Secp256k1) Point() kyber.Point { + return &secp256k1Point{newFieldZero(), newFieldZero()} +} diff --git a/keystore/corekeys/vrfkey/secp256k1/curve_test.go b/keystore/corekeys/vrfkey/secp256k1/curve_test.go new file mode 100644 index 0000000000..325bae20d4 --- /dev/null +++ b/keystore/corekeys/vrfkey/secp256k1/curve_test.go @@ -0,0 +1,20 @@ +package secp256k1 + +import ( + "testing" + + "github.com/stretchr/testify/require" +) + +var group = &Secp256k1{} + +func TestSecp256k1_String(t *testing.T) { + require.Equal(t, "Secp256k1", group.String()) +} + +func TestSecp256k1_Constructors(t *testing.T) { + require.Equal(t, 32, group.ScalarLen()) + require.Equal(t, ToInt(group.Scalar()), bigZero) + require.Equal(t, 33, group.PointLen()) + require.Equal(t, &secp256k1Point{fieldZero, fieldZero}, group.Point()) +} diff --git a/keystore/corekeys/vrfkey/secp256k1/field.go b/keystore/corekeys/vrfkey/secp256k1/field.go new file mode 100644 index 0000000000..bf9652e5db --- /dev/null +++ b/keystore/corekeys/vrfkey/secp256k1/field.go @@ -0,0 +1,169 @@ +// Package secp256k1 is an implementation of the kyber.{Group,Point,Scalar} +// ////////////////////////////////////////////////////////////////////////////// +// +// XXX: Do not use in production until this code has been audited. +// +// ////////////////////////////////////////////////////////////////////////////// +// interfaces, based on btcd/btcec and kyber/group/mod +// +// XXX: NOT CONSTANT TIME! +package secp256k1 + +// Arithmetic operations in the base field of secp256k1, i.e. ℤ/qℤ, where q is +// the base field characteristic. + +import ( + "crypto/cipher" + "fmt" + "math/big" + + "go.dedis.ch/kyber/v3/util/random" +) + +// q is the field characteristic (cardinality) of the secp256k1 base field. All +// arithmetic operations on the field are modulo this. +var q = s256.P + +type fieldElt big.Int + +// newFieldZero returns a newly allocated field element. +func newFieldZero() *fieldElt { return (*fieldElt)(big.NewInt(0)) } + +// Int returns f as a big.Int +func (f *fieldElt) int() *big.Int { return (*big.Int)(f) } + +// modQ reduces f's underlying big.Int modulo q, and returns it +func (f *fieldElt) modQ() *fieldElt { + if f.int().Cmp(q) != -1 || f.int().Cmp(bigZero) == -1 { + // f ∉ {0, ..., q-1}. Find the representative of f+qℤ in that set. + // + // Per Mod docstring, "Mod implements Euclidean modulus", meaning that after + // this, f will be the smallest non-negative representative of its + // equivalence class in ℤ/qℤ. TODO(alx): Make this faster + f.int().Mod(f.int(), q) + } + return f +} + +// This differs from SetInt below, in that it does not take a copy of v. +func fieldEltFromBigInt(v *big.Int) *fieldElt { return (*fieldElt)(v).modQ() } + +func fieldEltFromInt(v int64) *fieldElt { + return fieldEltFromBigInt(big.NewInt(v)).modQ() +} + +var fieldZero = fieldEltFromInt(0) +var bigZero = big.NewInt(0) + +// String returns the string representation of f +func (f *fieldElt) String() string { + return fmt.Sprintf("fieldElt{%x}", f.int()) +} + +// Equal returns true iff f=g, i.e. the backing big.Ints satisfy f ≡ g mod q +func (f *fieldElt) Equal(g *fieldElt) bool { + if f == (*fieldElt)(nil) && g == (*fieldElt)(nil) { + return true + } + if f == (*fieldElt)(nil) { // f is nil, g is not + return false + } + if g == (*fieldElt)(nil) { // g is nil, f is not + return false + } + return bigZero.Cmp(newFieldZero().Sub(f, g).modQ().int()) == 0 +} + +// Add sets f to the sum of a and b modulo q, and returns it. +func (f *fieldElt) Add(a, b *fieldElt) *fieldElt { + f.int().Add(a.int(), b.int()) + return f.modQ() +} + +// Sub sets f to a-b mod q, and returns it. +func (f *fieldElt) Sub(a, b *fieldElt) *fieldElt { + f.int().Sub(a.int(), b.int()) + return f.modQ() +} + +// Set sets f's value to v, and returns f. +func (f *fieldElt) Set(v *fieldElt) *fieldElt { + f.int().Set(v.int()) + return f.modQ() +} + +// SetInt sets f's value to v mod q, and returns f. +func (f *fieldElt) SetInt(v *big.Int) *fieldElt { + f.int().Set(v) + return f.modQ() +} + +// Pick samples uniformly from {0, ..., q-1}, assigns sample to f, and returns f +func (f *fieldElt) Pick(rand cipher.Stream) *fieldElt { + return f.SetInt(random.Int(q, rand)) // random.Int safe because q≅2²⁵⁶, q<2²⁵⁶ +} + +// Neg sets f to the negation of g modulo q, and returns it +func (f *fieldElt) Neg(g *fieldElt) *fieldElt { + f.int().Neg(g.int()) + return f.modQ() +} + +// Clone returns a new fieldElt, backed by a clone of f +func (f *fieldElt) Clone() *fieldElt { return newFieldZero().Set(f.modQ()) } + +// SetBytes sets f to the 32-byte big-endian value represented by buf, reduces +// it, and returns it. +func (f *fieldElt) SetBytes(buf [32]byte) *fieldElt { + f.int().SetBytes(buf[:]) + return f.modQ() +} + +// Bytes returns the 32-byte big-endian representation of f +func (f *fieldElt) Bytes() [32]byte { + bytes := f.modQ().int().Bytes() + if len(bytes) > 32 { + panic("field element longer than 256 bits") + } + var rv [32]byte + copy(rv[32-len(bytes):], bytes) // leftpad w zeros + return rv +} + +var two = big.NewInt(2) + +// square returns y² mod q +func fieldSquare(y *fieldElt) *fieldElt { + return fieldEltFromBigInt(newFieldZero().int().Exp(y.int(), two, q)) +} + +func i() *big.Int { return new(big.Int) } + +// sqrtPower is s.t. n^sqrtPower≡sqrt(n) mod q, if n has a root at all. See +// https://math.stackexchange.com/a/1816280, for instance +var sqrtPower = i().Rsh(i().Add(q, big.NewInt(1)), 2) // (q +1)/4 + +// maybeSqrtInField returns a square root of v, if it has any, else nil +func maybeSqrtInField(v *fieldElt) *fieldElt { + s := newFieldZero() + s.int().Exp(v.int(), sqrtPower, q) + if !fieldSquare(s).Equal(v) { + return nil + } + return s +} + +var three = big.NewInt(3) +var seven = fieldEltFromInt(7) + +// rightHandSide returns the RHS of the secp256k1 equation, x³+7 mod q, given x +func rightHandSide(x *fieldElt) *fieldElt { + xCubed := newFieldZero() + xCubed.int().Exp(x.int(), three, q) + return xCubed.Add(xCubed, seven) +} + +// isEven returns true if f is even, false otherwise +func (f *fieldElt) isEven() bool { + return big.NewInt(0).Mod(f.int(), two).Cmp(big.NewInt(0)) == 0 +} diff --git a/keystore/corekeys/vrfkey/secp256k1/field_test.go b/keystore/corekeys/vrfkey/secp256k1/field_test.go new file mode 100644 index 0000000000..70c4f15d2f --- /dev/null +++ b/keystore/corekeys/vrfkey/secp256k1/field_test.go @@ -0,0 +1,158 @@ +package secp256k1 + +import ( + "encoding/hex" + "math/big" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + "github.com/smartcontractkit/chainlink/v2/core/services/signatures/cryptotest" +) + +var numFieldSamples = 10 + +var observedFieldElts map[string]bool + +func init() { + observedFieldElts = make(map[string]bool) +} + +// observedFieldElt ensures that novel scalars are being picked. +func observedFieldElt(t *testing.T, s *fieldElt) { + elt := s.Bytes() + data := hex.Dump(elt[:]) + require.False(t, observedFieldElts[data]) + observedFieldElts[data] = true +} + +var randomStream = cryptotest.NewStream(&testing.T{}, 0) + +func TestField_SetIntAndEqual(t *testing.T) { + tests := []int64{5, 67108864, 67108865, 4294967295} + g := newFieldZero() + for _, test := range tests { + f := fieldEltFromInt(test) + i := big.NewInt(test) + g.SetInt(i) + assert.Equal(t, f, g, + "different values obtained for same input, using "+ + "SetInt vs fieldEltFromInt") + i.Add(i, big.NewInt(1)) + assert.Equal(t, f, g, + "SetInt should take a copy of the backing big.Int") + } +} + +func TestField_String(t *testing.T) { + require.Equal(t, "fieldElt{0}", fieldZero.String()) +} + +func TestField_Equal(t *testing.T) { + require.True(t, (*fieldElt)(nil).Equal((*fieldElt)(nil))) + require.False(t, (*fieldElt)(nil).Equal(fieldZero)) + require.False(t, fieldZero.Equal((*fieldElt)(nil))) +} + +func TestField_Set(t *testing.T) { + f := fieldEltFromInt(1) + g := newFieldZero() + g.Set(f) + g.Add(g, fieldEltFromInt(1)) + assert.Equal(t, f, fieldEltFromInt(1), + "Set takes a copy of the backing big.Int") +} + +func TestFieldEltFromInt(t *testing.T) { + assert.Equal(t, fieldEltFromInt(1), // Also tests fieldElt.modQ + fieldEltFromBigInt(new(big.Int).Add(q, big.NewInt(1))), + "only one representation of a ℤ/qℤ element should be used") +} + +func TestField_SmokeTestPick(t *testing.T) { + f := newFieldZero() + f.Pick(randomStream) + observedFieldElt(t, f) + assert.Equal(t, 1, f.int().Cmp(big.NewInt(1000000000)), + "should be greater than 1000000000, with very high probability") +} + +func TestField_Neg(t *testing.T) { + f := newFieldZero() + for range numFieldSamples { + f.Pick(randomStream) + observedFieldElt(t, f) + g := f.Clone() + g.Neg(g) + require.True(t, g.Add(f, g).Equal(fieldZero), + "adding something to its negative should give zero: "+ + "failed with %s", f) + } +} + +func TestField_Sub(t *testing.T) { + f := newFieldZero() + for range numFieldSamples { + f.Pick(randomStream) + observedFieldElt(t, f) + require.True(t, f.Sub(f, f).Equal(fieldZero), + "subtracting something from itself should give zero: "+ + "failed with %s", f) + } +} + +func TestField_Clone(t *testing.T) { + f := fieldEltFromInt(1) + g := f.Clone() + h := f.Clone() + assert.Equal(t, f, g, "clone output does not equal original") + g.Add(f, f) + assert.Equal(t, f, h, "clone does not make a copy") +} + +func TestField_SetBytesAndBytes(t *testing.T) { + f := newFieldZero() + g := newFieldZero() + for range numFieldSamples { + f.Pick(randomStream) + observedFieldElt(t, f) + g.SetBytes(f.Bytes()) + require.True(t, g.Equal(f), + "roundtrip through serialization should give same "+ + "result back: failed with %s", f) + } +} + +func TestField_MaybeSquareRootInField(t *testing.T) { + f := newFieldZero() + minusOne := fieldEltFromInt(-1) + assert.Nil(t, maybeSqrtInField(minusOne), "-1 is not a square, in this field") + for range numFieldSamples { + f.Pick(randomStream) + observedFieldElt(t, f) + require.Equal(t, -1, f.int().Cmp(q), "picked larger value than q: %s", f) + require.NotEqual(t, -1, f.int().Cmp(big.NewInt(-1)), + "backing int must be non-negative") + s := fieldSquare(f) + g := maybeSqrtInField(s) + require.NotEqual(t, (*fieldElt)(nil), g) + ng := newFieldZero().Neg(g) + require.True(t, f.Equal(g) || f.Equal(ng), "squaring something and "+ + "taking the square root should give ± the original: failed with %s", f) + bigIntSqrt := newFieldZero() // Cross-check against big.ModSqrt + rv := bigIntSqrt.int().ModSqrt(s.int(), q) + require.NotNil(t, rv) + require.True(t, bigIntSqrt.Equal(g) || bigIntSqrt.Equal(ng)) + nonSquare := newFieldZero().Neg(s) + rv = bigIntSqrt.int().ModSqrt(nonSquare.int(), q) + require.Nil(t, rv, "ModSqrt indicates nonSquare is square") + require.Nil(t, maybeSqrtInField(nonSquare), "the negative of square "+ + "should not be a square") + } +} + +func TestField_RightHandSide(t *testing.T) { + assert.Equal(t, rightHandSide(fieldEltFromInt(1)), fieldEltFromInt(8)) + assert.Equal(t, rightHandSide(fieldEltFromInt(2)), fieldEltFromInt(15)) +} diff --git a/keystore/corekeys/vrfkey/secp256k1/point.go b/keystore/corekeys/vrfkey/secp256k1/point.go new file mode 100644 index 0000000000..cc3fb47b60 --- /dev/null +++ b/keystore/corekeys/vrfkey/secp256k1/point.go @@ -0,0 +1,381 @@ +// Package secp256k1 is an implementation of the kyber.{Group,Point,Scalar} +// ////////////////////////////////////////////////////////////////////////////// +// +// XXX: Do not use in production until this code has been audited. +// +// ////////////////////////////////////////////////////////////////////////////// +// interfaces, based on btcd/btcec and kyber/group/mod +// +// XXX: NOT CONSTANT TIME! +package secp256k1 + +// Implementation of kyber.Point interface for elliptic-curve arithmetic +// operations on secpk256k1. +// +// This is mostly a wrapper of the functionality provided by btcec + +import ( + "crypto/cipher" + "errors" + "fmt" + "io" + "math/big" + + "go.dedis.ch/kyber/v3" + "go.dedis.ch/kyber/v3/util/key" + "golang.org/x/crypto/sha3" +) + +// btcec's public interface uses this affine representation for points on the +// curve. This does not naturally accommodate the point at infinity. btcec +// represents it as (0, 0), which is not a point on {y²=x³+7}. +type secp256k1Point struct { + X *fieldElt + Y *fieldElt +} + +func newPoint() *secp256k1Point { + return &secp256k1Point{newFieldZero(), newFieldZero()} +} + +// String returns a string representation of P +func (P *secp256k1Point) String() string { + return fmt.Sprintf("Secp256k1{X: %s, Y: %s}", P.X, P.Y) +} + +// Equal returns true if p and pPrime represent the same point, false otherwise. +func (P *secp256k1Point) Equal(pPrime kyber.Point) bool { + return P.X.Equal(pPrime.(*secp256k1Point).X) && + P.Y.Equal(pPrime.(*secp256k1Point).Y) +} + +// Null sets p to the group-identity value, and returns it. +func (P *secp256k1Point) Null() kyber.Point { + P.X = fieldEltFromInt(0) // btcec representation of null point is (0,0) + P.Y = fieldEltFromInt(0) + return P +} + +// Base sets p to a copy of the standard group generator, and returns it. +func (P *secp256k1Point) Base() kyber.Point { + P.X.SetInt(s256.Gx) + P.Y.SetInt(s256.Gy) + return P +} + +// Pick sets P to a random point sampled from rand, and returns it. +func (P *secp256k1Point) Pick(rand cipher.Stream) kyber.Point { + for { // Keep trying X's until one fits the curve (~50% probability of + // success each iteration + P.X.Set(newFieldZero().Pick(rand)) + maybeRHS := rightHandSide(P.X) + if maybeY := maybeSqrtInField(maybeRHS); maybeY != (*fieldElt)(nil) { + P.Y.Set(maybeY) + // Take the negative with 50% probability + b := make([]byte, 1) + rand.XORKeyStream(b, b) + if b[0]&1 == 0 { + P.Y.Neg(P.Y) + } + return P + } + } +} + +// Set sets P to copies of pPrime's values, and returns it. +func (P *secp256k1Point) Set(pPrime kyber.Point) kyber.Point { + P.X.Set(pPrime.(*secp256k1Point).X) + P.Y.Set(pPrime.(*secp256k1Point).Y) + return P +} + +// Clone returns a copy of P. +func (P *secp256k1Point) Clone() kyber.Point { + return &secp256k1Point{X: P.X.Clone(), Y: P.Y.Clone()} +} + +// EmbedLen returns the number of bytes of data which can be embedded in a point. +func (*secp256k1Point) EmbedLen() int { + // Reserve the most-significant 8 bits for pseudo-randomness. + // Reserve the least-significant 8 bits for embedded data length. + return (255 - 8 - 8) / 8 +} + +// Embed encodes a limited amount of specified data in the Point, using r as a +// source of cryptographically secure random data. Implementations only embed +// the first EmbedLen bytes of the given data. +func (P *secp256k1Point) Embed(data []byte, r cipher.Stream) kyber.Point { + numEmbedBytes := P.EmbedLen() + if len(data) > numEmbedBytes { + panic("too much data to embed in a point") + } + numEmbedBytes = len(data) + var x [32]byte + randStart := 1 // First byte to fill with random data + if data != nil { + x[0] = byte(numEmbedBytes) // Encode length in low 8 bits + copy(x[1:1+numEmbedBytes], data) // Copy in data to embed + randStart = 1 + numEmbedBytes + } + maxAttempts := 10000 + // Try random x ordinates satisfying the constraints, until one provides + // a point on secp256k1 + for range maxAttempts { + // Fill the rest of the x ordinate with random data + r.XORKeyStream(x[randStart:], x[randStart:]) + xOrdinate := newFieldZero().SetBytes(x) + // RHS of secp256k1 equation is x³+7 mod p. Success if square. + // We optimistically don't use btcec.IsOnCurve, here, because we + // hope to assign the intermediate result maybeY to P.Y + secp256k1RHS := rightHandSide(xOrdinate) + if maybeY := maybeSqrtInField(secp256k1RHS); maybeY != (*fieldElt)(nil) { + P.X = xOrdinate // success: found (x,y) s.t. y²=x³+7 + P.Y = maybeY + return P + } + } + // Probability 2^{-maxAttempts}, under correct operation. + panic("failed to find point satisfying all constraints") +} + +// Data returns data embedded in P, or an error if inconsistent with encoding +func (P *secp256k1Point) Data() ([]byte, error) { + b := P.X.Bytes() + dataLength := int(b[0]) + if dataLength > P.EmbedLen() { + return nil, errors.New("point specifies too much data") + } + return b[1 : dataLength+1], nil +} + +// Add sets P to a+b (secp256k1 group operation) and returns it. +func (P *secp256k1Point) Add(a, b kyber.Point) kyber.Point { + X, Y := s256.Add( + a.(*secp256k1Point).X.int(), a.(*secp256k1Point).Y.int(), + b.(*secp256k1Point).X.int(), b.(*secp256k1Point).Y.int()) + P.X.SetInt(X) + P.Y.SetInt(Y) + return P +} + +// Add sets P to a-b (secp256k1 group operation), and returns it. +func (P *secp256k1Point) Sub(a, b kyber.Point) kyber.Point { + X, Y := s256.Add( + a.(*secp256k1Point).X.int(), a.(*secp256k1Point).Y.int(), + b.(*secp256k1Point).X.int(), + newFieldZero().Neg(b.(*secp256k1Point).Y).int()) // -b_y + P.X.SetInt(X) + P.Y.SetInt(Y) + return P +} + +// Neg sets P to -a (in the secp256k1 group), and returns it. +func (P *secp256k1Point) Neg(a kyber.Point) kyber.Point { + P.X = a.(*secp256k1Point).X.Clone() + P.Y = newFieldZero().Neg(a.(*secp256k1Point).Y) + return P +} + +// Mul sets P to s*a (in the secp256k1 group, i.e. adding a to itself s times), +// and returns it. If a is nil, it is replaced by the secp256k1 generator. +func (P *secp256k1Point) Mul(s kyber.Scalar, a kyber.Point) kyber.Point { + sBytes, err := s.(*secp256k1Scalar).MarshalBinary() + if err != nil { + panic(fmt.Errorf("failure while marshaling multiplier: %w", + err)) + } + var X, Y *big.Int + if a == (*secp256k1Point)(nil) || a == nil { + X, Y = s256.ScalarBaseMult(sBytes) + } else { + X, Y = s256.ScalarMult(a.(*secp256k1Point).X.int(), + a.(*secp256k1Point).Y.int(), sBytes) + } + P.X.SetInt(X) + P.Y.SetInt(Y) + return P +} + +// MarshalBinary returns the concatenated big-endian representation of the X +// ordinate and a byte which is 0 if Y is even, 1 if it's odd. Or it returns an +// error on failure. +func (P *secp256k1Point) MarshalBinary() ([]byte, error) { + maybeSqrt := maybeSqrtInField(rightHandSide(P.X)) + if maybeSqrt == (*fieldElt)(nil) { + return nil, errors.New("x³+7 not a square") + } + minusMaybeSqrt := newFieldZero().Neg(maybeSqrt) + if !P.Y.Equal(maybeSqrt) && !P.Y.Equal(minusMaybeSqrt) { + return nil, errors.New("y ≠ ±maybeSqrt(x³+7), so not a point on the curve") + } + rv := make([]byte, P.MarshalSize()) + signByte := P.MarshalSize() - 1 // Last byte contains sign of Y. + xordinate := P.X.Bytes() + copyLen := copy(rv[:signByte], xordinate[:]) + if copyLen != P.MarshalSize()-1 { + return []byte{}, errors.New("marshal of x ordinate too short") + } + if P.Y.isEven() { + rv[signByte] = 0 + } else { + rv[signByte] = 1 + } + return rv, nil +} + +// MarshalSize returns the length of the byte representation of P +func (P *secp256k1Point) MarshalSize() int { return 33 } + +// MarshalID returns the ID for a secp256k1 point +func (P *secp256k1Point) MarshalID() [8]byte { + return [8]byte{'s', 'p', '2', '5', '6', '.', 'p', 'o'} +} + +// UnmarshalBinary sets P to the point represented by contents of buf, or +// returns an non-nil error +func (P *secp256k1Point) UnmarshalBinary(buf []byte) error { + var err error + if len(buf) != P.MarshalSize() { + err = errors.New("wrong length for marshaled point") + } + if err == nil && (buf[32] != 0 && buf[32] != 1) { + err = errors.New("bad sign byte (the last one)") + } + if err != nil { + return err + } + var xordinate [32]byte + copy(xordinate[:], buf[:32]) + P.X = newFieldZero().SetBytes(xordinate) + secp256k1RHS := rightHandSide(P.X) + maybeY := maybeSqrtInField(secp256k1RHS) + if maybeY == (*fieldElt)(nil) { + return errors.New("x ordinate does not correspond to a curve point") + } + isEven := maybeY.isEven() + P.Y.Set(maybeY) + if (buf[32] == 0 && !isEven) || (buf[32] == 1 && isEven) { + P.Y.Neg(P.Y) + } else { + if buf[32] != 0 && buf[32] != 1 { + return errors.New("parity byte must be 0 or 1") + } + } + return nil +} + +// MarshalTo writes the serialized P to w, and returns the number of bytes +// written, or an error on failure. +func (P *secp256k1Point) MarshalTo(w io.Writer) (int, error) { + buf, err := P.MarshalBinary() + if err != nil { + return 0, err + } + return w.Write(buf) +} + +// UnmarshalFrom sets P to the secp256k1 point represented by bytes read from r, +// and returns the number of bytes read, or an error on failure. +func (P *secp256k1Point) UnmarshalFrom(r io.Reader) (int, error) { + buf := make([]byte, P.MarshalSize()) + n, err := io.ReadFull(r, buf) + if err != nil { + return 0, err + } + return n, P.UnmarshalBinary(buf) +} + +// EthereumAddress returns the 160-bit address corresponding to p as public key. +func EthereumAddress(p kyber.Point) (rv [20]byte) { + // The Ethereum address of P is the bottom 160 bits of keccak256(P.X‖P.Y), + // where P.X and P.Y are represented in 32 bytes as big-endian. See equations + // (277, 284) of Ethereum Yellow Paper version 3e36772, or go-ethereum's + // crypto.PubkeyToAddress. + h := sha3.NewLegacyKeccak256() + if _, err := h.Write(LongMarshal(p)); err != nil { + panic(err) + } + copy(rv[:], h.Sum(nil)[12:]) + return rv +} + +// IsSecp256k1Point returns true if p is a secp256k1Point +func IsSecp256k1Point(p kyber.Point) bool { + switch p.(type) { + case *secp256k1Point: + return true + default: + return false + } +} + +// Coordinates returns the coordinates of p +func Coordinates(p kyber.Point) (*big.Int, *big.Int) { + return p.(*secp256k1Point).X.int(), p.(*secp256k1Point).Y.int() +} + +// ValidPublicKey returns true iff p can be used in the optimized on-chain +// Schnorr-signature verification. See SchnorrSECP256K1.sol for details. +func ValidPublicKey(p kyber.Point) bool { + if p == (*secp256k1Point)(nil) || p == nil { + return false + } + P, ok := p.(*secp256k1Point) + if !ok { + return false + } + maybeY := maybeSqrtInField(rightHandSide(P.X)) + return maybeY != nil && (P.Y.Equal(maybeY) || P.Y.Equal(maybeY.Neg(maybeY))) +} + +// Generate generates a public/private key pair, which can be verified cheaply +// on-chain +func Generate(random cipher.Stream) *key.Pair { + p := key.Pair{} + for !ValidPublicKey(p.Public) { + p.Private = (&Secp256k1{}).Scalar().Pick(random) + p.Public = (&Secp256k1{}).Point().Mul(p.Private, nil) + } + return &p +} + +// LongMarshal returns the concatenated coordinates serialized as uint256's +func LongMarshal(p kyber.Point) []byte { + xMarshal := p.(*secp256k1Point).X.Bytes() + yMarshal := p.(*secp256k1Point).Y.Bytes() + return append(xMarshal[:], yMarshal[:]...) +} + +// LongUnmarshal returns the secp256k1 point represented by m, as a concatenated +// pair of uint256's +func LongUnmarshal(m []byte) (kyber.Point, error) { + if len(m) != 64 { + return nil, fmt.Errorf( + "0x%x does not represent an uncompressed secp256k1Point. Should be length 64, but is length %d", + m, len(m)) + } + p := newPoint() + p.X.SetInt(big.NewInt(0).SetBytes(m[:32])) + p.Y.SetInt(big.NewInt(0).SetBytes(m[32:])) + if !ValidPublicKey(p) { + return nil, fmt.Errorf("%s is not a valid secp256k1 point", p) + } + return p, nil +} + +// ScalarToPublicPoint returns the public secp256k1 point associated to s +func ScalarToPublicPoint(s kyber.Scalar) kyber.Point { + publicPoint := (&Secp256k1{}).Point() + return publicPoint.Mul(s, nil) +} + +// SetCoordinates returns the point (x,y), or panics if an invalid secp256k1Point +func SetCoordinates(x, y *big.Int) kyber.Point { + rv := newPoint() + rv.X.SetInt(x) + rv.Y.SetInt(y) + if !ValidPublicKey(rv) { + panic("point requested from invalid coordinates") + } + return rv +} diff --git a/keystore/corekeys/vrfkey/secp256k1/point_test.go b/keystore/corekeys/vrfkey/secp256k1/point_test.go new file mode 100644 index 0000000000..b415825d0b --- /dev/null +++ b/keystore/corekeys/vrfkey/secp256k1/point_test.go @@ -0,0 +1,228 @@ +package secp256k1 + +import ( + "bytes" + "crypto/rand" + "encoding/hex" + "math/big" + "testing" + + "go.dedis.ch/kyber/v3/group/curve25519" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + "github.com/smartcontractkit/chainlink/v2/core/services/signatures/cryptotest" +) + +var numPointSamples = 10 + +var randomStreamPoint = cryptotest.NewStream(&testing.T{}, 0) + +func TestPoint_String(t *testing.T) { + require.Equal(t, "Secp256k1{X: fieldElt{0}, Y: fieldElt{0}}", newPoint().String()) +} + +func TestPoint_CloneAndEqual(t *testing.T) { + f := newPoint() + for range numPointSamples { + g := f.Clone() + f.Pick(randomStreamPoint) + assert.NotEqual(t, f, g, + "modifying original shouldn't change clone") + g, h := f.Clone(), f.Clone() + assert.Equal(t, f, g, "clones should be equal") + g.Add(g, f) + assert.Equal(t, h, f, + "modifying a clone shouldn't change original") + } +} + +func TestPoint_NullAndAdd(t *testing.T) { + f, g := newPoint(), newPoint() + for range numPointSamples { + g.Null() + f.Pick(randomStreamPoint) + g.Add(f, g) + assert.Equal(t, f, g, "adding zero should have no effect") + } +} + +func TestPoint_Set(t *testing.T) { + p := newPoint() + base := newPoint().Base() + assert.NotEqual(t, p, base, "generator should not be zero") + p.Set(base) + assert.Equal(t, p, base, "setting to generator should yield generator") +} + +func TestPoint_Embed(t *testing.T) { + p := newPoint() + for range numPointSamples { + data := make([]byte, p.EmbedLen()) + _, err := rand.Read(data) + require.NoError(t, err) + p.Embed(data, randomStreamPoint) + require.True(t, s256.IsOnCurve(p.X.int(), p.Y.int()), + "should embed to a secp256k1 point") + output, err := p.Data() + require.NoError(t, err) + require.True(t, bytes.Equal(data, output), + "should get same value back after round-trip "+ + "embedding, got %v, then %v", data, output) + } + var uint256Bytes [32]byte + uint256Bytes[0] = 30 + p.X.SetBytes(uint256Bytes) + _, err := p.Data() + require.Error(t, err) + require.Contains(t, err.Error(), "specifies too much data") + var b bytes.Buffer + p.Pick(randomStreamPoint) + _, err = p.MarshalTo(&b) + require.NoError(t, err) + _, err = p.UnmarshalFrom(&b) + require.NoError(t, err) + data := make([]byte, p.EmbedLen()+1) // Check length validation. This test + defer func() { // comes last, because it triggers panic + r := recover() + require.NotNil(t, r, "calling embed with too much data should panic") + require.Contains(t, r, "too much data to embed in a point") + }() + p.Embed(data, randomStreamPoint) +} + +func TestPoint_AddSubAndNeg(t *testing.T) { + zero := newPoint().Null() + p := newPoint() + for range numPointSamples { + p.Pick(randomStreamPoint) + q := p.Clone() + p.Sub(p, q) + require.True(t, p.Equal(zero), + "subtracting a point from itself should give zero, "+ + "got %v - %v = %v ≠ %v", q, q, p, zero) + p.Neg(q) + r := newPoint().Add(p, q) + require.True(t, r.Equal(zero), + "adding a point to its negative should give zero"+ + " got %v+%v=%v≠%v", q, p, r, zero) + r.Neg(q) + p.Sub(q, r) + s := newPoint().Add(q, q) + require.True(t, p.Equal(s), "q-(-q)=q+q?"+ + " got %v-%v=%v≠%v", q, r, p, s) + } +} + +func TestPoint_Mul(t *testing.T) { + zero := newPoint().Null() + multiplier := newScalar(bigZero) + one := newScalar(big.NewInt(int64(1))) + var p *secp256k1Point + for i := 0; i < numPointSamples/5; i++ { + if i%20 == 0 { + p = nil // Test default to generator point + } else { + p = newPoint() + p.Pick(randomStreamPoint) + } + multiplier.Pick(randomStreamPoint) + q := newPoint().Mul(one, p) + comparee := newPoint() + if p == (*secp256k1Point)(nil) { + comparee.Base() + } else { + comparee = p.Clone().(*secp256k1Point) + } + require.True(t, comparee.Equal(q), "1*p=p? %v * %v ≠ %v", one, + comparee, q) + q.Mul(multiplier, p) + negMultiplier := newScalar(bigZero).Neg(multiplier) + r := newPoint().Mul(negMultiplier, p) + s := newPoint().Add(q, r) + require.True(t, s.Equal(zero), "s*p+(-s)*p=0? got "+ + "%v*%v + %v*%v = %v + %v = %v ≠ %v", multiplier, p, + ) + } +} + +func TestPoint_Marshal(t *testing.T) { + p := newPoint() + for range numPointSamples { + p.Pick(randomStreamPoint) + serialized, err := p.MarshalBinary() + require.NoError(t, err) + q := newPoint() + err = q.UnmarshalBinary(serialized) + require.NoError(t, err) + require.True(t, p.Equal(q), "%v marshalled to %x, which "+ + "unmarshalled to %v", p, serialized, q) + } + p.X.SetInt(big.NewInt(0)) // 0³+7 is not a square in the base field. + _, err := p.MarshalBinary() + require.Error(t, err) + require.Contains(t, err.Error(), "not a square") + p.X.SetInt(big.NewInt(1)) + _, err = p.MarshalBinary() + require.Error(t, err) + require.Contains(t, err.Error(), "not a point on the curve") + id := p.MarshalID() + require.Equal(t, "sp256.po", string(id[:])) + data := make([]byte, 34) + err = p.UnmarshalBinary(data) + require.Error(t, err) + require.Contains(t, err.Error(), "wrong length for marshaled point") + require.Contains(t, p.UnmarshalBinary(data[:32]).Error(), + "wrong length for marshaled point") + data[32] = 2 + require.Contains(t, p.UnmarshalBinary(data[:33]).Error(), + "bad sign byte") + data[32] = 0 + data[31] = 5 // I.e., x-ordinate is now 5 + require.Contains(t, p.UnmarshalBinary(data[:33]).Error(), + "does not correspond to a curve point") +} + +func TestPoint_BaseTakesCopy(t *testing.T) { + p := newPoint().Base() + p.Add(p, p) + q := newPoint().Base() + assert.False(t, p.Equal(q), + "modifying output from Base changes S256.G{x,y}") +} + +func TestPoint_EthereumAddress(t *testing.T) { + // Example taken from + // https://theethereum.wiki/w/index.php/Accounts,_Addresses,_Public_And_Private_Keys,_And_Tokens + pString := "3a1076bf45ab87712ad64ccb3b10217737f7faacbf2872e88fdd9a537d8fe266" + pInt, ok := big.NewInt(0).SetString(pString, 16) + require.True(t, ok, "failed to parse private key") + private := newScalar(pInt) + public := newPoint().Mul(private, nil) + address := EthereumAddress(public) + assert.Equal(t, "c2d7cf95645d33006175b78989035c7c9061d3f9", hex.EncodeToString(address[:])) +} + +func TestIsSecp256k1Point(t *testing.T) { + p := curve25519.NewBlakeSHA256Curve25519(false).Point() + require.False(t, IsSecp256k1Point(p)) + require.True(t, IsSecp256k1Point(newPoint())) +} + +func TestCoordinates(t *testing.T) { + x, y := Coordinates(newPoint()) + require.Equal(t, x, bigZero) + require.Equal(t, y, bigZero) +} + +func TestValidPublicKey(t *testing.T) { + require.False(t, ValidPublicKey(newPoint()), "zero is not a valid key") + require.True(t, ValidPublicKey(newPoint().Base())) +} + +func TestGenerate(t *testing.T) { + for !ValidPublicKey(Generate(randomStreamPoint).Public) { + + } +} diff --git a/keystore/corekeys/vrfkey/secp256k1/public_key.go b/keystore/corekeys/vrfkey/secp256k1/public_key.go new file mode 100644 index 0000000000..bfd8fb0e31 --- /dev/null +++ b/keystore/corekeys/vrfkey/secp256k1/public_key.go @@ -0,0 +1,150 @@ +package secp256k1 + +import ( + "database/sql/driver" + "fmt" + + "github.com/pkg/errors" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/hexutil" + "go.dedis.ch/kyber/v3" + + "github.com/smartcontractkit/chainlink-evm/pkg/utils" +) + +// PublicKey is a secp256k1 point in compressed format +type PublicKey [CompressedPublicKeyLength]byte + +// CompressedPublicKeyLength is the length of a secp256k1 public key's x +// coordinate as a uint256, concatenated with 00 if y is even, 01 if odd. +const CompressedPublicKeyLength = 33 + +func init() { + if CompressedPublicKeyLength != (&Secp256k1{}).Point().MarshalSize() { + panic("disparity in expected public key lengths") + } +} + +// Set sets k to the public key represented by l +func (k *PublicKey) Set(l PublicKey) { + if copy(k[:], l[:]) != CompressedPublicKeyLength { + panic(fmt.Errorf("failed to copy entire public key %x to %x", l, k)) + } +} + +// Point returns the secp256k1 point corresponding to k +func (k *PublicKey) Point() (kyber.Point, error) { + p := (&Secp256k1{}).Point() + return p, p.UnmarshalBinary(k[:]) +} + +// NewPublicKeyFromHex returns the PublicKey encoded by 0x-hex string hex, or errors +func NewPublicKeyFromHex(hex string) (PublicKey, error) { + rawKey, err := hexutil.Decode(hex) + if err != nil { + return PublicKey{}, err + } + return NewPublicKeyFromBytes(rawKey) +} + +// NewPublicKeyFromBytes returns the PublicKey built from the given bytes, or errors +func NewPublicKeyFromBytes(rawKey []byte) (PublicKey, error) { + if l := len(rawKey); l != CompressedPublicKeyLength { + return PublicKey{}, fmt.Errorf( + "wrong length for public key: %s of length %d", rawKey, l) + } + var k PublicKey + if c := copy(k[:], rawKey); c != CompressedPublicKeyLength { + panic(errors.New("failed to copy entire key to return value")) + } + return k, nil +} + +// SetFromHex sets k to the public key represented by hex, which must represent +// the compressed binary format +func (k *PublicKey) SetFromHex(hex string) error { + nk, err := NewPublicKeyFromHex(hex) + if err != nil { + return err + } + k.Set(nk) + return nil +} + +// String returns k's binary compressed representation, as 0x-hex +func (k PublicKey) String() string { + return hexutil.Encode(k[:]) +} + +// StringUncompressed returns k's binary uncompressed representation, as 0x-hex +func (k *PublicKey) StringUncompressed() (string, error) { + p, err := k.Point() + if err != nil { + return "", err + } + return hexutil.Encode(LongMarshal(p)), nil +} + +// Hash returns the solidity Keccak256 hash of k. Corresponds to hashOfKey on +// VRFCoordinator. +func (k *PublicKey) Hash() (common.Hash, error) { + p, err := k.Point() + if err != nil { + return common.Hash{}, err + } + return utils.MustHash(string(LongMarshal(p))), nil +} + +// MustHash is like Hash, but panics on error. Useful for testing. +func (k *PublicKey) MustHash() common.Hash { + hash, err := k.Hash() + if err != nil { + panic(fmt.Sprintf("Failed to compute hash of public vrf key %v", k)) + } + return hash +} + +// Address returns the Ethereum address of k or 0 if the key is invalid +func (k *PublicKey) Address() common.Address { + hash, err := k.Hash() + if err != nil { + return common.Address{} + } + return common.BytesToAddress(hash.Bytes()[12:]) +} + +// IsZero returns true iff k is the zero value for PublicKey +func (k *PublicKey) IsZero() bool { + return *k == PublicKey{} +} + +// MarshalText renders k as a text string +func (k PublicKey) MarshalText() ([]byte, error) { + return []byte(k.String()), nil +} + +// UnmarshalText reads a PublicKey into k from text, or errors +func (k *PublicKey) UnmarshalText(text []byte) error { + if err := k.SetFromHex(string(text)); err != nil { + return errors.Wrapf(err, "while parsing %s as public key", text) + } + return nil +} + +// Value marshals PublicKey to be saved in the DB +func (k PublicKey) Value() (driver.Value, error) { + return k.String(), nil +} + +// Scan reconstructs a PublicKey from a DB record of it. +func (k *PublicKey) Scan(value any) error { + rawKey, ok := value.(string) + if !ok { + return errors.Wrap(fmt.Errorf("unable to convert %+v of type %T to PublicKey", value, value), "scan failure") + } + if err := k.SetFromHex(rawKey); err != nil { + return errors.Wrapf(err, "while scanning %s as PublicKey", rawKey) + } + return nil +} diff --git a/keystore/corekeys/vrfkey/secp256k1/public_key_test.go b/keystore/corekeys/vrfkey/secp256k1/public_key_test.go new file mode 100644 index 0000000000..428aba2e7a --- /dev/null +++ b/keystore/corekeys/vrfkey/secp256k1/public_key_test.go @@ -0,0 +1,40 @@ +package secp256k1 + +import ( + "testing" + + "github.com/smartcontractkit/chainlink/v2/core/services/signatures/cryptotest" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestValueScanIdentityPointSet(t *testing.T) { + randomStream := cryptotest.NewStream(t, 0) + for range 10 { + p := NewBlakeKeccackSecp256k1().Point().Pick(randomStream) + var pk, nPk, nnPk PublicKey + marshaledKey, err := p.MarshalBinary() + require.NoError(t, err, "failed to marshal public key") + require.Equal(t, CompressedPublicKeyLength, copy(pk[:], marshaledKey), "failed to copy marshaled key to pk") + assert.NotEqual(t, pk, nPk, "equality test succeeds on different keys!") + np, err := pk.Point() + require.NoError(t, err, "failed to marshal public key") + assert.True(t, p.Equal(np), "Point should give the point we constructed pk from") + value, err := pk.Value() + require.NoError(t, err, "failed to serialize public key for database") + require.NoError(t, nPk.Scan(value)) + assert.Equal(t, pk, nPk, + "roundtripping public key through db Value/Scan gave different key!") + nnPk.Set(pk) + assert.Equal(t, pk, nnPk, + "setting one PubliKey to another should result in equal keys") + } +} + +// Tests that PublicKey.Hash gives the same result as the VRFCoordinator's +func TestHash(t *testing.T) { + pk, err := NewPublicKeyFromHex("0x9dc09a0f898f3b5e8047204e7ce7e44b587920932f08431e29c9bf6923b8450a01") + assert.NoError(t, err) + assert.Equal(t, "0xc4406d555db624837188b91514a5f47e34d825d935ab887a35c06a3e7c41de69", pk.MustHash().String()) +} diff --git a/keystore/corekeys/vrfkey/secp256k1/scalar.go b/keystore/corekeys/vrfkey/secp256k1/scalar.go new file mode 100644 index 0000000000..d1d63ddcd1 --- /dev/null +++ b/keystore/corekeys/vrfkey/secp256k1/scalar.go @@ -0,0 +1,232 @@ +// Package secp256k1 is an implementation of the kyber.{Group,Point,Scalcar} +// ////////////////////////////////////////////////////////////////////////////// +// +// XXX: Do not use in production until this code has been audited. +// +// ////////////////////////////////////////////////////////////////////////////// +// interfaces, based on btcd/btcec and kyber/group/mod +// +// XXX: NOT CONSTANT TIME! +package secp256k1 + +// Implementation of kyber.Scalar interface for arithmetic operations mod the +// order of the secpk256k1 group (i.e. hex value +// 0xfffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141.) + +import ( + "crypto/cipher" + "errors" + "fmt" + "io" + "math/big" + + secp256k1BTCD "github.com/btcsuite/btcd/btcec/v2" + "github.com/ethereum/go-ethereum/common" + + "go.dedis.ch/kyber/v3" + "go.dedis.ch/kyber/v3/util/random" +) + +var GroupOrder = secp256k1BTCD.S256().N +var FieldSize = secp256k1BTCD.S256().P + +type secp256k1Scalar big.Int + +// AllowVarTime, if passed true indicates that variable-time operations may be +// used on s. +func (s *secp256k1Scalar) AllowVarTime(varTimeAllowed bool) { + // Since constant-time operations are unimplemented for secp256k1, a + // value of false panics. + if !varTimeAllowed { + panic("implementation is not constant-time!") + } +} + +// newScalar returns a secpk256k1 scalar, with value v modulo GroupOrder. +func newScalar(v *big.Int) kyber.Scalar { + return (*secp256k1Scalar)(zero().Mod(v, GroupOrder)) +} + +func zero() *big.Int { return big.NewInt(0) } + +func ToInt(s kyber.Scalar) *big.Int { return (*big.Int)(s.(*secp256k1Scalar)) } + +func (s *secp256k1Scalar) int() *big.Int { return (*big.Int)(s) } + +func (s *secp256k1Scalar) modG() kyber.Scalar { + // TODO(alx): Make this faster + s.int().Mod(s.int(), GroupOrder) + return s +} + +func (s *secp256k1Scalar) String() string { + return fmt.Sprintf("scalar{%x}", (*big.Int)(s)) +} + +var scalarZero = zero() + +// Equal returns true if s and sPrime represent the same value modulo the group +// order, false otherwise +func (s *secp256k1Scalar) Equal(sPrime kyber.Scalar) bool { + difference := zero().Sub(s.int(), ToInt(sPrime)) + return scalarZero.Cmp(difference.Mod(difference, GroupOrder)) == 0 +} + +// Set copies sPrime's value (modulo GroupOrder) to s, and returns it +func (s *secp256k1Scalar) Set(sPrime kyber.Scalar) kyber.Scalar { + return (*secp256k1Scalar)(s.int().Mod(ToInt(sPrime), GroupOrder)) +} + +// Clone returns a copy of s mod GroupOrder +func (s *secp256k1Scalar) Clone() kyber.Scalar { + return (*secp256k1Scalar)(zero().Mod(s.int(), GroupOrder)) +} + +// SetInt64 returns s with value set to v modulo GroupOrder +func (s *secp256k1Scalar) SetInt64(v int64) kyber.Scalar { + return (*secp256k1Scalar)(s.int().SetInt64(v)).modG() +} + +// Zero sets s to 0 mod GroupOrder, and returns it +func (s *secp256k1Scalar) Zero() kyber.Scalar { + return s.SetInt64(0) +} + +// Add sets s to a+b mod GroupOrder, and returns it +func (s *secp256k1Scalar) Add(a, b kyber.Scalar) kyber.Scalar { + s.int().Add(ToInt(a), ToInt(b)) + return s.modG() +} + +// Sub sets s to a-b mod GroupOrder, and returns it +func (s *secp256k1Scalar) Sub(a, b kyber.Scalar) kyber.Scalar { + s.int().Sub(ToInt(a), ToInt(b)) + return s.modG() +} + +// Neg sets s to -a mod GroupOrder, and returns it +func (s *secp256k1Scalar) Neg(a kyber.Scalar) kyber.Scalar { + s.int().Neg(ToInt(a)) + return s.modG() +} + +// One sets s to 1 mod GroupOrder, and returns it +func (s *secp256k1Scalar) One() kyber.Scalar { + return s.SetInt64(1) +} + +// Mul sets s to a*b mod GroupOrder, and returns it +func (s *secp256k1Scalar) Mul(a, b kyber.Scalar) kyber.Scalar { + // TODO(alx): Make this faster + s.int().Mul(ToInt(a), ToInt(b)) + return s.modG() +} + +// Div sets s to a*b⁻¹ mod GroupOrder, and returns it +func (s *secp256k1Scalar) Div(a, b kyber.Scalar) kyber.Scalar { + if ToInt(b).Cmp(scalarZero) == 0 { + panic("attempt to divide by zero") + } + // TODO(alx): Make this faster + s.int().Mul(ToInt(a), zero().ModInverse(ToInt(b), GroupOrder)) + return s.modG() +} + +// Inv sets s to s⁻¹ mod GroupOrder, and returns it +func (s *secp256k1Scalar) Inv(a kyber.Scalar) kyber.Scalar { + if ToInt(a).Cmp(scalarZero) == 0 { + panic("attempt to divide by zero") + } + s.int().ModInverse(ToInt(a), GroupOrder) + return s +} + +// Pick sets s to a random value mod GroupOrder sampled from rand, and returns +// it +func (s *secp256k1Scalar) Pick(rand cipher.Stream) kyber.Scalar { + return s.Set((*secp256k1Scalar)(random.Int(GroupOrder, rand))) +} + +// MarshalBinary returns the big-endian byte representation of s, or an error on +// failure +func (s *secp256k1Scalar) MarshalBinary() ([]byte, error) { + b := ToInt(s.modG()).Bytes() + // leftpad with zeros + rv := append(make([]byte, s.MarshalSize()-len(b)), b...) + if len(rv) != s.MarshalSize() { + return nil, errors.New("marshalled scalar to wrong length") + } + return rv, nil +} + +// MarshalSize returns the length of the byte representation of s +func (s *secp256k1Scalar) MarshalSize() int { return 32 } + +// MarshalID returns the ID for a secp256k1 scalar +func (s *secp256k1Scalar) MarshalID() [8]byte { + return [8]byte{'s', 'p', '2', '5', '6', '.', 's', 'c'} +} + +// UnmarshalBinary sets s to the scalar represented by the contents of buf, +// returning error on failure. +func (s *secp256k1Scalar) UnmarshalBinary(buf []byte) error { + if len(buf) != s.MarshalSize() { + return errors.New("cannot unmarshal to scalar: wrong length") + } + s.int().Mod(s.int().SetBytes(buf), GroupOrder) + return nil +} + +// MarshalTo writes the serialized s to w, and returns the number of bytes +// written, or an error on failure. +func (s *secp256k1Scalar) MarshalTo(w io.Writer) (int, error) { + buf, err := s.MarshalBinary() + if err != nil { + return 0, fmt.Errorf("cannot marshal binary: %w", err) + } + return w.Write(buf) +} + +// UnmarshalFrom sets s to the scalar represented by bytes read from r, and +// returns the number of bytes read, or an error on failure. +func (s *secp256k1Scalar) UnmarshalFrom(r io.Reader) (int, error) { + buf := make([]byte, s.MarshalSize()) + n, err := io.ReadFull(r, buf) + if err != nil { + return n, err + } + return n, s.UnmarshalBinary(buf) +} + +// SetBytes sets s to the number with big-endian representation a mod +// GroupOrder, and returns it +func (s *secp256k1Scalar) SetBytes(a []byte) kyber.Scalar { + return ((*secp256k1Scalar)(s.int().SetBytes(a))).modG() +} + +// IsSecp256k1Scalar returns true if p is a secp256k1Scalar +func IsSecp256k1Scalar(s kyber.Scalar) bool { + switch s := s.(type) { + case *secp256k1Scalar: + s.modG() + return true + default: + return false + } +} + +// IntToScalar returns i wrapped as a big.Int. +// +// May modify i to reduce mod GroupOrder +func IntToScalar(i *big.Int) kyber.Scalar { + return ((*secp256k1Scalar)(i)).modG() +} + +func ScalarToHash(s kyber.Scalar) common.Hash { + return common.BigToHash(ToInt(s.(*secp256k1Scalar))) +} + +// RepresentsScalar returns true iff i is in the right range to be a scalar +func RepresentsScalar(i *big.Int) bool { + return i.Cmp(GroupOrder) == -1 +} diff --git a/keystore/corekeys/vrfkey/secp256k1/scalar_test.go b/keystore/corekeys/vrfkey/secp256k1/scalar_test.go new file mode 100644 index 0000000000..266db37026 --- /dev/null +++ b/keystore/corekeys/vrfkey/secp256k1/scalar_test.go @@ -0,0 +1,189 @@ +package secp256k1 + +import ( + "bytes" + "encoding/hex" + "math/big" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + "go.dedis.ch/kyber/v3" + "go.dedis.ch/kyber/v3/group/curve25519" + + "github.com/smartcontractkit/chainlink/v2/core/services/signatures/cryptotest" +) + +var numScalarSamples = 10 + +var observedScalars map[string]bool + +func init() { + observedScalars = make(map[string]bool) +} + +// observedScalar ensures that novel scalars are being picked. +func observedScalar(t *testing.T, s kyber.Scalar) { + data, err := s.(*secp256k1Scalar).modG().MarshalBinary() + require.NoError(t, err) + scalar := hex.Dump(data) + require.False(t, observedScalars[scalar]) + observedScalars[scalar] = true +} + +var randomStreamScalar = cryptotest.NewStream(&testing.T{}, 0) + +func TestScalar_SetAndEqual(t *testing.T) { + tests := []int64{5, 67108864, 67108865, 4294967295} + g := newScalar(scalarZero) + for _, test := range tests { + f := newScalar(big.NewInt(test)) + g.Set(f) + assert.Equal(t, f, g, + "the method Set should give the same value to receiver") + f.Add(f, newScalar(big.NewInt(1))) + assert.NotEqual(t, f, g, + "SetInt should take a copy of the backing big.Int") + } +} + +func TestNewScalar(t *testing.T) { + one := newScalar(big.NewInt(1)) + assert.Equal(t, ToInt(one), + ToInt(newScalar(big.NewInt(0).Add(ToInt(one), GroupOrder))), + "equivalence classes mod GroupOrder not equal") +} + +func TestScalar_SmokeTestPick(t *testing.T) { + f := newScalar(scalarZero).Clone() + for range numScalarSamples { + f.Pick(randomStreamScalar) + observedScalar(t, f) + require.Equal(t, 1, ToInt(f).Cmp(big.NewInt(1000000000)), + "implausibly low value returned from Pick: %v", f) + } +} + +func TestScalar_Neg(t *testing.T) { + f := newScalar(scalarZero).Clone() + for range numScalarSamples { + f.Pick(randomStreamScalar) + observedScalar(t, f) + g := f.Clone() + g.Neg(g) + require.True(t, g.Add(f, g).Equal(newScalar(scalarZero))) + } +} + +func TestScalar_Sub(t *testing.T) { + f := newScalar(scalarZero).Clone() + for range numScalarSamples { + f.Pick(randomStreamScalar) + observedScalar(t, f) + require.True(t, f.Sub(f, f).Equal(newScalar(scalarZero)), + "subtracting something from itself should give zero") + } +} + +func TestScalar_Clone(t *testing.T) { + f := newScalar(big.NewInt(1)) + g := f.Clone() + h := f.Clone() + assert.Equal(t, f, g, "clone output does not equal input") + g.Add(f, f) + assert.Equal(t, f, h, "clone does not make a copy") +} + +func TestScalar_Marshal(t *testing.T) { + f := newScalar(scalarZero) + g := newScalar(scalarZero) + for range numFieldSamples { + f.Pick(randomStreamScalar) + observedScalar(t, f) + data, err := f.MarshalBinary() + require.NoError(t, err) + err = g.UnmarshalBinary(data) + require.NoError(t, err) + require.True(t, g.Equal(f), + "roundtrip through serialization should give same "+ + "result back: failed with %s", f) + } + marshalID := f.(*secp256k1Scalar).MarshalID() + require.Equal(t, "sp256.sc", string(marshalID[:])) + data := make([]byte, 33) + require.Contains(t, f.UnmarshalBinary(data).Error(), "wrong length") + var buf bytes.Buffer + _, err := f.MarshalTo(&buf) + require.NoError(t, err) + _, err = f.UnmarshalFrom(&buf) + require.NoError(t, err) +} + +func TestScalar_MulDivInv(t *testing.T) { + f := newScalar(scalarZero) + g := newScalar(scalarZero) + h := newScalar(scalarZero) + j := newScalar(scalarZero) + k := newScalar(scalarZero) + for range numFieldSamples { + f.Pick(randomStreamScalar) + observedScalar(t, f) + g.Inv(f) + h.Mul(f, g) + require.True(t, h.Equal(newScalar(big.NewInt(1)))) + h.Div(f, f) + require.True(t, h.Equal(newScalar(big.NewInt(1)))) + h.Div(newScalar(big.NewInt(1)), f) + require.True(t, h.Equal(g)) + h.Pick(randomStreamScalar) + observedScalar(t, h) + j.Neg(j.Mul(h, f)) + k.Mul(h, k.Neg(f)) + require.True(t, j.Equal(k), "-(h*f) != h*(-f)") + } +} + +func TestScalar_AllowVarTime(t *testing.T) { + defer func() { require.Contains(t, recover(), "not constant-time!") }() + newScalar(bigZero).(*secp256k1Scalar).AllowVarTime(false) +} + +func TestScalar_String(t *testing.T) { + require.Equal(t, "scalar{0}", newScalar(bigZero).String()) +} + +func TestScalar_SetInt64(t *testing.T) { + require.Equal(t, newScalar(bigZero).SetInt64(1), newScalar(big.NewInt(1))) + require.True(t, newScalar(big.NewInt(1)).Zero().Equal(newScalar(bigZero))) + require.Equal(t, newScalar(bigZero).One(), newScalar(big.NewInt(1))) +} + +func TestScalar_DivPanicsOnZeroDivisor(t *testing.T) { + defer func() { require.Contains(t, recover(), "divide by zero") }() + newScalar(bigZero).Div(newScalar(bigZero).One(), newScalar(bigZero)) +} + +func TestScalar_InvPanicsOnZero(t *testing.T) { + defer func() { require.Contains(t, recover(), "divide by zero") }() + newScalar(bigZero).Inv(newScalar(bigZero)) +} + +func TestScalar_SetBytes(t *testing.T) { + u256Cardinality := zero().Lsh(big.NewInt(1), 256) + newScalar(bigZero).(*secp256k1Scalar).int().Cmp( + zero().Sub(u256Cardinality, GroupOrder)) +} + +func TestScalar_IsSecp256k1Scalar(t *testing.T) { + c := curve25519.NewBlakeSHA256Curve25519(true) + require.False(t, IsSecp256k1Scalar(c.Scalar())) + require.True(t, IsSecp256k1Scalar(newScalar(bigZero))) +} + +func TestScalar_IntToScalar(t *testing.T) { + u256Cardinality := zero().Lsh(big.NewInt(1), 256) + IntToScalar(u256Cardinality) + require.Equal(t, u256Cardinality, zero().Sub(zero().Lsh(big.NewInt(1), 256), + GroupOrder)) +} diff --git a/keystore/corekeys/vrfkey/secp256k1/suite.go b/keystore/corekeys/vrfkey/secp256k1/suite.go new file mode 100644 index 0000000000..9141f881a0 --- /dev/null +++ b/keystore/corekeys/vrfkey/secp256k1/suite.go @@ -0,0 +1,91 @@ +// Package secp256k1 is an implementation of the kyber.{Group,Point,Scalar} +// ////////////////////////////////////////////////////////////////////////////// +// +// XXX: Do not use in production until this code has been audited. +// +// ////////////////////////////////////////////////////////////////////////////// +// interfaces, based on btcd/btcec and kyber/group/mod +// +// XXX: NOT CONSTANT TIME! +package secp256k1 + +import ( + "crypto/cipher" + "hash" + "io" + "reflect" + + "golang.org/x/crypto/sha3" + + "go.dedis.ch/fixbuf" + "go.dedis.ch/kyber/v3" + "go.dedis.ch/kyber/v3/util/random" + "go.dedis.ch/kyber/v3/xof/blake2xb" +) + +// SuiteSecp256k1 implements some basic functionalities such as Group, HashFactory, +// and XOFFactory. +type SuiteSecp256k1 struct { + Secp256k1 + r cipher.Stream +} + +// Hash returns a newly instantiated keccak hash function. +func (s *SuiteSecp256k1) Hash() hash.Hash { + return sha3.NewLegacyKeccak256() +} + +// XOF returns an XOR function, implemented via the Blake2b hash. +// +// This should only be used for generating secrets, so there is no need to make +// it cheap to compute on-chain. +func (s *SuiteSecp256k1) XOF(key []byte) kyber.XOF { + return blake2xb.New(key) +} + +// Read implements the Encoding interface function, and reads a series of objs from r +// The objs must all be pointers +func (s *SuiteSecp256k1) Read(r io.Reader, objs ...any) error { + return fixbuf.Read(r, s, objs...) +} + +// Write implements the Encoding interface, and writes the objs to r using their +// built-in binary serializations. Supports Points, Scalars, fixed-length data +// types supported by encoding/binary/Write(), and structs, arrays, and slices +// containing these types. +func (s *SuiteSecp256k1) Write(w io.Writer, objs ...any) error { + return fixbuf.Write(w, objs) +} + +var aScalar kyber.Scalar +var tScalar = reflect.TypeOf(aScalar) +var aPoint kyber.Point +var tPoint = reflect.TypeOf(aPoint) + +// New implements the kyber.Encoding interface, and returns a new element of +// type t, which can be a Point or a Scalar +func (s *SuiteSecp256k1) New(t reflect.Type) any { + switch t { + case tScalar: + return s.Scalar() + case tPoint: + return s.Point() + } + return nil +} + +// RandomStream returns a cipher.Stream that returns a key stream +// from crypto/rand. +func (s *SuiteSecp256k1) RandomStream() cipher.Stream { + if s.r != nil { + return s.r + } + return random.New() +} + +// NewBlakeKeccackSecp256k1 returns a cipher suite based on package +// go.dedis.ch/kyber/xof/blake2xb, SHA-256, and the secp256k1 curve. It +// produces cryptographically secure random numbers via package crypto/rand. +func NewBlakeKeccackSecp256k1() *SuiteSecp256k1 { + return new(SuiteSecp256k1) +} diff --git a/keystore/corekeys/vrfkey/secp256k1/suite_test.go b/keystore/corekeys/vrfkey/secp256k1/suite_test.go new file mode 100644 index 0000000000..f9c48999d1 --- /dev/null +++ b/keystore/corekeys/vrfkey/secp256k1/suite_test.go @@ -0,0 +1,15 @@ +package secp256k1 + +import ( + "encoding/hex" + "testing" + + "github.com/stretchr/testify/require" +) + +func TestSuite(t *testing.T) { + s := NewBlakeKeccackSecp256k1() + emptyHashAsHex := hex.EncodeToString(s.Hash().Sum(nil)) + require.Equal(t, "c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", emptyHashAsHex) + _ = s.RandomStream() +} diff --git a/keystore/go.mod b/keystore/go.mod index c75e2f4ef7..728ae803b2 100644 --- a/keystore/go.mod +++ b/keystore/go.mod @@ -4,7 +4,7 @@ go 1.25.5 replace github.com/smartcontractkit/chainlink-common => ../ -require github.com/smartcontractkit/chainlink-common v0.9.6-0.20260107095648-223976d2b9f1 +require github.com/smartcontractkit/chainlink-common v0.9.6-0.20260119150426-31ad843060e6 require ( github.com/NethermindEth/juno v0.12.5 @@ -12,6 +12,7 @@ require ( github.com/aws/aws-sdk-go-v2 v1.41.1 github.com/aws/aws-sdk-go-v2/config v1.28.4 github.com/aws/aws-sdk-go-v2/service/kms v1.49.5 + github.com/btcsuite/btcd/btcec/v2 v2.3.5 github.com/cosmos/cosmos-sdk v0.53.5 github.com/ethereum/go-ethereum v1.16.8 github.com/gagliardetto/solana-go v1.14.0 @@ -21,7 +22,7 @@ require ( github.com/lib/pq v1.10.9 github.com/mr-tron/base58 v1.2.0 github.com/pkg/errors v0.9.1 - github.com/smartcontractkit/chainlink-evm v0.3.4-0.20251210110629-10c56e8d2cec + github.com/smartcontractkit/chainlink-evm v0.3.4-0.20260205183656-836ec9472717 github.com/smartcontractkit/chainlink/v2 v2.32.0 github.com/smartcontractkit/libocr v0.0.0-20251212213002-0a5e2f907dda github.com/smartcontractkit/smdkg v0.0.0-20251029093710-c38905e58aeb @@ -29,6 +30,7 @@ require ( github.com/spf13/cobra v1.10.1 github.com/stretchr/testify v1.11.1 github.com/xssnick/tonutils-go v1.14.1 + go.dedis.ch/fixbuf v1.0.3 go.dedis.ch/kyber/v3 v3.1.0 golang.org/x/crypto v0.47.0 google.golang.org/protobuf v1.36.11 @@ -71,7 +73,6 @@ require ( github.com/bgentry/speakeasy v0.2.0 // indirect github.com/bits-and-blooms/bitset v1.24.3 // indirect github.com/blendle/zapdriver v1.3.1 // indirect - github.com/btcsuite/btcd/btcec/v2 v2.3.5 // indirect github.com/buger/jsonparser v1.1.1 // indirect github.com/bytedance/gopkg v0.1.3 // indirect github.com/bytedance/sonic v1.14.2 // indirect @@ -200,9 +201,7 @@ require ( github.com/mtibben/percent v0.2.1 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect github.com/oasisprotocol/curve25519-voi v0.0.0-20230904125328-1f23a7beb09a // indirect - github.com/olekukonko/errors v1.1.0 // indirect - github.com/olekukonko/ll v0.0.9 // indirect - github.com/olekukonko/tablewriter v1.0.9 // indirect + github.com/olekukonko/tablewriter v0.0.5 // indirect github.com/pelletier/go-toml/v2 v2.2.4 // indirect github.com/petermattis/goid v0.0.0-20240813172612-4fcff4a6cae7 // indirect github.com/pierrec/lz4/v4 v4.1.22 // indirect @@ -261,7 +260,6 @@ require ( github.com/zondax/golem v0.27.0 // indirect github.com/zondax/hid v0.9.2 // indirect github.com/zondax/ledger-go v1.0.1 // indirect - go.dedis.ch/fixbuf v1.0.3 // indirect go.etcd.io/bbolt v1.4.2 // indirect go.mongodb.org/mongo-driver v1.17.2 // indirect go.opentelemetry.io/auto/sdk v1.2.1 // indirect diff --git a/keystore/go.sum b/keystore/go.sum index 648ff41610..a87b4ff95b 100644 --- a/keystore/go.sum +++ b/keystore/go.sum @@ -681,6 +681,7 @@ github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/ github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= 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-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc= github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= github.com/mattn/go-sqlite3 v1.14.22/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y= @@ -738,12 +739,8 @@ github.com/oasisprotocol/curve25519-voi v0.0.0-20230904125328-1f23a7beb09a h1:dl github.com/oasisprotocol/curve25519-voi v0.0.0-20230904125328-1f23a7beb09a/go.mod h1:hVoHR2EVESiICEMbg137etN/Lx+lSrHPTD39Z/uE+2s= github.com/oklog/run v1.2.0 h1:O8x3yXwah4A73hJdlrwo/2X6J62gE5qTMusH0dvz60E= github.com/oklog/run v1.2.0/go.mod h1:mgDbKRSwPhJfesJ4PntqFUbKQRZ50NgmZTSPlFA0YFk= -github.com/olekukonko/errors v1.1.0 h1:RNuGIh15QdDenh+hNvKrJkmxxjV4hcS50Db478Ou5sM= -github.com/olekukonko/errors v1.1.0/go.mod h1:ppzxA5jBKcO1vIpCXQ9ZqgDh8iwODz6OXIGKU8r5m4Y= -github.com/olekukonko/ll v0.0.9 h1:Y+1YqDfVkqMWuEQMclsF9HUR5+a82+dxJuL1HHSRpxI= -github.com/olekukonko/ll v0.0.9/go.mod h1:En+sEW0JNETl26+K8eZ6/W4UQ7CYSrrgg/EdIYT2H8g= -github.com/olekukonko/tablewriter v1.0.9 h1:XGwRsYLC2bY7bNd93Dk51bcPZksWZmLYuaTHR0FqfL8= -github.com/olekukonko/tablewriter v1.0.9/go.mod h1:5c+EBPeSqvXnLLgkm9isDdzR3wjfBkHR9Nhfp3NWrzo= +github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec= +github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0= @@ -908,8 +905,8 @@ github.com/smartcontractkit/chainlink-common/pkg/chipingress v0.0.10 h1:FJAFgXS9 github.com/smartcontractkit/chainlink-common/pkg/chipingress v0.0.10/go.mod h1:oiDa54M0FwxevWwyAX773lwdWvFYYlYHHQV1LQ5HpWY= github.com/smartcontractkit/chainlink-data-streams v0.1.10 h1:YCwQNCcxFuoR714NV5UJ8oNwG/1j2PETUfZFssonTT8= github.com/smartcontractkit/chainlink-data-streams v0.1.10/go.mod h1:8rUcGhjeXBoTFx2MynWgXiBWzVSB+LXd9JR6m8y2FfQ= -github.com/smartcontractkit/chainlink-evm v0.3.4-0.20251210110629-10c56e8d2cec h1:K8sLjgwPgozQb86LH+aWXqBUJak6VGwSt5YiKbCI/uY= -github.com/smartcontractkit/chainlink-evm v0.3.4-0.20251210110629-10c56e8d2cec/go.mod h1:9VcrUs+H/f9ekkqAdfUd70Pk2dA1Zc3KykJVFBfJNHs= +github.com/smartcontractkit/chainlink-evm v0.3.4-0.20260205183656-836ec9472717 h1:OiR/E3lq1jMlA6B9mqhom0f2JeNJOCIxbbyktBlR+Fg= +github.com/smartcontractkit/chainlink-evm v0.3.4-0.20260205183656-836ec9472717/go.mod h1:jBZMFIz1C3sq/YyuTgk5MCu12SdHP+PcujdojZsSk6g= github.com/smartcontractkit/chainlink-evm/gethwrappers v0.0.0-20251211123524-f0c4fe7cfc0a h1:kVKWRGrSCioMY2lEVIEblerv/KkINIQS2hLUOw2wKOg= github.com/smartcontractkit/chainlink-evm/gethwrappers v0.0.0-20251211123524-f0c4fe7cfc0a/go.mod h1:oyfOm4k0uqmgZIfxk1elI/59B02shbbJQiiUdPdbMgI= github.com/smartcontractkit/chainlink-feeds v0.1.2-0.20250227211209-7cd000095135 h1:8u9xUrC+yHrTDexOKDd+jrA6LCzFFHeX1G82oj2fsSI= @@ -942,8 +939,8 @@ github.com/smartcontractkit/chainlink-protos/rmn/v1.6/go v0.0.0-20250131130834-1 github.com/smartcontractkit/chainlink-protos/rmn/v1.6/go v0.0.0-20250131130834-15e0d4cde2a6/go.mod h1:FRwzI3hGj4CJclNS733gfcffmqQ62ONCkbGi49s658w= github.com/smartcontractkit/chainlink-protos/storage-service v0.3.0 h1:B7itmjy+CMJ26elVw/cAJqqhBQ3Xa/mBYWK0/rQ5MuI= github.com/smartcontractkit/chainlink-protos/storage-service v0.3.0/go.mod h1:h6kqaGajbNRrezm56zhx03p0mVmmA2xxj7E/M4ytLUA= -github.com/smartcontractkit/chainlink-protos/svr v1.1.0 h1:79Z9N9dMbMVRGaLoDPAQ+vOwbM+Hnx8tIN2xCPG8H4o= -github.com/smartcontractkit/chainlink-protos/svr v1.1.0/go.mod h1:TcOliTQU6r59DwG4lo3U+mFM9WWyBHGuFkkxQpvSujo= +github.com/smartcontractkit/chainlink-protos/svr v1.1.1-0.20260203131522-bb8bc5c423b3 h1:X8Pekpv+cy0eW1laZTwATuYLTLZ6gRTxz1ZWOMtU74o= +github.com/smartcontractkit/chainlink-protos/svr v1.1.1-0.20260203131522-bb8bc5c423b3/go.mod h1:TcOliTQU6r59DwG4lo3U+mFM9WWyBHGuFkkxQpvSujo= github.com/smartcontractkit/chainlink-protos/workflows/go v0.0.0-20260205231316-3b9c600dd791 h1:S+yHuhcny3AKOhCekMQa65uUeR/p9rGrUIb8eifkSTY= github.com/smartcontractkit/chainlink-protos/workflows/go v0.0.0-20260205231316-3b9c600dd791/go.mod h1:GTpDgyK0OObf7jpch6p8N281KxN92wbB8serZhU9yRc= github.com/smartcontractkit/chainlink-solana v1.1.2-0.20251121223352-370eb61346d6 h1:4cvFf82P3VcNHgqUG0aRBeIMZd+wSX37ha28Gkie9Lk= From 298e1ca23552b0a4fb27d84912fd72a38addf208 Mon Sep 17 00:00:00 2001 From: pavel-raykov Date: Tue, 10 Feb 2026 09:32:07 +0100 Subject: [PATCH 03/13] Minor. --- keystore/corekeys/ocr2key/evm_keyring_test.go | 15 ++++++--- .../corekeys/vrfkey/secp256k1/cryptotest.go | 33 +++++++++++++++++++ .../corekeys/vrfkey/secp256k1/field_test.go | 14 ++++---- .../corekeys/vrfkey/secp256k1/point_test.go | 4 --- .../vrfkey/secp256k1/public_key_test.go | 4 +-- .../corekeys/vrfkey/secp256k1/scalar_test.go | 16 ++++----- 6 files changed, 57 insertions(+), 29 deletions(-) create mode 100644 keystore/corekeys/vrfkey/secp256k1/cryptotest.go diff --git a/keystore/corekeys/ocr2key/evm_keyring_test.go b/keystore/corekeys/ocr2key/evm_keyring_test.go index 38df8ac672..aee198ed3a 100644 --- a/keystore/corekeys/ocr2key/evm_keyring_test.go +++ b/keystore/corekeys/ocr2key/evm_keyring_test.go @@ -12,8 +12,6 @@ import ( "github.com/smartcontractkit/libocr/offchainreporting2/types" ocrtypes "github.com/smartcontractkit/libocr/offchainreporting2plus/types" - - "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" ) func TestEVMKeyring_SignVerify(t *testing.T) { @@ -54,10 +52,10 @@ func TestEVMKeyring_Sign3Verify3(t *testing.T) { kr2, err := newEVMKeyring(cryptorand.Reader) require.NoError(t, err) - digest, err := types.BytesToConfigDigest(testutils.MustRandBytes(32)) + digest, err := types.BytesToConfigDigest(mustRandBytes(32)) require.NoError(t, err) seqNr := rand.Uint64() - r := ocrtypes.Report(testutils.MustRandBytes(rand.Intn(1024))) + r := ocrtypes.Report(mustRandBytes(rand.Intn(1024))) t.Run("can verify", func(t *testing.T) { sig, err := kr1.Sign3(digest, seqNr, r) @@ -160,3 +158,12 @@ func TestRawReportContext3(t *testing.T) { }) } } + +func mustRandBytes(n int) (b []byte) { + b = make([]byte, n) + _, err := rand.Read(b) + if err != nil { + panic(err) + } + return +} diff --git a/keystore/corekeys/vrfkey/secp256k1/cryptotest.go b/keystore/corekeys/vrfkey/secp256k1/cryptotest.go new file mode 100644 index 0000000000..5ab7b2a4b1 --- /dev/null +++ b/keystore/corekeys/vrfkey/secp256k1/cryptotest.go @@ -0,0 +1,33 @@ +// Package cryptotest provides convenience functions for kyber-based APIs. +// +// It is separate from cltest to prevent an import cycle. +package secp256k1 + +import ( + "math/rand" + "testing" +) + +// randomStream implements cipher.Stream, but with a deterministic output. +type randomStream rand.Rand + +// NewStream returns a randomStream seeded from seed, for deterministic +// randomness in tests of random outputs, and for small property-based tests. +// +// This API is deliberately awkward to prevent it from being used outside of +// tests. +// +// The testing framework runs the tests in a file in series, unless you +// explicitly request otherwise with testing.T.Parallel(). So one such stream +// per file is enough, most of the time. +func NewStream(t *testing.T, seed int64) *randomStream { + return (*randomStream)(rand.New(rand.NewSource(seed))) +} + +// XORKeyStream dumps the output from a math/rand PRNG on dst. +// +// It gives no consideration for the contents of src, and is named so +// misleadingly purely to satisfy the cipher.Stream interface. +func (s *randomStream) XORKeyStream(dst, src []byte) { + (*rand.Rand)(s).Read(dst) +} diff --git a/keystore/corekeys/vrfkey/secp256k1/field_test.go b/keystore/corekeys/vrfkey/secp256k1/field_test.go index 70c4f15d2f..7ecbb645ad 100644 --- a/keystore/corekeys/vrfkey/secp256k1/field_test.go +++ b/keystore/corekeys/vrfkey/secp256k1/field_test.go @@ -7,8 +7,6 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - - "github.com/smartcontractkit/chainlink/v2/core/services/signatures/cryptotest" ) var numFieldSamples = 10 @@ -27,7 +25,7 @@ func observedFieldElt(t *testing.T, s *fieldElt) { observedFieldElts[data] = true } -var randomStream = cryptotest.NewStream(&testing.T{}, 0) +var randomStreamPoint = NewStream(&testing.T{}, 0) func TestField_SetIntAndEqual(t *testing.T) { tests := []int64{5, 67108864, 67108865, 4294967295} @@ -72,7 +70,7 @@ func TestFieldEltFromInt(t *testing.T) { func TestField_SmokeTestPick(t *testing.T) { f := newFieldZero() - f.Pick(randomStream) + f.Pick(randomStreamPoint) observedFieldElt(t, f) assert.Equal(t, 1, f.int().Cmp(big.NewInt(1000000000)), "should be greater than 1000000000, with very high probability") @@ -81,7 +79,7 @@ func TestField_SmokeTestPick(t *testing.T) { func TestField_Neg(t *testing.T) { f := newFieldZero() for range numFieldSamples { - f.Pick(randomStream) + f.Pick(randomStreamPoint) observedFieldElt(t, f) g := f.Clone() g.Neg(g) @@ -94,7 +92,7 @@ func TestField_Neg(t *testing.T) { func TestField_Sub(t *testing.T) { f := newFieldZero() for range numFieldSamples { - f.Pick(randomStream) + f.Pick(randomStreamPoint) observedFieldElt(t, f) require.True(t, f.Sub(f, f).Equal(fieldZero), "subtracting something from itself should give zero: "+ @@ -115,7 +113,7 @@ func TestField_SetBytesAndBytes(t *testing.T) { f := newFieldZero() g := newFieldZero() for range numFieldSamples { - f.Pick(randomStream) + f.Pick(randomStreamPoint) observedFieldElt(t, f) g.SetBytes(f.Bytes()) require.True(t, g.Equal(f), @@ -129,7 +127,7 @@ func TestField_MaybeSquareRootInField(t *testing.T) { minusOne := fieldEltFromInt(-1) assert.Nil(t, maybeSqrtInField(minusOne), "-1 is not a square, in this field") for range numFieldSamples { - f.Pick(randomStream) + f.Pick(randomStreamPoint) observedFieldElt(t, f) require.Equal(t, -1, f.int().Cmp(q), "picked larger value than q: %s", f) require.NotEqual(t, -1, f.int().Cmp(big.NewInt(-1)), diff --git a/keystore/corekeys/vrfkey/secp256k1/point_test.go b/keystore/corekeys/vrfkey/secp256k1/point_test.go index b415825d0b..4d72dfef05 100644 --- a/keystore/corekeys/vrfkey/secp256k1/point_test.go +++ b/keystore/corekeys/vrfkey/secp256k1/point_test.go @@ -11,14 +11,10 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - - "github.com/smartcontractkit/chainlink/v2/core/services/signatures/cryptotest" ) var numPointSamples = 10 -var randomStreamPoint = cryptotest.NewStream(&testing.T{}, 0) - func TestPoint_String(t *testing.T) { require.Equal(t, "Secp256k1{X: fieldElt{0}, Y: fieldElt{0}}", newPoint().String()) } diff --git a/keystore/corekeys/vrfkey/secp256k1/public_key_test.go b/keystore/corekeys/vrfkey/secp256k1/public_key_test.go index 428aba2e7a..79758918b9 100644 --- a/keystore/corekeys/vrfkey/secp256k1/public_key_test.go +++ b/keystore/corekeys/vrfkey/secp256k1/public_key_test.go @@ -3,14 +3,12 @@ package secp256k1 import ( "testing" - "github.com/smartcontractkit/chainlink/v2/core/services/signatures/cryptotest" - "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) func TestValueScanIdentityPointSet(t *testing.T) { - randomStream := cryptotest.NewStream(t, 0) + randomStream := NewStream(t, 0) for range 10 { p := NewBlakeKeccackSecp256k1().Point().Pick(randomStream) var pk, nPk, nnPk PublicKey diff --git a/keystore/corekeys/vrfkey/secp256k1/scalar_test.go b/keystore/corekeys/vrfkey/secp256k1/scalar_test.go index 266db37026..9399500bda 100644 --- a/keystore/corekeys/vrfkey/secp256k1/scalar_test.go +++ b/keystore/corekeys/vrfkey/secp256k1/scalar_test.go @@ -11,8 +11,6 @@ import ( "go.dedis.ch/kyber/v3" "go.dedis.ch/kyber/v3/group/curve25519" - - "github.com/smartcontractkit/chainlink/v2/core/services/signatures/cryptotest" ) var numScalarSamples = 10 @@ -32,8 +30,6 @@ func observedScalar(t *testing.T, s kyber.Scalar) { observedScalars[scalar] = true } -var randomStreamScalar = cryptotest.NewStream(&testing.T{}, 0) - func TestScalar_SetAndEqual(t *testing.T) { tests := []int64{5, 67108864, 67108865, 4294967295} g := newScalar(scalarZero) @@ -58,7 +54,7 @@ func TestNewScalar(t *testing.T) { func TestScalar_SmokeTestPick(t *testing.T) { f := newScalar(scalarZero).Clone() for range numScalarSamples { - f.Pick(randomStreamScalar) + f.Pick(randomStreamPoint) observedScalar(t, f) require.Equal(t, 1, ToInt(f).Cmp(big.NewInt(1000000000)), "implausibly low value returned from Pick: %v", f) @@ -68,7 +64,7 @@ func TestScalar_SmokeTestPick(t *testing.T) { func TestScalar_Neg(t *testing.T) { f := newScalar(scalarZero).Clone() for range numScalarSamples { - f.Pick(randomStreamScalar) + f.Pick(randomStreamPoint) observedScalar(t, f) g := f.Clone() g.Neg(g) @@ -79,7 +75,7 @@ func TestScalar_Neg(t *testing.T) { func TestScalar_Sub(t *testing.T) { f := newScalar(scalarZero).Clone() for range numScalarSamples { - f.Pick(randomStreamScalar) + f.Pick(randomStreamPoint) observedScalar(t, f) require.True(t, f.Sub(f, f).Equal(newScalar(scalarZero)), "subtracting something from itself should give zero") @@ -99,7 +95,7 @@ func TestScalar_Marshal(t *testing.T) { f := newScalar(scalarZero) g := newScalar(scalarZero) for range numFieldSamples { - f.Pick(randomStreamScalar) + f.Pick(randomStreamPoint) observedScalar(t, f) data, err := f.MarshalBinary() require.NoError(t, err) @@ -127,7 +123,7 @@ func TestScalar_MulDivInv(t *testing.T) { j := newScalar(scalarZero) k := newScalar(scalarZero) for range numFieldSamples { - f.Pick(randomStreamScalar) + f.Pick(randomStreamPoint) observedScalar(t, f) g.Inv(f) h.Mul(f, g) @@ -136,7 +132,7 @@ func TestScalar_MulDivInv(t *testing.T) { require.True(t, h.Equal(newScalar(big.NewInt(1)))) h.Div(newScalar(big.NewInt(1)), f) require.True(t, h.Equal(g)) - h.Pick(randomStreamScalar) + h.Pick(randomStreamPoint) observedScalar(t, h) j.Neg(j.Mul(h, f)) k.Mul(h, k.Neg(f)) From 1e71e1b18ea16dcb7b6e1af1b5bb1afb1db85199 Mon Sep 17 00:00:00 2001 From: pavel-raykov Date: Tue, 10 Feb 2026 09:37:21 +0100 Subject: [PATCH 04/13] Minor. --- keystore/go.mod | 15 ++----------- keystore/go.sum | 59 +++++++++++++++++++------------------------------ 2 files changed, 25 insertions(+), 49 deletions(-) diff --git a/keystore/go.mod b/keystore/go.mod index 728ae803b2..899b0003a1 100644 --- a/keystore/go.mod +++ b/keystore/go.mod @@ -13,7 +13,7 @@ require ( github.com/aws/aws-sdk-go-v2/config v1.28.4 github.com/aws/aws-sdk-go-v2/service/kms v1.49.5 github.com/btcsuite/btcd/btcec/v2 v2.3.5 - github.com/cosmos/cosmos-sdk v0.53.5 + github.com/cosmos/cosmos-sdk v0.50.14 github.com/ethereum/go-ethereum v1.16.8 github.com/gagliardetto/solana-go v1.14.0 github.com/google/uuid v1.6.0 @@ -88,7 +88,7 @@ require ( github.com/cockroachdb/pebble v1.1.5 // indirect github.com/cockroachdb/redact v1.1.6 // indirect github.com/cockroachdb/tokenbucket v0.0.0-20250429170803-42689b6311bb // indirect - github.com/cometbft/cometbft v0.38.20 // indirect + github.com/cometbft/cometbft v0.38.21 // indirect github.com/cometbft/cometbft-db v1.0.1 // indirect github.com/consensys/gnark-crypto v0.18.1 // indirect github.com/cosmos/btcutil v1.0.5 // indirect @@ -122,9 +122,6 @@ require ( github.com/gagliardetto/binary v0.8.0 // indirect github.com/gagliardetto/treeout v0.1.4 // indirect github.com/getsentry/sentry-go v0.35.1 // indirect - github.com/gin-contrib/sessions v0.0.5 // indirect - github.com/gin-contrib/sse v0.1.0 // indirect - github.com/gin-gonic/gin v1.10.1 // indirect github.com/go-json-experiment/json v0.0.0-20250223041408-d3c622f1b874 // indirect github.com/go-kit/kit v0.13.0 // indirect github.com/go-kit/log v0.2.1 // indirect @@ -147,12 +144,7 @@ require ( github.com/google/btree v1.1.3 // indirect github.com/google/flatbuffers v25.2.10+incompatible // indirect github.com/google/go-cmp v0.7.0 // indirect - github.com/gorilla/context v1.1.1 // indirect - github.com/gorilla/securecookie v1.1.2 // indirect - github.com/gorilla/sessions v1.2.2 // indirect github.com/gorilla/websocket v1.5.3 // indirect - github.com/grafana/pyroscope-go v1.2.7 // indirect - github.com/grafana/pyroscope-go/godeltaprof v0.1.9 // indirect github.com/grpc-ecosystem/grpc-gateway v1.16.0 // indirect github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.1 // indirect github.com/gsterjov/go-libsecret v0.0.0-20161001094733-a6f4afe4910c // indirect @@ -211,7 +203,6 @@ require ( github.com/pion/transport/v2 v2.2.10 // indirect github.com/pion/transport/v3 v3.0.7 // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect - github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 // indirect github.com/prometheus/client_golang v1.23.0 // indirect github.com/prometheus/client_model v0.6.2 // indirect github.com/prometheus/common v0.65.0 // indirect @@ -226,7 +217,6 @@ require ( github.com/sasha-s/go-deadlock v0.3.5 // indirect github.com/scylladb/go-reflectx v1.0.1 // indirect github.com/shirou/gopsutil v3.21.11+incompatible // indirect - github.com/shirou/gopsutil/v3 v3.24.3 // indirect github.com/shopspring/decimal v1.4.0 // indirect github.com/sigurn/crc16 v0.0.0-20211026045750-20ab5afb07e3 // indirect github.com/smartcontractkit/chain-selectors v1.0.89 // indirect @@ -238,7 +228,6 @@ require ( github.com/spf13/cast v1.10.0 // indirect github.com/spf13/pflag v1.0.10 // indirect github.com/streamingfast/logging v0.0.0-20230608130331-f22c91403091 // indirect - github.com/stretchr/objx v0.5.2 // indirect github.com/supranational/blst v0.3.16-0.20250831170142-f48500c1fdbe // indirect github.com/syndtr/goleveldb v1.0.1-0.20220721030215-126854af5e6d // indirect github.com/tendermint/go-amino v0.16.0 // indirect diff --git a/keystore/go.sum b/keystore/go.sum index a87b4ff95b..bbdeeb917d 100644 --- a/keystore/go.sum +++ b/keystore/go.sum @@ -6,8 +6,8 @@ cosmossdk.io/collections v1.3.1 h1:09e+DUId2brWsNOQ4nrk+bprVmMUaDH9xvtZkeqIjVw= cosmossdk.io/collections v1.3.1/go.mod h1:ynvkP0r5ruAjbmedE+vQ07MT6OtJ0ZIDKrtJHK7Q/4c= cosmossdk.io/core v0.11.3 h1:mei+MVDJOwIjIniaKelE3jPDqShCc/F4LkNNHh+4yfo= cosmossdk.io/core v0.11.3/go.mod h1:9rL4RE1uDt5AJ4Tg55sYyHWXA16VmpHgbe0PbJc6N2Y= -cosmossdk.io/depinject v1.2.1 h1:eD6FxkIjlVaNZT+dXTQuwQTKZrFZ4UrfCq1RKgzyhMw= -cosmossdk.io/depinject v1.2.1/go.mod h1:lqQEycz0H2JXqvOgVwTsjEdMI0plswI7p6KX+MVqFOM= +cosmossdk.io/depinject v1.1.0 h1:wLan7LG35VM7Yo6ov0jId3RHWCGRhe8E8bsuARorl5E= +cosmossdk.io/depinject v1.1.0/go.mod h1:kkI5H9jCGHeKeYWXTqYdruogYrEeWvBQCw1Pj4/eCFI= cosmossdk.io/errors v1.0.2 h1:wcYiJz08HThbWxd/L4jObeLaLySopyyuUFB5w4AGpCo= cosmossdk.io/errors v1.0.2/go.mod h1:0rjgiHkftRYPj//3DrD6y8hcm40HcPv/dR4R/4efr0k= cosmossdk.io/log v1.6.1 h1:YXNwAgbDwMEKwDlCdH8vPcoggma48MgZrTQXCfmMBeI= @@ -195,8 +195,8 @@ github.com/cockroachdb/tokenbucket v0.0.0-20250429170803-42689b6311bb h1:3bCgBvB github.com/cockroachdb/tokenbucket v0.0.0-20250429170803-42689b6311bb/go.mod h1:7nc4anLGjupUW/PeY5qiNYsdNXj7zopG+eqsS7To5IQ= github.com/coder/websocket v1.8.14 h1:9L0p0iKiNOibykf283eHkKUHHrpG7f65OE3BhhO7v9g= github.com/coder/websocket v1.8.14/go.mod h1:NX3SzP+inril6yawo5CQXx8+fk145lPDC6pumgx0mVg= -github.com/cometbft/cometbft v0.38.20 h1:i9v9rvh3Z4CZvGSWrByAOpiqNq5WLkat3r/tE/B49RU= -github.com/cometbft/cometbft v0.38.20/go.mod h1:UCu8dlHqvkAsmAFmWDRWNZJPlu6ya2fTWZlDrWsivwo= +github.com/cometbft/cometbft v0.38.21 h1:qcIJSH9LiwU5s6ZgKR5eRbsLNucbubfraDs5bzgjtOI= +github.com/cometbft/cometbft v0.38.21/go.mod h1:UCu8dlHqvkAsmAFmWDRWNZJPlu6ya2fTWZlDrWsivwo= github.com/cometbft/cometbft-db v1.0.1 h1:SylKuLseMLQKw3+i8y8KozZyJcQSL98qEe2CGMCGTYE= github.com/cometbft/cometbft-db v1.0.1/go.mod h1:EBrFs1GDRiTqrWXYi4v90Awf/gcdD5ExzdPbg4X8+mk= github.com/consensys/gnark-crypto v0.18.1 h1:RyLV6UhPRoYYzaFnPQA4qK3DyuDgkTgskDdoGqFt3fI= @@ -212,8 +212,8 @@ github.com/cosmos/cosmos-db v1.1.3 h1:7QNT77+vkefostcKkhrzDK9uoIEryzFrU9eoMeaQOP github.com/cosmos/cosmos-db v1.1.3/go.mod h1:kN+wGsnwUJZYn8Sy5Q2O0vCYA99MJllkKASbs6Unb9U= github.com/cosmos/cosmos-proto v1.0.0-beta.5 h1:eNcayDLpip+zVLRLYafhzLvQlSmyab+RC5W7ZfmxJLA= github.com/cosmos/cosmos-proto v1.0.0-beta.5/go.mod h1:hQGLpiIUloJBMdQMMWb/4wRApmI9hjHH05nefC0Ojec= -github.com/cosmos/cosmos-sdk v0.53.5 h1:JPue+SFn2gyDzTV9TYb8mGpuIH3kGt7WbGadulkpTcU= -github.com/cosmos/cosmos-sdk v0.53.5/go.mod h1:AQJx0jpon70WAD4oOs/y+SlST4u7VIwEPR6F8S7JMdo= +github.com/cosmos/cosmos-sdk v0.50.14 h1:G8CtGHFWbExa+ZpVOVAb4kFmko/R30igsYOwyzRMtgY= +github.com/cosmos/cosmos-sdk v0.50.14/go.mod h1:hrWEFMU1eoXqLJeE6VVESpJDQH67FS1nnMrQIjO2daw= github.com/cosmos/go-bip39 v1.0.0 h1:pcomnQdrdH22njcAatO0yWojsUnCO3y2tNoV1cb6hHY= github.com/cosmos/go-bip39 v1.0.0/go.mod h1:RNJv0H/pOIVgxw6KS7QeX2a0Uo0aKUlfhZ4xuwvCdJw= github.com/cosmos/gogogateway v1.2.0 h1:Ae/OivNhp8DqBi/sh2A8a1D0y638GpL3tkmLQAiKxTE= @@ -405,6 +405,8 @@ github.com/golang-jwt/jwt/v5 v5.2.3 h1:kkGXqQOBSDDWRhWNXTFpqGSCMyh/PLnqUvMGJPDJD github.com/golang-jwt/jwt/v5 v5.2.3/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.7.0-rc.1 h1:YojYx61/OLFsiv6Rw1Z96LpldJIy31o+UHmwAUMJ6/U= +github.com/golang/mock v1.7.0-rc.1/go.mod h1:s42URUywIqd+OcERslBJvOjepvNymP31m3q8d/GkuRs= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.0/go.mod h1:Qd/q+1AKNOZr9uGQzbzCmRO6sUih6GTPZv6a1/R87v0= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= @@ -434,9 +436,6 @@ github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMyw github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= -github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= 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/go-tpm v0.9.0 h1:sQF6YqWMi+SCXpsmS3fd21oPy/vSddwZry4JnmltHVk= @@ -528,8 +527,8 @@ github.com/holiman/bloomfilter/v2 v2.0.3/go.mod h1:zpoh+gs7qcpqrHr3dB55AMiJwo0iU github.com/holiman/uint256 v1.3.2 h1:a9EgMPSC1AAaj1SZL5zIQD3WbwTuHrMGOerLjGmM/TA= github.com/holiman/uint256 v1.3.2/go.mod h1:EOMSn4q6Nyt9P6efbI3bueV4e1b3dGlUCXeiRV4ng7E= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= -github.com/huandu/skiplist v1.2.1 h1:dTi93MgjwErA/8idWTzIw4Y1kZsMWx35fmI2c8Rij7w= -github.com/huandu/skiplist v1.2.1/go.mod h1:7v3iFjLcSAzO4fN5B8dvebvo/qsfumiLiDXMrPiHF9w= +github.com/huandu/skiplist v1.2.0 h1:gox56QD77HzSC0w+Ws3MH3iie755GBJU1OER3h5VsYw= +github.com/huandu/skiplist v1.2.0/go.mod h1:7v3iFjLcSAzO4fN5B8dvebvo/qsfumiLiDXMrPiHF9w= github.com/huin/goupnp v1.3.0 h1:UvLUlWDNpoUdYzb2TCn+MuTWtcjXKSza2n6CBdQ0xXc= github.com/huin/goupnp v1.3.0/go.mod h1:gnGPsThkYa7bFi/KWmEysQRf48l2dvR5bxr2OFckNX8= github.com/iancoleman/strcase v0.3.0 h1:nTXanmYxhfFAMjZL34Ov6gkzEsSJZ5DbhxWjvSASxEI= @@ -660,9 +659,8 @@ github.com/linxGnu/grocksdb v1.9.3 h1:s1cbPcOd0cU2SKXRG1nEqCOWYAELQjdqg3RVI2MH9i github.com/linxGnu/grocksdb v1.9.3/go.mod h1:QYiYypR2d4v63Wj1adOOfzglnoII0gLj3PNh4fZkcFA= github.com/logrusorgru/aurora v2.0.3+incompatible h1:tOpm7WcpBTn4fjmVfgpQq0EfczGlG91VSDkswnjF5A8= github.com/logrusorgru/aurora v2.0.3+incompatible/go.mod h1:7rIyQOR62GCctdiQpZ/zOJlFyk6y+94wXzv6RNZgaR4= -github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I= -github.com/magiconair/properties v1.8.10 h1:s31yESBquKXCV9a/ScB3ESkOjUYYv+X0rg8SYxI99mE= -github.com/magiconair/properties v1.8.10/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= +github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY= +github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= github.com/mailru/easyjson v0.9.0 h1:PrnmzHw7262yW8sTBwxi1PdJA3Iw/EKBa8psRf7d9a4= github.com/mailru/easyjson v0.9.0/go.mod h1:1+xMtQp2MRNVL/V1bOzuP3aP8VNwRW55fQUto+XFtTU= github.com/manyminds/api2go v0.0.0-20171030193247-e7b693844a6f h1:tVvGiZQFjOXP+9YyGqSA6jE55x1XVxmoPYudncxrZ8U= @@ -730,9 +728,8 @@ github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRW github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= +github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= -github.com/nxadm/tail v1.4.11 h1:8feyoE3OzPrcshW5/MJ4sGESc5cqmGkGCWlco4l0bqY= -github.com/nxadm/tail v1.4.11/go.mod h1:OTaG3NK980DZzxbRq6lEuzgU+mug70nY11sMd4JXXHc= github.com/oapi-codegen/runtime v1.1.2 h1:P2+CubHq8fO4Q6fV1tqDBZHCwpVpvPg7oKiYzQgXIyI= github.com/oapi-codegen/runtime v1.1.2/go.mod h1:SK9X900oXmPWilYR5/WKPzt3Kqxn/uS/+lbpREv+eCg= github.com/oasisprotocol/curve25519-voi v0.0.0-20230904125328-1f23a7beb09a h1:dlRvE5fWabOchtH7znfiFCcOvmIYgOeAS5ifBXBlh9Q= @@ -794,7 +791,6 @@ github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINE 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/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE= github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 h1:o4JXh1EVt9k/+g42oCprj/FisM4qX9L3sZB3upGN2ZU= github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE= github.com/pressly/goose/v3 v3.26.0 h1:KJakav68jdH0WDvoAcj8+n61WqOIaPGgH0bJWS6jpmM= @@ -853,8 +849,8 @@ github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/ryanuber/go-glob v1.0.0 h1:iQh3xXAumdQ+4Ufa5b25cRpC5TYKlno6hsv6Cb3pkBk= github.com/ryanuber/go-glob v1.0.0/go.mod h1:807d1WSdnB0XRJzKNil9Om6lcp/3a0v4qIHxIXzX/Yc= -github.com/sagikazarmark/locafero v0.11.0 h1:1iurJgmM9G3PA/I+wWYIOw/5SyBtxapeHDcg+AAIFXc= -github.com/sagikazarmark/locafero v0.11.0/go.mod h1:nVIGvgyzw595SUSUE6tvCp3YYTeHs15MvlmU87WwIik= +github.com/sagikazarmark/locafero v0.9.0 h1:GbgQGNtTrEmddYDSAH9QLRyfAHY12md+8YFTqyMTC9k= +github.com/sagikazarmark/locafero v0.9.0/go.mod h1:UBUyz37V+EdMS3hDF3QWIiVr/2dPrx49OMO0Bn0hJqk= github.com/samber/lo v1.49.1 h1:4BIFyVfuQSEpluc7Fua+j1NolZHiEHEpaSEKdsH0tew= github.com/samber/lo v1.49.1/go.mod h1:dO6KHFzUKXgP8LDhU0oI8d2hekjXnGOu0DB8Jecxd6o= github.com/sanity-io/litter v1.5.5 h1:iE+sBxPBzoK6uaEP5Lt3fHNgpKcHXc/A2HGETy0uJQo= @@ -872,8 +868,6 @@ github.com/shirou/gopsutil v3.21.11+incompatible h1:+1+c1VGhc88SSonWP6foOcLhvnKl github.com/shirou/gopsutil v3.21.11+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA= github.com/shirou/gopsutil/v3 v3.24.3 h1:eoUGJSmdfLzJ3mxIhmOAhgKEKgQkeOwKpz1NbhVnuPE= github.com/shirou/gopsutil/v3 v3.24.3/go.mod h1:JpND7O217xa72ewWz9zN2eIIkPWsDN/3pl0H8Qt0uwg= -github.com/shoenig/go-m1cpu v0.1.6/go.mod h1:1JJMcUBvfNwpq05QDQVAnx3gUHr9IYF7GNg9SUEw2VQ= -github.com/shoenig/test v0.6.4/go.mod h1:byHiCGXqrVaflBLAMq/srcZIHynQPQgeyvkvXnjqq0k= github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4= github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= github.com/shopspring/decimal v1.3.1/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= @@ -969,10 +963,10 @@ github.com/smartcontractkit/tdh2/go/tdh2 v0.0.0-20251120172354-e8ec0386b06c h1:S github.com/smartcontractkit/tdh2/go/tdh2 v0.0.0-20251120172354-e8ec0386b06c/go.mod h1:NSc7hgOQbXG3DAwkOdWnZzLTZENXSwDJ7Va1nBp0YU0= github.com/smartcontractkit/wsrpc v0.8.5-0.20250502134807-c57d3d995945 h1:zxcODLrFytOKmAd8ty8S/XK6WcIEJEgRBaL7sY/7l4Y= github.com/smartcontractkit/wsrpc v0.8.5-0.20250502134807-c57d3d995945/go.mod h1:m3pdp17i4bD50XgktkzWetcV5yaLsi7Gunbv4ZgN6qg= -github.com/sourcegraph/conc v0.3.1-0.20240121214520-5f936abd7ae8 h1:+jumHNA0Wrelhe64i8F6HNlS8pkoyMv5sreGx2Ry5Rw= -github.com/sourcegraph/conc v0.3.1-0.20240121214520-5f936abd7ae8/go.mod h1:3n1Cwaq1E1/1lhQhtRK2ts/ZwZEhjcQeJQ1RuC6Q/8U= -github.com/spf13/afero v1.15.0 h1:b/YBCLWAJdFWJTN9cLhiXXcD7mzKn9Dm86dNnfyQw1I= -github.com/spf13/afero v1.15.0/go.mod h1:NC2ByUVxtQs4b3sIUphxK0NioZnmxgyCrfzeuq8lxMg= +github.com/sourcegraph/conc v0.3.0 h1:OQTbbt6P72L20UqAkXXuLOj79LfEanQ+YQFNpLA9ySo= +github.com/sourcegraph/conc v0.3.0/go.mod h1:Sdozi7LEKbFPqYX2/J+iBAM6HpqSLTASQIKqDmF7Mt0= +github.com/spf13/afero v1.14.0 h1:9tH6MapGnn/j0eb0yIXiLjERO8RB6xIVZRDCX7PtqWA= +github.com/spf13/afero v1.14.0/go.mod h1:acJQ8t0ohCGuMN3O+Pv0V0hgMxNYDlvdk+VTfyZmbYo= github.com/spf13/cast v1.10.0 h1:h2x0u2shc1QuLHfxi+cTJvs30+ZAHOGRic8uyGTDWxY= github.com/spf13/cast v1.10.0/go.mod h1:jNfB8QC9IA6ZuY2ZjDp0KtFO2LZZlg4S/7bzP6qqeHo= github.com/spf13/cobra v1.10.1 h1:lJeBwCfmrnXthfAupyUTzJ/J4Nc1RsHC/mSRU2dll/s= @@ -980,8 +974,8 @@ github.com/spf13/cobra v1.10.1/go.mod h1:7SmJGaTHFVBY0jW4NXGluQoLvhqFQM+6XSKD+P4 github.com/spf13/pflag v1.0.9/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/spf13/pflag v1.0.10 h1:4EBh2KAYBwaONj6b2Ye1GiHfwjqyROoF4RwYO+vPwFk= github.com/spf13/pflag v1.0.10/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= -github.com/spf13/viper v1.21.0 h1:x5S+0EU27Lbphp4UKm1C+1oQO+rKx36vfCoaVebLFSU= -github.com/spf13/viper v1.21.0/go.mod h1:P0lhsswPGWD/1lZJ9ny3fYnVqxiegrlNrEmgLjbTCAY= +github.com/spf13/viper v1.20.1 h1:ZMi+z/lvLyPSCoNtFCpqjy0S4kPbirhpTMwl8BkW9X4= +github.com/spf13/viper v1.20.1/go.mod h1:P9Mdzt1zoHIG8m2eZQinpiBjo6kCmZSKBClNNqjJvu4= github.com/stephenlacy/go-ethereum-hdwallet v0.0.0-20230913225845-a4fa94429863 h1:ba4VRWSkRzgdP5hB5OxexIzBXZbSwgcw8bEu06ivGQI= github.com/stephenlacy/go-ethereum-hdwallet v0.0.0-20230913225845-a4fa94429863/go.mod h1:oPTjPNrRucLv9mU27iNPj6n0CWWcNFhoXFOLVGJwHCA= github.com/streamingfast/logging v0.0.0-20230608130331-f22c91403091 h1:RN5mrigyirb8anBEtdjtHFIufXdacyTi6i4KBfeNXeo= @@ -1005,7 +999,6 @@ github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= -github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= @@ -1030,10 +1023,8 @@ github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JT github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU= github.com/tidwall/pretty v1.2.1 h1:qjsOFOWWQl+N3RsoF5/ssm1pHmJJwhjlSbZ51I6wMl4= github.com/tidwall/pretty v1.2.1/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU= -github.com/tklauser/go-sysconf v0.3.12/go.mod h1:Ho14jnntGE1fpdOqQEEaiKRpvIavV0hSfmBq8nJbHYI= github.com/tklauser/go-sysconf v0.3.15 h1:VE89k0criAymJ/Os65CSn1IXaol+1wrsFHEB8Ol49K4= github.com/tklauser/go-sysconf v0.3.15/go.mod h1:Dmjwr6tYFIseJw7a3dRLJfsHAMXZ3nEnL/aZY+0IuI4= -github.com/tklauser/numcpus v0.6.1/go.mod h1:1XfjsgE2zo8GVw7POkMbHENHzVg3GzmoZ9fESEdAacY= github.com/tklauser/numcpus v0.10.0 h1:18njr6LDBk1zuna922MgdjQuJFjrdppsZG60sHGfjso= github.com/tklauser/numcpus v0.10.0/go.mod h1:BiTKazU708GQTYF4mB+cmlpT2Is1gLk7XVuEeem8LsQ= github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM= @@ -1148,8 +1139,6 @@ go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= go.uber.org/goleak v1.1.11/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= -go.uber.org/mock v0.6.0 h1:hyF9dfmbgIX5EfOdasqLsWD6xqpNZlXblLB/Dbnwv3Y= -go.uber.org/mock v0.6.0/go.mod h1:KiVJ4BqZJaMj4svdfmHM0AUx4NJYO8ZNpPnZn1Z+BBU= go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4= go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU= @@ -1167,8 +1156,8 @@ go.uber.org/zap v1.27.1 h1:08RqriUEv8+ArZRYSTXy1LeBScaMpVSTBhCeaZYfMYc= go.uber.org/zap v1.27.1/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= go.yaml.in/yaml/v2 v2.4.2 h1:DzmwEr2rDGHl7lsFgAHxmNz/1NlQ7xLIrlN2h5d1eGI= go.yaml.in/yaml/v2 v2.4.2/go.mod h1:081UH+NErpNdqlCXm3TtEran0rJZGxAYx9hb/ELlsPU= -go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc= -go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg= +go.yaml.in/yaml/v3 v3.0.3 h1:bXOww4E/J3f66rav3pX3m8w6jDE4knZjGOw8b5Y6iNE= +go.yaml.in/yaml/v3 v3.0.3/go.mod h1:tBHosrYAkRZjRAOREWbDnBXUf08JOwYq++0QNwQiWzI= golang.org/x/arch v0.17.0 h1:4O3dfLzd+lQewptAHqjewQZQDyEdejz3VwgeYwkZneU= golang.org/x/arch v0.17.0/go.mod h1:bdwinDaKcfZUGpH09BB7ZmOfhalA8lQdzl62l8gGWsk= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= @@ -1283,7 +1272,6 @@ golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20201204225414-ed752295db88/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -1305,7 +1293,6 @@ golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.40.0 h1:DBZZqJ2Rkml6QMQsZywtnjnnGvHza6BTfYFWY9kjEWQ= golang.org/x/sys v0.40.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= golang.org/x/telemetry v0.0.0-20260109210033-bd525da824e2 h1:O1cMQHRfwNpDfDJerqRoE2oD+AFlyid87D40L/OkkJo= From 0f80b319642e6ce44ea128772c4b49e1173e459b Mon Sep 17 00:00:00 2001 From: pavel-raykov Date: Tue, 10 Feb 2026 09:39:33 +0100 Subject: [PATCH 05/13] Minor. --- go.mod | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/go.mod b/go.mod index 050a498b11..8e670bec94 100644 --- a/go.mod +++ b/go.mod @@ -34,6 +34,7 @@ require ( github.com/mr-tron/base58 v1.2.0 github.com/pelletier/go-toml v1.9.5 github.com/pelletier/go-toml/v2 v2.2.4 + github.com/pkg/errors v0.9.1 github.com/prometheus/client_golang v1.22.0 github.com/santhosh-tekuri/jsonschema/v5 v5.3.1 github.com/scylladb/go-reflectx v1.0.1 @@ -131,7 +132,6 @@ require ( github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect github.com/oklog/run v1.2.0 // indirect github.com/pierrec/lz4/v4 v4.1.22 // indirect - github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect github.com/prometheus/client_model v0.6.2 // indirect github.com/prometheus/common v0.65.0 // indirect From e6ad1f3a0e4a941e131ef165e78e234c6f5e1f00 Mon Sep 17 00:00:00 2001 From: pavel-raykov Date: Tue, 10 Feb 2026 10:01:43 +0100 Subject: [PATCH 06/13] Minor. --- keystore/corekeys/aptoskey/export_test.go | 8 +++++--- keystore/corekeys/cosmoskey/export_test.go | 8 +++++--- keystore/corekeys/csakey/export_test.go | 8 +++++--- keystore/corekeys/ethkey/export_test.go | 6 ++++-- keystore/corekeys/ocrkey/export_test.go | 8 +++++--- keystore/corekeys/p2pkey/export_test.go | 8 +++++--- keystore/corekeys/solkey/export_test.go | 8 +++++--- keystore/corekeys/starkkey/export_test.go | 7 ++++--- keystore/corekeys/suikey/export_test.go | 8 +++++--- keystore/corekeys/tonkey/export_test.go | 8 +++++--- keystore/corekeys/tronkey/export_test.go | 8 +++++--- keystore/corekeys/vrfkey/export_test.go | 8 +++++--- 12 files changed, 58 insertions(+), 35 deletions(-) diff --git a/keystore/corekeys/aptoskey/export_test.go b/keystore/corekeys/aptoskey/export_test.go index aa1f4cce73..e2cfec6b23 100644 --- a/keystore/corekeys/aptoskey/export_test.go +++ b/keystore/corekeys/aptoskey/export_test.go @@ -2,16 +2,18 @@ package aptoskey import ( "testing" + + "github.com/smartcontractkit/chainlink-common/keystore/corekeys" ) func TestAptosKeys_ExportImport(t *testing.T) { - corekeys2.RunKeyExportImportTestcase(t, createKey, decryptKey) + corekeys.RunKeyExportImportTestcase(t, createKey, decryptKey) } -func createKey() (corekeys2.KeyType, error) { +func createKey() (corekeys.KeyType, error) { return New() } -func decryptKey(keyJSON []byte, password string) (corekeys2.KeyType, error) { +func decryptKey(keyJSON []byte, password string) (corekeys.KeyType, error) { return FromEncryptedJSON(keyJSON, password) } diff --git a/keystore/corekeys/cosmoskey/export_test.go b/keystore/corekeys/cosmoskey/export_test.go index 9abbbbec22..0c71a54b33 100644 --- a/keystore/corekeys/cosmoskey/export_test.go +++ b/keystore/corekeys/cosmoskey/export_test.go @@ -2,16 +2,18 @@ package cosmoskey import ( "testing" + + "github.com/smartcontractkit/chainlink-common/keystore/corekeys" ) func TestCosmosKeys_ExportImport(t *testing.T) { - corekeys2.RunKeyExportImportTestcase(t, createKey, decryptKey) + corekeys.RunKeyExportImportTestcase(t, createKey, decryptKey) } -func createKey() (corekeys2.KeyType, error) { +func createKey() (corekeys.KeyType, error) { return New(), nil } -func decryptKey(keyJSON []byte, password string) (corekeys2.KeyType, error) { +func decryptKey(keyJSON []byte, password string) (corekeys.KeyType, error) { return FromEncryptedJSON(keyJSON, password) } diff --git a/keystore/corekeys/csakey/export_test.go b/keystore/corekeys/csakey/export_test.go index 6c440b2f2e..57e4ff46cc 100644 --- a/keystore/corekeys/csakey/export_test.go +++ b/keystore/corekeys/csakey/export_test.go @@ -2,16 +2,18 @@ package csakey import ( "testing" + + "github.com/smartcontractkit/chainlink-common/keystore/corekeys" ) func TestCSAKeys_ExportImport(t *testing.T) { - corekeys2.RunKeyExportImportTestcase(t, createKey, decryptKey) + corekeys.RunKeyExportImportTestcase(t, createKey, decryptKey) } -func createKey() (corekeys2.KeyType, error) { +func createKey() (corekeys.KeyType, error) { return NewV2() } -func decryptKey(keyJSON []byte, password string) (corekeys2.KeyType, error) { +func decryptKey(keyJSON []byte, password string) (corekeys.KeyType, error) { return FromEncryptedJSON(keyJSON, password) } diff --git a/keystore/corekeys/ethkey/export_test.go b/keystore/corekeys/ethkey/export_test.go index 96f444f856..0fbe248fc5 100644 --- a/keystore/corekeys/ethkey/export_test.go +++ b/keystore/corekeys/ethkey/export_test.go @@ -2,15 +2,17 @@ package ethkey import ( "testing" + + "github.com/smartcontractkit/chainlink-common/keystore/corekeys" ) func TestEthKeys_ExportImport(t *testing.T) { - corekeys2.RunKeyExportImportTestcase(t, createKey, func(keyJSON []byte, password string) (kt corekeys2.KeyType, err error) { + corekeys.RunKeyExportImportTestcase(t, createKey, func(keyJSON []byte, password string) (kt corekeys.KeyType, err error) { t.SkipNow() return kt, err }) } -func createKey() (corekeys2.KeyType, error) { +func createKey() (corekeys.KeyType, error) { return NewV2() } diff --git a/keystore/corekeys/ocrkey/export_test.go b/keystore/corekeys/ocrkey/export_test.go index 261c3118e8..36b3d666ee 100644 --- a/keystore/corekeys/ocrkey/export_test.go +++ b/keystore/corekeys/ocrkey/export_test.go @@ -2,16 +2,18 @@ package ocrkey import ( "testing" + + "github.com/smartcontractkit/chainlink-common/keystore/corekeys" ) func TestOCRKeys_ExportImport(t *testing.T) { - corekeys2.RunKeyExportImportTestcase(t, createKey, decryptKey) + corekeys.RunKeyExportImportTestcase(t, createKey, decryptKey) } -func createKey() (corekeys2.KeyType, error) { +func createKey() (corekeys.KeyType, error) { return NewV2() } -func decryptKey(keyJSON []byte, password string) (corekeys2.KeyType, error) { +func decryptKey(keyJSON []byte, password string) (corekeys.KeyType, error) { return FromEncryptedJSON(keyJSON, password) } diff --git a/keystore/corekeys/p2pkey/export_test.go b/keystore/corekeys/p2pkey/export_test.go index ab265a2a29..baccb54deb 100644 --- a/keystore/corekeys/p2pkey/export_test.go +++ b/keystore/corekeys/p2pkey/export_test.go @@ -2,16 +2,18 @@ package p2pkey import ( "testing" + + "github.com/smartcontractkit/chainlink-common/keystore/corekeys" ) func TestP2PKeys_ExportImport(t *testing.T) { - corekeys2.RunKeyExportImportTestcase(t, createKey, decryptKey) + corekeys.RunKeyExportImportTestcase(t, createKey, decryptKey) } -func createKey() (corekeys2.KeyType, error) { +func createKey() (corekeys.KeyType, error) { return NewV2() } -func decryptKey(keyJSON []byte, password string) (corekeys2.KeyType, error) { +func decryptKey(keyJSON []byte, password string) (corekeys.KeyType, error) { return FromEncryptedJSON(keyJSON, password) } diff --git a/keystore/corekeys/solkey/export_test.go b/keystore/corekeys/solkey/export_test.go index 4f1b1a0062..fbc93f0c5c 100644 --- a/keystore/corekeys/solkey/export_test.go +++ b/keystore/corekeys/solkey/export_test.go @@ -2,16 +2,18 @@ package solkey import ( "testing" + + "github.com/smartcontractkit/chainlink-common/keystore/corekeys" ) func TestSolanaKeys_ExportImport(t *testing.T) { - corekeys2.RunKeyExportImportTestcase(t, createKey, decryptKey) + corekeys.RunKeyExportImportTestcase(t, createKey, decryptKey) } -func createKey() (corekeys2.KeyType, error) { +func createKey() (corekeys.KeyType, error) { return New() } -func decryptKey(keyJSON []byte, password string) (corekeys2.KeyType, error) { +func decryptKey(keyJSON []byte, password string) (corekeys.KeyType, error) { return FromEncryptedJSON(keyJSON, password) } diff --git a/keystore/corekeys/starkkey/export_test.go b/keystore/corekeys/starkkey/export_test.go index 0c938ba7b9..f420879a5e 100644 --- a/keystore/corekeys/starkkey/export_test.go +++ b/keystore/corekeys/starkkey/export_test.go @@ -3,19 +3,20 @@ package starkkey import ( "testing" + "github.com/smartcontractkit/chainlink-common/keystore/corekeys" "github.com/smartcontractkit/chainlink-common/keystore/scrypt" ) func TestStarkNetKeys_ExportImport(t *testing.T) { - corekeys2.RunKeyExportImportTestcase(t, createKey, decryptKey) + corekeys.RunKeyExportImportTestcase(t, createKey, decryptKey) } -func createKey() (corekeys2.KeyType, error) { +func createKey() (corekeys.KeyType, error) { key, err := New() return TestWrapped{key}, err } -func decryptKey(keyJSON []byte, password string) (corekeys2.KeyType, error) { +func decryptKey(keyJSON []byte, password string) (corekeys.KeyType, error) { key, err := FromEncryptedJSON(keyJSON, password) return TestWrapped{key}, err } diff --git a/keystore/corekeys/suikey/export_test.go b/keystore/corekeys/suikey/export_test.go index b311d00c96..1b319248c9 100644 --- a/keystore/corekeys/suikey/export_test.go +++ b/keystore/corekeys/suikey/export_test.go @@ -2,16 +2,18 @@ package suikey import ( "testing" + + "github.com/smartcontractkit/chainlink-common/keystore/corekeys" ) func TestSuiKeys_ExportImport(t *testing.T) { - corekeys2.RunKeyExportImportTestcase(t, createKey, decryptKey) + corekeys.RunKeyExportImportTestcase(t, createKey, decryptKey) } -func createKey() (corekeys2.KeyType, error) { +func createKey() (corekeys.KeyType, error) { return New() } -func decryptKey(keyJSON []byte, password string) (corekeys2.KeyType, error) { +func decryptKey(keyJSON []byte, password string) (corekeys.KeyType, error) { return FromEncryptedJSON(keyJSON, password) } diff --git a/keystore/corekeys/tonkey/export_test.go b/keystore/corekeys/tonkey/export_test.go index cc9ad9065f..f1c890f559 100644 --- a/keystore/corekeys/tonkey/export_test.go +++ b/keystore/corekeys/tonkey/export_test.go @@ -2,16 +2,18 @@ package tonkey import ( "testing" + + "github.com/smartcontractkit/chainlink-common/keystore/corekeys" ) func TestTONKeys_ExportImport(t *testing.T) { - corekeys2.RunKeyExportImportTestcase(t, createKey, decryptKey) + corekeys.RunKeyExportImportTestcase(t, createKey, decryptKey) } -func createKey() (corekeys2.KeyType, error) { +func createKey() (corekeys.KeyType, error) { return New() } -func decryptKey(keyJSON []byte, password string) (corekeys2.KeyType, error) { +func decryptKey(keyJSON []byte, password string) (corekeys.KeyType, error) { return FromEncryptedJSON(keyJSON, password) } diff --git a/keystore/corekeys/tronkey/export_test.go b/keystore/corekeys/tronkey/export_test.go index 5dd2ad4900..2cc0ce7d85 100644 --- a/keystore/corekeys/tronkey/export_test.go +++ b/keystore/corekeys/tronkey/export_test.go @@ -2,16 +2,18 @@ package tronkey import ( "testing" + + "github.com/smartcontractkit/chainlink-common/keystore/corekeys" ) func TestTronKeys_ExportImport(t *testing.T) { - corekeys2.RunKeyExportImportTestcase(t, createKey, decryptKey) + corekeys.RunKeyExportImportTestcase(t, createKey, decryptKey) } -func createKey() (corekeys2.KeyType, error) { +func createKey() (corekeys.KeyType, error) { return New() } -func decryptKey(keyJSON []byte, password string) (corekeys2.KeyType, error) { +func decryptKey(keyJSON []byte, password string) (corekeys.KeyType, error) { return FromEncryptedJSON(keyJSON, password) } diff --git a/keystore/corekeys/vrfkey/export_test.go b/keystore/corekeys/vrfkey/export_test.go index 252458d4fa..8c417517ac 100644 --- a/keystore/corekeys/vrfkey/export_test.go +++ b/keystore/corekeys/vrfkey/export_test.go @@ -2,16 +2,18 @@ package vrfkey import ( "testing" + + "github.com/smartcontractkit/chainlink-common/keystore/corekeys" ) func TestVRFKeys_ExportImport(t *testing.T) { - corekeys2.RunKeyExportImportTestcase(t, createKey, decryptKey) + corekeys.RunKeyExportImportTestcase(t, createKey, decryptKey) } -func createKey() (corekeys2.KeyType, error) { +func createKey() (corekeys.KeyType, error) { return NewV2() } -func decryptKey(keyJSON []byte, password string) (corekeys2.KeyType, error) { +func decryptKey(keyJSON []byte, password string) (corekeys.KeyType, error) { return FromEncryptedJSON(keyJSON, password) } From 8a73c0f76d11cf4d900b069b4fd25eefedc5c189 Mon Sep 17 00:00:00 2001 From: pavel-raykov Date: Tue, 10 Feb 2026 10:05:34 +0100 Subject: [PATCH 07/13] Minor. --- keystore/corekeys/ocrkey/key_v2_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/keystore/corekeys/ocrkey/key_v2_test.go b/keystore/corekeys/ocrkey/key_v2_test.go index 7457c19840..a6779abac4 100644 --- a/keystore/corekeys/ocrkey/key_v2_test.go +++ b/keystore/corekeys/ocrkey/key_v2_test.go @@ -7,8 +7,8 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + "github.com/smartcontractkit/chainlink-common/keystore/corekeys/ocrkey" "github.com/smartcontractkit/chainlink-common/keystore/internal" - "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/ocrkey" ) func assertKeyBundlesNotEqual(t *testing.T, pk1 ocrkey.KeyV2, pk2 ocrkey.KeyV2) { From d6be2b5f5ed2609ea808086ebcf2df5697d240cf Mon Sep 17 00:00:00 2001 From: pavel-raykov Date: Tue, 10 Feb 2026 10:10:13 +0100 Subject: [PATCH 08/13] Minor. --- .../ocrkey/off_chain_public_key_test.go | 2 +- .../ocrkey/on_chain_signing_address_test.go | 2 +- keystore/go.mod | 7 +- keystore/go.sum | 242 +----------------- 4 files changed, 11 insertions(+), 242 deletions(-) diff --git a/keystore/corekeys/ocrkey/off_chain_public_key_test.go b/keystore/corekeys/ocrkey/off_chain_public_key_test.go index 372ca8b273..84e13dc054 100644 --- a/keystore/corekeys/ocrkey/off_chain_public_key_test.go +++ b/keystore/corekeys/ocrkey/off_chain_public_key_test.go @@ -7,7 +7,7 @@ import ( "github.com/stretchr/testify/assert" - "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/ocrkey" + "github.com/smartcontractkit/chainlink-common/keystore/corekeys/ocrkey" ) func TestOCR_OffchainPublicKey_MarshalJSON(t *testing.T) { diff --git a/keystore/corekeys/ocrkey/on_chain_signing_address_test.go b/keystore/corekeys/ocrkey/on_chain_signing_address_test.go index e45da17f03..27db14dd1a 100644 --- a/keystore/corekeys/ocrkey/on_chain_signing_address_test.go +++ b/keystore/corekeys/ocrkey/on_chain_signing_address_test.go @@ -6,7 +6,7 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/ocrkey" + "github.com/smartcontractkit/chainlink-common/keystore/corekeys/ocrkey" ) func TestOCR_OnChainSigningAddress_String(t *testing.T) { diff --git a/keystore/go.mod b/keystore/go.mod index 899b0003a1..185c9e173f 100644 --- a/keystore/go.mod +++ b/keystore/go.mod @@ -23,7 +23,6 @@ require ( github.com/mr-tron/base58 v1.2.0 github.com/pkg/errors v0.9.1 github.com/smartcontractkit/chainlink-evm v0.3.4-0.20260205183656-836ec9472717 - github.com/smartcontractkit/chainlink/v2 v2.32.0 github.com/smartcontractkit/libocr v0.0.0-20251212213002-0a5e2f907dda github.com/smartcontractkit/smdkg v0.0.0-20251029093710-c38905e58aeb github.com/smartcontractkit/wsrpc v0.8.5-0.20250502134807-c57d3d995945 @@ -138,12 +137,14 @@ require ( github.com/gofrs/flock v0.12.1 // indirect github.com/gogo/protobuf v1.3.2 // indirect github.com/golang-jwt/jwt/v4 v4.5.2 // indirect - github.com/golang-jwt/jwt/v5 v5.2.3 // indirect + github.com/golang/mock v1.7.0-rc.1 // indirect github.com/golang/protobuf v1.5.4 // indirect github.com/golang/snappy v1.0.0 // indirect github.com/google/btree v1.1.3 // indirect github.com/google/flatbuffers v25.2.10+incompatible // indirect github.com/google/go-cmp v0.7.0 // indirect + github.com/gorilla/handlers v1.5.2 // indirect + github.com/gorilla/mux v1.8.1 // indirect github.com/gorilla/websocket v1.5.3 // indirect github.com/grpc-ecosystem/grpc-gateway v1.16.0 // indirect github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.1 // indirect @@ -151,6 +152,7 @@ require ( github.com/hashicorp/go-bexpr v0.1.10 // indirect github.com/hashicorp/go-immutable-radix v1.3.1 // indirect github.com/hashicorp/go-metrics v0.5.4 // indirect + github.com/hashicorp/go-uuid v1.0.3 // indirect github.com/hashicorp/golang-lru v1.0.2 // indirect github.com/holiman/billy v0.0.0-20250707135307-f2f9b9aae7db // indirect github.com/holiman/bloomfilter/v2 v2.0.3 // indirect @@ -208,7 +210,6 @@ require ( github.com/prometheus/common v0.65.0 // indirect github.com/prometheus/procfs v0.17.0 // indirect github.com/rivo/uniseg v0.4.7 // indirect - github.com/robfig/cron/v3 v3.0.1 // indirect github.com/rogpeppe/go-internal v1.14.1 // indirect github.com/rs/cors v1.11.1 // indirect github.com/rs/zerolog v1.34.0 // indirect diff --git a/keystore/go.sum b/keystore/go.sum index bbdeeb917d..186d282b2d 100644 --- a/keystore/go.sum +++ b/keystore/go.sum @@ -30,17 +30,11 @@ github.com/99designs/go-keychain v0.0.0-20191008050251-8e49817e8af4 h1:/vQbFIOMb github.com/99designs/go-keychain v0.0.0-20191008050251-8e49817e8af4/go.mod h1:hN7oaIRCjzsZ2dE+yG5k+rsdt3qcwykqK6HVGcKwsw4= github.com/99designs/keyring v1.2.1 h1:tYLp1ULvO7i3fI5vE21ReQuj99QFSs7lGm0xWyJo87o= github.com/99designs/keyring v1.2.1/go.mod h1:fc+wB5KTk9wQ9sDx0kFXB3A0MaeGHM9AwRStKOQ5vOA= -github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358 h1:mFRzDkZVAjdal+s7s0MwaRv9igoPqLRdzOLzw/8Xvq8= -github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358/go.mod h1:chxPXzSsl7ZWRAuOIE23GDNzjWuZquvFlgA8xmpunjU= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= -github.com/BurntSushi/toml v1.4.0 h1:kuoIxZQy2WRRk1pttg9asf+WVv6tWQuBNVmK8+nqPr0= -github.com/BurntSushi/toml v1.4.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho= github.com/DataDog/datadog-go v3.2.0+incompatible h1:qSG2N4FghB1He/r2mFrWKCaL7dXCilEuNEeAn20fdD4= github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= github.com/DataDog/zstd v1.5.7 h1:ybO8RBeh29qrxIhCA9E8gKY6xfONU9T6G6aP9DTKfLE= github.com/DataDog/zstd v1.5.7/go.mod h1:g4AWEaM3yOg3HYfnJ3YIawPnVdXJh9QME85blwSAmyw= -github.com/Depado/ginprom v1.8.0 h1:zaaibRLNI1dMiiuj1MKzatm8qrcHzikMlCc1anqOdyo= -github.com/Depado/ginprom v1.8.0/go.mod h1:XBaKzeNBqPF4vxJpNLincSQZeMDnZp1tIbU0FU0UKgg= github.com/Masterminds/semver/v3 v3.1.1/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs= 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= @@ -72,15 +66,7 @@ github.com/apache/arrow-go/v18 v18.3.1 h1:oYZT8FqONiK74JhlH3WKVv+2NKYoyZ7C2ioD4D github.com/apache/arrow-go/v18 v18.3.1/go.mod h1:12QBya5JZT6PnBihi5NJTzbACrDGXYkrgjujz3MRQXU= github.com/apache/thrift v0.21.0 h1:tdPmh/ptjE1IJnhbhrcl2++TauVjy242rkV/UzJChnE= github.com/apache/thrift v0.21.0/go.mod h1:W1H8aR/QRtYNvrPeFXBtobyRkd0/YVhTc6i07XIAgDw= -github.com/apapsch/go-jsonmerge/v2 v2.0.0 h1:axGnT1gRIfimI7gJifB699GoE/oq+F2MU7Dml6nw9rQ= -github.com/apapsch/go-jsonmerge/v2 v2.0.0/go.mod h1:lvDnEdqiQrp0O42VQGgmlKpxL1AP2+08jFMw88y4klk= -github.com/aptos-labs/aptos-go-sdk v1.11.0 h1:vIL1hpjECUiu7zMl9Wz6VV8ttXsrDqKUj0HxoeaIER4= -github.com/aptos-labs/aptos-go-sdk v1.11.0/go.mod h1:8YvYwRg93UcG6pTStCpZdYiscCtKh51sYfeLgIy/41c= github.com/armon/go-metrics v0.4.1/go.mod h1:E6amYzXo6aW1tqzoZGT755KkbgrJsSdpwZ+3JqfkOG4= -github.com/atombender/go-jsonschema v0.16.1-0.20240916205339-a74cd4e2851c h1:cxQVoh6kY+c4b0HUchHjGWBI8288VhH50qxKG3hdEg0= -github.com/atombender/go-jsonschema v0.16.1-0.20240916205339-a74cd4e2851c/go.mod h1:3XzxudkrYVUvbduN/uI2fl4lSrMSzU0+3RCu2mpnfx8= -github.com/avast/retry-go/v4 v4.6.1 h1:VkOLRubHdisGrHnTu89g08aQEWEgRU7LVEop3GbIcMk= -github.com/avast/retry-go/v4 v4.6.1/go.mod h1:V6oF8njAwxJ5gRo1Q7Cxab24xs5NCWZBeaHHBklR8mA= github.com/aws/aws-sdk-go-v2 v1.41.1 h1:ABlyEARCDLN034NhxlRUSZr4l71mh+T5KAeGh6cerhU= github.com/aws/aws-sdk-go-v2 v1.41.1/go.mod h1:MayyLB8y+buD9hZqkCW3kX1AKq07Y5pXxtgB+rRFhz0= github.com/aws/aws-sdk-go-v2/config v1.28.4 h1:qgD0MKmkIzZR2DrAjWJcI9UkndjR+8f6sjUQvXh0mb0= @@ -109,15 +95,9 @@ github.com/aws/aws-sdk-go-v2/service/sts v1.33.0 h1:s7LRgBqhwLaxcocnAniBJp7gaAB+ github.com/aws/aws-sdk-go-v2/service/sts v1.33.0/go.mod h1:9XEUty5v5UAsMiFOBJrNibZgwCeOma73jgGwwhgffa8= github.com/aws/smithy-go v1.24.0 h1:LpilSUItNPFr1eY85RYgTIg5eIEPtvFbskaFcmmIUnk= github.com/aws/smithy-go v1.24.0/go.mod h1:LEj2LM3rBRQJxPZTB4KuzZkaZYnZPnvgIhb4pu07mx0= -github.com/aybabtme/rgbterm v0.0.0-20170906152045-cc83f3b3ce59 h1:WWB576BN5zNSZc/M9d/10pqEx5VHNhaQ/yOVAkmj5Yo= -github.com/aybabtme/rgbterm v0.0.0-20170906152045-cc83f3b3ce59/go.mod h1:q/89r3U2H7sSsE2t6Kca0lfwTK8JdoNGS/yzM/4iH5I= github.com/bahlo/generic-list-go v0.2.0 h1:5sz/EEAK+ls5wF+NeqDpk5+iNdMDXrh3z3nPnH1Wvgk= github.com/bahlo/generic-list-go v0.2.0/go.mod h1:2KvAjgMlE5NNynlg/5iLrrCCZ2+5xWbdbCW3pNTGyYg= -github.com/beevik/ntp v1.5.0 h1:y+uj/JjNwlY2JahivxYvtmv4ehfi3h74fAuABB9ZSM4= -github.com/beevik/ntp v1.5.0/go.mod h1:mJEhBrwT76w9D+IfOEGvuzyuudiW9E52U2BaTrMOYow= github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= -github.com/benbjohnson/clock v1.3.5 h1:VvXlSJBzZpA/zum6Sj74hxwYI2DIxRWuNIoXAzHZz5o= -github.com/benbjohnson/clock v1.3.5/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= @@ -128,24 +108,12 @@ github.com/bits-and-blooms/bitset v1.24.3 h1:Bte86SlO3lwPQqww+7BE9ZuUCKIjfqnG5jt github.com/bits-and-blooms/bitset v1.24.3/go.mod h1:7hO7Gc7Pp1vODcmWvKMRA9BNmbv6a/7QIWpPxHddWR8= github.com/blendle/zapdriver v1.3.1 h1:C3dydBOWYRiOk+B8X9IVZ5IOe+7cl+tGOexN4QqHfpE= github.com/blendle/zapdriver v1.3.1/go.mod h1:mdXfREi6u5MArG4j9fewC+FGnXaBR+T4Ox4J2u4eHCc= -github.com/block-vision/sui-go-sdk v1.1.2 h1:p9DPfb51mEcTmF0Lx9ORpH+Nh9Rzg4Sv3Pu5gsJZ2AA= -github.com/block-vision/sui-go-sdk v1.1.2/go.mod h1:KlibJnwEpWt8qhQkIPxc/2ZE4kwh0Md6LvMHmW5kemA= -github.com/btcsuite/btcd v0.24.2 h1:aLmxPguqxza+4ag8R1I2nnJjSu2iFn/kqtHTIImswcY= -github.com/btcsuite/btcd v0.24.2/go.mod h1:5C8ChTkl5ejr3WHj8tkQSCmydiMEPB0ZhQhehpq7Dgg= github.com/btcsuite/btcd/btcec/v2 v2.3.5 h1:dpAlnAwmT1yIBm3exhT1/8iUSD98RDJM5vqJVQDQLiU= github.com/btcsuite/btcd/btcec/v2 v2.3.5/go.mod h1:m22FrOAiuxl/tht9wIqAoGHcbnCCaPWyauO8y2LGGtQ= github.com/btcsuite/btcd/btcutil v1.1.6 h1:zFL2+c3Lb9gEgqKNzowKUPQNb8jV7v5Oaodi/AYFd6c= github.com/btcsuite/btcd/btcutil v1.1.6/go.mod h1:9dFymx8HpuLqBnsPELrImQeTQfKBQqzqGbbV3jK55aE= -github.com/btcsuite/btcd/chaincfg/chainhash v1.1.0 h1:59Kx4K6lzOW5w6nFlA0v5+lk/6sjybR934QNHSJZPTQ= -github.com/btcsuite/btcd/chaincfg/chainhash v1.1.0/go.mod h1:7SFka0XMvUgj3hfZtydOrQY2mwhPclbT2snogU7SQQc= -github.com/btcsuite/btcutil v1.0.3-0.20201208143702-a53e38424cce h1:YtWJF7RHm2pYCvA5t0RPmAaLUhREsKuKd+SLhxFbFeQ= -github.com/btcsuite/btcutil v1.0.3-0.20201208143702-a53e38424cce/go.mod h1:0DVlHczLPewLcPGEIeUEzfOJhqGPQ0mJJRDBtD307+o= -github.com/buger/goterm v1.0.4 h1:Z9YvGmOih81P0FbVtEYTFF6YsSgxSUKEhf/f9bTMXbY= -github.com/buger/goterm v1.0.4/go.mod h1:HiFWV3xnkolgrBV3mY8m0X0Pumt4zg4QhbdOzQtB8tE= github.com/buger/jsonparser v1.1.1 h1:2PnMjfWD7wBILjqQbt530v576A/cAbQvEW9gGIpYMUs= github.com/buger/jsonparser v1.1.1/go.mod h1:6RYKKt7H4d4+iWqouImQ9R2FZql3VbhNgx27UK13J/0= -github.com/bytecodealliance/wasmtime-go/v28 v28.0.0 h1:aBU8cexP2rPZ0Qz488kvn2NXvWZHL2aG1/+n7Iv+xGc= -github.com/bytecodealliance/wasmtime-go/v28 v28.0.0/go.mod h1:4OCU0xAW9ycwtX4nMF4zxwgJBJ5/0eMfJiHB0wAmkV4= github.com/bytedance/gopkg v0.1.3 h1:TPBSwH8RsouGCBcMBktLt1AymVo2TVsBVCY4b6TnZ/M= github.com/bytedance/gopkg v0.1.3/go.mod h1:576VvJ+eJgyCzdjS+c4+77QF3p7ubbtiKARP3TxducM= github.com/bytedance/sonic v1.14.2 h1:k1twIoe97C1DtYUo+fZQy865IuHia4PR5RPiuGPPIIE= @@ -153,7 +121,6 @@ github.com/bytedance/sonic v1.14.2/go.mod h1:T80iDELeHiHKSc0C9tubFygiuXoGzrkjKzX github.com/bytedance/sonic/loader v0.4.0 h1:olZ7lEqcxtZygCK9EKYKADnpQoYkRQxaeY2NYzevs+o= github.com/bytedance/sonic/loader v0.4.0/go.mod h1:AR4NYCk5DdzZizZ5djGqQ92eEhCCcdf5x77udYiSJRo= github.com/cenkalti/backoff v2.2.1+incompatible h1:tNowT99t7UNflLxfYYSlKYsBpXdEet03Pg2g16Swow4= -github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM= github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8= github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= github.com/cenkalti/backoff/v5 v5.0.2 h1:rIfFVxEf1QsI7E1ZHfp/B4DF/6QBAUhmgkxc0H7Zss8= @@ -193,16 +160,12 @@ github.com/cockroachdb/redact v1.1.6 h1:zXJBwDZ84xJNlHl1rMyCojqyIxv+7YUpQiJLQ7n4 github.com/cockroachdb/redact v1.1.6/go.mod h1:BVNblN9mBWFyMyqK1k3AAiSxhvhfK2oOZZ2lK+dpvRg= github.com/cockroachdb/tokenbucket v0.0.0-20250429170803-42689b6311bb h1:3bCgBvB8PbJVMX1ouCcSIxvsqKPYM7gs72o0zC76n9g= github.com/cockroachdb/tokenbucket v0.0.0-20250429170803-42689b6311bb/go.mod h1:7nc4anLGjupUW/PeY5qiNYsdNXj7zopG+eqsS7To5IQ= -github.com/coder/websocket v1.8.14 h1:9L0p0iKiNOibykf283eHkKUHHrpG7f65OE3BhhO7v9g= -github.com/coder/websocket v1.8.14/go.mod h1:NX3SzP+inril6yawo5CQXx8+fk145lPDC6pumgx0mVg= github.com/cometbft/cometbft v0.38.21 h1:qcIJSH9LiwU5s6ZgKR5eRbsLNucbubfraDs5bzgjtOI= github.com/cometbft/cometbft v0.38.21/go.mod h1:UCu8dlHqvkAsmAFmWDRWNZJPlu6ya2fTWZlDrWsivwo= github.com/cometbft/cometbft-db v1.0.1 h1:SylKuLseMLQKw3+i8y8KozZyJcQSL98qEe2CGMCGTYE= github.com/cometbft/cometbft-db v1.0.1/go.mod h1:EBrFs1GDRiTqrWXYi4v90Awf/gcdD5ExzdPbg4X8+mk= github.com/consensys/gnark-crypto v0.18.1 h1:RyLV6UhPRoYYzaFnPQA4qK3DyuDgkTgskDdoGqFt3fI= github.com/consensys/gnark-crypto v0.18.1/go.mod h1:L3mXGFTe1ZN+RSJ+CLjUt9x7PNdx8ubaYfDROyp2Z8c= -github.com/coreos/go-oidc/v3 v3.11.0 h1:Ia3MxdwpSw702YW0xgfmP1GVCMA9aEFWu12XUZ3/OtI= -github.com/coreos/go-oidc/v3 v3.11.0/go.mod h1:gE3LgjOgFoHi9a4ce4/tJczr0Ai2/BoDhf0r5lltWI0= github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= @@ -236,8 +199,6 @@ github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7Do github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/danieljoos/wincred v1.2.1 h1:dl9cBrupW8+r5250DYkYxocLeZ1Y4vB1kxgtjxw8GQs= github.com/danieljoos/wincred v1.2.1/go.mod h1:uGaFL9fDn3OLTvzCGulzE+SzjEe5NGlh5FdCcyfPwps= -github.com/danielkov/gin-helmet v0.0.0-20171108135313-1387e224435e h1:5jVSh2l/ho6ajWhSPNN84eHEdq3dp0T7+f6r3Tc6hsk= -github.com/danielkov/gin-helmet v0.0.0-20171108135313-1387e224435e/go.mod h1:IJgIiGUARc4aOr4bOQ85klmjsShkEEfiRc6q/yBSfo8= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= @@ -260,10 +221,6 @@ github.com/dgraph-io/ristretto/v2 v2.2.0 h1:bkY3XzJcXoMuELV8F+vS8kzNgicwQFAaGINA github.com/dgraph-io/ristretto/v2 v2.2.0/go.mod h1:RZrm63UmcBAaYWC1DotLYBmTvgkrs0+XhBd7Npn7/zI= 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/dominikbraun/graph v0.23.0 h1:TdZB4pPqCLFxYhdyMFb1TBdFxp8XLcJfTTBQucVPgCo= -github.com/dominikbraun/graph v0.23.0/go.mod h1:yOjYyogZLY1LSG9E33JWZJiq5k83Qy2C6POAuiViluc= -github.com/doyensec/safeurl v0.2.1 h1:DY15JorEfQsnpBWhBkVQIkaif2jfxCC14PIuGDsjDVs= -github.com/doyensec/safeurl v0.2.1/go.mod h1:wzSXqC/6Z410qHz23jtBWT+wQ8yTxcY0p8bZH/4EZIg= 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/dvsekhvalnov/jose2go v1.7.0 h1:bnQc8+GMnidJZA8zc6lLEAb4xNrIqHwO+9TzqvtQZPo= @@ -274,8 +231,6 @@ github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymF github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= -github.com/esote/minmaxheap v1.0.0 h1:rgA7StnXXpZG6qlM0S7pUmEv1KpWe32rYT4x8J8ntaA= -github.com/esote/minmaxheap v1.0.0/go.mod h1:Ln8+i7fS1k3PLgZI2JAo0iA1as95QnIYiGCrqSJ5FZk= github.com/ethereum/c-kzg-4844/v2 v2.1.5 h1:aVtoLK5xwJ6c5RiqO8g8ptJ5KU+2Hdquf6G3aXiHh5s= github.com/ethereum/c-kzg-4844/v2 v2.1.5/go.mod h1:u59hRTTah4Co6i9fDWtiCjTrblJv0UwsqZKCc0GfgUs= github.com/ethereum/go-bigmodexpfix v0.0.0-20250911101455-f9e208c548ab h1:rvv6MJhy07IMfEKuARQ9TKojGqLVNxQajaXEp/BoqSk= @@ -284,10 +239,6 @@ github.com/ethereum/go-ethereum v1.16.8 h1:LLLfkZWijhR5m6yrAXbdlTeXoqontH+Ga2f9i github.com/ethereum/go-ethereum v1.16.8/go.mod h1:Fs6QebQbavneQTYcA39PEKv2+zIjX7rPUZ14DER46wk= github.com/ethereum/go-verkle v0.2.2 h1:I2W0WjnrFUIzzVPwm8ykY+7pL2d4VhlsePn4j7cnFk8= github.com/ethereum/go-verkle v0.2.2/go.mod h1:M3b90YRnzqKyyzBEWJGqj8Qff4IDeXnzFw0P9bFw3uk= -github.com/expr-lang/expr v1.17.5 h1:i1WrMvcdLF249nSNlpQZN1S6NXuW9WaOfF5tPi3aw3k= -github.com/expr-lang/expr v1.17.5/go.mod h1:8/vRC7+7HBzESEqt5kKpYXxrxkr31SaO8r40VO/1IT4= -github.com/failsafe-go/failsafe-go v0.9.0 h1:w0g7iv48RpQvV3UH1VlgUnLx9frQfCwI7ljnJzqEhYg= -github.com/failsafe-go/failsafe-go v0.9.0/go.mod h1:sX5TZ4HrMLYSzErWeckIHRZWgZj9PbKMAEKOVLFWtfM= github.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM= github.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU= github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= @@ -313,33 +264,13 @@ github.com/gagliardetto/solana-go v1.14.0 h1:3WfAi70jOOjAJ0deFMjdhFYlLXATF4tOQXs github.com/gagliardetto/solana-go v1.14.0/go.mod h1:l/qqqIN6qJJPtxW/G1PF4JtcE3Zg2vD2EliZrr9Gn5k= github.com/gagliardetto/treeout v0.1.4 h1:ozeYerrLCmCubo1TcIjFiOWTTGteOOHND1twdFpgwaw= github.com/gagliardetto/treeout v0.1.4/go.mod h1:loUefvXTrlRG5rYmJmExNryyBRh8f89VZhmMOyCyqok= -github.com/gagliardetto/utilz v0.1.3 h1:A+asc+6/3a9qNBrgticApj3yW5F7y4TaJd8Ijg+o0zM= -github.com/gagliardetto/utilz v0.1.3/go.mod h1:b+rGFkRHz3HWJD0RYMzat47JyvbTtpE0iEcYTRJTLLA= github.com/gballet/go-libpcsclite v0.0.0-20191108122812-4678299bea08 h1:f6D9Hr8xV8uYKlyuj8XIruxlh9WjVjdh1gIicAS7ays= github.com/gballet/go-libpcsclite v0.0.0-20191108122812-4678299bea08/go.mod h1:x7DCsMOv1taUwEWCzT4cmDeAkigA5/QCwUodaVOe8Ww= -github.com/gedex/inflector v0.0.0-20170307190818-16278e9db813 h1:Uc+IZ7gYqAf/rSGFplbWBSHaGolEQlNLgMgSE3ccnIQ= -github.com/gedex/inflector v0.0.0-20170307190818-16278e9db813/go.mod h1:P+oSoE9yhSRvsmYyZsshflcR6ePWYLql6UU1amW13IM= github.com/getsentry/sentry-go v0.35.1 h1:iopow6UVLE2aXu46xKVIs8Z9D/YZkJrHkgozrxa+tOQ= github.com/getsentry/sentry-go v0.35.1/go.mod h1:C55omcY9ChRQIUcVcGcs+Zdy4ZpQGvNJ7JYHIoSWOtE= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= -github.com/gin-contrib/cors v1.7.2 h1:oLDHxdg8W/XDoN/8zamqk/Drgt4oVZDvaV0YmvVICQw= -github.com/gin-contrib/cors v1.7.2/go.mod h1:SUJVARKgQ40dmrzgXEVxj2m7Ig1v1qIboQkPDTQ9t2E= -github.com/gin-contrib/expvar v0.0.1 h1:IuU5ArEgihz50vG8Onrwz22kJr7Mcvgv9xSSpfU5g+w= -github.com/gin-contrib/expvar v0.0.1/go.mod h1:8o2CznfQi1JjktORdHr2/abg3wSV6OCnXh0yGypvvVw= -github.com/gin-contrib/sessions v0.0.5 h1:CATtfHmLMQrMNpJRgzjWXD7worTh7g7ritsQfmF+0jE= -github.com/gin-contrib/sessions v0.0.5/go.mod h1:vYAuaUPqie3WUSsft6HUlCjlwwoJQs97miaG2+7neKY= -github.com/gin-contrib/size v0.0.0-20230212012657-e14a14094dc4 h1:Z9J0PVIt1PuibOShaOw1jH8hUYz+Ak8NLsR/GI0Hv5I= -github.com/gin-contrib/size v0.0.0-20230212012657-e14a14094dc4/go.mod h1:CEPcgZiz8998l9E8fDm16h8UfHRL7b+5oG0j/0koeVw= -github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE= -github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= -github.com/gin-gonic/gin v1.10.1 h1:T0ujvqyCSqRopADpgPgiTT63DUQVSfojyME59Ei63pQ= -github.com/gin-gonic/gin v1.10.1/go.mod h1:4PMNQiOhvDRa013RKVbsiNwoyezlm2rm0uX/T7kzp5Y= -github.com/go-asn1-ber/asn1-ber v1.5.5 h1:MNHlNMBDgEKD4TcKr36vQN68BA00aDfjIt3/bD50WnA= -github.com/go-asn1-ber/asn1-ber v1.5.5/go.mod h1:hEBeB/ic+5LoWskz+yKT7vGhhPYkProFKoKdwZRWMe0= github.com/go-errors/errors v1.4.2 h1:J6MZopCL4uSllY1OfXM374weqZFFItUbrImctkmUxIA= github.com/go-errors/errors v1.4.2/go.mod h1:sIVyrIiJhuEF+Pj9Ebtd6P/rEYROXFi3BopGUQ5a5Og= -github.com/go-jose/go-jose/v4 v4.1.3 h1:CVLmWDhDVRa6Mi/IgCgaopNosCaHz7zrMeF9MlZRkrs= -github.com/go-jose/go-jose/v4 v4.1.3/go.mod h1:x4oUasVrzR7071A4TnHLGSPpNOm2a21K9Kf04k1rs08= github.com/go-json-experiment/json v0.0.0-20250223041408-d3c622f1b874 h1:F8d1AJ6M9UQCavhwmO6ZsrYLfG8zVFWfEfMS2MXPkSY= github.com/go-json-experiment/json v0.0.0-20250223041408-d3c622f1b874/go.mod h1:TiCD2a1pcmjd7YnhGH0f/zKNcCD06B029pHhzV23c2M= github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= @@ -349,8 +280,6 @@ github.com/go-kit/kit v0.13.0/go.mod h1:phqEHMMUbyrCFCTgH48JueqrM3md2HcAZ8N3XE4F github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY= github.com/go-kit/log v0.2.1 h1:MRVx0/zhvdseW+Gza6N9rVzU/IVzaeE1SFI4raAhmBU= github.com/go-kit/log v0.2.1/go.mod h1:NwTd00d/i8cPZ3xOwwiv2PO5MOcx78fFErGNcVmBjv0= -github.com/go-ldap/ldap/v3 v3.4.6 h1:ert95MdbiG7aWo/oPYp9btL3KJlMPKnP58r09rI8T+A= -github.com/go-ldap/ldap/v3 v3.4.6/go.mod h1:IGMQANNtxpsOzj7uUAMjpGBaOVTC4DYyIy8VsTdxmtc= github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= @@ -378,14 +307,8 @@ github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/me github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= github.com/go-viper/mapstructure/v2 v2.4.0 h1:EBsztssimR/CONLSZZ04E8qAkxNYq4Qp9LvH92wZUgs= github.com/go-viper/mapstructure/v2 v2.4.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM= -github.com/go-webauthn/webauthn v0.9.4 h1:YxvHSqgUyc5AK2pZbqkWWR55qKeDPhP8zLDr6lpIc2g= -github.com/go-webauthn/webauthn v0.9.4/go.mod h1:LqupCtzSef38FcxzaklmOn7AykGKhAhr9xlRbdbgnTw= -github.com/go-webauthn/x v0.1.5 h1:V2TCzDU2TGLd0kSZOXdrqDVV5JB9ILnKxA9S53CSBw0= -github.com/go-webauthn/x v0.1.5/go.mod h1:qbzWwcFcv4rTwtCLOZd+icnr6B7oSsAGZJqlt8cukqY= github.com/goccy/go-json v0.10.5 h1:Fq85nIqj+gXn/S5ahsiTlK3TmC85qgirsdTP/+DeaC4= github.com/goccy/go-json v0.10.5/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M= -github.com/goccy/go-yaml v1.12.0 h1:/1WHjnMsI1dlIBQutrvSMGZRQufVO3asrHfTwfACoPM= -github.com/goccy/go-yaml v1.12.0/go.mod h1:wKnAMd44+9JAAnGQpWVEgBzGt3YuTaQ4uXoHvE4m7WU= github.com/godbus/dbus v0.0.0-20190726142602-4481cbc300e2 h1:ZpnhV/YsD2/4cESfV5+Hoeu/iUR3ruzNvZ+yQfO03a0= github.com/godbus/dbus v0.0.0-20190726142602-4481cbc300e2/go.mod h1:bBOAhwG1umN6/6ZUMtDFBMQR8jRg9O75tm9K00oMsK4= github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= @@ -401,8 +324,6 @@ github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/golang-jwt/jwt/v4 v4.5.2 h1:YtQM7lnr8iZ+j5q71MGKkNw9Mn7AjHM68uc9g5fXeUI= github.com/golang-jwt/jwt/v4 v4.5.2/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= -github.com/golang-jwt/jwt/v5 v5.2.3 h1:kkGXqQOBSDDWRhWNXTFpqGSCMyh/PLnqUvMGJPDJDs0= -github.com/golang-jwt/jwt/v5 v5.2.3/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.7.0-rc.1 h1:YojYx61/OLFsiv6Rw1Z96LpldJIy31o+UHmwAUMJ6/U= @@ -438,8 +359,6 @@ github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.5/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/go-tpm v0.9.0 h1:sQF6YqWMi+SCXpsmS3fd21oPy/vSddwZry4JnmltHVk= -github.com/google/go-tpm v0.9.0/go.mod h1:FkNVkc6C+IsvDI9Jw1OveJmxGZUUaKxtrpOS47QWKfU= github.com/google/gofuzz v0.0.0-20170612174753-24818f796faf/go.mod h1:HP5RmnzzSNb993RKQDq4+1A4ia9nllfqcQFTQJedwGI= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= @@ -447,53 +366,29 @@ github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/ github.com/google/orderedcode v0.0.1 h1:UzfcAexk9Vhv8+9pNOgRu41f16lHq725vPwnSeiG/Us= github.com/google/orderedcode v0.0.1/go.mod h1:iVyU4/qPKHY5h/wSd6rZZCDcLJNxiWO6dvsYES2Sb20= github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/pprof v0.0.0-20250317173921-a4b03ec1a45e h1:ijClszYn+mADRFY17kjQEVQ1XRhq2/JR1M3sGqeJoxs= -github.com/google/pprof v0.0.0-20250317173921-a4b03ec1a45e/go.mod h1:boTsfXsheKC2y+lKOCMpSfarhxDeIzfZG1jqGcPl3cA= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= 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/context v1.1.1 h1:AWwleXJkX/nhcU9bZSnZoi3h/qGYqQAGhq6zZe/aQW8= -github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg= github.com/gorilla/handlers v1.5.2 h1:cLTUSsNkgcwhgRqvCNmdbRWG0A3N4F+M2nWKdScwyEE= github.com/gorilla/handlers v1.5.2/go.mod h1:dX+xVpaxdSw+q0Qek8SSsl3dfMk3jNddUkMzo0GtH0w= github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY= github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ= -github.com/gorilla/securecookie v1.1.2 h1:YCIWL56dvtr73r6715mJs5ZvhtnY73hBvEF8kXD8ePA= -github.com/gorilla/securecookie v1.1.2/go.mod h1:NfCASbcHqRSY+3a8tlWJwsQap2VX5pwzwo4h3eOamfo= -github.com/gorilla/sessions v1.2.2 h1:lqzMYz6bOfvn2WriPUjNByzeXIlVzURcPmgMczkmTjY= -github.com/gorilla/sessions v1.2.2/go.mod h1:ePLdVu+jbEgHH+KWw8I1z2wqd0BAdAQh/8LRvBeoNcQ= github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg= github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= -github.com/grafana/pyroscope-go v1.2.7 h1:VWBBlqxjyR0Cwk2W6UrE8CdcdD80GOFNutj0Kb1T8ac= -github.com/grafana/pyroscope-go v1.2.7/go.mod h1:o/bpSLiJYYP6HQtvcoVKiE9s5RiNgjYTj1DhiddP2Pc= -github.com/grafana/pyroscope-go/godeltaprof v0.1.9 h1:c1Us8i6eSmkW+Ez05d3co8kasnuOY813tbMN8i/a3Og= -github.com/grafana/pyroscope-go/godeltaprof v0.1.9/go.mod h1:2+l7K7twW49Ct4wFluZD3tZ6e0SjanjcUUBPVD/UuGU= -github.com/graph-gophers/dataloader v5.0.0+incompatible h1:R+yjsbrNq1Mo3aPG+Z/EKYrXrXXUNJHOgbRt+U6jOug= -github.com/graph-gophers/dataloader v5.0.0+incompatible/go.mod h1:jk4jk0c5ZISbKaMe8WsVopGB5/15GvGHMdMdPtwlRp4= github.com/graph-gophers/graphql-go v1.5.0 h1:fDqblo50TEpD0LY7RXk/LFVYEVqo3+tXMNMPSVXA1yc= github.com/graph-gophers/graphql-go v1.5.0/go.mod h1:YtmJZDLbF1YYNrlNAuiO5zAStUWc3XZT07iGsVqe1Os= github.com/grpc-ecosystem/go-grpc-middleware v1.4.0 h1:UH//fgunKIs4JdUbpDl1VZCDaL56wXCB/5+wF6uHfaI= github.com/grpc-ecosystem/go-grpc-middleware v1.4.0/go.mod h1:g5qyo/la0ALbONm6Vbp88Yd8NsDy6rZz+RcrMPxvld8= -github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus v1.0.1 h1:qnpSQwGEnkcRpTqNOIR6bJbR0gAorgP9CSALpRcKoAA= -github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus v1.0.1/go.mod h1:lXGCsh6c22WGtjr+qGHj1otzZpV/1kwTMAqkwZsnWRU= -github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.3.2 h1:sGm2vDRFUrQJO/Veii4h4zG2vvqG6uWNkBHSTqXOZk0= -github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.3.2/go.mod h1:wd1YpapPLivG6nQgbf7ZkG1hhSOXDhhn4MLTknx2aAc= github.com/grpc-ecosystem/grpc-gateway v1.16.0 h1:gmcG1KaJ57LophUzW0Hy8NmPhnMZb4M0+kPpLofRdBo= github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.1 h1:X5VWvz21y3gzm9Nw/kaUeku/1+uBhcekkmy4IkffJww= github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.1/go.mod h1:Zanoh4+gvIgluNqcfMVTJueD4wSS5hT7zTt4Mrutd90= github.com/gsterjov/go-libsecret v0.0.0-20161001094733-a6f4afe4910c h1:6rhixN/i8ZofjG1Y75iExal34USq5p+wiN1tpie8IrU= github.com/gsterjov/go-libsecret v0.0.0-20161001094733-a6f4afe4910c/go.mod h1:NMPJylDgVpX0MLRlPy15sqSwOFv/U1GZ2m21JhFfek0= -github.com/hako/durafmt v0.0.0-20200710122514-c0fb7b4da026 h1:BpJ2o0OR5FV7vrkDYfXYVJQeMNWa8RhklZOpW2ITAIQ= -github.com/hako/durafmt v0.0.0-20200710122514-c0fb7b4da026/go.mod h1:5Scbynm8dF1XAPwIwkGPqzkM/shndPm79Jd1003hTjE= github.com/hashicorp/go-bexpr v0.1.10 h1:9kuI5PFotCboP3dkDYFr/wi0gg0QVbSNz5oFRpxn4uE= github.com/hashicorp/go-bexpr v0.1.10/go.mod h1:oxlubA2vC/gFVfX1A6JGp7ls7uCDlfJn732ehYYg+g0= github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= -github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ= -github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48= -github.com/hashicorp/go-envparse v0.1.0 h1:bE++6bhIsNCPLvgDZkYqo3nA+/PFI51pkrHdmPSDFPY= -github.com/hashicorp/go-envparse v0.1.0/go.mod h1:OHheN1GoygLlAkTlXLXvAdnXdZxy8JUweQ1rAXx1xnc= github.com/hashicorp/go-hclog v1.6.3 h1:Qr2kF+eVWjTiYmU7Y31tYlP1h0q/X3Nl3tPGdaB11/k= github.com/hashicorp/go-hclog v1.6.3/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M= github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= @@ -504,8 +399,6 @@ github.com/hashicorp/go-metrics v0.5.4/go.mod h1:CG5yz4NZ/AI/aQt9Ucm/vdBnbh7fvmv github.com/hashicorp/go-plugin v1.7.0 h1:YghfQH/0QmPNc/AZMTFE3ac8fipZyZECHdDPshfk+mA= github.com/hashicorp/go-plugin v1.7.0/go.mod h1:BExt6KEaIYx804z8k4gRzRLEvxKVb+kn0NMcihqOqb8= github.com/hashicorp/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs= -github.com/hashicorp/go-retryablehttp v0.7.7 h1:C8hUCYzor8PIfXHa4UrZkU4VvK8o9ISHxT2Q8+VepXU= -github.com/hashicorp/go-retryablehttp v0.7.7/go.mod h1:pkQpWZeYWskR+D1tR2O5OcBFOxfA7DoAO6xtkuQnHTk= github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8= github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= @@ -516,8 +409,6 @@ github.com/hashicorp/golang-lru/v2 v2.0.7 h1:a+bsQ5rvGLjzHuww6tVxozPZFVghXaHOwFs github.com/hashicorp/golang-lru/v2 v2.0.7/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM= github.com/hashicorp/yamux v0.1.2 h1:XtB8kyFOyHXYVFnwT5C3+Bdo8gArse7j2AQ0DA0Uey8= github.com/hashicorp/yamux v0.1.2/go.mod h1:C+zze2n6e/7wshOZep2A70/aQU6QBRWJO/G6FT1wIns= -github.com/hasura/go-graphql-client v0.14.5 h1:M9HxxGLCcDZnxJGYyWXAzDYEpommgjW+sUW3V8EaGms= -github.com/hasura/go-graphql-client v0.14.5/go.mod h1:jfSZtBER3or+88Q9vFhWHiFMPppfYILRyl+0zsgPIIw= github.com/hdevalence/ed25519consensus v0.2.0 h1:37ICyZqdyj0lAZ8P4D1d1id3HqbbG1N3iBb1Tb4rdcU= github.com/hdevalence/ed25519consensus v0.2.0/go.mod h1:w3BHWjwJbFU29IRHL1Iqkw3sus+7FctEyM4RqDxYNzo= github.com/holiman/billy v0.0.0-20250707135307-f2f9b9aae7db h1:IZUYC/xb3giYwBLMnr8d0TGTzPKFGNTCGgGLoyeX330= @@ -534,8 +425,6 @@ github.com/huin/goupnp v1.3.0/go.mod h1:gnGPsThkYa7bFi/KWmEysQRf48l2dvR5bxr2OFck github.com/iancoleman/strcase v0.3.0 h1:nTXanmYxhfFAMjZL34Ov6gkzEsSJZ5DbhxWjvSASxEI= github.com/iancoleman/strcase v0.3.0/go.mod h1:iwCmte+B7n89clKwxIoIXy/HfoL7AsD47ZCWhYzw7ho= github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= -github.com/imdario/mergo v0.3.16 h1:wwQJbIsHYGMUyLSPrEq1CT16AhnhNJQ51+4fdHUnCl4= -github.com/imdario/mergo v0.3.16/go.mod h1:WBLT9ZmE3lPoWsEzCh9LPo3TiwVN+ZKEjmz+hD27ysY= github.com/improbable-eng/grpc-web v0.15.0 h1:BN+7z6uNXZ1tQGcNAuaU1YjsLTApzkjt2tzCixLaUPQ= github.com/improbable-eng/grpc-web v0.15.0/go.mod h1:1sy9HKV4Jt9aEs9JSnkWlRJPuPtwNr0l57L4f878wP8= github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= @@ -546,8 +435,6 @@ github.com/influxdata/influxdb1-client v0.0.0-20220302092344-a9ab5670611c h1:qSH github.com/influxdata/influxdb1-client v0.0.0-20220302092344-a9ab5670611c/go.mod h1:qj24IKcXYK6Iy9ceXlo3Tc+vtHo9lIhSX5JddghvEPo= github.com/influxdata/line-protocol v0.0.0-20210311194329-9aa0e372d097 h1:vilfsDSy7TDxedi9gyBkMvAirat/oRcL0lFdJBf6tdM= github.com/influxdata/line-protocol v0.0.0-20210311194329-9aa0e372d097/go.mod h1:xaLFMmpvUxqXtVkUJfg9QmT88cDaCJ3ZKgdZ78oO8Qo= -github.com/influxdata/tdigest v0.0.1 h1:XpFptwYmnEKUqmkcDjrzffswZ3nvNeevbUSLPP/ZzIY= -github.com/influxdata/tdigest v0.0.1/go.mod h1:Z0kXnxzbTC2qrx4NaIzYkE1k66+6oEDQTvL95hQFh5Y= github.com/invopop/jsonschema v0.13.0 h1:KvpoAJWEjR3uD9Kbm2HWJmqsEaHt8lBUpd0qHcIi21E= github.com/invopop/jsonschema v0.13.0/go.mod h1:ffZ5Km5SWWRAIN6wbDXItl95euhFz2uON45H2qjYt+0= github.com/jackc/chunkreader v1.0.0/go.mod h1:RT6O25fNZIuasFJRyZ4R/Y2BbhasbmZXF9QQ7T3kePo= @@ -603,14 +490,10 @@ github.com/jackc/puddle v1.1.3/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dv github.com/jackc/puddle v1.3.0/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= github.com/jackpal/go-nat-pmp v1.0.2 h1:KzKSgb7qkJvOUTqYl9/Hg/me3pWgBmERKrTGD7BdWus= github.com/jackpal/go-nat-pmp v1.0.2/go.mod h1:QPH045xvCAeXUZOxsnwmrtiCoxIr9eob+4orBN1SBKc= -github.com/jinzhu/copier v0.4.0 h1:w3ciUoD19shMCRargcpm0cm91ytaBhDvuRpz1ODO/U8= -github.com/jinzhu/copier v0.4.0/go.mod h1:DfbEm0FYsaqBcKcFuvmOZb218JkPGtvSHsKg8S8hyyg= github.com/jmhodges/levigo v1.0.0 h1:q5EC36kV79HWeTBWsod3mG11EgStG3qArTKcvlksN1U= github.com/jmhodges/levigo v1.0.0/go.mod h1:Q6Qx+uH3RAqyK4rFQroq9RL7mdkABMcfhEI+nNuzMJQ= github.com/jmoiron/sqlx v1.4.0 h1:1PLqN7S1UYp5t4SrVVnt4nUVNemrDAtxlulVe+Qgm3o= github.com/jmoiron/sqlx v1.4.0/go.mod h1:ZrZ7UsYB/weZdl2Bxg6jCRO9c3YHl8r3ahlKmRT4JLY= -github.com/jonboulle/clockwork v0.5.0 h1:Hyh9A8u51kptdkR+cqRpT1EebBwTn1oK9YfGYbdFz6I= -github.com/jonboulle/clockwork v0.5.0/go.mod h1:3mZlmanh0g2NDKO5TWZVJAfofYk64M7XN3SzBPjZF60= github.com/jpillora/backoff v1.0.0 h1:uvFg412JmmHBHw7iwprIxkPMI+sGQ4kzOWsMeHnm2EA= github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= @@ -663,8 +546,6 @@ github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0V github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= github.com/mailru/easyjson v0.9.0 h1:PrnmzHw7262yW8sTBwxi1PdJA3Iw/EKBa8psRf7d9a4= github.com/mailru/easyjson v0.9.0/go.mod h1:1+xMtQp2MRNVL/V1bOzuP3aP8VNwRW55fQUto+XFtTU= -github.com/manyminds/api2go v0.0.0-20171030193247-e7b693844a6f h1:tVvGiZQFjOXP+9YyGqSA6jE55x1XVxmoPYudncxrZ8U= -github.com/manyminds/api2go v0.0.0-20171030193247-e7b693844a6f/go.mod h1:Z60vy0EZVSu0bOugCHdcN5ZxFMKSpjRgsnh0XKPFqqk= github.com/marcboeker/go-duckdb v1.8.5 h1:tkYp+TANippy0DaIOP5OEfBEwbUINqiFqgwMQ44jME0= github.com/marcboeker/go-duckdb v1.8.5/go.mod h1:6mK7+WQE4P4u5AFLvVBmhFxY5fvhymFptghgJX6B+/8= github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ= @@ -686,10 +567,6 @@ github.com/mattn/go-sqlite3 v1.14.22/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxU github.com/mattn/go-sqlite3 v2.0.3+incompatible h1:gXHsfypPkaMZrKbD5209QV9jbUTJKjyR5WD3HYQSd+U= github.com/mattn/go-sqlite3 v2.0.3+incompatible/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= -github.com/mfridman/interpolate v0.0.2 h1:pnuTK7MQIxxFz1Gr+rjSIx9u7qVjf5VOoM/u6BbAxPY= -github.com/mfridman/interpolate v0.0.2/go.mod h1:p+7uk6oE07mpE/Ik1b8EckO0O4ZXiGAfshKBWLUM9Xg= -github.com/miekg/dns v1.1.65 h1:0+tIPHzUW0GCge7IiK3guGP57VAw7hoPDfApjkMD1Fc= -github.com/miekg/dns v1.1.65/go.mod h1:Dzw9769uoKVaLuODMDZz9M6ynFU6Em65csPuoi8G0ck= github.com/minio/asm2plan9s v0.0.0-20200509001527-cdd76441f9d8 h1:AMFGa4R4MiIpspGNG7Z948v4n35fFGB3RR3G/ry4FWs= github.com/minio/asm2plan9s v0.0.0-20200509001527-cdd76441f9d8/go.mod h1:mC1jAcsrzbxHt8iiaC+zU4b1ylILSosueou12R++wfY= github.com/minio/c2goasm v0.0.0-20190812172519-36a3d3bbc4f3 h1:+n/aFZefKZp7spd8DFdX7uMikMLXX4oubIzJF4kv/wI= @@ -698,12 +575,8 @@ github.com/minio/highwayhash v1.0.3 h1:kbnuUMoHYyVl7szWjSxJnxw11k2U709jqFPPmIUyD github.com/minio/highwayhash v1.0.3/go.mod h1:GGYsuwP/fPD6Y9hMiXuapVvlIUEhFhMTh0rxU3ik1LQ= github.com/minio/sha256-simd v1.0.1 h1:6kaan5IFmwTNynnKKpDHe6FWHohJOHhCPchzK49dzMM= github.com/minio/sha256-simd v1.0.1/go.mod h1:Pz6AKMiUdngCLpeTL/RJY1M9rUuPMYujV5xJjtbRSN8= -github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= -github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/mitchellh/go-testing-interface v1.14.1 h1:jrgshOhYAUVNMAJiKbEu7EqAwgJJ2JqpQmpLJOu07cU= github.com/mitchellh/go-testing-interface v1.14.1/go.mod h1:gfgS7OtZj6MA4U1UrDRp04twqAjfvlZyCfX3sDjEym8= -github.com/mitchellh/go-wordwrap v1.0.1 h1:TLuKupo69TCn6TQSyGxwI1EblZZEsQ0vMlAFQflz0v0= -github.com/mitchellh/go-wordwrap v1.0.1/go.mod h1:R62XHJLzvMFRBbcrT7m7WgmE1eOyTSsCt+hzestvNj0= github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/mitchellh/mapstructure v1.5.1-0.20220423185008-bf980b35cac4 h1:BpfhmLKZf+SjVanKKhCgf3bg+511DmU9eDQTen7LLbY= github.com/mitchellh/mapstructure v1.5.1-0.20220423185008-bf980b35cac4/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= @@ -730,8 +603,6 @@ github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLA github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= -github.com/oapi-codegen/runtime v1.1.2 h1:P2+CubHq8fO4Q6fV1tqDBZHCwpVpvPg7oKiYzQgXIyI= -github.com/oapi-codegen/runtime v1.1.2/go.mod h1:SK9X900oXmPWilYR5/WKPzt3Kqxn/uS/+lbpREv+eCg= github.com/oasisprotocol/curve25519-voi v0.0.0-20230904125328-1f23a7beb09a h1:dlRvE5fWabOchtH7znfiFCcOvmIYgOeAS5ifBXBlh9Q= github.com/oasisprotocol/curve25519-voi v0.0.0-20230904125328-1f23a7beb09a/go.mod h1:hVoHR2EVESiICEMbg137etN/Lx+lSrHPTD39Z/uE+2s= github.com/oklog/run v1.2.0 h1:O8x3yXwah4A73hJdlrwo/2X6J62gE5qTMusH0dvz60E= @@ -750,14 +621,8 @@ github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAl github.com/onsi/gomega v1.19.0/go.mod h1:LY+I3pBVzYsTBU1AnDwOSxaYi9WoWiqgwooUqq9yPro= github.com/onsi/gomega v1.36.2 h1:koNYke6TVk6ZmnyHrCXba/T/MoLBXFjeC1PtvYgw0A8= github.com/onsi/gomega v1.36.2/go.mod h1:DdwyADRjrc825LhMEkD76cHR5+pUnjhUN8GlHlRPHzY= -github.com/opentracing/opentracing-go v1.2.1-0.20220228012449-10b1cf09e00b h1:FfH+VrHHk6Lxt9HdVS0PXzSXFyS2NbZKXv33FYPol0A= -github.com/opentracing/opentracing-go v1.2.1-0.20220228012449-10b1cf09e00b/go.mod h1:AC62GU6hc0BrNm+9RK9VSiwa/EUe1bkIeFORAMcHvJU= github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY= github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= -github.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaRUnok+kx1WdO15EQc= -github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ= -github.com/pelletier/go-toml v1.9.5 h1:4yBQzkHv+7BHq2PQUZF3Mx0IYxG7LsP222s7Agd3ve8= -github.com/pelletier/go-toml v1.9.5/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= github.com/pelletier/go-toml/v2 v2.2.4 h1:mye9XuhQ6gvn5h28+VilKrrPoQVanw5PMw/TB0t5Ec4= github.com/pelletier/go-toml/v2 v2.2.4/go.mod h1:2gIqNv+qfxSVS7cM2xJQKtLSTLUE9V8t9Stt+h56mCY= github.com/peterh/liner v1.1.1-0.20190123174540-a2c9a5303de7 h1:oYW+YCJ1pachXTQmzR3rNLYGGz4g/UgFcjb28p/viDM= @@ -791,10 +656,6 @@ github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINE 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/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 h1:o4JXh1EVt9k/+g42oCprj/FisM4qX9L3sZB3upGN2ZU= -github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE= -github.com/pressly/goose/v3 v3.26.0 h1:KJakav68jdH0WDvoAcj8+n61WqOIaPGgH0bJWS6jpmM= -github.com/pressly/goose/v3 v3.26.0/go.mod h1:4hC1KrritdCxtuFsqgs1R4AU5bWtTAf+cnWvfhf2DNY= github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= github.com/prometheus/client_golang v1.4.0/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU= @@ -821,8 +682,6 @@ github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4O github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= github.com/prometheus/procfs v0.17.0 h1:FuLQ+05u4ZI+SS/w9+BWEM2TXiHKsUQ9TADiRH7DuK0= github.com/prometheus/procfs v0.17.0/go.mod h1:oPQLaDAMRbA+u8H5Pbfq+dl3VDAvHxMUOVhe0wYB2zw= -github.com/prometheus/prometheus v0.304.2 h1:HhjbaAwet87x8Be19PFI/5W96UMubGy3zt24kayEuh4= -github.com/prometheus/prometheus v0.304.2/go.mod h1:ioGx2SGKTY+fLnJSQCdTHqARVldGNS8OlIe3kvp98so= github.com/prysmaticlabs/gohashtree v0.0.4-beta h1:H/EbCuXPeTV3lpKeXGPpEV9gsUpkqOOVnWapUyeWro4= github.com/prysmaticlabs/gohashtree v0.0.4-beta/go.mod h1:BFdtALS+Ffhg3lGQIHv9HDWuHS8cTvHZzrHWxwOtGOs= github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475 h1:N/ElC8H3+5XpJzTSTfLsJV/mx9Q9g7kxmchpfZyxgzM= @@ -830,8 +689,6 @@ github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475/go.mod h1:bCqn github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ= github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= -github.com/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs= -github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro= github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= @@ -847,14 +704,8 @@ github.com/rs/zerolog v1.34.0 h1:k43nTLIwcTVQAncfCw4KZ2VY6ukYoZaBPNOE8txlOeY= github.com/rs/zerolog v1.34.0/go.mod h1:bJsvje4Z08ROH4Nhs5iH600c3IkWhwp44iRc54W6wYQ= github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= -github.com/ryanuber/go-glob v1.0.0 h1:iQh3xXAumdQ+4Ufa5b25cRpC5TYKlno6hsv6Cb3pkBk= -github.com/ryanuber/go-glob v1.0.0/go.mod h1:807d1WSdnB0XRJzKNil9Om6lcp/3a0v4qIHxIXzX/Yc= github.com/sagikazarmark/locafero v0.9.0 h1:GbgQGNtTrEmddYDSAH9QLRyfAHY12md+8YFTqyMTC9k= github.com/sagikazarmark/locafero v0.9.0/go.mod h1:UBUyz37V+EdMS3hDF3QWIiVr/2dPrx49OMO0Bn0hJqk= -github.com/samber/lo v1.49.1 h1:4BIFyVfuQSEpluc7Fua+j1NolZHiEHEpaSEKdsH0tew= -github.com/samber/lo v1.49.1/go.mod h1:dO6KHFzUKXgP8LDhU0oI8d2hekjXnGOu0DB8Jecxd6o= -github.com/sanity-io/litter v1.5.5 h1:iE+sBxPBzoK6uaEP5Lt3fHNgpKcHXc/A2HGETy0uJQo= -github.com/sanity-io/litter v1.5.5/go.mod h1:9gzJgR2i4ZpjZHsKvUXIRQVk7P+yM3e+jAF7bU2UI5U= github.com/santhosh-tekuri/jsonschema/v5 v5.3.1 h1:lZUw3E0/J3roVtGQ+SCrUrg3ON6NgVqpn3+iol9aGu4= github.com/santhosh-tekuri/jsonschema/v5 v5.3.1/go.mod h1:uToXkOrWAZ6/Oc07xWQrPOhJotwFIyu2bBVN41fcDUY= github.com/sasha-s/go-deadlock v0.3.5 h1:tNCOEEDG6tBqrNDOX35j/7hL5FcFViG6awUGROb2NsU= @@ -862,12 +713,8 @@ github.com/sasha-s/go-deadlock v0.3.5/go.mod h1:bugP6EGbdGYObIlx7pUZtWqlvo8k9H6v github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= github.com/scylladb/go-reflectx v1.0.1 h1:b917wZM7189pZdlND9PbIJ6NQxfDPfBvUaQ7cjj1iZQ= github.com/scylladb/go-reflectx v1.0.1/go.mod h1:rWnOfDIRWBGN0miMLIcoPt/Dhi2doCMZqwMCJ3KupFc= -github.com/sethvargo/go-retry v0.3.0 h1:EEt31A35QhrcRZtrYFDTBg91cqZVnFL2navjDrah2SE= -github.com/sethvargo/go-retry v0.3.0/go.mod h1:mNX17F0C/HguQMyMyJxcnU471gOZGxCLyYaFyAZraas= github.com/shirou/gopsutil v3.21.11+incompatible h1:+1+c1VGhc88SSonWP6foOcLhvnKlUeu/erjjvaPEYiI= github.com/shirou/gopsutil v3.21.11+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA= -github.com/shirou/gopsutil/v3 v3.24.3 h1:eoUGJSmdfLzJ3mxIhmOAhgKEKgQkeOwKpz1NbhVnuPE= -github.com/shirou/gopsutil/v3 v3.24.3/go.mod h1:JpND7O217xa72ewWz9zN2eIIkPWsDN/3pl0H8Qt0uwg= github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4= github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= github.com/shopspring/decimal v1.3.1/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= @@ -881,86 +728,22 @@ github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6Mwd github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= github.com/smartcontractkit/chain-selectors v1.0.89 h1:L9oWZGqQXWyTPnC6ODXgu3b0DFyLmJ9eHv+uJrE9IZY= github.com/smartcontractkit/chain-selectors v1.0.89/go.mod h1:qy7whtgG5g+7z0jt0nRyii9bLND9m15NZTzuQPkMZ5w= -github.com/smartcontractkit/chainlink-aptos v0.0.0-20251027153600-2b072ff3618e h1:HIgcJV/CyhBntE5gK/8WitVzqD0k8PkuYj+lhfa6B6U= -github.com/smartcontractkit/chainlink-aptos v0.0.0-20251027153600-2b072ff3618e/go.mod h1:iteU0WORHkArACVh/HoY/1bipV4TcNcJdTmom9uIT0E= -github.com/smartcontractkit/chainlink-automation v0.8.1 h1:sTc9LKpBvcKPc1JDYAmgBc2xpDKBco/Q4h4ydl6+UUU= -github.com/smartcontractkit/chainlink-automation v0.8.1/go.mod h1:Iij36PvWZ6blrdC5A/nrQUBuf3MH3JvsBB9sSyc9W08= -github.com/smartcontractkit/chainlink-ccip v0.1.1-solana.0.20251128020529-88d93b01d749 h1:2Cn3OA7vJxXyR/U9JHFGwa8H8YKTPFxNlMrFNb8f46g= -github.com/smartcontractkit/chainlink-ccip v0.1.1-solana.0.20251128020529-88d93b01d749/go.mod h1:pETrvAF8uvkZgtDgI/oRllZZaC4IpPO26tMxh1u9LC4= -github.com/smartcontractkit/chainlink-ccip/ccv/chains/evm v0.0.0-20251229170147-e243de8c69ad h1:1GHqHUo/ZRrJUDNVAGJ9Ff7RTp5NxtMHSykZWVePAbM= -github.com/smartcontractkit/chainlink-ccip/ccv/chains/evm v0.0.0-20251229170147-e243de8c69ad/go.mod h1:Gl35ExaFLinqVhp50+Yq1GnMuHb3fnDtZUFPCtcfV3M= -github.com/smartcontractkit/chainlink-ccip/chains/solana v0.0.0-20250912190424-fd2e35d7deb5 h1:f8ak6g6P2KT4HjUbleU+Bh0gUJXMoGuoriMSyGxxD4M= -github.com/smartcontractkit/chainlink-ccip/chains/solana v0.0.0-20250912190424-fd2e35d7deb5/go.mod h1:Ve1xD71bl193YIZQEoJMmBqLGQJdNs29bwbuObwvbhQ= -github.com/smartcontractkit/chainlink-ccip/chains/solana/gobindings v0.0.0-20250912190424-fd2e35d7deb5 h1:Z4t2ZY+ZyGWxtcXvPr11y4o3CGqhg3frJB5jXkCSvWA= -github.com/smartcontractkit/chainlink-ccip/chains/solana/gobindings v0.0.0-20250912190424-fd2e35d7deb5/go.mod h1:xtZNi6pOKdC3sLvokDvXOhgHzT+cyBqH/gWwvxTxqrg= -github.com/smartcontractkit/chainlink-ccv v0.0.0-20260106165728-3d896e87cc56 h1:M6eS2r11Vbbll/bve5Us17cNYDlgs+dvrggPFVnhrgQ= -github.com/smartcontractkit/chainlink-ccv v0.0.0-20260106165728-3d896e87cc56/go.mod h1:6N8NSPmsy+sxtRBmBUwWlDyxPyauS7HMDzUl/lyJw7Y= github.com/smartcontractkit/chainlink-common/pkg/chipingress v0.0.10 h1:FJAFgXS9oqASnkS03RE1HQwYQQxrO4l46O5JSzxqLgg= github.com/smartcontractkit/chainlink-common/pkg/chipingress v0.0.10/go.mod h1:oiDa54M0FwxevWwyAX773lwdWvFYYlYHHQV1LQ5HpWY= -github.com/smartcontractkit/chainlink-data-streams v0.1.10 h1:YCwQNCcxFuoR714NV5UJ8oNwG/1j2PETUfZFssonTT8= -github.com/smartcontractkit/chainlink-data-streams v0.1.10/go.mod h1:8rUcGhjeXBoTFx2MynWgXiBWzVSB+LXd9JR6m8y2FfQ= github.com/smartcontractkit/chainlink-evm v0.3.4-0.20260205183656-836ec9472717 h1:OiR/E3lq1jMlA6B9mqhom0f2JeNJOCIxbbyktBlR+Fg= github.com/smartcontractkit/chainlink-evm v0.3.4-0.20260205183656-836ec9472717/go.mod h1:jBZMFIz1C3sq/YyuTgk5MCu12SdHP+PcujdojZsSk6g= -github.com/smartcontractkit/chainlink-evm/gethwrappers v0.0.0-20251211123524-f0c4fe7cfc0a h1:kVKWRGrSCioMY2lEVIEblerv/KkINIQS2hLUOw2wKOg= -github.com/smartcontractkit/chainlink-evm/gethwrappers v0.0.0-20251211123524-f0c4fe7cfc0a/go.mod h1:oyfOm4k0uqmgZIfxk1elI/59B02shbbJQiiUdPdbMgI= -github.com/smartcontractkit/chainlink-feeds v0.1.2-0.20250227211209-7cd000095135 h1:8u9xUrC+yHrTDexOKDd+jrA6LCzFFHeX1G82oj2fsSI= -github.com/smartcontractkit/chainlink-feeds v0.1.2-0.20250227211209-7cd000095135/go.mod h1:NkvE4iQgiT7dMCP6U3xPELHhWhN5Xr6rHC0axRebyMU= -github.com/smartcontractkit/chainlink-framework/capabilities v0.0.0-20250818175541-3389ac08a563 h1:ACpDbAxG4fa4sA83dbtYcrnlpE/y7thNIZfHxTv2ZLs= -github.com/smartcontractkit/chainlink-framework/capabilities v0.0.0-20250818175541-3389ac08a563/go.mod h1:jP5mrOLFEYZZkl7EiCHRRIMSSHCQsYypm1OZSus//iI= github.com/smartcontractkit/chainlink-framework/chains v0.0.0-20251210101658-1c5c8e4c4f15 h1:Mf+IRvrXutcKAKpuOxq5Ae+AAw4Z5vc66q1xI7qimZQ= github.com/smartcontractkit/chainlink-framework/chains v0.0.0-20251210101658-1c5c8e4c4f15/go.mod h1:kGprqyjsz6qFNVszOQoHc24wfvCjyipNZFste/3zcbs= -github.com/smartcontractkit/chainlink-framework/metrics v0.0.0-20251206233640-139a324649d9 h1:TAVreQK5eP63a0zu5Qe34i4pYGGo5x8zgfJ1NVVo6K4= -github.com/smartcontractkit/chainlink-framework/metrics v0.0.0-20251206233640-139a324649d9/go.mod h1:HG/aei0MgBOpsyRLexdKGtOUO8yjSJO3iUu0Uu8KBm4= -github.com/smartcontractkit/chainlink-framework/multinode v0.0.0-20251021173435-e86785845942 h1:T/eCDsUI8EJT4n5zSP4w1mz4RHH+ap8qieA17QYfBhk= -github.com/smartcontractkit/chainlink-framework/multinode v0.0.0-20251021173435-e86785845942/go.mod h1:2JTBNp3FlRdO/nHc4dsc9bfxxMClMO1Qt8sLJgtreBY= -github.com/smartcontractkit/chainlink-protos/billing/go v0.0.0-20251024234028-0988426d98f4 h1:GCzrxDWn3b7jFfEA+WiYRi8CKoegsayiDoJBCjYkneE= -github.com/smartcontractkit/chainlink-protos/billing/go v0.0.0-20251024234028-0988426d98f4/go.mod h1:HHGeDUpAsPa0pmOx7wrByCitjQ0mbUxf0R9v+g67uCA= -github.com/smartcontractkit/chainlink-protos/chainlink-ccv/committee-verifier v0.0.0-20251211142334-5c3421fe2c8d h1:VYoBBNnQpZ5p+enPTl8SkKBRaubqyGpO0ul3B1np++I= -github.com/smartcontractkit/chainlink-protos/chainlink-ccv/committee-verifier v0.0.0-20251211142334-5c3421fe2c8d/go.mod h1:oNFoKHRIerxuaANa8ASNejtHrdsG26LqGtQ2XhSac2g= -github.com/smartcontractkit/chainlink-protos/chainlink-ccv/message-discovery v0.0.0-20251211142334-5c3421fe2c8d h1:pKCyW7BYzO5GThFNlXZY0Azx/yOnI4b5GeuLeU23ie0= -github.com/smartcontractkit/chainlink-protos/chainlink-ccv/message-discovery v0.0.0-20251211142334-5c3421fe2c8d/go.mod h1:ATjAPIVJibHRcIfiG47rEQkUIOoYa6KDvWj3zwCAw6g= -github.com/smartcontractkit/chainlink-protos/chainlink-ccv/verifier v0.0.0-20251211142334-5c3421fe2c8d h1:AJy55QJ/pBhXkZjc7N+ATnWfxrcjq9BI9DmdtdjwDUQ= -github.com/smartcontractkit/chainlink-protos/chainlink-ccv/verifier v0.0.0-20251211142334-5c3421fe2c8d/go.mod h1:5JdppgngCOUS76p61zCinSCgOhPeYQ+OcDUuome5THQ= github.com/smartcontractkit/chainlink-protos/cre/go v0.0.0-20260206000552-087e235a7963 h1:DCLvEn4KkFzYbK/AYl4vJmf6EHaskPYvGDGdd0kOma0= github.com/smartcontractkit/chainlink-protos/cre/go v0.0.0-20260206000552-087e235a7963/go.mod h1:Jqt53s27Tr0jDl8mdBXg1xhu6F8Fci8JOuq43tgHOM8= github.com/smartcontractkit/chainlink-protos/linking-service/go v0.0.0-20251002192024-d2ad9222409b h1:QuI6SmQFK/zyUlVWEf0GMkiUYBPY4lssn26nKSd/bOM= github.com/smartcontractkit/chainlink-protos/linking-service/go v0.0.0-20251002192024-d2ad9222409b/go.mod h1:qSTSwX3cBP3FKQwQacdjArqv0g6QnukjV4XuzO6UyoY= -github.com/smartcontractkit/chainlink-protos/node-platform v0.0.0-20260205130626-db2a2aab956b h1:36knUpKHHAZ86K4FGWXtx8i/EQftGdk2bqCoEu/Cha8= -github.com/smartcontractkit/chainlink-protos/node-platform v0.0.0-20260205130626-db2a2aab956b/go.mod h1:dkR2uYg9XYJuT1JASkPzWE51jjFkVb86P7a/yXe5/GM= -github.com/smartcontractkit/chainlink-protos/orchestrator v0.10.0 h1:0eroOyBwmdoGUwUdvMI0/J7m5wuzNnJDMglSOK1sfNY= -github.com/smartcontractkit/chainlink-protos/orchestrator v0.10.0/go.mod h1:m/A3lqD7ms/RsQ9BT5P2uceYY0QX5mIt4KQxT2G6qEo= -github.com/smartcontractkit/chainlink-protos/rmn/v1.6/go v0.0.0-20250131130834-15e0d4cde2a6 h1:L6KJ4kGv/yNNoCk8affk7Y1vAY0qglPMXC/hevV/IsA= -github.com/smartcontractkit/chainlink-protos/rmn/v1.6/go v0.0.0-20250131130834-15e0d4cde2a6/go.mod h1:FRwzI3hGj4CJclNS733gfcffmqQ62ONCkbGi49s658w= -github.com/smartcontractkit/chainlink-protos/storage-service v0.3.0 h1:B7itmjy+CMJ26elVw/cAJqqhBQ3Xa/mBYWK0/rQ5MuI= -github.com/smartcontractkit/chainlink-protos/storage-service v0.3.0/go.mod h1:h6kqaGajbNRrezm56zhx03p0mVmmA2xxj7E/M4ytLUA= -github.com/smartcontractkit/chainlink-protos/svr v1.1.1-0.20260203131522-bb8bc5c423b3 h1:X8Pekpv+cy0eW1laZTwATuYLTLZ6gRTxz1ZWOMtU74o= -github.com/smartcontractkit/chainlink-protos/svr v1.1.1-0.20260203131522-bb8bc5c423b3/go.mod h1:TcOliTQU6r59DwG4lo3U+mFM9WWyBHGuFkkxQpvSujo= -github.com/smartcontractkit/chainlink-protos/workflows/go v0.0.0-20260205231316-3b9c600dd791 h1:S+yHuhcny3AKOhCekMQa65uUeR/p9rGrUIb8eifkSTY= -github.com/smartcontractkit/chainlink-protos/workflows/go v0.0.0-20260205231316-3b9c600dd791/go.mod h1:GTpDgyK0OObf7jpch6p8N281KxN92wbB8serZhU9yRc= -github.com/smartcontractkit/chainlink-solana v1.1.2-0.20251121223352-370eb61346d6 h1:4cvFf82P3VcNHgqUG0aRBeIMZd+wSX37ha28Gkie9Lk= -github.com/smartcontractkit/chainlink-solana v1.1.2-0.20251121223352-370eb61346d6/go.mod h1:zX8dX6aXjJNkfbpr1AiTzCioma0sHh5CBPZKtqC7plY= -github.com/smartcontractkit/chainlink-sui v0.0.0-20251205161630-88314452254c h1:aNA7J31EuOf755BDgNuhxte5+Z6wucBx/ONGihw2OqA= -github.com/smartcontractkit/chainlink-sui v0.0.0-20251205161630-88314452254c/go.mod h1:zrtmeh3wHL+qXu/vaaR7lZ5TSh00I4JYbpOqqb9bXp0= -github.com/smartcontractkit/chainlink-ton v0.0.0-20251219221624-54a39a031e62 h1:/gnBkA9Ph6+EaWoBuR7FE8UIKfegY7eP3+QhxvVTYxw= -github.com/smartcontractkit/chainlink-ton v0.0.0-20251219221624-54a39a031e62/go.mod h1:z27AgU6fEXkkfmUAzcbEH9u3RKz2oaGy3isb7KK6Z2E= -github.com/smartcontractkit/chainlink-tron/relayer v0.0.11-0.20251014143056-a0c6328c91e9 h1:7Ut0g+Pdm+gcu2J/Xv8OpQOVf7uLGErMX8yhC4b4tIA= -github.com/smartcontractkit/chainlink-tron/relayer v0.0.11-0.20251014143056-a0c6328c91e9/go.mod h1:h9hMs6K4hT1+mjYnJD3/SW1o7yC/sKjNi0Qh8hLfiCE= -github.com/smartcontractkit/chainlink-tron/relayer/gotron-sdk v0.0.5-0.20251014124537-af6b1684fe15 h1:idp/RjsFznR48JWGfZICsrpcl9JTrnMzoUNVz8MhQMI= -github.com/smartcontractkit/chainlink-tron/relayer/gotron-sdk v0.0.5-0.20251014124537-af6b1684fe15/go.mod h1:ea1LESxlSSOgc2zZBqf1RTkXTMthHaspdqUHd7W4lF0= -github.com/smartcontractkit/chainlink/v2 v2.32.0 h1:Fax3JOIAa0uvthgLsd34ktekmSkrDMP2rl0/KFVugcY= -github.com/smartcontractkit/chainlink/v2 v2.32.0/go.mod h1:MIh2RAuTXdC3voDTo5+AtPyJPQfeIH5hkBDZQ0P1tjg= github.com/smartcontractkit/freeport v0.1.3-0.20250716200817-cb5dfd0e369e h1:Hv9Mww35LrufCdM9wtS9yVi/rEWGI1UnjHbcKKU0nVY= github.com/smartcontractkit/freeport v0.1.3-0.20250716200817-cb5dfd0e369e/go.mod h1:T4zH9R8R8lVWKfU7tUvYz2o2jMv1OpGCdpY2j2QZXzU= -github.com/smartcontractkit/grpc-proxy v0.0.0-20240830132753-a7e17fec5ab7 h1:12ijqMM9tvYVEm+nR826WsrNi6zCKpwBhuApq127wHs= -github.com/smartcontractkit/grpc-proxy v0.0.0-20240830132753-a7e17fec5ab7/go.mod h1:FX7/bVdoep147QQhsOPkYsPEXhGZjeYx6lBSaSXtZOA= github.com/smartcontractkit/libocr v0.0.0-20251212213002-0a5e2f907dda h1:OjM+79FRuVZlj0Qd4y+q8Xmz/tEn5y8npqmiQiMMj+w= github.com/smartcontractkit/libocr v0.0.0-20251212213002-0a5e2f907dda/go.mod h1:oJkBKVn8zoBQm7Feah9CiuEHyCqAhnp1LJBzrvloQtM= github.com/smartcontractkit/smdkg v0.0.0-20251029093710-c38905e58aeb h1:kLHdQQkijaPGsBbtV2rJgpzVpQ96e7T10pzjNlWfK8U= github.com/smartcontractkit/smdkg v0.0.0-20251029093710-c38905e58aeb/go.mod h1:4s5hj/nlMF9WV+T5Uhy4n9IYpRpzfJzT+vTKkNT7T+Y= -github.com/smartcontractkit/tdh2/go/ocr2/decryptionplugin v0.0.0-20241009055228-33d0c0bf38de h1:n0w0rKF+SVM+S3WNlup6uabXj2zFlFNfrlsKCMMb/co= -github.com/smartcontractkit/tdh2/go/ocr2/decryptionplugin v0.0.0-20241009055228-33d0c0bf38de/go.mod h1:Sl2MF/Fp3fgJIVzhdGhmZZX2BlnM0oUUyBP4s4xYb6o= -github.com/smartcontractkit/tdh2/go/tdh2 v0.0.0-20251120172354-e8ec0386b06c h1:S1AFIjfHT95ev6gqHKBGy1zj3Tz0fIN3XzkaDUn77wY= -github.com/smartcontractkit/tdh2/go/tdh2 v0.0.0-20251120172354-e8ec0386b06c/go.mod h1:NSc7hgOQbXG3DAwkOdWnZzLTZENXSwDJ7Va1nBp0YU0= github.com/smartcontractkit/wsrpc v0.8.5-0.20250502134807-c57d3d995945 h1:zxcODLrFytOKmAd8ty8S/XK6WcIEJEgRBaL7sY/7l4Y= github.com/smartcontractkit/wsrpc v0.8.5-0.20250502134807-c57d3d995945/go.mod h1:m3pdp17i4bD50XgktkzWetcV5yaLsi7Gunbv4ZgN6qg= github.com/sourcegraph/conc v0.3.0 h1:OQTbbt6P72L20UqAkXXuLOj79LfEanQ+YQFNpLA9ySo= @@ -976,8 +759,6 @@ github.com/spf13/pflag v1.0.10 h1:4EBh2KAYBwaONj6b2Ye1GiHfwjqyROoF4RwYO+vPwFk= github.com/spf13/pflag v1.0.10/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/spf13/viper v1.20.1 h1:ZMi+z/lvLyPSCoNtFCpqjy0S4kPbirhpTMwl8BkW9X4= github.com/spf13/viper v1.20.1/go.mod h1:P9Mdzt1zoHIG8m2eZQinpiBjo6kCmZSKBClNNqjJvu4= -github.com/stephenlacy/go-ethereum-hdwallet v0.0.0-20230913225845-a4fa94429863 h1:ba4VRWSkRzgdP5hB5OxexIzBXZbSwgcw8bEu06ivGQI= -github.com/stephenlacy/go-ethereum-hdwallet v0.0.0-20230913225845-a4fa94429863/go.mod h1:oPTjPNrRucLv9mU27iNPj6n0CWWcNFhoXFOLVGJwHCA= github.com/streamingfast/logging v0.0.0-20230608130331-f22c91403091 h1:RN5mrigyirb8anBEtdjtHFIufXdacyTi6i4KBfeNXeo= github.com/streamingfast/logging v0.0.0-20230608130331-f22c91403091/go.mod h1:VlduQ80JcGJSargkRU4Sg9Xo63wZD/l8A5NC/Uo1/uU= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= @@ -1012,8 +793,6 @@ github.com/tendermint/go-amino v0.16.0 h1:GyhmgQKvqF82e2oZeuMSp9JTN0N09emoSZlb2l github.com/tendermint/go-amino v0.16.0/go.mod h1:TQU0M1i/ImAo+tYpZi73AU3V/dKeCoMC9Sphe2ZwGME= github.com/test-go/testify v1.1.4 h1:Tf9lntrKUMHiXQ07qBScBTSA0dhYQlu83hswqelv1iE= github.com/test-go/testify v1.1.4/go.mod h1:rH7cfJo/47vWGdi4GPj16x3/t1xGOj2YxzmNQzk2ghU= -github.com/theodesp/go-heaps v0.0.0-20190520121037-88e35354fe0a h1:YuO+afVc3eqrjiCUizNCxI53bl/BnPiVwXqLzqYTqgU= -github.com/theodesp/go-heaps v0.0.0-20190520121037-88e35354fe0a/go.mod h1:/sfW47zCZp9FrtGcWyo1VjbgDaodxX9ovZvgLb/MxaA= github.com/tidwall/btree v1.7.0 h1:L1fkJH/AuEh5zBnnBbmTwQ5Lt+bRJ5A8EWecslvo9iI= github.com/tidwall/btree v1.7.0/go.mod h1:twD9XRA5jj9VUQGELzDO4HPQTNJsoWWfYEL+EUQ2cKY= github.com/tidwall/gjson v1.18.0 h1:FIDeeyB800efLX89e5a8Y0BNH+LOngJyGrIWxG2FKQY= @@ -1030,16 +809,8 @@ github.com/tklauser/numcpus v0.10.0/go.mod h1:BiTKazU708GQTYF4mB+cmlpT2Is1gLk7XV github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM= github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI= github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08= -github.com/tyler-smith/go-bip39 v1.1.0 h1:5eUemwrMargf3BSLRRCalXT93Ns6pQJIjYQN2nyfOP8= -github.com/tyler-smith/go-bip39 v1.1.0/go.mod h1:gUYDtqQw1JS3ZJ8UWVcGTGqqr6YIN3CWg+kkNaLt55U= github.com/ugorji/go/codec v1.2.12 h1:9LC83zGrHhuUA9l16C9AHXAqEV/2wBQ4nkvumAE65EE= github.com/ugorji/go/codec v1.2.12/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= -github.com/ulule/limiter/v3 v3.11.2 h1:P4yOrxoEMJbOTfRJR2OzjL90oflzYPPmWg+dvwN2tHA= -github.com/ulule/limiter/v3 v3.11.2/go.mod h1:QG5GnFOCV+k7lrL5Y8kgEeeflPH3+Cviqlqa8SVSQxI= -github.com/unrolled/secure v1.13.0 h1:sdr3Phw2+f8Px8HE5sd1EHdj1aV3yUwed/uZXChLFsk= -github.com/unrolled/secure v1.13.0/go.mod h1:BmF5hyM6tXczk3MpQkFf1hpKSRqCyhqcbiQtiAF7+40= -github.com/urfave/cli v1.22.14 h1:ebbhrRiGK2i4naQJr+1Xj92HXZCrK7MsyTS/ob3HnAk= -github.com/urfave/cli v1.22.14/go.mod h1:X0eDS6pD6Exaclxm99NJ3FiCDRED7vIHpx2mDOHLvkA= github.com/urfave/cli/v2 v2.27.6 h1:VdRdS98FNhKZ8/Az8B7MTyGQmpIr36O1EHybx/LaZ4g= github.com/urfave/cli/v2 v2.27.6/go.mod h1:3Sevf16NykTbInEnD0yKkjDAeZDS0A6bzhBH5hrMvTQ= github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= @@ -1058,6 +829,7 @@ github.com/xssnick/tonutils-go v1.14.1/go.mod h1:68xwWjpoGGqiTbLJ0gT63sKu1Z1moCn github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= +github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= github.com/yusufpapurcu/wmi v1.2.4 h1:zFUKzehAFReQwLys1b/iSMl+JQGSCSjtVqQn9bBrPo0= github.com/yusufpapurcu/wmi v1.2.4/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0= @@ -1066,8 +838,6 @@ github.com/zeebo/assert v1.3.0/go.mod h1:Pq9JiuJQpG8JLJdtkwrJESF0Foym2/D9XMU5ciN github.com/zeebo/xxh3 v1.0.2 h1:xZmwmqxHZA8AI603jOQ0tMqmBr9lPeFwGg6d+xy9DC0= github.com/zeebo/xxh3 v1.0.2/go.mod h1:5NWz9Sef7zIDm2JHfFlcQvNekmcEl9ekUZQQKCYaDcA= github.com/zenazn/goji v0.9.0/go.mod h1:7S9M489iMyHBNxwZnk9/EHS098H4/F6TATF2mIxtB1Q= -github.com/zksync-sdk/zksync2-go v1.1.1-0.20250620124214-2c742ee399c6 h1:VRdX3Gn/I7ITbzUY4ZNfgn65tdQM9Zhf2b7KP0HZllk= -github.com/zksync-sdk/zksync2-go v1.1.1-0.20250620124214-2c742ee399c6/go.mod h1:NWNlQS21isOsSsn+hLRAPpiuv+3P+LcdaZNuRt2T5Yo= github.com/zondax/golem v0.27.0 h1:IbBjGIXF3SoGOZHsILJvIM/F/ylwJzMcHAcggiqniPw= github.com/zondax/golem v0.27.0/go.mod h1:AmorCgJPt00L8xN1VrMBe13PSifoZksnQ1Ge906bu4A= github.com/zondax/hid v0.9.2 h1:WCJFnEDMiqGF64nlZz28E9qLVZ0KSJ7xpc5DLEyma2U= @@ -1089,8 +859,6 @@ go.mongodb.org/mongo-driver v1.17.2 h1:gvZyk8352qSfzyZ2UMWcpDpMSGEr1eqE4T793Sqyh go.mongodb.org/mongo-driver v1.17.2/go.mod h1:Hy04i7O2kC4RS06ZrhPRqj/u4DTYkFDAAccj+rVKqgQ= go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64= go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y= -go.opentelemetry.io/contrib/instrumentation/github.com/gin-gonic/gin/otelgin v0.49.0 h1:1f31+6grJmV3X4lxcEvUy13i5/kfDw1nJZwhd8mA4tg= -go.opentelemetry.io/contrib/instrumentation/github.com/gin-gonic/gin/otelgin v0.49.0/go.mod h1:1P/02zM3OwkX9uki+Wmxw3a5GVb6KUXRsa7m7bOC9Fg= go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.63.0 h1:YH4g8lQroajqUwWbq/tr2QX1JFmEXaDLgG+ew9bLMWo= go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.63.0/go.mod h1:fvPi2qXDqFs8M4B4fmJhE92TyQs9Ydjlg3RvfUp+NbQ= go.opentelemetry.io/otel v1.39.0 h1:8yPrr/S0ND9QEfTfdP9V+SiwT4E0G7Y5MO7p85nis48= @@ -1145,8 +913,6 @@ go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKY go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= -go.uber.org/ratelimit v0.3.1 h1:K4qVE+byfv/B3tC+4nYWP7v/6SimcO7HzHekoMNBma0= -go.uber.org/ratelimit v0.3.1/go.mod h1:6euWsTB6U/Nb3X++xEUXA8ciPJvr19Q/0h1+oDcJhRk= go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA= go.uber.org/zap v1.9.1/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= @@ -1193,6 +959,7 @@ golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzB golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.32.0 h1:9F4d3PHLljb6x//jOyokMv3eX+YDeepZSEo3mFJy93c= @@ -1216,6 +983,7 @@ golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwY golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk= +golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220607020251-c690dde0001d/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= @@ -1231,8 +999,6 @@ golang.org/x/net v0.49.0/go.mod h1:/ysNB2EvaqvesRkuLAyjI1ycPZlQHM3q01F02UY/MV8= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.32.0 h1:jsCblLleRMDrxMN29H3z/k1KliIvpLgCkE6R8FXXNgY= -golang.org/x/oauth2 v0.32.0/go.mod h1:lzm5WQJQwKZ3nwavOZ3IS5Aulzxi68dUSgRHujetwEA= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -1279,6 +1045,7 @@ golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -1338,6 +1105,7 @@ golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roY golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.8/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= golang.org/x/tools v0.41.0 h1:a9b8iMweWG+S0OBnlU36rzLp20z1Rp10w+IY2czHTQc= From 7da1cb90608baad5b49920518086bfd8ea22522d Mon Sep 17 00:00:00 2001 From: pavel-raykov Date: Tue, 10 Feb 2026 10:19:02 +0100 Subject: [PATCH 09/13] Minor. --- keystore/corekeys/models/legacy_key.go | 2 +- keystore/corekeys/models/models.go | 40 +++++++++++++------------- 2 files changed, 21 insertions(+), 21 deletions(-) diff --git a/keystore/corekeys/models/legacy_key.go b/keystore/corekeys/models/legacy_key.go index bc9aeab104..915062740d 100644 --- a/keystore/corekeys/models/legacy_key.go +++ b/keystore/corekeys/models/legacy_key.go @@ -37,7 +37,7 @@ func (rlk *rawLegacyKeys) hasValueInField(fieldName, value string) bool { // StoreUnsupported will store the raw keys that no longer have support in the node // it will check if raw json contains keys that have not been added to the key ring // and stores them internally -func (k *LegacyKeyStorage) StoreUnsupported(allRawKeysJson []byte, keyRing *keyRing) error { +func (k *LegacyKeyStorage) StoreUnsupported(allRawKeysJson []byte, keyRing *KeyRing) error { if keyRing == nil { return errors.New("keyring is nil") } diff --git a/keystore/corekeys/models/models.go b/keystore/corekeys/models/models.go index 59a668b87a..2ad9a6e2ea 100644 --- a/keystore/corekeys/models/models.go +++ b/keystore/corekeys/models/models.go @@ -31,12 +31,12 @@ import ( "github.com/smartcontractkit/chainlink-common/keystore/scrypt" ) -type encryptedKeyRing struct { +type EncryptedKeyRing struct { UpdatedAt time.Time EncryptedKeys []byte } -func (ekr encryptedKeyRing) Decrypt(password string) (*keyRing, error) { +func (ekr EncryptedKeyRing) Decrypt(password string) (*KeyRing, error) { if len(ekr.EncryptedKeys) == 0 { return NewKeyRing(), nil } @@ -68,7 +68,7 @@ func (ekr encryptedKeyRing) Decrypt(password string) (*keyRing, error) { return ring, nil } -type keyStates struct { +type KeyStates struct { // Key ID => chain ID => state KeyIDChainID map[string]map[string]*ethkey.State // Chain ID => Key ID => state @@ -76,8 +76,8 @@ type keyStates struct { All []*ethkey.State } -func NewKeyStates() *keyStates { - return &keyStates{ +func NewKeyStates() *KeyStates { + return &KeyStates{ KeyIDChainID: make(map[string]map[string]*ethkey.State), ChainIDKeyID: make(map[string]map[string]*ethkey.State), } @@ -85,7 +85,7 @@ func NewKeyStates() *keyStates { // warning: not thread-safe! caller must sync // adds or replaces a state -func (ks *keyStates) add(state *ethkey.State) { +func (ks *KeyStates) add(state *ethkey.State) { cid := state.EVMChainID.String() kid := state.KeyID() @@ -117,7 +117,7 @@ func (ks *keyStates) add(state *ethkey.State) { } // warning: not thread-safe! caller must sync -func (ks *keyStates) get(addr common.Address, chainID *big.Int) *ethkey.State { +func (ks *KeyStates) get(addr common.Address, chainID *big.Int) *ethkey.State { chainStates, exists := ks.KeyIDChainID[addr.Hex()] if !exists { return nil @@ -126,21 +126,21 @@ func (ks *keyStates) get(addr common.Address, chainID *big.Int) *ethkey.State { } // warning: not thread-safe! caller must sync -func (ks *keyStates) disable(addr common.Address, chainID *big.Int, updatedAt time.Time) { +func (ks *KeyStates) disable(addr common.Address, chainID *big.Int, updatedAt time.Time) { state := ks.get(addr, chainID) state.Disabled = true state.UpdatedAt = updatedAt } // warning: not thread-safe! caller must sync -func (ks *keyStates) enable(addr common.Address, chainID *big.Int, updatedAt time.Time) { +func (ks *KeyStates) enable(addr common.Address, chainID *big.Int, updatedAt time.Time) { state := ks.get(addr, chainID) state.Disabled = false state.UpdatedAt = updatedAt } // warning: not thread-safe! caller must sync -func (ks *keyStates) delete(addr common.Address) { +func (ks *KeyStates) delete(addr common.Address) { var chainIDs []*big.Int for i := len(ks.All) - 1; i >= 0; i-- { if ks.All[i].Address.Address() == addr { @@ -154,7 +154,7 @@ func (ks *keyStates) delete(addr common.Address) { } } -type keyRing struct { +type KeyRing struct { CSA map[string]csakey.KeyV2 Eth map[string]ethkey.KeyV2 OCR map[string]ocrkey.KeyV2 @@ -173,8 +173,8 @@ type keyRing struct { LegacyKeys LegacyKeyStorage } -func NewKeyRing() *keyRing { - return &keyRing{ +func NewKeyRing() *KeyRing { + return &KeyRing{ CSA: make(map[string]csakey.KeyV2), Eth: make(map[string]ethkey.KeyV2), OCR: make(map[string]ocrkey.KeyV2), @@ -193,7 +193,7 @@ func NewKeyRing() *keyRing { } } -func (kr *keyRing) Encrypt(password string, scryptParams scrypt.ScryptParams) (ekr encryptedKeyRing, err error) { +func (kr *KeyRing) Encrypt(password string, scryptParams scrypt.ScryptParams) (ekr EncryptedKeyRing, err error) { marshalledRawKeyRingJson, err := json.Marshal(kr.raw()) if err != nil { return ekr, err @@ -201,7 +201,7 @@ func (kr *keyRing) Encrypt(password string, scryptParams scrypt.ScryptParams) (e marshalledRawKeyRingJson, err = kr.LegacyKeys.UnloadUnsupported(marshalledRawKeyRingJson) if err != nil { - return encryptedKeyRing{}, err + return EncryptedKeyRing{}, err } cryptoJSON, err := gethkeystore.EncryptDataV3( @@ -217,12 +217,12 @@ func (kr *keyRing) Encrypt(password string, scryptParams scrypt.ScryptParams) (e if err != nil { return ekr, errors.Wrapf(err, "could not encode cryptoJSON") } - return encryptedKeyRing{ + return EncryptedKeyRing{ EncryptedKeys: encryptedKeys, }, nil } -func (kr *keyRing) raw() (rawKeys rawKeyRing) { +func (kr *KeyRing) raw() (rawKeys rawKeyRing) { for _, csaKey := range kr.CSA { rawKeys.CSA = append(rawKeys.CSA, internal.RawBytes(csaKey)) } @@ -271,7 +271,7 @@ func (kr *keyRing) raw() (rawKeys rawKeyRing) { return rawKeys } -func (kr *keyRing) logPubKeys(lggr logger.Logger) { +func (kr *KeyRing) logPubKeys(lggr logger.Logger) { lggr = logger.Named(lggr, "KeyRing") var csaIDs []string for _, CSAKey := range kr.CSA { @@ -385,7 +385,7 @@ func (kr *keyRing) logPubKeys(lggr logger.Logger) { } } -// rawKeyRing is an intermediate struct for encrypting / decrypting keyRing +// rawKeyRing is an intermediate struct for encrypting / decrypting KeyRing // it holds only the essential key information to avoid adding unnecessary data // (like public keys) to the database type rawKeyRing struct { @@ -407,7 +407,7 @@ type rawKeyRing struct { LegacyKeys LegacyKeyStorage `json:"-"` } -func (rawKeys rawKeyRing) keys() (*keyRing, error) { +func (rawKeys rawKeyRing) keys() (*KeyRing, error) { keyRing := NewKeyRing() for _, rawCSAKey := range rawKeys.CSA { csaKey := csakey.KeyFor(internal.NewRaw(rawCSAKey)) From dc57c7844b9def449161881301e1a2da29e74350 Mon Sep 17 00:00:00 2001 From: pavel-raykov Date: Tue, 10 Feb 2026 10:24:43 +0100 Subject: [PATCH 10/13] Minor. --- keystore/corekeys/models/models.go | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/keystore/corekeys/models/models.go b/keystore/corekeys/models/models.go index 2ad9a6e2ea..59b85ea838 100644 --- a/keystore/corekeys/models/models.go +++ b/keystore/corekeys/models/models.go @@ -85,7 +85,7 @@ func NewKeyStates() *KeyStates { // warning: not thread-safe! caller must sync // adds or replaces a state -func (ks *KeyStates) add(state *ethkey.State) { +func (ks *KeyStates) Add(state *ethkey.State) { cid := state.EVMChainID.String() kid := state.KeyID() @@ -117,7 +117,7 @@ func (ks *KeyStates) add(state *ethkey.State) { } // warning: not thread-safe! caller must sync -func (ks *KeyStates) get(addr common.Address, chainID *big.Int) *ethkey.State { +func (ks *KeyStates) Get(addr common.Address, chainID *big.Int) *ethkey.State { chainStates, exists := ks.KeyIDChainID[addr.Hex()] if !exists { return nil @@ -126,21 +126,21 @@ func (ks *KeyStates) get(addr common.Address, chainID *big.Int) *ethkey.State { } // warning: not thread-safe! caller must sync -func (ks *KeyStates) disable(addr common.Address, chainID *big.Int, updatedAt time.Time) { - state := ks.get(addr, chainID) +func (ks *KeyStates) Disable(addr common.Address, chainID *big.Int, updatedAt time.Time) { + state := ks.Get(addr, chainID) state.Disabled = true state.UpdatedAt = updatedAt } // warning: not thread-safe! caller must sync -func (ks *KeyStates) enable(addr common.Address, chainID *big.Int, updatedAt time.Time) { - state := ks.get(addr, chainID) +func (ks *KeyStates) Enable(addr common.Address, chainID *big.Int, updatedAt time.Time) { + state := ks.Get(addr, chainID) state.Disabled = false state.UpdatedAt = updatedAt } // warning: not thread-safe! caller must sync -func (ks *KeyStates) delete(addr common.Address) { +func (ks *KeyStates) Delete(addr common.Address) { var chainIDs []*big.Int for i := len(ks.All) - 1; i >= 0; i-- { if ks.All[i].Address.Address() == addr { From c4abe68a77263ae9339c8d3fb5b66bb8d469307f Mon Sep 17 00:00:00 2001 From: pavel-raykov Date: Tue, 10 Feb 2026 11:25:10 +0100 Subject: [PATCH 11/13] Minor. --- go.md | 47 ++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 44 insertions(+), 3 deletions(-) diff --git a/go.md b/go.md index 3ec13d7a0c..36126917e8 100644 --- a/go.md +++ b/go.md @@ -15,7 +15,7 @@ flowchart LR chainlink-common --> grpc-proxy chainlink-common --> libocr click chainlink-common href "https://github.com/smartcontractkit/chainlink-common" - chainlink-common/keystore --> chainlink-common + chainlink-common/keystore --> chainlink-evm click chainlink-common/keystore href "https://github.com/smartcontractkit/chainlink-common" chainlink-common/pkg/chipingress click chainlink-common/pkg/chipingress href "https://github.com/smartcontractkit/chainlink-common" @@ -23,6 +23,19 @@ flowchart LR click chainlink-common/pkg/monitoring href "https://github.com/smartcontractkit/chainlink-common" chainlink-common/pkg/values click chainlink-common/pkg/values href "https://github.com/smartcontractkit/chainlink-common" + chainlink-evm --> chainlink-common/keystore + click chainlink-evm href "https://github.com/smartcontractkit/chainlink-evm" + chainlink-evm/gethwrappers + click chainlink-evm/gethwrappers href "https://github.com/smartcontractkit/chainlink-evm" + chainlink-framework/capabilities + click chainlink-framework/capabilities href "https://github.com/smartcontractkit/chainlink-framework" + chainlink-framework/chains --> chainlink-common + chainlink-framework/chains --> chainlink-framework/multinode + click chainlink-framework/chains href "https://github.com/smartcontractkit/chainlink-framework" + chainlink-framework/metrics + click chainlink-framework/metrics href "https://github.com/smartcontractkit/chainlink-framework" + chainlink-framework/multinode + click chainlink-framework/multinode href "https://github.com/smartcontractkit/chainlink-framework" chainlink-protos/billing/go --> chainlink-protos/workflows/go click chainlink-protos/billing/go href "https://github.com/smartcontractkit/chainlink-protos" chainlink-protos/cre/go --> chain-selectors @@ -33,14 +46,27 @@ flowchart LR click chainlink-protos/node-platform href "https://github.com/smartcontractkit/chainlink-protos" chainlink-protos/storage-service click chainlink-protos/storage-service href "https://github.com/smartcontractkit/chainlink-protos" + chainlink-protos/svr + click chainlink-protos/svr href "https://github.com/smartcontractkit/chainlink-protos" chainlink-protos/workflows/go click chainlink-protos/workflows/go href "https://github.com/smartcontractkit/chainlink-protos" + chainlink-tron/relayer + click chainlink-tron/relayer href "https://github.com/smartcontractkit/chainlink-tron" freeport click freeport href "https://github.com/smartcontractkit/freeport" + go-sumtype2 + click go-sumtype2 href "https://github.com/smartcontractkit/go-sumtype2" grpc-proxy click grpc-proxy href "https://github.com/smartcontractkit/grpc-proxy" - libocr + libocr --> go-sumtype2 click libocr href "https://github.com/smartcontractkit/libocr" + smdkg --> libocr + smdkg --> tdh2/go/tdh2 + click smdkg href "https://github.com/smartcontractkit/smdkg" + tdh2/go/tdh2 + click tdh2/go/tdh2 href "https://github.com/smartcontractkit/tdh2" + wsrpc + click wsrpc href "https://github.com/smartcontractkit/wsrpc" subgraph chainlink-common-repo[chainlink-common] chainlink-common @@ -51,16 +77,31 @@ flowchart LR end click chainlink-common-repo href "https://github.com/smartcontractkit/chainlink-common" + subgraph chainlink-evm-repo[chainlink-evm] + chainlink-evm + chainlink-evm/gethwrappers + end + click chainlink-evm-repo href "https://github.com/smartcontractkit/chainlink-evm" + + subgraph chainlink-framework-repo[chainlink-framework] + chainlink-framework/capabilities + chainlink-framework/chains + chainlink-framework/metrics + chainlink-framework/multinode + end + click chainlink-framework-repo href "https://github.com/smartcontractkit/chainlink-framework" + subgraph chainlink-protos-repo[chainlink-protos] chainlink-protos/billing/go chainlink-protos/cre/go chainlink-protos/linking-service/go chainlink-protos/node-platform chainlink-protos/storage-service + chainlink-protos/svr chainlink-protos/workflows/go end click chainlink-protos-repo href "https://github.com/smartcontractkit/chainlink-protos" classDef outline stroke-dasharray:6,fill:none; - class chainlink-common-repo,chainlink-protos-repo outline + class chainlink-common-repo,chainlink-evm-repo,chainlink-framework-repo,chainlink-protos-repo outline ``` From 224b260680ffc5fd0c70c0183fcccd38cd634924 Mon Sep 17 00:00:00 2001 From: pavel-raykov Date: Tue, 10 Feb 2026 11:31:29 +0100 Subject: [PATCH 12/13] Minor. --- keystore/go.mod | 2 +- keystore/go.sum | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/keystore/go.mod b/keystore/go.mod index 185c9e173f..6ca21b5093 100644 --- a/keystore/go.mod +++ b/keystore/go.mod @@ -223,7 +223,7 @@ require ( github.com/smartcontractkit/chain-selectors v1.0.89 // indirect github.com/smartcontractkit/chainlink-common/pkg/chipingress v0.0.10 // indirect github.com/smartcontractkit/chainlink-framework/chains v0.0.0-20251210101658-1c5c8e4c4f15 // indirect - github.com/smartcontractkit/chainlink-protos/cre/go v0.0.0-20260206000552-087e235a7963 // indirect + github.com/smartcontractkit/chainlink-protos/cre/go v0.0.0-20260209203401-a488315d180f // indirect github.com/smartcontractkit/chainlink-protos/linking-service/go v0.0.0-20251002192024-d2ad9222409b // indirect github.com/smartcontractkit/freeport v0.1.3-0.20250716200817-cb5dfd0e369e // indirect github.com/spf13/cast v1.10.0 // indirect diff --git a/keystore/go.sum b/keystore/go.sum index 186d282b2d..fb8316be79 100644 --- a/keystore/go.sum +++ b/keystore/go.sum @@ -736,6 +736,7 @@ github.com/smartcontractkit/chainlink-framework/chains v0.0.0-20251210101658-1c5 github.com/smartcontractkit/chainlink-framework/chains v0.0.0-20251210101658-1c5c8e4c4f15/go.mod h1:kGprqyjsz6qFNVszOQoHc24wfvCjyipNZFste/3zcbs= github.com/smartcontractkit/chainlink-protos/cre/go v0.0.0-20260206000552-087e235a7963 h1:DCLvEn4KkFzYbK/AYl4vJmf6EHaskPYvGDGdd0kOma0= github.com/smartcontractkit/chainlink-protos/cre/go v0.0.0-20260206000552-087e235a7963/go.mod h1:Jqt53s27Tr0jDl8mdBXg1xhu6F8Fci8JOuq43tgHOM8= +github.com/smartcontractkit/chainlink-protos/cre/go v0.0.0-20260209203401-a488315d180f/go.mod h1:Jqt53s27Tr0jDl8mdBXg1xhu6F8Fci8JOuq43tgHOM8= github.com/smartcontractkit/chainlink-protos/linking-service/go v0.0.0-20251002192024-d2ad9222409b h1:QuI6SmQFK/zyUlVWEf0GMkiUYBPY4lssn26nKSd/bOM= github.com/smartcontractkit/chainlink-protos/linking-service/go v0.0.0-20251002192024-d2ad9222409b/go.mod h1:qSTSwX3cBP3FKQwQacdjArqv0g6QnukjV4XuzO6UyoY= github.com/smartcontractkit/freeport v0.1.3-0.20250716200817-cb5dfd0e369e h1:Hv9Mww35LrufCdM9wtS9yVi/rEWGI1UnjHbcKKU0nVY= From d3dfdf1f33ef487b4befdf6fbb2a0adc1b37a106 Mon Sep 17 00:00:00 2001 From: pavel-raykov Date: Tue, 10 Feb 2026 11:40:33 +0100 Subject: [PATCH 13/13] Minor. --- keystore/go.sum | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/keystore/go.sum b/keystore/go.sum index fb8316be79..3f7b1b572f 100644 --- a/keystore/go.sum +++ b/keystore/go.sum @@ -734,8 +734,7 @@ github.com/smartcontractkit/chainlink-evm v0.3.4-0.20260205183656-836ec9472717 h github.com/smartcontractkit/chainlink-evm v0.3.4-0.20260205183656-836ec9472717/go.mod h1:jBZMFIz1C3sq/YyuTgk5MCu12SdHP+PcujdojZsSk6g= github.com/smartcontractkit/chainlink-framework/chains v0.0.0-20251210101658-1c5c8e4c4f15 h1:Mf+IRvrXutcKAKpuOxq5Ae+AAw4Z5vc66q1xI7qimZQ= github.com/smartcontractkit/chainlink-framework/chains v0.0.0-20251210101658-1c5c8e4c4f15/go.mod h1:kGprqyjsz6qFNVszOQoHc24wfvCjyipNZFste/3zcbs= -github.com/smartcontractkit/chainlink-protos/cre/go v0.0.0-20260206000552-087e235a7963 h1:DCLvEn4KkFzYbK/AYl4vJmf6EHaskPYvGDGdd0kOma0= -github.com/smartcontractkit/chainlink-protos/cre/go v0.0.0-20260206000552-087e235a7963/go.mod h1:Jqt53s27Tr0jDl8mdBXg1xhu6F8Fci8JOuq43tgHOM8= +github.com/smartcontractkit/chainlink-protos/cre/go v0.0.0-20260209203401-a488315d180f h1:YBpKK0O7IcbkMyhPRXxA4HGh9OYt+N5Qicx28z8NMvE= github.com/smartcontractkit/chainlink-protos/cre/go v0.0.0-20260209203401-a488315d180f/go.mod h1:Jqt53s27Tr0jDl8mdBXg1xhu6F8Fci8JOuq43tgHOM8= github.com/smartcontractkit/chainlink-protos/linking-service/go v0.0.0-20251002192024-d2ad9222409b h1:QuI6SmQFK/zyUlVWEf0GMkiUYBPY4lssn26nKSd/bOM= github.com/smartcontractkit/chainlink-protos/linking-service/go v0.0.0-20251002192024-d2ad9222409b/go.mod h1:qSTSwX3cBP3FKQwQacdjArqv0g6QnukjV4XuzO6UyoY=