Skip to content

Commit b8abab1

Browse files
authored
Merge pull request #90 from tomato42/seed-api
Add support for deriving keys from a specified seed
2 parents 038a5d9 + 53f4d8f commit b8abab1

File tree

2 files changed

+172
-0
lines changed

2 files changed

+172
-0
lines changed

src/kyber_py/ml_kem/ml_kem.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -292,6 +292,26 @@ def keygen(self):
292292
) = self._keygen_internal(d, z)
293293
return (ek, dk)
294294

295+
def key_derive(self, seed):
296+
"""
297+
Derive an encapsulation key and corresponding decapsulation key
298+
following the approach from Section 7.1 (FIPS 203)
299+
with storage of the ``seed`` value for later expansion.
300+
301+
``seed`` is a byte-encoded concatenation of the ``d`` and ``z``
302+
values.
303+
304+
:return: Tuple with encapsulation key and decapsulation key.
305+
:rtype: tuple(bytes, bytes)
306+
"""
307+
if len(seed) != 64:
308+
raise ValueError("The seed must be 64 bytes long")
309+
310+
d = seed[:32]
311+
z = seed[32:]
312+
ek, dk = self._keygen_internal(d, z)
313+
return (ek, dk)
314+
295315
def _encaps_internal(self, ek, m):
296316
"""
297317
Uses the encapsulation key and randomness to generate a key and an

tests/test_ml_kem.py

Lines changed: 152 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,158 @@ def test_decaps_hash_check_failure(self):
8383
dk_bad = b"0" * len(dk)
8484
self.assertRaises(ValueError, lambda: ML_KEM_512.decaps(dk_bad, c))
8585

86+
def test_derive_with_wrong_seed_length(self):
87+
with self.assertRaises(ValueError) as e:
88+
ML_KEM_512.key_derive(bytes(range(63)))
89+
90+
self.assertIn("seed must be 64 bytes", str(e.exception))
91+
92+
# test vectors copied from
93+
# https://datatracker.ietf.org/doc/html/draft-ietf-lamps-kyber-certificates-07
94+
def test_derive_from_seed_ML_KEM_512(self):
95+
ek, _ = ML_KEM_512.key_derive(bytes(range(64)))
96+
97+
exp_ek = bytes.fromhex(
98+
"""
99+
3995815e597d104355cf29aa5333c93251869d5bcdbe487124f602b8b6a66c16
100+
c4761648ad765cf5d8006b515e905a7f0ac076b0c62efa328153e7ca5701699f
101+
1305f1e6bc6f90b0e49b693512b6ce992a8b8016ddfc1a662c7e3f9619cbd869
102+
dd771af30896ccd5918ac6cb77466c5e779996d67ff9aabc97503f2c7b7e2d00
103+
0d86450fb1807ca4cabda465825a31c789a1b7a491ab3872765d320d0b71920f
104+
a213c94093416b83b8124e69f65e62cb5000dcc37aa9a0fff73970c4772f357d
105+
24189ca6f5305568c0e2376a3762a68c605e563c5d209572e0fc7532ca294729
106+
535567b5fc413c5e8792d2464536cc808f98add74664f141566f9016a90a5418
107+
29a98a0464ce41a8bb44c2d4fa3c2c209460728ef14a1a7c4c9b98d12203b4cc
108+
3529160a9ab2d7838f7ff6b53ae05aa31a7d646b7afa6c45932526a3c3755619
109+
be994c211c2a31c05b3447836cb2150be1829dae6b04c5535cff546e392ba797
110+
411720f924f490a5ac5495f21356d550b782a64c1688b6b655bcc7842197a434
111+
c2f6563b5b7f09a78bcc488232783561d16f4cbab6755400050781570c66604b
112+
817ad1252294736e8b01861a4b5a74519b8b6fe51489a5072392e587626c7137
113+
76575d33806a1c8e2732af97c2680f51666331c4eb8bbc0431c4f96832daf1b3
114+
c45528fba153f6c78b1c198702947ccd337727a46fb53ba11de5cb4191346859
115+
516cb6ad72400f3cf209b236aef35a580ac87eb3e30fafd66973ca8a7dd2675a
116+
f41f7a17b61433cd1af80f7708869f665488497980b1ac10a0cdcb636a00ed86
117+
81b35e429124ca80350725b85f83a5eac3a4a3cc1600903e65293560b9b336e5
118+
af0d529dac1a048119302cb7a9bcc110b94851bf02117f199dc485a852b7473f
119+
09b831a6831d5b54c0b790d225cf6bb92d9462a26cdb33dda5123c7aaf0e26a0
120+
b83655eea28bf3a8074725018fd6bae4b601cf61baab71a7a3d35197a343e74b
121+
4a272c125d540896426d85b7958d3b38a6ba987ec37225c7b44cdb12dde4539b
122+
4ab082363683f04bf7a09cc5c41dfe830a1b162e0b324334362f084a14467723
123+
344badd000f8d8c537c48f998f05307cebd1ede0b81c3bc59a065a1b6d63b26c
124+
"""
125+
)
126+
127+
self.assertEqual(len(ek), len(exp_ek))
128+
self.assertEqual(ek, exp_ek)
129+
130+
def test_derive_from_seed_ML_KEM_768(self):
131+
ek, _ = ML_KEM_768.key_derive(bytes(range(64)))
132+
133+
exp_ek = bytes.fromhex(
134+
"""
135+
298aa10d423c8dda069d02bc59e6cdf03a096b8b3da4cab9b80ca4a14907672c
136+
cef1ec4faf234a0bc5b7e9d473f2b3133b3b26a1d175cb67a7805919699c02f7
137+
6531b99c5f89180704bb4ca4535c5b8972679c660a07c5e514b87009c862eb8f
138+
5157695efb3fc40a9def6b81c1cc02a249ae4f094ad0d9bd3485c1c1c6808052
139+
0a7c8c632032cee738154e5c5176c07da56024776a430fe76eacf665a3f7b832
140+
102215bc82f10939c8355704336a8fac1d81e4bb0485aa5d7c74d6b59bbe5c5e
141+
972a0d8bac411b55b5d5557cd680a1a8f71b4eb86bc48c9a0509731a54bd9d72
142+
90b27963e4372dc9b199cfdcac0b01acd28a62395112e4c43648d622c48c8234
143+
d01440e8cc376c927f23a5afc9ac0474c662274e424525c8552ece3b3fe26516
144+
de901bc7d515bde89558e626c95c80b93342f8010004f39e6c6c94871c5e344c
145+
ab3966c835f9a96a59afd31c40286b38b1c1a78470bab947518934453ce86736
146+
a919f1f5a6d510a86f5454fc3980cb5c765bd2bd5f7b36b1410d6635c8ceb47c
147+
4dda0d76a28eac939c71c3024804866c71626658442163c2c22117e50acefce6
148+
378a985652302a4ef0c2ce0cc716b7796e2b6b2e3777dfa1ac3da259a31b5a9b
149+
530f8cb638a81a62ac301849abaf95a7301bda30068909bfdb7e67dbccbb38a5
150+
551a25b1a3a0f685748ad5753d8880f0016c627486166384c5571fe236590036
151+
4d038311e2d875db366686932b5ec602430a369e87a6ef5c338786657825bd4c
152+
057aceb923eb0935e6905e63b4ced7f80857a773dd64b150d26612ea9ac12052
153+
db2017bf1843ccb4b3281b690dc728adfa85c00281b8e3c09287335f856b4fc2
154+
892f69a2f57921ada01914c40988662d57769662a786351b9b66493dab79594d
155+
986de2100d65ba0ff4ea58b81538d24a4435a258fac25404aa7f41f658b13850
156+
65e158dcb60115732720f40459aaac15e406953a90ac52997d1ccd070060efc6
157+
5db9e653354467fad56ec713c86e7540c423acf2669f52fa6f4ac6888d871ef3
158+
e847c029a8aafbb92e17b24aa079b1f419ba6175b442afb11909d4a56b70a033
159+
5b28739218aa7c9348e2c3c2f3eb3d15a41e6417c0dd94bfeb21419b311a7bb1
160+
3a180bbe833218a9a6b17447cc85f225859587a73077049acbcfd44d0f025438
161+
e15d1538270d586e1bf83192a9459cf63c0e972f85297679831ecf121509851c
162+
b8340f6f107b0fa1a0efd1b36a8189bc085c4f5cb784e553f41b918f80397ce1
163+
956f785bee377ca9aa8be6998ada30c26b7c3d8c6b55254cc96203b20c42aee0
164+
ac4e1ebb408e49a9e3f879d0ab0785eb7025425d1305a2299c015e120d163b0e
165+
19494ce57253d0246d182745cb8197ab7438b3c1bb7972bec5a306eba3567855
166+
c014699fef65ae54c770a0d85c18400cf642aedc660777ba4b138502bd5a7812
167+
f621f84a48296b98dd4322b6f15828b8a8f0e00a8ba44a53c3a8b143571b0740
168+
abd567daf1cde9c79c204b6d5e259d1766a31bbbcb4e6a05cf4502176b301c1c
169+
2f41247750157bcec85e809b30a4d60d7747cdd0f5b99aa8c826987517793aaa
170+
8080a0b124a8558df72bbe37b75f4edbb6be8216d6c633fb2b2280e25113d869
171+
5e43481c3eeb397eb192505229b67a201ea893c3e2cb32da8bc342fa4dea0578
172+
"""
173+
)
174+
175+
self.assertEqual(len(ek), len(exp_ek))
176+
self.assertEqual(ek, exp_ek)
177+
178+
def test_derive_from_seed_ML_KEM_1024(self):
179+
ek, _ = ML_KEM_1024.key_derive(bytes(range(64)))
180+
181+
exp_ek = bytes.fromhex(
182+
"""
183+
4b94c29450111191823b3514c9ac1ea3d9825ccb86393a2dfb04654fa2192d37
184+
bfad1c497c6502eee5ca80a73bfce0baf5a54a88585a401397a3d232f426a7af
185+
b082bc21a44317090eaac7592c2ea88a653c4491ea193931335f52e989a3c4cc
186+
56d9c553732d57c470fb41ab759b65d2d04445382fcd9c4e344a1128fa9e11e0
187+
4358e192ed014b23232a7ee2b22e23717f44111ee33575399c37646da9813ec9
188+
b212afe94e5dc5c2330a7294cc1f4234a6d3fbb4f1685ab8892c04acb17cd1c1
189+
70d7b0611b6a7176c794cc8c67f55fc923c2ad203100f365991882c30243d778
190+
13843b5ec7c964032263706092ecf00c7516be64e4598ca4226c069bb5e67e41
191+
75cf2286c8dd5c488a6c5861f31baa0bd0269470e8b551dd3bcd38c86c12f9cd
192+
b176c77dc8b6c02a701f478902c8553f694c0d82727b4c4a5c2c1041212aa127
193+
4808b82111b377ec75214e9b1978f76004d4139d98613f4b8e98d20af7b53407
194+
3a509a959b7a7564f9b40ca218bf61829320a8502017954d328d7ac6c769ec29
195+
700756e7b0685b340d5e118059504a49a9a50a10198eb10a5784678eb427d7b4
196+
babb9552933b062897973e1318eaf0a0eac37584a65401b1703e042accd83753
197+
1483f241cadcd1c1d378119e694429db199ac891e4c5343757085bb3ae783667
198+
350c4458d97672e861e80b1d2679510ea3a6f2360c77a46942c7a06a554d2280
199+
80c84b47aef14db17620cb16c06ab30a1be4cda7082be9f87e9c211c46916349
200+
a5ba8eaa5201c7294a3c0885b53b657452108825ec646c90a04612324ee7d031
201+
afe5343132cbef67b6efb1a5ec2809b773538ce77b3d8b04eb0b3c2256011e4c
202+
716c19a8ba0752bf71492117649f0615c3290fc29a46fde4bd52db9286d60338
203+
8244259c15a7ac2b640a60cc03376a5841a3fb8a473568fa9b1a267215f34c01
204+
697b0f0e627175d72105b7707c29b9e614bdc33a6f6c818a95370b427882d7b4
205+
76796a9ec6eb993274cd9b2391a82ba45e3393d2e9ae9721ca9d6c1b988b5827
206+
713f90a6585de9433528c02b03ce10bb5f720138d0fbb4c30c1266b918e52925
207+
dfe17b37f95d22bca54f475919ac859098c0f0d08ac5875ef29b56fd141e6ef1
208+
5f700a0b66f39595c588177373c4669b21bc071e4c3aa5f0b4a31b6258f35da2
209+
4ac3cd29c7f2092410c5078355b138fb53a6b9ae6e0b9c08243e7baa45c47376
210+
eb8c7f13d4cf51aa736fa31540c9241f370da544bf9f9c28d9a57e2f2a7ca95a
211+
4e4b466e641ab3bcc76adf1139d567a6f12b52f3a65e7ec0aae26bcaa8c55833
212+
b04e59998ebc9a1930fbb6d2233c53d2c1f8b9518e3c2de73a19dee6b380a5b3
213+
2971cf64e129fd6c1fa6e75d4a234501e966dd3a540af5c8f4f34a6b4a253ee2
214+
8492566d5e67c6f55855fcb0506fb06c156744d9a03a31a26fa94cad14f157b7
215+
f303d07a69c773768fcb4d079c09059703a0c3a94de4b99ea3a2f16583d0f917
216+
0a3950db07b4f0bc30802927f9f7961b6259892636a9502a2705303637799dd3
217+
44da451c1cf7bf67840ceb3079ab8c6b8c1927f64053c612450c45c9e603bc16
218+
666e596b3471e103b6f15447424d17022048111ffbd37e1c670f64f14b8a7b32
219+
b94c1a49b45dd2fc38cd5289d910ad63602cf5e13042c64ac6797b89fb551ad0
220+
8e05a92d200cccb7e712ef23c9312cb350f029ab537e287347fd3075ac10906a
221+
783f1c6c07ccb88f41228c4be1c640f790b5c3a5d5d3ca792495d74bc4615626
222+
58c07ac600276b924ab5bc9be1f0494cb76f82f460a7480972663381e1699960
223+
61d799859ec54d4f5ca5c411c01db1597b165977669de13a928a34afbac258fe
224+
a8c4764239c9421dc3119bf5b47699206978327b1c5345ef746a7983841f056e
225+
2534100ab24d4e9abbd0b17c6a95bd4c3c0e40f69e1612aceeb28b99086c9511
226+
6e7204273893390bf46b899b36286b0ebf1947bb9884f732ca27da82b19b5dc0
227+
cc7f8885714910888b2310c4f9319d410b34e6433b9003e2176bb99525745610
228+
6e8952163b8ba592530cc5aa0aeb43ad398fe9e97baa523d7a4431677c3d3af0
229+
719e475db85ca95af5089beabeb05b2faab4896ba60f81c88472a57b46a82882
230+
6a0cdfb446f8189182d2bf5eac4ec1cc5deaf599c8a13e48235406d17ffddc83
231+
44b6c66984a868aa92fa02227a086950eb0c8701ed58dc628776b983882e1175
232+
"""
233+
)
234+
235+
self.assertEqual(len(ek), len(exp_ek))
236+
self.assertEqual(ek, exp_ek)
237+
86238

87239
class TestML_KEM_KAT(unittest.TestCase):
88240
"""

0 commit comments

Comments
 (0)