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

Provide BLS signature in Handshake message #2730

Merged
merged 8 commits into from
Feb 15, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions message/messages_benchmark_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,8 +53,9 @@ func BenchmarkMarshalHandshake(b *testing.B) {
IpPort: 0,
MyVersion: "v1.2.3",
IpSigningTime: uint64(time.Now().Unix()),
Sig: []byte{'y', 'e', 'e', 't'},
IpNodeIdSig: []byte{'y', 'e', 'e', 't'},
TrackedSubnets: [][]byte{id[:]},
IpBlsSig: []byte{'y', 'e', 'e', 't', '2'},
},
},
}
Expand Down Expand Up @@ -109,8 +110,9 @@ func BenchmarkUnmarshalHandshake(b *testing.B) {
IpPort: 0,
MyVersion: "v1.2.3",
IpSigningTime: uint64(time.Now().Unix()),
Sig: []byte{'y', 'e', 'e', 't'},
IpNodeIdSig: []byte{'y', 'e', 'e', 't'},
TrackedSubnets: [][]byte{id[:]},
IpBlsSig: []byte{'y', 'e', 'e', 't', '2'},
},
},
}
Expand Down
3 changes: 2 additions & 1 deletion message/messages_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -131,8 +131,9 @@ func TestMessage(t *testing.T) {
IpPort: 9651,
MyVersion: "v1.2.3",
IpSigningTime: uint64(nowUnix),
Sig: []byte{'y', 'e', 'e', 't'},
IpNodeIdSig: []byte{'y', 'e', 'e', 't'},
TrackedSubnets: [][]byte{testID[:]},
IpBlsSig: []byte{'y', 'e', 'e', 't', '2'},
},
},
},
Expand Down
8 changes: 4 additions & 4 deletions message/mock_outbound_message_builder.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

