Add DILITHIUM_public_from_private function.

Change-Id: I9b9c53d4f994bd0fc731c9fff3119f0d388900e9
Reviewed-on: https://boringssl-review.googlesource.com/c/boringssl/+/69667
Reviewed-by: Adam Langley <agl@google.com>
Commit-Queue: Adam Langley <agl@google.com>
This commit is contained in:
Guillaume Endignoux
2024-07-03 13:34:58 +00:00
committed by Boringssl LUCI CQ
parent 12f0f4bec2
commit 7c2b62e934
3 changed files with 68 additions and 7 deletions
+42
View File
@@ -1214,6 +1214,48 @@ err:
return ret;
}
int DILITHIUM_public_from_private(
struct DILITHIUM_public_key *out_public_key,
const struct DILITHIUM_private_key *private_key) {
int ret = 0;
// Intermediate values, allocated on the heap to allow use when there is a
// limited amount of stack.
struct values_st {
matrix a_ntt;
vectorl s1_ntt;
vectork t;
vectork t0;
};
struct values_st *values = OPENSSL_malloc(sizeof(*values));
if (values == NULL) {
goto err;
}
const struct private_key *priv = private_key_from_external(private_key);
struct public_key *pub = public_key_from_external(out_public_key);
OPENSSL_memcpy(pub->rho, priv->rho, sizeof(pub->rho));
OPENSSL_memcpy(pub->public_key_hash, priv->public_key_hash,
sizeof(pub->public_key_hash));
matrix_expand(&values->a_ntt, priv->rho);
OPENSSL_memcpy(&values->s1_ntt, &priv->s1, sizeof(values->s1_ntt));
vectorl_ntt(&values->s1_ntt);
matrix_mult(&values->t, &values->a_ntt, &values->s1_ntt);
vectork_inverse_ntt(&values->t);
vectork_add(&values->t, &values->t, &priv->s2);
vectork_power2_round(&pub->t1, &values->t0, &values->t);
ret = 1;
err:
OPENSSL_free(values);
return ret;
}
// FIPS 204, Algorithm 2 (`ML-DSA.Sign`). Returns 1 on success and 0 on failure.
static int dilithium_sign_with_randomizer(
uint8_t out_encoded_signature[DILITHIUM_SIGNATURE_BYTES],
+20 -7
View File
@@ -92,6 +92,23 @@ TEST(DilithiumTest, SignatureIsRandomized) {
1);
}
TEST(DilithiumTest, PublicFromPrivateIsConsistent) {
std::vector<uint8_t> encoded_public_key(DILITHIUM_PUBLIC_KEY_BYTES);
auto priv = std::make_unique<DILITHIUM_private_key>();
EXPECT_TRUE(DILITHIUM_generate_key(encoded_public_key.data(), priv.get()));
auto pub = std::make_unique<DILITHIUM_public_key>();
EXPECT_TRUE(DILITHIUM_public_from_private(pub.get(), priv.get()));
std::vector<uint8_t> encoded_public_key2(DILITHIUM_PUBLIC_KEY_BYTES);
CBB cbb;
CBB_init_fixed(&cbb, encoded_public_key2.data(), encoded_public_key2.size());
ASSERT_TRUE(DILITHIUM_marshal_public_key(&cbb, pub.get()));
EXPECT_EQ(Bytes(encoded_public_key2), Bytes(encoded_public_key));
}
TEST(DilithiumTest, InvalidPublicKeyEncodingLength) {
// Encode a public key with a trailing 0 at the end.
std::vector<uint8_t> encoded_public_key(DILITHIUM_PUBLIC_KEY_BYTES + 1);
@@ -100,13 +117,13 @@ TEST(DilithiumTest, InvalidPublicKeyEncodingLength) {
// Public key is 1 byte too short.
CBS cbs = bssl::MakeConstSpan(encoded_public_key)
.first(DILITHIUM_PUBLIC_KEY_BYTES - 1);
.first(DILITHIUM_PUBLIC_KEY_BYTES - 1);
auto parsed_pub = std::make_unique<DILITHIUM_public_key>();
EXPECT_FALSE(DILITHIUM_parse_public_key(parsed_pub.get(), &cbs));
// Public key has the correct length.
cbs = bssl::MakeConstSpan(encoded_public_key)
.first(DILITHIUM_PUBLIC_KEY_BYTES);
cbs =
bssl::MakeConstSpan(encoded_public_key).first(DILITHIUM_PUBLIC_KEY_BYTES);
EXPECT_TRUE(DILITHIUM_parse_public_key(parsed_pub.get(), &cbs));
// Public key is 1 byte too long.
@@ -142,10 +159,6 @@ TEST(DilithiumTest, InvalidPrivateKeyEncodingLength) {
EXPECT_FALSE(DILITHIUM_parse_private_key(parsed_priv.get(), &cbs));
}
// TODO: Add more parsing tests:
// - signed values out of range (private key's s1/s2 beyond ETA)
// - signature hints not in the canonical order (signature malleability)
static void DilithiumFileTest(FileTest *t) {
std::vector<uint8_t> seed, message, public_key_expected, private_key_expected,
signed_message_expected;
+6
View File
@@ -70,6 +70,12 @@ OPENSSL_EXPORT int DILITHIUM_generate_key(
uint8_t out_encoded_public_key[DILITHIUM_PUBLIC_KEY_BYTES],
struct DILITHIUM_private_key *out_private_key);
// DILITHIUM_public_from_private sets |*out_public_key| to the public key that
// corresponds to |private_key|. Returns 1 on success and 0 on failure.
OPENSSL_EXPORT int DILITHIUM_public_from_private(
struct DILITHIUM_public_key *out_public_key,
const struct DILITHIUM_private_key *private_key);
// DILITHIUM_sign generates a signature for the message |msg| of length
// |msg_len| using |private_key| following the randomized algorithm, and writes
// the encoded signature to |out_encoded_signature|. Returns 1 on success and 0