ppot_rs/
ptau.rs

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    // Read the magic string (the first 4 bytes)
30    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    // Read the version (a 32-bit little-endian uint)
37    let version = f.read_u32::<LittleEndian>().unwrap();
38    if version != 1 {
39        return Err(Error::InvalidVersion);
40    }
41
42    // Read the number of sections (a 32-bit little-endian uint)
43    let num_sections = f.read_u32::<LittleEndian>().unwrap();
44    if num_sections != 11 {
45        return Err(Error::InvalidNumSections);
46    }
47
48    // section_num => (file position, section size)
49    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    // Read the header (section 1)
60    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    // ensure that q_buf is not all 0s
66    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    // Read q_buf as an Fq element
77    let q = Fq::from_le_bytes_mod_order(&q_buf);
78
79    // q should be 0 since it's the Fq modulus
80    if q != Fq::from(0) {
81        return Err(Error::InvalidPrimeOrder);
82    }
83
84    // Read the power
85    let power = f.read_u32::<LittleEndian>().unwrap();
86    
87    // Read the ceremony power
88    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    // Read the G1 points
100    // Seek to section 2
101    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    // Seek to section 3
121    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        // Check that the first 2 G1 points are correct
177        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        // Check that the first G2 point is correct
186        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}