746 lines
24 KiB
C
746 lines
24 KiB
C
/* Cryptic -- Cryptographic tools and protocols
|
|
* Copyright (C) 2009 Mikaël Ates <mates@entrouvert.com>
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program 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 General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software Foundation,
|
|
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
*/
|
|
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
|
|
#include <glib.h>
|
|
#include <glib-object.h>
|
|
#include <openssl/bn.h>
|
|
#include <openssl/evp.h>
|
|
|
|
#include "../../errors.h"
|
|
#include "../../utils.h"
|
|
|
|
#include "schnorr_zkpk.h"
|
|
|
|
/*****************************************************************************/
|
|
/* private methods */
|
|
/*****************************************************************************/
|
|
|
|
static GObjectClass *parent_class = NULL;
|
|
|
|
/*****************************************************************************/
|
|
/* overridden parent class methods */
|
|
/*****************************************************************************/
|
|
|
|
static void
|
|
dispose(GObject *object)
|
|
{
|
|
CrypticZkpkSchnorr *shn = CRYPTIC_ZKPKSCHNORR(object);
|
|
|
|
int i = shn->nb_quantities-1;
|
|
cryptic_release_bn(shn->modulus);
|
|
cryptic_release_bn(shn->commitment);
|
|
while (i >= 0) {
|
|
if (shn->bases) {
|
|
cryptic_release_bn(shn->bases[i]);
|
|
}
|
|
if (shn->randoms) {
|
|
cryptic_release_bn(shn->randoms[i]);
|
|
}
|
|
if (shn->responses) {
|
|
cryptic_release_bn(shn->responses[i]);
|
|
}
|
|
i--;
|
|
}
|
|
cryptic_release(shn->bases);
|
|
cryptic_release(shn->randoms);
|
|
cryptic_release(shn->responses);
|
|
|
|
G_OBJECT_CLASS(parent_class)->dispose(G_OBJECT(shn));
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
/* instance and class init functions */
|
|
/*****************************************************************************/
|
|
|
|
static void
|
|
instance_init(CrypticZkpkSchnorr *shn)
|
|
{
|
|
shn->modulus = NULL;
|
|
shn->commitment = NULL;
|
|
shn->bases = NULL;
|
|
shn->randoms = NULL;
|
|
shn->responses = NULL;
|
|
}
|
|
|
|
static void
|
|
class_init(CrypticZkpkSchnorrClass *klass)
|
|
{
|
|
parent_class = g_type_class_peek_parent(klass);
|
|
G_OBJECT_CLASS(klass)->dispose = dispose;
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
/* public methods */
|
|
/*****************************************************************************/
|
|
|
|
GType
|
|
cryptic_zkpk_schnorr_get_type()
|
|
{
|
|
static GType this_type = 0;
|
|
if (!this_type) {
|
|
static const GTypeInfo this_info = {
|
|
sizeof (CrypticZkpkSchnorrClass),
|
|
NULL,
|
|
NULL,
|
|
(GClassInitFunc) class_init,
|
|
NULL,
|
|
NULL,
|
|
sizeof(CrypticZkpkSchnorr),
|
|
0,
|
|
(GInstanceInitFunc) instance_init,
|
|
NULL
|
|
};
|
|
this_type = g_type_register_static(G_TYPE_OBJECT,
|
|
"CrypticZkpkSchnorr", &this_info, 0);
|
|
}
|
|
return this_type;
|
|
}
|
|
|
|
/**
|
|
* cryptic_zkpk_schnorr_new
|
|
* @bases: bases of the DL representation.
|
|
* @nb_quantities: number of quantities in the DL representation.
|
|
* @dlrep: DL representation to prove.
|
|
* @modulus: modulus of the group.
|
|
*
|
|
* Creates a new #CrypticZkpkSchnorr.
|
|
* The non-interactive version is a signature scheme secure under the so-called
|
|
* random oracle model due to Fiat-Shamir, in practice the hash function is the oracle function.
|
|
*
|
|
* Return value: a newly created #CrypticZkpkSchnorr object; or NULL if an error
|
|
* occured
|
|
**/
|
|
CrypticZkpkSchnorr*
|
|
cryptic_zkpk_schnorr_new(BIGNUM **bases, int nb_quantities, BIGNUM *modulus)
|
|
{
|
|
int rc = CRYPTIC_ERROR_UNDEFINED;
|
|
|
|
CrypticZkpkSchnorr *shn;
|
|
shn = g_object_new(CRYPTIC_TYPE_ZKPKSCHNORR, NULL);
|
|
|
|
int i;
|
|
|
|
goto_cleanup_if_fail_with_rc_with_warning(nb_quantities > 0,
|
|
CRYPTIC_PROOF_GENERIC_NB_QUANTITIES_NULL);
|
|
goto_cleanup_if_fail_with_rc_with_warning(bases != NULL,
|
|
CRYPTIC_PROOF_GENERIC_BASES_MISSING);
|
|
for(i=0;i<shn->nb_quantities;i++){
|
|
goto_cleanup_if_fail_with_rc_with_warning(bases[i] != NULL,
|
|
CRYPTIC_PROOF_GENERIC_BASES_MISSING);
|
|
}
|
|
goto_cleanup_if_fail_with_rc_with_warning(modulus != NULL,
|
|
CRYPTIC_PROOF_GENERIC_MODULUS_MISSING);
|
|
|
|
shn->nb_quantities = nb_quantities;
|
|
|
|
cryptic_release_bn(shn->modulus);
|
|
goto_cleanup_if_fail_with_rc_with_warning_openssl(shn->modulus = BN_new());
|
|
goto_cleanup_if_fail_with_rc_with_warning_openssl(BN_copy(shn->modulus, modulus));
|
|
|
|
cryptic_release(shn->bases);
|
|
shn->bases = g_malloc0(nb_quantities * sizeof (**shn->bases));
|
|
if(shn->bases == NULL){
|
|
rc = CRYPTIC_MEMORY_ALLOCATION_FAILURE;
|
|
goto cleanup;
|
|
}
|
|
|
|
for(i=0;i<nb_quantities;i++){
|
|
shn->bases[i] = NULL;
|
|
goto_cleanup_if_fail_with_rc_with_warning_openssl(shn->bases[i] = BN_new());
|
|
goto_cleanup_if_fail_with_rc_with_warning_openssl(BN_copy(shn->bases[i], bases[i]));
|
|
}
|
|
|
|
return shn;
|
|
cleanup:
|
|
cryptic_release_gobject(shn);
|
|
return NULL;
|
|
}
|
|
|
|
/**
|
|
* cryptic_zkpk_schnorr_round1:
|
|
* @shn: a #CrypticZkpkSchnorr object
|
|
*
|
|
* Compute the commitment of the proof.
|
|
* All randoms are picked into this function.
|
|
*
|
|
* Return value: #CRYPTIC_NO_ERROR if successful, an error code otherwise.
|
|
*/
|
|
/*
|
|
To work with each bit of the commitment:
|
|
|
|
cryptic_release(shn->randoms);
|
|
shn->randoms = g_malloc0((shn->nb_quantities*size_hash) * sizeof (**shn->randoms));
|
|
|
|
/* commitment = MUL bases[i]^rij */
|
|
/* i quantities in the DL representation */
|
|
/* j is the number of bit of the hash *
|
|
goto_cleanup_if_fail_with_rc_with_warning_openssl(tmp1 = BN_new());
|
|
goto_cleanup_if_fail_with_rc_with_warning_openssl(shn->commitment = BN_new());
|
|
goto_cleanup_if_fail_with_rc_with_warning_openssl(BN_set_word(shn->commitment,1) == 1);
|
|
for(j=0;j<size_hash;j++){
|
|
for(i=0;i<shn->nb_quantities;i++){
|
|
goto_cleanup_if_fail_with_rc_with_warning_openssl(shn->randoms[i+(j*shn->nb_quantities)] = BN_new());
|
|
if( (rc = cryptic_find_random_with_range_value(shn->randoms[i+(j*shn->nb_quantities)],shn->modulus)) < 0)
|
|
goto cleanup;
|
|
goto_cleanup_if_fail_with_rc_with_warning_openssl(BN_mod_exp(tmp1,shn->bases[i],shn->randoms[i+(j*shn->nb_quantities)],shn->modulus,ctx) == 1);
|
|
goto_cleanup_if_fail_with_rc_with_warning_openssl(BN_mod_mul(shn->commitment,shn->commitment,tmp1,shn->modulus,ctx) == 1);
|
|
}
|
|
}
|
|
|
|
[...]
|
|
|
|
cryptic_release(shn->responses);
|
|
shn->responses = g_malloc0((shn->nb_quantities*size_hash) * sizeof (**shn->responses));
|
|
|
|
/* commitment = MUL bases[i]^rij */
|
|
/* sij = rij + ci xi -> ij responses -> e.g. 256 * 4)*/
|
|
/* ci = (ith bit) * 2^i */
|
|
/* j is the number of bit of the hash *
|
|
BIGNUM *c,*two,*exp,*count;
|
|
goto_cleanup_if_fail_with_rc_with_warning_openssl(c = BN_new());
|
|
goto_cleanup_if_fail_with_rc_with_warning_openssl(two = BN_new());
|
|
goto_cleanup_if_fail_with_rc_with_warning_openssl(exp = BN_new());
|
|
goto_cleanup_if_fail_with_rc_with_warning_openssl(count = BN_new());
|
|
BN_set_word(two,2);
|
|
int t,z,k,y;
|
|
for(j=0;j<(size_hash/8);j++){
|
|
t=(int)*(hash+((size_hash/8)-j-1));
|
|
for(z=0;z<8;z++){
|
|
k=1<<z;
|
|
y=t&k;
|
|
if(y!=0){ //ci = 2^i
|
|
BN_set_word(exp,(j*8)+z);
|
|
goto_cleanup_if_fail_with_rc_with_warning_openssl(BN_exp(c,two,exp,ctx) == 1);
|
|
goto_cleanup_if_fail_with_rc_with_warning_openssl(BN_add(count,count,c) == 1);
|
|
for(i=0;i<shn->nb_quantities;i++){
|
|
goto_cleanup_if_fail_with_rc_with_warning_openssl(shn->responses[(((j*8)+z)*shn->nb_quantities+i)] = BN_new());
|
|
goto_cleanup_if_fail_with_rc_with_warning_openssl(BN_mod_mul(tmp1,quantities[i],c,order,ctx) == 1);
|
|
goto_cleanup_if_fail_with_rc_with_warning_openssl(BN_mod_add(shn->responses[ (((j*8)+z)*shn->nb_quantities+i) ],shn->randoms[ (((j*8)+z)*shn->nb_quantities+i) ],tmp1,order,ctx) == 1);
|
|
}
|
|
}else{ //ci = 0 -> sij = rij
|
|
for(i=0;i<shn->nb_quantities;i++){
|
|
goto_cleanup_if_fail_with_rc_with_warning_openssl(shn->responses[(((j*8)+z)*shn->nb_quantities+i)] = BN_new());
|
|
BN_copy(shn->responses[ (((j*8)+z)*shn->nb_quantities+i) ],shn->randoms[ (((j*8)+z)*shn->nb_quantities+i) ]);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
*/
|
|
|
|
|
|
int cryptic_zkpk_schnorr_round1(CrypticZkpkSchnorr *shn)
|
|
{
|
|
int rc = CRYPTIC_ERROR_UNDEFINED;
|
|
|
|
int i;
|
|
|
|
BIGNUM *tmp1 = NULL;
|
|
BN_CTX *ctx = NULL;
|
|
|
|
goto_cleanup_if_fail_with_rc_with_warning(shn->modulus != NULL,
|
|
CRYPTIC_PROOF_GENERIC_STRUCTURE_NOT_INIT);
|
|
|
|
goto_cleanup_if_fail_with_rc_with_warning_openssl(tmp1 = BN_new());
|
|
|
|
goto_cleanup_if_fail_with_rc_with_warning_openssl(ctx = BN_CTX_new());
|
|
|
|
cryptic_release(shn->randoms);
|
|
shn->randoms = g_malloc0((shn->nb_quantities) * sizeof (**shn->randoms));
|
|
if(shn->randoms == NULL){
|
|
rc = CRYPTIC_MEMORY_ALLOCATION_FAILURE;
|
|
goto cleanup;
|
|
}
|
|
|
|
cryptic_release_bn(shn->commitment);
|
|
goto_cleanup_if_fail_with_rc_with_warning_openssl(shn->commitment = BN_new());
|
|
goto_cleanup_if_fail_with_rc_with_warning_openssl(BN_set_word(shn->commitment,1) == 1);
|
|
|
|
for(i=0;i<shn->nb_quantities;i++){
|
|
shn->randoms[i] = NULL;
|
|
goto_cleanup_if_fail_with_rc_with_warning_openssl(shn->randoms[i] = BN_new());
|
|
cryptic_check_good_rc(cryptic_find_random_with_range_value(shn->randoms[i],shn->modulus));
|
|
goto_cleanup_if_fail_with_rc_with_warning_openssl(BN_mod_exp(tmp1,shn->bases[i],shn->randoms[i],shn->modulus,ctx) == 1);
|
|
goto_cleanup_if_fail_with_rc_with_warning_openssl(BN_mod_mul(shn->commitment,shn->commitment,tmp1,shn->modulus,ctx) == 1);
|
|
}
|
|
|
|
rc = CRYPTIC_NO_ERROR;
|
|
cleanup:
|
|
cryptic_release_ctx(ctx);
|
|
cryptic_release_bn(tmp1);
|
|
return rc;
|
|
}
|
|
|
|
/**
|
|
* cryptic_zkpk_schnorr_round1_one_random_chosen:
|
|
* @shn: a #CrypticZkpkSchnorr object
|
|
* @random: random value
|
|
* @position: index of the base where use the random. Start at 0.
|
|
*
|
|
* Compute the proof.
|
|
* All randoms but one are picked into this function.
|
|
*
|
|
* Return value: #CRYPTIC_NO_ERROR if successful, an error code otherwise.
|
|
*/
|
|
int cryptic_zkpk_schnorr_round1_one_random_chosen(CrypticZkpkSchnorr *shn,
|
|
BIGNUM *random, int position)
|
|
{
|
|
int rc = CRYPTIC_ERROR_UNDEFINED;
|
|
|
|
int i;
|
|
BIGNUM *tmp1 = NULL;
|
|
BN_CTX *ctx = NULL;
|
|
|
|
goto_cleanup_if_fail_with_rc_with_warning(shn->modulus != NULL,
|
|
CRYPTIC_PROOF_GENERIC_STRUCTURE_NOT_INIT);
|
|
goto_cleanup_if_fail_with_rc_with_warning(random != NULL,
|
|
CRYPTIC_PROOF_GENERIC_RANDOMS_MISSING);
|
|
|
|
goto_cleanup_if_fail_with_rc_with_warning_openssl(tmp1 = BN_new());
|
|
|
|
goto_cleanup_if_fail_with_rc_with_warning_openssl(ctx = BN_CTX_new());
|
|
|
|
cryptic_release(shn->randoms);
|
|
shn->randoms = g_malloc0((shn->nb_quantities) * sizeof (**shn->randoms));
|
|
if(shn->randoms == NULL){
|
|
rc = CRYPTIC_MEMORY_ALLOCATION_FAILURE;
|
|
goto cleanup;
|
|
}
|
|
|
|
cryptic_release_bn(shn->commitment);
|
|
goto_cleanup_if_fail_with_rc_with_warning_openssl(shn->commitment = BN_new());
|
|
goto_cleanup_if_fail_with_rc_with_warning_openssl(BN_set_word(shn->commitment,1) == 1);
|
|
|
|
for(i=0;i<shn->nb_quantities;i++){
|
|
shn->randoms[i] = NULL;
|
|
goto_cleanup_if_fail_with_rc_with_warning_openssl(shn->randoms[i] = BN_new());
|
|
if(i != position){
|
|
cryptic_check_good_rc(cryptic_find_random_with_range_value(shn->randoms[i],shn->modulus));
|
|
}else{
|
|
goto_cleanup_if_fail_with_rc_with_warning_openssl(BN_copy(shn->randoms[i],random));
|
|
}
|
|
goto_cleanup_if_fail_with_rc_with_warning_openssl(BN_mod_exp(tmp1,shn->bases[i],shn->randoms[i],shn->modulus,ctx) == 1);
|
|
goto_cleanup_if_fail_with_rc_with_warning_openssl(BN_mod_mul(shn->commitment,shn->commitment,tmp1,shn->modulus,ctx) == 1);
|
|
}
|
|
|
|
rc = CRYPTIC_NO_ERROR;
|
|
cleanup:
|
|
cryptic_release_ctx(ctx);
|
|
cryptic_release_bn(tmp1);
|
|
return rc;
|
|
}
|
|
|
|
/**
|
|
* cryptic_zkpk_schnorr_round1_randoms_chosen:
|
|
* @shn: a #CrypticZkpkSchnorr object
|
|
* @randoms: random value
|
|
*
|
|
* Compute the proof.
|
|
* All randoms are picked out of this function.
|
|
*
|
|
* Return value: #CRYPTIC_NO_ERROR if successful, an error code otherwise.
|
|
*/
|
|
int cryptic_zkpk_schnorr_round1_randoms_chosen(CrypticZkpkSchnorr *shn,
|
|
BIGNUM **randoms)
|
|
{
|
|
int rc = CRYPTIC_ERROR_UNDEFINED;
|
|
|
|
int i;
|
|
BIGNUM *tmp1 = NULL;
|
|
BN_CTX *ctx = NULL;
|
|
|
|
goto_cleanup_if_fail_with_rc_with_warning(shn->modulus != NULL,
|
|
CRYPTIC_PROOF_GENERIC_STRUCTURE_NOT_INIT);
|
|
goto_cleanup_if_fail_with_rc_with_warning(randoms != NULL,
|
|
CRYPTIC_PROOF_GENERIC_RANDOMS_MISSING);
|
|
for(i=0;i<(shn->nb_quantities);i++){
|
|
goto_cleanup_if_fail_with_rc_with_warning(randoms[i] != NULL,
|
|
CRYPTIC_PROOF_GENERIC_RANDOMS_MISSING);
|
|
}
|
|
|
|
goto_cleanup_if_fail_with_rc_with_warning_openssl(tmp1 = BN_new());
|
|
cryptic_release_bn(shn->commitment);
|
|
goto_cleanup_if_fail_with_rc_with_warning_openssl(shn->commitment = BN_new());
|
|
goto_cleanup_if_fail_with_rc_with_warning_openssl(BN_set_word(shn->commitment,1) == 1);
|
|
|
|
goto_cleanup_if_fail_with_rc_with_warning_openssl(ctx = BN_CTX_new());
|
|
|
|
cryptic_release(shn->randoms);
|
|
shn->randoms = g_malloc0((shn->nb_quantities) * sizeof (**shn->randoms));
|
|
if(shn->randoms == NULL){
|
|
rc = CRYPTIC_MEMORY_ALLOCATION_FAILURE;
|
|
goto cleanup;
|
|
}
|
|
|
|
for(i=0;i<shn->nb_quantities;i++){
|
|
shn->randoms[i] = NULL;
|
|
goto_cleanup_if_fail_with_rc_with_warning_openssl(shn->randoms[i] = BN_new());
|
|
goto_cleanup_if_fail_with_rc_with_warning_openssl(BN_copy(shn->randoms[i],randoms[i]));
|
|
goto_cleanup_if_fail_with_rc_with_warning_openssl(BN_mod_exp(tmp1,shn->bases[i],shn->randoms[i],shn->modulus,ctx) == 1);
|
|
goto_cleanup_if_fail_with_rc_with_warning_openssl(BN_mod_mul(shn->commitment,shn->commitment,tmp1,shn->modulus,ctx) == 1);
|
|
}
|
|
|
|
rc = CRYPTIC_NO_ERROR;
|
|
cleanup:
|
|
cryptic_release_ctx(ctx);
|
|
cryptic_release_bn(tmp1);
|
|
return rc;
|
|
}
|
|
|
|
/**
|
|
* cryptic_zkpk_schnorr_round2:
|
|
* @shn: a #CrypticZkpkSchnorr object
|
|
* @order: group order used as the modulus when computing responses
|
|
* @quantities: quantities to prove
|
|
* @hash: hash value
|
|
*
|
|
* Compute the responses for the proof.
|
|
*
|
|
* Return value: #CRYPTIC_NO_ERROR if successful, an error code otherwise.
|
|
*/
|
|
int cryptic_zkpk_schnorr_round2(CrypticZkpkSchnorr *shn,
|
|
BIGNUM *order, BIGNUM *challenge, BIGNUM **quantities)
|
|
{
|
|
int rc = CRYPTIC_ERROR_UNDEFINED;
|
|
|
|
int i;
|
|
BIGNUM *tmp1 = NULL;
|
|
BN_CTX *ctx = NULL;
|
|
|
|
goto_cleanup_if_fail_with_rc_with_warning(shn->randoms != NULL,
|
|
CRYPTIC_PROOF_GENERIC_ROUND1_NOT_DONE);
|
|
goto_cleanup_if_fail_with_rc_with_warning(challenge != NULL,
|
|
CRYPTIC_PROOF_GENERIC_HASH_OR_CHALLENGE_MISSING);
|
|
goto_cleanup_if_fail_with_rc_with_warning(order != NULL,
|
|
CRYPTIC_PROOF_GENERIC_ORDER_MISSING);
|
|
goto_cleanup_if_fail_with_rc_with_warning(BN_num_bits(challenge) >= CRYPTIC_SCHNORR_CHALLENGE_MIN_SIZE,
|
|
CRYPTIC_PROOF_GENERIC_CHALLENGE_SIZE_NOT_VALID);
|
|
|
|
goto_cleanup_if_fail_with_rc_with_warning_openssl(tmp1 = BN_new());
|
|
|
|
goto_cleanup_if_fail_with_rc_with_warning_openssl(ctx = BN_CTX_new());
|
|
|
|
cryptic_release(shn->responses);
|
|
shn->responses = g_malloc0((shn->nb_quantities) * sizeof (**shn->responses));
|
|
if(shn->responses == NULL){
|
|
rc = CRYPTIC_MEMORY_ALLOCATION_FAILURE;
|
|
goto cleanup;
|
|
}
|
|
|
|
for(i=0;i<shn->nb_quantities;i++){
|
|
shn->responses[i] = NULL;
|
|
goto_cleanup_if_fail_with_rc_with_warning_openssl(shn->responses[i] = BN_new());
|
|
goto_cleanup_if_fail_with_rc_with_warning_openssl(BN_mod_mul(tmp1,quantities[i],challenge,order,ctx) == 1);
|
|
goto_cleanup_if_fail_with_rc_with_warning_openssl(BN_mod_add(shn->responses[i],shn->randoms[i],tmp1,order,ctx) == 1);
|
|
}
|
|
|
|
rc = CRYPTIC_NO_ERROR;
|
|
cleanup:
|
|
cryptic_release_ctx(ctx);
|
|
cryptic_release_bn(tmp1);
|
|
return rc;
|
|
}
|
|
|
|
/**
|
|
* cryptic_zkpk_schnorr_round2_without_order:
|
|
* @shn: a #CrypticZkpkSchnorr object
|
|
* @quantities: quantities to prove
|
|
* @hash: hash value
|
|
*
|
|
* Compute the responses for the proof.
|
|
* The responses are not computed using the group order as modulus.
|
|
*
|
|
* Return value: #CRYPTIC_NO_ERROR if successful, an error code otherwise.
|
|
*/
|
|
int cryptic_zkpk_schnorr_round2_without_order(CrypticZkpkSchnorr *shn,
|
|
BIGNUM *challenge, BIGNUM **quantities)
|
|
{
|
|
int rc = CRYPTIC_ERROR_UNDEFINED;
|
|
|
|
int i;
|
|
BIGNUM *tmp1 = NULL;
|
|
BN_CTX *ctx = NULL;
|
|
|
|
goto_cleanup_if_fail_with_rc_with_warning(shn->randoms != NULL,
|
|
CRYPTIC_PROOF_GENERIC_ROUND1_NOT_DONE);
|
|
goto_cleanup_if_fail_with_rc_with_warning(challenge != NULL,
|
|
CRYPTIC_PROOF_GENERIC_HASH_OR_CHALLENGE_MISSING);
|
|
goto_cleanup_if_fail_with_rc_with_warning(BN_num_bits(challenge) >= CRYPTIC_SCHNORR_CHALLENGE_MIN_SIZE,
|
|
CRYPTIC_PROOF_GENERIC_CHALLENGE_SIZE_NOT_VALID);
|
|
goto_cleanup_if_fail_with_rc_with_warning(quantities != NULL,
|
|
CRYPTIC_PROOF_GENERIC_QUANTITY_MISSING);
|
|
for(i=0;i<shn->nb_quantities;i++){
|
|
goto_cleanup_if_fail_with_rc_with_warning(quantities[i] != NULL,
|
|
CRYPTIC_PROOF_GENERIC_QUANTITY_MISSING);
|
|
}
|
|
|
|
goto_cleanup_if_fail_with_rc_with_warning_openssl(tmp1 = BN_new());
|
|
|
|
goto_cleanup_if_fail_with_rc_with_warning_openssl(ctx = BN_CTX_new());
|
|
|
|
cryptic_release(shn->responses);
|
|
shn->responses = g_malloc0((shn->nb_quantities) * sizeof (**shn->responses));
|
|
if(shn->responses == NULL){
|
|
rc = CRYPTIC_MEMORY_ALLOCATION_FAILURE;
|
|
goto cleanup;
|
|
}
|
|
|
|
for(i=0;i<shn->nb_quantities;i++){
|
|
shn->responses[i] = NULL;
|
|
goto_cleanup_if_fail_with_rc_with_warning_openssl(shn->responses[i] = BN_new());
|
|
goto_cleanup_if_fail_with_rc_with_warning_openssl(BN_mul(tmp1,quantities[i],challenge,ctx) == 1);
|
|
goto_cleanup_if_fail_with_rc_with_warning_openssl(BN_add(shn->responses[i],shn->randoms[i],tmp1) == 1);
|
|
}
|
|
|
|
rc = CRYPTIC_NO_ERROR;
|
|
cleanup:
|
|
cryptic_release_ctx(ctx);
|
|
cryptic_release_bn(tmp1);
|
|
return rc;
|
|
}
|
|
|
|
/**
|
|
* cryptic_zkpk_schnorr_verify_noninteractive_proof:
|
|
* @shn: a #CrypticZkpkSchnorr object
|
|
* @hash: hash received
|
|
* @responses:(array length=shn->nb_quantities): responses
|
|
*
|
|
* Compute the commitment of the proof.
|
|
* It will then be used to computed the hash.
|
|
*
|
|
* Return value: #CRYPTIC_NO_ERROR if successful, an error code otherwise.
|
|
*/
|
|
/*
|
|
To work with each bit of the commitment:
|
|
|
|
for(j=0;j<size_hash;j++){
|
|
for(i=0;i<shn->nb_quantities;i++){
|
|
if(BN_is_negative(responses[i+(j*shn->nb_quantities)])){
|
|
BN_copy(tmp2,shn->bases[i]);
|
|
shn->bases[i] = BN_mod_inverse(NULL,shn->bases[i],shn->modulus,ctx);
|
|
}
|
|
goto_cleanup_if_fail_with_rc_with_warning_openssl(BN_mod_exp(tmp1,shn->bases[i],responses[i+(j*shn->nb_quantities)],shn->modulus,ctx) == 1);
|
|
if(BN_is_negative(responses[i+(j*shn->nb_quantities)])) BN_copy(shn->bases[i],tmp2);
|
|
goto_cleanup_if_fail_with_rc_with_warning_openssl(BN_mod_mul(check,check,tmp1,shn->modulus,ctx) == 1);
|
|
}
|
|
}
|
|
|
|
*/
|
|
int
|
|
cryptic_zkpk_schnorr_verify_noninteractive_proof(CrypticZkpkSchnorr *shn, BIGNUM *dlrep, BIGNUM *hash, BIGNUM **responses)
|
|
{
|
|
int rc = CRYPTIC_ERROR_UNDEFINED;
|
|
|
|
int i;
|
|
BIGNUM *tmp1 = NULL, *tmp2 = NULL;
|
|
BN_CTX *ctx = NULL;
|
|
|
|
goto_cleanup_if_fail_with_rc_with_warning(dlrep != NULL,
|
|
CRYPTIC_PROOF_GENERIC_DLREP_MISSING);
|
|
goto_cleanup_if_fail_with_rc_with_warning(hash != NULL,
|
|
CRYPTIC_PROOF_GENERIC_CHALLENGE_MISSING);
|
|
goto_cleanup_if_fail_with_rc_with_warning(responses != NULL,
|
|
CRYPTIC_PROOF_GENERIC_RESPONSES_MISSING);
|
|
for(i=0;i<(shn->nb_quantities);i++){
|
|
goto_cleanup_if_fail_with_rc_with_warning(responses[i] != NULL,
|
|
CRYPTIC_PROOF_GENERIC_RESPONSES_MISSING);
|
|
}
|
|
|
|
goto_cleanup_if_fail_with_rc_with_warning_openssl(tmp1 = BN_new());
|
|
goto_cleanup_if_fail_with_rc_with_warning_openssl(tmp2 = BN_new());
|
|
cryptic_release_bn(shn->commitment);
|
|
goto_cleanup_if_fail_with_rc_with_warning_openssl(shn->commitment = BN_new());
|
|
|
|
goto_cleanup_if_fail_with_rc_with_warning_openssl(ctx = BN_CTX_new());
|
|
|
|
/* s = r + cx */
|
|
goto_cleanup_if_fail_with_rc_with_warning_openssl(BN_mod_inverse(tmp1,dlrep,shn->modulus,ctx)); /* Comment for s = r - cx */
|
|
goto_cleanup_if_fail_with_rc_with_warning_openssl(BN_mod_exp(shn->commitment,tmp1,hash,shn->modulus,ctx) == 1);
|
|
|
|
for(i=0;i<shn->nb_quantities;i++){
|
|
/* WARNING */
|
|
/* The exponentiation with a negative nb does not its sign into account */
|
|
/* So when the exponent is negative, it is enough to inverse the base */
|
|
if(BN_is_negative(responses[i])){
|
|
goto_cleanup_if_fail_with_rc_with_warning_openssl(BN_mod_inverse(tmp1,shn->bases[i],shn->modulus,ctx));
|
|
}else{
|
|
goto_cleanup_if_fail_with_rc_with_warning_openssl(BN_copy(tmp1,shn->bases[i]));
|
|
}
|
|
goto_cleanup_if_fail_with_rc_with_warning_openssl(BN_mod_exp(tmp1,tmp1,responses[i],shn->modulus,ctx) == 1);
|
|
goto_cleanup_if_fail_with_rc_with_warning_openssl(BN_mod_mul(shn->commitment,shn->commitment,tmp1,shn->modulus,ctx) == 1);
|
|
}
|
|
|
|
rc = CRYPTIC_NO_ERROR;
|
|
cleanup:
|
|
cryptic_release_ctx(ctx);
|
|
cryptic_release_bn(tmp1);
|
|
cryptic_release_bn(tmp2);
|
|
return rc;
|
|
}
|
|
|
|
/**
|
|
* cryptic_zkpk_schnorr_verify_interactive_proof:
|
|
* @shn: a #CrypticZkpkSchnorr object
|
|
* @hash: hash received
|
|
* @responses:(array length=shn->nb_quantities): responses
|
|
*
|
|
* Compute the commitment of the proof.
|
|
*
|
|
* Return value: 1 if interactive proof successful, 0 if the proof is bas, an error code otherwise.
|
|
*/
|
|
int
|
|
cryptic_zkpk_schnorr_verify_interactive_proof(CrypticZkpkSchnorr *shn, BIGNUM *dlrep, BIGNUM *commitment, BIGNUM *challenge, BIGNUM **responses)
|
|
{
|
|
int rc = CRYPTIC_ERROR_UNDEFINED;
|
|
|
|
int i;
|
|
int res;
|
|
BIGNUM *tmp1 = NULL, *tmp2 = NULL;
|
|
BN_CTX *ctx = NULL;
|
|
|
|
goto_cleanup_if_fail_with_rc_with_warning(dlrep != NULL,
|
|
CRYPTIC_PROOF_GENERIC_DLREP_MISSING);
|
|
goto_cleanup_if_fail_with_rc_with_warning(challenge != NULL,
|
|
CRYPTIC_PROOF_GENERIC_CHALLENGE_MISSING);
|
|
goto_cleanup_if_fail_with_rc_with_warning(responses != NULL,
|
|
CRYPTIC_PROOF_GENERIC_RESPONSES_MISSING);
|
|
for(i=0;i<(shn->nb_quantities);i++){
|
|
goto_cleanup_if_fail_with_rc_with_warning(responses[i] != NULL,
|
|
CRYPTIC_PROOF_GENERIC_RESPONSES_MISSING);
|
|
}
|
|
|
|
goto_cleanup_if_fail_with_rc_with_warning_openssl(tmp1 = BN_new());
|
|
goto_cleanup_if_fail_with_rc_with_warning_openssl(tmp2 = BN_new());
|
|
cryptic_release_bn(shn->commitment);
|
|
goto_cleanup_if_fail_with_rc_with_warning_openssl(shn->commitment = BN_new());
|
|
|
|
goto_cleanup_if_fail_with_rc_with_warning_openssl(ctx = BN_CTX_new());
|
|
|
|
/* s = r + cx */
|
|
goto_cleanup_if_fail_with_rc_with_warning_openssl(BN_mod_inverse(tmp1,dlrep,shn->modulus,ctx)); /* Comment for s = r - cx */
|
|
goto_cleanup_if_fail_with_rc_with_warning_openssl(BN_mod_exp(shn->commitment,tmp1,challenge,shn->modulus,ctx) == 1);
|
|
|
|
for(i=0;i<shn->nb_quantities;i++){
|
|
/* WARNING */
|
|
/* The exponentiation with a negative nb does not its sign into account */
|
|
/* So when the exponent is negative, it is enough to inverse the base */
|
|
if(BN_is_negative(responses[i])){
|
|
goto_cleanup_if_fail_with_rc_with_warning_openssl(BN_mod_inverse(tmp1,shn->bases[i],shn->modulus,ctx));
|
|
}else{
|
|
goto_cleanup_if_fail_with_rc_with_warning_openssl(BN_copy(tmp1,shn->bases[i]));
|
|
}
|
|
goto_cleanup_if_fail_with_rc_with_warning_openssl(BN_mod_exp(tmp1,tmp1,responses[i],shn->modulus,ctx) == 1);
|
|
goto_cleanup_if_fail_with_rc_with_warning_openssl(BN_mod_mul(shn->commitment,shn->commitment,tmp1,shn->modulus,ctx) == 1);
|
|
}
|
|
|
|
if(BN_ucmp(shn->commitment,commitment) == 0)
|
|
res= 1;
|
|
else
|
|
res = 0;
|
|
|
|
rc = CRYPTIC_NO_ERROR;
|
|
cleanup:
|
|
cryptic_release_ctx(ctx);
|
|
cryptic_release_bn(tmp1);
|
|
cryptic_release_bn(tmp2);
|
|
if(rc != CRYPTIC_NO_ERROR) return rc;
|
|
return res;
|
|
}
|
|
|
|
/**
|
|
* cryptic_zkpk_schnorr_get_randoms:
|
|
* @shn: a #CrypticZkpkSchnorr object
|
|
*
|
|
* Getter.
|
|
*
|
|
* Return value: BIGNUM** randoms
|
|
*/
|
|
BIGNUM**
|
|
cryptic_zkpk_schnorr_get_randoms(CrypticZkpkSchnorr *shn)
|
|
{
|
|
cryptic_return_null_if_fail(shn->randoms);
|
|
return shn->randoms;
|
|
}
|
|
|
|
/**
|
|
* cryptic_zkpk_schnorr_get_i_random:
|
|
* @shn: a #CrypticZkpkSchnorr object
|
|
*
|
|
* Getter of the random at the index given.
|
|
*
|
|
* Return value: BIGNUM* randoms[i]
|
|
*/
|
|
BIGNUM*
|
|
cryptic_zkpk_schnorr_get_i_random(CrypticZkpkSchnorr *shn, int i)
|
|
{
|
|
if (shn->randoms && i < shn->nb_quantities){
|
|
if (shn->randoms[i]) return shn->randoms[i];
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
/**
|
|
* cryptic_zkpk_schnorr_get_commitment:
|
|
* @shn: a #CrypticZkpkSchnorr object
|
|
*
|
|
* Getter.
|
|
*
|
|
* Return value: BIGNUM* commitment
|
|
*/
|
|
BIGNUM*
|
|
cryptic_zkpk_schnorr_get_commitment(CrypticZkpkSchnorr *shn)
|
|
{
|
|
cryptic_return_null_if_fail(shn->commitment);
|
|
return shn->commitment;
|
|
}
|
|
|
|
/**
|
|
* cryptic_zkpk_schnorr_get_responses:
|
|
* @shn: a #CrypticZkpkSchnorr object
|
|
*
|
|
* Getter.
|
|
*
|
|
* Return value: BIGNUM** responses
|
|
*/
|
|
BIGNUM**
|
|
cryptic_zkpk_schnorr_get_responses(CrypticZkpkSchnorr *shn)
|
|
{
|
|
cryptic_return_null_if_fail(shn->responses);
|
|
return shn->responses;
|
|
}
|
|
|
|
/**
|
|
* cryptic_zkpk_schnorr_get_i_response:
|
|
* @shn: a #CrypticZkpkSchnorr object
|
|
*
|
|
* Getter of the response at the index given.
|
|
*
|
|
* Return value: BIGNUM* responses[i]
|
|
*/
|
|
BIGNUM*
|
|
cryptic_zkpk_schnorr_get_i_response(CrypticZkpkSchnorr *shn, int i)
|
|
{
|
|
if (shn->responses && i < shn->nb_quantities){
|
|
if (shn->responses[i]) return shn->responses[i];
|
|
}
|
|
return NULL;
|
|
}
|