Skip to content

Latest commit

 

History

History
910 lines (744 loc) · 28.1 KB

api.md

File metadata and controls

910 lines (744 loc) · 28.1 KB

C/C++ API

Minimum sample

A sample of how to use BLS12-381:

C

sample/pairing_c.c

cd mcl
make -j4
make bin/pairing_c.exe && bin/pairing_c.exe

C++

sample/pairing.cpp

cd mcl
make -j4
make bin/pairing.exe && bin/pairing.exe

Header and libraries

C

To use BLS12-381, include <mcl/bn_c384_256.h> and link

  • libmclbn384_256.{a,so}
  • libmcl.{a,so} ; core library

384_256 means the max bit size of Fp is 384, and that size of Fr is 256.

C++

include <mcl/bls12_381.hpp> and link

  • libmcl.{a,so} ; core library

Notation

The elliptic equation of a curve E is E: y^2 = x^3 + b.

  • Fp ; a finite field of a prime order p, where a curve is defined over.
  • Fr ; a finite field of a prime order r.
  • Fp2 ; the field extension over Fp with degree 2. Fp[i] / (i^2 + 1).
  • Fp6 ; the field extension over Fp2 with degree 3. Fp2[v] / (v^3 - Xi) where Xi = i + 1.
  • Fp12 ; the field extension over Fp6 with degree 2. Fp6[w] / (w^2 - v).
  • G1 ; the cyclic subgroup of E(Fp).
  • G2 ; the cyclic subgroup of the inverse image of E'(Fp^2) under a twisting isomorphism from E' to E.
  • GT ; the cyclic subgroup of Fp12.
    • G1, G2, and GT have the order r.

The pairing e: G1 x G2 -> GT is the optimal ate pairing.

mcl treats G1 and G2 as an additive group and GT as a multiplicative group.

  • mclSize ; unsigned int if WebAssembly else size_t

Curve Parameter

r = |G1| = |G2| = |GT|

curveType b r and p
BN254 2 r = 0x2523648240000001ba344d8000000007ff9f800000000010a10000000000000d
p = 0x2523648240000001ba344d80000000086121000000000013a700000000000013
BN_SNARK1 3 r = 0x30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001
p = 0x30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47
BLS12-381 4 r = 0x73eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000001
p = 0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaaab
BN381 2 r = 0x240026400f3d82b2e42de125b00158405b710818ac000007e0042f008e3e00000000001080046200000000000000000d
p = 0x240026400f3d82b2e42de125b00158405b710818ac00000840046200950400000000001380052e000000000000000013

C Structures

mclBnFp

This is a struct of Fp. The value is stored as a Montgomery representation.

mclBnFr

This is a struct of Fr. The value is stored as a Montgomery representation.

mclBnFp2

This is a struct of Fp2 with a member mclBnFp d[2].

An element x of Fp2 is represented as x = d[0] + d[1] i where i^2 = -1.

mclBnG1

This is a struct of G1 with three members x, y, z of type mclBnFp.

An element P of G1 is represented as P = [x:y:z] of a Jacobi coordinate.

mclBnG2

This is a struct of G2 with three members x, y, z of type mclBnFp2.

An element Q of G2 is represented as Q = [x:y:z] of a Jacobi coordinate.

mclBnGT

This is a struct of GT with a member mclBnFp d[12].

C++ Structures

The namespace is mcl::bn.

Fp

This is a class of Fp.

Fr

This is a class of Fr.

Fp2

This is a struct of Fp2 with a member a and b of type Fp.

An element x of Fp2 is represented as x = a + b i where i^2 = -1.

Fp6

This is a struct of Fp6 with a member a, b, and c of type Fp2.

An element x of Fp6 is represented as x = a + b v + c v^2 where v^3 = xi := 1 + i.

Fp12

This is a struct of Fp12 with a member a and b of type Fp6.

An element x of Fp12 is represented as x = a + b w where w^2 = v.

G1

This is a struct of G1 with three members x, y, z of type Fp.

An element P of G1 is represented as P = [x:y:z] of a Jacobi coordinate.

G2

This is a struct of G2 with three members x, y, z of type Fp2.

An element Q of G2 is represented as Q = [x:y:z] of a Jacobi coordinate.

GT

GT is an alias of Fp12. But it means a set { x in Fp12 | x^r = 1}.

sizeof

