aboutsummaryrefslogtreecommitdiff
path: root/src/gen/gp.c
blob: dff7ca141365761392aaf7be8c3598d34003d9af (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
/*
 * ecgen, tool for generating Elliptic curve domain parameters
 * Copyright (C) 2017 J08nY
 */
#include "gp.h"
#include "exhaustive/arg.h"
#include "io/output.h"
#include "point.h"
#include "seed.h"
#include "util/bits.h"

static point_t **gp_points(const curve_t *curve, GEN point_vec) {
	long len = glength(point_vec);
	point_t **result = points_new((size_t)len);

	for (long i = 1; i <= len; ++i) {
		point_t *point = point_new();
		point->point = gel(point_vec, i);
		point->order = ellorder(curve->curve, point->point, NULL);
		result[i - 1] = point;
	}
	return result;
}

static point_t **gp_gens(const curve_t *curve, GEN gens_vec) {
	point_t **result = gp_points(curve, gens_vec);

	long len = glength(gens_vec);
	for (long i = 1; i <= len; ++i) {
		point_t *gen = result[i - 1];
		gen->cofactor = divii(curve->order, gen->order);
	}
	return result;
}

GENERATOR(gp_gen) {
	HAS_ARG(args);
	pari_sp ltop = avma;
	GEN closure = compile_str(args->args);
	GEN params = zerovec(state - OFFSET_SEED);

	if (state > OFFSET_SEED) {
		if (curve->seed && curve->seed->seed) {
			gel(params, 1) = bits_to_bitvec(curve->seed->seed);
		}
	}

	if (state > OFFSET_FIELD) {
		gel(params, 2) = curve->field;
	}

	if (state > OFFSET_A) {
		gel(params, 3) = curve->a;
	}

	if (state > OFFSET_B) {
		gel(params, 4) = curve->b;
	}

	if (state > OFFSET_CURVE) {
		gel(params, 5) = curve->curve;
	}

	if (state > OFFSET_ORDER) {
		gel(params, 6) = curve->order;
	}

	if (state > OFFSET_GENERATORS) {
		GEN gens = zerovec(curve->ngens);
		for (size_t i = 0; i < curve->ngens; ++i) {
			gel(gens, i + 1) = curve->generators[i]->point;
		}
		gel(params, 7) = gens;
	}

	if (state > OFFSET_POINTS) {
		GEN points = zerovec(curve->npoints);
		for (size_t i = 0; i < curve->npoints; ++i) {
			gel(points, i + 1) = curve->points[i]->point;
		}
		gel(params, 8) = points;
	}

	GEN res = call0(closure, zerovec(0));
	res = call0(res, params);

	res = gerepileupto(ltop, res);
	switch (state) {
		case OFFSET_SEED:
			curve->seed = seed_new();
			curve->seed->seed = bits_from_bitvec(res);
			break;
		case OFFSET_FIELD:
			curve->field = res;
			break;
		case OFFSET_A:
			curve->a = res;
			break;
		case OFFSET_B:
			curve->b = res;
			break;
		case OFFSET_CURVE:
			curve->curve = res;
			break;
		case OFFSET_ORDER:
			curve->order = res;
			break;
		case OFFSET_GENERATORS:
			curve->ngens = (size_t)glength(res);
			curve->generators = gp_gens(curve, res);
			break;
		case OFFSET_POINTS:
			curve->npoints = (size_t)glength(res);
			curve->points = gp_points(curve, res);
			break;
		case OFFSET_END:
			break;
	}
	return 1;
}