Обновить
44
0.5
Гончаров Вадим@nuclight

Программист Си | Perl | Tcl/Tk

Отправить сообщение

Интересные идеи есть (мерж и прочее подобие VCS), но неудивительно, что оно загнулось - типовая ошибка с идентификацией публичным ключом, а главное - "каждый сам себе". Вплоть до того, что в 3.1.8 приходится иметь костыли "Таким образом теги смогут распространяться через узлы, владельцы которых им не доверяют". Не Фидо это, потому и взлететь не может.

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

Это резко сужает популярность проекта, а значит, вредит и тем, кто виндой не пользуется.

Элементарно же, например из-за переупорядочивания компилятором операций floating point, которые принципиально неточные, и порядок влияет. И чему их только нынче учат, раньше любый программист (а computer значит вычислитель) это знал.

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

У Cap'n'proto есть другая интересная штука для производительности - http://capnproto.org/rpc.html в виде сокращения числа раунд-трипов (точнее для убирания не-производительности). Для описанного в комменте ниже, когда у нас latency может достигать скажем секунд, это серьезно. Но у них только промисы в виде одной переменной, а я предполагаю решать проблему передачей на сервер скрипта, который он исполнит, выполнив таким образом несколько API-запросов за раз (подразумевается if/else и т.п. по данным, содержащимся исключительно в ответах, а не привязанных к клиенту). Это одна из целей, для которой делается CBOR-TPL, и поскольку он "бинарный", фронтенд-языки будут называться... ну скажем CBOR-TCL :)

В моём проекте PyDERASN имеется строгая проверка DER, но он написан на Python, поэтому ни о каких embedded систем речи не идёт.

Гы, а почему такое название? Помнится, на @freebsd_ru в Телеграме была какая-то проблема с портом, угорали с названия.

На связи участник IETF CBOR WG, пришедший сюда из гугля по "Tcl CBOR" для ответа на сообщение в mail list насчет 'Hopefully nobody is treating "2" and 2 as the same', происходящего в рамках обсуждений по теме детерминированного CBOR, длящихся уже несколько лет (да, как бы что кому не казалось, детерминизм на самом деле сложная тема).

Но для начала необходимо озвучить несколько философско-мировоззренческих постулатов.

Аксиома первая - для прогресса человечества как наивысшей ценности первейшим врагом является нежелание думать, включать мозг; в контексте обсуждения это прежде всего значит чрезмерное упрощение и желание быстро что-нибудь склепать вместо стратегического подхода с предвидением будущего. Да, это естественно и биологически обусловленно, как нам постоянно рассказывает проф. С.В.Савельев, потому что мозг потребляет до 20% энергии тела при массе в 2%, и тем не менее для людей третичного сознания (по нему же), т.е. творящих что-то новое = двигающих прогресс, это недопустимо. А изобретение форматов относится именно сюда.

И ключевым является именно not simpler, которое обычно и нарушают; например типичным является, когда из-за черзмерной простоты потом в реальном мире приходится городить костыли, и в итоге всё оказывается сложнее, чем если бы было предусмотрено изначально.

Примеров в жизни тьма-тьмущая, например какой-нибудь suckless, который на поверку оказывается уровня от sucks до полной неюзабельности - потому что переупростили, повыкидывав нужное.

Постулат второй (частично следствие предыдущего): раздувание (bloat) и ориентация на "производительность" является врагом, и в том числе моральным - для развития необходимо наличие ограничений (негры в теплой сытой Африке как-то не очень развили науку и технику, в отличие от вынужденных преодолевать климатические ограничения северян и для этого что-то придумывать). Примером является тенденция развития IT-отрасли и около с начала 90-х - закон Мура и рост производительности сыграли развращающе, не только программисты прекратили оптимизировать код, что современный софт на современном железе работает медленнее, чем четверть века назад тогдашний софт на тогдашнем железе, но и обычные люди стали звонить голосом или как минимум строчить в реалтаймовых мессенджерах, не стремясь подумать и написать развернуто письмо (вот в Фидо было отлично!), или смотрящие видео только онлайн, будуче не в состоянии потерпеть и десять минут для скачки фильма торрентом (в наше время и час проблемой не был!). "Производительность" и блоат на руку только корпорациям, поскольку нужны в централизованной модели "наш ДЦ обрабатывает как можно больше пользователей".
К счастью, эпоха дешевой нефти и закона Мура заканчивается - пора забыть о производительности и думать наконец о децентрализации.

Объединяя 1 и 2, мы будем как примеры видеть системы, стремящиеся к строгости и ортогональности (в идеале как в математике), но при этом не закрытые и ригидные, а открытые и расширяемые - ну, скажем, подход "маленькое ядро и плагины" сюда.
Сюда стоило бы добавить ЧСВ, ну или не знаю, по какой причине программисты так любят переизобретать велосипеды, например свои форматы сериализации. При этом мало сделать формат, нужно сделать его пригодным для очень большого количества реальных задач в реальном мире - и сохранить при этом достаточную строгость и простоту с ортогональностью является целым искусством (пожалуй, в математике тоже, глядя сколько лет в истории поиски стройных систем аксиом и т.п. проводились), например JSON. То есть, если не делать формат для какого-то сугубо очень частного случая, то на самом деле не стоит даже и пытаться, если нет готовности приложить очень много усилий для изучения потребностей реального мира. Забегая вперёд, CBOR удалось в достаточной степени - да, не идеально и не без проблем, но это формат "на пять с минусом", в отличие от велосипедов. А как и в криптографии, лучше брать готовые массовые решения как "строительные блоки", нежели велосипедить.

Постулат третий - поскольку способность делать то или иное из практических задач важнее, чем отказ от них, то криптография - не королева, а служанка. Безопасность есть лишь свойство выполнения той или иной задачи - приоритеты могут быть таковы, что лучше сделать небезопасно, чем отказаться (в OpenBSD делают наоборот, как типичные невротики), но под соусом тотального шифрования (зачем? восстание масс не-публичными e2e-сообщениями не поднять, тут максимум подпись нужна) опять же всё в свои централизованные лапы захватывают корпорации с повальным HTTPS, например (а такие корпорации - враг).

