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