Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: bls remote signer #745

Merged
merged 5 commits into from
Nov 16, 2024
Merged

feat: bls remote signer #745

merged 5 commits into from
Nov 16, 2024

Conversation

shrimalmadhur
Copy link
Contributor

Why are these changes needed?

Checks

  • I've made sure the lint is passing in this PR.
  • I've made sure the tests are passing. Note that there might be a few flaky tests, in that case, please comment that they are not relevant.
  • Testing Strategy
    • Unit tests
    • Integration tests
    • This PR is not tested :(

@shrimalmadhur shrimalmadhur force-pushed the madhur/poc-remote-bls-signer branch 3 times, most recently from 283dc0e to 0b23714 Compare October 22, 2024 23:39
@shrimalmadhur shrimalmadhur marked this pull request as ready for review October 23, 2024 20:45
@shrimalmadhur shrimalmadhur changed the title feat: poc bls remote signer feat: bls remote signer Oct 23, 2024
Copy link
Contributor

@samlaf samlaf left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Overall LGTM. Added a bunch of nits

node/config.go Outdated
Comment on lines 81 to 85
BLSRemoteSignerUrl string
BLSPublicKeyHex string
BLSKeyPassword string
BLSSignerTLSCertFilePath string
UseBLSRemoteSigner bool
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
BLSRemoteSignerUrl string
BLSPublicKeyHex string
BLSKeyPassword string
BLSSignerTLSCertFilePath string
UseBLSRemoteSigner bool
BLSRemoteSignerEnabled bool
BLSRemoteSignerUrl string
BLSPublicKeyHex string
BLSKeyPassword string
BLSSignerTLSCertFilePath string

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Personally prefer to keep same naming convention for all vars, and to have the enabled var at the top.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe consider creating subconfigs also? The config for the node is crazy long.

node/config.go Outdated
@@ -143,14 +152,20 @@ func NewConfig(ctx *cli.Context) (*Config, error) {
ethClientConfig = geth.ReadEthClientConfig(ctx)
}

// check if BLS remote signer configuration is provided
useBLSRemoteSigner := ctx.GlobalString(flags.BLSRemoteSignerUrlFlag.Name) != "" && ctx.GlobalString(flags.BLSPublicKeyHexFlag.Name) != ""
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Personally prefer to have an explicit flag to turn a feature on/off

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comment on lines +283 to +294
BLSPublicKeyHexFlag = cli.StringFlag{
Name: common.PrefixFlag(FlagPrefix, "bls-public-key-hex"),
Usage: "The hex-encoded public key of the BLS signer",
Required: false,
EnvVar: common.PrefixEnvVar(EnvVarPrefix, "BLS_PUBLIC_KEY_HEX"),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

does bls signer do auth? Or does it just store a bunch of private keys and if I have access to its endpoint then I can just ask it to sign from any private key just by giving it the respective public key?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

right now it doesn't support auth - you can ask for any public key hex. but I think we will support it eventually.

@@ -283,7 +283,10 @@ func (s *Server) AttestBatch(ctx context.Context, in *pb.AttestBatchRequest) (*p
if err != nil {
return nil, fmt.Errorf("failed to get the batch header hash: %w", err)
}
sig := s.node.KeyPair.SignMessage(batchHeaderHash)
sig, err := s.node.GetSignature(ctx, batchHeaderHash)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

consider renaming GetSignature to just Sign?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yea - good suggestion

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

node/node.go Outdated
return signature, nil
}

func (n *Node) GetSignature(ctx context.Context, data [32]byte) (*core.Signature, error) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
func (n *Node) GetSignature(ctx context.Context, data [32]byte) (*core.Signature, error) {
func (n *Node) SignMessage(ctx context.Context, data [32]byte) (*core.Signature, error) {

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

rename to SignMessage to match the keypair.SignMessage function?

Comment on lines +121 to +138
if config.PrivateBls != "" {
nodeLogger.Info("using local keystore private key for BLS signing")
// Generate BLS keys
keyPair, err = core.MakeKeyPairFromString(config.PrivateBls)
if err != nil {
return nil, err
}

config.ID = keyPair.GetPubKeyG1().GetOperatorID()
} else {
pkBytes, err := hex.DecodeString(config.BLSPublicKeyHex)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

personally find this a bit confusing to read.
Is the intention that:

  • test mode: bls private key
  • prod mode: bls sk file OR bls remote signer
    ?

in config.go above you first check if !testmode, then build the bls remote signer, so I think here you should also duplicate the logic (for redundancy and future buggy refactor proofing) - check

if !testMode && config.PrivateBls != ""

or something. Haven't thought this through, but I personally don't like any implicit stuff (like implicitly turning bls remote signer when some other flag is present. Prefer everything to have an "enabled" switch. Perhaps you can have a SignerType flag, and then crash when that thing is set to private-key and testMode is set to disabled?

Copy link
Contributor Author

@shrimalmadhur shrimalmadhur Nov 13, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

test mode: bls private key
prod mode: bls sk file OR bls remote signer
?

Yes - I am not aware where test mode is used? maybe I think in inabox testing but yes that's the intention - in prod you can use either encrypted sk file or remote signer

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

so what I can do is - have an explicit flag which switches between sk file and bls remote signer. PrivateBls is not really used in prod. maybe @ian-shim can confirm but I think thats true.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maybe we should eventually remove out test node and use either sk file or remote signer as that clearly mimics prod usage

Copy link
Contributor Author

@shrimalmadhur shrimalmadhur Nov 13, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the ugly thing about testMode and prod mode with sk file is - both these cases populate privateBls and that's why checking testMode is not going to work here. since privateBls is populated in non testMode too. https://github.com/Layr-Labs/eigenda/pull/745/files#diff-923e406f4251573464f7748834b59f4747b3f6ec4eadda667614e2875a3b811aR166-R174

I think ideal would be to remove this testMode and eventually put the prod signing behind eigensdk as I said in above comment.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Test mode I think is just used to allow passing a sk directly? Think it should be allowed to simplify tests.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if that would remain - in current way - privateBls will be populated for both. I guess we could change eventually when we abstract out signing behind eigensdk

},
)
if err != nil {
return nil, fmt.Errorf("failed to sign data: %w", err)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

security check: are you sure that the error returned from your bls remote signer never leaks any sensitive info?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nope it does not. nothing ever returns any sensitive information from the signer itself.

return nil, err
}
}
conn, err := grpc.NewClient(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What happens if this connection gets broken while node is running?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A grpc « connection » is really a virtual connection. It’s not 1-1 with the underlying tcp connection. If tcp conn drops the grpc runtime dials a new connection.

don’t think grpc « connection » can ever be disconnected. But worth checking if there are conditions that need to be checked/handled.

@@ -114,6 +116,47 @@ func NewNode(reg *prometheus.Registry, config *Config, pubIPProvider pubip.Provi
// Create ChainState Client
cst := eth.NewChainState(tx, client)

var keyPair *core.KeyPair
var blsClient blssignerV1.SignerClient
Copy link
Contributor

@ian-shim ian-shim Nov 12, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I feel like this one-of pattern where one is expected to be nil and the other is not is very brittle.
There is this pattern in Config where PrivateBls can be empty and here where one of either keyPair or blsClient is nil.
Downstream, these attributes can't be assumed to be non-nil and there needs to be if/else nil check whenever they're accessed (or worse, forgetting to check this would result in panic).
Is there a blsClient abstraction that allows local signing with private bls key?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed! This is what I was trying to describe in #745 (comment)

Copy link
Contributor Author

@shrimalmadhur shrimalmadhur Nov 13, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a blsClient abstraction that allows local signing with private bls key?

I am thinking of having this abstraction in eigensdk and then you just initialize signer and based on config it would sign. Once I do that - we can switch it out.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this something that will be done & reflected in this PR? Or in a future PR?

@pschork
Copy link
Contributor

pschork commented Nov 15, 2024

Bump go-ethereum to latet to resolve unit tests

go-verkle was causing unit test failures with type *banderwagon.Element has no field or method BytesUncompressed

    go mod graph | grep go-verkle
    github.com/Layr-Labs/eigenda github.com/gballet/[email protected]
    github.com/ethereum/[email protected] github.com/gballet/[email protected]
    github.com/gballet/[email protected] github.com/crate-crypto/[email protected]
    github.com/gballet/[email protected] golang.org/x/[email protected]
    github.com/gballet/[email protected] github.com/bits-and-blooms/[email protected]
    github.com/gballet/[email protected] github.com/consensys/[email protected]
    github.com/gballet/[email protected] github.com/consensys/[email protected]
    github.com/gballet/[email protected] github.com/mmcloughlin/[email protected]
    github.com/gballet/[email protected] golang.org/x/[email protected]/gballet/[email protected] rsc.io/[email protected]

Resolve grpc.Dial deprecations due to cerbereus bumping grpc from v1.59.0 -> v1.64.1

  • Updates grpc.Dial -> grpc.NewClient
  • Removes withBlock() option from grpcConnection.Dial used by syntetic checks.

see https://github.com/grpc/grpc-go/blob/master/Documentation/anti-patterns.md for why withBlock() was deprecated.

shrimalmadhur and others added 3 commits November 15, 2024 13:50
update docker file for private repo

remove the go private

deps

api

fix  deps

fix flags

fix convert

support latest signer

support latest signer

support latest signer

replace with cerberus

add cert file path

operator id

move log up

move function up

move function up

fix incorrect logic

clean and and make backward compatible

clean up
go-verkle was causing unit test failures with `type *banderwagon.Element
has no field or method BytesUncompressed`

```
go mod graph | grep go-verkle
github.com/Layr-Labs/eigenda github.com/gballet/[email protected]
github.com/ethereum/[email protected] github.com/gballet/[email protected]
github.com/gballet/[email protected] github.com/crate-crypto/[email protected]
github.com/gballet/[email protected] golang.org/x/[email protected]
github.com/gballet/[email protected] github.com/bits-and-blooms/[email protected]
github.com/gballet/[email protected] github.com/consensys/[email protected]
github.com/gballet/[email protected] github.com/consensys/[email protected]
github.com/gballet/[email protected] github.com/mmcloughlin/[email protected]
github.com/gballet/[email protected] golang.org/x/[email protected]
github.com/gballet/[email protected] rsc.io/[email protected]
```

Resolve grpc.Dial deprecations due to cerbereus bumping grpc from v1.59.0 -> v1.64.1
- Updates `grpc.Dial` -> `grpc.NewClient`
- Removes `withBlock()` option from `grpcConnection.Dial` used by syntetic checks.

see https://github.com/grpc/grpc-go/blob/master/Documentation/anti-patterns.md for why `withBlock()` was deprecated.
Copy link
Contributor

@ian-shim ian-shim left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

one last comment

return nil, fmt.Errorf("could not read or decrypt the BLS private key: %v", err)
// If remote signer fields are empty then try to read the BLS key from the file
if !blsRemoteSignerEnabled {
kp, err := bls.ReadPrivateKeyFromFile(ctx.GlobalString(flags.BlsKeyFileFlag.Name), ctx.GlobalString(flags.BlsKeyPasswordFlag.Name))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

BlsKeyFileFlag is still a required flag. Does it need to be an optional field now?

@pschork pschork merged commit c70f576 into master Nov 16, 2024
9 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants