blob: 1f4293694d2ad8321ca64092a69b60fb86aa97cf [file] [log] [blame]
/*
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
*/
/* Boneh-Lynn-Shacham signature 128-bit API */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include "config_curve_ZZZ.h"
#include "hash_to_field_YYY.h"
#if CURVE_SECURITY_ZZZ == 128
#include "bls_ietf_ZZZ.h"
#else
#error "IETF-compliant BLS currently only supports 128-bit security level (i.e. BLS12-381)"
#endif
int BLS_IETF_ZZZ_keygen(char sk[SK_LEN],
const char *ikm, unsigned int ikmlen,
const char *salt, unsigned int saltlen,
const char *info, unsigned int infolen)
{
if (ikm == NULL || salt == NULL || (info == NULL && infolen))
return ERR_NULLPOINTER_BLS;
if (ikmlen < 32 || saltlen < SHA256_HASH_SIZE)
return ERR_BADARGLEN_BLS;
int ret;
// L = ceil((3 * ceil(log2(r))) / 16) as defined in RFC
unsigned int L = (3*(unsigned int)BIG_XXX_nbits(CURVE_Order_ZZZ) + 15) / 16; // 15 is added to ensure ceiling-division
char okm[L];
char prk[SHA256_HASH_SIZE];
char ikm_prime[ikmlen + 1];
char info_prime[infolen + 2];
char salt_prime[saltlen];
BIG_XXX s;
for(unsigned int i = 0; i < saltlen; i++)
salt_prime[i] = salt[i];
for(unsigned int i = 0; i < ikmlen; i++)
ikm_prime[i] = ikm[i];
// ikm_prime = ikm || I2OSP(0, 1)
ikm_prime[ikmlen] = 0x00;
for(unsigned int i = 0; i < infolen; i++)
info_prime[i] = info[i];
// info_prime = info || I2OSP(L, 2)
info_prime[infolen] = (char)(L >> 8); // most significant byte
info_prime[infolen + 1] = (char)(L & 0xff); // least significant byte
while (1) {
// PRK = HKDF-Extract(salt, IKM || I2OSP(0, 1))
ret = HKDF_SHA256_extract(prk, salt_prime, saltlen, ikm_prime, ikmlen + 1);
// OKM = HKDF-Expand(PRK, key_info || I2OSP(L, 2), L)
ret |= HKDF_SHA256_expand(okm, L, prk, SHA256_HASH_SIZE, info_prime, infolen + 2);
if (ret != SUCCESS)
return ret;
// SK = OS2IP(OKM) mod r
BIG_XXX_fromBytesLen(s, okm, L);
BIG_XXX_mod(s, CURVE_Order_ZZZ);
// if SK != 0
if (!BIG_XXX_iszilch(s)) {
// return SK
BIG_XXX_toBytes(okm, s);
// SK is only 32-byte long and requires BE encoding
for(unsigned int i = 0; i < SK_LEN; i++)
sk[i] = okm[L - SK_LEN + i];
break;
}
// salt = H(salt)
HASH256_oneshot(salt_prime, salt_prime, saltlen);
// the initial saltlen may be greater than the hash size
saltlen = SHA256_HASH_SIZE;
}
// zeroize pseudo-random key
for(unsigned int i = 0; i < SHA256_HASH_SIZE; i++)
prk[i] = 0x00;
// zeroize output keying material
for(unsigned int i = 0; i < L; i++)
okm[i] = 0x00;
// zeroize big variable
BIG_XXX_zero(s);
return SUCCESS;
}
int BLS_IETF_ZZZ_sk_to_pk_G1(ECP_ZZZ *pk, const char *sk)
{
if (pk == NULL || sk == NULL)
return ERR_NULLPOINTER_BLS;
BIG_XXX s;
// s <- SK
BIG_XXX_fromBytesLen(s, sk, SK_LEN);
// PK <- G
ECP_ZZZ_generator(pk);
// PK <- s*G
ECP_ZZZ_mul(pk, s);
// zeroize big variable
BIG_XXX_zero(s);
return SUCCESS;
}
int BLS_IETF_ZZZ_sk_to_pk_G2(ECP2_ZZZ *pk, const char *sk)
{
if (pk == NULL || sk == NULL)
return ERR_NULLPOINTER_BLS;
BIG_XXX s;
// s <- SK
BIG_XXX_fromBytesLen(s, sk, SK_LEN);
// PK <- G
ECP2_ZZZ_generator(pk);
// PK <- s*G
ECP2_ZZZ_mul(pk, s);
// zeroize big variable
BIG_XXX_zero(s);
return SUCCESS;
}
int BLS_IETF_ZZZ_serialize_G1(octet *bytes, const ECP_ZZZ *point)
{
if (bytes == NULL || point == NULL)
return ERR_NULLPOINTER_BLS;
BIG_XXX x;
BIG_XXX y;
if (ECP_ZZZ_get(x, y, point) == -1)
return ERR_NOTONCURVE_BLS;
BIG_XXX_toBytes(bytes->val, x);
BIG_XXX_toBytes(bytes->val + BFS_ZZZ, y);
return SUCCESS;
}
int BLS_IETF_ZZZ_deserialize_G1(ECP_ZZZ *point, const octet *bytes)
{
if (bytes == NULL || point == NULL)
return ERR_NULLPOINTER_BLS;
BIG_XXX x;
BIG_XXX y;
BIG_XXX_fromBytes(x, bytes->val);
BIG_XXX_fromBytes(y, bytes->val + BFS_ZZZ);
if (ECP_ZZZ_set(point, x, y) == 0)
return ERR_NOTONCURVE_BLS;
return SUCCESS;
}
int BLS_IETF_ZZZ_serialize_G2(octet *bytes, const ECP2_ZZZ *point)
{
if (bytes == NULL || point == NULL)
return ERR_NULLPOINTER_BLS;
BIG_XXX b;
FP2_YYY qx;
FP2_YYY qy;
if (ECP2_ZZZ_get(&qx, &qy, point) == -1)
return ERR_NOTONCURVE_BLS;
FP_YYY_redc(b, &(qx.b));
BIG_XXX_toBytes(bytes->val, b);
bytes->len = BFS_ZZZ;
FP_YYY_redc(b, &(qx.a));
BIG_XXX_toBytes(bytes->val + BFS_ZZZ, b);
bytes->len += BFS_ZZZ;
FP_YYY_redc(b, &(qy.b));
BIG_XXX_toBytes(bytes->val + 2*BFS_ZZZ, b);
bytes->len += BFS_ZZZ;
FP_YYY_redc(b, &(qy.a));
BIG_XXX_toBytes(bytes->val + 3*BFS_ZZZ, b);
bytes->len += BFS_ZZZ;
return SUCCESS;
}
int BLS_IETF_ZZZ_deserialize_G2(ECP2_ZZZ *point, const octet *bytes)
{
if (bytes == NULL || point == NULL)
return ERR_NULLPOINTER_BLS;
BIG_XXX re;
BIG_XXX im;
FP2_YYY x;
FP2_YYY y;
// First FP2 element
BIG_XXX_fromBytes(im, bytes->val);
BIG_XXX_fromBytes(re, bytes->val + BFS_ZZZ);
FP2_YYY_from_BIGs(&x, re, im);
// Second FP2 element
BIG_XXX_fromBytes(im, bytes->val + 2*BFS_ZZZ);
BIG_XXX_fromBytes(re, bytes->val + 3*BFS_ZZZ);
FP2_YYY_from_BIGs(&y, re, im);
if (ECP2_ZZZ_set(point, &x, &y) == 0)
return ERR_NOTONCURVE_BLS;
return SUCCESS;
}
/**
* @brief Indicates if given a y-coordinate is the lexicographically greatest
* as well as its parity.
*
* @param y y-coordinate
*
* @return A 2-bit value where:
* - the most-significant bit is set to 1 if the y-coordinate is the
* lexicographically largest of the two associated with its x-coordinate.
* - the least-significant bit is set to 1 if the y-coordinate is odd.
*/
static int sgn0_big(const BIG_XXX y)
{
int i;
int carry;
int ret;
chunk borrow;
chunk chunkx;
BIG_XXX tmp;
ret = y[0] & 1;
for (carry=0, i=0; i<NLEN_XXX; i++) {
tmp[i] = (y[i] << 1) | carry;
carry = y[i] >> (BASEBITS_XXX - 1);
}
for (borrow=0, i=0; i<NLEN_XXX; i++) {
chunkx = tmp[i] - (Modulus_ZZZ[i] + borrow);
borrow = (chunkx >> BASEBITS_XXX) & 1;
}
ret |= ((carry - (int)borrow) & 2) ^ 2;
return ret;
}
/**
* @brief Indicates if given a y-coordinate (FP2 element) is the
* lexicographically greatest as well as its parity.
*
* @param y y-coordinate
*
* @return A 2-bit value where:
* - the most-significant bit is set to 1 if the y-coordinate is the
* lexicographically largest of the two associated with its x-coordinate.
* - the least-significant bit is set to 1 if the y-coordinate is odd.
*/
static int sgn0_fp2(const FP2_YYY y)
{
int re;
int im;
int sign;
int prty;
BIG_XXX a;
BIG_XXX b;
FP_YYY_redc(a, &(y.a));
FP_YYY_redc(b, &(y.b));
re = sgn0_big(a);
im = sgn0_big(b);
// y->b != 0 ? sgn0_big(y->b) : sgn0_big(a->a)
sign = 0 - BIG_XXX_iszilch(b);
sign = (re & sign) | (im & ~sign);
// y->a == 0 ? prty(y->b) : prty(a->a)
prty = 0 - BIG_XXX_iszilch(a);
prty = (im & prty) | (re & ~prty);
return (sign & 2) | (prty & 1);
}
int BLS_IETF_ZZZ_compress_G1(octet *bytes, const ECP_ZZZ *point)
{
if (bytes == NULL || point == NULL)
return ERR_NULLPOINTER_BLS;
int sign;
BIG_XXX x;
BIG_XXX y;
if (ECP_ZZZ_isinf(point)) {
for(int i = 0; i < BFS_ZZZ; i++)
bytes->val[i] = 0x00;
bytes->val[0] = 0xc0; // compressed and infinity bits
} else {
if (ECP_ZZZ_get(x, y, point) == -1)
return ERR_NOTONCURVE_BLS;
BIG_XXX_toBytes(bytes->val, x);
sign = sgn0_big(y);
bytes->val[0] |= (unsigned char)(0x80 | ((sign & 2) << 4)); // compressed and not infinity
}
return SUCCESS;
}
int BLS_IETF_ZZZ_uncompress_G1(ECP_ZZZ *point, const octet *bytes)
{
if (bytes == NULL || point == NULL)
return ERR_NULLPOINTER_BLS;
if ((bytes->val[0] & 0x80) == 0x00)
return ERR_BADENCODING_BLS;
int sign;
BIG_XXX a;
BIG_XXX b;
FP_YYY x;
FP_YYY y;
char bytes_prime[BFS_ZZZ];
if (bytes->val[0] & 0x40) {
/**
* Ensure that all bytes are equal to zero
*/
if ((bytes->val[0] & 0x3f) != 0x00)
return ERR_BADENCODING_BLS;
for(int i = 1; i < BFS_ZZZ; i++) {
if ((bytes->val[i]) != 0x00)
return ERR_BADENCODING_BLS;
}
ECP_ZZZ_inf(point);
return SUCCESS;
}
for(int i = 0; i < BFS_ZZZ; i++)
bytes_prime[i] = bytes->val[i];
bytes_prime[0] &= 0x1f; //discard top 3 bits
BIG_XXX_fromBytes(a, bytes_prime);
FP_YYY_nres(&x, a);
ECP_ZZZ_rhs(&y, &x);
FP_YYY_sqrt(&y, &y);
FP_YYY_redc(b, &y);
sign = sgn0_big(b);
sign >>= 1; // discard parity bit
if (sign != ((bytes->val[0] & 0x20) >> 5)) {
FP_YYY_neg(&y, &y);
FP_YYY_redc(b, &y);
}
if (ECP_ZZZ_set(point, a, b) == 0)
return ERR_NOTONCURVE_BLS;
return SUCCESS;
}
int BLS_IETF_ZZZ_compress_G2(octet *bytes, const ECP2_ZZZ *point)
{
if (bytes == NULL || point == NULL)
return ERR_NULLPOINTER_BLS;
int sign;
BIG_XXX b;
FP2_YYY x;
FP2_YYY y;
if (ECP2_ZZZ_isinf(point)) {
for(int i = 1; i < 2*BFS_ZZZ; i++)
bytes->val[i] = 0x00;
bytes->val[0] = 0xc0; // compressed and infinity bits
} else {
if (ECP2_ZZZ_get(&x, &y, point) == -1)
return ERR_NOTONCURVE_BLS;
FP_YYY_redc(b, &(x.b));
BIG_XXX_toBytes(bytes->val, b);
FP_YYY_redc(b, &(x.a));
BIG_XXX_toBytes(bytes->val + BFS_ZZZ, b);
sign = sgn0_fp2(y);
bytes->val[0] |= (unsigned char)(0x80 | ((sign & 2) << 4)); // compressed and not infinity
}
return SUCCESS;
}
int BLS_IETF_ZZZ_uncompress_G2(ECP2_ZZZ *point, const octet *bytes)
{
if (bytes == NULL || point == NULL)
return ERR_NULLPOINTER_BLS;
if ((bytes->val[0] & 0x80) == 0x00)
return ERR_BADENCODING_BLS;
int sign;
BIG_XXX re;
BIG_XXX im;
FP2_YYY x;
FP2_YYY y;
char bytes_prime[2*BFS_ZZZ];
if (bytes->val[0] & 0x40) {
/**
* Ensure that all bytes are equal to zero
*/
if ((bytes->val[0] & 0x3f) != 0x00)
return ERR_BADENCODING_BLS;
for(int i = 1; i < 2*BFS_ZZZ; i++) {
if ((bytes->val[i]) != 0x00)
return ERR_BADENCODING_BLS;
}
ECP2_ZZZ_inf(point);
return SUCCESS;
}
for(int i = 0; i < 2*BFS_ZZZ; i++)
bytes_prime[i] = bytes->val[i];
bytes_prime[0] &= 0x1f; //discard top 3 bits
BIG_XXX_fromBytes(im, bytes_prime);
BIG_XXX_fromBytes(re, bytes_prime + BFS_ZZZ);
FP2_YYY_from_BIGs(&x, re, im);
ECP2_ZZZ_rhs(&y, &x);
FP2_YYY_sqrt(&y, &y);
sign = sgn0_fp2(y);
sign >>= 1; // discard parity bit
if (sign != ((bytes->val[0] & 0x20) >> 5))
FP2_YYY_neg(&y, &y);
if (ECP2_ZZZ_set(point, &x, &y) == 0)
return ERR_NOTONCURVE_BLS;
return SUCCESS;
}
/**
* @brief Calculates the 11-isogeny mapping for BLS12-381 G1.
*
* @param P Output point
* @param x_prime x-coordinate of input point
* @param y_prime y-coordinate of input point
*
* @return 0 if successful, error code otherwise
*/
static int iso11_to_ecp(ECP_ZZZ *P, FP_YYY x_prime, FP_YYY y_prime)
{
if (P == NULL)
return ERR_NULLPOINTER_BLS;
BIG_XXX x;
BIG_XXX y;
FP_YYY k;
FP_YYY xnum;
FP_YYY xden;
FP_YYY ynum;
FP_YYY yden;
FP_YYY_zero(&xnum);
FP_YYY_zero(&ynum);
FP_YYY_copy(&xden, &x_prime);
FP_YYY_copy(&yden, &x_prime);
// x_num = k_(1,11) * x'^11 + k_(1,10) * x'^10 + k_(1,9) * x'^9 + ... + k_(1,0)
for(int i = 11; i > 0; i--) {
FP_YYY_nres(&k, ISO11_XNUM_BLS381[i]);
FP_YYY_add(&xnum, &xnum, &k);
FP_YYY_mul(&xnum, &xnum, &x_prime);
}
FP_YYY_nres(&k, ISO11_XNUM_BLS381[0]);
FP_YYY_add(&xnum, &xnum, &k);
// x_den = x'^10 + k_(2,9) * x'^9 + k_(2,8) * x'^8 + ... + k_(2,0)
for(int i = 9; i > 0; i--) {
FP_YYY_nres(&k, ISO11_XDEN_BLS381[i]);
FP_YYY_add(&xden, &xden, &k);
FP_YYY_mul(&xden, &xden, &x_prime);
}
FP_YYY_nres(&k, ISO11_XDEN_BLS381[0]);
FP_YYY_add(&xden, &xden, &k);
// y_num = k_(3,15) * x'^15 + k_(3,14) * x'^14 + k_(3,13) * x'^13 + ... + k_(3,0)
for(int i = 15; i > 0; i--) {
FP_YYY_nres(&k, ISO11_YNUM_BLS381[i]);
FP_YYY_add(&ynum, &ynum, &k);
FP_YYY_mul(&ynum, &ynum, &x_prime);
}
FP_YYY_nres(&k, ISO11_YNUM_BLS381[0]);
FP_YYY_add(&ynum, &ynum, &k);
// y_den = x'^15 + k_(4,14) * x'^14 + k_(4,13) * x'^13 + ... + k_(4,0)
for(int i = 14; i > 0; i--) {
FP_YYY_nres(&k, ISO11_YDEN_BLS381[i]);
FP_YYY_add(&yden, &yden, &k);
FP_YYY_mul(&yden, &yden, &x_prime);
}
FP_YYY_nres(&k, ISO11_YDEN_BLS381[0]);
FP_YYY_add(&yden, &yden, &k);
// x = x_num / x_den
FP_YYY_inv(&xden, &xden);
FP_YYY_mul(&xnum, &xnum, &xden);
// y = y' * y_num / y_den
FP_YYY_inv(&yden, &yden);
FP_YYY_mul(&ynum, &ynum, &yden);
FP_YYY_mul(&ynum, &ynum, &y_prime);
// P = (x, y)
FP_YYY_redc(x, &xnum);
FP_YYY_redc(y, &ynum);
if (ECP_ZZZ_set(P, x, y) == 0)
return ERR_NOTONCURVE_BLS;
return SUCCESS;
}
/**
* @brief Calculates the 3-isogeny mapping for BLS12-381 G2.
*
* @param P Output point
* @param x_prime x-coordinate of input point
* @param y_prime y-coordinate of input point
*
* @return 0 if successful, error code otherwise
*/
static int iso3_to_ecp(ECP2_ZZZ *P, FP2_YYY x_prime, FP2_YYY y_prime)
{
if (P == NULL)
return ERR_NULLPOINTER_BLS;
FP2_YYY k;
FP2_YYY xnum;
FP2_YYY xden;
FP2_YYY ynum;
FP2_YYY yden;
FP2_YYY_zero(&xnum);
FP2_YYY_zero(&ynum);
FP2_YYY_copy(&yden, &x_prime);
// x_num = k_(1,3) * x'^3 + k_(1,2) * x'^2 + k_(1,1) * x' + k_(1,0)
for(int i = 3; i > 0; i--) {
FP2_YYY_from_BIGs(&k, ISO3_XNUMre_BLS381[i], ISO3_XNUMim_BLS381[i]);
FP2_YYY_add(&xnum, &xnum, &k);
FP2_YYY_mul(&xnum, &xnum, &x_prime);
}
FP2_YYY_from_BIGs(&k, ISO3_XNUMre_BLS381[0], ISO3_XNUMim_BLS381[0]);
FP2_YYY_add(&xnum, &xnum, &k);
// x_den = x'^2 + k_(2,1) * x' + k_(2,0)
FP2_YYY_from_BIGs(&k, ISO3_XDENre_BLS381[1], ISO3_XDENim_BLS381[1]);
FP2_YYY_add(&xden, &x_prime, &k);
FP2_YYY_mul(&xden, &xden, &x_prime);
FP2_YYY_from_BIGs(&k, ISO3_XDENre_BLS381[0], ISO3_XDENim_BLS381[0]);
FP2_YYY_add(&xden, &xden, &k);
// y_num = k_(3,3) * x'^3 + k_(3,2) * x'^2 + k_(3,1) * x' + k_(3,0)
for(int i = 3; i > 0; i--) {
FP2_YYY_from_BIGs(&k, ISO3_YNUMre_BLS381[i], ISO3_YNUMim_BLS381[i]);
FP2_YYY_add(&ynum, &ynum, &k);
FP2_YYY_mul(&ynum, &ynum, &x_prime);
}
FP2_YYY_from_BIGs(&k, ISO3_YNUMre_BLS381[0], ISO3_YNUMim_BLS381[0]);
FP2_YYY_add(&ynum, &ynum, &k);
// y_den = x'^3 + k_(4,2) * x'^2 + k_(4,1) * x' + k_(4,0)
for(int i = 2; i > 0; i--) {
FP2_YYY_from_BIGs(&k, ISO3_YDENre_BLS381[i], ISO3_YDENim_BLS381[i]);
FP2_YYY_add(&yden, &yden, &k);
FP2_YYY_mul(&yden, &yden, &x_prime);
}
FP2_YYY_from_BIGs(&k, ISO3_YDENre_BLS381[0], ISO3_YDENim_BLS381[0]);
FP2_YYY_add(&yden, &yden, &k);
// x = x_num / x_den
FP2_YYY_inv(&xden, &xden);
FP2_YYY_mul(&xnum, &xnum, &xden);
// y = y' * y_num / y_den
FP2_YYY_inv(&yden, &yden);
FP2_YYY_mul(&ynum, &ynum, &yden);
FP2_YYY_mul(&ynum, &ynum, &y_prime);
// P = (x, y)
ECP2_ZZZ_set(P, &xnum, &ynum);
return SUCCESS;
}
/**
* @brief Calculates a point on the elliptic curve E from an element of the finite field F over which E is defined.
* Follows the Simplified SWU for AB == 0 method as defined at
* https://www.ietf.org/archive/id/draft-irtf-cfrg-hash-to-curve-16.html#name-simplified-swu-for-ab-0 (§ 6.6.3)
*
* @param P Output EC point
* @param u Input finite field element
*
* @return 0 if successful, error code otherwise
*/
static int map_to_curve_G1(ECP_ZZZ *P, FP_YYY u)
{
if (P == NULL)
return ERR_NULLPOINTER_BLS;
FP_YYY x;
FP_YYY y;
int ret = SUCCESS;
// (x, y) = map_to_curve_simple_swu(u)
ret |= ECP_ZZZ_sswu(&x, &y, u);
// P = (x, y) = iso_map(x, y)
ret |= iso11_to_ecp(P, x, y);
return ret;
}
/**
* @brief Calculates a point on the elliptic curve from a quadratic extension field element.
* Follows the Simplified SWU for AB == 0 method as defined at
* https://www.ietf.org/archive/id/draft-irtf-cfrg-hash-to-curve-16.html#name-simplified-swu-for-ab-0
*
* @param P Output EC point
* @param u Input finite field element
*
* @return 0 if successful, error code otherwise
*/
static int map_to_curve_G2(ECP2_ZZZ *P, FP2_YYY u)
{
if (P == NULL)
return ERR_NULLPOINTER_BLS;
int ret = SUCCESS;
FP2_YYY x;
FP2_YYY y;
// (x, y) = map_to_curve_simple_swu(u)
ret |= ECP2_ZZZ_sswu(&x, &y, u);
// P = (x, y) = iso_map(x, y)
ret |= iso3_to_ecp(P, x, y);
return ret;
}
int BLS_IETF_ZZZ_hash2curve_G1(ECP_ZZZ *P, const octet *msg, const octet *dst)
{
if (P == NULL || msg == NULL || dst == NULL)
return ERR_NULLPOINTER_BLS;
BIG_XXX elems[2];
FP_YYY u;
ECP_ZZZ Q;
int ret = SUCCESS;
// u = hash_to_field(msg, 2)
ret |= hash_to_field_YYY(elems, 2, 1, msg->val, msg->len, dst->val, dst->len);
// P = map_to_curve(u[0])
FP_YYY_nres(&u, elems[0]);
ret |= map_to_curve_G1(P, u);
// Q = map_to_curve(u[1])
FP_YYY_nres(&u, elems[1]);
ret |= map_to_curve_G1(&Q, u);
// P = P + Q
ECP_ZZZ_add(P, &Q);
// P = clear_cofactor(P)
ECP_ZZZ_mul(P, H_EFF_G1);
return ret;
}
int BLS_IETF_ZZZ_encode2curve_G1(ECP_ZZZ *P, const octet *msg, const octet *dst)
{
if (P == NULL || msg == NULL || dst == NULL)
return ERR_NULLPOINTER_BLS;
BIG_XXX elems;
FP_YYY u;
int ret = SUCCESS;
// u = hash_to_field(msg, 1)
ret |= hash_to_field_YYY(&elems, 1, 1, msg->val, msg->len, dst->val, dst->len);
//P = map_to_curve(u[0])
FP_YYY_nres(&u, elems);
ret |= map_to_curve_G1(P, u);
// P = P = clear_cofactor(P)
ECP_ZZZ_mul(P, H_EFF_G1);
return ret;
}
int BLS_IETF_ZZZ_hash2curve_G2(ECP2_ZZZ *P, const octet *msg, const octet *dst)
{
if (P == NULL || msg == NULL || dst == NULL)
return ERR_NULLPOINTER_BLS;
int ret = SUCCESS;
BIG_XXX elems[4];
FP2_YYY u;
ECP2_ZZZ Q;
// u = hash_to_field(msg, 2)
ret |= hash_to_field_YYY(elems, 2, 2, msg->val, msg->len, dst->val, dst->len);
// P = map_to_curve(u[0])
FP2_YYY_from_BIGs(&u, elems[0], elems[1]);
ret |= map_to_curve_G2(P, u);
// Q = map_to_curve(u[1])
FP2_YYY_from_BIGs(&u, elems[2], elems[3]);
ret |= map_to_curve_G2(&Q, u);
// P = P + Q
ECP2_ZZZ_add(P, &Q);
// P = clear_cofactor(P)
ret |= ECP2_ZZZ_clearcofactor(P);
return ret;
}
int BLS_IETF_ZZZ_encode2curve_G2(ECP2_ZZZ *P, const octet *msg, const octet *dst)
{
if (P == NULL || msg == NULL || dst == NULL)
return ERR_NULLPOINTER_BLS;
int ret = SUCCESS;
BIG_XXX elems[2];
FP2_YYY u;
// u = hash_to_field(msg, 1)
ret |= hash_to_field_YYY(elems, 1, 2, msg->val, msg->len, dst->val, dst->len);
// P = map_to_curve(u[0])
FP2_YYY_from_BIGs(&u, elems[0], elems[1]);
ret |= map_to_curve_G2(P, u);
// P = clear_cofactor(P)
ret |= ECP2_ZZZ_clearcofactor(P);
return ret;
}
int BLS_IETF_ZZZ_core_sign_G1(octet *sig, const char *sk, const octet *msg, const octet *dst)
{
if (sig == NULL || sk == NULL || msg == NULL || dst == NULL)
return ERR_NULLPOINTER_BLS;
BIG_XXX s;
ECP_ZZZ Q;
int ret = SUCCESS;
// s <- SK
BIG_XXX_fromBytesLen(s, sk, SK_LEN);
// Q <- hash_to_point(msg)
ret |= BLS_IETF_ZZZ_hash2curve_G1(&Q, msg, dst);
// Q <- s*Q
PAIR_ZZZ_G1mul(&Q, s);
// sig <- point_to_signature(Q)
ret |= BLS_IETF_ZZZ_compress_G1(sig, &Q);
// zeroization
BIG_XXX_zero(s);
return ret;
}
int BLS_IETF_ZZZ_core_sign_G2(octet *sig, const char *sk, const octet *msg, const octet *dst)
{
if (sig == NULL || sk == NULL || msg == NULL || dst == NULL)
return ERR_NULLPOINTER_BLS;
BIG_XXX s;
ECP2_ZZZ Q;
int ret = SUCCESS;
// s <- SK
BIG_XXX_fromBytesLen(s, sk, SK_LEN);
// Q <- hash_to_point(msg)
ret |= BLS_IETF_ZZZ_hash2curve_G2(&Q, msg, dst);
// Q <- s*Q
PAIR_ZZZ_G2mul(&Q, s);
// sig <- point_to_signature(Q)
ret |= BLS_IETF_ZZZ_compress_G2(sig, &Q);
// zeroization
BIG_XXX_zero(s);
return ret;
}
// TODO: Implement a faster variant based on https://eprint.iacr.org/2019/814
static inline int subgroup_check_G1(ECP_ZZZ P)
{
ECP_ZZZ_mul(&P, CURVE_Order_ZZZ);
return ECP_ZZZ_isinf(&P);
}
// TODO: Implement a faster variant based on https://eprint.iacr.org/2019/814
static inline int subgroup_check_G2(ECP2_ZZZ P)
{
ECP2_ZZZ_mul(&P, CURVE_Order_ZZZ);
return ECP2_ZZZ_isinf(&P);
}
int BLS_IETF_ZZZ_core_verify_G1(const octet *sig, const ECP2_ZZZ *PK, const octet *msg, const octet *dst)
{
if (sig == NULL || PK == NULL || msg == NULL || dst == NULL)
return ERR_NULLPOINTER_BLS;
int ret = SUCCESS;
ECP_ZZZ Q;
ECP_ZZZ R;
ECP2_ZZZ P;
FP12_YYY f;
FP12_YYY acc[ATE_BITS_ZZZ];
// R <- signature_to_point(sig)
ret |= BLS_IETF_ZZZ_uncompress_G1(&R, sig);
if (ret != SUCCESS)
return ERR_BADSIGNATURE_BLS;
if (!subgroup_check_G1(R))
return ERR_NOTONCURVE_BLS;
if(ECP2_ZZZ_isinf(PK) || !subgroup_check_G2(*PK))
return ERR_INVALIDPUBKEY_BLS;
// Q <- hash_to_point(msg)
ret |= BLS_IETF_ZZZ_hash2curve_G1(&Q, msg, dst);
// pairing protocol according to https://eprint.iacr.org/2019/077.pdf
ECP2_ZZZ_generator(&P);
ECP2_ZZZ_neg(&P);
PAIR_ZZZ_initmp(acc);
PAIR_ZZZ_another(acc, &P, &R);
PAIR_ZZZ_another(acc, PK, &Q);
PAIR_ZZZ_miller(&f, acc);
PAIR_ZZZ_fexp(&f);
// ensure that pairing(Q, PK) * pairing(R, -P) == 1
if (!FP12_YYY_isunity(&f))
return ERR_BADSIGNATURE_BLS;
return ret;
}
int BLS_IETF_ZZZ_core_verify_G2(const octet *sig, const ECP_ZZZ *PK, const octet *msg, const octet *dst)
{
if (sig == NULL || PK == NULL || msg == NULL || dst == NULL)
return ERR_NULLPOINTER_BLS;
int ret = SUCCESS;
ECP2_ZZZ Q;
ECP2_ZZZ R;
ECP_ZZZ P;
FP12_YYY f;
FP12_YYY acc[ATE_BITS_ZZZ];
// R <- signature_to_point(sig)
ret |= BLS_IETF_ZZZ_uncompress_G2(&R, sig);
if (ret != SUCCESS)
return ERR_BADSIGNATURE_BLS;
if (!subgroup_check_G2(R))
return ERR_NOTONCURVE_BLS;
if(ECP_ZZZ_isinf(PK) || !subgroup_check_G1(*PK))
return ERR_INVALIDPUBKEY_BLS;
// Q <- hash_to_point(msg)
ret |= BLS_IETF_ZZZ_hash2curve_G2(&Q, msg, dst);
// pairing protocol according to https://eprint.iacr.org/2019/077.pdf
ECP_ZZZ_generator(&P);
ECP_ZZZ_neg(&P);
PAIR_ZZZ_initmp(acc);
PAIR_ZZZ_another(acc, &R, &P);
PAIR_ZZZ_another(acc, &Q, PK);
PAIR_ZZZ_miller(&f, acc);
PAIR_ZZZ_fexp(&f);
// ensure that pairing(Q, PK) * pairing(R, -P) == 1
if (!FP12_YYY_isunity(&f))
return ERR_BADSIGNATURE_BLS;
return ret;
}
int BLS_IETF_ZZZ_aggregate_G1(octet *out, const octet *in, unsigned int n)
{
if (out == NULL || in == NULL)
return ERR_NULLPOINTER_BLS;
if (n == 0)
return ERR_BADARGLEN_BLS;
int ret = SUCCESS;
ECP_ZZZ A;
ECP_ZZZ B;
// A <- signature_to_point(in)
ret |= BLS_IETF_ZZZ_uncompress_G1(&A, in);
if (ret != SUCCESS)
return ERR_BADSIGNATURE_BLS;
for (unsigned int i = 1; i < n; i++) {
// B <- signature_to_point(in + i)
ret |= BLS_IETF_ZZZ_uncompress_G1(&B, in + i);
if (ret != SUCCESS)
return ERR_BADSIGNATURE_BLS;
// A <- A + B
ECP_ZZZ_add(&A, &B);
}
// out <- point_to_signature(A)
ret |= BLS_IETF_ZZZ_compress_G1(out, &A);
return ret;
}
int BLS_IETF_ZZZ_aggregate_G2(octet *out, const octet *in, unsigned int n)
{
if (out == NULL || in == NULL)
return ERR_NULLPOINTER_BLS;
if (n == 0)
return ERR_BADARGLEN_BLS;
int ret = SUCCESS;
ECP2_ZZZ A;
ECP2_ZZZ B;
// A <- signature_to_point(in)
ret |= BLS_IETF_ZZZ_uncompress_G2(&A, in);
if (ret != SUCCESS)
return ERR_BADSIGNATURE_BLS;
for (unsigned int i = 1; i < n; i++) {
// B <- signature_to_point(in + i)
ret |= BLS_IETF_ZZZ_uncompress_G2(&B, in + i);
if (ret != SUCCESS)
return ERR_BADSIGNATURE_BLS;
// A <- A + B
ECP2_ZZZ_add(&A, &B);
}
// out <- point_to_signature(A)
ret |= BLS_IETF_ZZZ_compress_G2(out, &A);
return ret;
}
int BLS_IETF_ZZZ_core_aggregate_verify_G1(const octet *sig, const ECP2_ZZZ PK[], const octet msg[], unsigned int n, const octet *dst)
{
if (sig == NULL || PK == NULL || msg == NULL || dst == NULL)
return ERR_NULLPOINTER_BLS;
if (n == 0)
return ERR_BADARGLEN_BLS;
int ret = SUCCESS;
ECP_ZZZ Q;
ECP_ZZZ R;
ECP2_ZZZ P;
FP12_YYY f;
FP12_YYY acc[ATE_BITS_ZZZ];
// R <- signature_to_point(sig)
ret |= BLS_IETF_ZZZ_uncompress_G1(&R, sig);
if (ret != SUCCESS)
return ERR_BADSIGNATURE_BLS;
if (!subgroup_check_G1(R))
return ERR_NOTONCURVE_BLS;
// initialize the pairing protocol
ECP2_ZZZ_generator(&P);
ECP2_ZZZ_neg(&P);
PAIR_ZZZ_initmp(acc);
PAIR_ZZZ_another(acc, &P, &R);
for (unsigned int i = 0; i < n; i++) {
if(ECP2_ZZZ_isinf(PK + i) || !subgroup_check_G2(PK[i]))
return ERR_INVALIDPUBKEY_BLS;
if (ret != SUCCESS)
return ERR_BADSIGNATURE_BLS;
// Q <- hash_to_point(msg)
ret |= BLS_IETF_ZZZ_hash2curve_G1(&Q, msg + i, dst);
PAIR_ZZZ_another(acc, PK + i, &Q);
}
PAIR_ZZZ_miller(&f, acc);
PAIR_ZZZ_fexp(&f);
if (!FP12_YYY_isunity(&f))
return ERR_BADSIGNATURE_BLS;
return ret;
}
int BLS_IETF_ZZZ_core_aggregate_verify_G2(const octet *sig, const ECP_ZZZ PK[], const octet msg[], unsigned int n, const octet *dst)
{
if (sig == NULL || PK == NULL || msg == NULL || dst == NULL)
return ERR_NULLPOINTER_BLS;
if (n == 0)
return ERR_BADARGLEN_BLS;
int ret = SUCCESS;
ECP2_ZZZ Q;
ECP2_ZZZ R;
ECP_ZZZ P;
FP12_YYY f;
FP12_YYY acc[ATE_BITS_ZZZ];
// R <- signature_to_point(sig)
ret |= BLS_IETF_ZZZ_uncompress_G2(&R, sig);
if (ret != SUCCESS)
return ERR_BADSIGNATURE_BLS;
if (!subgroup_check_G2(R))
return ERR_NOTONCURVE_BLS;
// initialize the pairing protocol
ECP_ZZZ_generator(&P);
ECP_ZZZ_neg(&P);
PAIR_ZZZ_initmp(acc);
PAIR_ZZZ_another(acc, &R, &P);
for (unsigned int i = 0; i < n; i++) {
if(ECP_ZZZ_isinf(PK + i) || !subgroup_check_G1(PK[i]))
return ERR_INVALIDPUBKEY_BLS;
if (ret != SUCCESS)
return ERR_BADSIGNATURE_BLS;
// Q <- hash_to_point(msg)
ret |= BLS_IETF_ZZZ_hash2curve_G2(&Q, msg + i, dst);
PAIR_ZZZ_another(acc, &Q, PK + i);
}
PAIR_ZZZ_miller(&f, acc);
PAIR_ZZZ_fexp(&f);
if (!FP12_YYY_isunity(&f))
return ERR_BADSIGNATURE_BLS;
return ret;
}
int BLS_IETF_ZZZ_pop_prove_G1(octet *proof, const char *sk)
{
if (proof == NULL || sk == NULL)
return ERR_NULLPOINTER_BLS;
int ret = SUCCESS;
BIG_XXX s;
ECP_ZZZ Q;
ECP2_ZZZ PK;
char dst[43] = "BLS_POP_BLS12381G1_XMD:SHA-256_SSWU_RO_POP_";
octet dst_oct = {43, 43, dst};
char pubkey[2*BFS_ZZZ];
octet pk_oct = {2*BFS_ZZZ, 2*BFS_ZZZ, pubkey};
// s <- sk
BIG_XXX_fromBytesLen(s, sk, SK_LEN);
// PK <- SkToPk(sk)
ret |= BLS_IETF_ZZZ_sk_to_pk_G2(&PK, sk);
ret |= BLS_IETF_ZZZ_compress_G2(&pk_oct, &PK);
// Q <- hash_pubkey_to_point(PK)
ret |= BLS_IETF_ZZZ_hash2curve_G1(&Q, &pk_oct, &dst_oct);
// Q <- s*Q
ECP_ZZZ_mul(&Q, s);
// proof <- point_to_signature(Q)
ret |= BLS_IETF_ZZZ_compress_G1(proof, &Q);
// zeroize big variable
BIG_XXX_zero(s);
return ret;
}
int BLS_IETF_ZZZ_pop_prove_G2(octet *proof, const char *sk)
{
if (proof == NULL || sk == NULL)
return ERR_NULLPOINTER_BLS;
int ret = SUCCESS;
BIG_XXX s;
ECP2_ZZZ Q;
ECP_ZZZ PK;
char dst[43] = "BLS_POP_BLS12381G2_XMD:SHA-256_SSWU_RO_POP_";
octet dst_oct = {43, 43, dst};
char pubkey[BFS_ZZZ];
octet pk_oct = {BFS_ZZZ, BFS_ZZZ, pubkey};
// s <- sk
BIG_XXX_fromBytesLen(s, sk, SK_LEN);
// PK <- SkToPk(sk)
ret |= BLS_IETF_ZZZ_sk_to_pk_G1(&PK, sk);
ret |= BLS_IETF_ZZZ_compress_G1(&pk_oct, &PK);
// Q <- hash_pubkey_to_point(PK)
ret |= BLS_IETF_ZZZ_hash2curve_G2(&Q, &pk_oct, &dst_oct);
// Q <- s*Q
ECP2_ZZZ_mul(&Q, s);
// proof <- point_to_signature(Q)
ret |= BLS_IETF_ZZZ_compress_G2(proof, &Q);
// zeroize big variable
BIG_XXX_zero(s);
return ret;
}
int BLS_IETF_ZZZ_pop_verify_G1(const octet *proof, const ECP2_ZZZ *PK)
{
if (proof == NULL || PK == NULL)
return ERR_NULLPOINTER_BLS;
int ret = SUCCESS;
ECP_ZZZ Q;
ECP_ZZZ R;
ECP2_ZZZ P;
FP12_YYY f;
FP12_YYY acc[ATE_BITS_ZZZ];
char dst[43] = "BLS_POP_BLS12381G1_XMD:SHA-256_SSWU_RO_POP_";
octet dst_oct = {43, 43, dst};
char pubkey[2*BFS_ZZZ];
octet pk_oct = {2*BFS_ZZZ, 2*BFS_ZZZ, pubkey};
// R <- signature_to_point(proof)
ret |= BLS_IETF_ZZZ_uncompress_G1(&R, proof);
if (ret != SUCCESS)
return ERR_BADPOP_BLS;
if (!subgroup_check_G1(R))
return ERR_NOTONCURVE_BLS;
if(ECP2_ZZZ_isinf(PK) || !subgroup_check_G2(*PK))
return ERR_INVALIDPUBKEY_BLS;
// Q <- hash_pubkey_to_point(PK)
ret |= BLS_IETF_ZZZ_compress_G2(&pk_oct, PK);
ret |= BLS_IETF_ZZZ_hash2curve_G1(&Q, &pk_oct, &dst_oct);
// pairing protocol according to https://eprint.iacr.org/2019/077.pdf
ECP2_ZZZ_generator(&P);
ECP2_ZZZ_neg(&P);
PAIR_ZZZ_initmp(acc);
// accumulate 1st pairing(R, -P)
PAIR_ZZZ_another(acc, &P, &R);
// accumulate 2nd pairing(Q, PK)
PAIR_ZZZ_another(acc, PK, &Q);
// combined Miller loop calculation
PAIR_ZZZ_miller(&f, acc);
// final exponentiation
PAIR_ZZZ_fexp(&f);
// ensure that pairing(Q, PK) * pairing(R, -P) == 1
if (!FP12_YYY_isunity(&f))
return ERR_BADPOP_BLS;
return ret;
}
int BLS_IETF_ZZZ_pop_verify_G2(const octet *proof, const ECP_ZZZ *PK)
{
if (proof == NULL || PK == NULL)
return ERR_NULLPOINTER_BLS;
int ret = SUCCESS;
ECP2_ZZZ Q;
ECP2_ZZZ R;
ECP_ZZZ P;
FP12_YYY f;
FP12_YYY acc[ATE_BITS_ZZZ];
char dst[43] = "BLS_POP_BLS12381G2_XMD:SHA-256_SSWU_RO_POP_";
octet dst_oct = {43, 43, dst};
char pubkey[BFS_ZZZ];
octet pk_oct = {BFS_ZZZ, BFS_ZZZ, pubkey};
// R <- signature_to_point(proof)
ret |= BLS_IETF_ZZZ_uncompress_G2(&R, proof);
if (ret != SUCCESS)
return ERR_BADPOP_BLS;
if (!subgroup_check_G2(R))
return ERR_NOTONCURVE_BLS;
if(ECP_ZZZ_isinf(PK) || !subgroup_check_G1(*PK))
return ERR_INVALIDPUBKEY_BLS;
// Q <- hash_pubkey_to_point(PK)
ret |= BLS_IETF_ZZZ_compress_G1(&pk_oct, PK);
ret |= BLS_IETF_ZZZ_hash2curve_G2(&Q, &pk_oct, &dst_oct);
// pairing protocol according to https://eprint.iacr.org/2019/077.pdf
ECP_ZZZ_generator(&P);
ECP_ZZZ_neg(&P);
PAIR_ZZZ_initmp(acc);
// accumulate 1st pairing(R, -P)
PAIR_ZZZ_another(acc, &R, &P);
// accumulate 2nd pairing(Q, PK)
PAIR_ZZZ_another(acc, &Q, PK);
// combined Miller loop calculation
PAIR_ZZZ_miller(&f, acc);
// final exponentiation
PAIR_ZZZ_fexp(&f);
// ensure that pairing(Q, PK) * pairing(R, -P) == 1
if (!FP12_YYY_isunity(&f))
return ERR_BADPOP_BLS;
return ret;
}
int BLS_IETF_ZZZ_fast_aggregate_verify_G1(const octet *sig, const ECP2_ZZZ PK[], const octet *msg, unsigned int n, const octet *dst)
{
if (PK == NULL || msg == NULL || dst == NULL)
return ERR_NULLPOINTER_BLS;
if (n == 0)
return ERR_BADARGLEN_BLS;
ECP2_ZZZ A;
// aggregate <- pubkey_to_point(PK_1)
ECP2_ZZZ_copy(&A, PK);
// aggregate <- aggregate + pubkey_to_point(PK_i)
for (unsigned int i = 1; i < n; i++)
ECP2_ZZZ_add(&A, PK + i);
// return CoreVerify(A, message, signature)
return BLS_IETF_ZZZ_core_verify_G1(sig, &A, msg, dst);
}
int BLS_IETF_ZZZ_fast_aggregate_verify_G2(const octet *sig, const ECP_ZZZ PK[], const octet *msg, unsigned int n, const octet *dst)
{
if (PK == NULL || msg == NULL || dst == NULL)
return ERR_NULLPOINTER_BLS;
if (n == 0)
return ERR_BADARGLEN_BLS;
ECP_ZZZ A;
// aggregate <- pubkey_to_point(PK_1)
ECP_ZZZ_copy(&A, PK);
// aggregate <- aggregate + pubkey_to_point(PK_i)
for (unsigned int i = 1; i < n; i++)
ECP_ZZZ_add(&A, PK + i);
// return CoreVerify(A, message, signature)
return BLS_IETF_ZZZ_core_verify_G2(sig, &A, msg, dst);
}