Skip to content

Commit 20b4100

Browse files
committed
Move sans-io code into trust-quorum-protocol crate
1 parent bbb6cca commit 20b4100

29 files changed

+308
-194
lines changed

Cargo.lock

Lines changed: 43 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,7 @@ members = [
143143
"test-utils",
144144
"trust-quorum",
145145
"trust-quorum/gfss",
146+
"trust-quorum/protocol",
146147
"trust-quorum/test-utils",
147148
"trust-quorum/tqdb",
148149
"typed-rng",
@@ -304,6 +305,7 @@ default-members = [
304305
"sp-sim",
305306
"trust-quorum",
306307
"trust-quorum/gfss",
308+
"trust-quorum/protocol",
307309
"trust-quorum/test-utils",
308310
"trust-quorum/tqdb",
309311
"test-utils",
@@ -472,6 +474,7 @@ gateway-types = { path = "gateway-types" }
472474
gethostname = "0.5.0"
473475
gfss = { path = "trust-quorum/gfss" }
474476
trust-quorum = { path = "trust-quorum" }
477+
trust-quorum-protocol = { path = "trust-quorum/protocol" }
475478
trust-quorum-test-utils = { path = "trust-quorum/test-utils" }
476479
glob = "0.3.2"
477480
guppy = "0.17.20"

trust-quorum/Cargo.toml

Lines changed: 2 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,13 @@ name = "trust-quorum"
33
version = "0.1.0"
44
edition = "2021"
55
license = "MPL-2.0"
6+
description = "trust quorum library for use by bootstrap agent"
67

78
[lints]
89
workspace = true
910

1011
[dependencies]
1112
anyhow.workspace = true
12-
bcs.workspace = true
1313
bootstore.workspace = true
1414
bytes.workspace = true
1515
camino.workspace = true
@@ -36,6 +36,7 @@ static_assertions.workspace = true
3636
subtle.workspace = true
3737
thiserror.workspace = true
3838
tokio.workspace = true
39+
trust-quorum-protocol.workspace = true
3940
uuid.workspace = true
4041
zeroize.workspace = true
4142
omicron-workspace-hack.workspace = true
@@ -50,13 +51,3 @@ serde_json.workspace = true
5051
test-strategy.workspace = true
5152
trust-quorum-test-utils.workspace = true
5253
sprockets-tls-test-utils.workspace = true
53-
54-
[features]
55-
# Impl `PartialEq` and `Eq` for types implementing `subtle::ConstantTimeEq` when
56-
# this feature is enabled.
57-
#
58-
# This is of unknown risk. The rust compiler may obviate the security of using
59-
# subtle when we do this. On the other hand its very useful for testing and
60-
# debugging outside of production.
61-
danger_partial_eq_ct_wrapper = ["gfss/danger_partial_eq_ct_wrapper"]
62-
testing = []

trust-quorum/protocol/Cargo.toml

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
[package]
2+
name = "trust-quorum-protocol"
3+
version = "0.1.0"
4+
edition = "2021"
5+
license = "MPL-2.0"
6+
description = "sans-io trust quorum protocol implementation"
7+
8+
[lints]
9+
workspace = true
10+
11+
[dependencies]
12+
bootstore.workspace = true
13+
bytes.workspace = true
14+
camino.workspace = true
15+
chacha20poly1305.workspace = true
16+
ciborium.workspace = true
17+
daft.workspace = true
18+
derive_more.workspace = true
19+
gfss.workspace = true
20+
hex.workspace = true
21+
hkdf.workspace = true
22+
iddqd.workspace = true
23+
omicron-uuid-kinds.workspace = true
24+
rand = { workspace = true, features = ["os_rng"] }
25+
secrecy.workspace = true
26+
serde.workspace = true
27+
serde_with.workspace = true
28+
sha3.workspace = true
29+
sled-agent-types.workspace = true
30+
slog.workspace = true
31+
slog-error-chain.workspace = true
32+
static_assertions.workspace = true
33+
subtle.workspace = true
34+
thiserror.workspace = true
35+
uuid.workspace = true
36+
zeroize.workspace = true
37+
omicron-workspace-hack.workspace = true
38+
39+
[dev-dependencies]
40+
assert_matches.workspace = true
41+
attest-mock.workspace = true
42+
dropshot.workspace = true
43+
omicron-test-utils.workspace = true
44+
proptest.workspace = true
45+
serde_json.workspace = true
46+
test-strategy.workspace = true
47+
trust-quorum-test-utils.workspace = true
48+
49+
[features]
50+
# Impl `PartialEq` and `Eq` for types implementing `subtle::ConstantTimeEq` when
51+
# this feature is enabled.
52+
#
53+
# This is of unknown risk. The rust compiler may obviate the security of using
54+
# subtle when we do this. On the other hand its very useful for testing and
55+
# debugging outside of production.
56+
danger_partial_eq_ct_wrapper = ["gfss/danger_partial_eq_ct_wrapper"]
57+
testing = []
File renamed without changes.
File renamed without changes.
File renamed without changes.

trust-quorum/protocol/src/lib.rs

Lines changed: 162 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,162 @@
1+
// This Source Code Form is subject to the terms of the Mozilla Public
2+
// License, v. 2.0. If a copy of the MPL was not distributed with this
3+
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
4+
5+
//! Implementation of the oxide rack trust quorum protocol
6+
//!
7+
//! This protocol is written as a
8+
//! [no-IO](https://sans-io.readthedocs.io/how-to-sans-io.html) implementation.
9+
//! All persistent state and all networking is managed outside of this
10+
//! implementation.
11+
12+
use crypto::Sha3_256Digest;
13+
use daft::Diffable;
14+
use derive_more::Display;
15+
use gfss::shamir::Share;
16+
use serde::{Deserialize, Serialize};
17+
pub use sled_agent_types::sled::BaseboardId;
18+
use slog::{Logger, error, warn};
19+
20+
mod alarm;
21+
mod compute_key_share;
22+
mod configuration;
23+
mod coordinator_state;
24+
pub(crate) mod crypto;
25+
mod messages;
26+
mod node;
27+
mod node_ctx;
28+
mod persistent_state;
29+
#[allow(unused)]
30+
mod rack_secret_loader;
31+
mod validators;
32+
33+
pub use configuration::Configuration;
34+
pub use coordinator_state::{
35+
CoordinatingMsg, CoordinatorOperation, CoordinatorState,
36+
CoordinatorStateDiff,
37+
};
38+
pub use rack_secret_loader::{LoadRackSecretError, RackSecretLoaderDiff};
39+
pub use validators::{
40+
ValidatedLrtqUpgradeMsgDiff, ValidatedReconfigureMsgDiff,
41+
};
42+
43+
pub use alarm::Alarm;
44+
pub use crypto::RackSecret;
45+
pub use messages::*;
46+
pub use node::{Node, NodeDiff};
47+
// public only for docs.
48+
pub use node_ctx::NodeHandlerCtx;
49+
pub use node_ctx::{NodeCallerCtx, NodeCommonCtx, NodeCtx, NodeCtxDiff};
50+
pub use persistent_state::{
51+
ExpungedMetadata, PersistentState, PersistentStateSummary,
52+
};
53+
54+
#[derive(
55+
Debug,
56+
Clone,
57+
Copy,
58+
PartialEq,
59+
Eq,
60+
PartialOrd,
61+
Ord,
62+
Hash,
63+
Serialize,
64+
Deserialize,
65+
Display,
66+
Diffable,
67+
)]
68+
#[daft(leaf)]
69+
pub struct Epoch(pub u64);
70+
71+
impl Epoch {
72+
pub fn next(&self) -> Epoch {
73+
Epoch(self.0.checked_add(1).expect("fewer than 2^64 epochs"))
74+
}
75+
}
76+
77+
/// The number of shares required to reconstruct the rack secret
78+
///
79+
/// Typically referred to as `k` in the docs
80+
#[derive(
81+
Debug,
82+
Clone,
83+
Copy,
84+
PartialEq,
85+
Eq,
86+
PartialOrd,
87+
Ord,
88+
Serialize,
89+
Deserialize,
90+
Display,
91+
Diffable,
92+
)]
93+
#[daft(leaf)]
94+
pub struct Threshold(pub u8);
95+
96+
/// A container to make messages between trust quorum nodes routable
97+
#[derive(Debug, Clone, Serialize, Deserialize, Diffable)]
98+
#[cfg_attr(feature = "danger_partial_eq_ct_wrapper", derive(PartialEq, Eq))]
99+
#[daft(leaf)]
100+
pub struct Envelope {
101+
pub to: BaseboardId,
102+
pub from: BaseboardId,
103+
pub msg: PeerMsg,
104+
}
105+
106+
#[cfg(feature = "testing")]
107+
impl Envelope {
108+
pub fn equal_except_for_crypto_data(&self, other: &Self) -> bool {
109+
self.to == other.to
110+
&& self.from == other.from
111+
&& self.msg.equal_except_for_crypto_data(&other.msg)
112+
}
113+
}
114+
115+
/// Check if a received share is valid for a given configuration
116+
///
117+
/// Return true if valid, false otherwise.
118+
pub fn validate_share(
119+
log: &Logger,
120+
config: &Configuration,
121+
from: &BaseboardId,
122+
epoch: Epoch,
123+
share: &Share,
124+
) -> bool {
125+
// Are we trying to retrieve shares for `epoch`?
126+
if epoch != config.epoch {
127+
warn!(
128+
log,
129+
"Received Share from node with wrong epoch";
130+
"received_epoch" => %epoch,
131+
"from" => %from
132+
);
133+
return false;
134+
}
135+
136+
// Is the sender a member of the configuration `epoch`?
137+
// Was the sender a member of the configuration at `old_epoch`?
138+
let Some(expected_digest) = config.members.get(&from) else {
139+
warn!(
140+
log,
141+
"Received Share from unexpected node";
142+
"epoch" => %epoch,
143+
"from" => %from
144+
);
145+
return false;
146+
};
147+
148+
// Does the share hash match what we expect?
149+
let mut digest = Sha3_256Digest::default();
150+
share.digest::<sha3::Sha3_256>(&mut digest.0);
151+
if digest != *expected_digest {
152+
error!(
153+
log,
154+
"Received share with invalid digest";
155+
"epoch" => %epoch,
156+
"from" => %from
157+
);
158+
return false;
159+
}
160+
161+
true
162+
}

0 commit comments

Comments
 (0)