Appears in the Proceedings of the Third Symposium on Operating Systems Design and Implementation, New Orleans, USA, February 1999

Practical Byzantine Fault Tolerance
Miguel Castro and Barbara Liskov
Laboratory for Computer Science,
Massachusetts Institute of Technology,
545 Technology Square, Cambridge, MA 02139
castro,liskov @lcs.mit.edu

Abstract

and replication techniques that tolerate Byzantine faults(starting with [19]). However, most earlier work (e.g.,[3, 24, 10]) either concerns techniques designed todemonstrate theoretical feasibility that are too inefficient
to be used in practice, or assumes synchrony, i.e.,
relies on known bounds on message delays and process
speeds. The systems closest to ours, Rampart [30] andSecureRing [16], were designed to be practical, but they
rely on the synchrony assumption for correctness, whichis dangerous in the presence of malicious attacks. An
attacker may compromise the safety of a service bydelaying non-faulty nodes or the communication between
them until they are tagged as faulty and excluded from thereplica group. Such a denial-of-service attack is generally
easier than gaining control over a non-faulty node.
Our algorithm is not vulnerable to this type ofattack because it does not rely on synchrony forsafety. In addition, it improves the performance ofRampart and SecureRing by more than an order ofmagnitude as explained in Section 7. It uses only one
message round trip to execute read-only operations andtwo to execute read-write operations. Also, it uses
an efficient authentication scheme based on message
authentication codes during normal operation; public-key
cryptography, which was cited as the major latency [29]and throughput [22] bottleneck in Rampart, is used only
when there are faults.
To evaluate our approach, we implemented a replication library and used it to implement a real service: a
Byzantine-fault-tolerant distributed file system that supports the NFS protocol. We used the Andrew benchmark [15] to evaluate the performance of our system. The
results show that our system is only 3% slower than thestandard NFS daemon in the Digital Unix kernel during
normal-case operation.
Thus, the paper makes the following contributions:This paper describes a new replication algorithm that is able
to tolerate Byzantine faults. We believe that Byzantinefault-tolerant algorithms will be increasingly important in
the future because malicious attacks and software errors are
increasingly common and can cause faulty nodes to exhibit
arbitrary behavior. Whereas previous algorithms assumed asynchronous system or were too slow to be used in practice,
the algorithm described in this paper is practical: it works inasynchronous environments like the Internet and incorporates
several important optimizations that improve the response timeof previous algorithms by more than an order of magnitude. We
implemented a Byzantine-fault-tolerant NFS service using ouralgorithm and measured its performance. The results show that
our service is only 3% slower than a standard unreplicated NFS.

1 Introduction
Malicious attacks and software errors are increasingly
common. The growing reliance of industry and government on online information services makes malicious
attacks more attractive and makes the consequences ofsuccessful attacks more serious. In addition, the numberof software errors is increasing due to the growth in sizeand complexity of software. Since malicious attacks andsoftware errors can cause faulty nodes to exhibit Byzantine (i.e., arbitrary) behavior, Byzantine-fault-tolerant algorithms are increasingly important.
This paper presents a new, practical algorithm forstate machine replication [17, 34] that tolerates Byzantine
faults. The algorithm offers both liveness and safety
provided at most 3 1 out of a total of replicas are
simultaneously faulty. This means that clients eventually
receive replies to their requests and those replies arecorrect according to linearizability [14, 4]. The algorithm
works in asynchronous systems like the Internet and it
incorporates important optimizations that enable it toperform efficiently.
There is a significant body of work on agreement

It describes the first state-machine replication protocol that correctly survives Byzantine faults in asynchronous networks.
It describes a number of important optimizations thatallow the algorithm to perform well so that it can beused in real systems.

This research was supported in part by DARPA under contract DABT6395-C-005, monitored by Army Fort Huachuca, and under contract
F30602-98-1-0237, monitored by the Air Force Research Laboratory,
and in part by NEC. Miguel Castro was partially supported by a PRAXISXXI fellowship.

1

It describes the implementation of a Byzantine-faulttolerant distributed file system.
It provides experimental results that quantify the costof the replication technique.

are computationally bound so that (with very highprobability) it is unable to subvert the cryptographic
techniques mentioned above. For example, the adversary
cannot produce a valid signature of a non-faulty node,
compute the information summarized by a digest fromthe digest, or find two messages with the same digest.
The cryptographic techniques we use are thought to havethese properties [33, 36, 32].

The remainder of the paper is organized as follows.
We begin by describing our system model, including our
failure assumptions. Section 3 describes the problem
solved by the algorithm and states correctness conditions.
The algorithm is described in Section 4 and some
important optimizations are described in Section 5.
Section 6 describes our replication library and how
we used it to implement a Byzantine-fault-tolerant
NFS. Section 7 presents the results of our experiments.
Section 8 discusses related work. We conclude with asummary of what we have accomplished and a discussionof future research directions.

3 Service Properties
Our algorithm can be used to implement any deterministic
replicated service with a state and some operations. The
operations are not restricted to simple reads or writes of
portions of the service state; they can perform arbitrary
deterministic computations using the state and operationarguments. Clients issue requests to the replicated service
to invoke operations and block waiting for a reply. The
replicated service is implemented by replicas. Clientsand replicas are non-faulty if they follow the algorithm
in Section 4 and if no attacker can forge their signature.
The algorithm provides both safety and liveness assuming no more than 3 1 replicas are faulty. Safety meansthat the replicated service satisfies linearizability [14](modified to account for Byzantine-faulty clients [4]): itbehaves like a centralized implementation that executes
operations atomically one at a time. Safety requires thebound on the number of faulty replicas because a faulty
replica can behave arbitrarily, e.g., it can destroy its state.
Safety is provided regardless of how many faulty
clients are using the service (even if they collude withfaulty replicas): all operations performed by faulty clientsare observed in a consistent way by non-faulty clients.
In particular, if the service operations are designed topreserve some invariants on the service state, faulty
clients cannot break those invariants.
The safety property is insufficient to guard against
faulty clients, e.g., in a file system a faulty client canwrite garbage data to some shared file. However, welimit the amount of damage a faulty client can do byproviding access control: we authenticate clients anddeny access if the client issuing a request does not havethe right to invoke the operation. Also, services may
provide operations to change the access permissions fora client. Since the algorithm ensures that the effects ofaccess revocation operations are observed consistently by
all clients, this provides a powerful mechanism to recoverfrom attacks by faulty clients.
The algorithm does not rely on synchrony to provide
safety. Therefore, it must rely on synchrony to provide
liveness; otherwise it could be used to implement
consensus in an asynchronous system, which is notpossible [9].
We guarantee liveness, i.e., clients
eventually receive replies to their requests, provided at1
most
replicas are faulty and delay
does not3

2 System Model
We assume an asynchronous distributed system where
nodes are connected by a network. The network may
fail to deliver messages, delay them, duplicate them, ordeliver them out of order.
We use a Byzantine failure model, i.e., faulty nodes
may behave arbitrarily, subject only to the restriction
mentioned below. We assume independent node failures.
For this assumption to be true in the presence of malicious
attacks, some steps need to be taken, e.g., each node
should run different implementations of the service codeand operating system and should have a different root
password and a different administrator. It is possible
to obtain different implementations from the same codebase [28] and for low degrees of replication one can buy
operating systems from different vendors. N-version
programming, i.e., different teams of programmers
produce different implementations, is another option forsome services.
We use cryptographic techniques to prevent spoofing
and replays and to detect corrupted messages. Our
messages contain public-key signatures [33], message
authentication codes [36], and message digests producedby collision-resistant hash functions [32]. We denote a
message signed by node as
and the digest of
message by. We follow the common practiceof signing a digest of a message and appending it to
the plaintext of the message rather than signing the fullmessage (should be interpreted in this way). All
replicas know the others’ public keys to verify signatures.
We allow for a very strong adversary that cancoordinate faulty nodes, delay communication, or delay
correct nodes in order to cause the most damage to thereplicated service. We do assume that the adversary
cannot delay correct nodes indefinitely. We also assume
that the adversary (and the faulty nodes it controls)2

