chacha20-ietf-poly1305, разработка Гугла для внутренних нужд
Это вы что-то странное написали, chacha20 и poly1305 это известные открытые алгоритмы за авторством Daniel J. Bernstein (https://cr.yp.to/chacha.html, https://cr.yp.to/mac.html), референсные имплементации которых находятся в Public Domain.
Оба этих алгоритма, а также в каком-то смысле родственный им Curve25519/ed25519 (https://cr.yp.to/ecdh.html), проще, чем аналогичные им AES-GCM и RSA/ECDSA, у них меньше размер ключей при той же криптостойкости, и они сравнимы по скорости с аппаратными реализациями аналогов и быстрее софтверных. Собственно, поэтому они и появились в свежих версиях TLS и свежих имплементациях SSH. Кстати, на них же основана библиотека libsodium, которая дает ну очень простой и удобный API для шифрования, подписей и прочих операций.
Кстати, хорошей альтернативой для OpenVPN будет, имхо, Wireguard. Он гораздо проще в настройке чем OpenVPN и тем более другие виды VPN, он очень быстрый за счет того что по умолчанию идет как модуль ядра (хотя преполагается что будут и юзерспейсовые имплементации, особенно для не-Linux систем), основан на state-of-the-art криптографии (как раз вышеописанные chacha20, poly1305, ed25519), и очень активно развивается.
Многие VPN работают по UDP, где никаких хендшейков нет, если их нет в самом протоколе VPN. Например, у Wireguard это одна из заявленный фич (отсутствие ответов на неизвестные/невалидные пакеты).
Кондиционер. Есть ли поезда, где он может регулироваться раздельно в каждом купе? Во избежание случаев, когда одна мамочка с ребенком, боящаяся простуды, держит в жаре весь вагон.
Давно не ездил на поезде, но позавчера пришлось воспользоваться поездом, возвращаясь из командировки. Поезд Саратов-Москва №17, вагон был ТКС, купе, и в нем, как проводник показал, была ручка регуляции температуры и кондиционера, своя на каждое купе. Был приятно удивлен.
async/await существенно удобнее for/do. Только лишь с помощью комбинаторов очень многие паттерны выражать безумно геморройно. Год назад в одном проекте на скале большие асинхронные методы сначала мы пытались писать с помощью комбинаторов и for. Получалось совершенно нечитаемое месиво. После перехода на scala-async код стал чище и понятнее на порядок.
С async-await в Rust писать асинхронный код очень легко и приятно. А с недавними разработками в области immovable generators станет все совсем хорошо.
Я подозреваю, что имелось в виду не шифросообщение (которое ciphertext), а открытое сообщение (которое plain text). Хотя и здесь тоже все зависит от алгоритма, насколько я понимаю.
Вероятно, имеется в виду Stackoverflow developer survey, в котором уже второй год подряд Rust занимает первую строчку в номинации Most loved language. Согласен, что перевод несколько некорректен.
Насчет отладки C++ — если программа падает с segfault'ом, то для нее скорее всего образуется core dump файл, в котором будет вся информация о том месте, где упала программа, в том числе стектрейсы и содержимое памяти. Понять итерацию цикла, на которой произошло падение, весьма просто, если есть core dump, который загружается в отладчик.
Альтернативный вариант — запустить вычисление под отладчиком непосредственно. Все более-менее нормальные отладчики при сегфолтах умеют останавливать программу в нужном месте, и дают возможность смотреть стектрейсы и состояние памяти.
Да, это сложнее, чем в языках более высокого уровня, и требует некоторых знаний в области системного программирования. Если получается сделать вычисления на чем-то более удобном, и производительность не страдает, то конечно нужно использовать высокоуровневый язык.
Насчет падения компьютера от программы которая что-то вычисляет — это ну очень странно. Современные ОС уже очень давно нельзя обвалить (при условии отсутствия багов/эксплоитов, но в этом случае это делается намеренно, а не случайно), просто так вызвав что-то из программы, запущенной с правами простого пользователя. Тем более, если это просто вычисления, которые ничего кроме функций ввода-вывода и математики не вызывают. Я могу себе представить что система может например зависнуть от недостатка памяти (в Linux это проблема), но и в этом случае есть решения, например, квотирование ресурсов для программы или более аггресивный OOM-киллер. Кроме того, никакой язык от падений такого рода не застрахует.
Что-то вроде этого, да. Почти все структуры ядра, кроме тех, которые необходимо маппить из-за архитектуры процессора, перестанут маппиться "по умолчанию", Цитата из статьи о Meltdown:
The KAISER patch by Gruss et al. [8] implements
a stronger isolation between kernel and user space.
KAISER does not map any kernel memory in the user
space, except for some parts required by the x86 archi-
tecture (e.g., interrupt handlers). Thus, there is no valid
mapping to either kernel memory or physical memory
(via the direct-physical map) in the user space, and such
addresses can therefore not be resolved. Consequently,
Meltdown cannot leak any kernel or physical memory
except for the few memory locations which have to be
mapped in user space.
We verified that KAISER indeed prevents Meltdown,
and there is no leakage of any kernel or physical memory.
Furthermore, if KASLR is active, and the few re-
maining memory locations are randomized, finding these
memory locations is not trivial due to their small size of
several kilobytes. Section 7.2 discusses the implications
of these mapped memory locations from a security per-
spective.
Таким образом, уязвимость открывает только доступ к структурам ядра, но не структурам других приложений.
Не совсем так. Поскольку предполагалось, что хардварной проверки доступа достаточно для защиты, в целях производительности сисколлов и удобства в ядрах большинства систем, помимо собственно структур ядра, в адресное пространство ядра отображается также и физическая память целиком. В конце концов, на 64-битных системах виртуальное адресное пространство содержит 2^64 адресов, и пусть даже у компьютера десятки и сотни гигабайт оперативки, это все равно будет капля в море виртуальной памяти. Соответственно, возможность прочитать память ядра = возможности прочитать память любого процесса, работающего рядом. В этом суть фикса KAISER и его аналогов для других ОС — он убирает это отображение физической памяти и прочих структур ядра, кроме совершенно необходимых. Плата за это — необходимость восстанавливать маппинг памяти при системных вызовах, что приводит к просадке производительности.
Спасибо за статью. Есть несколько замечаний по коду, но в целом у вас вполне себе идиоматичный Rust получился.
Бинарный поиск:
Передавать &Vec<u32> нет никакого смысла — в таких случаях нужно передвать срез &[u32], это делает сигнатуру немного чище и обобщённее.
Для индексов стоит использовать usize вместо u32, и возвращать Option<usize>.
fn binary_search(vec: &[u32], value: u32) -> Option<usize> {
let mut l = 0;
let mut r = vec.len() - 1;
while l <= r {
let i = (l + r) / 2;
if vec[i] == value {
return Some(i + 1);
} else if vec[i] > value {
r = i - 1;
} else if vec[i] < value {
l = i + 1;
}
}
None
}
Должен отметить, что возвращать 1-based индекс немного странно, ну да ладно :) Как видите, код стал чуть чище.
Слияние.
Данная конструкция не взлетит в Rust без unsafe кода, т.к. тут мы передаем два изменяемых подмассива, которые располагаются в исходном массиве. Система типов в Rust не позволяет иметь две изменяемых переменных на один объект (мы знаем, что подмассивы не пересекаются по памяти, но компилятор — нет).
Это не совсем верно. На срезах в Rust есть метод split_at_mut(), который возвращает два непересекающихся изменяемых среза из одного исходного. Но в общем случае да, вы правы — без специального кода и возможно unsafe сделать две мутабельные ссылки в один объект, даже если они не пересекаются, не получится.
Кодирование Хаффмана:
Передавать String как аргумент, как правило, не нужно — но в вашей ситуации это оправдано, потому что вы этот объект немедленно добавляете в HashMap. Во втором match, однако, вызывать clone() на ней не нужно, потому что дальше по коду строка нигде не используется и её можно переместить в оператор конкатенации и дальше в HashMap.
Конструкцию типа match &self.left { &Some(ref leaf) => ... } вполне можно заменить на match self.left { Some(ref leaf) => ... }, и символов станет немного поменьше.
По поводу пункта 5 — на мой взгляд, код получился достаточно понятным. А вот что в Котлине действительно выносит мозг, на мой взгляд, даже сильнее имплиситов в Scala, так это неявный this в лямбдах, через который делаются билдеры и прочие DSLи. Из-за него внутри лямбды магическим образом становится возможно вызывать методы, которые определены на типе receiver'а, и откуда эти методы берутся в конкретном куске кода, без дополнительного исследования понять нельзя. В Scala, например, через имплиситы нельзя добавить новые методы непосредственно в область видимости; новые методы могут быть добавлены только к какому-нибудь объекту (через имплиситные классы).
Понятно, что и в том и в другом случае при наличии IDE найти, откуда берется какой-то метод, не составляет особой сложности, но лично мое ИМХО — понять код с имплиситами в Скале проще, чем код с переопределенным this для лямбд в Котлине. Кроме того, синтаксическая привязанность неявно добавленных методов к объекту упрощает чтение — код в Котлине был бы существенно понятнее, хоть и существенно многословнее, если бы для вызова методов на this необходимо было бы всегда писать this явно.
А, вот оно что. Я пристально за дотти не слежу, получается что там как-то унифицировали типовые параметры и ассоциированные типы? Я ещё удивился синтаксису refA.T/refB.T, который вроде как подразумевает что T это type T а не параметр. Про ассоциированные типы у меня с самого начала была мысль, да, но тут речь шла про параметры всё-таки)
Нет, тут другое, как мне кажется. Насколько я понимаю, то, что вы написали, применяется когда в сигнатуре метода используется один из типовых параметров. В этом случае стирание логично. В случае же когда метод сам по себе дженериковый и не зависит от типа в классе, где он объявлен, это уже существенно менее логично. Ведь в таком случае же совершенно не важно лля вызова метода, сырой ли тип, на котором метод объявлен, или вообще не дженериковый.
Это вы что-то странное написали, chacha20 и poly1305 это известные открытые алгоритмы за авторством Daniel J. Bernstein (https://cr.yp.to/chacha.html, https://cr.yp.to/mac.html), референсные имплементации которых находятся в Public Domain.
Оба этих алгоритма, а также в каком-то смысле родственный им Curve25519/ed25519 (https://cr.yp.to/ecdh.html), проще, чем аналогичные им AES-GCM и RSA/ECDSA, у них меньше размер ключей при той же криптостойкости, и они сравнимы по скорости с аппаратными реализациями аналогов и быстрее софтверных. Собственно, поэтому они и появились в свежих версиях TLS и свежих имплементациях SSH. Кстати, на них же основана библиотека libsodium, которая дает ну очень простой и удобный API для шифрования, подписей и прочих операций.
Кстати, хорошей альтернативой для OpenVPN будет, имхо, Wireguard. Он гораздо проще в настройке чем OpenVPN и тем более другие виды VPN, он очень быстрый за счет того что по умолчанию идет как модуль ядра (хотя преполагается что будут и юзерспейсовые имплементации, особенно для не-Linux систем), основан на state-of-the-art криптографии (как раз вышеописанные chacha20, poly1305, ed25519), и очень активно развивается.
Многие VPN работают по UDP, где никаких хендшейков нет, если их нет в самом протоколе VPN. Например, у Wireguard это одна из заявленный фич (отсутствие ответов на неизвестные/невалидные пакеты).
Давно не ездил на поезде, но позавчера пришлось воспользоваться поездом, возвращаясь из командировки. Поезд Саратов-Москва №17, вагон был ТКС, купе, и в нем, как проводник показал, была ручка регуляции температуры и кондиционера, своя на каждое купе. Был приятно удивлен.
Рак-богомол (mantis shrimp)
async/await существенно удобнее for/do. Только лишь с помощью комбинаторов очень многие паттерны выражать безумно геморройно. Год назад в одном проекте на скале большие асинхронные методы сначала мы пытались писать с помощью комбинаторов и for. Получалось совершенно нечитаемое месиво. После перехода на scala-async код стал чище и понятнее на порядок.
С async-await в Rust писать асинхронный код очень легко и приятно. А с недавними разработками в области immovable generators станет все совсем хорошо.
Вероятно, имеется в виду Stackoverflow developer survey, в котором уже второй год подряд Rust занимает первую строчку в номинации Most loved language. Согласен, что перевод несколько некорректен.
Альтернативный вариант — запустить вычисление под отладчиком непосредственно. Все более-менее нормальные отладчики при сегфолтах умеют останавливать программу в нужном месте, и дают возможность смотреть стектрейсы и состояние памяти.
Да, это сложнее, чем в языках более высокого уровня, и требует некоторых знаний в области системного программирования. Если получается сделать вычисления на чем-то более удобном, и производительность не страдает, то конечно нужно использовать высокоуровневый язык.
Насчет падения компьютера от программы которая что-то вычисляет — это ну очень странно. Современные ОС уже очень давно нельзя обвалить (при условии отсутствия багов/эксплоитов, но в этом случае это делается намеренно, а не случайно), просто так вызвав что-то из программы, запущенной с правами простого пользователя. Тем более, если это просто вычисления, которые ничего кроме функций ввода-вывода и математики не вызывают. Я могу себе представить что система может например зависнуть от недостатка памяти (в Linux это проблема), но и в этом случае есть решения, например, квотирование ресурсов для программы или более аггресивный OOM-киллер. Кроме того, никакой язык от падений такого рода не застрахует.
Это называется "теория скрытых параметров" и она опровергнута экспериментами по нарушению неравенств Белла.
Что-то вроде этого, да. Почти все структуры ядра, кроме тех, которые необходимо маппить из-за архитектуры процессора, перестанут маппиться "по умолчанию", Цитата из статьи о Meltdown:
Не совсем так. Поскольку предполагалось, что хардварной проверки доступа достаточно для защиты, в целях производительности сисколлов и удобства в ядрах большинства систем, помимо собственно структур ядра, в адресное пространство ядра отображается также и физическая память целиком. В конце концов, на 64-битных системах виртуальное адресное пространство содержит 2^64 адресов, и пусть даже у компьютера десятки и сотни гигабайт оперативки, это все равно будет капля в море виртуальной памяти. Соответственно, возможность прочитать память ядра = возможности прочитать память любого процесса, работающего рядом. В этом суть фикса KAISER и его аналогов для других ОС — он убирает это отображение физической памяти и прочих структур ядра, кроме совершенно необходимых. Плата за это — необходимость восстанавливать маппинг памяти при системных вызовах, что приводит к просадке производительности.
Собственно, это было как раз первым пунктом моих замечаний.
Спасибо за статью. Есть несколько замечаний по коду, но в целом у вас вполне себе идиоматичный Rust получился.
Бинарный поиск:
&Vec<u32>
нет никакого смысла — в таких случаях нужно передвать срез&[u32]
, это делает сигнатуру немного чище и обобщённее.usize
вместоu32
, и возвращатьOption<usize>
.Должен отметить, что возвращать 1-based индекс немного странно, ну да ладно :) Как видите, код стал чуть чище.
Слияние.
Это не совсем верно. На срезах в Rust есть метод
split_at_mut()
, который возвращает два непересекающихся изменяемых среза из одного исходного. Но в общем случае да, вы правы — без специального кода и возможно unsafe сделать две мутабельные ссылки в один объект, даже если они не пересекаются, не получится.Кодирование Хаффмана:
String
как аргумент, как правило, не нужно — но в вашей ситуации это оправдано, потому что вы этот объект немедленно добавляете в HashMap. Во второмmatch
, однако, вызыватьclone()
на ней не нужно, потому что дальше по коду строка нигде не используется и её можно переместить в оператор конкатенации и дальше в HashMap.match &self.left { &Some(ref leaf) => ... }
вполне можно заменить наmatch self.left { Some(ref leaf) => ... }
, и символов станет немного поменьше.http://lurkmore.to/%D0%96%D0%B4%D0%B5%D0%BC_%D0%B5%D0%B1%D0%B8%D0%BB%D0%B4%D0%BE%D0%B2
https://en.wikipedia.org/wiki/Ebuild
По поводу пункта 5 — на мой взгляд, код получился достаточно понятным. А вот что в Котлине действительно выносит мозг, на мой взгляд, даже сильнее имплиситов в Scala, так это неявный this в лямбдах, через который делаются билдеры и прочие DSLи. Из-за него внутри лямбды магическим образом становится возможно вызывать методы, которые определены на типе receiver'а, и откуда эти методы берутся в конкретном куске кода, без дополнительного исследования понять нельзя. В Scala, например, через имплиситы нельзя добавить новые методы непосредственно в область видимости; новые методы могут быть добавлены только к какому-нибудь объекту (через имплиситные классы).
Понятно, что и в том и в другом случае при наличии IDE найти, откуда берется какой-то метод, не составляет особой сложности, но лично мое ИМХО — понять код с имплиситами в Скале проще, чем код с переопределенным this для лямбд в Котлине. Кроме того, синтаксическая привязанность неявно добавленных методов к объекту упрощает чтение — код в Котлине был бы существенно понятнее, хоть и существенно многословнее, если бы для вызова методов на this необходимо было бы всегда писать this явно.
Понятно, спасибо за ссылку! Надо будет про отличия дотти почитать поподробнее.
А, вот оно что. Я пристально за дотти не слежу, получается что там как-то унифицировали типовые параметры и ассоциированные типы? Я ещё удивился синтаксису
refA.T
/refB.T
, который вроде как подразумевает чтоT
этоtype T
а не параметр. Про ассоциированные типы у меня с самого начала была мысль, да, но тут речь шла про параметры всё-таки)Нет, тут другое, как мне кажется. Насколько я понимаю, то, что вы написали, применяется когда в сигнатуре метода используется один из типовых параметров. В этом случае стирание логично. В случае же когда метод сам по себе дженериковый и не зависит от типа в классе, где он объявлен, это уже существенно менее логично. Ведь в таком случае же совершенно не важно лля вызова метода, сырой ли тип, на котором метод объявлен, или вообще не дженериковый.
Удивлён, что скала такое умеет. Это не Dotty, случайно?