Add crypto_core_ed25519_scalar_from_string

This commit is contained in:
Frank Denis
2026-02-20 23:06:12 +01:00
parent 78c80a9f73
commit 530252d9a3
9 changed files with 249 additions and 26 deletions
@@ -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)
{
@@ -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
@@ -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));
@@ -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));
+101 -2
View File
@@ -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");
+2
View File
@@ -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
+101 -6
View File
@@ -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");
+2
View File
@@ -1,2 +1,4 @@
RO with oversized context: eedf0384646af8a94b9c8153490ce78f2e79f301800b33f4bfa655bcdc4fb135
scalar_from_string oversized DST/sha512: 65a9285a623f62fb45d3f7f1598bb32d361c0e504d70d8401f28784af854cc09
scalar_from_string oversized DST/sha256: 9520c0e0dc6af766f5708c4a4b355dba66cf15462f2556c6fa8ccc03aaa0e102
OK
+1
View File
@@ -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