#include void signature_init(signature_t *sig) { id2iso_compressed_long_two_isog_init(&sig->zip, SQISIGN_signing_length); } void signature_finalize(signature_t *sig) { id2iso_compressed_long_two_isog_finalize(&sig->zip); } void protocols_commit(quat_left_ideal_t *ideal, ec_curve_t *E1, ec_basis_t *basis) { ibz_vec_2_t vec; ibz_vec_2_init(&vec); ibz_t tmp; ibz_init(&tmp); // sample the random scalars do { ibz_rand_interval(&vec[0], &ibz_const_one, &DEGREE_COMMITMENT); ibz_rand_interval(&vec[1], &ibz_const_one, &DEGREE_COMMITMENT); ibz_gcd(&tmp, &vec[0], &vec[1]); ibz_gcd(&tmp, &tmp, &DEGREE_COMMITMENT); } while (!ibz_is_one(&tmp)); // deduce the commitment ideal { quat_alg_elem_t gen; quat_alg_elem_init(&gen); ibz_set(&gen.denom, 1); for (unsigned i = 0; i < 4; ++i) { ibz_mul(&gen.coord[i], &COMMITMENT_IDEAL_DISTORTION_ENDO.coord[i], &vec[1]); if (i) ibz_neg(&gen.coord[i], &gen.coord[i]); // conjugate } ibz_add(&gen.coord[0], &gen.coord[0], &vec[0]); // now gen = a + b*dual(theta) where vec=(a,b) and theta is the distortion map quat_alg_mul(&gen, &COMMITMENT_IDEAL_UNDISTORTED_GEN, &gen, &QUATALG_PINFTY); #ifndef NDEBUG quat_alg_coord_t coeffs; ibz_t temp,remainder; quat_alg_coord_init(&coeffs); ibz_init(&temp);ibz_init(&remainder); quat_alg_make_primitive(&coeffs,&temp,&gen,&MAXORD_O0,&QUATALG_PINFTY); ibz_mul(&gen.denom,&gen.denom,&temp); quat_alg_normalize(&gen); assert(quat_alg_is_primitive(&gen,&MAXORD_O0,&QUATALG_PINFTY)); ibq_t ibq_norm; ibq_init(&ibq_norm); quat_alg_norm(&ibq_norm,&gen,&QUATALG_PINFTY); assert(ibq_to_ibz(&temp,&ibq_norm)); ibq_finalize(&ibq_norm); ibz_gcd(&temp,&temp,&DEGREE_COMMITMENT); ibz_div(&temp,&remainder,&temp,&DEGREE_COMMITMENT); assert(0==ibz_cmp(&remainder,&ibz_const_zero)); #endif quat_lideal_make_primitive_then_create(ideal, &gen, &DEGREE_COMMITMENT, &MAXORD_O0, &QUATALG_PINFTY); assert(!ibz_cmp(&ideal->norm, &DEGREE_COMMITMENT)); quat_alg_elem_finalize(&gen); } // deduce the commitment isogeny ec_isog_odd_t isogeny; { isogeny.curve = CURVE_E0; for (size_t i = 0; i < sizeof(TORSION_ODD_PRIMES)/sizeof(*TORSION_ODD_PRIMES); ++i) isogeny.degree[i] = DEGREE_COMMITMENT_POWERS[i]; digit_t scalars_plus[2][NWORDS_FIELD], scalars_minus[2][NWORDS_FIELD]; ibz_mod(&tmp, &vec[0], &DEGREE_COMMITMENT_PLUS); ibz_to_digit_array(scalars_plus[0], &tmp); ibz_mod(&tmp, &vec[1], &DEGREE_COMMITMENT_PLUS); ibz_to_digit_array(scalars_plus[1], &tmp); ibz_mod(&tmp, &vec[0], &DEGREE_COMMITMENT_MINUS); ibz_to_digit_array(scalars_minus[0], &tmp); ibz_mod(&tmp, &vec[1], &DEGREE_COMMITMENT_MINUS); ibz_to_digit_array(scalars_minus[1], &tmp); ec_biscalar_mul(&isogeny.ker_plus, &CURVE_E0, scalars_plus[0], scalars_plus[1], &BASIS_COMMITMENT_PLUS); ec_biscalar_mul(&isogeny.ker_minus, &CURVE_E0, scalars_minus[0], scalars_minus[1], &BASIS_COMMITMENT_MINUS); } ec_curve_t E1comp; ec_eval_odd_basis(&E1comp, &isogeny, basis, 1); // normalize E1 with the pushed basis { ec_isom_t isom; ec_curve_normalize(E1, &isom, &E1comp); ec_iso_eval(&basis->P, &isom); ec_iso_eval(&basis->Q, &isom); ec_iso_eval(&basis->PmQ, &isom); } ibz_finalize(&tmp); ibz_vec_2_finalize(&vec); } void protocols_challenge(quat_left_ideal_t *ideal, signature_t *sig, const ec_curve_t *E1, const ec_basis_t *pushedbasis6, const ibz_vec_2_t *hash, ec_curve_t *out_E2) { // compute deterministic and pushed 2*3*-torsion bases on E1 ec_basis_t E1basis6, E1basis2, E1basis3; ec_basis_t pushedbasis2, pushedbasis3; ec_curve_to_basis_6(&E1basis6, E1); { digit_t scalar[NWORDS_FIELD]; ibz_to_digit_array(scalar, &TORSION_PLUS_3POWER); ec_mul(&E1basis2.P, E1, scalar, &E1basis6.P); ec_mul(&E1basis2.Q, E1, scalar, &E1basis6.Q); ec_mul(&E1basis2.PmQ, E1, scalar, &E1basis6.PmQ); ec_mul(&pushedbasis2.P, E1, scalar, &pushedbasis6->P); ec_mul(&pushedbasis2.Q, E1, scalar, &pushedbasis6->Q); ec_mul(&pushedbasis2.PmQ, E1, scalar, &pushedbasis6->PmQ); ibz_to_digit_array(scalar, &TORSION_PLUS_2POWER); ec_mul(&E1basis3.P, E1, scalar, &E1basis6.P); ec_mul(&E1basis3.Q, E1, scalar, &E1basis6.Q); ec_mul(&E1basis3.PmQ, E1, scalar, &E1basis6.PmQ); ec_mul(&pushedbasis3.P, E1, scalar, &pushedbasis6->P); ec_mul(&pushedbasis3.Q, E1, scalar, &pushedbasis6->Q); ec_mul(&pushedbasis3.PmQ, E1, scalar, &pushedbasis6->PmQ); } // compute the kernel of the challenge isogeny ec_point_t ker; { digit_t scalars[2][NWORDS_FIELD]; ibz_to_digit_array(scalars[0], &(*hash)[0]); ibz_to_digit_array(scalars[1], &(*hash)[1]); ec_biscalar_mul(&ker, E1, scalars[0], scalars[1], &E1basis6); } ec_point_t ker2, ker3; { digit_t scalar[NWORDS_FIELD]; ibz_to_digit_array(scalar, &TORSION_PLUS_3POWER); ec_mul(&ker2, E1, scalar, &ker); ibz_to_digit_array(scalar, &TORSION_PLUS_2POWER); ec_mul(&ker3, E1, scalar, &ker); } // compute ideal corresponding to the challenge isogeny, pulled back to O0 { // compute the logarithm of the kernel with respect to the pushed basis ibz_vec_2_t vec2, vec3; ibz_vec_2_init(&vec2); ibz_vec_2_init(&vec3); digit_t log[2][NWORDS_FIELD]; ec_dlog_2(log[0], log[1], &pushedbasis2, &ker2, E1); ibz_copy_digit_array(&vec2[0], log[0]); ibz_copy_digit_array(&vec2[1], log[1]); ec_dlog_3(log[0], log[1], &pushedbasis3, &ker3, E1); ibz_copy_digit_array(&vec3[0], log[0]); ibz_copy_digit_array(&vec3[1], log[1]); // now compute the ideal id2iso_kernel_dlogs_to_ideal(ideal, &vec2, &vec3); ibz_vec_2_finalize(&vec2); ibz_vec_2_finalize(&vec3); assert(!ibz_cmp(&ideal->norm, &DEGREE_CHALLENGE)); } // compute the isogeny, evaluate at suitable point to find kernel of dual ec_curve_t Emid, E2comp, E2; ec_point_t pts[2]; ec_isom_t E2isom; { ec_isog_even_t isog2 = {.curve = *E1, .length = TORSION_PLUS_EVEN_POWER, .kernel = ker2}; // find a point independent to the kernel to push it through { bool const bit2 = !ibz_divides(&(*hash)[0], &ibz_const_two); bool const bit3 = !ibz_divides(&(*hash)[0], &ibz_const_three); if (bit2 == bit3) { pts[0] = bit2 ? E1basis6.Q : E1basis6.P; } else { digit_t scalars[2][NWORDS_FIELD]; ibz_to_digit_array(scalars[bit3], &TORSION_PLUS_2POWER); ibz_to_digit_array(scalars[bit2], &TORSION_PLUS_3POWER); ec_biscalar_mul(&pts[0], E1, scalars[0], scalars[1], &E1basis6); } } pts[1] = ker; ec_eval_even(&Emid, &isog2, pts, 2); assert(!fp2_is_zero(&Emid.C)); assert(TORSION_ODD_PRIMES[0] == 3); ec_isog_odd_t isog3 = {.curve = Emid, .degree = {TORSION_ODD_POWERS[0]}, .ker_plus = pts[1]}; ec_eval_odd(&E2comp, &isog3, pts, 1); assert(!fp2_is_zero(&E2comp.C)); ec_curve_normalize(&E2, &E2isom, &E2comp); if (out_E2) *out_E2 = E2; ec_iso_eval(&pts[0], &E2isom); } // now the kernel of the dual is in pts[0] // decompose kernel of dual over deterministic 2*3*-torsion basis on E2 ibz_vec_2_t vec2, vec3; ibz_vec_2_init(&vec2); ibz_vec_2_init(&vec3); ec_basis_t E2basis6; { ec_basis_t E2basis2, E2basis3; ec_curve_to_basis_6(&E2basis6, &E2); // set up the 2-power and 3-power bases as images of the 2*3*-torsion one { digit_t scalar[NWORDS_FIELD]; ibz_to_digit_array(scalar, &TORSION_PLUS_3POWER); ec_mul(&E2basis2.P, &E2, scalar, &E2basis6.P); ec_mul(&E2basis2.Q, &E2, scalar, &E2basis6.Q); ec_mul(&E2basis2.PmQ, &E2, scalar, &E2basis6.PmQ); ibz_to_digit_array(scalar, &TORSION_PLUS_2POWER); ec_mul(&E2basis3.P, &E2, scalar, &E2basis6.P); ec_mul(&E2basis3.Q, &E2, scalar, &E2basis6.Q); ec_mul(&E2basis3.PmQ, &E2, scalar, &E2basis6.PmQ); } // compute the 2-power and 3-power parts of the kernel of the dual { digit_t scalar[NWORDS_FIELD]; ibz_to_digit_array(scalar, &TORSION_PLUS_2POWER); ec_mul(&pts[1], &E2, scalar, &pts[0]); ibz_to_digit_array(scalar, &TORSION_PLUS_3POWER); ec_mul(&pts[0], &E2, scalar, &pts[0]); } // now compute the logarithms { digit_t scalars[2][NWORDS_FIELD]; ec_dlog_2(scalars[0], scalars[1], &E2basis2, &pts[0], &E2); ibz_copy_digit_array(&vec2[0], scalars[0]); ibz_copy_digit_array(&vec2[1], scalars[1]); //ibz_vec_2_print(&vec2); #ifndef NDEBUG { ec_point_t tmp; ec_biscalar_mul(&tmp, &E2, scalars[0], scalars[1], &E2basis2); assert(ec_is_equal(&tmp, &pts[0])); } #endif ec_dlog_3(scalars[0], scalars[1], &E2basis3, &pts[1], &E2); ibz_copy_digit_array(&vec3[0], scalars[0]); ibz_copy_digit_array(&vec3[1], scalars[1]); //ibz_vec_2_print(&vec3); #ifndef NDEBUG { ec_point_t tmp; ec_biscalar_mul(&tmp, &E2, scalars[0], scalars[1], &E2basis3); assert(ec_is_equal(&tmp, &pts[1])); } #endif } } // encode this projective vector in the signature field s bool const bit2 = !ibz_divides(&vec2[0], &ibz_const_two); bool const bit3 = !ibz_divides(&vec3[0], &ibz_const_three); { assert(!ibz_divides(&vec2[!bit2], &ibz_const_two)); assert(!ibz_divides(&vec3[!bit3], &ibz_const_three)); { ibz_t inv; ibz_init(&inv); ibz_invmod(&inv, &vec2[!bit2], &TORSION_PLUS_2POWER); ibz_mul(&vec2[bit2], &vec2[bit2], &inv); ibz_mod(&vec2[bit2], &vec2[bit2], &TORSION_PLUS_2POWER); ibz_set(&vec2[!bit2], 1); ibz_invmod(&inv, &vec3[!bit3], &TORSION_PLUS_3POWER); ibz_mul(&vec3[bit3], &vec3[bit3], &inv); ibz_mod(&vec3[bit3], &vec3[bit3], &TORSION_PLUS_3POWER); ibz_set(&vec3[!bit3], 1); ibz_finalize(&inv); } //printf("bit2=%u bit3=%u\n", (unsigned) bit2, (unsigned) bit3); //ibz_vec_2_print(&vec2); //ibz_vec_2_print(&vec3); sig->s.select23 = bit2 | ((unsigned) bit3 << 1); ibz_to_digit_array(sig->s.scalar2, &vec2[bit2]); ibz_to_digit_array(sig->s.scalar3, &vec3[bit3]); } // find another independent point R deterministically ec_point_t R; if (bit2 == bit3) { R = bit2 ? E2basis6.Q : E2basis6.P; } else { digit_t scalars[2][NWORDS_FIELD]; ibz_to_digit_array(scalars[bit3], &TORSION_PLUS_2POWER); ibz_to_digit_array(scalars[bit2], &TORSION_PLUS_3POWER); ec_biscalar_mul(&R, &E2, scalars[0], scalars[1], &E2basis6); } // evaluate the dual of the challenge isogeny { { ec_isom_t E2isom_inv = E2isom; ec_iso_inv(&E2isom_inv); ec_iso_eval(&pts[0], &E2isom_inv); ec_iso_eval(&pts[1], &E2isom_inv); ec_iso_eval(&R, &E2isom_inv); } assert(TORSION_ODD_PRIMES[0] == 3); ec_isog_odd_t isog3dual = {.curve = E2comp, .degree = {TORSION_ODD_POWERS[0]}, .ker_plus = pts[1]}; ec_curve_t Emidcomp; pts[1] = R; ec_eval_odd(&Emidcomp, &isog3dual, pts, 2); assert(!fp2_is_zero(&Emidcomp.C)); #ifndef NDEBUG { fp2_t j1, j2; ec_j_inv(&j1, &Emid); ec_j_inv(&j2, &Emidcomp); assert(fp2_is_equal(&j1, &j2)); } #endif R = pts[1]; ec_isog_even_t isog2dual = {.curve = Emidcomp, .length = TORSION_PLUS_EVEN_POWER, .kernel = pts[0]}; ec_curve_t E1comp; ec_eval_even(&E1comp, &isog2dual, &R, 1); assert(!fp2_is_zero(&E1comp.C)); #ifndef NDEBUG { fp2_t j1, j2; ec_j_inv(&j1, E1); ec_j_inv(&j2, &E1comp); assert(fp2_is_equal(&j1, &j2)); } #endif { ec_isom_t E1isom; ec_isomorphism(&E1isom, &E1comp, E1); ec_iso_eval(&R, &E1isom); } } ibz_t r; ibz_init(&r); //TODO this should just be a 1-dimensional logarithm in the 2*3*-torsion { ec_point_t R2, R3; { digit_t scalar[NWORDS_FIELD]; ibz_to_digit_array(scalar, &TORSION_PLUS_3POWER); ec_mul(&R2, E1, scalar, &R); ibz_to_digit_array(scalar, &TORSION_PLUS_2POWER); ec_mul(&R3, E1, scalar, &R); } ibz_vec_2_t log2, log3; ibz_vec_2_init(&log2); ibz_vec_2_init(&log3); { digit_t scalars[2][NWORDS_FIELD] = {0}; ec_dlog_2(scalars[0], scalars[1], &E1basis2, &R2, E1); #ifndef NDEBUG { ec_point_t tmp; ec_biscalar_mul(&tmp, E1, scalars[0], scalars[1], &E1basis2); assert(ec_is_equal(&tmp, &R2)); } #endif ibz_copy_digit_array(&log2[0], scalars[0]); ibz_copy_digit_array(&log2[1], scalars[1]); memset(scalars, 0, sizeof(scalars)); ec_dlog_3(scalars[0], scalars[1], &E1basis3, &R3, E1); #ifndef NDEBUG { ec_point_t tmp; ec_biscalar_mul(&tmp, E1, scalars[0], scalars[1], &E1basis3); assert(ec_is_equal(&tmp, &R3)); } #endif ibz_copy_digit_array(&log3[0], scalars[0]); ibz_copy_digit_array(&log3[1], scalars[1]); #ifndef NDEBUG { ibz_t lhs, rhs; ibz_init(&lhs); ibz_init(&rhs); // check log2 is a multiple of hash modulo 2* ibz_mul(&lhs, &log2[0], &(*hash)[1]); ibz_mul(&rhs, &log2[1], &(*hash)[0]); ibz_mod(&lhs, &lhs, &TORSION_PLUS_2POWER); ibz_mod(&rhs, &rhs, &TORSION_PLUS_2POWER); assert(!ibz_cmp(&lhs, &rhs)); // check log3 is a multiple of hash modulo 3* ibz_mul(&lhs, &log3[0], &(*hash)[1]); ibz_mul(&rhs, &log3[1], &(*hash)[0]); ibz_mod(&lhs, &lhs, &TORSION_PLUS_3POWER); ibz_mod(&rhs, &rhs, &TORSION_PLUS_3POWER); assert(!ibz_cmp(&lhs, &rhs)); ibz_finalize(&lhs); ibz_finalize(&rhs); } #endif { ibz_t r2, r3; ibz_init(&r2); ibz_init(&r3); bool bit = ibz_divides(&log2[0], &ibz_const_two); assert(!ibz_divides(&log2[bit], &ibz_const_two)); ibz_invmod(&r2, &log2[bit], &TORSION_PLUS_2POWER); ibz_mul(&r2, &(*hash)[bit], &r2); ibz_mod(&r2, &r2, &TORSION_PLUS_2POWER); //ibz_printf("r2 = %#Zx\n", &r2); #ifndef NDEBUG { digit_t scalar[NWORDS_FIELD]; ibz_to_digit_array(scalar, &r2); ec_point_t T1, T2; ec_mul(&T1, E1, scalar, &R); ibz_to_digit_array(scalar, &TORSION_PLUS_3POWER); ec_mul(&T1, E1, scalar, &T1); ec_mul(&T2, E1, scalar, &ker); assert(ec_is_equal(&T1, &T2)); } #endif bit = ibz_divides(&log3[0], &ibz_const_three); assert(!ibz_divides(&log3[bit], &ibz_const_three)); ibz_invmod(&r3, &log3[bit], &TORSION_PLUS_3POWER); ibz_mul(&r3, &(*hash)[bit], &r3); ibz_mod(&r3, &r3, &TORSION_PLUS_3POWER); //ibz_printf("r3 = %#Zx\n", &r3); #ifndef NDEBUG { digit_t scalar[NWORDS_FIELD]; ibz_to_digit_array(scalar, &r3); ec_point_t T1, T2; ec_mul(&T1, E1, scalar, &R); ibz_to_digit_array(scalar, &TORSION_PLUS_2POWER); ec_mul(&T1, E1, scalar, &T1); ec_mul(&T2, E1, scalar, &ker); assert(ec_is_equal(&T1, &T2)); } #endif ibz_crt(&r, &r2, &r3, &TORSION_PLUS_2POWER, &TORSION_PLUS_3POWER); // check if we mixed up the signs and correct it in that case { digit_t scalar[NWORDS_FIELD]; ibz_to_digit_array(scalar, &r); ec_point_t T; ec_mul(&T, E1, scalar, &R); if (!ec_is_equal(&T, &ker)) { ibz_sub(&r3, &TORSION_PLUS_3POWER, &r3); ibz_crt(&r, &r2, &r3, &TORSION_PLUS_2POWER, &TORSION_PLUS_3POWER); } } ibz_finalize(&r2); ibz_finalize(&r3); } } ibz_vec_2_finalize(&log2); ibz_vec_2_finalize(&log3); ibz_vec_2_finalize(&vec2); ibz_vec_2_finalize(&vec3); } #ifndef NDEBUG { digit_t scalar[NWORDS_FIELD]; ibz_to_digit_array(scalar, &r); ec_point_t T; ec_mul(&T, E1, scalar, &R); assert(ec_is_equal(&T, &ker)); assert(!ibz_divides(&r, &ibz_const_two)); assert(!ibz_divides(&r, &ibz_const_three)); } #endif ibz_to_digit_array(sig->r, &r); ibz_finalize(&r); } int protocols_sign(signature_t *sig,const public_key_t *pk, const secret_key_t *sk, const unsigned char* m, size_t l) { // var dec quat_order_t right_order_key; quat_left_ideal_t ideal_commit,ideal_challenge; quat_alg_elem_t gen,gen_small,gen_answer,delta; ibq_t ibq_norm; ibz_t norm,temp,remainder; ibz_mat_4x4_t reduced,gram; quat_alg_coord_t coeffs; quat_left_ideal_t ideal_comchall,ideal_seccomchall; quat_left_ideal_t ideal_eichler_rand; quat_left_ideal_t ideal_pullback,ideal_input_klpt; quat_alg_elem_t gen_challenge; // var init ibq_init(&ibq_norm); ibz_init(&norm);ibz_init(&temp); ibz_init(&remainder); quat_order_init(&right_order_key); quat_left_ideal_init(&ideal_commit); quat_left_ideal_init(&ideal_challenge); quat_alg_elem_init(&gen); quat_alg_elem_init(&gen_small); quat_alg_elem_init(&delta); ibz_mat_4x4_init(&reduced); ibz_mat_4x4_init(&gram); quat_alg_coord_init(&coeffs); quat_left_ideal_init(&ideal_comchall); quat_left_ideal_init(&ideal_seccomchall); quat_left_ideal_init(&ideal_eichler_rand); quat_left_ideal_init(&ideal_pullback); quat_left_ideal_init(&ideal_input_klpt); quat_alg_elem_init(&gen_challenge); ec_curve_t curve = sk->curve; ec_basis_t basis_plus = sk->basis_plus; ec_basis_t basis_minus = sk->basis_minus; ec_point_t kernel_dual = sk->kernel_dual; // Commitment (computes ideal_commit and pushes the 2*3*-torsion basis) ec_curve_t E1; ec_basis_t E1basis = BASIS_CHALLENGE; { protocols_commit(&ideal_commit, &E1, &E1basis); assert(!fp2_is_zero(&E1.C)); assert(!fp2_is_zero(&E1basis.P.z) && !fp2_is_zero(&E1basis.Q.z) && !fp2_is_zero(&E1basis.PmQ.z)); } // Challenge (computes ideal_challenge and sig->r, sig->s) ec_curve_t E2_for_testing; //XXX { ibz_vec_2_t vec; ibz_vec_2_init(&vec); hash_to_challenge(&vec, &E1, m, l); protocols_challenge(&ideal_challenge, sig, &E1, &E1basis, &vec, &E2_for_testing); ibz_vec_2_finalize(&vec); } assert(ibz_get(&ideal_commit.norm)%2!=0); // ideal_comchall is the intersectin of ideal_commit and ideal_challenge quat_lideal_inter(&ideal_comchall,&ideal_challenge,&ideal_commit,&QUATALG_PINFTY); #ifndef NDEBUG // debug the norm ibz_mul(&temp,&ideal_commit.norm,&ideal_challenge.norm); assert(0==ibz_cmp(&temp,&ideal_comchall.norm)); #endif int lideal_generator_ok = quat_lideal_generator(&gen,&ideal_comchall,&QUATALG_PINFTY,0); assert(lideal_generator_ok); // computing the generator of ideal seccomchall as gen = sk.gen_two * gen quat_alg_elem_copy(&gen_challenge,&gen); quat_alg_norm(&ibq_norm,&gen_challenge,&QUATALG_PINFTY); ibq_to_ibz(&norm,&ibq_norm); // computing a good norm element for sk.lideal_small lideal_generator_ok = quat_lideal_generator_coprime(&gen_small,&sk->lideal_small,&norm,&QUATALG_PINFTY,0); assert(lideal_generator_ok); quat_alg_conj(&gen_small,&gen_small); quat_alg_normalize(&gen_small); // gen = gen_small * gen_challenge quat_alg_mul(&gen,&gen_small,&gen_challenge,&QUATALG_PINFTY); ibz_mul(&temp,&ideal_comchall.norm,&sk->lideal_small.norm); quat_alg_normalize(&gen); // computing of the right order of lideal_small quat_lideal_right_order(&right_order_key,&sk->lideal_small,&QUATALG_PINFTY); assert(quat_lattice_contains(&coeffs,&right_order_key,&gen,&QUATALG_PINFTY)); // creation of ideal_seccomchall quat_lideal_make_primitive_then_create(&ideal_seccomchall,&gen,&temp,&right_order_key,&QUATALG_PINFTY); // copying a generator for later quat_alg_elem_copy(&gen_challenge,&gen); #ifndef NDEBUG // debug the norm ibz_mul(&temp,&ideal_comchall.norm,&sk->lideal_small.norm); assert(0==ibz_cmp(&temp,&ideal_seccomchall.norm)); #endif int found = 0; for (unsigned attempt = 0; !found && attempt < SQISIGN_response_attempts; ++attempt) { // TODUPDATE add a random ideal of norm 2^SQISIGN_random_length (right now SQISIGN_random_length ) // now we are computing a small ideal equivalent to ideal_seccomchall //TODUPDATE replace with another randomization to ensure a good distribution in the eichler order class set quat_lideal_reduce_basis(&reduced,&gram,&ideal_seccomchall,&QUATALG_PINFTY); found = klpt_lideal_equiv(&gen,&temp,&reduced,&gram,&ideal_seccomchall.norm,&ideal_seccomchall.lattice.denom,&QUATALG_PINFTY); if (!found) { continue; } // quat_alg_elem_copy(&gen_challenge,&gen); quat_alg_conj(&gen_challenge,&gen); // computing ideal_eichler_rand = right_order_key < gen, temp > quat_lideal_create_from_primitive(&ideal_eichler_rand,&gen,&temp,&right_order_key,&QUATALG_PINFTY); assert(quat_lideal_isom(&delta,&ideal_eichler_rand,&ideal_seccomchall,&QUATALG_PINFTY)); // computing the pullback through sk->lideal_small quat_alg_mul(&gen,&gen_small,&gen,&QUATALG_PINFTY); quat_alg_normalize(&gen); quat_lideal_create_from_primitive(&ideal_pullback,&gen,&ideal_eichler_rand.norm,&MAXORD_O0,&QUATALG_PINFTY); // computing the final input ideal as equivalent to ideal_pullback quat_lideal_reduce_basis(&reduced,&gram,&ideal_pullback,&QUATALG_PINFTY); found = found && klpt_lideal_equiv(&gen,&temp,&reduced,&gram,&ideal_pullback.norm,&ideal_pullback.lattice.denom,&QUATALG_PINFTY); // ruling out failure, or extreme values of gen if (!found || 0==ibz_cmp(&gen.coord[0],&ibz_const_zero) || 0==ibz_cmp(&gen.coord[1],&ibz_const_zero)) { found = 0; continue; } // creating this ideal quat_lideal_create_from_primitive(&ideal_input_klpt,&gen,&temp,&MAXORD_O0,&QUATALG_PINFTY); assert(quat_lideal_isom(&delta,&ideal_input_klpt,&ideal_pullback,&QUATALG_PINFTY)); // applying klpt quat_alg_conj(&delta,&gen); #ifndef NDEBUG assert(quat_lattice_contains(&coeffs,&ideal_pullback.lattice,&delta,&QUATALG_PINFTY)); #endif // applying signing klpt found = klpt_signing_klpt(&gen,&ideal_input_klpt,&sk->lideal_small,&delta,&QUATALG_PINFTY); if (!found) { continue; } assert(quat_lattice_contains(&coeffs,&ideal_input_klpt.lattice,&gen,&QUATALG_PINFTY)); // gen = gen *delta /norm(ideal_input_klpt) quat_alg_mul(&gen,&gen,&delta,&QUATALG_PINFTY); ibz_mul(&gen.denom,&gen.denom,&ideal_input_klpt.norm); quat_alg_normalize(&gen); // for debug we check that gen is contained in the right order and ideal assert(quat_lattice_contains(&coeffs,&ideal_pullback.lattice,&gen,&QUATALG_PINFTY)); assert(quat_lattice_contains(&coeffs,&right_order_key,&gen,&QUATALG_PINFTY)); // gen = conjugate(gen) // gen should be the generator of the ideal to be translated quat_alg_conj(&gen,&gen); #ifndef NDEBUG quat_left_ideal_t ideal_signing_test; quat_left_ideal_init(&ideal_signing_test); ibz_pow(&temp,&ibz_const_two,KLPT_signing_klpt_length); quat_lideal_create_from_primitive(&ideal_signing_test,&gen,&temp,&right_order_key,&QUATALG_PINFTY); assert(quat_lideal_isom(&delta,&ideal_signing_test,&ideal_seccomchall,&QUATALG_PINFTY)); assert(quat_lideal_isom(&delta,&ideal_eichler_rand,&ideal_seccomchall,&QUATALG_PINFTY)); assert(quat_lideal_isom(&delta,&ideal_eichler_rand,&ideal_seccomchall,&QUATALG_PINFTY)); assert(0==ibz_cmp(&temp,&ideal_signing_test.norm)); quat_alg_conj(&delta,&gen); quat_lideal_create_from_primitive(&ideal_signing_test,&delta,&ideal_eichler_rand.norm,&right_order_key,&QUATALG_PINFTY); assert(quat_lideal_equals(&ideal_signing_test,&ideal_eichler_rand,&QUATALG_PINFTY)); #endif // checking cyclicity quat_alg_conj(&delta,&gen); assert(quat_lattice_contains(&coeffs,&ideal_eichler_rand.lattice,&delta,&QUATALG_PINFTY)); // quat_alg_elem_copy(&delta,&gen); quat_alg_mul(&delta,&delta,&gen_challenge,&QUATALG_PINFTY); ibz_mul(&delta.denom,&delta.denom,&ideal_eichler_rand.norm); quat_alg_normalize(&delta); assert(quat_lattice_contains(&coeffs,&right_order_key,&delta,&QUATALG_PINFTY)); found = found && quat_alg_is_primitive(&delta,&right_order_key,&QUATALG_PINFTY); if (!found) { continue; } assert(SQISIGN_signing_length == KLPT_signing_klpt_length/TORSION_PLUS_EVEN_POWER); found = found && id2iso_ideal_to_isogeny_two_long_power_of_2(&sig->zip,&curve,&basis_minus,&basis_plus,&kernel_dual,&gen,SQISIGN_signing_length,&sk->lideal_small,&sk->lideal_two,&sk->gen_two,&QUATALG_PINFTY); } // if (!found) // return found; // quick check to see if we got the correct curve in the end #ifndef NDEBUG if (found) { fp2_t jchall, jresp; ec_j_inv(&jchall, &E2_for_testing); ec_j_inv(&jresp, &curve); assert(fp2_is_equal(&jchall, &jresp)); } else { printf("signature failed \n"); } #endif // var finalize ibq_finalize(&ibq_norm); ibz_finalize(&norm);ibz_finalize(&temp); ibz_finalize(&remainder); quat_order_finalize(&right_order_key); quat_left_ideal_finalize(&ideal_commit); quat_left_ideal_finalize(&ideal_challenge); quat_alg_elem_finalize(&gen); quat_alg_elem_finalize(&gen_small); quat_alg_elem_finalize(&delta); ibz_mat_4x4_finalize(&reduced); ibz_mat_4x4_finalize(&gram); quat_alg_coord_finalize(&coeffs); quat_left_ideal_finalize(&ideal_comchall); quat_left_ideal_finalize(&ideal_seccomchall); quat_left_ideal_finalize(&ideal_eichler_rand); quat_left_ideal_finalize(&ideal_pullback); quat_left_ideal_finalize(&ideal_input_klpt); quat_alg_elem_finalize(&gen_challenge); return found; }