Po drátě 6: Řešení úlohy č. 9

QR kód ze zadání úlohy

Ejhle, QR kód. Pokud zkusíte na monitor namířit mobil s dekodérem, nejspíš neuspějete. Ale pokud nějaký dekodér (třeba Zxing Online) nakrmíte přímo obrázkem, hned se dozvíte, že kód obsahuje URL http://en.wikipedia.org/w/index.php?title=QR_code. Nic moc, že je to QR kód, to už jsme věděli.

Kde tedy bude schované heslo? Nejspíš jsou v kódu ještě nějaká další data. Tak zkusíme URL zpětně zakódovat a porovnat se zadáním:

První pokus o zakódování URL

No tedy, to vypadá úplně jinak! Po chvíli ale zjistíme, že enkodér má několik zajímavých parametrů, konkrétně verzi kódu (ta udává jeho velikost, a tedy i kapacitu) a úroveň ochrany proti chybám. Chvíle experimentování odhalí, že velikost zadání odpovídá verzi 10. Když jsme si navíc mohli dovolit přes kód jen tak plácnout logo hry, bude nejspíš odolnost proti chybám nastavená dost vysoko, tak zkusme maximální možnou. Vyjde následující kód, od zadání ovšem stále dost odlišný. Tak zkusme zjistit, kde se všude liší – pravý obrázek ukazuje XOR se zadáním:

Druhý pokus o zakódování URL XOR oproti zadání

XOR vypadá zvláštně. Pravidelný vzorek a v něm dvě oblasti podoby rozsypaného čaje. Ta dolní je jasná, tam bylo nakresleno logo hry. Ale co ta horní? Zkusme doplnit pravidelný vzorek i do těchto částí a podívat se, v čem se liší:

Pravidelný vzorek Nepravidelnosti

Heslo je na světě, ale uznejte, že metodou jaksi haluznou. Speciálně hádání stupně zabezpečení a doplňování jakéhosi pravidelného vzorku, aniž bychom věděli, kde se vzal, má k elegantnímu řešení dost daleko.

Začteme se proto do specifikace a zkusíme přijít na kloub tomu, jak QR kódy fungují. Nejprve si označme různé speciální oblasti:

Anatomie QR kódu

Žlutě jsme vyznačili hlavní zaměřovací značky (podle těch se pozná, kde kód leží a jak je natočený), oranžově vedlejší zaměřovací značky (ke korekci zkosení), růžově synchronizační značky určující velikost bitů v obou směrech. Modré části popisují verzi kódu (opravdu je to verze 10), červené jeho formát (úroveň zabezpečení maximální a masku č. 1).

Vida, masku... to v parametrech enkodéru (aspoň toho našeho) jaksi chybělo. Během kódování se totiž celý obrázek vyxoruje jedním z osmi definovaných maskovacích vzorků, přičemž se zvolí taková maska, aby výsledný kód nebyl ani moc černý, ani moc bílý a aby se v něm nacházelo co nejméně artefaktů, které by mohly komplikovat dekódování (například tím, že by vypadaly jako některá ze zaměřovacích značek).

A právě to, že náš kód používal úplně jinou masku než ten, který vypadl z obvyklého enkodéru, způsobilo, že jejich rozdíl byl téměř všude nějaký pravidelný vzorek. Mimochodem, maska, kterou jsme vybrali, dostala podle standardního hodnotícího algoritmu jen o maličko víc trestných bodů než ta nejlepší. Vypadá takto:

Maska č. 1

Zde bychom se mohli zastavit a úlohu vyřešit drobnou úpravou enkodéru a vyxorováním jeho výstupu se zadáním. Ale jsouce zvědaví, nahlédneme do tajů konstrukce QR kódů ještě trochu hlouběji. Kód odmaskujeme a prohlédneme si ho podrobněji:

Odmaskovaný kód

Obrázek je složený z 57×57 = 3249 modulů (tak se v hantýrce okolo kódů říká jednotlivým elementárním čtverečkům). Z toho 414 zabírají zaměřovací a synchronizační značky, 67 popisuje verzi a formát a zbylých 2768 obsahuje data rozdělená do 346 bloků po 8 bitech (vyznačeny zeleně).

Bloky se hledají takto: začneme v pravém dolním rohu a chodíme po sloupečcích širokých 2 moduly střídavě nahoru a dolů (sloupce bereme zprava doleva). Na každém řádku nejdříve použijeme pravý modul a pak ten levý. Blok začína nejvyšším bitem a končí nejnižším. Moduly, které už jsme použili pro synchronizaci apod., přeskakujeme. První blok tedy obsahuje hodnotu 01000000, druhý 10110110, poslední 11101101.

