675 lines
24 KiB
C
675 lines
24 KiB
C
/*
|
|
* Copyright Supranational LLC
|
|
* Licensed under the Apache License, Version 2.0, see LICENSE for details.
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*/
|
|
|
|
/*
|
|
* Usage pattern on single-processor system is
|
|
*
|
|
* blst_pairing_init(ctx, hash_or_encode, DST);
|
|
* blst_pairing_aggregate_pk_in_g1(ctx, PK[0], aggregated_signature, msg[0]);
|
|
* blst_pairing_aggregate_pk_in_g1(ctx, PK[1], NULL, msg[1]);
|
|
* ...
|
|
* blst_pairing_commit(ctx);
|
|
* blst_pairing_finalverify(ctx, NULL);
|
|
*
|
|
***********************************************************************
|
|
* Usage pattern on multi-processor system is
|
|
*
|
|
* blst_pairing_init(pk[0], hash_or_encode, DST);
|
|
* blst_pairing_init(pk[1], hash_or_encode, DST);
|
|
* ...
|
|
* start threads each processing an N/nthreads slice of PKs and messages:
|
|
* blst_pairing_aggregate_pk_in_g1(pk[i], PK[i*n+0], NULL, msg[i*n+0]);
|
|
* blst_pairing_aggregate_pk_in_g1(pk[i], PK[i*n+1], NULL, msg[i*n+1]);
|
|
* ...
|
|
* blst_pairing_commit(pkx);
|
|
* ...
|
|
* meanwhile in main thread
|
|
* blst_fp12 gtsig;
|
|
* blst_aggregated_in_g2(>sig, aggregated_signature);
|
|
* join threads and merge their contexts:
|
|
* blst_pairing_merge(pk[0], pk[1]);
|
|
* blst_pairing_merge(pk[0], pk[2]);
|
|
* ...
|
|
* blst_pairing_finalverify(pk[0], gtsig);
|
|
*/
|
|
|
|
#ifndef N_MAX
|
|
# define N_MAX 8
|
|
#endif
|
|
|
|
typedef union { POINTonE1 e1; POINTonE2 e2; } AggregatedSignature;
|
|
typedef struct {
|
|
unsigned int ctrl;
|
|
unsigned int nelems;
|
|
const void *DST;
|
|
size_t DST_len;
|
|
vec384fp12 GT;
|
|
AggregatedSignature AggrSign;
|
|
POINTonE2_affine Q[N_MAX];
|
|
POINTonE1_affine P[N_MAX];
|
|
} PAIRING;
|
|
|
|
enum { AGGR_UNDEFINED = 0,
|
|
AGGR_MIN_SIG = 1,
|
|
AGGR_MIN_PK = 2,
|
|
AGGR_SIGN_SET = 0x10,
|
|
AGGR_GT_SET = 0x20,
|
|
AGGR_HASH_OR_ENCODE = 0x40 };
|
|
#define MIN_SIG_OR_PK (AGGR_MIN_SIG | AGGR_MIN_PK)
|
|
|
|
static const size_t sizeof_pairing = (sizeof(PAIRING) + 7) & ~(size_t)7;
|
|
|
|
size_t blst_pairing_sizeof(void)
|
|
{ return sizeof_pairing; }
|
|
|
|
void blst_pairing_init(PAIRING *ctx, int hash_or_encode,
|
|
const void *DST, size_t DST_len)
|
|
{
|
|
ctx->ctrl = AGGR_UNDEFINED | (hash_or_encode ? AGGR_HASH_OR_ENCODE : 0);
|
|
ctx->nelems = 0;
|
|
ctx->DST = (uptr_t)DST==(uptr_t)((byte *)ctx+sizeof_pairing) ? (void *)42
|
|
: DST;
|
|
ctx->DST_len = DST_len;
|
|
}
|
|
|
|
static const void *pairing_get_dst(const PAIRING *ctx)
|
|
{ return (uptr_t)ctx->DST==(uptr_t)42 ? (const byte *)ctx+sizeof_pairing
|
|
: ctx->DST;
|
|
}
|
|
|
|
const void *blst_pairing_get_dst(const PAIRING *ctx)
|
|
{ return pairing_get_dst(ctx); }
|
|
|
|
#define FROM_AFFINE(out,in) do { \
|
|
vec_copy((out)->X, in->X, 2*sizeof(in->X)), \
|
|
vec_select((out)->Z, in->X, BLS12_381_Rx.p, sizeof(in->X), \
|
|
vec_is_zero(in->X, 2*sizeof(in->X))); } while(0)
|
|
|
|
/*
|
|
* Optional |nbits|-wide |scalar| is used to facilitate multiple aggregated
|
|
* signature vetification as discussed at
|
|
* https://ethresear.ch/t/fast-verification-of-multiple-bls-signatures/5407.
|
|
* Usage pattern is not finalized yet, because (sig != NULL) is better and
|
|
* will be handled separately...
|
|
*/
|
|
static BLST_ERROR PAIRING_Aggregate_PK_in_G2(PAIRING *ctx,
|
|
const POINTonE2_affine *PK,
|
|
size_t pk_groupcheck,
|
|
const POINTonE1_affine *sig,
|
|
size_t sig_groupcheck,
|
|
const byte *scalar, size_t nbits,
|
|
const void *msg, size_t msg_len,
|
|
const void *aug, size_t aug_len)
|
|
{
|
|
if (ctx->ctrl & AGGR_MIN_PK)
|
|
return BLST_AGGR_TYPE_MISMATCH;
|
|
|
|
ctx->ctrl |= AGGR_MIN_SIG;
|
|
|
|
/*
|
|
* Since we don't know if the signature is individual or aggregated,
|
|
* the only sensible thing to do is to skip over infinite one and
|
|
* count on the corresponding infinite public key to be rejected,
|
|
* in case the signature is non-aggregated that is.
|
|
*/
|
|
if (sig != NULL && !vec_is_zero(sig, sizeof(*sig))) {
|
|
POINTonE1 *S = &ctx->AggrSign.e1;
|
|
POINTonE1 P[1];
|
|
|
|
FROM_AFFINE(P, sig);
|
|
|
|
if (sig_groupcheck && !POINTonE1_in_G1(P))
|
|
return BLST_POINT_NOT_IN_GROUP;
|
|
|
|
if (ctx->ctrl & AGGR_SIGN_SET) {
|
|
if (nbits != 0 && scalar != NULL) {
|
|
POINTonE1_mult_w5(P, P, scalar, nbits);
|
|
POINTonE1_dadd(S, S, P, NULL);
|
|
} else {
|
|
POINTonE1_dadd_affine(S, S, sig);
|
|
}
|
|
} else {
|
|
ctx->ctrl |= AGGR_SIGN_SET;
|
|
if (nbits != 0 && scalar != NULL)
|
|
POINTonE1_mult_w5(S, P, scalar, nbits);
|
|
else
|
|
vec_copy(S, P, sizeof(P));
|
|
}
|
|
}
|
|
|
|
if (PK != NULL) {
|
|
unsigned int n;
|
|
POINTonE1 H[1];
|
|
const void *DST = pairing_get_dst(ctx);
|
|
|
|
/*
|
|
* Reject infinite public keys.
|
|
*/
|
|
if (vec_is_zero(PK, sizeof(*PK)))
|
|
return BLST_PK_IS_INFINITY;
|
|
|
|
if (pk_groupcheck) {
|
|
POINTonE2 P[1];
|
|
|
|
FROM_AFFINE(P, PK);
|
|
if (!POINTonE2_in_G2(P))
|
|
return BLST_POINT_NOT_IN_GROUP;
|
|
}
|
|
|
|
if (ctx->ctrl & AGGR_HASH_OR_ENCODE)
|
|
Hash_to_G1(H, msg, msg_len, DST, ctx->DST_len, aug, aug_len);
|
|
else
|
|
Encode_to_G1(H, msg, msg_len, DST, ctx->DST_len, aug, aug_len);
|
|
|
|
if (nbits != 0 && scalar != NULL)
|
|
POINTonE1_mult_w5(H, H, scalar, nbits);
|
|
|
|
POINTonE1_from_Jacobian(H, H);
|
|
|
|
n = ctx->nelems;
|
|
vec_copy(ctx->Q + n, PK, sizeof(POINTonE2_affine));
|
|
vec_copy(ctx->P + n, H, sizeof(POINTonE1_affine));
|
|
if (++n == N_MAX) {
|
|
if (ctx->ctrl & AGGR_GT_SET) {
|
|
vec384fp12 GT;
|
|
miller_loop_n(GT, ctx->Q, ctx->P, n);
|
|
mul_fp12(ctx->GT, ctx->GT, GT);
|
|
} else {
|
|
miller_loop_n(ctx->GT, ctx->Q, ctx->P, n);
|
|
ctx->ctrl |= AGGR_GT_SET;
|
|
}
|
|
n = 0;
|
|
}
|
|
ctx->nelems = n;
|
|
}
|
|
|
|
return BLST_SUCCESS;
|
|
}
|
|
|
|
BLST_ERROR blst_pairing_aggregate_pk_in_g2(PAIRING *ctx,
|
|
const POINTonE2_affine *PK,
|
|
const POINTonE1_affine *signature,
|
|
const void *msg, size_t msg_len,
|
|
const void *aug, size_t aug_len)
|
|
{ return PAIRING_Aggregate_PK_in_G2(ctx, PK, 0, signature, 1, NULL, 0,
|
|
msg, msg_len, aug, aug_len);
|
|
}
|
|
|
|
BLST_ERROR blst_pairing_mul_n_aggregate_pk_in_g2(PAIRING *ctx,
|
|
const POINTonE2_affine *PK,
|
|
const POINTonE1_affine *sig,
|
|
const byte *scalar,
|
|
size_t nbits,
|
|
const void *msg,
|
|
size_t msg_len,
|
|
const void *aug,
|
|
size_t aug_len)
|
|
{ return PAIRING_Aggregate_PK_in_G2(ctx, PK, 0, sig, 1, scalar, nbits,
|
|
msg, msg_len, aug, aug_len);
|
|
}
|
|
|
|
BLST_ERROR blst_pairing_chk_n_aggr_pk_in_g2(PAIRING *ctx,
|
|
const POINTonE2_affine *PK,
|
|
size_t pk_grpchk,
|
|
const POINTonE1_affine *signature,
|
|
size_t sig_grpchk,
|
|
const void *msg, size_t msg_len,
|
|
const void *aug, size_t aug_len)
|
|
{ return PAIRING_Aggregate_PK_in_G2(ctx, PK, pk_grpchk, signature, sig_grpchk,
|
|
NULL, 0, msg, msg_len, aug, aug_len);
|
|
}
|
|
|
|
BLST_ERROR blst_pairing_chk_n_mul_n_aggr_pk_in_g2(PAIRING *ctx,
|
|
const POINTonE2_affine *PK,
|
|
size_t pk_grpchk,
|
|
const POINTonE1_affine *sig,
|
|
size_t sig_grpchk,
|
|
const byte *scalar,
|
|
size_t nbits,
|
|
const void *msg,
|
|
size_t msg_len,
|
|
const void *aug,
|
|
size_t aug_len)
|
|
{ return PAIRING_Aggregate_PK_in_G2(ctx, PK, pk_grpchk, sig, sig_grpchk,
|
|
scalar, nbits,
|
|
msg, msg_len, aug, aug_len);
|
|
}
|
|
|
|
static BLST_ERROR PAIRING_Aggregate_PK_in_G1(PAIRING *ctx,
|
|
const POINTonE1_affine *PK,
|
|
size_t pk_groupcheck,
|
|
const POINTonE2_affine *sig,
|
|
size_t sig_groupcheck,
|
|
const byte *scalar, size_t nbits,
|
|
const void *msg, size_t msg_len,
|
|
const void *aug, size_t aug_len)
|
|
{
|
|
if (ctx->ctrl & AGGR_MIN_SIG)
|
|
return BLST_AGGR_TYPE_MISMATCH;
|
|
|
|
ctx->ctrl |= AGGR_MIN_PK;
|
|
|
|
/*
|
|
* Since we don't know if the signature is individual or aggregated,
|
|
* the only sensible thing to do is to skip over infinite one and
|
|
* count on the corresponding infinite public key to be rejected,
|
|
* in case the signature is non-aggregated that is.
|
|
*/
|
|
if (sig != NULL && !vec_is_zero(sig, sizeof(*sig))) {
|
|
POINTonE2 *S = &ctx->AggrSign.e2;
|
|
POINTonE2 P[1];
|
|
|
|
FROM_AFFINE(P, sig);
|
|
|
|
if (sig_groupcheck && !POINTonE2_in_G2(P))
|
|
return BLST_POINT_NOT_IN_GROUP;
|
|
|
|
if (ctx->ctrl & AGGR_SIGN_SET) {
|
|
if (nbits != 0 && scalar != NULL) {
|
|
|
|
POINTonE2_mult_w5(P, P, scalar, nbits);
|
|
POINTonE2_dadd(S, S, P, NULL);
|
|
} else {
|
|
POINTonE2_dadd_affine(S, S, sig);
|
|
}
|
|
} else {
|
|
ctx->ctrl |= AGGR_SIGN_SET;
|
|
if (nbits != 0 && scalar != NULL)
|
|
POINTonE2_mult_w5(S, P, scalar, nbits);
|
|
else
|
|
vec_copy(S, P, sizeof(P));
|
|
}
|
|
}
|
|
|
|
if (PK != NULL) {
|
|
unsigned int n;
|
|
POINTonE2 H[1];
|
|
const void *DST = pairing_get_dst(ctx);
|
|
|
|
/*
|
|
* Reject infinite public keys.
|
|
*/
|
|
if (vec_is_zero(PK, sizeof(*PK)))
|
|
return BLST_PK_IS_INFINITY;
|
|
|
|
if (pk_groupcheck) {
|
|
POINTonE1 P[1];
|
|
|
|
FROM_AFFINE(P, PK);
|
|
if (!POINTonE1_in_G1(P))
|
|
return BLST_POINT_NOT_IN_GROUP;
|
|
}
|
|
|
|
if (ctx->ctrl & AGGR_HASH_OR_ENCODE)
|
|
Hash_to_G2(H, msg, msg_len, DST, ctx->DST_len, aug, aug_len);
|
|
else
|
|
Encode_to_G2(H, msg, msg_len, DST, ctx->DST_len, aug, aug_len);
|
|
|
|
POINTonE2_from_Jacobian(H, H);
|
|
|
|
if (nbits != 0 && scalar != NULL) {
|
|
POINTonE1 pk[1];
|
|
|
|
FROM_AFFINE(pk, PK);
|
|
POINTonE1_mult_w5(pk, pk, scalar, nbits);
|
|
POINTonE1_from_Jacobian(pk, pk);
|
|
PK = (const POINTonE1_affine *)pk;
|
|
}
|
|
|
|
n = ctx->nelems;
|
|
vec_copy(ctx->Q + n, H, sizeof(POINTonE2_affine));
|
|
vec_copy(ctx->P + n, PK, sizeof(POINTonE1_affine));
|
|
if (++n == N_MAX) {
|
|
if (ctx->ctrl & AGGR_GT_SET) {
|
|
vec384fp12 GT;
|
|
miller_loop_n(GT, ctx->Q, ctx->P, n);
|
|
mul_fp12(ctx->GT, ctx->GT, GT);
|
|
} else {
|
|
miller_loop_n(ctx->GT, ctx->Q, ctx->P, n);
|
|
ctx->ctrl |= AGGR_GT_SET;
|
|
}
|
|
n = 0;
|
|
}
|
|
ctx->nelems = n;
|
|
}
|
|
|
|
return BLST_SUCCESS;
|
|
}
|
|
|
|
BLST_ERROR blst_pairing_aggregate_pk_in_g1(PAIRING *ctx,
|
|
const POINTonE1_affine *PK,
|
|
const POINTonE2_affine *signature,
|
|
const void *msg, size_t msg_len,
|
|
const void *aug, size_t aug_len)
|
|
{ return PAIRING_Aggregate_PK_in_G1(ctx, PK, 0, signature, 1, NULL, 0,
|
|
msg, msg_len, aug, aug_len);
|
|
}
|
|
|
|
BLST_ERROR blst_pairing_mul_n_aggregate_pk_in_g1(PAIRING *ctx,
|
|
const POINTonE1_affine *PK,
|
|
const POINTonE2_affine *sig,
|
|
const byte *scalar,
|
|
size_t nbits,
|
|
const void *msg,
|
|
size_t msg_len,
|
|
const void *aug,
|
|
size_t aug_len)
|
|
{ return PAIRING_Aggregate_PK_in_G1(ctx, PK, 0, sig, 1, scalar, nbits,
|
|
msg, msg_len, aug, aug_len);
|
|
}
|
|
|
|
BLST_ERROR blst_pairing_chk_n_aggr_pk_in_g1(PAIRING *ctx,
|
|
const POINTonE1_affine *PK,
|
|
size_t pk_grpchk,
|
|
const POINTonE2_affine *signature,
|
|
size_t sig_grpchk,
|
|
const void *msg, size_t msg_len,
|
|
const void *aug, size_t aug_len)
|
|
{ return PAIRING_Aggregate_PK_in_G1(ctx, PK, pk_grpchk, signature, sig_grpchk,
|
|
NULL, 0, msg, msg_len, aug, aug_len);
|
|
}
|
|
|
|
BLST_ERROR blst_pairing_chk_n_mul_n_aggr_pk_in_g1(PAIRING *ctx,
|
|
const POINTonE1_affine *PK,
|
|
size_t pk_grpchk,
|
|
const POINTonE2_affine *sig,
|
|
size_t sig_grpchk,
|
|
const byte *scalar,
|
|
size_t nbits,
|
|
const void *msg,
|
|
size_t msg_len,
|
|
const void *aug,
|
|
size_t aug_len)
|
|
{ return PAIRING_Aggregate_PK_in_G1(ctx, PK, pk_grpchk, sig, sig_grpchk,
|
|
scalar, nbits,
|
|
msg, msg_len, aug, aug_len);
|
|
}
|
|
|
|
static void PAIRING_Commit(PAIRING *ctx)
|
|
{
|
|
unsigned int n;
|
|
|
|
if ((n = ctx->nelems) != 0) {
|
|
if (ctx->ctrl & AGGR_GT_SET) {
|
|
vec384fp12 GT;
|
|
miller_loop_n(GT, ctx->Q, ctx->P, n);
|
|
mul_fp12(ctx->GT, ctx->GT, GT);
|
|
} else {
|
|
miller_loop_n(ctx->GT, ctx->Q, ctx->P, n);
|
|
ctx->ctrl |= AGGR_GT_SET;
|
|
}
|
|
ctx->nelems = 0;
|
|
}
|
|
}
|
|
|
|
void blst_pairing_commit(PAIRING *ctx)
|
|
{ PAIRING_Commit(ctx); }
|
|
|
|
BLST_ERROR blst_pairing_merge(PAIRING *ctx, const PAIRING *ctx1)
|
|
{
|
|
if ((ctx->ctrl & MIN_SIG_OR_PK) != AGGR_UNDEFINED
|
|
&& (ctx1->ctrl & MIN_SIG_OR_PK) != AGGR_UNDEFINED
|
|
&& (ctx->ctrl & ctx1->ctrl & MIN_SIG_OR_PK) == 0)
|
|
return BLST_AGGR_TYPE_MISMATCH;
|
|
|
|
/* context producers are expected to have called blst_pairing_commit */
|
|
if (ctx->nelems || ctx1->nelems)
|
|
return BLST_AGGR_TYPE_MISMATCH;
|
|
|
|
ctx->ctrl |= ctx1->ctrl & MIN_SIG_OR_PK;
|
|
|
|
switch (ctx->ctrl & MIN_SIG_OR_PK) {
|
|
case AGGR_MIN_SIG:
|
|
if (ctx->ctrl & ctx1->ctrl & AGGR_SIGN_SET) {
|
|
POINTonE1_dadd(&ctx->AggrSign.e1, &ctx->AggrSign.e1,
|
|
&ctx1->AggrSign.e1, NULL);
|
|
} else if (ctx1->ctrl & AGGR_SIGN_SET) {
|
|
ctx->ctrl |= AGGR_SIGN_SET;
|
|
vec_copy(&ctx->AggrSign.e1, &ctx1->AggrSign.e1,
|
|
sizeof(ctx->AggrSign.e1));
|
|
}
|
|
break;
|
|
case AGGR_MIN_PK:
|
|
if (ctx->ctrl & ctx1->ctrl & AGGR_SIGN_SET) {
|
|
POINTonE2_dadd(&ctx->AggrSign.e2, &ctx->AggrSign.e2,
|
|
&ctx1->AggrSign.e2, NULL);
|
|
} else if (ctx1->ctrl & AGGR_SIGN_SET) {
|
|
ctx->ctrl |= AGGR_SIGN_SET;
|
|
vec_copy(&ctx->AggrSign.e2, &ctx1->AggrSign.e2,
|
|
sizeof(ctx->AggrSign.e2));
|
|
}
|
|
break;
|
|
case AGGR_UNDEFINED:
|
|
break;
|
|
default:
|
|
return BLST_AGGR_TYPE_MISMATCH;
|
|
}
|
|
|
|
if (ctx->ctrl & ctx1->ctrl & AGGR_GT_SET) {
|
|
mul_fp12(ctx->GT, ctx->GT, ctx1->GT);
|
|
} else if (ctx1->ctrl & AGGR_GT_SET) {
|
|
ctx->ctrl |= AGGR_GT_SET;
|
|
vec_copy(ctx->GT, ctx1->GT, sizeof(ctx->GT));
|
|
}
|
|
|
|
return BLST_SUCCESS;
|
|
}
|
|
|
|
static bool_t PAIRING_FinalVerify(const PAIRING *ctx, const vec384fp12 GTsig)
|
|
{
|
|
vec384fp12 GT;
|
|
|
|
if (!(ctx->ctrl & AGGR_GT_SET))
|
|
return 0;
|
|
|
|
if (GTsig != NULL) {
|
|
vec_copy(GT, GTsig, sizeof(GT));
|
|
} else if (ctx->ctrl & AGGR_SIGN_SET) {
|
|
AggregatedSignature AggrSign;
|
|
|
|
switch (ctx->ctrl & MIN_SIG_OR_PK) {
|
|
case AGGR_MIN_SIG:
|
|
POINTonE1_from_Jacobian(&AggrSign.e1, &ctx->AggrSign.e1);
|
|
miller_loop_n(GT, (const POINTonE2_affine *)&BLS12_381_G2,
|
|
(const POINTonE1_affine *)&AggrSign.e1, 1);
|
|
break;
|
|
case AGGR_MIN_PK:
|
|
POINTonE2_from_Jacobian(&AggrSign.e2, &ctx->AggrSign.e2);
|
|
miller_loop_n(GT, (const POINTonE2_affine *)&AggrSign.e2,
|
|
(const POINTonE1_affine *)&BLS12_381_G1, 1);
|
|
break;
|
|
default:
|
|
return 0;
|
|
}
|
|
} else {
|
|
/*
|
|
* The aggregated signature was infinite, relation between the
|
|
* hashes and the public keys has to be VERY special...
|
|
*/
|
|
vec_copy(GT, BLS12_381_Rx.p12, sizeof(GT));
|
|
}
|
|
|
|
conjugate_fp12(GT);
|
|
mul_fp12(GT, GT, ctx->GT);
|
|
final_exp(GT, GT);
|
|
|
|
/* return GT==1 */
|
|
return vec_is_equal(GT[0][0], BLS12_381_Rx.p2, sizeof(GT[0][0])) &
|
|
vec_is_zero(GT[0][1], sizeof(GT) - sizeof(GT[0][0]));
|
|
}
|
|
|
|
int blst_pairing_finalverify(const PAIRING *ctx, const vec384fp12 GTsig)
|
|
{ return (int)PAIRING_FinalVerify(ctx, GTsig); }
|
|
|
|
int blst_fp12_finalverify(const vec384fp12 GT1, const vec384fp12 GT2)
|
|
{
|
|
vec384fp12 GT;
|
|
|
|
vec_copy(GT, GT1, sizeof(GT));
|
|
conjugate_fp12(GT);
|
|
mul_fp12(GT, GT, GT2);
|
|
final_exp(GT, GT);
|
|
|
|
/* return GT==1 */
|
|
return (int)(vec_is_equal(GT[0][0], BLS12_381_Rx.p2, sizeof(GT[0][0])) &
|
|
vec_is_zero(GT[0][1], sizeof(GT) - sizeof(GT[0][0])));
|
|
}
|
|
|
|
void blst_pairing_raw_aggregate(PAIRING *ctx, const POINTonE2_affine *q,
|
|
const POINTonE1_affine *p)
|
|
{
|
|
unsigned int n;
|
|
|
|
if (vec_is_zero(q, sizeof(*q)) & vec_is_zero(p, sizeof(*p)))
|
|
return;
|
|
|
|
n = ctx->nelems;
|
|
vec_copy(ctx->Q + n, q, sizeof(*q));
|
|
vec_copy(ctx->P + n, p, sizeof(*p));
|
|
if (++n == N_MAX) {
|
|
if (ctx->ctrl & AGGR_GT_SET) {
|
|
vec384fp12 GT;
|
|
miller_loop_n(GT, ctx->Q, ctx->P, n);
|
|
mul_fp12(ctx->GT, ctx->GT, GT);
|
|
} else {
|
|
miller_loop_n(ctx->GT, ctx->Q, ctx->P, n);
|
|
ctx->ctrl |= AGGR_GT_SET;
|
|
}
|
|
n = 0;
|
|
}
|
|
ctx->nelems = n;
|
|
}
|
|
|
|
vec384fp12 *blst_pairing_as_fp12(PAIRING *ctx)
|
|
{
|
|
PAIRING_Commit(ctx);
|
|
return (vec384fp12 *)ctx->GT;
|
|
}
|
|
|
|
/*
|
|
* PAIRING context-free entry points.
|
|
*
|
|
* To perform FastAggregateVerify, aggregate all public keys and
|
|
* signatures with corresponding blst_aggregate_in_g{12}, convert
|
|
* result to affine and call suitable blst_core_verify_pk_in_g{12}
|
|
* or blst_aggregated_in_g{12}...
|
|
*/
|
|
BLST_ERROR blst_aggregate_in_g1(POINTonE1 *out, const POINTonE1 *in,
|
|
const unsigned char *zwire)
|
|
{
|
|
POINTonE1 P[1];
|
|
BLST_ERROR ret;
|
|
|
|
ret = POINTonE1_Deserialize_Z((POINTonE1_affine *)P, zwire);
|
|
|
|
if (ret != BLST_SUCCESS)
|
|
return ret;
|
|
|
|
if (vec_is_zero(P, sizeof(POINTonE1_affine))) {
|
|
if (in == NULL)
|
|
vec_zero(out, sizeof(*out));
|
|
return BLST_SUCCESS;
|
|
}
|
|
|
|
vec_copy(P->Z, BLS12_381_Rx.p, sizeof(P->Z));
|
|
|
|
if (!POINTonE1_in_G1(P))
|
|
return BLST_POINT_NOT_IN_GROUP;
|
|
|
|
if (in == NULL)
|
|
vec_copy(out, P, sizeof(P));
|
|
else
|
|
POINTonE1_dadd_affine(out, in, (POINTonE1_affine *)P);
|
|
|
|
return BLST_SUCCESS;
|
|
}
|
|
|
|
BLST_ERROR blst_aggregate_in_g2(POINTonE2 *out, const POINTonE2 *in,
|
|
const unsigned char *zwire)
|
|
{
|
|
POINTonE2 P[1];
|
|
BLST_ERROR ret;
|
|
|
|
ret = POINTonE2_Deserialize_Z((POINTonE2_affine *)P, zwire);
|
|
|
|
if (ret != BLST_SUCCESS)
|
|
return ret;
|
|
|
|
if (vec_is_zero(P, sizeof(POINTonE2_affine))) {
|
|
if (in == NULL)
|
|
vec_zero(out, sizeof(*out));
|
|
return BLST_SUCCESS;
|
|
}
|
|
|
|
vec_copy(P->Z, BLS12_381_Rx.p, sizeof(P->Z));
|
|
|
|
if (!POINTonE2_in_G2(P))
|
|
return BLST_POINT_NOT_IN_GROUP;
|
|
|
|
if (in == NULL) {
|
|
vec_copy(out, P, sizeof(P));
|
|
} else {
|
|
POINTonE2_dadd_affine(out, in, (POINTonE2_affine *)P);
|
|
}
|
|
return BLST_SUCCESS;
|
|
}
|
|
|
|
void blst_aggregated_in_g1(vec384fp12 ret, const POINTonE1_affine *sig)
|
|
{ miller_loop_n(ret, (const POINTonE2_affine *)&BLS12_381_G2, sig, 1); }
|
|
|
|
void blst_aggregated_in_g2(vec384fp12 ret, const POINTonE2_affine *sig)
|
|
{ miller_loop_n(ret, sig, (const POINTonE1_affine *)&BLS12_381_G1, 1); }
|
|
|
|
BLST_ERROR blst_core_verify_pk_in_g1(const POINTonE1_affine *pk,
|
|
const POINTonE2_affine *signature,
|
|
int hash_or_encode,
|
|
const void *msg, size_t msg_len,
|
|
const void *DST, size_t DST_len,
|
|
const void *aug, size_t aug_len)
|
|
{
|
|
PAIRING ctx;
|
|
BLST_ERROR ret;
|
|
|
|
ctx.ctrl = AGGR_UNDEFINED | (hash_or_encode ? AGGR_HASH_OR_ENCODE : 0);
|
|
ctx.nelems = 0;
|
|
ctx.DST = DST;
|
|
ctx.DST_len = DST_len;
|
|
|
|
ret = PAIRING_Aggregate_PK_in_G1(&ctx, pk, 1, signature, 1, NULL, 0,
|
|
msg, msg_len, aug, aug_len);
|
|
if (ret != BLST_SUCCESS)
|
|
return ret;
|
|
|
|
PAIRING_Commit(&ctx);
|
|
|
|
return PAIRING_FinalVerify(&ctx, NULL) ? BLST_SUCCESS : BLST_VERIFY_FAIL;
|
|
}
|
|
|
|
BLST_ERROR blst_core_verify_pk_in_g2(const POINTonE2_affine *pk,
|
|
const POINTonE1_affine *signature,
|
|
int hash_or_encode,
|
|
const void *msg, size_t msg_len,
|
|
const void *DST, size_t DST_len,
|
|
const void *aug, size_t aug_len)
|
|
{
|
|
PAIRING ctx;
|
|
BLST_ERROR ret;
|
|
|
|
ctx.ctrl = AGGR_UNDEFINED | (hash_or_encode ? AGGR_HASH_OR_ENCODE : 0);
|
|
ctx.nelems = 0;
|
|
ctx.DST = DST;
|
|
ctx.DST_len = DST_len;
|
|
|
|
ret = PAIRING_Aggregate_PK_in_G2(&ctx, pk, 1, signature, 1, NULL, 0,
|
|
msg, msg_len, aug, aug_len);
|
|
if (ret != BLST_SUCCESS)
|
|
return ret;
|
|
|
|
PAIRING_Commit(&ctx);
|
|
|
|
return PAIRING_FinalVerify(&ctx, NULL) ? BLST_SUCCESS : BLST_VERIFY_FAIL;
|
|
}
|