1#![no_std]
2
3use elliptic_curve::{
4 ff::PrimeField,
5 ops::Reduce,
6 sec1::{ModulusSize, ToEncodedPoint},
7 CurveArithmetic, FieldBytes,
8};
9
10#[cfg(feature = "merlin")]
11pub use merlin_imp::Transcript;
12
13#[cfg(all(not(feature = "merlin"), feature = "shake128"))]
14pub use shake128::Transcript;
15
16pub trait TranscriptProtocol {
22 fn new(label: &'static [u8]) -> Self
24 where
25 Self: Sized;
26
27 fn append_message(&mut self, label: &'static [u8], message: &[u8]);
29
30 fn append_u64(&mut self, label: &'static [u8], value: u64);
32
33 fn challenge_bytes(&mut self, label: &'static [u8], dest: &mut [u8]);
35
36 fn append_point<C>(
38 &mut self,
39 label: &'static [u8],
40 point: &C::ProjectivePoint,
41 ) where
42 C: CurveArithmetic,
43 C::FieldBytesSize: ModulusSize,
44 C::ProjectivePoint: ToEncodedPoint<C>,
45 {
46 self.append_message(label, point.to_encoded_point(true).as_ref())
47 }
48
49 fn append_scalar<C>(&mut self, label: &'static [u8], scalar: &C::Scalar)
51 where
52 C: CurveArithmetic,
53 C::FieldBytesSize: ModulusSize,
54 C::ProjectivePoint: ToEncodedPoint<C>,
55 {
56 let bytes = scalar.to_repr();
57 self.append_message(label, bytes.as_ref())
58 }
59
60 fn challenge_scalar<C>(&mut self, label: &'static [u8]) -> C::Scalar
62 where
63 C: CurveArithmetic,
64 C::FieldBytesSize: ModulusSize,
65 C::ProjectivePoint: ToEncodedPoint<C>,
66 {
67 let mut buf = FieldBytes::<C>::default();
68 self.challenge_bytes(label, &mut buf);
69 C::Scalar::reduce_bytes(&buf)
70 }
71
72 fn new_dlog_proof(
74 session_id: &[u8],
75 party_id: usize,
76 action: &[u8],
77 label: &'static [u8],
78 ) -> Self
79 where
80 Self: Sized,
81 {
82 let mut transcript = Self::new(label);
83 transcript.append_message(b"session_id", session_id.as_ref());
84 transcript.append_u64(b"party_id", party_id as u64);
85 transcript.append_message(b"action", action);
86 transcript
87 }
88}
89
90#[cfg(feature = "merlin")]
91mod merlin_imp {
92 use super::*;
93
94 pub struct Transcript(merlin::Transcript);
95
96 impl Transcript {
97 pub fn new(label: &'static [u8]) -> Self {
98 Self(merlin::Transcript::new(label))
99 }
100 }
101
102 impl TranscriptProtocol for Transcript {
103 fn new(label: &'static [u8]) -> Self {
104 Self::new(label)
105 }
106
107 fn append_message(&mut self, label: &'static [u8], message: &[u8]) {
108 self.0.append_message(label, message);
109 }
110
111 fn append_u64(&mut self, label: &'static [u8], value: u64) {
112 self.0.append_u64(label, value)
113 }
114
115 fn challenge_bytes(&mut self, label: &'static [u8], dest: &mut [u8]) {
116 self.0.challenge_bytes(label, dest);
117 }
118 }
119}
120
121#[cfg(feature = "shake128")]
122mod shake128 {
123 use super::TranscriptProtocol;
124
125 use sha3::{
126 digest::{ExtendableOutput, Update, XofReader},
127 Shake128,
128 };
129
130 pub struct Transcript(Shake128);
131
132 impl Transcript {
133 pub fn new(label: &'static [u8]) -> Self {
134 let mut t = Shake128::default();
135 t.update(&(label.len() as u64).to_le_bytes());
136 t.update(label);
137 Self(t)
138 }
139 }
140
141 impl TranscriptProtocol for Transcript {
142 fn new(label: &'static [u8]) -> Self {
143 Self::new(label)
144 }
145
146 fn append_message(&mut self, label: &'static [u8], message: &[u8]) {
147 self.0.update(&(label.len() as u64).to_le_bytes());
148 self.0.update(label);
149 self.0.update(&(message.len() as u64).to_le_bytes());
150 self.0.update(message);
151 }
152
153 fn append_u64(&mut self, label: &'static [u8], value: u64) {
154 self.append_message(label, &value.to_le_bytes());
155 }
156
157 fn challenge_bytes(&mut self, label: &'static [u8], dest: &mut [u8]) {
158 self.0.update(&(label.len() as u32).to_le_bytes());
159 self.0.update(label);
160 self.0.update(&(dest.len() as u32).to_le_bytes());
161
162 self.0.clone().finalize_xof().read(dest);
163 }
164 }
165}