mithril_stm/key_reg.rs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151
//! Key registration functionality.
use super::stm::Stake;
use crate::error::RegisterError;
use crate::merkle_tree::{MTLeaf, MerkleTree};
use crate::multi_sig::{VerificationKey, VerificationKeyPoP};
use blake2::digest::{Digest, FixedOutput};
use std::collections::hash_map::Entry;
use std::collections::HashMap;
use std::sync::Arc;
/// Stores a registered party with its public key and the associated stake.
pub type RegParty = MTLeaf;
/// Struct that collects public keys and stakes of parties.
/// Each participant (both the signers and the clerks) need to run their own instance of the key registration.
// todo: replace with KeyReg
#[derive(Clone, Debug, Default, PartialEq, Eq)]
pub struct KeyReg {
keys: HashMap<VerificationKey, Stake>,
}
/// Structure generated out of a closed registration containing the registered parties, total stake, and the merkle tree.
/// One can only get a global `avk` out of a closed key registration.
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct ClosedKeyReg<D: Digest> {
/// Ordered list of registered parties.
pub reg_parties: Vec<RegParty>,
/// Total stake of the registered parties.
pub total_stake: Stake,
/// Unique public key out of the key registration instance.
pub merkle_tree: Arc<MerkleTree<D>>,
}
impl KeyReg {
/// Initialise an empty `KeyReg`.
/// todo: remove this init function
pub fn init() -> Self {
Self {
keys: HashMap::new(),
}
}
/// Verify and register a public key and stake for a particular party.
/// # Error
/// The function fails when the proof of possession is invalid or when the key is already registered.
pub fn register(&mut self, stake: Stake, pk: VerificationKeyPoP) -> Result<(), RegisterError> {
if let Entry::Vacant(e) = self.keys.entry(pk.vk) {
if pk.check().is_ok() {
e.insert(stake);
return Ok(());
} else {
return Err(RegisterError::KeyInvalid(Box::new(pk)));
}
}
Err(RegisterError::KeyRegistered(Box::new(pk.vk)))
}
/// Finalize the key registration.
/// This function disables `KeyReg::register`, consumes the instance of `self`, and returns a `ClosedKeyReg`.
pub fn close<D>(self) -> ClosedKeyReg<D>
where
D: Digest + FixedOutput,
{
let mut total_stake: Stake = 0;
let mut reg_parties = self
.keys
.iter()
.map(|(&vk, &stake)| {
let (res, overflow) = total_stake.overflowing_add(stake);
if overflow {
panic!("Total stake overflow");
}
total_stake = res;
MTLeaf(vk, stake)
})
.collect::<Vec<RegParty>>();
reg_parties.sort();
ClosedKeyReg {
merkle_tree: Arc::new(MerkleTree::create(®_parties)),
reg_parties,
total_stake,
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::multi_sig::SigningKey;
use blake2::{digest::consts::U32, Blake2b};
use proptest::collection::vec;
use proptest::prelude::*;
use rand_chacha::ChaCha20Rng;
use rand_core::SeedableRng;
proptest! {
#[test]
fn test_keyreg(stake in vec(1..1u64 << 60, 2..=10),
nkeys in 2..10_usize,
fake_it in 0..4usize,
seed in any::<[u8;32]>()) {
let mut rng = ChaCha20Rng::from_seed(seed);
let mut kr = KeyReg::init();
let gen_keys = (1..nkeys).map(|_| {
let sk = SigningKey::gen(&mut rng);
VerificationKeyPoP::from(&sk)
}).collect::<Vec<_>>();
let fake_key = {
let sk = SigningKey::gen(&mut rng);
VerificationKeyPoP::from(&sk)
};
// Record successful registrations
let mut keys = HashMap::new();
for (i, &stake) in stake.iter().enumerate() {
let mut pk = gen_keys[i % gen_keys.len()];
if fake_it == 0 {
pk.pop = fake_key.pop;
}
let reg = kr.register(stake, pk);
match reg {
Ok(_) => {
assert!(keys.insert(pk.vk, stake).is_none());
},
Err(RegisterError::KeyRegistered(pk1)) => {
assert!(pk1.as_ref() == &pk.vk);
assert!(keys.contains_key(&pk.vk));
}
Err(RegisterError::KeyInvalid(a)) => {
assert_eq!(fake_it, 0);
assert!(a.check().is_err());
}
Err(RegisterError::SerializationError) => unreachable!(),
_ => unreachable!(),
}
}
if !kr.keys.is_empty() {
let closed = kr.close::<Blake2b<U32>>();
let retrieved_keys = closed.reg_parties.iter().map(|r| (r.0, r.1)).collect::<HashMap<_,_>>();
assert!(retrieved_keys == keys);
}
}
}
}