1use std::fs::File;
2use std::collections::BTreeMap;
3use std::io::{Read, Seek, SeekFrom};
4use byteorder::{LittleEndian, ReadBytesExt};
5use ark_bn254::{G1Affine, G2Affine, Fq, Fq2};
6use ark_ff::fields::PrimeField;
7use ark_ff::FromBytes;
8use ark_ff::biginteger::BigInteger256;
9
10#[derive(Debug, PartialEq)]
11pub enum Error {
12 InvalidMagicString,
13 InvalidVersion,
14 InvalidPrimeOrder,
15 InvalidNumSections,
16 InvalidNumG1Points,
17 InvalidNumG2Points,
18 InvalidG1Point,
19 InvalidG2Point,
20}
21
22pub fn read(
23 ptau_file: &str,
24 num_g1_points: usize,
25 num_g2_points: usize,
26) -> Result<(Vec<G1Affine>, Vec<G2Affine>), Error> {
27 let mut f = File::open(ptau_file).unwrap();
28
29 let mut magic_string_buf = [0u8; 4];
31 let _ = f.read_exact(&mut magic_string_buf);
32 if std::str::from_utf8(&magic_string_buf).unwrap() != "ptau" {
33 return Err(Error::InvalidMagicString);
34 }
35
36 let version = f.read_u32::<LittleEndian>().unwrap();
38 if version != 1 {
39 return Err(Error::InvalidVersion);
40 }
41
42 let num_sections = f.read_u32::<LittleEndian>().unwrap();
44 if num_sections != 11 {
45 return Err(Error::InvalidNumSections);
46 }
47
48 let mut sections = BTreeMap::<usize, u64>::new();
50
51 for _ in 0..num_sections {
52 let num = f.read_u32::<LittleEndian>().unwrap();
53 let size = f.read_i64::<LittleEndian>().unwrap();
54 let pos = f.stream_position().unwrap();
55 let _ = f.seek(SeekFrom::Current(size));
56 sections.insert(num as usize, pos);
57 }
58
59 let _ = f.seek(SeekFrom::Start(sections[&1]));
61 let n8 = f.read_u32::<LittleEndian>().unwrap();
62 let mut q_buf = vec![0u8; n8 as usize];
63 let _ = f.read_exact(&mut q_buf);
64
65 let mut num_zeroes = 0;
67 for b in q_buf.iter() {
68 if *b == 0u8 {
69 num_zeroes += 1;
70 }
71 }
72 if num_zeroes == 32 {
73 return Err(Error::InvalidPrimeOrder);
74 }
75
76 let q = Fq::from_le_bytes_mod_order(&q_buf);
78
79 if q != Fq::from(0) {
81 return Err(Error::InvalidPrimeOrder);
82 }
83
84 let power = f.read_u32::<LittleEndian>().unwrap();
86
87 let _ceremony_power = f.read_u32::<LittleEndian>().unwrap();
89
90 let max_g2_points = 1 << power;
91 let max_g1_points = max_g2_points * 2 - 1;
92 if num_g1_points > max_g1_points {
93 return Err(Error::InvalidNumG1Points)
94 }
95 if num_g2_points > max_g2_points {
96 return Err(Error::InvalidNumG2Points);
97 }
98
99 let mut g1_points = Vec::<G1Affine>::with_capacity(num_g1_points);
102 let _ = f.seek(SeekFrom::Start(sections[&2]));
103 for _ in 0..num_g1_points {
104 let mut x_buf = [0u8; 32];
105 let mut y_buf = [0u8; 32];
106 let _ = f.read_exact(&mut x_buf);
107 let _ = f.read_exact(&mut y_buf);
108
109 let x_bigint = BigInteger256::read(x_buf.as_slice()).unwrap();
110 let y_bigint = BigInteger256::read(y_buf.as_slice()).unwrap();
111 let x = Fq::new(x_bigint);
112 let y = Fq::new(y_bigint);
113 let g1 = G1Affine::new(x, y, false);
114 if !g1.is_on_curve() {
115 return Err(Error::InvalidG1Point);
116 }
117 g1_points.push(g1);
118 }
119
120 let _ = f.seek(SeekFrom::Start(sections[&3]));
122
123 let mut g2_points = Vec::<G2Affine>::with_capacity(num_g2_points);
124 for _ in 0..num_g2_points {
125 let mut x0_buf = [0u8; 32];
126 let mut x1_buf = [0u8; 32];
127 let mut y0_buf = [0u8; 32];
128 let mut y1_buf = [0u8; 32];
129 let _ = f.read_exact(&mut x0_buf);
130 let _ = f.read_exact(&mut x1_buf);
131 let _ = f.read_exact(&mut y0_buf);
132 let _ = f.read_exact(&mut y1_buf);
133 let x0_bigint = BigInteger256::read(x0_buf.as_slice()).unwrap();
134 let x1_bigint = BigInteger256::read(x1_buf.as_slice()).unwrap();
135 let y0_bigint = BigInteger256::read(y0_buf.as_slice()).unwrap();
136 let y1_bigint = BigInteger256::read(y1_buf.as_slice()).unwrap();
137 let x0 = Fq::new(x0_bigint);
138 let x1 = Fq::new(x1_bigint);
139 let y0 = Fq::new(y0_bigint);
140 let y1 = Fq::new(y1_bigint);
141 let x = Fq2::new(x0, x1);
142 let y = Fq2::new(y0, y1);
143 let g2 = G2Affine::new(x, y, false);
144 if !g2.is_on_curve() {
145 return Err(Error::InvalidG2Point);
146 }
147 g2_points.push(g2);
148 }
149 Ok((g1_points, g2_points))
150}
151
152#[cfg(test)]
153mod tests {
154 use super::Error;
155 use ark_bn254::{G1Affine, G2Affine, Fq, Fq2};
156 use ark_ff::FromBytes;
157 fn hex_to_fq(val: &str) -> Fq {
158 assert_eq!(val.len(), 64);
159 let bytes_vec = hex::decode(val).unwrap();
160 let bytes_slice: &[u8] = bytes_vec.as_slice();
161
162 Fq::read(bytes_slice).unwrap()
163 }
164
165 #[test]
166 pub fn test_read() {
167 let num_g1_points = 511;
168 let num_g2_points = 256;
169
170 let ptau_file = "8.ptau";
171
172 let (g1_points, g2_points) = super::read(ptau_file, num_g1_points, num_g2_points).unwrap();
173 assert_eq!(g1_points.len(), num_g1_points);
174 assert_eq!(g2_points.len(), num_g2_points);
175
176 let point_g1_0_x = Fq::from(1);
178 let point_g1_0_y = Fq::from(2);
179 let point_g1_1_x = hex_to_fq("cf51b65ad54479e394aef90d4b0ec4e4a1a16bbb6865614a4b5b8a0959fdd32d");
180 let point_g1_1_y = hex_to_fq("f04eb3f6ef601be3d326c237feed3351de969ce6d634905a4304ba25350c6825");
181
182 assert_eq!(g1_points[0], G1Affine::new(point_g1_0_x, point_g1_0_y, false));
183 assert_eq!(g1_points[1], G1Affine::new(point_g1_1_x, point_g1_1_y, false));
184
185 let point_g2_0_x0 = hex_to_fq("edf692d95cbdde46ddda5ef7d422436779445c5e66006a42761e1f12efde0018");
187 let point_g2_0_x1 = hex_to_fq("c212f3aeb785e49712e7a9353349aaf1255dfb31b7bf60723a480d9293938e19");
188 let point_g2_0_y0 = hex_to_fq("aa7dfa6601cce64c7bd3430c69e7d1e38f40cb8d8071ab4aeb6d8cdba55ec812");
189 let point_g2_0_y1 = hex_to_fq("5b9722d1dcdaac55f38eb37033314bbc95330c69ad999eec75f05f58d0890609");
190 let point_g2_0 = G2Affine::new(
191 Fq2::new(point_g2_0_x0, point_g2_0_x1),
192 Fq2::new(point_g2_0_y0, point_g2_0_y1),
193 false
194 );
195 assert_eq!(g2_points[0], point_g2_0);
196 }
197
198 #[test]
199 pub fn test_read_too_few_g1() {
200 let num_g1_points = 512;
201 let num_g2_points = 256;
202
203 let ptau_file = "8.ptau";
204
205 let r = super::read(ptau_file, num_g1_points, num_g2_points);
206 assert_eq!(r.err().unwrap(), Error::InvalidNumG1Points);
207 }
208
209 #[test]
210 pub fn test_read_too_few_g2() {
211 let num_g1_points = 511;
212 let num_g2_points = 257;
213
214 let ptau_file = "8.ptau";
215
216 let r = super::read(ptau_file, num_g1_points, num_g2_points);
217 assert_eq!(r.err().unwrap(), Error::InvalidNumG2Points);
218 }
219}