diff options
author | Florian Dold <florian.dold@gmail.com> | 2014-02-11 00:09:53 +0000 |
---|---|---|
committer | Florian Dold <florian.dold@gmail.com> | 2014-02-11 00:09:53 +0000 |
commit | 3e6c5eb76deedb76715e68e215622bcdd4eba3bf (patch) | |
tree | 6547309ea76a9daadfbedc04a0147b87340470d7 /src | |
parent | 48177fb73301df925712f5237ca71bb0a5088152 (diff) | |
download | gnunet-3e6c5eb76deedb76715e68e215622bcdd4eba3bf.tar.gz gnunet-3e6c5eb76deedb76715e68e215622bcdd4eba3bf.zip |
- fixed wrong crypto in secretsharing
- added zero knowledge proofs (except the one for fair encryption) and other verifications
Diffstat (limited to 'src')
-rw-r--r-- | src/secretsharing/gnunet-service-secretsharing.c | 417 | ||||
-rw-r--r-- | src/secretsharing/secretsharing.h | 9 | ||||
-rw-r--r-- | src/secretsharing/secretsharing_common.c | 6 | ||||
-rw-r--r-- | src/secretsharing/test_secretsharing.conf | 2 |
4 files changed, 370 insertions, 64 deletions
diff --git a/src/secretsharing/gnunet-service-secretsharing.c b/src/secretsharing/gnunet-service-secretsharing.c index b29433824..435c10b2b 100644 --- a/src/secretsharing/gnunet-service-secretsharing.c +++ b/src/secretsharing/gnunet-service-secretsharing.c | |||
@@ -58,15 +58,15 @@ struct KeygenPeerInfo | |||
58 | gcry_mpi_t presecret_commitment; | 58 | gcry_mpi_t presecret_commitment; |
59 | 59 | ||
60 | /** | 60 | /** |
61 | * The peer's preshare that we decrypted | 61 | * Commitment to the preshare that is |
62 | * with out private key. | 62 | * intended for our peer. |
63 | */ | 63 | */ |
64 | gcry_mpi_t decrypted_preshare; | 64 | gcry_mpi_t preshare_commitment; |
65 | 65 | ||
66 | /** | 66 | /** |
67 | * Multiplicative share of the public key. | 67 | * Sigma (exponentiated share) for this peer. |
68 | */ | 68 | */ |
69 | gcry_mpi_t public_key_share; | 69 | gcry_mpi_t sigma; |
70 | 70 | ||
71 | /** | 71 | /** |
72 | * Did we successfully receive the round1 element | 72 | * Did we successfully receive the round1 element |
@@ -204,6 +204,17 @@ struct KeygenSession | |||
204 | * of peers in the session. | 204 | * of peers in the session. |
205 | */ | 205 | */ |
206 | unsigned int local_peer_idx; | 206 | unsigned int local_peer_idx; |
207 | |||
208 | /** | ||
209 | * Share of our peer. Once preshares from other peers are received, they | ||
210 | * will be added to 'my'share. | ||
211 | */ | ||
212 | gcry_mpi_t my_share; | ||
213 | |||
214 | /** | ||
215 | * Public key, will be updated when a round2 element arrives. | ||
216 | */ | ||
217 | gcry_mpi_t public_key; | ||
207 | }; | 218 | }; |
208 | 219 | ||
209 | 220 | ||
@@ -593,6 +604,7 @@ cleanup_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) | |||
593 | } | 604 | } |
594 | 605 | ||
595 | 606 | ||
607 | |||
596 | /** | 608 | /** |
597 | * Generate the random coefficients of our pre-secret polynomial | 609 | * Generate the random coefficients of our pre-secret polynomial |
598 | * | 610 | * |
@@ -679,8 +691,7 @@ keygen_round1_new_element (void *cls, | |||
679 | return; | 691 | return; |
680 | } | 692 | } |
681 | info->paillier_public_key = d->pubkey; | 693 | info->paillier_public_key = d->pubkey; |
682 | // FIXME: does not make any sense / is wrong | 694 | GNUNET_CRYPTO_mpi_scan_unsigned (&info->presecret_commitment, &d->commitment, 512 / 8); |
683 | GNUNET_CRYPTO_mpi_scan_unsigned (&info->presecret_commitment, &d->pubkey.n, GNUNET_CRYPTO_PAILLIER_BITS / 8); | ||
684 | info->round1_valid = GNUNET_YES; | 695 | info->round1_valid = GNUNET_YES; |
685 | } | 696 | } |
686 | 697 | ||
@@ -720,21 +731,9 @@ keygen_round2_conclude (void *cls) | |||
720 | unsigned int i; | 731 | unsigned int i; |
721 | unsigned int j; | 732 | unsigned int j; |
722 | struct GNUNET_SECRETSHARING_Share *share; | 733 | struct GNUNET_SECRETSHARING_Share *share; |
723 | /* our share */ | ||
724 | gcry_mpi_t s; | ||
725 | /* public key */ | ||
726 | gcry_mpi_t h; | ||
727 | 734 | ||
728 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, "round2 conclude\n"); | 735 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, "round2 conclude\n"); |
729 | 736 | ||
730 | GNUNET_assert (0 != (s = gcry_mpi_new (GNUNET_SECRETSHARING_ELGAMAL_BITS))); | ||
731 | GNUNET_assert (0 != (h = gcry_mpi_new (GNUNET_SECRETSHARING_ELGAMAL_BITS))); | ||
732 | |||
733 | // multiplicative identity | ||
734 | gcry_mpi_set_ui (h, 1); | ||
735 | // additive identity | ||
736 | gcry_mpi_set_ui (s, 0); | ||
737 | |||
738 | share = GNUNET_new (struct GNUNET_SECRETSHARING_Share); | 737 | share = GNUNET_new (struct GNUNET_SECRETSHARING_Share); |
739 | 738 | ||
740 | share->num_peers = 0; | 739 | share->num_peers = 0; |
@@ -744,29 +743,38 @@ keygen_round2_conclude (void *cls) | |||
744 | share->num_peers++; | 743 | share->num_peers++; |
745 | 744 | ||
746 | share->peers = GNUNET_new_array (share->num_peers, struct GNUNET_PeerIdentity); | 745 | share->peers = GNUNET_new_array (share->num_peers, struct GNUNET_PeerIdentity); |
747 | share->hom_share_commitments = | 746 | share->sigmas = |
748 | GNUNET_new_array (share->num_peers, struct GNUNET_SECRETSHARING_FieldElement); | 747 | GNUNET_new_array (share->num_peers, struct GNUNET_SECRETSHARING_FieldElement); |
749 | share->original_indices = GNUNET_new_array (share->num_peers, uint16_t); | 748 | share->original_indices = GNUNET_new_array (share->num_peers, uint16_t); |
750 | 749 | ||
751 | /* maybe we're not even in the list of peers? */ | 750 | /* maybe we're not even in the list of peers? */ |
752 | share->my_peer = share->num_peers; | 751 | share->my_peer = share->num_peers; |
753 | 752 | ||
754 | j = 0; | 753 | j = 0; /* running index of valid peers */ |
755 | for (i = 0; i < ks->num_peers; i++) | 754 | for (i = 0; i < ks->num_peers; i++) |
756 | { | 755 | { |
757 | if (GNUNET_YES == ks->info[i].round2_valid) | 756 | if (GNUNET_YES == ks->info[i].round2_valid) |
758 | { | 757 | { |
759 | gcry_mpi_addm (s, s, ks->info[i].decrypted_preshare, elgamal_p); | 758 | share->peers[j] = ks->info[i].peer; |
760 | gcry_mpi_mulm (h, h, ks->info[i].public_key_share, elgamal_p); | 759 | GNUNET_CRYPTO_mpi_print_unsigned (&share->sigmas[j], |
761 | share->peers[i] = ks->info[i].peer; | 760 | GNUNET_SECRETSHARING_ELGAMAL_BITS / 8, |
762 | share->original_indices[i] = j++; | 761 | ks->info[i].sigma); |
762 | share->original_indices[i] = j; | ||
763 | if (0 == memcmp (&share->peers[i], &my_peer, sizeof (struct GNUNET_PeerIdentity))) | 763 | if (0 == memcmp (&share->peers[i], &my_peer, sizeof (struct GNUNET_PeerIdentity))) |
764 | share->my_peer = i; | 764 | share->my_peer = j; |
765 | j += 1; | ||
765 | } | 766 | } |
766 | } | 767 | } |
767 | 768 | ||
768 | GNUNET_CRYPTO_mpi_print_unsigned (&share->my_share, GNUNET_SECRETSHARING_ELGAMAL_BITS / 8, s); | 769 | if (share->my_peer == share->num_peers) |
769 | GNUNET_CRYPTO_mpi_print_unsigned (&share->public_key, GNUNET_SECRETSHARING_ELGAMAL_BITS / 8, h); | 770 | { |
771 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, "P%u: peer identity not in share\n", ks->local_peer_idx); | ||
772 | } | ||
773 | |||
774 | GNUNET_CRYPTO_mpi_print_unsigned (&share->my_share, GNUNET_SECRETSHARING_ELGAMAL_BITS / 8, | ||
775 | ks->my_share); | ||
776 | GNUNET_CRYPTO_mpi_print_unsigned (&share->public_key, GNUNET_SECRETSHARING_ELGAMAL_BITS / 8, | ||
777 | ks->public_key); | ||
770 | 778 | ||
771 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, "keygen completed with %u peers\n", share->num_peers); | 779 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, "keygen completed with %u peers\n", share->num_peers); |
772 | 780 | ||
@@ -792,8 +800,8 @@ keygen_round2_conclude (void *cls) | |||
792 | * (1) The exponentiated pre-share polynomial coefficients A_{i,l}=g^{a_{i,l}} | 800 | * (1) The exponentiated pre-share polynomial coefficients A_{i,l}=g^{a_{i,l}} |
793 | * (2) The exponentiated pre-shares y_{i,j}=g^{s_{i,j}} | 801 | * (2) The exponentiated pre-shares y_{i,j}=g^{s_{i,j}} |
794 | * (3) The encrypted pre-shares Y_{i,j} | 802 | * (3) The encrypted pre-shares Y_{i,j} |
795 | * (4) The zero knowledge proof for correctness of | 803 | * (4) The zero knowledge proof for fairness of |
796 | * the encryption | 804 | * the encryption |
797 | * | 805 | * |
798 | * @param ks session to use | 806 | * @param ks session to use |
799 | */ | 807 | */ |
@@ -899,6 +907,67 @@ insert_round2_element (struct KeygenSession *ks) | |||
899 | } | 907 | } |
900 | 908 | ||
901 | 909 | ||
910 | static gcry_mpi_t | ||
911 | keygen_reveal_get_exp_preshare (struct KeygenSession *ks, | ||
912 | const struct GNUNET_SECRETSHARING_KeygenRevealData *d, | ||
913 | unsigned int idx) | ||
914 | { | ||
915 | unsigned char *pos; | ||
916 | gcry_mpi_t exp_preshare; | ||
917 | |||
918 | GNUNET_assert (idx < ks->num_peers); | ||
919 | |||
920 | GNUNET_assert (NULL != (exp_preshare = gcry_mpi_new (0))); | ||
921 | |||
922 | pos = (void *) &d[1]; | ||
923 | // skip exponentiated pre-shares we don't want | ||
924 | pos += GNUNET_SECRETSHARING_ELGAMAL_BITS / 8 * idx; | ||
925 | GNUNET_CRYPTO_mpi_scan_unsigned (&exp_preshare, pos, GNUNET_SECRETSHARING_ELGAMAL_BITS / 8); | ||
926 | return exp_preshare; | ||
927 | } | ||
928 | |||
929 | static gcry_mpi_t | ||
930 | keygen_reveal_get_exp_coeff (struct KeygenSession *ks, | ||
931 | const struct GNUNET_SECRETSHARING_KeygenRevealData *d, | ||
932 | unsigned int idx) | ||
933 | { | ||
934 | unsigned char *pos; | ||
935 | gcry_mpi_t exp_coeff; | ||
936 | |||
937 | GNUNET_assert (idx < ks->threshold); | ||
938 | GNUNET_assert (NULL != (exp_coeff = gcry_mpi_new (0))); | ||
939 | |||
940 | pos = (void *) &d[1]; | ||
941 | // skip exponentiated pre-shares | ||
942 | pos += GNUNET_SECRETSHARING_ELGAMAL_BITS / 8 * ks->num_peers; | ||
943 | // skip encrypted pre-shares | ||
944 | pos += sizeof (struct GNUNET_CRYPTO_PaillierCiphertext) * ks->num_peers; | ||
945 | // skip exp. coeffs we are not interested in | ||
946 | pos += GNUNET_SECRETSHARING_ELGAMAL_BITS / 8 * idx; | ||
947 | // the first exponentiated coefficient is the public key share | ||
948 | GNUNET_CRYPTO_mpi_scan_unsigned (&exp_coeff, pos, GNUNET_SECRETSHARING_ELGAMAL_BITS / 8); | ||
949 | return exp_coeff; | ||
950 | } | ||
951 | |||
952 | |||
953 | static struct GNUNET_CRYPTO_PaillierCiphertext * | ||
954 | keygen_reveal_get_enc_preshare (struct KeygenSession *ks, | ||
955 | const struct GNUNET_SECRETSHARING_KeygenRevealData *d, | ||
956 | unsigned int idx) | ||
957 | { | ||
958 | unsigned char *pos; | ||
959 | |||
960 | GNUNET_assert (idx < ks->num_peers); | ||
961 | |||
962 | pos = (void *) &d[1]; | ||
963 | // skip exponentiated pre-shares | ||
964 | pos += GNUNET_SECRETSHARING_ELGAMAL_BITS / 8 * ks->num_peers; | ||
965 | // skip encrypted pre-shares we're not interested in | ||
966 | pos += sizeof (struct GNUNET_CRYPTO_PaillierCiphertext) * idx; | ||
967 | return (struct GNUNET_CRYPTO_PaillierCiphertext *) pos; | ||
968 | } | ||
969 | |||
970 | |||
902 | static void | 971 | static void |
903 | keygen_round2_new_element (void *cls, | 972 | keygen_round2_new_element (void *cls, |
904 | const struct GNUNET_SET_Element *element) | 973 | const struct GNUNET_SET_Element *element) |
@@ -906,8 +975,11 @@ keygen_round2_new_element (void *cls, | |||
906 | struct KeygenSession *ks = cls; | 975 | struct KeygenSession *ks = cls; |
907 | const struct GNUNET_SECRETSHARING_KeygenRevealData *d; | 976 | const struct GNUNET_SECRETSHARING_KeygenRevealData *d; |
908 | struct KeygenPeerInfo *info; | 977 | struct KeygenPeerInfo *info; |
909 | unsigned char *pos; | ||
910 | size_t expected_element_size; | 978 | size_t expected_element_size; |
979 | unsigned int j; | ||
980 | gcry_mpi_t tmp; | ||
981 | gcry_mpi_t public_key_share; | ||
982 | gcry_mpi_t preshare; | ||
911 | 983 | ||
912 | if (NULL == element) | 984 | if (NULL == element) |
913 | { | 985 | { |
@@ -958,26 +1030,6 @@ keygen_round2_new_element (void *cls, | |||
958 | 1030 | ||
959 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, "got round2 element\n"); | 1031 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, "got round2 element\n"); |
960 | 1032 | ||
961 | pos = (void *) &d[1]; | ||
962 | // skip exponentiated pre-shares | ||
963 | pos += GNUNET_SECRETSHARING_ELGAMAL_BITS / 8 * ks->num_peers; | ||
964 | // skip encrypted pre-shares | ||
965 | pos += sizeof (struct GNUNET_CRYPTO_PaillierCiphertext) * ks->num_peers; | ||
966 | // the first exponentiated coefficient is the public key share | ||
967 | GNUNET_CRYPTO_mpi_scan_unsigned (&info->public_key_share, pos, GNUNET_SECRETSHARING_ELGAMAL_BITS / 8); | ||
968 | |||
969 | pos = (void *) &d[1]; | ||
970 | // skip exp. pre-shares | ||
971 | pos += GNUNET_SECRETSHARING_ELGAMAL_BITS / 8 * ks->num_peers; | ||
972 | // skip to the encrypted value for our peer | ||
973 | pos += sizeof (struct GNUNET_CRYPTO_PaillierCiphertext) * ks->local_peer_idx; | ||
974 | |||
975 | GNUNET_assert (NULL != (info->decrypted_preshare = gcry_mpi_new (0))); | ||
976 | GNUNET_CRYPTO_paillier_decrypt (&ks->paillier_private_key, &ks->info[ks->local_peer_idx].paillier_public_key, | ||
977 | (struct GNUNET_CRYPTO_PaillierCiphertext *) pos, info->decrypted_preshare); | ||
978 | |||
979 | // TODO: validate zero knowledge proofs | ||
980 | |||
981 | if (ntohl (d->purpose.size) != | 1033 | if (ntohl (d->purpose.size) != |
982 | element->size - offsetof (struct GNUNET_SECRETSHARING_KeygenRevealData, purpose)) | 1034 | element->size - offsetof (struct GNUNET_SECRETSHARING_KeygenRevealData, purpose)) |
983 | { | 1035 | { |
@@ -991,6 +1043,84 @@ keygen_round2_new_element (void *cls, | |||
991 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "keygen reveal data with invalid signature in consensus\n"); | 1043 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "keygen reveal data with invalid signature in consensus\n"); |
992 | return; | 1044 | return; |
993 | } | 1045 | } |
1046 | |||
1047 | public_key_share = keygen_reveal_get_exp_coeff (ks, d, 0); | ||
1048 | info->preshare_commitment = keygen_reveal_get_exp_preshare (ks, d, ks->local_peer_idx); | ||
1049 | |||
1050 | if (NULL == ks->public_key) | ||
1051 | { | ||
1052 | GNUNET_assert (NULL != (ks->public_key = gcry_mpi_new (0))); | ||
1053 | gcry_mpi_set_ui (ks->public_key, 1); | ||
1054 | } | ||
1055 | gcry_mpi_mulm (ks->public_key, ks->public_key, public_key_share, elgamal_p); | ||
1056 | |||
1057 | GNUNET_assert (NULL != (preshare = gcry_mpi_new (0))); | ||
1058 | GNUNET_CRYPTO_paillier_decrypt (&ks->paillier_private_key, | ||
1059 | &ks->info[ks->local_peer_idx].paillier_public_key, | ||
1060 | keygen_reveal_get_enc_preshare (ks, d, ks->local_peer_idx), | ||
1061 | preshare); | ||
1062 | |||
1063 | GNUNET_assert (NULL != (tmp = gcry_mpi_new (0))); | ||
1064 | gcry_mpi_powm (tmp, elgamal_g, preshare, elgamal_p); | ||
1065 | |||
1066 | // TODO: restore a valid secret from the decryption (the hard part, solving SVP with gauss) | ||
1067 | if (0 != gcry_mpi_cmp (tmp, info->preshare_commitment)) | ||
1068 | { | ||
1069 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "P%u: Got invalid presecret from P%u\n", | ||
1070 | (unsigned int) ks->local_peer_idx, (unsigned int) (info - ks->info)); | ||
1071 | return; | ||
1072 | } | ||
1073 | |||
1074 | if (NULL == ks->my_share) | ||
1075 | { | ||
1076 | GNUNET_assert (NULL != (ks->my_share = gcry_mpi_new (0))); | ||
1077 | } | ||
1078 | gcry_mpi_addm (ks->my_share, ks->my_share, preshare, elgamal_q); | ||
1079 | |||
1080 | for (j = 0; j < ks->num_peers; j++) | ||
1081 | { | ||
1082 | gcry_mpi_t presigma; | ||
1083 | if (NULL == ks->info[j].sigma) | ||
1084 | { | ||
1085 | GNUNET_assert (NULL != (ks->info[j].sigma = gcry_mpi_new (0))); | ||
1086 | gcry_mpi_set_ui (ks->info[j].sigma, 1); | ||
1087 | } | ||
1088 | presigma = keygen_reveal_get_exp_preshare (ks, d, j); | ||
1089 | gcry_mpi_mulm (ks->info[j].sigma, ks->info[j].sigma, presigma, elgamal_p); | ||
1090 | } | ||
1091 | |||
1092 | gcry_mpi_t prod; | ||
1093 | GNUNET_assert (NULL != (prod = gcry_mpi_new (0))); | ||
1094 | gcry_mpi_t j_to_k; | ||
1095 | GNUNET_assert (NULL != (j_to_k = gcry_mpi_new (0))); | ||
1096 | // validate that the polynomial sharing matches the additive sharing | ||
1097 | for (j = 0; j < ks->num_peers; j++) | ||
1098 | { | ||
1099 | unsigned int k; | ||
1100 | gcry_mpi_t tmp; | ||
1101 | gcry_mpi_t exp_preshare; | ||
1102 | gcry_mpi_set_ui (prod, 1); | ||
1103 | for (k = 0; k < ks->threshold; k++) | ||
1104 | { | ||
1105 | // Using pow(double,double) is a bit sketchy. | ||
1106 | // We count players from 1, but shares from 0. | ||
1107 | gcry_mpi_set_ui (j_to_k, (unsigned int) pow(j+1, k)); | ||
1108 | tmp = keygen_reveal_get_exp_coeff (ks, d, k); | ||
1109 | gcry_mpi_powm (tmp, tmp, j_to_k, elgamal_p); | ||
1110 | gcry_mpi_mulm (prod, prod, tmp, elgamal_p); | ||
1111 | } | ||
1112 | exp_preshare = keygen_reveal_get_exp_preshare (ks, d, j); | ||
1113 | gcry_mpi_mod (exp_preshare, exp_preshare, elgamal_p); | ||
1114 | if (0 != gcry_mpi_cmp (prod, exp_preshare)) | ||
1115 | { | ||
1116 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "P%u: reveal data from P%u incorrect\n", | ||
1117 | ks->local_peer_idx, j); | ||
1118 | /* no need for further verification, round2 stays invalid ... */ | ||
1119 | return; | ||
1120 | } | ||
1121 | } | ||
1122 | |||
1123 | // TODO: verify proof of fair encryption (once implemented) | ||
994 | 1124 | ||
995 | info->round2_valid = GNUNET_YES; | 1125 | info->round2_valid = GNUNET_YES; |
996 | } | 1126 | } |
@@ -1205,6 +1335,23 @@ decrypt_conclude (void *cls) | |||
1205 | 1335 | ||
1206 | 1336 | ||
1207 | /** | 1337 | /** |
1338 | * Get a string representation of an MPI. | ||
1339 | * The caller must free the returned string. | ||
1340 | * | ||
1341 | * @param mpi mpi to convert to a string | ||
1342 | * @return string representation of @a mpi, must be free'd by the caller | ||
1343 | */ | ||
1344 | static char * | ||
1345 | mpi_to_str (gcry_mpi_t mpi) | ||
1346 | { | ||
1347 | unsigned char *buf; | ||
1348 | |||
1349 | GNUNET_assert (0 == gcry_mpi_aprint (GCRYMPI_FMT_HEX, &buf, NULL, mpi)); | ||
1350 | return (char *) buf; | ||
1351 | } | ||
1352 | |||
1353 | |||
1354 | /** | ||
1208 | * Called when a new partial decryption arrives. | 1355 | * Called when a new partial decryption arrives. |
1209 | */ | 1356 | */ |
1210 | static void | 1357 | static void |
@@ -1214,6 +1361,27 @@ decrypt_new_element (void *cls, | |||
1214 | struct DecryptSession *session = cls; | 1361 | struct DecryptSession *session = cls; |
1215 | const struct GNUNET_SECRETSHARING_DecryptData *d; | 1362 | const struct GNUNET_SECRETSHARING_DecryptData *d; |
1216 | struct DecryptPeerInfo *info; | 1363 | struct DecryptPeerInfo *info; |
1364 | struct GNUNET_HashCode challenge_hash; | ||
1365 | |||
1366 | /* nizk response */ | ||
1367 | gcry_mpi_t r; | ||
1368 | /* nizk challenge */ | ||
1369 | gcry_mpi_t challenge; | ||
1370 | /* nizk commit1, g^\beta */ | ||
1371 | gcry_mpi_t commit1; | ||
1372 | /* nizk commit2, c_1^\beta */ | ||
1373 | gcry_mpi_t commit2; | ||
1374 | /* homomorphic commitment to the peer's share, | ||
1375 | * public key share */ | ||
1376 | gcry_mpi_t sigma; | ||
1377 | /* partial decryption we received */ | ||
1378 | gcry_mpi_t w; | ||
1379 | /* ciphertext component #1 */ | ||
1380 | gcry_mpi_t c1; | ||
1381 | /* temporary variable (for comparision) #1 */ | ||
1382 | gcry_mpi_t tmp1; | ||
1383 | /* temporary variable (for comparision) #2 */ | ||
1384 | gcry_mpi_t tmp2; | ||
1217 | 1385 | ||
1218 | if (NULL == element) | 1386 | if (NULL == element) |
1219 | { | 1387 | { |
@@ -1246,19 +1414,101 @@ decrypt_new_element (void *cls, | |||
1246 | return; | 1414 | return; |
1247 | } | 1415 | } |
1248 | 1416 | ||
1249 | // FIXME: check NIZP first | 1417 | if (0 != memcmp (&d->ciphertext, &session->ciphertext, sizeof (struct GNUNET_SECRETSHARING_Ciphertext))) |
1418 | { | ||
1419 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "P%u: got decrypt element with non-matching ciphertext from P%u\n", | ||
1420 | (unsigned int) session->share->my_peer, (unsigned int) (info - session->info)); | ||
1421 | |||
1422 | return; | ||
1423 | } | ||
1424 | |||
1425 | |||
1426 | GNUNET_CRYPTO_hash (offsetof (struct GNUNET_SECRETSHARING_DecryptData, ciphertext) + (char *) d, | ||
1427 | offsetof (struct GNUNET_SECRETSHARING_DecryptData, nizk_response) - | ||
1428 | offsetof (struct GNUNET_SECRETSHARING_DecryptData, ciphertext), | ||
1429 | &challenge_hash); | ||
1430 | |||
1431 | GNUNET_CRYPTO_mpi_scan_unsigned (&challenge, &challenge_hash, | ||
1432 | sizeof (struct GNUNET_HashCode)); | ||
1433 | |||
1434 | GNUNET_CRYPTO_mpi_scan_unsigned (&sigma, &session->share->sigmas[info - session->info], | ||
1435 | sizeof (struct GNUNET_SECRETSHARING_FieldElement)); | ||
1436 | |||
1437 | GNUNET_CRYPTO_mpi_scan_unsigned (&c1, session->ciphertext.c1_bits, | ||
1438 | sizeof (struct GNUNET_SECRETSHARING_FieldElement)); | ||
1439 | |||
1440 | GNUNET_CRYPTO_mpi_scan_unsigned (&commit1, &d->nizk_commit1, | ||
1441 | sizeof (struct GNUNET_SECRETSHARING_FieldElement)); | ||
1442 | |||
1443 | GNUNET_CRYPTO_mpi_scan_unsigned (&commit2, &d->nizk_commit2, | ||
1444 | sizeof (struct GNUNET_SECRETSHARING_FieldElement)); | ||
1445 | |||
1446 | GNUNET_CRYPTO_mpi_scan_unsigned (&r, &d->nizk_response, | ||
1447 | sizeof (struct GNUNET_SECRETSHARING_FieldElement)); | ||
1448 | |||
1449 | GNUNET_CRYPTO_mpi_scan_unsigned (&w, &d->partial_decryption, | ||
1450 | sizeof (struct GNUNET_SECRETSHARING_FieldElement)); | ||
1451 | |||
1452 | GNUNET_assert (NULL != (tmp1 = gcry_mpi_new (0))); | ||
1453 | GNUNET_assert (NULL != (tmp2 = gcry_mpi_new (0))); | ||
1454 | |||
1455 | // tmp1 = g^r | ||
1456 | gcry_mpi_powm (tmp1, elgamal_g, r, elgamal_p); | ||
1457 | |||
1458 | // tmp2 = g^\beta * \sigma^challenge | ||
1459 | gcry_mpi_powm (tmp2, sigma, challenge, elgamal_p); | ||
1460 | gcry_mpi_mulm (tmp2, tmp2, commit1, elgamal_p); | ||
1461 | |||
1462 | if (0 != gcry_mpi_cmp (tmp1, tmp2)) | ||
1463 | { | ||
1464 | char *tmp1_str; | ||
1465 | char *tmp2_str; | ||
1466 | tmp1_str = mpi_to_str (tmp1); | ||
1467 | tmp2_str = mpi_to_str (tmp2); | ||
1468 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "P%u: Received invalid partial decryption from P%u (eqn 1), expected %s got %s\n", | ||
1469 | session->share->my_peer, info - session->info, tmp1_str, tmp2_str); | ||
1470 | GNUNET_free (tmp1_str); | ||
1471 | GNUNET_free (tmp2_str); | ||
1472 | // return; | ||
1473 | } | ||
1474 | |||
1475 | |||
1476 | gcry_mpi_powm (tmp1, c1, r, elgamal_p); | ||
1477 | |||
1478 | gcry_mpi_powm (tmp2, w, challenge, elgamal_p); | ||
1479 | gcry_mpi_mulm (tmp2, tmp2, commit2, elgamal_p); | ||
1480 | |||
1481 | |||
1482 | if (0 != gcry_mpi_cmp (tmp1, tmp2)) | ||
1483 | { | ||
1484 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "P%u: Received invalid partial decryption from P%u (eqn 2)\n", | ||
1485 | session->share->my_peer, info - session->info); | ||
1486 | // return; | ||
1487 | } | ||
1488 | |||
1250 | 1489 | ||
1251 | GNUNET_CRYPTO_mpi_scan_unsigned (&info->partial_decryption, &d->partial_decryption, | 1490 | GNUNET_CRYPTO_mpi_scan_unsigned (&info->partial_decryption, &d->partial_decryption, |
1252 | GNUNET_SECRETSHARING_ELGAMAL_BITS / 8); | 1491 | GNUNET_SECRETSHARING_ELGAMAL_BITS / 8); |
1253 | } | 1492 | } |
1254 | 1493 | ||
1494 | |||
1255 | static void | 1495 | static void |
1256 | insert_decrypt_element (struct DecryptSession *ds) | 1496 | insert_decrypt_element (struct DecryptSession *ds) |
1257 | { | 1497 | { |
1258 | struct GNUNET_SECRETSHARING_DecryptData d; | 1498 | struct GNUNET_SECRETSHARING_DecryptData d; |
1259 | struct GNUNET_SET_Element element; | 1499 | struct GNUNET_SET_Element element; |
1260 | gcry_mpi_t x; | 1500 | /* our share */ |
1261 | gcry_mpi_t s; | 1501 | gcry_mpi_t s; |
1502 | /* partial decryption with our share */ | ||
1503 | gcry_mpi_t w; | ||
1504 | /* first component of the elgamal ciphertext */ | ||
1505 | gcry_mpi_t c1; | ||
1506 | /* nonce for dlog zkp */ | ||
1507 | gcry_mpi_t beta; | ||
1508 | gcry_mpi_t tmp; | ||
1509 | gcry_mpi_t challenge; | ||
1510 | gcry_mpi_t sigma; | ||
1511 | struct GNUNET_HashCode challenge_hash; | ||
1262 | 1512 | ||
1263 | /* make vagrind happy until we implement the real deal ... */ | 1513 | /* make vagrind happy until we implement the real deal ... */ |
1264 | memset (&d, 0, sizeof d); | 1514 | memset (&d, 0, sizeof d); |
@@ -1266,12 +1516,36 @@ insert_decrypt_element (struct DecryptSession *ds) | |||
1266 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "P%u: Inserting decrypt element\n", | 1516 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "P%u: Inserting decrypt element\n", |
1267 | ds->share->my_peer); | 1517 | ds->share->my_peer); |
1268 | 1518 | ||
1269 | GNUNET_CRYPTO_mpi_scan_unsigned (&x, &ds->ciphertext.c1_bits, | 1519 | GNUNET_assert (ds->share->my_peer < ds->share->num_peers); |
1520 | |||
1521 | GNUNET_CRYPTO_mpi_scan_unsigned (&c1, &ds->ciphertext.c1_bits, | ||
1270 | GNUNET_SECRETSHARING_ELGAMAL_BITS / 8); | 1522 | GNUNET_SECRETSHARING_ELGAMAL_BITS / 8); |
1271 | GNUNET_CRYPTO_mpi_scan_unsigned (&s, &ds->share->my_share, | 1523 | GNUNET_CRYPTO_mpi_scan_unsigned (&s, &ds->share->my_share, |
1272 | GNUNET_SECRETSHARING_ELGAMAL_BITS / 8); | 1524 | GNUNET_SECRETSHARING_ELGAMAL_BITS / 8); |
1525 | GNUNET_CRYPTO_mpi_scan_unsigned (&sigma, &ds->share->sigmas[ds->share->my_peer], | ||
1526 | GNUNET_SECRETSHARING_ELGAMAL_BITS / 8); | ||
1273 | 1527 | ||
1274 | gcry_mpi_powm (x, x, s, elgamal_p); | 1528 | GNUNET_assert (NULL != (w = gcry_mpi_new (0))); |
1529 | GNUNET_assert (NULL != (beta = gcry_mpi_new (0))); | ||
1530 | GNUNET_assert (NULL != (tmp = gcry_mpi_new (0))); | ||
1531 | |||
1532 | // FIXME: unnecessary, remove once crypto works | ||
1533 | gcry_mpi_powm (tmp, elgamal_g, s, elgamal_p); | ||
1534 | if (0 != gcry_mpi_cmp (tmp, sigma)) | ||
1535 | { | ||
1536 | char *sigma_str = mpi_to_str (sigma); | ||
1537 | char *tmp_str = mpi_to_str (tmp); | ||
1538 | char *s_str = mpi_to_str (s); | ||
1539 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Share of P%u is invalid, ref sigma %s, " | ||
1540 | "computed sigma %s, s %s\n", | ||
1541 | ds->share->my_peer, | ||
1542 | sigma_str, tmp_str, s_str); | ||
1543 | GNUNET_free (sigma_str); | ||
1544 | GNUNET_free (tmp_str); | ||
1545 | GNUNET_free (s_str); | ||
1546 | } | ||
1547 | |||
1548 | gcry_mpi_powm (w, c1, s, elgamal_p); | ||
1275 | 1549 | ||
1276 | element.data = (void *) &d; | 1550 | element.data = (void *) &d; |
1277 | element.size = sizeof (struct GNUNET_SECRETSHARING_DecryptData); | 1551 | element.size = sizeof (struct GNUNET_SECRETSHARING_DecryptData); |
@@ -1279,13 +1553,42 @@ insert_decrypt_element (struct DecryptSession *ds) | |||
1279 | 1553 | ||
1280 | d.ciphertext = ds->ciphertext; | 1554 | d.ciphertext = ds->ciphertext; |
1281 | d.peer = my_peer; | 1555 | d.peer = my_peer; |
1556 | GNUNET_CRYPTO_mpi_print_unsigned (&d.partial_decryption, GNUNET_SECRETSHARING_ELGAMAL_BITS / 8, w); | ||
1557 | |||
1558 | // create the zero knowledge proof | ||
1559 | // randomly choose beta such that 0 < beta < q | ||
1560 | do | ||
1561 | { | ||
1562 | gcry_mpi_randomize (beta, GNUNET_SECRETSHARING_ELGAMAL_BITS - 1, GCRY_WEAK_RANDOM); | ||
1563 | } while ((gcry_mpi_cmp_ui (beta, 0) == 0) || (gcry_mpi_cmp (beta, elgamal_q) >= 0)); | ||
1564 | // tmp = g^beta | ||
1565 | gcry_mpi_powm (tmp, elgamal_g, beta, elgamal_p); | ||
1566 | GNUNET_CRYPTO_mpi_print_unsigned (&d.nizk_commit1, GNUNET_SECRETSHARING_ELGAMAL_BITS / 8, tmp); | ||
1567 | // tmp = (c_1)^beta | ||
1568 | gcry_mpi_powm (tmp, c1, beta, elgamal_p); | ||
1569 | GNUNET_CRYPTO_mpi_print_unsigned (&d.nizk_commit2, GNUNET_SECRETSHARING_ELGAMAL_BITS / 8, tmp); | ||
1570 | |||
1571 | // the challenge is the hash of everything up to the response | ||
1572 | GNUNET_CRYPTO_hash (offsetof (struct GNUNET_SECRETSHARING_DecryptData, ciphertext) + (char *) &d, | ||
1573 | offsetof (struct GNUNET_SECRETSHARING_DecryptData, nizk_response) - | ||
1574 | offsetof (struct GNUNET_SECRETSHARING_DecryptData, ciphertext), | ||
1575 | &challenge_hash); | ||
1576 | |||
1577 | GNUNET_CRYPTO_mpi_scan_unsigned (&challenge, &challenge_hash, | ||
1578 | sizeof (struct GNUNET_HashCode)); | ||
1579 | |||
1580 | // compute the response in tmp, | ||
1581 | // tmp = (c * s + beta) mod q | ||
1582 | gcry_mpi_mulm (tmp, challenge, s, elgamal_q); | ||
1583 | gcry_mpi_addm (tmp, tmp, beta, elgamal_q); | ||
1584 | |||
1585 | GNUNET_CRYPTO_mpi_print_unsigned (&d.nizk_response, GNUNET_SECRETSHARING_ELGAMAL_BITS / 8, tmp); | ||
1586 | |||
1282 | d.purpose.size = htonl (element.size - offsetof (struct GNUNET_SECRETSHARING_DecryptData, purpose)); | 1587 | d.purpose.size = htonl (element.size - offsetof (struct GNUNET_SECRETSHARING_DecryptData, purpose)); |
1283 | d.purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_SECRETSHARING_DECRYPTION); | 1588 | d.purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_SECRETSHARING_DECRYPTION); |
1284 | 1589 | ||
1285 | GNUNET_CRYPTO_eddsa_sign (my_peer_private_key, &d.purpose, &d.signature); | 1590 | GNUNET_CRYPTO_eddsa_sign (my_peer_private_key, &d.purpose, &d.signature); |
1286 | 1591 | ||
1287 | GNUNET_CRYPTO_mpi_print_unsigned (&d.partial_decryption, GNUNET_SECRETSHARING_ELGAMAL_BITS / 8, x); | ||
1288 | |||
1289 | GNUNET_CONSENSUS_insert (ds->consensus, &element, NULL, NULL); | 1592 | GNUNET_CONSENSUS_insert (ds->consensus, &element, NULL, NULL); |
1290 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "P%u: Inserting decrypt element done!\n", | 1593 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "P%u: Inserting decrypt element done!\n", |
1291 | ds->share->my_peer); | 1594 | ds->share->my_peer); |
diff --git a/src/secretsharing/secretsharing.h b/src/secretsharing/secretsharing.h index 796feabae..227349b05 100644 --- a/src/secretsharing/secretsharing.h +++ b/src/secretsharing/secretsharing.h | |||
@@ -198,8 +198,8 @@ struct GNUNET_SECRETSHARING_Share | |||
198 | uint16_t my_peer; | 198 | uint16_t my_peer; |
199 | 199 | ||
200 | /** | 200 | /** |
201 | * Public key. Must correspond to the product of | 201 | * Public key. Computed from the |
202 | * the homomorphic share commitments. | 202 | * exponentiated coefficients. |
203 | */ | 203 | */ |
204 | struct GNUNET_SECRETSHARING_PublicKey public_key; | 204 | struct GNUNET_SECRETSHARING_PublicKey public_key; |
205 | 205 | ||
@@ -214,9 +214,10 @@ struct GNUNET_SECRETSHARING_Share | |||
214 | struct GNUNET_PeerIdentity *peers; | 214 | struct GNUNET_PeerIdentity *peers; |
215 | 215 | ||
216 | /* | 216 | /* |
217 | * Homomorphic commitments to each peer's share (includes 'my_peer') | 217 | * For each peer, store elgamal_g to the peer's |
218 | * share. | ||
218 | */ | 219 | */ |
219 | struct GNUNET_SECRETSHARING_FieldElement *hom_share_commitments; | 220 | struct GNUNET_SECRETSHARING_FieldElement *sigmas; |
220 | 221 | ||
221 | /* | 222 | /* |
222 | * Original indices of peers from the DKG round. | 223 | * Original indices of peers from the DKG round. |
diff --git a/src/secretsharing/secretsharing_common.c b/src/secretsharing/secretsharing_common.c index 9f21a1102..7fe8f4666 100644 --- a/src/secretsharing/secretsharing_common.c +++ b/src/secretsharing/secretsharing_common.c | |||
@@ -62,8 +62,8 @@ GNUNET_SECRETSHARING_share_read (const void *data, size_t len, size_t *readlen) | |||
62 | p += n; | 62 | p += n; |
63 | 63 | ||
64 | n = share->num_peers * sizeof (struct GNUNET_SECRETSHARING_FieldElement); | 64 | n = share->num_peers * sizeof (struct GNUNET_SECRETSHARING_FieldElement); |
65 | share->hom_share_commitments = GNUNET_malloc (n); | 65 | share->sigmas= GNUNET_malloc (n); |
66 | memcpy (share->hom_share_commitments, p, n); | 66 | memcpy (share->sigmas, p, n); |
67 | p += n; | 67 | p += n; |
68 | 68 | ||
69 | n = share->num_peers * sizeof (uint16_t); | 69 | n = share->num_peers * sizeof (uint16_t); |
@@ -125,7 +125,7 @@ GNUNET_SECRETSHARING_share_write (const struct GNUNET_SECRETSHARING_Share *share | |||
125 | p += n; | 125 | p += n; |
126 | 126 | ||
127 | n = share->num_peers * sizeof (struct GNUNET_SECRETSHARING_FieldElement); | 127 | n = share->num_peers * sizeof (struct GNUNET_SECRETSHARING_FieldElement); |
128 | memcpy (p, share->hom_share_commitments, n); | 128 | memcpy (p, share->sigmas, n); |
129 | p += n; | 129 | p += n; |
130 | 130 | ||
131 | n = share->num_peers * sizeof (uint16_t); | 131 | n = share->num_peers * sizeof (uint16_t); |
diff --git a/src/secretsharing/test_secretsharing.conf b/src/secretsharing/test_secretsharing.conf index 6ce865e3a..44b9adf3d 100644 --- a/src/secretsharing/test_secretsharing.conf +++ b/src/secretsharing/test_secretsharing.conf | |||
@@ -1,6 +1,7 @@ | |||
1 | [secretsharing] | 1 | [secretsharing] |
2 | AUTOSTART = YES | 2 | AUTOSTART = YES |
3 | #PREFIX = valgrind | 3 | #PREFIX = valgrind |
4 | OPTIONS = -LINFO | ||
4 | 5 | ||
5 | [consensus] | 6 | [consensus] |
6 | AUTOSTART = YES | 7 | AUTOSTART = YES |
@@ -13,6 +14,7 @@ DEFAULTSERVICES = core consensus set secretsharing | |||
13 | 14 | ||
14 | [set] | 15 | [set] |
15 | OPTIONS = -L INFO | 16 | OPTIONS = -L INFO |
17 | AUTOSTART = YES | ||
16 | #PREFIX = valgrind --leak-check=full | 18 | #PREFIX = valgrind --leak-check=full |
17 | 19 | ||
18 | [testbed] | 20 | [testbed] |