id: Гость   вход   регистрация
текущее время 19:36 23/04/2024
Владелец: unknown (создано 10/08/2012 14:01), редакция от 30/08/2012 15:30 (автор: unknown) Печать
Категории: криптография, алгоритмы, симметричное шифрование
https://www.pgpru.com/Новости/2012/SwapOrNotПростейшиеБлочныеШифрыПретендуютНаСтойкость
создать
просмотр
редакции
ссылки

10.08 // Swap or Not: простейшие блочные шифры претендуют на стойкость


Несмотря на множество предложенных блочных шифров, в их основе лежат только два варианта конструкций: нечто, что по существу выглядит как некоторая разновидность сети Файстеля (напр. DES, FEAL, MARS, RC6) или SP-сеть (Rijndael, Safer, Serpent, Square). Соответствено, в литературе имеется описание того, как можно сконструировать псевдослучайные перестановки (Pseudo Random Permutations — PRP) из псевдослучайных функций (Pseudo Random Functions — PRF) для доказуемо-безопасных сетей Файстеля, так же как и для режимов операций, из которых могут быть созданы SP-сети (сети замены-перестановки на обратимых операциях). Возможно, что никаких других фундаментально отличающихся путей создания блочных шифров просто не существует. Но может быть просто никто не замечал других возможностей.


Исследователи Ви Тан Хо, Филип Рогуэй (Кафедра компьютерных наук Университета Калифорнии, Дэвис, США) и Бен Моррис (Кафедра математики Университета Калифорнии, Дэвис, США) предложили принципиально новую конструкцию создания блочных шифров. Консультантами в работе служили Михир Беллэйр и Терент Спайс. Следует отметить, что Рогуэй и Беллейр — одни из ведущих специалистов в области доказуемой безопасности, поэтому их разработки привлекают заслуженное внимание.


Самым удивительным свойством новых шифров является минималистичная простота. Если не рассматривать реализации ключевого расписания (авторы их не представили, но их создание может быть делом будущего), то весь шифр может уместиться в короткий однострочник, понятный практически любому программисту-любителю. Другим удивительным свойством является использование одной единственной линейной операции – XOR, которая задаёт перестановки, что приводит к созданию нелинейности. Наконец, шифр, основанный на таком прототипе, возможно будет реализован с ничтожными затратами памяти на исполнение.


Для создания новых шифров исследователи предложили конструкцию swap-or-not-сетей. Сложно перевести это столь же коротким термином, как вариант это может быть "перестановка-обмен с исключениями". В основе идеи лежат хорошо известные алгоритмы математики и комбинаторики первой половины XX века, связанные с генерацией перестановок, аналогичных перетасовке карточной колоды. Исследователям удалось привести первичные доказательства, что такие алгоритмы превосходят по соотношению затрат к стойкости обычные алгоритмы конвертирования PRF → PRP, используемые для создания блочных шифров. Помимо этого, такие алгоритмы претендуют на наилучшее решение проблемы шифрования с сохранением длины и формата сообщения (Format-Preserving Encryption — FPE), когда необходимо шифровать данные, имеющие размер меньше блока традиционного шифра, но при этом именно в блочном режиме, а не наложением гаммы. Такая задача может возникнуть при шифровании номеров PIN, социального страхования, записей в базах данных, использовании недвоичных систем счисления, с возможностью как компромисса в сторону пониженной стойкости, так и с сохранением стойкости на обычном уровне.


Несмотря на то, что алгоритм удивительно простой, следует по порядку рассмотреть несколько вариантов — от простого к сложному, хотя каждый из них сам по себе может стать прототипом каких-либо полезных реализаций.


Рис. 1. Swap or Not (17 Кб)

Пусть первое значение X — это n-битовый исходный текст из множества χ = {0,1}n. Пусть на каждом раунде значение X подвергается операции XOR с n-битовым раундовым подключом Ki, результат записывается как X'. Затем следует сравнить, какое значение получилось больше: X или X' и записать большее значение в Xˆ. Затем нужно применить n-битовую функцию раунда Fi(Xˆ), которая является уникальной для каждого раунда и выдаёт псевдослучайную свёртку в виде однобитового значения Fi: {0,1}n → {0,1}. Если выход этой функции равен единице, то X заменяется на X' — на свою парную точку, в противном случае на этом раунде не происходит никаких изменений.


