Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Proof of Work #75

Open
wants to merge 12 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ on:
pull_request:
push:
branches:
- master
- main
env:
RUST_BACKTRACE: 1

Expand Down
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@

### Features

- [\#75](https://github.com/arkworks-rs/crypto-primitives/pull/75) Add Cryptographic Hash and Proof of Work.
- [\#59](https://github.com/arkworks-rs/crypto-primitives/pull/59) Implement `TwoToOneCRHScheme` for Bowe-Hopwood CRH.
- [\#60](https://github.com/arkworks-rs/crypto-primitives/pull/60) Merkle tree no longer requires CRH to input and output bytes. Leaf can be any raw input of CRH, such as field elements.
- [\#67](https://github.com/arkworks-rs/crypto-primitives/pull/67) User can access or replace leaf index variable in `PathVar`.
Expand Down
22 changes: 22 additions & 0 deletions src/cryptographic_hash/constraints/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
use ark_std::borrow::Borrow;

use ark_ff::PrimeField;
use ark_relations::r1cs::{ConstraintSystemRef, SynthesisError};

pub mod poseidon;

/// R1CS Gadget for Crypto Hash.
pub trait CryptoHashGadget<CF: PrimeField> {
type Parameters;
/// Input of the hash
type InputVar: ?Sized;
/// Outout of the Hash
type OutputVar;

/// Given the input var and parameters, compute the output var.
fn digest<T: Borrow<Self::InputVar>>(
cs: ConstraintSystemRef<CF>,
param: &Self::Parameters,
input: T,
) -> Result<Self::OutputVar, SynthesisError>;
}
73 changes: 73 additions & 0 deletions src/cryptographic_hash/constraints/poseidon.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
use ark_std::{borrow::Borrow, marker::PhantomData};

use ark_ff::PrimeField;
use ark_r1cs_std::fields::fp::FpVar;
use ark_relations::r1cs::{ConstraintSystemRef, SynthesisError};
use ark_sponge::{
constraints::{AbsorbGadget, CryptographicSpongeVar},
poseidon::{constraints::PoseidonSpongeVar, PoseidonParameters},
};

use super::CryptoHashGadget;

pub struct PoseidonHashGadget<F: PrimeField, I: AbsorbGadget<F>> {
_field: PhantomData<F>,
_input: PhantomData<I>,
}

impl<F: PrimeField, I: AbsorbGadget<F>> CryptoHashGadget<F> for PoseidonHashGadget<F, I> {
type Parameters = PoseidonParameters<F>;

type InputVar = I;

type OutputVar = FpVar<F>;

fn digest<T: Borrow<Self::InputVar>>(
cs: ConstraintSystemRef<F>,
params: &Self::Parameters,
input: T,
) -> Result<Self::OutputVar, SynthesisError> {
let input = input.borrow();
let mut sponge = PoseidonSpongeVar::new(cs, params);
sponge.absorb(input)?;

let res = sponge.squeeze_field_elements(1)?;
Ok(res[0].clone())
}
}

#[cfg(test)]
mod tests {
use crate::{
ark_std::UniformRand,
cryptographic_hash::{constraints::CryptoHashGadget, poseidon::PoseidonHash, CryptoHash},
merkle_tree::tests::test_utils::poseidon_parameters,
};
use ark_ed_on_bls12_381::Fr;
use ark_r1cs_std::{alloc::AllocVar, fields::fp::FpVar, R1CSVar};
use ark_relations::r1cs::ConstraintSystem;
use ark_std::test_rng;

use super::PoseidonHashGadget;

#[test]
fn test_digest() {
let cs = ConstraintSystem::new_ref();
let mut rng = test_rng();
let input = (0..14).map(|_| Fr::rand(&mut rng)).collect::<Vec<_>>();
let input_var = input
.iter()
.map(|x| FpVar::new_witness(cs.clone(), || Ok(*x)).unwrap())
.collect::<Vec<_>>();

let param = poseidon_parameters();

let native_result = PoseidonHash::<_, &[Fr]>::digest(&param, input.as_slice());
let var_result =
PoseidonHashGadget::<_, &[FpVar<_>]>::digest(cs.clone(), &param, input_var.as_slice())
.unwrap();

assert_eq!(native_result, var_result.value().unwrap());
assert!(cs.is_satisfied().unwrap());
}
}
29 changes: 29 additions & 0 deletions src/cryptographic_hash/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
pub mod poseidon;

#[cfg(feature = "r1cs")]
pub mod constraints;

use ark_std::borrow::Borrow;

use ark_std::rand::Rng;

/// Any cryptographic hash implementation will satisfy those two properties:
/// - **Preimage Resistance**: For all adversary, given y = H(x) where x is
/// random, the probability to find z such that H(z) = y is negligible.
/// - **Collision Resistant**: It's computationally infeasible to find two
/// distinct inputs to lead to same output. This property is also satisfied by
/// CRH trait implementors.
/// - **One-way**:
pub trait CryptoHash {
/// Parameter for the crypto hash.
type Parameters: Sync;
/// Input of the hash.
type Input: Sync + ?Sized;
/// Output of the Hash.
type Output;
/// Generate the parameter for the crypto hash using `rng`.
fn setup<R: Rng>(rng: &mut R) -> &Self::Parameters;

/// Given the input and parameters, compute the output.
fn digest<T: Borrow<Self::Input>>(param: &Self::Parameters, input: T) -> Self::Output;
}
41 changes: 41 additions & 0 deletions src/cryptographic_hash/poseidon.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
use ark_std::borrow::Borrow;

use ark_std::marker::PhantomData;

use ark_ff::PrimeField;
use ark_sponge::{
poseidon::{PoseidonParameters, PoseidonSponge},
Absorb, CryptographicSponge,
};

use super::CryptoHash;

/// A wrapper to poseidon cryptographic sponge.
pub struct PoseidonHash<F: PrimeField, I: Absorb + Sync> {
_field: PhantomData<F>,
_input: PhantomData<I>,
}

impl<F: PrimeField, I: Absorb + Sync> CryptoHash for PoseidonHash<F, I> {
type Parameters = PoseidonParameters<F>;

type Input = I;

type Output = F;

fn setup<R: ark_std::rand::Rng>(_rng: &mut R) -> &Self::Parameters {
// automatic generation of parameters are not implemented yet
// therefore, the developers must specify the parameters themselves
unimplemented!()
}

fn digest<T: Borrow<Self::Input>>(param: &Self::Parameters, input: T) -> Self::Output {
let input = input.borrow();

let mut sponge = PoseidonSponge::new(param);
sponge.absorb(input);

let res = sponge.squeeze_field_elements::<F>(1);
res[0]
}
}
6 changes: 6 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,12 @@ pub mod crh;
#[cfg(feature = "merkle_tree")]
pub mod merkle_tree;

#[cfg(feature = "cryptographic_hash")]
pub mod cryptographic_hash;

#[cfg(feature = "proof_of_work")]
pub mod proof_of_work;

#[cfg(feature = "encryption")]
pub mod encryption;

Expand Down
Loading