Типичной комбинацией 1 и 3 является крайне типичные предложения гиков о соцсетях и т.п. где идентификатором пользователя будет публичный ключ. Почему в реальном мире это не работает, им мозгов не хватает понять (или включить) - типичное, когда человек в своей области разбирается (криптографии допустим), а в остальном нет.
Сюда я б еще добавил пример из типовой ошибки ориентации на авторитеты - скажем, известный DJBernstein хорош в криптографии, но люди почему-то из-за этого считают его авторитетом во всём, когда это не так. Скажем, код его qmail или DNS просто отвратителен, немайнтенабелен, да кстати и DNSCurve его не взлетел (а очень жаль!) из-за банальной неспособности выпустить спецификацию в виде RFC для независимых имплементаций, а не "берите мой криптобокс".

Прежде чем перейти к статье, на фразу из коммента выше:

мало типов данных (это не недостаток, если что, а тоже плюс)

См. аксиому первую: да, это таки недостаток, потому что когда они понадобятся - а они понадобятся - начнется горождение всяких костылей, весьма вероятно, очень fragile.

Теперь к статье. С частью про ASN.1 полностью согласен, правда непонятно, почему среди альтернатив не рассмотрен OpenSSH. Вообще SSH2 недооценённый протокол несмотря на распространенность, очень хороший и человечный, и у них даже сертификаты есть, кстати! Я думал его брать для своего muSCTP (и проекта уровнем выше, аналога Фидо) в качестве основы крипты, чисто почитав RFC, а потому узнал про signify и asignify и вот теперь еще age тоже, оказывается.

В секции требований почему-то производительность не упоминается вообще, хотя дальше большой упор на неё везде - но тут см. постулат 2. И вроде бы секция требований выглядит разумно, но:

Для криптографических задач критична детерминированность кодека. Единственно верное, каноничное представление данных. Хотя есть и вариант принятый в JSON-based криптографии: просто засовывать JSON внутрь строки другого JSON. Но это жуткий overhead и делается от безысходности и ограниченности web-экосистемы.

А вот и нет, см. аксиому 1. Засовывание подписываемого в отдельную бинарную строку, которая и подписывается - это не безысходность, а в 90% случаев самый правильный вариант. Да, в JSON оверхед, но он из-за текстовости - в любом бинарном формате оверхеда не будет. В COSE = CBOR Object Signing and Encryption применён именно этот подход, в том числе из-за необходимости работы на constrained-устройствах.

Теперь подробнее, почему детерминированность - костыль. Я это изложил в двух письмах в mail list:

Вкратце, от нежелания включать мозг - исходят из ложной посылки "два объекта равны, если равны их хэши, а чтобы сделать равными хэши, закодируем детерминированно". В реальном мире этому противоречит та же потоковость, компрессия, но более всего - есть философская проблема. При этом шаг назад - для чего еще это применять, кроме как не для сравнения объектов? То есть, автор dCBOR даже подтверждал, что главное применение - не для того, чтоб передавать детерминированно, а когда НЕ ПЕРЕДАВАТЬ. Ну, скажем, понимать, что такой объект уже есть в кэше, и сэкономить гигабайты.
Так вот, философская проблема - на самом деле, объекты равны только когда ИНТЕРПРЕТИРУЮТСЯ одинаково. Более того, интерпретируются одинаково ВСЕМИ ИМПЛЕМЕНТАЦИЯМИ - что, понятно, при достаточной сложности приложений (тут не про кодек формата речь совсем, он на OSI Layer 6, а приложение на Layer 7) вообще теоретически недостижимо - как от багов (мало кто из нас Кнут, чтоб суметь доказать математически), так и от невозможности даже получить код всех имплементаций в мире. Ну ладно, это лирика, но такое понятие, использовавшееся последние годы в подготовке драфта Common Determistic Encoding (of CBOR), как ALDR - Application-Layer Determinism Rules - вполне про практику. О чем речь?
Ну вот пример, есть у меня логгер сообщений в Telegram (то есть если кто что удалил или редактировал, у меня на диске останется), который из их кошмарного формата переводит в CBOR. Хочу я из него сделать свой полноценный клиент, да не простой, а с поддержкой p2p-обмена - допустим, у товарища в его стране такой-то канал забанен, у меня нет (или сам он где-то), да или просто сравнивать, как сервер в разные места отдает, не дурят ли нас корпораты... в общем, естественным образом напрашивается обмен сообщениями, но только теми, которых у получателя нет, для чего естественно выглядит обменяться их хэшами. И тут первая же засада - в них частенько бывает поле access_hash, что-то вроде куки/токена доступа к конкретному объекту, для каждого юзера он свой. То есть тупое детерминированное представление и хэш по нему нам ничем не поможет - надо выкидывать поле или из хэширования, или из объекта. Второй вариант с предобработкой выкидыванием первым приходит в голову, но что, если нам НАДО передавать версию с полем? Городить сбоку прилепливание "после расхэширования вставь такие-то поля туда и туда" в произвольном месте вложенных объектов?.. Или всё-таки переосмыслить тему детерминизма?

Иными словами, даже оставаясь в рамках темы "хэши нам помогут", правильным подходом будет не линейной хэширование массива байт, а подход Merkle-tree на уровне - считаем хэш каждой пары ключ-значение в мапе отдельно, хэшом мапы будет хэш отсортированных хэшей пар - т.е. нам становится неважен их порядок; у каждого элемента хэш считается не по его текущему представлению, а по канонизированному (это тоже отдельная тема, см. ниже), со списками аналогично, и т.д. Так можно решить например проблему collations (да, в LDAP страшный ASN.1, но сама тема-то имеет право на существование)ю Да, я уже слышу вопль "производительность!" - НУ И ЧТО? См. постулат 2. На самом деле, если речь о скалярах в памяти, которые редактируются как переменные, финальный подсчет даже может оказаться быстрее, если дерево постоянно поддерживать, нежели чем сериализовать это сначала в буфер.

