Skip to content

Commit 21d554e

Browse files
committed
Break test vectors CPP file into multiple files
1 parent dd919f2 commit 21d554e

16 files changed

+1939
-2012
lines changed

lib/mls_vectors/src/common.cpp

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
#include "common.h"
2+
3+
namespace mls_vectors {
4+
5+
using namespace mls;
6+
7+
///
8+
/// Assertions for verifying test vectors
9+
///
10+
11+
std::ostream&
12+
operator<<(std::ostream& str, const NodeIndex& obj)
13+
{
14+
return str << obj.val;
15+
}
16+
17+
std::ostream&
18+
operator<<(std::ostream& str, const NodeCount& obj)
19+
{
20+
return str << obj.val;
21+
}
22+
23+
std::ostream&
24+
operator<<(std::ostream& str, const std::vector<uint8_t>& obj)
25+
{
26+
return str << to_hex(obj);
27+
}
28+
29+
std::ostream&
30+
operator<<(std::ostream& str, const GroupContent::RawContent& obj)
31+
{
32+
return var::visit(
33+
overloaded{
34+
[&](const Proposal&) -> std::ostream& { return str << "[Proposal]"; },
35+
[&](const Commit&) -> std::ostream& { return str << "[Commit]"; },
36+
[&](const ApplicationData&) -> std::ostream& {
37+
return str << "[ApplicationData]";
38+
},
39+
},
40+
obj);
41+
}
42+
43+
} // namespace mls_vectors

lib/mls_vectors/src/crypto_basics.cpp

