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}