use curve25519_dalek::{ristretto::CompressedRistretto, RistrettoPoint, Scalar};
use ufotofu::sync::consumer::IntoVec;
use willow_encoding::sync::Encodable;
use crate::proto::{
data_model::{NamespaceId, Path, SubspaceId},
grouping::AreaSubspace,
};
type ReadCapability = super::meadowcap::McCapability;
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
pub struct PsiGroup(RistrettoPoint);
#[derive(Debug, thiserror::Error)]
#[error("Invalid Psi Group")]
pub struct InvalidPsiGroup;
impl PsiGroup {
pub fn from_bytes(bytes: [u8; 32]) -> Result<Self, InvalidPsiGroup> {
let compressed = CompressedRistretto(bytes);
let uncompressed = compressed.decompress().ok_or(InvalidPsiGroup)?;
Ok(Self(uncompressed))
}
pub fn to_bytes(self) -> [u8; 32] {
self.0.compress().0
}
}
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
pub struct PsiScalar(Scalar);
#[derive(Debug)]
pub struct PaiScheme;
impl PaiScheme {
pub fn hash_into_group(fragment: &Fragment) -> PsiGroup {
let encoded = {
let mut consumer = IntoVec::<u8>::new();
fragment
.encode(&mut consumer)
.expect("encoding not to fail");
consumer.into_vec()
};
let point = RistrettoPoint::hash_from_bytes::<sha2::Sha512>(&encoded);
PsiGroup(point)
}
pub fn get_scalar() -> PsiScalar {
PsiScalar(Scalar::random(&mut rand::thread_rng()))
}
pub fn scalar_mult(group: PsiGroup, scalar: PsiScalar) -> PsiGroup {
PsiGroup(group.0 * scalar.0)
}
pub fn is_group_equal(a: &PsiGroup, b: &PsiGroup) -> bool {
a == b
}
pub fn get_fragment_kit(cap: &ReadCapability) -> FragmentKit {
let granted_area = cap.granted_area();
let granted_namespace = cap.granted_namespace();
let granted_path = granted_area.path().clone();
match granted_area.subspace() {
AreaSubspace::Any => FragmentKit::Complete(*granted_namespace, granted_path),
AreaSubspace::Id(granted_subspace) => {
FragmentKit::Selective(*granted_namespace, *granted_subspace, granted_path)
}
}
}
}
#[derive(Debug, Clone)]
pub enum Fragment {
Pair(FragmentPair),
Triple(FragmentTriple),
}
impl Fragment {
pub fn into_parts(self) -> (NamespaceId, AreaSubspace, Path) {
match self {
Fragment::Pair((namespace_id, path)) => (namespace_id, AreaSubspace::Any, path),
Fragment::Triple((namespace_id, subspace_id, path)) => {
(namespace_id, AreaSubspace::Id(subspace_id), path)
}
}
}
}
pub type FragmentTriple = (NamespaceId, SubspaceId, Path);
pub type FragmentPair = (NamespaceId, Path);
#[derive(Debug, Clone, Copy)]
pub enum FragmentKind {
Primary,
Secondary,
}
impl FragmentKind {
pub fn is_secondary(&self) -> bool {
matches!(self, FragmentKind::Secondary)
}
}
#[derive(Debug, Clone)]
pub enum FragmentSet {
Complete(Vec<FragmentPair>),
Selective {
primary: Vec<FragmentTriple>,
secondary: Vec<FragmentPair>,
},
}
#[derive(Debug)]
pub enum FragmentKit {
Complete(NamespaceId, Path),
Selective(NamespaceId, SubspaceId, Path),
}
impl FragmentKit {
pub fn into_fragment_set(self) -> FragmentSet {
match self {
FragmentKit::Complete(namespace_id, path) => {
let pairs = path
.all_prefixes()
.map(|prefix| (namespace_id, prefix))
.collect();
FragmentSet::Complete(pairs)
}
FragmentKit::Selective(namespace_id, subspace_id, path) => {
let primary = path
.all_prefixes()
.map(|prefix| (namespace_id, subspace_id, prefix))
.collect();
let secondary = path
.all_prefixes()
.map(|prefix| (namespace_id, prefix))
.collect();
FragmentSet::Selective { primary, secondary }
}
}
}
}
use syncify::{syncify, syncify_replace};
#[syncify(encoding_sync)]
mod encoding {
#[syncify_replace(use ufotofu::sync::BulkConsumer;)]
use ufotofu::local_nb::BulkConsumer;
#[syncify_replace(use willow_encoding::sync::Encodable;)]
use willow_encoding::Encodable;
use super::*;
impl Encodable for Fragment {
async fn encode<Consumer>(&self, consumer: &mut Consumer) -> Result<(), Consumer::Error>
where
Consumer: BulkConsumer<Item = u8>,
{
match self {
Fragment::Pair((namespace_id, path)) => {
namespace_id.encode(consumer).await?;
path.encode(consumer).await?;
}
Fragment::Triple((namespace_id, subspace_id, path)) => {
namespace_id.encode(consumer).await?;
subspace_id.encode(consumer).await?;
path.encode(consumer).await?;
}
}
Ok(())
}
}
}