grow faster than indefinitely. Here, delayis thetime between the moment when a message is sent for
the first time and the moment when it is received by its
destination (assuming the sender keeps retransmitting themessage until it is received). (A more precise definition
can be found in [4].) This is a rather weak synchrony
assumption that is likely to be true in any real systemprovided network faults are eventually repaired, yet it
enables us to circumvent the impossibility result in [9].
The resiliency of our algorithm is optimal: 3
1 is theminimum number of replicas that allow an asynchronous
system to provide the safety and liveness properties when
up to replicas are faulty (see [2] for a proof). This
many replicas are needed because it must be possible toproceed after communicating withreplicas, since
replicas might be faulty and not responding. However,
it is possible that the replicas that did not respond are
not faulty and, therefore, of those that responded might
be faulty. Even so, there must still be enough responses
that those from non-faulty replicas outnumber those fromfaulty ones, i.e.,2. Therefore
3 .
The algorithm does not address the problem of faulttolerant privacy: a faulty replica may leak information to
an attacker. It is not feasible to offer fault-tolerant privacyin the general case because service operations may
perform arbitrary computations using their arguments andthe service state; replicas need this information in theclear to execute such operations efficiently. It is possible
to use secret sharing schemes [35] to obtain privacy evenin the presence of a threshold of malicious replicas [13]for the arguments and portions of the state that are opaque
to the service operations. We plan to investigate thesetechniques in the future.

used a similar approach to tolerate benign faults (as discussed in Section 8.)
The algorithm works roughly as follows:
1. A client sends a request to invoke a service operation
to the primary
2. The primary multicasts the request to the backups
3. Replicas execute the request and send a reply to theclient4. The client waits for1 replies from different
replicas with the same result; this is the result of
the operation.
Like all state machine replication techniques [34],we impose two requirements on replicas: they must
be deterministic (i.e., the execution of an operation ina given state and with a given set of arguments must
always produce the same result) and they must start in thesame state. Given these two requirements, the algorithm
ensures the safety property by guaranteeing that all nonfaulty replicas agree on a total order for the execution ofrequests despite failures.
The remainder of this section describes a simplified
version of the algorithm. We omit discussion of how
nodes recover from faults due to lack of space. We
also omit details related to message retransmissions.
Furthermore, we assume that message authentication isachieved using digital signatures rather than the more
efficient scheme based on message authentication codes;
Section 5 discusses this issue further. A detailed
formalization of the algorithm using the I/O automaton
model [21] is presented in [4].
4.1 The Client
A client
requests the execution of state machine
operation by sending a REQUEST
messageto the primary. Timestamp is used to ensure exactlyonce semantics for the execution of client requests.
Timestamps for ’s requests are totally ordered such thatlater requests have higher timestamps than earlier ones;for example, the timestamp could be the value of theclient’s local clock when the request is issued.
Each message sent by the replicas to the client includes
the current view number, allowing the client to track theview and hence the current primary. A client sends
a request to what it believes is the current primaryusing a point-to-point message. The primary atomicallymulticasts the request to all the backups using the protocol
described in the next section.
A replica sends the reply to the request directly tothe client. The reply has the form REPLY
where is the current view number, is the timestamp of
the corresponding request, is the replica number, andis the result of executing the requested operation.
The client waits for1 replies with valid signaturesfrom different replicas, and with the same and , before

4 The Algorithm
Our algorithm is a form of state machine replication [17,34]: the service is modeled as a state machine that is
replicated across different nodes in a distributed system.
Each state machine replica maintains the service stateand implements the service operations. We denote theset of replicas by
and identify each replica using an
integer in 0
1 . For simplicity, we assume
3
1 whereis the maximum number of
replicas that may be faulty; although there could be
more than 3
1 replicas, the additional replicas degrade
performance (since more and bigger messages are being
exchanged) without providing improved resiliency.
The replicas move through a succession of configurations called views. In a view one replica is the primary
and the others are backups. Views are numbered consecutively. The primary of a view is replica such thatmod
, where is the view number. View
changes are carried out when it appears that the primary
has failed. Viewstamped Replication [26] and Paxos [18]3

accepting the result . This ensures that the result is valid,
since at most replicas can be faulty.
If the client does not receive replies soon enough, it
broadcasts the request to all replicas. If the request has
already been processed, the replicas simply re-send the
reply; replicas remember the last reply message they sent
to each client. Otherwise, if the replica is not the primary,it relays the request to the primary. If the primary does
not multicast the request to the group, it will eventually
be suspected to be faulty by enough replicas to cause aview change.
In this paper we assume that the client waits for one
request to complete before sending the next one. But wecan allow a client to make asynchronous requests, yetpreserve ordering constraints on them.

A backup accepts a pre-prepare message provided:
the signatures in the request and the pre-prepare
message are correct and is the digest for ;it is in view ;it has not accepted a pre-prepare message for viewand sequence number containing a different digest;
the sequence number in the pre-prepare message is
between a low water mark, , and a high water mark,.
The last condition prevents a faulty primary fromexhausting the space of sequence numbers by selecting
a very large one. We discuss how
and advance inSection 4.3.
If backup accepts the PRE-PREPARE
message, it enters the prepare phase by multicasting a
PREPAREmessage to all other replicas andadds both messages to its log. Otherwise, it does nothing.
A replica (including the primary) accepts prepare
messages and adds them to its log provided theirsignatures are correct, their view number equals thereplica’s current view, and their sequence number isbetween and .
We define the predicate prepared
to be true
if and only if replica has inserted in its log: the request, a pre-prepare for in view with sequence number, and 2 prepares from different backups that match
the pre-prepare. The replicas verify whether the preparesmatch the pre-prepare by checking that they have thesame view, sequence number, and digest.
The pre-prepare and prepare phases of the algorithm
guarantee that non-faulty replicas agree on a total orderfor the requests within a view. More precisely, they
ensure the following invariant: if preparedistrue then preparedis false for any non-faulty
replica (including) and any such that
. This is true because preparedand3
1 imply that at least
1 non-faulty replicas
have sent a pre-prepare or prepare for in view withsequence number . Thus, for prepared
to be true at least one of these replicas needs to havesent two conflicting prepares (or pre-prepares if it is theprimary for ), i.e., two prepares with the same viewand sequence number and a different digest. But this is
not possible because the replica is not faulty. Finally, ourassumption about the strength of message digests ensuresthat the probability thatandisnegligible.
Replica multicasts a COMMIT
to theother replicas when preparedbecomes true.
This starts the commit phase. Replicas accept commit
messages and insert them in their log provided they areproperly signed, the view number in the message is equal
to the replica’s current view, and the sequence number isbetween and

