<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0"><channel><title>Undefined Behavior</title><link>https://undefinedbehavior.de/</link><description></description><lastBuildDate>Sun, 08 Dec 2024 12:20:00 +0100</lastBuildDate><item><title>Fiber Cleaner Test</title><link>https://undefinedbehavior.de/blog/fiber-cleaner-tests/</link><description>&lt;h2&gt;Intro&lt;/h2&gt;
&lt;p&gt;This post is a collaboration between &lt;a href="https://chaos.social/@hotaru"&gt;Hotaru&lt;/a&gt;, &lt;a href="https://chaos.social/@Error"&gt;error&lt;/a&gt; and &lt;a href="https://chaos.social/@992jo"&gt;jo&lt;/a&gt;.
It is published at &lt;a href="https://swagspace.org/blog/fiber-cleaner-tests/"&gt;swagspace.org&lt;/a&gt; as well as &lt;a href="https://undefinedbehavior.de/blog/index.html"&gt;undefinedbehavior.de&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The idea behind this post initially came from a &lt;a href="https://media.ccc.de/v/denog16-53304-return-loss-problems-associated-with-faster-optical-networks"&gt;talk at DENOG16&lt;/a&gt; &lt;sup id="fnref:1"&gt;&lt;a class="footnote-ref" href="#fn:1"&gt;1&lt;/a&gt;&lt;/sup&gt; about problems with return loss in optical transmission.
Our question was: How dirty do fibers get and how much work is it to get them clean again.&lt;/p&gt;
&lt;h2&gt;Making fibers dirty&lt;/h2&gt;
&lt;p&gt;We primarily tested two different kinds of contamination.
The first kind is touching the fiber.
The second kind is contamination with dirt, e.g. from the floor.
Both kinds can happen easily when handling fiber.&lt;/p&gt;
&lt;p&gt;It is interesting to see how visually distinct the different kinds of contamination are.
Just touching the polished face of the fiber once with our fingers covered the whole face with a thin grease film.&lt;/p&gt;
&lt;p&gt;&lt;img alt="dirty face of a fiber created by touching it" src="https://undefinedbehavior.de/blog/fiber-cleaner-test/fiber-touched.png" title="dirty face of a fiber created by touching it"&gt;&lt;/p&gt;
&lt;p&gt;Swiping over the face of the fiber leads to a more streaky pattern.&lt;/p&gt;
&lt;p&gt;&lt;img alt="dirty face of a fiber created by swiping over it" src="https://undefinedbehavior.de/blog/fiber-cleaner-test/fiber-swiped.png" title="dirty face of a fiber created by swiping over it"&gt;&lt;/p&gt;
&lt;p&gt;The contamination when touching hair is very similar to touching the fiber with your fingers.&lt;/p&gt;
&lt;p&gt;Dropping the fiber on the floor (in our case a carpet) contaminates the fiber with many small pieces of dirt.&lt;/p&gt;
&lt;p&gt;&lt;img alt="Contamination with dirt after dropping the fiber on the floor" src="https://undefinedbehavior.de/blog/fiber-cleaner-test/fiber-floor.png" title="Contamination with dirt after dropping the fiber on the floor"&gt;&lt;/p&gt;
&lt;h2&gt;Different types of cleaners&lt;/h2&gt;
&lt;h3&gt;Click-Cleaners&lt;/h3&gt;
&lt;p&gt;Click-Cleaners are somewhat pen shaped and fit directly on top of the connector of the fiber.
By pushing down on them, a small cleaning thread is dragged over the face of the fiber, cleaning it in the process.
Afterwards, a spring pushes the cleaner back into it's original position, ready to be used again.&lt;/p&gt;
&lt;h3&gt;Manual swiping&lt;/h3&gt;
&lt;p&gt;Manual swiping cleaners have a button that exposes a piece of cleaning cloth when pressed.
The fiber can then be swiped over the cloth to clean it.
When the button is released, the cover closes and the microfiber cloth moves forward.&lt;/p&gt;
&lt;h3&gt;Miscellaneuos "cleaning utensils"&lt;/h3&gt;
&lt;p&gt;Sometimes you have to improvise.
What if you don't have professional cleaning utensils at hand?
So we looked at wether a pair of work trousers and a piece of cleaning cloth for glasses work, as well as unicorn Ida and the locomotive &lt;a href="https://zug.network/@chuffchuff"&gt;Chuff Chuff&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;Tests&lt;/h2&gt;
&lt;p&gt;We did several tests with each type of cleaner and different kinds of contamination.
We cleaned until the fibers passed IEC 61300-3-35 testing.
The standard defines 4 areas of the fiber. The core (A), cladding (B), a small glue area (C) and the contact area of the ferrule (D).
The test specification allows for some minor defects on the fiber, especially in the contract area. So there might be some contamination left. Keep this in mind when looking at the figures.&lt;/p&gt;
&lt;p&gt;We used an EXFO FIB430B video microscope with automatic analysis features to analyse the fibers.&lt;/p&gt;
&lt;p&gt;All our tests were done on Singlemode LC/UPC connectors.&lt;/p&gt;
&lt;h3&gt;Cletop S&lt;/h3&gt;
&lt;p&gt;&lt;img alt="Cletop S fiber cleaner" src="https://undefinedbehavior.de/blog/fiber-cleaner-test/cletop-s.jpg" title="Cletop S fiber cleaner"&gt;&lt;/p&gt;
&lt;p&gt;The Cletop S is based on manual swiping.
In all 4 tests the Cletop S cleaned the fiber after one swipe.&lt;/p&gt;
&lt;h3&gt;Senko Smart Cleaner&lt;/h3&gt;
&lt;p&gt;&lt;img alt="Senko Smart Cleaner" src="https://undefinedbehavior.de/blog/fiber-cleaner-test/senko-smart-cleaner.jpg" title="Senko Smart Cleaner"&gt;&lt;/p&gt;
&lt;p&gt;The Senko Smart Cleaner is of the click cleaner variety.
In our tests we had the issue, that this cleaner did not reliably clean the fiber.
It looks like some part of the fiber did not get wiped at all.&lt;/p&gt;
&lt;p&gt;This is an example of a dirty fiber before cleaning&lt;/p&gt;
&lt;p&gt;&lt;img alt="dirty face of a fiber" src="https://undefinedbehavior.de/blog/fiber-cleaner-test/senko-dirty.png" title="dirty face of a fiber"&gt;&lt;/p&gt;
&lt;p&gt;And this is the result of the first cleaning.&lt;/p&gt;
&lt;p&gt;&lt;img alt="face of a fiber after 1 click" src="https://undefinedbehavior.de/blog/fiber-cleaner-test/senko-1-click.png" title="face of a fiber after 1 click"&gt;&lt;/p&gt;
&lt;p&gt;We have seen this pattern multiple times with this device during our tests. 3 clicks were necessary in order to reliably clean the fibers.&lt;/p&gt;
&lt;h3&gt;IBC Brand Cleaner Zi125&lt;/h3&gt;
&lt;p&gt;&lt;img alt="IBC Brand Cleaner Zi125" src="https://undefinedbehavior.de/blog/fiber-cleaner-test/ibc-cleaner.jpg" title="IBC Brand Cleaner Zi125"&gt;&lt;/p&gt;
&lt;p&gt;This cleaner is also of the click cleaner variety.
In all but 1 of our 4 tests this cleaner cleaned the fiber in one click.
In the one attempt that didn't clean the fiber, we observed a piece of contamination being moved onto the fiber that wasn't there before.&lt;/p&gt;
&lt;p&gt;&lt;img alt="Contamination with dirt after dropping the fiber on the floor" src="https://undefinedbehavior.de/blog/fiber-cleaner-test/fiber-floor.png" title="Contamination with dirt after dropping the fiber on the floor"&gt;&lt;/p&gt;
&lt;p&gt;This is the uncleaned fiber. [°Note: This fiber passed the IEC test, because the contamination is small enough.]
After cleaning this fiber a large piece of contamination was moved into the contact area that was not on our fiber before (or at least not in the part that we were able to observe with out microscope).&lt;/p&gt;
&lt;p&gt;&lt;img alt="face of a fiber after 1 click" src="https://undefinedbehavior.de/blog/fiber-cleaner-test/ibc-1-click.png" title="face of a fiber after 1 click"&gt;&lt;/p&gt;
&lt;p&gt;Here we can see a large piece of contamination in the top center.
Cleaning it once again removed the defect.&lt;/p&gt;
&lt;p&gt;&lt;img alt="face of a fiber after 2 clicks" src="https://undefinedbehavior.de/blog/fiber-cleaner-test/ibc-2-click.png" title="face of a fiber after 2 clicks"&gt;&lt;/p&gt;
&lt;p&gt;This shows us, that it is possible to introduce new defects through cleaning.&lt;/p&gt;
&lt;h2&gt;Other cleaning utensils&lt;/h2&gt;
&lt;p&gt;We had several other "improvised cleaning utensils" at hand so we did a couple of quick tests.
Hold on tight, we are entering shitpost territory now.&lt;/p&gt;
&lt;h3&gt;Work trousers and microfiber cloths for glasses&lt;/h3&gt;
&lt;p&gt;We did a quick test on a pair of work trousers that were worn for several days.
The results were not great.&lt;/p&gt;
&lt;p&gt;&lt;img alt="dirty face of a fiber" src="https://undefinedbehavior.de/blog/fiber-cleaner-test/es-0-swipe.png" title="dirty face of a fiber"&gt;&lt;/p&gt;
&lt;p&gt;&lt;img alt="face of a fiber after one swipe" src="https://undefinedbehavior.de/blog/fiber-cleaner-test/es-1-swipe.png" title="face of a fiber after 1 swipe"&gt;&lt;/p&gt;
&lt;p&gt;The trousers were not able to get the fiber clean, not even after several swipes.
The other issue with potentially contaminated pieces of clothing is, that you might introduce new contamination.&lt;/p&gt;
&lt;p&gt;We tried the same with used microfiber cloth for glasses.&lt;/p&gt;
&lt;p&gt;&lt;img alt="face of a fiber after one swipe" src="https://undefinedbehavior.de/blog/fiber-cleaner-test/cloth-1-swipe.png" title="face of a fiber after 1 swipe"&gt;&lt;/p&gt;
&lt;p&gt;Technically this fiber is clean according to the standard.
However there is a significant chance, that the defects still on the fiber end up in the center of the fiber.
So we can't recommend this method.&lt;/p&gt;
&lt;h3&gt;Plushies&lt;/h3&gt;
&lt;p&gt;In case you are carrying your plushy companion into the datacenter or the field, they might help you cleaning fibers.
We did tests with multiple different kinds of surfaces on Chuff-Chuff, a locomotive plushie.
Unfortunately none produced good results.&lt;/p&gt;
&lt;p&gt;However the results that were produced by unicorn Ida were surprisingly good.&lt;/p&gt;
&lt;p&gt;&lt;img alt="Ida and Chuff-Chuff cleaning fibers" src="https://undefinedbehavior.de/blog/fiber-cleaner-test/fiber-unicorn.webp" title="Ida and Chuff-Chuff cleaning fibers"&gt;&lt;/p&gt;
&lt;p&gt;Ida got the fiber almost clean with the first swipe:&lt;/p&gt;
&lt;p&gt;&lt;img alt="face of a fiber after one swipe" src="https://undefinedbehavior.de/blog/fiber-cleaner-test/ida-1-swipe.png" title="face of a fiber after 1 swipe"&gt;&lt;/p&gt;
&lt;p&gt;There is only one piece of contamination.
Sadly that one is directly in the center of the fiber where no contamination is acceptable.
Further swipes were not able to remove this contamination. (A purpose-built cleaner did it first try).&lt;/p&gt;
&lt;h2&gt;Conclusions&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Making fibers dirty is surprisingly easy.
  Simply dropping them on the ground or touching them is sufficient.&lt;/li&gt;
