<story><title>Updating the Git protocol for SHA-256</title><url>https://lwn.net/SubscriberLink/823352/ea717c1e49390505/</url></story><parent_chain><item><author>kelnos</author><text>One of the comments mentioned that there was a suggestion (presumably rejected) to &amp;quot;rotate&amp;quot; the first character of the hex string for the SHA256 hashes by 16 characters, so 0 becomes g, 1 becomes h, etc. (that way the SHA256 hashes would be unambiguously not SHA1 hashes, even when abbreviated).&lt;p&gt;This made me think... why are we using long, unwieldy base-16 hex strings at all?  Why not use an alphabetic (non-numeric) base-46 string: 20 lowercase letters ([g-z]), 26 capital letters ([A-Z])?  Then the new SHA256 hash strings end up being &lt;i&gt;shorter&lt;/i&gt; than the old SHA1 strings, and there is no overlap with the [0-9a-f] range of the base-16 strings.&lt;p&gt;If you wanted to even it out to 64 characters, you could create a &amp;quot;modified base-64&amp;quot; that doesn&amp;#x27;t use [0-9a-f] and instead uses more special characters (though for convenience you&amp;#x27;d want to choose characters that are shell-safe and possibly even URL-safe, which might make this not work).  Alternatively you could use a subset for a base-32 representation.&lt;p&gt;The downside -- perhaps a significant one? -- is that you can&amp;#x27;t use standard tools like `sha256sum` or the representation conversion functions into the stdlib of many languages to generate these hashes; it would require custom code.  Not sure if that&amp;#x27;s a concern, though.</text></item></parent_chain><comment><author>mkl</author><text>&amp;gt; This made me think... why are we using long, unwieldy base-16 hex strings at all? Why not use an alphabetic (non-numeric) base-46 string: 20 lowercase letters ([g-z]), 26 capital letters ([A-Z])? Then the new SHA256 hash strings end up being shorter than the old SHA1 strings, and there is no overlap with the [0-9a-f] range of the base-16 strings.&lt;p&gt;Are you sure?  SHA1 hashes are 40 hex digits, and SHA256 hashes are 64 hex digits.  But in base 46, 2^256-1 = 3ZS4A7V5Ki0LWg1f3Of06YNfgQXCA2P0Q6RACKhEIWQXe07, which is 47 base-46 digits long, so still longer than SHA1.  (This is not your base 46, since it&amp;#x27;s using 0..9, A..Z, a..j.)&lt;p&gt;&lt;pre&gt;&lt;code&gt;  import gmpy2
  gmpy2.digits(2**256-1, 46)
    -&amp;gt; &amp;#x27;3ZS4A7V5Ki0LWg1f3Of06YNfgQXCA2P0Q6RACKhEIWQXe07&amp;#x27;
  gmpy2.digits(gmpy2.mpz(&amp;#x27;f&amp;#x27;*64, 16), 46) #same, but more clearly the &amp;quot;maximum&amp;quot; hash
&lt;/code&gt;&lt;/pre&gt;
edit: more code to try kelnos&amp;#x27;s proposed digits:&lt;p&gt;&lt;pre&gt;&lt;code&gt;  gmpy_digits = &amp;#x27;0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz&amp;#x27;
  new_digits = &amp;#x27;ghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ&amp;#x27;
  &amp;#x27;&amp;#x27;.join(new_digits[gmpy_digits.index(d)] for d in gmpy2.digits(gmpy2.mpz(&amp;#x27;f&amp;#x27;*64, 16), 46))
    -&amp;gt; &amp;#x27;jPIkqnLlAYgBMWhVjEVgmODVWGNsqiFgGmHqsAXuyMGNUgn&amp;#x27;
&lt;/code&gt;&lt;/pre&gt;
I think hex strings are probably still better, as there&amp;#x27;s less ambiguity, and 47 characters isn&amp;#x27;t much shorter than 64 for practical purposes.</text></comment>
<story><title>Updating the Git protocol for SHA-256</title><url>https://lwn.net/SubscriberLink/823352/ea717c1e49390505/</url></story><parent_chain><item><author>kelnos</author><text>One of the comments mentioned that there was a suggestion (presumably rejected) to &amp;quot;rotate&amp;quot; the first character of the hex string for the SHA256 hashes by 16 characters, so 0 becomes g, 1 becomes h, etc. (that way the SHA256 hashes would be unambiguously not SHA1 hashes, even when abbreviated).&lt;p&gt;This made me think... why are we using long, unwieldy base-16 hex strings at all?  Why not use an alphabetic (non-numeric) base-46 string: 20 lowercase letters ([g-z]), 26 capital letters ([A-Z])?  Then the new SHA256 hash strings end up being &lt;i&gt;shorter&lt;/i&gt; than the old SHA1 strings, and there is no overlap with the [0-9a-f] range of the base-16 strings.&lt;p&gt;If you wanted to even it out to 64 characters, you could create a &amp;quot;modified base-64&amp;quot; that doesn&amp;#x27;t use [0-9a-f] and instead uses more special characters (though for convenience you&amp;#x27;d want to choose characters that are shell-safe and possibly even URL-safe, which might make this not work).  Alternatively you could use a subset for a base-32 representation.&lt;p&gt;The downside -- perhaps a significant one? -- is that you can&amp;#x27;t use standard tools like `sha256sum` or the representation conversion functions into the stdlib of many languages to generate these hashes; it would require custom code.  Not sure if that&amp;#x27;s a concern, though.</text></item></parent_chain><comment><author>user5994461</author><text>&amp;gt;&amp;gt;&amp;gt; This made me think... why are we using long, unwieldy base-16 hex strings at all?&lt;p&gt;Surprised you got ten answers to this comment and nobody was able to explain.&lt;p&gt;Hexadecimal encoding is widely used because computers work with bytes (8 bits). An hexadecimal character is 4 bits, so every byte is two hex characters.&lt;p&gt;It&amp;#x27;s trivial to encode (even by hand), it has no issue of padding. It can truly transit through anything that accepts alphanumeric characters. It&amp;#x27;s awesome.&lt;p&gt;edit: The most common alternative is base64 that encodes blocks of 3 bytes to 4 characters. Base64 has a bazillion issues due to padding and special characters +&amp;#x2F;=. If I had a dollar for every system I&amp;#x27;ve seen using broken base64, I could buy a car. Saving a bit of space (200% in hex VS 134% size in base64) is almost never worth an order of magnitude more complexity. Do not invent your own encoding algorithm.</text></comment>