library MCLBN_FR_UNIT_SIZE MCLBN_FP_UNIT_SIZE sizeof Fr sizeof Fp
libmclbn256.a 4 4 32 32
libmclbn384_256.a 4 6 32 48
libmclbn384.a 6 6 48 48

Thread safety

All functions except for initialization and changing global settings are thread-safe.

Initialization

C

Initialize mcl library. Call this function at first before calling the other functions.

int mclBn_init(int curve, int compiledTimeVar);
  • curve ; specify the curve type
    • MCL_BN254 ; BN254 (a little faster if including mcl/bn_c256.h and linking libmclbn256.{a,so})
    • MCL_BN_SNARK1 ; the same parameter used in libsnark
    • MCL_BLS12_381 ; BLS12-381
    • MCL_BN381_1 ; BN381 (include mcl/bn_c384.h and link libmclbn384.{a,so})
  • compiledTimeVar ; set MCLBN_COMPILED_TIME_VAR, which macro is used to make sure that the values are the same when the library is built and used.
  • return 0 if success.
  • This is not thread safe.

C++

void initPairing(<curve type>);

curve type is defined in mcl/curve_type.h.

  • BN254
  • BN_SNARK1
  • BN381_1
  • BLS12_381

Global setting

int mclBn_setMapToMode(int mode);
  • mode = MCL_MAP_TO_MODE_ORIGINAL : the old hash-to-curve (for backward compatibility)
  • mode = MCL_MAP_TO_MODE_HASH_TO_CURVE : the hash-to-curve defined in Hashing to Elliptic Curves

Control to verify that a point of the elliptic curve has the order r.

This function affects setStr() and deserialize() for G1/G2.

C

void mclBn_verifyOrderG1(int doVerify);
void mclBn_verifyOrderG2(int doVerify);

C++

verifyOrderG1(bool doVerify);
verifyOrderG2(bool doVerify);
  • verify if doVerify is 1 or does not. The default parameter is 0 because the cost of verification is not small.
  • Set doVerify = 1 if considering subgroup attack is necessary.
  • This is not thread-safe.

Set DST for hash functions

C

int mclBnG1_setDst(const char *dst, mclSize dstSize);
int mclBnG2_setDst(const char *dst, mclSize dstSize);

return 0 if success else -1

C++

bool setDstG1(const char *dst, size_t dstSize);
bool setDstG2(const char *dst, size_t dstSize);

return true if success else false

  • set dst[0, dstSize) to the DST for hash functions
  • The default value:
    • G1 : BLS_SIG_BLS12381G1_XMD:SHA-256_SSWU_RO_POP_
    • G2 : BLS_SIG_BLS12381G2_XMD:SHA-256_SSWU_RO_POP_

Setter / Getter

Clear

Set x is zero.

void mclBnFr_clear(mclBnFr *x);
void mclBnFp_clear(mclBnFp *x);
void mclBnFp2_clear(mclBnFp2 *x);
void mclBnG1_clear(mclBnG1 *x);
void mclBnG2_clear(mclBnG2 *x);
void mclBnGT_clear(mclBnGT *x);

C++

T::clear();

Set x to y.

void mclBnFp_setInt(mclBnFp *y, mclInt x);
void mclBnFr_setInt(mclBnFr *y, mclInt x);
void mclBnGT_setInt(mclBnGT *y, mclInt x);

C++

T x = <integer literal>;

Set bufSize bytes buf to x with masking according to the following way.

int mclBnFp_setLittleEndian(mclBnFp *x, const void *buf, mclSize bufSize);
int mclBnFr_setLittleEndian(mclBnFr *x, const void *buf, mclSize bufSize);

C++

T::setArrayMask(const uint8_t *buf, size_t n);
  1. set x = buf[0..bufSize-1] as little endian
  2. x &= (1 << bitLen(r)) - 1
  3. if (x >= r) x &= (1 << (bitLen(r) - 1)) - 1
  • always return 0

Set bufSize bytes buf of mod p or r to x.

int mclBnFp_setLittleEndianMod(mclBnFp *x, const void *buf, mclSize bufSize);
int mclBnFr_setLittleEndianMod(mclBnFr *x, const void *buf, mclSize bufSize);

C++

T::setLittleEndianMod(const uint8_t *buf, mclSize bufSize);
  • return 0 if bufSize <= (sizeof(T) * 2) else -1

Get little-endian byte sequence buf corresponding to x

