code: def millerRabin(n, k):
      
      assert n >= 1
      # ensure n is bigger than 1
      assert k > 0
      # ensure k is a positive integer so everything down here makes sense
  
      if n == 2:
          return True
      # make sure to return True if n == 2
  
      if n % 2 == 0:
          return False
      # immediately return False for all the even numbers bigger than 2
  
      extract2 = extractTwos(n - 1)
      s = extract2[0]
      d = extract2[1]
      assert 2 ** s * d == n - 1
  
      def tryComposite(a):
          """Inner function which will inspect whether a given witness
          will reveal the true identity of n. Will only be called within
          millerRabin"""
          x = modExp(a, d, n)
          if x == 1 or x == n - 1:
              return None
          else:
              for j in range(1, s):
                  x = modExp(x, 2, n)
                  if x == 1:
                      return False
                  elif x == n - 1:
                      return None
              return False
  
      for i in range(0, k):
          a = random.randint(2, n - 2)
          if tryComposite(a) == False:
              return False
      return True
docs: Miller Rabin pseudo-prime test
      return True means likely a prime, (how sure about that, depending on k)
      return False means definitely a composite.
      Raise assertion error when n, k are not positive integers
      and n is not 1