use std::{
collections::{HashSet, hash_map::RandomState},
iter,
};
use bc_components::{Digest, DigestProvider};
use crate::{Envelope, base::envelope::EnvelopeCase};
impl Envelope {
pub fn proof_contains_set(
&self,
target: &HashSet<Digest, RandomState>,
) -> Option<Envelope> {
let reveal_set = self.reveal_set_of_set(target);
if !target.is_subset(&reveal_set) {
return None;
}
Some(
self.elide_revealing_set(&reveal_set)
.elide_removing_set(target),
)
}
pub fn proof_contains_target(
&self,
target: &dyn DigestProvider,
) -> Option<Envelope> {
let set = HashSet::from_iter(iter::once(target.digest()));
self.proof_contains_set(&set)
}
pub fn confirm_contains_set(
&self,
target: &HashSet<Digest, RandomState>,
proof: &Envelope,
) -> bool {
self.digest() == proof.digest() && proof.contains_all(target)
}
pub fn confirm_contains_target(
&self,
target: &dyn DigestProvider,
proof: &Envelope,
) -> bool {
let set = HashSet::from_iter(iter::once(target.digest()));
self.confirm_contains_set(&set, proof)
}
}
impl Envelope {
fn reveal_set_of_set(&self, target: &HashSet<Digest>) -> HashSet<Digest> {
let mut result = HashSet::new();
self.reveal_sets(target, &HashSet::new(), &mut result);
result
}
fn contains_all(&self, target: &HashSet<Digest>) -> bool {
let mut target = target.clone();
self.remove_all_found(&mut target);
target.is_empty()
}
fn reveal_sets(
&self,
target: &HashSet<Digest>,
current: &HashSet<Digest>,
result: &mut HashSet<Digest>,
) {
let mut current = current.clone();
current.insert(self.digest());
if target.contains(&self.digest()) {
result.extend(current.iter().cloned());
}
match self.case() {
EnvelopeCase::Node { subject, assertions, .. } => {
subject.reveal_sets(target, ¤t, result);
for assertion in assertions {
assertion.reveal_sets(target, ¤t, result);
}
}
EnvelopeCase::Wrapped { envelope, .. } => {
envelope.reveal_sets(target, ¤t, result);
}
EnvelopeCase::Assertion(assertion) => {
assertion.predicate().reveal_sets(target, ¤t, result);
assertion.object().reveal_sets(target, ¤t, result);
}
_ => {}
}
}
fn remove_all_found(&self, target: &mut HashSet<Digest>) {
if target.contains(&self.digest()) {
target.remove(&self.digest());
}
if target.is_empty() {
return;
}
match self.case() {
EnvelopeCase::Node { subject, assertions, .. } => {
subject.remove_all_found(target);
for assertion in assertions {
assertion.remove_all_found(target);
}
}
EnvelopeCase::Wrapped { envelope, .. } => {
envelope.remove_all_found(target);
}
EnvelopeCase::Assertion(assertion) => {
assertion.predicate().remove_all_found(target);
assertion.object().remove_all_found(target);
}
_ => {}
}
}
}