Skip to content

Commit

Permalink
Ed25519ph, Ed25519ctx, and Ed25519ph w/ External Digest
Browse files Browse the repository at this point in the history
  • Loading branch information
skmcgrail committed Jan 17, 2025
1 parent 232b7b3 commit 0873ba1
Show file tree
Hide file tree
Showing 13 changed files with 1,905 additions and 873 deletions.
325 changes: 298 additions & 27 deletions crypto/fipsmodule/curve25519/curve25519.c

Large diffs are not rendered by default.

27 changes: 20 additions & 7 deletions crypto/fipsmodule/curve25519/curve25519_nohw.c
Original file line number Diff line number Diff line change
Expand Up @@ -1983,7 +1983,7 @@ void ed25519_public_key_from_hashed_seed_nohw(

void ed25519_sign_nohw(uint8_t out_sig[ED25519_SIGNATURE_LEN],
uint8_t r[SHA512_DIGEST_LENGTH], const uint8_t *s, const uint8_t *A,
const void *message, size_t message_len) {
const void *message, size_t message_len, const uint8_t* dom2, size_t dom2_len) {

// Reduce r modulo the order of the base-point B.
x25519_sc_reduce(r);
Expand All @@ -1992,10 +1992,17 @@ void ed25519_sign_nohw(uint8_t out_sig[ED25519_SIGNATURE_LEN],
x25519_ge_scalarmult_base(&R, r);
ge_p3_tobytes(out_sig, &R);

// Compute k = SHA512(R || A || message)
// R is of length 32 octets
uint8_t k[SHA512_DIGEST_LENGTH];
ed25519_sha512(k, out_sig, 32, A, ED25519_PUBLIC_KEY_LEN, message, message_len);
if (dom2_len > 0) {
// Compute k = SHA512(dom2(phflag, context) || R || A || message)
ed25519_sha512(k, dom2, dom2_len, out_sig, 32, A, ED25519_PUBLIC_KEY_LEN, message,
message_len);
} else {
// Compute k = SHA512(R || A || message)
ed25519_sha512(k, out_sig, 32, A, ED25519_PUBLIC_KEY_LEN, message,
message_len, NULL, 0);
}

// Reduce k modulo the order of the base-point B.
x25519_sc_reduce(k);
Expand All @@ -2006,7 +2013,7 @@ void ed25519_sign_nohw(uint8_t out_sig[ED25519_SIGNATURE_LEN],

int ed25519_verify_nohw(uint8_t R_computed_encoded[32],
const uint8_t public_key[ED25519_PUBLIC_KEY_LEN], uint8_t R_expected[32],
uint8_t S[32], const uint8_t *message, size_t message_len) {
uint8_t S[32], const uint8_t *message, size_t message_len, const uint8_t *dom2, size_t dom2_len) {

// Decode public key as A'.
ge_p3 A;
Expand All @@ -2015,10 +2022,16 @@ int ed25519_verify_nohw(uint8_t R_computed_encoded[32],
}

// Step: rfc8032 5.1.7.2
// Compute k = SHA512(R_expected || public_key || message).
uint8_t k[SHA512_DIGEST_LENGTH];
ed25519_sha512(k, R_expected, 32, public_key, ED25519_PUBLIC_KEY_LEN, message,
message_len);
if(dom2_len > 0) {
// Compute k = SHA512(dom2(phflag, context) || R_expected || public_key || message).
ed25519_sha512(k, dom2, dom2_len, R_expected, 32, public_key,
ED25519_PUBLIC_KEY_LEN, message, message_len);
} else {
// Compute k = SHA512(R_expected || public_key || message).
ed25519_sha512(k, R_expected, 32, public_key, ED25519_PUBLIC_KEY_LEN,
message, message_len, NULL, 0);
}

// Reduce k modulo the order of the base-point B. Saves compute in the
// subsequent scalar multiplication.
Expand Down
28 changes: 20 additions & 8 deletions crypto/fipsmodule/curve25519/curve25519_s2n_bignum_asm.c
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ void ed25519_public_key_from_hashed_seed_s2n_bignum(

void ed25519_sign_s2n_bignum(uint8_t out_sig[ED25519_SIGNATURE_LEN],
uint8_t r[SHA512_DIGEST_LENGTH], const uint8_t *s, const uint8_t *A,
const void *message, size_t message_len) {
const void *message, size_t message_len, const uint8_t *dom2, size_t dom2_len) {

uint8_t k[SHA512_DIGEST_LENGTH] = {0};
uint64_t R[8] = {0};
Expand All @@ -69,10 +69,16 @@ void ed25519_sign_s2n_bignum(uint8_t out_sig[ED25519_SIGNATURE_LEN],
edwards25519_scalarmulbase_selector(R, uint64_r);
edwards25519_encode(out_sig, R);

// Compute k = SHA512(R || A || message)
// R is of length 32 octets
ed25519_sha512(k, out_sig, 32, A, ED25519_PUBLIC_KEY_LEN, message,
message_len);
if (dom2_len > 0) {
// Compute k = SHA512(dom2(phflag, context) || R || A || message)
ed25519_sha512(k, dom2, dom2_len, out_sig, 32, A, ED25519_PUBLIC_KEY_LEN, message,
message_len);
} else {
// Compute k = SHA512(R || A || message)
ed25519_sha512(k, out_sig, 32, A, ED25519_PUBLIC_KEY_LEN, message,
message_len, NULL, 0);
}
OPENSSL_memcpy(uint64_k, k, SHA512_DIGEST_LENGTH);
bignum_mod_n25519(uint64_k, 8, uint64_k);

Expand All @@ -84,7 +90,7 @@ void ed25519_sign_s2n_bignum(uint8_t out_sig[ED25519_SIGNATURE_LEN],

int ed25519_verify_s2n_bignum(uint8_t R_computed_encoded[32],
const uint8_t public_key[ED25519_PUBLIC_KEY_LEN], uint8_t R_expected[32],
uint8_t S[32], const uint8_t *message, size_t message_len) {
uint8_t S[32], const uint8_t *message, size_t message_len, const uint8_t *dom2, size_t dom2_len) {

uint8_t k[SHA512_DIGEST_LENGTH] = {0};
uint64_t uint64_k[8] = {0};
Expand All @@ -98,9 +104,15 @@ int ed25519_verify_s2n_bignum(uint8_t R_computed_encoded[32],
}

// Step: rfc8032 5.1.7.2
// Compute k = SHA512(R_expected || public_key || message).
ed25519_sha512(k, R_expected, 32, public_key, ED25519_PUBLIC_KEY_LEN, message,
message_len);
if(dom2_len > 0) {
// Compute k = SHA512(dom2(phflag, context) || R_expected || public_key || message).
ed25519_sha512(k, dom2, dom2_len, R_expected, 32, public_key,
ED25519_PUBLIC_KEY_LEN, message, message_len);
} else {
// Compute k = SHA512(R_expected || public_key || message).
ed25519_sha512(k, R_expected, 32, public_key, ED25519_PUBLIC_KEY_LEN,
message, message_len, NULL, 0);
}
OPENSSL_memcpy(uint64_k, k, SHA512_DIGEST_LENGTH);
bignum_mod_n25519(uint64_k, 8, uint64_k);

Expand Down
117 changes: 117 additions & 0 deletions crypto/fipsmodule/curve25519/ed25519_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -130,3 +130,120 @@ TEST(Ed25519Test, KeypairFromSeed) {
EXPECT_EQ(Bytes(public_key1), Bytes(public_key2));
EXPECT_EQ(Bytes(private_key1), Bytes(private_key2));
}

TEST(Ed25519phTest, RFCTestCase) {
const uint8_t message[3] = {0x61, 0x62, 0x63};
const uint8_t seed[32] = {0x83, 0x3f, 0xe6, 0x24, 0x09, 0x23, 0x7b, 0x9d,
0x62, 0xec, 0x77, 0x58, 0x75, 0x20, 0x91, 0x1e,
0x9a, 0x75, 0x9c, 0xec, 0x1d, 0x19, 0x75, 0x5b,
0x7d, 0xa9, 0x01, 0xb9, 0x6d, 0xca, 0x3d, 0x42};
const uint8_t expected[ED25519_SIGNATURE_LEN] = {
0x98, 0xa7, 0x02, 0x22, 0xf0, 0xb8, 0x12, 0x1a, 0xa9, 0xd3, 0x0f,
0x81, 0x3d, 0x68, 0x3f, 0x80, 0x9e, 0x46, 0x2b, 0x46, 0x9c, 0x7f,
0xf8, 0x76, 0x39, 0x49, 0x9b, 0xb9, 0x4e, 0x6d, 0xae, 0x41, 0x31,
0xf8, 0x50, 0x42, 0x46, 0x3c, 0x2a, 0x35, 0x5a, 0x20, 0x03, 0xd0,
0x62, 0xad, 0xf5, 0xaa, 0xa1, 0x0b, 0x8c, 0x61, 0xe6, 0x36, 0x06,
0x2a, 0xaa, 0xd1, 0x1c, 0x2a, 0x26, 0x08, 0x34, 0x06};

uint8_t public_key[32], private_key[64];
ED25519_keypair_from_seed(public_key, private_key, seed);

uint8_t signature[ED25519_SIGNATURE_LEN] = {0};

ASSERT_TRUE(ED25519ph_sign(signature, &message[0], sizeof(message), private_key, NULL, 0));
ASSERT_TRUE(ED25519ph_verify(&message[0], sizeof(message), signature, public_key, NULL, 0));
ASSERT_EQ(Bytes(expected), Bytes(signature));
}

TEST(Ed25519phTest, TestVectors) {
FileTestGTest("crypto/fipsmodule/curve25519/ed25519ph_tests.txt", [](FileTest *t) {
std::vector<uint8_t> seed, q, message, context, expected_signature;
ASSERT_TRUE(t->GetBytes(&seed, "SEED"));
ASSERT_EQ(32u, seed.size());
ASSERT_TRUE(t->GetBytes(&q, "Q"));
ASSERT_EQ(32u, q.size());
ASSERT_TRUE(t->GetBytes(&message, "MESSAGE"));
ASSERT_TRUE(t->GetBytes(&expected_signature, "SIGNATURE"));
ASSERT_EQ(64u, expected_signature.size());

if (t->HasAttribute("CONTEXT")) {
t->GetBytes(&context, "CONTEXT");
} else {
context = std::vector<uint8_t>();
}

uint8_t private_key[ED25519_PRIVATE_KEY_LEN] = {0};
uint8_t public_key[ED25519_PUBLIC_KEY_LEN] = {0};

ED25519_keypair_from_seed(public_key, private_key, seed.data());
ASSERT_EQ(Bytes(q), Bytes(public_key));

// Signing should not leak the private key or the message.
CONSTTIME_SECRET(&private_key[0], sizeof(private_key));
CONSTTIME_SECRET(message.data(), message.size());
CONSTTIME_SECRET(context.data(), context.size());
uint8_t signature[64];
ASSERT_TRUE(ED25519ph_sign(signature, message.data(), message.size(),
private_key, context.data(), context.size()));
CONSTTIME_DECLASSIFY(signature, sizeof(signature));
CONSTTIME_DECLASSIFY(message.data(), message.size());
CONSTTIME_DECLASSIFY(context.data(), context.size());

EXPECT_EQ(Bytes(expected_signature), Bytes(signature));
EXPECT_TRUE(ED25519ph_verify(message.data(), message.size(), signature,
public_key, context.data(), context.size()));
});
}

TEST(Ed25519ctxTest, TestVectors) {
FileTestGTest("crypto/fipsmodule/curve25519/ed25519ctx_tests.txt", [](FileTest *t) {
std::vector<uint8_t> seed, q, message, context, expected_signature;
ASSERT_TRUE(t->GetBytes(&seed, "SEED"));
ASSERT_EQ(32u, seed.size());
ASSERT_TRUE(t->GetBytes(&q, "Q"));
ASSERT_EQ(32u, q.size());
ASSERT_TRUE(t->GetBytes(&message, "MESSAGE"));
ASSERT_TRUE(t->GetBytes(&expected_signature, "SIGNATURE"));
ASSERT_EQ(64u, expected_signature.size());

if (t->HasAttribute("CONTEXT")) {
t->GetBytes(&context, "CONTEXT");
} else {
context = std::vector<uint8_t>();
}

uint8_t private_key[ED25519_PRIVATE_KEY_LEN] = {0};
uint8_t public_key[ED25519_PUBLIC_KEY_LEN] = {0};

ED25519_keypair_from_seed(public_key, private_key, seed.data());
ASSERT_EQ(Bytes(q), Bytes(public_key));

// Signing should not leak the private key or the message.
CONSTTIME_SECRET(&private_key[0], sizeof(private_key));
CONSTTIME_SECRET(message.data(), message.size());
CONSTTIME_SECRET(context.data(), context.size());
uint8_t signature[64];
ASSERT_TRUE(ED25519ctx_sign(signature, message.data(), message.size(),
private_key, context.data(), context.size()));
CONSTTIME_DECLASSIFY(signature, sizeof(signature));
CONSTTIME_DECLASSIFY(message.data(), message.size());
CONSTTIME_DECLASSIFY(context.data(), context.size());

EXPECT_EQ(Bytes(expected_signature), Bytes(signature));
EXPECT_TRUE(ED25519ctx_verify(message.data(), message.size(), signature,
public_key, context.data(), context.size()));
});
}

TEST(Ed25519ctxTest, EmptyContext) {
uint8_t private_key[ED25519_PRIVATE_KEY_LEN] = {0};
uint8_t public_key[ED25519_PUBLIC_KEY_LEN] = {0};
uint8_t signature[ED25519_SIGNATURE_LEN] = {0};
const uint8_t message[3] = {'f', 'o', 'o'};

ED25519_keypair(public_key, private_key);

EXPECT_FALSE(ED25519ctx_sign(signature, message, sizeof(message), private_key, NULL, 0));
EXPECT_FALSE(ED25519ctx_verify(message, sizeof(message), signature, public_key, NULL, 0));
}

29 changes: 29 additions & 0 deletions crypto/fipsmodule/curve25519/ed25519ctx_tests.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# Test Cases from rfc8032

# foo
SEED = 0305334e381af78f141cb666f6199f57bc3495335a256a95bd2a55bf546663f6
Q = dfc9425e4f968f7f0c29f0259cf5f9aed6851c2bb4ad8bfb860cfee0ab248292
MESSAGE = f726936d19c800494e3fdaff20b276a8
CONTEXT = 666f6f
SIGNATURE = 55a4cc2f70a54e04288c5f4cd1e45a7bb520b36292911876cada7323198dd87a8b36950b95130022907a7fb7c4e9b2d5f6cca685a587b4b21f4b888e4e7edb0d

# bar
SEED = 0305334e381af78f141cb666f6199f57bc3495335a256a95bd2a55bf546663f6
Q = dfc9425e4f968f7f0c29f0259cf5f9aed6851c2bb4ad8bfb860cfee0ab248292
MESSAGE = f726936d19c800494e3fdaff20b276a8
CONTEXT = 626172
SIGNATURE = fc60d5872fc46b3aa69f8b5b4351d5808f92bcc044606db097abab6dbcb1aee3216c48e8b3b66431b5b186d1d28f8ee15a5ca2df6668346291c2043d4eb3e90d

# foo2
SEED = 0305334e381af78f141cb666f6199f57bc3495335a256a95bd2a55bf546663f6
Q = dfc9425e4f968f7f0c29f0259cf5f9aed6851c2bb4ad8bfb860cfee0ab248292
MESSAGE = 508e9e6882b979fea900f62adceaca35
CONTEXT = 666f6f
SIGNATURE = 8b70c1cc8310e1de20ac53ce28ae6e7207f33c3295e03bb5c0732a1d20dc64908922a8b052cf99b7c4fe107a5abb5b2c4085ae75890d02df26269d8945f84b0b

# foo3
SEED = ab9c2853ce297ddab85c993b3ae14bcad39b2c682beabc27d6d4eb20711d6560
Q = 0f1d1274943b91415889152e893d80e93275a1fc0b65fd71b4b0dda10ad7d772
MESSAGE = f726936d19c800494e3fdaff20b276a8
CONTEXT = 666f6f
SIGNATURE = 21655b5f1aa965996b3f97b3c849eafba922a0a62992f73b3d1b73106a84ad85e9b86a7b6005ea868337ff2d20a7f5fbd4cd10b0be49a68da2b2e0dc0ad8960f
Loading

0 comments on commit 0873ba1

Please sign in to comment.