1
mirror of https://github.com/jedisct1/libsodium.git synced 2024-12-23 12:05:11 -07:00

RFC9381 ECVRF implementation (#1188)

* Version 12 of ECVRF

* Incorrect ordering of function inputs

* Identation and notation

* single multiscalar multiplication function

Also changed the style of tests, where the expected output is in vrf.exp rather than in test data (following the style of the hashing).

* declarations inside the if code block

* identation of test_data

* Rename to RFC9381

* Move declarations to top of block

* Check small order over deserialised PK

* Include from_string functions in ed25519_ref10

* Update quirks.h

---------

Co-authored-by: Frank Denis <124872+jedisct1@users.noreply.github.com>
This commit is contained in:
Iñigo Querejeta Azurmendi 2024-05-25 18:55:14 +02:00 committed by GitHub
parent 43173b8354
commit 7978205916
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
21 changed files with 822 additions and 89 deletions

1
.gitignore vendored
View File

@ -166,6 +166,7 @@ test/default/stream2
test/default/stream3 test/default/stream3
test/default/stream4 test/default/stream4
test/default/verify1 test/default/verify1
test/default/vrf
test/default/xchacha20 test/default/xchacha20
test/js.done test/js.done
testing testing

View File

@ -99,6 +99,12 @@ libsodium_la_SOURCES = \
crypto_stream/xsalsa20/stream_xsalsa20.c \ crypto_stream/xsalsa20/stream_xsalsa20.c \
crypto_verify/verify.c \ crypto_verify/verify.c \
include/sodium/private/asm_cet.h \ include/sodium/private/asm_cet.h \
crypto_vrf/crypto_vrf.c \
crypto_vrf/rfc9381/keypair.c \
crypto_vrf/rfc9381/prove.c \
crypto_vrf/rfc9381/verify.c \
crypto_vrf/rfc9381/vrf.c \
crypto_vrf/rfc9381/vrf_rfc9381.h \
include/sodium/private/chacha20_ietf_ext.h \ include/sodium/private/chacha20_ietf_ext.h \
include/sodium/private/common.h \ include/sodium/private/common.h \
include/sodium/private/ed25519_ref10.h \ include/sodium/private/ed25519_ref10.h \

View File

@ -65,41 +65,12 @@ crypto_core_ed25519_from_uniform(unsigned char *p, const unsigned char *r)
return 0; return 0;
} }
#define HASH_GE_L 48U
static int
_string_to_points(unsigned char * const px, const size_t n,
const char *ctx, const unsigned char *msg, size_t msg_len,
int hash_alg)
{
unsigned char h[crypto_core_ed25519_HASHBYTES];
unsigned char h_be[2U * HASH_GE_L];
size_t i, j;
if (n > 2U) {
abort(); /* LCOV_EXCL_LINE */
}
if (core_h2c_string_to_hash(h_be, n * HASH_GE_L, ctx, msg, msg_len,
hash_alg) != 0) {
return -1;
}
COMPILER_ASSERT(sizeof h >= HASH_GE_L);
for (i = 0U; i < n; i++) {
for (j = 0U; j < HASH_GE_L; j++) {
h[j] = h_be[i * HASH_GE_L + HASH_GE_L - 1U - j];
}
memset(&h[j], 0, (sizeof h) - j);
ge25519_from_hash(&px[i * crypto_core_ed25519_BYTES], h);
}
return 0;
}
int int
crypto_core_ed25519_from_string(unsigned char p[crypto_core_ed25519_BYTES], crypto_core_ed25519_from_string(unsigned char p[crypto_core_ed25519_BYTES],
const char *ctx, const unsigned char *msg, const char *ctx, const unsigned char *msg,
size_t msg_len, int hash_alg) size_t msg_len, int hash_alg)
{ {
return _string_to_points(p, 1, ctx, msg, msg_len, hash_alg); return ge25519_from_string(p, ctx, msg, msg_len, hash_alg);
} }
int int
@ -107,12 +78,7 @@ crypto_core_ed25519_from_string_ro(unsigned char p[crypto_core_ed25519_BYTES],
const char *ctx, const unsigned char *msg, const char *ctx, const unsigned char *msg,
size_t msg_len, int hash_alg) size_t msg_len, int hash_alg)
{ {
unsigned char px[2 * crypto_core_ed25519_BYTES]; return ge25519_from_string_ro(p, ctx, msg, msg_len, hash_alg);
if (_string_to_points(px, 2, ctx, msg, msg_len, hash_alg) != 0) {
return -1;
}
return crypto_core_ed25519_add(p, &px[0], &px[crypto_core_ed25519_BYTES]);
} }
void void

View File

