The Shor Code

A single stray photon or stray magnetic pulse can flip a qubit's state. It can also scramble its phase. Classical error correction handles bit flips easily. Quantum information can be corrupted in continuously many ways, not just a discrete set of flips. Peter Shor's 1995 code was the first proof that this problem is solvable at all. A quantum state can be protected against an arbitrary single-qubit error. This requires only nine physical qubits per logical qubit. This result single-handedly answered the skeptics. They argued that decoherence would make quantum computing impossible in principle, not just in practice. The deep insight behind the Shor code is compositional. The Three-Qubit Code protects against bit flips (XX errors) by encoding one qubit into three. A structurally identical code protects against phase flips (ZZ errors). It uses the Hadamard-rotated basis instead. Shor's construction nests one inside the other. It is a concatenated code where each qubit of a phase-flip code is itself encoded using a bit-flip code. Any single-qubit error can be written as a combination of bit-flip, phase-flip, and combined errors. Correcting both independently corrects everything. This matters for real systems because physical qubits are never perfectly isolated. Superconducting qubits suffer from flux noise and photon loss. Trapped ions suffer from motional heating and laser phase noise. Every platform experiences some mixture of amplitude and phase decoherence. The Shor code demonstrates the general principle used by every practical quantum error-correcting code today. This includes the Surface Code and other Stabilizer Codes. The principle is simple: encode redundantly, measure error syndromes without collapsing the encoded information, and correct. This article builds the Shor code from its two ingredient codes. It gives the full encoding circuit and syndrome-decoding pseudocode. It proves why it corrects any single-qubit error. Finally, it works a concrete numerical example of catching a YY-error on a specific physical qubit.

Key takeaways
  • The Shor code encodes 1 logical qubit into 9 physical qubits, protecting against any single-qubit error.
  • It concatenates the three-qubit bit-flip code inside the three-qubit phase-flip code.
  • Bit flips are corrected within each block of 3 qubits; phase flips are corrected across the 3 blocks.
  • Since any single-qubit error decomposes into I,X,Y,ZI, X, Y, Z components, correcting XX and ZZ corrects everything, including YY.
  • Syndrome extraction uses ancilla-assisted parity measurements that never reveal the encoded quantum state.
  • It is not efficient for real hardware — its historical role is proving that quantum error correction is possible at all.
The core insight

Nesting a bit-flip code inside a phase-flip code lets nine qubits correct an arbitrary single-qubit error, because every such error is a combination of just bit-flip and phase-flip parts.

The idea

An arbitrary error on one qubit is a linear operator on a two-dimensional Hilbert space, so it can always be written in the Pauli basis as

E=a I+b X+c Y+d ZE = a\,I + b\,X + c\,Y + d\,Z

for complex coefficients a,b,c,da,b,c,d. Here XX is a bit flip, ZZ is a phase flip, and Y=iXZY = iXZ is both at once. This is the crucial fact that makes discrete error correction possible for a continuous space of errors: if a code can correct arbitrary XX and ZZ errors on each qubit, it can correct any error at all, because correction is linear and the measurement of the syndrome forces the error into one definite Pauli component even if the physical noise was a continuous rotation. The Three-Qubit Code corrects a single bit flip by encoding ∣0⟩↦∣000⟩|0\rangle \mapsto |000\rangle, ∣1⟩↦∣111⟩|1\rangle \mapsto |111\rangle, and detecting disagreement among the three qubits via parity checks Z1Z2Z_1Z_2 and Z2Z3Z_2Z_3. Applying a Hadamard transform to every qubit converts this into a code that corrects a single phase flip instead, since HXH=ZH X H = Z: it encodes ∣0⟩↦∣+++⟩|0\rangle \mapsto |{+}{+}{+}\rangle, ∣1⟩↦∣−−−⟩|1\rangle \mapsto |{-}{-}{-}\rangle, with ∣±⟩=(∣0⟩±∣1⟩)/2|\pm\rangle = (|0\rangle \pm |1\rangle)/\sqrt2. The Shor code concatenates these two ideas. First, encode the logical qubit against phase flips using the three-block structure

∣0⟩L↦∣+++⟩,∣1⟩L↦∣−−−⟩,|0\rangle_L \mapsto |{+}{+}{+}\rangle, \qquad |1\rangle_L \mapsto |{-}{-}{-}\rangle,

