|
1 | 1 | use anyhow::{anyhow, bail, Result};
|
| 2 | +use ed25519_dalek::{Signature, Verifier, VerifyingKey}; |
2 | 3 | use jmt::KeyHash;
|
3 | 4 | use serde::{Deserialize, Serialize};
|
4 | 5 | use std::{
|
5 |
| - collections::{HashMap, HashSet}, |
| 6 | + collections::HashSet, |
6 | 7 | ops::{Deref, DerefMut},
|
7 | 8 | };
|
8 | 9 |
|
@@ -165,24 +166,73 @@ impl Hashchain {
|
165 | 166 | }
|
166 | 167 |
|
167 | 168 | // TODO: Obviously, this needs to be authenticated by an existing key.
|
168 |
| - pub fn add(&mut self, value: PublicKey, signature: SignatureBundle) -> Result<Digest> { |
169 |
| - let operation = Operation::AddKey(KeyOperationArgs { |
| 169 | + pub fn add(&mut self, value: PublicKey, signature_bundle: SignatureBundle) -> Result<Digest> { |
| 170 | + self.perform_operation(Operation::AddKey, value, signature_bundle) |
| 171 | + } |
| 172 | + |
| 173 | + pub fn revoke( |
| 174 | + &mut self, |
| 175 | + value: PublicKey, |
| 176 | + signature_bundle: SignatureBundle, |
| 177 | + ) -> Result<Digest> { |
| 178 | + self.perform_operation(Operation::RevokeKey, value, signature_bundle) |
| 179 | + } |
| 180 | + |
| 181 | + fn perform_operation( |
| 182 | + &mut self, |
| 183 | + operation_type: fn(KeyOperationArgs) -> Operation, |
| 184 | + value: PublicKey, |
| 185 | + signature_bundle: SignatureBundle, |
| 186 | + ) -> Result<Digest> { |
| 187 | + let signing_key = self.get_key_at_index(signature_bundle.key_idx as usize)?; |
| 188 | + |
| 189 | + if self.is_key_revoked(signing_key.clone()) { |
| 190 | + bail!("The signing key is revoked"); |
| 191 | + } |
| 192 | + |
| 193 | + let operation_to_sign = operation_type(KeyOperationArgs { |
170 | 194 | id: self.id.clone(),
|
171 |
| - value, |
172 |
| - signature, |
| 195 | + value: value.clone(), |
| 196 | + signature: SignatureBundle { |
| 197 | + key_idx: signature_bundle.key_idx, |
| 198 | + signature: Vec::new(), |
| 199 | + }, |
173 | 200 | });
|
174 |
| - self.push(operation) |
175 |
| - } |
176 | 201 |
|
177 |
| - pub fn revoke(&mut self, value: PublicKey, signature: SignatureBundle) -> Result<Digest> { |
178 |
| - let operation = Operation::RevokeKey(KeyOperationArgs { |
| 202 | + let message = bincode::serialize(&operation_to_sign)?; |
| 203 | + self.verify_signature( |
| 204 | + &signing_key, |
| 205 | + &message, |
| 206 | + signature_bundle.signature.as_slice(), |
| 207 | + )?; |
| 208 | + |
| 209 | + let operation = operation_type(KeyOperationArgs { |
179 | 210 | id: self.id.clone(),
|
180 | 211 | value,
|
181 |
| - signature, |
| 212 | + signature: signature_bundle, |
182 | 213 | });
|
183 | 214 | self.push(operation)
|
184 | 215 | }
|
185 | 216 |
|
| 217 | + fn verify_signature( |
| 218 | + &self, |
| 219 | + public_key: &PublicKey, |
| 220 | + message: &[u8], |
| 221 | + signature: &[u8], |
| 222 | + ) -> Result<()> { |
| 223 | + match public_key { |
| 224 | + PublicKey::Ed25519(key_bytes) => { |
| 225 | + let verifying_key = VerifyingKey::from_bytes(key_bytes.as_slice().try_into()?)?; |
| 226 | + let signature = Signature::from_slice(signature)?; |
| 227 | + verifying_key |
| 228 | + .verify(message, &signature) |
| 229 | + .map_err(|e| anyhow::anyhow!("Signature verification failed: {}", e)) |
| 230 | + } |
| 231 | + // pot. cases for other key types in the future here |
| 232 | + _ => bail!("Unsupported key type for verification"), |
| 233 | + } |
| 234 | + } |
| 235 | + |
186 | 236 | pub fn get_keyhash(&self) -> KeyHash {
|
187 | 237 | KeyHash::with::<Hasher>(self.id.clone())
|
188 | 238 | }
|
|
0 commit comments