zei 0.0.10

Zei: Confidential Assets
Documentation
// Copyright 2019 Stichting Organism
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! Equality Proof

use bacteria::Transcript;
use mohan::{
    ser,
    dalek::{
        ristretto::RistrettoPoint,
        scalar::Scalar,
        constants::RISTRETTO_BASEPOINT_COMPRESSED
    },
    mohan_rand,
    hash::hash_to_ristretto
};
use crate::ZeiError;
use serde::{ Serialize, Deserialize };

/// A `EqualityProof` is a proof of the equivalence of the discrete logarithm between two pairs of points.
#[derive(Clone, Debug, Serialize, Deserialize)]
#[allow(non_snake_case)]
pub struct EqualityProof {
    /// `c` is a `Scalar`
    /// \\(c=HASH(A, H, rH)\\)
    pub(crate) c: Scalar,
    /// `z` is a `Scalar`
    /// \\(z = (ac + r) \mod p\\) 
    pub(crate) z: Scalar,
}

impl Default for EqualityProof {
    fn default() -> EqualityProof {
        EqualityProof {
            c: Scalar::zero(),
            z: Scalar::zero()
        }
    }
}

impl EqualityProof {
    
    /// Proove two pederson commitments commit to same value 
    pub fn proove(
        c1: &RistrettoPoint,
        c1_blind: &Scalar, 
        c2: &RistrettoPoint, 
        c2_blind: &Scalar
    ) -> Result<EqualityProof, ZeiError> {

        let mut transcript = Transcript::new(b"zei_equality_proof");

        let base_h = hash_to_ristretto(RISTRETTO_BASEPOINT_COMPRESSED.as_bytes());

        //randomize transcript and commit private key
        let mut rng = transcript
            .build_rng()
            .finalize(&mut mohan_rand());

        let r = Scalar::random(&mut rng);
        // rH
        let rh = &r * &base_h;
        //A = aH
        let big_a = c1 - c2;

        // HASH(A, H, rH)
        let c = {
            //commit Public Point
            transcript.commit_point(b"A", &big_a.compress());
            //commit to our nonce
            transcript.commit_point(b"H", &base_h.compress());
            transcript.commit_point(b"factor", &rh.compress());
            //sample challenge
            transcript.challenge_scalar(b"c")
        };
        
        let a = c1_blind - c2_blind;
        // z = ac + r
        let z = (&a*&c) + r;

        Ok(
            EqualityProof {
                c: c,
                z: z
            }
        )
    }

    /// Verify a Equality Proof of two commitments
    pub fn verify(&self, c1: &RistrettoPoint, c2: &RistrettoPoint) -> Result<(), ZeiError> {
        let mut transcript = Transcript::new(b"zei_equality_proof");

        let base_h = hash_to_ristretto(RISTRETTO_BASEPOINT_COMPRESSED.as_bytes());
        
        //A = aH
        let big_a = c1 - c2;

        //zH - cA
        let factor = (&self.z * base_h) - (self.c * big_a);

        // HASH(A, H, rH)
        let c = {
            //commit Public Point
            transcript.commit_point(b"A", &big_a.compress());
            //commit to our nonce
            transcript.commit_point(b"H", &base_h.compress());
            transcript.commit_point(b"factor", &factor.compress());
            //sample challenge
            transcript.challenge_scalar(b"c")
        };

        if c == self.c {
            Ok(())
        } else {
            Err(ZeiError::VerificationError)
        }
    }
}

impl ser::Writeable for EqualityProof {
	fn write<W: ser::Writer>(&self, writer: &mut W) -> Result<(), ser::Error> {
        self.c.write(writer)?;
        self.z.write(writer)?;
        Ok(())
	}
}

impl ser::Readable for EqualityProof {
	fn read(reader: &mut dyn ser::Reader) -> Result<EqualityProof, ser::Error> {
		Ok(EqualityProof{
            c: Scalar::read(reader)?,
            z: Scalar::read(reader)?
        })
	}
}


#[cfg(test)]
mod test {
    use super::*;
    use crate::PedersenGens;

    #[test]
    fn test_simple() { 
        let mut transcript = Transcript::new(b"zei_equality_proof_test");

        //randomize transcript and commit private key
        let mut rng = transcript
            .build_rng()
            .finalize(&mut mohan_rand());

        let value = Scalar::from(11111u64);

        let input_blind = Scalar::random(&mut rng);
        let output_blind = Scalar::random(&mut rng);

        //setup generators
        let pc_gens = PedersenGens::default();

        let inputs_comm = pc_gens.commit(&value, &input_blind);
        let outputs_comm = pc_gens.commit(&value, &output_blind);

        let proof = EqualityProof::proove(&inputs_comm, &input_blind, &outputs_comm, &output_blind).unwrap();

        assert!(proof.verify(&inputs_comm, &outputs_comm).is_ok());
    }

