Ticket #6841: trac_6841-shift-cipher.patch

File trac_6841-shift-cipher.patch, 100.0 KB (added by mvngu, 12 years ago)

based on Sage 4.1.2.alpha2

  • doc/en/reference/monoids.rst

    # HG changeset patch
    # User Minh Van Nguyen <nguyenminh2@gmail.com>
    # Date 1251613443 25200
    # Node ID 5d9b9378ee4ffe01f1caa3a334057f55c8ae3eba
    # Parent  7fc8b5794aca5e6bb3870659f305040e8f99cb00
    trac 6841: the shift cryptosystem
    
    diff -r 7fc8b5794aca -r 5d9b9378ee4f doc/en/reference/monoids.rst
    a b  
    1212   sage/monoids/free_monoid
    1313   sage/monoids/free_monoid_element
    1414   sage/monoids/free_abelian_monoid
    15    sage/monoids/free_abelian_monoid_element
    16  No newline at end of file
     15   sage/monoids/free_abelian_monoid_element
     16   sage/monoids/string_monoid_element
     17   sage/monoids/string_monoid
  • sage/crypto/all.py

    diff -r 7fc8b5794aca -r 5d9b9378ee4f sage/crypto/all.py
    a b  
    11from classical import (
    22     HillCryptosystem,
    33     SubstitutionCryptosystem,
     4     ShiftCryptosystem,
    45     TranspositionCryptosystem,
    56     VigenereCryptosystem)
    67
  • sage/crypto/cipher.py

    diff -r 7fc8b5794aca -r 5d9b9378ee4f sage/crypto/cipher.py
    a b  
    11"""
    2 Ciphers.
     2Ciphers
    33"""
    44
    55#*****************************************************************************
     
    3333    def __eq__(self, right):
    3434        return type(self) == type(right) and self._parent == right._parent and self._key == right._key
    3535
    36     def __repr__(self):
    37         return str(self._key)
     36    def _repr_(self):
     37        r"""
     38        Return the string representation of this cipher.
     39
     40        EXAMPLES::
     41
     42            sage: S = ShiftCryptosystem(AlphabeticStrings())
     43            sage: S(13)
     44            Shift cipher on Free alphabetic string monoid on A-Z
     45        """
     46        # return str(self._key)
     47        return "Cipher on %s" % self.parent().cipher_domain()
    3848
    3949    def key(self):
    4050        return self._key # was str(self._key)
  • sage/crypto/classical.py

    diff -r 7fc8b5794aca -r 5d9b9378ee4f sage/crypto/classical.py
    a b  
    1 """
     1r"""
    22Classical Cryptosystems
     3
     4A convenient user interface to various classical ciphers. These include:
     5
     6- Hill or matrix cipher; see :class:`HillCryptosystem`
     7- shift cipher; see :class:`ShiftCryptosystem`
     8- substitution cipher; see :class:`SubstitutionCryptosystem`
     9- transposition cipher; see :class:`TranspositionCryptosystem`
     10- Vigenere cipher; see :class:`VigenereCryptosystem`
     11
     12These classical cryptosystems support alphabets such as:
     13
     14- the capital letters of the English alphabet; see
     15  :func:`AlphabeticStrings() <sage.monoids.string_monoid.AlphabeticStrings>`
     16- the hexadecimal number system; see
     17  :func:`HexadecimalStrings() <sage.monoids.string_monoid.HexadecimalStrings>`
     18- the binary number system; see
     19  :func:`BinaryStrings() <sage.monoids.string_monoid.BinaryStrings>`
     20- the octal number system; see
     21  :func:`OctalStrings() <sage.monoids.string_monoid.OctalStrings>`
     22- the radix-64 number system; see
     23  :func:`Radix64Strings() <sage.monoids.string_monoid.Radix64Strings>`
     24
     25AUTHORS:
     26
     27- David Kohel (2007): initial version with the Hill, substitution,
     28  transposition, and Vigenere cryptosystems.
     29
     30- Minh Van Nguyen (2009-08): shift cipher
    331"""
    432
    533#*****************************************************************************
     
    1038#                  http://www.gnu.org/licenses/
    1139#*****************************************************************************
    1240
     41# TODO: check off this todo list:
     42# - methods for cryptanalysis of the shift cipher
     43# - implement the affine cipher
     44# - methods for cryptanalysis of the affine cipher
     45# - methods to cryptanalyze the Hill, substitution, transposition, and
     46#   Vigenere ciphers
     47
    1348from sage.monoids.string_monoid import StringMonoid_class, AlphabeticStringMonoid
    1449from sage.monoids.string_monoid_element import StringMonoidElement
    1550from sage.monoids.string_ops import strip_encoding
     
    2560from cryptosystem import SymmetricKeyCryptosystem
    2661from classical_cipher import (
    2762     HillCipher,
     63     ShiftCipher,
    2864     SubstitutionCipher,
    2965     TranspositionCipher,
    3066     VigenereCipher)
     
    6197        [2 2 3]
    6298        sage: e = E(A)
    6399        sage: e
    64         [1 0 1]
    65         [0 1 1]
    66         [2 2 3]
     100        Hill cipher on Free alphabetic string monoid on A-Z of block length 3
    67101        sage: e(S("LAMAISONBLANCHE"))
    68102        JYVKSKQPELAYKPV
    69103
     
    129163            [2 2 3]
    130164            sage: e = E(A)
    131165            sage: e
    132             [1 0 1]
    133             [0 1 1]
    134             [2 2 3]
     166            Hill cipher on Free alphabetic string monoid on A-Z of block length 3
    135167            sage: m = S("LAMAISONBLANCHE")
    136168            sage: e(m)
    137169            JYVKSKQPELAYKPV
     
    346378        e = self(A)
    347379        return e(M)
    348380
     381class ShiftCryptosystem(SymmetricKeyCryptosystem):
     382    r"""
     383    Create a shift cryptosystem.
     384
     385    Let `A = \{ a_0, a_1, a_2, \dots, a_{n-1} \}` be a non-empty alphabet
     386    consisting of `n` unique elements. Define a mapping
     387    `f : A \longrightarrow \ZZ/ n\ZZ` from the alphabet `A` to
     388    the set `\ZZ / n\ZZ` of integers modulo `n`, given by
     389    `f(a_i) = i`. Thus we can identify each element of the alphabet `A`
     390    with a unique integer `0 \leq i < n`. A key of the shift cipher is an
     391    integer `0 \leq k < n`. Therefore the key space is `\ZZ / n\ZZ`. Since
     392    we assume that `A` does not have repeated elements, the mapping
     393    `f : A \longrightarrow \ZZ/ n\ZZ` is bijective.
     394    Encryption works by moving along the alphabet by `k` positions, with
     395    wrap around. Decryption reverses the process by moving backwards by
     396    `k` positions, with wrap around. More generally, let `k` be a secret key,
     397    i.e. an element of the key space, and let `p` be a plaintext
     398    character and consequently `p \in \ZZ / n\ZZ`. Then the ciphertext
     399    character `c` corresponding to `p` is given by
     400
     401    .. MATH::
     402
     403        c \equiv p + k \pmod{n}
     404
     405    Similarly, given a ciphertext character `c \in \ZZ / n\ZZ` and a secret
     406    key `k`, we can recover the corresponding plaintext character as follows:
     407
     408    .. MATH::
     409
     410        p \equiv c - k \pmod{n}
     411
     412    Use the bijection `f : A \longrightarrow \ZZ/ n\ZZ` to convert `c`
     413    and `p` back to elements of the alphabet `A`. Currently, the following
     414    alphabets are supported for the shift cipher:
     415
     416    - capital letters of the English alphabet as implemented in
     417      :func:`AlphabeticStrings() <sage.monoids.string_monoid.AlphabeticStrings>`
     418
     419    - the alphabet consisting of the hexadecimal number system as
     420      implemented in
     421      :func:`HexadecimalStrings() <sage.monoids.string_monoid.HexadecimalStrings>`
     422
     423    - the alphabet consisting of the binary number system as implemented in
     424      :func:`BinaryStrings() <sage.monoids.string_monoid.BinaryStrings>`
     425
     426    EXAMPLES:
     427
     428    Some examples illustrating encryption and decryption over various
     429    alphabets. Here is an example over the upper-case letters of the English
     430    alphabet::
     431
     432        sage: S = ShiftCryptosystem(AlphabeticStrings()); S
     433        Shift cryptosystem on Free alphabetic string monoid on A-Z
     434        sage: P = S.encoding("The shift cryptosystem generalizes the Caesar cipher.")
     435        sage: P
     436        THESHIFTCRYPTOSYSTEMGENERALIZESTHECAESARCIPHER
     437        sage: K = 7
     438        sage: C = S.enciphering(K, P); C
     439        AOLZOPMAJYFWAVZFZALTNLULYHSPGLZAOLJHLZHYJPWOLY
     440        sage: S.deciphering(K, C)
     441        THESHIFTCRYPTOSYSTEMGENERALIZESTHECAESARCIPHER
     442        sage: S.deciphering(K, C) == P
     443        True
     444
     445    The previous example can also be done as follows::
     446
     447        sage: S = ShiftCryptosystem(AlphabeticStrings())
     448        sage: P = S.encoding("The shift cryptosystem generalizes the Caesar cipher.")
     449        sage: K = 7
     450        sage: E = S(K); E
     451        Shift cipher on Free alphabetic string monoid on A-Z
     452        sage: C = E(P); C
     453        AOLZOPMAJYFWAVZFZALTNLULYHSPGLZAOLJHLZHYJPWOLY
     454        sage: D = S(S.inverse_key(K)); D
     455        Shift cipher on Free alphabetic string monoid on A-Z
     456        sage: D(C) == P
     457        True
     458        sage: D(C) == P == D(E(P))
     459        True
     460
     461    Over the hexadecimal number system::
     462
     463        sage: S = ShiftCryptosystem(HexadecimalStrings()); S
     464        Shift cryptosystem on Free hexadecimal string monoid
     465        sage: P = S.encoding("Encryption & decryption shifts along the alphabet."); P
     466        456e6372797074696f6e20262064656372797074696f6e2073686966747320616c6f6e672074686520616c7068616265742e
     467        sage: K = 5
     468        sage: C = S.enciphering(K, P); C
     469        9ab3b8c7cec5c9beb4b3757b75b9bab8c7cec5c9beb4b375c8bdbebbc9c875b6b1b4b3bc75c9bdba75b6b1c5bdb6b7bac973
     470        sage: S.deciphering(K, C)
     471        456e6372797074696f6e20262064656372797074696f6e2073686966747320616c6f6e672074686520616c7068616265742e
     472        sage: S.deciphering(K, C) == P
     473        True
     474
     475    And over the binary number system::
     476
     477        sage: S = ShiftCryptosystem(BinaryStrings()); S
     478        Shift cryptosystem on Free binary string monoid
     479        sage: P = S.encoding("The binary alphabet is very insecure."); P
     480        01010100011010000110010100100000011000100110100101101110011000010111001001111001001000000110000101101100011100000110100001100001011000100110010101110100001000000110100101110011001000000111011001100101011100100111100100100000011010010110111001110011011001010110001101110101011100100110010100101110
     481        sage: K = 1
     482        sage: C = S.enciphering(K, P); C
     483        10101011100101111001101011011111100111011001011010010001100111101000110110000110110111111001111010010011100011111001011110011110100111011001101010001011110111111001011010001100110111111000100110011010100011011000011011011111100101101001000110001100100110101001110010001010100011011001101011010001
     484        sage: S.deciphering(K, C)
     485        01010100011010000110010100100000011000100110100101101110011000010111001001111001001000000110000101101100011100000110100001100001011000100110010101110100001000000110100101110011001000000111011001100101011100100111100100100000011010010110111001110011011001010110001101110101011100100110010100101110
     486        sage: S.deciphering(K, C) == P
     487        True
     488
     489    A shift cryptosystem with key `k = 3` is commonly referred to as the
     490    Caesar cipher. Create a Caesar cipher over the upper-case letters of the
     491    English alphabet::
     492
     493        sage: caesar = ShiftCryptosystem(AlphabeticStrings())
     494        sage: K = 3
     495        sage: P = caesar.encoding("abcdef"); P
     496        ABCDEF
     497        sage: C = caesar.enciphering(K, P); C
     498        DEFGHI
     499        sage: caesar.deciphering(K, C) == P
     500        True
     501
     502    Generate a random key for encryption and decryption::
     503
     504        sage: S = ShiftCryptosystem(AlphabeticStrings())
     505        sage: P = S.encoding("Shift cipher with a random key.")
     506        sage: K = S.random_key()
     507        sage: C = S.enciphering(K, P)
     508        sage: S.deciphering(K, C) == P
     509        True
     510
     511    Decrypting with the key ``K`` is equivalent to encrypting with its
     512    corresponding inverse key::
     513
     514        sage: S.enciphering(S.inverse_key(K), C) == P
     515        True
     516
     517    TESTS:
     518
     519    Currently, the octal number system is not supported as an alphabet for
     520    this shift cryptosystem::
     521
     522        sage: ShiftCryptosystem(OctalStrings())
     523        Traceback (most recent call last):
     524        ...
     525        TypeError: A (= Free octal string monoid) is not supported as a cipher domain of this shift cryptosystem.
     526
     527    Nor is the radix-64 number system supported::
     528
     529        sage: ShiftCryptosystem(Radix64Strings())
     530        Traceback (most recent call last):
     531        ...
     532        TypeError: A (= Free radix 64 string monoid) is not supported as a cipher domain of this shift cryptosystem.
     533
     534    Testing of dumping and loading objects::
     535
     536        sage: SA = ShiftCryptosystem(AlphabeticStrings())
     537        sage: SA == loads(dumps(SA))
     538        True
     539        sage: SH = ShiftCryptosystem(HexadecimalStrings())
     540        sage: SH == loads(dumps(SH))
     541        True
     542        sage: SB = ShiftCryptosystem(BinaryStrings())
     543        sage: SB == loads(dumps(SB))
     544        True
     545
     546    The key ``K`` must satisfy the inequality `0 \leq K < n` with `n`
     547    being the size of the plaintext, ciphertext, and key spaces. For the
     548    shift cryptosystem, all these spaces are the same alphabet. This
     549    inequality must be satisfied for each of the supported alphabets.
     550    The capital letters of the English alphabet::
     551
     552        sage: S = ShiftCryptosystem(AlphabeticStrings())
     553        sage: S(2 + S.alphabet_size())
     554        Traceback (most recent call last):
     555        ...
     556        ValueError: K (=28) is outside the range of acceptable values for a key of this shift cryptosystem.
     557        sage: S(-2)
     558        Traceback (most recent call last):
     559        ...
     560        ValueError: K (=-2) is outside the range of acceptable values for a key of this shift cryptosystem.
     561
     562    The hexadecimal number system::
     563
     564        sage: S = ShiftCryptosystem(HexadecimalStrings())
     565        sage: S(1 + S.alphabet_size())
     566        Traceback (most recent call last):
     567        ...
     568        ValueError: K (=17) is outside the range of acceptable values for a key of this shift cryptosystem.
     569        sage: S(-1)
     570        Traceback (most recent call last):
     571        ...
     572        ValueError: K (=-1) is outside the range of acceptable values for a key of this shift cryptosystem.
     573
     574    The binary number system::
     575
     576        sage: S = ShiftCryptosystem(BinaryStrings())
     577        sage: S(1 + S.alphabet_size())
     578        Traceback (most recent call last):
     579        ...
     580        ValueError: K (=3) is outside the range of acceptable values for a key of this shift cryptosystem.
     581        sage: S(-2)
     582        Traceback (most recent call last):
     583        ...
     584        ValueError: K (=-2) is outside the range of acceptable values for a key of this shift cryptosystem.
     585    """
     586
     587    def __init__(self, A):
     588        r"""
     589        See ``ShiftCryptosystem`` for full documentation.
     590
     591        Create a shift cryptosystem defined over the alphabet ``A``.
     592
     593        INPUT:
     594
     595        - ``A`` -- a string monoid over some alphabet; this is the non-empty
     596          alphabet over which the plaintext and ciphertext spaces
     597          are defined.
     598
     599        OUTPUT:
     600
     601        - A shift cryptosystem over the alphabet ``A``.
     602
     603        EXAMPLES::
     604
     605            sage: S = ShiftCryptosystem(AlphabeticStrings()); S
     606            Shift cryptosystem on Free alphabetic string monoid on A-Z
     607            sage: P = S.encoding("The shift cryptosystem generalizes the Caesar cipher.")
     608            sage: P
     609            THESHIFTCRYPTOSYSTEMGENERALIZESTHECAESARCIPHER
     610            sage: K = 7
     611            sage: C = S.enciphering(K, P); C
     612            AOLZOPMAJYFWAVZFZALTNLULYHSPGLZAOLJHLZHYJPWOLY
     613            sage: S.deciphering(K, C)
     614            THESHIFTCRYPTOSYSTEMGENERALIZESTHECAESARCIPHER
     615            sage: S.deciphering(K, C) == P
     616            True
     617        """
     618        # sanity check
     619        from sage.monoids.string_monoid import ( AlphabeticStringMonoid,
     620                                                 BinaryStringMonoid,
     621                                                 HexadecimalStringMonoid )
     622        if not isinstance(A, ( AlphabeticStringMonoid,
     623                               BinaryStringMonoid,
     624                               HexadecimalStringMonoid )):
     625            raise TypeError("A (= %s) is not supported as a cipher domain of this shift cryptosystem." % A)
     626        # Initialize the shift cryptosystem with the plaintext, ciphertext,
     627        # and key spaces.
     628        SymmetricKeyCryptosystem.__init__(self, A, A, IntegerModRing(A.ngens()))
     629
     630    def __call__(self, K):
     631        r"""
     632        Create a shift cipher with key ``K``.
     633
     634        INPUT:
     635
     636        - ``K`` -- a secret key; this key is used for both encryption and
     637          decryption. For the shift cryptosystem whose plaintext and
     638          ciphertext spaces are `A`, a key is any integer `k` such that
     639          `0 \leq k < n` where `n` is the size or cardinality of the set
     640          `A`.
     641
     642        OUTPUT:
     643
     644        - A shift cipher with secret key ``K``.
     645
     646        EXAMPLES::
     647
     648            sage: S = ShiftCryptosystem(AlphabeticStrings())
     649            sage: P = S.encoding("Shifting sand."); P
     650            SHIFTINGSAND
     651            sage: K = 3
     652            sage: E = S(K); E
     653            Shift cipher on Free alphabetic string monoid on A-Z
     654            sage: E(P)
     655            VKLIWLQJVDQG
     656            sage: D = S(S.inverse_key(K)); D
     657            Shift cipher on Free alphabetic string monoid on A-Z
     658            sage: D(E(P))
     659            SHIFTINGSAND
     660
     661        TESTS:
     662
     663        The key ``K`` must satisfy the inequality `0 \leq K < n` with `n`
     664        being the size of the plaintext, ciphertext, and key spaces. For the
     665        shift cryptosystem, all these spaces are the same alphabet. This
     666        inequality must be satisfied for each of the supported alphabets.
     667        The capital letters of the English alphabet::
     668
     669            sage: S = ShiftCryptosystem(AlphabeticStrings())
     670            sage: S(2 + S.alphabet_size())
     671            Traceback (most recent call last):
     672            ...
     673            ValueError: K (=28) is outside the range of acceptable values for a key of this shift cryptosystem.
     674            sage: S(-2)
     675            Traceback (most recent call last):
     676            ...
     677            ValueError: K (=-2) is outside the range of acceptable values for a key of this shift cryptosystem.
     678
     679        The hexadecimal number system::
     680
     681            sage: S = ShiftCryptosystem(HexadecimalStrings())
     682            sage: S(1 + S.alphabet_size())
     683            Traceback (most recent call last):
     684            ...
     685            ValueError: K (=17) is outside the range of acceptable values for a key of this shift cryptosystem.
     686            sage: S(-1)
     687            Traceback (most recent call last):
     688            ...
     689            ValueError: K (=-1) is outside the range of acceptable values for a key of this shift cryptosystem.
     690
     691        The binary number system::
     692
     693            sage: S = ShiftCryptosystem(BinaryStrings())
     694            sage: S(1 + S.alphabet_size())
     695            Traceback (most recent call last):
     696            ...
     697            ValueError: K (=3) is outside the range of acceptable values for a key of this shift cryptosystem.
     698            sage: S(-2)
     699            Traceback (most recent call last):
     700            ...
     701            ValueError: K (=-2) is outside the range of acceptable values for a key of this shift cryptosystem.
     702        """
     703        # Sanity check: the key K must satisfy the inequality
     704        # 0 <= K < n with n being the size of the plaintext, ciphertext, and
     705        # key spaces. For the shift cryptosystem, all these spaces are the
     706        # same alphabet.
     707        if 0 <= K < self.alphabet_size():
     708            return ShiftCipher(self, K)
     709            # from sage.rings.integer_mod import Mod
     710            # return ShiftCipher(self, Mod(K, self.alphabet_size()).lift())
     711        else:
     712            raise ValueError("K (=%s) is outside the range of acceptable values for a key of this shift cryptosystem." % K)
     713
     714    def _repr_(self):
     715        r"""
     716        Return the string representation of ``self``.
     717
     718        EXAMPLES::
     719
     720            sage: ShiftCryptosystem(AlphabeticStrings())
     721            Shift cryptosystem on Free alphabetic string monoid on A-Z
     722            sage: ShiftCryptosystem(HexadecimalStrings())
     723            Shift cryptosystem on Free hexadecimal string monoid
     724            sage: ShiftCryptosystem(BinaryStrings())
     725            Shift cryptosystem on Free binary string monoid
     726        """
     727        # The shift cipher has the plaintext and ciphertext spaces defined
     728        # over the same non-empty alphabet. The cipher domain is the same
     729        # as the alphabet used for the plaintext and ciphertext spaces.
     730        return "Shift cryptosystem on %s" % self.cipher_domain()
     731
     732    def deciphering(self, K, C):
     733        r"""
     734        Decrypt the ciphertext ``C`` with the key ``K`` using shift cipher
     735        decryption.
     736
     737        INPUT:
     738
     739        - ``K`` -- a secret key; a key belonging to the key space of this
     740          shift cipher. This key is an integer `k` satisfying the inequality
     741          `0 \leq k < n`, where `n` is the size of the cipher domain.
     742
     743        - ``C`` -- a string of ciphertext; possibly an empty string.
     744          Characters in this string must be encoded using one of the
     745          supported alphabets. See the method :func:`encoding()`
     746          for more information.
     747
     748        OUTPUT:
     749
     750        - The plaintext corresponding to the ciphertext ``C``.
     751
     752        EXAMPLES:
     753
     754        Let's perform decryption over the supported alphabets. Here is
     755        decryption over the capital letters of the English alphabet::
     756
     757            sage: S = ShiftCryptosystem(AlphabeticStrings())
     758            sage: P = S.encoding("Stop shifting me."); P
     759            STOPSHIFTINGME
     760            sage: K = 13
     761            sage: C = S.enciphering(K, P); C
     762            FGBCFUVSGVATZR
     763            sage: S.deciphering(K, C) == P
     764            True
     765
     766        Decryption over the hexadecimal number system::
     767
     768            sage: S = ShiftCryptosystem(HexadecimalStrings())
     769            sage: P = S.encoding("Shift me now."); P
     770            5368696674206d65206e6f772e
     771            sage: K = 7
     772            sage: C = S.enciphering(K, P); C
     773            cadfd0ddeb97d4dc97d5d6ee95
     774            sage: S.deciphering(K, C) == P
     775            True
     776
     777        Decryption over the binary number system::
     778
     779            sage: S = ShiftCryptosystem(BinaryStrings())
     780            sage: P = S.encoding("OK, enough shifting."); P
     781            0100111101001011001011000010000001100101011011100110111101110101011001110110100000100000011100110110100001101001011001100111010001101001011011100110011100101110
     782            sage: K = 1
     783            sage: C = S.enciphering(K, P); C
     784            1011000010110100110100111101111110011010100100011001000010001010100110001001011111011111100011001001011110010110100110011000101110010110100100011001100011010001
     785            sage: S.deciphering(K, C) == P
     786            True
     787        """
     788        E = self(self.inverse_key(K))
     789        return E(C)
     790
     791    def enciphering(self, K, P):
     792        r"""
     793        Encrypt the plaintext ``P`` with the key ``K`` using shift cipher
     794        encryption.
     795
     796        INPUT:
     797
     798        - ``K`` -- a key belonging to the key space of this shift cipher.
     799          This key is an integer `k` satisfying the inequality
     800          `0 \leq k < n`, where `n` is the size of the cipher domain.
     801
     802        - ``P`` -- a string of plaintext; possibly an empty string.
     803          Characters in this string must be encoded using one of the
     804          supported alphabets. See the method :func:`encoding()` for more
     805          information.
     806
     807        OUTPUT:
     808
     809        - The ciphertext corresponding to the plaintext ``P``.
     810
     811        EXAMPLES:
     812
     813        Let's perform encryption over the supported alphabets. Here is
     814        encryption over the capital letters of the English alphabet::
     815
     816            sage: S = ShiftCryptosystem(AlphabeticStrings())
     817            sage: P = S.encoding("Shift your gear."); P
     818            SHIFTYOURGEAR
     819            sage: K = 3
     820            sage: S.enciphering(K, P)
     821            VKLIWBRXUJHDU
     822
     823        Encryption over the hexadecimal number system::
     824
     825            sage: S = ShiftCryptosystem(HexadecimalStrings())
     826            sage: P = S.encoding("Capitalize with the shift key."); P
     827            4361706974616c697a65207769746820746865207368696674206b65792e
     828            sage: K = 5
     829            sage: S.enciphering(K, P)
     830            98b6c5bec9b6b1becfba75ccbec9bd75c9bdba75c8bdbebbc975b0bace73
     831
     832        Encryption over the binary number system::
     833
     834            sage: S = ShiftCryptosystem(BinaryStrings())
     835            sage: P = S.encoding("Don't shift."); P
     836            010001000110111101101110001001110111010000100000011100110110100001101001011001100111010000101110
     837            sage: K = 1
     838            sage: S.enciphering(K, P)
     839            101110111001000010010001110110001000101111011111100011001001011110010110100110011000101111010001
     840        """
     841        E = self(K)
     842        return E(P)
     843
     844    def encoding(self, S):
     845        r"""
     846        The encoding of the string ``S`` over the string monoid of this
     847        shift cipher. For example, if the string monoid of this cryptosystem
     848        is
     849        :class:`AlphabeticStringMonoid <sage.monoids.string_monoid.AlphabeticStringMonoid>`,
     850        then the encoding of ``S`` would be its upper-case equivalent
     851        stripped of all non-alphabetic characters. The following alphabets
     852        are supported for the shift cipher:
     853
     854        - capital letters of the English alphabet as implemented in
     855          :func:`AlphabeticStrings() <sage.monoids.string_monoid.AlphabeticStrings>`
     856
     857        - the alphabet consisting of the hexadecimal number system as
     858          implemented in
     859          :func:`HexadecimalStrings() <sage.monoids.string_monoid.HexadecimalStrings>`
     860
     861        - the alphabet consisting of the binary number system as implemented in
     862          :func:`BinaryStrings() <sage.monoids.string_monoid.BinaryStrings>`
     863
     864        INPUT:
     865
     866        - ``S`` -- a string, possibly empty.
     867
     868        OUTPUT:
     869
     870        - The encoding of ``S`` over the string monoid of this cryptosystem.
     871          If ``S`` is an empty string, return an empty string.
     872
     873        EXAMPLES:
     874
     875        Encoding over the upper-case letters of the English alphabet::
     876
     877            sage: S = ShiftCryptosystem(AlphabeticStrings())
     878            sage: S.encoding("Shift cipher on capital letters of the English alphabet.")
     879            SHIFTCIPHERONCAPITALLETTERSOFTHEENGLISHALPHABET
     880
     881        Encoding over the binary system::
     882
     883            sage: S = ShiftCryptosystem(BinaryStrings())
     884            sage: S.encoding("Binary")
     885            010000100110100101101110011000010111001001111001
     886
     887        Encoding over the hexadecimal system::
     888
     889            sage: S = ShiftCryptosystem(HexadecimalStrings())
     890            sage: S.encoding("Over hexadecimal system.")
     891            4f7665722068657861646563696d616c2073797374656d2e
     892
     893        The argument ``S`` can be an empty string, in which case an empty
     894        string is returned::
     895
     896            sage: ShiftCryptosystem(AlphabeticStrings()).encoding("")
     897            <BLANKLINE>
     898            sage: ShiftCryptosystem(HexadecimalStrings()).encoding("")
     899            <BLANKLINE>
     900            sage: ShiftCryptosystem(BinaryStrings()).encoding("")
     901            <BLANKLINE>
     902        """
     903        D = self.cipher_domain()
     904        if isinstance(D, AlphabeticStringMonoid):
     905            return D(strip_encoding(S))
     906        try:
     907            return D.encoding(S)
     908        except:
     909            raise TypeError("Argument S = %s does not encode in the cipher domain" % S)
     910
     911    def inverse_key(self, K):
     912        r"""
     913        The inverse key corresponding to the key ``K``. For the shift cipher,
     914        the inverse key corresponding to ``K`` is `-K \bmod n`, where
     915        `n > 0` is the size of the cipher domain, i.e. the
     916        plaintext/ciphertext space. A key `k` of the shift cipher is an
     917        integer `0 \leq k < n`. The key `k = 0` has no effect on either the
     918        plaintext or the ciphertext.
     919
     920        INPUT:
     921
     922        - ``K`` -- a key for this shift cipher. This must be an integer `k`
     923          such that `0 \leq k < n`, where `n` is the size of the cipher domain.
     924
     925        OUTPUT:
     926
     927        - The inverse key corresponding to ``K``.
     928
     929        EXAMPLES:
     930
     931        Some random keys and their respective inverse keys::
     932
     933            sage: S = ShiftCryptosystem(AlphabeticStrings())
     934            sage: key = S.random_key(); key  # random
     935            2
     936            sage: S.inverse_key(key)         # random
     937            24
     938            sage: S = ShiftCryptosystem(HexadecimalStrings())
     939            sage: key = S.random_key(); key  # random
     940            12
     941            sage: S.inverse_key(key)         # random
     942            4
     943            sage: S = ShiftCryptosystem(BinaryStrings())
     944            sage: key = S.random_key(); key  # random
     945            1
     946            sage: S.inverse_key(key)         # random
     947            1
     948            sage: key = S.random_key(); key  # random
     949            0
     950            sage: S.inverse_key(key)         # random
     951            0
     952
     953        Regardless of the value of a key, the addition of the key and its
     954        inverse must be equal to the alphabet size. This relationship holds
     955        exactly when the value of the key is non-zero::
     956
     957            sage: S = ShiftCryptosystem(AlphabeticStrings())
     958            sage: K = S.random_key()
     959            sage: while K == 0:
     960            ...       K = S.random_key()
     961            ...
     962            sage: invK = S.inverse_key(K)
     963            sage: K + invK == S.alphabet_size()
     964            True
     965            sage: invK + K == S.alphabet_size()
     966            True
     967            sage: K = S.random_key()
     968            sage: while K != 0:
     969            ...       K = S.random_key()
     970            ...
     971            sage: invK = S.inverse_key(K)
     972            sage: K + invK != S.alphabet_size()
     973            True
     974            sage: K; invK
     975            0
     976            0
     977        """
     978        # Let A be the alphabet of this cryptosystem and let n be the number
     979        # of elements in A. If k is a key, then the corresponding inverse
     980        # key is -k mod n.
     981        return self.key_space()(-Integer(K)).lift()
     982
     983    def random_key(self):
     984        r"""
     985        Generate a random key within the key space of this shift cipher.
     986        The generated key is an integer `0 \leq k < n` with `n` being the
     987        size of the cipher domain. Thus there are `n` possible keys in the
     988        key space, which is the set `\ZZ / n\ZZ`. The key `k = 0` has no
     989        effect on either the plaintext or the ciphertext.
     990
     991        OUTPUT:
     992
     993        - A random key within the key space of this shift cryptosystem.
     994
     995        EXAMPLES::
     996
     997            sage: S = ShiftCryptosystem(AlphabeticStrings())
     998            sage: S.random_key()  # random
     999            18
     1000            sage: S = ShiftCryptosystem(BinaryStrings())
     1001            sage: S.random_key()  # random
     1002            0
     1003            sage: S = ShiftCryptosystem(HexadecimalStrings())
     1004            sage: S.random_key()  # random
     1005            5
     1006
     1007        Regardless of the value of a key, the addition of the key and its
     1008        inverse must be equal to the alphabet size. This relationship holds
     1009        exactly when the value of the key is non-zero::
     1010
     1011            sage: S = ShiftCryptosystem(AlphabeticStrings())
     1012            sage: K = S.random_key()
     1013            sage: while K == 0:
     1014            ...       K = S.random_key()
     1015            ...
     1016            sage: invK = S.inverse_key(K)
     1017            sage: K + invK == S.alphabet_size()
     1018            True
     1019            sage: invK + K == S.alphabet_size()
     1020            True
     1021            sage: K = S.random_key()
     1022            sage: while K != 0:
     1023            ...       K = S.random_key()
     1024            ...
     1025            sage: invK = S.inverse_key(K)
     1026            sage: K + invK != S.alphabet_size()
     1027            True
     1028            sage: K; invK
     1029            0
     1030            0
     1031        """
     1032        # Return a random element in ZZ/nZZ where n is the number of elements
     1033        # in the plaintext/ciphertext alphabet and key space.
     1034        from sage.misc.prandom import randint
     1035        return Integer(randint(0, self.alphabet_size() - 1))
     1036
    3491037class SubstitutionCryptosystem(SymmetricKeyCryptosystem):
    3501038    """
    3511039    Create a substitution cryptosystem.
     
    8501538        ABCDEFGHIJKLMN
    8511539        sage: e = E(K)
    8521540        sage: e
    853         ABCDEFGHIJKLMN
     1541        Cipher on Free alphabetic string monoid on A-Z
    8541542        sage: e(S("THECATINTHEHAT"))
    8551543        TIGFEYOUBQOSMG
    8561544
     
    8651553    def __init__(self, S, n):
    8661554        """
    8671555        See ``VigenereCryptosystem`` for full documentation.
    868        
     1556
    8691557        EXAMPLES::
    8701558
    8711559            sage: S = AlphabeticStrings()
     
    8941582            ABCDEFGHIJKLMN
    8951583            sage: e = E(K)
    8961584            sage: e
    897             ABCDEFGHIJKLMN
     1585            Cipher on Free alphabetic string monoid on A-Z
    8981586            sage: e(S("THECATINTHEHAT"))
    8991587            TIGFEYOUBQOSMG
    9001588        """
     
    10641752        """
    10651753        e = self(K)
    10661754        return e(M)
    1067 
  • sage/crypto/classical_cipher.py

    diff -r 7fc8b5794aca -r 5d9b9378ee4f sage/crypto/classical_cipher.py
    a b  
    11"""
    2 Classical Ciphers.
     2Classical Ciphers
    33"""
    44
    55#*****************************************************************************
     
    2121    def __init__(self, parent, key):
    2222        """
    2323        Create a Hill cipher.
    24        
     24
    2525        INPUT: Parent and key
    26        
     26
    2727        EXAMPLES::
    28        
     28
    2929            sage: S = AlphabeticStrings()
    3030            sage: E = HillCryptosystem(S,3)
    3131            sage: E
     
    3636            [1 0 1]
    3737            [0 1 1]
    3838            [2 2 3]
    39             sage: e = E(A)
    40             sage: e
    41             [1 0 1]
    42             [0 1 1]
    43             [2 2 3]
     39            sage: e = E(A); e
     40            Hill cipher on Free alphabetic string monoid on A-Z of block length 3
    4441            sage: e(S("LAMAISONBLANCHE"))
    4542            JYVKSKQPELAYKPV
    46        
     43
    4744        TESTS::
    48        
     45
    4946            sage: S = AlphabeticStrings()
    5047            sage: E = HillCryptosystem(S,3)
    5148            sage: E == loads(dumps(E))
     
    6562        if len(M) % m != 0:
    6663            raise TypeError, "The length of M (= %s) must be a multiple of %s." % (M, m )
    6764        Alph = list(S.alphabet())
    68         A = self.key() # A is an m x m matrix 
     65        A = self.key() # A is an m x m matrix
    6966        R = A.parent().base_ring()
    7067        V = FreeModule(R,m)
    7168        Mstr = str(M)
     
    7471            v = V([ Alph.index(Mstr[m*i+j]) for j in range(m) ])
    7572            C += (v * A).list()
    7673        return S([ k.lift() for k in C ])
    77        
     74
     75    def _repr_(self):
     76        r"""
     77        Return the string representation of this Hill cipher.
     78
     79        EXAMPLES::
     80
     81            sage: H = HillCryptosystem(AlphabeticStrings(), 3)
     82            sage: M = MatrixSpace(IntegerModRing(26), 3, 3)
     83            sage: A = M([[1,0,1], [0,1,1], [2,2,3]])
     84            sage: e = H(A); e
     85            Hill cipher on Free alphabetic string monoid on A-Z of block length 3
     86        """
     87        return "Hill cipher on %s of block length %s" % (
     88            self.parent().cipher_domain(), self.parent().block_length() )
     89
    7890    def inverse(self):
    7991        E = self.parent()
    8092        try:
     
    8395            raise ValueError, "Argument\n\n%s\n\nmust be an invertible cipher." % self
    8496        return E(B)
    8597
     98class ShiftCipher(SymmetricKeyCipher):
     99    r"""
     100    Shift cipher class. This is the class that does the actual work of
     101    encryption and decryption. Users should not directly instantiate or
     102    create objects of this class. Instead, functionalities of this class
     103    should be accessed via
     104    :class:`ShiftCryptosystem <sage.crypto.classical.ShiftCryptosystem>`
     105    as the latter provides a convenient user interface.
     106    """
     107    def __init__(self, parent, key):
     108        r"""
     109        Create a shift cipher.
     110
     111        INPUT:
     112
     113        - ``parent`` -- a ``ShiftCryptosystem`` object.
     114
     115        - ``key`` -- a secret key.
     116
     117        EXAMPLES::
     118
     119            sage: S = ShiftCryptosystem(AlphabeticStrings()); S
     120            Shift cryptosystem on Free alphabetic string monoid on A-Z
     121            sage: P = S.encoding("The shift cryptosystem generalizes the Caesar cipher.")
     122            sage: P
     123            THESHIFTCRYPTOSYSTEMGENERALIZESTHECAESARCIPHER
     124            sage: K = 7
     125            sage: C = S.enciphering(K, P); C
     126            AOLZOPMAJYFWAVZFZALTNLULYHSPGLZAOLJHLZHYJPWOLY
     127            sage: S.deciphering(K, C)
     128            THESHIFTCRYPTOSYSTEMGENERALIZESTHECAESARCIPHER
     129            sage: S.deciphering(K, C) == P
     130            True
     131        """
     132        SymmetricKeyCipher.__init__(self, parent, key)
     133
     134    def __eq__(self, other):
     135        r"""
     136        Comparing this ``ShiftCipher`` with ``other``. Two ``ShiftCipher``
     137        objects are the same if they are of the same type, have the same
     138        parent, and share the same secret key.
     139
     140        INPUT:
     141
     142        - ``other`` -- another object to compare with.
     143
     144        OUTPUT:
     145
     146        - ``True`` if ``self`` and ``other`` are the same ``ShiftCipher``
     147          object; ``False`` otherwise.
     148
     149        EXAMPLES::
     150
     151            sage: shift1 = ShiftCryptosystem(AlphabeticStrings())
     152            sage: shift2 = ShiftCryptosystem(AlphabeticStrings())
     153            sage: shift1 == shift2
     154            True
     155            sage: shift1 = ShiftCryptosystem(HexadecimalStrings())
     156            sage: shift2 = ShiftCryptosystem(BinaryStrings())
     157            sage: shift1 == shift2
     158            False
     159        """
     160        return type(self) == type(other) and self.parent() == other.parent() and self.key() == other.key()
     161
     162    def __call__(self, M):
     163        r"""
     164        Return the ciphertext (respectively, plaintext) corresponding to
     165        ``M``. This is the main place where encryption and decryption takes
     166        place.
     167
     168        INPUT:
     169
     170        - ``M`` -- a message to be encrypted or decrypted. This message must
     171          be encoded using the plaintext or ciphertext alphabet. The current
     172          behaviour is that the plaintext and ciphertext alphabets are the
     173          same alphabet.
     174
     175        OUTPUT:
     176
     177        - The ciphertext or plaintext corresponding to ``M``.
     178
     179        EXAMPLES:
     180
     181        These are indirect doctests. Functionalities of this class are
     182        usually invoked from
     183        :class:`ShiftCryptosystem <sage.crypto.classical.ShiftCryptosystem>`.
     184
     185        ::
     186
     187            sage: S = ShiftCryptosystem(AlphabeticStrings())
     188            sage: S.enciphering(12, S.encoding("Stop shifting me."))
     189            EFABETURFUZSYQ
     190            sage: S = ShiftCryptosystem(HexadecimalStrings())
     191            sage: S.enciphering(7, S.encoding("Shift me now."))
     192            cadfd0ddeb97d4dc97d5d6ee95
     193            sage: S = ShiftCryptosystem(BinaryStrings())
     194            sage: S.enciphering(1, S.encoding("OK, enough shifting."))
     195            1011000010110100110100111101111110011010100100011001000010001010100110001001011111011111100011001001011110010110100110011000101110010110100100011001100011010001
     196        """
     197        dom = self.domain()  # = plaintext_space = ciphertext_space
     198        if not isinstance(M, StringMonoidElement) and M.parent() == dom:
     199            raise TypeError("Argument M (= %s) must be a string in the plaintext/ciphertext space." % M)
     200        from sage.rings.integer_mod import Mod
     201        A = list(dom.alphabet())   # plaintext/ciphertext alphabet as a list
     202        N = self.domain().ngens()  # number of elements in this alphabet
     203        K = self.key()             # encryption/decryption key
     204        # Here, M is a message encoded within the ciphertext/plaintext
     205        # alphabet of this shift cryptosystem. The list A above is a list of
     206        # all elements of this alphabet, each element being associated with
     207        # an index 0 <= i < n, where n is the size of A. Now get the index
     208        # of each character in the message M, storing all these indices
     209        # in the index list I.
     210        # TODO: the following two lines are coded with clarity and
     211        # readability in mind. It is possible to remove the overhead of
     212        # doing a list comprehension to get the index associated with each
     213        # element of M. For example, the next two lines can be crammed into
     214        # one list comprehension as follows:
     215        # return dom([ A.index(A[Mod(A.index(str(i)) + K, N).lift()]) for i in M ])
     216        # But it performs badly compared to the following two lines.
     217        I = [A.index(str(e)) for e in M]
     218        # Perform encryption/decryption on the whole message M, returning
     219        # the result as a string encoded in the alphabet A.
     220        return dom([ A.index(A[Mod(i + K, N).lift()]) for i in I ])
     221
     222    def _repr_(self):
     223        r"""
     224        Return the string representation of this shift cipher.
     225
     226        EXAMPLES::
     227
     228            sage: S = ShiftCryptosystem(AlphabeticStrings())
     229            sage: S(3)
     230            Shift cipher on Free alphabetic string monoid on A-Z
     231            sage: S = ShiftCryptosystem(HexadecimalStrings())
     232            sage: S(5)
     233            Shift cipher on Free hexadecimal string monoid
     234            sage: S = ShiftCryptosystem(BinaryStrings())
     235            sage: S(1)
     236            Shift cipher on Free binary string monoid
     237        """
     238        # The shift cipher has the plaintext and ciphertext spaces defined
     239        # over the same non-empty alphabet. The cipher domain is the same
     240        # as the alphabet used for the plaintext and ciphertext spaces.
     241        return "Shift cipher on %s" % self.parent().cipher_domain()
     242
    86243class SubstitutionCipher(SymmetricKeyCipher):
    87244    """
    88245    Substitution cipher class
     
    90247    def __init__(self, parent, key):
    91248        """
    92249        Create a substitution cipher.
    93        
     250
    94251        INPUT: Parent and key
    95        
     252
    96253        EXAMPLES::
    97        
     254
    98255            sage: S = AlphabeticStrings()
    99256            sage: E = SubstitutionCryptosystem(S)
    100257            sage: E
     
    106263            sage: m = S("THECATINTHEHAT")
    107264            sage: e(m)
    108265            GSVXZGRMGSVSZG
    109        
     266
    110267        TESTS::
    111        
     268
    112269            sage: S = AlphabeticStrings()
    113270            sage: E = SubstitutionCryptosystem(S)
    114271            sage: E == loads(dumps(E))
     
    128285        I = [ A.index(K[i]) for i in range(len(K)) ]
    129286        Mstr = str(M)
    130287        return S([ I[A.index(Mstr[i])] for i in range(len(Mstr)) ])
    131        
     288
     289    def _repr_(self):
     290        r"""
     291        Return the string representation of this substitution cipher.
     292
     293        EXAMPLES::
     294
     295            sage: A = HexadecimalStrings(); S = SubstitutionCryptosystem(A)
     296            sage: K = A([16-i for i in xrange(16)]); S(K)
     297            Substitution cipher on Free hexadecimal string monoid
     298            sage: A = AlphabeticStrings(); S = SubstitutionCryptosystem(A)
     299            sage: K = A([26-i for i in xrange(26)]); S(K)
     300            Substitution cipher on Free alphabetic string monoid on A-Z
     301            sage: A = OctalStrings(); S = SubstitutionCryptosystem(A)
     302            sage: K = A([8-i for i in xrange(8)]); S(K)
     303            Substitution cipher on Free octal string monoid
     304            sage: A = BinaryStrings(); S = SubstitutionCryptosystem(A)
     305            sage: K = A([2-i for i in xrange(2)]); S(K)
     306            Substitution cipher on Free binary string monoid
     307            sage: A = Radix64Strings(); S = SubstitutionCryptosystem(A)
     308            sage: K = A([64-i for i in xrange(64)]); S(K)
     309            Substitution cipher on Free radix 64 string monoid
     310        """
     311        return "Substitution cipher on %s" % self.parent().cipher_domain()
     312
    132313    def inverse(self):
    133314        E = self.parent()
    134315        K = E.inverse_key(self.key())
     
    141322    def __init__(self, parent, key):
    142323        """
    143324        Create a transposition cipher.
    144        
     325
    145326        INPUT: Parent and key
    146        
     327
    147328        EXAMPLES::
    148        
     329
    149330            sage: S = AlphabeticStrings()
    150331            sage: E = TranspositionCryptosystem(S,14)
    151332            sage: E
     
    157338            sage: m = S("THECATINTHEHAT")
    158339            sage: e(m)
    159340            TAHEHTNITACEHT
    160        
     341
    161342        EXAMPLES::
    162        
     343
    163344            sage: S = AlphabeticStrings()
    164345            sage: E = TranspositionCryptosystem(S,15);
    165346            sage: m = S("THECATANDTHEHAT")
    166347            sage: G = E.key_space()
    167348            sage: G
    168349            Symmetric group of order 15! as a permutation group
    169             sage: g = G([ 3, 2, 1, 6, 5, 4, 9, 8, 7, 12, 11, 10, 15, 14, 13 ]) 
     350            sage: g = G([ 3, 2, 1, 6, 5, 4, 9, 8, 7, 12, 11, 10, 15, 14, 13 ])
    170351            sage: e = E(g)
    171352            sage: e(m)
    172353            EHTTACDNAEHTTAH
    173        
     354
    174355        TESTS::
    175        
     356
    176357            sage: S = AlphabeticStrings()
    177358            sage: E = TranspositionCryptosystem(S,14)
    178359            sage: E == loads(dumps(E))
     
    189370            raise TypeError, "Argument M (= %s) must be a string in the plaintext space." % M
    190371        if not mode == "ECB":
    191372            raise NotImplementedError, "Enciphering not implemented for mode (= %s) other than 'ECB'." % mode
    192         g = self.key() 
     373        g = self.key()
    193374        N = len(M)
    194375        m = self.parent().block_length()
    195376        if not N%m == 0:
     
    213394    def __init__(self, parent, key):
    214395        """
    215396        Create a Vigenere cipher.
    216        
     397
    217398        INPUT: Parent and key
    218        
     399
    219400        EXAMPLES::
    220        
     401
    221402            sage: S = AlphabeticStrings()
    222403            sage: E = VigenereCryptosystem(S,11)
    223404            sage: K = S("SHAKESPEARE")
     
    225406            sage: m = S("THECATINTHEHAT")
    226407            sage: e(m)
    227408            LOEMELXRTYIZHT
    228        
     409
    229410        TESTS::
    230        
     411
    231412            sage: S = AlphabeticStrings()
    232413            sage: E = VigenereCryptosystem(S,11)
    233414            sage: E == loads(dumps(E))
     
    241422            raise TypeError, "Argument M (= %s) must be a string in the plaintext space." % M
    242423        if not mode == "ECB":
    243424            raise NotImplementedError, "Enciphering not implemented for mode (= %s) other than 'ECB'." % mode
    244         K = self.key() 
     425        K = self.key()
    245426        m = self.parent().period()
    246427        n = S.ngens()
    247428        # This uses the internal structure of string monoids
    248         Melt = M._element_list 
    249         Kelt = K._element_list 
     429        Melt = M._element_list
     430        Kelt = K._element_list
    250431        return S([ (Melt[i]+Kelt[i%m])%n for i in range(len(M)) ])
    251432
    252433    def inverse(self):
  • sage/crypto/cryptosystem.py

    diff -r 7fc8b5794aca -r 5d9b9378ee4f sage/crypto/cryptosystem.py
    a b  
    1 """
    2 Cryptosystems.
     1r"""
     2Cryptosystems
     3
     4This module contains base classes for various cryptosystems, including
     5symmetric key and public-key cryptosystems. The classes defined in this
     6module should not be called directly. It is the responsibility of child
     7classes to implement specific cryptosystems. Take for example the
     8Hill or matrix cryptosystem as implemented in
     9:class:`HillCryptosystem <sage.crypto.classical.HillCryptosystem>`. It is a
     10symmetric key cipher so
     11:class:`HillCryptosystem <sage.crypto.classical.HillCryptosystem>` is a child
     12class of
     13:class:`SymmetricKeyCryptosystem <sage.crypto.cryptosystem.SymmetricKeyCryptosystem>`,
     14which in turn is a child class of
     15:class:`Cryptosystem <sage.crypto.cryptosystem.Cryptosystem>`. The following
     16diagram shows the inheritance relationship of particular cryptosystems::
     17
     18    Cryptosystem
     19    + SymmetricKeyCryptosystem
     20    | + HillCryptosystem
     21    | + LFSRCryptosystem
     22    | + ShiftCryptosystem
     23    | + ShrinkingGeneratorCryptosystem
     24    | + SubstitutionCryptosystem
     25    | + TranspositionCryptosystem
     26    | + VigenereCryptosystem
     27    + PublicKeyCryptosystem
    328"""
    429
    530#*****************************************************************************
     
    1439from sage.sets.set import Set_generic
    1540
    1641class Cryptosystem(parent_old.Parent, Set_generic):
    17       r"""
    18       A cryptosystem is a pair of maps
    19      
    20       .. math::
    21      
    22                  E : {\mathcal K} \rightarrow {\rm Hom}({\mathcal M},{\mathcal C})       
    23      
    24      
    25      
    26       .. math::
    27      
    28                  D : {\mathcal K} \rightarrow {\rm Hom}({\mathcal C},{\mathcal M})       
    29      
    30      
    31       where `{\mathcal K}` is the keyspace,
    32       `{\mathcal M}` is the plaintext or message space, and
    33       `{\mathcal C}` is the ciphertext space. In many instances
    34       `{\mathcal M} = {\mathcal C}` and the images will lie in
    35       `{\rm Aut}({\mathcal M})`. An element of the image of
    36       `E` is called a cipher.
    37      
    38       We may assume that `E` and `D` are injective, hence
    39       identify a key `K` in `{\mathcal K}` with its image
    40       `E_K := E(K)` in
    41       `\mathrm{Hom}({\mathcal M},{\mathcal C})`.
    42      
    43       The cryptosystem has the property that for every encryption key
    44       `K_1` there is a decryption key `K_2` such that
    45       `D_{K_2} \circ E_{K_1}`. A cryptosystem with the
    46       property that `K := K_2 = K_1`, is called a symmetric
    47       cryptosystem. Otherwise, if the key `K_2 \ne K_1`, nor is
    48       `K_2` easily derived from `K_1`, we call the
    49       cryptosystem asymmetric of public key. In that case, `K_1`
    50       is called the public key and `K_2` is called the private
    51       key.
    52       """
    53       def __init__(self, plaintext_space, ciphertext_space, key_space, block_length = 1, period = None):
    54           self._cipher_domain = plaintext_space   
    55           self._cipher_codomain = ciphertext_space
    56           self._key_space = key_space
    57           self._block_length = block_length
    58           self._period = period
     42    r"""
     43    A base cryptosystem class. This is meant to be extended by other
     44    specialized child classes that implement specific cryptosystems.
     45    A cryptosystem is a pair of maps
    5946
    60       def __eq__(self,right):
    61             return type(self) == type(right) and  \
    62                    self._cipher_domain == right._cipher_domain and \
    63                    self._cipher_codomain == right._cipher_codomain and \
    64                    self._key_space ==  right._key_space and \
    65                    self._block_length == right._block_length and \
    66                    self._period == right._period
     47    .. math::
    6748
    68      
    69       def plaintext_space(self):
    70           return self._cipher_domain
     49        E : {\mathcal K} \rightarrow {\rm Hom}({\mathcal M},{\mathcal C})
    7150
    72       def cipher_domain(self):
    73           return self._cipher_domain
     51    .. math::
    7452
    75       def ciphertext_space(self):
    76           return self._cipher_codomain
     53        D : {\mathcal K} \rightarrow {\rm Hom}({\mathcal C},{\mathcal M})
    7754
    78       def cipher_codomain(self):
    79           return self._cipher_codomain
     55    where `{\mathcal K}` is the key space,
     56    `{\mathcal M}` is the plaintext or message space, and
     57    `{\mathcal C}` is the ciphertext space. In many instances
     58    `{\mathcal M} = {\mathcal C}` and the images will lie in
     59    `{\rm Aut}({\mathcal M})`. An element of the image of
     60    `E` is called a cipher.
    8061
    81       def key_space(self):
    82           return self._key_space
     62    We may assume that `E` and `D` are injective, hence
     63    identify a key `K` in `{\mathcal K}` with its image
     64    `E_K := E(K)` in
     65    `\mathrm{Hom}({\mathcal M},{\mathcal C})`.
    8366
    84       def block_length(self):
    85           return self._block_length
     67    The cryptosystem has the property that for every encryption key
     68    `K_1` there is a decryption key `K_2` such that
     69    `D_{K_2} \circ E_{K_1}`. A cryptosystem with the
     70    property that `K := K_2 = K_1`, is called a symmetric
     71    cryptosystem. Otherwise, if the key `K_2 \ne K_1`, nor is
     72    `K_2` easily derived from `K_1`, we call the
     73    cryptosystem asymmetric or public key. In that case, `K_1`
     74    is called the public key and `K_2` is called the private
     75    key.
    8676
    87       def period(self):
    88           if self._period is None:
    89               raise TypeError, "Argument has no associated period."
    90           return self._period
     77    INPUT:
     78
     79    - ``plaintext_space`` -- the plaintext alphabet.
     80
     81    - ``ciphertext_space`` -- the ciphertext alphabet.
     82
     83    - ``key_space`` -- the key alphabet.
     84
     85    - ``block_length`` -- (default: 1) the block length.
     86
     87    - ``period`` -- (default: ``None``) the period.
     88
     89    EXAMPLES:
     90
     91    Various classical cryptosystems::
     92
     93        sage: ShiftCryptosystem(AlphabeticStrings())
     94        Shift cryptosystem on Free alphabetic string monoid on A-Z
     95        sage: SubstitutionCryptosystem(HexadecimalStrings())
     96        Substitution cryptosystem on Free hexadecimal string monoid
     97        sage: HillCryptosystem(BinaryStrings(), 3)
     98        Hill cryptosystem on Free binary string monoid of block length 3
     99        sage: TranspositionCryptosystem(OctalStrings(), 5)
     100        Transposition cryptosystem on Free octal string monoid of block length 5
     101        sage: VigenereCryptosystem(Radix64Strings(), 7)
     102        Vigenere cryptosystem on Free radix 64 string monoid of period 7
     103    """
     104    def __init__(self, plaintext_space, ciphertext_space, key_space,
     105                 block_length=1, period=None):
     106        r"""
     107        Create a ``Cryptosystem`` object. See the class ``Cryptosystem``
     108        for detailed documentation.
     109
     110        INPUT:
     111
     112        - ``plaintext_space`` -- the plaintext alphabet.
     113
     114        - ``ciphertext_space`` -- the ciphertext alphabet.
     115
     116        - ``key_space`` -- the key alphabet.
     117
     118        - ``block_length`` -- (default: 1) the block length.
     119
     120        - ``period`` -- (default: ``None``) the period.
     121
     122        EXAMPLES:
     123
     124        Various classical cryptosystems::
     125
     126            sage: ShiftCryptosystem(AlphabeticStrings())
     127            Shift cryptosystem on Free alphabetic string monoid on A-Z
     128            sage: SubstitutionCryptosystem(HexadecimalStrings())
     129            Substitution cryptosystem on Free hexadecimal string monoid
     130            sage: HillCryptosystem(BinaryStrings(), 3)
     131            Hill cryptosystem on Free binary string monoid of block length 3
     132            sage: TranspositionCryptosystem(OctalStrings(), 5)
     133            Transposition cryptosystem on Free octal string monoid of block length 5
     134            sage: VigenereCryptosystem(Radix64Strings(), 7)
     135            Vigenere cryptosystem on Free radix 64 string monoid of period 7
     136        """
     137        self._cipher_domain = plaintext_space
     138        self._cipher_codomain = ciphertext_space
     139        self._key_space = key_space
     140        self._block_length = block_length
     141        self._period = period
     142
     143    def __eq__(self, right):
     144        r"""
     145        Comparing ``self`` with ``right``. Two ``Cryptosystem`` objects
     146        are the same if they satisfy all of these conditions:
     147
     148        - share the same type
     149        - have the same cipher domain
     150        - have the same cipher codomain
     151        - share the same key space
     152        - share the same block length
     153        - have the same period
     154
     155        INPUT:
     156
     157        - ``right`` -- a ``Cryptosystem`` object.
     158
     159        EXAMPLES:
     160
     161        Pairs of equivalent classical cryptosystems::
     162
     163            sage: sub1 = SubstitutionCryptosystem(AlphabeticStrings())
     164            sage: sub2 = SubstitutionCryptosystem(AlphabeticStrings())
     165            sage: sub1 == sub2
     166            True
     167            sage: shift1 = ShiftCryptosystem(HexadecimalStrings())
     168            sage: shift2 = ShiftCryptosystem(HexadecimalStrings())
     169            sage: shift1 == shift2
     170            True
     171            sage: hill1 = HillCryptosystem(AlphabeticStrings(), 4)
     172            sage: hill2 = HillCryptosystem(AlphabeticStrings(), 4)
     173            sage: hill1 == hill2
     174            True
     175            sage: tran1 = TranspositionCryptosystem(HexadecimalStrings(), 5)
     176            sage: tran2 = TranspositionCryptosystem(HexadecimalStrings(), 5)
     177            sage: tran1 == tran2
     178            True
     179            sage: vig1 = VigenereCryptosystem(AlphabeticStrings(), 7)
     180            sage: vig2 = VigenereCryptosystem(AlphabeticStrings(), 7)
     181            sage: vig1 == vig2
     182            True
     183
     184        Pairs of different classical cryptosystems::
     185
     186            sage: sub1 = SubstitutionCryptosystem(AlphabeticStrings())
     187            sage: sub2 = SubstitutionCryptosystem(OctalStrings())
     188            sage: sub1 == sub2
     189            False
     190            sage: shift1 = ShiftCryptosystem(HexadecimalStrings())
     191            sage: shift2 = ShiftCryptosystem(BinaryStrings())
     192            sage: shift1 == shift2
     193            False
     194            sage: hill1 = HillCryptosystem(Radix64Strings(), 4)
     195            sage: hill2 = HillCryptosystem(Radix64Strings(), 5)
     196            sage: hill1 == hill2
     197            False
     198            sage: tran1 = TranspositionCryptosystem(Radix64Strings(), 3)
     199            sage: tran2 = TranspositionCryptosystem(HexadecimalStrings(), 3)
     200            sage: tran1 == tran2
     201            False
     202            sage: vig1 = VigenereCryptosystem(AlphabeticStrings(), 7)
     203            sage: vig2 = VigenereCryptosystem(Radix64Strings(), 7)
     204            sage: vig1 == vig2
     205            False
     206        """
     207        return type(self) == type(right) and  \
     208            self._cipher_domain == right._cipher_domain and \
     209            self._cipher_codomain == right._cipher_codomain and \
     210            self._key_space ==  right._key_space and \
     211            self._block_length == right._block_length and \
     212            self._period == right._period
     213
     214    def plaintext_space(self):
     215        r"""
     216        Return the plaintext alphabet of this cryptosystem.
     217
     218        EXAMPLES:
     219
     220        The plaintext spaces of various classical cryptosystems::
     221
     222            sage: ShiftCryptosystem(AlphabeticStrings()).plaintext_space()
     223            Free alphabetic string monoid on A-Z
     224            sage: SubstitutionCryptosystem(HexadecimalStrings()).plaintext_space()
     225            Free hexadecimal string monoid
     226            sage: HillCryptosystem(BinaryStrings(), 3).plaintext_space()
     227            Free binary string monoid
     228            sage: TranspositionCryptosystem(OctalStrings(), 5).plaintext_space()
     229            Free octal string monoid
     230            sage: VigenereCryptosystem(Radix64Strings(), 7).plaintext_space()
     231            Free radix 64 string monoid
     232        """
     233        return self._cipher_domain
     234
     235    def cipher_domain(self):
     236        r"""
     237        Return the alphabet used by this cryptosystem for encoding plaintexts.
     238        This is the same as the plaintext space.
     239
     240        EXAMPLES:
     241
     242        The cipher domains, or plaintext spaces, of various classical
     243        cryptosystems::
     244
     245            sage: ShiftCryptosystem(AlphabeticStrings()).cipher_domain()
     246            Free alphabetic string monoid on A-Z
     247            sage: SubstitutionCryptosystem(HexadecimalStrings()).cipher_domain()
     248            Free hexadecimal string monoid
     249            sage: HillCryptosystem(BinaryStrings(), 3).cipher_domain()
     250            Free binary string monoid
     251            sage: TranspositionCryptosystem(OctalStrings(), 5).cipher_domain()
     252            Free octal string monoid
     253            sage: VigenereCryptosystem(Radix64Strings(), 7).cipher_domain()
     254            Free radix 64 string monoid
     255        """
     256        return self._cipher_domain
     257
     258    def ciphertext_space(self):
     259        r"""
     260        Return the ciphertext alphabet of this cryptosystem.
     261
     262        EXAMPLES:
     263
     264        The ciphertext spaces of various classical cryptosystems::
     265
     266            sage: ShiftCryptosystem(AlphabeticStrings()).ciphertext_space()
     267            Free alphabetic string monoid on A-Z
     268            sage: SubstitutionCryptosystem(HexadecimalStrings()).ciphertext_space()
     269            Free hexadecimal string monoid
     270            sage: HillCryptosystem(BinaryStrings(), 3).ciphertext_space()
     271            Free binary string monoid
     272            sage: TranspositionCryptosystem(OctalStrings(), 5).ciphertext_space()
     273            Free octal string monoid
     274            sage: VigenereCryptosystem(Radix64Strings(), 7).ciphertext_space()
     275            Free radix 64 string monoid
     276        """
     277        return self._cipher_codomain
     278
     279    def cipher_codomain(self):
     280        r"""
     281        Return the alphabet used by this cryptosystem for encoding ciphertexts.
     282        This is the same as the ciphertext space.
     283
     284        EXAMPLES:
     285
     286        The cipher codomains, or ciphertext spaces, of various classical
     287        cryptosystems::
     288
     289            sage: ShiftCryptosystem(AlphabeticStrings()).cipher_codomain()
     290            Free alphabetic string monoid on A-Z
     291            sage: SubstitutionCryptosystem(HexadecimalStrings()).cipher_codomain()
     292            Free hexadecimal string monoid
     293            sage: HillCryptosystem(BinaryStrings(), 3).cipher_codomain()
     294            Free binary string monoid
     295            sage: TranspositionCryptosystem(OctalStrings(), 5).cipher_codomain()
     296            Free octal string monoid
     297            sage: VigenereCryptosystem(Radix64Strings(), 7).cipher_codomain()
     298            Free radix 64 string monoid
     299        """
     300        return self._cipher_codomain
     301
     302    def key_space(self):
     303        r"""
     304        Return the alphabet used by this cryptosystem for encoding keys.
     305
     306        EXAMPLES:
     307
     308        The key spaces of various classical cryptosystems::
     309
     310            sage: ShiftCryptosystem(AlphabeticStrings()).key_space()
     311            Ring of integers modulo 26
     312            sage: SubstitutionCryptosystem(HexadecimalStrings()).key_space()
     313            Free hexadecimal string monoid
     314            sage: HillCryptosystem(BinaryStrings(), 3).key_space()
     315            Full MatrixSpace of 3 by 3 dense matrices over Ring of integers modulo 2
     316            sage: TranspositionCryptosystem(OctalStrings(), 5).key_space()
     317            Symmetric group of order 5! as a permutation group
     318            sage: VigenereCryptosystem(Radix64Strings(), 7).key_space()
     319            Free radix 64 string monoid
     320        """
     321        return self._key_space
     322
     323    def block_length(self):
     324        r"""
     325        Return the block length of this cryptosystem. For some cryptosystems
     326        this is not relevant, in which case the block length defaults to 1.
     327
     328        EXAMPLES:
     329
     330        The block lengths of various classical cryptosystems::
     331
     332            sage: ShiftCryptosystem(AlphabeticStrings()).block_length()
     333            1
     334            sage: SubstitutionCryptosystem(HexadecimalStrings()).block_length()
     335            1
     336            sage: HillCryptosystem(BinaryStrings(), 3).block_length()
     337            3
     338            sage: TranspositionCryptosystem(OctalStrings(), 5).block_length()
     339            5
     340            sage: VigenereCryptosystem(Radix64Strings(), 7).block_length()
     341            1
     342        """
     343        return self._block_length
     344
     345    def period(self):
     346        if self._period is None:
     347            raise TypeError, "Argument has no associated period."
     348        return self._period
    91349
    92350class SymmetricKeyCryptosystem(Cryptosystem):
    93       """
    94      
    95       """
     351    r"""
     352    The base class for symmetric key, or secret key, cryptosystems.
     353    """
     354    def alphabet_size(self):
     355        r"""
     356        Return the number of elements in the alphabet of this
     357        cryptosystem. This only applies to any cryptosystem whose plaintext
     358        and ciphertext spaces are the same alphabet.
     359
     360        EXAMPLES::
     361
     362            sage: ShiftCryptosystem(AlphabeticStrings()).alphabet_size()
     363            26
     364            sage: ShiftCryptosystem(BinaryStrings()).alphabet_size()
     365            2
     366            sage: ShiftCryptosystem(HexadecimalStrings()).alphabet_size()
     367            16
     368            sage: SubstitutionCryptosystem(OctalStrings()).alphabet_size()
     369            8
     370            sage: SubstitutionCryptosystem(Radix64Strings()).alphabet_size()
     371            64
     372        """
     373        return self._cipher_domain.ngens()
    96374
    97375class PublicKeyCryptosystem(Cryptosystem):
    98       """
    99      
    100       """
    101 
    102 
     376    r"""
     377    The base class for asymmetric or public-key cryptosystems.
     378    """
  • sage/crypto/lfsr.py

    diff -r 7fc8b5794aca -r 5d9b9378ee4f sage/crypto/lfsr.py
    a b  
    11r"""
    2 Linear feedback shift register (LFSR) sequence commands.
     2Linear feedback shift register (LFSR) sequence commands
    33
    44Stream ciphers have been used for a long time as a source of
    55pseudo-random number generators.
    66
    7 S. Golomb [G] gives a list of three statistical properties a
     7S. Golomb [G]_ gives a list of three statistical properties a
    88sequence of numbers `{\bf a}=\{a_n\}_{n=1}^\infty`,
    99`a_n\in \{0,1\}`, should display to be considered
    1010"random". Define the autocorrelation of `{\bf a}` to be
    1111
    1212.. math::
    1313
    14      C(k)=C(k,{\bf a})=\lim_{N\rightarrow \infty} {1\over N}\sum_{n=1}^N (-1)^{a_n+a_{n+k}}. 
     14     C(k)=C(k,{\bf a})=\lim_{N\rightarrow \infty} {1\over N}\sum_{n=1}^N (-1)^{a_n+a_{n+k}}.
    1515
    1616
    1717In the case where `{\bf a}` is periodic with period
     
    1919
    2020.. math::
    2121
    22      C(k)={1\over P}\sum_{n=1}^P (-1)^{a_n+a_{n+k}}. 
     22     C(k)={1\over P}\sum_{n=1}^P (-1)^{a_n+a_{n+k}}.
    2323
    2424
    2525Assume `{\bf a}` is periodic with period `P`.
     
    2828-  balance: `|\sum_{n=1}^P(-1)^{a_n}|\leq 1`.
    2929
    3030-  low autocorrelation:
    31    
     31
    3232   .. math::
    3333
    34       C(k)= \left\{ \begin{array}{cc} 1,& k=0,\\ \epsilon, & k\not= 0. \end{array} \right. 
     34      C(k)= \left\{ \begin{array}{cc} 1,& k=0,\\ \epsilon, & k\not= 0. \end{array} \right.
    3535
    3636
    3737   (For sequences satisfying these first two properties, it is known
     
    4848
    4949.. math::
    5050
    51      \begin{array}{c} f(x_0,...,x_{n-1})=(x_1,x_2,...,x_n),\\ x_n=C(x_0,...,x_{n-1}), \end{array} 
     51     \begin{array}{c} f(x_0,...,x_{n-1})=(x_1,x_2,...,x_n),\\ x_n=C(x_0,...,x_{n-1}), \end{array}
    5252
    5353
    5454where `C:{\bf F}_q^d\rightarrow {\bf F}_q` is a given
     
    5656
    5757.. math::
    5858
    59      C(x_0,...,x_{n-1})=a_0x_0+...+a_{n-1}x_{n-1}, 
     59     C(x_0,...,x_{n-1})=a_0x_0+...+a_{n-1}x_{n-1},
    6060
    6161
    6262for some given constants `a_i\in {\bf F}_q`, the map is
     
    6666
    6767.. math::
    6868
    69      f(x)=a_{{0}}+a_{{1}}x+...+a_{{n}}{x}^n+..., 
     69     f(x)=a_{{0}}+a_{{1}}x+...+a_{{n}}{x}^n+...,
    7070
    7171
    7272
    7373.. math::
    7474
    75      g(x)=b_{{0}}+b_{{1}}x+...+b_{{n}}{x}^n+..., 
     75     g(x)=b_{{0}}+b_{{1}}x+...+b_{{n}}{x}^n+...,
    7676
    7777
    7878be given polynomials in `{\bf F}_2[x]` and let
    7979
    8080.. math::
    8181
    82      h(x)={f(x)\over g(x)}=c_0+c_1x+...+c_nx^n+... \ . 
     82     h(x)={f(x)\over g(x)}=c_0+c_1x+...+c_nx^n+... \ .
    8383
    8484
    8585We can compute a recursion formula which allows us to rapidly
     
    8787
    8888.. math::
    8989
    90      c_{n}=\sum_{i=1}^n {{-b_i\over b_0}c_{n-i}}. 
     90     c_{n}=\sum_{i=1}^n {{-b_i\over b_0}c_{n-i}}.
    9191
    9292
    9393
     
    9999
    100100.. math::
    101101
    102      f(x)=1,\ \ \ \ g(x)=x^4+x+1, 
     102     f(x)=1,\ \ \ \ g(x)=x^4+x+1,
    103103
    104104then
    105105
    106106.. math::
    107107
    108      h(x)=1+x+x^2+x^3+x^5+x^7+x^8+...\ . 
     108     h(x)=1+x+x^2+x^3+x^5+x^7+x^8+...\ .
    109109
    110110The coefficients of `h` are
    111111
    112112.. math::
    113113
    114      \begin{array}{c} 1, 1, 1, 0, 1, 0, 1, 1, 0, 0, 1, 0, 0, 0, 1, \\ 1, 1, 1, 0, 1, 0, 1, 1, 0, 0, 1, 0, 0, 0, 1, ...\ . \end{array} 
     114     \begin{array}{c} 1, 1, 1, 0, 1, 0, 1, 1, 0, 0, 1, 0, 0, 0, 1, \\ 1, 1, 1, 0, 1, 0, 1, 1, 0, 0, 1, 0, 0, 0, 1, ...\ . \end{array}
    115115
    116116
    117117The sequence of `0,1`'s is periodic with period
    118118`P=2^4-1=15` and satisfies Golomb's three randomness
    119119conditions. However, this sequence of period 15 can be "cracked"
    120120(i.e., a procedure to reproduce `g(x)`) by knowing only 8
    121 terms! This is the function of the Berlekamp-Massey algorithm [M],
     121terms! This is the function of the Berlekamp-Massey algorithm [M]_,
    122122implemented as ``berlekamp_massey.py``.
    123123
    124 [G] Solomon Golomb, Shift register sequences, Aegean Park Press,
    125 Laguna Hills, Ca, 1967
     124.. [G] Solomon Golomb, Shift register sequences, Aegean Park Press,
     125  Laguna Hills, Ca, 1967
    126126
    127 [M] James L. Massey, "Shift-Register Synthesis and BCH Decoding."
    128 IEEE Trans. on Information Theory, vol. 15(1), pp. 122-127, Jan
    129 1969.
     127.. [M] James L. Massey, "Shift-Register Synthesis and BCH Decoding."
     128  IEEE Trans. on Information Theory, vol. 15(1), pp. 122-127, Jan
     129  1969.
    130130
    131131AUTHORS:
    132132
     
    152152def lfsr_sequence(key, fill, n):
    153153    r"""
    154154    This function creates an lfsr sequence.
    155    
     155
    156156    INPUT:
    157    
    158    
     157
     158
    159159    -  ``key`` - a list of finite field elements,
    160160       [c_0,c_1,...,c_k].
    161    
     161
    162162    -  ``fill`` - the list of the initial terms of the lfsr
    163163       sequence, [x_0,x_1,...,x_k].
    164    
     164
    165165    -  ``n`` - number of terms of the sequence that the
    166166       function returns.
    167    
    168    
     167
     168
    169169    OUTPUT: The lfsr sequence defined by
    170170    `x_{n+1} = c_kx_n+...+c_0x_{n-k}`, for
    171171    `n \leq k`.
    172    
     172
    173173    EXAMPLES::
    174    
     174
    175175        sage: F = GF(2); l = F(1); o = F(0)
    176176        sage: F = GF(2); S = LaurentSeriesRing(F,'x'); x = S.gen()
    177177        sage: fill = [l,l,o,l]; key = [1,o,o,l]; n = 20
     
    194194        1 + x + x^4 + x^5 + x^8 + x^9 + x^12 + x^13 + x^16 + x^17 + O(x^20)
    195195        sage: (1+x+x^3)/(g.reverse()+O(x^20))
    196196        1 + x + x^3 + x^4 + x^5 + x^7 + x^8 + x^9 + x^11 + x^12 + x^13 + x^15 + x^16 + x^17 + x^19 + O(x^20)
    197    
     197
    198198    AUTHORS:
    199199
    200200    - Timothy Brock (2005-11): with code modified from Python
     
    243243        4/15
    244244        sage: lfsr_autocorrelation(s,int(15),7)
    245245        4/15
    246    
     246
    247247    AUTHORS:
    248248
    249249    - Timothy Brock (2006-04-17)
     
    257257    L0 = L0 + L0[:k]
    258258    L1 = [int(L0[i])*int(L0[i + k])/p for i in range(_p)]
    259259    return sum(L1)
    260    
     260
    261261def lfsr_connection_polynomial(s):
    262262    """
    263263    INPUT:
    264    
    265    
     264
     265
    266266    -  ``s`` - a sequence of elements of a finite field (F)
    267267       of even length
    268    
    269    
     268
     269
    270270    OUTPUT:
    271    
    272    
     271
     272
    273273    -  ``C(x)`` - the connection polynomial of the minimal
    274274       LFSR.
    275    
    276    
     275
     276
    277277    This implements the algorithm in section 3 of J. L. Massey's
    278     article [M].
    279    
     278    article [M]_.
     279
    280280    EXAMPLE::
    281    
    282                 sage: F = GF(2)
     281
     282        sage: F = GF(2)
    283283        sage: F
    284284        Finite Field of size 2
    285285        sage: o = F(0); l = F(1)
    286                sage: key = [l,o,o,l]; fill = [l,l,o,l]; n = 20
    287                sage: s = lfsr_sequence(key,fill,n); s
    288                [1, 1, 0, 1, 0, 1, 1, 0, 0, 1, 0, 0, 0, 1, 1, 1, 1, 0, 1, 0]
    289                sage: lfsr_connection_polynomial(s)
    290                x^4 + x + 1
    291                sage: berlekamp_massey(s)
    292                x^4 + x^3 + 1
    293    
     286        sage: key = [l,o,o,l]; fill = [l,l,o,l]; n = 20
     287        sage: s = lfsr_sequence(key,fill,n); s
     288        [1, 1, 0, 1, 0, 1, 1, 0, 0, 1, 0, 0, 0, 1, 1, 1, 1, 0, 1, 0]
     289        sage: lfsr_connection_polynomial(s)
     290        x^4 + x + 1
     291        sage: berlekamp_massey(s)
     292        x^4 + x^3 + 1
     293
    294294    Notice that ``berlekamp_massey`` returns the reverse
    295295    of the connection polynomial (and is potentially must faster than
    296296    this implementation).
    297    
     297
    298298    AUTHORS:
    299299
    300300    - Timothy Brock (2006-04-17)
    301    
    302     REFERENCES:
    303 
    304     - [M] J. L. Massey, 'Shift-register synthesis and BCH decoding,'
    305       IEEE Trans. Inform. Theory, vol. IT-15, pp. 122-127, Jan. 19 69.
    306301    """
    307302    # Initialization:
    308303    FF = s[0].base_ring()
    309304    R = PolynomialRing(FF, "x")
    310305    x = R.gen()
    311306    C = R(1); B = R(1); m = 1; b = FF(1); L = 0; N = 0
    312    
     307
    313308    while N < len(s):
    314309        if L > 0:
    315310            r = min(L+1,C.degree()+1)
     
    333328                B = T
    334329                N += 1
    335330    return C
    336            
    337 
    338 
    339 
    340 
    341 
    342 
  • sage/crypto/stream.py

    diff -r 7fc8b5794aca -r 5d9b9378ee4f sage/crypto/stream.py
    a b  
    11"""
    2 Stream Cryptosystems.
     2Stream Cryptosystems
    33"""
    44
    55#*****************************************************************************
     
    2525    def __init__(self, field = None):
    2626        """
    2727        Create a linear feedback shift cryptosystem.
    28        
     28
    2929        INPUT: A string monoid over a binary alphabet.
    30        
     30
    3131        OUTPUT:
    32        
     32
    3333        EXAMPLES::
    34        
    35                    sage: E = LFSRCryptosystem(FiniteField(2))
     34
     35            sage: E = LFSRCryptosystem(FiniteField(2))
    3636            sage: E
    37                    LFSR cryptosystem over Finite Field of size 2
    38        
     37            LFSR cryptosystem over Finite Field of size 2
     38
    3939        TESTS::
    40        
     40
    4141            sage: E = LFSRCryptosystem(FiniteField(2))
    4242            sage: E == loads(dumps(E))
    4343            True
    44        
    45         TODO: Implement LFSR cryptosytem for arbitrary rings. The current
     44
     45        TODO: Implement LFSR cryptosystem for arbitrary rings. The current
    4646        implementation is limited to the finite field of 2 elements only
    4747        because of the dependence on binary strings.
    4848        """
     
    6161    def __call__(self, key):
    6262        """
    6363        Create a LFSR cipher.
    64        
     64
    6565        INPUT: A polynomial and initial state of the LFSR.
    66         """       
     66        """
    6767        if not isinstance(key, (list,tuple)) and len(key) == 2:
    6868            raise TypeError, "Argument key (= %s) must be a list of tuple of length 2" % key
    6969        poly = key[0]; IS = key[1]
     
    7676                "The length of IS (= %s) must equal the degree of poly (= %s)" % (IS, poly)
    7777        return LFSRCipher(self, poly, IS)
    7878
    79     def __repr__(self):
     79    def _repr_(self):
     80        r"""
     81        Return the string representation of this LFSR cryptosystem.
     82
     83        EXAMPLES::
     84
     85            sage: LFSRCryptosystem(FiniteField(2))
     86            LFSR cryptosystem over Finite Field of size 2
     87        """
    8088        return "LFSR cryptosystem over %s" % self._field
    8189
    8290    def encoding(self,M):
     
    93101    def __init__(self, field = None):
    94102        """
    95103        Create a shrinking generator cryptosystem.
    96        
     104
    97105        INPUT: A string monoid over a binary alphabet.
    98        
     106
    99107        OUTPUT:
    100        
     108
    101109        EXAMPLES::
    102        
    103                    sage: E = ShrinkingGeneratorCryptosystem()
     110
     111            sage: E = ShrinkingGeneratorCryptosystem()
    104112            sage: E
    105                    Shrinking generator cryptosystem over Finite Field of size 2
     113            Shrinking generator cryptosystem over Finite Field of size 2
    106114        """
    107115        if field is None:
    108116           field = FiniteField(2)
     
    116124    def __call__(self, key):
    117125        """
    118126        Create a Shrinking generator cipher.
    119        
     127
    120128        INPUT: A list or tuple consisting of two LFSR ciphers (e1,e2).
    121        
     129
    122130        OUTPUT: The shrinking generator cipher with key stream generator e1
    123131        and decimating cipher e2.
    124         """       
     132        """
    125133        if not isinstance(key, (list,tuple)) and len(key) == 2:
    126134            raise TypeError, "Argument key (= %s) must be a list of tuple of length 2" % key
    127135        e1 = key[0]; e2 = key[1]
     
    129137            raise TypeError, "The key (= (%s,%s)) must be a tuple of two LFSR ciphers." % key
    130138        return ShrinkingGeneratorCipher(self, e1, e2)
    131139
    132     def __repr__(self):
     140    def _repr_(self):
     141        r"""
     142        Return the string representation of this shrinking generator
     143        cryptosystem.
     144
     145        EXAMPLES::
     146
     147            sage: ShrinkingGeneratorCryptosystem()
     148            Shrinking generator cryptosystem over Finite Field of size 2
     149        """
    133150        return "Shrinking generator cryptosystem over %s" % self._field
    134151
    135152    def encoding(self,M):
     
    138155            return S.encoding(M)
    139156        except:
    140157            raise TypeError, "Argument M = %s does not encode in the cipher domain" % M
    141 
    142 
  • sage/crypto/stream_cipher.py

    diff -r 7fc8b5794aca -r 5d9b9378ee4f sage/crypto/stream_cipher.py
    a b  
    1717    def __init__(self, parent, poly, IS):
    1818        """
    1919        Create a linear feedback shift register (LFSR) cipher.
    20        
     20
    2121        INPUT:
    22        
    23        
     22
     23
    2424        -  ``parent`` - parent
    25        
     25
    2626        -  ``poly`` - connection polynomial
    27        
     27
    2828        -  ``IS`` - initial state
    29        
    30        
     29
     30
    3131        EXAMPLES::
    32        
     32
    3333            sage: FF = FiniteField(2)
    3434            sage: P.<x> = PolynomialRing(FF)
    3535            sage: E = LFSRCryptosystem(FF)
     
    5151            sage: e(m)
    5252            00111001110111101011111001001101110101011011101000011001100101101011001000000011100101101010111100000101110100111111101100000101110101111010111101000011
    5353            sage: m == e(e(m))
    54             True           
    55        
     54            True
     55
    5656        TESTS::
    57        
     57
    5858            sage: FF = FiniteField(2)
    5959            sage: P.<x> = PolynomialRing(FF)
    6060            sage: E = LFSRCryptosystem(FF)
     
    6666    def __call__(self, M, mode = "ECB"):
    6767        r"""
    6868        Generate key stream from the binary string ``M``.
    69        
     69
    7070        INPUT:
    71        
    72        
     71
     72
    7373        -  ``M`` - a StringMonoidElement
    74        
     74
    7575        -  ``mode`` - ignored (default: 'ECB')
    76        
    77        
     76
     77
    7878        EXAMPLE::
    79        
     79
    8080            sage: k = GF(2)
    8181            sage: P.<x> = PolynomialRing( k )
    8282            sage: LFSR = LFSRCryptosystem( k )
     
    9696        Kelt = lfsr_sequence(poly.list(), IS, N)
    9797        return B([ (Melt[i]+int(Kelt[i]))%n for i in range(N) ])
    9898
     99    def _repr_(self):
     100        r"""
     101        Return the string representation of this LFSR cipher.
     102
     103        EXAMPLES::
     104
     105            sage: FF = FiniteField(2)
     106            sage: P.<x> = PolynomialRing(FF)
     107            sage: LFSR = LFSRCryptosystem(FF)
     108            sage: IS_1 = [ FF(a) for a in [0,1,0,1,0,0,0] ]
     109            sage: e1 = LFSR((x^7 + x + 1,IS_1))
     110            sage: IS_2 = [ FF(a) for a in [0,0,1,0,0,0,1,0,1] ]
     111            sage: e2 = LFSR((x^9 + x^3 + 1,IS_2))
     112            sage: E = ShrinkingGeneratorCryptosystem()
     113            sage: e = E((e1,e2))
     114            sage: e.keystream_cipher()
     115            LFSR cipher on Free binary string monoid
     116        """
     117        return "LFSR cipher on %s" % self.domain()
     118
    99119    def connection_polynomial(self):
    100         """ 
     120        """
    101121        The connection polynomial defining the LFSR of the cipher.
    102        
     122
    103123        EXAMPLE::
    104        
     124
    105125            sage: k = GF(2)
    106126            sage: P.<x> = PolynomialRing( k )
    107127            sage: LFSR = LFSRCryptosystem( k )
     
    112132        return self.key()[0]
    113133
    114134    def initial_state(self):
    115         """ 
     135        """
    116136        The initial state of the LFSR cipher.
    117        
     137
    118138        EXAMPLE::
    119        
     139
    120140            sage: k = GF(2)
    121141            sage: P.<x> = PolynomialRing( k )
    122142            sage: LFSR = LFSRCryptosystem( k )
     
    130150    def __init__(self, parent, e1, e2):
    131151        """
    132152        Create a shrinking generator cipher.
    133        
     153
    134154        INPUT:
    135        
    136        
     155
     156
    137157        -  ``parent`` - parent
    138        
     158
    139159        -  ``poly`` - connection polynomial
    140        
     160
    141161        -  ``IS`` - initial state
    142        
    143        
     162
     163
    144164        EXAMPLES::
    145        
    146                    sage: FF = FiniteField(2)
    147                    sage: P.<x> = PolynomialRing(FF)
    148                    sage: LFSR = LFSRCryptosystem(FF)
    149                    sage: IS_1 = [ FF(a) for a in [0,1,0,1,0,0,0] ]
    150                    sage: e1 = LFSR((x^7 + x + 1,IS_1))
    151                    sage: IS_2 = [ FF(a) for a in [0,0,1,0,0,0,1,0,1] ]
    152                    sage: e2 = LFSR((x^9 + x^3 + 1,IS_2))
    153                    sage: E = ShrinkingGeneratorCryptosystem()
    154                    sage: e = E((e1,e2))
     165
     166            sage: FF = FiniteField(2)
     167            sage: P.<x> = PolynomialRing(FF)
     168            sage: LFSR = LFSRCryptosystem(FF)
     169            sage: IS_1 = [ FF(a) for a in [0,1,0,1,0,0,0] ]
     170            sage: e1 = LFSR((x^7 + x + 1,IS_1))
     171            sage: IS_2 = [ FF(a) for a in [0,0,1,0,0,0,1,0,1] ]
     172            sage: e2 = LFSR((x^9 + x^3 + 1,IS_2))
     173            sage: E = ShrinkingGeneratorCryptosystem()
     174            sage: e = E((e1,e2))
    155175            sage: e
    156             ((x^7 + x + 1, [0, 1, 0, 1, 0, 0, 0]), (x^9 + x^3 + 1, [0, 0, 1, 0, 0, 0, 1, 0, 1]))
     176            Shrinking generator cipher on Free binary string monoid
    157177        """
    158178        if not isinstance(e1, LFSRCipher):
    159179            raise TypeError, "Argument e1 (= %s) must be a LFSR cipher." % e1
     
    162182        SymmetricKeyCipher.__init__(self, parent, key = (e1, e2))
    163183
    164184    def keystream_cipher(self):
    165         """ 
     185        """
    166186        The LFSR cipher generating the output key stream.
    167        
     187
    168188        EXAMPLE::
    169        
    170                    sage: FF = FiniteField(2)
    171                    sage: P.<x> = PolynomialRing(FF)
    172                    sage: LFSR = LFSRCryptosystem(FF)
    173                    sage: IS_1 = [ FF(a) for a in [0,1,0,1,0,0,0] ]
    174                    sage: e1 = LFSR((x^7 + x + 1,IS_1))
    175                    sage: IS_2 = [ FF(a) for a in [0,0,1,0,0,0,1,0,1] ]
    176                    sage: e2 = LFSR((x^9 + x^3 + 1,IS_2))
    177                    sage: E = ShrinkingGeneratorCryptosystem()
    178                    sage: e = E((e1,e2))
     189
     190            sage: FF = FiniteField(2)
     191            sage: P.<x> = PolynomialRing(FF)
     192            sage: LFSR = LFSRCryptosystem(FF)
     193            sage: IS_1 = [ FF(a) for a in [0,1,0,1,0,0,0] ]
     194            sage: e1 = LFSR((x^7 + x + 1,IS_1))
     195            sage: IS_2 = [ FF(a) for a in [0,0,1,0,0,0,1,0,1] ]
     196            sage: e2 = LFSR((x^9 + x^3 + 1,IS_2))
     197            sage: E = ShrinkingGeneratorCryptosystem()
     198            sage: e = E((e1,e2))
    179199            sage: e.keystream_cipher()
    180                    (x^7 + x + 1, [0, 1, 0, 1, 0, 0, 0])
     200            LFSR cipher on Free binary string monoid
    181201        """
    182202        return self.key()[0]
    183203
    184204    def decimating_cipher(self):
    185         """ 
     205        """
    186206        The LFSR cipher generating the decimating key stream.
    187        
     207
    188208        EXAMPLE::
    189        
    190                    sage: FF = FiniteField(2)
    191                    sage: P.<x> = PolynomialRing(FF)
    192                    sage: LFSR = LFSRCryptosystem(FF)
    193                    sage: IS_1 = [ FF(a) for a in [0,1,0,1,0,0,0] ]
    194                    sage: e1 = LFSR((x^7 + x + 1,IS_1))
    195                    sage: IS_2 = [ FF(a) for a in [0,0,1,0,0,0,1,0,1] ]
    196                    sage: e2 = LFSR((x^9 + x^3 + 1,IS_2))
    197                    sage: E = ShrinkingGeneratorCryptosystem()
    198                    sage: e = E((e1,e2))
     209
     210            sage: FF = FiniteField(2)
     211            sage: P.<x> = PolynomialRing(FF)
     212            sage: LFSR = LFSRCryptosystem(FF)
     213            sage: IS_1 = [ FF(a) for a in [0,1,0,1,0,0,0] ]
     214            sage: e1 = LFSR((x^7 + x + 1,IS_1))
     215            sage: IS_2 = [ FF(a) for a in [0,0,1,0,0,0,1,0,1] ]
     216            sage: e2 = LFSR((x^9 + x^3 + 1,IS_2))
     217            sage: E = ShrinkingGeneratorCryptosystem()
     218            sage: e = E((e1,e2))
    199219            sage: e.decimating_cipher()
    200                    (x^9 + x^3 + 1, [0, 0, 1, 0, 0, 0, 1, 0, 1])
     220            LFSR cipher on Free binary string monoid
    201221        """
    202222        return self.key()[1]
    203223
    204224    def __call__(self, M, mode = "ECB"):
    205225        r"""
    206226        INPUT:
    207        
    208        
     227
     228
    209229        -  ``M`` - a StringMonoidElement
    210        
     230
    211231        -  ``mode`` - ignored (default: 'ECB')
    212        
    213        
     232
     233
    214234        EXAMPLES::
    215        
    216             sage: FF = FiniteField(2)   
    217             sage: P.<x> = PolynomialRing(FF)   
    218             sage: LFSR = LFSRCryptosystem(FF)   
    219             sage: IS_1 = [ FF(a) for a in [0,1,0,1,0,0,0] ]     
    220             sage: e1 = LFSR((x^7 + x + 1,IS_1)) 
    221             sage: IS_2 = [ FF(a) for a in [0,0,1,0,0,0,1,0,1] ] 
    222             sage: e2 = LFSR((x^9 + x^3 + 1,IS_2))       
    223             sage: E = ShrinkingGeneratorCryptosystem() 
     235
     236            sage: FF = FiniteField(2)
     237            sage: P.<x> = PolynomialRing(FF)
     238            sage: LFSR = LFSRCryptosystem(FF)
     239            sage: IS_1 = [ FF(a) for a in [0,1,0,1,0,0,0] ]
     240            sage: e1 = LFSR((x^7 + x + 1,IS_1))
     241            sage: IS_2 = [ FF(a) for a in [0,0,1,0,0,0,1,0,1] ]
     242            sage: e2 = LFSR((x^9 + x^3 + 1,IS_2))
     243            sage: E = ShrinkingGeneratorCryptosystem()
    224244            sage: e = E((e1,e2))
    225             sage: B = BinaryStrings()   
    226             sage: m = B.encoding("THECATINTHEHAT")     
     245            sage: B = BinaryStrings()
     246            sage: m = B.encoding("THECATINTHEHAT")
    227247            sage: c = e(m)
    228248            sage: c.decoding()
    229249            "t\xb6\xc1'\x83\x17\xae\xc9ZO\x84V\x7fX"
     
    247267        N = len(M)
    248268        n = max(n1,n2)
    249269        CStream = []
    250         while k < N: 
     270        while k < N:
    251271            r = max(N-k,2*n)
    252272            KStream = lfsr_sequence(g1.list(), IS_1, r)
    253273            DStream = lfsr_sequence(g2.list(), IS_2, r)
     
    256276                     CStream.append(int(MStream[k]+KStream[i]))
    257277                     k += 1
    258278                 if k == N:
    259                      break 
     279                     break
    260280            IS_1 = KStream[r-n-1:r-n+n1]
    261281            IS_2 = DStream[r-n-1:r-n+n2]
    262282        return B(CStream)
    263283
    264        
     284    def _repr_(self):
     285        r"""
     286        Return the string representation of this shrinking generator cipher.
    265287
     288        EXAMPLES::
     289
     290            sage: FF = FiniteField(2)
     291            sage: P.<x> = PolynomialRing(FF)
     292            sage: LFSR = LFSRCryptosystem(FF)
     293            sage: IS_1 = [ FF(a) for a in [0,1,0,1,0,0,0] ]
     294            sage: e1 = LFSR((x^7 + x + 1,IS_1))
     295            sage: IS_2 = [ FF(a) for a in [0,0,1,0,0,0,1,0,1] ]
     296            sage: e2 = LFSR((x^9 + x^3 + 1,IS_2))
     297            sage: E = ShrinkingGeneratorCryptosystem()
     298            sage: e = E((e1,e2)); e
     299            Shrinking generator cipher on Free binary string monoid
     300        """
     301        return "Shrinking generator cipher on %s" % self.domain()
  • sage/monoids/free_abelian_monoid_element.py

    diff -r 7fc8b5794aca -r 5d9b9378ee4f sage/monoids/free_abelian_monoid_element.py
    a b  
    55
    66- David Kohel (2005-09)
    77
    8 EXAMPLES: Recall the example from abelian monoids.
     8EXAMPLES:
     9
     10Recall the example from abelian monoids.
    911
    1012::
    1113
     
    4446from sage.structure.element import MonoidElement, generic_power
    4547
    4648def is_FreeAbelianMonoidElement(x):
     49    r"""
     50    Queries whether ``x`` is an object of type ``FreeAbelianMonoidElement``.
     51
     52    INPUT:
     53
     54    - ``x`` -- an object.
     55
     56    OUTPUT:
     57
     58    - ``True`` if ``x`` is an object of type ``FreeAbelianMonoidElement``;
     59      ``False`` otherwise.
     60    """
    4761    return isinstance(x, FreeAbelianMonoidElement)
    4862
    4963class FreeAbelianMonoidElement(MonoidElement):
  • sage/monoids/string_monoid.py

    diff -r 7fc8b5794aca -r 5d9b9378ee4f sage/monoids/string_monoid.py
    a b  
    11r"""
    22Free String Monoids
    33
    4 AUTHOR: David Kohel <kohel@maths.usyd.edu.au>, 2007-01
     4AUTHORS:
     5
     6- David Kohel <kohel@maths.usyd.edu.au>, 2007-01
    57
    68Sage supports a wide range of specific free string monoids.
    79"""
     
    2527
    2628def BinaryStrings():
    2729    r"""
    28     Returns the free binary string monoid on generators $\{0,1\}$.
     30    Returns the free binary string monoid on generators `\{ 0, 1 \}`.
    2931   
    30     INPUT: None
     32    OUTPUT:
    3133
    32     OUTPUT:
    33         Free binary string monoid
     34    - Free binary string monoid.
    3435
    35     EXAMPLES:
     36    EXAMPLES::
     37
    3638        sage: S = BinaryStrings(); S
    3739        Free binary string monoid
    3840        sage: u = S('')
     
    6365
    6466def OctalStrings():
    6567    r"""
    66     Returns the free octal string monoid on generators $\{0,1,..,7\}$.
     68    Returns the free octal string monoid on generators `\{ 0, 1, \dots, 7 \}`.
    6769   
    68     INPUT: None
     70    OUTPUT:
    6971
    70     OUTPUT:
    71         Free octal string monoid
     72    - Free octal string monoid.
    7273
    73     EXAMPLES:
     74    EXAMPLES::
     75
    7476        sage: S = OctalStrings(); S
    7577        Free octal string monoid
    7678        sage: x = S.gens()
     
    9395def HexadecimalStrings():
    9496    r"""
    9597    Returns the free hexadecimal string monoid on generators
    96     $\{0,1,..,9,a,b,c,d,e,f\}$.
     98    `\{ 0, 1, \dots , 9, a, b, c, d, e, f \}`.
    9799   
    98     INPUT: None
     100    OUTPUT:
    99101
    100     OUTPUT:
    101         Free hexadecimal string monoid
     102    - Free hexadecimal string monoid.
    102103
    103     EXAMPLES:
     104    EXAMPLES::
     105
    104106        sage: S = HexadecimalStrings(); S
    105107        Free hexadecimal string monoid
    106108        sage: x = S.gen(0)
     
    123125def Radix64Strings():
    124126    r"""
    125127    Returns the free radix 64 string monoid on 64 generators
    126     $$
    127     \{
    128        A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,
    129        a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z,
    130        0,1,2,3,4,5,6,7,8,9,+,/
    131     \}.
    132     $$
     128
     129    ::
     130
     131        A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,
     132        a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z,
     133        0,1,2,3,4,5,6,7,8,9,+,/
    133134   
    134     INPUT: None
     135    OUTPUT:
    135136
    136     OUTPUT:
    137         Free radix 64 string monoid
     137    - Free radix 64 string monoid.
    138138
    139     EXAMPLES:
     139    EXAMPLES::
     140
    140141        sage: S = Radix64Strings(); S
    141142        Free radix 64 string monoid
    142143        sage: x = S.gens()
     
    159160def AlphabeticStrings():
    160161    r"""
    161162    Returns the string monoid on generators A-Z:
    162     $$
    163     \{ A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z \}
    164     $$
     163    `\{ A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z \}`.
    165164   
    166     INPUT: None
     165    OUTPUT:
    167166
    168     OUTPUT:
    169         Free alphabetic string monoid on A-Z.
     167    - Free alphabetic string monoid on A-Z.
    170168
    171     EXAMPLES:
     169    EXAMPLES::
     170
    172171        sage: S = AlphabeticStrings(); S
    173172        Free alphabetic string monoid on A-Z
    174173        sage: x = S.gens()
     
    190189
    191190class StringMonoid_class(FreeMonoid_class):
    192191    r"""
    193     A free string monoid on $n$ generators.
     192    A free string monoid on `n` generators.
    194193    """
    195     def __init__(self,n,alphabet=()):
     194    def __init__(self, n, alphabet=()):
    196195        r"""
    197         Create free binary string monoid on $n$ generators$.
     196        Create free binary string monoid on `n` generators.
    198197
    199         INPUT:
    200             n: Integer
    201             alphabet: String or tuple whose characters or elements denote the generators.
     198        INPUT:
     199
     200        - ``n`` -- Integer
     201
     202        - ``alphabet`` -- String or tuple whose characters or elements denote
     203          the generators.
    202204       
    203         EXAMPLES:
     205        EXAMPLES::
     206
    204207            sage: S = BinaryStrings(); S
    205208            Free binary string monoid
    206209            sage: x = S.gens()
     
    220223
    221224    def gen(self,i=0):
    222225        r"""
    223         The $i$-th generator of the monoid.
     226        The `i`-th generator of the monoid.
    224227
    225228        INPUT:
    226             i -- integer (default: 0)
    227229
    228         EXAMPLES:
     230        - ``i`` -- integer (default: 0)
     231
     232        EXAMPLES::
     233
    229234            sage: S = BinaryStrings()
    230235            sage: S.gen(0)
    231236            0
     
    256261
    257262class BinaryStringMonoid(StringMonoid_class):
    258263    r"""
    259     The free binary string monoid on generators $\{0,1\}$.
     264    The free binary string monoid on generators `\{ 0, 1 \}`.
    260265    """
    261266    def __init__(self):
    262267        r"""
    263         Create free binary string monoid on generators $\{0,1\}$.
     268        Create free binary string monoid on generators `\{ 0, 1 \}`.
    264269
    265         INPUT: None
    266        
    267         EXAMPLES:
     270        EXAMPLES::
     271
    268272            sage: S = BinaryStrings(); S
    269273            Free binary string monoid
    270274            sage: x = S.gens()
     
    283287
    284288    def __call__(self, x, check=True):
    285289        r"""
    286         Return $x$ coerced into this free monoid.
     290        Return ``x`` coerced into this free monoid.
    287291
    288292        One can create a free binary string monoid element from a
    289         Python string of 0's and 1's or list integers
     293        Python string of 0's and 1's or list of integers.
    290294
    291         NOTE: Due to the ambiguity of the second generator '1' with the that the
    292         identity element '' of the monoid, the syntax S(1) is not permissible.
     295        NOTE: Due to the ambiguity of the second generator '1' with
     296        the identity element '' of the monoid, the syntax S(1) is not
     297        permissible.
    293298
    294         EXAMPLES:
     299        EXAMPLES::
     300
    295301            sage: S = BinaryStrings()
    296302            sage: S('101')
    297303            101
     
    312318                               
    313319    def encoding(self,S,padic=False):
    314320        r"""
    315         The binary encoding of the string S, as a binary string element.
     321        The binary encoding of the string ``S``, as a binary string element.
    316322   
    317323        The default is to keep the standard ASCII byte encoding, e.g.
    318324
     325        ::
     326
    319327            A = 65 -> 01000001
    320328            B = 66 -> 01000010
    321329            .
     
    325333       
    326334        rather than a 2-adic representation 65 -> 10000010.   
    327335
    328         Set padic = True to reverse the bit string.
     336        Set ``padic=True`` to reverse the bit string.
    329337
    330         EXAMPLES:       
     338        EXAMPLES::
     339
    331340            sage: S = BinaryStrings()
    332341            sage: S.encoding('A')
    333342            01000001
     
    349358            bit_string.extend(bits)
    350359        return self(bit_string)
    351360
     361    # def ngens(self):
     362    #     r"""
     363    #     Return the number of generators of this free binary string monoid.
     364    #     There are only 2 elements in the binary number system. Hence, this
     365    #     is the number of generators.
     366
     367    #     EXAMPLES::
     368
     369    #         sage: S = BinaryStrings()
     370    #         sage: S.ngens()
     371    #         2
     372    #     """
     373    #     return 2
     374
    352375class OctalStringMonoid(StringMonoid_class):
    353376    r"""
    354     The free octal string monoid on generators $\{0,1,..,7\}$.
     377    The free octal string monoid on generators `\{ 0, 1, \dots, 7 \}`.
    355378    """
    356379    def __init__(self):
    357380        r"""
    358         Create free octal string monoid on generators $\{0,1,..,7\}$.
     381        Create free octal string monoid on generators `\{ 0, 1, \dots, 7 \}`.
    359382
    360         INPUT: None
    361        
    362         EXAMPLES:
     383        EXAMPLES::
     384
    363385            sage: S = OctalStrings(); S
    364386            Free octal string monoid
    365387            sage: x = S.gens()
     
    380402
    381403    def __call__(self, x, check=True):
    382404        r"""
    383         Return $x$ coerced into this free monoid.
     405        Return ``x`` coerced into this free monoid.
    384406
    385407        One can create a free octal string monoid element from a
    386408        Python string of 0's to 7's or list of integers.
    387409
    388         EXAMPLES:
     410        EXAMPLES::
     411
    389412            sage: S = OctalStrings()
    390413            sage: S('07070701650165')
    391414            07070701650165
     
    408431
    409432class HexadecimalStringMonoid(StringMonoid_class):
    410433    r"""
    411     The free hexadecimal string monoid on generators $\{0,1,..,9,a,b,c,d,e,f\}$.
     434    The free hexadecimal string monoid on generators
     435    `\{ 0, 1, \dots, 9, a, b, c, d, e, f \}`.
    412436    """
    413437    def __init__(self):
    414438        r"""
    415         Create free hexadecimal string monoid on generators $\{0,1,..,9,a,b,c,d,e,f\}$.
     439        Create free hexadecimal string monoid on generators
     440        `\{ 0, 1, \dots, 9, a, b, c, d, e, f \}`.
    416441
    417         INPUT: None
    418        
    419         EXAMPLES:
     442        EXAMPLES::
     443
    420444            sage: S = HexadecimalStrings(); S
    421445            Free hexadecimal string monoid
    422446            sage: x = S.gens()
     
    438462
    439463    def __call__(self, x, check=True):
    440464        r"""
    441         Return $x$ coerced into this free monoid.
     465        Return ``x`` coerced into this free monoid.
    442466
    443467        One can create a free hexadecimal string monoid element from a
    444         Python string of a list of integers in $\{0,..,15\}$.
     468        Python string of a list of integers in `\{ 0, \dots, 15 \}`.
    445469
    446         EXAMPLES:
     470        EXAMPLES::
     471
    447472            sage: S = HexadecimalStrings()
    448473            sage: S('0a0a0a019f019f')
    449474            0a0a0a019f019f
     
    466491
    467492    def encoding(self,S,padic=False):
    468493        r"""
    469         The encoding of the string S, as a hexadecimal string element.
     494        The encoding of the string ``S`` as a hexadecimal string element.
    470495   
    471496        The default is to keep the standard right-to-left byte encoding, e.g.
    472497
     498        ::
     499
    473500            A = '\x41' -> 41
    474501            B = '\x42' -> 42
    475502            .
     
    481508        Although standard (e.g., in the Python constructor '\xhh'),
    482509        this can be confusing when the string reads left-to-right.
    483510
    484         Set padic = True to reverse the character encoding.
     511        Set ``padic=True`` to reverse the character encoding.
    485512
    486         EXAMPLES:       
     513        EXAMPLES::
     514
    487515            sage: S = HexadecimalStrings()
    488516            sage: S.encoding('A')
    489517            41
     
    514542        r"""
    515543        Create free radix 64 string monoid on 64 generators.
    516544
    517         INPUT: None
    518        
    519         EXAMPLES:
     545        EXAMPLES::
     546
    520547            sage: S = Radix64Strings(); S
    521548            Free radix 64 string monoid
    522549            sage: x = S.gens()
     
    539566
    540567    def __call__(self, x, check=True):
    541568        r"""
    542         Return $x$ coerced into this free monoid.
     569        Return ``x`` coerced into this free monoid.
    543570
    544571        One can create a free radix 64 string monoid element from a
    545         Python string or a list of integers in $0,..,63$, as for
    546         generic FreeMonoids. 
     572        Python string or a list of integers in `0, \dots, 63`, as for
     573        generic ``FreeMonoids``.
    547574
    548         EXAMPLES:
     575        EXAMPLES::
     576
    549577            sage: S = Radix64Strings()
    550578            sage: S.gen(0)
    551579            A
     
    571599class AlphabeticStringMonoid(StringMonoid_class):
    572600    """
    573601    The free alphabetic string monoid on generators A-Z.
     602
     603    EXAMPLES::
     604
     605        sage: S = AlphabeticStrings(); S
     606        Free alphabetic string monoid on A-Z
     607        sage: S.gen(0)
     608        A
     609        sage: S.gen(25)
     610        Z
     611        sage: S([ i for i in range(26) ])
     612        ABCDEFGHIJKLMNOPQRSTUVWXYZ
    574613    """
    575614    def __init__(self):
    576615        r"""
    577616        Create free alphabetic string monoid on generators A-Z.
    578617
    579         INPUT: None
    580        
    581         EXAMPLES:
     618        EXAMPLES::
     619
    582620            sage: S = AlphabeticStrings(); S
    583621            Free alphabetic string monoid on A-Z
    584622            sage: S.gen(0)
     
    601639
    602640    def __call__(self, x, check=True):
    603641        r"""
    604         Return $x$ coerced into this free monoid.
     642        Return ``x`` coerced into this free monoid.
    605643
    606644        One can create a free alphabetic string monoid element from a
    607         Python string, or a list of integers in $0,..,25$.
     645        Python string, or a list of integers in `0, \dots,25`.
    608646
    609         EXAMPLES:
     647        EXAMPLES::
     648
    610649            sage: S = AlphabeticStrings()
    611650            sage: S.gen(0)
    612651            A
     
    629668
    630669    def encoding(self,S):
    631670        r"""
    632         The encoding of the string S in the alphabetic string monoid,
    633         obtained by the monoid homomorphism
    634         \begin{verbatim}
     671        The encoding of the string ``S`` in the alphabetic string monoid,
     672        obtained by the monoid homomorphism
     673
     674        ::
     675
    635676            A -> A, ..., Z -> Z, a -> A, ..., z -> Z
    636         \end{verbatim}
    637         and stripping away all other characters.
    638677
    639         It should be noted that this is a non-injective monoid homomorphism.
     678        and stripping away all other characters. It should be noted that
     679        this is a non-injective monoid homomorphism.
    640680
    641         EXAMPLES:
     681        EXAMPLES::
     682
    642683            sage: S = AlphabeticStrings()
    643684            sage: s = S.encoding("The cat in the hat."); s
    644685            THECATINTHEHAT
     
    646687            'THECATINTHEHAT'
    647688        """
    648689        return self(strip_encoding(S))
    649 
    650 
    651 
  • sage/monoids/string_monoid_element.py

    diff -r 7fc8b5794aca -r 5d9b9378ee4f sage/monoids/string_monoid_element.py
    a b  
    11"""
    22String Monoid Elements
    33
    4 AUTHOR: David Kohel <kohel@maths.usyd.edu.au>, 2007-01
     4AUTHORS:
     5
     6- David Kohel <kohel@maths.usyd.edu.au>, 2007-01
    57
    68Elements of free string monoids, internal representation subject to change.
    79
     
    5759    """
    5860    def __init__(self, S, x, check=True):
    5961        """
    60         Create the element $x$ of the StringMonoid $S$.
     62        Create the element ``x`` of the StringMonoid ``S``.
    6163
    6264        This should typically be called by a StringMonoid.
    6365        """
     
    8789        The ordering is the one on the underlying sorted list of
    8890        (monomial,coefficients) pairs.
    8991
    90         EXAMPLES:
     92        EXAMPLES::
     93
    9194            sage: S = BinaryStrings()
    9295            sage: (x,y) = S.gens()
    9396            sage: x * y < y * x
     
    115118        """
    116119        Return latex representation of self.
    117120
    118         EXAMPLES:
     121        EXAMPLES::
     122
    119123            sage: S = BinaryStrings()
    120124            sage: s = S('101111000')
    121125            sage: latex(s)
     
    127131        """
    128132        Multiply 2 free string monoid elements.
    129133
    130         EXAMPLES:
     134        EXAMPLES::
     135
    131136            sage: S = BinaryStrings()
    132137            sage: (x,y) = S.gens()
    133138            sage: x*y
     
    144149
    145150    def __pow__(self, n):
    146151        """
    147         Return the $n$-th power of the string element.
     152        Return the `n`-th power of the string element.
    148153
    149         EXAMPLES:
     154        EXAMPLES::
     155
    150156            sage: (x,y) = BinaryStrings().gens()
    151157            sage: x**3 * y**5 * x**7
    152158            000111110000000
    153159            sage: x**0
    154160           
    155161
    156         Note that raising to a negative power is \emph{not} a constructor
     162        Note that raising to a negative power is *not* a constructor
    157163        for an element of the corresponding free group (yet).
     164
     165        ::
     166
    158167            sage: x**(-1)
    159168            Traceback (most recent call last):
    160169            ...
     
    176185        """
    177186        Return the number of products that occur in this monoid element.
    178187        For example, the length of the identity is 0, and the length
    179         of the monoid $x_0^2x_1$ is three.
     188        of the monoid `x_0^2x_1` is three.
    180189
    181         EXAMPLES:
     190        EXAMPLES::
     191
    182192            sage: S = BinaryStrings()
    183193            sage: z = S('')
    184194            sage: len(z)
     
    202212        return self.parent()(c)
    203213
    204214    def decoding(self,padic=False):
    205         """
     215        r"""
    206216        The byte string associated to a binary or hexadecimal string monoid element.
    207217
    208         EXAMPLES:
     218        EXAMPLES::
     219
    209220            sage: S = HexadecimalStrings()
    210221            sage: s = S.encoding("A..Za..z"); s
    211222            412e2e5a612e2e7a