From 2bcdfc2f958f5fd2512103c2240f1c24c07524d7 Mon Sep 17 00:00:00 2001 From: Lucien Heuzeveldt Date: Mon, 6 Dec 2021 22:13:35 +0100 Subject: add crypto_cs implementation --- src/include/gnunet_crypto_lib.h | 270 +++++++++++++++++++++++++ src/util/Makefile.am | 1 + src/util/crypto_cs.c | 425 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 696 insertions(+) create mode 100644 src/util/crypto_cs.c diff --git a/src/include/gnunet_crypto_lib.h b/src/include/gnunet_crypto_lib.h index edb4bb230..9166f822b 100644 --- a/src/include/gnunet_crypto_lib.h +++ b/src/include/gnunet_crypto_lib.h @@ -392,6 +392,127 @@ struct GNUNET_CRYPTO_PaillierCiphertext }; +/** + * Curve25519 Scalar + */ +struct GNUNET_CRYPTO_Cs25519Scalar +{ + /** + * 32 byte scalar + */ + unsigned char d[crypto_core_ed25519_SCALARBYTES]; +}; + + +/** + * Curve25519 point + */ +struct GNUNET_CRYPTO_Cs25519Point +{ + /** + * This is a point on the Curve25519. + * The x coordinate can be restored using the y coordinate + */ + unsigned char y[crypto_core_ed25519_BYTES]; +}; + + +/** + * The private information of an Schnorr key pair. + */ +struct GNUNET_CRYPTO_CsPrivateKey +{ + struct GNUNET_CRYPTO_Cs25519Scalar scalar; +}; + + +/** + * The public information of an Schnorr key pair. + */ +struct GNUNET_CRYPTO_CsPublicKey +{ + struct GNUNET_CRYPTO_Cs25519Point point; +}; + + +/** + * Secret used for blinding (alpha and beta). + */ +struct GNUNET_CRYPTO_CsBlindingSecret +{ + struct GNUNET_CRYPTO_Cs25519Scalar alpha; + struct GNUNET_CRYPTO_Cs25519Scalar beta; +}; + + +/** + * the private r used in the signature + */ +struct GNUNET_CRYPTO_CsRSecret +{ + struct GNUNET_CRYPTO_Cs25519Scalar scalar; +}; + + +/** + * the public R (derived from r) used in c + */ +struct GNUNET_CRYPTO_CsRPublic +{ + struct GNUNET_CRYPTO_Cs25519Point point; +}; + + +/** + * Schnorr c to be signed + */ +struct GNUNET_CRYPTO_CsC +{ + struct GNUNET_CRYPTO_Cs25519Scalar scalar; +}; + + +/** + * s in the signature + */ +struct GNUNET_CRYPTO_CsS +{ + struct GNUNET_CRYPTO_Cs25519Scalar scalar; +}; + + +/** + * blinded s in the signature + */ +struct GNUNET_CRYPTO_CsBlindS +{ + struct GNUNET_CRYPTO_Cs25519Scalar scalar; +}; + + +/** + * CS Signtature containing scalar s and point R + */ +struct GNUNET_CRYPTO_CsSignature +{ + /** + * Schnorr signatures are composed of a scalar s and a curve point + */ + struct GNUNET_CRYPTO_CsS s_scalar; + struct GNUNET_CRYPTO_CsRPublic r_point; +}; + + +/** + * Nonce + */ +struct GNUNET_CRYPTO_CsNonce +{ + /*a nonce*/ + unsigned char nonce[256 / 8]; +}; + + /* **************** Functions and Macros ************* */ /** @@ -2436,6 +2557,155 @@ GNUNET_CRYPTO_rsa_verify (const struct GNUNET_HashCode *hash, const struct GNUNET_CRYPTO_RsaPublicKey *public_key); +/** + * Create a new random private key. + * + * @param[out] priv where to write the fresh private key + */ +void +GNUNET_CRYPTO_cs_private_key_generate (struct GNUNET_CRYPTO_CsPrivateKey *priv); + + +/** + * Extract the public key of the given private key. + * + * @param priv the private key + * @param[out] pub where to write the public key + */ +void +GNUNET_CRYPTO_cs_private_key_get_public (const struct + GNUNET_CRYPTO_CsPrivateKey *priv, + struct GNUNET_CRYPTO_CsPublicKey *pub); + + +/** + * Derive a new secret r pair r0 and r1. + * In original papers r is generated randomly + * To provide abort-idempotency, r needs to be derived but still needs to be UNPREDICTABLE + * To ensure unpredictability a new nonce should be used when a new r needs to be derived. + * Uses HKDF internally. + * Comment: Can be done in one HKDF shot and split output. + * + * @param nonce is a random nonce + * @param lts is a long-term-secret in form of a private key + * @param[out] r array containing derived secrets r0 and r1 + */ +void +GNUNET_CRYPTO_cs_r_derive (const struct GNUNET_CRYPTO_CsNonce *nonce, + const struct GNUNET_CRYPTO_CsPrivateKey *lts, + struct GNUNET_CRYPTO_CsRSecret r[2]); + + +/** + * Extract the public R of the given secret r. + * + * @param r_priv the private key + * @param[out] r_pub where to write the public key + */ +void +GNUNET_CRYPTO_cs_r_get_public (const struct GNUNET_CRYPTO_CsRSecret *r_priv, + struct GNUNET_CRYPTO_CsRPublic *r_pub); + + +/** + * Derives new random blinding factors. + * In original papers blinding factors are generated randomly + * To provide abort-idempotency, blinding factors need to be derived but still need to be UNPREDICTABLE + * To ensure unpredictability a new nonce has to be used. + * Uses HKDF internally + * + * @param secret is secret to derive blinding factors + * @param secret_len secret length + * @param[out] bs array containing the two derived blinding secrets + */ +void +GNUNET_CRYPTO_cs_blinding_secrets_derive (const void *secret, + size_t secret_len, + struct GNUNET_CRYPTO_CsBlindingSecret + bs[2]); + + +/** + * Calculate two blinded c's + * Comment: One would be insecure due to Wagner's algorithm solving ROS + * + * @param bs array of the two blinding factor structs each containing alpha and beta + * @param r_pub array of the two signer's nonce R + * @param pub the public key of the signer + * @param msg the message to blind in preparation for signing + * @param msg_len length of message msg + * @param[out] blinded_c array of the two blinded c's + * @param[out] blinded_r_pub array of the two blinded R + */ +void +GNUNET_CRYPTO_cs_calc_blinded_c (const struct GNUNET_CRYPTO_CsBlindingSecret + bs[2], + const struct GNUNET_CRYPTO_CsRPublic r_pub[2], + const struct GNUNET_CRYPTO_CsPublicKey *pub, + const void *msg, + size_t msg_len, + struct GNUNET_CRYPTO_CsC blinded_c[2], + struct GNUNET_CRYPTO_CsRPublic + blinded_r_pub[2]); + + +/** + * Sign a blinded c + * This function derives b from a nonce and a longterm secret + * In original papers b is generated randomly + * To provide abort-idempotency, b needs to be derived but still need to be UNPREDICTABLE. + * To ensure unpredictability a new nonce has to be used for every signature + * HKDF is used internally for derivation + * r0 and r1 can be derived prior by using GNUNET_CRYPTO_cs_r_derive + * + * @param priv private key to use for the signing and as LTS in HKDF + * @param r array of the two secret nonce from the signer + * @param c array of the two blinded c to sign c_b + * @param nonce is a random nonce + * @param[out] blinded_signature_scalar where to write the signature + * @return 0 or 1 for b (see Clause Blind Signature Scheme) + */ +unsigned int +GNUNET_CRYPTO_cs_sign_derive (const struct GNUNET_CRYPTO_CsPrivateKey *priv, + const struct GNUNET_CRYPTO_CsRSecret r[2], + const struct GNUNET_CRYPTO_CsC c[2], + const struct GNUNET_CRYPTO_CsNonce *nonce, + struct GNUNET_CRYPTO_CsBlindS * + blinded_signature_scalar + ); + + +/** + * Unblind a blind-signed signature using a c that was blinded + * + * @param blinded_signature_scalar the signature made on the blinded c + * @param bs the blinding factors used in the blinding + * @param[out] signature_scalar where to write the unblinded signature + */ +void +GNUNET_CRYPTO_cs_unblind (const struct + GNUNET_CRYPTO_CsBlindS *blinded_signature_scalar, + const struct GNUNET_CRYPTO_CsBlindingSecret *bs, + struct GNUNET_CRYPTO_CsS *signature_scalar); + + +/** + * Verify whether the given message corresponds to the given signature and the + * signature is valid with respect to the given public key. + * + * @param sig signature that is being validated + * @param pub public key of the signer + * @param msg is the message that should be signed by @a sig (message is used to calculate c) + * @param msg_len is the message length + * @returns #GNUNET_YES on success, #GNUNET_SYSERR if signature invalid + */ +enum GNUNET_GenericReturnValue +GNUNET_CRYPTO_cs_verify (const struct GNUNET_CRYPTO_CsSignature *sig, + const struct GNUNET_CRYPTO_CsPublicKey *pub, + const void *msg, + size_t msg_len); + + #if 0 /* keep Emacsens' auto-indent happy */ { #endif diff --git a/src/util/Makefile.am b/src/util/Makefile.am index d21ac5e86..771be1ee3 100644 --- a/src/util/Makefile.am +++ b/src/util/Makefile.am @@ -61,6 +61,7 @@ libgnunetutil_la_SOURCES = \ container_multihashmap32.c \ crypto_symmetric.c \ crypto_crc.c \ + crypto_cs.c \ crypto_ecc.c \ crypto_ecc_gnsrecord.c \ $(DLOG) \ diff --git a/src/util/crypto_cs.c b/src/util/crypto_cs.c new file mode 100644 index 000000000..5c441b669 --- /dev/null +++ b/src/util/crypto_cs.c @@ -0,0 +1,425 @@ +/* + This file is part of GNUnet + Copyright (C) 2014,2016,2019 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/crypto_cs.c + * @brief Clause Blind Schnorr signatures using Curve25519 + * @author Lucien Heuzeveldt + * @author Gian Demarmels + */ +#include "platform.h" +#include "gnunet_crypto_lib.h" +#include +#include + +/** + * IMPLEMENTATION NOTICE: + * + * This is an implementation of the Clause Blind Schnorr Signature Scheme using Curve25519. + * Further details about the Clause Blind Schnorr Signature Scheme can be found here: + * https://eprint.iacr.org/2019/877.pdf + * + * We use libsodium wherever possible. + */ + + +/** + * Create a new random private key. + * + * @param[out] priv where to write the fresh private key + */ +void +GNUNET_CRYPTO_cs_private_key_generate (struct GNUNET_CRYPTO_CsPrivateKey *priv) +{ + crypto_core_ed25519_scalar_random (priv->scalar.d); +} + + +/** + * Extract the public key of the given private key. + * + * @param priv the private key + * @param[out] pub where to write the public key + */ +void +GNUNET_CRYPTO_cs_private_key_get_public (const struct + GNUNET_CRYPTO_CsPrivateKey *priv, + struct GNUNET_CRYPTO_CsPublicKey *pub) +{ + GNUNET_assert (0 == crypto_scalarmult_ed25519_base_noclamp (pub->point.y, + priv->scalar.d)); +} + + +/** + * maps 32 random bytes to a scalar + * this is necessary because libsodium expects scalar to be in the prime order subgroup + * @param[out] scalar containing 32 byte char array, is modified to be in prime order subgroup + */ +static void +map_to_scalar_subgroup (struct GNUNET_CRYPTO_Cs25519Scalar *scalar) +{ + // perform clamping as described in RFC7748 + scalar->d[0] &= 248; + scalar->d[31] &= 127; + scalar->d[31] |= 64; +} + + +/** + * Derive a new secret r pair r0 and r1. + * In original papers r is generated randomly + * To provide abort-idempotency, r needs to be derived but still needs to be UNPREDICTABLE + * To ensure unpredictability a new nonce should be used when a new r needs to be derived. + * Uses HKDF internally. + * Comment: Can be done in one HKDF shot and split output. + * + * @param nonce is a random nonce + * @param lts is a long-term-secret in form of a private key + * @param[out] r array containing derived secrets r0 and r1 + */ +void +GNUNET_CRYPTO_cs_r_derive (const struct GNUNET_CRYPTO_CsNonce *nonce, + const struct GNUNET_CRYPTO_CsPrivateKey *lts, + struct GNUNET_CRYPTO_CsRSecret r[2]) +{ + GNUNET_assert (GNUNET_YES == + GNUNET_CRYPTO_hkdf (r, + sizeof (struct GNUNET_CRYPTO_CsRSecret) + * 2, + GCRY_MD_SHA512, + GCRY_MD_SHA256, + "r", + strlen ("r"), + lts, + sizeof (*lts), + nonce, + sizeof (*nonce), + NULL, + 0)); + + map_to_scalar_subgroup (&r[0].scalar); + map_to_scalar_subgroup (&r[1].scalar); +} + + +/** + * Extract the public R of the given secret r. + * + * @param r_priv the private key + * @param[out] r_pub where to write the public key + */ +void +GNUNET_CRYPTO_cs_r_get_public (const struct GNUNET_CRYPTO_CsRSecret *r_priv, + struct GNUNET_CRYPTO_CsRPublic *r_pub) +{ + GNUNET_assert (0 == crypto_scalarmult_ed25519_base_noclamp (r_pub->point.y, + r_priv->scalar.d)); +} + + +/** + * Derives new random blinding factors. + * In original papers blinding factors are generated randomly + * To provide abort-idempotency, blinding factors need to be derived but still need to be UNPREDICTABLE + * To ensure unpredictability a new nonce has to be used. + * Uses HKDF internally + * + * @param secret is secret to derive blinding factors + * @param secret_len secret length + * @param[out] bs array containing the two derived blinding secrets + */ +void +GNUNET_CRYPTO_cs_blinding_secrets_derive (const void *secret, + size_t secret_len, + struct GNUNET_CRYPTO_CsBlindingSecret + bs[2]) +{ + GNUNET_assert (GNUNET_YES == + GNUNET_CRYPTO_hkdf (bs, + sizeof (struct + GNUNET_CRYPTO_CsBlindingSecret) + * 2, + GCRY_MD_SHA512, + GCRY_MD_SHA256, + "alphabeta", + strlen ("alphabeta"), + secret, + secret_len, + NULL, + 0)); + map_to_scalar_subgroup (&bs[0].alpha); + map_to_scalar_subgroup (&bs[0].beta); + map_to_scalar_subgroup (&bs[1].alpha); + map_to_scalar_subgroup (&bs[1].beta); +} + + +/* +order of subgroup required for scalars by libsodium +2^252 + 27742317777372353535851937790883648493 +copied from https://github.com/jedisct1/libsodium/blob/master/src/libsodium/crypto_core/ed25519/ref10/ed25519_ref10.c +and converted to big endian +*/ +static const unsigned char L_BIG_ENDIAN[32] = { + 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0xde, 0xf9, 0xde, 0xa2, 0xf7, + 0x9c, 0xd6, 0x58, 0x12, 0x63, 0x1a, 0x5c, 0xf5, 0xd3, 0xed +}; + + +/** + * Computes a Hash of (R', m) mapped to a Curve25519 scalar + * + * @param hash initial hash of the message to be signed + * @param pub denomination public key (used as salt) + * @param[out] c C containing scalar + */ +static void +cs_full_domain_hash (const struct GNUNET_CRYPTO_CsRPublic *r_dash, + const void *msg, + size_t msg_len, + const struct GNUNET_CRYPTO_CsPublicKey *pub, + struct GNUNET_CRYPTO_CsC *c) +{ + // SHA-512 hash of R' and message + size_t r_m_concat_len = sizeof(struct GNUNET_CRYPTO_CsRPublic) + msg_len; + char r_m_concat[r_m_concat_len]; + memcpy (r_m_concat, r_dash, sizeof(struct GNUNET_CRYPTO_CsRPublic)); + memcpy (r_m_concat + sizeof(struct GNUNET_CRYPTO_CsRPublic), msg, msg_len); + struct GNUNET_HashCode prehash; + GNUNET_CRYPTO_hash (r_m_concat, r_m_concat_len, &prehash); + + // modulus converted to MPI representation + gcry_mpi_t l_mpi; + GNUNET_CRYPTO_mpi_scan_unsigned (&l_mpi, L_BIG_ENDIAN, sizeof(L_BIG_ENDIAN)); + + // calculate full domain hash + gcry_mpi_t c_mpi; + GNUNET_CRYPTO_kdf_mod_mpi (&c_mpi, + l_mpi, + pub, + sizeof(struct GNUNET_CRYPTO_CsPublicKey), + &prehash, + sizeof(struct GNUNET_HashCode), + "Curve25519FDH"); + gcry_mpi_release (l_mpi); + + // convert c from mpi + unsigned char c_big_endian[256 / 8]; + GNUNET_CRYPTO_mpi_print_unsigned (c_big_endian, sizeof(c_big_endian), c_mpi); + gcry_mpi_release (c_mpi); + for (size_t i = 0; i<32; i++) + c->scalar.d[i] = c_big_endian[31 - i]; +} + + +/** + * calculate R' + * + * @param bs blinding secret + * @param r_pub R + * @param pub public key + * @param[out] blinded_r_pub R' + */ +static void +calc_r_dash (const struct GNUNET_CRYPTO_CsBlindingSecret *bs, + const struct GNUNET_CRYPTO_CsRPublic *r_pub, + const struct GNUNET_CRYPTO_CsPublicKey *pub, + struct GNUNET_CRYPTO_CsRPublic *blinded_r_pub) +{ + // R'i = Ri + alpha i*G + beta i*pub + struct GNUNET_CRYPTO_Cs25519Point alpha_mul_base; + GNUNET_assert (0 == crypto_scalarmult_ed25519_base_noclamp ( + alpha_mul_base.y, + bs->alpha.d)); + struct GNUNET_CRYPTO_Cs25519Point beta_mul_pub; + GNUNET_assert (0 == crypto_scalarmult_ed25519_noclamp (beta_mul_pub.y, + bs->beta.d, + pub->point.y)); + struct GNUNET_CRYPTO_Cs25519Point alpha_mul_base_plus_beta_mul_pub; + GNUNET_assert (0 == crypto_core_ed25519_add ( + alpha_mul_base_plus_beta_mul_pub.y, + alpha_mul_base.y, + beta_mul_pub.y)); + GNUNET_assert (0 == crypto_core_ed25519_add (blinded_r_pub->point.y, + r_pub->point.y, + alpha_mul_base_plus_beta_mul_pub. + y)); +} + + +/** + * Calculate two blinded c's + * Comment: One would be insecure due to Wagner's algorithm solving ROS + * + * @param bs array of the two blinding factor structs each containing alpha and beta + * @param r_pub array of the two signer's nonce R + * @param pub the public key of the signer + * @param msg the message to blind in preparation for signing + * @param msg_len length of message msg + * @param[out] blinded_c array of the two blinded c's + * @param[out] blinded_r_pub array of the two blinded R + */ +void +GNUNET_CRYPTO_cs_calc_blinded_c (const struct GNUNET_CRYPTO_CsBlindingSecret + bs[2], + const struct GNUNET_CRYPTO_CsRPublic r_pub[2], + const struct GNUNET_CRYPTO_CsPublicKey *pub, + const void *msg, + size_t msg_len, + struct GNUNET_CRYPTO_CsC blinded_c[2], + struct GNUNET_CRYPTO_CsRPublic + blinded_r_pub[2]) +{ + // for i 0/1: R'i = Ri + alpha i*G + beta i*pub + calc_r_dash (&bs[0], &r_pub[0], pub, &blinded_r_pub[0]); + calc_r_dash (&bs[1], &r_pub[1], pub, &blinded_r_pub[1]); + + // for i 0/1: c'i = H(R'i, msg) + struct GNUNET_CRYPTO_CsC c_dash_0; + struct GNUNET_CRYPTO_CsC c_dash_1; + cs_full_domain_hash (&blinded_r_pub[0], msg, msg_len, pub, &c_dash_0); + cs_full_domain_hash (&blinded_r_pub[1], msg, msg_len, pub, &c_dash_1); + + // for i 0/1: ci = c'i + beta i mod p + crypto_core_ed25519_scalar_add (blinded_c[0].scalar.d, + c_dash_0.scalar.d, + bs[0].beta.d); + crypto_core_ed25519_scalar_add (blinded_c[1].scalar.d, + c_dash_1.scalar.d, + bs[1].beta.d); +} + + +/** + * Sign a blinded c + * This function derives b from a nonce and a longterm secret + * In original papers b is generated randomly + * To provide abort-idempotency, b needs to be derived but still need to be UNPREDICTABLE. + * To ensure unpredictability a new nonce has to be used for every signature + * HKDF is used internally for derivation + * r0 and r1 can be derived prior by using GNUNET_CRYPTO_cs_r_derive + * + * @param priv private key to use for the signing and as LTS in HKDF + * @param r array of the two secret nonce from the signer + * @param c array of the two blinded c to sign c_b + * @param nonce is a random nonce + * @param[out] blinded_signature_scalar where to write the signature + * @return 0 or 1 for b (see Clause Blind Signature Scheme) + */ +unsigned int +GNUNET_CRYPTO_cs_sign_derive (const struct GNUNET_CRYPTO_CsPrivateKey *priv, + const struct GNUNET_CRYPTO_CsRSecret r[2], + const struct GNUNET_CRYPTO_CsC c[2], + const struct GNUNET_CRYPTO_CsNonce *nonce, + struct GNUNET_CRYPTO_CsBlindS * + blinded_signature_scalar + ) +{ + uint32_t hkdf_out; + + // derive clause session identifier b (random bit) + GNUNET_assert (GNUNET_YES == + GNUNET_CRYPTO_hkdf (&hkdf_out, + sizeof (hkdf_out), + GCRY_MD_SHA512, + GCRY_MD_SHA256, + "b", + strlen ("b"), + priv, + sizeof (*priv), + nonce, + sizeof (*nonce), + NULL, + 0)); + unsigned int b = hkdf_out % 2; + + // s = r_b + c_b priv + struct GNUNET_CRYPTO_Cs25519Scalar c_b_mul_priv; + crypto_core_ed25519_scalar_mul (c_b_mul_priv.d, + c[b].scalar.d, + priv->scalar.d); + crypto_core_ed25519_scalar_add (blinded_signature_scalar->scalar.d, + r[b].scalar.d, + c_b_mul_priv.d); + + return b; +} + + +/** + * Unblind a blind-signed signature using a c that was blinded + * + * @param blinded_signature_scalar the signature made on the blinded c + * @param bs the blinding factors used in the blinding + * @param[out] signature_scalar where to write the unblinded signature + */ +void +GNUNET_CRYPTO_cs_unblind (const struct + GNUNET_CRYPTO_CsBlindS *blinded_signature_scalar, + const struct GNUNET_CRYPTO_CsBlindingSecret *bs, + struct GNUNET_CRYPTO_CsS *signature_scalar) +{ + crypto_core_ed25519_scalar_add (signature_scalar->scalar.d, + blinded_signature_scalar->scalar.d, + bs->alpha.d); +} + + +/** + * Verify whether the given message corresponds to the given signature and the + * signature is valid with respect to the given public key. + * + * @param sig signature that is being validated + * @param pub public key of the signer + * @param msg is the message that should be signed by @a sig (message is used to calculate c) + * @param msg_len is the message length + * @returns #GNUNET_YES on success, #GNUNET_SYSERR if signature invalid + */ +enum GNUNET_GenericReturnValue +GNUNET_CRYPTO_cs_verify (const struct GNUNET_CRYPTO_CsSignature *sig, + const struct GNUNET_CRYPTO_CsPublicKey *pub, + const void *msg, + size_t msg_len) +{ + // calculate c' = H(R, m) + struct GNUNET_CRYPTO_CsC c_dash; + cs_full_domain_hash (&sig->r_point, msg, msg_len, pub, &c_dash); + + // s'G ?= R' + c' pub + struct GNUNET_CRYPTO_Cs25519Point sig_scal_mul_base; + GNUNET_assert (0 == crypto_scalarmult_ed25519_base_noclamp ( + sig_scal_mul_base.y, + sig->s_scalar.scalar.d)); + struct GNUNET_CRYPTO_Cs25519Point c_dash_mul_pub; + GNUNET_assert (0 == crypto_scalarmult_ed25519_noclamp (c_dash_mul_pub.y, + c_dash.scalar.d, + pub->point.y)); + struct GNUNET_CRYPTO_Cs25519Point R_add_c_dash_mul_pub; + GNUNET_assert (0 == crypto_core_ed25519_add (R_add_c_dash_mul_pub.y, + sig->r_point.point.y, + c_dash_mul_pub.y)); + + return 0 == GNUNET_memcmp (&sig_scal_mul_base, + &R_add_c_dash_mul_pub) + ? GNUNET_OK + : GNUNET_SYSERR; +} -- cgit v1.2.3