/*
This file is part of GNUnet.
Copyright (C) 2015 GNUnet e.V.
GNUnet is free software: you can redistribute it and/or modify it
under the terms of the GNU Affero General Public License as published
by the Free Software Foundation, either version 3 of the License,
or (at your option) any later version.
GNUnet is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see .
SPDX-License-Identifier: AGPL3.0-or-later
*/
/**
* @file util/test_ecc_scalarproduct.c
* @brief testcase for math behind ECC SP calculation
* @author Christian Grothoff
*/
#include "platform.h"
#include "gnunet_util_lib.h"
#include
/**
* Global context.
*/
static struct GNUNET_CRYPTO_EccDlogContext *edc;
/**
* Perform SP calculation.
*
* @param avec 0-terminated vector of Alice's values
* @param bvec 0-terminated vector of Bob's values
* @return avec * bvec
*/
static int
test_sp (const unsigned int *avec,
const unsigned int *bvec)
{
unsigned int len;
struct GNUNET_CRYPTO_EccScalar a;
struct GNUNET_CRYPTO_EccScalar a_neg;
struct GNUNET_CRYPTO_EccPoint *g;
struct GNUNET_CRYPTO_EccPoint *h;
struct GNUNET_CRYPTO_EccPoint pg;
struct GNUNET_CRYPTO_EccPoint ph;
/* determine length */
for (len = 0; 0 != avec[len]; len++)
;
if (0 == len)
return 0;
/* Alice */
GNUNET_CRYPTO_ecc_rnd_mpi (&a,
&a_neg);
g = GNUNET_new_array (len,
struct GNUNET_CRYPTO_EccPoint);
h = GNUNET_new_array (len,
struct GNUNET_CRYPTO_EccPoint);
for (unsigned int i = 0; i < len; i++)
{
struct GNUNET_CRYPTO_EccScalar tmp;
struct GNUNET_CRYPTO_EccScalar ri;
struct GNUNET_CRYPTO_EccScalar ria;
GNUNET_CRYPTO_ecc_random_mod_n (&ri);
GNUNET_assert (GNUNET_OK ==
GNUNET_CRYPTO_ecc_dexp_mpi (&ri,
&g[i]));
/* ria = ri * a mod L, where L is the order of the main subgroup */
crypto_core_ed25519_scalar_mul (ria.v,
ri.v,
a.v);
/* tmp = ria + avec[i] */
{
int64_t val = avec[i];
struct GNUNET_CRYPTO_EccScalar vali;
GNUNET_assert (INT64_MIN != val);
GNUNET_CRYPTO_ecc_scalar_from_int (val > 0 ? val : -val,
&vali);
if (val > 0)
crypto_core_ed25519_scalar_add (tmp.v,
ria.v,
vali.v);
else
crypto_core_ed25519_scalar_sub (tmp.v,
ria.v,
vali.v);
}
/* h[i] = g^tmp = g^{ria + avec[i]} */
GNUNET_assert (GNUNET_OK ==
GNUNET_CRYPTO_ecc_dexp_mpi (&tmp,
&h[i]));
}
/* Bob */
for (unsigned int i = 0; i < len; i++)
{
struct GNUNET_CRYPTO_EccPoint gm;
struct GNUNET_CRYPTO_EccPoint hm;
{
int64_t val = bvec[i];
struct GNUNET_CRYPTO_EccScalar vali;
GNUNET_assert (INT64_MIN != val);
GNUNET_CRYPTO_ecc_scalar_from_int (val > 0 ? val : -val,
&vali);
if (val < 0)
crypto_core_ed25519_scalar_negate (vali.v,
vali.v);
/* gm = g[i]^vali */
GNUNET_assert (GNUNET_OK ==
GNUNET_CRYPTO_ecc_pmul_mpi (&g[i],
&vali,
&gm));
/* hm = h[i]^vali */
GNUNET_assert (GNUNET_OK ==
GNUNET_CRYPTO_ecc_pmul_mpi (&h[i],
&vali,
&hm));
}
if (0 != i)
{
/* pg += gm */
GNUNET_assert (GNUNET_OK ==
GNUNET_CRYPTO_ecc_add (&gm,
&pg,
&pg));
/* ph += hm */
GNUNET_assert (GNUNET_OK ==
GNUNET_CRYPTO_ecc_add (&hm,
&ph,
&ph));
}
else
{
pg = gm;
ph = hm;
}
}
GNUNET_free (g);
GNUNET_free (h);
/* Alice */
{
struct GNUNET_CRYPTO_EccPoint pgi;
struct GNUNET_CRYPTO_EccPoint gsp;
/* pgi = pg^inv */
GNUNET_assert (GNUNET_OK ==
GNUNET_CRYPTO_ecc_pmul_mpi (&pg,
&a_neg,
&pgi));
/* gsp = pgi + ph */
GNUNET_assert (GNUNET_OK ==
GNUNET_CRYPTO_ecc_add (&pgi,
&ph,
&gsp));
return GNUNET_CRYPTO_ecc_dlog (edc,
&gsp);
}
}
/**
* Macro that checks that @a want is equal to @a have and
* if not returns with a failure code.
*/
#define CHECK(want,have) do { \
if (want != have) { \
GNUNET_break (0); \
GNUNET_log (GNUNET_ERROR_TYPE_ERROR, \
"Wanted %d, got %d\n", want, have); \
GNUNET_CRYPTO_ecc_dlog_release (edc); \
return 1; \
} } while (0)
int
main (int argc, char *argv[])
{
static unsigned int v11[] = { 1, 1, 0 };
static unsigned int v22[] = { 2, 2, 0 };
static unsigned int v35[] = { 3, 5, 0 };
static unsigned int v24[] = { 2, 4, 0 };
GNUNET_log_setup ("test-ecc-scalarproduct",
"WARNING",
NULL);
edc = GNUNET_CRYPTO_ecc_dlog_prepare (128, 128);
CHECK (2, test_sp (v11, v11));
CHECK (4, test_sp (v22, v11));
CHECK (8, test_sp (v35, v11));
CHECK (26, test_sp (v35, v24));
CHECK (26, test_sp (v24, v35));
CHECK (16, test_sp (v22, v35));
GNUNET_CRYPTO_ecc_dlog_release (edc);
return 0;
}
/* end of test_ecc_scalarproduct.c */