diff options
Diffstat (limited to 'src/blog')
| -rw-r--r-- | src/blog/2025-02-27-elliptic-curves-javascript/ecm.md | 283 |
1 files changed, 283 insertions, 0 deletions
diff --git a/src/blog/2025-02-27-elliptic-curves-javascript/ecm.md b/src/blog/2025-02-27-elliptic-curves-javascript/ecm.md new file mode 100644 index 0000000..56b876c --- /dev/null +++ b/src/blog/2025-02-27-elliptic-curves-javascript/ecm.md | |||
| @@ -0,0 +1,283 @@ | |||
| 1 | # Elliptic curves and JavaScript | ||
| 2 | |||
| 3 | At my company we regularly have talks and other knowledge events. | ||
| 4 | After attending many of these events, I decided to give a talk | ||
| 5 | about [elliptic curves](https://en.wikipedia.org/wiki/Elliptic_curve), | ||
| 6 | which I worked with during my PhD. | ||
| 7 | |||
| 8 | The intended audience consists of software developers, but their | ||
| 9 | background is mixed: some have studied Maths in university, but many did | ||
| 10 | not. Most are not familiar with abstract algebra other than polynomials | ||
| 11 | and matrices, let alone algebraic geometry. Considering all of this, | ||
| 12 | I decided to give a presentation about | ||
| 13 | [Lenstra elliptic curve factorization](https://en.wikipedia.org/wiki/Lenstra_elliptic-curve_factorization), | ||
| 14 | so I could also show some code and do a practical demo. | ||
| 15 | |||
| 16 | Since I gave a presentation on this topic to a different audience a | ||
| 17 | couple of years ago, I could have simply adapted the slides and used the | ||
| 18 | same code. Instead, I took this as an opportunity to experiment with | ||
| 19 | new tools and languages. This post is a summary of what I have learned | ||
| 20 | while preparing this talk. | ||
| 21 | |||
| 22 | All the code I talk about in this post, including the source for the | ||
| 23 | slides, can be found in [this git repository](https://git.tronto.net/ecm). | ||
| 24 | |||
| 25 | ## The code | ||
| 26 | |||
| 27 | For the practical part of the talk I had to write some code to demonstrate | ||
| 28 | the factorization algorithm. It's not much, maybe 200 lines or so, and | ||
| 29 | I already had a working Python version. It was a rather straightforward | ||
| 30 | implementation, and it used exceptions to handle the "a factor was found" | ||
| 31 | part of the algorithm; although this is not amazing coding style, it | ||
| 32 | was faithful to how the algorithm was originally explained - or to how | ||
| 33 | I wanted to explain it, anyway. | ||
| 34 | |||
| 35 | It was not bad code, but I wanted to experiment with something new. | ||
| 36 | |||
| 37 | ### Adventures in C++ | ||
| 38 | |||
| 39 | Recently I have been learning C++, and I wanted to experiment with some | ||
| 40 | of its more advanced features. So I decided to rewrite the whole thing. | ||
| 41 | |||
| 42 | I had a clear idea of where I wanted to start: a small | ||
| 43 | [library for modular arithmetic](https://git.tronto.net/zmodn/file/README.md.html), | ||
| 44 | with compile-time fixed | ||
| 45 | [modulus](https://en.wikipedia.org/wiki/Modular_arithmetic) via templates | ||
| 46 | and heavy use of | ||
| 47 | [type inference](https://en.wikipedia.org/wiki/Type_inference) | ||
| 48 | for seamless operations between regular integers and integers modulo N. | ||
| 49 | This endeavor was quite successful, and it taught me how to use | ||
| 50 | templates and concepts, which I have talked about in | ||
| 51 | [my previous blog post](../2025-01-21-taming-cpp-templates). | ||
| 52 | |||
| 53 | When working on the previous part, I made sure that any kind of integer | ||
| 54 | could be used as a base type for the modular integers, so I could use | ||
| 55 | some custom big integer types to show off the power of the factorization | ||
| 56 | algorithm with very large numbers. Unfortunately, I did not take into | ||
| 57 | account that with my setup I needed a big integer class that supported | ||
| 58 | *compile-time constants* - for example in the form of `constexpr` | ||
| 59 | constructors. I could not find any, so I decided to write | ||
| 60 | [my own big integer class](https://git.tronto.net/zmodn/file/bigint.h.html). | ||
| 61 | This was less successful: implementing an *efficient* big integer library | ||
| 62 | was not as straightforward as the modular integers library. I decided | ||
| 63 | not to care about efficiency for the time being, but that would come | ||
| 64 | back to bite me very soon. | ||
| 65 | |||
| 66 | Finally, I put these two libraries together and implemented the elliptic | ||
| 67 | curve factorization algorithm. This was not hard. The only problem was | ||
| 68 | that it was excruciatingly slow when I used large numbers, undoubtedly | ||
| 69 | due to my half-assed big integer implementation. I could restrict | ||
| 70 | myself to using regular 64-bit integers, but then I would have to use | ||
| 71 | to relatively small numbers, making the demo less interesting. I looked | ||
| 72 | online for other big integer libraries that I could use and I found | ||
| 73 | [ctbignum](https://github.com/niekbouman/ctbignum), but I could not make | ||
| 74 | it work together with my modular arithmetic class. The day of the | ||
| 75 | presentation was approaching quickly, so I decided to go back to | ||
| 76 | my original Python implementation instead. | ||
| 77 | |||
| 78 | ### Back to Python | ||
| 79 | |||
| 80 | When I looked back at my old Python implementation, I found it nicer | ||
| 81 | and cleaner than how I remembered it. I did not have to do much | ||
| 82 | cleanup, it was pretty much ready to go, and much more readable than | ||
| 83 | the C++ verion for anyone who is not a C++ expert - and probably for C++ | ||
| 84 | experts too. Moreover, Python's seamless use of large integers was | ||
| 85 | exactly what I was missing from the C++ version. | ||
| 86 | |||
| 87 | One of the few changes I made to this code was reworking a little bit | ||
| 88 | the "elliptic curve point" class I used. If anything, this was a good | ||
| 89 | excuse to learn about | ||
| 90 | [dataclasses](https://docs.python.org/3/library/dataclasses.html). I also | ||
| 91 | decided to add | ||
| 92 | [type hints](https://docs.python.org/3/library/typing.html), which I | ||
| 93 | have recently found out about. | ||
| 94 | |||
| 95 | And with little work, the old code was ready to go! | ||
| 96 | |||
| 97 | ## The slides | ||
| 98 | |||
| 99 | Compared to the code, the slides needed a few more adjustments. | ||
| 100 | When I gave this talk the first time, it was for an audience of | ||
| 101 | Math students at the end of their Bachelor program. I could freely | ||
| 102 | use all that Math jargon that we Mathematicians like, such as | ||
| 103 | "let K be a | ||
| 104 | [field](https://en.wikipedia.org/wiki/Field_(mathematics))" | ||
| 105 | and "E is a | ||
| 106 | [projective](https://en.wikipedia.org/wiki/Projective_space) curve". | ||
| 107 | But this time I had to phrase things differently. The content itself | ||
| 108 | didn't need much change, but I had to use a more approachable language, | ||
| 109 | at the cost of being a little less rigorous. For example, I could | ||
| 110 | get rid of all the projective plane business by just saying "let's | ||
| 111 | pretend that there is a point *at infinity*; trust me, the Math | ||
| 112 | works out". | ||
| 113 | |||
| 114 | The problem with changing the old slides is that I did not want to touch | ||
| 115 | [LaTeX](https://nl.wikipedia.org/wiki/LaTeX) | ||
| 116 | anymore. As a Mathematician I like it because it can do pretty much everything | ||
| 117 | you need (did you know you can | ||
| 118 | [draw diagrams programmatically](https://www.youtube.com/watch?v=mWqhB6qOIk0)?), | ||
| 119 | but as a computer scientist I'd rather not deal with the mess that is a | ||
| 120 | LaTeX installation. | ||
| 121 | So what did I decide to use instead? HTML, CSS and a bit of JavaScript! | ||
| 122 | |||
| 123 | ### Math formulas with MathJax | ||
| 124 | |||
| 125 | Even without LaTeX, I still needed a way to write Math formulas in my | ||
| 126 | slides. One way to achieve this is using [MathJax](https://www.mathjax.org), | ||
| 127 | which allows you to write LaTeX or | ||
| 128 | [MathML](https://en.wikipedia.org/wiki/MathML) formulas direclty in | ||
| 129 | your HTML, and have them rendered dynamically. A minimal example | ||
| 130 | looks like this: | ||
| 131 | |||
| 132 | ``` | ||
| 133 | <!doctype html> | ||
| 134 | <head> | ||
| 135 | <script id="MathJax-script" async src="https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-mml-chtml.js"> | ||
| 136 | </script> | ||
| 137 | </head> | ||
| 138 | |||
| 139 | <body> | ||
| 140 | <p>Hello! \[ e^{\pi i} + 1 = 0 \]</p> | ||
| 141 | </body> | ||
| 142 | ``` | ||
| 143 | |||
| 144 | In the example above I am including the MathJax library directly from a | ||
| 145 | URL. This means every time you load that page, a request is sent from | ||
| 146 | your browser to the MathJax server to get the code for rendering the | ||
| 147 | formulas. Among other things, this implies that my slides are going | ||
| 148 | to be dependent on this external website, and that they won't work | ||
| 149 | offline. The horror! | ||
| 150 | |||
| 151 | In theory I could install MathJax locally (or on my server) and get rid | ||
| 152 | of this dependency, and maybe at some point I'll do it. But for now | ||
| 153 | it is just easier and faster to include the script like this. And while | ||
| 154 | I was at it, I doubled down on the remote library thing and included | ||
| 155 | also [highlight.js](https://highlightjs.org), | ||
| 156 | a package for rendering code blocks with syntax highlighting. | ||
| 157 | |||
| 158 | ### Scrolling with JavaScript | ||
| 159 | |||
| 160 | The other big feature I wanted for the slides was for them to look and | ||
| 161 | behave like actual slides. So the whole HTML page should be divided into | ||
| 162 | single frames, and I wanted to be able to move back and forth between | ||
| 163 | frames by clicking or pressing a key. | ||
| 164 | |||
| 165 | In order to do this, I had to write my first piece of JavaScript. | ||
| 166 | The main part looks more or less like this: | ||
| 167 | |||
| 168 | ``` | ||
| 169 | const slides = document.querySelectorAll(".slide"); | ||
| 170 | |||
| 171 | const keysNext = ["ArrowRight", "ArrowDown", " "]; | ||
| 172 | const keysPrev = ["ArrowLeft", "ArrowUp"]; | ||
| 173 | |||
| 174 | // Disable default action of the navigation keys (e.g. scrolling). | ||
| 175 | document.addEventListener("keydown", function(e) { | ||
| 176 | if (keysNext.includes(e.key) || keysPrev.includes(e.key)) { | ||
| 177 | e.preventDefault(); | ||
| 178 | } | ||
| 179 | }); | ||
| 180 | |||
| 181 | function goto(slide) { | ||
| 182 | slide.focus(); | ||
| 183 | slide.scrollIntoView({ | ||
| 184 | behavior: "instant", | ||
| 185 | block: "start" | ||
| 186 | }); | ||
| 187 | } | ||
| 188 | |||
| 189 | function onkeydown(i, e) { | ||
| 190 | if (keysNext.includes(e.key) && i+1 < slides.length) { | ||
| 191 | goto(slides[i+1]); | ||
| 192 | } | ||
| 193 | if (keysPrev.includes(e.key) && i > 0) { | ||
| 194 | goto(slides[i-1]); | ||
| 195 | } | ||
| 196 | } | ||
| 197 | |||
| 198 | function onclick(i, e) { | ||
| 199 | const w = slides[i].offsetWidth; | ||
| 200 | const x = e.clientX; | ||
| 201 | |||
| 202 | if (x > w/2 && i+1 < slides.length) { | ||
| 203 | goto(slides[i+1]); | ||
| 204 | } | ||
| 205 | if (x < w/2 && i > 0) { | ||
| 206 | goto(slides[i-1]); | ||
| 207 | } | ||
| 208 | } | ||
| 209 | |||
| 210 | for (let i = 0; i < slides.length; i++) { | ||
| 211 | slides[i].addEventListener("keydown", e => onkeydown(i, e)); | ||
| 212 | slides[i].addEventListener("click", e => onclick(i, e)); | ||
| 213 | } | ||
| 214 | |||
| 215 | goto(slides[0]); // Go to the first slide when the presentation starts | ||
| 216 | ``` | ||
| 217 | |||
| 218 | First of all, every slide is a `div` with `class="slide"`. This allows | ||
| 219 | me to select all the slides with `document.querySelectorAll(".slide")`. | ||
| 220 | Then, after disabling any default handling of the arrows and space keys, | ||
| 221 | I add a new event listeners to every slide. These listeners uses the | ||
| 222 | `scrollIntoView()` function to scroll to the next or previous slide. | ||
| 223 | The `onclick()` function similarly handles clicks, where a click on the | ||
| 224 | left half of the screen goes to the previous slide and a click on the | ||
| 225 | right half goes to the next one. | ||
| 226 | |||
| 227 | And by the way, highjacking the default scrolling behavior is another | ||
| 228 | trend of modern web development that I hate. By I am fine with using | ||
| 229 | it here, because these slides are not meant to be a regular web page. | ||
| 230 | |||
| 231 | I also a function to add a footer to every slide: | ||
| 232 | |||
| 233 | ``` | ||
| 234 | function slideFooter() { | ||
| 235 | const start = "<div class=\"footer\"><table class=\"footer-table\"><tr>"; | ||
| 236 | const title = "Elliptic Curves and the ECM algorithm" | ||
| 237 | const link = "<a href=https://tronto.net/talks/ecm>tronto.net/talks/ecm</a>"; | ||
| 238 | const end = "</tr></table></div>"; | ||
| 239 | const content = | ||
| 240 | "<td class=\"footer-title\">" + title + "</td>" + | ||
| 241 | "<td class=\"footer-link\">" + link + "</td>"; | ||
| 242 | |||
| 243 | return start + content + end; | ||
| 244 | } | ||
| 245 | |||
| 246 | // In the main loop: | ||
| 247 | // slides[i].innerHTML += slideFooter() | ||
| 248 | ``` | ||
| 249 | |||
| 250 | In an older version I also had a small slide counter in the footer, | ||
| 251 | but I decided not to use it in the end. | ||
| 252 | |||
| 253 | Of course there was also some CSS work to | ||
| 254 | do. A new thing I learned in this regard is the | ||
| 255 | [flex](https://developer.mozilla.org/en-US/docs/Web/CSS/flex) | ||
| 256 | layout property, with which I was able to easily arrange | ||
| 257 | pieces of text and pictures in the slides - shoutout to | ||
| 258 | my friend [Jared](https://guissmo.com) for telling me about | ||
| 259 | it. Apart from this I don't have anything interesting to comment | ||
| 260 | about the CSS part of the slides. You can check the full code | ||
| 261 | [here](https://git.tronto.net/ecm/file/index.html.html) if you want; | ||
| 262 | everything is in a single HTML file. | ||
| 263 | |||
| 264 | The result looks fine, but it does not work perfectly will every screen | ||
| 265 | resolution. It's fine in 4:3 or 16:9, but with wider screens your | ||
| 266 | mileage may vary. I could improve it and always use the device height | ||
| 267 | (or width, but not both) as a reference. But this is quite some work | ||
| 268 | for very little gain, and in the end all I care about is that I can | ||
| 269 | show these slides from my laptop. I am sorry if you are viewing this | ||
| 270 | presentation from a smartphone. | ||
| 271 | |||
| 272 | You can view the slides | ||
| 273 | [on this page](https://sebastiano.tronto.net/talks/ecm). | ||
| 274 | |||
| 275 | ## Conclusion | ||
| 276 | |||
| 277 | I didn't need to do all this work for this presentation, but it was fun to | ||
| 278 | learn new stuff - not only for the C++ part, that I did not end up using | ||
| 279 | anyway, but also for the slides. It's good to know a bit of JavaScript, | ||
| 280 | even if I don't plan to use it much in the future. | ||
| 281 | |||
| 282 | I scheduled this post to go online on the same day as my presentation - | ||
| 283 | wish me good luck :) | ||
