This module describes a Byzantine consensus algorithm in which messages are not encrypted. An agent x that receives a message signed by an agent y cannot tell whether y signed the message or whether some other agent forged y's signature and corrupted the message.
This module describes solutions to the Byzantine problem with oral messages whereas the previous module studied the problem with written messages. For convenience we repeat the problem specification next.
An agent is a general or a lieutenant. An agent may be loyal or disloyal. Let \(N\) be the number of agents and \(t\) the number of disloyal agents. The general sends a command to each lieutenant where the command is either attack or retreat. A loyal general sends the same command to all lieutenants whereas a disloyal general may send different commands to different lieutenants. Each lieutenant decides to attack or retreat at the end of the algorithm.
If all loyal lieutenants get the same command then each loyal lieutenant obeys the commands that it received; if the command is attack then each loyal lieutenant attacks, and if the command is retreat then each loyal lieutenant retreats.
Even if loyal lieutenants receive different commands, all loyal lieutenants make the same the decision; either all loyal lieutenants attack or all loyal lieutenants retreat.
For a nonempty list \(L\), we use the Python notation \(L_{*}\) to refer the last element of the list. For example, if \(L = [5, 6]\), then \(L_{*} = 6\).
For a list \(L\) and an element \(x\), the notation \(L , x\) represents a list consisting of \(x\) appended to the tail of \(L\). For example, if \(L\) is the list \([1, 2]\) then \(L , 3\) is the list \([1, 2, 3]\), and \(L, 3, 4\) is the list \([1, 2, 3, 4]\).
The general is the agent with index \(0\), and the lieutenants have indices \(1, \ldots, N-1\).
Let \(m[x]\) be the message that the general sends lieutenant \(x\), and let \(a[x]\) be the decision the lieutenant \(x\) makes.
If all loyal lieutenants get the same message then each loyal lieutenant obeys the message that it receives.
\( (\forall i, j: m[i] = m[j]) \quad \Rightarrow \quad (\forall i: a[i] = m[i]) \)
First we describe the flow of message in the algorithm and then describe the algorithm
The next figure illustrates a part of the messaging tree for \(N = 7, t = 2\). (There is insufficient space to show the complete tree.)
Each non-leaf node \(m[L]\) in the tree has a child \(m[L, x]\) for each lieutenant \(x\) that is not in \(L\). For example, \(m[0]\) has children \(m[0,1], m[0,2], \ldots, m[0, N-1]\).
\(m[0,x]\) is the message that lieutenant \(x\) receives from the general. \(m[0, x_{0}, \ldots, x_{k}]\) is the message that lieutenant \(x_{0}\) receives from the general and forwards to lieutenant \(x_{1}\), ... which in turn forwards the message to lieutenant \(x_{n-1}\), which in turn forwards the message to lieutenant \(x_{n}\).
If the general is loyal then it sends the same message to all lieutenants: \(m[0,x] = m[0]\) for all \(x\). Loyal lieutenants forward the messages that they receive; however, disloyal lieutenants may send arbitrary messages.
The diagram below shows a part of the aggregation tree for \(N=7, t=2\); these are the processing steps of lieutenant 1.
Each node \(a[L, i]\) of the tree has a child \(a[L, x, i]\) for each \(x\) that is not in \([L, i]\). For example, \(a[0, 1]\) has children \(a[0, 2, 1], a[0, 3, 1], \ldots a[0, 6, 1]\).
Connections from Messaging to Aggregating Nodes
There is an edge directed from each message node \(m(L)\) to the aggregation node \(a(L)\). For example, there are edges from \(m[2, 3, 1]\) to \(a[2, 3, 1]\), and from \(m[2, 1]\) to \(a[2, 1]\), and from \(m[1]\) to \(a[1]\).Output of Aggregating Nodes
The output of an aggregation node is the majority of its inputs. For example:\( a[2, 1] = \textrm{majority}(m[2, 1], a[2, 3, 1], a[2, 4, 1], \ldots, a[2, 6, 1]) \)
If there are an equal number of attack and retreat inputs, then the majority value is defined to be any default value.
The base case of the induction is a node at depth \(t\). The input for the base case is \(m[L]\) where \(L\) is a list starting with \(0\) and followed by \(t\) lieutenants. For the base case, \(a[L, x] = m[L, x]\) for all \(x\). The base case is illustrated in the lower diagram. The data flow connecting a message node \(m[L]\) at depth \(d < t\) to aggregation nodes \(a[L,x]\) is shown below. Message node \(m[L]\) feeds message nodes \(m[L,x]\). The connections between \(m[L,x]\) and aggregation nodes \(a[L,x,y]\) are specified by the data flow connecting nodes of depth \(d + 1\), shown in the diagram by blue dotted lines.
The value of an aggregation node is the majority of its inputs.
\( a[L,i] = \textrm{majority}(m[L,i], [\forall x \notin [L, i]: a[L, x, i]]) \)
For example,
\( a[0, 1, 2] = \textrm{majority}(m[0,1,2], a[0, 1, 3, 2], a[0, 1, 4, 2], a[0, 1, 5, 2], \ldots) \)
\( a[L, i] = m[L] \)
The proof is by induction. The base case is for message nodes at depth \(t\). We prove that if validity holds for message nodes at depth \(d > 0\) then it holds for message nodes at depth \(d-1\).
\( a[L, i] = m[L, i] \)
If \(L_{*}\) is loyal then \(m[L, i] = m[L]\). and the result follows.
See figure 6.
A node \(L\) at depth \(d\) consists of \(d+1\) agents. Therefore, there are at least \(3t+1 - (d+1)\) lieutenants that are not in \(L\). Because \(d \leq t\) there are at least \(2t\) not in \(L\). So, at least \(t\) lieutenants not in \(L\) are loyal and at most \(t\) of them are disloyal.
Because \(L_{*}\) is loyal, \(m[L,i] = m[L]\).
By the induction assumption, for each loyal lieutenant \(j\) not in \(L\), and for each loyal lieutenant \(i\) not in \([L, j]\): \( a[L, j, i] = m[L, i] = m[L] \)
\( a[L, i] = \textrm{majority}(m[L,i], [\forall j \notin [L, i]: a[L, j, i]]) \)
The majority is taken over at least \(t + 1\) values equal to \(m[L]\), and at most \(t\) values that are different from it. And therefore \(a[L, i] = m[L]\)
A disloyal agent is represented by the symbol \(e\). The output of a disloyal agent is unknown and is shown in black. Node \(a[l. i]\) gets more than \(2t\) red inputs and at most \(t\) black inputs, and hence the majority of its inputs is red.
\(a[L, i, j] = m[L, i]\) and \(a[L, j, i] = m[L, j]\). Therefore the inputs to \(a[L,i]\) and to \(a[L,j]\) are identical and the result follows.
There are at most \(t - d\) faulty nodes. If the general is disloyal then there at most \(t-d-1 = t -(d+1)\) disloyal lieutenants. Therefore, the induction assumption holds for \(m[L, x]\). Therefore \(a[L, i, k] = a[L, i, j]\)
K. Mani Chandy, Emeritus Simon Ramo Professor, California Institute of Technology