mclSize mclBnFr_getLittleEndian(void *buf, mclSize maxBufSize, const mclBnFr *x);
mclSize mclBnFp_getLittleEndian(void *buf, mclSize maxBufSize, const mclBnFp *x);

C++

size_t T::getLittleEndian(uint8_t *buf, size_t maxBufSize) const
  • write x to buf as little endian
  • return the written size if sucess else 0
  • NOTE: buf[0] = 0 and return 1 if x is zero.

Serialization

Serialize

mclSize mclBnFr_serialize(void *buf, mclSize maxBufSize, const mclBnFr *x);
mclSize mclBnG1_serialize(void *buf, mclSize maxBufSize, const mclBnG1 *x);
mclSize mclBnG2_serialize(void *buf, mclSize maxBufSize, const mclBnG2 *x);
mclSize mclBnGT_serialize(void *buf, mclSize maxBufSize, const mclBnGT *x);
mclSize mclBnFp_serialize(void *buf, mclSize maxBufSize, const mclBnFp *x);
mclSize mclBnFp2_serialize(void *buf, mclSize maxBufSize, const mclBnFp2 *x);

C++

mclSize T::serialize(void *buf, mclSize maxBufSize) const;
  • serialize x into buf[0..maxBufSize-1]
  • return written byte size if success else 0

Serialization format

  • Fp(resp. Fr) ; a little endian byte sequence with a fixed size
    • the size is the return value of mclBn_getFpByteSize() (resp. mclBn_getFpByteSize()).
  • G1 ; a compressed fixed size
    • the size is equal to mclBn_getG1ByteSize() (=mclBn_getFpByteSize()).
  • G2 ; a compressed fixed size
    • the size is equal to mclBn_getG2ByteSize().

A pseudo-code to serialize P of G1 (resp. G2):

size = mclBn_getG1ByteSize() # resp. mclBn_getG2ByteSize()
if P is zero:
  return [0] * size
else:
  P = P.normalize()
  s = P.x.serialize()
  # x in Fp2 is odd <=> x.a is odd
  if Fp is fullBit:
    s[byte-length(s)] = P.y is odd ? 3 : 2
  elif P.y is odd: # resp. P.y.d[0] is odd
    s[byte-length(s) - 1] |= 0x80
  return s

Ethereum serialization mode for BLS12-381

void mclBn_setETHserialization(int ETHserialization);
  • Set ETHserialization = 1 for Ethereum compatibility (default 0).
  • See FAQ.

Deserialize

mclSize mclBnFr_deserialize(mclBnFr *x, const void *buf, mclSize bufSize);
mclSize mclBnG1_deserialize(mclBnG1 *x, const void *buf, mclSize bufSize);
mclSize mclBnG2_deserialize(mclBnG2 *x, const void *buf, mclSize bufSize);
mclSize mclBnGT_deserialize(mclBnGT *x, const void *buf, mclSize bufSize);
mclSize mclBnFp_deserialize(mclBnFp *x, const void *buf, mclSize bufSize);
mclSize mclBnFp2_deserialize(mclBnFp2 *x, const void *buf, mclSize bufSize);

C++

mclSize T::deserialize(const void *buf, mclSize bufSize);
  • deserialize x from buf[0..bufSize-1]
  • return read size if success else 0
    • mclBnG1_deserialize and mclBnG2_deserialize check whether the point has the correct order of G1/G2.
    • mclBnGT_deserialize does not check it. Call mclBnGT_isValid if necessary.

String conversion

Get string

mclSize mclBnFr_getStr(char *buf, mclSize maxBufSize, const mclBnFr *x, int ioMode);
mclSize mclBnG1_getStr(char *buf, mclSize maxBufSize, const mclBnG1 *x, int ioMode);
mclSize mclBnG2_getStr(char *buf, mclSize maxBufSize, const mclBnG2 *x, int ioMode);
mclSize mclBnGT_getStr(char *buf, mclSize maxBufSize, const mclBnGT *x, int ioMode);
mclSize mclBnFp_getStr(char *buf, mclSize maxBufSize, const mclBnFp *x, int ioMode);

C++

size_t T::getStr(char *buf, size_t maxBufSize, int iMode = 0) const
  • write x to buf according to ioMode
  • ioMode
    • 2 ; binary number
    • 10 ; decimal number
    • 16 ; hexadecimal number
    • MCLBN_IO_EC_PROJ ; output as Jacobi coordinate
  • return strlen(buf) if success else 0.

