Utility Functions for Cryptography - Cryptography

Skip to content
Back to top
View this page
Edit this page

# Utility Functions for Cryptography

Miscellaneous utility functions for cryptographic purposes.

AUTHORS:

- Minh Van Nguyen (2009-12): initial version with the following functions: `ascii_integer`, `ascii_to_bin`, `bin_to_ascii`, `has_blum_prime`, `is_blum_prime`, `least_significant_bits`, `random_blum_prime`.

sage.crypto.util.ascii_integer(B)

  Return the ASCII integer corresponding to the binary string `B`.

  INPUT:

  - `B` – a non-empty binary string or a non-empty list of bits. The number of bits in `B` must be 8

  OUTPUT: the ASCII integer corresponding to the 8-bit block `B`

  EXAMPLES:

  The ASCII integers of some binary strings:

  Sage

      sage: from sage.crypto.util import ascii_integer
      sage: bin = BinaryStrings()
      sage: B = bin.encoding("A"); B
      01000001
      sage: ascii_integer(B)
      65
      sage: B = bin.encoding("C"); list(B)
      [0, 1, 0, 0, 0, 0, 1, 1]
      sage: ascii_integer(list(B))
      67
      sage: ascii_integer("01000100")
      68
      sage: ascii_integer([0, 1, 0, 0, 0, 1, 0, 1])
      69

  Python

      >>> from sage.all import *
      >>> from sage.crypto.util import ascii_integer
      >>> bin = BinaryStrings()
      >>> B = bin.encoding("A"); B
      01000001
      >>> ascii_integer(B)
      65
      >>> B = bin.encoding("C"); list(B)
      [0, 1, 0, 0, 0, 0, 1, 1]
      >>> ascii_integer(list(B))
      67
      >>> ascii_integer("01000100")
      68
      >>> ascii_integer([Integer(0), Integer(1), Integer(0), Integer(0), Integer(0), Integer(1), Integer(0), Integer(1)])
      69

sage.crypto.util.ascii_to_bin(A)

  Return the binary representation of the ASCII string `A`.

  INPUT:

  - `A` – string or list of ASCII characters

  OUTPUT: the binary representation of `A`

  ALGORITHM:

  Let \(A = a_0 a_1 \cdots a_{n-1}\) be an ASCII string, where each \(a_i\) is an ASCII character. Let \(c_i\) be the ASCII integer corresponding to \(a_i\) and let \(b_i\) be the binary representation of \(c_i\). The binary representation \(B\) of \(A\) is \(B = b_0 b_1 \cdots b_{n-1}\).

  EXAMPLES:

  The binary representation of some ASCII strings:

  Sage

      sage: from sage.crypto.util import ascii_to_bin
      sage: ascii_to_bin("A")
      01000001
      sage: ascii_to_bin("Abc123")
      010000010110001001100011001100010011001000110011

  Python

      >>> from sage.all import *
      >>> from sage.crypto.util import ascii_to_bin
      >>> ascii_to_bin("A")
      01000001
      >>> ascii_to_bin("Abc123")
      010000010110001001100011001100010011001000110011

  The empty string is different from the string with one space character. For the empty string and the empty list, this function returns the same result:

  Sage

      sage: from sage.crypto.util import ascii_to_bin
      sage: ascii_to_bin("")

      sage: ascii_to_bin(" ")
      00100000
      sage: ascii_to_bin([])

  [Python]

      >>> from sage.all import *
      >>> from sage.crypto.util import ascii_to_bin
      >>> ascii_to_bin("")
      <BLANKLINE>
      >>> ascii_to_bin(" ")
      00100000
      >>> ascii_to_bin([])
      <BLANKLINE>

  This function also accepts a list of ASCII characters. You can also pass in a list of strings:

  Sage

      sage: from sage.crypto.util import ascii_to_bin
      sage: ascii_to_bin(["A", "b", "c", "1", "2", "3"])
      010000010110001001100011001100010011001000110011
      sage: ascii_to_bin(["A", "bc", "1", "23"])
      010000010110001001100011001100010011001000110011

  Python

      >>> from sage.all import *
      >>> from sage.crypto.util import ascii_to_bin
      >>> ascii_to_bin(["A", "b", "c", "1", "2", "3"])
      010000010110001001100011001100010011001000110011
      >>> ascii_to_bin(["A", "bc", "1", "23"])
      010000010110001001100011001100010011001000110011

