diff --git a/go.mod b/go.mod index 9635fe6..4b60b03 100644 --- a/go.mod +++ b/go.mod @@ -5,6 +5,7 @@ go 1.21 require ( github.com/AlecAivazis/survey/v2 v2.3.7 github.com/Layr-Labs/eigensdk-go v0.1.7 + github.com/consensys/gnark-crypto v0.12.1 github.com/ethereum/go-ethereum v1.14.3 github.com/fatih/color v1.17.0 github.com/posthog/posthog-go v0.0.0-20240327112532-87b23fe11103 @@ -39,7 +40,6 @@ require ( github.com/btcsuite/btcd/btcec/v2 v2.2.0 // indirect github.com/cespare/xxhash/v2 v2.2.0 // indirect github.com/consensys/bavard v0.1.13 // indirect - github.com/consensys/gnark-crypto v0.12.1 // indirect github.com/cpuguy83/go-md2man/v2 v2.0.4 // indirect github.com/crate-crypto/go-kzg-4844 v1.0.0 // indirect github.com/davecgh/go-spew v1.1.1 // indirect diff --git a/pkg/operator/keys/list.go b/pkg/operator/keys/list.go index 0b7499a..eabde9f 100644 --- a/pkg/operator/keys/list.go +++ b/pkg/operator/keys/list.go @@ -8,7 +8,12 @@ import ( "path/filepath" "strings" + "github.com/consensys/gnark-crypto/ecc/bn254" + "github.com/consensys/gnark-crypto/ecc/bn254/fp" + "github.com/Layr-Labs/eigenlayer-cli/pkg/telemetry" + "github.com/Layr-Labs/eigensdk-go/crypto/bls" + "github.com/Layr-Labs/eigensdk-go/types" "github.com/ethereum/go-ethereum/accounts/keystore" "github.com/urfave/cli/v2" @@ -61,6 +66,11 @@ It will only list keys created in the default folder (./operator_keys/) return err } fmt.Println("Public Key: " + pubKey) + operatorIdStr, err := GetOperatorIdFromBLSPubKey(pubKey) + if err != nil { + return err + } + fmt.Println("Operator Id: 0x" + operatorIdStr) fmt.Println("Key location: " + keyFilePath) fmt.Println("====================================================================================") fmt.Println() @@ -91,6 +101,56 @@ func GetPubKey(keyStoreFile string) (string, error) { } } +func GetOperatorIdFromBLSPubKey(pubKey string) (string, error) { + // The pubkey 's string is generated from this code: + // ```go + // func (p *G1Affine) String() string { + // if p.IsInfinity() { + // return "O" + // } + // return "E([" + p.X.String() + "," + p.Y.String() + "])" + // } + // ``` + // + // This code just parser this string: + // E([498211989701534593628498974128726712526336918939770789545660245177948853517,19434346619705907282579203143605058653932187676054178921788041096426532277474]) + + if pubKey == "O" { + return "", fmt.Errorf("pubKey is Infinity") + } + + if pubKey[:3] != "E([" && pubKey[len(pubKey)-2:] != "])" { + return "", fmt.Errorf("pubKey format failed by not E([x,y])") + } + + pubKeyStr := pubKey[3 : len(pubKey)-2] + strs := strings.Split(pubKeyStr, ",") + if len(strs) != 2 { + return "", fmt.Errorf("pubkey format failed by not x,y") + } + + xe, err := new(fp.Element).SetString(strs[0]) + if err != nil { + return "", err + } + + ye, err := new(fp.Element).SetString(strs[1]) + if err != nil { + return "", err + } + + point := &bls.G1Point{ + G1Affine: &bn254.G1Affine{ + X: *xe, + Y: *ye, + }, + } + + operatorId := types.OperatorIdFromG1Pubkey(point) + + return operatorId.LogValue().String(), nil +} + func GetAddress(keyStoreFile string) (string, error) { keyJson, err := os.ReadFile(keyStoreFile) if err != nil { diff --git a/pkg/operator/keys/list_test.go b/pkg/operator/keys/list_test.go new file mode 100644 index 0000000..4846fd0 --- /dev/null +++ b/pkg/operator/keys/list_test.go @@ -0,0 +1,29 @@ +package keys + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestGetOperatorIdFromPubKey(t *testing.T) { + keys := []string{ + "E([498211989701534593628498974128726712526336918939770789545660245177948853517,19434346619705907282579203143605058653932187676054178921788041096426532277474])", + "E([12892371960839255271113718323208293712766673033393673346290824524331477194807,6396504257730939433250301841781896216352727642879531794135340241924955921098])", + "E([8853142719404209253990126746578519340276504871809603927346768258823924530979,4464334502955619293730816404270634846469810746510824584853386555393710785481])", + "E([13817619904229904480359100813294586448353387608055146955542339872965842194541,13023353346332823262268273898508207656373251044010677832259145526114592960745])", + } + + operatorIds := []string{ + "5a76fe9014f9cd296a69ac589c2bbd2c6a354c5e4c0c79ee35c5b8202b8523a2", + "5a4c1940fd4437cea8649845b353ac5e0502a8bd15df09da6f4d73111517fdcf", + "c1d5a4eb52316da9a5cbd876d17125380f2a9e4184d779993c7cc75cd843c7bb", + "c89a00fede0eac2fcd4d4a13faa07ff806b9537990652934f79f3883789e48a8", + } + + for i, key := range keys { + id, err := GetOperatorIdFromBLSPubKey(key) + assert.NoError(t, err, "get operator id from pubkey for %s", key) + assert.Equal(t, operatorIds[i], id, "operator id from pubkey for %s should eq", key) + } +}