diff --git a/src/libsodium/crypto_core/ed25519/core_ed25519.c b/src/libsodium/crypto_core/ed25519/core_ed25519.c index 41b517b8..90c4ea6f 100644 --- a/src/libsodium/crypto_core/ed25519/core_ed25519.c +++ b/src/libsodium/crypto_core/ed25519/core_ed25519.c @@ -232,6 +232,32 @@ crypto_core_ed25519_scalar_is_canonical(const unsigned char *s) return sc25519_is_canonical(s); } +#define HASH_SC_L 48U + +int +crypto_core_ed25519_scalar_from_string(unsigned char *s, + const unsigned char *ctx, size_t ctx_len, + const unsigned char *msg, size_t msg_len, + int hash_alg) +{ + unsigned char h[crypto_core_ed25519_NONREDUCEDSCALARBYTES]; + unsigned char h_be[HASH_SC_L]; + size_t i; + + if (core_h2c_string_to_hash(h_be, sizeof h_be, ctx, ctx_len, msg, msg_len, + hash_alg) != 0) { + return -1; + } + COMPILER_ASSERT(sizeof h >= sizeof h_be); + for (i = 0U; i < HASH_SC_L; i++) { + h[i] = h_be[HASH_SC_L - 1U - i]; + } + memset(&h[i], 0, (sizeof h) - i); + crypto_core_ed25519_scalar_reduce(s, h); + + return 0; +} + size_t crypto_core_ed25519_bytes(void) { diff --git a/src/libsodium/crypto_core/ed25519/core_ristretto255.c b/src/libsodium/crypto_core/ed25519/core_ristretto255.c index cb4d817c..bf7c7814 100644 --- a/src/libsodium/crypto_core/ed25519/core_ristretto255.c +++ b/src/libsodium/crypto_core/ed25519/core_ristretto255.c @@ -159,30 +159,14 @@ crypto_core_ristretto255_scalar_is_canonical(const unsigned char *s) return sc25519_is_canonical(s); } -#define HASH_SC_L 48U - int crypto_core_ristretto255_scalar_from_string(unsigned char *s, const unsigned char *ctx, size_t ctx_len, const unsigned char *msg, size_t msg_len, int hash_alg) { - unsigned char h[crypto_core_ristretto255_NONREDUCEDSCALARBYTES]; - unsigned char h_be[HASH_SC_L]; - size_t i; - - if (core_h2c_string_to_hash(h_be, sizeof h_be, ctx, ctx_len, msg, msg_len, - hash_alg) != 0) { - return -1; - } - COMPILER_ASSERT(sizeof h >= sizeof h_be); - for (i = 0U; i < HASH_SC_L; i++) { - h[i] = h_be[HASH_SC_L - 1U - i]; - } - memset(&h[i], 0, (sizeof h) - i); - crypto_core_ristretto255_scalar_reduce(s, h); - - return 0; + return crypto_core_ed25519_scalar_from_string(s, ctx, ctx_len, msg, msg_len, + hash_alg); } size_t diff --git a/src/libsodium/include/sodium/crypto_core_ed25519.h b/src/libsodium/include/sodium/crypto_core_ed25519.h index 9114017e..0fd415e4 100644 --- a/src/libsodium/include/sodium/crypto_core_ed25519.h +++ b/src/libsodium/include/sodium/crypto_core_ed25519.h @@ -102,6 +102,13 @@ SODIUM_EXPORT void crypto_core_ed25519_scalar_reduce(unsigned char *r, const unsigned char *s) __attribute__ ((nonnull)); +SODIUM_EXPORT +int crypto_core_ed25519_scalar_from_string(unsigned char *s, + const unsigned char *ctx, size_t ctx_len, + const unsigned char *msg, size_t msg_len, + int hash_alg) + __attribute__ ((nonnull(1))); + SODIUM_EXPORT int crypto_core_ed25519_scalar_is_canonical(const unsigned char *s) __attribute__ ((nonnull)); diff --git a/src/libsodium/include/sodium/crypto_core_ristretto255.h b/src/libsodium/include/sodium/crypto_core_ristretto255.h index e7acd236..ec9bcb2f 100644 --- a/src/libsodium/include/sodium/crypto_core_ristretto255.h +++ b/src/libsodium/include/sodium/crypto_core_ristretto255.h @@ -103,6 +103,13 @@ void crypto_core_ristretto255_scalar_reduce(unsigned char *r, const unsigned char *s) __attribute__ ((nonnull)); +SODIUM_EXPORT +int crypto_core_ristretto255_scalar_from_string(unsigned char *s, + const unsigned char *ctx, size_t ctx_len, + const unsigned char *msg, size_t msg_len, + int hash_alg) + __attribute__ ((nonnull(1))); + SODIUM_EXPORT int crypto_core_ristretto255_scalar_is_canonical(const unsigned char *s) __attribute__ ((nonnull)); diff --git a/test/default/core_ed25519_h2c.c b/test/default/core_ed25519_h2c.c index 6a70cf5b..27c050ff 100644 --- a/test/default/core_ed25519_h2c.c +++ b/test/default/core_ed25519_h2c.c @@ -65,10 +65,102 @@ static TestData test_data[] = { "6dc2fc04f266c5c27f236a80b14f92ccd051ef1ff027f26a07f8c0f327d8f995" } }; +static void +test_scalar_from_string(void) +{ + static const struct { + int hash_alg; + const char *msg; + size_t msg_len; + const char *ctx; + size_t ctx_len; + const char expected[65]; + } scalar_tvs[] = { + { 1, "", 0U, "test-dst", 8U, + "28dae5fcb05a81163b41a90fc54e3e815613194ddd44b1e718bfab7457536705" }, + { 2, "", 0U, "test-dst", 8U, + "110d25b6c0f2ab15d9387d4d77847e62c3b133da1bcc71e588076765c74e0b03" }, + { 1, "abc", 3U, "test-dst", 8U, + "8a2383018254b8b57b624f049bc2e72c1c401ad0959b10d1d24ad863fcb5060c" }, + { 2, "abc", 3U, "test-dst", 8U, + "cc954e2d86fdba2af74270642bd6375bdf13e485077bb56a648aaf243d4a8007" }, + { 2, "", 0U, "", 0U, + "c9fb227ffae5fa378f3e6cbbafe054989748daae21c9ebe907f7b68d14093a06" }, + }; + unsigned char s_ed[crypto_core_ed25519_SCALARBYTES]; + unsigned char expected_s[crypto_core_ed25519_SCALARBYTES]; + char s_hex[crypto_core_ed25519_SCALARBYTES * 2U + 1U]; + size_t oversized_len = 256U; + unsigned char *big_ctx; + size_t t; + + for (t = 0U; t < sizeof scalar_tvs / sizeof scalar_tvs[0]; t++) { + sodium_hex2bin(expected_s, sizeof expected_s, + scalar_tvs[t].expected, (size_t) -1U, + NULL, NULL, NULL); + if (crypto_core_ed25519_scalar_from_string( + s_ed, + (const unsigned char *) scalar_tvs[t].ctx, + scalar_tvs[t].ctx_len, + (const unsigned char *) scalar_tvs[t].msg, + scalar_tvs[t].msg_len, + scalar_tvs[t].hash_alg) != 0) { + printf("scalar_from_string: ed25519 call failed for tv %u\n", + (unsigned) t); + continue; + } + if (memcmp(s_ed, expected_s, sizeof expected_s) != 0) { + sodium_bin2hex(s_hex, sizeof s_hex, s_ed, sizeof s_ed); + printf("scalar_from_string: ed25519 KAT %u mismatch: %s\n", + (unsigned) t, s_hex); + } + if (crypto_core_ed25519_scalar_is_canonical(s_ed) != 1) { + printf("scalar_from_string: ed25519 result %u not canonical\n", + (unsigned) t); + } + } + + if (crypto_core_ed25519_scalar_from_string( + s_ed, + (const unsigned char *) "test-dst", 8U, + (const unsigned char *) "abc", 3U, + 0) != -1) { + printf("scalar_from_string: invalid hash_alg 0 should fail\n"); + } + if (crypto_core_ed25519_scalar_from_string( + s_ed, + (const unsigned char *) "test-dst", 8U, + (const unsigned char *) "abc", 3U, + 99) != -1) { + printf("scalar_from_string: invalid hash_alg 99 should fail\n"); + } + + big_ctx = (unsigned char *) sodium_malloc(oversized_len); + memset(big_ctx, 'X', oversized_len); + + if (crypto_core_ed25519_scalar_from_string( + s_ed, big_ctx, oversized_len, + (const unsigned char *) "abc", 3U, 2) != 0) { + printf("scalar_from_string: oversized DST SHA-512 failed\n"); + } + sodium_bin2hex(s_hex, sizeof s_hex, s_ed, sizeof s_ed); + printf("scalar_from_string oversized DST/sha512: %s\n", s_hex); + + if (crypto_core_ed25519_scalar_from_string( + s_ed, big_ctx, oversized_len, + (const unsigned char *) "abc", 3U, 1) != 0) { + printf("scalar_from_string: oversized DST SHA-256 failed\n"); + } + sodium_bin2hex(s_hex, sizeof s_hex, s_ed, sizeof s_ed); + printf("scalar_from_string oversized DST/sha256: %s\n", s_hex); + + sodium_free(big_ctx); +} + #define H2CHASH crypto_core_ed25519_H2CSHA512 -int -main(void) +static void +test_from_string(void) { unsigned char *expected_xr, *expected_x; unsigned char *expected_yr, *expected_y, *y; @@ -167,6 +259,13 @@ main(void) sodium_free(expected_yr); sodium_free(expected_x); sodium_free(expected_xr); +} + +int +main(void) +{ + test_scalar_from_string(); + test_from_string(); printf("OK\n"); diff --git a/test/default/core_ed25519_h2c.exp b/test/default/core_ed25519_h2c.exp index 040a839e..12adc5eb 100644 --- a/test/default/core_ed25519_h2c.exp +++ b/test/default/core_ed25519_h2c.exp @@ -1,3 +1,5 @@ NU with oversized context: 998ca2fdd0ade350cb6c279173dfd4a6a42f46ca5c2928871aacff60c16546e3 RO with oversized context: 5ed4ae2ab665a7a9543f6e9887dc8f8f68a7720fdf32b971f3be71d9c9549ff4 +scalar_from_string oversized DST/sha512: 65a9285a623f62fb45d3f7f1598bb32d361c0e504d70d8401f28784af854cc09 +scalar_from_string oversized DST/sha256: 9520c0e0dc6af766f5708c4a4b355dba66cf15462f2556c6fa8ccc03aaa0e102 OK diff --git a/test/default/core_ristretto255_h2c.c b/test/default/core_ristretto255_h2c.c index 3b05dee0..78651675 100644 --- a/test/default/core_ristretto255_h2c.c +++ b/test/default/core_ristretto255_h2c.c @@ -26,10 +26,102 @@ static TestData test_data[] = { "caff66fcdc41da4d87ccc72aaac70c6e267a4b55c3dc9489bb365a70a04f1a52" }, }; +static void +test_scalar_from_string(void) +{ + static const struct { + int hash_alg; + const char *msg; + size_t msg_len; + const char *ctx; + size_t ctx_len; + const char expected[65]; + } scalar_tvs[] = { + { 1, "", 0U, "test-dst", 8U, + "28dae5fcb05a81163b41a90fc54e3e815613194ddd44b1e718bfab7457536705" }, + { 2, "", 0U, "test-dst", 8U, + "110d25b6c0f2ab15d9387d4d77847e62c3b133da1bcc71e588076765c74e0b03" }, + { 1, "abc", 3U, "test-dst", 8U, + "8a2383018254b8b57b624f049bc2e72c1c401ad0959b10d1d24ad863fcb5060c" }, + { 2, "abc", 3U, "test-dst", 8U, + "cc954e2d86fdba2af74270642bd6375bdf13e485077bb56a648aaf243d4a8007" }, + { 2, "", 0U, "", 0U, + "c9fb227ffae5fa378f3e6cbbafe054989748daae21c9ebe907f7b68d14093a06" }, + }; + unsigned char s[crypto_core_ristretto255_SCALARBYTES]; + unsigned char expected_s[crypto_core_ristretto255_SCALARBYTES]; + char s_hex[crypto_core_ristretto255_SCALARBYTES * 2U + 1U]; + size_t oversized_len = 256U; + unsigned char *big_ctx; + size_t t; + + for (t = 0U; t < sizeof scalar_tvs / sizeof scalar_tvs[0]; t++) { + sodium_hex2bin(expected_s, sizeof expected_s, + scalar_tvs[t].expected, (size_t) -1U, + NULL, NULL, NULL); + if (crypto_core_ristretto255_scalar_from_string( + s, + (const unsigned char *) scalar_tvs[t].ctx, + scalar_tvs[t].ctx_len, + (const unsigned char *) scalar_tvs[t].msg, + scalar_tvs[t].msg_len, + scalar_tvs[t].hash_alg) != 0) { + printf("scalar_from_string: call failed for tv %u\n", + (unsigned) t); + continue; + } + if (memcmp(s, expected_s, sizeof expected_s) != 0) { + sodium_bin2hex(s_hex, sizeof s_hex, s, sizeof s); + printf("scalar_from_string: KAT %u mismatch: %s\n", + (unsigned) t, s_hex); + } + if (crypto_core_ristretto255_scalar_is_canonical(s) != 1) { + printf("scalar_from_string: result %u not canonical\n", + (unsigned) t); + } + } + + if (crypto_core_ristretto255_scalar_from_string( + s, + (const unsigned char *) "test-dst", 8U, + (const unsigned char *) "abc", 3U, + 0) != -1) { + printf("scalar_from_string: invalid hash_alg 0 should fail\n"); + } + if (crypto_core_ristretto255_scalar_from_string( + s, + (const unsigned char *) "test-dst", 8U, + (const unsigned char *) "abc", 3U, + 99) != -1) { + printf("scalar_from_string: invalid hash_alg 99 should fail\n"); + } + + big_ctx = (unsigned char *) sodium_malloc(oversized_len); + memset(big_ctx, 'X', oversized_len); + + if (crypto_core_ristretto255_scalar_from_string( + s, big_ctx, oversized_len, + (const unsigned char *) "abc", 3U, 2) != 0) { + printf("scalar_from_string: oversized DST SHA-512 failed\n"); + } + sodium_bin2hex(s_hex, sizeof s_hex, s, sizeof s); + printf("scalar_from_string oversized DST/sha512: %s\n", s_hex); + + if (crypto_core_ristretto255_scalar_from_string( + s, big_ctx, oversized_len, + (const unsigned char *) "abc", 3U, 1) != 0) { + printf("scalar_from_string: oversized DST SHA-256 failed\n"); + } + sodium_bin2hex(s_hex, sizeof s_hex, s, sizeof s); + printf("scalar_from_string oversized DST/sha256: %s\n", s_hex); + + sodium_free(big_ctx); +} + #define H2CHASH crypto_core_ristretto255_H2CSHA512 -int -main(void) +static void +test_from_string_ro(void) { unsigned char *p, *expected, *input; char *p_hex, *expected_hex; @@ -38,10 +130,6 @@ main(void) size_t oversized_ctx_len = 500U; size_t input_len; - /* - * DST = "HashToGroup-OPRFV1-" || mode_byte || "-ristretto255-SHA512" - * The mode byte at offset 19 is patched per test vector. - */ unsigned char dst[] = { 'H','a','s','h','T','o','G','r','o','u','p','-', 'O','P','R','F','V','1','-', 0x00, '-', @@ -105,6 +193,13 @@ main(void) sodium_free(input); sodium_free(expected); sodium_free(p); +} + +int +main(void) +{ + test_scalar_from_string(); + test_from_string_ro(); printf("OK\n"); diff --git a/test/default/core_ristretto255_h2c.exp b/test/default/core_ristretto255_h2c.exp index 57e01397..c9fcb7dd 100644 --- a/test/default/core_ristretto255_h2c.exp +++ b/test/default/core_ristretto255_h2c.exp @@ -1,2 +1,4 @@ RO with oversized context: eedf0384646af8a94b9c8153490ce78f2e79f301800b33f4bfa655bcdc4fb135 +scalar_from_string oversized DST/sha512: 65a9285a623f62fb45d3f7f1598bb32d361c0e504d70d8401f28784af854cc09 +scalar_from_string oversized DST/sha256: 9520c0e0dc6af766f5708c4a4b355dba66cf15462f2556c6fa8ccc03aaa0e102 OK diff --git a/test/symbols/all-symbols.txt b/test/symbols/all-symbols.txt index 44f4559b..e65c30f7 100644 --- a/test/symbols/all-symbols.txt +++ b/test/symbols/all-symbols.txt @@ -202,6 +202,7 @@ crypto_core_ed25519_nonreducedscalarbytes crypto_core_ed25519_random crypto_core_ed25519_scalar_add crypto_core_ed25519_scalar_complement +crypto_core_ed25519_scalar_from_string crypto_core_ed25519_scalar_invert crypto_core_ed25519_scalar_is_canonical crypto_core_ed25519_scalar_mul