9 changes: 6 additions & 3 deletions message/outbound_msg_builder.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,8 @@ type OutboundMsgBuilder interface {
minor uint32,
patch uint32,
ipSigningTime uint64,
sig []byte,
ipNodeIDSig []byte,
ipBLSSig []byte,
trackedSubnets []ids.ID,
supportedACPs []uint32,
objectedACPs []uint32,
Expand Down Expand Up @@ -243,7 +244,8 @@ func (b *outMsgBuilder) Handshake(
minor uint32,
patch uint32,
ipSigningTime uint64,
sig []byte,
ipNodeIDSig []byte,
ipBLSSig []byte,
trackedSubnets []ids.ID,
supportedACPs []uint32,
objectedACPs []uint32,
Expand All @@ -262,7 +264,7 @@ func (b *outMsgBuilder) Handshake(
IpPort: uint32(ip.Port),
MyVersion: myVersion,
IpSigningTime: ipSigningTime,
Sig: sig,
IpNodeIdSig: ipNodeIDSig,
TrackedSubnets: subnetIDBytes,
Client: &p2p.Client{
Name: client,
Expand All @@ -276,6 +278,7 @@ func (b *outMsgBuilder) Handshake(
Filter: knownPeersFilter,
Salt: knownPeersSalt,
},
IpBlsSig: ipBLSSig,
},
},
},
Expand Down
3 changes: 3 additions & 0 deletions network/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import (
"github.com/ava-labs/avalanchego/snow/uptime"
"github.com/ava-labs/avalanchego/snow/validators"
"github.com/ava-labs/avalanchego/utils/compression"
"github.com/ava-labs/avalanchego/utils/crypto/bls"
"github.com/ava-labs/avalanchego/utils/ips"
"github.com/ava-labs/avalanchego/utils/set"
)
Expand Down Expand Up @@ -142,6 +143,8 @@ 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:"-"`

// TrackedSubnets of the node.
TrackedSubnets set.Set[ids.ID] `json:"-"`
Expand Down
6 changes: 3 additions & 3 deletions network/network.go
Original file line number Diff line number Diff line change
Expand Up @@ -268,7 +268,7 @@ func NewNetwork(
ObjectedACPs: config.ObjectedACPs.List(),
ResourceTracker: config.ResourceTracker,
UptimeCalculator: config.UptimeCalculator,
IPSigner: peer.NewIPSigner(config.MyIPPort, config.TLSKey),
IPSigner: peer.NewIPSigner(config.MyIPPort, config.TLSKey, config.BLSKey),
}

// Invariant: We delay the activation of durango during the TLS handshake to
Expand Down Expand Up @@ -435,7 +435,7 @@ func (n *network) Connected(nodeID ids.NodeID) {
peer.Cert(),
peerIP.IPPort,
peerIP.Timestamp,
peerIP.Signature,
peerIP.TLSSignature,
)
n.ipTracker.Connected(newIP)

Expand Down Expand Up @@ -621,7 +621,7 @@ func (n *network) track(ip *ips.ClaimedIPPort) error {
IPPort: ip.IPPort,
Timestamp: ip.Timestamp,
},
Signature: ip.Signature,
TLSSignature: ip.Signature,
}
maxTimestamp := n.peerConfig.Clock.Time().Add(n.peerConfig.MaxClockDifference)
if err := signedIP.Verify(ip.Cert, maxTimestamp); err != nil {
Expand Down
9 changes: 7 additions & 2 deletions network/network_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import (
"github.com/ava-labs/avalanchego/staking"
"github.com/ava-labs/avalanchego/subnets"
"github.com/ava-labs/avalanchego/utils/constants"
"github.com/ava-labs/avalanchego/utils/crypto/bls"
"github.com/ava-labs/avalanchego/utils/ips"
"github.com/ava-labs/avalanchego/utils/logging"
"github.com/ava-labs/avalanchego/utils/math/meter"
Expand Down Expand Up @@ -171,11 +172,15 @@ func newTestNetwork(t *testing.T, count int) (*testDialer, []*testListener, []id
ip, listener := dialer.NewListener()
nodeID, tlsCert, tlsConfig := getTLS(t, i)

blsKey, err := bls.NewSecretKey()
require.NoError(t, err)

config := defaultConfig
config.TLSConfig = tlsConfig
config.MyNodeID = nodeID
config.MyIPPort = ip
config.TLSKey = tlsCert.PrivateKey.(crypto.Signer)
config.BLSKey = blsKey

listeners[i] = listener
nodeIDs[i] = nodeID
Expand Down Expand Up @@ -542,7 +547,7 @@ func TestDialDeletesNonValidators(t *testing.T) {
}

config := configs[0]
signer := peer.NewIPSigner(config.MyIPPort, config.TLSKey)
signer := peer.NewIPSigner(config.MyIPPort, config.TLSKey, config.BLSKey)
ip, err := signer.GetSignedIP()
require.NoError(err)

Expand All @@ -555,7 +560,7 @@ func TestDialDeletesNonValidators(t *testing.T) {
staking.CertificateFromX509(config.TLSConfig.Certificates[0].Leaf),
ip.IPPort,
ip.Timestamp,
ip.Signature,
ip.TLSSignature,
),
})
require.NoError(err)
Expand Down
27 changes: 17 additions & 10 deletions network/peer/ip.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,15 @@ import (
"time"

"github.com/ava-labs/avalanchego/staking"
"github.com/ava-labs/avalanchego/utils/crypto/bls"
"github.com/ava-labs/avalanchego/utils/hashing"
"github.com/ava-labs/avalanchego/utils/ips"
"github.com/ava-labs/avalanchego/utils/wrappers"
)

var (
errTimestampTooFarInFuture = errors.New("timestamp too far in the future")
errInvalidSignature = errors.New("invalid signature")
errInvalidTLSSignature = errors.New("invalid TLS signature")
marun marked this conversation as resolved.
Show resolved Hide resolved
)

// UnsignedIP is used for a validator to claim an IP. The [Timestamp] is used to
Expand All @@ -30,15 +31,19 @@ type UnsignedIP struct {
}

// Sign this IP with the provided signer and return the signed IP.
func (ip *UnsignedIP) Sign(signer crypto.Signer) (*SignedIP, error) {
sig, err := signer.Sign(
func (ip *UnsignedIP) Sign(tlsSigner crypto.Signer, blsSigner *bls.SecretKey) (*SignedIP, error) {
ipBytes := ip.bytes()
tlsSignature, err := tlsSigner.Sign(
rand.Reader,
hashing.ComputeHash256(ip.bytes()),
hashing.ComputeHash256(ipBytes),
crypto.SHA256,
)
blsSignature := bls.SignProofOfPossession(blsSigner, ipBytes)
return &SignedIP{
UnsignedIP: *ip,
Signature: sig,
UnsignedIP: *ip,
TLSSignature: tlsSignature,
BLSSignature: blsSignature,
BLSSignatureBytes: bls.SignatureToBytes(blsSignature),
}, err
}

Expand All @@ -54,12 +59,14 @@ func (ip *UnsignedIP) bytes() []byte {
// SignedIP is a wrapper of an UnsignedIP with the signature from a signer.
type SignedIP struct {
UnsignedIP
Signature []byte
TLSSignature []byte
BLSSignature *bls.Signature
BLSSignatureBytes []byte
}

// Returns nil if:
// * [ip.Timestamp] is not after [maxTimestamp].
// * [ip.Signature] is a valid signature over [ip.UnsignedIP] from [cert].
// * [ip.TLSSignature] is a valid signature over [ip.UnsignedIP] from [cert].
func (ip *SignedIP) Verify(
cert *staking.Certificate,
maxTimestamp time.Time,
Expand All @@ -72,9 +79,9 @@ func (ip *SignedIP) Verify(
if err := staking.CheckSignature(
cert,
ip.UnsignedIP.bytes(),
ip.Signature,
ip.TLSSignature,
); err != nil {
return fmt.Errorf("%w: %w", errInvalidSignature, err)
return fmt.Errorf("%w: %w", errInvalidTLSSignature, err)
}
return nil
}
18 changes: 11 additions & 7 deletions network/peer/ip_signer.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,17 @@ import (
"crypto"
"sync"

"github.com/ava-labs/avalanchego/utils/crypto/bls"
"github.com/ava-labs/avalanchego/utils/ips"
"github.com/ava-labs/avalanchego/utils/timer/mockable"
)

// IPSigner will return a signedIP for the current value of our dynamic IP.
type IPSigner struct {
ip ips.DynamicIPPort
clock mockable.Clock
signer crypto.Signer
ip ips.DynamicIPPort
clock mockable.Clock
tlsSigner crypto.Signer
blsSigner *bls.SecretKey

// Must be held while accessing [signedIP]
signedIPLock sync.RWMutex
Expand All @@ -26,11 +28,13 @@ type IPSigner struct {

func NewIPSigner(
ip ips.DynamicIPPort,
signer crypto.Signer,
tlsSigner crypto.Signer,
blsSigner *bls.SecretKey,
) *IPSigner {
return &IPSigner{
ip: ip,
signer: signer,
ip: ip,
tlsSigner: tlsSigner,
blsSigner: blsSigner,
}
}

Expand Down Expand Up @@ -67,7 +71,7 @@ func (s *IPSigner) GetSignedIP() (*SignedIP, error) {
IPPort: ip,
Timestamp: s.clock.Unix(),
}
signedIP, err := unsignedIP.Sign(s.signer)
signedIP, err := unsignedIP.Sign(s.tlsSigner, s.blsSigner)
if err != nil {
return nil, err
}
Expand Down
11 changes: 7 additions & 4 deletions network/peer/ip_signer_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import (
"github.com/stretchr/testify/require"

"github.com/ava-labs/avalanchego/staking"
"github.com/ava-labs/avalanchego/utils/crypto/bls"
"github.com/ava-labs/avalanchego/utils/ips"
)

Expand All @@ -26,9 +27,11 @@ func TestIPSigner(t *testing.T) {
tlsCert, err := staking.NewTLSCert()
require.NoError(err)

key := tlsCert.PrivateKey.(crypto.Signer)
tlsKey := tlsCert.PrivateKey.(crypto.Signer)
blsKey, err := bls.NewSecretKey()
require.NoError(err)

s := NewIPSigner(dynIP, key)
s := NewIPSigner(dynIP, tlsKey, blsKey)

s.clock.Set(time.Unix(10, 0))

Expand All @@ -43,13 +46,13 @@ func TestIPSigner(t *testing.T) {
require.NoError(err)
require.Equal(dynIP.IPPort(), signedIP2.IPPort)
require.Equal(uint64(10), signedIP2.Timestamp)
require.Equal(signedIP1.Signature, signedIP2.Signature)
require.Equal(signedIP1.TLSSignature, signedIP2.TLSSignature)

dynIP.SetIP(net.IPv4(1, 2, 3, 4))

signedIP3, err := s.GetSignedIP()
require.NoError(err)
require.Equal(dynIP.IPPort(), signedIP3.IPPort)
require.Equal(uint64(11), signedIP3.Timestamp)
require.NotEqual(signedIP2.Signature, signedIP3.Signature)
require.NotEqual(signedIP2.TLSSignature, signedIP3.TLSSignature)
}
Loading
Loading