Skip to content

Commit

Permalink
Add serialisation (#278)
Browse files Browse the repository at this point in the history
* Implement FromBytes and ToBytes for ProverKey and VerifierKey

* Implement FromBytes and ToBytes for srs

* Implement FromBytes and ToBytes for Proof

* Add serde macro

* Implement Serde for Proof, SRS, ProverKey and VerifierKey
  • Loading branch information
kevaundray authored Aug 10, 2020
1 parent 1702222 commit a8d8f3e
Show file tree
Hide file tree
Showing 17 changed files with 1,058 additions and 34 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

### Added
- `Anyhow` & `thiserror` for error handling support.
- Serialisation methods for the crate public structures &
`serde` support.

### Removed
- `failure` for error support since has been deprecated.


## [0.2.6] - 03-08-20

### Changed
Expand Down
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ rayon = "1.3.0"
anyhow = "1.0.32"
dusk-jubjub = "0.3.5"
thiserror = "1.0"
serde = "1.0"

[dev-dependencies]
rand = "0.7.0"
Expand Down
76 changes: 76 additions & 0 deletions src/commitment_scheme/kzg10/key.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,39 @@ pub struct CommitKey {
}

impl CommitKey {
/// Serialises the commitment Key to a byte slice
pub fn to_bytes(&self) -> Vec<u8> {
use crate::serialisation::{write_g1_affine, write_u64};

let mut bytes = Vec::with_capacity(self.powers_of_g.len() * 48);

write_u64(self.powers_of_g.len() as u64, &mut bytes);

for point in self.powers_of_g.iter() {
write_g1_affine(point, &mut bytes);
}

bytes
}

/// Deserialises a bytes slice to a Commitment Key
pub fn from_bytes(bytes: &[u8]) -> Result<CommitKey, Error> {
use crate::serialisation::{read_g1_affine, read_u64};

let (num_points, rest) = read_u64(&bytes)?;

let mut powers_of_g = Vec::with_capacity(num_points as usize);

let mut remaining: &[u8] = &rest;
for _ in 0..num_points {
let (point, rest) = read_g1_affine(remaining)?;
powers_of_g.push(point);
remaining = rest;
}

Ok(CommitKey { powers_of_g })
}

/// Returns the maximum degree polynomial that you can commit to.
pub fn max_degree(&self) -> usize {
self.powers_of_g.len() - 1
Expand Down Expand Up @@ -159,6 +192,49 @@ impl CommitKey {
}

impl OpeningKey {
pub(crate) fn new(g: G1Affine, h: G2Affine, beta_h: G2Affine) -> OpeningKey {
let prepared_h: G2Prepared = G2Prepared::from(h);
let prepared_beta_h = G2Prepared::from(beta_h);
OpeningKey {
g,
h,
beta_h,
prepared_beta_h,
prepared_h,
}
}
/// Serialises an Opening Key to bytes
pub fn to_bytes(&self) -> Vec<u8> {
use crate::serialisation::{write_g1_affine, write_g2_affine};
let mut bytes = Vec::with_capacity(OpeningKey::serialised_size());

write_g1_affine(&self.g, &mut bytes);
write_g2_affine(&self.h, &mut bytes);
write_g2_affine(&self.beta_h, &mut bytes);

bytes
}

pub(crate) fn serialised_size() -> usize {
const NUM_G2: usize = 2;
const NUM_G1: usize = 1;
const G1_SIZE: usize = 48;
const G2_SIZE: usize = 96;

NUM_G1 * G1_SIZE + NUM_G2 * G2_SIZE
}

/// Deserialises a byte slice into an Opening Key
pub fn from_bytes(bytes: &[u8]) -> Result<OpeningKey, Error> {
use crate::serialisation::{read_g1_affine, read_g2_affine};

let (g, rest) = read_g1_affine(&bytes)?;
let (h, rest) = read_g2_affine(&rest)?;
let (beta_h, _) = read_g2_affine(&rest)?;

Ok(OpeningKey::new(g, h, beta_h))
}

/// Checks that a polynomial `p` was evaluated at a point `z` and returned the value specified `v`.
/// ie. v = p(z).
pub fn check(&self, point: Scalar, proof: Proof) -> bool {
Expand Down
53 changes: 43 additions & 10 deletions src/commitment_scheme/kzg10/srs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,12 @@ use super::{
};
use crate::util;
use anyhow::{Error, Result};
use dusk_bls12_381::{G1Affine, G1Projective, G2Affine, G2Prepared};
use dusk_bls12_381::{G1Affine, G1Projective, G2Affine};
use rand_core::RngCore;

use serde::de::Visitor;
use serde::{self, Deserialize, Deserializer, Serialize, Serializer};

/// The Public Parameters can also be referred to as the Structured Reference String (SRS).
/// It is available to both the prover and verifier and allows the verifier to
/// efficiently verify and make claims about polynomials up to and including a configured degree.
Expand All @@ -19,6 +22,8 @@ pub struct PublicParameters {
pub opening_key: OpeningKey,
}

impl_serde!(PublicParameters);

impl PublicParameters {
/// Setup generates the public parameters using a random number generator.
/// This method will in most cases be used for testing and exploration.
Expand Down Expand Up @@ -52,23 +57,38 @@ impl PublicParameters {
// Compute beta*G2 element and stored cached elements for verifying multiple proofs.
let h: G2Affine = util::random_g2_point(&mut rng).into();
let beta_h: G2Affine = (h * beta).into();
let prepared_h: G2Prepared = G2Prepared::from(h);
let prepared_beta_h = G2Prepared::from(beta_h);

Ok(PublicParameters {
commit_key: CommitKey {
powers_of_g: normalised_g,
},
opening_key: OpeningKey {
g: g.into(),
h,
beta_h,
prepared_h,
prepared_beta_h,
},
opening_key: OpeningKey::new(g.into(), h, beta_h),
})
}

/// Deserialise a slice of bytes into a Public Parameter struct
pub fn from_bytes(bytes: &[u8]) -> Result<PublicParameters, Error> {
let opening_key_bytes = &bytes[0..OpeningKey::serialised_size()];
let commit_key_bytes = &bytes[OpeningKey::serialised_size()..];

let opening_key = OpeningKey::from_bytes(opening_key_bytes)?;
let commit_key = CommitKey::from_bytes(commit_key_bytes)?;

let pp = PublicParameters {
opening_key,
commit_key,
};

Ok(pp)
}

/// Serialises a Public Parameter struct into a slice of bytes
pub fn to_bytes(&self) -> Vec<u8> {
let mut bytes = self.opening_key.to_bytes();
bytes.extend(self.commit_key.to_bytes());
bytes
}

/// Trim truncates the prover key to allow the prover to commit to polynomials up to the
/// and including the truncated degree.
/// Returns an error if the truncated degree is larger than the public parameters configured degree.
Expand Down Expand Up @@ -101,4 +121,17 @@ mod test {
let last_element = powers_of_x.last().unwrap();
assert_eq!(*last_element, x.pow(&[degree, 0, 0, 0]))
}

#[test]
fn test_serialise_deserialise_public_parameter() {
let pp = PublicParameters::setup(100, &mut rand::thread_rng()).unwrap();

let got_pp = PublicParameters::from_bytes(&pp.to_bytes()).unwrap();

assert_eq!(got_pp.commit_key.powers_of_g, pp.commit_key.powers_of_g);

assert_eq!(got_pp.opening_key.g, pp.opening_key.g);
assert_eq!(got_pp.opening_key.h, pp.opening_key.h);
assert_eq!(got_pp.opening_key.beta_h, pp.opening_key.beta_h);
}
}
15 changes: 0 additions & 15 deletions src/constraint_system/composer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -173,21 +173,6 @@ impl StandardComposer {
var
}

/// Adds the passed `BlsScalar` to the Constraint System as a
/// witness value and constraints it to be equal to the value that
/// was sent.
///
/// This makes easier to work with Public Inputs, since they can just be
/// used as witnesses constrained to a fixed value.
pub fn add_constant_witness(&mut self, s: Scalar) -> Variable {

This comment has been minimized.

Copy link
@CPerezz

CPerezz Aug 11, 2020

Contributor

Is there any reason why this was removed? Or it was just that you didn't rebase to `master``before merging @kevaundray ?

// Allocate and link the Variable and the Scalar values in the
// `Permutation` struct.
let var = self.add_input(s);
// We constraint the witness to be equal to a certain constant value.
self.constrain_to_constant(var, s, Scalar::zero());
var
}

/// Adds a width-3 poly gate.
/// This gate gives total freedom to the end user to implement the corresponding
/// circuits in the most optimized way possible because the under has access to the
Expand Down
4 changes: 4 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,13 +46,17 @@
#![deny(missing_docs)]
#![deny(unsafe_code)]

#[macro_use]
mod macros;

mod bit_iterator;
pub mod commitment_scheme;
pub mod constraint_system;
pub mod fft;
mod permutation;
pub mod prelude;
pub mod proof_system;
mod serialisation;
pub mod transcript;
mod util;

Expand Down
42 changes: 42 additions & 0 deletions src/macros.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
macro_rules! impl_serde {
($w : ident) => {
impl Serialize for $w {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
serializer.serialize_bytes(&self.to_bytes()[..])
}
}

impl<'de> Deserialize<'de> for $w {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
struct StructVisitor;

impl<'de> Visitor<'de> for StructVisitor {
type Value = $w;

fn expecting(
&self,
formatter: &mut ::core::fmt::Formatter,
) -> ::core::fmt::Result {
let struct_name = String::from(stringify!($w));
formatter.write_fmt(format_args!("expected a valid {}", struct_name))
}

fn visit_bytes<E>(self, v: &[u8]) -> Result<$w, E>
where
E: serde::de::Error,
{
return $w::from_bytes(v).map_err(serde::de::Error::custom);
}
}

deserializer.deserialize_bytes(StructVisitor)
}
}
};
}
81 changes: 80 additions & 1 deletion src/proof_system/linearisation_poly.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use crate::fft::{EvaluationDomain, Polynomial};
use crate::proof_system::widget::ProverKey;
use anyhow::{Error, Result};
use dusk_bls12_381::Scalar;

/// Evaluations at points `z` or and `z * root of unity`
pub struct Evaluations {
pub proof: ProofEvaluations,
Expand Down Expand Up @@ -48,6 +48,85 @@ pub struct ProofEvaluations {
pub perm_eval: Scalar,
}

impl ProofEvaluations {
/// Serialises a Proof Evaluation struct to bytes
pub fn to_bytes(&self) -> Vec<u8> {
use crate::serialisation::write_scalar;

let mut bytes = Vec::with_capacity(ProofEvaluations::serialised_size());

write_scalar(&self.a_eval, &mut bytes);
write_scalar(&self.b_eval, &mut bytes);
write_scalar(&self.c_eval, &mut bytes);
write_scalar(&self.d_eval, &mut bytes);
write_scalar(&self.a_next_eval, &mut bytes);
write_scalar(&self.b_next_eval, &mut bytes);
write_scalar(&self.d_next_eval, &mut bytes);
write_scalar(&self.q_arith_eval, &mut bytes);
write_scalar(&self.q_c_eval, &mut bytes);
write_scalar(&self.q_l_eval, &mut bytes);
write_scalar(&self.q_r_eval, &mut bytes);
write_scalar(&self.left_sigma_eval, &mut bytes);
write_scalar(&self.right_sigma_eval, &mut bytes);
write_scalar(&self.out_sigma_eval, &mut bytes);
write_scalar(&self.lin_poly_eval, &mut bytes);
write_scalar(&self.perm_eval, &mut bytes);

bytes
}
/// Deserialises a slice of bytes into a proof Evaluation struct
pub fn from_bytes(bytes: &[u8]) -> Result<ProofEvaluations, Error> {
use crate::serialisation::{read_scalar, SerialisationErrors};

if bytes.len() != ProofEvaluations::serialised_size() {
return Err(SerialisationErrors::NotEnoughBytes.into());
}

let (a_eval, rest) = read_scalar(bytes)?;
let (b_eval, rest) = read_scalar(rest)?;
let (c_eval, rest) = read_scalar(rest)?;
let (d_eval, rest) = read_scalar(rest)?;
let (a_next_eval, rest) = read_scalar(rest)?;
let (b_next_eval, rest) = read_scalar(rest)?;
let (d_next_eval, rest) = read_scalar(rest)?;
let (q_arith_eval, rest) = read_scalar(rest)?;
let (q_c_eval, rest) = read_scalar(rest)?;
let (q_l_eval, rest) = read_scalar(rest)?;
let (q_r_eval, rest) = read_scalar(rest)?;
let (left_sigma_eval, rest) = read_scalar(rest)?;
let (right_sigma_eval, rest) = read_scalar(rest)?;
let (out_sigma_eval, rest) = read_scalar(rest)?;
let (lin_poly_eval, rest) = read_scalar(rest)?;
let (perm_eval, _) = read_scalar(rest)?;

let proof_evals = ProofEvaluations {
a_eval,
b_eval,
c_eval,
d_eval,
a_next_eval,
b_next_eval,
d_next_eval,
q_arith_eval,
q_c_eval,
q_l_eval,
q_r_eval,
left_sigma_eval,
right_sigma_eval,
out_sigma_eval,
lin_poly_eval,
perm_eval,
};
Ok(proof_evals)
}

pub(crate) const fn serialised_size() -> usize {
const NUM_SCALARS: usize = 16;
const SCALAR_SIZE: usize = 32;
NUM_SCALARS * SCALAR_SIZE
}
}

#[allow(clippy::too_many_arguments)]
/// Compute the linearisation polynomial
pub fn compute(
Expand Down
3 changes: 2 additions & 1 deletion src/proof_system/preprocess.rs
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ impl StandardComposer {
{
Ok(())
} else {
Err(PreProcessingError::MismatchedPolyLen.into())
Err(PreProcessingError::MismatchedPolyLen)
}
}
/// These are the parts of preprocessing that the prover must compute
Expand Down Expand Up @@ -171,6 +171,7 @@ impl StandardComposer {
};

let prover_key = widget::ProverKey {
n: domain.size(),
arithmetic: arithmetic_prover_key,
logic: logic_prover_key,
range: range_prover_key,
Expand Down
Loading

0 comments on commit a8d8f3e

Please sign in to comment.