4.2 Normal-Case Operation
The state of each replica includes the state of theservice, a message log containing messages the replica
has accepted, and an integer denoting the replica’s current
view. We describe how to truncate the log in Section 4.3.
When the primary, , receives a client request, ,it starts a three-phase protocol to atomically multicast
the request to the replicas. The primary starts the
protocol immediately unless the number of messages
for which the protocol is in progress exceeds a given
maximum. In this case, it buffers the request. Buffered
requests are multicast later as a group to cut down on
message traffic and CPU overheads under heavy load; thisoptimization is similar to a group commit in transactional
systems [11]. For simplicity, we ignore this optimizationin the description below.
The three phases are pre-prepare, prepare, and commit.
The pre-prepare and prepare phases are used to totallyorder requests sent in the same view even when the
primary, which proposes the ordering of requests, isfaulty. The prepare and commit phases are used to ensurethat requests that commit are totally ordered across views.
In the pre-prepare phase, the primary assigns asequence number, , to the request, multicasts a preprepare message with piggybacked to all the backups,
and appends the message to its log. The message has theform PRE-PREPARE, where indicatesthe view in which the message is being sent,
is theclient’s request message, and is ’s digest.
Requests are not included in pre-prepare messages
to keep them small. This is important because preprepare messages are used as a proof that the request was
assigned sequence number in view in view changes.
Additionally, it decouples the protocol to totally orderrequests from the protocol to transmit the request to thereplicas; allowing us to use a transport optimized forsmall messages for protocol messages and a transport
optimized for large messages for large requests.

4

We define the committed and committed-local predicates as follows: committed
is true if and only
if preparedis true for all in some set of
1 non-faulty replicas; and committed-local
is true if and only if preparedis true and has
accepted 2
1 commits (possibly including its own)
from different replicas that match the pre-prepare for ;a commit matches a pre-prepare if they have the sameview, sequence number, and digest.
The commit phase ensures the following invariant: if
committed-local
is true for some non-faulty
then committed
is true. This invariant andthe view-change protocol described in Section 4.4 ensurethat non-faulty replicas agree on the sequence numbersof requests that commit locally even if they commit indifferent views at each replica. Furthermore, it ensuresthat any request that commits locally at a non-faulty
replica will commit at
1 or more non-faulty replicas
eventually.
Each replica executes the operation requested byafter committed-local
is true and ’s state
reflects the sequential execution of all requests withlower sequence numbers. This ensures that all nonfaulty replicas execute requests in the same order as
required to provide the safety property. After executing
the requested operation, replicas send a reply to the client.
Replicas discard requests whose timestamp is lower than
the timestamp in the last reply they sent to the client toguarantee exactly-once semantics.
We do not rely on ordered message delivery, andtherefore it is possible for a replica to commit requests
out of order. This does not matter since it keeps the preprepare, prepare, and commit messages logged until thecorresponding request can be executed.
Figure 1 shows the operation of the algorithm in thenormal case of no primary faults. Replica 0 is the primary,replica 3 is faulty, and is the client.
requestpre-prepare

preparecommitthe requests they concern have been executed by at least
1 non-faulty replicas and it can prove this to othersin view changes. In addition, if some replica misses
messages that were discarded by all non-faulty replicas,
it will need to be brought up to date by transferring all
or a portion of the service state. Therefore, replicas alsoneed some proof that the state is correct.
Generating these proofs after executing every operation would be expensive. Instead, they are generated
periodically, when a request with a sequence number divisible by some constant (e.g., 100) is executed. We willrefer to the states produced by the execution of these requests as checkpoints and we will say that a checkpointwith a proof is a stable checkpoint.
A replica maintains several logical copies of the service
state: the last stable checkpoint, zero or more checkpoints
that are not stable, and a current state. Copy-on-write
techniques can be used to reduce the space overhead
to store the extra copies of the state, as discussed in
Section 6.3.
The proof of correctness for a checkpoint is generated
as follows. When a replica produces a checkpoint,
it multicasts a message CHECKPOINT
to theother replicas, where is the sequence number of thelast request whose execution is reflected in the stateand is the digest of the state. Each replica collects
checkpoint messages in its log until it has 2
1 ofthem for sequence number with the same digest
signed by different replicas (including possibly its own
such message). These 2
1 messages are the proof ofcorrectness for the checkpoint.
A checkpoint with a proof becomes stable and thereplica discards all pre-prepare, prepare, and commit
messages with sequence number less than or equal tofrom its log; it also discards all earlier checkpoints andcheckpoint messages.
Computing the proofs is efficient because the digest
can be computed using incremental cryptography [1] asdiscussed in Section 6.3, and proofs are generated rarely.
The checkpoint protocol is used to advance the low
and high water marks (which limit what messages will
be accepted). The low-water mark is equal to thesequence number of the last stable checkpoint. The highwater mark, where is big enough so that
replicas do not stall waiting for a checkpoint to become
stable. For example, if checkpoints are taken every 100
requests, might be 200.

reply

C
0
1
2
3

X

Figure 1: Normal Case Operation

4.4 View Changes
The view-change protocol provides liveness by allowing
the system to make progress when the primary fails. View
changes are triggered by timeouts that prevent backups
from waiting indefinitely for requests to execute. A
backup is waiting for a request if it received a valid request

4.3 Garbage Collection
This section discusses the mechanism used to discard
messages from the log. For the safety condition to hold,messages must be kept in a replica’s log until it knows that

5

and has not executed it. A backup starts a timer when it
receives a request and the timer is not already running.
It stops the timer when it is no longer waiting to executethe request, but restarts it if at that point it is waiting to
execute some other request.
If the timer of backup
expires in view , thebackup starts a view change to move the system toview
1. It stops accepting messages (other thancheckpoint, view-change, and new-view messages) andmulticasts a VIEW-CHANGE
1messageto all replicas. Here is the sequence number of the laststable checkpoint known to , is a set of 2
1 validcheckpoint messages proving the correctness of , andis a set containing a set
for each request
that
prepared at with a sequence number higher than . Eachsetcontains a valid pre-prepare message (without thecorresponding client message) and 2 matching, valid
prepare messages signed by different backups with thesame view, sequence number, and the digest of .
When the primary of view
1 receives 2 valid
view-change messages for view
1 from other replicas,
it multicasts a NEW-VIEW
1message to allother replicas, where is a set containing the valid viewchange messages received by the primary plus the viewchange message for
1 the primary sent (or would havesent), and is a set of pre-prepare messages (without the
piggybacked request). is computed as follows:
1. The primary determines the sequence number min-sof the latest stable checkpoint in and the highest
sequence number max-s in a prepare message in .
2. The primary creates a new pre-prepare message forview
1 for each sequence number between min-s
and max-s. There are two cases: (1) there is at least
one set in thecomponent of some view-change
message in with sequence number , or (2) there
is no such set. In the first case, the primary createsa new message PRE-PREPARE
1, whereis the request digest in the pre-prepare message forsequence number with the highest view number
in . In the second case, it creates a new preprepare message PRE-PREPARE
1
,
where
is the digest of a special null request;
a null request goes through the protocol like otherrequests, but its execution is a no-op. (Paxos [18]used a similar technique to fill in gaps.)

