1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
use std::cmp;
use std::marker::PhantomData;

use bitvec::{self, BitVec};
use byteorder::{ByteOrder, LittleEndian};
use ff::{Field, PrimeField, ScalarEngine};
use itertools::Itertools;
use paired::bls12_381::{Bls12, Fr, FrRepr};
use paired::Engine;
use serde::de::Deserialize;
use serde::ser::Serialize;

use crate::error::{Error, Result};
use crate::fr32::fr_into_bytes;
use crate::hasher::{Domain, HashFunction, Hasher};
use crate::merkle::MerkleTree;
use crate::parameter_cache::ParameterSetMetadata;
use crate::porc::{self, PoRC};
use crate::proof::{NoRequirements, ProofScheme};
use crate::vdf::Vdf;

#[derive(Clone, Debug)]
pub struct SetupParams<T: Domain, V: Vdf<T>> {
    /// The number of challenges to be asked at each iteration.
    pub challenge_count: usize,
    /// Size of a sealed sector in bytes.
    pub sector_size: usize,
    /// Number of times we repeat an online Proof-of-Replication in one single PoSt.
    pub post_epochs: usize,
    pub setup_params_vdf: V::SetupParams,
    /// The number of sectors that are proven over.
    pub sectors_count: usize,
}

#[derive(Clone, Debug)]
pub struct PublicParams<T: Domain, V: Vdf<T>> {
    /// The number of challenges to be asked at each iteration.
    pub challenge_count: usize,
    /// Size of a sealed sector in bytes.
    pub sector_size: usize,
    /// Number of times we repeat an online Proof-of-Replication in one single PoSt.
    pub post_epochs: usize,
    pub pub_params_vdf: V::PublicParams,
    /// The number of leaves in one sector.
    pub leaves: usize,
    /// The number of sectors that are proven over.
    pub sectors_count: usize,
    /// The number of bits per challenge (the length of a merkle path)
    pub challenge_bits: usize,
    pub seed_bits: usize,
}

impl<T: Domain, V: Vdf<T>> ParameterSetMetadata for PublicParams<T, V> {
    fn identifier(&self) -> String {
        format!(
            "vdf_post::PublicParams{{challenge_count: {}, sector_size: {}, post_epochs: {}, pub_params_vdf: FIXME, leaves: {}, sectors_count: {}}}",
            self.challenge_count, self.sector_size, self.post_epochs,
            //self.pub_params_vdf.parameter_set_identifier(), // FIXME: implement
            self.leaves, self.sectors_count
        )
    }

    fn sector_size(&self) -> u64 {
        self.sector_size as u64
    }
}

#[derive(Clone, Debug)]
pub struct PublicInputs<T: Domain> {
    /// The root hash of the merkle tree of each sealed sector.
    pub commitments: Vec<T>,
    /// The initial set of challenges. Must be of length `challenge_count`.
    pub challenge_seed: T,
    pub faults: Vec<u64>, // TODO: Actually use the faults once faults are designed.
}

#[derive(Clone, Debug)]
pub struct PrivateInputs<'a, H: 'a + Hasher> {
    pub trees: &'a [&'a MerkleTree<H::Domain, H::Function>],
    _h: PhantomData<H>,
}

impl<'a, H: 'a + Hasher> PrivateInputs<'a, H> {
    pub fn new(trees: &'a [&'a MerkleTree<H::Domain, H::Function>]) -> Self {
        PrivateInputs {
            trees,
            _h: PhantomData,
        }
    }
}

pub fn compute_root_commitment<T: Domain>(commitments: &[T]) -> T {
    // NOTE: We're just returning the first commitment so we have a consistent, valid value.
    // In reality, we will need some kind of vector commitment, but we haven't committed to what yet.
    // This is here so we can get all the plumbing right without having to.
    commitments[0]
}

/// VDF-PoSt
/// This is one construction of a Proof-of-Spacetime.
/// It currently only supports proving over a single sector.
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct Proof<'a, H: Hasher + 'a, V: Vdf<H::Domain>> {
    /// `post_iteration` online Proof-of-Replication proofs.
    #[serde(bound(
        serialize = "V::Proof: Serialize",
        deserialize = "V::Proof: Deserialize<'de>"
    ))]
    pub porep_proofs: Vec<<PoRC<'a, H> as ProofScheme<'a>>::Proof>,
    /// `post_epochs - 1` VDF proofs
    #[serde(bound(
        serialize = "V::Proof: Serialize",
        deserialize = "V::Proof: Deserialize<'de>"
    ))]
    pub vdf_proofs: Vec<V::Proof>,
    #[serde(bound(
        serialize = "H::Domain: Serialize",
        deserialize = "H::Domain: Deserialize<'de>"
    ))]
    pub ys: Vec<H::Domain>,
    pub challenges: Vec<Vec<usize>>,
    pub challenged_sectors: Vec<Vec<usize>>,
    _v: PhantomData<V>,
}

