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
/// First 64 bytes of the BLAKE2s input during group hash.
/// This is chosen to be some random string that we couldn't have anticipated when we designed
/// the algorithm, for rigidity purposes.
/// We deliberately use an ASCII hex string of 32 bytes here.
pub const GH_FIRST_BLOCK: &'static [u8; 64]
          = b"096b36a5804bfacef1691e173c366a47ff5ba84a44f26ddd7e8d9f79d5b42df0";

// BLAKE2s invocation personalizations
/// BLAKE2s Personalization for CRH^ivk = BLAKE2s(ak | nk)
pub const CRH_IVK_PERSONALIZATION: &'static [u8; 8]
          = b"Zcashivk";

/// BLAKE2s Personalization for PRF^nf = BLAKE2s(nk | rho)
pub const PRF_NF_PERSONALIZATION: &'static [u8; 8]
          = b"Zcash_nf";

// Group hash personalizations
/// BLAKE2s Personalization for Pedersen hash generators.
pub const PEDERSEN_HASH_GENERATORS_PERSONALIZATION: &'static [u8; 8]
          = b"Zcash_PH";

/// BLAKE2s Personalization for the group hash for key diversification
pub const KEY_DIVERSIFICATION_PERSONALIZATION: &'static [u8; 8]
          = b"Zcash_gd";

/// BLAKE2s Personalization for the spending key base point
pub const SPENDING_KEY_GENERATOR_PERSONALIZATION: &'static [u8; 8]
          = b"Zcash_G_";

/// BLAKE2s Personalization for the proof generation key base point
pub const PROOF_GENERATION_KEY_BASE_GENERATOR_PERSONALIZATION: &'static [u8; 8]
          = b"Zcash_H_";

/// BLAKE2s Personalization for the value commitment generator for the value
pub const VALUE_COMMITMENT_GENERATOR_PERSONALIZATION: &'static [u8; 8]
          = b"Zcash_cv";

/// BLAKE2s Personalization for the nullifier position generator (for computing rho)
pub const NULLIFIER_POSITION_IN_TREE_GENERATOR_PERSONALIZATION: &'static [u8; 8]
          = b"Zcash_J_";

/// BLAKE2s Personalization hash of (R_x || message) in EdDSA variant with 256 bit hash
pub const MATTER_EDDSA_BLAKE2S_PERSONALIZATION: &'static [u8; 8] 
            = b"Matter_H";

/// Eth block hash for block 10M
pub const ETH_BLOCK_10_000_000_HASH: &'static str
            = "aa20f7bde5be60603f11a45fc4923aab7552be775403fc00c2e6b805e6297dbe";


/// DST constant for multiexp function
pub const MULTIEXP_DST: &'static [u8; 8]  = b"Multiexp";
  
use bellman::CurveAffine;

use crate::bellman::pairing::{Engine, GenericCurveAffine, GenericCurveProjective};
use crate::byteorder::{BigEndian, ReadBytesExt};
  
pub fn make_random_points_with_unknown_discrete_log_from_seed<G: GenericCurveAffine + rand::Rand>(
    dst: &[u8],
    seed: &[u8],
    num_points: usize
) -> Vec<G> {
    let mut result = vec![];

    use rand::{Rng, SeedableRng};
    use rand::chacha::ChaChaRng;
    // Create an RNG based on the outcome of the random beacon
    let mut rng = {
        // if we use Blake hasher
        let input: Vec<u8> = dst.iter().chain(seed.iter()).cloned().collect();
        let h = blake2s_simd::blake2s(&input);
        assert!(h.as_bytes().len() == 32);
        let mut seed = [0u32; 8];
        for (i, chunk) in h.as_bytes().chunks_exact(8).enumerate() {
            seed[i] = (&chunk[..]).read_u32::<BigEndian>().expect("digest is large enough for this to work");
        }

        ChaChaRng::from_seed(&seed)
    };

    for _ in 0..num_points {
        let point: G = rng.gen();
        result.push(point);
    }

    result
}
  
pub fn make_random_points_with_unknown_discrete_log<G: GenericCurveAffine + rand::Rand>(
    dst: &[u8],
    num_points: usize
) -> Vec<G> {
    make_random_points_with_unknown_discrete_log_from_seed::<G>(
        dst, 
        &hex::decode(crate::constants::ETH_BLOCK_10_000_000_HASH).unwrap(),
        num_points
    )
}

pub fn make_random_points_with_unknown_discrete_log_generic<G: GenericCurveAffine + rand::Rand>(
    dst: &[u8],
    num_points: usize
) -> Vec<G> {
    make_random_points_with_unknown_discrete_log_from_seed::<G>(
        dst, 
        &hex::decode(crate::constants::ETH_BLOCK_10_000_000_HASH).unwrap(),
        num_points
    )
}


pub fn make_random_points_with_unknown_discrete_log_from_seed_proj<G: GenericCurveProjective + rand::Rand>(
    dst: &[u8],
    seed: &[u8],
    num_points: usize
) -> Vec<G::Affine> {
    let mut result = vec![];

    use rand::{Rng, SeedableRng};
    use rand::chacha::ChaChaRng;
    // Create an RNG based on the outcome of the random beacon
    let mut rng = {
        // if we use Blake hasher
        let input: Vec<u8> = dst.iter().chain(seed.iter()).cloned().collect();
        let h = blake2s_simd::blake2s(&input);
        assert!(h.as_bytes().len() == 32);
        let mut seed = [0u32; 8];
        for (i, chunk) in h.as_bytes().chunks_exact(8).enumerate() {
            seed[i] = (&chunk[..]).read_u32::<BigEndian>().expect("digest is large enough for this to work");
        }

        ChaChaRng::from_seed(&seed)
    };

    for _ in 0..num_points {
        let point: G = rng.gen();

        result.push(point.into_affine());
    }

    result
}
  
pub fn make_random_points_with_unknown_discrete_log_proj<E: Engine>(
    dst: &[u8],
    num_points: usize
) -> Vec<E::G1Affine> {
    make_random_points_with_unknown_discrete_log_from_seed_proj::<E::G1>(
        dst, 
        &hex::decode(crate::constants::ETH_BLOCK_10_000_000_HASH).unwrap(),
        num_points
    )
}

pub fn make_random_points_with_unknown_discrete_log_generic_proj<G: GenericCurveProjective + rand::Rand>(
    dst: &[u8],
    num_points: usize
) -> Vec<G::Affine> {
    make_random_points_with_unknown_discrete_log_from_seed_proj::<G>(
        dst, 
        &hex::decode(crate::constants::ETH_BLOCK_10_000_000_HASH).unwrap(),
        num_points
    )
}