use halo2_gadgets::poseidon::{
primitives::{self as poseidon, ConstantLength},
Hash as PoseidonHash, Pow5Chip as PoseidonChip, Pow5Config as PoseidonConfig,
};
use halo2_proofs::{
circuit::{AssignedCell, Layouter},
plonk,
};
use pasta_curves::pallas;
use crate::protocol_hash::{poseidon_hash_2, poseidon_hash_in_circuit};
pub use crate::domain_tags::DOMAIN_VAN;
pub(crate) fn van_integrity_hash(
g_d_x: pallas::Base,
pk_d_x: pallas::Base,
value: pallas::Base,
voting_round_id: pallas::Base,
proposal_authority: pallas::Base,
van_comm_rand: pallas::Base,
) -> pallas::Base {
let van_comm_core = poseidon::Hash::<_, poseidon::P128Pow5T3, ConstantLength<6>, 3, 2>::init()
.hash([
pallas::Base::from(DOMAIN_VAN),
g_d_x,
pk_d_x,
value,
voting_round_id,
proposal_authority,
]);
poseidon_hash_2(van_comm_core, van_comm_rand)
}
pub(crate) fn van_integrity_poseidon(
poseidon_config: &PoseidonConfig<pallas::Base, 3, 2>,
layouter: &mut impl Layouter<pallas::Base>,
label: &str,
domain_van: AssignedCell<pallas::Base, pallas::Base>,
g_d_x: AssignedCell<pallas::Base, pallas::Base>,
pk_d_x: AssignedCell<pallas::Base, pallas::Base>,
value: AssignedCell<pallas::Base, pallas::Base>,
voting_round_id: AssignedCell<pallas::Base, pallas::Base>,
proposal_authority: AssignedCell<pallas::Base, pallas::Base>,
van_comm_rand: AssignedCell<pallas::Base, pallas::Base>,
) -> Result<AssignedCell<pallas::Base, pallas::Base>, plonk::Error> {
let core_message = [
domain_van,
g_d_x,
pk_d_x,
value,
voting_round_id,
proposal_authority,
];
let poseidon_hasher_6 =
PoseidonHash::<pallas::Base, _, poseidon::P128Pow5T3, ConstantLength<6>, 3, 2>::init(
PoseidonChip::construct(poseidon_config.clone()),
layouter.namespace(|| format!("{label} core Poseidon init")),
)?;
let van_comm_core = poseidon_hasher_6.hash(
layouter.namespace(|| format!("{label} Poseidon(core)")),
core_message,
)?;
poseidon_hash_in_circuit(
PoseidonChip::construct(poseidon_config.clone()),
layouter.namespace(|| format!("{label} final Poseidon")),
"Poseidon(core, rand)",
[van_comm_core, van_comm_rand],
)
}
#[cfg(test)]
mod tests {
use super::*;
use ff::PrimeField;
fn base_from_repr(bytes: [u8; 32]) -> pallas::Base {
pallas::Base::from_repr(bytes).expect("frozen vector must be canonical")
}
#[test]
fn van_integrity_hash_frozen_vector() {
let actual = van_integrity_hash(
pallas::Base::from(1u64),
pallas::Base::from(2u64),
pallas::Base::from(3u64),
pallas::Base::from(4u64),
pallas::Base::from(5u64),
pallas::Base::from(6u64),
);
assert_eq!(
actual,
base_from_repr([
170, 254, 87, 142, 76, 163, 228, 29, 153, 102, 1, 140, 237, 128, 137, 3, 137, 237,
179, 252, 168, 232, 117, 56, 227, 199, 242, 20, 178, 33, 130, 59,
])
);
}
}