894 lines
27 KiB
C
894 lines
27 KiB
C
/*
|
|
* Copyright 2023 The Tongsuo Project Authors. All Rights Reserved.
|
|
*
|
|
* Licensed under the Apache License 2.0 (the "License"). You may not use
|
|
* this file except in compliance with the License. You can obtain a copy
|
|
* in the file LICENSE in the source distribution or at
|
|
* https://github.com/Tongsuo-Project/Tongsuo/blob/master/LICENSE.txt
|
|
*/
|
|
|
|
#include <openssl/err.h>
|
|
#include <crypto/ec.h>
|
|
#include <crypto/ec/ec_local.h>
|
|
#include <crypto/zkp/common/zkp_util.h>
|
|
#include "range_proof.h"
|
|
|
|
DEFINE_STACK_OF(BIGNUM)
|
|
DEFINE_STACK_OF(EC_POINT)
|
|
DEFINE_STACK_OF(BP_VARIABLE)
|
|
|
|
static void bp_range_proof_cleanup(BP_RANGE_PROOF *proof);
|
|
|
|
BP_RANGE_PROOF *bp_range_proof_alloc(const EC_GROUP *group)
|
|
{
|
|
BP_RANGE_PROOF *proof = NULL;
|
|
|
|
if (group == NULL) {
|
|
ERR_raise(ERR_LIB_ZKP_BP, ERR_R_PASSED_NULL_PARAMETER);
|
|
return NULL;
|
|
}
|
|
|
|
proof = OPENSSL_zalloc(sizeof(*proof));
|
|
if (proof == NULL) {
|
|
ERR_raise(ERR_LIB_ZKP_BP, ERR_R_MALLOC_FAILURE);
|
|
return NULL;
|
|
}
|
|
|
|
if (!(proof->A = EC_POINT_new(group))
|
|
|| !(proof->S = EC_POINT_new(group))
|
|
|| !(proof->T1 = EC_POINT_new(group))
|
|
|| !(proof->T2 = EC_POINT_new(group))
|
|
|| !(proof->taux = BN_new())
|
|
|| !(proof->mu = BN_new())
|
|
|| !(proof->tx = BN_new()))
|
|
goto err;
|
|
|
|
proof->references = 1;
|
|
if ((proof->lock = CRYPTO_THREAD_lock_new()) == NULL) {
|
|
ERR_raise(ERR_LIB_ZKP_BP, ERR_R_MALLOC_FAILURE);
|
|
goto err;
|
|
}
|
|
|
|
return proof;
|
|
err:
|
|
BP_RANGE_PROOF_free(proof);
|
|
return NULL;
|
|
}
|
|
|
|
/** Creates a new BP_RANGE_CTX object
|
|
* \param pp BP_PUB_PARAM object
|
|
* \param witness BP_WITNESS object
|
|
* \param transcript ZKP_TRANSCRIPT object
|
|
* \return newly created BP_RANGE_CTX object or NULL in case of an error
|
|
*/
|
|
BP_RANGE_CTX *BP_RANGE_CTX_new(BP_PUB_PARAM *pp, BP_WITNESS *witness,
|
|
ZKP_TRANSCRIPT *transcript)
|
|
{
|
|
BP_RANGE_CTX *ctx = NULL;
|
|
|
|
if (pp == NULL || transcript == NULL) {
|
|
ERR_raise(ERR_LIB_ZKP_BP, ERR_R_PASSED_NULL_PARAMETER);
|
|
return NULL;
|
|
}
|
|
|
|
ctx = OPENSSL_zalloc(sizeof(*ctx));
|
|
if (ctx == NULL) {
|
|
ERR_raise(ERR_LIB_ZKP_BP, ERR_R_MALLOC_FAILURE);
|
|
return NULL;
|
|
}
|
|
|
|
if (!BP_PUB_PARAM_up_ref(pp))
|
|
goto err;
|
|
|
|
ctx->pp = pp;
|
|
|
|
if (!BP_WITNESS_up_ref(witness))
|
|
goto err;
|
|
|
|
ctx->witness = witness;
|
|
|
|
ctx->transcript = transcript;
|
|
|
|
return ctx;
|
|
|
|
err:
|
|
BP_RANGE_CTX_free(ctx);
|
|
return NULL;
|
|
}
|
|
|
|
/** Frees a BP_RANGE_CTX object
|
|
* \param ctx BP_RANGE_CTX object to be freed
|
|
*/
|
|
void BP_RANGE_CTX_free(BP_RANGE_CTX *ctx)
|
|
{
|
|
if (ctx == NULL)
|
|
return;
|
|
|
|
BP_PUB_PARAM_down_ref(ctx->pp);
|
|
BP_WITNESS_down_ref(ctx->witness);
|
|
OPENSSL_clear_free((void *)ctx, sizeof(*ctx));
|
|
}
|
|
|
|
/** Creates a new BP_RANGE_PROOF object
|
|
* \param pp BP_PUB_PARAM object
|
|
* \return newly created BP_RANGE_PROOF object or NULL in case of an error
|
|
*/
|
|
BP_RANGE_PROOF *BP_RANGE_PROOF_new(const BP_PUB_PARAM *pp)
|
|
{
|
|
if (pp == NULL) {
|
|
ERR_raise(ERR_LIB_ZKP_BP, ERR_R_PASSED_NULL_PARAMETER);
|
|
return NULL;
|
|
}
|
|
|
|
return bp_range_proof_alloc(pp->group);
|
|
}
|
|
|
|
/** Frees a BP_RANGE_PROOF object
|
|
* \param proof BP_RANGE_PROOF object to be freed
|
|
*/
|
|
void BP_RANGE_PROOF_free(BP_RANGE_PROOF *proof)
|
|
{
|
|
int ref;
|
|
|
|
if (proof == NULL)
|
|
return;
|
|
|
|
CRYPTO_DOWN_REF(&proof->references, &ref, proof->lock);
|
|
REF_PRINT_COUNT("BP_RANGE_PROOF", proof);
|
|
if (ref > 0)
|
|
return;
|
|
REF_ASSERT_ISNT(ref < 0);
|
|
|
|
EC_POINT_free(proof->A);
|
|
EC_POINT_free(proof->S);
|
|
EC_POINT_free(proof->T1);
|
|
EC_POINT_free(proof->T2);
|
|
BN_free(proof->taux);
|
|
BN_free(proof->mu);
|
|
BN_free(proof->tx);
|
|
bp_inner_product_proof_free(proof->ip_proof);
|
|
CRYPTO_THREAD_lock_free(proof->lock);
|
|
OPENSSL_free(proof);
|
|
}
|
|
|
|
static void bp_range_proof_cleanup(BP_RANGE_PROOF *proof)
|
|
{
|
|
if (proof == NULL)
|
|
return;
|
|
|
|
bp_inner_product_proof_free(proof->ip_proof);
|
|
proof->ip_proof = NULL;
|
|
}
|
|
|
|
/** Increases the internal reference count of a BP_RANGE_PROOF object.
|
|
* \param proof BP_RANGE_PROOF object
|
|
* \return 1 on success and 0 if an error occurred.
|
|
*/
|
|
int BP_RANGE_PROOF_up_ref(BP_RANGE_PROOF *proof)
|
|
{
|
|
int ref;
|
|
|
|
if (CRYPTO_UP_REF(&proof->references, &ref, proof->lock) <= 0)
|
|
return 0;
|
|
|
|
REF_PRINT_COUNT("BP_RANGE_PROOF", proof);
|
|
REF_ASSERT_ISNT(ref < 2);
|
|
return ((ref > 1) ? 1 : 0);
|
|
}
|
|
|
|
/** Decreases the internal reference count of a BP_RANGE_PROOF object.
|
|
* \param proof BP_RANGE_PROOF object
|
|
* \return 1 on success and 0 if an error occurred.
|
|
*/
|
|
int BP_RANGE_PROOF_down_ref(BP_RANGE_PROOF *proof)
|
|
{
|
|
int ref;
|
|
|
|
if (CRYPTO_DOWN_REF(&proof->references, &ref, proof->lock) <= 0)
|
|
return 0;
|
|
|
|
REF_PRINT_COUNT("BP_RANGE_PROOF", proof);
|
|
REF_ASSERT_ISNT(ref > 0);
|
|
return ((ref > 0) ? 1 : 0);
|
|
}
|
|
|
|
/** Prove computes the ZK rangeproof.
|
|
* \param ctx BP_RANGE_CTX object
|
|
* \param proof BP_RANGE_PROOF object
|
|
* \return 1 on success and 0 if an error occurred.
|
|
*/
|
|
int BP_RANGE_PROOF_prove(BP_RANGE_CTX *ctx, BP_RANGE_PROOF *proof)
|
|
{
|
|
int i, j, m = 0, n, ret = 0;
|
|
int bits, poly_num, witness_n, witness_r_n, witness_v_n, witness_padded_n;
|
|
int *aL = NULL, *aR = NULL;
|
|
ZKP_TRANSCRIPT *transcript;
|
|
BP_PUB_PARAM *pp;
|
|
BP_WITNESS *witness;
|
|
BIGNUM *witness_r, *witness_v;
|
|
BIGNUM *alpha, *rho, *tau1, *tau2, *bn0, *bn1, *bn2, *bn_1, *tmp;
|
|
BIGNUM *x, *y, *y_inv, *pow_y_inv, *z, *z2, *pow_zn, **pow_y = NULL;
|
|
BIGNUM *pow_2, *dv, *t, *t1, *t2, *r0, *r1, **sL = NULL, **sR = NULL;
|
|
BIGNUM **ll0 = NULL, **rr1 = NULL, **rr2 = NULL;
|
|
BIGNUM *g_scalar, *h_scalar, *l, *r;
|
|
STACK_OF(BIGNUM) *sk_G_scalars = NULL, *sk_H_scalars = NULL;
|
|
STACK_OF(BIGNUM) *sk_l = NULL, *sk_r = NULL;
|
|
STACK_OF(EC_POINT) *sk_G = NULL, *sk_H = NULL;
|
|
EC_POINT *P = NULL, *T = NULL, *U = NULL, *G, *H;
|
|
zkp_poly_points_t *poly_a = NULL, *poly_s = NULL, *poly_p = NULL;
|
|
const BIGNUM *order;
|
|
EC_GROUP *group;
|
|
BN_CTX *bn_ctx = NULL;
|
|
bp_inner_product_ctx_t *ip_ctx = NULL;
|
|
bp_inner_product_pub_param_t *ip_pp = NULL;
|
|
bp_inner_product_witness_t *ip_witness = NULL;
|
|
|
|
if (ctx == NULL || ctx->pp == NULL || ctx->witness == NULL || proof == NULL) {
|
|
ERR_raise(ERR_LIB_ZKP_BP, ERR_R_PASSED_NULL_PARAMETER);
|
|
return ret;
|
|
}
|
|
|
|
pp = ctx->pp;
|
|
witness = ctx->witness;
|
|
transcript = ctx->transcript;
|
|
group = pp->group;
|
|
order = EC_GROUP_get0_order(group);
|
|
|
|
bn_ctx = BN_CTX_new_ex(group->libctx);
|
|
if (bn_ctx == NULL)
|
|
goto err;
|
|
|
|
BN_CTX_start(bn_ctx);
|
|
alpha = BN_CTX_get(bn_ctx);
|
|
rho = BN_CTX_get(bn_ctx);
|
|
tau1 = BN_CTX_get(bn_ctx);
|
|
tau2 = BN_CTX_get(bn_ctx);
|
|
bn0 = BN_CTX_get(bn_ctx);
|
|
bn1 = BN_CTX_get(bn_ctx);
|
|
bn2 = BN_CTX_get(bn_ctx);
|
|
bn_1 = BN_CTX_get(bn_ctx);
|
|
x = BN_CTX_get(bn_ctx);
|
|
y = BN_CTX_get(bn_ctx);
|
|
y_inv = BN_CTX_get(bn_ctx);
|
|
pow_y_inv = BN_CTX_get(bn_ctx);
|
|
z = BN_CTX_get(bn_ctx);
|
|
z2 = BN_CTX_get(bn_ctx);
|
|
pow_zn = BN_CTX_get(bn_ctx);
|
|
pow_2 = BN_CTX_get(bn_ctx);
|
|
t1 = BN_CTX_get(bn_ctx);
|
|
t2 = BN_CTX_get(bn_ctx);
|
|
t = BN_CTX_get(bn_ctx);
|
|
r0 = BN_CTX_get(bn_ctx);
|
|
r1 = BN_CTX_get(bn_ctx);
|
|
dv = BN_CTX_get(bn_ctx);
|
|
if (dv == NULL)
|
|
goto err;
|
|
|
|
BN_zero(t1);
|
|
BN_zero(t2);
|
|
BN_zero(bn0);
|
|
BN_one(bn1);
|
|
BN_one(bn_1);
|
|
BN_set_negative(bn_1, 1);
|
|
BN_set_word(bn2, 2);
|
|
BN_one(pow_y_inv);
|
|
|
|
witness_n = sk_BP_VARIABLE_num(witness->sk_V);
|
|
witness_padded_n = zkp_next_power_of_two(witness_n);
|
|
if (witness_padded_n > ctx->pp->party_capacity) {
|
|
ERR_raise(ERR_LIB_ZKP_BP, ZKP_BP_R_EXCEEDS_PARTY_CAPACITY);
|
|
goto err;
|
|
}
|
|
|
|
for (i = witness_n; i < witness_padded_n; i++) {
|
|
if (!BP_WITNESS_commit(witness, NULL, bn0))
|
|
goto err;
|
|
}
|
|
|
|
witness_r_n = sk_BIGNUM_num(witness->sk_r);
|
|
witness_v_n = sk_BIGNUM_num(witness->sk_v);
|
|
witness_n = sk_BP_VARIABLE_num(witness->sk_V);
|
|
witness_padded_n = zkp_next_power_of_two(witness_n);
|
|
|
|
if (witness_r_n != witness_v_n || witness_v_n != witness_n) {
|
|
ERR_raise(ERR_LIB_ZKP_BP, ZKP_BP_R_WITNESS_INVALID);
|
|
goto err;
|
|
}
|
|
|
|
n = pp->gens_capacity * witness_padded_n;
|
|
poly_num = n * 2 + 1;
|
|
bits = pp->gens_capacity;
|
|
|
|
if (!zkp_is_power_of_two(n)) {
|
|
ERR_raise(ERR_LIB_ZKP_BP, ZKP_BP_R_RANGE_LEN_MUST_BE_POWER_OF_TWO);
|
|
goto err;
|
|
}
|
|
|
|
if (proof->ip_proof != NULL)
|
|
bp_range_proof_cleanup(proof);
|
|
|
|
if (!(P = EC_POINT_new(group))
|
|
|| !(T = EC_POINT_new(group))
|
|
|| !(U = EC_POINT_new(group)))
|
|
goto err;
|
|
|
|
if (!(aL = OPENSSL_zalloc(sizeof(*aL) * n))
|
|
|| !(aR = OPENSSL_zalloc(sizeof(*aL) * n))
|
|
|| !(sL = OPENSSL_zalloc(sizeof(*sL) * n))
|
|
|| !(sR = OPENSSL_zalloc(sizeof(*sR) * n))
|
|
|| !(sk_G = sk_EC_POINT_new_reserve(NULL, n))
|
|
|| !(sk_H = sk_EC_POINT_new_reserve(NULL, n))
|
|
|| !(sk_G_scalars = sk_BIGNUM_new_reserve(NULL, n))
|
|
|| !(sk_H_scalars = sk_BIGNUM_new_reserve(NULL, n))
|
|
|| !(sk_l = sk_BIGNUM_new_reserve(NULL, n))
|
|
|| !(sk_r = sk_BIGNUM_new_reserve(NULL, n))
|
|
|| !(pow_y = OPENSSL_zalloc(sizeof(*pow_y) * n))
|
|
|| !(ll0 = OPENSSL_zalloc(sizeof(*ll0) * n))
|
|
|| !(rr1 = OPENSSL_zalloc(sizeof(*rr1) * n))
|
|
|| !(rr2 = OPENSSL_zalloc(sizeof(*rr2) * n))) {
|
|
ERR_raise(ERR_LIB_ZKP_BP, ERR_R_MALLOC_FAILURE);
|
|
goto err;
|
|
}
|
|
|
|
if (!(poly_a = zkp_poly_points_new(poly_num))
|
|
|| !(poly_s = zkp_poly_points_new(poly_num))
|
|
|| !(poly_p = zkp_poly_points_new(poly_num)))
|
|
goto err;
|
|
|
|
if (!zkp_rand_range(alpha, order)
|
|
|| !zkp_rand_range(rho, order)
|
|
|| !zkp_rand_range(tau1, order)
|
|
|| !zkp_rand_range(tau2, order))
|
|
goto err;
|
|
|
|
/* (45) */
|
|
if (!zkp_random_bn_gen(group, sL, n, bn_ctx)
|
|
|| !zkp_random_bn_gen(group, sR, n, bn_ctx))
|
|
goto err;
|
|
|
|
for (i = 0; i < witness_n; i++) {
|
|
witness_v = sk_BIGNUM_value(witness->sk_v, i);
|
|
for (j = 0; j < bits; j++) {
|
|
if (!BN_div(dv, t, witness_v, bn2, bn_ctx))
|
|
goto err;
|
|
|
|
witness_v = dv;
|
|
m = i * pp->gens_capacity + j;
|
|
aL[m] = BN_is_one(t);
|
|
aR[m] = aL[m] - 1;
|
|
|
|
G = sk_EC_POINT_value(pp->sk_G, m);
|
|
H = sk_EC_POINT_value(pp->sk_H, m);
|
|
if (G == NULL || H == NULL)
|
|
goto err;
|
|
|
|
if (!zkp_poly_points_append(poly_a, G, aL[m] == 1 ? bn1 : bn0)
|
|
|| !zkp_poly_points_append(poly_a, H, aR[m] == -1 ? bn_1 : bn0)
|
|
|| !zkp_poly_points_append(poly_s, G, sL[m])
|
|
|| !zkp_poly_points_append(poly_s, H, sR[m]))
|
|
goto err;
|
|
}
|
|
}
|
|
|
|
if (!zkp_poly_points_append(poly_a, pp->H, alpha)
|
|
|| !zkp_poly_points_append(poly_s, pp->H, rho))
|
|
goto err;
|
|
|
|
/* (44, 47) */
|
|
if (!zkp_poly_points_mul(poly_a, proof->A, NULL, group, bn_ctx)
|
|
|| !zkp_poly_points_mul(poly_s, proof->S, NULL, group, bn_ctx))
|
|
goto err;
|
|
|
|
/* compute hash */
|
|
if (!ZKP_TRANSCRIPT_append_point(transcript, "A", proof->A, group)
|
|
|| !ZKP_TRANSCRIPT_append_point(transcript, "S", proof->S, group))
|
|
goto err;
|
|
|
|
if (!ZKP_TRANSCRIPT_challange(transcript, "y", y)
|
|
|| !ZKP_TRANSCRIPT_challange(transcript, "z", z))
|
|
goto err;
|
|
|
|
if (!BN_mod_sqr(z2, z, order, bn_ctx) || !BN_copy(pow_zn, z2)
|
|
|| !BN_mod_inverse(y_inv, y, order, bn_ctx))
|
|
goto err;
|
|
|
|
pow_y[0] = bn1;
|
|
BN_zero(proof->taux);
|
|
|
|
/*
|
|
* ll0 = aL - z * 1^n
|
|
* rr1 = aR + z * 1^n
|
|
* rr2 = z^(n+1) * 2^n
|
|
* r0 = y^n * (aR + z * 1^n) + z^(n+1) * 2^n = y^n * rr1 + rr2
|
|
* r1 = y^n * sR
|
|
* l = ll0 + sL * x
|
|
* r = y^n * (aR + z * 1^n + sR * x) + z^(n+1) * 2^n = y^n * (rr1 + sR * x) + rr2
|
|
* t1 = <ll0 * r1 + sL * r0>
|
|
* t2 = <r1 * r1> = <sL * y^n * sR>
|
|
*/
|
|
for (i = 0; i < witness_n; i++) {
|
|
witness_r = sk_BIGNUM_value(witness->sk_r, i);
|
|
BN_one(pow_2);
|
|
|
|
for (j = 0; j < bits; j++) {
|
|
m = i * bits + j;
|
|
if (m > 0) {
|
|
if ((pow_y[m] = BN_CTX_get(bn_ctx)) == NULL)
|
|
goto err;
|
|
|
|
if (!BN_mod_mul(pow_y[m], pow_y[m-1], y, order, bn_ctx))
|
|
goto err;
|
|
}
|
|
|
|
if ((ll0[m] = BN_CTX_get(bn_ctx)) == NULL
|
|
|| (rr1[m] = BN_CTX_get(bn_ctx)) == NULL
|
|
|| (rr2[m] = BN_CTX_get(bn_ctx)) == NULL)
|
|
goto err;
|
|
|
|
if (!BN_mod_sub(ll0[m], aL[m] == 1 ? bn1 : bn0, z, order, bn_ctx)
|
|
|| !BN_mod_mul(r1, pow_y[m], sR[m], order, bn_ctx)
|
|
|| !BN_mod_mul(t, ll0[m], r1, order, bn_ctx)
|
|
|| !BN_mod_add(t1, t1, t, order, bn_ctx)
|
|
|| !BN_mod_add(rr1[m], aR[m] == 0 ? bn0 : bn_1, z, order, bn_ctx)
|
|
|| !BN_mod_mul(t, pow_y[m], rr1[m], order, bn_ctx))
|
|
goto err;
|
|
|
|
if (!BN_mod_mul(rr2[m], pow_zn, pow_2, order, bn_ctx)
|
|
|| !BN_mod_add(r0, t, rr2[m], order, bn_ctx)
|
|
|| !BN_mod_mul(t, r0, sL[m], order, bn_ctx)
|
|
|| !BN_mod_add(t1, t1, t, order, bn_ctx)
|
|
|| !BN_mod_mul(t, r1, sL[m], order, bn_ctx)
|
|
|| !BN_mod_add(t2, t2, t, order, bn_ctx))
|
|
goto err;
|
|
|
|
if (!BN_mod_mul(pow_2, pow_2, bn2, order, bn_ctx))
|
|
goto err;
|
|
}
|
|
|
|
if (!BN_mul(t, pow_zn, witness_r, bn_ctx)
|
|
|| !BN_mod_add(proof->taux, proof->taux, t, order, bn_ctx))
|
|
goto err;
|
|
|
|
if (!BN_mod_mul(pow_zn, pow_zn, z, order, bn_ctx))
|
|
goto err;
|
|
}
|
|
|
|
/* (53, 54) */
|
|
if (!EC_POINT_mul(group, proof->T1, tau1, pp->H, t1, bn_ctx)
|
|
|| !EC_POINT_mul(group, proof->T2, tau2, pp->H, t2, bn_ctx))
|
|
goto err;
|
|
|
|
/* (55, 56) */
|
|
if (!ZKP_TRANSCRIPT_append_point(transcript, "T1", proof->T1, group)
|
|
|| !ZKP_TRANSCRIPT_append_point(transcript, "T2", proof->T2, group))
|
|
goto err;
|
|
|
|
if (!ZKP_TRANSCRIPT_challange(transcript, "x", x))
|
|
goto err;
|
|
|
|
BN_zero(proof->tx);
|
|
|
|
for (i = 0; i < witness_n; i++) {
|
|
for (j = 0; j < bits; j++) {
|
|
m = i * bits + j;
|
|
tmp = BN_CTX_get(bn_ctx);
|
|
l = BN_CTX_get(bn_ctx);
|
|
r = BN_CTX_get(bn_ctx);
|
|
g_scalar = BN_CTX_get(bn_ctx);
|
|
h_scalar = BN_CTX_get(bn_ctx);
|
|
if (h_scalar == NULL)
|
|
goto err;
|
|
|
|
G = sk_EC_POINT_value(pp->sk_G, m);
|
|
H = sk_EC_POINT_value(pp->sk_H, m);
|
|
if (G == NULL || H == NULL)
|
|
goto err;
|
|
|
|
BN_one(g_scalar);
|
|
|
|
/* (58, 59, 60) */
|
|
if (!BN_mod_mul(t, sL[m], x, order, bn_ctx)
|
|
|| !BN_mod_add(l, ll0[m], t, order, bn_ctx)
|
|
|| !BN_mod_mul(t, sR[m], x, order, bn_ctx)
|
|
|| !BN_mod_add(rr1[m], rr1[m], t, order, bn_ctx)
|
|
|| !BN_mod_mul(dv, pow_y[m], rr1[m], order, bn_ctx)
|
|
|| !BN_mod_add(r, dv, rr2[m], order, bn_ctx)
|
|
|| !BN_mod_mul(t, l, r, order, bn_ctx)
|
|
|| !BN_mod_add(proof->tx, proof->tx, t, order, bn_ctx))
|
|
goto err;
|
|
|
|
if (!BN_copy(h_scalar, pow_y_inv))
|
|
goto err;
|
|
|
|
if (sk_EC_POINT_push(sk_G, sk_EC_POINT_value(pp->sk_G, m)) <= 0
|
|
|| sk_EC_POINT_push(sk_H, sk_EC_POINT_value(pp->sk_H, m)) <= 0
|
|
|| sk_BIGNUM_push(sk_G_scalars, g_scalar) <= 0
|
|
|| sk_BIGNUM_push(sk_H_scalars, h_scalar) <= 0
|
|
|| sk_BIGNUM_push(sk_l, l) <= 0
|
|
|| sk_BIGNUM_push(sk_r, r) <= 0)
|
|
goto err;
|
|
|
|
if (!BN_mod_mul(tmp, r, pow_y_inv, order, bn_ctx))
|
|
goto err;
|
|
|
|
if (!BN_mod_mul(pow_y_inv, pow_y_inv, y_inv, order, bn_ctx))
|
|
goto err;
|
|
|
|
if (!zkp_poly_points_append(poly_p, G, l)
|
|
|| !zkp_poly_points_append(poly_p, H, tmp))
|
|
goto err;
|
|
}
|
|
}
|
|
|
|
/* (61) */
|
|
if (!BN_mod_sqr(t, x, order, bn_ctx)
|
|
|| !BN_mod_mul(t, t, tau2, order, bn_ctx)
|
|
|| !BN_mod_add(proof->taux, proof->taux, t, order, bn_ctx)
|
|
|| !BN_mod_mul(t, x, tau1, order, bn_ctx)
|
|
|| !BN_mod_add(proof->taux, proof->taux, t, order, bn_ctx))
|
|
goto err;
|
|
|
|
/* (62) */
|
|
if (!BN_mul(proof->mu, rho, x, bn_ctx)
|
|
|| !BN_mod_add(proof->mu, proof->mu, alpha, order, bn_ctx))
|
|
goto err;
|
|
|
|
/* (67) */
|
|
if (!EC_POINT_mul(group, U, NULL, pp->U, x, bn_ctx)
|
|
|| !zkp_poly_points_append(poly_p, U, proof->tx)
|
|
|| !zkp_poly_points_mul(poly_p, P, NULL, group, bn_ctx))
|
|
goto err;
|
|
|
|
if (!(ip_pp = bp_inner_product_pub_param_new(group, sk_G, sk_H))
|
|
|| !(ip_ctx = bp_inner_product_ctx_new(ip_pp, transcript, U, P,
|
|
sk_G_scalars, sk_H_scalars))
|
|
|| !(ip_witness = bp_inner_product_witness_new(sk_l, sk_r))
|
|
|| !(proof->ip_proof = bp_inner_product_proof_prove(ip_ctx, ip_witness)))
|
|
goto err;
|
|
|
|
ret = 1;
|
|
|
|
err:
|
|
ZKP_TRANSCRIPT_reset(transcript);
|
|
|
|
bp_inner_product_witness_free(ip_witness);
|
|
bp_inner_product_pub_param_free(ip_pp);
|
|
bp_inner_product_ctx_free(ip_ctx);
|
|
|
|
zkp_poly_points_free(poly_a);
|
|
zkp_poly_points_free(poly_s);
|
|
zkp_poly_points_free(poly_p);
|
|
|
|
sk_EC_POINT_free(sk_G);
|
|
sk_EC_POINT_free(sk_H);
|
|
sk_BIGNUM_free(sk_G_scalars);
|
|
sk_BIGNUM_free(sk_H_scalars);
|
|
sk_BIGNUM_free(sk_l);
|
|
sk_BIGNUM_free(sk_r);
|
|
|
|
OPENSSL_free(pow_y);
|
|
OPENSSL_free(ll0);
|
|
OPENSSL_free(rr1);
|
|
OPENSSL_free(rr2);
|
|
OPENSSL_free(sL);
|
|
OPENSSL_free(sR);
|
|
OPENSSL_free(aL);
|
|
OPENSSL_free(aR);
|
|
EC_POINT_free(P);
|
|
EC_POINT_free(T);
|
|
EC_POINT_free(U);
|
|
BN_CTX_end(bn_ctx);
|
|
BN_CTX_free(bn_ctx);
|
|
return ret;
|
|
}
|
|
|
|
/** Prove computes the ZK rangeproof and new a proof object.
|
|
* \param ctx BP_RANGE_CTX object
|
|
* \return BP_RANGE_PROOF object on success or NULL in case of an error
|
|
*/
|
|
BP_RANGE_PROOF *BP_RANGE_PROOF_new_prove(BP_RANGE_CTX *ctx)
|
|
{
|
|
BP_RANGE_PROOF *proof = NULL;
|
|
|
|
if (ctx == NULL) {
|
|
ERR_raise(ERR_LIB_ZKP_BP, ERR_R_PASSED_NULL_PARAMETER);
|
|
return NULL;
|
|
}
|
|
|
|
if (!(proof = BP_RANGE_PROOF_new(ctx->pp)))
|
|
return NULL;
|
|
|
|
if (!BP_RANGE_PROOF_prove(ctx, proof))
|
|
goto err;
|
|
|
|
return proof;
|
|
err:
|
|
BP_RANGE_PROOF_free(proof);
|
|
return NULL;
|
|
}
|
|
|
|
/** Verifies that the supplied proof is a valid proof
|
|
* for the supplied secret values using the supplied public parameters.
|
|
* \param ctx BP_RANGE_CTX object
|
|
* \param proof BP_RANGE_PROOF object
|
|
* \return 1 if the proof is valid, 0 if the proof is invalid and -1 on error
|
|
*/
|
|
int BP_RANGE_PROOF_verify(BP_RANGE_CTX *ctx, const BP_RANGE_PROOF *proof)
|
|
{
|
|
int ret = 0, i = 0, j, m, n, bits, poly_p_num, poly_r_num, witness_n, witness_padded_n;
|
|
ZKP_TRANSCRIPT *transcript;
|
|
BP_PUB_PARAM *pp;
|
|
BP_WITNESS *witness;
|
|
BP_VARIABLE *V;
|
|
BIGNUM *bn0, *bn1, *bn2, *delta;
|
|
BIGNUM *x, *x2, *y, *y_inv, *z, *z2, *nz, *t, *tmp, *z_pow_y;
|
|
BIGNUM *pow_y, *pow_y_inv, *pow_z, *pow_2, *sum_pow_y, *sum_pow_z, *sum_pow_2;
|
|
BIGNUM *g_scalar, *h_scalar;
|
|
STACK_OF(BIGNUM) *sk_G_scalars = NULL, *sk_H_scalars = NULL;
|
|
STACK_OF(EC_POINT) *sk_G = NULL, *sk_H = NULL;
|
|
EC_POINT *O = NULL, *P = NULL, *U = NULL, *L = NULL, *R = NULL, *G, *H;
|
|
BN_CTX *bn_ctx = NULL;
|
|
zkp_poly_points_t *poly_p = NULL, *poly_r = NULL;
|
|
EC_GROUP *group;
|
|
const BIGNUM *order;
|
|
bp_inner_product_ctx_t *ip_ctx = NULL;
|
|
bp_inner_product_pub_param_t *ip_pp = NULL;
|
|
|
|
if (ctx == NULL || ctx->pp == NULL || ctx->witness == NULL || proof == NULL) {
|
|
ERR_raise(ERR_LIB_ZKP_BP, ERR_R_PASSED_NULL_PARAMETER);
|
|
return ret;
|
|
}
|
|
|
|
transcript = ctx->transcript;
|
|
pp = ctx->pp;
|
|
witness = ctx->witness;
|
|
bits = pp->gens_capacity;
|
|
witness_n = sk_BP_VARIABLE_num(witness->sk_V);
|
|
witness_padded_n = zkp_next_power_of_two(witness_n);
|
|
n = bits * witness_padded_n;
|
|
poly_p_num = bits * witness_padded_n * 2 + 4;
|
|
poly_r_num = bits * witness_padded_n + 3;
|
|
group = pp->group;
|
|
order = EC_GROUP_get0_order(group);
|
|
|
|
if (!zkp_is_power_of_two(n)) {
|
|
ERR_raise(ERR_LIB_ZKP_BP, ZKP_BP_R_RANGE_LEN_MUST_BE_POWER_OF_TWO);
|
|
return 0;
|
|
}
|
|
|
|
if (witness_n != witness_padded_n) {
|
|
ERR_raise(ERR_LIB_ZKP_BP, ZKP_BP_R_WITNESS_INVALID);
|
|
return 0;
|
|
}
|
|
|
|
if (witness_padded_n > ctx->pp->party_capacity) {
|
|
ERR_raise(ERR_LIB_ZKP_BP, ZKP_BP_R_EXCEEDS_PARTY_CAPACITY);
|
|
return 0;
|
|
}
|
|
|
|
if (EC_GROUP_get_curve_name(pp->group) != EC_POINT_get_curve_name(proof->A)) {
|
|
ERR_raise(ERR_LIB_ZKP_BP, ERR_R_PASSED_INVALID_ARGUMENT);
|
|
return 0;
|
|
}
|
|
|
|
if (!(sk_G = sk_EC_POINT_new_reserve(NULL, n))
|
|
|| !(sk_H = sk_EC_POINT_new_reserve(NULL, n))
|
|
|| !(sk_G_scalars = sk_BIGNUM_new_reserve(NULL, n))
|
|
|| !(sk_H_scalars = sk_BIGNUM_new_reserve(NULL, n))) {
|
|
ERR_raise(ERR_LIB_ZKP_BP, ERR_R_MALLOC_FAILURE);
|
|
goto err;
|
|
}
|
|
|
|
if (!(poly_p = zkp_poly_points_new(poly_p_num)) || !(poly_r = zkp_poly_points_new(poly_r_num)))
|
|
goto err;
|
|
|
|
if (!(O = EC_POINT_new(group))
|
|
|| !(P = EC_POINT_new(group))
|
|
|| !(U = EC_POINT_new(group))
|
|
|| !(L = EC_POINT_new(group))
|
|
|| !(R = EC_POINT_new(group)))
|
|
goto err;
|
|
|
|
bn_ctx = BN_CTX_new_ex(group->libctx);
|
|
if (bn_ctx == NULL)
|
|
goto err;
|
|
|
|
BN_CTX_start(bn_ctx);
|
|
bn0 = BN_CTX_get(bn_ctx);
|
|
bn1 = BN_CTX_get(bn_ctx);
|
|
bn2 = BN_CTX_get(bn_ctx);
|
|
x = BN_CTX_get(bn_ctx);
|
|
x2 = BN_CTX_get(bn_ctx);
|
|
y = BN_CTX_get(bn_ctx);
|
|
y_inv = BN_CTX_get(bn_ctx);
|
|
z = BN_CTX_get(bn_ctx);
|
|
z2 = BN_CTX_get(bn_ctx);
|
|
z_pow_y = BN_CTX_get(bn_ctx);
|
|
nz = BN_CTX_get(bn_ctx);
|
|
sum_pow_y = BN_CTX_get(bn_ctx);
|
|
sum_pow_z = BN_CTX_get(bn_ctx);
|
|
sum_pow_2 = BN_CTX_get(bn_ctx);
|
|
t = BN_CTX_get(bn_ctx);
|
|
pow_y = BN_CTX_get(bn_ctx);
|
|
pow_y_inv = BN_CTX_get(bn_ctx);
|
|
pow_z = BN_CTX_get(bn_ctx);
|
|
pow_2 = BN_CTX_get(bn_ctx);
|
|
delta = BN_CTX_get(bn_ctx);
|
|
if (delta == NULL)
|
|
goto err;
|
|
|
|
BN_zero(sum_pow_y);
|
|
BN_zero(sum_pow_z);
|
|
BN_zero(sum_pow_2);
|
|
BN_one(pow_y);
|
|
BN_one(pow_y_inv);
|
|
BN_one(bn0);
|
|
BN_one(bn1);
|
|
BN_set_word(bn2, 2);
|
|
|
|
EC_POINT_set_to_infinity(group, O);
|
|
|
|
if (!ZKP_TRANSCRIPT_append_point(transcript, "A", proof->A, group)
|
|
|| !ZKP_TRANSCRIPT_append_point(transcript, "S", proof->S, group))
|
|
goto err;
|
|
|
|
if (!ZKP_TRANSCRIPT_challange(transcript, "y", y)
|
|
|| !ZKP_TRANSCRIPT_challange(transcript, "z", z))
|
|
goto err;
|
|
|
|
if (!ZKP_TRANSCRIPT_append_point(transcript, "T1", proof->T1, group)
|
|
|| !ZKP_TRANSCRIPT_append_point(transcript, "T2", proof->T2, group))
|
|
goto err;
|
|
|
|
if (!ZKP_TRANSCRIPT_challange(transcript, "x", x))
|
|
goto err;
|
|
|
|
if (!BN_mod_inverse(y_inv, y, order, bn_ctx)
|
|
|| !BN_mod_sqr(x2, x, order, bn_ctx)
|
|
|| !BN_mod_sqr(z2, z, order, bn_ctx)
|
|
|| !BN_sub(nz, order, z)
|
|
|| !BN_copy(pow_z, z))
|
|
goto err;
|
|
|
|
for (i = 0; i < witness_n; i++) {
|
|
V = sk_BP_VARIABLE_value(witness->sk_V, i);
|
|
if (V == NULL)
|
|
goto err;
|
|
|
|
BN_one(pow_2);
|
|
|
|
if (!BN_mod_mul(pow_z, pow_z, z, order, bn_ctx)
|
|
|| !BN_mod_add(sum_pow_z, sum_pow_z, pow_z, order, bn_ctx))
|
|
goto err;
|
|
|
|
for (j = 0; j < bits; j++) {
|
|
m = i * bits + j;
|
|
if (i == 0) {
|
|
if (!BN_mod_add(sum_pow_2, sum_pow_2, pow_2, order, bn_ctx))
|
|
goto err;
|
|
}
|
|
|
|
G = sk_EC_POINT_value(pp->sk_G, m);
|
|
H = sk_EC_POINT_value(pp->sk_H, m);
|
|
if (G == NULL || H == NULL)
|
|
goto err;
|
|
|
|
tmp = BN_CTX_get(bn_ctx);
|
|
g_scalar = BN_CTX_get(bn_ctx);
|
|
h_scalar = BN_CTX_get(bn_ctx);
|
|
if (h_scalar == NULL)
|
|
goto err;
|
|
|
|
BN_one(g_scalar);
|
|
|
|
if (!BN_copy(h_scalar, pow_y_inv))
|
|
goto err;
|
|
|
|
if (sk_EC_POINT_push(sk_G, sk_EC_POINT_value(pp->sk_G, m)) <= 0
|
|
|| sk_EC_POINT_push(sk_H, sk_EC_POINT_value(pp->sk_H, m)) <= 0
|
|
|| sk_BIGNUM_push(sk_G_scalars, g_scalar) <= 0
|
|
|| sk_BIGNUM_push(sk_H_scalars, h_scalar) <= 0)
|
|
goto err;
|
|
|
|
if (!BN_mod_add(sum_pow_y, sum_pow_y, pow_y, order, bn_ctx)
|
|
|| !BN_mod_mul(z_pow_y, z, pow_y, order, bn_ctx)
|
|
|| !BN_mod_mul(t, pow_z, pow_2, order, bn_ctx)
|
|
|| !BN_mod_add(t, t, z_pow_y, order, bn_ctx))
|
|
goto err;
|
|
|
|
if (!BN_copy(tmp, t) || !BN_mod_mul(tmp, tmp, pow_y_inv, order, bn_ctx))
|
|
goto err;
|
|
|
|
if (!zkp_poly_points_append(poly_p, G, nz)
|
|
|| !zkp_poly_points_append(poly_p, H, tmp))
|
|
goto err;
|
|
|
|
if (!BN_mod_mul(pow_y, pow_y, y, order, bn_ctx)
|
|
|| !BN_mod_mul(pow_y_inv, pow_y_inv, y_inv, order, bn_ctx)
|
|
|| !BN_mod_mul(pow_2, pow_2, bn2, order, bn_ctx))
|
|
goto err;
|
|
}
|
|
|
|
tmp = BN_CTX_get(bn_ctx);
|
|
if (tmp == NULL || !BN_copy(tmp, pow_z))
|
|
goto err;
|
|
|
|
if (!zkp_poly_points_append(poly_r, V->point, tmp))
|
|
goto err;
|
|
}
|
|
|
|
if (!BN_mod_mul(sum_pow_z, sum_pow_z, z, order, bn_ctx))
|
|
goto err;
|
|
|
|
/* (39) also see page 21 */
|
|
if (!BN_mod_sub(delta, z, z2, order, bn_ctx)
|
|
|| !BN_mod_mul(delta, delta, sum_pow_y, order, bn_ctx)
|
|
|| !BN_mod_mul(t, sum_pow_z, sum_pow_2, order, bn_ctx)
|
|
|| !BN_mod_sub(delta, delta, t, order, bn_ctx))
|
|
goto err;
|
|
|
|
/* (72) */
|
|
if (!zkp_poly_points_append(poly_r, pp->H, delta)
|
|
|| !zkp_poly_points_append(poly_r, proof->T1, x)
|
|
|| !zkp_poly_points_append(poly_r, proof->T2, x2)
|
|
|| !zkp_poly_points_mul(poly_r, R, NULL, group, bn_ctx))
|
|
goto err;
|
|
|
|
/* (65) */
|
|
if (!EC_POINT_mul(group, L, proof->taux, pp->H, proof->tx, bn_ctx)
|
|
|| !EC_POINT_invert(group, L, bn_ctx)
|
|
|| !EC_POINT_add(group, R, R, L, bn_ctx)
|
|
|| !EC_POINT_is_at_infinity(group, R))
|
|
goto err;
|
|
|
|
if (!EC_POINT_mul(group, U, NULL, pp->U, x, bn_ctx))
|
|
goto err;
|
|
|
|
tmp = BN_CTX_get(bn_ctx);
|
|
if (tmp == NULL)
|
|
goto err;
|
|
|
|
if (!BN_copy(tmp, proof->mu))
|
|
goto err;
|
|
|
|
BN_set_negative(tmp, !BN_is_negative(tmp));
|
|
|
|
if (!zkp_poly_points_append(poly_p, proof->S, x)
|
|
|| !zkp_poly_points_append(poly_p, proof->A, bn1)
|
|
|| !zkp_poly_points_append(poly_p, pp->H, tmp)
|
|
|| !zkp_poly_points_append(poly_p, U, proof->tx)
|
|
|| !zkp_poly_points_mul(poly_p, P, NULL, group, bn_ctx))
|
|
goto err;
|
|
|
|
if (!(ip_pp = bp_inner_product_pub_param_new(group, sk_G, sk_H))
|
|
|| !(ip_ctx = bp_inner_product_ctx_new(ip_pp, transcript, U, P,
|
|
sk_G_scalars, sk_H_scalars)))
|
|
goto err;
|
|
|
|
ret = bp_inner_product_proof_verify(ip_ctx, proof->ip_proof);
|
|
|
|
err:
|
|
ZKP_TRANSCRIPT_reset(transcript);
|
|
|
|
bp_inner_product_ctx_free(ip_ctx);
|
|
bp_inner_product_pub_param_free(ip_pp);
|
|
|
|
zkp_poly_points_free(poly_p);
|
|
zkp_poly_points_free(poly_r);
|
|
|
|
BN_CTX_end(bn_ctx);
|
|
BN_CTX_free(bn_ctx);
|
|
|
|
EC_POINT_free(L);
|
|
EC_POINT_free(R);
|
|
EC_POINT_free(U);
|
|
EC_POINT_free(P);
|
|
EC_POINT_free(O);
|
|
|
|
sk_EC_POINT_free(sk_G);
|
|
sk_EC_POINT_free(sk_H);
|
|
sk_BIGNUM_free(sk_G_scalars);
|
|
sk_BIGNUM_free(sk_H_scalars);
|
|
return ret;
|
|
}
|