Skip to content

Commit 17fca25

Browse files
feat(storage-proofs): implement memory reduced stacked replication
1 parent f6de948 commit 17fca25

File tree

15 files changed

+486
-215
lines changed

15 files changed

+486
-215
lines changed

filecoin-proofs/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ rexpect = "0.3.0"
5353
[features]
5454
default = []
5555
cpu-profile = []
56-
heap-profile = []
56+
heap-profile = ["gperftools/heap"]
5757
simd = ["storage-proofs/simd"]
5858
asm = ["storage-proofs/asm"]
5959
gpu = ["storage-proofs/gpu", "bellperson/gpu", "fil-sapling-crypto/gpu", "phase21/gpu"]

storage-proofs/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ bench = false
1515
bitvec = "0.5"
1616
rand = "0.4"
1717
libc = "0.2"
18-
merkletree = "0.10"
18+
merkletree = "0.11"
1919
failure = "0.1"
2020
byteorder = "1"
2121
config = "0.9.3"

storage-proofs/src/circuit/pedersen.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -174,7 +174,8 @@ mod tests {
174174
assert_eq!(
175175
expected,
176176
out.get_value().unwrap(),
177-
"circuit and non circuit do not match"
177+
"circuit and non circuit do not match {} bytes",
178+
bytes
178179
);
179180
}
180181
}

storage-proofs/src/crypto/pedersen.rs

Lines changed: 252 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
use bitvec::{self, BitVec};
21
use ff::PrimeFieldRepr;
32
use fil_sapling_crypto::jubjub::JubjubBls12;
43
use fil_sapling_crypto::pedersen_hash::{pedersen_hash, Personalization};
@@ -20,64 +19,229 @@ pub const PEDERSEN_BLOCK_SIZE: usize = 256;
2019
pub const PEDERSEN_BLOCK_BYTES: usize = PEDERSEN_BLOCK_SIZE / 8;
2120

2221
pub fn pedersen(data: &[u8]) -> Fr {
23-
pedersen_hash::<Bls12, _>(
24-
Personalization::None,
25-
BitVec::<bitvec::LittleEndian, u8>::from(data)
26-
.iter()
27-
.take(data.len() * 8),
28-
&JJ_PARAMS,
29-
)
30-
.into_xy()
31-
.0
22+
pedersen_bits(Bits::new(data))
23+
}
24+
25+
pub fn pedersen_bits<'a, S: Iterator<Item = &'a [u8]>>(data: Bits<&'a [u8], S>) -> Fr {
26+
pedersen_hash::<Bls12, _>(Personalization::None, data, &JJ_PARAMS)
27+
.into_xy()
28+
.0
3229
}
3330

3431
/// Pedersen hashing for inputs that have length mulitple of the block size `256`. Based on pedersen hashes and a Merkle-Damgard construction.
3532
pub fn pedersen_md_no_padding(data: &[u8]) -> Fr {
36-
assert!(
37-
data.len() >= 2 * PEDERSEN_BLOCK_BYTES,
38-
"must be at least 2 block sizes long, got {}bits",
39-
data.len()
40-
);
41-
assert_eq!(
42-
data.len() % PEDERSEN_BLOCK_BYTES,
43-
0,
44-
"input must be a multiple of the blocksize"
45-
);
46-
let mut chunks = data.chunks(PEDERSEN_BLOCK_BYTES);
47-
let mut cur = Vec::with_capacity(2 * PEDERSEN_BLOCK_BYTES);
48-
cur.resize(PEDERSEN_BLOCK_BYTES, 0);
49-
cur[0..PEDERSEN_BLOCK_BYTES].copy_from_slice(chunks.nth(0).unwrap());
33+
pedersen_md_no_padding_bits(Bits::new(data))
34+
}
5035

