From 9c3f370c88ff094c29c4bffa4b64eec51b6c09e4 Mon Sep 17 00:00:00 2001 From: MITSUNARI Shigeo Date: Fri, 13 Mar 2020 11:00:41 +0900 Subject: [PATCH] support hash-to-curve-06 --- include/mcl/bn.hpp | 16 +++++++++++++--- include/mcl/curve_type.h | 10 +++++++++- include/mcl/fp.hpp | 2 ++ include/mcl/mapto_wb19.hpp | 32 ++++++++++++++++++++++++++++---- include/mcl/op.hpp | 2 +- readme.md | 12 ++++++++---- src/fp.cpp | 36 ++++++++++++++++++++++++++++++++++++ test/mapto_wb19_test.cpp | 25 +++++++++++++++++++++++++ 8 files changed, 122 insertions(+), 13 deletions(-) diff --git a/include/mcl/bn.hpp b/include/mcl/bn.hpp index 9e36188..ece87b9 100644 --- a/include/mcl/bn.hpp +++ b/include/mcl/bn.hpp @@ -494,10 +494,19 @@ struct MapTo { case MCL_MAP_TO_MODE_ORIGINAL: case MCL_MAP_TO_MODE_TRY_AND_INC: case MCL_MAP_TO_MODE_ETH2: - case MCL_MAP_TO_MODE_WB19: mapToMode_ = mode; return true; break; + case MCL_MAP_TO_MODE_HASH_TO_CURVE_05: + mapToMode_ = mode; + mapToG2_WB19_.setDraftVersion(5); + return true; + break; + case MCL_MAP_TO_MODE_HASH_TO_CURVE_06: + mapToMode_ = mode; + mapToG2_WB19_.setDraftVersion(6); + return true; + break; default: return false; } @@ -569,7 +578,7 @@ struct MapTo { } bool calc(G2& P, const Fp2& t, bool fast = false) const { - if (mapToMode_ == MCL_MAP_TO_MODE_WB19) { + if (mapToMode_ == MCL_MAP_TO_MODE_WB19 || mapToMode_ == MCL_MAP_TO_MODE_HASH_TO_CURVE_06) { mapToG2_WB19_.opt_swu2_map(P, t); return true; } @@ -2132,7 +2141,8 @@ inline void hashAndMapToG1(G1& P, const void *buf, size_t bufSize) } inline void hashAndMapToG2(G2& P, const void *buf, size_t bufSize) { - if (getMapToMode() == MCL_MAP_TO_MODE_WB19) { + int mode = getMapToMode(); + if (mode == MCL_MAP_TO_MODE_WB19 || mode == MCL_MAP_TO_MODE_HASH_TO_CURVE_06) { BN::param.mapTo.mapToG2_WB19_.msgToG2(P, buf, bufSize); return; } diff --git a/include/mcl/curve_type.h b/include/mcl/curve_type.h index 2b89a4e..c0eb822 100644 --- a/include/mcl/curve_type.h +++ b/include/mcl/curve_type.h @@ -36,11 +36,19 @@ enum { MCL_NIST_P521 = MCL_SECP521R1 }; +/* + remark : if irtf-cfrg-hash-to-curve is compeletely fixed, then + MCL_MAP_TO_MODE_WB19, MCL_MAP_TO_MODE_HASH_TO_CURVE_0? will be removed and + only MCL_MAP_TO_MODE_HASH_TO_CURVE will be available. +*/ enum { MCL_MAP_TO_MODE_ORIGINAL, // see MapTo::calcBN MCL_MAP_TO_MODE_TRY_AND_INC, // try-and-incremental-x MCL_MAP_TO_MODE_ETH2, // old eth2.0 spec - MCL_MAP_TO_MODE_WB19 // used in new eth2.0 spec + MCL_MAP_TO_MODE_WB19, // used in new eth2.0 spec + MCL_MAP_TO_MODE_HASH_TO_CURVE_05 = MCL_MAP_TO_MODE_WB19, // draft-irtf-cfrg-hash-to-curve-05 + MCL_MAP_TO_MODE_HASH_TO_CURVE_06, // draft-irtf-cfrg-hash-to-curve-06 + MCL_MAP_TO_MODE_HASH_TO_CURVE = MCL_MAP_TO_MODE_HASH_TO_CURVE_06 // the latset version }; #ifdef __cplusplus diff --git a/include/mcl/fp.hpp b/include/mcl/fp.hpp index d49fd45..0564d98 100644 --- a/include/mcl/fp.hpp +++ b/include/mcl/fp.hpp @@ -77,6 +77,8 @@ void hkdf_extract_addZeroByte(uint8_t hmac[32], const uint8_t *salt, size_t salt void hkdf_extract(uint8_t hmac[32], const uint8_t *salt, size_t saltSize, const uint8_t *msg, size_t msgSize); void hkdf_expand(uint8_t out[64], const uint8_t prk[32], char info[6]); +void expand_message_xmd(uint8_t out[256], const void *msg, size_t msgSize, const void *dst, size_t dstSize); + namespace local { inline void byteSwap(void *x, size_t n) diff --git a/include/mcl/mapto_wb19.hpp b/include/mcl/mapto_wb19.hpp index 78d2941..a0c1393 100644 --- a/include/mcl/mapto_wb19.hpp +++ b/include/mcl/mapto_wb19.hpp @@ -50,6 +50,11 @@ struct MapToG2_WB19 { Fp2 xden[3]; Fp2 ynum[4]; Fp2 yden[4]; + int draftVersion_; + void setDraftVersion(int version) + { + draftVersion_ = version; + } struct Point { Fp2 x, y, z; bool isZero() const @@ -209,6 +214,7 @@ struct MapToG2_WB19 { Fp::neg(etas[3].a, ev4); etas[3].b = ev3; init_iso(); + draftVersion_ = 5; } void init_iso() { @@ -656,12 +662,30 @@ struct MapToG2_WB19 { P1 += P2; clear_h2(out, P1); } + // hash-to-curve-06 + void hashToFp2v6(Fp2 out[2], const void *msg, size_t msgSize, const void *dst, size_t dstSize) const + { + uint8_t md[256]; + mcl::fp::expand_message_xmd(md, msg, msgSize, dst, dstSize); + Fp *x = out[0].getFp0(); + for (size_t i = 0; i < 4; i++) { + uint8_t *p = &md[64 * i]; + fp::local::byteSwap(p, 64); + bool b; + x[i].setArrayMod(&b, p, 64); + assert(b); (void)b; + } + } void map2curve_osswu2(G2& out, const void *msg, size_t msgSize, const void *dst, size_t dstSize) const { - Fp2 t1, t2; - hashToFp2(t1, msg, msgSize, 0, dst, dstSize); - hashToFp2(t2, msg, msgSize, 1, dst, dstSize); - opt_swu2_map(out, t1, &t2); + Fp2 t[2]; + if (draftVersion_ == 5) { + hashToFp2(t[0], msg, msgSize, 0, dst, dstSize); + hashToFp2(t[1], msg, msgSize, 1, dst, dstSize); + } else { + hashToFp2v6(t, msg, msgSize, dst, dstSize); + } + opt_swu2_map(out, t[0], &t[1]); } void msgToG2(G2& out, const void *msg, size_t msgSize) const { diff --git a/include/mcl/op.hpp b/include/mcl/op.hpp index 021d415..3f8476b 100644 --- a/include/mcl/op.hpp +++ b/include/mcl/op.hpp @@ -23,7 +23,7 @@ namespace mcl { -static const int version = 0x105; /* 0xABC = A.BC */ +static const int version = 0x106; /* 0xABC = A.BC */ /* specifies available string format mode for X::setIoMode() diff --git a/readme.md b/readme.md index 7387889..ace5483 100644 --- a/readme.md +++ b/readme.md @@ -10,10 +10,13 @@ mcl is a library for pairing-based cryptography, which supports the optimal Ate pairing over BN curves and BLS12-381 curves. # News -add new hash functions corresponding to python-impl of [algorand/bls_sig_ref](https://github.com/algorand/bls_sigs_ref). -* `mclBn_ethMsgToFp2`(resp. `Hp2`) -* `mclBn_ethFp2ToG2`(resp. `opt_swu2_map`) -* `mclBn_ethMsgToG2`(resp. `map2curve_osswu2`) +- add new hash-to-curve function of [draft-irtf-cfrg-hash-to-curve](https://cfrg.github.io/draft-irtf-cfrg-hash-to-curve/draft-irtf-cfrg-hash-to-curve.txt) at March 2020. + - call `setETHmode(MCL_MAP_TO_MODE_HASH_TO_CURVE_06);` + - The older `MAP_TO_MODE` will be removed after the draft is fixed. +- add new hash functions corresponding to python-impl of [algorand/bls_sig_ref](https://github.com/algorand/bls_sigs_ref). + - `mclBn_ethMsgToFp2`(resp. `Hp2`) + - `mclBn_ethFp2ToG2`(resp. `opt_swu2_map`) + - `mclBn_ethMsgToG2`(resp. `map2curve_osswu2`) # Support architecture @@ -292,6 +295,7 @@ If `MCL_USE_OLD_MAPTO_FOR_BLS12` is defined, then the old function is used, but # History +- 2020/Mar/15 v1.06 support hash-to-curve-06 - 2020/Jan/31 v1.05 mclBn_ethMsgToFp2 has changed to append zero byte at the end of msg - 2020/Jan/25 v1.04 add new hash functions - 2019/Dec/05 v1.03 disable to check the order in setStr diff --git a/src/fp.cpp b/src/fp.cpp index 64dc4a1..aab8e1e 100644 --- a/src/fp.cpp +++ b/src/fp.cpp @@ -159,6 +159,42 @@ void hkdf_expand(uint8_t out[64], const uint8_t prk[32], char info[6]) cybozu::hmac256(out + 32, prk, 32, out, 32 + 6); } +void expand_message_xmd(uint8_t out[256], const void *msg, size_t msgSize, const void *dst, size_t dstSize) +{ + const size_t len_in_bytes = 256; + const size_t mdSize = 32; + const size_t r_in_bytes = 64; + const size_t ell = len_in_bytes / mdSize; + uint8_t Z_pad[r_in_bytes] = {}; + assert(dstSize < 256); + // BE(len_in_bytes, 2) + BE(0, 1) + BE(dstSize, 1) + uint8_t buf[2 + 1 + 1] = { 1, 0, 0, uint8_t(dstSize) }; + uint8_t *const buf2 = buf + 2; // BE(0, 1) + BE(dstSize, 1) + cybozu::Sha256 h; + h.update(Z_pad, r_in_bytes); + h.update(msg, msgSize); + h.update(buf, sizeof(buf)); + uint8_t md[mdSize]; + h.digest(md, mdSize, dst, dstSize); + h.clear(); + buf2[0] = 1; + h.update(md, mdSize); + h.update(buf2, 2); + h.digest(out, mdSize, dst, dstSize); + uint8_t mdXor[mdSize]; + for (size_t i = 1; i < ell; i++) { + h.clear(); + for (size_t j = 0; j < mdSize; j++) { + mdXor[j] = md[j] ^ out[mdSize * (i - 1) + j]; + } + h.update(mdXor, mdSize); + buf2[0] = uint8_t(i + 1); + h.update(buf2, 2); + h.digest(out + mdSize * i, mdSize, dst, dstSize); + } +} + + #ifndef MCL_USE_VINT static inline void set_mpz_t(mpz_t& z, const Unit* p, int n) { diff --git a/test/mapto_wb19_test.cpp b/test/mapto_wb19_test.cpp index 405c367..559de9c 100644 --- a/test/mapto_wb19_test.cpp +++ b/test/mapto_wb19_test.cpp @@ -629,6 +629,30 @@ void py_eccTest2(const T& mapto) CYBOZU_TEST_EQUAL(P, Q); } +template +void testHashToFp2v6(const T& mapto) +{ + const char msg[] = "asdf"; + const char dst[] = "QUUX-V01-CS02"; + Fp2 out[2]; + mapto.hashToFp2v6(out, msg, strlen(msg), dst, strlen(dst)); + const Fp2Str expectStr[] = { + { + "2036684013374073670470642478097435082393965905216073159069132582313283074894808330704754509140183015844408257838394", + "1442095344782436377607687657711937282361342321405422912347590889376773969332935605209326528060836557922932229521614", + }, + { + "712603160732423529538850938327197859251773848793464448294977148617985113767869616209273456982966659285651019780554", + "3549454379036632156704729135192770954406411172309331582430747991672599371642148666322072960024366511631069032927782", + }, + }; + Fp2 expect[2]; + for (int i = 0; i < 2; i++) { + set(expect[i], expectStr[i]); + CYBOZU_TEST_EQUAL(out[i], expect[i]); + } +} + CYBOZU_TEST_AUTO(test) { initPairing(mcl::BLS12_381); @@ -648,4 +672,5 @@ CYBOZU_TEST_AUTO(test) testVec("../misc/mapto/fips_186_3_B233.txt"); testVec("../misc/mapto/misc.txt"); ethMsgToG2testAll("../bls_sigs_ref/test-vectors/hash_g2/"); + testHashToFp2v6(mapto); }