Поскольку операция XKiX — это инволюция (самообратимое преобразование), то расшифровка происходит простым прохождением раундов в обратном порядке.


К вопросу о конкретной реализации функции Fi мы вернёмся в конце работы, а сейчас рассмотрим более подробно, почему авторы предложили рассматривать блочный шифр, как перетасовку колоды карт.


Если существует некоторый метод по перетасовке колоды N карт, то он определяет соответствующий метод шифрования N точек: достаточно поместить карту на каждую позицию X ∈ [N], где [N] = {0, 1, …, N-1}; перетасовать карты; затем посмотреть на какой позиции оказалась карта, которая изначально была на позиции X. Такую позицию можно назвать шифртекстом Y для X. Случайность, используемая для шифрования, определяется ключом.


Первое, что нужно, чтобы использовать перетасовку карт в качестве вычислительно приемлемого шифра — это требование вычислений с забыванием или рассеянных вычислений, идея которых была высказана Мони Наором. В забывчивой перетасовке можно следить за траекторией одной карты, не обращая внимания на другие карты в колоде. Большинство известных алгоритмов перетасовок таковыми не являются. Наиболее известный алгоритм рассеянной перетасовки — алгоритм Торпа, поэтому он подходит под метод swap-or-not. Вот как он выглядит в качестве перестановки.


Рис. 2. Swap Or Not как перетасовка (23 Кб)

Для колоды из N = 2n карт, каждая из которых размещена на позиции X ∈ [N] случайным образом выбирается n-битовый ключ K. Для каждой пары размещений {X, KX} подбрасывается монета b для получения одного бита энтропии. Если выпадает "орёл" или бит "1", то X и KX меняются местами. Если "0", то ничего не происходит. Используя независимые честные монеты процесс может быть повторён r раундов для достижения требуемого качества перемешивания ("стойкости").


Если алгоритм swap-or-not-перетасовки со второй иллюстрации перевести обратно на язык криптографии, то мы получим первый алгоритм, swap-or-not-шифр. Это лишь разные взгляды на один и тот же процесс. Случайный выбор парных карт, определяемый ключом K в i-той перетасовке, определяется раундовым подключом Ki в шифровании. Случайный бит b, выкидываемый на каждом раунде в перетасовке пары {X, KX}, в случае шифрования соответствует Fi(Xˆ).


Теперь рассмотрим этот алгоритм шифрования с обобщённой областью определения:


Рис. 3. Обобщённая область определения (20 Кб)

Вместо того, чтобы использовать операцию XOR, или иначе говоря, группу G = ({0, 1}n, ⊕), алгоритм может быть исполнен на любой конечной абелевой группе G = ([N], +]). Для определённости, пусть элементы этой группы нумеруются с нуля: [N] = {0, …, N – 1}. Если с операцией XOR шифр мог иметь размер блока, равный любой величине степени двойки, то в случае с произвольной группой в этом нет необходимости. Размер блока шифра может быть любым конечным числом, для этого оператор группы можно задать, к примеру, как сложение по модулю N. Нужно лишь выбирать равномерно и случайно значение K из области N, которое также не является степенью двойки, т.е. не относится к {0,1}n. Вместо парных обменов {X, KX} будут использоваться обмены {X, K – X}, а для замены выбором будет X'kiX вместо X'KiX. Вот и все отличия от первого алгоритма.


Авторы анализируют стойкость своей swap-or-not-конструкции на основании основополагающей работы Любы-Ракоффа, в которой подразумевается, что соответствующие части преобразования выбираются равномерно и однородно. Тогда алгоритм на третьей иллюстрации можно описать как преобразование SN [r, N, +]: k x [N] → [N], в виде блочного шифра E с количеством раундов r, областью определения сообщений [N], указанным оператором группы "+" и где область определения значений ключей включает все возможные подключи K1, …, Kr ∈ [N] и всех возможных раундовых функций F1, …, Fr: [N → {0, 1}]. Таким образом ключ KF для данного шифра состоит из равномерно выбранных раундовых подключей Ki и Fi.


