1use alloc::vec::Vec;
5
6use curve25519_dalek::{RistrettoPoint, Scalar};
7use merlin::TranscriptRng;
8use rand_core::CryptoRngCore;
9
10use crate::{proof::ProofError, Transcript, TriptychParameters, TriptychStatement, TriptychWitness};
11
12pub(crate) struct ProofTranscript<'a, R: CryptoRngCore> {
14 transcript: &'a mut Transcript,
15 witness: Option<&'a TriptychWitness>,
16 transcript_rng: TranscriptRng,
17 external_rng: &'a mut R,
18}
19
20impl<'a, R: CryptoRngCore> ProofTranscript<'a, R> {
21 const DOMAIN: &'static str = "Triptych proof";
23 const VERSION: u64 = 0;
25
26 pub(crate) fn new(
28 transcript: &'a mut Transcript,
29 statement: &TriptychStatement,
30 external_rng: &'a mut R,
31 witness: Option<&'a TriptychWitness>,
32 ) -> Self {
33 transcript.append_message(b"dom-sep", Self::DOMAIN.as_bytes());
35 transcript.append_u64(b"version", Self::VERSION);
36 transcript.append_message(b"statement", statement.get_hash());
37
38 let transcript_rng = Self::build_transcript_rng(transcript, witness, external_rng);
40
41 Self {
42 transcript,
43 witness,
44 transcript_rng,
45 external_rng,
46 }
47 }
48
49 #[allow(non_snake_case, clippy::too_many_arguments)]
51 pub(crate) fn commit(
52 &mut self,
53 params: &TriptychParameters,
54 A: &RistrettoPoint,
55 B: &RistrettoPoint,
56 C: &RistrettoPoint,
57 D: &RistrettoPoint,
58 X: &Vec<RistrettoPoint>,
59 Y: &Vec<RistrettoPoint>,
60 ) -> Result<Vec<Scalar>, ProofError> {
61 let m = params.get_m() as usize;
62
63 self.transcript.append_message(b"A", A.compress().as_bytes());
65 self.transcript.append_message(b"B", B.compress().as_bytes());
66 self.transcript.append_message(b"C", C.compress().as_bytes());
67 self.transcript.append_message(b"D", D.compress().as_bytes());
68 for X_item in X {
69 self.transcript.append_message(b"X", X_item.compress().as_bytes());
70 }
71 for Y_item in Y {
72 self.transcript.append_message(b"Y", Y_item.compress().as_bytes());
73 }
74
75 self.transcript_rng = Self::build_transcript_rng(self.transcript, self.witness, self.external_rng);
77
78 let mut xi_bytes = [0u8; 64];
80 self.transcript.challenge_bytes(b"xi", &mut xi_bytes);
81 let xi = Scalar::from_bytes_mod_order_wide(&xi_bytes);
82
83 let mut xi_powers = Vec::with_capacity(m.checked_add(1).ok_or(ProofError::InvalidParameter)?);
85 let mut xi_power = Scalar::ONE;
86 for _ in 0..=m {
87 if xi_power == Scalar::ZERO {
88 return Err(ProofError::InvalidChallenge);
89 }
90
91 xi_powers.push(xi_power);
92 xi_power *= xi;
93 }
94
95 Ok(xi_powers)
96 }
97
98 #[allow(non_snake_case)]
100 pub(crate) fn response(mut self, f: &Vec<Vec<Scalar>>, z_A: &Scalar, z_C: &Scalar, z: &Scalar) -> TranscriptRng {
101 for f_row in f {
103 for f in f_row {
104 self.transcript.append_message(b"f", f.as_bytes());
105 }
106 }
107 self.transcript.append_message(b"z_A", z_A.as_bytes());
108 self.transcript.append_message(b"z_C", z_C.as_bytes());
109 self.transcript.append_message(b"z", z.as_bytes());
110
111 self.transcript_rng = Self::build_transcript_rng(self.transcript, self.witness, self.external_rng);
113
114 self.transcript_rng
115 }
116
117 pub(crate) fn as_mut_rng(&mut self) -> &mut TranscriptRng {
119 &mut self.transcript_rng
120 }
121
122 fn build_transcript_rng(
124 transcript: &Transcript,
125 witness: Option<&TriptychWitness>,
126 external_rng: &mut R,
127 ) -> TranscriptRng {
128 if let Some(witness) = witness {
129 transcript
130 .build_rng()
131 .rekey_with_witness_bytes(b"l", &witness.get_l().to_le_bytes())
132 .rekey_with_witness_bytes(b"r", witness.get_r().as_bytes())
133 .finalize(external_rng)
134 } else {
135 transcript.build_rng().finalize(external_rng)
136 }
137 }
138}