Lines changed: 177 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,177 @@
1+
#include "common.h"
2+
#include <mls_vectors/mls_vectors.h>
3+
4+
namespace mls_vectors {
5+
6+
using namespace mls;
7+
8+
CryptoBasicsTestVector::RefHash::RefHash(CipherSuite suite,
9+
PseudoRandom::Generator&& prg)
10+
: label("RefHash")
11+
, value(prg.secret("value"))
12+
, out(suite.raw_ref(from_ascii(label), value))
13+
{
14+
}
15+
16+
std::optional<std::string>
17+
CryptoBasicsTestVector::RefHash::verify(CipherSuite suite) const
18+
{
19+
VERIFY_EQUAL("ref hash", out, suite.raw_ref(from_ascii(label), value));
20+
return std::nullopt;
21+
}
22+
23+
CryptoBasicsTestVector::ExpandWithLabel::ExpandWithLabel(
24+
CipherSuite suite,
25+
PseudoRandom::Generator&& prg)
26+
: secret(prg.secret("secret"))
27+
, label("ExpandWithLabel")
28+
, context(prg.secret("context"))
29+
, length(static_cast<uint16_t>(prg.output_length()))
30+
, out(suite.expand_with_label(secret, label, context, length))
31+
{
32+
}
33+
34+
std::optional<std::string>
35+
CryptoBasicsTestVector::ExpandWithLabel::verify(CipherSuite suite) const
36+
{
37+
VERIFY_EQUAL("expand with label",
38+
out,
39+
suite.expand_with_label(secret, label, context, length));
40+
return std::nullopt;
41+
}
42+
43+
CryptoBasicsTestVector::DeriveSecret::DeriveSecret(
44+
CipherSuite suite,
45+
PseudoRandom::Generator&& prg)
46+
: secret(prg.secret("secret"))
47+
, label("DeriveSecret")
48+
, out(suite.derive_secret(secret, label))
49+
{
50+
}
51+
52+
std::optional<std::string>
53+
CryptoBasicsTestVector::DeriveSecret::verify(CipherSuite suite) const
54+
{
55+
VERIFY_EQUAL("derive secret", out, suite.derive_secret(secret, label));
56+
return std::nullopt;
57+
}
58+
59+
CryptoBasicsTestVector::DeriveTreeSecret::DeriveTreeSecret(
60+
CipherSuite suite,
61+
PseudoRandom::Generator&& prg)
62+
: secret(prg.secret("secret"))
63+
, label("DeriveTreeSecret")
64+
, generation(prg.uint32("generation"))
65+
, length(static_cast<uint16_t>(prg.output_length()))
66+
, out(suite.derive_tree_secret(secret, label, generation, length))
67+
{
68+
}
69+
70+
std::optional<std::string>
71+
CryptoBasicsTestVector::DeriveTreeSecret::verify(CipherSuite suite) const
72+
{
73+
VERIFY_EQUAL("derive tree secret",
74+
out,
75+
suite.derive_tree_secret(secret, label, generation, length));
76+
return std::nullopt;
77+
}
78+
79+
CryptoBasicsTestVector::SignWithLabel::SignWithLabel(
80+
CipherSuite suite,
81+
PseudoRandom::Generator&& prg)
82+
: priv(prg.signature_key("priv"))
83+
, pub(priv.public_key)
84+
, content(prg.secret("content"))
85+
, label("SignWithLabel")
86+
, signature(priv.sign(suite, label, content))
87+
{
88+
}
89+
90+
std::optional<std::string>
91+
CryptoBasicsTestVector::SignWithLabel::verify(CipherSuite suite) const
92+
{
93+
VERIFY("verify with label", pub.verify(suite, label, content, signature));
94+
95+
auto new_signature = priv.sign(suite, label, content);
96+
VERIFY("sign with label", pub.verify(suite, label, content, new_signature));
97+
98+
return std::nullopt;
99+
}
100+
101+
CryptoBasicsTestVector::EncryptWithLabel::EncryptWithLabel(
102+
CipherSuite suite,
103+
PseudoRandom::Generator&& prg)
104+
: priv(prg.hpke_key("priv"))
105+
, pub(priv.public_key)
106+
, label("EncryptWithLabel")
107+
, context(prg.secret("context"))
108+
, plaintext(prg.secret("plaintext"))
109+
{
110+
auto ct = pub.encrypt(suite, label, context, plaintext);
111+
kem_output = ct.kem_output;
112+
ciphertext = ct.ciphertext;
113+
}
114+
115+
std::optional<std::string>
116+
CryptoBasicsTestVector::EncryptWithLabel::verify(CipherSuite suite) const
117+
{
118+
auto ct = HPKECiphertext{ kem_output, ciphertext };
119+
auto pt = priv.decrypt(suite, label, context, ct);
120+
VERIFY_EQUAL("decrypt with label", pt, plaintext);
121+
122+
auto new_ct = pub.encrypt(suite, label, context, plaintext);
123+
auto new_pt = priv.decrypt(suite, label, context, new_ct);
124+
VERIFY_EQUAL("encrypt with label", new_pt, plaintext);
125+
126+
return std::nullopt;
127+
}
128+
129+
CryptoBasicsTestVector::CryptoBasicsTestVector(CipherSuite suite)
130+
: PseudoRandom(suite, "crypto-basics")
131+
, cipher_suite(suite)
132+
, ref_hash(suite, prg.sub("ref_hash"))
133+
, expand_with_label(suite, prg.sub("expand_with_label"))
134+
, derive_secret(suite, prg.sub("derive_secret"))
135+
, derive_tree_secret(suite, prg.sub("derive_tree_secret"))
136+
, sign_with_label(suite, prg.sub("sign_with_label"))
137+
, encrypt_with_label(suite, prg.sub("encrypt_with_label"))
138+
{
139+
}
140+
141+
std::optional<std::string>
142+
CryptoBasicsTestVector::verify() const
143+
{
144+
auto result = ref_hash.verify(cipher_suite);
145+
if (result) {
146+
return result;
147+
}
148+
149+
result = expand_with_label.verify(cipher_suite);
150+
if (result) {
151+
return result;
152+
}
153+
154+
result = derive_secret.verify(cipher_suite);
155+
if (result) {
156+
return result;
157+
}
158+
159+
result = derive_tree_secret.verify(cipher_suite);
160+
if (result) {
161+
return result;
162+
}
163+
164+
result = sign_with_label.verify(cipher_suite);
165+
if (result) {
166+
return result;
167+
}
168+
169+
result = encrypt_with_label.verify(cipher_suite);
170+
if (result) {
171+
return result;
172+
}
173+
174+
return std::nullopt;
175+
}
176+
177+
} // namespace mls_vectors