The meaning of the output of G1:

  • 0 ; infinity
  • 1 <x> <y> ; affine coordinate
  • 4 <x> <y> <z> ; Jacobi coordinate
  • the element <x> of G2 outputs d[0] d[1].

Set string

int mclBnFr_setStr(mclBnFr *x, const char *buf, mclSize bufSize, int ioMode);
int mclBnG1_setStr(mclBnG1 *x, const char *buf, mclSize bufSize, int ioMode);
int mclBnG2_setStr(mclBnG2 *x, const char *buf, mclSize bufSize, int ioMode);
int mclBnGT_setStr(mclBnGT *x, const char *buf, mclSize bufSize, int ioMode);
int mclBnFp_setStr(mclBnFp *x, const char *buf, mclSize bufSize, int ioMode);

C++

void T::setStr(bool *pb, const char *str, int iMode = 0)
void T::setStr(const char *str, int iMode = 0)
  • set buf[0..bufSize-1] to x accoring to ioMode
    • mask and truncate the value if it is greater than (r or p).
    • See masking
  • deny too large bufSize. The maximum length depends on compile options, but at least the bit length of the type of x.
  • The set string of G1/G2 fails if the point is not on the elliptic curve.
    • And check whether the point has the valid order of G1/G2(default).
    • You can disable this check by mclBn_verifyOrderG1/G2(0).
  • return 0 if success else -1
    • *pb = result of setStr or throw exception if error (C++)
    • mclBnG1_setStr and mclBnG2_setStr check whether the point has the correct order of G1/G2.
    • mclBnGT_setStr does not check it. Call mclBnGT_isValid if necessary.

If you want to use the same BLS12-381 generator as zkcrypto then,

mclBnG1 P;
const char *g1Str = "1 0x17f1d3a73197d7942695638c4fa9ac0fc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb 0x08b3f481e3aaa0f1a09e30ed741d8ae4fcf5e095d5d00af600db18cb2c04b3edd03cc744a2888ae40caa232946c5e7e1";
mclBnG1_setStr(&P, g1Str, strlen(g1Str), 16);

mclBnG2 Q;
const char *g2Str = "1 0x24aa2b2f08f0a91260805272dc51051c6e47ad4fa403b02b4510b647ae3d1770bac0326a805bbefd48056c8c121bdb8 0x13e02b6052719f607dacd3a088274f65596bd0d09920b61ab5da61bbdc7f5049334cf11213945d57e5ac7d055d042b7e 0x0ce5d527727d6e118cc9cdc6da2e351aadfd9baa8cbdd3a76d429a695160d12c923ac9cc3baca289e193548608b82801 0x0606c4a02ea734cc32acd2b02bc28b99cb3e287e85a763af267492ab572e99ab3f370d275cec1da1aaa9075ff05f79be";
mclBnG2_setStr(&Q, g2Str, strlen(g2Str), 16);

Set a random value

Set x by a cryptographically secure pseudo-random number generator.

int mclBnFr_setByCSPRNG(mclBnFr *x);
int mclBnFp_setByCSPRNG(mclBnFp *x);

C++

void T::setByCSPRNG()

Change random generator function

void mclBn_setRandFunc(
  void *self,
  unsigned int (*readFunc)(void *self, void *buf, unsigned int bufSize)
);
  • self ; user-defined pointer
  • readFunc ; user-defined function, which writes random bufSize bytes to buf and returns bufSize if success else returns 0.
    • readFunc must be thread-safe.
  • Set the default random function if self == 0 and readFunc == 0.
  • This is not thread-safe.

Arithmetic operations

neg / inv / sqr / add / sub / mul / div of Fr, Fp, Fp2, GT.

void mclBnFr_neg(mclBnFr *y, const mclBnFr *x);
void mclBnFr_inv(mclBnFr *y, const mclBnFr *x);
// y[i] = 1/x[i] if x[i] != 0 else 0
// faster than normalizing each one individually
void mclBnFr_invVec(mclBnFr *y, const mclBnFr *x, mclSize n);
void mclBnFr_sqr(mclBnFr *y, const mclBnFr *x);
void mclBnFr_add(mclBnFr *z, const mclBnFr *x, const mclBnFr *y);
void mclBnFr_sub(mclBnFr *z, const mclBnFr *x, const mclBnFr *y);
void mclBnFr_mul(mclBnFr *z, const mclBnFr *x, const mclBnFr *y);
void mclBnFr_div(mclBnFr *z, const mclBnFr *x, const mclBnFr *y);

