Skip to content

Commit d4331d8

Browse files
perf(storage-proofs): optimize sdr replication
* perf(storage-proofs): improve thread handling during sdr encoding * feat(storage-proofs): implement updatable pedersen md hasher * perf(storage-proofs): column commitments in the background * feat(storage-proofs): improve memory usage * perf(storage-proofs): reduce allocations for expander parents * perf(storage-proofs): split column hashing * perf: build tree_d during encoding
1 parent 7e9c5de commit d4331d8

File tree

14 files changed

+286
-235
lines changed

14 files changed

+286
-235
lines changed

storage-proofs/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ log = "0.4.7"
4848
pretty_env_logger = "0.3.0"
4949
pretty_assertions = "0.6.1"
5050
crossbeam = "0.7.2"
51+
num_cpus = "1.10.1"
5152

5253
[features]
5354
default = []

storage-proofs/benches/encode.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ use storage_proofs::util::{data_at_node_offset, NODE_SIZE};
1515

1616
struct Pregenerated<H: 'static + Hasher> {
1717
data: Vec<u8>,
18-
parents: Vec<usize>,
18+
parents: Vec<u32>,
1919
replica_id: H::Domain,
2020
graph: StackedBucketGraph<H>,
2121
}
@@ -25,7 +25,7 @@ fn pregenerate_data<H: Hasher>(degree: usize) -> Pregenerated<H> {
2525
let data: Vec<u8> = (0..(degree + 1))
2626
.flat_map(|_| fr_into_bytes::<Bls12>(&rng.gen()))
2727
.collect();
28-
let parents: Vec<usize> = (0..degree).map(|pos| pos).collect();
28+
let parents: Vec<u32> = (0..degree as u32).map(|pos| pos).collect();
2929
let replica_id: H::Domain = rng.gen();
3030

3131
let graph = StackedBucketGraph::<H>::new_stacked(degree + 1, degree, 0, new_seed());
@@ -40,7 +40,7 @@ fn pregenerate_data<H: Hasher>(degree: usize) -> Pregenerated<H> {
4040

4141
fn encode_single_node<H: Hasher>(
4242
data: &mut [u8],
43-
parents: &[usize],
43+
parents: &[u32],
4444
replica_id: &H::Domain,
4545
node: usize,
4646
graph: &StackedBucketGraph<H>,

storage-proofs/benches/parents.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ fn pregenerate_graph<H: Hasher>(size: usize) -> StackedBucketGraph<H> {
4444
StackedBucketGraph::<H>::new_stacked(size, BASE_DEGREE, EXP_DEGREE, seed)
4545
}
4646

47-
fn parents_loop<H: Hasher, G: Graph<H>>(graph: &G, parents: &mut [usize]) {
47+
fn parents_loop<H: Hasher, G: Graph<H>>(graph: &G, parents: &mut [u32]) {
4848
(0..graph.size())
4949
.map(|node| graph.parents(node, parents))
5050
.collect()

storage-proofs/src/circuit/drgporep.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -186,14 +186,14 @@ where
186186

187187
let mut parents = vec![0; pub_params.graph.degree()];
188188
for challenge in challenges {
189-
let mut por_nodes = vec![*challenge];
189+
let mut por_nodes = vec![*challenge as u32];
190190
pub_params.graph.parents(*challenge, &mut parents);
191191
por_nodes.extend_from_slice(&parents);
192192

193193
for node in por_nodes {
194194
let por_pub_inputs = merklepor::PublicInputs {
195195
commitment: comm_r,
196-
challenge: node,
196+
challenge: node as usize,
197197
};
198198
let por_inputs = PoRCompound::<H>::generate_public_inputs(
199199
&por_pub_inputs,

storage-proofs/src/circuit/stacked/column.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ use crate::stacked::{Column as VanillaColumn, PublicParams};
99

1010
#[derive(Debug, Clone)]
1111
pub struct Column {
12-
index: Option<usize>,
12+
index: Option<u32>,
1313
rows: Vec<Option<Fr>>,
1414
}
1515

storage-proofs/src/circuit/stacked/proof.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -247,11 +247,12 @@ impl<'a, H: 'static + Hasher>
247247
graph.base_graph().parents(challenge, &mut drg_parents);
248248

249249
for parent in drg_parents.into_iter() {
250-
inputs.extend(generate_inclusion_inputs(parent));
250+
inputs.extend(generate_inclusion_inputs(parent as usize));
251251
}
252252

253253
// exp parents
254-
let exp_parents = graph.expanded_parents(challenge, |p| p.clone());
254+
let mut exp_parents = vec![0; graph.expansion_degree()];
255+
graph.expanded_parents(challenge, &mut exp_parents);
255256
for parent in exp_parents.into_iter() {
256257
inputs.extend(generate_inclusion_inputs(parent as usize));
257258
}

storage-proofs/src/crypto/pedersen.rs

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,44 @@ where
6565
x.into()
6666
}
6767

68+
#[derive(Debug, Clone)]
69+
pub struct Hasher {
70+
curr: [u8; 32],
71+
}
72+
73+
impl Hasher {
74+
pub fn new(data: &[u8]) -> Self {
75+
assert_eq!(data.len(), 32);
76+
let mut curr = [0u8; 32];
77+
curr.copy_from_slice(data);
78+
79+
Hasher { curr }
80+
}
81+
82+
pub fn update(&mut self, data: &[u8]) {
83+
assert_eq!(data.len(), 32);
84+
85+
let parts = [&self.curr, data];
86+
let data = Bits::new_many(parts.iter());
87+
let x = pedersen_compression_bits(data);
88+
89+
x.write_le(std::io::Cursor::new(&mut self.curr[..]))
90+
.expect("failed to write result");
91+
}
92+
93+
pub fn finalize_bytes(self) -> [u8; 32] {
94+
let Hasher { curr } = self;
95+
curr
96+
}
97+
98+
pub fn finalize(self) -> Fr {
99+
let frs =
100+
bytes_into_frs::<Bls12>(&self.curr).expect("pedersen must generate valid fr elements");
101+
assert_eq!(frs.len(), 1);
102+
frs[0]
103+
}
104+
}
105+
68106
/// Creates an iterator over the byte slices in little endian format.
69107
#[derive(Debug, Clone)]
70108
pub struct Bits<K: AsRef<[u8]>, S: Iterator<Item = K>> {
@@ -326,4 +364,26 @@ mod tests {
326364

327365
assert_eq!(bits, bits_collected);
328366
}
367+
368+
#[test]
369+
fn test_pedersen_hasher_update() {
370+
let rng = &mut XorShiftRng::from_seed([0x3dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
371+
372+
for _ in 2..5 {
373+
let x: Vec<Vec<u8>> = (0..5)
374+
.map(|_| (0..32).map(|_| rng.gen()).collect())
375+
.collect();
376+
let flat: Vec<u8> = x.iter().flatten().copied().collect();
377+
let hashed = pedersen_md_no_padding(&flat);
378+
379+
let mut hasher = Hasher::new(&x[0]);
380+
for k in 1..5 {
381+
hasher.update(&x[k]);
382+
}
383+
384+
let hasher_final = hasher.finalize();
385+
386+
assert_eq!(hashed, hasher_final);
387+
}
388+
}
329389
}

storage-proofs/src/drgporep.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,7 @@ impl<H: Hasher> DataProof<H> {
129129
}
130130
}
131131

132-
pub type ReplicaParents<H> = Vec<(usize, DataProof<H>)>;
132+
pub type ReplicaParents<H> = Vec<(u32, DataProof<H>)>;
133133

134134
#[derive(Default, Debug, Clone, Serialize, Deserialize)]
135135
pub struct Proof<H: Hasher> {
@@ -292,10 +292,10 @@ where
292292

293293
for p in &parents {
294294
replica_parentsi.push((*p, {
295-
let proof = tree_r.gen_proof(*p);
295+
let proof = tree_r.gen_proof(*p as usize);
296296
DataProof {
297297
proof: MerkleProof::new_from_proof(&proof),
298-
data: tree_r.read_at(*p),
298+
data: tree_r.read_at(*p as usize),
299299
}
300300
}));
301301
}
@@ -384,7 +384,7 @@ where
384384
}
385385

386386
for (parent_node, p) in &proof.replica_parents[i] {
387-
if !p.proof.validate(*parent_node) {
387+
if !p.proof.validate(*parent_node as usize) {
388388
return Ok(false);
389389
}
390390
}
@@ -717,7 +717,7 @@ mod tests {
717717
// Rotate the real parent proofs.
718718
let x = (i + 1) % real_parents[0].len();
719719
let j = real_parents[0][x].0;
720-
(*p, real_parents[0][j].1.clone())
720+
(*p, real_parents[0][j as usize].1.clone())
721721
})
722722
.collect::<Vec<_>>()];
723723

storage-proofs/src/drgraph.rs

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ pub trait Graph<H: Hasher>: ::std::fmt::Debug + Clone + PartialEq + Eq {
8484
///
8585
/// The `parents` parameter is used to store the result. This is done fore performance
8686
/// reasons, so that the vector can be allocated outside this call.
87-
fn parents(&self, node: usize, parents: &mut [usize]);
87+
fn parents(&self, node: usize, parents: &mut [u32]);
8888

8989
/// Returns the size of the graph (number of nodes).
9090
fn size(&self) -> usize;
@@ -101,7 +101,7 @@ pub trait Graph<H: Hasher>: ::std::fmt::Debug + Clone + PartialEq + Eq {
101101
&self,
102102
id: &H::Domain,
103103
node: usize,
104-
parents: &[usize],
104+
parents: &[u32],
105105
parents_data: &[u8],
106106
exp_parents_data: Option<&[u8]>,
107107
) -> Result<Self::Key>;
@@ -143,17 +143,17 @@ impl<H: Hasher> Graph<H> for BucketGraph<H> {
143143
&self,
144144
id: &H::Domain,
145145
node: usize,
146-
parents: &[usize],
146+
parents: &[u32],
147147
base_parents_data: &[u8],
148148
_exp_parents_data: Option<&[u8]>,
149149
) -> Result<Self::Key> {
150150
let mut hasher = Blake2s::new().hash_length(NODE_SIZE).to_state();
151151
hasher.update(AsRef::<[u8]>::as_ref(id));
152152

153153
// The hash is about the parents, hence skip if a node doesn't have any parents
154-
if node != parents[0] {
154+
if node != parents[0] as usize {
155155
for parent in parents.iter() {
156-
let offset = data_at_node_offset(*parent);
156+
let offset = data_at_node_offset(*parent as usize);
157157
hasher.update(&base_parents_data[offset..offset + NODE_SIZE]);
158158
}
159159
}
@@ -163,7 +163,7 @@ impl<H: Hasher> Graph<H> for BucketGraph<H> {
163163
}
164164

165165
#[inline]
166-
fn parents(&self, node: usize, parents: &mut [usize]) {
166+
fn parents(&self, node: usize, parents: &mut [u32]) {
167167
let m = self.degree();
168168

169169
match node {
@@ -198,15 +198,15 @@ impl<H: Hasher> Graph<H> for BucketGraph<H> {
198198

199199
// remove self references and replace with reference to previous node
200200
if out == node {
201-
*parent = node - 1;
201+
*parent = (node - 1) as u32;
202202
} else {
203203
assert!(out <= node);
204-
*parent = out;
204+
*parent = out as u32;
205205
}
206206
}
207207

208208
// Add the immediate predecessor as a parent to ensure unique topological ordering.
209-
parents[m_prime] = node - 1;
209+
parents[m_prime] = (node - 1) as u32;
210210
}
211211
}
212212
}
@@ -297,7 +297,7 @@ mod tests {
297297

298298
for parent in p1 {
299299
// TODO: fix me
300-
assert_ne!(i, parent, "self reference found");
300+
assert_ne!(i, parent as usize, "self reference found");
301301
}
302302
}
303303
}

storage-proofs/src/stacked/column.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,29 +7,29 @@ use crate::stacked::{column_proof::ColumnProof, hash::hash_single_column, params
77

88
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
99
pub struct Column<H: Hasher> {
10-
pub(crate) index: usize,
10+
pub(crate) index: u32,
1111
pub(crate) rows: Vec<H::Domain>,
1212
_h: PhantomData<H>,
1313
}
1414

1515
impl<H: Hasher> Column<H> {
16-
pub fn new(index: usize, rows: Vec<H::Domain>) -> Self {
16+
pub fn new(index: u32, rows: Vec<H::Domain>) -> Self {
1717
Column {
1818
index,
1919
rows,
2020
_h: PhantomData,
2121
}
2222
}
2323

24-
pub fn with_capacity(index: usize, capacity: usize) -> Self {
24+
pub fn with_capacity(index: u32, capacity: usize) -> Self {
2525
Column::new(index, Vec::with_capacity(capacity))
2626
}
2727

2828
pub fn rows(&self) -> &[H::Domain] {
2929
&self.rows
3030
}
3131

32-
pub fn index(&self) -> usize {
32+
pub fn index(&self) -> u32 {
3333
self.index
3434
}
3535

@@ -46,7 +46,7 @@ impl<H: Hasher> Column<H> {
4646

4747
/// Create a column proof for this column.
4848
pub fn into_proof(self, tree_c: &Tree<H>) -> ColumnProof<H> {
49-
let inclusion_proof = MerkleProof::new_from_proof(&tree_c.gen_proof(self.index()));
49+
let inclusion_proof = MerkleProof::new_from_proof(&tree_c.gen_proof(self.index() as usize));
5050
ColumnProof::<H>::from_column(self, inclusion_proof)
5151
}
5252
}

0 commit comments

Comments
 (0)