#[derive(Clone, Debug)]
pub struct VDFPoSt<H: Hasher, V: Vdf<H::Domain>> {
    _t: PhantomData<H>,
    _v: PhantomData<V>,
}

impl<'a, H: Hasher + 'a, V: Vdf<H::Domain>> ProofScheme<'a> for VDFPoSt<H, V> {
    type PublicParams = PublicParams<H::Domain, V>;
    type SetupParams = SetupParams<H::Domain, V>;
    type PublicInputs = PublicInputs<H::Domain>;
    type PrivateInputs = PrivateInputs<'a, H>;
    type Proof = Proof<'a, H, V>;
    type Requirements = NoRequirements;

    fn setup(sp: &Self::SetupParams) -> Result<Self::PublicParams> {
        // Sector sizes which are powers of two have the form 100000 (i.e. leading one and all zeroes after).
        let sector_size = sp.sector_size;
        assert_eq!(
            sector_size.count_ones(),
            1,
            "sector size must be a power of 2"
        );
        // Assuming well-formed (power of two) sector size, log2(sector_size) is given by number of trailing zeroes.
        let log2 = sector_size.trailing_zeros();
        let leaves = sector_size / 32;
        let challenge_bits = (log2 - 5) as usize;
        assert_eq!(
            2u64.pow(challenge_bits as u32),
            leaves as u64,
            "sanity check"
        );

        Ok(PublicParams {
            challenge_count: sp.challenge_count,
            sector_size: sp.sector_size,
            post_epochs: sp.post_epochs,
            pub_params_vdf: V::setup(&sp.setup_params_vdf)?,
            leaves,
            sectors_count: sp.sectors_count,
            challenge_bits,
            seed_bits: 255,
        })
    }

    fn prove<'b>(
        pub_params: &'b Self::PublicParams,
        pub_inputs: &'b Self::PublicInputs,
        priv_inputs: &'b Self::PrivateInputs,
    ) -> Result<Self::Proof> {
        if priv_inputs.trees.len() != pub_params.sectors_count {
            return Err(Error::MalformedInput);
        }

        let challenge_count = pub_params.challenge_count;
        let post_epochs = pub_params.post_epochs;

        let pub_params_porep = porc::PublicParams {
            leaves: pub_params.leaves,
            sectors_count: pub_params.sectors_count,
            challenges_count: pub_params.challenge_count,
        };

        let mut porep_proofs = Vec::with_capacity(post_epochs);
        let mut vdf_proofs = Vec::with_capacity(post_epochs - 1);
        let mut ys = Vec::with_capacity(post_epochs - 1);
        let mut challenges_vec = Vec::with_capacity(post_epochs);
        let mut challenged_sectors_vec = Vec::with_capacity(post_epochs);

        let mut challenge_stream = ChallengeStream::<H, V>::new(pub_params);

        {
            let mut mix = pub_inputs.challenge_seed;
            let mut i = 0;

            while let Some((challenges, challenged_sectors)) = challenge_stream.next(mix) {
                assert!(
                    challenges.len() == challenge_count,
                    format!(
                        "expected {} challenges, but {} were mixed.",
                        challenge_count,
                        challenges.len()
                    )
                );
                challenges_vec.push(challenges.clone());
                challenged_sectors_vec.push(challenged_sectors.clone());

                let pub_inputs_porep = porc::PublicInputs {
                    challenges: &challenges,
                    challenged_sectors: &challenged_sectors,
                    commitments: &pub_inputs.commitments,
                };

                let priv_inputs_porep = porc::PrivateInputs {
                    trees: priv_inputs.trees,
                };

                let proof = PoRC::prove(&pub_params_porep, &pub_inputs_porep, &priv_inputs_porep)?;
                porep_proofs.push(proof.clone());

                // Skip last VDF evaluation.
                if i + 1 < post_epochs {
                    let x = extract_vdf_input::<H>(&proof);
                    let (y, vdf_proof) = V::eval(&pub_params.pub_params_vdf, &x)?;

                    ys.push(y);
                    vdf_proofs.push(vdf_proof);
                    mix = y;
                } else {
                    break;
                }
                i += 1;
            }
        }

        assert_eq!(porep_proofs.len(), pub_params.post_epochs);
        assert_eq!(ys.len(), pub_params.post_epochs - 1);
        assert_eq!(vdf_proofs.len(), pub_params.post_epochs - 1);
        assert_eq!(challenges_vec.len(), pub_params.post_epochs);
        assert_eq!(challenged_sectors_vec.len(), pub_params.post_epochs);

        Ok(Proof {
            porep_proofs,
            ys,
            vdf_proofs,
            challenges: challenges_vec,
            challenged_sectors: challenged_sectors_vec,
            _v: PhantomData,
        })
    }

    fn verify(
        pub_params: &Self::PublicParams,
        pub_inputs: &Self::PublicInputs,
        proof: &Self::Proof,
    ) -> Result<bool> {
        let post_epochs = pub_params.post_epochs;

        let mut mix = pub_inputs.challenge_seed;
        let mut challenge_stream = ChallengeStream::<H, V>::new(pub_params);

        let mut i = 0;
        while let Some((challenges, challenged_sectors)) = challenge_stream.next(mix) {
            if i + 1 >= post_epochs {
                break;
            }

            // VDF Output Verification
            {
                if !V::verify(
                    &pub_params.pub_params_vdf,
                    &extract_vdf_input::<H>(&proof.porep_proofs[i]),
                    &proof.vdf_proofs[i],
                )? {
                    return Ok(false);
                }
            }

            // Explicit challenge verification is not needed here, since we generate the challenges ourselves
            // and provide them as input to PoRC::verify below.

            // TODO: Root Commitment verification.
            // FIXME: Skip for now, but this is an absence that needs to be addressed once we have a vector commitment strategy.

            // Online PoRep Verification
            {
                let pub_params_porep = porc::PublicParams {
                    leaves: pub_params.leaves,
                    sectors_count: pub_params.sectors_count,
                    challenges_count: pub_params.challenge_count,
                };

                let pub_inputs_porep = porc::PublicInputs {
                    challenges: &challenges,
                    challenged_sectors: &challenged_sectors,
                    commitments: &pub_inputs.commitments,
                };

                if !PoRC::verify(&pub_params_porep, &pub_inputs_porep, &proof.porep_proofs[i])? {
                    return Ok(false);
                }
            }

            // update loop state
            mix = proof.ys[i];
            i += 1;
        }
        Ok(true)
    }
}