51-
for block in chunks {
52-
cur.resize(2 * PEDERSEN_BLOCK_BYTES, 0);
53-
cur[PEDERSEN_BLOCK_BYTES..].copy_from_slice(block);
54-
pedersen_compression(&mut cur);
36+
pub fn pedersen_md_no_padding_bits<T: AsRef<[u8]>, S: Iterator<Item = T>>(
37+
mut data: Bits<T, S>,
38+
) -> Fr {
39+
let mut cur = Vec::with_capacity(PEDERSEN_BLOCK_SIZE);
40+
41+
// hash the first two blocks
42+
let first = pedersen_compression_bits(data.ref_take(2 * PEDERSEN_BLOCK_SIZE));
43+
first
44+
.write_le(&mut cur)
45+
.expect("failed to write result hash");
46+
47+
while !data.is_done() {
48+
let r = data.ref_take(PEDERSEN_BLOCK_SIZE);
49+
let x = pedersen_compression_bits(Bits::new(&cur).chain(r));
50+
51+
cur.truncate(0);
52+
x.write_le(&mut cur).expect("failed to write result hash");
5553
}
5654

57-
let frs = bytes_into_frs::<Bls12>(&cur[0..PEDERSEN_BLOCK_BYTES])
58-
.expect("pedersen must generate valid fr elements");
55+
let frs = bytes_into_frs::<Bls12>(&cur).expect("pedersen must generate valid fr elements");
5956
assert_eq!(frs.len(), 1);
6057
frs[0]
6158
}
6259

63-
pub fn pedersen_compression(bytes: &mut Vec<u8>) {
64-
let bits = BitVec::<bitvec::LittleEndian, u8>::from(&bytes[..]);
65-
let (x, _) = pedersen_hash::<Bls12, _>(
66-
Personalization::None,
67-
bits.iter().take(bytes.len() * 8),
68-
&JJ_PARAMS,
69-
)
70-
.into_xy();
71-
let x: FrRepr = x.into();
60+
fn pedersen_compression_bits<T>(bits: T) -> FrRepr
61+
where
62+
T: IntoIterator<Item = bool>,
63+
{
64+
let (x, _) = pedersen_hash::<Bls12, _>(Personalization::None, bits, &JJ_PARAMS).into_xy();
65+
x.into()
66+
}
67+
68+
/// Creates an iterator over the byte slices in little endian format.
69+
#[derive(Debug, Clone)]
70+
pub struct Bits<K: AsRef<[u8]>, S: Iterator<Item = K>> {
71+
/// The individual parts that make up the data that is being iterated over.
72+
parts: ManyOrSingle<K, S>,
73+
/// How many bytes we are into the `current_part`
74+
position_byte: usize,
75+
/// How many bits we are into the `current_byte`.
76+
position_bit: u8,
77+
/// The current part we are reading from.
78+
current_part: Option<K>,
79+
/// Track the first iteration.
80+
first: bool,
81+
/// Are we done yet?
82+
done: bool,
83+
}
84+
85+
/// Abstraction over either an iterator or a single element.
86+
#[derive(Debug, Clone)]
87+
enum ManyOrSingle<T, S = <Vec<T> as IntoIterator>::IntoIter>
88+
where
89+
S: Iterator<Item = T>,
90+
{
91+
Many(S),
92+
Single(Option<T>),
93+
}
94+
95+
impl<T: AsRef<[u8]>> Bits<T, <Vec<T> as IntoIterator>::IntoIter> {
96+
pub fn new(parts: T) -> Self {
97+
Bits {
98+
parts: ManyOrSingle::<T, <Vec<T> as IntoIterator>::IntoIter>::Single(Some(parts)),
99+
position_byte: 0,
100+
position_bit: 0,
101+
current_part: None,
102+
first: true,
103+
done: false,
104+
}
105+
}
106+
}
107+
108+
impl<T: AsRef<[u8]>, S: Iterator<Item = T>> Bits<T, S> {
109+
pub fn new_many(parts: S) -> Self {
110+
Bits {
111+
parts: ManyOrSingle::Many(parts),
112+
position_byte: 0,
113+
position_bit: 0,
114+
current_part: None,
115+
first: true,
116+
done: false,
117+
}
118+
}
119+
120+
pub fn is_done(&self) -> bool {
121+
self.done
122+
}
123+
124+
fn inc_part(&mut self) {
125+
self.current_part = match self.parts {
126+
ManyOrSingle::Many(ref mut parts) => {
127+
if self.first {
128+
self.first = false;
129+
}
130+
parts.next()
131+
}
132+
ManyOrSingle::Single(ref mut part) => {
133+
if self.first {
134+
self.first = false;
135+
part.take()
136+
} else {
137+
None
138+
}
139+
}
140+
}
141+
}
142+
143+
/// Increments the inner positions by 1 bit.
144+
fn inc(&mut self) {
145+
if self.position_bit < 7 {
146+
self.position_bit += 1;
147+
return;
148+
}
149+
150+
self.position_bit = 0;
151+
if let Some(ref part) = self.current_part {
152+
if self.position_byte + 1 < part.as_ref().len() {
153+
self.position_byte += 1;
154+
return;
155+
}
156+
}
157+
158+
self.inc_part();
159+
self.position_byte = 0;
160+
self.done = self.current_part.is_none();
161+
}
162+
163+
fn ref_take(&mut self, take: usize) -> BitsTake<'_, T, S> {
164+
BitsTake::new(self, take)
165+
}
166+
}
167+
168+
#[derive(Debug)]
169+
struct BitsTake<'a, T: AsRef<[u8]>, S: Iterator<Item = T>> {
170+
iter: &'a mut Bits<T, S>,
171+
take: usize,
172+
}
173+
174+
impl<'a, T: AsRef<[u8]>, S: Iterator<Item = T>> BitsTake<'a, T, S> {
175+
pub fn new(iter: &'a mut Bits<T, S>, take: usize) -> Self {
176+
BitsTake { iter, take }
177+
}
178+
}
179+
180+
impl<'a, T: AsRef<[u8]>, S: Iterator<Item = T> + std::iter::FusedIterator> std::iter::FusedIterator
181+
for BitsTake<'a, T, S>
182+
{
183+
}
184+
185+
impl<'a, T: AsRef<[u8]>, S: Iterator<Item = T>> Iterator for BitsTake<'a, T, S> {
186+
type Item = bool;
187+
188+
fn next(&mut self) -> Option<Self::Item> {
189+
if self.take == 0 {
190+
return None;
191+
}
192+
193+
self.take -= 1;
194+
self.iter.next()
195+
}
196+
}
197+
198+
impl<T: AsRef<[u8]>, S: Iterator<Item = T> + std::iter::FusedIterator> std::iter::FusedIterator
199+
for Bits<T, S>
200+
{
201+
}
202+
203+
impl<T: AsRef<[u8]>, S: Iterator<Item = T>> Iterator for Bits<T, S> {
204+
type Item = bool;
72205

73-
bytes.truncate(0);
74-
x.write_le(bytes).expect("failed to write result hash");
206+
fn next(&mut self) -> Option<Self::Item> {
207+
if self.done {
208+
return None;
209+
}
210+
211+
if self.first {
212+
// first time
213+
self.inc_part();
214+
}
215+
216+
let byte = match self.current_part {
217+
Some(ref part) => part.as_ref()[self.position_byte],
218+
None => {
219+
self.done = true;
220+
return None;
221+
}
222+
};
223+
224+
let res = (byte >> self.position_bit) & 1u8 == 1u8;
225+
self.inc();
226+
227+
Some(res)
228+
}
229+
230+
// optimized nth method so we can use it to skip forward easily
231+
fn nth(&mut self, n: usize) -> Option<Self::Item> {
232+
for _ in 0..n {
233+
// TODO: implement optimized inc for n bits.
234+
self.inc();
235+
}
236+
self.next()
237+
}
75238
}
76239