Bloky se nicméně nečtou v tomto pořadí. Data jsou v kódu verze 10 rozdělena na 8 částí a každá z nich je zvlášť ochráněna proti chybám. Prvních 6 částí se skládá z 43 bloků (z toho 15 datových a 28 ochranných), zbylé 2 části z 44 bloků (16 datových, 28 ochranných). V obou případech se proti chybám chráníme Reedovým-Solomonovým samoopravným kódem s kódovou vzdáleností 28, který dokáže v každé části opravit až 14 chyb. Tak to pojďme udělat:

Kód po opravě chyb

Modře jsou vyznačena místa, kde nastaly chyby (celkem v 87 blocích, což je dost blízko hranice možností použitého opravného kódu, proto také nefungovaly čtečky v mobilech – po přidání nepřesností vzniklých při sejmutí z obrazovky bylo chyb už příliš).

Nakonec najdeme jednotlivé části dat:

Rozložení částí do bloků

Části jsou uloženy na střídačku, vždy jeden blok z každé části. Datové bloky první části jsou označeny zeleně (obsahují byty 40 03 16 87 47 47 03 a2 f2 f6 56 e2 e7 75 96 hexadecimálně), ochranné bloky fialově. Datové bloky druhé části azurově (data: b6 97 06 56 46 96 12 e6 f6 26 72 f7 72 f6 96). Ostatních 6 částí jistě najdete sami.

Zbývá tedy části pospojovat za sebe a zjistit, co v nich je napsáno. První 4 bity určují způsob uložení znaků (čtyřka značí "8 bitů na znak", jiné možnosti by byly třeba kompaktní kódování anglické abecedy, čísel nebo japonštiny), ve verzi 10 dalších 16 bitů (0031) udává počet znaků. Pak už následují jednotlivé znaky: 68 74 74 70 3a 2f 2f 65 6e 2e 77 59 6b 69 70 65 64 69 61 2e 6f 62 67 2f 77 2f 69 atd., tedy přesně text URL z Wikipedie.

Poznámky

Úloha se nechtěně stala připomínkou toho, že Wikipedii není radno brát příliš vážně. Až při kreslení obrázků ke vzorovému řešení jsme zjistili, že některé ukázky struktury kódu v článku o QR kódech odpovídají zastaralé podobě "model 1", kterou takřka nemáte šanci potkat ve světě a tím méně v této úloze.

Setkání s normami vydávanými ISO je pro člověka zvyklého na internetové standardy značný kulturní šok. Ať už v preciznosti formulací nebo v dostupnosti. Velebena buď IETF.

Autorem úlohy je Medvěd, který konečně našel záminku k důkladnému průzkumu fungování dvojrozměrných kódů.

Re: Po drátě 6: Řešení úlohy č. 9 pavian (25. 1. 2012 - 13:32) Sbalit(1)
na teto uloze jsme umreli, i kdyz jsme byli blizko (udelal jsem si rozdily podobne jako haluz metoda XOR, ale netrklo me to). Napoveda 1 byla k nicemu, protoze tu hroznou ISO dokumentaci jsme uz meli, druha nas jenom zmatla, protoze jsme mysleli, ze heslo ziskame opravou casti, kde je "PODRATE6". Orgum klobouk dolu, dostali jste nas!
Re: Po drátě 6: Řešení úlohy č. 9 jan (25. 1. 2012 - 13:33) Sbalit(2)
V textu je drobná nepřesnost - červeně jsou označena místa, kde je uložen formát, a modře verze.
A doplnich bych zkušenost, že moje čtečka v mobilu s tím neměla problém, i když jsem ještě další bity pokusně skrýval.
Re: Po drátě 6: Řešení úlohy č. 9 Martin Mares (org) (25. 1. 2012 - 13:39) Sbalit(1)
> V textu je drobná nepřesnost - červeně jsou označena místa, kde je uložen formát, a modře verze.

Ej, uklepl jsem se. Díky, opraveno.