written more explicitly as sums of ∣000⟩|000\rangle and ∣111⟩|111\rangle states. Then encode each of the three qubits in that expression using the bit-flip code, replacing every ∣0⟩|0\rangle by ∣000⟩|000\rangle and every ∣1⟩|1\rangle by ∣111⟩|111\rangle. This gives the full nine-qubit codewords:

∣0⟩L  ⟼  122(∣000⟩+∣111⟩)(∣000⟩+∣111⟩)(∣000⟩+∣111⟩)|0\rangle_L \;\longmapsto\; \frac{1}{2\sqrt2}\big(|000\rangle+|111\rangle\big)\big(|000\rangle+|111\rangle\big)\big(|000\rangle+|111\rangle\big)
∣1⟩L  ⟼  122(∣000⟩−∣111⟩)(∣000⟩−∣111⟩)(∣000⟩−∣111⟩)|1\rangle_L \;\longmapsto\; \frac{1}{2\sqrt2}\big(|000\rangle-|111\rangle\big)\big(|000\rangle-|111\rangle\big)\big(|000\rangle-|111\rangle\big)

Each of the three parenthesized triples is a block. Bit flips are detected and corrected within a block by comparing the three qubits of that block. Phase flips are detected by comparing the overall sign (relative phase) between blocks, which is a property of triples of qubits, not individual ones — this is why phase-flip protection needs three blocks, giving 3×3=93 \times 3 = 9 qubits in total.

How it works

Step 1 — Outer (phase) encoding. Take the input qubit α∣0⟩+β∣1⟩\alpha|0\rangle + \beta|1\rangle and apply the phase-flip code: CNOTCNOT into two ancillas, then Hadamard all three, producing

α ∣+++⟩+β ∣−−−⟩.\alpha \,|{+}{+}{+}\rangle + \beta \,|{-}{-}{-}\rangle.

Step 2 — Inner (bit-flip) encoding. Encode each of the three qubits above using the bit-flip code: for each qubit, introduce two fresh ancillas in ∣0⟩|0\rangle and apply two CNOTCNOTs so that ∣0⟩→∣000⟩|0\rangle \to |000\rangle and ∣1⟩→∣111⟩|1\rangle \to |111\rangle. Since ∣±⟩=(∣0⟩±∣1⟩)/2|\pm\rangle = (|0\rangle \pm |1\rangle)/\sqrt2, this turns each ∣±⟩|\pm\rangle into (∣000⟩±∣111⟩)/2(|000\rangle \pm |111\rangle)/\sqrt2.

Step 3 — Noise. The channel acts on one (or more, for intuition) of the nine physical qubits with some Pauli error (or an arbitrary unitary/decoherence, by linearity).

Step 4 — Bit-flip syndrome extraction, within each block. For each of the three blocks independently, measure the two stabilizer generators Z1Z2Z_1Z_2 and Z2Z3Z_2Z_3 (of that block) using ancilla qubits, exactly as in the three-qubit code. This identifies which qubit (if any) inside the block suffered a bit flip, without measuring the encoded data.

Step 5 — Bit-flip correction. Apply XX to the identified qubit in each block, restoring each block to a consistent superposition of ∣000⟩|000\rangle and ∣111⟩|111\rangle.

Step 6 — Phase-flip syndrome extraction, across blocks. Decode each block back to a single qubit conceptually (or work with the collective parity operators X1X2⋯X6X_1X_2\cdots X_6 and X4X5⋯X9X_4X_5\cdots X_9, the two stabilizers comparing block signs). This determines whether a relative phase flip occurred between block 1 and block 2, or between block 2 and block 3.