@ -4,6 +4,7 @@
#include <string.h> #include <string.h>
#include "crypto_verify_32.h" #include "crypto_verify_32.h"
#include "../core_h2c.h"
#include "private/common.h" #include "private/common.h"
#include "private/ed25519_ref10.h" #include "private/ed25519_ref10.h"
#include "utils.h" #include "utils.h"
@ -742,68 +743,76 @@ ge25519_tobytes(unsigned char *s, const ge25519_p2 *h)
} }
/* /*
* Precomputation of a base point, to use in multiscalar multiplication algorithm A,3A,5A,7A,9A,11A,13A,15A
*/
static void point_precomputation(ge25519_cached cached[8], const ge25519_p3 *base) {
ge25519_p1p1 t;
ge25519_p3 u;
ge25519_p3 A;
// Precomputation of values of A
ge25519_p3_to_cached(&cached[0], base);
ge25519_p3_dbl(&t, base);
ge25519_p1p1_to_p3(&A, &t);
ge25519_add_cached(&t, &A, &cached[0]);
ge25519_p1p1_to_p3(&u, &t);
ge25519_p3_to_cached(&cached[1], &u);
ge25519_add_cached(&t, &A, &cached[1]);
ge25519_p1p1_to_p3(&u, &t);
ge25519_p3_to_cached(&cached[2], &u);
ge25519_add_cached(&t, &A, &cached[2]);
ge25519_p1p1_to_p3(&u, &t);
ge25519_p3_to_cached(&cached[3], &u);
ge25519_add_cached(&t, &A, &cached[3]);
ge25519_p1p1_to_p3(&u, &t);
ge25519_p3_to_cached(&cached[4], &u);
ge25519_add_cached(&t, &A, &cached[4]);
ge25519_p1p1_to_p3(&u, &t);
ge25519_p3_to_cached(&cached[5], &u);
ge25519_add_cached(&t, &A, &cached[5]);
ge25519_p1p1_to_p3(&u, &t);
ge25519_p3_to_cached(&cached[6], &u);
ge25519_add_cached(&t, &A, &cached[6]);
ge25519_p1p1_to_p3(&u, &t);
ge25519_p3_to_cached(&cached[7], &u);
}
/*
Variable time double scalar multiplication with variable bases
r = a * A + b * B r = a * A + b * B
where a = a[0]+256*a[1]+...+256^31 a[31]. where a = a[0]+256*a[1]+...+256^31 a[31].
and b = b[0]+256*b[1]+...+256^31 b[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 signatures verification. If a null pointer is passed as an argument for B, the function uses
the precomputed values of the base point for the scalar multiplication.
Only used for ed25519 and VRF verification.
*/ */
void void
ge25519_double_scalarmult_vartime(ge25519_p2 *r, const unsigned char *a, ge25519_double_scalarmult_vartime(ge25519_p2 *r, const unsigned char *a,
const ge25519_p3 *A, const unsigned char *b) const ge25519_p3 *A, const unsigned char *b,
const ge25519_p3 *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 aslide[256];
signed char bslide[256]; signed char bslide[256];
ge25519_cached Ai[8]; /* A,3A,5A,7A,9A,11A,13A,15A */ ge25519_cached Ai[8];
ge25519_p1p1 t; ge25519_p1p1 t;
ge25519_p3 u; ge25519_p3 u;
ge25519_p3 A2;
int i; int i;
slide_vartime(aslide, a); slide_vartime(aslide, a);
slide_vartime(bslide, b); slide_vartime(bslide, b);
ge25519_p3_to_cached(&Ai[0], A); point_precomputation(Ai, A);
ge25519_p3_dbl(&t, A);
ge25519_p1p1_to_p3(&A2, &t);
ge25519_add_cached(&t, &A2, &Ai[0]);
ge25519_p1p1_to_p3(&u, &t);
ge25519_p3_to_cached(&Ai[1], &u);
ge25519_add_cached(&t, &A2, &Ai[1]);
ge25519_p1p1_to_p3(&u, &t);
ge25519_p3_to_cached(&Ai[2], &u);
ge25519_add_cached(&t, &A2, &Ai[2]);
ge25519_p1p1_to_p3(&u, &t);
ge25519_p3_to_cached(&Ai[3], &u);
ge25519_add_cached(&t, &A2, &Ai[3]);
ge25519_p1p1_to_p3(&u, &t);
ge25519_p3_to_cached(&Ai[4], &u);
ge25519_add_cached(&t, &A2, &Ai[4]);
ge25519_p1p1_to_p3(&u, &t);
ge25519_p3_to_cached(&Ai[5], &u);
ge25519_add_cached(&t, &A2, &Ai[5]);
ge25519_p1p1_to_p3(&u, &t);
ge25519_p3_to_cached(&Ai[6], &u);
ge25519_add_cached(&t, &A2, &Ai[6]);
ge25519_p1p1_to_p3(&u, &t);
ge25519_p3_to_cached(&Ai[7], &u);
ge25519_p2_0(r); ge25519_p2_0(r);
@ -824,12 +833,31 @@ ge25519_double_scalarmult_vartime(ge25519_p2 *r, const unsigned char *a,
ge25519_sub_cached(&t, &u, &Ai[(-aslide[i]) / 2]); ge25519_sub_cached(&t, &u, &Ai[(-aslide[i]) / 2]);
} }
if (bslide[i] > 0) { if (B == NULL) {
ge25519_p1p1_to_p3(&u, &t); static const ge25519_precomp Bi[8] = {
ge25519_add_precomp(&t, &u, &Bi[bslide[i] / 2]); #ifdef HAVE_TI_MODE
} else if (bslide[i] < 0) { # include "fe_51/base2.h"
ge25519_p1p1_to_p3(&u, &t); #else
ge25519_sub_precomp(&t, &u, &Bi[(-bslide[i]) / 2]); # include "fe_25_5/base2.h"
#endif
};
if (bslide[i] > 0) {
ge25519_p1p1_to_p3(&u, &t);
ge25519_add_precomp(&t, &u, &Bi[bslide[i] / 2]);
} else if (bslide[i] < 0) {
ge25519_p1p1_to_p3(&u, &t);
ge25519_sub_precomp(&t, &u, &Bi[(-bslide[i]) / 2]);
}
} else {
ge25519_cached Bi[8];
point_precomputation(Bi, B);
if (bslide[i] > 0) {
ge25519_p1p1_to_p3(&u, &t);
ge25519_add_cached(&t, &u, &Bi[bslide[i] / 2]);
} else if (bslide[i] < 0) {
ge25519_p1p1_to_p3(&u, &t);
ge25519_sub_cached(&t, &u, &Bi[(-bslide[i]) / 2]);
}
} }
ge25519_p1p1_to_p2(r, &t); ge25519_p1p1_to_p2(r, &t);
@ -2224,6 +2252,29 @@ sc25519_invert(unsigned char recip[32], const unsigned char s[32])
sc25519_sqmul(recip, 8, _11101011); sc25519_sqmul(recip, 8, _11101011);
} }
/* 2^252+27742317777372353535851937790883648493 */
static const unsigned char L[] = {
0xed, 0xd3, 0xf5, 0x5c, 0x1a, 0x63, 0x12, 0x58, 0xd6, 0x9c, 0xf7,
0xa2, 0xde, 0xf9, 0xde, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10
};
void
sc25519_negate(unsigned char neg[32], const unsigned char s[32])
{
unsigned char t_[64];
unsigned char s_[64];
memset(t_, 0, sizeof t_);
memset(s_, 0, sizeof s_);
memcpy(t_ + 32, L,
32);
memcpy(s_, s, 32);
sodium_sub(t_, s_, sizeof t_);
sc25519_reduce(t_);
memcpy(neg, t_, 32);
}
/* /*
Input: Input:
s[0]+256*s[1]+...+256^63*s[63] = s s[0]+256*s[1]+...+256^63*s[63] = s
@ -2700,6 +2751,68 @@ ge25519_from_uniform(unsigned char s[32], const unsigned char r[32])
ge25519_p3_tobytes(s, &p3); ge25519_p3_tobytes(s, &p3);
} }
#define HASH_GE_L 48U
static int
_string_to_points(unsigned char * const px, const size_t n,
const char *ctx, const unsigned char *msg, size_t msg_len,
int hash_alg)
{
unsigned char h[64];
unsigned char h_be[2U * HASH_GE_L];
size_t i, j;
if (n > 2U) {
abort(); /* LCOV_EXCL_LINE */;
}
if (core_h2c_string_to_hash(h_be, n * HASH_GE_L, ctx, msg, msg_len,
hash_alg) != 0) {
return -1;
}
COMPILER_ASSERT(sizeof h >= HASH_GE_L);
for (i = 0U; i < n; i++) {
for (j = 0U; j < HASH_GE_L; j++) {
h[j] = h_be[i * HASH_GE_L + HASH_GE_L - 1U - j];
}
memset(&h[j], 0, (sizeof h) - j);
ge25519_from_hash(&px[i * 32], h);
}
return 0;
}
int
ge25519_from_string(unsigned char p[32],
const char *ctx, const unsigned char *msg,
size_t msg_len, int hash_alg)
{
return _string_to_points(p, 1, ctx, msg, msg_len, hash_alg);
}
int
ge25519_from_string_ro(unsigned char p[32],
const char *ctx, const unsigned char *msg,
size_t msg_len, int hash_alg)
{
unsigned char px[64];
ge25519_p3 p_p3, q_p3, r_p3;
if (_string_to_points(px, 2, ctx, msg, msg_len, hash_alg) != 0) {
return -1;
}
if (ge25519_frombytes(&p_p3, &px[0]) != 0 || ge25519_is_on_curve(&p_p3) == 0 ||
ge25519_frombytes(&q_p3, &px[32]) != 0 || ge25519_is_on_curve(&q_p3) == 0) {
return -1;
}
ge25519_p3_add(&r_p3, &p_p3, &q_p3);
ge25519_p3_tobytes(p, &r_p3);
return 0;
}
static void static void
fe25519_reduce64(fe25519 fe_f, const unsigned char h[64]) fe25519_reduce64(fe25519 fe_f, const unsigned char h[64])
{ {

View File

@ -55,7 +55,7 @@ _crypto_sign_ed25519_verify_detached(const unsigned char *sig,
crypto_hash_sha512_final(&hs, h); crypto_hash_sha512_final(&hs, h);
sc25519_reduce(h); sc25519_reduce(h);
ge25519_double_scalarmult_vartime(&sb_ah_p2, h, &A, sig + 32); ge25519_double_scalarmult_vartime(&sb_ah_p2, h, &A, sig + 32, NULL);
ge25519_p2_to_p3(&sb_ah, &sb_ah_p2); ge25519_p2_to_p3(&sb_ah, &sb_ah_p2);
ge25519_p3_sub(&check, &expected_r, &sb_ah); ge25519_p3_sub(&check, &expected_r, &sb_ah);

View File

@ -0,0 +1,72 @@
#include "crypto_vrf.h"
size_t
crypto_vrf_publickeybytes(void)
{
return crypto_vrf_PUBLICKEYBYTES;
}
size_t
crypto_vrf_secretkeybytes(void)
{
return crypto_vrf_SECRETKEYBYTES;
}
size_t
crypto_vrf_seedbytes(void)
{
return crypto_vrf_SEEDBYTES;
}
size_t
crypto_vrf_proofbytes(void)
{
return crypto_vrf_PROOFBYTES;
}
size_t
crypto_vrf_outputbytes(void)
{
return crypto_vrf_OUTPUTBYTES;
}
const char *
crypto_vrf_primitive(void)
{
return crypto_vrf_PRIMITIVE;
}
int
crypto_vrf_keypair(unsigned char *pk, unsigned char *sk)
{
return crypto_vrf_rfc9381_keypair(pk, sk);
}
int
crypto_vrf_seed_keypair(unsigned char *pk, unsigned char *sk,
const unsigned char *seed)
{
return crypto_vrf_rfc9381_seed_keypair(pk, sk, seed);
}
int
crypto_vrf_prove(unsigned char *proof, const unsigned char *m, const unsigned long long mlen,
const unsigned char *skpk)
{
return crypto_vrf_rfc9381_prove(proof, m, mlen, skpk);
}
int
crypto_vrf_verify(unsigned char *output, const unsigned char *pk,
const unsigned char *proof, const unsigned char *m,
const unsigned long long mlen)
{
return crypto_vrf_rfc9381_verify(output, pk, proof, m, mlen);
}
int
crypto_vrf_proof_to_hash(unsigned char *hash, const unsigned char *proof)
{
return crypto_vrf_rfc9381_proof_to_hash(hash, proof);
}

View File

@ -0,0 +1,40 @@
#include <string.h>
#include "crypto_hash_sha512.h"
#include "crypto_vrf_rfc9381.h"
#include "private/ed25519_ref10.h"
#include "randombytes.h"
#include "utils.h"
int
crypto_vrf_rfc9381_seed_keypair(unsigned char *pk, unsigned char *sk,
const unsigned char *seed)
{
ge25519_p3 A;
crypto_hash_sha512(sk, seed, 32);
sk[0] &= 248;
sk[31] &= 127;
sk[31] |= 64;
ge25519_scalarmult_base(&A, sk);
ge25519_p3_tobytes(pk, &A);
memmove(sk, seed, 32);
memmove(sk + 32, pk, 32);
return 0;
}
int
crypto_vrf_rfc9381_keypair(unsigned char *pk, unsigned char *sk)
{
unsigned char seed[32];
int ret;
randombytes_buf(seed, sizeof seed);
ret = crypto_vrf_rfc9381_seed_keypair(pk, sk, seed);
sodium_memzero(seed, sizeof seed);
return ret;
}

View File

@ -0,0 +1,69 @@
#include <string.h>
#include <stdlib.h>
#include "crypto_hash_sha512.h"
#include "crypto_vrf_rfc9381.h"
#include "private/ed25519_ref10.h"
#include "utils.h"
#include "vrf_rfc9381.h"
int
crypto_vrf_rfc9381_prove(unsigned char *proof,
const unsigned char *m, unsigned long long mlen,
const unsigned char *sk)
{
crypto_hash_sha512_state hs;
unsigned char az[64];
unsigned char H_string[32];
unsigned char kB_string[32], kH_string[32];
unsigned char string_to_hash[32 + mlen];
unsigned char challenge[64], nonce[64];
ge25519_p3 H, Gamma, kB, kH;
crypto_hash_sha512(az, sk, 32);
az[0] &= 248;
az[31] &= 127;
az[31] |= 64;
memmove(string_to_hash, sk + 32, 32);
memmove(string_to_hash + 32, m, mlen);
ge25519_from_string(H_string, "ECVRF_edwards25519_XMD:SHA-512_ELL2_NU_\4", string_to_hash, 32 + mlen, 2); /* elligator2 */
ge25519_frombytes(&H, H_string);
ge25519_scalarmult(&Gamma, az, &H);
crypto_hash_sha512_init(&hs);
crypto_hash_sha512_update(&hs, az + 32, 32);
crypto_hash_sha512_update(&hs, H_string, 32);
crypto_hash_sha512_final(&hs, nonce);
sc25519_reduce(nonce);
ge25519_scalarmult_base(&kB, nonce);
ge25519_scalarmult(&kH, nonce, &H);
ge25519_p3_tobytes(proof, &Gamma);
ge25519_p3_tobytes(kB_string, &kB);
ge25519_p3_tobytes(kH_string, &kH);
crypto_hash_sha512_init(&hs);
crypto_hash_sha512_update(&hs, &SUITE, 1);
crypto_hash_sha512_update(&hs, &TWO, 1);
crypto_hash_sha512_update(&hs, sk + 32, 32);
crypto_hash_sha512_update(&hs, H_string, 32);
crypto_hash_sha512_update(&hs, proof, 32);
crypto_hash_sha512_update(&hs, kB_string, 32);
crypto_hash_sha512_update(&hs, kH_string, 32);
crypto_hash_sha512_update(&hs, &ZERO, 1);
crypto_hash_sha512_final(&hs, challenge);
memmove(proof + 32, challenge, 16);
memset(challenge + 16, 0, 48); /* we zero out the last 48 bytes of the challenge */
sc25519_muladd(proof + 48, challenge, az, nonce);
sodium_memzero(az, sizeof az);
sodium_memzero(nonce, sizeof nonce);
return 0;
}

View File

@ -0,0 +1,116 @@
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include "crypto_hash_sha512.h"
#include "crypto_vrf_rfc9381.h"
#include "private/ed25519_ref10.h"
#include "vrf_rfc9381.h"
#include "crypto_verify_16.h"
int
crypto_vrf_rfc9381_proof_to_hash(unsigned char *beta,
const unsigned char *pi)
{
ge25519_p3 Gamma;
unsigned char gamma_string[32];
if (ge25519_is_canonical(pi) == 0 ||
ge25519_frombytes(&Gamma, pi) != 0) {
return -1;
}
if (pi[48 + 31] & 240 &&
sc25519_is_canonical(pi + 48) == 0) {
return -1;
}
ge25519_clear_cofactor(&Gamma);
ge25519_p3_tobytes(gamma_string, &Gamma);
/* beta_string = Hash(suite_string || three_string || point_to_string(cofactor * Gamma) || zero_string ) */
crypto_hash_sha512_state hs;
crypto_hash_sha512_init(&hs);
crypto_hash_sha512_update(&hs, &SUITE, 1);
crypto_hash_sha512_update(&hs, &THREE, 1);
crypto_hash_sha512_update(&hs, gamma_string, 32);
crypto_hash_sha512_update(&hs, &ZERO, 1);
crypto_hash_sha512_final(&hs, beta);
return 0;
}
static int
vrf_verify(const unsigned char *pi,
const unsigned char *alpha, unsigned long long alphalen,
const ge25519_p3 *Y_point)
{
unsigned char H_string[32], U_string[32], V_string[32], Y_string[32];
unsigned char cn[32], c[32], s[32];
unsigned char string_to_hash[32 + alphalen], challenge[64];
crypto_hash_sha512_state hs;
ge25519_p2 U, V;
ge25519_p3 H, Gamma;
ge25519_p1p1 tmp_p1p1_point;
ge25519_cached tmp_cached_point;
ge25519_p3_tobytes(Y_string, Y_point);
if (ge25519_is_canonical(pi) == 0 ||
ge25519_frombytes(&Gamma, pi) != 0) {
return -1;
}
memmove(c, pi + 32, 16); /* c = pi[32:48] */
memmove(s, pi + 48, 32); /* s = pi[48:80] */
if (s[31] & 240 &&
sc25519_is_canonical(s) == 0) {
return -1;
}
memset(c + 16, 0, 16);
memmove(string_to_hash, Y_string, 32);
memmove(string_to_hash + 32, alpha, alphalen);
ge25519_from_string(H_string, "ECVRF_edwards25519_XMD:SHA-512_ELL2_NU_\4", string_to_hash, 32 + alphalen, 2); /* elligator2 */
ge25519_frombytes(&H, H_string);
sc25519_negate(cn, c); /* negate scalar c */
ge25519_double_scalarmult_vartime(&U, cn, Y_point, s, NULL);
ge25519_double_scalarmult_vartime(&V, cn, &Gamma, s, &H);
ge25519_tobytes(U_string, &U);
ge25519_tobytes(V_string, &V);
crypto_hash_sha512_init(&hs);
crypto_hash_sha512_update(&hs, &SUITE, 1);
crypto_hash_sha512_update(&hs, &TWO, 1);
crypto_hash_sha512_update(&hs, Y_string, 32);
crypto_hash_sha512_update(&hs, H_string, 32);
crypto_hash_sha512_update(&hs, pi, 32);
crypto_hash_sha512_update(&hs, U_string, 32);
crypto_hash_sha512_update(&hs, V_string, 32);
crypto_hash_sha512_update(&hs, &ZERO, 1);
crypto_hash_sha512_final(&hs, challenge);
return crypto_verify_16(c, challenge);
}
int
crypto_vrf_rfc9381_verify(unsigned char *output,
const unsigned char *pk,
const unsigned char *proof,
const unsigned char *msg, const unsigned long long msglen)
{
ge25519_p3 Y;
if (ge25519_frombytes(&Y, pk) == 0 && ge25519_has_small_order(&Y) == 0 &&
ge25519_is_canonical(pk) == 1 && (vrf_verify(proof, msg, msglen, &Y) == 0)) {
return crypto_vrf_rfc9381_proof_to_hash(output, proof);
} else {
return -1;
}
}

View File

@ -0,0 +1,31 @@
#include "crypto_vrf_rfc9381.h"
size_t
crypto_vrf_rfc9381_bytes(void)
{
return crypto_vrf_rfc9381_BYTES;
}
size_t
crypto_vrf_rfc9381_outputbytes(void)
{
return crypto_vrf_rfc9381_OUTPUTBYTES;
}
size_t
crypto_vrf_rfc9381_seedbytes(void)
{
return crypto_vrf_rfc9381_SEEDBYTES;
}
size_t
crypto_vrf_rfc9381_publickeybytes(void)
{
return crypto_vrf_rfc9381_PUBLICKEYBYTES;
}
size_t
crypto_vrf_rfc9381_secretkeybytes(void)
{
return crypto_vrf_rfc9381_SECRETKEYBYTES;
}

View File

@ -0,0 +1,10 @@
#ifndef vrf_rfc9381_H
#define vrf_rfc9381_H
static const unsigned char SUITE = 0x04; /* ECVRF-ED25519-SHA512-ELL2 */
static const unsigned char ZERO = 0x00;
static const unsigned char TWO = 0x02;
static const unsigned char THREE = 0x03;
#endif

View File

@ -59,6 +59,8 @@ SODIUM_EXPORT = \
sodium/crypto_verify_16.h \ sodium/crypto_verify_16.h \
sodium/crypto_verify_32.h \ sodium/crypto_verify_32.h \
sodium/crypto_verify_64.h \ sodium/crypto_verify_64.h \
sodium/crypto_vrf.h \
sodium/crypto_vrf_rfc9381.h \
sodium/export.h \ sodium/export.h \
sodium/randombytes.h \ sodium/randombytes.h \
sodium/randombytes_internal_random.h \ sodium/randombytes_internal_random.h \

View File

@ -51,6 +51,8 @@
#include "sodium/crypto_verify_16.h" #include "sodium/crypto_verify_16.h"
#include "sodium/crypto_verify_32.h" #include "sodium/crypto_verify_32.h"
#include "sodium/crypto_verify_64.h" #include "sodium/crypto_verify_64.h"
#include "sodium/crypto_vrf.h"
#include "sodium/crypto_vrf_rfc9381.h"
#include "sodium/randombytes.h" #include "sodium/randombytes.h"
#include "sodium/randombytes_internal_random.h" #include "sodium/randombytes_internal_random.h"
#include "sodium/randombytes_sysrandom.h" #include "sodium/randombytes_sysrandom.h"

View File

@ -0,0 +1,75 @@
#ifndef crypto_vrf_H
#define crypto_vrf_H
/*
* THREAD SAFETY: crypto_vrf_keypair() is thread-safe,
* provided that sodium_init() was called before.
*
* Other functions, including crypto_vrf_keypair_from_seed(), are always thread-safe.
*/
#include <stddef.h>
#include "crypto_vrf_rfc9381.h"
#include "export.h"
#ifdef __cplusplus
# ifdef __GNUC__
# pragma GCC diagnostic ignored "-Wlong-long"
# endif
extern "C" {
#endif
#define crypto_vrf_PROOFBYTES crypto_vrf_rfc9381_BYTES
SODIUM_EXPORT
size_t crypto_vrf_bytes(void);
#define crypto_vrf_OUTPUTBYTES crypto_vrf_rfc9381_OUTPUTBYTES
SODIUM_EXPORT
size_t crypto_vrf_outputbytes(void);
#define crypto_vrf_SEEDBYTES crypto_vrf_rfc9381_SEEDBYTES
SODIUM_EXPORT
size_t crypto_vrf_seedbytes(void);
#define crypto_vrf_PUBLICKEYBYTES crypto_vrf_rfc9381_PUBLICKEYBYTES
SODIUM_EXPORT
size_t crypto_vrf_publickeybytes(void);
#define crypto_vrf_SECRETKEYBYTES crypto_vrf_rfc9381_SECRETKEYBYTES
SODIUM_EXPORT
size_t crypto_vrf_secretkeybytes(void);
#define crypto_vrf_PRIMITIVE "rfc9381"
SODIUM_EXPORT
const char *crypto_vrf_primitive(void);
SODIUM_EXPORT
int crypto_vrf_keypair(unsigned char *pk, unsigned char *sk)
__attribute__ ((nonnull));
SODIUM_EXPORT
int crypto_vrf_seed_keypair(unsigned char *pk, unsigned char *sk,
const unsigned char *seed)
__attribute__ ((nonnull));
SODIUM_EXPORT
int crypto_vrf_prove(unsigned char *proof, const unsigned char *m,
unsigned long long mlen, const unsigned char *sk)
__attribute__ ((nonnull));
SODIUM_EXPORT
int crypto_vrf_verify(unsigned char *output,
const unsigned char *pk,
const unsigned char *proof,
const unsigned char *m, unsigned long long mlen)
__attribute__ ((warn_unused_result)) __attribute__ ((nonnull));
SODIUM_EXPORT
int crypto_vrf_proof_to_hash(unsigned char *hash, const unsigned char *proof);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -0,0 +1,78 @@
#ifndef crypto_vrf_rfc9381_H
#define crypto_vrf_rfc9381_H
#include <stddef.h>
#include "export.h"
#ifdef __cplusplus
# ifdef __GNUC__
# pragma GCC diagnostic ignored "-Wlong-long"
# endif
extern "C" {
#endif
#define crypto_vrf_rfc9381_BYTES 80U
SODIUM_EXPORT
size_t crypto_vrf_rfc9381_bytes(void);
#define crypto_vrf_rfc9381_OUTPUTBYTES 64U
SODIUM_EXPORT
size_t crypto_vrf_rfc9381_outputbytes(void);
#define crypto_vrf_rfc9381_SEEDBYTES 32U
SODIUM_EXPORT
size_t crypto_vrf_rfc9381_seedbytes(void);
#define crypto_vrf_rfc9381_PUBLICKEYBYTES 32U
SODIUM_EXPORT
size_t crypto_vrf_rfc9381_publickeybytes(void);
#define crypto_vrf_rfc9381_SECRETKEYBYTES 64U
SODIUM_EXPORT
size_t crypto_vrf_rfc9381_secretkeybytes(void);
SODIUM_EXPORT
int crypto_vrf_rfc9381_prove(unsigned char *proof,
const unsigned char *m,
unsigned long long mlen, const unsigned char *sk);
SODIUM_EXPORT
int crypto_vrf_rfc9381_verify(unsigned char *output,
const unsigned char *pk,
const unsigned char *proof,
const unsigned char *m,
unsigned long long mlen)
__attribute__ ((warn_unused_result)) __attribute__ ((nonnull));
SODIUM_EXPORT
int crypto_vrf_rfc9381_proof_to_hash(unsigned char *hash,
const unsigned char *proof)
__attribute__ ((nonnull));
SODIUM_EXPORT
int crypto_vrf_rfc9381_keypair(unsigned char *pk, unsigned char *sk)
__attribute__ ((nonnull));
SODIUM_EXPORT
int crypto_vrf_rfc9381_seed_keypair(unsigned char *pk,
unsigned char *sk,
const unsigned char *seed)
__attribute__ ((nonnull));
SODIUM_EXPORT
void crypto_vrf_rfc9381_sk_to_seed(unsigned char *seed,
const unsigned char *sk)
__attribute__ ((nonnull));
SODIUM_EXPORT
void crypto_vrf_rfc9381_sk_to_pk(unsigned char *pk,
const unsigned char *sk)
__attribute__ ((nonnull));
#ifdef __cplusplus
}
#endif
#endif

View File

@ -96,7 +96,8 @@ void ge25519_scalarmult_base(ge25519_p3 *h, const unsigned char *a);
void ge25519_double_scalarmult_vartime(ge25519_p2 *r, const unsigned char *a, void ge25519_double_scalarmult_vartime(ge25519_p2 *r, const unsigned char *a,
const ge25519_p3 *A, const ge25519_p3 *A,
const unsigned char *b); const unsigned char *b,
const ge25519_p3 *B);
void ge25519_scalarmult(ge25519_p3 *h, const unsigned char *a, void ge25519_scalarmult(ge25519_p3 *h, const unsigned char *a,
const ge25519_p3 *p); const ge25519_p3 *p);
@ -115,6 +116,14 @@ void ge25519_from_uniform(unsigned char s[32], const unsigned char r[32]);
void ge25519_from_hash(unsigned char s[32], const unsigned char h[64]); void ge25519_from_hash(unsigned char s[32], const unsigned char h[64]);
int ge25519_from_string(unsigned char p[32],
const char *ctx, const unsigned char *msg,
size_t msg_len, int hash_alg);
int ge25519_from_string_ro(unsigned char p[32],
const char *ctx, const unsigned char *msg,
size_t msg_len, int hash_alg);
/* /*
Ristretto group Ristretto group
*/ */
@ -132,6 +141,8 @@ void ristretto255_from_hash(unsigned char s[32], const unsigned char h[64]);
void sc25519_invert(unsigned char recip[32], const unsigned char s[32]); void sc25519_invert(unsigned char recip[32], const unsigned char s[32]);
void sc25519_negate(unsigned char neg[32], const unsigned char s[32]);
void sc25519_reduce(unsigned char s[64]); void sc25519_reduce(unsigned char s[64]);
void sc25519_mul(unsigned char s[32], const unsigned char a[32], void sc25519_mul(unsigned char s[32], const unsigned char a[32],
@ -142,4 +153,6 @@ void sc25519_muladd(unsigned char s[32], const unsigned char a[32],
int sc25519_is_canonical(const unsigned char s[32]); int sc25519_is_canonical(const unsigned char s[32]);
void ge25519_clear_cofactor(ge25519_p3 *p3);
#endif #endif

View File

@ -54,6 +54,8 @@
#define ge25519_clear_cofactor _sodium_ge25519_clear_cofactor #define ge25519_clear_cofactor _sodium_ge25519_clear_cofactor
#define ge25519_double_scalarmult_vartime _sodium_ge25519_double_scalarmult_vartime #define ge25519_double_scalarmult_vartime _sodium_ge25519_double_scalarmult_vartime
#define ge25519_from_hash _sodium_ge25519_from_hash #define ge25519_from_hash _sodium_ge25519_from_hash
#define ge25519_from_string _sodium_ge25519_from_string
#define ge25519_from_string_ro _sodium_ge25519_from_string_ro
#define ge25519_from_uniform _sodium_ge25519_from_uniform #define ge25519_from_uniform _sodium_ge25519_from_uniform
#define ge25519_frombytes _sodium_ge25519_frombytes #define ge25519_frombytes _sodium_ge25519_frombytes
#define ge25519_frombytes_negate_vartime _sodium_ge25519_frombytes_negate_vartime #define ge25519_frombytes_negate_vartime _sodium_ge25519_frombytes_negate_vartime
@ -77,6 +79,7 @@
#define sc25519_is_canonical _sodium_sc25519_is_canonical #define sc25519_is_canonical _sodium_sc25519_is_canonical
#define sc25519_mul _sodium_sc25519_mul #define sc25519_mul _sodium_sc25519_mul
#define sc25519_muladd _sodium_sc25519_muladd #define sc25519_muladd _sodium_sc25519_muladd
#define sc25519_negate _sodium_sc25519_negate
#define sc25519_reduce _sodium_sc25519_reduce #define sc25519_reduce _sodium_sc25519_reduce
#define softaes_block_encrypt _sodium_softaes_block_encrypt #define softaes_block_encrypt _sodium_softaes_block_encrypt

View File

@ -86,6 +86,7 @@ EXTRA_DIST = \
stream3.exp \ stream3.exp \
stream4.exp \ stream4.exp \
verify1.exp \ verify1.exp \
vrf.exp \
xchacha20.exp xchacha20.exp
DISTCLEANFILES = \ DISTCLEANFILES = \
@ -171,6 +172,7 @@ DISTCLEANFILES = \
stream3.res \ stream3.res \
stream4.res \ stream4.res \
verify1.res \ verify1.res \
vrf.res \
xchacha20.res xchacha20.res
AM_CPPFLAGS = \ AM_CPPFLAGS = \
@ -253,7 +255,8 @@ TESTS_TARGETS = \
stream2 \ stream2 \
stream3 \ stream3 \
stream4 \ stream4 \
verify1 verify1 \
vrf
if !EMSCRIPTEN if !EMSCRIPTEN
TESTS_TARGETS += \ TESTS_TARGETS += \
@ -511,6 +514,9 @@ stream4_LDADD = $(TESTS_LDADD)
verify1_SOURCE = cmptest.h verify1.c verify1_SOURCE = cmptest.h verify1.c
verify1_LDADD = $(TESTS_LDADD) verify1_LDADD = $(TESTS_LDADD)
vrf_SOURCE = cmptest.h vrf.c
vrf_LDADD = $(TESTS_LDADD)
xchacha20_SOURCE = cmptest.h xchacha20.c xchacha20_SOURCE = cmptest.h xchacha20.c
xchacha20_LDADD = $(TESTS_LDADD) xchacha20_LDADD = $(TESTS_LDADD)

91
test/default/vrf.c Normal file
View File

@ -0,0 +1,91 @@
#define TEST_NAME "vrf"
#include "cmptest.h"
typedef struct TestData_ {
const char seed[2 * 32 + 1];
} TestData;
/*
* Test data taken from https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-vrf-09#appendix-A.4
* which contains the seeds. The expected values for the pk, proof and output are in vrf.exp
*/
static const TestData test_data[] = {
{"9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60"},
{"4ccd089b28ff96da9db6c346ec114e0f5b8a319f35aba624da8cf6ed4fb8a6fb"},
{"c5aa8df43f9f837bedb7442f31dcb7b166d38535076f094b85ce3a2e0b4458f7"},
};
static const unsigned char messages[3][2] = {{0x00}, {0x72}, {0xaf, 0x82}};
int main(void)
{
unsigned char *seed;
unsigned char sk[64];
unsigned char pk[32];
unsigned char proof[80];
unsigned char output[64];
unsigned int i;
char pk_hex[32 * 2 + 1];
char proof_hex[80 * 2 + 1];
char output_hex[64 * 2 + 1];
seed = (unsigned char *) sodium_malloc(crypto_vrf_rfc9381_SEEDBYTES);
assert(crypto_vrf_rfc9381_SECRETKEYBYTES == 64);
assert(crypto_vrf_rfc9381_PUBLICKEYBYTES == 32);
assert(crypto_vrf_rfc9381_SEEDBYTES == 32);
assert(crypto_vrf_rfc9381_BYTES == 80);
assert(crypto_vrf_rfc9381_OUTPUTBYTES == 64);
for (i = 0U; i < (sizeof test_data) / (sizeof test_data[0]); i++) {
sodium_hex2bin(seed, 32,
test_data[i].seed, (size_t) -1U, NULL, NULL, NULL);
crypto_vrf_rfc9381_seed_keypair(pk, sk, seed);
printf("%s\n", sodium_bin2hex(pk_hex, sizeof pk_hex, pk, sizeof pk));
if (crypto_vrf_rfc9381_prove(proof, messages[i], i, sk) != 0){
printf("crypto_vrf_prove() error: [%u]\n", i);
}
printf("%s\n", sodium_bin2hex(proof_hex, sizeof proof_hex, proof, sizeof proof));
if (crypto_vrf_rfc9381_verify(output, pk, proof, messages[i], i) != 0){
printf("verify error: [%u]\n", i);
}
printf("%s\n", sodium_bin2hex(output_hex, sizeof output_hex, output, sizeof output));
proof[0] ^= 0x01;
if (crypto_vrf_rfc9381_verify(output, pk, proof, messages[i], i) == 0){
printf("verify succeeded with bad gamma: [%u]\n", i);
}
proof[0] ^= 0x01;
proof[32] ^= 0x01;
if (crypto_vrf_rfc9381_verify(output, pk, proof, messages[i], i) == 0){
printf("verify succeeded with bad c value: [%u]\n", i);
}
proof[32] ^= 0x01;
proof[48] ^= 0x01;
if (crypto_vrf_rfc9381_verify(output, pk, proof, messages[i], i) == 0){
printf("verify succeeded with bad s value: [%u]\n", i);
}
proof[48] ^= 0x01;
proof[79] ^= 0x80;
if (crypto_vrf_rfc9381_verify(output, pk, proof, messages[i], i) == 0){
printf("verify succeeded with bad s value (high-order-bit flipped): [%u]\n", i);
}
proof[79] ^= 0x80;
if (i > 0) {
if (crypto_vrf_rfc9381_verify(output, pk, proof, messages[i], i-1) == 0){
printf("verify succeeded with truncated message: [%u]\n", i);
}
}
if (crypto_vrf_rfc9381_proof_to_hash(output, proof) != 0){
printf("crypto_vrf_proof_to_hash() error: [%u]\n", i);
}
printf("%s\n\n", sodium_bin2hex(output_hex, sizeof output_hex, output, sizeof output));
}
return 0;
}

15
test/default/vrf.exp Normal file
View File

@ -0,0 +1,15 @@
d75a980182b10ab7d54bfed3c964073a0ee172f3daa62325af021a68f707511a
7d9c633ffeee27349264cf5c667579fc583b4bda63ab71d001f89c10003ab46f14adf9a3cd8b8412d9038531e865c341cafa73589b023d14311c331a9ad15ff2fb37831e00f0acaa6d73bc9997b06501
9d574bf9b8302ec0fc1e21c3ec5368269527b87b462ce36dab2d14ccf80c53cccf6758f058c5b1c856b116388152bbe509ee3b9ecfe63d93c3b4346c1fbc6c54
9d574bf9b8302ec0fc1e21c3ec5368269527b87b462ce36dab2d14ccf80c53cccf6758f058c5b1c856b116388152bbe509ee3b9ecfe63d93c3b4346c1fbc6c54
3d4017c3e843895a92b70aa74d1b7ebc9c982ccf2ec4968cc0cd55f12af4660c
47b327393ff2dd81336f8a2ef10339112401253b3c714eeda879f12c509072ef055b48372bb82efbdce8e10c8cb9a2f9d60e93908f93df1623ad78a86a028d6bc064dbfc75a6a57379ef855dc6733801
38561d6b77b71d30eb97a062168ae12b667ce5c28caccdf76bc88e093e4635987cd96814ce55b4689b3dd2947f80e59aac7b7675f8083865b46c89b2ce9cc735
38561d6b77b71d30eb97a062168ae12b667ce5c28caccdf76bc88e093e4635987cd96814ce55b4689b3dd2947f80e59aac7b7675f8083865b46c89b2ce9cc735
fc51cd8e6218a1a38da47ed00230f0580816ed13ba3303ac5deb911548908025
926e895d308f5e328e7aa159c06eddbe56d06846abf5d98c2512235eaa57fdce35b46edfc655bc828d44ad09d1150f31374e7ef73027e14760d42e77341fe05467bb286cc2c9d7fde29120a0b2320d04
121b7f9b9aaaa29099fc04a94ba52784d44eac976dd1a3cca458733be5cd090a7b5fbd148444f17f8daf1fb55cb04b1ae85a626e30a54b4b0f8abf4a43314a58
121b7f9b9aaaa29099fc04a94ba52784d44eac976dd1a3cca458733be5cd090a7b5fbd148444f17f8daf1fb55cb04b1ae85a626e30a54b4b0f8abf4a43314a58

View File

@ -637,6 +637,27 @@ crypto_verify_32
crypto_verify_32_bytes crypto_verify_32_bytes
crypto_verify_64 crypto_verify_64
crypto_verify_64_bytes crypto_verify_64_bytes
crypto_vrf_keypair
crypto_vrf_outputbytes
crypto_vrf_primitive
crypto_vrf_proof_to_hash
crypto_vrf_proofbytes
crypto_vrf_prove
crypto_vrf_publickeybytes
crypto_vrf_rfc9381_bytes
crypto_vrf_rfc9381_keypair
crypto_vrf_rfc9381_outputbytes
crypto_vrf_rfc9381_proof_to_hash
crypto_vrf_rfc9381_prove
crypto_vrf_rfc9381_publickeybytes
crypto_vrf_rfc9381_secretkeybytes
crypto_vrf_rfc9381_seed_keypair
crypto_vrf_rfc9381_seedbytes
crypto_vrf_rfc9381_verify
crypto_vrf_secretkeybytes
crypto_vrf_seed_keypair
crypto_vrf_seedbytes
crypto_vrf_verify
escrypt_PBKDF2_SHA256 escrypt_PBKDF2_SHA256
escrypt_alloc_region escrypt_alloc_region
escrypt_free_local escrypt_free_local
@ -653,6 +674,8 @@ fe25519_tobytes
ge25519_clear_cofactor ge25519_clear_cofactor
ge25519_double_scalarmult_vartime ge25519_double_scalarmult_vartime
ge25519_from_hash ge25519_from_hash
ge25519_from_string
ge25519_from_string_ro
ge25519_from_uniform ge25519_from_uniform
ge25519_frombytes ge25519_frombytes
ge25519_frombytes_negate_vartime ge25519_frombytes_negate_vartime
@ -686,6 +709,7 @@ sc25519_invert
sc25519_is_canonical sc25519_is_canonical
sc25519_mul sc25519_mul
sc25519_muladd sc25519_muladd
sc25519_negate
sc25519_reduce sc25519_reduce
sodium_add sodium_add
sodium_allocarray sodium_allocarray