diff --git a/.gitignore b/.gitignore index add2a728..5ed7dcdd 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,4 @@ /build/ -/.idea/ \ No newline at end of file +/.idea/ +.DS_Store +.vscode diff --git a/.gitmodules b/.gitmodules index 74ba1026..3267f351 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +1,6 @@ +[submodule "depends/gtest"] + path = depends/gtest + url = https://github.com/google/googletest.git [submodule "depends/ate-pairing"] path = depends/ate-pairing url = https://github.com/herumi/ate-pairing.git diff --git a/CMakeLists.txt b/CMakeLists.txt index 1079483b..386532e3 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -191,6 +191,7 @@ endif() if("${USE_ASM}") add_definitions(-DUSE_ASM) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mpclmul -msse4.1") # used for binary fields endif() # Configure CCache if available diff --git a/README.md b/README.md index 7fe8d7d8..582c989a 100755 --- a/README.md +++ b/README.md @@ -54,6 +54,7 @@ The library has the following dependencies: * [CMake](http://cmake.org/) * [GMP](http://gmplib.org/) * [libprocps](http://packages.ubuntu.com/trusty/libprocps-dev) +* [libsodium](https://libsodium.gitbook.io/doc/) The library has been tested on Linux, but it is compatible with Windows and Mac OS X. @@ -65,6 +66,9 @@ On Ubuntu 14.04 LTS: sudo apt-get install build-essential git libboost-all-dev cmake libgmp3-dev libssl-dev libprocps3-dev pkg-config ``` + +On Mac OS X, all of the libraries from the previous section can be installed with brew, except for `libprocps`. You will need to turn that off for Mac OS X. + Fetch dependencies from their GitHub repos: ``` @@ -82,6 +86,11 @@ Optionally, you can specify the install location by providing the desired instal ``` cmake .. -DCMAKE_INSTALL_PREFIX=/install/path ``` +On Mac OS X, you may also need to turn off `libprocps` and/or provide the path to openssl (your exact path may vary): +``` +cmake -DWITH_PROCPS=OFF -DOPENSSL_ROOT_DIR=/usr/local/Cellar/openssl/1.0.2s -DOPENSSL_LIBRARIES=/usr/local/Cellar/openssl/1.0.2s/lib .. +``` +To enable asserts, use the `-DCMAKE_BUILD_TYPE=Debug` flag. Then, to compile and install the library, run this within the build directory: ``` @@ -93,7 +102,7 @@ This will install `libff.a` into `/install/path/lib`; so your application should ## Testing -To execute the tests for this library, run: +To build and execute the tests for this library, run: ``` make check ``` diff --git a/depends/CMakeLists.txt b/depends/CMakeLists.txt index fa8ccef1..ccdec257 100755 --- a/depends/CMakeLists.txt +++ b/depends/CMakeLists.txt @@ -1,3 +1,7 @@ +# gtest for binary fields +add_subdirectory(gtest EXCLUDE_FROM_ALL) + + if(${CURVE} STREQUAL "BN128") include_directories(ate-pairing/include) include_directories(xbyak) diff --git a/depends/gtest b/depends/gtest new file mode 160000 index 00000000..a325ad2d --- /dev/null +++ b/depends/gtest @@ -0,0 +1 @@ +Subproject commit a325ad2db5deb623eab740527e559b81c0f39d65 diff --git a/libff/CMakeLists.txt b/libff/CMakeLists.txt index bcc0bb06..806bbd0e 100755 --- a/libff/CMakeLists.txt +++ b/libff/CMakeLists.txt @@ -5,6 +5,7 @@ if(${CURVE} STREQUAL "BN128") FF_EXTRASRCS ${FF_EXTRASRCS} + algebra/curves/bn128/bn128_fields.cpp algebra/curves/bn128/bn128_g1.cpp algebra/curves/bn128/bn128_g2.cpp algebra/curves/bn128/bn128_gt.cpp @@ -24,27 +25,32 @@ add_library( ff STATIC + algebra/curves/alt_bn128/alt_bn128_fields.cpp algebra/curves/alt_bn128/alt_bn128_g1.cpp algebra/curves/alt_bn128/alt_bn128_g2.cpp algebra/curves/alt_bn128/alt_bn128_init.cpp algebra/curves/alt_bn128/alt_bn128_pairing.cpp algebra/curves/alt_bn128/alt_bn128_pp.cpp + algebra/curves/edwards/edwards_fields.cpp algebra/curves/edwards/edwards_g1.cpp algebra/curves/edwards/edwards_g2.cpp algebra/curves/edwards/edwards_init.cpp algebra/curves/edwards/edwards_pairing.cpp algebra/curves/edwards/edwards_pp.cpp + algebra/curves/mnt/mnt4/mnt4_fields.cpp algebra/curves/mnt/mnt4/mnt4_g1.cpp algebra/curves/mnt/mnt4/mnt4_g2.cpp algebra/curves/mnt/mnt4/mnt4_init.cpp algebra/curves/mnt/mnt4/mnt4_pairing.cpp algebra/curves/mnt/mnt4/mnt4_pp.cpp algebra/curves/mnt/mnt46_common.cpp + algebra/curves/mnt/mnt6/mnt6_fields.cpp algebra/curves/mnt/mnt6/mnt6_g1.cpp algebra/curves/mnt/mnt6/mnt6_g2.cpp algebra/curves/mnt/mnt6/mnt6_init.cpp algebra/curves/mnt/mnt6/mnt6_pairing.cpp algebra/curves/mnt/mnt6/mnt6_pp.cpp + common/double.cpp common/profiling.cpp common/utils.cpp @@ -63,6 +69,35 @@ target_include_directories( PUBLIC .. ) +# sodium for binary fields +find_path( + SODIUM_INCLUDE_DIR + sodium.h + HINTS ${LIBSODIUM_INCLUDE_DIRS} + /usr/local/include /opt/local/include /opt/include +) +find_library( + SODIUM_LIBRARY + NAMES sodium + HINTS ${LIBSODIUM_LIBRARY_DIRS} + /usr/local/lib /opt/local/lib /opt/lib +) + +target_include_directories( + ff + PUBLIC + ${SODIUM_INCLUDE_DIR} +) +target_compile_options( + ff + PUBLIC + ${LIBSODIUM_CFLAGS} ${LIBSODIUM_CFLAGS_OTHER} +) +target_link_libraries( + ff + ${SODIUM_LIBRARY} ${LIBSODIUM_LDFLAGS_OTHER} +) + install( DIRECTORY "" DESTINATION "include/libff" FILES_MATCHING @@ -78,6 +113,7 @@ install( # Tests if ("${IS_LIBFF_PARENT}") + # Tests for prime fields add_executable( algebra_bilinearity_test EXCLUDE_FROM_ALL @@ -88,6 +124,7 @@ if ("${IS_LIBFF_PARENT}") algebra_bilinearity_test ff + gtest_main ) add_executable( @@ -100,18 +137,46 @@ if ("${IS_LIBFF_PARENT}") algebra_groups_test ff + gtest_main + ) + + add_executable( + algebra_prime_fields_test + EXCLUDE_FROM_ALL + + algebra/fields/tests/test_prime_fields.cpp + ) + target_link_libraries( + algebra_prime_fields_test + + ff + gtest_main + ) + + add_executable( + algebra_all_fields_test + EXCLUDE_FROM_ALL + + algebra/fields/tests/test_all_fields.cpp + ) + target_link_libraries( + algebra_all_fields_test + + ff + gtest_main ) add_executable( - algebra_fields_test + algebra_field_utils_test EXCLUDE_FROM_ALL - algebra/fields/tests/test_fields.cpp + algebra/field_utils/tests/test_field_utils.cpp ) target_link_libraries( - algebra_fields_test + algebra_field_utils_test ff + gtest_main ) include(CTest) @@ -124,14 +189,46 @@ if ("${IS_LIBFF_PARENT}") COMMAND algebra_groups_test ) add_test( - NAME algebra_fields_test - COMMAND algebra_fields_test + NAME algebra_prime_fields_test + COMMAND algebra_prime_fields_test + ) + add_test( + NAME algebra_all_fields_test + COMMAND algebra_all_fields_test + ) + add_test( + NAME algebra_field_utils_test + COMMAND algebra_field_utils_test ) add_dependencies(check algebra_bilinearity_test) add_dependencies(check algebra_groups_test) - add_dependencies(check algebra_fields_test) + add_dependencies(check algebra_prime_fields_test) + add_dependencies(check algebra_all_fields_test) + add_dependencies(check algebra_field_utils_test) + + # Tests for binary fields + add_executable( + algebra_binary_fields_test + EXCLUDE_FROM_ALL + + algebra/fields/tests/test_binary_fields.cpp + ) + target_link_libraries( + algebra_binary_fields_test + + ff + gtest_main + ) + + add_test( + NAME algebra_binary_fields_test + COMMAND algebra_binary_fields_test + ) + + add_dependencies(check algebra_binary_fields_test) + # Profiling for prime fields add_executable( multiexp_profile EXCLUDE_FROM_ALL diff --git a/libff/algebra/curves/alt_bn128/alt_bn128_fields.cpp b/libff/algebra/curves/alt_bn128/alt_bn128_fields.cpp new file mode 100644 index 00000000..e465d49e --- /dev/null +++ b/libff/algebra/curves/alt_bn128/alt_bn128_fields.cpp @@ -0,0 +1,145 @@ +/** @file + ***************************************************************************** + * @author This file is part of libff, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#include + +namespace libff { + +bigint alt_bn128_modulus_r; +bigint alt_bn128_modulus_q; + +void init_alt_bn128_fields() +{ + typedef bigint bigint_r; + typedef bigint bigint_q; + + assert(sizeof(mp_limb_t) == 8 || sizeof(mp_limb_t) == 4); // Montgomery assumes this + + /* parameters for scalar field Fr */ + + alt_bn128_modulus_r = bigint_r("21888242871839275222246405745257275088548364400416034343698204186575808495617"); + assert(alt_bn128_Fr::modulus_is_valid()); + if (sizeof(mp_limb_t) == 8) + { + alt_bn128_Fr::Rsquared = bigint_r("944936681149208446651664254269745548490766851729442924617792859073125903783"); + alt_bn128_Fr::Rcubed = bigint_r("5866548545943845227489894872040244720403868105578784105281690076696998248512"); + alt_bn128_Fr::inv = 0xc2e1f593efffffff; + } + if (sizeof(mp_limb_t) == 4) + { + alt_bn128_Fr::Rsquared = bigint_r("944936681149208446651664254269745548490766851729442924617792859073125903783"); + alt_bn128_Fr::Rcubed = bigint_r("5866548545943845227489894872040244720403868105578784105281690076696998248512"); + alt_bn128_Fr::inv = 0xefffffff; + } + alt_bn128_Fr::num_bits = 254; + alt_bn128_Fr::euler = bigint_r("10944121435919637611123202872628637544274182200208017171849102093287904247808"); + alt_bn128_Fr::s = 28; + alt_bn128_Fr::t = bigint_r("81540058820840996586704275553141814055101440848469862132140264610111"); + alt_bn128_Fr::t_minus_1_over_2 = bigint_r("40770029410420498293352137776570907027550720424234931066070132305055"); + alt_bn128_Fr::multiplicative_generator = alt_bn128_Fr("5"); + alt_bn128_Fr::root_of_unity = alt_bn128_Fr("19103219067921713944291392827692070036145651957329286315305642004821462161904"); + alt_bn128_Fr::nqr = alt_bn128_Fr("5"); + alt_bn128_Fr::nqr_to_t = alt_bn128_Fr("19103219067921713944291392827692070036145651957329286315305642004821462161904"); + + /* parameters for base field Fq */ + + alt_bn128_modulus_q = bigint_q("21888242871839275222246405745257275088696311157297823662689037894645226208583"); + assert(alt_bn128_Fq::modulus_is_valid()); + if (sizeof(mp_limb_t) == 8) + { + alt_bn128_Fq::Rsquared = bigint_q("3096616502983703923843567936837374451735540968419076528771170197431451843209"); + alt_bn128_Fq::Rcubed = bigint_q("14921786541159648185948152738563080959093619838510245177710943249661917737183"); + alt_bn128_Fq::inv = 0x87d20782e4866389; + } + if (sizeof(mp_limb_t) == 4) + { + alt_bn128_Fq::Rsquared = bigint_q("3096616502983703923843567936837374451735540968419076528771170197431451843209"); + alt_bn128_Fq::Rcubed = bigint_q("14921786541159648185948152738563080959093619838510245177710943249661917737183"); + alt_bn128_Fq::inv = 0xe4866389; + } + alt_bn128_Fq::num_bits = 254; + alt_bn128_Fq::euler = bigint_q("10944121435919637611123202872628637544348155578648911831344518947322613104291"); + alt_bn128_Fq::s = 1; + alt_bn128_Fq::t = bigint_q("10944121435919637611123202872628637544348155578648911831344518947322613104291"); + alt_bn128_Fq::t_minus_1_over_2 = bigint_q("5472060717959818805561601436314318772174077789324455915672259473661306552145"); + alt_bn128_Fq::multiplicative_generator = alt_bn128_Fq("3"); + alt_bn128_Fq::root_of_unity = alt_bn128_Fq("21888242871839275222246405745257275088696311157297823662689037894645226208582"); + alt_bn128_Fq::nqr = alt_bn128_Fq("3"); + alt_bn128_Fq::nqr_to_t = alt_bn128_Fq("21888242871839275222246405745257275088696311157297823662689037894645226208582"); + + /* parameters for twist field Fq2 */ + + alt_bn128_Fq2::euler = bigint<2*alt_bn128_q_limbs>("239547588008311421220994022608339370399626158265550411218223901127035046843189118723920525909718935985594116157406550130918127817069793474323196511433944"); + alt_bn128_Fq2::s = 4; + alt_bn128_Fq2::t = bigint<2*alt_bn128_q_limbs>("29943448501038927652624252826042421299953269783193801402277987640879380855398639840490065738714866998199264519675818766364765977133724184290399563929243"); + alt_bn128_Fq2::t_minus_1_over_2 = bigint<2*alt_bn128_q_limbs>("14971724250519463826312126413021210649976634891596900701138993820439690427699319920245032869357433499099632259837909383182382988566862092145199781964621"); + alt_bn128_Fq2::non_residue = alt_bn128_Fq("21888242871839275222246405745257275088696311157297823662689037894645226208582"); + alt_bn128_Fq2::nqr = alt_bn128_Fq2(alt_bn128_Fq("2"),alt_bn128_Fq("1")); + alt_bn128_Fq2::nqr_to_t = alt_bn128_Fq2(alt_bn128_Fq("5033503716262624267312492558379982687175200734934877598599011485707452665730"),alt_bn128_Fq("314498342015008975724433667930697407966947188435857772134235984660852259084")); + alt_bn128_Fq2::Frobenius_coeffs_c1[0] = alt_bn128_Fq("1"); + alt_bn128_Fq2::Frobenius_coeffs_c1[1] = alt_bn128_Fq("21888242871839275222246405745257275088696311157297823662689037894645226208582"); + + /* parameters for Fq6 */ + + alt_bn128_Fq6::euler = bigint<6*alt_bn128_q_limbs>("5498388192958968685942133058043672206732751847567792101833005999610030333730837412886721209788291211298383180141055457431344429976884849349913268061994433794710968384709566373503289284049367666702094574752748221137683704401917587" + "7068998572693741735838873805855113185414083578466773124823719245338616604713715536237007459144818392105176489621967934260959676496778033242067460465148059540293548160766892478385479634355306233598756643954842572490928255038258184"); + alt_bn128_Fq6::s = 4; + alt_bn128_Fq6::t = bigint<6*alt_bn128_q_limbs>("6872985241198710857427666322554590258415939809459740127291257499512537917163546766108401512235364014122978975176319321789180537471106061687391585077493042243388710480886957966879111605061709583377618218440935276422104630502396984" + "633624821586717716979859225731889148176760447308346640602964905667327075589214442029625932393102299013147061202745991782619959562097254155258432558143507442536693520095861559798184954294413279199844580494355321561366031879782273"); + alt_bn128_Fq6::t_minus_1_over_2 = bigint<6*alt_bn128_q_limbs>("3436492620599355428713833161277295129207969904729870063645628749756268958581773383054200756117682007061489487588159660894590268735553030843695792538746521121694355240443478983439555802530854791688809109220467638211052315251198492" + "316812410793358858489929612865944574088380223654173320301482452833663537794607221014812966196551149506573530601372995891309979781048627077629216279071753721268346760047930779899092477147206639599922290247177660780683015939891136"); + alt_bn128_Fq6::non_residue = alt_bn128_Fq2(alt_bn128_Fq("9"),alt_bn128_Fq("1")); + alt_bn128_Fq6::nqr = alt_bn128_Fq6(alt_bn128_Fq2::one(),alt_bn128_Fq2::one(),alt_bn128_Fq2::zero()); + alt_bn128_Fq6::nqr_to_t = alt_bn128_Fq6(alt_bn128_Fq2(alt_bn128_Fq("5033503716262624267312492558379982687175200734934877598599011485707452665730"),alt_bn128_Fq("314498342015008975724433667930697407966947188435857772134235984660852259084")), + alt_bn128_Fq2::zero(),alt_bn128_Fq2::zero()); + alt_bn128_Fq6::Frobenius_coeffs_c1[0] = alt_bn128_Fq2(alt_bn128_Fq("1"),alt_bn128_Fq("0")); + alt_bn128_Fq6::Frobenius_coeffs_c1[1] = alt_bn128_Fq2(alt_bn128_Fq("21575463638280843010398324269430826099269044274347216827212613867836435027261"),alt_bn128_Fq("10307601595873709700152284273816112264069230130616436755625194854815875713954")); + alt_bn128_Fq6::Frobenius_coeffs_c1[2] = alt_bn128_Fq2(alt_bn128_Fq("21888242871839275220042445260109153167277707414472061641714758635765020556616"),alt_bn128_Fq("0")); + alt_bn128_Fq6::Frobenius_coeffs_c1[3] = alt_bn128_Fq2(alt_bn128_Fq("3772000881919853776433695186713858239009073593817195771773381919316419345261"),alt_bn128_Fq("2236595495967245188281701248203181795121068902605861227855261137820944008926")); + alt_bn128_Fq6::Frobenius_coeffs_c1[4] = alt_bn128_Fq2(alt_bn128_Fq("2203960485148121921418603742825762020974279258880205651966"),alt_bn128_Fq("0")); + alt_bn128_Fq6::Frobenius_coeffs_c1[5] = alt_bn128_Fq2(alt_bn128_Fq("18429021223477853657660792034369865839114504446431234726392080002137598044644"),alt_bn128_Fq("9344045779998320333812420223237981029506012124075525679208581902008406485703")); + alt_bn128_Fq6::Frobenius_coeffs_c2[0] = alt_bn128_Fq2(alt_bn128_Fq("1"),alt_bn128_Fq("0")); + alt_bn128_Fq6::Frobenius_coeffs_c2[1] = alt_bn128_Fq2(alt_bn128_Fq("2581911344467009335267311115468803099551665605076196740867805258568234346338"),alt_bn128_Fq("19937756971775647987995932169929341994314640652964949448313374472400716661030")); + alt_bn128_Fq6::Frobenius_coeffs_c2[2] = alt_bn128_Fq2(alt_bn128_Fq("2203960485148121921418603742825762020974279258880205651966"),alt_bn128_Fq("0")); + alt_bn128_Fq6::Frobenius_coeffs_c2[3] = alt_bn128_Fq2(alt_bn128_Fq("5324479202449903542726783395506214481928257762400643279780343368557297135718"),alt_bn128_Fq("16208900380737693084919495127334387981393726419856888799917914180988844123039")); + alt_bn128_Fq6::Frobenius_coeffs_c2[4] = alt_bn128_Fq2(alt_bn128_Fq("21888242871839275220042445260109153167277707414472061641714758635765020556616"),alt_bn128_Fq("0")); + alt_bn128_Fq6::Frobenius_coeffs_c2[5] = alt_bn128_Fq2(alt_bn128_Fq("13981852324922362344252311234282257507216387789820983642040889267519694726527"),alt_bn128_Fq("7629828391165209371577384193250820201684255241773809077146787135900891633097")); + + /* parameters for Fq12 */ + + alt_bn128_Fq12::euler = bigint<12*alt_bn128_q_limbs>("6046454544094118612696716508779587437811568806609539163841022840837511675160439295069809579470726816362285317189074189593010054711753278639030702124756988051901885569977000289997599951414317131996165287196109395898133161740013239" + "9888297521435321796045181656948751979423639329028967870230773431739673019331878848229304257798356000945534097884727669953970987792240845774002479163950538365882113983376282498734078978127251495373970720242630990733199570106949023" + "7762076416585403922810013029850683334917030622308132823590417497097051812125040060283944081016629563604381750765903889723685281433578635694885707011225313483583616375087345107775624111047238927818711997768928884593065817839459018" + "6562743353071320465908984361117040009944460908570918928026578161925375182627523989293890456243197793702483966432294320134848198228187915704499812007832429165557659647468827260733943113908864341788809250341940281027139567362472080"); + alt_bn128_Fq12::s = 5; + alt_bn128_Fq12::t = bigint<12*alt_bn128_q_limbs>("3779034090058824132935447817987242148632230504130961977400639275523444796975274559418630987169204260226428323243171368495631284194845799149394188827973117532438678481235625181248499969633948207497603304497568372436333226087508274" + "9930185950897076122528238535592969987139774580643104918894233394837295637082424280143315161123972500590958811177954793721231867370150528608751549477469086478676321239610176561708799361329532184608731700151644369208249731316843139" + "8601297760365877451756258143656677084323144138942583014744010935685657382578150037677465050635393477252738594228689931077303300895986647309303566882015820927239760234429590692359765069404524329886694998605580552870666136149661886" + "660171459566957529119311522569815000621528806785682433001661135120335948914220249330868153515199862106405247902018395008428012389261744731531238250489526822847353727966801703795871444619304021361800578146371267564196222960154505"); + alt_bn128_Fq12::t_minus_1_over_2 = bigint<12*alt_bn128_q_limbs>("1889517045029412066467723908993621074316115252065480988700319637761722398487637279709315493584602130113214161621585684247815642097422899574697094413986558766219339240617812590624249984816974103748801652248784186218166613043754137" + "4965092975448538061264119267796484993569887290321552459447116697418647818541212140071657580561986250295479405588977396860615933685075264304375774738734543239338160619805088280854399680664766092304365850075822184604124865658421569" + "9300648880182938725878129071828338542161572069471291507372005467842828691289075018838732525317696738626369297114344965538651650447993323654651783441007910463619880117214795346179882534702262164943347499302790276435333068074830943" + "330085729783478764559655761284907500310764403392841216500830567560167974457110124665434076757599931053202623951009197504214006194630872365765619125244763411423676863983400851897935722309652010680900289073185633782098111480077252"); + alt_bn128_Fq12::non_residue = alt_bn128_Fq2(alt_bn128_Fq("9"),alt_bn128_Fq("1")); + alt_bn128_Fq12::nqr = alt_bn128_Fq12(alt_bn128_Fq6::one(), alt_bn128_Fq6::one()); + alt_bn128_Fq12::nqr_to_t = alt_bn128_Fq12(alt_bn128_Fq6::zero(), + alt_bn128_Fq6(alt_bn128_Fq2::zero(),alt_bn128_Fq2(alt_bn128_Fq("7299059822208274084482252430043382812017501266368539931062816119060212104055"),alt_bn128_Fq("9394737973577957017988251966646482882049672572091998406660728871491334118516")),alt_bn128_Fq2::zero())); + alt_bn128_Fq12::Frobenius_coeffs_c1[0] = alt_bn128_Fq2(alt_bn128_Fq("1"),alt_bn128_Fq("0")); + alt_bn128_Fq12::Frobenius_coeffs_c1[1] = alt_bn128_Fq2(alt_bn128_Fq("8376118865763821496583973867626364092589906065868298776909617916018768340080"),alt_bn128_Fq("16469823323077808223889137241176536799009286646108169935659301613961712198316")); + alt_bn128_Fq12::Frobenius_coeffs_c1[2] = alt_bn128_Fq2(alt_bn128_Fq("21888242871839275220042445260109153167277707414472061641714758635765020556617"),alt_bn128_Fq("0")); + alt_bn128_Fq12::Frobenius_coeffs_c1[3] = alt_bn128_Fq2(alt_bn128_Fq("11697423496358154304825782922584725312912383441159505038794027105778954184319"),alt_bn128_Fq("303847389135065887422783454877609941456349188919719272345083954437860409601")); + alt_bn128_Fq12::Frobenius_coeffs_c1[4] = alt_bn128_Fq2(alt_bn128_Fq("21888242871839275220042445260109153167277707414472061641714758635765020556616"),alt_bn128_Fq("0")); + alt_bn128_Fq12::Frobenius_coeffs_c1[5] = alt_bn128_Fq2(alt_bn128_Fq("3321304630594332808241809054958361220322477375291206261884409189760185844239"),alt_bn128_Fq("5722266937896532885780051958958348231143373700109372999374820235121374419868")); + alt_bn128_Fq12::Frobenius_coeffs_c1[6] = alt_bn128_Fq2(alt_bn128_Fq("21888242871839275222246405745257275088696311157297823662689037894645226208582"),alt_bn128_Fq("0")); + alt_bn128_Fq12::Frobenius_coeffs_c1[7] = alt_bn128_Fq2(alt_bn128_Fq("13512124006075453725662431877630910996106405091429524885779419978626457868503"),alt_bn128_Fq("5418419548761466998357268504080738289687024511189653727029736280683514010267")); + alt_bn128_Fq12::Frobenius_coeffs_c1[8] = alt_bn128_Fq2(alt_bn128_Fq("2203960485148121921418603742825762020974279258880205651966"),alt_bn128_Fq("0")); + alt_bn128_Fq12::Frobenius_coeffs_c1[9] = alt_bn128_Fq2(alt_bn128_Fq("10190819375481120917420622822672549775783927716138318623895010788866272024264"),alt_bn128_Fq("21584395482704209334823622290379665147239961968378104390343953940207365798982")); + alt_bn128_Fq12::Frobenius_coeffs_c1[10] = alt_bn128_Fq2(alt_bn128_Fq("2203960485148121921418603742825762020974279258880205651967"),alt_bn128_Fq("0")); + alt_bn128_Fq12::Frobenius_coeffs_c1[11] = alt_bn128_Fq2(alt_bn128_Fq("18566938241244942414004596690298913868373833782006617400804628704885040364344"),alt_bn128_Fq("16165975933942742336466353786298926857552937457188450663314217659523851788715")); +} + +} // libff diff --git a/libff/algebra/curves/alt_bn128/alt_bn128_fields.hpp b/libff/algebra/curves/alt_bn128/alt_bn128_fields.hpp new file mode 100644 index 00000000..dd1d12b8 --- /dev/null +++ b/libff/algebra/curves/alt_bn128/alt_bn128_fields.hpp @@ -0,0 +1,36 @@ +/** @file + ***************************************************************************** + * @author This file is part of libff, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef ALT_BN128_FIELDS_HPP_ +#define ALT_BN128_FIELDS_HPP_ +#include +#include +#include +#include + +namespace libff { + +const mp_size_t alt_bn128_r_bitcount = 254; +const mp_size_t alt_bn128_q_bitcount = 254; + +const mp_size_t alt_bn128_r_limbs = (alt_bn128_r_bitcount+GMP_NUMB_BITS-1)/GMP_NUMB_BITS; +const mp_size_t alt_bn128_q_limbs = (alt_bn128_q_bitcount+GMP_NUMB_BITS-1)/GMP_NUMB_BITS; + +extern bigint alt_bn128_modulus_r; +extern bigint alt_bn128_modulus_q; + +typedef Fp_model alt_bn128_Fr; +typedef Fp_model alt_bn128_Fq; +typedef Fp2_model alt_bn128_Fq2; +typedef Fp6_3over2_model alt_bn128_Fq6; +typedef Fp12_2over3over2_model alt_bn128_Fq12; +typedef alt_bn128_Fq12 alt_bn128_GT; + +void init_alt_bn128_fields(); + +} // libff +#endif // ALT_BN128_FIELDS_HPP_ diff --git a/libff/algebra/curves/alt_bn128/alt_bn128_g1.cpp b/libff/algebra/curves/alt_bn128/alt_bn128_g1.cpp index 8be6340a..f402ad90 100755 --- a/libff/algebra/curves/alt_bn128/alt_bn128_g1.cpp +++ b/libff/algebra/curves/alt_bn128/alt_bn128_g1.cpp @@ -9,6 +9,8 @@ namespace libff { +using std::size_t; + #ifdef PROFILE_OP_COUNTS long long alt_bn128_G1::add_cnt = 0; long long alt_bn128_G1::dbl_cnt = 0; diff --git a/libff/algebra/curves/alt_bn128/alt_bn128_g1.hpp b/libff/algebra/curves/alt_bn128/alt_bn128_g1.hpp index 232513ce..fb4b9f8a 100755 --- a/libff/algebra/curves/alt_bn128/alt_bn128_g1.hpp +++ b/libff/algebra/curves/alt_bn128/alt_bn128_g1.hpp @@ -65,8 +65,8 @@ class alt_bn128_G1 { static alt_bn128_G1 one(); static alt_bn128_G1 random_element(); - static size_t size_in_bits() { return base_field::size_in_bits() + 1; } - static bigint base_field_char() { return base_field::field_char(); } + static std::size_t size_in_bits() { return base_field::size_in_bits() + 1; } + static bigint field_char() { return base_field::field_char(); } static bigint order() { return scalar_field::field_char(); } friend std::ostream& operator<<(std::ostream &out, const alt_bn128_G1 &g); diff --git a/libff/algebra/curves/alt_bn128/alt_bn128_g2.hpp b/libff/algebra/curves/alt_bn128/alt_bn128_g2.hpp index a22c06f3..cdadf29c 100755 --- a/libff/algebra/curves/alt_bn128/alt_bn128_g2.hpp +++ b/libff/algebra/curves/alt_bn128/alt_bn128_g2.hpp @@ -69,8 +69,8 @@ class alt_bn128_G2 { static alt_bn128_G2 one(); static alt_bn128_G2 random_element(); - static size_t size_in_bits() { return twist_field::size_in_bits() + 1; } - static bigint base_field_char() { return base_field::field_char(); } + static std::size_t size_in_bits() { return twist_field::size_in_bits() + 1; } + static bigint field_char() { return base_field::field_char(); } static bigint order() { return scalar_field::field_char(); } friend std::ostream& operator<<(std::ostream &out, const alt_bn128_G2 &g); diff --git a/libff/algebra/curves/alt_bn128/alt_bn128_init.cpp b/libff/algebra/curves/alt_bn128/alt_bn128_init.cpp index 32f6ba8b..ab9dade3 100755 --- a/libff/algebra/curves/alt_bn128/alt_bn128_init.cpp +++ b/libff/algebra/curves/alt_bn128/alt_bn128_init.cpp @@ -11,9 +11,6 @@ namespace libff { -bigint alt_bn128_modulus_r; -bigint alt_bn128_modulus_q; - alt_bn128_Fq alt_bn128_coeff_b; alt_bn128_Fq2 alt_bn128_twist; alt_bn128_Fq2 alt_bn128_twist_coeff_b; @@ -30,104 +27,7 @@ bool alt_bn128_final_exponent_is_z_neg; void init_alt_bn128_params() { - typedef bigint bigint_r; - typedef bigint bigint_q; - - assert(sizeof(mp_limb_t) == 8 || sizeof(mp_limb_t) == 4); // Montgomery assumes this - - /* parameters for scalar field Fr */ - - alt_bn128_modulus_r = bigint_r("21888242871839275222246405745257275088548364400416034343698204186575808495617"); - assert(alt_bn128_Fr::modulus_is_valid()); - if (sizeof(mp_limb_t) == 8) - { - alt_bn128_Fr::Rsquared = bigint_r("944936681149208446651664254269745548490766851729442924617792859073125903783"); - alt_bn128_Fr::Rcubed = bigint_r("5866548545943845227489894872040244720403868105578784105281690076696998248512"); - alt_bn128_Fr::inv = 0xc2e1f593efffffff; - } - if (sizeof(mp_limb_t) == 4) - { - alt_bn128_Fr::Rsquared = bigint_r("944936681149208446651664254269745548490766851729442924617792859073125903783"); - alt_bn128_Fr::Rcubed = bigint_r("5866548545943845227489894872040244720403868105578784105281690076696998248512"); - alt_bn128_Fr::inv = 0xefffffff; - } - alt_bn128_Fr::num_bits = 254; - alt_bn128_Fr::euler = bigint_r("10944121435919637611123202872628637544274182200208017171849102093287904247808"); - alt_bn128_Fr::s = 28; - alt_bn128_Fr::t = bigint_r("81540058820840996586704275553141814055101440848469862132140264610111"); - alt_bn128_Fr::t_minus_1_over_2 = bigint_r("40770029410420498293352137776570907027550720424234931066070132305055"); - alt_bn128_Fr::multiplicative_generator = alt_bn128_Fr("5"); - alt_bn128_Fr::root_of_unity = alt_bn128_Fr("19103219067921713944291392827692070036145651957329286315305642004821462161904"); - alt_bn128_Fr::nqr = alt_bn128_Fr("5"); - alt_bn128_Fr::nqr_to_t = alt_bn128_Fr("19103219067921713944291392827692070036145651957329286315305642004821462161904"); - - /* parameters for base field Fq */ - - alt_bn128_modulus_q = bigint_q("21888242871839275222246405745257275088696311157297823662689037894645226208583"); - assert(alt_bn128_Fq::modulus_is_valid()); - if (sizeof(mp_limb_t) == 8) - { - alt_bn128_Fq::Rsquared = bigint_q("3096616502983703923843567936837374451735540968419076528771170197431451843209"); - alt_bn128_Fq::Rcubed = bigint_q("14921786541159648185948152738563080959093619838510245177710943249661917737183"); - alt_bn128_Fq::inv = 0x87d20782e4866389; - } - if (sizeof(mp_limb_t) == 4) - { - alt_bn128_Fq::Rsquared = bigint_q("3096616502983703923843567936837374451735540968419076528771170197431451843209"); - alt_bn128_Fq::Rcubed = bigint_q("14921786541159648185948152738563080959093619838510245177710943249661917737183"); - alt_bn128_Fq::inv = 0xe4866389; - } - alt_bn128_Fq::num_bits = 254; - alt_bn128_Fq::euler = bigint_q("10944121435919637611123202872628637544348155578648911831344518947322613104291"); - alt_bn128_Fq::s = 1; - alt_bn128_Fq::t = bigint_q("10944121435919637611123202872628637544348155578648911831344518947322613104291"); - alt_bn128_Fq::t_minus_1_over_2 = bigint_q("5472060717959818805561601436314318772174077789324455915672259473661306552145"); - alt_bn128_Fq::multiplicative_generator = alt_bn128_Fq("3"); - alt_bn128_Fq::root_of_unity = alt_bn128_Fq("21888242871839275222246405745257275088696311157297823662689037894645226208582"); - alt_bn128_Fq::nqr = alt_bn128_Fq("3"); - alt_bn128_Fq::nqr_to_t = alt_bn128_Fq("21888242871839275222246405745257275088696311157297823662689037894645226208582"); - - /* parameters for twist field Fq2 */ - alt_bn128_Fq2::euler = bigint<2*alt_bn128_q_limbs>("239547588008311421220994022608339370399626158265550411218223901127035046843189118723920525909718935985594116157406550130918127817069793474323196511433944"); - alt_bn128_Fq2::s = 4; - alt_bn128_Fq2::t = bigint<2*alt_bn128_q_limbs>("29943448501038927652624252826042421299953269783193801402277987640879380855398639840490065738714866998199264519675818766364765977133724184290399563929243"); - alt_bn128_Fq2::t_minus_1_over_2 = bigint<2*alt_bn128_q_limbs>("14971724250519463826312126413021210649976634891596900701138993820439690427699319920245032869357433499099632259837909383182382988566862092145199781964621"); - alt_bn128_Fq2::non_residue = alt_bn128_Fq("21888242871839275222246405745257275088696311157297823662689037894645226208582"); - alt_bn128_Fq2::nqr = alt_bn128_Fq2(alt_bn128_Fq("2"),alt_bn128_Fq("1")); - alt_bn128_Fq2::nqr_to_t = alt_bn128_Fq2(alt_bn128_Fq("5033503716262624267312492558379982687175200734934877598599011485707452665730"),alt_bn128_Fq("314498342015008975724433667930697407966947188435857772134235984660852259084")); - alt_bn128_Fq2::Frobenius_coeffs_c1[0] = alt_bn128_Fq("1"); - alt_bn128_Fq2::Frobenius_coeffs_c1[1] = alt_bn128_Fq("21888242871839275222246405745257275088696311157297823662689037894645226208582"); - - /* parameters for Fq6 */ - alt_bn128_Fq6::non_residue = alt_bn128_Fq2(alt_bn128_Fq("9"),alt_bn128_Fq("1")); - alt_bn128_Fq6::Frobenius_coeffs_c1[0] = alt_bn128_Fq2(alt_bn128_Fq("1"),alt_bn128_Fq("0")); - alt_bn128_Fq6::Frobenius_coeffs_c1[1] = alt_bn128_Fq2(alt_bn128_Fq("21575463638280843010398324269430826099269044274347216827212613867836435027261"),alt_bn128_Fq("10307601595873709700152284273816112264069230130616436755625194854815875713954")); - alt_bn128_Fq6::Frobenius_coeffs_c1[2] = alt_bn128_Fq2(alt_bn128_Fq("21888242871839275220042445260109153167277707414472061641714758635765020556616"),alt_bn128_Fq("0")); - alt_bn128_Fq6::Frobenius_coeffs_c1[3] = alt_bn128_Fq2(alt_bn128_Fq("3772000881919853776433695186713858239009073593817195771773381919316419345261"),alt_bn128_Fq("2236595495967245188281701248203181795121068902605861227855261137820944008926")); - alt_bn128_Fq6::Frobenius_coeffs_c1[4] = alt_bn128_Fq2(alt_bn128_Fq("2203960485148121921418603742825762020974279258880205651966"),alt_bn128_Fq("0")); - alt_bn128_Fq6::Frobenius_coeffs_c1[5] = alt_bn128_Fq2(alt_bn128_Fq("18429021223477853657660792034369865839114504446431234726392080002137598044644"),alt_bn128_Fq("9344045779998320333812420223237981029506012124075525679208581902008406485703")); - alt_bn128_Fq6::Frobenius_coeffs_c2[0] = alt_bn128_Fq2(alt_bn128_Fq("1"),alt_bn128_Fq("0")); - alt_bn128_Fq6::Frobenius_coeffs_c2[1] = alt_bn128_Fq2(alt_bn128_Fq("2581911344467009335267311115468803099551665605076196740867805258568234346338"),alt_bn128_Fq("19937756971775647987995932169929341994314640652964949448313374472400716661030")); - alt_bn128_Fq6::Frobenius_coeffs_c2[2] = alt_bn128_Fq2(alt_bn128_Fq("2203960485148121921418603742825762020974279258880205651966"),alt_bn128_Fq("0")); - alt_bn128_Fq6::Frobenius_coeffs_c2[3] = alt_bn128_Fq2(alt_bn128_Fq("5324479202449903542726783395506214481928257762400643279780343368557297135718"),alt_bn128_Fq("16208900380737693084919495127334387981393726419856888799917914180988844123039")); - alt_bn128_Fq6::Frobenius_coeffs_c2[4] = alt_bn128_Fq2(alt_bn128_Fq("21888242871839275220042445260109153167277707414472061641714758635765020556616"),alt_bn128_Fq("0")); - alt_bn128_Fq6::Frobenius_coeffs_c2[5] = alt_bn128_Fq2(alt_bn128_Fq("13981852324922362344252311234282257507216387789820983642040889267519694726527"),alt_bn128_Fq("7629828391165209371577384193250820201684255241773809077146787135900891633097")); - - /* parameters for Fq12 */ - - alt_bn128_Fq12::non_residue = alt_bn128_Fq2(alt_bn128_Fq("9"),alt_bn128_Fq("1")); - alt_bn128_Fq12::Frobenius_coeffs_c1[0] = alt_bn128_Fq2(alt_bn128_Fq("1"),alt_bn128_Fq("0")); - alt_bn128_Fq12::Frobenius_coeffs_c1[1] = alt_bn128_Fq2(alt_bn128_Fq("8376118865763821496583973867626364092589906065868298776909617916018768340080"),alt_bn128_Fq("16469823323077808223889137241176536799009286646108169935659301613961712198316")); - alt_bn128_Fq12::Frobenius_coeffs_c1[2] = alt_bn128_Fq2(alt_bn128_Fq("21888242871839275220042445260109153167277707414472061641714758635765020556617"),alt_bn128_Fq("0")); - alt_bn128_Fq12::Frobenius_coeffs_c1[3] = alt_bn128_Fq2(alt_bn128_Fq("11697423496358154304825782922584725312912383441159505038794027105778954184319"),alt_bn128_Fq("303847389135065887422783454877609941456349188919719272345083954437860409601")); - alt_bn128_Fq12::Frobenius_coeffs_c1[4] = alt_bn128_Fq2(alt_bn128_Fq("21888242871839275220042445260109153167277707414472061641714758635765020556616"),alt_bn128_Fq("0")); - alt_bn128_Fq12::Frobenius_coeffs_c1[5] = alt_bn128_Fq2(alt_bn128_Fq("3321304630594332808241809054958361220322477375291206261884409189760185844239"),alt_bn128_Fq("5722266937896532885780051958958348231143373700109372999374820235121374419868")); - alt_bn128_Fq12::Frobenius_coeffs_c1[6] = alt_bn128_Fq2(alt_bn128_Fq("21888242871839275222246405745257275088696311157297823662689037894645226208582"),alt_bn128_Fq("0")); - alt_bn128_Fq12::Frobenius_coeffs_c1[7] = alt_bn128_Fq2(alt_bn128_Fq("13512124006075453725662431877630910996106405091429524885779419978626457868503"),alt_bn128_Fq("5418419548761466998357268504080738289687024511189653727029736280683514010267")); - alt_bn128_Fq12::Frobenius_coeffs_c1[8] = alt_bn128_Fq2(alt_bn128_Fq("2203960485148121921418603742825762020974279258880205651966"),alt_bn128_Fq("0")); - alt_bn128_Fq12::Frobenius_coeffs_c1[9] = alt_bn128_Fq2(alt_bn128_Fq("10190819375481120917420622822672549775783927716138318623895010788866272024264"),alt_bn128_Fq("21584395482704209334823622290379665147239961968378104390343953940207365798982")); - alt_bn128_Fq12::Frobenius_coeffs_c1[10] = alt_bn128_Fq2(alt_bn128_Fq("2203960485148121921418603742825762020974279258880205651967"),alt_bn128_Fq("0")); - alt_bn128_Fq12::Frobenius_coeffs_c1[11] = alt_bn128_Fq2(alt_bn128_Fq("18566938241244942414004596690298913868373833782006617400804628704885040364344"),alt_bn128_Fq("16165975933942742336466353786298926857552937457188450663314217659523851788715")); + init_alt_bn128_fields(); /* choice of short Weierstrass curve and its twist */ @@ -269,10 +169,10 @@ void init_alt_bn128_params() /* pairing parameters */ - alt_bn128_ate_loop_count = bigint_q("29793968203157093288"); + alt_bn128_ate_loop_count = bigint("29793968203157093288"); alt_bn128_ate_is_loop_count_neg = false; alt_bn128_final_exponent = bigint<12*alt_bn128_q_limbs>("552484233613224096312617126783173147097382103762957654188882734314196910839907541213974502761540629817009608548654680343627701153829446747810907373256841551006201639677726139946029199968412598804882391702273019083653272047566316584365559776493027495458238373902875937659943504873220554161550525926302303331747463515644711876653177129578303191095900909191624817826566688241804408081892785725967931714097716709526092261278071952560171111444072049229123565057483750161460024353346284167282452756217662335528813519139808291170539072125381230815729071544861602750936964829313608137325426383735122175229541155376346436093930287402089517426973178917569713384748081827255472576937471496195752727188261435633271238710131736096299798168852925540549342330775279877006784354801422249722573783561685179618816480037695005515426162362431072245638324744480"); - alt_bn128_final_exponent_z = bigint_q("4965661367192848881"); + alt_bn128_final_exponent_z = bigint("4965661367192848881"); alt_bn128_final_exponent_is_z_neg = false; } diff --git a/libff/algebra/curves/alt_bn128/alt_bn128_init.hpp b/libff/algebra/curves/alt_bn128/alt_bn128_init.hpp index 7dfabe70..ab284bb8 100755 --- a/libff/algebra/curves/alt_bn128/alt_bn128_init.hpp +++ b/libff/algebra/curves/alt_bn128/alt_bn128_init.hpp @@ -8,29 +8,10 @@ #ifndef ALT_BN128_INIT_HPP_ #define ALT_BN128_INIT_HPP_ #include -#include -#include -#include -#include +#include namespace libff { -const mp_size_t alt_bn128_r_bitcount = 254; -const mp_size_t alt_bn128_q_bitcount = 254; - -const mp_size_t alt_bn128_r_limbs = (alt_bn128_r_bitcount+GMP_NUMB_BITS-1)/GMP_NUMB_BITS; -const mp_size_t alt_bn128_q_limbs = (alt_bn128_q_bitcount+GMP_NUMB_BITS-1)/GMP_NUMB_BITS; - -extern bigint alt_bn128_modulus_r; -extern bigint alt_bn128_modulus_q; - -typedef Fp_model alt_bn128_Fr; -typedef Fp_model alt_bn128_Fq; -typedef Fp2_model alt_bn128_Fq2; -typedef Fp6_3over2_model alt_bn128_Fq6; -typedef Fp12_2over3over2_model alt_bn128_Fq12; -typedef alt_bn128_Fq12 alt_bn128_GT; - // parameters for Barreto--Naehrig curve E/Fq : y^2 = x^3 + b extern alt_bn128_Fq alt_bn128_coeff_b; // parameters for twisted Barreto--Naehrig curve E'/Fq2 : y^2 = x^3 + b/xi diff --git a/libff/algebra/curves/alt_bn128/alt_bn128_pairing.cpp b/libff/algebra/curves/alt_bn128/alt_bn128_pairing.cpp index 7b79540e..50feb409 100755 --- a/libff/algebra/curves/alt_bn128/alt_bn128_pairing.cpp +++ b/libff/algebra/curves/alt_bn128/alt_bn128_pairing.cpp @@ -15,6 +15,8 @@ namespace libff { +using std::size_t; + bool alt_bn128_ate_G1_precomp::operator==(const alt_bn128_ate_G1_precomp &other) const { return (this->PX == other.PX && diff --git a/libff/algebra/curves/bn128/bn128_fields.cpp b/libff/algebra/curves/bn128/bn128_fields.cpp new file mode 100644 index 00000000..183aaa43 --- /dev/null +++ b/libff/algebra/curves/bn128/bn128_fields.cpp @@ -0,0 +1,75 @@ +/** @file + ***************************************************************************** + * @author This file is part of libff, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#include + +namespace libff { + +bigint bn128_modulus_r; +bigint bn128_modulus_q; + +void init_bn128_fields() +{ + bn::Param::init(); // init ate-pairing library + + typedef bigint bigint_r; + typedef bigint bigint_q; + + assert(sizeof(mp_limb_t) == 8 || sizeof(mp_limb_t) == 4); // Montgomery assumes this + + /* parameters for scalar field Fr */ + bn128_modulus_r = bigint_r("21888242871839275222246405745257275088548364400416034343698204186575808495617"); + assert(bn128_Fr::modulus_is_valid()); + if (sizeof(mp_limb_t) == 8) + { + bn128_Fr::Rsquared = bigint_r("944936681149208446651664254269745548490766851729442924617792859073125903783"); + bn128_Fr::Rcubed = bigint_r("5866548545943845227489894872040244720403868105578784105281690076696998248512"); + bn128_Fr::inv = 0xc2e1f593efffffff; + } + if (sizeof(mp_limb_t) == 4) + { + bn128_Fr::Rsquared = bigint_r("944936681149208446651664254269745548490766851729442924617792859073125903783"); + bn128_Fr::Rcubed = bigint_r("5866548545943845227489894872040244720403868105578784105281690076696998248512"); + bn128_Fr::inv = 0xefffffff; + } + bn128_Fr::num_bits = 254; + bn128_Fr::euler = bigint_r("10944121435919637611123202872628637544274182200208017171849102093287904247808"); + bn128_Fr::s = 28; + bn128_Fr::t = bigint_r("81540058820840996586704275553141814055101440848469862132140264610111"); + bn128_Fr::t_minus_1_over_2 = bigint_r("40770029410420498293352137776570907027550720424234931066070132305055"); + bn128_Fr::multiplicative_generator = bn128_Fr("5"); + bn128_Fr::root_of_unity = bn128_Fr("19103219067921713944291392827692070036145651957329286315305642004821462161904"); + bn128_Fr::nqr = bn128_Fr("5"); + bn128_Fr::nqr_to_t = bn128_Fr("19103219067921713944291392827692070036145651957329286315305642004821462161904"); + + /* parameters for base field Fq */ + bn128_modulus_q = bigint_q("21888242871839275222246405745257275088696311157297823662689037894645226208583"); + assert(bn128_Fq::modulus_is_valid()); + if (sizeof(mp_limb_t) == 8) + { + bn128_Fq::Rsquared = bigint_q("3096616502983703923843567936837374451735540968419076528771170197431451843209"); + bn128_Fq::Rcubed = bigint_q("14921786541159648185948152738563080959093619838510245177710943249661917737183"); + bn128_Fq::inv = 0x87d20782e4866389; + } + if (sizeof(mp_limb_t) == 4) + { + bn128_Fq::Rsquared = bigint_q("3096616502983703923843567936837374451735540968419076528771170197431451843209"); + bn128_Fq::Rcubed = bigint_q("14921786541159648185948152738563080959093619838510245177710943249661917737183"); + bn128_Fq::inv = 0xe4866389; + } + bn128_Fq::num_bits = 254; + bn128_Fq::euler = bigint_q("10944121435919637611123202872628637544348155578648911831344518947322613104291"); + bn128_Fq::s = 1; + bn128_Fq::t = bigint_q("10944121435919637611123202872628637544348155578648911831344518947322613104291"); + bn128_Fq::t_minus_1_over_2 = bigint_q("5472060717959818805561601436314318772174077789324455915672259473661306552145"); + bn128_Fq::multiplicative_generator = bn128_Fq("3"); + bn128_Fq::root_of_unity = bn128_Fq("21888242871839275222246405745257275088696311157297823662689037894645226208582"); + bn128_Fq::nqr = bn128_Fq("3"); + bn128_Fq::nqr_to_t = bn128_Fq("21888242871839275222246405745257275088696311157297823662689037894645226208582"); +} + +} // libff diff --git a/libff/algebra/curves/bn128/bn128_fields.hpp b/libff/algebra/curves/bn128/bn128_fields.hpp new file mode 100644 index 00000000..df8b9b48 --- /dev/null +++ b/libff/algebra/curves/bn128/bn128_fields.hpp @@ -0,0 +1,30 @@ +/** @file + ***************************************************************************** + * @author This file is part of libff, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef BN128_FIELDS_HPP_ +#define BN128_FIELDS_HPP_ +#include "depends/ate-pairing/include/bn.h" +#include + +namespace libff { + +const mp_size_t bn128_r_bitcount = 254; +const mp_size_t bn128_q_bitcount = 254; + +const mp_size_t bn128_r_limbs = (bn128_r_bitcount+GMP_NUMB_BITS-1)/GMP_NUMB_BITS; +const mp_size_t bn128_q_limbs = (bn128_q_bitcount+GMP_NUMB_BITS-1)/GMP_NUMB_BITS; + +extern bigint bn128_modulus_r; +extern bigint bn128_modulus_q; + +typedef Fp_model bn128_Fr; +typedef Fp_model bn128_Fq; + +void init_bn128_fields(); + +} // libff +#endif // BN128_FIELDS_HPP_ diff --git a/libff/algebra/curves/bn128/bn128_g1.cpp b/libff/algebra/curves/bn128/bn128_g1.cpp index 6d1e8b2b..adad071c 100755 --- a/libff/algebra/curves/bn128/bn128_g1.cpp +++ b/libff/algebra/curves/bn128/bn128_g1.cpp @@ -10,6 +10,8 @@ namespace libff { +using std::size_t; + #ifdef PROFILE_OP_COUNTS long long bn128_G1::add_cnt = 0; long long bn128_G1::dbl_cnt = 0; diff --git a/libff/algebra/curves/bn128/bn128_g1.hpp b/libff/algebra/curves/bn128/bn128_g1.hpp index 02a4ad0a..ba7130a4 100755 --- a/libff/algebra/curves/bn128/bn128_g1.hpp +++ b/libff/algebra/curves/bn128/bn128_g1.hpp @@ -69,8 +69,8 @@ class bn128_G1 { static bn128_G1 one(); static bn128_G1 random_element(); - static size_t size_in_bits() { return bn128_Fq::size_in_bits() + 1; } - static bigint base_field_char() { return base_field::field_char(); } + static std::size_t size_in_bits() { return bn128_Fq::size_in_bits() + 1; } + static bigint field_char() { return base_field::field_char(); } static bigint order() { return scalar_field::field_char(); } friend std::ostream& operator<<(std::ostream &out, const bn128_G1 &g); diff --git a/libff/algebra/curves/bn128/bn128_g2.cpp b/libff/algebra/curves/bn128/bn128_g2.cpp index fa59d3ae..de871ce1 100755 --- a/libff/algebra/curves/bn128/bn128_g2.cpp +++ b/libff/algebra/curves/bn128/bn128_g2.cpp @@ -10,6 +10,8 @@ namespace libff { +using std::size_t; + #ifdef PROFILE_OP_COUNTS long long bn128_G2::add_cnt = 0; long long bn128_G2::dbl_cnt = 0; diff --git a/libff/algebra/curves/bn128/bn128_g2.hpp b/libff/algebra/curves/bn128/bn128_g2.hpp index df06bf6d..42869353 100755 --- a/libff/algebra/curves/bn128/bn128_g2.hpp +++ b/libff/algebra/curves/bn128/bn128_g2.hpp @@ -70,8 +70,8 @@ class bn128_G2 { static bn128_G2 one(); static bn128_G2 random_element(); - static size_t size_in_bits() { return 2*base_field::size_in_bits() + 1; } - static bigint base_field_char() { return base_field::field_char(); } + static std::size_t size_in_bits() { return 2*base_field::size_in_bits() + 1; } + static bigint field_char() { return base_field::field_char(); } static bigint order() { return scalar_field::field_char(); } friend std::ostream& operator<<(std::ostream &out, const bn128_G2 &g); diff --git a/libff/algebra/curves/bn128/bn128_gt.hpp b/libff/algebra/curves/bn128/bn128_gt.hpp index a4e18548..aa172b14 100755 --- a/libff/algebra/curves/bn128/bn128_gt.hpp +++ b/libff/algebra/curves/bn128/bn128_gt.hpp @@ -11,8 +11,8 @@ #include "depends/ate-pairing/include/bn.h" -#include -#include +#include +#include namespace libff { diff --git a/libff/algebra/curves/bn128/bn128_init.cpp b/libff/algebra/curves/bn128/bn128_init.cpp index 9b5f9eb7..61265acf 100755 --- a/libff/algebra/curves/bn128/bn128_init.cpp +++ b/libff/algebra/curves/bn128/bn128_init.cpp @@ -12,9 +12,6 @@ namespace libff { -bigint bn128_modulus_r; -bigint bn128_modulus_q; - bn::Fp bn128_coeff_b; size_t bn128_Fq_s; bn::Fp bn128_Fq_nqr_to_t; @@ -27,62 +24,7 @@ mie::Vuint bn128_Fq2_t_minus_1_over_2; void init_bn128_params() { - bn::Param::init(); // init ate-pairing library - - typedef bigint bigint_r; - typedef bigint bigint_q; - - assert(sizeof(mp_limb_t) == 8 || sizeof(mp_limb_t) == 4); // Montgomery assumes this - - /* parameters for scalar field Fr */ - bn128_modulus_r = bigint_r("21888242871839275222246405745257275088548364400416034343698204186575808495617"); - assert(bn128_Fr::modulus_is_valid()); - if (sizeof(mp_limb_t) == 8) - { - bn128_Fr::Rsquared = bigint_r("944936681149208446651664254269745548490766851729442924617792859073125903783"); - bn128_Fr::Rcubed = bigint_r("5866548545943845227489894872040244720403868105578784105281690076696998248512"); - bn128_Fr::inv = 0xc2e1f593efffffff; - } - if (sizeof(mp_limb_t) == 4) - { - bn128_Fr::Rsquared = bigint_r("944936681149208446651664254269745548490766851729442924617792859073125903783"); - bn128_Fr::Rcubed = bigint_r("5866548545943845227489894872040244720403868105578784105281690076696998248512"); - bn128_Fr::inv = 0xefffffff; - } - bn128_Fr::num_bits = 254; - bn128_Fr::euler = bigint_r("10944121435919637611123202872628637544274182200208017171849102093287904247808"); - bn128_Fr::s = 28; - bn128_Fr::t = bigint_r("81540058820840996586704275553141814055101440848469862132140264610111"); - bn128_Fr::t_minus_1_over_2 = bigint_r("40770029410420498293352137776570907027550720424234931066070132305055"); - bn128_Fr::multiplicative_generator = bn128_Fr("5"); - bn128_Fr::root_of_unity = bn128_Fr("19103219067921713944291392827692070036145651957329286315305642004821462161904"); - bn128_Fr::nqr = bn128_Fr("5"); - bn128_Fr::nqr_to_t = bn128_Fr("19103219067921713944291392827692070036145651957329286315305642004821462161904"); - - /* parameters for base field Fq */ - bn128_modulus_q = bigint_q("21888242871839275222246405745257275088696311157297823662689037894645226208583"); - assert(bn128_Fq::modulus_is_valid()); - if (sizeof(mp_limb_t) == 8) - { - bn128_Fq::Rsquared = bigint_q("3096616502983703923843567936837374451735540968419076528771170197431451843209"); - bn128_Fq::Rcubed = bigint_q("14921786541159648185948152738563080959093619838510245177710943249661917737183"); - bn128_Fq::inv = 0x87d20782e4866389; - } - if (sizeof(mp_limb_t) == 4) - { - bn128_Fq::Rsquared = bigint_q("3096616502983703923843567936837374451735540968419076528771170197431451843209"); - bn128_Fq::Rcubed = bigint_q("14921786541159648185948152738563080959093619838510245177710943249661917737183"); - bn128_Fq::inv = 0xe4866389; - } - bn128_Fq::num_bits = 254; - bn128_Fq::euler = bigint_q("10944121435919637611123202872628637544348155578648911831344518947322613104291"); - bn128_Fq::s = 1; - bn128_Fq::t = bigint_q("10944121435919637611123202872628637544348155578648911831344518947322613104291"); - bn128_Fq::t_minus_1_over_2 = bigint_q("5472060717959818805561601436314318772174077789324455915672259473661306552145"); - bn128_Fq::multiplicative_generator = bn128_Fq("3"); - bn128_Fq::root_of_unity = bn128_Fq("21888242871839275222246405745257275088696311157297823662689037894645226208582"); - bn128_Fq::nqr = bn128_Fq("3"); - bn128_Fq::nqr_to_t = bn128_Fq("21888242871839275222246405745257275088696311157297823662689037894645226208582"); + init_bn128_fields(); /* additional parameters for square roots in Fq/Fq2 */ bn128_coeff_b = bn::Fp(3); diff --git a/libff/algebra/curves/bn128/bn128_init.hpp b/libff/algebra/curves/bn128/bn128_init.hpp index dc7fdbf8..34746473 100755 --- a/libff/algebra/curves/bn128/bn128_init.hpp +++ b/libff/algebra/curves/bn128/bn128_init.hpp @@ -10,32 +10,20 @@ #include "depends/ate-pairing/include/bn.h" #include -#include +#include namespace libff { -const mp_size_t bn128_r_bitcount = 254; -const mp_size_t bn128_q_bitcount = 254; - -const mp_size_t bn128_r_limbs = (bn128_r_bitcount+GMP_NUMB_BITS-1)/GMP_NUMB_BITS; -const mp_size_t bn128_q_limbs = (bn128_q_bitcount+GMP_NUMB_BITS-1)/GMP_NUMB_BITS; - -extern bigint bn128_modulus_r; -extern bigint bn128_modulus_q; - extern bn::Fp bn128_coeff_b; -extern size_t bn128_Fq_s; +extern std::size_t bn128_Fq_s; extern bn::Fp bn128_Fq_nqr_to_t; extern mie::Vuint bn128_Fq_t_minus_1_over_2; extern bn::Fp2 bn128_twist_coeff_b; -extern size_t bn128_Fq2_s; +extern std::size_t bn128_Fq2_s; extern bn::Fp2 bn128_Fq2_nqr_to_t; extern mie::Vuint bn128_Fq2_t_minus_1_over_2; -typedef Fp_model bn128_Fr; -typedef Fp_model bn128_Fq; - void init_bn128_params(); class bn128_G1; diff --git a/libff/algebra/curves/bn128/bn128_pairing.cpp b/libff/algebra/curves/bn128/bn128_pairing.cpp index 4b211676..9c5b14a1 100755 --- a/libff/algebra/curves/bn128/bn128_pairing.cpp +++ b/libff/algebra/curves/bn128/bn128_pairing.cpp @@ -19,6 +19,8 @@ namespace libff { +using std::size_t; + bool bn128_ate_G1_precomp::operator==(const bn128_ate_G1_precomp &other) const { return (this->P[0] == other.P[0] && diff --git a/libff/algebra/curves/curve_utils.hpp b/libff/algebra/curves/curve_utils.hpp index aff03ba0..f3e0e192 100755 --- a/libff/algebra/curves/curve_utils.hpp +++ b/libff/algebra/curves/curve_utils.hpp @@ -9,7 +9,7 @@ #define CURVE_UTILS_HPP_ #include -#include +#include namespace libff { diff --git a/libff/algebra/curves/edwards/edwards_fields.cpp b/libff/algebra/curves/edwards/edwards_fields.cpp new file mode 100644 index 00000000..4da14ab5 --- /dev/null +++ b/libff/algebra/curves/edwards/edwards_fields.cpp @@ -0,0 +1,111 @@ +/** @file + ***************************************************************************** + * @author This file is part of libff, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#include + +namespace libff { + +bigint edwards_modulus_r; +bigint edwards_modulus_q; + +void init_edwards_fields() +{ + typedef bigint bigint_r; + typedef bigint bigint_q; + + assert(sizeof(mp_limb_t) == 8 || sizeof(mp_limb_t) == 4); // Montgomery assumes this + + /* parameters for scalar field Fr */ + + edwards_modulus_r = bigint_r("1552511030102430251236801561344621993261920897571225601"); + assert(edwards_Fr::modulus_is_valid()); + if (sizeof(mp_limb_t) == 8) + { + edwards_Fr::Rsquared = bigint_r("621738487827897760168419760282818735947979812540885779"); + edwards_Fr::Rcubed = bigint_r("899968968216802386013510389846941393831065658679774050"); + edwards_Fr::inv = 0xdde553277fffffff; + } + if (sizeof(mp_limb_t) == 4) + { + edwards_Fr::Rsquared = bigint_r("621738487827897760168419760282818735947979812540885779"); + edwards_Fr::Rcubed = bigint_r("899968968216802386013510389846941393831065658679774050"); + edwards_Fr::inv = 0x7fffffff; + } + edwards_Fr::num_bits = 181; + edwards_Fr::euler = bigint_r("776255515051215125618400780672310996630960448785612800"); + edwards_Fr::s = 31; + edwards_Fr::t = bigint_r("722944284836962004768104088187507350585386575"); + edwards_Fr::t_minus_1_over_2 = bigint_r("361472142418481002384052044093753675292693287"); + edwards_Fr::multiplicative_generator = edwards_Fr("19"); + edwards_Fr::root_of_unity = edwards_Fr("695314865466598274460565335217615316274564719601897184"); + edwards_Fr::nqr = edwards_Fr("11"); + edwards_Fr::nqr_to_t = edwards_Fr("1326707053668679463752768729767248251415639579872144553"); + + /* parameters for base field Fq */ + + edwards_modulus_q = bigint_q("6210044120409721004947206240885978274523751269793792001"); + assert(edwards_Fq::modulus_is_valid()); + if (sizeof(mp_limb_t) == 8) + { + edwards_Fq::Rsquared = bigint_q("5943559676554581037560514598978484097352477055348195432"); + edwards_Fq::Rcubed = bigint_q("1081560488703514202058739223469726982199727506489234349"); + edwards_Fq::inv = 0x76eb690b7fffffff; + } + if (sizeof(mp_limb_t) == 4) + { + edwards_Fq::Rsquared = bigint_q("5943559676554581037560514598978484097352477055348195432"); + edwards_Fq::Rcubed = bigint_q("1081560488703514202058739223469726982199727506489234349"); + edwards_Fq::inv = 0x7fffffff; + } + edwards_Fq::num_bits = 183; + edwards_Fq::euler = bigint_q("3105022060204860502473603120442989137261875634896896000"); + edwards_Fq::s = 31; + edwards_Fq::t = bigint_q("2891777139347848019072416350658041552884388375"); + edwards_Fq::t_minus_1_over_2 = bigint_q("1445888569673924009536208175329020776442194187"); + edwards_Fq::multiplicative_generator = edwards_Fq("61"); + edwards_Fq::root_of_unity = edwards_Fq("4692813029219384139894873043933463717810008194158530536"); + edwards_Fq::nqr = edwards_Fq("23"); + edwards_Fq::nqr_to_t = edwards_Fq("2626736066325740702418554487368721595489070118548299138"); + + /* parameters for twist field Fq3 */ + + edwards_Fq3::euler = bigint<3*edwards_q_limbs>("119744082713971502962992613191067836698205043373978948903839934564152994858051284658545502971203325031831647424413111161318314144765646525057914792711854057586688000"); + edwards_Fq3::s = 31; + edwards_Fq3::t = bigint<3*edwards_q_limbs>("111520367408144756185815309352304634357062208814526860512643991563611659089151103662834971185031649686239331424621037357783237607000066456438894190557165125"); + edwards_Fq3::t_minus_1_over_2 = bigint<3*edwards_q_limbs>("55760183704072378092907654676152317178531104407263430256321995781805829544575551831417485592515824843119665712310518678891618803500033228219447095278582562"); + edwards_Fq3::non_residue = edwards_Fq("61"); + edwards_Fq3::nqr = edwards_Fq3(edwards_Fq("23"),edwards_Fq("0"),edwards_Fq("0")); + edwards_Fq3::nqr_to_t = edwards_Fq3(edwards_Fq("104810943629412208121981114244673004633270996333237516"),edwards_Fq("0"),edwards_Fq("0")); + edwards_Fq3::Frobenius_coeffs_c1[0] = edwards_Fq("1"); + edwards_Fq3::Frobenius_coeffs_c1[1] = edwards_Fq("1073752683758513276629212192812154536507607213288832061"); + edwards_Fq3::Frobenius_coeffs_c1[2] = edwards_Fq("5136291436651207728317994048073823738016144056504959939"); + edwards_Fq3::Frobenius_coeffs_c2[0] = edwards_Fq("1"); + edwards_Fq3::Frobenius_coeffs_c2[1] = edwards_Fq("5136291436651207728317994048073823738016144056504959939"); + edwards_Fq3::Frobenius_coeffs_c2[2] = edwards_Fq("1073752683758513276629212192812154536507607213288832061"); + + /* parameters for Fq6 */ + + edwards_Fq6::euler = bigint<6*edwards_q_limbs>("286772906900208978053659358438511744950463073927050691441013733733308852103113703187330276692859302954336930908810347208181904968549176866575351093481768308610598000" + "12474722471292022005286908893541416599742789523143737959708214461870605874121090272322517073698670457333498341250241297120220551099521678676677016084977733861376000"); + edwards_Fq6::s = 32; + edwards_Fq6::t = bigint<6*edwards_q_limbs>("133539040992133774819625242817453921283810899558966370039160239386050427380536544689596759478030401726410226388280441615815230164932635084993835116495270425738113932" + "36962483483968312854546545489477653335660132357451942730559136002264267706368626222164610900775841650242683636606783278808100405661166495958658408413165125"); + edwards_Fq6::t_minus_1_over_2 = bigint<6*edwards_q_limbs>("667695204960668874098126214087269606419054497794831850195801196930252136902682723447983797390152008632051131941402208079076150824663175424969175582476352128690569661" + "8481241741984156427273272744738826667830066178725971365279568001132133853184313111082305450387920825121341818303391639404050202830583247979329204206582562"); + edwards_Fq6::non_residue = edwards_Fq("61"); + edwards_Fq6::nqr = edwards_Fq6(edwards_Fq3(edwards_Fq("5"),edwards_Fq("0"),edwards_Fq("0")),edwards_Fq3::one()); + edwards_Fq6::nqr_to_t = edwards_Fq6(edwards_Fq3::zero(),edwards_Fq3(edwards_Fq("0"),edwards_Fq("6018622460271751604575462891699668290753365582464183006"),edwards_Fq("0"))); + edwards_Fq6::Frobenius_coeffs_c1[0] = edwards_Fq("1"); + edwards_Fq6::Frobenius_coeffs_c1[1] = edwards_Fq("1073752683758513276629212192812154536507607213288832062"); + edwards_Fq6::Frobenius_coeffs_c1[2] = edwards_Fq("1073752683758513276629212192812154536507607213288832061"); + edwards_Fq6::Frobenius_coeffs_c1[3] = edwards_Fq("6210044120409721004947206240885978274523751269793792000"); + edwards_Fq6::Frobenius_coeffs_c1[4] = edwards_Fq("5136291436651207728317994048073823738016144056504959939"); + edwards_Fq6::Frobenius_coeffs_c1[5] = edwards_Fq("5136291436651207728317994048073823738016144056504959940"); + edwards_Fq6::my_Fp2::non_residue = edwards_Fq3::non_residue; +} + +} // libff diff --git a/libff/algebra/curves/edwards/edwards_fields.hpp b/libff/algebra/curves/edwards/edwards_fields.hpp new file mode 100644 index 00000000..e693b77a --- /dev/null +++ b/libff/algebra/curves/edwards/edwards_fields.hpp @@ -0,0 +1,34 @@ +/** @file + ***************************************************************************** + * @author This file is part of libff, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef EDWARDS_FIELDS_HPP_ +#define EDWARDS_FIELDS_HPP_ +#include +#include +#include + +namespace libff { + +const mp_size_t edwards_r_bitcount = 181; +const mp_size_t edwards_q_bitcount = 183; + +const mp_size_t edwards_r_limbs = (edwards_r_bitcount+GMP_NUMB_BITS-1)/GMP_NUMB_BITS; +const mp_size_t edwards_q_limbs = (edwards_q_bitcount+GMP_NUMB_BITS-1)/GMP_NUMB_BITS; + +extern bigint edwards_modulus_r; +extern bigint edwards_modulus_q; + +typedef Fp_model edwards_Fr; +typedef Fp_model edwards_Fq; +typedef Fp3_model edwards_Fq3; +typedef Fp6_2over3_model edwards_Fq6; +typedef edwards_Fq6 edwards_GT; + +void init_edwards_fields(); + +} // libff +#endif // EDWARDS_FIELDS_HPP_ diff --git a/libff/algebra/curves/edwards/edwards_g1.cpp b/libff/algebra/curves/edwards/edwards_g1.cpp index 3e30f345..fdb2fe38 100755 --- a/libff/algebra/curves/edwards/edwards_g1.cpp +++ b/libff/algebra/curves/edwards/edwards_g1.cpp @@ -9,6 +9,8 @@ namespace libff { +using std::size_t; + #ifdef PROFILE_OP_COUNTS long long edwards_G1::add_cnt = 0; long long edwards_G1::dbl_cnt = 0; diff --git a/libff/algebra/curves/edwards/edwards_g1.hpp b/libff/algebra/curves/edwards/edwards_g1.hpp index 29539fb5..faeba040 100755 --- a/libff/algebra/curves/edwards/edwards_g1.hpp +++ b/libff/algebra/curves/edwards/edwards_g1.hpp @@ -67,8 +67,8 @@ class edwards_G1 { static edwards_G1 one(); static edwards_G1 random_element(); - static size_t size_in_bits() { return edwards_Fq::size_in_bits() + 1; } - static bigint base_field_char() { return base_field::field_char(); } + static std::size_t size_in_bits() { return edwards_Fq::size_in_bits() + 1; } + static bigint field_char() { return base_field::field_char(); } static bigint order() { return scalar_field::field_char(); } friend std::ostream& operator<<(std::ostream &out, const edwards_G1 &g); diff --git a/libff/algebra/curves/edwards/edwards_g2.hpp b/libff/algebra/curves/edwards/edwards_g2.hpp index afdc0883..c04d9531 100755 --- a/libff/algebra/curves/edwards/edwards_g2.hpp +++ b/libff/algebra/curves/edwards/edwards_g2.hpp @@ -73,8 +73,8 @@ class edwards_G2 { static edwards_G2 one(); static edwards_G2 random_element(); - static size_t size_in_bits() { return twist_field::size_in_bits() + 1; } - static bigint base_field_char() { return base_field::field_char(); } + static std::size_t size_in_bits() { return twist_field::size_in_bits() + 1; } + static bigint field_char() { return base_field::field_char(); } static bigint order() { return scalar_field::field_char(); } friend std::ostream& operator<<(std::ostream &out, const edwards_G2 &g); diff --git a/libff/algebra/curves/edwards/edwards_init.cpp b/libff/algebra/curves/edwards/edwards_init.cpp index 68cb0829..4c34f56e 100755 --- a/libff/algebra/curves/edwards/edwards_init.cpp +++ b/libff/algebra/curves/edwards/edwards_init.cpp @@ -11,9 +11,6 @@ namespace libff { -bigint edwards_modulus_r; -bigint edwards_modulus_q; - edwards_Fq edwards_coeff_a; edwards_Fq edwards_coeff_d; edwards_Fq3 edwards_twist; @@ -36,89 +33,7 @@ bigint edwards_final_exponent_last_chunk_w1; void init_edwards_params() { - typedef bigint bigint_r; - typedef bigint bigint_q; - - assert(sizeof(mp_limb_t) == 8 || sizeof(mp_limb_t) == 4); // Montgomery assumes this - - /* parameters for scalar field Fr */ - - edwards_modulus_r = bigint_r("1552511030102430251236801561344621993261920897571225601"); - assert(edwards_Fr::modulus_is_valid()); - if (sizeof(mp_limb_t) == 8) - { - edwards_Fr::Rsquared = bigint_r("621738487827897760168419760282818735947979812540885779"); - edwards_Fr::Rcubed = bigint_r("899968968216802386013510389846941393831065658679774050"); - edwards_Fr::inv = 0xdde553277fffffff; - } - if (sizeof(mp_limb_t) == 4) - { - edwards_Fr::Rsquared = bigint_r("621738487827897760168419760282818735947979812540885779"); - edwards_Fr::Rcubed = bigint_r("899968968216802386013510389846941393831065658679774050"); - edwards_Fr::inv = 0x7fffffff; - } - edwards_Fr::num_bits = 181; - edwards_Fr::euler = bigint_r("776255515051215125618400780672310996630960448785612800"); - edwards_Fr::s = 31; - edwards_Fr::t = bigint_r("722944284836962004768104088187507350585386575"); - edwards_Fr::t_minus_1_over_2 = bigint_r("361472142418481002384052044093753675292693287"); - edwards_Fr::multiplicative_generator = edwards_Fr("19"); - edwards_Fr::root_of_unity = edwards_Fr("695314865466598274460565335217615316274564719601897184"); - edwards_Fr::nqr = edwards_Fr("11"); - edwards_Fr::nqr_to_t = edwards_Fr("1326707053668679463752768729767248251415639579872144553"); - - /* parameters for base field Fq */ - - edwards_modulus_q = bigint_q("6210044120409721004947206240885978274523751269793792001"); - assert(edwards_Fq::modulus_is_valid()); - if (sizeof(mp_limb_t) == 8) - { - edwards_Fq::Rsquared = bigint_q("5943559676554581037560514598978484097352477055348195432"); - edwards_Fq::Rcubed = bigint_q("1081560488703514202058739223469726982199727506489234349"); - edwards_Fq::inv = 0x76eb690b7fffffff; - } - if (sizeof(mp_limb_t) == 4) - { - edwards_Fq::Rsquared = bigint_q("5943559676554581037560514598978484097352477055348195432"); - edwards_Fq::Rcubed = bigint_q("1081560488703514202058739223469726982199727506489234349"); - edwards_Fq::inv = 0x7fffffff; - } - edwards_Fq::num_bits = 183; - edwards_Fq::euler = bigint_q("3105022060204860502473603120442989137261875634896896000"); - edwards_Fq::s = 31; - edwards_Fq::t = bigint_q("2891777139347848019072416350658041552884388375"); - edwards_Fq::t_minus_1_over_2 = bigint_q("1445888569673924009536208175329020776442194187"); - edwards_Fq::multiplicative_generator = edwards_Fq("61"); - edwards_Fq::root_of_unity = edwards_Fq("4692813029219384139894873043933463717810008194158530536"); - edwards_Fq::nqr = edwards_Fq("23"); - edwards_Fq::nqr_to_t = edwards_Fq("2626736066325740702418554487368721595489070118548299138"); - - /* parameters for twist field Fq3 */ - - edwards_Fq3::euler = bigint<3*edwards_q_limbs>("119744082713971502962992613191067836698205043373978948903839934564152994858051284658545502971203325031831647424413111161318314144765646525057914792711854057586688000"); - edwards_Fq3::s = 31; - edwards_Fq3::t = bigint<3*edwards_q_limbs>("111520367408144756185815309352304634357062208814526860512643991563611659089151103662834971185031649686239331424621037357783237607000066456438894190557165125"); - edwards_Fq3::t_minus_1_over_2 = bigint<3*edwards_q_limbs>("55760183704072378092907654676152317178531104407263430256321995781805829544575551831417485592515824843119665712310518678891618803500033228219447095278582562"); - edwards_Fq3::non_residue = edwards_Fq("61"); - edwards_Fq3::nqr = edwards_Fq3(edwards_Fq("23"),edwards_Fq("0"),edwards_Fq("0")); - edwards_Fq3::nqr_to_t = edwards_Fq3(edwards_Fq("104810943629412208121981114244673004633270996333237516"),edwards_Fq("0"),edwards_Fq("0")); - edwards_Fq3::Frobenius_coeffs_c1[0] = edwards_Fq("1"); - edwards_Fq3::Frobenius_coeffs_c1[1] = edwards_Fq("1073752683758513276629212192812154536507607213288832061"); - edwards_Fq3::Frobenius_coeffs_c1[2] = edwards_Fq("5136291436651207728317994048073823738016144056504959939"); - edwards_Fq3::Frobenius_coeffs_c2[0] = edwards_Fq("1"); - edwards_Fq3::Frobenius_coeffs_c2[1] = edwards_Fq("5136291436651207728317994048073823738016144056504959939"); - edwards_Fq3::Frobenius_coeffs_c2[2] = edwards_Fq("1073752683758513276629212192812154536507607213288832061"); - - /* parameters for Fq6 */ - - edwards_Fq6::non_residue = edwards_Fq("61"); - edwards_Fq6::Frobenius_coeffs_c1[0] = edwards_Fq("1"); - edwards_Fq6::Frobenius_coeffs_c1[1] = edwards_Fq("1073752683758513276629212192812154536507607213288832062"); - edwards_Fq6::Frobenius_coeffs_c1[2] = edwards_Fq("1073752683758513276629212192812154536507607213288832061"); - edwards_Fq6::Frobenius_coeffs_c1[3] = edwards_Fq("6210044120409721004947206240885978274523751269793792000"); - edwards_Fq6::Frobenius_coeffs_c1[4] = edwards_Fq("5136291436651207728317994048073823738016144056504959939"); - edwards_Fq6::Frobenius_coeffs_c1[5] = edwards_Fq("5136291436651207728317994048073823738016144056504959940"); - edwards_Fq6::my_Fp2::non_residue = edwards_Fq3::non_residue; + init_edwards_fields(); /* choice of Edwards curve and its twist */ @@ -261,11 +176,11 @@ void init_edwards_params() /* pairing parameters */ - edwards_ate_loop_count = bigint_q("4492509698523932320491110403"); + edwards_ate_loop_count = bigint("4492509698523932320491110403"); edwards_final_exponent = bigint<6*edwards_q_limbs>("36943107177961694649618797346446870138748651578611748415128207429491593976636391130175425245705674550269561361208979548749447898941828686017765730419416875539615941651269793928962468899856083169227457503942470721108165443528513330156264699608120624990672333642644221591552000"); - edwards_final_exponent_last_chunk_abs_of_w0 = bigint_q("17970038794095729281964441603"); + edwards_final_exponent_last_chunk_abs_of_w0 = bigint("17970038794095729281964441603"); edwards_final_exponent_last_chunk_is_w0_neg = true; - edwards_final_exponent_last_chunk_w1 = bigint_q("4"); + edwards_final_exponent_last_chunk_w1 = bigint("4"); } } // libff diff --git a/libff/algebra/curves/edwards/edwards_init.hpp b/libff/algebra/curves/edwards/edwards_init.hpp index 5871f8ad..c75f661f 100755 --- a/libff/algebra/curves/edwards/edwards_init.hpp +++ b/libff/algebra/curves/edwards/edwards_init.hpp @@ -8,27 +8,10 @@ #ifndef EDWARDS_INIT_HPP_ #define EDWARDS_INIT_HPP_ #include -#include -#include -#include +#include namespace libff { -const mp_size_t edwards_r_bitcount = 181; -const mp_size_t edwards_q_bitcount = 183; - -const mp_size_t edwards_r_limbs = (edwards_r_bitcount+GMP_NUMB_BITS-1)/GMP_NUMB_BITS; -const mp_size_t edwards_q_limbs = (edwards_q_bitcount+GMP_NUMB_BITS-1)/GMP_NUMB_BITS; - -extern bigint edwards_modulus_r; -extern bigint edwards_modulus_q; - -typedef Fp_model edwards_Fr; -typedef Fp_model edwards_Fq; -typedef Fp3_model edwards_Fq3; -typedef Fp6_2over3_model edwards_Fq6; -typedef edwards_Fq6 edwards_GT; - // parameters for Edwards curve E_{1,d}(F_q) extern edwards_Fq edwards_coeff_a; extern edwards_Fq edwards_coeff_d; diff --git a/libff/algebra/curves/edwards/edwards_pairing.cpp b/libff/algebra/curves/edwards/edwards_pairing.cpp index ea81ff52..ba7bcfb6 100755 --- a/libff/algebra/curves/edwards/edwards_pairing.cpp +++ b/libff/algebra/curves/edwards/edwards_pairing.cpp @@ -15,6 +15,8 @@ namespace libff { +using std::size_t; + bool edwards_Fq_conic_coefficients::operator==(const edwards_Fq_conic_coefficients &other) const { return (this->c_ZZ == other.c_ZZ && diff --git a/libff/algebra/curves/mnt/mnt4/mnt4_fields.cpp b/libff/algebra/curves/mnt/mnt4/mnt4_fields.cpp new file mode 100644 index 00000000..02337381 --- /dev/null +++ b/libff/algebra/curves/mnt/mnt4/mnt4_fields.cpp @@ -0,0 +1,107 @@ +/** @file + ***************************************************************************** + + Implementation of interfaces for initializing MNT4. + + See mnt4_init.hpp . + + ***************************************************************************** + * @author This file is part of libff, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#include + +namespace libff { + +void init_mnt4_fields() +{ + typedef bigint bigint_r; + typedef bigint bigint_q; + + assert(sizeof(mp_limb_t) == 8 || sizeof(mp_limb_t) == 4); // Montgomery assumes this + + /* parameters for scalar field Fr */ + + mnt4_modulus_r = bigint_r("475922286169261325753349249653048451545124878552823515553267735739164647307408490559963137"); + assert(mnt4_Fr::modulus_is_valid()); + if (sizeof(mp_limb_t) == 8) + { + mnt4_Fr::Rsquared = bigint_r("163983144722506446826715124368972380525894397127205577781234305496325861831001705438796139"); + mnt4_Fr::Rcubed = bigint_r("207236281459091063710247635236340312578688659363066707916716212805695955118593239854980171"); + mnt4_Fr::inv = 0xbb4334a3ffffffff; + } + if (sizeof(mp_limb_t) == 4) + { + mnt4_Fr::Rsquared = bigint_r("163983144722506446826715124368972380525894397127205577781234305496325861831001705438796139"); + mnt4_Fr::Rcubed = bigint_r("207236281459091063710247635236340312578688659363066707916716212805695955118593239854980171"); + mnt4_Fr::inv = 0xffffffff; + } + mnt4_Fr::num_bits = 298; + mnt4_Fr::euler = bigint_r("237961143084630662876674624826524225772562439276411757776633867869582323653704245279981568"); + mnt4_Fr::s = 34; + mnt4_Fr::t = bigint_r("27702323054502562488973446286577291993024111641153199339359284829066871159442729"); + mnt4_Fr::t_minus_1_over_2 = bigint_r("13851161527251281244486723143288645996512055820576599669679642414533435579721364"); + mnt4_Fr::multiplicative_generator = mnt4_Fr("10"); + mnt4_Fr::root_of_unity = mnt4_Fr("120638817826913173458768829485690099845377008030891618010109772937363554409782252579816313"); + mnt4_Fr::nqr = mnt4_Fr("5"); + mnt4_Fr::nqr_to_t = mnt4_Fr("406220604243090401056429458730298145937262552508985450684842547562990900634752279902740880"); + + /* parameters for base field Fq */ + + mnt4_modulus_q = bigint_q("475922286169261325753349249653048451545124879242694725395555128576210262817955800483758081"); + assert(mnt4_Fq::modulus_is_valid()); + if (sizeof(mp_limb_t) == 8) + { + mnt4_Fq::Rsquared = bigint_q("273000478523237720910981655601160860640083126627235719712980612296263966512828033847775776"); + mnt4_Fq::Rcubed = bigint_q("427298980065529822574935274648041073124704261331681436071990730954930769758106792920349077"); + mnt4_Fq::inv = 0xb071a1b67165ffff; + } + if (sizeof(mp_limb_t) == 4) + { + mnt4_Fq::Rsquared = bigint_q("273000478523237720910981655601160860640083126627235719712980612296263966512828033847775776"); + mnt4_Fq::Rcubed = bigint_q("427298980065529822574935274648041073124704261331681436071990730954930769758106792920349077"); + mnt4_Fq::inv = 0x7165ffff; + } + mnt4_Fq::num_bits = 298; + mnt4_Fq::euler = bigint_q("237961143084630662876674624826524225772562439621347362697777564288105131408977900241879040"); + mnt4_Fq::s = 17; + mnt4_Fq::t = bigint_q("3630998887399759870554727551674258816109656366292531779446068791017229177993437198515"); + mnt4_Fq::t_minus_1_over_2 = bigint_q("1815499443699879935277363775837129408054828183146265889723034395508614588996718599257"); + mnt4_Fq::multiplicative_generator = mnt4_Fq("17"); + mnt4_Fq::root_of_unity = mnt4_Fq("264706250571800080758069302369654305530125675521263976034054878017580902343339784464690243"); + mnt4_Fq::nqr = mnt4_Fq("17"); + mnt4_Fq::nqr_to_t = mnt4_Fq("264706250571800080758069302369654305530125675521263976034054878017580902343339784464690243"); + + /* parameters for twist field Fq2 */ + + mnt4_Fq2::euler = bigint<2*mnt4_q_limbs>("113251011236288135098249345249154230895914381858788918106847214243419142422924133497460817468249854833067260038985710370091920860837014281886963086681184370139950267830740466401280"); + mnt4_Fq2::s = 18; + mnt4_Fq2::t = bigint<2*mnt4_q_limbs>("864036645784668999467844736092790457885088972921668381552484239528039111503022258739172496553419912972009735404859240494475714575477709059806542104196047745818712370534824115"); + mnt4_Fq2::t_minus_1_over_2 = bigint<2*mnt4_q_limbs>("432018322892334499733922368046395228942544486460834190776242119764019555751511129369586248276709956486004867702429620247237857287738854529903271052098023872909356185267412057"); + mnt4_Fq2::non_residue = mnt4_Fq("17"); + mnt4_Fq2::nqr = mnt4_Fq2(mnt4_Fq("8"),mnt4_Fq("1")); + mnt4_Fq2::nqr_to_t = mnt4_Fq2(mnt4_Fq("0"),mnt4_Fq("29402818985595053196743631544512156561638230562612542604956687802791427330205135130967658")); + mnt4_Fq2::Frobenius_coeffs_c1[0] = mnt4_Fq("1"); + mnt4_Fq2::Frobenius_coeffs_c1[1] = mnt4_Fq("475922286169261325753349249653048451545124879242694725395555128576210262817955800483758080"); + + /* parameters for Fq4 */ + + mnt4_Fq4::euler = bigint<4*mnt4_q_limbs>("256515830920837228603894562946361224104398799265865805633159457364347160648491325197665112074594203843606979074063463732151330068748561097967387024709381297334575804200924440372388" + "70266485480310448412800447687355912222889117273270333186953365310343339095195101362180341777704896596606135620801390396337387451719858347266414533678045654385500808110588904079360"); + mnt4_Fq4::s = 19; + mnt4_Fq4::t = bigint<4*mnt4_q_limbs>("978530238803242601790979625497288605134577939094031546147001103837383883089032460013065765665413680433681408210996489456754036211961979286069439028584981145227721421054551850785784" + "54080526276819032336427489041732453242832631199914295909703694573758465176372914742204062567538820635246794207768975816106366927031930340829523215019400231878283722345691315"); + mnt4_Fq4::t_minus_1_over_2 = bigint<4*mnt4_q_limbs>("489265119401621300895489812748644302567288969547015773073500551918691941544516230006532882832706840216840704105498244728377018105980989643034719514292490572613860710527275925392892" + "27040263138409516168213744520866226621416315599957147954851847286879232588186457371102031283769410317623397103884487908053183463515965170414761607509700115939141861172845657"); + mnt4_Fq4::non_residue = mnt4_Fq("17"); + mnt4_Fq4::nqr = mnt4_Fq4(mnt4_Fq2(mnt4_Fq("4"),mnt4_Fq("0")),mnt4_Fq2::one()); + mnt4_Fq4::nqr_to_t = mnt4_Fq4(mnt4_Fq2::zero(),mnt4_Fq2(mnt4_Fq("29121826399401736230321201250169476571908331476055427845679523445723222361523083487327506"),mnt4_Fq("0"))); + mnt4_Fq4::Frobenius_coeffs_c1[0] = mnt4_Fq("1"); + mnt4_Fq4::Frobenius_coeffs_c1[1] = mnt4_Fq("7684163245453501615621351552473337069301082060976805004625011694147890954040864167002308"); + mnt4_Fq4::Frobenius_coeffs_c1[2] = mnt4_Fq("475922286169261325753349249653048451545124879242694725395555128576210262817955800483758080"); + mnt4_Fq4::Frobenius_coeffs_c1[3] = mnt4_Fq("468238122923807824137727898100575114475823797181717920390930116882062371863914936316755773"); +} + +} // libff diff --git a/libff/algebra/curves/mnt/mnt4/mnt4_fields.hpp b/libff/algebra/curves/mnt/mnt4/mnt4_fields.hpp new file mode 100644 index 00000000..07f965fe --- /dev/null +++ b/libff/algebra/curves/mnt/mnt4/mnt4_fields.hpp @@ -0,0 +1,44 @@ +/** @file + ***************************************************************************** + + Declaration of interfaces for initializing MNT4. + + ***************************************************************************** + * @author This file is part of libff, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef MNT4_FIELDS_HPP_ +#define MNT4_FIELDS_HPP_ + +#include +#include +#include +#include + +namespace libff { + +#define mnt4_modulus_r mnt46_modulus_A +#define mnt4_modulus_q mnt46_modulus_B + +const mp_size_t mnt4_r_bitcount = mnt46_A_bitcount; +const mp_size_t mnt4_q_bitcount = mnt46_B_bitcount; + +const mp_size_t mnt4_r_limbs = mnt46_A_limbs; +const mp_size_t mnt4_q_limbs = mnt46_B_limbs; + +extern bigint mnt4_modulus_r; +extern bigint mnt4_modulus_q; + +typedef Fp_model mnt4_Fr; +typedef Fp_model mnt4_Fq; +typedef Fp2_model mnt4_Fq2; +typedef Fp4_model mnt4_Fq4; +typedef mnt4_Fq4 mnt4_GT; + +void init_mnt4_fields(); + +} // libff + +#endif // MNT4_FIELDS_HPP_ diff --git a/libff/algebra/curves/mnt/mnt4/mnt4_g1.cpp b/libff/algebra/curves/mnt/mnt4/mnt4_g1.cpp index 0863c778..4f8b0af5 100755 --- a/libff/algebra/curves/mnt/mnt4/mnt4_g1.cpp +++ b/libff/algebra/curves/mnt/mnt4/mnt4_g1.cpp @@ -15,6 +15,8 @@ namespace libff { +using std::size_t; + #ifdef PROFILE_OP_COUNTS long long mnt4_G1::add_cnt = 0; long long mnt4_G1::dbl_cnt = 0; diff --git a/libff/algebra/curves/mnt/mnt4/mnt4_g1.hpp b/libff/algebra/curves/mnt/mnt4/mnt4_g1.hpp index 4297cbf2..11279cf8 100755 --- a/libff/algebra/curves/mnt/mnt4/mnt4_g1.hpp +++ b/libff/algebra/curves/mnt/mnt4/mnt4_g1.hpp @@ -73,8 +73,8 @@ class mnt4_G1 { static mnt4_G1 one(); static mnt4_G1 random_element(); - static size_t size_in_bits() { return mnt4_Fq::size_in_bits() + 1; } - static bigint base_field_char() { return mnt4_Fq::field_char(); } + static std::size_t size_in_bits() { return mnt4_Fq::size_in_bits() + 1; } + static bigint field_char() { return mnt4_Fq::field_char(); } static bigint order() { return mnt4_Fr::field_char(); } friend std::ostream& operator<<(std::ostream &out, const mnt4_G1 &g); diff --git a/libff/algebra/curves/mnt/mnt4/mnt4_g2.hpp b/libff/algebra/curves/mnt/mnt4/mnt4_g2.hpp index 24cb6a7a..fe232b52 100755 --- a/libff/algebra/curves/mnt/mnt4/mnt4_g2.hpp +++ b/libff/algebra/curves/mnt/mnt4/mnt4_g2.hpp @@ -78,8 +78,8 @@ class mnt4_G2 { static mnt4_G2 one(); static mnt4_G2 random_element(); - static size_t size_in_bits() { return mnt4_Fq2::size_in_bits() + 1; } - static bigint base_field_char() { return mnt4_Fq::field_char(); } + static std::size_t size_in_bits() { return mnt4_Fq2::size_in_bits() + 1; } + static bigint field_char() { return mnt4_Fq::field_char(); } static bigint order() { return mnt4_Fr::field_char(); } friend std::ostream& operator<<(std::ostream &out, const mnt4_G2 &g); diff --git a/libff/algebra/curves/mnt/mnt4/mnt4_init.cpp b/libff/algebra/curves/mnt/mnt4/mnt4_init.cpp index dbc20d7a..492b4441 100755 --- a/libff/algebra/curves/mnt/mnt4/mnt4_init.cpp +++ b/libff/algebra/curves/mnt/mnt4/mnt4_init.cpp @@ -17,9 +17,6 @@ namespace libff { -// bigint mnt4_modulus_r = mnt46_modulus_A; -// bigint mnt4_modulus_q = mnt46_modulus_B; - mnt4_Fq2 mnt4_twist; mnt4_Fq2 mnt4_twist_coeff_a; mnt4_Fq2 mnt4_twist_coeff_b; @@ -39,78 +36,7 @@ bigint mnt4_final_exponent_last_chunk_w1; void init_mnt4_params() { - typedef bigint bigint_r; - typedef bigint bigint_q; - - assert(sizeof(mp_limb_t) == 8 || sizeof(mp_limb_t) == 4); // Montgomery assumes this - - /* parameters for scalar field Fr */ - mnt4_modulus_r = bigint_r("475922286169261325753349249653048451545124878552823515553267735739164647307408490559963137"); - assert(mnt4_Fr::modulus_is_valid()); - if (sizeof(mp_limb_t) == 8) - { - mnt4_Fr::Rsquared = bigint_r("163983144722506446826715124368972380525894397127205577781234305496325861831001705438796139"); - mnt4_Fr::Rcubed = bigint_r("207236281459091063710247635236340312578688659363066707916716212805695955118593239854980171"); - mnt4_Fr::inv = 0xbb4334a3ffffffff; - } - if (sizeof(mp_limb_t) == 4) - { - mnt4_Fr::Rsquared = bigint_r("163983144722506446826715124368972380525894397127205577781234305496325861831001705438796139"); - mnt4_Fr::Rcubed = bigint_r("207236281459091063710247635236340312578688659363066707916716212805695955118593239854980171"); - mnt4_Fr::inv = 0xffffffff; - } - mnt4_Fr::num_bits = 298; - mnt4_Fr::euler = bigint_r("237961143084630662876674624826524225772562439276411757776633867869582323653704245279981568"); - mnt4_Fr::s = 34; - mnt4_Fr::t = bigint_r("27702323054502562488973446286577291993024111641153199339359284829066871159442729"); - mnt4_Fr::t_minus_1_over_2 = bigint_r("13851161527251281244486723143288645996512055820576599669679642414533435579721364"); - mnt4_Fr::multiplicative_generator = mnt4_Fr("10"); - mnt4_Fr::root_of_unity = mnt4_Fr("120638817826913173458768829485690099845377008030891618010109772937363554409782252579816313"); - mnt4_Fr::nqr = mnt4_Fr("5"); - mnt4_Fr::nqr_to_t = mnt4_Fr("406220604243090401056429458730298145937262552508985450684842547562990900634752279902740880"); - - /* parameters for base field Fq */ - mnt4_modulus_q = bigint_q("475922286169261325753349249653048451545124879242694725395555128576210262817955800483758081"); - assert(mnt4_Fq::modulus_is_valid()); - if (sizeof(mp_limb_t) == 8) - { - mnt4_Fq::Rsquared = bigint_q("273000478523237720910981655601160860640083126627235719712980612296263966512828033847775776"); - mnt4_Fq::Rcubed = bigint_q("427298980065529822574935274648041073124704261331681436071990730954930769758106792920349077"); - mnt4_Fq::inv = 0xb071a1b67165ffff; - } - if (sizeof(mp_limb_t) == 4) - { - mnt4_Fq::Rsquared = bigint_q("273000478523237720910981655601160860640083126627235719712980612296263966512828033847775776"); - mnt4_Fq::Rcubed = bigint_q("427298980065529822574935274648041073124704261331681436071990730954930769758106792920349077"); - mnt4_Fq::inv = 0x7165ffff; - } - mnt4_Fq::num_bits = 298; - mnt4_Fq::euler = bigint_q("237961143084630662876674624826524225772562439621347362697777564288105131408977900241879040"); - mnt4_Fq::s = 17; - mnt4_Fq::t = bigint_q("3630998887399759870554727551674258816109656366292531779446068791017229177993437198515"); - mnt4_Fq::t_minus_1_over_2 = bigint_q("1815499443699879935277363775837129408054828183146265889723034395508614588996718599257"); - mnt4_Fq::multiplicative_generator = mnt4_Fq("17"); - mnt4_Fq::root_of_unity = mnt4_Fq("264706250571800080758069302369654305530125675521263976034054878017580902343339784464690243"); - mnt4_Fq::nqr = mnt4_Fq("17"); - mnt4_Fq::nqr_to_t = mnt4_Fq("264706250571800080758069302369654305530125675521263976034054878017580902343339784464690243"); - - /* parameters for twist field Fq2 */ - mnt4_Fq2::euler = bigint<2*mnt4_q_limbs>("113251011236288135098249345249154230895914381858788918106847214243419142422924133497460817468249854833067260038985710370091920860837014281886963086681184370139950267830740466401280"); - mnt4_Fq2::s = 18; - mnt4_Fq2::t = bigint<2*mnt4_q_limbs>("864036645784668999467844736092790457885088972921668381552484239528039111503022258739172496553419912972009735404859240494475714575477709059806542104196047745818712370534824115"); - mnt4_Fq2::t_minus_1_over_2 = bigint<2*mnt4_q_limbs>("432018322892334499733922368046395228942544486460834190776242119764019555751511129369586248276709956486004867702429620247237857287738854529903271052098023872909356185267412057"); - mnt4_Fq2::non_residue = mnt4_Fq("17"); - mnt4_Fq2::nqr = mnt4_Fq2(mnt4_Fq("8"),mnt4_Fq("1")); - mnt4_Fq2::nqr_to_t = mnt4_Fq2(mnt4_Fq("0"),mnt4_Fq("29402818985595053196743631544512156561638230562612542604956687802791427330205135130967658")); - mnt4_Fq2::Frobenius_coeffs_c1[0] = mnt4_Fq("1"); - mnt4_Fq2::Frobenius_coeffs_c1[1] = mnt4_Fq("475922286169261325753349249653048451545124879242694725395555128576210262817955800483758080"); - - /* parameters for Fq4 */ - mnt4_Fq4::non_residue = mnt4_Fq("17"); - mnt4_Fq4::Frobenius_coeffs_c1[0] = mnt4_Fq("1"); - mnt4_Fq4::Frobenius_coeffs_c1[1] = mnt4_Fq("7684163245453501615621351552473337069301082060976805004625011694147890954040864167002308"); - mnt4_Fq4::Frobenius_coeffs_c1[2] = mnt4_Fq("475922286169261325753349249653048451545124879242694725395555128576210262817955800483758080"); - mnt4_Fq4::Frobenius_coeffs_c1[3] = mnt4_Fq("468238122923807824137727898100575114475823797181717920390930116882062371863914936316755773"); + init_mnt4_fields(); /* choice of short Weierstrass curve and its twist */ mnt4_G1::coeff_a = mnt4_Fq("2"); @@ -256,12 +182,12 @@ void init_mnt4_params() mnt4_G2::fixed_base_exp_window_table.push_back(38760027); /* pairing parameters */ - mnt4_ate_loop_count = bigint_q("689871209842287392837045615510547309923794944"); + mnt4_ate_loop_count = bigint("689871209842287392837045615510547309923794944"); mnt4_ate_is_loop_count_neg = false; mnt4_final_exponent = bigint<4*mnt4_q_limbs>("107797360357109903430794490309592072278927783803031854357910908121903439838772861497177116410825586743089760869945394610511917274977971559062689561855016270594656570874331111995170645233717143416875749097203441437192367065467706065411650403684877366879441766585988546560"); - mnt4_final_exponent_last_chunk_abs_of_w0 = bigint_q("689871209842287392837045615510547309923794945"); + mnt4_final_exponent_last_chunk_abs_of_w0 = bigint("689871209842287392837045615510547309923794945"); mnt4_final_exponent_last_chunk_is_w0_neg = false; - mnt4_final_exponent_last_chunk_w1 = bigint_q("1"); + mnt4_final_exponent_last_chunk_w1 = bigint("1"); } } // libff diff --git a/libff/algebra/curves/mnt/mnt4/mnt4_init.hpp b/libff/algebra/curves/mnt/mnt4/mnt4_init.hpp index 600d16c8..1a20bddc 100755 --- a/libff/algebra/curves/mnt/mnt4/mnt4_init.hpp +++ b/libff/algebra/curves/mnt/mnt4/mnt4_init.hpp @@ -12,32 +12,11 @@ #ifndef MNT4_INIT_HPP_ #define MNT4_INIT_HPP_ -#include #include -#include -#include -#include +#include namespace libff { -#define mnt4_modulus_r mnt46_modulus_A -#define mnt4_modulus_q mnt46_modulus_B - -const mp_size_t mnt4_r_bitcount = mnt46_A_bitcount; -const mp_size_t mnt4_q_bitcount = mnt46_B_bitcount; - -const mp_size_t mnt4_r_limbs = mnt46_A_limbs; -const mp_size_t mnt4_q_limbs = mnt46_B_limbs; - -extern bigint mnt4_modulus_r; -extern bigint mnt4_modulus_q; - -typedef Fp_model mnt4_Fr; -typedef Fp_model mnt4_Fq; -typedef Fp2_model mnt4_Fq2; -typedef Fp4_model mnt4_Fq4; -typedef mnt4_Fq4 mnt4_GT; - // parameters for twisted short Weierstrass curve E'/Fq2 : y^2 = x^3 + (a * twist^2) * x + (b * twist^3) extern mnt4_Fq2 mnt4_twist; extern mnt4_Fq2 mnt4_twist_coeff_a; diff --git a/libff/algebra/curves/mnt/mnt4/mnt4_pairing.cpp b/libff/algebra/curves/mnt/mnt4/mnt4_pairing.cpp index 81ebd8c6..3b3edf33 100755 --- a/libff/algebra/curves/mnt/mnt4/mnt4_pairing.cpp +++ b/libff/algebra/curves/mnt/mnt4/mnt4_pairing.cpp @@ -22,6 +22,8 @@ namespace libff { +using std::size_t; + bool mnt4_ate_G1_precomp::operator==(const mnt4_ate_G1_precomp &other) const { return (this->PX == other.PX && diff --git a/libff/algebra/curves/mnt/mnt46_common.hpp b/libff/algebra/curves/mnt/mnt46_common.hpp index 2029fe89..6827fe79 100755 --- a/libff/algebra/curves/mnt/mnt46_common.hpp +++ b/libff/algebra/curves/mnt/mnt46_common.hpp @@ -12,7 +12,7 @@ #ifndef MNT46_COMMON_HPP_ #define MNT46_COMMON_HPP_ -#include +#include namespace libff { diff --git a/libff/algebra/curves/mnt/mnt6/mnt6_fields.cpp b/libff/algebra/curves/mnt/mnt6/mnt6_fields.cpp new file mode 100644 index 00000000..3fedc1f9 --- /dev/null +++ b/libff/algebra/curves/mnt/mnt6/mnt6_fields.cpp @@ -0,0 +1,114 @@ +/** @file + ***************************************************************************** + + Implementation of interfaces for initializing MNT6. + + See mnt6_init.hpp . + + ***************************************************************************** + * @author This file is part of libff, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#include + +namespace libff { + +void init_mnt6_fields() +{ + typedef bigint bigint_r; + typedef bigint bigint_q; + + assert(sizeof(mp_limb_t) == 8 || sizeof(mp_limb_t) == 4); // Montgomery assumes this + + /* parameters for scalar field Fr */ + + mnt6_modulus_r = bigint_r("475922286169261325753349249653048451545124879242694725395555128576210262817955800483758081"); + assert(mnt6_Fr::modulus_is_valid()); + if (sizeof(mp_limb_t) == 8) + { + mnt6_Fr::Rsquared = bigint_r("273000478523237720910981655601160860640083126627235719712980612296263966512828033847775776"); + mnt6_Fr::Rcubed = bigint_r("427298980065529822574935274648041073124704261331681436071990730954930769758106792920349077"); + mnt6_Fr::inv = 0xb071a1b67165ffff; + } + if (sizeof(mp_limb_t) == 4) + { + mnt6_Fr::Rsquared = bigint_r("273000478523237720910981655601160860640083126627235719712980612296263966512828033847775776"); + mnt6_Fr::Rcubed = bigint_r("427298980065529822574935274648041073124704261331681436071990730954930769758106792920349077"); + mnt6_Fr::inv = 0x7165ffff; + } + mnt6_Fr::num_bits = 298; + mnt6_Fr::euler = bigint_r("237961143084630662876674624826524225772562439621347362697777564288105131408977900241879040"); + mnt6_Fr::s = 17; + mnt6_Fr::t = bigint_r("3630998887399759870554727551674258816109656366292531779446068791017229177993437198515"); + mnt6_Fr::t_minus_1_over_2 = bigint_r("1815499443699879935277363775837129408054828183146265889723034395508614588996718599257"); + mnt6_Fr::multiplicative_generator = mnt6_Fr("17"); + mnt6_Fr::root_of_unity = mnt6_Fr("264706250571800080758069302369654305530125675521263976034054878017580902343339784464690243"); + mnt6_Fr::nqr = mnt6_Fr("17"); + mnt6_Fr::nqr_to_t = mnt6_Fr("264706250571800080758069302369654305530125675521263976034054878017580902343339784464690243"); + + /* parameters for base field Fq */ + + mnt6_modulus_q = bigint_q("475922286169261325753349249653048451545124878552823515553267735739164647307408490559963137"); + assert(mnt6_Fq::modulus_is_valid()); + if (sizeof(mp_limb_t) == 8) + { + mnt6_Fq::Rsquared = bigint_q("163983144722506446826715124368972380525894397127205577781234305496325861831001705438796139"); + mnt6_Fq::Rcubed = bigint_q("207236281459091063710247635236340312578688659363066707916716212805695955118593239854980171"); + mnt6_Fq::inv = 0xbb4334a3ffffffff; + } + if (sizeof(mp_limb_t) == 4) + { + mnt6_Fq::Rsquared = bigint_q("163983144722506446826715124368972380525894397127205577781234305496325861831001705438796139"); + mnt6_Fq::Rcubed = bigint_q("207236281459091063710247635236340312578688659363066707916716212805695955118593239854980171"); + mnt6_Fq::inv = 0xffffffff; + } + mnt6_Fq::num_bits = 298; + mnt6_Fq::euler = bigint_q("237961143084630662876674624826524225772562439276411757776633867869582323653704245279981568"); + mnt6_Fq::s = 34; + mnt6_Fq::t = bigint_q("27702323054502562488973446286577291993024111641153199339359284829066871159442729"); + mnt6_Fq::t_minus_1_over_2 = bigint_q("13851161527251281244486723143288645996512055820576599669679642414533435579721364"); + mnt6_Fq::multiplicative_generator = mnt6_Fq("10"); + mnt6_Fq::root_of_unity = mnt6_Fq("120638817826913173458768829485690099845377008030891618010109772937363554409782252579816313"); + mnt6_Fq::nqr = mnt6_Fq("5"); + mnt6_Fq::nqr_to_t = mnt6_Fq("406220604243090401056429458730298145937262552508985450684842547562990900634752279902740880"); + + /* parameters for twist field Fq3 */ + + mnt6_Fq3::euler = bigint<3*mnt6_q_limbs>("53898680178554951715397245154796036139463891589001478629193136369124915637741423690184935056189295242736833704290747216410090671804540908400210778934462129625646263095398323485795557551284190224166851571615834194321908328559167529729507439069424158411618728014749106176"); + mnt6_Fq3::s = 34; + mnt6_Fq3::t = bigint<3*mnt6_q_limbs>("6274632199033507112809136178669989590936327770934612330653836993631547740397674926811006741620285348354004521888069251599964996777072188956687550402067383940523288107407084140669968625447269322370045302856694231080113482726640944570478452261237446033817102203"); + mnt6_Fq3::t_minus_1_over_2 = bigint<3*mnt6_q_limbs>("3137316099516753556404568089334994795468163885467306165326918496815773870198837463405503370810142674177002260944034625799982498388536094478343775201033691970261644053703542070334984312723634661185022651428347115540056741363320472285239226130618723016908551101"); + mnt6_Fq3::non_residue = mnt6_Fq("5"); + mnt6_Fq3::nqr = mnt6_Fq3(mnt6_Fq("5"),mnt6_Fq("0"),mnt6_Fq("0")); + mnt6_Fq3::nqr_to_t = mnt6_Fq3(mnt6_Fq("154361449678783505076984156275977937654331103361174469632346230549735979552469642799720052"),mnt6_Fq("0"),mnt6_Fq("0")); + mnt6_Fq3::Frobenius_coeffs_c1[0] = mnt6_Fq("1"); + mnt6_Fq3::Frobenius_coeffs_c1[1] = mnt6_Fq("471738898967521029133040851318449165997304108729558973770077319830005517129946578866686956"); + mnt6_Fq3::Frobenius_coeffs_c1[2] = mnt6_Fq("4183387201740296620308398334599285547820769823264541783190415909159130177461911693276180"); + mnt6_Fq3::Frobenius_coeffs_c2[0] = mnt6_Fq("1"); + mnt6_Fq3::Frobenius_coeffs_c2[1] = mnt6_Fq("4183387201740296620308398334599285547820769823264541783190415909159130177461911693276180"); + mnt6_Fq3::Frobenius_coeffs_c2[2] = mnt6_Fq("471738898967521029133040851318449165997304108729558973770077319830005517129946578866686956"); + + /* parameters for Fq6 */ + + mnt6_Fq6::euler = bigint<6*mnt6_q_limbs>("58101354499803048834583303220952913087824099988886273927160035716575561879937723707648335894925330628895188378773913275197213919452183382055206387082172181425605923957620009042449526418177025032365963902004248852434047609548572040108115533682304388051005201389178753450" + "43409872160393969038819851306130935281801223313744881543615360884552109851303547212609185435570387523149780308979035592069180747953000755531869142327042207668768296881030935139706074910917829157651610581536611575608256606920332948110215549184448842466566234011340898304"); + mnt6_Fq6::s = 35; + mnt6_Fq6::t = bigint<6*mnt6_q_limbs>("33819439413376995848132823140449422113495005753872842718358172404449178068862368648201422704689513559508596301762103845363723765739812155984811477294524771525528004833974415111849972988814712171655825747877969902727082144439087738345910057939067708823716501582634375343" + "5847458438970728837816268863746135919459701010127603166248612157334114299813724775601247409100783262585160573302944865547422130356601017732864079433903226609619351620845900332770896779310297521160194334896316959965523367684819557943277500405933756990507607931"); + mnt6_Fq6::t_minus_1_over_2 = bigint<6*mnt6_q_limbs>("16909719706688497924066411570224711056747502876936421359179086202224589034431184324100711352344756779754298150881051922681861882869906077992405738647262385762764002416987207555924986494407356085827912873938984951363541072219543869172955028969533854411858250791317187671" + "7923729219485364418908134431873067959729850505063801583124306078667057149906862387800623704550391631292580286651472432773711065178300508866432039716951613304809675810422950166385448389655148760580097167448158479982761683842409778971638750202966878495253803965"); + mnt6_Fq6::non_residue = mnt6_Fq("5"); + mnt6_Fq6::nqr = mnt6_Fq6(mnt6_Fq3(mnt6_Fq("2"),mnt6_Fq("0"),mnt6_Fq("0")),mnt6_Fq3::one()); + mnt6_Fq6::nqr_to_t = mnt6_Fq6(mnt6_Fq3::zero(),mnt6_Fq3(mnt6_Fq("0"),mnt6_Fq("95371092960829291863271933246328602470562937077363363183769791678780911004969735451493071"),mnt6_Fq("0"))); + mnt6_Fq6::Frobenius_coeffs_c1[0] = mnt6_Fq("1"); + mnt6_Fq6::Frobenius_coeffs_c1[1] = mnt6_Fq("471738898967521029133040851318449165997304108729558973770077319830005517129946578866686957"); + mnt6_Fq6::Frobenius_coeffs_c1[2] = mnt6_Fq("471738898967521029133040851318449165997304108729558973770077319830005517129946578866686956"); + mnt6_Fq6::Frobenius_coeffs_c1[3] = mnt6_Fq("475922286169261325753349249653048451545124878552823515553267735739164647307408490559963136"); + mnt6_Fq6::Frobenius_coeffs_c1[4] = mnt6_Fq("4183387201740296620308398334599285547820769823264541783190415909159130177461911693276180"); + mnt6_Fq6::Frobenius_coeffs_c1[5] = mnt6_Fq("4183387201740296620308398334599285547820769823264541783190415909159130177461911693276181"); + mnt6_Fq6::my_Fp2::non_residue = mnt6_Fq3::non_residue; +} + +} // libff diff --git a/libff/algebra/curves/mnt/mnt6/mnt6_fields.hpp b/libff/algebra/curves/mnt/mnt6/mnt6_fields.hpp new file mode 100644 index 00000000..9786d266 --- /dev/null +++ b/libff/algebra/curves/mnt/mnt6/mnt6_fields.hpp @@ -0,0 +1,45 @@ +/** @file + ***************************************************************************** + + Declaration of interfaces for initializing MNT6. + + ***************************************************************************** + * @author This file is part of libff, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef MNT6_INIT_FIELDS_ +#define MNT6_INIT_FIELDS_ + +#include +#include +#include +#include +#include + +namespace libff { + +#define mnt6_modulus_r mnt46_modulus_B +#define mnt6_modulus_q mnt46_modulus_A + +const mp_size_t mnt6_r_bitcount = mnt46_B_bitcount; +const mp_size_t mnt6_q_bitcount = mnt46_A_bitcount; + +const mp_size_t mnt6_r_limbs = mnt46_B_limbs; +const mp_size_t mnt6_q_limbs = mnt46_A_limbs; + +extern bigint mnt6_modulus_r; +extern bigint mnt6_modulus_q; + +typedef Fp_model mnt6_Fr; +typedef Fp_model mnt6_Fq; +typedef Fp3_model mnt6_Fq3; +typedef Fp6_2over3_model mnt6_Fq6; +typedef mnt6_Fq6 mnt6_GT; + +void init_mnt6_fields(); + +} // libff + +#endif // MNT6_INIT_FIELDS_ diff --git a/libff/algebra/curves/mnt/mnt6/mnt6_g1.cpp b/libff/algebra/curves/mnt/mnt6/mnt6_g1.cpp index 9b527e47..bf385853 100755 --- a/libff/algebra/curves/mnt/mnt6/mnt6_g1.cpp +++ b/libff/algebra/curves/mnt/mnt6/mnt6_g1.cpp @@ -15,6 +15,8 @@ namespace libff { +using std::size_t; + #ifdef PROFILE_OP_COUNTS long long mnt6_G1::add_cnt = 0; long long mnt6_G1::dbl_cnt = 0; diff --git a/libff/algebra/curves/mnt/mnt6/mnt6_g1.hpp b/libff/algebra/curves/mnt/mnt6/mnt6_g1.hpp index 06e7b1ee..54636831 100755 --- a/libff/algebra/curves/mnt/mnt6/mnt6_g1.hpp +++ b/libff/algebra/curves/mnt/mnt6/mnt6_g1.hpp @@ -73,8 +73,8 @@ class mnt6_G1 { static mnt6_G1 one(); static mnt6_G1 random_element(); - static size_t size_in_bits() { return base_field::size_in_bits() + 1; } - static bigint base_field_char() { return base_field::field_char(); } + static std::size_t size_in_bits() { return base_field::size_in_bits() + 1; } + static bigint field_char() { return base_field::field_char(); } static bigint order() { return scalar_field::field_char(); } friend std::ostream& operator<<(std::ostream &out, const mnt6_G1 &g); diff --git a/libff/algebra/curves/mnt/mnt6/mnt6_g2.hpp b/libff/algebra/curves/mnt/mnt6/mnt6_g2.hpp index 8c8d7dfa..f4fe45ef 100755 --- a/libff/algebra/curves/mnt/mnt6/mnt6_g2.hpp +++ b/libff/algebra/curves/mnt/mnt6/mnt6_g2.hpp @@ -78,8 +78,8 @@ class mnt6_G2 { static mnt6_G2 one(); static mnt6_G2 random_element(); - static size_t size_in_bits() { return twist_field::size_in_bits() + 1; } - static bigint base_field_char() { return base_field::field_char(); } + static std::size_t size_in_bits() { return twist_field::size_in_bits() + 1; } + static bigint field_char() { return base_field::field_char(); } static bigint order() { return scalar_field::field_char(); } friend std::ostream& operator<<(std::ostream &out, const mnt6_G2 &g); diff --git a/libff/algebra/curves/mnt/mnt6/mnt6_init.cpp b/libff/algebra/curves/mnt/mnt6/mnt6_init.cpp index 61599fa9..16b5441b 100755 --- a/libff/algebra/curves/mnt/mnt6/mnt6_init.cpp +++ b/libff/algebra/curves/mnt/mnt6/mnt6_init.cpp @@ -17,9 +17,6 @@ namespace libff { -//bigint mnt6_modulus_r = mnt46_modulus_B; -//bigint mnt6_modulus_q = mnt46_modulus_A; - mnt6_Fq3 mnt6_twist; mnt6_Fq3 mnt6_twist_coeff_a; mnt6_Fq3 mnt6_twist_coeff_b; @@ -41,85 +38,7 @@ bigint mnt6_final_exponent_last_chunk_w1; void init_mnt6_params() { - typedef bigint bigint_r; - typedef bigint bigint_q; - - assert(sizeof(mp_limb_t) == 8 || sizeof(mp_limb_t) == 4); // Montgomery assumes this - - /* parameters for scalar field Fr */ - mnt6_modulus_r = bigint_r("475922286169261325753349249653048451545124879242694725395555128576210262817955800483758081"); - assert(mnt6_Fr::modulus_is_valid()); - if (sizeof(mp_limb_t) == 8) - { - mnt6_Fr::Rsquared = bigint_r("273000478523237720910981655601160860640083126627235719712980612296263966512828033847775776"); - mnt6_Fr::Rcubed = bigint_r("427298980065529822574935274648041073124704261331681436071990730954930769758106792920349077"); - mnt6_Fr::inv = 0xb071a1b67165ffff; - } - if (sizeof(mp_limb_t) == 4) - { - mnt6_Fr::Rsquared = bigint_r("273000478523237720910981655601160860640083126627235719712980612296263966512828033847775776"); - mnt6_Fr::Rcubed = bigint_r("427298980065529822574935274648041073124704261331681436071990730954930769758106792920349077"); - mnt6_Fr::inv = 0x7165ffff; - } - mnt6_Fr::num_bits = 298; - mnt6_Fr::euler = bigint_r("237961143084630662876674624826524225772562439621347362697777564288105131408977900241879040"); - mnt6_Fr::s = 17; - mnt6_Fr::t = bigint_r("3630998887399759870554727551674258816109656366292531779446068791017229177993437198515"); - mnt6_Fr::t_minus_1_over_2 = bigint_r("1815499443699879935277363775837129408054828183146265889723034395508614588996718599257"); - mnt6_Fr::multiplicative_generator = mnt6_Fr("17"); - mnt6_Fr::root_of_unity = mnt6_Fr("264706250571800080758069302369654305530125675521263976034054878017580902343339784464690243"); - mnt6_Fr::nqr = mnt6_Fr("17"); - mnt6_Fr::nqr_to_t = mnt6_Fr("264706250571800080758069302369654305530125675521263976034054878017580902343339784464690243"); - - /* parameters for base field Fq */ - mnt6_modulus_q = bigint_q("475922286169261325753349249653048451545124878552823515553267735739164647307408490559963137"); - assert(mnt6_Fq::modulus_is_valid()); - if (sizeof(mp_limb_t) == 8) - { - mnt6_Fq::Rsquared = bigint_q("163983144722506446826715124368972380525894397127205577781234305496325861831001705438796139"); - mnt6_Fq::Rcubed = bigint_q("207236281459091063710247635236340312578688659363066707916716212805695955118593239854980171"); - mnt6_Fq::inv = 0xbb4334a3ffffffff; - } - if (sizeof(mp_limb_t) == 4) - { - mnt6_Fq::Rsquared = bigint_q("163983144722506446826715124368972380525894397127205577781234305496325861831001705438796139"); - mnt6_Fq::Rcubed = bigint_q("207236281459091063710247635236340312578688659363066707916716212805695955118593239854980171"); - mnt6_Fq::inv = 0xffffffff; - } - mnt6_Fq::num_bits = 298; - mnt6_Fq::euler = bigint_q("237961143084630662876674624826524225772562439276411757776633867869582323653704245279981568"); - mnt6_Fq::s = 34; - mnt6_Fq::t = bigint_q("27702323054502562488973446286577291993024111641153199339359284829066871159442729"); - mnt6_Fq::t_minus_1_over_2 = bigint_q("13851161527251281244486723143288645996512055820576599669679642414533435579721364"); - mnt6_Fq::multiplicative_generator = mnt6_Fq("10"); - mnt6_Fq::root_of_unity = mnt6_Fq("120638817826913173458768829485690099845377008030891618010109772937363554409782252579816313"); - mnt6_Fq::nqr = mnt6_Fq("5"); - mnt6_Fq::nqr_to_t = mnt6_Fq("406220604243090401056429458730298145937262552508985450684842547562990900634752279902740880"); - - /* parameters for twist field Fq3 */ - mnt6_Fq3::euler = bigint<3*mnt6_q_limbs>("53898680178554951715397245154796036139463891589001478629193136369124915637741423690184935056189295242736833704290747216410090671804540908400210778934462129625646263095398323485795557551284190224166851571615834194321908328559167529729507439069424158411618728014749106176"); - mnt6_Fq3::s = 34; - mnt6_Fq3::t = bigint<3*mnt6_q_limbs>("6274632199033507112809136178669989590936327770934612330653836993631547740397674926811006741620285348354004521888069251599964996777072188956687550402067383940523288107407084140669968625447269322370045302856694231080113482726640944570478452261237446033817102203"); - mnt6_Fq3::t_minus_1_over_2 = bigint<3*mnt6_q_limbs>("3137316099516753556404568089334994795468163885467306165326918496815773870198837463405503370810142674177002260944034625799982498388536094478343775201033691970261644053703542070334984312723634661185022651428347115540056741363320472285239226130618723016908551101"); - mnt6_Fq3::non_residue = mnt6_Fq("5"); - mnt6_Fq3::nqr = mnt6_Fq3(mnt6_Fq("5"),mnt6_Fq("0"),mnt6_Fq("0")); - mnt6_Fq3::nqr_to_t = mnt6_Fq3(mnt6_Fq("154361449678783505076984156275977937654331103361174469632346230549735979552469642799720052"),mnt6_Fq("0"),mnt6_Fq("0")); - mnt6_Fq3::Frobenius_coeffs_c1[0] = mnt6_Fq("1"); - mnt6_Fq3::Frobenius_coeffs_c1[1] = mnt6_Fq("471738898967521029133040851318449165997304108729558973770077319830005517129946578866686956"); - mnt6_Fq3::Frobenius_coeffs_c1[2] = mnt6_Fq("4183387201740296620308398334599285547820769823264541783190415909159130177461911693276180"); - mnt6_Fq3::Frobenius_coeffs_c2[0] = mnt6_Fq("1"); - mnt6_Fq3::Frobenius_coeffs_c2[1] = mnt6_Fq("4183387201740296620308398334599285547820769823264541783190415909159130177461911693276180"); - mnt6_Fq3::Frobenius_coeffs_c2[2] = mnt6_Fq("471738898967521029133040851318449165997304108729558973770077319830005517129946578866686956"); - - /* parameters for Fq6 */ - mnt6_Fq6::non_residue = mnt6_Fq("5"); - mnt6_Fq6::Frobenius_coeffs_c1[0] = mnt6_Fq("1"); - mnt6_Fq6::Frobenius_coeffs_c1[1] = mnt6_Fq("471738898967521029133040851318449165997304108729558973770077319830005517129946578866686957"); - mnt6_Fq6::Frobenius_coeffs_c1[2] = mnt6_Fq("471738898967521029133040851318449165997304108729558973770077319830005517129946578866686956"); - mnt6_Fq6::Frobenius_coeffs_c1[3] = mnt6_Fq("475922286169261325753349249653048451545124878552823515553267735739164647307408490559963136"); - mnt6_Fq6::Frobenius_coeffs_c1[4] = mnt6_Fq("4183387201740296620308398334599285547820769823264541783190415909159130177461911693276180"); - mnt6_Fq6::Frobenius_coeffs_c1[5] = mnt6_Fq("4183387201740296620308398334599285547820769823264541783190415909159130177461911693276181"); - mnt6_Fq6::my_Fp2::non_residue = mnt6_Fq3::non_residue; + init_mnt6_fields(); /* choice of short Weierstrass curve and its twist */ mnt6_G1::coeff_a = mnt6_Fq("11"); @@ -268,12 +187,12 @@ void init_mnt6_params() mnt6_G2::fixed_base_exp_window_table.push_back(38554492); /* pairing parameters */ - mnt6_ate_loop_count = bigint_q("689871209842287392837045615510547309923794944"); + mnt6_ate_loop_count = bigint("689871209842287392837045615510547309923794944"); mnt6_ate_is_loop_count_neg = true; mnt6_final_exponent = bigint<6*mnt6_q_limbs>("24416320138090509697890595414313438768353977489862543935904010715439066975957855922532159264213056712140358746422742237328406558352706591021642230618060502855451264045397444793186876199015256781648746888625527075466063075011307800862173764236311342105211681121426931616843635215852236649271569251468773714424208521977615548771268520882870120900360322044218806712027729351845307690474985502587527753847200130592058098363641559341826790559426614919168"); - mnt6_final_exponent_last_chunk_abs_of_w0 = bigint_q("689871209842287392837045615510547309923794944"); + mnt6_final_exponent_last_chunk_abs_of_w0 = bigint("689871209842287392837045615510547309923794944"); mnt6_final_exponent_last_chunk_is_w0_neg = true; - mnt6_final_exponent_last_chunk_w1 = bigint_q("1"); + mnt6_final_exponent_last_chunk_w1 = bigint("1"); } } // libff diff --git a/libff/algebra/curves/mnt/mnt6/mnt6_init.hpp b/libff/algebra/curves/mnt/mnt6/mnt6_init.hpp index e4e2c942..75084eeb 100755 --- a/libff/algebra/curves/mnt/mnt6/mnt6_init.hpp +++ b/libff/algebra/curves/mnt/mnt6/mnt6_init.hpp @@ -12,26 +12,11 @@ #ifndef MNT6_INIT_HPP_ #define MNT6_INIT_HPP_ -#include #include -#include -#include -#include +#include namespace libff { -#define mnt6_modulus_r mnt46_modulus_B -#define mnt6_modulus_q mnt46_modulus_A - -const mp_size_t mnt6_r_bitcount = mnt46_B_bitcount; -const mp_size_t mnt6_q_bitcount = mnt46_A_bitcount; - -const mp_size_t mnt6_r_limbs = mnt46_B_limbs; -const mp_size_t mnt6_q_limbs = mnt46_A_limbs; - -extern bigint mnt6_modulus_r; -extern bigint mnt6_modulus_q; - typedef Fp_model mnt6_Fr; typedef Fp_model mnt6_Fq; typedef Fp3_model mnt6_Fq3; diff --git a/libff/algebra/curves/mnt/mnt6/mnt6_pairing.cpp b/libff/algebra/curves/mnt/mnt6/mnt6_pairing.cpp index 2d3b2660..91b4f757 100755 --- a/libff/algebra/curves/mnt/mnt6/mnt6_pairing.cpp +++ b/libff/algebra/curves/mnt/mnt6/mnt6_pairing.cpp @@ -22,6 +22,8 @@ namespace libff { +using std::size_t; + bool mnt6_ate_G1_precomp::operator==(const mnt6_ate_G1_precomp &other) const { return (this->PX == other.PX && diff --git a/libff/algebra/curves/tests/test_bilinearity.cpp b/libff/algebra/curves/tests/test_bilinearity.cpp index 963dfc55..65ff3e5a 100755 --- a/libff/algebra/curves/tests/test_bilinearity.cpp +++ b/libff/algebra/curves/tests/test_bilinearity.cpp @@ -4,6 +4,8 @@ * and contributors (see AUTHORS). * @copyright MIT license (see LICENSE file) *****************************************************************************/ +#include + #include #include #ifdef CURVE_BN128 @@ -15,7 +17,21 @@ using namespace libff; -#ifndef NDEBUG +class CurveBilinearityTest: public ::testing::Test { +public: + CurveBilinearityTest() + { + start_profiling(); + edwards_pp::init_public_params(); + mnt4_pp::init_public_params(); + mnt6_pp::init_public_params(); + alt_bn128_pp::init_public_params(); +#ifdef CURVE_BN128 // BN128 has fancy dependencies so it may be disabled + bn128_pp::init_public_params(); +#endif + } +}; + template void pairing_test() { @@ -47,11 +63,11 @@ void pairing_test() ans1.print(); ans2.print(); ans3.print(); - assert(ans1 == ans2); - assert(ans2 == ans3); + EXPECT_EQ(ans1, ans2); + EXPECT_EQ(ans2, ans3); - assert(ans1 != GT_one); - assert((ans1^Fr::field_char()) == GT_one); + EXPECT_NE(ans1, GT_one); + EXPECT_EQ((ans1^Fr::field_char()), GT_one); printf("\n\n"); } @@ -71,7 +87,7 @@ void double_miller_loop_test() const Fqk ans_1 = ppT::miller_loop(prec_P1, prec_Q1); const Fqk ans_2 = ppT::miller_loop(prec_P2, prec_Q2); const Fqk ans_12 = ppT::double_miller_loop(prec_P1, prec_Q1, prec_P2, prec_Q2); - assert(ans_1 * ans_2 == ans_12); + EXPECT_EQ(ans_1 * ans_2, ans_12); } template @@ -100,46 +116,38 @@ void affine_pairing_test() ans1.print(); ans2.print(); ans3.print(); - assert(ans1 == ans2); - assert(ans2 == ans3); + EXPECT_EQ(ans1, ans2); + EXPECT_EQ(ans2, ans3); - assert(ans1 != GT_one); - assert((ans1^Fr::field_char()) == GT_one); + EXPECT_NE(ans1, GT_one); + EXPECT_EQ((ans1^Fr::field_char()), GT_one); printf("\n\n"); } -int main(void) +TEST_F(CurveBilinearityTest, PairingTest) { - start_profiling(); - edwards_pp::init_public_params(); pairing_test(); - double_miller_loop_test(); - - mnt6_pp::init_public_params(); pairing_test(); - double_miller_loop_test(); - affine_pairing_test(); - - mnt4_pp::init_public_params(); pairing_test(); - double_miller_loop_test(); - affine_pairing_test(); - - alt_bn128_pp::init_public_params(); pairing_test(); - double_miller_loop_test(); - #ifdef CURVE_BN128 // BN128 has fancy dependencies so it may be disabled - bn128_pp::init_public_params(); pairing_test(); - double_miller_loop_test(); #endif } -#else // NDEBUG +TEST_F(CurveBilinearityTest, DoubleMillerLoopTest) +{ + double_miller_loop_test(); + double_miller_loop_test(); + double_miller_loop_test(); + double_miller_loop_test(); +#ifdef CURVE_BN128 // BN128 has fancy dependencies so it may be disabled + double_miller_loop_test(); +#endif +} -int main() +TEST_F(CurveBilinearityTest, AffinePairingTest) { - printf("All tests here depend on assert() which is disabled by -DNDEBUG. Please recompile and run again.\n"); + affine_pairing_test(); + affine_pairing_test(); } -#endif // NDEBUG diff --git a/libff/algebra/curves/tests/test_groups.cpp b/libff/algebra/curves/tests/test_groups.cpp index b2ecf585..f286e00f 100755 --- a/libff/algebra/curves/tests/test_groups.cpp +++ b/libff/algebra/curves/tests/test_groups.cpp @@ -4,6 +4,8 @@ * and contributors (see AUTHORS). * @copyright MIT license (see LICENSE file) *****************************************************************************/ +#include + #include #include #include @@ -14,10 +16,34 @@ #include #include +#include using namespace libff; -#ifndef NDEBUG +class CurveGroupsTest: public ::testing::Test { +public: + CurveGroupsTest() + { + edwards_pp::init_public_params(); + mnt4_pp::init_public_params(); + mnt6_pp::init_public_params(); + alt_bn128_pp::init_public_params(); +#ifdef CURVE_BN128 // BN128 has fancy dependencies so it may be disabled + bn128_pp::init_public_params(); +#endif + } +}; + +/** Returns a random element of FieldT that is not zero or one. */ +template +GroupT random_element_non_zero_one() +{ + GroupT x = GroupT::random_element(); + while (x == GroupT::zero() || x == GroupT::one()) + x = GroupT::random_element(); + return x; +} + template void test_mixed_add() { @@ -27,31 +53,31 @@ void test_mixed_add() el = GroupT::zero(); el.to_special(); result = base.mixed_add(el); - assert(result == base + el); + EXPECT_EQ(result, base + el); base = GroupT::zero(); el = GroupT::random_element(); el.to_special(); result = base.mixed_add(el); - assert(result == base + el); + EXPECT_EQ(result, base + el); base = GroupT::random_element(); el = GroupT::zero(); el.to_special(); result = base.mixed_add(el); - assert(result == base + el); + EXPECT_EQ(result, base + el); base = GroupT::random_element(); el = GroupT::random_element(); el.to_special(); result = base.mixed_add(el); - assert(result == base + el); + EXPECT_EQ(result, base + el); base = GroupT::random_element(); el = base; el.to_special(); result = base.mixed_add(el); - assert(result == base.dbl()); + EXPECT_EQ(result, base.dbl()); } template @@ -62,53 +88,52 @@ void test_group() bigint<1> randsum = bigint<1>("121160274"); GroupT zero = GroupT::zero(); - assert(zero == zero); + EXPECT_EQ(zero, zero); GroupT one = GroupT::one(); - assert(one == one); + EXPECT_EQ(one, one); GroupT two = bigint<1>(2l) * GroupT::one(); - assert(two == two); + EXPECT_EQ(two, two); GroupT five = bigint<1>(5l) * GroupT::one(); GroupT three = bigint<1>(3l) * GroupT::one(); GroupT four = bigint<1>(4l) * GroupT::one(); - assert(two+five == three+four); + EXPECT_EQ(two+five, three+four); - GroupT a = GroupT::random_element(); - GroupT b = GroupT::random_element(); - - assert(one != zero); - assert(a != zero); - assert(a != one); + GroupT a = random_element_non_zero_one(); + GroupT b = random_element_non_zero_one(); - assert(b != zero); - assert(b != one); + EXPECT_NE(one, zero); + ASSERT_NE(a, zero); + ASSERT_NE(a, one); + ASSERT_NE(b, zero); + ASSERT_NE(b, one); - assert(a.dbl() == a + a); - assert(b.dbl() == b + b); - assert(one.add(two) == three); - assert(two.add(one) == three); - assert(a + b == b + a); - assert(a - a == zero); - assert(a - b == a + (-b)); - assert(a - b == (-b) + a); + EXPECT_EQ(a.dbl(), a + a); + EXPECT_EQ(b.dbl(), b + b); + EXPECT_EQ(one.add(two), three); + EXPECT_EQ(two.add(one), three); + EXPECT_EQ(a + b, b + a); + EXPECT_EQ(a - a, zero); + EXPECT_EQ(a - b, a + (-b)); + EXPECT_EQ(a - b, (-b) + a); // handle special cases - assert(zero + (-a) == -a); - assert(zero - a == -a); - assert(a - zero == a); - assert(a + zero == a); - assert(zero + a == a); + EXPECT_EQ(zero + (-a), -a); + EXPECT_EQ(zero - a, -a); + EXPECT_EQ(a - zero, a); + EXPECT_EQ(a + zero, a); + EXPECT_EQ(zero + a, a); - assert((a + b).dbl() == (a + b) + (b + a)); - assert(bigint<1>("2") * (a + b) == (a + b) + (b + a)); + EXPECT_EQ((a + b).dbl(), (a + b) + (b + a)); + EXPECT_EQ(bigint<1>("2") * (a + b), (a + b) + (b + a)); - assert((rand1 * a) + (rand2 * a) == (randsum * a)); + EXPECT_EQ((rand1 * a) + (rand2 * a), (randsum * a)); - assert(GroupT::order() * a == zero); - assert(GroupT::order() * one == zero); - assert((GroupT::order() * a) - a != zero); - assert((GroupT::order() * one) - one != zero); + EXPECT_EQ(GroupT::order() * a, zero); + EXPECT_EQ(GroupT::order() * one, zero); + EXPECT_NE((GroupT::order() * a) - a, zero); + EXPECT_NE((GroupT::order() * one) - one, zero); test_mixed_add(); } @@ -117,7 +142,7 @@ template void test_mul_by_q() { GroupT a = GroupT::random_element(); - assert((GroupT::base_field_char()*a) == a.mul_by_q()); + EXPECT_EQ((GroupT::field_char()*a), a.mul_by_q()); } template @@ -131,55 +156,56 @@ void test_output() ss << g; GroupT gg; ss >> gg; - assert(g == gg); + EXPECT_EQ(g, gg); /* use a random point in next iteration */ g = GroupT::random_element(); } } -int main(void) +TEST_F(CurveGroupsTest, GroupTest) { - edwards_pp::init_public_params(); test_group >(); - test_output >(); test_group >(); - test_output >(); - test_mul_by_q >(); - mnt4_pp::init_public_params(); test_group >(); - test_output >(); test_group >(); - test_output >(); - test_mul_by_q >(); - mnt6_pp::init_public_params(); test_group >(); - test_output >(); test_group >(); - test_output >(); - test_mul_by_q >(); - alt_bn128_pp::init_public_params(); test_group >(); - test_output >(); test_group >(); - test_output >(); - test_mul_by_q >(); #ifdef CURVE_BN128 // BN128 has fancy dependencies so it may be disabled - bn128_pp::init_public_params(); test_group >(); - test_output >(); test_group >(); - test_output >(); #endif } -#else // NDEBUG +TEST_F(CurveGroupsTest, OutputTest) +{ + test_output >(); + test_output >(); + + test_output >(); + test_output >(); + + test_output >(); + test_output >(); -int main() + test_output >(); + test_output >(); + +#ifdef CURVE_BN128 // BN128 has fancy dependencies so it may be disabled + test_output >(); + test_output >(); +#endif +} + +TEST_F(CurveGroupsTest, MulByQTest) { - printf("All tests here depend on assert() which is disabled by -DNDEBUG. Please recompile and run again.\n"); + test_mul_by_q >(); + test_mul_by_q >(); + test_mul_by_q >(); + test_mul_by_q >(); } -#endif // NDEBUG diff --git a/libff/algebra/exponentiation/exponentiation.hpp b/libff/algebra/exponentiation/exponentiation.hpp deleted file mode 100755 index 0970983c..00000000 --- a/libff/algebra/exponentiation/exponentiation.hpp +++ /dev/null @@ -1,31 +0,0 @@ -/** @file - ***************************************************************************** - - Declaration of interfaces for (square-and-multiply) exponentiation. - - ***************************************************************************** - * @author This file is part of libff, developed by SCIPR Lab - * and contributors (see AUTHORS). - * @copyright MIT license (see LICENSE file) - *****************************************************************************/ - -#ifndef EXPONENTIATION_HPP_ -#define EXPONENTIATION_HPP_ - -#include - -#include - -namespace libff { - -template -FieldT power(const FieldT &base, const bigint &exponent); - -template -FieldT power(const FieldT &base, const unsigned long exponent); - -} // libff - -#include - -#endif // EXPONENTIATION_HPP_ diff --git a/libff/algebra/exponentiation/exponentiation.tcc b/libff/algebra/exponentiation/exponentiation.tcc deleted file mode 100755 index 3da5287d..00000000 --- a/libff/algebra/exponentiation/exponentiation.tcc +++ /dev/null @@ -1,53 +0,0 @@ -/** @file - ***************************************************************************** - - Implementation of interfaces for (square-and-multiply) exponentiation. - - See exponentiation.hpp . - - ***************************************************************************** - * @author This file is part of libff, developed by SCIPR Lab - * and contributors (see AUTHORS). - * @copyright MIT license (see LICENSE file) - *****************************************************************************/ - -#ifndef EXPONENTIATION_TCC_ -#define EXPONENTIATION_TCC_ - -#include - -namespace libff { - -template -FieldT power(const FieldT &base, const bigint &exponent) -{ - FieldT result = FieldT::one(); - - bool found_one = false; - - for (long i = exponent.max_bits() - 1; i >= 0; --i) - { - if (found_one) - { - result = result * result; - } - - if (exponent.test_bit(i)) - { - found_one = true; - result = result * base; - } - } - - return result; -} - -template -FieldT power(const FieldT &base, const unsigned long exponent) -{ - return power(base, bigint<1>(exponent)); -} - -} // libff - -#endif // EXPONENTIATION_TCC_ diff --git a/libff/algebra/field_utils/algorithms.hpp b/libff/algebra/field_utils/algorithms.hpp new file mode 100755 index 00000000..7a2312e6 --- /dev/null +++ b/libff/algebra/field_utils/algorithms.hpp @@ -0,0 +1,45 @@ +/** @file + ***************************************************************************** + + Declaration of interfaces for (square-and-multiply) exponentiation and + Tonelli-Shanks square root. + + ***************************************************************************** + * @author This file is part of libff, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef ALGORITHMS_HPP_ +#define ALGORITHMS_HPP_ + +#include + +#include "libff/algebra/field_utils/bigint.hpp" + +namespace libff { + +/** Repeated squaring. */ +template +FieldT power(const FieldT &base, const bigint &exponent); + +/** Repeated squaring. */ +template +FieldT power(const FieldT &base, const unsigned long exponent); + +/** Compute s, t, and quadratic non-residue as well as (p^n-1)/2, (t-1)/2, and nqr^t. + * Stores these constants inside static field attributes. + * Only needs to be called once for each field. */ +template +void find_tonelli_shanks_constants(); + +/** Tonelli-Shanks square root with given s, t, and quadratic non-residue. + * Only terminates if there is a square root. */ +template +FieldT tonelli_shanks_sqrt(const FieldT &value); + +} // libff + +#include + +#endif // ALGORITHMS_HPP_ diff --git a/libff/algebra/field_utils/algorithms.tcc b/libff/algebra/field_utils/algorithms.tcc new file mode 100755 index 00000000..ca4aaf1c --- /dev/null +++ b/libff/algebra/field_utils/algorithms.tcc @@ -0,0 +1,151 @@ +/** @file + ***************************************************************************** + + Declaration of interfaces for (square-and-multiply) exponentiation and + Tonelli-Shanks square root. + + See algorithms.hpp . + + ***************************************************************************** + * @author This file is part of libff, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef ALGORITHMS_TCC_ +#define ALGORITHMS_TCC_ + +#include "libff/common/utils.hpp" +#include "libff/common/profiling.hpp" + +namespace libff { + +using std::size_t; + +template +FieldT power(const FieldT &base, const bigint &exponent) +{ + FieldT result = FieldT::one(); + + bool found_one = false; + + for (long i = exponent.max_bits() - 1; i >= 0; --i) + { + if (found_one) + { + result = result * result; + } + + if (exponent.test_bit(i)) + { + found_one = true; + result = result * base; + } + } + + return result; +} + +template +FieldT power(const FieldT &base, const unsigned long exponent) +{ + return power(base, bigint<1>(exponent)); +} + +template +void find_tonelli_shanks_constants() +{ + // Find s and t such that p^n - 1 = t * 2^s, with t odd. + const mp_size_t m = n * FieldT::extension_degree(); + bigint one_i = bigint(1); // integer one + bigint p_to_n_minus_1 = FieldT::field_char().template power(FieldT::extension_degree()) - one_i; + size_t s = 0; + bigint t = p_to_n_minus_1; + while ((t % 2).is_zero()) + { + s++; + t = t / 2; + } + + // Find a quadratic non-residue by generating random elements and testing with Euler's criterion. + FieldT neg_one = -FieldT::one(); + bigint euler = p_to_n_minus_1 / 2; + FieldT nqr; + while (true) + { + nqr.randomize(); + if ((nqr^euler) == neg_one) + break; + } + + FieldT::euler = euler; + FieldT::s = s; + FieldT::t = t; + FieldT::t_minus_1_over_2 = (t - one_i) / 2; + FieldT::nqr = nqr; + FieldT::nqr_to_t = nqr^t; +} + +template +FieldT tonelli_shanks_sqrt(const FieldT &value) +{ + // a few assertions to make sure s, t, and nqr are initialized + assert(FieldT::s != 0); + assert(!(FieldT::t % 2).is_zero()); // check that t is odd + assert(!FieldT::nqr.is_zero()); + + if (value.is_zero()) + return FieldT::zero(); + + FieldT one = FieldT::one(); + + size_t v = FieldT::s; + FieldT z = FieldT::nqr_to_t; + FieldT w = value^FieldT::t_minus_1_over_2; + FieldT x = value * w; + FieldT b = x * w; // b = (*this)^t + +#if DEBUG + // check if square with euler's criterion + FieldT check = b; + for (size_t i = 0; i < v-1; ++i) + { + check = check.squared(); + } + assert(check == one); +#endif + + // compute square root with Tonelli--Shanks + // (does not terminate if not a square!) + + while (b != one) + { + size_t m = 0; + FieldT b2m = b; + while (b2m != one) + { + /* invariant: b2m = b^(2^m) after entering this loop */ + b2m = b2m.squared(); + m += 1; + } + + int j = v-m-1; + w = z; + while (j > 0) + { + w = w.squared(); + --j; + } // w = z^2^(v-m-1) + + z = w.squared(); + b = b * z; + x = x * w; + v = m; + } + + return x; +} + +} // libff + +#endif // ALGORITHMS_TCC_ diff --git a/libff/algebra/fields/bigint.hpp b/libff/algebra/field_utils/bigint.hpp similarity index 78% rename from libff/algebra/fields/bigint.hpp rename to libff/algebra/field_utils/bigint.hpp index 47db2d3c..426dcc21 100755 --- a/libff/algebra/fields/bigint.hpp +++ b/libff/algebra/field_utils/bigint.hpp @@ -39,14 +39,20 @@ class bigint { bigint(const char* s); /// Initialize from a string containing an integer in decimal notation bigint(const mpz_t r); /// Initialize from MPZ element + bigint operator-(const bigint& other) const; + bigint operator/(const mp_limb_t other) const; + bigint operator%(const mp_limb_t other) const; + template + bigint power(const std::size_t exp) const; + void print() const; void print_hex() const; bool operator==(const bigint& other) const; bool operator!=(const bigint& other) const; void clear(); bool is_zero() const; - size_t max_bits() const { return n * GMP_NUMB_BITS; } /// Returns the number of bits representable by this bigint type - size_t num_bits() const; /// Returns the number of bits in this specific bigint value, i.e., position of the most-significant 1 + std::size_t max_bits() const { return n * GMP_NUMB_BITS; } /// Returns the number of bits representable by this bigint type + std::size_t num_bits() const; /// Returns the number of bits in this specific bigint value, i.e., position of the most-significant 1 unsigned long as_ulong() const; /// Return the last limb of the integer void to_mpz(mpz_t r) const; @@ -59,5 +65,5 @@ class bigint { }; } // libff -#include +#include #endif diff --git a/libff/algebra/fields/bigint.tcc b/libff/algebra/field_utils/bigint.tcc similarity index 85% rename from libff/algebra/fields/bigint.tcc rename to libff/algebra/field_utils/bigint.tcc index d78e94f8..f8f70036 100755 --- a/libff/algebra/fields/bigint.tcc +++ b/libff/algebra/field_utils/bigint.tcc @@ -15,6 +15,8 @@ namespace libff { +using std::size_t; + template bigint::bigint(const unsigned long x) /// Initalize from a small integer { @@ -60,6 +62,42 @@ bigint::bigint(const mpz_t r) /// Initialize from MPZ element mpz_clear(k); } +template +bigint bigint::operator-(const bigint &other) const +{ + bigint result; + mpn_sub_n(result.data, this->data, other.data, n); + return result; +} + +template +bigint bigint::operator/(const mp_limb_t other) const +{ + bigint quotient; + mpn_divmod_1(quotient.data, this->data, n, other); + return quotient; +} + +template +bigint bigint::operator%(const mp_limb_t other) const +{ + bigint quotient; + mp_limb_t remainder = mpn_divmod_1(quotient.data, this->data, n, other); + UNUSED(quotient); + return remainder; +} + +template +template +bigint bigint::power(const size_t exp) const +{ + mpz_t value; + mpz_init(value); + this->to_mpz(value); + mpz_pow_ui(value, value, exp); + return bigint(value); +} + template void bigint::print() const { diff --git a/libff/algebra/field_utils/binary_utils.hpp b/libff/algebra/field_utils/binary_utils.hpp new file mode 100644 index 00000000..486c7fd7 --- /dev/null +++ b/libff/algebra/field_utils/binary_utils.hpp @@ -0,0 +1,118 @@ +/**@file + ***************************************************************************** + API hack for treating fields as additive or multiplicative + ***************************************************************************** + * @author This file is part of libff (see AUTHORS), migrated from libiop + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ + +#ifndef LIBFF_ALGEBRA_FIELDS_UTILS_HPP +#define LIBFF_ALGEBRA_FIELDS_UTILS_HPP + +#include "libff/algebra/fields/binary/gf64.hpp" +#include "libff/algebra/fields/binary/gf128.hpp" +#include "libff/algebra/fields/binary/gf192.hpp" +#include "libff/algebra/fields/binary/gf256.hpp" + +#include "libff/algebra/fields/prime_base/fp.hpp" + +namespace libff { + +template +struct is_additive { + static const bool value = false; +}; + +template<> +struct is_additive { + static const bool value = true; +}; + +template<> +struct is_additive { + static const bool value = true; +}; + +template<> +struct is_additive { + static const bool value = true; +}; + +template<> +struct is_additive { + static const bool value = true; +}; + +template +struct is_multiplicative { + static const bool value = false; +}; + +template& modulus> +struct is_multiplicative> { + static const bool value = true; +}; + +// Represents fields from which only the additive (resp. multiplicative) group is used. +enum field_type { + multiplicative_field_type = 1, + additive_field_type = 2 +}; + +template +struct enable_if { typedef void* type; }; + +template +struct enable_if { typedef T type; }; + +template +field_type get_field_type(const typename enable_if::value, FieldT>::type elem) +{ + UNUSED(elem); // only to identify field type + return multiplicative_field_type; +} + +template +field_type get_field_type(const typename enable_if::value, FieldT>::type elem) +{ + UNUSED(elem); // only to identify field type + return additive_field_type; +} + +template +std::size_t log_of_field_size_helper( + typename enable_if::value, FieldT>::type field_elem) +{ + return FieldT::size_in_bits(); +} + +template +std::size_t log_of_field_size_helper( + typename enable_if::value, FieldT>::type field_elem) +{ + return FieldT::extension_degree(); +} + +template +std::size_t soundness_log_of_field_size_helper( + typename enable_if::value, FieldT>::type field_elem) +{ + /** size in bits is the number of bits needed to represent a field element. + * However there isn't perfect alignment between the number of bits and the number of field elements, + * there could be a factor of two difference. + * For calculating soundness, we use the log of field size as number of bits - 1, + * as (2 << returned) size lower bounds the actual size. + */ + return FieldT::size_in_bits() - 1; +} + +template +std::size_t soundness_log_of_field_size_helper( + typename enable_if::value, FieldT>::type field_elem) +{ + return FieldT::extension_degree(); +} + +} // namespace libff + +#endif // LIBFF_ALGEBRA_FIELDS_UTILS_HPP \ No newline at end of file diff --git a/libff/algebra/fields/field_utils.hpp b/libff/algebra/field_utils/field_utils.hpp similarity index 84% rename from libff/algebra/fields/field_utils.hpp rename to libff/algebra/field_utils/field_utils.hpp index 04365caa..7db42ba1 100755 --- a/libff/algebra/fields/field_utils.hpp +++ b/libff/algebra/field_utils/field_utils.hpp @@ -9,7 +9,7 @@ #define FIELD_UTILS_HPP_ #include -#include +#include #include #include @@ -18,17 +18,17 @@ namespace libff { // returns root of unity of order n (for n a power of 2), if one exists template typename std::enable_if::value, FieldT>::type -get_root_of_unity(const size_t n); +get_root_of_unity(const std::size_t n); template typename std::enable_if::value, FieldT>::type -get_root_of_unity(const size_t n); +get_root_of_unity(const std::size_t n); template -std::vector pack_int_vector_into_field_element_vector(const std::vector &v, const size_t w); +std::vector pack_int_vector_into_field_element_vector(const std::vector &v, const std::size_t w); template -std::vector pack_bit_vector_into_field_element_vector(const bit_vector &v, const size_t chunk_bits); +std::vector pack_bit_vector_into_field_element_vector(const bit_vector &v, const std::size_t chunk_bits); template std::vector pack_bit_vector_into_field_element_vector(const bit_vector &v); @@ -43,7 +43,7 @@ template bit_vector convert_field_element_to_bit_vector(const FieldT &el); template -bit_vector convert_field_element_to_bit_vector(const FieldT &el, const size_t bitcount); +bit_vector convert_field_element_to_bit_vector(const FieldT &el, const std::size_t bitcount); template FieldT convert_bit_vector_to_field_element(const bit_vector &v); @@ -52,6 +52,6 @@ template void batch_invert(std::vector &vec); } // libff -#include +#include #endif // FIELD_UTILS_HPP_ diff --git a/libff/algebra/fields/field_utils.tcc b/libff/algebra/field_utils/field_utils.tcc similarity index 99% rename from libff/algebra/fields/field_utils.tcc rename to libff/algebra/field_utils/field_utils.tcc index 216caaea..7303c07e 100755 --- a/libff/algebra/fields/field_utils.tcc +++ b/libff/algebra/field_utils/field_utils.tcc @@ -18,6 +18,8 @@ namespace libff { +using std::size_t; + template FieldT coset_shift() { diff --git a/libff/algebra/fields/fp_aux.tcc b/libff/algebra/field_utils/fp_aux.tcc similarity index 100% rename from libff/algebra/fields/fp_aux.tcc rename to libff/algebra/field_utils/fp_aux.tcc diff --git a/libff/algebra/field_utils/tests/test_field_utils.cpp b/libff/algebra/field_utils/tests/test_field_utils.cpp new file mode 100644 index 00000000..995eaa73 --- /dev/null +++ b/libff/algebra/field_utils/tests/test_field_utils.cpp @@ -0,0 +1,43 @@ +/** + ***************************************************************************** + * @author This file is part of libff, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ +#include +#include "libff/algebra/field_utils/bigint.hpp" + +using namespace libff; + +/** Returns a random element of FieldT that is not zero. */ +template +bigint random_element_nonzero() +{ + bigint x; + x.randomize(); + while (x.is_zero()) + x.randomize(); + return x; +} + +TEST(FieldUtilsTest, BigintTest) +{ + bigint<3> zero = bigint<3>("0"); + bigint<3> one = bigint<3>("1"); + bigint<3> x = bigint<3>("987654567895678909876876545678909876543456"); + bigint<3> y = bigint<3>("324531232345676543272920293863628304859020"); + EXPECT_EQ(x - y, bigint<3>("663123335550002366603956251815281571684436")); + EXPECT_EQ(x / 100000, bigint<3>("9876545678956789098768765456789098765")); + EXPECT_EQ(x % 100000, bigint<3>("43456")); + + bigint<1> z = bigint<1>("1234"); + EXPECT_EQ(z - z, bigint<1>("0")); + EXPECT_EQ(z.power<4>(12), bigint<4>("12467572902176589255564000298710470656")); + + x.randomize(); + y = random_element_nonzero<3>(); + EXPECT_EQ(x - y, zero - (y - x)); + EXPECT_EQ(x - y - x, zero - y); + EXPECT_EQ(x / 2 / 3 / 25, x / 5 / 30); + EXPECT_TRUE(x % 2 == zero || x % 2 == one); +} diff --git a/libff/algebra/fields/binary/README.md b/libff/algebra/fields/binary/README.md new file mode 100644 index 00000000..a8614f71 --- /dev/null +++ b/libff/algebra/fields/binary/README.md @@ -0,0 +1,50 @@ +# Fields + +This folder contains implementations of various binary fields, +and some helper methods to distinguish these binary fields from the supported smooth prime fields from libff. +(These are distinguished as either "additive" or "multiplicative" field types from the utils file) + +For the binary fields, the irreducible polynomial of order `d` chosen is the lexicographically smallest +such polynomial of the given degree. +The field implementations provided in this library will utilize Intel intrinsics +if available, and otherwise will fall back to a pure C++ implementation.[1] +The implementation of field arithmetic will work for any irreducible polynomial +such that there is no term with degree greater than `d / 2` other than `x^d`. +The reason for this constraint is described in the multiplication section. + +[1]: More precisely, it depends on if the 128 bit carryless instruction is supported. This has the corresponnding CPUID flag: `PCLMULQDQ`. + +## Encoding +An element of a binary field can be represented as `d` bits, +where the `i`th bit counting from the right is `x^i`. +We encode these bits in fixed size arrays of int64s. +The size of the int64 array is `d / 64`. + +## Addition / Subtraction + +Addition over any field extension is carry-less addition. +In a binary field, this is equivalent to a XOR operation. +Similarly, in a binary field subtraction is equivalent to a XOR as well. + +## Multiplication + +Multiplication over a binary field is [carry-less multiplication](https://en.wikipedia.org/wiki/Carry-less_product), +with modular reduction. + +When taking advantage of Intrinsics, the relevant operation provided is `_mm_clmulepi64_si128`. +This allows carry-less multiplication of two 64 bit numbers into a 128 bit number. +Because there is no term in the irreducible polynomial with degree greater +than `d / 2` other than `x^d`, the number of operations needed for +modular reduction can be reduced. (See section 5.2 of [MS17]) + +This same multiplication implementation is used for squaring. + +## Inversion + +Field inversion is implemented as `x^{-1} = x^{2^d -2}`, using an addition chains for this exponentiation. +These addition chains were found using the Bergeron-Berstel-Brlek-Duboc method implemented in +https://github.com/kwantam/addchain. + +## References + +[MS17] [On Fast Multiplication in Binary Finite Fields and Optimal Primitive Polynomials over GF(2)](https://eprint.iacr.org/2017/889), Alexander Maximov and Helena Sjoberg, 2017. \ No newline at end of file diff --git a/libff/algebra/fields/binary/gf128.hpp b/libff/algebra/fields/binary/gf128.hpp new file mode 100644 index 00000000..29694ffb --- /dev/null +++ b/libff/algebra/fields/binary/gf128.hpp @@ -0,0 +1,103 @@ +/**@file + ***************************************************************************** + Declaration of GF(2^128) finite field. + ***************************************************************************** + * @author This file is part of libff (see AUTHORS), migrated from libiop + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ +#ifndef LIBFF_ALGEBRA_GF128_HPP_ +#define LIBFF_ALGEBRA_GF128_HPP_ + +#include +#include +#include +#include + +namespace libff { + +/* gf128 implements the field GF(2)/(x^128 + x^7 + x^2 + x + 1). + Elements are represented internally with two uint64s */ +class gf128 { +public: +#ifdef PROFILE_OP_COUNTS // NOTE: op counts are affected when you exponentiate with ^ + static long long add_cnt; + static long long sub_cnt; + static long long mul_cnt; + static long long sqr_cnt; + static long long inv_cnt; +#endif + // x^128 + x^7 + x^2 + x + 1 + static const constexpr uint64_t modulus_ = 0b10000111; + static const constexpr uint64_t num_bits = 128; + + explicit gf128(); + /* we need a constructor that only initializes the low half of value_ to + be able to do gf128(0) and gf128(1). */ + explicit gf128(const uint64_t value_low); + explicit gf128(const uint64_t value_high, const uint64_t value_low); + /** Returns the constituent bits in 64 bit words, in little-endian order */ + std::vector as_words() const; + + gf128& operator+=(const gf128 &other); + gf128& operator-=(const gf128 &other); + gf128& operator*=(const gf128 &other); + gf128& operator^=(const unsigned long pow); + template + gf128& operator^=(const bigint &pow); + + gf128& square(); + gf128& invert(); + + gf128 operator+(const gf128 &other) const; + gf128 operator-(const gf128 &other) const; + gf128 operator-() const; + gf128 operator*(const gf128 &other) const; + gf128 operator^(const unsigned long pow) const; + template + gf128 operator^(const bigint &pow) const; + + gf128 squared() const; + gf128 inverse() const; + /** HAS TO BE A SQUARE (else does not terminate). */ + gf128 sqrt() const; + + void randomize(); + void clear(); + + bool operator==(const gf128 &other) const; + bool operator!=(const gf128 &other) const; + + bool is_zero() const; + + void print() const; + + static gf128 random_element(); + + static gf128 zero(); + static gf128 one(); + static gf128 multiplicative_generator; // generator of gf128^* + + static std::size_t size_in_bits() { return num_bits; } + static constexpr std::size_t extension_degree() { return 128; } + template + static constexpr bigint field_char() { return bigint(2); } + + friend std::ostream& operator<<(std::ostream &out, const gf128 &p); + friend std::istream& operator>>(std::istream &in, gf128 &p); +private: + /* little-endian */ + uint64_t value_[2]; +}; + +#ifdef PROFILE_OP_COUNTS +long long gf128::add_cnt = 0; +long long gf128::sub_cnt = 0; +long long gf128::mul_cnt = 0; +long long gf128::sqr_cnt = 0; +long long gf128::inv_cnt = 0; +#endif + +} // namespace libff +#include + +#endif // LIBFF_ALGEBRA_GF128_HPP_ diff --git a/libff/algebra/fields/binary/gf128.tcc b/libff/algebra/fields/binary/gf128.tcc new file mode 100644 index 00000000..a8f0d523 --- /dev/null +++ b/libff/algebra/fields/binary/gf128.tcc @@ -0,0 +1,310 @@ +#include + +#define __STDC_FORMAT_MACROS +#include + +#include + +#include "libff/algebra/fields/binary/gf128.hpp" +#include "libff/algebra/field_utils/algorithms.hpp" + +#ifdef USE_ASM +#include +#include +#include +#endif + +namespace libff { + +using std::size_t; + +const uint64_t gf128::modulus_; +gf128 gf128::multiplicative_generator = gf128(2); + +gf128::gf128() : value_{0, 0} +{ +} + +gf128::gf128(const uint64_t value_low) : value_{value_low, 0} +{ +} + +gf128::gf128(const uint64_t value_high, const uint64_t value_low) : + value_{value_low, value_high} +{ +} + +std::vector gf128::as_words() const +{ + return std::vector({this->value_[0], this->value_[1]}); +} + +gf128& gf128::operator+=(const gf128 &other) +{ +#ifdef PROFILE_OP_COUNTS + this->add_cnt++; +#endif + this->value_[0] ^= other.value_[0]; + this->value_[1] ^= other.value_[1]; + return (*this); +} + +gf128& gf128::operator-=(const gf128 &other) +{ +#ifdef PROFILE_OP_COUNTS + this->sub_cnt++; +#endif + this->value_[0] ^= other.value_[0]; + this->value_[1] ^= other.value_[1]; + return (*this); +} + +gf128& gf128::operator*=(const gf128 &other) +{ +#ifdef PROFILE_OP_COUNTS + this->mul_cnt++; +#endif + /* Does not require *this and other to be different, and therefore + also works for squaring, implemented below. */ +#ifdef USE_ASM + /* load the two operands and the modulus into 128-bit registers */ + const __m128i a = _mm_loadu_si128((const __m128i*) &(this->value_)); + const __m128i b = _mm_loadu_si128((const __m128i*) &(other.value_)); + const __m128i modulus = _mm_loadl_epi64((const __m128i*) &(this->modulus_)); + + /* compute the 256-bit result of a * b with the 64x64-bit multiplication + intrinsic */ + __m128i mul256_high = _mm_clmulepi64_si128(a, b, 0x11); /* high of both */ + __m128i mul256_low = _mm_clmulepi64_si128(a, b, 0x00); /* low of both */ + + __m128i mul256_mid1 = _mm_clmulepi64_si128(a, b, 0x01); /* low of a, high of b */ + __m128i mul256_mid2 = _mm_clmulepi64_si128(a, b, 0x10); /* high of a, low of b */ + + /* Add the 4 terms together */ + __m128i mul256_mid = _mm_xor_si128(mul256_mid1, mul256_mid2); + /* lower 64 bits of mid don't intersect with high, and upper 64 bits don't intersect with low */ + mul256_high = _mm_xor_si128(mul256_high, _mm_srli_si128(mul256_mid, 8)); + mul256_low = _mm_xor_si128(mul256_low, _mm_slli_si128(mul256_mid, 8)); + + /* done computing mul256_low and mul256_high, time to reduce */ + + /* reduce w.r.t. high half of mul256_high */ + __m128i tmp = _mm_clmulepi64_si128(mul256_high, modulus, 0x01); + mul256_low = _mm_xor_si128(mul256_low, _mm_slli_si128(tmp, 8)); + mul256_high = _mm_xor_si128(mul256_high, _mm_srli_si128(tmp, 8)); + + /* reduce w.r.t. low half of mul256_high */ + tmp = _mm_clmulepi64_si128(mul256_high, modulus, 0x00); + mul256_low = _mm_xor_si128(mul256_low, tmp); + + _mm_storeu_si128((__m128i*) this->value_, mul256_low); + + return (*this); +#else + /* Slow, but straight-forward */ + uint64_t shifted[2] = {this->value_[0], this->value_[1]}; + uint64_t result[2] = {0, 0}; + + for (size_t i = 0; i < 2; ++i) + { + for (size_t j = 0; j < 64; ++j) + { + if (other.value_[i] & (1ull << j)) + { + result[0] ^= shifted[0]; + result[1] ^= shifted[1]; + } + + if (shifted[1] & (1ull << 63)) + { + shifted[1] = (shifted[1] << 1) | (shifted[0] >> 63); + shifted[0] = (shifted[0] << 1) ^ this->modulus_; + } else { + shifted[1] = (shifted[1] << 1) | (shifted[0] >> 63); + shifted[0] = shifted[0] << 1; + } + } + + } + + this->value_[0] = result[0]; + this->value_[1] = result[1]; + + return (*this); +#endif +} + +gf128& gf128::operator^=(const unsigned long pow) +{ + (*this) = *this ^ pow; + return (*this); +} + +template +gf128& gf128::operator^=(const bigint &pow) +{ + (*this) = *this ^ pow; + return (*this); +} + +gf128& gf128::square() +{ +#ifdef PROFILE_OP_COUNTS + this->sqr_cnt++; + this->mul_cnt--; +#endif + this->operator*=(*this); + return *this; +} + +gf128& gf128::invert() +{ + (*this) = inverse(); + return (*this); +} + +gf128 gf128::operator+(const gf128 &other) const +{ + gf128 result(*this); + return (result+=(other)); +} + +gf128 gf128::operator-(const gf128 &other) const +{ + gf128 result(*this); + return (result-=(other)); +} + +gf128 gf128::operator-() const +{ + return gf128(this->value_[1], this->value_[0]); +} + +gf128 gf128::operator*(const gf128 &other) const +{ + gf128 result(*this); + return (result*=(other)); +} + +gf128 gf128::operator^(const unsigned long pow) const +{ + return power(*this, pow); +} + +template +gf128 gf128::operator^(const bigint &pow) const +{ + return power(*this, pow); +} + +gf128 gf128::squared() const +{ + gf128 result(*this); + result.square(); + return result; +} + +/* calculate el^{-1} as el^{2^{128}-2}. the addition chain below + requires 142 mul/sqr operations total. */ +gf128 gf128::inverse() const +{ +#ifdef PROFILE_OP_COUNTS + this->inv_cnt++; + this->mul_cnt -= 13; + this->sqr_cnt -= 127; +#endif + assert(!this->is_zero()); + gf128 a(*this); + + gf128 result(0); + for (size_t i = 0; i <= 6; ++i) + { + /* entering the loop a = el^{2^{2^i}-1} */ + gf128 b = a; + for (size_t j = 0; j < (1ul<("170141183460469231731687303715884105728"); // 2^127 +} + +void gf128::randomize() +{ + randombytes_buf(&this->value_, 128/8); +} + +void gf128::clear() +{ + this->value_[0] = 0; + this->value_[1] = 0; +} + +bool gf128::operator==(const gf128 &other) const +{ + return (this->value_[0] == other.value_[0]) && ((this->value_[1] == other.value_[1])); +} + +bool gf128::operator!=(const gf128 &other) const +{ + return !(this->operator==(other)); +} + +bool gf128::is_zero() const +{ + return (this->value_[0] == 0) && (this->value_[1] == 0); +} + +void gf128::print() const +{ + printf("%016" PRIx64 "%016" PRIx64 "\n", this->value_[1], this->value_[0]); +} + +gf128 gf128::random_element() +{ + gf128 result; + result.randomize(); + return result; +} + +gf128 gf128::zero() +{ + return gf128(0); +} + +gf128 gf128::one() +{ + return gf128(1); +} + +std::ostream& operator<<(std::ostream &out, const gf128 &el) +{ + out << el.value_[0] << " " << el.value_[1]; + return out; +} + +std::istream& operator>>(std::istream &in, gf128 &el) +{ + in >> el.value_[0] >> el.value_[1]; + return in; +} + +} // namespace libff diff --git a/libff/algebra/fields/binary/gf192.hpp b/libff/algebra/fields/binary/gf192.hpp new file mode 100644 index 00000000..8a886811 --- /dev/null +++ b/libff/algebra/fields/binary/gf192.hpp @@ -0,0 +1,103 @@ +/**@file + ***************************************************************************** + Declaration of GF(2^192) finite field. + ***************************************************************************** + * @author This file is part of libff (see AUTHORS), migrated from libiop + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ +#ifndef LIBFF_ALGEBRA_GF192_HPP_ +#define LIBFF_ALGEBRA_GF192_HPP_ + +#include +#include +#include +#include + +namespace libff { + +/* gf192 implements the field GF(2)/(x^192 + x^7 + x^2 + x + 1). + Elements are represented internally with three uint64s */ +class gf192 { +public: +#ifdef PROFILE_OP_COUNTS // NOTE: op counts are affected when you exponentiate with ^ + static long long add_cnt; + static long long sub_cnt; + static long long mul_cnt; + static long long sqr_cnt; + static long long inv_cnt; +#endif + // x^192 + x^7 + x^2 + x + 1 + static const constexpr uint64_t modulus_ = 0b10000111; + static const constexpr uint64_t num_bits = 192; + + explicit gf192(); + /* we need a constructor that only initializes the low half of value_ to + be able to do gf192(0) and gf192(1). */ + explicit gf192(const uint64_t value_low); + explicit gf192(const uint64_t value_high, const uint64_t value_mid, const uint64_t value_low); + /** Returns the constituent bits in 64 bit words, in little-endian order */ + std::vector as_words() const; + + gf192& operator+=(const gf192 &other); + gf192& operator-=(const gf192 &other); + gf192& operator*=(const gf192 &other); + gf192& operator^=(const unsigned long pow); + template + gf192& operator^=(const bigint &pow); + + gf192& square(); + gf192& invert(); + + gf192 operator+(const gf192 &other) const; + gf192 operator-(const gf192 &other) const; + gf192 operator-() const; + gf192 operator*(const gf192 &other) const; + gf192 operator^(const unsigned long pow) const; + template + gf192 operator^(const bigint &pow) const; + + gf192 squared() const; + gf192 inverse() const; + /** HAS TO BE A SQUARE (else does not terminate). */ + gf192 sqrt() const; + + void randomize(); + void clear(); + + bool operator==(const gf192 &other) const; + bool operator!=(const gf192 &other) const; + + bool is_zero() const; + + void print() const; + + static gf192 random_element(); + + static gf192 zero(); + static gf192 one(); + static gf192 multiplicative_generator; // generator of gf192^* + + static std::size_t size_in_bits() { return num_bits; } + static constexpr std::size_t extension_degree() { return 192; } + template + static constexpr bigint field_char() { return bigint(2); } + + friend std::ostream& operator<<(std::ostream &out, const gf192 &p); + friend std::istream& operator>>(std::istream &in, gf192 &p); +private: + /* little-endian */ + uint64_t value_[3]; +}; + +#ifdef PROFILE_OP_COUNTS +long long gf192::add_cnt = 0; +long long gf192::sub_cnt = 0; +long long gf192::mul_cnt = 0; +long long gf192::sqr_cnt = 0; +long long gf192::inv_cnt = 0; +#endif + +} // namespace libff +#include + +#endif // LIBFF_ALGEBRA_GF192_HPP_ diff --git a/libff/algebra/fields/binary/gf192.tcc b/libff/algebra/fields/binary/gf192.tcc new file mode 100644 index 00000000..9ae5e6c5 --- /dev/null +++ b/libff/algebra/fields/binary/gf192.tcc @@ -0,0 +1,363 @@ +#include + +#define __STDC_FORMAT_MACROS +#include + +#include + +#include "libff/algebra/fields/binary/gf192.hpp" +#include "libff/algebra/field_utils/algorithms.hpp" + +#ifdef USE_ASM +#include +#include +#include +#endif + +namespace libff { + +using std::size_t; + +const uint64_t gf192::modulus_; +gf192 gf192::multiplicative_generator = gf192(2); + +gf192::gf192() : value_{0, 0, 0} +{ +} + +gf192::gf192(const uint64_t value_low) : value_{value_low, 0, 0} +{ +} + +gf192::gf192(const uint64_t value_high, const uint64_t value_mid, const uint64_t value_low) : + value_{value_low, value_mid, value_high} +{ +} + +std::vector gf192::as_words() const +{ + return std::vector({this->value_[0], this->value_[1], this->value_[2]}); +} + +gf192& gf192::operator+=(const gf192 &other) +{ +#ifdef PROFILE_OP_COUNTS + this->add_cnt++; +#endif + this->value_[0] ^= other.value_[0]; + this->value_[1] ^= other.value_[1]; + this->value_[2] ^= other.value_[2]; + return (*this); +} + +gf192& gf192::operator-=(const gf192 &other) +{ +#ifdef PROFILE_OP_COUNTS + this->sub_cnt++; +#endif + this->value_[0] ^= other.value_[0]; + this->value_[1] ^= other.value_[1]; + this->value_[2] ^= other.value_[2]; + return (*this); +} + +gf192& gf192::operator*=(const gf192 &other) +{ +#ifdef PROFILE_OP_COUNTS + this->mul_cnt++; +#endif + /* Does not require *this and other to be different, and therefore + also works for squaring, implemented below. */ +#ifdef USE_ASM + /* load the two operands and the modulus into 128-bit registers. + we load corresponding limbs of both operands into a single register, + because it lets us implement Karatsuba (see below) with fewer 128-bit + xors. */ + const __m128i ab0 = _mm_set_epi64x(this->value_[0], other.value_[0]); + const __m128i ab1 = _mm_set_epi64x(this->value_[1], other.value_[1]); + const __m128i ab2 = _mm_set_epi64x(this->value_[2], other.value_[2]); + const __m128i modulus = _mm_loadl_epi64((const __m128i*) &(this->modulus_)); + + /* here we implement a Karatsuba-like approach for multiplying 3-limb numbers. + given + a = a0 + B * a1 + B^2 * a2 + b = b0 + B * b1 + B^2 * b2 + we can compute + c = c0 + ... + B^4 * c4 + (where ai and bi are < B, but ci are < B^2) + with 6 multiplications as follows: + 1. c0 = a0 * b0 + 2. c4 = a2 * b2 + 3. t = a1 * b1 + 4. c1 = (a0 + a1) * (b0 + b1) - c0 - t + 5. c3 = (a1 + a2) * (b1 + b2) - c4 - t + 6. c2 = (a0 + a2) * (b0 + b2) - c0 - c4 + t */ + __m128i c0 = _mm_clmulepi64_si128(ab0, ab0, 0x01); /* multiply low and high halves */ + __m128i c4 = _mm_clmulepi64_si128(ab2, ab2, 0x01); + + __m128i t = _mm_clmulepi64_si128(ab1, ab1, 0x01); + + __m128i xor01 = _mm_xor_si128(ab0, ab1); + __m128i c1 = _mm_clmulepi64_si128(xor01, xor01, 0x01); + c1 = _mm_xor_si128(_mm_xor_si128(c1, c0), t); + + __m128i xor12 = _mm_xor_si128(ab1, ab2); + __m128i c3 = _mm_clmulepi64_si128(xor12, xor12, 0x01); + c3 = _mm_xor_si128(_mm_xor_si128(c3, c4), t); + + __m128i xor02 = _mm_xor_si128(ab0, ab2); + __m128i c2 = _mm_clmulepi64_si128(xor02, xor02, 0x01); + c2 = _mm_xor_si128(_mm_xor_si128(_mm_xor_si128(c2, c0), c4), t); + + /* now let's compute + d = d0 + B^2 * d1 + B^4 d2 + where d = c and di < B^2 */ + __m128i d0 = _mm_xor_si128(c0, _mm_slli_si128(c1, 8)); + __m128i d2 = _mm_xor_si128(c4, _mm_srli_si128(c3, 8)); + __m128i d1 = _mm_xor_si128(_mm_xor_si128(c2, _mm_srli_si128(c1, 8)), + _mm_slli_si128(c3, 8)); + + /* done with the multiplication, time to reduce */ + + /* reduce w.r.t. high half of d2 */ + __m128i tmp = _mm_clmulepi64_si128(d2, modulus, 0x01); + d1 = _mm_xor_si128(d1, tmp); + + /* reduce w.r.t. low half of d2 */ + tmp = _mm_clmulepi64_si128(d2, modulus, 0x00); + d1 = _mm_xor_si128(d1, _mm_srli_si128(tmp, 8)); + d0 = _mm_xor_si128(d0, _mm_slli_si128(tmp, 8)); + + /* reduce w.r.t. high half of d1 */ + tmp = _mm_clmulepi64_si128(d1, modulus, 0x01); + d0 = _mm_xor_si128(d0, tmp); + + /* done, now just store everything back into this->value_ */ + _mm_storeu_si128((__m128i*) &this->value_[0], d0); + _mm_storel_epi64((__m128i*) &this->value_[2], d1); + + return (*this); +#else + /* Slow, but straight-forward */ + uint64_t shifted[3] = {this->value_[0], this->value_[1], this->value_[2]}; + uint64_t result[3] = {0, 0, 0}; + + for (size_t i = 0; i < 3; ++i) + { + for (size_t j = 0; j < 64; ++j) + { + if (other.value_[i] & (1ull << j)) + { + result[0] ^= shifted[0]; + result[1] ^= shifted[1]; + result[2] ^= shifted[2]; + } + + if (shifted[2] & (1ull << 63)) + { + shifted[2] = (shifted[2] << 1) | (shifted[1] >> 63); + shifted[1] = (shifted[1] << 1) | (shifted[0] >> 63); + shifted[0] = (shifted[0] << 1) ^ this->modulus_; + } else { + shifted[2] = (shifted[2] << 1) | (shifted[1] >> 63); + shifted[1] = (shifted[1] << 1) | (shifted[0] >> 63); + shifted[0] = shifted[0] << 1; + } + } + + } + + this->value_[0] = result[0]; + this->value_[1] = result[1]; + this->value_[2] = result[2]; + + return (*this); +#endif +} + +gf192& gf192::operator^=(const unsigned long pow) +{ + (*this) = *this ^ pow; + return (*this); +} + +template +gf192& gf192::operator^=(const bigint &pow) +{ + (*this) = *this ^ pow; + return (*this); +} + +gf192& gf192::square() +{ +#ifdef PROFILE_OP_COUNTS + this->sqr_cnt++; + this->mul_cnt--; +#endif + this->operator*=(*this); + return *this; +} + +gf192& gf192::invert() +{ + (*this) = inverse(); + return (*this); +} + +gf192 gf192::operator+(const gf192 &other) const +{ + gf192 result(*this); + return (result+=(other)); +} + +gf192 gf192::operator-(const gf192 &other) const +{ + gf192 result(*this); + return (result-=(other)); +} + +gf192 gf192::operator-() const +{ + return gf192(*this); +} + +gf192 gf192::operator*(const gf192 &other) const +{ + gf192 result(*this); + return (result*=(other)); +} + +gf192 gf192::operator^(const unsigned long pow) const +{ + return power(*this, pow); +} + +template +gf192 gf192::operator^(const bigint &pow) const +{ + return power(*this, pow); +} + +gf192 gf192::squared() const +{ + gf192 result(*this); + result.square(); + return result; +} + +/* calculate el^{-1} as el^{2^{192}-2}. the addition chain below + requires 210 mul/sqr operations total. */ +gf192 gf192::inverse() const +{ +#ifdef PROFILE_OP_COUNTS + this->inv_cnt++; + this->mul_cnt -= 15; + this->sqr_cnt -= 193; +#endif + assert(!this->is_zero()); + gf192 a(*this); + + gf192 result(0); + gf192 prev_result(0); + for (size_t i = 0; i <= 6; ++i) + { + /* entering the loop a = el^{2^{2^i}-1} */ + gf192 b = a; + for (size_t j = 0; j < (1ul<squared(); +} + +gf192 gf192::sqrt() const +{ + return (*this)^bigint<3>("3138550867693340381917894711603833208051177722232017256448"); // 2^191 +} + +void gf192::randomize() +{ + randombytes_buf(&this->value_, 192/8); +} + +void gf192::clear() +{ + this->value_[0] = 0; + this->value_[1] = 0; + this->value_[2] = 0; +} + +bool gf192::operator==(const gf192 &other) const +{ + return ((this->value_[0] == other.value_[0]) && + (this->value_[1] == other.value_[1]) && + (this->value_[2] == other.value_[2])); +} + +bool gf192::operator!=(const gf192 &other) const +{ + return !(this->operator==(other)); +} + +bool gf192::is_zero() const +{ + return (this->value_[0] == 0) && (this->value_[1] == 0) && (this->value_[2] == 0); +} + +void gf192::print() const +{ + printf("%016" PRIx64 "%016" PRIx64 "%016" PRIx64 "\n", this->value_[2], this->value_[1], this->value_[0]); +} + +gf192 gf192::random_element() +{ + gf192 result; + result.randomize(); + return result; +} + +gf192 gf192::zero() +{ + return gf192(0); +} + +gf192 gf192::one() +{ + return gf192(1); +} + +std::ostream& operator<<(std::ostream &out, const gf192 &el) +{ + out << el.value_[0] << " " << el.value_[1] << " " << el.value_[2]; + return out; +} + +std::istream& operator>>(std::istream &in, gf192 &el) +{ + in >> el.value_[0] >> el.value_[1] >> el.value_[2]; + return in; +} + +} // namespace libff diff --git a/libff/algebra/fields/binary/gf256.hpp b/libff/algebra/fields/binary/gf256.hpp new file mode 100644 index 00000000..a550dcdb --- /dev/null +++ b/libff/algebra/fields/binary/gf256.hpp @@ -0,0 +1,105 @@ +/**@file + ***************************************************************************** + Declaration of GF(2^256) finite field. + ***************************************************************************** + * @author This file is part of libff (see AUTHORS), migrated from libiop + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ +#ifndef LIBFF_ALGEBRA_GF256_HPP_ +#define LIBFF_ALGEBRA_GF256_HPP_ + +#include +#include +#include +#include + +namespace libff { + +/* x^256 + x^10 + x^5 + x^2 + 1 */ +/* gf256 implements the field GF(2)/(x^256 + x^10 + x^5 + x^2 + 1). + Elements are represented internally with four uint64s */ +class gf256 { +public: +#ifdef PROFILE_OP_COUNTS // NOTE: op counts are affected when you exponentiate with ^ + static long long add_cnt; + static long long sub_cnt; + static long long mul_cnt; + static long long sqr_cnt; + static long long inv_cnt; +#endif + // x^256 + x^10 + x^5 + x^2 + 1 + static const constexpr uint64_t modulus_ = 0b10000100101; + static const constexpr uint64_t num_bits = 256; + + explicit gf256(); + /* we need a constructor that only initializes the low 64 bits of value_ to + be able to do gf256(0) and gf256(1). */ + explicit gf256(const uint64_t value_low); + explicit gf256(const uint64_t value_high, const uint64_t value_midh, + const uint64_t value_midl, const uint64_t value_low); + /** Returns the constituent bits in 64 bit words, in little-endian order */ + std::vector as_words() const; + + gf256& operator+=(const gf256 &other); + gf256& operator-=(const gf256 &other); + gf256& operator*=(const gf256 &other); + gf256& operator^=(const unsigned long pow); + template + gf256& operator^=(const bigint &pow); + + gf256& square(); + gf256& invert(); + + gf256 operator+(const gf256 &other) const; + gf256 operator-(const gf256 &other) const; + gf256 operator-() const; + gf256 operator*(const gf256 &other) const; + gf256 operator^(const unsigned long pow) const; + template + gf256 operator^(const bigint &pow) const; + + gf256 squared() const; + gf256 inverse() const; + /** HAS TO BE A SQUARE (else does not terminate). */ + gf256 sqrt() const; + + void randomize(); + void clear(); + + bool operator==(const gf256 &other) const; + bool operator!=(const gf256 &other) const; + + bool is_zero() const; + + void print() const; + + static gf256 random_element(); + + static gf256 zero(); + static gf256 one(); + static gf256 multiplicative_generator; // generator of gf256^* + + static std::size_t size_in_bits() { return num_bits; } + static constexpr std::size_t extension_degree() { return 256; } + template + static constexpr bigint field_char() { return bigint(2); } + + friend std::ostream& operator<<(std::ostream &out, const gf256 &p); + friend std::istream& operator>>(std::istream &in, gf256 &p); +private: + /* little-endian */ + uint64_t value_[4]; +}; + +#ifdef PROFILE_OP_COUNTS +long long gf256::add_cnt = 0; +long long gf256::sub_cnt = 0; +long long gf256::mul_cnt = 0; +long long gf256::sqr_cnt = 0; +long long gf256::inv_cnt = 0; +#endif + +} // namespace libff +#include + +#endif // LIBFF_ALGEBRA_GF256_HPP_ diff --git a/libff/algebra/fields/binary/gf256.tcc b/libff/algebra/fields/binary/gf256.tcc new file mode 100644 index 00000000..575795b3 --- /dev/null +++ b/libff/algebra/fields/binary/gf256.tcc @@ -0,0 +1,439 @@ +#include + +#define __STDC_FORMAT_MACROS +#include + +#include + +#include "libff/algebra/fields/binary/gf256.hpp" +#include "libff/algebra/field_utils/algorithms.hpp" + +#ifdef USE_ASM +#include +#include +#include +#endif + +namespace libff { + +using std::size_t; + +const uint64_t gf256::modulus_; +gf256 gf256::multiplicative_generator = gf256(2); + +gf256::gf256() : value_{0, 0, 0, 0} +{ +} + +gf256::gf256(const uint64_t value_low) : value_{value_low, 0, 0, 0} +{ +} + +gf256::gf256(const uint64_t value_high, const uint64_t value_midh, + const uint64_t value_midl, const uint64_t value_low) : + value_{value_low, value_midl, value_midh, value_high} +{ +} + +std::vector gf256::as_words() const +{ + return std::vector({this->value_[0], this->value_[1], this->value_[2], this->value_[3]}); +} + +gf256& gf256::operator+=(const gf256 &other) +{ +#ifdef PROFILE_OP_COUNTS + this->add_cnt++; +#endif + this->value_[0] ^= other.value_[0]; + this->value_[1] ^= other.value_[1]; + this->value_[2] ^= other.value_[2]; + this->value_[3] ^= other.value_[3]; + return (*this); +} + +gf256& gf256::operator-=(const gf256 &other) +{ +#ifdef PROFILE_OP_COUNTS + this->sub_cnt++; +#endif + this->value_[0] ^= other.value_[0]; + this->value_[1] ^= other.value_[1]; + this->value_[2] ^= other.value_[2]; + this->value_[3] ^= other.value_[3]; + return (*this); +} + +gf256& gf256::operator*=(const gf256 &other) +{ +#ifdef PROFILE_OP_COUNTS + this->mul_cnt++; +#endif + /* Does not require *this and other to be different, and therefore + also works for squaring, implemented below. */ +#ifdef USE_ASM + /* depending on the manufacturer and generation of a CPU, the PCLMUL + instruction might take different amounts of time. + empirically, it appears that on recent Intel CPUs, PCLMUL is so fast that + a naive multiplicator that uses 16 PCLMULs is faster than anything more + complicated (because time spent doing non-PCLMUL operations dominates). + on AMD CPUs, however, more complicated multiplicators (e.g. Karatsuba, + which uses a total of 9 multiplications) can be faster. + + thus we use a preprocessor flag to choose between a naive and a Karatsuba + multiplicator. */ +#ifdef ASM_MINIMIZE_CLMULS + /* here we implement a Karatsuba-like approach for multiplying 4-limb numbers. + + given + a = a0 + B * a1 + B^2 * a2 + B^3 * a3 + b = b0 + B * b1 + B^2 * b2 + B^3 * b3 + we can compute + c = a * b = c0 + ... + B^6 * c6 + (where ai and bi are < B, but ci are < B^2) + with 9 multiplications as follows: + 1. c0 = a0 * b0 + 2. c6 = a3 * b3 + 3. t = a1 * b1 + 4. u = a2 * b2 + 5. c1 = (a0 + a1) * (b0 + b1) - c0 - t + 6. c2 = (a0 + a2) * (b0 + b2) - c0 + t - u + 7. c5 = (a2 + a3) * (b2 + b3) - c6 - u + 8. c4 = (a1 + a3) * (b1 + b3) - c6 + u - t + 9. c3 = (a0 + a1 + a2 + a3) * (b0 + b1 + b2 + b3) + - c0 - c1 - c2 - c4 - c5 - c6 */ + + /* load the two operands and the modulus into 128-bit registers. + we load corresponding limbs of both operands into a single register, + because it lets us implement Karatsuba with fewer 128-bit xors. */ + const __m128i ab0 = _mm_set_epi64x(this->value_[0], other.value_[0]); + const __m128i ab1 = _mm_set_epi64x(this->value_[1], other.value_[1]); + const __m128i ab2 = _mm_set_epi64x(this->value_[2], other.value_[2]); + const __m128i ab3 = _mm_set_epi64x(this->value_[3], other.value_[3]); + const __m128i modulus = _mm_loadl_epi64((const __m128i*) &(this->modulus_)); + __m128i c0 = _mm_clmulepi64_si128(ab0, ab0, 0x01); /* multiply low and high halves */ + __m128i c6 = _mm_clmulepi64_si128(ab3, ab3, 0x01); + + __m128i t = _mm_clmulepi64_si128(ab1, ab1, 0x01); + __m128i u = _mm_clmulepi64_si128(ab2, ab2, 0x01); + + __m128i xor01 = _mm_xor_si128(ab0, ab1); + __m128i c1 = _mm_clmulepi64_si128(xor01, xor01, 0x01); + __m128i xor_c0_t = _mm_xor_si128(c0, t); + c1 = _mm_xor_si128(c1, xor_c0_t); + + __m128i xor02 = _mm_xor_si128(ab0, ab2); + __m128i c2 = _mm_clmulepi64_si128(xor02, xor02, 0x01); + c2 = _mm_xor_si128(_mm_xor_si128(c2, xor_c0_t), u); + + __m128i xor23 = _mm_xor_si128(ab2, ab3); + __m128i c5 = _mm_clmulepi64_si128(xor23, xor23, 0x01); + __m128i xor_c6_u = _mm_xor_si128(c6, u); + c5 = _mm_xor_si128(c5, xor_c6_u); + + __m128i xor13 = _mm_xor_si128(ab1, ab3); + __m128i c4 = _mm_clmulepi64_si128(xor13, xor13, 0x01); + c4 = _mm_xor_si128(_mm_xor_si128(c4, xor_c6_u), t); + + __m128i xor0123 = _mm_xor_si128(xor02, xor13); + __m128i c3 = _mm_clmulepi64_si128(xor0123, xor0123, 0x01); + c3 = _mm_xor_si128(_mm_xor_si128(_mm_xor_si128( + _mm_xor_si128(_mm_xor_si128(_mm_xor_si128( + c3, c0), c1), c2), c4), c5), c6); + +#else // ASM_MINIMIZE_CLMULS + /* here we compute the same c as in Karatsuba, but by just naively + multiplying all pairs of limbs of the operands and adding together + the results that correspond to the same shift. */ + const __m128i a_low = _mm_loadu_si128((const __m128i*) &(this->value_[0])); + const __m128i a_high = _mm_loadu_si128((const __m128i*) &(this->value_[2])); + const __m128i b_low = _mm_loadu_si128((const __m128i*) &(other.value_[0])); + const __m128i b_high = _mm_loadu_si128((const __m128i*) &(other.value_[2])); + const __m128i modulus = _mm_loadl_epi64((const __m128i*) &(this->modulus_)); + + __m128i m00 = _mm_clmulepi64_si128(a_low, b_low, 0x00); + __m128i m01 = _mm_clmulepi64_si128(a_low, b_low, 0x10); + __m128i m10 = _mm_clmulepi64_si128(a_low, b_low, 0x01); + __m128i m11 = _mm_clmulepi64_si128(a_low, b_low, 0x11); + __m128i m20 = _mm_clmulepi64_si128(a_high, b_low, 0x00); + __m128i m21 = _mm_clmulepi64_si128(a_high, b_low, 0x10); + __m128i m30 = _mm_clmulepi64_si128(a_high, b_low, 0x01); + __m128i m31 = _mm_clmulepi64_si128(a_high, b_low, 0x11); + __m128i m02 = _mm_clmulepi64_si128(a_low, b_high, 0x00); + __m128i m03 = _mm_clmulepi64_si128(a_low, b_high, 0x10); + __m128i m12 = _mm_clmulepi64_si128(a_low, b_high, 0x01); + __m128i m13 = _mm_clmulepi64_si128(a_low, b_high, 0x11); + __m128i m22 = _mm_clmulepi64_si128(a_high, b_high, 0x00); + __m128i m23 = _mm_clmulepi64_si128(a_high, b_high, 0x10); + __m128i m32 = _mm_clmulepi64_si128(a_high, b_high, 0x01); + __m128i m33 = _mm_clmulepi64_si128(a_high, b_high, 0x11); + + __m128i c0 = m00; + __m128i c1 = _mm_xor_si128(m01, m10); + __m128i c2 = _mm_xor_si128(_mm_xor_si128(m02, m11), m20); + __m128i c3 = _mm_xor_si128(_mm_xor_si128(_mm_xor_si128(m03, m12), m21), m30); + __m128i c4 = _mm_xor_si128(_mm_xor_si128(m13, m22), m31); + __m128i c5 = _mm_xor_si128(m23, m32); + __m128i c6 = m33; + +#endif // ASM_MINIMIZE_CLMULS + + /* this part is common to both multiplication algorithms: + given the 6 overlapping 128-bit limbs such that + a * b = c0 + (c1 << 64) + (c2 << 128) + (c3 << 192) + ... (c6 << 384) + merge them into non-overlapping 128-bit limbs + a * b = d0 + (d1 << 128) + (d2 << 256) + (d3 << 384) */ + __m128i d0 = _mm_xor_si128(c0, _mm_slli_si128(c1, 8)); + __m128i d1 = _mm_xor_si128(_mm_xor_si128(c2, _mm_srli_si128(c1, 8)), _mm_slli_si128(c3, 8)); + __m128i d2 = _mm_xor_si128(_mm_xor_si128(c4, _mm_srli_si128(c3, 8)), _mm_slli_si128(c5, 8)); + __m128i d3 = _mm_xor_si128(c6, _mm_srli_si128(c5, 8)); + + /* done with the multiplication, time to reduce */ + + /* reduce w.r.t. high half of d3 */ + __m128i tmp = _mm_clmulepi64_si128(d3, modulus, 0x01); + d2 = _mm_xor_si128(d2, _mm_srli_si128(tmp, 8)); + d1 = _mm_xor_si128(d1, _mm_slli_si128(tmp, 8)); + + /* reduce w.r.t. low half of d3 */ + tmp = _mm_clmulepi64_si128(d3, modulus, 0x00); + d1 = _mm_xor_si128(d1, tmp); + + /* reduce w.r.t. high half of d2 */ + tmp = _mm_clmulepi64_si128(d2, modulus, 0x01); + d1 = _mm_xor_si128(d1, _mm_srli_si128(tmp, 8)); + d0 = _mm_xor_si128(d0, _mm_slli_si128(tmp, 8)); + + /* reduce w.r.t. low half of d2 */ + tmp = _mm_clmulepi64_si128(d2, modulus, 0x00); + d0 = _mm_xor_si128(d0, tmp); + + /* done, now just store everything back into this->value_ */ + _mm_storeu_si128((__m128i*) &this->value_[0], d0); + _mm_storeu_si128((__m128i*) &this->value_[2], d1); + + return (*this); +#else + /* Slow, but straight-forward */ + uint64_t shifted[4] = {this->value_[0], this->value_[1], + this->value_[2], this->value_[3]}; + uint64_t result[4] = {0, 0, 0, 0}; + + for (size_t i = 0; i < 4; ++i) + { + for (size_t j = 0; j < 64; ++j) + { + if (other.value_[i] & (1ull << j)) + { + result[0] ^= shifted[0]; + result[1] ^= shifted[1]; + result[2] ^= shifted[2]; + result[3] ^= shifted[3]; + } + + bool reduce = (shifted[3] & (1ull << 63)); + + shifted[3] = (shifted[3] << 1) | (shifted[2] >> 63); + shifted[2] = (shifted[2] << 1) | (shifted[1] >> 63); + shifted[1] = (shifted[1] << 1) | (shifted[0] >> 63); + shifted[0] = shifted[0] << 1; + + if (reduce) + { + shifted[0] ^= this->modulus_; + } + } + + } + + this->value_[0] = result[0]; + this->value_[1] = result[1]; + this->value_[2] = result[2]; + this->value_[3] = result[3]; +#endif + + return (*this); +} + +gf256& gf256::operator^=(const unsigned long pow) +{ + (*this) = *this ^ pow; + return (*this); +} + +template +gf256& gf256::operator^=(const bigint &pow) +{ + (*this) = *this ^ pow; + return (*this); +} + +gf256& gf256::square() +{ +#ifdef PROFILE_OP_COUNTS + this->sqr_cnt++; + this->mul_cnt--; +#endif + this->operator*=(*this); + return *this; +} + +gf256& gf256::invert() +{ + (*this) = inverse(); + return (*this); +} + +gf256 gf256::operator+(const gf256 &other) const +{ + gf256 result(*this); + return (result+=(other)); +} + +gf256 gf256::operator-(const gf256 &other) const +{ + gf256 result(*this); + return (result-=(other)); +} + +gf256 gf256::operator-() const +{ + return gf256(*this); +} + +gf256 gf256::operator*(const gf256 &other) const +{ + gf256 result(*this); + return (result*=(other)); +} + +gf256 gf256::operator^(const unsigned long pow) const +{ + return power(*this, pow); +} + +template +gf256 gf256::operator^(const bigint &pow) const +{ + return power(*this, pow); +} + +gf256 gf256::squared() const +{ + gf256 result(*this); + result.square(); + return result; +} + +/* calculate el^{-1} as el^{2^{256}-2}. the addition chain below + requires 270 mul/sqr operations total. */ +gf256 gf256::inverse() const +{ +#ifdef PROFILE_OP_COUNTS + this->inv_cnt++; + this->mul_cnt -= 15; + this->sqr_cnt -= 255; +#endif + assert(!this->is_zero()); + gf256 a(*this); + + gf256 result(0); + for (size_t i = 0; i <= 7; ++i) + { + /* entering the loop a = el^{2^{2^i}-1} */ + gf256 b = a; + for (size_t j = 0; j < (1ul<("57896044618658097711785492504343953926634992332820282019728792003956564819968"); // 2^255 +} + +void gf256::randomize() +{ + randombytes_buf(&this->value_, 256/8); +} + +void gf256::clear() +{ + this->value_[0] = 0; + this->value_[1] = 0; + this->value_[2] = 0; + this->value_[3] = 0; +} + +bool gf256::operator==(const gf256 &other) const +{ + return ((this->value_[0] == other.value_[0]) && + (this->value_[1] == other.value_[1]) && + (this->value_[2] == other.value_[2]) && + (this->value_[3] == other.value_[3])); +} + +bool gf256::operator!=(const gf256 &other) const +{ + return !(this->operator==(other)); +} + +bool gf256::is_zero() const +{ + return (this->value_[0] == 0) && (this->value_[1] == 0) && + (this->value_[2] == 0) && (this->value_[3] == 0); +} + +void gf256::print() const +{ + printf("%016" PRIx64 "%016" PRIx64 "%016" PRIx64 "%016" PRIx64 "\n", + this->value_[3], this->value_[2], + this->value_[1], this->value_[0]); +} + +gf256 gf256::random_element() +{ + gf256 result; + result.randomize(); + return result; +} + +gf256 gf256::zero() +{ + return gf256(0); +} + +gf256 gf256::one() +{ + return gf256(1); +} + +std::ostream& operator<<(std::ostream &out, const gf256 &el) +{ + out << el.value_[0] << " " << el.value_[1] << " " << el.value_[2] << " " << el.value_[3]; + return out; +} + +std::istream& operator>>(std::istream &in, gf256 &el) +{ + in >> el.value_[0] >> el.value_[1] >> el.value_[2] >> el.value_[3]; + return in; +} + +} // namespace libff diff --git a/libff/algebra/fields/binary/gf32.hpp b/libff/algebra/fields/binary/gf32.hpp new file mode 100644 index 00000000..1797def7 --- /dev/null +++ b/libff/algebra/fields/binary/gf32.hpp @@ -0,0 +1,98 @@ +/**@file + ***************************************************************************** + Declaration of GF(2^32) finite field. + ***************************************************************************** + * @author This file is part of libff (see AUTHORS), migrated from libiop + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ +#ifndef LIBFF_ALGEBRA_GF32_HPP_ +#define LIBFF_ALGEBRA_GF32_HPP_ + +#include +#include +#include +#include + +namespace libff { + +/* gf32 implements the field GF(2)/[x^32 + x^22 + x^2 + x^1 + 1]. + Elements are represented internally with a single uint32 */ +class gf32 { +public: +#ifdef PROFILE_OP_COUNTS // NOTE: op counts are affected when you exponentiate with ^ + static long long add_cnt; + static long long sub_cnt; + static long long mul_cnt; + static long long sqr_cnt; + static long long inv_cnt; +#endif + // x^32 + x^22 + x^2 + x^1 + 1 + static const constexpr uint64_t modulus_ = 0b10000000000000000000111; + static const constexpr uint64_t num_bits = 32; + + explicit gf32(); + explicit gf32(const uint32_t value); + std::vector as_words() const; + + gf32& operator+=(const gf32 &other); + gf32& operator-=(const gf32 &other); + gf32& operator*=(const gf32 &other); + gf32& operator^=(const unsigned long pow); + template + gf32& operator^=(const bigint &pow); + + gf32& square(); + gf32& invert(); + + gf32 operator+(const gf32 &other) const; + gf32 operator-(const gf32 &other) const; + gf32 operator-() const; + gf32 operator*(const gf32 &other) const; + gf32 operator^(const unsigned long pow) const; + template + gf32 operator^(const bigint &pow) const; + + gf32 squared() const; + gf32 inverse() const; + /** HAS TO BE A SQUARE (else does not terminate). */ + gf32 sqrt() const; + + void randomize(); + void clear(); + + bool operator==(const gf32 &other) const; + bool operator!=(const gf32 &other) const; + + bool is_zero() const; + + void print() const; + + static gf32 random_element(); + + static gf32 zero(); + static gf32 one(); + static gf32 multiplicative_generator; // generator of gf32^* + + static std::size_t size_in_bits() { return num_bits; } + static constexpr std::size_t extension_degree() { return 32; } + template + static constexpr bigint field_char() { return bigint(2); } + + friend std::ostream& operator<<(std::ostream &out, const gf32 &p); + friend std::istream& operator>>(std::istream &in, gf32 &p); +private: + uint32_t value_; +}; + +#ifdef PROFILE_OP_COUNTS +long long gf32::add_cnt = 0; +long long gf32::sub_cnt = 0; +long long gf32::mul_cnt = 0; +long long gf32::sqr_cnt = 0; +long long gf32::inv_cnt = 0; +#endif + +} // namespace libff +#include + +#endif // #ifndef LIBFF_ALGEBRA_GF32_HPP_ diff --git a/libff/algebra/fields/binary/gf32.tcc b/libff/algebra/fields/binary/gf32.tcc new file mode 100644 index 00000000..2636bc41 --- /dev/null +++ b/libff/algebra/fields/binary/gf32.tcc @@ -0,0 +1,271 @@ +#include + +#define __STDC_FORMAT_MACROS +#include + +#include + +#include "libff/algebra/fields/binary/gf32.hpp" +#include "libff/algebra/field_utils/algorithms.hpp" + +#ifdef USE_ASM +#include +#include +#include +#endif + +namespace libff { + +using std::size_t; + +const uint64_t gf32::modulus_; +gf32 gf32::multiplicative_generator = gf32(2); + +gf32::gf32() : value_(0) +{ +} + +gf32::gf32(const uint32_t value) : value_(value) +{ +} + +std::vector gf32::as_words() const +{ + return std::vector({uint64_t(this->value_)}); +} + +gf32& gf32::operator+=(const gf32 &other) +{ +#ifdef PROFILE_OP_COUNTS + this->add_cnt++; +#endif + this->value_ ^= other.value_; + return (*this); +} + +gf32& gf32::operator-=(const gf32 &other) +{ +#ifdef PROFILE_OP_COUNTS + this->sub_cnt++; +#endif + this->value_ ^= other.value_; + return (*this); +} + +// multiplication over GF(2^k) is carryless multiplication +gf32& gf32::operator*=(const gf32 &other) +{ +#ifdef PROFILE_OP_COUNTS + this->mul_cnt++; +#endif + /* Does not require *this and other to be different, and therefore + also works for squaring, implemented below. */ + + /* Slow, but straight-forward */ + uint32_t result = 0; + uint32_t shifted = this->value_; + + for (uint32_t i = 0; i < 32; ++i) + { + if (other.value_ & (1ull << i)) + { + result ^= shifted; + } + if (shifted & (1ul << 31)) + { + shifted <<= 1; + shifted ^= this->modulus_; + } + else + { + shifted <<= 1; + } + } + + this->value_ = result; + + return (*this); +} + +gf32& gf32::operator^=(const unsigned long pow) +{ + (*this) = *this ^ pow; + return (*this); +} + +template +gf32& gf32::operator^=(const bigint &pow) +{ + (*this) = *this ^ pow; + return (*this); +} + +gf32& gf32::square() +{ +#ifdef PROFILE_OP_COUNTS + this->sqr_cnt++; + this->mul_cnt--; +#endif + this->operator*=(*this); + return *this; +} + +gf32& gf32::invert() +{ + (*this) = inverse(); + return (*this); +} + +gf32 gf32::operator+(const gf32 &other) const +{ + gf32 result(*this); + return (result+=(other)); +} + +gf32 gf32::operator-(const gf32 &other) const +{ + gf32 result(*this); + return (result-=(other)); +} + +gf32 gf32::operator-() const +{ + /* additive inverse matches the element itself */ + return gf32(*this); +} + +gf32 gf32::operator*(const gf32 &other) const +{ + gf32 result(*this); + return (result*=(other)); +} + +gf32 gf32::operator^(const unsigned long pow) const +{ + return power(*this, pow); +} + +template +gf32 gf32::operator^(const bigint &pow) const +{ + return power(*this, pow); +} + +gf32 gf32::squared() const +{ + gf32 result(*this); + result.square(); + return result; +} + +// repeatedly square pt, num_times. For use in inverse. +void square_multi(gf32* pt, int8_t num_times) +{ + for (int8_t i = 0; i < num_times; i++) + { + (*pt).square(); + } +} + +/* calculate el^{-1} as el^{2^{32}-2}. */ +gf32 gf32::inverse() const +{ +#ifdef PROFILE_OP_COUNTS + this->inv_cnt++; + this->mul_cnt -= 9; + this->sqr_cnt -= 31; +#endif + assert(!this->is_zero()); + gf32 a(*this); + + gf32 result(0); + for (size_t i = 0; i <= 4; ++i) + { + /* entering the loop a = el^{2^{2^i}-1} */ + gf32 b = a; + for (size_t j = 0; j < (1ul<("2147483648"); // 2^31 +} + +void gf32::randomize() +{ + randombytes_buf(&this->value_, 32/8); +} + +void gf32::clear() +{ + this->value_ = 0; +} + +bool gf32::operator==(const gf32 &other) const +{ + return (this->value_ == other.value_); +} + +bool gf32::operator!=(const gf32 &other) const +{ + return !(this->operator==(other)); +} + +void gf32::print() const +{ + printf("%u\n", this->value_); +} + +bool gf32::is_zero() const +{ + return (this->value_ == 0); +} + +gf32 gf32::zero() +{ + return gf32(0); +} + +gf32 gf32::one() +{ + return gf32(1); +} + +gf32 gf32::random_element() +{ + gf32 result; + result.randomize(); + return result; +} + +std::ostream& operator<<(std::ostream &out, const gf32 &el) +{ + out << el.value_; + return out; +} + +std::istream& operator>>(std::istream &in, gf32 &el) +{ + in >> el.value_; + return in; +} + +} // namespace libff diff --git a/libff/algebra/fields/binary/gf64.hpp b/libff/algebra/fields/binary/gf64.hpp new file mode 100644 index 00000000..c2398d19 --- /dev/null +++ b/libff/algebra/fields/binary/gf64.hpp @@ -0,0 +1,99 @@ +/**@file + ***************************************************************************** + Declaration of GF(2^64) finite field. + ***************************************************************************** + * @author This file is part of libff (see AUTHORS), migrated from libiop + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ +#ifndef LIBFF_ALGEBRA_GF64_HPP_ +#define LIBFF_ALGEBRA_GF64_HPP_ + +#include +#include +#include +#include + +namespace libff { + +/* gf64 implements the field GF(2)/[x^64 + x^4 + x^3 + x + 1]. + Elements are represented internally with a single uint64 */ +class gf64 { +public: +#ifdef PROFILE_OP_COUNTS // NOTE: op counts are affected when you exponentiate with ^ + static long long add_cnt; + static long long sub_cnt; + static long long mul_cnt; + static long long sqr_cnt; + static long long inv_cnt; +#endif + // x^64 + x^4 + x^3 + x + 1. The assembly code assumes that no term other + // than x^64 is greater than x^31, to enable faster multiplication. + static const constexpr uint64_t modulus_ = 0b11011; + static const constexpr uint64_t num_bits = 64; + + explicit gf64(); + explicit gf64(const uint64_t value); + std::vector as_words() const; + + gf64& operator+=(const gf64 &other); + gf64& operator-=(const gf64 &other); + gf64& operator*=(const gf64 &other); + gf64& operator^=(const unsigned long pow); + template + gf64& operator^=(const bigint &pow); + + gf64& square(); + gf64& invert(); + + gf64 operator+(const gf64 &other) const; + gf64 operator-(const gf64 &other) const; + gf64 operator-() const; + gf64 operator*(const gf64 &other) const; + gf64 operator^(const unsigned long pow) const; + template + gf64 operator^(const bigint &pow) const; + + gf64 squared() const; + gf64 inverse() const; + /** HAS TO BE A SQUARE (else does not terminate). */ + gf64 sqrt() const; + + void randomize(); + void clear(); + + bool operator==(const gf64 &other) const; + bool operator!=(const gf64 &other) const; + + bool is_zero() const; + + void print() const; + + static gf64 random_element(); + + static gf64 zero(); + static gf64 one(); + static gf64 multiplicative_generator; // generator of gf64^* + + static std::size_t size_in_bits() { return num_bits; } + static constexpr std::size_t extension_degree() { return 64; } + template + static constexpr bigint field_char() { return bigint(2); } + + friend std::ostream& operator<<(std::ostream &out, const gf64 &p); + friend std::istream& operator>>(std::istream &in, gf64 &p); +private: + uint64_t value_; +}; + +#ifdef PROFILE_OP_COUNTS +long long gf64::add_cnt = 0; +long long gf64::sub_cnt = 0; +long long gf64::mul_cnt = 0; +long long gf64::sqr_cnt = 0; +long long gf64::inv_cnt = 0; +#endif + +} // namespace libff +#include + +#endif // LIBFF_ALGEBRA_GF64_HPP_ diff --git a/libff/algebra/fields/binary/gf64.tcc b/libff/algebra/fields/binary/gf64.tcc new file mode 100644 index 00000000..ae801692 --- /dev/null +++ b/libff/algebra/fields/binary/gf64.tcc @@ -0,0 +1,312 @@ +#include + +#define __STDC_FORMAT_MACROS +#include + +#include + +#include "libff/algebra/fields/binary/gf64.hpp" +#include "libff/algebra/field_utils/algorithms.hpp" + +#ifdef USE_ASM +#include +#include +#include +#endif + +namespace libff { + +using std::size_t; + +const uint64_t gf64::modulus_; +gf64 gf64::multiplicative_generator = gf64(2); + +gf64::gf64() : value_(0) +{ +} + +gf64::gf64(const uint64_t value) : value_(value) +{ +} + +std::vector gf64::as_words() const +{ + return std::vector({this->value_}); +} + +gf64& gf64::operator+=(const gf64 &other) +{ +#ifdef PROFILE_OP_COUNTS + this->add_cnt++; +#endif + this->value_ ^= other.value_; + return (*this); +} + +gf64& gf64::operator-=(const gf64 &other) +{ +#ifdef PROFILE_OP_COUNTS + this->sub_cnt++; +#endif + this->value_ ^= other.value_; + return (*this); +} + +// multiplication over GF(2^k) is carryless multiplication +gf64& gf64::operator*=(const gf64 &other) +{ +#ifdef PROFILE_OP_COUNTS + this->mul_cnt++; +#endif + /* Does not require *this and other to be different, and therefore + also works for squaring, implemented below. */ +#ifdef USE_ASM + const __m128i modulus = _mm_loadl_epi64((const __m128i*)&(this->modulus_)); + const __m128i mul128 = _mm_clmulepi64_si128(_mm_loadl_epi64((const __m128i*)&(this->value_)), + _mm_loadl_epi64((const __m128i*)&(other.value_)), 0); + + /* reduce the 64 higher order bits of mul128. Output is 96 bits since modulus < 2^64 */ + const __m128i mul96 = _mm_clmulepi64_si128(modulus, mul128, 0x10); /* use high half of mul128 */ + __m128i rem = _mm_xor_si128(mul128, mul96); + + /* reduce the 32 higher order bits of mul96 */ + const __m128i mul64 = _mm_clmulepi64_si128(modulus, mul96, 0x10); /* use high half of mul96 */ + + rem = _mm_xor_si128(rem, mul64); + this->value_ = (uint64_t)_mm_movepi64_pi64(rem); + + return (*this); +#else + /* Slow, but straight-forward */ + uint64_t result = 0; + uint64_t shifted = this->value_; + + for (uint64_t i = 0; i < 64; ++i) + { + if (other.value_ & (1ull << i)) + { + result ^= shifted; + } + if (shifted & (1ul << 63)) + { + shifted <<= 1; + shifted ^= this->modulus_; + } + else + { + shifted <<= 1; + } + } + + this->value_ = result; + + return (*this); +#endif +} + +gf64& gf64::operator^=(const unsigned long pow) +{ + (*this) = *this ^ pow; + return (*this); +} + +template +gf64& gf64::operator^=(const bigint &pow) +{ + (*this) = *this ^ pow; + return (*this); +} + +gf64& gf64::square() +{ +#ifdef PROFILE_OP_COUNTS + this->sqr_cnt++; + this->mul_cnt--; +#endif + this->operator*=(*this); + return *this; +} + +gf64& gf64::invert() +{ + (*this) = inverse(); + return (*this); +} + +gf64 gf64::operator+(const gf64 &other) const +{ + gf64 result(*this); + return (result+=(other)); +} + +gf64 gf64::operator-(const gf64 &other) const +{ + gf64 result(*this); + return (result-=(other)); +} + +gf64 gf64::operator-() const +{ + /* additive inverse matches the element itself */ + return gf64(*this); +} + +gf64 gf64::operator*(const gf64 &other) const +{ + gf64 result(*this); + return (result*=(other)); +} + +gf64 gf64::operator^(const unsigned long pow) const +{ + return power(*this, pow); +} + +template +gf64 gf64::operator^(const bigint &pow) const +{ + return power(*this, pow); +} + +gf64 gf64::squared() const +{ + gf64 result(*this); + result.square(); + return result; +} + +// repeatedly square pt, num_times. For use in inverse. +void square_multi(gf64* pt, int8_t num_times) +{ + for (int8_t i = 0; i < num_times; i++) + { + (*pt).square(); + } +} + +/* calculate el^{-1} as el^{2^{64}-2}. the addition chain below + requires 74 mul/sqr operations total. It was found using the + Bergeron-Berstel-Brlek-Duboc method implemented in + https://github.com/kwantam/addchain. */ +gf64 gf64::inverse() const +{ +#ifdef PROFILE_OP_COUNTS + this->inv_cnt++; + this->mul_cnt -= 15; + this->sqr_cnt -= 58; +#endif + assert(!this->is_zero()); + // comments on the right side are of the form operation_number : exponent at the set variable + gf64 t0 = *this; // 1 : 1 + gf64 t1 = t0 * t0; // 2 : 2 + gf64 t2 = t1 * t0; // 3 : 3 + t0 = t2 * t2; // 4 : 6 + t0.square(); // 5 : 12 + t1 *= t0; // 6 : 14 + t2 *= t0; // 7 : 15 + t0 = t2 * t2; // 8 : 30 + t0.square(); // 9 : 60 + t0.square(); // 10 : 120 + t0.square(); // 11 : 240 + t1 *= t0; // 12 : 254 + t2 *= t0; // 13 : 255 + t0 = t2 * t2; // 14 : 510 + t0.square(); // 15 : 1020 + t0.square(); // 16 : 2040 + t0.square(); // 17 : 4080 + t0.square(); // 18 : 8160 + t0.square(); // 19 : 16320 + t0.square(); // 20 : 32640 + t0.square(); // 21 : 65280 + t1 *= t0; // 22 : 65534 + t2 *= t0; // 23 : 65535 + t0 = t2 * t2; // 24 : 131070 + t0.square(); // 25 : 262140 + t0.square(); // 26 : 524280 + t0.square(); // 27 : 1048560 + t0.square(); // 28 : 2097120 + t0.square(); // 29 : 4194240 + t0.square(); // 30 : 8388480 + t0.square(); // 31 : 16776960 + t0.square(); // 32 : 33553920 + t0.square(); // 33 : 67107840 + t0.square(); // 34 : 134215680 + t0.square(); // 35 : 268431360 + t0.square(); // 36 : 536862720 + t0.square(); // 37 : 1073725440 + t0.square(); // 38 : 2147450880 + t0.square(); // 39 : 4294901760 + t1 *= t0; // 40 : 4294967294 + t0 *= t2; // 41 : 4294967295 + for (int i = 0; i < 32; i++) { + t0.square(); // 42-73: 8589934590 - 18446744069414584320 + } + t0 *= t1; // 74 : 18446744073709551614 + return t0; +} + +gf64 gf64::sqrt() const +{ + return (*this)^bigint<1>("9223372036854775808"); // 2^63 +} + +void gf64::randomize() +{ + randombytes_buf(&this->value_, 64/8); +} + +void gf64::clear() +{ + this->value_ = 0; +} + +bool gf64::operator==(const gf64 &other) const +{ + return (this->value_ == other.value_); +} + +bool gf64::operator!=(const gf64 &other) const +{ + return !(this->operator==(other)); +} + +void gf64::print() const +{ + printf("%016" PRIx64 "\n", this->value_); +} + +bool gf64::is_zero() const +{ + return (this->value_ == 0); +} + +gf64 gf64::zero() +{ + return gf64(0); +} + +gf64 gf64::one() +{ + return gf64(1); +} + +gf64 gf64::random_element() +{ + gf64 result; + result.randomize(); + return result; +} + +std::ostream& operator<<(std::ostream &out, const gf64 &el) +{ + out << el.value_; + return out; +} + +std::istream& operator>>(std::istream &in, gf64 &el) +{ + in >> el.value_; + return in; +} + +} // namespace libff diff --git a/libff/algebra/fields/binary_field.hpp b/libff/algebra/fields/binary_field.hpp new file mode 100644 index 00000000..a7faa7ad --- /dev/null +++ b/libff/algebra/fields/binary_field.hpp @@ -0,0 +1,101 @@ +/** @file + ***************************************************************************** + Declaration of common API for all finite fields in the binary/ directory. + + Currently NOT used by the fields in this library. This class is not actually + the parent class of any field. All APIs are enforced through tests instead. + + The reason for this is to ensure high performance of all fields. This class + exists as documentation for common API between fields. + + Includes fields F2^n for specified n. All of the binary entension fields must + implement all functions declared in this class. + ***************************************************************************** + * @author This file is part of libff, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ +#include +#include + +namespace libff { + +template +class BinaryField; + +/* The type parameter T is intended to be set to the child class + * when this class is extended. For example, + * class gf32 : public BinaryField ... + */ +template +class BinaryField { +public: + /* Functions unique to binary fields */ + + /** Returns the constituent bits in 64 bit words, in little-endian order. */ + std::vector as_words() const = 0; + + static const constexpr uint64_t modulus_; + static const constexpr uint64_t num_bits; + + /** generator of gf2^n */ + static T multiplicative_generator; + + /** If extension field, returns the base field's characteristic. */ + template + static constexpr bigint field_char() { return bigint(2); } + + /* Functions common to all finite fields */ +#ifdef PROFILE_OP_COUNTS // NOTE: op counts are affected when you exponentiate with ^ + static long long add_cnt; + static long long sub_cnt; + static long long mul_cnt; + static long long sqr_cnt; + static long long inv_cnt; +#endif + + virtual T& operator+=(const T& other) = 0; + virtual T& operator-=(const T& other) = 0; + virtual T& operator*=(const T& other) = 0; + virtual T& operator^=(const unsigned long pow) = 0; + template + virtual T& operator^=(const bigint &pow) = 0; + + virtual T& square() = 0; + virtual T& invert() = 0; + + virtual T operator+(const T& other) const; + virtual T operator-(const T& other) const; + virtual T operator*(const T& other) const; + virtual T operator^(const unsigned long pow) const; + template + virtual T operator^(const bigint &pow) const; + virtual T operator-() const = 0; + + virtual T squared() const; + virtual T inverse() const; + /** HAS TO BE A SQUARE (else does not terminate). */ + virtual T sqrt() const = 0; + + bool operator==(const T& other) const = 0; + bool operator!=(const T& other) const = 0; + bool is_zero() const = 0; + + void print() const = 0; + + void randomize() = 0; + void clear() = 0; + + // the following should be defined in child classes, but are static so they can't be inherited + static T zero(); + static T one(); + static T random_element(); + static constexpr std::size_t extension_degree(); + static std::size_t size_in_bits() { return num_bits; } + + // the following should be defined as well but can't be inherited + friend std::ostream& operator<<(std::ostream &out, const T &p); + friend std::istream& operator>>(std::istream &in, T &p); +}; + +} // libff diff --git a/libff/algebra/fields/field.hpp b/libff/algebra/fields/field.hpp new file mode 100644 index 00000000..65e43789 --- /dev/null +++ b/libff/algebra/fields/field.hpp @@ -0,0 +1,90 @@ +/** @file + ***************************************************************************** + Declaration of common API for all finite fields. + + Currently NOT used by the fields in this library. This class is not actually + the parent class of any field. All APIs are enforced through tests instead. + + The reason for this is to ensure high performance of all fields. This class + exists as documentation for common API between fields. + + Includes two types of fields, F[p^n] for selected n and F[2^n] for a separate + range of n. All of these finite fields must implement all functions declared + in this class. + ***************************************************************************** + * @author This file is part of libff, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ +#include +#include + +namespace libff { + +template +class Field; + +/* The type parameter T is intended to be set to the child class + * when this class is extended. For example, + * class Fp_model : public Field ... + */ +template +class Field { +public: +#ifdef PROFILE_OP_COUNTS // NOTE: op counts are affected when you exponentiate with ^ + static long long add_cnt; + static long long sub_cnt; + static long long mul_cnt; + static long long sqr_cnt; + static long long inv_cnt; +#endif + + virtual T& operator+=(const T& other) = 0; + virtual T& operator-=(const T& other) = 0; + virtual T& operator*=(const T& other) = 0; + virtual T& operator^=(const unsigned long pow) = 0; + template + virtual T& operator^=(const bigint &pow) = 0; + + virtual T& square() = 0; + virtual T& invert() = 0; + + virtual T operator+(const T& other) const; + virtual T operator-(const T& other) const; + virtual T operator*(const T& other) const; + virtual T operator-() const = 0; + + virtual T squared() const; + virtual T inverse() const; + /** HAS TO BE A SQUARE (else does not terminate). */ + virtual T sqrt() const = 0; + + virtual T operator^(const unsigned long pow) const; + template + virtual T operator^(const bigint &pow) const; + + bool operator==(const T& other) const = 0; + bool operator!=(const T& other) const = 0; + bool is_zero() const = 0; + + void print() const = 0; + + void randomize() = 0; + void clear() = 0; + + // the following should be defined in child classes, but are static so they can't be inherited + static T zero(); + static T one(); + static T random_element(); + /** Equals 1 for prime field Fp. */ + static constexpr std::size_t extension_degree(); + static std::size_t size_in_bits(); + + // the following should be defined as well but can't be inherited; + // make sure binary and prime never serialize to same thing + friend std::ostream& operator<<(std::ostream &out, const T &p); + friend std::istream& operator>>(std::istream &in, T &p); + +}; + +} // libff diff --git a/libff/algebra/fields/fp.hpp b/libff/algebra/fields/prime_base/fp.hpp similarity index 87% rename from libff/algebra/fields/fp.hpp rename to libff/algebra/fields/prime_base/fp.hpp index 01f88838..159993ab 100755 --- a/libff/algebra/fields/fp.hpp +++ b/libff/algebra/fields/prime_base/fp.hpp @@ -10,8 +10,8 @@ #ifndef FP_HPP_ #define FP_HPP_ -#include -#include +#include +#include namespace libff { @@ -35,7 +35,7 @@ std::istream& operator>>(std::istream &, Fp_model &); * But for the integer sizes of interest for libff (3 to 5 limbs of 64 bits each), * we implement performance-critical routines, like addition and multiplication, * using hand-optimzied assembly code. -*/ + */ template& modulus> class Fp_model { public: @@ -43,16 +43,16 @@ class Fp_model { public: static const mp_size_t num_limbs = n; static const constexpr bigint& mod = modulus; -#ifdef PROFILE_OP_COUNTS +#ifdef PROFILE_OP_COUNTS // NOTE: op counts are affected when you exponentiate with ^ static long long add_cnt; static long long sub_cnt; static long long mul_cnt; static long long sqr_cnt; static long long inv_cnt; #endif - static size_t num_bits; + static std::size_t num_bits; static bigint euler; // (modulus-1)/2 - static size_t s; // modulus = 2^s * t + 1 + static std::size_t s; // modulus = 2^s * t + 1 static bigint t; // with t odd static bigint t_minus_1_over_2; // (t-1)/2 static Fp_model nqr; // a quadratic nonresidue @@ -63,8 +63,6 @@ class Fp_model { static bigint Rsquared; // R^2, where R = W^k, where k = ?? static bigint Rcubed; // R^3 - static bool modulus_is_valid() { return modulus.data[n-1] != 0; } // mpn inverse assumes that highest limb is non-zero - Fp_model() {}; Fp_model(const bigint &b); Fp_model(const long x, const bool is_unsigned=false); @@ -74,6 +72,7 @@ class Fp_model { void mul_reduce(const bigint &other); void clear(); + void randomize(); /* Return the standard (not Montgomery) representation of the Field element's requivalence class. I.e. Fp(2).as_bigint() @@ -94,26 +93,32 @@ class Fp_model { Fp_model& operator-=(const Fp_model& other); Fp_model& operator*=(const Fp_model& other); Fp_model& operator^=(const unsigned long pow); - template Fp_model& operator^=(const bigint &pow); Fp_model operator+(const Fp_model& other) const; Fp_model operator-(const Fp_model& other) const; Fp_model operator*(const Fp_model& other) const; + Fp_model operator^(const unsigned long pow) const; + template + Fp_model operator^(const bigint &pow) const; Fp_model operator-() const; + + Fp_model& square(); Fp_model squared() const; Fp_model& invert(); Fp_model inverse() const; + Fp_model Frobenius_map(unsigned long power) const; Fp_model sqrt() const; // HAS TO BE A SQUARE (else does not terminate) - Fp_model operator^(const unsigned long pow) const; - template - Fp_model operator^(const bigint &pow) const; - - static size_t size_in_bits() { return num_bits; } - static size_t capacity() { return num_bits - 1; } - static bigint field_char() { return modulus; } + /** Initializes euler, s, t, t_minus_1_over_2, nqr, and nqr_to_t. + * Must be called before sqrt(). Alternatively, these constants can be set manually. */ + static void init_tonelli_shanks_constants(); + static std::size_t size_in_bits() { return num_bits; } + static std::size_t capacity() { return num_bits - 1; } + static constexpr std::size_t extension_degree() { return 1; } + static constexpr bigint field_char() { return modulus; } + static bool modulus_is_valid() { return modulus.data[n-1] != 0; } // mpn inverse assumes that highest limb is non-zero static Fp_model zero(); static Fp_model one(); @@ -179,6 +184,6 @@ template& modulus> bigint Fp_model::Rcubed; } // libff -#include +#include #endif // FP_HPP_ diff --git a/libff/algebra/fields/fp.tcc b/libff/algebra/fields/prime_base/fp.tcc similarity index 94% rename from libff/algebra/fields/fp.tcc rename to libff/algebra/fields/prime_base/fp.tcc index 2d919faa..624f6666 100755 --- a/libff/algebra/fields/fp.tcc +++ b/libff/algebra/fields/prime_base/fp.tcc @@ -14,11 +14,13 @@ #include #include -#include -#include +#include +#include namespace libff { +using std::size_t; + template& modulus> void Fp_model::mul_reduce(const bigint &other) { @@ -232,6 +234,12 @@ void Fp_model::clear() this->mont_repr.clear(); } +template& modulus> +void Fp_model::randomize() +{ + (*this) = Fp_model::random_element(); +} + template& modulus> bigint Fp_model::as_bigint() const { @@ -654,6 +662,13 @@ Fp_model Fp_model::squared() const } } +template& modulus> +Fp_model& Fp_model::square() +{ + (*this) = squared(); + return (*this); +} + template& modulus> Fp_model& Fp_model::invert() { @@ -715,6 +730,14 @@ Fp_model Fp_model::inverse() const return (r.invert()); } +template& modulus> +Fp_model Fp_model::Frobenius_map(unsigned long power) const +{ + UNUSED(power); // only for API consistency + Fp_model copy = *this; + return copy; +} + template& modulus> Fp_model Fp_model::random_element() /// returns random element of Fp_model { @@ -747,56 +770,13 @@ Fp_model Fp_model::random_element() /// returns random el template& modulus> Fp_model Fp_model::sqrt() const { - Fp_model one = Fp_model::one(); - - size_t v = Fp_model::s; - Fp_model z = Fp_model::nqr_to_t; - Fp_model w = (*this)^Fp_model::t_minus_1_over_2; - Fp_model x = (*this) * w; - Fp_model b = x * w; // b = (*this)^t - -#if DEBUG - // check if square with euler's criterion - Fp_model check = b; - for (size_t i = 0; i < v-1; ++i) - { - check = check.squared(); - } - if (check != one) - { - assert(0); - } -#endif - - // compute square root with Tonelli--Shanks - // (does not terminate if not a square!) - - while (b != one) - { - size_t m = 0; - Fp_model b2m = b; - while (b2m != one) - { - /* invariant: b2m = b^(2^m) after entering this loop */ - b2m = b2m.squared(); - m += 1; - } - - int j = v-m-1; - w = z; - while (j > 0) - { - w = w.squared(); - --j; - } // w = z^2^(v-m-1) - - z = w.squared(); - b = b * z; - x = x * w; - v = m; - } + return tonelli_shanks_sqrt(*this); +} - return x; +template& modulus> +void Fp_model::init_tonelli_shanks_constants() +{ + find_tonelli_shanks_constants, n>(); } template& modulus> diff --git a/libff/algebra/fields/fp12_2over3over2.hpp b/libff/algebra/fields/prime_extension/fp12_2over3over2.hpp similarity index 57% rename from libff/algebra/fields/fp12_2over3over2.hpp rename to libff/algebra/fields/prime_extension/fp12_2over3over2.hpp index 6c31291f..1849772d 100755 --- a/libff/algebra/fields/fp12_2over3over2.hpp +++ b/libff/algebra/fields/prime_extension/fp12_2over3over2.hpp @@ -11,9 +11,9 @@ #define FP12_2OVER3OVER2_HPP_ #include -#include -#include -#include +#include +#include +#include namespace libff { @@ -40,7 +40,20 @@ class Fp12_2over3over2_model { typedef Fp_model my_Fp; typedef Fp2_model my_Fp2; typedef Fp6_3over2_model my_Fp6; - +#ifdef PROFILE_OP_COUNTS // NOTE: op counts are affected when you exponentiate with ^ + static long long add_cnt; + static long long sub_cnt; + static long long mul_cnt; + static long long sqr_cnt; + static long long inv_cnt; +#endif + + static bigint<12*n> euler; // (modulus^12-1)/2 + static std::size_t s; // modulus^12 = 2^s * t + 1 + static bigint<12*n> t; // with t odd + static bigint<12*n> t_minus_1_over_2; // (t-1)/2 + static Fp12_2over3over2_model nqr; // a quadratic nonresidue in Fp12 + static Fp12_2over3over2_model nqr_to_t; // nqr^t static Fp2_model non_residue; static Fp2_model Frobenius_coeffs_c1[12]; // non_residue^((modulus^i-1)/6) for i=0,...,11 @@ -50,26 +63,39 @@ class Fp12_2over3over2_model { void clear() { c0.clear(); c1.clear(); } void print() const { printf("c0/c1:\n"); c0.print(); c1.print(); } - - static Fp12_2over3over2_model zero(); - static Fp12_2over3over2_model one(); - static Fp12_2over3over2_model random_element(); + void randomize(); bool is_zero() const { return c0.is_zero() && c1.is_zero(); } bool operator==(const Fp12_2over3over2_model &other) const; bool operator!=(const Fp12_2over3over2_model &other) const; + Fp12_2over3over2_model& operator+=(const Fp12_2over3over2_model& other); + Fp12_2over3over2_model& operator-=(const Fp12_2over3over2_model& other); + Fp12_2over3over2_model& operator*=(const Fp12_2over3over2_model& other); + Fp12_2over3over2_model& operator^=(const unsigned long pow); + template + Fp12_2over3over2_model& operator^=(const bigint &pow); + Fp12_2over3over2_model operator+(const Fp12_2over3over2_model &other) const; Fp12_2over3over2_model operator-(const Fp12_2over3over2_model &other) const; Fp12_2over3over2_model operator*(const Fp12_2over3over2_model &other) const; + Fp12_2over3over2_model operator^(const unsigned long pow) const; + template + Fp12_2over3over2_model operator^(const bigint &exponent) const; + template& exp_modulus> + Fp12_2over3over2_model operator^(const Fp_model &exponent) const; Fp12_2over3over2_model operator-() const; + + Fp12_2over3over2_model& square(); Fp12_2over3over2_model squared() const; // default is squared_complex Fp12_2over3over2_model squared_karatsuba() const; Fp12_2over3over2_model squared_complex() const; + Fp12_2over3over2_model& invert(); Fp12_2over3over2_model inverse() const; Fp12_2over3over2_model Frobenius_map(unsigned long power) const; Fp12_2over3over2_model unitary_inverse() const; Fp12_2over3over2_model cyclotomic_squared() const; + Fp12_2over3over2_model sqrt() const; // HAS TO BE A SQUARE (else does not terminate) Fp12_2over3over2_model mul_by_024(const my_Fp2 &ell_0, const my_Fp2 &ell_VW, const my_Fp2 &ell_VV) const; @@ -78,13 +104,38 @@ class Fp12_2over3over2_model { template Fp12_2over3over2_model cyclotomic_exp(const bigint &exponent) const; - static bigint base_field_char() { return modulus; } - static size_t extension_degree() { return 12; } + /** Initializes euler, s, t, t_minus_1_over_2, nqr, and nqr_to_t. + * Must be called before sqrt(). Alternatively, these constants can be set manually. */ + static void init_tonelli_shanks_constants(); + static std::size_t size_in_bits() { return 2*my_Fp6::size_in_bits(); } + static constexpr std::size_t extension_degree() { return 12; } + static constexpr bigint field_char() { return modulus; } + + static Fp12_2over3over2_model zero(); + static Fp12_2over3over2_model one(); + static Fp12_2over3over2_model random_element(); friend std::ostream& operator<< (std::ostream &out, const Fp12_2over3over2_model &el); friend std::istream& operator>> (std::istream &in, Fp12_2over3over2_model &el); }; +#ifdef PROFILE_OP_COUNTS +template& modulus> +long long Fp12_2over3over2_model::add_cnt = 0; + +template& modulus> +long long Fp12_2over3over2_model::sub_cnt = 0; + +template& modulus> +long long Fp12_2over3over2_model::mul_cnt = 0; + +template& modulus> +long long Fp12_2over3over2_model::sqr_cnt = 0; + +template& modulus> +long long Fp12_2over3over2_model::inv_cnt = 0; +#endif + template& modulus> std::ostream& operator<<(std::ostream& out, const std::vector > &v); @@ -100,11 +151,23 @@ Fp12_2over3over2_model operator*(const Fp2_model &lhs, c template& modulus> Fp12_2over3over2_model operator*(const Fp6_3over2_model &lhs, const Fp12_2over3over2_model &rhs); -template& modulus, mp_size_t m> -Fp12_2over3over2_model operator^(const Fp12_2over3over2_model &self, const bigint &exponent); +template& modulus> +bigint<12*n> Fp12_2over3over2_model::euler; + +template& modulus> +size_t Fp12_2over3over2_model::s; + +template& modulus> +bigint<12*n> Fp12_2over3over2_model::t; + +template& modulus> +bigint<12*n> Fp12_2over3over2_model::t_minus_1_over_2; + +template& modulus> +Fp12_2over3over2_model Fp12_2over3over2_model::nqr; -template& modulus, mp_size_t m, const bigint& exp_modulus> -Fp12_2over3over2_model operator^(const Fp12_2over3over2_model &self, const Fp_model &exponent); +template& modulus> +Fp12_2over3over2_model Fp12_2over3over2_model::nqr_to_t; template& modulus> Fp2_model Fp12_2over3over2_model::non_residue; @@ -113,5 +176,5 @@ template& modulus> Fp2_model Fp12_2over3over2_model::Frobenius_coeffs_c1[12]; } // libff -#include +#include #endif // FP12_2OVER3OVER2_HPP_ diff --git a/libff/algebra/fields/fp12_2over3over2.tcc b/libff/algebra/fields/prime_extension/fp12_2over3over2.tcc similarity index 79% rename from libff/algebra/fields/fp12_2over3over2.tcc rename to libff/algebra/fields/prime_extension/fp12_2over3over2.tcc index 6220c4f5..63579d60 100755 --- a/libff/algebra/fields/fp12_2over3over2.tcc +++ b/libff/algebra/fields/prime_extension/fp12_2over3over2.tcc @@ -12,6 +12,8 @@ namespace libff { +using std::size_t; + template& modulus> Fp6_3over2_model Fp12_2over3over2_model::mul_by_non_residue(const Fp6_3over2_model &elt) { @@ -40,6 +42,12 @@ Fp12_2over3over2_model Fp12_2over3over2_model::random_elem return r; } +template& modulus> +void Fp12_2over3over2_model::randomize() +{ + (*this) = Fp12_2over3over2_model::random_element(); +} + template& modulus> bool Fp12_2over3over2_model::operator==(const Fp12_2over3over2_model &other) const { @@ -55,6 +63,9 @@ bool Fp12_2over3over2_model::operator!=(const Fp12_2over3over2_model< template& modulus> Fp12_2over3over2_model Fp12_2over3over2_model::operator+(const Fp12_2over3over2_model &other) const { +#ifdef PROFILE_OP_COUNTS + this->add_cnt++; +#endif return Fp12_2over3over2_model(this->c0 + other.c0, this->c1 + other.c1); } @@ -62,6 +73,9 @@ Fp12_2over3over2_model Fp12_2over3over2_model::operator+(c template& modulus> Fp12_2over3over2_model Fp12_2over3over2_model::operator-(const Fp12_2over3over2_model &other) const { +#ifdef PROFILE_OP_COUNTS + this->sub_cnt++; +#endif return Fp12_2over3over2_model(this->c0 - other.c0, this->c1 - other.c1); } @@ -69,6 +83,9 @@ Fp12_2over3over2_model Fp12_2over3over2_model::operator-(c template& modulus> Fp12_2over3over2_model operator*(const Fp_model &lhs, const Fp12_2over3over2_model &rhs) { +#ifdef PROFILE_OP_COUNTS + rhs.mul_cnt++; +#endif return Fp12_2over3over2_model(lhs*rhs.c0, lhs*rhs.c1); } @@ -76,6 +93,9 @@ Fp12_2over3over2_model operator*(const Fp_model &lhs, co template& modulus> Fp12_2over3over2_model operator*(const Fp2_model &lhs, const Fp12_2over3over2_model &rhs) { +#ifdef PROFILE_OP_COUNTS + rhs.mul_cnt++; +#endif return Fp12_2over3over2_model(lhs*rhs.c0, lhs*rhs.c1); } @@ -83,6 +103,9 @@ Fp12_2over3over2_model operator*(const Fp2_model &lhs, c template& modulus> Fp12_2over3over2_model operator*(const Fp6_3over2_model &lhs, const Fp12_2over3over2_model &rhs) { +#ifdef PROFILE_OP_COUNTS + rhs.mul_cnt++; +#endif return Fp12_2over3over2_model(lhs*rhs.c0, lhs*rhs.c1); } @@ -90,6 +113,9 @@ Fp12_2over3over2_model operator*(const Fp6_3over2_model template& modulus> Fp12_2over3over2_model Fp12_2over3over2_model::operator*(const Fp12_2over3over2_model &other) const { +#ifdef PROFILE_OP_COUNTS + this->mul_cnt++; +#endif /* Devegili OhEig Scott Dahab --- Multiplication and Squaring on Pairing-Friendly Fields.pdf; Section 3 (Karatsuba) */ const my_Fp6 &A = other.c0, &B = other.c1, @@ -108,15 +134,81 @@ Fp12_2over3over2_model Fp12_2over3over2_model::operator-() -this->c1); } +template& modulus> +Fp12_2over3over2_model Fp12_2over3over2_model::operator^(const unsigned long pow) const +{ + return power >(*this, pow); +} + +template& modulus> +template +Fp12_2over3over2_model Fp12_2over3over2_model::operator^(const bigint &exponent) const +{ + return power >(*this, exponent); +} + +template& modulus> +template& exp_modulus> +Fp12_2over3over2_model Fp12_2over3over2_model::operator^(const Fp_model &exponent) const +{ + return (*this)^(exponent.as_bigint()); +} + +template& modulus> +Fp12_2over3over2_model& Fp12_2over3over2_model::operator+=(const Fp12_2over3over2_model& other) +{ + (*this) = *this + other; + return (*this); +} + +template& modulus> +Fp12_2over3over2_model& Fp12_2over3over2_model::operator-=(const Fp12_2over3over2_model& other) +{ + (*this) = *this - other; + return (*this); +} + +template& modulus> +Fp12_2over3over2_model& Fp12_2over3over2_model::operator*=(const Fp12_2over3over2_model& other) +{ + (*this) = *this * other; + return (*this); +} + +template& modulus> +Fp12_2over3over2_model& Fp12_2over3over2_model::operator^=(const unsigned long pow) +{ + (*this) = *this ^ pow; + return (*this); +} + +template& modulus> +template +Fp12_2over3over2_model& Fp12_2over3over2_model::operator^=(const bigint &pow) +{ + (*this) = *this ^ pow; + return (*this); +} + template& modulus> Fp12_2over3over2_model Fp12_2over3over2_model::squared() const { return squared_complex(); } +template& modulus> +Fp12_2over3over2_model& Fp12_2over3over2_model::square() +{ + (*this) = squared(); + return (*this); +} + template& modulus> Fp12_2over3over2_model Fp12_2over3over2_model::squared_karatsuba() const { +#ifdef PROFILE_OP_COUNTS + this->sqr_cnt++; +#endif /* Devegili OhEig Scott Dahab --- Multiplication and Squaring on Pairing-Friendly Fields.pdf; Section 3 (Karatsuba squaring) */ const my_Fp6 &a = this->c0, &b = this->c1; @@ -130,6 +222,9 @@ Fp12_2over3over2_model Fp12_2over3over2_model::squared_kar template& modulus> Fp12_2over3over2_model Fp12_2over3over2_model::squared_complex() const { +#ifdef PROFILE_OP_COUNTS + this->sqr_cnt++; +#endif /* Devegili OhEig Scott Dahab --- Multiplication and Squaring on Pairing-Friendly Fields.pdf; Section 3 (Complex squaring) */ const my_Fp6 &a = this->c0, &b = this->c1; @@ -142,6 +237,9 @@ Fp12_2over3over2_model Fp12_2over3over2_model::squared_com template& modulus> Fp12_2over3over2_model Fp12_2over3over2_model::inverse() const { +#ifdef PROFILE_OP_COUNTS + this->inv_cnt++; +#endif /* From "High-Speed Software Implementation of the Optimal Ate Pairing over Barreto-Naehrig Curves"; Algorithm 8 */ const my_Fp6 &a = this->c0, &b = this->c1; @@ -155,6 +253,13 @@ Fp12_2over3over2_model Fp12_2over3over2_model::inverse() c return Fp12_2over3over2_model(c0, c1); } +template& modulus> +Fp12_2over3over2_model& Fp12_2over3over2_model::invert() +{ + (*this) = inverse(); + return (*this); +} + template& modulus> Fp12_2over3over2_model Fp12_2over3over2_model::Frobenius_map(unsigned long power) const { @@ -319,19 +424,6 @@ Fp12_2over3over2_model Fp12_2over3over2_model::mul_by_024( } -template& modulus, mp_size_t m> -Fp12_2over3over2_model operator^(const Fp12_2over3over2_model &self, const bigint &exponent) -{ - return power >(self, exponent); -} - -template& modulus, mp_size_t m, const bigint& exp_modulus> -Fp12_2over3over2_model operator^(const Fp12_2over3over2_model &self, const Fp_model &exponent) -{ - return self^(exponent.as_bigint()); -} - - template& modulus> template Fp12_2over3over2_model Fp12_2over3over2_model::cyclotomic_exp(const bigint &exponent) const @@ -359,6 +451,18 @@ Fp12_2over3over2_model Fp12_2over3over2_model::cyclotomic return res; } +template& modulus> +Fp12_2over3over2_model Fp12_2over3over2_model::sqrt() const +{ + return tonelli_shanks_sqrt(*this); +} + +template& modulus> +void Fp12_2over3over2_model::init_tonelli_shanks_constants() +{ + find_tonelli_shanks_constants, n>(); +} + template& modulus> std::ostream& operator<<(std::ostream &out, const Fp12_2over3over2_model &el) { diff --git a/libff/algebra/fields/fp2.hpp b/libff/algebra/fields/prime_extension/fp2.hpp similarity index 70% rename from libff/algebra/fields/fp2.hpp rename to libff/algebra/fields/prime_extension/fp2.hpp index a0ffd1de..27d64dac 100755 --- a/libff/algebra/fields/fp2.hpp +++ b/libff/algebra/fields/prime_extension/fp2.hpp @@ -11,7 +11,7 @@ #define FP2_HPP_ #include -#include +#include namespace libff { @@ -36,9 +36,16 @@ template& modulus> class Fp2_model { public: typedef Fp_model my_Fp; +#ifdef PROFILE_OP_COUNTS // NOTE: op counts are affected when you exponentiate with ^ + static long long add_cnt; + static long long sub_cnt; + static long long mul_cnt; + static long long sqr_cnt; + static long long inv_cnt; +#endif static bigint<2*n> euler; // (modulus^2-1)/2 - static size_t s; // modulus^2 = 2^s * t + 1 + static std::size_t s; // modulus^2 = 2^s * t + 1 static bigint<2*n> t; // with t odd static bigint<2*n> t_minus_1_over_2; // (t-1)/2 static my_Fp non_residue; // X^4-non_residue irreducible over Fp; used for constructing Fp2 = Fp[X] / (X^2 - non_residue) @@ -52,36 +59,68 @@ class Fp2_model { void clear() { c0.clear(); c1.clear(); } void print() const { printf("c0/c1:\n"); c0.print(); c1.print(); } - - static Fp2_model zero(); - static Fp2_model one(); - static Fp2_model random_element(); + void randomize(); bool is_zero() const { return c0.is_zero() && c1.is_zero(); } bool operator==(const Fp2_model &other) const; bool operator!=(const Fp2_model &other) const; + Fp2_model& operator+=(const Fp2_model& other); + Fp2_model& operator-=(const Fp2_model& other); + Fp2_model& operator*=(const Fp2_model& other); + Fp2_model& operator^=(const unsigned long pow); + template + Fp2_model& operator^=(const bigint &pow); + Fp2_model operator+(const Fp2_model &other) const; Fp2_model operator-(const Fp2_model &other) const; Fp2_model operator*(const Fp2_model &other) const; + Fp2_model operator^(const unsigned long pow) const; + template + Fp2_model operator^(const bigint &other) const; Fp2_model operator-() const; + + Fp2_model& square(); // default is squared_complex Fp2_model squared() const; // default is squared_complex + Fp2_model& invert(); Fp2_model inverse() const; Fp2_model Frobenius_map(unsigned long power) const; Fp2_model sqrt() const; // HAS TO BE A SQUARE (else does not terminate) Fp2_model squared_karatsuba() const; Fp2_model squared_complex() const; - template - Fp2_model operator^(const bigint &other) const; + /** Initializes euler, s, t, t_minus_1_over_2, nqr, and nqr_to_t. + * Must be called before sqrt(). Alternatively, these constants can be set manually. */ + static void init_tonelli_shanks_constants(); + static std::size_t size_in_bits() { return 2*my_Fp::size_in_bits(); } + static constexpr std::size_t extension_degree() { return 2; } + static constexpr bigint field_char() { return modulus; } - static size_t size_in_bits() { return 2*my_Fp::size_in_bits(); } - static bigint base_field_char() { return modulus; } + static Fp2_model zero(); + static Fp2_model one(); + static Fp2_model random_element(); friend std::ostream& operator<< (std::ostream &out, const Fp2_model &el); friend std::istream& operator>> (std::istream &in, Fp2_model &el); }; +#ifdef PROFILE_OP_COUNTS +template& modulus> +long long Fp2_model::add_cnt = 0; + +template& modulus> +long long Fp2_model::sub_cnt = 0; + +template& modulus> +long long Fp2_model::mul_cnt = 0; + +template& modulus> +long long Fp2_model::sqr_cnt = 0; + +template& modulus> +long long Fp2_model::inv_cnt = 0; +#endif + template& modulus> std::ostream& operator<<(std::ostream& out, const std::vector > &v); @@ -116,6 +155,6 @@ template& modulus> Fp_model Fp2_model::Frobenius_coeffs_c1[2]; } // libff -#include +#include #endif // FP2_HPP_ diff --git a/libff/algebra/fields/fp2.tcc b/libff/algebra/fields/prime_extension/fp2.tcc similarity index 73% rename from libff/algebra/fields/fp2.tcc rename to libff/algebra/fields/prime_extension/fp2.tcc index bc5cca79..15aaf2fd 100755 --- a/libff/algebra/fields/fp2.tcc +++ b/libff/algebra/fields/prime_extension/fp2.tcc @@ -10,10 +10,12 @@ #ifndef FP2_TCC_ #define FP2_TCC_ -#include +#include namespace libff { +using std::size_t; + template& modulus> Fp2_model Fp2_model::zero() { @@ -36,6 +38,12 @@ Fp2_model Fp2_model::random_element() return r; } +template& modulus> +void Fp2_model::randomize() +{ + (*this) = Fp2_model::random_element(); +} + template& modulus> bool Fp2_model::operator==(const Fp2_model &other) const { @@ -51,6 +59,9 @@ bool Fp2_model::operator!=(const Fp2_model &other) const template& modulus> Fp2_model Fp2_model::operator+(const Fp2_model &other) const { +#ifdef PROFILE_OP_COUNTS + this->add_cnt++; +#endif return Fp2_model(this->c0 + other.c0, this->c1 + other.c1); } @@ -58,6 +69,9 @@ Fp2_model Fp2_model::operator+(const Fp2_model template& modulus> Fp2_model Fp2_model::operator-(const Fp2_model &other) const { +#ifdef PROFILE_OP_COUNTS + this->sub_cnt++; +#endif return Fp2_model(this->c0 - other.c0, this->c1 - other.c1); } @@ -65,6 +79,9 @@ Fp2_model Fp2_model::operator-(const Fp2_model template& modulus> Fp2_model operator*(const Fp_model &lhs, const Fp2_model &rhs) { +#ifdef PROFILE_OP_COUNTS + rhs.mul_cnt++; +#endif return Fp2_model(lhs*rhs.c0, lhs*rhs.c1); } @@ -72,6 +89,9 @@ Fp2_model operator*(const Fp_model &lhs, const Fp2_model template& modulus> Fp2_model Fp2_model::operator*(const Fp2_model &other) const { +#ifdef PROFILE_OP_COUNTS + this->mul_cnt++; +#endif /* Devegili OhEig Scott Dahab --- Multiplication and Squaring on Pairing-Friendly Fields.pdf; Section 3 (Karatsuba) */ const my_Fp &A = other.c0, &B = other.c1, @@ -90,15 +110,75 @@ Fp2_model Fp2_model::operator-() const -this->c1); } +template& modulus> +Fp2_model Fp2_model::operator^(const unsigned long pow) const +{ + return power>(*this, pow); +} + +template& modulus> +template +Fp2_model Fp2_model::operator^(const bigint &pow) const +{ + return power, m>(*this, pow); +} + +template& modulus> +Fp2_model& Fp2_model::operator+=(const Fp2_model& other) +{ + (*this) = *this + other; + return (*this); +} + +template& modulus> +Fp2_model& Fp2_model::operator-=(const Fp2_model& other) +{ + (*this) = *this - other; + return (*this); +} + +template& modulus> +Fp2_model& Fp2_model::operator*=(const Fp2_model& other) +{ + (*this) = *this * other; + return (*this); +} + +template& modulus> +Fp2_model& Fp2_model::operator^=(const unsigned long pow) +{ + (*this) = *this ^ pow; + return (*this); +} + +template& modulus> +template +Fp2_model& Fp2_model::operator^=(const bigint &pow) +{ + (*this) = *this ^ pow; + return (*this); +} + template& modulus> Fp2_model Fp2_model::squared() const { return squared_complex(); } +template& modulus> +Fp2_model& Fp2_model::square() +{ + (*this) = squared(); + return (*this); +} + + template& modulus> Fp2_model Fp2_model::squared_karatsuba() const { +#ifdef PROFILE_OP_COUNTS + this->sqr_cnt++; +#endif /* Devegili OhEig Scott Dahab --- Multiplication and Squaring on Pairing-Friendly Fields.pdf; Section 3 (Karatsuba squaring) */ const my_Fp &a = this->c0, &b = this->c1; const my_Fp asq = a.squared(); @@ -111,6 +191,9 @@ Fp2_model Fp2_model::squared_karatsuba() const template& modulus> Fp2_model Fp2_model::squared_complex() const { +#ifdef PROFILE_OP_COUNTS + this->sqr_cnt++; +#endif /* Devegili OhEig Scott Dahab --- Multiplication and Squaring on Pairing-Friendly Fields.pdf; Section 3 (Complex squaring) */ const my_Fp &a = this->c0, &b = this->c1; const my_Fp ab = a * b; @@ -122,6 +205,9 @@ Fp2_model Fp2_model::squared_complex() const template& modulus> Fp2_model Fp2_model::inverse() const { +#ifdef PROFILE_OP_COUNTS + this->inv_cnt++; +#endif const my_Fp &a = this->c0, &b = this->c1; /* From "High-Speed Software Implementation of the Optimal Ate Pairing over Barreto-Naehrig Curves"; Algorithm 8 */ @@ -135,6 +221,13 @@ Fp2_model Fp2_model::inverse() const return Fp2_model(c0, c1); } +template& modulus> +Fp2_model& Fp2_model::invert() +{ + (*this) = inverse(); + return (*this); +} + template& modulus> Fp2_model Fp2_model::Frobenius_map(unsigned long power) const { @@ -145,63 +238,13 @@ Fp2_model Fp2_model::Frobenius_map(unsigned long power) co template& modulus> Fp2_model Fp2_model::sqrt() const { - Fp2_model one = Fp2_model::one(); - - size_t v = Fp2_model::s; - Fp2_model z = Fp2_model::nqr_to_t; - Fp2_model w = (*this)^Fp2_model::t_minus_1_over_2; - Fp2_model x = (*this) * w; - Fp2_model b = x * w; // b = (*this)^t - -#if DEBUG - // check if square with euler's criterion - Fp2_model check = b; - for (size_t i = 0; i < v-1; ++i) - { - check = check.squared(); - } - if (check != one) - { - assert(0); - } -#endif - - // compute square root with Tonelli--Shanks - // (does not terminate if not a square!) - - while (b != one) - { - size_t m = 0; - Fp2_model b2m = b; - while (b2m != one) - { - /* invariant: b2m = b^(2^m) after entering this loop */ - b2m = b2m.squared(); - m += 1; - } - - int j = v-m-1; - w = z; - while (j > 0) - { - w = w.squared(); - --j; - } // w = z^2^(v-m-1) - - z = w.squared(); - b = b * z; - x = x * w; - v = m; - } - - return x; + return tonelli_shanks_sqrt(*this); } template& modulus> -template -Fp2_model Fp2_model::operator^(const bigint &pow) const +void Fp2_model::init_tonelli_shanks_constants() { - return power, m>(*this, pow); + find_tonelli_shanks_constants, n>(); } template& modulus> diff --git a/libff/algebra/fields/fp3.hpp b/libff/algebra/fields/prime_extension/fp3.hpp similarity index 71% rename from libff/algebra/fields/fp3.hpp rename to libff/algebra/fields/prime_extension/fp3.hpp index cd34fbf1..14d422b5 100755 --- a/libff/algebra/fields/fp3.hpp +++ b/libff/algebra/fields/prime_extension/fp3.hpp @@ -11,7 +11,7 @@ #define FP3_HPP_ #include -#include +#include namespace libff { @@ -36,9 +36,16 @@ template& modulus> class Fp3_model { public: typedef Fp_model my_Fp; +#ifdef PROFILE_OP_COUNTS // NOTE: op counts are affected when you exponentiate with ^ + static long long add_cnt; + static long long sub_cnt; + static long long mul_cnt; + static long long sqr_cnt; + static long long inv_cnt; +#endif static bigint<3*n> euler; // (modulus^3-1)/2 - static size_t s; // modulus^3 = 2^s * t + 1 + static std::size_t s; // modulus^3 = 2^s * t + 1 static bigint<3*n> t; // with t odd static bigint<3*n> t_minus_1_over_2; // (t-1)/2 static my_Fp non_residue; // X^6-non_residue irreducible over Fp; used for constructing Fp3 = Fp[X] / (X^3 - non_residue) @@ -53,34 +60,66 @@ class Fp3_model { void clear() { c0.clear(); c1.clear(); c2.clear(); } void print() const { printf("c0/c1/c2:\n"); c0.print(); c1.print(); c2.print(); } - - static Fp3_model zero(); - static Fp3_model one(); - static Fp3_model random_element(); + void randomize(); bool is_zero() const { return c0.is_zero() && c1.is_zero() && c2.is_zero(); } bool operator==(const Fp3_model &other) const; bool operator!=(const Fp3_model &other) const; + Fp3_model& operator+=(const Fp3_model& other); + Fp3_model& operator-=(const Fp3_model& other); + Fp3_model& operator*=(const Fp3_model& other); + Fp3_model& operator^=(const unsigned long pow); + template + Fp3_model& operator^=(const bigint &pow); + Fp3_model operator+(const Fp3_model &other) const; Fp3_model operator-(const Fp3_model &other) const; Fp3_model operator*(const Fp3_model &other) const; + Fp3_model operator^(const unsigned long pow) const; + template + Fp3_model operator^(const bigint &other) const; Fp3_model operator-() const; + + Fp3_model& square(); Fp3_model squared() const; + Fp3_model& invert(); Fp3_model inverse() const; Fp3_model Frobenius_map(unsigned long power) const; Fp3_model sqrt() const; // HAS TO BE A SQUARE (else does not terminate) - template - Fp3_model operator^(const bigint &other) const; + /** Initializes euler, s, t, t_minus_1_over_2, nqr, and nqr_to_t. + * Must be called before sqrt(). Alternatively, these constants can be set manually. */ + static void init_tonelli_shanks_constants(); + static std::size_t size_in_bits() { return 3*my_Fp::size_in_bits(); } + static constexpr std::size_t extension_degree() { return 3; } + static constexpr bigint field_char() { return modulus; } - static size_t size_in_bits() { return 3*my_Fp::size_in_bits(); } - static bigint base_field_char() { return modulus; } + static Fp3_model zero(); + static Fp3_model one(); + static Fp3_model random_element(); friend std::ostream& operator<< (std::ostream &out, const Fp3_model &el); friend std::istream& operator>> (std::istream &in, Fp3_model &el); }; +#ifdef PROFILE_OP_COUNTS +template& modulus> +long long Fp3_model::add_cnt = 0; + +template& modulus> +long long Fp3_model::sub_cnt = 0; + +template& modulus> +long long Fp3_model::mul_cnt = 0; + +template& modulus> +long long Fp3_model::sqr_cnt = 0; + +template& modulus> +long long Fp3_model::inv_cnt = 0; +#endif + template& modulus> std::ostream& operator<<(std::ostream& out, const std::vector > &v); @@ -118,6 +157,6 @@ template& modulus> Fp_model Fp3_model::Frobenius_coeffs_c2[3]; } // libff -#include +#include #endif // FP3_HPP_ diff --git a/libff/algebra/fields/fp3.tcc b/libff/algebra/fields/prime_extension/fp3.tcc similarity index 75% rename from libff/algebra/fields/fp3.tcc rename to libff/algebra/fields/prime_extension/fp3.tcc index d3ea3fa6..0b184a92 100755 --- a/libff/algebra/fields/fp3.tcc +++ b/libff/algebra/fields/prime_extension/fp3.tcc @@ -10,10 +10,12 @@ #ifndef FP3_TCC_ #define FP3_TCC_ -#include +#include namespace libff { +using std::size_t; + template& modulus> Fp3_model Fp3_model::zero() { @@ -37,6 +39,12 @@ Fp3_model Fp3_model::random_element() return r; } +template& modulus> +void Fp3_model::randomize() +{ + (*this) = Fp3_model::random_element(); +} + template& modulus> bool Fp3_model::operator==(const Fp3_model &other) const { @@ -52,6 +60,9 @@ bool Fp3_model::operator!=(const Fp3_model &other) const template& modulus> Fp3_model Fp3_model::operator+(const Fp3_model &other) const { +#ifdef PROFILE_OP_COUNTS + this->add_cnt++; +#endif return Fp3_model(this->c0 + other.c0, this->c1 + other.c1, this->c2 + other.c2); @@ -60,6 +71,9 @@ Fp3_model Fp3_model::operator+(const Fp3_model template& modulus> Fp3_model Fp3_model::operator-(const Fp3_model &other) const { +#ifdef PROFILE_OP_COUNTS + this->sub_cnt++; +#endif return Fp3_model(this->c0 - other.c0, this->c1 - other.c1, this->c2 - other.c2); @@ -68,6 +82,9 @@ Fp3_model Fp3_model::operator-(const Fp3_model template& modulus> Fp3_model operator*(const Fp_model &lhs, const Fp3_model &rhs) { +#ifdef PROFILE_OP_COUNTS + rhs.mul_cnt++; +#endif return Fp3_model(lhs*rhs.c0, lhs*rhs.c1, lhs*rhs.c2); @@ -76,6 +93,9 @@ Fp3_model operator*(const Fp_model &lhs, const Fp3_model template& modulus> Fp3_model Fp3_model::operator*(const Fp3_model &other) const { +#ifdef PROFILE_OP_COUNTS + this->mul_cnt++; +#endif /* Devegili OhEig Scott Dahab --- Multiplication and Squaring on Pairing-Friendly Fields.pdf; Section 4 (Karatsuba) */ const my_Fp &A = other.c0, &B = other.c1, &C = other.c2, @@ -97,9 +117,61 @@ Fp3_model Fp3_model::operator-() const -this->c2); } +template& modulus> +Fp3_model Fp3_model::operator^(const unsigned long pow) const +{ + return power >(*this, pow); +} + +template& modulus> +template +Fp3_model Fp3_model::operator^(const bigint &pow) const +{ + return power >(*this, pow); +} + +template& modulus> +Fp3_model& Fp3_model::operator+=(const Fp3_model& other) +{ + (*this) = *this + other; + return (*this); +} + +template& modulus> +Fp3_model& Fp3_model::operator-=(const Fp3_model& other) +{ + (*this) = *this - other; + return (*this); +} + +template& modulus> +Fp3_model& Fp3_model::operator*=(const Fp3_model& other) +{ + (*this) = *this * other; + return (*this); +} + +template& modulus> +Fp3_model& Fp3_model::operator^=(const unsigned long pow) +{ + (*this) = *this ^ pow; + return (*this); +} + +template& modulus> +template +Fp3_model& Fp3_model::operator^=(const bigint &pow) +{ + (*this) = *this ^ pow; + return (*this); +} + template& modulus> Fp3_model Fp3_model::squared() const { +#ifdef PROFILE_OP_COUNTS + this->sqr_cnt++; +#endif /* Devegili OhEig Scott Dahab --- Multiplication and Squaring on Pairing-Friendly Fields.pdf; Section 4 (CH-SQR2) */ const my_Fp &a = this->c0, &b = this->c1, &c = this->c2; @@ -116,9 +188,19 @@ Fp3_model Fp3_model::squared() const s1 + s2 + s3 - s0 - s4); } +template& modulus> +Fp3_model& Fp3_model::square() +{ + (*this) = squared(); + return (*this); +} + template& modulus> Fp3_model Fp3_model::inverse() const { +#ifdef PROFILE_OP_COUNTS + this->inv_cnt++; +#endif const my_Fp &a = this->c0, &b = this->c1, &c = this->c2; @@ -136,6 +218,13 @@ Fp3_model Fp3_model::inverse() const return Fp3_model(t6 * c0, t6 * c1, t6 * c2); } +template& modulus> +Fp3_model& Fp3_model::invert() +{ + (*this) = inverse(); + return (*this); +} + template& modulus> Fp3_model Fp3_model::Frobenius_map(unsigned long power) const { @@ -147,63 +236,13 @@ Fp3_model Fp3_model::Frobenius_map(unsigned long power) co template& modulus> Fp3_model Fp3_model::sqrt() const { - Fp3_model one = Fp3_model::one(); - - size_t v = Fp3_model::s; - Fp3_model z = Fp3_model::nqr_to_t; - Fp3_model w = (*this)^Fp3_model::t_minus_1_over_2; - Fp3_model x = (*this) * w; - Fp3_model b = x * w; // b = (*this)^t - -#if DEBUG - // check if square with euler's criterion - Fp3_model check = b; - for (size_t i = 0; i < v-1; ++i) - { - check = check.squared(); - } - if (check != one) - { - assert(0); - } -#endif - - // compute square root with Tonelli--Shanks - // (does not terminate if not a square!) - - while (b != one) - { - size_t m = 0; - Fp3_model b2m = b; - while (b2m != one) - { - /* invariant: b2m = b^(2^m) after entering this loop */ - b2m = b2m.squared(); - m += 1; - } - - int j = v-m-1; - w = z; - while (j > 0) - { - w = w.squared(); - --j; - } // w = z^2^(v-m-1) - - z = w.squared(); - b = b * z; - x = x * w; - v = m; - } - - return x; + return tonelli_shanks_sqrt(*this); } template& modulus> -template -Fp3_model Fp3_model::operator^(const bigint &pow) const +void Fp3_model::init_tonelli_shanks_constants() { - return power >(*this, pow); + find_tonelli_shanks_constants, n>(); } template& modulus> diff --git a/libff/algebra/fields/fp4.hpp b/libff/algebra/fields/prime_extension/fp4.hpp similarity index 52% rename from libff/algebra/fields/fp4.hpp rename to libff/algebra/fields/prime_extension/fp4.hpp index a9630436..18e83d52 100755 --- a/libff/algebra/fields/fp4.hpp +++ b/libff/algebra/fields/prime_extension/fp4.hpp @@ -16,8 +16,8 @@ #ifndef FP4_HPP_ #define FP4_HPP_ -#include -#include +#include +#include namespace libff { @@ -36,7 +36,20 @@ class Fp4_model { typedef Fp_model my_Fp; typedef Fp2_model my_Fp2; typedef my_Fp2 my_Fpe; - +#ifdef PROFILE_OP_COUNTS // NOTE: op counts are affected when you exponentiate with ^ + static long long add_cnt; + static long long sub_cnt; + static long long mul_cnt; + static long long sqr_cnt; + static long long inv_cnt; +#endif + + static bigint<4*n> euler; // (modulus^4-1)/2 + static std::size_t s; // modulus^4 = 2^s * t + 1 + static bigint<4*n> t; // with t odd + static bigint<4*n> t_minus_1_over_2; // (t-1)/2 + static Fp4_model nqr; // a quadratic nonresidue in Fp4 + static Fp4_model nqr_to_t; // nqr^t static my_Fp non_residue; static my_Fp Frobenius_coeffs_c1[4]; // non_residue^((modulus^i-1)/4) for i=0,1,2,3 @@ -46,49 +59,99 @@ class Fp4_model { void print() const { printf("c0/c1:\n"); c0.print(); c1.print(); } void clear() { c0.clear(); c1.clear(); } - - static Fp4_model zero(); - static Fp4_model one(); - static Fp4_model random_element(); + void randomize(); bool is_zero() const { return c0.is_zero() && c1.is_zero(); } bool operator==(const Fp4_model &other) const; bool operator!=(const Fp4_model &other) const; + Fp4_model& operator+=(const Fp4_model& other); + Fp4_model& operator-=(const Fp4_model& other); + Fp4_model& operator*=(const Fp4_model& other); + Fp4_model& operator^=(const unsigned long pow); + template + Fp4_model& operator^=(const bigint &pow); + Fp4_model operator+(const Fp4_model &other) const; Fp4_model operator-(const Fp4_model &other) const; Fp4_model operator*(const Fp4_model &other) const; Fp4_model mul_by_023(const Fp4_model &other) const; + Fp4_model operator^(const unsigned long pow) const; + template + Fp4_model operator^(const bigint &exponent) const; + template& modulus_p> + Fp4_model operator^(const Fp_model &exponent) const; Fp4_model operator-() const; + + Fp4_model& square(); Fp4_model squared() const; + Fp4_model& invert(); Fp4_model inverse() const; Fp4_model Frobenius_map(unsigned long power) const; Fp4_model unitary_inverse() const; Fp4_model cyclotomic_squared() const; + Fp4_model sqrt() const; // HAS TO BE A SQUARE (else does not terminate) static my_Fp2 mul_by_non_residue(const my_Fp2 &elt); template Fp4_model cyclotomic_exp(const bigint &exponent) const; - static bigint base_field_char() { return modulus; } - static constexpr size_t extension_degree() { return 4; } + /** Initializes euler, s, t, t_minus_1_over_2, nqr, and nqr_to_t. + * Must be called before sqrt(). Alternatively, these constants can be set manually. */ + static void init_tonelli_shanks_constants(); + static std::size_t size_in_bits() { return 2*my_Fp2::size_in_bits(); } + static constexpr std::size_t extension_degree() { return 4; } + static constexpr bigint field_char() { return modulus; } + + static Fp4_model zero(); + static Fp4_model one(); + static Fp4_model random_element(); friend std::ostream& operator<< (std::ostream &out, const Fp4_model &el); friend std::istream& operator>> (std::istream &in, Fp4_model &el); }; +#ifdef PROFILE_OP_COUNTS +template& modulus> +long long Fp4_model::add_cnt = 0; + +template& modulus> +long long Fp4_model::sub_cnt = 0; + +template& modulus> +long long Fp4_model::mul_cnt = 0; + +template& modulus> +long long Fp4_model::sqr_cnt = 0; + +template& modulus> +long long Fp4_model::inv_cnt = 0; +#endif + template& modulus> Fp4_model operator*(const Fp_model &lhs, const Fp4_model &rhs); template& modulus> Fp4_model operator*(const Fp2_model &lhs, const Fp4_model &rhs); -template& modulus, mp_size_t m> -Fp4_model operator^(const Fp4_model &self, const bigint &exponent); +template& modulus> +bigint<4*n> Fp4_model::euler; + +template& modulus> +size_t Fp4_model::s; + +template& modulus> +bigint<4*n> Fp4_model::t; + +template& modulus> +bigint<4*n> Fp4_model::t_minus_1_over_2; + +template& modulus> +Fp4_model Fp4_model::nqr; -template& modulus, mp_size_t m, const bigint& modulus_p> -Fp4_model operator^(const Fp4_model &self, const Fp_model &exponent); +template& modulus> +Fp4_model Fp4_model::nqr_to_t; template& modulus> Fp_model Fp4_model::non_residue; @@ -99,6 +162,6 @@ Fp_model Fp4_model::Frobenius_coeffs_c1[4]; } // libff -#include +#include #endif // FP4_HPP_ diff --git a/libff/algebra/fields/fp4.tcc b/libff/algebra/fields/prime_extension/fp4.tcc similarity index 72% rename from libff/algebra/fields/fp4.tcc rename to libff/algebra/fields/prime_extension/fp4.tcc index 608a5844..8e298978 100755 --- a/libff/algebra/fields/fp4.tcc +++ b/libff/algebra/fields/prime_extension/fp4.tcc @@ -14,7 +14,7 @@ #ifndef FP4_TCC_ #define FP4_TCC_ -#include +#include #include namespace libff { @@ -49,6 +49,12 @@ Fp4_model Fp4_model::random_element() return r; } +template& modulus> +void Fp4_model::randomize() +{ + (*this) = Fp4_model::random_element(); +} + template& modulus> bool Fp4_model::operator==(const Fp4_model &other) const { @@ -64,6 +70,9 @@ bool Fp4_model::operator!=(const Fp4_model &other) const template& modulus> Fp4_model Fp4_model::operator+(const Fp4_model &other) const { +#ifdef PROFILE_OP_COUNTS + this->add_cnt++; +#endif return Fp4_model(this->c0 + other.c0, this->c1 + other.c1); } @@ -71,6 +80,9 @@ Fp4_model Fp4_model::operator+(const Fp4_model template& modulus> Fp4_model Fp4_model::operator-(const Fp4_model &other) const { +#ifdef PROFILE_OP_COUNTS + this->sub_cnt++; +#endif return Fp4_model(this->c0 - other.c0, this->c1 - other.c1); } @@ -78,6 +90,9 @@ Fp4_model Fp4_model::operator-(const Fp4_model template& modulus> Fp4_model operator*(const Fp_model &lhs, const Fp4_model &rhs) { +#ifdef PROFILE_OP_COUNTS + rhs.mul_cnt++; +#endif return Fp4_model(lhs*rhs.c0, lhs*rhs.c1); } @@ -85,6 +100,9 @@ Fp4_model operator*(const Fp_model &lhs, const Fp4_model template& modulus> Fp4_model operator*(const Fp2_model &lhs, const Fp4_model &rhs) { +#ifdef PROFILE_OP_COUNTS + rhs.mul_cnt++; +#endif return Fp4_model(lhs*rhs.c0, lhs*rhs.c1); } @@ -92,6 +110,9 @@ Fp4_model operator*(const Fp2_model &lhs, const Fp4_mode template& modulus> Fp4_model Fp4_model::operator*(const Fp4_model &other) const { +#ifdef PROFILE_OP_COUNTS + this->mul_cnt++; +#endif /* Devegili OhEig Scott Dahab --- Multiplication and Squaring on Pairing-Friendly Fields.pdf; Section 3 (Karatsuba) */ const my_Fp2 &B = other.c1, &A = other.c0, @@ -107,6 +128,9 @@ Fp4_model Fp4_model::operator*(const Fp4_model template& modulus> Fp4_model Fp4_model::mul_by_023(const Fp4_model &other) const { +#ifdef PROFILE_OP_COUNTS + this->mul_cnt++; +#endif /* Devegili OhEig Scott Dahab --- Multiplication and Squaring on Pairing-Friendly Fields.pdf; Section 3 (Karatsuba) */ assert(other.c0.c1.is_zero()); @@ -127,9 +151,68 @@ Fp4_model Fp4_model::operator-() const -this->c1); } +template& modulus> +Fp4_model Fp4_model::operator^(const unsigned long pow) const +{ + return power >(*this, pow); +} + +template& modulus> +template +Fp4_model Fp4_model::operator^(const bigint &exponent) const +{ + return power >(*this, exponent); +} + +template& modulus> +template& modulus_p> +Fp4_model Fp4_model::operator^(const Fp_model &exponent) const +{ + return (*this)^(exponent.as_bigint()); +} + +template& modulus> +Fp4_model& Fp4_model::operator+=(const Fp4_model& other) +{ + (*this) = *this + other; + return (*this); +} + +template& modulus> +Fp4_model& Fp4_model::operator-=(const Fp4_model& other) +{ + (*this) = *this - other; + return (*this); +} + +template& modulus> +Fp4_model& Fp4_model::operator*=(const Fp4_model& other) +{ + (*this) = *this * other; + return (*this); +} + +template& modulus> +Fp4_model& Fp4_model::operator^=(const unsigned long pow) +{ + (*this) = *this ^ pow; + return (*this); +} + +template& modulus> +template +Fp4_model& Fp4_model::operator^=(const bigint &pow) +{ + (*this) = *this ^ pow; + return (*this); +} + template& modulus> Fp4_model Fp4_model::squared() const { +#ifdef PROFILE_OP_COUNTS + this->sqr_cnt++; +#endif /* Devegili OhEig Scott Dahab --- Multiplication and Squaring on Pairing-Friendly Fields.pdf; Section 3 (Complex) */ const my_Fp2 &b = this->c1, &a = this->c0; @@ -139,9 +222,19 @@ Fp4_model Fp4_model::squared() const ab + ab); } +template& modulus> +Fp4_model& Fp4_model::square() +{ + (*this) = squared(); + return (*this); +} + template& modulus> Fp4_model Fp4_model::inverse() const { +#ifdef PROFILE_OP_COUNTS + this->inv_cnt++; +#endif /* From "High-Speed Software Implementation of the Optimal Ate Pairing over Barreto-Naehrig Curves"; Algorithm 8 */ const my_Fp2 &b = this->c1, &a = this->c0; const my_Fp2 t1 = b.squared(); @@ -151,6 +244,13 @@ Fp4_model Fp4_model::inverse() const return Fp4_model(a * new_t1, - (b * new_t1)); } +template& modulus> +Fp4_model& Fp4_model::invert() +{ + (*this) = inverse(); + return (*this); +} + template& modulus> Fp4_model Fp4_model::Frobenius_map(unsigned long power) const { @@ -214,16 +314,16 @@ Fp4_model Fp4_model::cyclotomic_exp(const bigint &expo return res; } -template& modulus, mp_size_t m> -Fp4_model operator^(const Fp4_model &self, const bigint &exponent) +template& modulus> +Fp4_model Fp4_model::sqrt() const { - return power >(self, exponent); + return tonelli_shanks_sqrt(*this); } -template& modulus, mp_size_t m, const bigint& modulus_p> -Fp4_model operator^(const Fp4_model &self, const Fp_model &exponent) +template& modulus> +void Fp4_model::init_tonelli_shanks_constants() { - return self^(exponent.as_bigint()); + find_tonelli_shanks_constants, n>(); } template& modulus> diff --git a/libff/algebra/fields/fp6_2over3.hpp b/libff/algebra/fields/prime_extension/fp6_2over3.hpp similarity index 53% rename from libff/algebra/fields/fp6_2over3.hpp rename to libff/algebra/fields/prime_extension/fp6_2over3.hpp index 7a256872..85db9082 100755 --- a/libff/algebra/fields/fp6_2over3.hpp +++ b/libff/algebra/fields/prime_extension/fp6_2over3.hpp @@ -9,9 +9,9 @@ #ifndef FP6_2OVER3_HPP_ #define FP6_2OVER3_HPP_ -#include -#include -#include +#include +#include +#include namespace libff { @@ -39,7 +39,20 @@ class Fp6_2over3_model { typedef Fp2_model my_Fp2; typedef Fp3_model my_Fp3; typedef my_Fp3 my_Fpe; - +#ifdef PROFILE_OP_COUNTS // NOTE: op counts are affected when you exponentiate with ^ + static long long add_cnt; + static long long sub_cnt; + static long long mul_cnt; + static long long sqr_cnt; + static long long inv_cnt; +#endif + + static bigint<6*n> euler; // (modulus^6-1)/2 + static std::size_t s; // modulus^6 = 2^s * t + 1 + static bigint<6*n> t; // with t odd + static bigint<6*n> t_minus_1_over_2; // (t-1)/2 + static Fp6_2over3_model nqr; // a quadratic nonresidue in Fp6 + static Fp6_2over3_model nqr_to_t; // nqr^t static my_Fp non_residue; static my_Fp Frobenius_coeffs_c1[6]; // non_residue^((modulus^i-1)/6) for i=0,1,2,3,4,5 @@ -49,38 +62,76 @@ class Fp6_2over3_model { void print() const { printf("c0/c1:\n"); c0.print(); c1.print(); } void clear() { c0.clear(); c1.clear(); } - - static Fp6_2over3_model zero(); - static Fp6_2over3_model one(); - static Fp6_2over3_model random_element(); + void randomize(); bool is_zero() const { return c0.is_zero() && c1.is_zero(); } bool operator==(const Fp6_2over3_model &other) const; bool operator!=(const Fp6_2over3_model &other) const; + Fp6_2over3_model& operator+=(const Fp6_2over3_model& other); + Fp6_2over3_model& operator-=(const Fp6_2over3_model& other); + Fp6_2over3_model& operator*=(const Fp6_2over3_model& other); + Fp6_2over3_model& operator^=(const unsigned long pow); + template + Fp6_2over3_model& operator^=(const bigint &pow); + Fp6_2over3_model operator+(const Fp6_2over3_model &other) const; Fp6_2over3_model operator-(const Fp6_2over3_model &other) const; Fp6_2over3_model operator*(const Fp6_2over3_model &other) const; Fp6_2over3_model mul_by_2345(const Fp6_2over3_model &other) const; + Fp6_2over3_model operator^(const unsigned long pow) const; + template + Fp6_2over3_model operator^(const bigint &exponent) const; + template& exp_modulus> + Fp6_2over3_model operator^(const Fp_model &exponent) const; Fp6_2over3_model operator-() const; + + Fp6_2over3_model& square(); Fp6_2over3_model squared() const; + Fp6_2over3_model& invert(); Fp6_2over3_model inverse() const; Fp6_2over3_model Frobenius_map(unsigned long power) const; Fp6_2over3_model unitary_inverse() const; Fp6_2over3_model cyclotomic_squared() const; + Fp6_2over3_model sqrt() const; // HAS TO BE A SQUARE (else does not terminate) static my_Fp3 mul_by_non_residue(const my_Fp3 &elem); template Fp6_2over3_model cyclotomic_exp(const bigint &exponent) const; - static bigint base_field_char() { return modulus; } - static constexpr size_t extension_degree() { return 6; } + /** Initializes euler, s, t, t_minus_1_over_2, nqr, and nqr_to_t. + * Must be called before sqrt(). Alternatively, these constants can be set manually. */ + static void init_tonelli_shanks_constants(); + static std::size_t size_in_bits() { return 2*my_Fp3::size_in_bits(); } + static constexpr std::size_t extension_degree() { return 6; } + static constexpr bigint field_char() { return modulus; } + + static Fp6_2over3_model zero(); + static Fp6_2over3_model one(); + static Fp6_2over3_model random_element(); friend std::ostream& operator<< (std::ostream &out, const Fp6_2over3_model &el); friend std::istream& operator>> (std::istream &in, Fp6_2over3_model &el); }; +#ifdef PROFILE_OP_COUNTS +template& modulus> +long long Fp6_2over3_model::add_cnt = 0; + +template& modulus> +long long Fp6_2over3_model::sub_cnt = 0; + +template& modulus> +long long Fp6_2over3_model::mul_cnt = 0; + +template& modulus> +long long Fp6_2over3_model::sqr_cnt = 0; + +template& modulus> +long long Fp6_2over3_model::inv_cnt = 0; +#endif + template& modulus> std::ostream& operator<<(std::ostream& out, const std::vector > &v); @@ -90,11 +141,23 @@ std::istream& operator>>(std::istream& in, std::vector& modulus> Fp6_2over3_model operator*(const Fp_model &lhs, const Fp6_2over3_model &rhs); -template& modulus, mp_size_t m> -Fp6_2over3_model operator^(const Fp6_2over3_model &self, const bigint &exponent); +template& modulus> +bigint<6*n> Fp6_2over3_model::euler; + +template& modulus> +size_t Fp6_2over3_model::s; + +template& modulus> +bigint<6*n> Fp6_2over3_model::t; + +template& modulus> +bigint<6*n> Fp6_2over3_model::t_minus_1_over_2; + +template& modulus> +Fp6_2over3_model Fp6_2over3_model::nqr; -template& modulus, mp_size_t m, const bigint& exp_modulus> -Fp6_2over3_model operator^(const Fp6_2over3_model &self, const Fp_model &exponent); +template& modulus> +Fp6_2over3_model Fp6_2over3_model::nqr_to_t; template& modulus> Fp_model Fp6_2over3_model::non_residue; @@ -103,6 +166,6 @@ template& modulus> Fp_model Fp6_2over3_model::Frobenius_coeffs_c1[6]; } // libff -#include +#include #endif // FP6_2OVER3_HPP_ diff --git a/libff/algebra/fields/fp6_2over3.tcc b/libff/algebra/fields/prime_extension/fp6_2over3.tcc similarity index 75% rename from libff/algebra/fields/fp6_2over3.tcc rename to libff/algebra/fields/prime_extension/fp6_2over3.tcc index 0b671d9d..d093592d 100755 --- a/libff/algebra/fields/fp6_2over3.tcc +++ b/libff/algebra/fields/prime_extension/fp6_2over3.tcc @@ -9,7 +9,7 @@ #ifndef FP6_2OVER3_TCC_ #define FP6_2OVER3_TCC_ -#include +#include #include namespace libff { @@ -44,6 +44,12 @@ Fp6_2over3_model Fp6_2over3_model::random_element() return r; } +template& modulus> +void Fp6_2over3_model::randomize() +{ + (*this) = Fp6_2over3_model::random_element(); +} + template& modulus> bool Fp6_2over3_model::operator==(const Fp6_2over3_model &other) const { @@ -59,6 +65,9 @@ bool Fp6_2over3_model::operator!=(const Fp6_2over3_model & template& modulus> Fp6_2over3_model Fp6_2over3_model::operator+(const Fp6_2over3_model &other) const { +#ifdef PROFILE_OP_COUNTS + this->add_cnt++; +#endif return Fp6_2over3_model(this->c0 + other.c0, this->c1 + other.c1); } @@ -66,6 +75,9 @@ Fp6_2over3_model Fp6_2over3_model::operator+(const Fp6_2ov template& modulus> Fp6_2over3_model Fp6_2over3_model::operator-(const Fp6_2over3_model &other) const { +#ifdef PROFILE_OP_COUNTS + this->sub_cnt++; +#endif return Fp6_2over3_model(this->c0 - other.c0, this->c1 - other.c1); } @@ -73,6 +85,9 @@ Fp6_2over3_model Fp6_2over3_model::operator-(const Fp6_2ov template& modulus> Fp6_2over3_model operator*(const Fp_model &lhs, const Fp6_2over3_model &rhs) { +#ifdef PROFILE_OP_COUNTS + rhs.mul_cnt++; +#endif return Fp6_2over3_model(lhs*rhs.c0, lhs*rhs.c1); } @@ -80,6 +95,9 @@ Fp6_2over3_model operator*(const Fp_model &lhs, const Fp template& modulus> Fp6_2over3_model Fp6_2over3_model::operator*(const Fp6_2over3_model &other) const { +#ifdef PROFILE_OP_COUNTS + this->mul_cnt++; +#endif /* Devegili OhEig Scott Dahab --- Multiplication and Squaring on Pairing-Friendly Fields.pdf; Section 3 (Karatsuba) */ const my_Fp3 &B = other.c1, &A = other.c0, @@ -95,6 +113,9 @@ Fp6_2over3_model Fp6_2over3_model::operator*(const Fp6_2ov template& modulus> Fp6_2over3_model Fp6_2over3_model::mul_by_2345(const Fp6_2over3_model &other) const { +#ifdef PROFILE_OP_COUNTS + this->mul_cnt++; +#endif /* Devegili OhEig Scott Dahab --- Multiplication and Squaring on Pairing-Friendly Fields.pdf; Section 3 (Karatsuba) */ assert(other.c0.c0.is_zero()); assert(other.c0.c1.is_zero()); @@ -116,9 +137,68 @@ Fp6_2over3_model Fp6_2over3_model::operator-() const -this->c1); } +template& modulus> +Fp6_2over3_model Fp6_2over3_model::operator^(const unsigned long pow) const +{ + return power >(*this, pow); +} + +template& modulus> +template +Fp6_2over3_model Fp6_2over3_model::operator^(const bigint &exponent) const +{ + return power, m>(*this, exponent); +} + +template& modulus> +template& exp_modulus> +Fp6_2over3_model Fp6_2over3_model::operator^(const Fp_model &exponent) const +{ + return (*this)^(exponent.as_bigint()); +} + +template& modulus> +Fp6_2over3_model& Fp6_2over3_model::operator+=(const Fp6_2over3_model& other) +{ + (*this) = *this + other; + return (*this); +} + +template& modulus> +Fp6_2over3_model& Fp6_2over3_model::operator-=(const Fp6_2over3_model& other) +{ + (*this) = *this - other; + return (*this); +} + +template& modulus> +Fp6_2over3_model& Fp6_2over3_model::operator*=(const Fp6_2over3_model& other) +{ + (*this) = *this * other; + return (*this); +} + +template& modulus> +Fp6_2over3_model& Fp6_2over3_model::operator^=(const unsigned long pow) +{ + (*this) = *this ^ pow; + return (*this); +} + +template& modulus> +template +Fp6_2over3_model& Fp6_2over3_model::operator^=(const bigint &pow) +{ + (*this) = *this ^ pow; + return (*this); +} + template& modulus> Fp6_2over3_model Fp6_2over3_model::squared() const { +#ifdef PROFILE_OP_COUNTS + this->sqr_cnt++; +#endif /* Devegili OhEig Scott Dahab --- Multiplication and Squaring on Pairing-Friendly Fields.pdf; Section 3 (Complex) */ const my_Fp3 &b = this->c1, &a = this->c0; const my_Fp3 ab = a * b; @@ -127,9 +207,19 @@ Fp6_2over3_model Fp6_2over3_model::squared() const ab + ab); } +template& modulus> +Fp6_2over3_model& Fp6_2over3_model::square() +{ + (*this) = squared(); + return (*this); +} + template& modulus> Fp6_2over3_model Fp6_2over3_model::inverse() const { +#ifdef PROFILE_OP_COUNTS + this->inv_cnt++; +#endif /* From "High-Speed Software Implementation of the Optimal Ate Pairing over Barreto-Naehrig Curves"; Algorithm 8 */ const my_Fp3 &b = this->c1, &a = this->c0; @@ -141,6 +231,13 @@ Fp6_2over3_model Fp6_2over3_model::inverse() const - (b * new_t1)); } +template& modulus> +Fp6_2over3_model& Fp6_2over3_model::invert() +{ + (*this) = inverse(); + return (*this); +} + template& modulus> Fp6_2over3_model Fp6_2over3_model::Frobenius_map(unsigned long power) const { @@ -245,29 +342,29 @@ Fp6_2over3_model Fp6_2over3_model::cyclotomic_exp(const b } template& modulus> -std::ostream& operator<<(std::ostream &out, const Fp6_2over3_model &el) +Fp6_2over3_model Fp6_2over3_model::sqrt() const { - out << el.c0 << OUTPUT_SEPARATOR << el.c1; - return out; + return tonelli_shanks_sqrt(*this); } template& modulus> -std::istream& operator>>(std::istream &in, Fp6_2over3_model &el) +void Fp6_2over3_model::init_tonelli_shanks_constants() { - in >> el.c0 >> el.c1; - return in; + find_tonelli_shanks_constants, n>(); } -template& modulus, mp_size_t m> -Fp6_2over3_model operator^(const Fp6_2over3_model &self, const bigint &exponent) +template& modulus> +std::ostream& operator<<(std::ostream &out, const Fp6_2over3_model &el) { - return power, m>(self, exponent); + out << el.c0 << OUTPUT_SEPARATOR << el.c1; + return out; } -template& modulus, mp_size_t m, const bigint& exp_modulus> -Fp6_2over3_model operator^(const Fp6_2over3_model &self, const Fp_model &exponent) +template& modulus> +std::istream& operator>>(std::istream &in, Fp6_2over3_model &el) { - return self^(exponent.as_bigint()); + in >> el.c0 >> el.c1; + return in; } } // libff diff --git a/libff/algebra/fields/fp6_3over2.hpp b/libff/algebra/fields/prime_extension/fp6_3over2.hpp similarity index 57% rename from libff/algebra/fields/fp6_3over2.hpp rename to libff/algebra/fields/prime_extension/fp6_3over2.hpp index 816ce85f..af07a17e 100755 --- a/libff/algebra/fields/fp6_3over2.hpp +++ b/libff/algebra/fields/prime_extension/fp6_3over2.hpp @@ -11,8 +11,8 @@ #define FP6_3OVER2_HPP_ #include -#include -#include +#include +#include namespace libff { @@ -38,7 +38,20 @@ class Fp6_3over2_model { public: typedef Fp_model my_Fp; typedef Fp2_model my_Fp2; - +#ifdef PROFILE_OP_COUNTS // NOTE: op counts are affected when you exponentiate with ^ + static long long add_cnt; + static long long sub_cnt; + static long long mul_cnt; + static long long sqr_cnt; + static long long inv_cnt; +#endif + + static bigint<6*n> euler; // (modulus^6-1)/2 + static std::size_t s; // modulus^6 = 2^s * t + 1 + static bigint<6*n> t; // with t odd + static bigint<6*n> t_minus_1_over_2; // (t-1)/2 + static Fp6_3over2_model nqr; // a quadratic nonresidue in Fp6 + static Fp6_3over2_model nqr_to_t; // nqr^t static my_Fp2 non_residue; static my_Fp2 Frobenius_coeffs_c1[6]; // non_residue^((modulus^i-1)/3) for i=0,1,2,3,4,5 static my_Fp2 Frobenius_coeffs_c2[6]; // non_residue^((2*modulus^i-2)/3) for i=0,1,2,3,4,5 @@ -49,35 +62,68 @@ class Fp6_3over2_model { void clear() { c0.clear(); c1.clear(); c2.clear(); } void print() const { printf("c0/c1/c2:\n"); c0.print(); c1.print(); c2.print(); } - - static Fp6_3over2_model zero(); - static Fp6_3over2_model one(); - static Fp6_3over2_model random_element(); + void randomize(); bool is_zero() const { return c0.is_zero() && c1.is_zero() && c2.is_zero(); } bool operator==(const Fp6_3over2_model &other) const; bool operator!=(const Fp6_3over2_model &other) const; + Fp6_3over2_model& operator+=(const Fp6_3over2_model& other); + Fp6_3over2_model& operator-=(const Fp6_3over2_model& other); + Fp6_3over2_model& operator*=(const Fp6_3over2_model& other); + Fp6_3over2_model& operator^=(const unsigned long pow); + template + Fp6_3over2_model& operator^=(const bigint &pow); + Fp6_3over2_model operator+(const Fp6_3over2_model &other) const; Fp6_3over2_model operator-(const Fp6_3over2_model &other) const; Fp6_3over2_model operator*(const Fp6_3over2_model &other) const; + Fp6_3over2_model operator^(const unsigned long pow) const; + template + Fp6_3over2_model operator^(const bigint &other) const; Fp6_3over2_model operator-() const; + + Fp6_3over2_model& square(); Fp6_3over2_model squared() const; + Fp6_3over2_model& invert(); Fp6_3over2_model inverse() const; Fp6_3over2_model Frobenius_map(unsigned long power) const; + Fp6_3over2_model sqrt() const; // HAS TO BE A SQUARE (else does not terminate) static my_Fp2 mul_by_non_residue(const my_Fp2 &elt); - template - Fp6_3over2_model operator^(const bigint &other) const; + /** Initializes euler, s, t, t_minus_1_over_2, nqr, and nqr_to_t. + * Must be called before sqrt(). Alternatively, these constants can be set manually. */ + static void init_tonelli_shanks_constants(); + static std::size_t size_in_bits() { return 3*my_Fp2::size_in_bits(); } + static constexpr std::size_t extension_degree() { return 6; } + static constexpr bigint field_char() { return modulus; } - static bigint base_field_char() { return modulus; } - static size_t extension_degree() { return 6; } + static Fp6_3over2_model zero(); + static Fp6_3over2_model one(); + static Fp6_3over2_model random_element(); friend std::ostream& operator<< (std::ostream &out, const Fp6_3over2_model &el); friend std::istream& operator>> (std::istream &in, Fp6_3over2_model &el); }; +#ifdef PROFILE_OP_COUNTS +template& modulus> +long long Fp6_3over2_model::add_cnt = 0; + +template& modulus> +long long Fp6_3over2_model::sub_cnt = 0; + +template& modulus> +long long Fp6_3over2_model::mul_cnt = 0; + +template& modulus> +long long Fp6_3over2_model::sqr_cnt = 0; + +template& modulus> +long long Fp6_3over2_model::inv_cnt = 0; +#endif + template& modulus> std::ostream& operator<<(std::ostream& out, const std::vector > &v); @@ -90,6 +136,24 @@ Fp6_3over2_model operator*(const Fp_model &lhs, const Fp template& modulus> Fp6_3over2_model operator*(const Fp2_model &lhs, const Fp6_3over2_model &rhs); +template& modulus> +bigint<6*n> Fp6_3over2_model::euler; + +template& modulus> +size_t Fp6_3over2_model::s; + +template& modulus> +bigint<6*n> Fp6_3over2_model::t; + +template& modulus> +bigint<6*n> Fp6_3over2_model::t_minus_1_over_2; + +template& modulus> +Fp6_3over2_model Fp6_3over2_model::nqr; + +template& modulus> +Fp6_3over2_model Fp6_3over2_model::nqr_to_t; + template& modulus> Fp2_model Fp6_3over2_model::non_residue; @@ -100,6 +164,6 @@ template& modulus> Fp2_model Fp6_3over2_model::Frobenius_coeffs_c2[6]; } // libff -#include +#include #endif // FP6_3OVER2_HPP_ diff --git a/libff/algebra/fields/fp6_3over2.tcc b/libff/algebra/fields/prime_extension/fp6_3over2.tcc similarity index 75% rename from libff/algebra/fields/fp6_3over2.tcc rename to libff/algebra/fields/prime_extension/fp6_3over2.tcc index de305678..a46c6a5b 100755 --- a/libff/algebra/fields/fp6_3over2.tcc +++ b/libff/algebra/fields/prime_extension/fp6_3over2.tcc @@ -9,10 +9,12 @@ #ifndef FP6_3OVER2_TCC_ #define FP6_3OVER2_TCC_ -#include +#include namespace libff { +using std::size_t; + template& modulus> Fp2_model Fp6_3over2_model::mul_by_non_residue(const Fp2_model &elt) { @@ -42,6 +44,12 @@ Fp6_3over2_model Fp6_3over2_model::random_element() return r; } +template& modulus> +void Fp6_3over2_model::randomize() +{ + (*this) = Fp6_3over2_model::random_element(); +} + template& modulus> bool Fp6_3over2_model::operator==(const Fp6_3over2_model &other) const { @@ -57,6 +65,9 @@ bool Fp6_3over2_model::operator!=(const Fp6_3over2_model & template& modulus> Fp6_3over2_model Fp6_3over2_model::operator+(const Fp6_3over2_model &other) const { +#ifdef PROFILE_OP_COUNTS + this->add_cnt++; +#endif return Fp6_3over2_model(this->c0 + other.c0, this->c1 + other.c1, this->c2 + other.c2); @@ -65,6 +76,9 @@ Fp6_3over2_model Fp6_3over2_model::operator+(const Fp6_3ov template& modulus> Fp6_3over2_model Fp6_3over2_model::operator-(const Fp6_3over2_model &other) const { +#ifdef PROFILE_OP_COUNTS + this->sub_cnt++; +#endif return Fp6_3over2_model(this->c0 - other.c0, this->c1 - other.c1, this->c2 - other.c2); @@ -73,6 +87,9 @@ Fp6_3over2_model Fp6_3over2_model::operator-(const Fp6_3ov template& modulus> Fp6_3over2_model operator*(const Fp_model &lhs, const Fp6_3over2_model &rhs) { +#ifdef PROFILE_OP_COUNTS + rhs.mul_cnt++; +#endif return Fp6_3over2_model(lhs*rhs.c0, lhs*rhs.c1, lhs*rhs.c2); @@ -81,6 +98,9 @@ Fp6_3over2_model operator*(const Fp_model &lhs, const Fp template& modulus> Fp6_3over2_model operator*(const Fp2_model &lhs, const Fp6_3over2_model &rhs) { +#ifdef PROFILE_OP_COUNTS + rhs.mul_cnt++; +#endif return Fp6_3over2_model(lhs*rhs.c0, lhs*rhs.c1, lhs*rhs.c2); @@ -89,6 +109,9 @@ Fp6_3over2_model operator*(const Fp2_model &lhs, const F template& modulus> Fp6_3over2_model Fp6_3over2_model::operator*(const Fp6_3over2_model &other) const { +#ifdef PROFILE_OP_COUNTS + this->mul_cnt++; +#endif /* Devegili OhEig Scott Dahab --- Multiplication and Squaring on Pairing-Friendly Fields.pdf; Section 4 (Karatsuba) */ const my_Fp2 &A = other.c0, &B = other.c1, &C = other.c2, @@ -110,9 +133,61 @@ Fp6_3over2_model Fp6_3over2_model::operator-() const -this->c2); } +template& modulus> +Fp6_3over2_model Fp6_3over2_model::operator^(const unsigned long pow) const +{ + return power >(*this, pow); +} + +template& modulus> +template +Fp6_3over2_model Fp6_3over2_model::operator^(const bigint &pow) const +{ + return power, m>(*this, pow); +} + +template& modulus> +Fp6_3over2_model& Fp6_3over2_model::operator+=(const Fp6_3over2_model& other) +{ + (*this) = *this + other; + return (*this); +} + +template& modulus> +Fp6_3over2_model& Fp6_3over2_model::operator-=(const Fp6_3over2_model& other) +{ + (*this) = *this - other; + return (*this); +} + +template& modulus> +Fp6_3over2_model& Fp6_3over2_model::operator*=(const Fp6_3over2_model& other) +{ + (*this) = *this * other; + return (*this); +} + +template& modulus> +Fp6_3over2_model& Fp6_3over2_model::operator^=(const unsigned long pow) +{ + (*this) = *this ^ pow; + return (*this); +} + +template& modulus> +template +Fp6_3over2_model& Fp6_3over2_model::operator^=(const bigint &pow) +{ + (*this) = *this ^ pow; + return (*this); +} + template& modulus> Fp6_3over2_model Fp6_3over2_model::squared() const { +#ifdef PROFILE_OP_COUNTS + this->sqr_cnt++; +#endif /* Devegili OhEig Scott Dahab --- Multiplication and Squaring on Pairing-Friendly Fields.pdf; Section 4 (CH-SQR2) */ const my_Fp2 &a = this->c0, &b = this->c1, &c = this->c2; @@ -129,9 +204,19 @@ Fp6_3over2_model Fp6_3over2_model::squared() const s1 + s2 + s3 - s0 - s4); } +template& modulus> +Fp6_3over2_model& Fp6_3over2_model::square() +{ + (*this) = squared(); + return (*this); +} + template& modulus> Fp6_3over2_model Fp6_3over2_model::inverse() const { +#ifdef PROFILE_OP_COUNTS + this->inv_cnt++; +#endif /* From "High-Speed Software Implementation of the Optimal Ate Pairing over Barreto-Naehrig Curves"; Algorithm 17 */ const my_Fp2 &a = this->c0, &b = this->c1, &c = this->c2; @@ -148,6 +233,13 @@ Fp6_3over2_model Fp6_3over2_model::inverse() const return Fp6_3over2_model(t6 * c0, t6 * c1, t6 * c2); } +template& modulus> +Fp6_3over2_model& Fp6_3over2_model::invert() +{ + (*this) = inverse(); + return (*this); +} + template& modulus> Fp6_3over2_model Fp6_3over2_model::Frobenius_map(unsigned long power) const { @@ -157,10 +249,15 @@ Fp6_3over2_model Fp6_3over2_model::Frobenius_map(unsigned } template& modulus> -template -Fp6_3over2_model Fp6_3over2_model::operator^(const bigint &pow) const +Fp6_3over2_model Fp6_3over2_model::sqrt() const { - return power, m>(*this, pow); + return tonelli_shanks_sqrt(*this); +} + +template& modulus> +void Fp6_3over2_model::init_tonelli_shanks_constants() +{ + find_tonelli_shanks_constants, n>(); } template& modulus> diff --git a/libff/algebra/fields/prime_field.hpp b/libff/algebra/fields/prime_field.hpp new file mode 100644 index 00000000..4aaf3a68 --- /dev/null +++ b/libff/algebra/fields/prime_field.hpp @@ -0,0 +1,109 @@ +/** @file + ***************************************************************************** + Declaration of common API for all finite fields in the prime_base/ and + prime_extension/ directories. + + Currently NOT used by the fields in this library. This class is not actually + the parent class of any field. All APIs are enforced through tests instead. + + The reason for this is to ensure high performance of all fields. This class + exists as documentation for common API between fields. + + Includes fields Fp^n for specified n. All of the prime extension fields must + implement all functions declared in this class. + ***************************************************************************** + * @author This file is part of libff, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ +#include +#include + +namespace libff { + +template& modulus> +class PrimeField; + +/* The type parameter T is intended to be set to the child class + * when this class is extended. For example, + * class Fp_model : public PrimeField ... + */ +template& modulus> +class PrimeField { +public: + /* Functions unique to prime fields */ + + /** The following parameters are used for the Tonelli-Shanks square root algorithms. + * Can be set manually or calculated with init_tonelli_shanks_constants(). */ + static bigint euler; // (modulus^deg-1)/2 + static std::size_t s; // modulus^deg = 2^s * t + 1 + static bigint t; // with t odd + static bigint t_minus_1_over_2; // (t-1)/2 + static T nqr; // a quadratic nonresidue in field + static T nqr_to_t; // nqr^t + + /** If extension field, returns the base field's characteristic. */ + static constexpr bigint field_char(); + + /** If base field, is the identity. */ + T Frobenius_map(unsigned long power) const; + + /* Functions common to all finite fields */ +#ifdef PROFILE_OP_COUNTS // NOTE: op counts are affected when you exponentiate with ^ + static long long add_cnt; + static long long sub_cnt; + static long long mul_cnt; + static long long sqr_cnt; + static long long inv_cnt; +#endif + + virtual T& operator+=(const T& other) = 0; + virtual T& operator-=(const T& other) = 0; + virtual T& operator*=(const T& other) = 0; + virtual T& operator^=(const unsigned long pow) = 0; + template + virtual T& operator^=(const bigint &pow) = 0; + + virtual T& square() = 0; + virtual T& invert() = 0; + + virtual T operator+(const T& other) const; + virtual T operator-(const T& other) const; + virtual T operator*(const T& other) const; + virtual T operator^(const unsigned long pow) const; + template + virtual T operator^(const bigint &pow) const; + virtual T operator-() const = 0; + + virtual T squared() const; + virtual T inverse() const; + /** HAS TO BE A SQUARE (else does not terminate). */ + virtual T sqrt() const = 0; + + bool operator==(const T& other) const = 0; + bool operator!=(const T& other) const = 0; + bool is_zero() const = 0; + + void print() const = 0; + + void randomize() = 0; + void clear() = 0; + + // the following should be defined in child classes, but are static so they can't be inherited + static T zero(); + static T one(); + static T random_element(); + /** Equals 1 for prime field Fp. */ + static constexpr std::size_t extension_degree(); + static std::size_t size_in_bits(); + + /** Initializes euler, s, t, t_minus_1_over_2, nqr, and nqr_to_t. + * Must be called before sqrt(). Alternatively, these constants can be set manually. */ + static void init_tonelli_shanks_constants(); + + // the following should be defined as well but can't be inherited + friend std::ostream& operator<<(std::ostream &out, const T &p); + friend std::istream& operator>>(std::istream &in, T &p); +}; + +} // libff diff --git a/libff/algebra/fields/tests/test_all_fields.cpp b/libff/algebra/fields/tests/test_all_fields.cpp new file mode 100644 index 00000000..38d788af --- /dev/null +++ b/libff/algebra/fields/tests/test_all_fields.cpp @@ -0,0 +1,384 @@ +/** + ***************************************************************************** + * @author This file is part of libff, developed by SCIPR Lab + * and contributors (see AUTHORS). + * @copyright MIT license (see LICENSE file) + *****************************************************************************/ +#include +#include + +#include "libff/algebra/curves/mnt/mnt4/mnt4_fields.hpp" +#include "libff/algebra/curves/mnt/mnt6/mnt6_fields.hpp" +#include "libff/algebra/curves/alt_bn128/alt_bn128_fields.hpp" +#include "libff/algebra/fields/binary/gf32.hpp" +#include "libff/algebra/fields/binary/gf64.hpp" +#include "libff/algebra/fields/binary/gf128.hpp" +#include "libff/algebra/fields/binary/gf192.hpp" +#include "libff/algebra/fields/binary/gf256.hpp" + +using namespace libff; + +class AllFieldsTest: public ::testing::Test { +public: + // p, q, r are three different primes + typedef alt_bn128_Fq Fp; + typedef alt_bn128_Fq2 Fp2; + typedef alt_bn128_Fq6 Fp6_3_2; + typedef alt_bn128_Fq12 Fp12_2_3_2; + + typedef mnt4_Fq Fq; + typedef mnt4_Fq2 Fq2; + typedef mnt4_Fq4 Fq4; + + typedef mnt6_Fq Fr; + typedef mnt6_Fq3 Fr3; + typedef mnt6_Fq6 Fr6_2_3; + + AllFieldsTest() + { + init_alt_bn128_fields(); + init_mnt4_fields(); + init_mnt6_fields(); + } +}; + +/** Returns a random element of FieldT that is not equal to y. */ +template +FieldT random_element_exclude(FieldT y) +{ + FieldT x = FieldT::random_element(); + while (x == y) + x = FieldT::random_element(); + return x; +} + +template +void expect_equal_or_negative(FieldT x, FieldT y) +{ + EXPECT_TRUE(x == y || x == -y); +} + +template +void test_field() +{ + // constants + const FieldT one = FieldT::one(); + const FieldT zero = FieldT::zero(); + const FieldT two = one + one; + + /******************* Test standard field axioms and properties. *******************/ + + FieldT x = FieldT::random_element(); + FieldT y = FieldT::random_element(); + FieldT z = FieldT::random_element(); + FieldT w = random_element_exclude(zero); + + EXPECT_EQ(x + y, y + x); // commutative law of addition + EXPECT_EQ((x + y) + z, x + (y + z)); // associative law of addition + EXPECT_EQ(x + zero, x); // additive identity + EXPECT_EQ(x + (-x), zero); // additive inverse + EXPECT_EQ(x * y, y * x); // commutative law of multiplication + EXPECT_EQ((x * y) * z, x * (y * z)); // associative law of multiplication + EXPECT_EQ(x * one, x); // multiplicative identity + EXPECT_EQ(w * w.inverse(), one); // multiplicative inverse + EXPECT_EQ((x + y) * z, x * z + y * z); // distributive law + + EXPECT_EQ(-zero, zero); + EXPECT_EQ(one.inverse(), one); + EXPECT_EQ(-(-x), x); + EXPECT_EQ(w.inverse().inverse(), w); + EXPECT_EQ(x * zero, zero); + EXPECT_EQ(x * (-y), -(x * y)); + + /*********************** Test +, -, *, zero(), and one(). ***********************/ + + x.randomize(); + y = x + x; + EXPECT_EQ(x * two, y); + EXPECT_EQ(x + y, x + x + x); + EXPECT_EQ(two + two, two * two); + + EXPECT_EQ(x - x, zero); + EXPECT_EQ(x - y, -x); + y.randomize(); + EXPECT_EQ(x + (-y), x - y); + EXPECT_EQ(x - y, -(y - x)); + + EXPECT_EQ(x * (-one), -x); + EXPECT_EQ((-x) * (-y), x * y); + z.randomize(); + w.randomize(); + EXPECT_EQ((x + y) * (z + w), x * z + x * w + y * z + y * w); + + EXPECT_NE(zero, one); + EXPECT_NE(one, two); + EXPECT_NE(x + one, x); + x = random_element_exclude(zero); + y = random_element_exclude(zero); + z = random_element_exclude(one); + if (two == zero) + EXPECT_EQ(x, -x); + else + EXPECT_NE(x, -x); + EXPECT_NE(x + y, x); + EXPECT_NE(x * z, x); + y = random_element_exclude(x); + z = random_element_exclude(two); + EXPECT_NE(x - y, zero); + EXPECT_NE(x * z, x + x); + + // test assignment + x.randomize(); + y = x; + x += one; + EXPECT_NE(x, y); + y += one; + EXPECT_EQ(x, y); + x.square(); + EXPECT_EQ(x, y * y); + + /******************** Test squared(), inverse(), sqrt(), and ^. ********************/ + + x.randomize(); + FieldT x2 = x * x; + y = x; + EXPECT_EQ(x.squared(), x2); + EXPECT_EQ(x, y); + x += x; + EXPECT_EQ(x, y + y); + x.randomize(); + y.randomize(); + EXPECT_EQ(x.squared() + two * x * y + y.squared(), (x + y).squared()); + EXPECT_EQ((x * y).squared(), x.squared() * y.squared()); + + expect_equal_or_negative((x * x).sqrt(), x); + expect_equal_or_negative((x * (x + x + x + x)).sqrt(), two * x); + expect_equal_or_negative(one.sqrt(), one); + expect_equal_or_negative((two + two).sqrt(), two); + expect_equal_or_negative(zero.sqrt(), zero); + + x = random_element_exclude(zero); + y = random_element_exclude(zero); + EXPECT_EQ(x.squared().inverse(), x.inverse().squared()); + EXPECT_EQ((x * y).inverse(), x.inverse() * y.inverse()); + EXPECT_EQ((x * y.inverse()).inverse(), x.inverse() * y); + + x.randomize(); + y.randomize(); + EXPECT_EQ(x.squared(), x^2); + EXPECT_EQ(x * x * x, x^3); + EXPECT_EQ(x.squared().squared().squared() * x, x^9); + + // I tried using random bigints, but it was too much work + const bigint<1> pow1 = bigint<1>("64703871"); + const bigint<1> pow2 = bigint<1>("42796681"); + const bigint<1> sum = bigint<1>("107500552"); + const bigint<1> diff = bigint<1>("21907190"); + EXPECT_EQ((x^pow1) * (x^pow2), x^sum); + EXPECT_EQ((x * y)^pow1, (x^pow1) * (y^pow1)); + + x = random_element_exclude(zero); + EXPECT_EQ(x.inverse()^pow1, (x^pow1).inverse()); + EXPECT_EQ((x^pow1) * (x.inverse()^pow2), x^diff); + + /******************** Test +=, -=, *=, square(), inverse(), ^=. ********************/ + + x.randomize(); + y.randomize(); + z = x + y; + x += y; + EXPECT_EQ(x, z); + x.randomize(); + z = x - y; + x -= y; + EXPECT_EQ(x, z); + x.randomize(); + z = x * y; + x *= y; + EXPECT_EQ(x, z); + + x.randomize(); + z = x.squared(); + x.square(); + EXPECT_EQ(x, z); + x = random_element_exclude(zero); + z = x.inverse(); + x.invert(); + EXPECT_EQ(x, z); + x.randomize(); + z = x^82; + x ^= 82; + EXPECT_EQ(x, z); + x.randomize(); + z = x^pow1; + x ^= pow1; + EXPECT_EQ(x, z); + + /****************** Test is_zero(), print(), clear(), <<, and >>. ******************/ + + EXPECT_TRUE(zero.is_zero()); + EXPECT_FALSE(one.is_zero()); + EXPECT_FALSE(random_element_exclude(zero).is_zero()); + + EXPECT_NO_THROW(x.print()); + + x.clear(); + EXPECT_EQ(x, zero); + EXPECT_TRUE(x.is_zero()); + + x.randomize(); + EXPECT_EQ(reserialize(x), x); + + /****************** Test extension_degree() and size_in_bits(). ******************/ + + EXPECT_GE(FieldT::extension_degree(), 1); + EXPECT_GE(FieldT::size_in_bits(), 1); +} + +template +void test_op_profiling() +{ + FieldT::add_cnt = 0; + FieldT::sub_cnt = 0; + FieldT::mul_cnt = 0; + FieldT::sqr_cnt = 0; + FieldT::inv_cnt = 0; + + FieldT x = FieldT::random_element(); + FieldT y = FieldT::random_element(); + FieldT one = FieldT::one(); + FieldT zero = FieldT::zero(); + x += y; + y = x + one; + x *= x + y; + y = x * y + one.inverse() - (x * one); + y.square(); + x -= y.squared(); + x = random_element_exclude(zero); + x.invert(); + x = x - one; + x *= x * x.squared(); + + EXPECT_EQ(FieldT::add_cnt, 4); + EXPECT_EQ(FieldT::sub_cnt, 3); + EXPECT_EQ(FieldT::mul_cnt, 5); + EXPECT_EQ(FieldT::sqr_cnt, 3); + EXPECT_EQ(FieldT::inv_cnt, 2); +} + +template +void test_prime_field() +{ + EXPECT_GE(FieldT::field_char().num_bits(), 2); // characteristic is at least 2 + + FieldT x = FieldT::random_element(); + FieldT x_q = x; + for (size_t power = 0; power < 10; ++power) + { + const FieldT x_qi = x.Frobenius_map(power); + EXPECT_EQ(x_qi, x_q); + + x_q = x_q^FieldT::field_char(); + } +} + +template +void test_binary_field() +{ + FieldT zero = FieldT::zero(); + FieldT one = FieldT::one(); + FieldT x = FieldT::random_element(); + FieldT y = random_element_exclude(x); + FieldT z = x; + + std::vector x_words = x.as_words(); + std::vector y_words = y.as_words(); + std::vector z_words = z.as_words(); + std::vector zero_words = zero.as_words(); + EXPECT_NE(x_words, y_words); + EXPECT_EQ(x_words, z_words); + for (uint64_t word : zero_words) + EXPECT_EQ(word, 0); + + EXPECT_GE(FieldT::modulus_, 1); + const uint64_t bits = FieldT::num_bits; + EXPECT_GE(bits, 1); + const bigint<1> characteristic = FieldT::template field_char<1>(); + EXPECT_EQ(characteristic, bigint<1>(2)); + + FieldT generator = FieldT::multiplicative_generator; + x = generator; + EXPECT_NE(generator, zero); + EXPECT_NE(generator, one); + std::set > values; + for (uint16_t i = 0; i < 10000; i++) + { + if (x == one) + break; + EXPECT_EQ(values.find(x.as_words()), values.end()); // generator^n never repeats + values.insert(x.as_words()); + x *= generator; + } +} + +TEST_F(AllFieldsTest, AllFieldsApiTest) +{ + test_field(); + test_field(); + test_field(); + test_field(); + + test_field(); + + test_field(); + test_field(); + + test_field(); + test_field(); + test_field(); + test_field(); + test_field(); +} + +#ifdef PROFILE_OP_COUNTS +TEST_F(AllFieldsTest, AllFieldsOpCountTest) +{ + test_op_profiling(); + test_op_profiling(); + test_op_profiling(); + test_op_profiling(); + + test_op_profiling(); + + test_op_profiling(); + test_op_profiling(); + + test_op_profiling(); + test_op_profiling(); + test_op_profiling(); + test_op_profiling(); + test_op_profiling(); +} +#endif + +TEST_F(AllFieldsTest, PrimeFieldsApiTest) +{ + test_prime_field(); + test_prime_field(); + test_prime_field(); + test_prime_field(); + + test_prime_field(); + + test_prime_field(); + test_prime_field(); +} + +TEST_F(AllFieldsTest, BinaryFieldsApiTest) +{ + test_binary_field(); + test_binary_field(); + test_binary_field(); + test_binary_field(); + test_binary_field(); +} diff --git a/libff/algebra/fields/tests/test_binary_fields.cpp b/libff/algebra/fields/tests/test_binary_fields.cpp new file mode 100644 index 00000000..f4edcd4f --- /dev/null +++ b/libff/algebra/fields/tests/test_binary_fields.cpp @@ -0,0 +1,152 @@ +#include + +#include "libff/algebra/fields/binary/gf32.hpp" +#include "libff/algebra/fields/binary/gf64.hpp" +#include "libff/algebra/fields/binary/gf128.hpp" +#include "libff/algebra/fields/binary/gf192.hpp" +#include "libff/algebra/fields/binary/gf256.hpp" + +using namespace libff; + +gf32 gf32_mul(const uint32_t &a_val, const uint32_t &b_val) +{ + return gf32(a_val) * gf32(b_val); +} + +gf64 gf64_mul(const uint64_t &a_val, const uint64_t &b_val) +{ + return gf64(a_val) * gf64(b_val); +} + +gf128 gf128_mul(const uint64_t &a_val_high, const uint64_t &a_val_low, const uint64_t &b_val_high, const uint64_t &b_val_low) +{ + return gf128(a_val_high, a_val_low) * gf128(b_val_high, b_val_low); +} + +gf192 gf192_mul(const uint64_t &a_val_high, const uint64_t &a_val_mid, const uint64_t &a_val_low, + const uint64_t &b_val_high, const uint64_t &b_val_mid, const uint64_t &b_val_low) +{ + return gf192(a_val_high, a_val_mid, a_val_low) * gf192(b_val_high, b_val_mid, b_val_low); +} + +gf256 gf256_mul(const uint64_t &a_val_high, const uint64_t &a_val_midh, + const uint64_t &a_val_midl, const uint64_t &a_val_low, + const uint64_t &b_val_high, const uint64_t &b_val_midh, + const uint64_t &b_val_midl, const uint64_t &b_val_low) +{ + return gf256(a_val_high, a_val_midh, a_val_midl, a_val_low) * + gf256(b_val_high, b_val_midh, b_val_midl, b_val_low); +} + +/* test cases generated by sage/gf32.sage script */ + +TEST(GF32Test, MultiplicationTest) { + EXPECT_EQ(gf32_mul(0xec71187bLL, 0x3c2b4dc6LL), gf32(0x18a792bdLL)); + EXPECT_EQ(gf32_mul(0xe24186cdLL, 0xc7b13dc2LL), gf32(0x5d8822c4LL)); + EXPECT_EQ(gf32_mul(0x0c053421LL, 0xe357be15LL), gf32(0x9692f4d2LL)); + EXPECT_EQ(gf32_mul(0xd0d42130LL, 0x3e597e24LL), gf32(0xc7ea9d01LL)); + EXPECT_EQ(gf32_mul(0x394b1a86LL, 0x3674def5LL), gf32(0xafa1ca21LL)); + EXPECT_EQ(gf32_mul(0xaf9995cbLL, 0x4c12835bLL), gf32(0x795b61feLL)); + EXPECT_EQ(gf32_mul(0x494cccf7LL, 0x47d58182LL), gf32(0xab95d1beLL)); + EXPECT_EQ(gf32_mul(0x00f6c1e7LL, 0x1dc6cb1eLL), gf32(0x2d4bd0c9LL)); + EXPECT_EQ(gf32_mul(0x81fe4a5fLL, 0xc975aa50LL), gf32(0x6f64a32eLL)); + EXPECT_EQ(gf32_mul(0x6903f854LL, 0x701eca01LL), gf32(0xee8735bbLL)); +} + +TEST(GF32Test, InverseTest) { + for (std::size_t i = 0; i < 10; i++) { + const gf32 a = gf32::random_element(); + const gf32 a_inv = a.inverse(); + + EXPECT_EQ(a*a_inv, gf32(1)); + } +} + +/* test cases generated by sage/gf64.sage script */ + +TEST(GF64Test, MultiplicationTest) { + EXPECT_EQ(gf64_mul(0x4c12835baf9995cbLL, 0x47d58182494cccf7LL), gf64(0xcd8d885948717796LL)); + EXPECT_EQ(gf64_mul(0x1dc6cb1e00f6c1e7LL, 0xc975aa5081fe4a5fLL), gf64(0x68a12cd69de5ba13LL)); + EXPECT_EQ(gf64_mul(0x701eca016903f854LL, 0x1bff27de896d5a63LL), gf64(0x3f2b03920fe6f850LL)); + EXPECT_EQ(gf64_mul(0x84949f71b013dafdLL, 0xc8642090f94902a6LL), gf64(0x0260be4b638467b4LL)); + EXPECT_EQ(gf64_mul(0x415405db8945dfb1LL, 0xe45f3b3b4fafbbfdLL), gf64(0xeedd9f3f9a790308LL)); + EXPECT_EQ(gf64_mul(0x4556f8aac66f427fLL, 0xb1d2219b0266de02LL), gf64(0xbdfd1cb2a183fd56LL)); + EXPECT_EQ(gf64_mul(0x3dddbcee3039f5fcLL, 0xfc9de0af7ec40b3fLL), gf64(0xab78b6d459d0d7a9LL)); + EXPECT_EQ(gf64_mul(0xc63a3ae27b186b00LL, 0x7218e0e28cba2badLL), gf64(0x7cc11d40edaf1d46LL)); + EXPECT_EQ(gf64_mul(0xbfe1ca4a7ccb135fLL, 0x6cbf9a222a7f80a7LL), gf64(0x6afbe201c18d9334LL)); + EXPECT_EQ(gf64_mul(0x38567cdad827aacfLL, 0xfa309c33b717dd13LL), gf64(0xc2db83d1400e7d58LL)); +} + +TEST(GF64Test, InverseTest) { + for (std::size_t i = 0; i < 10; i++) { + const gf64 a = gf64::random_element(); + const gf64 a_inv = a.inverse(); + + EXPECT_EQ(a*a_inv, gf64(1)); + } +} +/* test cases generated by sage/gf128.sage script */ + +TEST(GF128Test, MultiplicationTest) { + EXPECT_EQ(gf128_mul(0xb1d2219b0266de02LL, 0x4556f8aac66f427fLL, 0xfc9de0af7ec40b3fLL, 0x3dddbcee3039f5fcLL), gf128(0xf0b63cd2d8d9acb7LL, 0x14c9965cbb45f242LL)); + EXPECT_EQ(gf128_mul(0x7218e0e28cba2badLL, 0xc63a3ae27b186b00LL, 0x6cbf9a222a7f80a7LL, 0xbfe1ca4a7ccb135fLL), gf128(0x9a68dc276e08964aLL, 0x94cf56a81986e62fLL)); + EXPECT_EQ(gf128_mul(0xfa309c33b717dd13LL, 0x38567cdad827aacfLL, 0x8418b817f5caf84cLL, 0x3590e0c94d76b16aLL), gf128(0x0d4af0a0c7778f42LL, 0xa52cdf9b42326edcLL)); + EXPECT_EQ(gf128_mul(0xf7903a9c58e4223cLL, 0x0cdc30af062ba589LL, 0x4193e34b8241b8b6LL, 0x8d73a6d58a9833adLL), gf128(0x1aebbb2a40e6bdc5LL, 0x40b58b1663f1e7baLL)); + EXPECT_EQ(gf128_mul(0x81f59dadf3516810LL, 0x657e286088c96142LL, 0x12356e70b09e27a6LL, 0x56aa86373c498fddLL), gf128(0x6f1931b5b32adfd6LL, 0x3d0721c2dd988b1dLL)); + EXPECT_EQ(gf128_mul(0x0fe9a9f10ea6b3beLL, 0x614becf0f6981970LL, 0xf764a67447957a65LL, 0x897bb93561e04d72LL), gf128(0x7082df4ae39182f8LL, 0x29ead6ff7a231a76LL)); + EXPECT_EQ(gf128_mul(0xb6f0e7fe834a305fLL, 0x5d1bce4867374275LL, 0xf507be43450e596cLL, 0x7625671a07a1b127LL), gf128(0x7d87898bb86b9700LL, 0x288b33919644a559LL)); + EXPECT_EQ(gf128_mul(0x00a7fced16ffa59bLL, 0x7009d6ea6cbc3723LL, 0xb4dab96b1454919dLL, 0x23fad70584b9ff24LL), gf128(0x6f67249586163ab9LL, 0xbb823abc98939faeLL)); + EXPECT_EQ(gf128_mul(0x5756b56a1d208f91LL, 0xac2c97ebcf121998LL, 0x633c9cefc089eb74LL, 0x0fd73239d93bd077LL), gf128(0xb2658b016f98c47fLL, 0x9dfa616729b5e040LL)); + EXPECT_EQ(gf128_mul(0xf55ab02f9dae69b8LL, 0xc1c42adfa999b078LL, 0xfae308c406eb08feLL, 0x49bfcd0bd4d96b01LL), gf128(0xdf0f7f62ecc610e1LL, 0x9bcec94d9f08f412LL)); +} + +TEST(GF128Test, InverseTest) { + const gf128 a = gf128::random_element(); + const gf128 a_inv = a.inverse(); + + EXPECT_EQ(a*a_inv, gf128(1)); +} + +/* test cases generated by sage/gf192.sage script */ + +TEST(GF192Test, MultiplicationTest) { + EXPECT_EQ(gf192_mul(0x0cdc30af062ba589LL, 0x8418b817f5caf84cLL, 0x3590e0c94d76b16aLL, 0x4193e34b8241b8b6LL, 0x8d73a6d58a9833adLL, 0xf7903a9c58e4223cLL), gf192(0xedb2d77042f07f3eLL, 0xc223197d04425354LL, 0x601e9baa99e6b2fdLL)); + EXPECT_EQ(gf192_mul(0x56aa86373c498fddLL, 0x81f59dadf3516810LL, 0x657e286088c96142LL, 0x0fe9a9f10ea6b3beLL, 0x614becf0f6981970LL, 0x12356e70b09e27a6LL), gf192(0xcf0642476758587aLL, 0x2ed578d8f170b814LL, 0x0b86792ebec24165LL)); + EXPECT_EQ(gf192_mul(0x5d1bce4867374275LL, 0xf764a67447957a65LL, 0x897bb93561e04d72LL, 0xf507be43450e596cLL, 0x7625671a07a1b127LL, 0xb6f0e7fe834a305fLL), gf192(0x2d43614daf895767LL, 0xa0d43a4a59167a19LL, 0x1d01f4493cf9f6bfLL)); + EXPECT_EQ(gf192_mul(0x23fad70584b9ff24LL, 0x00a7fced16ffa59bLL, 0x7009d6ea6cbc3723LL, 0x5756b56a1d208f91LL, 0xac2c97ebcf121998LL, 0xb4dab96b1454919dLL), gf192(0x0b31e0f4e429e2d8LL, 0x91b61a18bdb18fd4LL, 0x35ce63ac64f58838LL)); + EXPECT_EQ(gf192_mul(0xc1c42adfa999b078LL, 0x633c9cefc089eb74LL, 0x0fd73239d93bd077LL, 0xfae308c406eb08feLL, 0x49bfcd0bd4d96b01LL, 0xf55ab02f9dae69b8LL), gf192(0xecd19c6c59d10edeLL, 0x5c081d84ee58552dLL, 0x598aefe615b5a49aLL)); + EXPECT_EQ(gf192_mul(0xf2e6b1294f40ac62LL, 0x512288f4b06917d3LL, 0xd2c36d17d828d9b4LL, 0x206901073d267fa5LL, 0x9a2789bfb11c03c4LL, 0x1cf009d26ee1f80fLL), gf192(0x68fd98a8545f9688LL, 0x1e6f3c0f65f3b25dLL, 0x75fb9afdb21f1278LL)); + EXPECT_EQ(gf192_mul(0xc78b2478a98afb85LL, 0x579c25544b3ba640LL, 0x7766723a1141eddcLL, 0x1d5e8949c38296e0LL, 0x224aa1e6e025b316LL, 0x84eb9e2187501666LL), gf192(0xd33304755a3790f5LL, 0xd9f5f3be81d6054dLL, 0x742cb900f1d5bcf9LL)); + EXPECT_EQ(gf192_mul(0x75bee645ed32bf73LL, 0xfaaf7393e729adf5LL, 0xe4e8ae96b691f6d2LL, 0x94659c82eed44ed6LL, 0x0d6f1491ffab6313LL, 0x034858f4f1f7b14bLL), gf192(0x998f56abe7e4348fLL, 0xcafb5a359d76233dLL, 0x930bfcefe10d3166LL)); + EXPECT_EQ(gf192_mul(0x9ded3331f7e20e08LL, 0xae8f8592118650dfLL, 0x4105e1bce7fda1a5LL, 0x22677e786437ded8LL, 0xeab6bb9efffe16f2LL, 0xae333a6c2e525a7eLL), gf192(0x981afe97f038b8e7LL, 0x2803fd759a41f4e0LL, 0xf80ac10929fc7e3fLL)); + EXPECT_EQ(gf192_mul(0x13ee2aa2bc56bb9fLL, 0x4b28b4a78b34aed6LL, 0xc9a973387db34f3cLL, 0x5980393a96b7e262LL, 0xbee979d0d3e73491LL, 0x724efc0872e555d7LL), gf192(0xce5179b296413b74LL, 0x90b969c3def4555fLL, 0x2de0b46a441b4738LL)); +} + +TEST(GF192Test, InverseTest) { + const gf192 a = gf192::random_element(); + const gf192 a_inv = a.inverse(); + + EXPECT_EQ(a*a_inv, gf192(1)); +} + +/* test cases generated by sage/gf256.sage script */ + +TEST(GF256Test, MultiplicationTest) { + EXPECT_EQ(gf256_mul(0xf764a67447957a65LL, 0x897bb93561e04d72LL, 0x0fe9a9f10ea6b3beLL, 0x614becf0f6981970LL, 0xf507be43450e596cLL, 0x7625671a07a1b127LL, 0xb6f0e7fe834a305fLL, 0x5d1bce4867374275LL), gf256(0x7830000656b147bbLL, 0x84aedc89d9eef7d5LL, 0x206521a58a74c76dLL, 0x15b45070f9272694LL)); + EXPECT_EQ(gf256_mul(0xb4dab96b1454919dLL, 0x23fad70584b9ff24LL, 0x00a7fced16ffa59bLL, 0x7009d6ea6cbc3723LL, 0x633c9cefc089eb74LL, 0x0fd73239d93bd077LL, 0x5756b56a1d208f91LL, 0xac2c97ebcf121998LL), gf256(0xec433aa096b7c5a3LL, 0xb988c6486912b0ffLL, 0xf4974416b3ec0351LL, 0xa0abd7439b4a90b4LL)); + EXPECT_EQ(gf256_mul(0xfae308c406eb08feLL, 0x49bfcd0bd4d96b01LL, 0xf55ab02f9dae69b8LL, 0xc1c42adfa999b078LL, 0x1cf009d26ee1f80fLL, 0xf2e6b1294f40ac62LL, 0x512288f4b06917d3LL, 0xd2c36d17d828d9b4LL), gf256(0xd4c9b1f1b6032f4aLL, 0x5a443906b0fd92f4LL, 0x069ef58da6005ef0LL, 0x81149bf7a2a4e9efLL)); + EXPECT_EQ(gf256_mul(0x579c25544b3ba640LL, 0x7766723a1141eddcLL, 0x206901073d267fa5LL, 0x9a2789bfb11c03c4LL, 0x1d5e8949c38296e0LL, 0x224aa1e6e025b316LL, 0x84eb9e2187501666LL, 0xc78b2478a98afb85LL), gf256(0xc92ed4a7f831b22eLL, 0x42d345a89b213da0LL, 0x6ca9b1401b327636LL, 0x81a1d4e28ecb3203LL)); + EXPECT_EQ(gf256_mul(0x034858f4f1f7b14bLL, 0x75bee645ed32bf73LL, 0xfaaf7393e729adf5LL, 0xe4e8ae96b691f6d2LL, 0xae8f8592118650dfLL, 0x4105e1bce7fda1a5LL, 0x94659c82eed44ed6LL, 0x0d6f1491ffab6313LL), gf256(0x3c58c4917b50380aLL, 0x155a26d3e04dc3f9LL, 0x0ece08a653d5d785LL, 0xa0491208d489ad20LL)); + EXPECT_EQ(gf256_mul(0x22677e786437ded8LL, 0xeab6bb9efffe16f2LL, 0xae333a6c2e525a7eLL, 0x9ded3331f7e20e08LL, 0x724efc0872e555d7LL, 0x13ee2aa2bc56bb9fLL, 0x4b28b4a78b34aed6LL, 0xc9a973387db34f3cLL), gf256(0x31c713050f9fe79fLL, 0x91f3134564072e28LL, 0xbd3b97df5ceaa321LL, 0x85ae031df2087301LL)); + EXPECT_EQ(gf256_mul(0xe103fdd38559f718LL, 0xbde830a033005e9dLL, 0x5980393a96b7e262LL, 0xbee979d0d3e73491LL, 0x24d79165090b54bbLL, 0x6be4979855b9f4a1LL, 0x3c84f51267ae0f3eLL, 0x49762387dc75fbcfLL), gf256(0xaf3c148f5a6d62b6LL, 0xcb2caa9c1491eb09LL, 0x9d964ce7c25f9cc4LL, 0xf0774bdc5efd321bLL)); + EXPECT_EQ(gf256_mul(0xc8d362a82d40e33dLL, 0x7ebb79ea0539aab6LL, 0xd4cb229a76bbfdf8LL, 0xe1ed007e6b4d18c4LL, 0xc5ff42586ffe84beLL, 0x2fa0d6324909d6bcLL, 0xd059de8a3f216806LL, 0x11ce6283a327c2aeLL), gf256(0x6d8f5131a50a1174LL, 0x3716b1b7b85aa29fLL, 0x786f09fc7add372aLL, 0xd9be899417749c66LL)); + EXPECT_EQ(gf256_mul(0xa34a5c6dc2269e92LL, 0xd4926e0f5173ba59LL, 0xad04af41cefd288cLL, 0xd6910fac0958e021LL, 0xb8efe59559134148LL, 0xe2df550b05c8346bLL, 0x471c649050d8df10LL, 0x3c4ddb6e1d7bdf2bLL), gf256(0x31bc02040d35ef67LL, 0xf4df56b7f489a233LL, 0x94a98345cd1c505eLL, 0x9b8880399d5b6f17LL)); + EXPECT_EQ(gf256_mul(0x0dd2d419a879877eLL, 0xbbd7c0e1cb89df45LL, 0xb920792cb175a788LL, 0xfe328eb0319d0dd7LL, 0xfdd10984711604a6LL, 0x449e2950c151d1f4LL, 0x06b95b1542038a8aLL, 0xbbc51592da56e2feLL), gf256(0x5eac8a0dfe585d7dLL, 0x8bb81c1be4902348LL, 0xb441d39d98693d34LL, 0x480e988c351ac9f3LL)); +} + +TEST(GF256Test, InverseTest) { + const gf256 a = gf256::random_element(); + const gf256 a_inv = a.inverse(); + + EXPECT_EQ(a*a_inv, gf256(1)); +} diff --git a/libff/algebra/fields/tests/test_fields.cpp b/libff/algebra/fields/tests/test_prime_fields.cpp similarity index 63% rename from libff/algebra/fields/tests/test_fields.cpp rename to libff/algebra/fields/tests/test_prime_fields.cpp index 8412796f..81a66538 100755 --- a/libff/algebra/fields/tests/test_fields.cpp +++ b/libff/algebra/fields/tests/test_prime_fields.cpp @@ -4,6 +4,8 @@ * and contributors (see AUTHORS). * @copyright MIT license (see LICENSE file) *****************************************************************************/ +#include + #include #include #include @@ -12,12 +14,35 @@ #include #endif #include -#include -#include +#include +#include using namespace libff; -#ifndef NDEBUG +class PrimeFieldsTest: public ::testing::Test { +public: + PrimeFieldsTest() + { + init_edwards_fields(); + init_mnt4_fields(); + init_mnt6_fields(); + init_alt_bn128_fields(); +#ifdef CURVE_BN128 // BN128 has fancy dependencies so it may be disabled + init_bn128_fields(); +#endif + } +}; + +/** Returns a random element of FieldT that is not zero. */ +template +FieldT random_element_non_zero() +{ + FieldT x = FieldT::random_element(); + while (x.is_zero()) + x = FieldT::random_element(); + return x; +} + template void test_field() { @@ -30,25 +55,29 @@ void test_field() FieldT a = FieldT::random_element(); FieldT a_ser; a_ser = reserialize(a); - assert(a_ser == a); + EXPECT_EQ(a_ser, a); FieldT b = FieldT::random_element(); FieldT c = FieldT::random_element(); FieldT d = FieldT::random_element(); - assert(a != zero); - assert(a != one); + EXPECT_EQ(a * a, a.squared()); + EXPECT_EQ((a + b).squared(), a.squared() + a*b + b*a + b.squared()); + EXPECT_EQ((a + b)*(c + d), a*c + a*d + b*c + b*d); + EXPECT_EQ(a - b, a + (-b)); + EXPECT_EQ(a - b, (-b) + a); - assert(a * a == a.squared()); - assert((a + b).squared() == a.squared() + a*b + b*a + b.squared()); - assert((a + b)*(c + d) == a*c + a*d + b*c + b*d); - assert(a - b == a + (-b)); - assert(a - b == (-b) + a); + EXPECT_EQ((a ^ rand1) * (a ^ rand2), (a^randsum)); - assert((a ^ rand1) * (a ^ rand2) == (a^randsum)); + a = random_element_non_zero(); + b = random_element_non_zero(); + c = random_element_non_zero(); + ASSERT_NE(a, zero); + ASSERT_NE(b, zero); + ASSERT_NE(c, zero); - assert(a * a.inverse() == one); - assert((a + b) * c.inverse() == a * c.inverse() + (b.inverse() * c).inverse()); + EXPECT_EQ(a * a.inverse(), one); + EXPECT_EQ((a + b) * c.inverse(), a * c.inverse() + (b.inverse() * c).inverse()); } @@ -59,7 +88,7 @@ void test_sqrt() { FieldT a = FieldT::random_element(); FieldT asq = a.squared(); - assert(asq.sqrt() == a || asq.sqrt() == -a); + EXPECT_TRUE(asq.sqrt() == a || asq.sqrt() == -a); } } @@ -67,33 +96,35 @@ template void test_two_squarings() { FieldT a = FieldT::random_element(); - assert(a.squared() == a * a); - assert(a.squared() == a.squared_complex()); - assert(a.squared() == a.squared_karatsuba()); + EXPECT_EQ(a.squared(), a * a); + EXPECT_EQ(a.squared(), a.squared_complex()); + EXPECT_EQ(a.squared(), a.squared_karatsuba()); } template void test_Frobenius() { FieldT a = FieldT::random_element(); - assert(a.Frobenius_map(0) == a); - FieldT a_q = a ^ FieldT::base_field_char(); + EXPECT_EQ(a.Frobenius_map(0), a); + FieldT a_q = a ^ FieldT::field_char(); for (size_t power = 1; power < 10; ++power) { const FieldT a_qi = a.Frobenius_map(power); - assert(a_qi == a_q); + EXPECT_EQ(a_qi, a_q); - a_q = a_q ^ FieldT::base_field_char(); + a_q = a_q ^ FieldT::field_char(); } } template void test_unitary_inverse() { - assert(FieldT::extension_degree() % 2 == 0); - FieldT a = FieldT::random_element(); + ASSERT_EQ(FieldT::extension_degree() % 2, 0); + FieldT a = random_element_non_zero(); + ASSERT_NE(a, FieldT::zero()); FieldT aqcubed_minus1 = a.Frobenius_map(FieldT::extension_degree()/2) * a.inverse(); - assert(aqcubed_minus1.inverse() == aqcubed_minus1.unitary_inverse()); + ASSERT_NE(aqcubed_minus1, FieldT::zero()); + EXPECT_EQ(aqcubed_minus1.inverse(), aqcubed_minus1.unitary_inverse()); } template @@ -103,36 +134,39 @@ template<> void test_cyclotomic_squaring >() { typedef Fqk FieldT; - assert(FieldT::extension_degree() % 2 == 0); - FieldT a = FieldT::random_element(); + EXPECT_EQ(FieldT::extension_degree() % 2, 0); + FieldT a = random_element_non_zero(); + ASSERT_NE(a, FieldT::zero()); FieldT a_unitary = a.Frobenius_map(FieldT::extension_degree()/2) * a.inverse(); // beta = a^((q^(k/2)-1)*(q+1)) FieldT beta = a_unitary.Frobenius_map(1) * a_unitary; - assert(beta.cyclotomic_squared() == beta.squared()); + EXPECT_EQ(beta.cyclotomic_squared(), beta.squared()); } template<> void test_cyclotomic_squaring >() { typedef Fqk FieldT; - assert(FieldT::extension_degree() % 2 == 0); - FieldT a = FieldT::random_element(); + ASSERT_EQ(FieldT::extension_degree() % 2, 0); + FieldT a = random_element_non_zero(); + ASSERT_NE(a, FieldT::zero()); FieldT a_unitary = a.Frobenius_map(FieldT::extension_degree()/2) * a.inverse(); // beta = a^(q^(k/2)-1) FieldT beta = a_unitary; - assert(beta.cyclotomic_squared() == beta.squared()); + EXPECT_EQ(beta.cyclotomic_squared(), beta.squared()); } template<> void test_cyclotomic_squaring >() { typedef Fqk FieldT; - assert(FieldT::extension_degree() % 2 == 0); - FieldT a = FieldT::random_element(); + ASSERT_EQ(FieldT::extension_degree() % 2, 0); + FieldT a = random_element_non_zero(); + ASSERT_NE(a, FieldT::zero()); FieldT a_unitary = a.Frobenius_map(FieldT::extension_degree()/2) * a.inverse(); // beta = a^((q^(k/2)-1)*(q+1)) FieldT beta = a_unitary.Frobenius_map(1) * a_unitary; - assert(beta.cyclotomic_squared() == beta.squared()); + EXPECT_EQ(beta.cyclotomic_squared(), beta.squared()); } template @@ -198,16 +232,16 @@ void test_Fp4_tom_cook() c2 = - (FieldT(5)*(FieldT(4).inverse()))* v0 + (FieldT(2)*(FieldT(3).inverse()))*(v1 + v2) - FieldT(24).inverse()*(v3 + v4) + FieldT(4)*v6 + beta*v6; c3 = FieldT(12).inverse() * (FieldT(5)*v0 - FieldT(7)*v1) - FieldT(24).inverse()*(v2 - FieldT(7)*v3 + v4 + v5) + FieldT(15)*v6; - assert(res == correct_res); + EXPECT_EQ(res, correct_res); // {v0, v3, v4, v5} const FieldT u = (FieldT::one() - beta).inverse(); - assert(v0 == u * c0 + beta * u * c2 - beta * u * FieldT(2).inverse() * v1 - beta * u * FieldT(2).inverse() * v2 + beta * v6); - assert(v3 == - FieldT(15) * u * c0 - FieldT(30) * u * c1 - FieldT(3) * (FieldT(4) + beta) * u * c2 - FieldT(6) * (FieldT(4) + beta) * u * c3 + (FieldT(24) - FieldT(3) * beta * FieldT(2).inverse()) * u * v1 + (-FieldT(8) + beta * FieldT(2).inverse()) * u * v2 + EXPECT_EQ(v0, u * c0 + beta * u * c2 - beta * u * FieldT(2).inverse() * v1 - beta * u * FieldT(2).inverse() * v2 + beta * v6); + EXPECT_EQ(v3, - FieldT(15) * u * c0 - FieldT(30) * u * c1 - FieldT(3) * (FieldT(4) + beta) * u * c2 - FieldT(6) * (FieldT(4) + beta) * u * c3 + (FieldT(24) - FieldT(3) * beta * FieldT(2).inverse()) * u * v1 + (-FieldT(8) + beta * FieldT(2).inverse()) * u * v2 - FieldT(3) * (-FieldT(16) + beta) * v6); - assert(v4 == - FieldT(15) * u * c0 + FieldT(30) * u * c1 - FieldT(3) * (FieldT(4) + beta) * u * c2 + FieldT(6) * (FieldT(4) + beta) * u * c3 + (FieldT(24) - FieldT(3) * beta * FieldT(2).inverse()) * u * v2 + (-FieldT(8) + beta * FieldT(2).inverse()) * u * v1 + EXPECT_EQ(v4, - FieldT(15) * u * c0 + FieldT(30) * u * c1 - FieldT(3) * (FieldT(4) + beta) * u * c2 + FieldT(6) * (FieldT(4) + beta) * u * c3 + (FieldT(24) - FieldT(3) * beta * FieldT(2).inverse()) * u * v2 + (-FieldT(8) + beta * FieldT(2).inverse()) * u * v1 - FieldT(3) * (-FieldT(16) + beta) * v6); - assert(v5 == - FieldT(80) * u * c0 - FieldT(240) * u * c1 - FieldT(8) * (FieldT(9) + beta) * u * c2 - FieldT(24) * (FieldT(9) + beta) * u * c3 - FieldT(2) * (-FieldT(81) + beta) * u * v1 + (-FieldT(81) + beta) * u * v2 + EXPECT_EQ(v5, - FieldT(80) * u * c0 - FieldT(240) * u * c1 - FieldT(8) * (FieldT(9) + beta) * u * c2 - FieldT(24) * (FieldT(9) + beta) * u * c3 - FieldT(2) * (-FieldT(81) + beta) * u * v1 + (-FieldT(81) + beta) * u * v2 - FieldT(8) * (-FieldT(81) + beta) * v6); // c0 + beta c2 - (beta v1)/2 - (beta v2)/ 2 - (-1 + beta) beta v6, @@ -217,38 +251,35 @@ void test_Fp4_tom_cook() } } -int main() +TEST_F(PrimeFieldsTest, GeneralTest) { - edwards_pp::init_public_params(); test_all_fields(); - test_cyclotomic_squaring >(); - mnt4_pp::init_public_params(); test_all_fields(); - test_Fp4_tom_cook(); - test_two_squarings >(); - test_cyclotomic_squaring >(); - mnt6_pp::init_public_params(); test_all_fields(); - test_cyclotomic_squaring >(); - alt_bn128_pp::init_public_params(); - test_field(); + test_field(); // alt_bn128_Fq6 is not included in test_all_fields test_Frobenius(); test_all_fields(); #ifdef CURVE_BN128 // BN128 has fancy dependencies so it may be disabled - bn128_pp::init_public_params(); test_field >(); test_field >(); #endif } -#else // NDEBUG +TEST_F(PrimeFieldsTest, SquareTest) +{ + test_cyclotomic_squaring >(); -int main() + test_two_squarings >(); + test_cyclotomic_squaring >(); + + test_cyclotomic_squaring >(); +} + +TEST_F(PrimeFieldsTest, TomCookTest) { - printf("All tests here depend on assert() which is disabled by -DNDEBUG. Please recompile and run again.\n"); + test_Fp4_tom_cook(); } -#endif // NDEBUG diff --git a/libff/algebra/scalar_multiplication/multiexp.hpp b/libff/algebra/scalar_multiplication/multiexp.hpp index bbbdb040..26b530ec 100755 --- a/libff/algebra/scalar_multiplication/multiexp.hpp +++ b/libff/algebra/scalar_multiplication/multiexp.hpp @@ -58,7 +58,7 @@ T multi_exp(typename std::vector::const_iterator vec_start, typename std::vector::const_iterator vec_end, typename std::vector::const_iterator scalar_start, typename std::vector::const_iterator scalar_end, - const size_t chunks); + const std::size_t chunks); /** @@ -72,7 +72,7 @@ T multi_exp_with_mixed_addition(typename std::vector::const_iterator vec_star typename std::vector::const_iterator vec_end, typename std::vector::const_iterator scalar_start, typename std::vector::const_iterator scalar_end, - const size_t chunks); + const std::size_t chunks); /** * A convenience function for calculating a pure inner product, where the @@ -94,31 +94,31 @@ using window_table = std::vector >; * Compute window size for the given number of scalars. */ template -size_t get_exp_window_size(const size_t num_scalars); +size_t get_exp_window_size(const std::size_t num_scalars); /** * Compute table of window sizes. */ template -window_table get_window_table(const size_t scalar_size, - const size_t window, +window_table get_window_table(const std::size_t scalar_size, + const std::size_t window, const T &g); template -T windowed_exp(const size_t scalar_size, - const size_t window, +T windowed_exp(const std::size_t scalar_size, + const std::size_t window, const window_table &powers_of_g, const FieldT &pow); template -std::vector batch_exp(const size_t scalar_size, - const size_t window, +std::vector batch_exp(const std::size_t scalar_size, + const std::size_t window, const window_table &table, const std::vector &v); template -std::vector batch_exp_with_coeff(const size_t scalar_size, - const size_t window, +std::vector batch_exp_with_coeff(const std::size_t scalar_size, + const std::size_t window, const window_table &table, const FieldT &coeff, const std::vector &v); diff --git a/libff/algebra/scalar_multiplication/multiexp.tcc b/libff/algebra/scalar_multiplication/multiexp.tcc index 0c85e2bc..a9e1b5ae 100755 --- a/libff/algebra/scalar_multiplication/multiexp.tcc +++ b/libff/algebra/scalar_multiplication/multiexp.tcc @@ -18,8 +18,8 @@ #include #include -#include -#include +#include +#include #include #include #include @@ -27,6 +27,8 @@ namespace libff { +using std::size_t; + template class ordered_exponent { // to use std::push_heap and friends later diff --git a/libff/algebra/scalar_multiplication/multiexp_profile.cpp b/libff/algebra/scalar_multiplication/multiexp_profile.cpp index 0434bb25..a220cbdc 100644 --- a/libff/algebra/scalar_multiplication/multiexp_profile.cpp +++ b/libff/algebra/scalar_multiplication/multiexp_profile.cpp @@ -8,6 +8,8 @@ using namespace libff; +using std::size_t; + template using run_result_t = std::pair >; diff --git a/libff/algebra/scalar_multiplication/wnaf.hpp b/libff/algebra/scalar_multiplication/wnaf.hpp index 6c65cde2..5bdb5733 100755 --- a/libff/algebra/scalar_multiplication/wnaf.hpp +++ b/libff/algebra/scalar_multiplication/wnaf.hpp @@ -14,7 +14,7 @@ #include -#include +#include namespace libff { @@ -22,19 +22,19 @@ namespace libff { * Find the wNAF representation of the given scalar relative to the given window size. */ template -std::vector find_wnaf(const size_t window_size, const bigint &scalar); +std::vector find_wnaf(const std::size_t window_size, const bigint &scalar); /** * In additive notation, use wNAF exponentiation (with the given window size) to compute scalar * base. */ template -T fixed_window_wnaf_exp(const size_t window_size, const T &base, const bigint &scalar); +T fixed_window_wnaf_exp(const std::size_t window_size, const T &base, const bigint &scalar); /** * In additive notation, use wNAF exponentiation (with the window size determined by T) to compute scalar * base. */ template -T opt_window_wnaf_exp(const T &base, const bigint &scalar, const size_t scalar_bits); +T opt_window_wnaf_exp(const T &base, const bigint &scalar, const std::size_t scalar_bits); } // libff diff --git a/libff/algebra/scalar_multiplication/wnaf.tcc b/libff/algebra/scalar_multiplication/wnaf.tcc index 5a8205e7..f9bece64 100755 --- a/libff/algebra/scalar_multiplication/wnaf.tcc +++ b/libff/algebra/scalar_multiplication/wnaf.tcc @@ -18,6 +18,8 @@ namespace libff { +using std::size_t; + template std::vector find_wnaf(const size_t window_size, const bigint &scalar) { diff --git a/libff/common/double.cpp b/libff/common/double.cpp index 6d9b93c0..24b114bd 100755 --- a/libff/common/double.cpp +++ b/libff/common/double.cpp @@ -14,7 +14,7 @@ #include -#include +#include #include namespace libff { diff --git a/libff/common/double.hpp b/libff/common/double.hpp index f74cead0..77c7dd5e 100755 --- a/libff/common/double.hpp +++ b/libff/common/double.hpp @@ -14,7 +14,7 @@ #include -#include +#include namespace libff { diff --git a/libff/common/profiling.cpp b/libff/common/profiling.cpp index f2a19858..04ef1544 100755 --- a/libff/common/profiling.cpp +++ b/libff/common/profiling.cpp @@ -92,8 +92,8 @@ std::list > op_data_points = { #endif }; -bool inhibit_profiling_info = false; -bool inhibit_profiling_counters = false; +bool inhibit_profiling_info = true; +bool inhibit_profiling_counters = true; void clear_profiling_counters() { @@ -344,6 +344,7 @@ void print_mem(const std::string &s) printf("* Peak vsize (physical memory+swap) in mebibytes (%s): %lu\n", s.c_str(), usage.vsize >> 20); } #else + UNUSED(s); printf("* Memory profiling not supported in NO_PROCPS mode\n"); #endif } diff --git a/libff/common/rng.tcc b/libff/common/rng.tcc index 92eecea1..52aa48f9 100755 --- a/libff/common/rng.tcc +++ b/libff/common/rng.tcc @@ -17,7 +17,7 @@ #include #include -#include +#include #include #include