Step 7 — Phase-flip correction. Apply ZZ to any one qubit in the identified block, which flips the relative sign of that whole block and restores the correct global phase pattern. ``` // SHOR-9 ENCODE function ENCODE(alpha, beta): // qubit 0 holds alpha|0> + beta|1> // outer phase-flip encoding using 2 ancillas (qubits 3, 6) CNOT(0, 3) CNOT(0, 6) H(0); H(3); H(6) // inner bit-flip encoding: each of the 3 "block leaders" gets 2 more ancillas for leader in [0, 3, 6]: a, b = leader + 1, leader + 2 // fresh ancillas, initially |0> CNOT(leader, a) CNOT(leader, b) return qubits[0..8] // the 9-qubit codeword // SHOR-9 SYNDROME DECODE + CORRECT function DECODE_AND_CORRECT(qubits[0..8]): // --- Step A: bit-flip correction inside each block of 3 --- for block_start in [0, 3, 6]: q0, q1, q2 = qubits[block_start], qubits[block_start+1], qubits[block_start+2] s1 = MEASURE_STABILIZER(Z(q0) Z(q1)) // ancilla-assisted parity check s2 = MEASURE_STABILIZER(Z(q1) Z(q2)) flip_target = BIT_FLIP_TABLE[(s1, s2)] // -1 = none, else 0/1/2 (local index) if flip_target != -1: APPLY_X(qubits[block_start + flip_target]) // --- Step B: phase-flip correction across the 3 blocks --- p1 = MEASURE_STABILIZER( PRODUCT_X(qubits[0..5]) ) // X1..X6 compares block 1 vs 2 p2 = MEASURE_STABILIZER( PRODUCT_X(qubits[3..8]) ) // X4..X9 compares block 2 vs 3 phase_block = PHASE_FLIP_TABLE[(p1, p2)] // -1 = none, else 0/1/2 (block index) if phase_block != -1: APPLY_Z(qubits[phase_block * 3]) // Z on any one qubit in that block return qubits[0..8] // corrected codeword, logical state untouched ``` The two lookup tables are identical in structure to the three-qubit repetition-code decoder: syndrome (0,0)(0,0) means no error, (1,0)(1,0) localizes qubit/block 1, (1,1)(1,1) localizes the middle one, (0,1)(0,1) localizes the last one.

Figure
The Shor nine-qubit code: outer phase-flip code concatenated with inner bit-flip codes
Logical qubit |ψ⟩ = α|0⟩ + β|1⟩ q outer phase-flip encode (CNOT×2, then H×3) |±⟩ |±⟩ |±⟩ inner bit-flip encode (CNOT×2 per block) Block 1 q1 q2 q3 Z1Z2, Z2Z3 → bit-flip syndrome detects local X error Block 2 q4 q5 q6 Z4Z5, Z5Z6 → bit-flip syndrome detects local X error Block 3 q7 q8 q9 Z7Z8, Z8Z9 → bit-flip syndrome detects local X error X1..X6 and X4..X9 → phase-flip syndrome (compares sign between blocks, detects Z error) Total: 9 physical qubits protect 1 logical qubit against any single-qubit error

Complexity & correctness

Resource counts. Encoding uses 9 physical qubits and 8 CNOTCNOTs plus 3 Hadamards (O(1)O(1) gates, independent of any problem size, since this protects one logical qubit). Syndrome extraction requires 6 ancilla qubits for the six bit-flip stabilizer measurements (or these ancillas can be reused sequentially) plus 2 more for the two phase-flip stabilizer measurements, each requiring a constant number of CNOTCNOT/Hadamard gates. All operations are O(1)O(1) in circuit depth and gate count — the Shor code is a fixed, constant-overhead code, not an asymptotic family. This is a strength for teaching, but a weakness for scaling: unlike the Surface Code, its overhead per logical qubit does not shrink relative to the target error rate.