Если ALDR-тема с полями Telegram показалась далекой от практики, то есть гораздо более простые вопросы на самом деле. Допустим, вот у нас есть тип данных для больших чисел, и есть число обычное - мы их считаем равными, если там то же число, или разными? Ах, у нас нет такого типа? А если в будущем введут, что делать? Не введут? Хорошо, пример гораздо проще - инты и флоаты равными считаем, 2 и 2.0 ? Или разными, у них же разная сериализация? Вот dCBOR выбрал подход "вместо 2.0 должен передаваться инт 2", от чего последовали вопли со стороны тех реализаций, которые не динамические языки, и у них это разные типы.
Вот из-за кучи таких нюансов (в этом году еще в NaN payloads погрузились, еще одна бездна) от конфликтующих имплементоров за несколько лет драфт CDE так и не был принят в качестве RFC, а был недавно сменившимся председателем CBOR WG остановлен (будут пытаться зайти по-другому). И подобное ждёт любого автора нового формата, как только он столкнется с имплементациями кроме своей.

Для встраиваемых систем, для мест, где может быть bare metal без ОС: крайне желательно потоковое кодирование. Без него мы будем вынужденны иметь дело с буферизацией, динамической памятью и куда более сложным кодом из-за этого.

Тут сначала должно быть некое просвещение про IoT. Есть такое радио, IEEE 802.15.4, как вайфай, только очень ограниченное - 250 кбит/с, максимальный размер фрейма 127 байт. Причина - устройство, например умный выключатель на липучке, должно годами работать от батареи, а в основном её жрёт именно трансивер, то есть надо как можно меньше данных (можно даже O(N) или хуже алгоритмы, это не так критично, как размер пакета). Из этих 127 байт при максимальном шифровании канального уровня на L3 остается 81 байт. Дальше на этом работают Zigbee со своими протоколами, или 6LoWPAN, в случае которого "в лоб" IPv6-заголовок отожрал бы 40 байт, UDP еще 8 и на данные осталось бы всего 33 байта. Путем различных ухищрений в типовом случае размер доступного пэйлоада поднимают до 60-70 байт.
Типичные устройства, которые с этим работают, в текущей классификации IETF класс C2, самый роскошный, это когда есть килобайт десять RAM, и скока там флэша, в смысле размер скомпилированного кода тоже роляет. В либе QCBOR код сортировки мапов (для достижения детерминизма) занимает около 1.2 Кб, что достигает более чем половины от размера всего остального (зависит от опций компиляции). Для constrained-имплементаций это очень заметный напряг.

Так вот, CBOR делался именно для таких условий, и "потоковое" в нём есть в виде indefinite-length. Но как можно заметить, главным её врагом является детерминизм - например, что мапу надо сначала отсортировать. Это серьезные затраты. А передать число элементов в мапе или массиве (и обычно даже байт в строке) проблемы обычно не составляет - там типичен хардкод типа add("key1", "val1"); add("key1", val2) с последующим "закрытием" контейнера, что как бы потоково, но как бы и не.
Другим применением потоковости мог бы быть highload-стриминг, когда мы открыли мапу и миллион ключей плюём; хоть такой кейс и сложно представить, он тоже конфликтует с детерминизмом.

Приемлемая/достаточная компактность сериализованных данных. Объективной меры, что считать достаточно компактным — нет. Но если сертификат будет занимать в два раза больше чем X.509 ASN.1 DER версия, то неприятно, ведь мы не должны забывать и про какие-нибудь смарт-карты, где каждый килобайт на счету.

Довольно очевидно, что оно должно быть "лучше JSON", а дальше зависит от задачи. Параметры выше я показал (конечно, они и по несколько сотен байт гоняют, блоками, там протокол CoAP вместо HTTP, но всё равно минимизация важна).

Пожеланием является и достаточное количество возможных типов данных, чтобы можно бы было прозрачно заменить JSON, как это часто делают BSON или MessagePack кодеками. Обязательная дифференциация бинарных строк и человекочитаемых текстовых! Крайне желательная возможность передачи строк более четырёх гибибайт, ибо какой же это general purpose кодек, если в нём нельзя содержимое относительно большого файла разом передать? Желательна родная поддержка datetime объектов: это очень часто используемый тип данных.
[...]
FLOAT передаётся как тэг с двумя KEKS-закодированными INT-ами, содержащими произвольной длины мантиссу и экспоненту (по основанию 2). Не компактно, но этот тип данных редко где встречается в «общих» задачах.

А в моей практике наоборот, даты-время я редко вижу, а вот флоаты куда чаще. Даже в том же IoT они есть (координаты и температуры), хотя есть и места, где с флоатами напряг. Засада в другом - если формат объявляется general purpose, нужна возможность вводить произвольные типы данных, т.е. хотя бы описать расширения. В CBOR это решено тегами.

CBOR, судя по описанию, должен быть идеалом! Всё что нам нужно — упомянуто в его спецификации. Но при пристальном рассмотрении, он полностью отпадает. Это самый переусложнённый формат из всех что встречал (исключая ASN.1).
В нём есть система тэгирования данных, как в ASN.1. Многие реализации её вообще не поддерживали. В MessagePack есть extension поле, но оно в общем случае (почти?) не используется. В CBOR-е использование тэгированных данных встречается сплошь и рядом. Поддержка datetime производится только через тэги. Если реализация CBOR не поддерживает тэги, то и не будет datetime.

