Skip to content

Commit f077286

Browse files
committed
X25519 x64 ASM: fix full reduction
The last add was overflowing into the top bit. Must mask the last word to clear top bit. Add test vectors from Wycheproof.
1 parent 91f3e7e commit f077286

3 files changed

Lines changed: 99 additions & 0 deletions

File tree

tests/api/test_curve25519.c

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -353,6 +353,99 @@ int test_wc_curve25519_shared_secret_ex(void)
353353
return EXPECT_RESULT();
354354
} /* END test_wc_curve25519_shared_secret_ex */
355355

356+
/*
357+
* Known-answer tests for wc_curve25519_shared_secret_ex.
358+
*
359+
* Both vectors share one private scalar and produce a shared secret that is a
360+
* small canonical value (9 and 16, little-endian). Because the result is close
361+
* to a multiple of the field prime, these exercise the final modular reduction
362+
* of the X25519 computation: a result that was only reduced mod 2^256 (or left
363+
* in [p, 2^255)) instead of fully reduced mod 2^255-19 would not match.
364+
* All values are 32-byte little-endian encodings per RFC 7748.
365+
*/
366+
int test_wc_curve25519_shared_secret_ex_kat(void)
367+
{
368+
EXPECT_DECLS;
369+
#if defined(HAVE_CURVE25519) && defined(HAVE_CURVE25519_KEY_IMPORT)
370+
/* Private scalar shared by both vectors. */
371+
static const byte kPriv[CURVE25519_KEYSIZE] = {
372+
0x60, 0xa3, 0xa4, 0xf1, 0x30, 0xb9, 0x8a, 0x5b,
373+
0xe4, 0xb1, 0xce, 0xdb, 0x7c, 0xb8, 0x55, 0x84,
374+
0xa3, 0x52, 0x0e, 0x14, 0x2d, 0x47, 0x4d, 0xc9,
375+
0xcc, 0xb9, 0x09, 0xa0, 0x73, 0xa9, 0x76, 0x7f
376+
};
377+
/* Vector 1 public value, expected shared secret == 9. */
378+
static const byte kPub1[CURVE25519_KEYSIZE] = {
379+
0x3b, 0x18, 0xdf, 0x1e, 0x50, 0xb8, 0x99, 0xeb,
380+
0xd5, 0x88, 0xc3, 0x16, 0x1c, 0xbd, 0x3b, 0xf9,
381+
0x8e, 0xbc, 0xc2, 0xc1, 0xf7, 0xdf, 0x53, 0xb8,
382+
0x11, 0xbd, 0x0e, 0x91, 0xb4, 0xd5, 0x15, 0x3d
383+
};
384+
static const byte kExpected1[CURVE25519_KEYSIZE] = {
385+
0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
386+
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
387+
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
388+
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
389+
};
390+
/* Vector 2 public value, expected shared secret == 16. */
391+
static const byte kPub2[CURVE25519_KEYSIZE] = {
392+
0xca, 0xb6, 0xf9, 0xe7, 0xd8, 0xce, 0x00, 0xdf,
393+
0xce, 0xa9, 0xbb, 0xd8, 0xf0, 0x69, 0xef, 0x7f,
394+
0xb2, 0xac, 0x50, 0x4a, 0xbf, 0x83, 0xb8, 0x7d,
395+
0xb6, 0x01, 0xb5, 0xae, 0x0a, 0x7f, 0x76, 0x15
396+
};
397+
static const byte kExpected2[CURVE25519_KEYSIZE] = {
398+
0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
399+
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
400+
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
401+
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
402+
};
403+
/* Table-driven so both vectors run through the identical code path. */
404+
struct {
405+
const byte* pub;
406+
const byte* expected;
407+
} vec[2];
408+
int i;
409+
curve25519_key private_key;
410+
curve25519_key public_key;
411+
WC_RNG rng;
412+
byte out[CURVE25519_KEYSIZE];
413+
word32 outLen;
414+
415+
vec[0].pub = kPub1; vec[0].expected = kExpected1;
416+
vec[1].pub = kPub2; vec[1].expected = kExpected2;
417+
418+
XMEMSET(&rng, 0, sizeof(WC_RNG));
419+
ExpectIntEQ(wc_InitRng(&rng), 0);
420+
421+
for (i = 0; i < 2; i++) {
422+
XMEMSET(&private_key, 0, sizeof(private_key));
423+
XMEMSET(&public_key, 0, sizeof(public_key));
424+
ExpectIntEQ(wc_curve25519_init(&private_key), 0);
425+
ExpectIntEQ(wc_curve25519_init(&public_key), 0);
426+
#ifdef WOLFSSL_CURVE25519_BLINDING
427+
ExpectIntEQ(wc_curve25519_set_rng(&private_key, &rng), 0);
428+
#endif
429+
ExpectIntEQ(wc_curve25519_import_private_ex(kPriv, sizeof(kPriv),
430+
&private_key, EC25519_LITTLE_ENDIAN), 0);
431+
ExpectIntEQ(wc_curve25519_import_public_ex(vec[i].pub,
432+
CURVE25519_KEYSIZE, &public_key, EC25519_LITTLE_ENDIAN), 0);
433+
434+
outLen = sizeof(out);
435+
ExpectIntEQ(wc_curve25519_shared_secret_ex(&private_key, &public_key,
436+
out, &outLen, EC25519_LITTLE_ENDIAN), 0);
437+
ExpectIntEQ(outLen, CURVE25519_KEYSIZE);
438+
ExpectIntEQ(XMEMCMP(out, vec[i].expected, CURVE25519_KEYSIZE), 0);
439+
440+
wc_curve25519_free(&private_key);
441+
wc_curve25519_free(&public_key);
442+
}
443+
444+
DoExpectIntEQ(wc_FreeRng(&rng), 0);
445+
#endif
446+
return EXPECT_RESULT();
447+
} /* END test_wc_curve25519_shared_secret_ex_kat */
448+
356449
/*
357450
* Testing wc_curve25519_make_pub
358451
*/

