1use core::iter;
4
5use elliptic_curve::rand_core::{CryptoRng, RngCore};
6use merlin::Transcript;
7
8use crate::{
9 Ciphertext, DiscreteLogTable, LogEqualityProof, PreparedRange, PublicKey, RangeProof,
10 RingProof, RingProofBuilder, SecretKey, VerificationError, alloc::vec,
11 encryption::ExtendedCiphertext, group::Group,
12};
13
14impl<G: Group> PublicKey<G> {
15 pub fn encrypt<T, R: CryptoRng + RngCore>(&self, value: T, rng: &mut R) -> Ciphertext<G>
17 where
18 G::Scalar: From<T>,
19 {
20 let scalar = G::Scalar::from(value);
21 let element = G::mul_generator(&scalar);
22 ExtendedCiphertext::new(element, self, rng).inner
23 }
24
25 pub fn encrypt_element<R: CryptoRng + RngCore>(
27 &self,
28 value: G::Element,
29 rng: &mut R,
30 ) -> Ciphertext<G> {
31 ExtendedCiphertext::new(value, self, rng).inner
32 }
33
34 pub fn encrypt_zero<R>(&self, rng: &mut R) -> (Ciphertext<G>, LogEqualityProof<G>)
36 where
37 R: CryptoRng + RngCore,
38 {
39 let random_scalar = SecretKey::<G>::generate(rng);
40 let random_element = G::mul_generator(&random_scalar.0);
41 let blinded_element = self.element * &random_scalar.0;
42 let ciphertext = Ciphertext {
43 random_element,
44 blinded_element,
45 };
46
47 let proof = LogEqualityProof::new(
48 self,
49 &random_scalar,
50 (random_element, blinded_element),
51 &mut Transcript::new(b"zero_encryption"),
52 rng,
53 );
54
55 (ciphertext, proof)
56 }
57
58 pub fn verify_zero(
64 &self,
65 ciphertext: Ciphertext<G>,
66 proof: &LogEqualityProof<G>,
67 ) -> Result<(), VerificationError> {
68 proof.verify(
69 self,
70 (ciphertext.random_element, ciphertext.blinded_element),
71 &mut Transcript::new(b"zero_encryption"),
72 )
73 }
74
75 pub fn encrypt_bool<R: CryptoRng + RngCore>(
82 &self,
83 value: bool,
84 rng: &mut R,
85 ) -> (Ciphertext<G>, RingProof<G>) {
86 let mut transcript = Transcript::new(b"bool_encryption");
87 let admissible_values = [G::identity(), G::generator()];
88 let mut ring_responses = vec![G::Scalar::default(); 2];
89 let mut builder = RingProofBuilder::new(self, 1, &mut ring_responses, &mut transcript, rng);
90 let ciphertext = builder.add_value(&admissible_values, usize::from(value));
91 let proof = RingProof::new(builder.build(), ring_responses);
92 (ciphertext.inner, proof)
93 }
94
95 pub fn verify_bool(
106 &self,
107 ciphertext: Ciphertext<G>,
108 proof: &RingProof<G>,
109 ) -> Result<(), VerificationError> {
110 let admissible_values = [G::identity(), G::generator()];
111 proof.verify(
112 self,
113 iter::once(&admissible_values as &[_]),
114 iter::once(ciphertext),
115 &mut Transcript::new(b"bool_encryption"),
116 )
117 }
118
119 pub fn encrypt_range<R: CryptoRng + RngCore>(
129 &self,
130 range: &PreparedRange<G>,
131 value: u64,
132 rng: &mut R,
133 ) -> (Ciphertext<G>, RangeProof<G>) {
134 let mut transcript = Transcript::new(b"ciphertext_range");
135 let (ciphertext, proof) = RangeProof::new(self, range, value, &mut transcript, rng);
136 (ciphertext.into(), proof)
137 }
138
139 pub fn verify_range(
148 &self,
149 range: &PreparedRange<G>,
150 ciphertext: Ciphertext<G>,
151 proof: &RangeProof<G>,
152 ) -> Result<(), VerificationError> {
153 let mut transcript = Transcript::new(b"ciphertext_range");
154 proof.verify(self, range, ciphertext, &mut transcript)
155 }
156}
157
158impl<G: Group> SecretKey<G> {
159 pub fn decrypt_to_element(&self, encrypted: Ciphertext<G>) -> G::Element {
165 let dh_element = encrypted.random_element * &self.0;
166 encrypted.blinded_element - dh_element
167 }
168
169 pub fn decrypt(
175 &self,
176 encrypted: Ciphertext<G>,
177 lookup_table: &DiscreteLogTable<G>,
178 ) -> Option<u64> {
179 lookup_table.get(&self.decrypt_to_element(encrypted))
180 }
181}