lib/mls_vectors/src/key_schedule.cpp

Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
#include "common.h"
2+
#include <mls_vectors/mls_vectors.h>
3+
4+
namespace mls_vectors {
5+
6+
using namespace mls;
7+
8+
KeyScheduleTestVector::KeyScheduleTestVector(CipherSuite suite,
9+
uint32_t n_epochs)
10+
: PseudoRandom(suite, "key-schedule")
11+
, cipher_suite(suite)
12+
, group_id(prg.secret("group_id"))
13+
, initial_init_secret(prg.secret("group_id"))
14+
{
15+
auto group_context = GroupContext{ suite, group_id, 0, {}, {}, {} };
16+
auto epoch = KeyScheduleEpoch(cipher_suite);
17+
epoch.init_secret = initial_init_secret;
18+
19+
for (uint64_t i = 0; i < n_epochs; i++) {
20+
auto epoch_prg = prg.sub(to_hex(tls::marshal(i)));
21+
22+
group_context.tree_hash = epoch_prg.secret("tree_hash");
23+
group_context.confirmed_transcript_hash =
24+
epoch_prg.secret("confirmed_transcript_hash");
25+
auto ctx = tls::marshal(group_context);
26+
27+
// TODO(RLB) Add Test case for externally-driven epoch change
28+
auto commit_secret = epoch_prg.secret("commit_secret");
29+
auto psk_secret = epoch_prg.secret("psk_secret");
30+
epoch = epoch.next_raw(commit_secret, psk_secret, std::nullopt, ctx);
31+
32+
auto welcome_secret = KeyScheduleEpoch::welcome_secret_raw(
33+
cipher_suite, epoch.joiner_secret, psk_secret);
34+
35+
auto exporter_prg = epoch_prg.sub("exporter");
36+
auto exporter_label = to_hex(exporter_prg.secret("label"));
37+
auto exporter_context = exporter_prg.secret("context");
38+
auto exporter_length = cipher_suite.secret_size();
39+
auto exported =
40+
epoch.do_export(exporter_label, exporter_context, exporter_length);
41+
42+
epochs.push_back({ group_context.tree_hash,
43+
commit_secret,
44+
psk_secret,
45+
group_context.confirmed_transcript_hash,
46+
47+
ctx,
48+
49+
epoch.joiner_secret,
50+
welcome_secret,
51+
epoch.init_secret,
52+
53+
epoch.sender_data_secret,
54+
epoch.encryption_secret,
55+
epoch.exporter_secret,
56+
epoch.epoch_authenticator,
57+
epoch.external_secret,
58+
epoch.confirmation_key,
59+
epoch.membership_key,
60+
epoch.resumption_psk,
61+
62+
epoch.external_priv.public_key,
63+
64+
{
65+
exporter_label,
66+
exporter_context,
67+
exporter_length,
68+
exported,
69+
} });
70+
71+
group_context.epoch += 1;
72+
}
73+
}
74+
75+
std::optional<std::string>
76+
KeyScheduleTestVector::verify() const
77+
{
78+
auto group_context = GroupContext{ cipher_suite, group_id, 0, {}, {}, {} };
79+
auto epoch = KeyScheduleEpoch(cipher_suite);
80+
epoch.init_secret = initial_init_secret;
81+
82+
for (const auto& tve : epochs) {
83+
group_context.tree_hash = tve.tree_hash;
84+
group_context.confirmed_transcript_hash = tve.confirmed_transcript_hash;
85+
auto ctx = tls::marshal(group_context);
86+
VERIFY_EQUAL("group context", ctx, tve.group_context);
87+
88+
epoch =
89+
epoch.next_raw(tve.commit_secret, tve.psk_secret, std::nullopt, ctx);
90+
91+
// Verify the rest of the epoch
92+
VERIFY_EQUAL("joiner secret", epoch.joiner_secret, tve.joiner_secret);
93+
94+
auto welcome_secret = KeyScheduleEpoch::welcome_secret_raw(
95+
cipher_suite, tve.joiner_secret, tve.psk_secret);
96+
VERIFY_EQUAL("welcome secret", welcome_secret, tve.welcome_secret);
97+
98+
VERIFY_EQUAL(
99+
"sender data secret", epoch.sender_data_secret, tve.sender_data_secret);
100+
VERIFY_EQUAL(
101+
"encryption secret", epoch.encryption_secret, tve.encryption_secret);
102+
VERIFY_EQUAL("exporter secret", epoch.exporter_secret, tve.exporter_secret);
103+
VERIFY_EQUAL("epoch authenticator",
104+
epoch.epoch_authenticator,
105+
tve.epoch_authenticator);
106+
VERIFY_EQUAL("external secret", epoch.external_secret, tve.external_secret);
107+
VERIFY_EQUAL(
108+
"confirmation key", epoch.confirmation_key, tve.confirmation_key);
109+
VERIFY_EQUAL("membership key", epoch.membership_key, tve.membership_key);
110+
VERIFY_EQUAL("resumption psk", epoch.resumption_psk, tve.resumption_psk);
111+
VERIFY_EQUAL("init secret", epoch.init_secret, tve.init_secret);
112+
113+
VERIFY_EQUAL(
114+
"external pub", epoch.external_priv.public_key, tve.external_pub);
115+
116+
auto exported = epoch.do_export(
117+
tve.exporter.label, tve.exporter.context, tve.exporter.length);
118+
VERIFY_EQUAL("exported", exported, tve.exporter.secret);
119+
120+
group_context.epoch += 1;
121+
}
122+
123+
return std::nullopt;
124+
}
125+
126+
} // namespace mls_vectors

0 commit comments

Comments
 (0)