768 lines
19 KiB
C
768 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 <crypto/ec.h>
|
|
#include <crypto/ec/ec_local.h>
|
|
#include "r1cs.h"
|
|
|
|
DEFINE_STACK_OF(BIGNUM)
|
|
DEFINE_STACK_OF(BP_R1CS_VARIABLE)
|
|
DEFINE_STACK_OF(BP_R1CS_LINEAR_COMBINATION_ITEM)
|
|
DEFINE_STACK_OF(BP_R1CS_LINEAR_COMBINATION)
|
|
|
|
BP_R1CS_VARIABLE *BP_R1CS_VARIABLE_new(BP_R1CS_VARIABLE_TYPE type, uint64_t value)
|
|
{
|
|
BP_R1CS_VARIABLE *var = NULL;
|
|
|
|
var = OPENSSL_zalloc(sizeof(*var));
|
|
if (var == NULL) {
|
|
ERR_raise(ERR_LIB_ZKP_BP, ERR_R_MALLOC_FAILURE);
|
|
return NULL;
|
|
}
|
|
|
|
var->references = 1;
|
|
if ((var->lock = CRYPTO_THREAD_lock_new()) == NULL) {
|
|
ERR_raise(ERR_LIB_ZKP_BP, ERR_R_MALLOC_FAILURE);
|
|
goto err;
|
|
}
|
|
|
|
var->type = type;
|
|
var->value = value;
|
|
|
|
return var;
|
|
err:
|
|
OPENSSL_free(var);
|
|
return NULL;
|
|
}
|
|
|
|
BP_R1CS_VARIABLE *BP_R1CS_VARIABLE_dup(const BP_R1CS_VARIABLE *var)
|
|
{
|
|
BP_R1CS_VARIABLE *ret;
|
|
|
|
if (var == NULL)
|
|
return NULL;
|
|
|
|
if ((ret = BP_R1CS_VARIABLE_new(var->type, var->value)) == NULL)
|
|
return NULL;
|
|
|
|
return ret;
|
|
}
|
|
|
|
void BP_R1CS_VARIABLE_free(BP_R1CS_VARIABLE *var)
|
|
{
|
|
int ref;
|
|
|
|
if (var == NULL)
|
|
return;
|
|
|
|
CRYPTO_DOWN_REF(&var->references, &ref, var->lock);
|
|
REF_PRINT_COUNT("BP_R1CS_VARIABLE", var);
|
|
if (ref > 0)
|
|
return;
|
|
REF_ASSERT_ISNT(ref < 0);
|
|
|
|
CRYPTO_THREAD_lock_free(var->lock);
|
|
OPENSSL_clear_free((void *)var, sizeof(*var));
|
|
}
|
|
|
|
BP_R1CS_LC_ITEM *BP_R1CS_LC_ITEM_new(BP_R1CS_VARIABLE *var, const BIGNUM *scalar)
|
|
{
|
|
int ref;
|
|
BP_R1CS_LC_ITEM *item = NULL;
|
|
BP_R1CS_VARIABLE *v = NULL;
|
|
BIGNUM *s = NULL;
|
|
|
|
item = OPENSSL_zalloc(sizeof(*item));
|
|
if (item == NULL) {
|
|
ERR_raise(ERR_LIB_ZKP_BP, ERR_R_MALLOC_FAILURE);
|
|
return NULL;
|
|
}
|
|
|
|
if (var == NULL) {
|
|
if (!(v = BP_R1CS_VARIABLE_new(BP_R1CS_VARIABLE_ONE, 1))) {
|
|
goto err;
|
|
}
|
|
var = v;
|
|
} else {
|
|
if (CRYPTO_UP_REF(&var->references, &ref, var->lock) <= 0)
|
|
goto err;
|
|
}
|
|
|
|
if (scalar == NULL) {
|
|
if ((s = BN_new()) == NULL)
|
|
goto err;
|
|
|
|
BN_one(s);
|
|
} else {
|
|
if ((s = BN_dup(scalar)) == NULL)
|
|
goto err;
|
|
}
|
|
|
|
item->variable = var;
|
|
item->scalar = s;
|
|
|
|
return item;
|
|
err:
|
|
BN_free(s);
|
|
BP_R1CS_VARIABLE_free(v);
|
|
BP_R1CS_LC_ITEM_free(item);
|
|
return NULL;
|
|
}
|
|
|
|
BP_R1CS_LC_ITEM *BP_R1CS_LC_ITEM_dup(BP_R1CS_LC_ITEM *item)
|
|
{
|
|
if (item == NULL) {
|
|
ERR_raise(ERR_LIB_ZKP_BP, ERR_R_PASSED_NULL_PARAMETER);
|
|
return NULL;
|
|
}
|
|
|
|
return BP_R1CS_LC_ITEM_new(item->variable, item->scalar);
|
|
}
|
|
|
|
void BP_R1CS_LC_ITEM_free(BP_R1CS_LC_ITEM *item)
|
|
{
|
|
if (item == NULL)
|
|
return;
|
|
|
|
BP_R1CS_VARIABLE_free(item->variable);
|
|
BN_free(item->scalar);
|
|
OPENSSL_clear_free((void *)item, sizeof(*item));
|
|
}
|
|
|
|
BP_R1CS_LINEAR_COMBINATION *BP_R1CS_LINEAR_COMBINATION_new(void)
|
|
{
|
|
BP_R1CS_LINEAR_COMBINATION *lc = NULL;
|
|
|
|
lc = OPENSSL_zalloc(sizeof(*lc));
|
|
if (lc == NULL) {
|
|
ERR_raise(ERR_LIB_ZKP_BP, ERR_R_MALLOC_FAILURE);
|
|
return NULL;
|
|
}
|
|
|
|
if ((lc->items = sk_BP_R1CS_LINEAR_COMBINATION_ITEM_new_null()) == NULL)
|
|
goto err;
|
|
|
|
lc->references = 1;
|
|
if ((lc->lock = CRYPTO_THREAD_lock_new()) == NULL) {
|
|
ERR_raise(ERR_LIB_ZKP_BP, ERR_R_MALLOC_FAILURE);
|
|
goto err;
|
|
}
|
|
|
|
lc->type = BP_R1CS_LC_TYPE_UNKOWN;
|
|
|
|
return lc;
|
|
err:
|
|
BP_R1CS_LINEAR_COMBINATION_free(lc);
|
|
return NULL;
|
|
}
|
|
|
|
BP_R1CS_LINEAR_COMBINATION *BP_R1CS_LINEAR_COMBINATION_new_from_param(BP_R1CS_VARIABLE *var,
|
|
const BIGNUM *scalar)
|
|
{
|
|
BP_R1CS_LINEAR_COMBINATION *lc = NULL;
|
|
BP_R1CS_LC_ITEM *item = NULL;
|
|
|
|
lc = BP_R1CS_LINEAR_COMBINATION_new();
|
|
if (lc == NULL) {
|
|
return NULL;
|
|
}
|
|
|
|
if ((item = BP_R1CS_LC_ITEM_new(var, scalar)) == NULL
|
|
|| sk_BP_R1CS_LINEAR_COMBINATION_ITEM_push(lc->items, item) <= 0)
|
|
goto err;
|
|
|
|
return lc;
|
|
err:
|
|
BP_R1CS_LINEAR_COMBINATION_free(lc);
|
|
return NULL;
|
|
}
|
|
|
|
BP_R1CS_LINEAR_COMBINATION *BP_R1CS_LINEAR_COMBINATION_dup(const BP_R1CS_LINEAR_COMBINATION *lc)
|
|
{
|
|
int i, num;
|
|
BP_R1CS_LINEAR_COMBINATION *ret = NULL;
|
|
BP_R1CS_LC_ITEM *item, *item_dup = NULL;
|
|
|
|
if (lc == NULL) {
|
|
ERR_raise(ERR_LIB_ZKP_BP, ERR_R_PASSED_NULL_PARAMETER);
|
|
return NULL;
|
|
}
|
|
|
|
ret = BP_R1CS_LINEAR_COMBINATION_new();
|
|
if (ret == NULL) {
|
|
return NULL;
|
|
}
|
|
|
|
num = sk_BP_R1CS_LINEAR_COMBINATION_ITEM_num(lc->items);
|
|
for (i = 0; i < num; i++) {
|
|
item = sk_BP_R1CS_LINEAR_COMBINATION_ITEM_value(lc->items, i);
|
|
if (item == NULL)
|
|
goto err;
|
|
|
|
item_dup = BP_R1CS_LC_ITEM_dup(item);
|
|
if (item_dup == NULL)
|
|
goto err;
|
|
|
|
sk_BP_R1CS_LINEAR_COMBINATION_ITEM_push(ret->items, item_dup);
|
|
}
|
|
|
|
ret->type = lc->type;
|
|
|
|
return ret;
|
|
|
|
err:
|
|
BP_R1CS_LINEAR_COMBINATION_free(ret);
|
|
return NULL;
|
|
}
|
|
|
|
void BP_R1CS_LINEAR_COMBINATION_free(BP_R1CS_LINEAR_COMBINATION *lc)
|
|
{
|
|
int ref;
|
|
|
|
if (lc == NULL)
|
|
return;
|
|
|
|
CRYPTO_DOWN_REF(&lc->references, &ref, lc->lock);
|
|
REF_PRINT_COUNT("BP_R1CS_LINEAR_COMBINATION", lc);
|
|
if (ref > 0)
|
|
return;
|
|
REF_ASSERT_ISNT(ref < 0);
|
|
|
|
CRYPTO_THREAD_lock_free(lc->lock);
|
|
sk_BP_R1CS_LINEAR_COMBINATION_ITEM_pop_free(lc->items, BP_R1CS_LC_ITEM_free);
|
|
OPENSSL_clear_free((void *)lc, sizeof(*lc));
|
|
}
|
|
|
|
int BP_R1CS_LINEAR_COMBINATION_clean(BP_R1CS_LINEAR_COMBINATION *lc)
|
|
{
|
|
if (lc == NULL)
|
|
return 0;
|
|
|
|
sk_BP_R1CS_LINEAR_COMBINATION_ITEM_pop_free(lc->items, BP_R1CS_LC_ITEM_free);
|
|
if ((lc->items = sk_BP_R1CS_LINEAR_COMBINATION_ITEM_new_null()) == NULL)
|
|
return 0;
|
|
|
|
lc->type = BP_R1CS_LC_TYPE_UNKOWN;
|
|
return 1;
|
|
}
|
|
|
|
static int BP_R1CS_LINEAR_COMBINATION_eval(BP_R1CS_CTX *ctx,
|
|
const BP_R1CS_LINEAR_COMBINATION *lc,
|
|
BIGNUM *r, BN_CTX *bn_ctx)
|
|
{
|
|
int i, num, ret = 0;
|
|
BN_CTX *bctx = NULL;
|
|
BIGNUM *a, *product, *sum, *one;
|
|
BP_WITNESS *witness;
|
|
BP_R1CS_VARIABLE *var;
|
|
BP_R1CS_LINEAR_COMBINATION_ITEM *item;
|
|
|
|
if (ctx == NULL || ctx->witness == NULL || lc == NULL || r == NULL) {
|
|
ERR_raise(ERR_LIB_ZKP_BP, ERR_R_PASSED_NULL_PARAMETER);
|
|
return 0;
|
|
}
|
|
|
|
witness = ctx->witness;
|
|
|
|
if (bn_ctx == NULL) {
|
|
bctx = bn_ctx = BN_CTX_new();
|
|
if (bctx == NULL)
|
|
return 0;
|
|
}
|
|
|
|
BN_CTX_start(bn_ctx);
|
|
|
|
sum = BN_CTX_get(bn_ctx);
|
|
product = BN_CTX_get(bn_ctx);
|
|
one = BN_CTX_get(bn_ctx);
|
|
if (one == NULL)
|
|
goto err;
|
|
|
|
BN_zero(sum);
|
|
BN_one(one);
|
|
|
|
num = sk_BP_R1CS_LINEAR_COMBINATION_ITEM_num(lc->items);
|
|
for (i = 0; i < num; i++) {
|
|
item = sk_BP_R1CS_LINEAR_COMBINATION_ITEM_value(lc->items, i);
|
|
if (item == NULL)
|
|
goto err;
|
|
|
|
var = item->variable;
|
|
|
|
switch (var->type) {
|
|
case BP_R1CS_VARIABLE_COMMITTED:
|
|
a = sk_BIGNUM_value(witness->sk_v, var->value);
|
|
break;
|
|
case BP_R1CS_VARIABLE_MULTIPLIER_LEFT:
|
|
a = sk_BIGNUM_value(ctx->aL, var->value);
|
|
break;
|
|
case BP_R1CS_VARIABLE_MULTIPLIER_RIGHT:
|
|
a = sk_BIGNUM_value(ctx->aR, var->value);
|
|
break;
|
|
case BP_R1CS_VARIABLE_MULTIPLIER_OUTPUT:
|
|
a = sk_BIGNUM_value(ctx->aO, var->value);
|
|
break;
|
|
case BP_R1CS_VARIABLE_ONE:
|
|
default:
|
|
a = one;
|
|
}
|
|
|
|
if (!BN_mul(product, a, item->scalar, bn_ctx)
|
|
|| !BN_add(sum, sum, product))
|
|
goto err;
|
|
}
|
|
|
|
BN_copy(r, sum);
|
|
ret = 1;
|
|
|
|
err:
|
|
BN_CTX_end(bn_ctx);
|
|
BN_CTX_free(bctx);
|
|
return ret;
|
|
}
|
|
|
|
/*
|
|
* left = lc(l)
|
|
* right = lc(r)
|
|
* output = left * right
|
|
*/
|
|
int BP_R1CS_LINEAR_COMBINATION_raw_mul(BP_R1CS_LINEAR_COMBINATION **output,
|
|
BP_R1CS_LINEAR_COMBINATION **left,
|
|
BP_R1CS_LINEAR_COMBINATION **right,
|
|
const BIGNUM *l, const BIGNUM *r,
|
|
BP_R1CS_CTX *ctx)
|
|
{
|
|
int ln, rn, on, ret = 0;
|
|
BN_CTX *bn_ctx = NULL;
|
|
BIGNUM *lb = NULL, *rb = NULL, *ob = NULL;
|
|
BP_R1CS_VARIABLE *lv = NULL, *rv = NULL, *ov = NULL;
|
|
BP_R1CS_LINEAR_COMBINATION *llc = NULL, *rlc = NULL, *olc = NULL;
|
|
|
|
if (output == NULL || ctx == NULL) {
|
|
ERR_raise(ERR_LIB_ZKP_BP, ERR_R_PASSED_NULL_PARAMETER);
|
|
return 0;
|
|
}
|
|
|
|
if (l != NULL && r != NULL) {
|
|
ln = sk_BIGNUM_num(ctx->aL);
|
|
rn = sk_BIGNUM_num(ctx->aR);
|
|
on = sk_BIGNUM_num(ctx->aO);
|
|
|
|
bn_ctx = BN_CTX_new();
|
|
if (bn_ctx == NULL)
|
|
goto err;
|
|
|
|
lb = BN_dup(l);
|
|
rb = BN_dup(r);
|
|
ob = BN_new();
|
|
if (lb == NULL || rb == NULL || ob == NULL)
|
|
goto err;
|
|
|
|
if (!BN_mul(ob, lb, rb, bn_ctx))
|
|
goto err;
|
|
|
|
if (sk_BIGNUM_push(ctx->aL, lb) <= 0)
|
|
goto err;
|
|
lb = NULL;
|
|
|
|
if (sk_BIGNUM_push(ctx->aR, rb) <= 0)
|
|
goto err;
|
|
rb = NULL;
|
|
|
|
if (sk_BIGNUM_push(ctx->aO, ob) <= 0)
|
|
goto err;
|
|
ob = NULL;
|
|
} else {
|
|
ln = rn = on = ctx->vars_num;
|
|
ctx->vars_num += 1;
|
|
}
|
|
|
|
ov = BP_R1CS_VARIABLE_new(BP_R1CS_VARIABLE_MULTIPLIER_OUTPUT, on);
|
|
if (ov == NULL)
|
|
goto err;
|
|
|
|
olc = BP_R1CS_LINEAR_COMBINATION_new_from_param(ov, NULL);
|
|
if (olc == NULL) {
|
|
goto err;
|
|
}
|
|
|
|
*output = olc;
|
|
|
|
if (left != NULL) {
|
|
lv = BP_R1CS_VARIABLE_new(BP_R1CS_VARIABLE_MULTIPLIER_LEFT, ln);
|
|
if (lv == NULL)
|
|
goto err;
|
|
|
|
llc = BP_R1CS_LINEAR_COMBINATION_new_from_param(lv, NULL);
|
|
if (llc == NULL) {
|
|
goto err;
|
|
}
|
|
|
|
*left = llc;
|
|
}
|
|
|
|
if (right != NULL) {
|
|
rv = BP_R1CS_VARIABLE_new(BP_R1CS_VARIABLE_MULTIPLIER_RIGHT, rn);
|
|
if (rv == NULL)
|
|
goto err;
|
|
|
|
rlc = BP_R1CS_LINEAR_COMBINATION_new_from_param(rv, NULL);
|
|
if (rlc == NULL) {
|
|
goto err;
|
|
}
|
|
|
|
*right = rlc;
|
|
}
|
|
|
|
BP_R1CS_VARIABLE_free(lv);
|
|
BP_R1CS_VARIABLE_free(rv);
|
|
BP_R1CS_VARIABLE_free(ov);
|
|
BN_CTX_free(bn_ctx);
|
|
return 1;
|
|
err:
|
|
if (output == NULL)
|
|
output = NULL;
|
|
if (left == NULL)
|
|
left = NULL;
|
|
if (right == NULL)
|
|
right = NULL;
|
|
|
|
BP_R1CS_LINEAR_COMBINATION_free(llc);
|
|
BP_R1CS_LINEAR_COMBINATION_free(rlc);
|
|
BP_R1CS_LINEAR_COMBINATION_free(olc);
|
|
BP_R1CS_VARIABLE_free(lv);
|
|
BP_R1CS_VARIABLE_free(rv);
|
|
BP_R1CS_VARIABLE_free(ov);
|
|
BN_free(lb);
|
|
BN_free(rb);
|
|
BN_free(ob);
|
|
BN_CTX_free(bn_ctx);
|
|
return ret;
|
|
}
|
|
|
|
/* lc *= other */
|
|
int BP_R1CS_LINEAR_COMBINATION_mul(BP_R1CS_LINEAR_COMBINATION *lc,
|
|
const BP_R1CS_LINEAR_COMBINATION *other,
|
|
BP_R1CS_CTX *ctx)
|
|
{
|
|
int ln, rn, on, ret = 0;
|
|
BN_CTX *bn_ctx = NULL;
|
|
BIGNUM *l = NULL, *r = NULL, *o = NULL, *bn_1;
|
|
BP_R1CS_VARIABLE *lv = NULL, *rv = NULL, *ov = NULL;
|
|
BP_R1CS_LINEAR_COMBINATION_ITEM *li = NULL, *ri = NULL, *oi = NULL;
|
|
BP_R1CS_LINEAR_COMBINATION *llc = NULL, *rlc = NULL;
|
|
STACK_OF(BP_R1CS_LINEAR_COMBINATION_ITEM) *lc_items = NULL;
|
|
|
|
if (lc == NULL || other == NULL || ctx == NULL) {
|
|
ERR_raise(ERR_LIB_ZKP_BP, ERR_R_PASSED_NULL_PARAMETER);
|
|
return 0;
|
|
}
|
|
|
|
if (lc->type != BP_R1CS_LC_TYPE_UNKOWN && lc->type != other->type) {
|
|
ERR_raise(ERR_LIB_ZKP_BP, ERR_R_PASSED_INVALID_ARGUMENT);
|
|
return 0;
|
|
}
|
|
|
|
bn_ctx = BN_CTX_new();
|
|
if (bn_ctx == NULL)
|
|
return 0;
|
|
|
|
BN_CTX_start(bn_ctx);
|
|
|
|
bn_1 = BN_CTX_get(bn_ctx);
|
|
if (bn_1 == NULL)
|
|
goto err;
|
|
|
|
BN_one(bn_1);
|
|
BN_set_negative(bn_1, 1);
|
|
|
|
if (lc->type == BP_R1CS_LC_TYPE_PROVE) {
|
|
l = BN_new();
|
|
r = BN_new();
|
|
o = BN_new();
|
|
if (l == NULL || r == NULL || o == NULL)
|
|
goto err;
|
|
|
|
if (!BP_R1CS_LINEAR_COMBINATION_eval(ctx, lc, l, bn_ctx)
|
|
|| !BP_R1CS_LINEAR_COMBINATION_eval(ctx, other, r, bn_ctx))
|
|
goto err;
|
|
|
|
if (!BN_mul(o, l, r, bn_ctx))
|
|
goto err;
|
|
|
|
ln = sk_BIGNUM_num(ctx->aL);
|
|
rn = sk_BIGNUM_num(ctx->aR);
|
|
on = sk_BIGNUM_num(ctx->aO);
|
|
|
|
if (sk_BIGNUM_push(ctx->aL, l) <= 0)
|
|
goto err;
|
|
l = NULL;
|
|
|
|
if (sk_BIGNUM_push(ctx->aR, r) <= 0)
|
|
goto err;
|
|
r = NULL;
|
|
|
|
if (sk_BIGNUM_push(ctx->aO, o) <= 0)
|
|
goto err;
|
|
o = NULL;
|
|
} else {
|
|
ln = rn = on = ctx->vars_num;
|
|
ctx->vars_num += 1;
|
|
}
|
|
|
|
llc = BP_R1CS_LINEAR_COMBINATION_dup(lc);
|
|
rlc = BP_R1CS_LINEAR_COMBINATION_dup(other);
|
|
if (llc == NULL || rlc == NULL)
|
|
goto err;
|
|
|
|
lv = BP_R1CS_VARIABLE_new(BP_R1CS_VARIABLE_MULTIPLIER_LEFT, ln);
|
|
rv = BP_R1CS_VARIABLE_new(BP_R1CS_VARIABLE_MULTIPLIER_RIGHT, rn);
|
|
ov = BP_R1CS_VARIABLE_new(BP_R1CS_VARIABLE_MULTIPLIER_OUTPUT, on);
|
|
if (lv == NULL || rv == NULL || ov == NULL)
|
|
goto err;
|
|
|
|
if ((li = BP_R1CS_LC_ITEM_new(lv, bn_1)) == NULL
|
|
|| sk_BP_R1CS_LINEAR_COMBINATION_ITEM_push(llc->items, li) <= 0)
|
|
goto err;
|
|
li = NULL;
|
|
|
|
if ((ri = BP_R1CS_LC_ITEM_new(rv, bn_1)) == NULL
|
|
|| sk_BP_R1CS_LINEAR_COMBINATION_ITEM_push(rlc->items, ri) <= 0)
|
|
goto err;
|
|
ri = NULL;
|
|
|
|
if (!BP_R1CS_LINEAR_COMBINATION_constrain(llc, ctx)
|
|
|| !BP_R1CS_LINEAR_COMBINATION_constrain(rlc, ctx))
|
|
goto err;
|
|
|
|
if (!(lc_items = sk_BP_R1CS_LINEAR_COMBINATION_ITEM_new_reserve(NULL, 1)))
|
|
goto err;
|
|
|
|
if ((oi = BP_R1CS_LC_ITEM_new(ov, NULL)) == NULL
|
|
|| sk_BP_R1CS_LINEAR_COMBINATION_ITEM_push(lc_items, oi) <= 0)
|
|
goto err;
|
|
|
|
sk_BP_R1CS_LINEAR_COMBINATION_ITEM_pop_free(lc->items, BP_R1CS_LC_ITEM_free);
|
|
lc->items = lc_items;
|
|
lc_items = NULL;
|
|
oi = NULL;
|
|
llc = rlc = NULL;
|
|
|
|
ret = 1;
|
|
|
|
err:
|
|
sk_BP_R1CS_LINEAR_COMBINATION_ITEM_free(lc_items);
|
|
BP_R1CS_LINEAR_COMBINATION_free(llc);
|
|
BP_R1CS_LINEAR_COMBINATION_free(rlc);
|
|
BP_R1CS_LC_ITEM_free(li);
|
|
BP_R1CS_LC_ITEM_free(ri);
|
|
BP_R1CS_LC_ITEM_free(oi);
|
|
BP_R1CS_VARIABLE_free(lv);
|
|
BP_R1CS_VARIABLE_free(rv);
|
|
BP_R1CS_VARIABLE_free(ov);
|
|
BN_free(l);
|
|
BN_free(r);
|
|
BN_free(o);
|
|
BN_CTX_end(bn_ctx);
|
|
BN_CTX_free(bn_ctx);
|
|
return ret;
|
|
}
|
|
|
|
/* lc += other */
|
|
int BP_R1CS_LINEAR_COMBINATION_add(BP_R1CS_LINEAR_COMBINATION *lc,
|
|
const BP_R1CS_LINEAR_COMBINATION *other)
|
|
{
|
|
int i, num;
|
|
BP_R1CS_LINEAR_COMBINATION_ITEM *item = NULL, *p;
|
|
|
|
if (lc == NULL || other == NULL) {
|
|
ERR_raise(ERR_LIB_ZKP_BP, ERR_R_PASSED_NULL_PARAMETER);
|
|
return 0;
|
|
}
|
|
|
|
num = sk_BP_R1CS_LINEAR_COMBINATION_ITEM_num(other->items);
|
|
for (i = 0; i < num; i++) {
|
|
p = sk_BP_R1CS_LINEAR_COMBINATION_ITEM_value(other->items, i);
|
|
if (p == NULL)
|
|
goto err;
|
|
|
|
if ((item = BP_R1CS_LC_ITEM_dup(p)) == NULL)
|
|
goto err;
|
|
|
|
if (sk_BP_R1CS_LINEAR_COMBINATION_ITEM_push(lc->items, item) <= 0)
|
|
goto err;
|
|
}
|
|
|
|
return 1;
|
|
err:
|
|
BP_R1CS_LC_ITEM_free(item);
|
|
return 0;
|
|
}
|
|
|
|
/* lc -= other */
|
|
int BP_R1CS_LINEAR_COMBINATION_sub(BP_R1CS_LINEAR_COMBINATION *lc,
|
|
const BP_R1CS_LINEAR_COMBINATION *other)
|
|
{
|
|
int i, num;
|
|
BP_R1CS_LINEAR_COMBINATION_ITEM *item = NULL, *p;
|
|
|
|
if (lc == NULL || other == NULL) {
|
|
ERR_raise(ERR_LIB_ZKP_BP, ERR_R_PASSED_NULL_PARAMETER);
|
|
return 0;
|
|
}
|
|
|
|
num = sk_BP_R1CS_LINEAR_COMBINATION_ITEM_num(other->items);
|
|
for (i = 0; i < num; i++) {
|
|
p = sk_BP_R1CS_LINEAR_COMBINATION_ITEM_value(other->items, i);
|
|
if (p == NULL)
|
|
goto err;
|
|
|
|
if ((item = BP_R1CS_LC_ITEM_dup(p)) == NULL)
|
|
goto err;
|
|
|
|
BN_set_negative(item->scalar, 1);
|
|
|
|
if (sk_BP_R1CS_LINEAR_COMBINATION_ITEM_push(lc->items, item) <= 0)
|
|
goto err;
|
|
}
|
|
|
|
return 1;
|
|
err:
|
|
BP_R1CS_LC_ITEM_free(item);
|
|
return 0;
|
|
}
|
|
|
|
/* lc = -lc */
|
|
int BP_R1CS_LINEAR_COMBINATION_neg(BP_R1CS_LINEAR_COMBINATION *lc)
|
|
{
|
|
int i, num, ret = 0;
|
|
BP_R1CS_LINEAR_COMBINATION_ITEM *item;
|
|
|
|
if (lc == NULL) {
|
|
ERR_raise(ERR_LIB_ZKP_BP, ERR_R_PASSED_NULL_PARAMETER);
|
|
return 0;
|
|
}
|
|
|
|
num = sk_BP_R1CS_LINEAR_COMBINATION_ITEM_num(lc->items);
|
|
for (i = 0; i < num; i++) {
|
|
item = sk_BP_R1CS_LINEAR_COMBINATION_ITEM_value(lc->items, i);
|
|
if (item == NULL || item->scalar == NULL)
|
|
goto err;
|
|
|
|
BN_set_negative(item->scalar, 1);
|
|
}
|
|
|
|
ret = 1;
|
|
|
|
err:
|
|
return ret;
|
|
}
|
|
|
|
/* lc = lc * value */
|
|
int BP_R1CS_LINEAR_COMBINATION_mul_bn(BP_R1CS_LINEAR_COMBINATION *lc,
|
|
const BIGNUM *value)
|
|
{
|
|
int i, num, ret = 0;
|
|
BN_CTX *bn_ctx = NULL;
|
|
BP_R1CS_LINEAR_COMBINATION_ITEM *item;
|
|
|
|
if (lc == NULL || value == NULL) {
|
|
ERR_raise(ERR_LIB_ZKP_BP, ERR_R_PASSED_NULL_PARAMETER);
|
|
return 0;
|
|
}
|
|
|
|
if (!(bn_ctx = BN_CTX_new()))
|
|
goto err;
|
|
|
|
num = sk_BP_R1CS_LINEAR_COMBINATION_ITEM_num(lc->items);
|
|
for (i = 0; i < num; i++) {
|
|
item = sk_BP_R1CS_LINEAR_COMBINATION_ITEM_value(lc->items, i);
|
|
if (item == NULL || item->scalar == NULL)
|
|
goto err;
|
|
|
|
if (!BN_mul(item->scalar, item->scalar, value, bn_ctx))
|
|
goto err;
|
|
}
|
|
|
|
ret = 1;
|
|
|
|
err:
|
|
BN_CTX_free(bn_ctx);
|
|
return ret;
|
|
}
|
|
|
|
/* lc = lc + value */
|
|
int BP_R1CS_LINEAR_COMBINATION_add_bn(BP_R1CS_LINEAR_COMBINATION *lc,
|
|
const BIGNUM *value)
|
|
{
|
|
BP_R1CS_LINEAR_COMBINATION_ITEM *item;
|
|
|
|
if (lc == NULL || value == NULL) {
|
|
ERR_raise(ERR_LIB_ZKP_BP, ERR_R_PASSED_NULL_PARAMETER);
|
|
return 0;
|
|
}
|
|
|
|
if ((item = BP_R1CS_LC_ITEM_new(NULL, value)) == NULL)
|
|
return 0;
|
|
|
|
if (sk_BP_R1CS_LINEAR_COMBINATION_ITEM_push(lc->items, item) <= 0) {
|
|
BP_R1CS_LC_ITEM_free(item);
|
|
return 0;
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
/* lc = lc - value */
|
|
int BP_R1CS_LINEAR_COMBINATION_sub_bn(BP_R1CS_LINEAR_COMBINATION *lc,
|
|
const BIGNUM *value)
|
|
{
|
|
int ret = 0;
|
|
BIGNUM *scalar = NULL;
|
|
|
|
if (lc == NULL || value == NULL) {
|
|
ERR_raise(ERR_LIB_ZKP_BP, ERR_R_PASSED_NULL_PARAMETER);
|
|
return 0;
|
|
}
|
|
|
|
if (!(scalar = BN_dup(value)))
|
|
return 0;
|
|
|
|
BN_set_negative(scalar, 1);
|
|
|
|
ret = BP_R1CS_LINEAR_COMBINATION_add_bn(lc, scalar);
|
|
|
|
BN_free(scalar);
|
|
return ret;
|
|
}
|
|
|
|
int BP_R1CS_LINEAR_COMBINATION_constrain(BP_R1CS_LINEAR_COMBINATION *lc,
|
|
BP_R1CS_CTX *ctx)
|
|
{
|
|
int ref;
|
|
|
|
if (ctx == NULL || lc == NULL) {
|
|
ERR_raise(ERR_LIB_ZKP_BP, ERR_R_PASSED_NULL_PARAMETER);
|
|
return 0;
|
|
}
|
|
|
|
if (CRYPTO_UP_REF(&lc->references, &ref, lc->lock) <= 0)
|
|
return 0;
|
|
|
|
if (sk_BP_R1CS_LINEAR_COMBINATION_push(ctx->constraints, lc) <= 0)
|
|
goto err;
|
|
|
|
return 1;
|
|
err:
|
|
CRYPTO_DOWN_REF(&lc->references, &ref, lc->lock);
|
|
return 0;
|
|
}
|
|
|