tests/api/test_curve25519.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ int test_wc_curve25519_export_key_raw(void);
3030
int test_wc_curve25519_export_key_raw_ex(void);
3131
int test_wc_curve25519_make_key(void);
3232
int test_wc_curve25519_shared_secret_ex(void);
33+
int test_wc_curve25519_shared_secret_ex_kat(void);
3334
int test_wc_curve25519_make_pub(void);
3435
int test_wc_curve25519_export_public_ex(void);
3536
int test_wc_curve25519_export_private_raw_ex(void);
@@ -45,6 +46,7 @@ int test_wc_Curve25519KeyToDer_oneasymkey_version(void);
4546
TEST_DECL_GROUP("curve25519", test_wc_curve25519_export_key_raw_ex), \
4647
TEST_DECL_GROUP("curve25519", test_wc_curve25519_make_key), \
4748
TEST_DECL_GROUP("curve25519", test_wc_curve25519_shared_secret_ex), \
49+
TEST_DECL_GROUP("curve25519", test_wc_curve25519_shared_secret_ex_kat), \
4850
TEST_DECL_GROUP("curve25519", test_wc_curve25519_make_pub), \
4951
TEST_DECL_GROUP("curve25519", test_wc_curve25519_export_public_ex), \
5052
TEST_DECL_GROUP("curve25519", test_wc_curve25519_export_private_raw_ex), \

wolfcrypt/src/fe_x25519_asm.S

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4639,6 +4639,7 @@ L_curve25519_base_x64_3:
46394639
adcq $0x00, %r8
46404640
adcq $0x00, %r9
46414641
adcq $0x00, %r10
4642+
andq %rax, %r10
46424643
# Store
46434644
movq %rcx, (%rdi)
46444645
movq %r8, 8(%rdi)
@@ -7054,6 +7055,7 @@ L_curve25519_x64_3:
70547055
adcq $0x00, %r9
70557056
adcq $0x00, %r10
70567057
adcq $0x00, %r11
7058+
andq %rax, %r11
70577059
# Store
70587060
movq %rcx, (%rdi)
70597061
movq %r9, 8(%rdi)
@@ -15107,6 +15109,7 @@ L_curve25519_base_avx2_last_3:
1510715109
adcq $0x00, %r9
1510815110
adcq $0x00, %r10
1510915111
adcq $0x00, %r11
15112+
andq %rcx, %r11
1511015113
# Store
1511115114
movq %r8, (%rdi)
1511215115
movq %r9, 8(%rdi)
@@ -17116,6 +17119,7 @@ L_curve25519_avx2_last_3:
1711617119
adcq $0x00, %r10
1711717120
adcq $0x00, %r11
1711817121
adcq $0x00, %r12
17122+
andq %rcx, %r12
1711917123
# Store
1712017124
movq %r9, (%rdi)
1712117125
movq %r10, 8(%rdi)

0 commit comments

Comments
 (0)