From df048112c39ff891d6fac2293db3a58e6fb2c6f4 Mon Sep 17 00:00:00 2001 From: Mamy Ratsimbazafy Date: Thu, 15 Sep 2022 17:11:57 +0200 Subject: [PATCH] Example+Test C API vs GMP (#203) * Example+Test C API vs GMP * Create build directory for bindings test * --nimMainPrefix is 1.6 only * Add libdl for dynamic loading * absolute paths * add static link test * Fix man main, rename Nimmain to init_NimMain * Deal with MacOS annoying linker w.r.t. static libraries * use .exe extension to satisfy windows (?) * annoying GCC which doesn't create paths * Try skipping DLL test on windows * windows extensions ... * no lib prefix on windows --- .github/workflows/ci.yml | 14 +- bindings/constantine_bls12_381.nim | 19 +- bindings/constantine_pasta.nim | 20 +- bindings/gen_bindings.nim | 7 +- bindings/gen_header.nim | 45 ++-- bindings/generated/constantine_bls12_381.h | 31 +-- bindings/generated/constantine_pasta.h | 38 ++-- constantine.nimble | 71 +++++- constantine/curves_primitives.nim | 4 +- tests/bindings/t_libctt_bls12_381.c | 247 +++++++++++++++++++++ 10 files changed, 403 insertions(+), 93 deletions(-) create mode 100644 tests/bindings/t_libctt_bls12_381.c diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 0ba58d7..8dafbc5 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -7,7 +7,7 @@ jobs: fail-fast: false max-parallel: 20 matrix: - nim_version: [version-1-4, version-1-6] # [version-1-4, devel] + nim_version: [version-1-6] # [version-1-4, devel] target: - os: linux cpu: amd64 @@ -197,21 +197,27 @@ jobs: nimble refresh --verbose -y nimble install --verbose -y gmp stew jsony asynctools - - name: Run Constantine tests (UNIX with Assembler) + - name: Run Constantine tests (UNIX with Assembly) if: runner.os != 'Windows' && matrix.target.BACKEND == 'ASM' shell: bash run: | cd constantine + nimble bindings --verbose + nimble test_bindings --verbose nimble test_parallel --verbose - - name: Run Constantine tests (UNIX no Assembler) + - name: Run Constantine tests (UNIX no Assembly) if: runner.os != 'Windows' && matrix.target.BACKEND == 'NO_ASM' shell: bash run: | cd constantine + nimble bindings --verbose + nimble test_bindings --verbose nimble test_parallel_no_asm --verbose - - name: Run Constantine tests (Windows no Assembler) + - name: Run Constantine tests (Windows no Assembly) if: runner.os == 'Windows' && matrix.target.BACKEND == 'NO_ASM' shell: msys2 {0} run: | cd constantine + nimble bindings --verbose + nimble test_bindings --verbose nimble test_parallel_no_asm --verbose diff --git a/bindings/constantine_bls12_381.nim b/bindings/constantine_bls12_381.nim index d1e22f4..9b97397 100644 --- a/bindings/constantine_bls12_381.nim +++ b/bindings/constantine_bls12_381.nim @@ -34,10 +34,19 @@ collectBindings(cBindings): # Write header when isMainModule and defined(CttGenerateHeaders): - import std/os + import std/[os, strformat] proc main() = - echo "Running bindings generation for " & getAppFilename().extractFilename() + # echo "Running bindings generation for " & getAppFilename().extractFilename() + + var dir = "." + if paramCount() == 1: + dir = paramStr(1) + elif paramCount() > 1: + let exeName = getAppFilename().extractFilename() + echo &"Usage: {exeName} " + echo "Found more than one parameter" + quit 1 var header: string header = genBuiltinsTypes() @@ -64,15 +73,15 @@ when isMainModule and defined(CttGenerateHeaders): header &= '\n' header &= genEllipticCurvePoint("bls12381_ec_g2_prj", "x, y, z", "bls12381_fp2") header &= '\n' + header &= declNimMain("bls12381") + header &= '\n' header &= cBindings header &= '\n' - header &= declNimMain("bls12381") header = genCpp(header) header = genHeader("BLS12381", header) header = genHeaderLicense() & header - writeFile("constantine_bls12_381.h", header) - + writeFile(dir/"constantine_bls12_381.h", header) main() \ No newline at end of file diff --git a/bindings/constantine_pasta.nim b/bindings/constantine_pasta.nim index 8760985..d11e232 100644 --- a/bindings/constantine_pasta.nim +++ b/bindings/constantine_pasta.nim @@ -36,10 +36,20 @@ collectBindings(cBindings): # Write header when isMainModule and defined(CttGenerateHeaders): - import std/os + import std/[os, strformat] proc main() = - echo "Running bindings generation for " & getAppFilename().extractFilename() + # echo "Running bindings generation for " & getAppFilename().extractFilename() + + var dir = "." + if paramCount() == 1: + dir = paramStr(1) + elif paramCount() > 1: + let exeName = getAppFilename().extractFilename() + echo &"Usage: {exeName} " + echo "Found more than one parameter" + quit 1 + var header: string header = genBuiltinsTypes() @@ -68,15 +78,15 @@ when isMainModule and defined(CttGenerateHeaders): header &= '\n' header &= genEllipticCurvePoint("vesta_ec_prj", "x, y, z", "vesta_fp") header &= '\n' + header &= declNimMain("pasta") + header &= '\n' header &= cBindings header &= '\n' - header &= declNimMain("pasta") header = genCpp(header) header = genHeader("PASTA", header) header = genHeaderLicense() & header - writeFile("constantine_pasta.h", header) - + writeFile(dir/"constantine_pasta.h", header) main() \ No newline at end of file diff --git a/bindings/gen_bindings.nim b/bindings/gen_bindings.nim index 7b1f58d..59e9e9d 100644 --- a/bindings/gen_bindings.nim +++ b/bindings/gen_bindings.nim @@ -19,7 +19,7 @@ export curves, curves_primitives template genBindingsField*(Field: untyped) = {.push cdecl, dynlib, exportc, raises: [].} # No exceptions allowed - + func `ctt _ Field _ unmarshalBE`(dst: var Field, src: openarray[byte]) = ## Deserialize unmarshalBE(dst, src) @@ -48,7 +48,10 @@ template genBindingsField*(Field: untyped) = func `ctt _ Field _ set_minus_one`(a: var Field) = a.setMinusOne() # -------------------------------------------------------------------------------------- - func `ctt _ Field _ neg`(a: var Field) = + func `ctt _ Field _ neg`(r: var Field, a: Field) = + r.neg(a) + + func `ctt _ Field _ neg_in_place`(a: var Field) = a.neg() func `ctt _ Field _ sum`(r: var Field, a, b: Field) = diff --git a/bindings/gen_header.nim b/bindings/gen_header.nim index d48d126..1220312 100644 --- a/bindings/gen_header.nim +++ b/bindings/gen_header.nim @@ -55,7 +55,7 @@ extern "C" {{ proc genBuiltinsTypes*(): string = """ -#if defined{__SIZE_TYPE__} && defined(__PTRDIFF_TYPE__) +#if defined(__SIZE_TYPE__) && defined(__PTRDIFF_TYPE__) typedef __SIZE_TYPE__ size_t; typedef __PTRDIFF_TYPE__ ptrdiff_t; #else @@ -93,6 +93,25 @@ proc genExtField*(name: string, degree: int, basename: string): string = proc genEllipticCurvePoint*(name, coords, basename: string): string = &"typedef struct {{ {basename} {coords}; }} {name};" +# Nim internals +# ------------------------------------------- + +proc declNimMain*(libName: string): string = + ## Create the NimMain function. + ## It initializes: + ## - the Nim runtime if seqs, strings or heap-allocated types are used, + ## this is the case only if Constantine is multithreaded. + ## - runtime CPU features detection + ## + ## Assumes library is compiled with --nimMainPrefix:ctt_{libName}_ + &""" + +/* + * Initializes the library: + * - detect CPU features like ADX instructions support (MULX, ADCX, ADOX) + */ +void ctt_{libName}_init_NimMain(void);""" + # Subroutines' declarations # ------------------------------------------- @@ -159,7 +178,6 @@ macro collectBindings*(cBindingsStr: untyped, body: typed): untyped = for generator in body: generator.expectKind(nnkStmtList) - cBindings &= "\n" for fnDef in generator: if fnDef.kind notin {nnkProcDef, nnkFuncDef}: continue @@ -190,26 +208,3 @@ macro collectBindings*(cBindingsStr: untyped, body: typed): untyped = result = newConstStmt(cBindingsStr, newLit cBindings) else: result = body - - -# Nim internals -# ------------------------------------------- - -proc declNimMain*(libName: string): string = - ## Create the NimMain function. - ## It initializes: - ## - the Nim runtime if seqs, strings or heap-allocated types are used, - ## this is the case only if Constantine is multithreaded. - ## - runtime CPU features detection - ## - ## Assumes library is compiled with --nimMainPrefix:ctt_{libName}_ - &""" - -/* - * Initializes the library: - * - the Nim runtime if heap-allocated types are used, - * this is the case only if Constantine is multithreaded. - * - runtime CPU features detection - */ -void ctt_{libName}_NimMain(void); -""" \ No newline at end of file diff --git a/bindings/generated/constantine_bls12_381.h b/bindings/generated/constantine_bls12_381.h index 94cbaab..a6e59b7 100644 --- a/bindings/generated/constantine_bls12_381.h +++ b/bindings/generated/constantine_bls12_381.h @@ -14,7 +14,7 @@ extern "C" { #endif -#if defined{__SIZE_TYPE__} && defined(__PTRDIFF_TYPE__) +#if defined(__SIZE_TYPE__) && defined(__PTRDIFF_TYPE__) typedef __SIZE_TYPE__ size_t; typedef __PTRDIFF_TYPE__ ptrdiff_t; #else @@ -46,6 +46,11 @@ typedef struct { bls12381_fp2 x, y; } bls12381_ec_g2_aff; typedef struct { bls12381_fp2 x, y, z; } bls12381_ec_g2_jac; typedef struct { bls12381_fp2 x, y, z; } bls12381_ec_g2_prj; +/* + * Initializes the library: + * - detect CPU features like ADX instructions support (MULX, ADCX, ADOX) + */ +void ctt_bls12381_init_NimMain(void); void ctt_bls12381_fr_unmarshalBE(bls12381_fr* dst, const byte src[], ptrdiff_t src_len); void ctt_bls12381_fr_marshalBE(byte dst[], ptrdiff_t dst_len, const bls12381_fr* src); @@ -56,7 +61,8 @@ secret_bool ctt_bls12381_fr_is_minus_one(const bls12381_fr* a); void ctt_bls12381_fr_set_zero(bls12381_fr* a); void ctt_bls12381_fr_set_one(bls12381_fr* a); void ctt_bls12381_fr_set_minus_one(bls12381_fr* a); -void ctt_bls12381_fr_neg(bls12381_fr* a); +void ctt_bls12381_fr_neg(bls12381_fr* r, const bls12381_fr* a); +void ctt_bls12381_fr_neg_in_place(bls12381_fr* a); void ctt_bls12381_fr_sum(bls12381_fr* r, const bls12381_fr* a, const bls12381_fr* b); void ctt_bls12381_fr_add_in_place(bls12381_fr* a, const bls12381_fr* b); void ctt_bls12381_fr_diff(bls12381_fr* r, const bls12381_fr* a, const bls12381_fr* b); @@ -77,7 +83,6 @@ void ctt_bls12381_fr_cset_one(bls12381_fr* a, const secret_bool ctl); void ctt_bls12381_fr_cneg_in_place(bls12381_fr* a, const secret_bool ctl); void ctt_bls12381_fr_cadd_in_place(bls12381_fr* a, const bls12381_fr* b, const secret_bool ctl); void ctt_bls12381_fr_csub_in_place(bls12381_fr* a, const bls12381_fr* b, const secret_bool ctl); - void ctt_bls12381_fp_unmarshalBE(bls12381_fp* dst, const byte src[], ptrdiff_t src_len); void ctt_bls12381_fp_marshalBE(byte dst[], ptrdiff_t dst_len, const bls12381_fp* src); secret_bool ctt_bls12381_fp_is_eq(const bls12381_fp* a, const bls12381_fp* b); @@ -87,7 +92,8 @@ secret_bool ctt_bls12381_fp_is_minus_one(const bls12381_fp* a); void ctt_bls12381_fp_set_zero(bls12381_fp* a); void ctt_bls12381_fp_set_one(bls12381_fp* a); void ctt_bls12381_fp_set_minus_one(bls12381_fp* a); -void ctt_bls12381_fp_neg(bls12381_fp* a); +void ctt_bls12381_fp_neg(bls12381_fp* r, const bls12381_fp* a); +void ctt_bls12381_fp_neg_in_place(bls12381_fp* a); void ctt_bls12381_fp_sum(bls12381_fp* r, const bls12381_fp* a, const bls12381_fp* b); void ctt_bls12381_fp_add_in_place(bls12381_fp* a, const bls12381_fp* b); void ctt_bls12381_fp_diff(bls12381_fp* r, const bls12381_fp* a, const bls12381_fp* b); @@ -108,7 +114,6 @@ void ctt_bls12381_fp_cset_one(bls12381_fp* a, const secret_bool ctl); void ctt_bls12381_fp_cneg_in_place(bls12381_fp* a, const secret_bool ctl); void ctt_bls12381_fp_cadd_in_place(bls12381_fp* a, const bls12381_fp* b, const secret_bool ctl); void ctt_bls12381_fp_csub_in_place(bls12381_fp* a, const bls12381_fp* b, const secret_bool ctl); - secret_bool ctt_bls12381_fp_is_square(const bls12381_fp* a); void ctt_bls12381_fp_invsqrt(bls12381_fp* r, const bls12381_fp* a); secret_bool ctt_bls12381_fp_invsqrt_in_place(bls12381_fp* r, const bls12381_fp* a); @@ -117,7 +122,6 @@ secret_bool ctt_bls12381_fp_sqrt_if_square_in_place(bls12381_fp* a); void ctt_bls12381_fp_sqrt_invsqrt(bls12381_fp* sqrt, bls12381_fp* invsqrt, const bls12381_fp* a); secret_bool ctt_bls12381_fp_sqrt_invsqrt_if_square(bls12381_fp* sqrt, bls12381_fp* invsqrt, const bls12381_fp* a); secret_bool ctt_bls12381_fp_sqrt_ratio_if_square(bls12381_fp* r, const bls12381_fp* u, const bls12381_fp* v); - secret_bool ctt_bls12381_fp2_is_eq(const bls12381_fp2* a, const bls12381_fp2* b); secret_bool ctt_bls12381_fp2_is_zero(const bls12381_fp2* a); secret_bool ctt_bls12381_fp2_is_one(const bls12381_fp2* a); @@ -149,11 +153,9 @@ void ctt_bls12381_fp2_cset_one(bls12381_fp2* a, const secret_bool ctl); void ctt_bls12381_fp2_cneg_in_place(bls12381_fp2* a, const secret_bool ctl); void ctt_bls12381_fp2_cadd_in_place(bls12381_fp2* a, const bls12381_fp2* b, const secret_bool ctl); void ctt_bls12381_fp2_csub_in_place(bls12381_fp2* a, const bls12381_fp2* b, const secret_bool ctl); - secret_bool ctt_bls12381_fp2_is_square(const bls12381_fp2* a); void ctt_bls12381_fp2_sqrt_in_place(bls12381_fp2* a); secret_bool ctt_bls12381_fp2_sqrt_if_square_in_place(bls12381_fp2* a); - secret_bool ctt_bls12381_ec_g1_aff_is_eq(const bls12381_ec_g1_aff* P, const bls12381_ec_g1_aff* Q); secret_bool ctt_bls12381_ec_g1_aff_is_inf(const bls12381_ec_g1_aff* P); void ctt_bls12381_ec_g1_aff_set_inf(bls12381_ec_g1_aff* P); @@ -161,7 +163,6 @@ void ctt_bls12381_ec_g1_aff_ccopy(bls12381_ec_g1_aff* P, const bls12381_e secret_bool ctt_bls12381_ec_g1_aff_is_on_curve(const bls12381_fp* x, const bls12381_fp* y); void ctt_bls12381_ec_g1_aff_neg(bls12381_ec_g1_aff* P, const bls12381_ec_g1_aff* Q); void ctt_bls12381_ec_g1_aff_neg_in_place(bls12381_ec_g1_aff* P); - secret_bool ctt_bls12381_ec_g1_jac_is_eq(const bls12381_ec_g1_jac* P, const bls12381_ec_g1_jac* Q); secret_bool ctt_bls12381_ec_g1_jac_is_inf(const bls12381_ec_g1_jac* P); void ctt_bls12381_ec_g1_jac_set_inf(bls12381_ec_g1_jac* P); @@ -176,7 +177,6 @@ void ctt_bls12381_ec_g1_jac_double(bls12381_ec_g1_jac* r, const bls12381_ void ctt_bls12381_ec_g1_jac_double_in_place(bls12381_ec_g1_jac* P); void ctt_bls12381_ec_g1_jac_affine(bls12381_ec_g1_aff* dst, const bls12381_ec_g1_jac* src); void ctt_bls12381_ec_g1_jac_from_affine(bls12381_ec_g1_jac* dst, const bls12381_ec_g1_aff* src); - secret_bool ctt_bls12381_ec_g1_prj_is_eq(const bls12381_ec_g1_prj* P, const bls12381_ec_g1_prj* Q); secret_bool ctt_bls12381_ec_g1_prj_is_inf(const bls12381_ec_g1_prj* P); void ctt_bls12381_ec_g1_prj_set_inf(bls12381_ec_g1_prj* P); @@ -191,7 +191,6 @@ void ctt_bls12381_ec_g1_prj_double(bls12381_ec_g1_prj* r, const bls12381_ void ctt_bls12381_ec_g1_prj_double_in_place(bls12381_ec_g1_prj* P); void ctt_bls12381_ec_g1_prj_affine(bls12381_ec_g1_aff* dst, const bls12381_ec_g1_prj* src); void ctt_bls12381_ec_g1_prj_from_affine(bls12381_ec_g1_prj* dst, const bls12381_ec_g1_aff* src); - secret_bool ctt_bls12381_ec_g2_aff_is_eq(const bls12381_ec_g2_aff* P, const bls12381_ec_g2_aff* Q); secret_bool ctt_bls12381_ec_g2_aff_is_inf(const bls12381_ec_g2_aff* P); void ctt_bls12381_ec_g2_aff_set_inf(bls12381_ec_g2_aff* P); @@ -199,7 +198,6 @@ void ctt_bls12381_ec_g2_aff_ccopy(bls12381_ec_g2_aff* P, const bls12381_e secret_bool ctt_bls12381_ec_g2_aff_is_on_curve(const bls12381_fp2* x, const bls12381_fp2* y); void ctt_bls12381_ec_g2_aff_neg(bls12381_ec_g2_aff* P, const bls12381_ec_g2_aff* Q); void ctt_bls12381_ec_g2_aff_neg_in_place(bls12381_ec_g2_aff* P); - secret_bool ctt_bls12381_ec_g2_jac_is_eq(const bls12381_ec_g2_jac* P, const bls12381_ec_g2_jac* Q); secret_bool ctt_bls12381_ec_g2_jac_is_inf(const bls12381_ec_g2_jac* P); void ctt_bls12381_ec_g2_jac_set_inf(bls12381_ec_g2_jac* P); @@ -214,7 +212,6 @@ void ctt_bls12381_ec_g2_jac_double(bls12381_ec_g2_jac* r, const bls12381_ void ctt_bls12381_ec_g2_jac_double_in_place(bls12381_ec_g2_jac* P); void ctt_bls12381_ec_g2_jac_affine(bls12381_ec_g2_aff* dst, const bls12381_ec_g2_jac* src); void ctt_bls12381_ec_g2_jac_from_affine(bls12381_ec_g2_jac* dst, const bls12381_ec_g2_aff* src); - secret_bool ctt_bls12381_ec_g2_prj_is_eq(const bls12381_ec_g2_prj* P, const bls12381_ec_g2_prj* Q); secret_bool ctt_bls12381_ec_g2_prj_is_inf(const bls12381_ec_g2_prj* P); void ctt_bls12381_ec_g2_prj_set_inf(bls12381_ec_g2_prj* P); @@ -230,14 +227,6 @@ void ctt_bls12381_ec_g2_prj_double_in_place(bls12381_ec_g2_prj* P); void ctt_bls12381_ec_g2_prj_affine(bls12381_ec_g2_aff* dst, const bls12381_ec_g2_prj* src); void ctt_bls12381_ec_g2_prj_from_affine(bls12381_ec_g2_prj* dst, const bls12381_ec_g2_aff* src); -/* - * Initializes the library: - * - the Nim runtime if heap-allocated types are used, - * this is the case only if Constantine is multithreaded. - * - runtime CPU features detection - */ -void ctt_bls12381_NimMain(void); - #ifdef __cplusplus } diff --git a/bindings/generated/constantine_pasta.h b/bindings/generated/constantine_pasta.h index 4b4c6cd..b007918 100644 --- a/bindings/generated/constantine_pasta.h +++ b/bindings/generated/constantine_pasta.h @@ -14,7 +14,7 @@ extern "C" { #endif -#if defined{__SIZE_TYPE__} && defined(__PTRDIFF_TYPE__) +#if defined(__SIZE_TYPE__) && defined(__PTRDIFF_TYPE__) typedef __SIZE_TYPE__ size_t; typedef __PTRDIFF_TYPE__ ptrdiff_t; #else @@ -47,6 +47,11 @@ typedef struct { vesta_fp x, y; } vesta_ec_aff; typedef struct { vesta_fp x, y, z; } vesta_ec_jac; typedef struct { vesta_fp x, y, z; } vesta_ec_prj; +/* + * Initializes the library: + * - detect CPU features like ADX instructions support (MULX, ADCX, ADOX) + */ +void ctt_pasta_init_NimMain(void); void ctt_pallas_fr_unmarshalBE(pallas_fr* dst, const byte src[], ptrdiff_t src_len); void ctt_pallas_fr_marshalBE(byte dst[], ptrdiff_t dst_len, const pallas_fr* src); @@ -57,7 +62,8 @@ secret_bool ctt_pallas_fr_is_minus_one(const pallas_fr* a); void ctt_pallas_fr_set_zero(pallas_fr* a); void ctt_pallas_fr_set_one(pallas_fr* a); void ctt_pallas_fr_set_minus_one(pallas_fr* a); -void ctt_pallas_fr_neg(pallas_fr* a); +void ctt_pallas_fr_neg(pallas_fr* r, const pallas_fr* a); +void ctt_pallas_fr_neg_in_place(pallas_fr* a); void ctt_pallas_fr_sum(pallas_fr* r, const pallas_fr* a, const pallas_fr* b); void ctt_pallas_fr_add_in_place(pallas_fr* a, const pallas_fr* b); void ctt_pallas_fr_diff(pallas_fr* r, const pallas_fr* a, const pallas_fr* b); @@ -78,7 +84,6 @@ void ctt_pallas_fr_cset_one(pallas_fr* a, const secret_bool ctl); void ctt_pallas_fr_cneg_in_place(pallas_fr* a, const secret_bool ctl); void ctt_pallas_fr_cadd_in_place(pallas_fr* a, const pallas_fr* b, const secret_bool ctl); void ctt_pallas_fr_csub_in_place(pallas_fr* a, const pallas_fr* b, const secret_bool ctl); - void ctt_pallas_fp_unmarshalBE(pallas_fp* dst, const byte src[], ptrdiff_t src_len); void ctt_pallas_fp_marshalBE(byte dst[], ptrdiff_t dst_len, const pallas_fp* src); secret_bool ctt_pallas_fp_is_eq(const pallas_fp* a, const pallas_fp* b); @@ -88,7 +93,8 @@ secret_bool ctt_pallas_fp_is_minus_one(const pallas_fp* a); void ctt_pallas_fp_set_zero(pallas_fp* a); void ctt_pallas_fp_set_one(pallas_fp* a); void ctt_pallas_fp_set_minus_one(pallas_fp* a); -void ctt_pallas_fp_neg(pallas_fp* a); +void ctt_pallas_fp_neg(pallas_fp* r, const pallas_fp* a); +void ctt_pallas_fp_neg_in_place(pallas_fp* a); void ctt_pallas_fp_sum(pallas_fp* r, const pallas_fp* a, const pallas_fp* b); void ctt_pallas_fp_add_in_place(pallas_fp* a, const pallas_fp* b); void ctt_pallas_fp_diff(pallas_fp* r, const pallas_fp* a, const pallas_fp* b); @@ -109,7 +115,6 @@ void ctt_pallas_fp_cset_one(pallas_fp* a, const secret_bool ctl); void ctt_pallas_fp_cneg_in_place(pallas_fp* a, const secret_bool ctl); void ctt_pallas_fp_cadd_in_place(pallas_fp* a, const pallas_fp* b, const secret_bool ctl); void ctt_pallas_fp_csub_in_place(pallas_fp* a, const pallas_fp* b, const secret_bool ctl); - secret_bool ctt_pallas_fp_is_square(const pallas_fp* a); void ctt_pallas_fp_invsqrt(pallas_fp* r, const pallas_fp* a); secret_bool ctt_pallas_fp_invsqrt_in_place(pallas_fp* r, const pallas_fp* a); @@ -118,7 +123,6 @@ secret_bool ctt_pallas_fp_sqrt_if_square_in_place(pallas_fp* a); void ctt_pallas_fp_sqrt_invsqrt(pallas_fp* sqrt, pallas_fp* invsqrt, const pallas_fp* a); secret_bool ctt_pallas_fp_sqrt_invsqrt_if_square(pallas_fp* sqrt, pallas_fp* invsqrt, const pallas_fp* a); secret_bool ctt_pallas_fp_sqrt_ratio_if_square(pallas_fp* r, const pallas_fp* u, const pallas_fp* v); - void ctt_vesta_fr_unmarshalBE(vesta_fr* dst, const byte src[], ptrdiff_t src_len); void ctt_vesta_fr_marshalBE(byte dst[], ptrdiff_t dst_len, const vesta_fr* src); secret_bool ctt_vesta_fr_is_eq(const vesta_fr* a, const vesta_fr* b); @@ -128,7 +132,8 @@ secret_bool ctt_vesta_fr_is_minus_one(const vesta_fr* a); void ctt_vesta_fr_set_zero(vesta_fr* a); void ctt_vesta_fr_set_one(vesta_fr* a); void ctt_vesta_fr_set_minus_one(vesta_fr* a); -void ctt_vesta_fr_neg(vesta_fr* a); +void ctt_vesta_fr_neg(vesta_fr* r, const vesta_fr* a); +void ctt_vesta_fr_neg_in_place(vesta_fr* a); void ctt_vesta_fr_sum(vesta_fr* r, const vesta_fr* a, const vesta_fr* b); void ctt_vesta_fr_add_in_place(vesta_fr* a, const vesta_fr* b); void ctt_vesta_fr_diff(vesta_fr* r, const vesta_fr* a, const vesta_fr* b); @@ -149,7 +154,6 @@ void ctt_vesta_fr_cset_one(vesta_fr* a, const secret_bool ctl); void ctt_vesta_fr_cneg_in_place(vesta_fr* a, const secret_bool ctl); void ctt_vesta_fr_cadd_in_place(vesta_fr* a, const vesta_fr* b, const secret_bool ctl); void ctt_vesta_fr_csub_in_place(vesta_fr* a, const vesta_fr* b, const secret_bool ctl); - void ctt_vesta_fp_unmarshalBE(vesta_fp* dst, const byte src[], ptrdiff_t src_len); void ctt_vesta_fp_marshalBE(byte dst[], ptrdiff_t dst_len, const vesta_fp* src); secret_bool ctt_vesta_fp_is_eq(const vesta_fp* a, const vesta_fp* b); @@ -159,7 +163,8 @@ secret_bool ctt_vesta_fp_is_minus_one(const vesta_fp* a); void ctt_vesta_fp_set_zero(vesta_fp* a); void ctt_vesta_fp_set_one(vesta_fp* a); void ctt_vesta_fp_set_minus_one(vesta_fp* a); -void ctt_vesta_fp_neg(vesta_fp* a); +void ctt_vesta_fp_neg(vesta_fp* r, const vesta_fp* a); +void ctt_vesta_fp_neg_in_place(vesta_fp* a); void ctt_vesta_fp_sum(vesta_fp* r, const vesta_fp* a, const vesta_fp* b); void ctt_vesta_fp_add_in_place(vesta_fp* a, const vesta_fp* b); void ctt_vesta_fp_diff(vesta_fp* r, const vesta_fp* a, const vesta_fp* b); @@ -180,7 +185,6 @@ void ctt_vesta_fp_cset_one(vesta_fp* a, const secret_bool ctl); void ctt_vesta_fp_cneg_in_place(vesta_fp* a, const secret_bool ctl); void ctt_vesta_fp_cadd_in_place(vesta_fp* a, const vesta_fp* b, const secret_bool ctl); void ctt_vesta_fp_csub_in_place(vesta_fp* a, const vesta_fp* b, const secret_bool ctl); - secret_bool ctt_vesta_fp_is_square(const vesta_fp* a); void ctt_vesta_fp_invsqrt(vesta_fp* r, const vesta_fp* a); secret_bool ctt_vesta_fp_invsqrt_in_place(vesta_fp* r, const vesta_fp* a); @@ -189,7 +193,6 @@ secret_bool ctt_vesta_fp_sqrt_if_square_in_place(vesta_fp* a); void ctt_vesta_fp_sqrt_invsqrt(vesta_fp* sqrt, vesta_fp* invsqrt, const vesta_fp* a); secret_bool ctt_vesta_fp_sqrt_invsqrt_if_square(vesta_fp* sqrt, vesta_fp* invsqrt, const vesta_fp* a); secret_bool ctt_vesta_fp_sqrt_ratio_if_square(vesta_fp* r, const vesta_fp* u, const vesta_fp* v); - secret_bool ctt_pallas_ec_aff_is_eq(const pallas_ec_aff* P, const pallas_ec_aff* Q); secret_bool ctt_pallas_ec_aff_is_inf(const pallas_ec_aff* P); void ctt_pallas_ec_aff_set_inf(pallas_ec_aff* P); @@ -197,7 +200,6 @@ void ctt_pallas_ec_aff_ccopy(pallas_ec_aff* P, const pallas_ec_aff* Q, co secret_bool ctt_pallas_ec_aff_is_on_curve(const pallas_fp* x, const pallas_fp* y); void ctt_pallas_ec_aff_neg(pallas_ec_aff* P, const pallas_ec_aff* Q); void ctt_pallas_ec_aff_neg_in_place(pallas_ec_aff* P); - secret_bool ctt_pallas_ec_jac_is_eq(const pallas_ec_jac* P, const pallas_ec_jac* Q); secret_bool ctt_pallas_ec_jac_is_inf(const pallas_ec_jac* P); void ctt_pallas_ec_jac_set_inf(pallas_ec_jac* P); @@ -212,7 +214,6 @@ void ctt_pallas_ec_jac_double(pallas_ec_jac* r, const pallas_ec_jac* P); void ctt_pallas_ec_jac_double_in_place(pallas_ec_jac* P); void ctt_pallas_ec_jac_affine(pallas_ec_aff* dst, const pallas_ec_jac* src); void ctt_pallas_ec_jac_from_affine(pallas_ec_jac* dst, const pallas_ec_aff* src); - secret_bool ctt_pallas_ec_prj_is_eq(const pallas_ec_prj* P, const pallas_ec_prj* Q); secret_bool ctt_pallas_ec_prj_is_inf(const pallas_ec_prj* P); void ctt_pallas_ec_prj_set_inf(pallas_ec_prj* P); @@ -227,7 +228,6 @@ void ctt_pallas_ec_prj_double(pallas_ec_prj* r, const pallas_ec_prj* P); void ctt_pallas_ec_prj_double_in_place(pallas_ec_prj* P); void ctt_pallas_ec_prj_affine(pallas_ec_aff* dst, const pallas_ec_prj* src); void ctt_pallas_ec_prj_from_affine(pallas_ec_prj* dst, const pallas_ec_aff* src); - secret_bool ctt_vesta_ec_aff_is_eq(const vesta_ec_aff* P, const vesta_ec_aff* Q); secret_bool ctt_vesta_ec_aff_is_inf(const vesta_ec_aff* P); void ctt_vesta_ec_aff_set_inf(vesta_ec_aff* P); @@ -235,7 +235,6 @@ void ctt_vesta_ec_aff_ccopy(vesta_ec_aff* P, const vesta_ec_aff* Q, const secret_bool ctt_vesta_ec_aff_is_on_curve(const pallas_fp* x, const pallas_fp* y); void ctt_vesta_ec_aff_neg(vesta_ec_aff* P, const vesta_ec_aff* Q); void ctt_vesta_ec_aff_neg_in_place(vesta_ec_aff* P); - secret_bool ctt_vesta_ec_jac_is_eq(const vesta_ec_jac* P, const vesta_ec_jac* Q); secret_bool ctt_vesta_ec_jac_is_inf(const vesta_ec_jac* P); void ctt_vesta_ec_jac_set_inf(vesta_ec_jac* P); @@ -250,7 +249,6 @@ void ctt_vesta_ec_jac_double(vesta_ec_jac* r, const vesta_ec_jac* P); void ctt_vesta_ec_jac_double_in_place(vesta_ec_jac* P); void ctt_vesta_ec_jac_affine(vesta_ec_aff* dst, const vesta_ec_jac* src); void ctt_vesta_ec_jac_from_affine(vesta_ec_jac* dst, const vesta_ec_aff* src); - secret_bool ctt_vesta_ec_prj_is_eq(const vesta_ec_prj* P, const vesta_ec_prj* Q); secret_bool ctt_vesta_ec_prj_is_inf(const vesta_ec_prj* P); void ctt_vesta_ec_prj_set_inf(vesta_ec_prj* P); @@ -266,14 +264,6 @@ void ctt_vesta_ec_prj_double_in_place(vesta_ec_prj* P); void ctt_vesta_ec_prj_affine(vesta_ec_aff* dst, const vesta_ec_prj* src); void ctt_vesta_ec_prj_from_affine(vesta_ec_prj* dst, const vesta_ec_aff* src); -/* - * Initializes the library: - * - the Nim runtime if heap-allocated types are used, - * this is the case only if Constantine is multithreaded. - * - runtime CPU features detection - */ -void ctt_pasta_NimMain(void); - #ifdef __cplusplus } diff --git a/constantine.nimble b/constantine.nimble index b948498..493dd59 100644 --- a/constantine.nimble +++ b/constantine.nimble @@ -327,7 +327,7 @@ template setupBench(): untyped {.dirty.} = cc &= " -d:CttASM=false" let command = "nim " & lang & cc & " -d:danger --verbosity:0 -o:build/bench/" & benchName & "_" & compiler & "_" & (if useAsm: "useASM" else: "noASM") & - " --nimcache:nimcache/" & benchName & "_" & compiler & "_" & (if useAsm: "useASM" else: "noASM") & + " --nimcache:nimcache/benches/" & benchName & "_" & compiler & "_" & (if useAsm: "useASM" else: "noASM") & runFlag & "--hints:off --warnings:off benchmarks/" & benchName & ".nim" proc runBench(benchName: string, compiler = "", useAsm = true) = @@ -369,7 +369,7 @@ proc addBenchSet(cmdFile: var string, useAsm = true) = for bd in benchDesc: cmdFile.buildBenchBatch(bd, useASM = useASM) -proc genBindings(bindingsName, prefixNimMain: string) = +proc genDynamicBindings(bindingsName, prefixNimMain: string) = proc compile(libName: string, flags = "") = # -d:danger to avoid boundsCheck, overflowChecks that would trigger exceptions or allocations in a crypto library. # Those are internally guaranteed at compile-time by fixed-sized array @@ -378,7 +378,9 @@ proc genBindings(bindingsName, prefixNimMain: string) = # In the future, Constantine might use: # - heap-allocated sequences and objects manually managed or managed by destructors for multithreading. # - heap-allocated strings for hex-string or decimal strings + echo "Compiling dynamic library: bindings/generated/" & libName exec "nim c -f " & flags & " --noMain -d:danger --app:lib --gc:arc " & + " --verbosity:0 --hints:off --warnings:off " & " --nimMainPrefix:" & prefixNimMain & " --out:" & libName & " --outdir:bindings/generated " & " --nimcache:nimcache/bindings/" & bindingsName & @@ -397,11 +399,44 @@ proc genBindings(bindingsName, prefixNimMain: string) = else: compile "lib" & bindingsName & ".so" +proc genStaticBindings(bindingsName, prefixNimMain: string) = + proc compile(libName: string, flags = "") = + # -d:danger to avoid boundsCheck, overflowChecks that would trigger exceptions or allocations in a crypto library. + # Those are internally guaranteed at compile-time by fixed-sized array + # and checked at runtime with an appropriate error code if any for user-input. + # -gc:arc Constantine stack allocates everything. Inputs are through unmanaged ptr+len. + # In the future, Constantine might use: + # - heap-allocated sequences and objects manually managed or managed by destructors for multithreading. + # - heap-allocated strings for hex-string or decimal strings + echo "Compiling static library: bindings/generated/" & libName + exec "nim c -f " & flags & " --noMain -d:danger --app:staticLib --gc:arc " & + " --verbosity:0 --hints:off --warnings:off " & + " --nimMainPrefix:" & prefixNimMain & + " --out:" & libName & " --outdir:bindings/generated " & + " --nimcache:nimcache/bindings/" & bindingsName & + " bindings/" & bindingsName & ".nim" + + when defined(windows): + compile bindingsName & ".lib" + + elif defined(macosx): + compile "lib" & bindingsName & ".a.arm", "--cpu:arm64 -l:'-target arm64-apple-macos11' -t:'-target arm64-apple-macos11'" + compile "lib" & bindingsName & ".a.x64", "--cpu:amd64 -l:'-target x86_64-apple-macos10.12' -t:'-target x86_64-apple-macos10.12'" + exec "lipo bindings/generated/lib" & bindingsName & ".a.arm " & + " bindings/generated/lib" & bindingsName & ".a.x64 " & + " -output bindings/generated/lib" & bindingsName & ".a -create" + + else: + compile "lib" & bindingsName & ".a" + proc genHeaders(bindingsName: string) = - exec "nim c -r -d:release -d:CttGenerateHeaders " & + echo "Generating header: bindings/generated/" & bindingsName & ".h" + exec "nim c -d:release -d:CttGenerateHeaders " & + " --verbosity:0 --hints:off --warnings:off " & " --out:" & bindingsName & "_gen_header.exe --outdir:bindings/generated " & " --nimcache:nimcache/bindings/" & bindingsName & "_header" & " bindings/" & bindingsName & ".nim" + exec "bindings/generated/" & bindingsName & "_gen_header.exe bindings/generated" proc genParallelCmdRunner() = exec "nim c --verbosity:0 --hints:off --warnings:off -d:release --out:build/pararun --nimcache:nimcache/pararun helpers/pararun.nim" @@ -410,11 +445,37 @@ proc genParallelCmdRunner() = # ---------------------------------------------------------------- task bindings, "Generate Constantine bindings": - genBindings("constantine_bls12_381", "ctt_bls12381_") + genDynamicBindings("constantine_bls12_381", "ctt_bls12381_init_") + genStaticBindings("constantine_bls12_381", "ctt_bls12381_init_") genHeaders("constantine_bls12_381") - genBindings("constantine_pasta", "ctt_pasta_") + echo "" + genDynamicBindings("constantine_pasta", "ctt_pasta_init_") + genStaticBindings("constantine_pasta", "ctt_pasta_init_") genHeaders("constantine_pasta") +task test_bindings, "Test C bindings": + exec "mkdir -p build/testsuite" + echo "--> Testing dynamically linked library" + when not defined(windows): + exec "gcc -Ibindings/generated -Lbindings/generated -o build/testsuite/t_libctt_bls12_381_dl tests/bindings/t_libctt_bls12_381.c -lgmp -lconstantine_bls12_381" + exec "LD_LIBRARY_PATH=bindings/generated ./build/testsuite/t_libctt_bls12_381_dl" + else: + # Put DLL near the exe as LD_LIBRARY_PATH doesn't work even in an POSIX compatible shell + exec "gcc -Ibindings/generated -Lbindings/generated -o build/testsuite/t_libctt_bls12_381_dl.exe tests/bindings/t_libctt_bls12_381.c -lgmp -lconstantine_bls12_381" + exec "./build/testsuite/t_libctt_bls12_381_dl.exe" + + echo "--> Testing statically linked library" + when not defined(windows): + # Beware MacOS annoying linker with regards to static libraries + # The following standard way cannot be used on MacOS + # exec "gcc -Ibindings/generated -Lbindings/generated -o build/t_libctt_bls12_381_sl.exe tests/bindings/t_libctt_bls12_381.c -lgmp -Wl,-Bstatic -lconstantine_bls12_381 -Wl,-Bdynamic" + + exec "gcc -Ibindings/generated -o build/testsuite/t_libctt_bls12_381_sl tests/bindings/t_libctt_bls12_381.c bindings/generated/libconstantine_bls12_381.a -lgmp" + exec "./build/testsuite/t_libctt_bls12_381_sl" + else: + exec "gcc -Ibindings/generated -o build/testsuite/t_libctt_bls12_381_sl.exe tests/bindings/t_libctt_bls12_381.c bindings/generated/constantine_bls12_381.lib -lgmp" + exec "./build/testsuite/t_libctt_bls12_381_sl.exe" + task test, "Run all tests": # -d:testingCurves is configured in a *.nim.cfg for convenience var cmdFile: string diff --git a/constantine/curves_primitives.nim b/constantine/curves_primitives.nim index 9603980..740b641 100644 --- a/constantine/curves_primitives.nim +++ b/constantine/curves_primitives.nim @@ -13,8 +13,8 @@ import ec_shortweierstrass, extension_fields, arithmetic, - curves/zoo_subgroups, - curves/zoo_generators + constants/zoo_subgroups, + constants/zoo_generators ], ./math/io/[io_bigints, io_fields], ./math/isogenies/frobenius, diff --git a/tests/bindings/t_libctt_bls12_381.c b/tests/bindings/t_libctt_bls12_381.c new file mode 100644 index 0000000..8f9692d --- /dev/null +++ b/tests/bindings/t_libctt_bls12_381.c @@ -0,0 +1,247 @@ +// Constantine +// Copyright (c) 2018-2019 Status Research & Development GmbH +// Copyright (c) 2020-Present Mamy André-Ratsimbazafy +// Licensed and distributed under either of +// * MIT license (license terms in the root directory or at http://opensource.org/licenses/MIT). +// * Apache v2 license (license terms in the root directory or at http://www.apache.org/licenses/LICENSE-2.0). +// at your option. This file may not be copied, modified, or distributed except according to those terms. + +#include +#include +#include +#include +#include + +typedef unsigned char byte; + +// https://gmplib.org/manual/Integer-Import-and-Export.html +const int GMP_WordLittleEndian = -1; +const int GMP_WordNativeEndian = 0; +const int GMP_WordBigEndian = 1; + +const int GMP_MostSignificantWordFirst = 1; +const int GMP_LeastSignificantWordFirst = -1; + +#define Curve "BLS12_381" +#define BitLength 381 +#define ByteLength ((BitLength + 7) / 8) +#define Modulus "0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaaab" +#define Iter 24 + +void prologue( + gmp_randstate_t gmp_rng, + mpz_ptr a, mpz_ptr b, + mpz_ptr p, + bls12381_fp* a_ctt, bls12381_fp* b_ctt, + byte a_buf[ByteLength], byte b_buf[ByteLength]) { + + // Generate random value in the range 0 ..< 2^(bits-1) + mpz_urandomb(a, gmp_rng, BitLength); + mpz_urandomb(b, gmp_rng, BitLength); + + // Set modulus to curve modulus + mpz_set_str(p, Modulus, 0); + + // GMP -> Constantine + size_t aW, bW; + mpz_export(a_buf, &aW, GMP_MostSignificantWordFirst, 1, GMP_WordNativeEndian, 0, a); + mpz_export(b_buf, &bW, GMP_MostSignificantWordFirst, 1, GMP_WordNativeEndian, 0, b); + + assert(ByteLength >= aW); + assert(ByteLength >= bW); + + ctt_bls12381_fp_unmarshalBE(a_ctt, a_buf, aW); + ctt_bls12381_fp_unmarshalBE(b_ctt, b_buf, bW); +} + +void dump_hex(byte a[ByteLength]){ + printf("0x"); + for (int i = 0; i < ByteLength; ++i){ + printf("%.02x", a[i]); + } +} + +void epilogue( + mpz_ptr r, mpz_ptr a, mpz_ptr b, + bls12381_fp* r_ctt, bls12381_fp* a_ctt, bls12381_fp* b_ctt, + char* operation) { + + byte r_raw_gmp[ByteLength]; + byte r_raw_ctt[ByteLength]; + + // GMP -> Raw + size_t rW; // number of words written + mpz_export(r_raw_gmp, &rW, GMP_MostSignificantWordFirst, 1, GMP_WordNativeEndian, 0, r); + + // Constantine -> Raw + ctt_bls12381_fp_marshalBE(r_raw_ctt, ByteLength, r_ctt); + + // Check + for (int g = 0, c = ByteLength-rW; g < rW; g+=1, c+=1) { + if (r_raw_gmp[g] != r_raw_ctt[c]) { + // reexport for debugging + byte a_buf[ByteLength], b_buf[ByteLength]; + size_t aW, bW; + mpz_export(a_buf, &aW, GMP_MostSignificantWordFirst, 1, GMP_WordNativeEndian, 0, a); + mpz_export(b_buf, &bW, GMP_MostSignificantWordFirst, 1, GMP_WordNativeEndian, 0, b); + printf("\nModular %s on curve %s with operands", operation, Curve); + printf("\n a: "); dump_hex(a_buf); + printf("\n b: "); dump_hex(b_buf); + printf("\nfailed:"); + printf("\n GMP: "); dump_hex(r_raw_gmp); + printf("\n Constantine: "); dump_hex(r_raw_ctt); + printf("\n(Note that GMP aligns bytes left while constantine aligns bytes right)\n"); + exit(1); + } + } + printf("."); +} + +int main(){ + + // Initialize the runtime. For Constantine, it populates CPU runtime detection dispatch. + ctt_bls12381_init_NimMain(); + + gmp_randstate_t gmpRng; + gmp_randinit_mt(gmpRng); + // The GMP seed varies between run so that + // test coverage increases as the library gets tested. + // This requires to dump the seed in the console or the function inputs + // to be able to reproduce a bug + int seed = 0xDEADBEEF; + printf("GMP seed: 0x%.04x\n", seed); + gmp_randseed_ui(gmpRng, seed); + + mpz_t a, b, p, r; + mpz_init(a); + mpz_init(b); + mpz_init(p); + mpz_init(r); + + bls12381_fp a_ctt, b_ctt, r_ctt; + byte a_buf[ByteLength], b_buf[ByteLength]; + + for (int i = 0; i < Iter; ++i){ + prologue( + gmpRng, + a, b, p, + &a_ctt, &b_ctt, + a_buf, b_buf + ); + + mpz_neg(r, a); + mpz_mod(r, r, p); + ctt_bls12381_fp_neg(&r_ctt, &a_ctt); + + epilogue( + r, a, b, + &r_ctt, &a_ctt, &b_ctt, + "negation" + ); + } + printf(" SUCCESS negation\n"); + + for (int i = 0; i < Iter; ++i){ + prologue( + gmpRng, + a, b, p, + &a_ctt, &b_ctt, + a_buf, b_buf + ); + + mpz_add(r, a, b); + mpz_mod(r, r, p); + ctt_bls12381_fp_sum(&r_ctt, &a_ctt, &b_ctt); + + epilogue( + r, a, b, + &r_ctt, &a_ctt, &b_ctt, + "addition" + ); + } + printf(" SUCCESS addition\n"); + + for (int i = 0; i < Iter; ++i){ + prologue( + gmpRng, + a, b, p, + &a_ctt, &b_ctt, + a_buf, b_buf + ); + + mpz_mul(r, a, b); + mpz_mod(r, r, p); + ctt_bls12381_fp_prod(&r_ctt, &a_ctt, &b_ctt); + + epilogue( + r, a, b, + &r_ctt, &a_ctt, &b_ctt, + "multiplication" + ); + } + printf(" SUCCESS multiplication\n"); + + for (int i = 0; i < Iter; ++i){ + prologue( + gmpRng, + a, b, p, + &a_ctt, &b_ctt, + a_buf, b_buf + ); + + mpz_invert(r, a, p); + ctt_bls12381_fp_inv(&r_ctt, &a_ctt); + + epilogue( + r, a, b, + &r_ctt, &a_ctt, &b_ctt, + "inversion" + ); + } + printf(" SUCCESS inversion\n"); + + for (int i = 0; i < Iter; ++i){ + prologue( + gmpRng, + a, b, p, + &a_ctt, &b_ctt, + a_buf, b_buf + ); + + int is_square_gmp = mpz_legendre(a, p) == -1 ? 0:1; + int is_square_ctt = ctt_bls12381_fp_is_square(&a_ctt); + + assert(is_square_gmp == is_square_ctt); + } + printf(" SUCCESS Legendre symbol / is_square\n"); + + // TODO: THere are a "positive" and "negative" square roots + // for (int i = 0; i < Iter; ++i){ + // prologue( + // gmpRng, + // a, b, p, + // &a_ctt, &b_ctt, + // a_buf, b_buf + // ); + + // if (mpz_congruent_ui_p(p, 3, 4)) { + // // a^((p+1)/4) (mod p) + // mpz_add_ui(b, p, 1); + // mpz_tdiv_q_2exp(b, b, 2); + // mpz_powm(r, a, b, p); + // } else { + // assert(0); + // } + // ctt_bls12381_fp_prod(&r_ctt, &a_ctt, &b_ctt); + + // epilogue( + // r, a, b, + // &r_ctt, &a_ctt, &b_ctt, + // "square root" + // ); + // } + // printf(" SUCCESS square root\n"); + + return 0; + +} \ No newline at end of file