 point P is defined. I don't need to know what the elliptic curve is because P knows it. And P knows how to add itself to other points on that elliptic curve. Okay, but notice you can already see from the structure of this algorithm, we're always going to be working in the subgroup generated by P because we know nothing else. Then we're going to let T be the greatest integer below 2 square root of Q, and then we're going to compute upper and lower bounds on the Haas interval. Low is the bottom of the Haas interval, and then we're going to let Q be the first multiple of P in the Haas interval. So that's low times P. Just for convenience, just to make the notation really clear, I'm going to let 0 be 0 times P. And it's important to do that. I mean, I don't have to write 0. I could have just written 0 times P everywhere, but I have to write 0 times P, not just 0. And the reason is if I just write 0, again, you have the situation of which 0 do you mean? Do you mean the 0 in Z, the 0 in FQ, the 0 in some polynomial ring, or the 0 on the elliptic curve? By writing 0, by writing 0 times P, it's clear that that has to mean the 0 on the elliptic curve. Then we start at the bottom, and while Q is not 0, we keep adding P to it and adding 1 to M. When we're done, we record the M that killed P as M0, and then we keep on marching until either we find another point where Q vanishes or we hit the top of the Haas interval. And then at the end, we either return, if we found two multiples, we return the second one minus the first, and if we only found one, we return the one multiple that we had. And we could check this against a bunch of random points. So I'm just, this is just a code snippet here. It's just generating a bunch of random elliptic curves, generating a bunch of random points on them, and then calling order multiple and making sure that the integer order multiple returns kills the point. That's all that was promised. We weren't promising to get the order on the nose. Question? Can I say that all of these particular cases? Yeah, I think if the integer is, so if we return a unique, if we return any integer, well, if Q is really small, maybe not, but if we return, if Q is large, if we return any integer that's bigger than Q plus 1 minus 2 squared of Q, we must be in that case where it's unique multiple. But as you'll see, when we go through MESTR's algorithm, it doesn't matter. You don't actually need to distinguish. But if you were trying to make this interface more friendly, maybe you could provide an optional return value that would tell the caller what it is. Yeah, that's a reasonable thing to want to do. Any other questions? Okay. So now, there's a faster way to do what we just did, but before I tell you the faster way to do it, let's jump down to MESTR's algorithm because I want you to see how this algorithm is actually used. Okay. So here's MESTR's algorithm. So its goal is to compute the number of FQ rational points on our elliptic curve E to find over FQ. So our input is the elliptic curve E. Our output is the number of FQ rational points. It's a very simple interface. We have one job. We just need to do that one job. We know we have problems potentially with Qs that are less than or equal to 49. So in that situation, we just farm it out to the algorithm. We already implemented our less naive point counting algorithm. Otherwise, we're going to let, because we're going to be working with two elliptic curves, E and its quadratic twist, we'll let, we'll call the curve we were given, call that E0, and we'll call the other, the quadratic twist E1, which is our non-isomorphic quadratic twist. And our setup is we're going to, our goal is to compute the trace of Arbenius mod some integer M. And once that integer M is at least as big as 4 square root of Q, we know we have the trace of Arbenius on the nose. So the invariant that's going to be preserved throughout this loop is that the trace of Arbenius is congruent to T mod M. And to make that true at the beginning, we just set M to 1 and T to 0. Every integer is congruent to 0 mod 1. And we're going to know when M is big enough, we want to compare, we want M to make M bigger than W, which is the floor of 4 square root of Q, that's the width of the Haas interval. And S is going to keep, is just a sign, it's going to be 1 or minus 1, and it's going to keep track of which quadratic twist we're on. And I'm realizing as I'm looking at the pseudocode that I left out a step, which is to switch between E0 and E1 depending on the sign of S. But that'll be clear in the code when we look at it. But our strategy is while M is smaller than W, so we haven't made M big enough, we're going to compute and or our order, we're going to call our order multiple algorithm to compute either the exact order of P or a unique multiple of its order in the Haas interval. And I've used the notation, you know, line P line quote as sort of an alternative pseudo-order of our point to denote that. And so, but which point P is this? This is going to be a random point on the quadratic twist that we're currently working with, either E0 or E1 depending on the sign of S. I'll fix the notes to include that before the problem session tomorrow. But so we generated a random point on one of the two quadratic twists. We replaced, and now we're going, and now we have new information about the tracepherbenius. Because if you think about the, on the elliptic curve, the number of rational points is q plus 1 minus t. And on the trace is q plus 1 plus t. And if we think of that equation modulo q plus 1, it's giving us information about the tracepherbenius. The tracepherbenius is going to be congruent to the number of points on our elliptic curve, which is a multiple of the order of point, of the point modulo q plus 1. And so we're going to incorporate that information, our new information about the tracepherbenius using sort of a CRT approach to compute the unique integer that is between 0 and the least common multiple of m and our pseudo order of our point p that's congruent to t mod m. It has to be consistent with what we already know. And it satisfies the equation mod q plus 1 that we know it has to satisfy in order to be the tracepherbenius in order for the order to be a multiple of the elliptic curve that we're working with. And so sometimes we'll get new information, maybe n divides m, or maybe the least common multiple didn't change, but that's okay are the theorem, the mestres theorem, and the generalization of Cremona and myself guarantees that this will eventually produce an m that's bigger than w and uniquely determines the trace. And once we have that, either we have to determine what the sign of t should be. It's just an integer between 0 and m, but it could be positive or negative, but we know which it must be because it has absolute value at most 2 root q. So if t is bigger than m minus t, then the sign has to be negative. So let me jump to the code where it'll be a little clearer, I hope. What's going on? Okay. So this is our mestre point counting function. It takes in an elliptic curve e, and it also takes an optional parameter, which is telling it what function to call to compute this pseudo-order. And so the function that we implemented, we just called order multiple, but there's a faster function called order multiple bsgs, which stands for baby steps, giant steps, which I realize I'm not going to have time to show you today, but it's a very simple algorithm, and I think I'll ask you to read it in election notes, and it improves the running time to the square root of the size of the house interval, so it'll be a q to the 1 fourth time algorithm rather than a q to the 1 half time algorithm. So our default is to use the faster algorithm, but if the caller, and we might want to do this to compare the two approaches, the caller can specify the order algorithm. So our first step is to figure out what finite field we're working in, what's its cardinality q. Here I even added an assert to say that it really should be a finite field, if we're in a characteristic zero field. And if q is smaller than 49, we call our less naive point counting algorithm, and now we're going to set up an array of size two, a vector with two elliptic curves in it, and we're going to use s, the s is going to oscillate between 1 and minus 1, and we're going to use the sine of s to tell us which elliptic curve we're working with. And as instructor, we're going to set m to 1 initially and t to 0, and w to the width of the Haas interval. And while m is smaller than w, or not bigger than w, we're going to take a random point on the twist that we're working with, which is sort of awkwardly written as take 3 minus s and divide by 2, that's going to give you either 1 or 2, depending on whether s is 1 or minus 1. And since magma does its array indexing from 1, you really have to write the algorithm in a funny arithmetic. If it was zero based, so if you implement this in sage, this line of code will be a little cleaner. So it's going to take a random point on one of the two quadratic twists, and it's just alternating between the quadratic twists in each iteration. That's all that's happening here. And then it's going to call the order function, which is this parameter that was passed in, to compute a multiple of the order of this randomly generated point that's either exactly the order and then we're going to call magma's built-in CRT function, which you can give it an array of values, so an array of integers, t and s times q plus 1, and an array of moduli that don't need to be relatively prime. It'll do the right thing. It'll compute the answer will be modulo the least common multiple. And then we multiply s by negative 1 to switch the sign of the trace of Frobenius, which simultaneously, because we've set it up with this array, is switching which quadratic twist we're working with. And then at the end, we figure out the sign of the trace of Frobenius by seeing whether the integer we got, modulo, some m that's bigger than 4, square root of q, is bigger than it could possibly be, in which case we know we must make the sign of negative. So let's go ahead and run this. And I loaded point-counting.p because that's where this order of multiple dsgs is defined. dsgs is defined. Let's just run our sanity check that it gives the right answers on a bunch of random curves and now let's just actually time it and boys this algorithm fast. It takes no measurable time when q is 1,000. It still takes very little time, like 10 milliseconds when q... That was for the slow version. The fast version is still instantaneous when q is a million, or close to a million. Let's go to a billion. Okay, at a billion, this starts to sweat a bit. So order multiple is the version that I showed you that doesn't use baby steps, giant steps. But the faster version is still instantaneous when q is a billion. So let's go bigger. I'm not going to try this on the slower version because it would take too long, but even when q is say 2 to the 61 minus 1, the bsgs version which has complexity q to the 1 fourth is still giving you an answer in under a second. Okay, so this for the question, if your goal were to count points on reductions of an elliptic curve over q that you wanted to compute mod p for a large sequence of p, say all the p's up to some bound n, well I can guarantee you your n is never going to be bigger than 2 to the 61. And this is the algorithm you should be using all the way along the way. We'll talk about that more tomorrow. But if you make q bigger, suppose q was cryptographically sized, like 2 to the 255 minus 19, for example, this algorithm would have no hope of counting points on that elliptic curve because even the fourth root of that q is too big. But, and in particular would take up too much space, but Schof's algorithm will happily be able to count points on it and the optimization to Schof's algorithm, due to Elkie's Knacken, the SEA algorithm can count points on a cryptographically sized elliptic curve without even breaking a sweat. And we'll talk about that on Friday. I better stop there. Questions for Drew?