365 Days of Code - Day 034

Project Status

Going to start including the project status table moving forward. This should help better track progress over the year.

ProjectLanguageStatusDue DateLatest Update
Personal WebsiteHugoOngoingNoneThe site is live. There are some TODOs. Need to work on categorization, tagging, and layout improvements.
Laravel From ScratchLaravel (PHP)In-Progress2026-03-31Episode 8
PRMLaravel (PHP)In-Progress2026-03-31Working alongside other Laravel projects.
Client Website (J.L.)Laravel (PHP)In-Progress2026-03-31Working alongside other Laravel projects.
Project EulerCOngoingNoneWorking on P25. BigInt (AI gen) was a waste of time, need to rewrite
Practice JavaJavaPausedNoneInstalled, need to find a good project.
Practice PythonPythonPausedNoneInstalled, need to find a good project.
Learn GoGoPausedNoneInstalled, work on LDAP Injector from ippsec.
Learn RustRustHaven’t StartedNoneInstalled, need a good tutorial project.
Learn ElixirElixirHaven’t StartedNoneInstalled, need a good tutorial project.
Learn HaskellHaskellHaven’t StartedNoneInstalled, need a good tutorial project.
Linux+N/AIn-Progress2026-03-31Reading Chapter 4.
Cyber Quest 2026N/AIn-Progress2026-02-28Finished quiz 1 with 75%. Need to work on ARP poisoning and timestamp adjustments in WireShark.
Operating SystemsN/AIn-Progress2026-03-31Reading Chapter 4: Abstraction
Grey-Hat HackingVariousIn-Progress2026-03-31Reading Chapter 8: Threat Hunting Lab
PHP Time TrackerPHPBeta FinishedNoneWorking on a basic level. Could use a couple more updates to make it fully functional.
HTTP Status Code ReaderCComplete2026-02-18Complete. Could potentially upgrade for more advanced functions or follow redirects.
ZSH Configurationbash/zshCompleteNoneSort of an ongoing process, but complete for now. Works good.
Network ProtocolsCIn-ProgressNoneIPv4 Datagram Header built, working on checksum calculation

Network Protocols - Calculating the IP Header Checksum

I’m working through the checksum calculation today. I’ve read up on RFC 1071, RFC 1141 and RFC 1624, which all have to do with implementing checksum calculations for the Internet Protocol. The process seems relatively simple, but I needed some refreshment on terminology since I’m not well versed in binary math and manipulation.

The 1’s Complement and 2’s Complement

The term complement is thrown around quite a bit when reading about checksum calculation, and I had to refresh myself on what this actually means.

In decimal math, the opposite of a positive number is the same number in negative. So, 55 and 5-5.

Binary doesn’t have a negative sign, to opposites are represented by the complement. A flipping of every bit. So, 000011110000 1111 has a one’s complement of 111100001111 0000. This is equivalent to a bitwise NOT operation. Why is this the case?

Boolean Algebra

I had to bust out a text book to help understand this a bit deeper. I’m not satisfied with knowing something is true without digging into why it is true. I have a copy of Discrete Mathematics with Applications by Susanna S. Epp at my desk for purposes such as this. I figured there was likely some information on binary complements in the book. The index of terms led me to Chapter 6.4 on Boolean Algebra, Russell’s Paradox, and the Halting Problem. Here we get the Complement Law and Double Complement Law for boolean algebra, with associated proofs. These proofs lead directly into Russell’s Paradox, The Barber Puzzle, and Turing’s Halting Problem. Which are all interesting reads on their own. I’m starting to get into the weeds here though, so I did a little research online and found an explanation on the Electrical and Computer Engineering subreddit (opens in a new tab). This post (opens in a new tab) explains both 1’s and 2’s complements with some examples with the number 44. I’m going to repost an expanded summary and minor excerpts of the explanation, should the reddit post ever become unavailable.

Complements Explainer Example

The number 44 in binary, represented in 5 bits, is 0010000100. The 1’s complement of 44 is therefore 1101111011. Taken as a decimal number, this would equal 2727. But, that isn’t how it works in the complement system.

For a 1’s complement, the complement of 44 (4-4) is a straight inverse (NOT) operation, as shown in the previous sentence.

For a 2’s complement, a 1’s complement is taken, and then 11 is added to the binary value. The 2’s complement of 44 is therefore 1110011100. In decimal, this equals 2828.

One of the key insights here, is that we have to decide how we are going to interpret the binary value. Not all representations mean the same thing in every context. There are at least 3 representations of the binary values that must be considered:

  • Unsigned
  • 1’s complement
  • 2’s complement

Each representation differs in how the binary is going to interpreted. 1’s and 2’s complements are called a signed encoding scheme.

Unsigned
  • 0010000100 = 44
  • 1101111011 = 2727
  • 1110011100 = 2828
1’s Complement

In a 1’s complement encoding, a negative value is represented by inverting all bits of the corresponding positive value. This means the inverse of 0010000100 (which is 1101111011) is interpreted as 4-4, not 2727.

  • 0010000100 = 44
  • 1101111011 = 4-4
  • 1110011100 = 3-3

