fullcodec_plonk/commitment_scheme/kzg10/srs.rs
1// This Source Code Form is subject to the terms of the Mozilla Public
2// License, v. 2.0. If a copy of the MPL was not distributed with this
3// file, You can obtain one at http://mozilla.org/MPL/2.0/.
4//
5// Copyright (c) DUSK NETWORK. All rights reserved.
6
7//! The Public Parameters can also be referred to as the Structured Reference
8//! String (SRS).
9use super::key::{CommitKey, OpeningKey};
10use crate::{error::Error, util};
11use dusk_bls12_381::{G1Affine, G1Projective, G2Affine};
12use dusk_bytes::{DeserializableSlice, Serializable};
13use parity_scale_codec::{Decode, Encode};
14use rand_core::RngCore;
15use serde::{Deserialize, Serialize};
16use sp_std::vec;
17use sp_std::vec::Vec;
18
19/// The Public Parameters can also be referred to as the Structured Reference
20/// String (SRS). It is available to both the prover and verifier and allows the
21/// verifier to efficiently verify and make claims about polynomials up to and
22/// including a configured degree.
23#[derive(Debug, Clone, Encode, Decode, Serialize, Deserialize, PartialEq)]
24pub struct PublicParameters {
25 /// Key used to generate proofs for composed circuits.
26 pub(crate) commit_key: CommitKey,
27 /// Key used to verify proofs for composed circuits.
28 pub(crate) opening_key: OpeningKey,
29}
30
31impl PublicParameters {
32 /// Returns an untrimmed [`CommitKey`] reference contained in the
33 /// `PublicParameters` instance.
34 pub fn commit_key(&self) -> &CommitKey {
35 &self.commit_key
36 }
37
38 /// Returns an [`OpeningKey`] reference contained in the
39 /// `PublicParameters` instance.
40 pub fn opening_key(&self) -> &OpeningKey {
41 &self.opening_key
42 }
43
44 /// Setup generates the public parameters using a random number generator.
45 /// This method will in most cases be used for testing and exploration.
46 /// In reality, a `Trusted party` or a `Multiparty Computation` will be used
47 /// to generate the SRS. Returns an error if the configured degree is less
48 /// than one.
49 pub fn setup(
50 max_degree: usize,
51 mut rng: impl RngCore,
52 ) -> Result<PublicParameters, Error> {
53 // Cannot commit to constants
54 if max_degree < 1 {
55 return Err(Error::DegreeIsZero);
56 }
57
58 // Generate the secret scalar beta
59 let beta = util::random_scalar(&mut rng);
60
61 // Compute powers of beta up to and including beta^max_degree
62 let powers_of_beta = util::powers_of(&beta, max_degree);
63
64 // Powers of G1 that will be used to commit to a specified polynomial
65 let g = util::random_g1_point(&mut rng);
66 let powers_of_g: Vec<G1Projective> =
67 util::slow_multiscalar_mul_single_base(&powers_of_beta, g);
68 assert_eq!(powers_of_g.len(), max_degree + 1);
69
70 // Normalise all projective points
71 let mut normalised_g = vec![G1Affine::identity(); max_degree + 1];
72 G1Projective::batch_normalize(&powers_of_g, &mut normalised_g);
73
74 // Compute beta*G2 element and stored cached elements for verifying
75 // multiple proofs.
76 let h: G2Affine = util::random_g2_point(&mut rng).into();
77 let beta_h: G2Affine = (h * beta).into();
78
79 Ok(PublicParameters {
80 commit_key: CommitKey {
81 powers_of_g: normalised_g,
82 },
83 opening_key: OpeningKey::new(g.into(), h, beta_h),
84 })
85 }
86
87 /// Serialize the [`PublicParameters`] into bytes.
88 ///
89 /// This operation is designed to store the raw representation of the
90 /// contents of the PublicParameters. Therefore, the size of the bytes
91 /// outputed by this function is expected to be the double than the one
92 /// that [`PublicParameters::to_var_bytes`].
93 ///
94 /// # Note
95 /// This function should be used when we want to serialize the
96 /// PublicParameters allowing a really fast deserialization later.
97 /// This functions output should not be used by the regular
98 /// [`PublicParameters::from_slice`] fn.
99 pub fn to_raw_var_bytes(&self) -> Vec<u8> {
100 let mut bytes = self.opening_key.to_bytes().to_vec();
101 bytes.extend(&self.commit_key.to_raw_var_bytes());
102
103 bytes
104 }
105
106 /// Deserialize [`PublicParameters`] from a set of bytes created by
107 /// [`PublicParameters::to_raw_var_bytes`].
108 ///
109 /// The bytes source is expected to be trusted and no checks will be
110 /// performed reggarding the content of the points that the bytes
111 /// contain serialized.
112 ///
113 /// # Safety
114 /// This function will not produce any memory errors but can deal to the
115 /// generation of invalid or unsafe points/keys. To make sure this does not
116 /// happen, the inputed bytes must match the ones that were generated by
117 /// the encoding functions of this lib.
118 pub unsafe fn from_slice_unchecked(bytes: &[u8]) -> Self {
119 let opening_key = &bytes[..OpeningKey::SIZE];
120 let opening_key = OpeningKey::from_slice(opening_key)
121 .expect("Error at OpeningKey deserialization");
122
123 let commit_key = &bytes[OpeningKey::SIZE..];
124 let commit_key = CommitKey::from_slice_unchecked(commit_key);
125
126 Self {
127 commit_key,
128 opening_key,
129 }
130 }
131
132 /// Serialises a [`PublicParameters`] struct into a slice of bytes.
133 pub fn to_var_bytes(&self) -> Vec<u8> {
134 let mut bytes = self.opening_key.to_bytes().to_vec();
135 bytes.extend(self.commit_key.to_var_bytes().iter());
136 bytes
137 }
138
139 /// Deserialise a slice of bytes into a Public Parameter struct performing
140 /// security and consistency checks for each point that the bytes
141 /// contain.
142 ///
143 /// # Note
144 /// This function can be really slow if the [`PublicParameters`] have a
145 /// certain degree. If the bytes come from a trusted source such as a
146 /// local file, we recommend to use
147 /// [`PublicParameters::from_slice_unchecked`] and
148 /// [`PublicParameters::to_raw_var_bytes`].
149 pub fn from_slice(bytes: &[u8]) -> Result<PublicParameters, Error> {
150 if bytes.len() <= OpeningKey::SIZE {
151 return Err(Error::NotEnoughBytes);
152 }
153 let mut buf = bytes;
154 let opening_key = OpeningKey::from_reader(&mut buf)?;
155 let commit_key = CommitKey::from_slice(buf)?;
156
157 let pp = PublicParameters {
158 commit_key,
159 opening_key,
160 };
161
162 Ok(pp)
163 }
164
165 /// Trim truncates the [`PublicParameters`] to allow the prover to commit to
166 /// polynomials up to the and including the truncated degree.
167 /// Returns the [`CommitKey`] and [`OpeningKey`] used to generate and verify
168 /// proofs.
169 ///
170 /// Returns an error if the truncated degree is larger than the public
171 /// parameters configured degree.
172 pub fn trim(
173 &self,
174 truncated_degree: usize,
175 ) -> Result<(CommitKey, OpeningKey), Error> {
176 let truncated_prover_key =
177 self.commit_key.truncate(truncated_degree)?;
178 let opening_key = self.opening_key.clone();
179 Ok((truncated_prover_key, opening_key))
180 }
181
182 /// Max degree specifies the largest Polynomial
183 /// that this prover key can commit to.
184 pub fn max_degree(&self) -> usize {
185 self.commit_key.max_degree()
186 }
187}
188
189#[cfg(feature = "std")]
190#[cfg(test)]
191mod test {
192 use super::*;
193 use dusk_bls12_381::BlsScalar;
194 use rand_core::OsRng;
195
196 #[test]
197 fn test_powers_of() {
198 let x = BlsScalar::from(10u64);
199 let degree = 100u64;
200
201 let powers_of_x = util::powers_of(&x, degree as usize);
202
203 for (i, x_i) in powers_of_x.iter().enumerate() {
204 assert_eq!(*x_i, x.pow(&[i as u64, 0, 0, 0]))
205 }
206
207 let last_element = powers_of_x.last().unwrap();
208 assert_eq!(*last_element, x.pow(&[degree, 0, 0, 0]))
209 }
210
211 #[test]
212 fn test_serialise_deserialise_public_parameter() {
213 let pp = PublicParameters::setup(1 << 7, &mut OsRng).unwrap();
214
215 let got_pp = PublicParameters::from_slice(&pp.to_var_bytes()).unwrap();
216
217 assert_eq!(got_pp.commit_key.powers_of_g, pp.commit_key.powers_of_g);
218 assert_eq!(got_pp.opening_key.g, pp.opening_key.g);
219 assert_eq!(got_pp.opening_key.h, pp.opening_key.h);
220 assert_eq!(got_pp.opening_key.beta_h, pp.opening_key.beta_h);
221 }
222
223 #[test]
224 fn public_parameters_bytes_unchecked() {
225 let pp = PublicParameters::setup(1 << 7, &mut OsRng).unwrap();
226
227 let pp_p = unsafe {
228 let bytes = pp.to_raw_var_bytes();
229 PublicParameters::from_slice_unchecked(&bytes)
230 };
231
232 assert_eq!(pp.commit_key, pp_p.commit_key);
233 assert_eq!(pp.opening_key.g, pp_p.opening_key.g);
234 assert_eq!(pp.opening_key.h, pp_p.opening_key.h);
235 assert_eq!(pp.opening_key.beta_h, pp_p.opening_key.beta_h);
236 }
237}