Correctness argument. The proof rests on three facts: 1. Pauli decomposition. Any single-qubit error operator EE can be written as E=aI+bX+cY+dZE = aI + bX + cY + dZ. If the code's correction procedure returns the state to the correct codeword whenever the actual error was II, XX, YY, or ZZ on any one physical qubit, then by linearity of quantum mechanics it corrects any superposition/mixture of such errors — the syndrome measurement projects the noisy state onto the subspace corresponding to one specific Pauli error, collapsing the continuous uncertainty into a discrete, correctable case. This is the reason a code built to handle just {I,X,Y,Z}\{I, X, Y, Z\} per qubit handles literally every possible single-qubit error, including small-angle rotations and amplitude damping. 2. Bit-flip correction within a block. Inside a block, XiX_i on qubit ii anticommutes with exactly the stabilizer generators Z1Z2Z_1Z_2 or Z2Z3Z_2Z_3 that include qubit ii, giving each of the three possible single-XX errors a distinct nontrivial syndrome — while II gives the trivial syndrome. Since the block only ever holds a state in the 2-dimensional code space spanned by ∣000⟩,∣111⟩|000\rangle,|111\rangle, this syndrome uniquely diagnoses the error and correction is guaranteed by the same argument used for the Three-Qubit Code. Two simultaneous XX errors in the same block are misdiagnosed as a single flip on the third qubit — this is the code's actual failure mode, discussed below. 3. Phase-flip correction across blocks. A ZZ error on any one qubit within a block flips the relative sign of that block's ∣000⟩/∣111⟩|000\rangle/|111\rangle superposition — i.e., a ZZ anywhere in block kk acts identically, up to the bit-flip code's own error correction, to a single logical ZZ on that block considered as one unit. Comparing block signs via X1⋯X6X_1\cdots X_6 and X4⋯X9X_4 \cdots X_9 (the analogue of Z1Z2,Z2Z3Z_1Z_2, Z_2Z_3 but in the Hadamard-conjugated frame) localizes which block suffered the sign flip, and applying ZZ to any one qubit in that block restores it. Crucially, a YY error on one qubit is Y=iXZY = iXZ: the XX part is caught and fixed by step 4/5, and the same physical event's ZZ part is caught and fixed by step 6/7 — the two correction stages act on the same photon-scale event but different aspects of it, and their order does not matter because bit-flip correction operates entirely within blocks while phase-flip correction operates entirely across blocks, so the two procedures commute.

Degeneracy. The Shor code is a degenerate code: several distinct physical errors (e.g. ZZ on any of the three qubits in a block) produce the same syndrome and are corrected by the same recovery operation, because they act identically on the codespace. Degenerate codes can, in principle, correct more errors than a naive counting bound would suggest, and this is a preview of the richer structure exploited by general Stabilizer Codes.

Honest tradeoff. The Shor code corrects any single-qubit error but is not distance-optimal: it uses 9 qubits where later constructions (e.g. the 5-qubit code) achieve the same single-error-correcting guarantee with fewer physical qubits, at the cost of a less intuitive derivation. The Shor code's virtue is conceptual clarity and historical priority, not efficiency.

Worked example

Take the logical state ∣ψ⟩L|\psi\rangle_L encoding α∣0⟩+β∣1⟩\alpha|0\rangle + \beta|1\rangle, and suppose physical qubit q5 (the middle qubit of Block 2) suffers a YY error, i.e. the channel applies Y5=iX5Z5Y_5 = iX_5Z_5.

StepActionEffect
Before noiseCodeword is the ideal 9-qubit stateBlock 2 is (∣000⟩±∣111⟩)/2(|000\rangle \pm |111\rangle)/\sqrt2 (sign per logical bit)
NoiseApply Y5Y_5Equivalent to applying X5X_5 then Z5Z_5 (up to global phase ii)
Bit-flip syndrome, Block 1Measure Z1Z2Z_1Z_2, Z2Z3Z_2Z_3Result (0,0)(0,0) — no error in Block 1
Bit-flip syndrome, Block 2Measure Z4Z5Z_4Z_5, Z5Z6Z_5Z_6Result (1,1)(1,1) — both parities violated, indicating the middle qubit (q5) flipped
Bit-flip syndrome, Block 3Measure Z7Z8Z_7Z_8, Z8Z9Z_8Z_9Result (0,0)(0,0) — no error in Block 3
Bit-flip correctionApply X5X_5Removes the X5X_5 component; Block 2 is now back to (∣000⟩±∣111⟩)/2(|000\rangle \pm |111\rangle)/\sqrt2 but with the sign flipped, since the leftover was Z5Z_5 acting on that corrected block
Phase-flip syndromeMeasure X1X2X3X4X5X6X_1X_2X_3X_4X_5X_6 and X4X5X6X7X8X9X_4X_5X_6X_7X_8X_9First gives −1-1 (blocks 1,2 disagree in sign), second gives +1+1 (blocks 2,3 agree) → localizes the sign flip to Block 2
Phase-flip correctionApply ZZ to any one qubit in Block 2, e.g. Z4Z_4Restores the correct relative sign between all three blocks
After correctionCodeword matches ideal ∣ψ⟩L|\psi\rangle_L exactlyLogical information α,β\alpha, \beta recovered with no information ever measured about α,β\alpha,\beta themselves

