change api to weight, use weight_factor internally

This commit is contained in:
Alexey Proshutinskiy 2021-09-14 17:55:26 +03:00
parent 02406c6426
commit 0541946a1f
9 changed files with 267 additions and 287 deletions

View File

@ -23,7 +23,6 @@ impl From<Result<(), ServiceError>> for InsertResult {
}
}
// TODO: add peer id to result
#[marine]
pub struct WeightResult {
pub success: bool,
@ -32,17 +31,19 @@ pub struct WeightResult {
pub error: String,
}
impl From<Result<Option<u32>, ServiceError>> for WeightResult {
fn from(result: Result<Option<u32>, ServiceError>) -> Self {
impl From<Result<(u32, String), ServiceError>> for WeightResult {
fn from(result: Result<(u32, String), ServiceError>) -> Self {
match result {
Ok(wo) => WeightResult {
Ok((weight, peer_id)) => WeightResult {
success: true,
weight: wo.map(|w| vec![w]).unwrap_or(vec![]),
weight,
peer_id,
error: "".to_string(),
},
Err(e) => WeightResult {
success: false,
weight: vec![],
weight: 0u32,
peer_id: "".to_string(),
error: format!("{}", e),
},
}

View File

@ -1,12 +1,11 @@
use crate::dto::{Certificate, Trust};
use crate::results::{
AddRootResult, AddTrustResult, AllCertsResult, GetTrustMetadataResult, InsertResult,
IssueCertificateResult, IssueTrustResult, VerifyTrustResult, WeightResult,
IssueTrustResult, VerifyTrustResult, WeightResult,
};
use crate::service_impl::{
add_root_impl, add_trust_impl, get_all_certs_impl, get_trust_metadata_imp, get_weight_impl,
insert_cert_impl, insert_cert_impl_raw, issue_certificate_with_trust_checked_impl,
issue_root_certificate_checked_impl, issue_trust_impl, verify_trust_impl,
insert_cert_impl, insert_cert_impl_raw, issue_trust_impl, verify_trust_impl,
};
use marine_rs_sdk::{marine, CallParameters};
@ -28,7 +27,9 @@ fn insert_cert(certificate: Certificate, timestamp_sec: u64) -> InsertResult {
// TODO: pass current timestamp, return only valid, delete expired, return max weight
#[marine]
fn get_weight(peer_id: String) -> WeightResult {
get_weight_impl(peer_id).into()
get_weight_impl(peer_id.clone())
.map(|w| (w, peer_id))
.into()
}
// TODO: pass current timestamp, return only valid, delete expired
@ -37,8 +38,6 @@ fn get_all_certs(issued_for: String) -> AllCertsResult {
get_all_certs_impl(issued_for).into()
}
// todo: add trust method
#[marine]
/// could add only a host of a trust graph service
fn add_root(peer_id: String, weight: u32) -> AddRootResult {
@ -57,20 +56,26 @@ fn add_root(peer_id: String, weight: u32) -> AddRootResult {
#[marine]
fn get_trust_metadata(
issued_for_peer_id: String,
expires_at: u64,
issued_at: u64,
expires_at_sec: u64,
issued_at_sec: u64,
) -> GetTrustMetadataResult {
get_trust_metadata_imp(issued_for_peer_id, expires_at, issued_at).into()
get_trust_metadata_imp(issued_for_peer_id, expires_at_sec, issued_at_sec).into()
}
#[marine]
fn issue_trust(
issued_for_peer_id: String,
expires_at: u64,
issued_at: u64,
expires_at_sec: u64,
issued_at_sec: u64,
signed_metadata: Vec<u8>,
) -> IssueTrustResult {
issue_trust_impl(issued_for_peer_id, expires_at, issued_at, signed_metadata).into()
issue_trust_impl(
issued_for_peer_id,
expires_at_sec,
issued_at_sec,
signed_metadata,
)
.into()
}
#[marine]
@ -78,47 +83,8 @@ fn verify_trust(trust: Trust, issuer_peer_id: String, timestamp_sec: u64) -> Ver
verify_trust_impl(trust, issuer_peer_id, timestamp_sec).into()
}
// TODO: check issued_at earlier than timestamp_sec
#[marine]
fn add_trust(trust: Trust, issuer_peer_id: String, timestamp_sec: u64) -> AddTrustResult {
add_trust_impl(trust, issuer_peer_id, timestamp_sec).into()
}
// service TrustGraph("trust-graph"):
// -- returns hash of metadata to sign
// get_trust_bytes(issued_for_peer_id: string, expires_at: u64, issued_at: u64) -> GetTrustMetadataResult
//
// -- issued_by needed to identify signature type (ed25519, rsa or secp256k1)
// issue_trust(issued_by_peer_id: string, issued_for_peer_id: string, expires_at: u64, issued_at: u64, signature: []u8) -> IssueTrustResult
//
// -- just verifying signatures, timestamp without inserting into local trust graph
// verify_trust(issued_by_peer_id: string, trust: Trust, timestamp_sec: u64) -> VerifyTrustResult
//
// -- checks signature, timestamp, try to find place to insert, returns max_weight if succeed
// add_trust(issued_by_peer_id: string, trust: Trust, timestamp_sec: u64) -> AddTrustResult
//
// -- add root trust with given weight
// add_root(peer_id: string, trust: Trust, weight: u32) -> AddRootResult
//
// -- return max weight if found, remove expired
// get_weight(issued_for: string, timestamp_sec: u32) -> WeightResult
//
// -- return all certs, remove expired
// get_all_certs(issued_for: string, timestamp_sec) -> AllCertsResult
//
// -- insert full certificate if possible
// insert_cert(certificate: Certificate, current_time: u64) -> InsertResult
// insert_cert_raw(certificate: string, current_time: u64) -> InsertResult
//
// -- returns hash of metadata to sign
// get_revoke_bytes(revoked_peer_id: string, revoked_at: u64, issued_at: u64) -> GetRevokeMetadataResult
//
// -- revoked_by needed to identify signature type (ed25519, rsa or secp256k1)
// issue_revoke(revoked_by_peer_id: string, revoked_peer_id: string, revoked_at: u64, signature: []u8) -> IssueRevokeResult
//
// -- checks signature, checks timestamp
// revoke(revoke: Revoke, timestamp_sec: u64) -> AddRevokeResult
//
// get_all_revocation(revoked_peer_id: string)
//
// -- TODO
// get_trust

View File

@ -10,7 +10,7 @@ use std::convert::{Into, TryInto};
use std::str::FromStr;
use std::time::Duration;
use thiserror::Error as ThisError;
use trust_graph::{current_time, CertificateError, TrustError, TrustGraphError};
use trust_graph::{CertificateError, TrustError, TrustGraphError};
pub static TRUSTED_TIMESTAMP_SERVICE_ID: &str = "peer";
pub static TRUSTED_TIMESTAMP_FUNCTION_NAME: &str = "timestamp_sec";
@ -24,7 +24,7 @@ pub(crate) fn check_timestamp_tetraplets(
.tetraplets
.get(arg_number)
.ok_or(InvalidTimestampTetraplet)?;
let tetraplet = tetraplets.get(0).wrap_err(error_msg)?;
let tetraplet = tetraplets.get(0).ok_or(InvalidTimestampTetraplet)?;
(tetraplet.service_id == TRUSTED_TIMESTAMP_SERVICE_ID
&& tetraplet.function_name == TRUSTED_TIMESTAMP_FUNCTION_NAME
&& tetraplet.peer_pk == call_parameters.host_id)
@ -82,7 +82,7 @@ fn extract_public_key(peer_id: String) -> Result<PublicKey, ServiceError> {
.map_err(|e| ServiceError::PublicKeyExtractionError(e.to_string()))
}
pub fn get_weight_impl(peer_id: String) -> Result<Option<u32>, ServiceError> {
pub fn get_weight_impl(peer_id: String) -> Result<u32, ServiceError> {
let tg = get_data().lock();
let public_key = extract_public_key(peer_id)?;
let weight = tg.weight(public_key)?;
@ -127,35 +127,38 @@ pub fn insert_cert_impl(certificate: Certificate, timestamp_sec: u64) -> Result<
pub fn add_root_impl(peer_id: String, weight: u32) -> Result<(), ServiceError> {
let mut tg = get_data().lock();
let public_key = extract_public_key(peer_id)?;
tg.add_root_weight(public_key, weight)?;
tg.add_root_weight_factor(public_key, weight)?;
Ok(())
}
pub fn get_trust_metadata_imp(
peer_id: String,
expires_at: u64,
issued_at: u64,
expires_at_sec: u64,
issued_at_sec: u64,
) -> Result<Vec<u8>, ServiceError> {
let public_key = extract_public_key(peer_id)?;
Ok(trust_graph::Trust::metadata_bytes(
&public_key,
Duration::from_secs(expires_at),
Duration::from_secs(issued_at),
Duration::from_secs(expires_at_sec),
Duration::from_secs(issued_at_sec),
))
}
pub fn issue_trust_impl(
peer_id: String,
expires_at: u64,
issued_at: u64,
expires_at_sec: u64,
issued_at_sec: u64,
signed_metadata: Vec<u8>,
) -> Result<Trust, ServiceError> {
let public_key = extract_public_key(peer_id)?;
let expires_at = Duration::from_secs(expires_at);
let issued_at = Duration::from_secs(issued_at);
let expires_at_sec = Duration::from_secs(expires_at_sec);
let issued_at_sec = Duration::from_secs(issued_at_sec);
let signature = Signature::from_bytes_with_public_key(&public_key, signed_metadata);
Ok(Trust::from(trust_graph::Trust::new(
public_key, expires_at, issued_at, signature,
public_key,
expires_at_sec,
issued_at_sec,
signature,
)))
}
@ -179,15 +182,14 @@ pub fn add_trust_impl(
trust: Trust,
issuer_peer_id: String,
timestamp_sec: u64,
) -> Result<(), ServiceError> {
) -> Result<u32, ServiceError> {
let public_key = extract_public_key(issuer_peer_id)?;
check_timestamp_tetraplets(&marine_rs_sdk::get_call_parameters(), 2)?;
let mut tg = get_data().lock();
tg.add_trust(
trust.try_into()?,
&trust.try_into()?,
public_key,
Duration::from_secs(timestamp_sec),
)?;
Ok(())
)
.map_err(ServiceError::TGError)
}

View File

@ -7,7 +7,6 @@ use crate::storage_impl::SQLiteStorageError::{
WeightConversionDB,
};
use core::convert::TryFrom;
use fluence_keypair::public_key::PublicKey;
use marine_sqlite_connector;
use marine_sqlite_connector::Connection;
use marine_sqlite_connector::Error as InternalSqliteError;
@ -21,7 +20,8 @@ use std::str::FromStr;
use std::time::Duration;
use thiserror::Error as ThisError;
use trust_graph::{
Auth, PublicKeyHashable as PK, Revoke, Storage, StorageError, TrustGraph, TrustNode, Weight,
Auth, PublicKeyHashable as PK, Revoke, Storage, StorageError, TrustGraph, TrustNode,
WeightFactor,
};
static INSTANCE: OnceCell<Mutex<TrustGraph<SQLiteStorage>>> = OnceCell::new();
@ -140,7 +140,7 @@ impl Storage for SQLiteStorage {
Ok({})
}
fn get_root_weight(&self, pk: &PK) -> Result<Option<Weight>, Self::Error> {
fn get_root_weight_factor(&self, pk: &PK) -> Result<Option<WeightFactor>, Self::Error> {
let mut cursor = self
.connection
.prepare("SELECT public_key,weight FROM roots WHERE public_key = ?")?
@ -160,7 +160,7 @@ impl Storage for SQLiteStorage {
}
}
fn add_root_weight(&mut self, pk: PK, weight: Weight) -> Result<(), Self::Error> {
fn add_root_weight_factor(&mut self, pk: PK, weight: WeightFactor) -> Result<(), Self::Error> {
log::info!("add root: {} weight: {}", pk, weight);
let mut cursor = self
.connection
@ -208,20 +208,19 @@ impl Storage for SQLiteStorage {
fn update_auth(
&mut self,
pk: &PK,
issued_for_pk: &PK,
auth: Auth,
issued_for: &PublicKey,
cur_time: Duration,
) -> Result<(), Self::Error> {
match self.get(&pk)? {
match self.get(&issued_for_pk)? {
Some(mut trust_node) => {
trust_node.update_auth(auth);
self.insert(pk.clone(), trust_node)
self.insert(issued_for_pk.clone(), trust_node)
}
None => {
let mut trust_node = TrustNode::new(issued_for.clone(), cur_time);
let mut trust_node = TrustNode::new(auth.trust.issued_for.clone(), cur_time);
trust_node.update_auth(auth);
self.insert(pk.clone(), trust_node)
self.insert(issued_for_pk.clone(), trust_node)
}
}
}

View File

@ -17,10 +17,30 @@
// TODO: clear DB before every test, run in 1 thread
#[cfg(test)]
mod tests {
use crate::service_impl::{TRUSTED_TIMESTAMP_FUNCTION_NAME, TRUSTED_TIMESTAMP_SERVICE_ID};
use fluence_keypair;
use fluence_keypair::KeyPair;
use marine_rs_sdk_test::marine_test;
use std::time::Duration;
use marine_rs_sdk_test::{marine_test, CallParameters, SecurityTetraplet};
pub static HOST_ID: &str = "host_id";
fn get_correct_timestamp_cp(arg_number: usize) -> CallParameters {
let mut cp = CallParameters::default();
cp.host_id = HOST_ID.to_string();
for _ in 0..arg_number {
cp.tetraplets.push(vec![]);
}
cp.tetraplets.push(vec![SecurityTetraplet {
peer_pk: HOST_ID.to_string(),
service_id: TRUSTED_TIMESTAMP_SERVICE_ID.to_string(),
function_name: TRUSTED_TIMESTAMP_FUNCTION_NAME.to_string(),
json_path: "".to_string(),
}]);
cp
}
macro_rules! issue_trust {
($trust_graph:expr, $issuer_kp:expr, $issued_peer_id: expr, $expires_at:expr, $issued_at: expr) => {{
@ -64,67 +84,12 @@ mod tests {
expires_at,
issued_at
);
let verify_result = trust_graph.verify_trust(trust, issuer_kp.get_peer_id().to_base58(), 0);
let verify_result = trust_graph.verify_trust_cp(
trust,
issuer_kp.get_peer_id().to_base58(),
0,
get_correct_timestamp_cp(2),
);
assert_result!(verify_result);
}
#[marine_test(config_path = "../Config.toml", modules_dir = "../artifacts/")]
fn issue_cert_test() {
let issuer_kp = KeyPair::generate_ed25519();
let issued_peer_id = KeyPair::generate_ed25519().get_peer_id();
let issued_at = 0u64;
let expires_at = 10u64;
let root_trust = issue_trust!(
trust_graph,
issuer_kp,
issuer_kp.get_peer_id(),
expires_at,
issued_at
);
let trust = issue_trust!(
trust_graph,
issuer_kp,
issued_peer_id,
expires_at,
issued_at
);
let cert_result = trust_graph.issue_root_certificate_checked(root_trust, trust, 0u64);
assert_result!(cert_result);
}
#[marine_test(config_path = "../Config.toml", modules_dir = "../artifacts/")]
fn extend_cert_test() {
let issuer_kp = KeyPair::generate_ed25519();
let issued_peer_id = KeyPair::generate_ed25519().get_peer_id();
let issued_at = 0u64;
let expires_at = 10u64;
let root_trust = issue_trust!(
trust_graph,
issuer_kp,
issuer_kp.get_peer_id(),
expires_at,
issued_at
);
let trust = issue_trust!(
trust_graph,
issuer_kp,
issued_peer_id,
expires_at,
issued_at
);
let cert_result = trust_graph.issue_root_certificate_checked(root_trust, trust, 0u64);
assert_result!(cert_result);
println!("{:?}", cert_result.cert);
assert_result!(trust_graph.add_root(issuer_kp.get_peer_id().to_base58(), 300));
let insert_res = trust_graph.insert_cert(cert_result.cert, 0u64);
assert_result!(insert_res);
let all_certs_res = trust_graph.get_all_certs(issued_peer_id.to_base58());
assert_result!(all_certs_res);
assert_eq!(all_certs_res.certificates.len(), 1);
println!("{:?}", all_certs_res.certificates);
}
}

View File

@ -2,6 +2,11 @@ data AddRootResult:
success: bool
error: string
data AddTrustResult:
success: bool
error: string
weight: u32
data Trust:
issued_for: string
expires_at: u64
@ -26,11 +31,6 @@ data InsertResult:
success: bool
error: string
data IssueCertificateResult:
success: bool
error: string
cert: Certificate
data IssueTrustResult:
success: bool
error: string
@ -40,12 +40,6 @@ data VerifyTrustResult:
success: bool
error: string
data AddTrustResult:
success: bool
error: string
weight: u32
peer_id: u32
data WeightResult:
success: bool
weight: u32
@ -53,41 +47,12 @@ data WeightResult:
error: string
service TrustGraph("trust-graph"):
-- returns hash of metadata to sign
get_trust_bytes(issued_for_peer_id: string, expires_at: u64, issued_at: u64) -> GetTrustMetadataResult
-- issued_by needed to identify signature type (ed25519, rsa or secp256k1)
issue_trust(issued_by_peer_id: string, issued_for_peer_id: string, expires_at: u64, issued_at: u64, signature: []u8) -> IssueTrustResult
-- just verifying signatures, timestamp without inserting into local trust graph
verify_trust(issued_by_peer_id: string, trust: Trust, timestamp_sec: u64) -> VerifyTrustResult
-- checks signature, timestamp, try to find place to insert, returns max_weight if succeed
add_trust(issued_by_peer_id: string, trust: Trust, timestamp_sec: u64) -> AddTrustResult
-- add root trust with given weight
add_root(peer_id: string, trust: Trust, weight: u32) -> AddRootResult
-- return max weight if found, remove expired
get_weight(issued_for: string, timestamp_sec: u32) -> WeightResult
-- return all certs, remove expired
get_all_certs(issued_for: string, timestamp_sec) -> AllCertsResult
-- insert full certificate if possible
insert_cert(certificate: Certificate, current_time: u64) -> InsertResult
insert_cert_raw(certificate: string, current_time: u64) -> InsertResult
-- returns hash of metadata to sign
get_revoke_bytes(revoked_peer_id: string, revoked_at: u64, issued_at: u64) -> GetRevokeMetadataResult
-- revoked_by needed to identify signature type (ed25519, rsa or secp256k1)
issue_revoke(revoked_by_peer_id: string, revoked_peer_id: string, revoked_at: u64, signature: []u8) -> IssueRevokeResult
-- checks signature, checks timestamp
revoke(revoke: Revoke, timestamp_sec: u64) -> AddRevokeResult
get_all_revocation(revoked_peer_id: string)
-- TODO
get_trust
add_root(peer_id: string, weight: u32) -> AddRootResult
add_trust(trust: Trust, issuer_peer_id: string, timestamp_sec: u64) -> AddTrustResult
get_all_certs(issued_for: string) -> AllCertsResult
get_trust_metadata(issued_for_peer_id: string, expires_at: u64, issued_at: u64) -> GetTrustMetadataResult
get_weight(peer_id: string) -> WeightResult
insert_cert(certificate: Certificate, timestamp_sec: u64) -> InsertResult
insert_cert_raw(certificate: string, timestamp_sec: u64) -> InsertResult
issue_trust(issued_for_peer_id: string, expires_at: u64, issued_at: u64, signed_metadata: []u8) -> IssueTrustResult
verify_trust(trust: Trust, issuer_peer_id: string, timestamp_sec: u64) -> VerifyTrustResult

View File

@ -41,6 +41,8 @@ pub use crate::misc::current_time;
pub use crate::public_key_hashable::PublicKeyHashable;
pub use crate::revoke::Revoke;
pub use crate::trust::{Trust, TrustError};
pub use crate::trust_graph::{TrustGraph, TrustGraphError, Weight};
pub use crate::trust_graph_storage::{Storage, StorageError, InMemoryStorage, InMemoryStorageError};
pub use crate::trust_graph::{TrustGraph, TrustGraphError, WeightFactor};
pub use crate::trust_graph_storage::{
InMemoryStorage, InMemoryStorageError, Storage, StorageError,
};
pub use crate::trust_node::{Auth, TrustNode};

View File

@ -25,7 +25,7 @@ use crate::trust_graph::TrustGraphError::{
};
use crate::trust_graph_storage::Storage;
use crate::trust_node::{Auth, TrustNode};
use crate::StorageError;
use crate::{StorageError, TrustError};
use fluence_keypair::public_key::PublicKey;
use std::borrow::Borrow;
use std::collections::{HashSet, VecDeque};
@ -35,7 +35,9 @@ use std::time::Duration;
use thiserror::Error as ThisError;
/// for simplicity, we store `n` where Weight = 1/n^2
pub type Weight = u32;
pub type WeightFactor = u32;
pub static MAX_WEIGHT_FACTOR: u32 = 16;
/// Graph to efficiently calculate weights of certificates and get chains of certificates.
/// TODO serialization/deserialization
@ -70,6 +72,12 @@ pub enum TrustGraphError {
),
#[error("Path to {0} not found")]
AddTrustError(String),
#[error("Trust verification error: {0}")]
TrustVerificationError(
#[from]
#[source]
TrustError,
),
}
impl<T: StorageError + 'static> From<T> for TrustGraphError {
@ -84,6 +92,10 @@ impl From<TrustGraphError> for String {
}
}
pub fn get_weight_from_factor(wf: WeightFactor) -> u32 {
2u32.pow(MAX_WEIGHT_FACTOR - wf)
}
#[allow(dead_code)]
impl<S> TrustGraph<S>
where
@ -94,12 +106,12 @@ where
}
/// Insert new root weight
pub fn add_root_weight(
pub fn add_root_weight_factor(
&mut self,
pk: PublicKey,
weight: Weight,
weight: WeightFactor,
) -> Result<(), TrustGraphError> {
Ok(self.storage.add_root_weight(pk.into(), weight)?)
Ok(self.storage.add_root_weight_factor(pk.into(), weight)?)
}
/// Get trust by public key
@ -112,28 +124,29 @@ where
trust: T,
issued_by: P,
cur_time: Duration,
) -> Result<(), TrustGraphError>
) -> Result<u32, TrustGraphError>
where
T: Borrow<Trust>,
P: Borrow<PublicKey>,
{
Trust::verify(trust, issued_by.borrow(), cur_time)?;
Trust::verify(trust.borrow(), issued_by.borrow(), cur_time)?;
let _parent_trust_node =
self.get(issued_by.clone().borrow())?
.ok_or(TrustGraphError::AddTrustError(
issued_by.borrow().to_peer_id().to_base58(),
))?;
let issued_by_weight = self.weight(issued_by.borrow().clone().borrow())?;
let pk = trust.issued_for.clone().into();
if issued_by_weight == 0u32 {
return Ok(0u32);
}
let pk = trust.borrow().issued_for.clone().into();
let auth = Auth {
trust: trust.clone(),
issued_by,
trust: trust.borrow().clone(),
issued_by: issued_by.borrow().clone(),
};
self.storage
.update_auth(&pk, auth, &root_trust.issued_for, cur_time)
self.storage.update_auth(&pk, auth, cur_time)?;
Ok(issued_by_weight / 2)
}
/// Certificate is a chain of trusts, add this chain to graph
@ -148,36 +161,25 @@ where
.cloned()
.map(Into::into)
.collect();
// TODO: add possibility to add certs with root not in trusted_roots (if path to cert root exists)
// Check that certificate is valid and converges to one of the known roots
Certificate::verify(cert.borrow(), roots.as_slice(), cur_time)?;
let mut chain = cert.borrow().chain.iter();
let root_trust = chain.next().ok_or(EmptyChain)?;
let root_pk: PK = root_trust.issued_for.clone().into();
// Insert new TrustNode for this root_pk if there wasn't one
if self.storage.get(&root_pk)?.is_none() {
let root_auth = Auth {
trust: root_trust.clone(),
issued_by: root_trust.issued_for.clone(),
};
self.storage
.update_auth(&root_pk, root_auth, &root_trust.issued_for, cur_time)?;
}
let chain = &cert.borrow().chain;
let root_trust = chain.get(0).ok_or(EmptyChain)?;
// Insert remaining trusts to the graph
let mut previous_trust = root_trust;
for trust in chain {
let pk = trust.issued_for.clone().into();
let issued_for_pk = trust.issued_for.clone().into();
let auth = Auth {
trust: trust.clone(),
issued_by: previous_trust.issued_for.clone(),
};
self.storage
.update_auth(&pk, auth, &root_trust.issued_for, cur_time)?;
self.storage.update_auth(&issued_for_pk, auth, cur_time)?;
previous_trust = trust;
}
@ -186,12 +188,12 @@ where
}
/// Get the maximum weight of trust for one public key.
pub fn weight<P>(&self, pk: P) -> Result<Option<Weight>, TrustGraphError>
pub fn weight<P>(&self, pk: P) -> Result<u32, TrustGraphError>
where
P: Borrow<PublicKey>,
{
if let Some(weight) = self.storage.get_root_weight(pk.borrow().as_ref())? {
return Ok(Some(weight));
if let Some(weight_factor) = self.storage.get_root_weight_factor(pk.borrow().as_ref())? {
return Ok(get_weight_from_factor(weight_factor));
}
let roots: Vec<PublicKey> = self
@ -203,14 +205,18 @@ where
// get all possible certificates from the given public key to all roots in the graph
let certs = self.get_all_certs(pk, roots.as_slice())?;
self.certificates_weight(certs)
self.certificates_weight_factor(certs)
.map(get_weight_from_factor)
}
/// Calculate weight from given certificates
/// Returns None if there is no such public key
/// or some trust between this key and a root key is revoked.
/// TODO handle non-direct revocations
pub fn certificates_weight<C, I>(&self, certs: I) -> Result<Option<Weight>, TrustGraphError>
pub fn certificates_weight_factor<C, I>(
&self,
certs: I,
) -> Result<WeightFactor, TrustGraphError>
where
C: Borrow<Certificate>,
I: IntoIterator<Item = C>,
@ -219,10 +225,10 @@ where
// if there are no certificates for the given public key, there is no info about this public key
// or some elements of possible certificate chains was revoked
if certs.peek().is_none() {
return Ok(None);
return Ok(0u32);
}
let mut weight = u32::MAX;
let mut weight_factor = u32::MAX;
for cert in certs {
let c = cert.borrow();
@ -234,15 +240,15 @@ where
let root_weight = self
.storage
.get_root_weight(first.issued_for.as_ref())?
.get_root_weight_factor(first.issued_for.as_ref())?
.ok_or(NoRoot)?;
// certificate weight = root weight + 1 * every other element in the chain
// (except root, so the formula is `root weight + chain length - 1`)
weight = std::cmp::min(weight, root_weight + c.chain.len() as u32 - 1)
weight_factor = std::cmp::min(weight_factor, root_weight + c.chain.len() as u32 - 1)
}
Ok(Some(weight))
Ok(weight_factor)
}
/// BF search for all converging paths (chains) in the graph
@ -463,7 +469,9 @@ mod tests {
let st = InMemoryStorage::new();
let mut graph = TrustGraph::new(st);
graph.add_root_weight(root.public().into(), 0).unwrap();
graph
.add_root_weight_factor(root.public().into(), 0)
.unwrap();
let addition = graph.add(cert, current_time());
assert_eq!(addition.is_ok(), true);
@ -497,8 +505,8 @@ mod tests {
let mut graph = TrustGraph::new(st);
let root1_pk = key_pairs1[0].public();
let root2_pk = key_pairs2[0].public();
graph.add_root_weight(root1_pk.into(), 1).unwrap();
graph.add_root_weight(root2_pk.into(), 0).unwrap();
graph.add_root_weight_factor(root1_pk.into(), 1).unwrap();
graph.add_root_weight_factor(root2_pk.into(), 0).unwrap();
graph.add(cert1, cur_time).unwrap();
let node2 = graph.get(key_pair2.public()).unwrap().unwrap();
@ -529,18 +537,19 @@ mod tests {
let mut graph = TrustGraph::new(st);
let root_pk = key_pairs[0].public();
graph.add_root_weight(root_pk.into(), 1).unwrap();
graph.add_root_weight_factor(root_pk.into(), 1).unwrap();
graph.add(cert1, current_time()).unwrap();
let w1 = graph.weight(key_pairs[0].public()).unwrap().unwrap();
assert_eq!(w1, 1);
let root_weight = get_weight_from_factor(1);
let w1 = graph.weight(key_pairs[0].public()).unwrap();
assert_eq!(w1, root_weight * 2u32.pow(0));
let w2 = graph.weight(key_pairs[1].public()).unwrap().unwrap();
assert_eq!(w2, 2);
let w2 = graph.weight(key_pairs[1].public()).unwrap();
assert_eq!(w2, root_weight / 2u32.pow(1));
let w3 = graph.weight(key_pairs[9].public()).unwrap().unwrap();
assert_eq!(w3, 10);
let w3 = graph.weight(key_pairs[9].public()).unwrap();
assert_eq!(w3, root_weight / 2u32.pow(9));
let node = graph.get(key_pairs[9].public()).unwrap().unwrap();
let auths: Vec<&Auth> = node.authorizations().collect();
@ -573,8 +582,8 @@ mod tests {
let mut graph = TrustGraph::new(st);
let root1_pk = key_pairs1[0].public();
let root2_pk = key_pairs2[0].public();
graph.add_root_weight(root1_pk.into(), 1).unwrap();
graph.add_root_weight(root2_pk.into(), 0).unwrap();
graph.add_root_weight_factor(root1_pk.into(), 1).unwrap();
graph.add_root_weight_factor(root2_pk.into(), 0).unwrap();
let last_pk1 = cert1.chain[9].issued_for.clone();
let last_pk2 = cert2.chain[9].issued_for.clone();
@ -587,15 +596,15 @@ mod tests {
let revoke2 = Revoke::create(&key_pairs2[5], key_pairs2[6].public(), current_time());
graph.revoke(revoke2).unwrap();
let w1 = graph.weight(key_pair1.public()).unwrap().unwrap();
let w1 = graph.weight(key_pair1.public()).unwrap();
// all upper trusts are revoked for this public key
let w2 = graph.weight(key_pair2.public()).unwrap();
let w3 = graph.weight(key_pair3.public()).unwrap().unwrap();
let w_last1 = graph.weight(last_pk1).unwrap().unwrap();
let w_last2 = graph.weight(last_pk2).unwrap().unwrap();
let w3 = graph.weight(key_pair3.public()).unwrap();
let w_last1 = graph.weight(last_pk1).unwrap();
let w_last2 = graph.weight(last_pk2).unwrap();
assert_eq!(w1, 4);
assert_eq!(w2.is_none(), true);
assert_eq!(w2, 0);
assert_eq!(w3, 5);
assert_eq!(w_last1, 7);
assert_eq!(w_last2, 6);
@ -608,7 +617,9 @@ mod tests {
let st = InMemoryStorage::new();
let mut graph = TrustGraph::new(st);
let root1_pk = key_pairs[0].public();
graph.add_root_weight(root1_pk.clone().into(), 1).unwrap();
graph
.add_root_weight_factor(root1_pk.clone().into(), 1)
.unwrap();
graph.add(cert.clone(), current_time()).unwrap();
@ -628,13 +639,13 @@ mod tests {
let mut graph = TrustGraph::new(st);
// add first and last trusts as roots
graph
.add_root_weight(cert.chain[0].clone().issued_for.into(), 1)
.add_root_weight_factor(cert.chain[0].clone().issued_for.into(), 1)
.unwrap();
graph
.add_root_weight(cert.chain[3].clone().issued_for.into(), 1)
.add_root_weight_factor(cert.chain[3].clone().issued_for.into(), 1)
.unwrap();
graph
.add_root_weight(cert.chain[5].clone().issued_for.into(), 1)
.add_root_weight_factor(cert.chain[5].clone().issued_for.into(), 1)
.unwrap();
graph.add(cert.clone(), current_time()).unwrap();
@ -677,9 +688,15 @@ mod tests {
let root1_pk = key_pairs1[0].public();
let root2_pk = key_pairs2[0].public();
let root3_pk = key_pairs3[0].public();
graph.add_root_weight(root1_pk.clone().into(), 1).unwrap();
graph.add_root_weight(root2_pk.clone().into(), 0).unwrap();
graph.add_root_weight(root3_pk.clone().into(), 0).unwrap();
graph
.add_root_weight_factor(root1_pk.clone().into(), 1)
.unwrap();
graph
.add_root_weight_factor(root2_pk.clone().into(), 0)
.unwrap();
graph
.add_root_weight_factor(root3_pk.clone().into(), 0)
.unwrap();
graph.add(cert1, current_time()).unwrap();
graph.add(cert2, current_time()).unwrap();
@ -708,4 +725,74 @@ mod tests {
let check_lenghts3: Vec<usize> = vec![3, 3, 5];
assert_eq!(lenghts3, check_lenghts3);
}
#[test]
fn test_add_one_trust_to_cert_last() {
let (key_pairs, mut cert) = generate_cert_with_len(5, HashMap::new()).unwrap();
let cur_time = current_time();
let st = InMemoryStorage::new();
let mut graph = TrustGraph::new(st);
let root_pk = key_pairs[0].public();
graph
.add_root_weight_factor(root_pk.clone().into(), 2)
.unwrap();
graph.add(cert.clone(), cur_time).unwrap();
let issued_by = key_pairs.last().unwrap();
let trust_kp = KeyPair::generate_ed25519();
let trust = Trust::create(
issued_by,
trust_kp.public(),
cur_time.checked_add(one_minute()).unwrap(),
cur_time,
);
let weight = graph
.add_trust(trust.clone(), issued_by.public(), cur_time)
.unwrap();
assert_eq!(weight, graph.weight(issued_by.public()).unwrap() / 2);
cert.chain.push(trust);
let certs = graph.get_all_certs(trust_kp.public(), &[]).unwrap();
assert_eq!(certs.len(), 1);
assert_eq!(certs[0], cert);
}
#[test]
fn test_add_one_trust_to_cert_after_root() {
let (key_pairs, cert) = generate_cert_with_len(5, HashMap::new()).unwrap();
let cur_time = current_time();
let st = InMemoryStorage::new();
let mut graph = TrustGraph::new(st);
let root1_pk = key_pairs[0].public();
graph
.add_root_weight_factor(root1_pk.clone().into(), 2)
.unwrap();
graph.add(cert.clone(), cur_time).unwrap();
let issued_by = key_pairs.first().unwrap();
let trust_kp = KeyPair::generate_ed25519();
let trust = Trust::create(
issued_by,
trust_kp.public(),
cur_time.checked_add(one_minute()).unwrap(),
cur_time,
);
let weight = graph
.add_trust(trust.clone(), issued_by.public(), cur_time)
.unwrap();
assert_eq!(weight, graph.weight(issued_by.public()).unwrap() / 2);
let target_cert = Certificate {
chain: vec![cert.chain[0].clone(), trust],
};
let certs = graph.get_all_certs(trust_kp.public(), &[root1_pk]).unwrap();
assert_eq!(certs.len(), 1);
assert_eq!(certs[0], target_cert);
}
}

View File

@ -1,6 +1,6 @@
use crate::public_key_hashable::PublicKeyHashable as PK;
use crate::revoke::Revoke;
use crate::trust_graph::Weight;
use crate::trust_graph::WeightFactor;
use crate::trust_graph_storage::InMemoryStorageError::RevokeError;
use crate::trust_node::{Auth, TrustNode};
use fluence_keypair::public_key::PublicKey;
@ -17,28 +17,22 @@ pub trait Storage {
fn get(&self, pk: &PK) -> Result<Option<TrustNode>, Self::Error>;
fn insert(&mut self, pk: PK, node: TrustNode) -> Result<(), Self::Error>;
fn get_root_weight(&self, pk: &PK) -> Result<Option<Weight>, Self::Error>;
fn add_root_weight(&mut self, pk: PK, weight: Weight) -> Result<(), Self::Error>;
fn get_root_weight_factor(&self, pk: &PK) -> Result<Option<WeightFactor>, Self::Error>;
fn add_root_weight_factor(&mut self, pk: PK, weight: WeightFactor) -> Result<(), Self::Error>;
fn root_keys(&self) -> Result<Vec<PK>, Self::Error>;
fn revoke(&mut self, pk: &PK, revoke: Revoke) -> Result<(), Self::Error>;
fn update_auth(
&mut self,
pk: &PK,
auth: Auth,
issued_for: &PublicKey,
cur_time: Duration,
) -> Result<(), Self::Error>;
fn update_auth(&mut self, pk: &PK, auth: Auth, cur_time: Duration) -> Result<(), Self::Error>;
}
#[derive(Debug, Default)]
pub struct InMemoryStorage {
nodes: HashMap<PK, TrustNode>,
root_weights: HashMap<PK, Weight>,
root_weights: HashMap<PK, WeightFactor>,
}
impl InMemoryStorage {
#[allow(dead_code)]
pub fn new_in_memory(root_weights: Vec<(PublicKey, Weight)>) -> Self {
pub fn new_in_memory(root_weights: Vec<(PublicKey, WeightFactor)>) -> Self {
let root_weights = root_weights
.into_iter()
.map(|(k, w)| (k.into(), w))
@ -78,11 +72,11 @@ impl Storage for InMemoryStorage {
Ok(())
}
fn get_root_weight(&self, pk: &PK) -> Result<Option<Weight>, Self::Error> {
fn get_root_weight_factor(&self, pk: &PK) -> Result<Option<WeightFactor>, Self::Error> {
Ok(self.root_weights.get(pk).cloned())
}
fn add_root_weight(&mut self, pk: PK, weight: Weight) -> Result<(), Self::Error> {
fn add_root_weight_factor(&mut self, pk: PK, weight: WeightFactor) -> Result<(), Self::Error> {
self.root_weights.insert(pk, weight);
Ok(())
}
@ -105,20 +99,19 @@ impl Storage for InMemoryStorage {
fn update_auth(
&mut self,
pk: &PK,
issued_for_pk: &PK,
auth: Auth,
issued_for: &PublicKey,
cur_time: Duration,
) -> Result<(), Self::Error> {
match self.nodes.get_mut(&pk) {
match self.nodes.get_mut(&issued_for_pk) {
Some(trust_node) => {
trust_node.update_auth(auth);
Ok(())
}
None => {
let mut trust_node = TrustNode::new(issued_for.clone(), cur_time);
let mut trust_node = TrustNode::new(auth.trust.issued_for.clone(), cur_time);
trust_node.update_auth(auth);
self.insert(pk.clone(), trust_node)
self.insert(issued_for_pk.clone(), trust_node)
}
}
}