feat: proof generation for max and equality proof

This commit is contained in:
Sam Kim 2021-12-23 09:41:57 -05:00 committed by Michael Vines
parent 601247d958
commit bc7ac42f2a
1 changed files with 140 additions and 30 deletions

View File

@ -2,7 +2,7 @@
use {
crate::encryption::{
elgamal::{ElGamalCiphertext, ElGamalPubkey},
pedersen::{PedersenBase, PedersenOpening},
pedersen::{PedersenBase, PedersenCommitment, PedersenOpening},
},
rand::rngs::OsRng,
};
@ -11,66 +11,175 @@ use {
curve25519_dalek::{
ristretto::{CompressedRistretto, RistrettoPoint},
scalar::Scalar,
traits::{IsIdentity, VartimeMultiscalarMul},
traits::{IsIdentity, MultiscalarMul, VartimeMultiscalarMul},
},
merlin::Transcript,
};
#[allow(non_snake_case)]
#[derive(Clone)]
pub struct FeeProof {
pub Y_H: CompressedRistretto,
pub Y_P: CompressedRistretto,
pub z: Scalar,
pub fee_max_proof: FeeMaxProof,
pub fee_equality_proof: FeeEqualityProof,
}
#[allow(non_snake_case, dead_code)]
#[cfg(not(target_arch = "bpf"))]
impl FeeProof {
pub fn new(
fee_authority_elgamal_pubkey: &ElGamalPubkey,
fee_ciphertext: &ElGamalCiphertext,
amount_fee: u64,
max_fee: u64,
opening: &PedersenOpening,
commitment_fee: PedersenCommitment,
opening_fee: PedersenOpening,
commitment_delta_real: PedersenCommitment,
opening_delta_real: PedersenOpening,
commitment_delta_claimed: PedersenCommitment,
opening_delta_claimed: PedersenOpening,
transcript: &mut Transcript,
) -> Self {
// extract the relevant scalar and Ristretto points from the input
let G = PedersenBase::default().G;
let H = PedersenBase::default().H;
let P = fee_authority_elgamal_pubkey.get_point();
let x = Scalar::from(amount_fee);
let m = Scalar::from(max_fee);
let C = fee_ciphertext.message_comm.get_point() - m * G;
let D = fee_ciphertext.decrypt_handle.get_point();
let r = opening.get_scalar();
let C_max = commitment_fee.get_point();
let r_max = opening_fee.get_scalar();
let C_delta_real = commitment_fee.get_point();
let r_delta_real = opening_fee.get_scalar();
let C_delta_claimed = commitment_fee.get_point();
let r_delta_claimed = opening_fee.get_scalar();
// record public values in transcript
//
// TODO: consider committing to these points outside this method
transcript.append_point(b"P", &P.compress());
transcript.append_point(b"C", &C.compress());
transcript.append_point(b"D", &D.compress());
transcript.append_point(b"C_max", &C_max.compress());
transcript.append_point(b"C_delta_real", &C_delta_real.compress());
transcript.append_point(b"C_delta_claimed", &C_delta_claimed.compress());
// generate a random masking factor that also serve as a nonce
let y = Scalar::random(&mut OsRng);
let Y_H = (y * H).compress();
let Y_P = (y * P).compress();
// generate z values depending on whether the fee exceeds max fee or not
//
// TODO: use constant time conditional
if amount_fee < max_fee {
// simulate max proof
let z_max = Scalar::random(&mut OsRng);
let c_max = Scalar::random(&mut OsRng);
let Y_max =
RistrettoPoint::multiscalar_mul(vec![z_max, c_max, c_max * x], vec![H, C_max, G])
.compress();
// record Y values in transcript and receive a challenge scalar
transcript.append_point(b"Y_H", &Y_H);
transcript.append_point(b"Y_P", &Y_P);
let c = transcript.challenge_scalar(b"c");
transcript.challenge_scalar(b"w");
let fee_max_proof = FeeMaxProof {
Y_max, z_max,
};
println!("prover c: {:?}", c);
// generate equality proof
let y_x = Scalar::random(&mut OsRng);
let y_delta_real = Scalar::random(&mut OsRng);
let y_delta_claimed = Scalar::random(&mut OsRng);
// compute the masked encryption randomness
let z = c * r + y;
let Y_delta_real =
RistrettoPoint::multiscalar_mul(vec![y_x, y_delta_real], vec![G, H]).compress();
let Y_delta_claimed =
RistrettoPoint::multiscalar_mul(vec![y_x, y_delta_claimed], vec![G, H]).compress();
// TODO: actual fee calculation
transcript.append_point(b"Y_max", &Y_max);
transcript.append_point(b"Y_delta_real", &Y_delta_real);
transcript.append_point(b"Y_delta_claimed", &Y_delta_claimed);
Self { Y_H, Y_P, z }
let c = transcript.challenge_scalar(b"c");
let c_equality = c - c_max;
let z_x = c_equality * x + y_x;
let z_delta_real = c_equality * x + y_delta_real;
let z_delta_claimed = c_equality * x + y_delta_claimed;
let fee_equality_proof = FeeEqualityProof {
Y_delta_real,
Y_delta_claimed,
z_x,
z_delta_real,
z_delta_claimed,
};
Self {
fee_max_proof,
fee_equality_proof,
}
} else {
// simulate equality proof
let z_x = Scalar::random(&mut OsRng);
let z_delta_real = Scalar::random(&mut OsRng);
let z_delta_claimed = Scalar::random(&mut OsRng);
let c_equality = Scalar::random(&mut OsRng);
let Y_delta_real = RistrettoPoint::multiscalar_mul(
vec![z_x, z_delta_real, -c_equality],
vec![G, H, C_delta_real],
)
.compress();
let Y_delta_claimed = RistrettoPoint::multiscalar_mul(
vec![z_x, z_delta_claimed, -c_equality],
vec![G, H, C_delta_claimed],
)
.compress();
let fee_equality_proof = FeeEqualityProof {
Y_delta_real,
Y_delta_claimed,
z_x,
z_delta_real,
z_delta_claimed,
};
// generate max proof
let y_max = Scalar::random(&mut OsRng);
let Y_max = (y_max * H).compress();
transcript.append_point(b"Y_max", &Y_max);
transcript.append_point(b"Y_delta_real", &Y_delta_real);
transcript.append_point(b"Y_delta_claimed", &Y_delta_claimed);
let c = transcript.challenge_scalar(b"c");
let c_max = c - c_equality;
let z_max = c_max * r_max + y_max;
let fee_max_proof = FeeMaxProof {
Y_max, z_max,
};
Self {
fee_max_proof,
fee_equality_proof,
}
}
}
}
#[allow(non_snake_case)]
#[derive(Clone)]
pub struct FeeMaxProof {
pub Y_max: CompressedRistretto,
pub z_max: Scalar,
}
#[allow(non_snake_case)]
#[derive(Clone)]
pub struct FeeEqualityProof {
pub Y_delta_real: CompressedRistretto,
pub Y_delta_claimed: CompressedRistretto,
pub z_x: Scalar,
pub z_delta_real: Scalar,
pub z_delta_claimed: Scalar,
}
#[allow(non_snake_case, dead_code)]
#[cfg(not(target_arch = "bpf"))]
impl FeeProof {
pub fn verify(
self,
@ -119,6 +228,7 @@ impl FeeProof {
}
}
#[cfg(test)]
mod test {
use super::*;