kem_test.go 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226
  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, fail := sk.KEMDecrypt(ct)
  73. require.Equal(0, fail, "KEMDecrypt(): fail")
  74. require.Equal(ss, ss2, "KEMDecrypt(): ss")
  75. }
  76. }
  77. func doTestKEMInvalidSkA(t *testing.T, p *ParameterSet) {
  78. require := require.New(t)
  79. for i := 0; i < nTests; i++ {
  80. // Alice generates a public key.
  81. pk, skA, err := p.GenerateKeyPair(rand.Reader)
  82. require.NoError(err, "GenerateKeyPair()")
  83. // Bob derives a secret key and creates a response.
  84. sendB, keyB, err := pk.KEMEncrypt(rand.Reader)
  85. require.NoError(err, "KEMEncrypt()")
  86. // Replace secret key with random values.
  87. _, err = rand.Read(skA.sk.packed)
  88. require.NoError(err, "rand.Read()")
  89. // Alice uses Bob's response to get her secret key.
  90. keyA, fail := skA.KEMDecrypt(sendB)
  91. require.Equal(-1, fail, "KEMDecrypt(): fail")
  92. require.NotEqual(keyA, keyB, "KEMDecrypt(): ss")
  93. }
  94. }
  95. func doTestKEMInvalidCipherText(t *testing.T, p *ParameterSet) {
  96. require := require.New(t)
  97. var rawPos [2]byte
  98. ciphertextSize := p.CipherTextSize()
  99. for i := 0; i < nTests; i++ {
  100. _, err := rand.Read(rawPos[:])
  101. require.NoError(err, "rand.Read()")
  102. pos := (int(rawPos[0]) << 8) | int(rawPos[1])
  103. // Alice generates a public key.
  104. pk, skA, err := p.GenerateKeyPair(rand.Reader)
  105. require.NoError(err, "GenerateKeyPair()")
  106. // Bob derives a secret key and creates a response.
  107. sendB, keyB, err := pk.KEMEncrypt(rand.Reader)
  108. require.NoError(err, "KEMEncrypt()")
  109. // Change some byte in the ciphertext (i.e., encapsulated key).
  110. sendB[pos%ciphertextSize] ^= 23
  111. // Alice uses Bob's response to get her secret key.
  112. keyA, fail := skA.KEMDecrypt(sendB)
  113. require.Equal(-1, fail, "KEMDecrypt(): fail")
  114. require.NotEqual(keyA, keyB, "KEMDecrypt(): ss")
  115. }
  116. }
  117. func requirePrivateKeyEqual(require *require.Assertions, a, b *PrivateKey) {
  118. require.EqualValues(a.sk, b.sk, "sk (indcpaSecretKey)")
  119. require.Equal(a.z, b.z, "z (random bytes)")
  120. requirePublicKeyEqual(require, &a.PublicKey, &b.PublicKey)
  121. }
  122. func requirePublicKeyEqual(require *require.Assertions, a, b *PublicKey) {
  123. require.EqualValues(a.pk, b.pk, "pk (indcpaPublicKey)")
  124. require.Equal(a.p, b.p, "p (ParameterSet)")
  125. }
  126. func BenchmarkKEM(b *testing.B) {
  127. forceDisableHardwareAcceleration()
  128. doBenchmarkKEM(b)
  129. if !canAccelerate {
  130. b.Log("Hardware acceleration not supported on this host.")
  131. return
  132. }
  133. mustInitHardwareAcceleration()
  134. doBenchmarkKEM(b)
  135. }
  136. func doBenchmarkKEM(b *testing.B) {
  137. impl := "_" + hardwareAccelImpl.name
  138. for _, p := range allParams {
  139. b.Run(p.Name()+"_GenerateKeyPair"+impl, func(b *testing.B) { doBenchKEMGenerateKeyPair(b, p) })
  140. b.Run(p.Name()+"_KEMEncrypt"+impl, func(b *testing.B) { doBenchKEMEncDec(b, p, true) })
  141. b.Run(p.Name()+"_KEMDecrypt"+impl, func(b *testing.B) { doBenchKEMEncDec(b, p, false) })
  142. }
  143. }
  144. func doBenchKEMGenerateKeyPair(b *testing.B, p *ParameterSet) {
  145. for i := 0; i < b.N; i++ {
  146. _, _, err := p.GenerateKeyPair(rand.Reader)
  147. if err != nil {
  148. b.Fatalf("GenerateKeyPair(): %v", err)
  149. }
  150. }
  151. }
  152. func doBenchKEMEncDec(b *testing.B, p *ParameterSet, isEnc bool) {
  153. b.StopTimer()
  154. for i := 0; i < b.N; i++ {
  155. pk, skA, err := p.GenerateKeyPair(rand.Reader)
  156. if err != nil {
  157. b.Fatalf("GenerateKeyPair(): %v", err)
  158. }
  159. if isEnc {
  160. b.StartTimer()
  161. }
  162. sendB, keyB, err := pk.KEMEncrypt(rand.Reader)
  163. if err != nil {
  164. b.Fatalf("KEMEncrypt(): %v", err)
  165. }
  166. if isEnc {
  167. b.StopTimer()
  168. } else {
  169. b.StartTimer()
  170. }
  171. keyA, fail := skA.KEMDecrypt(sendB)
  172. if !isEnc {
  173. b.StopTimer()
  174. }
  175. if fail != 0 {
  176. b.Fatalf("KEMDecrypt(): fail %v", fail)
  177. }
  178. if !bytes.Equal(keyA, keyB) {
  179. b.Fatalf("KEMDecrypt(): key mismatch")
  180. }
  181. }
  182. }
  183. func init() {
  184. canAccelerate = IsHardwareAccelerated()
  185. }