From 4b0e7b0d258e23662a8e916f6fabd9b949a1f40f Mon Sep 17 00:00:00 2001 From: jackddouglas Date: Fri, 6 Sep 2024 18:11:39 +0100 Subject: [PATCH] Quartz sync: Sep 6, 2024, 6:11 PM --- content/.gitkeep | 0 content/Abelian group.md | 3 + content/Euclidean algorithm.md | 60 +++++++ content/Eurler's Theorem.md | 3 + content/Fermat's Little Theorem.md | 5 + content/Groups.md | 15 ++ content/Miller-Rabin primality test.md | 71 +++++++++ content/Modular exponentiation.md | 56 +++++++ content/Monoid.md | 5 + content/RSA.md | 181 ++++++++++++++++++++++ content/Week 1.md | 7 + content/extended Euclidean algorithm.md | 64 ++++++++ content/fields.md | 11 ++ content/modular multiplicative inverse.md | 67 ++++++++ content/rings.md | 9 ++ content/subgroup.md | 7 + content/totient.md | 22 +++ 17 files changed, 586 insertions(+) delete mode 100644 content/.gitkeep create mode 100644 content/Abelian group.md create mode 100644 content/Euclidean algorithm.md create mode 100644 content/Eurler's Theorem.md create mode 100644 content/Fermat's Little Theorem.md create mode 100644 content/Groups.md create mode 100644 content/Miller-Rabin primality test.md create mode 100644 content/Modular exponentiation.md create mode 100644 content/Monoid.md create mode 100644 content/RSA.md create mode 100644 content/Week 1.md create mode 100644 content/extended Euclidean algorithm.md create mode 100644 content/fields.md create mode 100644 content/modular multiplicative inverse.md create mode 100644 content/rings.md create mode 100644 content/subgroup.md create mode 100644 content/totient.md diff --git a/content/.gitkeep b/content/.gitkeep deleted file mode 100644 index e69de29..0000000 diff --git a/content/Abelian group.md b/content/Abelian group.md new file mode 100644 index 0000000..ba75fef --- /dev/null +++ b/content/Abelian group.md @@ -0,0 +1,3 @@ +AKA commutative group + +Group operation is commutative. Group in which the result of applying the group operation to two group elements does not depend on order in which they are written. \ No newline at end of file diff --git a/content/Euclidean algorithm.md b/content/Euclidean algorithm.md new file mode 100644 index 0000000..5aa71fc --- /dev/null +++ b/content/Euclidean algorithm.md @@ -0,0 +1,60 @@ +--- +id: Euclidean algorithm +aliases: + - standard Euclidean algorithm +tags: [] +--- + +see also: [[extended Euclidean algorithm]] + +# Euclidean algorithm +A simple and efficient method for computing the greatest common divisor (GCD) of two numbers. + +1. Start with two positive integers a and b. +2. Divide a by b and get the remainder r. +3. If r is 0, b is the GCD. +4. If not, replace a with b and b with r. +5. Repeat from step 2 until r becomes 0. + +## Rust Implementation +```rust +fn gcd(mut a: u64, mut b: u64) -> u64 { + while b != 0 { + let temp = b; + b = a % b; + a = temp; + } + a +} + +fn main() { + let a = 48; + let b = 18; + let result = gcd(a, b); + println!("The GCD of {} and {} is {}", a, b, result); + + let c = 17; + let d = 23; + let result2 = gcd(c, d); + println!("The GCD of {} and {} is {}", c, d, result2); +} +``` + +This implementation: +1. Takes two unsigned 64-bit integers as input. +2. Uses a while loop to repeatedly apply the division step. +3. Swaps the values of a and b in each iteration, with b becoming the remainder. +4. Continues until b becomes 0, at which point a is the GCD. + +The algorithm works because of the following property: +If a = bq + r, then GCD(a,b) = GCD(b,r) + +This property allows us to continually reduce the problem to smaller numbers until we reach the GCD. + +Key points about the Euclidean algorithm: + +1. It's efficient: the number of steps is at most 5 times the number of digits in the smaller number. +2. It works with any two positive integers, regardless of which is larger. +3. It can be extended to find the GCD of more than two numbers by repeatedly applying it. + +The main difference between the standard and [[extended Euclidean algorithm|extended Euclidean algorithms]] is that the extended version also finds the coefficients of [[Bézout's identity]], which expresses the GCD as a linear combination of the two original numbers. diff --git a/content/Eurler's Theorem.md b/content/Eurler's Theorem.md new file mode 100644 index 0000000..b6d3ab1 --- /dev/null +++ b/content/Eurler's Theorem.md @@ -0,0 +1,3 @@ +Expansion of [[Fermat's Little Theorem]]. + +States that for any integer $a$ and any positive integer $n$ s.t. $a$ is coprime to $n$, and $\varphi(n)$ is the number of positive integers ($\leq n$) that are coprime to $n$, then$$a^{\varphi(n)}\equiv1\text{ (mod n)}$$ \ No newline at end of file diff --git a/content/Fermat's Little Theorem.md b/content/Fermat's Little Theorem.md new file mode 100644 index 0000000..3863f65 --- /dev/null +++ b/content/Fermat's Little Theorem.md @@ -0,0 +1,5 @@ +AKA Fermat's remainder theorem + +If $p$ is a prime number and $a$ is an integer not divisible by $p$ ($p\nmid a$), then $a$ raised to the power $p-1$ is congruent to $1$ modulo $p$. +$$a^p\equiv a \text{ (mod p)}\Rightarrow a^{p-1}\equiv1\text{ (mod p)}$$ +Also expressed as:$$p\mid a^p-a.$$Provable by [[Eurler's Theorem]]. \ No newline at end of file diff --git a/content/Groups.md b/content/Groups.md new file mode 100644 index 0000000..6a80e25 --- /dev/null +++ b/content/Groups.md @@ -0,0 +1,15 @@ +A group $G$ is a set algebraic structure with the binary operation $*$ that combines two elements $a,b$ in the set to produce a third element $a*b$ in the set. The operation has the following properties: +1. *Closure* — $a*b=c\in G$ +2. *Associative* — $(a*b)*c=a*(b*c)$ +3. *Existence of Identity element* — $a*0=0*a=a$ +4. *Existence of inverse element for every element of set* — $a*b=0$ +5. *Commutativity (only Abelian groups)* — $a*b=b*a$ + +Examples +- $Z$ is a group under addition defined as $(Z,+)$ +- $(Z/nZ)^\times$ is a finite group under multiplication +- Equilateral triangles for non-abelian group of order 6 under symmetry +- Invertible $n\times n$ for a non-abelian group under multiplication +\*need to explain last two + +A subset of $G$ is a [[subgroup]] of $G$ if the members of subset from a group with respect to the group operation in $G$. \ No newline at end of file diff --git a/content/Miller-Rabin primality test.md b/content/Miller-Rabin primality test.md new file mode 100644 index 0000000..3afeb80 --- /dev/null +++ b/content/Miller-Rabin primality test.md @@ -0,0 +1,71 @@ +--- +id: 1725614892-miller-rabin-primality-test +aliases: + - Miller-Rabin primality test +tags: [] +--- + +# Miller-Rabin primality test +- Probabilistic algorithm used to determine wheter a given number is prime. +- Particularly efficient for large numbers. + +1. Concept: + - For a prime number p, the equation a^(p-1) ≡ 1 (mod p) holds for all a coprime to p ([[Fermat's Little Theorem]]). + - Miller-Rabin extends this idea by considering how a number reaches 1 when repeatedly squared. + +2. Algorithm steps: + a. Express n-1 as (2^s) * d, where d is odd. + b. Choose a random base a (2 < a < n-2). + c. Compute x = a^d mod n. + d. If x = 1 or x = n-1, the number might be prime. + e. Square x up to s-1 times. If we ever get n-1, the number might be prime. + f. If we never get n-1 in step e, the number is definitely composite. + g. Repeat with different bases for higher confidence. + +## Rust Implementation +```rust +fn miller_rabin(n: u64) -> bool { + let witnesses = [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37]; + for &a in witnesses.iter() { + if n == a { + return true; + } + + if !witness(a, n) { + return false; + } + } + true +} +``` +- This function tests the number against a fixed set of "witnesses". +- If the number fails the test for any witness, it's composite. +- If it passes for all witnesses, it's probably prime. + +```rust +fn witness(a: u64, n: u64) -> bool { + let mut t = n - 1; + let mut s = 0; + + while t % 2 == 0 { + t /= 2; + s += 1; + } + + let mut x = mod_pow(a, t, n); + if x == 1 || x == n - 1 { + return true; + } + + for _ in 0..s-1 { + x = mod_mul(x, x, n); + if x == n - 1 { + return true; + } + } + false +} +``` +- This function performs the actual Miller-Rabin test for a single witness. +- It first decomposes n-1 into (2^s) * t. +- Then it computes a^t mod n and checks for the conditions that indicate primality. diff --git a/content/Modular exponentiation.md b/content/Modular exponentiation.md new file mode 100644 index 0000000..0758b84 --- /dev/null +++ b/content/Modular exponentiation.md @@ -0,0 +1,56 @@ +--- +id: 1725615525-modular-exponentiation +aliases: + - Modular exponentiation +tags: [] +--- + +# Modular exponentiation +Efficient algorithm to calculate (base^exp) % modulus. + +## Rust Implementation +```rust +fn mod_pow(mut base: u64, mut exp: u64, modulus: u64) -> u64 { + if modulus == 1 { + return 0; + } + + let mut result = 1; + base %= modulus; + while exp > 0 { + if exp % 2 == 1 { + result = mod_mul(result, base, modulus); + } + + exp >>= 1; + base = mod_mul(base, base, modulus); + } + result +} + +fn mod_mul(a: u64, b: u64, m: u64) -> u64 { + ((a as u128 * b as u128) % m as u128) as u64 +} +``` +1. Function signature: + - Takes three `u64` parameters: `base`, `exp` (exponent), and `modulus` + - Returns a `u64` result + +2. Edge case handling: + - If `modulus` is 1, it returns 0 (as any number mod 1 is 0) + +3. Initialization: + - `result` is set to 1 (neutral element for multiplication) + - `base` is reduced modulo `modulus` to ensure it's smaller than `modulus` + +4. Main loop: + - Continues while `exp` is greater than 0 + - Uses the binary exponentiation algorithm: + - If the least significant bit of `exp` is 1, multiply `result` by `base` + - Divide `exp` by 2 (right shift by 1 bit) + - Square `base` + - All multiplications are done using modular arithmetic (via `mod_mul` function) + +5. Return the final `result` + +This algorithm is efficient because it reduces the number of multiplications needed from O(exp) to O(log(exp)). diff --git a/content/Monoid.md b/content/Monoid.md new file mode 100644 index 0000000..9a5a184 --- /dev/null +++ b/content/Monoid.md @@ -0,0 +1,5 @@ +A set $S$ with binary operation $S\times S\rightarrow S$, denoted as $*$, is a monoid if it satisfies the following two axioms: +**Associativity** +For all $a,b$ and $c$ in $S$, the equation $(a*b)*c=a*(b*c)$ holds. +**Identity Element** +There exists an element $e$ in $S$ s.t. for every element $a$ in $S$, the equalities $e*a=a$ and $a*e=a$ hold. \ No newline at end of file diff --git a/content/RSA.md b/content/RSA.md new file mode 100644 index 0000000..288956e --- /dev/null +++ b/content/RSA.md @@ -0,0 +1,181 @@ +--- +id: RSA +aliases: [] +tags: [] +--- + +[Implementation Overview](https://link.springer.com/chapter/10.1007/978-3-319-21936-3_15) + +# Basic Implementation Steps +1. Generate two prime numbers ($p$ and $q$) +2. Calculate n = p * q +3. Calculate the [[totient]] φ(n) = (p-1) * (q-1) +4. Choose a public exponent $e$ (usually 65537) +5. Calculate the private exponent $d$ using the [[modular multiplicative inverse]] +6. Implement encryption: $c = m^e mod n$ +7. Implement decryption: $m = c^d mod n$ + +## Rust Implementation +```rust +use rand::Rng; + +fn is_prime(n: u64) -> bool { + if n <= 1 { + return false; + } + + if n <= 3 { + return true; + } + + if n % 2 == 0 || n % 3 == 0 { + return false; + } + + let limit = (n as f64).sqrt() as u64; + let mut i = 5; + while i <= limit { + if n % i == 0 || n % (i + 2) == 0 { + return false; + } + i += 6; + } + + if n < 2_u64.pow(32) { + return true; + } + + miller_rabin(n) +} + +fn miller_rabin(n: u64) -> bool { + let witnesses = [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37]; + for &a in witnesses.iter() { + if n == a { + return true; + } + + if !witness(a, n) { + return false; + } + } + true +} + +fn witness(a: u64, n: u64) -> bool { + let mut t = n - 1; + let mut s = 0; + + while t % 2 == 0 { + t /= 2; + s += 1; + } + + let mut x = mod_pow(a, t, n); + if x == 1 || x == n - 1 { + return true; + } + + for _ in 0..s - 1 { + x = mod_mul(x, x, n); + if x == n - 1 { + return true; + } + } + false +} + +fn mod_pow(mut base: u64, mut exp: u64, modulus: u64) -> u64 { + if modulus == 1 { + return 0; + } + + let mut result = 1; + base %= modulus; + while exp > 0 { + if exp % 2 == 1 { + result = mod_mul(result, base, modulus); + } + + exp >>= 1; + base = mod_mul(base, base, modulus); + } + result +} + +fn mod_mul(a: u64, b: u64, m: u64) -> u64 { + ((a as u128 * b as u128) % m as u128) as u64 +} + +fn generate_prime(min: u64, max: u64) -> u64 { + let mut rng = rand::thread_rng(); + loop { + let n = rng.gen_range(min..=max); + if is_prime(n) { + return n; + } + } +} + +fn gcd(a: u64, b: u64) -> u64 { + if b == 0 { + a + } else { + gcd(b, a % b) + } +} + +fn mod_inverse(a: u64, m: u64) -> Option { + for i in 1..m { + if (a * i) % m == 1 { + return Some(i); + } + } + Nne +} + +fn generate_keys() -> ((u64, u64), (u64, u64)) { + let p = generate_prime(100, 1000); + let q = generate_prime(100, 1000); + let n = p * q; + let phi = (p - 1) * (q - 1); + + let mut e = 65537; // Common choice for e + while gcd(e, phi) != 1 { + e += 2; + } + + let d = mod_inverse(e, phi).unwrap(); + + ((e, n), (d, n)) // ((public_key), (private_key)) +} + +fn encrypt(message: u64, public_key: (u64, u64)) -> u64 { + let (e, n) = public_key; + mod_pow(message, e, n) +} + +fn decrypt(ciphertext: u64, private_key: (u64, u64)) -> u64 { + let (d, n) = private_key; + mod_pow(ciphertext, d, n) +} + +fn main() { + let (public_key, private_key) = generate_keys(); + println!("Public Key (e, n): {:?}", public_key); + println!("Private Key (d, n): {:?}", private_key); + + let message = 42; + println!("Original Message: {}", message); + + let encrypted = encrypt(message, public_key); + println!("Encrypted: {}", encrypted); + + let decrypted = decrypt(encrypted, private_key); + println!("Decrypted: {}", decrypted); +} +``` + +### Notes +- [[Miller-Rabin primality test]] for numbers larger than 2^32 +- [[Modular exponentiation]] to calculate (base^exp) % modulus diff --git a/content/Week 1.md b/content/Week 1.md new file mode 100644 index 0000000..d79d0e8 --- /dev/null +++ b/content/Week 1.md @@ -0,0 +1,7 @@ +# Key Ideas +- [[Groups]], [[subgroup|subgroups]], [[rings]], [[fields]] +- [[Finite Fields]] +- Euler's Theorem, [[Fermat's Lxxxxxittle Theorem]] +- Chinese Remainder Theorem +- Primality Testing +- [[RSAx]] \ No newline at end of file diff --git a/content/extended Euclidean algorithm.md b/content/extended Euclidean algorithm.md new file mode 100644 index 0000000..e967fb5 --- /dev/null +++ b/content/extended Euclidean algorithm.md @@ -0,0 +1,64 @@ +--- +id: 1725556992-extended-euclidean-algorithm +aliases: + - extended Euclidean algorithm +tags: [] +--- + +# extended Euclidean algorithm +Extension of [[Euclidean algorithm|standard Euclidean algorithm]] for +finding the GCD of two numbers. Particularly useful in number theory and +cryptography. + +1. Purpose: + - Find the GCD of two numbers a and b + - Express the GCD as a linear combination of a and b: gcd(a,b) = ax + by + +2. Algorithm steps: + 1. Initialize variables: + r0 = a, r1 = b + s0 = 1, s1 = 0 + t0 = 0, t1 = 1 + 2. While r1 ≠ 0: + - Calculate quotient q = r0 / r1 + - Update remainders: r2 = r0 - q * r1 + - Update coefficients: s2 = s0 - q * s1, t2 = t0 - q * t1 + - Shift values: r0 = r1, r1 = r2, s0 = s1, s1 = s2, t0 = t1, t1 = t2 + 3. When the algorithm terminates, r0 is the GCD, and s0 and t0 are the coefficients + +## Rust Implementation +```rust +fn extended_gcd(a: i64, b: i64) -> (i64, i64, i64) { let mut r0 = a; let +mut r1 = b; let mut s0 = 1; let mut s1 = 0; let mut t0 = 0; let mut t1 += 1; + + while r1 != 0 { + let q = r0 / r1; + let r2 = r0 - q * r1; + let s2 = s0 - q * s1; + let t2 = t0 - q * t1; + + r0 = r1; r1 = r2; + s0 = s1; s1 = s2; + t0 = t1; t1 = t2; + } + + // Return (gcd, x, y) such that ax + by = gcd + (r0, s0, t0) +} + +fn main() { + let a = 48; + let b = 18; + let (gcd, x, y) = extended_gcd(a, b); + + println!("GCD of {} and {} is {}", a, b, gcd); + println!("Coefficients: x = {}, y = {}", x, y); + println!("Verification: {}*{} + {}*{} = {}", a, x, b, y, gcd); +} +``` + +This implementation: +1. Finds the GCD of two numbers +2. Calculates the coefficients x and y +3. Verifies that ax + by = gcd diff --git a/content/fields.md b/content/fields.md new file mode 100644 index 0000000..a69c47a --- /dev/null +++ b/content/fields.md @@ -0,0 +1,11 @@ +Algebraic structures with two binary operations $F(+,*)$ s.t.: +- [[Abelian group]] under $+$ +- Non-zero numbers $F-0$ form abelian group under $*$ +- Multiplicative distribution over $+$ +> [!note] +> Fields can also be defined as commutative ring $(R,+,*)$ with existence of inverse under $*$. Thus, every field can be classified as a [[rings|ring]]. + +Examples: +- $Q,R,C$ (set of rational, real, and complex numbers) are all fields +- $Z$ is not a field +- $Z/nZ$ forms a finite field under modulo addition and multiplication \ No newline at end of file diff --git a/content/modular multiplicative inverse.md b/content/modular multiplicative inverse.md new file mode 100644 index 0000000..7b5bc1c --- /dev/null +++ b/content/modular multiplicative inverse.md @@ -0,0 +1,67 @@ +--- +id: 1725555801-modular-multiplicative-inverse +aliases: + - modular multiplicative inverse +tags: [] +--- + +# Modular multiplicative inverse +1. Definition: + For two numbers 'a' and 'm', the modular multiplicative inverse of 'a' modulo 'm' is a number 'b' such that: + + (a * b) % m = 1 + + In other words, 'b' is the number that when multiplied by 'a', gives a remainder of 1 when divided by 'm'. + +2. Existence: + The modular multiplicative inverse of 'a' modulo 'm' exists if and only if 'a' and 'm' are coprime (their greatest common divisor is 1). + +3. Usage in [[RSA]]: + In the context of RSA, we use the modular multiplicative inverse to calculate the private key 'd' given the public exponent 'e' and the totient φ(n). We need to find 'd' such that: + + (e * d) % φ(n) = 1 + +4. Calculation: + The most common way to calculate the modular multiplicative inverse is using the [[extended Euclidean algorithm]]. + +## Rust Implementation +```rust +use num_bigint::BigUint; +use num_traits::{Zero, One}; + +fn mod_inverse(a: &BigUint, m: &BigUint) -> Option { + let mut t = BigUint::zero(); + let mut newt = BigUint::one(); + let mut r = m.clone(); + let mut newr = a.clone(); + + while !newr.is_zero() { + let quotient = &r / &newr; + t = std::mem::replace(&mut newt, t - "ient * &newt); + r = std::mem::replace(&mut newr, r - "ient * &newr); + } + + if r > BigUint::one() { + None // Modular inverse doesn't exist + } else if t < BigUint::zero() { + Some(t + m) + } else { + Some(t) + } +} + +fn main() { + let a = BigUint::from(3u32); + let m = BigUint::from(11u32); + + if let Some(inverse) = mod_inverse(&a, &m) { + println!("The modular multiplicative inverse of {} modulo {} is {}", a, m, inverse); + // This should print: The modular multiplicative inverse of 3 modulo 11 is 4 + // Because (3 * 4) % 11 = 1 + } else { + println!("Modular inverse doesn't exist"); + } +} +``` + +This implementation uses the [[extended Euclidean algorithm]] to find the modular multiplicative inverse. This works for all cases where the inverse exists. diff --git a/content/rings.md b/content/rings.md new file mode 100644 index 0000000..0f12579 --- /dev/null +++ b/content/rings.md @@ -0,0 +1,9 @@ +Algebraic structures with two binary operators $R(+,*)$ satisfying the following properties: +- [[Abelian group]] under $+$ +- [[Monoid]] under $*$ +- Distributive with respect to $*$ + +Examples: +- $Z/nZ$ form a ring +- A polynomial with integer coefficients: $Z[x]$ satisfy ring axioms +\*understand the examples better \ No newline at end of file diff --git a/content/subgroup.md b/content/subgroup.md new file mode 100644 index 0000000..8c047e7 --- /dev/null +++ b/content/subgroup.md @@ -0,0 +1,7 @@ +A group $G$ under binary operation $*$, a subset of $H$ of $G$ is a *subgroup* of $G$ if $H$ also forms a group under operation $*$. Precisely, $H$ is a subgroup of $G$ if the restriction of $*$ to $H\times H$ is a group operation on $H$, denoted as $H\leq G$. + +The *trivial subgroup* of any group is the subgroup $\{e\}$ consisting of just the identity element. + +A *proper subgroup* of a group $G$ is a subgroup $H$ which is a *proper subset* of $G$ ($H\neq G$). + +\*add properties specific to subgroups \ No newline at end of file diff --git a/content/totient.md b/content/totient.md new file mode 100644 index 0000000..d8b49dd --- /dev/null +++ b/content/totient.md @@ -0,0 +1,22 @@ +--- +id: 1725554049-totient +aliases: + - totient +tags: [] +--- + +# Euler's totient function + +1. Definition: + For a positive integer n, the totient function φ(n) counts the number of integers between 1 and n that are coprime to n (i.e., their greatest common divisor with n is 1). + +2. Properties: + - For a prime number p, φ(p) = p - 1 + - The function is multiplicative: if a and b are coprime, then φ(ab) = φ(a) * φ(b) + +3. In RSA: + In the context of RSA, we use φ(n) where n = p * q (p and q are prime numbers) + φ(n) = φ(p) * φ(q) = (p - 1) * (q - 1) + +4. Importance: + The totient is crucial for generating the private key in RSA. It's used to find the [[modular multiplicative inverse]] of the public exponent.