1use crate::{commitment::*, diff::Diff, encoding, utils::evals_to_polynomial};
13use ark_ff::PrimeField;
14use ark_poly::{univariate::DensePolynomial, EvaluationDomain, Radix2EvaluationDomain as R2D};
15use kimchi::curve::KimchiCurve;
16use poly_commitment::ipa::SRS;
17use std::{
18 fs::{File, OpenOptions},
19 io::{Read, Seek, SeekFrom, Write},
20};
21
22use crate::SRS_SIZE;
23
24pub struct Data<F: PrimeField> {
25 pub data: Vec<F>,
26}
27
28impl<F: PrimeField> Data<F> {
29 pub fn of_bytes(bytes: &[u8]) -> Data<F> {
31 Data {
32 data: encoding::encode_as_field_elements_full(bytes),
33 }
34 }
35
36 pub fn is_empty(&self) -> bool {
37 self.data.is_empty()
38 }
39
40 pub fn len(&self) -> usize {
42 self.data.len()
43 }
44
45 pub fn to_polynomial(&self, domain: R2D<F>) -> DensePolynomial<F> {
49 use std::iter;
50 let n = domain.size();
51 let padded_data: Vec<F> = self
52 .data
53 .iter()
54 .cloned()
55 .chain(iter::repeat(F::zero()))
56 .take(n)
57 .collect();
58 evals_to_polynomial(padded_data, domain)
59 }
60
61 pub fn to_commitment<G: KimchiCurve<ScalarField = F>>(&self, srs: &SRS<G>) -> G {
64 commit_to_field_elems::<G>(srs, &self.data)[0]
65 }
66
67 pub fn apply_inplace(&mut self, diff: &Diff<F>) {
69 let data_slice = std::slice::from_mut(&mut self.data);
70 Diff::apply_inplace(data_slice, diff);
71 }
72
73 pub fn apply(&self, diff: &Diff<F>) -> Data<F> {
75 let mut data = Data {
76 data: self.data.clone(),
77 };
78 data.apply_inplace(diff);
79 data
80 }
81}
82
83pub fn init<F: PrimeField>(path: &str, data: &Data<F>) -> std::io::Result<()> {
86 assert!(data.len() <= SRS_SIZE);
88 let mut file = File::create(path)?;
89 for x in &data.data {
90 let x_bytes = encoding::decode_full(*x);
91 file.write_all(&x_bytes)?
92 }
93 Ok(())
94}
95
96pub fn read<F: PrimeField>(path: &str) -> std::io::Result<Data<F>> {
101 let mut file = File::open(path)?;
102 let mut buffer = Vec::new();
103 file.read_to_end(&mut buffer)?;
104 Ok(Data::of_bytes(&buffer))
106}
107
108pub fn update<F: PrimeField>(path: &str, diff: &Diff<F>) -> std::io::Result<()> {
114 let mut file = OpenOptions::new().write(true).open(path)?;
115 let region_offset = diff.region * (SRS_SIZE as u64);
116 let scalar_size = encoding::encoding_size_full::<F>() as u64;
117 for (index, new_value) in diff.addresses.iter().zip(diff.new_values.iter()) {
118 let corresponding_bytes_index = (region_offset + index) * scalar_size;
119 file.seek(SeekFrom::Start(corresponding_bytes_index))?;
120 let new_value_bytes = encoding::decode_full(*new_value);
121 file.write_all(&new_value_bytes)?;
122 }
123 Ok(())
124}
125
126#[cfg(test)]
127mod tests {
128 use crate::{diff::Diff, encoding, storage, storage::Data, Curve, ScalarField, SRS_SIZE};
129 use ark_ff::{One, UniformRand, Zero};
130 use mina_curves::pasta::Fp;
131 use rand::Rng;
132 use std::fs;
133 use tempfile::NamedTempFile;
134
135 #[test]
136 fn test_data_consistency() {
140 let mut rng = o1_utils::tests::make_test_rng(None);
141
142 let srs = poly_commitment::precomputed_srs::get_srs_test();
143
144 let file = NamedTempFile::new().unwrap();
146 let path = file.path().to_str().unwrap();
147
148 let data_bytes: Vec<u8> = (0..(SRS_SIZE * (encoding::encoding_size_full::<ScalarField>())))
149 .map(|_| rng.gen())
150 .collect();
151 let data = Data::of_bytes(&data_bytes);
152 let data_comm = data.to_commitment(&srs);
153
154 let read_consistency = {
155 let _init_storage_file = storage::init(path, &data);
156 let read_data = storage::read(path).unwrap();
157 let read_data_comm = read_data.to_commitment(&srs);
158
159 Curve::eq(&data_comm, &read_data_comm)
161 };
162
163 let (data_updated, update_consistency) = {
164 let diff = {
165 let nb_updates = std::cmp::max(data.len() / 20, 1);
169 let region = 0;
170 let addresses: Vec<u64> = (0..nb_updates)
171 .map(|_| (rng.gen_range(0..data.len() as u64)))
172 .collect();
173 let mut new_values: Vec<ScalarField> =
174 addresses.iter().map(|_| Fp::rand(&mut rng)).collect();
175 new_values[0] = Fp::zero() - Fp::one();
179 Diff {
180 region,
181 addresses,
182 new_values,
183 }
184 };
185
186 let updated_data = data.apply(&diff);
187 let updated_data_comm = updated_data.to_commitment(&srs);
188
189 let _file_update = storage::update(path, &diff);
190
191 let updated_read_data = storage::read(path).unwrap();
192 let updated_read_data_comm = updated_read_data.to_commitment(&srs);
193
194 (
195 Curve::ne(&updated_data_comm, &data_comm),
196 Curve::eq(&updated_data_comm, &updated_read_data_comm),
198 )
199 };
200
201 let _remove_file = fs::remove_file(path);
202
203 assert!(read_consistency);
204 assert!(data_updated);
205 assert!(update_consistency);
206 }
207}