chaum_pedersen/primitives/
transcript.rs1use curve25519_dalek::scalar::Scalar as DalekScalar;
6use merlin::Transcript as MerlinTranscript;
7
8use super::Scalar;
9
10const PROTOCOL_LABEL: &[u8] = b"Chaum-Pedersen ZKP v1.0.0";
12
13const PROTOCOL_DST: &[u8] = b"chaum-pedersen-ristretto255";
15
16const CHALLENGE_DST: &[u8] = b"challenge";
18
19const WIDE_REDUCTION_BYTES: usize = 64;
21
22pub struct Transcript(MerlinTranscript);
26
27impl Transcript {
28 pub fn new() -> Self {
30 let mut transcript = MerlinTranscript::new(PROTOCOL_LABEL);
31 transcript.append_message(b"protocol", PROTOCOL_DST);
32 Self(transcript)
33 }
34
35 pub fn append_context(&mut self, context: &[u8]) {
43 self.0.append_message(b"context", context);
44 }
45
46 pub fn append_parameters(&mut self, generator_g: &[u8], generator_h: &[u8]) {
48 self.0.append_message(b"generator-g", generator_g);
49 self.0.append_message(b"generator-h", generator_h);
50 }
51
52 pub fn append_statement(&mut self, y1: &[u8], y2: &[u8]) {
54 self.0.append_message(b"y1", y1);
55 self.0.append_message(b"y2", y2);
56 }
57
58 pub fn append_commitment(&mut self, r1: &[u8], r2: &[u8]) {
60 self.0.append_message(b"r1", r1);
61 self.0.append_message(b"r2", r2);
62 }
63
64 pub fn challenge_scalar(&mut self) -> Scalar {
68 let mut buf = [0u8; WIDE_REDUCTION_BYTES];
69 self.0.challenge_bytes(CHALLENGE_DST, &mut buf);
70 Scalar::new(DalekScalar::from_bytes_mod_order_wide(&buf))
71 }
72}
73
74impl Default for Transcript {
75 fn default() -> Self {
76 Self::new()
77 }
78}
79
80#[cfg(test)]
81mod tests {
82 use super::*;
83
84 #[test]
85 fn transcript_creation() {
86 let transcript = Transcript::new();
87 assert!(core::mem::size_of_val(&transcript) > 0);
88 }
89
90 #[test]
91 fn challenge_scalar_deterministic() {
92 let mut t1 = Transcript::new();
93 t1.append_parameters(b"g", b"h");
94 t1.append_statement(b"y1", b"y2");
95 t1.append_commitment(b"r1", b"r2");
96 let c1 = t1.challenge_scalar();
97
98 let mut t2 = Transcript::new();
99 t2.append_parameters(b"g", b"h");
100 t2.append_statement(b"y1", b"y2");
101 t2.append_commitment(b"r1", b"r2");
102 let c2 = t2.challenge_scalar();
103
104 assert_eq!(c1, c2);
105 }
106
107 #[test]
108 fn challenge_scalar_different_inputs() {
109 let mut t1 = Transcript::new();
110 t1.append_commitment(b"r1", b"r2");
111 let c1 = t1.challenge_scalar();
112
113 let mut t2 = Transcript::new();
114 t2.append_commitment(b"r1_different", b"r2");
115 let c2 = t2.challenge_scalar();
116
117 assert_ne!(c1, c2);
118 }
119}