Notice the key point that makes this a genuine correctness demonstration rather than a toy case: the single physical event Y5Y_5 triggered two separate, independently diagnosed syndromes (a bit-flip syndrome localized to a specific qubit within a block, and a phase-flip syndrome localized to a specific block), and fixing each independently fixed the whole error — exactly the linear-decomposition argument from the correctness section, now traced through concrete syndrome bits rather than asserted abstractly.

Common pitfalls & traps

PitfallWhy it happensFix
Measuring qubits directly to "check for errors"Directly measuring ZZ or XX on a data qubit collapses α,β\alpha,\beta and destroys the logical stateAlways use ancilla-assisted stabilizer measurement, never measure data qubits directly
Assuming the code corrects two errorsTwo XX errors in the same block are indistinguishable from one XX error on the third qubit, and are corrected wronglyRecognize the code's guarantee is "any single-qubit error," not "any two-qubit error"; distance is 3
Forgetting to correct across-block phase after within-block bit correctionTreating the two corrections as independent without noting the bit-flip fix can leave a residual signPerform bit-flip correction first per block, then re-derive the block-level state before phase correction (order used above is safe)
Confusing ∣±⟩|\pm\rangle triple structure with ∣0⟩/∣1⟩|0\rangle/|1\rangle triple structureThe outer code lives in the Hadamard basis; naive parity checks on raw qubit values miss the outer-layer sign errorsUse XX-type stabilizers (X1⋯X6X_1\cdots X_6, X4⋯X9X_4 \cdots X_9) for the phase-flip layer, not ZZ-type
Treating 9 qubits as "3 independent copies" of the 3-qubit codeThe 9 qubits are not three separate encodings of the same logical bit; they are a nested/concatenated structureEncode outer-then-inner exactly per the circuit; decode inner-then-outer (bit-flip first, then phase-flip)

Pioneers & history

Origins · 1 minPeter W. Shor and how this was discovered
PW
Peter W. Shor
born 1959 · Bell Labs, 1994–1995

Peter Shor is best known for Shor's Algorithm for integer factorization, but his 1995 quantum error-correcting code was arguably just as consequential: it was the first proof that quantum information could survive noise at all, silencing early claims that decoherence made scalable quantum computing physically impossible.

History
1995
— Peter Shor publishes the nine-qubit code, the first quantum error-correcting code.
1996
— Andrew Steane and, independently, Robert Calderbank and Peter Shor generalize the idea into CSS codes.
1996
— Daniel Gottesman formalizes the stabilizer formalism, unifying Shor's code and its successors.
1997
— Alexei Kitaev introduces topological error correction, leading toward the surface code.
1998–2000
s — Fault-tolerant threshold theorems establish that arbitrarily long quantum computation is possible below a noise threshold.

Where this matters

The Shor code itself is rarely used in production hardware today because its 9-qubit overhead is inefficient compared to more modern codes, but its conceptual DNA is everywhere. Every leading quantum computing effort — Google's and IBM's superconducting processors, IonQ's and Quantinuum's trapped-ion systems, and photonic approaches — relies on the same core idea: encode a logical qubit redundantly, measure stabilizers via ancillas without touching the encoded data, and correct. The Surface Code, the workhorse of most current large-scale hardware roadmaps, is a two-dimensional descendant of exactly this bit-flip/phase-flip separation, using local stabilizer checks arranged on a lattice instead of Shor's flat concatenation. The broader framework of Stabilizer Codes that Daniel Gottesman built to describe Shor's code and its relatives underlies essentially all of modern Fault-Tolerant Quantum Computing theory, including magic-state distillation and logical gate synthesis. Understanding the Shor code is the cleanest way to internalize why discretizing continuous quantum errors into Pauli components is always possible — a fact quietly assumed in every subsequent, more sophisticated code.

Ask the tutor: How would you adapt the Shor code's decoding circuit if you only had ancilla qubits available for two stabilizer measurements at a time, instead of all eight at once?

Why does the Shor code need exactly 9 qubits, no fewer?

