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.
| Project | Language | Status | Due Date | Latest Update |
|---|---|---|---|---|
| Personal Website | Hugo | Ongoing | None | The site is live. There are some TODOs. Need to work on categorization, tagging, and layout improvements. |
| Laravel From Scratch | Laravel (PHP) | In-Progress | 2026-03-31 | Episode 8 |
| PRM | Laravel (PHP) | In-Progress | 2026-03-31 | Working alongside other Laravel projects. |
| Client Website (J.L.) | Laravel (PHP) | In-Progress | 2026-03-31 | Working alongside other Laravel projects. |
| Project Euler | C | Ongoing | None | Working on P25. BigInt (AI gen) was a waste of time, need to rewrite |
| Practice Java | Java | Paused | None | Installed, need to find a good project. |
| Practice Python | Python | Paused | None | Installed, need to find a good project. |
| Learn Go | Go | Paused | None | Installed, work on LDAP Injector from ippsec. |
| Learn Rust | Rust | Haven’t Started | None | Installed, need a good tutorial project. |
| Learn Elixir | Elixir | Haven’t Started | None | Installed, need a good tutorial project. |
| Learn Haskell | Haskell | Haven’t Started | None | Installed, need a good tutorial project. |
| Linux+ | N/A | In-Progress | 2026-03-31 | Reading Chapter 4. |
| Cyber Quest 2026 | N/A | In-Progress | 2026-02-28 | Finished quiz 1 with 75%. Need to work on ARP poisoning and timestamp adjustments in WireShark. |
| Operating Systems | N/A | In-Progress | 2026-03-31 | Reading Chapter 4: Abstraction |
| Grey-Hat Hacking | Various | In-Progress | 2026-03-31 | Reading Chapter 8: Threat Hunting Lab |
| PHP Time Tracker | PHP | Beta Finished | None | Working on a basic level. Could use a couple more updates to make it fully functional. |
| HTTP Status Code Reader | C | Complete | 2026-02-18 | Complete. Could potentially upgrade for more advanced functions or follow redirects. |
| ZSH Configuration | bash/zsh | Complete | None | Sort of an ongoing process, but complete for now. Works good. |
| Network Protocols | C | In-Progress | None | IPv4 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, and .
Binary doesn’t have a negative sign, to opposites are represented by the complement. A flipping of every bit. So, has a one’s complement of . 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 . 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 in binary, represented in 5 bits, is . The 1’s complement of is therefore . Taken as a decimal number, this would equal . But, that isn’t how it works in the complement system.
For a 1’s complement, the complement of () 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 is added to the binary value. The 2’s complement of is therefore . In decimal, this equals .
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
- =
- =
- =
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 (which is ) is interpreted as , not .
- =
- =
- =
To see why is in 1’s complement, invert it:
Since the original value started with a leading , it is interpreted as a negative value in this encoding, so the result is .
A major drawback of 1’s complement is that it has two representations of zero:
- =
- =
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 . This is why is interpreted as in 2’s complement.
- =
- =
- =
To verify as , reverse the process:
- Invert the bits:
- Add :
- Apply the negative sign:
Likewise, in 2’s complement is:
- Invert the bits:
- Add :
- Therefore:
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 can mean:
- (unsigned)
- (1’s complement)
- (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 total bit patterns, so arithmetic wraps around modulo . In that system, the value that behaves like is the one that adds with to produce (mod ).
Since in binary is , the pattern is used to represent in 2’s complement.
This is why the unsigned value and the signed value can share the same bit pattern.
Summary
Using the 5-bit value for , :
- 1’s complement of : (represents in 1’s complement)
- 2’s complement of : (represents 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 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.
0x8000 + 0x8000 = 0x10000
0x8000 + 0x8000 = 0x10000The 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
0xFFFFand0x0001. - Standard addition:
0xFFFF+0x0001=0x10000. - End-around carry: Take that 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.