77240
#[cfg(test)]
78241
mod tests {
79242
use super::*;
80243
use crate::util::bytes_into_bits;
244+
use bitvec::{self, BitVec};
81245
use ff::Field;
82246
use paired::bls12_381::Fr;
83247
use rand::{Rng, SeedableRng, XorShiftRng};
@@ -98,10 +262,12 @@ mod tests {
98262

99263
#[test]
100264
fn test_pedersen_compression() {
101-
let bytes = b"some bytes";
102-
let mut data = vec![0; bytes.len()];
103-
data.copy_from_slice(&bytes[..]);
104-
pedersen_compression(&mut data);
265+
let bytes = Bits::new(b"some bytes");
266+
267+
let x = pedersen_compression_bits(bytes);
268+
let mut data = Vec::new();
269+
x.write_le(&mut data).unwrap();
270+
105271
let expected = vec![
106272
237, 70, 41, 231, 39, 180, 131, 120, 36, 36, 119, 199, 200, 225, 153, 242, 106, 116,
107273
70, 9, 12, 249, 169, 84, 105, 38, 225, 115, 165, 188, 98, 25,
@@ -119,4 +285,45 @@ mod tests {
119285
assert_ne!(hashed, Fr::zero());
120286
}
121287
}
288+
289+
#[test]
290+
fn test_bits_collect() {
291+
let bytes = b"hello";
292+
let bits = bytes_into_bits(bytes);
293+
294+
let bits_iter = Bits::new(bytes);
295+
let bits_iter_collected: Vec<bool> = bits_iter.collect();
296+
297+
assert_eq!(bits, bits_iter_collected);
298+
299+
let bytes = b"hello world these are some bytes";
300+
let bits = bytes_into_bits(bytes);
301+
302+
let parts: Vec<&[u8]> = vec![b"hello ", b"world", b" these are some bytes"];
303+
let bits_iter = Bits::new_many(parts.into_iter());
304+
305+
let bits_iter_collected: Vec<bool> = bits_iter.collect();
306+
307+
assert_eq!(bits, bits_iter_collected);
308+
}
309+
310+
#[test]
311+
fn test_bits_take() {
312+
let bytes = b"hello world these are some bytes";
313+
let bits = bytes_into_bits(bytes);
314+
315+
let parts: Vec<&[u8]> = vec![b"hello ", b"world", b" these are some bytes"];
316+
let mut bits_iter = Bits::new_many(parts.into_iter());
317+
318+
let bits_collected: Vec<bool> = vec![
319+
bits_iter.ref_take(8).collect::<Vec<bool>>(),
320+
bits_iter.ref_take(8).collect::<Vec<bool>>(),
321+
bits_iter.ref_take(bits.len() - 16).collect::<Vec<bool>>(),
322+
]
323+
.into_iter()
324+
.flatten()
325+
.collect();
326+
327+
assert_eq!(bits, bits_collected);
328+
}
122329
}

storage-proofs/src/drgraph.rs

Lines changed: 1 addition & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ use crate::error::*;
99
use crate::fr32::bytes_into_fr_repr_safe;
1010
use crate::hasher::pedersen::PedersenHasher;
1111
use crate::hasher::{Domain, Hasher};
12-
use crate::merkle::{MerkleStore, MerkleTree};
12+
use crate::merkle::MerkleTree;
1313
use crate::parameter_cache::ParameterSetMetadata;
1414
use crate::util::{data_at_node, data_at_node_offset, NODE_SIZE};
1515
use merkletree::merkle::FromIndexedParallelIterator;
@@ -71,16 +71,6 @@ pub trait Graph<H: Hasher>: ::std::fmt::Debug + Clone + PartialEq + Eq {
7171
}
7272
}
7373

74-
/// Builds a merkle tree based on the given leaves store.
75-
// FIXME: Add the parallel case (if it's worth it).
76-
fn merkle_tree_from_leaves(
77-
&self,
78-
leaves: MerkleStore<H::Domain>,
79-
leafs_number: usize,
80-
) -> Result<MerkleTree<H::Domain, H::Function>> {
81-
Ok(MerkleTree::from_leaves_store(leaves, leafs_number))
82-
}
83-
8474
/// Returns the merkle tree depth.
8575
fn merkle_tree_depth(&self) -> u64 {
8676
graph_height(self.size()) as u64

0 commit comments

Comments
 (0)