contains are valid for view
1, and if the set
iscorrect; it verifies the correctness of by performing acomputation similar to the one used by the primary tocreate . Then it adds the new information to its log as
described for the primary, multicasts a prepare for eachmessage in to all the other replicas, adds these prepares
to its log, and enters view
1.
Thereafter, the protocol proceeds as described in
Section 4.2. Replicas redo the protocol for messages
between min-s and max-s but they avoid re-executing
client requests (by using their stored information about
the last reply sent to each client).
A replica may be missing some request message
or a stable checkpoint (since these are not sent in newview messages.) It can obtain missing information fromanother replica. For example, replica can obtain amissing checkpoint statefrom one of the replicas
whose checkpoint messages certified its correctness in. Since
1 of those replicas are correct, replica will
always obtain or a later certified stable checkpoint. We
can avoid sending the entire checkpoint by partitioning
the state and stamping each partition with the sequencenumber of the last request that modified it. To bringa replica up to date, it is only necessary to send it thepartitions where it is out of date, rather than the wholecheckpoint.
4.5 Correctness
This section sketches the proof that the algorithm
provides safety and liveness; details can be found in [4].
4.5.1 Safety
As discussed earlier, the algorithm provides safety if all
non-faulty replicas agree on the sequence numbers ofrequests that commit locally.
In Section 4.2, we showed that if preparedis true, preparedis false for any non-faulty
replica(including) and anysuch that. This implies that two non-faulty
replicas agree on the sequence number of requests thatcommit locally in the same view at the two replicas.
The view-change protocol ensures that non-faulty
replicas also agree on the sequence number of requests
that commit locally in different views at different replicas.
A request commits locally at a non-faulty replica withsequence number in view only if committed
is true. This means that there is a set 1 containing at least
1 non-faulty replicas such that preparedis true for every replica in the set.
Non-faulty replicas will not accept a pre-prepare forview
without having received a new-view messagefor (since only at that point do they enter the view). But
any correct new-view message for viewcontains
correct view-change messages from every replica in a

Next the primary appends the messages in
to itslog. If min-s is greater than the sequence number of its
latest stable checkpoint, the primary also inserts the proofof stability for the checkpoint with sequence number
min-s in its log, and discards information from the log
as discussed in Section 4.3. Then it enters view
1: atthis point it is able to accept messages for view
1.
A backup accepts a new-view message for view1
if it is signed properly, if the view-change messages it

6

set

1 replicas. Since there are 3
1 replicas,
2 of 2
andmust
intersect
in
at
least
one
replicathat is1
2
not faulty. ’s view-change message will ensure that thefact that prepared in a previous view is propagated tosubsequent views, unless the new-view message contains
a view-change message with a stable checkpoint with asequence number higher than . In the first case, thealgorithm redoes the three phases of the atomic multicast
protocol for with the same sequence number and the
new view number. This is important because it prevents
any different request that was assigned the sequencenumber in a previous view from ever committing. In
the second case no replica in the new view will accept any
message with sequence number lower than . In either
case, the replicas will agree on the request that commits
locally with sequence number .

4.6 Non-Determinism
State machine replicas must be deterministic but many
services involve some form of non-determinism. For
example, the time-last-modified in NFS is set by reading
the server’s local clock; if this were done independently
at each replica, the states of non-faulty replicas would
diverge. Therefore, some mechanism to ensure that all
replicas select the same value is needed. In general, theclient cannot select the value because it does not haveenough information; for example, it does not know how
its request will be ordered relative to concurrent requests
by other clients. Instead, the primary needs to select thevalue either independently or based on values provided
by the backups.
If the primary selects the non-deterministic value independently, it concatenates the value with the associatedrequest and executes the three phase protocol to ensurethat non-faulty replicas agree on a sequence number forthe request and value. This prevents a faulty primary from
causing replica state to diverge by sending different values to different replicas. However, a faulty primary might
send the same, incorrect, value to all replicas. Therefore,
replicas must be able to decide deterministically whether
the value is correct (and what to do if it is not) based only
on the service state.
This protocol is adequate for most services (includingNFS) but occasionally replicas must participate inselecting the value to satisfy a service’s specification.
This can be accomplished by adding an extra phase to
the protocol: the primary obtains authenticated values
proposed by the backups, concatenates 2
1 of themwith the associated request, and starts the three phase
protocol for the concatenated message. Replicas choose
the value by a deterministic computation on the 2
1values and their state, e.g., taking the median. The extra
phase can be optimized away in the common case. For
example, if replicas need a value that is “close enough”
to that of their local clock, the extra phase can be avoided
when their clocks are synchronized within some delta.

4.5.2 LivenessTo provide liveness, replicas must move to a new view ifthey are unable to execute a request. But it is important
to maximize the period of time when at least 2
1
non-faulty replicas are in the same view, and to ensurethat this period of time increases exponentially until somerequested operation executes. We achieve these goals by
three means.
First, to avoid starting a view change too soon, a replicathat multicasts a view-change message for view1
waits for 2
1 view-change messages for view1and then starts its timer to expire after some time .
If the timer expires before it receives a valid new-view
message for
1 or before it executes a request in the
new view that it had not executed previously, it starts theview change for view
2 but this time it will wait 2
before starting a view change for view
3.
Second, if a replica receives a set of
1 valid viewchange messages from other replicas for views greaterthan its current view, it sends a view-change message
for the smallest view in the set, even if its timer has
not expired; this prevents it from starting the next view
change too late.
Third, faulty replicas are unable to impede progressby forcing frequent view changes. A faulty replica
cannot cause a view change by sending a view-change
message, because a view change will happen only if at
least
1 replicas send view-change messages, but it
can cause a view change when it is the primary (by notsending messages or sending bad messages). However,
because the primary of view is the replica such thatmod, the primary cannot be faulty for morethan consecutive views.
These three techniques guarantee liveness unlessmessage delays grow faster than the timeout period
indefinitely, which is unlikely in a real system.

5 Optimizations
This section describes some optimizations that improve
the performance of the algorithm during normal-case
operation. All the optimizations preserve the livenessand safety properties.
5.1 Reducing Communication
We use three optimizations to reduce the cost ofcommunication. The first avoids sending most large
replies. A client request designates a replica to send
the result; all other replicas send replies containing justthe digest of the result. The digests allow the client tocheck the correctness of the result while reducing network

7

bandwidth consumption and CPU overhead significantly
for large replies. If the client does not receive a correct
result from the designated replica, it retransmits therequest as usual, requesting all replicas to send full
replies.
The second optimization reduces the number ofmessage delays for an operation invocation from 5
to 4. Replicas execute a request tentatively as soon
as the prepared predicate holds for the request, theirstate reflects the execution of all requests with lower
sequence number, and these requests are all known tohave committed. After executing the request, the replicas
send tentative replies to the client. The client waits for2
1 matching tentative replies. If it receives thismany, the request is guaranteed to commit eventually.
Otherwise, the client retransmits the request and waits
for
1 non-tentative replies.
A request that has executed tentatively may abort if
there is a view change and it is replaced by a null
request. In this case the replica reverts its state to thelast stable checkpoint in the new-view message or to its
last checkpointed state (depending on which one has thehigher sequence number).
The third optimization improves the performance ofread-only operations that do not modify the service
state. A client multicasts a read-only request to all
replicas. Replicas execute the request immediately intheir tentative state after checking that the request is
properly authenticated, that the client has access, andthat the request is in fact read-only. They send the reply
only after all requests reflected in the tentative state havecommitted; this is necessary to prevent the client fromobserving uncommitted state. The client waits for 2
1
replies from different replicas with the same result. The
client may be unable to collect 2
1 such replies if there
are concurrent writes to data that affect the result; in thiscase, it retransmits the request as a regular read-write
request after its retransmission timer expires.