Большей чуши про CBOR я еще не слышал! Переусложнён?! Многие реализации не поддерживают теги?!! Простите, это какие же?! Теги - базовая часть формата, их нельзя не поддерживать, иначе это не реализация стандарта, а фиг знает что. При этом простейшая реализация CBOR (например на связных списках, хотя в IoT делают не так) пишется в несколько сот строк кода на Си. Сам пробовал, так что это правда. Причем с поддержкой тегов! Да, они будут просто еще одним enum в union в узле списка (например), так никто и не обязывает generic decoder поддерживать конкретные теги - этим может заниматься приложение, то есть потребитель API либы кодека. Это уже если моему приложению надо, пусть для тега 0 парсит как дату. Либы для скриптовых языков могут автоматически конвертировать такие-то теги в объекты языка (ту же дату), но это удобство, а не необходимость.

В качестве ключей словарей могут выступать почти любые типы данных. Как же должен будет декодироваться словарь с int(1), «1», True и 1.0 ключами? Как это будет выглядеть в Python, Lua, Tcl?

Не "почти", а действительно любые - да-да, ключом может быть даже массив или целая другая мапа! Как он будет выглядеть? Да как и в любом ООП-языке, объект класса Map, у которого есть методы .get() и .set(), и объекты для соответствующих значений. Если в Tcl так не получается ну никак, это всё-таки проблема Tcl, а не формата :) На самом деле, CBOR - как и JSON! - не является чем-то отдельным, а лишь строительный блок (OSI Layer 6, Presentation) для приложения - то есть конкретный протокол на базе CBOR определяет, какие в нём допустимы ключи - допустим, только строки - да и всё остальное, кстати, нужны ж имена, значения... Это абсолютно нормально, пользоваться подмножеством, в том числе для поддержки реализаций, где нативные объекты попроще (хотя, говорят, какой-то протокол в дикой природе с составными ключами уже появился...)

Каноничное представление CBOR по определению не может быть потоковым. Наши два требования — взаимоисключающие для CBOR. Кроме того, не всех устраивают недостаточно строгие правила каноничного представления и придуман ещё и dCBOR, который требует нормализации Unicode символов. Что не очень разумно для embedded систем.

Как я уже показал выше, эти два требования взаимоисключающие по природе, а не в CBOR. И в KEKS будет ровно та же самая проблема - мапу надо отсортировать перед сериализацией, а это не потоково.

Какие реализации CBOR поддерживают строгое декодирование каноничного представления CBOR или dCBOR? Среди нескольких десятков библиотек на Си и Go не нашлось ни одной!

Как я уже рассказал выше, из-за сложности проблемы документ готовился очень долго, а авторы dCBOR решили базировать свой на этом драфте, потому сами находятся в стадии драфта до сих пор, а не RFC (вот недавно его поправили чтоб было без упоминаний, надеюсь теперь будет прогресс). А раз RFC нет, то и авторы библиотек не спешат поддерживать (я тоже хотел реализовать dCBOR, но решил подождать официальной спеки).
Тем не менее, это совершенно не мешало отдельным протоколам на базе CBOR объявлять свои правила для детерминистичного представления, например так сделал Bundle Protocol (см. ниже).

Отдельной проблемой видится желание авторов структур для CBOR экономить на байтах. Вместо плюс-минус человекочитаемых названий ключей, используют целые числа или тэги. Почти старый добрый ASN.1 BER.

Как я уже рассказал выше, это особенность тех CBOR-based протоколов, которые работают вон в тех условиях. На 60 байт особенно не развернетесь, поэтому там предпочитают массивы, а не мапы. Например, [ "lat", "lon" ] даже чисто самими строками занимает 8 байт, а еще заголовок массива. То есть 15% пакета уже сожрано, даже если он не повторяется в нём больше. Это - чрезмерно дохера. Двухбайтовый тег CBOR здесь гораздо, гораздо эффективнее. При этом, понятно, стараются делать такие схемы данных, чтобы избегать даже тегов по возможности.
Но! Это только в сфере constrained-устройств, хотя они и были одной из мотиваций создания CBOR. В "больших" протоколах прекрасно используют человекочитаемые названий ключей, конечно же (Я б тут встречно поехидничал насчет человекочитаемости "a", "v" и "cek", между прочим).

Реальной же проблемой является НЕДОСТАТОЧНОЕ желание авторов [структур для] CBOR экономить на байтах. Тут недостаточно постулатов насчет блоата, щас поясню. Мы вступили в новый мир - забудьте о производительности, теперь самым важным будет являться размер. Это должно быть понятно любому, кто работает на фронте, где врагом является Великий Цензурский Файрвол - я не говорю о простых пользователях трех букв, а о тех, кто придумывает новое в этой области, причем желательно стратегически, а не затыкает текущие дыры. Конкретику предсказать трудно, но ясно, что покуда у нас еще есть онлайн (когда и его не будет, я в сентябре конце прошлого десятилетия на конференции слышал про утилиту NNCP), он будет всё более и более замедляться и/или ограничиваться размером пакетов. Ну, например, при маскировке пакета данных под GET /kotik001.jpg там может быть реальный jpg (допустим прокси нас слушает), в котором несколько десятков байт - наш пакет данных. Или когда еще не настолько жёстко, но наши сорок байт размазаны в полноценном TCP-пакете. То есть приходим к необходимости будущих протоколов работать на примерно тех же размерах, что 802.15.4, но без ограничений по CPU/памяти, и на производительность будет насрать - не до жиру, главное чтоб работало, да и ждали же во времена Фидо и ничего.

Поэтому, замыслив новый гипертекстовый растровый Фидонет, я пока его самого толком не проектировал, а начал с основы - транспортного протокола muSCTP, потому что TCP в таких условиях работать не сможет (а тем более еще более жирный QUIC). Поэтому нужна максимальная экономия байтов и компрессия. Причем с компрессией всё хорошо только на больших данных, RFC 2394 советует на пакетах не менее 90 байт; да и забивать окно компрессора структурами протокола тоже не способствует, лучше увеличить степень сжатия двухфазным подходом. И я реально помучался в попытке сделать более компактный формат, чем CBOR, в итоге решив, что надо не велосипедить с форматом, а просто сделать схему адаптации, чтоб потом, как в криптографии, просто засунуть в любую имеющуюся реализацию CBOR. Кстати о криптографии, на 33-байтных пакетах это тот еще челлендж - все распространенные подходы рассчитаны на оверхед в десятки байт, что не подходит ну никак, блин.