Re: Po drátě 6: Řešení úlohy č. 9 milan.bohacek (25. 1. 2012 - 14:30) Sbalit(1)
Já úlohu vyřešil profackováním C# implementace z zxing.
Re: Po drátě 6: Řešení úlohy č. 9 Tomas Vondra (25. 1. 2012 - 14:38) Sbalit(4)
Ja uz jsem to skoro mel, vcetne demaskovani obou obrazku upravenym (silne zmrvenym) dekoderem zxing a urcenim oblasti, kde heslo bude. Co me ale zastavilo bylo, ze jsem kvuli skole nestihl najit zadny program, ktery by dokazal rychle vyxorovat dva obrazky.
Proto dotaz na autory - cim obvykle xorujete obrazky, a jak jste udelali ty pekne vizualizace na tehle strance? Snad ne rucne?
Re: Po drátě 6: Řešení úlohy č. 9 Tomáš Janoušek (25. 1. 2012 - 14:40) Sbalit(1)
Já to xoroval v GIMPu. Stačí mít dvě vrstvy a u té druhé nastavit překrývání na rozdíl nebo tak cosi. Dokonce stačilo i jen hýbat průhledností té horní vrstvy a mozek si ten nápis v tom sám našel.
Re: Po drátě 6: Řešení úlohy č. 9 Martin Mares (org) (25. 1. 2012 - 14:43) Sbalit(1)
> Proto dotaz na autory - cim obvykle xorujete obrazky,

Zrovna tady jsem to dělal Gimpem (položit vrstvy přes sebe a té horní dát
mód "difference"; jen pozor, že pracuje nad hodnotami pixelů, takže jednička
je bílá). Ale např. ImageMagickem to jde také a v netpbm jsem na to myslím
před časem také nějaké udělátko viděl.

> a jak jste udelali ty pekne vizualizace na tehle strance? Snad ne rucne?

Napůl ručně za pomoci všelijaké magie v Gimpu. Dost jsem váhal, jestli si
na to mám napsat program, ale vzhledem k pokročilé noční hodině jsem usoudil,
že mi 2 hodiny mechanické práce půjdou lépe než 2 hodiny programování :)

Re: Po drátě 6: Řešení úlohy č. 9 MP (25. 1. 2012 - 19:49) Sbalit(1)
Xoroval jsem to v obycejnem prohlizeci. Nahral jsem si do adresare oba obrazky a pak zmackl page down - prechod na dalsi obrazek v adresari. Pridrzeni pagedown zpusobilo ze obrazky se zacaly stridat velmi rychle po sobe (nezmenene casti se nemenily, zmenene blikaly 30x za sekundu), takze vnikl takovy vizualni blikavy xor :)
Re: Po drátě 6: Řešení úlohy č. 9 next_ghost (26. 1. 2012 - 2:54) Sbalit(2)
No nic, no, tak jsem byl zas vedle jak ta jedle. Mně napadlo, že heslo bude schované za tím linkem a že potřebuju změnit délku toho QR kódu. Po pár hodinách zjišťování, jak přesně vypadá kódování pánů Solomona a Reeda použité u QR kódů, jsem to vzdal. Na experimenty s výrobou vlastního pomocného QR kódu jsem používal media-gfx/qrencode, ale ten má natvrdo zadrátovanou masku 7 (v úloze byla použitá maska 4), takže jsem tuhle cestu zabalil moc brzo...
Re: Po drátě 6: Řešení úlohy č. 9 jakub (26. 1. 2012 - 9:33) Sbalit(1)
To mě napadlo jako první, ale na to, abych to vyloučil, stačila stupidní úprava existujícího dekodéru a pak to dekódovat ručně.
Re: Po drátě 6: Řešení úlohy č. 9 JS (26. 1. 2012 - 11:54) Sbalit(10)
Skoda, ze me spravne reseni napadlo az pote, co jsem si napsal cely QR dekoder/enkoder.. (puvodne jsem myslel, ze to heslo bude schovane za tim wiki odkazem - problem mozna je, ze ja Podrate vnimam trochu jako programatorskou soutez, a ona ji tak uplne neni :-))

Nicmene, chtel jsem se zeptat, proc maji nekteri v tabulce vysledku penalizaci jinou nez 1h nebo 25h ?
Re: Po drátě 6: Řešení úlohy č. 9 JS (26. 1. 2012 - 11:58) Sbalit(1)
Tedy - cely.. na RS kody uz jsem nemel silu, to jsem delal pres jakousi Javovou knihovnu (druha v C nefungovala). Nastesti ta napoveda byla i motivaci pokracovat dal..
Re: Po drátě 6: Řešení úlohy č. 9 Martin Beranek (26. 1. 2012 - 12:03) Sbalit(7)
Ad penalizace: kvůli organizátorské chybě se nabídka nápovědy prvním hráčům
odeslala později než měla. Protože už si zároveň někdo o nápovědu požádal
a dostal ji, nemohli jsme časový limit globálně zvětšit.