&lt;li&gt;The Cletop S and IBC Brand Cleaner usually cleaned the fiber in 1 swipe/click, 2 at most.&lt;/li&gt;
&lt;li&gt;If you are not working on very critical optical interfaces 1 swipe on a cletop or 2 clicks from a good cleaner are sufficient.&lt;/li&gt;
&lt;li&gt;It doesn't occur frequently, but it is possible to reintroduce dirt to the contact area of a fiber from other parts through cleaning.
  If you are working on critical patches, use a scope to verify your work.&lt;/li&gt;
&lt;li&gt;Keep in mind, that this is a limited test on LC-PC/UPC connectors only and that we are only testing the patch cable end of the interface.
  The results might not hold for other types of connectors like E2k, SC or the APC variants of these connectors.&lt;/li&gt;
&lt;li&gt;Due to missing equipment we were not able to test the cleaning performance of the click cleaners in the recepacle part of the connection, e.g. a transceiver.&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="footnote"&gt;
&lt;hr&gt;
&lt;ol&gt;
&lt;li id="fn:1"&gt;
&lt;p&gt;T. Nakagawa. (2024, November) Return loss problems associated with faster optical networks. &lt;a href="https://media.ccc.de/v/denog16-53304-return-loss-problems-associated-with-faster-optical-networks" title="Return loss problems associated with faster optical networks - media.ccc.de"&gt;https://media.ccc.de/v/denog16-53304-return-loss-problems-associated-with-faster-optical-networks&lt;/a&gt;&amp;#160;&lt;a class="footnote-backref" href="#fnref:1" title="Jump back to footnote 1 in the text"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">Hotaru, Error, jo</dc:creator><pubDate>Sun, 08 Dec 2024 12:20:00 +0100</pubDate><guid isPermaLink="false">tag:undefinedbehavior.de,2024-12-08:/blog/fiber-cleaner-tests/</guid><category>blog</category></item><item><title>git commit --vandalism</title><link>https://undefinedbehavior.de/blog/commit-vandalism/</link><description>&lt;p&gt;&lt;em&gt;This is not a vulnerability report.
I intentionally disabled safeguards in the code in order to be able observe this behavior.
However, it's a nice example for why you shouldn't use SHA-1 for anything security related and a good opportunity to learn more about the inner workings of git.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;In 2017, the Cryptology Group at Centrum Wiskunde &amp;amp; Informatica (CWI) and the Google Research Security, Privacy and Anti-abuse Group announced the first (public) SHA-1 hash collision.
They generated 2 PDF files with the same hash in an attack they called SHAttered.
While it still required a lot of processing power (the equivalent of 6,500 years single-CPU computations and 110 years of single-GPU computations), it showed that such attacks are not only theoretically possible - they are technically feasible. &lt;sup id="fnref:1"&gt;&lt;a class="footnote-ref" href="#fn:1"&gt;1&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;p&gt;IDs in git, for example for commits, are generated using SHA-1 by default.
As explained by git's creator, Linus Torvalds, the hash function is not used for security.
It's simply used to generate a checksum, like e.g. a CRC.[°The quote "We check a checksum that's cryptographically secure. Nobody has been able to break SHA-1" didn't hold up that well, but in general, Linus' point still stands: git uses SHA-1 for consistency checks, not for security.] &lt;sup id="fnref:2"&gt;&lt;a class="footnote-ref" href="#fn:2"&gt;2&lt;/a&gt;&lt;/sup&gt;
But what happens if a collision occurs, or someone intentionally causes a collision?
Let's try it out.&lt;/p&gt;
&lt;p&gt;So if the SHAttered files already have a hash collision, they could be used to cause a collision in git, right?
Let's put them in a repository and find out.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;$&lt;span class="w"&gt; &lt;/span&gt;wget&lt;span class="w"&gt; &lt;/span&gt;https://shattered.io/static/shattered-1.pdf&lt;span class="w"&gt; &lt;/span&gt;-O&lt;span class="w"&gt; &lt;/span&gt;shattered1.pdf&lt;span class="w"&gt; &lt;/span&gt;-q
$&lt;span class="w"&gt; &lt;/span&gt;sha1sum&lt;span class="w"&gt; &lt;/span&gt;shattered-1.pdf
38762cf7f55934b34d179ae6a4c80cadccbb7f0a&lt;span class="w"&gt;  &lt;/span&gt;shattered-1.pdf
$&lt;span class="w"&gt; &lt;/span&gt;wget&lt;span class="w"&gt; &lt;/span&gt;https://shattered.io/static/shattered-2.pdf&lt;span class="w"&gt; &lt;/span&gt;-O&lt;span class="w"&gt; &lt;/span&gt;shattered2.pdf&lt;span class="w"&gt; &lt;/span&gt;-q
$&lt;span class="w"&gt; &lt;/span&gt;sha1sum&lt;span class="w"&gt; &lt;/span&gt;shattered-2.pdf
38762cf7f55934b34d179ae6a4c80cadccbb7f0a&lt;span class="w"&gt;  &lt;/span&gt;shattered-2.pdf
$&lt;span class="w"&gt; &lt;/span&gt;diff&lt;span class="w"&gt; &lt;/span&gt;shattered-1.pdf&lt;span class="w"&gt; &lt;/span&gt;shattered-2.pdf
Binary&lt;span class="w"&gt; &lt;/span&gt;files&lt;span class="w"&gt; &lt;/span&gt;shattered-1.pdf&lt;span class="w"&gt; &lt;/span&gt;and&lt;span class="w"&gt; &lt;/span&gt;shattered-2.pdf&lt;span class="w"&gt; &lt;/span&gt;differ
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;As promised, these files have different contents, but the same SHA-1 hash.
The next step is to add them to a git repository and observe what happens.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;$&lt;span class="w"&gt; &lt;/span&gt;cp&lt;span class="w"&gt; &lt;/span&gt;shattered-1.pdf&lt;span class="w"&gt; &lt;/span&gt;shattered.pdf
$&lt;span class="w"&gt; &lt;/span&gt;git&lt;span class="w"&gt; &lt;/span&gt;add&lt;span class="w"&gt; &lt;/span&gt;shattered.pdf
$&lt;span class="w"&gt; &lt;/span&gt;git&lt;span class="w"&gt; &lt;/span&gt;commit&lt;span class="w"&gt; &lt;/span&gt;-m&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;shattered&amp;#39;&lt;/span&gt;
&lt;span class="o"&gt;[&lt;/span&gt;main&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;Root-Commit&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;0aa8c5a&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;shattered
&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;file&lt;span class="w"&gt; &lt;/span&gt;changed,&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;insertions&lt;span class="o"&gt;(&lt;/span&gt;+&lt;span class="o"&gt;)&lt;/span&gt;,&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;deletions&lt;span class="o"&gt;(&lt;/span&gt;-&lt;span class="o"&gt;)&lt;/span&gt;
create&lt;span class="w"&gt; &lt;/span&gt;mode&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;100644&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;shattered.pdf
$&lt;span class="w"&gt; &lt;/span&gt;cp&lt;span class="w"&gt; &lt;/span&gt;shattered-2.pdf&lt;span class="w"&gt; &lt;/span&gt;shattered.pdf&lt;span class="w"&gt; &lt;/span&gt;-f
$&lt;span class="w"&gt; &lt;/span&gt;git&lt;span class="w"&gt; &lt;/span&gt;add&lt;span class="w"&gt; &lt;/span&gt;shattered.pdf
$&lt;span class="w"&gt; &lt;/span&gt;git&lt;span class="w"&gt; &lt;/span&gt;commit&lt;span class="w"&gt; &lt;/span&gt;-m&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;shattered&amp;#39;&lt;/span&gt;
&lt;span class="o"&gt;[&lt;/span&gt;main&lt;span class="w"&gt; &lt;/span&gt;f1906a7&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;shattered
&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;file&lt;span class="w"&gt; &lt;/span&gt;changed,&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;insertions&lt;span class="o"&gt;(&lt;/span&gt;+&lt;span class="o"&gt;)&lt;/span&gt;,&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;deletions&lt;span class="o"&gt;(&lt;/span&gt;-&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Looking at the result, this did not seem to cause any issues.
If the commit ID is a SHA-1 hash, shouldn't this cause a commit ID collision?
Such a collision did not happen.
The file was updated successfully in the second commit and checking out the first commit restores the original version.
Investigating this closer shows that git somehow calculates different hashes for these files.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;$&lt;span class="w"&gt; &lt;/span&gt;git&lt;span class="w"&gt; &lt;/span&gt;hash-object&lt;span class="w"&gt; &lt;/span&gt;shattered-1.pdf
b621eeccd5c7edac9b7dcba35a8d5afd075e24f2
$&lt;span class="w"&gt; &lt;/span&gt;git&lt;span class="w"&gt; &lt;/span&gt;hash-object&lt;span class="w"&gt; &lt;/span&gt;shattered-2.pdf
ba9aaa145ccd24ef760cf31c74d8f7ca1a2e47b0
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Internally, git is a key-value store.
It generates an ID for each object that it stores, which can later be used to identify and retrieve the object.
By default, this ID is a SHA-1 hash.
The input given to the hash function depends on the object type.
For files, which are stored as so called blobs, the ID is generated by hashing the string &lt;code&gt;blob&lt;/code&gt;, the length of the file, a null byte and the file itself. &lt;sup id="fnref:3"&gt;&lt;a class="footnote-ref" href="#fn:3"&gt;3&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;$&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;so long and thanks for all the fish&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;test.txt
$&lt;span class="w"&gt; &lt;/span&gt;git&lt;span class="w"&gt; &lt;/span&gt;hash-object&lt;span class="w"&gt; &lt;/span&gt;test.txt
8b86cb67f1f19db567a100b55edb5466a33e7fb7
$&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;printf&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;blob &lt;/span&gt;&lt;span class="k"&gt;$(&lt;/span&gt;wc&lt;span class="w"&gt; &lt;/span&gt;-c&lt;span class="w"&gt; &lt;/span&gt;&amp;lt;test.txt&lt;span class="k"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;\0&lt;/span&gt;&lt;span class="k"&gt;$(&lt;/span&gt;&amp;lt;test.txt&lt;span class="k"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;\n&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;sha1sum
8b86cb67f1f19db567a100b55edb5466a33e7fb7&lt;span class="w"&gt;  &lt;/span&gt;-
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Blobs can be assigned names to using tree objects.
These objects can group multiple blobs and trees, which are referenced by their id. &lt;sup id="fnref2:3"&gt;&lt;a class="footnote-ref" href="#fn:3"&gt;3&lt;/a&gt;&lt;/sup&gt;
A tree object could look like this for example:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;$&lt;span class="w"&gt; &lt;/span&gt;git&lt;span class="w"&gt; &lt;/span&gt;cat-file&lt;span class="w"&gt; &lt;/span&gt;-p&lt;span class="w"&gt; &lt;/span&gt;8004c8a7b6fce1452539556bb4c4c91b92b5c2bc
&lt;span class="m"&gt;100644&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;blob&lt;span class="w"&gt; &lt;/span&gt;ba9aaa145ccd24ef760cf31c74d8f7ca1a2e47b0&lt;span class="w"&gt;    &lt;/span&gt;shattered.pdf
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;However, one does not usually work directly with blobs and trees.
It's what git uses internally, but from a user perspective, it's usually not necessary to interact with git on that level.
The usual workflow consists out of editing files, staging these changes and then committing them.
Commits are just another object type in git.
These objects associate a tree with an author and committer,[°The author and the committer can be different. The author is who wrote the code and the committer is who added it to the repository.] a parent commit (if it exists) and a commit message to describe to changes included in this commit. &lt;sup id="fnref3:3"&gt;&lt;a class="footnote-ref" href="#fn:3"&gt;3&lt;/a&gt;&lt;/sup&gt;
The resulting object can once again be viewed with &lt;code&gt;git cat-file&lt;/code&gt;.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;$&lt;span class="w"&gt; &lt;/span&gt;git&lt;span class="w"&gt; &lt;/span&gt;cat-file&lt;span class="w"&gt; &lt;/span&gt;-p&lt;span class="w"&gt; &lt;/span&gt;f1906a7bf1c4c8ce49f264e2f3ba313c305b7ede
tree&lt;span class="w"&gt; &lt;/span&gt;8004c8a7b6fce1452539556bb4c4c91b92b5c2bc
parent&lt;span class="w"&gt; &lt;/span&gt;0aa8c5ad0be568d680d5f613807bde46a39424e3
author&lt;span class="w"&gt; &lt;/span&gt;error&lt;span class="w"&gt; &lt;/span&gt;&amp;lt;redacted&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;1683729684&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;+0200
committer&lt;span class="w"&gt; &lt;/span&gt;error&lt;span class="w"&gt; &lt;/span&gt;&amp;lt;redacted&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;1683729684&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;+0200

shattered
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The commit ID is generated by hashing this information, prepended by the same header that is used for the other object types: &lt;code&gt;$object-type $length\0&lt;/code&gt;.[°You can find a nice example how the commit hash is constructed &lt;a href="https://gist.github.com/masak/2415865" title="How is git commit sha1 formed"&gt;here&lt;/a&gt;.]&lt;/p&gt;
&lt;p&gt;OK, so that's the reason why &lt;code&gt;git hash-object&lt;/code&gt; returns different values for the two SHAttered files.[°Try it yourself if you want: prepending any data to these files will make their SHA-1 hashes differ. &lt;code&gt;echo test | cat - shatterd-1.pdf | sha1sum&lt;/code&gt; results in a different hash than &lt;code&gt;echo test | cat - shatterd-2.pdf | sha1sum&lt;/code&gt;]
Further, this explains why the commit hashes didn't collide.
There won't be any progress made by using the existing SHA-1 hash collision from SHAttered, but collisions can still happen.
It's unlikely to find one by accident and it's expensive to cause them intentionally, but it's not impossible.
How would git behave in this case?
Let's vandalize the code a little bit and find out.&lt;/p&gt;
&lt;p&gt;Git can be built with multiple different SHA-1 backends.
By default, it uses an implementation with a collision attack detection mechanism.[°This collision attack detection is not relevant for our experiment for now. We'll get back to it later.]
It can be found in the &lt;code&gt;SHA1DC&lt;/code&gt; directory.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;SHA1DCFinal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;unsigned&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;output&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;SHA1_CTX&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;uint32_t&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;last&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;total&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;63&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;uint32_t&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;padn&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;last&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;56&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;56&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;last&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;120&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;last&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;uint64_t&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;total&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;SHA1DCUpdate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)(&lt;/span&gt;&lt;span class="n"&gt;sha1_padding&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;padn&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;total&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;total&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;padn&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;total&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;lt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;buffer&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;56&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;unsigned&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="p"&gt;)(&lt;/span&gt;&lt;span class="n"&gt;total&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;56&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;buffer&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;57&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;unsigned&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="p"&gt;)(&lt;/span&gt;&lt;span class="n"&gt;total&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;48&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;buffer&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;58&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;unsigned&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="p"&gt;)(&lt;/span&gt;&lt;span class="n"&gt;total&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;40&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;buffer&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;59&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;unsigned&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="p"&gt;)(&lt;/span&gt;&lt;span class="n"&gt;total&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;32&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;buffer&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;60&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;unsigned&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="p"&gt;)(&lt;/span&gt;&lt;span class="n"&gt;total&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;24&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;buffer&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;61&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;unsigned&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="p"&gt;)(&lt;/span&gt;&lt;span class="n"&gt;total&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;16&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;buffer&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;62&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;unsigned&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="p"&gt;)(&lt;/span&gt;&lt;span class="n"&gt;total&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;buffer&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;63&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;unsigned&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="p"&gt;)(&lt;/span&gt;&lt;span class="n"&gt;total&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;sha1_process&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;uint32_t&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;buffer&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;output&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;unsigned&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="p"&gt;)(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;ihv&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;24&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;output&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="c1"&gt;//(unsigned char)(ctx-&amp;gt;ihv[0] &amp;gt;&amp;gt; 16);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;output&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="c1"&gt;//(unsigned char)(ctx-&amp;gt;ihv[0] &amp;gt;&amp;gt; 8);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;output&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="c1"&gt;//(unsigned char)(ctx-&amp;gt;ihv[0]);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;output&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="c1"&gt;//(unsigned char)(ctx-&amp;gt;ihv[1] &amp;gt;&amp;gt; 24);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;output&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="c1"&gt;//(unsigned char)(ctx-&amp;gt;ihv[1] &amp;gt;&amp;gt; 16);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;output&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="c1"&gt;//(unsigned char)(ctx-&amp;gt;ihv[1] &amp;gt;&amp;gt; 8);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;output&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="c1"&gt;//(unsigned char)(ctx-&amp;gt;ihv[1]);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;output&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="c1"&gt;//(unsigned char)(ctx-&amp;gt;ihv[2] &amp;gt;&amp;gt; 24);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;output&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;9&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="c1"&gt;//(unsigned char)(ctx-&amp;gt;ihv[2] &amp;gt;&amp;gt; 16);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;output&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;//(unsigned char)(ctx-&amp;gt;ihv[2] &amp;gt;&amp;gt; 8);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;output&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;11&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;//(unsigned char)(ctx-&amp;gt;ihv[2]);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;output&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;12&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;//(unsigned char)(ctx-&amp;gt;ihv[3] &amp;gt;&amp;gt; 24);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;output&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;13&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;//(unsigned char)(ctx-&amp;gt;ihv[3] &amp;gt;&amp;gt; 16);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;output&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;14&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;//(unsigned char)(ctx-&amp;gt;ihv[3] &amp;gt;&amp;gt; 8);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;output&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;15&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;//(unsigned char)(ctx-&amp;gt;ihv[3]);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;output&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;16&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;//(unsigned char)(ctx-&amp;gt;ihv[4] &amp;gt;&amp;gt; 24);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;output&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;17&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;//(unsigned char)(ctx-&amp;gt;ihv[4] &amp;gt;&amp;gt; 16);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;output&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;18&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;//(unsigned char)(ctx-&amp;gt;ihv[4] &amp;gt;&amp;gt; 8);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;output&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;19&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;//(unsigned char)(ctx-&amp;gt;ihv[4]);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;found_collision&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;In order to cause collisions between object IDs in git, it is helpful to reduce the size of the identifier.
To achieve this, every byte of the hash after the first one was set to 1.
This reduces the effective length of the identifier to 1 byte.
256 values may still sound like a lot, but there's no need to check every possible value.
We're not looking for a specific hash, any collision will do.
The first collisions should occur after a few tries.[°Such collisions are already very likely after a surprisingly small amount of attempts if the value range is not too large. Look up the birthday problem if you don't know it.]&lt;/p&gt;
&lt;p&gt;So let's compile git with our "improvement" and try to cause some collisions.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;$&lt;span class="w"&gt; &lt;/span&gt;touch&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;test&lt;/span&gt;
$&lt;span class="w"&gt; &lt;/span&gt;../git/git&lt;span class="w"&gt; &lt;/span&gt;add&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;test&lt;/span&gt;
$&lt;span class="w"&gt; &lt;/span&gt;../git/git&lt;span class="w"&gt; &lt;/span&gt;commit&lt;span class="w"&gt; &lt;/span&gt;-m&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;test&amp;#39;&lt;/span&gt;
&lt;span class="o"&gt;[&lt;/span&gt;main&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;root-commit&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;c101010&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;test&lt;/span&gt;
&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;file&lt;span class="w"&gt; &lt;/span&gt;changed,&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;insertion&lt;span class="o"&gt;(&lt;/span&gt;+&lt;span class="o"&gt;)&lt;/span&gt;
create&lt;span class="w"&gt; &lt;/span&gt;mode&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;100644&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;test&lt;/span&gt;
$&lt;span class="w"&gt; &lt;/span&gt;touch&lt;span class="w"&gt; &lt;/span&gt;test2
$&lt;span class="w"&gt; &lt;/span&gt;../git/git&lt;span class="w"&gt; &lt;/span&gt;add&lt;span class="w"&gt; &lt;/span&gt;test2
$&lt;span class="w"&gt; &lt;/span&gt;../git/git&lt;span class="w"&gt; &lt;/span&gt;commit&lt;span class="w"&gt; &lt;/span&gt;-m&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;test2&amp;#39;&lt;/span&gt;
&lt;span class="o"&gt;[&lt;/span&gt;main&lt;span class="w"&gt; &lt;/span&gt;db01010&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;test2
&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;file&lt;span class="w"&gt; &lt;/span&gt;changed,&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;insertions&lt;span class="o"&gt;(&lt;/span&gt;+&lt;span class="o"&gt;)&lt;/span&gt;,&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;deletions&lt;span class="o"&gt;(&lt;/span&gt;-&lt;span class="o"&gt;)&lt;/span&gt;
create&lt;span class="w"&gt; &lt;/span&gt;mode&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;100644&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;test2
$&lt;span class="w"&gt; &lt;/span&gt;../git/git&lt;span class="w"&gt; &lt;/span&gt;log
commit&lt;span class="w"&gt; &lt;/span&gt;db01010101010101010101010101010101010101&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;HEAD&lt;span class="w"&gt; &lt;/span&gt;-&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;main&lt;span class="o"&gt;)&lt;/span&gt;
Author:&lt;span class="w"&gt; &lt;/span&gt;error&lt;span class="w"&gt; &lt;/span&gt;&amp;lt;redacted&amp;gt;
Date:&lt;span class="w"&gt;   &lt;/span&gt;Sun&lt;span class="w"&gt; &lt;/span&gt;May&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;7&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;20&lt;/span&gt;:32:54&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;2023&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;+0200

&lt;span class="w"&gt;    &lt;/span&gt;test2

commit&lt;span class="w"&gt; &lt;/span&gt;c101010101010101010101010101010101010101
Author:&lt;span class="w"&gt; &lt;/span&gt;error&lt;span class="w"&gt; &lt;/span&gt;&amp;lt;redacted&amp;gt;
Date:&lt;span class="w"&gt;   &lt;/span&gt;Sun&lt;span class="w"&gt; &lt;/span&gt;May&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;7&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;20&lt;/span&gt;:32:00&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;2023&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;+0200

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nb"&gt;test&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The fist two commits may not collide, but it's already obvious what our little modification to the source code did: only the first 2 characters of the commit hash differ, everything afterwards is filled with the same two characters.&lt;/p&gt;
&lt;p&gt;Continuing to add and commits to this repository, the first collision was observed on the 7th attempt.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;$&lt;span class="w"&gt; &lt;/span&gt;touch&lt;span class="w"&gt; &lt;/span&gt;test7
$&lt;span class="w"&gt; &lt;/span&gt;../git/git&lt;span class="w"&gt; &lt;/span&gt;add&lt;span class="w"&gt; &lt;/span&gt;test7
$&lt;span class="w"&gt; &lt;/span&gt;../git/git&lt;span class="w"&gt; &lt;/span&gt;commit&lt;span class="w"&gt; &lt;/span&gt;-m&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;test7&amp;#39;&lt;/span&gt;
fatal:&lt;span class="w"&gt; &lt;/span&gt;0f01010101010101010101010101010101010101&lt;span class="w"&gt; &lt;/span&gt;is&lt;span class="w"&gt; &lt;/span&gt;not&lt;span class="w"&gt; &lt;/span&gt;a&lt;span class="w"&gt; &lt;/span&gt;valid&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;tree&amp;#39;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;object
$&lt;span class="w"&gt; &lt;/span&gt;../git/git&lt;span class="w"&gt; &lt;/span&gt;cat-file&lt;span class="w"&gt; &lt;/span&gt;-p&lt;span class="w"&gt; &lt;/span&gt;0f01010101010101010101010101010101010101
tree&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;8501010101010101010101010101010101010101&lt;/span&gt;
parent&lt;span class="w"&gt; &lt;/span&gt;e801010101010101010101010101010101010101
author&lt;span class="w"&gt; &lt;/span&gt;error&lt;span class="w"&gt; &lt;/span&gt;&amp;lt;redacted&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;1683484473&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;+0200
committer&lt;span class="w"&gt; &lt;/span&gt;error&lt;span class="w"&gt; &lt;/span&gt;&amp;lt;redacted&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;1683484473&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;+0200

test5
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The collision happened between the tree object for the new commit and an already existing commit.
Interestingly, git did notice this problem only when it tried to add the tree to the commit and found an object of a wrong type instead.
The original object was not modified in the process.
It looks like the attempt to add a new object failed silently.&lt;/p&gt;
&lt;p&gt;On the 15th attempt, another interesting collision occurred:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;$&lt;span class="w"&gt; &lt;/span&gt;touch&lt;span class="w"&gt; &lt;/span&gt;test15
$&lt;span class="w"&gt; &lt;/span&gt;../git/git&lt;span class="w"&gt; &lt;/span&gt;add&lt;span class="w"&gt; &lt;/span&gt;test15
$&lt;span class="w"&gt; &lt;/span&gt;../git/git&lt;span class="w"&gt; &lt;/span&gt;commit&lt;span class="w"&gt; &lt;/span&gt;-m&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;test15&amp;#39;&lt;/span&gt;
&lt;span class="o"&gt;[&lt;/span&gt;main&lt;span class="w"&gt; &lt;/span&gt;e201010&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;test12
&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;file&lt;span class="w"&gt; &lt;/span&gt;changed,&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;insertions&lt;span class="o"&gt;(&lt;/span&gt;+&lt;span class="o"&gt;)&lt;/span&gt;,&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;deletions&lt;span class="o"&gt;(&lt;/span&gt;-&lt;span class="o"&gt;)&lt;/span&gt;
create&lt;span class="w"&gt; &lt;/span&gt;mode&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;100644&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;test12
$&lt;span class="w"&gt; &lt;/span&gt;../git/git&lt;span class="w"&gt; &lt;/span&gt;log
commit&lt;span class="w"&gt; &lt;/span&gt;e201010101010101010101010101010101010101&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;HEAD&lt;span class="w"&gt; &lt;/span&gt;-&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;main&lt;span class="o"&gt;)&lt;/span&gt;
Author:&lt;span class="w"&gt; &lt;/span&gt;error&lt;span class="w"&gt; &lt;/span&gt;&amp;lt;redacted&amp;gt;
Date:&lt;span class="w"&gt;   &lt;/span&gt;Sun&lt;span class="w"&gt; &lt;/span&gt;May&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;7&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;21&lt;/span&gt;:12:38&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;2023&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;+0200

test12

commit&lt;span class="w"&gt; &lt;/span&gt;3b01010101010101010101010101010101010101
Author:&lt;span class="w"&gt; &lt;/span&gt;error&lt;span class="w"&gt; &lt;/span&gt;&amp;lt;redacted&amp;gt;
Date:&lt;span class="w"&gt;   &lt;/span&gt;Sun&lt;span class="w"&gt; &lt;/span&gt;May&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;7&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;21&lt;/span&gt;:12:06&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;2023&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;+0200

test11

commit&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;6001010101010101010101010101010101010101&lt;/span&gt;
Author:&lt;span class="w"&gt; &lt;/span&gt;error&lt;span class="w"&gt; &lt;/span&gt;&amp;lt;redacted&amp;gt;
Date:&lt;span class="w"&gt;   &lt;/span&gt;Sun&lt;span class="w"&gt; &lt;/span&gt;May&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;7&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;21&lt;/span&gt;:11:40&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;2023&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;+0200

test10
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;In this case both of the colliding objects are commits.
This time, git did not even print an error message.
After the creation of the new commit object once again failed silently, git proceeded to check out the existing commit with the same hash.[°People assume that a commit history is a strict progression of cause to effect. But actually from a non-linear, non-subjective viewpoint it's more like a big ball of wibbly-wobbly timey-wimey... stuff.]
This confirms the assumption that git will keep the existing object in case of a collision.
The other commits that got rolled back are still present as objects in git and can be checked out, but especially if the user does not notice what happened here and continues working, this can seriously mess up the commit history.&lt;/p&gt;
&lt;p&gt;Those tests were continued until the following collisions occurred and git's behavior could be observed:&lt;/p&gt;
&lt;dl&gt;
&lt;dt&gt;Collisions between two blobs&lt;/dt&gt;
&lt;dd&gt;Creating the new blob object fails silently. The existing blob object remains unchanged.&lt;/dd&gt;
&lt;dt&gt;Collisions between blobs and trees&lt;/dt&gt;
&lt;dd&gt;Creating the new blob object fails silently. The existing tree object remains unchanged.&lt;/dd&gt;
&lt;dt&gt;Collisions between blobs and commits&lt;/dt&gt;
&lt;dd&gt;Creating the new blob object fails silently. The existing commit object remains unchanged.&lt;/dd&gt;
&lt;dt&gt;Collisions between blobs and tags&lt;/dt&gt;
&lt;dd&gt;Creating the new blob object fails silently. The existing tag object remains unchanged.&lt;/dd&gt;
&lt;dt&gt;Collisions between trees and blobs&lt;/dt&gt;
&lt;dd&gt;Creating the new tree object fails silently. The existing blob object remains unchanged. Trying to commit this results in an error message complaining that the object is not a valid tree object.&lt;/dd&gt;
&lt;dt&gt;Collisions between two trees&lt;/dt&gt;
&lt;dd&gt;Creating the tree object fails silently. The existing tree object remains unchanged. Trying to commit this, git commits the old tree again. This effectively means a rollback to the commit associated with of the old tree while keeping the commit history.&lt;/dd&gt;
&lt;dt&gt;Collisions between trees and commits&lt;/dt&gt;
&lt;dd&gt;Creating the new tree object fails silently. The existing commit object remains unchanged. Trying to commit this results in an error message complaining that the object is not a valid tree object.&lt;/dd&gt;
&lt;dt&gt;Collisions between trees and tags&lt;/dt&gt;
&lt;dd&gt;Creating the new tree object fails silently. The existing tag object remains unchanged. Trying to commit this results in an error message complaining that the object is not a valid tree object.&lt;/dd&gt;
&lt;dt&gt;Collisions between commits and blobs&lt;/dt&gt;
&lt;dd&gt;Creating the new commit object fails. The existing blob object remains unchanged. Git attempts to check out the new commit (that wasn't created) and fails with the error message &lt;code&gt;fatal: cannot update ref 'refs/heads/main': trying to write non-commit object $HASH to branch 'refs/heads/main'&lt;/code&gt;.&lt;/dd&gt;
&lt;dt&gt;Collisions between commits and trees&lt;/dt&gt;
&lt;dd&gt;Creating the new commit object fails. The existing tree object remains unchanged. Git attempts to check out the new commit (that wasn't created) and fails with the error message &lt;code&gt;fatal: cannot update ref 'refs/heads/main': trying to write non-commit object $HASH to branch 'refs/heads/main'&lt;/code&gt;.&lt;/dd&gt;
&lt;dt&gt;Collisions between two commits&lt;/dt&gt;
&lt;dd&gt;Creating the new commit object fails silently. The existing commit remains unchanged and is checked out.&lt;/dd&gt;
&lt;dt&gt;Collisions between commits and tags&lt;/dt&gt;
&lt;dd&gt;Creating the new commit object fails. The existing tag object remains unchanged. Git attempts to check out the new commit (that wasn't created) and fails with the error message &lt;code&gt;fatal: cannot update ref 'refs/heads/main': trying to write non-commit object $HASH to branch 'refs/heads/main'&lt;/code&gt;.&lt;/dd&gt;
&lt;dt&gt;Collisions between tags and blobs&lt;/dt&gt;
&lt;dd&gt;A new file is created under &lt;code&gt;.git/refs/tags&lt;/code&gt; pointing at the hash, but the creation of the new tag object under &lt;code&gt;.git/objects&lt;/code&gt; fails silently. The existing blob object remains unchanged.&lt;/dd&gt;
&lt;dt&gt;Collisions between tags and trees&lt;/dt&gt;
&lt;dd&gt;A new file is created under &lt;code&gt;.git/refs/tags&lt;/code&gt; pointing at the hash, but the creation of the new tag object under &lt;code&gt;.git/objects&lt;/code&gt; fails silently. The existing tree object remains unchanged. The tag is displayed by &lt;code&gt;git tag -l&lt;/code&gt;, but attempts at checking it out fail with the error message &lt;code&gt;fatal: Cannot switch branch to a non-commit&lt;/code&gt;.&lt;/dd&gt;
&lt;dt&gt;Collisions between tags and commits&lt;/dt&gt;
&lt;dd&gt;A new file is created under &lt;code&gt;.git/refs/tags&lt;/code&gt; pointing at the hash, but the creation of this new tag object under &lt;code&gt;.git/objects&lt;/code&gt; fails silently. The existing commit object remains unchanged. The tag is displayed by &lt;code&gt;git tag -l&lt;/code&gt;, but is interpreted as a lightweight tag for the colliding commit.&lt;/dd&gt;
&lt;dt&gt;Collisions between two tags&lt;/dt&gt;
&lt;dd&gt;A new file is created under &lt;code&gt;.git/refs/tags&lt;/code&gt; pointing at the hash, but the creation of this new tag object under &lt;code&gt;.git/objects&lt;/code&gt; fails silently. The existing tag object remains unchanged. Since the new tag reference object points at the old tag object, the new tag will be an alias for the old tag, with the same message and object reference.&lt;/dd&gt;
&lt;/dl&gt;
&lt;p&gt;Git does not overwrite existing objects.
Creating a new object with a hash that's already associated with another object always fails silently.
However, depending on the object type, git shows some interesting behavior.
If the object type fits, git will just continue with it as if nothing is wrong, e.g. it will commit an old tree or checkout an old commit.
Git only responds with an error if the object types are incompatible, e.g. if the collision causes a reference to a tree to point at a tag object instead.&lt;/p&gt;
&lt;p&gt;Hash collisions, intentional oŕ not, can become a problem for git.
To mitigate this risk, git includes a mechanism that detects SHA-1 collision attacks and reacts by hashing the suspected block 3 times, extending SHA-1 from 80 to 240 steps in these cases.
This ensures that different hashes are generated in theses cases.&lt;sup id="fnref:4"&gt;&lt;a class="footnote-ref" href="#fn:4"&gt;4&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;p&gt;Further, git does not only support SHA-1.
It supports SHA-256, too.
Unlike SHA-1, SHA-256 is considered cryptographically secure.&lt;/p&gt;
&lt;p&gt;Actual SHA-1 collisions are very unlikely to occur as a coincidence.
The collisions in this experiment could only be observed after the code was modified to limit the effective hash size to 1 byte.
Otherwise, it would not have been possible to create collisions with the available resources.
However, SHAttered shows that it is feasible to intentionally cause such a collision.[°Whether or not attackers with the resources required to do this are part of your threat model is up to you to decide.]&lt;/p&gt;
&lt;p&gt;In case of a collision, git shows some interesting behavior that may not be noticed immediately.
This may leave the git repository in an unintended state.
Further, attackers could modify files and commits by replacing objects with specifically crafted objects that produce the same hash.
This risk is mitigated by the use of the collision attack detection mechanism.&lt;/p&gt;
&lt;p&gt;Even though the risk is already mitigated, this example shows why SHA-1 should not be used for cryptographic hashing and was a good opportunity to learn more about git itself.
If you want to try it out yourself, you can have a look at the code with my modification &lt;a href="https://git.undefinedbehavior.de/undef/git-commit-vandalism" title="git commit vandalism - undefined git server"&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;div class="footnote"&gt;
&lt;hr&gt;
&lt;ol&gt;
&lt;li id="fn:1"&gt;
&lt;p&gt;M. Stevens, E. Bursztein, P. Karpman, A. Albertini and Y. Markov (2017, February) "The first collision for full SHA-1", &lt;a href="https://shattered.io/static/shattered.pdf" title="The first collision for full SHA-1"&gt;https://shattered.io/static/shattered.pdf&lt;/a&gt;.&amp;#160;&lt;a class="footnote-backref" href="#fnref:1" title="Jump back to footnote 1 in the text"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:2"&gt;
&lt;p&gt;L. Torvalds (2007, May) "Tech Talk: Linus Torvalds on git", &lt;a href="https://www.youtube.com/watch?v=4XpnKHJAok8&amp;amp;t=56m20s" title="Tech Talk: Linus Torvalds on git"&gt;https://www.youtube.com/watch?v=4XpnKHJAok8&amp;amp;t=56m20s&lt;/a&gt;.&amp;#160;&lt;a class="footnote-backref" href="#fnref:2" title="Jump back to footnote 2 in the text"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:3"&gt;
&lt;p&gt;S. Chacon, B. Straub et al. (2014) "10.2 Git Internals - Git Objects" in &lt;em&gt;Pro Git&lt;/em&gt;, &lt;a href="https://git-scm.com/book/en/v2/Git-Internals-Git-Objects" title="Git Internals - Git Objects"&gt;https://git-scm.com/book/en/v2/Git-Internals-Git-Objects&lt;/a&gt;.&amp;#160;&lt;a class="footnote-backref" href="#fnref:3" title="Jump back to footnote 3 in the text"&gt;&amp;#8617;&lt;/a&gt;&lt;a class="footnote-backref" href="#fnref2:3" title="Jump back to footnote 3 in the text"&gt;&amp;#8617;&lt;/a&gt;&lt;a class="footnote-backref" href="#fnref3:3" title="Jump back to footnote 3 in the text"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:4"&gt;
&lt;p&gt;M. Stevens, D. Shumow (2017) "sha1dc/sha1.h", &lt;a href="https://github.com/git/git/blob/master/sha1dc/sha1.h" title="sha1dc/sha1.h"&gt;https://github.com/git/git/blob/master/sha1dc/sha1.h&lt;/a&gt;.&amp;#160;&lt;a class="footnote-backref" href="#fnref:4" title="Jump back to footnote 4 in the text"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">Error</dc:creator><pubDate>Thu, 25 May 2023 18:55:00 +0200</pubDate><guid isPermaLink="false">tag:undefinedbehavior.de,2023-05-25:/blog/commit-vandalism/</guid><category>blog</category></item><item><title>RFCartography - Visualizing relations between RFCs</title><link>https://undefinedbehavior.de/blog/rfcartography/</link><description>&lt;p&gt;RFCs are nice documents which explain how the internet works.
They define protocols, describe best practices and discuss the organisation of internet infrastructure.
Unlike some standards from other organizations, they are publicly available for free, usually written in a comprehensible manner and structured in a logical way.&lt;/p&gt;
&lt;p&gt;Looking for a new project to do in my spare time at the end of 2022, I ended up thinking about how to visualize relations between RFCs.
I always liked the way RFCs are connected to each other:
Information about which RFC updates which, which RFC is obsoleted by which, and so on, all displayed at the top of the document, easy to find.
So I decided to create RFCartography[°portmanteau word built out of "RFC" and "Cartography"; If you were under the impression that it has something to do with radio frequencies, you were misled, sorry.], a small tool that draws graphs of these relations.&lt;/p&gt;
&lt;p&gt;&lt;img alt="A graph of the relations of RFC791 (Internet Protocol) generated by RFCartography" src="https://undefinedbehavior.de/blog/rfcartography/791.svg" title="A graph of the relations of RFC791 (Internet Protocol) generated by RFCartography"&gt;&lt;/p&gt;
&lt;p&gt;Parsing all the RFCs in order to extract the required information would have been a lot of effort and probably prone to errors.
Fortunately, &lt;a href="https://rfc-editor.org"&gt;rfc-editor.org&lt;/a&gt; has a nice, machine readable RFC index file in XML format with all the meta data for each RFC. &lt;sup id="fnref:1"&gt;&lt;a class="footnote-ref" href="#fn:1"&gt;1&lt;/a&gt;&lt;/sup&gt;
This includes, among other data, all the relations between RFCs:&lt;/p&gt;
&lt;dl&gt;
&lt;dt&gt;obsoletes&lt;/dt&gt;
&lt;dd&gt;points to older RFCs which are superseded by this document &lt;sup id="fnref:2"&gt;&lt;a class="footnote-ref" href="#fn:2"&gt;2&lt;/a&gt;&lt;/sup&gt;, &lt;sup id="fnref:3"&gt;&lt;a class="footnote-ref" href="#fn:3"&gt;3&lt;/a&gt;&lt;/sup&gt;&lt;/dd&gt;
&lt;dt&gt;obsoleted-by&lt;/dt&gt;
&lt;dd&gt;points to newer RFCs which supersede this document &lt;sup id="fnref2:2"&gt;&lt;a class="footnote-ref" href="#fn:2"&gt;2&lt;/a&gt;&lt;/sup&gt;, &lt;sup id="fnref2:3"&gt;&lt;a class="footnote-ref" href="#fn:3"&gt;3&lt;/a&gt;&lt;/sup&gt;&lt;/dd&gt;
&lt;dt&gt;updates&lt;/dt&gt;
&lt;dd&gt;points to older RFCs which are modified and/or extended by this document &lt;sup id="fnref3:2"&gt;&lt;a class="footnote-ref" href="#fn:2"&gt;2&lt;/a&gt;&lt;/sup&gt;, &lt;sup id="fnref3:3"&gt;&lt;a class="footnote-ref" href="#fn:3"&gt;3&lt;/a&gt;&lt;/sup&gt;&lt;/dd&gt;
&lt;dt&gt;updated-by&lt;/dt&gt;
&lt;dd&gt;points to newer RFCs which modify and/or extend this document &lt;sup id="fnref4:2"&gt;&lt;a class="footnote-ref" href="#fn:2"&gt;2&lt;/a&gt;&lt;/sup&gt;, &lt;sup id="fnref4:3"&gt;&lt;a class="footnote-ref" href="#fn:3"&gt;3&lt;/a&gt;&lt;/sup&gt;&lt;/dd&gt;
&lt;dt&gt;is-also&lt;/dt&gt;
&lt;dd&gt;shows which other IDs this document is known as &lt;sup id="fnref5:2"&gt;&lt;a class="footnote-ref" href="#fn:2"&gt;2&lt;/a&gt;&lt;/sup&gt;, &lt;sup id="fnref5:3"&gt;&lt;a class="footnote-ref" href="#fn:3"&gt;3&lt;/a&gt;&lt;/sup&gt;&lt;/dd&gt;
&lt;dt&gt;see-also&lt;/dt&gt;
&lt;dd&gt;references other relevant documents &lt;sup id="fnref6:2"&gt;&lt;a class="footnote-ref" href="#fn:2"&gt;2&lt;/a&gt;&lt;/sup&gt;&lt;/dd&gt;
&lt;/dl&gt;
&lt;p&gt;RFCartography consists out of the IndexParser component, which parses the index file and makes its information available, and the RFCartography component, which builds the requested graphs and generates SVGs from them.
This is held together by a Flask application that initially calls the IndexParser and provides the data returned by the parser to the RFCartographer, which it then repeatedly consults to generate graphs and render SVGs.
Further, the Flask application implements the web frontend.
The application is made available by a web server and a wsgi server.&lt;/p&gt;
&lt;p&gt;&lt;img alt="Component diagram of RFCartography" src="https://undefinedbehavior.de/blog/rfcartography/components.svg" title="Component diagram of RFCartography"&gt;&lt;/p&gt;
&lt;p&gt;When a request is received, the Flask application calls the RFCartographer to generate the subgraph belonging to the requested RFC.
In order to do this, the initial RFC is added to a queue.
Every RFC in the queue is added to the graph and all of its references are checked and added as edges to the graph.
If a referenced document in not in the queue and hasn't been analyzed yet, it is added to the queue.
To prevent long waiting times, a maximum depth can be specified.
Once the queue is empty, the subgraph generation is completed and the graph can be returned.[°I profoundly apologise for this atrociously unreadable piece of code. In my defence: it seems to be working]&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nl"&gt;todo&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="n"&gt;list&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="n"&gt;tuple[Document, int&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="err"&gt;]&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="n"&gt;(core, 0)&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
&lt;span class="nl"&gt;done&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="n"&gt;list&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="n"&gt;Document&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="w"&gt;              &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;[]&lt;/span&gt;
&lt;span class="nl"&gt;graph&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="n"&gt;MultiDiGraph&lt;/span&gt;&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;MultiDiGraph&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;graph&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;add_node&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;core&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;nodes&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="n"&gt;core.type&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;core&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;while&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;todo&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nl"&gt;node&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;tuple&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="n"&gt;Document, int&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;todo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;pop&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="n"&gt;0&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;not&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;in&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;done&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;done&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="n"&gt;0&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="n"&gt;1&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;max_depth&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;or&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;max_depth&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;neighbor&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;in&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="n"&gt;0&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get_references&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;not&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;neighbor&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="n"&gt;1&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;in&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;node_types&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="k"&gt;continue&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;not&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;graph&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;has_node&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;neighbor&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="n"&gt;1&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="n"&gt;graph&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;add_node&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;neighbor&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="n"&gt;1&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="n"&gt;nodes&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="n"&gt;neighbor[1&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;type&lt;/span&gt;&lt;span class="err"&gt;]&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;neighbor&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="n"&gt;1&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="n"&gt;graph&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;add_edge&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="n"&gt;0&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;neighbor&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="n"&gt;1&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;reftype&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;neighbor&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="n"&gt;0&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="n"&gt;edges&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="n"&gt;neighbor[0&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="err"&gt;]&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="n"&gt;0&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;neighbor&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="n"&gt;1&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="n"&gt;todo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;neighbor&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="n"&gt;1&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="n"&gt;1&lt;/span&gt;&lt;span class="o"&gt;]+&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Afterwards, the subgraph can be rendered into a SVG with the help of pyplot.&lt;/p&gt;
&lt;p&gt;Of course this does not work without problems.
First of all, RFCartography is really slow.
Generating and rendering graphs takes a while, leading to long response times.
This can be mitigated to a degree by caching responses, but to really improve on this issue, the application should probably use a database backend.[°I'll add this to RFCartography at some point]&lt;/p&gt;
&lt;p&gt;Another issue seems to be due to a bug in pyplot.
SVGs generated by RFCartography are supposed to have hyperlinks for each node that point to a page with details about that document.
However, this does not work in some edge cases.
If, for example, a subgraph consists out of only one node, pyplot does not add links to it.
Further, it does not add links to the nodes if different shapes are used for different node types.[°Using different shapes would have been nice from an accessibility point of view, but since it doesn't work at the moment, RFCartography has to rely on colors only.]&lt;/p&gt;
&lt;p&gt;&lt;img alt="A graph of the relations of RFC2322 (Management of IP numbers by peg-dhcp) generated by RFCartography" src="https://undefinedbehavior.de/blog/rfcartography/2322.svg" title="A graph of the relations of RFC2322 (Management of IP numbers by peg-dhcp) generated by RFCartography"&gt;&lt;/p&gt;
&lt;p&gt;You can try RFCartography yourself on &lt;a href="https://rfcartography.undefinedbehavior.de/" title="RFCartography"&gt;rfcartography.undefinedbehavior.de&lt;/a&gt;.
The source code can be found &lt;a href="https://git.undefinedbehavior.de/undef/RFCartography" title="RFCartography - undefined git server"&gt;here&lt;/a&gt;.
I'm not sure whether this project is actually useful for anyone, but it was fun to build it.&lt;/p&gt;
&lt;div class="footnote"&gt;
&lt;hr&gt;
&lt;ol&gt;
&lt;li id="fn:1"&gt;
&lt;p&gt;&lt;a href="https://www.rfc-editor.org/rfc-index.xml" title="RFC Index"&gt;https://www.rfc-editor.org/rfc-index.xml&lt;/a&gt;&amp;#160;&lt;a class="footnote-backref" href="#fnref:1" title="Jump back to footnote 1 in the text"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:2"&gt;
&lt;p&gt;&lt;a href="https://www.rfc-editor.org/rfc-index.xsd" title="RFC Index Schema"&gt;https://www.rfc-editor.org/rfc-index.xsd&lt;/a&gt;&amp;#160;&lt;a class="footnote-backref" href="#fnref:2" title="Jump back to footnote 2 in the text"&gt;&amp;#8617;&lt;/a&gt;&lt;a class="footnote-backref" href="#fnref2:2" title="Jump back to footnote 2 in the text"&gt;&amp;#8617;&lt;/a&gt;&lt;a class="footnote-backref" href="#fnref3:2" title="Jump back to footnote 2 in the text"&gt;&amp;#8617;&lt;/a&gt;&lt;a class="footnote-backref" href="#fnref4:2" title="Jump back to footnote 2 in the text"&gt;&amp;#8617;&lt;/a&gt;&lt;a class="footnote-backref" href="#fnref5:2" title="Jump back to footnote 2 in the text"&gt;&amp;#8617;&lt;/a&gt;&lt;a class="footnote-backref" href="#fnref6:2" title="Jump back to footnote 2 in the text"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:3"&gt;
&lt;p&gt;J. Halpern, L. Daigle and O. Kolkman. (2016, May) RFC 7841: RFC Streams, Headers, and Boilerplates. &lt;a href="https://www.rfc-editor.org/rfc/rfc7841" title="RFC7841: RFC Streams, Headers, and Boilerplates"&gt;https://www.rfc-editor.org/rfc/rfc7841&lt;/a&gt;&amp;#160;&lt;a class="footnote-backref" href="#fnref:3" title="Jump back to footnote 3 in the text"&gt;&amp;#8617;&lt;/a&gt;&lt;a class="footnote-backref" href="#fnref2:3" title="Jump back to footnote 3 in the text"&gt;&amp;#8617;&lt;/a&gt;&lt;a class="footnote-backref" href="#fnref3:3" title="Jump back to footnote 3 in the text"&gt;&amp;#8617;&lt;/a&gt;&lt;a class="footnote-backref" href="#fnref4:3" title="Jump back to footnote 3 in the text"&gt;&amp;#8617;&lt;/a&gt;&lt;a class="footnote-backref" href="#fnref5:3" title="Jump back to footnote 3 in the text"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">Error</dc:creator><pubDate>Tue, 28 Feb 2023 19:50:00 +0100</pubDate><guid isPermaLink="false">tag:undefinedbehavior.de,2023-02-28:/blog/rfcartography/</guid><category>blog</category></item><item><title>Slot Car Racing over IP (SCRoIP)</title><link>https://undefinedbehavior.de/blog/scroip/</link><description>&lt;p&gt;When I was a child, I used to play a lot with my slot car racing track.
After stumbling upon it again recently, I started wondering if I could build something to control it over the network.
Not that I needed a remote control for it, but it seemed like a fun project.
However, simply creating an API that offers precise control over the device seemed way too straight forward - the controlling mechanism itself should add its challenges.
So I came up with the idea to control it with the network traffic itself.
The more traffic is sent to the remote control, the faster the car is supposed to go.[°Use more bandwidth!!!]&lt;/p&gt;
&lt;p&gt;In order to build the remote control, the first step was to figure out how the slot car racing system works. So I disassembled it and took a look at its wiring.&lt;/p&gt;
&lt;p&gt;&lt;img alt="Simplified circuit diagram for a slot car racing system" src="https://undefinedbehavior.de/blog/scroip/carrera.svg" title="Simplified circuit diagram of a slot car racing system"&gt;&lt;/p&gt;
&lt;p&gt;The underlying mechanism is fairly simple. The power supply provides about 14.8&amp;nbsp;V DC voltage, which is used to power the car's engine.
The speed of the car is controlled by a variable resistor within the controller, which allows to control the voltage the car receives.
Pushing the controller further down lowers the resistance, which raises the voltage available to the car and makes is go faster.
A third wire is used to brake the car when the controller is in its neutral position by utilizing the current generated by the motor when the car is rolling out.
A look at wikipedia confirms this analysis. &lt;sup id="fnref:1"&gt;&lt;a class="footnote-ref" href="#fn:1"&gt;1&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;p&gt;Now that I understood the mechanism, the next step was to create a digital version of it, so that I could control the slot car racing track with a Raspberry Pi.
My first idea was to simply use a digital potentiometer.
However, searching for a suitable digipot, I quickly realized that there were no options with the desired dimensions of about 30&amp;nbsp;&amp;#8486; available.
Therefore I built it myself using a few resistors, solid state relais and multiplexers.[°I'm sure there are simpler solutions for this, but, well, it worked for me.]&lt;/p&gt;
&lt;p&gt;&lt;img alt="SCRoIP controller circuit diagram" src="https://undefinedbehavior.de/blog/scroip/scroip.svg" title="SCRoIP controller circuit diagram"&gt;&lt;/p&gt;
&lt;p&gt;For the sake of simplicity,[°or maybe out of laziness, who knows? :)] I did not add the braking mechanism from the analog controller to my digital version.&lt;/p&gt;
&lt;p&gt;With the hardware fully assembled and soldered, it was time to have a look at the software.
Python offers an easy way of implementing TCP servers.[°This project will use TCP. Even though the payload is immediately discarded, reliability is of the utmost importance and packet loss will not be accepted!!!]
By default, it only supports IPv4, but IPv6 support can be added by setting &lt;code&gt;address_family&lt;/code&gt; to &lt;code&gt;AF_INET6&lt;/code&gt;.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;not&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;legacy&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;address_family&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;AF_INET6&lt;/span&gt;
&lt;span class="nx"&gt;super&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;SCRoIPServer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;address&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;port&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;SCRoIPRequestHandler&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The server's logic itself is implemented in the method &lt;code&gt;handle()&lt;/code&gt; of the class &lt;code&gt;SCRoIPRequestHandler&lt;/code&gt;. While there is an active connection, it reads from the socket and sums up the amount of data that was received.
Once every 100 ms, it then calculates the average throughput for that time period and sets the raspi's GPIO pins accordingly.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;while self.data != b&amp;#39;&amp;#39;:
    try:
        self.data = self.request.recv(4096)
        self.traffic_counter += len(self.data)
    except TimeoutError:
        pass

    time = clock_gettime_ns(CLOCK_REALTIME)
    diff = time - self.last
    if (diff &amp;gt; 100000000):
        self.last = time
        traffic: float = self.traffic_counter / diff * 1000000000
        print(f&amp;quot;{traffic} Bytes/s&amp;quot;)
        self.server.set_throttle(traffic)
        self.server.apply_throttle()
        self.traffic_counter = 0
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The full server code can be found &lt;a href="https://git.undefinedbehavior.de/undef/SCRoIP" title="Slot Car Racing over IP - SCRoIP - undefined git server"&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Once the server was implemented as well, all that was left to do was to test it.
So I deployed the server script to a Raspberry Pi, connected its GPIO pins to the controller and the controller to the slot car racing track.
Using netcat, I was now able to accelerate the car with the network traffic I generated:&lt;/p&gt;
&lt;video controls preload="metadata"&gt;
    &lt;source src="https://undefinedbehavior.de/blog/scroip/demo.webm" type="video/webm"&gt;
    &lt;p&gt;
        The video could not be loaded.
        You can try to download it directly &lt;a href="/blog/scroip/demo.webm"&gt;here&lt;/a&gt; instead.
    &lt;/p&gt;
&lt;/video&gt;

&lt;div class="footnote"&gt;
&lt;hr&gt;
&lt;ol&gt;
&lt;li id="fn:1"&gt;
&lt;p&gt;&lt;a href="https://de.wikipedia.org/wiki/Autorennbahn#Fahrzeugsteuerung" title="Autorennbahn – Wikipedia"&gt;https://de.wikipedia.org/wiki/Autorennbahn#Fahrzeugsteuerung&lt;/a&gt;&amp;#160;&lt;a class="footnote-backref" href="#fnref:1" title="Jump back to footnote 1 in the text"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">Error</dc:creator><pubDate>Sun, 28 Aug 2022 16:05:00 +0200</pubDate><guid isPermaLink="false">tag:undefinedbehavior.de,2022-08-28:/blog/scroip/</guid><category>blog</category></item></channel></rss>