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
This commit is contained in:
Mamy Ratsimbazafy 2022-09-15 17:11:57 +02:00 committed by GitHub
parent 962e7ccf49
commit df048112c3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 403 additions and 93 deletions

View File

@ -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

View File

@ -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} <optional directory to save header to>"
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()

View File

@ -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} <optional directory to save header to>"
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()

View File

@ -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) =

View File

@ -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);
"""

View File

@ -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
}

View File

@ -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
}

View File

@ -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

View File

@ -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,

View File

@ -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 <assert.h>
#include <gmp.h>
#include <constantine_bls12_381.h>
#include <stdio.h>
#include <stdlib.h>
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;
}