├── .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 | --------------------------------------------------------------------------------