Skip to main content

sigma_proof_compiler/
transcript.rs

1use curve25519_dalek::{
2    ristretto::{CompressedRistretto, RistrettoPoint},
3    scalar::Scalar,
4};
5use std::io::{Read, Write};
6
7pub(crate) struct ProofTranscript {
8    state: merlin::Transcript,
9    proof: std::io::Cursor<Vec<u8>>,
10    is_prover: bool,
11}
12
13impl ProofTranscript {
14    pub(crate) fn new_prover(label: &'static [u8]) -> Self {
15        Self {
16            state: merlin::Transcript::new(label),
17            proof: std::io::Cursor::new(Vec::new()),
18            is_prover: true,
19        }
20    }
21
22    pub(crate) fn new_verifier(label: &'static [u8], proof: &[u8]) -> Self {
23        Self {
24            state: merlin::Transcript::new(label),
25            proof: std::io::Cursor::new(proof.to_vec()),
26            is_prover: false,
27        }
28    }
29
30    pub(crate) fn common_absorb_scalar(&mut self, label: &'static [u8], scalar: &Scalar) {
31        self.state.append_message(label, scalar.as_bytes());
32    }
33
34    pub(crate) fn common_absorb_point(&mut self, label: &'static [u8], point: &RistrettoPoint) {
35        self.state
36            .append_message(label, point.compress().as_bytes());
37    }
38
39    pub(crate) fn prover_absorb_scalar(&mut self, label: &'static [u8], scalar: &Scalar) {
40        assert!(self.is_prover);
41        self.common_absorb_scalar(label, scalar);
42        self.proof.write_all(scalar.as_bytes()).unwrap();
43    }
44
45    pub(crate) fn verifier_receives_all_scalars(
46        &mut self,
47        label: &'static [u8],
48    ) -> Option<Vec<Scalar>> {
49        assert!(!self.is_prover);
50        let mut scalars = Vec::new();
51        loop {
52            let mut buf = [0u8; 32];
53            match self.proof.read_exact(&mut buf) {
54                Ok(()) => {
55                    let scalar = Scalar::from_canonical_bytes(buf).into_option()?;
56                    self.common_absorb_scalar(label, &scalar);
57                    scalars.push(scalar);
58                }
59                Err(_) => break,
60            }
61        }
62        Some(scalars)
63    }
64
65    pub(crate) fn prover_absorb_point(&mut self, label: &'static [u8], point: &RistrettoPoint) {
66        assert!(self.is_prover);
67        self.common_absorb_point(label, &point);
68        self.proof.write_all(point.compress().as_bytes()).unwrap();
69    }
70
71    pub(crate) fn verifier_receive_points(
72        &mut self,
73        label: &'static [u8],
74        count: usize,
75    ) -> Option<Vec<RistrettoPoint>> {
76        assert!(!self.is_prover);
77        let mut points = Vec::with_capacity(count);
78        for _ in 0..count {
79            let mut buf = [0u8; 32];
80            if self.proof.read_exact(&mut buf).is_err() {
81                return None;
82            }
83            let point = CompressedRistretto(buf).decompress()?;
84            self.common_absorb_point(label, &point); // TODO: we recompress here :/
85            points.push(point);
86        }
87        Some(points)
88    }
89
90    pub(crate) fn challenge(&mut self, label: &'static [u8]) -> Scalar {
91        let mut buf = [0u8; 64];
92        self.state.challenge_bytes(label, &mut buf);
93        Scalar::from_bytes_mod_order_wide(&buf)
94    }
95
96    pub(crate) fn finalize(self) -> Vec<u8> {
97        self.proof.into_inner()
98    }
99}