Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -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]);
}

Copy link
Contributor

Choose a reason for hiding this comment

The 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
Copy link
Contributor

Choose a reason for hiding this comment

The 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
Expand Down
16 changes: 12 additions & 4 deletions crypto/libsodium-fork/src/libsodium/crypto_vrf/crypto_vrf.c
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ crypto_vrf_keypair(unsigned char *pk, unsigned char *sk)

int
crypto_vrf_keypair_from_seed(unsigned char *pk, unsigned char *sk,
const unsigned char *seed)
const unsigned char *seed)
{
return crypto_vrf_ietfdraft03_keypair_from_seed(pk, sk, seed);
}
Expand All @@ -58,19 +58,27 @@ crypto_vrf_is_valid_key(const unsigned char *pk)

int
crypto_vrf_prove(unsigned char *proof, const unsigned char *skpk,
const unsigned char *m, const unsigned long long mlen)
const unsigned char *m, const unsigned long long mlen)
{
return crypto_vrf_ietfdraft03_prove(proof, skpk, m, mlen);
}

int
crypto_vrf_verify(unsigned char *output, const unsigned char *pk,
const unsigned char *proof, const unsigned char *m,
const unsigned long long mlen)
const unsigned char *proof, const unsigned char *m,
const unsigned long long mlen)
{
return crypto_vrf_ietfdraft03_verify(output, pk, proof, m, mlen);
}

int
crypto_vrf_verify_vartime(unsigned char *output, const unsigned char *pk,
const unsigned char *proof, const unsigned char *m,
const unsigned long long mlen)
{
return crypto_vrf_ietfdraft03_verify_vartime(output, pk, proof, m, mlen);
}

int
crypto_vrf_proof_to_hash(unsigned char *hash, const unsigned char *proof)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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.
*
Expand Down Expand Up @@ -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 */
Copy link
Contributor

Choose a reason for hiding this comment

The 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.
Expand Down
Loading