1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
use ark_crypto_primitives::{crh::CRH, Error};
use ark_ff::{fields::PrimeField, to_bytes};
use ark_std::{marker::PhantomData, rand::Rng};

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

#[derive(Default, Clone)]
pub struct Private<F: PrimeField> {
	pub secret: F,
	pub nullifier: F,
}

impl<F: PrimeField> Private<F> {
	pub fn generate<R: Rng>(rng: &mut R) -> Self {
		Self {
			secret: F::rand(rng),
			nullifier: F::rand(rng),
		}
	}

	pub fn new(secret: F, nullifier: F) -> Self {
		Self { secret, nullifier }
	}

	pub fn secret(&self) -> F {
		self.secret
	}

	pub fn nullifier(&self) -> F {
		self.nullifier
	}
}

#[derive(Default, Clone)]
pub struct Public<F: PrimeField> {
	pub chain_id: F,
}

impl<F: PrimeField> Public<F> {
	pub fn new(chain_id: F) -> Self {
		Self { chain_id }
	}
}

#[derive(Clone)]
pub struct AnchorLeaf<F: PrimeField, H: CRH> {
	field: PhantomData<F>,
	hasher: PhantomData<H>,
}

impl<F: PrimeField, H: CRH> AnchorLeaf<F, H> {
	pub fn create_leaf(
		private: &Private<F>,
		public: &Public<F>,
		h: &H::Parameters,
	) -> Result<H::Output, Error> {
		let input_bytes = to_bytes![private.secret, private.nullifier, public.chain_id]?;
		H::evaluate(h, &input_bytes)
	}

	pub fn create_nullifier(private: &Private<F>, h: &H::Parameters) -> Result<H::Output, Error> {
		let nullifier_bytes = to_bytes![private.nullifier, private.nullifier]?;
		H::evaluate(h, &nullifier_bytes)
	}
}

#[cfg(test)]
mod test {
	use super::*;
	use crate::poseidon::CRH;
	use ark_bls12_381::Fq;
	use ark_crypto_primitives::crh::CRH as CRHTrait;
	use ark_ff::One;
	use ark_std::test_rng;
	use arkworks_utils::utils::common::setup_params_x5_5;

	type PoseidonCRH5 = CRH<Fq>;

	type Leaf = AnchorLeaf<Fq, PoseidonCRH5>;
	#[test]
	fn should_crate_anchor_leaf() {
		let rng = &mut test_rng();
		let curve = arkworks_utils::utils::common::Curve::Bls381;

		let private = Private::generate(rng);

		let chain_id = Fq::one();
		let public = Public::new(chain_id);

		let leaf_inputs = to_bytes![private.secret, private.nullifier, public.chain_id].unwrap();

		let nullifier_inputs = to_bytes![private.nullifier, private.nullifier].unwrap();

		let params = setup_params_x5_5(curve);

		let leaf_res = PoseidonCRH5::evaluate(&params, &leaf_inputs).unwrap();
		let nullifier_res = PoseidonCRH5::evaluate(&params, &nullifier_inputs).unwrap();

		let leaf_hash = Leaf::create_leaf(&private, &public, &params).unwrap();
		let nullifier_hash = Leaf::create_nullifier(&private, &params).unwrap();
		assert_eq!(leaf_res, leaf_hash);
		assert_eq!(nullifier_res, nullifier_hash);
	}
}