darkfi/zk/
proof.rs

1/* This file is part of DarkFi (https://dark.fi)
2 *
3 * Copyright (C) 2020-2026 Dyne.org foundation
4 *
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU Affero General Public License as
7 * published by the Free Software Foundation, either version 3 of the
8 * License, or (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 * GNU Affero General Public License for more details.
14 *
15 * You should have received a copy of the GNU Affero General Public License
16 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
17 */
18use std::{io, io::Cursor};
19
20#[cfg(feature = "async-serial")]
21use darkfi_serial::async_trait;
22
23use darkfi_sdk::pasta::{pallas, vesta};
24use darkfi_serial::{SerialDecodable, SerialEncodable};
25use halo2_proofs::{
26    helpers::SerdeFormat,
27    plonk,
28    plonk::{Circuit, SingleVerifier},
29    poly::commitment::Params,
30    transcript::{Blake2bRead, Blake2bWrite},
31};
32use rand::RngCore;
33
34#[derive(Clone, Debug)]
35pub struct VerifyingKey {
36    pub params: Params<vesta::Affine>,
37    pub vk: plonk::VerifyingKey<vesta::Affine>,
38}
39
40impl VerifyingKey {
41    pub fn build(k: u32, c: &impl Circuit<pallas::Base>) -> Self {
42        let params = Params::new(k);
43        let vk = plonk::keygen_vk(&params, c).unwrap();
44        VerifyingKey { params, vk }
45    }
46
47    pub fn write<W: io::Write>(&self, writer: &mut W) -> io::Result<()> {
48        let mut params = vec![];
49        self.params.write(&mut params)?;
50
51        let mut vk = vec![];
52        self.vk.write(&mut vk, SerdeFormat::RawBytes)?;
53
54        let _ = writer.write(&(params.len() as u32).to_le_bytes())?;
55        let _ = writer.write(&params)?;
56        let _ = writer.write(&(vk.len() as u32).to_le_bytes())?;
57        let _ = writer.write(&vk)?;
58
59        Ok(())
60    }
61
62    pub fn read<R: io::Read, ConcreteCircuit: Circuit<pallas::Base>>(
63        reader: &mut R,
64        circuit: ConcreteCircuit,
65    ) -> io::Result<Self> {
66        // The format chosen in write():
67        // [params.len()<u32>, params..., vk.len()<u32>, vk...]
68
69        let mut params_len = [0u8; 4];
70        reader.read_exact(&mut params_len)?;
71        let params_len = u32::from_le_bytes(params_len) as usize;
72
73        let mut params_buf = vec![0u8; params_len];
74        reader.read_exact(&mut params_buf)?;
75
76        assert!(params_buf.len() == params_len);
77
78        let mut vk_len = [0u8; 4];
79        reader.read_exact(&mut vk_len)?;
80        let vk_len = u32::from_le_bytes(vk_len) as usize;
81
82        let mut vk_buf = vec![0u8; vk_len];
83        reader.read_exact(&mut vk_buf)?;
84
85        assert!(vk_buf.len() == vk_len);
86
87        let mut params_c = Cursor::new(params_buf);
88        let params: Params<vesta::Affine> = Params::read(&mut params_c)?;
89
90        let mut vk_c = Cursor::new(vk_buf);
91        let vk: plonk::VerifyingKey<vesta::Affine> =
92            plonk::VerifyingKey::read::<Cursor<Vec<u8>>, ConcreteCircuit>(
93                &mut vk_c,
94                SerdeFormat::RawBytes,
95                circuit.params(),
96            )?;
97
98        Ok(Self { params, vk })
99    }
100}
101
102#[derive(Clone, Debug)]
103pub struct ProvingKey {
104    pub params: Params<vesta::Affine>,
105    pub pk: plonk::ProvingKey<vesta::Affine>,
106}
107
108impl ProvingKey {
109    pub fn build(k: u32, c: &impl Circuit<pallas::Base>) -> Self {
110        let params = Params::new(k);
111        let vk = plonk::keygen_vk(&params, c).unwrap();
112        let pk = plonk::keygen_pk(&params, vk, c).unwrap();
113        ProvingKey { params, pk }
114    }
115
116    pub fn write<W: io::Write>(&self, writer: &mut W) -> io::Result<()> {
117        let mut params = vec![];
118        self.params.write(&mut params)?;
119
120        let mut pk = vec![];
121        self.pk.write(&mut pk, SerdeFormat::RawBytes)?;
122
123        let _ = writer.write(&(params.len() as u32).to_le_bytes())?;
124        let _ = writer.write(&params)?;
125        let _ = writer.write(&(pk.len() as u32).to_le_bytes())?;
126        let _ = writer.write(&pk)?;
127
128        Ok(())
129    }
130
131    pub fn read<R: io::Read, ConcreteCircuit: Circuit<pallas::Base>>(
132        reader: &mut R,
133        circuit: ConcreteCircuit,
134    ) -> io::Result<Self> {
135        let mut params_len = [0u8; 4];
136        reader.read_exact(&mut params_len)?;
137        let params_len = u32::from_le_bytes(params_len) as usize;
138
139        let mut params_buf = vec![0u8; params_len];
140        reader.read_exact(&mut params_buf)?;
141
142        assert!(params_buf.len() == params_len);
143
144        let mut pk_len = [0u8; 4];
145        reader.read_exact(&mut pk_len)?;
146        let pk_len = u32::from_le_bytes(pk_len) as usize;
147
148        let mut pk_buf = vec![0u8; pk_len];
149        reader.read_exact(&mut pk_buf)?;
150
151        assert!(pk_buf.len() == pk_len);
152
153        let mut params_c = Cursor::new(params_buf);
154        let params: Params<vesta::Affine> = Params::read(&mut params_c)?;
155
156        let mut pk_c = Cursor::new(pk_buf);
157        let pk: plonk::ProvingKey<vesta::Affine> =
158            plonk::ProvingKey::read::<Cursor<Vec<u8>>, ConcreteCircuit>(
159                &mut pk_c,
160                SerdeFormat::RawBytes,
161                circuit.params(),
162            )?;
163
164        Ok(Self { params, pk })
165    }
166}
167
168#[derive(Clone, Default, PartialEq, Eq, SerialEncodable, SerialDecodable)]
169pub struct Proof(Vec<u8>);
170
171impl AsRef<[u8]> for Proof {
172    fn as_ref(&self) -> &[u8] {
173        &self.0
174    }
175}
176
177impl core::fmt::Debug for Proof {
178    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
179        write!(f, "Proof({:?})", self.0)
180    }
181}
182
183impl Proof {
184    pub fn create(
185        pk: &ProvingKey,
186        circuits: &[impl Circuit<pallas::Base>],
187        instances: &[pallas::Base],
188        mut rng: impl RngCore,
189    ) -> std::result::Result<Self, plonk::Error> {
190        let mut transcript = Blake2bWrite::<_, vesta::Affine, _>::init(vec![]);
191        plonk::create_proof(
192            &pk.params,
193            &pk.pk,
194            circuits,
195            &[&[instances]],
196            &mut rng,
197            &mut transcript,
198        )?;
199
200        Ok(Proof(transcript.finalize()))
201    }
202
203    pub fn verify(
204        &self,
205        vk: &VerifyingKey,
206        instances: &[pallas::Base],
207    ) -> std::result::Result<(), plonk::Error> {
208        let strategy = SingleVerifier::new(&vk.params);
209        let mut transcript = Blake2bRead::init(&self.0[..]);
210
211        plonk::verify_proof(&vk.params, &vk.vk, strategy, &[&[instances]], &mut transcript)
212    }
213
214    pub fn new(bytes: Vec<u8>) -> Self {
215        Proof(bytes)
216    }
217}