[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[gnunet] 01/02: add crypto_cs implementation
From: |
gnunet |
Subject: |
[gnunet] 01/02: add crypto_cs implementation |
Date: |
Tue, 07 Dec 2021 20:48:39 +0100 |
This is an automated email from the git hooks/post-receive script.
lucien-heuzeveldt pushed a commit to branch master
in repository gnunet.
commit 2bcdfc2f958f5fd2512103c2240f1c24c07524d7
Author: Lucien Heuzeveldt <lucienclaude.heuzeveldt@students.bfh.ch>
AuthorDate: Mon Dec 6 22:13:35 2021 +0100
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(+)
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 <http://www.gnu.org/licenses/>.
+
+ SPDX-License-Identifier: AGPL3.0-or-later
+ */
+
+/**
+ * @file util/crypto_cs.c
+ * @brief Clause Blind Schnorr signatures using Curve25519
+ * @author Lucien Heuzeveldt <lucienclaude.heuzeveldt@students.bfh.ch>
+ * @author Gian Demarmels <gian@demarmels.org>
+ */
+#include "platform.h"
+#include "gnunet_crypto_lib.h"
+#include <sodium.h>
+#include <gcrypt.h>
+
+/**
+ * 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;
+}
--
To stop receiving notification emails like this one, please contact
gnunet@gnunet.org.