coconut_crypto/proof/
mod.rs

1//! Proofs of knowledge for the signature and messages.
2
3use alloc::vec::Vec;
4
5pub mod messages_pok;
6pub mod signature_pok;
7
8use ark_ff::PrimeField;
9
10use ark_std::rand::RngCore;
11
12use itertools::process_results;
13use serde::{Deserialize, Serialize};
14use serde_with::serde_as;
15use utils::serde_utils::ArkObjectBytes;
16
17pub use messages_pok::*;
18pub use signature_pok::*;
19
20use crate::helpers::{pair_with_slice, rand, IndexIsOutOfBounds};
21
22/// Each message can be either randomly blinded, unblinded, or blinded using supplied blinding.
23/// By default, a message is blinded with random blinding.
24#[serde_as]
25#[derive(Clone, Copy, PartialEq, Eq, Debug, Serialize, Deserialize)]
26#[serde(bound = "")]
27pub enum CommitMessage<F: PrimeField> {
28    /// Message will be randomly blinded into the commitment.
29    BlindMessageRandomly(#[serde_as(as = "ArkObjectBytes")] F),
30    /// Message will be revealed, and thus won't be included in PoK.
31    RevealMessage,
32    /// Message will be blinded into the commitment with the supplied blinding.
33    BlindMessageWithConcreteBlinding {
34        #[serde_as(as = "ArkObjectBytes")]
35        message: F,
36        #[serde_as(as = "ArkObjectBytes")]
37        blinding: F,
38    },
39}
40
41impl<F: PrimeField> CommitMessage<F> {
42    /// Splits blinded message into the message and blinding, returns `None` for the revealed message.
43    pub fn split<R: RngCore>(self, rng: &mut R) -> Option<(F, F)> {
44        match self {
45            Self::BlindMessageRandomly(message) => Some((message, rand(rng))),
46            Self::BlindMessageWithConcreteBlinding { message, blinding } => {
47                Some((message, blinding))
48            }
49            Self::RevealMessage => None,
50        }
51    }
52
53    /// Blinds given `message` using supplied `blinding`.
54    pub fn blind_message_with(message: F, blinding: F) -> Self {
55        Self::BlindMessageWithConcreteBlinding { message, blinding }
56    }
57}
58
59impl<F: PrimeField> From<F> for CommitMessage<F> {
60    fn from(message: F) -> Self {
61        Self::BlindMessageRandomly(message)
62    }
63}
64
65impl<F: PrimeField> From<&'_ F> for CommitMessage<F> {
66    fn from(&message: &'_ F) -> Self {
67        Self::BlindMessageRandomly(message)
68    }
69}
70
71impl<F: PrimeField> From<(F, F)> for CommitMessage<F> {
72    fn from((message, blinding): (F, F)) -> Self {
73        Self::BlindMessageWithConcreteBlinding { message, blinding }
74    }
75}
76
77impl<F: PrimeField> From<(F, Option<F>)> for CommitMessage<F> {
78    fn from((message, blinding): (F, Option<F>)) -> Self {
79        if let Some(blinding) = blinding {
80            Self::BlindMessageWithConcreteBlinding { message, blinding }
81        } else {
82            Self::BlindMessageRandomly(message)
83        }
84    }
85}
86
87impl<F: PrimeField> From<Option<F>> for CommitMessage<F> {
88    fn from(opt: Option<F>) -> Self {
89        match opt {
90            Some(msg) => Self::BlindMessageRandomly(msg),
91            None => Self::RevealMessage,
92        }
93    }
94}
95
96impl<F: PrimeField> From<Option<&'_ F>> for CommitMessage<F> {
97    fn from(opt: Option<&'_ F>) -> Self {
98        match opt {
99            Some(&msg) => Self::BlindMessageRandomly(msg),
100            None => Self::RevealMessage,
101        }
102    }
103}
104
105impl<F: PrimeField> From<(&'_ F, F)> for CommitMessage<F> {
106    fn from((&message, blinding): (&'_ F, F)) -> Self {
107        Self::BlindMessageWithConcreteBlinding { message, blinding }
108    }
109}
110
111impl<F: PrimeField> From<(&'_ F, &'_ F)> for CommitMessage<F> {
112    fn from((&message, &blinding): (&'_ F, &'_ F)) -> Self {
113        Self::BlindMessageWithConcreteBlinding { message, blinding }
114    }
115}
116
117impl<F: PrimeField> From<(&'_ F, Option<F>)> for CommitMessage<F> {
118    fn from((&message, blinding): (&'_ F, Option<F>)) -> Self {
119        if let Some(blinding) = blinding {
120            Self::BlindMessageWithConcreteBlinding { message, blinding }
121        } else {
122            Self::BlindMessageRandomly(message)
123        }
124    }
125}
126
127impl<F: PrimeField> From<(&'_ F, Option<&'_ F>)> for CommitMessage<F> {
128    fn from((&message, blinding): (&'_ F, Option<&'_ F>)) -> Self {
129        if let Some(blinding) = blinding.copied() {
130            Self::BlindMessageWithConcreteBlinding { message, blinding }
131        } else {
132            Self::BlindMessageRandomly(message)
133        }
134    }
135}
136
137/// Contains vectors of items paired with messages along with messages and blindings.
138/// All vectors have one item per message.
139#[derive(Debug, PartialEq, Eq, Clone)]
140struct UnpackedBlindedMessages<'pair, Pair, F>(pub Vec<&'pair Pair>, pub Vec<F>, pub Vec<F>);
141
142#[derive(Clone, Debug, PartialEq, Eq)]
143pub enum MessageUnpackingError {
144    MessageIndexIsOutOfBounds(IndexIsOutOfBounds),
145    NoMessagesProvided,
146    LessMessagesThanExpected { provided: usize, expected: usize },
147}
148
149impl From<IndexIsOutOfBounds> for MessageUnpackingError {
150    fn from(err: IndexIsOutOfBounds) -> Self {
151        Self::MessageIndexIsOutOfBounds(err)
152    }
153}
154
155impl<'pair, Pair, F: PrimeField> UnpackedBlindedMessages<'pair, Pair, F> {
156    /// Accepts a random generator, an iterator of blinded and revealed messages, and a slice
157    /// to pair blinded messages with.
158    /// Returns a result containing a vectors of corresponding `pair_with` elements along with
159    /// messages and blindings. Each collection has one item per message.
160    pub fn new(
161        rng: &mut impl RngCore,
162        messages: impl IntoIterator<Item = impl Into<CommitMessage<F>>>,
163        pair_with: &'pair [Pair],
164    ) -> Result<Self, MessageUnpackingError> {
165        let mut total_count = 0;
166        let indexed_blinded_msgs = messages
167            .into_iter()
168            .map(Into::into)
169            .enumerate()
170            .inspect(|_| total_count += 1)
171            .filter_map(|(idx, msg_with_blinding)| {
172                msg_with_blinding.split(rng).map(|split| (idx, split))
173            });
174
175        // Pair each indexed blinded message with an item from the provided slice.
176        let paired = pair_with_slice(indexed_blinded_msgs, pair_with);
177
178        let (paired, (msgs, blindings)): (Vec<_>, _) =
179            process_results(paired, |iter| iter.unzip())?;
180        if pair_with.len() != total_count {
181            Err(MessageUnpackingError::LessMessagesThanExpected {
182                provided: total_count,
183                expected: pair_with.len(),
184            })
185        } else {
186            Ok(Self(paired, msgs, blindings))
187        }
188    }
189}