Поэтому я год назад, посмотрев на draft-cbor-packed, ужаснулся неэффективности, и стал доводить свой CBAR до ума и спеки, а дальше расширил его до CBAPT и даже интерпретируемого языка CBOR-TPL, построенного примерно как Tcl, кстати. Подробнее:

MAP кодируется аналогично, но парами key-value значений. Ключ — не пустая строка. Все ключи отсортированы побайтно по возрастанию, с учётом длины (короткие сначала).

Кто из двух будет первым, "abc" или "cd" ? В естественной memcmp-сортировке "abc" будет первым.

для кодирования datetime выделено три тэга: TAI64, TAI64N, TAI64NA. Это предложенный Дэниелем Бернштейном (DJB) формат. 64-бит big-endian количество TAI секунд с 1970-го года, плюс 2**62. «Смещение» значения времени относительно нуля — удобство для того, чтобы время до 1970 можно было указывать без преобразования в отрицательное число.

В этом месте надо поплеваться на DJB ядом, как всегда, за пределами крипты плохое советует. В протоколах, рассчитанных на десятилетия и тем более столетия (а файлы на диске могут лежать в архивах / найтись археологами) очень плохо promote'ить юниксовую эпоху - здесь время должно задаваться хотя б NTP, а лучше в Julian Day, астрономия решает. Но если что, в принятом не так давно CBOR-стандарте [RFC9581] для тега time есть поддержка и TAI с PTP epoch.

BLOB: потоково закодированная бинарная строка:
тэг + 64-бит big-endian chunk-len + BIN(chunk) + ... + BIN(last-chunk).
last-chunk должен иметь меньшую длину чем chunk-len, пускай даже нулевую.
В формате типа ASN.1 CER, который тоже потоковый, все строки насильно разбиваются на кусочки (chunk), что создаёт неудобства для программиста, так как в памяти данные будут расположены не линейно. В KEKS же, чёткое разделение атомарных и потоковых строк. Как правило, мы заранее знаем, где у нас произвольные данные огромного размера могут пойти — там будем применять BLOB.

Непонятно, зачем именно такой формат для блобов всегда, кто такой BIN (наверное у него таки есть своя длина?), ну или на худой конец зачем там сhunk-len аж на 8 байт всегда, если его можно взять просто из первого чанка? А так - ну чисто indefinite-length в CBOR, никакой выгоды.

Дальше идёт про CDDL, и как ни странно, в положительном ключе - видимо, не было опыта применения? Потому что претензию к CBOR можно было бы ожидать как раз здесь - CDDL делали теоретики в башне из слоновой кости для целей формального языка описания протоколов в RFC и генерации примеров по схеме (всяких foo/bar/baz), поэтому для целей валидации входящего пакета, ну точнее вообще для чего делался JSON Schema, оно подходит ну так себе.

Резюмируя по формату: расширения не прописаны, текущий набор типов не строгий/стройный/ортогональный, а какой попало, подвержен тем же проблемам, что и CBOR, в плане детерминизма - они нифига не решены (просто проигнорированы), менее компактный. Смысл существования не оправдан - как и с криптографией, где не следует изобретать свой шифр или хэш из "смотрите, я тоже могу!", так и с сериализацией, лучше взять СТАНДАРТ, для которого уже много десятков имплементаций, есть интероперабельность, экосистема, открытость в плане регистрации новых тегов и т.д., и просто адаптировать под конкретные задачи. На https://www.iana.org/assignments/cbor-tags/cbor-tags.xhtml кстати можно посмотреть, даже конкретно по криптографии уже немаленький такой набор спецификаций есть. Есть COSE, RFC 9360 и даже https://datatracker.ietf.org/doc/draft-ietf-cose-cbor-encoded-cert/ описывающий X.509 - не то что б я любил X.509, но это то, на что первым делом надо было смотреть в поисках альтернативы ASN.1, ибо какой смысл ссать против ветра, разрабатывая не профиль применения, а прям формат?..

А вот язык проверки схем мне очень понравился! Я бы утащил подход в CBOR-TPL, тем более, надо заметить, этот язык никак не привязан к KEKS - он много к чему подойдет, и к CBOR, и даже подмножеству JSON наверное. У меня в дальнейших планах для пущей компрессии описывать вообще распаковку из сырых байт - ну как сырая Си-структура, но с машиночитаемой инфой по преобразованию её в CBOR, чтоб на приёмной стороне не писать распаковщик; думаю, этот подход можно развить дальше и до такого...

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

С тех пор что-то изменилось, наверное? 2017 год, 9-й постгрес...

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

Миллионы мух не могут ошибаться! "Создатели", тоже мне. Этот веб испортился, несите следующий.

одна выписывала препарат, который меня мог убить, неверно интерпретировав картину.

А расскажите, какой (у меня полайтовее ситуация была, но полностью из-за побочек на глаза не сказать чтоб решил)

А зачем ей выделять на любое рандомное поступление йода? Тем более ТТГ вообще не щитовидкой вырабатывается.

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

Да прям.

Видели как мышца сокращается под воздействием электрического импульса?Причем даже свеже-отрезанная лапка лягушки будет сокращаться под воздействием тока.

И чё?

Я её кривые аргументы уже прокомментировал ниже https://habr.com/ru/articles/423811/comments/#comment_29124256