sage.crypto.util.bin_to_ascii(B)

  Return the ASCII representation of the binary string `B`.

  INPUT:

  - `B` – a non-empty binary string or a non-empty list of bits. The number of bits in `B` must be a multiple of 8

  OUTPUT: the ASCII string corresponding to `B`

  ALGORITHM:

  Consider a block of bits \(B = b_0 b_1 \cdots b_{n-1}\) where each sub-block \(b_i\) is a binary string of length 8. Then the total number of bits is a multiple of 8 and is given by \(8n\). Let \(c_i\) be the integer representation of \(b_i\). We can consider \(c_i\) as the integer representation of an ASCII character. Then the ASCII representation \(A\) of \(B\) is \(A = a_0 a_1 \cdots a_{n-1}\).

  EXAMPLES:

  Convert some ASCII strings to their binary representations and recover the ASCII strings from the binary representations:

  Sage

      sage: from sage.crypto.util import ascii_to_bin
      sage: from sage.crypto.util import bin_to_ascii
      sage: A = "Abc"
      sage: B = ascii_to_bin(A); B
      010000010110001001100011
      sage: bin_to_ascii(B)
      'Abc'
      sage: bin_to_ascii(B) == A
      True

  Python

      >>> from sage.all import *
      >>> from sage.crypto.util import ascii_to_bin
      >>> from sage.crypto.util import bin_to_ascii
      >>> A = "Abc"
      >>> B = ascii_to_bin(A); B
      010000010110001001100011
      >>> bin_to_ascii(B)
      'Abc'
      >>> bin_to_ascii(B) == A
      True

  Sage

      sage: A = "123 \" #"
      sage: B = ascii_to_bin(A); B
      00110001001100100011001100100000001000100010000000100011
      sage: bin_to_ascii(B)
      '123 " #'
      sage: bin_to_ascii(B) == A
      True

  [Python]

      >>> from sage.all import *
      >>> A = "123 \" #"
      >>> B = ascii_to_bin(A); B
      00110001001100100011001100100000001000100010000000100011
      >>> bin_to_ascii(B)
      '123 " #'
      >>> bin_to_ascii(B) == A
      True

  This function also accepts strings and lists of bits:

  Sage

      sage: from sage.crypto.util import bin_to_ascii
      sage: bin_to_ascii("010000010110001001100011")
      'Abc'
      sage: bin_to_ascii([0, 1, 0, 0, 0, 0, 0, 1])
      'A'

  Python

      >>> from sage.all import *
      >>> from sage.crypto.util import bin_to_ascii
      >>> bin_to_ascii("010000010110001001100011")
      'Abc'
      >>> bin_to_ascii([Integer(0), Integer(1), Integer(0), Integer(0), Integer(0), Integer(0), Integer(0), Integer(1)])
      'A'

sage.crypto.util.has_blum_prime(lbound, ubound)

  Determine whether or not there is a Blum prime within the specified closed interval.

  INPUT:

  - `lbound` – positive integer; the lower bound on how small a Blum prime can be. The lower bound must be distinct from the upper bound.

  - `ubound` – positive integer; the upper bound on how large a Blum prime can be. The lower bound must be distinct from the upper bound.

  OUTPUT:

  - `True` if there is a Blum prime `p` such that `lbound <= p <= ubound`. `False` otherwise.

  ALGORITHM:

  Let \(L\) and \(U\) be distinct positive integers. Let \(P\) be the set of all odd primes \(p\) such that \(L \leq p \leq U\). Our main focus is on Blum primes, i.e. odd primes that are congruent to 3 modulo 4, so we assume that the lower bound \(L > 2\). The closed interval \([L, U]\) has a Blum prime if and only if the set \(P\) has a Blum prime.

  EXAMPLES:

  Testing for the presence of Blum primes within some closed intervals. The interval \([4, 100]\) has a Blum prime, the smallest such prime being 7. The interval \([24, 28]\) has no primes, hence no Blum primes.

  Sage

      sage: from sage.crypto.util import has_blum_prime
      sage: from sage.crypto.util import is_blum_prime
      sage: has_blum_prime(4, 100)                                                    # needs sage.libs.pari
      True
      sage: for n in range(4, 100):
      ....:     if is_blum_prime(n):
      ....:         print(n)
      ....:         break
      7
      sage: has_blum_prime(24, 28)                                                    # needs sage.libs.pari
      False

  Python

      >>> from sage.all import *
      >>> from sage.crypto.util import has_blum_prime
      >>> from sage.crypto.util import is_blum_prime
      >>> has_blum_prime(Integer(4), Integer(100))                                                    # needs sage.libs.pari
      True
      >>> for n in range(Integer(4), Integer(100)):
      ...     if is_blum_prime(n):
      ...         print(n)
      ...         break
      7
      >>> has_blum_prime(Integer(24), Integer(28))                                                    # needs sage.libs.pari
      False

sage.crypto.util.is_blum_prime(n)

  Determine whether or not `n` is a Blum prime.

  INPUT:

  - `n` – a positive prime

  OUTPUT: `True` if `n` is a Blum prime; `False` otherwise

  Let \(n\) be a positive prime. Then \(n\) is a Blum prime if \(n\) is congruent to 3 modulo 4, i.e. \(n \equiv 3 \pmod{4}\).

  EXAMPLES:

  Testing some integers to see if they are Blum primes:

  Sage

      sage: from sage.crypto.util import is_blum_prime
      sage: from sage.crypto.util import random_blum_prime
      sage: is_blum_prime(101)
      False
      sage: is_blum_prime(7)
      True
      sage: p = random_blum_prime(10**3, 10**5)                                       # needs sage.libs.pari
      sage: is_blum_prime(p)                                                          # needs sage.libs.pari
      True

  Python

      >>> from sage.all import *
      >>> from sage.crypto.util import is_blum_prime
      >>> from sage.crypto.util import random_blum_prime
      >>> is_blum_prime(Integer(101))
      False
      >>> is_blum_prime(Integer(7))
      True
      >>> p = random_blum_prime(Integer(10)**Integer(3), Integer(10)**Integer(5))                                       # needs sage.libs.pari
      >>> is_blum_prime(p)                                                          # needs sage.libs.pari
      True

