use ff::Field;
use group::Group;
use midnight_circuits::{
ecc::{curves::CircuitCurve, native::AssignedScalarOfNativeCurve},
instructions::{
AssignmentInstructions, ConversionInstructions, EccInstructions, PublicInputInstructions,
},
types::{AssignedNativePoint, Instantiable},
};
use midnight_curves::{Fr as JubjubScalar, JubjubExtended as Jubjub, JubjubSubgroup};
use midnight_proofs::{
circuit::{Layouter, Value},
plonk::Error,
};
use midnight_zk_stdlib::{utils::plonk_api::filecoin_srs, Relation, ZkStdLib, ZkStdLibArch};
use rand::rngs::OsRng;
type F = midnight_curves::Fq;
#[derive(Clone, Default)]
pub struct EccExample;
impl Relation for EccExample {
type Instance = JubjubSubgroup;
type Witness = JubjubScalar;
type Error = Error;
fn format_instance(instance: &Self::Instance) -> Result<Vec<F>, Error> {
Ok(AssignedNativePoint::<Jubjub>::as_public_input(instance))
}
fn circuit(
&self,
std_lib: &ZkStdLib,
layouter: &mut impl Layouter<F>,
_instance: Value<Self::Instance>,
witness: Value<Self::Witness>,
) -> Result<(), Error> {
let scalar = std_lib.jubjub().assign(layouter, witness)?;
let native_value = std_lib.assign(layouter, Value::known(F::default()))?;
let scalar_from_native: AssignedScalarOfNativeCurve<Jubjub> =
std_lib.jubjub().convert(layouter, &native_value)?;
let generator: AssignedNativePoint<Jubjub> = std_lib
.jubjub()
.assign_fixed(layouter, <JubjubSubgroup as Group>::generator())?;
let one = std_lib.assign_fixed(layouter, <Jubjub as CircuitCurve>::Base::ONE)?;
let extra_base = std_lib.hash_to_curve(layouter, &[one])?;
let result = std_lib.jubjub().msm(
layouter,
&[scalar, scalar_from_native],
&[generator, extra_base],
)?;
std_lib.jubjub().constrain_as_public_input(layouter, &result)
}
fn used_chips(&self) -> ZkStdLibArch {
ZkStdLibArch {
jubjub: true,
poseidon: true,
..ZkStdLibArch::default()
}
}
fn write_relation<W: std::io::Write>(&self, _writer: &mut W) -> std::io::Result<()> {
Ok(())
}
fn read_relation<R: std::io::Read>(_reader: &mut R) -> std::io::Result<Self> {
Ok(EccExample)
}
}
fn main() {
const K: u32 = 11;
let srs = filecoin_srs(K);
let relation = EccExample;
let vk = midnight_zk_stdlib::setup_vk(&srs, &relation);
let pk = midnight_zk_stdlib::setup_pk(&relation, &vk);
const N: usize = 5;
let mut vks = vec![];
let mut pis = vec![];
let mut proofs = vec![];
for _ in 0..N {
let witness = JubjubScalar::random(&mut OsRng);
let instance = JubjubSubgroup::generator() * witness;
let proof = midnight_zk_stdlib::prove::<EccExample, blake2b_simd::State>(
&srs, &pk, &relation, &instance, witness, OsRng,
)
.expect("Proof generation should not fail");
vks.push(vk.clone());
pis.push(EccExample::format_instance(&instance).unwrap());
proofs.push(proof);
}
assert!(midnight_zk_stdlib::batch_verify::<blake2b_simd::State>(
&srs.verifier_params(),
&vks,
&pis,
&proofs
)
.is_ok())
}