/* This file is part of GNUnet. Copyright (C) 2014 GNUnet e.V. GNUnet is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . SPDX-License-Identifier: AGPL3.0-or-later */ /** * @file util/test_crypto_paillier.c * @brief testcase paillier crypto * @author Christian Fuchs * @author Florian Dold */ #include "platform.h" #include "gnunet_util_lib.h" #include static int test_crypto() { gcry_mpi_t plaintext; gcry_mpi_t plaintext_result; struct GNUNET_CRYPTO_PaillierCiphertext ciphertext; struct GNUNET_CRYPTO_PaillierPublicKey public_key; struct GNUNET_CRYPTO_PaillierPrivateKey private_key; int ret = 0; GNUNET_CRYPTO_paillier_create(&public_key, &private_key); GNUNET_assert(NULL != (plaintext = gcry_mpi_new(0))); GNUNET_assert(NULL != (plaintext_result = gcry_mpi_new(0))); gcry_mpi_randomize(plaintext, GNUNET_CRYPTO_PAILLIER_BITS / 2, GCRY_WEAK_RANDOM); GNUNET_CRYPTO_paillier_encrypt(&public_key, plaintext, 0 /* 0 hom ops */, &ciphertext); GNUNET_CRYPTO_paillier_decrypt(&private_key, &public_key, &ciphertext, plaintext_result); if (0 != gcry_mpi_cmp(plaintext, plaintext_result)) { fprintf(stderr, "Paillier decryption failed with plaintext of size %u\n", gcry_mpi_get_nbits(plaintext)); gcry_log_debugmpi("\n", plaintext); gcry_log_debugmpi("\n", plaintext_result); ret = 1; } gcry_mpi_release(plaintext); gcry_mpi_release(plaintext_result); return ret; } static int test_hom_simple(unsigned int a, unsigned int b) { gcry_mpi_t m1; gcry_mpi_t m2; gcry_mpi_t result; gcry_mpi_t hom_result; struct GNUNET_CRYPTO_PaillierCiphertext c1; struct GNUNET_CRYPTO_PaillierCiphertext c2; struct GNUNET_CRYPTO_PaillierCiphertext c_result; struct GNUNET_CRYPTO_PaillierPublicKey public_key; struct GNUNET_CRYPTO_PaillierPrivateKey private_key; int ret = 0; GNUNET_CRYPTO_paillier_create(&public_key, &private_key); GNUNET_assert(NULL != (m1 = gcry_mpi_new(0))); GNUNET_assert(NULL != (m2 = gcry_mpi_new(0))); GNUNET_assert(NULL != (result = gcry_mpi_new(0))); GNUNET_assert(NULL != (hom_result = gcry_mpi_new(0))); m1 = gcry_mpi_set_ui(m1, a); m2 = gcry_mpi_set_ui(m2, b); gcry_mpi_add(result, m1, m2); GNUNET_CRYPTO_paillier_encrypt(&public_key, m1, 2, &c1); GNUNET_CRYPTO_paillier_encrypt(&public_key, m2, 2, &c2); GNUNET_CRYPTO_paillier_hom_add(&public_key, &c1, &c2, &c_result); GNUNET_CRYPTO_paillier_decrypt(&private_key, &public_key, &c_result, hom_result); if (0 != gcry_mpi_cmp(result, hom_result)) { fprintf(stderr, "GNUNET_CRYPTO_paillier failed simple math!\n"); gcry_log_debugmpi("got ", hom_result); gcry_log_debugmpi("wanted ", result); ret = 1; } gcry_mpi_release(m1); gcry_mpi_release(m2); gcry_mpi_release(result); gcry_mpi_release(hom_result); return ret; } static int test_hom() { int ret; gcry_mpi_t m1; gcry_mpi_t m2; gcry_mpi_t result; gcry_mpi_t hom_result; struct GNUNET_CRYPTO_PaillierCiphertext c1; struct GNUNET_CRYPTO_PaillierCiphertext c2; struct GNUNET_CRYPTO_PaillierCiphertext c_result; struct GNUNET_CRYPTO_PaillierPublicKey public_key; struct GNUNET_CRYPTO_PaillierPrivateKey private_key; GNUNET_CRYPTO_paillier_create(&public_key, &private_key); GNUNET_assert(NULL != (m1 = gcry_mpi_new(0))); GNUNET_assert(NULL != (m2 = gcry_mpi_new(0))); GNUNET_assert(NULL != (result = gcry_mpi_new(0))); GNUNET_assert(NULL != (hom_result = gcry_mpi_new(0))); m1 = gcry_mpi_set_ui(m1, 1); /* m1 = m1 * 2 ^ (GCPB - 3) */ gcry_mpi_mul_2exp(m1, m1, GNUNET_CRYPTO_PAILLIER_BITS - 3); m2 = gcry_mpi_set_ui(m2, 15); /* m1 = m1 * 2 ^ (GCPB / 2) */ gcry_mpi_mul_2exp(m2, m2, GNUNET_CRYPTO_PAILLIER_BITS / 2); gcry_mpi_add(result, m1, m2); if (1 != (ret = GNUNET_CRYPTO_paillier_encrypt(&public_key, m1, 2, &c1))) { fprintf(stderr, "GNUNET_CRYPTO_paillier_encrypt 1 failed, should return 1 allowed operation, got %d!\n", ret); ret = 1; goto out; } if (2 != (ret = GNUNET_CRYPTO_paillier_encrypt(&public_key, m2, 2, &c2))) { fprintf(stderr, "GNUNET_CRYPTO_paillier_encrypt 2 failed, should return 2 allowed operation, got %d!\n", ret); ret = 1; goto out; } if (0 != (ret = GNUNET_CRYPTO_paillier_hom_add(&public_key, &c1, &c2, &c_result))) { fprintf(stderr, "GNUNET_CRYPTO_paillier_hom_add failed, expected 0 remaining operations, got %d!\n", ret); ret = 1; goto out; } GNUNET_CRYPTO_paillier_decrypt(&private_key, &public_key, &c_result, hom_result); if (0 != gcry_mpi_cmp(result, hom_result)) { fprintf(stderr, "GNUNET_CRYPTO_paillier miscalculated with large numbers!\n"); gcry_log_debugmpi("got", hom_result); gcry_log_debugmpi("wanted", result); ret = 1; } out: gcry_mpi_release(m1); gcry_mpi_release(m2); gcry_mpi_release(result); gcry_mpi_release(hom_result); return ret; } int main(int argc, char *argv[]) { int ret; ret = test_crypto(); if (0 != ret) return ret; ret = test_hom_simple(2, 4); if (0 != ret) return ret; ret = test_hom_simple(13, 17); if (0 != ret) return ret; ret = test_hom(); return ret; } /* end of test_crypto_paillier.c */