|
| 1 | +use ark_r1cs_std::prelude::*; |
| 2 | +use ark_relations::r1cs::{Namespace, SynthesisError}; |
| 3 | + |
| 4 | +use crate::encryption::elgamal::{ |
| 5 | + Ciphertext, ElGamal, Parameters, Plaintext, PublicKey, Randomness, |
| 6 | +}; |
| 7 | +use crate::encryption::AsymmetricEncryptionGadget; |
| 8 | +use ark_ec::ProjectiveCurve; |
| 9 | +use ark_ff::{ |
| 10 | + fields::{Field, PrimeField}, |
| 11 | + to_bytes, Zero, |
| 12 | +}; |
| 13 | +use core::{borrow::Borrow, marker::PhantomData}; |
| 14 | + |
| 15 | +pub type ConstraintF<C> = <<C as ProjectiveCurve>::BaseField as Field>::BasePrimeField; |
| 16 | + |
| 17 | +#[derive(Clone, Debug)] |
| 18 | +pub struct RandomnessVar<F: Field>(Vec<UInt8<F>>); |
| 19 | + |
| 20 | +impl<C, F> AllocVar<Randomness<C>, F> for RandomnessVar<F> |
| 21 | +where |
| 22 | + C: ProjectiveCurve, |
| 23 | + F: PrimeField, |
| 24 | +{ |
| 25 | + fn new_variable<T: Borrow<Randomness<C>>>( |
| 26 | + cs: impl Into<Namespace<F>>, |
| 27 | + f: impl FnOnce() -> Result<T, SynthesisError>, |
| 28 | + mode: AllocationMode, |
| 29 | + ) -> Result<Self, SynthesisError> { |
| 30 | + let r = to_bytes![&f().map(|b| b.borrow().0).unwrap_or(C::ScalarField::zero())].unwrap(); |
| 31 | + match mode { |
| 32 | + AllocationMode::Constant => Ok(Self(UInt8::constant_vec(&r))), |
| 33 | + AllocationMode::Input => UInt8::new_input_vec(cs, &r).map(Self), |
| 34 | + AllocationMode::Witness => UInt8::new_witness_vec(cs, &r).map(Self), |
| 35 | + } |
| 36 | + } |
| 37 | +} |
| 38 | + |
| 39 | +#[derive(Derivative)] |
| 40 | +#[derivative(Clone(bound = "C: ProjectiveCurve, GG: CurveVar<C, ConstraintF<C>>"))] |
| 41 | +pub struct ParametersVar<C: ProjectiveCurve, GG: CurveVar<C, ConstraintF<C>>> |
| 42 | +where |
| 43 | + for<'a> &'a GG: GroupOpsBounds<'a, C, GG>, |
| 44 | +{ |
| 45 | + generator: GG, |
| 46 | + #[doc(hidden)] |
| 47 | + _curve: PhantomData<C>, |
| 48 | +} |
| 49 | + |
| 50 | +impl<C, GG> AllocVar<Parameters<C>, ConstraintF<C>> for ParametersVar<C, GG> |
| 51 | +where |
| 52 | + C: ProjectiveCurve, |
| 53 | + GG: CurveVar<C, ConstraintF<C>>, |
| 54 | + for<'a> &'a GG: GroupOpsBounds<'a, C, GG>, |
| 55 | +{ |
| 56 | + fn new_variable<T: Borrow<Parameters<C>>>( |
| 57 | + cs: impl Into<Namespace<ConstraintF<C>>>, |
| 58 | + f: impl FnOnce() -> Result<T, SynthesisError>, |
| 59 | + mode: AllocationMode, |
| 60 | + ) -> Result<Self, SynthesisError> { |
| 61 | + let generator = GG::new_variable(cs, || f().map(|g| g.borrow().generator), mode)?; |
| 62 | + Ok(Self { |
| 63 | + generator, |
| 64 | + _curve: PhantomData, |
| 65 | + }) |
| 66 | + } |
| 67 | +} |
| 68 | + |
| 69 | +#[derive(Derivative)] |
| 70 | +#[derivative(Clone(bound = "C: ProjectiveCurve, GG: CurveVar<C, ConstraintF<C>>"))] |
| 71 | +pub struct PlaintextVar<C: ProjectiveCurve, GG: CurveVar<C, ConstraintF<C>>> |
| 72 | +where |
| 73 | + for<'a> &'a GG: GroupOpsBounds<'a, C, GG>, |
| 74 | +{ |
| 75 | + pub plaintext: GG, |
| 76 | + #[doc(hidden)] |
| 77 | + _curve: PhantomData<C>, |
| 78 | +} |
| 79 | + |
| 80 | +impl<C, GG> AllocVar<Plaintext<C>, ConstraintF<C>> for PlaintextVar<C, GG> |
| 81 | +where |
| 82 | + C: ProjectiveCurve, |
| 83 | + GG: CurveVar<C, ConstraintF<C>>, |
| 84 | + for<'a> &'a GG: GroupOpsBounds<'a, C, GG>, |
| 85 | +{ |
| 86 | + fn new_variable<T: Borrow<Plaintext<C>>>( |
| 87 | + cs: impl Into<Namespace<ConstraintF<C>>>, |
| 88 | + f: impl FnOnce() -> Result<T, SynthesisError>, |
| 89 | + mode: AllocationMode, |
| 90 | + ) -> Result<Self, SynthesisError> { |
| 91 | + let plaintext = GG::new_variable(cs, f, mode)?; |
| 92 | + Ok(Self { |
| 93 | + plaintext, |
| 94 | + _curve: PhantomData, |
| 95 | + }) |
| 96 | + } |
| 97 | +} |
| 98 | + |
| 99 | +#[derive(Derivative)] |
| 100 | +#[derivative(Clone(bound = "C: ProjectiveCurve, GG: CurveVar<C, ConstraintF<C>>"))] |
| 101 | +pub struct PublicKeyVar<C: ProjectiveCurve, GG: CurveVar<C, ConstraintF<C>>> |
| 102 | +where |
| 103 | + for<'a> &'a GG: GroupOpsBounds<'a, C, GG>, |
| 104 | +{ |
| 105 | + pub pk: GG, |
| 106 | + #[doc(hidden)] |
| 107 | + _curve: PhantomData<C>, |
| 108 | +} |
| 109 | + |
| 110 | +impl<C, GG> AllocVar<PublicKey<C>, ConstraintF<C>> for PublicKeyVar<C, GG> |
| 111 | +where |
| 112 | + C: ProjectiveCurve, |
| 113 | + GG: CurveVar<C, ConstraintF<C>>, |
| 114 | + for<'a> &'a GG: GroupOpsBounds<'a, C, GG>, |
| 115 | +{ |
| 116 | + fn new_variable<T: Borrow<PublicKey<C>>>( |
| 117 | + cs: impl Into<Namespace<ConstraintF<C>>>, |
| 118 | + f: impl FnOnce() -> Result<T, SynthesisError>, |
| 119 | + mode: AllocationMode, |
| 120 | + ) -> Result<Self, SynthesisError> { |
| 121 | + let pk = GG::new_variable(cs, f, mode)?; |
| 122 | + Ok(Self { |
| 123 | + pk, |
| 124 | + _curve: PhantomData, |
| 125 | + }) |
| 126 | + } |
| 127 | +} |
| 128 | + |
| 129 | +#[derive(Derivative, Debug)] |
| 130 | +#[derivative(Clone(bound = "C: ProjectiveCurve, GG: CurveVar<C, ConstraintF<C>>"))] |
| 131 | +pub struct OutputVar<C: ProjectiveCurve, GG: CurveVar<C, ConstraintF<C>>> |
| 132 | +where |
| 133 | + for<'a> &'a GG: GroupOpsBounds<'a, C, GG>, |
| 134 | +{ |
| 135 | + pub c1: GG, |
| 136 | + pub c2: GG, |
| 137 | + #[doc(hidden)] |
| 138 | + _curve: PhantomData<C>, |
| 139 | +} |
| 140 | + |
| 141 | +impl<C, GG> AllocVar<Ciphertext<C>, ConstraintF<C>> for OutputVar<C, GG> |
| 142 | +where |
| 143 | + C: ProjectiveCurve, |
| 144 | + GG: CurveVar<C, ConstraintF<C>>, |
| 145 | + for<'a> &'a GG: GroupOpsBounds<'a, C, GG>, |
| 146 | +{ |
| 147 | + fn new_variable<T: Borrow<Ciphertext<C>>>( |
| 148 | + cs: impl Into<Namespace<ConstraintF<C>>>, |
| 149 | + f: impl FnOnce() -> Result<T, SynthesisError>, |
| 150 | + mode: AllocationMode, |
| 151 | + ) -> Result<Self, SynthesisError> { |
| 152 | + let ns = cs.into(); |
| 153 | + let cs = ns.cs(); |
| 154 | + let prep = f().map(|g| *g.borrow()); |
| 155 | + let c1 = GG::new_variable(cs.clone(), || prep.map(|g| g.borrow().0), mode)?; |
| 156 | + let c2 = GG::new_variable(cs.clone(), || prep.map(|g| g.borrow().1), mode)?; |
| 157 | + Ok(Self { |
| 158 | + c1, |
| 159 | + c2, |
| 160 | + _curve: PhantomData, |
| 161 | + }) |
| 162 | + } |
| 163 | +} |
| 164 | + |
| 165 | +impl<C, GC> EqGadget<ConstraintF<C>> for OutputVar<C, GC> |
| 166 | +where |
| 167 | + C: ProjectiveCurve, |
| 168 | + GC: CurveVar<C, ConstraintF<C>>, |
| 169 | + for<'a> &'a GC: GroupOpsBounds<'a, C, GC>, |
| 170 | +{ |
| 171 | + #[inline] |
| 172 | + fn is_eq(&self, other: &Self) -> Result<Boolean<ConstraintF<C>>, SynthesisError> { |
| 173 | + self.c1.is_eq(&other.c1)?.and(&self.c2.is_eq(&other.c2)?) |
| 174 | + } |
| 175 | +} |
| 176 | + |
| 177 | +pub struct ElGamalEncGadget<C: ProjectiveCurve, GG: CurveVar<C, ConstraintF<C>>> |
| 178 | +where |
| 179 | + for<'a> &'a GG: GroupOpsBounds<'a, C, GG>, |
| 180 | +{ |
| 181 | + #[doc(hidden)] |
| 182 | + _curve: PhantomData<*const C>, |
| 183 | + _group_var: PhantomData<*const GG>, |
| 184 | +} |
| 185 | + |
| 186 | +impl<C, GG> AsymmetricEncryptionGadget<ElGamal<C>, ConstraintF<C>> for ElGamalEncGadget<C, GG> |
| 187 | +where |
| 188 | + C: ProjectiveCurve, |
| 189 | + GG: CurveVar<C, ConstraintF<C>>, |
| 190 | + for<'a> &'a GG: GroupOpsBounds<'a, C, GG>, |
| 191 | + ConstraintF<C>: PrimeField, |
| 192 | +{ |
| 193 | + type OutputVar = OutputVar<C, GG>; |
| 194 | + type ParametersVar = ParametersVar<C, GG>; |
| 195 | + type PlaintextVar = PlaintextVar<C, GG>; |
| 196 | + type PublicKeyVar = PublicKeyVar<C, GG>; |
| 197 | + type RandomnessVar = RandomnessVar<ConstraintF<C>>; |
| 198 | + |
| 199 | + fn encrypt( |
| 200 | + parameters: &Self::ParametersVar, |
| 201 | + message: &Self::PlaintextVar, |
| 202 | + randomness: &Self::RandomnessVar, |
| 203 | + public_key: &Self::PublicKeyVar, |
| 204 | + ) -> Result<Self::OutputVar, SynthesisError> { |
| 205 | + // flatten randomness to little-endian bit vector |
| 206 | + let randomness = randomness |
| 207 | + .0 |
| 208 | + .iter() |
| 209 | + .flat_map(|b| b.to_bits_le().unwrap()) |
| 210 | + .collect::<Vec<_>>(); |
| 211 | + |
| 212 | + // compute s = randomness*pk |
| 213 | + let s = public_key.pk.clone().scalar_mul_le(randomness.iter())?; |
| 214 | + |
| 215 | + // compute c1 = randomness*generator |
| 216 | + let c1 = parameters |
| 217 | + .generator |
| 218 | + .clone() |
| 219 | + .scalar_mul_le(randomness.iter())?; |
| 220 | + |
| 221 | + // compute c2 = m + s |
| 222 | + let c2 = message.plaintext.clone() + s; |
| 223 | + |
| 224 | + Ok(Self::OutputVar { |
| 225 | + c1, |
| 226 | + c2, |
| 227 | + _curve: PhantomData, |
| 228 | + }) |
| 229 | + } |
| 230 | +} |
0 commit comments