Sha256: 5d629ad76761df7e13e9bb7d8f56e4b6e940c09774d2614014b87d8f86391314

Contents?: true

Size: 1.92 KB

Versions: 3

Compression:

Stored size: 1.92 KB

Contents

module Affine
  # The affine cipher for positive integers.  This algorithm is only defined
  # for positive integers, and many arguments have further restrictions.
  #
  # == Usage
  #
  #   @a = Affine::Cipher.new(2176782371, 65182241782, 123235151)
  #   ct = @a.encipher(14)
  #   14 == @a.decipher(ct)
  class Cipher

    # Cipher objects are used both for decryption and encryption.
    #
    # == Arguments
    # [+modulus+] specifies how many different plaintexts and ciphertexts
    #             are available.
    # [+a_key+] multiplied against the plaintext. <b>Must be coprime with
    #           +modulus+.</b>
    # [+b_key+] added to the multiplied plaintext.  No restrictions, but
    #           it's modulus math, so making it larger than +modulus+ is
    #           useless.
    def initialize(modulus, a_key, b_key)
      raise CoprimeError.new(modulus, a_key) if modulus.gcd(a_key) != 1
      @modulus = modulus
      @a_key = a_key
      @b_key = b_key
      @a_inv = extended_gcd(a_key, modulus)
    end

    # Encrypt one +plaintext+ into a +ciphertext+.
    def encipher(plaintext)
      raise RangeError.new(plaintext, @modulus) if plaintext > @modulus
      ((@a_key * plaintext) + @b_key) % @modulus
    end

    # Decrypt one +ciphertext+ into a +plaintext+.
    def decipher(ciphertext)
      raise RangeError.new(ciphertext, @modulus) if ciphertext > @modulus
      (@a_inv * (ciphertext - @b_key)) % @modulus
    end

    alias_method :encrypt, :encipher
    alias_method :decrypt, :decipher
    private
    # from http://snippets.dzone.com/posts/show/6074
    def extended_gcd(b,m,_recursion_depth=0)
      if b % m == 0
        temp = [0,1]
        return temp
      else
        temp = extended_gcd(m, b % m, _recursion_depth+1)
        temp2 = [temp[1], temp[0]-temp[1] * ((b/m).to_i)]
        if _recursion_depth == 0
          return temp2[0] % m
        else
          return temp2
        end
      end
    end
  end
end

Version data entries

3 entries across 3 versions & 2 rubygems

Version Path
bkerley-affine-0.2.0 lib/affine/cipher.rb
bkerley-affine-0.2.1 lib/affine/cipher.rb
affine-0.2.1 lib/affine/cipher.rb