Смешно. Он там два раза вместо аргументов пишет "That is ugly", но потом "Adhering to convention a) yields, when starting with subscript 1, the subscript range 1 ≤ i < N+1; starting with 0, however, gives the nicer range 0 ≤  i < N." - чем сам своему же первому ugly противоречит, которое "into the realm of the unnatural numbers". Итого, с выбором между a-d можно согласиться (как и с пассажем про еретиков), но оно про задание интервалом, а обоснованного перехода к индексам у него нет.

Вообще, об этом даже Дейкстра ещё писал в заметке «Why numbering should start at zero».

Смешно. Он там два раза вместо аргументов пишет "That is ugly", но потом "Adhering to convention a) yields, when starting with subscript 1, the subscript range 1 ≤ i < N+1; starting with 0, however, gives the nicer range 0 ≤  i < N." - чем сам своему же первому ugly противоречит, которое "into the realm of the unnatural numbers". Итого, с выбором между a-d можно согласиться (как и с пассажем про еретиков), но оно про задание интервалом, а обоснованного перехода к индексам у него нет.

Даже Computer Science относится таки к Science, где принята естественная нумерация, а не особенности высокоуровневого ассемблера "Си", где нет ни строк, ни массивов, а есть только указатели и смещения.

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

Сразу видно отсутствие практического опыта, приводят реальный пример, так нет же... Хорошо, сказано "клиентов", ловим на слове. Пусть клиент - это мобильное приложение, то есть мы не можем повлиять на то, когда конкретный юзер обновится, значит в ходу будет одновременно и две, и три версии, и более... А бэкенды не обновлять нельзя. Всё, начинаем городить огород.

Не будете же вы возить ради обратной совместимости в шейпе 100500 полей, которые когда-либо были в типе?

С обычными объектами JSON не будем, хотя какой-то период сосуществования возможен, а вот с "шейпами" - придётся.

В конце концов, вы всегда можете в поле объекта поместить в отдельное поле словарь, куда свободно добавлять новые поля.

Бгы, начинаются костыли. Ладно, допустим добавили, а вот с удалением по-прежнему засада.

> да, хотя бы записи того же fp128, НЕ через существующие типы(иначе это просто конверсия), а именно через расширение стандарта.
В том и фишка, что он не требует для этого расширения.

Неа. Всё, что получится сделать - это boxed-тип, а не примитив. Например класс с полем из бинарной строки длиной 16. То есть вышеозначенная конверсия типов, а не расширение.

Это тоже фича - отсутствие конфигурирования

Вообще это, конечно, шедеврально - выдавать за фичи отсутствие фич, и отсутствие расширяемости и совместимости за расширяемость и совместимость, "которых нет у конкурентов".

Если у вас ещё и проблемы с памятью (что, в принципе, не удивительно при хроническом недосыпе), то можете глянуть мета-информацию по каждому слову тут: https://sync.hyoo.ru/watch/#!section=search/search=jf99kg_f3vfrj/land=jf99kg_f3vfrj/head=tzhgi1_7kcn6x

Какому слову?
Какому слову?

Я вижу здесь какую-то галиматью вместо чего-то похожего на вывод git log -p, интерфейса сравнения драфтов datatracker.ietf.org или хотя бы сравения ревизий страницы на википедии. Пользоваться этим невозможно, совершенно неюзабельно.

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

Вижу, автор приписывает оппонненту то, что в его проекциях характеризовало бы его самого - на технические аргументы ответить нечего, значит, раз пошли оскорбления и переходы на личности (собрал их https://habr.com/ru/articles/966270/#comment_29120442 тут на всякий). По сути-то претензии ответить не может - вот это:

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

Формулу пересчёта внутреннего времени в миллисекунды эпохи юникс найдёте здесь: https://github.com/hyoo-ru/crowd.hyoo.ru/blob/master/time/time.ts#L9

Я ссылки на реализацию даже открывать не буду (тем более на убогих недоязыках) - это ДОЛЖНО быть в спеке. Садись, два.

> Вот ничего подобного, в CBOR значение undefined есть ошибка. Это не какое-то там "оба сразу, и true и false, логически непонятное", это вполне конкретная запись ошибки энкодера

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

Ох, лол! Открываем секцию и читаем:

5.7. Undefined Values

In some CBOR-based protocols, the simple value (Section 3.3) of undefined might be used by an encoder as a substitute for a data item with an encoding problem, in order to allow the rest of the enclosing data items to be encoded without harm.

То есть именно и ровно то, что я написал. Если есть проблемы с пониманием написанного в спецификации (вот уж явно опять проекция с нейролептиками), можно пойти в архивы CBOR mail list, посмотреть задавал ли кто такой вопрос, или взять документацию (не код!) какой-нибудь реализации. Например, CBOR::XS описывает:
true, false, undefined

These CBOR values become [...] and Types::Serialiser::error, respectively. They are overloaded to [...]and false) or to throw an exception on access (for error). See the Types::Serialiser manpage for details.

Я подчеркнул относящееся к undefined.

Не хотелось бы травмировать вашу детскую психику, но всё же отмечу, что логика не ограничена лишь булевой алгеброй, которая принципиально не полна. Подробнее, если захотите лучше разобраться в логике, можете почитать тут: https://page.hyoo.ru/#!=ixy44o_3oga48

Мне давно неинтересно читать философские разглагольствования, парадоксом лжеца или троичной логикой я интересовался в юности, а в мейнстримных языках программирования у нас сугубо булева логика. Помимо того, что я уже показал, что в CBOR оно не для этого, будьте добры продемонстрировать, как с булевым значением "both" должен обращаться реальный код потребителя библиотеки.

Вместо номеров, для них указаны ASCII-символы.

О чем совершенно нет никакой нотации. Ну даже одинарных кавычек типа 'T', принятых во многих языках программирования.

Про представление целых чисел в ЭВМ вообще и дополнительный код в частности вам расскажут в 8 классе.

