{"id":28437796,"url":"https://github.com/moosesue/modular-inverses","last_synced_at":"2026-06-23T04:31:49.121Z","repository":{"id":290738775,"uuid":"975408397","full_name":"moosesue/Modular-inverses","owner":"moosesue","description":"Modular inverse discussion leading to single character RSA demo.","archived":false,"fork":false,"pushed_at":"2025-05-12T11:06:53.000Z","size":33,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-06-28T10:39:50.442Z","etag":null,"topics":["cryptography","modular-inverse","number-theory","rsa","rsa-algorithm","rsa-cryptography","rsa-decryption"],"latest_commit_sha":null,"homepage":"","language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/moosesue.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2025-04-30T09:08:55.000Z","updated_at":"2025-05-12T11:06:56.000Z","dependencies_parsed_at":null,"dependency_job_id":"71d56f3c-573e-41d9-9112-302c173cf0a9","html_url":"https://github.com/moosesue/Modular-inverses","commit_stats":null,"previous_names":["moosesue/modular_inverses"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/moosesue/Modular-inverses","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/moosesue%2FModular-inverses","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/moosesue%2FModular-inverses/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/moosesue%2FModular-inverses/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/moosesue%2FModular-inverses/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/moosesue","download_url":"https://codeload.github.com/moosesue/Modular-inverses/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/moosesue%2FModular-inverses/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34675970,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-23T02:00:07.161Z","response_time":65,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["cryptography","modular-inverse","number-theory","rsa","rsa-algorithm","rsa-cryptography","rsa-decryption"],"created_at":"2025-06-06T00:08:45.449Z","updated_at":"2026-06-23T04:31:49.115Z","avatar_url":"https://github.com/moosesue.png","language":"Rust","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Modular Inverses\n\nBézout’s identity, $a \\cdot x + b \\cdot y = \\gcd(a, b)$, is the basis for finding modular inverses.\nA modular inverse (or modular multiplicative inverse) is a number $x$ such that:\n$a \\cdot x\\equiv 1\\pmod{b}$.\n\nA modular inverse only exists if $\\gcd(a, b) = 1$.\nWhen this happens, $a$ and $b$ are said to be coprime (they share no common factors except 1).\nIf $\\gcd(a, b) = 1$, then the $x$ found from the Extended GCD algorithm is the modular inverse of $a$ modulo $b$.\n\n### Example:\n\nConsider finding the modular inverse of 28 modulo 29:\nSince 29 is prime, $\\gcd(28, 29) = 1$.\nUsing the Extended GCD algorithm, we find that $x = 1$.\n\nTherefore:\n\n$28 \\equiv 1 \\pmod{29}$. \nSo, 1 is the modular inverse of 28 modulo 29.\n\nIn Python we can write this as:\n```python\ndef modular_inverse(a: int, b: int) -\u003e int:\n    #We don't need y from extended_gcd as looking for ax = 1 (mod b)\n    gcd_inverse, x, _ = gcd_utils.extended_gcd(a, b, False)\n    if gcd_inverse != 1:\n        raise ValueError(f\"No modular inverse for {a} mod {b}\")\n    return x % b\n```\nAnd in Rust:\n```rust\nfn modular_inverse(a:i32, b:i32) -\u003e Result\u003ci32, String\u003e {\n    \n    //We don't need y from extended_gcd as looking for ax = 1 (mod b)\n    let (gcd_inverse, x, _y) = extended_gcd(a, b, false);\n    if gcd_inverse != 1{\n        return Err(format!(\"No modular inverse exists for {} mod {}\", a, b));\n    }\n    //ensures positive return instead of just x % b\n    //done automatically in Python but not in Rust\n    Ok((x % b + b) % b) \n}\n``` \n## Application in RSA (Rivest-Shamir-Adleman) cryptosystems.\n\nThe RSA algorithm uses modular inverses to generate key pairs using two prime numbers. For two prime numbers, $p$ and $q$, the product of these primes, $n$, is used to calculate an encryption key $e$ and decryption key $d$ such that $c = m$\u003csup\u003ee\u003c/sup\u003e mod $n$ and $m = c$ \u003csup\u003ed\u003c/sup\u003e mod $n$ for ciphertext $c$ and plaintext $m$.\n\n### Example:\n\nIf $p = 13$ and $q = 29$, then $n = 13 \\times 29 = 377$. \n\nEuler's totient function, $\\varphi(n)$, counts how many numbers there are coprime to $n$. As we need an encryption key, $e$, and decryption key, $d$, that satisfy $e \\cdot d \\equiv 1\\pmod{\\varphi(n)}$, we need to calculate $d$ and to do this we need to find $\\varphi(n)$.\n\n$$\n\\varphi(n)= (p-1)(q-1) = 12 \\times 28 = 336\n$$\n\nChoose an integer $e$ between 1 and 336 which must be coprime with 336. Let’s choose $e$ = 11, as 11 is prime. \n\nThe public key is (377,11).\n\nCalculate the inverse of $11 \\pmod{336}$. The inverse is 275.\n\nThe private key is (377,275).\n\nAllowing anyone to encrypt a message but keeping the decryption key secret is an example of asymmetric cryptography and is based on the fact that given only the encryption key and product of two large prime numbers, it is difficult to find the decryption key. The security of the algorithm depends on the size of the two primes chosen. \n\n### Example:\n\nSay we want to encrypt the number 5 using our public key (377,11). \n\nThe ciphertext, $c$, is found by using $5^{11} \\pmod{377}$. We can split this into indices where the result is bigger than 377 and evaluate it at each point to make things easier (and the numbers smaller!).\n\n$5^2 = 25$ (not bigger than 377 so $25 \\pmod{377}$ is still 25)\n$5^4 = 625 = 248 \\pmod{377}$\n$5^8 = 248^2 = 61504 \\pmod{377} = 320$ \n$5^{11} = 5^{8} \\times 5^{2} \\times 5$ (remember indices rules where indexes are added when multiplying).\n\nSo $5^{11} \\pmod{377} = (320 \\times 248 \\times 5) \\pmod{377} = 38 \\pmod{377}$.\n\nSo $c = 38$.\n\nTo decrypt and find the plaintext $m$, we would then use $38^{275} \\pmod{377}$.  \n(Recall that 275 is the modular inverse of 11 mod 336.)\n\nWe can implement a demo of using RSA to encrypt/decrypt a single character in Python:\n\n```python\ndef generate_keys(p:int, q:int) -\u003e tuple[int,int,int]:\n    #calculate n\n    n = p * q\n\n    #calculate Euler's totient\n    euler_totient = (p - 1)*(q - 1)\n\n    #public key (n,e)\n\n    #generate a suitable value e\n    for test_e in range(2,euler_totient):\n        gcd_euler = gcd_utils.standard_gcd(test_e, euler_totient)\n        if gcd_euler == 1:\n            e = test_e\n            break\n\n    #private key is (n,d)\n    d = mod.modular_inverse(e,euler_totient)\n\n    return n,e,d\ndef rsa_encrypt(m: int, e: int, n: int)-\u003e int:\n    #ciphertext = m**e mod n \n    return pow(m,e,n)\n\ndef rsa_decrypt(c: int, d: int,n: int)-\u003eint:\n    #plaintext = c**d mod n\n    return pow(c,d,n)\n```\nOr in Rust:\n```rust\npub fn generate_keys(p:i32, q:i32) -\u003e Result\u003c(i32,i32,i32),String\u003e{\n    //calculate n\n    let n = p * q;\n\n    //calculate Euler's totient\n    let euler_totient = (p - 1)*(q - 1);\n\n    let mut rng = rand::thread_rng();\n\n    //public key (n,e)\n    \n    //generate a suitable value e\n    let e;\n    loop {\n        let candidate_e = rng.gen_range(2..euler_totient);\n        if gcd_utils::standard_gcd(candidate_e, euler_totient) == 1 {\n            if candidate_e \u003c euler_totient{\n                e = candidate_e;\n                break;\n            }\n        }\n    }\n\n    //private key is (n,d)\n    let d = match modular_inverse::modular_inverse(e,euler_totient){\n        Ok(val) =\u003e val,\n        Err(err) =\u003e return Err(err),\n    };\n\n    Ok((n,e,d))\n     \n}\n\npub fn rsa_encrypt(m: u32, e: u32, n: u32)-\u003e BigUint{\n    //ciphertext = m**e mod n \n    let base = BigUint::from(m);\n    let exponent = BigUint::from(e);\n    let modulus = BigUint::from(n);\n\n    base.modpow(\u0026exponent, \u0026modulus)\n        \n       \n}\n\npub fn rsa_decrypt(c: BigUint, d: u32,n: u32)-\u003eBigUint{\n    //plaintext = c**d mod n\n    let exponent = BigUint::from(d);\n    let modulus = BigUint::from(n);\n\n    c.modpow(\u0026exponent, \u0026modulus)\n    \n}\n```\n\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmoosesue%2Fmodular-inverses","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmoosesue%2Fmodular-inverses","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmoosesue%2Fmodular-inverses/lists"}