pub fn extract_vdf_input<H: Hasher>(proof: &porc::Proof<H>) -> H::Domain {
    let leafs: Vec<u8> = proof.leafs().iter().fold(Vec::new(), |mut acc, leaf| {
        acc.extend(leaf.as_ref());
        acc
    });

    H::Function::hash(&leafs)
}

/// `derive_partial_challenges` generates `count` hashed 'partial' challenges, using `seed` as a source of randomness.
fn derive_partial_challenges<H: Hasher>(count: usize, seed: &[u8]) -> Vec<H::Domain> {
    (0..count)
        .map(|j| {
            let mut j_bytes = [0u8; 32];
            LittleEndian::write_u32(&mut j_bytes[0..4], j as u32);

            H::Function::hash(&[seed, &j_bytes].concat())
        })
        .collect()
}

/// `ChallengeStream` manages incremental challenge derivation.
/// Consumers require groups of `challenge_count` challenges. Each round of challenge generation
/// requires a new random input (`mix`).
/// A `ChallengeStream` mediates between this usage requirement and the implementation details
/// of the actual challenge generation mechanism.
pub struct ChallengeStream<H: Hasher, V: Vdf<H::Domain>> {
    partial_challenges: Option<Vec<H::Domain>>,
    challenge_count: usize,
    challenge_rounds: usize,
    partial_challenge_count: usize,
    sectors_count: usize,
    challenge_bits: usize,
    _v: PhantomData<V>,
}