To see why 1110011100 is 3-3 in 1’s complement, invert it:

  • 11100NOT00011=311100 \xrightarrow{\text{NOT}} 00011 = 3

Since the original value started with a leading 11, it is interpreted as a negative value in this encoding, so the result is 3-3.

A major drawback of 1’s complement is that it has two representations of zero:

  • 0000000000 = +0+0
  • 1111111111 = 0-0

This duplicate zero is one of the reasons 1’s complement is not commonly used in modern systems.

2’s Complement

In a 2’s complement encoding, a negative value is represented by inverting all bits and then adding 11. This is why 1110011100 is interpreted as 4-4 in 2’s complement.

  • 0010000100 = 44
  • 1101111011 = 5-5
  • 1110011100 = 4-4

To verify 1110011100 as 4-4, reverse the process:

  1. Invert the bits: 111000001111100 \to 00011
  2. Add 11: 00011+1=0010000011 + 1 = 00100
  3. Apply the negative sign: 4-4

Likewise, 1101111011 in 2’s complement is:

  1. Invert the bits: 110110010011011 \to 00100
  2. Add 11: 00100+1=0010100100 + 1 = 00101
  3. Therefore: 5-5
Why the Same Bits Mean Different Things

This is the part that usually feels strange at first: the bit pattern itself does not inherently contain a sign. The meaning comes from the encoding scheme you choose.

For example, the same 5-bit pattern 1110011100 can mean:

  • 2828 (unsigned)
  • 3-3 (1’s complement)
  • 4-4 (2’s complement)

So when working with binary, you are never just asking, “What number is this?” You are asking:

  • “What number is this, under this encoding scheme?”
A Quick Intuition for 2’s Complement

A helpful way to think about 2’s complement is wraparound arithmetic.

With 5 bits, there are 25=322^5 = 32 total bit patterns, so arithmetic wraps around modulo 3232. In that system, the value that behaves like 4-4 is the one that adds with 44 to produce 00 (mod 3232).

4+28=320(mod32) 4 + 28 = 32 \equiv 0 \pmod{32}

Since 2828 in binary is 1110011100, the pattern 1110011100 is used to represent 4-4 in 2’s complement.

This is why the unsigned value 2828 and the signed value 4-4 can share the same bit pattern.

Summary

Using the 5-bit value for 44, 0010000100:

  • 1’s complement of 44: 1101111011 (represents 4-4 in 1’s complement)
  • 2’s complement of 44: 1110011100 (represents 4-4 in 2’s complement)

The key concept is that binary patterns are interpreted according to a representation scheme. Without specifying whether the value is unsigned, 1’s complement, or 2’s complement, the bit pattern alone is ambiguous.

The Carry Bit

The IP Header checksum relies on adding numbers together in 16-bit chunks. 16-bits has a maximum decimal value of 6553565535 and a max binary value of 0xFFFF. If you add two values and the result exceeds 0xFFFF, the extra bits overflow and would be lost.

math
0x8000 + 0x8000 = 0x10000
0x8000 + 0x8000 = 0x10000

The 11 in the 17th bit would be lost and the result would be 0x0000. The 17th bit in this example is the carry bit.

Standard binary addition ignores the carry bit (this is called 2’s complement arithmetic, which is how standard CPU addition works). However, 1’s Complement Addition has a special rule: You must never lose the carry bit. If an addition causes an overflow (a carry), you take that carry bit from the 17th position and add it back into the lowest bit (the 1st position) of your sum. This is formally called “end-around carry.”

Example of 1’s Complement Addition

  • Add 0xFFFF and 0x0001.
  • Standard addition: 0xFFFF + 0x0001 = 0x10000.
  • End-around carry: Take that 11 from the 17th position, erase it, and add it to the bottom.
  • Result: 0x0000 + 0x0001 = 0x0001.

The RFC Requirement for 1’s Complement

RFC 791 states that the checksum is:

The checksum field is the 16 bit one’s complement of the one’s complement sum of all 16 bit words in the header. For purposes of computing the checksum, the value of the checksum field is zero.

With this information, we can determine that the checksum calculation will require three steps:

Step A: Accumulate (The One’s Complement Sum)

We read our IP header in 16-bit chunks. Because standard CPUs do not automatically perform “end-around carry” for us, we cheat. We create a 32-bit bucket (variable) to hold our sum. Because the bucket is 32 bits wide, the 17th-bit carries never overflow and disappear; they simply accumulate safely in the upper 16 bits of our 32-bit bucket.

Step B: Fold (End-Around Carry)

Once we have added every 16-bit word of the header into our 32-bit bucket, we look at the upper 16 bits. If there is anything up there, we shift it down and add it to the lower 16 bits. We have now manually performed the “end-around carry.”

Step C: Invert (The One’s Complement)

Finally, we take our folded 16-bit sum and flip all the bits (the one’s complement). This final, flipped value is the checksum we write into the IP header.

Conclusion

All of this time spent on researching the checksum, history and mathematics ate up most of my time today. The actual checksum code will have to wait until tomorrow.