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

342 lines
9.6 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 "internal/cryptlib.h"
#include <openssl/bulletproofs.h>
#include "r1cs.h"
typedef struct bp_r1cs_expression_st {
char *expression;
int len;
int pos;
int is_prove;
int var_found;
} bp_r1cs_expression_t;
DEFINE_STACK_OF(BP_R1CS_LINEAR_COMBINATION_ITEM)
static bp_r1cs_expression_t *bp_r1cs_expression_new(const char *exp_str, int is_prove);
static void bp_r1cs_expression_free(bp_r1cs_expression_t *e);
static int bp_r1cs_expression_evaluate_expression(bp_r1cs_expression_t *e,
BP_R1CS_LINEAR_COMBINATION *lc,
BP_R1CS_CTX *ctx);
static int bp_r1cs_expression_evaluate_term(bp_r1cs_expression_t *e,
BP_R1CS_LINEAR_COMBINATION *lc,
BP_R1CS_CTX *ctx);
static int bp_r1cs_expression_evaluate_factor(bp_r1cs_expression_t *e,
BP_R1CS_LINEAR_COMBINATION *lc,
BP_R1CS_CTX *ctx);
static int bp_r1cs_expression_evaluate_number(bp_r1cs_expression_t *e,
BP_R1CS_LINEAR_COMBINATION *lc,
BP_R1CS_CTX *ctx);
static int bp_r1cs_expression_evaluate_variable(bp_r1cs_expression_t *e,
BP_R1CS_LINEAR_COMBINATION *lc,
BP_R1CS_CTX *ctx);
static void bp_r1cs_expression_skip_whitespace(bp_r1cs_expression_t *e);
static bp_r1cs_expression_t *bp_r1cs_expression_new(const char *exp_str, int is_prove)
{
bp_r1cs_expression_t *e;
if (exp_str == NULL) {
ERR_raise(ERR_LIB_ZKP_BP, ERR_R_PASSED_NULL_PARAMETER);
return NULL;
}
e = OPENSSL_malloc(sizeof(*e));
if (e == NULL) {
ERR_raise(ERR_LIB_ZKP_BP, ERR_R_MALLOC_FAILURE);
return NULL;
}
e->expression = OPENSSL_strdup(exp_str);
if (e->expression == NULL) {
OPENSSL_free(e);
ERR_raise(ERR_LIB_ZKP_BP, ERR_R_MALLOC_FAILURE);
return NULL;
}
e->len = strlen(e->expression);
e->pos = 0;
e->var_found = 0;
e->is_prove = is_prove;
return e;
}
static void bp_r1cs_expression_free(bp_r1cs_expression_t *e)
{
if (e == NULL)
return;
OPENSSL_free(e->expression);
OPENSSL_free(e);
}
static int bp_r1cs_expression_evaluate_expression(bp_r1cs_expression_t *e,
BP_R1CS_LINEAR_COMBINATION *lc,
BP_R1CS_CTX *ctx)
{
int ret = 0;
BP_R1CS_LINEAR_COMBINATION *right = NULL;
if (e == NULL)
return 0;
if (!bp_r1cs_expression_evaluate_term(e, lc, ctx))
return 0;
right = BP_R1CS_LINEAR_COMBINATION_new();
if (right == NULL)
return 0;
while (e->expression[e->pos] == '+' || e->expression[e->pos] == '-') {
char operator = e->expression[e->pos++];
bp_r1cs_expression_skip_whitespace(e);
if (!bp_r1cs_expression_evaluate_term(e, right, ctx))
goto err;
if (operator == '+') {
if (!BP_R1CS_LINEAR_COMBINATION_add(lc, right))
goto err;
} else {
if (!BP_R1CS_LINEAR_COMBINATION_sub(lc, right))
goto err;
}
if (!BP_R1CS_LINEAR_COMBINATION_clean(right))
goto err;
}
bp_r1cs_expression_skip_whitespace(e);
ret = 1;
err:
BP_R1CS_LINEAR_COMBINATION_free(right);
return ret;
}
static int bp_r1cs_expression_evaluate_term(bp_r1cs_expression_t *e,
BP_R1CS_LINEAR_COMBINATION *lc,
BP_R1CS_CTX *ctx)
{
int ret = 0;
BP_R1CS_LINEAR_COMBINATION *right = NULL;
if (e == NULL)
return 0;
if (!bp_r1cs_expression_evaluate_factor(e, lc, ctx))
return 0;
right = BP_R1CS_LINEAR_COMBINATION_new();
if (right == NULL)
return 0;
while (e->expression[e->pos] == '*') {
e->pos++;
bp_r1cs_expression_skip_whitespace(e);
if (!bp_r1cs_expression_evaluate_factor(e, right, ctx))
goto err;
if (!BP_R1CS_LINEAR_COMBINATION_mul(lc, right, ctx))
goto err;
if (!BP_R1CS_LINEAR_COMBINATION_clean(right))
goto err;
}
ret = 1;
err:
BP_R1CS_LINEAR_COMBINATION_free(right);
return ret;
}
static int bp_r1cs_expression_evaluate_factor(bp_r1cs_expression_t *e,
BP_R1CS_LINEAR_COMBINATION *lc,
BP_R1CS_CTX *ctx)
{
if (e == NULL)
return 0;
if (e->expression[e->pos] == '(') {
e->pos++;
bp_r1cs_expression_skip_whitespace(e);
if (!bp_r1cs_expression_evaluate_expression(e, lc, ctx))
return 0;
if (e->expression[e->pos] != ')') {
ERR_raise(ERR_LIB_ZKP_BP, ZKP_BP_R_R1CS_CONSTRAINT_EXPRESSION_FORMAT_ERROR);
return 0;
}
e->pos++;
return 1;
} else if (ossl_isalpha(e->expression[e->pos])) {
return bp_r1cs_expression_evaluate_variable(e, lc, ctx);
} else if (ossl_isdigit(e->expression[e->pos])) {
return bp_r1cs_expression_evaluate_number(e, lc, ctx);
}
return 0;
}
static int bp_r1cs_expression_evaluate_number(bp_r1cs_expression_t *e,
BP_R1CS_LINEAR_COMBINATION *lc,
BP_R1CS_CTX *ctx)
{
int number = 0;
BIGNUM *bn = NULL;
BP_R1CS_LC_ITEM *item = NULL;
if (e == NULL)
return 0;
if (!ossl_isdigit(e->expression[e->pos]))
return 0;
while (ossl_isdigit(e->expression[e->pos])) {
number = 10 * number + (e->expression[e->pos] - '0');
e->pos++;
}
bp_r1cs_expression_skip_whitespace(e);
bn = BN_new();
if (bn == NULL)
return 0;
BN_set_word(bn, number);
if ((item = BP_R1CS_LC_ITEM_new(NULL, bn)) == NULL
|| sk_BP_R1CS_LINEAR_COMBINATION_ITEM_push(lc->items, item) <= 0)
goto err;
lc->type = e->is_prove ? BP_R1CS_LC_TYPE_PROVE : BP_R1CS_LC_TYPE_VERIFY;
BN_free(bn);
return 1;
err:
BN_free(bn);
BP_R1CS_LC_ITEM_free(item);
return 0;
}
static int bp_r1cs_expression_evaluate_variable(bp_r1cs_expression_t *e,
BP_R1CS_LINEAR_COMBINATION *lc,
BP_R1CS_CTX *ctx)
{
int i = 0;
char var[BP_VARIABLE_NAME_MAX_LEN + 1];
BP_R1CS_VARIABLE *r1cs_var = NULL;
BP_R1CS_LC_ITEM *item = NULL;
if (e == NULL)
return 0;
if (!ossl_isalpha(e->expression[e->pos]))
return 0;
memset(var, 0, sizeof(var));
while (ossl_isalpha(e->expression[e->pos]) || ossl_isdigit(e->expression[e->pos])
|| e->expression[e->pos] == '_') {
if (i > BP_VARIABLE_NAME_MAX_LEN) {
ERR_raise(ERR_LIB_ZKP_BP, ZKP_BP_R_R1CS_CONSTRAINT_EXPRESSION_VAR_TOO_LONG);
return 0;
}
var[i++] = e->expression[e->pos++];
}
bp_r1cs_expression_skip_whitespace(e);
i = BP_WITNESS_get_variable_index(ctx->witness, var);
if (i < 0) {
ERR_raise(ERR_LIB_ZKP_BP, ZKP_BP_R_R1CS_CONSTRAINT_EXPRESSION_VAR_NOT_FOUND);
return 0;
}
if ((r1cs_var = BP_R1CS_VARIABLE_new(BP_R1CS_VARIABLE_COMMITTED, i)) == NULL)
goto err;
if ((item = BP_R1CS_LC_ITEM_new(r1cs_var, NULL)) == NULL
|| sk_BP_R1CS_LINEAR_COMBINATION_ITEM_push(lc->items, item) <= 0)
goto err;
lc->type = e->is_prove ? BP_R1CS_LC_TYPE_PROVE : BP_R1CS_LC_TYPE_VERIFY;
e->var_found = 1;
BP_R1CS_VARIABLE_free(r1cs_var);
return 1;
err:
BP_R1CS_VARIABLE_free(r1cs_var);
BP_R1CS_LC_ITEM_free(item);
return 0;
}
static void bp_r1cs_expression_skip_whitespace(bp_r1cs_expression_t *e)
{
if (e == NULL)
return;
while (ossl_isspace(e->expression[e->pos]))
e->pos++;
}
static int bp_r1cs_expression_process(bp_r1cs_expression_t *e,
BP_R1CS_LINEAR_COMBINATION *lc,
BP_R1CS_CTX *ctx)
{
if (!bp_r1cs_expression_evaluate_expression(e, lc, ctx)) {
ERR_raise(ERR_LIB_ZKP_BP, ZKP_BP_R_R1CS_CONSTRAINT_EXPRESSION_PROCESS_ERROR);
return 0;
}
if (e->pos != e->len) {
ERR_raise(ERR_LIB_ZKP_BP, ZKP_BP_R_R1CS_CONSTRAINT_EXPRESSION_FORMAT_ERROR);
return 0;
}
if (!e->var_found) {
ERR_raise(ERR_LIB_ZKP_BP, ZKP_BP_R_R1CS_CONSTRAINT_EXPRESSION_NO_VAR);
return 0;
}
return 1;
}
int BP_R1CS_constraint_expression(BP_R1CS_CTX *ctx, const char *constraint, int is_prove)
{
int ret = 0;
bp_r1cs_expression_t *e = NULL;
BP_R1CS_LINEAR_COMBINATION *lc = NULL;
e = bp_r1cs_expression_new(constraint, is_prove);
lc = BP_R1CS_LINEAR_COMBINATION_new();
if (e == NULL || lc == NULL)
goto err;
if (!bp_r1cs_expression_process(e, lc, ctx))
goto err;
ret = BP_R1CS_LINEAR_COMBINATION_constrain(lc, ctx);
err:
BP_R1CS_LINEAR_COMBINATION_free(lc);
bp_r1cs_expression_free(e);
return ret;
}