age_restriction.c (21572B)
1 /* 2 This file is part of TALER 3 Copyright (C) 2022-2023 Taler Systems SA 4 5 TALER is free software; you can redistribute it and/or modify it under the 6 terms of the GNU General Public License as published by the Free Software 7 Foundation; either version 3, or (at your option) any later version. 8 9 TALER is distributed in the hope that it will be useful, but WITHOUT ANY 10 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR 11 A PARTICULAR PURPOSE. See the GNU General Public License for more details. 12 13 You should have received a copy of the GNU General Public License along with 14 TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/> 15 */ 16 /** 17 * @file util/age_restriction.c 18 * @brief Functions that are used for age restriction 19 * @author Özgür Kesim 20 */ 21 #include "platform.h" /* UNNECESSARY? */ 22 #include "taler/taler_util.h" 23 #include "taler/taler_signatures.h" 24 #include <gnunet/gnunet_json_lib.h> 25 #include <gcrypt.h> 26 #include <stdint.h> 27 28 struct 29 #ifndef AGE_RESTRICTION_WITH_ECDSA 30 GNUNET_CRYPTO_Edx25519PublicKey 31 #else 32 GNUNET_CRYPTO_EcdsaPublicKey 33 #endif 34 TALER_age_commitment_base_public_key = { 35 .q_y = { 0x64, 0x41, 0xb9, 0xbd, 0xbf, 0x14, 0x39, 0x8e, 36 0x46, 0xeb, 0x5c, 0x1d, 0x34, 0xd3, 0x9b, 0x2f, 37 0x9b, 0x7d, 0xc8, 0x18, 0xeb, 0x9c, 0x09, 0xfb, 38 0x43, 0xad, 0x16, 0x64, 0xbc, 0x18, 0x49, 0xb5}, 39 }; 40 41 void 42 TALER_age_commitment_hash ( 43 const struct TALER_AgeCommitment *commitment, 44 struct TALER_AgeCommitmentHashP *ahash) 45 { 46 struct GNUNET_HashContext *hash_context; 47 struct GNUNET_HashCode hash; 48 49 GNUNET_assert (NULL != ahash); 50 if (NULL == commitment) 51 { 52 memset (ahash, 0, sizeof(struct TALER_AgeCommitmentHashP)); 53 return; 54 } 55 56 GNUNET_assert (__builtin_popcount (commitment->mask.bits) - 1 == 57 (int) commitment->num); 58 59 hash_context = GNUNET_CRYPTO_hash_context_start (); 60 61 for (size_t i = 0; i < commitment->num; i++) 62 { 63 GNUNET_CRYPTO_hash_context_read (hash_context, 64 &commitment->pubs[i], 65 sizeof(commitment->pubs[i])); 66 } 67 68 GNUNET_CRYPTO_hash_context_finish (hash_context, 69 &hash); 70 GNUNET_memcpy (&ahash->shash.bits, 71 &hash.bits, 72 sizeof(ahash->shash.bits)); 73 } 74 75 76 uint8_t 77 TALER_get_age_group ( 78 const struct TALER_AgeMask *mask, 79 uint8_t age) 80 { 81 uint32_t m = mask->bits; 82 uint8_t i = 0; 83 84 while (m > 0) 85 { 86 if (0 >= age) 87 break; 88 m = m >> 1; 89 i += m & 1; 90 age--; 91 } 92 return i; 93 } 94 95 96 uint8_t 97 TALER_get_lowest_age ( 98 const struct TALER_AgeMask *mask, 99 uint8_t age) 100 { 101 uint32_t m = mask->bits; 102 uint8_t group = TALER_get_age_group (mask, age); 103 uint8_t lowest = 0; 104 105 while (group > 0) 106 { 107 m = m >> 1; 108 if (m & 1) 109 group--; 110 lowest++; 111 } 112 113 return lowest; 114 } 115 116 117 #ifdef AGE_RESTRICTION_WITH_ECDSA 118 /** 119 * @brief Helper function to generate a ECDSA private key 120 * 121 * @param seed Input seed 122 * @param size Size of the seed in bytes 123 * @param[out] pkey ECDSA private key 124 */ 125 static void 126 ecdsa_create_from_seed ( 127 const void *seed, 128 size_t seed_size, 129 struct GNUNET_CRYPTO_EcdsaPrivateKey *key) 130 { 131 enum GNUNET_GenericReturnValue ret; 132 133 GNUNET_assert ( 134 GNUNET_OK == 135 GNUNET_CRYPTO_hkdf_gnunet (key, 136 sizeof (*key), 137 "age commitment", 138 sizeof ("age commitment") - 1), 139 seed, 140 seed_size); 141 /* See GNUNET_CRYPTO_ecdsa_key_create */ 142 key->d[0] &= 248; 143 key->d[31] &= 127; 144 key->d[31] |= 64; 145 } 146 147 148 #endif 149 150 151 void 152 TALER_age_restriction_commit ( 153 const struct TALER_AgeMask *mask, 154 uint8_t age, 155 const struct GNUNET_HashCode *seed, 156 struct TALER_AgeCommitmentProof *ncp) 157 { 158 struct GNUNET_HashCode seed_i; 159 uint8_t num_pub; 160 uint8_t num_priv; 161 size_t i; 162 163 GNUNET_assert (NULL != mask); 164 GNUNET_assert (NULL != seed); 165 GNUNET_assert (NULL != ncp); 166 GNUNET_assert (mask->bits & 1); /* first bit must have been set */ 167 168 num_pub = __builtin_popcount (mask->bits) - 1; 169 num_priv = TALER_get_age_group (mask, age); 170 171 GNUNET_assert (31 > num_priv); 172 GNUNET_assert (num_priv <= num_pub); 173 174 seed_i = *seed; 175 ncp->commitment.mask.bits = mask->bits; 176 ncp->commitment.num = num_pub; 177 ncp->proof.num = num_priv; 178 ncp->proof.privs = NULL; 179 180 ncp->commitment.pubs = GNUNET_new_array ( 181 num_pub, 182 struct TALER_AgeCommitmentPublicKeyP); 183 184 if (0 < num_priv) 185 ncp->proof.privs = GNUNET_new_array ( 186 num_priv, 187 struct TALER_AgeCommitmentPrivateKeyP); 188 189 /* Create as many private keys as we need and fill the rest of the 190 * public keys with valid curve points. 191 * We need to make sure that the public keys are proper points on the 192 * elliptic curve, so we can't simply fill the struct with random values. */ 193 for (i = 0; i < num_pub; i++) 194 { 195 struct TALER_AgeCommitmentPrivateKeyP key = {0}; 196 struct TALER_AgeCommitmentPrivateKeyP *pkey = &key; 197 198 /* Only save the private keys for age groups less than num_priv */ 199 if (i < num_priv) 200 pkey = &ncp->proof.privs[i]; 201 202 #ifndef AGE_RESTRICTION_WITH_ECDSA 203 GNUNET_CRYPTO_edx25519_key_create_from_seed (&seed_i, 204 sizeof(seed_i), 205 &pkey->priv); 206 GNUNET_CRYPTO_edx25519_key_get_public (&pkey->priv, 207 &ncp->commitment.pubs[i].pub); 208 #else 209 ecdsa_create_from_seed (&seed_i, 210 sizeof(seed_i), 211 &pkey->priv); 212 GNUNET_CRYPTO_ecdsa_key_get_public (&pkey->priv, 213 &ncp->commitment.pubs[i].pub); 214 #endif 215 216 seed_i.bits[0] += 1; 217 } 218 } 219 220 221 enum GNUNET_GenericReturnValue 222 TALER_age_commitment_derive ( 223 const struct TALER_AgeCommitment *orig, 224 const struct GNUNET_HashCode *salt, 225 struct TALER_AgeCommitment *newac) 226 { 227 GNUNET_assert (NULL != newac); 228 GNUNET_assert (((int) orig->num) == 229 __builtin_popcount (orig->mask.bits) - 1); 230 231 newac->mask = orig->mask; 232 newac->num = orig->num; 233 newac->pubs = GNUNET_new_array ( 234 newac->num, 235 struct TALER_AgeCommitmentPublicKeyP); 236 237 #ifndef AGE_RESTRICTION_WITH_ECDSA 238 /* Derive the public keys */ 239 for (size_t i = 0; i < orig->num; i++) 240 { 241 GNUNET_CRYPTO_edx25519_public_key_derive ( 242 &orig->pubs[i].pub, 243 salt, 244 sizeof(*salt), 245 &newac->pubs[i].pub); 246 } 247 #else 248 { 249 const char *label = GNUNET_h2s (salt); 250 251 /* Derive the public keys */ 252 for (size_t i = 0; i < orig->num; i++) 253 { 254 GNUNET_CRYPTO_ecdsa_public_key_derive ( 255 &orig->pubs[i].pub, 256 label, 257 "age commitment derive", 258 &newac->pubs[i].pub); 259 } 260 } 261 #endif 262 263 return GNUNET_OK; 264 } 265 266 267 enum GNUNET_GenericReturnValue 268 TALER_age_commitment_derive_from_secret ( 269 const struct TALER_AgeCommitment *orig, 270 const struct TALER_PlanchetMasterSecretP *secret, 271 struct TALER_AgeCommitment *newac) 272 { 273 struct GNUNET_HashCode salt; 274 enum GNUNET_GenericReturnValue ret; 275 276 ret = GNUNET_CRYPTO_hkdf_gnunet (&salt, 277 sizeof (salt), 278 "age commitment", 279 strlen ("age commitment"), 280 secret, 281 sizeof(*secret)); 282 if (GNUNET_OK != ret) 283 { 284 GNUNET_break (0); 285 return ret; 286 } 287 288 return TALER_age_commitment_derive ( 289 orig, 290 &salt, 291 newac); 292 } 293 294 295 enum GNUNET_GenericReturnValue 296 TALER_age_commitment_proof_derive ( 297 const struct TALER_AgeCommitmentProof *orig, 298 const struct GNUNET_HashCode *salt, 299 struct TALER_AgeCommitmentProof *newacp) 300 { 301 enum GNUNET_GenericReturnValue ret; 302 GNUNET_assert (NULL != newacp); 303 GNUNET_assert (orig->proof.num <= 304 orig->commitment.num); 305 GNUNET_assert (((int) orig->commitment.num) == 306 __builtin_popcount (orig->commitment.mask.bits) - 1); 307 308 ret = TALER_age_commitment_derive ( 309 &orig->commitment, 310 salt, 311 &newacp->commitment); 312 if (GNUNET_OK != ret) 313 { 314 GNUNET_break (0); 315 return ret; 316 } 317 318 newacp->proof.num = orig->proof.num; 319 newacp->proof.privs = NULL; 320 if (0 != newacp->proof.num) 321 newacp->proof.privs = GNUNET_new_array ( 322 newacp->proof.num, 323 struct TALER_AgeCommitmentPrivateKeyP); 324 325 #ifndef AGE_RESTRICTION_WITH_ECDSA 326 /* Derive the private keys */ 327 for (size_t i = 0; i < orig->proof.num; i++) 328 { 329 GNUNET_CRYPTO_edx25519_private_key_derive ( 330 &orig->proof.privs[i].priv, 331 salt, 332 sizeof(*salt), 333 &newacp->proof.privs[i].priv); 334 } 335 #else 336 { 337 const char *label = GNUNET_h2s (salt); 338 339 /* Derive the private keys */ 340 for (size_t i = 0; i < orig->proof.num; i++) 341 { 342 struct GNUNET_CRYPTO_EcdsaPrivateKey *priv; 343 priv = GNUNET_CRYPTO_ecdsa_private_key_derive ( 344 &orig->proof.privs[i].priv, 345 label, 346 "age commitment derive"); 347 newacp->proof.privs[i].priv = *priv; 348 GNUNET_free (priv); 349 } 350 } 351 #endif 352 353 return GNUNET_OK; 354 } 355 356 357 enum GNUNET_GenericReturnValue 358 TALER_age_commitment_proof_derive_from_secret ( 359 const struct TALER_AgeCommitmentProof *orig, 360 const struct TALER_PlanchetMasterSecretP *secret, 361 struct TALER_AgeCommitmentProof *newacp) 362 { 363 struct GNUNET_HashCode salt; 364 enum GNUNET_GenericReturnValue ret; 365 366 ret = GNUNET_CRYPTO_hkdf_gnunet (&salt, 367 sizeof (salt), 368 "age commitment", 369 strlen ("age commitment"), 370 secret, 371 sizeof(*secret)); 372 if (GNUNET_OK != ret) 373 { 374 GNUNET_break (0); 375 return ret; 376 } 377 378 return TALER_age_commitment_proof_derive ( 379 orig, 380 &salt, 381 newacp); 382 } 383 384 385 GNUNET_NETWORK_STRUCT_BEGIN 386 387 /** 388 * Age group mask in network byte order. 389 */ 390 struct TALER_AgeMaskNBO 391 { 392 uint32_t bits_nbo; 393 }; 394 395 /** 396 * Used for attestation of a particular age 397 */ 398 struct TALER_AgeAttestationPPS 399 { 400 /** 401 * Purpose must be #TALER_SIGNATURE_WALLET_AGE_ATTESTATION. 402 * (no GNUNET_PACKED here because the struct is already packed) 403 */ 404 struct GNUNET_CRYPTO_SignaturePurpose purpose; 405 406 /** 407 * Age mask that defines the underlying age groups 408 */ 409 struct TALER_AgeMaskNBO mask GNUNET_PACKED; 410 411 /** 412 * The particular age that this attestation is for. 413 * We use uint32_t here for alignment. 414 */ 415 uint32_t age GNUNET_PACKED; 416 }; 417 418 GNUNET_NETWORK_STRUCT_END 419 420 421 enum GNUNET_GenericReturnValue 422 TALER_age_commitment_attest ( 423 const struct TALER_AgeCommitmentProof *cp, 424 uint8_t age, 425 struct TALER_AgeAttestationP *attest) 426 { 427 uint8_t group; 428 429 GNUNET_assert (NULL != attest); 430 GNUNET_assert (NULL != cp); 431 432 group = TALER_get_age_group (&cp->commitment.mask, 433 age); 434 435 GNUNET_assert (group < 32); 436 437 if (0 == group) 438 { 439 /* Age group 0 means: no attestation necessary. 440 * We set the signature to zero and communicate success. */ 441 memset (attest, 442 0, 443 sizeof(struct TALER_AgeAttestationP)); 444 return GNUNET_OK; 445 } 446 447 if (group > cp->proof.num) 448 return GNUNET_NO; 449 450 { 451 struct TALER_AgeAttestationPPS at = { 452 .purpose.size = htonl (sizeof(at)), 453 .purpose.purpose = htonl (TALER_SIGNATURE_WALLET_AGE_ATTESTATION), 454 .mask.bits_nbo = htonl (cp->commitment.mask.bits), 455 .age = htonl (age), 456 }; 457 458 #ifndef AGE_RESTRICTION_WITH_ECDSA 459 #define sign(a,b,c) GNUNET_CRYPTO_edx25519_sign (a,b,c) 460 #else 461 #define sign(a,b,c) GNUNET_CRYPTO_ecdsa_sign (a,b,c) 462 #endif 463 sign (&cp->proof.privs[group - 1].priv, 464 &at, 465 &attest->signature); 466 } 467 #undef sign 468 469 return GNUNET_OK; 470 } 471 472 473 enum GNUNET_GenericReturnValue 474 TALER_age_commitment_verify ( 475 const struct TALER_AgeCommitment *comm, 476 uint8_t age, 477 const struct TALER_AgeAttestationP *attest) 478 { 479 uint8_t group; 480 481 GNUNET_assert (NULL != attest); 482 GNUNET_assert (NULL != comm); 483 484 group = TALER_get_age_group (&comm->mask, 485 age); 486 487 GNUNET_assert (group < 32); 488 489 /* Age group 0 means: no attestation necessary. */ 490 if (0 == group) 491 return GNUNET_OK; 492 493 if (group > comm->num) 494 { 495 GNUNET_break_op (0); 496 return GNUNET_NO; 497 } 498 499 { 500 struct TALER_AgeAttestationPPS at = { 501 .purpose.size = htonl (sizeof(at)), 502 .purpose.purpose = htonl (TALER_SIGNATURE_WALLET_AGE_ATTESTATION), 503 .mask.bits_nbo = htonl (comm->mask.bits), 504 .age = htonl (age), 505 }; 506 507 #ifndef AGE_RESTRICTION_WITH_ECDSA 508 #define verify(a,b,c,d) GNUNET_CRYPTO_edx25519_verify ((a),(b),(c),(d)) 509 #else 510 #define verify(a,b,c,d) GNUNET_CRYPTO_ecdsa_verify ((a),(b),(c),(d)) 511 #endif 512 return verify (TALER_SIGNATURE_WALLET_AGE_ATTESTATION, 513 &at, 514 &attest->signature, 515 &comm->pubs[group - 1].pub); 516 } 517 #undef verify 518 } 519 520 521 void 522 TALER_age_commitment_free ( 523 struct TALER_AgeCommitment *commitment) 524 { 525 if (NULL == commitment) 526 return; 527 528 if (NULL != commitment->pubs) 529 { 530 GNUNET_free (commitment->pubs); 531 commitment->pubs = NULL; 532 } 533 } 534 535 536 void 537 TALER_age_proof_free ( 538 struct TALER_AgeProof *proof) 539 { 540 if (NULL == proof) 541 return; 542 543 if (NULL != proof->privs) 544 { 545 GNUNET_CRYPTO_zero_keys ( 546 proof->privs, 547 sizeof(*proof->privs) * proof->num); 548 549 GNUNET_free (proof->privs); 550 proof->privs = NULL; 551 } 552 } 553 554 555 void 556 TALER_age_commitment_proof_free ( 557 struct TALER_AgeCommitmentProof *acp) 558 { 559 if (NULL == acp) 560 return; 561 562 if (NULL != acp->proof.privs) 563 { 564 GNUNET_CRYPTO_zero_keys ( 565 acp->proof.privs, 566 sizeof(*acp->proof.privs) * acp->proof.num); 567 568 GNUNET_free (acp->proof.privs); 569 acp->proof.privs = NULL; 570 } 571 572 if (NULL != acp->commitment.pubs) 573 { 574 GNUNET_free (acp->commitment.pubs); 575 acp->commitment.pubs = NULL; 576 } 577 } 578 579 580 struct TALER_AgeCommitmentProof * 581 TALER_age_commitment_proof_duplicate ( 582 const struct TALER_AgeCommitmentProof *acp) 583 { 584 struct TALER_AgeCommitmentProof *nacp; 585 586 GNUNET_assert (NULL != acp); 587 GNUNET_assert (__builtin_popcount (acp->commitment.mask.bits) - 1 == 588 (int) acp->commitment.num); 589 590 nacp = GNUNET_new (struct TALER_AgeCommitmentProof); 591 592 TALER_age_commitment_proof_deep_copy (nacp, acp); 593 return nacp; 594 } 595 596 597 struct TALER_AgeCommitment * 598 TALER_age_commitment_duplicate ( 599 const struct TALER_AgeCommitment *ac) 600 { 601 struct TALER_AgeCommitment *nac; 602 603 GNUNET_assert (NULL != ac); 604 GNUNET_assert (__builtin_popcount (ac->mask.bits) - 1 == 605 (int) ac->num); 606 607 nac = GNUNET_new (struct TALER_AgeCommitment); 608 TALER_age_commitment_deep_copy (nac, ac); 609 return nac; 610 } 611 612 613 void 614 TALER_age_commitment_proof_deep_copy ( 615 struct TALER_AgeCommitmentProof *nacp, 616 const struct TALER_AgeCommitmentProof *acp) 617 { 618 GNUNET_assert (NULL != acp); 619 GNUNET_assert (__builtin_popcount (acp->commitment.mask.bits) - 1 == 620 (int) acp->commitment.num); 621 622 *nacp = *acp; 623 nacp->commitment.pubs = 624 GNUNET_new_array (acp->commitment.num, 625 struct TALER_AgeCommitmentPublicKeyP); 626 nacp->proof.privs = 627 GNUNET_new_array (acp->proof.num, 628 struct TALER_AgeCommitmentPrivateKeyP); 629 630 for (size_t i = 0; i < acp->commitment.num; i++) 631 nacp->commitment.pubs[i] = acp->commitment.pubs[i]; 632 633 for (size_t i = 0; i < acp->proof.num; i++) 634 nacp->proof.privs[i] = acp->proof.privs[i]; 635 } 636 637 638 void 639 TALER_age_commitment_deep_copy ( 640 struct TALER_AgeCommitment *nac, 641 const struct TALER_AgeCommitment *ac) 642 { 643 GNUNET_assert (NULL != ac); 644 GNUNET_assert (__builtin_popcount (ac->mask.bits) - 1 == 645 (int) ac->num); 646 647 *nac = *ac; 648 nac->pubs = 649 GNUNET_new_array (ac->num, 650 struct TALER_AgeCommitmentPublicKeyP); 651 652 for (size_t i = 0; i < ac->num; i++) 653 nac->pubs[i] = ac->pubs[i]; 654 655 } 656 657 658 enum GNUNET_GenericReturnValue 659 TALER_parse_age_group_string ( 660 const char *groups, 661 struct TALER_AgeMask *mask) 662 { 663 664 const char *pos = groups; 665 unsigned int prev = 0; 666 unsigned int val = 0; 667 char c; 668 669 /* reset mask */ 670 mask->bits = 0; 671 672 while (*pos) 673 { 674 c = *pos++; 675 if (':' == c) 676 { 677 if (prev >= val) 678 return GNUNET_SYSERR; 679 680 mask->bits |= 1 << val; 681 prev = val; 682 val = 0; 683 continue; 684 } 685 686 if ('0'>c || '9'<c) 687 return GNUNET_SYSERR; 688 689 val = 10 * val + c - '0'; 690 691 if (0>=val || 32<=val) 692 return GNUNET_SYSERR; 693 } 694 695 if (32<=val || prev>=val) 696 return GNUNET_SYSERR; 697 698 mask->bits |= (1 << val); 699 mask->bits |= 1; // mark zeroth group, too 700 701 return GNUNET_OK; 702 } 703 704 705 const char * 706 TALER_age_mask_to_string ( 707 const struct TALER_AgeMask *mask) 708 { 709 static char buf[256] = {0}; 710 uint32_t bits = mask->bits; 711 unsigned int n = 0; 712 char *pos = buf; 713 714 memset (buf, 0, sizeof(buf)); 715 716 while (bits != 0) 717 { 718 bits >>= 1; 719 n++; 720 if (0 == (bits & 1)) 721 { 722 continue; 723 } 724 725 if (n > 9) 726 { 727 *(pos++) = '0' + n / 10; 728 } 729 *(pos++) = '0' + n % 10; 730 731 if (0 != (bits >> 1)) 732 { 733 *(pos++) = ':'; 734 } 735 } 736 return buf; 737 } 738 739 740 void 741 TALER_age_restriction_from_secret ( 742 const struct TALER_PlanchetMasterSecretP *secret, 743 const struct TALER_AgeMask *mask, 744 const uint8_t max_age, 745 struct TALER_AgeCommitmentProof *ncp) 746 { 747 struct GNUNET_HashCode seed_i = {0}; 748 uint8_t num_pub; 749 uint8_t num_priv; 750 751 GNUNET_assert (NULL != mask); 752 GNUNET_assert (NULL != secret); 753 GNUNET_assert (NULL != ncp); 754 GNUNET_assert (mask->bits & 1); /* fist bit must have been set */ 755 756 num_pub = __builtin_popcount (mask->bits) - 1; 757 num_priv = TALER_get_age_group (mask, max_age); 758 759 GNUNET_assert (31 > num_priv); 760 GNUNET_assert (num_priv <= num_pub); 761 762 ncp->commitment.mask.bits = mask->bits; 763 ncp->commitment.num = num_pub; 764 ncp->proof.num = num_priv; 765 ncp->proof.privs = NULL; 766 ncp->commitment.pubs = GNUNET_new_array ( 767 num_pub, 768 struct TALER_AgeCommitmentPublicKeyP); 769 if (0 < num_priv) 770 ncp->proof.privs = GNUNET_new_array ( 771 num_priv, 772 struct TALER_AgeCommitmentPrivateKeyP); 773 774 /* Create as many private keys as allow with max_age and derive the 775 * corresponding public keys. The rest of the needed public keys are created 776 * by scalar multiplication with the TALER_age_commitment_base_public_key. */ 777 for (size_t i = 0; i < num_pub; i++) 778 { 779 enum GNUNET_GenericReturnValue ret; 780 const char *label = i < num_priv ? "age-commitment" : "age-factor"; 781 uint32_t ibe = htonl ((uint32_t) i); 782 783 ret = GNUNET_CRYPTO_hkdf_gnunet (&seed_i, sizeof(seed_i), 784 label, strlen (label), 785 secret, sizeof(*secret), 786 GNUNET_CRYPTO_kdf_arg_auto (&ibe)); 787 GNUNET_assert (GNUNET_OK == ret); 788 789 /* Only generate and save the private keys and public keys for age groups 790 * less than num_priv */ 791 if (i < num_priv) 792 { 793 struct TALER_AgeCommitmentPrivateKeyP *pkey = &ncp->proof.privs[i]; 794 795 #ifndef AGE_RESTRICTION_WITH_ECDSA 796 GNUNET_CRYPTO_edx25519_key_create_from_seed (&seed_i, 797 sizeof(seed_i), 798 &pkey->priv); 799 GNUNET_CRYPTO_edx25519_key_get_public (&pkey->priv, 800 &ncp->commitment.pubs[i].pub); 801 #else 802 ecdsa_create_from_seed (&seed_i, 803 sizeof(seed_i), 804 &pkey->priv); 805 GNUNET_CRYPTO_ecdsa_key_get_public (&pkey->priv, 806 &ncp->commitment.pubs[i].pub); 807 #endif 808 } 809 else 810 { 811 /* For all indices larger than num_priv, derive a public key from 812 * TALER_age_commitment_base_public_key by scalar multiplication */ 813 #ifndef AGE_RESTRICTION_WITH_ECDSA 814 GNUNET_CRYPTO_edx25519_public_key_derive ( 815 &TALER_age_commitment_base_public_key, 816 &seed_i, 817 sizeof(seed_i), 818 &ncp->commitment.pubs[i].pub); 819 #else 820 821 GNUNET_CRYPTO_ecdsa_public_key_derive ( 822 &TALER_age_commitment_base_public_key, 823 GNUNET_h2s (&seed_i), 824 "age withdraw", 825 &ncp->commitment.pubs[i].pub); 826 #endif 827 } 828 } 829 } 830 831 832 enum GNUNET_GenericReturnValue 833 TALER_parse_coarse_date ( 834 const char *in, 835 const struct TALER_AgeMask *mask, 836 uint32_t *out) 837 { 838 struct tm date = {0}; 839 struct tm limit = {0}; 840 time_t seconds; 841 842 if (NULL == in) 843 { 844 /* FIXME[oec]: correct behaviour? */ 845 *out = 0; 846 return GNUNET_OK; 847 } 848 849 GNUNET_assert (NULL !=mask); 850 GNUNET_assert (NULL !=out); 851 852 if (NULL == strptime (in, "%Y-%m-%d", &date)) 853 { 854 if (NULL == strptime (in, "%Y-%m-00", &date)) 855 if (NULL == strptime (in, "%Y-00-00", &date)) 856 return GNUNET_SYSERR; 857 /* turns out that the day is off by one in the last two cases */ 858 date.tm_mday += 1; 859 } 860 861 seconds = timegm (&date); 862 if (-1 == seconds) 863 return GNUNET_SYSERR; 864 865 /* calculate the limit date for the largest age group */ 866 { 867 time_t l = time (NULL); 868 localtime_r (&l, &limit); 869 } 870 limit.tm_year -= TALER_adult_age (mask); 871 GNUNET_assert (-1 != timegm (&limit)); 872 873 if ((limit.tm_year < date.tm_year) 874 || ((limit.tm_year == date.tm_year) 875 && (limit.tm_mon < date.tm_mon)) 876 || ((limit.tm_year == date.tm_year) 877 && (limit.tm_mon == date.tm_mon) 878 && (limit.tm_mday < date.tm_mday))) 879 *out = seconds / 60 / 60 / 24; 880 else 881 *out = 0; 882 883 return GNUNET_OK; 884 } 885 886 887 /* end util/age_restriction.c */