Для оценки стойкости блочного шифра его сравнивают со стойкой псевдослучайной перестановкой ("strong-PRP"). Сложность нахождения различителя между такой перестановкой и блочным шифром определяет уровень защиты от атак с подобранным шифртекстом, которые включают в себя и атаки с известным и подобранным открытым текстом. Для описания такой модели атакующего A, пытающегося взломать блочный шифр E, помещают в один из двух миров. В первом мире атакующий имеет доступ к оракулу EKF(∙) для случайных KF, а также доступ к его обратному (расшифровывающему) оракулу E-1KF(∙). В другом мире атакующий имеет дело с равномерной случайной перестановкой π: [N] → [N], также как и с обратной перестановкой, π-1(∙). Цель атакующего — определить в каком из миров он находится: в мире управляемом сконструированным шифром или в мире, управляемом случайным оракулом, задающим наборы фиксированных случайных перестановок. В общем виде его успех в этом деле описывается вероятностной зависимостью от числа запросов q к определяемому оракулу:

Формула различителя (7 Кб)

Исследователям удалось вывести конкретное значение, которое равно:

Формула числа запросов для различителя (6 Кб)

Грубо говоря, достаточно минимум r = 6 lg N раундов swap-or-not для начала хорошего приближения к CCA-стойкости. После этого преимущество противника падает обратно-экспоненциально в зависимости от r. Это превосходит стойкость сетей Файстеля и перестановок Торпа.

Рис. 4. Графики устойчивости к атакам с подобранным шифртекстом (7 Кб)

На графике показаны результаты приближения CCA-преимущества для q запросов при N = 264. По оси x значения пронормированы в виде log2(q). Два правых графика показывают результаты шифра swap-or-not с восьмью проходами (512 раундами) (SN-8) и с 10 (SN-10) (один проход определяется как верхнее округление lg N раундов). Для сравнения: два левых графика — это сбалансированная сеть Файстеля по классическим результатам Любы-Ракоффа для четырёх раундов (LR-4) и шестираундовому результату Патарина (LR-6). Посредине показаны перестановки Торпа (TH-8, TH-20).


В качестве простого числового примера, можно показать, что swap-or-not шифрование 64-битных строк за 1200 раундов с использованием случайных раундовых функций позволяет достичь максимального CCA-преимущества менее, чем 10-10, даже если противник может сделать q = 263 запросов. Несмотря на большое число раундов, никакая другая конструкция не обеспечивает безопасность при q близком к N. Кроме того, можно предположить, что раунды swap-or-not будут исполняться эффективнее традиционных сетей Файстеля.


Авторы также приводят вывод информационно-теоретической и комплексно-теоретической оценки стойкости алгоритма.


Однако, можно заметить, что наличие нереализованной идеальной функции F в каждом раунде делает алгоритм слишком теоретическим. Можно ли использовать какую-либо реальную функцию для получения однобитовой свёртки? На этот вопрос авторы отвечают утвердительно.


В качестве такой функции возможно использование двоичного скалярного произведения — цепочки XOR-операций между битами текущего состояния раунда и некоего раундового подключа Li, дающей на выходе один бит:

Формула двоичного скалярного произведения (4 Кб)

Используя два раундовых подключа Ki и Li возможно представить полноценный алгоритм:

Рис. 5. Смешивание-рассеивание на двоичном скалярном произведении (19 Кб)