specific invariants, e.g, the invariant that no two different
requests prepare with the same view and sequence number at two non-faulty replicas. The modified algorithm is
described in [5]. Here we sketch the main implicationsof using MACs.
MACs can be computed three orders of magnitude
faster than digital signatures. For example, a 200MHz
Pentium Pro takes 43ms to generate a 1024-bit modulus
RSA signature of an MD5 digest and 0.6ms to verify
the signature [37], whereas it takes only 10.3 s tocompute the MAC of a 64-byte message on the same
hardware in our implementation. There are other publickey cryptosystems that generate signatures faster, e.g.,
elliptic curve public-key cryptosystems, but signature
verification is slower [37] and in our algorithm eachsignature is verified many times.
Each node (including active clients) shares a 16-byte
secret session key with each replica. We computemessage authentication codes by applying MD5 to theconcatenation of the message with the secret key. Rather
than using the 16 bytes of the final MD5 digest, we use
only the 10 least significant bytes. This truncation has
the obvious advantage of reducing the size of MACs andit also improves their resilience to certain attacks [27].
This is a variant of the secret suffix method [36], which
is secure as long as MD5 is collision resistant [27, 8].
The digital signature in a reply message is replaced by asingle MAC, which is sufficient because these messages
have a single intended recipient. The signatures in allother messages (including client requests but excluding
view changes) are replaced by vectors of MACs that wecall authenticators. An authenticator has an entry forevery replica other than the sender; each entry is the
MAC computed with the key shared by the sender andthe replica corresponding to the entry.
The time to verify an authenticator is constant but thetime to generate one grows linearly with the number of
replicas. This is not a problem because we do not expect
to have a large number of replicas and there is a huge
performance gap between MAC and digital signaturecomputation. Furthermore, we compute authenticators
efficiently; MD5 is applied to the message once and theresulting context is used to compute each vector entry
by applying MD5 to the corresponding session key. For
example, in a system with 37 replicas (i.e., a systemthat can tolerate 12 simultaneous faults) an authenticator
can still be computed much more than two orders ofmagnitude faster than a 1024-bit modulus RSA signature.
The size of authenticators grows linearly with thenumber of replicas but it grows slowly: it is equal to130
bytes. An authenticator is smaller than an
3
RSA signature with a 1024-bit modulus for
13 (i.e.,systems that can tolerate up to 4 simultaneous faults),
which we expect to be true in most configurations.

5.2 Cryptography
In Section 4, we described an algorithm that uses
digital signatures to authenticate all messages. However,we actually use digital signatures only for viewchange and new-view messages, which are sent rarely,
and authenticate all other messages using message
authentication codes (MACs). This eliminates the main
performance bottleneck in previous systems [29, 22].
However, MACs have a fundamental limitation relative to digital signatures — the inability to prove thata message is authentic to a third party. The algorithm
in Section 4 and previous Byzantine-fault-tolerant algorithms [31, 16] for state machine replication rely on theextra power of digital signatures. We modified our algorithm to circumvent the problem by taking advantage of8

6 Implementation

completely implemented (including the manipulation of
the timers that trigger view changes) and because wehave formalized the complete algorithm and proved its
correctness [4].

This section describes our implementation. First we
discuss the replication library, which can be used asa basis for any replicated service. In Section 6.2 wedescribe how we implemented a replicated NFS on topof the replication library. Then we describe how wemaintain checkpoints and compute checkpoint digests
efficiently.

6.2 BFS: A Byzantine-Fault-tolerant File System
We implemented BFS, a Byzantine-fault-tolerant NFS
service, using the replication library. Figure 2 shows thearchitecture of BFS. We opted not to modify the kernel
NFS client and server because we did not have the sources
for the Digital Unix kernel.
A file system exported by the fault-tolerant NFS service
is mounted on the client machine like any regular NFS
file system. Application processes run unmodified andinteract with the mounted file system through the NFS
client in the kernel. We rely on user level relay processes
to mediate communication between the standard NFS
client and the replicas. A relay receives NFS protocol
requests, calls the invoke procedure of our replication
library, and sends the result back to the NFS client.

6.1 The Replication Library
The client interface to the replication library consists ofa single procedure, invoke, with one argument, an input
buffer containing a request to invoke a state machine
operation. The invoke procedure uses our protocol to
execute the requested operation at the replicas and selectthe correct reply from among the replies of the individual
replicas. It returns a pointer to a buffer containing theoperation result.
On the server side, the replication code makes anumber of upcalls to procedures that the server part of
the application must implement. There are procedures
to execute requests (execute), to maintain checkpoints ofthe service state (make checkpoint, delete checkpoint), to
obtain the digest of a specified checkpoint (get digest),
and to obtain missing information (get checkpoint,
set checkpoint). The execute procedure receives as input
a buffer containing the requested operation, executes theoperation, and places the result in an output buffer. The
other procedures are discussed further in Sections 6.3
and 6.4.
Point-to-point communication between nodes is implemented using UDP, and multicast to the group of replicas
is implemented using UDP over IP multicast [7]. Thereis a single IP multicast group for each service, which contains all the replicas. These communication protocols areunreliable; they may duplicate or lose messages or deliver
them out of order.
The algorithm tolerates out-of-order delivery andrejects duplicates. View changes can be used to recoverfrom lost messages, but this is expensive and therefore it
is important to perform retransmissions. During normal
operation recovery from lost messages is driven by
the receiver: backups send negative acknowledgments
to the primary when they are out of date and theprimary retransmits pre-prepare messages after a longtimeout. A reply to a negative acknowledgment may
include both a portion of a stable checkpoint and missing
messages. During view changes, replicas retransmit
view-change messages until they receive a matching newview message or they move on to a later view.
The replication library does not implement view
changes or retransmissions at present.
This does
not compromise the accuracy of the results given
in Section 7 because the rest of the algorithm isreplica 0
snfsd

replication
library

clientrelay
Andrewbenchmarkreplication
library

kernel NFS client

kernel VM

replica n
snfsd

replication
library

kernel VM

Figure 2: Replicated File System Architecture.
Each replica runs a user-level process with thereplication library and our NFS V2 daemon, which wewill refer to as snfsd (for simple nfsd). The replication
library receives requests from the relay, interacts with
snfsd by making upcalls, and packages NFS replies into
replication protocol replies that it sends to the relay.
We implemented snfsd using a fixed-size memorymapped file. All the file system data structures, e.g.,
inodes, blocks and their free lists, are in the mapped file.
We rely on the operating system to manage the cache ofmemory-mapped file pages and to write modified pages
to disk asynchronously. The current implementation
uses 8KB blocks and inodes contain the NFS status
information plus 256 bytes of data, which is used to store
directory entries in directories, pointers to blocks in files,
and text in symbolic links. Directories and files may also
use indirect blocks in a way similar to Unix.
Our implementation ensures that all state machine9

replicas start in the same initial state and are deterministic,
which are necessary conditions for the correctness of aservice implemented using our protocol. The primary
proposes the values for time-last-modified and timelast-accessed, and replicas select the larger of the
proposed value and one greater than the maximum of allvalues selected for earlier requests. We do not require
synchronous writes to implement NFS V2 protocol
semantics because BFS achieves stability of modified
data and meta-data through replication [20].

maximum of 500.
6.4 Computing Checkpoint Digests
snfsd computes a digest of a checkpoint state as partof a make checkpoint upcall. Although checkpoints
are only taken occasionally, it is important to computethe state digest incrementally because the state may belarge. snfsd uses an incremental collision-resistant oneway hash function called AdHash [1]. This function
divides the state into fixed-size blocks and uses someother hash function (e.g., MD5) to compute the digestof the string obtained by concatenating the block index
with the block value for each block. The digest of thestate is the sum of the digests of the blocks modulo somelarge integer. In our current implementation, we use the512-byte blocks from the copy-on-write technique andcompute their digest using MD5.
To compute the digest for the state incrementally, snfsd
maintains a table with a hash value for each 512-byte
block. This hash value is obtained by applying MD5
to the block index concatenated with the block value atthe time of the last checkpoint. When make checkpointis called, snfsd obtains the digest for the previous
checkpoint state (from the associated checkpoint record).
It computes new hash values for each block whose copyon-write bit is reset by applying MD5 to the block index
concatenated with the current block value. Then, it adds
the new hash value to , subtracts the old hash value
from , and updates the table to contain the new hashvalue. This process is efficient provided the number ofmodified blocks is small; as mentioned above, on average
182 blocks are modified per checkpoint for the Andrew
benchmark.

