Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: More reliably cache NameAccumulator modexps #326

Merged
merged 6 commits into from
Aug 17, 2023
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
59 changes: 16 additions & 43 deletions wnfs-nameaccumulator/src/name.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,10 @@ const L_HASH_DSI: &str = "wnfs/PoKE*/l 128-bit hash derivation";
/// However, these names are based on RSA accumulators to make it possible
/// to prove a relationship between two names, e.g a file being contained in
/// a sub-directory of a directory while leaking as little information as possible.
#[derive(Clone, Debug, Eq)]
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct Name {
relative_to: NameAccumulator,
segments: Vec<NameSegment>,
accumulated: OnceCell<(NameAccumulator, ElementsProof)>,
}

/// Represents a setup needed for RSA accumulator operation.
Expand All @@ -52,7 +51,7 @@ pub struct NameAccumulator {

/// A name accumluator segment. A name accumulator commits to a set of these.
/// They are represented as 256-bit prime numbers.
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord)]
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct NameSegment(
/// Invariant: Must be a 256-bit prime
BigUint,
Expand Down Expand Up @@ -116,7 +115,6 @@ impl Name {
Self {
relative_to,
segments: segments.into_iter().collect(),
accumulated: OnceCell::new(),
}
}

Expand All @@ -129,7 +127,6 @@ impl Name {
/// Remove the last name segment, if possible.
pub fn up(&mut self) {
self.segments.pop();
self.accumulated = OnceCell::new();
}

/// Return the parent name, if possible.
Expand All @@ -149,7 +146,6 @@ impl Name {

pub fn add_segments(&mut self, segments: impl IntoIterator<Item = NameSegment>) {
self.segments.extend(segments);
self.accumulated = OnceCell::new();
}

pub fn with_segments_added(&self, segments: impl IntoIterator<Item = NameSegment>) -> Self {
Expand All @@ -163,20 +159,18 @@ impl Name {
/// this name is relative to.
///
/// This proof process is memoized. Running it twice won't duplicate work.
pub fn as_proven_accumulator(
pub fn into_proven_accumulator(
&self,
setup: &AccumulatorSetup,
) -> &(NameAccumulator, ElementsProof) {
self.accumulated.get_or_init(|| {
let mut name = self.relative_to.clone();
let proof = name.add(self.segments.iter(), setup);
(name, proof)
})
) -> (NameAccumulator, ElementsProof) {
let mut name = self.relative_to.clone();
let proof = name.add(self.segments.iter(), setup);
(name, proof)
}

/// Return what name accumulator this name commits to.
pub fn as_accumulator(&self, setup: &AccumulatorSetup) -> &NameAccumulator {
&self.as_proven_accumulator(setup).0
pub fn into_accumulator(&self, setup: &AccumulatorSetup) -> NameAccumulator {
self.into_proven_accumulator(setup).0
}
}

Expand Down Expand Up @@ -498,27 +492,6 @@ impl Serialize for UnbatchableProofPart {
}
}

impl PartialEq for Name {
fn eq(&self, other: &Self) -> bool {
let left = self
.accumulated
.get()
.map(|x| &x.0)
.or(self.segments.is_empty().then_some(&self.relative_to));
let right = other
.accumulated
.get()
.map(|x| &x.0)
.or(other.segments.is_empty().then_some(&other.relative_to));

if let (Some(left), Some(right)) = (left, right) {
return left == right;
}

self.relative_to == other.relative_to && self.segments == other.segments
}
}

impl PartialEq for NameAccumulator {
fn eq(&self, other: &Self) -> bool {
self.state == other.state
Expand Down Expand Up @@ -690,17 +663,17 @@ mod tests {
]);
name_image.add_segments([root_dir_segment, pics_dir_segment, image_file_segment]);

let (accum_note, proof_note) = name_note.as_proven_accumulator(setup);
let (accum_image, proof_image) = name_image.as_proven_accumulator(setup);
let (accum_note, proof_note) = name_note.into_proven_accumulator(setup);
let (accum_image, proof_image) = name_image.into_proven_accumulator(setup);

let mut batched_proof = BatchedProofPart::new();
batched_proof.add(proof_note, setup);
batched_proof.add(proof_image, setup);
batched_proof.add(&proof_note, setup);
batched_proof.add(&proof_image, setup);

let name_base = Name::empty(setup).as_accumulator(setup).clone();
let name_base = Name::empty(setup).into_accumulator(setup);
let mut verification = BatchedProofVerification::new(setup);
verification.add(&name_base, accum_note, &proof_note.part)?;
verification.add(&name_base, accum_image, &proof_image.part)?;
verification.add(&name_base, &accum_note, &proof_note.part)?;
verification.add(&name_base, &accum_image, &proof_image.part)?;
verification.verify(&batched_proof)?;

Ok(())
Expand Down
1 change: 1 addition & 0 deletions wnfs/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ libipld-core = { version = "0.16" }
multihash = "0.19"
once_cell = "1.16"
proptest = { version = "1.1", optional = true }
quick_cache = "0.3.0"
rand_core = "0.6"
semver = { version = "1.0", features = ["serde"] }
serde = { version = "1.0", features = ["rc"] }
Expand Down
3 changes: 1 addition & 2 deletions wnfs/examples/write_proofs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,8 +57,7 @@ async fn alice_actions(store: &impl BlockStore) -> Result<(Cid, AccessKey, NameA

let access_key = root_dir.as_node().store(forest, store, rng).await?;
let cid = forest.store(store).await?;
let setup = forest.get_accumulator_setup();
let allowed_name = root_dir.header.get_name().as_accumulator(setup).clone();
let allowed_name = forest.get_accumulated_name(&root_dir.header.get_name());

Ok((cid, access_key, allowed_name))
}
Expand Down
22 changes: 6 additions & 16 deletions wnfs/src/private/directory.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ use std::{
rc::Rc,
};
use wnfs_common::{utils::error, BlockStore, Metadata, PathNodes, PathNodesResult, CODEC_RAW};
use wnfs_nameaccumulator::{AccumulatorSetup, Name, NameSegment};
use wnfs_nameaccumulator::{Name, NameSegment};

//--------------------------------------------------------------------------------------------------
// Type Definitions
Expand Down Expand Up @@ -394,15 +394,6 @@ impl PrivateDirectory {
Ok(cloned)
}

/// Returns the private ref, if this directory has been `.store()`ed before.
pub(crate) fn derive_private_ref(&self, setup: &AccumulatorSetup) -> Option<PrivateRef> {
self.content.persisted_as.get().map(|content_cid| {
self.header
.derive_revision_ref(setup)
.into_private_ref(*content_cid)
})
}

/// This prepares this directory for key rotation, usually for moving or
/// copying the directory to some other place.
///
Expand Down Expand Up @@ -1259,8 +1250,7 @@ impl PrivateDirectory {
store: &impl BlockStore,
rng: &mut impl CryptoRngCore,
) -> Result<PrivateRef> {
let setup = &forest.get_accumulator_setup().clone();
let header_cid = self.header.store(store, setup).await?;
let header_cid = self.header.store(store, forest).await?;
let temporal_key = self.header.derive_temporal_key();
let name_with_revision = self.header.get_revision_name();

Expand All @@ -1270,12 +1260,12 @@ impl PrivateDirectory {
.await?;

forest
.put_encrypted(name_with_revision, [header_cid, content_cid], store)
.put_encrypted(&name_with_revision, [header_cid, content_cid], store)
.await?;

Ok(self
.header
.derive_revision_ref(setup)
.derive_revision_ref(forest)
.into_private_ref(content_cid))
}

Expand All @@ -1284,9 +1274,9 @@ impl PrivateDirectory {
serializable: PrivateDirectoryContentSerializable,
temporal_key: &TemporalKey,
cid: Cid,
forest: &impl PrivateForest,
store: &impl BlockStore,
parent_name: Option<Name>,
setup: &AccumulatorSetup,
) -> Result<Self> {
if serializable.version.major != 0 || serializable.version.minor != 2 {
bail!(FsError::UnexpectedVersion(serializable.version));
Expand All @@ -1309,9 +1299,9 @@ impl PrivateDirectory {
let header = PrivateNodeHeader::load(
&serializable.header_cid,
temporal_key,
forest,
store,
parent_name,
setup,
)
.await?;
Ok(Self { header, content })
Expand Down
30 changes: 8 additions & 22 deletions wnfs/src/private/file.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ use rand_core::CryptoRngCore;
use serde::{Deserialize, Serialize};
use std::{collections::BTreeSet, iter, rc::Rc};
use wnfs_common::{utils, BlockStore, Metadata, CODEC_RAW, MAX_BLOCK_SIZE};
use wnfs_nameaccumulator::{AccumulatorSetup, Name, NameAccumulator, NameSegment};
use wnfs_nameaccumulator::{Name, NameAccumulator, NameSegment};

//--------------------------------------------------------------------------------------------------
// Constants
Expand Down Expand Up @@ -531,9 +531,7 @@ impl PrivateFile {

Ok(FileContent::External {
key,
base_name: base_name
.as_accumulator(forest.get_accumulator_setup())
.clone(),
base_name: forest.get_accumulated_name(&base_name),
block_count,
block_content_size: MAX_BLOCK_CONTENT_SIZE,
})
Expand Down Expand Up @@ -588,9 +586,7 @@ impl PrivateFile {

Ok(FileContent::External {
key,
base_name: base_name
.as_accumulator(forest.get_accumulator_setup())
.clone(),
base_name: forest.get_accumulated_name(&base_name),
block_count: block_index,
block_content_size: MAX_BLOCK_CONTENT_SIZE,
})
Expand Down Expand Up @@ -696,15 +692,6 @@ impl PrivateFile {
Ok(cloned)
}

/// Returns the private ref, if this file has been `.store()`ed before.
pub(crate) fn derive_private_ref(&self, setup: &AccumulatorSetup) -> Option<PrivateRef> {
self.content.persisted_as.get().map(|content_cid| {
self.header
.derive_revision_ref(setup)
.into_private_ref(*content_cid)
})
}

/// This prepares this file for key rotation, usually for moving or
/// copying the file to some other place.
///
Expand Down Expand Up @@ -733,8 +720,7 @@ impl PrivateFile {
store: &impl BlockStore,
rng: &mut impl CryptoRngCore,
) -> Result<PrivateRef> {
let setup = &forest.get_accumulator_setup().clone();
let header_cid = self.header.store(store, setup).await?;
let header_cid = self.header.store(store, forest).await?;
let temporal_key = self.header.derive_temporal_key();
let snapshot_key = temporal_key.derive_snapshot_key();
let name_with_revision = self.header.get_revision_name();
Expand All @@ -745,12 +731,12 @@ impl PrivateFile {
.await?;

forest
.put_encrypted(name_with_revision, [header_cid, content_cid], store)
.put_encrypted(&name_with_revision, [header_cid, content_cid], store)
.await?;

Ok(self
.header
.derive_revision_ref(setup)
.derive_revision_ref(forest)
.into_private_ref(content_cid))
}

Expand All @@ -759,9 +745,9 @@ impl PrivateFile {
serializable: PrivateFileContentSerializable,
temporal_key: &TemporalKey,
cid: Cid,
forest: &impl PrivateForest,
store: &impl BlockStore,
parent_name: Option<Name>,
setup: &AccumulatorSetup,
) -> Result<Self> {
if serializable.version.major != 0 || serializable.version.minor != 2 {
bail!(FsError::UnexpectedVersion(serializable.version));
Expand All @@ -777,9 +763,9 @@ impl PrivateFile {
let header = PrivateNodeHeader::load(
&serializable.header_cid,
temporal_key,
forest,
store,
parent_name,
setup,
)
.await?;
Ok(Self { header, content })
Expand Down
Loading
Loading