#include "common/lincomb.h"
#include "common/alloc.h"
#include <stdlib.h>
void g1_lincomb_naive(g1_t *out, const g1_t *p, const fr_t *coeffs, size_t len) {
g1_t tmp;
*out = G1_IDENTITY;
for (size_t i = 0; i < len; i++) {
g1_mul(&tmp, &p[i], &coeffs[i]);
g1_add(out, out, &tmp);
}
}
C_KZG_RET g1_lincomb_fast(g1_t *out, const g1_t *p, const fr_t *coeffs, size_t len) {
C_KZG_RET ret;
limb_t *scratch = NULL;
blst_p1 *p_filtered = NULL;
blst_p1_affine *p_affine = NULL;
blst_scalar *scalars = NULL;
ret = c_kzg_calloc((void **)&p_filtered, len, sizeof(blst_p1));
if (ret != C_KZG_OK) goto out;
ret = c_kzg_calloc((void **)&p_affine, len, sizeof(blst_p1_affine));
if (ret != C_KZG_OK) goto out;
ret = c_kzg_calloc((void **)&scalars, len, sizeof(blst_scalar));
if (ret != C_KZG_OK) goto out;
size_t scratch_size = blst_p1s_mult_pippenger_scratch_sizeof(len);
ret = c_kzg_malloc((void **)&scratch, scratch_size);
if (ret != C_KZG_OK) goto out;
for (size_t i = 0; i < len; i++) {
blst_scalar_from_fr(&scalars[i], &coeffs[i]);
}
size_t new_len = 0;
for (size_t i = 0; i < len; i++) {
if (!blst_p1_is_inf(&p[i])) {
p_filtered[new_len] = p[i];
scalars[new_len] = scalars[i];
new_len++;
}
}
if (new_len == 0) {
*out = G1_IDENTITY;
goto out;
}
const blst_p1 *p_arg[2] = {p_filtered, NULL};
blst_p1s_to_affine(p_affine, p_arg, new_len);
const byte *scalars_arg[2] = {(byte *)scalars, NULL};
const blst_p1_affine *points_arg[2] = {p_affine, NULL};
blst_p1s_mult_pippenger(out, points_arg, new_len, scalars_arg, BITS_PER_FIELD_ELEMENT, scratch);
ret = C_KZG_OK;
out:
c_kzg_free(scratch);
c_kzg_free(p_filtered);
c_kzg_free(p_affine);
c_kzg_free(scalars);
return ret;
}