Skip to content

Commit

Permalink
Merge pull request ProvableHQ#1217 from AleoHQ/feat/coinbase-map
Browse files Browse the repository at this point in the history
Adds puzzle commitments to `BlockStore`, adds serializers on `PuzzleCommitment`
  • Loading branch information
howardwu authored Oct 26, 2022
2 parents 7ade894 + 4425295 commit e1150d1
Show file tree
Hide file tree
Showing 19 changed files with 446 additions and 86 deletions.
18 changes: 9 additions & 9 deletions synthesizer/src/block/bytes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,20 +33,20 @@ impl<N: Network> FromBytes for Block<N> {
let header = FromBytes::read_le(&mut reader)?;
let transactions = FromBytes::read_le(&mut reader)?;

// Write the coinbase proof.
// Write the coinbase.
let coinbase_variant = u8::read_le(&mut reader)?;
let coinbase_proof = match coinbase_variant {
let coinbase = match coinbase_variant {
0 => None,
1 => Some(FromBytes::read_le(&mut reader)?),
_ => return Err(error("Invalid coinbase proof variant")),
_ => return Err(error("Invalid coinbase variant")),
};

// Write the signature.
let signature = FromBytes::read_le(&mut reader)?;

// Construct the block.
let block = Self::from(previous_hash, header, transactions, coinbase_proof, signature)
.map_err(|e| error(e.to_string()))?;
let block =
Self::from(previous_hash, header, transactions, coinbase, signature).map_err(|e| error(e.to_string()))?;

// Ensure the block hash matches.
match block_hash == block.hash() {
Expand All @@ -69,12 +69,12 @@ impl<N: Network> ToBytes for Block<N> {
self.header.write_le(&mut writer)?;
self.transactions.write_le(&mut writer)?;

// Write the coinbase proof.
match self.coinbase_proof {
// Write the coinbase solution.
match self.coinbase {
None => 0u8.write_le(&mut writer)?,
Some(ref coinbase_proof) => {
Some(ref coinbase) => {
1u8.write_le(&mut writer)?;
coinbase_proof.write_le(&mut writer)?;
coinbase.write_le(&mut writer)?;
}
}

Expand Down
10 changes: 5 additions & 5 deletions synthesizer/src/block/genesis.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,11 +44,11 @@ impl<N: Network> Block<N> {
// Prepare the previous block hash.
let previous_hash = N::BlockHash::default();

// Prepare the coinbase proof.
let coinbase_proof = None; // The genesis block does not require a coinbase proof.
// Prepare the coinbase solution.
let coinbase_solution = None; // The genesis block does not require a coinbase solution.

// Construct the block.
let block = Self::new(private_key, previous_hash, header, transactions, coinbase_proof, rng)?;
let block = Self::new(private_key, previous_hash, header, transactions, coinbase_solution, rng)?;
// Ensure the block is valid genesis block.
match block.is_genesis() {
true => Ok(block),
Expand All @@ -64,8 +64,8 @@ impl<N: Network> Block<N> {
&& self.header.is_genesis()
// Ensure there is 1 transaction in the genesis block.
&& self.transactions.len() == 1
// Ensure the coinbase proof does not exist.
&& self.coinbase_proof.is_none()
// Ensure the coinbase solution does not exist.
&& self.coinbase.is_none()
}
}

Expand Down
30 changes: 15 additions & 15 deletions synthesizer/src/block/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,20 +62,20 @@ pub struct Block<N: Network> {
header: Header<N>,
/// The transactions in this block.
transactions: Transactions<N>,
/// The coinbase proof.
coinbase_proof: Option<CoinbaseSolution<N>>,
/// The coinbase solution.
coinbase: Option<CoinbaseSolution<N>>,
/// The signature for this block.
signature: Signature<N>,
}

impl<N: Network> Block<N> {
/// Initializes a new block from a given previous hash, header, and transactions list.
/// Initializes a new block from a given previous hash, header, transactions, coinbase, and signature.
pub fn new<R: Rng + CryptoRng>(
private_key: &PrivateKey<N>,
previous_hash: N::BlockHash,
header: Header<N>,
transactions: Transactions<N>,
coinbase_proof: Option<CoinbaseSolution<N>>,
coinbase: Option<CoinbaseSolution<N>>,
rng: &mut R,
) -> Result<Self> {
// Ensure the block is not empty.
Expand All @@ -85,15 +85,15 @@ impl<N: Network> Block<N> {
// Sign the block hash.
let signature = private_key.sign(&[block_hash], rng)?;
// Construct the block.
Self::from(previous_hash, header, transactions, coinbase_proof, signature)
Self::from(previous_hash, header, transactions, coinbase, signature)
}

/// Initializes a new block from a given previous hash, header, and transactions list.
/// Initializes a new block from a given previous hash, header, transactions, coinbase, and signature.
pub fn from(
previous_hash: N::BlockHash,
header: Header<N>,
transactions: Transactions<N>,
coinbase_proof: Option<CoinbaseSolution<N>>,
coinbase: Option<CoinbaseSolution<N>>,
signature: Signature<N>,
) -> Result<Self> {
// Ensure the block is not empty.
Expand All @@ -105,18 +105,18 @@ impl<N: Network> Block<N> {
// Ensure the signature is valid.
ensure!(signature.verify(&address, &[block_hash]), "Invalid signature for block {}", header.height());

// Ensure that coinbase accumulator matches the coinbase proof.
let expected_accumulator_point = match &coinbase_proof {
Some(coinbase_proof) => coinbase_proof.to_accumulator_point()?,
// Ensure that coinbase accumulator matches the coinbase solution.
let expected_accumulator_point = match &coinbase {
Some(coinbase_solution) => coinbase_solution.to_accumulator_point()?,
None => Field::<N>::zero(),
};
ensure!(
header.coinbase_accumulator_point() == expected_accumulator_point,
"The coinbase accumulator point in the block header does not correspond to the given coinbase proof"
"The coinbase accumulator point in the block header does not correspond to the given coinbase solution"
);

// Construct the block.
Ok(Self { block_hash: block_hash.into(), previous_hash, header, transactions, coinbase_proof, signature })
Ok(Self { block_hash: block_hash.into(), previous_hash, header, transactions, coinbase, signature })
}
}

Expand All @@ -131,9 +131,9 @@ impl<N: Network> Block<N> {
self.previous_hash
}

/// Returns the coinbase proof.
pub const fn coinbase_proof(&self) -> Option<&CoinbaseSolution<N>> {
self.coinbase_proof.as_ref()
/// Returns the coinbase solution.
pub const fn coinbase(&self) -> Option<&CoinbaseSolution<N>> {
self.coinbase.as_ref()
}

/// Returns the signature.
Expand Down
8 changes: 4 additions & 4 deletions synthesizer/src/block/serialize.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,8 @@ impl<N: Network> Serialize for Block<N> {
block.serialize_field("header", &self.header)?;
block.serialize_field("transactions", &self.transactions)?;

if let Some(coinbase_proof) = self.coinbase_proof() {
block.serialize_field("coinbase_proof", coinbase_proof)?;
if let Some(coinbase) = &self.coinbase {
block.serialize_field("coinbase", coinbase)?;
}

block.serialize_field("signature", &self.signature)?;
Expand All @@ -53,8 +53,8 @@ impl<'de, N: Network> Deserialize<'de> for Block<N> {
serde_json::from_value(block["previous_hash"].take()).map_err(de::Error::custom)?,
serde_json::from_value(block["header"].take()).map_err(de::Error::custom)?,
serde_json::from_value(block["transactions"].take()).map_err(de::Error::custom)?,
match block["coinbase_proof"].as_str() {
Some(coinbase_proof) => Some(serde_json::from_str(coinbase_proof).map_err(de::Error::custom)?),
match block["coinbase"].as_str() {
Some(coinbase) => Some(serde_json::from_str(coinbase).map_err(de::Error::custom)?),
None => None,
},
serde_json::from_value(block["signature"].take()).map_err(de::Error::custom)?,
Expand Down
2 changes: 1 addition & 1 deletion synthesizer/src/coinbase_puzzle/hash.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ pub fn hash_to_polynomial<F: PrimeField>(input: &[u8], degree: u32) -> DensePoly
DensePolynomial::from_coefficients_vec(coefficients)
}

pub fn hash_commitment<E: PairingEngine>(commitment: KZGCommitment<E>) -> Result<E::Fr> {
pub fn hash_commitment<E: PairingEngine>(commitment: &KZGCommitment<E>) -> Result<E::Fr> {
// Convert the commitment into bytes.
let mut bytes = Vec::with_capacity(96);
commitment.serialize_uncompressed(&mut bytes)?;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ impl<N: Network> FromBytes for CoinbaseSolution<N> {

let proof = KZGProof::read_le(&mut reader)?;

Ok(Self { partial_solutions, proof })
Ok(Self::new(partial_solutions, proof))
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ impl<N: Network> CoinbaseSolution<N> {
}

/// Returns the cumulative sum of the prover solutions.
pub fn to_cumulative_target(&self) -> Result<u128> {
pub fn to_cumulative_proof_target(&self) -> Result<u128> {
// Compute the cumulative target as a u128.
self.partial_solutions.iter().try_fold(0u128, |cumulative, solution| {
cumulative.checked_add(solution.to_target()? as u128).ok_or_else(|| anyhow!("Cumulative target overflowed"))
Expand All @@ -66,7 +66,7 @@ impl<N: Network> CoinbaseSolution<N> {
/// Returns the accumulator challenge point.
pub fn to_accumulator_point(&self) -> Result<Field<N>> {
let mut challenge_points =
hash_commitments(self.partial_solutions.iter().map(|solution| solution.commitment()))?;
hash_commitments(self.partial_solutions.iter().map(|solution| *solution.commitment()))?;
ensure!(challenge_points.len() == self.partial_solutions.len() + 1, "Invalid number of challenge points");

// Pop the last challenge point as the accumulator challenge point.
Expand Down
5 changes: 3 additions & 2 deletions synthesizer/src/coinbase_puzzle/helpers/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,9 @@ pub use partial_solution::*;
mod prover_solution;
pub use prover_solution::*;

mod puzzle_commitment;
pub use puzzle_commitment::*;

use crate::coinbase_puzzle::{hash_commitment, hash_commitments, CoinbasePuzzle};
use console::{account::Address, prelude::*, types::Field};
use snarkvm_algorithms::{
Expand All @@ -41,8 +44,6 @@ use std::{
io::{Read, Result as IoResult, Write},
};

/// The commitment to the polynomial.
pub type PuzzleCommitment<N> = KZGCommitment<<N as Environment>::PairingCurve>;
/// The proof of opening the polynomial, for the solution.
pub type PuzzleProof<N> = KZGProof<<N as Environment>::PairingCurve>;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ impl<N: Network> FromBytes for PartialSolution<N> {
let nonce = u64::read_le(&mut reader)?;
let commitment = KZGCommitment::read_le(&mut reader)?;

Ok(Self { address, nonce, commitment })
Ok(Self::new(address, nonce, commitment))
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,8 @@ pub struct PartialSolution<N: Network> {

impl<N: Network> PartialSolution<N> {
/// Initializes a new instance of the partial solution.
pub const fn new(address: Address<N>, nonce: u64, commitment: PuzzleCommitment<N>) -> Self {
Self { address, nonce, commitment }
pub fn new<C: Into<PuzzleCommitment<N>>>(address: Address<N>, nonce: u64, commitment: C) -> Self {
Self { address, nonce, commitment: commitment.into() }
}

/// Returns the address of the prover.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ impl<N: Network> Serialize for PartialSolution<N> {
let mut partial_prover_solution = serializer.serialize_struct("PartialSolution", 3)?;
partial_prover_solution.serialize_field("address", &self.address)?;
partial_prover_solution.serialize_field("nonce", &self.nonce)?;
partial_prover_solution.serialize_field("commitment", &self.commitment.0)?;
partial_prover_solution.serialize_field("commitment", &self.commitment)?;
partial_prover_solution.end()
}
false => ToBytesSerializer::serialize_with_size_encoding(self, serializer),
Expand All @@ -41,10 +41,8 @@ impl<'de, N: Network> Deserialize<'de> for PartialSolution<N> {
Ok(Self::new(
serde_json::from_value(partial_prover_solution["address"].clone()).map_err(de::Error::custom)?,
serde_json::from_value(partial_prover_solution["nonce"].clone()).map_err(de::Error::custom)?,
KZGCommitment(
serde_json::from_value(partial_prover_solution["commitment"].clone())
.map_err(de::Error::custom)?,
),
serde_json::from_value::<PuzzleCommitment<N>>(partial_prover_solution["commitment"].clone())
.map_err(de::Error::custom)?,
))
}
false => FromBytesDeserializer::<Self>::deserialize_with_size_encoding(deserializer, "partial solution"),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ impl<N: Network> FromBytes for ProverSolution<N> {
let partial_solution: PartialSolution<N> = FromBytes::read_le(&mut reader)?;
let proof = KZGProof::read_le(&mut reader)?;

Ok(Self { partial_solution, proof })
Ok(Self::new(partial_solution, proof))
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ impl<N: Network> ProverSolution<N> {
let prover_polynomial = self.partial_solution.to_prover_polynomial(epoch_challenge)?;

// Compute the challenge point.
let challenge_point = hash_commitment(self.commitment())?;
let challenge_point = hash_commitment(&self.commitment())?;

// Evaluate the epoch and prover polynomials at the challenge point.
let epoch_evaluation = epoch_challenge.epoch_polynomial().evaluate(challenge_point);
Expand Down
56 changes: 56 additions & 0 deletions synthesizer/src/coinbase_puzzle/helpers/puzzle_commitment/bytes.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
// Copyright (C) 2019-2022 Aleo Systems Inc.
// This file is part of the snarkVM library.

// The snarkVM library is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.

// The snarkVM library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with the snarkVM library. If not, see <https://www.gnu.org/licenses/>.

use super::*;

impl<N: Network> FromBytes for PuzzleCommitment<N> {
/// Reads the puzzle commitment from the buffer.
fn read_le<R: Read>(mut reader: R) -> IoResult<Self> {
let commitment = KZGCommitment::read_le(&mut reader)?;

Ok(Self::new(commitment))
}
}

impl<N: Network> ToBytes for PuzzleCommitment<N> {
/// Writes the puzzle commitment to the buffer.
fn write_le<W: Write>(&self, mut writer: W) -> IoResult<()> {
self.commitment.write_le(&mut writer)
}
}

#[cfg(test)]
mod tests {
use super::*;
use console::network::Testnet3;

type CurrentNetwork = Testnet3;

#[test]
fn test_bytes() -> Result<()> {
let mut rng = TestRng::default();
// Sample a new puzzle commitment.
let expected = PuzzleCommitment::<CurrentNetwork>::new(KZGCommitment(rng.gen()));

// Check the byte representation.
let expected_bytes = expected.to_bytes_le()?;
assert_eq!(expected_bytes.len(), 48);
assert_eq!(expected, PuzzleCommitment::read_le(&expected_bytes[..])?);
assert!(PuzzleCommitment::<CurrentNetwork>::read_le(&expected_bytes[1..]).is_err());

Ok(())
}
}
50 changes: 50 additions & 0 deletions synthesizer/src/coinbase_puzzle/helpers/puzzle_commitment/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
// Copyright (C) 2019-2022 Aleo Systems Inc.
// This file is part of the snarkVM library.

// The snarkVM library is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.

// The snarkVM library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with the snarkVM library. If not, see <https://www.gnu.org/licenses/>.

mod bytes;
mod serialize;
mod string;

use super::*;

/// A coinbase puzzle commitment to a polynomial.
#[derive(Copy, Clone, Eq, PartialEq, Hash)]
pub struct PuzzleCommitment<N: Network> {
/// The commitment for the solution.
commitment: KZGCommitment<<N as Environment>::PairingCurve>,
}

impl<N: Network> PuzzleCommitment<N> {
/// Initializes a new instance of the puzzle commitment.
pub const fn new(commitment: KZGCommitment<<N as Environment>::PairingCurve>) -> Self {
Self { commitment }
}
}

impl<N: Network> From<KZGCommitment<<N as Environment>::PairingCurve>> for PuzzleCommitment<N> {
/// Initializes a new instance of the puzzle commitment.
fn from(commitment: KZGCommitment<<N as Environment>::PairingCurve>) -> Self {
Self::new(commitment)
}
}

impl<N: Network> Deref for PuzzleCommitment<N> {
type Target = KZGCommitment<<N as Environment>::PairingCurve>;

fn deref(&self) -> &Self::Target {
&self.commitment
}
}
Loading

0 comments on commit e1150d1

Please sign in to comment.