void mclBnFp_neg(mclBnFp *y, const mclBnFp *x);
void mclBnFp_inv(mclBnFp *y, const mclBnFp *x);
void mclBnFp_invVec(mclBnFp *y, const mclBnFp *x, mclSize n);
void mclBnFp_sqr(mclBnFp *y, const mclBnFp *x);
void mclBnFp_add(mclBnFp *z, const mclBnFp *x, const mclBnFp *y);
void mclBnFp_sub(mclBnFp *z, const mclBnFp *x, const mclBnFp *y);
void mclBnFp_mul(mclBnFp *z, const mclBnFp *x, const mclBnFp *y);
void mclBnFp_div(mclBnFp *z, const mclBnFp *x, const mclBnFp *y);

void mclBnFp2_neg(mclBnFp2 *y, const mclBnFp2 *x);
void mclBnFp2_inv(mclBnFp2 *y, const mclBnFp2 *x);
void mclBnFp2_sqr(mclBnFp2 *y, const mclBnFp2 *x);
void mclBnFp2_add(mclBnFp2 *z, const mclBnFp2 *x, const mclBnFp2 *y);
void mclBnFp2_sub(mclBnFp2 *z, const mclBnFp2 *x, const mclBnFp2 *y);
void mclBnFp2_mul(mclBnFp2 *z, const mclBnFp2 *x, const mclBnFp2 *y);
void mclBnFp2_div(mclBnFp2 *z, const mclBnFp2 *x, const mclBnFp2 *y);

void mclBnGT_inv(mclBnGT *y, const mclBnGT *x); // y = a - bw for x = a + bw where Fp12 = Fp6[w]
void mclBnGT_sqr(mclBnGT *y, const mclBnGT *x);
void mclBnGT_mul(mclBnGT *z, const mclBnGT *x, const mclBnGT *y);
void mclBnGT_div(mclBnGT *z, const mclBnGT *x, const mclBnGT *y);
  • use mclBnGT_invGeneric for an element in Fp12 - GT.

  • NOTE: The following functions do NOT return a GT element because GT is a multiplicative group.

void mclBnGT_neg(mclBnGT *y, const mclBnGT *x);
void mclBnGT_add(mclBnGT *z, const mclBnGT *x, const mclBnGT *y);
void mclBnGT_sub(mclBnGT *z, const mclBnGT *x, const mclBnGT *y);

C++

  • +, -, *, /
T::add(T& z, const T& x, const T& y);
T::sub(T& z, const T& x, const T& y);
T::mul(T& z, const T& x, const T& y);
T::div(T& z, const T& x, const T& y);
T::neg(T& y, const T& x);
T::inv(T& y, const T& x);
// y[i] = 1/x[i] if x[i] != 0 else 0
mcl::invVec(T y[], const T x[], size_t n);

pow of Fr, Fp

  • pow(z, x, y) means z = x^y.
  • powArray(z, x, y, ySize) means z = x^y where y is a little endian ySize-byte sequence.
// z = x^y
void mclBnFp_pow(mclBnFp *z, const mclBnFp *x, const mclBnFp *y);
void mclBnFr_pow(mclBnFr *z, const mclBnFr *x, const mclBnFr *y);

// return 0 if ySize <= mclBn_getFrByteSize() else -1
int mclBnFr_powArray(mclBnFr *z, const mclBnFr *x, const uint8_t *y, mclSize ySize);
// return 0 if ySize <= mclBn_getFpByteSize() else -1
int mclBnFp_powArray(mclBnFp *z, const mclBnFp *x, const uint8_t *y, mclSize ySize);

Square root of x.

int mclBnFr_squareRoot(mclBnFr *y, const mclBnFr *x);
int mclBnFp_squareRoot(mclBnFp *y, const mclBnFp *x);
int mclBnFp2_squareRoot(mclBnFp2 *y, const mclBnFp2 *x);

C++

bool T::squareRoot(T& y, const T& x);
  • y is one of a square root of x if y exists.
  • return 0 if success else -1

add / sub / dbl / neg for G1 and G2.

void mclBnG1_neg(mclBnG1 *y, const mclBnG1 *x);
void mclBnG1_dbl(mclBnG1 *y, const mclBnG1 *x);
void mclBnG1_add(mclBnG1 *z, const mclBnG1 *x, const mclBnG1 *y);
void mclBnG1_sub(mclBnG1 *z, const mclBnG1 *x, const mclBnG1 *y);

