-
Notifications
You must be signed in to change notification settings - Fork 518
crypto: Variable-time implementation of VRF verify #3925
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -803,6 +803,246 @@ ge25519_double_scalarmult_vartime(ge25519_p2 *r, const unsigned char *a, | |
| } | ||
| } | ||
|
|
||
| /* | ||
| r = - a * A + b * B | ||
| where a = a[0]+256*a[1]+...+256^31 a[31]. | ||
| and b = b[0]+256*b[1]+...+256^31 b[31]. | ||
| B is the Ed25519 base point (x,4/5) with x positive. | ||
|
|
||
| Only used for VRF verification. | ||
|
|
||
| Same as ge25519_double_scalarmult_vartime | ||
| but with a minus "-" before a | ||
| */ | ||
|
|
||
| void | ||
| ge25519_double_sub_scalarmult_vartime(ge25519_p2 *r, const unsigned char *a, | ||
| const ge25519_p3 *A, const unsigned char *b) | ||
| { | ||
| static const ge25519_precomp Bi[8] = { | ||
| #ifdef HAVE_TI_MODE | ||
| # include "fe_51/base2.h" | ||
| #else | ||
| # include "fe_25_5/base2.h" | ||
| #endif | ||
| }; | ||
| signed char aslide[256]; | ||
| signed char bslide[256]; | ||
| ge25519_cached Ai[8]; /* A,3A,5A,7A,9A,11A,13A,15A */ | ||
| ge25519_p1p1 t; | ||
| ge25519_p3 u; | ||
| ge25519_p3 A2; | ||
| int i; | ||
|
|
||
| slide_vartime(aslide, a); | ||
| slide_vartime(bslide, b); | ||
|
|
||
| ge25519_p3_to_cached(&Ai[0], A); | ||
|
|
||
| ge25519_p3_dbl(&t, A); | ||
| ge25519_p1p1_to_p3(&A2, &t); | ||
|
|
||
| ge25519_add(&t, &A2, &Ai[0]); | ||
| ge25519_p1p1_to_p3(&u, &t); | ||
| ge25519_p3_to_cached(&Ai[1], &u); | ||
|
|
||
| ge25519_add(&t, &A2, &Ai[1]); | ||
| ge25519_p1p1_to_p3(&u, &t); | ||
| ge25519_p3_to_cached(&Ai[2], &u); | ||
|
|
||
| ge25519_add(&t, &A2, &Ai[2]); | ||
| ge25519_p1p1_to_p3(&u, &t); | ||
| ge25519_p3_to_cached(&Ai[3], &u); | ||
|
|
||
| ge25519_add(&t, &A2, &Ai[3]); | ||
| ge25519_p1p1_to_p3(&u, &t); | ||
| ge25519_p3_to_cached(&Ai[4], &u); | ||
|
|
||
| ge25519_add(&t, &A2, &Ai[4]); | ||
| ge25519_p1p1_to_p3(&u, &t); | ||
| ge25519_p3_to_cached(&Ai[5], &u); | ||
|
|
||
| ge25519_add(&t, &A2, &Ai[5]); | ||
| ge25519_p1p1_to_p3(&u, &t); | ||
| ge25519_p3_to_cached(&Ai[6], &u); | ||
|
|
||
| ge25519_add(&t, &A2, &Ai[6]); | ||
| ge25519_p1p1_to_p3(&u, &t); | ||
| ge25519_p3_to_cached(&Ai[7], &u); | ||
|
|
||
| ge25519_p2_0(r); | ||
|
|
||
| for (i = 255; i >= 0; --i) { | ||
| if (aslide[i] || bslide[i]) { | ||
| break; | ||
| } | ||
| } | ||
|
|
||
| for (; i >= 0; --i) { | ||
| ge25519_p2_dbl(&t, r); | ||
|
|
||
| if (aslide[i] > 0) { | ||
| ge25519_p1p1_to_p3(&u, &t); | ||
| // this is where we do -a * A, instead of a * A | ||
| // we use sub instead of add | ||
| ge25519_sub(&t, &u, &Ai[aslide[i] / 2]); | ||
| } else if (aslide[i] < 0) { | ||
| ge25519_p1p1_to_p3(&u, &t); | ||
| // this is where we do -a * A, instead of a * A | ||
| // we use add instead of sub | ||
| ge25519_add(&t, &u, &Ai[(-aslide[i]) / 2]); | ||
| } | ||
|
|
||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. what you propose sounds logically sound, in that you have replaced the 25519 arithmetic with the additive inverse in the area of code that deals with aslide in particular, to achieve the -a result. caveat, I can't render an opinion on the libsodium implementation as a whole. |
||
| if (bslide[i] > 0) { | ||
| ge25519_p1p1_to_p3(&u, &t); | ||
| ge25519_madd(&t, &u, &Bi[bslide[i] / 2]); | ||
| } else if (bslide[i] < 0) { | ||
| ge25519_p1p1_to_p3(&u, &t); | ||
| ge25519_msub(&t, &u, &Bi[(-bslide[i]) / 2]); | ||
| } | ||
|
|
||
| ge25519_p1p1_to_p2(r, &t); | ||
| } | ||
| } | ||
|
|
||
| /* | ||
| r = - a * A + b * B | ||
| where a = a[0]+256*a[1]+...+256^31 a[31]. | ||
| and b = b[0]+256*b[1]+...+256^31 b[31]. | ||
| where contrary to | ||
| ge25519_double_sub_scalarmult_vartime | ||
| B is not necessarily the base | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. in the prior function, B came from a header file, either fe_51/base2.h or fe_25_5/base2.h, here is it calculated in the same style as A |
||
|
|
||
| Non-constant time | ||
|
|
||
| Only used for VRF verification. | ||
| */ | ||
|
|
||
| void | ||
| ge25519_double_sub_nonbase_scalarmult_vartime(ge25519_p2 *r, const unsigned char *a, | ||
| const ge25519_p3 *A, const unsigned char *b, | ||
| const ge25519_p3 *B) | ||
| { | ||
| signed char aslide[256]; | ||
| signed char bslide[256]; | ||
| ge25519_cached Ai[8]; /* A,3A,5A,7A,9A,11A,13A,15A */ | ||
| ge25519_cached Bi[8]; /* B,3B,5B,7B,9B,11B,13B,15B */ | ||
| ge25519_p1p1 t; | ||
| ge25519_p3 u; | ||
| ge25519_p3 A2, B2; | ||
| int i; | ||
|
|
||
| slide_vartime(aslide, a); | ||
| slide_vartime(bslide, b); | ||
|
|
||
| // Compute Ai | ||
|
|
||
| ge25519_p3_to_cached(&Ai[0], A); | ||
|
|
||
| ge25519_p3_dbl(&t, A); | ||
| ge25519_p1p1_to_p3(&A2, &t); | ||
|
|
||
| ge25519_add(&t, &A2, &Ai[0]); | ||
| ge25519_p1p1_to_p3(&u, &t); | ||
| ge25519_p3_to_cached(&Ai[1], &u); | ||
|
|
||
| ge25519_add(&t, &A2, &Ai[1]); | ||
| ge25519_p1p1_to_p3(&u, &t); | ||
| ge25519_p3_to_cached(&Ai[2], &u); | ||
|
|
||
| ge25519_add(&t, &A2, &Ai[2]); | ||
| ge25519_p1p1_to_p3(&u, &t); | ||
| ge25519_p3_to_cached(&Ai[3], &u); | ||
|
|
||
| ge25519_add(&t, &A2, &Ai[3]); | ||
| ge25519_p1p1_to_p3(&u, &t); | ||
| ge25519_p3_to_cached(&Ai[4], &u); | ||
|
|
||
| ge25519_add(&t, &A2, &Ai[4]); | ||
| ge25519_p1p1_to_p3(&u, &t); | ||
| ge25519_p3_to_cached(&Ai[5], &u); | ||
|
|
||
| ge25519_add(&t, &A2, &Ai[5]); | ||
| ge25519_p1p1_to_p3(&u, &t); | ||
| ge25519_p3_to_cached(&Ai[6], &u); | ||
|
|
||
| ge25519_add(&t, &A2, &Ai[6]); | ||
| ge25519_p1p1_to_p3(&u, &t); | ||
| ge25519_p3_to_cached(&Ai[7], &u); | ||
|
|
||
| // Compute Bi (same as Ai) | ||
| // This looks to me like too much copy-pasting | ||
| // but libsodium contains such copy-pasting | ||
| // all over the place so I'm keeping it this way | ||
|
|
||
| ge25519_p3_to_cached(&Bi[0], B); | ||
|
|
||
| ge25519_p3_dbl(&t, B); | ||
| ge25519_p1p1_to_p3(&B2, &t); | ||
|
|
||
| ge25519_add(&t, &B2, &Bi[0]); | ||
| ge25519_p1p1_to_p3(&u, &t); | ||
| ge25519_p3_to_cached(&Bi[1], &u); | ||
|
|
||
| ge25519_add(&t, &B2, &Bi[1]); | ||
| ge25519_p1p1_to_p3(&u, &t); | ||
| ge25519_p3_to_cached(&Bi[2], &u); | ||
|
|
||
| ge25519_add(&t, &B2, &Bi[2]); | ||
| ge25519_p1p1_to_p3(&u, &t); | ||
| ge25519_p3_to_cached(&Bi[3], &u); | ||
|
|
||
| ge25519_add(&t, &B2, &Bi[3]); | ||
| ge25519_p1p1_to_p3(&u, &t); | ||
| ge25519_p3_to_cached(&Bi[4], &u); | ||
|
|
||
| ge25519_add(&t, &B2, &Bi[4]); | ||
| ge25519_p1p1_to_p3(&u, &t); | ||
| ge25519_p3_to_cached(&Bi[5], &u); | ||
|
|
||
| ge25519_add(&t, &B2, &Bi[5]); | ||
| ge25519_p1p1_to_p3(&u, &t); | ||
| ge25519_p3_to_cached(&Bi[6], &u); | ||
|
|
||
| ge25519_add(&t, &B2, &Bi[6]); | ||
| ge25519_p1p1_to_p3(&u, &t); | ||
| ge25519_p3_to_cached(&Bi[7], &u); | ||
|
|
||
| ge25519_p2_0(r); | ||
|
|
||
| for (i = 255; i >= 0; --i) { | ||
| if (aslide[i] || bslide[i]) { | ||
| break; | ||
| } | ||
| } | ||
|
|
||
| for (; i >= 0; --i) { | ||
| ge25519_p2_dbl(&t, r); | ||
|
|
||
| if (aslide[i] > 0) { | ||
| ge25519_p1p1_to_p3(&u, &t); | ||
| // this is where we do -a * A, instead of a * A | ||
| // we use sub instead of add | ||
| ge25519_sub(&t, &u, &Ai[aslide[i] / 2]); | ||
| } else if (aslide[i] < 0) { | ||
| ge25519_p1p1_to_p3(&u, &t); | ||
| // this is where we do -a * A, instead of a * A | ||
| // we use add instead of sub | ||
| ge25519_add(&t, &u, &Ai[(-aslide[i]) / 2]); | ||
| } | ||
|
|
||
| if (bslide[i] > 0) { | ||
| ge25519_p1p1_to_p3(&u, &t); | ||
| ge25519_add(&t, &u, &Bi[bslide[i] / 2]); | ||
| } else if (bslide[i] < 0) { | ||
| ge25519_p1p1_to_p3(&u, &t); | ||
| ge25519_sub(&t, &u, &Bi[(-bslide[i]) / 2]); | ||
| } | ||
|
|
||
| ge25519_p1p1_to_p2(r, &t); | ||
| } | ||
| } | ||
|
|
||
|
|
||
| /* | ||
| r = a * A + b * B | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -39,6 +39,14 @@ _vrf_ietfdraft03_point_to_string(unsigned char string[32], const ge25519_p3 *poi | |
| ge25519_p3_tobytes(string, point); | ||
| } | ||
|
|
||
| /* Same as _vrf_ietfdraft03_point_to_string but for p2 points instead | ||
| */ | ||
| void | ||
| _vrf_ietfdraft03_point_p2_to_string(unsigned char string[32], const ge25519_p2 *point) | ||
| { | ||
| ge25519_tobytes(string, point); | ||
| } | ||
|
|
||
| /* Decode elliptic curve point from 32-byte octet string per RFC8032 section | ||
| * 5.1.3. | ||
| * | ||
|
|
@@ -106,6 +114,26 @@ _vrf_ietfdraft03_hash_points(unsigned char c[16], const ge25519_p3 *P1, | |
| sodium_memzero(c1, 64); | ||
| } | ||
|
|
||
| /* Same as _vrf_ietfdraft03_hash_points but for ge25519_p2 points instead | ||
| * for the last two points */ | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. this function changes the functional signature from p3 to p2 and replaces point_to_string with the relevant new call to point_p2_to_string, otherwise it's as above |
||
| void | ||
| _vrf_ietfdraft03_hash_points_p3p2(unsigned char c[16], const ge25519_p3 *P1, | ||
| const ge25519_p3 *P2, const ge25519_p2 *P3, | ||
| const ge25519_p2 *P4) | ||
| { | ||
| unsigned char str[2+32*4], c1[64]; | ||
|
|
||
| str[0] = SUITE; | ||
| str[1] = TWO; | ||
| _vrf_ietfdraft03_point_to_string(str+2+32*0, P1); | ||
| _vrf_ietfdraft03_point_to_string(str+2+32*1, P2); | ||
| _vrf_ietfdraft03_point_p2_to_string(str+2+32*2, P3); | ||
| _vrf_ietfdraft03_point_p2_to_string(str+2+32*3, P4); | ||
| crypto_hash_sha512(c1, str, sizeof str); | ||
| memmove(c, c1, 16); | ||
| sodium_memzero(c1, 64); | ||
| } | ||
|
|
||
| /* Decode an 80-byte proof pi into a point gamma, a 16-byte scalar c, and a | ||
| * 32-byte scalar s, as specified in IETF draft section 5.4.4. | ||
| * Returns 0 on success, nonzero on failure. | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.