Takže těm, kdo dostali nabídku nápovědy později, než měli, a zároveň nápovědu
využili, jsme jako kompenzaci časový postih adekvátně snížili. (Ono to myslím
nakonec stejně nikde ve výsledném pořadí nehraje roli.)

Marble

Re: Po drátě 6: Řešení úlohy č. 9 JS (26. 1. 2012 - 14:57) Sbalit(6)
Po jake dobe se ty napovedy mely posilat? Mozna jsem tim byl take postizen, ale svedl jsem to na Gmail. Dostal jsem obe napovedy asi 22.1. 10:00, ale ta prvni mela cas asi 21.1. 18:00 (ktera by mi usetrila dost trhani si vlasu predchozi vecer, protoze jsem se snazil ten QR kod dekodovat pomoci Wikipedie - kam vedl ten puvodni odkaz - a tam chybi ta zasadni informace, totiz ze ty datove bloky jsou u delsich kodu zprehazene).

(Ale jelikoz jsem rad, ze jste me nakonec uplne nevykopli, jsem posledni, kdo se chce hadat o poradi. Navic me hra dobre bavila.)
Re: Po drátě 6: Řešení úlohy č. 9 Jirka Benc (org) (26. 1. 2012 - 15:04) Sbalit(1)
Týkalo se to jen druhé nápovědy, první odešla v pořádku. Nápovědy byly odeslány pozdě robůtkem, nebylo to tak, že by seděly někde ve frontě - pokud tedy byl mezi časem odeslání v hlavičkách a časem přijetí velký rozdíl, hledal bych spíš problém někde u googlu.

Všechny, kterých se to týkalo, jsme navíc upozornili mailem.
Re: Po drátě 6: Řešení úlohy č. 9 Martin Mares (org) (26. 1. 2012 - 15:06) Sbalit(4)
> a tam chybi ta zasadni informace, totiz ze ty datove bloky jsou u delsich kodu zprehazene).

Ta se z toho clanku mimochodem vykoukat da, viz obrazek "Larger symbol
illustrating interleaved blocks". Ale vubec se nedivim, cim vic toho
o specifikaci QR kodu vim, tim mi ten clanek pripada pochybnejsi...

Re: Po drátě 6: Řešení úlohy č. 9 Michal Kubeček (26. 1. 2012 - 15:53) Sbalit(1)
On Thu, Jan 26, 2012 at 03:06:54PM +0100, Martin Mares wrote:
> Ta se z toho clanku mimochodem vykoukat da, viz obrazek "Larger symbol
> illustrating interleaved blocks".

Informace, že tam nějaký interleaving je a že je pro každou velikost
jiný (čím větší, tím složitější), se z toho vykoukat dá, ale použitelný
popis toho, jak má vypadat, se mi najít nepodařilo tam ani nikde jinde.
Což bylo možná štěstí, protože takhle mi nezbylo než použít zbarimg
(opatchovaný tak, aby mi ukazoval data před RS korekcí a po ní) a zint
(opatchovaný tak, aby používal natvrdo masku, kterou měl původní kód)
místo abych se psal s implementací těch hrůz.

Re: Po drátě 6: Řešení úlohy č. 9 JS (26. 1. 2012 - 16:40) Sbalit(2)
Mas pravdu, trochu to tam zminene i je. Ja se ridil hlavne podle tech "decoding example" niz, tam je pekny priklad, ale zda se, ze je to tam zrovna spatne (a ten interleave tam neni).

Mozna by bylo uzitecne nahrat tam jeste ten posledni obrazek, kdyz uz jsi si s nim dal takovou praci.
Re: Po drátě 6: Řešení úlohy č. 9 Martin Mares (org) (26. 1. 2012 - 16:42) Sbalit(1)
> Mozna by bylo uzitecne nahrat tam jeste ten posledni obrazek, kdyz uz jsi si s nim dal takovou praci.

Jo jo, mam jiste nutkani ten clanek prepsat ;)

Re: Po drátě 6: Řešení úlohy č. 9 Jirka Benc (org) (26. 1. 2012 - 12:10) Sbalit(1)
Kvůli naší chybě(*) přišla několika lidem nabídka na nápovědu až o několik hodin později, než měla. Jako kompenzaci jsme jim snížili postih.

(*) Dvě nápovědy na jednu úlohu jsme už pár let neposlali. Některé části robůtka byly od té doby kompletně přepsány a podpora dvou nápověd z nich tak nějak zmizela ;-), což nám došlo příliš pozdě. Takže jsme to narychlo dohackovávali během hry. A jak známo, práce kvapná...