void mclBnG2_neg(mclBnG2 *y, const mclBnG2 *x);
void mclBnG2_dbl(mclBnG2 *y, const mclBnG2 *x);
void mclBnG2_add(mclBnG2 *z, const mclBnG2 *x, const mclBnG2 *y);
void mclBnG2_sub(mclBnG2 *z, const mclBnG2 *x, const mclBnG2 *y);

C++

  • +, -
    • T::add(T& z, const T& x, const T& y);
    • T::sub(T& z, const T& x, const T& y);
    • T::neg(T& y, const T& x);

Convert a point from Jacobi/Projective coordinate to affine.

void mclBnG1_normalize(mclBnG1 *y, const mclBnG1 *x);
void mclBnG2_normalize(mclBnG2 *y, const mclBnG2 *x);

// y[i] = normalize(x[i]) for i = 0, 1, ..., n-1
// faster than normalizing each one individually
void mclBnG1_normalizeVec(mclBnG1 *y, const mclBnG1 *x, mclSize n);
void mclBnG2_normalizeVec(mclBnG2 *y, const mclBnG2 *x, mclSize n);

C++

T::normalize(T& y, const T& x);
T::normalizeVec(T& y[n], const T& x[n], size_t n);
  • convert [x:y:z] to [x:y:1] if z != 0 else [*:*:0]

scalar multiplication

void mclBnG1_mul(mclBnG1 *z, const mclBnG1 *x, const mclBnFr *y);
void mclBnG2_mul(mclBnG2 *z, const mclBnG2 *x, const mclBnFr *y);
void mclBnGT_pow(mclBnGT *z, const mclBnGT *x, const mclBnFr *y);

C++

T::mul(const T& z, const T& x, const Fr& y);
  • z = x * y for G1 / G2

  • z = pow(x, y) for GT

  • use mclBnGT_powGeneric for an element in Fp12 - GT.

multi-scalar multiplication

void mclBnG1_mulVec(mclBnG1 *z, mclBnG1 *x, const mclBnFr *y, mclSize n);
void mclBnG2_mulVec(mclBnG2 *z, mclBnG2 *x, const mclBnFr *y, mclSize n);
void mclBnGT_powVec(mclBnGT *z, const mclBnGT *x, const mclBnFr *y, mclSize n);

C++

T::mulVec(T& z, T* x, const Fr *y, size_t n);
  • z = sum_{i=0}^{n-1} mul(x[i], y[i]) for G1 / G2.
  • z = prod_{i=0}^{n-1} pow(x[i], y[i]) for GT.
  • x[] does not const because they may be normailzed (The value does not change).

scalar multiplication of each point

void mclBnG1_mulEach(mclBnG1 *x, const mclBnFr *y, mclSize n);

C++

G1::mulEach(G1 *xVec, const Fr *yVec, size_t n);
  • xVec[i] *= yVec[i]
  • G1::mulVec and G1::mulEach for BLS12-381 use AVX-512 IFMA if possible

hash-to-curve function

Set hash of buf[0..bufSize-1] to x

int mclBnFr_setHashOf(mclBnFr *x, const void *buf, mclSize bufSize);
int mclBnFp_setHashOf(mclBnFp *x, const void *buf, mclSize bufSize);

C++

T::setHashOf(const void *msg, size_t msgSize);
  • always return 0
  • use SHA-256 if sizeof(*x) <= 256 else SHA-512
  • set according to the same way as setLittleEndian.
  • This is a function for backward compatibility only. DO'NT use it. Instead of this, use setLittleEndianMod to the hashed value.

map x to G1 / G2.

int mclBnFp_mapToG1(mclBnG1 *y, const mclBnFp *x);
int mclBnFp2_mapToG2(mclBnG2 *y, const mclBnFp2 *x);

C++

void mapToG1(G1& P, const Fp& x);
void mapToG2(G2& P, const Fp2& x);
  • See struct MapTo in mcl/bn.hpp for the detail of the algorithm.
  • return 0 if success else -1

If you want to use the MapTo function defined in Hashing to Elliptic Curves, then use mclBn_seMapToMode.

mclBn_setMapToMode(MCL_MAP_TO_MODE_HASH_TO_CURVE);

And if you want to change DST (domain separation tag), then use setDst functions.

int mclBnG1_setDst(const char *dst, mclSize dstSize);
int mclBnG2_setDst(const char *dst, mclSize dstSize);

