/*
* ecgen, tool for generating Elliptic curve domain parameters
* Copyright (C) 2017-2018 J08nY
*/
#include "subgroup.h"
/**
* @brief All prime divisors of a given integer with multiplicity.
*
* subgroups_divisors(27) = [3, 3, 3]
* @param order
* @return a t_VEC of prime divisors.
*/
static GEN subgroups_divisors(GEN order) {
GEN factors = Z_factor(order);
GEN primes = gel(factors, 1);
GEN multiples = gel(factors, 2);
long uniqs = glength(primes);
long size = 0;
for (long i = 1; i <= uniqs; ++i) {
size += itos(gel(multiples, i));
}
GEN result = gtovec0(gen_0, size);
long count = 0;
for (long i = 1; i <= uniqs; ++i) {
long multiple = itos(gel(multiples, i));
for (long j = 1; j <= multiple; ++j) {
gel(result, ++count) = gel(primes, i);
}
}
return result;
}
/**
* @brief All factors consisting of at least min_bits prime
* factors.
*
* @param factors
* @param min_bits
* @return a t_VEC of factors
*/
static GEN subgroups_2n_factors(GEN factors, size_t min_bits) {
pari_sp ltop = avma;
long nprimes = glength(factors);
if (nprimes == min_bits) return NULL;
GEN amount = int2n(nprimes);
GEN groups = gtovec0(gen_0, itos(amount) - (min_bits * nprimes) - 1);
size_t i = 0;
for (size_t count = 1; count < (size_t)(1) << nprimes; ++count) {
pari_sp btop = avma;
GEN result = gen_1;
size_t bits = 0;
for (long bit = 0; bit < nprimes; ++bit) {
size_t mask = (size_t)(1) << bit;
if (count & mask) {
result = mulii(result, gel(factors, bit + 1));
bits++;
}
}
if (bits > min_bits) {
gel(groups, ++i) = result;
} else {
avma = btop;
}
}
GEN ret = gtoset(groups);
return gerepilecopy(ltop, ret);
}
GEN subgroups_prime(GEN order) {
if (isprime(order)) {
return gtovec(order);
}
GEN factors = Z_factor(order);
return gtovec(gel(factors, 1));
}
GEN subgroups_nonprime(GEN order) {
if (isprime(order)) {
return NULL;
}
GEN factors = subgroups_divisors(order);
return subgroups_2n_factors(factors, 1);
}
GEN subgroups_all(GEN order) {
if (isprime(order)) {
return gtovec(order);
}
GEN factors = subgroups_divisors(order);
return subgroups_2n_factors(factors, 0);
}
/**
* @brief
* @param curve
* @param min_bits
* @return
*/
/*
static GEN subgroups_2n_gens(const curve_t *curve, size_t min_bits) {
GEN one_factors = subgroups_divisors(curve->generators[0]->order);
GEN one = subgroups_2n_factors(one_factors, min_bits);
GEN other_factors = subgroups_divisors(curve->generators[1]->order);
GEN other = subgroups_2n_factors(other_factors, min_bits);
if (!one) {
return other;
}
if (!other) {
return one;
}
GEN result = gtovec0(gen_0, glength(one) + glength(other));
for (long i = 1; i <= glength(result); ++i) {
if (i <= glength(one)) {
gel(result, i) = gel(one, i);
} else {
gel(result, i) = gel(other, i - glength(one));
}
}
return result;
}
*/
/**
* @brief
* @param curve
* @param min_bits
* @return
*/
/*
static GEN subgroups_2n(const curve_t *curve, size_t min_bits) {
if (curve->ngens == 1) {
GEN factors = subgroups_divisors(curve->order);
return subgroups_2n_factors(factors, min_bits);
}
return subgroups_2n_gens(curve, min_bits);
}
*/