250 lines
6.3 KiB
C
250 lines
6.3 KiB
C
/** 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.
|
|
*/
|
|
|
|
// This is a test to ensure Constantine's modular arithmetic is consistent with GMP.
|
|
// While not intended as a tutorial, it showcases serialization, deserialization and computation.
|
|
|
|
#include <assert.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
|
|
#include <gmp.h>
|
|
#include <constantine_bls12_381.h>
|
|
|
|
// 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;
|
|
|
|
} |