Skip to content

Commit 5a432ce

Browse files
schomatisdignifiedquire
authored andcommitted
feat(storage-proofs): test Feistel permutation for collisions
1 parent d98069d commit 5a432ce

File tree

1 file changed

+40
-1
lines changed

1 file changed

+40
-1
lines changed

storage-proofs/src/zigzag_graph.rs

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -419,7 +419,7 @@ where
419419
mod tests {
420420
use super::*;
421421

422-
use std::collections::HashMap;
422+
use std::collections::{HashMap, HashSet};
423423

424424
use crate::drgraph::new_seed;
425425
use crate::hasher::{Blake2sHasher, PedersenHasher, Sha256Hasher};
@@ -542,4 +542,43 @@ mod tests {
542542
let parents_cache_lock = zigzag_graph.parents_cache.read().unwrap();
543543
(*parents_cache_lock)[zigzag_graph.get_cache_index()].len()
544544
}
545+
546+
// Test that 3 (or more) rounds of the Feistel cipher can be used
547+
// as a pseudorandom permutation, that is, each input will be mapped
548+
// to a unique output (and though not test here, since the cipher
549+
// is symmetric, the decryption rounds also work as the inverse
550+
// permutation), for more details see:
551+
// https://en.wikipedia.org/wiki/Feistel_cipher#Theoretical_work.
552+
#[test]
553+
fn test_shuffle() {
554+
let n = 2_u64.pow(10);
555+
let d = DEFAULT_EXPANSION_DEGREE as u64;
556+
// Use a relatively small value of `n` as Feistel is expensive (but big
557+
// enough that `n >> d`).
558+
559+
let mut shuffled: HashSet<u64> = HashSet::with_capacity((n * d) as usize);
560+
561+
let feistel_keys = &[1, 2, 3, 4];
562+
let feistel_precomputed = feistel::precompute((n * d) as feistel::Index);
563+
564+
for i in 0..n {
565+
for k in 0..d {
566+
let permuted =
567+
feistel::permute(n * d, i * d + k, feistel_keys, feistel_precomputed);
568+
569+
// Since the permutation implies a one-to-one correspondence,
570+
// traversing the entire input space should generate the entire
571+
// output space (in `shuffled`) without repetitions (since a duplicate
572+
// output would imply there is another output that wasn't generated
573+
// and the permutation would be incomplete).
574+
assert!(shuffled.insert(permuted));
575+
}
576+
}
577+
578+
// Actually implied by the previous `assert!` this is left in place as an
579+
// extra safety check that indeed the permutation preserved all the output
580+
// space (of `n * d` nodes) without repetitions (which the `HashSet` would
581+
// have skipped as duplicates).
582+
assert_eq!(shuffled.len(), (n * d) as usize);
583+
}
545584
}

0 commit comments

Comments
 (0)