This repository has been archived on 2023-02-21. You can view files and clone it, but cannot push or open issues or pull requests.
cryptic/cryptic/protocols/pok_schnorr/schnorr_zkpk.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;
}