aboutsummaryrefslogtreecommitdiff
path: root/src/util/crypto_edx25519.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/util/crypto_edx25519.c')
-rw-r--r--src/util/crypto_edx25519.c354
1 files changed, 0 insertions, 354 deletions
diff --git a/src/util/crypto_edx25519.c b/src/util/crypto_edx25519.c
deleted file mode 100644
index e43c1685b..000000000
--- a/src/util/crypto_edx25519.c
+++ /dev/null
@@ -1,354 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2022 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_edx25519.c
23 * @brief An variant of EdDSA which allows for iterative derivation of key pairs.
24 * @author Özgür Kesim
25 * @author Christian Grothoff
26 * @author Florian Dold
27 * @author Martin Schanzenbach
28 */
29#include "platform.h"
30#include <gcrypt.h>
31#include <sodium.h>
32#include "gnunet_crypto_lib.h"
33#include "gnunet_strings_lib.h"
34
35#define CURVE "Ed25519"
36
37void
38GNUNET_CRYPTO_edx25519_key_clear (struct GNUNET_CRYPTO_Edx25519PrivateKey *pk)
39{
40 memset (pk, 0, sizeof(struct GNUNET_CRYPTO_Edx25519PrivateKey));
41}
42
43
44void
45GNUNET_CRYPTO_edx25519_key_create_from_seed (
46 const void *seed,
47 size_t seedsize,
48 struct GNUNET_CRYPTO_Edx25519PrivateKey *pk)
49{
50
51 GNUNET_static_assert (sizeof(*pk) == sizeof(struct GNUNET_HashCode));
52 GNUNET_CRYPTO_hash (seed,
53 seedsize,
54 (struct GNUNET_HashCode *) pk);
55
56 /* Clamp the first half of the key. The second half is used in the signature
57 * process. */
58 pk->a[0] &= 248;
59 pk->a[31] &= 127;
60 pk->a[31] |= 64;
61}
62
63
64void
65GNUNET_CRYPTO_edx25519_key_create (
66 struct GNUNET_CRYPTO_Edx25519PrivateKey *pk)
67{
68 char seed[256 / 8];
69 GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE,
70 seed,
71 sizeof (seed));
72 GNUNET_CRYPTO_edx25519_key_create_from_seed (seed,
73 sizeof(seed),
74 pk);
75}
76
77
78void
79GNUNET_CRYPTO_edx25519_key_get_public (
80 const struct GNUNET_CRYPTO_Edx25519PrivateKey *priv,
81 struct GNUNET_CRYPTO_Edx25519PublicKey *pub)
82{
83 crypto_scalarmult_ed25519_base_noclamp (pub->q_y,
84 priv->a);
85}
86
87
88/**
89 * This function operates the basically same way as the signature function for
90 * EdDSA. But instead of expanding a private seed (which is usually the case
91 * for crypto APIs) and using the resulting scalars, it takes the scalars
92 * directly from Edx25519PrivateKey. We require this functionality in order to
93 * use derived private keys for signatures.
94 *
95 * The resulting signature is a standard EdDSA signature
96 * which can be verified using the usual APIs.
97 *
98 * @param priv the private key (containing two scalars .a and .b)
99 * @param purp the signature purpose
100 * @param sig the resulting signature
101 */
102enum GNUNET_GenericReturnValue
103GNUNET_CRYPTO_edx25519_sign_ (
104 const struct GNUNET_CRYPTO_Edx25519PrivateKey *priv,
105 const struct GNUNET_CRYPTO_EccSignaturePurpose *purpose,
106 struct GNUNET_CRYPTO_Edx25519Signature *sig)
107{
108
109 crypto_hash_sha512_state hs;
110 unsigned char r[64];
111 unsigned char hram[64];
112 unsigned char P[32];
113 unsigned char r_mod[64];
114 unsigned char R[32];
115 unsigned char tmp[32];
116
117 crypto_hash_sha512_init (&hs);
118
119 /**
120 * Calculate the public key P from the private scalar in the key.
121 */
122 crypto_scalarmult_ed25519_base_noclamp (P,
123 priv->a);
124
125 /**
126 * Calculate r:
127 * r = SHA512 (b ∥ M)
128 * where M is our message (purpose).
129 */
130 crypto_hash_sha512_update (&hs,
131 priv->b,
132 sizeof(priv->b));
133 crypto_hash_sha512_update (&hs,
134 (uint8_t*) purpose,
135 ntohl (purpose->size));
136 crypto_hash_sha512_final (&hs,
137 r);
138
139 /**
140 * Temporarily put P into S
141 */
142 memcpy (sig->s, P, 32);
143
144 /**
145 * Reduce the scalar value r
146 */
147 crypto_core_ed25519_scalar_reduce (r_mod, r);
148
149 /**
150 * Calculate R := r * G of the signature
151 */
152 crypto_scalarmult_ed25519_base_noclamp (R, r_mod);
153 memcpy (sig->r, R, sizeof (R));
154
155 /**
156 * Calculate
157 * hram := SHA512 (R ∥ P ∥ M)
158 */
159 crypto_hash_sha512_init (&hs);
160 crypto_hash_sha512_update (&hs, (uint8_t*) sig, 64);
161 crypto_hash_sha512_update (&hs, (uint8_t*) purpose,
162 ntohl (purpose->size));
163 crypto_hash_sha512_final (&hs, hram);
164
165 /**
166 * Reduce the resulting scalar value
167 */
168 unsigned char hram_mod[64];
169 crypto_core_ed25519_scalar_reduce (hram_mod, hram);
170
171 /**
172 * Calculate
173 * S := r + hram * s mod L
174 */
175 crypto_core_ed25519_scalar_mul (tmp, hram_mod, priv->a);
176 crypto_core_ed25519_scalar_add (sig->s, tmp, r_mod);
177
178 sodium_memzero (r, sizeof (r));
179 sodium_memzero (r_mod, sizeof (r_mod));
180
181 return GNUNET_OK;
182}
183
184
185enum GNUNET_GenericReturnValue
186GNUNET_CRYPTO_edx25519_verify_ (
187 uint32_t purpose,
188 const struct GNUNET_CRYPTO_EccSignaturePurpose *validate,
189 const struct GNUNET_CRYPTO_Edx25519Signature *sig,
190 const struct GNUNET_CRYPTO_Edx25519PublicKey *pub)
191{
192 const unsigned char *m = (const void *) validate;
193 size_t mlen = ntohl (validate->size);
194 const unsigned char *s = (const void *) sig;
195
196 int res;
197
198 if (purpose != ntohl (validate->purpose))
199 return GNUNET_SYSERR; /* purpose mismatch */
200
201 res = crypto_sign_verify_detached (s, m, mlen, pub->q_y);
202 return (res == 0) ? GNUNET_OK : GNUNET_SYSERR;
203}
204
205
206/**
207 * Derive the 'h' value for key derivation, where
208 * 'h = H(P ∥ seed) mod n' and 'n' is the size of the cyclic subroup.
209 *
210 * @param pub public key for deriviation
211 * @param seed seed for key the deriviation
212 * @param seedsize the size of the seed
213 * @param[out] phc if not NULL, the output of H() will be written into
214 * return h_mod_n (allocated by this function)
215 */
216static void
217derive_h (
218 const struct GNUNET_CRYPTO_Edx25519PublicKey *pub,
219 const void *seed,
220 size_t seedsize,
221 struct GNUNET_HashCode *phc)
222{
223 static const char *const salt = "edx25519-derivation";
224
225 GNUNET_CRYPTO_kdf (/* output*/
226 phc, sizeof(*phc),
227 /* salt */
228 seed, seedsize,
229 /* ikm */
230 pub, sizeof(*pub),
231 /* ctx chunks*/
232 salt, strlen (salt),
233 NULL, 0);
234
235}
236
237
238void
239GNUNET_CRYPTO_edx25519_private_key_derive (
240 const struct GNUNET_CRYPTO_Edx25519PrivateKey *priv,
241 const void *seed,
242 size_t seedsize,
243 struct GNUNET_CRYPTO_Edx25519PrivateKey *result)
244{
245 struct GNUNET_CRYPTO_Edx25519PublicKey pub;
246 struct GNUNET_HashCode hc;
247 uint8_t a[32];
248 uint8_t eight[32] = { 8 };
249 uint8_t eight_inv[32];
250 uint8_t h[64] = { 0 };
251
252 GNUNET_CRYPTO_edx25519_key_get_public (priv, &pub);
253
254 /* Get h mod n */
255 derive_h (&pub,
256 seed,
257 seedsize,
258 &hc);
259
260 memcpy (h, &hc, 64);
261 crypto_core_ed25519_scalar_reduce (h,
262 h);
263#ifdef CHECK_RARE_CASES
264 /**
265 * Note that the following cases would be problematic:
266 * 1.) h == 0 mod n
267 * 2.) h == 1 mod n
268 * 3.) [h] * P == E
269 * We assume that the probalities for these cases to occur are neglegible.
270 */
271 {
272 char zero[32] = { 0 };
273 char one[32] = { 1 };
274
275 GNUNET_assert (0 != memcmp (zero, h, 32));
276 GNUNET_assert (0 != memcmp (one, h, 32));
277 }
278#endif
279
280 /**
281 * dc now contains the private scalar "a".
282 * We carefully remove the clamping and derive a'.
283 * Calculate:
284 * a1 := a / 8
285 * a2 := h * a1 mod n
286 * a' := a2 * 8 mod n
287 */
288
289 GNUNET_assert (0 == crypto_core_ed25519_scalar_invert (eight_inv,
290 eight));
291
292 crypto_core_ed25519_scalar_mul (a, priv->a, eight_inv);
293 crypto_core_ed25519_scalar_mul (a, a, h);
294 crypto_core_ed25519_scalar_mul (a, a, eight);
295
296#ifdef CHECK_RARE_CASES
297 /* The likelihood for a' == 0 or a' == 1 is neglegible */
298 {
299 char zero[32] = { 0 };
300 char one[32] = { 1 };
301
302 GNUNET_assert (0 != memcmp (zero, a, 32));
303 GNUNET_assert (0 != memcmp (one, a, 32));
304 }
305#endif
306
307 /* We hash the derived "h" parameter with the other half of the expanded
308 * private key (that is: priv->b). This ensures that for signature
309 * generation, the "R" is derived from the same derivation path as "h" and is
310 * not reused. */
311 {
312 struct GNUNET_HashCode hcb;
313 struct GNUNET_HashContext *hctx;
314
315 hctx = GNUNET_CRYPTO_hash_context_start ();
316 GNUNET_CRYPTO_hash_context_read (hctx, priv->b, sizeof(priv->b));
317 GNUNET_CRYPTO_hash_context_read (hctx, (unsigned char*) &hc, sizeof (hc));
318 GNUNET_CRYPTO_hash_context_finish (hctx, &hcb);
319
320 /* Truncate result, effectively doing SHA512/256 */
321 for (size_t i = 0; i < 32; i++)
322 result->b[i] = ((unsigned char *) &hcb)[i];
323 }
324
325 for (size_t i = 0; i < 32; i++)
326 result->a[i] = a[i];
327
328 sodium_memzero (a, sizeof(a));
329}
330
331
332void
333GNUNET_CRYPTO_edx25519_public_key_derive (
334 const struct GNUNET_CRYPTO_Edx25519PublicKey *pub,
335 const void *seed,
336 size_t seedsize,
337 struct GNUNET_CRYPTO_Edx25519PublicKey *result)
338{
339 struct GNUNET_HashCode hc;
340 uint8_t h[64] = { 0 };
341
342 derive_h (pub,
343 seed,
344 seedsize,
345 &hc);
346 memcpy (h,
347 &hc,
348 64);
349 crypto_core_ed25519_scalar_reduce (h,
350 h);
351 GNUNET_assert (0 == crypto_scalarmult_ed25519_noclamp (result->q_y,
352 h,
353 pub->q_y));
354}