protected function genericRand(
        $rangeMinimum,
        $rangeMaximum,
        $source = self::MODE_OPEN_SSL
    )
    {
        $diff = $rangeMaximum - ($rangeMinimum + 1);

        if ($diff > PHP_INT_MAX) {
            throw new Exception('Bad range');
        }

        // The largest *multiple* of diff less than our sample
        $ceiling = floor(PHP_INT_MAX / $diff) * $diff;

        do {
            switch ($source) {
                case self::MODE_OPEN_SSL:
                default:
                    $bytes = $this->getRandomBytesFromOpenSSL(PHP_INT_SIZE);
                    break;
            }

            /* @codeCoverageIgnoreStart */
            // Check for error
            if (false === $bytes || PHP_INT_SIZE !== strlen($bytes)) {
                throw new Exception(
                    sprintf(
                        'Failed to read %s bytes from %s.',
                        PHP_INT_SIZE,
                        'OpenSSL'
                    )
                );
            }
            /* @codeCoverageIgnoreEnd */

            if (PHP_INT_SIZE === 8) {
                // 64-bit versions
                list($higher, $lower) = array_values(unpack('N2', $bytes));
                $val = $higher << 32 | $lower;
            } else {
                // 32-bit versions
                $val = unpack('Nint', $bytes);
            }

            $val = $val['int'] & PHP_INT_MAX;
        } while ($val > $ceiling);

        // In the unlikely case our sample is bigger than largest multiple, just do over until it’s not any more.
        // Perfectly even sampling in our 0<output<diff domain is mathematically impossible unless the total number of
        // *valid* inputs is an exact multiple of diff.
        return $val % $diff + $rangeMinimum;
    }