|
|
@@ -24,6 +24,8 @@ extern "C" {
|
|
|
|
|
|
NTL_CLIENT
|
|
|
|
|
|
+#define DEBUG
|
|
|
+
|
|
|
struct SubproblemProgress;
|
|
|
|
|
|
typedef std::set<struct bufferevent *> BESet;
|
|
|
@@ -74,11 +76,23 @@ void vsppdump(const vector<SubproblemProgress> &spv, ostream &os);
|
|
|
static struct ControllerState {
|
|
|
ZZ rho;
|
|
|
FactorDecomp p, q;
|
|
|
- int working;
|
|
|
+ ZZ base, target;
|
|
|
+ bool working;
|
|
|
vector<SubproblemProgress> subproblems_p, subproblems_q;
|
|
|
Statuses dpnodes, workers;
|
|
|
-
|
|
|
- ControllerState() : working(0) {}
|
|
|
+ unsigned int num_unsolved_subproblems;
|
|
|
+
|
|
|
+ ControllerState() : working(false), num_unsolved_subproblems(0) {}
|
|
|
+
|
|
|
+ // Reset the state for a new problem with the same modulus
|
|
|
+ void reset(void) {
|
|
|
+ base = 0;
|
|
|
+ target = 0;
|
|
|
+ working = false;
|
|
|
+ subproblems_p.clear();
|
|
|
+ subproblems_q.clear();
|
|
|
+ num_unsolved_subproblems = 0;
|
|
|
+ }
|
|
|
|
|
|
// Dump the state for debug purposes
|
|
|
void dump(ostream &os) const {
|
|
|
@@ -199,6 +213,10 @@ struct SubproblemProgress : Subproblem {
|
|
|
for (unsigned short i = 0; i < num_ipports; ++i) {
|
|
|
bufferevent_write(bev, ipports[i].ipport, 6);
|
|
|
}
|
|
|
+#ifdef DEBUG
|
|
|
+ cerr << "Added worker " << bev << "to subproblem "
|
|
|
+ << problemid << "\n";
|
|
|
+#endif
|
|
|
}
|
|
|
};
|
|
|
|
|
|
@@ -273,10 +291,8 @@ static void find_subproblem_for_worker(vector<SubproblemProgress> &spv)
|
|
|
}
|
|
|
|
|
|
// See if there are any idle DPnodes or workers we can put to use
|
|
|
-void schedule(void)
|
|
|
+static void schedule(void)
|
|
|
{
|
|
|
- cerr << "Before schedule:\n"; ctrlstate.dump(cerr);
|
|
|
-
|
|
|
// Check the DPnodes
|
|
|
|
|
|
// Iterate through the subproblems, looking for one that can use
|
|
|
@@ -308,7 +324,141 @@ void schedule(void)
|
|
|
find_subproblem_for_worker(ctrlstate.subproblems_q);
|
|
|
}
|
|
|
|
|
|
- cerr << "After schedule:\n"; ctrlstate.dump(cerr);
|
|
|
+ // cerr << "After schedule:\n"; ctrlstate.dump(cerr);
|
|
|
+}
|
|
|
+
|
|
|
+static ZZ computation_complete_p(const vector<SubproblemProgress> &v)
|
|
|
+{
|
|
|
+ ZZ curmodulus, curexp;
|
|
|
+ curmodulus = 2;
|
|
|
+ curexp = 0;
|
|
|
+
|
|
|
+ vector<SubproblemProgress>::const_iterator vit;
|
|
|
+ for(vit = v.begin(); vit != v.end(); ++vit) {
|
|
|
+ CRT(curexp, curmodulus, vit->solution, vit->order);
|
|
|
+ }
|
|
|
+
|
|
|
+ if (curexp < 0) {
|
|
|
+ curexp += curmodulus;
|
|
|
+ }
|
|
|
+
|
|
|
+ return curexp;
|
|
|
+}
|
|
|
+
|
|
|
+// All subproblems are solved. Combine the results.
|
|
|
+static void computation_complete(void)
|
|
|
+{
|
|
|
+ ZZ exp_p = computation_complete_p(ctrlstate.subproblems_p);
|
|
|
+ ZZ exp_q = computation_complete_p(ctrlstate.subproblems_q);
|
|
|
+ ZZ pm1 = (ctrlstate.p.factor - 1)/2;
|
|
|
+ ZZ qm1 = (ctrlstate.q.factor - 1)/2;
|
|
|
+ CRT(exp_p, pm1, exp_q, qm1);
|
|
|
+ if (exp_p < 0) {
|
|
|
+ exp_p += pm1;
|
|
|
+ }
|
|
|
+ ZZ& expon = exp_p;
|
|
|
+
|
|
|
+ cout << "expon = " << expon << "\n";
|
|
|
+ ZZ base_exp = PowerMod(ctrlstate.base, expon, ctrlstate.rho);
|
|
|
+ if (base_exp == ctrlstate.target) {
|
|
|
+ cout << "CORRECT!\n";
|
|
|
+ } else {
|
|
|
+ cout << "INCORRECT:\nbase^exp = " << base_exp << "\n";
|
|
|
+ cout << "target = " << ctrlstate.target << "\n";
|
|
|
+ }
|
|
|
+
|
|
|
+ ctrlstate.reset();
|
|
|
+}
|
|
|
+
|
|
|
+static unsigned short curproblemid = 0;
|
|
|
+
|
|
|
+// Take base and target mod f.factor, then decompose that into small
|
|
|
+// subproblems given our knowledge of the factors of phi(f.factor)
|
|
|
+static vector<SubproblemProgress> decomp(const ZZ_p &base, const ZZ_p &target,
|
|
|
+ const FactorDecomp &f)
|
|
|
+{
|
|
|
+ vector<SubproblemProgress> ret;
|
|
|
+
|
|
|
+ // Compute phi(factor)
|
|
|
+ const int fveclen = f.fvec.length();
|
|
|
+ ZZ phi = to_ZZ(2);
|
|
|
+ for (int i = 0; i < fveclen; ++i) {
|
|
|
+ phi *= f.fvec[i];
|
|
|
+ }
|
|
|
+
|
|
|
+ ZZ_p::init(f.factor);
|
|
|
+ for (int i = 0; i < fveclen; ++i) {
|
|
|
+ const ZZ& order = f.fvec[i];
|
|
|
+ ZZ quotient = phi / order;
|
|
|
+ ZZ_p subgroup_base = to_ZZ_p(rep(base));
|
|
|
+ subgroup_base = power(subgroup_base, quotient);
|
|
|
+ ZZ_p subgroup_target = to_ZZ_p(rep(target));
|
|
|
+ subgroup_target = power(subgroup_target, quotient);
|
|
|
+
|
|
|
+ if (subgroup_base == 1) {
|
|
|
+ // The original base wasn't a generator of the whole group
|
|
|
+ if (subgroup_target == 1) {
|
|
|
+ // But the target is in the subgroup. Lucky us.
|
|
|
+ continue;
|
|
|
+ } else {
|
|
|
+ ret.clear();
|
|
|
+ return ret;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // By default, 1 in 1000 points are distinguihed points. The
|
|
|
+ // number in the next line is 2^32/1000
|
|
|
+ unsigned int dpfreq = 4294967;
|
|
|
+ if (order < 1000) {
|
|
|
+ // Just make every point a DP
|
|
|
+ dpfreq = 4294967295U;
|
|
|
+ } else if (NumBits(order) < 27) {
|
|
|
+ // The frequency of DPs should be 10/sqrt(order) to avoid
|
|
|
+ // a DP-free cycle, so dpfreq = (10*2^32)/sqrt(order)
|
|
|
+ ZZ f = (to_ZZ(10) << 32) / SqrRoot(order);
|
|
|
+ dpfreq = trunc_long(f, 31);
|
|
|
+ }
|
|
|
+ ++curproblemid;
|
|
|
+ ret.push_back(SubproblemProgress(curproblemid, rep(subgroup_base),
|
|
|
+ rep(subgroup_target),
|
|
|
+ f.factor, order, dpfreq));
|
|
|
+ }
|
|
|
+
|
|
|
+ return ret;
|
|
|
+}
|
|
|
+
|
|
|
+static int generate_problem(struct event_base *evbase)
|
|
|
+{
|
|
|
+ // If there's already a problem on the go, don't generate another one
|
|
|
+ if (ctrlstate.working == true) {
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+ ctrlstate.working = true;
|
|
|
+
|
|
|
+ int num_subproblems_p = 0;
|
|
|
+ int num_subproblems_q = 0;
|
|
|
+
|
|
|
+ // Generate a DLP mod rho (in the large odd-order subgroup)
|
|
|
+ ZZ_p::init(ctrlstate.rho);
|
|
|
+ do {
|
|
|
+ ZZ_p base = power(random_ZZ_p(), 2);
|
|
|
+ ZZ_p target = power(random_ZZ_p(), 2);
|
|
|
+ ctrlstate.base = rep(base);
|
|
|
+ ctrlstate.target = rep(target);
|
|
|
+
|
|
|
+ // Decompose it mod p and mod q
|
|
|
+ ctrlstate.subproblems_p = decomp(base, target, ctrlstate.p);
|
|
|
+ ctrlstate.subproblems_q = decomp(base, target, ctrlstate.q);
|
|
|
+ num_subproblems_p = ctrlstate.subproblems_p.size();
|
|
|
+ num_subproblems_q = ctrlstate.subproblems_q.size();
|
|
|
+ } while (num_subproblems_p == 0 || num_subproblems_q == 0);
|
|
|
+
|
|
|
+ ctrlstate.num_unsolved_subproblems =
|
|
|
+ num_subproblems_p + num_subproblems_q;
|
|
|
+
|
|
|
+ schedule();
|
|
|
+
|
|
|
+ return 0;
|
|
|
}
|
|
|
|
|
|
typedef enum {
|
|
|
@@ -367,7 +517,9 @@ static void controller_dpnode_reader(struct bufferevent *bev, void *ctx)
|
|
|
memmove(&DPport, ipport+4, 2);
|
|
|
{
|
|
|
struct in_addr DPaddr = { DPip };
|
|
|
- printf("DP node at %s:%d\n", inet_ntoa(DPaddr), ntohs(DPport));
|
|
|
+#ifdef DEBUG
|
|
|
+ fprintf(stderr, "DP node at %s:%d\n", inet_ntoa(DPaddr), ntohs(DPport));
|
|
|
+#endif
|
|
|
if (ctrlstate.dpnodes.working.count(bev) > 0) {
|
|
|
ctrlstate.dpnodes.working[bev]->ipports.push_back(
|
|
|
IPPort(ipport));
|
|
|
@@ -389,12 +541,19 @@ static void controller_dpnode_reader(struct bufferevent *bev, void *ctx)
|
|
|
if (ctrlstate.dpnodes.working.count(bev) > 0) {
|
|
|
SubproblemProgress *spp = ctrlstate.dpnodes.working[bev];
|
|
|
if (spp->problemid == problemid &&
|
|
|
+ spp->solved == false &&
|
|
|
spp->target ==
|
|
|
PowerMod(spp->base, expon, spp->modulus)) {
|
|
|
// Subproblem solved!
|
|
|
spp->solution = expon;
|
|
|
spp->solved = true;
|
|
|
spp->stop();
|
|
|
+ ctrlstate.num_unsolved_subproblems--;
|
|
|
+ if (ctrlstate.num_unsolved_subproblems == 0) {
|
|
|
+ computation_complete();
|
|
|
+ generate_problem(bufferevent_get_base(bev));
|
|
|
+ ctrlstate.dump(cerr);
|
|
|
+ }
|
|
|
schedule();
|
|
|
}
|
|
|
}
|
|
|
@@ -477,7 +636,6 @@ static void controller_master_reader(struct bufferevent *bev, void *ctx)
|
|
|
bufferevent_read(bev, indata, 1);
|
|
|
switch(indata[0]) {
|
|
|
case 'D':
|
|
|
- printf("DPnode\n");
|
|
|
/* Add this DPnode to the list of available ones */
|
|
|
ctrlstate.dpnodes.idle.insert(bev);
|
|
|
bufferevent_setcb(bev, controller_dpnode_reader, NULL,
|
|
|
@@ -486,7 +644,6 @@ static void controller_master_reader(struct bufferevent *bev, void *ctx)
|
|
|
schedule();
|
|
|
return;
|
|
|
case 'W':
|
|
|
- printf("Worker\n");
|
|
|
ctrlstate.workers.idle.insert(bev);
|
|
|
// We don't actually read anything from workers
|
|
|
bufferevent_enable(bev, EV_WRITE);
|
|
|
@@ -533,85 +690,6 @@ void *controller_create(struct event_base *evbase, unsigned short bindport,
|
|
|
ip, boundport, false);
|
|
|
}
|
|
|
|
|
|
-static unsigned short curproblemid = 0;
|
|
|
-
|
|
|
-// Take base and target mod f.factor, then decompose that into small
|
|
|
-// subproblems given our knowledge of the factors of phi(f.factor)
|
|
|
-static vector<SubproblemProgress> decomp(const ZZ_p &base, const ZZ_p &target,
|
|
|
- const FactorDecomp &f)
|
|
|
-{
|
|
|
- vector<SubproblemProgress> ret;
|
|
|
-
|
|
|
- // Compute phi(factor)
|
|
|
- const int fveclen = f.fvec.length();
|
|
|
- ZZ phi = to_ZZ(2);
|
|
|
- for (int i = 0; i < fveclen; ++i) {
|
|
|
- phi *= f.fvec[i];
|
|
|
- }
|
|
|
-
|
|
|
- ZZ_p::init(f.factor);
|
|
|
- for (int i = 0; i < fveclen; ++i) {
|
|
|
- const ZZ& order = f.fvec[i];
|
|
|
- ZZ quotient = phi / order;
|
|
|
- ZZ_p subgroup_base = to_ZZ_p(rep(base));
|
|
|
- subgroup_base = power(subgroup_base, quotient);
|
|
|
- ZZ_p subgroup_target = to_ZZ_p(rep(target));
|
|
|
- subgroup_target = power(subgroup_target, quotient);
|
|
|
-
|
|
|
- if (subgroup_base == 1) {
|
|
|
- // The original base wasn't a generator of the whole group
|
|
|
- if (subgroup_target == 1) {
|
|
|
- // But the target is in the subgroup. Lucky us.
|
|
|
- continue;
|
|
|
- } else {
|
|
|
- ret.clear();
|
|
|
- return ret;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- // By default, 1 in 1000 points are distinguihed points. The
|
|
|
- // number in the next line is 2^32/1000
|
|
|
- unsigned int dpfreq = 4294967;
|
|
|
- if (order < 1000) {
|
|
|
- // Just make every point a DP
|
|
|
- dpfreq = 4294967295U;
|
|
|
- } else if (NumBits(order) < 27) {
|
|
|
- // The frequency of DPs should be 10/sqrt(order) to avoid
|
|
|
- // a DP-free cycle, so dpfreq = (10*2^32)/sqrt(order)
|
|
|
- ZZ f = (to_ZZ(10) << 32) / SqrRoot(order);
|
|
|
- dpfreq = trunc_long(f, 31);
|
|
|
- }
|
|
|
- ++curproblemid;
|
|
|
- ret.push_back(SubproblemProgress(curproblemid, rep(subgroup_base),
|
|
|
- rep(subgroup_target),
|
|
|
- f.factor, order, dpfreq));
|
|
|
- }
|
|
|
-
|
|
|
- return ret;
|
|
|
-}
|
|
|
-
|
|
|
-static int generate_problem(struct event_base *evbase)
|
|
|
-{
|
|
|
- // If there's already a problem on the go, don't generate another one
|
|
|
- if (ctrlstate.working == 1) {
|
|
|
- return -1;
|
|
|
- }
|
|
|
- ctrlstate.working = 1;
|
|
|
-
|
|
|
- // Generate a DLP mod rho (in the large odd-order subgroup)
|
|
|
- ZZ_p::init(ctrlstate.rho);
|
|
|
- ZZ_p base = power(random_ZZ_p(), 2);
|
|
|
- ZZ_p target = power(random_ZZ_p(), 2);
|
|
|
-
|
|
|
- // Decompose it mod p and mod q
|
|
|
- ctrlstate.subproblems_p = decomp(base, target, ctrlstate.p);
|
|
|
- ctrlstate.subproblems_q = decomp(base, target, ctrlstate.q);
|
|
|
-
|
|
|
- schedule();
|
|
|
-
|
|
|
- return 0;
|
|
|
-}
|
|
|
-
|
|
|
int main(int argc, char **argv)
|
|
|
{
|
|
|
// Initialize the prng with some randomness from the kernel
|