├── .gitignore
├── LICENSE
├── Makefile
├── README.md
├── bls.c
├── bls.h
├── bn.c
├── bn.h
├── config.h
├── dh.c
├── dh.h
├── ec.c
├── ec.h
├── ec_pqr.c
├── ec_pqr.h
├── ecdsa.c
├── ecdsa.h
├── ecnr.c
├── ecnr.h
├── inr.c
├── inr.h
├── mt19937.c
├── mt19937.h
├── pairing.c
├── pairing.h
├── pc.c
├── pc.h
├── pcnr.c
├── pcnr.h
├── poly.c
├── poly.h
├── pqr.c
├── pqr.h
├── ssecrets.c
├── ssecrets.h
└── tests
├── test_prq.c
├── test_rsa.c
└── test_rsa_tiny.c
/.gitignore:
--------------------------------------------------------------------------------
1 | *.swp
2 | *.swo
3 | *.o
4 | *.a
5 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | GNU GENERAL PUBLIC LICENSE
2 | Version 2, June 1991
3 |
4 | Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
5 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
6 | Everyone is permitted to copy and distribute verbatim copies
7 | of this license document, but changing it is not allowed.
8 |
9 | Preamble
10 |
11 | The licenses for most software are designed to take away your
12 | freedom to share and change it. By contrast, the GNU General Public
13 | License is intended to guarantee your freedom to share and change free
14 | software--to make sure the software is free for all its users. This
15 | General Public License applies to most of the Free Software
16 | Foundation's software and to any other program whose authors commit to
17 | using it. (Some other Free Software Foundation software is covered by
18 | the GNU Lesser General Public License instead.) You can apply it to
19 | your programs, too.
20 |
21 | When we speak of free software, we are referring to freedom, not
22 | price. Our General Public Licenses are designed to make sure that you
23 | have the freedom to distribute copies of free software (and charge for
24 | this service if you wish), that you receive source code or can get it
25 | if you want it, that you can change the software or use pieces of it
26 | in new free programs; and that you know you can do these things.
27 |
28 | To protect your rights, we need to make restrictions that forbid
29 | anyone to deny you these rights or to ask you to surrender the rights.
30 | These restrictions translate to certain responsibilities for you if you
31 | distribute copies of the software, or if you modify it.
32 |
33 | For example, if you distribute copies of such a program, whether
34 | gratis or for a fee, you must give the recipients all the rights that
35 | you have. You must make sure that they, too, receive or can get the
36 | source code. And you must show them these terms so they know their
37 | rights.
38 |
39 | We protect your rights with two steps: (1) copyright the software, and
40 | (2) offer you this license which gives you legal permission to copy,
41 | distribute and/or modify the software.
42 |
43 | Also, for each author's protection and ours, we want to make certain
44 | that everyone understands that there is no warranty for this free
45 | software. If the software is modified by someone else and passed on, we
46 | want its recipients to know that what they have is not the original, so
47 | that any problems introduced by others will not reflect on the original
48 | authors' reputations.
49 |
50 | Finally, any free program is threatened constantly by software
51 | patents. We wish to avoid the danger that redistributors of a free
52 | program will individually obtain patent licenses, in effect making the
53 | program proprietary. To prevent this, we have made it clear that any
54 | patent must be licensed for everyone's free use or not licensed at all.
55 |
56 | The precise terms and conditions for copying, distribution and
57 | modification follow.
58 |
59 | GNU GENERAL PUBLIC LICENSE
60 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
61 |
62 | 0. This License applies to any program or other work which contains
63 | a notice placed by the copyright holder saying it may be distributed
64 | under the terms of this General Public License. The "Program", below,
65 | refers to any such program or work, and a "work based on the Program"
66 | means either the Program or any derivative work under copyright law:
67 | that is to say, a work containing the Program or a portion of it,
68 | either verbatim or with modifications and/or translated into another
69 | language. (Hereinafter, translation is included without limitation in
70 | the term "modification".) Each licensee is addressed as "you".
71 |
72 | Activities other than copying, distribution and modification are not
73 | covered by this License; they are outside its scope. The act of
74 | running the Program is not restricted, and the output from the Program
75 | is covered only if its contents constitute a work based on the
76 | Program (independent of having been made by running the Program).
77 | Whether that is true depends on what the Program does.
78 |
79 | 1. You may copy and distribute verbatim copies of the Program's
80 | source code as you receive it, in any medium, provided that you
81 | conspicuously and appropriately publish on each copy an appropriate
82 | copyright notice and disclaimer of warranty; keep intact all the
83 | notices that refer to this License and to the absence of any warranty;
84 | and give any other recipients of the Program a copy of this License
85 | along with the Program.
86 |
87 | You may charge a fee for the physical act of transferring a copy, and
88 | you may at your option offer warranty protection in exchange for a fee.
89 |
90 | 2. You may modify your copy or copies of the Program or any portion
91 | of it, thus forming a work based on the Program, and copy and
92 | distribute such modifications or work under the terms of Section 1
93 | above, provided that you also meet all of these conditions:
94 |
95 | a) You must cause the modified files to carry prominent notices
96 | stating that you changed the files and the date of any change.
97 |
98 | b) You must cause any work that you distribute or publish, that in
99 | whole or in part contains or is derived from the Program or any
100 | part thereof, to be licensed as a whole at no charge to all third
101 | parties under the terms of this License.
102 |
103 | c) If the modified program normally reads commands interactively
104 | when run, you must cause it, when started running for such
105 | interactive use in the most ordinary way, to print or display an
106 | announcement including an appropriate copyright notice and a
107 | notice that there is no warranty (or else, saying that you provide
108 | a warranty) and that users may redistribute the program under
109 | these conditions, and telling the user how to view a copy of this
110 | License. (Exception: if the Program itself is interactive but
111 | does not normally print such an announcement, your work based on
112 | the Program is not required to print an announcement.)
113 |
114 | These requirements apply to the modified work as a whole. If
115 | identifiable sections of that work are not derived from the Program,
116 | and can be reasonably considered independent and separate works in
117 | themselves, then this License, and its terms, do not apply to those
118 | sections when you distribute them as separate works. But when you
119 | distribute the same sections as part of a whole which is a work based
120 | on the Program, the distribution of the whole must be on the terms of
121 | this License, whose permissions for other licensees extend to the
122 | entire whole, and thus to each and every part regardless of who wrote it.
123 |
124 | Thus, it is not the intent of this section to claim rights or contest
125 | your rights to work written entirely by you; rather, the intent is to
126 | exercise the right to control the distribution of derivative or
127 | collective works based on the Program.
128 |
129 | In addition, mere aggregation of another work not based on the Program
130 | with the Program (or with a work based on the Program) on a volume of
131 | a storage or distribution medium does not bring the other work under
132 | the scope of this License.
133 |
134 | 3. You may copy and distribute the Program (or a work based on it,
135 | under Section 2) in object code or executable form under the terms of
136 | Sections 1 and 2 above provided that you also do one of the following:
137 |
138 | a) Accompany it with the complete corresponding machine-readable
139 | source code, which must be distributed under the terms of Sections
140 | 1 and 2 above on a medium customarily used for software interchange; or,
141 |
142 | b) Accompany it with a written offer, valid for at least three
143 | years, to give any third party, for a charge no more than your
144 | cost of physically performing source distribution, a complete
145 | machine-readable copy of the corresponding source code, to be
146 | distributed under the terms of Sections 1 and 2 above on a medium
147 | customarily used for software interchange; or,
148 |
149 | c) Accompany it with the information you received as to the offer
150 | to distribute corresponding source code. (This alternative is
151 | allowed only for noncommercial distribution and only if you
152 | received the program in object code or executable form with such
153 | an offer, in accord with Subsection b above.)
154 |
155 | The source code for a work means the preferred form of the work for
156 | making modifications to it. For an executable work, complete source
157 | code means all the source code for all modules it contains, plus any
158 | associated interface definition files, plus the scripts used to
159 | control compilation and installation of the executable. However, as a
160 | special exception, the source code distributed need not include
161 | anything that is normally distributed (in either source or binary
162 | form) with the major components (compiler, kernel, and so on) of the
163 | operating system on which the executable runs, unless that component
164 | itself accompanies the executable.
165 |
166 | If distribution of executable or object code is made by offering
167 | access to copy from a designated place, then offering equivalent
168 | access to copy the source code from the same place counts as
169 | distribution of the source code, even though third parties are not
170 | compelled to copy the source along with the object code.
171 |
172 | 4. You may not copy, modify, sublicense, or distribute the Program
173 | except as expressly provided under this License. Any attempt
174 | otherwise to copy, modify, sublicense or distribute the Program is
175 | void, and will automatically terminate your rights under this License.
176 | However, parties who have received copies, or rights, from you under
177 | this License will not have their licenses terminated so long as such
178 | parties remain in full compliance.
179 |
180 | 5. You are not required to accept this License, since you have not
181 | signed it. However, nothing else grants you permission to modify or
182 | distribute the Program or its derivative works. These actions are
183 | prohibited by law if you do not accept this License. Therefore, by
184 | modifying or distributing the Program (or any work based on the
185 | Program), you indicate your acceptance of this License to do so, and
186 | all its terms and conditions for copying, distributing or modifying
187 | the Program or works based on it.
188 |
189 | 6. Each time you redistribute the Program (or any work based on the
190 | Program), the recipient automatically receives a license from the
191 | original licensor to copy, distribute or modify the Program subject to
192 | these terms and conditions. You may not impose any further
193 | restrictions on the recipients' exercise of the rights granted herein.
194 | You are not responsible for enforcing compliance by third parties to
195 | this License.
196 |
197 | 7. If, as a consequence of a court judgment or allegation of patent
198 | infringement or for any other reason (not limited to patent issues),
199 | conditions are imposed on you (whether by court order, agreement or
200 | otherwise) that contradict the conditions of this License, they do not
201 | excuse you from the conditions of this License. If you cannot
202 | distribute so as to satisfy simultaneously your obligations under this
203 | License and any other pertinent obligations, then as a consequence you
204 | may not distribute the Program at all. For example, if a patent
205 | license would not permit royalty-free redistribution of the Program by
206 | all those who receive copies directly or indirectly through you, then
207 | the only way you could satisfy both it and this License would be to
208 | refrain entirely from distribution of the Program.
209 |
210 | If any portion of this section is held invalid or unenforceable under
211 | any particular circumstance, the balance of the section is intended to
212 | apply and the section as a whole is intended to apply in other
213 | circumstances.
214 |
215 | It is not the purpose of this section to induce you to infringe any
216 | patents or other property right claims or to contest validity of any
217 | such claims; this section has the sole purpose of protecting the
218 | integrity of the free software distribution system, which is
219 | implemented by public license practices. Many people have made
220 | generous contributions to the wide range of software distributed
221 | through that system in reliance on consistent application of that
222 | system; it is up to the author/donor to decide if he or she is willing
223 | to distribute software through any other system and a licensee cannot
224 | impose that choice.
225 |
226 | This section is intended to make thoroughly clear what is believed to
227 | be a consequence of the rest of this License.
228 |
229 | 8. If the distribution and/or use of the Program is restricted in
230 | certain countries either by patents or by copyrighted interfaces, the
231 | original copyright holder who places the Program under this License
232 | may add an explicit geographical distribution limitation excluding
233 | those countries, so that distribution is permitted only in or among
234 | countries not thus excluded. In such case, this License incorporates
235 | the limitation as if written in the body of this License.
236 |
237 | 9. The Free Software Foundation may publish revised and/or new versions
238 | of the General Public License from time to time. Such new versions will
239 | be similar in spirit to the present version, but may differ in detail to
240 | address new problems or concerns.
241 |
242 | Each version is given a distinguishing version number. If the Program
243 | specifies a version number of this License which applies to it and "any
244 | later version", you have the option of following the terms and conditions
245 | either of that version or of any later version published by the Free
246 | Software Foundation. If the Program does not specify a version number of
247 | this License, you may choose any version ever published by the Free Software
248 | Foundation.
249 |
250 | 10. If you wish to incorporate parts of the Program into other free
251 | programs whose distribution conditions are different, write to the author
252 | to ask for permission. For software which is copyrighted by the Free
253 | Software Foundation, write to the Free Software Foundation; we sometimes
254 | make exceptions for this. Our decision will be guided by the two goals
255 | of preserving the free status of all derivatives of our free software and
256 | of promoting the sharing and reuse of software generally.
257 |
258 | NO WARRANTY
259 |
260 | 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
261 | FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
262 | OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
263 | PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
264 | OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
265 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
266 | TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
267 | PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
268 | REPAIR OR CORRECTION.
269 |
270 | 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
271 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
272 | REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
273 | INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
274 | OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
275 | TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
276 | YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
277 | PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
278 | POSSIBILITY OF SUCH DAMAGES.
279 |
280 | END OF TERMS AND CONDITIONS
281 |
282 | How to Apply These Terms to Your New Programs
283 |
284 | If you develop a new program, and you want it to be of the greatest
285 | possible use to the public, the best way to achieve this is to make it
286 | free software which everyone can redistribute and change under these terms.
287 |
288 | To do so, attach the following notices to the program. It is safest
289 | to attach them to the start of each source file to most effectively
290 | convey the exclusion of warranty; and each file should have at least
291 | the "copyright" line and a pointer to where the full notice is found.
292 |
293 | {description}
294 | Copyright (C) {year} {fullname}
295 |
296 | This program is free software; you can redistribute it and/or modify
297 | it under the terms of the GNU General Public License as published by
298 | the Free Software Foundation; either version 2 of the License, or
299 | (at your option) any later version.
300 |
301 | This program is distributed in the hope that it will be useful,
302 | but WITHOUT ANY WARRANTY; without even the implied warranty of
303 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
304 | GNU General Public License for more details.
305 |
306 | You should have received a copy of the GNU General Public License along
307 | with this program; if not, write to the Free Software Foundation, Inc.,
308 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
309 |
310 | Also add information on how to contact you by electronic and paper mail.
311 |
312 | If the program is interactive, make it output a short notice like this
313 | when it starts in an interactive mode:
314 |
315 | Gnomovision version 69, Copyright (C) year name of author
316 | Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
317 | This is free software, and you are welcome to redistribute it
318 | under certain conditions; type `show c' for details.
319 |
320 | The hypothetical commands `show w' and `show c' should show the appropriate
321 | parts of the General Public License. Of course, the commands you use may
322 | be called something other than `show w' and `show c'; they could even be
323 | mouse-clicks or menu items--whatever suits your program.
324 |
325 | You should also get your employer (if you work as a programmer) or your
326 | school, if any, to sign a "copyright disclaimer" for the program, if
327 | necessary. Here is a sample; alter the names:
328 |
329 | Yoyodyne, Inc., hereby disclaims all copyright interest in the program
330 | `Gnomovision' (which makes passes at compilers) written by James Hacker.
331 |
332 | {signature of Ty Coon}, 1 April 1989
333 | Ty Coon, President of Vice
334 |
335 | This General Public License does not permit incorporating your program into
336 | proprietary programs. If your program is a subroutine library, you may
337 | consider it more useful to permit linking proprietary applications with the
338 | library. If this is what you want to do, use the GNU Lesser General
339 | Public License instead of this License.
340 |
--------------------------------------------------------------------------------
/Makefile:
--------------------------------------------------------------------------------
1 | #PREFIX := x86_64-w64-mingw32-
2 | PREFIX :=
3 |
4 | #CC := $(PREFIX)gcc
5 | CC := $(PREFIX)clang
6 | AR := $(PREFIX)ar
7 |
8 | SRCS := bn.c ec.c dh.c ecdsa.c poly.c mt19937.c ecnr.c inr.c pc.c pcnr.c pqr.c ssecrets.c bls.c pairing.c
9 | OBJS := $(SRCS:.c=.o)
10 |
11 | CFLAGS := -Os -ffunction-sections -fdata-sections -Wall -Wno-unused-function -DNDEBUG
12 |
13 | # On osx use
14 | # LDFLAGS := -dead_strip
15 |
16 | LDFLAGS := -Wl,--gc-sections
17 |
18 | all: libfinite.a
19 |
20 | clean:
21 | rm -f ./*.o ./*.a
22 |
23 | libfinite.a: $(OBJS)
24 | $(AR) rcs $@ $^
25 |
26 | %.o: %.c
27 | $(CC) -c $(CFLAGS) $< -o $@
28 |
29 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | ## libfinite
2 |
3 | ```
4 | Copyright 2016 naehrwert
5 | Copyright 2016 Luka Malisa
6 | Licensed under the terms of the GNU GPL, version 2
7 | http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
8 | ```
9 |
10 | ### Introduction
11 |
12 | `libfinite` is a small and fast bignum library. In our tests (timing modular exponentiation, with modulus of 4096 bits), `libfinite` was only 3 (if compiled with clang), or 4 times slower (if compiled with gcc) than a [libgmp](https://gmplib.org/) and [OpenSSL](https://www.openssl.org/) implementation. Not bad for an example that compiles to ~5KB of code! Furthermore, `libfinite` can be compiled with arbitrary limb sizes. For example, if you need this code to run on a 16 bit processor, you could set `BN_LIMB_SIZE` to 8 in `config.h`. However, if you want maximum speed, use `BN_LIMB_SIZE` of 64.
13 |
14 | ##### `bn.c`
15 | Bignum library for arithmetic in Z/nZ (the positive half, since we don't care about signs) which can also be used to describe operations over some finite field GF(p) (F_p). Note that in some of the cases below, the use of a finite field can be substituted for a more general Z/nZ.
16 |
17 | ##### `dh.c`
18 | This implements Diffie-Hellman key exchange.
19 |
20 | ##### `ec.c`
21 | Given an elliptic curve in Weierstrass form (y^2 = x^3 + ax + b) over a finite field, this gives a representation of the group of points on the elliptic curve, i.e. point addition, point doubling, multiplication by a number.
22 |
23 | ##### `ecdsa.c`
24 | This implements the Elliptic Curve Digital Signature Algorithm (ECDSA).
25 |
26 | ##### `ecnr.c`
27 | This implements Elliptic Curve Nyberg Rueppel (ECNR), the Nyberg-Rueppel signature scheme over the elliptic curve group.
28 |
29 | ##### `inr.c`
30 | This implements the Nyberg-Rueppel signature scheme over a finite field.
31 |
32 | ##### `pc.c`
33 | Given a Pell conic (x^2 - Dy^2 = 1) over a finite field, this gives a representation of the group of points on the Pell conic, i.e. point addition, multiplication by a number.
34 | Assuming the finite field is F_p, the parameter D should be a non-square in the field since then the group is known to be isomorphic to the multiplicative subgroup of F_p^2. Otherwise it will simply be isomorphic to the multiplicative subgroup of F_p.
35 |
36 | ##### `pcnr.c`
37 | This implements Pell Conic Nyberg Rueppel (PCNR), the Nyberg-Rueppel signature scheme over the Pell conic group.
38 |
39 | ##### `poly.c`
40 | This implements operations for the ring of polynomials R over some finite field F_p (R = F_p[X]), i.e. addition, subtraction, multiplication, division and remainder.
41 |
42 | ##### `pqr.c`
43 | Given a polynomial ring R and a polynomial I in R, this implements operations for the polynomial quotient ring R/(I), i.e. addition, subtraction, multiplication, inversion, exponentiation. This can be used to construct a representation of certain finite fields, e.g. F_q where q = p^n, p prime, n some positive integer, i.e. take I to be an irreducible polynomial of degree n over the finite field F_p.
44 |
45 | ##### `ssecrets.c`
46 | This implements Shamir's Secret Sharing.
47 |
48 | ### Examples
49 |
50 | TODO
51 |
--------------------------------------------------------------------------------
/bls.c:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2016 naehrwert
3 | * Licensed under the terms of the GNU GPL, version 2
4 | * http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
5 | */
6 |
7 | #include "bls.h"
8 | #include "pairing.h"
9 |
10 | /*
11 | * BLS:
12 | * pairing e: G1 x G2 -> GT (all of order r)
13 | * private parameters:
14 | * x \in [0, r - 1] (random)
15 | * public parameters:
16 | * G (a generator point of G2)
17 | * P = [x]G
18 | * signing a message m:
19 | * h = H(m) (e.g. H(m) = [m]Q where Q is a generator point of G1)
20 | * S = [x]h (the signature)
21 | * verification of a signature S:
22 | * e(S,G) == e(H(m),P)
23 | */
24 |
25 | void bls_sign(bls_ctxt_t *ctxt, ec_pqr_point_t *sig, bn_t *m)
26 | {
27 | //S = [k]H(m)
28 | ec_pqr_point_mul(sig, m, ctxt->G1, ctxt->ecg);
29 | ec_pqr_point_mul(sig, ctxt->k, sig, ctxt->ecg);
30 | }
31 |
32 | int bls_verify(bls_ctxt_t *ctxt, ec_pqr_point_t *sig, bn_t *m)
33 | {
34 | int res = 0;
35 |
36 | poly_t *a = poly_alloc(ctxt->ecg->p->degree - 1, ctxt->p, 1);
37 | poly_t *b = poly_alloc(ctxt->ecg->p->degree - 1, ctxt->p, 1);
38 | ec_pqr_point_t *P = ec_pqr_point_alloc(ctxt->ecg);
39 |
40 | //e(H(m), P)
41 | ec_pqr_point_mul(P, m, ctxt->G1, ctxt->ecg);
42 | pairing_weil(a, P, ctxt->P, ctxt->r, ctxt->ecg);
43 | //e(S, G)
44 | pairing_weil(b, sig, ctxt->G2, ctxt->r, ctxt->ecg);
45 |
46 | res = (poly_cmp(a, b) == POLY_CMP_E ? 1 : 0);
47 |
48 | ec_pqr_point_free(P);
49 | poly_free(b, 1);
50 | poly_free(a, 1);
51 |
52 | return res;
53 | }
54 |
--------------------------------------------------------------------------------
/bls.h:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2016 naehrwert
3 | * Licensed under the terms of the GNU GPL, version 2
4 | * http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
5 | */
6 |
7 | #ifndef _BLS_H_
8 | #define _BLS_H_
9 |
10 | #include "ec_pqr.h"
11 |
12 | typedef struct _bls_ctxt_t
13 | {
14 | /*! Base field prime. */
15 | bn_t *p;
16 | /*! Elliptic curve group. */
17 | ec_pqr_group_t *ecg;
18 | /*! Generator point G1 (in E/GF(p)). */
19 | ec_pqr_point_t *G1;
20 | /*! Generator point G2 (in E/GF(p^12)). */
21 | ec_pqr_point_t *G2;
22 | /*! Group order r (for both points). */
23 | bn_t *r;
24 | /*! Public point P. */
25 | ec_pqr_point_t *P;
26 | /*! Private k. */
27 | bn_t *k;
28 | } bls_ctxt_t;
29 |
30 | void bls_sign(bls_ctxt_t *ctxt, ec_pqr_point_t *sig, bn_t *m);
31 | int bls_verify(bls_ctxt_t *ctxt, ec_pqr_point_t *sig, bn_t *m);
32 |
33 | #endif
34 |
--------------------------------------------------------------------------------
/bn.c:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2016 Luka Malisa
3 | * Licensed under the terms of the GNU GPL, version 2
4 | * http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
5 | */
6 |
7 | #if !defined(NAKED)
8 | #include
9 | #include
10 | #include
11 | #include
12 | #include
13 | #include
14 | #include
15 |
16 | #if defined(_WIN32) || defined(_MSC_VER)
17 | #include
18 | #endif
19 | #endif
20 |
21 | #include "bn.h"
22 |
23 | // Fast Montgomery initialization (taken from PolarSSL)
24 | static void _bn_mon_init(bn_t *n)
25 | {
26 | ul_t x, m0 = n->l[0];
27 |
28 | x = m0;
29 | x += ((m0 + 2) & 4) << 1;
30 |
31 | for(int i = BN_LIMB_BITS; i >= 8; i /= 2)
32 | x *= (2 - (m0 * x));
33 |
34 | n->mp = ~x + 1;
35 | }
36 |
37 | static u8 _bn_str_to_u8(const s8 *str)
38 | {
39 | u32 i = 2;
40 | u8 t, res = 0;
41 | u8 c;
42 |
43 | while(i--)
44 | {
45 | c = *str++;
46 | if(c >= '0' && c <= '9')
47 | t = c - '0';
48 | else if(c >= 'a' && c <= 'f')
49 | t = c - 'a' + 10;
50 | else if(c >= 'A' && c <= 'F')
51 | t = c - 'A' + 10;
52 | else
53 | t = 0;
54 | res |= t << (i * 4);
55 | }
56 |
57 | return res;
58 | }
59 |
60 | static int _bn_add(bn_t *d, bn_t *a, bn_t *b)
61 | {
62 | ull_t C = 0;
63 |
64 | // assert(a->n == b->n);
65 |
66 | for(int i = 0; i < MIN(a->n_limbs, b->n_limbs); i++)
67 | {
68 | C += (ull_t)a->l[i] + b->l[i];
69 | d->l[i] = C;
70 |
71 | C >>= BN_LIMB_BITS;
72 | }
73 |
74 | return C;
75 | }
76 |
77 | static int _bn_add_ui(bn_t *d, bn_t *a, ul_t b)
78 | {
79 | ull_t C = b;
80 |
81 | for(int i = 0; i < a->n_limbs; i++)
82 | {
83 | C += (ull_t)a->l[i];
84 | d->l[i] = C;
85 |
86 | C >>= BN_LIMB_BITS;
87 | }
88 |
89 | return C;
90 | }
91 |
92 | static int _bn_sub(bn_t *d, bn_t *a, bn_t *b)
93 | {
94 | ull_t C = 1;
95 |
96 | // assert(a->n == b->n);
97 |
98 | for(int i = 0; i < MIN(a->n_limbs, b->n_limbs); i++)
99 | {
100 | C += (ull_t)a->l[i] + BN_MAX_DIGIT - b->l[i];
101 | d->l[i] = C;
102 |
103 | C >>= BN_LIMB_BITS;
104 | }
105 |
106 | return 1 - C;
107 | }
108 |
109 | static int _bn_sub_ui(bn_t *d, bn_t *a, ul_t b)
110 | {
111 | ull_t C = 1 + BN_MAX_DIGIT - b;
112 |
113 | for(int i = 0; i < a->n_limbs; i++)
114 | {
115 | C += (ull_t)a->l[i];
116 | d->l[i] = C;
117 |
118 | C >>= BN_LIMB_BITS;
119 | }
120 |
121 | return 1 - C;
122 | }
123 |
124 | // Runtime endianess detection. A bit slower, but no macro magic needed
125 | static int _bn_big_endian()
126 | {
127 | u32 t = 0x11223344;
128 | u8 *p = (u8 *)&t;
129 |
130 | if(p[0] == 0x11)
131 | return 1;
132 | else
133 | return 0;
134 | }
135 |
136 | static bn_t *_bn_lshift_limbs(bn_t *a, int n)
137 | {
138 | int i;
139 |
140 | for(i = a->n_limbs; i >= n; i--)
141 | a->l[i] = a->l[i-n];
142 |
143 | while(i >= 0)
144 | a->l[i--] = 0;
145 |
146 | return a;
147 | }
148 |
149 | static bn_t *_bn_lshift(bn_t *a, int b)
150 | {
151 | ul_t mask = -1;
152 | ul_t prev_c = 0;
153 | ul_t c = 0;
154 |
155 | if(b != BN_LIMB_BITS)
156 | mask = ~(mask >> b);
157 |
158 | for(int x = 0; x < a->n_limbs; x++)
159 | {
160 | c = a->l[x] & mask;
161 |
162 | // Shift left by amount
163 | a->l[x] <<= b;
164 |
165 | // Add the carry part from the previous limb
166 | a->l[x] |= prev_c >> (BN_LIMB_BITS - b);
167 |
168 | prev_c = c;
169 | }
170 |
171 | return a;
172 | }
173 |
174 | static bn_t *_bn_rshift_limbs(bn_t *a, int n)
175 | {
176 | // Makes the code run faster
177 | memmove(a->l, &a->l[n], (a->n_limbs - n) * BN_LIMB_BYTES);
178 |
179 | /*
180 | int x;
181 |
182 | for(x = 0; x < a->n_limbs - n; x++)
183 | a->l[x] = a->l[x+n];
184 |
185 | while(x <= n)
186 | a->l[x++] = 0;
187 | */
188 | return a;
189 | }
190 |
191 | static bn_t *_bn_rshift(bn_t *a, int b)
192 | {
193 | ull_t mask;
194 | ul_t prev_c = 0;
195 | ul_t c = 0;
196 |
197 | // Create the mask
198 | mask = ((ull_t)1 << b) - 1;
199 |
200 | for(int x = a->n_limbs - 1; x >= 0; x--)
201 | {
202 | c = a->l[x] & mask;
203 |
204 | // Shift right by amount
205 | a->l[x] >>= b;
206 |
207 | // Add the carry part from the previous limb
208 | a->l[x] |= prev_c << (BN_LIMB_BITS - b);
209 |
210 | prev_c = c;
211 | }
212 |
213 | return a;
214 | }
215 |
216 | // Helper function which multiplies and adds in a single run.
217 | static bn_t *_bn_mad_ui(bn_t *d, bn_t *a, ul_t b)
218 | {
219 | // D = D + A * b
220 | int x;
221 | ull_t S = 0;
222 |
223 | // Can a hold the result?
224 | assert(d->n >= (a->n + 2));
225 |
226 | for(x = 0; x < a->n_limbs; x++)
227 | {
228 | S += (ull_t)a->l[x] * (ull_t)b + (ull_t)d->l[x];
229 | d->l[x] = S;
230 |
231 | S >>= BN_LIMB_BITS;
232 | }
233 |
234 | // Add in the remaining carry
235 | while(S)
236 | {
237 | S += d->l[x];
238 | d->l[x] = S;
239 |
240 | S >>= BN_LIMB_BITS;
241 | x++;
242 | }
243 |
244 | return d;
245 | }
246 |
247 | int bn_maxbit(bn_t *a)
248 | {
249 | for(int x = a->n_limbs * BN_LIMB_BITS; x >= 0; x--)
250 | if(bn_getbit(a, x) != 0)
251 | return x;
252 |
253 | return 0;
254 | }
255 |
256 | int bn_getbit(bn_t *a, int x)
257 | {
258 | return (a->l[x / BN_LIMB_BITS] >> (x % BN_LIMB_BITS)) & 1;
259 | }
260 |
261 | void bn_setbit(bn_t *a, int x)
262 | {
263 | a->l[x / BN_LIMB_BITS] |= 1 << (x % BN_LIMB_BITS);
264 | }
265 |
266 | bn_t *bn_from_bin(bn_t *a, s8 *s, int len)
267 | {
268 | int x, y, z, w;
269 |
270 | ul_t limb;
271 | u8 *p_limb = (u8 *)&limb;
272 |
273 | for(x = len - 1, y = 0; x >= 0; y++)
274 | {
275 | limb = 0;
276 |
277 | for(z = 0, w = 0; z < BN_LIMB_BYTES; z += 1, w += 1)
278 | {
279 | if(x < 0)
280 | break;
281 |
282 | p_limb[w] = s[x];
283 |
284 | x -= 1;
285 | }
286 |
287 | if(_bn_big_endian())
288 | limb = SWAP(limb);
289 |
290 | a->l[y] = limb;
291 | }
292 |
293 | return a;
294 | }
295 |
296 | u8 *bn_to_bin(u8 *s, bn_t *a)
297 | {
298 | ul_t *p = (ul_t *)s;
299 |
300 | int be = _bn_big_endian();
301 |
302 | for(int x = a->n_limbs - 1, y = 0; x >= 0; x--, y++)
303 | {
304 | if(be)
305 | p[y] = a->l[x];
306 | else
307 | p[y] = SWAP(a->l[x]);
308 | }
309 |
310 | return s;
311 | }
312 |
313 | bn_t *bn_from_str(bn_t *a, const s8 *s)
314 | {
315 | int len = strlen(s);
316 | int x, y, z, w;
317 |
318 | ul_t limb;
319 | u8 *p_limb = (u8 *)&limb;
320 |
321 | // The x2 is for two ascii chars representing a single byte
322 | int step = (BN_LIMB_BYTES * 2);
323 |
324 | if(len % 2)
325 | return NULL;
326 |
327 | for(x = len - 2, y = 0; x >= 0; y++)
328 | {
329 | limb = 0;
330 |
331 | for(z = 0, w = 0; z < step && x >= 0; z += 2, w += 1)
332 | {
333 | p_limb[w] = _bn_str_to_u8(&s[x]);
334 |
335 | x -= 2;
336 | }
337 |
338 | if(_bn_big_endian())
339 | limb = SWAP(limb);
340 |
341 | a->l[y] = limb;
342 | }
343 |
344 | return a;
345 | }
346 |
347 | bn_t *bn_zero(bn_t *a)
348 | {
349 | memset((char *)a->l, 0, a->n_limbs * BN_LIMB_BYTES);
350 | return a;
351 | }
352 |
353 | bn_t *bn_alloc(int size)
354 | {
355 | int s;
356 |
357 | bn_t *ret = (bn_t *)mem_alloc(sizeof(bn_t));
358 | memset((char *)ret, 0x00, sizeof(bn_t));
359 |
360 | ret->n = size;
361 | ret->n_limbs = BYTES_TO_LIMBS(size);
362 |
363 | // Always allocate 4 limbs more than we need, so that potential bn_mon_mul is faster
364 | s = sizeof(ul_t) * (ret->n_limbs + 4);
365 | ret->l = (ul_t *)mem_alloc(s);
366 | memset((char *)ret->l, 0x00, s);
367 |
368 | return ret;
369 | }
370 |
371 | bn_t *bn_alloc_limbs(int limbs)
372 | {
373 | return bn_alloc(LIMBS_TO_BYTES(limbs));
374 | }
375 |
376 | bn_t *bn_copy(bn_t *a, bn_t *b)
377 | {
378 | int s = MIN(a->n_limbs, b->n_limbs);
379 |
380 | bn_zero(a);
381 | memcpy((s8 *)a->l, (s8 *)b->l, sizeof(ul_t) * s);
382 |
383 | return a;
384 | }
385 |
386 | void bn_free(bn_t *a)
387 | {
388 | // Zero it out, just for good measure
389 | bn_zero(a);
390 |
391 | mem_free(a->l);
392 | mem_free(a);
393 | }
394 |
395 | inline bn_t *bn_set_ui(bn_t *a, u64 val)
396 | {
397 | for(int x = 0; x < sizeof(val) / sizeof(ul_t); x++)
398 | {
399 | a->l[x] = val & (ul_t)-1;
400 | val >>= BN_LIMB_BITS;
401 | }
402 |
403 | return a;
404 | }
405 |
406 | bn_t *bn_add(bn_t *d, bn_t *a, bn_t *b, bn_t *n)
407 | {
408 | // D = A + B % N
409 |
410 | // Prevent overflow
411 | if(_bn_add(d, a, b))
412 | _bn_sub(d, d, n);
413 |
414 | bn_reduce(d, n);
415 |
416 | return d;
417 | }
418 |
419 | bn_t *bn_add_ui(bn_t *d, bn_t *a, unsigned int b, bn_t *n)
420 | {
421 | // D = A + B % N
422 |
423 | // Prevent overflow
424 | if(_bn_add_ui(d, a, b))
425 | _bn_sub(d, d, n);
426 |
427 | bn_reduce(d, n);
428 |
429 | return d;
430 | }
431 |
432 | bn_t *bn_sub(bn_t *d, bn_t *a, bn_t *b, bn_t *n)
433 | {
434 | // D = A - B % N
435 |
436 | // Prevent underflow
437 | if(_bn_sub(d, a, b))
438 | _bn_add(d, d, n);
439 |
440 | bn_reduce(d, n);
441 |
442 | return d;
443 | }
444 |
445 | bn_t *bn_sub_ui(bn_t *d, bn_t *a, unsigned int b, bn_t *n)
446 | {
447 | // D = A - B % N
448 |
449 | // Prevent underflow
450 | if(_bn_sub_ui(d, a, b))
451 | _bn_add(d, d, n);
452 |
453 | bn_reduce(d, n);
454 |
455 | return d;
456 | }
457 |
458 | int bn_cmp(bn_t *a, bn_t *b)
459 | {
460 | // assert(a->n_limbs == b->n_limbs);
461 |
462 | // First check the high limbs, if any
463 | if(a->n_limbs > b->n_limbs)
464 | {
465 | for(int i = b->n_limbs; i < a->n_limbs; i++)
466 | if(a->l[i])
467 | return BN_CMP_G;
468 | }
469 | else if(b->n_limbs > a->n_limbs)
470 | {
471 | for(int i = a->n_limbs; i < b->n_limbs; i++)
472 | if(b->l[i])
473 | return BN_CMP_G;
474 | }
475 |
476 | // ...then check the main limbs
477 | for(int x = MIN(a->n_limbs, b->n_limbs); x >= 0; x--)
478 | {
479 | if(a->l[x] < b->l[x])
480 | return BN_CMP_L;
481 | else if(a->l[x] > b->l[x])
482 | return BN_CMP_G;
483 | }
484 |
485 | return BN_CMP_E;
486 | }
487 |
488 | int bn_cmp_ui(bn_t *a, ul_t b)
489 | {
490 | int ret = 0;
491 |
492 | if(a->l[0] < b)
493 | ret = BN_CMP_L;
494 | else if(a->l[0] > b)
495 | ret = BN_CMP_G;
496 | else if(a->l[0] == b)
497 | ret = BN_CMP_E;
498 |
499 | // Let's walk over all other digits of a (if any)
500 | for(int x = 1; x < a->n_limbs; x++)
501 | {
502 | if(a->l[x] != 0)
503 | {
504 | // So a has some non-zero digits. It's clearly bigger than b
505 | ret = BN_CMP_G;
506 | break;
507 | }
508 | }
509 |
510 | return ret;
511 | }
512 |
513 | int bn_is_zero(bn_t *a)
514 | {
515 | for(int x = 0; x < a->n_limbs; x++)
516 | if(a->l[x] != 0)
517 | return 0;
518 |
519 | return 1;
520 | }
521 |
522 | bn_t *bn_reduce(bn_t *a, bn_t *n)
523 | {
524 | while(bn_cmp(a, n) >= 0)
525 | _bn_sub(a, a, n);
526 |
527 | return a;
528 | }
529 |
530 | bn_t *bn_reduce_slow(bn_t *a, bn_t *n)
531 | {
532 | bn_t *q = bn_alloc_limbs(n->n_limbs);
533 | bn_t *r = bn_alloc_limbs(n->n_limbs);
534 |
535 | bn_divrem(q, r, a, n);
536 | bn_copy(a, r);
537 |
538 | bn_free(q);
539 | bn_free(r);
540 |
541 | return a;
542 | }
543 |
544 | bn_t *bn_lshift(bn_t *a, int b)
545 | {
546 | // Single largest shift we can do is one limb
547 | while(b > BN_LIMB_BITS)
548 | {
549 | _bn_lshift_limbs(a, 1);
550 | b -= BN_LIMB_BITS;
551 | }
552 |
553 | return _bn_lshift(a, b);
554 | }
555 |
556 | bn_t *bn_rshift(bn_t *a, int b)
557 | {
558 | // Single largest shift we can do is one limb
559 | while(b > BN_LIMB_BITS)
560 | {
561 | _bn_rshift_limbs(a, 1);
562 | b -= BN_LIMB_BITS;
563 | }
564 |
565 | return _bn_rshift(a, b);
566 | }
567 |
568 | int bn_lsb(bn_t *a)
569 | {
570 | return a->l[0] & 1;
571 | }
572 |
573 | int bn_msb(bn_t *a)
574 | {
575 | return a->l[a->n - 1] >> (BN_LIMB_BITS - 1);
576 | }
577 |
578 | #if defined(BN_PRINT_FUNCS)
579 | void bn_print(FILE *fp, const s8 *pre, bn_t *a, const s8 *post)
580 | {
581 | int i, init = 1;
582 |
583 | fputs((char *)pre, fp);
584 |
585 | //Skip zero limbs.
586 | for(i = a->n_limbs - 1; i >= 0; i--)
587 | if(a->l[i] != 0)
588 | break;
589 |
590 | for(; i >= 0; i--)
591 | {
592 | if(init)
593 | {
594 | init = 0;
595 | fprintf(fp, BN_PRINT_FORMAT_I, a->l[i]);
596 | }
597 | else
598 | fprintf(fp, BN_PRINT_FORMAT, a->l[i]);
599 | }
600 |
601 | fputs((char *)post, fp);
602 | }
603 |
604 | bn_t *bn_read(FILE *fp, bn_t *dst)
605 | {
606 | s8 *data = mem_alloc(dst->n);
607 |
608 | fread(data, sizeof(u8), dst->n, fp);
609 | bn_from_bin(dst, data, dst->n);
610 | mem_free(data);
611 |
612 | return dst;
613 | }
614 |
615 | bn_t *bn_write(FILE *fp, bn_t *num)
616 | {
617 | u8 *data = mem_alloc(num->n);
618 |
619 | bn_to_bin(data, num);
620 | fwrite(data, 1, num->n, fp);
621 | mem_free(data);
622 |
623 | return num;
624 | }
625 | #endif
626 |
627 | bn_t *bn_mul(bn_t *d, bn_t *a, bn_t *b)
628 | {
629 | // D = A * b
630 |
631 | // Can a hold the result?
632 | assert(d->n >= (a->n * 2 + 1));
633 |
634 | bn_zero(d);
635 |
636 | for(int i = 0; i < a->n_limbs; i++)
637 | {
638 | ull_t S = 0;
639 |
640 | for(int j = 0; j < a->n_limbs; j++)
641 | {
642 | S += (ull_t)a->l[i] * b->l[j];
643 | d->l[i+j] += S;
644 |
645 | S >>= BN_LIMB_BITS;
646 | }
647 |
648 | d->l[i + a->n_limbs] = S;
649 | }
650 |
651 | return d;
652 | }
653 |
654 | bn_t *bn_mul_ui(bn_t *d, bn_t *a, ul_t b)
655 | {
656 | // D = A * b
657 | ull_t S = 0;
658 |
659 | // Can a hold the result?
660 | assert(d->n >= (a->n + 1));
661 |
662 | bn_zero(d);
663 |
664 | for(int x = 0; x < a->n_limbs; x++)
665 | {
666 | S += (ull_t)a->l[x] * b;
667 | d->l[x] = S;
668 |
669 | S >>= BN_LIMB_BITS;
670 | }
671 |
672 | d->l[a->n_limbs] = S;
673 |
674 | return d;
675 | }
676 |
677 | bn_t *bn_divrem(bn_t *q, bn_t *r, bn_t *a, bn_t *b)
678 | {
679 | bn_zero(q);
680 | bn_zero(r);
681 |
682 | for(int i = bn_maxbit(a); i >= 0 ;i--)
683 | {
684 | bn_lshift(r, 1);
685 | bn_lshift(q, 1);
686 |
687 | if(bn_getbit(a, i))
688 | bn_setbit(r, 0);
689 |
690 | if(bn_cmp(r, b) >= 0)
691 | {
692 | _bn_sub(r, r, b);
693 | bn_setbit(q, 0);
694 | }
695 | }
696 |
697 | return q;
698 | }
699 |
700 | bn_t *bn_rand(bn_t *a)
701 | {
702 | int size = a->n;
703 | u8 *tmp = (u8 *)mem_alloc(size);
704 |
705 | #if defined(_WIN32) || defined(_MSC_VER)
706 | HCRYPTPROV hProvider;
707 |
708 | CryptAcquireContext(&hProvider, 0, 0, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT | CRYPT_SILENT);
709 | CryptGenRandom(hProvider, size, tmp);
710 | #else
711 | int fd = open("/dev/urandom", O_RDONLY, 0);
712 | read(fd, tmp, size);
713 | close(fd);
714 | #endif
715 |
716 | bn_zero(a);
717 | bn_from_bin(a, (s8 *)tmp, size);
718 |
719 | mem_free(tmp);
720 |
721 | return a;
722 | }
723 |
724 | // Generate random a \in [x, b - y].
725 | bn_t *bn_rand_range(bn_t *a, int x, bn_t *b, int y)
726 | {
727 | bn_t *t = bn_alloc(b->n);
728 | _bn_sub_ui(t, b, y);
729 |
730 | while(1)
731 | {
732 | bn_rand(a);
733 |
734 | if(bn_cmp_ui(a, x) <= 0) // Check a < x
735 | continue;
736 |
737 | if(bn_cmp(a, t) > 0) // Check a > b - y
738 | continue;
739 |
740 | break;
741 | }
742 |
743 | bn_free(t);
744 |
745 | return a;
746 | }
747 |
748 | bn_t *bn_to_mon(bn_t *a, bn_t *n)
749 | {
750 | bn_t *at = bn_copy(bn_alloc_limbs(a->n_limbs + 1), a);
751 | bn_t *nt = bn_copy(bn_alloc_limbs(n->n_limbs + 1), n);
752 |
753 | // We can't loop bn_add here since bn_add calls bn_reduce which in turn calls bn_to_mon.
754 | // POOF, infinite recursion.
755 | for(int x = 0; x < BN_LIMB_BITS * a->n_limbs; x++)
756 | {
757 | _bn_add(at, at, at);
758 | bn_reduce(at, nt);
759 | }
760 |
761 | bn_copy(a, at);
762 |
763 | bn_free(at);
764 | bn_free(nt);
765 |
766 | return a;
767 | }
768 |
769 | bn_t *bn_from_mon(bn_t *a, bn_t *n)
770 | {
771 | bn_t *t = bn_alloc(a->n);
772 | bn_set_ui(t, 1);
773 |
774 | bn_mon_mul(a, a, t, n);
775 |
776 | bn_free(t);
777 |
778 | return a;
779 | }
780 |
781 | bn_t *bn_mon_mul(bn_t *d, bn_t *a, bn_t *b, bn_t *n)
782 | {
783 | ul_t q;
784 | ull_t r = (ull_t)1 << BN_LIMB_BITS;
785 |
786 | // The calculation of the mp value needs to be done only once.
787 | if(n->mp == 0)
788 | _bn_mon_init(n);
789 |
790 | // This num needs to be 4 digits bigger so we prevent overflows.
791 | // The mul_ui increases digit count by 1, and add's possibly increase
792 | // the count by one (each).
793 | bn_t *t = bn_alloc_limbs(n->n_limbs + 4);
794 |
795 | for(int x = 0; x < a->n_limbs; x++)
796 | {
797 | q = (t->l[0] + a->l[x] * b->l[0]) * n->mp;
798 | // q % r == q & (r-1), for r power of two
799 | q = q & (r - 1);
800 |
801 | _bn_mad_ui(t, n, q);
802 | _bn_mad_ui(t, b, a->l[x]);
803 |
804 | // Shift right by one limb
805 | _bn_rshift_limbs(t, 1);
806 | }
807 |
808 | if(bn_cmp(t, n) >= 0)
809 | _bn_sub(t, t, n);
810 |
811 | bn_copy(d, t);
812 | bn_free(t);
813 |
814 | return d;
815 | }
816 |
817 | // Montgomery reduction
818 | bn_t *bn_mon_reduce(bn_t *a, bn_t *n)
819 | {
820 | ull_t r = (ull_t)1 << BN_LIMB_BITS;
821 | ul_t mu;
822 |
823 | // The calculation of the mp value needs to be done only once.
824 | if(n->mp == 0)
825 | _bn_mon_init(n);
826 |
827 | bn_t *at = bn_copy(bn_alloc_limbs(a->n_limbs * 2 + 1), a);
828 | bn_t *tmp = bn_alloc_limbs(a->n_limbs * 2 + 1);
829 |
830 | for(int x = 0; x < a->n_limbs; x++)
831 | {
832 | mu = at->l[x] * n->mp % r;
833 |
834 | bn_mul_ui(tmp, n, mu);
835 | _bn_lshift_limbs(tmp, x);
836 |
837 | _bn_add(at, at, tmp);
838 | }
839 |
840 | _bn_rshift_limbs(at, a->n_limbs);
841 |
842 | bn_copy(a, at);
843 |
844 | bn_free(at);
845 | bn_free(tmp);
846 |
847 | return a;
848 | }
849 |
850 | // Square and multiply exponentiation
851 | bn_t *bn_mon_pow_sm(bn_t *d, bn_t *a, bn_t *e, bn_t *n)
852 | {
853 | // D = A**E % N
854 | bn_t *s = bn_copy(bn_alloc(a->n), a);
855 | bn_t *t = bn_copy(bn_alloc(d->n), d);
856 |
857 | bn_set_ui(t, 1);
858 | bn_to_mon(t, n);
859 |
860 | for(int i = 0; i <= bn_maxbit(e); i++)
861 | {
862 | if(bn_getbit(e, i))
863 | bn_mon_mul(t, t, s, n);
864 |
865 | bn_mon_mul(s, s, s, n);
866 | }
867 |
868 | bn_copy(d, t);
869 |
870 | bn_free(s);
871 | bn_free(t);
872 |
873 | return d;
874 | }
875 |
876 | // Square and multiply montgomery power ladder
877 | bn_t *bn_mon_pow_ml(bn_t *d, bn_t *a, bn_t *e, bn_t *n)
878 | {
879 | // D = A**E % N
880 | bn_t *r0 = bn_set_ui(bn_alloc(a->n), 1);
881 | bn_t *r1 = bn_copy(bn_alloc(a->n), a);
882 |
883 | bn_to_mon(r0, n);
884 |
885 | for(int i = e->n * 8; i >= 0; i--)
886 | {
887 | if(bn_getbit(e, i))
888 | {
889 | bn_mon_mul(r0, r0, r1, n);
890 | bn_mon_mul(r1, r1, r1, n);
891 | }
892 | else
893 | {
894 | bn_mon_mul(r1, r0, r1, n);
895 | bn_mon_mul(r0, r0, r0, n);
896 | }
897 | }
898 |
899 | bn_copy(d, r0);
900 |
901 | bn_free(r0);
902 | bn_free(r1);
903 |
904 | return d;
905 | }
906 |
907 | // Sliding-window exponentiation (HAC 14.83)
908 | bn_t *bn_mon_pow_sw(bn_t *d, bn_t *a, bn_t *e, bn_t *n)
909 | {
910 | // D = A**E % N
911 | bn_t *s = bn_copy(bn_alloc(a->n), a);
912 | bn_t *t = bn_copy(bn_alloc(d->n), d);
913 |
914 | // Select which window size to use
915 | int blen = BN_LIMB_BITS * n->n_limbs;
916 | int wsize = (blen > 671) ? 6 : (blen > 239) ? 5 : (blen > 79) ? 4 : (blen > 23) ? 3 : 1;
917 |
918 | //
919 | // Initialize the cache
920 | //
921 | bn_t *cache[1 << wsize];
922 | bn_set_ui(t, 1);
923 | bn_to_mon(t, n);
924 |
925 | // Initialize the cache first
926 | for(int i = 0; i < (1 << wsize); i++)
927 | cache[i] = bn_zero(bn_alloc(a->n));
928 |
929 | // 1st and 2nd elements are always the same
930 | bn_copy(cache[1], a);
931 | bn_mon_mul(cache[2], a, a, n);
932 |
933 | for(int i = 1; i < 1 << (wsize - 1); i++)
934 | bn_mon_mul(cache[2*i+1], cache[2*i-1], cache[2], n);
935 |
936 | // And iterate...
937 | for(int i = bn_maxbit(e); i >= 0;)
938 | {
939 | // In the 0-bit case, just square
940 | if(!bn_getbit(e, i))
941 | {
942 | bn_mon_mul(t, t, t, n);
943 | i--;
944 | }
945 | else
946 | {
947 | int num = 0;
948 | int sub = 0;
949 | int idx = 0;
950 |
951 | for(int j = 0; j < wsize; j++)
952 | {
953 | if(i - j < 0)
954 | break;
955 |
956 | int bit = bn_getbit(e, i - j);
957 | idx = (idx << 1) | bit;
958 |
959 | if(bit)
960 | {
961 | num = idx;
962 | sub = j + 1;
963 | }
964 | }
965 |
966 | // Square first
967 | for(int j = 0; j < sub; j++)
968 | bn_mon_mul(t, t, t, n);
969 |
970 | // ...then multiply with cache
971 | bn_mon_mul(t, t, cache[num], n);
972 |
973 | i -= sub;
974 | }
975 | }
976 |
977 | bn_copy(d, t);
978 |
979 | bn_free(s);
980 | bn_free(t);
981 |
982 | for(int i = 0; i < (1 << wsize); i++)
983 | bn_free(cache[i]);
984 |
985 | return d;
986 | }
987 |
988 | bn_t *bn_inv(bn_t *d, bn_t *a, bn_t *n)
989 | {
990 | // D = A**-1 % N
991 | bn_t *q = bn_alloc_limbs(n->n_limbs);
992 | bn_t *r = bn_alloc_limbs(n->n_limbs);
993 | bn_t *m = bn_alloc_limbs(n->n_limbs);
994 | bn_t *t = bn_alloc_limbs(2*n->n_limbs);
995 | bn_t *b = bn_copy(bn_alloc_limbs(n->n_limbs), n);
996 | bn_t *nn = bn_copy(bn_alloc_limbs(2*n->n_limbs), n);
997 |
998 | bn_t *x = bn_alloc_limbs(n->n_limbs);
999 | bn_t *u = bn_alloc_limbs(n->n_limbs);
1000 |
1001 | bn_set_ui(x, 0);
1002 | bn_set_ui(u, 1);
1003 |
1004 | while(bn_cmp_ui(a, 0) != 0)
1005 | {
1006 | bn_divrem(q, r, b, a);
1007 |
1008 | bn_mul(t, u, q);
1009 | bn_reduce_slow(t, nn);
1010 | bn_sub(m, x, t, n);
1011 |
1012 | bn_copy(b, a);
1013 | bn_copy(a, r);
1014 | bn_copy(x, u);
1015 | bn_copy(u, m);
1016 | }
1017 |
1018 | bn_copy(d, x);
1019 |
1020 | bn_free(q);
1021 | bn_free(r);
1022 | bn_free(m);
1023 | bn_free(t);
1024 | bn_free(b);
1025 | bn_free(nn);
1026 | bn_free(x);
1027 | bn_free(u);
1028 |
1029 | return d;
1030 | }
1031 |
1032 | bn_t *bn_mon_inv(bn_t *d, bn_t *a, bn_t *n)
1033 | {
1034 | // D = A**-1 % N
1035 |
1036 | // Note: Only for prime modulus
1037 | bn_t *t = bn_copy(bn_alloc(n->n), n);
1038 | bn_t *s = bn_alloc(n->n);
1039 |
1040 | bn_set_ui(s, 2);
1041 |
1042 | _bn_sub(t, t, s);
1043 | bn_mon_pow_sw(d, a, t, n);
1044 |
1045 | bn_free(t);
1046 | bn_free(s);
1047 |
1048 | return d;
1049 | }
1050 |
1051 | bn_t *bn_pow_mod(bn_t *d, bn_t *a, bn_t *e, bn_t *n)
1052 | {
1053 | // D = A**E mod N
1054 | bn_t *t = bn_copy(bn_alloc(a->n), a);
1055 | bn_to_mon(t, n);
1056 |
1057 | bn_from_mon(bn_mon_pow_sw(d, t, e, n), n);
1058 | // bn_from_mon(bn_mon_pow_ml(d, t, e, n), n);
1059 |
1060 | bn_free(t);
1061 |
1062 | return d;
1063 | }
1064 |
--------------------------------------------------------------------------------
/bn.h:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2016 Luka Malisa
3 | * Licensed under the terms of the GNU GPL, version 2
4 | * http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
5 | */
6 |
7 | #ifndef _BN_H_
8 | #define _BN_H_
9 |
10 | #if !defined(NAKED)
11 | #include
12 | #include
13 | #include
14 |
15 | #if !defined(_WIN32) && !defined(_MSC_VER)
16 | #include
17 | #endif
18 | #endif
19 |
20 | #include "config.h"
21 |
22 | #if BN_LIMB_SIZE == 8
23 | #define l_t int8_t
24 | #define ul_t uint8_t
25 | #define ll_t int16_t
26 | #define ull_t uint16_t
27 | #define BN_PRINT_FORMAT_I "%"PRIX8
28 | #define BN_PRINT_FORMAT "%02"PRIX8
29 | #define SWAP SWAP8
30 | #define BN_LIMB_BYTES 1
31 | #elif BN_LIMB_SIZE == 16
32 | #define l_t int16_t
33 | #define ul_t uint16_t
34 | #define ll_t int32_t
35 | #define ull_t uint32_t
36 | #define BN_PRINT_FORMAT_I "%"PRIX16
37 | #define BN_PRINT_FORMAT "%04"PRIX16
38 | #define SWAP SWAP16
39 | #define BN_LIMB_BYTES 2
40 | #elif BN_LIMB_SIZE == 32
41 | #define l_t int32_t
42 | #define ul_t uint32_t
43 | #define ll_t int64_t
44 | #define ull_t uint64_t
45 | #define BN_PRINT_FORMAT_I "%"PRIX32
46 | #define BN_PRINT_FORMAT "%08"PRIX32
47 | #define SWAP SWAP32
48 | #define BN_LIMB_BYTES 4
49 | #elif BN_LIMB_SIZE == 64
50 | #define l_t int64_t
51 | #define ul_t uint64_t
52 | #define ll_t __int128
53 | #define ull_t unsigned __int128
54 | #define BN_PRINT_FORMAT_I "%"PRIX64
55 | #define BN_PRINT_FORMAT "%016"PRIX64
56 | #define SWAP SWAP64
57 | #define BN_LIMB_BYTES 8
58 | #else
59 | #error "Are you a wizard?"
60 | #endif
61 |
62 | #if !defined(BN_ASSERT)
63 | #define assert(...)
64 | #endif
65 |
66 | typedef char s8;
67 | typedef uint8_t u8;
68 | typedef int16_t s16;
69 | typedef uint16_t u16;
70 | typedef int32_t s32;
71 | typedef uint32_t u32;
72 | typedef int64_t s64;
73 | typedef uint64_t u64;
74 |
75 | #define BOOL int
76 | #define TRUE 1
77 | #define FALSE 0
78 |
79 | #define BN_LIMB_BITS (BN_LIMB_BYTES * 8)
80 | #define BN_MAX_DIGIT ((ul_t)-1)
81 |
82 | /*! Comparison results. */
83 | /*! Less. */
84 | #define BN_CMP_L (-1)
85 | /*! Greater. */
86 | #define BN_CMP_G (1)
87 | /*! Equal. */
88 | #define BN_CMP_E (0)
89 |
90 | /*! Generic helper macros. */
91 | #define MAX(x, y) ((x >= y) ? x : y)
92 | #define MIN(x, y) ((x >= y) ? y : x)
93 |
94 | /*! Byte-order swapping. */
95 | #define SWAP64(x) ((SWAP32(((x) & 0xffffffff)) << 32) | SWAP32(((x >> 32) & 0xffffffff)))
96 | #define SWAP32(x) ((SWAP16(((x) & 0xffff)) << 16) | SWAP16(((x >> 16) & 0xffff)))
97 | #define SWAP16(x) (((x << 8) & 0xff00) | ((x >> 8) & 0xff))
98 | #define SWAP8(x) x
99 |
100 | /*! Convert bits to number of limbs. */
101 | #define BYTES_TO_LIMBS(x) ((x * 8) / BN_LIMB_BITS + ((x * 8) % BN_LIMB_BITS ? 1 : 0))
102 | #define LIMBS_TO_BYTES(x) (x * BN_LIMB_BYTES)
103 |
104 | /*! Bignum struct. */
105 | typedef struct _bn_t
106 | {
107 | /*! Length in bytes. */
108 | int n;
109 | /*! Length in limbs. */
110 | int n_limbs;
111 | /*! A temporary value needed by Montgomery multiplication. */
112 | ull_t mp;
113 | /*! The limbs. */
114 | ul_t *l;
115 | } bn_t;
116 |
117 | /*!
118 | * \brief Returns the position of the highest-placed non-zero bit.
119 | */
120 | int bn_maxbit(bn_t *a);
121 |
122 | /*!
123 | * \brief Returns the x-th bit.
124 | */
125 | int bn_getbit(bn_t *a, int x);
126 |
127 | /*!
128 | * \brief Sets the x-th bit.
129 | */
130 | void bn_setbit(bn_t *a, int x);
131 |
132 | /*!
133 | * \brief Read bignum from char array (binary data).
134 | */
135 | bn_t *bn_from_bin(bn_t *a, s8 *s, int len);
136 |
137 | /*!
138 | * \brief Export bignum to a char array.
139 | */
140 | u8 *bn_to_bin(u8 *s, bn_t *a);
141 |
142 | /*!
143 | * \brief Read bignum from a string.
144 | */
145 | bn_t *bn_from_str(bn_t *a, const s8 *s);
146 |
147 | /*!
148 | * \brief Zero out the bignum.
149 | */
150 | bn_t *bn_zero(bn_t *num);
151 |
152 | /*!
153 | * \brief Allocate a new bignum of chosen size (in bytes).
154 | */
155 | bn_t *bn_alloc(int size);
156 |
157 | /*!
158 | * \brief Allocate a new bignum of chosen size (in limbs).
159 | */
160 | bn_t *bn_alloc_limbs(int size);
161 |
162 | /*!
163 | * \brief Copy the bignum.
164 | */bn_t *bn_copy(bn_t *a, bn_t *b);
165 |
166 | /*!
167 | * \brief Free the bignum.
168 | */
169 | void bn_free(bn_t *a);
170 |
171 | /*!
172 | * \brief Set the bignum to an integer value.
173 | */
174 | bn_t *bn_set_ui(bn_t *a, u64 val);
175 |
176 | /*!
177 | * \brief Add two bignums.
178 | */
179 | bn_t *bn_add(bn_t *a, bn_t *b, bn_t *c, bn_t *n);
180 |
181 | /*!
182 | * \brief Add a bignum and an integer.
183 | */
184 | bn_t *bn_add_ui(bn_t *d, bn_t *a, unsigned int b, bn_t *n);
185 |
186 | /*!
187 | * \brief Subtract two bignums.
188 | */
189 | bn_t *bn_sub(bn_t *a, bn_t *b, bn_t *c, bn_t *n);
190 |
191 | /*!
192 | * \brief Subtract a bignum and an integer.
193 | */
194 | bn_t *bn_sub_ui(bn_t *d, bn_t *a, unsigned int b, bn_t *n);
195 |
196 | /*!
197 | * \brief Compare two bignums. Returns: BN_CMP_L, BN_CMP_G or BN_CMP_E.
198 | */
199 | int bn_cmp(bn_t *a, bn_t *b);
200 |
201 | /*!
202 | * \brief Compare a bignum to an integer. Returns: BN_CMP_L, BN_CMP_G or BN_CMP_E.
203 | */
204 | int bn_cmp_ui(bn_t *a, ul_t b);
205 |
206 | /*!
207 | * \brief Return 1 if the bignum is zero, 0 otherwise.
208 | */
209 | int bn_is_zero(bn_t *a);
210 |
211 | /*!
212 | * \brief a = a % n
213 | */
214 | bn_t *bn_reduce(bn_t *a, bn_t *n);
215 |
216 | /*!
217 | * \brief a = a % n
218 | */
219 | bn_t *bn_reduce_slow(bn_t *a, bn_t *n);
220 |
221 | /*!
222 | * \brief Shift left by a number of bits.
223 | */
224 | bn_t *bn_lshift(bn_t *a, int b);
225 |
226 | /*!
227 | * \brief Shift right by a number of bits.
228 | */
229 | bn_t *bn_rshift(bn_t *a, int b);
230 |
231 | /*!
232 | * \brief Return the most significant bit.
233 | */
234 | int bn_msb(bn_t *a);
235 |
236 | /*!
237 | * \brief Return the least significant bit.
238 | */
239 | int bn_lsb(bn_t *a);
240 |
241 | #if defined(BN_PRINT_FUNCS)
242 | /*!
243 | * \brief Prints the bignum in hexadecimal format.
244 | */
245 | void bn_print(FILE *fp, const s8 *pre, bn_t *a, const s8 *post);
246 |
247 | /*!
248 | * \brief Read bignum from file stream.
249 | */
250 | bn_t *bn_read(FILE *fp, bn_t *dst);
251 |
252 | /*!
253 | * \brief Write bignum to file stream.
254 | */
255 | bn_t *bn_write(FILE *fp, bn_t *num);
256 | #endif
257 |
258 | /*!
259 | * \brief Textbook multiplication of two bignums.
260 | */
261 | bn_t *bn_mul(bn_t *d, bn_t *a, bn_t *b);
262 |
263 | /*!
264 | * \brief Multiply bignum with an integer.
265 | */
266 | bn_t *bn_mul_ui(bn_t *d, bn_t *a, ul_t b);
267 |
268 | /*!
269 | * \brief Divide two bignums, while tracking both the quotient (q) as well as
270 | * and the remainder (r).
271 | */
272 | bn_t *bn_divrem(bn_t *q, bn_t *r, bn_t *a, bn_t *b);
273 |
274 | /*!
275 | * \brief Fill the bignum with random data.
276 | */
277 | bn_t *bn_rand(bn_t *a);
278 |
279 | /*!
280 | * \brief Generate random a \in [x, b - y].
281 | */
282 | bn_t *bn_rand_range(bn_t *a, int x, bn_t *b, int y);
283 |
284 | /*!
285 | * \brief Convert to Montgomery form.
286 | */
287 | bn_t *bn_to_mon(bn_t *a, bn_t *n);
288 |
289 | /*!
290 | * \brief Convert from Montgomery form.
291 | */
292 | bn_t *bn_from_mon(bn_t *a, bn_t *n);
293 |
294 | /*!
295 | * \brief D = A * B % N
296 | */
297 | bn_t *bn_mon_mul(bn_t *d, bn_t *a, bn_t *b, bn_t *n);
298 |
299 | /*!
300 | * \brief A = A % N
301 | */
302 | bn_t *bn_mon_reduce(bn_t *a, bn_t *n);
303 |
304 | /*!
305 | * \brief D = A**E % N
306 | */
307 | bn_t *bn_mon_pow(bn_t *d, bn_t *a, bn_t *e, bn_t *n);
308 |
309 | /*!
310 | * \brief D = A**-1 % N
311 | */
312 | bn_t *bn_mon_inv(bn_t *d, bn_t *a, bn_t *n);
313 |
314 | /*!
315 | * \brief D = A**-1 % N
316 | */
317 | bn_t *bn_inv(bn_t *d, bn_t *a, bn_t *n);
318 |
319 | /*!
320 | * \brief This is a helper function which does *NOT* take Montgomery form
321 | * numbers. It will make conversions internally.
322 | *
323 | * D = A**B % N
324 | */
325 | bn_t *bn_pow_mod(bn_t *d, bn_t *a, bn_t *b, bn_t *n);
326 |
327 | #endif // _BN_H_
328 |
--------------------------------------------------------------------------------
/config.h:
--------------------------------------------------------------------------------
1 | #ifndef _CONFIG_H_
2 | #define _CONFIG_H_
3 |
4 | /*! Size (in bits) of each limb */
5 | #define BN_LIMB_SIZE 64
6 |
7 | /*! Include file-related functions */
8 | #define BN_PRINT_FUNCS
9 |
10 | /*! Include debug checks */
11 | //#define BN_ASSERT
12 |
13 | /*! Custom memory functions, e.g., for embedded code. */
14 | #define mem_alloc(x) malloc(x)
15 | #define mem_free(x) free(x)
16 |
17 | #endif // _CONFIG_H_
18 |
--------------------------------------------------------------------------------
/dh.c:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2016 naehrwert
3 | * Licensed under the terms of the GNU GPL, version 2
4 | * http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
5 | */
6 |
7 | #if !defined(NAKED)
8 | #include
9 | #include
10 | #endif
11 |
12 | #include "dh.h"
13 |
14 | dh_ctxt_t *dh_init(bn_t *p, bn_t *g)
15 | {
16 | dh_ctxt_t *res;
17 | bn_t *t;
18 |
19 | if (p == NULL || g == NULL)
20 | return NULL;
21 |
22 | assert(p->n == g->n);
23 |
24 | if ((res = (dh_ctxt_t *)mem_alloc(sizeof(dh_ctxt_t))) == NULL)
25 | return NULL;
26 |
27 | res->g = g;
28 | res->p = p;
29 |
30 | t = bn_copy(bn_alloc(p->n), p);
31 | bn_sub_ui(t, t, 2, p);
32 |
33 | // Check g \in [2, p - 2].
34 | if (bn_cmp_ui(g, 2) < 0 || bn_cmp(g, t) > 0)
35 | goto outerr;
36 |
37 | // Generate c \in [1, p - 2].
38 | res->c = bn_alloc(p->n);
39 | bn_rand_range(res->c, 1, p, 2);
40 |
41 | // C = g^c mod p
42 | res->C = bn_alloc(p->n);
43 | bn_pow_mod(res->C, res->g, res->c, p);
44 | goto outok;
45 |
46 | outerr:;
47 | mem_free(res);
48 | res = NULL;
49 |
50 | outok:;
51 | bn_free(t);
52 |
53 | return res;
54 | }
55 |
56 | void dh_free(dh_ctxt_t *ctxt)
57 | {
58 | if (ctxt == NULL)
59 | return;
60 |
61 | bn_free(ctxt->C);
62 | bn_free(ctxt->c);
63 | mem_free(ctxt);
64 | }
65 |
66 | bn_t *dh_step(bn_t *K, dh_ctxt_t *ctxt, bn_t *D)
67 | {
68 | if (K == NULL || ctxt == NULL || D == NULL)
69 | return NULL;
70 |
71 | assert(K->n == D->n && D->n == ctxt->p->n);
72 |
73 | // K = D^c mod p
74 | return bn_pow_mod(K, D, ctxt->c, ctxt->p);
75 | }
76 |
--------------------------------------------------------------------------------
/dh.h:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/malisal/libfinite/e6df7efc98a0e690efc3a5b5fd47d1d3f7f89162/dh.h
--------------------------------------------------------------------------------
/ec.c:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2016 naehrwert
3 | * Licensed under the terms of the GNU GPL, version 2
4 | * http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
5 | */
6 |
7 | #include
8 | #include "ec.h"
9 |
10 | static void _ec_add(bn_t *d, bn_t *a, bn_t *b, ec_group_t *ecg)
11 | {
12 | bn_add(d, a, b, ecg->p);
13 | }
14 |
15 | static void _ec_sub(bn_t *d, bn_t *a, bn_t *b, ec_group_t *ecg)
16 | {
17 | bn_sub(d, a, b, ecg->p);
18 | }
19 |
20 | static void _ec_mul(bn_t *d, bn_t *a, bn_t *b, ec_group_t *ecg)
21 | {
22 | bn_mon_mul(d, a, b, ecg->p);
23 | }
24 |
25 | static void _ec_square(bn_t *d, bn_t *a, ec_group_t *ecg)
26 | {
27 | _ec_mul(d, a, a, ecg);
28 | }
29 |
30 | static void _ec_inv(bn_t *d, bn_t *a, ec_group_t *ecg)
31 | {
32 | bn_mon_inv(d, a, ecg->p);
33 | }
34 |
35 | ec_point_t *ec_point_alloc(uint32_t n)
36 | {
37 | ec_point_t *res;
38 |
39 | if ((res = (ec_point_t *)mem_alloc(sizeof(ec_point_t))) == NULL)
40 | return NULL;
41 |
42 | res->x = bn_alloc(n);
43 | res->y = bn_alloc(n);
44 |
45 | return res;
46 | }
47 |
48 | void ec_point_free(ec_point_t *p)
49 | {
50 | bn_free(p->x);
51 | bn_free(p->y);
52 | mem_free(p);
53 | }
54 |
55 | ec_point_t *ec_point_copy(ec_point_t *d, ec_point_t *s)
56 | {
57 | bn_copy(d->x, s->x);
58 | bn_copy(d->y, s->y);
59 |
60 | return d;
61 | }
62 |
63 | ec_point_t *ec_point_zero(ec_point_t *p)
64 | {
65 | bn_zero(p->x);
66 | bn_zero(p->y);
67 |
68 | return p;
69 | }
70 |
71 | int ec_point_is_zero(ec_point_t *p)
72 | {
73 | return (bn_is_zero(p->x) && bn_is_zero(p->y));
74 | }
75 |
76 | void ec_point_to_mon(ec_point_t *p, ec_group_t *ecg)
77 | {
78 | bn_to_mon(p->x, ecg->p);
79 | bn_to_mon(p->y, ecg->p);
80 | }
81 |
82 | void ec_point_from_mon(ec_point_t *p, ec_group_t *ecg)
83 | {
84 | bn_from_mon(p->x, ecg->p);
85 | bn_from_mon(p->y, ecg->p);
86 | }
87 |
88 | ec_point_t *ec_point_double(ec_point_t *r, ec_point_t *p, ec_group_t *ecg)
89 | {
90 | // Handle trivial case.
91 | if (bn_is_zero(p->y))
92 | {
93 | ec_point_zero(r);
94 | return r;
95 | }
96 |
97 | bn_t *s = bn_alloc(ecg->p->n), *t = bn_alloc(ecg->p->n);
98 | ec_point_t *pp = ec_point_copy(ec_point_alloc(ecg->p->n), p);
99 | bn_t *px = pp->x, *py = pp->y, *rx = r->x, *ry = r->y;
100 |
101 | _ec_square(t, px, ecg); // t = px*px
102 | _ec_add(s, t, t, ecg); // s = 2*px*px
103 | _ec_add(s, s, t, ecg); // s = 3*px*px
104 | _ec_add(s, s, ecg->a, ecg); // s = 3*px*px + a
105 | _ec_add(t, py, py, ecg); // t = 2*py
106 | _ec_inv(t, t, ecg); // t = 1/(2*py)
107 | _ec_mul(s, s, t, ecg); // s = (3*px*px+a)/(2*py)
108 |
109 | _ec_square(rx, s, ecg); // rx = s*s
110 | _ec_add(t, px, px, ecg); // t = 2*px
111 | _ec_sub(rx, rx, t, ecg); // rx = s*s - 2*px
112 |
113 | _ec_sub(t, px, rx, ecg); // t = -(rx-px)
114 | _ec_mul(ry, s, t, ecg); // ry = -s*(rx-px)
115 | _ec_sub(ry, ry, py, ecg); // ry = -s*(rx-px) - py
116 |
117 | bn_free(s);
118 | bn_free(t);
119 | ec_point_free(pp);
120 |
121 | return r;
122 | }
123 |
124 | ec_point_t *ec_point_add(ec_point_t *r, ec_point_t *p, ec_point_t *q, ec_group_t *ecg)
125 | {
126 | // Handle trivial cases.
127 | if (ec_point_is_zero(p))
128 | {
129 | ec_point_copy(r, q);
130 | return r;
131 | }
132 |
133 | if (ec_point_is_zero(q))
134 | {
135 | ec_point_copy(r, p);
136 | return r;
137 | }
138 |
139 | bn_t *s = bn_alloc(ecg->p->n), *t = bn_alloc(ecg->p->n), *u = bn_alloc(ecg->p->n);
140 | ec_point_t *pp = ec_point_copy(ec_point_alloc(ecg->p->n), p), *qq = ec_point_copy(ec_point_alloc(ecg->p->n), q);
141 | bn_t *px = pp->x, *py = pp->y, *qx = qq->x, *qy = qq->y, *rx = r->x, *ry = r->y;
142 |
143 | // Handle limit cases.
144 | _ec_sub(u, qx, px, ecg);
145 | if (bn_is_zero(u))
146 | {
147 | _ec_sub(u, qy, py, ecg);
148 | if (bn_is_zero(u))
149 | ec_point_double(r, pp, ecg);
150 | else
151 | ec_point_zero(r);
152 | return r;
153 | }
154 |
155 | _ec_inv(t, u, ecg); // t = 1/(qx-px)
156 | _ec_sub(u, qy, py, ecg); // u = qy-py
157 | _ec_mul(s, t, u, ecg); // s = (qy-py)/(qx-px)
158 |
159 | _ec_square(rx, s, ecg); // rx = s*s
160 | _ec_add(t, px, qx, ecg); // t = px+qx
161 | _ec_sub(rx, rx, t, ecg); // rx = s*s - (px+qx)
162 |
163 | _ec_sub(t, px, rx, ecg); // t = -(rx-px)
164 | _ec_mul(ry, s, t, ecg); // ry = -s*(rx-px)
165 | _ec_sub(ry, ry, py, ecg); // ry = -s*(rx-px) - py
166 |
167 | bn_free(s);
168 | bn_free(t);
169 | bn_free(u);
170 | ec_point_free(pp);
171 | ec_point_free(qq);
172 |
173 | return r;
174 | }
175 |
176 | ec_point_t *ec_point_mul(ec_point_t *d, bn_t *a, ec_point_t *b, ec_group_t *ecg)
177 | {
178 | int i;
179 | ec_point_t *bt = ec_point_copy(ec_point_alloc(b->x->n), b);
180 |
181 | ec_point_zero(d);
182 |
183 | for (i = 0; i <= bn_maxbit(a); i++)
184 | {
185 | if (bn_getbit(a, i))
186 | ec_point_add(d, d, bt, ecg);
187 | ec_point_double(bt, bt, ecg);
188 | }
189 |
190 | ec_point_free(bt);
191 |
192 | return d;
193 | }
194 |
--------------------------------------------------------------------------------
/ec.h:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2016 naehrwert
3 | * Licensed under the terms of the GNU GPL, version 2
4 | * http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
5 | */
6 |
7 | #ifndef _EC_H_
8 | #define _EC_H_
9 |
10 | #include "bn.h"
11 |
12 | /*! Elliptic curve point. */
13 | typedef struct _ec_point
14 | {
15 | /*! x coord. */
16 | bn_t *x;
17 | /*! y coord. */
18 | bn_t *y;
19 | } ec_point_t;
20 |
21 | /*! Elliptic curve group parameters (defining equation: y^2 = x^3 + ax + b). */
22 | typedef struct _ec_group
23 | {
24 | /*! Modulus. */
25 | bn_t *p;
26 | /*! Parameter a. (mon!) */
27 | bn_t *a;
28 | /*! Parameter b. (mon!) */
29 | bn_t *b;
30 | } ec_group_t;
31 |
32 | /*!
33 | * \brief Allocate point.
34 | */
35 | ec_point_t *ec_point_alloc(uint32_t n);
36 |
37 | /*!
38 | * \brief Free point.
39 | */
40 | void ec_point_free(ec_point_t *p);
41 |
42 | /*!
43 | * \brief Copy point.
44 | */
45 | ec_point_t *ec_point_copy(ec_point_t *d, ec_point_t *s);
46 |
47 | /*!
48 | * \brief Zero out point.
49 | */
50 | ec_point_t *ec_point_zero(ec_point_t *p);
51 |
52 | /*!
53 | * \brief Test for zero point.
54 | */
55 | int ec_point_is_zero(ec_point_t *p);
56 |
57 | /*!
58 | * \brief Convert point to montgomery form.
59 | */
60 | void ec_point_to_mon(ec_point_t *p, ec_group_t *ecg);
61 |
62 | /*!
63 | * \brief Convert point from montgomery form.
64 | */
65 | void ec_point_from_mon(ec_point_t *p, ec_group_t *ecg);
66 |
67 | /*!
68 | * \brief Double point.
69 | */
70 | ec_point_t *ec_point_double(ec_point_t *r, ec_point_t *p, ec_group_t *ecg);
71 |
72 | /*!
73 | * \brief Add two points.
74 | */
75 | ec_point_t *ec_point_add(ec_point_t *r, ec_point_t *p, ec_point_t *q, ec_group_t *ecg);
76 |
77 | /*!
78 | * \brief Multiply point with bignum (d = a * b).
79 | */
80 | ec_point_t *ec_point_mul(ec_point_t *d, bn_t *a, ec_point_t *b, ec_group_t *ecg);
81 |
82 | #endif // _EC_H_
83 |
84 |
--------------------------------------------------------------------------------
/ec_pqr.c:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2016 naehrwert
3 | * Licensed under the terms of the GNU GPL, version 2
4 | * http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
5 | */
6 |
7 | #include
8 | #include "ec_pqr.h"
9 |
10 | static void _ec_pqr_add(poly_t *d, poly_t *a, poly_t *b, ec_pqr_group_t *ecg)
11 | {
12 | pqr_add(d, a, b, ecg->p);
13 | }
14 |
15 | static void _ec_pqr_sub(poly_t *d, poly_t *a, poly_t *b, ec_pqr_group_t *ecg)
16 | {
17 | pqr_sub(d, a, b, ecg->p);
18 | }
19 |
20 | static void _ec_pqr_mul(poly_t *d, poly_t *a, poly_t *b, ec_pqr_group_t *ecg)
21 | {
22 | pqr_mul(d, a, b, ecg->p);
23 | }
24 |
25 | static void _ec_pqr_square(poly_t *d, poly_t *a, ec_pqr_group_t *ecg)
26 | {
27 | _ec_pqr_mul(d, a, a, ecg);
28 | }
29 |
30 | static void _ec_pqr_inv(poly_t *d, poly_t *a, ec_pqr_group_t *ecg)
31 | {
32 | pqr_inv(d, a, ecg->p);
33 | }
34 |
35 | ec_pqr_point_t *ec_pqr_point_alloc(ec_pqr_group_t *ecg)
36 | {
37 | ec_pqr_point_t *res;
38 |
39 | if ((res = (ec_pqr_point_t *)mem_alloc(sizeof(ec_pqr_point_t))) == NULL)
40 | return NULL;
41 |
42 | //(degree - 1) since x, y are in the polynomial quotient ring.
43 | res->x = poly_alloc(ecg->p->degree - 1, ecg->p->N, 1);
44 | res->y = poly_alloc(ecg->p->degree - 1, ecg->p->N, 1);
45 |
46 | return res;
47 | }
48 |
49 | void ec_pqr_point_free(ec_pqr_point_t *p)
50 | {
51 | poly_free(p->x, 1);
52 | poly_free(p->y, 1);
53 | mem_free(p);
54 | }
55 |
56 | ec_pqr_point_t *ec_pqr_point_copy(ec_pqr_point_t *d, ec_pqr_point_t *s)
57 | {
58 | //TODO: maybe we don't need to force adjust here.
59 | poly_copy(d->x, s->x, 1);
60 | poly_copy(d->y, s->y, 1);
61 |
62 | return d;
63 | }
64 |
65 | int ec_pqr_point_cmp(ec_pqr_point_t *p, ec_pqr_point_t *q)
66 | {
67 | if (poly_cmp(p->x, q->x) == POLY_CMP_E && poly_cmp(p->y, q->y) == POLY_CMP_E)
68 | return POINT_CMP_E;
69 | return POINT_CMP_NE;
70 | }
71 |
72 | ec_pqr_point_t *ec_pqr_point_zero(ec_pqr_point_t *p)
73 | {
74 | poly_zero(p->x);
75 | poly_zero(p->y);
76 |
77 | return p;
78 | }
79 |
80 | int ec_pqr_point_is_zero(ec_pqr_point_t *p)
81 | {
82 | return (poly_is_zero(p->x) && poly_is_zero(p->y));
83 | }
84 |
85 | void ec_pqr_point_to_mon(ec_pqr_point_t *p)
86 | {
87 | poly_to_mon(p->x);
88 | poly_to_mon(p->y);
89 | }
90 |
91 | void ec_pqr_point_from_mon(ec_pqr_point_t *p)
92 | {
93 | poly_from_mon(p->x);
94 | poly_from_mon(p->y);
95 | }
96 |
97 | ec_pqr_point_t *ec_pqr_point_neg(ec_pqr_point_t *r, ec_pqr_point_t *p, ec_pqr_group_t *ecg)
98 | {
99 | poly_copy(r->x, p->x, 1);
100 | poly_zero(r->y);
101 | pqr_sub(r->y, r->y, p->y, ecg->p);
102 | return r;
103 | }
104 |
105 | ec_pqr_point_t *ec_pqr_point_double(ec_pqr_point_t *r, ec_pqr_point_t *p, ec_pqr_group_t *ecg)
106 | {
107 | // Handle trivial case.
108 | if (poly_is_zero(p->y))
109 | {
110 | ec_pqr_point_zero(r);
111 | return r;
112 | }
113 |
114 | poly_t *s = poly_alloc(ecg->p->degree - 1, ecg->p->N, 1),
115 | *t = poly_alloc(ecg->p->degree - 1, ecg->p->N, 1);
116 | ec_pqr_point_t *pp = ec_pqr_point_copy(ec_pqr_point_alloc(ecg), p);
117 | poly_t *px = pp->x, *py = pp->y, *rx = r->x, *ry = r->y;
118 |
119 | _ec_pqr_square(t, px, ecg); // t = px*px
120 | _ec_pqr_add(s, t, t, ecg); // s = 2*px*px
121 | _ec_pqr_add(s, s, t, ecg); // s = 3*px*px
122 | _ec_pqr_add(s, s, ecg->a, ecg); // s = 3*px*px + a
123 | _ec_pqr_add(t, py, py, ecg); // t = 2*py
124 | _ec_pqr_inv(t, t, ecg); // t = 1/(2*py)
125 | _ec_pqr_mul(s, s, t, ecg); // s = (3*px*px+a)/(2*py)
126 |
127 | _ec_pqr_square(rx, s, ecg); // rx = s*s
128 | _ec_pqr_add(t, px, px, ecg); // t = 2*px
129 | _ec_pqr_sub(rx, rx, t, ecg); // rx = s*s - 2*px
130 |
131 | _ec_pqr_sub(t, px, rx, ecg); // t = -(rx-px)
132 | _ec_pqr_mul(ry, s, t, ecg); // ry = -s*(rx-px)
133 | _ec_pqr_sub(ry, ry, py, ecg); // ry = -s*(rx-px) - py
134 |
135 | poly_free(s, 1);
136 | poly_free(t, 1);
137 | ec_pqr_point_free(pp);
138 |
139 | return r;
140 | }
141 |
142 | ec_pqr_point_t *ec_pqr_point_add(ec_pqr_point_t *r, ec_pqr_point_t *p, ec_pqr_point_t *q, ec_pqr_group_t *ecg)
143 | {
144 | // Handle trivial cases.
145 | if (ec_pqr_point_is_zero(p))
146 | {
147 | ec_pqr_point_copy(r, q);
148 | return r;
149 | }
150 |
151 | if (ec_pqr_point_is_zero(q))
152 | {
153 | ec_pqr_point_copy(r, p);
154 | return r;
155 | }
156 |
157 | poly_t *s = poly_alloc(ecg->p->degree - 1, ecg->p->N, 1),
158 | *t = poly_alloc(ecg->p->degree - 1, ecg->p->N, 1),
159 | *u = poly_alloc(ecg->p->degree - 1, ecg->p->N, 1);
160 | ec_pqr_point_t *pp = ec_pqr_point_copy(ec_pqr_point_alloc(ecg), p),
161 | *qq = ec_pqr_point_copy(ec_pqr_point_alloc(ecg), q);
162 | poly_t *px = pp->x, *py = pp->y, *qx = qq->x, *qy = qq->y, *rx = r->x, *ry = r->y;
163 |
164 | // Handle limit cases.
165 | _ec_pqr_sub(u, qx, px, ecg);
166 | if (poly_is_zero(u))
167 | {
168 | _ec_pqr_sub(u, qy, py, ecg);
169 | if (poly_is_zero(u))
170 | ec_pqr_point_double(r, pp, ecg);
171 | else
172 | ec_pqr_point_zero(r);
173 | return r;
174 | }
175 |
176 | _ec_pqr_inv(t, u, ecg); // t = 1/(qx-px)
177 | _ec_pqr_sub(u, qy, py, ecg); // u = qy-py
178 | _ec_pqr_mul(s, t, u, ecg); // s = (qy-py)/(qx-px)
179 |
180 | _ec_pqr_square(rx, s, ecg); // rx = s*s
181 | _ec_pqr_add(t, px, qx, ecg); // t = px+qx
182 | _ec_pqr_sub(rx, rx, t, ecg); // rx = s*s - (px+qx)
183 |
184 | _ec_pqr_sub(t, px, rx, ecg); // t = -(rx-px)
185 | _ec_pqr_mul(ry, s, t, ecg); // ry = -s*(rx-px)
186 | _ec_pqr_sub(ry, ry, py, ecg); // ry = -s*(rx-px) - py
187 |
188 | poly_free(s, 1);
189 | poly_free(t, 1);
190 | poly_free(u, 1);
191 | ec_pqr_point_free(pp);
192 | ec_pqr_point_free(qq);
193 |
194 | return r;
195 | }
196 |
197 | ec_pqr_point_t *ec_pqr_point_mul(ec_pqr_point_t *d, bn_t *a, ec_pqr_point_t *b, ec_pqr_group_t *ecg)
198 | {
199 | int i;
200 | ec_pqr_point_t *bt = ec_pqr_point_copy(ec_pqr_point_alloc(ecg), b);
201 |
202 | ec_pqr_point_zero(d);
203 |
204 | for (i = 0; i <= bn_maxbit(a); i++)
205 | {
206 | if (bn_getbit(a, i))
207 | ec_pqr_point_add(d, d, bt, ecg);
208 | ec_pqr_point_double(bt, bt, ecg);
209 | }
210 |
211 | ec_pqr_point_free(bt);
212 |
213 | return d;
214 | }
215 |
--------------------------------------------------------------------------------
/ec_pqr.h:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2016 naehrwert
3 | * Licensed under the terms of the GNU GPL, version 2
4 | * http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
5 | */
6 |
7 | #ifndef _EC_PQR_H_
8 | #define _EC_PQR_H_
9 |
10 | #include "pqr.h"
11 |
12 | #define POINT_CMP_E 1
13 | #define POINT_CMP_NE 0
14 |
15 | /*! Elliptic curve (over polynomial quotient ring) point. */
16 | typedef struct _ec_pqr_point
17 | {
18 | /*! x coord. */
19 | poly_t *x;
20 | /*! y coord. */
21 | poly_t *y;
22 | } ec_pqr_point_t;
23 |
24 | /*! Elliptic curve (over polynomial quotient ring) group parameters (defining equation: y^2 = x^3 + ax + b). */
25 | typedef struct _ec_pqr_group
26 | {
27 | /*! Modulus. */
28 | poly_t *p;
29 | /*! Parameter a. (mon!) */
30 | poly_t *a;
31 | /*! Parameter b. (mon!) */
32 | poly_t *b;
33 | } ec_pqr_group_t;
34 |
35 | /*!
36 | * \brief Allocate point.
37 | */
38 | ec_pqr_point_t *ec_pqr_point_alloc(ec_pqr_group_t *ecg);
39 |
40 | /*!
41 | * \brief Free point.
42 | */
43 | void ec_pqr_point_free(ec_pqr_point_t *p);
44 |
45 | /*!
46 | * \brief Copy point.
47 | */
48 | ec_pqr_point_t *ec_pqr_point_copy(ec_pqr_point_t *d, ec_pqr_point_t *s);
49 |
50 | /*!
51 | * \brief Compare points.
52 | */
53 | int ec_pqr_point_cmp(ec_pqr_point_t *p, ec_pqr_point_t *q);
54 |
55 | /*!
56 | * \brief Zero out point.
57 | */
58 | ec_pqr_point_t *ec_pqr_point_zero(ec_pqr_point_t *p);
59 |
60 | /*!
61 | * \brief Test for zero point.
62 | */
63 | int ec_pqr_point_is_zero(ec_pqr_point_t *p);
64 |
65 | /*!
66 | * \brief Convert point to montgomery form.
67 | */
68 | void ec_pqr_point_to_mon(ec_pqr_point_t *p);
69 |
70 | /*!
71 | * \brief Convert point from montgomery form.
72 | */
73 | void ec_pqr_point_from_mon(ec_pqr_point_t *p);
74 |
75 | /*!
76 | * \brief Negate point.
77 | */
78 | ec_pqr_point_t *ec_pqr_point_neg(ec_pqr_point_t *r, ec_pqr_point_t *p, ec_pqr_group_t *ecg);
79 |
80 | /*!
81 | * \brief Double point.
82 | */
83 | ec_pqr_point_t *ec_pqr_point_double(ec_pqr_point_t *r, ec_pqr_point_t *p, ec_pqr_group_t *ecg);
84 |
85 | /*!
86 | * \brief Add two points.
87 | */
88 | ec_pqr_point_t *ec_pqr_point_add(ec_pqr_point_t *r, ec_pqr_point_t *p, ec_pqr_point_t *q, ec_pqr_group_t *ecg);
89 |
90 | /*!
91 | * \brief Multiply point with bignum (d = a * b).
92 | */
93 | ec_pqr_point_t *ec_pqr_point_mul(ec_pqr_point_t *d, bn_t *a, ec_pqr_point_t *b, ec_pqr_group_t *ecg);
94 |
95 | #endif // _EC_PQR_H_
96 |
--------------------------------------------------------------------------------
/ecdsa.c:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2016 naehrwert
3 | * Licensed under the terms of the GNU GPL, version 2
4 | * http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
5 | */
6 |
7 | #include
8 |
9 | #include "ecdsa.h"
10 |
11 | void ecdsa_sign(ecdsa_ctxt_t *ctxt, ecdsa_sig_t *sig, bn_t *H)
12 | {
13 | bn_t *e = bn_alloc(ctxt->N->n),
14 | *kk = bn_alloc(ctxt->N->n),
15 | *m = bn_alloc(ctxt->N->n),
16 | *minv = bn_alloc(ctxt->N->n);
17 | ec_point_t *mG = ec_point_alloc(ctxt->ecg->p->n);
18 |
19 | // Create random(!) m.
20 | bn_reduce(bn_rand(m), ctxt->N);
21 |
22 | // R = (mG).x
23 | ec_point_mul(mG, m, ctxt->G, ctxt->ecg);
24 | ec_point_from_mon(mG, ctxt->ecg);
25 | bn_copy(sig->R, mG->x);
26 |
27 | // S = m^(-1)*(e + Rk) mod N
28 | bn_reduce(bn_copy(e, H), ctxt->N);
29 | bn_reduce(bn_copy(kk, ctxt->k), ctxt->N);
30 | bn_to_mon(m, ctxt->N);
31 | bn_to_mon(e, ctxt->N);
32 | bn_to_mon(sig->R, ctxt->N);
33 | bn_to_mon(kk, ctxt->N);
34 |
35 | bn_mon_mul(sig->S, sig->R, kk, ctxt->N);
36 | bn_add(kk, sig->S, e, ctxt->N);
37 | bn_mon_inv(minv, m, ctxt->N);
38 | bn_mon_mul(sig->S, minv, kk, ctxt->N);
39 |
40 | bn_from_mon(sig->R, ctxt->N);
41 | bn_from_mon(sig->S, ctxt->N);
42 |
43 | //Free temporaries.
44 | ec_point_free(mG);
45 | bn_free(minv);
46 | bn_free(m);
47 | bn_free(kk);
48 | bn_free(e);
49 | }
50 |
51 | int ecdsa_verify(ecdsa_ctxt_t *ctxt, ecdsa_sig_t *sig, bn_t *H)
52 | {
53 | int res = 0;
54 | bn_t *Sinv = bn_alloc(ctxt->N->n),
55 | *e = bn_alloc(ctxt->N->n),
56 | *w1 = bn_alloc(ctxt->N->n),
57 | *w2 = bn_alloc(ctxt->N->n),
58 | *rr = bn_alloc(ctxt->N->n);
59 | ec_point_t *r1 = ec_point_alloc(ctxt->ecg->p->n),
60 | *r2 = ec_point_alloc(ctxt->ecg->p->n);
61 |
62 | bn_reduce(bn_copy(e, H), ctxt->N);
63 | bn_to_mon(sig->R, ctxt->N);
64 | bn_to_mon(sig->S, ctxt->N);
65 | bn_to_mon(e, ctxt->N);
66 |
67 | bn_mon_inv(Sinv, sig->S, ctxt->N);
68 |
69 | bn_mon_mul(w1, e, Sinv, ctxt->N);
70 | bn_mon_mul(w2, sig->R, Sinv, ctxt->N);
71 |
72 | bn_from_mon(w1, ctxt->N);
73 | bn_from_mon(w2, ctxt->N);
74 |
75 | ec_point_mul(r1, w1, ctxt->G, ctxt->ecg);
76 | ec_point_mul(r2, w2, ctxt->Q, ctxt->ecg);
77 |
78 | ec_point_add(r1, r1, r2, ctxt->ecg);
79 |
80 | ec_point_from_mon(r1, ctxt->ecg);
81 |
82 | bn_copy(rr, r1->x);
83 | bn_reduce(rr, ctxt->N);
84 |
85 | bn_from_mon(sig->R, ctxt->N);
86 | bn_from_mon(sig->S, ctxt->N);
87 |
88 | res = (bn_cmp(rr, sig->R) == BN_CMP_E);
89 |
90 | //Free temporaries.
91 | ec_point_free(r2);
92 | ec_point_free(r1);
93 | bn_free(rr);
94 | bn_free(w2);
95 | bn_free(w1);
96 | bn_free(e);
97 | bn_free(Sinv);
98 |
99 | return res;
100 | }
101 |
102 | void ecdsa_recover_priv(bn_t *k, ecdsa_ctxt_t *ctxt, bn_t *H1, bn_t *H2, ecdsa_sig_t *sig1, ecdsa_sig_t *sig2)
103 | {
104 | bn_t *z1 = bn_alloc(ctxt->N->n),
105 | *z2 = bn_alloc(ctxt->N->n),
106 | *t1 = bn_alloc(ctxt->N->n),
107 | *t2 = bn_alloc(ctxt->N->n);
108 |
109 | bn_reduce(bn_copy(z1, H1), ctxt->N);
110 | bn_reduce(bn_copy(z2, H2), ctxt->N);
111 |
112 | //t_1 = (S_1 - S_2)^{-1}
113 | bn_to_mon(bn_sub(t2, sig1->S, sig2->S, ctxt->N), ctxt->N);
114 | bn_mon_inv(t1, t2, ctxt->N);
115 |
116 | //t_1 = (Z_1 - Z_2)/(S_1 - S_2)
117 | bn_to_mon(bn_sub(t2, z1, z2, ctxt->N), ctxt->N);
118 | bn_mon_mul(t1, t2, t1, ctxt->N);
119 |
120 | //k = (S*t_1 - Z_1)/R_1
121 | bn_mon_mul(t1, bn_to_mon(sig1->S, ctxt->N), t1, ctxt->N);
122 | bn_from_mon(sig1->S, ctxt->N);
123 | bn_from_mon(t1, ctxt->N);
124 | bn_sub(t1, t1, z1, ctxt->N);
125 | bn_to_mon(t1, ctxt->N);
126 |
127 | bn_to_mon(sig1->R, ctxt->N);
128 | bn_mon_inv(t2, sig1->R, ctxt->N);
129 | bn_from_mon(sig1->R, ctxt->N);
130 |
131 | bn_mon_mul(t1, t1, t2, ctxt->N);
132 | bn_from_mon(t1, ctxt->N);
133 |
134 | bn_copy(k, t1);
135 |
136 | bn_free(t2);
137 | bn_free(t1);
138 | bn_free(z2);
139 | bn_free(z1);
140 | }
141 |
--------------------------------------------------------------------------------
/ecdsa.h:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2016 naehrwert
3 | * Licensed under the terms of the GNU GPL, version 2
4 | * http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
5 | */
6 |
7 | #ifndef _ECDSA_H_
8 | #define _ECDSA_H_
9 |
10 | #include "ec.h"
11 |
12 | /*! ECDSA context. */
13 | typedef struct _ecdsa_ctxt_t
14 | {
15 | /*! Elliptic curve group. */
16 | ec_group_t *ecg;
17 | /*! Base field modulus. */
18 | bn_t *N;
19 | /*! Generator point G. (mon!) */
20 | ec_point_t *G;
21 | /*! Public point Q. (mon!) */
22 | ec_point_t *Q;
23 | /*! Private k. */
24 | bn_t *k;
25 | } ecdsa_ctxt_t;
26 |
27 | /*! ECDSA signature. */
28 | typedef struct _ecdsa_sig_t
29 | {
30 | /*! Signature R. */
31 | bn_t *R;
32 | /*! Signature S. */
33 | bn_t *S;
34 | } ecdsa_sig_t;
35 |
36 | /*!
37 | * \brief Sign message using ECDSA.
38 | */
39 | void ecdsa_sign(ecdsa_ctxt_t *ctxt, ecdsa_sig_t *sig, bn_t *H);
40 |
41 | /*!
42 | * \brief Verify message using ECDSA.
43 | */
44 | int ecdsa_verify(ecdsa_ctxt_t *ctxt, ecdsa_sig_t *sig, bn_t *H);
45 |
46 | /*!
47 | * \brief Recover private key from flawed signatures (same R values).
48 | */
49 | void ecdsa_recover_priv(bn_t *k, ecdsa_ctxt_t *ctxt, bn_t *H1, bn_t *H2, ecdsa_sig_t *sig1, ecdsa_sig_t *sig2);
50 |
51 | #endif
52 |
--------------------------------------------------------------------------------
/ecnr.c:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2016 naehrwert
3 | * Licensed under the terms of the GNU GPL, version 2
4 | * http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
5 | */
6 |
7 | #include "ecnr.h"
8 |
9 | void ecnr_sign(ecnr_ctxt_t *ctxt, ecnr_sig_t *sig, bn_t *H)
10 | {
11 | bn_t *e = bn_alloc(ctxt->N->n),
12 | *kk = bn_alloc(ctxt->N->n),
13 | *m = bn_alloc(ctxt->N->n);
14 | ec_point_t *mG = ec_point_alloc(ctxt->ecg->p->n);
15 |
16 | // Create random(!) m.
17 | bn_reduce(bn_rand(m), ctxt->N);
18 |
19 | // R = (mG).x + e
20 | bn_reduce(bn_copy(e, H), ctxt->N);
21 | ec_point_mul(mG, m, ctxt->G, ctxt->ecg);
22 | ec_point_from_mon(mG, ctxt->ecg);
23 | bn_add(sig->R, mG->x, e, ctxt->N);
24 |
25 | // S = (m - kR) mod N
26 | bn_reduce(bn_copy(kk, ctxt->k), ctxt->N);
27 | bn_to_mon(kk, ctxt->N);
28 | bn_to_mon(sig->R, ctxt->N);
29 | bn_mon_mul(e, kk, sig->R, ctxt->N);
30 | bn_from_mon(sig->R, ctxt->N);
31 | bn_from_mon(e, ctxt->N);
32 | bn_sub(sig->S, m, e, ctxt->N);
33 |
34 | //Free temporaries.
35 | ec_point_free(mG);
36 | bn_free(m);
37 | bn_free(kk);
38 | bn_free(e);
39 | }
40 |
41 | int ecnr_verify(ecnr_ctxt_t *ctxt, ecnr_sig_t *sig, bn_t *H)
42 | {
43 | int res = 0;
44 | bn_t *e = bn_alloc(ctxt->N->n),
45 | *z = bn_alloc(ctxt->N->n);
46 | ec_point_t *P1 = ec_point_alloc(ctxt->ecg->p->n),
47 | *P2 = ec_point_alloc(ctxt->ecg->p->n);
48 |
49 | //P1 = S*G + R*Q
50 | ec_point_mul(P1, sig->S, ctxt->G, ctxt->ecg);
51 | ec_point_mul(P2, sig->R, ctxt->Q, ctxt->ecg);
52 | ec_point_add(P1, P1, P2, ctxt->ecg);
53 | ec_point_from_mon(P1, ctxt->ecg);
54 |
55 | //z = R - P.x (mod N)
56 | bn_sub(z, sig->R, P1->x, ctxt->N);
57 |
58 | bn_reduce(bn_copy(e, H), ctxt->N);
59 | res = (bn_cmp(e, z) == BN_CMP_E);
60 |
61 | bn_free(z);
62 | bn_free(e);
63 | ec_point_free(P2);
64 | ec_point_free(P1);
65 |
66 | return res;
67 | }
68 |
--------------------------------------------------------------------------------
/ecnr.h:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2016 naehrwert
3 | * Licensed under the terms of the GNU GPL, version 2
4 | * http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
5 | */
6 |
7 | #ifndef _ECNR_H_
8 | #define _ECNR_H_
9 |
10 | #include "ec.h"
11 |
12 | /*! Elliptic curve Nyberg-Rueppel context. */
13 | typedef struct _ecnr_ctxt_t
14 | {
15 | /*! Elliptic curve group. */
16 | ec_group_t *ecg;
17 | /*! Base field modulus. */
18 | bn_t *N;
19 | /*! Generator point G. (mon!) */
20 | ec_point_t *G;
21 | /*! Public point Q. (mon!) */
22 | ec_point_t *Q;
23 | /*! Private k. */
24 | bn_t *k;
25 | } ecnr_ctxt_t;
26 |
27 | /*! Elliptic curve Nyberg-Rueppel signature. */
28 | typedef struct _ecnr_sig_t
29 | {
30 | /*! Signature R. */
31 | bn_t *R;
32 | /*! Signature S. */
33 | bn_t *S;
34 | } ecnr_sig_t;
35 |
36 | /*!
37 | * \brief Sign message using ECNR.
38 | */
39 | void ecnr_sign(ecnr_ctxt_t *ctxt, ecnr_sig_t *sig, bn_t *H);
40 |
41 | /*!
42 | * \brief Verify message using ECNR.
43 | */
44 | int ecnr_verify(ecnr_ctxt_t *ctxt, ecnr_sig_t *sig, bn_t *H);
45 |
46 | #endif
47 |
--------------------------------------------------------------------------------
/inr.c:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2016 naehrwert
3 | * Licensed under the terms of the GNU GPL, version 2
4 | * http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
5 | */
6 |
7 | #include "inr.h"
8 |
9 | void inr_sign(inr_ctxt_t *ctxt, inr_sig_t *sig, bn_t *m)
10 | {
11 | bn_t *k = bn_alloc(ctxt->p->n),
12 | *r2 = bn_alloc(ctxt->p->n),
13 | *t = bn_alloc(ctxt->p->n);
14 |
15 | // Try to create a valid signature.
16 | while (1)
17 | {
18 | bn_reduce(bn_rand(k), ctxt->q); // TODO: should be k \in [1,q-1].
19 | bn_to_mon(bn_reduce(bn_copy(sig->r, m), ctxt->p), ctxt->p); // r=m (mod p)
20 | bn_mon_pow(t, ctxt->g, ctxt->p, k); // t=g^k
21 | bn_mon_mul(sig->r, sig->r, t, ctxt->p); // r=m*g^k
22 | bn_from_mon(sig->r, ctxt->p);
23 | bn_reduce(bn_copy(r2, sig->r), ctxt->q); // r2 = r mod q
24 | bn_to_mon(r2, ctxt->q);
25 | bn_mon_mul(r2, r2, ctxt->x, ctxt->q); // r2 = r2*x
26 | bn_from_mon(r2, ctxt->q);
27 | bn_zero(sig->s);
28 | bn_sub(sig->s, sig->s, k, ctxt->q); // s = -k
29 | bn_sub(sig->s, sig->s, r2, ctxt->q); // s = -k - x*r2
30 | if (inr_verify(ctxt, sig, m))
31 | break;
32 | }
33 |
34 | bn_free(t);
35 | bn_free(r2);
36 | bn_free(k);
37 | }
38 |
39 | int inr_verify(inr_ctxt_t *ctxt, inr_sig_t *sig, bn_t *m)
40 | {
41 | bn_t *r2 = bn_alloc(ctxt->p->n),
42 | *m2 = bn_alloc(ctxt->p->n),
43 | *t = bn_alloc(ctxt->p->n);
44 |
45 | bn_to_mon(bn_copy(m2, sig->r), ctxt->p);
46 | bn_reduce(bn_copy(r2, sig->r), ctxt->q); // r2 = r mod q
47 | bn_to_mon(sig->r, ctxt->p);
48 |
49 | bn_mon_pow(t, ctxt->g, ctxt->p, sig->s); // t=g^s
50 | bn_mon_mul(m2, m2, t, ctxt->p); // m2=r*g^s
51 | bn_mon_pow(t, ctxt->y, ctxt->p, r2); // t=y^r2
52 | bn_mon_mul(m2, m2, t, ctxt->p); // m2=r*g^s*y^r2
53 |
54 | bn_from_mon(sig->r, ctxt->p);
55 | bn_from_mon(m2, ctxt->p);
56 |
57 | int res = bn_cmp(bn_reduce(bn_copy(t, m), ctxt->p), m2) == BN_CMP_E;
58 |
59 | bn_free(t);
60 | bn_free(m2);
61 | bn_free(r2);
62 |
63 | return res;
64 | }
65 |
--------------------------------------------------------------------------------
/inr.h:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2016 naehrwert
3 | * Licensed under the terms of the GNU GPL, version 2
4 | * http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
5 | */
6 |
7 | #ifndef _INR_H_
8 | #define _INR_H_
9 |
10 | #include "bn.h"
11 |
12 | /*! Integer Nyberg-Rueppel context. */
13 | typedef struct _inr_ctxt_t
14 | {
15 | /*! Common prime p (= u*q + 1 with small u). */
16 | bn_t *p;
17 | /*! Common prime q. */
18 | bn_t *q;
19 | /*! Common primitive root g of q. (mon!) */
20 | bn_t *g;
21 | /*! Private x \in [1, q - 1] (mod q). (mon!) */
22 | bn_t *x;
23 | /*! Public y (mod p). (mon!) */
24 | bn_t *y;
25 | } inr_ctxt_t;
26 |
27 | /*! Integer Nyber-Rueppel signature. */
28 | typedef struct _inr_sig_t
29 | {
30 | /*! Signature r (mod p) */
31 | bn_t *r;
32 | /*! Signature s (mod q) */
33 | bn_t *s;
34 | } inr_sig_t;
35 |
36 | /*!
37 | * \brief Sign message using INR.
38 | * \param ctxt Integer Nyberg-Rueppel context.
39 | * \param sig Integer Nyber-Rueppel signature.
40 | * \param m Message to sign.
41 | */
42 | void inr_sign(inr_ctxt_t *ctxt, inr_sig_t *sig, bn_t *m);
43 |
44 | /*!
45 | * \brief Verify message sing INR.
46 | * \param ctxt Integer Nyberg-Rueppel context.
47 | * \param sig Integer Nyber-Rueppel signature.
48 | * \param m Message to verify.
49 | */
50 | int inr_verify(inr_ctxt_t *ctxt, inr_sig_t *sig, bn_t *m);
51 |
52 | #endif
53 |
--------------------------------------------------------------------------------
/mt19937.c:
--------------------------------------------------------------------------------
1 | //Mersenne-Twister 19937 pseudorandom number generator.
2 | //Reference implementation at:
3 | //http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/MT2002/CODES/mt19937ar.c
4 |
5 | #include "mt19937.h"
6 |
7 | void mt19937_init(mt19937_ctxt_t *ctxt, unsigned int seed)
8 | {
9 | ctxt->state[0] = seed;
10 |
11 | for (ctxt->idx = 1; ctxt->idx < MT_N; ctxt->idx++)
12 | ctxt->state[ctxt->idx] = (1812433253 * (ctxt->state[ctxt->idx - 1] ^ (ctxt->state[ctxt->idx - 1] >> 30)) + ctxt->idx);
13 |
14 | ctxt->idx = MT_M + 1;
15 | }
16 |
17 | unsigned int mt19937_update(mt19937_ctxt_t *ctxt)
18 | {
19 | unsigned int y, k;
20 | static unsigned int mag01[2] = { 0, MT_MATRIX_A };
21 |
22 | if (ctxt->idx >= MT_N)
23 | {
24 | for (k = 0; k < MT_N - MT_M; k++)
25 | {
26 | y = (ctxt->state[k] & MT_UPPER_MASK) |
27 | (ctxt->state[k + 1] & MT_LOWER_MASK);
28 | ctxt->state[k] = ctxt->state[k + MT_M] ^ (y >> 1) ^ mag01[y & 1];
29 | }
30 |
31 | for (; k < MT_N - 1; k++)
32 | {
33 | y = (ctxt->state[k] & MT_UPPER_MASK) |
34 | (ctxt->state[k + 1] & MT_LOWER_MASK);
35 | ctxt->state[k] = ctxt->state[k + (MT_M - MT_N)] ^ (y >> 1) ^ mag01[y & 1];
36 | }
37 |
38 | y = (ctxt->state[MT_N - 1] & MT_UPPER_MASK) |
39 | (ctxt->state[0] & MT_LOWER_MASK);
40 | ctxt->state[MT_N - 1] = ctxt->state[MT_M - 1] ^ (y >> 1) ^ mag01[y & 1];
41 |
42 | ctxt->idx = 0;
43 | }
44 |
45 | y = ctxt->state[ctxt->idx++];
46 |
47 | y ^= (y >> 11);
48 | y ^= (y << 7) & 0x9d2c5680UL;
49 | y ^= (y << 15) & 0xefc60000UL;
50 | y ^= (y >> 18);
51 |
52 | return y;
53 | }
54 |
--------------------------------------------------------------------------------
/mt19937.h:
--------------------------------------------------------------------------------
1 | //Mersenne-Twister 19937 pseudorandom number generator.
2 | //Reference implementation at:
3 | //http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/MT2002/CODES/mt19937ar.c
4 |
5 | #ifndef _MT19937_H_
6 | #define _MT19937_H_
7 |
8 | /*! State size. */
9 | #define MT_N 624
10 | #define MT_M 397
11 | #define MT_MATRIX_A 0x9908b0df
12 | #define MT_UPPER_MASK 0x80000000
13 | #define MT_LOWER_MASK 0x7fffffff
14 |
15 | /*! Mersenne-Twister 19937 context. */
16 | typedef struct _mt19937_ctxt
17 | {
18 | /*! State. */
19 | unsigned int state[MT_N];
20 | /*! Index. */
21 | unsigned int idx;
22 | } mt19937_ctxt_t;
23 |
24 | /*!
25 | * \brief Initialize Mersenne-Twister 19937 context.
26 | *
27 | * \param ctxt Mersenne-Twister 19937 context.
28 | * \param seed Random seed.
29 | */
30 | void mt19937_init(mt19937_ctxt_t *ctxt, unsigned int seed);
31 |
32 | /*!
33 | * \brief Update Mersenne-Twister 19937 state.
34 | *
35 | * \param ctxt Mersenne-Twister 19937 context.
36 | *
37 | * \return Generated pseudorandom number.
38 | */
39 | unsigned int mt19937_update(mt19937_ctxt_t *ctxt);
40 |
41 | #endif
42 |
--------------------------------------------------------------------------------
/pairing.c:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2016 naehrwert
3 | * Licensed under the terms of the GNU GPL, version 2
4 | * http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
5 | */
6 |
7 | #include
8 | #include
9 |
10 | #include "pairing.h"
11 |
12 | poly_t *_pairing_line(poly_t *d, ec_pqr_point_t *P, ec_pqr_point_t *R, ec_pqr_point_t *Q, ec_pqr_group_t *ecg)
13 | {
14 | if (ec_pqr_point_is_zero(P) || ec_pqr_point_is_zero(R))
15 | {
16 | if (ec_pqr_point_cmp(P, R) == POINT_CMP_E)
17 | return poly_one(d);
18 | if (ec_pqr_point_is_zero(P))
19 | return pqr_sub(d, Q->x, R->x, ecg->p);
20 | if (ec_pqr_point_is_zero(R))
21 | return pqr_sub(d, Q->x, P->x, ecg->p);
22 | }
23 | else if (ec_pqr_point_cmp(P, R) != POINT_CMP_E)
24 | {
25 | if (poly_cmp(P->x, R->x) == POLY_CMP_E)
26 | return pqr_sub(d, Q->x, P->x, ecg->p);
27 |
28 | poly_t *l = poly_alloc(d->degree, d->N, 1);
29 |
30 | pqr_sub(l, R->x, P->x, ecg->p); //l = R.x - P.x
31 | pqr_inv(d, l, ecg->p); //d = 1 / (R.x - P.x)
32 | pqr_sub(l, R->y, P->y, ecg->p); //l = R.y - P.y
33 | pqr_mul(l, l, d, ecg->p); //l = (R.y - P.y) / (R.x - P.x)
34 | pqr_sub(d, Q->x, P->x, ecg->p); //d = Q.x - P.x
35 | pqr_mul(l, l, d, ecg->p); //l = l * (Q.x - P.x)
36 | pqr_sub(d, Q->y, P->y, ecg->p); //d = Q.y - P.y
37 | pqr_sub(d, d, l, ecg->p); //d = Q.y - P.y - l * (Q.x - P.x)
38 |
39 | poly_free(l, 1);
40 |
41 | return d;
42 | }
43 |
44 | poly_t *t = poly_alloc(d->degree, d->N, 1);
45 | poly_t *s = poly_alloc(d->degree, d->N, 1);
46 |
47 | pqr_mul(t, P->x, P->x, ecg->p); //t = P.x*P.x
48 | pqr_add(s, t, t, ecg->p); //s = 2*P.x*P.x
49 | pqr_add(s, s, t, ecg->p); //s = 3*P.x*P.x
50 | pqr_add(s, s, ecg->a, ecg->p); //s = 3*px*px + a
51 | pqr_add(t, P->y, P->y, ecg->p); //t = 2*py
52 |
53 | if (poly_is_zero(t))
54 | pqr_sub(d, Q->x, P->x, ecg->p);
55 | else
56 | {
57 | pqr_inv(t, t, ecg->p); //t = 1 / (2*py)
58 | pqr_mul(s, s, t, ecg->p); //s = (3*px*px + a) / (2*py)
59 | pqr_sub(t, Q->x, P->x, ecg->p); //t = Q.x - P.x
60 | pqr_mul(s, s, t, ecg->p); //s = s * (Q.x - P.x)
61 | pqr_sub(d, Q->y, P->y, ecg->p); //d = Q.y - P.y
62 | pqr_sub(d, d, s, ecg->p); //d = Q.y - P.y - s * (Q.x - P.x)
63 | }
64 |
65 | poly_free(s, 1);
66 | poly_free(t, 1);
67 |
68 | return d;
69 | }
70 |
71 | poly_t *_pairing_miller(poly_t *d, ec_pqr_point_t *P, ec_pqr_point_t *Q, bn_t *n, ec_pqr_group_t *ecg)
72 | {
73 | assert(!ec_pqr_point_is_zero(Q));
74 | assert(!bn_is_zero(n));
75 |
76 | int i;
77 |
78 | ec_pqr_point_t *R = ec_pqr_point_copy(ec_pqr_point_alloc(ecg), P);
79 | ec_pqr_point_t *S = ec_pqr_point_alloc(ecg);
80 |
81 | poly_t *l = poly_alloc(d->degree, d->N, 1);
82 | poly_t *v = poly_alloc(d->degree, d->N, 1);
83 |
84 | poly_one(d);
85 |
86 | for (i = bn_maxbit(n) - 1; i >= 0; i--)
87 | {
88 | ec_pqr_point_double(S, R, ecg); //S = [2]R
89 | _pairing_line(l, R, R, Q, ecg); //l_{R,R}
90 | ec_pqr_point_neg(R, S, ecg);
91 | _pairing_line(v, S, R, Q, ecg);
92 | pqr_inv(v, v, ecg->p); //1 / v_{[2]R}
93 | pqr_mul(d, d, d, ecg->p);
94 | pqr_mul(d, d, l, ecg->p);
95 | pqr_mul(d, d, v, ecg->p); //d = d^2 * l_{R,R} / v_{[2]R}
96 |
97 | ec_pqr_point_copy(R, S);
98 |
99 | if (!bn_getbit(n, i))
100 | continue;
101 |
102 | ec_pqr_point_add(S, R, P, ecg); //S = R + P
103 | _pairing_line(l, R, P, Q, ecg); //l_{R,P}
104 | ec_pqr_point_neg(R, S, ecg);
105 | _pairing_line(v, S, R, Q, ecg);
106 | pqr_inv(v, v, ecg->p); //1 / v_{R+P}
107 | pqr_mul(d, d, l, ecg->p);
108 | pqr_mul(d, d, v, ecg->p); //d = d * l_{R,P} / v_{R+P}
109 |
110 | ec_pqr_point_copy(R, S);
111 |
112 | }
113 |
114 | poly_free(v, 1);
115 | poly_free(l, 1);
116 | ec_pqr_point_free(S);
117 | ec_pqr_point_free(R);
118 |
119 | return d;
120 | }
121 |
122 | poly_t *pairing_weil(poly_t *d, ec_pqr_point_t *P, ec_pqr_point_t *Q, bn_t *n, ec_pqr_group_t *ecg)
123 | {
124 | poly_t *t = poly_alloc(d->degree, d->N, 1);
125 |
126 | //d = f_{n,P}(D_Q) / f_{n,Q}(D_P)
127 | _pairing_miller(d, P, Q, n, ecg);
128 | _pairing_miller(t, Q, P, n, ecg);
129 | pqr_inv(t, t, ecg->p);
130 | pqr_mul(d, d, t, ecg->p);
131 |
132 | if (bn_getbit(n, 0))
133 | {
134 | //d = -d
135 | poly_zero(t);
136 | pqr_sub(d, t, d, ecg->p);
137 | }
138 |
139 | poly_free(t, 1);
140 |
141 | return d;
142 | }
143 |
144 | /*poly_t *pairing_tate(poly_t *d, ec_pqr_point_t *P, ec_pqr_point_t *Q, bn_t *n, bn_t *k, ec_pqr_group_t *ecg)
145 | {
146 | bn_t *e = bn_alloc(ecg->p->N->n);
147 |
148 | _pairing_miller(d, P, Q, n, ecg);
149 | //(q^k - 1) / n
150 | bn_exp(e, ecg->p->N, k);
151 | bn_sub(e, e, one);
152 | bn_div(e, e, n);
153 |
154 | pqr_exp(d, d, e, ecg->p);
155 |
156 | bn_free(e);
157 |
158 | return d;
159 | }*/
160 |
--------------------------------------------------------------------------------
/pairing.h:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2016 naehrwert
3 | * Licensed under the terms of the GNU GPL, version 2
4 | * http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
5 | */
6 |
7 | #ifndef _PAIRING_H_
8 | #define _PAIRING_H_
9 |
10 | #include "ec_pqr.h"
11 |
12 | /*!
13 | * \brief Compute line.
14 | */
15 | poly_t *_pairing_line(poly_t *d, ec_pqr_point_t *P, ec_pqr_point_t *R, ec_pqr_point_t *Q, ec_pqr_group_t *ecg);
16 |
17 | /*!
18 | * \brief Miller's algorithm.
19 | */
20 | poly_t *_pairing_miller(poly_t *d, ec_pqr_point_t *P, ec_pqr_point_t *Q, bn_t *n, ec_pqr_group_t *ecg);
21 |
22 | /*!
23 | * \brief Weil pairing.
24 | */
25 | poly_t *pairing_weil(poly_t *d, ec_pqr_point_t *P, ec_pqr_point_t *Q, bn_t *n, ec_pqr_group_t *ecg);
26 |
27 | #endif // _PAIRING_H_
28 |
--------------------------------------------------------------------------------
/pc.c:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2016 naehrwert
3 | * Licensed under the terms of the GNU GPL, version 2
4 | * http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
5 | */
6 |
7 | #include
8 |
9 | #include "pc.h"
10 |
11 | static void _pc_add(bn_t *d, bn_t *a, bn_t *b, pc_group_t *pcg)
12 | {
13 | bn_add(d, a, b, pcg->p);
14 | }
15 |
16 | static void _pc_sub(bn_t *d, bn_t *a, bn_t *b, pc_group_t *pcg)
17 | {
18 | bn_sub(d, a, b, pcg->p);
19 | }
20 |
21 | static void _pc_mul(bn_t *d, bn_t *a, bn_t *b, pc_group_t *pcg)
22 | {
23 | bn_mon_mul(d, a, b, pcg->p);
24 | }
25 |
26 | static void _pc_square(bn_t *d, bn_t *a, pc_group_t *pcg)
27 | {
28 | _pc_mul(d, a, a, pcg);
29 | }
30 |
31 | static void _pc_inv(bn_t *d, bn_t *a, pc_group_t *pcg)
32 | {
33 | bn_t *t = bn_copy(bn_alloc(a->n), a);
34 | bn_mon_inv(d, t, pcg->p);
35 | bn_free(t);
36 | }
37 |
38 | pc_point_t *pc_point_alloc(u32 n)
39 | {
40 | pc_point_t *res;
41 |
42 | if ((res = (pc_point_t *)mem_alloc(sizeof(pc_point_t))) == NULL)
43 | return NULL;
44 |
45 | res->x = bn_alloc(n);
46 | res->y = bn_alloc(n);
47 |
48 | return res;
49 | }
50 |
51 | void pc_point_free(pc_point_t *p)
52 | {
53 | bn_free(p->x);
54 | bn_free(p->y);
55 | mem_free(p);
56 | }
57 |
58 | pc_point_t *pc_point_copy(pc_point_t *d, pc_point_t *s)
59 | {
60 | bn_copy(d->x, s->x);
61 | bn_copy(d->y, s->y);
62 |
63 | return d;
64 | }
65 |
66 | pc_point_t *pc_point_zero(pc_point_t *p)
67 | {
68 | bn_zero(p->x);
69 | bn_zero(p->y);
70 |
71 | bn_set_ui(p->x, 1);
72 |
73 | return p;
74 | }
75 |
76 | int pc_point_is_zero(pc_point_t *p)
77 | {
78 | return (bn_is_zero(p->x) && bn_is_zero(p->y));
79 | }
80 |
81 | void pc_point_to_mon(pc_point_t *p, pc_group_t *pcg)
82 | {
83 | bn_to_mon(p->x, pcg->p);
84 | bn_to_mon(p->y, pcg->p);
85 | }
86 |
87 | void pc_point_from_mon(pc_point_t *p, pc_group_t *pcg)
88 | {
89 | bn_from_mon(p->x, pcg->p);
90 | bn_from_mon(p->y, pcg->p);
91 | }
92 |
93 | pc_point_t *pc_point_add(pc_point_t *r, pc_point_t *p, pc_point_t *q, pc_group_t *pcg)
94 | {
95 | bn_t *x1 = p->x, *y1 = p->y, *x2 = q->x, *y2 = q->y;
96 | bn_t *s = bn_alloc(pcg->p->n), *t = bn_alloc(pcg->p->n);
97 | pc_point_t *rr = pc_point_alloc(pcg->p->n);
98 |
99 | // r.x = x1*x2 + D*y1*y2
100 | _pc_mul(s, x1, x2, pcg);
101 | _pc_mul(t, y1, y2, pcg);
102 | _pc_mul(t, pcg->D, t, pcg);
103 | _pc_add(rr->x, s, t, pcg);
104 |
105 | // r.y = x1*y2 + x2*y1
106 | _pc_mul(s, x1, y2, pcg);
107 | _pc_mul(t, x2, y1, pcg);
108 | _pc_add(rr->y, s, t, pcg);
109 |
110 | pc_point_copy(r, rr);
111 |
112 | pc_point_free(rr);
113 | bn_free(t);
114 | bn_free(s);
115 |
116 | return r;
117 | }
118 |
119 |
120 | pc_point_t *pc_point_mul(pc_point_t *d, bn_t *a, pc_point_t *b, pc_group_t *pcg)
121 | {
122 | int i;
123 | pc_point_t *bt = pc_point_copy(pc_point_alloc(b->x->n), b);
124 |
125 | pc_point_zero(d);
126 |
127 | for (i = 0; i <= bn_maxbit(a); i++)
128 | {
129 | if (bn_getbit(a, i))
130 | pc_point_add(d, d, bt, pcg);
131 | pc_point_add(bt, bt, bt, pcg);
132 | }
133 |
134 | pc_point_free(bt);
135 |
136 | return d;
137 | }
138 |
--------------------------------------------------------------------------------
/pc.h:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2016 naehrwert
3 | * Licensed under the terms of the GNU GPL, version 2
4 | * http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
5 | */
6 |
7 | #ifndef _PC_H_
8 | #define _PC_H_
9 |
10 | #include "bn.h"
11 |
12 | /*! Pell conic point. */
13 | typedef struct _pc_point
14 | {
15 | /*! x coord. */
16 | bn_t *x;
17 | /*! y coord. */
18 | bn_t *y;
19 | } pc_point_t;
20 |
21 | /*! Pell conic group parameters (defining equation: x^2 - D*y^2 = 1). */
22 | typedef struct _pc_group
23 | {
24 | /*! Modulus. */
25 | bn_t *p;
26 | /*! Parameter D. (mon!) */
27 | bn_t *D;
28 | } pc_group_t;
29 |
30 | /*!
31 | * \brief Allocate point.
32 | */
33 | pc_point_t *pc_point_alloc(u32 n);
34 |
35 | /*!
36 | * \brief Free point.
37 | */
38 | void pc_point_free(pc_point_t *p);
39 |
40 | /*!
41 | * \brief Copy point.
42 | */
43 | pc_point_t *pc_point_copy(pc_point_t *d, pc_point_t *s);
44 |
45 | /*!
46 | * \brief Zero out point.
47 | */
48 | pc_point_t *pc_point_zero(pc_point_t *p);
49 |
50 | /*!
51 | * \brief Test for zero point.
52 | */
53 | int pc_point_is_zero(pc_point_t *p);
54 |
55 | /*!
56 | * \brief Convert point to montgomery form.
57 | */
58 | void pc_point_to_mon(pc_point_t *p, pc_group_t *pcg);
59 |
60 | /*!
61 | * \brief Convert point from montgomery form.
62 | */
63 | void pc_point_from_mon(pc_point_t *p, pc_group_t *pcg);
64 |
65 | /*!
66 | * \brief Add two points.
67 | */
68 | pc_point_t *pc_point_add(pc_point_t *r, pc_point_t *p, pc_point_t *q, pc_group_t *pcg);
69 |
70 | /*!
71 | * \brief Multiply point with bignum (d = a * b).
72 | */
73 | pc_point_t *pc_point_mul(pc_point_t *d, bn_t *a, pc_point_t *b, pc_group_t *pcg);
74 |
75 | #endif
76 |
--------------------------------------------------------------------------------
/pcnr.c:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2016 naehrwert
3 | * Licensed under the terms of the GNU GPL, version 2
4 | * http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
5 | */
6 |
7 | #include "pcnr.h"
8 |
9 | void pcnr_sign(pcnr_ctxt_t *ctxt, pcnr_sig_t *sig, bn_t *H)
10 | {
11 | bn_t *e = bn_alloc(ctxt->N->n),
12 | *kk = bn_alloc(ctxt->N->n),
13 | *m = bn_alloc(ctxt->N->n);
14 | pc_point_t *mG = pc_point_alloc(ctxt->pcg->p->n);
15 |
16 | // Create random(!) m.
17 | bn_reduce(bn_rand(m), ctxt->N);
18 |
19 | // R = (mG).x + e
20 | bn_reduce(bn_copy(e, H), ctxt->N);
21 | pc_point_mul(mG, m, ctxt->G, ctxt->pcg);
22 | pc_point_from_mon(mG, ctxt->pcg);
23 | bn_add(sig->R, mG->x, e, ctxt->N);
24 |
25 | // S = (m - kR) mod N
26 | bn_reduce(bn_copy(kk, ctxt->k), ctxt->N);
27 | bn_to_mon(kk, ctxt->N);
28 | bn_to_mon(sig->R, ctxt->N);
29 | bn_mon_mul(e, kk, sig->R, ctxt->N);
30 | bn_from_mon(sig->R, ctxt->N);
31 | bn_from_mon(e, ctxt->N);
32 | bn_sub(sig->S, m, e, ctxt->N);
33 |
34 | //Free temporaries.
35 | pc_point_free(mG);
36 | bn_free(m);
37 | bn_free(kk);
38 | bn_free(e);
39 | }
40 |
41 | int pcnr_verify(pcnr_ctxt_t *ctxt, pcnr_sig_t *sig, bn_t *H)
42 | {
43 | int res = 0;
44 | bn_t *e = bn_alloc(ctxt->N->n),
45 | *z = bn_alloc(ctxt->N->n);
46 | pc_point_t *P1 = pc_point_alloc(ctxt->pcg->p->n),
47 | *P2 = pc_point_alloc(ctxt->pcg->p->n);
48 |
49 | //P1 = S*G + R*Q
50 | pc_point_mul(P1, sig->S, ctxt->G, ctxt->pcg);
51 | pc_point_mul(P2, sig->R, ctxt->Q, ctxt->pcg);
52 | pc_point_add(P1, P1, P2, ctxt->pcg);
53 | pc_point_from_mon(P1, ctxt->pcg);
54 |
55 | //z = R - P.x (mod N)
56 | bn_sub(z, sig->R, P1->x, ctxt->N);
57 |
58 | bn_reduce(bn_copy(e, H), ctxt->N);
59 | res = (bn_cmp(e, z) == BN_CMP_E);
60 |
61 | bn_free(z);
62 | bn_free(e);
63 | pc_point_free(P2);
64 | pc_point_free(P1);
65 |
66 | return res;
67 | }
68 |
--------------------------------------------------------------------------------
/pcnr.h:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2016 naehrwert
3 | * Licensed under the terms of the GNU GPL, version 2
4 | * http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
5 | */
6 |
7 | #ifndef _PCNR_H_
8 | #define _PCNR_H_
9 |
10 | #include "pc.h"
11 |
12 | /*! Pell conic Nyberg-Rueppel context. */
13 | typedef struct _pcnr_ctxt_t
14 | {
15 | /*! Pell conic group. */
16 | pc_group_t *pcg;
17 | /*! Base field modulus. */
18 | bn_t *N;
19 | /*! Generator point G. (mon!) */
20 | pc_point_t *G;
21 | /*! Public point Q. (mon!) */
22 | pc_point_t *Q;
23 | /*! Private k. */
24 | bn_t *k;
25 | } pcnr_ctxt_t;
26 |
27 | /*! Pell conic Nyberg-Rueppel signature. */
28 | typedef struct _pcnr_sig_t
29 | {
30 | /*! Signature R. */
31 | bn_t *R;
32 | /*! Signature S. */
33 | bn_t *S;
34 | } pcnr_sig_t;
35 |
36 | /*!
37 | * \brief Sign message using PCNR.
38 | */
39 | void pcnr_sign(pcnr_ctxt_t *ctxt, pcnr_sig_t *sig, bn_t *H);
40 |
41 | /*!
42 | * \brief Verify message using PCNR.
43 | */
44 | int pcnr_verify(pcnr_ctxt_t *ctxt, pcnr_sig_t *sig, bn_t *H);
45 |
46 | #endif
47 |
--------------------------------------------------------------------------------
/poly.c:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2016 naehrwert
3 | * Licensed under the terms of the GNU GPL, version 2
4 | * http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
5 | */
6 |
7 | #include
8 | #include
9 | #include
10 |
11 | #include "poly.h"
12 |
13 | /* Wrapper for safe calling fast poly op. */
14 | #define _FAST_WRAPPER(op, d, a, b) \
15 | do { \
16 | if (d == a && d != b) \
17 | { \
18 | poly_t *t = poly_alloc(d->degree, d->N, 1); \
19 | poly_copy(t, a, 0); \
20 | poly_##op##_fast(d, t, b); \
21 | poly_free(t, 1); \
22 | return d; \
23 | } \
24 | else if (d == b && d != a) \
25 | { \
26 | poly_t *t = poly_alloc(d->degree, d->N, 1); \
27 | poly_copy(t, b, 0); \
28 | poly_##op##_fast(d, a, t); \
29 | poly_free(t, 1); \
30 | return d; \
31 | } \
32 | else if (d == a && d == b) \
33 | { \
34 | poly_t *t = poly_alloc(d->degree, d->N, 1); \
35 | poly_copy(t, a, 0); \
36 | poly_##op##_fast(d, t, t); \
37 | poly_free(t, 1); \
38 | return d; \
39 | } \
40 | return poly_##op##_fast(d, a, b); \
41 | } while (0)
42 |
43 | poly_t *poly_read(FILE *fp, poly_t *dst)
44 | {
45 | int i;
46 |
47 | for (i = 0; i <= dst->degree; i++)
48 | bn_read(fp, dst->coeffs[i]);
49 |
50 | return dst;
51 | }
52 |
53 | poly_t *poly_write(FILE *fp, poly_t *p)
54 | {
55 | int i;
56 |
57 | for (i = 0; i <= p->degree; i++)
58 | bn_write(fp, p->coeffs[i]);
59 |
60 | return p;
61 | }
62 |
63 | void poly_print(FILE *fp, const s8 *pre, poly_t *p, const s8 *post)
64 | {
65 | int i, not_first = 0;
66 |
67 | if (p == NULL)
68 | {
69 | fprintf(fp, "%s(NULL)%s", pre, post);
70 | return;
71 | }
72 |
73 | fputs((char *)pre, fp);
74 | for (i = 0; i <= p->degree; i++)
75 | {
76 | if (bn_is_zero(p->coeffs[i]))
77 | continue;
78 |
79 | if (not_first)
80 | fputs(" + ", fp);
81 | else
82 | not_first = 1;
83 |
84 | bn_print(fp, "", bn_from_mon(p->coeffs[i], p->N), "");
85 | bn_to_mon(p->coeffs[i], p->N);
86 |
87 | if (i == 1)
88 | fputs("*X", fp);
89 | else if (i > 1)
90 | fprintf(fp, "*X^%d", i);
91 | }
92 | fputs((char *)post, fp);
93 | }
94 |
95 | poly_t *poly_alloc(int degree, bn_t *N, int alloc_coeffs)
96 | {
97 | poly_t *res;
98 |
99 | if ((res = (poly_t *)mem_alloc(sizeof(poly_t))) == NULL)
100 | return NULL;
101 |
102 | // Degree + 1 coeffs.
103 | if ((res->coeffs = (bn_t **)mem_alloc(sizeof(bn_t *) * (degree + 1))) == NULL)
104 | {
105 | mem_free(res);
106 | return NULL;
107 | }
108 |
109 | res->degree = degree;
110 | res->N = N;
111 |
112 | if (alloc_coeffs)
113 | {
114 | int i;
115 | for (i = 0; i < degree + 1; i++)
116 | res->coeffs[i] = bn_zero(bn_alloc(N->n));
117 | }
118 |
119 | return res;
120 | }
121 |
122 | void poly_free(poly_t *p, int free_coeffs)
123 | {
124 | if (free_coeffs)
125 | {
126 | int i;
127 | for (i = 0; i < p->degree + 1; i++)
128 | bn_free(p->coeffs[i]);
129 | }
130 |
131 | mem_free(p->coeffs);
132 | mem_free(p);
133 | }
134 |
135 | poly_t *poly_adjust(poly_t *p, int degree, int alloc_free_coeffs)
136 | {
137 | if (p->degree == degree)
138 | return p;
139 |
140 | if (p->degree < degree)
141 | {
142 | // Grow polynomial.
143 | p->coeffs = (bn_t **)realloc(p->coeffs, sizeof(bn_t *) * (degree + 1));
144 |
145 | if (alloc_free_coeffs)
146 | {
147 | // Allocate new coefficients.
148 | int i;
149 | for (i = p->degree + 1; i < degree + 1; i++)
150 | p->coeffs[i] = bn_zero(bn_alloc(p->N->n));
151 | }
152 |
153 | p->degree = degree;
154 | }
155 | else if (p->degree > degree)
156 | {
157 | if (alloc_free_coeffs)
158 | {
159 | // Free old coefficients
160 | int i;
161 | for (i = degree + 1; i < p->degree + 1; i++)
162 | bn_free(p->coeffs[i]);
163 | }
164 |
165 | // Shrink polynomial.
166 | p->coeffs = (bn_t **)realloc(p->coeffs, sizeof(bn_t *) * (degree + 1));
167 | p->degree = degree;
168 | }
169 |
170 | return p;
171 | }
172 |
173 | poly_t *poly_copy(poly_t *d, poly_t *s, int adjust)
174 | {
175 | int i;
176 |
177 | if (adjust)
178 | {
179 | // Adjust degree and copy all of the coefficients.
180 | if (d->degree != s->degree)
181 | poly_adjust(d, s->degree, 1);
182 | for (i = 0; i < d->degree + 1; i++)
183 | bn_copy(d->coeffs[i], s->coeffs[i]);
184 |
185 | return d;
186 | }
187 |
188 | int to = d->degree < s->degree ? d->degree + 1 : s->degree + 1;
189 |
190 | // Copy or truncate.
191 | for (i = 0; i < to; i++)
192 | bn_copy(d->coeffs[i], s->coeffs[i]);
193 |
194 | // Zero out higher degrees.
195 | for (; i < d->degree + 1; i++)
196 | bn_zero(d->coeffs[i]);
197 |
198 | return d;
199 | }
200 |
201 | poly_t *poly_concat(poly_t *d, poly_t *a, poly_t *b)
202 | {
203 | int i;
204 |
205 | poly_adjust(d, a->degree + b->degree + 1, 1);
206 | for (i = 0; i < a->degree + 1; i++)
207 | bn_copy(d->coeffs[i], a->coeffs[i]);
208 | for (; i < a->degree + 1 + b->degree + 1; i++)
209 | bn_copy(d->coeffs[i], b->coeffs[i - a->degree - 1]);
210 |
211 | return d;
212 | }
213 |
214 | int poly_cmp(poly_t * p, poly_t * q)
215 | {
216 | int i;
217 |
218 | if (p->degree != q->degree)
219 | return POLY_CMP_NE;
220 |
221 | for (i = 0; i < p->degree + 1; i++)
222 | if (bn_cmp(p->coeffs[i], q->coeffs[i]) != BN_CMP_E)
223 | return POLY_CMP_NE;
224 |
225 | return POLY_CMP_E;
226 | }
227 |
228 | poly_t *poly_zero(poly_t *p)
229 | {
230 | int i;
231 |
232 | for (i = 0; i < p->degree + 1; i++)
233 | bn_zero(p->coeffs[i]);
234 |
235 | return p;
236 | }
237 |
238 | int poly_is_zero(poly_t *p)
239 | {
240 | int i = 0;
241 |
242 | assert(p->degree >= 0);
243 |
244 | // Check if all the coeffs are 0.
245 | for (i = 0; i < p->degree + 1; i++)
246 | if (!bn_is_zero(p->coeffs[i]))
247 | return 0;
248 |
249 | return 1;
250 | }
251 |
252 | poly_t *poly_one(poly_t *p)
253 | {
254 | assert(p->degree >= 0 && p->coeffs[0] != NULL);
255 |
256 | poly_zero(p);
257 | bn_set_ui(p->coeffs[0], 1);
258 | bn_to_mon(p->coeffs[0], p->N);
259 |
260 | return p;
261 | }
262 |
263 | int poly_is_one(poly_t *p)
264 | {
265 | int i, is_one = 0;
266 |
267 | assert(p->degree >= 0 && p->coeffs[0] != NULL);
268 |
269 | //Check if the linear coeff is 1.
270 | bn_from_mon(p->coeffs[0], p->N);
271 | is_one = bn_cmp_ui(p->coeffs[0], 1) == BN_CMP_E;
272 | bn_to_mon(p->coeffs[0], p->N);
273 | if (!is_one)
274 | return 0;
275 |
276 | // Return 1 if we only have a linear term.
277 | if (p->degree == 0)
278 | return 1;
279 |
280 | // Check if the other coeffs are 0.
281 | for (i = 1; i < p->degree + 1; i++)
282 | if (!bn_is_zero(p->coeffs[i]))
283 | return 0;
284 |
285 | return 1;
286 | }
287 |
288 | int poly_deg(poly_t *p)
289 | {
290 | int i;
291 |
292 | for (i = p->degree; i >= 0 && bn_is_zero(p->coeffs[i]); i--);
293 |
294 | return i;
295 | }
296 |
297 | int poly_set_coeff(poly_t *p, int i, bn_t *coeff)
298 | {
299 | if (i > p->degree)
300 | return 0;
301 |
302 | // Convert coefficients for faster eval.
303 | p->coeffs[i] = bn_to_mon(coeff, p->N);
304 | return 1;
305 | }
306 |
307 | int poly_free_coeff(poly_t *p, int i)
308 | {
309 | if (i > p->degree)
310 | return 0;
311 |
312 | bn_free(p->coeffs[i]);
313 | p->coeffs[i] = NULL;
314 | return 1;
315 | }
316 |
317 | poly_t *poly_from_fmt(poly_t *p, const char *fmt, ...)
318 | {
319 | va_list ap;
320 | int i;
321 |
322 | va_start(ap, fmt);
323 |
324 | for (i = 0; fmt[i] && i <= p->degree; i++)
325 | {
326 | switch (fmt[i])
327 | {
328 | case 'i':
329 | bn_set_ui(p->coeffs[i], va_arg(ap, uint32_t));
330 | break;
331 | case 'I':
332 | bn_to_mon(bn_set_ui(p->coeffs[i], va_arg(ap, uint32_t)), p->N);
333 | break;
334 | case 'q':
335 | bn_set_ui(p->coeffs[i], va_arg(ap, uint64_t));
336 | break;
337 | case 'Q':
338 | bn_to_mon(bn_set_ui(p->coeffs[i], va_arg(ap, uint64_t)), p->N);
339 | break;
340 | case 's':
341 | bn_from_str(p->coeffs[i], va_arg(ap, char *));
342 | break;
343 | case 'S':
344 | bn_to_mon(bn_from_str(p->coeffs[i], va_arg(ap, char *)), p->N);
345 | break;
346 | case '0':
347 | bn_zero(p->coeffs[i]);
348 | break;
349 | }
350 | }
351 |
352 | va_end(ap);
353 |
354 | return p;
355 | }
356 |
357 | poly_t *poly_to_mon(poly_t *p)
358 | {
359 | int i;
360 |
361 | for (i = 0; i <= p->degree; i++)
362 | bn_to_mon(p->coeffs[i], p->N);
363 |
364 | return p;
365 | }
366 |
367 | poly_t *poly_from_mon(poly_t *p)
368 | {
369 | int i;
370 |
371 | for (i = 0; i <= p->degree; i++)
372 | bn_from_mon(p->coeffs[i], p->N);
373 |
374 | return p;
375 | }
376 |
377 | bn_t *poly_eval(poly_t *p, bn_t *dst, bn_t *x)
378 | {
379 | int i;
380 | bn_t *e = bn_alloc(4);
381 | bn_t *t = bn_alloc(p->N->n);
382 | bn_t *tx = bn_to_mon(bn_copy(bn_alloc(x->n), x), p->N);
383 |
384 | // TODO: Use Horner's method for faster eval.
385 | for (i = 0; i <= p->degree; i++)
386 | {
387 | bn_set_ui(e, i);
388 | // t = x^e
389 | bn_mon_pow(t, tx, p->N, e);
390 | // dst += t * a_i
391 | bn_add(dst, dst, bn_mon_mul(t, t, p->coeffs[i], p->N), p->N);
392 | }
393 |
394 | bn_free(e);
395 | bn_free(t);
396 | bn_free(tx);
397 |
398 | return dst;
399 | }
400 |
401 | poly_t *poly_add_fast(poly_t *d, poly_t *a, poly_t *b)
402 | {
403 | int i, md;
404 |
405 | assert(d != a && d != b);
406 |
407 | // Grow d if the degree is too small.
408 | md = MAX(a->degree, b->degree);
409 | if (d->degree < md)
410 | poly_adjust(d, md, 1);
411 |
412 | if (a->degree < b->degree)
413 | {
414 | for (i = 0; i < a->degree + 1; i++)
415 | bn_add(d->coeffs[i], a->coeffs[i], b->coeffs[i], d->N);
416 | for (; i < b->degree + 1; i++)
417 | bn_copy(d->coeffs[i], b->coeffs[i]);
418 | }
419 | else
420 | {
421 | for (i = 0; i < b->degree + 1; i++)
422 | bn_add(d->coeffs[i], b->coeffs[i], a->coeffs[i], d->N);
423 | for (; i < a->degree + 1; i++)
424 | bn_copy(d->coeffs[i], a->coeffs[i]);
425 | }
426 |
427 | return d;
428 | }
429 |
430 | poly_t *poly_add(poly_t *d, poly_t *a, poly_t *b)
431 | {
432 | _FAST_WRAPPER(add, d, a, b);
433 | }
434 |
435 | poly_t *poly_sub_fast(poly_t *d, poly_t *a, poly_t *b)
436 | {
437 | int i, md;
438 |
439 | assert(d != a && d != b);
440 |
441 | //Grow d if the degree is too small.
442 | md = MAX(a->degree, b->degree);
443 | if (d->degree < md)
444 | poly_adjust(d, md, 1);
445 |
446 | if (a->degree < b->degree)
447 | {
448 | for (i = 0; i < a->degree + 1; i++)
449 | bn_sub(d->coeffs[i], a->coeffs[i], b->coeffs[i], d->N);
450 | for (; i < b->degree + 1; i++)
451 | {
452 | bn_zero(d->coeffs[i]);
453 | bn_sub(d->coeffs[i], d->coeffs[i], b->coeffs[i], d->N);
454 | }
455 | }
456 | else
457 | {
458 | for (i = 0; i < b->degree + 1; i++)
459 | bn_sub(d->coeffs[i], a->coeffs[i], b->coeffs[i], d->N);
460 | for (; i < a->degree + 1; i++)
461 | bn_copy(d->coeffs[i], a->coeffs[i]);
462 | }
463 |
464 | return d;
465 | }
466 |
467 | poly_t *poly_sub(poly_t *d, poly_t *a, poly_t *b)
468 | {
469 | _FAST_WRAPPER(sub, d, a, b);
470 | }
471 |
472 | poly_t *poly_mul_fast(poly_t *d, poly_t *a, poly_t *b)
473 | {
474 | int i, j;
475 |
476 | assert(d != a && d != b);
477 |
478 | // TODO: could just always keep this in the poly_t struct for speed.
479 | bn_t *t = bn_alloc(d->N->n);
480 |
481 | // Adjust degree of d and zero out coefficients.
482 | poly_adjust(d, a->degree + b->degree, 1);
483 | poly_zero(d);
484 |
485 | for (i = 0; i < a->degree + 1; i++)
486 | for (j = 0; j < b->degree + 1; j++)
487 | {
488 | bn_mon_mul(t, a->coeffs[i], b->coeffs[j], d->N);
489 | bn_add(d->coeffs[i + j], d->coeffs[i + j], t, d->N);
490 | }
491 |
492 | bn_free(t);
493 |
494 | return d;
495 | }
496 |
497 | poly_t *poly_mul(poly_t *d, poly_t *a, poly_t *b)
498 | {
499 | _FAST_WRAPPER(mul, d, a, b);
500 | }
501 |
502 | poly_t *poly_mulc(poly_t *d, poly_t *a, bn_t *b)
503 | {
504 | int i;
505 |
506 | if (d->degree != a->degree)
507 | poly_adjust(d, a->degree, 1);
508 |
509 | for (i = 0; i < d->degree + 1; i++)
510 | bn_mon_mul(d->coeffs[i], a->coeffs[i], b, d->N);
511 |
512 | return d;
513 | }
514 |
515 | poly_t *poly_div(poly_t *q, poly_t *r, poly_t *a, poly_t *b)
516 | {
517 | int i, dega = poly_deg(a), degb = poly_deg(b);
518 |
519 | poly_t *t = poly_alloc(-1, q->N, 0);
520 | poly_t *tt = poly_alloc(-1, q->N, 0);
521 | poly_t *ta = poly_alloc(dega, q->N, 1);
522 | poly_t *tq = poly_alloc(-1, q->N, 0);
523 |
524 | bn_t *bc = bn_alloc(q->N->n);
525 | bn_t *c = bn_alloc(q->N->n);
526 | bn_t *ctb = bn_alloc(q->N->n);
527 |
528 | // Truncate a.
529 | poly_copy(ta, a, 0);
530 |
531 | // Calculate inverse of lead coefficient.
532 | bn_mon_inv(bc, b->coeffs[degb], q->N);
533 |
534 | while (ta->degree + 1 >= degb + 1)
535 | {
536 | poly_adjust(t, degb, 1);
537 | for (i = 0; i < degb + 1; i++)
538 | bn_copy(t->coeffs[i], ta->coeffs[ta->degree - degb + i]);
539 |
540 | bn_mon_mul(c, t->coeffs[t->degree], bc, q->N);
541 | poly_adjust(tq, tq->degree + 1, 1);
542 | for (i = tq->degree; i > 0; i--)
543 | bn_copy(tq->coeffs[i], tq->coeffs[i - 1]);
544 | bn_copy(tq->coeffs[0], c);
545 |
546 | for (i = 0; i < degb + 1; i++)
547 | {
548 | bn_mon_mul(ctb, c, b->coeffs[i], q->N);
549 | bn_sub(t->coeffs[i], t->coeffs[i], ctb, q->N);
550 | }
551 |
552 | poly_adjust(tt, ta->degree - degb - 1, 1);
553 | poly_copy(tt, ta, 0); //Truncate ta.
554 | poly_adjust(t, t->degree - 1, 1);
555 | poly_concat(ta, tt, t);
556 | }
557 |
558 | poly_copy(q, tq, 1);
559 | poly_copy(r, ta, 1);
560 |
561 | poly_free(tq, 1);
562 | poly_free(ta, 1);
563 | poly_free(tt, 1);
564 | poly_free(t, 1);
565 |
566 | bn_free(ctb);
567 | bn_free(c);
568 | bn_free(bc);
569 |
570 | return q;
571 | }
572 |
573 | poly_t *poly_rem(poly_t *r, poly_t *a, poly_t *b)
574 | {
575 | int i, dega = poly_deg(a), degb = poly_deg(b);
576 |
577 | poly_t *t = poly_alloc(-1, r->N, 0);
578 | poly_t *tt = poly_alloc(-1, r->N, 0);
579 | poly_t *ta = poly_alloc(dega, r->N, 1);
580 |
581 | bn_t *bc = bn_alloc(r->N->n);
582 | bn_t *c = bn_alloc(r->N->n);
583 | bn_t *ctb = bn_alloc(r->N->n);
584 |
585 | // Truncate a.
586 | poly_copy(ta, a, 0);
587 |
588 | // Calculate inverse of lead coefficient.
589 | bn_mon_inv(bc, b->coeffs[degb], r->N);
590 |
591 | while (ta->degree + 1 >= degb + 1)
592 | {
593 | poly_adjust(t, degb, 1);
594 | for (i = 0; i < degb + 1; i++)
595 | bn_copy(t->coeffs[i], ta->coeffs[ta->degree - degb + i]);
596 |
597 | bn_mon_mul(c, t->coeffs[t->degree], bc, r->N);
598 |
599 | for (i = 0; i < degb + 1; i++)
600 | {
601 | bn_mon_mul(ctb, c, b->coeffs[i], r->N);
602 | bn_sub(t->coeffs[i], t->coeffs[i], ctb, r->N);
603 | }
604 |
605 | poly_adjust(tt, ta->degree - degb - 1, 1);
606 | poly_copy(tt, ta, 0); //Truncate ta.
607 | poly_adjust(t, t->degree - 1, 1);
608 | poly_concat(ta, tt, t);
609 | }
610 |
611 | poly_copy(r, ta, 1);
612 |
613 | poly_free(ta, 1);
614 | poly_free(tt, 1);
615 | poly_free(t, 1);
616 |
617 | bn_free(ctb);
618 | bn_free(c);
619 | bn_free(bc);
620 |
621 | return r;
622 | }
623 |
--------------------------------------------------------------------------------
/poly.h:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2016 naehrwert
3 | * Licensed under the terms of the GNU GPL, version 2
4 | * http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
5 | */
6 |
7 | #ifndef _POLY_H_
8 | #define _POLY_H_
9 |
10 | #include
11 |
12 | #include "bn.h"
13 |
14 | #define POLY_CMP_E 1
15 | #define POLY_CMP_NE 0
16 |
17 | /*! Polynomial. */
18 | /*
19 | * Define a polynomial P of degree n as
20 | * P(X) = a_0 + a_1*X + a_2*X^2 + ... + a_n*X^n
21 | * with n + 1 coefficients a_0, a_1, ..., a_n.
22 | */
23 | typedef struct _poly
24 | {
25 | /*! The polynomial's degree. */
26 | int degree;
27 | /*! Coefficients (mon). */
28 | bn_t **coeffs;
29 | /*! Modulus. */
30 | bn_t *N;
31 | } poly_t;
32 |
33 | /*!
34 | * \brief Read polynomial from file stream.
35 | */
36 | poly_t *poly_read(FILE *fp, poly_t *dst);
37 |
38 | /*!
39 | * \brief Write polynomial to file stream.
40 | */
41 | poly_t *poly_write(FILE *fp, poly_t *p);
42 |
43 | /*!
44 | * \brief Print polynomial to file stream.
45 | */
46 | void poly_print(FILE *fp, const s8 *pre, poly_t *p, const s8 *post);
47 |
48 | /*!
49 | * \brief Allocate polynomial (with zero coefficients).
50 | */
51 | poly_t *poly_alloc(int degree, bn_t *N, int alloc_coeffs);
52 |
53 | /*!
54 | * \brief Free polynomial.
55 | */
56 | void poly_free(poly_t *p, int free_coeffs);
57 |
58 | /*!
59 | * \brief Adjust polynomial degree.
60 | * This will alloc/free coefficients of alloc_free_coeffs is true.
61 | */
62 | poly_t *poly_adjust(poly_t *p, int degree, int alloc_free_coeffs);
63 |
64 | /*!
65 | * \brief Copy polynomial.
66 | * This will zero out coefficients if the source degree is smaller and adjust is false.
67 | * This will truncate coefficients if the destination degree is smaller and adjust is false.
68 | * If adjust is true, then it will set the destination degree to that of the source and copy every coefficient.
69 | */
70 | poly_t *poly_copy(poly_t *d, poly_t *s, int adjust);
71 |
72 | /*!
73 | * \brief Concatenate two polynomials (as lists of coefficients).
74 | */
75 | poly_t *poly_concat(poly_t *d, poly_t *a, poly_t *b);
76 |
77 | /*!
78 | * \brief Compare two polynomials.
79 | */
80 | int poly_cmp(poly_t *p, poly_t *q);
81 |
82 | /*!
83 | * \brief Zero out coefficients.
84 | */
85 | poly_t *poly_zero(poly_t *p);
86 |
87 | /*!
88 | * \brief Checks whether the polynomial is zero.
89 | */
90 | int poly_is_zero(poly_t *p);
91 |
92 | /*!
93 | * \brief Set linear coefficient to one.
94 | */
95 | poly_t *poly_one(poly_t *p);
96 |
97 | /*!
98 | * \brief Checks whether the polynomial is linear one.
99 | */
100 | int poly_is_one(poly_t *p);
101 |
102 | /*!
103 | * \brief Get mathematical degree of polynomial (highest non-zero power).
104 | */
105 | int poly_deg(poly_t *p);
106 |
107 | /*!
108 | * \brief Set coefficient.
109 | */
110 | int poly_set_coeff(poly_t *p, int i, bn_t *coeff);
111 |
112 | /*!
113 | * \brief Free coefficient.
114 | */
115 | int poly_free_coeff(poly_t *p, int i);
116 |
117 | /*!
118 | * \brief Fill coefficients from format.
119 | */
120 | poly_t *poly_from_fmt(poly_t *p, const char *fmt, ...);
121 |
122 | /*!
123 | * \brief Convert coefficients to montgomery form.
124 | */
125 | poly_t *poly_to_mon(poly_t *p);
126 |
127 | /*!
128 | * \brief Convert coefficients from montgomery form.
129 | */
130 | poly_t *poly_from_mon(poly_t *p);
131 |
132 | /*!
133 | * \brief Evaluate polynomial at given x.
134 | */
135 | bn_t *poly_eval(poly_t *p, bn_t *dst, bn_t *x);
136 |
137 | /*!
138 | * \brief Add two polynomials.
139 | * Note that d must not be the same as a or b.
140 | */
141 | poly_t *poly_add_fast(poly_t *d, poly_t *a, poly_t *b);
142 |
143 | /*!
144 | * \brief Add two polynomials.
145 | */
146 | poly_t *poly_add(poly_t *d, poly_t *a, poly_t *b);
147 |
148 | /*!
149 | * \brief Subtract two polynomials.
150 | * Note that d must not be the same as a or b.
151 | */
152 | poly_t *poly_sub_fast(poly_t *d, poly_t *a, poly_t *b);
153 |
154 | /*!
155 | * \brief Subtract two polynomials.
156 | */
157 | poly_t *poly_sub(poly_t *d, poly_t *a, poly_t *b);
158 |
159 | /*!
160 | * \brief Multiply two polynomials.
161 | * Note that d must not be the same as a or b.
162 | */
163 | poly_t *poly_mul_fast(poly_t *d, poly_t *a, poly_t *b);
164 |
165 | /*!
166 | * \brief Multiply two polynomials.
167 | */
168 | poly_t *poly_mul(poly_t *d, poly_t *a, poly_t *b);
169 |
170 | /*!
171 | * \brief Multiply each polynomial coefficient with a constant.
172 | */
173 | poly_t *poly_mulc(poly_t *d, poly_t *a, bn_t *b);
174 |
175 | /*!
176 | * \brief Divide two polynomials yielding quotient and remainder.
177 | */
178 | poly_t *poly_div(poly_t *q, poly_t *r, poly_t *a, poly_t *b);
179 |
180 | /*!
181 | * \brief Compute remainder of two polynomials.
182 | */
183 | poly_t *poly_rem(poly_t *r, poly_t *a, poly_t *b);
184 |
185 | #endif
186 |
--------------------------------------------------------------------------------
/pqr.c:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2016 naehrwert
3 | * Licensed under the terms of the GNU GPL, version 2
4 | * http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
5 | */
6 |
7 | #include
8 | #include
9 | #include "pqr.h"
10 |
11 | poly_t *pqr_add(poly_t *d, poly_t *a, poly_t *b, poly_t *N)
12 | {
13 | int i;
14 |
15 | assert(d->degree == a->degree && d->degree == b->degree);
16 |
17 | for (i = 0; i < d->degree + 1; i++)
18 | bn_add(d->coeffs[i], a->coeffs[i], b->coeffs[i], N->N);
19 |
20 | return d;
21 | }
22 |
23 | poly_t *pqr_sub(poly_t *d, poly_t *a, poly_t *b, poly_t *N)
24 | {
25 | int i;
26 |
27 | assert(d->degree == a->degree && d->degree == b->degree);
28 |
29 | for (i = 0; i < d->degree + 1; i++)
30 | bn_sub(d->coeffs[i], a->coeffs[i], b->coeffs[i], N->N);
31 |
32 | return d;
33 | }
34 |
35 | poly_t *pqr_mul_fast(poly_t *d, poly_t *a, poly_t *b, poly_t *N)
36 | {
37 | poly_mul_fast(d, a, b);
38 | poly_rem(d, d, N);
39 | return poly_adjust(d, a->degree, 1);
40 | }
41 |
42 | poly_t *pqr_mul(poly_t *d, poly_t *a, poly_t *b, poly_t *N)
43 | {
44 | assert(d->degree == a->degree && d->degree == b->degree);
45 |
46 | if (d == a || d == b)
47 | {
48 | poly_mul(d, a, b);
49 | poly_rem(d, d, N);
50 | return poly_adjust(d, a->degree, 1);
51 | }
52 |
53 | return pqr_mul_fast(d, a, b, N);
54 | }
55 |
56 | poly_t *pqr_inv(poly_t *d, poly_t *p, poly_t *N)
57 | {
58 | assert(d->degree == p->degree);
59 |
60 | poly_t *a = poly_alloc(p->degree, d->N, 1);
61 | poly_copy(a, p, 0);
62 | poly_t *b = poly_alloc(N->degree, d->N, 1);
63 | poly_copy(b, N, 0);
64 |
65 | poly_t *ea = poly_alloc(d->degree, d->N, 1);
66 | poly_t *eb = poly_alloc(d->degree, d->N, 1);
67 |
68 | poly_t *t1 = poly_alloc(d->degree, d->N, 1);
69 | poly_t *t2 = poly_alloc(d->degree, d->N, 1);
70 |
71 | poly_one(ea); // ea = 1
72 | poly_zero(eb); // eb = 0
73 |
74 | while (1)
75 | {
76 | poly_div(t2, a, a, b); // q, a = quo_rem(a, b)
77 | poly_mul_fast(t1, t2, eb); // t1 = q*eb
78 | poly_copy(t2, ea, 1);
79 | poly_sub_fast(ea, t2, t1); // ea = ea - t1
80 |
81 | if (a->degree == 0)
82 | break;
83 |
84 | // Swap a and b.
85 | poly_t *x = b;
86 | b = a;
87 | a = x;
88 |
89 | // Swap ea and eb.
90 | x = eb;
91 | eb = ea;
92 | ea = x;
93 | }
94 |
95 | poly_copy(d, ea, 0);
96 |
97 | // Make it monic.
98 | if (!poly_is_one(a))
99 | {
100 | bn_mon_inv(a->coeffs[0], a->coeffs[0], a->N);
101 | poly_mulc(d, d, a->coeffs[0]);
102 | }
103 |
104 | poly_free(t2, 1);
105 | poly_free(t1, 1);
106 | poly_free(eb, 1);
107 | poly_free(ea, 1);
108 | poly_free(b, 1);
109 | poly_free(a, 1);
110 |
111 | return d;
112 | }
113 |
114 | poly_t *pqr_exp_fast(poly_t *d, poly_t *p, bn_t *e, poly_t *N)
115 | {
116 | int i;
117 |
118 | assert(d->degree == p->degree);
119 | assert(d != p);
120 |
121 | poly_one(d);
122 |
123 | poly_t *r = poly_alloc(p->degree, d->N, 1);
124 |
125 | for (i = bn_maxbit(e); i >= 0; i--)
126 | {
127 | pqr_mul_fast(r, d, d, N);
128 | if (bn_getbit(e, i))
129 | pqr_mul_fast(d, r, p, N);
130 | else
131 | poly_copy(d, r, 0);
132 | }
133 |
134 | poly_free(r, 1);
135 |
136 | return d;
137 | }
138 |
139 | poly_t *pqr_exp(poly_t *d, poly_t *p, bn_t *e, poly_t *N)
140 | {
141 | if (d == p)
142 | {
143 | poly_t *t = poly_alloc(p->degree, p->N, 1);
144 | poly_copy(t, p, 0);
145 | pqr_exp_fast(d, t, e, N);
146 | poly_free(t, 1);
147 | return d;
148 | }
149 |
150 | return pqr_exp_fast(d, p, e, N);
151 | }
152 |
--------------------------------------------------------------------------------
/pqr.h:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2016 naehrwert
3 | * Licensed under the terms of the GNU GPL, version 2
4 | * http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
5 | */
6 |
7 | #ifndef _PQR_H_
8 | #define _PQR_H_
9 |
10 | #include "poly.h"
11 |
12 | /*!
13 | * \brief Add two polynomials modulo N.
14 | */
15 | poly_t *pqr_add(poly_t *d, poly_t *a, poly_t *b, poly_t *N);
16 |
17 | /*!
18 | * \brief Subtract two polynomials modulo N.
19 | */
20 | poly_t *pqr_sub(poly_t *d, poly_t *a, poly_t *b, poly_t *N);
21 |
22 | /*!
23 | * \brief Multiply two polynomials modulo N.
24 | * Note that d must not be the same as a or b.
25 | */
26 | poly_t *pqr_mul_fast(poly_t *d, poly_t *a, poly_t *b, poly_t *N);
27 |
28 | /*!
29 | * \brief Multiply two polynomials modulo N.
30 | */
31 | poly_t *pqr_mul(poly_t *d, poly_t *a, poly_t *b, poly_t *N);
32 |
33 | /*!
34 | * \brief Invert two polynomials modulo N.
35 | */
36 | poly_t *pqr_inv(poly_t *d, poly_t *p, poly_t *N);
37 |
38 | /*!
39 | * \brief Exponentiate two polynomials modulo N.
40 | * Note that d must not be the same as p.
41 | */
42 | poly_t *pqr_exp_fast(poly_t *d, poly_t *p, bn_t *e, poly_t *N);
43 |
44 | /*!
45 | * \brief Exponentiate two polynomials modulo N.
46 | */
47 | poly_t *pqr_exp(poly_t *d, poly_t *p, bn_t *e, poly_t *N);
48 |
49 | #endif
50 |
--------------------------------------------------------------------------------
/ssecrets.c:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2016 naehrwert
3 | * Licensed under the terms of the GNU GPL, version 2
4 | * http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
5 | */
6 |
7 | #include "bn.h"
8 | #include "poly.h"
9 |
10 | static poly_t *_ssecrets_random_poly(u32 k, bn_t *N)
11 | {
12 | u32 i;
13 | poly_t *res = poly_alloc(k - 1, N, 0);
14 |
15 | for (i = 1; i <= k - 1; i++)
16 | {
17 | bn_t *c = bn_reduce(bn_rand(bn_alloc(N->n)), N);
18 | poly_set_coeff(res, i, c);
19 | }
20 |
21 | return res;
22 | }
23 |
24 | poly_t *ssecrets_create_poly(bn_t *s, u32 k, bn_t *N)
25 | {
26 | poly_t *res;
27 |
28 | // Create random polynomial with k-1 coefficients.
29 | res = _ssecrets_random_poly(k, N);
30 | // Set shared secret as coefficient 0.
31 | if (s != NULL)
32 | poly_set_coeff(res, 0, bn_copy(bn_alloc(N->n), s));
33 | else
34 | poly_set_coeff(res, 0, bn_alloc(N->n));
35 |
36 | return res;
37 | }
38 |
39 | bn_t *ssecrets_create_share(poly_t *p, bn_t *x)
40 | {
41 | // Evaluate polynomial at x.
42 | return poly_eval(p, bn_alloc(p->N->n), x);
43 | }
44 |
45 | bn_t *ssecrets_calc_secret(bn_t **x, bn_t **s, u32 cnt, bn_t *N)
46 | {
47 | u32 i, j;
48 | BOOL first;
49 |
50 | bn_t *res = bn_alloc(N->n), *t = bn_alloc(N->n), *a = bn_alloc(N->n), *b = bn_alloc(N->n);
51 |
52 | // Compute secret by using Lagrange polynomial interpolation algorithm for x = 0.
53 | // s = \sum s_i \prod_{j \ne i} (-x_j)(x_i - x_j)^{-1} \mod N
54 | for (i = 0; i < cnt; i++)
55 | {
56 | bn_zero(t);
57 | first = TRUE;
58 | for (j = 0; j < cnt; j++)
59 | {
60 | if (j == i)
61 | continue;
62 |
63 | // b = (x_i - x_j)^(-1)
64 | bn_mon_inv(b, bn_to_mon(bn_sub(b, x[i], x[j], N), N), N);
65 | // a = -x_j*b
66 | bn_mon_mul(a, bn_to_mon(bn_sub(a, bn_zero(a), x[j], N), N), b, N);
67 | // t *= a
68 | if (first == TRUE)
69 | {
70 | bn_to_mon(bn_copy(t, a), N);
71 | first = FALSE;
72 | }
73 | else
74 | bn_mon_mul(t, t, a, N);
75 | }
76 | // res += s_i * t
77 | bn_add(res, res, bn_from_mon(bn_mon_mul(t, s[i], t, N), N), N);
78 | }
79 |
80 | bn_free(t);
81 | bn_free(a);
82 | bn_free(b);
83 |
84 | return res;
85 | }
86 |
--------------------------------------------------------------------------------
/ssecrets.h:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2016 naehrwert
3 | * Licensed under the terms of the GNU GPL, version 2
4 | * http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
5 | */
6 |
7 | #ifndef _SSECRETS_H_
8 | #define _SSECRETS_H_
9 |
10 | #include "bn.h"
11 | #include "poly.h"
12 |
13 | /*!
14 | * \brief Create Shamir's secret sharing polynomial.
15 | */
16 | poly_t *ssecrets_create_poly(bn_t *s, u32 k, bn_t *N);
17 |
18 | /*!
19 | * \brief Create share.
20 | */
21 | bn_t *ssecrets_create_share(poly_t *p, bn_t *x);
22 |
23 | /*!
24 | * \brief Calculate secret from shares.
25 | */
26 | bn_t *ssecrets_calc_secret(bn_t **x, bn_t **s, u32 cnt, bn_t *N);
27 |
28 | #endif
29 |
--------------------------------------------------------------------------------
/tests/test_prq.c:
--------------------------------------------------------------------------------
1 | #include
2 |
3 | #include "bn.h"
4 | #include "poly.h"
5 | #include "pqr.h"
6 |
7 | int main(int argc, char **argv)
8 | {
9 | bn_t *N = bn_from_str(bn_alloc(9), "01000000000000000D");
10 |
11 | poly_t *I = poly_from_fmt(poly_alloc(3, N, 1), "IIII", 1, 1, 0, 1); //1 + x + x^3
12 | poly_print(stdout, "I = ", I, "\n");
13 |
14 | poly_t *q = poly_from_fmt(poly_alloc(2, N, 1), "III", 1, 2, 1); //1 + 2x + x^2
15 | poly_print(stdout, "q = ", q, "\n");
16 |
17 | poly_t *qi = poly_alloc(2, N, 1);
18 | pqr_inv_fast(qi, q, I);
19 | poly_print(stdout, "qi = ", qi, "\n");
20 |
21 | poly_t *p = poly_alloc(2, N, 1);
22 | pqr_mul_fast(p, q, qi, I);
23 | poly_print(stdout, "q*qi = ", p, "\n");
24 |
25 | return 0;
26 | }
27 |
--------------------------------------------------------------------------------
/tests/test_rsa.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include "bn.h"
3 |
4 | int main()
5 | {
6 | bn_t *N = bn_from_bin(bn_alloc(32), "\xa0\xe1\x53\x75\xe4\xe6\x94\xbb\x41\x8f\xdd\x18\xab\x4f\xae\x55\x42\xe9\x78\xd1\xdf\xef\x04\xbb\x90\x07\x2a\xa6\xc9\xc1\xf9\xc1", 32);
7 | bn_t *e = bn_from_bin(bn_alloc(32), "\x01\x00\x01", 3);
8 | bn_t *d = bn_from_bin(bn_alloc(32), "\x96\xb8\xe3\x6f\x45\x47\x3d\x3a\x7e\x3e\xe0\xfd\xd6\xa9\x6d\x02\x19\x97\xb2\xd0\x22\x9b\x69\xff\xc0\x52\x47\x60\x20\xb3\x89\x9d", 32);
9 |
10 | bn_t *r = bn_from_bin(bn_alloc(32), "\x01\x00\x01", 3);
11 | bn_t *rez = bn_alloc(32);
12 |
13 | bn_t *m1 = bn_from_bin(bn_alloc(32), "Hello World", 12);
14 | bn_t *m2 = bn_alloc(32);
15 |
16 | bn_t *c = bn_alloc(32);
17 |
18 | // RSA Encryption
19 | // c = m1 ^ e % N
20 | bn_pow_mod(c, m1, e, N);
21 | bn_print(stdout, "", d, "\n");
22 |
23 | // RSA Decryption
24 | // m2 = c ^ d % N
25 | bn_pow_mod(m2, c, d, N);
26 | bn_print(stdout, "", m2, "\n");
27 |
28 | s8 plain[32];
29 | bn_to_bin(plain, m2);
30 |
31 | printf("%s\n", &plain[20]);
32 |
33 | bn_free(N);
34 | bn_free(e);
35 | bn_free(d);
36 | bn_free(m1);
37 | bn_free(m2);
38 | bn_free(c);
39 |
40 | return 0;
41 | }
42 |
--------------------------------------------------------------------------------
/tests/test_rsa_tiny.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include "bn.h"
3 |
4 | int main()
5 | {
6 | bn_t *N = bn_from_bin(bn_alloc(32), "\xa0\xe1\x53\x75\xe4\xe6\x94\xbb\x41\x8f\xdd\x18\xab\x4f\xae\x55\x42\xe9\x78\xd1\xdf\xef\x04\xbb\x90\x07\x2a\xa6\xc9\xc1\xf9\xc1", 32);
7 | bn_t *e = bn_from_bin(bn_alloc(32), "\x01\x00\x01", 3);
8 | bn_t *d = bn_from_bin(bn_alloc(32), "\x96\xb8\xe3\x6f\x45\x47\x3d\x3a\x7e\x3e\xe0\xfd\xd6\xa9\x6d\x02\x19\x97\xb2\xd0\x22\x9b\x69\xff\xc0\x52\x47\x60\x20\xb3\x89\x9d", 32);
9 |
10 | bn_t *m1 = bn_from_bin(bn_alloc(32), "Hello World", 12);
11 | bn_t *m2 = bn_alloc(32);
12 |
13 | bn_t *c = bn_alloc(32);
14 |
15 | // RSA Encryption
16 | // c = m1 ^ e % N
17 | bn_pow_mod(c, m1, e, N);
18 |
19 | // RSA Decryption
20 | // m2 = c ^ d % N
21 | bn_pow_mod(m2, c, d, N);
22 |
23 | s8 plain[32];
24 | bn_to_bin(plain, m2);
25 |
26 | printf("%s\n", &plain[20]);
27 |
28 | bn_free(N);
29 | bn_free(e);
30 | bn_free(d);
31 | bn_free(m1);
32 | bn_free(m2);
33 | bn_free(c);
34 |
35 | return 0;
36 | }
37 |
38 |
--------------------------------------------------------------------------------