6.3 Maintaining Checkpoints
This section describes how snfsd maintains checkpointsof the file system state. Recall that each replica maintains
several logical copies of the state: the current state, somenumber of checkpoints that are not yet stable, and the laststable checkpoint.
snfsd executes file system operations directly in thememory mapped file to preserve locality, and it uses copyon-write to reduce the space and time overhead associatedwith maintaining checkpoints. snfsd maintains a copyon-write bit for every 512-byte block in the memory
mapped file. When the replication code invokes themake checkpoint upcall, snfsd sets all the copy-on-write
bits and creates a (volatile) checkpoint record, containing
the current sequence number, which it receives as anargument to the upcall, and a list of blocks. This list
contains the copies of the blocks that were modified
since the checkpoint was taken, and therefore, it isinitially empty. The record also contains the digest of
the current state; we discuss how the digest is computedin Section 6.4.
When a block of the memory mapped file is modified
while executing a client request, snfsd checks the copyon-write bit for the block and, if it is set, stores the block’s
current contents and its identifier in the checkpoint record
for the last checkpoint. Then, it overwrites the blockwith its new value and resets its copy-on-write bit.
snfsd retains a checkpoint record until told to discard
it via a delete checkpoint upcall, which is made by the
replication code when a later checkpoint becomes stable.
If the replication code requires a checkpoint to send
to another replica, it calls the get checkpoint upcall. To
obtain the value for a block, snfsd first searches for theblock in the checkpoint record of the stable checkpoint,
and then searches the checkpoint records of any latercheckpoints. If the block is not in any checkpoint record,
it returns the value from the current state.
The use of the copy-on-write technique and the factthat we keep at most 2 checkpoints ensure that the space
and time overheads of keeping several logical copiesof the state are low. For example, in the Andrew
benchmark experiments described in Section 7, theaverage checkpoint record size is only 182 blocks with a

7 Performance Evaluation
This section evaluates the performance of our systemusing two benchmarks: a micro-benchmark and theAndrew benchmark [15]. The micro-benchmark provides
a service-independent evaluation of the performance ofthe replication library; it measures the latency to invoke
a null operation, i.e., an operation that does nothing.
The Andrew benchmark is used to compare BFS with
two other file systems: one is the NFS V2 implementationin Digital Unix, and the other is identical to BFS except
without replication. The first comparison demonstrates
that our system is practical by showing that its latency issimilar to the latency of a commercial system that is useddaily by many users. The second comparison allows us toevaluate the overhead of our algorithm accurately within
an implementation of a real service.
7.1 Experimental Setup
The experiments measure normal-case behavior (i.e.,there are no view changes), because this is the behavior

10that determines the performance of the system. All
experiments ran with one client running two relay
processes, and four replicas. Four replicas can tolerate
one Byzantine fault; we expect this reliability level tosuffice for most applications. The replicas and theclient ran on identical DEC 3000/400 Alpha workstations.
These workstations have a 133 MHz Alpha 21064
processor, 128 MB of memory, and run Digital Unix
version 4.0. The file system was stored by each replica
on a DEC RZ26 disk. All the workstations wereconnected by a 10Mbit/s switched Ethernet and had DEC
LANCE Ethernet interfaces. The switch was a DEC
EtherWORKS 8T/TX. The experiments were run on an
isolated network.
The interval between checkpoints was 128 requests,
which causes garbage collection to occur several times inany of the experiments. The maximum sequence number
accepted by replicas in pre-prepare messages was 256
plus the sequence number of the last stable checkpoint.

The overhead for read-only operations is significantly
lower because the optimization discussed in Section 5.1
reduces both computation and communication overheads.
For example, the computation overhead for the read-only
0/0 operation is approximately 0.43ms, which includes
0.23ms spent executing cryptographic operations, andthe communication overhead is only 0.37ms because theprotocol to execute read-only operations uses a single
round-trip.
Table 1 shows that the relative overhead is lower for
the 4/0 and 0/4 operations. This is because a significant
fraction of the overhead introduced by the replication
library is independent of the size of operation arguments
and results. For example, in the read-write 0/4 operation,
the large message (the reply) goes over the network
only once (as discussed in Section 5.1) and only thecryptographic overhead to process the reply message isincreased. The overhead is higher for the read-write 4/0
operation because the large message (the request) goesover the network twice and increases the cryptographic
overhead for processing both request and pre-prepare
messages.
It is important to note that this micro-benchmark
represents the worst case overhead for our algorithm
because the operations perform no work and theunreplicated server provides very weak guarantees.
Most services will require stronger guarantees, e.g.,authenticated connections, and the overhead introducedby our algorithm relative to a server that implements theseguarantees will be lower. For example, the overheadof the replication library relative to a version of theunreplicated service that uses MACs for authenticationis only 243% for the read-write 0/0 operation and 4% for
the read-only 4/0 operation.
We can estimate a rough lower bound on theperformance gain afforded by our algorithm relative to
Rampart [30]. Reiter reports that Rampart has a latencyof 45ms for a multi-RPC of a null message in a 10 Mbit/s
Ethernet network of 4 SparcStation 10s [30]. The multiRPC is sufficient for the primary to invoke a state machine
operation but for an arbitrary client to invoke an operation
it would be necessary to add an extra message delay andan extra RSA signature and verification to authenticate
the client; this would lead to a latency of at least 65ms
(using the RSA timings reported in [29].) Even if we
divide this latency by 1.7, the ratio of the SPECint92
ratings of the DEC 3000/400 and the SparcStation 10, ouralgorithm still reduces the latency to invoke the read-write
and read-only 0/0 operations by factors of more than 10
and 20, respectively. Note that this scaling is conservative
because the network accounts for a significant fractionof Rampart’s latency [29] and Rampart’s results wereobtained using 300-bit modulus RSA signatures, which
are not considered secure today unless the keys used to

7.2 Micro-Benchmark
The micro-benchmark measures the latency to invoke
a null operation. It evaluates the performance of two
implementations of a simple service with no state that
implements null operations with arguments and resultsof different sizes. The first implementation is replicatedusing our library and the second is unreplicated anduses UDP directly. Table 1 reports the response times
measured at the client for both read-only and readwrite operations. They were obtained by timing 10,000
operation invocations in three separate runs and we report
the median value of the three runs. The maximum
deviation from the median was always below 0.3% of
the reported value. We denote each operation by a/b,
where a and b are the sizes of the operation argument andresult in KBytes.
arg./res.
(KB)
0/0
4/0
0/4

replicatedread-write
read-only
3.35 (309%)
1.62 (98%)
14.19 (207%) 6.98 (51%)
8.01 (72%)
5.94 (27%)

without
replication
0.82
4.62
4.66

Table 1: Micro-benchmark results (in milliseconds); thepercentage overhead is relative to the unreplicated case.
The overhead introduced by the replication library is
due to extra computation and communication. For example, the computation overhead for the read-write 0/0 operation is approximately 1.06ms, which includes 0.55ms
spent executing cryptographic operations. The remaining 1.47ms of overhead are due to extra communication;
the replication library introduces an extra message roundtrip, it sends larger messages, and it increases the numberof messages received by each node relative to the service
without replication.

11

generate them are refreshed very frequently.
There are no published performance numbers for
SecureRing [16] but it would be slower than Rampart
because its algorithm has more message delays andsignature operations in the critical path.

phase
1
2
3
4
5
total

