Čteno 14. 9. 2026 proti IAM.md na commitu 9e95c989. Píše autor prvního auditu, takže opět ne nezávislý hlas.
Souhrn: tohle je dobrá práce a dva nálezy v ní jsou lepší než cokoli v mém auditu. Doporučuju přijmout, s devíti doplňky. Jediné rozhodnutí, které se nedá odložit, je identifikace profilu, a tam bych se přiklonil jinam, než k čemu se návrh kloní.
Důkaz o forku musí být autentizovaný (graph-validation §2). To je nejlepší nález celé téhle výměny. V algoritmu 1.0 krok 5 prochází sourozence takto: s != r AND (s.tree, s.context, s.actor) == chain_key AND s.prev == r.prev. Žádná podmínka na platnost s. Kdokoli tedy může vyrobit záznam s cizím actor, správným prev a naprosto vymyšleným podpisem, a tím trvale zlomit řetězec oběti. Žádný klíč k tomu není potřeba.
Nejde o teorii, protože spec sama tu cestu otevírá na dvou místech. Za prvé v sekci o ukotvení: nový účastník smí převzít ukotvenou množinu od důvěryhodného protějšku. Za druhé v poznámkách k algoritmu, kde se výslovně tvrdí, že krok 2 znovu ověřuje invariant admission, „takže vyhodnocení nezávisí na tom, že admission proběhla správně“. Sourozenecká kontrola je přesně to místo, kde tohle tvrzení neplatí. Návrh to opravuje správně a navíc správně dodává, že zpětné datování nesmí důkaz o dvojím podpisu smazat.
Rezervace genesis klíče (graph-validation §4) opravuje mě. V auditu jsem napsal, že únik genesis klíče je inertní, protože genesis není členem grafu. To platí jen do chvíle, kdy ho někdo přijme. Genesis veřejný klíč je veřejně čitelný z bootstrapu, je to platný Ed25519 klíč a nic v 1.0 nebrání kterémukoli platnému členovi vydat na něj obyčejný ACCEPT. Pak držitel neuklizeného klíče podepisuje jako plnoprávný člen. Erasure je tedy nosná, ne pás k šlím, a moje věta o tom byla špatně.
K tomu dvě menší, kde je verze v návrhu lepší než moje:
Zdůvodnění p=1 je celé chybné, nejen jeho bezpečnostní věta. Argon2 parametr m je celková paměť napříč drahami, takže „čtyři paralelní 64MiB buffery“ nikdy neexistovaly; p=4 by spotřebovalo stejných 64 MiB ve čtyřech drahách po 16. Můj nález 13 mířil na poznámku o odolnosti, návrh odstraňuje i ten důvod. Souhlas i s tím, že p se měnit nemá, protože by to změnilo odvozené klíče.
Nejednoznačnost vstupu do pečeti. Spec píše pub_hash = SHA-512(public_key) a o kus výš definuje veřejný klíč jako 64 hexadecimálních znaků. Přehlédl jsem to. Rozdíl není kosmetický, tady je tentýž klíč přečtený třemi způsoby:
pubkey d48a52a5…88ef
SHA-512(32 bajtů) horizon arch heath fleet
SHA-512(hex textu) onyx maple heron moss
SHA-512(HEX textu) wake grain frost cloud
Tři implementace, tři pečeti, jedna identita. Rozhodnutí pro syrové bajty je správné.
Kryptografický profil v §1 má vlastnost, kterou bych zvlášť pochválil, protože nevypadá jako náhoda: tím, že se A i R zamknou do podgrupy prvořádu ([L]A = O, A != O, [L]R = O) a S do 0..L-1, přestává být volba mezi kofaktorovou a nekofaktorovou rovnicí pozorovatelná. Ověřovač postavený na libsodium a ověřovač s kofaktorovou rovnicí dojdou ke stejnému výsledku. Přesně tohle se od profilu chce: ne vybrat jednu z možností a doufat, ale zúžit vstupy tak, aby na té volbě nezáleželo. Povolení R = O s uvedeným odůvodněním je v pořádku.
Uzavřené schéma obálky i záznamu, omezení číselných tokenů na 0|[1-9][0-9]*, kanonická base64 s kontrolou přes zpětné zakódování, odmítnutí duplicitních klíčů až po dekódování escape sekvencí a zákaz zahazovat neznámá pole před ověřením: každý z těch bodů zavírá jedno místo, kde se dvě implementace mohly rozejít. HKDF s povinným Extract i Expand je další reálná nejednoznačnost, kterou jsem minul.
Procesní disciplína je nadprůměrná. Status „PROPOSED, not adopted“, oddělení erraty od změny pravidel, věta, že širší změna se nesmí vydávat za redakční, a připnutí auditních artefaktů k původnímu commitu. Tohle je lepší hygiena než u většiny vydaných specifikací.
Návrh správně pojmenovává jádro problému: štítek 1.1 na dokumentu nevybírá pravidla na drátě, v=1 a prefixy IAM1:* nový profil nekódují, a dva hostitelé s různými profily mohou pod stejným tree id uznávat různé záznamy. Souhlas, a je to hlubší postřeh než cokoli v mém auditu.
Kloní se ale k vnějšímu výběru profilu z důvěryhodné konfigurace. Proti tomu mám tři argumenty.
Za prvé, tree id tím přestává identifikovat graf a začíná identifikovat jen jeho bootstrap. Dvě komunity mohou sdílet tree id a neshodnout se na členství. Spec přitom tree id staví jako obsahově vázanou identitu grafu.
Za druhé, „důvěryhodná konfigurace nebo autentizovaná dohoda“ je v jinak offline protokolu nejslabší článek. Celý smysl je, že k ověření není potřeba živá instituce. Profil z konfigurace ji tiše vrací zpátky, jen se jí neříká instituce.
Za třetí, cena. Migrační náklad je úměrný instalované základně. Pokud je jediný živý strom pořád ten s jediným bootstrap kořenem a bez následných záznamů, je ten náklad dnes prakticky nulový. Za rok už nebude. Tohle si ověř, než se rozhodne, protože na tom rozhodnutí to stojí.
Minimální konkrétní podoba: nechat tvar záznamu i v=1 beze změny a lišit jen doménový prefix pro tree id (IAM1:tree\0 pro 1.0, jiný řetězec pro 1.1). Staré stromy si ponechají svoje id pod starými pravidly, nový strom má id obsahově vázané na pravidla, kterými se řídí. Žádné nové pole, žádná nová verze záznamu, nic ke konfiguraci. Druhá varianta je vložit identifikátor profilu do bootstrap deskriptoru, což je čistší, ale mění tvar deskriptoru.
Pokud vnější výběr přesto vyhraje, patří do textu jedna věta: samotné tree id není tvrzením o interoperabilitě, jednotkou je dvojice profil a tree id.
Podporuju to, a to argumentem, který v dokumentu není: §3 zavírá díru se zpětným datováním. Můj nález 5 předpokládal, že monotónnost řetězce omezuje, jak hluboko může aktér datovat dozadu. V 1.0 to neplatilo: nemonotónní záznam se odmítl, ale jeho potomek se přes něj aplikoval, takže si aktér mohl resetovat čas pod vlastní hlavu a pokračovat. S §3 to nejde. Monotónnost m je tedy bezpečnostní vlastnost, ne hygiena, a pravidlo je správné.
Cena je reálná a stojí za to ji napsat nahlas: chybný klíček na hodinách teď zabije řetězec stejně spolehlivě jako dvojí podpis. Způsoby, jak si nevratně zlomit řetězec, jsou nově dva místo jednoho. Obrana je na straně podepisujícího a je to táž obrana jako proti forku: runtime musí znát hlavu vlastního řetězce a odmítnout podepsat pod ni. Dal bych obě povinnosti na jedno místo jako závazky podepisujícího, ne je nechal roztroušené mezi fork a monotónnost.
[L]A = O je plnohodnotné násobení skalárem na každý klíč, tedy zhruba zdvojnásobení ceny ověření. Na PIS a PIZE nad velkou ukotvenou množinou to není zanedbatelné. Buď to přiznat a změřit, nebo připustit ekvivalentní rychlejší test, nebo zavést cache ověřených klíčů vázanou na profil.id podpis nekryje. Deduplikace podle id v §1 řeší stav grafu, ale profil by měl říct, která obálka se uchová a že bajty podpisu nejsou součástí identity záznamu.(tree, context). Abortovat kvůli tomu, že v témže souboru je záznam z neznámého cizího stromu, je zbytečná vazba. Buď požadavek omezit na scope, nebo říct, že ukotvené množiny jsou vždy per strom.Přijmout. Jedno vydání, ne dvě, souhlasím s návrhem. Jediná výhrada k tomu: současný text obsahuje věcně chybné zdůvodnění u p=1 a zavádějící větu o m, a obojí dnes aktivně mate implementátory. Pokud se 1.1 protáhne, vydal bych erratu dřív, ale s viditelnou poznámkou, že revize validace probíhá a konformitu 1.0 zatím nelze testovat.
Rozhodnutí, které se nedá odložit, je identifikace profilu. Všechno ostatní v těch třech dokumentech snese měsíc. Tohle ne, protože jeho cena roste s každým stromem, který mezitím vznikne.