1use core::iter;
4
5use elliptic_curve::rand_core::CryptoRng;
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>(&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>(&self, value: G::Element, rng: &mut R) -> Ciphertext<G> {
27 ExtendedCiphertext::new(value, self, rng).inner
28 }
29
30 pub fn encrypt_zero<R>(&self, rng: &mut R) -> (Ciphertext<G>, LogEqualityProof<G>)
32 where
33 R: CryptoRng,
34 {
35 let random_scalar = SecretKey::<G>::generate(rng);
36 let random_element = G::mul_generator(&random_scalar.0);
37 let blinded_element = self.element * &random_scalar.0;
38 let ciphertext = Ciphertext {
39 random_element,
40 blinded_element,
41 };
42
43 let proof = LogEqualityProof::new(
44 self,
45 &random_scalar,
46 (random_element, blinded_element),
47 &mut Transcript::new(b"zero_encryption"),
48 rng,
49 );
50
51 (ciphertext, proof)
52 }
53
54 pub fn verify_zero(
60 &self,
61 ciphertext: Ciphertext<G>,
62 proof: &LogEqualityProof<G>,
63 ) -> Result<(), VerificationError> {
64 proof.verify(
65 self,
66 (ciphertext.random_element, ciphertext.blinded_element),
67 &mut Transcript::new(b"zero_encryption"),
68 )
69 }
70
71 pub fn encrypt_bool<R: CryptoRng>(
78 &self,
79 value: bool,
80 rng: &mut R,
81 ) -> (Ciphertext<G>, RingProof<G>) {
82 let mut transcript = Transcript::new(b"bool_encryption");
83 let admissible_values = [G::identity(), G::generator()];
84 let mut ring_responses = vec![G::Scalar::default(); 2];
85 let mut builder = RingProofBuilder::new(self, 1, &mut ring_responses, &mut transcript, rng);
86 let ciphertext = builder.add_value(&admissible_values, usize::from(value));
87 let proof = RingProof::new(builder.build(), ring_responses);
88 (ciphertext.inner, proof)
89 }
90
91 pub fn verify_bool(
102 &self,
103 ciphertext: Ciphertext<G>,
104 proof: &RingProof<G>,
105 ) -> Result<(), VerificationError> {
106 let admissible_values = [G::identity(), G::generator()];
107 proof.verify(
108 self,
109 iter::once(&admissible_values as &[_]),
110 iter::once(ciphertext),
111 &mut Transcript::new(b"bool_encryption"),
112 )
113 }
114
115 pub fn encrypt_range<R: CryptoRng>(
125 &self,
126 range: &PreparedRange<G>,
127 value: u64,
128 rng: &mut R,
129 ) -> (Ciphertext<G>, RangeProof<G>) {
130 let mut transcript = Transcript::new(b"ciphertext_range");
131 let (ciphertext, proof) = RangeProof::new(self, range, value, &mut transcript, rng);
132 (ciphertext.into(), proof)
133 }
134
135 pub fn verify_range(
144 &self,
145 range: &PreparedRange<G>,
146 ciphertext: Ciphertext<G>,
147 proof: &RangeProof<G>,
148 ) -> Result<(), VerificationError> {
149 let mut transcript = Transcript::new(b"ciphertext_range");
150 proof.verify(self, range, ciphertext, &mut transcript)
151 }
152}
153
154impl<G: Group> SecretKey<G> {
155 pub fn decrypt_to_element(&self, encrypted: Ciphertext<G>) -> G::Element {
161 let dh_element = encrypted.random_element * &self.0;
162 encrypted.blinded_element - dh_element
163 }
164
165 pub fn decrypt(
171 &self,
172 encrypted: Ciphertext<G>,
173 lookup_table: &DiscreteLogTable<G>,
174 ) -> Option<u64> {
175 lookup_table.get(&self.decrypt_to_element(encrypted))
176 }
177}