hash and map to G1 / G2.

int mclBnG1_hashAndMapTo(mclBnG1 *x, const void *buf, mclSize bufSize);
int mclBnG2_hashAndMapTo(mclBnG2 *x, const void *buf, mclSize bufSize);

C++

void hashAndMapToG1(G1& P, const void *buf, size_t bufSize);
void hashAndMapToG2(G2& P, const void *buf, size_t bufSize);
  • Combine setHashOf and mapTo functions

Pairing operations

The pairing function e(P, Q) is consist of two parts:

  • MillerLoop(P, Q)
  • finalExp(x)

finalExp satisfies the following properties:

  • e(P, Q) = finalExp(MillerLoop(P, Q))
  • e(P1, Q1) e(P2, Q2) = finalExp(MillerLoop(P1, Q1) MillerLoop(P2, Q2))

pairing

void mclBn_pairing(mclBnGT *z, const mclBnG1 *x, const mclBnG2 *y);

C++

void pairing(GT& z, const G1& x, const G2& y);

millerLoop

void mclBn_millerLoop(mclBnGT *z, const mclBnG1 *x, const mclBnG2 *y);

C++

void millerLoop(GT& z, const G1& x, const G2& y);

finalExp

void mclBn_finalExp(mclBnGT *y, const mclBnGT *x);

C++

void finalExp(GT& y, const GT& x);

Variants of MillerLoop

multi pairing

void mclBn_millerLoopVec(mclBnGT *z, const mclBnG1 *x, const mclBnG2 *y, mclSize n);

C++

void millerLoopVec(GT& z, const G1 *x, const G2 *y, size_t n);
  • This function is for multi-pairing
    • computes prod_{i=0}^{n-1} MillerLoop(x[i], y[i])
    • prod_{i=0}^{n-1} e(x[i], y[i]) = finalExp(prod_{i=0}^{n-1} MillerLoop(x[i], y[i]))

pairing for a fixed point of G2

int mclBn_getUint64NumToPrecompute(void);
void mclBn_precomputeG2(uint64_t *Qbuf, const mclBnG2 *Q);
void mclBn_precomputedMillerLoop(mclBnGT *f, const mclBnG1 *P, const uint64_t *Qbuf);

These functions is the same computation of pairing(P, Q); as the followings:

uint64_t *Qbuf = (uint64_t*)malloc(mclBn_getUint64NumToPrecompute() * sizeof(uint64_t));
mclBn_precomputeG2(Qbuf, Q); // precomputing of Q
mclBn_precomputedMillerLoop(f, P, Qbuf); // pairing of any P of G1 and the fixed Q
free(p);
void mclBn_precomputedMillerLoop2(
  mclBnGT *f,
  const mclBnG1 *P1, const uint64_t *Q1buf,
  const mclBnG1 *P2, const uint64_t *Q2buf
);
  • compute MillerLoop(P1, Q1buf) * MillerLoop(P2, Q2buf)
void mclBn_precomputedMillerLoop2mixed(
  mclBnGT *f,
  const mclBnG1 *P1, const mclBnG2 *Q1,
  const mclBnG1 *P2, const uint64_t *Q2buf
);
  • compute MillerLoop(P1, Q2) * MillerLoop(P2, Q2buf)

Check value

Check validness

int mclBnFr_isValid(const mclBnFr *x);
int mclBnFp_isValid(const mclBnFp *x);
int mclBnG1_isValid(const mclBnG1 *x);
int mclBnG2_isValid(const mclBnG2 *x);

C++

bool T::isValid() const;
  • return 1 if true else 0

Check the order of a point

int mclBnG1_isValidOrder(const mclBnG1 *x);
int mclBnG2_isValidOrder(const mclBnG2 *x);

C++

bool T::isValidOrder() const;
  • Check whether the order of x is valid or not
  • return 1 if true else 0
  • This function always checks according to mclBn_verifyOrderG1 and mclBn_verifyOrderG2.

Is equal / zero / one / isOdd

int mclBnFr_isEqual(const mclBnFr *x, const mclBnFr *y);
int mclBnFr_isZero(const mclBnFr *x);
int mclBnFr_isOne(const mclBnFr *x);
int mclBnFr_isOdd(const mclBnFr *x);

int mclBnFp_isEqual(const mclBnFp *x, const mclBnFp *y);
int mclBnFp_isZero(const mclBnFp *x);
int mclBnFp_isOne(const mclBnFp *x);
int mclBnFp_isOdd(const mclBnFp *x);

