gateway2/Tongsuo-8.4.0/crypto/zkp/bulletproofs/r1cs.c
2026-07-11 13:40:57 +08:00

1229 lines
38 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/ctype.h>
#include <crypto/ec/ec_local.h>
#include <crypto/zkp/common/zkp_util.h>
#include "r1cs.h"
DEFINE_STACK_OF(BIGNUM)
DEFINE_STACK_OF(EC_POINT)
DEFINE_STACK_OF(BP_VARIABLE)
DEFINE_STACK_OF(BP_R1CS_LINEAR_COMBINATION)
DEFINE_STACK_OF(BP_R1CS_LINEAR_COMBINATION_ITEM)
BP_R1CS_CTX *BP_R1CS_CTX_new(BP_PUB_PARAM *pp, BP_WITNESS *witness,
ZKP_TRANSCRIPT *transcript)
{
BP_R1CS_CTX *ctx = NULL;
if (pp == NULL || witness == 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;
}
ctx->transcript = transcript;
if (!BP_PUB_PARAM_up_ref(pp))
goto err;
ctx->pp = pp;
if (!BP_WITNESS_up_ref(witness))
goto err;
ctx->witness = witness;
if ((ctx->constraints = sk_BP_R1CS_LINEAR_COMBINATION_new_null()) == NULL
|| (ctx->aL = sk_BIGNUM_new_null()) == NULL
|| (ctx->aR = sk_BIGNUM_new_null()) == NULL
|| (ctx->aO = sk_BIGNUM_new_null()) == NULL)
goto err;
return ctx;
err:
BP_R1CS_CTX_free(ctx);
return NULL;
}
void BP_R1CS_CTX_free(BP_R1CS_CTX *ctx)
{
if (ctx == NULL)
return;
BP_PUB_PARAM_down_ref(ctx->pp);
BP_WITNESS_down_ref(ctx->witness);
sk_BP_R1CS_LINEAR_COMBINATION_pop_free(ctx->constraints,
BP_R1CS_LINEAR_COMBINATION_free);
sk_BIGNUM_pop_free(ctx->aL, BN_free);
sk_BIGNUM_pop_free(ctx->aR, BN_free);
sk_BIGNUM_pop_free(ctx->aO, BN_free);
OPENSSL_clear_free((void *)ctx, sizeof(*ctx));
}
BP_R1CS_PROOF *BP_R1CS_PROOF_new(BP_R1CS_CTX *ctx)
{
BP_R1CS_PROOF *proof = NULL;
proof = OPENSSL_zalloc(sizeof(*proof));
if (proof == NULL) {
ERR_raise(ERR_LIB_ZKP_BP, ERR_R_MALLOC_FAILURE);
return NULL;
}
if ((proof->AI1 = EC_POINT_new(ctx->pp->group)) == NULL
|| (proof->AO1 = EC_POINT_new(ctx->pp->group)) == NULL
|| (proof->S1 = EC_POINT_new(ctx->pp->group)) == NULL
|| (proof->AI2 = EC_POINT_new(ctx->pp->group)) == NULL
|| (proof->AO2 = EC_POINT_new(ctx->pp->group)) == NULL
|| (proof->S2 = EC_POINT_new(ctx->pp->group)) == NULL
|| (proof->T1 = EC_POINT_new(ctx->pp->group)) == NULL
|| (proof->T3 = EC_POINT_new(ctx->pp->group)) == NULL
|| (proof->T4 = EC_POINT_new(ctx->pp->group)) == NULL
|| (proof->T5 = EC_POINT_new(ctx->pp->group)) == NULL
|| (proof->T6 = EC_POINT_new(ctx->pp->group)) == NULL
|| (proof->taux = BN_new()) == NULL
|| (proof->mu = BN_new()) == NULL
|| (proof->tx = BN_new()) == NULL)
goto err;
EC_POINT_set_to_infinity(ctx->pp->group, proof->AI1);
EC_POINT_set_to_infinity(ctx->pp->group, proof->AO1);
EC_POINT_set_to_infinity(ctx->pp->group, proof->S1);
EC_POINT_set_to_infinity(ctx->pp->group, proof->AI2);
EC_POINT_set_to_infinity(ctx->pp->group, proof->AO2);
EC_POINT_set_to_infinity(ctx->pp->group, proof->S2);
EC_POINT_set_to_infinity(ctx->pp->group, proof->T1);
EC_POINT_set_to_infinity(ctx->pp->group, proof->T3);
EC_POINT_set_to_infinity(ctx->pp->group, proof->T4);
EC_POINT_set_to_infinity(ctx->pp->group, proof->T5);
EC_POINT_set_to_infinity(ctx->pp->group, proof->T6);
BN_zero(proof->taux);
BN_zero(proof->mu);
BN_zero(proof->tx);
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_R1CS_PROOF_free(proof);
return NULL;
}
void BP_R1CS_PROOF_free(BP_R1CS_PROOF *proof)
{
int ref;
if (proof == NULL)
return;
CRYPTO_DOWN_REF(&proof->references, &ref, proof->lock);
REF_PRINT_COUNT("BP_R1CS_PROOF", proof);
if (ref > 0)
return;
REF_ASSERT_ISNT(ref < 0);
EC_POINT_free(proof->AI1);
EC_POINT_free(proof->AO1);
EC_POINT_free(proof->S1);
EC_POINT_free(proof->AI2);
EC_POINT_free(proof->AO2);
EC_POINT_free(proof->S2);
EC_POINT_free(proof->T1);
EC_POINT_free(proof->T3);
EC_POINT_free(proof->T4);
EC_POINT_free(proof->T5);
EC_POINT_free(proof->T6);
BN_free(proof->taux);
BN_free(proof->mu);
BN_free(proof->tx);
CRYPTO_THREAD_lock_free(proof->lock);
OPENSSL_clear_free((void *)proof, sizeof(*proof));
}
int BP_WITNESS_r1cs_commit(BP_WITNESS *witness, const char *name, BIGNUM *v)
{
const BIGNUM *order;
BIGNUM *r = NULL, *val = NULL;
EC_POINT *V = NULL;
BP_VARIABLE *var = NULL;
if (witness == NULL || name == NULL || v == NULL) {
ERR_raise(ERR_LIB_ZKP_BP, ERR_R_PASSED_NULL_PARAMETER);
return 0;
}
if (strlen(name) > BP_VARIABLE_NAME_MAX_LEN) {
ERR_raise(ERR_LIB_ZKP_BP, ZKP_BP_R_VARIABLE_NAME_TOO_LONG);
return 0;
}
order = EC_GROUP_get0_order(witness->group);
if (BP_WITNESS_get_variable_index(witness, name) >= 0) {
ERR_raise(ERR_LIB_ZKP_BP, ZKP_BP_R_VARIABLE_DUPLICATED);
return 0;
}
r = BN_new();
val = BN_dup(v);
V = EC_POINT_new(witness->group);
if (r == NULL || val == NULL || V == NULL)
goto err;
if (!zkp_rand_range(r, order))
goto err;
/* (69) */
if (!EC_POINT_mul(witness->group, V, v, witness->H, r, NULL))
goto err;
if (!(var = BP_VARIABLE_new(name, V, witness->group)))
goto err;
if (sk_BIGNUM_push(witness->sk_r, r) <= 0)
goto err;
r = NULL;
if (sk_BIGNUM_push(witness->sk_v, val) <= 0)
goto err;
val = NULL;
if (sk_BP_VARIABLE_push(witness->sk_V, var) <= 0)
goto err;
return 1;
err:
BN_free(r);
BN_free(val);
EC_POINT_free(V);
BP_VARIABLE_free(var);
return 0;
}
BP_R1CS_LINEAR_COMBINATION *BP_WITNESS_r1cs_linear_combination_commit(BP_WITNESS *witness,
const char *name,
BIGNUM *v)
{
int num;
BP_R1CS_VARIABLE *r1cs_var = NULL;
BP_R1CS_LINEAR_COMBINATION *lc = NULL;
if (!BP_WITNESS_r1cs_commit(witness, name, v))
return 0;
num = sk_BP_VARIABLE_num(witness->sk_V) - 1;
if ((r1cs_var = BP_R1CS_VARIABLE_new(BP_R1CS_VARIABLE_COMMITTED, num)) == NULL)
goto err;
if (!(lc = BP_R1CS_LINEAR_COMBINATION_new_from_param(r1cs_var, NULL)))
goto err;
lc->type = BP_R1CS_LC_TYPE_PROVE;
return lc;
err:
BP_R1CS_VARIABLE_free(r1cs_var);
BP_R1CS_LINEAR_COMBINATION_free(lc);
return NULL;
}
BP_R1CS_LINEAR_COMBINATION *BP_WITNESS_r1cs_linear_combination_get(BP_WITNESS *witness,
const char *name)
{
int i;
BP_R1CS_VARIABLE *var = NULL;
BP_R1CS_LINEAR_COMBINATION *ret = NULL;
if (witness == NULL || name == NULL) {
ERR_raise(ERR_LIB_ZKP_BP, ERR_R_PASSED_NULL_PARAMETER);
return NULL;
}
i = BP_WITNESS_get_variable_index(witness, name);
if (i < 0)
return NULL;
if ((var = BP_R1CS_VARIABLE_new(BP_R1CS_VARIABLE_COMMITTED, i)) == NULL)
goto err;
if (!(ret = BP_R1CS_LINEAR_COMBINATION_new_from_param(var, NULL)))
goto err;
ret->type = BP_R1CS_LC_TYPE_VERIFY;
return ret;
err:
BP_R1CS_VARIABLE_free(var);
BP_R1CS_LINEAR_COMBINATION_free(ret);
return NULL;
}
BP_R1CS_PROOF *BP_R1CS_PROOF_prove(BP_R1CS_CTX *ctx)
{
EC_GROUP *group;
const BIGNUM *order;
BN_CTX *bn_ctx = NULL;
int i, j, k, m, n, nn, n1, seed_buf_len, size, padded_n, pp_capacity;
unsigned char *seed_buf = NULL, *buf = NULL;
BIGNUM *alpha, *beta, *rho, *r = NULL, *product;
BIGNUM **sL = NULL, **sR = NULL;
BIGNUM *x, *u, *w, *z, *z2, *pow_z, *pw = NULL;
BIGNUM *y, *y_inv, *pow_y_inv, *pow_y;
BIGNUM **wL = NULL, **wR = NULL, **wO = NULL, **wV = NULL;
BIGNUM *tau1, *tau2, *tau3, *tau4, *tau5, *tau6;
BIGNUM *g_scalar, *h_scalar, *padded_l, *padded_r;
STACK_OF(EC_POINT) *sk_G = NULL, *sk_H = NULL;
STACK_OF(BIGNUM) *sk_G_scalars = NULL, *sk_H_scalars = NULL;
STACK_OF(BIGNUM) *sk_l = NULL, *sk_r = NULL;
EC_POINT *U = NULL, *G, *H;
zkp_poly3_t *poly_l = NULL, *poly_r = NULL;
zkp_poly6_t *poly_t = NULL, *poly_tau = NULL;
zkp_poly_points_t *poly_ai1 = NULL, *poly_ao1 = NULL, *poly_s1 = NULL;
bp_inner_product_ctx_t *ip_ctx = NULL;
bp_inner_product_witness_t *ip_witness = NULL;
bp_inner_product_pub_param_t *ip_pp = NULL;
ZKP_TRANSCRIPT *transcript;
BP_PUB_PARAM *pp;
BP_WITNESS *witness;
BP_VARIABLE *var;
BP_R1CS_VARIABLE *r1cs_var;
BP_R1CS_LINEAR_COMBINATION *lc;
BP_R1CS_LINEAR_COMBINATION_ITEM *item;
BP_R1CS_PROOF *proof = NULL, *ret = NULL;
if (ctx == NULL || ctx->constraints == NULL || ctx->witness == NULL) {
ERR_raise(ERR_LIB_ZKP_BP, ERR_R_PASSED_NULL_PARAMETER);
return NULL;
}
transcript = ctx->transcript;
witness = ctx->witness;
pp = ctx->pp;
group = pp->group;
order = EC_GROUP_get0_order(group);
n1 = sk_BIGNUM_num(ctx->aL);
nn = n1 + 1;
padded_n = zkp_next_power_of_two(n1);
pp_capacity = pp->gens_capacity * pp->party_capacity;
if (pp_capacity < padded_n) {
ERR_raise(ERR_LIB_ZKP_BP, ZKP_BP_R_EXCEEDS_PP_CAPACITY);
goto err;
}
if (!(proof = BP_R1CS_PROOF_new(ctx)) || !(U = EC_POINT_new(group))) {
ERR_raise(ERR_LIB_ZKP_BP, ERR_R_MALLOC_FAILURE);
goto err;
}
if (!(sk_G = sk_EC_POINT_new_reserve(NULL, padded_n))
|| !(sk_H = sk_EC_POINT_new_reserve(NULL, padded_n))
|| !(sk_G_scalars = sk_BIGNUM_new_reserve(NULL, padded_n))
|| !(sk_H_scalars = sk_BIGNUM_new_reserve(NULL, padded_n))) {
ERR_raise(ERR_LIB_ZKP_BP, ERR_R_MALLOC_FAILURE);
goto err;
}
bn_ctx = BN_CTX_new();
if (bn_ctx == NULL)
return NULL;
BN_CTX_start(bn_ctx);
alpha = BN_CTX_get(bn_ctx);
beta = BN_CTX_get(bn_ctx);
rho = BN_CTX_get(bn_ctx);
product = 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 = BN_CTX_get(bn_ctx);
pow_y_inv = BN_CTX_get(bn_ctx);
z = BN_CTX_get(bn_ctx);
pow_z = BN_CTX_get(bn_ctx);
z2 = BN_CTX_get(bn_ctx);
u = BN_CTX_get(bn_ctx);
w = BN_CTX_get(bn_ctx);
if (w == NULL)
goto err;
m = sk_BP_VARIABLE_num(witness->sk_V);
for (i = 0; i < m; i++) {
var = sk_BP_VARIABLE_value(witness->sk_V, i);
if (var == NULL)
goto err;
if (!ZKP_TRANSCRIPT_append_point(transcript, "V", var->point, group))
goto err;
}
m = sk_BIGNUM_num(witness->sk_v);
if (!ZKP_TRANSCRIPT_append_int64(transcript, "m", m))
goto err;
m = sk_BIGNUM_num(witness->sk_r);
if (m > 0) {
r = sk_BIGNUM_value(witness->sk_r, 0);
if (r == NULL)
goto err;
seed_buf_len = BN_num_bytes(r) * m * 2;
if ((seed_buf = OPENSSL_zalloc(seed_buf_len)) == NULL)
goto err;
}
buf = seed_buf;
for (i = 0; i < m; i++) {
r = sk_BIGNUM_value(witness->sk_r, i);
if (r == NULL)
goto err;
size = BN_num_bytes(r);
if (!BN_bn2bin(r, buf))
goto err;
buf += size;
}
RAND_seed(seed_buf, buf - seed_buf);
n = n1 * 2 + 1;
if (!(poly_ai1 = zkp_poly_points_new(n))
|| !(poly_ao1 = zkp_poly_points_new(n))
|| !(poly_s1 = zkp_poly_points_new(n)))
goto err;
if (!zkp_rand_range(alpha, order)
|| !zkp_rand_range(beta, order)
|| !zkp_rand_range(rho, order))
goto err;
if (!(sL = OPENSSL_zalloc(sizeof(*sL) * nn))
|| !(sR = OPENSSL_zalloc(sizeof(*sR) * nn))) {
ERR_raise(ERR_LIB_ZKP_BP, ERR_R_MALLOC_FAILURE);
goto err;
}
if (!zkp_random_bn_gen(group, sL, n1, bn_ctx)
|| !zkp_random_bn_gen(group, sR, n1, bn_ctx))
goto err;
if (!zkp_poly_points_append(poly_ai1, pp->H, alpha)
|| !zkp_poly_points_append(poly_ao1, pp->H, beta)
|| !zkp_poly_points_append(poly_s1, pp->H, rho))
goto err;
for (i = 0; i < n1; i++) {
G = sk_EC_POINT_value(pp->sk_G, i);
H = sk_EC_POINT_value(pp->sk_H, i);
if (!zkp_poly_points_append(poly_ai1, G, sk_BIGNUM_value(ctx->aL, i))
|| !zkp_poly_points_append(poly_ai1, H, sk_BIGNUM_value(ctx->aR, i))
|| !zkp_poly_points_append(poly_ao1, G, sk_BIGNUM_value(ctx->aO, i))
|| !zkp_poly_points_append(poly_s1, G, sL[i])
|| !zkp_poly_points_append(poly_s1, H, sR[i]))
goto err;
}
if (!zkp_poly_points_mul(poly_ai1, proof->AI1, NULL, group, bn_ctx)
|| !zkp_poly_points_mul(poly_ao1, proof->AO1, NULL, group, bn_ctx)
|| !zkp_poly_points_mul(poly_s1, proof->S1, NULL, group, bn_ctx))
goto err;
if (!ZKP_TRANSCRIPT_append_point(transcript, "A_I1", proof->AI1, group)
|| !ZKP_TRANSCRIPT_append_point(transcript, "A_O1", proof->AO1, group)
|| !ZKP_TRANSCRIPT_append_point(transcript, "S1", proof->S1, group))
goto err;
/*
* TODO
* Process the remaining constraints.
*/
n = sk_BIGNUM_num(ctx->aL);
nn = n + 1;
padded_n = zkp_next_power_of_two(n);
if (pp_capacity < padded_n) {
ERR_raise(ERR_LIB_ZKP_BP, ZKP_BP_R_EXCEEDS_PP_CAPACITY);
goto err;
}
if (!ZKP_TRANSCRIPT_append_point(transcript, "A_I2", proof->AI2, group)
|| !ZKP_TRANSCRIPT_append_point(transcript, "A_O2", proof->AO2, group)
|| !ZKP_TRANSCRIPT_append_point(transcript, "S2", proof->S2, 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_z, z)
|| !BN_mod_inverse(y_inv, y, order, bn_ctx))
goto err;
/*
* flatten the constraints
*/
m = sk_BIGNUM_num(witness->sk_v);
if ((wL = OPENSSL_zalloc(sizeof(*wL) * nn)) == NULL
|| (wR = OPENSSL_zalloc(sizeof(*wR) * nn)) == NULL
|| (wO = OPENSSL_zalloc(sizeof(*wO) * nn)) == NULL
|| (wV = OPENSSL_zalloc(sizeof(*wV) * m)) == NULL) {
ERR_raise(ERR_LIB_ZKP_BP, ERR_R_MALLOC_FAILURE);
goto err;
}
for (i = 0; i < n; i++) {
wL[i] = BN_CTX_get(bn_ctx);
wR[i] = BN_CTX_get(bn_ctx);
wO[i] = BN_CTX_get(bn_ctx);
if (wO[i] == NULL)
goto err;
BN_zero(wL[i]);
BN_zero(wR[i]);
BN_zero(wO[i]);
}
for (i = 0; i < m; i++) {
wV[i] = BN_CTX_get(bn_ctx);
if (wV[i] == NULL)
goto err;
BN_zero(wV[i]);
}
k = sk_BP_R1CS_LINEAR_COMBINATION_num(ctx->constraints);
for (i = 0; i < k; i++) {
lc = sk_BP_R1CS_LINEAR_COMBINATION_value(ctx->constraints, i);
if (lc == NULL)
goto err;
if (lc->type != BP_R1CS_LC_TYPE_PROVE)
continue;
m = sk_BP_R1CS_LINEAR_COMBINATION_ITEM_num(lc->items);
for (j = 0; j < m; j++) {
item = sk_BP_R1CS_LINEAR_COMBINATION_ITEM_value(lc->items, j);
if (item == NULL)
goto err;
r1cs_var = item->variable;
switch (r1cs_var->type) {
case BP_R1CS_VARIABLE_COMMITTED:
pw = wV[r1cs_var->value];
break;
case BP_R1CS_VARIABLE_MULTIPLIER_LEFT:
pw = wL[r1cs_var->value];
break;
case BP_R1CS_VARIABLE_MULTIPLIER_RIGHT:
pw = wR[r1cs_var->value];
break;
case BP_R1CS_VARIABLE_MULTIPLIER_OUTPUT:
pw = wO[r1cs_var->value];
break;
default:
break;
}
if (pw == NULL)
continue;
if (!BN_mod_mul(product, pow_z, item->scalar, order, bn_ctx))
goto err;
if (r1cs_var->type == BP_R1CS_VARIABLE_COMMITTED) {
if (!BN_mod_sub(pw, pw, product, order, bn_ctx))
goto err;
} else {
if (!BN_mod_add(pw, pw, product, order, bn_ctx))
goto err;
}
pw = NULL;
}
if (!BN_mod_mul(pow_z, pow_z, z, order, bn_ctx))
goto err;
}
BN_one(pow_y);
BN_one(pow_y_inv);
if (!(poly_l = zkp_poly3_new(n, order)) || !(poly_r = zkp_poly3_new(n, order)))
goto err;
for (i = 0; i < n; i++) {
g_scalar = BN_CTX_get(bn_ctx);
h_scalar = BN_CTX_get(bn_ctx);
if (h_scalar == NULL)
goto err;
if (!BN_mod_mul(poly_l->x1[i], pow_y_inv, wR[i], order, bn_ctx)
|| !BN_mod_add(poly_l->x1[i], poly_l->x1[i], sk_BIGNUM_value(ctx->aL, i),
order, bn_ctx)
|| !BN_copy(poly_l->x2[i], sk_BIGNUM_value(ctx->aO, i))
|| !BN_copy(poly_l->x3[i], sL[i]))
goto err;
if (!BN_mod_sub(poly_r->x0[i], wO[i], pow_y, order, bn_ctx)
|| !BN_mod_mul(poly_r->x1[i], pow_y, sk_BIGNUM_value(ctx->aR, i),
order, bn_ctx)
|| !BN_mod_add(poly_r->x1[i], poly_r->x1[i], wL[i], order, bn_ctx)
|| !BN_mod_mul(poly_r->x3[i], pow_y, sR[i], order, bn_ctx))
goto err;
BN_one(g_scalar);
if (!BN_copy(h_scalar, pow_y_inv))
goto err;
G = sk_EC_POINT_value(pp->sk_G, i);
H = sk_EC_POINT_value(pp->sk_H, i);
if (sk_EC_POINT_push(sk_G, G) <= 0
|| sk_EC_POINT_push(sk_H, H) <= 0
|| sk_BIGNUM_push(sk_G_scalars, g_scalar) <= 0
|| sk_BIGNUM_push(sk_H_scalars, h_scalar) <= 0)
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))
goto err;
}
if (!(poly_t = zkp_poly6_new(order)))
goto err;
if (!zkp_poly3_special_inner_product(poly_t, poly_l, poly_r))
goto err;
tau1 = BN_CTX_get(bn_ctx);
tau2 = BN_CTX_get(bn_ctx);
tau3 = BN_CTX_get(bn_ctx);
tau4 = BN_CTX_get(bn_ctx);
tau5 = BN_CTX_get(bn_ctx);
if (!(tau6 = BN_CTX_get(bn_ctx)))
goto err;
if (!zkp_rand_range(tau1, order)
|| !zkp_rand_range(tau3, order)
|| !zkp_rand_range(tau4, order)
|| !zkp_rand_range(tau5, order)
|| !zkp_rand_range(tau6, order))
goto err;
if (!EC_POINT_mul(group, proof->T1, poly_t->t1, pp->H, tau1, bn_ctx)
|| !EC_POINT_mul(group, proof->T3, poly_t->t3, pp->H, tau3, bn_ctx)
|| !EC_POINT_mul(group, proof->T4, poly_t->t4, pp->H, tau4, bn_ctx)
|| !EC_POINT_mul(group, proof->T5, poly_t->t5, pp->H, tau5, bn_ctx)
|| !EC_POINT_mul(group, proof->T6, poly_t->t6, pp->H, tau6, bn_ctx))
goto err;
if (!ZKP_TRANSCRIPT_append_point(transcript, "T_1", proof->T1, group)
|| !ZKP_TRANSCRIPT_append_point(transcript, "T_3", proof->T3, group)
|| !ZKP_TRANSCRIPT_append_point(transcript, "T_4", proof->T4, group)
|| !ZKP_TRANSCRIPT_append_point(transcript, "T_5", proof->T5, group)
|| !ZKP_TRANSCRIPT_append_point(transcript, "T_6", proof->T6, group))
goto err;
if (!ZKP_TRANSCRIPT_challange(transcript, "u", u)
|| !ZKP_TRANSCRIPT_challange(transcript, "x", x))
goto err;
BN_zero(tau2);
m = sk_BIGNUM_num(witness->sk_r);
for (i = 0; i < m; i++) {
r = sk_BIGNUM_value(witness->sk_r, i);
if (r == NULL || !BN_mod_mul(product, wV[i], r, order, bn_ctx))
goto err;
if (!BN_mod_add(tau2, tau2, product, order, bn_ctx))
goto err;
}
if (!(poly_tau = zkp_poly6_new(order)))
goto err;
poly_tau->t1 = tau1;
poly_tau->t2 = tau2;
poly_tau->t3 = tau3;
poly_tau->t4 = tau4;
poly_tau->t5 = tau5;
poly_tau->t6 = tau6;
if (!zkp_poly6_eval(poly_t, x, proof->tx) || !zkp_poly6_eval(poly_tau, x, proof->taux))
goto err;
if (!(sk_l = zkp_poly3_eval(poly_l, x)) || !(sk_r = zkp_poly3_eval(poly_r, x)))
goto err;
/* TODO: 2nd phase commitments */
if (!BN_mod_mul(proof->mu, x, rho, order, bn_ctx)
|| !BN_mod_add(proof->mu, proof->mu, beta, order, bn_ctx)
|| !BN_mod_mul(proof->mu, proof->mu, x, order, bn_ctx)
|| !BN_mod_add(proof->mu, proof->mu, alpha, order, bn_ctx)
|| !BN_mod_mul(proof->mu, proof->mu, x, order, bn_ctx))
goto err;
if (!ZKP_TRANSCRIPT_append_bn(transcript, "t_x", proof->tx)
|| !ZKP_TRANSCRIPT_append_bn(transcript, "t_x_blinding", proof->taux)
|| !ZKP_TRANSCRIPT_append_bn(transcript, "e_blinding", proof->mu))
goto err;
if (!ZKP_TRANSCRIPT_challange(transcript, "w", w))
goto err;
if (!EC_POINT_mul(group, U, w, NULL, NULL, bn_ctx))
goto err;
for (i = n; i < padded_n; i++) {
g_scalar = BN_CTX_get(bn_ctx);
h_scalar = BN_CTX_get(bn_ctx);
padded_l = BN_CTX_get(bn_ctx);
padded_r = BN_CTX_get(bn_ctx);
if (padded_r == NULL)
goto err;
if (!BN_copy(g_scalar, u)
|| !BN_mod_mul(h_scalar, pow_y_inv, u, order, bn_ctx))
goto err;
if (!BN_copy(padded_r, pow_y))
goto err;
BN_set_negative(padded_r, 1);
BN_zero(padded_l);
G = sk_EC_POINT_value(pp->sk_G, i);
H = sk_EC_POINT_value(pp->sk_H, i);
if (sk_EC_POINT_push(sk_G, G) <= 0
|| sk_EC_POINT_push(sk_H, H) <= 0
|| sk_BIGNUM_push(sk_G_scalars, g_scalar) <= 0
|| sk_BIGNUM_push(sk_H_scalars, h_scalar) <= 0
|| sk_BIGNUM_push(sk_l, padded_l) <= 0
|| sk_BIGNUM_push(sk_r, padded_r) <= 0)
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))
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, NULL,
sk_G_scalars, sk_H_scalars))
|| !(ip_witness = bp_inner_product_witness_new(sk_l, sk_r)))
goto err;
if (!(proof->ip_proof = bp_inner_product_proof_prove(ip_ctx, ip_witness)))
goto err;
ret = proof;
proof = NULL;
err:
ZKP_TRANSCRIPT_reset(transcript);
bp_inner_product_ctx_free(ip_ctx);
bp_inner_product_pub_param_free(ip_pp);
zkp_poly3_free(poly_l);
zkp_poly3_free(poly_r);
zkp_poly6_free(poly_t);
zkp_poly_points_free(poly_ai1);
zkp_poly_points_free(poly_ao1);
zkp_poly_points_free(poly_s1);
BN_CTX_end(bn_ctx);
BN_CTX_free(bn_ctx);
OPENSSL_free(sL);
OPENSSL_free(sR);
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);
EC_POINT_free(U);
OPENSSL_free(seed_buf);
BP_R1CS_PROOF_free(proof);
return ret;
}
int BP_R1CS_PROOF_verify(BP_R1CS_CTX *ctx, BP_R1CS_PROOF *proof)
{
BN_CTX *bn_ctx = NULL;
EC_GROUP *group;
const BIGNUM *order;
int i, j, m, n, nn, padded_n, v_n, lg_i, lg_n, pp_capacity, ret = 0;
BIGNUM *delta, *bn1;
BIGNUM **vec_s = NULL, **vec_ip_x2 = NULL;
BIGNUM *x, *x2, *x3, *ip_x, *ip_x_inv, *ip_x2, *ip_x2_inv;
BIGNUM *y, *y_inv, *pow_y_inv, *wR_pow_y_inv;
BIGNUM *z, *u, *w, *wc, *pw = NULL, *pow_z, *tmp, *product;
BIGNUM *ux, *ux2, *ux3, *r, *rx, *rx2, *rx3, *rx4, *rx5, *rx6;
BIGNUM *scalar, *g_scalar, *h_scalar, *b_scalar, *v_scalar, *s_a, *s_b;
BIGNUM **wL = NULL, **wR = NULL, **wO = NULL, **wV = NULL;
EC_POINT *P = NULL, *L, *R, *G, *H;
zkp_poly_points_t *poly_p = NULL;
ZKP_TRANSCRIPT *transcript;
BP_PUB_PARAM *pp;
BP_WITNESS *witness;
BP_VARIABLE *var;
BP_R1CS_VARIABLE *r1cs_var;
BP_R1CS_LINEAR_COMBINATION *lc;
BP_R1CS_LINEAR_COMBINATION_ITEM *item;
bp_inner_product_proof_t *ip_proof = NULL;
if (ctx == NULL || ctx->constraints == NULL || ctx->witness == NULL) {
ERR_raise(ERR_LIB_ZKP_BP, ERR_R_PASSED_NULL_PARAMETER);
return 0;
}
pp = ctx->pp;
transcript = ctx->transcript;
witness = ctx->witness;
group = pp->group;
order = EC_GROUP_get0_order(group);
ip_proof = proof->ip_proof;
pp_capacity = pp->gens_capacity * pp->party_capacity;
nn = ctx->vars_num + 1;
padded_n = zkp_next_power_of_two(ctx->vars_num);
if (pp_capacity < padded_n) {
ERR_raise(ERR_LIB_ZKP_BP, ZKP_BP_R_EXCEEDS_PP_CAPACITY);
goto err;
}
v_n = sk_BP_VARIABLE_num(witness->sk_V);
lg_n = sk_EC_POINT_num(ip_proof->sk_L);
if (padded_n != 1 << lg_n) {
ERR_raise(ERR_LIB_ZKP_BP, ERR_R_PASSED_INVALID_ARGUMENT);
goto err;
}
if (!(poly_p = zkp_poly_points_new(12 + padded_n * 2 + lg_n * 2 + v_n)))
goto err;
if (!(P = EC_POINT_new(group))
|| !(vec_ip_x2 = OPENSSL_zalloc((lg_n + 1) * sizeof(*vec_ip_x2)))
|| !(vec_s = OPENSSL_zalloc(padded_n * sizeof(*vec_s)))) {
ERR_raise(ERR_LIB_ZKP_BP, ERR_R_MALLOC_FAILURE);
goto err;
}
bn_ctx = BN_CTX_new();
if (bn_ctx == NULL)
goto err;
BN_CTX_start(bn_ctx);
bn1 = BN_CTX_get(bn_ctx);
product = BN_CTX_get(bn_ctx);
delta = 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);
wR_pow_y_inv = BN_CTX_get(bn_ctx);
z = BN_CTX_get(bn_ctx);
pow_z = BN_CTX_get(bn_ctx);
u = BN_CTX_get(bn_ctx);
w = BN_CTX_get(bn_ctx);
wc = BN_CTX_get(bn_ctx);
s_a = BN_CTX_get(bn_ctx);
s_b = BN_CTX_get(bn_ctx);
x2 = BN_CTX_get(bn_ctx);
x3 = BN_CTX_get(bn_ctx);
ux = BN_CTX_get(bn_ctx);
ux2 = BN_CTX_get(bn_ctx);
ux3 = BN_CTX_get(bn_ctx);
r = BN_CTX_get(bn_ctx);
rx = BN_CTX_get(bn_ctx);
rx2 = BN_CTX_get(bn_ctx);
rx3 = BN_CTX_get(bn_ctx);
rx4 = BN_CTX_get(bn_ctx);
rx5 = BN_CTX_get(bn_ctx);
rx6 = BN_CTX_get(bn_ctx);
ip_x = BN_CTX_get(bn_ctx);
ip_x_inv = BN_CTX_get(bn_ctx);
ip_x2 = BN_CTX_get(bn_ctx);
ip_x2_inv = BN_CTX_get(bn_ctx);
vec_s[0] = BN_CTX_get(bn_ctx);
tmp = BN_CTX_get(bn_ctx);
if (tmp == NULL)
goto err;
BN_zero(delta);
BN_one(bn1);
BN_one(pow_y_inv);
if (!zkp_rand_range(r, order))
goto err;
//START
for (i = 0; i < v_n; i++) {
var = sk_BP_VARIABLE_value(witness->sk_V, i);
if (var == NULL)
goto err;
if (!ZKP_TRANSCRIPT_append_point(transcript, "V", var->point, group))
goto err;
}
if (!ZKP_TRANSCRIPT_append_int64(transcript, "m", v_n))
goto err;
if (!ZKP_TRANSCRIPT_append_point(transcript, "A_I1", proof->AI1, group)
|| !ZKP_TRANSCRIPT_append_point(transcript, "A_O1", proof->AO1, group)
|| !ZKP_TRANSCRIPT_append_point(transcript, "S1", proof->S1, group))
goto err;
/*
* TODO
* Process the remaining constraints.
*/
if (!ZKP_TRANSCRIPT_append_point(transcript, "A_I2", proof->AI2, group)
|| !ZKP_TRANSCRIPT_append_point(transcript, "A_O2", proof->AO2, group)
|| !ZKP_TRANSCRIPT_append_point(transcript, "S2", proof->S2, group))
goto err;
if (!ZKP_TRANSCRIPT_challange(transcript, "y", y)
|| !ZKP_TRANSCRIPT_challange(transcript, "z", z))
goto err;
if (!ZKP_TRANSCRIPT_append_point(transcript, "T_1", proof->T1, group)
|| !ZKP_TRANSCRIPT_append_point(transcript, "T_3", proof->T3, group)
|| !ZKP_TRANSCRIPT_append_point(transcript, "T_4", proof->T4, group)
|| !ZKP_TRANSCRIPT_append_point(transcript, "T_5", proof->T5, group)
|| !ZKP_TRANSCRIPT_append_point(transcript, "T_6", proof->T6, group))
goto err;
if (!ZKP_TRANSCRIPT_challange(transcript, "u", u)
|| !ZKP_TRANSCRIPT_challange(transcript, "x", x))
goto err;
if (!ZKP_TRANSCRIPT_append_bn(transcript, "t_x", proof->tx)
|| !ZKP_TRANSCRIPT_append_bn(transcript, "t_x_blinding", proof->taux)
|| !ZKP_TRANSCRIPT_append_bn(transcript, "e_blinding", proof->mu))
goto err;
if (!ZKP_TRANSCRIPT_challange(transcript, "w", w))
goto err;
if (!BN_mod_inverse(y_inv, y, order, bn_ctx)
|| !BN_mod_sqr(x2, x, order, bn_ctx)
|| !BN_mod_mul(x3, x2, x, order, bn_ctx)
|| !BN_mod_mul(ux, u, x, order, bn_ctx)
|| !BN_mod_mul(ux2, ux, x, order, bn_ctx)
|| !BN_mod_mul(ux3, ux2, x, order, bn_ctx)
|| !BN_mod_mul(rx, r, x, order, bn_ctx)
|| !BN_mod_mul(rx2, rx, x, order, bn_ctx)
|| !BN_mod_mul(rx3, rx2, x, order, bn_ctx)
|| !BN_mod_mul(rx4, rx3, x, order, bn_ctx)
|| !BN_mod_mul(rx5, rx4, x, order, bn_ctx)
|| !BN_mod_mul(rx6, rx5, x, order, bn_ctx)
|| !BN_copy(pow_z, z))
goto err;
/*
* flatten the constraints
*/
if ((wL = OPENSSL_zalloc(sizeof(*wL) * nn)) == NULL
|| (wR = OPENSSL_zalloc(sizeof(*wR) * nn)) == NULL
|| (wO = OPENSSL_zalloc(sizeof(*wO) * nn)) == NULL
|| (wV = OPENSSL_zalloc(sizeof(*wV) * v_n)) == NULL) {
ERR_raise(ERR_LIB_ZKP_BP, ERR_R_MALLOC_FAILURE);
goto err;
}
for (i = 0; i < ctx->vars_num; i++) {
wL[i] = BN_CTX_get(bn_ctx);
wR[i] = BN_CTX_get(bn_ctx);
wO[i] = BN_CTX_get(bn_ctx);
if (wO[i] == NULL)
goto err;
BN_zero(wL[i]);
BN_zero(wR[i]);
BN_zero(wO[i]);
}
for (i = 0; i < v_n; i++) {
wV[i] = BN_CTX_get(bn_ctx);
if (wV[i] == NULL)
goto err;
BN_zero(wV[i]);
}
BN_zero(wc);
m = sk_BP_R1CS_LINEAR_COMBINATION_num(ctx->constraints);
for (i = 0; i < m; i++) {
lc = sk_BP_R1CS_LINEAR_COMBINATION_value(ctx->constraints, i);
if (lc == NULL)
goto err;
if (lc->type != BP_R1CS_LC_TYPE_VERIFY)
continue;
n = sk_BP_R1CS_LINEAR_COMBINATION_ITEM_num(lc->items);
for (j = 0; j < n; j++) {
item = sk_BP_R1CS_LINEAR_COMBINATION_ITEM_value(lc->items, j);
if (item == NULL)
goto err;
r1cs_var = item->variable;
switch (r1cs_var->type) {
case BP_R1CS_VARIABLE_COMMITTED:
pw = wV[r1cs_var->value];
break;
case BP_R1CS_VARIABLE_MULTIPLIER_LEFT:
pw = wL[r1cs_var->value];
break;
case BP_R1CS_VARIABLE_MULTIPLIER_RIGHT:
pw = wR[r1cs_var->value];
break;
case BP_R1CS_VARIABLE_MULTIPLIER_OUTPUT:
pw = wO[r1cs_var->value];
break;
case BP_R1CS_VARIABLE_ONE:
pw = wc;
break;
default:
break;
}
if (w == NULL)
continue;
if (!BN_mod_mul(product, pow_z, item->scalar, order, bn_ctx))
goto err;
if (r1cs_var->type == BP_R1CS_VARIABLE_COMMITTED
|| r1cs_var->type == BP_R1CS_VARIABLE_ONE) {
if (!BN_mod_sub(pw, pw, product, order, bn_ctx))
goto err;
} else {
if (!BN_mod_add(pw, pw, product, order, bn_ctx))
goto err;
}
pw = NULL;
}
if (!BN_mod_mul(pow_z, pow_z, z, order, bn_ctx))
goto err;
}
if (!zkp_poly_points_append(poly_p, proof->AI1, x)
|| !zkp_poly_points_append(poly_p, proof->AO1, x2)
|| !zkp_poly_points_append(poly_p, proof->S1, x3)
|| !zkp_poly_points_append(poly_p, proof->AI2, ux)
|| !zkp_poly_points_append(poly_p, proof->AO2, ux2)
|| !zkp_poly_points_append(poly_p, proof->S2, ux3)
|| !zkp_poly_points_append(poly_p, proof->T1, rx)
|| !zkp_poly_points_append(poly_p, proof->T3, rx3)
|| !zkp_poly_points_append(poly_p, proof->T4, rx4)
|| !zkp_poly_points_append(poly_p, proof->T5, rx5)
|| !zkp_poly_points_append(poly_p, proof->T6, rx6))
goto err;
BN_one(vec_s[0]);
for (i = 0; i < lg_n; i++) {
scalar = BN_CTX_get(bn_ctx);
vec_ip_x2[i] = BN_CTX_get(bn_ctx);
if (vec_ip_x2[i] == NULL)
goto err;
L = sk_EC_POINT_value(ip_proof->sk_L, i);
R = sk_EC_POINT_value(ip_proof->sk_R, i);
if (L == NULL || R == NULL)
goto err;
if (!ZKP_TRANSCRIPT_append_point(transcript, "L", L, group)
|| !ZKP_TRANSCRIPT_append_point(transcript, "R", R, group))
goto err;
if (!ZKP_TRANSCRIPT_challange(transcript, "x", ip_x))
goto err;
if (!BN_mod_sqr(ip_x2, ip_x, order, bn_ctx)
|| !BN_copy(vec_ip_x2[i], ip_x2)
|| !BN_mod_inverse(ip_x_inv, ip_x, order, bn_ctx)
|| !BN_mod_inverse(ip_x2_inv, ip_x2, order, bn_ctx)
|| !BN_mod_mul(vec_s[0], vec_s[0], ip_x_inv, order, bn_ctx))
goto err;
if (!BN_copy(scalar, ip_x2) || !zkp_poly_points_append(poly_p, L, scalar))
goto err;
scalar = BN_CTX_get(bn_ctx);
if (scalar == NULL || !BN_copy(scalar, ip_x2_inv) || !zkp_poly_points_append(poly_p, R, scalar))
goto err;
}
for (i = 1; i < padded_n; i++) {
lg_i = zkp_floor_log2(i);
vec_s[i] = BN_CTX_get(bn_ctx);
if (vec_s[i] == NULL)
goto err;
if (!BN_mod_mul(vec_s[i], vec_s[i - (1 << lg_i)],
vec_ip_x2[lg_n - 1 - lg_i], order, bn_ctx))
goto err;
}
for (i = 0; i < padded_n; i++) {
g_scalar = BN_CTX_get(bn_ctx);
h_scalar = BN_CTX_get(bn_ctx);
if (h_scalar == NULL)
goto err;
if (!BN_mod_mul(s_a, ip_proof->a, vec_s[i], order, bn_ctx)
|| !BN_mod_mul(s_b, ip_proof->b, vec_s[padded_n - i - 1], order, bn_ctx))
goto err;
BN_set_negative(s_a, 1);
BN_set_negative(s_b, 1);
if (i < ctx->vars_num) {
if (!BN_mod_mul(wR_pow_y_inv, wR[i], pow_y_inv, order, bn_ctx)
|| !BN_mod_mul(tmp, wR_pow_y_inv, wL[i], order, bn_ctx)
|| !BN_mod_add(delta, delta, tmp, order, bn_ctx))
goto err;
if (!BN_mod_mul(g_scalar, x, wR_pow_y_inv, order, bn_ctx)
|| !BN_mod_add(g_scalar, g_scalar, s_a, order, bn_ctx))
goto err;
if (!BN_mod_mul(h_scalar, x, wL[i], order, bn_ctx)
|| !BN_mod_add(h_scalar, h_scalar, wO[i], order, bn_ctx)
|| !BN_mod_add(h_scalar, h_scalar, s_b, order, bn_ctx)
|| !BN_mod_mul(h_scalar, h_scalar, pow_y_inv, order, bn_ctx)
|| !BN_mod_sub(h_scalar, h_scalar, bn1, order, bn_ctx))
goto err;
} else {
if (!BN_mod_mul(g_scalar, u, s_a, order, bn_ctx))
goto err;
if (!BN_mod_mul(h_scalar, pow_y_inv, s_b, order, bn_ctx)
|| !BN_mod_sub(h_scalar, h_scalar, bn1, order, bn_ctx)
|| !BN_mod_mul(h_scalar, h_scalar, u, order, bn_ctx))
goto err;
}
G = sk_EC_POINT_value(pp->sk_G, i);
H = sk_EC_POINT_value(pp->sk_H, i);
if (G == NULL || H == NULL)
goto err;
if (!zkp_poly_points_append(poly_p, G, g_scalar)
|| !zkp_poly_points_append(poly_p, H, h_scalar))
goto err;
if (!BN_mod_mul(pow_y_inv, pow_y_inv, y_inv, order, bn_ctx))
goto err;
}
for (i = 0; i < v_n; i++) {
var = sk_BP_VARIABLE_value(witness->sk_V, i);
if (var == NULL || var->point == NULL)
goto err;
v_scalar = BN_CTX_get(bn_ctx);
if (v_scalar == NULL)
goto err;
if (!BN_mod_mul(v_scalar, wV[i], rx2, order, bn_ctx))
goto err;
if (!zkp_poly_points_append(poly_p, var->point, v_scalar))
goto err;
}
b_scalar = BN_CTX_get(bn_ctx);
h_scalar = BN_CTX_get(bn_ctx);
if (h_scalar == NULL)
goto err;
if (!BN_mod_add(wc, wc, delta, order, bn_ctx)
|| !BN_mod_mul(wc, wc, x2, order, bn_ctx)
|| !BN_mod_sub(wc, wc, proof->tx, order, bn_ctx)
|| !BN_mod_mul(wc, wc, r, order, bn_ctx)
|| !BN_mod_mul(b_scalar, ip_proof->a, ip_proof->b, order, bn_ctx)
|| !BN_mod_sub(b_scalar, proof->tx, b_scalar, order, bn_ctx)
|| !BN_mod_mul(b_scalar, b_scalar, w, order, bn_ctx)
|| !BN_mod_add(b_scalar, b_scalar, wc, order, bn_ctx)
|| !BN_mod_mul(h_scalar, r, proof->taux, order, bn_ctx)
|| !BN_mod_add(h_scalar, h_scalar, proof->mu, order, bn_ctx))
goto err;
BN_set_negative(h_scalar, 1);
if (!zkp_poly_points_append(poly_p, pp->H, h_scalar)
|| !zkp_poly_points_mul(poly_p, P, b_scalar, group, bn_ctx))
goto err;
ret = EC_POINT_is_at_infinity(group, P);
err:
ZKP_TRANSCRIPT_reset(transcript);
OPENSSL_free(wV);
OPENSSL_free(wO);
OPENSSL_free(wR);
OPENSSL_free(wL);
BN_CTX_end(bn_ctx);
BN_CTX_free(bn_ctx);
OPENSSL_free(vec_s);
OPENSSL_free(vec_ip_x2);
EC_POINT_free(P);
zkp_poly_points_free(poly_p);
return ret;
}