<?xml version="1.0" encoding="UTF-8" ?>
<?xml-stylesheet type="text/css" href="/styles/rss.css" ?>
<rss version="2.0">
<channel>
    <title>dramforever's blog</title>
    <description>dramforever's blog</description>
    <link>https://dram.page</link>
    <ttl>3600</ttl>
    <item>
        <title>Cryptography 30 years apart: Ascon on an HP-16C</title>
        <pubDate>Thu, 15 Jan 2026 00:00:00 +0000</pubDate>
        <guid isPermaLink="true">https://dram.page/p/ascon-hp16c</guid>
        <description><![CDATA[<p>Ascon (<a
href="https://csrc.nist.gov/pubs/sp/800/232/final">NIST</a>, <a
href="https://en.wikipedia.org/wiki/Ascon_(cipher)">Wikipedia</a>) is a
set of lightweight cryptographic algorithms intended for resource
constrained applications that nevertheless is intended to produce modern
security. It was originally developed in 2014, and was finalized as a
standard in August of 2025 as NIST SP 800-232 “Ascon-Based Lightweight
Cryptography Standards for Constrained Devices: Authenticated
Encryption, Hash, and Extendable Output Functions”.</p>
<p>How resource constrained? How about an HP-16C (<a
href="https://en.wikipedia.org/wiki/HP-16C">Wikipedia</a>), a
programmable programmer’s calculator from over 30 years earlier? ~200
bytes total of program and storage should be enough.</p>
<p>I’m not going to pretend I’m going to be good at teaching you how to
use these HP calculators. There are tutorials online all over that will
do a far better job at explaining them. If you don’t have an HP-16C, you
can use <a href="https://jrpn.jovial.com/run/index.html">JRPN 16C</a> as
an in-browser emulator. It can directly import the listing below for
your convenience.</p>
<h2 id="example">Example</h2>
<p>Computing the hash function on an empty string,
<code>Ascon-Hash256("")</code>, which should be
<code>0b 3b e5 85 0f 2f 6b 98 ca f2 9f 8f de a8 9b 64 a1 fa 70 aa 24 9b 8f 83 9b d5 3b aa 30 4d 92 b2</code>.</p>
<p>First, pad the message with one <code>01</code> byte and as much
zeros as needed to get to a multiple of 8. Bytes are read/written in
little-endian, so the padded message is a single block
<code>0x0000000000000001</code>. Then do the following:</p>
<ul>
<li>Enter the program (see end of post)</li>
<li>Set mode: <code>[HEX] 0 [f] [WSIZE] [f] [UNSGN]</code> (set
hexadecimal, 64-bit, unsigned)</li>
<li>Initial value:
<code>[f] [CLEAR REG] 80100cc0002 [STO] [0]</code></li>
<li>Initialization: <code>C [GSB] [0]</code> to apply the 12-round
<code>Ascon-p[12]</code> permutation. You should get
<code>9b1e5494e934d681</code>, which is <code>S0</code></li>
<li>XOR message: <code>1 [f] [XOR] [STO] [0]</code>, you should get
<code>9b1e5494e934d680</code></li>
<li>Process message: <code>C [GSB] [0]</code> to apply again</li>
<li>Read hash: you should get <code>986b2f0f85e53b0b</code>. Read bytes
in little-endian, so the first 8 bytes are
<code>0b 3b e5 85 0f 2f 6b 98</code></li>
<li>Iterate once more and read further bytes of hash:
<code>C [GSB] [0]</code>, you should get <code>649ba8de8f9ff2ca</code>,
hence <code>ca f2 9f 8f de a8 9b 64</code></li>
<li>Repeat until all 64 bytes are produced</li>
</ul>
<p>(Note: Only <code>R0</code> is directly used to XOR the input onto
and form the hash. It is, as a convenience, recalled after every
<code>[GSB] [0]</code>. Other registers participate in the round
function but the bytes are not directly used for input and output.)</p>
<h2 id="program-listing">Program listing</h2>
<p>This program isn’t specifically optimized — it is just a
straightforward translation of <a
href="https://github.com/ascon/ascon-c/blob/9057124473a4b9cbcc8a028b65a4abf6b4222b0f/src/opt64_lowsize/round.h">one
of the C reference implementations</a>. It takes 140 lines of program
space. On a real 16C it takes about 20 seconds per round, so
<code>Ascon-p[8]</code> (8 rounds) takes ~2.5min, and
<code>Ascon-p[12]</code> (12 rounds) takes ~4min.</p>
<p>(In <a href="https://jrpn.jovial.com/run/index.html">JRPN 16C</a>
compatible format, so you can load it in directly via
<code>(menu) &gt; File &gt; Import Program &gt; Import from Clipboard</code>.
Set <code>(menu) &gt; Settings &gt; Long Numbers</code> to
<code>Grow LCD</code> and
<code>(menu) &gt; Settings &gt; System Settings &gt; ms/Program Instruction</code>
to <code>0</code> for extra convenience.)</p>
<pre><code># Ascon round function
#
# Usage:
# Assumed Mode: [HEX] 0 [f] [WSIZE] [f] [UNSGN] (hexadecimal, 64-bit, unsigned)
#
# Modifies state S0 through S4 stored in R0 through R4
# Uses R5, R6 as scratch
#
#    Single round: &lt;round constant&gt; [GSB] [A]
#            e.g.: b4 [GSB] [A]
#
# Up to 12 rounds: &lt;num rounds&gt; [GSB] [0]
#            e.g.: 8 [GSB] [0]    for Ascon-p[8]
#            e.g.: C [GSB] [0]    for Ascon-p[12]
#
# 2026-01-18: Updated the multi-round subroutine to free up I register. Not
#             enough for a key, but you could store the IV there.
# 2026-02-23: Subroutine 0 performs RCL 0 at end for convenience
#             Minor peephole optimization near the start of subroutine A

   000 {          }
# Single round
   001 { 43 22  A } g LBL A

# s2 ^= s1 ^ c
   002 {    45  1 } RCL 1
   003 {    45  2 } RCL 2
   004 {    42 10 } f XOR
   005 {    42 10 } f XOR
   006 {    44  2 } STO 2

# s0 ^= s4
   007 {    45  4 } RCL 4
   008 {    45  0 } RCL 0
   009 {    42 10 } f XOR
   010 {    44  0 } STO 0

# s4 ^= s3
   011 {    45  3 } RCL 3
   012 {    45  4 } RCL 4
   013 {    42 10 } f XOR
   014 {    44  4 } STO 4

# tmp = ~s4 &amp; s0
# (s4 already conveniently on TOS)
   015 {    42 30 } f NOT
   016 {    45  0 } RCL 0
   017 {    42 20 } f AND
   018 {    44  5 } STO 5

# s0 ^= ~s1 &amp; s2
   019 {    45  1 } RCL 1
   020 {    42 30 } f NOT
   021 {    45  2 } RCL 2
   022 {    42 20 } f AND
   023 {    45  0 } RCL 0
   024 {    42 10 } f XOR
   025 {    44  0 } STO 0

# s2 ^= ~s3 &amp; s4
   026 {    45  3 } RCL 3
   027 {    42 30 } f NOT
   028 {    45  4 } RCL 4
   029 {    42 20 } f AND
   030 {    45  2 } RCL 2
   031 {    42 10 } f XOR
   032 {    44  2 } STO 2

# s4 ^= ~s0 &amp; s1
   033 {    45  0 } RCL 0
   034 {    42 30 } f NOT
   035 {    45  1 } RCL 1
   036 {    42 20 } f AND
   037 {    45  4 } RCL 4
   038 {    42 10 } f XOR
   039 {    44  4 } STO 4

# s1 ^= ~s2 &amp; s3
   040 {    45  2 } RCL 2
   041 {    42 30 } f NOT
   042 {    45  3 } RCL 3
   043 {    42 20 } f AND
   044 {    45  1 } RCL 1
   045 {    42 10 } f XOR
   046 {    44  1 } STO 1

# s3 ^= tmp
   047 {    45  5 } RCL 5
   048 {    45  3 } RCL 3
   049 {    42 10 } f XOR
   050 {    44  3 } STO 3

# s1 ^= s0
   051 {    45  0 } RCL 0
   052 {    45  1 } RCL 1
   053 {    42 10 } f XOR
   054 {    44  1 } STO 1

# s3 ^= s2
   055 {    45  2 } RCL 2
   056 {    45  3 } RCL 3
   057 {    42 10 } f XOR
   058 {    44  3 } STO 3

# s0 ^= s4
   059 {    45  4 } RCL 4
   060 {    45  0 } RCL 0
   061 {    42 10 } f XOR
   062 {    44  0 } STO 0

# s0 = s0 ^ (s0 ror 19) ^ (s0 ror 28)
   063 {    45  0 } RCL 0
   064 {       36 } ENTER
   065 {       36 } ENTER
   066 {       36 } ENTER
   067 {        9 } 9
   068 {    42  F } f RRn
   069 {    42 10 } f XOR
   070 {        1 } 1
   071 {        3 } 3
   072 {    42  F } f RRn
   073 {    42 10 } f XOR
   074 {    44  0 } STO 0

# s1 = s1 ^ (s1 ror 39) ^ (s1 ror 61)
   075 {    45  1 } RCL 1
   076 {       36 } ENTER
   077 {       36 } ENTER
   078 {       36 } ENTER
   079 {        1 } 1
   080 {        6 } 6
   081 {    42  F } f RRn
   082 {    42 10 } f XOR
   083 {        2 } 2
   084 {        7 } 7
   085 {    42  F } f RRn
   086 {    42 10 } f XOR
   087 {    44  1 } STO 1

# s2 = s2 ^ (s2 ror 1) ^ (s2 ror 6)
   088 {    45  2 } RCL 2
   089 {       36 } ENTER
   090 {       36 } ENTER
   091 {       36 } ENTER
   092 {        5 } 5
   093 {    42  F } f RRn
   094 {    42 10 } f XOR
   095 {    42  D } f RR
   096 {    42 10 } f XOR
   097 {    44  2 } STO 2

# s3 = s3 ^ (s3 ror 10) ^ (s3 ror 17)
   098 {    45  3 } RCL 3
   099 {       36 } ENTER
   100 {       36 } ENTER
   101 {       36 } ENTER
   102 {        7 } 7
   103 {    42  F } f RRn
   104 {    42 10 } f XOR
   105 {        A } A
   106 {    42  F } f RRn
   107 {    42 10 } f XOR
   108 {    44  3 } STO 3

# s4 = s4 ^ (s4 ror 7) ^ (s4 ror 41)
   109 {    45  4 } RCL 4
   110 {       36 } ENTER
   111 {       36 } ENTER
   112 {       36 } ENTER
   113 {        2 } 2
   114 {        2 } 2
   115 {    42  F } f RRn
   116 {    42 10 } f XOR
   117 {        7 } 7
   118 {    42  F } f RRn
   119 {    42 10 } f XOR
   120 {    44  4 } STO 4

# s2 = ~s2
   121 {    45  2 } RCL 2
   122 {    42 30 } f NOT
   123 {    44  2 } STO 2

   124 {    43 21 } g RTN

# Multiple rounds
   125 { 43 22  0 } g LBL 0
   126 {        4 } 4
   127 {       40 } +
   128 {        F } F
   129 {       20 } *
   130 { 43 22  B } g LBL B
   131 {    44  6 } STO 6
   132 {    21  A } GSB A
   133 {    45  6 } RCL 6
   134 {        4 } 4
   135 {        B } B
   136 {    43 49 } g x==y
   137 {    22  C } GTO C
   138 {       33 } Rv
   139 {        F } F
   140 {       30 } -
   141 {    22  B } GTO B
   142 { 43 22  C } g LBL C
   143 {    45  0 } RCL 0
   144 {    43 21 } g RTN</code></pre>]]></description>
    </item>
    <item>
        <title>dram.page is now served by grebedoc.dev</title>
        <pubDate>Fri, 19 Sep 2025 00:00:00 +0000</pubDate>
        <guid isPermaLink="true">https://dram.page/p/migration-to-grebedoc</guid>
        <description><![CDATA[<p>That’s it. If you’re seeing this post,
your receiving this page from <a
href="https://grebedoc.dev">grebedoc.dev</a>.</p>
<p>Check it out if you want a way to serve the contents from a git repo
over HTTP(S) on the public Internet.</p>
<p>The backend server on grebedoc.dev is called git-pages. I’ll probably
use the two names interchangably for the rest of this article.</p>
<p>(However, I will use “<code>grebedoc.dev</code>” to specifically
refer to the domain itself, and use grebedoc.dev to refer to the
service.)</p>
<h2 id="zero-downtime-migration">Zero downtime migration</h2>
<p>I think I’ve managed to do a zero-downtime migration from Netlify.
This is what I did:</p>
<p>First, I moved everything to the <code>pages</code> branch. This is
just easier.</p>
<p>Then, I set up the “method 1” DNS record:</p>
<pre><code>_git-pages-repository.dram.page.  600  IN  TXT  (
    &quot;https://github.com/dramforever/dram.page.git&quot; )</code></pre>
<p>Then, I triggered an initial clone using the <code>PUT</code>
method.</p>
<pre><code>$ curl -v -X PUT -H &#39;Host: dram.page&#39; \
    &#39;https://grebedoc.dev&#39; \
    --data &#39;https://github.com/dramforever/dram.page.git&#39;</code></pre>
<p>This has two effects:</p>
<ul>
<li>It asks git-pages to start serving files for
<code>Host: dram.page</code></li>
<li>It registers <code>dram.page</code> as a known domain to git-pages,
allowing it to immediately start receiving HTTPS requests. This lets me
to completely avoid sending anything over unencrypted HTTP, including
the webhook.</li>
</ul>
<p>Now I can see if it’s serving my pages correctly:</p>
<pre><code>$ curl -v -H &#39;Host: dram.page&#39; &#39;https://grebedoc.dev&#39;</code></pre>
<p>For me, that looked good, so I’m ready to do the switch, changing the
actual DNS record to make my site point to the grebedoc.dev server:</p>
<pre><code>dram.page.  600  IN  ALIAS  grebedoc.dev</code></pre>
<p>… well, <code>ALIAS</code> is not a real DNS record. The effect is
that the authoritative DNS server looks up the IPv4 and IPv6 address of
the domain <code>grebedoc.dev</code> and serves them as A and AAAA
records of <code>dram.page</code>. Fortunately my authoritative DNS
service has this feature.</p>
<p>And that’s it, I’m serving the latest site on grebedoc.dev.</p>
<p>As for auto-updating, the webhook part works normally.</p>
<h2 id="whats-wrong-with-netlify">What’s wrong with Netlify?</h2>
<p>Nothing, really, but since I use zero complex features and just serve
what’s in the git repo, this is just simpler.</p>]]></description>
    </item>
    <item>
        <title>Slide rules approximating Vernier scales</title>
        <pubDate>Sat, 19 Apr 2025 00:00:00 +0000</pubDate>
        <guid isPermaLink="true">https://dram.page/p/slide-rule-vernier</guid>
        <description><![CDATA[<p><a
href="https://en.wikipedia.org/wiki/Slide_rule">Slide rules</a> are
amazing. Even though nowadays we carry around in our pockets a computer
with power unfathomed in the last century, I still think slide rules are
a wonderful way to manipulate proportions in the analog domain. In fact,
I regularly carry one in my daily bag.</p>
<p>One problem with the slide rule I carry daily (a Faber-Castelle
62/82) is that it’s rather small, about half a foot (around 15
centimeters) in length. (Presumably, the “6” in its name refers to its
length of 6 inches.) This means there are fewer markings on it, and the
precision of the numbers read from it is limited. I can only, for the
most part, get 2 significant digits out of it.</p>
<p>Today I learned about a trick published over 60 years ago that allows
me to pretty consistently get to 3 significant digits on the same
hardware, at the cost of some more manipulations. To me, it felt like a
software upgrade to my slide rule. How does it work? Let’s find out.</p>
<h2 id="the-method">The method</h2>
<p>Here’s a simplified representation of the two conventional scales C
and D. The top scale here is C, and the bottom is D. They both go from 1
to 10, and the horizontal lengths are proportional to the logarithm of
the numeric values.</p>
<p>For convenience, we’ll refer to the two scales as “top scale” and
“bottom scale”.</p>
<svg
    version="1.1"
    viewBox="-10 -2 360 48"
    xmlns:xlink="http://www.w3.org/1999/xlink"
    xmlns="http://www.w3.org/2000/svg">
    <use xlink:href="#slideup" x="0" y="22" />
    <use xlink:href="#slidedown" x="20" y="22" />
</svg>
<p>Let’s say we want to read the position of the hairline on the bottom
scale, shown here as a long red line:</p>
<svg
    version="1.1"
    viewBox="140 20 90 26"
    xmlns:xlink="http://www.w3.org/1999/xlink"
    xmlns="http://www.w3.org/2000/svg">
    <use xlink:href="#slidedown" x="14.17099" y="22" />
</svg>
<p>We can see that it’s between <code>3.7</code> and <code>3.8</code>,
but it would be difficult to ascertain the next digit.</p>
<p>Step 1: Line up 10 on the top scale with 9 on the bottom scale:</p>
<svg
    version="1.1"
    viewBox="200 -2 160 48"
    xmlns:xlink="http://www.w3.org/1999/xlink"
    xmlns="http://www.w3.org/2000/svg">
    <use xlink:href="#slideup" x="0" y="22" />
    <use xlink:href="#slidedown" x="14.17099" y="22" />
    <rect
        style="fill: #0000ff22; stroke: blue; stroke-width: 0.5"
        width="6"
        height="38"
        x="306.6977"
        y="3" />
</svg>
<p>Step 2: Go back to the hairline, and find a nearby marking on the top
scale that is close to the hairline:</p>
<svg
    version="1.1"
    viewBox="160 -2 200 48"
    xmlns:xlink="http://www.w3.org/1999/xlink"
    xmlns="http://www.w3.org/2000/svg">
    <use xlink:href="#slideup" x="0" y="22" />
    <use xlink:href="#slidedown" x="14.17099" y="22" />
    <rect
        style="fill: #0000ff22; stroke: blue; stroke-width: 0.5"
        width="3"
        height="10"
        x="188.27775"
        y="13" />
</svg>
<p>Step 2: Move the top scale so that the found marking lines up with
the hairline:</p>
<svg
    version="1.1"
    viewBox="160 -2 200 48"
    xmlns:xlink="http://www.w3.org/1999/xlink"
    xmlns="http://www.w3.org/2000/svg">
    <use xlink:href="#slideup" x="1.45015" y="22" />
    <use xlink:href="#slidedown" x="14.17099" y="22" />
    <rect
        style="fill: #0000ff22; stroke: blue; stroke-width: 0.5"
        width="3"
        height="10"
        x="189.72790028083742"
        y="13" />
</svg>
<p>Let’s zoom in on the hairline:</p>
<svg
    version="1.1"
    viewBox="160 -2 120 48"
    xmlns:xlink="http://www.w3.org/1999/xlink"
    xmlns="http://www.w3.org/2000/svg">
    <use xlink:href="#slideup" x="1.45015" y="22" />
    <use xlink:href="#slidedown" x="14.17099" y="22" />
    <rect
        style="fill: #0000ff22; stroke: blue; stroke-width: 0.5"
        width="3"
        height="10"
        x="189.72790028083742"
        y="13" />
</svg>
<p>Step 3: Starting at the hairline position, going in the positive
direction.</p>
<ul>
<li>On the bottom scale, count markings after the hairline, starting at
1.</li>
<li>On the top scale, count markings starting at the one at the hairline
as 0.</li>
</ul>
<p>Find the pair of markings that line up best and note the number.
Here, marking number 3 lines up best, as marked by the magenta dot.</p>
<svg
    version="1.1"
    viewBox="175 4 65 30"
    xmlns:xlink="http://www.w3.org/1999/xlink"
    xmlns="http://www.w3.org/2000/svg">
    <use xlink:href="#slideup" x="1.45015" y="22" />
    <use xlink:href="#slidedown" x="14.17099" y="22" />

    <rect style="
        x: 188.778; y: calc(15px - 0.2lh);
        width: calc(32.3551px + 0.4ch);
        height: calc(0.2lh + 1px);
        fill: #ffffffaa" />

    <rect style="
        x: 191.929; y: calc(31px - 0.2lh);
        width: calc(30.5895px + 0.4ch);
        height: calc(0.2lh + 1px);
        fill: #ffffffaa" />

    <g style="font-size: 20%; fill: blue" transform="translate(0.5, 15)">
        <text x="189.778" y="0">0</text>
        <text x="193.019" y="0">1</text>
        <text x="196.184" y="0">2</text>
        <text x="199.276" y="0">3</text>
        <text x="202.298" y="0">4</text>
        <text x="205.255" y="0">5</text>
        <text x="208.147" y="0">6</text>
        <text x="210.979" y="0">7</text>
        <text x="213.752" y="0">8</text>
        <text x="216.469" y="0">9</text>
        <text x="219.133" y="0">10</text>
    </g>
    <g style="font-size: 20%; fill: blue" transform="translate(-0.8, 31)">
        <text x="193.729" y="0">1</text>
        <text x="197.222" y="0">2</text>
        <text x="200.628" y="0">3</text>
        <text x="203.949" y="0">4</text>
        <text x="207.19" y="0">5</text>
        <text x="210.355" y="0">6</text>
        <text x="213.447" y="0">7</text>
        <text x="216.469" y="0">8</text>
        <text x="219.426" y="0">9</text>
        <text x="222.318" y="0">10</text>

    </g>

    <circle cx="200.68758" cy="22" r="1.7" stroke="none" fill="#ff00ff88"/>
</svg>
<p>If you’re having trouble telling which line matches up, note how on
the left of the correct line, the bottom markings deviate left, and
similarly on the right side the bottom markings deviate right.</p>
<p>(This is exactly how you read a Vernier scale, by the way.)</p>
<p>Step 4: Whatever the number is, the hairline is that many tenths of a
division past the previous marking.</p>
<p>For example, since the number of the line matching up is 3, and the
hairline is between <code>3.7</code> and <code>3.8</code>, we know the
hairline is at <code>3.7 + 0.1 × (3/10) = 3.73</code>.</p>
<p>That is, in fact, exactly the value I used to generate the position
of this hairline.</p>
<h2 id="how-does-this-work">How does this work?</h2>
<p>Corresponding positions on the top and bottom scale preserve
proportions. Therefore, when we line up 10 on the top scale with 9 on
the bottom scale, the numbers on the top scale are <code>10/9</code>
times the number on the bottom scale. This means that the distance
between markings on the top scale must be <code>9/10</code> of the
distance on the bottom scale. This turns our slide rule markings into a
<a href="https://en.wikipedia.org/wiki/Vernier_scale">Vernier scale</a>,
and can be read similarly.</p>
<p>Of course, this makes a few approximating assumptions. Firstly, it
assumes that the markings are locally linear. Secondly, it assumes that
the adjusting step 2 does not affect distance proportions much.
Therefore, the new significant digit provided by this method is an
approximate value.</p>
<h2 id="more-details-on-usage">More details on usage</h2>
<p>This method also won’t directly work if the two scales have different
amount of increment per division. You may have to ignore some markings
to make it work.</p>
<p>It also does not work directly with positions after 9. However, you
can consider using a folded scale (CF and DF) to move the value closer
to the middle of the slide rule. Some slide rules (such as my 62/82)
have “overflow” areas before 1 and after 10 that may help.</p>
<p>You can also count backwards to the previous matching line, and
extrapolate the answer, noting that 9 divisions on the bottom equals 10
divisions on the top. The original article even suggests trying other
proportions.</p>
<h2 id="references">References</h2>
<p>The method described in this article was originally published in:
Roger Wickenden, 1948, Utilizing the Vernier Principle for Precise
Readings of Slide Rule Settings, <a
href="https://doi.org/10.1119/1.1991139">doi:10.1119/1.1991139</a></p>
<p>Images in this article are based on work by Wrtlprnft, itself based
on original image made by Benjamin Crowell. See the original file at: <a
href="https://en.wikipedia.org/wiki/File:Slide_rule_example3.svg"
class="uri">https://en.wikipedia.org/wiki/File:Slide_rule_example3.svg</a></p>
<h2 id="license-and-source-code">License and source code</h2>
<p>This article, including the images, are licensed under the Creative
Commons Attribution-ShareAlike 4.0 International license. For more
information on the license, see: <a
href="https://creativecommons.org/licenses/by-sa/4.0/deed.en"
class="uri">https://creativecommons.org/licenses/by-sa/4.0/deed.en</a></p>
<p>The Markdown source to this page can be found at: <a
href="https://github.com/dramforever/dram.page/blob/master/p/slide-rule-vernier/index.md"
class="uri">https://github.com/dramforever/dram.page/blob/master/p/slide-rule-vernier/index.md</a></p>
<svg
    version="1.1"
    viewBox="0 0 0 0"
    style="display: none"
    xmlns:xlink="http://www.w3.org/1999/xlink"
    xmlns="http://www.w3.org/2000/svg">
  <defs>
    <g id="scale">
      <rect
         style="fill:#f0e0d0;stroke:#000000;stroke-width:1"
         width="328"
         height="22"
         x="-9"
         y="0" />
      <path
         d="m 0,0 0,12 m 6.5622771,-12 0,6 m 6.2569419,-6 0,9 m 5.978762,-9 0,6 m 5.724268,-6 0,9 m 5.490559,-9 0,6 m 5.275186,-6 0,9 m 5.076074,-9 0,6 m 4.891448,-6 0,9 m 4.719782,-9 0,6 m 4.559759,-6 0,12 m 4.410231,-12 0,6 m 4.2702,-6 0,9 m 4.138788,-9 0,6 m 4.015224,-6 0,9 m 3.898823,-9 0,6 m 3.788983,-6 0,9 m 3.685162,-9 0,6 m 3.58688,-6 0,9 m 3.493703,-9 0,6 m 3.405245,-6 0,12 m 3.321156,-12 0,6 m 3.241121,-6 0,9 m 3.164847,-9 0,6 m 3.09209,-6 0,9 m 3.0226,-9 0,6 m 2.95617,-6 0,9 m 2.89258,-9 0,6 m 2.83169,-6 0,9 m 2.77329,-9 0,6 m 2.71726,-6 0,12 m 2.66346,-12 0,6 m 2.61173,-6 0,9 m 2.56198,-9 0,6 m 2.51409,-6 0,9 m 2.46796,-9 0,6 m 2.42349,-6 0,9 m 2.38059,-9 0,6 m 2.33919,-6 0,9 m 2.29921,-9 0,6 m 2.26055,-6 0,12 m 4.41023,-12 0,6 m 4.2702,-6 0,6 m 4.13879,-6 0,6 m 4.01523,-6 0,6 m 3.89882,-6 0,9 m 3.78898,-9 0,6 m 3.68516,-6 0,6 m 3.58688,-6 0,6 m 3.49371,-6 0,6 m 3.40524,-6 0,12 m 3.32116,-12 0,6 m 3.24112,-6 0,6 m 3.16485,-6 0,6 m 3.09209,-6 0,6 m 3.0226,-6 0,9 m 2.95616,-9 0,6 m 2.89259,-6 0,6 m 2.83168,-6 0,6 m 2.7733,-6 0,6 m 2.71726,-6 0,12 m 2.66345,-12 0,6 m 2.61174,-6 0,6 m 2.56198,-6 0,6 m 2.51409,-6 0,6 m 2.46796,-6 0,9 m 2.42349,-9 0,6 m 2.38059,-6 0,6 m 2.33919,-6 0,6 m 2.2992,-6 0,6 m 2.26056,-6 0,12 m 4.41023,-12 0,6 m 4.2702,-6 0,6 m 4.13879,-6 0,6 m 4.01522,-6 0,6 m 3.89883,-6 0,12 m 3.78898,-12 0,6 m 3.68516,-6 0,6 m 3.58688,-6 0,6 m 3.4937,-6 0,6 m 3.40525,-6 0,12 m 3.32115,-12 0,6 m 3.24112,-6 0,6 m 3.16486,-6 0,6 m 3.09209,-6 0,6 m 3.0226,-6 0,12 m 2.95616,-12 0,6 m 2.89258,-6 0,6 m 2.83169,-6 0,6 m 2.77329,-6 0,6 m 2.71727,-6 0,12"
         style="stroke: black; stroke-width: 1" />
    </g>
    <g id="numbers" font-size="9px">
      <text x="1.5" y="0">1</text>
      <text x="94.728302" y="0">2</text>
      <text x="149.263" y="0">3</text>
      <text x="187.957" y="0">4</text>
      <text x="217.96899" y="0">5</text>
      <text x="242.492" y="0">6</text>
      <text x="263.22501" y="0">7</text>
      <text x="281.185" y="0">8</text>
      <text x="297.02701" y="0">9</text>
      <text x="311.198" y="0">1</text>
    </g>
    <g id="slidedown">
      <use xlink:href="#scale" x="0" y="0" />
      <use xlink:href="#numbers" x="0" y="16" />
      <path
         d="m 177.05691028083743,-0.5 0,23"
         style="stroke: red; stroke-width: 0.5" />
    </g>
    <g id="slideup">
      <use xlink:href="#scale" x="0" y="0" transform="scale(1,-1)" />
      <use xlink:href="#numbers" x="0" y="-9" />
    </g>
  </defs>
</svg>]]></description>
    </item>
    <item>
        <title>Threaded code explained in C</title>
        <pubDate>Mon, 20 Nov 2023 00:00:00 +0000</pubDate>
        <guid isPermaLink="true">https://dram.page/p/threaded-code</guid>
        <description><![CDATA[<p>At some point in your life you may have
decided that it would be a good idea to represent something in term of a
“virtual machine”. You know, a relatively simple format of data that
encodes things to do, and a simple interpreter reading it and doing the
actual thing.</p>
<p>I hope what you were intending to implement is actually a programming
language, not just something that got to the point of being accidentally
Turing-complete. I wouldn’t judge either way though.</p>
<h2 id="side-note-c-features-used-in-this-article">Side note: C features
used in this article</h2>
<p>I’m going to assume familiarity with the C language, but just to make
easier for those less familiar with C, here are some explanations of
less obvious constructs used in the code:</p>
<h3 id="infinite-loop">Infinite loop</h3>
<p><code>for (;;)</code> is an infinite loop.</p>
<h3 id="stack-operations">Stack operations</h3>
<p>We’re going to use arrays and pointers as stacks. The convention
we’re going to use is:</p>
<pre><code>uintptr_t stack_buf[STACK_SIZE];
uintptr_t *sp = stack_buf;</code></pre>
<ul>
<li>The stack “grows up”, meaning that successive pushes go into higher
indices.</li>
<li>The stack pointer starts at the beginning of the underlying
array.</li>
<li>The stack pointer points to one element after the top element. So if
the stack currently has <code>3</code> elements, then
<code>sp = stack_buf + 3</code>.</li>
<li>Using the semantics of C’s increment/decrement operators,
<code>*(sp++) = foo</code> pushes <code>foo</code> on the stack, whereas
<code>bar = *(--sp)</code> pops an element from the stack and assigns it
to <code>bar</code>.</li>
</ul>
<h3 id="function-pointers">Function pointers</h3>
<p>Later in the article we’re going to need to “store” functions as
data. The way this is done is using a <em>function pointer</em>.</p>
<p>It’s possible to declare function pointers directly, but I’m going to
use a <code>typedef</code> for the sake of your sanity:</p>
<pre><code>typedef void (*codeptr)(void);</code></pre>
<p>This means <code>codeptr</code> is now a type alias for the type
“function pointer to a function that takes no arguments and returns
<code>void</code>”.</p>
<p>(For historical reasons a parameter list of <code>(void)</code>, not
<code>()</code>, means “takes no arguments” in C.)</p>
<p>You can use this type in variables or members. The name of any
function with the correct signature can be used as a value of type
<code>codeptr</code>. To use a function pointer, just call it like any
function.</p>
<pre><code>void foo(void);
codeptr p = foo;
p(); // Calls foo</code></pre>
<p>On most architectures a function pointer is represented by the
address of the start of the code of a function.</p>
<h2 id="bytecode">Bytecode</h2>
<p>A “bytecode” is one of the obvious popular choices. Each instruction
has, say, one byte of opcode and several bytes of operands. Let’s also
say we’re using a stack machine, because it’s also an obvious popular
choice. A bytecode program might look something like this:</p>
<pre><code>#define OP_EXIT 0
#define OP_PUSH 1
#define OP_ADD 2
#define OP_PRINT 3
// ... more opcodes

const uint8_t program[] = {
    OP_PUSH, 1, OP_PUSH, 1, OP_ADD, OP_PRINT, OP_EXIT,
};</code></pre>
<p>And the interpreter would look something like this:</p>
<pre><code>const uint8_t *ip = program;

uintptr_t stack_buf[STACK_SIZE];
uintptr_t *sp = stack_buf;

void interpreter(void) {
    for (;;) {
        switch (*ip) {
        case OP_PUSH:
            ip++;
            uintptr_t operand = *(ip++);
            *(sp++) = operand;
            break;

        case OP_ADD:
            ip++;
            uintptr_t b = *(--sp);
            uintptr_t a = *(--sp);
            *(sp++) = a + b;
            break;

        // ... more opcodes
        }
    }
}</code></pre>
<h2 id="direct-threaded-code">Direct threaded code</h2>
<p>The <code>switch</code> statement above would probably be compiled
into a jump table by the compiler. If you don’t need the program to be
serializable, one thing you can do is to simply store function pointers
in an array, skipping the table altogether:</p>
<pre><code>typedef void (*codeptr)(void);

void code_one(void);
// ... more functions

const codeptr program[] = {
    code_one, code_one, code_add, code_print, code_exit,
};</code></pre>
<p>Instead of <code>case</code>s in a <code>switch</code> block, the
individual opcodes are now individual functions</p>
<pre><code>void code_one(void) {
    ip++;
    *(sp++) = 1;
}

void code_add(void) {
    ip++;
    uintptr_t b = *(--sp);
    uintptr_t a = *(--sp);
    *(sp++) = a + b;
}

// ...</code></pre>
<p>And the interpreter would simply repeatedly call the current function
pointer. For simplicity’s sake, we’ll keep the interpreter state in
global variables (for now).</p>
<pre><code>const codeptr *ip = program; // Changed!

uintptr_t stack_buf[STACK_SIZE];
uintptr_t *sp = stack_buf;

void interpreter(void) {
    for (;;)
        (*ip)();
}</code></pre>
<h2 id="indirect-threaded-code">Indirect threaded code</h2>
<p>Instead of function pointers, the program can contain pointers to
more complicated objects. An obvious example would be <em>other
programs</em>, as an implementation of subroutines.</p>
<p>Since we want the handling of objects to remain uniform, each object
would need a function pointer pointing to some code telling it what to
do. Following it could be some payload. For simplicity, let’s say that
the only possible payload is a subroutine.</p>
<p>To handle subroutine calls and returns, we’d also need to add a
return stack pointer (<code>rsp</code>) to our interpreter state. We’ll
see how to handle it later.</p>
<pre><code>typedef void (*codeptr)(void);

struct object {
    codeptr code;
    const struct object *payload[];
};

const struct object *const *ip = ...; // Changed!

uintptr_t stack_buf[STACK_SIZE];
uintptr_t *sp = stack_buf;

// New: return stack
const struct object *const *rstack_buf[STACK_SIZE];
const struct object *const **rsp = rstack_buf;</code></pre>
<p>Primitive objects can have <code>code</code> with no
<code>payload</code>:</p>
<pre><code>void code_add(void) {
    ip++;
    uintptr_t b = *(--sp);
    uintptr_t a = *(--sp);
    *(sp++) = a + b;
}

const struct object o_add = { .code = code_add };</code></pre>
<p>Within a <code>code</code>, you can get access to a pointer to the
current object with <code>*ip</code>.</p>
<p>Let’s see how we could handle subroutines. The code of a subroutine
objects should bump the <code>ip</code> and push it on the return stack,
and change <code>ip</code> to point to the payload. Each subroutine
should end with a <code>return</code> primitive that pops the return
address and change <code>ip</code> back:</p>
<pre><code>void code_subroutine(void) {
    const struct object *self = *ip;
    ip++;
    *(rsp++) = ip;
    ip = self-&gt;payload;
}

void code_return(void) {
    ip = *(--rsp);
}

const struct object o_return = { .code = code_return };</code></pre>
<p>And now a subroutine could look like</p>
<pre><code>const struct object o_two = {
    .code = code_subroutine,
    .payload = { &amp;o_one, &amp;o_one, &amp;o_add, &amp;o_return },
};</code></pre>
<p>The interpreter is largely unchanged, just with an additional
dereferencing on <code>ip</code>. Starting the interpreter is slightly
tricky. Where do you point <code>ip</code> initially?</p>
<p>If you have an object that’s the “main program” <code>o_main</code>,
you can store <code>&amp;o_main</code> in memory and let <code>ip</code>
point to that. Be careful — the main program must not return because it
has nowhere to return to.</p>
<pre><code>const struct object *const start = &amp;o_main;
const struct object *const *ip = &amp;start;

void interpreter(void) {
    for (;;)
        (*ip)-&gt;code();
}</code></pre>
<h2 id="primitive-centric-threaded-code">Primitive-centric threaded
code</h2>
<p>There are two issues with indirect threaded code from the previous
section:</p>
<ul>
<li>The extra pointer indirection might be unsatisfactory for efficiency
reasons.</li>
<li>There’s no easy way to encode an immediate operand.</li>
</ul>
<p>We can solve both problems with yet another spin on threaded code. M.
Anton Ertl, in implementing Gforth, used what was referred to as
“primitive-centric threaded code”. It is essentially a fat pointer
scheme:</p>
<pre><code>typedef void (*codeptr)(uintptr_t);

struct instr {
    codeptr code;
    uintptr_t data;
};</code></pre>
<p>Instead of requiring a dereference of a point to access an object,
the program directly stores a function pointer and one pointer worth of
extra data. When processing each “instruction” in the program, the
interpreter provides the extra data to the function.</p>
<pre><code>const struct instr i_main = { ... };
const struct instr *ip = &amp;i_main; // Changed!

uintptr_t stack_buf[STACK_SIZE];
uintptr_t *sp = stack_buf;

// Changed to adapt to match the type of ip
const struct instr *rstack_buf[STACK_SIZE];
const struct instr **rsp = rstack_buf;

void interpreter(void) {
    for (;;) {
        struct instr ins = *ip;
        ins.code(ins.data);
    }
}</code></pre>
<p>It’s now possible again to make a generic “push”, without requiring
separate code for every possible immediate value:</p>
<pre><code>void code_push(uintptr_t data) {
    ip++;
    *(sp++) = data;
}

const struct instr i_one = { .code = code_push, .data = 1 };
const struct instr i_two = { .code = code_push, .data = 2 };</code></pre>
<p>Subroutine calls can be made by making <code>data</code> point to an
array of instructions making up the subroutines:</p>
<pre><code>void code_subroutine(uintptr_t data) {
    const struct instr *sr = (const struct instr *) data;
    ip++;
    *(rsp++) = ip;
    ip = sr;
}

void code_return(uintptr_t data) {
    ip = *(--rsp);
}

const struct instr sr_three[] = {
    { .code = code_push, .data = 1 },
    { .code = code_push, .data = 2 },
    { .code = code_add },
    { .code = code_return },
};

const struct instr sr_six[] = {
    { .code = code_subroutine, .data = (uintptr_t) sr_three },
    { .code = code_subroutine, .data = (uintptr_t) sr_three },
    { .code = code_add },
    { .code = code_return },
};</code></pre>
<h2 id="optimization">Optimization</h2>
<p>We can leverage a few tricks to convince the compiler into keeping
our interpreter state in registers, and avoid doing a function call and
return for each step.</p>
<p>Firstly, instead of using a loop to repeatedly call functions, we can
instead make each piece of code tail call the next:</p>
<pre><code>void code_foo(uintptr_t data) {
    // ...

    struct instr ins = *ip;
    ins.code(ins.data);
}</code></pre>
<p>Compile your code with optimizations on. Your compiler should
recognize that this is a tail call, and compile this down to a simpler
indirect jump.</p>
<p>Next, instead of using global variables for the interpreter state,
put them into arguments:</p>
<pre><code>void code_foo(
    uintptr_t data,
    const struct instr *ip,
    uintptr_t *sp,
    const struct instr **rsp
) {
    // ...

    struct instr ins = *ip;
    ins.code(ins.data, ip, sp, rsp);
}</code></pre>
<p>Using some macros would reduce the boilerplate a bit</p>
<pre><code>#define DECL_STATE \
    const struct instr *ip, \
    uintptr_t *sp, \
    const struct instr **rsp

#define STATE ip, sp, rsp

void code_foo(uintptr_t data, DECL_STATE) {
    // ...

    struct instr ins = *ip;
    ins.code(ins.data, STATE);
}</code></pre>
<p>On modern register-rich architectures (x86-64, ARM, RISC-V, MIPS, …),
the arguments <code>ip</code>, <code>sp</code>, <code>rsp</code> would
be passed in registers. Since <code>ins.code</code> expect these in the
same registers, if your code leaves some of those state variables
unchanged, there’s no cost to simply passing it on.</p>
<p>(On 32-bit x86, it might be possible with some non-portable
<code>__attribute__((regparm(4)))</code> magic. I have not yet
experimented with this.)</p>
<p>For threaded code, this is about as close as it gets to what you’d
write in assembly. More native-code optimizations is possible, but would
be out of the scope of (mostly) portable C.</p>
<h2 id="notes">Notes</h2>
<p>The <a
href="https://gforth.org/manual/Threading.html"><em>Threading</em></a>
section from the Gforth manual was very helpful when writing this
article. In particular, the concept of primitive-centric threaded code
is described in detail.</p>
<p>Complete demos corresponding to snippets in this article can be found
on <a href="https://github.com/dramforever/threaded-code-demo">GitHub at
dramforever/threaded-code-demo</a>.</p>]]></description>
    </item>
    <item>
        <title>ELF relative relocations explained</title>
        <pubDate>Mon, 18 Sep 2023 00:00:00 +0000</pubDate>
        <guid isPermaLink="true">https://dram.page/p/relative-relocs-explained</guid>
        <description><![CDATA[<h2 id="background">Background</h2>
<p>Consider this code, where one piece of global data is a pointer to
another piece of global data:</p>
<pre><code>void *foo;
void *bar = &amp;foo;</code></pre>
<p>During program execution, the memory at <code>bar</code> contains an
address of <code>foo</code>. One way to achieve this is to require all
the data to be loaded at a certain address. Then the linker can simply
pre-calculate the address at link time and fill in the address for
<code>bar</code>.</p>
<p>Having a program runnable from only one fixed address may be
undesirable, however:</p>
<ul>
<li>If we’re a shared library, this would require a global registry of
library addresses to avoid collision, and would be a massive pain.</li>
<li>ASLR by definition requires randomized addresses and is in direct
conflict of fixed addresses.</li>
<li>In early boot scenarios such as bootloaders or EFI applications or
drivers, virtual memory is not available, and it’s desirable to place
executables out of the way of one another at runtime.</li>
</ul>
<p>If something can work at any (suitably aligned) address, it is
<em>position-independent</em>. Otherwise it’s
<em>position-dependent</em>.</p>
<p>By compiling code to use PC-relative addressing, executable code can
be made position-independent <em>relatively</em> easily. (Ha!) However
the problem with global pointers is more fundamental. Again, take a look
back at the code:</p>
<pre><code>void *foo;
void *bar = &amp;foo;</code></pre>
<p>If we don’t want to change the representation of a
<code>void *</code>, and the address of global data is only known at
runtime, something has to, <em>at runtime</em>, figure out the address
of <code>foo</code> and put it in <code>bar</code> before user code can
see it.</p>
<h2 id="relative-relocations">Relative relocations</h2>
<p>On ELF systems, this problem is handled with <em>dynamic
relocations</em>. We’ll tackle the most simple case here: relative
relocations.</p>
<p>We’ll handle the simplest case and assume everything (code, data) in
an executable must still be contiguous and cannot move relative to one
another. The entire executable will move as a whole to some “base
address” that is only known at runtime. Then everything in the
executable will be at a fixed offset from the base address.</p>
<p>We will also not need to link to dynamic shared libraries, and
everything we need is in the executable. This is known as a
statically-linked position-independent executable, or
<em>static-pie</em>.</p>
<p>Conceptually, the three major steps that occur to make the code
example work are:</p>
<ol type="1">
<li><p>Compiler: Generates a relocatable file (object file) with static
relocations saying this:</p>
<pre><code>(8 bytes) // foo
(8 bytes) // bar, Please fill in the address of foo</code></pre></li>
<li><p>Linker: Places everything the compiler says to place at offsets
from the base and generates a static-pie with dynamic relocations:</p>
<pre><code>offset       contents
0x100        (8 bytes)
0x108        (8 bytes) // Please fill in value of (base + 0x100)</code></pre></li>
<li><p>Startup code: Figures out <code>base</code>, looks at the dynamic
relocations, and fills in the correct addresses:</p>
<pre><code>addr         contents
0xabc100     0
0xabc108     0xabc100</code></pre></li>
</ol>
<p>We’ll ignore the relocatable file and focus on the static-pie.</p>
<h2 id="rela-and-rel">RELA and REL</h2>
<p>An instruction like “please fill in value of
<code>(base + one_offset)</code> at
<code>(base + another_offset)</code>” is called a <em>relocation</em>.
The most obvious way to encode such a relocation is to just have a table
of offsets. Like maybe an array of “RELA” entries:</p>
<pre><code>struct {
    uintptr_t offset;
    uintptr_t info;
    intptr_t addend;
}</code></pre>
<p><code>info</code> encodes information. The low 8 (for 32-bit ELF) or
32 (for 64-bit ELF) bits encodes the type of relocation and higher bits
is a symbol index. For our purposes the type is just
<code>R_*_RELATIVE</code>, and since it’s just an offset and there’s no
symbol, all the higher bits are 0.</p>
<p>(In <code>elf.h</code> speak, <code>ELF*_R_INFO(sym, type)</code>
encodes the symbol index and relocation type into <code>info</code>
(<code>*</code> is <code>32</code> or <code>64</code>), and
<code>ELF*_R_TYPE(info)</code>, <code>ELF*_R_SYM(info)</code> unpacks
the fields back.)</p>
<p><code>offset</code> is the offset from the base address to which the
entry applies to, and the addend is… the value to be added, in this case
added to the base address.</p>
<p>(<em>Note</em>: The same structure is used for static relocations but
the meanings of fields are not identical. That’s irrelevant to this
article.)</p>
<p>To put everything together again, for each entry in the array, if
<code>info == R_*_RELATIVE</code>, then it means “Please fill in the
value of <code>(base + addend)</code> at <code>(base + offset)</code>”.
The algorithm to run to apply these relocations is also pretty
simple:</p>
<pre><code>uintptr_t base = ...;
for (rela = ...) {
    if (ELF*_R_TYPE(rela-&gt;info) == R_*_RELATIVE) {
        *(uintptr_t *)(base + rela-&gt;offset) = base + rela-&gt;addend;
    } else ...
}</code></pre>
<p>On some architectures a simplified structure “REL” is used, like:</p>
<pre><code>struct {
    uintptr_t offset;
    uintptr_t info;
}</code></pre>
<p>The <code>addend</code> field is gone from the table, and is just
stashed into where <code>offset</code> points. The meaning of entries is
otherwise the same.</p>
<pre><code>for (rel = ...) {
    if (ELF*_R_TYPE(rel-&gt;info) == R_*_RELATIVE) {
        *(uintptr_t *)(base + rel-&gt;offset) += base;
    } else ...
}</code></pre>
<h2 id="the-.rela.dyn-section-and-dt_rela">The <code>.rel[a].dyn</code>
section, and <code>DT_REL[A]*</code></h2>
<p>The linker synthesizes an array of tag-value pairs of dynamic linking
information, and also synthesizes a symbol <code>_DYNAMIC</code> to
point to the start of it:</p>
<pre><code>struct {
    uintptr_t tag;
    uintptr_t value;
} _DYNAMIC[];</code></pre>
<p>The format of the dynamic array does not have an explicit size and is
terminated by an entry with <code>tag</code> as
<code>DT_NULL = 0</code>. The relevant tags for us are:</p>
<ul>
<li><code>tag</code> is <code>DT_RELA = 7</code>, <code>value</code> is
offset of array of RELA entries</li>
<li><code>tag</code> is <code>DT_RELASZ = 8</code>, <code>value</code>
is total size in bytes of the array of RELA entries</li>
<li><code>tag</code> is <code>DT_RELAENT = 9</code>, <code>value</code>
is the size in bytes of one RELA entry. If there ever is a future need
for extending the contents RELA entry, this will grow larger.</li>
</ul>
<p>This allows us to find where the array of RELA entries is. We can
just find <code>_DYNAMIC</code> and the base address using PC-relative
addressing, and we can run the relocation algorithm from the previous
section.</p>
<pre><code>// Find these from _DYNAMIC
size_t dt_rela, dt_relasz, dt_relaent;

for (char *ptr = (char*)(dt_rela + base);
    ptr &lt; (char*)(base + dt_rela + dt_relasz);
    ptr += dt_relaent) {
    Rela *rela = (Rela*)ptr;

    // Handle rela
}</code></pre>
<p>Perhaps just for convenience, the linker puts the
<code>_DYNAMIC</code> array in a section called <code>.dynamic</code>,
and the dynamic RELA relocations in <code>.rela.dyn</code>.</p>
<p>(If you have an operating system giving you ELF auxillary vectors,
you can look up the base address as <code>AT_BASE</code>, and look up
where <code>_DYNAMIC</code> is by looking for <code>AT_PHDR</code> to
find the <code>PT_DYNAMIC</code> segment. I suppose this is more
portable.)</p>
<p>A similar thing happens for REL, with the <code>.rel.dyn</code>
section, and tags <code>DT_REL = 17</code>, <code>DT_RELSZ = 18</code>,
<code>DT_RELENT = 19</code>. Not much more to say about those.</p>
<h2 id="linker-script-trickery-for-the-.rela.dyn-section">Linker script
trickery for the <code>.rel[a].dyn</code> section</h2>
<p>If you’re building a bootloader or something and just want to, you
don’t <em>have</em> to use <code>_DYNAMIC</code>. You can just use the
linker script to give you symbols that bound the <code>.rel[a]</code>
array.</p>
<pre><code>.rela.dyn : {
    __rela_start = .;
    *(.rela*)
    __rela_end = .;
}</code></pre>
<h2 id="relr">RELR</h2>
<p>The RELA format is grossly inefficient space-wise at representing
relocations. REL is 1/3 better but is only really a thing on some
architectures. Can we do even better?</p>
<p>For position independent executables it is often the case that there
are a lot of contiguous addresses needing relative relocation. For
example, this is one relocation per every string:</p>
<pre><code>const char *string_table = {
    &quot;one string&quot;,
    &quot;another string&quot;,
    &quot;a third string&quot;,
    ...
};</code></pre>
<p>RELR is a new packed format to store dynamic relative relocations
more efficiently with bitmaps. From what I can tell it’s not really well
documented, but support exists in e.g. glibc and musl. The linker LLD
supports it fully. BFD ld supports it for x86 only.</p>
<p><del>The closest to an official documentation is <a
href="https://groups.google.com/g/generic-abi/c/bX460iggiKg/m/YT2RrjpMAwAJ">one
email on the general-abi mailing list</a> that is a proposal for the
RELR format.</del></p>
<p><strong>Update 2025-06-02</strong>: DannyNiu/NJF informed me that
Xinuos Inc., the company that has been most recently maintaining the ELF
gABI, has, after nearly a decade of silence, published a new draft
version at <a href="https://gabi.xinuos.com"
class="uri">https://gabi.xinuos.com</a>, which includes a section
“Relative Relocation Table” describing RELR. This is the official
specification of RELR.</p>
<p>The idea originates from Google for their Android stuff, but the
format eventually settled on is this:</p>
<ul>
<li>Each entry is <code>uintptr_t</code> long.</li>
<li>If an entry is even, it means the <code>uintptr_t</code> at this
address needs relocating.</li>
<li>If an entry is odd, the bits except the least significant bit, from
lowest to highest, is a bitmap encoding which of the
<code>sizeof(uintptr_t) * 8 - 1</code> <code>uintptr_t</code> values
after the last address handled needs relocating.</li>
</ul>
<p>(It is simply assumed that all offsets needing relocation is
aligned.)</p>
<p>For example, on a 64-bit system, if we want 64 contiguous
relocations, we can just represent it with two entries:</p>
<pre><code>0x0000_0000_0001_0000   The one uintptr_t at offset 0x10000 needs relocating
0xffff_ffff_ffff_ffff   The next 63 uintptr_t values after that needs relocating
                        (Offset 0x10008 through 0x101f8)</code></pre>
<p>The last address handled is <code>0x101f8</code>, so if the next
entry is still a bitmap it would start from <code>0x10200</code>. If we
want one more relocation, making it 65 instead of 64:</p>
<pre><code>0x0000_0000_0000_0003   Of the next 63 words, only the first one needs relocating
                        (Offset 0x10200)</code></pre>
<p>(Remember that the least significant bit isn’t part of the
bitmap.)</p>
<p>Even though bitmap only has one bit set, it still handles 63
<code>uintptr_t</code> values, so if the next entry is still a bitmap it
would start from <code>0x103f8</code>.</p>
<p>If we want to skip to another address, just put in the address. In
fact if you want to be lazy and don’t want to figure out how to generate
bitmaps, you can skip this altogether and just put down a list of
addresses, and it’s still valid.</p>
<p>As simple as RELR is, the savings are remarkable. For our example, 65
relocations are represented with 24 bytes with RELR. In RELA that’s 1560
bytes. This is a space saving of 98%. According to <a
href="https://groups.google.com/g/generic-abi/c/bX460iggiKg/m/s8AOWvPaCAAJ">some
measurements</a> this saves around 5% to 20% of binary size for PIEs. On
most modern computers it is likely that the more compact in-memory
representation is also faster due to less memory accesses.</p>
<p>The algorithm in more detail is like this:</p>
<pre><code>uintptr_t next; // Next address to relocate
for (uintptr_t entry ...) {
    if ((entry &amp; 1) == 0) {
        *(uintptr_t *)(base + entry) += base; // Like REL

        // Next to relocate is the word after the one pointed to by entry
        next = base + entry + sizeof(uintptr_t);
    } else {
        // The bitmap handles the next (sizeof(uintptr_t) * 8 - 1) words
        for (i = 0; i &lt; sizeof(uintptr_t) * 8 - 1; i ++) {
            if ((entry &gt;&gt; (i + 1)) &amp; 1) {
                // If bit (i + 1) is set, word i needs relocating
                *(uintptr_t *)(next + sizeof(uintptr_t) * i) += base;
            }
        }

        // Next to relocate is after that
        next += sizeof(uintptr_t) * (8 * sizeof(uintptr_t) - 1);
    }
}</code></pre>
<p>For the bitmap case, it might be more convenient to write it like
this:</p>
<pre><code>        uintptr_t tmp = next;
        for (; entry &gt;&gt;= 1; tmp += sizeof(uintptr_t)) {
            if (entry &amp; 1) {
                *(uintptr_t *)tmp += base;
            }
        }

        next += sizeof(uintptr_t) * (8 * sizeof(uintptr_t) - 1);</code></pre>
<p>RELR uses <code>.relr.dyn</code> section and tags
<code>DT_RELR = 36</code>, <code>DT_RELRSZ = 35</code>,
<code>DT_RELRENT = 37</code>. (Note: The values aren’t sequential!)
Contrary to RELA, and most struct arrays in ELF, for that matter, RELR
doesn’t seem to designed to be extensible, since it’s just a compact
form of REL.</p>
<p>Since only dynamic relative relocations are represented in RELR, it
does not replace RELA/REL. The proposal states that dynamic RELR
relocations should be processed before REL/RELA.</p>
<h2 id="a-note-on-base-address">A note on “base address”</h2>
<p>The base address mentioned above is not actually the start of the
binary, but the offset of which the segments in a PIE (or shared
library) has been moved, so <code>real_address - segment_address</code>.
Since PIEs are usually linked to starting at <code>0</code> this checks
out. If your linker script links everything starting at somewhere else,
like:</p>
<pre><code>SECTIONS {
    . = 0x80000000;
    __executable_start = .;

    // ...
}</code></pre>
<p>The base address is actually
<code>real __executable_start - 0x80000000</code>. No idea why you would
do that though, since the whole point of PIE is to not have a fixed
start address…</p>
<h2 id="references">References</h2>
<ul>
<li><a
href="https://maskray.me/blog/2021-10-31-relative-relocations-and-relr">Relative
relocations and RELR</a> by MaskRay</li>
<li><a
href="https://lore.kernel.org/all/20190801011842.199786-1-pcc@google.com/">arm64:
Add support for relocating the kernel with RELR relocations</a> by Peter
Collingbourne</li>
<li><a
href="https://docs.oracle.com/cd/E23824_01/html/819-0690/toc.html">Linker
and Libraries Guide, Oracle Solaris 11 Information Library</a></li>
</ul>]]></description>
    </item>
    <item>
        <title>VisionFive JTAG adventures, Part 1: JH7100 GPIO</title>
        <pubDate>Mon, 27 Jun 2022 00:00:00 +0000</pubDate>
        <guid isPermaLink="true">https://dram.page/p/visionfive-jtag-1</guid>
        <description><![CDATA[<h2 id="background">Background</h2>
<p>The research that went into this article began as a simple technical
question: How do I connect to the JTAG debug port on the VisionFive?</p>
<p>When luojia <a
href="https://forum.rvspace.org/t/jtag-visionfive/354">asked this very
question</a> on the support forum, the only responses were,
surprisingly, discouragement. However, for any low-level software
development, such a debug port is pretty much the only way to sanely,
well, debug anything at all. Even though <code>printf</code> debugging
was technically possible, it is still worth it to see if we can reach it
over JTAG, given that the board is supposed to have JTAG connectors.</p>
<h2 id="visionfive">VisionFive</h2>
<p>The development board in question, <a
href="https://rvspace.org/en/Product/VisionFive/Technical_Documents/VisionFive_Single_Board_Computer_Quick_Start_Guide">VisionFive</a>,
is a RISC-V single-board computer from StarFive. At its core is a
StarFive JH7100 SoC, with two SiFive U74 cores and one E24 core.</p>
<p><em>(As of writing, the version of VisionFive currently available is
also known as ‘VisionFive V1’, though even official documentation often
omits the version number. The name ‘VisionFive’ in this article
consistently refers to VisionFive V1, in case confusion arises in the
future.)</em></p>
<p>The same processor core is also found on the <a
href="https://www.sifive.com/boards/hifive-unmatched">HiFive
Unmatched</a>, on which the main SoC has four U74 cores and one S7 core.
Unmatched had more RAM and better peripherals, and was made in the form
factor of a regular PC motherboard. VisionFive is, instead, clearly
intended for a slightly lower end market, or for those who prefers a
palm-sized Raspberry Pi lookalike.</p>
<h2 id="jtag-on-the-visionfive-or-not">JTAG on the VisionFive, or
not</h2>
<p>For our purposes, the one main difference between the Unmatched and
the VisionFive is how the JTAG port is connected. On the Unmatched, an
FT2322H adapter on-board means that the Micro-USB port gives access to
both the UART port and the JTAG port, readily usable with <a
href="https://github.com/riscv/riscv-openocd">riscv-openocd</a>.</p>
<p>On the VisionFive, however, JTAG access seems… elusive. Nowhere in
the documentation is the JTAG port on-board mentioned. On drawings of
the board, the words JTAG are written next to the PMIC, which is, at
least to me, nonsensical, as there are no notable ports to be found
there.</p>
<figure>
<img src="images/visionfive-drawing.jpg"
alt="One of the VisionFive drawings" />
<figcaption aria-hidden="true">One of the VisionFive
drawings</figcaption>
</figure>
<figure>
<img src="images/visionfive-photo.png"
alt="A photo of the VisionFive board" />
<figcaption aria-hidden="true">A photo of the VisionFive
board</figcaption>
</figure>
<p>Next to the color-coded (nice!) 40-pin header though, one can find
seven plated holes, one of them having a square outline. Browsing
through the schematic reveals that this is indeed where the JTAG port is
connected.</p>
<figure>
<img src="images/sch-jtag-port.png" alt="The JTAG port" />
<figcaption aria-hidden="true">The JTAG port</figcaption>
</figure>
<p>Problem solved, right? Solder up some header pins or build a pogo-pin
rig, and just connect it up to your workstation with an FT2322H, and we
have JTAG.</p>
<p>Or so we thought. Unfortunately, this JTAG ports does not seem to
respond at all to any input. It seems as if this port isn’t connected at
all.</p>
<h2 id="finding-the-jtag-port">Finding the JTAG port</h2>
<p>Chasing through labels on the schematics reveals that the
<code>JTAG_*</code> through-holes connect to a level shifter, which
presents the SoC with 1.8 V signals instead of 3.3 V ones. They then
connect to pads on the SoC, mysteriously named
<code>GPIOxx/U74_JTAG_*</code>.</p>
<figure>
<img src="images/sch-jtag-soc.png" alt="JTAG connections to the SOC" />
<figcaption aria-hidden="true">JTAG connections to the SOC</figcaption>
</figure>
<p>So are these GPIO or JTAG? Thankfully the pad connections have labels
with positions, so we can look them up on the datasheet. For example,
<code>A25</code> is described as…</p>
<pre><code>A25     GPIO[0]     IO      function IO share with GPIO</code></pre>
<p>‘Function IO Share’ is the title of section 11 in the datasheet. One
register, named <code>IO_PADSHARE_SEL</code>, has one of 7 valid values,
0 through 6, is a global configuration controlling the functions
two-hundred-odd pads <code>PAD_FUNC_SHARE[141:0]</code> and
<code>PAD_GPIO[63:0]</code>. Each of the configurations is called a
‘signal group’, and the groups themselves are called ‘Function 0’
through ‘Function 7’. A giant table then follows, showing each pad’s
function under each signal group.</p>
<p>The pads <code>PAD_GPIO[4:0]</code> would be the connections we found
earlier, and in Function 0, they. Since Function 0 is supposed to be the
default value on reset, this means that we should see a JTAG port there,
right?</p>
<p>At this point, the only thing I could think of is connecting to JTAG
while holding down the reset button. However, since I had neither a JTAG
adapter nor a VisionFive board, all I did was tell luojia about it, and
moved on to finish my finals.</p>
<h2 id="digging-deeper-into-the-gpio-multiplexer">Digging deeper into
the GPIO multiplexer</h2>
<p>The single document that made the system ‘click’ for me is the
devicetree documentation for <code>starfive,jh7100-pinctrl</code>. This
node can be found in <code>jh7100.dtsi</code>, which is included in
<code>jh7100-starfive-visionfive-v1.dts</code>:</p>
<pre class="dts"><code>gpio: pinctrl@11910000 {
    compatible = &quot;starfive,jh7100-pinctrl&quot;;
    reg = &lt;0x0 0x11910000 0x0 0x10000&gt;,
          &lt;0x0 0x11858000 0x0 0x1000&gt;;
    reg-names = &quot;gpio&quot;, &quot;padctl&quot;;
    /* &lt;snip&gt; */
};</code></pre>
<p>The address ranges mentioned here correspond to these rows in the
datasheet:</p>
<pre><code>SYSCTRL-IOPAD_CTRL  0x00_1185_8000  0x00_1185_BFFF  16KB
GPIO                0x00_1191_0000  0x00_1191_FFFF  64KB</code></pre>
<p>These registers control the functions and states of
<code>PAD_GPIO[63:0]</code> and <code>PAD_FUNC_SHARE[141:0]</code>. The
following diagram is included in the devicetree bindings
documentation:</p>
<pre><code>                          Signal group 0, 1, ... or 6
                                 ___|___
                                |       |
    LCD output -----------------|       |
    CMOS Camera interface ------|       |--- PAD_GPIO[0]
    Ethernet PHY interface -----|  MUX  |--- PAD_GPIO[1]
      ...                       |       |      ...
                                |       |--- PAD_GPIO[63]
     -------- GPIO0 ------------|       |
    |  -------|-- GPIO1 --------|       |--- PAD_FUNC_SHARE[0]
    | |       |   |             |       |--- PAD_FUNC_SHARE[1]
    | |       |   |  ...        |       |       ...
    | |       |   |             |       |--- PAD_FUNC_SHARE[141]
    | |  -----|---|-- GPIO63 ---|       |
    | | |     |   |   |          -------
    UART0     UART1 --</code></pre>
<p>These pads on the package, or ‘function IO share with GPIO’ as listed
in the datasheet, are connected to the internal signals through a
<em>two</em>-stage multiplexer:</p>
<p>First, as mentioned, the <code>IO_PADSHARE_SEL</code> register
selects one of 7 ‘signal groups’. This is, curiously, a global setting,
meaning that it affects <em>all</em> of the ‘function share’ pads at
once. A huge table in the datasheet describes the function of each such
pad’s function in each signal group. For example, the row in the table
for <code>PAG_GPIO[0]</code> reads: (Reproduced here vertically for
convenience)</p>
<pre><code>Interface               GPIO
IO Name                 PAD_GPIO[0]
Function 0 (Default)    U74_JTAG_TDO
Function 1              GPIO0
Function 2              X2C_TX_DATA3
Function 3              LCD_DATA4
Function 4              X2C_TX_DATA3
Function 5              PLL_RFSLIP[0]
Function 6              MIPITX_MPOSV[0]</code></pre>
<p>Note that <code>GPIOn</code> has no direct correspondence to
<code>PAD_GPIO[n]</code>. For example, <code>PAD_FUNC_SHARE[0]</code>
can also be connected to <code>GPIO0</code>:</p>
<pre><code>Interface               ChipLink
IO Name                 PAD_FUNC_SHARE[0]
Function 0 (Default)    X2C_TX_CLK
Function 1              LCD_CLK
Function 2              CM_CLK
Function 3              X2C_TX_CLK
Function 4              GPIO0
Function 5              GPIO0
Function 6              GPIO0</code></pre>
<p>Instead, <code>GPIOn</code> are internal signals further multiplexed
into internal inputs and outputs by the ‘GPIO FMUX’. Each of the
<code>GPIOn</code> signals also has configurable pull up/down and
Schmitt triggers, though not all options are available for all I/O
pads.</p>
<p>After that, there are three connections to be made: output, output
enable, and input. These are all configured from the destination side,
so:</p>
<ul>
<li>Each GPIO output and output enable may be connected to either one of
the internal outputs or a constant <code>0</code> or
<code>1</code>.</li>
<li>Each internal input may be connected to one of the GPIO inputs, or a
constant <code>0</code> or <code>1</code>.</li>
</ul>
<p>In addition, the input value from each GPIO may be read from MMIO
registers <code>GPIODIN_0</code> and <code>GPIODIN_1</code>, and it’s
also possible to configure them to fire interrupts.</p>
<p>This allows quite a flexible usage of the GPIO internal signals. They
can be selected to work with the 1.8 V or 3.3 V I/O pads, and can either
be fully controlled by software with interrupt support, or connected to
one of the internal I2C/I2S/SDIO/… controllers.</p>
<p>Curiously, in Function 0, the default mode for
<code>IO_PADSHARE_SEL</code>, <em>none</em> of the GPIOn signals are
connected to the I/O pads. Instead, some of the internal signals are
directly connected to I/O pads. Moreover, in a few of the cases, the
internal signals <code>PAD_GPIO[n]</code> connects to in Function 0 are
conveniently also by default connected to the same-numbered internal
<code>GPIOn</code>. For example, most relevant to our original use
cases, in Function 0 these connections are made:</p>
<pre><code>PAD_GPIO[0]         U74_JTAG_TDO
PAD_GPIO[1]         U74_JTAG_TCK
PAD_GPIO[2]         U74_JTAG_TDI
PAD_GPIO[3]         U74_JTAG_TMS
PAD_GPIO[4]         U74_JTAG_TRSTN</code></pre>
<p>At the same time, the default GPIO FMUX configuration for these JTAG
signals are:</p>
<pre><code>CPU_JTAG_TDO        GPIO0
CPU_JTAG_TCK        GPIO1
CPU_JTAG_TDI        GPIO2
CPU_JTAG_TMS        GPIO3
CPU_JTAG_TRSTN      GPIO4</code></pre>
<p>(It seems that <code>CPU_JTAG_*</code> are synonymous with
<code>U74_JTAG_*</code>.)</p>
<h2 id="finding-the-jtag-port-take-two">Finding the JTAG port, take
two</h2>
<p>It seems that Function 0 is intended for booting and initialization,
with many of the internal functions available on I/O pads right away
without configuration. However given the lack of, well, actual general
purpose input/output, there is no chance Linux runs in Function 0.</p>
<p>We already see our problem: The seven through-holes going to
<code>PAD_GPIO[4:0]</code> are JTAG in Function 0 but might not be when
another ‘Function’ is selected. This means that at some time after
booting, <code>IO_PADSHARE_SEL</code> is set from <code>0</code> to some
other value, and these JTAG-appearing through-holes would no longer be
JTAG.</p>
<p>Which value is it then? Curiously, the example listed in the
devicetree documentation has this property:</p>
<pre><code>starfive,signal-group = &lt;6&gt;;</code></pre>
<p>Which would suggest that Linux selects Function 6 at initialization,
though the actual <code>jh7100.dtsi</code> did not have this property.
The documentation indicates that in case the property is not specified,
the <code>IO_PADSHARE_SEL</code> register is left unchanged:</p>
<div class="sourceCode" id="cb10"><pre
class="sourceCode yaml"><code class="sourceCode yaml"><span id="cb10-1"><a href="#cb10-1" aria-hidden="true" tabindex="-1"></a><span class="fu">starfive,signal-group</span><span class="kw">:</span></span>
<span id="cb10-2"><a href="#cb10-2" aria-hidden="true" tabindex="-1"></a><span class="fu">  description</span><span class="kw">: </span><span class="ch">|</span></span>
<span id="cb10-3"><a href="#cb10-3" aria-hidden="true" tabindex="-1"></a>    Select one of the 7 signal groups. If this property is not set it</span>
<span id="cb10-4"><a href="#cb10-4" aria-hidden="true" tabindex="-1"></a>    defaults to the configuration already chosen by the earlier boot stages.</span>
<span id="cb10-5"><a href="#cb10-5" aria-hidden="true" tabindex="-1"></a><span class="at">  </span><span class="fu">$ref</span><span class="kw">:</span><span class="at"> /schemas/types.yaml</span><span class="co">#/definitions/uint32</span></span>
<span id="cb10-6"><a href="#cb10-6" aria-hidden="true" tabindex="-1"></a><span class="at">  </span><span class="fu">enum</span><span class="kw">:</span><span class="at"> </span><span class="kw">[</span><span class="dv">0</span><span class="kw">,</span><span class="at"> </span><span class="dv">1</span><span class="kw">,</span><span class="at"> </span><span class="dv">2</span><span class="kw">,</span><span class="at"> </span><span class="dv">3</span><span class="kw">,</span><span class="at"> </span><span class="dv">4</span><span class="kw">,</span><span class="at"> </span><span class="dv">5</span><span class="kw">,</span><span class="at"> </span><span class="dv">6</span><span class="kw">]</span></span></code></pre></div>
<p>After a short chat with luojia, who tried connecting to JTAG without
a microSD card unsuccessfully, it is apparent that some earlier boot
stage sets <code>IO_PADSHARE_SEL</code>. It did not take long crawling
through the code provided by StarFive to find <a
href="https://github.com/starfive-tech/JH7100_secondBoot/blob/bootloader-211102_VisionFive_JH7100/boot/bootmain.c#L179">this
particular line in secondBoot</a>:</p>
<div class="sourceCode" id="cb11"><pre class="sourceCode c"><code class="sourceCode c"><span id="cb11-1"><a href="#cb11-1" aria-hidden="true" tabindex="-1"></a>_SET_SYSCON_REG_register104_SCFG_io_padshare_sel<span class="op">(</span><span class="dv">6</span><span class="op">);</span></span></code></pre></div>
<p>For those not familiar with secondBoot, it is one of the first stages
of bootloaders on the VisionFive, second to only the internal ROM.</p>
<figure>
<img src="images/boot-flow.png" alt="VisionFive boot flow" />
<figcaption aria-hidden="true">VisionFive boot flow</figcaption>
</figure>
<p>All of the ‘Firmware’ stages run from an on-board QSPI flash, without
requiring a microSD card present. This means that early on in the boot
sequence, <code>IO_PADSHARE_SEL</code> is switched from <code>0</code>
to <code>6</code>, disabling the JTAG through-holes. Searching through
the other files in this repository also reveals the undocumented address
of <code>IO_PADSHARE_SEL</code>:</p>
<pre><code>0x118581a0</code></pre>
<p>There is still a way to confirm <code>IO_PADSHARE_SEL</code>. If you
hold down the ‘Boot mode’ button while powering the board up, instead of
following the normal boot process, a prompt appears on the ‘debug’
serial console port at 9600 8n1, running off internal ROM, where you can
read and write arbitrary physical memory. At this point, NickCao helped
me out by connecting to this ‘recovery console’, and reading
<code>IO_PADSHARE_SEL</code>:</p>
<pre><code># rh 0x118581a0

 Read Half : 0x0000</code></pre>
<p>Reading the same address in the U-Boot shell gives <code>6</code>,
confirming much of what we had seen.</p>
<h2 id="connecting-to-jtag-for-the-first-time">Connecting to JTAG, for
the first time</h2>
<p>But wait, if <code>IO_PADSHARE_SEL</code> is <code>0</code> when
running in internal ROM, does this mean JTAG <em>is</em> available on
the seven through-holes? Should we be able to connect to the debug
modules in this state?</p>
<p>I asked Icenowy, the only person I know of with both a VisionFive and
some JTAG adapter handy to help out. I told them to power up the board
with ‘Boot mode’ button held down, and <em>then</em> try connecting to
JTAG. They came back with what was, at the time of writing, the first
screenshot of GDB-over-OpenOCD connected to the JH7100, at least from
what I could find on the Internet.</p>
<figure>
<img src="images/gdb-connected.jpg" alt="Connected to GDB, yay!" />
<figcaption aria-hidden="true">Connected to GDB, yay!</figcaption>
</figure>
<p>Among the addresses found in the registers are:</p>
<ul>
<li><code>0x1840084c</code>: Middle of internal ROM</li>
<li><code>0x1800ff80</code>: Middle of intRAM0</li>
<li><code>0x1244000c</code>: One of the UART3 registers</li>
</ul>
<p>Finally, we have JTAG access to the VisionFive.</p>
<h2 id="finding-the-jtag-port-take-three">Finding the JTAG port, take
three</h2>
<p>Even though technically we’re connected to the debug module, running
the SoC entirely in Function 0 isn’t really an option as the board
doesn’t seem to be configured this way. Once we switch to Function 6
though, our connection would be cut off.</p>
<p>Where do the JTAG signals now go go? As mentioned earlier, the JTAG
signals are mapped by default to <code>GPIO0</code> through
<code>GPIO4</code>. Since we’re now in Function 6, these GPIO signals
correspond to I/O pads… (looks at datasheet)
<code>PAD_FUNC_SHARE[4:0]</code>, which are 3.3 V and connected on the
schematic to nets confusingly named <code>GPIO0</code> through
<code>GPIO4</code>.</p>
<figure>
<img src="images/sch-func-share.png"
alt="Nets GPIOn on the schematic" />
<figcaption aria-hidden="true">Nets GPIOn on the schematic</figcaption>
</figure>
<p>These nets are connected to the 40-pin Raspberry Pi compatible header
at pins… Wait what?</p>
<figure>
<img src="images/sch-jtag-pi-connector.png"
alt="Nets GPIOn connected to the Raspberry Pi header" />
<figcaption aria-hidden="true">Nets GPIOn connected to the Raspberry Pi
header</figcaption>
</figure>
<p>For some reason, these pins are labelled on the schematic with JTAG
signal names. On any other documentation, such as <a
href="https://rvspace.org/Product/General/StarFive_40-Pin_GPIO_Header_User_Guide">StarFive’s
GPIO Header Guide</a>, they are only referred to as <code>GPIO0</code>,
etc. and nowhere is JTAG mentioned.</p>
<p>A straightforward test of connecting the JTAG adapter while the
system is up and running showed that these five pins… do not respond to
the JTAG adapter.</p>
<p>Confusingly, Icenowy found out that for a certain period during the
boot process, they <em>could</em> connect through those pins on the
40-pin header. Before this period, JTAG is found on the seven
through-holes, and after that, it just seems to… disappear. Perhaps
somewhere in the boot process another piece of code configured the
second-stage GPIO FMUX and disconnected the JTAG signals. It makes sense
because it frees up five pins on the header for actual GPIO.</p>
<h2 id="finding-the-jtag-port-take-four">Finding the JTAG port, take
four</h2>
<p>Around the same time when I asked NickCao to confirm the value of
<code>IO_PADSHARE_SEL</code> in U-Boot, I also asked them to check the
GPIO FMUX configuration, which showed that JTAG signals are connected
correctly to <code>GPIO0</code> through <code>GPIO4</code>. Therefore,
whatever changed the configuration must have come after. Linux it
is.</p>
<p>As mentioned before, the devicetree node
<code>starfive,jh7100-pinctrl</code> manages both layers of GPIO
multiplexing. The driver itself can be found in
<code>drivers/pinctrl/pinctrl-starfive.c</code>.</p>
<p>Initially, I had assumed that the driver in StarFive’s fork of Linux
was identical to that found in mainline Linux 5.18, though I would soon
be proven wrong. As I was browsing through the dts files hoping to gain
some insight on why the JTAG signals were gone, a section in
<code>jh7100-starfive-visionfive-v1.dts</code> caught my eye.</p>
<pre class="dts"><code>&amp;gpio {
    /* don&#39;t reset gpio mux for serial console and reset gpio */
    starfive,keep-gpiomux = &lt;13 14 63&gt;;
};</code></pre>
<p>There was no mention of <code>starfive,keep-gpiomux</code> in
mainline Linux’s version of <code>pinctrl-starfive</code>, but these two
lines in StarFive’s version seemed relevant.</p>
<div class="sourceCode" id="cb15"><pre class="sourceCode c"><code class="sourceCode c"><span id="cb15-1"><a href="#cb15-1" aria-hidden="true" tabindex="-1"></a><span class="cf">if</span> <span class="op">(!</span>keepmux<span class="op">)</span></span>
<span id="cb15-2"><a href="#cb15-2" aria-hidden="true" tabindex="-1"></a>    starfive_pinmux_reset<span class="op">(</span>sfp<span class="op">);</span></span></code></pre></div>
<p><code>keepmux</code> is a module option defined as:</p>
<div class="sourceCode" id="cb16"><pre class="sourceCode c"><code class="sourceCode c"><span id="cb16-1"><a href="#cb16-1" aria-hidden="true" tabindex="-1"></a><span class="dt">static</span> <span class="dt">bool</span> keepmux<span class="op">;</span></span>
<span id="cb16-2"><a href="#cb16-2" aria-hidden="true" tabindex="-1"></a>module_param<span class="op">(</span>keepmux<span class="op">,</span> <span class="dt">bool</span><span class="op">,</span> <span class="bn">0644</span><span class="op">);</span></span>
<span id="cb16-3"><a href="#cb16-3" aria-hidden="true" tabindex="-1"></a>MODULE_PARM_DESC<span class="op">(</span>keepmux<span class="op">,</span> <span class="st">&quot;Keep pinmux settings from previous boot stage&quot;</span><span class="op">);</span></span></code></pre></div>
<p><code>starfive_pinmux_reset</code> disables the inputs and outputs
associated with every <code>GPIOn</code> signal, unless <code>n</code>
was mentioned in <code>starfive,keep-gpiomux</code>.</p>
<p>The next step was clear: Boot with the kernel command line option
<code>pinctrl-starfive.keepmux=1</code>, or modify
<code>jh7100-starfive-visionfive-v1.dts</code> and add the JTAG signals
to <code>starfive,keep-gpiomux</code>:</p>
<div class="sourceCode" id="cb17"><pre class="sourceCode c"><code class="sourceCode c"><span id="cb17-1"><a href="#cb17-1" aria-hidden="true" tabindex="-1"></a>    starfive<span class="op">,</span>keep<span class="op">-</span>gpiomux <span class="op">=</span> <span class="op">&lt;</span><span class="dv">0</span> <span class="dv">1</span> <span class="dv">2</span> <span class="dv">3</span> <span class="dv">4</span> <span class="dv">13</span> <span class="dv">14</span> <span class="dv">63</span><span class="op">&gt;;</span></span></code></pre></div>
<h2 id="connecting-to-visionfive-with-openocd">Connecting to VisionFive
with OpenOCD</h2>
<p>At this point I borrowed the board from NickCao, and used a Raspberry
Pi as an adapter to connect to it, over the JTAG pins on the 40-pin
connector. Two TAPs can be found on the JTAG port, the first of which
connects to the E24 core, and the second connects to the two U74 cores.
This was my OpenOCD configuration file:</p>
<div class="sourceCode" id="cb18"><pre
class="sourceCode tcl"><code class="sourceCode tcl"><span id="cb18-1"><a href="#cb18-1" aria-hidden="true" tabindex="-1"></a>adapter driver linuxgpiod</span>
<span id="cb18-2"><a href="#cb18-2" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb18-3"><a href="#cb18-3" aria-hidden="true" tabindex="-1"></a>linuxgpiod gpiochip <span class="dv">0</span></span>
<span id="cb18-4"><a href="#cb18-4" aria-hidden="true" tabindex="-1"></a>linuxgpiod jtag_nums <span class="dv">11</span> <span class="dv">25</span> <span class="dv">10</span> <span class="dv">9</span></span>
<span id="cb18-5"><a href="#cb18-5" aria-hidden="true" tabindex="-1"></a>linuxgpiod trst_num <span class="dv">7</span></span>
<span id="cb18-6"><a href="#cb18-6" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb18-7"><a href="#cb18-7" aria-hidden="true" tabindex="-1"></a>reset_config trst_only</span>
<span id="cb18-8"><a href="#cb18-8" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb18-9"><a href="#cb18-9" aria-hidden="true" tabindex="-1"></a>transport <span class="ot">select</span> jtag</span>
<span id="cb18-10"><a href="#cb18-10" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb18-11"><a href="#cb18-11" aria-hidden="true" tabindex="-1"></a>jtag newtap e24 cpu -irlen <span class="dv">5</span> -expected-id <span class="dv">0x200005fd</span></span>
<span id="cb18-12"><a href="#cb18-12" aria-hidden="true" tabindex="-1"></a>jtag newtap u74 cpu -irlen <span class="dv">5</span> -expected-id <span class="dv">0x200003fd</span></span>
<span id="cb18-13"><a href="#cb18-13" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb18-14"><a href="#cb18-14" aria-hidden="true" tabindex="-1"></a>target <span class="ot">create</span> e24.cpu0 riscv -chain-position e24.cpu -coreid <span class="dv">0</span></span>
<span id="cb18-15"><a href="#cb18-15" aria-hidden="true" tabindex="-1"></a>target <span class="ot">create</span> u74.cpu0 riscv -chain-position u74.cpu -coreid <span class="dv">0</span> -rtos hwthread</span>
<span id="cb18-16"><a href="#cb18-16" aria-hidden="true" tabindex="-1"></a>target <span class="ot">create</span> u74.cpu1 riscv -chain-position u74.cpu -coreid <span class="dv">1</span></span>
<span id="cb18-17"><a href="#cb18-17" aria-hidden="true" tabindex="-1"></a>target smp u74.cpu0 u74.cpu1</span>
<span id="cb18-18"><a href="#cb18-18" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb18-19"><a href="#cb18-19" aria-hidden="true" tabindex="-1"></a>init</span></code></pre></div>
<p>Before Linux boots, I was able to connect to all of these cores, and
read some information off of them. For example, reading CSRs from the
U74 cores:</p>
<figure>
<img src="images/gdb-read-csr.png" alt="Reading some CSRs over GDB" />
<figcaption aria-hidden="true">Reading some CSRs over GDB</figcaption>
</figure>
<p>As expected, this is a SiFive (<code>mvendorid = 0x489</code>)
7-series (<code>marchid = (1 &lt;&lt; 63) | 7</code>) core, version
19.05 (<code>mimpid = 0x20190531</code>). Seen from the ISA implemented,
namely <code>RV64GC</code> with Supervisor/User, this was certainly a
U74 core.</p>
<p>After Linux starts, however, the E24 core seems to start misbehaving.
OpenOCD starts generating error messages like:</p>
<pre><code>Warn : target e24.cpu0 examination failed
Error: [e24.cpu0] DMI operation didn&#39;t complete in 2 seconds. The target is either really slow or broken. You could increase the timeout with riscv set_command_timeout_sec.</code></pre>
<p>It seems that the E24 core had been disconnected or disabled. In any
case, it was not responding. OpenOCD was confused by this lack of
response and debugging on the U74 was also affected:</p>
<figure>
<img src="images/gdb-errors.png"
alt="GDB errors due to E24 not responding" />
<figcaption aria-hidden="true">GDB errors due to E24 not
responding</figcaption>
</figure>
<p>Commenting out the <code>e24.cpu0</code> line in the config would
ignore the E24 core and work around this issue.</p>
<div class="sourceCode" id="cb20"><pre
class="sourceCode tcl"><code class="sourceCode tcl"><span id="cb20-1"><a href="#cb20-1" aria-hidden="true" tabindex="-1"></a><span class="co"># target create e24.cpu0 riscv -chain-position e24.cpu -coreid 0</span></span></code></pre></div>
<p>What is going on with the E24 core? Seeing that the main star of the
show, the dual U74 cores, have already been ‘conquered’, it’s probably
an appropriate time to take a break. This article has already been
filled with too many details, so we will look at the E24
‘microcontroller’ core next time, as a side quest, in a future post.</p>
<p>(By the way: It seems that beta/sample versions of the now cancelled
BeagleV Starlight board has a very similar JTAG configuration. If anyone
still has one of these boards, it would be extremely interesting to try
it out.)</p>
<p><em>To be continued…</em></p>
<h2 id="references">References</h2>
<ul>
<li>JH7100 documentation: <a
href="https://github.com/starfive-tech/JH7100_Docs"
class="uri">https://github.com/starfive-tech/JH7100_Docs</a></li>
<li>VisionFive schematics: <a
href="https://github.com/starfive-tech/VisionFive"
class="uri">https://github.com/starfive-tech/VisionFive</a></li>
<li>JH7100 ‘secondBoot’ bootloader: <a
href="https://github.com/starfive-tech/JH7100_secondBoot"
class="uri">https://github.com/starfive-tech/JH7100_secondBoot</a></li>
<li>SiFive U74 Core Complex Manual: <a
href="https://sifive.cdn.prismic.io/sifive/ad5577a0-9a00-45c9-a5d0-424a3d586060_u74_core_complex_manual_21G3.pdf"
class="uri">https://sifive.cdn.prismic.io/sifive/ad5577a0-9a00-45c9-a5d0-424a3d586060_u74_core_complex_manual_21G3.pdf</a></li>
<li>Files found in VisionFive Linux source code, provided by StarFive:
<ul>
<li><a
href="https://github.com/starfive-tech/linux/blob/visionfive/include/dt-bindings/pinctrl/pinctrl-starfive.h"><code>include/dt-bindings/pinctrl/pinctrl-starfive.h</code></a></li>
<li><a
href="https://github.com/starfive-tech/linux/blob/visionfive/drivers/pinctrl/pinctrl-starfive.c"><code>drivers/pinctrl/pinctrl-starfive.c</code></a></li>
<li><a
href="https://github.com/starfive-tech/linux/blob/visionfive/Documentation/devicetree/bindings/pinctrl/starfive%2Cjh7100-pinctrl.yaml"><code>Documentation/devicetree/bindings/pinctrl/starfive,jh7100-pinctrl.yaml</code></a></li>
<li><a
href="https://github.com/starfive-tech/linux/blob/visionfive/arch/riscv/boot/dts/starfive/jh7100.dtsi"><code>arch/riscv/boot/dts/starfive/jh7100.dtsi</code></a></li>
<li><a
href="https://github.com/starfive-tech/linux/blob/visionfive/arch/riscv/boot/dts/starfive/jh7100-starfive-visionfive-v1.dts"><code>arch/riscv/boot/dts/starfive/jh7100-starfive-visionfive-v1.dts</code></a></li>
</ul></li>
</ul>
<p>I made a post to StarFive’s RVSpace forum with a how-to of connecting
to VisionFive’s JTAG port, hoping it would help those looking to do
low-level work on the board: <a
href="https://forum.rvspace.org/t/connecting-to-visionfive-s-jtag-port-a-short-guide/514"
class="uri">https://forum.rvspace.org/t/connecting-to-visionfive-s-jtag-port-a-short-guide/514</a>.</p>
<h2 id="acknowledgements">Acknowledgements</h2>
<p>I would like to thank these people for helping out during the
research:</p>
<ul>
<li>NickCao (GitHub: <a href="https://github.com/NickCao"><span
class="citation" data-cites="NickCao">@NickCao</span></a>)</li>
<li>luojia (GitHub: <a href="https://github.com/luojia65"><span
class="citation" data-cites="luojia65">@luojia65</span></a>)</li>
<li>Icenowy (GitHub: <a href="https://github.com/Icenowy"><span
class="citation" data-cites="Icenowy">@Icenowy</span></a>)</li>
</ul>]]></description>
    </item>
    <item>
        <title>Magic tricks with CRC</title>
        <pubDate>Sat, 25 Dec 2021 00:00:00 +0000</pubDate>
        <guid isPermaLink="true">https://dram.page/p/crc-tricks</guid>
        <description><![CDATA[<h2 id="an-adjustable-desk">An adjustable
desk</h2>
<p>A friend of mine bought a motorized adjustable desk a long time ago
and recently got the idea to hook up the controller to the Internet for
some reason. They tapped the wire coming from the controls panel with a
logic analyzer and was able to capture some packets, hexdumps shown:</p>
<pre><code>AAFF 0040 2EEC
AAFF 0060 2964
AAFF 0050 2B08
AAFF 040E02 0450
AAFF 050E02 8EDA
AAFF 060E02 1D05
AAFF 070E02 978F
... (and many more samples)</code></pre>
<p>They were reasonably sure that the framing was correctly decoded,
meaning that each line of hexdump is exactly one complete transmission.
The message format of two bytes of (seemingly fixed) header, variable
number of bytes of message, and two bytes of checksum resembles <a
href="https://modbus.org/">Modbus</a> RTU.</p>
<p>An implementation of the Modbus CRC-16, however, gives check
sequences that don’t match up with what we see. It’s still suspiciously
like some sort of CRC-16 though, so I decided to go though with the
assumption that it is a CRC-16 variant waiting to be discovered.</p>
<h2 id="but-what-is-a-crc-anyway">But what is a CRC anyway?</h2>
<p>The <a
href="https://en.wikipedia.org/wiki/Cyclic_redundancy_check"><em>cyclic
redundancy check</em> (CRC)</a> is a family of error-checking codes that
is widely used to detect inadvertent data corruption of data during
transmission or in storage. The most common way a CRC is implemented is
using a <em>linear feedback shift register</em> (LFSR), and the
mathematical structure of it is taking the remainder of a polynomial
division, where the polynomial is defined in
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mrow><mi mathvariant="normal">G</mi><mi mathvariant="normal">F</mi></mrow><mo stretchy="false" form="prefix">(</mo><mn>2</mn><mo stretchy="false" form="postfix">)</mo></mrow><annotation encoding="application/x-tex">\mathrm{GF}(2)</annotation></semantics></math>.</p>
<p>Let’s go into details of how CRCs work in practice, in particular how
the details of the algorithms maps to polynomials, and how we can
manipulate CRCs using its properties, along with how I applied the ideas
while reverse engineering the exact parameters used for my friend’s
desk.</p>
<h2 id="mathematical-basics">Mathematical basics</h2>
<p>Just for a warm up, let’s go into some basics of how polynomials
work. These things are immensely useful in various fields of computer
science because they provide an interesting way to work with bit
strings, so it can’t hurt to take a closer look.</p>
<h3 id="the-galois-field-mathrmgf2">The Galois field
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mrow><mi mathvariant="normal">G</mi><mi mathvariant="normal">F</mi></mrow><mo stretchy="false" form="prefix">(</mo><mn>2</mn><mo stretchy="false" form="postfix">)</mo></mrow><annotation encoding="application/x-tex">\mathrm{GF}(2)</annotation></semantics></math></h3>
<p><math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>G</mi><mi>F</mi><mo stretchy="false" form="prefix">(</mo><mn>2</mn><mo stretchy="false" form="postfix">)</mo></mrow><annotation encoding="application/x-tex">GF(2)</annotation></semantics></math>
might have a scary name, but it really is just the integers modulo
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mn>2</mn><annotation encoding="application/x-tex">2</annotation></semantics></math>.
This field only has two elements,
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mn>0</mn><annotation encoding="application/x-tex">0</annotation></semantics></math>
and
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mn>1</mn><annotation encoding="application/x-tex">1</annotation></semantics></math>.
Thinking of them as logical bits, addition is exclusive-or (xor), and
multiplication is logical ‘and’. Anything added with itself is gone, and
subtraction is the same as addition:</p>
<ul>
<li><math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>a</mi><mo>+</mo><mi>a</mi><mo>=</mo><mn>0</mn></mrow><annotation encoding="application/x-tex">a + a = 0</annotation></semantics></math></li>
<li><math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>a</mi><mo>+</mo><mi>b</mi><mo>=</mo><mi>a</mi><mo>−</mo><mi>b</mi></mrow><annotation encoding="application/x-tex">a + b = a - b</annotation></semantics></math></li>
</ul>
<p>Polynomials in
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mrow><mi mathvariant="normal">G</mi><mi mathvariant="normal">F</mi></mrow><mo stretchy="false" form="prefix">(</mo><mn>2</mn><mo stretchy="false" form="postfix">)</mo></mrow><annotation encoding="application/x-tex">\mathrm{GF}(2)</annotation></semantics></math>,
in particular univariate polynomials in
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mi>x</mi><annotation encoding="application/x-tex">x</annotation></semantics></math>,
called
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mrow><mi mathvariant="normal">G</mi><mi mathvariant="normal">F</mi></mrow><mo stretchy="false" form="prefix">(</mo><mn>2</mn><mo stretchy="false" form="postfix">)</mo><mo stretchy="false" form="prefix">[</mo><mi>x</mi><mo stretchy="false" form="postfix">]</mo></mrow><annotation encoding="application/x-tex">\mathrm{GF}(2)[x]</annotation></semantics></math>,
is what we’re interested in here. In particular, since the coefficients
of the terms are either
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mn>0</mn><annotation encoding="application/x-tex">0</annotation></semantics></math>
or
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mn>1</mn><annotation encoding="application/x-tex">1</annotation></semantics></math>,
we can write them as if each term just exists or doesn’t exist,
like:</p>
<p><math display="block" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msup><mi>x</mi><mn>16</mn></msup><mo>+</mo><msup><mi>x</mi><mn>3</mn></msup><mo>+</mo><msup><mi>x</mi><mn>1</mn></msup><mo>+</mo><msup><mi>x</mi><mn>0</mn></msup></mrow><annotation encoding="application/x-tex"> x^{16} + x^{3} + x^{1} + x^{0} </annotation></semantics></math></p>
<p>(Side note: Polynomials are <em>not</em> polynomial functions. There
are only
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mn>4</mn><annotation encoding="application/x-tex">4</annotation></semantics></math>
functions of
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mrow><mi mathvariant="normal">G</mi><mi mathvariant="normal">F</mi></mrow><mo stretchy="false" form="prefix">(</mo><mn>2</mn><mo stretchy="false" form="postfix">)</mo><mo>→</mo><mrow><mi mathvariant="normal">G</mi><mi mathvariant="normal">F</mi></mrow><mo stretchy="false" form="prefix">(</mo><mn>2</mn><mo stretchy="false" form="postfix">)</mo></mrow><annotation encoding="application/x-tex">\mathrm{GF}(2) \to \mathrm{GF}(2)</annotation></semantics></math>,
but if the term coefficients of two polynomials differ they are not the
same polynomial, regardless of whether they correspond to the same
function.)</p>
<p>We can the coefficients of a polynomial into a bit string, highest
power term first, omitting (the infinite sequence of) leading zeros. For
example, the above example corresponds to:</p>
<pre><code>1 0000 0000 0000 1011</code></pre>
<p>We can then read that as an (unsigned) integer in binary, which is a
convenient representation of
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mrow><mi mathvariant="normal">G</mi><mi mathvariant="normal">F</mi></mrow><mo stretchy="false" form="prefix">(</mo><mn>2</mn><mo stretchy="false" form="postfix">)</mo><mo stretchy="false" form="prefix">[</mo><mi>x</mi><mo stretchy="false" form="postfix">]</mo></mrow><annotation encoding="application/x-tex">\mathrm{GF}(2)[x]</annotation></semantics></math>
polynomials in computers.</p>
<h3 id="polynomial-addition-and-multiplication">Polynomial addition and
multiplication</h3>
<p>Addition and multiplications work exactly as we expect, if you take
care that the coefficients should be calculated modulo 2. As we all
know,
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mn>2</mn><mo>=</mo><mn>0</mn></mrow><annotation encoding="application/x-tex">2 = 0</annotation></semantics></math>,
so each term will cancel with itself:</p>
<p><math display="block" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msup><mi>x</mi><mi>n</mi></msup><mo>+</mo><msup><mi>x</mi><mi>n</mi></msup><mo>=</mo><msup><mi>x</mi><mi>n</mi></msup><mo>−</mo><msup><mi>x</mi><mi>n</mi></msup><mo>=</mo><mn>0</mn></mrow><annotation encoding="application/x-tex"> x^{n} + x^{n} = x^{n} - x^{n} = 0 </annotation></semantics></math></p>
<p>So for example:</p>
<p><math display="block" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mo stretchy="false" form="prefix">(</mo><msup><mi>x</mi><mn>4</mn></msup><mo>+</mo><msup><mi>x</mi><mn>2</mn></msup><mo stretchy="false" form="postfix">)</mo><mo>+</mo><mo stretchy="false" form="prefix">(</mo><msup><mi>x</mi><mn>2</mn></msup><mo>+</mo><msup><mi>x</mi><mn>0</mn></msup><mo stretchy="false" form="postfix">)</mo><mo>=</mo><msup><mi>x</mi><mn>4</mn></msup><mo>+</mo><mn>2</mn><msup><mi>x</mi><mn>2</mn></msup><mo>+</mo><msup><mi>x</mi><mn>0</mn></msup><mo>=</mo><msup><mi>x</mi><mn>4</mn></msup><mo>+</mo><msup><mi>x</mi><mn>0</mn></msup></mrow><annotation encoding="application/x-tex"> (x^{4} + x^{2}) + (x^{2} + x^{0}) = x^{4} + 2 x^{2} + x^{0} = x^{4} + x^{0}</annotation></semantics></math></p>
<p>Addition and multiplication have the commutativity, associativity and
distributivity properties we all know and love.</p>
<p>Using the representation of polynomials as unsigned integers,
polynomial addition is just bitwise-xor. Meanwhile, multiplication is
known as ‘carry-less multiplication’, which is often available as
dedicated instructions in modern CPUs for cryptographic
applications.</p>
<h3 id="polynomial-euclidean-division">Polynomial (Euclidean)
division</h3>
<p>What we’re concerned here most, when working with CRCs, is polynomial
division. It is defined analogously to integer division with remainder,
except instead of comparing the magnitude of numbers, we compare the
<em>degree</em> of polynomials.</p>
<p>Given two polynomials
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>a</mi><mo stretchy="false" form="prefix">(</mo><mi>x</mi><mo stretchy="false" form="postfix">)</mo></mrow><annotation encoding="application/x-tex">a(x)</annotation></semantics></math>
and
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>b</mi><mo stretchy="false" form="prefix">(</mo><mi>x</mi><mo stretchy="false" form="postfix">)</mo></mrow><annotation encoding="application/x-tex">b(x)</annotation></semantics></math>
(where
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>b</mi><mo stretchy="false" form="prefix">(</mo><mi>x</mi><mo stretchy="false" form="postfix">)</mo><mo>≠</mo><mn>0</mn></mrow><annotation encoding="application/x-tex">b(x) \ne 0</annotation></semantics></math>),
there is only one <em>quotient</em>
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>q</mi><mo stretchy="false" form="prefix">(</mo><mi>x</mi><mo stretchy="false" form="postfix">)</mo></mrow><annotation encoding="application/x-tex">q(x)</annotation></semantics></math>
and <em>remainder</em>
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>r</mi><mo stretchy="false" form="prefix">(</mo><mi>x</mi><mo stretchy="false" form="postfix">)</mo></mrow><annotation encoding="application/x-tex">r(x)</annotation></semantics></math>
such that
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>r</mi><mo stretchy="false" form="prefix">(</mo><mi>x</mi><mo stretchy="false" form="postfix">)</mo></mrow><annotation encoding="application/x-tex">r(x)</annotation></semantics></math>
has strictly smaller degree than
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>b</mi><mo stretchy="false" form="prefix">(</mo><mi>x</mi><mo stretchy="false" form="postfix">)</mo></mrow><annotation encoding="application/x-tex">b(x)</annotation></semantics></math>,
and:</p>
<p><math display="block" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>a</mi><mo stretchy="false" form="prefix">(</mo><mi>x</mi><mo stretchy="false" form="postfix">)</mo><mo>=</mo><mi>b</mi><mo stretchy="false" form="prefix">(</mo><mi>x</mi><mo stretchy="false" form="postfix">)</mo><mi>q</mi><mo stretchy="false" form="prefix">(</mo><mi>x</mi><mo stretchy="false" form="postfix">)</mo><mo>+</mo><mi>r</mi><mo stretchy="false" form="prefix">(</mo><mi>x</mi><mo stretchy="false" form="postfix">)</mo></mrow><annotation encoding="application/x-tex"> a(x) = b(x) q(x) + r(x) </annotation></semantics></math></p>
<p>The algorithm to figure out
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>q</mi><mo stretchy="false" form="prefix">(</mo><mi>x</mi><mo stretchy="false" form="postfix">)</mo></mrow><annotation encoding="application/x-tex">q(x)</annotation></semantics></math>
and
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>r</mi><mo stretchy="false" form="prefix">(</mo><mi>x</mi><mo stretchy="false" form="postfix">)</mo></mrow><annotation encoding="application/x-tex">r(x)</annotation></semantics></math>
is a variation on the integer long division algorithm. In particular, we
don’t usually care about
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>q</mi><mo stretchy="false" form="prefix">(</mo><mi>x</mi><mo stretchy="false" form="postfix">)</mo></mrow><annotation encoding="application/x-tex">q(x)</annotation></semantics></math>,
so it is fairly easy to ‘reduce’
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>a</mi><mo stretchy="false" form="prefix">(</mo><mi>x</mi><mo stretchy="false" form="postfix">)</mo></mrow><annotation encoding="application/x-tex">a(x)</annotation></semantics></math>
with multiples of
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>b</mi><mo stretchy="false" form="prefix">(</mo><mi>x</mi><mo stretchy="false" form="postfix">)</mo></mrow><annotation encoding="application/x-tex">b(x)</annotation></semantics></math>
until the degree is strictly less than
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>b</mi><mo stretchy="false" form="prefix">(</mo><mi>x</mi><mo stretchy="false" form="postfix">)</mo></mrow><annotation encoding="application/x-tex">b(x)</annotation></semantics></math>.
Moreover, since the only possible non-zero coefficient is
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mn>1</mn><annotation encoding="application/x-tex">1</annotation></semantics></math>,
we don’t even need a division to figure out the scalar to multiply
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>b</mi><mo stretchy="false" form="prefix">(</mo><mi>x</mi><mo stretchy="false" form="postfix">)</mo><msup><mi>x</mi><mi>k</mi></msup></mrow><annotation encoding="application/x-tex">b(x) x^k</annotation></semantics></math>
by.</p>
<pre><code>a = <em>(polynomial dividend)</em>
b = <em>(polynomial divisor)</em>

<b>while</b> (degree of a) >= (degree of b):
    a = a + b x^((degree of a) - (degree of b))

<b>return</b> a</code></pre>
<p>In Python for example, the <code>int.bit_length</code> method returns
the length of an integer in binary representation, excluding leading
zeros. It is one more than the polynomial’s degree, which is not
important in our case:</p>
<div class="sourceCode" id="cb3"><pre
class="sourceCode python"><code class="sourceCode python"><span id="cb3-1"><a href="#cb3-1" aria-hidden="true" tabindex="-1"></a><span class="kw">def</span> poly_mod(a, b):</span>
<span id="cb3-2"><a href="#cb3-2" aria-hidden="true" tabindex="-1"></a>    <span class="cf">while</span> a.bit_length() <span class="op">&gt;=</span> b.bit_length():</span>
<span id="cb3-3"><a href="#cb3-3" aria-hidden="true" tabindex="-1"></a>        a <span class="op">^=</span> b <span class="op">&lt;&lt;</span> (a.bit_length() <span class="op">-</span> b.bit_length())</span>
<span id="cb3-4"><a href="#cb3-4" aria-hidden="true" tabindex="-1"></a>    <span class="cf">return</span> a</span></code></pre></div>
<p>For convenience we can use
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>a</mi><mo stretchy="false" form="prefix">(</mo><mi>x</mi><mo stretchy="false" form="postfix">)</mo><mrow><mspace width="0.222em"></mspace><mrow><mi>mod</mi><mo>&#8289;</mo></mrow><mspace width="0.222em"></mspace><mi>b</mi></mrow><mo stretchy="false" form="prefix">(</mo><mi>x</mi><mo stretchy="false" form="postfix">)</mo></mrow><annotation encoding="application/x-tex">a(x) \bmod b(x)</annotation></semantics></math>
to refer to
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>r</mi><mo stretchy="false" form="prefix">(</mo><mi>x</mi><mo stretchy="false" form="postfix">)</mo></mrow><annotation encoding="application/x-tex">r(x)</annotation></semantics></math>.</p>
<p>One notable thing is that adding two polynomials together doesn’t
increase the degree, so:</p>
<p><math display="block" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mo stretchy="false" form="prefix">(</mo><mi>u</mi><mo>+</mo><mi>v</mi><mo stretchy="false" form="postfix">)</mo><mrow><mspace width="0.222em"></mspace><mrow><mi>mod</mi><mo>&#8289;</mo></mrow><mspace width="0.222em"></mspace><mi>b</mi></mrow><mo>=</mo><mo stretchy="false" form="prefix">(</mo><mi>u</mi><mrow><mspace width="0.222em"></mspace><mrow><mi>mod</mi><mo>&#8289;</mo></mrow><mspace width="0.222em"></mspace><mi>b</mi></mrow><mo stretchy="false" form="postfix">)</mo><mo>+</mo><mo stretchy="false" form="prefix">(</mo><mi>v</mi><mrow><mspace width="0.222em"></mspace><mrow><mi>mod</mi><mo>&#8289;</mo></mrow><mspace width="0.222em"></mspace><mi>b</mi></mrow><mo stretchy="false" form="postfix">)</mo></mrow><annotation encoding="application/x-tex"> (u + v) \bmod b = (u \bmod b) + (v \bmod b) </annotation></semantics></math></p>
<h2 id="cyclic-redundancy-checks">Cyclic redundancy checks</h2>
<h3 id="basic-crcs">Basic CRCs</h3>
<p>For a message consisting of bytes, we can also convert it to a bit
string, by putting each byte in order, and for each byte, put the
<em>least significant</em> bit first. So <code>f0 30</code> becomes
<code>0000 1111 0000 1100</code>.</p>
<p>For simplicity, consider this CRC generation code, with a single
parameter <code>tap</code>:</p>
<pre><code>crc = 0

<b>for each</b> bit b in message:
    crc = crc ^ b
    <b>if</b> least significant bit of crc is 1:
        crc = (crc >> 1) ^ <em>tap</em>
    <b>else</b>:
        crc = crc >> 1

<b>return</b> crc</code></pre>
<p>This structure is called a linear feedback shift register, or LFSR.
We can try to reverse engineer this in terms of polynomials in
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mrow><mi mathvariant="normal">G</mi><mi mathvariant="normal">F</mi></mrow><mo stretchy="false" form="prefix">(</mo><mn>2</mn><mo stretchy="false" form="postfix">)</mo></mrow><annotation encoding="application/x-tex">\mathrm{GF}(2)</annotation></semantics></math>.</p>
<p>As the message is read in bit by bit, we can say that the ‘current
polynomial’ starts at
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mn>0</mn><annotation encoding="application/x-tex">0</annotation></semantics></math>,
and for each bit
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mi>b</mi><annotation encoding="application/x-tex">b</annotation></semantics></math>
we read, we update the polynomial from
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mi>m</mi><annotation encoding="application/x-tex">m</annotation></semantics></math>
to
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>m</mi><mi>x</mi><mo>+</mo><mi>b</mi></mrow><annotation encoding="application/x-tex">mx + b</annotation></semantics></math>.
This continues until the message is completely read, and
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mi>m</mi><annotation encoding="application/x-tex">m</annotation></semantics></math>
is the polynomial corresponding to the entire message.</p>
<p>Since the <code>crc</code> ‘register’ is constantly being shifted to
the <em>right</em>, it actually contains a ‘bit reversed’ polynomial.
The least significant bit is actually the highest power term. So
similarly, if <code>tap</code> were some polynomial, it should also be
bit reversed. For convenience, say <code>crc</code> and <code>tap</code>
are
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mi>N</mi><annotation encoding="application/x-tex">N</annotation></semantics></math>-bit
integers.</p>
<p>The ‘bit reversed’ part is not weird anymore if we write the integer
<code>crc</code> as an
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mi>N</mi><annotation encoding="application/x-tex">N</annotation></semantics></math>
bit integer in little endian as a bit string and find the corresponding
polynomial. It <em>is</em> the correct polynomial we’re looking for.</p>
<p>We can start interpreting the bit operations taken:</p>
<ul>
<li>For each bit
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mi>b</mi><annotation encoding="application/x-tex">b</annotation></semantics></math>
in message:
<ul>
<li><math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mrow><mi>𝚌</mi><mi>𝚛</mi><mi>𝚌</mi></mrow><mo>←</mo><mrow><mi>𝚌</mi><mi>𝚛</mi><mi>𝚌</mi></mrow><mo>+</mo><mi>b</mi><msup><mi>x</mi><mrow><mi>N</mi><mo>−</mo><mn>1</mn></mrow></msup></mrow><annotation encoding="application/x-tex">\mathtt{crc} \leftarrow \mathtt{crc} + b x^{N - 1}</annotation></semantics></math></li>
<li>If the
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><msup><mi>x</mi><mrow><mi>N</mi><mo>−</mo><mn>1</mn></mrow></msup><annotation encoding="application/x-tex">x^{N - 1}</annotation></semantics></math>
coefficient of
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>𝚌</mi><mi>𝚛</mi><mi>𝚌</mi></mrow><annotation encoding="application/x-tex">\mathtt{crc}</annotation></semantics></math>
is
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mn>1</mn><annotation encoding="application/x-tex">1</annotation></semantics></math>,
then
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mrow><mi>𝚌</mi><mi>𝚛</mi><mi>𝚌</mi></mrow><mo>←</mo><mrow><mi>𝚌</mi><mi>𝚛</mi><mi>𝚌</mi></mrow><mo>⋅</mo><mi>x</mi><mo>+</mo><msup><mi>x</mi><mi>N</mi></msup><mo>+</mo><mrow><mi>𝚝</mi><mi>𝚊</mi><mi>𝚙</mi></mrow></mrow><annotation encoding="application/x-tex">\mathtt{crc} \leftarrow \mathtt{crc} \cdot x + x^N + \mathtt{tap}</annotation></semantics></math></li>
<li>Else:
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mrow><mi>𝚌</mi><mi>𝚛</mi><mi>𝚌</mi></mrow><mo>←</mo><mrow><mi>𝚌</mi><mi>𝚛</mi><mi>𝚌</mi></mrow><mo>⋅</mo><mi>x</mi></mrow><annotation encoding="application/x-tex">\mathtt{crc} \leftarrow \mathtt{crc} \cdot x</annotation></semantics></math></li>
</ul></li>
</ul>
<p>Noting that for the operation <code>crc &gt;&gt; 1</code>, it
<em>discards</em> the least significant bit if it’s zero. So in terms of
polynomials, this means that a
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><msup><mi>x</mi><mi>N</mi></msup><annotation encoding="application/x-tex">x^N</annotation></semantics></math>
term cannot occur in
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>𝚌</mi><mi>𝚛</mi><mi>𝚌</mi></mrow><annotation encoding="application/x-tex">\mathtt{crc}</annotation></semantics></math>
and would be discarded. That’s what adding (or really, subtracting)
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><msup><mi>x</mi><mi>n</mi></msup><annotation encoding="application/x-tex">x^n</annotation></semantics></math>
means.</p>
<p>A bit of distributing gives:</p>
<ul>
<li>For each bit
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mi>b</mi><annotation encoding="application/x-tex">b</annotation></semantics></math>
in message:
<ul>
<li><math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mrow><mi>𝚌</mi><mi>𝚛</mi><mi>𝚌</mi></mrow><mo>←</mo><mrow><mi>𝚌</mi><mi>𝚛</mi><mi>𝚌</mi></mrow><mo>⋅</mo><mi>x</mi><mo>+</mo><mi>b</mi><msup><mi>x</mi><mi>N</mi></msup></mrow><annotation encoding="application/x-tex">\mathtt{crc} \leftarrow \mathtt{crc} \cdot x + b x^N</annotation></semantics></math></li>
<li>If the
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><msup><mi>x</mi><mi>N</mi></msup><annotation encoding="application/x-tex">x^N</annotation></semantics></math>
coefficient of
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>𝚌</mi><mi>𝚛</mi><mi>𝚌</mi></mrow><annotation encoding="application/x-tex">\mathtt{crc}</annotation></semantics></math>
is
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mn>1</mn><annotation encoding="application/x-tex">1</annotation></semantics></math>,
then
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mrow><mi>𝚌</mi><mi>𝚛</mi><mi>𝚌</mi></mrow><mo>←</mo><mrow><mi>𝚌</mi><mi>𝚛</mi><mi>𝚌</mi></mrow><mo>+</mo><msup><mi>x</mi><mi>N</mi></msup><mo>+</mo><mrow><mi>𝚝</mi><mi>𝚊</mi><mi>𝚙</mi></mrow></mrow><annotation encoding="application/x-tex">\mathtt{crc} \leftarrow \mathtt{crc} + x^N + \mathtt{tap}</annotation></semantics></math></li>
</ul></li>
</ul>
<p>Each time a
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mi>b</mi><annotation encoding="application/x-tex">b</annotation></semantics></math>
term is shifted into
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mi>m</mi><annotation encoding="application/x-tex">m</annotation></semantics></math>,
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mi>m</mi><annotation encoding="application/x-tex">m</annotation></semantics></math>
turns into
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>m</mi><mi>x</mi><mo>+</mo><mi>b</mi></mrow><annotation encoding="application/x-tex">mx + b</annotation></semantics></math>,
and,
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>𝚌</mi><mi>𝚛</mi><mi>𝚌</mi></mrow><annotation encoding="application/x-tex">\mathtt{crc}</annotation></semantics></math>
is turned into
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mrow><mi>𝚌</mi><mi>𝚛</mi><mi>𝚌</mi></mrow><mo>⋅</mo><mi>x</mi><mo>+</mo><mi>b</mi><msup><mi>x</mi><mi>N</mi></msup></mrow><annotation encoding="application/x-tex">\mathtt{crc} \cdot x + b x^N</annotation></semantics></math>.
If we don’t bother with the ‘if’ step, then after reading everything
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mrow><mi>𝚌</mi><mi>𝚛</mi><mi>𝚌</mi></mrow><mo>=</mo><mi>m</mi><msup><mi>x</mi><mi>N</mi></msup></mrow><annotation encoding="application/x-tex">\mathtt{crc} = m x^N</annotation></semantics></math>.</p>
<p>But after reading each bit,
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msup><mi>x</mi><mi>N</mi></msup><mo>+</mo><mrow><mi>𝚝</mi><mi>𝚊</mi><mi>𝚙</mi></mrow></mrow><annotation encoding="application/x-tex">x^N + \mathtt{tap}</annotation></semantics></math>
is either added or not. This means
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>𝚌</mi><mi>𝚛</mi><mi>𝚌</mi></mrow><annotation encoding="application/x-tex">\mathtt{crc}</annotation></semantics></math>
and
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>m</mi><msup><mi>x</mi><mi>N</mi></msup></mrow><annotation encoding="application/x-tex">m x^N</annotation></semantics></math>
are actually only equal modulo
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msup><mi>x</mi><mi>N</mi></msup><mo>+</mo><mrow><mi>𝚝</mi><mi>𝚊</mi><mi>𝚙</mi></mrow></mrow><annotation encoding="application/x-tex">x^N +
\mathtt{tap}</annotation></semantics></math>. Also notice that
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>𝚌</mi><mi>𝚛</mi><mi>𝚌</mi></mrow><annotation encoding="application/x-tex">\mathtt{crc}</annotation></semantics></math>
has degree strictly smaller than
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mi>N</mi><annotation encoding="application/x-tex">N</annotation></semantics></math>.
Therefore:</p>
<p><math display="block" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mrow><mi>𝚌</mi><mi>𝚛</mi><mi>𝚌</mi></mrow><mo>=</mo><mo stretchy="false" form="prefix">(</mo><mi>m</mi><msup><mi>x</mi><mi>N</mi></msup><mo stretchy="false" form="postfix">)</mo><mrow><mspace width="0.222em"></mspace><mrow><mi>mod</mi><mo>&#8289;</mo></mrow><mspace width="0.222em"></mspace><mo stretchy="false" form="prefix">(</mo></mrow><mrow><mi>𝚝</mi><mi>𝚊</mi><mi>𝚙</mi></mrow><mo>+</mo><msup><mi>x</mi><mi>N</mi></msup><mo stretchy="false" form="postfix">)</mo></mrow><annotation encoding="application/x-tex"> \mathtt{crc} = (m x^N) \bmod (\mathtt{tap} + x^N) </annotation></semantics></math></p>
<h3 id="realistic-crcs">Realistic CRCs</h3>
<p>Realistic CRCs have a few more parameters. I call them
<code>init</code> and <code>final</code>.</p>
<pre><code>crc = <em>init</em>

<b>for each</b> bit b in message:
    crc = crc ^ b
    <b>if</b> least significant bit of crc is 1:
        crc = (crc >> 1) ^ <em>tap</em>
    <b>else</b>:
        crc = crc >> 1

<b>return</b> crc ^ <em>final</em></code></pre>
<p>(Side note: A particular may also reverse or not reverse the order of
the bits on input, and may reverse or not reverse the bit order of
<code>crc</code>. In practice, these options have not shown up at least
for me, and only takes 4 tries to brute force, so they’re not
considered.)</p>
<p>Just like before, we notice that if we don’t do the ‘reduction’ step,
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mrow><mi>𝚌</mi><mi>𝚛</mi><mi>𝚌</mi></mrow><mo>=</mo><mrow><mi>𝚒</mi><mi>𝚗</mi><mi>𝚒</mi><mi>𝚝</mi></mrow><mo>⋅</mo><msup><mi>x</mi><mi>L</mi></msup><mo>+</mo><mi>m</mi><msup><mi>x</mi><mi>N</mi></msup></mrow><annotation encoding="application/x-tex">\mathtt{crc} = \mathtt{init} \cdot x^L + m x^N</annotation></semantics></math>,
where
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mi>L</mi><annotation encoding="application/x-tex">L</annotation></semantics></math>
is the length of the message, this time <em>counting</em> leading zeros.
A
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>𝚏</mi><mi>𝚒</mi><mi>𝚗</mi><mi>𝚊</mi><mi>𝚕</mi></mrow><annotation encoding="application/x-tex">\mathtt{final}</annotation></semantics></math>
thing is added to the result.</p>
<p>Suppose that
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>𝚒</mi><mi>𝚗</mi><mi>𝚒</mi><mi>𝚝</mi></mrow><annotation encoding="application/x-tex">\mathtt{init}</annotation></semantics></math>
and
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>𝚏</mi><mi>𝚒</mi><mi>𝚗</mi><mi>𝚊</mi><mi>𝚕</mi></mrow><annotation encoding="application/x-tex">\mathtt{final}</annotation></semantics></math>
have degree less than
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mi>N</mi><annotation encoding="application/x-tex">N</annotation></semantics></math>,
then:</p>
<p><math display="block" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mrow><mi>𝚌</mi><mi>𝚛</mi><mi>𝚌</mi></mrow><mo>=</mo><mo stretchy="false" form="prefix">(</mo><mi>m</mi><msup><mi>x</mi><mi>N</mi></msup><mo>+</mo><mrow><mi>𝚒</mi><mi>𝚗</mi><mi>𝚒</mi><mi>𝚝</mi></mrow><mo>⋅</mo><msup><mi>x</mi><mi>L</mi></msup><mo>+</mo><mrow><mi>𝚏</mi><mi>𝚒</mi><mi>𝚗</mi><mi>𝚊</mi><mi>𝚕</mi></mrow><mo stretchy="false" form="postfix">)</mo><mrow><mspace width="0.222em"></mspace><mrow><mi>mod</mi><mo>&#8289;</mo></mrow><mspace width="0.222em"></mspace><mo stretchy="false" form="prefix">(</mo></mrow><mrow><mi>𝚝</mi><mi>𝚊</mi><mi>𝚙</mi></mrow><mo>+</mo><msup><mi>x</mi><mi>N</mi></msup><mo stretchy="false" form="postfix">)</mo></mrow><annotation encoding="application/x-tex"> \mathtt{crc} = (m x^N + \mathtt{init} \cdot x^L + \mathtt{final}) \bmod (\mathtt{tap} + x^N) </annotation></semantics></math></p>
<p>We note that the previous zero-initialized CRC does not depend on
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mi>L</mi><annotation encoding="application/x-tex">L</annotation></semantics></math>,
which means that it cannot detect extra/missing leading zeros. A
non-zero <code>init</code> mitigates this. I have absolutely no idea
what <code>final</code> is supposed to achieve, but it’s just there.</p>
<p>From now on, we’ll use these symbols consistently:</p>
<ul>
<li><math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mi>L</mi><annotation encoding="application/x-tex">L</annotation></semantics></math>
(length) is the message length in bits</li>
<li><math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mi>m</mi><annotation encoding="application/x-tex">m</annotation></semantics></math>
(message) is the message bit string as a polynomial</li>
<li><math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mi>N</mi><annotation encoding="application/x-tex">N</annotation></semantics></math>
is the length of the CRC</li>
<li><math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mi>r</mi><annotation encoding="application/x-tex">r</annotation></semantics></math>
(remainder) is
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>𝚌</mi><mi>𝚛</mi><mi>𝚌</mi></mrow><annotation encoding="application/x-tex">\mathtt{crc}</annotation></semantics></math></li>
<li><math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mi>F</mi><annotation encoding="application/x-tex">F</annotation></semantics></math>
is
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>𝚏</mi><mi>𝚒</mi><mi>𝚗</mi><mi>𝚊</mi><mi>𝚕</mi></mrow><annotation encoding="application/x-tex">\mathtt{final}</annotation></semantics></math></li>
<li><math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mi>I</mi><annotation encoding="application/x-tex">I</annotation></semantics></math>
is
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>𝚒</mi><mi>𝚗</mi><mi>𝚒</mi><mi>𝚝</mi></mrow><annotation encoding="application/x-tex">\mathtt{init}</annotation></semantics></math></li>
<li><math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mi>P</mi><annotation encoding="application/x-tex">P</annotation></semantics></math>
(polynomial) is
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mrow><mi>𝚝</mi><mi>𝚊</mi><mi>𝚙</mi></mrow><mo>+</mo><msup><mi>x</mi><mi>N</mi></msup></mrow><annotation encoding="application/x-tex">\mathtt{tap} + x^N</annotation></semantics></math></li>
</ul>
<p>Now the equation for a realistic CRC can be written:</p>
<p><math display="block" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>r</mi><mo>=</mo><mo stretchy="false" form="prefix">(</mo><mi>m</mi><msup><mi>x</mi><mi>N</mi></msup><mo>+</mo><mi>I</mi><msup><mi>x</mi><mi>L</mi></msup><mo>+</mo><mi>F</mi><mo stretchy="false" form="postfix">)</mo><mrow><mspace width="0.222em"></mspace><mrow><mi>mod</mi><mo>&#8289;</mo></mrow><mspace width="0.222em"></mspace><mi>P</mi></mrow></mrow><annotation encoding="application/x-tex"> r = (m x^N + I x^L + F) \bmod P </annotation></semantics></math></p>
<p>The following one just means both sides are equal after doing a
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mspace width="0.222em"></mspace><mrow><mi>mod</mi><mo>&#8289;</mo></mrow><mspace width="0.222em"></mspace><mi>P</mi></mrow><annotation encoding="application/x-tex">\bmod P</annotation></semantics></math>.
If you’re familiar with modulo congruences in integers, it’s basically
the same thing.</p>
<p><math display="block" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>r</mi><mo>≡</mo><mi>m</mi><msup><mi>x</mi><mi>N</mi></msup><mo>+</mo><mi>I</mi><msup><mi>x</mi><mi>L</mi></msup><mo>+</mo><mi>F</mi><mrow><mspace width="0.222em"></mspace><mo stretchy="false" form="prefix">(</mo><mrow><mi>mod</mi><mo>&#8289;</mo></mrow><mspace width="0.222em"></mspace><mi>P</mi><mo stretchy="false" form="postfix">)</mo></mrow></mrow><annotation encoding="application/x-tex"> r \equiv m x^N + I x^L + F \pmod P </annotation></semantics></math></p>
<h2 id="linearity-properties-of-crcs">Linearity properties of CRCs</h2>
<h3 id="crcs-are-linear">CRCs are linear</h3>
<p>(Or affine, if you’re pedantic)</p>
<p>Suppose we have two messages
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><msub><mi>m</mi><mn>1</mn></msub><annotation encoding="application/x-tex">m_1</annotation></semantics></math>
and
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><msub><mi>m</mi><mn>2</mn></msub><annotation encoding="application/x-tex">m_2</annotation></semantics></math>
of the same length
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mi>L</mi><annotation encoding="application/x-tex">L</annotation></semantics></math>,
with CRCs
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><msub><mi>r</mi><mn>1</mn></msub><annotation encoding="application/x-tex">r_1</annotation></semantics></math>
and
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><msub><mi>r</mi><mn>2</mn></msub><annotation encoding="application/x-tex">r_2</annotation></semantics></math>
respectively.</p>
<p><math display="block" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mtable><mtr><mtd columnalign="right" style="text-align: right; padding-right: 0"><msub><mi>r</mi><mn>1</mn></msub></mtd><mtd columnalign="left" style="text-align: left; padding-left: 0"><mo>≡</mo><msub><mi>m</mi><mn>1</mn></msub><msup><mi>x</mi><mi>N</mi></msup><mo>+</mo><mi>I</mi><msup><mi>x</mi><mi>L</mi></msup><mo>+</mo><mi>F</mi><mrow><mspace width="0.222em"></mspace><mo stretchy="false" form="prefix">(</mo><mrow><mi>mod</mi><mo>&#8289;</mo></mrow><mspace width="0.222em"></mspace><mi>P</mi><mo stretchy="false" form="postfix">)</mo></mrow></mtd></mtr><mtr><mtd columnalign="right" style="text-align: right; padding-right: 0"><msub><mi>r</mi><mn>2</mn></msub></mtd><mtd columnalign="left" style="text-align: left; padding-left: 0"><mo>≡</mo><msub><mi>m</mi><mn>2</mn></msub><msup><mi>x</mi><mi>N</mi></msup><mo>+</mo><mi>I</mi><msup><mi>x</mi><mi>L</mi></msup><mo>+</mo><mi>F</mi><mrow><mspace width="0.222em"></mspace><mo stretchy="false" form="prefix">(</mo><mrow><mi>mod</mi><mo>&#8289;</mo></mrow><mspace width="0.222em"></mspace><mi>P</mi><mo stretchy="false" form="postfix">)</mo></mrow></mtd></mtr></mtable><annotation encoding="application/x-tex">
\begin{aligned}
r_1 &amp;\equiv m_1 x^N + I x^L + F  \pmod{P} \\
r_2 &amp;\equiv m_2 x^N + I x^L + F  \pmod{P}
\end{aligned}
</annotation></semantics></math></p>
<p>Adding the two equations together gives something quite nice
(remember, anything added with itself equals zero):</p>
<p><math display="block" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msub><mi>r</mi><mn>1</mn></msub><mo>+</mo><msub><mi>r</mi><mn>2</mn></msub><mo>≡</mo><mo stretchy="false" form="prefix">(</mo><msub><mi>m</mi><mn>1</mn></msub><mo>+</mo><msub><mi>m</mi><mn>2</mn></msub><mo stretchy="false" form="postfix">)</mo><msup><mi>x</mi><mi>N</mi></msup><mrow><mspace width="0.222em"></mspace><mo stretchy="false" form="prefix">(</mo><mrow><mi>mod</mi><mo>&#8289;</mo></mrow><mspace width="0.222em"></mspace><mi>P</mi><mo stretchy="false" form="postfix">)</mo></mrow></mrow><annotation encoding="application/x-tex"> r_1 + r_2 \equiv (m_1 + m_2) x^N  \pmod{P} </annotation></semantics></math></p>
<p>Suppose that we have another pair of messages
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><msub><mi>m</mi><mn>3</mn></msub><annotation encoding="application/x-tex">m_3</annotation></semantics></math>
and
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><msub><mi>m</mi><mn>4</mn></msub><annotation encoding="application/x-tex">m_4</annotation></semantics></math>,
still with lengths
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mi>L</mi><annotation encoding="application/x-tex">L</annotation></semantics></math>,
such that
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msub><mi>m</mi><mn>1</mn></msub><mo>+</mo><msub><mi>m</mi><mn>2</mn></msub><mo>=</mo><msub><mi>m</mi><mn>3</mn></msub><mo>+</mo><msub><mi>m</mi><mn>4</mn></msub></mrow><annotation encoding="application/x-tex">m_1 + m_2 = m_3 + m_4</annotation></semantics></math>,
i.e. the four messages bitwise-xor to all zeros. Then we have:</p>
<p><math display="block" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msub><mi>r</mi><mn>1</mn></msub><mo>+</mo><msub><mi>r</mi><mn>2</mn></msub><mo>≡</mo><mo stretchy="false" form="prefix">(</mo><msub><mi>m</mi><mn>1</mn></msub><mo>+</mo><msub><mi>m</mi><mn>2</mn></msub><mo stretchy="false" form="postfix">)</mo><msup><mi>x</mi><mi>N</mi></msup><mo>≡</mo><mo stretchy="false" form="prefix">(</mo><msub><mi>m</mi><mn>3</mn></msub><mo>+</mo><msub><mi>m</mi><mn>4</mn></msub><mo stretchy="false" form="postfix">)</mo><msup><mi>x</mi><mi>N</mi></msup><mo>≡</mo><msub><mi>r</mi><mn>3</mn></msub><mo>+</mo><msub><mi>r</mi><mn>4</mn></msub><mrow><mspace width="0.222em"></mspace><mo stretchy="false" form="prefix">(</mo><mrow><mi>mod</mi><mo>&#8289;</mo></mrow><mspace width="0.222em"></mspace><mi>P</mi><mo stretchy="false" form="postfix">)</mo></mrow></mrow><annotation encoding="application/x-tex"> r_1 + r_2 \equiv (m_1 + m_2) x^N \equiv (m_3 + m_4) x^N \equiv r_3 + r_4  \pmod{P} </annotation></semantics></math></p>
<p>This is actually fairly common. For example, with consecutive numbers
as strings:</p>
<ul>
<li><math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><msub><mi>m</mi><mn>1</mn></msub><annotation encoding="application/x-tex">m_1</annotation></semantics></math>
is ASCII <code>10</code>, binary <code>1000 1100 0000 1100</code></li>
<li><math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><msub><mi>m</mi><mn>2</mn></msub><annotation encoding="application/x-tex">m_2</annotation></semantics></math>
is ASCII <code>11</code>, binary <code>1000 1100 1000 1100</code></li>
<li><math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><msub><mi>m</mi><mn>3</mn></msub><annotation encoding="application/x-tex">m_3</annotation></semantics></math>
is ASCII <code>12</code>, binary <code>0100 1100 1000 1100</code></li>
<li><math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><msub><mi>m</mi><mn>4</mn></msub><annotation encoding="application/x-tex">m_4</annotation></semantics></math>
is ASCII <code>13</code>, binary <code>1100 1100 1000 1100</code></li>
</ul>
<p>Or, taking these four message hexdumps from the samples:</p>
<pre><code>AAFF 040E02 0450
AAFF 050E02 8EDA
AAFF 060E02 1D05
AAFF 070E02 978F</code></pre>
<p>The messages match up just like the consecutive numbers example
above, and the check sequences also match up. That’s some encouraging
confirmation that we’re indeed looking at a CRC.</p>
<p>(I guess technically this kind of property should be called ‘affine’
instead of ‘linear’, but, meh…)</p>
<h3 id="applications">Applications</h3>
<p>This property is tremendously useful if we actually <em>know</em> the
parameters of a certain CRC algorithm. For example, going back to
bitwise land, if we have two messages
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mi>a</mi><annotation encoding="application/x-tex">a</annotation></semantics></math>
and
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mi>b</mi><annotation encoding="application/x-tex">b</annotation></semantics></math>
of the same length, and
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mi>z</mi><annotation encoding="application/x-tex">z</annotation></semantics></math>
is the all-zeros messages of that length, then:</p>
<p><math display="block" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mrow><mi mathvariant="normal">c</mi><mi mathvariant="normal">r</mi><mi mathvariant="normal">c</mi></mrow><mo stretchy="false" form="prefix">(</mo><mi>a</mi><mo>⊕</mo><mi>b</mi><mo stretchy="false" form="postfix">)</mo><mo>=</mo><mrow><mi mathvariant="normal">c</mi><mi mathvariant="normal">r</mi><mi mathvariant="normal">c</mi></mrow><mo stretchy="false" form="prefix">(</mo><mi>a</mi><mo stretchy="false" form="postfix">)</mo><mo>⊕</mo><mrow><mi mathvariant="normal">c</mi><mi mathvariant="normal">r</mi><mi mathvariant="normal">c</mi></mrow><mo stretchy="false" form="prefix">(</mo><mi>b</mi><mo stretchy="false" form="postfix">)</mo><mo>⊕</mo><mrow><mi mathvariant="normal">c</mi><mi mathvariant="normal">r</mi><mi mathvariant="normal">c</mi></mrow><mo stretchy="false" form="prefix">(</mo><mi>z</mi><mo stretchy="false" form="postfix">)</mo></mrow><annotation encoding="application/x-tex"> \mathrm{crc}(a \oplus b) = \mathrm{crc}(a) \oplus \mathrm{crc}(b) \oplus \mathrm{crc}(z)</annotation></semantics></math></p>
<p>Suppose for some inexplicable reason, someone uses a CRC-32 as a hash
function to hash string representations of integers, as an attempt to
hide the original numbers:</p>
<pre><code>crc(&quot;123456&quot;) = 0x0972d361</code></pre>
<p>The number can range up to 10 digits, so they’re hoping that we can’t
brute force our way through a billion numbers to find a match.</p>
<p>Nobody with even a tiny bit of sanity would think that’s a reasonable
way to hide a number… Right?</p>
<p>(Right? I suppose that’s a story for another time…)</p>
<p>To reverse the digit string out of the CRC, we can do a <a
href="https://en.wikipedia.org/wiki/Meet-in-the-middle_attack">meet-in-the-middle
attack</a>, matching up strings like <code>123\0\0\0</code> (that’s
<code>123</code> then 3 NUL bytes) with <code>\0\0\0456</code>. The
details are not that hard, and it takes milliseconds to ‘crack’ each
hash (if memory serves). For collisions we also get every solution.</p>
<p>However in our case of the adjustable desk, we don’t actually know
the parameters used. We must dig deeper. But before that, let’s take a
detour into how CRCs are transmitted:</p>
<h2 id="messages-with-crc-appended">Messages with CRC appended</h2>
<p>There’s another thing about how CRCs are implemented. Take a look
back at the ‘CRC equation’</p>
<p><math display="block" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>r</mi><mo>≡</mo><mi>m</mi><msup><mi>x</mi><mi>N</mi></msup><mo>+</mo><mi>I</mi><msup><mi>x</mi><mi>L</mi></msup><mo>+</mo><mi>F</mi><mrow><mspace width="0.222em"></mspace><mo stretchy="false" form="prefix">(</mo><mrow><mi>mod</mi><mo>&#8289;</mo></mrow><mspace width="0.222em"></mspace><mi>P</mi><mo stretchy="false" form="postfix">)</mo></mrow></mrow><annotation encoding="application/x-tex"> r \equiv m x^N + I x^L + F \pmod P </annotation></semantics></math></p>
<p>Let’s rearrange it a bit:</p>
<p><math display="block" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>m</mi><msup><mi>x</mi><mi>N</mi></msup><mo>+</mo><mi>r</mi><mo>≡</mo><mi>I</mi><msup><mi>x</mi><mi>L</mi></msup><mo>+</mo><mi>F</mi><mrow><mspace width="0.222em"></mspace><mo stretchy="false" form="prefix">(</mo><mrow><mi>mod</mi><mo>&#8289;</mo></mrow><mspace width="0.222em"></mspace><mi>P</mi><mo stretchy="false" form="postfix">)</mo></mrow></mrow><annotation encoding="application/x-tex"> m x^N + r \equiv I x^L + F \pmod P </annotation></semantics></math></p>
<p>The right hand side only depends on the message length, and the left
hand side… It’s the message with
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mi>N</mi><annotation encoding="application/x-tex">N</annotation></semantics></math>
zeros appended, then bitwise-xor with the CRC, i.e. exactly the message
and the CRC concatenated. If you like thinking of CRCs as integers,
that’s the messages concatenated with the CRC in little endian.</p>
<p>It is not a coincidence that CRCs are often concatenated after the
message in this exact way. Due to this nice property, this concatenation
simplifies CRC checking hardware, which need not keep track of a ‘state’
of whether it’s reading data or reading the CRC, and only need an
end-of-stream signal. We’ll not go into detail on that, but just notice
that each line in our hexdump:</p>
<pre><code>AAFF 0040 2EEC</code></pre>
<p>Is already the polynomial
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>m</mi><msup><mi>x</mi><mi>N</mi></msup><mo>+</mo><mi>r</mi></mrow><annotation encoding="application/x-tex">m x^N + r</annotation></semantics></math>.</p>
<h2 id="messages-with-equal-length">Messages with equal length</h2>
<p>In our case, we know several pairs of messages and their correct
CRCs. We can work out a fair bit of information by comparing messages.
We’ll first focus on pairs of messages with equal length.</p>
<h3 id="comparing-several-equal-length-messages">Comparing several
equal-length messages</h3>
<p>Given two messages
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><msub><mi>m</mi><mn>1</mn></msub><annotation encoding="application/x-tex">m_1</annotation></semantics></math>
and
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><msub><mi>m</mi><mn>2</mn></msub><annotation encoding="application/x-tex">m_2</annotation></semantics></math>
with equal length
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mi>L</mi><annotation encoding="application/x-tex">L</annotation></semantics></math>,
and known CRCs
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><msub><mi>r</mi><mn>1</mn></msub><annotation encoding="application/x-tex">r_1</annotation></semantics></math>
and
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><msub><mi>r</mi><mn>2</mn></msub><annotation encoding="application/x-tex">r_2</annotation></semantics></math>,</p>
<p><math display="block" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mtable><mtr><mtd columnalign="right" style="text-align: right; padding-right: 0"><msub><mi>m</mi><mn>1</mn></msub><msup><mi>x</mi><mi>N</mi></msup><mo>+</mo><msub><mi>r</mi><mn>1</mn></msub></mtd><mtd columnalign="left" style="text-align: left; padding-left: 0"><mo>≡</mo><mi>I</mi><msup><mi>x</mi><mi>L</mi></msup><mo>+</mo><mi>F</mi><mrow><mspace width="0.222em"></mspace><mo stretchy="false" form="prefix">(</mo><mrow><mi>mod</mi><mo>&#8289;</mo></mrow><mspace width="0.222em"></mspace><mi>P</mi><mo stretchy="false" form="postfix">)</mo></mrow></mtd></mtr><mtr><mtd columnalign="right" style="text-align: right; padding-right: 0"><msub><mi>m</mi><mn>2</mn></msub><msup><mi>x</mi><mi>N</mi></msup><mo>+</mo><msub><mi>r</mi><mn>2</mn></msub></mtd><mtd columnalign="left" style="text-align: left; padding-left: 0"><mo>≡</mo><mi>I</mi><msup><mi>x</mi><mi>L</mi></msup><mo>+</mo><mi>F</mi><mrow><mspace width="0.222em"></mspace><mo stretchy="false" form="prefix">(</mo><mrow><mi>mod</mi><mo>&#8289;</mo></mrow><mspace width="0.222em"></mspace><mi>P</mi><mo stretchy="false" form="postfix">)</mo></mrow></mtd></mtr></mtable><annotation encoding="application/x-tex">
\begin{aligned}
m_1 x^N + r_1 &amp;\equiv I x^L + F  \pmod{P} \\
m_2 x^N + r_2 &amp;\equiv I x^L + F  \pmod{P}
\end{aligned}
</annotation></semantics></math></p>
<p>Adding the two equations together give:</p>
<p><math display="block" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mo stretchy="false" form="prefix">(</mo><msub><mi>m</mi><mn>1</mn></msub><msup><mi>x</mi><mi>N</mi></msup><mo>+</mo><msub><mi>r</mi><mn>1</mn></msub><mo stretchy="false" form="postfix">)</mo><mo>+</mo><mo stretchy="false" form="prefix">(</mo><msub><mi>m</mi><mn>2</mn></msub><msup><mi>x</mi><mi>N</mi></msup><mo>+</mo><msub><mi>r</mi><mn>2</mn></msub><mo stretchy="false" form="postfix">)</mo><mo>≡</mo><mn>0</mn><mrow><mspace width="0.222em"></mspace><mo stretchy="false" form="prefix">(</mo><mrow><mi>mod</mi><mo>&#8289;</mo></mrow><mspace width="0.222em"></mspace><mi>P</mi><mo stretchy="false" form="postfix">)</mo></mrow></mrow><annotation encoding="application/x-tex"> (m_1 x^N + r_1) + (m_2 x^N + r_2) \equiv 0  \pmod{P} </annotation></semantics></math></p>
<p>Similarly, if we have more messages
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><msub><mi>m</mi><mn>3</mn></msub><annotation encoding="application/x-tex">m_3</annotation></semantics></math>,
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><msub><mi>m</mi><mn>4</mn></msub><annotation encoding="application/x-tex">m_4</annotation></semantics></math>,
etc. still of length
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mi>L</mi><annotation encoding="application/x-tex">L</annotation></semantics></math>,
we have:</p>
<p><math display="block" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mtable><mtr><mtd columnalign="right" style="text-align: right"><mo stretchy="false" form="prefix">(</mo><msub><mi>m</mi><mn>1</mn></msub><msup><mi>x</mi><mi>N</mi></msup><mo>+</mo><msub><mi>r</mi><mn>1</mn></msub><mo stretchy="false" form="postfix">)</mo><mo>+</mo><mo stretchy="false" form="prefix">(</mo><msub><mi>m</mi><mn>3</mn></msub><msup><mi>x</mi><mi>N</mi></msup><mo>+</mo><msub><mi>r</mi><mn>3</mn></msub><mo stretchy="false" form="postfix">)</mo><mo>≡</mo><mn>0</mn><mrow><mspace width="0.222em"></mspace><mo stretchy="false" form="prefix">(</mo><mrow><mi>mod</mi><mo>&#8289;</mo></mrow><mspace width="0.222em"></mspace><mi>P</mi><mo stretchy="false" form="postfix">)</mo></mrow></mtd></mtr><mtr><mtd columnalign="right" style="text-align: right"><mo stretchy="false" form="prefix">(</mo><msub><mi>m</mi><mn>1</mn></msub><msup><mi>x</mi><mi>N</mi></msup><mo>+</mo><msub><mi>r</mi><mn>1</mn></msub><mo stretchy="false" form="postfix">)</mo><mo>+</mo><mo stretchy="false" form="prefix">(</mo><msub><mi>m</mi><mn>4</mn></msub><msup><mi>x</mi><mi>N</mi></msup><mo>+</mo><msub><mi>r</mi><mn>4</mn></msub><mo stretchy="false" form="postfix">)</mo><mo>≡</mo><mn>0</mn><mrow><mspace width="0.222em"></mspace><mo stretchy="false" form="prefix">(</mo><mrow><mi>mod</mi><mo>&#8289;</mo></mrow><mspace width="0.222em"></mspace><mi>P</mi><mo stretchy="false" form="postfix">)</mo></mrow></mtd></mtr></mtable><annotation encoding="application/x-tex">
\begin{aligned}
(m_1 x^N + r_1) + (m_3 x^N + r_3) \equiv 0  \pmod{P} \\
(m_1 x^N + r_1) + (m_4 x^N + r_4) \equiv 0  \pmod{P}
\end{aligned}
</annotation></semantics></math></p>
<p>Actually, it only matters that for each pair used in this adding, the
messages have the same length. The pairs don’t have to be all
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mi>L</mi><annotation encoding="application/x-tex">L</annotation></semantics></math>.
Let’s call
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msub><mi>d</mi><mrow><mi>k</mi><mo>,</mo><mi>l</mi></mrow></msub><mo>=</mo><mo stretchy="false" form="prefix">(</mo><msub><mi>m</mi><mi>k</mi></msub><msup><mi>x</mi><mi>N</mi></msup><mo>+</mo><msub><mi>r</mi><mi>k</mi></msub><mo stretchy="false" form="postfix">)</mo><mo>+</mo><mo stretchy="false" form="prefix">(</mo><msub><mi>m</mi><mi>l</mi></msub><msup><mi>x</mi><mi>N</mi></msup><mo>+</mo><msub><mi>r</mi><mi>l</mi></msub><mo stretchy="false" form="postfix">)</mo></mrow><annotation encoding="application/x-tex">d_{k,l} =
(m_k x^N + r_k) + (m_l x^N + r_l)</annotation></semantics></math></p>
<p>Since all the
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msub><mi>m</mi><mi>k</mi></msub><msup><mi>x</mi><mi>N</mi></msup><mo>+</mo><msub><mi>r</mi><mi>k</mi></msub></mrow><annotation encoding="application/x-tex">m_k x^N + r_k</annotation></semantics></math>
directly correspond to the data we dumped, we actually know them <em>in
full</em>, not just modulo something. So we know all
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><msub><mi>d</mi><mrow><mi>k</mi><mo>,</mo><mi>l</mi></mrow></msub><annotation encoding="application/x-tex">d_{k,
l}</annotation></semantics></math> in full. If
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><msub><mi>m</mi><mi>k</mi></msub><annotation encoding="application/x-tex">m_k</annotation></semantics></math>
and
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><msub><mi>m</mi><mi>l</mi></msub><annotation encoding="application/x-tex">m_l</annotation></semantics></math>
have the same length then for some unknown
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><msub><mi>q</mi><mrow><mi>k</mi><mo>,</mo><mi>l</mi></mrow></msub><annotation encoding="application/x-tex">q_{k,l}</annotation></semantics></math>:</p>
<p><math display="block" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msub><mi>d</mi><mrow><mi>k</mi><mo>,</mo><mi>l</mi></mrow></msub><mo>=</mo><mi>P</mi><mo>⋅</mo><msub><mi>q</mi><mrow><mi>k</mi><mo>,</mo><mi>l</mi></mrow></msub></mrow><annotation encoding="application/x-tex"> d_{k, l} = P \cdot q_{k, l} </annotation></semantics></math></p>
<p>We have several multiples of
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mi>P</mi><annotation encoding="application/x-tex">P</annotation></semantics></math>.
How can we find
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mi>P</mi><annotation encoding="application/x-tex">P</annotation></semantics></math>
itself? This sounds like a job for…</p>
<h3 id="polynomial-greatest-common-divisor-gcd">Polynomial greatest
common divisor (GCD)</h3>
<p>So if we can calculate the remainder of polynomial division, is there
an analogous Euclidean algorithm to calculate the <a
href="https://en.wikipedia.org/wiki/Polynomial_greatest_common_divisor">greatest
common divisor (GCD) of two polynomials</a>? You bet:</p>
<div class="sourceCode" id="cb7"><pre
class="sourceCode python"><code class="sourceCode python"><span id="cb7-1"><a href="#cb7-1" aria-hidden="true" tabindex="-1"></a><span class="kw">def</span> poly_gcd(a, b):</span>
<span id="cb7-2"><a href="#cb7-2" aria-hidden="true" tabindex="-1"></a>    <span class="cf">while</span> b <span class="op">!=</span> <span class="dv">0</span>:</span>
<span id="cb7-3"><a href="#cb7-3" aria-hidden="true" tabindex="-1"></a>        a, b <span class="op">=</span> b, poly_mod(a, b)</span>
<span id="cb7-4"><a href="#cb7-4" aria-hidden="true" tabindex="-1"></a>    <span class="cf">return</span> a</span></code></pre></div>
<p>The GCD of two polynomials
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>a</mi><mo stretchy="false" form="prefix">(</mo><mi>x</mi><mo stretchy="false" form="postfix">)</mo></mrow><annotation encoding="application/x-tex">a(x)</annotation></semantics></math>
and
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>b</mi><mo stretchy="false" form="prefix">(</mo><mi>x</mi><mo stretchy="false" form="postfix">)</mo></mrow><annotation encoding="application/x-tex">b(x)</annotation></semantics></math>
is the polynomial
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>g</mi><mo stretchy="false" form="prefix">(</mo><mi>x</mi><mo stretchy="false" form="postfix">)</mo></mrow><annotation encoding="application/x-tex">g(x)</annotation></semantics></math>
with the highest degree such that
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>a</mi><mo stretchy="false" form="prefix">(</mo><mi>x</mi><mo stretchy="false" form="postfix">)</mo></mrow><annotation encoding="application/x-tex">a(x)</annotation></semantics></math>
and
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>b</mi><mo stretchy="false" form="prefix">(</mo><mi>x</mi><mo stretchy="false" form="postfix">)</mo></mrow><annotation encoding="application/x-tex">b(x)</annotation></semantics></math>
are both the product
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>g</mi><mo stretchy="false" form="prefix">(</mo><mi>x</mi><mo stretchy="false" form="postfix">)</mo></mrow><annotation encoding="application/x-tex">g(x)</annotation></semantics></math>
and another polynomial.</p>
<p>The Euclidean algorithm for finding GCD works with polynomials, just
like with integers.</p>
<h3 id="finding-p-with-gcd">Finding
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mi>P</mi><annotation encoding="application/x-tex">P</annotation></semantics></math>
with GCD</h3>
<p>Since if we have examples of
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>P</mi><mo>⋅</mo><msub><mi>q</mi><mrow><mi>k</mi><mo>,</mo><mi>l</mi></mrow></msub></mrow><annotation encoding="application/x-tex">P \cdot q_{k, l}</annotation></semantics></math>
available, even though all the
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><msub><mi>q</mi><mrow><mi>k</mi><mo>,</mo><mi>l</mi></mrow></msub><annotation encoding="application/x-tex">q_{k, l}</annotation></semantics></math>
are unknown, we should be able to take the GCD of all of them and
hopefully get
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mi>P</mi><annotation encoding="application/x-tex">P</annotation></semantics></math>.</p>
<p>So for example with these three message hexdumps:</p>
<pre><code>m1, r1 = AAFF 0040 2EEC
m2, r2 = AAFF 0060 2964
m3, r3 = AAFF 0050 2B08</code></pre>
<p>Pairing them up arbitrarily give these polynomials:</p>
<p><math display="block" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mtable><mtr><mtd columnalign="right" style="text-align: right; padding-right: 0"><mo stretchy="false" form="prefix">(</mo><msub><mi>m</mi><mn>1</mn></msub><msup><mi>x</mi><mn>16</mn></msup><mo>+</mo><msub><mi>r</mi><mn>1</mn></msub><mo stretchy="false" form="postfix">)</mo><mo>+</mo><mo stretchy="false" form="prefix">(</mo><msub><mi>m</mi><mn>2</mn></msub><msup><mi>x</mi><mn>16</mn></msup><mo>+</mo><msub><mi>r</mi><mn>2</mn></msub><mo stretchy="false" form="postfix">)</mo></mtd><mtd columnalign="left" style="text-align: left; padding-left: 0"><mo>=</mo><msup><mi>x</mi><mn>18</mn></msup><mo>+</mo><msup><mi>x</mi><mn>15</mn></msup><mo>+</mo><msup><mi>x</mi><mn>14</mn></msup><mo>+</mo><msup><mi>x</mi><mn>13</mn></msup><mo>+</mo><msup><mi>x</mi><mn>4</mn></msup><mo>+</mo><msup><mi>x</mi><mn>0</mn></msup></mtd></mtr><mtr><mtd columnalign="right" style="text-align: right; padding-right: 0"><mo stretchy="false" form="prefix">(</mo><msub><mi>m</mi><mn>1</mn></msub><msup><mi>x</mi><mn>16</mn></msup><mo>+</mo><msub><mi>r</mi><mn>1</mn></msub><mo stretchy="false" form="postfix">)</mo><mo>+</mo><mo stretchy="false" form="prefix">(</mo><msub><mi>m</mi><mn>3</mn></msub><msup><mi>x</mi><mn>16</mn></msup><mo>+</mo><msub><mi>r</mi><mn>3</mn></msub><mo stretchy="false" form="postfix">)</mo></mtd><mtd columnalign="left" style="text-align: left; padding-left: 0"><mo>=</mo><msup><mi>x</mi><mn>19</mn></msup><mo>+</mo><msup><mi>x</mi><mn>15</mn></msup><mo>+</mo><msup><mi>x</mi><mn>13</mn></msup><mo>+</mo><msup><mi>x</mi><mn>5</mn></msup><mo>+</mo><msup><mi>x</mi><mn>2</mn></msup><mo>+</mo><msup><mi>x</mi><mn>1</mn></msup><mo>+</mo><msup><mi>x</mi><mn>0</mn></msup></mtd></mtr></mtable><annotation encoding="application/x-tex">
\begin{aligned}
(m_1 x^{16} + r_1) + (m_2 x^{16} + r_2) &amp;= x^{18} + x^{15} + x^{14} + x^{13} + x^{4} + x^{0} \\
(m_1 x^{16} + r_1) + (m_3 x^{16} + r_3) &amp;= x^{19} + x^{15} + x^{13} + x^{5} + x^{2} + x^{1} + x^{0}
\end{aligned}
</annotation></semantics></math></p>
<p>They should both be a multiple of
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mi>P</mi><annotation encoding="application/x-tex">P</annotation></semantics></math>,
so taking the polynomial GCD should give us a multiple of
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mi>P</mi><annotation encoding="application/x-tex">P</annotation></semantics></math>
of lower degree, hopefully
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mi>P</mi><annotation encoding="application/x-tex">P</annotation></semantics></math>
itself.</p>
<p>What we get is:</p>
<p><math display="block" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msup><mi>x</mi><mn>16</mn></msup><mo>+</mo><msup><mi>x</mi><mn>14</mn></msup><mo>+</mo><msup><mi>x</mi><mn>13</mn></msup><mo>+</mo><msup><mi>x</mi><mn>2</mn></msup><mo>+</mo><msup><mi>x</mi><mn>0</mn></msup></mrow><annotation encoding="application/x-tex"> x^{16} + x^{14} + x^{13} + x^{2} + x^{0} </annotation></semantics></math></p>
<p>Since we guessed that it’s a CRC-16,
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mi>P</mi><annotation encoding="application/x-tex">P</annotation></semantics></math>
should have degree
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>N</mi><mo>=</mo><mn>16</mn></mrow><annotation encoding="application/x-tex">N = 16</annotation></semantics></math>,
and this result does have degree
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mn>16</mn><annotation encoding="application/x-tex">16</annotation></semantics></math>.
So that’s it, we found our polynomial
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>P</mi><mo>=</mo><msup><mi>x</mi><mn>16</mn></msup><mo>+</mo><mrow><mi>𝚝</mi><mi>𝚊</mi><mi>𝚙</mi></mrow></mrow><annotation encoding="application/x-tex">P = x^{16}
+ \mathtt{tap}</annotation></semantics></math>.</p>
<p>For use in code, <code>tap</code> should be the bit reversal of
<code>0x6005</code>, i.e. <code>0xa006</code>.</p>
<h2 id="messages-with-unequal-length">Messages with unequal length</h2>
<h3 id="comparing-messages-with-unequal-length">Comparing messages with
unequal length</h3>
<p>Having figured out
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mi>P</mi><annotation encoding="application/x-tex">P</annotation></semantics></math>,
we can try working on the rest of our parameters. We’ll pick two
messages
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><msub><mi>m</mi><mn>1</mn></msub><annotation encoding="application/x-tex">m_1</annotation></semantics></math>
and
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><msub><mi>m</mi><mn>2</mn></msub><annotation encoding="application/x-tex">m_2</annotation></semantics></math>
with unequal lengths
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><msub><mi>L</mi><mn>1</mn></msub><annotation encoding="application/x-tex">L_1</annotation></semantics></math>
and
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><msub><mi>L</mi><mn>2</mn></msub><annotation encoding="application/x-tex">L_2</annotation></semantics></math>,
and known CRCs
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><msub><mi>r</mi><mn>1</mn></msub><annotation encoding="application/x-tex">r_1</annotation></semantics></math>
and
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><msub><mi>r</mi><mn>2</mn></msub><annotation encoding="application/x-tex">r_2</annotation></semantics></math>,</p>
<p><math display="block" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mtable><mtr><mtd columnalign="right" style="text-align: right; padding-right: 0"><msub><mi>m</mi><mn>1</mn></msub><msup><mi>x</mi><mi>N</mi></msup><mo>+</mo><msub><mi>r</mi><mn>1</mn></msub></mtd><mtd columnalign="left" style="text-align: left; padding-left: 0"><mo>≡</mo><mi>I</mi><msup><mi>x</mi><msub><mi>L</mi><mn>1</mn></msub></msup><mo>+</mo><mi>F</mi><mrow><mspace width="0.222em"></mspace><mo stretchy="false" form="prefix">(</mo><mrow><mi>mod</mi><mo>&#8289;</mo></mrow><mspace width="0.222em"></mspace><mi>P</mi><mo stretchy="false" form="postfix">)</mo></mrow></mtd></mtr><mtr><mtd columnalign="right" style="text-align: right; padding-right: 0"><msub><mi>m</mi><mn>2</mn></msub><msup><mi>x</mi><mi>N</mi></msup><mo>+</mo><msub><mi>r</mi><mn>2</mn></msub></mtd><mtd columnalign="left" style="text-align: left; padding-left: 0"><mo>≡</mo><mi>I</mi><msup><mi>x</mi><msub><mi>L</mi><mn>2</mn></msub></msup><mo>+</mo><mi>F</mi><mrow><mspace width="0.222em"></mspace><mo stretchy="false" form="prefix">(</mo><mrow><mi>mod</mi><mo>&#8289;</mo></mrow><mspace width="0.222em"></mspace><mi>P</mi><mo stretchy="false" form="postfix">)</mo></mrow></mtd></mtr></mtable><annotation encoding="application/x-tex">
\begin{aligned}
m_1 x^N + r_1 &amp;\equiv I x^{L_1} + F  \pmod{P} \\
m_2 x^N + r_2 &amp;\equiv I x^{L_2} + F  \pmod{P}
\end{aligned}
</annotation></semantics></math></p>
<p>Adding them this time gives:</p>
<p><math display="block" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mo stretchy="false" form="prefix">(</mo><msub><mi>m</mi><mn>1</mn></msub><msup><mi>x</mi><mi>N</mi></msup><mo>+</mo><msub><mi>r</mi><mn>1</mn></msub><mo stretchy="false" form="postfix">)</mo><mo>+</mo><mo stretchy="false" form="prefix">(</mo><msub><mi>m</mi><mn>2</mn></msub><msup><mi>x</mi><mi>N</mi></msup><mo>+</mo><msub><mi>r</mi><mn>2</mn></msub><mo stretchy="false" form="postfix">)</mo><mo>≡</mo><mi>I</mi><mo stretchy="false" form="prefix">(</mo><msup><mi>x</mi><msub><mi>L</mi><mn>1</mn></msub></msup><mo>+</mo><msup><mi>x</mi><msub><mi>L</mi><mn>2</mn></msub></msup><mo stretchy="false" form="postfix">)</mo><mrow><mspace width="0.222em"></mspace><mo stretchy="false" form="prefix">(</mo><mrow><mi>mod</mi><mo>&#8289;</mo></mrow><mspace width="0.222em"></mspace><mi>P</mi><mo stretchy="false" form="postfix">)</mo></mrow></mrow><annotation encoding="application/x-tex"> (m_1 x^N + r_1) + (m_2 x^N + r_2) \equiv I (x^{L_1} + x^{L_2}) \pmod{P} </annotation></semantics></math></p>
<p>Everything except
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mi>I</mi><annotation encoding="application/x-tex">I</annotation></semantics></math>
is known here.</p>
<h3 id="solving-for-i">Solving for
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mi>I</mi><annotation encoding="application/x-tex">I</annotation></semantics></math></h3>
<p>Suppose that:</p>
<p><math display="block" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>I</mi><mo>=</mo><munderover><mo>∑</mo><mrow><mi>k</mi><mo>=</mo><mn>0</mn></mrow><mrow><mi>N</mi><mo>−</mo><mn>1</mn></mrow></munderover><msub><mi>a</mi><mi>k</mi></msub><msup><mi>x</mi><mi>k</mi></msup></mrow><annotation encoding="application/x-tex"> I = \sum_{k = 0}^{N - 1} a_k x^k </annotation></semantics></math></p>
<p>Then:</p>
<p><math display="block" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>I</mi><mo stretchy="false" form="prefix">(</mo><msup><mi>x</mi><msub><mi>L</mi><mn>1</mn></msub></msup><mo>+</mo><msup><mi>x</mi><msub><mi>L</mi><mn>2</mn></msub></msup><mo stretchy="false" form="postfix">)</mo><mrow><mspace width="0.222em"></mspace><mrow><mi>mod</mi><mo>&#8289;</mo></mrow><mspace width="0.222em"></mspace><mi>P</mi></mrow><mo>=</mo><munderover><mo>∑</mo><mrow><mi>k</mi><mo>=</mo><mn>0</mn></mrow><mrow><mi>N</mi><mo>−</mo><mn>1</mn></mrow></munderover><msub><mi>a</mi><mi>k</mi></msub><mo>⋅</mo><mo stretchy="false" form="prefix">(</mo><msup><mi>x</mi><mi>k</mi></msup><mo stretchy="false" form="prefix">(</mo><msup><mi>x</mi><msub><mi>L</mi><mn>1</mn></msub></msup><mo>+</mo><msup><mi>x</mi><msub><mi>L</mi><mn>2</mn></msub></msup><mo stretchy="false" form="postfix">)</mo><mrow><mspace width="0.222em"></mspace><mrow><mi>mod</mi><mo>&#8289;</mo></mrow><mspace width="0.222em"></mspace><mi>P</mi></mrow><mo stretchy="false" form="postfix">)</mo></mrow><annotation encoding="application/x-tex"> I (x^{L_1} + x^{L_2}) \bmod P = \sum_{k = 0}^{N - 1} a_k \cdot (x^k (x^{L_1} + x^{L_2}) \bmod P) </annotation></semantics></math></p>
<p>The left hand side is just
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mo stretchy="false" form="prefix">(</mo><mo stretchy="false" form="prefix">(</mo><msub><mi>m</mi><mn>1</mn></msub><msup><mi>x</mi><mi>N</mi></msup><mo>+</mo><msub><mi>r</mi><mn>1</mn></msub><mo stretchy="false" form="postfix">)</mo><mo>+</mo><mo stretchy="false" form="prefix">(</mo><msub><mi>m</mi><mn>2</mn></msub><msup><mi>x</mi><mi>N</mi></msup><mo>+</mo><msub><mi>r</mi><mn>2</mn></msub><mo stretchy="false" form="postfix">)</mo><mo stretchy="false" form="postfix">)</mo><mrow><mspace width="0.222em"></mspace><mrow><mi>mod</mi><mo>&#8289;</mo></mrow><mspace width="0.222em"></mspace><mi>P</mi></mrow></mrow><annotation encoding="application/x-tex">((m_1 x^N + r_1) + (m_2 x^N + r_2)) \bmod P</annotation></semantics></math>.
Each one of
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msup><mi>x</mi><mi>k</mi></msup><mo stretchy="false" form="prefix">(</mo><msup><mi>x</mi><msub><mi>L</mi><mn>1</mn></msub></msup><mo>+</mo><msup><mi>x</mi><msub><mi>L</mi><mn>2</mn></msub></msup><mo stretchy="false" form="postfix">)</mo><mrow><mspace width="0.222em"></mspace><mrow><mi>mod</mi><mo>&#8289;</mo></mrow><mspace width="0.222em"></mspace><mi>P</mi></mrow></mrow><annotation encoding="application/x-tex">x^k (x^{L_1} + x^{L_2}) \bmod P</annotation></semantics></math>
is also known.</p>
<p>Note also that each of those is a polynomial of degree smaller than
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mi>N</mi><annotation encoding="application/x-tex">N</annotation></semantics></math>.
These polynomials form a <em>vector space</em> over
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mrow><mi mathvariant="normal">G</mi><mi mathvariant="normal">F</mi></mrow><mo stretchy="false" form="prefix">(</mo><mn>2</mn><mo stretchy="false" form="postfix">)</mo></mrow><annotation encoding="application/x-tex">\mathrm{GF}(2)</annotation></semantics></math>.
If we think in terms of vector spaces, the problem now is to figure out
a linear combination of the base vectors
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msup><mi>x</mi><mi>k</mi></msup><mo stretchy="false" form="prefix">(</mo><msup><mi>x</mi><msub><mi>L</mi><mn>1</mn></msub></msup><mo>+</mo><msup><mi>x</mi><msub><mi>L</mi><mn>2</mn></msub></msup><mo stretchy="false" form="postfix">)</mo><mrow><mspace width="0.222em"></mspace><mrow><mi>mod</mi><mo>&#8289;</mo></mrow><mspace width="0.222em"></mspace><mi>P</mi></mrow></mrow><annotation encoding="application/x-tex">x^k (x^{L_1} + x^{L_2}) \bmod P</annotation></semantics></math>
that gives
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>I</mi><mo stretchy="false" form="prefix">(</mo><msup><mi>x</mi><msub><mi>L</mi><mn>1</mn></msub></msup><mo>+</mo><msup><mi>x</mi><msub><mi>L</mi><mn>2</mn></msub></msup><mo stretchy="false" form="postfix">)</mo><mrow><mspace width="0.222em"></mspace><mrow><mi>mod</mi><mo>&#8289;</mo></mrow><mspace width="0.222em"></mspace><mi>P</mi></mrow></mrow><annotation encoding="application/x-tex">I (x^{L_1} + x^{L_2})
\bmod P</annotation></semantics></math>.</p>
<p>In other words, we need to solve a linear equation. That’s a job for
our beloved Gauss-Jordan elimination. But this time we work in
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mrow><mi mathvariant="normal">G</mi><mi mathvariant="normal">F</mi></mrow><mo stretchy="false" form="prefix">(</mo><mn>2</mn><mo stretchy="false" form="postfix">)</mo></mrow><annotation encoding="application/x-tex">\mathrm{GF}(2)</annotation></semantics></math>,
so adding rows just means bitwise-xor, and there is no scaling
involved.</p>
<p>In the rare chance that we don’t get a unique solution, i.e. the base
vectors aren’t actually linear independent, we can pick another message
with a different length try again.</p>
<p>If we go back to the real data we collected and pick these two
messages:</p>
<pre><code>m1, r1 = AAFF 0040 2EEC
m2, r2 = AAFF 040E02 0450</code></pre>
<p>The lengths are
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msub><mi>L</mi><mn>1</mn></msub><mo>=</mo><mn>32</mn></mrow><annotation encoding="application/x-tex">L_1 = 32</annotation></semantics></math>
and
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msub><mi>L</mi><mn>2</mn></msub><mo>=</mo><mn>40</mn></mrow><annotation encoding="application/x-tex">L_2 = 40</annotation></semantics></math>,
so the base vectors are (remember first bit is highest power):</p>
<pre><code>k  | x^k (x^L1 + x^L2) mod P
---|-------------------------
0  | 0001 1011 1100 0010
1  | 0011 0111 1000 0100
2  | 0110 1111 0000 1000
3  | 1101 1110 0001 0000
4  | 1101 1100 0010 0101
5  | 1101 1000 0100 1111
6  | 1101 0000 1001 1011
7  | 1100 0001 0011 0011
8  | 1110 0010 0110 0011
9  | 1010 0100 1100 0011
10 | 0010 1001 1000 0011
11 | 0101 0011 0000 0110
12 | 1010 0110 0000 1100
13 | 0010 1100 0001 1101
14 | 0101 1000 0011 1010
15 | 1011 0000 0111 0100</code></pre>
<p>Our target polynomial
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mo stretchy="false" form="prefix">(</mo><mo stretchy="false" form="prefix">(</mo><msub><mi>m</mi><mn>1</mn></msub><msup><mi>x</mi><mi>N</mi></msup><mo>+</mo><msub><mi>r</mi><mn>1</mn></msub><mo stretchy="false" form="postfix">)</mo><mo>+</mo><mo stretchy="false" form="prefix">(</mo><msub><mi>m</mi><mn>2</mn></msub><msup><mi>x</mi><mi>N</mi></msup><mo>+</mo><msub><mi>r</mi><mn>2</mn></msub><mo stretchy="false" form="postfix">)</mo><mo stretchy="false" form="postfix">)</mo><mrow><mspace width="0.222em"></mspace><mrow><mi>mod</mi><mo>&#8289;</mo></mrow><mspace width="0.222em"></mspace><mi>P</mi></mrow></mrow><annotation encoding="application/x-tex">((m_1 x^N + r_1) + (m_2 x^N + r_2)) \bmod P</annotation></semantics></math>
is <code>1101 0110 1110 0110</code>, or:</p>
<p><math display="block" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msup><mi>x</mi><mn>15</mn></msup><mo>+</mo><msup><mi>x</mi><mn>14</mn></msup><mo>+</mo><msup><mi>x</mi><mn>12</mn></msup><mo>+</mo><msup><mi>x</mi><mn>10</mn></msup><mo>+</mo><msup><mi>x</mi><mn>9</mn></msup><mo>+</mo><msup><mi>x</mi><mn>7</mn></msup><mo>+</mo><msup><mi>x</mi><mn>6</mn></msup><mo>+</mo><msup><mi>x</mi><mn>5</mn></msup><mo>+</mo><msup><mi>x</mi><mn>2</mn></msup><mo>+</mo><msup><mi>x</mi><mn>1</mn></msup></mrow><annotation encoding="application/x-tex"> x^{15} + x^{14} + x^{12} + x^{10} + x^{9} + x^{7} + x^{6} + x^{5} + x^{2} + x^{1} </annotation></semantics></math></p>
<p>Solving for
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><msub><mi>a</mi><mi>k</mi></msub><annotation encoding="application/x-tex">a_k</annotation></semantics></math>,
and we get that every single
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><msub><mi>a</mi><mi>k</mi></msub><annotation encoding="application/x-tex">a_k</annotation></semantics></math>
is
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mn>1</mn><annotation encoding="application/x-tex">1</annotation></semantics></math>,
i.e. <code>init</code> is the all-ones <code>0xffff</code>.</p>
<h1 id="solving-for-f">Solving for
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mi>F</mi><annotation encoding="application/x-tex">F</annotation></semantics></math></h1>
<p>Now the only thing remaining to figure out is the final value
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mi>F</mi><annotation encoding="application/x-tex">F</annotation></semantics></math>.
Going back to this:</p>
<p><math display="block" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>r</mi><mo>≡</mo><mi>m</mi><msup><mi>x</mi><mi>N</mi></msup><mo>+</mo><mi>I</mi><msup><mi>x</mi><mi>L</mi></msup><mo>+</mo><mi>F</mi><mrow><mspace width="0.222em"></mspace><mo stretchy="false" form="prefix">(</mo><mrow><mi>mod</mi><mo>&#8289;</mo></mrow><mspace width="0.222em"></mspace><mi>P</mi><mo stretchy="false" form="postfix">)</mo></mrow></mrow><annotation encoding="application/x-tex"> r \equiv m x^N + I x^L + F \pmod P </annotation></semantics></math></p>
<p>Solving for
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mi>F</mi><annotation encoding="application/x-tex">F</annotation></semantics></math>
is pretty easy now, given that we know everything else:</p>
<p><math display="block" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>F</mi><mo>≡</mo><mi>m</mi><msup><mi>x</mi><mi>N</mi></msup><mo>+</mo><mi>r</mi><mo>+</mo><mi>I</mi><msup><mi>x</mi><mi>L</mi></msup><mrow><mspace width="0.222em"></mspace><mo stretchy="false" form="prefix">(</mo><mrow><mi>mod</mi><mo>&#8289;</mo></mrow><mspace width="0.222em"></mspace><mi>P</mi><mo stretchy="false" form="postfix">)</mo></mrow></mrow><annotation encoding="application/x-tex"> F \equiv m x^N + r + I x^L \pmod P </annotation></semantics></math></p>
<p>In other words, we can do a CRC calculation on something we know,
assuming that <code>final</code> is zero, and check the bitwise-xor with
the real CRC to get the real value or <code>final</code>. In the case of
this adjustable desk it turns out that <code>final</code> actually is
just zero.</p>
<p>Now we have the complete set of parameters:</p>
<pre><code>tap   = 0xa006
init  = 0xffff
final = 0x0000</code></pre>
<p>This is not any standard CRC, as far as I know. I have no idea why
the desk was programmed this way.</p>
<p>I tried this process on some other samples including some CRC-32 ones
and it seems to work fairly reliably given like 10 example pairs.</p>
<h1 id="did-you-really-do-all-these-just-to-hack-into-a-desk">Did you
really do all these just to hack into a desk?</h1>
<p>No, I just wrote a program that went through all
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><msup><mn>2</mn><mn>16</mn></msup><annotation encoding="application/x-tex">2^{16}</annotation></semantics></math>
values of <code>tap</code>, assuming that <code>init = 0xffff</code> and
<code>final = 0x0000</code> just like Modbus. I found
<code>tap = 0x2006</code> works.</p>
<p>Then they started talking about sending it into a solver like Z3 or
something, in case brute force didn’t work (well, brute forcing 32-bit
CRCs where you need to figure out both <code>init</code> and
<code>tap</code> does seem to be intractable), but I was <em>so</em>
sure that I can reverse engineer CRC without brute force or relying on
solvers that I actually went ahead and did it. Got <a
href="https://xkcd.com/356">nerd snipped</a>, I
suppose.</p>]]></description>
    </item>
    <item>
        <title>The with construct in nix-lang</title>
        <pubDate>Wed, 19 May 2021 00:00:00 +0000</pubDate>
        <guid isPermaLink="true">https://dram.page/p/nix-lang-with</guid>
        <description><![CDATA[<p>The Nix package manager comes with its
own programming language for, among other things, defining packages.
We’re not here to discuss whether that’s a good decision. We’ll call it
the Nix language, or nix-lang for short.</p>
<p>This article assumes some familiarity with nix-lang. This is not a
tutorial.</p>
<h1 id="the-syntax-with-a-e">The syntax <code>with A; E</code></h1>
<p>Nix-lang has a construct <code>with A; E</code>. Its purpose is to
bring the attributes of the attrset <code>A</code> into scope as
variables within the expression <code>E</code>. So instead of:</p>
<div class="sourceCode" id="cb1"><pre
class="sourceCode nix"><code class="sourceCode nix"><span id="cb1-1"><a href="#cb1-1" aria-hidden="true" tabindex="-1"></a><span class="op">[</span> pkgs<span class="op">.</span>foo pkgs<span class="op">.</span>bar pkgs<span class="op">.</span>baz <span class="op">]</span></span></code></pre></div>
<p>You can write:</p>
<div class="sourceCode" id="cb2"><pre
class="sourceCode nix"><code class="sourceCode nix"><span id="cb2-1"><a href="#cb2-1" aria-hidden="true" tabindex="-1"></a><span class="kw">with</span> pkgs<span class="op">;</span> <span class="op">[</span> foo bar baz <span class="op">]</span></span></code></pre></div>
<p>As a syntax sugar, this has the obvious advantages of making code
look shorter, and the obvious disadvantage of making it confusing.</p>
<h1 id="the-problem-with-with">‘The’ problem with <code>with</code></h1>
<p>A problem arises when there’s a conflict between a lexically bound
variable (‘normal’ various bound by <code>let</code> or a lambda
parameter) and something that’s bound by <code>with</code>:</p>
<div class="sourceCode" id="cb3"><pre
class="sourceCode nix"><code class="sourceCode nix"><span id="cb3-1"><a href="#cb3-1" aria-hidden="true" tabindex="-1"></a><span class="kw">let</span> <span class="va">a</span> <span class="op">=</span> <span class="dv">4</span><span class="op">;</span></span>
<span id="cb3-2"><a href="#cb3-2" aria-hidden="true" tabindex="-1"></a><span class="kw">in</span> <span class="kw">with</span> <span class="op">{</span> <span class="va">a</span> <span class="op">=</span> <span class="dv">3</span><span class="op">;</span> <span class="op">};</span> a</span></code></pre></div>
<p>An obvious way to resolve this would be to make this expression
evaluate to <code>3</code>. This comes with a price though: Lexical
scope would be broken. This is in fact the most commonly cited reason
that an almost equivalent construct, <code>with</code> in JavaScript, is
considered deprecated. (See <a
href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/with#ambiguity_contra">MDN</a>
for example.)</p>
<p>Since we’re talking about Nix, let’s imagine that Nix-lang worked
this way, <code>with</code> overriding normal variables. You have in
your code:</p>
<div class="sourceCode" id="cb4"><pre
class="sourceCode nix"><code class="sourceCode nix"><span id="cb4-1"><a href="#cb4-1" aria-hidden="true" tabindex="-1"></a><span class="kw">let</span> <span class="va">foobar</span> <span class="op">=</span> <span class="st">&quot;something&quot;</span><span class="op">;</span></span>
<span id="cb4-2"><a href="#cb4-2" aria-hidden="true" tabindex="-1"></a><span class="kw">in</span> <span class="kw">with</span> pkgs<span class="op">;</span></span>
<span id="cb4-3"><a href="#cb4-3" aria-hidden="true" tabindex="-1"></a>  <span class="co">/* ... */</span></span></code></pre></div>
<p>And next month, a package called <code>foobar</code> is added to
Nixpkgs. Your code would be broken.</p>
<p>Thankfully, that’s not what happens in nix-lang.</p>
<h1 id="the-solution-in-nix-lang">The solution in Nix-lang</h1>
<p>In nix-lang, <code>with</code> does <em>not</em> override lexically
bound variables. This example, in the real nix-lang, evaluates to
<code>4</code>:</p>
<div class="sourceCode" id="cb5"><pre
class="sourceCode nix"><code class="sourceCode nix"><span id="cb5-1"><a href="#cb5-1" aria-hidden="true" tabindex="-1"></a><span class="kw">let</span> <span class="va">a</span> <span class="op">=</span> <span class="dv">4</span><span class="op">;</span></span>
<span id="cb5-2"><a href="#cb5-2" aria-hidden="true" tabindex="-1"></a><span class="kw">in</span> <span class="kw">with</span> <span class="op">{</span> <span class="va">a</span> <span class="op">=</span> <span class="dv">3</span><span class="op">;</span> <span class="op">};</span> a</span></code></pre></div>
<p><code>with</code> simply <em>never</em> override something that’s
lexically bound. <code>with A; E</code> only affects variables in
<code>E</code> that are otherwise unbound.</p>
<h1 id="a-desugaring-of-with">A desugaring of <code>with</code></h1>
<p>This means that <code>with</code> in nix-lang is a purely syntactical
construct. You can eliminate all uses of <code>with</code> in an
expression without ever evaluating the code, because you don’t need
to.</p>
<p>The only thing changed is that an unbound variable, which would be a
syntax error, now becomes a reference to the attrset mentioned to
<code>with</code>.</p>
<p>So, to desugar <code>with</code>, look at each variable mentioned in
the code:</p>
<ul>
<li>If it’s lexically bound, leave it as is.</li>
<li>Otherwise, if there are no <code>with</code> constructs above it,
report an unbound variable.</li>
<li>Otherwise, take all the <code>with A;</code> that wraps this
variable, combine them together like <code>(A1 // A2 // A3)</code>, and
change the variable <code>v</code> into
<code>((A1 // A2 // A3).v)</code></li>
</ul>
<p>Some examples:</p>
<ul>
<li><p>Most common usage: Just let me type less stuff:</p>
<div class="sourceCode" id="cb6"><pre
class="sourceCode nix"><code class="sourceCode nix"><span id="cb6-1"><a href="#cb6-1" aria-hidden="true" tabindex="-1"></a><span class="co"># Before</span></span>
<span id="cb6-2"><a href="#cb6-2" aria-hidden="true" tabindex="-1"></a><span class="op">[</span> pkgs<span class="op">.</span>foo pkgs<span class="op">.</span>bar pkgs<span class="op">.</span>baz <span class="op">]</span></span>
<span id="cb6-3"><a href="#cb6-3" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb6-4"><a href="#cb6-4" aria-hidden="true" tabindex="-1"></a><span class="co"># After</span></span>
<span id="cb6-5"><a href="#cb6-5" aria-hidden="true" tabindex="-1"></a><span class="kw">with</span> pkgs<span class="op">;</span> <span class="op">[</span> foo bar baz <span class="op">]</span></span></code></pre></div></li>
<li><p>Lexical scoping is preserved</p>
<div class="sourceCode" id="cb7"><pre
class="sourceCode nix"><code class="sourceCode nix"><span id="cb7-1"><a href="#cb7-1" aria-hidden="true" tabindex="-1"></a><span class="co"># Before</span></span>
<span id="cb7-2"><a href="#cb7-2" aria-hidden="true" tabindex="-1"></a><span class="kw">let</span> <span class="va">a</span> <span class="op">=</span> <span class="dv">4</span><span class="op">;</span></span>
<span id="cb7-3"><a href="#cb7-3" aria-hidden="true" tabindex="-1"></a><span class="kw">in</span> <span class="kw">with</span> <span class="op">{</span> <span class="va">a</span> <span class="op">=</span> <span class="dv">3</span><span class="op">;</span> <span class="va">b</span> <span class="op">=</span> <span class="dv">4</span><span class="op">;</span> <span class="va">c</span> <span class="op">=</span> <span class="dv">5</span><span class="op">;</span> <span class="op">};</span> a <span class="op">+</span> b <span class="op">+</span> c</span>
<span id="cb7-4"><a href="#cb7-4" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb7-5"><a href="#cb7-5" aria-hidden="true" tabindex="-1"></a><span class="co"># After</span></span>
<span id="cb7-6"><a href="#cb7-6" aria-hidden="true" tabindex="-1"></a><span class="kw">let</span> <span class="va">a</span> <span class="op">=</span> <span class="dv">4</span><span class="op">;</span></span>
<span id="cb7-7"><a href="#cb7-7" aria-hidden="true" tabindex="-1"></a><span class="kw">in</span> a <span class="op">+</span> <span class="op">({</span> <span class="va">a</span> <span class="op">=</span> <span class="dv">3</span><span class="op">;</span> <span class="va">b</span> <span class="op">=</span> <span class="dv">4</span><span class="op">;</span> <span class="op">}.</span>b<span class="op">)</span> <span class="op">+</span> <span class="op">({</span> <span class="va">a</span> <span class="op">=</span> <span class="dv">3</span><span class="op">;</span> <span class="va">b</span> <span class="op">=</span> <span class="dv">4</span><span class="op">;</span> <span class="op">}.</span>c<span class="op">)</span></span></code></pre></div></li>
</ul>
<h1 id="well-technically">Well technically…</h1>
<p>There’s a small mistake with the translation above. You can’t just
copy verbatim the attrset used in <code>with</code> into each usage,
because the <code>with</code> dictionary is only evaluated once. This
hardly matters ever, but ideally, the latter example should be
translated into something like: (Where <code>__with_1</code> is a fresh
variable)</p>
<div class="sourceCode" id="cb8"><pre
class="sourceCode nix"><code class="sourceCode nix"><span id="cb8-1"><a href="#cb8-1" aria-hidden="true" tabindex="-1"></a><span class="kw">let</span> <span class="va">a</span> <span class="op">=</span> <span class="dv">4</span><span class="op">;</span></span>
<span id="cb8-2"><a href="#cb8-2" aria-hidden="true" tabindex="-1"></a><span class="kw">in</span> <span class="kw">let</span> <span class="va">__with_1</span> <span class="op">=</span> <span class="op">{</span> <span class="va">a</span> <span class="op">=</span> <span class="dv">3</span><span class="op">;</span> <span class="va">b</span> <span class="op">=</span> <span class="dv">4</span><span class="op">;</span> <span class="va">c</span> <span class="op">=</span> <span class="dv">5</span><span class="op">;</span> <span class="op">};</span></span>
<span id="cb8-3"><a href="#cb8-3" aria-hidden="true" tabindex="-1"></a>  <span class="kw">in</span> a <span class="op">+</span> __with_1<span class="op">.</span>b <span class="op">+</span> __with_1<span class="op">.</span>c</span></code></pre></div>
<p>Imagine that instead of <code>{ a = 3; b = 4; c = 5; }</code> there
is a complicated computation. The naive translation would duplicate this
computation, which is probably undesirable. This case occurs in the
commonly used pattern:</p>
<div class="sourceCode" id="cb9"><pre
class="sourceCode nix"><code class="sourceCode nix"><span id="cb9-1"><a href="#cb9-1" aria-hidden="true" tabindex="-1"></a><span class="kw">with</span> <span class="op">(</span><span class="bu">import</span> &lt;nixpkgs&gt; <span class="op">{});</span> <span class="co">/* ... */</span></span></code></pre></div>
<h1 id="so-should-we-use-with">So should we use <code>with</code>?</h1>
<p>Be careful. The fact that <code>with</code> modifies the behavior of
unbound variables instead of all variables is arguably an improvement
over the now deprecated JavaScript <code>with</code>. But it still
modifies the behavior of unbound variables.</p>
<p>Given the possibly confusing behavior, I personally only use
<code>with</code> in certain circumstances in which I’m familiar
<em>with</em> the consequences, like:</p>
<div class="sourceCode" id="cb10"><pre
class="sourceCode nix"><code class="sourceCode nix"><span id="cb10-1"><a href="#cb10-1" aria-hidden="true" tabindex="-1"></a>environment<span class="op">.</span>systemPackages = <span class="kw">with</span> pkgs<span class="op">;</span> <span class="op">[</span> foo bar baz <span class="op">]</span>;</span>
<span id="cb10-2"><a href="#cb10-2" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb10-3"><a href="#cb10-3" aria-hidden="true" tabindex="-1"></a>meta = <span class="kw">with</span> lib<span class="op">;</span> <span class="op">{</span> <span class="co">/* ... */</span> <span class="op">}</span>;</span>
<span id="cb10-4"><a href="#cb10-4" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb10-5"><a href="#cb10-5" aria-hidden="true" tabindex="-1"></a>helperFunction = <span class="kw">with</span> <span class="bu">builtins</span><span class="op">;</span> <span class="co">/* use builtins here */</span></span></code></pre></div>
<p>I don’t really like <code>with (import &lt;nixpkgs&gt; {});</code>,
but admittedly, I sometimes get sloppy and use it.</p>
<p>Hopefully, equipped <em>with</em> a better understanding of what
nix-lang’s <code>with</code> does, you know what you want to do
<em>with</em> it.</p>
<p>I probably already annoyed you <em>with</em> all those
<code>with</code> jokes. I’m going to stop.</p>]]></description>
    </item>
    <item>
        <title>Untitled router：一个路由器的故事</title>
        <pubDate>Thu, 31 Dec 2020 00:00:00 +0000</pubDate>
        <guid isPermaLink="true">https://dram.page/p/untitled-router</guid>
        <description><![CDATA[<p>（大概是这一年里做的还算有意义的一件事）</p>
<h2 id="一次命运转折的约饭">一次命运转折的约饭</h2>
<p>2020
年秋季开学之前的什么时候，在一次约饭的时候，正好和一些计算机系专业课的助教说到这学期要参加的一些课程的事情。</p>
<p>根据课程的安排（可参见<a
href="https://harrychen.xyz/2020/06/20/cs-course-reform/">也谈课改——以网原为例</a>一文），两门比较硬核的专业课：计算机组成原理和计算机网络原理（简称<strong>计原</strong>和<strong>网原</strong>而不是什么乱七八糟的东西）作为两门实验项目改动比较大的专业课，现在大概是如下的情况：</p>
<ul>
<li>从 2020
年开始，计原课程的“奋战三星期，造台计算机”与国际先进技术接轨，又原来的
MIPS 架构改为 RISC-V
架构。当然造机这件事是不变的，三人一组做一个软核。这里有两个小故事：
<ul>
<li>之前假期的时候在 ICFP 的时候在神秘的 Coffee break room
聊的时候，有人就提到 MIPS 架构已经凉了。虽然还能买到 MIPS
的芯片和产品，但是已经不再有新的发展了。</li>
<li>有一位同学在上课之前尝试翻了下往年题目，发现了关于分支延迟槽的问题，于是在群里问这个可以在哪儿学到。这位同学可能需要一个时光机。</li>
</ul></li>
<li>从 2019
年开始，网原课程的大实验是自己造路由器，分为软件实验和硬件实验两个
track。2020 年的具体情况如下：
<ul>
<li>软件实验是每组 3 位同学，每人做一个路由器，然后测试时使用在线平台的
Raspberry Pi
运行，通过交换机的虚拟连接测试在给定网络拓扑下的性能和功能。</li>
<li>硬件实验是每组 3 位同学，一起做一个路由器。今年的要求是在一个 FPGA
上完成大部分转发相关的内容，然后在计原实验里造的软核 CPU 上运行 RIPv2
动态路由协议相关的处理，也就是说相当于三个人一起做了两个课的实验，当然要求显然是高于软件实验的。因为包含了计原和网原两个课的内容，所以被称为“计网联合实验”。</li>
</ul></li>
</ul>
<p>其中一位助教建议我参加联合实验。考虑到我之前并没有参加前面的硬件相关的数字逻辑课程，我一再说这可能是误解了我的水平，但是看来这位助教对我还是很有信心的。</p>
<p>后来和找到的两位朋友 akyuu 和 pwe
组成了小组，说了这些事情之后，我们按照课程要求报了名，通过一个（看来比较主观但并不是没有道理的）“选拔”，正式加入了联合实验的队伍。</p>
<h2 id="摸鱼和赶工的几周">摸鱼和赶工的几周</h2>
<p>联合实验是每周的一个晚上开一次会，讨论上周的工作，布置下周的任务。佛系的我们最开始是每周大概约一个研讨间待上个好久，后来直接在宿舍的活动室工作了。</p>
<p>由于摸鱼比较严重，我们经常是赶在晚上开会当天才做完，最神奇的一次是从研讨间出来之后，已经还有大概只半个小时左右就要开会了，只能飞奔赶往。</p>
<p>暂时先不说技术细节了，感觉没什么特别的，可能以后再讲吧。</p>
<p>感觉在造机之前的那段时间里，其实是最开始的时候做那些比较基础的功能的时候比较头疼，因为确实没有做过什么硬件和网络相关的东西，需要熟悉整个流程、AXI
Stream 协议，一些 workflow
相关的事情等，以及做出来的东西的可见性较差，不太能直观感受到进度。</p>
<p>在我们完成转发引擎的那个晚上，我提议跑一个 HTTP 服务器通过我们的 FPGA
路由下载一个文件。当我们看到 <code>python3 -m http.server</code>
的页面，以及成功下载了一个文件的时候，至少我当时非常高兴，感觉到自己至少做了一个可以在一定程度上接入现有的环境中作为
infrastructure 的一个东西。</p>
<p>或者简单来说就是，它通了。</p>
<p>那天晚上在宿舍活动室，我们组的三人对着一个 effectively
就是一根超级贵的网线的板子，庆祝了好久。</p>
<p>当然，我们也有不太顺利的时候。中间有一段时间，我们发现转发部分的逻辑有性能问题，十分困惑，改的时候也很头疼，越改性能越差，改着改着干脆就不通了。试了很多种方式才最终搞定。</p>
<h2 id="造机的三周">造机的三周</h2>
<p>硬件实验，造机还是得造的。</p>
<p>在硬件的设计方面，我们做的是一个 <a
href="https://en.wikipedia.org/wiki/Classic_RISC_pipeline">Classic RISC
pipeline</a>
的五级流水线设计，这点上没有什么特别的。在具体的一些细节上实际上参考了之前路由器的数据处理流水线，以及喵喵的一些建议，没有按照传统的方式设计控制器，而是使用
<code>ready/valid</code>
握手和总线仲裁协调各个流水线级的工作。在之后的一些调整设计、修改实现的过程中，虽然不是很明显，但是还是能感受到这样的一个设计所带来的方便，因此我觉得这是一个比较科学的做法。</p>
<p>总线我们使用了一个相当于 <a
href="https://www.wishbone-interconnect.org">Wishbone Classic</a>
的总线协议，当然没有使用现有的组件，而是自己实现了访存、外设、仲裁、互联的模块。本来最开始想做的是
Pipelined
模式的总线，但是实在是没做出来就放弃了。在总线相关的事情上，我也在和一些课程的编外人员（“不是助教”）讨论，要不要在硬件相关的实验中加入总线协议的内容，使大家的设计可以互联互通。</p>
<p>不知道是不是 Stolkhome Syndrome 的原因，我现在真的非常喜欢 RISC-V
的指令集。</p>
<p>如果更客观的来说，我之前曾经也想过自己做一个 CPU。之前我曾经做过一个
6502 的模拟器，可以运行一个简单的 BASIC 解释器；也尝试用 Clash
做过一些神秘的小指令集的
CPU，但是由于设计方面实在是不知道如何下手最终搁置了。</p>
<p>而 RISC-V 实际上是一个美妙的机会，三周实现的 RISC-V RV32I
的大部分指令，实际上相当于已经是一个 <code>riscv32-none</code>
的裸机，可以使用现有的工具链。RISC-V
的活跃的社区意味着这些工具不是祖传的 legacy，而是最新的成果。</p>
<p>或许这就是开放的社区的意义所在吧。</p>
<h2 id="意外顺利的又几周">意外顺利的又几周</h2>
<p>当然，说是意外顺利，可能更恰当的说法是有些意外，有些顺利。</p>
<p>CPU 与路由器的集(feng)成(he)从把 CPU 的总线和基于 AXI Stream
的数据平面连接开始。在这点上折腾了很久都没搞定，最后发现是别的地方写出锅了。之后逐渐的我们把路由部分的逻辑中需要软件访问的部分，以及收发以太网帧的都作为
MMIO 接入到了总线上。</p>
<p>队友也参考提供好的模板完成了 RIP
协议的软件，在本地测试了一下，看起来可以和 BIRD 互操作。</p>
<p>（有一次聊天的时候意外发现，VGA 用的 framebuffer
直接复制过来就是以太网 framebuffer，名字都不用改。）</p>
<p>这段时间我的状态也不是很好，主要还是靠两位队友 carry
的大部分硬件工作和全部软件工作，作为组长的 dram
就一直在划水。这里我要真诚感谢一下队友，感谢一下助教和不是助教，也要感谢此时以及支持我的所有人。</p>
<h2 id="验收工作">验收工作</h2>
<p>随着千兆网络测速仪的研制成功，我们还是发现了一些大大小小的
bug，但是修起来还不是那么难。有两个到现在也没太搞明白的问题，一个是软件部分有一段似乎不太能正常运行，需要加上一些没用的代码，另一块是软件接收到的以太网帧出现被截断的问题，在换了一些写法之后似乎没有再遇到相同的现象，所以也没有追究。</p>
<p>到最后验收还是花了不少时间，不过比较高兴的是，最终测试环境的各种网络拓扑下的路由器工作都比较顺利。其中有一个测试是将三个路由器接成一个环，然后移除其中两个路由器之间的链路，过一段时间再恢复链路，来测试
RIP
动态路由协议的工作状况。由于之前说到我一直在划水，其实我是不知道软件是个什么情况的。连软件担当的队友都表示没想到写的东西能正常完成错误恢复。</p>
<p>验收完成之后，我三人一起去吃了一顿烤肉。</p>
<h2 id="造机的答辩">造机的答辩</h2>
<p>2020 年 12 月 19 号是造机的答辩，作为第 5
组，在别的组答辩的时候，我们组的群里依次出现了 <code>v3</code> 到
<code>v10</code> 的 slides，页数从 25 增长到了 31。</p>
<p>答辩的整体过程都是我在说，不知道是紧张还是怕 31 页 10
分钟时间不够的原因，我的语速特别快。</p>
<p>答辩的全程好像有人来录像，以及听说有造机队伍来采访了某位队友。看来这些写新闻的对造机的工作不是很了解吧，至少我觉得最后写出来的推送并没有展现出我们实际完成了什么工作，从评论区也可以看出来大家没太理解我们在做什么。评论区有一个家长自称孩子
11
岁，想找个指导老师做一下这个三周造机之类的。倒不一定是技术难度问题，给这年纪孩子做点什么不好，来造机干啥……</p>
<p>另外，在答辩的最后，我插播了一段私货。事实上，这段私货的内容是我前一天的晚上才准备好的，当时事实上紧急叫了几个朋友帮忙看看有没有什么写的不太妙的地方，做了一些细微修改。这段在演讲的时候，内容我自己有所发挥，但是大致的文字内容是前一天写好的，在此：</p>
<blockquote>
<p>Claire Wolf 是 RISC-V B
扩展指令规范的主编，我们每个组的三个扩展指令就选自这里。她除此之外对开源的数字逻辑工具有很大贡献，包括开源的
HDL 工具 Yosys 等。</p>
<p>大家可能注意到我们下发的 bitmanip 规范的待定稿的作者的名字写的是
Clifford Wolf。如果大家有关注过这个人的话，就会知道这位 RISC-V
社区的重量级人物是一位跨性别者，在去年的大概这个时候正式以女性的身份出现在大家面前，包括将自己的名字改为
Claire。</p>
<p>我本人至少是非常敬佩她的。我想起不记得在哪里看到的一句话：RISC-V
给大家一个公平的起跑线。我希望这个公平的起跑线，不仅在技术上给大家一个开放的环境，不被当前
CPU
核心设计领域当前的近乎垄断的现状限制住，而且能让我们这些搞科技和学术的不被那些无关的事情所困扰，能够真正展现出自己的水平。</p>
<p>近来发生的一些跨性别者受到不正当对待事情，大家可能已经听说过了。我其实一直比较愧疚，没有做什么事情来给予帮助。希望今天我所说的至少能引起大家对这些群体以及这些事件的一些关注和思考。我觉得对于大部分人来说，尽量去理解，就已经是很好地在支持了。</p>
</blockquote>
<p>结束之后，一位助教指出，网络测试仪在两个 FPGA 之间通信所使用的协议 <a
href="https://github.com/cliffordwolf/PonyLink">PonyLink</a> 也是 Claire
Wolf
的作品。大部分人可能并不能理解这样一个身份所带来的痛苦，但是至少我们作为技术人员，能够谈论的是一个人所做的贡献，而不是一些无关的处境或者身份问题，这其实正是我想看到的。</p>
<h2 id="最终答辩">最终答辩</h2>
<p>最终的答辩计划在 2021 年 1 月 12
号进行，那时可能会进行组间的联通测试。</p>
<p>上午是，见到了很多助教和上一届联合实验的同学，聊了很多有趣的事情和无聊的事情。</p>
<p>下午的测试非常迷惑，各种问题，可以参见<a
href="https://twd2.me/archives/15187">助教 twd2 的博客</a>。</p>
<blockquote>
<p>某网络专家对此评价为“群魔乱舞”。</p>
</blockquote>]]></description>
    </item>
    <item>
        <title>Counting empty triangles with number theory</title>
        <pubDate>Sun, 31 May 2020 00:00:00 +0000</pubDate>
        <guid isPermaLink="true">https://dram.page/p/empty-triangles</guid>
        <description><![CDATA[<p><em>This is a writeup of the Codewars
kata <a
href="https://www.codewars.com/kata/count-empty-triangles-in-the-future/">‘Count
Empty Triangles in the Future’</a>. You can see <a
href="https://www.codewars.com/kata/reviews/5c77022ab9e5260001c6eaee/groups/5ed20453b5d4a00001e0270d">the
solution code I submitted</a> if you solve it in C++ (or
forfeit…).</em></p>
<h2 id="the-problem-statement">The problem statement</h2>
<p>On a grid with width
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mi>m</mi><annotation encoding="application/x-tex">m</annotation></semantics></math>
and height
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mi>n</mi><annotation encoding="application/x-tex">n</annotation></semantics></math>,
how many triangles have lattice points as vertices but otherwise have no
lattice points on the edges and interiors? (Such triangles are called
‘empty’.) Find the answer modulo
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msup><mn>10</mn><mn>9</mn></msup><mo>+</mo><mn>7</mn></mrow><annotation encoding="application/x-tex">10^9 + 7</annotation></semantics></math>.</p>
<p>For example, for
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>m</mi><mo>=</mo><mn>1</mn></mrow><annotation encoding="application/x-tex">m = 1</annotation></semantics></math>
and
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>n</mi><mo>=</mo><mn>2</mn></mrow><annotation encoding="application/x-tex">n = 2</annotation></semantics></math>,
the
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mn>12</mn><annotation encoding="application/x-tex">12</annotation></semantics></math>
empty triangles by shape and multiplicity are given below: (Image from
kata description.)</p>
<figure>
<img src="images/example.png" style="width:90.0%"
alt="Example from kata" />
<figcaption aria-hidden="true">Example from kata</figcaption>
</figure>
<h2 id="geometry-part">Geometry part</h2>
<p>According to <a
href="https://en.wikipedia.org/wiki/Pick%27s_theorem">Pick’s
theorem</a>, a triangle with lattice point vertices has area:
<math display="block" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>A</mi><mo>=</mo><mi>i</mi><mo>+</mo><mfrac><mi>e</mi><mn>2</mn></mfrac><mo>+</mo><mfrac><mn>1</mn><mn>2</mn></mfrac></mrow><annotation encoding="application/x-tex">
A =i + \frac{e}{2} + \frac{1}{2}
</annotation></semantics></math> Where
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mi>i</mi><annotation encoding="application/x-tex">i</annotation></semantics></math>
is the number of lattice points on the interior (not counting edges),
and
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mi>e</mi><annotation encoding="application/x-tex">e</annotation></semantics></math>
is the number of points on the edges (not counting vertices). Therefore
triangle is empty iff its area is
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mn>1</mn><mi>/</mi><mn>2</mn></mrow><annotation encoding="application/x-tex">1/2</annotation></semantics></math>
and its vertices are lattice points. (For the sake of brevity we always
work with lattice points from now on.)</p>
<p>Intuitively, empty triangles have a relatively ‘thin’ shape. The
longer edges get, the ‘thinner’ the triangle gets. An exact useful bound
in the ‘thickness’ of an empty triangle be encapsulated in this
lemma:</p>
<p><strong>Lemma</strong>: For an empty triangle, two of its vertices
coincide with opposite corners of its bounding box.</p>
<p><em>Proof</em>: Pick the leftmost point
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mi>A</mi><annotation encoding="application/x-tex">A</annotation></semantics></math>
and rightmost point
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mi>B</mi><annotation encoding="application/x-tex">B</annotation></semantics></math>
of a triangle. (If there is a tie, pick an arbitrary one.)</p>
<figure>
<img src="images/bounding-box.svg" style="width:80.0%"
alt="A triangle in its bounding box" />
<figcaption aria-hidden="true">A triangle in its bounding
box</figcaption>
</figure>
<p>Without loss of generality, we assume that
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mi>B</mi><annotation encoding="application/x-tex">B</annotation></semantics></math>
is higher than or level with
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mi>A</mi><annotation encoding="application/x-tex">A</annotation></semantics></math>,
and
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mi>C</mi><annotation encoding="application/x-tex">C</annotation></semantics></math>
is above the line segment
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>A</mi><mi>B</mi></mrow><annotation encoding="application/x-tex">AB</annotation></semantics></math>.
Construct a vertical line through
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mi>C</mi><annotation encoding="application/x-tex">C</annotation></semantics></math>,
intersecting
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>A</mi><mi>B</mi></mrow><annotation encoding="application/x-tex">AB</annotation></semantics></math>
at
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mi>D</mi><annotation encoding="application/x-tex">D</annotation></semantics></math>
as shown. Let
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>h</mi><mo>=</mo><mrow><mo stretchy="true" form="prefix">|</mo><mi>C</mi><mi>D</mi><mo stretchy="true" form="postfix">|</mo></mrow></mrow><annotation encoding="application/x-tex">h = \left|CD\right|</annotation></semantics></math>
and let
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mi>m</mi><annotation encoding="application/x-tex">m</annotation></semantics></math>
be the horizontal distance between
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mi>A</mi><annotation encoding="application/x-tex">A</annotation></semantics></math>
and
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mi>B</mi><annotation encoding="application/x-tex">B</annotation></semantics></math>.
Then the area of
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>△</mi><mi>A</mi><mi>B</mi><mi>C</mi></mrow><annotation encoding="application/x-tex">\triangle ABC</annotation></semantics></math>
is
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>h</mi><mi>m</mi><mi>/</mi><mn>2</mn></mrow><annotation encoding="application/x-tex">hm/2</annotation></semantics></math>.
This can be shown by constructing a horizontal line through
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mi>D</mi><annotation encoding="application/x-tex">D</annotation></semantics></math>
intersecting the bounding box on the side of
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mi>A</mi><annotation encoding="application/x-tex">A</annotation></semantics></math>
at
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mi>E</mi><annotation encoding="application/x-tex">E</annotation></semantics></math>,
and on the side of
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mi>B</mi><annotation encoding="application/x-tex">B</annotation></semantics></math>
at
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mi>F</mi><annotation encoding="application/x-tex">F</annotation></semantics></math>,
then
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>△</mi><mi>C</mi><mi>D</mi><mi>E</mi><mo>=</mo><mi>△</mi><mi>C</mi><mi>D</mi><mi>A</mi></mrow><annotation encoding="application/x-tex">\triangle CDE = \triangle CDA</annotation></semantics></math>
and
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>△</mi><mi>C</mi><mi>D</mi><mi>F</mi><mo>=</mo><mi>△</mi><mi>C</mi><mi>D</mi><mi>B</mi></mrow><annotation encoding="application/x-tex">\triangle CDF = \triangle CDB</annotation></semantics></math>.
Then:</p>
<p><math display="block" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mtable><mtr><mtd columnalign="right" style="text-align: right; padding-right: 0"><mi>△</mi><mi>A</mi><mi>B</mi><mi>C</mi></mtd><mtd columnalign="left" style="text-align: left; padding-left: 0"><mo>=</mo><mi>△</mi><mi>C</mi><mi>D</mi><mi>A</mi><mo>+</mo><mi>△</mi><mi>C</mi><mi>D</mi><mi>B</mi></mtd></mtr><mtr><mtd columnalign="right" style="text-align: right; padding-right: 0"></mtd><mtd columnalign="left" style="text-align: left; padding-left: 0"><mo>=</mo><mi>△</mi><mi>C</mi><mi>D</mi><mi>E</mi><mo>+</mo><mi>△</mi><mi>C</mi><mi>D</mi><mi>F</mi></mtd></mtr><mtr><mtd columnalign="right" style="text-align: right; padding-right: 0"></mtd><mtd columnalign="left" style="text-align: left; padding-left: 0"><mo>=</mo><mi>△</mi><mi>C</mi><mi>E</mi><mi>F</mi></mtd></mtr><mtr><mtd columnalign="right" style="text-align: right; padding-right: 0"></mtd><mtd columnalign="left" style="text-align: left; padding-left: 0"><mo>=</mo><mi>h</mi><mi>m</mi><mi>/</mi><mn>2</mn></mtd></mtr></mtable><annotation encoding="application/x-tex">
\begin{split}
\triangle ABC &amp;= \triangle CDA + \triangle CDB \\
&amp;= \triangle CDE + \triangle CDF \\
&amp;= \triangle CEF \\
&amp;= hm/2
\end{split}
</annotation></semantics></math></p>
<p>(Where clear from context
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>△</mi><mi>X</mi><mi>Y</mi><mi>Z</mi></mrow><annotation encoding="application/x-tex">\triangle XYZ</annotation></semantics></math>
represents the triangle’s area)</p>
<p>Therefore if
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>△</mi><mi>A</mi><mi>B</mi><mi>C</mi></mrow><annotation encoding="application/x-tex">\triangle ABC</annotation></semantics></math>
is empty, then
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>h</mi><mi>m</mi><mo>=</mo><mn>1</mn></mrow><annotation encoding="application/x-tex">hm = 1</annotation></semantics></math>.
If
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mi>C</mi><annotation encoding="application/x-tex">C</annotation></semantics></math>
is within the rectangle with
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mi>A</mi><annotation encoding="application/x-tex">A</annotation></semantics></math>
and
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mi>B</mi><annotation encoding="application/x-tex">B</annotation></semantics></math>
as corners (including boundaries), then it satisfies the desired
conclusion.</p>
<p>Otherwise
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mi>C</mi><annotation encoding="application/x-tex">C</annotation></semantics></math>
is above
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mi>B</mi><annotation encoding="application/x-tex">B</annotation></semantics></math>,
and since they are lattice points,
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mi>C</mi><annotation encoding="application/x-tex">C</annotation></semantics></math>
must be at least
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mn>1</mn><annotation encoding="application/x-tex">1</annotation></semantics></math>
unit higher than
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mi>B</mi><annotation encoding="application/x-tex">B</annotation></semantics></math>,
therefore
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>h</mi><mo>≥</mo><mn>1</mn></mrow><annotation encoding="application/x-tex">h \ge 1</annotation></semantics></math>.
But we already have
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>m</mi><mo>≥</mo><mn>1</mn></mrow><annotation encoding="application/x-tex">m \ge 1</annotation></semantics></math>,
so it must be the case that
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>h</mi><mo>=</mo><mi>m</mi><mo>=</mo><mn>1</mn></mrow><annotation encoding="application/x-tex">h = m = 1</annotation></semantics></math>.
Then one of
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>C</mi><mi>A</mi></mrow><annotation encoding="application/x-tex">CA</annotation></semantics></math>
and
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>C</mi><mi>B</mi></mrow><annotation encoding="application/x-tex">CB</annotation></semantics></math>
is vertical.</p>
<ul>
<li>If
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>C</mi><mi>A</mi></mrow><annotation encoding="application/x-tex">CA</annotation></semantics></math>
is vertical, then
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mrow><mo stretchy="true" form="prefix">|</mo><mi>C</mi><mi>A</mi><mo stretchy="true" form="postfix">|</mo></mrow><mo>=</mo><mi>h</mi><mo>=</mo><mn>1</mn></mrow><annotation encoding="application/x-tex">\left|CA\right| = h = 1</annotation></semantics></math>.
We are now constrained in a
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mn>1</mn><mo>×</mo><mn>1</mn></mrow><annotation encoding="application/x-tex">1 \times 1</annotation></semantics></math>
box, in which the only possible triangle shape of edge lengths
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mo stretchy="false" form="prefix">(</mo><mn>1</mn><mo>,</mo><mn>1</mn><mo>,</mo><msqrt><mn>2</mn></msqrt><mo stretchy="false" form="postfix">)</mo></mrow><annotation encoding="application/x-tex">(1, 1, \sqrt{2})</annotation></semantics></math>
indeed has two vertices as corners of its bounding box.</li>
<li>If
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>C</mi><mi>B</mi></mrow><annotation encoding="application/x-tex">CB</annotation></semantics></math>
is vertical, then
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mi>A</mi><annotation encoding="application/x-tex">A</annotation></semantics></math>
and
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mi>C</mi><annotation encoding="application/x-tex">C</annotation></semantics></math>
are corners of the bounding box of
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>△</mi><mi>A</mi><mi>B</mi><mi>C</mi></mrow><annotation encoding="application/x-tex">\triangle ABC</annotation></semantics></math></li>
</ul>
<p>Thus concludes the proof of this lemma.</p>
<p>Now we only need to find, for each possible bounding box size, the
number of empty triangles that fits exactly into this bounding box.
There are four completely symmetric ways to fit an empty triangle into
its, depending which diagonal the triangle’s two points ‘outer’ points
sit on, and on which side the third ‘inner’ point lies. Here’s the four
cases illustrated, where in each case the shown diagonal is one edge of
the triangle, and the other vertex is in the shaded region.</p>
<figure>
<img src="images/rectangle-cut.svg" style="width:90.0%"
alt="The four cases" />
<figcaption aria-hidden="true">The four cases</figcaption>
</figure>
<p>Therefore we can just calculate one case and multiply the answer by
four. Let’s put one case at the origin like this:</p>
<figure>
<img src="images/intersect.svg" style="width:70.0%"
alt="Solving for a certain size" />
<figcaption aria-hidden="true">Solving for a certain size</figcaption>
</figure>
<p>Supposed the rectangle has width
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mi>m</mi><annotation encoding="application/x-tex">m</annotation></semantics></math>
and height
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mi>n</mi><annotation encoding="application/x-tex">n</annotation></semantics></math>.
Similar to what has been shown while proving the lemma, for the area of
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>△</mi><mi>A</mi><mi>B</mi><mi>C</mi></mrow><annotation encoding="application/x-tex">\triangle ABC</annotation></semantics></math>
to be
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mn>1</mn><mi>/</mi><mn>2</mn></mrow><annotation encoding="application/x-tex">1/2</annotation></semantics></math>,
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mi>C</mi><annotation encoding="application/x-tex">C</annotation></semantics></math>
must lie on a line that is
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>A</mi><mi>B</mi></mrow><annotation encoding="application/x-tex">AB</annotation></semantics></math>
shifted down by
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mn>1</mn><mi>/</mi><mi>m</mi></mrow><annotation encoding="application/x-tex">1/m</annotation></semantics></math>,
and it must also be a lattice point. The equation of line
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>A</mi><mi>B</mi></mrow><annotation encoding="application/x-tex">AB</annotation></semantics></math>
is:
<math display="block" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mfrac><mi>x</mi><mi>m</mi></mfrac><mo>+</mo><mfrac><mi>y</mi><mi>n</mi></mfrac><mo>=</mo><mn>1</mn></mrow><annotation encoding="application/x-tex">
\frac{x}{m} + \frac{y}{n} = 1
</annotation></semantics></math> And therefore that of the shifted line
is:
<math display="block" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mtable><mtr><mtd columnalign="right" style="text-align: right; padding-right: 0"><mfrac><mi>x</mi><mi>m</mi></mfrac><mo>+</mo><mfrac><mrow><mi>y</mi><mo>+</mo><mn>1</mn><mi>/</mi><mi>m</mi></mrow><mi>n</mi></mfrac></mtd><mtd columnalign="left" style="text-align: left; padding-left: 0"><mo>=</mo><mn>1</mn></mtd></mtr><mtr><mtd columnalign="right" style="text-align: right; padding-right: 0"><mi>n</mi><mi>x</mi><mo>+</mo><mi>m</mi><mi>y</mi><mo>+</mo><mn>1</mn></mtd><mtd columnalign="left" style="text-align: left; padding-left: 0"><mo>=</mo><mi>m</mi><mi>n</mi></mtd></mtr><mtr><mtd columnalign="right" style="text-align: right; padding-right: 0"><mi>m</mi><mo stretchy="false" form="prefix">(</mo><mi>n</mi><mo>−</mo><mi>y</mi><mo stretchy="false" form="postfix">)</mo><mo>+</mo><mi>n</mi><mo stretchy="false" form="prefix">(</mo><mi>−</mi><mi>x</mi><mo stretchy="false" form="postfix">)</mo></mtd><mtd columnalign="left" style="text-align: left; padding-left: 0"><mo>=</mo><mn>1</mn></mtd></mtr></mtable><annotation encoding="application/x-tex">
\begin{align}
\frac{x}{m} + \frac{y + 1/m}{n} &amp;= 1 \\
nx + my + 1 &amp;= mn \\
m(n - y) + n(- x) &amp;= 1
\end{align}
</annotation></semantics></math> <a
href="https://en.wikipedia.org/wiki/B%C3%A9zout%27s_identity">Bézout’s
identity</a> tells us that there are solutions if and only if
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mrow><mi>gcd</mi><mo>&#8289;</mo></mrow><mo stretchy="false" form="prefix">(</mo><mi>m</mi><mo>,</mo><mi>n</mi><mo stretchy="false" form="postfix">)</mo><mo>=</mo><mn>1</mn></mrow><annotation encoding="application/x-tex">\gcd(m, n) = 1</annotation></semantics></math>.
We are interested in only solutions in the region
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mn>0</mn><mo>≤</mo><mi>x</mi><mo>&lt;</mo><mi>m</mi></mrow><annotation encoding="application/x-tex">0 \le x &lt; m</annotation></semantics></math>
and
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mn>0</mn><mo>≤</mo><mi>y</mi><mo>&lt;</mo><mi>n</mi></mrow><annotation encoding="application/x-tex">0 \le y &lt; n</annotation></semantics></math>.
Given one solution
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mo stretchy="false" form="prefix">(</mo><mi>x</mi><mo>=</mo><msub><mi>x</mi><mn>0</mn></msub><mo>,</mo><mi>y</mi><mo>=</mo><msub><mi>y</mi><mn>0</mn></msub><mo stretchy="false" form="postfix">)</mo></mrow><annotation encoding="application/x-tex">(x=x_{0},y=y_{0})</annotation></semantics></math>,
the general solution is
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mo stretchy="false" form="prefix">(</mo><mi>x</mi><mo>=</mo><msub><mi>x</mi><mn>0</mn></msub><mo>+</mo><mi>k</mi><mi>m</mi><mo>,</mo><mi>y</mi><mo>=</mo><msub><mi>y</mi><mn>0</mn></msub><mo>−</mo><mi>k</mi><mi>n</mi><mo stretchy="false" form="postfix">)</mo></mrow><annotation encoding="application/x-tex">(x = x_0 + km,y = y_0 - kn)</annotation></semantics></math>
where
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mi>k</mi><annotation encoding="application/x-tex">k</annotation></semantics></math>
is any integer. There is a unique solution
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mo stretchy="false" form="prefix">(</mo><mi>x</mi><mo>=</mo><msub><mi>x</mi><mn>0</mn></msub><mo>+</mo><mo stretchy="false" form="prefix">⌊</mo><msub><mi>y</mi><mn>0</mn></msub><mi>/</mi><mi>n</mi><mo stretchy="false" form="postfix">⌋</mo><mi>m</mi><mo>,</mo><mi>y</mi><mo>=</mo><msub><mi>y</mi><mn>0</mn></msub><mrow><mspace width="0.222em"></mspace><mrow><mi>mod</mi><mo>&#8289;</mo></mrow><mspace width="0.222em"></mspace><mi>n</mi></mrow><mo stretchy="false" form="postfix">)</mo></mrow><annotation encoding="application/x-tex">(x = x_0 + \lfloor y_0 / n \rfloor m, y = y_0 \bmod n)</annotation></semantics></math>
that lies within the region. This can be shown first by noting that
euclidean division of integers gives a unique
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mn>0</mn><mo>≤</mo><mi>y</mi><mo>&lt;</mo><mi>n</mi></mrow><annotation encoding="application/x-tex">0 \le y &lt; n</annotation></semantics></math>
such that for some integer
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mi>k</mi><annotation encoding="application/x-tex">k</annotation></semantics></math>,
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msub><mi>y</mi><mn>0</mn></msub><mo>=</mo><mi>k</mi><mi>n</mi><mo>+</mo><mi>y</mi></mrow><annotation encoding="application/x-tex">y_0 = kn+y</annotation></semantics></math>.
Then we verify that
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>x</mi><mo>≥</mo><mn>0</mn></mrow><annotation encoding="application/x-tex">x \ge 0</annotation></semantics></math>,
which shows that the solution is inside the region we want:</p>
<p><math display="block" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mtable><mtr><mtd columnalign="right" style="text-align: right; padding-right: 0"><mi>x</mi></mtd><mtd columnalign="left" style="text-align: left; padding-left: 0"><mo>=</mo><msub><mi>x</mi><mn>0</mn></msub><mo>+</mo><mo stretchy="false" form="prefix">⌊</mo><mfrac><msub><mi>y</mi><mn>0</mn></msub><mi>n</mi></mfrac><mo stretchy="false" form="postfix">⌋</mo><mi>m</mi></mtd></mtr><mtr><mtd columnalign="right" style="text-align: right; padding-right: 0"></mtd><mtd columnalign="left" style="text-align: left; padding-left: 0"><mo>=</mo><mfrac><mrow><mi>m</mi><mo stretchy="false" form="prefix">(</mo><mi>n</mi><mo>−</mo><msub><mi>y</mi><mn>0</mn></msub><mo stretchy="false" form="postfix">)</mo><mo>−</mo><mn>1</mn></mrow><mi>n</mi></mfrac><mo>+</mo><mo stretchy="false" form="prefix">⌊</mo><mfrac><msub><mi>y</mi><mn>0</mn></msub><mi>n</mi></mfrac><mo stretchy="false" form="postfix">⌋</mo><mi>m</mi></mtd></mtr><mtr><mtd columnalign="right" style="text-align: right; padding-right: 0"></mtd><mtd columnalign="left" style="text-align: left; padding-left: 0"><mo>=</mo><mi>m</mi><mo stretchy="false" form="prefix">(</mo><mn>1</mn><mo>+</mo><mo stretchy="false" form="prefix">⌊</mo><mfrac><msub><mi>y</mi><mn>0</mn></msub><mi>n</mi></mfrac><mo stretchy="false" form="postfix">⌋</mo><mo>−</mo><mfrac><msub><mi>y</mi><mn>0</mn></msub><mi>n</mi></mfrac><mo stretchy="false" form="postfix">)</mo><mo>−</mo><mfrac><mn>1</mn><mi>n</mi></mfrac></mtd></mtr><mtr><mtd columnalign="right" style="text-align: right; padding-right: 0"></mtd><mtd columnalign="left" style="text-align: left; padding-left: 0"><mo>≥</mo><mi>m</mi><mo>⋅</mo><mfrac><mn>1</mn><mi>n</mi></mfrac><mo>−</mo><mfrac><mn>1</mn><mi>n</mi></mfrac></mtd></mtr><mtr><mtd columnalign="right" style="text-align: right; padding-right: 0"></mtd><mtd columnalign="left" style="text-align: left; padding-left: 0"><mo>=</mo><mfrac><mrow><mi>m</mi><mo>−</mo><mn>1</mn></mrow><mi>n</mi></mfrac></mtd></mtr><mtr><mtd columnalign="right" style="text-align: right; padding-right: 0"></mtd><mtd columnalign="left" style="text-align: left; padding-left: 0"><mo>≥</mo><mn>0</mn></mtd></mtr></mtable><annotation encoding="application/x-tex">
\begin{split}
x &amp;= x_0 + \lfloor \frac{y_0}{n} \rfloor m \\
&amp;= \frac{m(n - y_0) - 1}{n} + \lfloor \frac{y_0}{n} \rfloor m \\
&amp;= m(1 + \lfloor \frac{y_0}{n} \rfloor - \frac{y_0}{n}) - \frac{1}{n} \\
&amp;\ge m \cdot \frac{1}{n} - \frac{1}{n} \\
&amp;= \frac{m - 1}{n} \\
&amp;\ge 0
\end{split}
</annotation></semantics></math> (In the middle inequality step, note
that since
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><msub><mi>y</mi><mn>0</mn></msub><annotation encoding="application/x-tex">y_0</annotation></semantics></math>
is a integer,
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msub><mi>y</mi><mn>0</mn></msub><mi>/</mi><mi>n</mi></mrow><annotation encoding="application/x-tex">y_0 / n</annotation></semantics></math>
is some integer plus
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>k</mi><mi>/</mi><mi>n</mi></mrow><annotation encoding="application/x-tex">k / n</annotation></semantics></math>,
where
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mi>k</mi><annotation encoding="application/x-tex">k</annotation></semantics></math>
is a integer such that
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mn>0</mn><mo>≤</mo><mi>k</mi><mo>&lt;</mo><mi>n</mi></mrow><annotation encoding="application/x-tex">0 \le k &lt; n</annotation></semantics></math>.)</p>
<p>Therefore an
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>m</mi><mo>×</mo><mi>n</mi></mrow><annotation encoding="application/x-tex">m \times n</annotation></semantics></math>
bounding box has four empty triangles if
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mrow><mi>gcd</mi><mo>&#8289;</mo></mrow><mo stretchy="false" form="prefix">(</mo><mi>m</mi><mo>,</mo><mi>n</mi><mo stretchy="false" form="postfix">)</mo><mo>=</mo><mn>1</mn></mrow><annotation encoding="application/x-tex">\gcd(m, n) = 1</annotation></semantics></math>,
and none otherwise.</p>
<p>We however need to consider all bounding box sizes from
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mn>1</mn><mo>×</mo><mn>1</mn></mrow><annotation encoding="application/x-tex">1 \times 1</annotation></semantics></math>
up to
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>m</mi><mo>×</mo><mi>n</mi></mrow><annotation encoding="application/x-tex">m \times n</annotation></semantics></math>,
instead of just one size. A size
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>j</mi><mo>×</mo><mi>i</mi></mrow><annotation encoding="application/x-tex">j \times i</annotation></semantics></math>
rectangle fits into a size
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>m</mi><mo>×</mo><mi>n</mi></mrow><annotation encoding="application/x-tex">m \times n</annotation></semantics></math>
rectangle
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mo stretchy="false" form="prefix">(</mo><mi>n</mi><mo>+</mo><mn>1</mn><mo>−</mo><mi>i</mi><mo stretchy="false" form="postfix">)</mo><mo stretchy="false" form="prefix">(</mo><mi>m</mi><mo>+</mo><mn>1</mn><mo>−</mo><mi>j</mi><mo stretchy="false" form="postfix">)</mo></mrow><annotation encoding="application/x-tex">(n + 1 - i)(m + 1 - j)</annotation></semantics></math>
times. So the answer is:
<math display="block" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mn>4</mn><munderover><mo>∑</mo><mrow><mi>i</mi><mo>=</mo><mn>1</mn></mrow><mi>n</mi></munderover><munderover><mo>∑</mo><mrow><mi>j</mi><mo>=</mo><mn>1</mn></mrow><mi>m</mi></munderover><mo stretchy="false" form="prefix">[</mo><mrow><mi>gcd</mi><mo>&#8289;</mo></mrow><mo stretchy="false" form="prefix">(</mo><mi>i</mi><mo>,</mo><mi>j</mi><mo stretchy="false" form="postfix">)</mo><mo>=</mo><mn>1</mn><mo stretchy="false" form="postfix">]</mo><mo stretchy="false" form="prefix">(</mo><mi>n</mi><mo>+</mo><mn>1</mn><mo>−</mo><mi>i</mi><mo stretchy="false" form="postfix">)</mo><mo stretchy="false" form="prefix">(</mo><mi>m</mi><mo>+</mo><mn>1</mn><mo>−</mo><mi>j</mi><mo stretchy="false" form="postfix">)</mo></mrow><annotation encoding="application/x-tex">
4\sum_{i = 1}^{n} \sum_{j = 1}^{m}
    [\gcd(i, j) = 1] (n + 1 - i) (m + 1 - j)
</annotation></semantics></math></p>
<p>(<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mo stretchy="false" form="prefix">[</mo><mi>P</mi><mo stretchy="false" form="postfix">]</mo></mrow><annotation encoding="application/x-tex">[P]</annotation></semantics></math>
is the <a href="https://en.wikipedia.org/wiki/Iverson_bracket">Iverson
bracket</a>, which is
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mn>1</mn><annotation encoding="application/x-tex">1</annotation></semantics></math>
when
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mi>P</mi><annotation encoding="application/x-tex">P</annotation></semantics></math>
is true and
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mn>0</mn><annotation encoding="application/x-tex">0</annotation></semantics></math>
otherwise.)</p>
<p>(Note 1: I’m doing this weird transposition of coordinate thing (just
once here) because we don’t use coordinates consistently between
geometry and, shall we say, discrete mathematics. In geometry to refer
to a point we have
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mi>x</mi><annotation encoding="application/x-tex">x</annotation></semantics></math>
before
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mi>y</mi><annotation encoding="application/x-tex">y</annotation></semantics></math>,
and
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mi>y</mi><annotation encoding="application/x-tex">y</annotation></semantics></math>
positive goes up, but if we refer to an entry in a matrix we have row
number before column number, and successive rows goes down. Things are
completely symmetric anyway, so the best way to deal with this
inconsistency is to forget that you noticed it or that I told you
it.)</p>
<p>(Note 2: This function without the factor
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mn>4</mn><annotation encoding="application/x-tex">4</annotation></semantics></math>
can be found as <a href="http://oeis.org/A114999">A114999</a> on
OEIS.)</p>
<p><strong>Current progress</strong>: We know that we need to find
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mn>4</mn><mo>×</mo><mi>a</mi><mo stretchy="false" form="prefix">(</mo><mi>n</mi><mo>,</mo><mi>m</mi><mo stretchy="false" form="postfix">)</mo></mrow><annotation encoding="application/x-tex">4 \times a(n, m)</annotation></semantics></math>
where
<math display="block" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>a</mi><mo stretchy="false" form="prefix">(</mo><mi>n</mi><mo>,</mo><mi>m</mi><mo stretchy="false" form="postfix">)</mo><mo>=</mo><munderover><mo>∑</mo><mrow><mi>i</mi><mo>=</mo><mn>1</mn></mrow><mi>n</mi></munderover><munderover><mo>∑</mo><mrow><mi>j</mi><mo>=</mo><mn>1</mn></mrow><mi>m</mi></munderover><mo stretchy="false" form="prefix">[</mo><mrow><mi>gcd</mi><mo>&#8289;</mo></mrow><mo stretchy="false" form="prefix">(</mo><mi>i</mi><mo>,</mo><mi>j</mi><mo stretchy="false" form="postfix">)</mo><mo>=</mo><mn>1</mn><mo stretchy="false" form="postfix">]</mo><mo stretchy="false" form="prefix">(</mo><mi>n</mi><mo>+</mo><mn>1</mn><mo>−</mo><mi>i</mi><mo stretchy="false" form="postfix">)</mo><mo stretchy="false" form="prefix">(</mo><mi>m</mi><mo>+</mo><mn>1</mn><mo>−</mo><mi>j</mi><mo stretchy="false" form="postfix">)</mo></mrow><annotation encoding="application/x-tex">
a(n, m) = \sum_{i = 1}^{n} \sum_{j = 1}^{m}
    [\gcd(i, j) = 1] (n + 1 - i) (m + 1 - j)
</annotation></semantics></math></p>
<h2 id="number-theory-part">Number theory part</h2>
<p><math display="block" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mtable><mtr><mtd columnalign="right" style="text-align: right; padding-right: 0"><mi>a</mi><mo stretchy="false" form="prefix">(</mo><mi>n</mi><mo>,</mo><mi>m</mi><mo stretchy="false" form="postfix">)</mo></mtd><mtd columnalign="left" style="text-align: left; padding-left: 0"><mo>=</mo><munderover><mo>∑</mo><mrow><mi>i</mi><mo>=</mo><mn>1</mn></mrow><mi>n</mi></munderover><munderover><mo>∑</mo><mrow><mi>j</mi><mo>=</mo><mn>1</mn></mrow><mi>m</mi></munderover><mo stretchy="false" form="prefix">[</mo><mrow><mi>gcd</mi><mo>&#8289;</mo></mrow><mo stretchy="false" form="prefix">(</mo><mi>i</mi><mo>,</mo><mi>j</mi><mo stretchy="false" form="postfix">)</mo><mo>=</mo><mn>1</mn><mo stretchy="false" form="postfix">]</mo><mo stretchy="false" form="prefix">(</mo><mi>n</mi><mo>+</mo><mn>1</mn><mo>−</mo><mi>i</mi><mo stretchy="false" form="postfix">)</mo><mo stretchy="false" form="prefix">(</mo><mi>m</mi><mo>+</mo><mn>1</mn><mo>−</mo><mi>j</mi><mo stretchy="false" form="postfix">)</mo></mtd></mtr><mtr><mtd columnalign="right" style="text-align: right; padding-right: 0"></mtd><mtd columnalign="left" style="text-align: left; padding-left: 0"><mo>=</mo><munderover><mo>∑</mo><mrow><mi>i</mi><mo>=</mo><mn>1</mn></mrow><mi>n</mi></munderover><munderover><mo>∑</mo><mrow><mi>j</mi><mo>=</mo><mn>1</mn></mrow><mi>m</mi></munderover><mo stretchy="false" form="prefix">[</mo><mrow><mi>gcd</mi><mo>&#8289;</mo></mrow><mo stretchy="false" form="prefix">(</mo><mi>i</mi><mo>,</mo><mi>j</mi><mo stretchy="false" form="postfix">)</mo><mo>=</mo><mn>1</mn><mo stretchy="false" form="postfix">]</mo><mo stretchy="false" form="prefix">(</mo><mo stretchy="false" form="prefix">(</mo><mi>n</mi><mo>+</mo><mn>1</mn><mo stretchy="false" form="postfix">)</mo><mo stretchy="false" form="prefix">(</mo><mi>m</mi><mo>+</mo><mn>1</mn><mo stretchy="false" form="postfix">)</mo><mo>−</mo><mo stretchy="false" form="prefix">(</mo><mi>m</mi><mo>+</mo><mn>1</mn><mo stretchy="false" form="postfix">)</mo><mi>i</mi><mo>−</mo><mo stretchy="false" form="prefix">(</mo><mi>n</mi><mo>+</mo><mn>1</mn><mo stretchy="false" form="postfix">)</mo><mi>j</mi><mo>+</mo><mi>i</mi><mi>j</mi><mo stretchy="false" form="postfix">)</mo></mtd></mtr><mtr><mtd columnalign="right" style="text-align: right; padding-right: 0"></mtd></mtr></mtable><annotation encoding="application/x-tex">
\begin{split}
a(n, m) &amp;= \sum_{i = 1}^{n} \sum_{j = 1}^{m}
    [\gcd(i, j) = 1] (n + 1 - i) (m + 1 - j) \\
&amp;= \sum_{i = 1}^{n} \sum_{j = 1}^{m}
    [\gcd(i, j) = 1] ((n + 1) (m + 1) - (m + 1) i - (n + 1) j + ij) \\
\end{split}
</annotation></semantics></math></p>
<p><a href="https://en.wikipedia.org/wiki/Möbius_inversion">Möbius
inversion</a> is an application of the inclusion-exclusion principle. A
function is defined as follows:</p>
<p><math display="block" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>μ</mi><mo stretchy="false" form="prefix">(</mo><mi>n</mi><mo stretchy="false" form="postfix">)</mo><mo>=</mo><mrow><mo stretchy="true" form="prefix">{</mo><mtable><mtr><mtd columnalign="left" style="text-align: left"><mo stretchy="false" form="prefix">(</mo><mi>−</mi><mn>1</mn><msup><mo stretchy="false" form="postfix">)</mo><mi>k</mi></msup></mtd><mtd columnalign="left" style="text-align: left"><mrow><mtext mathvariant="normal">if </mtext><mspace width="0.333em"></mspace></mrow><mi>n</mi><mrow><mspace width="0.333em"></mspace><mtext mathvariant="normal"> factorizes to </mtext><mspace width="0.333em"></mspace></mrow><mi>k</mi><mrow><mspace width="0.333em"></mspace><mtext mathvariant="normal"> distinct primes</mtext></mrow></mtd></mtr><mtr><mtd columnalign="left" style="text-align: left"><mn>0</mn></mtd><mtd columnalign="left" style="text-align: left"><mtext mathvariant="normal">otherwise</mtext></mtd></mtr></mtable></mrow></mrow><annotation encoding="application/x-tex">
\mu(n) = \begin{cases}
(-1)^{k} &amp; \text{if $n$ factorizes to $k$ distinct primes} \\
0 &amp; \text{otherwise}
\end{cases}
</annotation></semantics></math> This function has this important
property:
<math display="block" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><munder><mo>∑</mo><mrow><mi>d</mi><mo stretchy="false" form="prefix">|</mo><mi>n</mi></mrow></munder><mi>μ</mi><mo stretchy="false" form="prefix">(</mo><mi>d</mi><mo stretchy="false" form="postfix">)</mo><mo>=</mo><mo stretchy="false" form="prefix">[</mo><mi>n</mi><mo>=</mo><mn>1</mn><mo stretchy="false" form="postfix">]</mo></mrow><annotation encoding="application/x-tex">
\sum_{d | n} \mu(d)=[n=1]
</annotation></semantics></math> (Where
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>d</mi><mo stretchy="false" form="prefix">|</mo><mi>n</mi></mrow><annotation encoding="application/x-tex">d|n</annotation></semantics></math>
means for each positive divisor of
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mi>n</mi><annotation encoding="application/x-tex">n</annotation></semantics></math>
including
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mn>1</mn><annotation encoding="application/x-tex">1</annotation></semantics></math>
and
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mi>n</mi><annotation encoding="application/x-tex">n</annotation></semantics></math>,
of course not counting twice if
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mi>n</mi><annotation encoding="application/x-tex">n</annotation></semantics></math>
is
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mn>1</mn><annotation encoding="application/x-tex">1</annotation></semantics></math>.)</p>
<p>We can use this equation to replace
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mo stretchy="false" form="prefix">[</mo><mrow><mi>gcd</mi><mo>&#8289;</mo></mrow><mo stretchy="false" form="prefix">(</mo><mi>i</mi><mo>,</mo><mi>j</mi><mo stretchy="false" form="postfix">)</mo><mo>=</mo><mn>1</mn><mo stretchy="false" form="postfix">]</mo></mrow><annotation encoding="application/x-tex">[\gcd(i, j) = 1]</annotation></semantics></math>
with
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msub><mo>∑</mo><mrow><mi>d</mi><mo stretchy="false" form="prefix">|</mo><mspace width="-0.167em"></mspace><mrow><mi>gcd</mi><mo>&#8289;</mo></mrow><mo stretchy="false" form="prefix">(</mo><mi>i</mi><mo>,</mo><mi>j</mi><mo stretchy="false" form="postfix">)</mo></mrow></msub><mi>μ</mi><mo stretchy="false" form="prefix">(</mo><mi>d</mi><mo stretchy="false" form="postfix">)</mo></mrow><annotation encoding="application/x-tex">\sum_{d|\!\gcd(i, j)} \mu(d)</annotation></semantics></math>,
which allows us to ‘unleash’ the properties of
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mrow><mi>gcd</mi><mo>&#8289;</mo></mrow><mo stretchy="false" form="prefix">(</mo><mi>i</mi><mo>,</mo><mi>j</mi><mo stretchy="false" form="postfix">)</mo></mrow><annotation encoding="application/x-tex">\gcd(i, j)</annotation></semantics></math>,
namely that the set of divisors of
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mrow><mi>gcd</mi><mo>&#8289;</mo></mrow><mo stretchy="false" form="prefix">(</mo><mi>i</mi><mo>,</mo><mi>j</mi><mo stretchy="false" form="postfix">)</mo></mrow><annotation encoding="application/x-tex">\gcd(i, j)</annotation></semantics></math>
is the set of common divisors of
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mi>i</mi><annotation encoding="application/x-tex">i</annotation></semantics></math>
and
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mi>j</mi><annotation encoding="application/x-tex">j</annotation></semantics></math>
(which I write as summing over
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>d</mi><mo stretchy="false" form="prefix">|</mo><mi>i</mi><mo>,</mo><mi>d</mi><mo stretchy="false" form="prefix">|</mo><mi>j</mi></mrow><annotation encoding="application/x-tex">d | i, d | j</annotation></semantics></math>
below), which in turn allows us to rewrite out summations:
<math display="block" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mtable><mtr><mtd columnalign="right" style="text-align: right; padding-right: 0"><mi>⋯</mi></mtd><mtd columnalign="left" style="text-align: left; padding-left: 0"><mo>=</mo><munderover><mo>∑</mo><mrow><mi>i</mi><mo>=</mo><mn>1</mn></mrow><mi>n</mi></munderover><munderover><mo>∑</mo><mrow><mi>j</mi><mo>=</mo><mn>1</mn></mrow><mi>m</mi></munderover><munder><mo>∑</mo><mrow><mi>d</mi><mo stretchy="false" form="prefix">|</mo><mspace width="-0.167em"></mspace><mrow><mi>gcd</mi><mo>&#8289;</mo></mrow><mo stretchy="false" form="prefix">(</mo><mi>i</mi><mo>,</mo><mi>j</mi><mo stretchy="false" form="postfix">)</mo></mrow></munder><mi>μ</mi><mo stretchy="false" form="prefix">(</mo><mi>d</mi><mo stretchy="false" form="postfix">)</mo><mo stretchy="false" form="prefix">(</mo><mo stretchy="false" form="prefix">(</mo><mi>n</mi><mo>+</mo><mn>1</mn><mo stretchy="false" form="postfix">)</mo><mo stretchy="false" form="prefix">(</mo><mi>m</mi><mo>+</mo><mn>1</mn><mo stretchy="false" form="postfix">)</mo><mo>−</mo><mo stretchy="false" form="prefix">(</mo><mi>m</mi><mo>+</mo><mn>1</mn><mo stretchy="false" form="postfix">)</mo><mi>i</mi><mo>−</mo><mo stretchy="false" form="prefix">(</mo><mi>n</mi><mo>+</mo><mn>1</mn><mo stretchy="false" form="postfix">)</mo><mi>j</mi><mo>+</mo><mi>i</mi><mi>j</mi><mo stretchy="false" form="postfix">)</mo></mtd></mtr><mtr><mtd columnalign="right" style="text-align: right; padding-right: 0"></mtd><mtd columnalign="left" style="text-align: left; padding-left: 0"><mo>=</mo><munderover><mo>∑</mo><mrow><mi>i</mi><mo>=</mo><mn>1</mn></mrow><mi>n</mi></munderover><munderover><mo>∑</mo><mrow><mi>j</mi><mo>=</mo><mn>1</mn></mrow><mi>m</mi></munderover><munder><mo>∑</mo><mrow><mi>d</mi><mo stretchy="false" form="prefix">|</mo><mi>i</mi><mo>,</mo><mi>d</mi><mo stretchy="false" form="prefix">|</mo><mi>j</mi></mrow></munder><mi>μ</mi><mo stretchy="false" form="prefix">(</mo><mi>d</mi><mo stretchy="false" form="postfix">)</mo><mo stretchy="false" form="prefix">(</mo><mo stretchy="false" form="prefix">(</mo><mi>n</mi><mo>+</mo><mn>1</mn><mo stretchy="false" form="postfix">)</mo><mo stretchy="false" form="prefix">(</mo><mi>m</mi><mo>+</mo><mn>1</mn><mo stretchy="false" form="postfix">)</mo><mo>−</mo><mo stretchy="false" form="prefix">(</mo><mi>m</mi><mo>+</mo><mn>1</mn><mo stretchy="false" form="postfix">)</mo><mi>i</mi><mo>−</mo><mo stretchy="false" form="prefix">(</mo><mi>n</mi><mo>+</mo><mn>1</mn><mo stretchy="false" form="postfix">)</mo><mi>j</mi><mo>+</mo><mi>i</mi><mi>j</mi><mo stretchy="false" form="postfix">)</mo></mtd></mtr><mtr><mtd columnalign="right" style="text-align: right; padding-right: 0"></mtd><mtd columnalign="left" style="text-align: left; padding-left: 0"><mo>=</mo><munderover><mo>∑</mo><mrow><mi>d</mi><mo>=</mo><mn>1</mn></mrow><mrow><mrow><mi>min</mi><mo>&#8289;</mo></mrow><mo stretchy="false" form="prefix">{</mo><mi>n</mi><mo>,</mo><mi>m</mi><mo stretchy="false" form="postfix">}</mo></mrow></munderover><munderover><mo>∑</mo><mrow><mi>i</mi><mo>=</mo><mn>1</mn></mrow><mrow><mo stretchy="false" form="prefix">⌊</mo><mi>n</mi><mi>/</mi><mi>d</mi><mo stretchy="false" form="postfix">⌋</mo></mrow></munderover><munderover><mo>∑</mo><mrow><mi>j</mi><mo>=</mo><mn>1</mn></mrow><mrow><mo stretchy="false" form="prefix">⌊</mo><mi>m</mi><mi>/</mi><mi>d</mi><mo stretchy="false" form="postfix">⌋</mo></mrow></munderover><mi>μ</mi><mo stretchy="false" form="prefix">(</mo><mi>d</mi><mo stretchy="false" form="postfix">)</mo><mo stretchy="false" form="prefix">(</mo><mo stretchy="false" form="prefix">(</mo><mi>n</mi><mo>+</mo><mn>1</mn><mo stretchy="false" form="postfix">)</mo><mo stretchy="false" form="prefix">(</mo><mi>m</mi><mo>+</mo><mn>1</mn><mo stretchy="false" form="postfix">)</mo><mo>−</mo><mo stretchy="false" form="prefix">(</mo><mi>m</mi><mo>+</mo><mn>1</mn><mo stretchy="false" form="postfix">)</mo><mi>d</mi><mi>i</mi><mo>−</mo><mo stretchy="false" form="prefix">(</mo><mi>n</mi><mo>+</mo><mn>1</mn><mo stretchy="false" form="postfix">)</mo><mi>d</mi><mi>j</mi><mo>+</mo><msup><mi>d</mi><mn>2</mn></msup><mi>i</mi><mi>j</mi><mo stretchy="false" form="postfix">)</mo></mtd></mtr><mtr><mtd columnalign="right" style="text-align: right; padding-right: 0"></mtd></mtr></mtable><annotation encoding="application/x-tex">
\begin{split}
\cdots &amp;= \sum_{i = 1}^{n}
    \sum_{j = 1}^{m}
    \sum_{d | \!\gcd(i, j)}
    \mu(d) ((n + 1) (m + 1) - (m + 1) i - (n + 1) j + ij) \\
&amp;= \sum_{i = 1}^{n}
    \sum_{j = 1}^{m}
    \sum_{d | i, d | j}
    \mu(d) ((n + 1) (m + 1) - (m + 1) i - (n + 1) j + ij) \\
&amp;= \sum_{d = 1}^{\min\{n, m\}}
    \sum_{i = 1}^{\lfloor n / d \rfloor}
    \sum_{j = 1}^{\lfloor m / d \rfloor}
    \mu(d) ((n + 1) (m + 1) - (m + 1) di - (n + 1) dj + d^2ij) \\
\end{split}
</annotation></semantics></math></p>
<p>Note that in the last step I ‘switched variables’
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>i</mi><mo>←</mo><mi>i</mi><mi>/</mi><mi>d</mi></mrow><annotation encoding="application/x-tex">i \leftarrow i/d</annotation></semantics></math>
and
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>j</mi><mo>←</mo><mi>j</mi><mi>/</mi><mi>d</mi></mrow><annotation encoding="application/x-tex">j \leftarrow j/d</annotation></semantics></math>,
and instead of looking for possible
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mi>d</mi><annotation encoding="application/x-tex">d</annotation></semantics></math>
given
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mi>i</mi><annotation encoding="application/x-tex">i</annotation></semantics></math>
and
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mi>j</mi><annotation encoding="application/x-tex">j</annotation></semantics></math>,
I look for possible
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>d</mi><mi>i</mi></mrow><annotation encoding="application/x-tex">di</annotation></semantics></math>
and
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>d</mi><mi>j</mi></mrow><annotation encoding="application/x-tex">dj</annotation></semantics></math>
given
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mi>d</mi><annotation encoding="application/x-tex">d</annotation></semantics></math>,
which is simpler because it does not involve a divisibility check.</p>
<p>Let’s split that up into three parts for easier handling later
on:</p>
<p><math display="block" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>⋯</mi><mo>=</mo><msub><mi>a</mi><mn>0</mn></msub><mo stretchy="false" form="prefix">(</mo><mi>n</mi><mo>,</mo><mi>m</mi><mo stretchy="false" form="postfix">)</mo><mo>+</mo><msub><mi>a</mi><mn>1</mn></msub><mo stretchy="false" form="prefix">(</mo><mi>n</mi><mo>,</mo><mi>m</mi><mo stretchy="false" form="postfix">)</mo><mo>+</mo><msub><mi>a</mi><mn>2</mn></msub><mo stretchy="false" form="prefix">(</mo><mi>n</mi><mo>,</mo><mi>m</mi><mo stretchy="false" form="postfix">)</mo></mrow><annotation encoding="application/x-tex">
\cdots = a_0(n, m) + a_1(n, m) + a_2(n, m)
</annotation></semantics></math></p>
<p>Where:</p>
<math display="block" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mtable><mtr><mtd columnalign="right" style="text-align: right; padding-right: 0"><msub><mi>a</mi><mn>0</mn></msub><mo stretchy="false" form="prefix">(</mo><mi>n</mi><mo>,</mo><mi>m</mi><mo stretchy="false" form="postfix">)</mo></mtd><mtd columnalign="left" style="text-align: left; padding-left: 0"><mo>=</mo><munderover><mo>∑</mo><mrow><mi>d</mi><mo>=</mo><mn>1</mn></mrow><mrow><mrow><mi>min</mi><mo>&#8289;</mo></mrow><mo stretchy="false" form="prefix">{</mo><mi>n</mi><mo>,</mo><mi>m</mi><mo stretchy="false" form="postfix">}</mo></mrow></munderover><mi>μ</mi><mo stretchy="false" form="prefix">(</mo><mi>d</mi><mo stretchy="false" form="postfix">)</mo><mo stretchy="false" form="prefix">(</mo><mi>n</mi><mo>+</mo><mn>1</mn><mo stretchy="false" form="postfix">)</mo><mo stretchy="false" form="prefix">(</mo><mi>m</mi><mo>+</mo><mn>1</mn><mo stretchy="false" form="postfix">)</mo><mo stretchy="false" form="prefix">⌊</mo><mfrac><mi>n</mi><mi>d</mi></mfrac><mo stretchy="false" form="postfix">⌋</mo><mo stretchy="false" form="prefix">⌊</mo><mfrac><mi>m</mi><mi>d</mi></mfrac><mo stretchy="false" form="postfix">⌋</mo></mtd></mtr><mtr><mtd columnalign="right" style="text-align: right; padding-right: 0"><msub><mi>a</mi><mn>1</mn></msub><mo stretchy="false" form="prefix">(</mo><mi>n</mi><mo>,</mo><mi>m</mi><mo stretchy="false" form="postfix">)</mo></mtd><mtd columnalign="left" style="text-align: left; padding-left: 0"><mo>=</mo><munderover><mo>∑</mo><mrow><mi>d</mi><mo>=</mo><mn>1</mn></mrow><mrow><mrow><mi>min</mi><mo>&#8289;</mo></mrow><mo stretchy="false" form="prefix">{</mo><mi>n</mi><mo>,</mo><mi>m</mi><mo stretchy="false" form="postfix">}</mo></mrow></munderover><mi>μ</mi><mo stretchy="false" form="prefix">(</mo><mi>d</mi><mo stretchy="false" form="postfix">)</mo><mi>d</mi><mrow><mo stretchy="true" form="prefix">(</mo><mi>−</mi><mo stretchy="false" form="prefix">(</mo><mi>m</mi><mo>+</mo><mn>1</mn><mo stretchy="false" form="postfix">)</mo><mrow><mi>𝖨</mi><mi>𝖣</mi></mrow><mo stretchy="false" form="prefix">(</mo><mo stretchy="false" form="prefix">⌊</mo><mfrac><mi>n</mi><mi>d</mi></mfrac><mo stretchy="false" form="postfix">⌋</mo><mo stretchy="false" form="postfix">)</mo><mo stretchy="false" form="prefix">⌊</mo><mfrac><mi>m</mi><mi>d</mi></mfrac><mo stretchy="false" form="postfix">⌋</mo><mo>−</mo><mo stretchy="false" form="prefix">(</mo><mi>n</mi><mo>+</mo><mn>1</mn><mo stretchy="false" form="postfix">)</mo><mrow><mi>𝖨</mi><mi>𝖣</mi></mrow><mo stretchy="false" form="prefix">(</mo><mo stretchy="false" form="prefix">⌊</mo><mfrac><mi>m</mi><mi>d</mi></mfrac><mo stretchy="false" form="postfix">⌋</mo><mo stretchy="false" form="postfix">)</mo><mo stretchy="false" form="prefix">⌊</mo><mfrac><mi>n</mi><mi>d</mi></mfrac><mo stretchy="false" form="postfix">⌋</mo><mo stretchy="true" form="postfix">)</mo></mrow></mtd></mtr><mtr><mtd columnalign="right" style="text-align: right; padding-right: 0"><msub><mi>a</mi><mn>2</mn></msub><mo stretchy="false" form="prefix">(</mo><mi>n</mi><mo>,</mo><mi>m</mi><mo stretchy="false" form="postfix">)</mo></mtd><mtd columnalign="left" style="text-align: left; padding-left: 0"><mo>=</mo><munderover><mo>∑</mo><mrow><mi>d</mi><mo>=</mo><mn>1</mn></mrow><mrow><mrow><mi>min</mi><mo>&#8289;</mo></mrow><mo stretchy="false" form="prefix">{</mo><mi>n</mi><mo>,</mo><mi>m</mi><mo stretchy="false" form="postfix">}</mo></mrow></munderover><mi>μ</mi><mo stretchy="false" form="prefix">(</mo><mi>d</mi><mo stretchy="false" form="postfix">)</mo><msup><mi>d</mi><mn>2</mn></msup><mrow><mi>𝖨</mi><mi>𝖣</mi></mrow><mo stretchy="false" form="prefix">(</mo><mo stretchy="false" form="prefix">⌊</mo><mfrac><mi>n</mi><mi>d</mi></mfrac><mo stretchy="false" form="postfix">⌋</mo><mo stretchy="false" form="postfix">)</mo><mrow><mi>𝖨</mi><mi>𝖣</mi></mrow><mo stretchy="false" form="prefix">(</mo><mo stretchy="false" form="prefix">⌊</mo><mfrac><mi>m</mi><mi>d</mi></mfrac><mo stretchy="false" form="postfix">⌋</mo><mo stretchy="false" form="postfix">)</mo></mtd></mtr></mtable><annotation encoding="application/x-tex">\begin{aligned}
a_0(n, m) &amp;= \sum_{d = 1}^{\min\{n, m\}}
    \mu(d)
    (n + 1) (m + 1)
    \lfloor \frac{n}{d} \rfloor
    \lfloor \frac{m}{d} \rfloor \\

a_1(n, m) &amp;= \sum_{d = 1}^{\min\{n, m\}}
    \mu(d) d
    \left(
    -
        (m + 1)
        \mathsf{ID}(\lfloor \frac{n}{d} \rfloor)
        \lfloor \frac{m}{d} \rfloor
    -
        (n + 1)
        \mathsf{ID}(\lfloor \frac{m}{d} \rfloor)
        \lfloor \frac{n}{d} \rfloor
    \right) \\

a_2(n, m) &amp;= \sum_{d = 1}^{\min\{n, m\}}
    \mu(d) d^2
    \mathsf{ID}(\lfloor \frac{n}{d} \rfloor)
    \mathsf{ID}(\lfloor \frac{m}{d} \rfloor)
\end{aligned}</annotation></semantics></math>
<p>Where
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mrow><mi>𝖨</mi><mi>𝖣</mi></mrow><mo stretchy="false" form="prefix">(</mo><mi>n</mi><mo stretchy="false" form="postfix">)</mo></mrow><annotation encoding="application/x-tex">\mathsf{ID}(n)</annotation></semantics></math>
is the sum of
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mrow><mi>𝗂</mi><mi>𝖽</mi></mrow><mo stretchy="false" form="prefix">(</mo><mi>n</mi><mo stretchy="false" form="postfix">)</mo><mo>=</mo><mi>n</mi></mrow><annotation encoding="application/x-tex">\mathsf{id}(n) = n</annotation></semantics></math>,
that is
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mrow><mi>𝖨</mi><mi>𝖣</mi></mrow><mo stretchy="false" form="prefix">(</mo><mi>n</mi><mo stretchy="false" form="postfix">)</mo><mo>=</mo><mi>n</mi><mo stretchy="false" form="prefix">(</mo><mi>n</mi><mo>+</mo><mn>1</mn><mo stretchy="false" form="postfix">)</mo><mi>/</mi><mn>2</mn></mrow><annotation encoding="application/x-tex">\mathsf{ID}(n) = n (n + 1) / 2</annotation></semantics></math>.</p>
<p>The three parts have a common pattern:
<math display="block" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mtable><mtr><mtd columnalign="right" style="text-align: right; padding-right: 0"><msub><mi>s</mi><mrow><mi>k</mi><mo>,</mo><mi>u</mi></mrow></msub><mo stretchy="false" form="prefix">(</mo><mi>n</mi><mo>,</mo><mi>m</mi><mo stretchy="false" form="postfix">)</mo></mtd><mtd columnalign="left" style="text-align: left; padding-left: 0"><mo>=</mo><munderover><mo>∑</mo><mrow><mi>d</mi><mo>=</mo><mn>1</mn></mrow><mrow><mrow><mi>min</mi><mo>&#8289;</mo></mrow><mo stretchy="false" form="prefix">{</mo><mi>n</mi><mo>,</mo><mi>m</mi><mo stretchy="false" form="postfix">}</mo></mrow></munderover><mi>μ</mi><mo stretchy="false" form="prefix">(</mo><mi>d</mi><mo stretchy="false" form="postfix">)</mo><msup><mi>d</mi><mi>k</mi></msup><mi>u</mi><mo stretchy="false" form="prefix">(</mo><mo stretchy="false" form="prefix">⌊</mo><mfrac><mi>n</mi><mi>d</mi></mfrac><mo stretchy="false" form="postfix">⌋</mo><mo>,</mo><mo stretchy="false" form="prefix">⌊</mo><mfrac><mi>m</mi><mi>d</mi></mfrac><mo stretchy="false" form="postfix">⌋</mo><mo stretchy="false" form="postfix">)</mo></mtd></mtr></mtable><annotation encoding="application/x-tex">
\begin{align}
s_{k, u}(n, m) &amp;= \sum_{d = 1}^{\min\{n, m\}}
    \mu(d) d^k
    u(\lfloor \frac{n}{d} \rfloor, \lfloor \frac{m}{d} \rfloor)
\end{align}
</annotation></semantics></math> Where
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mi>u</mi><annotation encoding="application/x-tex">u</annotation></semantics></math>
is trivially computable. If we figure out how to compute
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><msub><mi>s</mi><mrow><mi>k</mi><mo>,</mo><mi>u</mi></mrow></msub><annotation encoding="application/x-tex">s_{k, u}</annotation></semantics></math>,
we’re set.</p>
<h2 id="intermission-number-theoretic-summation-trick">Intermission:
Number-theoretic summation trick</h2>
<p>Now for something completely out of nowhere.</p>
<p>The Dirichlet convolution of two functions is defined as:
<math display="block" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mo stretchy="false" form="prefix">(</mo><mi>f</mi><mo>*</mo><mi>g</mi><mo stretchy="false" form="postfix">)</mo><mo stretchy="false" form="prefix">(</mo><mi>n</mi><mo stretchy="false" form="postfix">)</mo><mo>=</mo><munder><mo>∑</mo><mrow><mi>d</mi><mo stretchy="false" form="prefix">|</mo><mi>n</mi></mrow></munder><mi>f</mi><mo stretchy="false" form="prefix">(</mo><mi>d</mi><mo stretchy="false" form="postfix">)</mo><mi>g</mi><mo stretchy="false" form="prefix">(</mo><mfrac><mi>n</mi><mi>d</mi></mfrac><mo stretchy="false" form="postfix">)</mo></mrow><annotation encoding="application/x-tex">
(f * g)(n) = \sum_{d | n} f(d) g(\frac{n}{d})
</annotation></semantics></math> Let
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>G</mi><mo stretchy="false" form="prefix">(</mo><mi>n</mi><mo stretchy="false" form="postfix">)</mo><mo>=</mo><msubsup><mo>∑</mo><mrow><mi>i</mi><mo>=</mo><mn>1</mn></mrow><mi>n</mi></msubsup><mi>g</mi><mo stretchy="false" form="prefix">(</mo><mi>i</mi><mo stretchy="false" form="postfix">)</mo></mrow><annotation encoding="application/x-tex">G(n) = \sum_{i = 1}^{n} g(i)</annotation></semantics></math>,
and similarly let capital letter functions represent the sum of the
corresponding lowercase letter functions. An observation is that if we
sum a Dirichlet convolution, we get: (The sum over
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>c</mi><mi>d</mi><mo>=</mo><mi>i</mi></mrow><annotation encoding="application/x-tex">cd = i</annotation></semantics></math>
means all positive integers
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mi>c</mi><annotation encoding="application/x-tex">c</annotation></semantics></math>
and
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mi>d</mi><annotation encoding="application/x-tex">d</annotation></semantics></math>
such that
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>c</mi><mi>d</mi><mo>=</mo><mi>i</mi></mrow><annotation encoding="application/x-tex">cd = i</annotation></semantics></math>,
and the sum over
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>c</mi><mi>d</mi><mo>≤</mo><mi>n</mi></mrow><annotation encoding="application/x-tex">cd \le n</annotation></semantics></math>
works similarly)
<math display="block" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mtable><mtr><mtd columnalign="right" style="text-align: right; padding-right: 0"><munderover><mo>∑</mo><mrow><mi>i</mi><mo>=</mo><mn>1</mn></mrow><mi>n</mi></munderover><mo stretchy="false" form="prefix">(</mo><mi>f</mi><mo>*</mo><mi>g</mi><mo stretchy="false" form="postfix">)</mo><mo stretchy="false" form="prefix">(</mo><mi>i</mi><mo stretchy="false" form="postfix">)</mo></mtd><mtd columnalign="left" style="text-align: left; padding-left: 0"><mo>=</mo><munderover><mo>∑</mo><mrow><mi>i</mi><mo>=</mo><mn>1</mn></mrow><mi>n</mi></munderover><munder><mo>∑</mo><mrow><mi>d</mi><mo stretchy="false" form="prefix">|</mo><mi>i</mi></mrow></munder><mi>f</mi><mo stretchy="false" form="prefix">(</mo><mi>d</mi><mo stretchy="false" form="postfix">)</mo><mi>g</mi><mo stretchy="false" form="prefix">(</mo><mfrac><mi>i</mi><mi>d</mi></mfrac><mo stretchy="false" form="postfix">)</mo></mtd></mtr><mtr><mtd columnalign="right" style="text-align: right; padding-right: 0"></mtd><mtd columnalign="left" style="text-align: left; padding-left: 0"><mo>=</mo><munderover><mo>∑</mo><mrow><mi>i</mi><mo>=</mo><mn>1</mn></mrow><mi>n</mi></munderover><munder><mo>∑</mo><mrow><mi>c</mi><mi>d</mi><mo>=</mo><mi>i</mi></mrow></munder><mi>f</mi><mo stretchy="false" form="prefix">(</mo><mi>c</mi><mo stretchy="false" form="postfix">)</mo><mi>g</mi><mo stretchy="false" form="prefix">(</mo><mi>d</mi><mo stretchy="false" form="postfix">)</mo></mtd></mtr><mtr><mtd columnalign="right" style="text-align: right; padding-right: 0"></mtd><mtd columnalign="left" style="text-align: left; padding-left: 0"><mo>=</mo><munder><mo>∑</mo><mrow><mi>c</mi><mi>d</mi><mo>≤</mo><mi>n</mi></mrow></munder><mi>f</mi><mo stretchy="false" form="prefix">(</mo><mi>c</mi><mo stretchy="false" form="postfix">)</mo><mi>g</mi><mo stretchy="false" form="prefix">(</mo><mi>d</mi><mo stretchy="false" form="postfix">)</mo></mtd></mtr><mtr><mtd columnalign="right" style="text-align: right; padding-right: 0"></mtd><mtd columnalign="left" style="text-align: left; padding-left: 0"><mo>=</mo><munderover><mo>∑</mo><mrow><mi>c</mi><mo>=</mo><mn>1</mn></mrow><mi>n</mi></munderover><mi>f</mi><mo stretchy="false" form="prefix">(</mo><mi>c</mi><mo stretchy="false" form="postfix">)</mo><munderover><mo>∑</mo><mrow><mi>i</mi><mo>=</mo><mn>1</mn></mrow><mrow><mo stretchy="false" form="prefix">⌊</mo><mi>n</mi><mi>/</mi><mi>c</mi><mo stretchy="false" form="postfix">⌋</mo></mrow></munderover><mi>g</mi><mo stretchy="false" form="prefix">(</mo><mi>i</mi><mo stretchy="false" form="postfix">)</mo></mtd></mtr><mtr><mtd columnalign="right" style="text-align: right; padding-right: 0"></mtd><mtd columnalign="left" style="text-align: left; padding-left: 0"><mo>=</mo><munderover><mo>∑</mo><mrow><mi>c</mi><mo>=</mo><mn>1</mn></mrow><mi>n</mi></munderover><mi>f</mi><mo stretchy="false" form="prefix">(</mo><mi>c</mi><mo stretchy="false" form="postfix">)</mo><mi>G</mi><mo stretchy="false" form="prefix">(</mo><mo stretchy="false" form="prefix">⌊</mo><mfrac><mi>n</mi><mi>c</mi></mfrac><mo stretchy="false" form="postfix">⌋</mo><mo stretchy="false" form="postfix">)</mo></mtd></mtr></mtable><annotation encoding="application/x-tex">
\begin{split}
\sum_{i = 1}^{n} (f * g)(i) &amp;= \sum_{i = 1}^{n} \sum_{d | i} f(d) g(\frac{i}{d}) \\
&amp;= \sum_{i = 1}^{n} \sum_{cd = i} f(c) g(d) \\
&amp;= \sum_{cd \le n} f(c) g(d) \\
&amp;= \sum_{c = 1}^{n} f(c) \sum_{i = 1}^{\lfloor n / c \rfloor} g(i) \\
&amp;= \sum_{c = 1}^{n} f(c) G(\lfloor \frac{n}{c} \rfloor)
\end{split}
</annotation></semantics></math> Isolating the first term gives:
<math display="block" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>f</mi><mo stretchy="false" form="prefix">(</mo><mn>1</mn><mo stretchy="false" form="postfix">)</mo><mi>G</mi><mo stretchy="false" form="prefix">(</mo><mi>n</mi><mo stretchy="false" form="postfix">)</mo><mo>=</mo><munderover><mo>∑</mo><mrow><mi>i</mi><mo>=</mo><mn>1</mn></mrow><mi>n</mi></munderover><mo stretchy="false" form="prefix">(</mo><mi>f</mi><mo>*</mo><mi>g</mi><mo stretchy="false" form="postfix">)</mo><mo stretchy="false" form="prefix">(</mo><mi>i</mi><mo stretchy="false" form="postfix">)</mo><mo>−</mo><munderover><mo>∑</mo><mrow><mi>c</mi><mo>=</mo><mn>1</mn></mrow><mi>n</mi></munderover><mi>f</mi><mo stretchy="false" form="prefix">(</mo><mi>c</mi><mo stretchy="false" form="postfix">)</mo><mi>G</mi><mo stretchy="false" form="prefix">(</mo><mo stretchy="false" form="prefix">⌊</mo><mfrac><mi>n</mi><mi>c</mi></mfrac><mo stretchy="false" form="postfix">⌋</mo><mo stretchy="false" form="postfix">)</mo></mrow><annotation encoding="application/x-tex">
f(1) G(n) = \sum_{i = 1}^{n} (f * g)(i) - \sum_{c = 1}^{n} f(c) G(\lfloor \frac{n}{c} \rfloor)
</annotation></semantics></math> If
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>f</mi><mo stretchy="false" form="prefix">(</mo><mn>1</mn><mo stretchy="false" form="postfix">)</mo><mo>≠</mo></mrow><annotation encoding="application/x-tex">f(1) \ne</annotation></semantics></math>
0, then:
<math display="block" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>G</mi><mo stretchy="false" form="prefix">(</mo><mi>n</mi><mo stretchy="false" form="postfix">)</mo><mo>=</mo><mfrac><mn>1</mn><mrow><mi>f</mi><mo stretchy="false" form="prefix">(</mo><mn>1</mn><mo stretchy="false" form="postfix">)</mo></mrow></mfrac><mrow><mo stretchy="true" form="prefix">(</mo><munderover><mo>∑</mo><mrow><mi>i</mi><mo>=</mo><mn>1</mn></mrow><mi>n</mi></munderover><mo stretchy="false" form="prefix">(</mo><mi>f</mi><mo>*</mo><mi>g</mi><mo stretchy="false" form="postfix">)</mo><mo stretchy="false" form="prefix">(</mo><mi>i</mi><mo stretchy="false" form="postfix">)</mo><mo>−</mo><munderover><mo>∑</mo><mrow><mi>c</mi><mo>=</mo><mn>1</mn></mrow><mi>n</mi></munderover><mi>f</mi><mo stretchy="false" form="prefix">(</mo><mi>c</mi><mo stretchy="false" form="postfix">)</mo><mi>G</mi><mo stretchy="false" form="prefix">(</mo><mo stretchy="false" form="prefix">⌊</mo><mfrac><mi>n</mi><mi>c</mi></mfrac><mo stretchy="false" form="postfix">⌋</mo><mo stretchy="false" form="postfix">)</mo><mo stretchy="true" form="postfix">)</mo></mrow></mrow><annotation encoding="application/x-tex">
G(n) = \frac{1}{f(1)} \left(\sum_{i = 1}^{n} (f * g)(i) - \sum_{c = 1}^{n} f(c) G(\lfloor \frac{n}{c} \rfloor) \right)
</annotation></semantics></math> Assume for now that
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mi>f</mi><annotation encoding="application/x-tex">f</annotation></semantics></math>
is chosen such that
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>F</mi><mo stretchy="false" form="prefix">(</mo><mi>i</mi><mo stretchy="false" form="postfix">)</mo></mrow><annotation encoding="application/x-tex">F(i)</annotation></semantics></math>
and
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msubsup><mo>∑</mo><mrow><mi>i</mi><mo>=</mo><mn>1</mn></mrow><mi>n</mi></msubsup><mo stretchy="false" form="prefix">(</mo><mi>f</mi><mo>*</mo><mi>g</mi><mo stretchy="false" form="postfix">)</mo><mo stretchy="false" form="prefix">(</mo><mi>i</mi><mo stretchy="false" form="postfix">)</mo></mrow><annotation encoding="application/x-tex">\sum_{i = 1}^{n} (f * g)(i)</annotation></semantics></math>
are efficiently computable, either directly via an
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>O</mi><mo stretchy="false" form="prefix">(</mo><mn>1</mn><mo stretchy="false" form="postfix">)</mo></mrow><annotation encoding="application/x-tex">O(1)</annotation></semantics></math>
formula or indirectly via a ‘recursive’ application of this
technique.</p>
<p>Note that
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mo stretchy="false" form="prefix">⌊</mo><mi>n</mi><mi>/</mi><mi>c</mi><mo stretchy="false" form="postfix">⌋</mo></mrow><annotation encoding="application/x-tex">\lfloor n / c \rfloor</annotation></semantics></math>
can only take on a maximum of about
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mn>2</mn><msqrt><mi>n</mi></msqrt></mrow><annotation encoding="application/x-tex">2 \sqrt{n}</annotation></semantics></math>
values:</p>
<ul>
<li><math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>n</mi><mi>/</mi><mn>1</mn><mo>,</mo><mi>n</mi><mi>/</mi><mn>2</mn><mo>,</mo><mi>…</mi><mo>,</mo><mi>n</mi><mi>/</mi><msqrt><mi>n</mi></msqrt></mrow><annotation encoding="application/x-tex">n/1, n/2,\dots,n/\sqrt{n}</annotation></semantics></math>
(final term is approximate), for
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>c</mi><mo>≤</mo><msqrt><mi>n</mi></msqrt></mrow><annotation encoding="application/x-tex">c \le \sqrt{n}</annotation></semantics></math></li>
<li>about
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msqrt><mi>n</mi></msqrt><mo>,</mo><msqrt><mi>n</mi></msqrt><mo>−</mo><mn>1</mn><mo>,</mo><mi>…</mi><mo>,</mo><mn>1</mn></mrow><annotation encoding="application/x-tex">\sqrt{n}, \sqrt{n} - 1, \dots, 1</annotation></semantics></math>,
for
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>c</mi><mo>&gt;</mo><msqrt><mi>n</mi></msqrt></mrow><annotation encoding="application/x-tex">c &gt; \sqrt{n}</annotation></semantics></math></li>
</ul>
<p>The sum over
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mi>c</mi><annotation encoding="application/x-tex">c</annotation></semantics></math>
from
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mn>1</mn><annotation encoding="application/x-tex">1</annotation></semantics></math>
to
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mi>n</mi><annotation encoding="application/x-tex">n</annotation></semantics></math>
is now broken up into
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>O</mi><mo stretchy="false" form="prefix">(</mo><msqrt><mi>n</mi></msqrt><mo stretchy="false" form="postfix">)</mo></mrow><annotation encoding="application/x-tex">O(\sqrt{n})</annotation></semantics></math>
segments where
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mo stretchy="false" form="prefix">⌊</mo><mi>n</mi><mi>/</mi><mi>c</mi><mo stretchy="false" form="postfix">⌋</mo></mrow><annotation encoding="application/x-tex">\lfloor n / c \rfloor</annotation></semantics></math>
is equal, and
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>G</mi><mo stretchy="false" form="prefix">(</mo><mo stretchy="false" form="prefix">⌊</mo><mi>n</mi><mi>/</mi><mi>c</mi><mo stretchy="false" form="postfix">⌋</mo><mo stretchy="false" form="postfix">)</mo></mrow><annotation encoding="application/x-tex">G(\lfloor n / c \rfloor)</annotation></semantics></math>
only needs to be calculated once per segment.</p>
<p>Given
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mi>x</mi><annotation encoding="application/x-tex">x</annotation></semantics></math>,
we want to solve for
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mi>j</mi><annotation encoding="application/x-tex">j</annotation></semantics></math>
in
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mo stretchy="false" form="prefix">⌊</mo><mi>n</mi><mi>/</mi><mi>j</mi><mo stretchy="false" form="postfix">⌋</mo><mo>=</mo><mi>x</mi></mrow><annotation encoding="application/x-tex">\lfloor n / j \rfloor = x</annotation></semantics></math>,
which shall give us the form of each segment.</p>
<p><math display="block" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mtable><mtr><mtd columnalign="center" style="text-align: center"><mi>x</mi><mo>=</mo><mo stretchy="false" form="prefix">⌊</mo><mfrac><mi>n</mi><mi>j</mi></mfrac><mo stretchy="false" form="postfix">⌋</mo></mtd></mtr><mtr><mtd columnalign="center" style="text-align: center"><mi>x</mi><mo>≤</mo><mfrac><mi>n</mi><mi>j</mi></mfrac><mo>&lt;</mo><mi>x</mi><mo>+</mo><mn>1</mn></mtd></mtr><mtr><mtd columnalign="center" style="text-align: center"><mfrac><mi>n</mi><mrow><mi>x</mi><mo>+</mo><mn>1</mn></mrow></mfrac><mo>&lt;</mo><mi>j</mi><mo>≤</mo><mfrac><mi>n</mi><mi>x</mi></mfrac></mtd></mtr><mtr><mtd columnalign="center" style="text-align: center"><mrow><mo stretchy="true" form="prefix">⌊</mo><mfrac><mi>n</mi><mrow><mi>x</mi><mo>+</mo><mn>1</mn></mrow></mfrac><mo stretchy="true" form="postfix">⌋</mo></mrow><mo>+</mo><mn>1</mn><mo>≤</mo><mi>j</mi><mo>≤</mo><mrow><mo stretchy="true" form="prefix">⌊</mo><mfrac><mi>n</mi><mi>x</mi></mfrac><mo stretchy="true" form="postfix">⌋</mo></mrow></mtd></mtr></mtable><annotation encoding="application/x-tex">\begin{gather}
x = \lfloor \frac{n}{j} \rfloor \\

x \le \frac{n}{j} &lt; x + 1 \\
\frac{n}{x+1} &lt; j \le \frac{n}{x} \\

\left\lfloor \frac{n}{x+1} \right\rfloor + 1
\le j
\le \left\lfloor \frac{n}{x} \right\rfloor

\end{gather}</annotation></semantics></math></p>
<p>Therefore given the the first interval’s starting point
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msub><mi>l</mi><mn>1</mn></msub><mo>=</mo><mn>2</mn></mrow><annotation encoding="application/x-tex">l_{1} = 2</annotation></semantics></math>,
the end of this interval is
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msub><mi>r</mi><mn>1</mn></msub><mo>=</mo><mo stretchy="false" form="prefix">⌊</mo><mi>n</mi><mi>/</mi><mo stretchy="false" form="prefix">⌊</mo><mi>n</mi><mi>/</mi><mn>2</mn><mo stretchy="false" form="postfix">⌋</mo><mo stretchy="false" form="postfix">⌋</mo></mrow><annotation encoding="application/x-tex">r_{1} = \lfloor n / \lfloor n / 2 \rfloor \rfloor</annotation></semantics></math>,
and then the next interval starts at
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msub><mi>l</mi><mn>2</mn></msub><mo>=</mo><msub><mi>r</mi><mn>1</mn></msub><mo>+</mo><mn>1</mn></mrow><annotation encoding="application/x-tex">l_{2} = r_{1} + 1</annotation></semantics></math>
and ends at
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msub><mi>r</mi><mn>2</mn></msub><mo>=</mo><mo stretchy="false" form="prefix">⌊</mo><mi>n</mi><mi>/</mi><mo stretchy="false" form="prefix">⌊</mo><mi>n</mi><mi>/</mi><msub><mi>l</mi><mn>2</mn></msub><mo stretchy="false" form="postfix">⌋</mo><mo stretchy="false" form="postfix">⌋</mo></mrow><annotation encoding="application/x-tex">r_2 = \lfloor n / \lfloor n / l_{2} \rfloor \rfloor</annotation></semantics></math>,
etc. until
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mi>n</mi><annotation encoding="application/x-tex">n</annotation></semantics></math>
is reached. In each interval
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mo stretchy="false" form="prefix">[</mo><msub><mi>l</mi><mi>i</mi></msub><mo>,</mo><msub><mi>r</mi><mi>i</mi></msub><mo stretchy="false" form="postfix">]</mo></mrow><annotation encoding="application/x-tex">[l_i, r_i]</annotation></semantics></math>
the sum is
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mo stretchy="false" form="prefix">(</mo><mi>F</mi><mo stretchy="false" form="prefix">(</mo><msub><mi>r</mi><mi>i</mi></msub><mo stretchy="false" form="postfix">)</mo><mo>−</mo><mi>F</mi><mo stretchy="false" form="prefix">(</mo><msub><mi>l</mi><mi>i</mi></msub><mo stretchy="false" form="postfix">)</mo><mo stretchy="false" form="postfix">)</mo><mi>G</mi><mo stretchy="false" form="prefix">(</mo><mo stretchy="false" form="prefix">⌊</mo><mi>n</mi><mi>/</mi><msub><mi>l</mi><mi>i</mi></msub><mo stretchy="false" form="postfix">⌋</mo><mo stretchy="false" form="postfix">)</mo></mrow><annotation encoding="application/x-tex">(F(r_i) - F(l_i)) G(\lfloor n / l_i \rfloor)</annotation></semantics></math>.</p>
<p>By recursively computing
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mi>G</mi><annotation encoding="application/x-tex">G</annotation></semantics></math>
as shown, memoizing using a hash table, we can achieve
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>O</mi><mo stretchy="false" form="prefix">(</mo><msup><mi>n</mi><mrow><mn>3</mn><mi>/</mi><mn>4</mn></mrow></msup><mo stretchy="false" form="postfix">)</mo></mrow><annotation encoding="application/x-tex">O(n^{3/4})</annotation></semantics></math>
time complexity and
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>O</mi><mo stretchy="false" form="prefix">(</mo><msup><mi>n</mi><mrow><mn>1</mn><mi>/</mi><mn>2</mn></mrow></msup><mo stretchy="false" form="postfix">)</mo></mrow><annotation encoding="application/x-tex">O(n^{1/2})</annotation></semantics></math>
space complexity. If we use a sieve to pre-compute the first
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>O</mi><mo stretchy="false" form="prefix">(</mo><msup><mi>n</mi><mrow><mn>2</mn><mi>/</mi><mn>3</mn></mrow></msup><mo stretchy="false" form="postfix">)</mo></mrow><annotation encoding="application/x-tex">O(n^{2/3})</annotation></semantics></math>
terms of
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>G</mi><mo stretchy="false" form="prefix">(</mo><mi>n</mi><mo stretchy="false" form="postfix">)</mo></mrow><annotation encoding="application/x-tex">G(n)</annotation></semantics></math>
we can achieve
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>O</mi><mo stretchy="false" form="prefix">(</mo><msup><mi>n</mi><mrow><mn>2</mn><mi>/</mi><mn>3</mn></mrow></msup><mo stretchy="false" form="postfix">)</mo></mrow><annotation encoding="application/x-tex">O(n^{2/3})</annotation></semantics></math>
time and space complexity.</p>
<p>The complexity proof: In the no-precomputation case every
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>G</mi><mo stretchy="false" form="prefix">(</mo><mo stretchy="false" form="prefix">⌊</mo><mi>n</mi><mi>/</mi><mi>d</mi><mo stretchy="false" form="postfix">⌋</mo><mo stretchy="false" form="postfix">)</mo></mrow><annotation encoding="application/x-tex">G(\lfloor n / d \rfloor)</annotation></semantics></math>
is computed exactly once, each taking
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>O</mi><mo stretchy="false" form="prefix">(</mo><msqrt><mrow><mo stretchy="false" form="prefix">⌊</mo><mi>n</mi><mi>/</mi><mi>d</mi><mo stretchy="false" form="postfix">⌋</mo></mrow></msqrt><mo stretchy="false" form="postfix">)</mo></mrow><annotation encoding="application/x-tex">O(\sqrt{\lfloor n / d \rfloor})</annotation></semantics></math>
time. As discussed earlier
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mo stretchy="false" form="prefix">⌊</mo><mi>n</mi><mi>/</mi><mi>d</mi><mo stretchy="false" form="postfix">⌋</mo></mrow><annotation encoding="application/x-tex">\lfloor n / d \rfloor</annotation></semantics></math>
takes on the values
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mn>1</mn><mo>,</mo><mn>2</mn><mo>,</mo><mi>…</mi><mo>,</mo><msqrt><mi>n</mi></msqrt></mrow><annotation encoding="application/x-tex">1, 2, \dots, \sqrt{n}</annotation></semantics></math>
and
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>n</mi><mi>/</mi><mn>1</mn><mo>,</mo><mi>n</mi><mi>/</mi><mn>2</mn><mo>,</mo><mi>.</mi><mi>.</mi><mi>.</mi><mo>,</mo><mi>n</mi><mi>/</mi><msqrt><mi>n</mi></msqrt></mrow><annotation encoding="application/x-tex">n/1, n/2, ..., n/\sqrt{n}</annotation></semantics></math>
(We are talking asymptotics here so we’ll just ignore the details.),
therefore the total time is:
<math display="block" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mtable><mtr><mtd columnalign="right" style="text-align: right; padding-right: 0"><mi>T</mi><mo stretchy="false" form="prefix">(</mo><mi>n</mi><mo stretchy="false" form="postfix">)</mo></mtd><mtd columnalign="left" style="text-align: left; padding-left: 0"><mo>=</mo><munderover><mo>∑</mo><mrow><mi>i</mi><mo>=</mo><mn>1</mn></mrow><msqrt><mi>n</mi></msqrt></munderover><mi>O</mi><mrow><mo stretchy="true" form="prefix">(</mo><msqrt><mi>i</mi></msqrt><mo>+</mo><msqrt><mfrac><mi>n</mi><mi>i</mi></mfrac></msqrt><mo stretchy="true" form="postfix">)</mo></mrow></mtd></mtr><mtr><mtd columnalign="right" style="text-align: right; padding-right: 0"></mtd><mtd columnalign="left" style="text-align: left; padding-left: 0"><mo>=</mo><munderover><mo>∑</mo><mrow><mi>i</mi><mo>=</mo><mn>1</mn></mrow><msqrt><mi>n</mi></msqrt></munderover><mi>O</mi><mrow><mo stretchy="true" form="prefix">(</mo><msup><mi>i</mi><mrow><mn>1</mn><mi>/</mi><mn>2</mn></mrow></msup><mo>+</mo><msup><mi>i</mi><mrow><mi>−</mi><mn>1</mn><mi>/</mi><mn>2</mn></mrow></msup><msqrt><mi>n</mi></msqrt><mo stretchy="true" form="postfix">)</mo></mrow></mtd></mtr><mtr><mtd columnalign="right" style="text-align: right; padding-right: 0"></mtd><mtd columnalign="left" style="text-align: left; padding-left: 0"><mo>=</mo><mi>O</mi><mo stretchy="false" form="prefix">(</mo><mo stretchy="false" form="prefix">(</mo><msqrt><mi>n</mi></msqrt><msup><mo stretchy="false" form="postfix">)</mo><mrow><mn>3</mn><mi>/</mi><mn>2</mn></mrow></msup><mo stretchy="false" form="postfix">)</mo><mo>+</mo><mi>O</mi><mo stretchy="false" form="prefix">(</mo><mo stretchy="false" form="prefix">(</mo><msqrt><mi>n</mi></msqrt><msup><mo stretchy="false" form="postfix">)</mo><mrow><mn>1</mn><mi>/</mi><mn>2</mn></mrow></msup><mo stretchy="false" form="postfix">)</mo><msqrt><mi>n</mi></msqrt></mtd></mtr><mtr><mtd columnalign="right" style="text-align: right; padding-right: 0"></mtd><mtd columnalign="left" style="text-align: left; padding-left: 0"><mo>=</mo><mi>O</mi><mo stretchy="false" form="prefix">(</mo><msup><mi>n</mi><mrow><mn>3</mn><mi>/</mi><mn>4</mn></mrow></msup><mo stretchy="false" form="postfix">)</mo></mtd></mtr></mtable><annotation encoding="application/x-tex">
\begin{align}
T(n) &amp;= \sum_{i = 1}^{\sqrt{n}} O\left( \sqrt{i} + \sqrt{\frac{n}{i}} \right) \\
&amp;= \sum_{i = 1}^{\sqrt{n}} O\left( i^{1/2} + i^{-1/2} \sqrt{n} \right) \\
&amp;= O((\sqrt{n})^{3/2}) + O((\sqrt{n})^{1/2}) \sqrt{n} \\
&amp;= O(n^{3/4})
\end{align}
</annotation></semantics></math> If we can find the first
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>O</mi><mo stretchy="false" form="prefix">(</mo><msup><mi>n</mi><mi>k</mi></msup><mo stretchy="false" form="postfix">)</mo></mrow><annotation encoding="application/x-tex">O(n^k)</annotation></semantics></math>
(where
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mn>1</mn><mi>/</mi><mn>2</mn><mo>≤</mo><mi>k</mi><mo>≤</mo><mn>3</mn><mi>/</mi><mn>4</mn></mrow><annotation encoding="application/x-tex">1/2 \le k \le 3/4</annotation></semantics></math>)
values of
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mi>g</mi><annotation encoding="application/x-tex">g</annotation></semantics></math>
in
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>O</mi><mo stretchy="false" form="prefix">(</mo><msup><mi>n</mi><mi>k</mi></msup><mo stretchy="false" form="postfix">)</mo></mrow><annotation encoding="application/x-tex">O(n^k)</annotation></semantics></math>
time we can accelerate the process. This is often possible for, for
example, multiplicative functions where <a
href="https://en.wikipedia.org/wiki/Sieve_of_Eratosthenes#Euler&#39;s_sieve">Euler’s
sieve</a> can be used. For more detailed information check <a
href="https://codeforces.com/blog/entry/54090">this note on
Codeforces</a>. The new execution time is</p>
<p><math display="block" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mtable><mtr><mtd columnalign="right" style="text-align: right; padding-right: 0"><msub><msup><mi>T</mi><mo>′</mo></msup><mi>k</mi></msub><mo stretchy="false" form="prefix">(</mo><mi>n</mi><mo stretchy="false" form="postfix">)</mo></mtd><mtd columnalign="left" style="text-align: left; padding-left: 0"><mo>=</mo><mi>O</mi><mo stretchy="false" form="prefix">(</mo><msup><mi>n</mi><mi>k</mi></msup><mo stretchy="false" form="postfix">)</mo><mo>+</mo><munderover><mo>∑</mo><mrow><mi>i</mi><mo>=</mo><mn>1</mn></mrow><msup><mi>n</mi><mrow><mn>1</mn><mo>−</mo><mi>k</mi></mrow></msup></munderover><mi>O</mi><mo stretchy="false" form="prefix">(</mo><msqrt><mfrac><mi>n</mi><mi>i</mi></mfrac></msqrt><mo stretchy="false" form="postfix">)</mo></mtd></mtr><mtr><mtd columnalign="right" style="text-align: right; padding-right: 0"></mtd><mtd columnalign="left" style="text-align: left; padding-left: 0"><mo>=</mo><mi>O</mi><mo stretchy="false" form="prefix">(</mo><msup><mi>n</mi><mi>k</mi></msup><mo>+</mo><msup><mi>n</mi><mrow><mo stretchy="false" form="prefix">(</mo><mn>1</mn><mo>−</mo><mi>k</mi><mo stretchy="false" form="postfix">)</mo><mi>/</mi><mn>2</mn></mrow></msup><msqrt><mi>n</mi></msqrt><mo stretchy="false" form="postfix">)</mo></mtd></mtr><mtr><mtd columnalign="right" style="text-align: right; padding-right: 0"></mtd><mtd columnalign="left" style="text-align: left; padding-left: 0"><mo>=</mo><mi>O</mi><mo stretchy="false" form="prefix">(</mo><msup><mi>n</mi><mi>k</mi></msup><mo>+</mo><msup><mi>n</mi><mrow><mo stretchy="false" form="prefix">(</mo><mn>2</mn><mo>−</mo><mi>k</mi><mo stretchy="false" form="postfix">)</mo><mi>/</mi><mn>2</mn></mrow></msup><mo stretchy="false" form="postfix">)</mo></mtd></mtr></mtable><annotation encoding="application/x-tex">
\begin{align}
T&#39;_k(n) &amp;= O(n^k) + \sum_{i = 1}^{n^{1 - k}} O(\sqrt{\frac{n}{i}}) \\
&amp;= O(n^k + n^{(1 - k) / 2} \sqrt{n}) \\
&amp;= O(n^k + n^{(2 - k) / 2})
\end{align}
</annotation></semantics></math></p>
<p>Asymptotically,
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msub><msup><mi>T</mi><mo>′</mo></msup><mi>k</mi></msub><mo stretchy="false" form="prefix">(</mo><mi>n</mi><mo stretchy="false" form="postfix">)</mo></mrow><annotation encoding="application/x-tex">T&#39;_k(n)</annotation></semantics></math>
is minimized when
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>k</mi><mo>=</mo><mo stretchy="false" form="prefix">(</mo><mn>2</mn><mo>−</mo><mi>k</mi><mo stretchy="false" form="postfix">)</mo><mi>/</mi><mn>2</mn></mrow><annotation encoding="application/x-tex">k = (2 - k) / 2</annotation></semantics></math>,
which is
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>k</mi><mo>=</mo><mn>2</mn><mi>/</mi><mn>3</mn></mrow><annotation encoding="application/x-tex">k = 2/3</annotation></semantics></math>.
In practice, the number of values to precompute is a tunable that will
be set according to needs.</p>
<p>To summarize, this means that if
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>h</mi><mo>=</mo><mi>f</mi><mo>*</mo><mi>g</mi></mrow><annotation encoding="application/x-tex">h = f * g</annotation></semantics></math>,
and
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mi>H</mi><annotation encoding="application/x-tex">H</annotation></semantics></math>
and
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mi>F</mi><annotation encoding="application/x-tex">F</annotation></semantics></math>
can be computed efficiently either directly or ‘recursively’ by this
technique, then
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mi>G</mi><annotation encoding="application/x-tex">G</annotation></semantics></math>
can be computed efficiently.</p>
<p>I could not find any authoritative reference on this method. The best
I could find is this <a
href="https://math.stackexchange.com/a/1740370">answer on
math.SE</a>.</p>
<p>The algorithm described above is often shown as a method to compute
isolated values of
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>G</mi><mo stretchy="false" form="prefix">(</mo><mi>n</mi><mo stretchy="false" form="postfix">)</mo></mrow><annotation encoding="application/x-tex">G(n)</annotation></semantics></math>,
but it actually computes
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>G</mi><mo stretchy="false" form="prefix">(</mo><mo stretchy="false" form="prefix">⌊</mo><mi>n</mi><mi>/</mi><mi>d</mi><mo stretchy="false" form="postfix">⌋</mo><mo stretchy="false" form="postfix">)</mo></mrow><annotation encoding="application/x-tex">G(\lfloor n / d \rfloor)</annotation></semantics></math>
for all possible values of
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mo stretchy="false" form="prefix">⌊</mo><mi>n</mi><mi>/</mi><mi>d</mi><mo stretchy="false" form="postfix">⌋</mo></mrow><annotation encoding="application/x-tex">\lfloor n / d \rfloor</annotation></semantics></math>.
This will become handy if, as alluded to earlier,
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>F</mi><mo stretchy="false" form="prefix">(</mo><mi>n</mi><mo stretchy="false" form="postfix">)</mo></mrow><annotation encoding="application/x-tex">F(n)</annotation></semantics></math>
is still non-trivial but this method can apply, but we won’t need this
for now. We shall see how this helps us here in a minute, but first we
need to find
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mi>f</mi><annotation encoding="application/x-tex">f</annotation></semantics></math>
and
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mi>h</mi><annotation encoding="application/x-tex">h</annotation></semantics></math>.</p>
<h2 id="back-to-business">Back to business</h2>
<p>In the definition of
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><msub><mi>s</mi><mrow><mi>k</mi><mo>,</mo><mi>f</mi></mrow></msub><annotation encoding="application/x-tex">s_{k,f}</annotation></semantics></math>,
we extract the ‘difficult’ part
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>μ</mi><mo stretchy="false" form="prefix">(</mo><mi>n</mi><mo stretchy="false" form="postfix">)</mo><msup><mi>n</mi><mi>k</mi></msup></mrow><annotation encoding="application/x-tex">\mu(n) n^{k}</annotation></semantics></math>
and we can define another function along with it:
<math display="block" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mtable><mtr><mtd columnalign="right" style="text-align: right; padding-right: 0"><msub><mi>m</mi><mi>k</mi></msub><mo stretchy="false" form="prefix">(</mo><mi>n</mi><mo stretchy="false" form="postfix">)</mo></mtd><mtd columnalign="left" style="text-align: left; padding-left: 0"><mo>=</mo><mi>μ</mi><mo stretchy="false" form="prefix">(</mo><mi>n</mi><mo stretchy="false" form="postfix">)</mo><msup><mi>n</mi><mi>k</mi></msup></mtd></mtr><mtr><mtd columnalign="right" style="text-align: right; padding-right: 0"><msup><mrow><mi>𝗂</mi><mi>𝖽</mi></mrow><mi>k</mi></msup><mo stretchy="false" form="prefix">(</mo><mi>n</mi><mo stretchy="false" form="postfix">)</mo></mtd><mtd columnalign="left" style="text-align: left; padding-left: 0"><mo>=</mo><msup><mi>n</mi><mi>k</mi></msup></mtd></mtr></mtable><annotation encoding="application/x-tex">
\begin{align}m_k(n) &amp;= \mu(n) n^k \\\mathsf{id}^k(n) &amp;= n^k\end{align}
</annotation></semantics></math> The Dirichlet convolution of the two
is:
<math display="block" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mtable><mtr><mtd columnalign="right" style="text-align: right; padding-right: 0"><mo stretchy="false" form="prefix">(</mo><msub><mi>m</mi><mi>k</mi></msub><mo>*</mo><msup><mrow><mi>𝗂</mi><mi>𝖽</mi></mrow><mi>k</mi></msup><mo stretchy="false" form="postfix">)</mo><mo stretchy="false" form="prefix">(</mo><mi>n</mi><mo stretchy="false" form="postfix">)</mo></mtd><mtd columnalign="left" style="text-align: left; padding-left: 0"><mo>=</mo><munder><mo>∑</mo><mrow><mi>d</mi><mo stretchy="false" form="prefix">|</mo><mi>n</mi></mrow></munder><mi>μ</mi><mo stretchy="false" form="prefix">(</mo><mi>d</mi><mo stretchy="false" form="postfix">)</mo><msup><mi>d</mi><mi>k</mi></msup><mo stretchy="false" form="prefix">(</mo><mfrac><mi>n</mi><mi>d</mi></mfrac><msup><mo stretchy="false" form="postfix">)</mo><mi>k</mi></msup></mtd></mtr><mtr><mtd columnalign="right" style="text-align: right; padding-right: 0"></mtd><mtd columnalign="left" style="text-align: left; padding-left: 0"><mo>=</mo><munder><mo>∑</mo><mrow><mi>d</mi><mo stretchy="false" form="prefix">|</mo><mi>n</mi></mrow></munder><mi>μ</mi><mo stretchy="false" form="prefix">(</mo><mi>d</mi><mo stretchy="false" form="postfix">)</mo><msup><mi>n</mi><mi>k</mi></msup></mtd></mtr><mtr><mtd columnalign="right" style="text-align: right; padding-right: 0"></mtd><mtd columnalign="left" style="text-align: left; padding-left: 0"><mo>=</mo><mo stretchy="false" form="prefix">(</mo><munder><mo>∑</mo><mrow><mi>d</mi><mo stretchy="false" form="prefix">|</mo><mi>n</mi></mrow></munder><mi>μ</mi><mo stretchy="false" form="prefix">(</mo><mi>d</mi><mo stretchy="false" form="postfix">)</mo><mo stretchy="false" form="postfix">)</mo><msup><mi>n</mi><mi>k</mi></msup></mtd></mtr><mtr><mtd columnalign="right" style="text-align: right; padding-right: 0"></mtd><mtd columnalign="left" style="text-align: left; padding-left: 0"><mo>=</mo><mo stretchy="false" form="prefix">[</mo><mi>n</mi><mo>=</mo><mn>1</mn><mo stretchy="false" form="postfix">]</mo><msup><mi>n</mi><mi>k</mi></msup></mtd></mtr><mtr><mtd columnalign="right" style="text-align: right; padding-right: 0"></mtd><mtd columnalign="left" style="text-align: left; padding-left: 0"><mo>=</mo><mo stretchy="false" form="prefix">[</mo><mi>n</mi><mo>=</mo><mn>1</mn><mo stretchy="false" form="postfix">]</mo></mtd></mtr></mtable><annotation encoding="application/x-tex">
\begin{align}(m_{k} * \mathsf{id}^{k})(n) &amp;= \sum_{d|n} \mu(d) d^k (\frac{n}{d})^k \\&amp;= \sum_{d|n} \mu(d) n^k \\&amp;= (\sum_{d|n} \mu(d)) n^k \\&amp;= [n = 1] n^k \\&amp;= [n = 1]\end{align}
</annotation></semantics></math> That’s quite simple. This is no
surprise, since
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mo stretchy="false" form="prefix">[</mo><mi>n</mi><mo>=</mo><mn>1</mn><mo stretchy="false" form="postfix">]</mo></mrow><annotation encoding="application/x-tex">[n = 1]</annotation></semantics></math>
is the identity of Dirichlet convolution, and
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><msub><mi>m</mi><mi>k</mi></msub><annotation encoding="application/x-tex">m_{k}</annotation></semantics></math>
is the Dirichlet inverse of
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><msup><mrow><mi>𝗂</mi><mi>𝖽</mi></mrow><mi>k</mi></msup><annotation encoding="application/x-tex">\mathsf{id}^{k}</annotation></semantics></math>.
Refer to <a
href="https://en.wikipedia.org/wiki/Dirichlet_convolution#Other_formulas">Wikipedia</a>
for details.</p>
<p>Can we use the earlier technique to compute sums of
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msub><mi>m</mi><mi>k</mi></msub><mo stretchy="false" form="prefix">(</mo><mi>n</mi><mo stretchy="false" form="postfix">)</mo><mo>=</mo><mi>μ</mi><mo stretchy="false" form="prefix">(</mo><mi>n</mi><mo stretchy="false" form="postfix">)</mo><msup><mi>n</mi><mi>k</mi></msup></mrow><annotation encoding="application/x-tex">m_k(n) = \mu(n) n^k</annotation></semantics></math>?
The answer is yes, as the sum of the functions involved are either
trivial or well-known:
<math display="block" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mtable><mtr><mtd columnalign="right" style="text-align: right; padding-right: 0"><munderover><mo>∑</mo><mrow><mi>i</mi><mo>=</mo><mn>1</mn></mrow><mi>n</mi></munderover><mo stretchy="false" form="prefix">[</mo><mi>i</mi><mo>=</mo><mn>1</mn><mo stretchy="false" form="postfix">]</mo></mtd><mtd columnalign="left" style="text-align: left; padding-left: 0"><mo>=</mo><mn>1</mn></mtd></mtr><mtr><mtd columnalign="right" style="text-align: right; padding-right: 0"><munderover><mo>∑</mo><mrow><mi>i</mi><mo>=</mo><mn>1</mn></mrow><mi>n</mi></munderover><mn>1</mn></mtd><mtd columnalign="left" style="text-align: left; padding-left: 0"><mo>=</mo><mi>n</mi></mtd></mtr><mtr><mtd columnalign="right" style="text-align: right; padding-right: 0"><munderover><mo>∑</mo><mrow><mi>i</mi><mo>=</mo><mn>1</mn></mrow><mi>n</mi></munderover><mi>i</mi></mtd><mtd columnalign="left" style="text-align: left; padding-left: 0"><mo>=</mo><mfrac><mrow><mi>i</mi><mo stretchy="false" form="prefix">(</mo><mi>i</mi><mo>+</mo><mn>1</mn><mo stretchy="false" form="postfix">)</mo></mrow><mn>2</mn></mfrac></mtd></mtr><mtr><mtd columnalign="right" style="text-align: right; padding-right: 0"><munderover><mo>∑</mo><mrow><mi>i</mi><mo>=</mo><mn>1</mn></mrow><mi>n</mi></munderover><msup><mi>i</mi><mn>2</mn></msup></mtd><mtd columnalign="left" style="text-align: left; padding-left: 0"><mo>=</mo><mfrac><mrow><mi>i</mi><mo stretchy="false" form="prefix">(</mo><mi>i</mi><mo>+</mo><mn>1</mn><mo stretchy="false" form="postfix">)</mo><mo stretchy="false" form="prefix">(</mo><mn>2</mn><mi>i</mi><mo>+</mo><mn>1</mn><mo stretchy="false" form="postfix">)</mo></mrow><mn>6</mn></mfrac></mtd></mtr><mtr><mtd columnalign="right" style="text-align: right; padding-right: 0"></mtd></mtr></mtable><annotation encoding="application/x-tex">
\begin{align}
\sum_{i = 1}^{n} [i = 1] &amp;= 1 \\
\sum_{i = 1}^{n} 1 &amp;= n \\
\sum_{i = 1}^{n} i &amp;= \frac{i (i + 1)}{2} \\
\sum_{i = 1}^{n} i^2 &amp;= \frac{i (i + 1) (2i + 1)}{6} \\
\end{align}
</annotation></semantics></math> Therefore it is possible to compute
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msub><mi>M</mi><mi>k</mi></msub><mo stretchy="false" form="prefix">(</mo><mo stretchy="false" form="prefix">⌊</mo><mi>n</mi><mi>/</mi><mi>d</mi><mo stretchy="false" form="postfix">⌋</mo><mo stretchy="false" form="postfix">)</mo></mrow><annotation encoding="application/x-tex">M_k(\lfloor n / d \rfloor)</annotation></semantics></math>
for all possible values of
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mo stretchy="false" form="prefix">⌊</mo><mi>n</mi><mi>/</mi><mi>d</mi><mo stretchy="false" form="postfix">⌋</mo></mrow><annotation encoding="application/x-tex">\lfloor n / d \rfloor</annotation></semantics></math>
in
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>O</mi><mo stretchy="false" form="prefix">(</mo><msup><mi>n</mi><mrow><mn>3</mn><mi>/</mi><mn>4</mn></mrow></msup><mo stretchy="false" form="postfix">)</mo></mrow><annotation encoding="application/x-tex">O(n^{3/4})</annotation></semantics></math>
time. (Remember that uppercase means sum.)</p>
<p>Can we use the faster
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>O</mi><mo stretchy="false" form="prefix">(</mo><msup><mi>n</mi><mrow><mn>2</mn><mi>/</mi><mn>3</mn></mrow></msup><mo stretchy="false" form="postfix">)</mo></mrow><annotation encoding="application/x-tex">O(n^{2/3})</annotation></semantics></math>
method? The answer is yes because
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><msub><mi>m</mi><mi>k</mi></msub><annotation encoding="application/x-tex">m_k</annotation></semantics></math>
is multiplicative. I’ll refer to the <a
href="https://codeforces.com/blog/entry/54090">notes on Euler’s
sieve</a> mentioned earlier.</p>
<p>Remind you, we want to compute this.
<math display="block" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mtable><mtr><mtd columnalign="right" style="text-align: right; padding-right: 0"><msub><mi>s</mi><mrow><mi>k</mi><mo>,</mo><mi>u</mi></mrow></msub><mo stretchy="false" form="prefix">(</mo><mi>n</mi><mo>,</mo><mi>m</mi><mo stretchy="false" form="postfix">)</mo></mtd><mtd columnalign="left" style="text-align: left; padding-left: 0"><mo>=</mo><munderover><mo>∑</mo><mrow><mi>d</mi><mo>=</mo><mn>1</mn></mrow><mrow><mrow><mi>min</mi><mo>&#8289;</mo></mrow><mo stretchy="false" form="prefix">{</mo><mi>n</mi><mo>,</mo><mi>m</mi><mo stretchy="false" form="postfix">}</mo></mrow></munderover><msub><mi>m</mi><mi>k</mi></msub><mo stretchy="false" form="prefix">(</mo><mi>d</mi><mo stretchy="false" form="postfix">)</mo><mi>u</mi><mo stretchy="false" form="prefix">(</mo><mo stretchy="false" form="prefix">⌊</mo><mfrac><mi>n</mi><mi>d</mi></mfrac><mo stretchy="false" form="postfix">⌋</mo><mo>,</mo><mo stretchy="false" form="prefix">⌊</mo><mfrac><mi>m</mi><mi>d</mi></mfrac><mo stretchy="false" form="postfix">⌋</mo><mo stretchy="false" form="postfix">)</mo></mtd></mtr></mtable><annotation encoding="application/x-tex">
\begin{align}
s_{k, u}(n, m) &amp;= \sum_{d = 1}^{\min\{n, m\}}
    m_k(d)
    u(\lfloor \frac{n}{d} \rfloor, \lfloor \frac{m}{d} \rfloor)
\end{align}
</annotation></semantics></math> This is eerily familiar. In fact this
is almost what we did in the intermission, but now
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mi>u</mi><annotation encoding="application/x-tex">u</annotation></semantics></math>
takes two arguments.</p>
<p>How many values can the pair
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mo stretchy="false" form="prefix">(</mo><mo stretchy="false" form="prefix">⌊</mo><mi>n</mi><mi>/</mi><mi>d</mi><mo stretchy="false" form="postfix">⌋</mo><mo>,</mo><mo stretchy="false" form="prefix">⌊</mo><mi>m</mi><mi>/</mi><mi>d</mi><mo stretchy="false" form="postfix">⌋</mo><mo stretchy="false" form="postfix">)</mo></mrow><annotation encoding="application/x-tex">(\lfloor n / d \rfloor, \lfloor m / d \rfloor)</annotation></semantics></math>
take on? As
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mi>d</mi><annotation encoding="application/x-tex">d</annotation></semantics></math>
increases,
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mo stretchy="false" form="prefix">⌊</mo><mi>n</mi><mi>/</mi><mi>d</mi><mo stretchy="false" form="postfix">⌋</mo></mrow><annotation encoding="application/x-tex">\lfloor n / d \rfloor</annotation></semantics></math>
decreases, and it will take about
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mn>2</mn><msqrt><mi>n</mi></msqrt></mrow><annotation encoding="application/x-tex">2 \sqrt{n}</annotation></semantics></math>
steps doing so, and similarly for
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mo stretchy="false" form="prefix">⌊</mo><mi>n</mi><mi>/</mi><mi>d</mi><mo stretchy="false" form="postfix">⌋</mo></mrow><annotation encoding="application/x-tex">\lfloor n / d \rfloor</annotation></semantics></math>,
therefore
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mo stretchy="false" form="prefix">(</mo><mo stretchy="false" form="prefix">⌊</mo><mi>n</mi><mi>/</mi><mi>d</mi><mo stretchy="false" form="postfix">⌋</mo><mo>,</mo><mo stretchy="false" form="prefix">⌊</mo><mi>m</mi><mi>/</mi><mi>d</mi><mo stretchy="false" form="postfix">⌋</mo><mo stretchy="false" form="postfix">)</mo></mrow><annotation encoding="application/x-tex">(\lfloor n / d \rfloor, \lfloor m / d \rfloor)</annotation></semantics></math>
takes on a maximum of about
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mn>2</mn><mo stretchy="false" form="prefix">(</mo><msqrt><mi>n</mi></msqrt><mo>+</mo><msqrt><mi>m</mi></msqrt><mo stretchy="false" form="postfix">)</mo></mrow><annotation encoding="application/x-tex">2 (\sqrt{n} + \sqrt{m})</annotation></semantics></math>
steps (not a simple sum because the steps can overlap). For example for
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>n</mi><mo>=</mo><mn>10</mn></mrow><annotation encoding="application/x-tex">n = 10</annotation></semantics></math>
and
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>m</mi><mo>=</mo><mn>3</mn></mrow><annotation encoding="application/x-tex">m = 3</annotation></semantics></math>,
the combined steps like this (open the image in a new tab if it’s too
small for you):</p>
<figure>
<img src="images/pairs-values.svg" style="width:90.0%"
alt="Steps of change compared" />
<figcaption aria-hidden="true">Steps of change compared</figcaption>
</figure>
<p>Apply the exact same strategy as before: For the first interval, the
start is
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msub><mi>l</mi><mn>1</mn></msub><mo>=</mo><mn>1</mn></mrow><annotation encoding="application/x-tex">l_1 = 1</annotation></semantics></math>,
and end is
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msub><mi>r</mi><mn>1</mn></msub><mo>=</mo><mrow><mi>min</mi><mo>&#8289;</mo></mrow><mo stretchy="false" form="prefix">{</mo><mo stretchy="false" form="prefix">⌊</mo><mi>n</mi><mi>/</mi><mo stretchy="false" form="prefix">⌊</mo><mi>n</mi><mi>/</mi><msub><mi>l</mi><mn>1</mn></msub><mo stretchy="false" form="postfix">⌋</mo><mo stretchy="false" form="postfix">⌋</mo><mo>,</mo><mo stretchy="false" form="prefix">⌊</mo><mi>m</mi><mi>/</mi><mo stretchy="false" form="prefix">⌊</mo><mi>m</mi><mi>/</mi><msub><mi>l</mi><mn>1</mn></msub><mo stretchy="false" form="postfix">⌋</mo><mo stretchy="false" form="postfix">⌋</mo><mo stretchy="false" form="postfix">}</mo></mrow><annotation encoding="application/x-tex">r_1 = \min\{\lfloor n / \lfloor n / l_1 \rfloor \rfloor, \lfloor m / \lfloor m / l_1 \rfloor \rfloor\}</annotation></semantics></math>,
then for the second interval
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msub><mi>l</mi><mn>2</mn></msub><mo>=</mo><msub><mi>r</mi><mn>1</mn></msub><mo>+</mo><mn>1</mn></mrow><annotation encoding="application/x-tex">l_2 = r_1 + 1</annotation></semantics></math>
and
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msub><mi>r</mi><mn>2</mn></msub><mo>=</mo><mrow><mi>min</mi><mo>&#8289;</mo></mrow><mo stretchy="false" form="prefix">{</mo><mo stretchy="false" form="prefix">⌊</mo><mi>n</mi><mi>/</mi><mo stretchy="false" form="prefix">⌊</mo><mi>n</mi><mi>/</mi><msub><mi>l</mi><mn>2</mn></msub><mo stretchy="false" form="postfix">⌋</mo><mo stretchy="false" form="postfix">⌋</mo><mo>,</mo><mo stretchy="false" form="prefix">⌊</mo><mi>m</mi><mi>/</mi><mo stretchy="false" form="prefix">⌊</mo><mi>m</mi><mi>/</mi><msub><mi>l</mi><mn>2</mn></msub><mo stretchy="false" form="postfix">⌋</mo><mo stretchy="false" form="postfix">⌋</mo><mo stretchy="false" form="postfix">}</mo></mrow><annotation encoding="application/x-tex">r_2 = \min\{\lfloor n / \lfloor n / l_2 \rfloor \rfloor, \lfloor m / \lfloor m / l_2 \rfloor \rfloor\}</annotation></semantics></math>
and so on until
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mrow><mi>min</mi><mo>&#8289;</mo></mrow><mo stretchy="false" form="prefix">{</mo><mi>n</mi><mo>,</mo><mi>m</mi><mo stretchy="false" form="postfix">}</mo></mrow><annotation encoding="application/x-tex">\min\{n, m\}</annotation></semantics></math>.
The sum in each interval is then
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mo stretchy="false" form="prefix">(</mo><msub><mi>M</mi><mi>k</mi></msub><mo stretchy="false" form="prefix">(</mo><msub><mi>r</mi><mi>i</mi></msub><mo stretchy="false" form="postfix">)</mo><mo>−</mo><msub><mi>M</mi><mi>k</mi></msub><mo stretchy="false" form="prefix">(</mo><msub><mi>l</mi><mi>i</mi></msub><mo>−</mo><mn>1</mn><mo stretchy="false" form="postfix">)</mo><mo stretchy="false" form="postfix">)</mo><mi>f</mi><mo stretchy="false" form="prefix">(</mo><mo stretchy="false" form="prefix">⌊</mo><mi>n</mi><mi>/</mi><msub><mi>l</mi><mi>i</mi></msub><mo stretchy="false" form="postfix">⌋</mo><mo>,</mo><mo stretchy="false" form="prefix">⌊</mo><mi>m</mi><mi>/</mi><msub><mi>l</mi><mi>i</mi></msub><mo stretchy="false" form="postfix">⌋</mo><mo stretchy="false" form="postfix">)</mo></mrow><annotation encoding="application/x-tex">(M_k(r_i) - M_k(l_i - 1))f(\lfloor n / l_i \rfloor, \lfloor m / l_i \rfloor)</annotation></semantics></math>.</p>
<p>We can see that each
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><msub><mi>r</mi><mi>i</mi></msub><annotation encoding="application/x-tex">r_i</annotation></semantics></math>
and
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msub><mi>l</mi><mi>i</mi></msub><mo>−</mo><mn>1</mn></mrow><annotation encoding="application/x-tex">l_i - 1</annotation></semantics></math>
is either of the form
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mo stretchy="false" form="prefix">⌊</mo><mi>n</mi><mi>/</mi><mi>d</mi><mo stretchy="false" form="postfix">⌋</mo></mrow><annotation encoding="application/x-tex">\lfloor n / d \rfloor</annotation></semantics></math>
or
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mo stretchy="false" form="prefix">⌊</mo><mi>m</mi><mi>/</mi><mi>d</mi><mo stretchy="false" form="postfix">⌋</mo></mrow><annotation encoding="application/x-tex">\lfloor m / d \rfloor</annotation></semantics></math>
or
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mn>0</mn><annotation encoding="application/x-tex">0</annotation></semantics></math>.
For the algorithm to work,
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msub><mi>M</mi><mi>k</mi></msub><mo stretchy="false" form="prefix">(</mo><mn>0</mn><mo stretchy="false" form="postfix">)</mo></mrow><annotation encoding="application/x-tex">M_k(0)</annotation></semantics></math>
should be the natural choice of sum of no numbers,
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mn>0</mn><annotation encoding="application/x-tex">0</annotation></semantics></math>.
Therefore if we compute all
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msub><mi>M</mi><mi>k</mi></msub><mo stretchy="false" form="prefix">(</mo><mo stretchy="false" form="prefix">⌊</mo><mi>n</mi><mi>/</mi><mi>d</mi><mo stretchy="false" form="postfix">⌋</mo><mo stretchy="false" form="postfix">)</mo></mrow><annotation encoding="application/x-tex">M_k(\lfloor n / d \rfloor)</annotation></semantics></math>
and
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msub><mi>M</mi><mi>k</mi></msub><mo stretchy="false" form="prefix">(</mo><mo stretchy="false" form="prefix">⌊</mo><mi>m</mi><mi>/</mi><mi>d</mi><mo stretchy="false" form="postfix">⌋</mo><mo stretchy="false" form="postfix">)</mo></mrow><annotation encoding="application/x-tex">M_k(\lfloor m / d \rfloor)</annotation></semantics></math>
in
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>O</mi><mo stretchy="false" form="prefix">(</mo><mrow><mi>max</mi><mo>&#8289;</mo></mrow><mo stretchy="false" form="prefix">{</mo><mi>n</mi><mo>,</mo><mi>m</mi><msup><mo stretchy="false" form="postfix">}</mo><mrow><mn>2</mn><mi>/</mi><mn>3</mn></mrow></msup><mo stretchy="false" form="postfix">)</mo></mrow><annotation encoding="application/x-tex">O(\max\{n, m\}^{2/3})</annotation></semantics></math>
time, we can use
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>O</mi><mo stretchy="false" form="prefix">(</mo><msqrt><mi>n</mi></msqrt><mo stretchy="false" form="postfix">)</mo></mrow><annotation encoding="application/x-tex">O(\sqrt{n})</annotation></semantics></math>
time to combine them into our answer
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msub><mi>s</mi><mrow><mi>k</mi><mo>,</mo><mi>f</mi></mrow></msub><mo stretchy="false" form="prefix">(</mo><mi>n</mi><mo>,</mo><mi>m</mi><mo stretchy="false" form="postfix">)</mo></mrow><annotation encoding="application/x-tex">s_{k, f}(n, m)</annotation></semantics></math>
(provided that
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mi>f</mi><annotation encoding="application/x-tex">f</annotation></semantics></math>
is available in
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>O</mi><mo stretchy="false" form="prefix">(</mo><mn>1</mn><mo stretchy="false" form="postfix">)</mo></mrow><annotation encoding="application/x-tex">O(1)</annotation></semantics></math>,
which is the case.)</p>
<p>Applying this template to the three parts of the sum, which as a
reminder are:</p>
<p><math display="block" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mtable><mtr><mtd columnalign="right" style="text-align: right; padding-right: 0"><msub><mi>a</mi><mn>0</mn></msub><mo stretchy="false" form="prefix">(</mo><mi>n</mi><mo>,</mo><mi>m</mi><mo stretchy="false" form="postfix">)</mo></mtd><mtd columnalign="left" style="text-align: left; padding-left: 0"><mo>=</mo><munderover><mo>∑</mo><mrow><mi>d</mi><mo>=</mo><mn>1</mn></mrow><mrow><mrow><mi>min</mi><mo>&#8289;</mo></mrow><mo stretchy="false" form="prefix">{</mo><mi>n</mi><mo>,</mo><mi>m</mi><mo stretchy="false" form="postfix">}</mo></mrow></munderover><mi>μ</mi><mo stretchy="false" form="prefix">(</mo><mi>d</mi><mo stretchy="false" form="postfix">)</mo><mo stretchy="false" form="prefix">(</mo><mi>n</mi><mo>+</mo><mn>1</mn><mo stretchy="false" form="postfix">)</mo><mo stretchy="false" form="prefix">(</mo><mi>m</mi><mo>+</mo><mn>1</mn><mo stretchy="false" form="postfix">)</mo><mo stretchy="false" form="prefix">⌊</mo><mfrac><mi>n</mi><mi>d</mi></mfrac><mo stretchy="false" form="postfix">⌋</mo><mo stretchy="false" form="prefix">⌊</mo><mfrac><mi>m</mi><mi>d</mi></mfrac><mo stretchy="false" form="postfix">⌋</mo></mtd></mtr><mtr><mtd columnalign="right" style="text-align: right; padding-right: 0"><msub><mi>a</mi><mn>1</mn></msub><mo stretchy="false" form="prefix">(</mo><mi>n</mi><mo>,</mo><mi>m</mi><mo stretchy="false" form="postfix">)</mo></mtd><mtd columnalign="left" style="text-align: left; padding-left: 0"><mo>=</mo><munderover><mo>∑</mo><mrow><mi>d</mi><mo>=</mo><mn>1</mn></mrow><mrow><mrow><mi>min</mi><mo>&#8289;</mo></mrow><mo stretchy="false" form="prefix">{</mo><mi>n</mi><mo>,</mo><mi>m</mi><mo stretchy="false" form="postfix">}</mo></mrow></munderover><mi>μ</mi><mo stretchy="false" form="prefix">(</mo><mi>d</mi><mo stretchy="false" form="postfix">)</mo><mi>d</mi><mrow><mo stretchy="true" form="prefix">(</mo><mi>−</mi><mo stretchy="false" form="prefix">(</mo><mi>m</mi><mo>+</mo><mn>1</mn><mo stretchy="false" form="postfix">)</mo><mrow><mi>𝖨</mi><mi>𝖣</mi></mrow><mo stretchy="false" form="prefix">(</mo><mo stretchy="false" form="prefix">⌊</mo><mfrac><mi>n</mi><mi>d</mi></mfrac><mo stretchy="false" form="postfix">⌋</mo><mo stretchy="false" form="postfix">)</mo><mo stretchy="false" form="prefix">⌊</mo><mfrac><mi>m</mi><mi>d</mi></mfrac><mo stretchy="false" form="postfix">⌋</mo><mo>−</mo><mo stretchy="false" form="prefix">(</mo><mi>n</mi><mo>+</mo><mn>1</mn><mo stretchy="false" form="postfix">)</mo><mrow><mi>𝖨</mi><mi>𝖣</mi></mrow><mo stretchy="false" form="prefix">(</mo><mo stretchy="false" form="prefix">⌊</mo><mfrac><mi>m</mi><mi>d</mi></mfrac><mo stretchy="false" form="postfix">⌋</mo><mo stretchy="false" form="postfix">)</mo><mo stretchy="false" form="prefix">⌊</mo><mfrac><mi>n</mi><mi>d</mi></mfrac><mo stretchy="false" form="postfix">⌋</mo><mo stretchy="true" form="postfix">)</mo></mrow></mtd></mtr><mtr><mtd columnalign="right" style="text-align: right; padding-right: 0"><msub><mi>a</mi><mn>2</mn></msub><mo stretchy="false" form="prefix">(</mo><mi>n</mi><mo>,</mo><mi>m</mi><mo stretchy="false" form="postfix">)</mo></mtd><mtd columnalign="left" style="text-align: left; padding-left: 0"><mo>=</mo><munderover><mo>∑</mo><mrow><mi>d</mi><mo>=</mo><mn>1</mn></mrow><mrow><mrow><mi>min</mi><mo>&#8289;</mo></mrow><mo stretchy="false" form="prefix">{</mo><mi>n</mi><mo>,</mo><mi>m</mi><mo stretchy="false" form="postfix">}</mo></mrow></munderover><mi>μ</mi><mo stretchy="false" form="prefix">(</mo><mi>d</mi><mo stretchy="false" form="postfix">)</mo><msup><mi>d</mi><mn>2</mn></msup><mrow><mi>𝖨</mi><mi>𝖣</mi></mrow><mo stretchy="false" form="prefix">(</mo><mo stretchy="false" form="prefix">⌊</mo><mfrac><mi>n</mi><mi>d</mi></mfrac><mo stretchy="false" form="postfix">⌋</mo><mo stretchy="false" form="postfix">)</mo><mrow><mi>𝖨</mi><mi>𝖣</mi></mrow><mo stretchy="false" form="prefix">(</mo><mo stretchy="false" form="prefix">⌊</mo><mfrac><mi>m</mi><mi>d</mi></mfrac><mo stretchy="false" form="postfix">⌋</mo><mo stretchy="false" form="postfix">)</mo></mtd></mtr></mtable><annotation encoding="application/x-tex">\begin{align}
a_0(n, m) &amp;= \sum_{d = 1}^{\min\{n, m\}}
    \mu(d)
    (n + 1) (m + 1)
    \lfloor \frac{n}{d} \rfloor
    \lfloor \frac{m}{d} \rfloor \\

a_1(n, m) &amp;= \sum_{d = 1}^{\min\{n, m\}}
    \mu(d) d
    \left(
    -
        (m + 1)
        \mathsf{ID}(\lfloor \frac{n}{d} \rfloor)
        \lfloor \frac{m}{d} \rfloor
    -
        (n + 1)
        \mathsf{ID}(\lfloor \frac{m}{d} \rfloor)
        \lfloor \frac{n}{d} \rfloor
    \right) \\

a_2(n, m) &amp;= \sum_{d = 1}^{\min\{n, m\}}
    \mu(d) d^2
    \mathsf{ID}(\lfloor \frac{n}{d} \rfloor)
    \mathsf{ID}(\lfloor \frac{m}{d} \rfloor)
\end{align}</annotation></semantics></math></p>
<p>We can have our answer
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mn>4</mn><mo stretchy="false" form="prefix">(</mo><msub><mi>a</mi><mn>0</mn></msub><mo stretchy="false" form="prefix">(</mo><mi>n</mi><mo>,</mo><mi>m</mi><mo stretchy="false" form="postfix">)</mo><mo>+</mo><msub><mi>a</mi><mn>1</mn></msub><mo stretchy="false" form="prefix">(</mo><mi>n</mi><mo>,</mo><mi>m</mi><mo stretchy="false" form="postfix">)</mo><mo>+</mo><msub><mi>a</mi><mn>2</mn></msub><mo stretchy="false" form="prefix">(</mo><mi>n</mi><mo>,</mo><mi>m</mi><mo stretchy="false" form="postfix">)</mo><mo stretchy="false" form="postfix">)</mo></mrow><annotation encoding="application/x-tex">4 (a_0(n, m) + a_1(n, m) + a_2(n, m))</annotation></semantics></math>
in
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>O</mi><mo stretchy="false" form="prefix">(</mo><mrow><mi>max</mi><mo>&#8289;</mo></mrow><mo stretchy="false" form="prefix">{</mo><mi>n</mi><mo>,</mo><mi>m</mi><msup><mo stretchy="false" form="postfix">}</mo><mrow><mn>2</mn><mi>/</mi><mn>3</mn></mrow></msup><mo stretchy="false" form="postfix">)</mo></mrow><annotation encoding="application/x-tex">O(\max\{n, m\}^{2/3})</annotation></semantics></math>
time and
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>O</mi><mo stretchy="false" form="prefix">(</mo><mrow><mi>max</mi><mo>&#8289;</mo></mrow><mo stretchy="false" form="prefix">{</mo><mi>n</mi><mo>,</mo><mi>m</mi><msup><mo stretchy="false" form="postfix">}</mo><mrow><mn>2</mn><mi>/</mi><mn>3</mn></mrow></msup><mo stretchy="false" form="postfix">)</mo></mrow><annotation encoding="application/x-tex">O(\max\{n, m\}^{2/3})</annotation></semantics></math>
space.</p>
<p>Phew, that was a whopping three thousand words according to Typora.
Admittedly though it does count words in LaTeX code, which may or may
not represent the effort needed to read math notation.</p>
<h2 id="a-few-more-details">A few more details</h2>
<p>The problem requires modulo arithmetic, otherwise word-sized integers
won’t hold such large numbers. In my code supporting class
<code>mo</code> is used for this purpose. I worried that it would hinder
optimization, but casually playing around on <a
href="https://godbolt.org" class="uri">https://godbolt.org</a> shows
that it works exactly the same as using functions while not wrapping the
number in a class.</p>
<p>Since this method requires calculating three things at once, I wrote
this tiny function that ‘vectorizes’ a function to multiple
<code>std::array</code> ‘vectors’. It comes into play quite a few times
in my code and cleans up the code quite a bit. It seems to optimize
well, with the loop unrolled and function properly inlined at least when
tested under recent Clang. Quite a bit of what I learned while solving
this kata is actually for writing this.</p>
<div class="sourceCode" id="cb1"><pre
class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb1-1"><a href="#cb1-1" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">typename</span> Func<span class="op">,</span> <span class="dt">size_t</span> N<span class="op">,</span> <span class="kw">typename</span><span class="op">...</span> Args<span class="op">&gt;</span></span>
<span id="cb1-2"><a href="#cb1-2" aria-hidden="true" tabindex="-1"></a><span class="kw">decltype</span><span class="op">(</span><span class="kw">auto</span><span class="op">)</span> arrf<span class="op">(</span>Func f<span class="op">,</span> <span class="bu">std::</span>array<span class="op">&lt;</span>Args<span class="op">,</span> N<span class="op">&gt;...</span> args<span class="op">)</span> <span class="op">{</span></span>
<span id="cb1-3"><a href="#cb1-3" aria-hidden="true" tabindex="-1"></a>    <span class="bu">std::</span>array<span class="op">&lt;</span><span class="kw">decltype</span><span class="op">(</span>f<span class="op">(</span>args<span class="op">[</span><span class="dv">0</span><span class="op">]...)),</span> N<span class="op">&gt;</span> res<span class="op">;</span></span>
<span id="cb1-4"><a href="#cb1-4" aria-hidden="true" tabindex="-1"></a>    <span class="cf">for</span> <span class="op">(</span><span class="dt">size_t</span> i <span class="op">=</span> <span class="dv">0</span><span class="op">;</span> i <span class="op">!=</span> res<span class="op">.</span>size<span class="op">();</span> i <span class="op">++)</span> <span class="op">{</span></span>
<span id="cb1-5"><a href="#cb1-5" aria-hidden="true" tabindex="-1"></a>        res<span class="op">[</span>i<span class="op">]</span> <span class="op">=</span> f<span class="op">(</span>args<span class="op">[</span>i<span class="op">]...);</span></span>
<span id="cb1-6"><a href="#cb1-6" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span></span>
<span id="cb1-7"><a href="#cb1-7" aria-hidden="true" tabindex="-1"></a>    <span class="cf">return</span> res<span class="op">;</span></span>
<span id="cb1-8"><a href="#cb1-8" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<p>I also took the opportunity to enjoy many post-C++11 features such as
initializer lists, <code>std::optional</code>, <code>std::array</code>,
<code>std::unordered_map</code>, parameter packs
<code>typename... Args</code>, and maybe some others I’ve missed. I did
not get to use these features when I used to do competitive programming
a few years ago because of the poor adoption of up-to-date compilers.
It’s a nice refresher doing these things at a slightly higher level of
abstraction while sacrificing little to no efficiency, in a modernized
language that is admittedly quite old but also more alive than
ever.</p>]]></description>
    </item>
    <item>
        <title>Heyting algebra made unnecessarily complex</title>
        <pubDate>Thu, 06 Feb 2020 00:00:00 +0000</pubDate>
        <guid isPermaLink="true">https://dram.page/p/heyting-algebra</guid>
        <description><![CDATA[]]></description>
    </item>
    <item>
        <title>What happens when you foreign import “wrapper”?</title>
        <pubDate>Wed, 29 Jan 2020 00:00:00 +0000</pubDate>
        <guid isPermaLink="true">https://dram.page/p/foreign-wrapper</guid>
        <description><![CDATA[]]></description>
    </item>
    <item>
        <title>6 步搞懂 FFT</title>
        <pubDate>Sun, 15 Sep 2019 00:00:00 +0000</pubDate>
        <guid isPermaLink="true">https://dram.page/p/fft-easy</guid>
        <description><![CDATA[]]></description>
    </item>
    <item>
        <title>Stack-based Clash environment</title>
        <pubDate>Mon, 05 Aug 2019 00:00:00 +0000</pubDate>
        <guid isPermaLink="true">https://dram.page/p/clash-with-stack</guid>
        <description><![CDATA[]]></description>
    </item>
    <item>
        <title>Bootstrapping Nix</title>
        <pubDate>Thu, 24 Jan 2019 00:00:00 +0000</pubDate>
        <guid isPermaLink="true">https://dram.page/p/bootstrapping-nix</guid>
        <description><![CDATA[]]></description>
    </item>
    <item>
        <title>用 2 盏灯也能实现群聊</title>
        <pubDate>Fri, 18 May 2018 00:00:00 +0000</pubDate>
        <guid isPermaLink="true">https://dram.page/p/lampcomms</guid>
        <description><![CDATA[]]></description>
    </item>
    <item>
        <title>CPS、ANF、Monad 和 Callback hell</title>
        <pubDate>Tue, 28 Mar 2017 00:00:00 +0000</pubDate>
        <guid isPermaLink="true">https://dram.page/p/cps-anf-monad-callback</guid>
        <description><![CDATA[]]></description>
    </item>
    <item>
        <title>Möbius 反演</title>
        <pubDate>Sat, 18 Mar 2017 00:00:00 +0000</pubDate>
        <guid isPermaLink="true">https://dram.page/p/mobius-inversion</guid>
        <description><![CDATA[]]></description>
    </item>
    <item>
        <title>有关 monad 的一些想法 (4)</title>
        <pubDate>Wed, 25 Jan 2017 00:00:00 +0000</pubDate>
        <guid isPermaLink="true">https://dram.page/p/on-monad-4</guid>
        <description><![CDATA[]]></description>
    </item>
    <item>
        <title>有关 monad 的一些想法 (3)</title>
        <pubDate>Mon, 23 Jan 2017 00:00:00 +0000</pubDate>
        <guid isPermaLink="true">https://dram.page/p/on-monad-3</guid>
        <description><![CDATA[]]></description>
    </item>
    <item>
        <title>C 语言注释的妙用</title>
        <pubDate>Fri, 13 Jan 2017 00:00:00 +0000</pubDate>
        <guid isPermaLink="true">https://dram.page/p/comment-magic</guid>
        <description><![CDATA[]]></description>
    </item>
    <item>
        <title>有关 monad 的一些想法 (2)</title>
        <pubDate>Mon, 26 Dec 2016 00:00:00 +0000</pubDate>
        <guid isPermaLink="true">https://dram.page/p/on-monad-2</guid>
        <description><![CDATA[]]></description>
    </item>
    <item>
        <title>有关 monad 的一些想法 (1)</title>
        <pubDate>Fri, 02 Dec 2016 00:00:00 +0000</pubDate>
        <guid isPermaLink="true">https://dram.page/p/on-monad-1</guid>
        <description><![CDATA[]]></description>
    </item>
    <item>
        <title>表达式归一化和 Traversable, Generics</title>
        <pubDate>Thu, 02 Jun 2016 00:00:00 +0000</pubDate>
        <guid isPermaLink="true">https://dram.page/p/generic-unification</guid>
        <description><![CDATA[]]></description>
    </item>
    <item>
        <title>表达式归一化与 Free Monad</title>
        <pubDate>Sun, 22 May 2016 00:00:00 +0000</pubDate>
        <guid isPermaLink="true">https://dram.page/p/unification</guid>
        <description><![CDATA[]]></description>
    </item>
    <item>
        <title>七树归一</title>
        <pubDate>Wed, 10 Feb 2016 00:00:00 +0000</pubDate>
        <guid isPermaLink="true">https://dram.page/p/seven-trees</guid>
        <description><![CDATA[]]></description>
    </item>
    <item>
        <title>Chair Trees (SPOJ MKTHNUM)</title>
        <pubDate>Wed, 30 Dec 2015 00:00:00 +0000</pubDate>
        <guid isPermaLink="true">https://dram.page/p/chair-tree</guid>
        <description><![CDATA[]]></description>
    </item>
    <item>
        <title>Splay 和 Link/cut tree (HDU 2475)</title>
        <pubDate>Mon, 14 Dec 2015 00:00:00 +0000</pubDate>
        <guid isPermaLink="true">https://dram.page/p/splay-lct</guid>
        <description><![CDATA[]]></description>
    </item>
    <item>
        <title>Hello World</title>
        <pubDate>Sat, 22 Aug 2015 00:00:00 +0000</pubDate>
        <guid isPermaLink="true">https://dram.page/p/hello-world</guid>
        <description><![CDATA[]]></description>
    </item>
</channel>
</rss>
