diff --git a/understanding-rsa.py b/understanding-rsa.py
new file mode 100644
index 0000000..f3fcb95
--- /dev/null
+++ b/understanding-rsa.py
@@ -0,0 +1,254 @@
+# Understanding RSA
+
+### Setting the Stage
+I want this paper and exercise to be fun and enlightening for everyone.
+I will try to make it fun and easy to follow along without glossing over too much of the underlying maths.
+That being said, if this is not for you, or you just hate math, I encourage you to still try.
+I will be adding python code blocks you can run as we move through the paper which I hope will make it more interactive and engaging.
+
+### So what is RSA?
+We can't start talking about what RSA is without first paying homage to the creators, where it gets its name.
+Ron Rivest, Adi Shamir, and Leonard Adleman collaborated and invented this public key system back in 1977, which in of itself really
+does show its stability since it is still used widely today. RSA as I said before is a public key system or also known as an
+Asymmetric encryption. This basically means that the encryption key is actually made public for everyone to use, called a public keys
+then a 2nd decryption key us held privately by the owner, simply named a private key.
+But I am sure many of you know this and thats not why you are here, you are here for the Juicy bits
+
+### Defining the Language
+As with most mathematics, someone a while ago decided to use fancy letters to represent things, probably as a way to flex their
+intelligence... I'm joking for the most part, normally this is done to help differentiate between different types of mathematics.
+I plan on doing some First order Logic papers eventually and you will see what I mean by that then.
+ANYWAY... Lets just make a table we can refer back to later to help.
+
+|Symbol|Meaning|Do we Keep it Private?|
+|---|---|---|
+|p| Prime #1 | TRUE |
+|q| Prime #2 | TRUE |
+|n| n = p * q | FALSE |
+|φ(n)| φ(n) = (p-1) * (p-1) | TRUE |
+|e | pick any integer where 1 < e < φ(n) AND e is a coprime of (n AND φ(n))| FALSE |
+|d | where d*e(mod φ(n)) = 1 | TRUE|
+
+Now, I will gloss over the phi function here but if you want to learn more as to where it comes from there are links at the bottom
+e and d (for encryption and decryption) on the other hand needs some explaining but hang with me we have some tricks.
+
+The first part of e is simple enough, we need a integer that is between 1 and φ(n) which at this point we know. The second part however,
+what does coprime mean, well in this case it means it shares no common factors with both n and φ(n). Now what we can do to simplify this
+is to just say e must be prime, and not a divisor of φ(n) (or if you divide φ(n) by e you do not get a whole number),
+which we can do some quick checks to be sure.
+
+For d what we need to find a value that results in multiplying it by e and then doing mod φ(n) which gives us 1. I will go into how to find
+this in our first example.
+
+To clear the air incase anyone is rusty or does not know what 'mod' means it basically is a remainder function, you shove
+a number into a mod(n) and you get out what is left over. I like to picture it like a clock which is mod(12). So if you know
+military time you kind of do this already, 1400 hours is actually 14 mod(12) which is 2, or 2pm. You count up to 12 and then
+start back over so 5 mod(3) would be 2, and 12 mod(5) would be 2 like 1,2,3,4,5,1,2,3,4,5,1,2
+
+### Example Please...
+OK you stuck with me this long lets generate some keys. For this first one we will start with really small prime numbers.
+Clearly this is a terrible idea since the smaller our starting primes are the easier it is to crack, but the math is still the same
+and it is faster and easier to follow along.
+
+1. Pick 2 primes, our p and q, let's say 67 and 79
+2. Generate n by multiplying p and q to get 5293
+3. Generate φ(n) by multiplying p-1 and q-1 to get 5148
+4. For e, pick a prime number between 1 and 5148 and is not a divisor of 5148, let's go with 17
+5. For d we find a value where d*e(mod φ(n)) = 1, lets go with 1817
+
+OK, now you might be asking, how the hell did I get 1817 for d, the question feels kind of brute forced. Well this is where
+I used the first bit of python code we really kind of need.
+
+```py
+def mvi(e,phi_n):
+ for x in range(1,phi_n):
+ if((e%phi_n)*(x%phi_n) % phi_n==1):
+ return x
+```
+
+I called this mvi which is short for Modular Multiplicative Inverse, which I will also kind of gloss over as well,
+but I wanted you to see that you don't need to manually guess and check by hand, this does it for you.
+
+So now we have our numbers, let't table them back out
+
+|Symbol|Value|
+|---|---|
+|p| 67 |
+|q| 79 |
+|n| 5293 |
+|φ(n)| 5148 |
+|e | 17 |
+|d | 1817 |
+
+
+### Great now what...
+
+Well now the fun starts, again we are kind of doing this by hand so rather than starting with a string and converting it
+to a number to encrypt then send and then decrypt then convert back into a string lets just encrypt a number using our
+new keys
+
+First we need to send our Pub key to Alice, this is the pair of numbers e and n, so we will send her (17, 5293).
+Again this is public, so we can send this however we like, as long as we are sure its not messed with on the way.
+
+Now Alice will send us a secret number by encrypting a clear number using this public key and that is done with the
+following function
+NOTE: For those that do not know, the power function in python (pow()) allows for 3 inputs with the 3rd being Mod which comes in really handy for us since it is way more effienent than doing `message**e % n`
+```
+def encrypt(message,e,n):
+ return pow(message,e,n)
+```
+Thats it, so in this case let's send 791, so we do `encrypt(791,17,5293)` which results in 5215
+
+Bob gets 5215 and needs to decrypt it and that is done with this function
+```
+def decrypt(message,d,n):
+ return pow(message,d,n)
+```
+This is almost the same but we swap out the e for the d, and if we plug in `decrypt(5215,1817,5293)` we get, you guessed it, 791
+
+And to show Im not making this up...
+
+[![python.png](https://docs.hackliberty.org/uploads/images/gallery/2022-05/scaled-1680-/TqDpiF2ceumYtBO2-python.png)](https://docs.hackliberty.org/uploads/images/gallery/2022-05/TqDpiF2ceumYtBO2-python.png)
+
+The last bit is a full python function you can play with to do some encrypton and decryption using what I have shown
+
+```py
+def simple_rsa_gen():
+ # Just a short list of 3 digit primes we can pick from so you dont need to find your own
+ primes = [211,223,227,229,233,239,241,251,257,263,269,271,277,281,283,293,307,311,313,317,331,337,347,349,353,359,367,373,379]
+ # Lets pick our p and q from this list
+ p = primes[(randint(1,29)-1)]
+ q = primes[(randint(1,29)-1)]
+ # Lets make sure we did not happen to pick the same prime for both
+ if p == q:
+ while p == q:
+ q = primes[(randint(1,29)-1)]
+ print("p = "+str(p))
+ print("q = "+str(q))
+ # Now lets generate n by getting the product
+ n = p * q
+ print("n = "+str(n))
+ # Lets get that phi_n we need
+ phi_n = (p-1)*(q-1)
+ print("phi_n = "+str(phi_n))
+ # Lets find a good value for e, remember this needs to be a prime between 1 and phi_n and cannot be a divisor of phi_n
+ # you will see my range is not going to start at 1, first becuase 1 is not prime also I want to move into 3 digits to start
+ def get_e(var_phi_n):
+ for i in range(101, var_phi_n):
+ prime = 1
+ for j in range(2, i // 2 + 1):
+ if (i % j == 0):
+ prime = 0
+ break
+ if (prime == 1):
+ if var_phi_n % i != 0:
+ return i
+ break
+ # So let me break down what I just did, first we need to pass in what out phi_n is, that will be out upper limit
+ # then we need to determine if its a prime which we can do by seeing if its mod returns 0 for any int up to itself
+ # which in laymans terms means does it have any devisors at all, then if it is a prime we just make sure it't not
+ # a divisor of phi_n which just can be checked with does phi_n mod n = 0, if it does its no good
+ # Now we are starting at 101 and in most cases this will work for us, would be rare to find an instance where 101
+ # is infact a divisor of your phi_n so expect to see it more times than not. In general the goto e is actually 2^16 + 1 = 65537
+ e = get_e(phi_n)
+ print("e = "+str(e))
+ # Lets get that d value we need, the bigger phi_n gets the longer this could take
+ # here we are doing that mvi funtion again and the larger your starting primes the longer this can take
+ def mvi(var_e,var_phi_n):
+ for x in range(1,phi_n):
+ if((var_e%var_phi_n)*(x%var_phi_n) % var_phi_n==1):
+ return x
+ d = mvi(e, phi_n)
+ print("d = "+str(d))
+ # Now we have all of he numbers we need. Lets make our pub and priv keys and end this.
+ print("Your Public key is ("+str(e)+","+str(n)+")")
+ print("Your Private key is ("+str(d)+","+str(n)+")")
+ # Now we can use these with the encrypt and decrypt functions we made before
+```
+The output from above will look something like this
+```
+p = 283
+q = 211
+n = 59713
+phi_n = 59220
+e = 101
+d = 57461
+Your Public key is (101,59713)
+Your Private key is (57461,59713)
+```
+And then you can use them to run those functions we defined before
+
+[![encdec.png](https://docs.hackliberty.org/uploads/images/gallery/2022-05/scaled-1680-/q7YOjVDrTov5Cuw6-encdec.png)](https://docs.hackliberty.org/uploads/images/gallery/2022-05/q7YOjVDrTov5Cuw6-encdec.png)
+
+### Is this real life?
+
+For the most part yes, of course it is. The big differences are when actually implemented in code there are some better
+methods for being more efferent as well as using random primes that are hundred of digits long, not 2.
+
+For example, try the above code and method with 2 much bigger Mersenne primes 2^521 - 1 and 2^607 -1
+
+You can see this in practice in the openssl sourcecode for rsa generation here.
+[OpenSSL rsa_gen.c](https://github.com/openssl/openssl/blob/master/crypto/rsa/rsa_gen.c)
+Look around line 174 and go from there, see if you can gather what its doing and how it is being more efficient than what we did.
+
+### So you seen some stuff
+
+This was a very high level and I did for sure gloss over some things but the math is there and I encourage you to look at
+what I have shown here and ask yourself some questions, challenge yourself
+1. Can you see any potential issues, how would you get past them?
+2. Can you update the functions to use strings not just numbers?
+3. In our first example what happens if I picked the number 31337 like we did in the 2nd example?
+
+If you liked this please let me know back in the community post where I linked this, if you have questions or want more
+let me know that too.
+
+### More Links
+I said I would
+- https://en.wikipedia.org/wiki/RSA_(cryptosystem)
+- https://en.wikipedia.org/wiki/Modular_multiplicative_inverse
+- https://yewtu.be/watch?v=-ShwJqAalOk
+- https://yewtu.be/watch?v=JD72Ry60eP4
+- https://yewtu.be/watch?v=S9JGmA5_unY
+- https://yewtu.be/watch?v=O4xNJsjtN6E
+
+### A Little More
+When I changed to pow(message,d,n) I was able to do bigger primes much faster so I put together another one using 5 digit primes you can play with.
+```py
+def bigger_rsa_gen():
+ # Doing a bit Bigger list of 5 digit primes now
+ # I stripped comments to save space
+ primes = [17029,17033,17041,17047,17053,17077,17093,17099,17107,17117,17683,17707,17713,17729,17737,17747,17749,17761,18233,18251,18253,18257,18269,18287,18289,18301,18307,18311,18313,18329,18341,18353,18367,19207,19211,19213,19219,19231,19237,19249,19259,19267,19273,19289,19301,19309,19319,19333,19373]
+ p = primes[(randint(1,49)-1)]
+ q = primes[(randint(1,49)-1)]
+ if p == q:
+ while p == q:
+ q = primes[(randint(1,49)-1)]
+ print("p = "+str(p))
+ print("q = "+str(q))
+ n = p * q
+ print("n = "+str(n))
+ phi_n = (p-1)*(q-1)
+ print("phi_n = "+str(phi_n))
+ def get_e(var_phi_n):
+ for i in range(10007, var_phi_n):
+ prime = 1
+ for j in range(2, i // 2 + 1):
+ if (i % j == 0):
+ prime = 0
+ break
+ if (prime == 1):
+ if var_phi_n % i != 0:
+ return i
+ break
+ e = get_e(phi_n)
+ print("e = "+str(e))
+ def mvi(var_e,var_phi_n):
+ for x in range(1,phi_n):
+ if((var_e%var_phi_n)*(x%var_phi_n) % var_phi_n==1):
+ return x
+ d = mvi(e, phi_n)
+ print("d = "+str(d))
+ print("Your Public key is ("+str(e)+","+str(n)+")")
+ print("Your Private key is ("+str(d)+","+str(n)+")")
+```
+