Where bits become
physical.
You've seen bits as numbers and bits as letters. Now we go all the way down to the actual switches on a chip. A modern CPU has tens of billions of them. They do one thing: let current through, or don't. From that single trick, every program you've ever run is built.
The transistor: a switch you can write to
In 1947, at Bell Labs in New Jersey, a physicist named William Shockley placed two gold foil contacts onto a sliver of germanium. He applied a small voltage. And for the first time in history, one electrical signal controlled another. He called it a transistor.
He had no idea he had just built the foundation of every computer, every phone, every blockchain, and every line of code ever written.
That single switch is still the only trick computing has ever used. Everything else is just how many of them you can wire together, and how fast you can make them switch.
A transistor is a tiny three-terminal device. Two of the terminals carry current; the third controls whether that current flows. Apply a voltage to the control terminal and the circuit closes; current flows. Remove it and the circuit opens.
That's it. That is the foundation of computing. Every laptop, phone, satellite, and smart fridge is, at its core, a city of these switches connected to each other in just the right way. Map "current flowing" to 1 and "no current" to 0, and you've bridged the physical world into the binary one you read about on the first page.
Two transistors → one logic gate
Wire two transistors in series and you've made a circuit that outputs HIGH only when both inputs are HIGH. That's an AND gate. Wire them in parallel and the output goes HIGH when either is HIGH. That's OR. Add a single inverting transistor and you've got NOT. From those three, you can build everything else.
The four core gates
Try it: wire your own gate
&, |, ~, and ^ as bitwise operators in code. Those operators are these gates. When your program runs x & y, the CPU is literally feeding the bits of x and y into AND gates etched in silicon.When you write x & y in Rust or C the compiler emits a single AND instruction. The CPU feeds the bits of x and y into AND gates etched into silicon. The same gates you just simulated above. ← see: binary
Building an adder from gates
Here's where it gets satisfying. Let's compose simple gates into something that does real work: add two numbers. The CPU's arithmetic unit is, at heart, a chain of these.
Half adder: 1 bit + 1 bit
What does adding two bits look like?
| A | B | Sum | Carry |
|---|---|---|---|
| 0 | 0 | 0 | 0 |
| 0 | 1 | 1 | 0 |
| 1 | 0 | 1 | 0 |
| 1 | 1 | 0 | 1 |
Look at the Sum column: it's exactly the XOR truth table. Look at the Carry column: it's exactly the AND truth table. So a half adder is just:
Sum = A XOR B
Carry = A AND B
Full adder: 1 bit + 1 bit + carry-in
To add multi-bit numbers, each bit position also accepts a carry from the position to its right. A full adder takes three inputs (A, B, Cin) and produces two outputs (Sum, Cout). It's two half adders glued together with an OR.
Simulating a full adder in code
// Sum = A ⊕ B ⊕ Cin
// Cout = (A·B) + (Cin·(A⊕B))
fn full_adder(a: u8, b: u8, cin: u8) -> (u8, u8) {
let sum = a ^ b ^ cin;
let cout = (a & b) | (cin & (a ^ b));
(sum, cout)
}
// chain 8 full adders to add two bytes
fn add_u8(a: u8, b: u8) -> u8 {
let mut result = 0;
let mut carry = 0;
for i in 0..8 {
let ai = (a >> i) & 1;
let bi = (b >> i) & 1;
let (s, c) = full_adder(ai, bi, carry);
result |= s << i;
carry = c;
}
result
}
fn main() {
println!("{}", add_u8(23, 42)); // 65
}#include <stdio.h>
#include <stdint.h>
void full_adder(uint8_t a, uint8_t b, uint8_t cin,
uint8_t *sum, uint8_t *cout) {
*sum = a ^ b ^ cin;
*cout = (a & b) | (cin & (a ^ b));
}
uint8_t add_u8(uint8_t a, uint8_t b) {
uint8_t result = 0, carry = 0;
for (int i = 0; i < 8; i++) {
uint8_t ai = (a >> i) & 1;
uint8_t bi = (b >> i) & 1;
uint8_t s, c;
full_adder(ai, bi, carry, &s, &c);
result |= s << i;
carry = c;
}
return result;
}
int main(void) {
printf("%u\n", add_u8(23, 42)); // 65
return 0;
}x + y. Real CPUs use faster variants (carry-lookahead, Kogge-Stone) for speed, but the logic is identical.The full adder above is a software simulation of the actual circuit in your CPU. When your CPU executes ADD RAX, RBX it is running this exact logic in hardware at four billion cycles per second. ← see: cpu
NAND universality, CMOS & the modern chip
NAND is universal
One of the most beautiful results in digital design: every Boolean function can be built from NAND gates alone. (Same for NOR.) NAND is a single gate that, by composition, gives you AND, OR, NOT, XOR, adders, multipliers, memory cells, and ultimately entire CPUs.
| built from NAND | recipe |
|---|---|
| NOT(A) | NAND(A, A) |
| AND(A, B) | NOT(NAND(A, B)) |
| OR(A, B) | NAND(NOT(A), NOT(B)) |
| XOR(A, B) | NAND of three NANDs (4 gates total) |
Why does this matter in practice? Because manufacturing one type of gate is cheaper, more uniform, and easier to optimize. NAND-only design is a real strategy used in everything from flash memory to ASIC layout.
CMOS: how a real chip is wired
Modern chips use CMOS (Complementary Metal-Oxide-Semiconductor), which pairs two transistor types: NMOS (conducts when its gate is HIGH) and PMOS (conducts when LOW). They're mirror images, and together they give you four critical properties:
Memory: when a circuit remembers
So far every circuit we've discussed is combinational: output is a pure function of input. To make memory, you need feedback. Connect two NOR gates in a loop and you get an SR latch, a circuit with two stable states. Set it HIGH, it stays HIGH. Reset it, stays LOW. You've just built a 1-bit memory cell, the ancestor of every register, cache line, and DRAM cell.
Add a clock signal so the latch only updates on a rising edge, and you have a flip-flop. Stack 32 flip-flops side by side and that's a register. Stack thousands of registers and that's L1 cache. Pair logic + memory + a clock and that's a CPU.
The full stack, one picture
- Electrons flow (or don't) through silicon doped with impurities.
- That flow is gated by a transistor, our atomic switch.
- A few transistors form a logic gate (NAND, NOR, XOR, …).
- Gates compose into adders, multiplexers, latches.
- Latches and ALUs compose into a CPU with registers and instructions.
- Instructions encode as bits, the binary you read about on page 1.
- Bits encode numbers, characters (page 2: ASCII), and code.
- And that is how a string like
"hello"ends up flickering electrons in your CPU at 5 GHz.
Gates in Bitcoin: SHA-256
Every hash function you have ever used is built from logic gates. SHA-256, the algorithm that secures Bitcoin, performs 64 rounds of operations on its input data. Every single operation is one of these:
- AND gate:
(e & f) - XOR gate:
(a ^ b) - NOT gate:
(~e) - Bit rotation:
x.rotate_right(n) - Bit shift:
x >> n
The same five operations. The same gates you learned on this page. Running on the same transistors Shockley invented in 1947. Here is the heart of one SHA-256 round, in both languages:
// Three of the core functions inside SHA-256.
// Every operation is a gate you met on this page.
fn ch(e: u32, f: u32, g: u32) -> u32 {
(e & f) ^ (!e & g)
// AND gate, XOR gate, NOT gate
// three gates, one function
// 64 times per hash
// billions of times per second
// on every Bitcoin miner on Earth
}
fn maj(a: u32, b: u32, c: u32) -> u32 {
(a & b) ^ (a & c) ^ (b & c)
// majority vote across three bits
// three AND gates, two XOR gates
}
fn rotr(x: u32, n: u32) -> u32 {
x.rotate_right(n)
// bit rotation
// shifts bits around the 32-bit word
// no new gate type needed
}#include <stdint.h>
// The same three functions in C.
uint32_t ch(uint32_t e, uint32_t f, uint32_t g) {
return (e & f) ^ (~e & g);
}
uint32_t maj(uint32_t a, uint32_t b, uint32_t c) {
return (a & b) ^ (a & c) ^ (b & c);
}
uint32_t rotr(uint32_t x, uint32_t n) {
return (x >> n) | (x << (32 - n));
}Bitcoin miners run SHA-256 billions of times per second, looking for a hash that starts with enough zeros. Every attempt is these three functions. Every function is AND, XOR, NOT, and shifts. Every operation is logic gates. Every gate is transistors. Every transistor is a switch.
From one switch in 1947 to a network securing hundreds of billions of dollars. One gate at a time.
SHA-256 is 64 rounds of AND, XOR, NOT and bit rotations, the exact operations on this page, hashed into the 256-bit fingerprint that secures every Bitcoin block. ← see: hashing
Where to go from here
You've now seen the entire vertical slice, from physical switching to high-level encoding. Natural next stops:
- Instruction set architectures, i.e. how bit patterns become operations (RISC-V is wonderfully clean).
- Computer organization: pipelines, caches, branch prediction, how chips get fast.
- FPGAs & HDLs, where you write hardware in code with Verilog, Chisel, or SpinalHDL.
- Build a CPU yourself: the nand2tetris course takes you from NAND gates to running a full OS.
- Build SHA-256 from scratch: implement the full algorithm using only the AND, XOR, NOT, and shift operations from this page. Every line of code maps directly to a gate on a chip.
The point isn't to know every layer in detail. The point is to know they're there, stacked on top of each other, all the way down to electrons.
Where logic gates appear in BitRoot
This is the page everything else rests on. Every later topic reaches back to a gate somewhere: