A sample demonstrating BLS12-381 usage:
cd mcl
make -j4
make bin/pairing_c.exe && bin/pairing_c.execd mcl
make -j4
make bin/pairing.exe && bin/pairing.exeTo use BLS12-381, include <mcl/bn_c384_256.h> and link libmcl.{a,so}.
384_256 indicates that the maximum bit size of Fp is 384, and the size of Fr is 256.
Include <mcl/bls12_381.hpp> and link libmcl.{a,so}.
The elliptic curve equation is E: y^2 = x^3 + b.
Fp: a finite field of prime orderp, over which the curve is defined.Fr: a finite field of prime orderr.Fp2: field extension over Fp of degree 2. Fp[i] / (i^2 + u).Fp6: field extension over Fp2 of degree 3. Fp2[v] / (v^3 - Xi) where Xi = i + xi_a.Fp12: field extension over Fp6 of degree 2. Fp6[w] / (w^2 - v).G1: the cyclic subgroup of E(Fp).G2: the cyclic subgroup of E'(Fp^2), where E' is a twist of E.GT: the cyclic subgroup of Fp12.G1,G2, andGThave the orderr.
The pairing e: G1 x G2 -> GT is the optimal ate pairing.
mcl treats G1 and G2 as additive groups and GT as a multiplicative group.
mclSize;unsigned intif WebAssembly, otherwisesize_tmclInt;intif WebAssembly, otherwiseint64_t
r = |G1| = |G2| = |GT|
| curveType | b | u | xi_a | r and p |
|---|---|---|---|---|
| BN254 | 2 | 1 | 1 | r = 0x2523648240000001ba344d8000000007ff9f800000000010a10000000000000d p = 0x2523648240000001ba344d80000000086121000000000013a700000000000013 |
| BN_SNARK1 | 3 | 1 | 9 | r = 0x30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001 p = 0x30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47 |
| BLS12_381 | 4 | 1 | 1 | r = 0x73eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000001 p = 0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaaab |
| BLS12_377 | 1 | 5 | 0 | r = 0x12ab655e9a2ca55660b44d1e5c37b00159aa76fed00000010a11800000000001 p = 0x1ae3a4617c510eac63b05c06ca1493b1a22d9f300f5138f1ef3622fba094800170b5d44300000008508c00000000001 |
| BN381 | 2 | 1 | 1 | r = 0x240026400f3d82b2e42de125b00158405b710818ac000007e0042f008e3e00000000001080046200000000000000000d p = 0x240026400f3d82b2e42de125b00158405b710818ac00000840046200950400000000001380052e000000000000000013 |
This is a struct for Fp. The value is stored in Montgomery representation.
This is a struct for Fr. The value is stored in Montgomery representation.
This is a struct for 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.
This is a struct for G1 with three members x, y, z of type mclBnFp.
An element P of G1 is represented as P = [x:y:z] in Jacobian coordinates.
This is a struct for G2 with three members x, y, z of type mclBnFp2.
An element Q of G2 is represented as Q = [x:y:z] in Jacobian coordinates.
This is a struct for GT with a member mclBnFp d[12].
The namespace is mcl::bn. <mcl/bls12_381.hpp> also provides the namespace mcl::bls12, which imports mcl::bn.
This is a class for Fp.
This is a class for Fr.
This is a struct for Fp2 with members a and b of type Fp.
An element x of Fp2 is represented as x = a + b i where i^2 = -1.
This is a struct for Fp6 with members 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.
This is a struct for Fp12 with members a and b of type Fp6.
An element x of Fp12 is represented as x = a + b w where w^2 = v.
This is a struct for G1 with three members x, y, z of type Fp.
An element P of G1 is represented as P = [x:y:z] in Jacobian coordinates.
This is a struct for G2 with three members x, y, z of type Fp2.
An element Q of G2 is represented as Q = [x:y:z] in Jacobian coordinates.
GT is an alias for Fp12.
However, it represents the set { x in Fp12 | x^r = 1}.
By default, MCL_FP_BIT=384 and MCL_FR_BIT=256 are set.
If you want to change these values, use commands such as make MCL_FP_BIT=256 MCL_FR_BIT=256.
You must set the same macro and value to compile your application program.
| MCL_FP_BIT | MCL_FR_BIT | sizeof Fr | sizeof Fp | supported curves |
|---|---|---|---|---|
| 256 | 256 | 32 | 32 | MCL_BN254, MCL_BN_SNARK1 |
| 384 | 256 | 48 | 32 | +MCL_BLS12_381, MCL_BLS12_377 |
| 384 | 384 | 48 | 48 | +MCL_BN381_1 |
All functions except initialization and global setting changes are thread-safe.
Initialize the mcl library. Call this function first before calling other functions.
int mclBn_init(int curve, int compiledTimeVar);curve; specify the curve typecompiledTimeVar; setMCLBN_COMPILED_TIME_VAR, a macro used to ensure that the values are consistent between library build time and usage.- return 0 on success.
- This is not thread safe.
void initPairing(bool *pb, const mcl::CurveParam& cp = mcl::BN254);
void initPairing(const mcl::CurveParam& cp = mcl::BN254); // throws an exception on errorThe curve parameters are defined in mcl/curve_type.hpp.
- mcl::BN254
- mcl::BN_SNARK1
- mcl::BLS12_381
- mcl::BLS12_377
- mcl::BN381_1
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 RFC 9380 (Hashing to Elliptic Curves)
This function affects setStr() and deserialize() for G1/G2.
void mclBn_verifyOrderG1(int doVerify);
void mclBn_verifyOrderG2(int doVerify);verifyOrderG1(bool doVerify);
verifyOrderG2(bool doVerify);- verify if
doVerifyis 1, otherwise do not verify. - The default values set by initialization are as follows: for BLS12 curves, both G1 and G2 are verified (a fast subgroup check is used). For BN curves, G1 is not verified (the cofactor is 1, so the check is unnecessary) and G2 is verified.
- Set
doVerify = 1if protection against subgroup attacks is necessary. - This is not thread-safe.
int mclBnG1_setDst(const char *dst, mclSize dstSize);
int mclBnG2_setDst(const char *dst, mclSize dstSize);return 0 if success else -1
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_
- G1 :
Set x to 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();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>;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);- set x = buf[0..bufSize-1] as little endian
- x &= (1 << bitLen(r)) - 1
- if (x >= r), then x &= (1 << (bitLen(r) - 1)) - 1
- always returns 0
int mclBnFp_setLittleEndianMod(mclBnFp *x, const void *buf, mclSize bufSize);
int mclBnFr_setLittleEndianMod(mclBnFr *x, const void *buf, mclSize bufSize);
int mclBnFp_setBigEndianMod(mclBnFp *x, const void *buf, mclSize bufSize);
int mclBnFr_setBigEndianMod(mclBnFr *x, const void *buf, mclSize bufSize);C++
void T::setLittleEndianMod(const uint8_t *buf, size_t bufSize);
void T::setBigEndianMod(const uint8_t *buf, size_t bufSize);- return 0 if bufSize <= (sizeof(T) * 2), otherwise -1
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
xtobufin little-endian format - return the written size on success, otherwise 0
- NOTE: if
xis zero, thenbuf[0] = 0and the function returns 1.
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
xintobuf[0..maxBufSize-1] - return written byte size on success, otherwise 0
Fp(resp.Fr) ; a little-endian byte sequence with a fixed size- the size is the return value of
mclBn_getFpByteSize()(resp.mclBn_getFrByteSize()).
- the size is the return value of
G1; compressed with a fixed size- the size is equal to
mclBn_getG1ByteSize()(=mclBn_getFpByteSize()).
- the size is equal to
G2; compressed with a fixed size- the size is equal to
mclBn_getG2ByteSize().
- the size is equal to
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 = [P.y is odd ? 3 : 2] + s # prepend one byte
elif P.y is odd: # resp. P.y.d[0] is odd
s[byte-length(s) - 1] |= 0x80
return svoid mclBn_setETHserialization(int ETHserialization);- Set
ETHserialization = 1for Ethereum compatibility (default 0). - See FAQ.
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
xfrombuf[0..bufSize-1] - return read size on success, otherwise 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.
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
xtobufaccording toioMode ioMode- 2 ; binary number
- 10 ; decimal number
- 16 ; hexadecimal number
MCLBN_IO_EC_PROJ; output in Jacobian coordinates
- return
strlen(buf)on success, otherwise 0.
The meaning of the output of G1:
0; infinity1 <x> <y>; affine coordinate4 <x> <y> <z>; Jacobian coordinates- the element
<x>ofG2outputsd[0] d[1].
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]toxaccording toioMode- mask and truncate the value if it is greater than (r or p).
- See masking
- A
bufSizethat is too large is rejected. The maximum length depends on compile options, but it is at least the bit length of the type ofx. - Setting a string for G1/G2 fails if the point is not on the elliptic curve.
- By default, it also checks that the point has the correct order of G1/G2.
- You can disable this check with
mclBn_verifyOrderG1(0)/mclBn_verifyOrderG2(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 x by a cryptographically secure pseudo-random number generator.
int mclBnFr_setByCSPRNG(mclBnFr *x);
int mclBnFp_setByCSPRNG(mclBnFp *x);C++
void T::setByCSPRNG()void mclBn_setRandFunc(
void *self,
unsigned int (*readFunc)(void *self, void *buf, unsigned int bufSize)
);self; user-defined pointerreadFunc; user-defined function, which writes randombufSizebytes tobufand returnsbufSizeif success else returns 0.readFuncmust be thread-safe.
- Set the default random function if
self == 0andreadFunc == 0. - This is not thread-safe.
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_invGenericfor an element in Fp12 - GT. -
NOTE: The result of the following functions is not an element of GT 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(z, x, y)meansz = x^y.powArray(z, x, y, ySize)means z = x^y where y is a little endianySize-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);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);yis one of the square roots ofxif it exists.- return 0 if success else -1
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);
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, const T *x, size_t n);- convert
[x:y:z]to[x:y:1]ifz != 0else[*:*:0]
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(T& z, const T& x, const Fr& y);-
z = x * y for G1 / G2
-
z = pow(x, y) for GT
-
use
mclBnGT_powGenericfor an element in Fp12 - GT.
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[]is not const because the points may be normalized (the values they represent do not change).
void mclBnG1_mulVecMT(mclBnG1 *z, mclBnG1 *x, const mclBnFr *y, mclSize n, mclSize cpuN);
void mclBnG2_mulVecMT(mclBnG2 *z, mclBnG2 *x, const mclBnFr *y, mclSize n, mclSize cpuN);- multi-threaded version of
mulVecwithcpuNthreads - enabled if the library is built with
MCL_USE_OMP=1
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::mulVecandG1::mulEachfor BLS12-381 use AVX-512 IFMA if possible
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 returns 0
- uses SHA-256 if the bit size of the field is not greater than 256, otherwise SHA-512
- sets the value in the same way as
setLittleEndian. - This function is for backward compatibility only. DON'T use it. Instead, apply
setLittleEndianModto the hashed value.
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 MapToinsrc/map_impl.hppfor details of the algorithm. - return 0 if success else -1
If you want to use the MapTo function defined in RFC 9380 (Hashing to Elliptic Curves), then use mclBn_setMapToMode.
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);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);- Combines the
setHashOfandmapTofunctions
The pairing function e(P, Q) consists 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))
void mclBn_pairing(mclBnGT *z, const mclBnG1 *x, const mclBnG2 *y);C++
void pairing(GT& z, const G1& x, const G2& y);void mclBn_millerLoop(mclBnGT *z, const mclBnG1 *x, const mclBnG2 *y);C++
void millerLoop(GT& z, const G1& x, const G2& y);void mclBn_finalExp(mclBnGT *y, const mclBnGT *x);C++
void finalExp(GT& y, const GT& x);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]))
void mclBn_millerLoopVecMT(mclBnGT *z, const mclBnG1 *x, const mclBnG2 *y, mclSize n, mclSize cpuN);- multi-threaded version of
mclBn_millerLoopVecwithcpuNthreads - enabled if the library is built with
MCL_USE_OMP=1
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 compute the same value as pairing(P, Q) as follows:
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(Qbuf);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, Q1) * MillerLoop(P2, Q2buf)
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
int mclBnG1_isValidOrder(const mclBnG1 *x);
int mclBnG2_isValidOrder(const mclBnG2 *x);C++
bool T::isValidOrder() const;- Check whether the order of
xis valid or not - return 1 if true else 0
- This function always performs the check regardless of the settings of
mclBn_verifyOrderG1andmclBn_verifyOrderG2.
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)
int mclBnFr_isNegative(const mclBnFr *x);
int mclBnFp_isNegative(const mclBnFp *x);return 1 if x >= half where half = (r + 1) / 2 (resp. (p + 1) / 2).
int mclBnFr_cmp(const mclBnFr *x, const mclBnFr *y);
int mclBnFp_cmp(const mclBnFp *x, const mclBnFp *y);- compare
xandyas unsigned integers - return -1 if x < y, 0 if x == y, 1 if x > y
- NOTE: two Montgomery conversions may be required
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
- requires that xVec[i] != 0 and 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
- requires cSize >= 1
The value set by Fp::setStr is masked and truncated if it is greater than p (resp. r). See Set string
mcl supports various modes of the hash-to-curve function, serialize/deserialize, and getStr/setStr for historical reasons and backward 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], thend[0] |= 0x80, andd[0] |= 0x20ify >= (p+1)/2.
- zero :
- G2
- zero :
[0xc0 : (95 bytes zero)] - (x, y) :
d = [96 bytes x], thend[0] |= 0x80, andd[0] |= 0x20ifb >= (p+1)/2wherey = a + bi.
- zero :
See Point Serialization Procedure for details.