This library implements the cryptographic primitives necessary for WNFS to prove that its writes were valid in a way that's verifyable by third parties without read access.
Specifically, it implements 2048-bit RSA accumulators and the PoKE* and PoKCR algorithms from the paper "Batching Techniques for Accumulators with Applications to IOPs and Stateless Blockchains", as well as some WNFS-specific interfaces and serialized representations for them.
RSA accumulators require a trusted setup. Whoever has access to the trusted setup can create arbitrary valid proofs, which would in practice let malicious actors who've only been given partial access to a WNFS access to the rest of the file system. For this reason the trusted setup is run once upon creation of a new WNFS by the root author. The root author is naturally incentivized to throw away the toxic waste from the trusted setup.
```rust use wnfsnameaccumulator::{AccumulatorSetup, BatchedProofPart, BatchedProofVerification, Name, NameSegment}; use rand::threadrng;
// Run the trutsed setup. let rng = &mut thread_rng(); let setup = &AccumulatorSetup::trusted(rng);
// We want to prove the names for two files at // /Docs/Note and /Pics/Image respectively let mut namenote = Name::empty(setup); let mut nameimage = Name::empty(setup);
// Each segment is represented by a random 256-bit prime number let rootdirsegment = NameSegment::new(rng); let docsdirsegment = NameSegment::new(rng); let picsdirsegment = NameSegment::new(rng); let notefilesegment = NameSegment::new(rng); let imagefilesegment = NameSegment::new(rng);
namenote.addsegments([rootdirsegment.clone(), docsdirsegment, notefilesegment]); nameimage.addsegments([rootdirsegment, picsdirsegment, imagefilesegment]);
// We can collapse these arrays of primes that represent paths into 2048-bit RSA accumulators
// with a proof that they were derived from the same "base" name, in this case the Name::empty
above.
let (accumnote, proofnote) = namenote.asprovenaccumulator(setup);
let (accumimage, proofimage) = nameimage.asprovenaccumulator(setup);
// Knowing the proofs, we can batch at least parts of the proofs together. // This results in a single 2048-bit batched proof part and ~17-20 bytes of unbatched proof per element. let mut batchedproof = BatchedProofPart::new(); batchedproof.add(&proofnote); batchedproof.add(&proof_image);
// Without read access, but given the accumulated base name and the proofs, // we can verify that the accumulated names are related to the same base name. let namebase = Name::empty(setup).asaccumulator(setup).clone(); let mut verification = BatchedProofVerification::new(setup); verification.add(&namebase, &accumnote, &proofnote.part)?; verification.add(&namebase, &accumimage, &proofimage.part)?; verification.verify(&batched_proof)?; ```