    #[test]
    fn test_simple_2() { 
        let mut transcript = Transcript::new(b"zei_equality_proof_test");

        //randomize transcript and commit private key
        let mut rng = transcript
            .build_rng()
            .finalize(&mut mohan_rand());

        let input_blind = Scalar::random(&mut rng);
        let output_blind = Scalar::random(&mut rng);
        
        let input_blind2 = Scalar::random(&mut rng);
        let output_blind2 = Scalar::random(&mut rng);

        //setup generators
        let pc_gens = PedersenGens::default();

        let inputs_comm = pc_gens.commit(&Scalar::from(11u64), &input_blind);
        let inputs_comm2 = pc_gens.commit(&Scalar::from(12u64), &input_blind2);
        let outputs_comm = pc_gens.commit(&Scalar::from(11u64), &output_blind);
        let outputs_comm2 = pc_gens.commit(&Scalar::from(1u64), &output_blind2);

        let total_in = inputs_comm + inputs_comm2;
        let total_out = outputs_comm + outputs_comm2;
        let total_in_r = input_blind + input_blind2;
        let total_out_r = output_blind + output_blind2;

        let proof = EqualityProof::proove(&total_in, &total_in_r, &total_out, &total_out_r).unwrap();

        assert!(proof.verify(&total_in, &total_out).is_err());
    }

    #[test]
    fn test_simple_3() { 
        let mut transcript = Transcript::new(b"zei_equality_proof_test");

        //randomize transcript and commit private key
        let mut rng = transcript
            .build_rng()
            .finalize(&mut mohan_rand());

        let input_blind = Scalar::random(&mut rng);
        let output_blind = Scalar::random(&mut rng);
        
        let input_blind2 = Scalar::random(&mut rng);
        let output_blind2 = Scalar::random(&mut rng);

        //setup generators
        let pc_gens = PedersenGens::default();

        let inputs_comm = pc_gens.commit(&Scalar::from(11u64), &input_blind);
        let inputs_comm2 = pc_gens.commit(&Scalar::from(11u64), &input_blind2);
        let outputs_comm = pc_gens.commit(&Scalar::from(11u64), &output_blind);
        let outputs_comm2 = pc_gens.commit(&Scalar::from(11u64), &output_blind2);

        let total_in = inputs_comm + inputs_comm2;
        let total_out = outputs_comm + outputs_comm2;
        let total_in_r = input_blind + input_blind2;
        let total_out_r = output_blind + output_blind2;

        let proof = EqualityProof::proove(&total_in, &total_in_r, &total_out, &total_out_r).unwrap();

        assert!(proof.verify(&total_in, &total_out).is_ok());
    }

    #[test]
    fn test_simple_4() { 
        let mut transcript = Transcript::new(b"zei_equality_proof_test");

        //randomize transcript and commit private key
        let mut rng = transcript
            .build_rng()
            .finalize(&mut mohan_rand());

        let input_blind = Scalar::random(&mut rng);
        let output_blind = Scalar::random(&mut rng);
        
        let input_blind2 = Scalar::random(&mut rng);
        

        //setup generators
        let pc_gens = PedersenGens::default();

        let inputs_comm = pc_gens.commit(&Scalar::from(11u64), &input_blind);
        let inputs_comm2 = pc_gens.commit(&Scalar::from(11u64), &input_blind2);
        let outputs_comm = pc_gens.commit(&Scalar::from(11u64), &output_blind);
      

        let total_in = inputs_comm + inputs_comm2;
        let total_out = outputs_comm;
        let total_in_r = input_blind + input_blind2;
        let total_out_r = output_blind;

        let proof = EqualityProof::proove(&total_in, &total_in_r, &total_out, &total_out_r).unwrap();

        assert!(proof.verify(&total_in, &total_out).is_err());
    }

    #[test]
    fn test_simple_5() { 
        let mut transcript = Transcript::new(b"zei_equality_proof_test");

        //randomize transcript and commit private key
        let mut rng = transcript
            .build_rng()
            .finalize(&mut mohan_rand());

        let input_blind = Scalar::random(&mut rng);
        let output_blind = Scalar::random(&mut rng);
        
        let input_blind2 = Scalar::random(&mut rng);
        

        //setup generators
        let pc_gens = PedersenGens::default();

        let inputs_comm = pc_gens.commit(&Scalar::from(11u64), &input_blind);
        let inputs_comm2 = pc_gens.commit(&Scalar::from(11u64), &input_blind2);
        let outputs_comm = pc_gens.commit(&Scalar::from(1000u64), &output_blind);
      

        let total_in = inputs_comm + inputs_comm2;
        let total_out = outputs_comm;
        let total_in_r = input_blind + input_blind2;
        let total_out_r = output_blind;

        let proof = EqualityProof::proove(&total_in, &total_in_r, &total_out, &total_out_r).unwrap();

        assert!(proof.verify(&total_in, &total_out).is_err());
    }

    #[test]
    fn test_simple_not_equal() { 
        let mut transcript = Transcript::new(b"zei_equality_proof_test");

        //randomize transcript and commit private key
        let mut rng = transcript
            .build_rng()
            .finalize(&mut mohan_rand());

        let value = Scalar::from(11111u64);
        let value2 = Scalar::from(111111u64);

        let input_blind = Scalar::random(&mut rng);
        let output_blind = Scalar::random(&mut rng);

        //setup generators
        let pc_gens = PedersenGens::default();

        let inputs_comm = pc_gens.commit(&value, &input_blind);
        let outputs_comm = pc_gens.commit(&value2, &output_blind);

        let proof = EqualityProof::proove(&inputs_comm, &input_blind, &outputs_comm, &output_blind).unwrap();

        assert!(proof.verify(&inputs_comm, &outputs_comm).is_err());
    }

    


}