github.com/onflow/flow-go/crypto@v0.24.8/sign_test_utils.go (about) 1 package crypto 2 3 import ( 4 crand "crypto/rand" 5 "fmt" 6 mrand "math/rand" 7 "testing" 8 "time" 9 10 "github.com/stretchr/testify/assert" 11 "github.com/stretchr/testify/require" 12 13 "github.com/onflow/flow-go/crypto/hash" 14 ) 15 16 func getPRG(t *testing.T) *mrand.Rand { 17 random := time.Now().UnixNano() 18 t.Logf("rng seed is %d", random) 19 rng := mrand.New(mrand.NewSource(random)) 20 return rng 21 } 22 23 func TestKeyGenErrors(t *testing.T) { 24 seed := make([]byte, 50) 25 invalidSigAlgo := SigningAlgorithm(20) 26 sk, err := GeneratePrivateKey(invalidSigAlgo, seed) 27 assert.Nil(t, sk) 28 assert.Error(t, err) 29 assert.True(t, IsInvalidInputsError(err)) 30 } 31 32 func TestHasherErrors(t *testing.T) { 33 t.Run("nilHasher error sanity", func(t *testing.T) { 34 err := nilHasherError 35 invInpError := invalidInputsErrorf("") 36 otherError := fmt.Errorf("some error") 37 assert.True(t, IsNilHasherError(err)) 38 assert.False(t, IsInvalidInputsError(err)) 39 assert.False(t, IsNilHasherError(invInpError)) 40 assert.False(t, IsNilHasherError(otherError)) 41 assert.False(t, IsNilHasherError(nil)) 42 }) 43 44 t.Run("nilHasher error sanity", func(t *testing.T) { 45 err := invalidHasherSizeErrorf("") 46 invInpError := invalidInputsErrorf("") 47 otherError := fmt.Errorf("some error") 48 assert.True(t, IsInvalidHasherSizeError(err)) 49 assert.False(t, IsInvalidInputsError(err)) 50 assert.False(t, IsInvalidHasherSizeError(invInpError)) 51 assert.False(t, IsInvalidHasherSizeError(otherError)) 52 assert.False(t, IsInvalidHasherSizeError(nil)) 53 }) 54 } 55 56 // tests sign and verify are consistent for multiple generated keys and messages 57 func testGenSignVerify(t *testing.T, salg SigningAlgorithm, halg hash.Hasher) { 58 t.Logf("Testing Generation/Signature/Verification for %s", salg) 59 // make sure the length is larger than minimum lengths of all the signaure algos 60 seedMinLength := 48 61 seed := make([]byte, seedMinLength) 62 input := make([]byte, 100) 63 rand := getPRG(t) 64 65 loops := 50 66 for j := 0; j < loops; j++ { 67 n, err := rand.Read(seed) 68 require.Equal(t, n, seedMinLength) 69 require.NoError(t, err) 70 sk, err := GeneratePrivateKey(salg, seed) 71 require.NoError(t, err) 72 _, err = rand.Read(input) 73 require.NoError(t, err) 74 s, err := sk.Sign(input, halg) 75 require.NoError(t, err) 76 pk := sk.PublicKey() 77 78 // test a valid signature 79 result, err := pk.Verify(s, input, halg) 80 require.NoError(t, err) 81 assert.True(t, result, fmt.Sprintf( 82 "Verification should succeed:\n signature:%s\n message:%x\n private key:%s", s, input, sk)) 83 84 // test with a different message 85 input[0] ^= 1 86 result, err = pk.Verify(s, input, halg) 87 require.NoError(t, err) 88 assert.False(t, result, fmt.Sprintf( 89 "Verification should fail:\n signature:%s\n message:%x\n private key:%s", s, input, sk)) 90 input[0] ^= 1 91 92 // test with a valid but different key 93 seed[0] ^= 1 94 wrongSk, err := GeneratePrivateKey(salg, seed) 95 require.NoError(t, err) 96 result, err = wrongSk.PublicKey().Verify(s, input, halg) 97 require.NoError(t, err) 98 assert.False(t, result, fmt.Sprintf( 99 "Verification should fail:\n signature:%s\n message:%x\n private key:%s", s, input, sk)) 100 101 // test a wrong signature length 102 invalidLen := rand.Intn(2 * len(s)) // try random invalid lengths 103 if invalidLen == len(s) { // map to an invalid length 104 invalidLen = 0 105 } 106 invalidSig := make([]byte, invalidLen) 107 result, err = pk.Verify(invalidSig, input, halg) 108 require.NoError(t, err) 109 assert.False(t, result, fmt.Sprintf( 110 "Verification should fail:\n signature:%s\n with invalid length %d", invalidSig, invalidLen)) 111 } 112 } 113 114 // tests the key generation constraints with regards to the input seed, mainly 115 // the seed length constraints and the result determinicity. 116 func testKeyGenSeed(t *testing.T, salg SigningAlgorithm, minLen int, maxLen int) { 117 t.Run("seed length check", func(t *testing.T) { 118 // valid seed lengths 119 seed := make([]byte, minLen) 120 _, err := GeneratePrivateKey(salg, seed) 121 assert.NoError(t, err) 122 if maxLen > 0 { 123 seed = make([]byte, maxLen) 124 _, err = GeneratePrivateKey(salg, seed) 125 assert.NoError(t, err) 126 } 127 // invalid seed lengths 128 seed = make([]byte, minLen-1) 129 _, err = GeneratePrivateKey(salg, seed) 130 assert.Error(t, err) 131 assert.True(t, IsInvalidInputsError(err)) 132 if maxLen > 0 { 133 seed = make([]byte, maxLen+1) 134 _, err = GeneratePrivateKey(salg, seed) 135 assert.Error(t, err) 136 assert.True(t, IsInvalidInputsError(err)) 137 } 138 }) 139 140 t.Run("deterministic generation", func(t *testing.T) { 141 142 // same seed results in the same key 143 seed := make([]byte, minLen) 144 read, err := crand.Read(seed) 145 require.Equal(t, read, minLen) 146 require.NoError(t, err) 147 sk1, err := GeneratePrivateKey(salg, seed) 148 require.NoError(t, err) 149 sk2, err := GeneratePrivateKey(salg, seed) 150 require.NoError(t, err) 151 assert.True(t, sk1.Equals(sk2)) 152 // different seed results in a different key 153 seed[0] ^= 1 // alter a seed bit 154 sk2, err = GeneratePrivateKey(salg, seed) 155 require.NoError(t, err) 156 assert.False(t, sk1.Equals(sk2)) 157 }) 158 } 159 160 var BLS12381Order = []byte{0x73, 0xED, 0xA7, 0x53, 0x29, 0x9D, 0x7D, 0x48, 0x33, 0x39, 161 0xD8, 0x08, 0x09, 0xA1, 0xD8, 0x05, 0x53, 0xBD, 0xA4, 0x02, 0xFF, 0xFE, 162 0x5B, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x01} 163 164 func testEncodeDecode(t *testing.T, salg SigningAlgorithm) { 165 t.Logf("Testing encode/decode for %s", salg) 166 rand := getPRG(t) 167 // make sure the length is larger than minimum lengths of all the signaure algos 168 seedMinLength := 48 169 170 t.Run("happy path tests", func(t *testing.T) { 171 loops := 50 172 for j := 0; j < loops; j++ { 173 // generate a private key 174 seed := make([]byte, seedMinLength) 175 read, err := rand.Read(seed) 176 require.Equal(t, read, seedMinLength) 177 require.NoError(t, err) 178 sk, err := GeneratePrivateKey(salg, seed) 179 assert.Nil(t, err, "the key generation failed") 180 seed[0] ^= 1 // alter the seed to get a new private key 181 distinctSk, err := GeneratePrivateKey(salg, seed) 182 require.NoError(t, err) 183 184 // check private key encoding 185 skBytes := sk.Encode() 186 skCheck, err := DecodePrivateKey(salg, skBytes) 187 require.Nil(t, err, "the key decoding failed") 188 assert.True(t, sk.Equals(skCheck), "key equality check failed") 189 skCheckBytes := skCheck.Encode() 190 assert.Equal(t, skBytes, skCheckBytes, "keys should be equal") 191 distinctSkBytes := distinctSk.Encode() 192 assert.NotEqual(t, skBytes, distinctSkBytes, "keys should be different") 193 194 // check public key encoding 195 pk := sk.PublicKey() 196 pkBytes := pk.Encode() 197 pkCheck, err := DecodePublicKey(salg, pkBytes) 198 require.Nil(t, err, "the key decoding failed") 199 assert.True(t, pk.Equals(pkCheck), "key equality check failed") 200 pkCheckBytes := pkCheck.Encode() 201 assert.Equal(t, pkBytes, pkCheckBytes, "keys should be equal") 202 distinctPkBytes := distinctSk.PublicKey().Encode() 203 assert.NotEqual(t, pkBytes, distinctPkBytes, "keys should be different") 204 205 // same for the compressed encoding 206 pkComprBytes := pk.EncodeCompressed() 207 pkComprCheck, err := DecodePublicKeyCompressed(salg, pkComprBytes) 208 require.Nil(t, err, "the key decoding failed") 209 assert.True(t, pk.Equals(pkComprCheck), "key equality check failed") 210 pkCheckComprBytes := pkComprCheck.EncodeCompressed() 211 assert.Equal(t, pkComprBytes, pkCheckComprBytes, "keys should be equal") 212 distinctPkComprBytes := distinctSk.PublicKey().EncodeCompressed() 213 assert.NotEqual(t, pkComprBytes, distinctPkComprBytes, "keys should be different") 214 } 215 }) 216 217 // test invalid private keys (equal to the curve group order) 218 t.Run("private keys equal to the group order", func(t *testing.T) { 219 groupOrder := make(map[SigningAlgorithm][]byte) 220 groupOrder[ECDSAP256] = []byte{255, 255, 255, 255, 0, 0, 0, 0, 255, 255, 255, 221 255, 255, 255, 255, 255, 188, 230, 250, 173, 167, 222 23, 158, 132, 243, 185, 202, 194, 252, 99, 37, 81} 223 224 groupOrder[ECDSASecp256k1] = []byte{255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 225 255, 255, 255, 255, 255, 254, 186, 174, 220, 230, 226 175, 72, 160, 59, 191, 210, 94, 140, 208, 54, 65, 65} 227 228 groupOrder[BLSBLS12381] = BLS12381Order 229 230 sk, err := DecodePrivateKey(salg, groupOrder[salg]) 231 require.Error(t, err, "the key decoding should fail - private key value is too large") 232 assert.True(t, IsInvalidInputsError(err)) 233 assert.Nil(t, sk) 234 }) 235 236 // test invalid private and public keys (invalid length) 237 t.Run("invalid key length", func(t *testing.T) { 238 // private key 239 skLens := make(map[SigningAlgorithm]int) 240 skLens[ECDSAP256] = PrKeyLenECDSAP256 241 skLens[ECDSASecp256k1] = PrKeyLenECDSASecp256k1 242 skLens[BLSBLS12381] = 32 243 244 bytes := make([]byte, skLens[salg]+1) 245 sk, err := DecodePrivateKey(salg, bytes) 246 require.Error(t, err) 247 assert.True(t, IsInvalidInputsError(err)) 248 assert.Nil(t, sk) 249 250 // public key 251 pkLens := make(map[SigningAlgorithm]int) 252 pkLens[ECDSAP256] = PubKeyLenECDSAP256 253 pkLens[ECDSASecp256k1] = PubKeyLenECDSASecp256k1 254 pkLens[BLSBLS12381] = 96 255 256 bytes = make([]byte, pkLens[salg]+1) 257 pk, err := DecodePublicKey(salg, bytes) 258 require.Error(t, err) 259 assert.True(t, IsInvalidInputsError(err)) 260 assert.Nil(t, pk) 261 }) 262 } 263 264 func testEquals(t *testing.T, salg SigningAlgorithm, otherSigAlgo SigningAlgorithm) { 265 t.Logf("Testing Equals for %s", salg) 266 rand := getPRG(t) 267 // make sure the length is larger than minimum lengths of all the signaure algos 268 seedMinLength := 48 269 270 // generate a key pair 271 seed := make([]byte, seedMinLength) 272 n, err := rand.Read(seed) 273 require.Equal(t, n, seedMinLength) 274 require.NoError(t, err) 275 276 // first pair 277 sk1, err := GeneratePrivateKey(salg, seed) 278 require.NoError(t, err) 279 pk1 := sk1.PublicKey() 280 281 // second pair without changing the seed 282 sk2, err := GeneratePrivateKey(salg, seed) 283 require.NoError(t, err) 284 pk2 := sk2.PublicKey() 285 286 // unrelated algo pair 287 sk3, err := GeneratePrivateKey(otherSigAlgo, seed) 288 require.NoError(t, err) 289 pk3 := sk3.PublicKey() 290 291 // fourth pair with same algo but a different seed 292 seed[0] ^= 1 293 sk4, err := GeneratePrivateKey(salg, seed) 294 require.NoError(t, err) 295 pk4 := sk4.PublicKey() 296 297 // tests 298 assert.True(t, sk1.Equals(sk2), "key equality should return true") 299 assert.True(t, pk1.Equals(pk2), "key equality should return true") 300 assert.False(t, sk1.Equals(sk3), "key equality should return false") 301 assert.False(t, pk1.Equals(pk3), "key equality should return false") 302 assert.False(t, sk1.Equals(sk4), "key equality should return false") 303 assert.False(t, pk1.Equals(pk4), "key equality should return false") 304 } 305 306 func testKeysAlgorithm(t *testing.T, sk PrivateKey, salg SigningAlgorithm) { 307 t.Logf("Testing key.Algorithm for %s", salg) 308 alg := sk.Algorithm() 309 assert.Equal(t, alg, salg) 310 alg = sk.PublicKey().Algorithm() 311 assert.Equal(t, alg, salg) 312 } 313 314 func testKeySize(t *testing.T, sk PrivateKey, skLen int, pkLen int) { 315 t.Logf("Testing key.Size for %s", sk.Algorithm()) 316 size := sk.Size() 317 assert.Equal(t, size, skLen) 318 size = sk.PublicKey().Size() 319 assert.Equal(t, size, pkLen) 320 } 321 322 func benchVerify(b *testing.B, algo SigningAlgorithm, halg hash.Hasher) { 323 seed := make([]byte, 48) 324 for j := 0; j < len(seed); j++ { 325 seed[j] = byte(j) 326 } 327 sk, err := GeneratePrivateKey(algo, seed) 328 require.NoError(b, err) 329 pk := sk.PublicKey() 330 331 input := []byte("Bench input") 332 s, err := sk.Sign(input, halg) 333 require.NoError(b, err) 334 var result bool 335 336 b.ResetTimer() 337 for i := 0; i < b.N; i++ { 338 result, err = pk.Verify(s, input, halg) 339 require.NoError(b, err) 340 } 341 // sanity check 342 require.True(b, result) 343 344 b.StopTimer() 345 } 346 347 func benchSign(b *testing.B, algo SigningAlgorithm, halg hash.Hasher) { 348 seed := make([]byte, 48) 349 for j := 0; j < len(seed); j++ { 350 seed[j] = byte(j) 351 } 352 sk, err := GeneratePrivateKey(algo, seed) 353 require.NoError(b, err) 354 355 input := []byte("Bench input") 356 var signature []byte 357 358 b.ResetTimer() 359 for i := 0; i < b.N; i++ { 360 signature, err = sk.Sign(input, halg) 361 require.NoError(b, err) 362 } 363 // sanity check 364 result, err := sk.PublicKey().Verify(signature, input, halg) 365 require.NoError(b, err) 366 require.True(b, result) 367 368 b.StopTimer() 369 }