Skip to content

Commit

Permalink
refactor
Browse files Browse the repository at this point in the history
  • Loading branch information
pavelkrolevets committed Nov 7, 2023
1 parent 94edf54 commit 064fc33
Show file tree
Hide file tree
Showing 6 changed files with 159 additions and 203 deletions.
91 changes: 24 additions & 67 deletions integration_test/integration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,10 @@ import (
"github.com/bloxapp/ssv/logging"
"github.com/bloxapp/ssv/utils/rsaencryption"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
eth_crypto "github.com/ethereum/go-ethereum/crypto"
"github.com/stretchr/testify/require"

"github.com/bloxapp/ssv-dkg/pkgs/crypto"
ourcrypto "github.com/bloxapp/ssv-dkg/pkgs/crypto"
"github.com/bloxapp/ssv-dkg/pkgs/initiator"
"github.com/bloxapp/ssv-dkg/pkgs/utils"
"github.com/bloxapp/ssv-dkg/pkgs/utils/test_utils"
Expand Down Expand Up @@ -80,7 +78,8 @@ func TestHappyFlows(t *testing.T) {
require.NoError(t, err)
err = testSharesData(ops, 4, []*rsa.PrivateKey{srv1.PrivKey, srv2.PrivKey, srv3.PrivKey, srv4.PrivKey}, sharesDataSigned, pubkeyraw, owner, 0)
require.NoError(t, err)
testDepositData(t, depositData, withdraw.Bytes(), owner, 0)
err = initiator.VerifyDepositData(depositData, withdraw.Bytes(), owner, 0)
require.NoError(t, err)
})
t.Run("test 7 operators happy flow", func(t *testing.T) {
id := crypto.NewID()
Expand All @@ -92,7 +91,8 @@ func TestHappyFlows(t *testing.T) {
require.NoError(t, err)
err = testSharesData(ops, 7, []*rsa.PrivateKey{srv1.PrivKey, srv2.PrivKey, srv3.PrivKey, srv4.PrivKey, srv5.PrivKey, srv6.PrivKey, srv7.PrivKey}, sharesDataSigned, pubkeyraw, owner, 0)
require.NoError(t, err)
testDepositData(t, depositData, withdraw.Bytes(), owner, 0)
err = initiator.VerifyDepositData(depositData, withdraw.Bytes(), owner, 0)
require.NoError(t, err)
})
t.Run("test 10 operators happy flow", func(t *testing.T) {
id := crypto.NewID()
Expand All @@ -104,7 +104,8 @@ func TestHappyFlows(t *testing.T) {
require.NoError(t, err)
err = testSharesData(ops, 10, []*rsa.PrivateKey{srv1.PrivKey, srv2.PrivKey, srv3.PrivKey, srv4.PrivKey, srv5.PrivKey, srv6.PrivKey, srv7.PrivKey, srv8.PrivKey, srv9.PrivKey, srv10.PrivKey}, sharesDataSigned, pubkeyraw, owner, 0)
require.NoError(t, err)
testDepositData(t, depositData, withdraw.Bytes(), owner, 0)
err = initiator.VerifyDepositData(depositData, withdraw.Bytes(), owner, 0)
require.NoError(t, err)
})
t.Run("test 13 operators happy flow", func(t *testing.T) {
id := crypto.NewID()
Expand All @@ -116,7 +117,8 @@ func TestHappyFlows(t *testing.T) {
require.NoError(t, err)
err = testSharesData(ops, 13, []*rsa.PrivateKey{srv1.PrivKey, srv2.PrivKey, srv3.PrivKey, srv4.PrivKey, srv5.PrivKey, srv6.PrivKey, srv7.PrivKey, srv8.PrivKey, srv9.PrivKey, srv10.PrivKey, srv11.PrivKey, srv12.PrivKey, srv13.PrivKey}, sharesDataSigned, pubkeyraw, owner, 0)
require.NoError(t, err)
testDepositData(t, depositData, withdraw.Bytes(), owner, 0)
err = initiator.VerifyDepositData(depositData, withdraw.Bytes(), owner, 0)
require.NoError(t, err)
})
t.Run("test 13 operators - random operators order", func(t *testing.T) {
id := crypto.NewID()
Expand All @@ -128,7 +130,8 @@ func TestHappyFlows(t *testing.T) {
require.NoError(t, err)
err = testSharesData(ops, 13, []*rsa.PrivateKey{srv1.PrivKey, srv2.PrivKey, srv3.PrivKey, srv4.PrivKey, srv5.PrivKey, srv6.PrivKey, srv7.PrivKey, srv8.PrivKey, srv9.PrivKey, srv10.PrivKey, srv11.PrivKey, srv12.PrivKey, srv13.PrivKey}, sharesDataSigned, pubkeyraw, owner, 0)
require.NoError(t, err)
testDepositData(t, depositData, withdraw.Bytes(), owner, 0)
err = initiator.VerifyDepositData(depositData, withdraw.Bytes(), owner, 0)
require.NoError(t, err)
})
srv1.HttpSrv.Close()
srv2.HttpSrv.Close()
Expand Down Expand Up @@ -328,7 +331,8 @@ func TestUnhappyFlows(t *testing.T) {
require.NoError(t, err)
err = testSharesData(ops, 4, []*rsa.PrivateKey{srv1.PrivKey, srv2.PrivKey, srv3.PrivKey, srv4.PrivKey}, sharesDataSigned, pubkeyraw, owner, 0)
require.NoError(t, err)
testDepositData(t, depositData, withdraw.Bytes(), owner, 0)
err = initiator.VerifyDepositData(depositData, withdraw.Bytes(), owner, 0)
require.NoError(t, err)
t.Run("test wrong operators shares order at SSV payload", func(t *testing.T) {
withdraw := newEthAddress(t)
owner := newEthAddress(t)
Expand All @@ -341,8 +345,8 @@ func TestUnhappyFlows(t *testing.T) {
require.NoError(t, err)
signatureOffset := phase0.SignatureLength
pubKeysOffset := phase0.PublicKeyLength*13 + signatureOffset
_ = splitBytes(sharesDataSigned[signatureOffset:pubKeysOffset], phase0.PublicKeyLength)
encryptedKeys := splitBytes(sharesDataSigned[pubKeysOffset:], len(sharesDataSigned[pubKeysOffset:])/13)
_ = utils.SplitBytes(sharesDataSigned[signatureOffset:pubKeysOffset], phase0.PublicKeyLength)
encryptedKeys := utils.SplitBytes(sharesDataSigned[pubKeysOffset:], len(sharesDataSigned[pubKeysOffset:])/13)
wrongOrderSharesData := make([]byte, 0)
wrongOrderSharesData = append(wrongOrderSharesData, sharesDataSigned[:pubKeysOffset]...)
for i := len(encryptedKeys) - 1; i >= 0; i-- {
Expand Down Expand Up @@ -428,7 +432,8 @@ func TestReshareHappyFlow(t *testing.T) {
require.NoError(t, err)
err = testSharesData(ops, 4, []*rsa.PrivateKey{srv1.PrivKey, srv2.PrivKey, srv3.PrivKey, srv4.PrivKey}, sharesDataSigned, pubkeyraw, owner, 0)
require.NoError(t, err)
testDepositData(t, depositData, withdraw.Bytes(), owner, 0)
err = initiator.VerifyDepositData(depositData, withdraw.Bytes(), owner, 0)
require.NoError(t, err)
newIds := []uint64{5, 6, 7, 8, 9}
newId := crypto.NewID()
ks, err = i.StartReshare(newId, id, ids, newIds, owner, 0)
Expand Down Expand Up @@ -457,7 +462,8 @@ func TestReshareHappyFlow(t *testing.T) {
require.NoError(t, err)
err = testSharesData(ops, 4, []*rsa.PrivateKey{srv1.PrivKey, srv2.PrivKey, srv3.PrivKey, srv4.PrivKey}, sharesDataSigned, pubkeyraw, owner, 0)
require.NoError(t, err)
testDepositData(t, depositData, withdraw.Bytes(), owner, 0)
err = initiator.VerifyDepositData(depositData, withdraw.Bytes(), owner, 0)
require.NoError(t, err)
newIds := []uint64{1, 2, 7, 8, 9}
newId := crypto.NewID()
ks, err = i.StartReshare(newId, id, ids, newIds, owner, 0)
Expand Down Expand Up @@ -486,7 +492,8 @@ func TestReshareHappyFlow(t *testing.T) {
require.NoError(t, err)
err = testSharesData(ops, 5, []*rsa.PrivateKey{srv1.PrivKey, srv2.PrivKey, srv3.PrivKey, srv4.PrivKey, srv5.PrivKey}, sharesDataSigned, pubkeyraw, owner, 0)
require.NoError(t, err)
testDepositData(t, depositData, withdraw.Bytes(), owner, 0)
err = initiator.VerifyDepositData(depositData, withdraw.Bytes(), owner, 0)
require.NoError(t, err)
newIds := []uint64{1, 2, 3, 4, 5, 8, 9}
newId := crypto.NewID()
ks, err = i.StartReshare(newId, id, ids, newIds, owner, 0)
Expand Down Expand Up @@ -525,17 +532,17 @@ func testSharesData(ops map[uint64]initiator.Operator, operatorCount int, keys [
}
signature := sharesData[:signatureOffset]
msg := []byte("Hello")
err := ourcrypto.VerifyOwnerNoceSignature(signature, owner, validatorPublicKey, nonce)
err := crypto.VerifyOwnerNoceSignature(signature, owner, validatorPublicKey, nonce)
if err != nil {
return err
}
_ = splitBytes(sharesData[signatureOffset:pubKeysOffset], phase0.PublicKeyLength)
encryptedKeys := splitBytes(sharesData[pubKeysOffset:], len(sharesData[pubKeysOffset:])/operatorCount)
_ = utils.SplitBytes(sharesData[signatureOffset:pubKeysOffset], phase0.PublicKeyLength)
encryptedKeys := utils.SplitBytes(sharesData[pubKeysOffset:], len(sharesData[pubKeysOffset:])/operatorCount)
sigs2 := make(map[uint64][]byte)
opsIDs := make([]uint64, 0)
for i, enck := range encryptedKeys {
var priv *rsa.PrivateKey
if contains(keys, i) {
if utils.Contains(keys, i) {

Check failure on line 545 in integration_test/integration_test.go

View workflow job for this annotation

GitHub Actions / build

undefined: utils.Contains
priv = keys[i]
} else {
continue
Expand Down Expand Up @@ -632,53 +639,3 @@ func newEthAddress(t *testing.T) common.Address {
address := eth_crypto.PubkeyToAddress(*publicKeyECDSA)
return address
}

func splitBytes(buf []byte, lim int) [][]byte {
var chunk []byte
chunks := make([][]byte, 0, len(buf)/lim+1)
for len(buf) >= lim {
chunk, buf = buf[:lim], buf[lim:]
chunks = append(chunks, chunk)
}
if len(buf) > 0 {
chunks = append(chunks, buf[:])
}
return chunks
}

func testDepositData(t *testing.T, depsitDataJson *initiator.DepositDataJson, withdrawCred []byte, owner common.Address, nonce uint16) {
require.True(t, bytes.Equal(ourcrypto.ETH1WithdrawalCredentialsHash(withdrawCred), hexutil.MustDecode("0x"+depsitDataJson.WithdrawalCredentials)))
masterSig := &bls.Sign{}
require.NoError(t, masterSig.DeserializeHexStr(depsitDataJson.Signature))
valdatorPubKey := &bls.PublicKey{}
require.NoError(t, valdatorPubKey.DeserializeHexStr(depsitDataJson.PubKey))

// Check root
var fork [4]byte
copy(fork[:], hexutil.MustDecode("0x"+depsitDataJson.ForkVersion))
depositDataRoot, err := ourcrypto.DepositDataRoot(withdrawCred, valdatorPubKey, utils.GetNetworkByFork(fork), initiator.MaxEffectiveBalanceInGwei)
require.NoError(t, err)
res := masterSig.VerifyByte(valdatorPubKey, depositDataRoot[:])
require.True(t, res)
depositData, _, err := ourcrypto.DepositData(masterSig.Serialize(), withdrawCred, valdatorPubKey.Serialize(), utils.GetNetworkByFork(fork), initiator.MaxEffectiveBalanceInGwei)
require.NoError(t, err)
res, err = ourcrypto.VerifyDepositData(depositData, utils.GetNetworkByFork(fork))
require.NoError(t, err)
require.True(t, res)
depositMsg := &phase0.DepositMessage{
WithdrawalCredentials: depositData.WithdrawalCredentials,
Amount: initiator.MaxEffectiveBalanceInGwei,
}
copy(depositMsg.PublicKey[:], depositData.PublicKey[:])
depositMsgRoot, _ := depositMsg.HashTreeRoot()
require.True(t, bytes.Equal(depositMsgRoot[:], hexutil.MustDecode("0x"+depsitDataJson.DepositMessageRoot)))
}

func contains(s []*rsa.PrivateKey, i int) bool {
for k := range s {
if k == i {
return true
}
}
return false
}
35 changes: 19 additions & 16 deletions pkgs/crypto/crypto.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ import (
e2m_core "github.com/bloxapp/eth2-key-manager/core"
e2m_deposit "github.com/bloxapp/eth2-key-manager/eth1_deposit"
"github.com/drand/kyber/share"
"github.com/drand/kyber/share/dkg"
drand_dkg "github.com/drand/kyber/share/dkg"
"github.com/ethereum/go-ethereum/common"
eth_crypto "github.com/ethereum/go-ethereum/crypto"
"github.com/google/uuid"
Expand All @@ -32,6 +32,8 @@ import (
)

const (
// b64 encrypted key length is 256
EncryptedKeyLength = 256
// BLSWithdrawalPrefixByte is the BLS withdrawal prefix
BLSWithdrawalPrefixByte = byte(0)
ETH1WithdrawalPrefixByte = byte(1)
Expand Down Expand Up @@ -78,7 +80,7 @@ func VerifyRSA(pk *rsa.PublicKey, msg, signature []byte) error {
}

// ResultToShareSecretKey converts a private share at kyber DKG result to github.com/herumi/bls-eth-go-binary/bls private key
func ResultToShareSecretKey(result *dkg.Result) (*bls.SecretKey, error) {
func ResultToShareSecretKey(result *drand_dkg.Result) (*bls.SecretKey, error) {
share := result.Key.PriShare()
bytsSk, err := share.V.MarshalBinary()
if err != nil {
Expand All @@ -105,7 +107,7 @@ func KyberShareToBLSKey(share *share.PriShare) (*bls.SecretKey, error) {
}

// ResultsToValidatorPK converts a public polynomial at kyber DKG result to github.com/herumi/bls-eth-go-binary/bls public key
func ResultToValidatorPK(result *dkg.Result, suite dkg.Suite) (*bls.PublicKey, error) {
func ResultToValidatorPK(result *drand_dkg.Result, suite drand_dkg.Suite) (*bls.PublicKey, error) {
exp := share.NewPubPoly(suite, suite.Point().Base(), result.Key.Commitments())
bytsPK, err := exp.Commit().MarshalBinary()
if err != nil {
Expand Down Expand Up @@ -222,6 +224,7 @@ func ConvertPemToPrivateKey(skPem string) (*rsa.PrivateKey, error) {
return parsePrivateKey(b)
}

// parsePrivateKey parses an encoded x509 RSA private key
func parsePrivateKey(derBytes []byte) (*rsa.PrivateKey, error) {
parsedSk, err := x509.ParsePKCS1PrivateKey(derBytes)
if err != nil {
Expand All @@ -230,6 +233,7 @@ func parsePrivateKey(derBytes []byte) (*rsa.PrivateKey, error) {
return parsedSk, nil
}

// RecoverValidatorPublicKey recovers a BLS master public key (validator pub key) from provided partial pub keys
func RecoverValidatorPublicKey(sharePks map[uint64]*bls.PublicKey) (*bls.PublicKey, error) {
validatorRecoveredPK := bls.PublicKey{}
idVec := make([]bls.ID, 0)
Expand All @@ -247,6 +251,8 @@ func RecoverValidatorPublicKey(sharePks map[uint64]*bls.PublicKey) (*bls.PublicK
}
return &validatorRecoveredPK, nil
}

// RecoverMasterSig recovers a BLS master signature from T-threshold partial signatures
func RecoverMasterSig(sigDepositShares map[uint64]*bls.Sign) (*bls.Sign, error) {
reconstructedDepositMasterSig := bls.Sign{}
idVec := make([]bls.ID, 0)
Expand All @@ -265,6 +271,7 @@ func RecoverMasterSig(sigDepositShares map[uint64]*bls.Sign) (*bls.Sign, error)
return &reconstructedDepositMasterSig, nil
}

// DepositData crates and signs a ETH2 deposit message
func DepositData(masterSig, withdrawalPubKey, publicKey []byte, network e2m_core.Network, amount phase0.Gwei) (*phase0.DepositData, [32]byte, error) {
if !e2m_deposit.IsSupportedDepositNetwork(network) {
return nil, [32]byte{}, fmt.Errorf("network %s is not supported", network)
Expand Down Expand Up @@ -330,6 +337,7 @@ func ETH1WithdrawalCredentialsHash(withdrawalAddr []byte) []byte {
return withdrawalCredentials
}

// DepositDataRoot computes a deposit root used for ETH2 deposit message
func DepositDataRoot(withdrawalPubKey []byte, publicKey *bls.PublicKey, network e2m_core.Network, amount phase0.Gwei) ([]byte, error) {
if !e2m_deposit.IsSupportedDepositNetwork(network) {
return nil, fmt.Errorf("network %s is not supported", network)
Expand Down Expand Up @@ -366,6 +374,7 @@ func DepositDataRoot(withdrawalPubKey []byte, publicKey *bls.PublicKey, network
return root[:], nil
}

// VerifyDepositData reconstructs and checks BLS signatures for ETH2 deposit message
func VerifyDepositData(depositData *phase0.DepositData, network e2m_core.Network) (bool, error) {
depositMessage := &phase0.DepositMessage{
WithdrawalCredentials: depositData.WithdrawalCredentials,
Expand Down Expand Up @@ -410,6 +419,7 @@ func VerifyDepositData(depositData *phase0.DepositData, network e2m_core.Network
return sig.Verify(signingRoot[:], pubkey), nil
}

// SignDepositData creates a BLS signature for ETH2 deposit message
func SignDepositData(validationKey *bls.SecretKey, withdrawalPubKey []byte, validatorPublicKey *bls.PublicKey, network e2m_core.Network, amount phase0.Gwei) (*bls.Sign, []byte, error) {
if !e2m_deposit.IsSupportedDepositNetwork(network) {
return nil, nil, errors.Errorf("Network %s is not supported", network)
Expand Down Expand Up @@ -451,6 +461,7 @@ func SignDepositData(validationKey *bls.SecretKey, withdrawalPubKey []byte, vali
return sig, root[:], nil
}

// VerifyPartialSigs verifies provided partial BLS signatures
func VerifyPartialSigs(sigShares map[uint64]*bls.Sign, sharePks map[uint64]*bls.PublicKey, data []byte) error {
res := make(map[uint64]bool)
for index, pub := range sharePks {
Expand All @@ -473,6 +484,7 @@ func VerifyPartialSigs(sigShares map[uint64]*bls.Sign, sharePks map[uint64]*bls.
return nil
}

// EncryptedPrivateKey reads an encoded RSA priv key from path encrypted with password
func EncryptedPrivateKey(path, pass string) (*rsa.PrivateKey, error) {
data, err := os.ReadFile(path)
if err != nil {
Expand All @@ -487,6 +499,7 @@ func EncryptedPrivateKey(path, pass string) (*rsa.PrivateKey, error) {
return privateKey, nil
}

// PrivateKey reads an encoded RSA priv key from path
func PrivateKey(path string) (*rsa.PrivateKey, error) {
data, err := os.ReadFile(path)
if err != nil {
Expand Down Expand Up @@ -516,6 +529,7 @@ func PrivateKey(path string) (*rsa.PrivateKey, error) {
return parsedSk, nil
}

// NewID generates a random ID from 2 random concat UUIDs
func NewID() [24]byte {
var id [24]byte
b := uuid.New()
Expand All @@ -525,6 +539,7 @@ func NewID() [24]byte {
return id
}

// GenerateSecurePassword randomly generates a password consisting of digits + english letters
func GenerateSecurePassword() (string, error) {
const alpha = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
var pass []rune
Expand Down Expand Up @@ -566,6 +581,7 @@ func ReconstructSignatures(signatures map[uint64][]byte) (*bls.Sign, error) {
return &reconstructedSig, err
}

// VerifyReconstructedSignature checks a reconstructed msg master signature against validator public key
func VerifyReconstructedSignature(sig *bls.Sign, validatorPubKey []byte, msg []byte) error {
pk := &bls.PublicKey{}
if err := pk.Deserialize(validatorPubKey); err != nil {
Expand All @@ -577,16 +593,3 @@ func VerifyReconstructedSignature(sig *bls.Sign, validatorPubKey []byte, msg []b
}
return nil
}

func SplitBytes(buf []byte, lim int) [][]byte {
var chunk []byte
chunks := make([][]byte, 0, len(buf)/lim+1)
for len(buf) >= lim {
chunk, buf = buf[:lim], buf[lim:]
chunks = append(chunks, chunk)
}
if len(buf) > 0 {
chunks = append(chunks, buf[:])
}
return chunks
}
8 changes: 0 additions & 8 deletions pkgs/dkg/drand.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import (
"fmt"

"github.com/attestantio/go-eth2-client/spec/phase0"
eth2_key_manager_core "github.com/bloxapp/eth2-key-manager/core"
ssvspec_types "github.com/bloxapp/ssv-spec/types"
"github.com/bloxapp/ssv/storage/kv"
"github.com/drand/kyber"
Expand All @@ -32,15 +31,8 @@ var StoreShare bool
const (
// MaxEffectiveBalanceInGwei is the max effective balance
MaxEffectiveBalanceInGwei phase0.Gwei = 32000000000
// BLSWithdrawalPrefixByte is the BLS withdrawal prefix
BLSWithdrawalPrefixByte = byte(0)
)

// IsSupportedDepositNetwork returns true if the given network is supported
var IsSupportedDepositNetwork = func(network eth2_key_manager_core.Network) bool {
return network == eth2_key_manager_core.PraterNetwork || network == eth2_key_manager_core.MainNetwork || network == eth2_key_manager_core.HoleskyNetwork
}

// Operator structure contains information about external operator participating in the DKG ceremony
type Operator struct {
IP string
Expand Down
8 changes: 4 additions & 4 deletions pkgs/dkg/drand_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,9 +53,9 @@ func (tv *testVerify) Verify(id uint64, msg, sig []byte) error {
}

type testState struct {
T *testing.T
ops map[uint64]*LocalOwner
tv *testVerify
T *testing.T
ops map[uint64]*LocalOwner
tv *testVerify
}

func (ts *testState) Broadcast(id uint64, data []byte) error {
Expand Down Expand Up @@ -199,7 +199,7 @@ func TestDKG(t *testing.T) {
ts.ops[op.ID] = op
}
opsarr := make([]*wire2.Operator, 0, len(ts.ops))
for id, _ := range ts.ops {
for id := range ts.ops {
pktobytes, err := crypto.EncodePublicKey(ts.tv.ops[id])
require.NoError(t, err)
opsarr = append(opsarr, &wire2.Operator{
Expand Down
Loading

0 comments on commit 064fc33

Please sign in to comment.