ergotree_interpreter/
sigma_protocol.rs

1//! Sigma protocols
2
3#![deny(clippy::unwrap_used)]
4
5pub mod private_input;
6pub mod prover;
7pub mod verifier;
8
9pub(crate) mod challenge;
10mod crypto_utils;
11pub mod dht_protocol;
12pub mod dlog_protocol;
13mod fiat_shamir;
14mod gf2_192;
15pub mod proof_tree;
16pub mod sig_serializer;
17pub mod unchecked_tree;
18pub mod unproven_tree;
19pub mod wscalar;
20
21use std::array::TryFromSliceError;
22use std::convert::TryFrom;
23use std::convert::TryInto;
24
25use ergotree_ir::sigma_protocol::sigma_boolean::SigmaBoolean;
26
27use dlog_protocol::FirstDlogProverMessage;
28use unchecked_tree::UncheckedTree;
29use unproven_tree::{UnprovenLeaf, UnprovenSchnorr};
30
31use self::challenge::Challenge;
32use self::dht_protocol::FirstDhTupleProverMessage;
33use self::unchecked_tree::UncheckedSchnorr;
34
35use derive_more::From;
36use derive_more::TryInto;
37
38/** The message sent by a prover to its associated verifier as part of a sigma protocol interaction. */
39pub(crate) trait ProverMessage {
40    /// serialized message
41    fn bytes(&self) -> Vec<u8>;
42}
43
44/** First message from the prover (message `a` of `SigmaProtocol`)*/
45#[derive(PartialEq, Eq, Debug, Clone, From, TryInto)]
46#[cfg_attr(feature = "json", derive(serde::Serialize, serde::Deserialize))]
47#[cfg_attr(feature = "json", serde(tag = "type"))]
48#[cfg_attr(feature = "arbitrary", derive(proptest_derive::Arbitrary))]
49pub enum FirstProverMessage {
50    /// Discrete log
51    #[cfg_attr(feature = "json", serde(rename = "dlog"))]
52    FirstDlogProverMessage(FirstDlogProverMessage),
53    /// DH tupl
54    #[cfg_attr(feature = "json", serde(rename = "dht"))]
55    FirstDhtProverMessage(FirstDhTupleProverMessage),
56}
57
58impl ProverMessage for FirstProverMessage {
59    fn bytes(&self) -> Vec<u8> {
60        match self {
61            FirstProverMessage::FirstDlogProverMessage(fdpm) => fdpm.bytes(),
62            FirstProverMessage::FirstDhtProverMessage(fdhtpm) => fdhtpm.bytes(),
63        }
64    }
65}
66
67/** Size of the binary representation of any group element (2 ^ groupSizeBits == <number of elements in a group>) */
68pub(crate) const GROUP_SIZE_BITS: usize = 256;
69/** Number of bytes to represent any group element as byte array */
70pub(crate) const GROUP_SIZE: usize = GROUP_SIZE_BITS / 8;
71
72/// Byte array of Group size (32 bytes)
73#[derive(PartialEq, Eq, Debug, Clone)]
74pub(crate) struct GroupSizedBytes(pub(crate) Box<[u8; GROUP_SIZE]>);
75
76impl From<&[u8; GROUP_SIZE]> for GroupSizedBytes {
77    fn from(b: &[u8; GROUP_SIZE]) -> Self {
78        GroupSizedBytes(Box::new(*b))
79    }
80}
81
82impl TryFrom<Vec<u8>> for GroupSizedBytes {
83    type Error = TryFromSliceError;
84
85    fn try_from(value: Vec<u8>) -> Result<Self, Self::Error> {
86        let bytes: [u8; GROUP_SIZE] = value.as_slice().try_into()?;
87        Ok(GroupSizedBytes(bytes.into()))
88    }
89}
90
91impl TryFrom<&[u8]> for GroupSizedBytes {
92    type Error = TryFromSliceError;
93
94    fn try_from(value: &[u8]) -> Result<Self, Self::Error> {
95        let bytes: [u8; GROUP_SIZE] = value.try_into()?;
96        Ok(GroupSizedBytes(bytes.into()))
97    }
98}
99
100/** A size of challenge in Sigma protocols, in bits.
101 * If this anything but 192, threshold won't work, because we have polynomials over GF(2^192) and no others.
102 * We get the challenge by reducing hash function output to proper value.
103 */
104pub const SOUNDNESS_BITS: usize = 192;
105/// A size of challenge in Sigma protocols, in bytes
106pub const SOUNDNESS_BYTES: usize = SOUNDNESS_BITS / 8;
107
108#[cfg(test)]
109#[cfg(feature = "arbitrary")]
110mod tests {
111    use super::*;
112
113    #[allow(clippy::assertions_on_constants)]
114    #[test]
115    fn ensure_soundness_bits() {
116        // see SOUNDNESS_BITS doc comment
117        assert!(SOUNDNESS_BITS < GROUP_SIZE_BITS);
118        // blake2b hash function requirements
119        assert!(SOUNDNESS_BYTES * 8 <= 512);
120        assert!(SOUNDNESS_BYTES % 8 == 0);
121    }
122}