zebra_consensus/primitives/
groth16.rs1use std::fmt;
4
5use bellman::{
6 gadgets::multipack,
7 groth16::{batch, PreparedVerifyingKey, VerifyingKey},
8 VerificationError,
9};
10use bls12_381::Bls12;
11use futures::{future::BoxFuture, FutureExt};
12use once_cell::sync::Lazy;
13
14use tokio::sync::watch;
15use tower::util::ServiceFn;
16
17use tower_batch_control::RequestWeight;
18use tower_fallback::BoxedError;
19
20use zebra_chain::{
21 primitives::{
22 ed25519::{self, VerificationKeyBytes},
23 Groth16Proof,
24 },
25 sprout::{JoinSplit, Nullifier, RandomSeed},
26};
27
28use crate::BoxError;
29
30use super::spawn_fifo_and_convert;
31
32mod params;
33#[cfg(test)]
34mod tests;
35#[cfg(test)]
36mod vectors;
37
38pub use params::SPROUT;
39
40use crate::error::TransactionError;
41
42type VerifyResult = Result<(), VerificationError>;
44
45type Sender = watch::Sender<Option<VerifyResult>>;
47
48#[derive(Clone, Debug)]
51pub struct Item(batch::Item<Bls12>);
52
53impl RequestWeight for Item {}
54
55impl<T: Into<batch::Item<Bls12>>> From<T> for Item {
56 fn from(value: T) -> Self {
57 Self(value.into())
58 }
59}
60
61impl Item {
62 pub fn verify_single(self, pvk: &PreparedVerifyingKey<Bls12>) -> VerifyResult {
64 self.0.verify_single(pvk)
65 }
66}
67
68pub type BatchVerifyingKey = VerifyingKey<Bls12>;
71
72pub type ItemVerifyingKey = PreparedVerifyingKey<Bls12>;
75
76pub static JOINSPLIT_VERIFIER: Lazy<
85 ServiceFn<fn(Item) -> BoxFuture<'static, Result<(), BoxedError>>>,
86> = Lazy::new(|| {
87 tower::service_fn(
91 (|item: Item| {
92 Verifier::verify_single_spawning(item, SPROUT.prepared_verifying_key())
94 .map(|result| {
95 result
96 .map_err(|e| TransactionError::Groth16(e.to_string()))
97 .map_err(tower_fallback::BoxedError::from)
98 })
99 .boxed()
100 }) as fn(_) -> _,
101 )
102});
103
104pub(super) fn h_sig(
113 random_seed: &RandomSeed,
114 nf1: &Nullifier,
115 nf2: &Nullifier,
116 joinsplit_pub_key: &VerificationKeyBytes,
117) -> [u8; 32] {
118 let h_sig: [u8; 32] = blake2b_simd::Params::new()
119 .hash_length(32)
120 .personal(b"ZcashComputehSig")
121 .to_state()
122 .update(&(<[u8; 32]>::from(random_seed))[..])
123 .update(&(<[u8; 32]>::from(nf1))[..])
124 .update(&(<[u8; 32]>::from(nf2))[..])
125 .update(joinsplit_pub_key.as_ref())
126 .finalize()
127 .as_bytes()
128 .try_into()
129 .expect("32 byte array");
130 h_sig
131}
132
133impl Item {
134 #[allow(clippy::needless_borrow)]
150 pub fn from_joinsplit(
151 joinsplit: &JoinSplit<Groth16Proof>,
152 joinsplit_pub_key: &ed25519::VerificationKeyBytes,
153 ) -> Result<Self, TransactionError> {
154 let rt: [u8; 32] = joinsplit.anchor.into();
155 let mac1: [u8; 32] = (&joinsplit.vmacs[0]).into();
156 let mac2: [u8; 32] = (&joinsplit.vmacs[1]).into();
157 let nf1: [u8; 32] = (&joinsplit.nullifiers[0]).into();
158 let nf2: [u8; 32] = (&joinsplit.nullifiers[1]).into();
159 let cm1: [u8; 32] = (&joinsplit.commitments[0]).into();
160 let cm2: [u8; 32] = (&joinsplit.commitments[1]).into();
161 let vpub_old = joinsplit.vpub_old.to_bytes();
162 let vpub_new = joinsplit.vpub_new.to_bytes();
163
164 let h_sig = h_sig(
165 &joinsplit.random_seed,
166 &joinsplit.nullifiers[0],
167 &joinsplit.nullifiers[1],
168 joinsplit_pub_key,
169 );
170
171 let mut public_input = Vec::with_capacity((32 * 8) + (8 * 2));
173 public_input.extend(rt);
174 public_input.extend(h_sig);
175 public_input.extend(nf1);
176 public_input.extend(mac1);
177 public_input.extend(nf2);
178 public_input.extend(mac2);
179 public_input.extend(cm1);
180 public_input.extend(cm2);
181 public_input.extend(vpub_old);
182 public_input.extend(vpub_new);
183
184 let public_input = multipack::bytes_to_bits(&public_input);
185 let primary_inputs = multipack::compute_multipacking(&public_input);
186
187 let proof = bellman::groth16::Proof::read(&joinsplit.zkproof.0[..])
196 .map_err(|e| TransactionError::MalformedGroth16(e.to_string()))?;
197
198 Ok(Item::from((proof, primary_inputs)))
199 }
200}
201
202pub struct Verifier {
208 tx: Sender,
213}
214
215impl Verifier {
216 async fn verify_single_spawning(
218 item: Item,
219 pvk: &'static ItemVerifyingKey,
220 ) -> Result<(), BoxError> {
221 spawn_fifo_and_convert(move || item.verify_single(pvk)).await
223 }
224}
225
226impl fmt::Debug for Verifier {
227 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
228 let name = "Verifier";
229 f.debug_struct(name)
230 .field("batch", &"..")
231 .field("tx", &self.tx)
232 .finish()
233 }
234}