impl<H: Hasher, V: Vdf<H::Domain>> ChallengeStream<H, V> {
    /// A `ChallengeStream` must derive some shared parameters used in challenge derivation.
    /// `new` initializes a new, stateful, `ChallengeStream` with these parameters.
    pub fn new(pp: &PublicParams<H::Domain, V>) -> ChallengeStream<H, V> {
        let challenge_count = pp.challenge_count;
        let challenge_rounds = pp.post_epochs;
        let sectors_count = pp.sectors_count;
        let challenge_bits = pp.challenge_bits;
        let sub_challenges = pp.seed_bits / challenge_bits;
        let partial_challenge_count =
            ((pp.post_epochs * challenge_count) as f32 / sub_challenges as f32).ceil() as usize;

        ChallengeStream {
            partial_challenges: None,
            challenge_count,
            challenge_rounds,
            partial_challenge_count,
            sectors_count,
            challenge_bits,
            _v: PhantomData,
        }
    }

    /// A set of partial challenges must be generated as a one-time initialization.
    /// These partial challenges are 'mixed' with randomness during challenge finalization.
    /// Because partial challenge generation requires access to the first `mix` value as a random seed,
    /// it must be deferred until the first set of challenges is requested.
    fn ensure_partial_challenges(&mut self, mix: H::Domain) {
        if self.partial_challenges.is_none() {
            let partial_challenges = derive_partial_challenges::<H>(
                self.challenge_rounds * self.partial_challenge_count,
                &fr_into_bytes::<Bls12>(&mix.into()),
            );

            self.partial_challenges = Some(partial_challenges);
        }
    }

    /// `next` takes a random value, `mix`, and return an appropriate (conforming with `ChallengeStream`'s parameters)
    /// set of 'final challenges' (and challenged sectors) suitable as input to PoRC.
    /// This process consumes `partial_challenges`, mutating `ChallengeStream`'s state.
    ///
    // FIXME: It's currently possible that a partial_challenge is not completely consumed by production
    // of all needed final challenges. In this case, the remainder will be needed as a witness to prove
    // challenge-generation was performed correctly. However, `next` currently only returns the needed
    // final challenges. This will have to be addressed when we implement challenge verification in circuits.
    fn next(&mut self, mix: H::Domain) -> Option<(Vec<usize>, Vec<usize>)> {
        self.ensure_partial_challenges(mix);

        let mut partial_challenges = self.partial_challenges.clone().unwrap();

        if partial_challenges.is_empty() {
            None
        } else {
            let partial_challenge = partial_challenges.remove(0);
            self.partial_challenges = Some(partial_challenges);

            let mut all_challenges = Vec::with_capacity(self.challenge_count);
            let mut all_challenged_sectors = Vec::with_capacity(self.challenge_count);
            let mut remaining_challenges = self.challenge_count;

            while all_challenges.len() < self.challenge_count {
                let (challenges, challenged_sectors) = derive_final_challenges::<H, Bls12>(
                    partial_challenge,
                    mix,
                    self.sectors_count,
                    self.challenge_bits,
                );

                for i in 0..cmp::min(challenges.len(), remaining_challenges) {
                    all_challenges.push(challenges[i]);
                    all_challenged_sectors.push(challenged_sectors[i]);
                }
                remaining_challenges = self.challenge_count - all_challenges.len();
            }
            Some((all_challenges, all_challenged_sectors))
        }
    }
}

/// Returns (challenges, challenged_sectors)
/// Note that if challenge_bits does not evenly divide 256, then the last challenge will be
/// sampled from a space of only `remainder` bits.
fn derive_final_challenges<H: Hasher, E: Engine>(
    partial_challenge: H::Domain,
    mix: H::Domain,
    _sectors_count: usize,
    challenge_bits: usize,
) -> (Vec<usize>, Vec<usize>)
where
    <E as ScalarEngine>::Fr: std::convert::From<paired::bls12_381::Fr>,
{
    type BV = BitVec<bitvec::LittleEndian, u8>;

    let mut mixed = partial_challenge.into();
    mixed.sub_assign(&mix.into());

    let mixed_bytes = fr_into_bytes::<E>(&mixed.into());
    let mut challenges = Vec::new();
    let mut challenged_sectors = Vec::new();

    for chunk in BV::from(mixed_bytes)
        .into_iter()
        .chunks(challenge_bits)
        .into_iter()
    {
        let mut challenge: usize = 0;
        let mut place = 1;

        for bit in chunk {
            if bit {
                challenge += place;
            }
            place <<= 1;
        }

        let challenged_sector = 0; // FIXME: Actually generate challenged_sector.

        challenges.push(challenge);
        challenged_sectors.push(challenged_sector);
    }

    challenges.reverse();
    challenged_sectors.reverse();

    (challenges, challenged_sectors)
}

