T`was brillig and the slithy tovesYou want to use this string as the seed to a psuedo-random number generator. The one provided to you in the library wants a decimal string as its seed. So you
Now you want to get two prime numbers p and q. It is important to think ahead here. When you get around to doing the encryption or decryption, you will need to chop a file into blocks, where each block is encrypted as a single unit. Decide right now how large those blocks will be. Suppose that you decide to encipher blocks of about 10 characters (much too small for high security, but fine for testing). Since you treat a string as a number in base 257, the largest number that can be written in 10 characters is just less than 257^10. You want n (=pq) to be a little larger than that, since the RSA system requires that n be larger than any number that you try to encrypt.
You might choose p and q randomly in the range [2, ..., 257^6]. That way, each should be roughly in the middle of that range, and their product should end up being larger than 257^10.
It is entirely possible (but unlikely) that you find out, after choosing p and q at random and computing their product n = pq, that n < 257^10. In that case, you should either choose new numbers p and q, or (simpler) just scale back how many characters in a block. Whatever n is, you can safely use log(base 257) n characters in a block. To avoid type checking problems, compute this as nabs(floor(log 257 ~n)).
Please do not hard-code a number like 10 into your program. Instead, do something like
Let nominalCharsPerBlock = 10.and use nominalCharsPerBlock as the value to decide the range from which to choose p and q. That way, you can adjust this quantity as desired.
Let's explore a similar problem, converting from base 16 to base 10, where we have base 10 arithmetic built-in. Number 2a34 (base 16) can be thought as the list of its digits, [2, 10, 3, 4]. (Note that we can decide to write the numbers from left-to-right if we like, rather than from right-to-left.) This list of digits represents the decimal number 2*16^3 + 10*16^2 + 3*16^1 + 4. Factoring out common factors of 16 yields
((2*16 + 10)*16 + 3)*16 + 4It is convenient to add a starting value for a fold. Starting at 0 yields expression
(((0*16 + 2)*16 + 10)*16 + 3)*16 + 4Suppose that function f is defined so that f(x,d) = x*16 + d. Then the number represented by hexadecimal number [2,10,3,4] is just
f(f(f(f(0,2),10),3),4)This is a little awkward. A special binary operator can be defined, just to make this more clear. Say that # is the binary operator. Define x#d = f(x,d) = x*16 + d. Also, suppose that # is left-associative, so that several of them in a row are done from left to right. Then the number represented by hexadecimal number [2,10,3,4] is just
0 # 2 # 10 # 3 # 4Obviously, this base conversion is just a left fold. The result is 10804.
Of course, what you really start with is a string of characters, not a string of integers. But you can convert each character to its ascii code (using function rank), and you can convert them all by doing a map. You don't want 0's in the list, so you add one to each one of them. That is, what you really want is not the ascii code of each character, but a number that is one larger than the ascii code. If you see character 'a', you want to replace it by 99. (The ascii code for 'a' is 98). How can you do that?
The simplest way to understand this function is to work in mathematics rather than thinking too deeply about the process involved. Suppose that number n is represented by list x (in base 16). For example, n might be 10804, and x would be [2,10,3,4]. Divide n by 16, yielding quotient q and remainder r. That is, n = 16*q + r. Then x must be y++[r], where y is the result of converting q to a base 16 list.
For example dividing 10804 by 16 yields a quotient of 675 and a remainder of 4. Converting 675 to hexadecimal yields [2,10,3]. So converting 10804 to hexadecimal yields [2,10,3,4].
Just write a recursive definition of a function that converts a number to a base 257 number (as a list of digits). Now you need to take that list of digits and convert it back to a list of characters.
pulls (pullUpToN 10) "did gyre and gimble in the wabe" = ["did gyre a", "nd gimble ", "in the wab", "e"]
To decipher a number x, you take x to the power d, mod n. From a mathematical standpoint, it would be correct to write
Let blockDecipher(?x) = numToStr(s^d _mod_ n).Unfortunately, even for moderate size n, this will take a VERY long time. In reality, it will exhaust the available memory before it can finish. It is EXTREMELY inefficient, both in memory and time. You must use the efficient power algorithm that is provided to you in the modular.ast package. It works by the following equations. Suppose that pow(x,k,n) is suppose to compute x^k mod n.
pow(x, 2k, n) = pow(x, k, n)^2 mod n pow(x, k+1, n) = x*pow(x, k, n) mod n pow(x, 0, n) = 1 (x not 0)where the squaring done in the first equation is done as a single multiplication of a number by itself.