use crate::{
circuit::{POSWCircuit, POSWCircuitParameters},
error::PoswError,
};
use snarkvm_algorithms::{
crh::sha256d_to_u64,
traits::{MaskedMerkleParameters, SNARK},
};
use snarkvm_curves::{
bls12_377::Fr,
edwards_bls12::{EdwardsProjective, Fq},
traits::PairingEngine,
};
use snarkvm_dpc::block::{
pedersen_merkle_tree::{pedersen_merkle_root_hash_with_leaves, PedersenMerkleRootHash, PARAMS},
MaskedMerkleTreeParameters,
};
use snarkvm_fields::{PrimeField, ToConstraintField};
use snarkvm_gadgets::{
algorithms::crh::PedersenCompressedCRHGadget,
curves::edwards_bls12::EdwardsBls12Gadget,
traits::algorithms::MaskedCRHGadget,
};
use snarkvm_marlin::snark::SRS;
use snarkvm_parameters::{
testnet1::{PoswSNARKPKParameters, PoswSNARKVKParameters},
traits::Parameter,
};
use snarkvm_polycommit::optional_rng::OptionalRng;
use snarkvm_profiler::{end_timer, start_timer};
use snarkvm_utilities::{
bytes::{FromBytes, ToBytes},
to_bytes,
};
use blake2::{digest::Digest, Blake2s};
use rand::{rngs::OsRng, Rng};
use std::marker::PhantomData;
pub fn commit(nonce: u32, root: &PedersenMerkleRootHash) -> Vec<u8> {
let mut h = Blake2s::new();
h.update(&nonce.to_le_bytes());
h.update(root.0.as_ref());
h.finalize().to_vec()
}
pub type M = MaskedMerkleTreeParameters;
pub type HG = PedersenCompressedCRHGadget<EdwardsProjective, Fq, EdwardsBls12Gadget>;
pub type F = Fr;
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct Posw<S, F, M, HG, CP>
where
S: SNARK,
F: PrimeField,
M: MaskedMerkleParameters,
HG: MaskedCRHGadget<M::H, F>,
CP: POSWCircuitParameters,
{
pub pk: Option<S::ProvingKey>,
pub vk: S::PreparedVerifyingKey,
_circuit: PhantomData<POSWCircuit<F, M, HG, CP>>,
}
impl<S, CP> Posw<S, F, M, HG, CP>
where
S: SNARK,
CP: POSWCircuitParameters,
{
pub fn verify_only() -> Result<Self, PoswError> {
let params = PoswSNARKVKParameters::load_bytes()?;
let vk = S::VerifyingKey::read(¶ms[..])?;
Ok(Self {
pk: None,
vk: vk.into(),
_circuit: PhantomData,
})
}
pub fn load() -> Result<Self, PoswError> {
let vk = S::VerifyingKey::read(&PoswSNARKVKParameters::load_bytes()?[..])?;
let pk = S::ProvingKey::read(&PoswSNARKPKParameters::load_bytes()?[..])?;
Ok(Self {
pk: Some(pk),
vk: vk.into(),
_circuit: PhantomData,
})
}
fn circuit_from(nonce: u32, leaves: &[[u8; 32]]) -> POSWCircuit<F, M, HG, CP> {
let (root, leaves) = pedersen_merkle_root_hash_with_leaves(leaves);
let mask = commit(nonce, &root.into());
let leaves = leaves.into_iter().map(Some).collect();
POSWCircuit {
leaves,
merkle_parameters: PARAMS.clone(),
mask: Some(mask),
root: Some(root),
field_type: PhantomData,
crh_gadget_type: PhantomData,
circuit_parameters_type: PhantomData,
}
}
fn check_difficulty(&self, proof: &[u8], difficulty_target: u64) -> bool {
let hash_result = sha256d_to_u64(proof);
hash_result <= difficulty_target
}
}
impl<S, CP> Posw<S, F, M, HG, CP>
where
S: SNARK<VerifierInput = Vec<F>, AllocatedCircuit = POSWCircuit<F, M, HG, CP>>,
CP: POSWCircuitParameters,
{
#[deprecated]
pub fn setup<R: Rng>(rng: &mut R) -> Result<Self, PoswError>
where
S: SNARK<Circuit = POSWCircuit<F, M, HG, CP>>,
{
let params = S::setup(
&POSWCircuit {
leaves: vec![None; 0],
merkle_parameters: PARAMS.clone(),
mask: None,
root: None,
field_type: PhantomData,
crh_gadget_type: PhantomData,
circuit_parameters_type: PhantomData,
},
rng,
)?;
Ok(Self {
pk: Some(params.0),
vk: params.1,
_circuit: PhantomData,
})
}
pub fn index<E>(srs: SRS<E>) -> Result<Self, PoswError>
where
E: PairingEngine,
S: SNARK<Circuit = (POSWCircuit<F, M, HG, CP>, SRS<E>)>,
{
let params = S::setup(
&(
POSWCircuit {
leaves: vec![None; 0],
merkle_parameters: PARAMS.clone(),
mask: None,
root: None,
field_type: PhantomData,
crh_gadget_type: PhantomData,
circuit_parameters_type: PhantomData,
},
srs,
),
&mut OptionalRng(None::<OsRng>),
)?;
Ok(Self {
pk: Some(params.0),
vk: params.1,
_circuit: PhantomData,
})
}
pub fn mine<R: Rng>(
&self,
subroots: &[[u8; 32]],
difficulty_target: u64, rng: &mut R,
max_nonce: u32,
) -> Result<(u32, Vec<u8>), PoswError> {
let pk = self.pk.as_ref().expect("tried to mine without a PK set up");
let mut nonce;
let mut proof;
let mut serialized_proof;
loop {
nonce = rng.gen_range(0..max_nonce);
proof = Self::prove(&pk, nonce, subroots, rng)?;
serialized_proof = to_bytes!(proof)?;
if self.check_difficulty(&serialized_proof, difficulty_target) {
break;
}
}
Ok((nonce, serialized_proof))
}
fn prove<R: Rng>(
pk: &S::ProvingKey,
nonce: u32,
subroots: &[[u8; 32]],
rng: &mut R,
) -> Result<S::Proof, PoswError> {
let circuit = Self::circuit_from(nonce, subroots);
let proof_timer = start_timer!(|| "POSW proof");
let proof = S::prove(pk, &circuit, rng)?;
end_timer!(proof_timer);
Ok(proof)
}
pub fn verify(
&self,
nonce: u32,
proof: &S::Proof,
pedersen_merkle_root: &PedersenMerkleRootHash,
) -> Result<(), PoswError> {
let mask = commit(nonce, pedersen_merkle_root);
let merkle_root = F::read(&pedersen_merkle_root.0[..])?;
let inputs = [mask.to_field_elements()?, vec![merkle_root]].concat();
let res = S::verify(&self.vk, &inputs, &proof)?;
if !res {
return Err(PoswError::PoswVerificationFailed);
}
Ok(())
}
}