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

639 lines
19 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 <openssl/zkpbperr.h>
#include <openssl/zkp_transcript.h>
#include <crypto/zkp/common/zkp_util.h>
#include <crypto/ec/ec_local.h>
#include "inner_product.h"
DEFINE_STACK_OF(BIGNUM)
DEFINE_STACK_OF(EC_POINT)
bp_inner_product_pub_param_t *bp_inner_product_pub_param_new(const EC_GROUP *group,
STACK_OF(EC_POINT) *sk_G,
STACK_OF(EC_POINT) *sk_H)
{
bp_inner_product_pub_param_t *pp = NULL;
if (sk_EC_POINT_num(sk_G) != sk_EC_POINT_num(sk_H)) {
ERR_raise(ERR_LIB_ZKP_BP, ERR_R_PASSED_INVALID_ARGUMENT);
return NULL;
}
if (!(pp = OPENSSL_zalloc(sizeof(*pp)))) {
ERR_raise(ERR_LIB_ZKP_BP, ERR_R_MALLOC_FAILURE);
return NULL;
}
pp->group = group;
pp->sk_G = sk_G;
pp->sk_H = sk_H;
return pp;
}
void bp_inner_product_pub_param_free(bp_inner_product_pub_param_t *pp)
{
if (!pp)
return;
OPENSSL_clear_free((void *)pp, sizeof(*pp));
}
bp_inner_product_ctx_t *bp_inner_product_ctx_new(bp_inner_product_pub_param_t *pp,
ZKP_TRANSCRIPT *transcript,
EC_POINT *U, EC_POINT *P,
STACK_OF(BIGNUM) *sk_G_factors,
STACK_OF(BIGNUM) *sk_H_factors)
{
bp_inner_product_ctx_t *ctx = NULL;
if (pp == NULL || U == NULL || transcript == NULL
|| sk_G_factors == NULL || sk_H_factors == NULL) {
ERR_raise(ERR_LIB_ZKP_BP, ERR_R_PASSED_NULL_PARAMETER);
return NULL;
}
if (sk_BIGNUM_num(sk_G_factors) != sk_EC_POINT_num(pp->sk_G)
|| sk_BIGNUM_num(sk_H_factors) != sk_EC_POINT_num(pp->sk_H)) {
ERR_raise(ERR_LIB_ZKP_BP, ERR_R_PASSED_INVALID_ARGUMENT);
return NULL;
}
if (!(ctx = OPENSSL_zalloc(sizeof(*ctx)))) {
ERR_raise(ERR_LIB_ZKP_BP, ERR_R_MALLOC_FAILURE);
return NULL;
}
ctx->pp = pp;
ctx->transcript = transcript;
ctx->sk_G_factors = sk_G_factors;
ctx->sk_H_factors = sk_H_factors;
if (!(ctx->U = EC_POINT_dup(U, pp->group)))
goto err;
if (P != NULL && !(ctx->P = EC_POINT_dup(P, pp->group)))
goto err;
return ctx;
err:
bp_inner_product_ctx_free(ctx);
return NULL;
}
void bp_inner_product_ctx_free(bp_inner_product_ctx_t *ctx)
{
if (!ctx)
return;
EC_POINT_free(ctx->U);
EC_POINT_free(ctx->P);
OPENSSL_clear_free((void *)ctx, sizeof(*ctx));
}
bp_inner_product_witness_t *bp_inner_product_witness_new(STACK_OF(BIGNUM) *sk_a,
STACK_OF(BIGNUM) *sk_b)
{
bp_inner_product_witness_t *witness = NULL;
if (!sk_a || !sk_b) {
ERR_raise(ERR_LIB_ZKP_BP, ERR_R_PASSED_NULL_PARAMETER);
return NULL;
}
if (sk_BIGNUM_num(sk_a) != sk_BIGNUM_num(sk_b)) {
ERR_raise(ERR_LIB_ZKP_BP, ERR_R_PASSED_INVALID_ARGUMENT);
return NULL;
}
if (!(witness = OPENSSL_zalloc(sizeof(*witness)))) {
ERR_raise(ERR_LIB_ZKP_BP, ERR_R_MALLOC_FAILURE);
return NULL;
}
witness->sk_a = sk_a;
witness->sk_b = sk_b;
return witness;
}
void bp_inner_product_witness_free(bp_inner_product_witness_t *witness)
{
if (!witness)
return;
OPENSSL_free(witness);
}
bp_inner_product_proof_t *bp_inner_product_proof_alloc(int n)
{
bp_inner_product_proof_t *proof = NULL;
proof = OPENSSL_zalloc(sizeof(*proof));
if (!proof) {
ERR_raise(ERR_LIB_ZKP_BP, ERR_R_MALLOC_FAILURE);
return NULL;
}
proof->sk_L = sk_EC_POINT_new_reserve(NULL, n);
if (!proof->sk_L) {
ERR_raise(ERR_LIB_ZKP_BP, ERR_R_MALLOC_FAILURE);
goto err;
}
proof->sk_R = sk_EC_POINT_new_reserve(NULL, n);
if (!proof->sk_R) {
ERR_raise(ERR_LIB_ZKP_BP, ERR_R_MALLOC_FAILURE);
goto err;
}
if (!(proof->a = BN_new()) || !(proof->b = BN_new()))
goto err;
return proof;
err:
bp_inner_product_proof_free(proof);
return NULL;
}
bp_inner_product_proof_t *bp_inner_product_proof_new(bp_inner_product_ctx_t *ctx)
{
int n;
if (ctx == NULL || ctx->pp == NULL) {
ERR_raise(ERR_LIB_ZKP_BP, ERR_R_PASSED_NULL_PARAMETER);
}
n = sk_EC_POINT_num(ctx->pp->sk_G);
return bp_inner_product_proof_alloc(n);
}
void bp_inner_product_proof_free(bp_inner_product_proof_t *proof)
{
if (!proof)
return;
BN_free(proof->a);
BN_free(proof->b);
sk_EC_POINT_pop_free(proof->sk_L, EC_POINT_free);
sk_EC_POINT_pop_free(proof->sk_R, EC_POINT_free);
OPENSSL_free(proof);
}
bp_inner_product_proof_t *bp_inner_product_proof_prove(bp_inner_product_ctx_t *ctx,
bp_inner_product_witness_t *witness)
{
int i, j, m, n, pp_num, poly_num;
ZKP_TRANSCRIPT *transcript;
BN_CTX *bn_ctx = NULL;
BIGNUM *x, *x_inv, *t, *cL, *cR, *a, *b, *u, *u_inv;
BIGNUM *G_factors_L, *G_factors_R, *H_factors_L, *H_factors_R;
BIGNUM *a_L, *a_R, *b_L, *b_R, *aL, *aR, *bL, *bR, *sk_a_L, *sk_b_L;
EC_POINT *L = NULL, *R = NULL, *P = NULL;
EC_POINT *G_L, *G_R, *H_L, *H_R, *sk_G_L, *sk_H_L;
STACK_OF(EC_POINT) *sk_G = NULL, *sk_H = NULL, *p_sk_G, *p_sk_H;
STACK_OF(BIGNUM) *sk_a = NULL, *sk_b = NULL, *p_sk_a, *p_sk_b;
zkp_poly_points_t *poly_l = NULL, *poly_r = NULL, *poly_g = NULL, *poly_h = NULL;
const BIGNUM *order;
const EC_GROUP *group;
bp_inner_product_pub_param_t *pp;
bp_inner_product_proof_t *proof = NULL, *ret = NULL;
if (!ctx || !witness || !ctx->pp) {
ERR_raise(ERR_LIB_ZKP_BP, ERR_R_PASSED_NULL_PARAMETER);
return NULL;
}
transcript = ctx->transcript;
pp = ctx->pp;
group = pp->group;
order = EC_GROUP_get0_order(group);
pp_num = sk_EC_POINT_num(pp->sk_G);
poly_num = pp_num + 1;
if (pp_num != sk_BIGNUM_num(witness->sk_a)) {
ERR_raise(ERR_LIB_ZKP_BP, ERR_R_PASSED_INVALID_ARGUMENT);
return NULL;
}
if (!(proof = bp_inner_product_proof_new(ctx)))
goto end;
if (!(poly_l = zkp_poly_points_new(poly_num)) || !(poly_r = zkp_poly_points_new(poly_num))
|| !(poly_g = zkp_poly_points_new(2)) || !(poly_h = zkp_poly_points_new(2)))
goto end;
if (!(sk_G = sk_EC_POINT_new_reserve(NULL, pp_num))
|| !(sk_H = sk_EC_POINT_new_reserve(NULL, pp_num))
|| !(sk_a = sk_BIGNUM_new_reserve(NULL, pp_num))
|| !(sk_b = sk_BIGNUM_new_reserve(NULL, pp_num))) {
ERR_raise(ERR_LIB_ZKP_BP, ERR_R_MALLOC_FAILURE);
goto end;
}
bn_ctx = BN_CTX_new_ex(group->libctx);
if (bn_ctx == NULL)
goto end;
BN_CTX_start(bn_ctx);
x = BN_CTX_get(bn_ctx);
x_inv = BN_CTX_get(bn_ctx);
cL = BN_CTX_get(bn_ctx);
cR = BN_CTX_get(bn_ctx);
t = BN_CTX_get(bn_ctx);
if (t == NULL)
goto end;
p_sk_G = pp->sk_G;
p_sk_H = pp->sk_H;
p_sk_a = witness->sk_a;
p_sk_b = witness->sk_b;
for (i = 0; i < pp_num; i++) {
if (!(P = EC_POINT_new(group)) || sk_EC_POINT_push(sk_G, P) <= 0)
goto end;
P = NULL;
if (!(P = EC_POINT_new(group)) || sk_EC_POINT_push(sk_H, P) <= 0)
goto end;
P = NULL;
if (!(a = BN_CTX_get(bn_ctx)) || sk_BIGNUM_push(sk_a, a) <= 0
|| !(b = BN_CTX_get(bn_ctx)) || sk_BIGNUM_push(sk_b, b) <= 0)
goto end;
}
for (n = pp_num, j = 0; n > 1; n = m, j++) {
m = n / 2;
BN_zero(cL);
BN_zero(cR);
if (!(L = EC_POINT_new(group)) || !(R = EC_POINT_new(group)))
goto end;
if (!EC_POINT_set_to_infinity(group, L)
|| !EC_POINT_set_to_infinity(group, R))
goto end;
zkp_poly_points_reset(poly_l);
zkp_poly_points_reset(poly_r);
for (i = 0; i < m; i++) {
/* (21) */
a_L = sk_BIGNUM_value(p_sk_a, i);
b_R = sk_BIGNUM_value(p_sk_b, i + m);
if (!BN_mul(t, a_L, b_R, bn_ctx)
|| !BN_mod_add(cL, cL, t, order, bn_ctx))
goto end;
/* (22) */
a_R = sk_BIGNUM_value(p_sk_a, i + m);
b_L = sk_BIGNUM_value(p_sk_b, i);
if (!BN_mul(t, a_R, b_L, bn_ctx)
|| !BN_mod_add(cR, cR, t, order, bn_ctx))
goto end;
aL = BN_CTX_get(bn_ctx);
aR = BN_CTX_get(bn_ctx);
bL = BN_CTX_get(bn_ctx);
bR = BN_CTX_get(bn_ctx);
if (bR == NULL)
goto end;
if (p_sk_G == pp->sk_G) {
G_factors_L = sk_BIGNUM_value(ctx->sk_G_factors, i);
G_factors_R = sk_BIGNUM_value(ctx->sk_G_factors, i + m);
if (!BN_mod_mul(aL, a_L, G_factors_R, order, bn_ctx))
goto end;
if (!BN_mod_mul(aR, a_R, G_factors_L, order, bn_ctx))
goto end;
H_factors_L = sk_BIGNUM_value(ctx->sk_H_factors, i);
H_factors_R = sk_BIGNUM_value(ctx->sk_H_factors, i + m);
if (!BN_mod_mul(bL, b_L, H_factors_R, order, bn_ctx))
goto end;
if (!BN_mod_mul(bR, b_R, H_factors_L, order, bn_ctx))
goto end;
} else {
if (!BN_copy(aL, a_L) || !BN_copy(aR, a_R)
|| !BN_copy(bL, b_L) || !BN_copy(bR, b_R))
goto end;
}
G_L = sk_EC_POINT_value(p_sk_G, i);
G_R = sk_EC_POINT_value(p_sk_G, i + m);
H_L = sk_EC_POINT_value(p_sk_H, i);
H_R = sk_EC_POINT_value(p_sk_H, i + m);
if (!zkp_poly_points_append(poly_l, G_R, aL)
|| !zkp_poly_points_append(poly_l, H_L, bR)
|| !zkp_poly_points_append(poly_r, G_L, aR)
|| !zkp_poly_points_append(poly_r, H_R, bL))
goto end;
}
/* (23, 24) */
if (!zkp_poly_points_append(poly_l, ctx->U, cL)
|| !zkp_poly_points_append(poly_r, ctx->U, cR))
goto end;
if (!zkp_poly_points_mul(poly_l, L, NULL, group, bn_ctx)
|| !zkp_poly_points_mul(poly_r, R, NULL, group, bn_ctx))
goto end;
/* compute the challenge */
if (!ZKP_TRANSCRIPT_append_point(transcript, "L", L, group)
|| !ZKP_TRANSCRIPT_append_point(transcript, "R", R, group))
goto end;
if (!ZKP_TRANSCRIPT_challange(transcript, "x", x))
goto end;
/* (26, 27) */
if (!BN_mod_inverse(x_inv, x, order, bn_ctx))
goto end;
for (i = 0; i < m; i++) {
u = BN_CTX_get(bn_ctx);
u_inv = BN_CTX_get(bn_ctx);
if (u_inv == NULL)
goto end;
if (n == pp_num) {
G_factors_L = sk_BIGNUM_value(ctx->sk_G_factors, i);
G_factors_R = sk_BIGNUM_value(ctx->sk_G_factors, i + m);
if (!BN_mod_mul(u_inv, x_inv, G_factors_L, order, bn_ctx)
|| !BN_mod_mul(u, x, G_factors_R, order, bn_ctx))
goto end;
} else {
if (!BN_copy(u, x) || !BN_copy(u_inv, x_inv))
goto end;
}
zkp_poly_points_reset(poly_g);
G_L = sk_EC_POINT_value(p_sk_G, i);
G_R = sk_EC_POINT_value(p_sk_G, i + m);
sk_G_L = sk_EC_POINT_value(sk_G, i);
if (!zkp_poly_points_append(poly_g, G_L, u_inv)
|| !zkp_poly_points_append(poly_g, G_R, u))
goto end;
/* (29) */
if (!zkp_poly_points_mul(poly_g, sk_G_L, NULL, group, bn_ctx))
goto end;
u = BN_CTX_get(bn_ctx);
u_inv = BN_CTX_get(bn_ctx);
if (u_inv == NULL)
goto end;
if (n == pp_num) {
H_factors_L = sk_BIGNUM_value(ctx->sk_H_factors, i);
H_factors_R = sk_BIGNUM_value(ctx->sk_H_factors, i + m);
if (!BN_mod_mul(u, x, H_factors_L, order, bn_ctx)
|| !BN_mod_mul(u_inv, x_inv, H_factors_R, order, bn_ctx))
goto end;
} else {
if (!BN_copy(u, x) || !BN_copy(u_inv, x_inv))
goto end;
}
zkp_poly_points_reset(poly_h);
H_L = sk_EC_POINT_value(p_sk_H, i);
H_R = sk_EC_POINT_value(p_sk_H, i + m);
sk_H_L = sk_EC_POINT_value(sk_H, i);
if (!zkp_poly_points_append(poly_h, H_L, u)
|| !zkp_poly_points_append(poly_h, H_R, u_inv))
goto end;
/* (30) */
if (!zkp_poly_points_mul(poly_h, sk_H_L, NULL, group, bn_ctx))
goto end;
sk_a_L = sk_BIGNUM_value(sk_a, i);
sk_b_L = sk_BIGNUM_value(sk_b, i);
a_L = sk_BIGNUM_value(p_sk_a, i);
a_R = sk_BIGNUM_value(p_sk_a, i + m);
b_L = sk_BIGNUM_value(p_sk_b, i);
b_R = sk_BIGNUM_value(p_sk_b, i + m);
/* (33) */
if (!BN_mod_mul(sk_a_L, a_L, x, order, bn_ctx)
|| !BN_mod_mul(t, a_R, x_inv, order, bn_ctx)
|| !BN_mod_add(sk_a_L, sk_a_L, t, order, bn_ctx))
goto end;
/* (34) */
if (!BN_mod_mul(sk_b_L, b_L, x_inv, order, bn_ctx)
|| !BN_mod_mul(t, b_R, x, order, bn_ctx)
|| !BN_mod_add(sk_b_L, sk_b_L, t, order, bn_ctx))
goto end;
}
if (sk_EC_POINT_push(proof->sk_L, L) <= 0
|| sk_EC_POINT_push(proof->sk_R, R) <= 0)
goto end;
L = R = NULL;
p_sk_G = sk_G;
p_sk_H = sk_H;
p_sk_a = sk_a;
p_sk_b = sk_b;
}
if (!BN_copy(proof->a, sk_BIGNUM_value(p_sk_a, 0))
|| !BN_copy(proof->b, sk_BIGNUM_value(p_sk_b, 0)))
goto end;
/*
BN_debug_print(NULL, proof->a, "ip_proof->a");
BN_debug_print(NULL, proof->b, "ip_proof->b");
*/
ret = proof;
proof = NULL;
end:
sk_BIGNUM_free(sk_a);
sk_BIGNUM_free(sk_b);
sk_EC_POINT_pop_free(sk_G, EC_POINT_free);
sk_EC_POINT_pop_free(sk_H, EC_POINT_free);
EC_POINT_free(L);
EC_POINT_free(R);
EC_POINT_free(P);
BN_CTX_end(bn_ctx);
BN_CTX_free(bn_ctx);
zkp_poly_points_free(poly_l);
zkp_poly_points_free(poly_r);
zkp_poly_points_free(poly_g);
zkp_poly_points_free(poly_h);
bp_inner_product_proof_free(proof);
return ret;
}
int bp_inner_product_proof_verify(bp_inner_product_ctx_t *ctx,
bp_inner_product_proof_t *proof)
{
int ret = 0;
int i, j, m, n, proof_num, pp_num;
EC_POINT *P = NULL, *L, *R, *G, *H;
ZKP_TRANSCRIPT *transcript;
BN_CTX *bn_ctx = NULL;
BIGNUM **vec_x = NULL, **vec_x_inv = NULL, *G_factors, *H_factors;
BIGNUM *s, *s_inv, *u, *u_inv, *x2, *x2_inv;
zkp_poly_points_t *poly = NULL;
const BIGNUM *order;
const EC_GROUP *group;
bp_inner_product_pub_param_t *pp;
if (!ctx || !proof) {
ERR_raise(ERR_LIB_ZKP_BP, ERR_R_PASSED_NULL_PARAMETER);
return ret;
}
transcript = ctx->transcript;
pp = ctx->pp;
group = pp->group;
order = EC_GROUP_get0_order(group);
pp_num = sk_EC_POINT_num(pp->sk_G);
proof_num = sk_EC_POINT_num(proof->sk_L);
n = 2 * proof_num + 2 * pp_num + 1;
if (!(vec_x = OPENSSL_zalloc(proof_num * sizeof(*vec_x)))
|| !(vec_x_inv = OPENSSL_zalloc(proof_num * sizeof(*vec_x_inv)))) {
ERR_raise(ERR_LIB_ZKP_BP, ERR_R_MALLOC_FAILURE);
goto end;
}
if (!(poly = zkp_poly_points_new(n)))
goto end;
if (!(P = EC_POINT_new(group)))
goto end;
bn_ctx = BN_CTX_new_ex(group->libctx);
if (!bn_ctx)
goto end;
BN_CTX_start(bn_ctx);
s = BN_CTX_get(bn_ctx);
s_inv = BN_CTX_get(bn_ctx);
if (s_inv == NULL)
goto end;
for (i = 0; i < proof_num; i++) {
vec_x[i] = BN_CTX_get(bn_ctx);
vec_x_inv[i] = BN_CTX_get(bn_ctx);
x2 = BN_CTX_get(bn_ctx);
x2_inv = BN_CTX_get(bn_ctx);
if (x2_inv == NULL)
goto end;
L = sk_EC_POINT_value(proof->sk_L, i);
R = sk_EC_POINT_value(proof->sk_R, i);
/* compute hash */
if (!ZKP_TRANSCRIPT_append_point(transcript, "L", L, group)
|| !ZKP_TRANSCRIPT_append_point(transcript, "R", R, group))
goto end;
if (!ZKP_TRANSCRIPT_challange(transcript, "x", vec_x[i]))
goto end;
if (!BN_mod_inverse(vec_x_inv[i], vec_x[i], order, bn_ctx)
|| !BN_mod_sqr(x2, vec_x[i], order, bn_ctx)
|| !BN_mod_inverse(x2_inv, x2, order, bn_ctx))
goto end;
BN_set_negative(x2, !BN_is_negative(x2));
BN_set_negative(x2_inv, !BN_is_negative(x2_inv));
if (!zkp_poly_points_append(poly, L, x2) || !zkp_poly_points_append(poly, R, x2_inv))
goto end;
}
for (i = 0; i < pp_num; i++) {
G = sk_EC_POINT_value(pp->sk_G, i);
H = sk_EC_POINT_value(pp->sk_H, i);
G_factors = sk_BIGNUM_value(ctx->sk_G_factors, i);
H_factors = sk_BIGNUM_value(ctx->sk_H_factors, i);
u = BN_CTX_get(bn_ctx);
u_inv = BN_CTX_get(bn_ctx);
if (u == NULL)
goto end;
BN_one(s);
for (j = 0; j < proof_num; j++) {
m = i & (1 << (proof_num - j - 1));
if (!BN_mod_mul(s, s, m ? vec_x[j] : vec_x_inv[j], order, bn_ctx))
goto end;
}
if (!BN_mod_inverse(s_inv, s, order, bn_ctx))
goto end;
if (!BN_mod_mul(s, s, proof->a, order, bn_ctx)
|| !BN_mod_mul(u, s, G_factors, order, bn_ctx)
|| !BN_mod_mul(s_inv, s_inv, proof->b, order, bn_ctx)
|| !BN_mod_mul(u_inv, s_inv, H_factors, order, bn_ctx))
goto end;
if (!zkp_poly_points_append(poly, G, u) || !zkp_poly_points_append(poly, H, u_inv))
goto end;
}
if (!BN_mod_mul(s, proof->a, proof->b, order, bn_ctx))
goto end;
if (!zkp_poly_points_append(poly, ctx->U, s))
goto end;
if (!zkp_poly_points_mul(poly, P, NULL, group, bn_ctx))
goto end;
ret = EC_POINT_cmp(group, P, ctx->P, bn_ctx) == 0;
end:
BN_CTX_end(bn_ctx);
BN_CTX_free(bn_ctx);
zkp_poly_points_free(poly);
EC_POINT_free(P);
OPENSSL_free(vec_x);
OPENSSL_free(vec_x_inv);
return ret;
}