1 //==============================================================================================
2 //
3 //	This file is part of LiDIA --- a library for computational number theory
4 //
5 //	Copyright (c) 1994--2001 the LiDIA Group.  All rights reserved.
6 //
7 //	See http://www.informatik.tu-darmstadt.de/TI/LiDIA/
8 //
9 //----------------------------------------------------------------------------------------------
10 //
11 //	$Id$
12 //
13 //	Author	: Victor Shoup (VS), Thomas Pfahler (TPf)
14 //	Changes	: See CVS log
15 //
16 //==============================================================================================
17 
18 
19 #ifdef HAVE_CONFIG_H
20 # include	"config.h"
21 #endif
22 #include	"LiDIA/finite_fields/Fp_polynomial_util.h"
23 #include	"LiDIA/Fp_poly_multiplier.h"
24 
25 
26 
27 #ifdef LIDIA_NAMESPACE
28 namespace LiDIA {
29 #endif
30 
31 
32 
33 //******************************************************************
34 //
35 //			class poly_argument
36 //
37 //*******************************************************************
38 
39 lidia_size_t poly_argument::poly_arg_bound = 0;
40 bool poly_argument::change_enable = true;
41 
set_poly_arg_bound(lidia_size_t n)42 void poly_argument::set_poly_arg_bound(lidia_size_t n)
43 {
44 	//this value can only be changed if no poly_arguments have been
45 	//declared yet
46 	debug_handler("poly_argument", "set_poly_arg_bound(lidia_size_t)");
47 	if (change_enable == true) {
48 		poly_arg_bound = n;
49 		change_enable = false;
50 	}
51 	else
52 		lidia_error_handler("poly_argument", "set_poly_arg_bound"
53 				    "(lidia_size_t)::poly_arg_bound can only be set before "
54 				    "declaring any poly_arguments");
55 }
56 
57 
58 
59 // The routine poly_argument::build (see below) which is implicitly called
60 // by the various compose and update_map routines builds a table
61 // of polynomials.  If poly_arg_bound > 0, then only up to
62 // about poly_arg_bound bigmod's are allocated.  Setting this too
63 // low may lead to slower execution.
64 // If poly_arg_bound <= 0, then it is ignored, and space is allocated
65 // so as to maximize speed.
66 // Initially, poly_arg_bound = 0.
67 
68 // If a single h is going to be used with many g's
69 // then you should build a poly_argument for h,
70 // and then use the compose routine below.
71 // poly_argument::build computes and stores h, h^2, ..., h^m mod f.
72 // After this pre-computation, composing a polynomial of degree
73 // roughly n with h takes n/m multiplies mod f, plus n^2
74 // scalar multiplies.
75 // Thus, increasing m increases the space requirement and the pre-computation
76 // time, but reduces the composition time.
77 // If poly_arg_bound > 0, a table of size less than m may be built.
78 
79 // m must be > 0, otherwise an error is raised
80 
build(const Fp_polynomial & h,const Fp_poly_modulus & F,lidia_size_t m)81 void poly_argument::build(const Fp_polynomial& h, const Fp_poly_modulus& F, lidia_size_t m)
82 {
83 	debug_handler("poly_argument", "build (Fp_polynomial&, Fp_poly_modulus&, lidia_size_t)");
84 
85 	const Fp_polynomial &f = F.modulus();
86 	h.comp_modulus(f, "poly_argument::build");
87 
88 	if (m <= 0) {
89 		lidia_error_handler("poly_argument", "build (Fp_polynomial&, "
90 				    "Fp_poly_modulus&, lidia_size_t)::bad args");
91 		return;
92 	}
93 
94 
95 	if (poly_arg_bound > 0) {
96 		m = comparator< lidia_size_t >::min(m, poly_arg_bound/f.degree());
97 		m = comparator< lidia_size_t >::max(m, 1);
98 	}
99 
100 	Fp_poly_multiplier M;
101 	if (h.degree() < f.degree())
102 		M.build(h, F);
103 	else {
104 		Fp_polynomial tmp;
105 		remainder(tmp, h, F);
106 		M.build(tmp, F);
107 	}
108 
109 	if (H.capacity() < m+1)
110 		H.set_capacity(m+1);
111 	H.set_size(m+1);
112 
113 	H[0].set_modulus(h);
114 	(H[0]).assign_one();
115 	H[1].assign(h);
116 
117 	lidia_size_t i;
118 	for (i = 2; i <= m; i++)
119 		multiply(H[i], H[i-1], M, F); //Fp_poly_multiplier
120 }
121 
122 
123 
124 //***************************************************************
125 //
126 //                      compose
127 //
128 //****************************************************************
129 
compose(Fp_polynomial & x,const Fp_polynomial & g,const Fp_poly_modulus & F) const130 void poly_argument::compose(Fp_polynomial& x, const Fp_polynomial& g,
131 			    const Fp_poly_modulus& F) const
132 {
133 	debug_handler("poly_argument", "compose(Fp_polynomial&, Fp_polynomial&, Fp_poly_modulus&)");
134 
135 	g.comp_modulus(F.modulus(), "poly_argument::compose");
136 
137 	if (g.degree() <= 0) {
138 		x.assign(g);
139 		return;
140 	}
141 
142 	Fp_polynomial s, t;
143 	lidia_size_t n = F.modulus().degree();
144 
145 	bigint *scratch = new bigint[n];
146 	memory_handler(scratch, "poly_argument",
147 		       "compose :: Error in memory allocation");
148 
149 	lidia_size_t m = H.size() - 1;
150 	lidia_size_t l = ((g.degree()+m)/m) - 1;
151 
152 	Fp_poly_multiplier M(H[m], F);
153 
154 	compose_InnerProd(t, g, l*m, l*m + m - 1, H, n, scratch);
155 
156 	lidia_size_t i;
157 	for (i = l-1; i >= 0; i--) {
158 		compose_InnerProd(s, g, i*m, i*m + m - 1, H, n, scratch);
159 		multiply(t, t, M, F); //Fp_poly_multiplier
160 		add(t, t, s);
161 	}
162 
163 	delete[] scratch;
164 	x.assign(t);
165 }
166 
167 
168 
compose_InnerProd(Fp_polynomial & x,const Fp_polynomial & v,lidia_size_t low,lidia_size_t high,const base_vector<Fp_polynomial> & H,lidia_size_t n,bigint * t)169 void poly_argument::compose_InnerProd(Fp_polynomial& x,
170 				      const Fp_polynomial &v, lidia_size_t low, lidia_size_t high,
171 				      const base_vector< Fp_polynomial > & H, lidia_size_t n, bigint * t)
172 	// only used in compose
173 	// assumes t.size() >= n
174 {
175 	debug_handler("poly_argument", "compose_InnerProduct(Fp_polynomial&, Fp_polynomial&, lidia_size_t, lidia_size_t, base_vector< Fp_polynomial > &, lidia_size_t, bigint*)");
176 
177 	if (H.size() == 0) {
178 		lidia_error_handler("poly_argument",
179 				    "compose_InnerProduct(...)::wrong argument size");
180 		return;
181 	}
182 
183 	bigint s; //static
184 	const bigint &p = H[0].modulus();
185 	lidia_size_t i, j;
186 
187 	for (j = 0; j < n; j++)
188 		t[j].assign_zero();
189 
190 	high = comparator< lidia_size_t >::min(high, v.degree());
191 	for (i = low; i <= high; i++) {
192 		const bigint* h = H[i-low].coeff;
193 		lidia_size_t m = H[i-low].c_length;
194 
195 		const bigint & w = v.coeff[i];
196 
197 		for (j = 0; j < m; j++) {
198 			multiply(s, w, h[j]);
199 			add(t[j], t[j], s);
200 		}
201 	}
202 
203 	x.set_modulus(p);
204 	x.set_degree(n-1);
205 	for (j = 0; j < n; j++)
206 		Remainder(x.coeff[j], t[j], p);
207 	x.remove_leading_zeros();
208 }
209 
210 
211 
212 #ifdef LIDIA_NAMESPACE
213 }	// end of namespace LiDIA
214 #endif
215