1use crate::{
14 rand_core::{CryptoRng, RngCore},
15 Sigma,
16};
17use core::marker::PhantomData;
18pub use curve25519_dalek;
19use curve25519_dalek::{constants::ED25519_BASEPOINT_TABLE, edwards::EdwardsPoint, scalar::Scalar};
20use digest::Update;
21use generic_array::{
22 typenum::{self, type_operators::IsLessOrEqual, U31},
23 ArrayLength, GenericArray,
24};
25
26#[derive(Clone, Debug, Default, PartialEq)]
28pub struct DL<L> {
29 challenge_len: PhantomData<L>,
30}
31
32impl<L: ArrayLength<u8>> Sigma for DL<L>
33where
34 L: IsLessOrEqual<U31>,
35 <L as IsLessOrEqual<U31>>::Output: typenum::marker_traits::NonZero,
36{
37 type Witness = Scalar;
38 type Statement = (EdwardsPoint, EdwardsPoint);
39 type AnnounceSecret = Scalar;
40 type Announcement = EdwardsPoint;
41 type Response = Scalar;
42 type ChallengeLength = L;
43
44 fn respond(
45 &self,
46 witness: &Self::Witness,
47 _statement: &Self::Statement,
48 announce_secret: Self::AnnounceSecret,
49 _announce: &Self::Announcement,
50 challenge: &GenericArray<u8, Self::ChallengeLength>,
51 ) -> Self::Response {
52 let challenge = normalize_challenge(challenge);
53 announce_secret + challenge * witness
54 }
55
56 fn announce(
57 &self,
58 statement: &Self::Statement,
59 announce_secret: &Self::AnnounceSecret,
60 ) -> Self::Announcement {
61 let G = &statement.0;
62 announce_secret * G
63 }
64
65 fn gen_announce_secret<Rng: CryptoRng + RngCore>(
66 &self,
67 _witness: &Self::Witness,
68 rng: &mut Rng,
69 ) -> Self::AnnounceSecret {
70 Scalar::random(rng)
71 }
72
73 fn sample_response<Rng: CryptoRng + RngCore>(&self, rng: &mut Rng) -> Self::Response {
74 Scalar::random(rng)
75 }
76
77 fn implied_announcement(
78 &self,
79 statement: &Self::Statement,
80 challenge: &GenericArray<u8, Self::ChallengeLength>,
81 response: &Self::Response,
82 ) -> Option<Self::Announcement> {
83 let (G, X) = statement;
84 let challenge = normalize_challenge(challenge);
85 Some(response * G - challenge * X)
86 }
87
88 fn hash_statement<H: Update>(&self, hash: &mut H, statement: &Self::Statement) {
89 hash.update(statement.0.compress().as_bytes());
90 hash.update(statement.1.compress().as_bytes());
91 }
92
93 fn hash_announcement<H: Update>(&self, hash: &mut H, announcement: &Self::Announcement) {
94 hash.update(announcement.compress().as_bytes())
95 }
96
97 fn hash_witness<H: Update>(&self, hash: &mut H, witness: &Self::Witness) {
98 hash.update(witness.to_bytes().as_ref())
99 }
100}
101
102#[derive(Clone, Debug, Default, PartialEq)]
105pub struct DLG<L> {
106 challenge_len: PhantomData<L>,
107}
108
109impl<L: ArrayLength<u8>> Sigma for DLG<L>
110where
111 L: IsLessOrEqual<U31>,
112 <L as IsLessOrEqual<U31>>::Output: typenum::marker_traits::NonZero,
113{
114 type Witness = Scalar;
115 type Statement = EdwardsPoint;
116 type AnnounceSecret = Scalar;
117 type Announcement = EdwardsPoint;
118 type Response = Scalar;
119 type ChallengeLength = L;
120
121 fn respond(
122 &self,
123 witness: &Self::Witness,
124 _statement: &Self::Statement,
125 announce_secret: Self::AnnounceSecret,
126 _announce: &Self::Announcement,
127 challenge: &GenericArray<u8, Self::ChallengeLength>,
128 ) -> Self::Response {
129 let challenge = normalize_challenge(challenge);
130 announce_secret + challenge * witness
131 }
132
133 fn announce(
134 &self,
135 _statement: &Self::Statement,
136 announce_secret: &Self::AnnounceSecret,
137 ) -> Self::Announcement {
138 let G = &ED25519_BASEPOINT_TABLE;
139 announce_secret * G
140 }
141
142 fn gen_announce_secret<Rng: CryptoRng + RngCore>(
143 &self,
144 _witness: &Self::Witness,
145 rng: &mut Rng,
146 ) -> Self::AnnounceSecret {
147 Scalar::random(rng)
148 }
149
150 fn sample_response<Rng: CryptoRng + RngCore>(&self, rng: &mut Rng) -> Self::Response {
151 Scalar::random(rng)
152 }
153
154 fn implied_announcement(
155 &self,
156 statement: &Self::Statement,
157 challenge: &GenericArray<u8, Self::ChallengeLength>,
158 response: &Self::Response,
159 ) -> Option<Self::Announcement> {
160 let X = statement;
161 let challenge = normalize_challenge(challenge);
162 Some(EdwardsPoint::vartime_double_scalar_mul_basepoint(
163 &-challenge,
164 X,
165 response,
166 ))
167 }
168
169 fn hash_statement<H: Update>(&self, hash: &mut H, statement: &Self::Statement) {
170 hash.update(statement.compress().as_bytes());
171 }
172
173 fn hash_announcement<H: Update>(&self, hash: &mut H, announcement: &Self::Announcement) {
174 hash.update(announcement.compress().as_bytes())
175 }
176
177 fn hash_witness<H: Update>(&self, hash: &mut H, witness: &Self::Witness) {
178 hash.update(witness.to_bytes().as_ref())
179 }
180}
181
182fn normalize_challenge<L: ArrayLength<u8>>(challenge: &GenericArray<u8, L>) -> Scalar {
183 let mut challenge_bytes = [0u8; 32];
184 challenge_bytes[..challenge.len()].copy_from_slice(challenge.as_slice());
185 Scalar::from_canonical_bytes(challenge_bytes)
186 .expect("this function is only passed 31 byte arrays at most")
187}
188
189impl<L> crate::Writable for DL<L> {
190 fn write_to<W: core::fmt::Write>(&self, w: &mut W) -> core::fmt::Result {
191 write!(w, "DL(ed25519)")
192 }
193}
194
195impl<L> crate::Writable for DLG<L> {
196 fn write_to<W: core::fmt::Write>(&self, w: &mut W) -> core::fmt::Result {
197 write!(w, "DLG(ed25519)")
198 }
199}
200
201crate::impl_display!(DL<L>);
202crate::impl_display!(DLG<L>);
203
204#[cfg(test)]
205#[allow(missing_docs)]
206pub mod test {
207 use super::*;
208 use crate::FiatShamir;
209 use ::proptest::prelude::*;
210 use sha2::Sha256;
211
212 prop_compose! {
213 pub fn ed25519_scalar()(
214 bytes in any::<[u8; 32]>(),
215 ) -> Scalar {
216 Scalar::from_bytes_mod_order(bytes)
217 }
218 }
219
220 prop_compose! {
221 pub fn ed25519_point()(
222 x in ed25519_scalar(),
223 ) -> EdwardsPoint {
224 &x * &ED25519_BASEPOINT_TABLE
225 }
226 }
227
228 type Transcript = crate::HashTranscript<Sha256, rand_chacha::ChaCha20Rng>;
229
230 proptest! {
231 #[test]
232 fn ed25519_dlg(
233 x in ed25519_scalar(),
234 ) {
235 let G = &ED25519_BASEPOINT_TABLE;
236 let xG = &x * G;
237 let proof_system = FiatShamir::<DLG<U31>, Transcript>::default();
238 let proof = proof_system.prove(&x, &xG, Some(&mut rand::thread_rng()));
239 assert!(proof_system.verify(&xG, &proof));
240 }
241 }
242
243 proptest! {
244 #[test]
245 fn ed25519_dl(
246 x in ed25519_scalar(),
247 ) {
248 let G = &Scalar::random(&mut rand::thread_rng()) * &ED25519_BASEPOINT_TABLE;
249 let xG = x * G;
250 let proof_system = FiatShamir::<DL<U31>, Transcript>::default();
251 let proof = proof_system.prove(&x, &(G, xG), Some(&mut rand::thread_rng()));
252 assert!(proof_system.verify(&(G, xG), &proof));
253 }
254 }
255}