7.3 Andrew Benchmark
The Andrew benchmark [15] emulates a softwaredevelopment workload. It has five phases: (1) creates
subdirectories recursively; (2) copies a source tree; (3)examines the status of all the files in the tree without
examining their data; (4) examines every byte of data inall the files; and (5) compiles and links the files.
We use the Andrew benchmark to compare BFS with
two other file system configurations: NFS-std, which is
the NFS V2 implementation in Digital Unix, and BFS-nr,
which is identical to BFS but with no replication. BFS-nr
ran two simple UDP relays on the client, and on the server
it ran a thin veneer linked with a version of snfsd fromwhich all the checkpoint management code was removed.
This configuration does not write modified file system
state to disk before replying to the client. Therefore, itdoes not implement NFS V2 protocol semantics, whereas
both BFS and NFS-std do.
Out of the 18 operations in the NFS V2 protocol only
getattr is read-only because the time-last-accessed
attribute of files and directories is set by operations
that would otherwise be read-only, e.g., read andlookup. The result is that our optimization for readonly operations can rarely be used. To show the impactof this optimization, we also ran the Andrew benchmark
on a second version of BFS that modifies the lookup
operation to be read-only. This modification violates
strict Unix file system semantics but is unlikely to haveadverse effects in practice.
For all configurations, the actual benchmark code ran
at the client workstation using the standard NFS client
implementation in the Digital Unix kernel with the same
mount options. The most relevant of these options forthe benchmark are: UDP transport, 4096-byte read andwrite buffers, allowing asynchronous client writes, andallowing attribute caching.
We report the mean of 10 runs of the benchmark foreach configuration. The sample standard deviation for
the total time to run the benchmark was always below
2.6% of the reported value but it was as high as 14% for
the individual times of the first four phases. This highvariance was also present in the NFS-std configuration.
The estimated error for the reported mean was below
4.5% for the individual phases and 0.8% for the total.
Table 2 shows the results for BFS and BFS-nr. The
comparison between BFS-strict and BFS-nr shows thatthe overhead of Byzantine fault tolerance for this service
is low — BFS-strict takes only 26% more time to run

BFS
strictr/o lookup
0.55 (57%)
0.47 (34%)
9.24 (82%)
7.91 (56%)
7.24 (18%)
6.45 (6%)
8.77 (18%)
7.87 (6%)
38.68 (20%) 38.38 (19%)
64.48 (26%) 61.07 (20%)

BFS-nr
0.35
5.08
6.11
7.41
32.12
51.07

Table 2: Andrew benchmark: BFS vs BFS-nr. The times
are in seconds.
the complete benchmark. The overhead is lower thanwhat was observed for the micro-benchmarks because
the client spends a significant fraction of the elapsed timecomputing between operations, i.e., between receiving
the reply to an operation and issuing the next request,
and operations at the server perform some computation.
But the overhead is not uniform across the benchmark
phases. The main reason for this is a variation in theamount of time the client spends computing between
operations; the first two phases have a higher relative
overhead because the client spends approximately 40%of the total time computing between operations, whereas
it spends approximately 70% during the last three phases.
The table shows that applying the read-only optimization to lookup improves the performance of BFS significantly and reduces the overhead relative to BFS-nr
to 20%. This optimization has a significant impact in
the first four phases because the time spent waiting for
lookup operations to complete in BFS-strict is at least
20% of the elapsed time for these phases, whereas it isless than 5% of the elapsed time for the last phase.
phase
1
2
3
4
5
total

BFS
strictr/o lookup
0.55 (-69%) 0.47 (-73%)
9.24 (-2%)
7.91 (-16%)
7.24 (35%)
6.45 (20%)
8.77 (32%)
7.87 (19%)
38.68 (-2%) 38.38 (-2%)
64.48 (3%) 61.07 (-2%)

NFS-std
1.75
9.46
5.36
6.60
39.35
62.52

Table 3: Andrew benchmark: BFS vs NFS-std. The
times are in seconds.
Table 3 shows the results for BFS vs NFS-std. These
results show that BFS can be used in practice — BFSstrict takes only 3% more time to run the complete
benchmark. Thus, one could replace the NFS V2
implementation in Digital Unix, which is used daily
by many users, by BFS without affecting the latency
perceived by those users. Furthermore, BFS with theread-only optimization for the lookup operation is
actually 2% faster than NFS-std.
The overhead of BFS relative to NFS-std is not the12same for all phases. Both versions of BFS are fasterthan NFS-std for phases 1, 2, and 5 but slower for theother phases. This is because during phases 1, 2, and 5 alarge fraction (between 21% and 40%) of the operations
issued by the client are synchronous, i.e., operations that
require the NFS implementation to ensure stability ofmodified file system state before replying to the client.
NFS-std achieves stability by writing modified state todisk whereas BFS achieves stability with lower latency
using replication (as in Harp [20]). NFS-std is faster than
BFS (and BFS-nr) in phases 3 and 4 because the clientissues no synchronous operations during these phases.

replicas or the communication between them until enoughare excluded from the group.
To reduce the probability of misclassification, failure
detectors can be calibrated to delay classifying a replica
as faulty. However, for the probability to be negligible
the delay must be very large, which is undesirable. For
example, if the primary has actually failed, the group will
be unable to process client requests until the delay has
expired. Our algorithm is not vulnerable to this problem
because it never needs to exclude replicas from the group.
Phalanx [23, 25] applies quorum replication techniques [12] to achieve Byzantine fault-tolerance in asynchronous systems. This work does not provide genericstate machine replication; instead, it offers a data repository with operations to read and write individual variables
and to acquire locks. The semantics it provides for read
and write operations are weaker than those offered by ouralgorithm; we can implement arbitrary operations that access any number of variables, whereas in Phalanx it would
be necessary to acquire and release locks to execute suchoperations. There are no published performance numbers for Phalanx but we believe our algorithm is fasterbecause it has fewer message delays in the critical pathand because of our use of MACs rather than public key
cryptography. The approach in Phalanx offers the potential for improved scalability; each operation is processedby only a subset of replicas. But this approach to scalability is expensive: it requires
4
1 to tolerate
faults; each replica needs a copy of the state; and the loadon each replica decreases slowly with (it is O 1).

8 Related Work
Most previous work on replication techniques ignored
Byzantine faults or assumed a synchronous systemmodel (e.g., [17, 26, 18, 34, 6, 10]). Viewstamped
replication [26] and Paxos [18] use views with a primaryand backups to tolerate benign faults in an asynchronous
system. Tolerating Byzantine faults requires a much more
complex protocol with cryptographic authentication, an
extra pre-prepare phase, and a different technique totrigger view changes and select primaries. Furthermore,
our system uses view changes only to select a new primary
but never to select a different set of replicas to form the
new view as in [26, 18].
Some agreement and consensus algorithms tolerate
Byzantine faults in asynchronous systems (e.g,[2, 3, 24]).
However, they do not provide a complete solution forstate machine replication, and furthermore, most of themwere designed to demonstrate theoretical feasibility andare too slow to be used in practice. Our algorithm
during normal-case operation is similar to the Byzantine
agreement algorithm in [2] but that algorithm is unable
to survive primary failures.
The two systems that are most closely related to ourwork are Rampart [29, 30, 31, 22] and SecureRing [16].
They implement state machine replication but are morethan an order of magnitude slower than our system and,most importantly, they rely on synchrony assumptions.
Both Rampart and SecureRing must exclude faulty
replicas from the group to make progress (e.g., to remove
a faulty primary and elect a new one), and to performgarbage collection. They rely on failure detectors
to determine which replicas are faulty.
However,
failure detectors cannot be accurate in an asynchronous
system [21], i.e., they may misclassify a replica as faulty.
Since correctness requires that fewer than 1 3 of groupmembers be faulty, a misclassification can compromise
correctness by removing a non-faulty replica from thegroup. This opens an avenue of attack: an attacker
gains control over a single replica but does not change
its behavior in any detectable way; then it slows correct

