pushed the file
pushed the file
This commit is contained in:
parent
ffb73d21c5
commit
b538f74bbd
199
file.rs
Normal file
199
file.rs
Normal file
|
@ -0,0 +1,199 @@
|
||||||
|
#![no_std]
|
||||||
|
use ark_ec::CurveGroup;
|
||||||
|
use ark_ff::{fields::PrimeField, UniformRand};
|
||||||
|
use ark_serialize::{CanonicalSerialize, SerializationError};
|
||||||
|
use ark_std::{marker::PhantomData, rand::Rng, vec::Vec};
|
||||||
|
use sha3::{
|
||||||
|
digest::{ExtendableOutput, Update, XofReader},
|
||||||
|
Shake128,
|
||||||
|
};
|
||||||
|
pub type Commitment<C> = C;
|
||||||
|
|
||||||
|
pub struct Ciphertext<C: CurveGroup> {
|
||||||
|
c1: C::Affine,
|
||||||
|
c2: C::Affine,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum Error {
|
||||||
|
SerializationError,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<C: CurveGroup> Ciphertext<C> {
|
||||||
|
fn serialize_compressed(&self) -> Result<(Vec<u8>, Vec<u8>), SerializationError> {
|
||||||
|
let mut c1_bytes = Vec::new();
|
||||||
|
let mut c2_bytes = Vec::new();
|
||||||
|
|
||||||
|
self.c1.serialize_compressed(&mut c1_bytes)?;
|
||||||
|
self.c2.serialize_compressed(&mut c2_bytes)?;
|
||||||
|
|
||||||
|
Ok((c1_bytes, c2_bytes))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct PoK<C: CurveGroup> {
|
||||||
|
pub t: C,
|
||||||
|
pub a: C,
|
||||||
|
pub z: C::ScalarField,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
pub struct Params<C: CurveGroup> {
|
||||||
|
pub g: C,
|
||||||
|
pub h: C,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct ElGamalSigmaProtocol<C> {
|
||||||
|
_c: PhantomData<C>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<C: CurveGroup> ElGamalSigmaProtocol<C> {
|
||||||
|
pub fn prove<R: Rng + Sized>(
|
||||||
|
s: C::ScalarField,
|
||||||
|
params: Params<C>,
|
||||||
|
mut rng: R,
|
||||||
|
) -> (Commitment<C>, Ciphertext<C>, PoK<C>) {
|
||||||
|
let r = C::ScalarField::rand(&mut rng);
|
||||||
|
let c1 = params.g * r;
|
||||||
|
let c2 = params.h * (s * r);
|
||||||
|
|
||||||
|
let ct: Ciphertext<C> = Ciphertext {
|
||||||
|
c1: c1.into(),
|
||||||
|
c2: c2.into(),
|
||||||
|
};
|
||||||
|
let c: Commitment<C> = params.g * s + params.h * s;
|
||||||
|
|
||||||
|
let k = C::ScalarField::rand(&mut rng);
|
||||||
|
let t = params.g * k;
|
||||||
|
let a = params.h * k;
|
||||||
|
|
||||||
|
let mut t_bytes = Vec::new();
|
||||||
|
let mut a_bytes = Vec::new();
|
||||||
|
t.serialize_compressed(&mut t_bytes)
|
||||||
|
.expect("group element should exist");
|
||||||
|
a.serialize_compressed(&mut a_bytes)
|
||||||
|
.expect("group element should exist");
|
||||||
|
|
||||||
|
let mut inputs = Vec::new();
|
||||||
|
inputs.push(t_bytes);
|
||||||
|
inputs.push(a_bytes);
|
||||||
|
let (c1_bytes, c2_bytes) = ct
|
||||||
|
.serialize_compressed()
|
||||||
|
.expect("group elements should exist");
|
||||||
|
inputs.push(c1_bytes);
|
||||||
|
inputs.push(c2_bytes);
|
||||||
|
|
||||||
|
let challenge: C::ScalarField =
|
||||||
|
C::ScalarField::from_be_bytes_mod_order(&shake128(inputs.as_ref()));
|
||||||
|
let z = k + challenge * s;
|
||||||
|
(c, ct, PoK { t, a, z })
|
||||||
|
}
|
||||||
|
pub fn verify(
|
||||||
|
commitment: Commitment<C>,
|
||||||
|
ciphertext: Ciphertext<C>,
|
||||||
|
proof: PoK<C>,
|
||||||
|
params: Params<C>,
|
||||||
|
) -> bool {
|
||||||
|
let mut t_bytes = Vec::new();
|
||||||
|
let mut a_bytes = Vec::new();
|
||||||
|
proof
|
||||||
|
.t
|
||||||
|
.serialize_compressed(&mut t_bytes)
|
||||||
|
.expect("group element should exist");
|
||||||
|
proof
|
||||||
|
.a
|
||||||
|
.serialize_compressed(&mut a_bytes)
|
||||||
|
.expect("group element should exist");
|
||||||
|
|
||||||
|
let mut inputs = Vec::new();
|
||||||
|
inputs.push(t_bytes);
|
||||||
|
inputs.push(a_bytes);
|
||||||
|
let (c1_bytes, c2_bytes) = ciphertext
|
||||||
|
.serialize_compressed()
|
||||||
|
.expect("group element should exist");
|
||||||
|
inputs.push(c1_bytes);
|
||||||
|
inputs.push(c2_bytes);
|
||||||
|
|
||||||
|
let challenge: C::ScalarField =
|
||||||
|
C::ScalarField::from_be_bytes_mod_order(&shake128(inputs.as_ref()));
|
||||||
|
|
||||||
|
let zg = params.g * proof.z;
|
||||||
|
let zh = params.h * proof.z;
|
||||||
|
|
||||||
|
zg + zh == proof.t + proof.a + commitment * challenge
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn shake128(input: &[Vec<u8>]) -> [u8; 32] {
|
||||||
|
let mut h = Shake128::default();
|
||||||
|
for item in input.iter() {
|
||||||
|
h.update(item);
|
||||||
|
}
|
||||||
|
let mut o = [0u8; 32];
|
||||||
|
h.finalize_xof().read(&mut o);
|
||||||
|
o
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test {
|
||||||
|
|
||||||
|
use super::*;
|
||||||
|
use ark_ec::Group;
|
||||||
|
use ark_ed_on_bls12_381::EdwardsProjective as JubJub;
|
||||||
|
use ark_std::{ops::Mul, test_rng};
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
pub fn prove_and_verify() {
|
||||||
|
let mut rng = test_rng();
|
||||||
|
let x = <JubJub as Group>::ScalarField::rand(&mut rng);
|
||||||
|
let g: JubJub = JubJub::generator().into();
|
||||||
|
let h: JubJub = g.mul(x).into();
|
||||||
|
|
||||||
|
let params = Params { g, h };
|
||||||
|
|
||||||
|
let (commitment, ciphertext, proof) =
|
||||||
|
ElGamalSigmaProtocol::prove(x, params.clone(), test_rng());
|
||||||
|
let result = ElGamalSigmaProtocol::verify(commitment, ciphertext, proof, params);
|
||||||
|
assert_eq!(result, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
pub fn verify_fails_with_invalid_proof() {
|
||||||
|
let mut rng = test_rng();
|
||||||
|
let x = <JubJub as Group>::ScalarField::rand(&mut rng);
|
||||||
|
let g: JubJub = JubJub::generator().into();
|
||||||
|
let h: JubJub = g.mul(x).into();
|
||||||
|
|
||||||
|
let j = <JubJub as Group>::ScalarField::rand(&mut rng);
|
||||||
|
let bad_proof = PoK {
|
||||||
|
t: g.mul(j).into(),
|
||||||
|
a: g.mul(j).into(),
|
||||||
|
z: j,
|
||||||
|
};
|
||||||
|
|
||||||
|
let params = Params { g, h };
|
||||||
|
|
||||||
|
let (commitment, ciphertext, _proof) =
|
||||||
|
ElGamalSigmaProtocol::prove(x, params.clone(), test_rng());
|
||||||
|
let result = ElGamalSigmaProtocol::verify(commitment, ciphertext, bad_proof, params);
|
||||||
|
assert_eq!(result, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
pub fn verify_fails_with_invalid_commitment() {
|
||||||
|
let mut rng = test_rng();
|
||||||
|
let x = <JubJub as Group>::ScalarField::rand(&mut rng);
|
||||||
|
let g: JubJub = JubJub::generator().into();
|
||||||
|
let h: JubJub = g.mul(x).into();
|
||||||
|
|
||||||
|
let j = <JubJub as Group>::ScalarField::rand(&mut rng);
|
||||||
|
let bad_commitment = g.mul(j).into();
|
||||||
|
|
||||||
|
let params = Params { g, h };
|
||||||
|
|
||||||
|
let (_commitment, ciphertext, proof) =
|
||||||
|
ElGamalSigmaProtocol::prove(x, params.clone(), test_rng());
|
||||||
|
let result = ElGamalSigmaProtocol::verify(bad_commitment, ciphertext, proof, params);
|
||||||
|
assert_eq!(result, false);
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue