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

1138 lines
30 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/ec_local.h>
#include <crypto/zkp/common/zkp_util.h>
#include "internal/endian.h"
#include "bulletproofs.h"
#include "range_proof.h"
#include "r1cs.h"
DEFINE_STACK_OF(BIGNUM)
DEFINE_STACK_OF(EC_POINT)
DEFINE_STACK_OF(BP_VARIABLE)
static point_conversion_form_t form = POINT_CONVERSION_COMPRESSED;
static int bp_stack_of_variable_encode(STACK_OF(BP_VARIABLE) *sk, unsigned char *out,
const EC_GROUP *group, BN_CTX *bn_ctx)
{
int i, n, *q, size;
size_t point_len;
unsigned char *p;
BP_VARIABLE *V;
if (sk == NULL || group == NULL)
return 0;
point_len = EC_POINT_point2oct(group, EC_GROUP_get0_generator(group),
form, NULL, 0, bn_ctx);
n = sk_BP_VARIABLE_num(sk);
if (out == NULL) {
size = sizeof(n) + n * point_len;
for (i = 0; i < n; i++) {
V = sk_BP_VARIABLE_value(sk, i);
if (V == NULL)
break;
if (V->name != NULL) {
size += strlen(V->name);
}
size += 1;
}
return size;
}
q = (int *)out;
*q++ = zkp_l2n((int)n);
p = (unsigned char *)q;
for (i = 0; i < n; i++) {
V = sk_BP_VARIABLE_value(sk, i);
if (V == NULL)
goto end;
if (EC_POINT_point2oct(group, V->point, form, p, point_len, bn_ctx) == 0)
goto end;
p += point_len;
if (V->name == NULL) {
*p++ = '\0';
continue;
}
stpcpy((char *)p, V->name);
p += strlen(V->name) + 1;
}
end:
return p - out;
}
static STACK_OF(BP_VARIABLE) *bp_stack_of_variable_decode(const unsigned char *in,
int *len,
const EC_GROUP *group,
BN_CTX *bn_ctx)
{
char *name;
unsigned char *p;
int *q = (int *)in, n, i;
size_t point_len;
EC_POINT *V = NULL;
BP_VARIABLE *var = NULL;
STACK_OF(BP_VARIABLE) *ret = NULL;
if (in == NULL || group == NULL)
return 0;
point_len = EC_POINT_point2oct(group, EC_GROUP_get0_generator(group),
form, NULL, 0, bn_ctx);
n = (int)zkp_n2l(*q);
q++;
p = (unsigned char *)q;
if (n < 0) {
return NULL;
}
if (!(ret = sk_BP_VARIABLE_new_reserve(NULL, n)))
return NULL;
for (i = 0; i < n; i++) {
if (!(V = EC_POINT_new(group)))
goto err;
if (!EC_POINT_oct2point(group, V, p, point_len, bn_ctx))
goto err;
p += point_len;
name = (char *)p;
if (*name == '\0') {
name = NULL;
} else {
p += strlen(name);
}
p += 1;
if (!(var = BP_VARIABLE_new(name, V, group)))
goto err;
if (sk_BP_VARIABLE_push(ret, var) <= 0)
goto err;
EC_POINT_free(V);
}
if (len != NULL)
*len = p - in;
return ret;
err:
EC_POINT_free(V);
BP_VARIABLE_free(var);
sk_BP_VARIABLE_pop_free(ret, BP_VARIABLE_free);
return NULL;
}
static int bp_inner_product_proof_encode(bp_inner_product_proof_t *ip_proof,
unsigned char *out, const EC_GROUP *group,
BN_CTX *bn_ctx)
{
int bn_len, sk_len, len;
unsigned char *p = out;
STACK_OF(BIGNUM) *sk_bn = NULL;
if (ip_proof == NULL || group == NULL || bn_ctx == NULL)
return 0;
bn_len = BN_num_bytes(EC_GROUP_get0_order(group));
sk_bn = sk_BIGNUM_new_reserve(NULL, 2);
if (sk_bn == NULL)
goto end;
if (sk_BIGNUM_push(sk_bn, ip_proof->a) <= 0
|| sk_BIGNUM_push(sk_bn, ip_proof->b) <= 0)
goto end;
sk_len = zkp_stack_of_bignum_encode(sk_bn, NULL, bn_len);
if (sk_len == 0)
goto end;
len = sk_len;
sk_len = zkp_stack_of_point_encode(ip_proof->sk_L, NULL, group, bn_ctx);
if (sk_len == 0)
goto end;
len += sk_len;
sk_len = zkp_stack_of_point_encode(ip_proof->sk_R, NULL, group, bn_ctx);
if (sk_len == 0)
goto end;
len += sk_len;
if (out == NULL)
return len;
sk_len = zkp_stack_of_bignum_encode(sk_bn, p, bn_len);
if (sk_len == 0)
goto end;
p += sk_len;
sk_len = zkp_stack_of_point_encode(ip_proof->sk_L, p, group, bn_ctx);
if (sk_len == 0)
goto end;
p += sk_len;
sk_len = zkp_stack_of_point_encode(ip_proof->sk_R, p, group, bn_ctx);
if (sk_len == 0)
goto end;
p += sk_len;
end:
sk_BIGNUM_free(sk_bn);
return p != NULL ? p - out : 0;
}
static bp_inner_product_proof_t *bp_inner_product_proof_decode(const unsigned char *in,
int *len,
const EC_GROUP *group,
BN_CTX *bn_ctx)
{
int bn_len, sk_len;
unsigned char *p = (unsigned char *)in;
STACK_OF(BIGNUM) *sk_bn = NULL;
bp_inner_product_proof_t *ip_proof = NULL;
if (in == NULL || group == NULL || bn_ctx == NULL)
return NULL;
bn_len = BN_num_bytes(EC_GROUP_get0_order(group));
if (!(ip_proof = bp_inner_product_proof_alloc(1)))
goto err;
sk_EC_POINT_free(ip_proof->sk_L);
sk_EC_POINT_free(ip_proof->sk_R);
ip_proof->sk_L = NULL;
ip_proof->sk_R = NULL;
if (!(sk_bn = zkp_stack_of_bignum_decode(p, &sk_len, bn_len)))
goto err;
if (sk_BIGNUM_num(sk_bn) != 2)
goto err;
if (!BN_copy(ip_proof->a, sk_BIGNUM_value(sk_bn, 0))
|| !BN_copy(ip_proof->b, sk_BIGNUM_value(sk_bn, 1)))
goto err;
p += sk_len;
if (!(ip_proof->sk_L = zkp_stack_of_point_decode(p, &sk_len, group, bn_ctx)))
goto err;
p += sk_len;
if (!(ip_proof->sk_R = zkp_stack_of_point_decode(p, &sk_len, group, bn_ctx)))
goto err;
p += sk_len;
if (len != NULL)
*len = p - in;
sk_BIGNUM_free(sk_bn);
return ip_proof;
err:
sk_BIGNUM_pop_free(sk_bn, BN_free);
bp_inner_product_proof_free(ip_proof);
return NULL;
}
/** Encodes BP_PUB_PARAM to binary
* \param pp BP_PUB_PARAM object
* \param out the buffer for the result (if NULL the function returns
* number of bytes needed).
* \param size The memory size of the out pointer object
* \return the length of the encoded octet string or 0 if an error occurred
*/
size_t BP_PUB_PARAM_encode(const BP_PUB_PARAM *pp, unsigned char *out, size_t size)
{
int *q, sk_len, curve_id;
size_t point_len, ret = 0, len;
unsigned char *p;
BN_CTX *bn_ctx = NULL;
EC_GROUP *group = NULL;
if (pp == NULL) {
ERR_raise(ERR_LIB_ZKP_BP, ERR_R_PASSED_NULL_PARAMETER);
return ret;
}
group = pp->group;
curve_id = EC_GROUP_get_curve_name(group);
bn_ctx = BN_CTX_new();
if (bn_ctx == NULL) {
ERR_raise(ERR_LIB_ZKP_BP, ERR_R_MALLOC_FAILURE);
goto end;
}
point_len = EC_POINT_point2oct(group, EC_GROUP_get0_generator(group),
form, NULL, 0, bn_ctx);
sk_len = zkp_stack_of_point_encode(pp->sk_G, NULL, group, bn_ctx);
if (sk_len == 0)
goto end;
len = sizeof(int) * 3 + point_len * 2 + sk_len * 2;
if (out == NULL) {
ret = len;
goto end;
}
if (size < len)
goto end;
memset(out, 0, size);
q = (int *)out;
*q++ = zkp_l2n((int)curve_id);
*q++ = zkp_l2n((int)pp->gens_capacity);
*q++ = zkp_l2n((int)pp->party_capacity);
p = (unsigned char *)q;
if (EC_POINT_point2oct(group, pp->H, form, p, point_len, bn_ctx) == 0)
goto end;
p += point_len;
if (EC_POINT_point2oct(group, pp->U, form, p, point_len, bn_ctx) == 0)
goto end;
p += point_len;
sk_len = zkp_stack_of_point_encode(pp->sk_G, p, group, bn_ctx);
if (sk_len == 0)
goto end;
p += sk_len;
sk_len = zkp_stack_of_point_encode(pp->sk_H, p, group, bn_ctx);
if (sk_len == 0)
goto end;
p += sk_len;
ret = len;
end:
BN_CTX_free(bn_ctx);
return ret;
}
/** Decodes binary to BP_PUB_PARAM
* \param in Memory buffer with the encoded BP_PUB_PARAM
* object
* \param size The memory size of the in pointer object
* \return BP_PUB_PARAM object pointer on success and NULL otherwise
*/
BP_PUB_PARAM *BP_PUB_PARAM_decode(const unsigned char *in, size_t size)
{
unsigned char *p;
int curve_id, *q = (int *)in, sk_len;
size_t point_len, gens_capacity, party_capacity, n;
BP_PUB_PARAM *pp = NULL;
BN_CTX *bn_ctx = NULL;
EC_GROUP *group = NULL;
if (in == NULL || size <= 12) {
ERR_raise(ERR_LIB_ZKP_BP, ERR_R_PASSED_NULL_PARAMETER);
return NULL;
}
bn_ctx = BN_CTX_new();
if (bn_ctx == NULL) {
ERR_raise(ERR_LIB_ZKP_BP, ERR_R_MALLOC_FAILURE);
goto err;
}
curve_id = zkp_n2l(*q);
q++;
gens_capacity = (size_t)zkp_n2l(*q);
q++;
party_capacity = (size_t)zkp_n2l(*q);
q++;
p = (unsigned char *)q;
n = gens_capacity * party_capacity;
group = EC_GROUP_new_by_curve_name_ex(NULL, NULL, curve_id);
if (group == NULL)
goto err;
point_len = EC_POINT_point2oct(group, EC_GROUP_get0_generator(group),
form, NULL, 0, bn_ctx);
if (point_len <= 0)
goto err;
if (size < (sizeof(int) * 3 + point_len * (n * 2 + 2))) {
ERR_raise(ERR_LIB_ZKP_BP, ERR_R_PASSED_INVALID_ARGUMENT);
goto err;
}
pp = BP_PUB_PARAM_new(group, gens_capacity, party_capacity);
if (pp == NULL)
goto err;
sk_EC_POINT_pop_free(pp->sk_G, EC_POINT_free);
sk_EC_POINT_pop_free(pp->sk_H, EC_POINT_free);
pp->sk_G = NULL;
pp->sk_H = NULL;
if (!EC_POINT_oct2point(group, pp->H, p, point_len, bn_ctx))
goto err;
p += point_len;
if (!EC_POINT_oct2point(group, pp->U, p, point_len, bn_ctx))
goto err;
p += point_len;
if (!(pp->sk_G = zkp_stack_of_point_decode(p, &sk_len, group, bn_ctx)))
goto err;
p += sk_len;
if (!(pp->sk_H = zkp_stack_of_point_decode(p, &sk_len, group, bn_ctx)))
goto err;
p += sk_len;
EC_GROUP_free(group);
BN_CTX_free(bn_ctx);
return pp;
err:
EC_GROUP_free(group);
BP_PUB_PARAM_free(pp);
BN_CTX_free(bn_ctx);
return NULL;
}
/** Encodes BP_WITNESS to binary
* \param pp BP_WITNESS object
* \param out The buffer for the result (if NULL the function returns
* number of bytes needed).
* \param size The memory size of the out pointer object
* \param flag The flag is an indicator for encoding random number 'r'
* and plaintext 'v', with 1 indicating encoding and 0
* indicating no encoding.
* \return the length of the encoded octet string or 0 if an error occurred
*/
size_t BP_WITNESS_encode(const BP_WITNESS *witness, unsigned char *out,
size_t size, int flag)
{
int *q, curve_id, bn_len, sk_len;
size_t ret = 0, len, n, point_len;
unsigned char *p;
BP_VARIABLE *V;
BN_CTX *bn_ctx = NULL;
EC_GROUP *group = NULL;
if (witness == NULL || witness->sk_V == NULL) {
ERR_raise(ERR_LIB_ZKP_BP, ERR_R_PASSED_NULL_PARAMETER);
return ret;
}
n = sk_BP_VARIABLE_num(witness->sk_V);
if (n == 0) {
ERR_raise(ERR_LIB_ZKP_BP, ERR_R_PASSED_INVALID_ARGUMENT);
return ret;
}
V = sk_BP_VARIABLE_value(witness->sk_V, 0);
if ((curve_id = EC_POINT_get_curve_name(V->point)) == NID_undef) {
ERR_raise(ERR_LIB_ZKP_BP, ERR_R_PASSED_INVALID_ARGUMENT);
goto end;
}
group = EC_GROUP_new_by_curve_name_ex(NULL, NULL, curve_id);
if (group == NULL)
goto end;
bn_len = BN_num_bytes(EC_GROUP_get0_order(group));
point_len = EC_POINT_point2oct(group, EC_GROUP_get0_generator(group),
form, NULL, 0, bn_ctx);
if (point_len <= 0)
goto end;
bn_ctx = BN_CTX_new();
if (bn_ctx == NULL) {
ERR_raise(ERR_LIB_ZKP_BP, ERR_R_MALLOC_FAILURE);
goto end;
}
if (!(sk_len = bp_stack_of_variable_encode(witness->sk_V, NULL, group, bn_ctx)))
goto end;
len = 4 + point_len + sk_len;
if (!(sk_len = zkp_stack_of_bignum_encode(witness->sk_r, NULL, bn_len)))
goto end;
if (flag == 1)
len += sk_len * 2;
if (out == NULL) {
ret = len;
goto end;
}
if (size < len)
goto end;
memset(out, 0, size);
q = (int *)out;
*q++ = zkp_l2n((int)curve_id);
p = (unsigned char *)q;
if (EC_POINT_point2oct(group, witness->H, form, p, point_len, bn_ctx) == 0)
goto end;
p += point_len;
if (!(sk_len = bp_stack_of_variable_encode(witness->sk_V, p, group, bn_ctx)))
goto end;
p += sk_len;
if (flag == 1) {
if (!(sk_len = zkp_stack_of_bignum_encode(witness->sk_r, p, bn_len)))
goto end;
p += sk_len;
if (!(sk_len = zkp_stack_of_bignum_encode(witness->sk_v, p, bn_len)))
goto end;
p += sk_len;
}
ret = len;
end:
BN_CTX_free(bn_ctx);
EC_GROUP_free(group);
return ret;
}
/** Decodes binary to BP_WITNESS
* \param in Memory buffer with the encoded BP_WITNESS
* object
* \param size The memory size of the in pointer object
* \param flag The flag is an indicator for decoding random number 'r'
* and plaintext 'v', with 1 indicating decoding and 0
* indicating no decoding.
* \return BP_WITNESS object pointer on success and NULL otherwise
*/
BP_WITNESS *BP_WITNESS_decode(const unsigned char *in, size_t size, int flag)
{
unsigned char *p;
int curve_id, *q = (int *)in, bn_len, sk_len;
size_t point_len;
BP_WITNESS *witness = NULL;
BN_CTX *bn_ctx = NULL;
EC_GROUP *group = NULL;
if (in == NULL || size <= 12) {
ERR_raise(ERR_LIB_ZKP_BP, ERR_R_PASSED_NULL_PARAMETER);
return NULL;
}
bn_ctx = BN_CTX_new();
if (bn_ctx == NULL) {
ERR_raise(ERR_LIB_ZKP_BP, ERR_R_MALLOC_FAILURE);
goto err;
}
curve_id = zkp_n2l(*q);
q++;
p = (unsigned char *)q;
group = EC_GROUP_new_by_curve_name_ex(NULL, NULL, curve_id);
if (group == NULL)
goto err;
bn_len = BN_num_bytes(EC_GROUP_get0_order(group));
point_len = EC_POINT_point2oct(group, EC_GROUP_get0_generator(group),
form, NULL, 0, bn_ctx);
if (point_len <= 0)
goto err;
if (!(witness = OPENSSL_zalloc(sizeof(*witness)))) {
goto err;
}
if (!(witness->H = EC_POINT_new(group)))
goto err;
if (!EC_POINT_oct2point(group, witness->H, p, point_len, bn_ctx))
goto err;
p += point_len;
if (!(witness->sk_V = bp_stack_of_variable_decode(p, &sk_len, group, bn_ctx)))
goto err;
p += sk_len;
if (flag == 1) {
if (!(witness->sk_r = zkp_stack_of_bignum_decode(p, &sk_len, bn_len)))
goto err;
p += sk_len;
if (!(witness->sk_v = zkp_stack_of_bignum_decode(p, &sk_len, bn_len)))
goto err;
p += sk_len;
}
witness->group = group;
witness->references = 1;
if ((witness->lock = CRYPTO_THREAD_lock_new()) == NULL)
goto err;
BN_CTX_free(bn_ctx);
return witness;
err:
EC_GROUP_free(group);
BP_WITNESS_free(witness);
BN_CTX_free(bn_ctx);
return NULL;
}
/** Encodes BP_RANGE_PROOF to binary
* \param proof BP_RANGE_PROOF object
* \param out the buffer for the result (if NULL the function returns
* number of bytes needed).
* \param size The memory size of the out pointer object
* \return the length of the encoded octet string or 0 if an error occurred
*/
size_t BP_RANGE_PROOF_encode(const BP_RANGE_PROOF *proof, unsigned char *out,
size_t size)
{
int *q, curve_id, bn_len, ret = 0, sk_len;
size_t len;
unsigned char *p = NULL;
bp_inner_product_proof_t *ip_proof;
BN_CTX *bn_ctx = NULL;
EC_GROUP *group = NULL;
STACK_OF(EC_POINT) *sk_point = NULL;
STACK_OF(BIGNUM) *sk_bn = NULL;
if (proof == NULL) {
ERR_raise(ERR_LIB_ZKP_BP, ERR_R_PASSED_NULL_PARAMETER);
return 0;
}
sk_point = sk_EC_POINT_new_reserve(NULL, 4);
sk_bn = sk_BIGNUM_new_reserve(NULL, 3);
if (sk_point == NULL || sk_bn == NULL) {
ERR_raise(ERR_LIB_ZKP_BP, ERR_R_MALLOC_FAILURE);
return 0;
}
ip_proof = proof->ip_proof;
if ((curve_id = EC_POINT_get_curve_name(proof->A)) == NID_undef
|| ip_proof == NULL) {
ERR_raise(ERR_LIB_ZKP_BP, ERR_R_PASSED_INVALID_ARGUMENT);
goto end;
}
group = EC_GROUP_new_by_curve_name_ex(NULL, NULL, curve_id);
if (group == NULL)
goto end;
bn_ctx = BN_CTX_new();
if (bn_ctx == NULL) {
ERR_raise(ERR_LIB_ZKP_BP, ERR_R_MALLOC_FAILURE);
goto end;
}
bn_len = BN_num_bytes(EC_GROUP_get0_order(group));
len = sizeof(int);
if (sk_EC_POINT_push(sk_point, proof->A) <= 0
|| sk_EC_POINT_push(sk_point, proof->S) <= 0
|| sk_EC_POINT_push(sk_point, proof->T1) <= 0
|| sk_EC_POINT_push(sk_point, proof->T2) <= 0)
goto end;
sk_len = zkp_stack_of_point_encode(sk_point, NULL, group, bn_ctx);
if (sk_len == 0)
goto end;
len += sk_len;
if (sk_BIGNUM_push(sk_bn, proof->taux) <= 0
|| sk_BIGNUM_push(sk_bn, proof->mu) <= 0
|| sk_BIGNUM_push(sk_bn, proof->tx) <= 0)
goto end;
sk_len = zkp_stack_of_bignum_encode(sk_bn, NULL, bn_len);
if (sk_len == 0)
goto end;
len += sk_len;
sk_len = bp_inner_product_proof_encode(ip_proof, NULL, group, bn_ctx);
if (sk_len == 0)
goto end;
len += sk_len;
if (out == NULL) {
ret = len;
goto end;
}
if (size < len)
goto end;
memset(out, 0, size);
/* encoding proof */
q = (int *)out;
*q++ = zkp_l2n(curve_id);
p = (unsigned char *)q;
sk_len = zkp_stack_of_point_encode(sk_point, p, group, bn_ctx);
if (sk_len == 0)
goto end;
p += sk_len;
sk_len = zkp_stack_of_bignum_encode(sk_bn, p, bn_len);
if (sk_len == 0)
goto end;
p += sk_len;
/* encoding ip_proof */
len = bp_inner_product_proof_encode(ip_proof, p, group, bn_ctx);
if (len == 0)
goto end;
p += len;
ret = p - out;
end:
BN_CTX_free(bn_ctx);
EC_GROUP_free(group);
sk_BIGNUM_free(sk_bn);
sk_EC_POINT_free(sk_point);
return ret;
}
/** Decodes binary to BP_RANGE_PROOF
* \param in Memory buffer with the encoded BP_RANGE_PROOF object
* \param size The memory size of the in pointer object
* \return BP_RANGE_PROOF object pointer on success and NULL otherwise
*/
BP_RANGE_PROOF *BP_RANGE_PROOF_decode(const unsigned char *in, size_t size)
{
unsigned char *p;
int *q = (int *)in, curve_id, len;
size_t point_len, bn_len, proof_len;
BP_RANGE_PROOF *proof = NULL;
bp_inner_product_proof_t *ip_proof = NULL;
BN_CTX *bn_ctx = NULL;
EC_GROUP *group = NULL;
STACK_OF(EC_POINT) *sk_point = NULL;
STACK_OF(BIGNUM) *sk_bn = NULL;
if (in == NULL || size <= 8) {
ERR_raise(ERR_LIB_ZKP_BP, ERR_R_PASSED_NULL_PARAMETER);
return NULL;
}
curve_id = zkp_n2l(*q);
q++;
if (curve_id <= 0) {
ERR_raise(ERR_LIB_ZKP_BP, ERR_R_PASSED_INVALID_ARGUMENT);
goto err;
}
group = EC_GROUP_new_by_curve_name_ex(NULL, NULL, curve_id);
if (group == NULL)
goto err;
bn_ctx = BN_CTX_new();
if (bn_ctx == NULL) {
ERR_raise(ERR_LIB_ZKP_BP, ERR_R_MALLOC_FAILURE);
goto err;
}
p = (unsigned char *)q;
bn_len = BN_num_bytes(EC_GROUP_get0_order(group));
point_len = EC_POINT_point2oct(group, EC_GROUP_get0_generator(group),
form, NULL, 0, bn_ctx);
if (point_len <= 0)
goto err;
/* len(curve_id) + len(A+S+T1+T2) + len(taux+mu+tx) + len(a+b) */
proof_len = 4 + point_len * 4 + bn_len * 3 + bn_len * 2;
if (size < proof_len) {
ERR_raise(ERR_LIB_ZKP_BP, ERR_R_PASSED_INVALID_ARGUMENT);
goto err;
}
proof = OPENSSL_zalloc(sizeof(*proof));
if (proof == NULL)
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;
}
sk_point = zkp_stack_of_point_decode(p, &len, group, bn_ctx);
if (sk_point == NULL)
goto err;
p += len;
if (sk_EC_POINT_num(sk_point) < 4)
goto err;
proof->A = sk_EC_POINT_value(sk_point, 0);
proof->S = sk_EC_POINT_value(sk_point, 1);
proof->T1 = sk_EC_POINT_value(sk_point, 2);
proof->T2 = sk_EC_POINT_value(sk_point, 3);
sk_bn = zkp_stack_of_bignum_decode(p, &len, bn_len);
if (sk_point == NULL)
goto err;
p += len;
if (sk_BIGNUM_num(sk_bn) < 3)
goto err;
proof->taux = sk_BIGNUM_value(sk_bn, 0);
proof->mu = sk_BIGNUM_value(sk_bn, 1);
proof->tx = sk_BIGNUM_value(sk_bn, 2);
ip_proof = bp_inner_product_proof_decode(p, &len, group, bn_ctx);
if (ip_proof == NULL)
goto err;
p += len;
proof->ip_proof = ip_proof;
sk_BIGNUM_free(sk_bn);
sk_EC_POINT_free(sk_point);
BN_CTX_free(bn_ctx);
EC_GROUP_free(group);
return proof;
err:
sk_BIGNUM_pop_free(sk_bn, BN_free);
sk_EC_POINT_pop_free(sk_point, EC_POINT_free);
bp_inner_product_proof_free(ip_proof);
OPENSSL_free(proof);
BN_CTX_free(bn_ctx);
EC_GROUP_free(group);
return NULL;
}
/** Encodes BP_R1CS_PROOF to binary
* \param proof BP_R1CS_PROOF object
* \param out the buffer for the result (if NULL the function returns
* number of bytes needed).
* \param size The memory size of the out pointer object
* \return the length of the encoded octet string or 0 if an error occurred
*/
size_t BP_R1CS_PROOF_encode(const BP_R1CS_PROOF *proof, unsigned char *out,
size_t size)
{
int *q, curve_id, bn_len, ret = 0, sk_len;
size_t len;
unsigned char *p = NULL;
bp_inner_product_proof_t *ip_proof;
BN_CTX *bn_ctx = NULL;
EC_GROUP *group = NULL;
STACK_OF(EC_POINT) *sk_point = NULL;
STACK_OF(BIGNUM) *sk_bn = NULL;
if (proof == NULL) {
ERR_raise(ERR_LIB_ZKP_BP, ERR_R_PASSED_NULL_PARAMETER);
return 0;
}
sk_point = sk_EC_POINT_new_reserve(NULL, 11);
sk_bn = sk_BIGNUM_new_reserve(NULL, 3);
if (sk_point == NULL || sk_bn == NULL) {
ERR_raise(ERR_LIB_ZKP_BP, ERR_R_MALLOC_FAILURE);
return 0;
}
ip_proof = proof->ip_proof;
if ((curve_id = EC_POINT_get_curve_name(proof->AI1)) == NID_undef
|| ip_proof == NULL) {
ERR_raise(ERR_LIB_ZKP_BP, ERR_R_PASSED_INVALID_ARGUMENT);
goto end;
}
group = EC_GROUP_new_by_curve_name_ex(NULL, NULL, curve_id);
if (group == NULL)
goto end;
bn_ctx = BN_CTX_new();
if (bn_ctx == NULL) {
ERR_raise(ERR_LIB_ZKP_BP, ERR_R_MALLOC_FAILURE);
goto end;
}
bn_len = BN_num_bytes(EC_GROUP_get0_order(group));
len = sizeof(int);
if (sk_EC_POINT_push(sk_point, proof->AI1) <= 0
|| sk_EC_POINT_push(sk_point, proof->AO1) <= 0
|| sk_EC_POINT_push(sk_point, proof->S1) <= 0
|| sk_EC_POINT_push(sk_point, proof->T1) <= 0
|| sk_EC_POINT_push(sk_point, proof->T3) <= 0
|| sk_EC_POINT_push(sk_point, proof->T4) <= 0
|| sk_EC_POINT_push(sk_point, proof->T5) <= 0
|| sk_EC_POINT_push(sk_point, proof->T6) <= 0
#if 0
|| sk_EC_POINT_push(sk_point, proof->AI2) <= 0
|| sk_EC_POINT_push(sk_point, proof->AO2) <= 0
|| sk_EC_POINT_push(sk_point, proof->S2) <= 0
#endif
)
goto end;
sk_len = zkp_stack_of_point_encode(sk_point, NULL, group, bn_ctx);
if (sk_len == 0)
goto end;
len += sk_len;
if (sk_BIGNUM_push(sk_bn, proof->taux) <= 0
|| sk_BIGNUM_push(sk_bn, proof->mu) <= 0
|| sk_BIGNUM_push(sk_bn, proof->tx) <= 0)
goto end;
sk_len = zkp_stack_of_bignum_encode(sk_bn, NULL, bn_len);
if (sk_len == 0)
goto end;
len += sk_len;
sk_len = bp_inner_product_proof_encode(ip_proof, NULL, group, bn_ctx);
if (sk_len == 0)
goto end;
len += sk_len;
if (out == NULL) {
ret = len;
goto end;
}
if (size < len)
goto end;
memset(out, 0, size);
/* encoding proof */
q = (int *)out;
*q++ = zkp_l2n(curve_id);
p = (unsigned char *)q;
sk_len = zkp_stack_of_point_encode(sk_point, p, group, bn_ctx);
if (sk_len == 0)
goto end;
p += sk_len;
sk_len = zkp_stack_of_bignum_encode(sk_bn, p, bn_len);
if (sk_len == 0)
goto end;
p += sk_len;
/* encoding ip_proof */
sk_len = bp_inner_product_proof_encode(ip_proof, p, group, bn_ctx);
if (sk_len == 0)
goto end;
p += sk_len;
ret = p - out;
end:
BN_CTX_free(bn_ctx);
EC_GROUP_free(group);
sk_BIGNUM_free(sk_bn);
sk_EC_POINT_free(sk_point);
return ret;
}
/** Decodes binary to BP_R1CS_PROOF
* \param in Memory buffer with the encoded BP_R1CS_PROOF object
* \param size The memory size of the in pointer object
* \return BP_R1CS_PROOF object pointer on success and NULL otherwise
*/
BP_R1CS_PROOF *BP_R1CS_PROOF_decode(const unsigned char *in, size_t size)
{
unsigned char *p;
int *q = (int *)in, curve_id, len;
size_t point_len, bn_len, proof_len;
BP_R1CS_PROOF *proof = NULL;
bp_inner_product_proof_t *ip_proof = NULL;
BN_CTX *bn_ctx = NULL;
EC_GROUP *group = NULL;
STACK_OF(EC_POINT) *sk_point = NULL;
STACK_OF(BIGNUM) *sk_bn = NULL;
if (in == NULL || size <= 8) {
ERR_raise(ERR_LIB_ZKP_BP, ERR_R_PASSED_NULL_PARAMETER);
return NULL;
}
curve_id = zkp_n2l(*q);
q++;
if (curve_id <= 0) {
ERR_raise(ERR_LIB_ZKP_BP, ERR_R_PASSED_INVALID_ARGUMENT);
goto err;
}
group = EC_GROUP_new_by_curve_name_ex(NULL, NULL, curve_id);
if (group == NULL)
goto err;
bn_ctx = BN_CTX_new();
if (bn_ctx == NULL) {
ERR_raise(ERR_LIB_ZKP_BP, ERR_R_MALLOC_FAILURE);
goto err;
}
p = (unsigned char *)q;
bn_len = BN_num_bytes(EC_GROUP_get0_order(group));
point_len = EC_POINT_point2oct(group, EC_GROUP_get0_generator(group),
form, NULL, 0, bn_ctx);
if (point_len <= 0)
goto err;
#if 1
proof_len = 4 + point_len * 8 + bn_len * 3 + bn_len * 2;
#else
proof_len = 4 + point_len * 11 + bn_len * 3 + bn_len * 2;
#endif
if (size < proof_len) {
ERR_raise(ERR_LIB_ZKP_BP, ERR_R_PASSED_INVALID_ARGUMENT);
goto err;
}
proof = OPENSSL_zalloc(sizeof(*proof));
if (proof == NULL)
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;
}
sk_point = zkp_stack_of_point_decode(p, &len, group, bn_ctx);
if (sk_point == NULL)
goto err;
p += len;
if (sk_EC_POINT_num(sk_point) < 8)
goto err;
proof->AI1 = sk_EC_POINT_value(sk_point, 0);
proof->AO1 = sk_EC_POINT_value(sk_point, 1);
proof->S1 = sk_EC_POINT_value(sk_point, 2);
proof->T1 = sk_EC_POINT_value(sk_point, 3);
proof->T3 = sk_EC_POINT_value(sk_point, 4);
proof->T4 = sk_EC_POINT_value(sk_point, 5);
proof->T5 = sk_EC_POINT_value(sk_point, 6);
proof->T6 = sk_EC_POINT_value(sk_point, 7);
#if 1
proof->AI2 = EC_POINT_new(group);
proof->AO2 = EC_POINT_new(group);
proof->S2 = EC_POINT_new(group);
if (proof->AI2 == NULL || proof->AO2 == NULL || proof->S2 == NULL) {
ERR_raise(ERR_LIB_ZKP_BP, ERR_R_MALLOC_FAILURE);
goto err;
}
EC_POINT_set_to_infinity(group, proof->AI2);
EC_POINT_set_to_infinity(group, proof->AO2);
EC_POINT_set_to_infinity(group, proof->S2);
#else
proof->AI2 = sk_EC_POINT_value(sk_point, 8);
proof->AO2 = sk_EC_POINT_value(sk_point, 9);
proof->S2 = sk_EC_POINT_value(sk_point, 10);
#endif
sk_bn = zkp_stack_of_bignum_decode(p, &len, bn_len);
if (sk_point == NULL)
goto err;
p += len;
if (sk_BIGNUM_num(sk_bn) < 3)
goto err;
proof->taux = sk_BIGNUM_value(sk_bn, 0);
proof->mu = sk_BIGNUM_value(sk_bn, 1);
proof->tx = sk_BIGNUM_value(sk_bn, 2);
ip_proof = bp_inner_product_proof_decode(p, &len, group, bn_ctx);
if (ip_proof == NULL)
goto err;
p += len;
proof->ip_proof = ip_proof;
sk_BIGNUM_free(sk_bn);
sk_EC_POINT_free(sk_point);
BN_CTX_free(bn_ctx);
EC_GROUP_free(group);
return proof;
err:
sk_BIGNUM_pop_free(sk_bn, BN_free);
sk_EC_POINT_pop_free(sk_point, EC_POINT_free);
bp_inner_product_proof_free(ip_proof);
BP_R1CS_PROOF_free(proof);
BN_CTX_free(bn_ctx);
EC_GROUP_free(group);
return NULL;
}