def randint(self, a, b): """Return a random integer N such that a <= N <= b.""" if not is_native_int(a) or not is_native_int(b): raise TypeError("randint requires integer arguments") N = self.randrange(a, b + 1) assert a <= N <= b return N
def randrange(self, *args): """randrange([start,] stop[, step]): Return a randomly-selected element from range(start, stop, step).""" if len(args) == 3: (start, stop, step) = args elif len(args) == 2: (start, stop) = args step = 1 elif len(args) == 1: (stop, ) = args start = 0 step = 1 else: raise TypeError("randrange expected at most 3 arguments, got %d" % (len(args), )) if (not is_native_int(start) or not is_native_int(stop) or not is_native_int(step)): raise TypeError("randrange requires integer arguments") if step == 0: raise ValueError("randrange step argument must not be zero") num_choices = ceil_div(stop - start, step) if num_choices < 0: num_choices = 0 if num_choices < 1: raise ValueError("empty range for randrange(%r, %r, %r)" % (start, stop, step)) # Pick a random number in the range of possible numbers r = num_choices while r >= num_choices: r = self.getrandbits(size(num_choices)) return start + (step * r)
def randrange(self, *args): """randrange([start,] stop[, step]): Return a randomly-selected element from range(start, stop, step).""" if len(args) == 3: (start, stop, step) = args elif len(args) == 2: (start, stop) = args step = 1 elif len(args) == 1: (stop,) = args start = 0 step = 1 else: raise TypeError("randrange expected at most 3 arguments, got %d" % (len(args),)) if (not is_native_int(start) or not is_native_int(stop) or not is_native_int(step)): raise TypeError("randrange requires integer arguments") if step == 0: raise ValueError("randrange step argument must not be zero") num_choices = ceil_div(stop - start, step) if num_choices < 0: num_choices = 0 if num_choices < 1: raise ValueError("empty range for randrange(%r, %r, %r)" % (start, stop, step)) # Pick a random number in the range of possible numbers r = num_choices while r >= num_choices: r = self.getrandbits(size(num_choices)) return start + (step * r)
def randint(self, a, b): """Return a random integer N such that a <= N <= b.""" if not is_native_int(a) or not is_native_int(b): raise TypeError("randint requires integer arguments") N = self.randrange(a, b+1) assert a <= N <= b return N
def inplace_pow(self, exponent, modulus=None): if modulus is None: if exponent < 0: raise ValueError("Exponent must not be negative") # Normal exponentiation if exponent > 256: raise ValueError("Exponent is too big") _gmp.mpz_pow_ui( self._mpz_p, self._mpz_p, # Base c_ulong(int(exponent))) else: # Modular exponentiation if not isinstance(modulus, IntegerGMP): modulus = IntegerGMP(modulus) if not modulus: raise ZeroDivisionError("Division by zero") if modulus.is_negative(): raise ValueError("Modulus must be positive") if is_native_int(exponent): if exponent < 0: raise ValueError("Exponent must not be negative") if exponent < 65536: _gmp.mpz_powm_ui(self._mpz_p, self._mpz_p, c_ulong(exponent), modulus._mpz_p) return self exponent = IntegerGMP(exponent) elif exponent.is_negative(): raise ValueError("Exponent must not be negative") _gmp.mpz_powm(self._mpz_p, self._mpz_p, exponent._mpz_p, modulus._mpz_p) return self
def __isub__(self, term): if is_native_int(term): if 0 <= term < 65536: _gmp.mpz_sub_ui(self._mpz_p, self._mpz_p, c_ulong(term)) return self if -65535 < term < 0: _gmp.mpz_add_ui(self._mpz_p, self._mpz_p, c_ulong(-term)) return self term = IntegerGMP(term) _gmp.mpz_sub(self._mpz_p, self._mpz_p, term._mpz_p) return self
def fail_if_divisible_by(self, small_prime): """Raise an exception if the small prime is a divisor.""" if is_native_int(small_prime): if 0 < small_prime < 65536: if _gmp.mpz_divisible_ui_p(self._mpz_p, c_ulong(small_prime)): raise ValueError("The value is composite") return small_prime = IntegerGMP(small_prime) if _gmp.mpz_divisible_p(self._mpz_p, small_prime._mpz_p): raise ValueError("The value is composite")
def gcd(self, term): """Compute the greatest common denominator between this number and another term.""" result = IntegerGMP(0) if is_native_int(term): if 0 < term < 65535: _gmp.mpz_gcd_ui(result._mpz_p, self._mpz_p, c_ulong(term)) return result term = IntegerGMP(term) _gmp.mpz_gcd(result._mpz_p, self._mpz_p, term._mpz_p) return result
def __imul__(self, term): if is_native_int(term): if 0 <= term < 65536: _gmp.mpz_mul_ui(self._mpz_p, self._mpz_p, c_ulong(term)) return self if -65535 < term < 0: _gmp.mpz_mul_ui(self._mpz_p, self._mpz_p, c_ulong(-term)) _gmp.mpz_neg(self._mpz_p, self._mpz_p) return self term = IntegerGMP(term) _gmp.mpz_mul(self._mpz_p, self._mpz_p, term._mpz_p) return self
def __init__(self, encoded_value): """Initialize the element to a certain value. The value passed as parameter is internally encoded as a 128-bit integer, where each bit represents a polynomial coefficient. The LSB is the constant coefficient. """ if is_native_int(encoded_value): self._value = encoded_value elif len(encoded_value) == 16: self._value = bytes_to_long(encoded_value) else: raise ValueError("The encoded value must be an integer or a 16 byte string")
def multiply_accumulate(self, a, b): """Increment the number by the product of a and b.""" if not isinstance(a, IntegerGMP): a = IntegerGMP(a) if is_native_int(b): if 0 < b < 65536: _gmp.mpz_addmul_ui(self._mpz_p, a._mpz_p, c_ulong(b)) return self if -65535 < b < 0: _gmp.mpz_submul_ui(self._mpz_p, a._mpz_p, c_ulong(-b)) return self b = IntegerGMP(b) _gmp.mpz_addmul(self._mpz_p, a._mpz_p, b._mpz_p) return self
def __init__(self, value): """Initialize the integer to the given value.""" self._mpz_p = new_mpz() self._initialized = False if isinstance(value, float): raise ValueError("A floating point type is not a natural number") self._initialized = True if is_native_int(value): _gmp.mpz_init(self._mpz_p) result = _gmp.gmp_sscanf(tobytes(str(value)), b"%Zd", self._mpz_p) if result != 1: raise ValueError("Error converting '%d'" % value) else: _gmp.mpz_init_set(self._mpz_p, value._mpz_p)
def __init__(self, value): """Initialize the integer to the given value.""" self._mpz_p = new_mpz() self._initialized = False if isinstance(value, float): raise ValueError("A floating point type is not a natural number") if is_native_int(value): _gmp.mpz_init(self._mpz_p) self._initialized = True if value == 0: return tmp = new_mpz() _gmp.mpz_init(tmp) try: positive = value >= 0 reduce = abs(value) slots = (reduce.bit_length() - 1) // 32 + 1 while slots > 0: slots = slots - 1 _gmp.mpz_set_ui( tmp, c_ulong(0xFFFFFFFF & (reduce >> (slots * 32)))) _gmp.mpz_mul_2exp(tmp, tmp, c_ulong(slots * 32)) _gmp.mpz_add(self._mpz_p, self._mpz_p, tmp) finally: _gmp.mpz_clear(tmp) if not positive: _gmp.mpz_neg(self._mpz_p, self._mpz_p) elif isinstance(value, IntegerGMP): _gmp.mpz_init_set(self._mpz_p, value._mpz_p) self._initialized = True else: raise NotImplementedError
def inplace_pow(self, exponent, modulus=None): if modulus is None: if exponent < 0: raise ValueError("Exponent must not be negative") # Normal exponentiation if exponent > 256: raise ValueError("Exponent is too big") _gmp.mpz_pow_ui(self._mpz_p, self._mpz_p, # Base c_ulong(int(exponent)) ) else: # Modular exponentiation if not isinstance(modulus, IntegerGMP): modulus = IntegerGMP(modulus) if not modulus: raise ZeroDivisionError("Division by zero") if modulus.is_negative(): raise ValueError("Modulus must be positive") if is_native_int(exponent): if exponent < 0: raise ValueError("Exponent must not be negative") if exponent < 65536: _gmp.mpz_powm_ui(self._mpz_p, self._mpz_p, c_ulong(exponent), modulus._mpz_p) return self exponent = IntegerGMP(exponent) elif exponent.is_negative(): raise ValueError("Exponent must not be negative") _gmp.mpz_powm(self._mpz_p, self._mpz_p, exponent._mpz_p, modulus._mpz_p) return self
def __ne__(self, term): if not (isinstance(term, IntegerGMP) or is_native_int(term)): return True return self._apply_and_return(_gmp.mpz_cmp, term) != 0
def _create_ctr_cipher(factory, **kwargs): """Instantiate a cipher object that performs CTR encryption/decryption. :Parameters: factory : module The underlying block cipher, a module from ``Cryptodome.Cipher``. :Keywords: nonce : bytes/bytearray/memoryview The fixed part at the beginning of the counter block - the rest is the counter number that gets increased when processing the next block. The nonce must be such that no two messages are encrypted under the same key and the same nonce. The nonce must be shorter than the block size (it can have zero length; the counter is then as long as the block). If this parameter is not present, a random nonce will be created with length equal to half the block size. No random nonce shorter than 64 bits will be created though - you must really think through all security consequences of using such a short block size. initial_value : posive integer or bytes/bytearray/memoryview The initial value for the counter. If not present, the cipher will start counting from 0. The value is incremented by one for each block. The counter number is encoded in big endian mode. counter : object Instance of ``Cryptodome.Util.Counter``, which allows full customization of the counter block. This parameter is incompatible to both ``nonce`` and ``initial_value``. Any other keyword will be passed to the underlying block cipher. See the relevant documentation for details (at least ``key`` will need to be present). """ cipher_state = factory._create_base_cipher(kwargs) counter = kwargs.pop("counter", None) nonce = kwargs.pop("nonce", None) initial_value = kwargs.pop("initial_value", None) if kwargs: raise TypeError("Invalid parameters for CTR mode: %s" % str(kwargs)) if counter is not None and (nonce, initial_value) != (None, None): raise TypeError("'counter' and 'nonce'/'initial_value'" " are mutually exclusive") if counter is None: # Cryptodome.Util.Counter is not used if nonce is None: if factory.block_size < 16: raise TypeError("Impossible to create a safe nonce for short" " block sizes") nonce = get_random_bytes(factory.block_size // 2) else: if len(nonce) >= factory.block_size: raise ValueError("Nonce is too long") # What is not nonce is counter counter_len = factory.block_size - len(nonce) if initial_value is None: initial_value = 0 if is_native_int(initial_value): if (1 << (counter_len * 8)) - 1 < initial_value: raise ValueError("Initial counter value is too large") initial_counter_block = nonce + long_to_bytes( initial_value, counter_len) else: if len(initial_value) != counter_len: raise ValueError( "Incorrect length for counter byte string (%d bytes, expected %d)" % (len(initial_value), counter_len)) initial_counter_block = nonce + initial_value return CtrMode( cipher_state, initial_counter_block, len(nonce), # prefix counter_len, False) # little_endian # Cryptodome.Util.Counter is used # 'counter' used to be a callable object, but now it is # just a dictionary for backward compatibility. _counter = dict(counter) try: counter_len = _counter.pop("counter_len") prefix = _counter.pop("prefix") suffix = _counter.pop("suffix") initial_value = _counter.pop("initial_value") little_endian = _counter.pop("little_endian") except KeyError: raise TypeError("Incorrect counter object" " (use Cryptodome.Util.Counter.new)") # Compute initial counter block words = [] while initial_value > 0: words.append(struct.pack('B', initial_value & 255)) initial_value >>= 8 words += [b'\x00'] * max(0, counter_len - len(words)) if not little_endian: words.reverse() initial_counter_block = prefix + b"".join(words) + suffix if len(initial_counter_block) != factory.block_size: raise ValueError("Size of the counter block (%d bytes) must match" " block size (%d)" % (len(initial_counter_block), factory.block_size)) return CtrMode(cipher_state, initial_counter_block, len(prefix), counter_len, little_endian)