int mclBnFp2_isEqual(const mclBnFp2 *x, const mclBnFp2 *y);
int mclBnFp2_isZero(const mclBnFp2 *x);
int mclBnFp2_isOne(const mclBnFp2 *x);

int mclBnG1_isEqual(const mclBnG1 *x, const mclBnG1 *y);
int mclBnG1_isZero(const mclBnG1 *x);

int mclBnG2_isEqual(const mclBnG2 *x, const mclBnG2 *y);
int mclBnG2_isZero(const mclBnG2 *x);

int mclBnGT_isEqual(const mclBnGT *x, const mclBnGT *y);
int mclBnGT_isZero(const mclBnGT *x);
int mclBnGT_isOne(const mclBnGT *x);

C++

bool T::operator==(const T& rhs) const;
bool T::isZero() const;
bool T::isOne() const;
  • return 1 (true) if true else 0 (false)

isNegative

int mclBnFr_isNegative(const mclBnFr *x);
int mclBnFp_isNegative(const mclBnFr *x);

return 1 if x >= half where half = (r + 1) / 2 (resp. (p + 1) / 2).

Lagrange interpolation

int mclBn_FrLagrangeInterpolation(mclBnFr *out, const mclBnFr *xVec, const mclBnFr *yVec, mclSize k);
int mclBn_G1LagrangeInterpolation(mclBnG1 *out, const mclBnFr *xVec, const mclBnG1 *yVec, mclSize k);
int mclBn_G2LagrangeInterpolation(mclBnG2 *out, const mclBnFr *xVec, const mclBnG2 *yVec, mclSize k);
  • Lagrange interpolation
  • recover out = y(0) from {(xVec[i], yVec[i])} for {i=0..k-1}
  • return 0 if success else -1
    • satisfy that xVec[i] != 0, xVec[i] != xVec[j] for i != j
int mclBn_FrEvaluatePolynomial(mclBnFr *out, const mclBnFr *cVec, mclSize cSize, const mclBnFr *x);
int mclBn_G1EvaluatePolynomial(mclBnG1 *out, const mclBnG1 *cVec, mclSize cSize, const mclBnFr *x);
int mclBn_G2EvaluatePolynomial(mclBnG2 *out, const mclBnG2 *cVec, mclSize cSize, const mclBnFr *x);
  • Evaluate polynomial
  • out = f(x) = c[0] + c[1] * x + ... + c[cSize - 1] * x^{cSize - 1}
  • return 0 if success else -1
    • satisfy cSize >= 1

FAQ

Why the value set by Fp::setStr is different?

The value set by Fp::setStr is masked and truncated if it is greater than p (resp. r). See Set string

What parameters of configuration are for Ethereum?

mcl supports various mode of hash-to-curve function, serialize/deserialize and getStr/setStr for historical reasons and backwards compatibility.

If using BLS12-381 and Ethereum compatibility mode, set

// C++
Fp::setETHserialization(true);
Fr::setETHserialization(true);
bn::setMapToMode(MCL_MAP_TO_MODE_HASH_TO_CURVE);

or

// C
mclBn_setETHserialization(1);
mclBn_setMapToMode(MCL_MAP_TO_MODE_HASH_TO_CURVE);

and use

// C++
void Fp::setBigEndianMod(const uint8_t *x, size_t bufSize);
size_t T::serialize(void *buf, size_t maxBufSize) const
size_t T::deserialize(const void *buf, size_t bufSize);

or

// C
int mclBnFp_setBigEndianMod(mclBnFp *x, const void *buf, mclSize bufSize);
mclSize mclBnFp_serialize(void *buf, mclSize maxBufSize, const mclBnFp *x);
mclSize mclBnFp_deserialize(mclBnFp *x, const void *buf, mclSize bufSize);

Serialization of Fp/Fr

  • Fp
    • 48 bytes data in big-endian format
  • Fr
    • 32 bytes data in big-endian format
  • G1
    • zero : [0xc0 : (47 bytes zero)]
    • (x, y) : d = [48 bytes x] and d[0] |= 0x20 if y < (p+1)/2.
  • G2
    • zero : [0xc0 : (95 bytes zero)]
    • (x, y) : d = [96 bytes x] and d[0] |= 0x20 if b < (p+1)/2 where y=a+bi.

See Point Serialization Procedure for details.