coconut_crypto/proof/messages_pok/
proof.rs1use alloc::vec::Vec;
2use ark_ec::pairing::Pairing;
3use ark_serialize::*;
4
5use serde::{Deserialize, Serialize};
6use utils::try_iter::InvalidPair;
7
8use crate::{
9 helpers::{
10 pluck_missed, seq_pairs_satisfy, take_while_satisfy, DoubleEndedExactSizeIterator,
11 SendIfParallel, WithSchnorrResponse,
12 },
13 setup::SignatureParams,
14};
15#[cfg(feature = "parallel")]
16use rayon::prelude::*;
17
18use super::*;
19
20#[derive(
22 Clone, Debug, PartialEq, Eq, CanonicalSerialize, CanonicalDeserialize, Serialize, Deserialize,
23)]
24pub struct MessagesPoK<E: Pairing> {
25 pub(super) com_resp: WithSchnorrResponse<E::G1Affine, MultiMessageCommitment<E>>,
27 pub(super) com_j_resp: Vec<WithSchnorrResponse<E::G1Affine, MessageCommitment<E>>>,
29}
30
31impl<E: Pairing> MessagesPoK<E> {
32 pub fn verify<I>(
35 &self,
36 challenge: &E::ScalarField,
37 unique_sorted_revealed_indices: I,
38 params: &SignatureParams<E>,
39 h: &E::G1Affine,
40 ) -> Result<()>
41 where
42 I: IntoIterator<Item = usize> + SendIfParallel,
43 {
44 let (eq_res, com_res, com_j_res) = join!(
45 self.verify_responses(),
47 self.verify_com(challenge, unique_sorted_revealed_indices, params),
49 self.verify_com_j(challenge, params, h)
51 );
52
53 eq_res.and(com_res).and(com_j_res)
54 }
55
56 pub fn challenge_contribution<W: Write>(
58 &self,
59 mut writer: W,
60 &SignatureParams {
61 g, h: ref h_arr, ..
62 }: &SignatureParams<E>,
63 h: &E::G1Affine,
64 ) -> Result<(), SchnorrError> {
65 g.serialize_compressed(&mut writer)?;
67 h_arr.serialize_compressed(&mut writer)?;
68 self.com_resp.challenge_contribution(&mut writer)?;
69
70 h.serialize_compressed(&mut writer)?;
72 for com_j in &self.com_j_resp {
73 com_j.challenge_contribution(&mut writer)?;
74 }
75
76 Ok(())
77 }
78
79 pub fn commitments(
81 &self,
82 ) -> impl DoubleEndedExactSizeIterator<Item = &MessageCommitment<E>> + Clone + '_ {
83 self.com_j_resp.iter().map(|resp| &resp.value)
84 }
85
86 fn verify_responses(&self) -> Result<()> {
88 if self.com_resp.response.0.len() != self.com_j_resp.len() + 1 {
89 Err(MessagesPoKError::SchnorrResponsesHaveDifferentLength)?
90 }
91
92 let m_i_resp = cfg_iter!(self.com_resp.response.0).skip(1).map(Some);
93 let m_j_resp = cfg_iter!(self.com_j_resp).map(|resp| resp.response.0.get(1));
94
95 #[cfg(feature = "parallel")]
96 let find_map = ParallelIterator::find_map_any;
97 #[cfg(not(feature = "parallel"))]
98 let find_map = |mut iter, f| Iterator::find_map(&mut iter, f);
99
100 let invalid_idx = find_map(
101 m_i_resp.zip(m_j_resp).enumerate(),
102 |(idx, (m_i_resp, m_j_resp))| (m_i_resp != m_j_resp).then_some(idx),
103 );
104
105 if let Some(idx) = invalid_idx {
106 Err(MessagesPoKError::SchnorrResponsesNotEqual(idx))
107 } else {
108 Ok(())
109 }
110 }
111
112 fn verify_com(
114 &self,
115 challenge: &E::ScalarField,
116 unique_sorted_revealed_indices: impl IntoIterator<Item = usize>,
117 SignatureParams { g, h, .. }: &SignatureParams<E>,
118 ) -> Result<()> {
119 let mut invalid_idx_pair = None;
121 let committed_h = pluck_missed(
123 take_while_satisfy(
124 unique_sorted_revealed_indices,
125 seq_pairs_satisfy(|a, b| a < b),
126 &mut invalid_idx_pair,
127 ),
128 h,
129 );
130 let verification_res = self
131 .com_resp
132 .verify_challenge(challenge, g, committed_h)
133 .map_err(schnorr_error)
134 .map_err(MessagesPoKError::InvalidComProof);
135
136 if let Some(InvalidPair(previous, current)) = invalid_idx_pair {
137 Err(MessagesPoKError::RevealedIndicesMustBeUniqueAndSorted { previous, current })
138 } else {
139 verification_res
140 }
141 }
142
143 fn verify_com_j(
145 &self,
146 challenge: &E::ScalarField,
147 SignatureParams { g, .. }: &SignatureParams<E>,
148 h: &E::G1Affine,
149 ) -> Result<()> {
150 cfg_iter!(self.com_j_resp)
151 .enumerate()
152 .map(|(index, com_j)| {
153 com_j
154 .verify_challenge(challenge, g, h)
155 .map_err(schnorr_error)
156 .map_err(|error| MessagesPoKError::InvalidComJProof { index, error })
157 })
158 .collect()
159 }
160}