Автор, видимо, сам из 9 класса, если думает, что в реальной жизни в ходу какой-то один единственный формат, о котором рассказали в учебнике. И особенно это верно в форматах сериализации, где разный порядок байт, variable-length integers могут склеиваться из битовых кусков (а не быть ровным числом байт как в регистре), и знаковый бит может находиться где попало, даже между MSB и LSB нет предпочтения. LEB128 и git передают привет.

Автор, твоя проблема в том, что называемое тобой "фантазиями" в действительности есть многообразие реального мира, о котором у тебя попросту нет знаний, и ты свой узкий взгляд из тесного мирка принимаешь как что-то, понятное всем по умолчанию. Невежество, однако, совершенно не аргумент называть людей, которые видели гораздо больше тебя и предполагают множество вариантов интерпретаций, не понимающими школьниками. Иди лечи свой синдром Даннинга-Крюгера, и заодно на курсы этикета сходи.

> про эллиптические кривые расскажите например Telegram'у

Обязательно расскажу. Сразу после рассказа про E2E-шифрование, которого там до сих пор нет нигде, кроме бестолковых "секретных чатов".

Вообще не аргумент. Пишешь либу работы с Telegram (а у меня конвертер из их ужасного формата в CBOR работает) - должен поддерживать. Или, следуя той же "логике", немедленно откажись от своего Telegram-канала =)

В какой области науки не хватает 2111 бит для целых чисел?

А какая разница? Ни одна известная реализация больших чисел не ограничивает их таким произвольным числом, в формате сериализации поддержать более длинные тоже никакой проблемы не составляет. Вот вообще. Что, неужели для varypack это сложно? =)

> Вполне очевидно, что неупорядоченные мапы нельзя воспроизвести из сортированных туплов, а вот обратное возможно.

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

Вот номер очередной неграмотного владения речью. Что такое "бинаризация"? Определение термина где? Под ним может пониматься уйма вещей, прежде всего "сделать блоб из строки". Если же "бинаризация" значила "сериализация", то опять - садись, два. Более того, в случае мапов он не является упорядоченным - енкодер вправе выдать ключи в произвольном порядке, и я уже говорил, что требование упорядоченности создает большую нагрузку - что, если там миллион-другой ключей? Сортировка будет очень затратна. Не приходит в голову такое, да?

Иными словами, туплы вполне можно вводить в качестве дополнительного типа данных (и среди тегов CBOR подобное есть), но никак не в качестве базы и основы.

Я слабо представляю себе пользу от такого стриминга.

Вот-вот. Иди и изучи реальный мир, прокачай абстрактное мышление, посмотри, что людям на практике требуется. Только после этого пытайся изобретать новые форматы.

> Ну и что должен показать скриншот куска какой-то имплементации, на языке, который я почти не знаю?

Что с совместимостью между CBOR библиотеками всё плохо из-за подхода к реализации этой самой совместимости. В данном случае объекты не отличимы от словарей, ибо в базе есть только мапки, а всё остальное достигается лишь через несовместимые между собой расширения.

Я всё еще жду вменяемого человеческого описания, где именно и как сам подход CBOR - а не какой-то отдельной библиотеки, что может быть багом этой одной конкретной либы - мешает обсуждавшейся прямой и обратной совместимости (а не "между библиотеками", вижу попытку подмены тезиса). Словами через рот, буквами в тексте - не скриншотами, наскальной живописью или обезьяним уханием. Нет, предложение выше таковым не является, потому что за "объекты не отличимы от словарей" в том же IETF немедленно пошлют на три буквы и будут правы - во-первых, в data-модели JSON объект и есть словарь, во-вторых, заявлялось про прямую и обратную совместимость и что варипак её якобы обеспечивает (на самом деле нет - или расширения, или прямая+обратная), а не совместимость расширений между собой, что в общем случае невозможно.

Реализуйте своё шифрование и сможете задействовать до 112 байт.

Нет. Не сможете. Максимум 90 с копейками, путем радикальной смены стека протоколов (то есть не решение), при этом радикально 30-40 байт картину не изменят.

> При этом, понятно, стараются делать такие схемы данных, чтобы избегать даже тегов по возможности.

Очевидно, в таких условиях безсхемные форматы вообще не подходят, ибо возят с собой имена полей туда-сюда. Ваша экономия на 2 строках из 20, погоды тут не сделает.

Схемы по типу protobuf дадут геморрой с майнтенабельностью, чего как раз - наевшись за много лет - хотели избежать. А экономия на строках достигается легко (в теории, на практике много чего проработать надо, варипак так не сможет) путем передачи имени словаря строк вместо самого набора строк, даже однократного. Это сейчас для cbor-packed и CBAR как раз в процессе.

> И схем, типа JSON Schema, нет. А в CBOR есть CDDL

К формату бинаризации это всё и не относится - это не его уровня ответственность.

Не бинаризации, блъ, а сериализации. И нет, это таки его уровня ответственность, потому что есть целые форматы, построенные на схемах, например Protobuf. И у них есть свои достоинства, например производительность и компактность, которые self-described форматы скорее всего достичь не смогут. Именно поэтому CBOR описал иерархию целей, сразу заняв другую нишу - а вот выгод varypack перед protobuf при такой его ригидности пока что не видно.

> если я пришлю ему свой класс MyFooFrobnicate. Которого у вас нет

... то получите его POJO представление.

Необщепринятый термин, даже гуглить не буду, принципиально. Это ваша обязанность говорить языконезависимыми терминами и писать языконезависимые спеки.

> Неизвестный же набор полей вообще в большинстве случаев не несёт информации, от чего именно он.

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

Одним из преимуществ классов/ООП является как раз инкапсуляция, когда никому нет дела, как названы поля внутри, и можно не бояться, что оно с кем-то пересечётся. Varypack своими "шейпами" нарушает этот принцип очень сильно.

> Это может быть, например, невалидный netflow, из которого пропали все поля, кроме таймштампа

От того, что у вас нет значений некоторых полей, сами поля никуда не деваются. [...] Отсутствие значения записывается как none или both

