provenance_mark/
generator.rs

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
use std::fmt::Formatter;

use bc_rand::RandomNumberGenerator;
use dcbor::{ CBOREncodable, Date };
use serde::{ Serialize, Deserialize };
use crate::crypto_utils::sha256;
use crate::util::{ serialize_base64, deserialize_base64 };

use crate::{ ProvenanceSeed, RngState };
use crate::{
    crypto_utils::extend_key,
    xoshiro256starstar::Xoshiro256StarStar,
    ProvenanceMark,
    ProvenanceMarkResolution,
};

#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct ProvenanceMarkGenerator {
    res: ProvenanceMarkResolution,
    seed: ProvenanceSeed,
    #[serde(rename = "chainID")]
    #[serde(serialize_with = "serialize_base64", deserialize_with = "deserialize_base64")]
    chain_id: Vec<u8>,
    #[serde(rename = "nextSeq")]
    next_seq: u32,
    #[serde(rename = "rngState")]
    rng_state: RngState,
}

impl ProvenanceMarkGenerator {
    pub fn res(&self) -> &ProvenanceMarkResolution {
        &self.res
    }

    pub fn seed(&self) -> &ProvenanceSeed {
        &self.seed
    }

    pub fn chain_id(&self) -> &[u8] {
        &self.chain_id
    }

    pub fn next_seq(&self) -> u32 {
        self.next_seq
    }

    pub fn rng_state(&self) -> &RngState {
        &self.rng_state
    }
}

impl ProvenanceMarkGenerator {
    pub fn new_with_seed(res: ProvenanceMarkResolution, seed: ProvenanceSeed) -> Self {
        // Definitely don't use the bare seed as the chain ID!
        let digest1 = sha256(seed.to_bytes().as_ref());
        let chain_id = digest1[..res.link_length()].to_vec();
        let digest2 = sha256(digest1);
        Self::new(res, seed.clone(), chain_id, 0, digest2.into())
    }

    pub fn new_with_passphrase(res: ProvenanceMarkResolution, passphrase: &str) -> Self {
        let seed_data = extend_key(passphrase.as_bytes());
        let seed = ProvenanceSeed::from_bytes(seed_data);
        Self::new_with_seed(res, seed)
    }

    pub fn new_using(res: ProvenanceMarkResolution, rng: &mut impl RandomNumberGenerator) -> Self {
        // Randomness for a new seed can come from any secure random number generator.
        let seed = ProvenanceSeed::new_using(rng);
        Self::new_with_seed(res, seed)
    }

    pub fn new_random(res: ProvenanceMarkResolution) -> Self {
        let seed = ProvenanceSeed::new();
        Self::new_with_seed(res, seed)
    }

    pub fn new(
        res: ProvenanceMarkResolution,
        seed: ProvenanceSeed,
        chain_id: Vec<u8>,
        next_seq: u32,
        rng_state: RngState
    ) -> Self {
        assert!(chain_id.len() == res.link_length());
        Self { res, seed, chain_id, next_seq, rng_state }
    }

    pub fn next(&mut self, date: Date, info: Option<impl CBOREncodable>) -> ProvenanceMark {
        let data: [u8; 32] = self.rng_state.clone().into();
        let mut rng = Xoshiro256StarStar::from_data(&data);

        let seq = self.next_seq;
        self.next_seq += 1;

        let key;
        if seq == 0 {
            key = self.chain_id.clone();
        } else {
            // The randomness generated by the PRNG should be portable across implementations.
            key = rng.next_bytes(self.res.link_length());
            self.rng_state = rng.to_data().into();
        }

        let mut next_rng = rng.clone();
        let next_key = next_rng.next_bytes(self.res.link_length());

        ProvenanceMark::new(
            self.res,
            key,
            next_key,
            self.chain_id.clone(),
            seq,
            date,
            info
        ).unwrap()
    }
}

impl std::fmt::Display for ProvenanceMarkGenerator {
    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
        write!(
            f,
            "ProvenanceMarkGenerator(chainID: {}, res: {}, seed: {}, nextSeq: {}, rngState: {:?})",
            hex::encode(&self.chain_id),
            self.res,
            self.seed.hex(),
            self.next_seq,
            self.rng_state
        )
    }
}