9 Conclusions
This paper has described a new state-machine replication
algorithm that is able to tolerate Byzantine faults and canbe used in practice: it is the first to work correctly inan asynchronous system like the Internet and it improves
the performance of previous algorithms by more than anorder of magnitude.
The paper also described BFS, a Byzantine-faulttolerant implementation of NFS. BFS demonstrates that
it is possible to use our algorithm to implement real
services with performance close to that of an unreplicatedservice — the performance of BFS is only 3% worse thanthat of the standard NFS implementation in Digital Unix.
This good performance is due to a number of important
optimizations, including replacing public-key signaturesby vectors of message authentication codes, reducing
the size and number of messages, and the incremental
checkpoint-management techniques.
One reason why Byzantine-fault-tolerant algorithms
will be important in the future is that they can allow
systems to continue to work correctly even when there
are software errors. Not all errors are survivable;
our approach cannot mask a software error that occurs

13

at all replicas. However, it can mask errors that
occur independently at different replicas, including
nondeterministic software errors, which are the mostproblematic and persistent errors since they are thehardest to detect. In fact, we encountered such a software
bug while running our system, and our algorithm was able
to continue running correctly in spite of it.
There is still much work to do on improving our system.
One problem of special interest is reducing the amountof resources required to implement our algorithm. The
number of replicas can be reduced by using replicas
as witnesses that are involved in the protocol only whensome full replica fails. We also believe that it is possible
to reduce the number of copies of the state to
1 but
the details remain to be worked out.

[14] M. Herlihy and J. Wing. Axioms for Concurrent Objects. In ACM
Symposium on Principles of Programming Languages, 1987.
[15] J. Howard et al. Scale and performance in a distributed file system.
ACM Transactions on Computer Systems, 6(1), 1988.
[16] K. Kihlstrom, L. Moser, and P. Melliar-Smith. The SecureRing
Protocols for Securing Group Communication. In HawaiiInternational Conference on System Sciences, 1998.
[17] L. Lamport. Time, Clocks, and the Ordering of Events in aDistributed System. Commun. ACM, 21(7), 1978.
[18] L. Lamport. The Part-Time Parliament. Technical Report 49,
DEC Systems Research Center, 1989.
[19] L. Lamport, R. Shostak, and M. Pease. The Byzantine Generals
Problem. ACM Transactions on Programming Languages andSystems, 4(3), 1982.
[20] B. Liskov et al. Replication in the Harp File System. In ACM
Symposium on Operating System Principles, 1991.
[21] N. Lynch. Distributed Algorithms. Morgan Kaufmann Publishers,
1996.

Acknowledgments
We would like to thank Atul Adya, Chandrasekhar
Boyapati, Nancy Lynch, Sape Mullender, Andrew Myers,
Liuba Shrira, and the anonymous referees for their helpfulcomments on drafts of this paper.

[22] D. Malkhi and M. Reiter. A High-Throughput Secure Reliable
Multicast Protocol. In Computer Security Foundations Workshop,
1996.
[23] D. Malkhi and M. Reiter. Byzantine Quorum Systems. In ACM
Symposium on Theory of Computing, 1997.
[24] D. Malkhi and M. Reiter. Unreliable Intrusion Detection inDistributed Computations. In Computer Security Foundations
Workshop, 1997.

References[1] M. Bellare and D. Micciancio. A New Paradigm for Collisionfree Hashing: Incrementality at Reduced Cost. In Advances in
Cryptology – Eurocrypt 97, 1997.

[25] D. Malkhi and M. Reiter. Secure and Scalable Replication in
Phalanx. In IEEE Symposium on Reliable Distributed Systems,
1998.

[2] G. Bracha and S. Toueg. Asynchronous Consensus and Broadcast
Protocols. Journal of the ACM, 32(4), 1995.

[26] B. Oki and B. Liskov. Viewstamped Replication: A New Primary
Copy Method to Support Highly-Available Distributed Systems.
In ACM Symposium on Principles of Distributed Computing,
1988.

[3] R. Canneti and T. Rabin. Optimal Asynchronous Byzantine
Agreement.
Technical Report #92-15, Computer Science
Department, Hebrew University, 1992.

[27] B. Preneel and P. Oorschot. MDx-MAC and Building Fast MACs
from Hash Functions. In Crypto 95, 1995.

[4] M. Castro and B. Liskov. A Correctness Proof for a Practical Byzantine-Fault-Tolerant Replication Algorithm. Technical
Memo MIT/LCS/TM-590, MIT Laboratory for Computer Science, 1999.

[28] C. Pu, A. Black, C. Cowan, and J. Walpole. A Specialization
Toolkit to Increase the Diversity of Operating Systems. In ICMAS
Workshop on Immunity-Based Systems, 1996.

[5] M. Castro and B. Liskov. Authenticated Byzantine Fault
Tolerance Without Public-Key Cryptography. Technical Memo
MIT/LCS/TM-589, MIT Laboratory for Computer Science, 1999.

[29] M. Reiter. Secure Agreement Protocols. In ACM Conference on
Computer and Communication Security, 1994.

[6] F. Cristian, H. Aghili, H. Strong, and D. Dolev. Atomic Broadcast:
From Simple Message Diffusion to Byzantine Agreement. In
International Conference on Fault Tolerant Computing, 1985.

[30] M. Reiter. The Rampart Toolkit for Building High-Integrity
Services. Theory and Practice in Distributed Systems (LNCS
938), 1995.

[7] S. Deering and D. Cheriton. Multicast Routing in Datagram
Internetworks and Extended LANs. ACM Transactions on
Computer Systems, 8(2), 1990.

[31] M. Reiter. A Secure Group Membership Protocol.
Transactions on Software Engineering, 22(1), 1996.

IEEE[32] R. Rivest. The MD5 Message-Digest Algorithm. Internet RFC1321, 1992.

[8] H. Dobbertin. The Status of MD5 After a Recent Attack. RSA
Laboratories’ CryptoBytes, 2(2), 1996.

[33] R. Rivest, A. Shamir, and L. Adleman. A Method for
Obtaining Digital Signatures and Public-Key Cryptosystems.
Communications of the ACM, 21(2), 1978.

[9] M. Fischer, N. Lynch, and M. Paterson. Impossibility ofDistributed Consensus With One Faulty Process. Journal of theACM, 32(2), 1985.

[34] F. Schneider. Implementing Fault-Tolerant Services Using The
State Machine Approach: A Tutorial. ACM Computing Surveys,
22(4), 1990.

[10] J. Garay and Y. Moses. Fully Polynomial Byzantine Agreement
for n 3t Processors in t+1 Rounds. SIAM Journal of Computing,27(1), 1998.

[35] A. Shamir. How to share a secret. Communications of the ACM,
22(11), 1979.

[11] D. Gawlick and D. Kinkade. Varieties of Concurrency Control in
IMS/VS Fast Path. Database Engineering, 8(2), 1985.

[36] G. Tsudik. Message Authentication with One-Way Hash
Functions. ACM Computer Communications Review, 22(5), 1992.

[12] D. Gifford. Weighted Voting for Replicated Data. In Symposium
on Operating Systems Principles, 1979.

[37] M. Wiener. Performance Comparison of Public-Key Cryptosystems. RSA Laboratories’ CryptoBytes, 4(1), 1998.

[13] M. Herlihy and J. Tygar. How to make replicated data secure.
Advances in Cryptology (LNCS 293), 1988.

14