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
152
//! hbkr - KeyConfig
use serde::{Deserialize, Serialize};
use crate::{
basicpre::BasicPrefix,
said::{SelfAddressing, SelfAddressingPrefix},
threshold::SignatureThreshold,
Prefix,
};
#[derive(Serialize, Deserialize, Debug, Clone, Default, PartialEq)]
pub struct KeyConfig {
#[serde(rename = "kt")]
pub threshold: SignatureThreshold,
#[serde(rename = "k")]
pub public_keys: Vec<BasicPrefix>,
#[serde(rename = "n", with = "empty_string_as_none")]
pub threshold_key_digest: Option<SelfAddressingPrefix>,
}
impl KeyConfig {
pub fn new(
public_keys: Vec<BasicPrefix>,
threshold_key_digest: Option<SelfAddressingPrefix>,
threshold: Option<SignatureThreshold>,
) -> Self {
Self {
threshold: threshold.map_or_else(
|| SignatureThreshold::Simple(public_keys.len() as u64 / 2 + 1),
|t| t,
),
public_keys,
threshold_key_digest,
}
}
/// Verify
///
/// Verifies the given sigs against the given message using the KeyConfigs
/// Public Keys, according to the indexes in the sigs.
// pub fn verify(&self, message: &[u8], sigs: &[AttachedSignaturePrefix]) -> Result<bool, Error> {
// // ensure there's enough sigs
// if !self.threshold.enough_signatures(sigs)? {
// Err(Error::NotEnoughSigsError)
// } else if
// // and that there are not too many
// sigs.len() <= self.public_keys.len()
// // and that there are no duplicates
// && sigs
// .iter()
// .fold(vec![0u64; self.public_keys.len()], |mut acc, sig| {
// acc[sig.index as usize] += 1;
// acc
// })
// .iter()
// .all(|n| *n <= 1)
// {
// Ok(sigs
// .iter()
// .fold(Ok(true), |acc: Result<bool, Error>, sig| {
// Ok(acc?
// && self
// .public_keys
// .get(sig.index as usize)
// .ok_or_else(|| {
// Error::SemanticError("Key index not present in set".into())
// })
// .and_then(|key: &BasicPrefix| key.verify(message, &sig.signature))?)
// })?)
// } else {
// Err(Error::SemanticError("Invalid signatures set".into()))
// }
// }
/// Verify Next
///
/// Verifies that the given next KeyConfig matches that which is committed
/// to in the threshold_key_digest of this KeyConfig
pub fn verify_next(&self, next: &KeyConfig) -> bool {
match &self.threshold_key_digest {
Some(n) => n == &next.commit(&n.derivation),
None => false,
}
}
/// Serialize For Next
///
/// Serializes the KeyConfig for creation or verification of a threshold
/// key digest commitment
pub fn commit(&self, derivation: &SelfAddressing) -> SelfAddressingPrefix {
nxt_commitment(&self.threshold, &self.public_keys, derivation)
}
}
/// Serialize For Commitment
///
/// Serializes a threshold and key set into the form
/// required for threshold key digest creation
pub fn nxt_commitment(
threshold: &SignatureThreshold,
keys: &[BasicPrefix],
derivation: &SelfAddressing,
) -> SelfAddressingPrefix {
let extracted_threshold = match threshold {
SignatureThreshold::Simple(n) => format!("{:x}", n),
// _ => unreachable!(),
};
keys.iter().fold(
derivation.derive(extracted_threshold.as_bytes()),
|acc, pk| {
SelfAddressingPrefix::new(
derivation.to_owned(),
acc.derivative()
.iter()
.zip(derivation.derive(pk.to_str().as_bytes()).derivative())
.map(|(acc_byte, pk_byte)| acc_byte ^ pk_byte)
.collect(),
)
},
)
}
mod empty_string_as_none {
use serde::{de::IntoDeserializer, Deserialize, Deserializer, Serializer};
pub fn deserialize<'d, D, T>(de: D) -> Result<Option<T>, D::Error>
where
D: Deserializer<'d>,
T: Deserialize<'d>,
{
let opt = Option::<String>::deserialize(de)?;
let opt = opt.as_deref();
match opt {
None | Some("") => Ok(None),
Some(s) => T::deserialize(s.into_deserializer()).map(Some),
}
}
pub fn serialize<S, T>(t: &Option<T>, s: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
T: ToString,
{
s.serialize_str(&match &t {
Some(v) => v.to_string(),
None => "".into(),
})
}
}