diff options
author | Özgür Kesim <oec-taler@kesim.org> | 2022-03-27 17:12:52 +0200 |
---|---|---|
committer | Özgür Kesim <oec-taler@kesim.org> | 2022-03-27 17:12:52 +0200 |
commit | ce38d1f6c9bd7857a1c3bc2094a0ee9752b86c32 (patch) | |
tree | 984ac3c3018e218acd74c5866a3df2169bfd0557 /src/include | |
parent | 1e4d6256731d69f1309ff8439569c65d2e1384a0 (diff) | |
download | gnunet-ce38d1f6c9bd7857a1c3bc2094a0ee9752b86c32.tar.gz gnunet-ce38d1f6c9bd7857a1c3bc2094a0ee9752b86c32.zip |
Edx25519 implemented
Edx25519 is a variant of EdDSA on curve25519 which allows for repeated
derivation of private and public keys, independently. The private keys
in Edx25519 initially correspond to the data after expansion and
clamping in EdDSA. However, this correspondence is lost after deriving
further keys from existing ones. The public keys and signature
verification are compatible with EdDSA.
The ability to repeatedly derive key material is used for example in the
context of age restriction in GNU Taler.
The scheme that has been implemented is as follows:
/* Private keys in Edx25519 are pairs (a, b) of 32 byte each.
* Initially they correspond to the result of the expansion
* and clamping in EdDSA.
*/
Edx25519_generate_private(seed) {
/* EdDSA expand and clamp */
dh := SHA-512(seed)
a := dh[0..31]
b := dh[32..64]
a[0] &= 0b11111000
a[31] &= 0b01111111
a[31] |= 0b01000000
return (a, b)
}
Edx25519_public_from_private(private) {
/* Public keys are the same as in EdDSA */
(a, _) := private
return [a] * G
}
Edx25519_blinding_factor(P, seed) {
/* This is a helper function used in the derivation of
* private/public keys from existing ones. */
h1 := HKDF_32(P, seed)
/* Ensure that h == h % L */
h := h1 % L
/* Optionally: Make sure that we don't create weak keys. */
P' := [h] * P
if !( (h!=1) && (h!=0) && (P'!=E) ) {
return Edx25519_blinding_factor(P, seed+1)
}
return h
}
Edx25519_derive_private(private, seed) {
/* This is based on the definition in
* GNUNET_CRYPTO_eddsa_private_key_derive. But it accepts
* and returns a private pair (a, b) and allows for iteration.
*/
(a, b) := private
P := Edx25519_public_key_from_private(private)
h := Edx25519_blinding_factor(P, seed)
/* Carefully calculate the new value for a */
a1 := a / 8;
a2 := (h * a1) % L
a' := (a2 * 8) % L
/* Update b as well, binding it to h.
This is an additional step compared to GNS. */
b' := SHA256(b ∥ h)
return (a', b')
}
Edx25519_derive_public(P, seed) {
h := Edx25519_blinding_factor(P, seed)
return [h]*P
}
Edx25519_sign(private, message) {
/* As in Ed25519, except for the origin of b */
(d, b) := private
P := Edx25519_public_from_private(private)
r := SHA-512(b ∥ message)
R := [r] * G
s := r + SHA-512(R ∥ P ∥ message) * d % L
return (R,s)
}
Edx25519_verify(P, message, signature) {
/* Identical to Ed25519 */
(R, s) := signature
return [s] * G == R + [SHA-512(R ∥ P ∥ message)] * P
}
Diffstat (limited to 'src/include')
-rw-r--r-- | src/include/gnunet_crypto_lib.h | 235 |
1 files changed, 233 insertions, 2 deletions
diff --git a/src/include/gnunet_crypto_lib.h b/src/include/gnunet_crypto_lib.h index 77abab45d..582a58861 100644 --- a/src/include/gnunet_crypto_lib.h +++ b/src/include/gnunet_crypto_lib.h | |||
@@ -287,6 +287,59 @@ struct GNUNET_CRYPTO_EddsaPrivateScalar | |||
287 | unsigned char s[512 / 8]; | 287 | unsigned char s[512 / 8]; |
288 | }; | 288 | }; |
289 | 289 | ||
290 | /** | ||
291 | * Private ECC key material encoded for transmission. To be used only for | ||
292 | * Edx25519 signatures. An inital key corresponds to data from the key | ||
293 | * expansion and clamping in the EdDSA key generation. | ||
294 | */ | ||
295 | struct GNUNET_CRYPTO_Edx25519PrivateKey | ||
296 | { | ||
297 | /** | ||
298 | * a is a value mod n, where n has at most 256 bits. It is the first half of | ||
299 | * the seed-expansion of EdDSA and will be clamped. | ||
300 | */ | ||
301 | unsigned char a[256 / 8]; | ||
302 | |||
303 | /** | ||
304 | * b consists of 32 bytes which where originally the lower 32bytes of the key | ||
305 | * expansion. Subsequent calls to derive_private will change this value, too. | ||
306 | */ | ||
307 | unsigned char b[256 / 8]; | ||
308 | }; | ||
309 | |||
310 | |||
311 | /** | ||
312 | * Public ECC key (always for curve Ed25519) encoded in a format suitable for | ||
313 | * network transmission and Edx25519 (same as EdDSA) signatures. Refer to | ||
314 | * section 5.1.3 of rfc8032, for a thorough explanation of how this value maps | ||
315 | * to the x- and y-coordinates. | ||
316 | */ | ||
317 | struct GNUNET_CRYPTO_Edx25519PublicKey | ||
318 | { | ||
319 | /** | ||
320 | * Point Q consists of a y-value mod p (256 bits); the x-value is | ||
321 | * always positive. The point is stored in Ed25519 standard | ||
322 | * compact format. | ||
323 | */ | ||
324 | unsigned char q_y[256 / 8]; | ||
325 | }; | ||
326 | |||
327 | /** | ||
328 | * @brief an ECC signature using Edx25519 (same as in EdDSA). | ||
329 | */ | ||
330 | struct GNUNET_CRYPTO_Edx25519Signature | ||
331 | { | ||
332 | /** | ||
333 | * R value. | ||
334 | */ | ||
335 | unsigned char r[256 / 8]; | ||
336 | |||
337 | /** | ||
338 | * S value. | ||
339 | */ | ||
340 | unsigned char s[256 / 8]; | ||
341 | }; | ||
342 | |||
290 | 343 | ||
291 | /** | 344 | /** |
292 | * @brief type for session keys | 345 | * @brief type for session keys |
@@ -1279,6 +1332,17 @@ GNUNET_CRYPTO_eddsa_key_get_public ( | |||
1279 | const struct GNUNET_CRYPTO_EddsaPrivateKey *priv, | 1332 | const struct GNUNET_CRYPTO_EddsaPrivateKey *priv, |
1280 | struct GNUNET_CRYPTO_EddsaPublicKey *pub); | 1333 | struct GNUNET_CRYPTO_EddsaPublicKey *pub); |
1281 | 1334 | ||
1335 | /** | ||
1336 | * @ingroup crypto | ||
1337 | * Extract the public key for the given private key. | ||
1338 | * | ||
1339 | * @param priv the private key | ||
1340 | * @param pub where to write the public key | ||
1341 | */ | ||
1342 | void | ||
1343 | GNUNET_CRYPTO_edx25519_key_get_public ( | ||
1344 | const struct GNUNET_CRYPTO_Edx25519PrivateKey *priv, | ||
1345 | struct GNUNET_CRYPTO_Edx25519PublicKey *pub); | ||
1282 | 1346 | ||
1283 | /** | 1347 | /** |
1284 | * @ingroup crypto | 1348 | * @ingroup crypto |
@@ -1465,6 +1529,30 @@ GNUNET_CRYPTO_eddsa_key_create (struct GNUNET_CRYPTO_EddsaPrivateKey *pk); | |||
1465 | 1529 | ||
1466 | /** | 1530 | /** |
1467 | * @ingroup crypto | 1531 | * @ingroup crypto |
1532 | * Create a new private key. | ||
1533 | * | ||
1534 | * @param[out] pk private key to initialize | ||
1535 | */ | ||
1536 | void | ||
1537 | GNUNET_CRYPTO_edx25519_key_create (struct GNUNET_CRYPTO_Edx25519PrivateKey *pk); | ||
1538 | |||
1539 | /** | ||
1540 | * @ingroup crypto | ||
1541 | * Create a new private key for Edx25519 from a given seed. After expanding | ||
1542 | * the seed, the first half of the key will be clamped according to EdDSA. | ||
1543 | * | ||
1544 | * @param seed seed input | ||
1545 | * @param seedsize size of the seed in bytes | ||
1546 | * @param[out] pk private key to initialize | ||
1547 | */ | ||
1548 | void | ||
1549 | GNUNET_CRYPTO_edx25519_key_create_from_seed ( | ||
1550 | const void *seed, | ||
1551 | size_t seedsize, | ||
1552 | struct GNUNET_CRYPTO_Edx25519PrivateKey *pk); | ||
1553 | |||
1554 | /** | ||
1555 | * @ingroup crypto | ||
1468 | * Create a new private key. Clear with #GNUNET_CRYPTO_ecdhe_key_clear(). | 1556 | * Create a new private key. Clear with #GNUNET_CRYPTO_ecdhe_key_clear(). |
1469 | * | 1557 | * |
1470 | * @param[out] pk set to fresh private key; | 1558 | * @param[out] pk set to fresh private key; |
@@ -1492,6 +1580,14 @@ GNUNET_CRYPTO_eddsa_key_clear (struct GNUNET_CRYPTO_EddsaPrivateKey *pk); | |||
1492 | void | 1580 | void |
1493 | GNUNET_CRYPTO_ecdsa_key_clear (struct GNUNET_CRYPTO_EcdsaPrivateKey *pk); | 1581 | GNUNET_CRYPTO_ecdsa_key_clear (struct GNUNET_CRYPTO_EcdsaPrivateKey *pk); |
1494 | 1582 | ||
1583 | /** | ||
1584 | * @ingroup crypto | ||
1585 | * Clear memory that was used to store a private key. | ||
1586 | * | ||
1587 | * @param pk location of the key | ||
1588 | */ | ||
1589 | void | ||
1590 | GNUNET_CRYPTO_edx25519_key_clear (struct GNUNET_CRYPTO_Edx25519PrivateKey *pk); | ||
1495 | 1591 | ||
1496 | /** | 1592 | /** |
1497 | * @ingroup crypto | 1593 | * @ingroup crypto |
@@ -1874,6 +1970,53 @@ GNUNET_CRYPTO_ecdsa_sign_ ( | |||
1874 | sig)); \ | 1970 | sig)); \ |
1875 | } while (0) | 1971 | } while (0) |
1876 | 1972 | ||
1973 | /** | ||
1974 | * @ingroup crypto | ||
1975 | * @brief Edx25519 sign a given block. | ||
1976 | * | ||
1977 | * The @a purpose data is the beginning of the data of which the signature is | ||
1978 | * to be created. The `size` field in @a purpose must correctly indicate the | ||
1979 | * number of bytes of the data structure, including its header. If possible, | ||
1980 | * use #GNUNET_CRYPTO_edx25519_sign() instead of this function (only if @a | ||
1981 | * validate is not fixed-size, you must use this function directly). | ||
1982 | * | ||
1983 | * @param priv private key to use for the signing | ||
1984 | * @param purpose what to sign (size, purpose) | ||
1985 | * @param[out] sig where to write the signature | ||
1986 | * @return #GNUNET_SYSERR on error, #GNUNET_OK on success | ||
1987 | */ | ||
1988 | enum GNUNET_GenericReturnValue | ||
1989 | GNUNET_CRYPTO_edx25519_sign_ ( | ||
1990 | const struct GNUNET_CRYPTO_Edx25519PrivateKey *priv, | ||
1991 | const struct GNUNET_CRYPTO_EccSignaturePurpose *purpose, | ||
1992 | struct GNUNET_CRYPTO_Edx25519Signature *sig); | ||
1993 | |||
1994 | |||
1995 | /** | ||
1996 | * @ingroup crypto | ||
1997 | * @brief Edx25519 sign a given block. The resulting signature is compatible | ||
1998 | * with EdDSA. | ||
1999 | * | ||
2000 | * The @a ps data must be a fixed-size struct for which the signature is to be | ||
2001 | * created. The `size` field in @a ps->purpose must correctly indicate the | ||
2002 | * number of bytes of the data structure, including its header. | ||
2003 | * | ||
2004 | * @param priv private key to use for the signing | ||
2005 | * @param ps packed struct with what to sign, MUST begin with a purpose | ||
2006 | * @param[out] sig where to write the signature | ||
2007 | */ | ||
2008 | #define GNUNET_CRYPTO_edx25519_sign(priv,ps,sig) do { \ | ||
2009 | /* check size is set correctly */ \ | ||
2010 | GNUNET_assert (ntohl ((ps)->purpose.size) == sizeof (*(ps))); \ | ||
2011 | /* check 'ps' begins with the purpose */ \ | ||
2012 | GNUNET_static_assert (((void*) (ps)) == \ | ||
2013 | ((void*) &(ps)->purpose)); \ | ||
2014 | GNUNET_assert (GNUNET_OK == \ | ||
2015 | GNUNET_CRYPTO_edx25519_sign_ (priv, \ | ||
2016 | &(ps)->purpose, \ | ||
2017 | sig)); \ | ||
2018 | } while (0) | ||
2019 | |||
1877 | 2020 | ||
1878 | /** | 2021 | /** |
1879 | * @ingroup crypto | 2022 | * @ingroup crypto |
@@ -1917,7 +2060,7 @@ GNUNET_CRYPTO_eddsa_verify_ ( | |||
1917 | */ | 2060 | */ |
1918 | #define GNUNET_CRYPTO_eddsa_verify(purp,ps,sig,pub) ({ \ | 2061 | #define GNUNET_CRYPTO_eddsa_verify(purp,ps,sig,pub) ({ \ |
1919 | /* check size is set correctly */ \ | 2062 | /* check size is set correctly */ \ |
1920 | GNUNET_assert (ntohl ((ps)->purpose.size) == sizeof (*(ps))); \ | 2063 | GNUNET_assert (ntohl ((ps)->purpose.size) == sizeof (*(ps))); \ |
1921 | /* check 'ps' begins with the purpose */ \ | 2064 | /* check 'ps' begins with the purpose */ \ |
1922 | GNUNET_static_assert (((void*) (ps)) == \ | 2065 | GNUNET_static_assert (((void*) (ps)) == \ |
1923 | ((void*) &(ps)->purpose)); \ | 2066 | ((void*) &(ps)->purpose)); \ |
@@ -1927,7 +2070,6 @@ GNUNET_CRYPTO_eddsa_verify_ ( | |||
1927 | pub); \ | 2070 | pub); \ |
1928 | }) | 2071 | }) |
1929 | 2072 | ||
1930 | |||
1931 | /** | 2073 | /** |
1932 | * @ingroup crypto | 2074 | * @ingroup crypto |
1933 | * @brief Verify ECDSA signature. | 2075 | * @brief Verify ECDSA signature. |
@@ -1982,6 +2124,58 @@ GNUNET_CRYPTO_ecdsa_verify_ ( | |||
1982 | 2124 | ||
1983 | /** | 2125 | /** |
1984 | * @ingroup crypto | 2126 | * @ingroup crypto |
2127 | * @brief Verify Edx25519 signature. | ||
2128 | * | ||
2129 | * The @a validate data is the beginning of the data of which the signature | ||
2130 | * is to be verified. The `size` field in @a validate must correctly indicate | ||
2131 | * the number of bytes of the data structure, including its header. If @a | ||
2132 | * purpose does not match the purpose given in @a validate (the latter must be | ||
2133 | * in big endian), signature verification fails. If possible, use | ||
2134 | * #GNUNET_CRYPTO_edx25519_verify() instead of this function (only if @a | ||
2135 | * validate is not fixed-size, you must use this function directly). | ||
2136 | * | ||
2137 | * @param purpose what is the purpose that the signature should have? | ||
2138 | * @param validate block to validate (size, purpose, data) | ||
2139 | * @param sig signature that is being validated | ||
2140 | * @param pub public key of the signer | ||
2141 | * @returns #GNUNET_OK if ok, #GNUNET_SYSERR if invalid | ||
2142 | */ | ||
2143 | enum GNUNET_GenericReturnValue | ||
2144 | GNUNET_CRYPTO_edx25519_verify_ ( | ||
2145 | uint32_t purpose, | ||
2146 | const struct GNUNET_CRYPTO_EccSignaturePurpose *validate, | ||
2147 | const struct GNUNET_CRYPTO_Edx25519Signature *sig, | ||
2148 | const struct GNUNET_CRYPTO_Edx25519PublicKey *pub); | ||
2149 | |||
2150 | |||
2151 | /** | ||
2152 | * @ingroup crypto | ||
2153 | * @brief Verify Edx25519 signature. | ||
2154 | * | ||
2155 | * The @a ps data must be a fixed-size struct for which the signature is to be | ||
2156 | * created. The `size` field in @a ps->purpose must correctly indicate the | ||
2157 | * number of bytes of the data structure, including its header. | ||
2158 | * | ||
2159 | * @param purp purpose of the signature, must match 'ps->purpose.purpose' | ||
2160 | * (except in host byte order) | ||
2161 | * @param priv private key to use for the signing | ||
2162 | * @param ps packed struct with what to sign, MUST begin with a purpose | ||
2163 | * @param sig where to write the signature | ||
2164 | */ | ||
2165 | #define GNUNET_CRYPTO_edx25519_verify(purp,ps,sig,pub) ({ \ | ||
2166 | /* check size is set correctly */ \ | ||
2167 | GNUNET_assert (ntohl ((ps)->purpose.size) == sizeof (*(ps))); \ | ||
2168 | /* check 'ps' begins with the purpose */ \ | ||
2169 | GNUNET_static_assert (((void*) (ps)) == \ | ||
2170 | ((void*) &(ps)->purpose)); \ | ||
2171 | GNUNET_CRYPTO_edx25519_verify_ (purp, \ | ||
2172 | &(ps)->purpose, \ | ||
2173 | sig, \ | ||
2174 | pub); \ | ||
2175 | }) | ||
2176 | |||
2177 | /** | ||
2178 | * @ingroup crypto | ||
1985 | * Derive a private key from a given private key and a label. | 2179 | * Derive a private key from a given private key and a label. |
1986 | * Essentially calculates a private key 'h = H(l,P) * d mod n' | 2180 | * Essentially calculates a private key 'h = H(l,P) * d mod n' |
1987 | * where n is the size of the ECC group and P is the public | 2181 | * where n is the size of the ECC group and P is the public |
@@ -2115,6 +2309,43 @@ GNUNET_CRYPTO_eddsa_key_get_public_from_scalar ( | |||
2115 | const struct GNUNET_CRYPTO_EddsaPrivateScalar *s, | 2309 | const struct GNUNET_CRYPTO_EddsaPrivateScalar *s, |
2116 | struct GNUNET_CRYPTO_EddsaPublicKey *pkey); | 2310 | struct GNUNET_CRYPTO_EddsaPublicKey *pkey); |
2117 | 2311 | ||
2312 | /** | ||
2313 | * @ingroup crypto | ||
2314 | * Derive a private scalar from a given private key and a label. | ||
2315 | * Essentially calculates a private key 'h = H(l,P) * d mod n' | ||
2316 | * where n is the size of the ECC group and P is the public | ||
2317 | * key associated with the private key 'd'. | ||
2318 | * | ||
2319 | * @param priv original private key | ||
2320 | * @param seed input seed | ||
2321 | * @param seedsize size of the seed | ||
2322 | * @param result derived private key | ||
2323 | */ | ||
2324 | void | ||
2325 | GNUNET_CRYPTO_edx25519_private_key_derive ( | ||
2326 | const struct GNUNET_CRYPTO_Edx25519PrivateKey *priv, | ||
2327 | const void *seed, | ||
2328 | size_t seedsize, | ||
2329 | struct GNUNET_CRYPTO_Edx25519PrivateKey *result); | ||
2330 | |||
2331 | |||
2332 | /** | ||
2333 | * @ingroup crypto | ||
2334 | * Derive a public key from a given public key and a label. | ||
2335 | * Essentially calculates a public key 'V = H(l,P) * P'. | ||
2336 | * | ||
2337 | * @param pub original public key | ||
2338 | * @param seed input seed | ||
2339 | * @param seedsize size of the seed | ||
2340 | * @param result where to write the derived public key | ||
2341 | */ | ||
2342 | void | ||
2343 | GNUNET_CRYPTO_edx25519_public_key_derive ( | ||
2344 | const struct GNUNET_CRYPTO_Edx25519PublicKey *pub, | ||
2345 | const void *seed, | ||
2346 | size_t seedsize, | ||
2347 | struct GNUNET_CRYPTO_Edx25519PublicKey *result); | ||
2348 | |||
2118 | 2349 | ||
2119 | /** | 2350 | /** |
2120 | * Output the given MPI value to the given buffer in network | 2351 | * Output the given MPI value to the given buffer in network |