github.com/koko1123/flow-go-1@v0.29.6/network/p2p/keyutils/keyTranslator_test.go (about) 1 package keyutils 2 3 import ( 4 "crypto/rand" 5 "fmt" 6 "math" 7 "testing" 8 9 "github.com/btcsuite/btcd/btcec/v2" 10 lcrypto "github.com/libp2p/go-libp2p/core/crypto" 11 "github.com/libp2p/go-libp2p/core/peer" 12 "github.com/stretchr/testify/assert" 13 "github.com/stretchr/testify/require" 14 "github.com/stretchr/testify/suite" 15 16 fcrypto "github.com/onflow/flow-go/crypto" 17 ) 18 19 // KeyTranslatorTestSuite tests key conversion from Flow keys to LibP2P keys 20 type KeyTranslatorTestSuite struct { 21 suite.Suite 22 } 23 24 // TestKeyTranslatorTestSuite runs all the test methods in this test suite 25 func TestKeyTranslatorTestSuite(t *testing.T) { 26 suite.Run(t, new(KeyTranslatorTestSuite)) 27 } 28 29 // TestPrivateKeyConversion tests that Private keys are successfully converted from Flow to LibP2P representation 30 func (k *KeyTranslatorTestSuite) TestPrivateKeyConversion() { 31 32 // test all the ECDSA curves that are supported by the translator for private key conversion 33 sa := []fcrypto.SigningAlgorithm{fcrypto.ECDSAP256, fcrypto.ECDSASecp256k1} 34 prKeyLen := []int{fcrypto.PrKeyLenECDSAP256, fcrypto.PrKeyLenECDSASecp256k1} 35 // offset of the key raw bytes in the libp2p encoding 36 offset := []int{7, 0} 37 38 loops := 50 39 for j, s := range sa { 40 for i := 0; i < loops; i++ { 41 // generate seed 42 seed := k.createSeed() 43 // generate a Flow private key 44 fpk, err := fcrypto.GeneratePrivateKey(s, seed) 45 require.NoError(k.T(), err) 46 47 // convert it to a LibP2P private key 48 lpk, err := LibP2PPrivKeyFromFlow(fpk) 49 require.NoError(k.T(), err) 50 51 // get the raw bytes of both the keys 52 fbytes := fpk.Encode() 53 lbytes, err := lpk.Raw() 54 lbytes = lbytes[offset[j] : offset[j]+prKeyLen[j]] 55 require.NoError(k.T(), err) 56 57 // compare the raw bytes 58 require.Equal(k.T(), fbytes, lbytes) 59 } 60 } 61 } 62 63 // RawUncompressed returns the bytes of the key in an uncompressed format (like Flow library) 64 // This function is added to the test since Raw function from libp2p only returns the compressed format 65 func rawUncompressed(key lcrypto.PubKey) ([]byte, error) { 66 k, ok := key.(*lcrypto.Secp256k1PublicKey) 67 if !ok { 68 return nil, fmt.Errorf("libp2p public key must be of type Secp256k1PublicKey") 69 } 70 return (*btcec.PublicKey)(k).SerializeUncompressed()[1:], nil 71 } 72 73 // TestPublicKeyConversion tests that Public keys are successfully converted from Flow to LibP2P representation 74 func (k *KeyTranslatorTestSuite) TestPublicKeyConversion() { 75 76 // test the algorithms that are supported by the translator for public key conversion (currently only ECDSA 256) 77 // ECDSASecp256k1 doesn't work and throws a 'invalid pub key length 64' error 78 sa := []fcrypto.SigningAlgorithm{fcrypto.ECDSAP256, fcrypto.ECDSASecp256k1} 79 // the offset of the public key bytes in the x509 encoding of an ECDSA P-256 public key 80 x509offset := 27 81 82 loops := 50 83 for _, s := range sa { 84 for i := 0; i < loops; i++ { 85 // generate seed 86 seed := k.createSeed() 87 fpk, err := fcrypto.GeneratePrivateKey(s, seed) 88 require.NoError(k.T(), err) 89 90 // get the Flow public key 91 fpublic := fpk.PublicKey() 92 93 // convert the Flow public key to a Libp2p public key 94 lpublic, err := LibP2PPublicKeyFromFlow(fpublic) 95 require.NoError(k.T(), err) 96 97 // compare raw bytes of the public keys 98 fbytes := fpublic.Encode() 99 var lbytes []byte 100 if s == fcrypto.ECDSAP256 { 101 lbytes, err = lpublic.Raw() 102 lbytes = lbytes[x509offset:] 103 } else if s == fcrypto.ECDSASecp256k1 { 104 lbytes, err = rawUncompressed(lpublic) 105 } 106 require.NoError(k.T(), err) 107 108 require.Equal(k.T(), fbytes, lbytes) 109 } 110 } 111 } 112 113 func (k *KeyTranslatorTestSuite) TestPublicKeyRoundTrip() { 114 sa := []fcrypto.SigningAlgorithm{fcrypto.ECDSAP256, fcrypto.ECDSASecp256k1} 115 loops := 50 116 for _, s := range sa { 117 for i := 0; i < loops; i++ { 118 119 // generate seed 120 seed := k.createSeed() 121 fpk, err := fcrypto.GeneratePrivateKey(s, seed) 122 require.NoError(k.T(), err) 123 124 // get the Flow public key 125 fpublic := fpk.PublicKey() 126 127 // convert the Flow public key to a Libp2p public key 128 lpublic, err := LibP2PPublicKeyFromFlow(fpublic) 129 require.NoError(k.T(), err) 130 131 fpublic2, err := FlowPublicKeyFromLibP2P(lpublic) 132 require.NoError(k.T(), err) 133 require.Equal(k.T(), fpublic, fpublic2) 134 135 } 136 } 137 138 } 139 140 // TestLibP2PIDGenerationIsConsistent tests that a LibP2P peer ID generated using Flow ECDSA key is deterministic 141 func (k *KeyTranslatorTestSuite) TestPeerIDGenerationIsConsistent() { 142 // generate a seed which will be used for both - Flow keys and Libp2p keys 143 seed := k.createSeed() 144 145 // generate a Flow private key 146 fpk, err := fcrypto.GeneratePrivateKey(fcrypto.ECDSAP256, seed) 147 require.NoError(k.T(), err) 148 149 // get the Flow public key 150 fpublic := fpk.PublicKey() 151 152 // convert it to the Libp2p Public key 153 lconverted, err := LibP2PPublicKeyFromFlow(fpublic) 154 require.NoError(k.T(), err) 155 156 // check that the LibP2P Id generation is deterministic 157 var prev peer.ID 158 for i := 0; i < 100; i++ { 159 160 // generate a Libp2p Peer ID from the converted public key 161 fpeerID, err := peer.IDFromPublicKey(lconverted) 162 require.NoError(k.T(), err) 163 164 if i > 0 { 165 err = prev.Validate() 166 require.NoError(k.T(), err) 167 assert.Equal(k.T(), prev, fpeerID, "peer ID generation is not deterministic") 168 } 169 prev = fpeerID 170 } 171 } 172 173 func (k *KeyTranslatorTestSuite) createSeed() []byte { 174 seedLen := int(math.Max(fcrypto.KeyGenSeedMinLenECDSAP256, fcrypto.KeyGenSeedMinLenECDSASecp256k1)) 175 seed := make([]byte, seedLen) 176 n, err := rand.Read(seed) 177 require.NoError(k.T(), err) 178 require.Equal(k.T(), n, seedLen) 179 return seed 180 }