voting_circuits/
prove_error.rs1use halo2_proofs::{
2 pasta::EqAffine,
3 plonk::{self, create_proof},
4 poly::commitment::Params,
5 transcript::{Blake2bWrite, Challenge255},
6};
7use pasta_curves::vesta;
8use rand::rngs::OsRng;
9use std::vec::Vec;
10
11pub(crate) fn create_proof_bytes<ConcreteCircuit>(
12 params: &Params<EqAffine>,
13 pk: &plonk::ProvingKey<EqAffine>,
14 circuit: ConcreteCircuit,
15 public_inputs: &[vesta::Scalar],
16) -> Result<Vec<u8>, ProveError>
17where
18 ConcreteCircuit: plonk::Circuit<vesta::Scalar>,
19{
20 let mut transcript = Blake2bWrite::<_, EqAffine, Challenge255<_>>::init(vec![]);
21 create_proof(
22 params,
23 pk,
24 &[circuit],
25 &[&[public_inputs]],
26 OsRng,
27 &mut transcript,
28 )?;
29 Ok(transcript.finalize())
30}
31
32#[derive(Debug)]
34#[non_exhaustive]
35pub enum ProveError {
36 KeygenVk(plonk::Error),
38 KeygenPk(plonk::Error),
40 CachedKeygen(String),
42 Halo2(plonk::Error),
44}
45
46impl From<plonk::Error> for ProveError {
47 fn from(error: plonk::Error) -> Self {
48 ProveError::Halo2(error)
49 }
50}
51
52impl core::fmt::Display for ProveError {
53 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
54 match self {
55 ProveError::KeygenVk(error) => {
56 write!(f, "Halo2 verifying key generation failed: {error}")
57 }
58 ProveError::KeygenPk(error) => {
59 write!(f, "Halo2 proving key generation failed: {error}")
60 }
61 ProveError::CachedKeygen(error) => write!(f, "Halo2 key generation failed: {error}"),
62 ProveError::Halo2(error) => write!(f, "Halo2 proof creation failed: {error}"),
63 }
64 }
65}
66
67impl std::error::Error for ProveError {
68 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
69 match self {
70 ProveError::KeygenVk(error) => Some(error),
71 ProveError::KeygenPk(error) => Some(error),
72 ProveError::CachedKeygen(_) => None,
73 ProveError::Halo2(error) => Some(error),
74 }
75 }
76}
77
78#[cfg(test)]
79mod tests {
80 use super::*;
81 use halo2_proofs::{
82 circuit::{Layouter, SimpleFloorPlanner, Value},
83 plonk::{Advice, Column, ConstraintSystem, Error as PlonkError, Instance},
84 };
85
86 #[derive(Clone, Debug)]
87 struct TinyCircuit {
88 witness: Value<vesta::Scalar>,
89 }
90
91 #[derive(Clone, Debug)]
92 struct TinyConfig {
93 advice: Column<Advice>,
94 instance: Column<Instance>,
95 }
96
97 impl plonk::Circuit<vesta::Scalar> for TinyCircuit {
98 type Config = TinyConfig;
99 type FloorPlanner = SimpleFloorPlanner;
100
101 fn without_witnesses(&self) -> Self {
102 Self {
103 witness: Value::unknown(),
104 }
105 }
106
107 fn configure(meta: &mut ConstraintSystem<vesta::Scalar>) -> Self::Config {
108 let advice = meta.advice_column();
109 let instance = meta.instance_column();
110 meta.enable_equality(advice);
111 meta.enable_equality(instance);
112 TinyConfig { advice, instance }
113 }
114
115 fn synthesize(
116 &self,
117 config: Self::Config,
118 mut layouter: impl Layouter<vesta::Scalar>,
119 ) -> Result<(), PlonkError> {
120 let cell = layouter.assign_region(
121 || "witness",
122 |mut region| region.assign_advice(|| "witness", config.advice, 0, || self.witness),
123 )?;
124
125 layouter.constrain_instance(cell.cell(), config.instance, 0)
126 }
127 }
128
129 #[test]
130 fn create_proof_bytes_returns_err_for_missing_witness() {
131 let params = Params::<EqAffine>::new(4);
132 let empty_circuit = TinyCircuit {
133 witness: Value::unknown(),
134 };
135 let vk = plonk::keygen_vk(¶ms, &empty_circuit).expect("tiny keygen_vk should succeed");
136 let pk =
137 plonk::keygen_pk(¶ms, vk, &empty_circuit).expect("tiny keygen_pk should succeed");
138 let public_inputs = [vesta::Scalar::from(1)];
139
140 let err = create_proof_bytes(¶ms, &pk, empty_circuit, &public_inputs).unwrap_err();
141
142 assert!(matches!(err, ProveError::Halo2(plonk::Error::Synthesis)));
143 }
144}