use ff::Field;
use pasta_curves::pallas;
use super::{commit_ivk::CommitIvkChip, note_commit::NoteCommitChip};
use crate::constants::{
NullifierK, OrchardCommitDomains, OrchardFixedBases, OrchardFixedBasesFull, OrchardHashDomains,
ValueCommitV,
};
use halo2_gadgets::{
ecc::{
chip::EccChip, EccInstructions, FixedPoint, FixedPointBaseField, FixedPointShort, Point,
ScalarFixed, ScalarFixedShort, X,
},
poseidon::{
primitives::{self as poseidon, ConstantLength},
Hash as PoseidonHash, PoseidonSpongeInstructions, Pow5Chip as PoseidonChip,
},
sinsemilla::{chip::SinsemillaChip, merkle::chip::MerkleChip},
};
use halo2_proofs::{
circuit::{AssignedCell, Chip, Layouter, Value},
plonk::{self, Advice, Assigned, Column},
};
pub(in crate::circuit) mod add_chip;
impl super::Config {
pub(super) fn add_chip(&self) -> add_chip::AddChip {
add_chip::AddChip::construct(self.add_config.clone())
}
pub(super) fn commit_ivk_chip(&self) -> CommitIvkChip {
CommitIvkChip::construct(self.commit_ivk_config.clone())
}
pub(super) fn ecc_chip(&self) -> EccChip<OrchardFixedBases> {
EccChip::construct(self.ecc_config.clone())
}
pub(super) fn sinsemilla_chip_1(
&self,
) -> SinsemillaChip<OrchardHashDomains, OrchardCommitDomains, OrchardFixedBases> {
SinsemillaChip::construct(self.sinsemilla_config_1.clone())
}
pub(super) fn sinsemilla_chip_2(
&self,
) -> SinsemillaChip<OrchardHashDomains, OrchardCommitDomains, OrchardFixedBases> {
SinsemillaChip::construct(self.sinsemilla_config_2.clone())
}
pub(super) fn merkle_chip_1(
&self,
) -> MerkleChip<OrchardHashDomains, OrchardCommitDomains, OrchardFixedBases> {
MerkleChip::construct(self.merkle_config_1.clone())
}
pub(super) fn merkle_chip_2(
&self,
) -> MerkleChip<OrchardHashDomains, OrchardCommitDomains, OrchardFixedBases> {
MerkleChip::construct(self.merkle_config_2.clone())
}
pub(super) fn poseidon_chip(&self) -> PoseidonChip<pallas::Base, 3, 2> {
PoseidonChip::construct(self.poseidon_config.clone())
}
pub(super) fn note_commit_chip_new(&self) -> NoteCommitChip {
NoteCommitChip::construct(self.new_note_commit_config.clone())
}
pub(super) fn note_commit_chip_old(&self) -> NoteCommitChip {
NoteCommitChip::construct(self.old_note_commit_config.clone())
}
}
pub(in crate::circuit) trait AddInstruction<F: Field>: Chip<F> {
fn add(
&self,
layouter: impl Layouter<F>,
a: &AssignedCell<F, F>,
b: &AssignedCell<F, F>,
) -> Result<AssignedCell<F, F>, plonk::Error>;
}
pub(in crate::circuit) fn assign_free_advice<F: Field, V: Copy>(
mut layouter: impl Layouter<F>,
column: Column<Advice>,
value: Value<V>,
) -> Result<AssignedCell<V, F>, plonk::Error>
where
for<'v> Assigned<F>: From<&'v V>,
{
layouter.assign_region(
|| "load private",
|mut region| region.assign_advice(|| "load private", column, 0, || value),
)
}
pub(in crate::circuit) fn value_commit_orchard<
EccChip: EccInstructions<
pallas::Affine,
FixedPoints = OrchardFixedBases,
Var = AssignedCell<pallas::Base, pallas::Base>,
>,
>(
mut layouter: impl Layouter<pallas::Base>,
ecc_chip: EccChip,
v: ScalarFixedShort<pallas::Affine, EccChip>,
rcv: ScalarFixed<pallas::Affine, EccChip>,
) -> Result<Point<pallas::Affine, EccChip>, plonk::Error> {
let (commitment, _) = {
let value_commit_v = ValueCommitV;
let value_commit_v = FixedPointShort::from_inner(ecc_chip.clone(), value_commit_v);
value_commit_v.mul(layouter.namespace(|| "[v] ValueCommitV"), v)?
};
let (blind, _rcv) = {
let value_commit_r = OrchardFixedBasesFull::ValueCommitR;
let value_commit_r = FixedPoint::from_inner(ecc_chip, value_commit_r);
value_commit_r.mul(layouter.namespace(|| "[rcv] ValueCommitR"), rcv)?
};
commitment.add(layouter.namespace(|| "cv"), &blind)
}
#[allow(clippy::too_many_arguments)]
pub(in crate::circuit) fn derive_nullifier<
PoseidonChip: PoseidonSpongeInstructions<pallas::Base, poseidon::P128Pow5T3, ConstantLength<2>, 3, 2>,
AddChip: AddInstruction<pallas::Base>,
EccChip: EccInstructions<
pallas::Affine,
FixedPoints = OrchardFixedBases,
Var = AssignedCell<pallas::Base, pallas::Base>,
>,
>(
mut layouter: impl Layouter<pallas::Base>,
poseidon_chip: PoseidonChip,
add_chip: AddChip,
ecc_chip: EccChip,
rho: AssignedCell<pallas::Base, pallas::Base>,
psi: &AssignedCell<pallas::Base, pallas::Base>,
cm: &Point<pallas::Affine, EccChip>,
nk: AssignedCell<pallas::Base, pallas::Base>,
) -> Result<X<pallas::Affine, EccChip>, plonk::Error> {
let hash = {
let poseidon_message = [nk, rho];
let poseidon_hasher =
PoseidonHash::init(poseidon_chip, layouter.namespace(|| "Poseidon init"))?;
poseidon_hasher.hash(
layouter.namespace(|| "Poseidon hash (nk, rho)"),
poseidon_message,
)?
};
let scalar = add_chip.add(
layouter.namespace(|| "scalar = poseidon_hash(nk, rho) + psi"),
&hash,
psi,
)?;
let product = {
let nullifier_k = FixedPointBaseField::from_inner(ecc_chip, NullifierK);
nullifier_k.mul(
layouter.namespace(|| "[poseidon_output + psi] NullifierK"),
scalar,
)?
};
cm.add(layouter.namespace(|| "nf"), &product)
.map(|res| res.extract_p())
}
pub(in crate::circuit) use crate::circuit::commit_ivk::gadgets::commit_ivk;
pub(in crate::circuit) use crate::circuit::note_commit::gadgets::note_commit;