Деваются. Зачем мне их передавать, если их нет? Они "не деваются" только в негибких структурах типа SQL-таблиц, но объекты/мапы JSON хороши как раз тем, что опциональное поле может отсутствовать. Это настолько выгодно при необходимости компактности передачи (о которой заявляет варипак), что применяется в других форматах. Например, в Telegram (при всей ужасности их TL, я в свое время писал на хабр статью), они типично экономят на опциональных полях, передавая их, если только стоит соответствующий бит во флагах:

chatFull#c9d31138 flags:# can_set_username:flags.7?true has_scheduled:flags.8?true translations_disabled:flags.19?true id:long about:string participants:ChatParticipants chat_photo:flags.2?Photo notify_settings:PeerNotifySettings exported_invite:flags.13?ExportedChatInvite bot_info:flags.3?Vector pinned_msg_id:flags.6?int folder_id:flags.11?int call:flags.12?InputGroupCall ttl_period:flags.14?int groupcall_default_join_as:flags.15?Peer theme_emoticon:flags.16?string requests_pending:flags.17?int recent_requesters:flags.17?Vector available_reactions:flags.18?ChatReactions = ChatFull;

Флагов может быть до 32 (хотя пару лет назад стали в некоторых крупных классах второе поле добавлять), то есть передача жестко фиксированных none (бгы, а если у поля null может быть валидным значением) в Varypack приведёт к передаче до 31 лишнего байта, по сравнению с 0 у CBOR или 4 у Telegram.

Даже кошмарный Telegram'ный TL оказался лучше VaryPack, стыдно должно быть!

> Или это может быть вполне валидный объект измерения с датчика, в котором отсутствие значения читается согласно данному конкретному application-layer протоколу как "возьми значение из предыдущей секунды, оно такое же"

Отсутствие значения записывается как none или both. Оно не просто так кортежами называется. Это не словари, где набор полей может быть произвольным.

Они-то называются, а вот их выбор в качестве основного структурного типа - крайне скверный дизайн.

> Это, простите, объект, а не примитивный тип. 

Нет, из туплов могут получаться как объекты так и примитивы.

Не могут. Передайте своему преподавателю, что у вас проблемы с пониманием терминологии. Объект никак не может быть скаляром.

> проще передать само название объекта, хоть то же "UserEntity", а для этого в CBOR уже даже есть готовые теги.

.. которые поддерживаются в одной единственной библиотеке, да.

Все-все пересмотрели? Никто не мешает, однако, реализовать их самостоятельно в своей - спека очень простая.

> Причем, кстати, 27(["Date", 1762848671]) еще и места меньше займет, чем [["unix_time"], 1762848671] - то есть ваш варипак еще и по хваленой компрессии проигрывает.

unix_time - общеизвестный термин. Что скрывается за Date - никому не известно. День месяца? Число секунд? миллисекунд? наносекнд? Какой часовой пояс? Или это вообще идентификатор табельного дня?

Бгы, лол. Автор, у тебя в твоем собственном примере в "спеке" написано new Date - это вот ровно оно и есть. Гораздо лучше передавать имя объекта для определения этого самого объекта, чем определять его набором полей - которые могут пересекаться у разных объектов.

> Да много чего, начиная с естественного упрощения отладки в хексдампах

uint и sint показываются hex-вьювером как есть. Половина spec показываются им как первые буквы имени. Очень удобно. В CBOR до такого не додумались.

Неа, не показываются. Как раз по причине little-endian. И да, в CBOR не стали ломать стройность схемы, усложняя имплементацию, ради четырех букв в дебаге - с числами это приходится делать чаще.

> мы хотим запихнуть ключ в такую базу, при этом она о наших форматах, естественно, ничего знать не будет - она может только сортировать ключи по алфавиту, т.е. в memcmp()-порядке.

В результате имеем некорректную сортировку чисел разной байтовой длины, прекрасно.

Если не умеете сделать разную байтовую длину с обеспечением корректной сортировки, ваши проблемы. Авторы SQLite4 и CBOR умеют.

> Сразу видно человека, который с реальным железом дела не имел, вращаясь в мире розовых пони скриптовых языков. На 1 Кб RAM вообще нет памяти

Честно говоря, это крохоборство меня совсем не интересует. Экстравагантным девайсам - экстравагантные решения.

Неа. Хороший протокол/формат должен быть как советский инженер-строитель - уметь всё, от хибары до небоскрёба. TCP может, от ограниченных контроллеров до терабитных датацентров. CBOR тоже может, от маленьких IoT до строк в 2^64 длиной. Varypack не может, значит к хорошим не относится.

К "экстравагантным" в этой области можно было бы отнести какой-нибудь LoRaWAN и подобные, где размер пакета вообще 10-20 байт. Там да, только специализированные решения. Но где заводится IP, там должен быть пригоден и общий формат. В конце концов, это удобно, управлять например умным домом с обычного смартфона обычным IP+JSON(CBOR), вместо специализированных железяк для конвертации.

В общем, вменяемых аргументов я так и не увидел.

Я так понимаю, "достал" он всех манерой общения? Вот в https://habr.com/ru/articles/966270/comments/#comment_29118098 вижу целую пачку оскорблений и переходов на личности вместо технических аргументов:

... если бы вы более внимательно читали, и меньше фантазировали. СДВГ хоть и не лечится, но его симптомы вполне поддаются купированию, если не запускать.

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

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

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

Не хотелось бы травмировать вашу детскую психику, но

Про представление целых чисел в ЭВМ вообще и дополнительный код в частности вам расскажут в 8 классе. Учебник рекомендовать не буду, чтобы не перегружать лишней информацией, а то ваш 1КБ может совсем переполниться.

Информация

В рейтинге
2 264-й
Откуда
Москва и Московская обл., Россия
Дата рождения
Зарегистрирован
Активность

Специализация

Специалист
FreeBSD
Perl