From f1d0865f1c0881d072f0bea821da6baf818b4088 Mon Sep 17 00:00:00 2001 From: MITSUNARI Shigeo Date: Mon, 29 Apr 2019 14:02:55 +0900 Subject: [PATCH] add mclBn_setETHserialization --- include/mcl/bn.h | 6 ++ include/mcl/ec.hpp | 103 +++++++++++++++++++++++++++------ include/mcl/fp.hpp | 1 + include/mcl/impl/bn_c_impl.hpp | 5 ++ test/bls12_test.cpp | 26 ++++++++- 5 files changed, 122 insertions(+), 19 deletions(-) diff --git a/include/mcl/bn.h b/include/mcl/bn.h index e866a7a..68053cb 100644 --- a/include/mcl/bn.h +++ b/include/mcl/bn.h @@ -177,6 +177,12 @@ MCLBN_DLL_API mclSize mclBn_getCurveOrder(char *buf, mclSize maxBufSize); */ MCLBN_DLL_API mclSize mclBn_getFieldOrder(char *buf, mclSize maxBufSize); +/* + set ETH serialization mode for BLS12-381 + @param ETHserialization [in] 1:enable, 0:disable + @note ignore the flag if curve is not BLS12-381 +*/ +MCLBN_DLL_API void mclBn_setETHserialization(int ETHserialization); //////////////////////////////////////////////// /* deserialize diff --git a/include/mcl/ec.hpp b/include/mcl/ec.hpp index b8eb10b..3cf7054 100644 --- a/include/mcl/ec.hpp +++ b/include/mcl/ec.hpp @@ -20,6 +20,8 @@ namespace mcl { +template class Fp2T; + namespace ec { enum Mode { @@ -27,6 +29,25 @@ enum Mode { Proj = 1 }; +namespace local { + +// x is negative <=> x < half(:=(p+1)/2) <=> a = 1 +template +bool get_a_flag(const Fp& x) +{ + return x.isNegative(); +} + +// Im(x) is negative <=> Im(x) < half(:=(p+1)/2) <=> a = 1 + +template +bool get_a_flag(const mcl::Fp2T& x) +{ + return get_a_flag(x.b); // x = a + bi +} + +} // mcl::ec::local + } // mcl::ec /* @@ -708,28 +729,44 @@ public: EcT P(*this); P.normalize(); if (ioMode & (IoSerialize | IoSerializeHexStr)) { - /* - if (isMSBserialize()) { - // n bytes - x | (y.isOdd ? 0x80 : 0) - } else { - // n + 1 bytes - (y.isOdd ? 3 : 2), x - } - */ const size_t n = Fp::getByteSize(); const size_t adj = isMSBserialize() ? 0 : 1; char buf[sizeof(Fp) + 1]; - if (isZero()) { - memset(buf, 0, n + adj); + if (Fp::BaseFp::isETHserialization()) { + const char c_flag = 0x80; + const char b_flag = 0x40; + const char a_flag = 0x20; + if (P.isZero()) { + buf[0] = c_flag | b_flag; + memset(buf + 1, 0, n - 1); + } else { + cybozu::MemoryOutputStream mos(buf, n); + P.x.save(pb, mos, IoSerialize); if (!*pb) return; + char cba = c_flag; + if (ec::local::get_a_flag(P.y)) cba |= a_flag; + buf[0] |= cba; + } } else { - cybozu::MemoryOutputStream mos(buf + adj, n); - P.x.save(pb, mos, IoSerialize); if (!*pb) return; - if (adj) { - buf[0] = P.y.isOdd() ? 3 : 2; + /* + if (isMSBserialize()) { + // n bytes + x | (y.isOdd ? 0x80 : 0) + } else { + // n + 1 bytes + (y.isOdd ? 3 : 2), x + } + */ + if (isZero()) { + memset(buf, 0, n + adj); } else { - if (P.y.isOdd()) { - buf[n - 1] |= 0x80; + cybozu::MemoryOutputStream mos(buf + adj, n); + P.x.save(pb, mos, IoSerialize); if (!*pb) return; + if (adj) { + buf[0] = P.y.isOdd() ? 3 : 2; + } else { + if (P.y.isOdd()) { + buf[n - 1] |= 0x80; + } } } } @@ -789,6 +826,38 @@ public: *pb = false; return; } + if (Fp::BaseFp::isETHserialization()) { + const char c_flag = 0x80; + const char b_flag = 0x40; + const char a_flag = 0x20; + *pb = false; + if ((buf[0] & c_flag) == 0) { // assume compressed + return; + } + if (buf[0] & b_flag) { // infinity + if (buf[0] != (c_flag | b_flag)) return; + for (size_t i = 1; i < n - 1; i++) { + if (buf[i]) return; + } + clear(); + *pb = true; + return; + } + bool a = (buf[0] & a_flag) != 0; + buf[0] &= ~(c_flag | b_flag | a_flag); + mcl::fp::local::byteSwap(buf, n); + x.setArray(pb, buf, n); + if (!*pb) return; + getWeierstrass(y, x); + if (!Fp::squareRoot(y, y)) { + *pb = false; + return; + } + if (ec::local::get_a_flag(y) ^ a) { + Fp::neg(y, y); + } + return; + } if (fp::isZeroArray(buf, n1)) { clear(); *pb = true; diff --git a/include/mcl/fp.hpp b/include/mcl/fp.hpp index db44227..8c16468 100644 --- a/include/mcl/fp.hpp +++ b/include/mcl/fp.hpp @@ -529,6 +529,7 @@ public: if (getBitSize() != 381) return; isETHserialization_ = ETHserialization; } + static inline bool isETHserialization() { return isETHserialization_; } static inline int getIoMode() { return ioMode_; } static inline size_t getModBitLen() { return getBitSize(); } static inline void setHashFunc(uint32_t hash(void *out, uint32_t maxOutSize, const void *msg, uint32_t msgSize)) diff --git a/include/mcl/impl/bn_c_impl.hpp b/include/mcl/impl/bn_c_impl.hpp index bec2466..7c14f63 100644 --- a/include/mcl/impl/bn_c_impl.hpp +++ b/include/mcl/impl/bn_c_impl.hpp @@ -113,6 +113,11 @@ mclSize mclBn_getFieldOrder(char *buf, mclSize maxBufSize) return Fp::getModulo(buf, maxBufSize); } +void mclBn_setETHserialization(int ETHserialization) +{ + Fp::setETHserialization(ETHserialization == 1); +} + //////////////////////////////////////////////// // set zero void mclBnFr_clear(mclBnFr *x) diff --git a/test/bls12_test.cpp b/test/bls12_test.cpp index 8b67ce6..cc8ddef 100644 --- a/test/bls12_test.cpp +++ b/test/bls12_test.cpp @@ -307,7 +307,18 @@ void testTrivial(const G1& P, const G2& Q) CYBOZU_TEST_EQUAL(e, 1); } -void testSerialize() +template +void deserializeAndSerialize(const T& x) +{ + char buf[1024]; + size_t n = x.serialize(buf, sizeof(buf)); + CYBOZU_TEST_ASSERT(n > 0); + T y; + CYBOZU_TEST_EQUAL(y.deserialize(buf, n), n); + CYBOZU_TEST_EQUAL(x, y); +} + +void testSerialize(const G1& P, const G2& Q) { Fp::setETHserialization(true); // big endian const struct FpTbl { @@ -329,6 +340,17 @@ void testSerialize() CYBOZU_TEST_EQUAL(y.deserialize(buf, n, mcl::IoSerializeHexStr), n); CYBOZU_TEST_EQUAL(x, y); } + deserializeAndSerialize(P); + deserializeAndSerialize(-P); + G1 zero1; + zero1.clear(); + deserializeAndSerialize(zero1); + + deserializeAndSerialize(Q); + deserializeAndSerialize(-Q); + G2 zero2; + zero2.clear(); + deserializeAndSerialize(zero2); Fp::setETHserialization(false); } @@ -350,7 +372,7 @@ CYBOZU_TEST_AUTO(naive) clk.put(); return; #endif - testSerialize(); + testSerialize(P, Q); testParam(ts); testIo(P, Q); // testFp12pow(P, Q);