Abstract
This blog explains Leslie Lamport’s solution to the Byzantine Generals’ problem that uses unsigned messages, providing a step-by-step walkthrough with visual examples.
Motivation
Distributed systems are everywhere in our modern digital infrastructure, from cloud computing to blockchain networks. However, a fundamental challenge in these systems is achieving consensus when some components might be faulty or malicious.
The Byzantine Generals’ Problem, introduced by Leslie Lamport, Robert Shostak, and Marshall Pease in 1982, elegantly captures this challenge through a military metaphor. Understanding this problem and its solution is crucial for anyone working with distributed systems, blockchain technology, or fault-tolerant computing.
This blog focuses specifically on the solution using unsigned messages, the most challenging scenario where messages carry no authentication. We’ll examine a non-trivial instance with the most adversarial case: where the commander is a traitor and strategically sends conflicting commands to create maximum confusion.
The unsigned message solution is particularly fascinating because it operates under the loosest guarantees. Unlike solutions that rely on cryptographic signatures or other forms of authentication, this approach must achieve consensus through pure logic and majority reasoning, making it both intellectually stimulating and practically relevant.
Our goal is not to reprove any of the results from the original paper, but rather to walk through detailed examples that illustrate how the protocol functions step by step. We hope this can serve as a companion for readers trying to better understand the original proofs, especially since those proofs, while rigorous, offer limited worked-out examples beyond the basic four-general case.
Introduction
Imagine a scenario where several Byzantine generals have surrounded an enemy city. They must decide collectively whether to Attack or Retreat. To succeed, all loyal generals must agree on the same plan of action: either all Attack or all Retreat. A split decision would be disastrous.
The generals can only communicate through messengers, and some generals might be traitors (potentially including the commander) who seek to prevent the loyal generals from reaching agreement. These traitors can:
- Send different messages to different generals
- Collude with other traitors
- Lie about messages they claim to have received
The challenge is to design an algorithm that ensures all loyal generals reach the same decision despite these traitors. This is the essence of the Byzantine Generals’ Problem.
The solution we explore does not rely on message signatures or authentication. Instead, it uses a recursive message-passing approach called Oral Message (OM) algorithm that can withstand up to traitors in a system with at least generals.
Terminology
Before diving into the solution, let’s establish some terminology:
- Generals: The participants in the system, denoted as where is the general’s identifier.
- Commander: The general who initiates the decision process (usually ).
- Lieutenants: All other generals who must follow the commander’s decision.
- Loyal (): Generals who follow the algorithm correctly.
- Traitors (): Generals who may behave arbitrarily and maliciously.
- Commands: The possible decisions, typically Attack or Retreat.
- OM(): The Oral Message algorithm with recursion depth .
The Byzantine Generals’ Problem has two key requirements:
- Agreement: All loyal generals must agree on the same decision. On receiving equal number of Attack and Retreat messages the loyal generals default to predetermined decision, Retreat.
- Validity: If the commander is loyal, all loyal generals must follow the commander’s order.
Lamport proved that with oral (unsigned) messages, we need at least generals to tolerate traitors, and the algorithm requires rounds of message exchanges.
The Algorithm
The Oral Message algorithm (OM) works recursively:
OM(0)
- The commander sends an order to all lieutenants
- Each lieutenant uses the message received or uses Retreat if receives no message.
OM(), for :
- The commander sends a message to each lieutenant.
- Each lieutenant acts as a commander in the OM() algorithm to share the message they received with all other lieutenants.
- Each lieutenant determines the majority value reported for each commander and uses that as their final decision.
The algorithm guarantees correct operation if where is the total number of generals and is the maximum number of traitors.
The recursive nature of this algorithm creates a tree of message exchanges that grows exponentially with . For a system with generals, the message complexity is , which makes it practical only for small values of and thus .
The Problem
Let’s examine a specific instance of the Byzantine Generals’ Problem:
- Total generals:
- Traitors:
- Loyal generals:
In our scenario:
- Commander is a traitor
- Lieutenant is also a traitor
- Lieutenants through are loyal
This is a particularly challenging case because the commander, who initiates the algorithm, is malicious. The commander’s strategy is to create maximum confusion by sending conflicting commands:
- Commander sends Attack (A) to generals , , and
- Commander sends Retreat (R) to generals , , and
Additionally, the second traitor will also attempt to confuse the loyal generals by inconsistently relaying messages during the second round.
With traitors, we need at least generals, which is exactly what we have. According to the theory, OM(2) should be sufficient to achieve consensus among loyal generals. Let’s see how this works in practice.
The Algorithm in Play
Round 0
In round 0 of the algorithm, the commander sends commands to all lieutenants. Since the commander is a traitor, it can send different commands to different lieutenants.
flowchart TB G0["G₀ Traitor Commander"] G1["G₁ Traitor"] G2["G₂ Loyal"] G3["G₃ Loyal"] G4["G₄ Loyal"] G5["G₅ Loyal"] G6["G₆ Loyal"] G0 -->|R| G1 G0 -->|A| G2 G0 -->|R| G3 G0 -->|A| G4 G0 -->|R| G5 G0 -->|A| G6 style G0 fill:#f88,stroke:#333,color:#000 style G1 fill:#f88,stroke:#333,color:#000 style G2 fill:#8f8,stroke:#333,color:#000 style G3 fill:#8f8,stroke:#333,color:#000 style G4 fill:#8f8,stroke:#333,color:#000 style G5 fill:#8f8,stroke:#333,color:#000 style G6 fill:#8f8,stroke:#333,color:#000
Figure 1: In Round 0 the traitor commander sends inconsistent messages to lieutenants. Red = Traitor, Green = Loyal. R = Retreat, A = Attack.
As shown in Figure 1, the traitor commander sends:
- Retreat (R) to generals (traitor), , and
- Attack (A) to generals , , and
At this point, each lieutenant only knows what the commander told them directly. The table below represents this initial knowledge state, with each lieutenant recording the message they received on the diagonal.
| R | |||||
| A | |||||
| R | |||||
| A | |||||
| R | |||||
| A |
Table 1: Diagonal cells show the message that each lieutenant ( - ) receives from the traitor commander (). Off-diagonal cells are empty, to be filled by messages exchanged between lieutenants in the next rounds.
Round 1
In this round each lieutenant takes turns acting as the commander for the round and tells all other lieutenants the message they received from the commander of the previous round (In this case Round 0 and the original commander ).
| Iter No | Acting Commander | Lieutenants |
|---|---|---|
| 1 | ||
| 2 | ||
| 3 | ||
| 4 | ||
| 5 | ||
| 6 |
Table 2: Displays all the scenarios for Round 1 of the example
Note that each lieutenant while acting as the commander does not send out any new commands, but instead just reports what they claim the commander of the previous round (In this case, the original commander ) sent them.
flowchart TB G0["G₀ Traitor Commander"] G1["G₁ Traitor - Acting Commander"] G2["G₂"] G3["G₃"] G4["G₄"] G5["G₅"] G6["G₆"] G0 -->|R| G1 G1 -->|R| G2 G1 -->|A| G3 G1 -->|R| G4 G1 -->|A| G5 G1 -->|R| G6 style G0 fill:#f88,stroke:#333,color:#000 style G1 fill:#f88,stroke:#333,color:#000 style G2 fill:#8f8,stroke:#333,color:#000 style G3 fill:#8f8,stroke:#333,color:#000 style G4 fill:#8f8,stroke:#333,color:#000 style G5 fill:#8f8,stroke:#333,color:#000 style G6 fill:#8f8,stroke:#333,color:#000
Figure 2: Round 1 when acts as commander. Being a traitor, it deliberately sends contradicting messages (R and A) to different lieutenants.
Round 2
Round 2 will take place for every iteration of Round 1 as the lieutenants of Round 1 take turn acting as the commander.
During the final round, Round 2, lieutenants of the round instead of acting as the commander simply gossip about what they received from the commander of the previous round ( in our example).
Continuing the example instance we considered for Round 1 where acts as the commander, we will now demonstrate what happened during the instance of Round 2 where is the commander and & are the lieutenants.
As for our example, Round 2 will act as the final round, so instead of taking turns acting as the commander in the recursive fashion like earlier rounds, lieutenants & simply relay the message that they received from the acting commander .
| — | — | — | — | — | — | |
| — | R | R | R | R | R | |
| — | A | A | A | A | A | |
| — | R | R | R | R | R | |
| — | A | A | A | A | A | |
| — | R | R | R | R | R | |
| Majority | — | R | R | R | R | R |
Table 3: Round 2 gossip where each cell shows the message the sender (row) tells the receiver (column) that it received from the acting commander . Bold diagonal: sender’s own message from . Grey cells (—): is the acting commander and does not participate in consensus.
In our table visualization, the row headers are marked as Senders and the column headers are marked as Receivers, as each lieutenant gossips by filling out the rows (telling the other lieutenant what it received from the acting commander, in this case). Thus, the diagonals will simply contain the value that the lieutenant received from the acting commander, .
Since each of the lieutenants in Round 2 is loyal, they just send out the exact same message that they received from the acting commander .
After the gossip is over each lieutenant takes the majority of all the messages that they received during the gossip and treats it as the truth. In Table 3 a column represents the messages that a lieutenant receives from other lieutenants along with the message that they received from the acting commander . The values in the last row contains the majority of the messages in that column.
Back To Round 1
The majority that was obtained from the Round 2 during the iteration of Round 1 (In our example, when was acting as the commander) is then used by the lieutenants for the same iteration of Round 1. In the example that we consider the majority that was obtained from Round 2 when the commander was is then used by the lieutenants as the truth values for Round 1 when was acting as the commander.
| R | R | R | R | R | R |
| A | |||||
| R | |||||
| A | |||||
| R | |||||
| A |
Table 4: The majority obtained from Round 2 is now used as the truth in Round 1 when completes acting as the commander.
To formalize, The majority from round is then used as the truth in .
Like mentioned earlier, each lieutenant acts as the commander in Round 1 that will result in a similar Round 2 where other lieutenants will gossip about the message that the new acting commander sends them.
Second Iteration of Round 1
For the sake of completeness of the example, we will now carry out the same process for the second iteration of Round 1 when (a Loyal lieutenant) acts as the commander.
flowchart TB G0["G₀ Traitor Commander"] G2["G₂ Loyal - Acting Commander"] G1["G₁"] G3["G₃"] G4["G₄"] G5["G₅"] G6["G₆"] G0 -->|A| G2 G2 -->|A| G1 G2 -->|A| G3 G2 -->|A| G4 G2 -->|A| G5 G2 -->|A| G6 style G0 fill:#f88,stroke:#333,color:#000 style G1 fill:#f88,stroke:#333,color:#000 style G2 fill:#8f8,stroke:#333,color:#000 style G3 fill:#8f8,stroke:#333,color:#000 style G4 fill:#8f8,stroke:#333,color:#000 style G5 fill:#8f8,stroke:#333,color:#000 style G6 fill:#8f8,stroke:#333,color:#000
Figure 3: Round 1 when acts as commander. Being loyal, it sends the same message (A) it received from to all lieutenants.
Round 2, Again
Like in the previous iteration, the rest of the lieutenants ( & ) will gossip about the message that they receive from the new acting commander . The only difference is that being a traitor, it will send contradicting messages to other lieutenants, lying about what it received from to create confusion.
| A | — | R | R | R | R | |
| — | — | — | — | — | — | |
| A | — | A | A | A | A | |
| A | — | A | A | A | A | |
| A | — | A | A | A | A | |
| A | — | A | A | A | A | |
| Majority | A | — | A | A | A | A |
Table 5: Round 2 gossip when is commander. lies but loyal lieutenants form the correct majority.
Once again exactly like before, the lieutenants use the majority of the messages that they receive (represented by column of the table) and this majority is used by the lieutenants for the iteration of Round 1 when was acting as the commander.
| R | R | R | R | R | R |
| A | A | A | A | A | A |
| R | |||||
| A | |||||
| R | |||||
| A |
Table 6: The majority obtained from Round 2 (when is acting commander) is incorporated into the knowledge table for Round 1.
Concluding the Example
After all lieutenants have completed acting as the commander in Round 1 and obtaining the majority from their respective Round 2, the final knowledge table for Round 1 is:
| R | R | R | R | R | R |
| A | A | A | A | A | A |
| R | R | R | R | R | R |
| A | A | A | A | A | A |
| R | R | R | R | R | R |
| A | A | A | A | A | A |
| R | R | R | R | R | R |
Table 7: Final Table. The last row shows the majority decision for each lieutenant.
Every loyal lieutenant will now take the majority of messages that were obtained from all the Round 2 (recorded in the respective column) and use that as the final decision. In our example, the amount of Retreat and Attack messages are the same for all loyal lieutenants hence they will all use a predetermined decision which is Retreat for the algorithm. As guaranteed all the loyal lieutenants () finally concluded to the same decision which proves the correctness of the algorithm even when the commander itself was a traitor.
To summarize, the traitor lieutenant (who received Retreat from ) continues the deception by:
- Telling some lieutenants that it received Attack from the commander
- Telling other lieutenants that it received Retreat from the commander
Meanwhile, all loyal lieutenants honestly relay the commands they received. After this round, each lieutenant has:
- Their original command from the commander, from Round 0.
- Reports from all other lieutenants about what they claim to have received
The final table shows what each lieutenant knows after all Round 2 and Round 1 messages have been exchanged.
This demonstrates the power of the OM(2) algorithm: despite having a traitor commander and a traitor lieutenant, all loyal lieutenants reach the same conclusion. The Byzantine Generals’ Problem is solved for this instance!
A Second Example: Loyal Commander with Collaborating Traitors
To completely solidify our understanding of the algorithm let’s examine a different but also crucial scenario where the commander is loyal but traitor lieutenants collaborate to disrupt consensus.
- Total generals:
- Traitors:
- Loyal generals:
In this scenario:
- Commander is loyal
- Lieutenants and are traitors
- Lieutenants , , , and are loyal
We’ll execute the OM(2) algorithm for this scenario and observe how the loyal lieutenants achieve consensus despite the traitors’ attempts to disrupt it.
Round 0
In Round 0, the loyal commander sends the same command to all lieutenants. For this example, the commander issues an Attack order.
flowchart TB G0["G₀ Loyal Commander"] G1["G₁ Traitor"] G2["G₂ Loyal"] G3["G₃ Loyal"] G4["G₄ Traitor"] G5["G₅ Loyal"] G6["G₆ Loyal"] G0 -->|A| G1 G0 -->|A| G2 G0 -->|A| G3 G0 -->|A| G4 G0 -->|A| G5 G0 -->|A| G6 style G0 fill:#8f8,stroke:#333,color:#000 style G1 fill:#f88,stroke:#333,color:#000 style G2 fill:#8f8,stroke:#333,color:#000 style G3 fill:#8f8,stroke:#333,color:#000 style G4 fill:#f88,stroke:#333,color:#000 style G5 fill:#8f8,stroke:#333,color:#000 style G6 fill:#8f8,stroke:#333,color:#000
Figure 4: Round 0 - Loyal Commander sends consistent Attack (A) to all lieutenants. Red = Traitor, Green = Loyal.
Because the commander is loyal, every lieutenant, including the traitors and , receives the same Attack command.
| A | |||||
| A | |||||
| A | |||||
| A | |||||
| A | |||||
| A |
Table 8: Initial values received by each lieutenant from the loyal commander. Off-diagonal cells are empty, to be filled by messages exchanged in the next rounds.
Round 1
In Round 1, each lieutenant acts as the commander and relays the message they received from to all other lieutenants. This is where the traitors make their move.
Let’s consider the iteration where traitor is the acting commander. Although received an Attack command, it will lie and tell every other lieutenant that it received a Retreat command.
flowchart TB G0["G₀ Loyal Commander"] G1["G₁ Traitor - Acting Commander"] G2["G₂"] G3["G₃"] G4["G₄"] G5["G₅"] G6["G₆"] G0 -->|A| G1 G1 -->|"R ✗"| G2 G1 -->|"R ✗"| G3 G1 -->|"R ✗"| G4 G1 -->|"R ✗"| G5 G1 -->|"R ✗"| G6 style G0 fill:#8f8,stroke:#333,color:#000 style G1 fill:#f88,stroke:#333,color:#000 style G2 fill:#8f8,stroke:#333,color:#000 style G3 fill:#8f8,stroke:#333,color:#000 style G4 fill:#f88,stroke:#333,color:#000 style G5 fill:#8f8,stroke:#333,color:#000 style G6 fill:#8f8,stroke:#333,color:#000
Figure 5: Traitor lies - reports R (Retreat) to everyone despite receiving A (Attack) from .
Round 2
Now, the other lieutenants (, , , , ) enter Round 2. They gossip about the command they just received from the acting commander, . Loyal lieutenants honestly relay the Retreat message they received from . The other traitor, , also relays Retreat, collaborating with . Each lieutenant then takes the majority of the messages in their column. Since sent a consistent lie, every other lieutenant’s majority decision for this iteration is Retreat.
| — | — | — | — | — | — | |
| — | R | R | R | R | R | |
| — | R | R | R | R | R | |
| — | R | R | R | R | R | |
| — | R | R | R | R | R | |
| — | R | R | R | R | R | |
| Majority | — | R | R | R | R | R |
Table 9: Round 2 gossip when is commander. All lieutenants report receiving Retreat, leading to a unanimous (but false) majority.
The majority of the messages obtained from Round 2 for the iteration is then used by the lieutenants for that iteration:
| A | R | R | R | R | R |
| A | |||||
| A | |||||
| A | |||||
| A | |||||
| A |
Table 10: Majority from Round 2 (when is acting commander) is incorporated into the knowledge table for Round 1.
Round 1, Again
Next, let’s see what happens when a loyal lieutenant, , is the acting commander. honestly reports the Attack command it received from to all other lieutenants.
flowchart TB G0["G₀ Loyal Commander"] G2["G₂ Loyal - Acting Commander"] G1["G₁"] G3["G₃"] G4["G₄"] G5["G₅"] G6["G₆"] G0 -->|A| G2 G2 -->|A| G1 G2 -->|A| G3 G2 -->|A| G4 G2 -->|A| G5 G2 -->|A| G6 style G0 fill:#8f8,stroke:#333,color:#000 style G1 fill:#f88,stroke:#333,color:#000 style G2 fill:#8f8,stroke:#333,color:#000 style G3 fill:#8f8,stroke:#333,color:#000 style G4 fill:#f88,stroke:#333,color:#000 style G5 fill:#8f8,stroke:#333,color:#000 style G6 fill:#8f8,stroke:#333,color:#000
Figure 6: Loyal honestly reports A (Attack) to all lieutenants.
Round 2, Again
In the corresponding Round 2, the lieutenants gossip about the message they received from . This time, the traitors and lie, claiming they received Retreat from , while loyal lieutenants report truthfully. Each loyal lieutenant receives two false Retreat messages (from and ) but three honest Attack messages from the loyal lieutenants. The majority for all loyal lieutenants is therefore Attack.
| A | — | R | R | R | R | |
| — | — | — | — | — | — | |
| A | — | A | A | A | A | |
| R | — | R | A | R | R | |
| A | — | A | A | A | A | |
| A | — | A | A | A | A | |
| Majority | A | — | A | A | A | A |
Table 11: Round 2 gossip when is commander. Traitors and send false reports, but loyal lieutenants form a majority for Attack.
The Round 1 knowledge table, after the completion of Round 2 where acts as the commander:
| A | R | R | R | R | R |
| A | A | A | A | A | A |
| A | |||||
| A | |||||
| A | |||||
| A |
Table 12: Majority from Round 2 (when is acting commander) is incorporated into the knowledge table for Round 1.
Concluding the Example
This process repeats for every lieutenant acting as commander in Round 1. Traitors and will always report receiving Retreat. Loyal lieutenants will always honestly report receiving Attack. After all iterations are complete, the final state of knowledge is shown below. Each row represents the majority value determined from the corresponding Round 2 iteration.
| A | R | R | R | R | R |
| A | A | A | A | A | A |
| A | A | A | A | A | A |
| R | R | R | A | R | R |
| A | A | A | A | A | A |
| A | A | A | A | A | A |
| A | A | A | A | A | A |
Table 13: Final Round 1 knowledge table for all lieutenants after OM(2) completes. Each cell shows the majority value from the corresponding Round 2, and the diagonal shows the direct message from the commander.
Finally, each loyal lieutenant (, , , and ) takes a majority vote of the values in its column from Table 13. The majority of messages for each loyal lieutenant is the same as the original command Attack that the loyal commander sent in Round 0. Although it is irrelevant what the traitor lieutenants ( & ) end up doing, the majority of the messages for them is consistent with the loyal lieutenants.
This demonstrates that when the commander is loyal, OM(2) ensures all loyal lieutenants follow the commander’s order.
Conclusion
The Byzantine Generals’ Problem represents one of the fundamental challenges in distributed computing. Through our examination of the Oral Message algorithm (OM), we’ve seen how it’s possible to achieve consensus even in the presence of malicious actors.
Key insights from our exploration:
- With generals and at most traitors, consensus requires and rounds of communication.
- The recursive nature of the algorithm allows loyal generals to filter out inconsistent information.
- Even with a traitor commander sending contradictory commands, loyal generals can still reach agreement.
- The solution works without requiring any form of message authentication or signatures.
This algorithm laid the foundation for many fault-tolerant distributed systems we rely on today, from cloud databases to blockchain networks. Modern consensus protocols like Practical Byzantine Fault Tolerance (PBFT) and those used in blockchain systems are direct descendants of Lamport’s original solution.
Understanding these principles not only helps in designing robust distributed systems but also provides insight into the fundamental limits of what’s achievable in the presence of Byzantine failures.