2021-04-14 21:35:48 -07:00
|
|
|
use group::Curve;
|
|
|
|
use halo2::{
|
|
|
|
plonk,
|
|
|
|
poly::{EvaluationDomain, LagrangeCoeff, Polynomial, Rotation},
|
|
|
|
transcript::{Blake2bRead, Blake2bWrite},
|
|
|
|
};
|
|
|
|
use pasta_curves::{pallas, vesta};
|
|
|
|
|
|
|
|
use crate::{
|
2021-05-05 10:46:24 -07:00
|
|
|
note::{nullifier::Nullifier, ExtractedNoteCommitment},
|
2021-04-14 21:35:48 -07:00
|
|
|
primitives::redpallas::{SpendAuth, VerificationKey},
|
|
|
|
tree::Anchor,
|
|
|
|
value::ValueCommitment,
|
|
|
|
};
|
|
|
|
|
2021-02-25 10:11:46 -08:00
|
|
|
pub(crate) mod gadget;
|
|
|
|
|
2021-04-14 21:35:48 -07:00
|
|
|
/// Size of the Orchard circuit.
|
|
|
|
const K: u32 = 11;
|
|
|
|
|
|
|
|
/// The Orchard Action circuit.
|
|
|
|
#[derive(Debug)]
|
|
|
|
pub struct Circuit {}
|
|
|
|
|
|
|
|
impl plonk::Circuit<pallas::Base> for Circuit {
|
|
|
|
type Config = ();
|
|
|
|
|
|
|
|
fn configure(meta: &mut plonk::ConstraintSystem<pallas::Base>) -> Self::Config {
|
|
|
|
// Placeholder so the proving key is correctly built.
|
|
|
|
meta.instance_column();
|
|
|
|
|
|
|
|
// Placeholder gate so there is something for the prover to operate on.
|
|
|
|
let advice = meta.advice_column();
|
2021-06-01 09:37:44 -07:00
|
|
|
meta.create_gate("TODO", |meta| {
|
|
|
|
vec![meta.query_advice(advice, Rotation::cur())]
|
|
|
|
});
|
2021-04-14 21:35:48 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
fn synthesize(
|
|
|
|
&self,
|
|
|
|
_cs: &mut impl plonk::Assignment<pallas::Base>,
|
|
|
|
_config: Self::Config,
|
|
|
|
) -> Result<(), plonk::Error> {
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// The verifying key for the Orchard Action circuit.
|
|
|
|
#[derive(Debug)]
|
|
|
|
pub struct VerifyingKey {
|
|
|
|
params: halo2::poly::commitment::Params<vesta::Affine>,
|
|
|
|
vk: plonk::VerifyingKey<vesta::Affine>,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl VerifyingKey {
|
|
|
|
/// Builds the verifying key.
|
|
|
|
pub fn build() -> Self {
|
|
|
|
let params = halo2::poly::commitment::Params::new(K);
|
|
|
|
let circuit = Circuit {}; // TODO
|
|
|
|
|
|
|
|
let vk = plonk::keygen_vk(¶ms, &circuit).unwrap();
|
|
|
|
|
|
|
|
VerifyingKey { params, vk }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// The proving key for the Orchard Action circuit.
|
|
|
|
#[derive(Debug)]
|
|
|
|
pub struct ProvingKey {
|
|
|
|
params: halo2::poly::commitment::Params<vesta::Affine>,
|
|
|
|
pk: plonk::ProvingKey<vesta::Affine>,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl ProvingKey {
|
|
|
|
/// Builds the proving key.
|
|
|
|
pub fn build() -> Self {
|
|
|
|
let params = halo2::poly::commitment::Params::new(K);
|
|
|
|
let circuit = Circuit {}; // TODO
|
|
|
|
|
|
|
|
let vk = plonk::keygen_vk(¶ms, &circuit).unwrap();
|
|
|
|
let pk = plonk::keygen_pk(¶ms, vk, &circuit).unwrap();
|
|
|
|
|
|
|
|
ProvingKey { params, pk }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Public inputs to the Orchard Action circuit.
|
|
|
|
#[derive(Debug)]
|
|
|
|
pub struct Instance {
|
|
|
|
pub(crate) anchor: Anchor,
|
|
|
|
pub(crate) cv_net: ValueCommitment,
|
|
|
|
pub(crate) nf_old: Nullifier,
|
|
|
|
pub(crate) rk: VerificationKey<SpendAuth>,
|
|
|
|
pub(crate) cmx: ExtractedNoteCommitment,
|
|
|
|
pub(crate) enable_spend: bool,
|
|
|
|
pub(crate) enable_output: bool,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Instance {
|
|
|
|
fn to_halo2_instance(
|
|
|
|
&self,
|
|
|
|
domain: &EvaluationDomain<vesta::Scalar>,
|
|
|
|
) -> [Polynomial<vesta::Scalar, LagrangeCoeff>; 1] {
|
|
|
|
// TODO
|
|
|
|
[domain.empty_lagrange()]
|
|
|
|
}
|
|
|
|
|
|
|
|
fn to_halo2_instance_commitments(&self, vk: &VerifyingKey) -> [vesta::Affine; 1] {
|
|
|
|
[vk.params
|
|
|
|
.commit_lagrange(
|
|
|
|
&self.to_halo2_instance(vk.vk.get_domain())[0],
|
|
|
|
Default::default(),
|
|
|
|
)
|
|
|
|
.to_affine()]
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// A proof of the validity of an Orchard [`Bundle`].
|
|
|
|
///
|
|
|
|
/// [`Bundle`]: crate::bundle::Bundle
|
2021-05-13 14:35:44 -07:00
|
|
|
#[derive(Debug, Clone)]
|
2021-05-05 10:46:24 -07:00
|
|
|
pub struct Proof(Vec<u8>);
|
2021-04-14 21:35:48 -07:00
|
|
|
|
2021-05-05 10:37:56 -07:00
|
|
|
impl AsRef<[u8]> for Proof {
|
|
|
|
fn as_ref(&self) -> &[u8] {
|
|
|
|
&self.0
|
2021-04-21 13:32:54 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-04-14 21:35:48 -07:00
|
|
|
impl Proof {
|
|
|
|
/// Creates a proof for the given circuits and instances.
|
|
|
|
pub fn create(
|
|
|
|
pk: &ProvingKey,
|
|
|
|
circuits: &[Circuit],
|
|
|
|
instances: &[Instance],
|
|
|
|
) -> Result<Self, plonk::Error> {
|
|
|
|
let instances: Vec<_> = instances
|
|
|
|
.iter()
|
|
|
|
.map(|i| i.to_halo2_instance(pk.pk.get_vk().get_domain()))
|
|
|
|
.collect();
|
|
|
|
let instances: Vec<_> = instances.iter().map(|i| &i[..]).collect();
|
|
|
|
|
2021-06-01 09:37:44 -07:00
|
|
|
let mut transcript = Blake2bWrite::<_, vesta::Affine, _>::init(vec![]);
|
2021-04-14 21:35:48 -07:00
|
|
|
plonk::create_proof(&pk.params, &pk.pk, circuits, &instances, &mut transcript)?;
|
|
|
|
Ok(Proof(transcript.finalize()))
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Verifies this proof with the given instances.
|
|
|
|
pub fn verify(&self, vk: &VerifyingKey, instances: &[Instance]) -> Result<(), plonk::Error> {
|
|
|
|
let instances: Vec<_> = instances
|
|
|
|
.iter()
|
|
|
|
.map(|i| i.to_halo2_instance_commitments(vk))
|
|
|
|
.collect();
|
|
|
|
let instances: Vec<_> = instances.iter().map(|i| &i[..]).collect();
|
|
|
|
|
|
|
|
let msm = vk.params.empty_msm();
|
|
|
|
let mut transcript = Blake2bRead::init(&self.0[..]);
|
|
|
|
let guard = plonk::verify_proof(&vk.params, &vk.vk, msm, &instances, &mut transcript)?;
|
|
|
|
let msm = guard.clone().use_challenges();
|
|
|
|
if msm.eval() {
|
|
|
|
Ok(())
|
|
|
|
} else {
|
|
|
|
Err(plonk::Error::ConstraintSystemFailure)
|
|
|
|
}
|
|
|
|
}
|
2021-04-21 08:57:48 -07:00
|
|
|
|
2021-05-05 10:37:56 -07:00
|
|
|
/// Constructs a new Proof value.
|
2021-04-21 08:57:48 -07:00
|
|
|
pub fn new(bytes: Vec<u8>) -> Self {
|
|
|
|
Proof(bytes)
|
|
|
|
}
|
2021-04-14 21:35:48 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg(test)]
|
|
|
|
mod tests {
|
|
|
|
use ff::Field;
|
|
|
|
use halo2::dev::MockProver;
|
|
|
|
use pasta_curves::pallas;
|
|
|
|
use rand::rngs::OsRng;
|
|
|
|
use std::iter;
|
|
|
|
|
|
|
|
use super::{Circuit, Instance, Proof, ProvingKey, VerifyingKey, K};
|
|
|
|
use crate::{
|
|
|
|
keys::SpendValidatingKey,
|
|
|
|
note::Note,
|
|
|
|
value::{ValueCommitTrapdoor, ValueCommitment},
|
|
|
|
};
|
|
|
|
|
2021-04-21 08:57:48 -07:00
|
|
|
// TODO: recast as a proptest
|
2021-04-14 21:35:48 -07:00
|
|
|
#[test]
|
|
|
|
fn round_trip() {
|
|
|
|
let mut rng = OsRng;
|
|
|
|
|
|
|
|
let (circuits, instances): (Vec<_>, Vec<_>) = iter::once(())
|
|
|
|
.map(|()| {
|
2021-04-26 17:25:03 -07:00
|
|
|
let (_, fvk, spent_note) = Note::dummy(&mut rng, None);
|
2021-04-14 21:35:48 -07:00
|
|
|
let nf_old = spent_note.nullifier(&fvk);
|
|
|
|
let ak: SpendValidatingKey = fvk.into();
|
|
|
|
let alpha = pallas::Scalar::random(&mut rng);
|
|
|
|
let rk = ak.randomize(&alpha);
|
|
|
|
|
2021-05-28 04:06:50 -07:00
|
|
|
let (_, _, output_note) = Note::dummy(&mut rng, Some(nf_old));
|
2021-04-14 21:35:48 -07:00
|
|
|
let cmx = output_note.commitment().into();
|
|
|
|
|
|
|
|
let value = spent_note.value() - output_note.value();
|
|
|
|
let cv_net = ValueCommitment::derive(value.unwrap(), ValueCommitTrapdoor::zero());
|
|
|
|
|
|
|
|
(
|
|
|
|
Circuit {},
|
|
|
|
Instance {
|
2021-06-12 13:35:37 -07:00
|
|
|
anchor: pallas::Base::zero().into(),
|
2021-04-14 21:35:48 -07:00
|
|
|
cv_net,
|
|
|
|
nf_old,
|
|
|
|
rk,
|
|
|
|
cmx,
|
|
|
|
enable_spend: true,
|
|
|
|
enable_output: true,
|
|
|
|
},
|
|
|
|
)
|
|
|
|
})
|
|
|
|
.unzip();
|
|
|
|
|
|
|
|
let vk = VerifyingKey::build();
|
|
|
|
for (circuit, instance) in circuits.iter().zip(instances.iter()) {
|
|
|
|
assert_eq!(
|
|
|
|
MockProver::run(
|
|
|
|
K,
|
|
|
|
circuit,
|
|
|
|
instance
|
|
|
|
.to_halo2_instance(vk.vk.get_domain())
|
|
|
|
.iter()
|
|
|
|
.map(|p| p.iter().cloned().collect())
|
|
|
|
.collect()
|
|
|
|
)
|
|
|
|
.unwrap()
|
|
|
|
.verify(),
|
|
|
|
Ok(())
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
let pk = ProvingKey::build();
|
|
|
|
let proof = Proof::create(&pk, &circuits, &instances).unwrap();
|
|
|
|
assert!(proof.verify(&vk, &instances).is_ok());
|
|
|
|
}
|
|
|
|
}
|