 So, I'm going to be talking about simple number theory in Perle-6. Number theory, the fundamental branch of mathematics, studying properties of integers, it is certainly fundamental in modern cryptography. Perle-6, I don't really need to talk a lot about what Perle-6 is here, sister language to Perle-5. A lot of this is conference-driven development, that is I've done a little bit of work with Perle-6 and wanted to do some more, so this is a way to force myself to do that. So I am Dana Jacobson, I'm coming from Portland, Oregon, the United States, come to Fostom a couple of times, love it here. Number theory for me is a hobby that got out of hand, I imagine lots of you guys have had something similar. So nice things about Perle-6. I've all heard there's lots of ways to do something in Perle-5, there's more than one way to do it. Perle-6, here's this, laughs, hold my drink, I'll tell you. Perle-6 has so many ways to do things, a lot of them are really nice. For me, everyone's going to have a different set of features they like, Damian Conway talked about how he just loves using Unicode characters in his programs. I'm from the United States, I don't know what he's talking about. So Jeff and some other people, Brian, are looking at grammars, I haven't looked at grammars, but it has something for everybody. I love big ins, native to Perle-6. In C code and in Perle code, you're constantly fighting with this issue of when my numbers start getting large, weird things start happening. We have rationals, I don't actually care so much about them, I know a lot of people love having the idea of rationals where I can just maintain this idea of it's 1 over 3, not immediately turn that into 0.333, something not 3. Junctions are pretty cool, EXP mod is a wonderful feature, it's a function I end up writing in every other language because when you want to raise A to the kth power, mod n, that's a terrible way to do it if you actually raise A to the kth power. And then mod n, because you end up with the humongous number and there are much faster ways to do it. Perle-6 has it completely built in. Perle-6 also decided that hey, this idea of is a number prime is pretty fundamental and people keep writing it in every language, so we're just going to toss it in. That's nice. We get a bunch of other little functions. Pick is surprisingly useful, you take a list and just say give me a random element from it, it has lots of variations, it is used all over the place. So let me start with this very simple RSA example, we're going to generate a key. So we want to generate a couple random primes and as the product of the two, I think, yeah, so we choose, take the LCM of the totions, which because their prime is very easy, we choose an E, we get our D, let me go through the Perle-6 code for this. And random primes, it's really, really simple except my is prime ran off the screen there. So we just take, we have a number of bits, we just keep taking random numbers until it's prime. And there we go, now we can fill up P and Q very easily. These are very simple, oh wait, but Perle-6 has LCM built in, the least common multiple. So I want to choose an E, there's a different way to do this, if you want you could just pick an E that's coprime, this is a different way to do it, you go ahead and pick a random one. And we get to use our GCD function and again our pick just says, just give me a random value from that, we do it until it's coprime. So now we want D which is going to be our private key, we want the inverse of that. The idea is D times E ends up being one mod phi. So how do we do that in other languages? Well we get to write a routine to do it, but in Perle-6, well we have this exp mod, just give it minus one, it'll give you the inverse. It's surprisingly handy, this is really short code compared to what we end up with writing in other languages. And we decided to use 1024 bits, Perle-6 has no problem with this whatsoever. My talk is not going to be about cryptography so I'm going to leave aside all of the math reasons why and the boilerplate code you would normally add to actually make this a useful routine, you can look that up. So binomial is very common, we want to find the number of combinations, taking 50 items for instance, I want 50 items and I want to choose combinations of 10 of those. How many do I have? I add dot elements and I get this humongous number. Well I'm sure I'm glad I didn't iterate over that, Perle-6 is very clever and knows that in fact you're just asking for the number of elements, you didn't want me to create this huge list with this many items in it, you didn't want an iterator, you just wanted the number of elements. So Perle-6 gives that to me. This is a formula for how you calculate that. If you dig through the Perle-6 internals, this is the product of n times n minus one, n minus two and so on, we divide by factorial of k, if you dig through the Perle-6 code you find basically this in Perle-6. First we have n down to zero, this is a zip operator, so we're going to take this second list which has a little optimization in it for the minimum and we do the divides. And finally we get to reduce it, we just say star here, it says multiply everything together. Now in these, these ended up being rationals. So in most languages you end up having to write a whole lot of code to deal with this, it's not complicated code but you have to keep in mind oh wait I have to make sure those divides are all integers. In Perle-6 we don't really care, we just write the routine just like we would like to. Here's binomial in C, this is a pretty standard way to do it, Mark Jason Dominus had this on his blog in 2007, well not this, but something like it and said this is how you should do binomial, it has no overflow problems, it's great, except it does overflow. Someone found a, he posted this on Reddit and someone said oh actually it does overflow. Now probably most of you will see the obvious way to fix it. So this is how you fix it in C, it's actually very fast, it's clear, everybody would do this and you completely understand why this works until you realize this is still only for 64 bit. If I go past 64 bit I have to start getting into big ant libraries and portability issues and so on, Perle-6 solves it all. So now I'm going to talk a little bit about primes, why primes, well okay some of you who know me are wondering have you ever given a talk where you did not say the word prime and yes but it was about a decade ago. Primes are really important, in number theory they are the atoms for the integers, if you will, there are a lot of algorithms, in fact the binomial algorithm you can do faster, if you say well I don't actually have to denote all the numbers up to n, I can just go over the primes so I can speed things up. There are a lot of algorithms in number theory where it turns out you don't actually have to go up for instance solve to n, you can factor n, perform your operations on the prime factors and then combine them and you come up with much faster ways. So there are three things we generally want to do, generate primes, recognize primes and factor integers, we don't factor primes. So the usual way of generating primes is the Seaf of Eratosthenes who wrote about this in about 250 BC, he was the chief librarian of Alexandria, he wrote in all sorts of different areas, he contributed to many many many fields, unfortunately all his works were lost when the library burned but lots of people wrote about the things he did including this algorithm and interestingly there are some new sieves that have come out in the 20th century, they are all slower than this, they have some interesting properties, the Seaf of Atkin actually is slower than the Seaf of Eratosthenes, I'm going to talk about just the very basic monolithic non-segmented sieve, you can get complicated, start adding optimizations like everything you can spend a year adding optimizations. So very simply we enumerate all our numbers from 2 to n, I've chosen 120, we pick the first one and say that one's prime, because they all kind of look prime right now and we actually we know that 3 is as well because we know everything up to 2 squared is prime and we just mark all the evens because we know they're all multiples of 2. So then we can move on to the next one which is 3, we're going to mark all the multiples of 3 because I've chosen 15 here, they're all going to line up, we can do the same thing for fives, notice that I don't, I start at 5 squared because everything up to that it's already been marked, we go up to 7 and it turns out at that point we're done because 11 squared is 121, so there wasn't a whole lot of operation going on to generate these primes. On Wikipedia you'll find the pseudocode, which it turns out seems to be remarkably hard for people to implement, it's four lines, we go up to the square root of n, we ask if it's prime, if this number's prime so far we go from i squared up county by n. So there's an operation that is not done in here, which is remainder or divide, it's a very efficient algorithm because the only thing going on is marking and adding. So in C, we're not going to go over this very long but basically it's exactly the same thing as the C, here's our four lines we can argue about i times i versus taking the integer square root, but there's your four lines and then we go through and we can do that. Pearl 5, in this case I've done an additional optimization of only going through the odds, that is we saw most of that work was at the very beginning where we had to mark all the odds, well after two we know we don't have to deal with them at all, so we're just going to ignore them. So here's, this is not very pearly code but it is exactly the same as that C code or the Wikipedia but in this case we get to go, we skip the odds. There is a bit of wonkiness at the end where we're doing a map and grep to turn those odds back into the numbers we care about. So we use half the memory by doing this. So on Rosetta code, I looked last year, it was partly the reason for this, I said there are three examples of the sieve of veritastins on Rosetta code and all of them are wrong. So they start out okay, they say zero and one, not prime, everything else looks prime so far. We do a gather, this is a cool feature where we take the key value, we just say I want the actual number and then I want the value that's in that array. So I can get them both at the same time and then we do, oh well if it looks prime then take the number but wait what is this doing? That's a mod operator. So for every number from n squared up to n, I'm going and checking the divisibility. I'm basically doing trial division on every number repeatedly. So there's a simple solution, now we have the sieve of veritastins in pearl six. Looks exactly like the C code or like the pearl five code or the Wikipedia pseudocode and it runs significantly faster. So pearl six has a lot of different ways to do these things. We can try doing it using a set, this is something someone put on Rosetta code as well. Doing it with a set, we have our multiples, we're going to gather unless multiples contains the number, we take it and we do a set union. You can use fancy unicode characters for the contains and union. Basically we're making a new set with number squared, that plus number and so on, which is exactly what we wanted from that pseudocode. You could change it to is the number an element of the set, is the number intersected with the set, we can go straight to exists key, lots of ways to do it. We also have this is prime operator so we could just do, well I'm just going to walk all the numbers and ask if it's a prime. That's not a sieve but is prime is built in so maybe that's fast and certainly easy. It's so easy you could just do basically grep is prime through a list. So the set operator, so that code has some significant problems with it and also pearl six's sets haven't been optimized entirely so we're going to ignore that. But here's our trial division. It took four hundred and one seconds to generate the primes to one million, which is absurdly slow. So we know doing trial division basically the incorrect sieve of veritostin is the wrong way to do it. Here's the is prime version. Okay, so I wrote a new version of is prime. I went to more VM and started writing C code and so there's a new version of is prime and I'll talk about that more later, which is significantly faster and it's faster at all sizes. So hopefully I will actually get that pushed out soon. So our sieve actually when you fix the sieve instead of doing this kind of broken sieve you do the real one it's looking pretty good. You can do odds only. I didn't show that example but you can speed that up some more. That's looking good if you increase this it would start looking better. Pearl five has had what twenty something years of additional optimization and we're marking and adding this is absolutely what C loves to do. So this is a little bit of an unfair example here because this is so simple but we've chosen something very very simple to try out and see there are lots of ways to do it in pearl six and you can speed it up and in fact you can certainly call C code from pearl six if you wanted to. So we're moving on to the next one how do we recognize a prime? Well we can do trial division which is actually really good for numbers up to you know a thousand or a million but if I give you a 64-bit number and say hey try dividing by all the numbers up to the square root of n or if I give you a thousand digit number you're never going to finish it's really slow. Miller came up with this method in about 1975 which is very efficient and answers the question entirely of whether a number is prime. It's a bit of a problem. Step one prove the Riemann hypothesis. So this has been giving us a bit of a bother for the last 150 years so that doesn't really work very well. We can do special forms. Mersin numbers or proth numbers that is numbers that are two to the n minus one or two to the k times two to the n plus one we have some really efficient ways to do it but that only works for numbers of that sort if you like to finding large Mersin primes then that's nice but that's not very useful for most people. We can do partial factoring methods this is really what was used up to well in the 1800s 1900s up to 1980s where I take n minus one I want to find out if n is prime I take n minus one or n plus one and I perform some factoring on it. I don't have to completely factor the number but I have to do some factoring. It turns out we did primality fairly well that method works quite well up to about 40 digits starts getting slower and eventually you just can't find factors. So in the 1990s there were a couple methods. They're quite efficient APRCL and ECPP. APRCL are the initials of the people who created the algorithm. ECPP is elliptic curve primality proving. I think there are two reasons people normally don't use these. One is computer programmers don't usually know that they exist and two is they're complicated. Perl 5 has one of the in the n-3 module has one of the only implementations of ECPP out there this open source certainly the vastest and hopefully Perl 6 will get one soon. So because these are hard we come up with this idea of a probable prime. So what to do to find a probable prime you find some property that all primes have and that most composites don't have well if lots of composites have it then it's not a very useful test but if all primes have this property and very few composites have this is actually fairly useful and this is quite commonly used. So the common return values are zero definitely composite one is probably prime sometimes will add something for definitely prime and minus one is the if these are your only responses and you have for instance you're doing a Lecaux Limer test and it's not Lecaux Limer scene number well you can't return anything here it's the wrong form you don't know what it is. No small divisors we're going to give some little little Perl 6 code here this is a particularly bad one this just says are you visible by two or three if not you look kind of prime most humans go something like this they might go with five as well do something like this I don't know it looks kind of prime so this is kind of neat these junctions where we can basically just instead of saying n equals two or or n equals three or and so on we get to just say n equals two or three here's the mod 30 version of it all primes past five are going to have this property this gets kind of messy in most languages junctions make this really simple and easy to read oh if the remainder after 30 is this great so from all I was just in France and they were telling me yes it is from all and look ah in the United States it's either from all or format if I said look ah in the United States no one would have a clue who I was talking about it's a Lucas there but so from all came up with this little theorem which says if we take an a between two and p minus one and we raised to p minus one power if p is prime it's one mod p all primes have this property some composites do most don't so here in pearl six this is a bunch of boilerplate mainly having to do with small numbers and I'm gonna you could add restrictions for making sure your base doesn't exceed it doesn't go out of range I've decided to try to make that work it's kind of irrelevant wow that's easy the XP mod so there is a problem Carmichael came up it said hey there's this class of numbers where this is true for composite some composites this is true for every base so you will never be able to figure out those numbers are prime or composite because they look prime based on this test so Euler published a few papers and one of the things he came up with was well we can improve this test so we're gonna have now it is p minus one divided by two is plus or minus one and same boilerplate but there we go note the shift operator is plus the bitwise shift operator plus greater than we use our junction again very easy Euler also went and said you know it's not just plus or minus one it's equal to the Jacobi symbol what's the Jacobi symbol so Legendre came up with this idea even earlier and said well this symbol and surprisingly useful number theory is zero if it evenly divides P it is one if it is a quadratic residue that is if there is a number that exists that it's a square mod P and minus one otherwise so here's a crazy version of Legendre symbol in Pearl six we've used an infix operator with a special pipe we've made Damian happy by using italicized characters and their sigilists and we're using a given one so unfortunately this particular form doesn't help us much because we're already going through the same operation the Jacobi symbol is basically the product of that for factors but you don't have to factor and you can do this is kind of ugly code but it exists you'll see the same code in lots of languages so now once we have that very simple Euler Jacobi in Pearl six we mod n because we're going to get back a one or minus one so this is a simple way to do it and all of a sudden our kind Michael go numbers go away this test if you run random a values it turns out that no more than half of the a values are going to work for any composite so Solovey and Strossen made this a primality test you probably heard of Miller Rabin test this came first and now we'll go to Miller Rabin you may have seen this before we take n minus one basically take out the odd part and run this routine I'm not going to go over the math behind it but that one also has no Carmichael numbers is is classically used this looks exactly like C code you'll find everywhere for this so in Pearl six with this idea that will the chance of being a composite passing this test is one quarter if you use random bases then your chance is four to the minus K which goes very small very quickly in Pearl six says we'll use a hundred bases for this is a great idea no so the reason why this is not a good idea is actually two-fold the number one is in more vm it uses Lib Tom math and Lib Tom math does not use random bases is the first 100 prime bases which sounds great until you find out that in 1994 someone published a paper which showed you how to generate counter examples to this so this is a particular number that he published there's an algorithm to generate these and Pearl six will tell you that this is prime it is not prime there are ways to fix this we'll talk about that in a minute the other thing is using a hundred of these tests is significant overkill we don't need to do that any tests so that's a performance issues and this was a common method in the 1980s early 90s some people published papers and said you know this is really problematic for a number of reasons so Pearl six used to have in the language specification that is prime took a parameter of the number of trials for Miller Abin which I particularly disliked because it put implementation details into the language itself fortunately that was all removed before the language came out so we can apply better methods without changing the API as long as we do the right thing so the BPSW test is the way that most people have standardized on you do a single Miller Abin test and you do a look at test hopefully a strong test this is my wall of text that I should not do in talks it was published in 1980 it is deterministic for all 64 bit in numbers no counter examples have been found there are at least two theses where people worked hard on trying to find counter examples using very clever math to say well I'm sure that this set contains it the only problem is the set is of size two to the one thousand something and so one of those numbers in that set might be a counter example so we haven't found that yet almost all math programs use this and go Julia and Python modules have all started moving to this so I have an implementation in more VM for this and it should be pretty easy to put in JVM as well and it's faster so you know a couple methods for factoring I'm not going to talk about all of these trial division very straightforward for Ma busy guy also came up with a method for factoring Pollard has his row method and P minus one very common square form factorization ECM quadratic sieve and NFS are all commonly used NFS is generally a PhD level pro I think there are two implementations out there certainly I'm not going to show you an implementation it would be tens of thousands of lines so child division Damian showed an example in his talk the primary difference here is just that when you find a factor you need just your new composite you need to start looking less I guess I should say a lot of the examples do not do this test of redoing the limit and so they do a lot more work this this is useful for small numbers for Ma we do basically we're looking for differences of squares all odd numbers can be represented as differences of squares from all said hey if there are two factors are close to each other we can find this fairly quickly we have this is perfect square predicate so how do you find perfect squares that is a number that is s times s equals n is any perfect square so you think oh well I can just write it like this I have big big numbers so big it's great I just take the square root of n turn that into an integer and see if that returns that but we then realize Pearl 6 does not have big floating point numbers so that actually doesn't work so the right thing to do is write a integer square root routine I did not do that yet about 64 or 53 bits this starts failing it's just like see just like Pearl 5 this is a way to solve the problem it's not ever it's fine for 64 bit it gets very very slow this is the wrong way to do it or it's an inefficient way to do it so some other people have said you can actually do some tests you can actually quickly look at a number and find out for some simple properties is this is it possible this is a perfect square so we can run that final test less often if square root is really expensive you can do some very simple math to avoid it you can also be clever with bits and do it notice the shifting the bitwise and is a little different in Pearl 6 you can go totally crazy if square roots are really expensive and you can continue this process these are using bloom filters which are basically a way of filtering out anything that isn't going to be possible using different simple divisors so Pollard row Damien showed this example this is with Brent's cycle optimization Damien said that this was called the row algorithm because it uses a variable called row it doesn't use a variable called row and that's not at all the reason why that's named that it's a really fuzzy image the idea is we're trying to use the birthday paradox to find examples where we can find a collision so we have two processes running one going slow one going fast and the idea is when can we find an example where they correspond and if you graph this out somebody said well it looks kind of like a row simple and that's why it's called Pollard's row and it is really really fast at finding small factors when I say small I mean say eight digit ten digits it doesn't matter how big your number is if it has a small factor you know under ten digits this is going to be extremely fast at finding it so it's not useful for solving RSA cryptography if your keys were generated correctly you have two very very large factors not going to work at all but for small factors this is really common and this is Pollard's P-1 algorithm was trivial to write straight from Wikipedia into Pearl 6 it basically says well maybe I'm having a hard time factoring n but what if n minus 1 has a lot of small factors and if it does we can factor n very quickly and that pretty much concludes my talk on Pearl 6 and number theory