oasis_core_runtime/consensus/keymanager/churp.rs
1//! Key manager state in the consensus layer.
2use std::collections::HashMap;
3
4use anyhow::Result;
5use thiserror::Error;
6
7use crate::{
8 common::{
9 crypto::{
10 hash::Hash,
11 signature::{PublicKey, SignatureBundle},
12 },
13 namespace::Namespace,
14 sgx::EnclaveIdentity,
15 },
16 consensus::beacon::EpochTime,
17};
18
19/// Context used to sign key manager CHURP policies.
20const POLICY_SIGNATURE_CONTEXT: &[u8] = b"oasis-core/keymanager/churp: policy";
21
22/// Errors emitted by the CHURP module.
23#[derive(Error, Debug)]
24pub enum Error {
25 #[error("invalid signature")]
26 InvalidSignature,
27}
28
29/// Cipher suite identifier.
30#[derive(Clone, Debug, Default, PartialEq, Eq, cbor::Decode, cbor::Encode)]
31#[repr(u8)]
32pub enum SuiteId {
33 /// The NIST P-384 elliptic curve group with the SHA3-384 hash function
34 /// used to encode arbitrary-length byte strings to elements of the
35 /// underlying prime field or elliptic curve points.
36 #[default]
37 NistP384Sha3_384 = 0,
38}
39
40/// Status represents the current state of a CHURP instance.
41#[derive(Clone, Debug, Default, PartialEq, Eq, cbor::Decode, cbor::Encode)]
42pub struct Status {
43 /// A unique identifier within the key manager runtime.
44 pub id: u8,
45
46 /// The identifier of the key manager runtime.
47 pub runtime_id: Namespace,
48
49 /// The identifier of a cipher suite used for verifiable secret sharing
50 /// and key derivation.
51 pub suite_id: SuiteId,
52
53 /// The degree of the secret-sharing polynomial.
54 ///
55 /// In a (t,n) secret-sharing scheme, where t represents the threshold,
56 /// any combination of t+1 or more shares can reconstruct the secret,
57 /// while losing n-t or fewer shares still allows the secret to be
58 /// recovered.
59 pub threshold: u8,
60
61 /// The minimum number of shares that can be lost to render the secret
62 /// unrecoverable.
63 ///
64 /// If t and e represent the threshold and extra shares, respectively,
65 /// then the minimum size of the committee is t+e+1.
66 pub extra_shares: u8,
67
68 /// The time interval in epochs between handoffs.
69 ///
70 /// A zero value disables handoffs.
71 pub handoff_interval: EpochTime,
72
73 /// A signed SGX access control policy.
74 pub policy: SignedPolicySGX,
75
76 /// The epoch of the last successfully completed handoff.
77 ///
78 /// The zero value indicates that no handoffs have been completed so far.
79 /// Note that the first handoff is special and is called the dealer phase,
80 /// in which nodes do not reshare or randomize shares but instead construct
81 /// the secret and shares.
82 pub handoff: EpochTime,
83
84 /// The hash of the verification matrix from the last successfully completed
85 /// handoff.
86 #[cbor(optional)]
87 pub checksum: Option<Hash>,
88
89 /// A vector of nodes holding a share of the secret in the active handoff.
90 ///
91 /// A client needs to obtain more than a threshold number of key shares
92 /// from the nodes in this vector to construct the key.
93 #[cbor(optional)]
94 pub committee: Vec<PublicKey>,
95
96 /// The epoch in which the next handoff will occur.
97 ///
98 /// If an insufficient number of applications is received, the next handoff
99 /// will be delayed by one epoch.
100 pub next_handoff: EpochTime,
101
102 /// The hash of the verification matrix from the current handoff.
103 ///
104 /// The first candidate to confirm share reconstruction is the source
105 /// of truth for the checksum. All other candidates need to confirm
106 /// with the same checksum; otherwise, the applications will be annulled,
107 /// and the nodes will need to apply for the new committee again.
108 #[cbor(optional)]
109 pub next_checksum: Option<Hash>,
110
111 /// A map of nodes that wish to form the new committee.
112 ///
113 /// Candidates are expected to generate a random bivariate polynomial,
114 /// construct a verification matrix, compute its checksum, and submit
115 /// an application one epoch in advance of the next scheduled handoff.
116 /// Subsequently, upon the arrival of the handoff epoch, nodes must execute
117 /// the handoff protocol and confirm the reconstruction of its share.
118 #[cbor(optional)]
119 pub applications: HashMap<PublicKey, Application>,
120}
121
122/// Application represents a node's application to form a new committee.
123#[derive(Clone, Debug, Default, PartialEq, Eq, cbor::Decode, cbor::Encode)]
124pub struct Application {
125 /// The hash of the random verification matrix.
126 ///
127 /// In all handoffs, except in the dealer phase, the verification matrix
128 /// needs to be zero-hole.
129 pub checksum: Hash,
130
131 /// Reconstructed is true if and only if the node verified all matrices
132 /// and successfully reconstructed its share during the handoff.
133 pub reconstructed: bool,
134}
135
136/// Key manager access control policy.
137#[derive(Clone, Debug, Default, PartialEq, Eq, cbor::Encode, cbor::Decode)]
138pub struct PolicySGX {
139 /// A unique identifier within the key manager runtime.
140 pub id: u8,
141
142 /// The identifier of the key manager runtime.
143 pub runtime_id: Namespace,
144
145 /// A monotonically increasing policy serial number.
146 pub serial: u32,
147
148 /// A vector of enclave identities from which a share can be obtained
149 /// during handoffs.
150 pub may_share: Vec<EnclaveIdentity>,
151
152 /// A vector of enclave identities that may form the new committee
153 /// in the next handoffs.
154 pub may_join: Vec<EnclaveIdentity>,
155
156 /// A map of runtime identities to the vector of enclave identities
157 /// that may query key shares.
158 pub may_query: HashMap<Namespace, Vec<EnclaveIdentity>>,
159}
160
161/// Signed key manager access control policy.
162#[derive(Clone, Debug, Default, PartialEq, Eq, cbor::Encode, cbor::Decode)]
163pub struct SignedPolicySGX {
164 /// An SGX access control policy.
165 pub policy: PolicySGX,
166
167 /// A vector of signatures.
168 #[cbor(optional)]
169 pub signatures: Vec<SignatureBundle>,
170}
171
172impl SignedPolicySGX {
173 /// Verify the signatures.
174 pub fn verify(&self) -> Result<&PolicySGX> {
175 let raw_policy = cbor::to_vec(self.policy.clone());
176 for sig in &self.signatures {
177 sig.signature
178 .verify(&sig.public_key, POLICY_SIGNATURE_CONTEXT, &raw_policy)
179 .map_err(|_| Error::InvalidSignature)?;
180 }
181
182 Ok(&self.policy)
183 }
184}