/// verify_final_challenge_derivation is used only in a unit test, but it is an important check of
/// and documentation of both the challenge derivation and the method of verifying it.
#[allow(dead_code)]
fn verify_final_challenge_derivation<H: Hasher>(
    challenges: &[usize],
    partial_challenge: H::Domain,
    mix: H::Domain,
    challenge_bits: usize,
) -> bool {
    assert!(challenge_bits > 0 && challenge_bits < 64);
    // Computing shift_factor will overflow if challenge_bits >= 64. No need to work around: 63 bits is plenty.
    let shift_factor = Fr::from_repr(FrRepr::from(1u64 << challenge_bits)).unwrap();
    let packed = challenges.iter().fold(Fr::zero(), |mut acc, challenge| {
        let fr_challenge = Fr::from_repr(FrRepr::from(*challenge as u64)).unwrap();

        acc.mul_assign(&shift_factor);
        acc.add_assign(&fr_challenge);

        acc
    });

    let mut fr_mixed: Fr = mix.into();
    let fr_partial: Fr = partial_challenge.into();
    fr_mixed.add_assign(&packed);

    fr_partial == fr_mixed
}

#[cfg(test)]
mod tests {
    use super::*;

    use paired::bls12_381::Bls12;
    use rand::{Rng, SeedableRng, XorShiftRng};

    use crate::drgraph::{new_seed, BucketGraph, Graph};
    use crate::fr32::fr_into_bytes;
    use crate::hasher::pedersen::{PedersenDomain, PedersenHasher};
    use crate::vdf_sloth;

    #[test]
    fn test_derive_and_verify_final_challenges() {
        let rng = &mut XorShiftRng::from_seed([0x3dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);

        for challenge_bits in 1..64 {
            let sectors_count = 1;
            let partial_challenge: Fr = rng.gen();
            let mix: Fr = rng.gen();

            let (challenges, _challenged_sectors) = derive_final_challenges::<PedersenHasher, Bls12>(
                partial_challenge.into(),
                mix.into(),
                sectors_count,
                challenge_bits,
            );

            assert!(verify_final_challenge_derivation::<PedersenHasher>(
                &challenges,
                partial_challenge.into(),
                mix.into(),
                challenge_bits,
            ));
        }
    }

    #[test]
    fn test_vdf_post_basics() {
        let rng = &mut XorShiftRng::from_seed([0x3dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);

        let sp = SetupParams::<PedersenDomain, vdf_sloth::Sloth> {
            challenge_count: 30,
            sector_size: 1024 * 32,
            post_epochs: 3,
            setup_params_vdf: vdf_sloth::SetupParams {
                key: rng.gen(),
                rounds: 1,
            },
            sectors_count: 2,
        };

        let pub_params =
            VDFPoSt::<PedersenHasher, vdf_sloth::Sloth>::setup(&sp).expect("PoSt setup failed");

        let data0: Vec<u8> = (0..1024)
            .flat_map(|_| fr_into_bytes::<Bls12>(&rng.gen()))
            .collect();
        let data1: Vec<u8> = (0..1024)
            .flat_map(|_| fr_into_bytes::<Bls12>(&rng.gen()))
            .collect();

        let graph0 = BucketGraph::<PedersenHasher>::new(1024, 5, 0, new_seed());
        let tree0 = graph0.merkle_tree(data0.as_slice()).unwrap();
        let graph1 = BucketGraph::<PedersenHasher>::new(1024, 5, 0, new_seed());
        let tree1 = graph1.merkle_tree(data1.as_slice()).unwrap();

        let pub_inputs = PublicInputs {
            challenge_seed: rng.gen(),
            commitments: vec![tree0.root(), tree1.root()],
            faults: Vec::new(),
        };

        let priv_inputs = PrivateInputs {
            trees: &[&tree0, &tree1],
            _h: PhantomData,
        };

        let proof = VDFPoSt::<PedersenHasher, vdf_sloth::Sloth>::prove(
            &pub_params,
            &pub_inputs,
            &priv_inputs,
        )
        .expect("proving failed");

        let is_valid =
            VDFPoSt::<PedersenHasher, vdf_sloth::Sloth>::verify(&pub_params, &pub_inputs, &proof)
                .expect("verification failed");

        assert!(is_valid);
    }
}