Module: RSA::Math
- Extended by:
- Math
- Defined in:
- lib/rsa/math.rb
Overview
Mathematical helper functions for RSA.
Defined Under Namespace
Classes: ArithmeticError
Constant Summary collapse
- ONE =
BigDecimal('1')
Class Method Summary collapse
-
.coprime?(a, b) ⇒ Boolean
Returns ‘true` if the integer `a` is coprime (relatively prime) to integer `b`.
-
.egcd(a, b) ⇒ Array(Integer, Integer)
Returns the Bezout coefficients of the two nonzero integers ‘a` and `b` using the extended Euclidean algorithm.
-
.factorize(n) {|p, e| ... } ⇒ Enumerator
Yields the prime factorization of the nonzero integer ‘n`.
-
.gcd(a, b) ⇒ Integer
Returns the greatest common divisor (GCD) of the two integers ‘a` and `b`.
-
.log(n, b = nil) ⇒ Float
Returns the natural logarithm of ‘n`.
-
.log2(n) ⇒ Float
Returns the binary logarithm of ‘n`.
-
.log256(n) ⇒ Float
Returns the base-256 logarithm of ‘n`.
-
.modinv(b, m) ⇒ Integer
Returns the modular multiplicative inverse of the integer ‘b` modulo `m`, where `b <= m`.
-
.modpow(base, exponent, modulus) ⇒ Integer
Performs modular exponentiation in a memory-efficient manner.
-
.phi(n) ⇒ Integer
Returns the Euler totient for the positive integer ‘n`.
-
.prime?(n) ⇒ Boolean
Performs a primality test on the integer ‘n`, returning `true` if it is a prime.
-
.primes {|p| ... } ⇒ Enumerator
Yields an infinite pseudo-prime number sequence.
Class Method Details
.coprime?(a, b) ⇒ Boolean
Returns ‘true` if the integer `a` is coprime (relatively prime) to integer `b`.
101 102 103 |
# File 'lib/rsa/math.rb', line 101 def self.coprime?(a, b) gcd(a, b).equal?(1) end |
.egcd(a, b) ⇒ Array(Integer, Integer)
Returns the Bezout coefficients of the two nonzero integers ‘a` and `b` using the extended Euclidean algorithm.
142 143 144 145 146 147 148 149 |
# File 'lib/rsa/math.rb', line 142 def self.egcd(a, b) if a.modulo(b).zero? [0, 1] else x, y = egcd(b, a.modulo(b)) [y, x - y * a.div(b)] end end |
.factorize(n) {|p, e| ... } ⇒ Enumerator
Yields the prime factorization of the nonzero integer ‘n`.
48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 |
# File 'lib/rsa/math.rb', line 48 def self.factorize(n, &block) raise ZeroDivisionError if n.zero? if block_given? n = n.abs if n < 0 primes.find do |p| e = 0 while (q, r = n.divmod(p); r.zero?) n, e = q, e + 1 end yield p, e unless e.zero? n <= p end yield n, 1 if n > 1 end enum_for(:factorize, n) end |
.gcd(a, b) ⇒ Integer
Returns the greatest common divisor (GCD) of the two integers ‘a` and `b`. The GCD is the largest positive integer that divides both numbers without a remainder.
121 122 123 |
# File 'lib/rsa/math.rb', line 121 def self.gcd(a, b) a.gcd(b) end |
.log(n, b = nil) ⇒ Float
Returns the natural logarithm of ‘n`. If the optional argument `b` is given, it will be used as the base of the logarithm.
272 273 274 |
# File 'lib/rsa/math.rb', line 272 def self.log(n, b = nil) b ? ::Math.log(n, b) : ::Math.log(n) end |
.log2(n) ⇒ Float
Returns the binary logarithm of ‘n`.
240 241 242 |
# File 'lib/rsa/math.rb', line 240 def self.log2(n) ::Math.log2(n) end |
.log256(n) ⇒ Float
Returns the base-256 logarithm of ‘n`.
255 256 257 |
# File 'lib/rsa/math.rb', line 255 def self.log256(n) ::Math.log(n, 256) end |
.modinv(b, m) ⇒ Integer
Returns the modular multiplicative inverse of the integer ‘b` modulo `m`, where `b <= m`.
The running time of the used algorithm, the extended Euclidean algorithm, is on the order of O(log2 m).
170 171 172 173 174 175 176 177 |
# File 'lib/rsa/math.rb', line 170 def self.modinv(b, m) if m > 0 && coprime?(b, m) egcd(b, m).first.modulo(m) else raise ArithmeticError, "modulus #{m} is not positive" if m <= 0 raise ArithmeticError, "#{b} is not coprime to #{m}" end end |
.modpow(base, exponent, modulus) ⇒ Integer
Performs modular exponentiation in a memory-efficient manner.
This is equivalent to ‘base**exponent % modulus` but much faster for large exponents.
The running time of the used algorithm, the right-to-left binary method, is on the order of O(log exponent).
197 198 199 200 201 202 203 204 205 |
# File 'lib/rsa/math.rb', line 197 def self.modpow(base, exponent, modulus) result = 1 while exponent > 0 result = (base * result) % modulus unless (exponent & 1).zero? base = (base * base) % modulus exponent >>= 1 end result end |
.phi(n) ⇒ Integer
Returns the Euler totient for the positive integer ‘n`.
220 221 222 223 224 225 226 227 |
# File 'lib/rsa/math.rb', line 220 def self.phi(n) case when n < 0 then raise ArgumentError, "expected a positive integer, but got #{n}" when n < 2 then 1 # by convention when prime?(n) then n - 1 else factorize(n).inject(n) { |product, (p, e)| product * (ONE - (ONE / BigDecimal(p.to_s))) }.round.to_i end end |
.prime?(n) ⇒ Boolean
Performs a primality test on the integer ‘n`, returning `true` if it is a prime.
76 77 78 79 80 81 82 83 84 85 86 |
# File 'lib/rsa/math.rb', line 76 def self.prime?(n) case when n < 0 then prime?(n.abs) when n < 2 then false else primes do |p| q, r = n.divmod(p) return true if q < p return false if r.zero? end end end |
.primes {|p| ... } ⇒ Enumerator
Yields an infinite pseudo-prime number sequence.
This is a pseudo-prime generator that simply yields the initial values 2 and 3, followed by all positive integers that are not divisible by 2 or 3.
It works identically to ‘Prime::Generator23`, the Ruby 1.9 standard library’s default pseudo-prime generator implementation.
26 27 28 29 30 31 32 33 |
# File 'lib/rsa/math.rb', line 26 def self.primes(&block) if block_given? yield 2; yield 3; yield 5 prime, step = 5, 4 loop { yield prime += (step = 6 - step) } end enum_for(:primes) end |