kem_test.go 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220
  1. // kem_test.go - Kyber KEM tests.
  2. //
  3. // To the extent possible under law, Yawning Angel has waived all copyright
  4. // and related or neighboring rights to the software, using the Creative
  5. // Commons "CC0" public domain dedication. See LICENSE or
  6. // <http://creativecommons.org/publicdomain/zero/1.0/> for full details.
  7. package kyber
  8. import (
  9. "bytes"
  10. "crypto/rand"
  11. "testing"
  12. "github.com/stretchr/testify/require"
  13. )
  14. const nTests = 100
  15. var (
  16. allParams = []*ParameterSet{
  17. Kyber512,
  18. Kyber768,
  19. Kyber1024,
  20. }
  21. canAccelerate bool
  22. )
  23. func mustInitHardwareAcceleration() {
  24. initHardwareAcceleration()
  25. if !IsHardwareAccelerated() {
  26. panic("initHardwareAcceleration() failed")
  27. }
  28. }
  29. func TestKEM(t *testing.T) {
  30. forceDisableHardwareAcceleration()
  31. doTestKEM(t)
  32. if !canAccelerate {
  33. t.Log("Hardware acceleration not supported on this host.")
  34. return
  35. }
  36. mustInitHardwareAcceleration()
  37. doTestKEM(t)
  38. }
  39. func doTestKEM(t *testing.T) {
  40. impl := "_" + hardwareAccelImpl.name
  41. for _, p := range allParams {
  42. t.Run(p.Name()+"_Keys"+impl, func(t *testing.T) { doTestKEMKeys(t, p) })
  43. t.Run(p.Name()+"_Invalid_SecretKey_A"+impl, func(t *testing.T) { doTestKEMInvalidSkA(t, p) })
  44. t.Run(p.Name()+"_Invalid_CipherText"+impl, func(t *testing.T) { doTestKEMInvalidCipherText(t, p) })
  45. }
  46. }
  47. func doTestKEMKeys(t *testing.T, p *ParameterSet) {
  48. require := require.New(t)
  49. t.Logf("PrivateKeySize(): %v", p.PrivateKeySize())
  50. t.Logf("PublicKeySize(): %v", p.PublicKeySize())
  51. t.Logf("CipherTextSize(): %v", p.CipherTextSize())
  52. for i := 0; i < nTests; i++ {
  53. // Generate a key pair.
  54. pk, sk, err := p.GenerateKeyPair(rand.Reader)
  55. require.NoError(err, "GenerateKeyPair()")
  56. // Test serialization.
  57. b := sk.Bytes()
  58. require.Len(b, p.PrivateKeySize(), "sk.Bytes(): Length")
  59. sk2, err := p.PrivateKeyFromBytes(b)
  60. require.NoError(err, "PrivateKeyFromBytes(b)")
  61. requirePrivateKeyEqual(require, sk, sk2)
  62. b = pk.Bytes()
  63. require.Len(b, p.PublicKeySize(), "pk.Bytes(): Length")
  64. pk2, err := p.PublicKeyFromBytes(b)
  65. require.NoError(err, "PublicKeyFromBytes(b)")
  66. requirePublicKeyEqual(require, pk, pk2)
  67. // Test encrypt/decrypt.
  68. ct, ss, err := pk.KEMEncrypt(rand.Reader)
  69. require.NoError(err, "KEMEncrypt()")
  70. require.Len(ct, p.CipherTextSize(), "KEMEncrypt(): ct Length")
  71. require.Len(ss, SymSize, "KEMEncrypt(): ss Length")
  72. ss2 := sk.KEMDecrypt(ct)
  73. require.Equal(ss, ss2, "KEMDecrypt(): ss")
  74. }
  75. }
  76. func doTestKEMInvalidSkA(t *testing.T, p *ParameterSet) {
  77. require := require.New(t)
  78. for i := 0; i < nTests; i++ {
  79. // Alice generates a public key.
  80. pk, skA, err := p.GenerateKeyPair(rand.Reader)
  81. require.NoError(err, "GenerateKeyPair()")
  82. // Bob derives a secret key and creates a response.
  83. sendB, keyB, err := pk.KEMEncrypt(rand.Reader)
  84. require.NoError(err, "KEMEncrypt()")
  85. // Replace secret key with random values.
  86. _, err = rand.Read(skA.sk.packed)
  87. require.NoError(err, "rand.Read()")
  88. // Alice uses Bob's response to get her secret key.
  89. keyA := skA.KEMDecrypt(sendB)
  90. require.NotEqual(keyA, keyB, "KEMDecrypt(): ss")
  91. }
  92. }
  93. func doTestKEMInvalidCipherText(t *testing.T, p *ParameterSet) {
  94. require := require.New(t)
  95. var rawPos [2]byte
  96. ciphertextSize := p.CipherTextSize()
  97. for i := 0; i < nTests; i++ {
  98. _, err := rand.Read(rawPos[:])
  99. require.NoError(err, "rand.Read()")
  100. pos := (int(rawPos[0]) << 8) | int(rawPos[1])
  101. // Alice generates a public key.
  102. pk, skA, err := p.GenerateKeyPair(rand.Reader)
  103. require.NoError(err, "GenerateKeyPair()")
  104. // Bob derives a secret key and creates a response.
  105. sendB, keyB, err := pk.KEMEncrypt(rand.Reader)
  106. require.NoError(err, "KEMEncrypt()")
  107. // Change some byte in the ciphertext (i.e., encapsulated key).
  108. sendB[pos%ciphertextSize] ^= 23
  109. // Alice uses Bob's response to get her secret key.
  110. keyA := skA.KEMDecrypt(sendB)
  111. require.NotEqual(keyA, keyB, "KEMDecrypt(): ss")
  112. }
  113. }
  114. func requirePrivateKeyEqual(require *require.Assertions, a, b *PrivateKey) {
  115. require.EqualValues(a.sk, b.sk, "sk (indcpaSecretKey)")
  116. require.Equal(a.z, b.z, "z (random bytes)")
  117. requirePublicKeyEqual(require, &a.PublicKey, &b.PublicKey)
  118. }
  119. func requirePublicKeyEqual(require *require.Assertions, a, b *PublicKey) {
  120. require.EqualValues(a.pk, b.pk, "pk (indcpaPublicKey)")
  121. require.Equal(a.p, b.p, "p (ParameterSet)")
  122. }
  123. func BenchmarkKEM(b *testing.B) {
  124. forceDisableHardwareAcceleration()
  125. doBenchmarkKEM(b)
  126. if !canAccelerate {
  127. b.Log("Hardware acceleration not supported on this host.")
  128. return
  129. }
  130. mustInitHardwareAcceleration()
  131. doBenchmarkKEM(b)
  132. }
  133. func doBenchmarkKEM(b *testing.B) {
  134. impl := "_" + hardwareAccelImpl.name
  135. for _, p := range allParams {
  136. b.Run(p.Name()+"_GenerateKeyPair"+impl, func(b *testing.B) { doBenchKEMGenerateKeyPair(b, p) })
  137. b.Run(p.Name()+"_KEMEncrypt"+impl, func(b *testing.B) { doBenchKEMEncDec(b, p, true) })
  138. b.Run(p.Name()+"_KEMDecrypt"+impl, func(b *testing.B) { doBenchKEMEncDec(b, p, false) })
  139. }
  140. }
  141. func doBenchKEMGenerateKeyPair(b *testing.B, p *ParameterSet) {
  142. for i := 0; i < b.N; i++ {
  143. _, _, err := p.GenerateKeyPair(rand.Reader)
  144. if err != nil {
  145. b.Fatalf("GenerateKeyPair(): %v", err)
  146. }
  147. }
  148. }
  149. func doBenchKEMEncDec(b *testing.B, p *ParameterSet, isEnc bool) {
  150. b.StopTimer()
  151. for i := 0; i < b.N; i++ {
  152. pk, skA, err := p.GenerateKeyPair(rand.Reader)
  153. if err != nil {
  154. b.Fatalf("GenerateKeyPair(): %v", err)
  155. }
  156. if isEnc {
  157. b.StartTimer()
  158. }
  159. sendB, keyB, err := pk.KEMEncrypt(rand.Reader)
  160. if err != nil {
  161. b.Fatalf("KEMEncrypt(): %v", err)
  162. }
  163. if isEnc {
  164. b.StopTimer()
  165. } else {
  166. b.StartTimer()
  167. }
  168. keyA := skA.KEMDecrypt(sendB)
  169. if !isEnc {
  170. b.StopTimer()
  171. }
  172. if !bytes.Equal(keyA, keyB) {
  173. b.Fatalf("KEMDecrypt(): key mismatch")
  174. }
  175. }
  176. }
  177. func init() {
  178. canAccelerate = IsHardwareAccelerated()
  179. }