Skip to main content

solana_zk_sdk/
transcript.rs

1use {
2    crate::{errors::TranscriptError, TRANSCRIPT_DOMAIN},
3    curve25519_dalek::{ristretto::CompressedRistretto, scalar::Scalar, traits::IsIdentity},
4    merlin::Transcript,
5};
6
7pub trait TranscriptProtocol {
8    /// Create a new transcript with the global domain separator and a specific label.
9    fn new_zk_elgamal_transcript(label: &'static [u8]) -> Transcript;
10
11    /// Append a `scalar` with the given `label`.
12    fn append_scalar(&mut self, label: &'static [u8], scalar: &Scalar);
13
14    /// Append a `point` with the given `label`.
15    fn append_point(&mut self, label: &'static [u8], point: &CompressedRistretto);
16
17    /// Check that a point is not the identity, then append it to the
18    /// transcript.  Otherwise, return an error.
19    fn validate_and_append_point(
20        &mut self,
21        label: &'static [u8],
22        point: &CompressedRistretto,
23    ) -> Result<(), TranscriptError>;
24
25    /// Append a domain separator for an `n`-bit range proof
26    fn range_proof_domain_separator(&mut self, n: u64);
27
28    /// Append a domain separator for a length-`n` inner product proof.
29    fn inner_product_proof_domain_separator(&mut self, n: u64);
30
31    /// Append a domain separator for ciphertext-ciphertext equality proof.
32    fn ciphertext_ciphertext_equality_proof_domain_separator(&mut self);
33
34    /// Append a domain separator for ciphertext-commitment equality proof.
35    fn ciphertext_commitment_equality_proof_domain_separator(&mut self);
36
37    /// Append a domain separator for zero-ciphertext proof.
38    fn zero_ciphertext_proof_domain_separator(&mut self);
39
40    /// Append a domain separator for grouped ciphertext validity proof.
41    fn grouped_ciphertext_validity_proof_domain_separator(&mut self, handles: u64);
42
43    /// Append a domain separator for batched grouped ciphertext validity proof.
44    fn batched_grouped_ciphertext_validity_proof_domain_separator(&mut self, handles: u64);
45
46    /// Append a domain separator for percentage with cap proof.
47    fn percentage_with_cap_proof_domain_separator(&mut self);
48
49    /// Append a domain separator for public-key proof.
50    fn pubkey_proof_domain_separator(&mut self);
51
52    /// Compute a `label`ed challenge variable.
53    fn challenge_scalar(&mut self, label: &'static [u8]) -> Scalar;
54}
55
56impl TranscriptProtocol for Transcript {
57    fn new_zk_elgamal_transcript(label: &'static [u8]) -> Transcript {
58        let mut transcript = Transcript::new(TRANSCRIPT_DOMAIN);
59        transcript.append_message(b"dom-sep", label);
60        transcript
61    }
62
63    fn append_scalar(&mut self, label: &'static [u8], scalar: &Scalar) {
64        self.append_message(label, scalar.as_bytes());
65    }
66
67    fn append_point(&mut self, label: &'static [u8], point: &CompressedRistretto) {
68        self.append_message(label, point.as_bytes());
69    }
70
71    fn validate_and_append_point(
72        &mut self,
73        label: &'static [u8],
74        point: &CompressedRistretto,
75    ) -> Result<(), TranscriptError> {
76        if point.is_identity() {
77            Err(TranscriptError::ValidationError)
78        } else {
79            self.append_message(label, point.as_bytes());
80            Ok(())
81        }
82    }
83
84    fn range_proof_domain_separator(&mut self, n: u64) {
85        self.append_message(b"dom-sep", b"range-proof");
86        self.append_u64(b"n", n);
87    }
88
89    fn inner_product_proof_domain_separator(&mut self, n: u64) {
90        self.append_message(b"dom-sep", b"inner-product");
91        self.append_u64(b"n", n);
92    }
93
94    fn ciphertext_ciphertext_equality_proof_domain_separator(&mut self) {
95        self.append_message(b"dom-sep", b"ciphertext-ciphertext-equality-proof")
96    }
97
98    fn ciphertext_commitment_equality_proof_domain_separator(&mut self) {
99        self.append_message(b"dom-sep", b"ciphertext-commitment-equality-proof")
100    }
101
102    fn zero_ciphertext_proof_domain_separator(&mut self) {
103        self.append_message(b"dom-sep", b"zero-ciphertext-proof")
104    }
105
106    fn grouped_ciphertext_validity_proof_domain_separator(&mut self, handles: u64) {
107        self.append_message(b"dom-sep", b"validity-proof");
108        self.append_u64(b"handles", handles);
109    }
110
111    fn batched_grouped_ciphertext_validity_proof_domain_separator(&mut self, handles: u64) {
112        self.append_message(b"dom-sep", b"batched-validity-proof");
113        self.append_u64(b"handles", handles);
114    }
115
116    fn percentage_with_cap_proof_domain_separator(&mut self) {
117        self.append_message(b"dom-sep", b"percentage-with-cap-proof")
118    }
119
120    fn pubkey_proof_domain_separator(&mut self) {
121        self.append_message(b"dom-sep", b"pubkey-proof")
122    }
123
124    fn challenge_scalar(&mut self, label: &'static [u8]) -> Scalar {
125        let mut buf = [0u8; 64];
126        self.challenge_bytes(label, &mut buf);
127
128        Scalar::from_bytes_mod_order_wide(&buf)
129    }
130}