aboutsummaryrefslogtreecommitdiff
path: root/src/util/crypto_cs.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/util/crypto_cs.c')
-rw-r--r--src/util/crypto_cs.c343
1 files changed, 0 insertions, 343 deletions
diff --git a/src/util/crypto_cs.c b/src/util/crypto_cs.c
deleted file mode 100644
index 4c6648229..000000000
--- a/src/util/crypto_cs.c
+++ /dev/null
@@ -1,343 +0,0 @@
1/*
2 This file is part of GNUnet
3 Copyright (C) 2014,2016,2019 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20
21/**
22 * @file util/crypto_cs.c
23 * @brief Clause Blind Schnorr signatures using Curve25519
24 * @author Lucien Heuzeveldt <lucienclaude.heuzeveldt@students.bfh.ch>
25 * @author Gian Demarmels <gian@demarmels.org>
26 */
27#include "platform.h"
28#include "gnunet_crypto_lib.h"
29#include <sodium.h>
30#include <gcrypt.h>
31
32/**
33 * IMPLEMENTATION NOTICE:
34 *
35 * This is an implementation of the Clause Blind Schnorr Signature Scheme using Curve25519.
36 * Further details about the Clause Blind Schnorr Signature Scheme can be found here:
37 * https://eprint.iacr.org/2019/877.pdf
38 *
39 * We use libsodium wherever possible.
40 */
41
42
43void
44GNUNET_CRYPTO_cs_private_key_generate (struct GNUNET_CRYPTO_CsPrivateKey *priv)
45{
46 crypto_core_ed25519_scalar_random (priv->scalar.d);
47}
48
49
50void
51GNUNET_CRYPTO_cs_private_key_get_public (
52 const struct GNUNET_CRYPTO_CsPrivateKey *priv,
53 struct GNUNET_CRYPTO_CsPublicKey *pub)
54{
55 GNUNET_assert (0 == crypto_scalarmult_ed25519_base_noclamp (pub->point.y,
56 priv->scalar.d));
57}
58
59
60/**
61 * Maps 32 random bytes to a scalar. This is necessary because libsodium
62 * expects scalar to be in the prime order subgroup.
63 *
64 * @param[in,out] scalar containing 32 byte char array, is modified to be in prime order subgroup
65 */
66static void
67map_to_scalar_subgroup (struct GNUNET_CRYPTO_Cs25519Scalar *scalar)
68{
69 /* perform clamping as described in RFC7748 */
70 scalar->d[0] &= 248;
71 scalar->d[31] &= 127;
72 scalar->d[31] |= 64;
73}
74
75
76void
77GNUNET_CRYPTO_cs_r_derive (const struct GNUNET_CRYPTO_CsNonce *nonce,
78 const char *seed,
79 const struct GNUNET_CRYPTO_CsPrivateKey *lts,
80 struct GNUNET_CRYPTO_CsRSecret r[2])
81{
82 GNUNET_assert (
83 GNUNET_YES ==
84 GNUNET_CRYPTO_kdf (
85 r, sizeof (struct GNUNET_CRYPTO_CsRSecret) * 2,
86 seed, strlen (seed),
87 lts, sizeof (*lts),
88 nonce, sizeof (*nonce),
89 NULL, 0));
90 map_to_scalar_subgroup (&r[0].scalar);
91 map_to_scalar_subgroup (&r[1].scalar);
92}
93
94
95void
96GNUNET_CRYPTO_cs_r_get_public (const struct GNUNET_CRYPTO_CsRSecret *r_priv,
97 struct GNUNET_CRYPTO_CsRPublic *r_pub)
98{
99 GNUNET_assert (0 == crypto_scalarmult_ed25519_base_noclamp (r_pub->point.y,
100 r_priv->scalar.d));
101}
102
103
104void
105GNUNET_CRYPTO_cs_blinding_secrets_derive (
106 const struct GNUNET_CRYPTO_CsNonce *blind_seed,
107 struct GNUNET_CRYPTO_CsBlindingSecret bs[2])
108{
109 GNUNET_assert (
110 GNUNET_YES ==
111 GNUNET_CRYPTO_hkdf (bs,
112 sizeof (struct GNUNET_CRYPTO_CsBlindingSecret) * 2,
113 GCRY_MD_SHA512,
114 GCRY_MD_SHA256,
115 "alphabeta",
116 strlen ("alphabeta"),
117 blind_seed,
118 sizeof(*blind_seed),
119 NULL,
120 0));
121 map_to_scalar_subgroup (&bs[0].alpha);
122 map_to_scalar_subgroup (&bs[0].beta);
123 map_to_scalar_subgroup (&bs[1].alpha);
124 map_to_scalar_subgroup (&bs[1].beta);
125}
126
127
128/*
129order of subgroup required for scalars by libsodium
1302^252 + 27742317777372353535851937790883648493
131copied from https://github.com/jedisct1/libsodium/blob/master/src/libsodium/crypto_core/ed25519/ref10/ed25519_ref10.c
132and converted to big endian
133*/
134static const unsigned char L_BIG_ENDIAN[32] = {
135 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
136 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0xde, 0xf9, 0xde, 0xa2, 0xf7,
137 0x9c, 0xd6, 0x58, 0x12, 0x63, 0x1a, 0x5c, 0xf5, 0xd3, 0xed
138};
139
140
141/**
142 * Computes a Hash of (R', m) mapped to a Curve25519 scalar
143 *
144 * @param hash initial hash of the message to be signed
145 * @param pub denomination public key (used as salt)
146 * @param[out] c C containing scalar
147 */
148static void
149cs_full_domain_hash (const struct GNUNET_CRYPTO_CsRPublic *r_dash,
150 const void *msg,
151 size_t msg_len,
152 const struct GNUNET_CRYPTO_CsPublicKey *pub,
153 struct GNUNET_CRYPTO_CsC *c)
154{
155 // SHA-512 hash of R' and message
156 size_t r_m_concat_len = sizeof(struct GNUNET_CRYPTO_CsRPublic) + msg_len;
157 char r_m_concat[r_m_concat_len];
158 memcpy (r_m_concat, r_dash, sizeof(struct GNUNET_CRYPTO_CsRPublic));
159 memcpy (r_m_concat + sizeof(struct GNUNET_CRYPTO_CsRPublic), msg, msg_len);
160 struct GNUNET_HashCode prehash;
161
162 GNUNET_CRYPTO_hash (r_m_concat,
163 r_m_concat_len,
164 &prehash);
165
166 // modulus converted to MPI representation
167 gcry_mpi_t l_mpi;
168 GNUNET_CRYPTO_mpi_scan_unsigned (&l_mpi,
169 L_BIG_ENDIAN,
170 sizeof(L_BIG_ENDIAN));
171
172 // calculate full domain hash
173 gcry_mpi_t c_mpi;
174 GNUNET_CRYPTO_kdf_mod_mpi (&c_mpi,
175 l_mpi,
176 pub,
177 sizeof(struct GNUNET_CRYPTO_CsPublicKey),
178 &prehash,
179 sizeof(struct GNUNET_HashCode),
180 "Curve25519FDH");
181 gcry_mpi_release (l_mpi);
182
183 // convert c from mpi
184 unsigned char c_big_endian[256 / 8];
185 GNUNET_CRYPTO_mpi_print_unsigned (c_big_endian,
186 sizeof(c_big_endian),
187 c_mpi);
188 gcry_mpi_release (c_mpi);
189 for (size_t i = 0; i<32; i++)
190 c->scalar.d[i] = c_big_endian[31 - i];
191}
192
193
194/**
195 * calculate R'
196 *
197 * @param bs blinding secret
198 * @param r_pub R
199 * @param pub public key
200 * @param[out] blinded_r_pub R'
201 */
202static void
203calc_r_dash (const struct GNUNET_CRYPTO_CsBlindingSecret *bs,
204 const struct GNUNET_CRYPTO_CsRPublic *r_pub,
205 const struct GNUNET_CRYPTO_CsPublicKey *pub,
206 struct GNUNET_CRYPTO_CsRPublic *blinded_r_pub)
207{
208 // R'i = Ri + alpha i*G + beta i*pub
209 struct GNUNET_CRYPTO_Cs25519Point alpha_mul_base;
210 GNUNET_assert (0 == crypto_scalarmult_ed25519_base_noclamp (
211 alpha_mul_base.y,
212 bs->alpha.d));
213 struct GNUNET_CRYPTO_Cs25519Point beta_mul_pub;
214 GNUNET_assert (0 == crypto_scalarmult_ed25519_noclamp (beta_mul_pub.y,
215 bs->beta.d,
216 pub->point.y));
217 struct GNUNET_CRYPTO_Cs25519Point alpha_mul_base_plus_beta_mul_pub;
218 GNUNET_assert (0 == crypto_core_ed25519_add (
219 alpha_mul_base_plus_beta_mul_pub.y,
220 alpha_mul_base.y,
221 beta_mul_pub.y));
222 GNUNET_assert (0 == crypto_core_ed25519_add (blinded_r_pub->point.y,
223 r_pub->point.y,
224 alpha_mul_base_plus_beta_mul_pub.
225 y));
226}
227
228
229void
230GNUNET_CRYPTO_cs_calc_blinded_c (
231 const struct GNUNET_CRYPTO_CsBlindingSecret bs[2],
232 const struct GNUNET_CRYPTO_CsRPublic r_pub[2],
233 const struct GNUNET_CRYPTO_CsPublicKey *pub,
234 const void *msg,
235 size_t msg_len,
236 struct GNUNET_CRYPTO_CsC blinded_c[2],
237 struct GNUNET_CRYPTO_CsRPublic blinded_r_pub[2])
238{
239 // for i 0/1: R'i = Ri + alpha i*G + beta i*pub
240 calc_r_dash (&bs[0], &r_pub[0], pub, &blinded_r_pub[0]);
241 calc_r_dash (&bs[1], &r_pub[1], pub, &blinded_r_pub[1]);
242
243 // for i 0/1: c'i = H(R'i, msg)
244 struct GNUNET_CRYPTO_CsC c_dash_0;
245 struct GNUNET_CRYPTO_CsC c_dash_1;
246 cs_full_domain_hash (&blinded_r_pub[0], msg, msg_len, pub, &c_dash_0);
247 cs_full_domain_hash (&blinded_r_pub[1], msg, msg_len, pub, &c_dash_1);
248
249 // for i 0/1: ci = c'i + beta i mod p
250 crypto_core_ed25519_scalar_add (blinded_c[0].scalar.d,
251 c_dash_0.scalar.d,
252 bs[0].beta.d);
253 crypto_core_ed25519_scalar_add (blinded_c[1].scalar.d,
254 c_dash_1.scalar.d,
255 bs[1].beta.d);
256}
257
258
259unsigned int
260GNUNET_CRYPTO_cs_sign_derive (
261 const struct GNUNET_CRYPTO_CsPrivateKey *priv,
262 const struct GNUNET_CRYPTO_CsRSecret r[2],
263 const struct GNUNET_CRYPTO_CsC c[2],
264 const struct GNUNET_CRYPTO_CsNonce *nonce,
265 struct GNUNET_CRYPTO_CsBlindS *blinded_signature_scalar)
266{
267 uint32_t hkdf_out;
268
269 // derive clause session identifier b (random bit)
270 GNUNET_assert (GNUNET_YES ==
271 GNUNET_CRYPTO_hkdf (&hkdf_out,
272 sizeof (hkdf_out),
273 GCRY_MD_SHA512,
274 GCRY_MD_SHA256,
275 "b",
276 strlen ("b"),
277 priv,
278 sizeof (*priv),
279 nonce,
280 sizeof (*nonce),
281 NULL,
282 0));
283 unsigned int b = hkdf_out % 2;
284
285 // s = r_b + c_b priv
286 struct GNUNET_CRYPTO_Cs25519Scalar c_b_mul_priv;
287 crypto_core_ed25519_scalar_mul (c_b_mul_priv.d,
288 c[b].scalar.d,
289 priv->scalar.d);
290 crypto_core_ed25519_scalar_add (blinded_signature_scalar->scalar.d,
291 r[b].scalar.d,
292 c_b_mul_priv.d);
293
294 return b;
295}
296
297
298void
299GNUNET_CRYPTO_cs_unblind (
300 const struct GNUNET_CRYPTO_CsBlindS *blinded_signature_scalar,
301 const struct GNUNET_CRYPTO_CsBlindingSecret *bs,
302 struct GNUNET_CRYPTO_CsS *signature_scalar)
303{
304 crypto_core_ed25519_scalar_add (signature_scalar->scalar.d,
305 blinded_signature_scalar->scalar.d,
306 bs->alpha.d);
307}
308
309
310enum GNUNET_GenericReturnValue
311GNUNET_CRYPTO_cs_verify (const struct GNUNET_CRYPTO_CsSignature *sig,
312 const struct GNUNET_CRYPTO_CsPublicKey *pub,
313 const void *msg,
314 size_t msg_len)
315{
316 // calculate c' = H(R, m)
317 struct GNUNET_CRYPTO_CsC c_dash;
318
319 cs_full_domain_hash (&sig->r_point,
320 msg,
321 msg_len,
322 pub,
323 &c_dash);
324
325 // s'G ?= R' + c' pub
326 struct GNUNET_CRYPTO_Cs25519Point sig_scal_mul_base;
327 GNUNET_assert (0 == crypto_scalarmult_ed25519_base_noclamp (
328 sig_scal_mul_base.y,
329 sig->s_scalar.scalar.d));
330 struct GNUNET_CRYPTO_Cs25519Point c_dash_mul_pub;
331 GNUNET_assert (0 == crypto_scalarmult_ed25519_noclamp (c_dash_mul_pub.y,
332 c_dash.scalar.d,
333 pub->point.y));
334 struct GNUNET_CRYPTO_Cs25519Point R_add_c_dash_mul_pub;
335 GNUNET_assert (0 == crypto_core_ed25519_add (R_add_c_dash_mul_pub.y,
336 sig->r_point.point.y,
337 c_dash_mul_pub.y));
338
339 return 0 == GNUNET_memcmp (&sig_scal_mul_base,
340 &R_add_c_dash_mul_pub)
341 ? GNUNET_OK
342 : GNUNET_SYSERR;
343}