Здесь отмечается, что использование наибольшего значения max для выбора {X, X'} является обязательным требованием, в противном случае, при использовании минимума, X = 0n всегда будет шифроваться как 0n.


Итак, авторы представили простейший полноценный, обоснованно-стойкий алгоритм блочного шифрования, обладающий свойствами замены и перемешивания (лавинным эффектом), работающий только на операции XOR.


Читатель, знакомый с основами доказуемой безопасности, может почуять подвох в этом месте, о котором говорят сами авторы. При замене идеальной случайной функции F на сконструированную, доказательства стойкости теряют свою строгость и простейшее приближение r = 6n (например 6 ∙ 128 = 768 раундов) не может быть применено.


Однако, такая же проблема существует и в любом другом блочном шифре, который опирается не на признанно сложные математические задачи, а искусственные инженерные построения, поэтому для дальнейшего исследования стойкости с целью определения необходимого числа раундов необходимо определить, насколько выбор реальной функции F для замены её идеализированного представления влияет на стойкость шифра, в частности изучением алгебраической сложности получающихся преобразований. Авторы призывают всех заинтересовавшихся криптографов продолжить исследования в данной области.


В работе не отмечены варианты построения ключевого расписания (разворачивание раундовых подключей из основного ключа), которое подошло бы к таким шифрам. И в этом также может оказаться одна из проблем. Большое количество требуемых раундов исполнения алгоритма возможно сделает непрактичным просчёт всех раундовых подключей и сохранение их в памяти. А попытка создать такой же простой алгоритм ключевого расписания, исполняющийся без предвычислений и затрат памяти — "на лету", может потребовать слишком большого количества операций на каждый подключ.


Тем не менее, интересно запомнить алгоритм построения простейшего универсального блочного шифра, котрый претендует на переворот многих представлений в области симметричной криптографии. Сформулируем его ещё раз простыми словами для удобства запоминания:


  1. Провести операцию XOR текущего значения на входе раунда с первым подключом раунда.
  2. Вычислить наибольшее значение между результатом п.1 и значением без XOR (входом раунда).
  3. Вычислить однобитовую XOR свёртку между результатом п.2 и вторым раундовым подключом.
  4. Если значение бита свёртки равно 1, то заменить исходное раундовое значение на результат полученный в п.1.
  5. Если значение бита свёртки равно 0, то оставить результат на выходе раунда равным исходному значению на входе раунда без каких-либо изменений.

Расшифрование производится таким же образом, проходя раунды в обратном порядке.
Если заменить операцию XOR (за исключением п.3) на вычитание по модулю любого числа, то можно работать с блоками любого размера, в т.ч. не с двоичными числами. При этом необходимо соблюдать равномерность и случайность в создании раундовых подключей в соответствии с областью определения.


Работа исследователей была проведена на гранты Национального Научного Фонда США по программе финансирования математических наук. По их утверждению, открытие нового метода создания шифров явилось случайным побочным результатом исследований в области создания алгоритмов блочного шифрования с сохранением формата сообщений (FPE). Пока ключевого расписания к данным алгоритмам не создано, в работе предлагается использовать swap-or-not-сети для FPE-шифрования совместно с шифром AES.


P.S.
Работа авторов заслужила честь открыть конференцию CRYPTO-2012.
А на Rump-сессии в ходе закрытия конференции Серж Водене попытался сделать "закрытие" этого "открытия". В докладе file"Конец шифрования на перетасовке карт?" он указал на уязвимость в практической реализации алгоритма, в том виде как он был предложен авторами. Он отметил, что выбор максимального значения не может быть использован для замены значений, т.к. это в некоторых случаях приводит к утечке информации об определённых битах ключа и превращению алгоритма в линейную функцию. Для спасения алгоритма он предложил реализовать идею Генри Гильберта в использовании функции выбора Xˆ ← (X + X') mod 2l.

Модификация Водене-Гилберта (20 Кб)

Стойкость альтернативного варианта реализации также не является строго обоснованной и уже на этапе предложения вызывает сомнения в применимости для шифрования на малых множествах.


Источник: Cryptography and Security Archive, Advances in Cryptology — CRYPTO 2012, Crypto 2012 rump session.


 
На страницу: 1, 2 След.
Комментарии [скрыть комментарии/форму]
— Гость (12/08/2012 23:45)   <#>
А еще бывает dup-drop-swap. А вообще мне понравилось, проверка на различитель, да не какая-нибудь тривиальная, параллельные миры опять же. Только не понятно, чего тут эдакого сверхнового, и позабористей были концепции.
— unknown (13/08/2012 10:58)   профиль/связь   <#>
комментариев: 9796   документов: 488   редакций: 5664
Сама по себе проверка на различитель в каком-то смысле тривиальная. Ничего принципиального нового в ней нет. Это просто игры с интерпретациями статистичесих моделей. Можно пытаться различать чёрные ящики, куда помещены разные алгоритмы, а можно самого различающего помещать в разные миры. Это такой модный тренд, который сам по себе мало что меняет, но во многих работах фигурирует уже давно. Может это ввели для более полного описания изоляции и разделения между атакующим и алгоритмом — алгоритмы в мирах разные, атакующий абсолютно один и тот же, но он не может переносить информацию о своих измерениях из одного мира в другой. Может для того, чтобы иметь небольшой дополнительный уровень абстракции: миров может быть и больше одного и между ними можно строить зависимости, недоступные изолированным там атакующим, но доступные внешнему наблюдателю.

Но в целом конечно, обоснование стойкости образцово-показательное, хотя и незаконченное.

Интересен сам алгоритм. Т.к. любой блочный шифр в общем виде — это задаваемая ключом псевдослучайная перестановка (PRP) всех вариантов открытых текстов во все варианты шифртекстов в пределах размеров блока, то поскольку на построение большой перестановки уйдёт столько же затрат, как и на взлом, то и пользоваться идеальной перестановкой невозможно. До этого большие перестановки в блочных шифрах часто "склеивали" из маленьких: маленький S-блок или аналог в виде нелинейной функции, затем линейная перемешивающая функция.

А в swap-or-not предлагается перетасовывать открытый текст как карту в колоде и посмотреть, куда она ляжет. При этом состояние других карт в процессе перетасовывания запоминать не надо. А то пришлось бы запоминать, к примеру, 2128 карт, что опять было бы равносильно затратам на работу алгоритма таким же как и на взлом.

Вместо этого использован простейший и универсальный алгоритм на XOR, сравнении и выборе из двух величин.

Интереснее другое. Насколько реально разработать для него столь же простое ключевое расписание без потери практических свойств и как его стойкость соотносится с алгебраическим криптоанализом. Или всё так и останется красивой теоретической игрушкой с ограниченной областью применения.
— Гость (26/08/2012 19:10)   <#>
"Исследователям удалось вывести конкретное значение"-вообще не понял как, оригинал на Архиве, правда, ещё не читал. А так идея интересная, особенно если попробовать сделать на этой основе хэш-функцию,тут с ключевым расписанием не должно быть проблем, можно брать хоть открытый текст же. Параллельные миры можно заменить множествами образов и прообразов, если покажется вдруг слишком экстравагантно.
— Гость (27/08/2012 08:57)   <#>
Я правильно понимаю, что идея состоит в том, что у нас имеется известная последовательность раундовых ключей, но при шифровании некоторые просто пропускаются, а какие именно – определяется псевдослучайным образом?
— Гость (27/08/2012 09:26)   <#>
По факту примерно так и получается,"нереализованная идеальная функция F" отвечает за это.
— Гость (27/08/2012 10:49)   <#>
при использовании минимума, X = 0n всегда будет шифроваться как 0n.

А при использовании максимума, X = 1n не будет всегда шифроваться как 1n ?
— unknown (27/08/2012 10:51)   профиль/связь   <#>
комментариев: 9796   документов: 488   редакций: 5664
Совершенно верно, идея состоит в выборе-пропуске подключей, зависящем от изменений исходного открытого текста после каждого раунда. Но сам их массив противнику разумеется неизвестен. Тогда и для шифрования можно использовать простой XOR или вычитание по модулю.

Функция F просто не может быть идеальной, таких в реальном мире не бывает, но предложенный вариант (побитовая XOR свёртка со вторым раундовым подключом) вполне претендует на реальное использование. Приведённое в работе доказательство показывает, что если функция F была бы идеальной, то шифр-перестановка стремился бы к идеальному при таких-то параметрах. Эта система доказательств идёт от работ Любы-Ракоффа (ещё 80-е годы) и Патарина. Многомировая интерпретация и роль наблюдателя упомянута в работе вскользь и более широко используется в других работах Беллейра-Рогуэя. Можно не обращать внимание на эту пародию квантмеха, пользуясь подходом "заткнись и считай".

С ключевым расписанием намного сложнее. Скорее всего, простое ключевое расписание не подойдёт. Здесь (бездоказательное IMHO) в отличии от традиционных шифров критически важно, чтобы подключи были почти идеально псевдослучайными. Тоже и с предполагаемым хэшем. На один блок открытого текста в шифре или один обрабатываемый блок в предполагаемом хэше нужно 2N подключей, т.е. порядка двух тысяч подключей размером с блок шифрования/хэширования. Как это эффективно развернуть из короткого ключа, а тем более из блока открытого текста в хэшировании, которым может манипулировать противник, трудно пока представить.

Получается, что для того, чтобы получить близкую к идеальной псевдослучайную функцию, нужно уже иметь близкую к идеальной псевдослучайную функцию. Это фундаментальная рекурсивная неполнота вообще всей симметричной криптографии, но здесь она проявляется наиболее явно. Примерно из-за этого "доказуемая безопасность" ничего по сути не доказывает. И поэтому Swap-Or-Not схема имеет и большой теоретический интерес — можно увидеть в ней и обобщённый вариант перестановок и вырожденный вариант сети Файстеля.
— unknown (27/08/2012 11:35, исправлен 27/08/2012 11:35)   профиль/связь   <#>
комментариев: 9796   документов: 488   редакций: 5664
при использовании минимума, X = 0n всегда будет шифроваться как 0n.

А при использовании максимума, X = 1n не будет всегда шифроваться как 1n ?

Интересное наблюдение, здорово, что заметили, честно говоря самому непонятно:


Если X = 0n, то всегда при любом Ki: min(X, KiX) = 0n
Если X = 1n, то всегда при любом Ki: max(X, KiX) = 1n


И после первого же такого раунда пойдёт замена блоков 0n или 1n на самого себя до конца выполнения алгоритма независимо от подключей.


Можно было бы ввести исключение для блоков из нулей и единиц и делать некое инвертирование (хотя как потом расшифровывать обратно?), но как это сочетается с:

We comment that for this instantiation it is necessary to use “max” instead of “min” in selecting a canonical one of {X, X' }; otherwise, we’d have X = 0n always encrypting to 0n .

И всё. Больше авторы ничего не предлагают, вроде всем всё должно быть очевидно.

— unknown (28/08/2012 12:16, исправлен 28/08/2012 13:01)   профиль/связь   <#>
комментариев: 9796   документов: 488   редакций: 5664

А там всё ещё хуже оказалось:
fileSerge Vaudenay "The End of Encryption based on Card Shuffling?".


Вместо выбора большего надо хотя бы складывать по модулю 2l чтобы спасти схему, что также не даёт гарантий стойкости.


Вот вам и оракулы, и параллельные миры, и доказуемая безопасность, и авторитетные исследователи!


Swap-or-Not торжественно переименовывается в fileSlap-or-Scuffle.

— SATtva (28/08/2012 14:48)   профиль/связь   <#>
комментариев: 11558   документов: 1036   редакций: 4118
Просто это в очередной раз демонстрирует консерватизм криптографии. Методы проходят проверку годами и десятилетиями, а новые подходы, пусть даже от самых авторитетных авторов, рискуют не продержаться и нескольких месяцев.
— unknown (28/08/2012 15:09)   профиль/связь   <#>
комментариев: 9796   документов: 488   редакций: 5664
Демонстрирует консерватизм практической криптографии. А с теоретической точки зрения работа авторов замечательна. Они представили блестящее доказательство того, что при использовании идеальной и несуществующей в реальности функции F можно получить стойкий блочный шифр совсем из ничего.
— Гость (29/08/2012 19:44)   <#>
Простота не заметна.
К тому же ввели мифическую супер-функцию и свалили на нее всю стойкойсть.

В таком виде работа не вызывает доверия.
— Гость (30/08/2012 10:45)   <#>
Простота то как-раз заметна, и это даёт больше надежд получить строгое доказательство.
А "мифическая суперфункция" – это XOR :)
— Гость (30/08/2012 22:47)   <#>
Не советую быть таким категоричным со ксором, он вещь коварная.

Например,
1 xor 1 xor 1 xor 1 xor 1 xor 1 xor 1 xor 1 xor 0 = 1
0 xor 0 xor 1 xor 1 xor 1 xor 1 xor 1 xor 1 xor 0 = 1
1 xor 1 xor 0 xor 0 xor 1 xor 1 xor 1 xor 1 xor 1 = 1
1 xor 1 xor 1 xor 0 xor 0 xor 0 xor 0 xor 0 xor 0 = 1
— Гость (30/08/2012 23:32)   <#>
1 xor 1 xor 1 xor 1 xor 1 xor 1 xor 1 xor 1 xor 0 = 1

1 xor 1 xor 1 xor 1 xor 1 xor 1 xor 1 xor 1 xor 0 = 0

0 xor 0 xor 1 xor 1 xor 1 xor 1 xor 1 xor 1 xor 0 = 1

0 xor 0 xor 1 xor 1 xor 1 xor 1 xor 1 xor 1 xor 0 = 0

зы
xor нескольких нулей и единиц равен количеству единиц по модулю 2, то есть нечётности этого количества.
На страницу: 1, 2 След.
Ваша оценка документа [показать результаты]
-3-2-1 0+1+2+3