feat: proof generation for max and equality proof
This commit is contained in:
parent
601247d958
commit
bc7ac42f2a
|
@ -2,7 +2,7 @@
|
||||||
use {
|
use {
|
||||||
crate::encryption::{
|
crate::encryption::{
|
||||||
elgamal::{ElGamalCiphertext, ElGamalPubkey},
|
elgamal::{ElGamalCiphertext, ElGamalPubkey},
|
||||||
pedersen::{PedersenBase, PedersenOpening},
|
pedersen::{PedersenBase, PedersenCommitment, PedersenOpening},
|
||||||
},
|
},
|
||||||
rand::rngs::OsRng,
|
rand::rngs::OsRng,
|
||||||
};
|
};
|
||||||
|
@ -11,66 +11,175 @@ use {
|
||||||
curve25519_dalek::{
|
curve25519_dalek::{
|
||||||
ristretto::{CompressedRistretto, RistrettoPoint},
|
ristretto::{CompressedRistretto, RistrettoPoint},
|
||||||
scalar::Scalar,
|
scalar::Scalar,
|
||||||
traits::{IsIdentity, VartimeMultiscalarMul},
|
traits::{IsIdentity, MultiscalarMul, VartimeMultiscalarMul},
|
||||||
},
|
},
|
||||||
merlin::Transcript,
|
merlin::Transcript,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[allow(non_snake_case)]
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct FeeProof {
|
pub struct FeeProof {
|
||||||
pub Y_H: CompressedRistretto,
|
pub fee_max_proof: FeeMaxProof,
|
||||||
pub Y_P: CompressedRistretto,
|
pub fee_equality_proof: FeeEqualityProof,
|
||||||
pub z: Scalar,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(non_snake_case, dead_code)]
|
#[allow(non_snake_case, dead_code)]
|
||||||
#[cfg(not(target_arch = "bpf"))]
|
#[cfg(not(target_arch = "bpf"))]
|
||||||
impl FeeProof {
|
impl FeeProof {
|
||||||
pub fn new(
|
pub fn new(
|
||||||
fee_authority_elgamal_pubkey: &ElGamalPubkey,
|
amount_fee: u64,
|
||||||
fee_ciphertext: &ElGamalCiphertext,
|
|
||||||
max_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,
|
transcript: &mut Transcript,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
// extract the relevant scalar and Ristretto points from the input
|
// extract the relevant scalar and Ristretto points from the input
|
||||||
let G = PedersenBase::default().G;
|
let G = PedersenBase::default().G;
|
||||||
let H = PedersenBase::default().H;
|
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 m = Scalar::from(max_fee);
|
||||||
let C = fee_ciphertext.message_comm.get_point() - m * G;
|
|
||||||
let D = fee_ciphertext.decrypt_handle.get_point();
|
let C_max = commitment_fee.get_point();
|
||||||
let r = opening.get_scalar();
|
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
|
// record public values in transcript
|
||||||
//
|
//
|
||||||
// TODO: consider committing to these points outside this method
|
// TODO: consider committing to these points outside this method
|
||||||
transcript.append_point(b"P", &P.compress());
|
transcript.append_point(b"C_max", &C_max.compress());
|
||||||
transcript.append_point(b"C", &C.compress());
|
transcript.append_point(b"C_delta_real", &C_delta_real.compress());
|
||||||
transcript.append_point(b"D", &D.compress());
|
transcript.append_point(b"C_delta_claimed", &C_delta_claimed.compress());
|
||||||
|
|
||||||
// generate a random masking factor that also serve as a nonce
|
// generate z values depending on whether the fee exceeds max fee or not
|
||||||
let y = Scalar::random(&mut OsRng);
|
//
|
||||||
let Y_H = (y * H).compress();
|
// TODO: use constant time conditional
|
||||||
let Y_P = (y * P).compress();
|
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
|
let fee_max_proof = FeeMaxProof {
|
||||||
transcript.append_point(b"Y_H", &Y_H);
|
Y_max, z_max,
|
||||||
transcript.append_point(b"Y_P", &Y_P);
|
};
|
||||||
let c = transcript.challenge_scalar(b"c");
|
|
||||||
transcript.challenge_scalar(b"w");
|
|
||||||
|
|
||||||
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 Y_delta_real =
|
||||||
let z = c * r + y;
|
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(
|
pub fn verify(
|
||||||
self,
|
self,
|
||||||
|
@ -119,6 +228,7 @@ impl FeeProof {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test {
|
mod test {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
Loading…
Reference in New Issue