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

806 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/ec.h>
#include <openssl/zkperr.h>
#include <crypto/ec/ec_local.h>
#include "zkp_util.h"
DEFINE_STACK_OF(BIGNUM)
DEFINE_STACK_OF(EC_POINT)
static point_conversion_form_t form = POINT_CONVERSION_COMPRESSED;
EC_POINT *zkp_random_ec_point_new(const EC_GROUP *group, BN_CTX *bn_ctx)
{
BIGNUM *r = NULL;
BN_CTX *bctx = NULL;
EC_POINT *P = NULL;
const BIGNUM *order;
if (group == NULL)
return NULL;
if (bn_ctx == NULL) {
bctx = bn_ctx = BN_CTX_new_ex(group->libctx);
if (bn_ctx == NULL)
goto err;
}
order = EC_GROUP_get0_order(group);
BN_CTX_start(bn_ctx);
r = BN_CTX_get(bn_ctx);
if (r == NULL)
goto err;
zkp_rand_range(r, order);
if (!(P = EC_POINT_new(group)) || !EC_POINT_mul(group, P, r, NULL, NULL, bn_ctx))
goto err;
BN_CTX_end(bn_ctx);
BN_CTX_free(bctx);
return P;
err:
BN_CTX_end(bn_ctx);
BN_CTX_free(bctx);
zkp_random_ec_point_free(P);
return NULL;
}
void zkp_random_ec_point_free(EC_POINT *P)
{
if (P == NULL)
return;
EC_POINT_free(P);
}
int zkp_random_bn_gen(const EC_GROUP *group, BIGNUM **r, size_t n, BN_CTX *bn_ctx)
{
size_t i;
const BIGNUM *order;
if (group == NULL || r == NULL || bn_ctx == NULL)
return 0;
order = EC_GROUP_get0_order(group);
for (i = 0; i < n; i++) {
if (!(r[i] = BN_CTX_get(bn_ctx)) || !zkp_rand_range(r[i], order))
return 0;
}
return 1;
}
int zkp_str2point(const EC_GROUP *group, const unsigned char *str, size_t len,
EC_POINT *r, BN_CTX *bn_ctx)
{
int ret = 0, i = 0;
unsigned char hash_res[SHA256_DIGEST_LENGTH];
unsigned char *p = (unsigned char *)str;
BN_CTX *ctx = NULL;
BIGNUM *x;
memset(hash_res, 0, sizeof(hash_res));
if (bn_ctx == NULL) {
if ((ctx = bn_ctx = BN_CTX_new_ex(group->libctx)) == NULL)
goto end;
}
BN_CTX_start(bn_ctx);
if ((x = BN_CTX_get(bn_ctx)) == NULL)
goto end;
do {
if (!SHA256(p, len, hash_res))
goto end;
BN_bin2bn(hash_res, SHA256_DIGEST_LENGTH, x);
p = &hash_res[0];
len = sizeof(hash_res);
if(EC_POINT_set_compressed_coordinates(group, r, x, 0, bn_ctx) == 1) {
ret = 1;
break;
}
ERR_clear_error();
} while (i++ < 10);
end:
BN_CTX_end(bn_ctx);
BN_CTX_free(ctx);
return ret;
}
size_t zkp_point2oct(const EC_GROUP *group, const EC_POINT *P,
unsigned char *buf, BN_CTX *bn_ctx)
{
size_t plen;
point_conversion_form_t format = POINT_CONVERSION_COMPRESSED;
if (group == NULL || P == NULL || bn_ctx == NULL)
return -1;
plen = EC_POINT_point2oct(group, EC_GROUP_get0_generator(group),
format, NULL, 0, bn_ctx);
if (plen <= 0 || buf == NULL)
return plen;
if (EC_POINT_point2oct(group, P, format, buf, plen, bn_ctx) <= 0)
return -1;
return plen;
}
int zkp_point2point(const EC_GROUP *group, const EC_POINT *P, EC_POINT *H, BN_CTX *bn_ctx)
{
int ret = 0;
size_t len;
unsigned char *buf = NULL;
BN_CTX *bctx = NULL;
if (group == NULL || P == NULL || H == NULL)
return -1;
if (bn_ctx == NULL) {
bctx = bn_ctx = BN_CTX_new();
}
if (bn_ctx == NULL) {
ERR_raise(ERR_LIB_EC, ERR_R_MALLOC_FAILURE);
goto err;
}
len = EC_POINT_point2oct(group, P, POINT_CONVERSION_COMPRESSED, NULL, 0, bn_ctx);
if (len <= 0)
goto err;
buf = OPENSSL_zalloc(len);
if (buf == NULL)
goto err;
if (!EC_POINT_point2oct(group, P, POINT_CONVERSION_COMPRESSED, buf, len, bn_ctx))
goto err;
if (!EC_POINT_from_string(group, H, buf, len))
goto err;
ret = 1;
err:
OPENSSL_free(buf);
BN_CTX_free(bctx);
return ret;
}
int zkp_bin_hash2bn(const unsigned char *data, size_t len, BIGNUM *r)
{
int ret = 0;
unsigned char hash_res[SHA256_DIGEST_LENGTH];
if (data == NULL || len <= 0 || r == NULL)
return ret;
if (!SHA256(data, len, hash_res))
goto end;
if (!BN_bin2bn(hash_res, SHA256_DIGEST_LENGTH, r))
goto end;
ret = 1;
end:
return ret;
}
int zkp_next_power_of_two(int num)
{
int next_power_of_2 = 1;
while(next_power_of_2 < num) {
next_power_of_2 <<= 1;
}
return next_power_of_2;
}
int zkp_is_power_of_two(int num)
{
return (num != 0) && ((num & (num - 1)) == 0);
}
int zkp_floor_log2(int x)
{
int result = 0;
while (x > 1) {
x >>= 1;
result++;
}
return result;
}
int zkp_inner_product(BIGNUM *r, int num, const BIGNUM *a[], const BIGNUM *b[],
const BIGNUM *order, BN_CTX *bn_ctx)
{
int ret = 0, i;
BN_CTX *ctx = NULL;
BIGNUM *v, *t;
const BIGNUM *p;
if (r == NULL || num <= 0 || (a == NULL && b == NULL))
return 0;
if (bn_ctx == NULL) {
if ((ctx = bn_ctx = BN_CTX_new()) == NULL)
goto end;
}
BN_CTX_start(bn_ctx);
v = BN_CTX_get(bn_ctx);
if ((t = BN_CTX_get(bn_ctx)) == NULL)
goto end;
BN_zero(v);
for (i = 0; i < num; i++) {
if (a == NULL) {
p = b[i];
} else if (b == NULL) {
p = a[i];
} else {
if (!BN_mod_mul(t, a[i], b[i], order, bn_ctx))
goto end;
p = t;
}
if (!BN_mod_add(v, v, p, order, bn_ctx))
goto end;
}
if (!BN_copy(r, v))
goto end;
ret = 1;
end:
BN_CTX_end(bn_ctx);
BN_CTX_free(ctx);
return ret;
}
zkp_poly3_t *zkp_poly3_new(int n, const BIGNUM *order)
{
int i;
zkp_poly3_t *ret = NULL;
if (n < 0 || order == NULL) {
ERR_raise(ERR_LIB_ZKP_BP, ERR_R_PASSED_INVALID_ARGUMENT);
return NULL;
}
if (!(ret = OPENSSL_zalloc(sizeof(*ret)))) {
ERR_raise(ERR_LIB_ZKP_BP, ERR_R_MALLOC_FAILURE);
return NULL;
}
ret->order = order;
if (!(ret->bn_ctx = BN_CTX_new()))
goto err;
if (n == 0) {
ret->n = 0;
return ret;
}
if (!(ret->x0 = OPENSSL_zalloc(sizeof(*ret->x0) * n))
|| !(ret->x1 = OPENSSL_zalloc(sizeof(*ret->x1) * n))
|| !(ret->x2 = OPENSSL_zalloc(sizeof(*ret->x2) * n))
|| !(ret->x3 = OPENSSL_zalloc(sizeof(*ret->x3) * n))) {
ERR_raise(ERR_LIB_ZKP_BP, ERR_R_MALLOC_FAILURE);
goto err;
}
ret->n = n;
for (i = 0; i < n; i++) {
ret->x0[i] = BN_CTX_get(ret->bn_ctx);
ret->x1[i] = BN_CTX_get(ret->bn_ctx);
ret->x2[i] = BN_CTX_get(ret->bn_ctx);
if (!(ret->x3[i] = BN_CTX_get(ret->bn_ctx)))
goto err;
BN_zero(ret->x0[i]);
BN_zero(ret->x1[i]);
BN_zero(ret->x2[i]);
BN_zero(ret->x3[i]);
}
return ret;
err:
zkp_poly3_free(ret);
return NULL;
}
void zkp_poly3_free(zkp_poly3_t *poly3)
{
if (poly3 == NULL)
return;
BN_CTX_free(poly3->bn_ctx);
OPENSSL_free(poly3->x0);
OPENSSL_free(poly3->x1);
OPENSSL_free(poly3->x2);
OPENSSL_free(poly3->x3);
OPENSSL_free(poly3);
}
STACK_OF(BIGNUM) *zkp_poly3_eval(zkp_poly3_t *poly3, const BIGNUM *x)
{
int i;
BIGNUM *eval = NULL;
STACK_OF(BIGNUM) *ret = NULL;
if (poly3 == NULL) {
ERR_raise(ERR_LIB_ZKP_BP, ERR_R_PASSED_NULL_PARAMETER);
return 0;
}
if (!(ret = sk_BIGNUM_new_reserve(NULL, poly3->n)))
return 0;
for (i = 0; i < poly3->n; i++) {
if (!(eval = BN_CTX_get(poly3->bn_ctx)))
goto err;
if (!BN_mod_mul(eval, x, poly3->x3[i], poly3->order, poly3->bn_ctx)
|| !BN_mod_add(eval, eval, poly3->x2[i], poly3->order, poly3->bn_ctx)
|| !BN_mod_mul(eval, eval, x, poly3->order, poly3->bn_ctx)
|| !BN_mod_add(eval, eval, poly3->x1[i], poly3->order, poly3->bn_ctx)
|| !BN_mod_mul(eval, eval, x, poly3->order, poly3->bn_ctx)
|| !BN_mod_add(eval, eval, poly3->x0[i], poly3->order, poly3->bn_ctx))
goto err;
if (sk_BIGNUM_push(ret, eval) <= 0)
goto err;
}
return ret;
err:
sk_BIGNUM_free(ret);
return NULL;
}
int zkp_poly3_special_inner_product(zkp_poly6_t *r, zkp_poly3_t *lhs, zkp_poly3_t *rhs)
{
int ret = 0;
BIGNUM *t;
if (r == NULL || lhs == NULL || rhs == NULL) {
ERR_raise(ERR_LIB_ZKP_BP, ERR_R_PASSED_NULL_PARAMETER);
return 0;
}
if (lhs->n != rhs->n) {
ERR_raise(ERR_LIB_ZKP_BP, ERR_R_PASSED_INVALID_ARGUMENT);
return 0;
}
if (lhs->n == 0) {
BN_zero(r->t1);
BN_zero(r->t2);
BN_zero(r->t3);
BN_zero(r->t4);
BN_zero(r->t5);
BN_zero(r->t6);
return 1;
}
BN_CTX_start(r->bn_ctx);
if (!(t = BN_CTX_get(r->bn_ctx)))
goto err;
if (!zkp_inner_product(r->t1, lhs->n, (const BIGNUM **)lhs->x1,
(const BIGNUM **)rhs->x0, r->order, r->bn_ctx)
|| !zkp_inner_product(r->t2, lhs->n, (const BIGNUM **)lhs->x1,
(const BIGNUM **)rhs->x1, r->order, r->bn_ctx)
|| !zkp_inner_product(t, lhs->n, (const BIGNUM **)lhs->x2,
(const BIGNUM **)rhs->x0, r->order, r->bn_ctx)
|| !BN_mod_add(r->t2, r->t2, t, r->order, r->bn_ctx)
|| !zkp_inner_product(r->t3, lhs->n, (const BIGNUM **)lhs->x2,
(const BIGNUM **)rhs->x1, r->order, r->bn_ctx)
|| !zkp_inner_product(t, lhs->n, (const BIGNUM **)lhs->x3,
(const BIGNUM **)rhs->x0, r->order, r->bn_ctx)
|| !BN_mod_add(r->t3, r->t3, t, r->order, r->bn_ctx)
|| !zkp_inner_product(r->t4, lhs->n, (const BIGNUM **)lhs->x1,
(const BIGNUM **)rhs->x3, r->order, r->bn_ctx)
|| !zkp_inner_product(t, lhs->n, (const BIGNUM **)lhs->x3,
(const BIGNUM **)rhs->x1, r->order, r->bn_ctx)
|| !BN_mod_add(r->t4, r->t4, t, r->order, r->bn_ctx)
|| !zkp_inner_product(r->t5, lhs->n, (const BIGNUM **)lhs->x2,
(const BIGNUM **)rhs->x3, r->order, r->bn_ctx)
|| !zkp_inner_product(r->t6, lhs->n, (const BIGNUM **)lhs->x3,
(const BIGNUM **)rhs->x3, r->order, r->bn_ctx))
goto err;
ret = 1;
err:
BN_CTX_end(r->bn_ctx);
return ret;
}
zkp_poly6_t *zkp_poly6_new(const BIGNUM *order)
{
zkp_poly6_t *ret = NULL;
if (order == NULL) {
ERR_raise(ERR_LIB_ZKP_BP, ERR_R_PASSED_NULL_PARAMETER);
return NULL;
}
if (!(ret = OPENSSL_zalloc(sizeof(zkp_poly6_t)))) {
ERR_raise(ERR_LIB_ZKP_BP, ERR_R_MALLOC_FAILURE);
return NULL;
}
if (!(ret->bn_ctx = BN_CTX_new()))
goto err;
ret->t1 = BN_CTX_get(ret->bn_ctx);
ret->t2 = BN_CTX_get(ret->bn_ctx);
ret->t3 = BN_CTX_get(ret->bn_ctx);
ret->t4 = BN_CTX_get(ret->bn_ctx);
ret->t5 = BN_CTX_get(ret->bn_ctx);
ret->t6 = BN_CTX_get(ret->bn_ctx);
if (ret->t6 == NULL)
goto err;
ret->order = order;
return ret;
err:
zkp_poly6_free(ret);
return NULL;
}
void zkp_poly6_free(zkp_poly6_t *poly6)
{
if (poly6 == NULL)
return;
BN_CTX_free(poly6->bn_ctx);
OPENSSL_free(poly6);
}
int zkp_poly6_eval(zkp_poly6_t *poly6, const BIGNUM *x, BIGNUM *r)
{
int ret = 0;
if (poly6 == NULL || r == NULL) {
ERR_raise(ERR_LIB_ZKP_BP, ERR_R_PASSED_NULL_PARAMETER);
return 0;
}
if (!BN_mod_mul(r, x, poly6->t6, poly6->order, poly6->bn_ctx)
|| !BN_mod_add(r, r, poly6->t5, poly6->order, poly6->bn_ctx)
|| !BN_mod_mul(r, r, x, poly6->order, poly6->bn_ctx)
|| !BN_mod_add(r, r, poly6->t4, poly6->order, poly6->bn_ctx)
|| !BN_mod_mul(r, r, x, poly6->order, poly6->bn_ctx)
|| !BN_mod_add(r, r, poly6->t3, poly6->order, poly6->bn_ctx)
|| !BN_mod_mul(r, r, x, poly6->order, poly6->bn_ctx)
|| !BN_mod_add(r, r, poly6->t2, poly6->order, poly6->bn_ctx)
|| !BN_mod_mul(r, r, x, poly6->order, poly6->bn_ctx)
|| !BN_mod_add(r, r, poly6->t1, poly6->order, poly6->bn_ctx)
|| !BN_mod_mul(r, r, x, poly6->order, poly6->bn_ctx))
goto err;
ret = 1;
err:
return ret;
}
zkp_poly_points_t *zkp_poly_points_new(int capacity)
{
zkp_poly_points_t *ret = NULL;
if (capacity <= 0) {
ERR_raise(ERR_LIB_ZKP_BP, ERR_R_PASSED_INVALID_ARGUMENT);
return NULL;
}
if (!(ret = OPENSSL_zalloc(sizeof(*ret)))) {
ERR_raise(ERR_LIB_ZKP_BP, ERR_R_MALLOC_FAILURE);
return NULL;
}
if (!(ret->points = OPENSSL_zalloc(sizeof(*ret->points) * capacity))
|| !(ret->scalars = OPENSSL_zalloc(sizeof(*ret->scalars) * capacity))) {
ERR_raise(ERR_LIB_ZKP_BP, ERR_R_MALLOC_FAILURE);
goto err;
}
ret->num = 0;
ret->capacity = capacity;
return ret;
err:
zkp_poly_points_free(ret);
return NULL;
}
void zkp_poly_points_free(zkp_poly_points_t *ps)
{
if (ps == NULL)
return;
OPENSSL_free(ps->points);
OPENSSL_free(ps->scalars);
OPENSSL_free(ps);
}
void zkp_poly_points_reset(zkp_poly_points_t *ps)
{
if (ps == NULL || ps->num == 0)
return;
memset(ps->points, 0, sizeof(*ps->points) * ps->num);
memset(ps->scalars, 0, sizeof(*ps->scalars) * ps->num);
ps->num = 0;
}
int zkp_poly_points_append(zkp_poly_points_t *ps, EC_POINT *point, BIGNUM *scalar)
{
if (ps == NULL || point == NULL || scalar == NULL) {
ERR_raise(ERR_LIB_ZKP_BP, ERR_R_PASSED_NULL_PARAMETER);
return 0;
}
if (ps->num >= ps->capacity)
return 0;
ps->points[ps->num] = point;
ps->scalars[ps->num] = scalar;
ps->num++;
return 1;
}
int zkp_poly_points_mul(zkp_poly_points_t *ps, EC_POINT *r, BIGNUM *scalar,
const EC_GROUP *group, BN_CTX *bn_ctx)
{
if (ps == NULL || r == NULL || group == NULL || bn_ctx == NULL) {
ERR_raise(ERR_LIB_ZKP_BP, ERR_R_PASSED_NULL_PARAMETER);
return 0;
}
return EC_POINTs_mul(group, r, scalar, ps->num, (const EC_POINT **)ps->points,
(const BIGNUM **)ps->scalars, bn_ctx);
}
int zkp_bignum_encode(BIGNUM *bn, unsigned char *out, int bn_len)
{
unsigned char *p = out;
if (bn == NULL)
return 0;
*p++ = BN_is_negative(bn) ? '-' : '+';
if (!BN_bn2binpad(bn, p, bn_len))
goto end;
p += bn_len;
end:
return p - out;
}
BIGNUM *zkp_bignum_decode(const unsigned char *in, int *len, int bn_len)
{
int neg;
unsigned char *p = (unsigned char *)in;
BIGNUM *b = NULL;
if (in == NULL)
return NULL;
b = BN_new();
if (b == NULL)
return NULL;
neg = *p++ == '-' ? 1 : 0;
if (!BN_bin2bn(p, bn_len, b))
goto err;
BN_set_negative(b, neg);
p += bn_len;
if (len != NULL)
*len = p - in;
return b;
err:
BN_free(b);
return NULL;
}
int zkp_stack_of_bignum_encode(STACK_OF(BIGNUM) *sk, unsigned char *out,
int bn_len)
{
int i, n, *q;
unsigned char *p;
BIGNUM *b;
n = sk ? sk_BIGNUM_num(sk) : 0;
if (out == NULL)
return sizeof(n) + n * (bn_len + 1);
q = (int *)out;
*q++ = zkp_l2n((int)n);
p = (unsigned char *)q;
for (i = 0; i < n; i++) {
b = sk_BIGNUM_value(sk, i);
if (b == NULL)
goto end;
*p++ = BN_is_negative(b) ? '-' : '+';
if (!BN_bn2binpad(b, p, bn_len))
goto end;
p += bn_len;
}
end:
return p - out;
}
STACK_OF(BIGNUM) *zkp_stack_of_bignum_decode(const unsigned char *in,
int *len, int bn_len)
{
unsigned char *p;
int *q = (int *)in, n, i, neg;
BIGNUM *b = NULL;
STACK_OF(BIGNUM) *ret;
n = (int)zkp_n2l(*q);
q++;
p = (unsigned char *)q;
if (n < 0) {
return NULL;
}
if (!(ret = sk_BIGNUM_new_reserve(NULL, n)))
return NULL;
for (i = 0; i < n; i++) {
b = BN_new();
if (b == NULL)
goto err;
neg = *p++ == '-' ? 1 : 0;
if (!BN_bin2bn(p, (int)bn_len, b))
goto err;
BN_set_negative(b, neg);
if (sk_BIGNUM_push(ret, b) <= 0)
goto err;
p += bn_len;
}
if (len != NULL)
*len = p - in;
return ret;
err:
BN_free(b);
sk_BIGNUM_pop_free(ret, BN_free);
return NULL;
}
int zkp_stack_of_point_encode(STACK_OF(EC_POINT) *sk, unsigned char *out,
const EC_GROUP *group, BN_CTX *bn_ctx)
{
int i, n, *q;
size_t point_len;
unsigned char *p;
EC_POINT *P;
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_EC_POINT_num(sk);
if (out == NULL)
return sizeof(n) + n * point_len;
q = (int *)out;
*q++ = zkp_l2n((int)n);
p = (unsigned char *)q;
for (i = 0; i < n; i++) {
P = sk_EC_POINT_value(sk, i);
if (P == NULL)
goto end;
if (EC_POINT_point2oct(group, P, form, p, point_len, bn_ctx) == 0)
goto end;
p += point_len;
}
end:
return p - out;
}
STACK_OF(EC_POINT) *zkp_stack_of_point_decode(const unsigned char *in, int *len,
const EC_GROUP *group,
BN_CTX *bn_ctx)
{
unsigned char *p;
int *q = (int *)in, n, i;
size_t point_len;
EC_POINT *P = NULL;
STACK_OF(EC_POINT) *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_EC_POINT_new_reserve(NULL, n)))
return NULL;
for (i = 0; i < n; i++) {
if (!(P = EC_POINT_new(group)))
goto err;
if (!EC_POINT_oct2point(group, P, p, point_len, bn_ctx))
goto err;
if (sk_EC_POINT_push(ret, P) <= 0)
goto err;
p += point_len;
}
if (len != NULL)
*len = p - in;
return ret;
err:
EC_POINT_free(P);
sk_EC_POINT_pop_free(ret, EC_POINT_free);
return NULL;
}