Premakni poglavje o koliziji.
This commit is contained in:
parent
21674c1270
commit
1e19f3b9c2
2 changed files with 3113 additions and 3099 deletions
6129
git-obzornik.pdf
6129
git-obzornik.pdf
File diff suppressed because it is too large
Load diff
|
|
@ -83,52 +83,18 @@ Git za izračun imena uporabi _zgoščevalno funkcijo_. Naj bo $B$ množica vseh
|
|||
$
|
||||
H: B -> {0, 1, dots, 2^(n)-1},
|
||||
$
|
||||
ki vsakemu besedilu $b$ priredi $n$-bitno vrednost $H(b)$. Vrednosti zgoščevalne funkcije $H(b)$ pravimo _zgostitev_ vsebine $b$. Funkcija $H$, je izbrana tako, da
|
||||
sprememba enega samega bita v besedilu $b in B$ spremeni vrednost $H(b)$. Poleg mora dobra zgoščevalna funkcija zagotoviti, da je porazdelitev vrednosti $H(b)$ čim bližje enakomerni porazdelitvi. To pomeni, da so vse vrednosti $H(b)$ približno enako verjetne.
|
||||
ki vsakemu besedilu $b$ priredi $n$-bitno vrednost $H(b)$. Vrednosti zgoščevalne funkcije $H(b)$ pravimo _zgostitev_ vsebine $b$.
|
||||
Git hrani datoteke pod imeni, ki so enaka zgostitvi vsebine. Kaj pa če imata dve različni vsebini isto zgostitev. Funkcija $H$ ni injektivna, saj je množica nizov, bistveno večja od množice zgostitev. To pomeni, da imata lahko dve različni datoteki enako zgostitev. Če se to zgodi, rečemo, da pride do _kolizije zgostitve_. V primeru kolizije zgostitve bi Git shranil le eno datoteko, za drugo pa bi predpostavil da je že shranjena. Zato je funkcija $H$ izbrana tako, da
|
||||
sprememba enega samega bita v besedilu $b in B$ spremeni vrednost $H(b)$ in je porazdelitev vrednosti $H(b)$ čim bližje enakomerni porazdelitvi. To pomeni, da so vse vrednosti $H(b)$ približno enako verjetne. Na ta način zmanjšamo verjetnost kolizije. Zato Git lahko predpostavi, da je niz $b$ enolično določen z njegovo zgostitvijo $H(b)$. Več o tem v @sec_kolizije[poglavju].
|
||||
|
||||
Git uporablja zgoščevalno funkcijo _SHA1_. Funkcija SHA1 je posebna implementacija zgoščevalne funkcije, ki se je uporabljala v kriptografiji#footnote[Leta 2017 so raziskovalci
|
||||
Git uporablja $160$ bitno zgoščevalno funkcijo _SHA1_. Funkcija SHA1 je posebna implementacija zgoščevalne funkcije, ki se je uporabljala v kriptografiji#footnote[Leta 2017 so raziskovalci
|
||||
iz CWI Amsterdam in Google Research našli prvi praktični primer dveh različnih pdf datotek, ki imata isto SHA1 zgostitev#cite(<stevens_first_2017>). Opisan napad so poimenovali _SHAttered_. Git je zato z verzijo `v2.13.0`
|
||||
začel uporabljati verzijo SHA1, ki je odporna proti napadu _SHAttered_. Kljub temu razvijalci Gita načrtujejo, da bodo SHA1 postopoma nadomestili z ].
|
||||
začel uporabljati verzijo SHA1, ki je odporna proti napadu _SHAttered_. Kljub temu razvijalci Gita načrtujejo, da bodo SHA1 postopoma nadomestili s SHA-256.].
|
||||
|
||||
Ko datoteko z vsebino $b$ zabeležimo v Git repozitorij, Git izračuna zgostitev vsebine $H(b)$ in jo shrani v datoteko z imenom $H(b)$ v `git/objects`#footnote[V resnici Git shrani vsebino v datoteko z imenom $h_3 h_4 dots h_(40)$ v mapi $h_1 h_2$, kjer je
|
||||
$h_1 h_2 h_3 dots h_(40)$ zapis $H(b)$ v 16-tiškem sistemu. Datoteka, katere vsebina ima zgostitev $H(b)$ enako `8dd6d4bdaeff93016bd49474b54a911131759648` bo shranjena v `.git/objects/8d/d6d4bdaeff93016bd49474b54a911131759648`].
|
||||
Vsebina $b$ je tako vedno dostopna pod imenom, ki je enako njeni zgostitvi $H(b)$. Tako dobimo #link("https://en.wikipedia.org/wiki/Content-addressable_storage")[vsebinsko naslovljivo shrambo objektov], ki je ena od bistvenih značilnosti Gita. Ta način shranjevanja omogoča, da lahko vedno preverimo, če ima shranjenjena vsebina isto zgostitev, kot je njeno ime. Lahko tudi shranimo več različic iste datoteke, saj ima vsaka različica drugačno zgostitev. Zgostitev služi tudi kot kontrola, če je prišlo do kvaritve podatkov, ki so shranjeni v Git repozitoriju.
|
||||
|
||||
=== Kolizije zgostitev in rojstnodnevni paradoks
|
||||
|
||||
Git hrani datoteke pod imeni, ki so enaka zgostitvi vsebine. Kaj pa če imata dve različni vsebini isto zgostitev. Funkcija $H$ ni injektivna, saj je množica nizov, bistveno večja od množice zgostitev. To pomeni, da imata lahko dve različni datoteki enako zgostitev. Če bi prišlo do tega, bi Git shranil le eno datoteko, za drugo pa bi predpostavil da je že shranjena. Na srečo je verjetnost, da bi se kaj takega zgodilo izjemno majhna. Kljub temu, da zgoščevalna funkcija $H$
|
||||
ni injektivna, je verjetnost, da bi imela dva naključno izbrana podatkovna niza isto zgostitev (vrednost $H$) zelo majhna. Zato Git predpostavi, da je niz $b$ enolično določen z njegovo zgostitvijo $H(b)$. Kako bi ocenili verjetnost, da pride do kolizije zgostitev?
|
||||
|
||||
Koliko datotek bi morali shraniti v Git, da bi z znatno verjetnostjo prišlo do kolizije? Vprašanje je povezano z rojstnodnevnim problemom. Kako velika naj bo skupina ljudi,
|
||||
da bo vsaj $50%$ verjetnost, da imata dve osebi na isti dan rojstni dan? Velikost skupine je presenetljivo majhna(23), zato rojstnodnevnei problem včasih poimenujemo paradoks.
|
||||
Vprašanje lahko matematično zastavimo tako. Naključno izberemo $n<d$ števil iz množice ${1, 2, dots, h}$, tako da je vsaka izbira enakomerno porazdeljena. Kolikšna je verjetnost $p(n, h)$, da bosta vsaj dve števili enaki? Verjetnost $p(n, h)$ izračunamo elementarno z verjetnostjo nasprotnega dogodka:
|
||||
|
||||
$
|
||||
1 -p(n, h) = (h dot (h-1) dots.c (h-n+1))/(h^n) = product_(k=1)^(n-1)(1-k/h).
|
||||
$
|
||||
|
||||
Če izraz logaritmiramo, dobimo
|
||||
$
|
||||
log(1 - p(n, h)) = sum_(k=1)^(n-1)log(1-k/h) < -sum_(k=1)^(n-1) k/h=-(n(n-1))/(2h).
|
||||
$<eq_log_ocena>
|
||||
Res! Logaritem je konveksna funkcija, zato so vrednosti manjše od vrednosti na tangenti $log(1-k/h) = log(1-x) < x = k/h$.
|
||||
|
||||
Od tod izpeljemo oceno za $p(n, h)$
|
||||
$
|
||||
p(n, h) > 1 - e^(-(n(n-1))/(2h)) approx 1 - e^(-n^2/(2h)).
|
||||
$<eq_ocena>
|
||||
Za vrednosti $1 << n << h$ je $1- e^(-n^2/(2h))$ tudi dobra aproksimacija za $p(n, h)$.
|
||||
|
||||
Da bi odgovorili kako odporna je zgoščevalna funkcija na morebitne kolizije, moramo rešiti obratno nalogo: največ koliko števil $n(p, d)$ lahko izberemo, da bosta med izbranimi števili vsaj dve enaki z verjetnostjo manjšo od $p in [0,1]$. Natančen odgovor na to vprašanje ni tako preprost #cite(<brink_probably_2012>). Lahko pa uporabimo oceno (@eq_ocena) in čez palec ocenimo:
|
||||
|
||||
$
|
||||
-n^2 approx log(1-p) =>\ n(p, h) approx sqrt(2h log(1/(1-p))) approx sqrt(2h).
|
||||
$
|
||||
|
||||
Funkcija $sqrt(log(1/(1-p)))$ zelo počasi narašča, ko se $p$ približuje $1$, zato jo lahko zanemarimo. Če je zgoščevalna funkcija $160$ bitna, kot je primer za SHA1, je
|
||||
$n approx sqrt(2^(160)) approx 2^(80)$. Znatna verjetnost, da pride do kolizije zgostitev, bi se pojavila, ko bi shranili $2^(80)$ različnih datotek v Git.
|
||||
Raziskovalci, ki so razvili napad _SHAttered_, pa so potrebovali zgolj približno $2^(63)$ primerov, da so prišli do kolizije.
|
||||
|
||||
== Datotečna drevesa
|
||||
|
||||
V vsebinsko naslovljivo shrambo objektov lahko shranimo vsebino datotek in njihovih prejšnjih različic. A kako ohranimo informacijo o imenu datotek in drevesni strukturi mape? Git za to ustvari nov tip objekta _drevo_ (angl. _tree_), ki hrani preprost seznam imen datotek in naslovov na vsebino datotek v mapi. Naslov na vsebino datoteke $b$ je seveda zgostitev vsebine $H(b)$. Seznam imen datotek in zgostitev je preprosta tekstovna datoteka, za katero lahko izračunamo zgostitev. Zgostitev datotečnega drevesa natanko določa tako imena datotek, kot tudi vsebino datotek, ki so vsebovane v mapi. Če se katerakoli datoteka ali ime datoteke v mapi spremeni, se bo spremnila tudi
|
||||
|
|
@ -172,7 +138,7 @@ datotek enaka(npr. `bla.txt` in `mapa/bla.txt`), Git shrani le eno kopijo, ki je
|
|||
#let bla(coord, ..args) = file-object(coord, "bcc138", ..args)[bla]
|
||||
#let blabla(coord, ..args) = file-object(coord, "2ce22b", ..args)[blabla]
|
||||
|
||||
#figure(caption: [Primer datotečnega grafa povezanega z zgostitvami. Zaradi preglednosti smo izpisali le prvih 6 znakov zgostitve.],
|
||||
#figure(caption: [Primer datotečnega grafa povezanega z zgostitvami. Zaradi preglednosti bomo v slikah izpisali le prvih 6 znakov zgostitve.],
|
||||
diagram(
|
||||
{
|
||||
bla((-1, 1), name:<bla>)
|
||||
|
|
@ -199,6 +165,41 @@ vsebina objekta določena z njegovo zgostitvijo. To pomeni, da lahko enostavno p
|
|||
|
||||
]
|
||||
|
||||
== Kolizije zgostitev in rojstnodnevni paradoks <sec_kolizije>
|
||||
|
||||
Git hrani datoteke pod imeni, ki so enaka zgostitvi vsebine. Če imata dve datoteki z različno vsebino
|
||||
isto zgostitev, Git shrani le eno datoteko in pride do izgubil podatkov. Git se zanaša na to, da je verjetnost za to izjemno majhna.
|
||||
Kako bi ocenili to verjetnost?
|
||||
|
||||
Koliko datotek bi morali shraniti v Git, da bi z znatno verjetnostjo prišlo do kolizije? Vprašanje je povezano z rojstnodnevnim problemom. Kako velika naj bo skupina ljudi,
|
||||
da bo vsaj $50%$ verjetnost, da imata dve osebi na isti dan rojstni dan? Velikost skupine je presenetljivo majhna(23), zato rojstnodnevnei problem imenujemo tudi rojstnodnevni paradoks. Vprašanje zastavimo matematično. Naključno izberemo $n<d$ števil iz množice ${1, 2, dots, h}$, tako da je vsaka izbira enakomerno porazdeljena. Kolikšna je verjetnost $p(n, h)$, da bosta vsaj dve števili enaki? Verjetnost $p(n, h)$ izračunamo elementarno z verjetnostjo nasprotnega dogodka:
|
||||
|
||||
$
|
||||
1 -p(n, h) = (h dot (h-1) dots.c (h-n+1))/(h^n) = product_(k=1)^(n-1)(1-k/h).
|
||||
$
|
||||
|
||||
Če izraz logaritmiramo, dobimo
|
||||
$
|
||||
log(1 - p(n, h)) = sum_(k=1)^(n-1)log(1-k/h) < -sum_(k=1)^(n-1) k/h=-(n(n-1))/(2h).
|
||||
$<eq_log_ocena>
|
||||
Res! Logaritem je konveksna funkcija, zato so vrednosti manjše od vrednosti na tangenti $log(1-k/h) = log(1-x) < x = k/h$.
|
||||
|
||||
Od tod izpeljemo oceno za $p(n, h)$
|
||||
$
|
||||
p(n, h) > 1 - e^(-(n(n-1))/(2h)) approx 1 - e^(-n^2/(2h)).
|
||||
$<eq_ocena>
|
||||
Za vrednosti $1 << n << h$ je $1- e^(-n^2/(2h))$ tudi dobra aproksimacija za $p(n, h)$.
|
||||
|
||||
Da bi odgovorili kako odporna je zgoščevalna funkcija na morebitne kolizije, moramo rešiti obratno nalogo: največ koliko števil $n(p, d)$ lahko izberemo, da bo verjetnost pojava dveh enakih števil manjša od $p in [0,1]$? Natančen odgovor na to vprašanje ni tako preprost #cite(<brink_probably_2012>). Lahko pa uporabimo oceno (@eq_ocena) in čez palec ocenimo vrednost $n(p, h)$:
|
||||
|
||||
$
|
||||
-n^2 approx log(1-p) =>\ n(p, h) approx sqrt(2h log(1/(1-p))) approx sqrt(2h).
|
||||
$
|
||||
|
||||
Funkcija $sqrt(log(1/(1-p)))$ zelo počasi narašča, ko se $p$ približuje $1$, zato jo lahko zanemarimo. Če je zgoščevalna funkcija $160$ bitna, kot na primer SHA1, je
|
||||
$n approx sqrt(2^(160)) approx 2^(80)$. Znatna verjetnost, da pride do kolizije zgostitev, bi se pojavila, ko bi shranili $2^(80)$ različnih verzij datotek v Git.
|
||||
Raziskovalci, ki so razvili napad _SHAttered_, so se posebej potrudili in so potrebovali "zgolj" približno $2^(63)$ primerov, da so prišli do kolizije.
|
||||
|
||||
|
||||
Podrobnosti o tem, kako Git hrani podatke, si lahko preberete v knjigi Pro Git
|
||||
#cite(<chacon_102_nodate>, supplement: [pog. 10.2]).
|
||||
|
|
@ -366,7 +367,6 @@ Vse te pomene damo vejam ljudje, ki sodelujemo v nekem Git repozitoriju. Za Git
|
|||
caption: [*HEAD* je referenca na trenutno aktiven vnos. _Index_ vsebuje spremembe, ki bodo zabeležene v naslednjem vnosu.]
|
||||
)
|
||||
|
||||
|
||||
== Povzetek
|
||||
|
||||
Povzemimo sedaj, kaj smo spoznali o podatkovnem modelu Gita.
|
||||
|
|
@ -389,6 +389,7 @@ Omenimo še dva pojma, ki jih uporabljamo pri delu z Gitom:
|
|||
Nekatere operacije pa tudi brišejo vnose (npr. `git rebase`). Takim operacijam rečemo, da spreminjajo zgodovino.
|
||||
Uporabniki morajo biti pri uporabi operacij, ki spreminjajo zgodovino posebej pazljivi, da česa trajno ne zamočijo.
|
||||
]
|
||||
|
||||
= Git ukazi kot operacije na grafu
|
||||
|
||||
Ko smo opremljeni z razumevanjem podatkovnega modela Gita, razložimo kaj pomenijo posamezne operacije, ki jih Git omogoča. Ukazov ne bom prevajal, ampak jih bom navedel kot jih pozna program `git`.
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue