-
Notifications
You must be signed in to change notification settings - Fork 678
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
encapsulate signer #3576
encapsulate signer #3576
Conversation
c522086
to
fc6bc8d
Compare
fc6bc8d
to
57c6ec7
Compare
go.mod
Outdated
@@ -190,3 +190,5 @@ require ( | |||
sigs.k8s.io/structured-merge-diff/v4 v4.4.1 // indirect | |||
sigs.k8s.io/yaml v1.3.0 // indirect | |||
) | |||
|
|||
replace github.com/ava-labs/coreth v0.13.9-rc.1 => github.com/ava-labs/coreth v0.13.9-rc.1.0.20241127225719-c225e43551e1 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not sure what the process is here
@@ -128,7 +128,7 @@ type Config struct { | |||
// TLSKey is this node's TLS key that is used to sign IPs. | |||
TLSKey crypto.Signer `json:"-"` | |||
// BLSKey is this node's BLS key that is used to sign IPs. | |||
BLSKey *bls.SecretKey `json:"-"` | |||
BLSKey bls.Signer `json:"-"` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I assume this means the BLSKey
property gets serialized as the string, "-"
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
IIRC this actually omits it from serialization, i.e it's not serialized or deserialized. This is done because we use the Config
struct to also hold fields and not just config values.... so our hack is to ignore serialization for non-config values (which is weird IMO).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Makes sense.
Yeah, I generally prefer to split up raw config data vs actual dependent services/structs, but 🤷. I've seen this pattern before too.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yup think it makes sense to leave this as is in this PR. Separating it would be an improvement
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
one day...
@@ -186,7 +186,7 @@ type ManagerConfig struct { | |||
SybilProtectionEnabled bool | |||
StakingTLSSigner crypto.Signer | |||
StakingTLSCert *staking.Certificate | |||
StakingBLSKey *bls.SecretKey | |||
StakingBLSKey bls.Signer |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we want to change the property name here too?
@@ -694,7 +694,7 @@ func getStakingSigner(v *viper.Viper) (*bls.SecretKey, error) { | |||
return nil, fmt.Errorf("couldn't create path for signing key at %s: %w", signingKeyPath, err) | |||
} | |||
|
|||
keyBytes := bls.SecretKeyToBytes(key) | |||
keyBytes := key.ToBytes() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'll have to change this eventually to fully abstract the signer. I'm open to ideas on how best to do this
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Within the config, I'd expect us to have a switch that offers different BLS Signers ie. generate and store a new BLS key on the machine or use an external signing service.
I'd think this is either AvalancheGo defining the options it wants to support directly here or it supports a gRPC service that dials an external signer and handles signature requests.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, looking at the code again, signer creation would be specific. A LocalSigner
should actually write the key to disk before returning from a constructor. We could have an EphemeralSigner
that's similar but doesn't save the key and is used for testing.
With that said, I would probably create a
func initializeSigner(signerConfig) (Signer) { /* ... */ }
and deal with saving or not saving there. It should not be dealt with here IMO.
This is all for a future PR though
@@ -175,7 +175,7 @@ func newTestNetwork(t *testing.T, count int) (*testDialer, []*testListener, []id | |||
require.NoError(t, err) | |||
nodeID := ids.NodeIDFromCert(cert) | |||
|
|||
blsKey, err := bls.NewSecretKey() | |||
blsKey, err := bls.NewSigner() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🤔 If we want to change all the *Key
names (variables or properties), I would recommend/request that I do that in a follow-up to limit the scope of both changes.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Seems reasonable
Do they support BLS? Most hardware security modules only support ECDSA / ed25519... |
Yeah, they specifically have support for Ethereum validators |
@@ -25,49 +25,64 @@ var ( | |||
|
|||
type SecretKey = blst.SecretKey |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I should get rid of this type
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
tests/ changes LGTM
utils/crypto/bls/secret.go
Outdated
// NewSecretKey generates a new secret key from the local source of | ||
// cryptographically secure randomness. | ||
func NewSecretKey() (*SecretKey, error) { | ||
func NewSigner() (Signer, error) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: export signer
and return it as a concrete type here so that the calling code can decide whether to use it as an interface/as a concrete type. We'll have to figure out a fix/good naming scheme since it'll collide w/ the interface name as it currently is though. We could also as an alternative argue that the interface is premature and just use the struct.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🤔 I don't think the interface is premature though, I don't plan on adding any functionality for the other implementations. What I'm trying to get is encapsulation so that you can't access the secret-key outside of this package. I think want to make a LocalSigner
, then some "cloud-based" signers (there are a couple of options here that will each have their own concrete types).
Having it generic from day 1 minimizes the impact of converting what's here to a LocalSigner
(which would also be used in all tests), and other signer types would be created based on config values on application start.
Thoughts?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Discussed offline. Change signer
to LocalSigner
. Will move this out in a follow PR
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Another idea is to cache the key bytes and public key but not going to block on it since it's an increase in scope.
Signed-off-by: Richard Pringle <[email protected]>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could we update to a coreth rc rather than a commit before merging to master? After that, this LGTM
@@ -128,7 +128,7 @@ type Config struct { | |||
// TLSKey is this node's TLS key that is used to sign IPs. | |||
TLSKey crypto.Signer `json:"-"` | |||
// BLSKey is this node's BLS key that is used to sign IPs. | |||
BLSKey *bls.SecretKey `json:"-"` | |||
BLSKey bls.Signer `json:"-"` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yup think it makes sense to leave this as is in this PR. Separating it would be an improvement
@@ -175,7 +175,7 @@ func newTestNetwork(t *testing.T, count int) (*testDialer, []*testListener, []id | |||
require.NoError(t, err) | |||
nodeID := ids.NodeIDFromCert(cert) | |||
|
|||
blsKey, err := bls.NewSecretKey() | |||
blsKey, err := bls.NewSigner() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Seems reasonable
go.mod
Outdated
@@ -10,7 +10,7 @@ require ( | |||
github.com/DataDog/zstd v1.5.2 | |||
github.com/NYTimes/gziphandler v1.1.1 | |||
github.com/antithesishq/antithesis-sdk-go v0.3.8 | |||
github.com/ava-labs/coreth v0.13.9-rc.1 | |||
github.com/ava-labs/coreth v0.13.9-rc.1.0.20241204232641-e73e655356b7 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we create an rc with a name that indicates what the change is for (ref to previous update of coreth dependency 33bd401 ) ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yep
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
@@ -694,7 +694,7 @@ func getStakingSigner(v *viper.Viper) (*bls.SecretKey, error) { | |||
return nil, fmt.Errorf("couldn't create path for signing key at %s: %w", signingKeyPath, err) | |||
} | |||
|
|||
keyBytes := bls.SecretKeyToBytes(key) | |||
keyBytes := key.ToBytes() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Within the config, I'd expect us to have a switch that offers different BLS Signers ie. generate and store a new BLS key on the machine or use an external signing service.
I'd think this is either AvalancheGo defining the options it wants to support directly here or it supports a gRPC service that dials an external signer and handles signature requests.
utils/crypto/bls/secret.go
Outdated
} | ||
|
||
// SecretKeyFromBytes parses the big-endian format of the secret key into a | ||
// secret key. | ||
func SecretKeyFromBytes(skBytes []byte) (*SecretKey, error) { | ||
func SecretKeyFromBytes(skBytes []byte) (Signer, error) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
func SecretKeyFromBytes(skBytes []byte) (Signer, error) { | |
func SecretKeyFromBytes(skBytes []byte) (*LocalSigner, error) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done fd7f326
utils/crypto/bls/secret.go
Outdated
// TODO: delete me | ||
ToBytes() []byte |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If we adopt the suggested change on SecretKeyFromBytes
- then this can be deleted now.
// TODO: delete me | |
ToBytes() []byte |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done fd7f326
Sign(msg []byte) *Signature | ||
SignProofOfPossession(msg []byte) *Signature |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I feel like these functions are going to need to return error
once we want to use them for remote signing. Are we waiting to add error
to the return value for when that other implementation is introduced?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, I don't think there's any point in pre-maturely defining the interface here. It's unclear to me at this point whether or not we'll want the specific signer implementation to handle its own errors or wether we would want the caller to handle errors (I'm missing some details on how to gracefully shutdown).
I'm interested to hear your thoughts here, but I definitely don't think this is something that we should deal with yet.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sounds good. I think the only complex question will be around the PoP in the networking code... Everything else should be fairly straightforward I think... But 🤷 we can deal with that when we need to I suppose.
Depends on ava-labs/coreth#693. But ava-labs/coreth#693 also depends on this. Not sure about merge order...
Why this should be merged
Currently, signing happens all over the place and should definitely be abstracted away, especially when dealing with sensitive data like a private key.
Once this abstraction lands, we could further enhance security by using secure hardware and signing outside of the avalanchego application and potentially integrate platforms like cubist.
How this works
Encapsulate signing such that the secret-key does not leave our
bls
utility package.The main changes are in this file:
utils/crypto/bls/secret.go
How this was tested
CI
Need to be documented in RELEASES.md?
I don't think so?