The construction is a concatenation: an outer 3-qubit phase-flip code applied to a logical qubit, with each of those 3 qubits then re-encoded using an inner 3-qubit bit-flip code. That nesting multiplies 3×3=93 \times 3 = 9. The 9 is not fundamental to quantum error correction in general — later codes like the 5-qubit code achieve single-error correction with fewer qubits — but it is fundamental to this particular construction, since it results directly from stacking two independent 3-qubit codes. The Shor code trades qubit efficiency for conceptual transparency: each layer's job (bit-flip or phase-flip protection) is easy to isolate and verify separately.

Does the Shor code protect against errors on more than one qubit?

Only in limited cases. Its code distance is 3, meaning it guarantees correction of any error affecting a single physical qubit, but two simultaneous errors can defeat it — for example, two bit flips in the same 3-qubit block are misread as a single flip on the third qubit and "corrected" incorrectly. Errors on two qubits in different blocks, of the right type, can sometimes still be handled correctly due to the code's degeneracy, but this is not a general guarantee. Real fault-tolerant systems stack multiple rounds of such single-error-correcting codes, or use codes with larger distance, to handle the low but nonzero probability of multiple simultaneous errors.

How is the phase-flip syndrome actually measured without collapsing the logical qubit?

By measuring products of Pauli-XX operators across two adjacent blocks, such as X1X2X3X4X5X6X_1X_2X_3X_4X_5X_6, using an ancilla qubit prepared in ∣+⟩|+\rangle, entangled via controlled-XX (technically controlled-ZZ conjugated appropriately, or via directly implementable XXXX-type parity gates) with all six data qubits, then measured in the XX basis. This measures the joint parity — whether the two blocks have matching or opposite relative signs — without revealing anything about the coefficients α,β\alpha, \beta of the encoded logical state, because the stabilizer commutes with the logical operators, a defining property that will be generalized when studying Stabilizer Codes.

Is the Shor code used in any real quantum computer today?

Not directly in large-scale hardware roadmaps, mainly because its resource overhead is worse than alternatives with the same error-correcting power, such as the 5-qubit code or the 2D surface code, which also offers better scalability and more local (nearest-neighbor) stabilizer measurements suited to physical chip layouts. However, small demonstrations of the Shor code have been implemented experimentally (in trapped ions and superconducting qubits) as proof-of-principle tests of quantum error correction. Its lasting importance is pedagogical and historical: it is the cleanest illustration of the bit-flip/phase-flip decomposition that underlies essentially every practical code used today.

What is the relationship between the Shor code and the concept of code "distance"?

Code distance measures the minimum number of physical qubit errors needed to move from one valid codeword to another (or, equivalently, to cause an undetectable logical error). The Shor code has distance 3: any single-qubit error is correctable, but certain carefully chosen two-qubit errors can cause a logical failure. This distance-3 property is exactly analogous to a classical repetition code with 3 copies, which is precisely the pattern reused twice (once for bit flips, once for phase flips) in Shor's construction. Distance is the same invariant used to compare all later stabilizer codes, including the surface code, whose distance can be scaled up by simply enlarging the code's underlying lattice.

Why is degeneracy in the Shor code considered a feature rather than a bug?

A non-degenerate code needs a distinct syndrome for every distinct correctable error, which can require many stabilizer measurement outcomes. The Shor code is degenerate: several different physical errors, such as a ZZ error on any of the three qubits in one block, produce the identical syndrome and are fixed by the identical recovery step, since they have the exact same effect on the logical codespace. This means the code can tolerate more physical error events than a naive non-degenerate counting bound would suggest, using fewer distinct syndrome outcomes than one might expect. Degeneracy becomes a central design tool in more advanced stabilizer and topological codes.

How does the Shor code foreshadow the stabilizer formalism?

Every check the Shor code uses — Z1Z2Z_1Z_2, Z2Z3Z_2Z_3 within blocks and X1⋯X6X_1{\cdots}X_6, X4⋯X9X_4{\cdots}X_9 across blocks — is an operator that has the encoded logical states as +1+1 eigenstates, commutes with all the other checks, and commutes with the logical XL,ZLX_L, Z_L operators. This is precisely the definition of a stabilizer group, formalized shortly after by Daniel Gottesman to unify Shor's code, Steane's code, and every subsequent quantum code into a single algebraic framework. Learning the Shor code by hand, checking each commutation explicitly, is the standard on-ramp before studying the general theory of Stabilizer Codes and, eventually, Fault-Tolerant Quantum Computing.

Before this

Where this leads