sage.crypto.util.least_significant_bits(n, k)

  Return the `k` least significant bits of `n`.

  INPUT:

  - `n` – integer

  - `k` – positive integer

  OUTPUT:

  - The `k` least significant bits of the integer `n`. If `k=1`, then return the parity bit of the integer `n`. Let \(b\) be the binary representation of `n`, where \(m\) is the length of the binary string \(b\). If \(k \geq m\), then return the binary representation of `n`.

  EXAMPLES:

  Obtain the parity bits of some integers:

  Sage

      sage: from sage.crypto.util import least_significant_bits
      sage: least_significant_bits(0, 1)
      [0]
      sage: least_significant_bits(2, 1)
      [0]
      sage: least_significant_bits(3, 1)
      [1]
      sage: least_significant_bits(-2, 1)
      [0]
      sage: least_significant_bits(-3, 1)
      [1]

  Python

      >>> from sage.all import *
      >>> from sage.crypto.util import least_significant_bits
      >>> least_significant_bits(Integer(0), Integer(1))
      [0]
      >>> least_significant_bits(Integer(2), Integer(1))
      [0]
      >>> least_significant_bits(Integer(3), Integer(1))
      [1]
      >>> least_significant_bits(-Integer(2), Integer(1))
      [0]
      >>> least_significant_bits(-Integer(3), Integer(1))
      [1]

  Obtain the 4 least significant bits of some integers:

  Sage

      sage: least_significant_bits(101, 4)
      [0, 1, 0, 1]
      sage: least_significant_bits(-101, 4)
      [0, 1, 0, 1]
      sage: least_significant_bits(124, 4)
      [1, 1, 0, 0]
      sage: least_significant_bits(-124, 4)
      [1, 1, 0, 0]

  [Python]

      >>> from sage.all import *
      >>> least_significant_bits(Integer(101), Integer(4))
      [0, 1, 0, 1]
      >>> least_significant_bits(-Integer(101), Integer(4))
      [0, 1, 0, 1]
      >>> least_significant_bits(Integer(124), Integer(4))
      [1, 1, 0, 0]
      >>> least_significant_bits(-Integer(124), Integer(4))
      [1, 1, 0, 0]

  The binary representation of 123:

  Sage

      sage: n = 123; b = n.binary(); b
      '1111011'
      sage: least_significant_bits(n, len(b))
      [1, 1, 1, 1, 0, 1, 1]

  Python

      >>> from sage.all import *
      >>> n = Integer(123); b = n.binary(); b
      '1111011'
      >>> least_significant_bits(n, len(b))
      [1, 1, 1, 1, 0, 1, 1]

sage.crypto.util.random_blum_prime(lbound, ubound, ntries=100)

  A random Blum prime within the specified bounds.

  Let \(p\) be a positive prime. Then \(p\) is a Blum prime if \(p\) is congruent to 3 modulo 4, i.e. \(p \equiv 3 \pmod{4}\).

  INPUT:

  - `lbound` – positive integer; the lower bound on how small a random Blum prime \(p\) can be. So we have `0 < lbound <= p <= ubound`. The lower bound must be distinct from the upper bound.

  - `ubound` – positive integer; the upper bound on how large a random Blum prime \(p\) can be. So we have `0 < lbound <= p <= ubound`. The lower bound must be distinct from the upper bound.

  - `ntries` – (default: `100`) the number of attempts to generate a random Blum prime. If `ntries` is a positive integer, then perform that many attempts at generating a random Blum prime. This might or might not result in a Blum prime.

  OUTPUT: a random Blum prime within the specified lower and upper bounds

  Note

  Beware that there might not be any primes between the lower and upper bounds. So make sure that these two bounds are “sufficiently” far apart from each other for there to be primes congruent to 3 modulo 4. In particular, there should be at least two distinct Blum primes within the specified bounds.

  EXAMPLES:

  Choose a random prime and check that it is a Blum prime:

  Sage

      sage: from sage.crypto.util import random_blum_prime
      sage: p = random_blum_prime(10**4, 10**5)                                       # needs sage.libs.pari
      sage: is_prime(p)                                                               # needs sage.libs.pari
      True
      sage: mod(p, 4) == 3                                                            # needs sage.libs.pari
      True

  Python

      >>> from sage.all import *
      >>> from sage.crypto.util import random_blum_prime
      >>> p = random_blum_prime(Integer(10)**Integer(4), Integer(10)**Integer(5))                                       # needs sage.libs.pari
      >>> is_prime(p)                                                               # needs sage.libs.pari
      True
      >>> mod(p, Integer(4)) == Integer(3)                                                            # needs sage.libs.pari
      True