incorporate validity proof into transfer proof

This commit is contained in:
Sam Kim 2021-12-12 10:23:10 -05:00 committed by Michael Vines
parent c7bf9958e7
commit 30871784e4
5 changed files with 82 additions and 21 deletions

View File

@ -15,6 +15,7 @@ use {
instruction::{Role, Verifiable},
range_proof::RangeProof,
transcript::TranscriptProtocol,
validity_proof::ValidityProof,
},
curve25519_dalek::scalar::Scalar,
merlin::Transcript,
@ -117,8 +118,7 @@ impl TransferData {
&dest_pk,
&auditor_pk,
(amount_lo as u64, amount_hi as u64),
&open_lo,
&open_hi,
(&open_lo, &open_hi),
new_spendable_balance,
&new_spendable_ct,
);
@ -205,6 +205,9 @@ pub struct TransferProof {
/// Associated equality proof
pub equality_proof: pod::EqualityProof,
/// Associated ciphertext validity proof
pub validity_proof: pod::ValidityProof,
// Associated range proof
pub range_proof: pod::RangeProof128,
}
@ -220,11 +223,10 @@ impl TransferProof {
#[allow(clippy::many_single_char_names)]
pub fn new(
source_keypair: &ElGamalKeypair,
_dest_pk: &ElGamalPubkey,
_auditor_pk: &ElGamalPubkey,
dest_pk: &ElGamalPubkey,
auditor_pk: &ElGamalPubkey,
transfer_amt: (u64, u64),
lo_open: &PedersenOpening,
hi_open: &PedersenOpening,
openings: (&PedersenOpening, &PedersenOpening),
source_new_balance: u64,
source_new_balance_ct: &ElGamalCiphertext,
) -> Self {
@ -260,19 +262,27 @@ impl TransferProof {
&mut transcript,
);
// TODO: Add ct validity proof
// generate ciphertext validity proof
let validity_proof = ValidityProof::new(
&dest_pk,
&auditor_pk,
transfer_amt,
openings,
&mut transcript,
);
// generate the range proof
let range_proof = RangeProof::create(
vec![source_new_balance, transfer_amt.0, transfer_amt.1],
vec![64, 32, 32],
vec![&source_open, lo_open, hi_open],
vec![&source_open, openings.0, openings.1],
&mut transcript,
);
Self {
source_commitment: source_commitment.into(),
equality_proof: equality_proof.try_into().expect("equality proof"),
validity_proof: validity_proof.try_into().expect("validity proof"),
range_proof: range_proof.try_into().expect("range proof"),
}
}
@ -280,8 +290,8 @@ impl TransferProof {
pub fn verify(
self,
amount_comms: &TransferCommitments,
_decryption_handles_lo: &TransferDecryptHandles,
_decryption_handles_hi: &TransferDecryptHandles,
decryption_handles_lo: &TransferDecryptHandles,
decryption_handles_hi: &TransferDecryptHandles,
new_spendable_ct: &pod::ElGamalCiphertext,
transfer_public_keys: &TransferPubkeys,
) -> Result<(), ProofError> {
@ -289,6 +299,7 @@ impl TransferProof {
let commitment: PedersenCommitment = self.source_commitment.try_into()?;
let equality_proof: EqualityProof = self.equality_proof.try_into()?;
let validity_proof: ValidityProof = self.validity_proof.try_into()?;
let range_proof: RangeProof = self.range_proof.try_into()?;
// add a domain separator to record the start of the protocol
@ -314,7 +325,28 @@ impl TransferProof {
// TODO: we can also consider verifying equality and range proof in a batch
equality_proof.verify(&source_pk, &new_spendable_ct, &commitment, &mut transcript)?;
// TODO: record destination and auditor public keys to transcript
let dest_elgamal_pubkey: ElGamalPubkey = transfer_public_keys.dest_pk.try_into()?;
let auditor_elgamal_pubkey: ElGamalPubkey = transfer_public_keys.auditor_pk.try_into()?;
let amount_comm_lo: PedersenCommitment = amount_comms.lo.try_into()?;
let amount_comm_hi: PedersenCommitment = amount_comms.hi.try_into()?;
let handle_lo_dest: PedersenDecryptHandle = decryption_handles_lo.dest.try_into()?;
let handle_hi_dest: PedersenDecryptHandle = decryption_handles_hi.dest.try_into()?;
let handle_lo_auditor: PedersenDecryptHandle = decryption_handles_lo.auditor.try_into()?;
let handle_hi_auditor: PedersenDecryptHandle = decryption_handles_hi.auditor.try_into()?;
// TODO: validity proof
validity_proof.verify(
&dest_elgamal_pubkey,
&auditor_elgamal_pubkey,
(&amount_comm_lo, &amount_comm_hi),
(&handle_lo_dest, &handle_hi_dest),
(&handle_lo_auditor, &handle_hi_auditor),
&mut transcript,
)?;
// verify range proof
range_proof.verify(

View File

@ -6,11 +6,11 @@ use {
pub trait TranscriptProtocol {
/// Append a domain separator for an `n`-bit rangeproof for ElGamalKeypair
/// ciphertext using a decryption key // TODO: remove?
/// ciphertext using a decryption key
fn rangeproof_from_key_domain_sep(&mut self, n: u64);
/// Append a domain separator for an `n`-bit rangeproof for ElGamalKeypair
/// ciphertext using an opening // TODO: remove?
/// ciphertext using an opening
fn rangeproof_from_opening_domain_sep(&mut self, n: u64);
/// Append a domain separator for a length-`n` inner product proof.
@ -19,6 +19,9 @@ pub trait TranscriptProtocol {
/// Append a domain separator for close account proof.
fn close_account_proof_domain_sep(&mut self);
/// Append a domain separator for update account public key proof.
fn update_account_public_key_proof_domain_sep(&mut self);
/// Append a domain separator for withdraw proof.
fn withdraw_proof_domain_sep(&mut self);
@ -60,15 +63,19 @@ impl TranscriptProtocol for Transcript {
}
fn close_account_proof_domain_sep(&mut self) {
self.append_message(b"dom_sep", b"CloseAccountProof");
self.append_message(b"dom-sep", b"CloseAccountProof");
}
fn update_account_public_key_proof_domain_sep(&mut self) {
self.append_message(b"dom-sep", b"UpdateAccountPublicKeyProof");
}
fn withdraw_proof_domain_sep(&mut self) {
self.append_message(b"dom_sep", b"WithdrawProof");
self.append_message(b"dom-sep", b"WithdrawProof");
}
fn transfer_proof_domain_sep(&mut self) {
self.append_message(b"dom_sep", b"TransferProof");
self.append_message(b"dom-sep", b"TransferProof");
}
fn append_scalar(&mut self, label: &'static [u8], scalar: &Scalar) {

View File

@ -1,7 +1,7 @@
#[cfg(not(target_arch = "bpf"))]
use {
crate::encryption::{
elgamal::{ElGamalCiphertext, ElGamalKeypair, ElGamalPubkey},
elgamal::{ElGamalKeypair, ElGamalPubkey},
pedersen::{PedersenBase, PedersenCommitment, PedersenDecryptHandle, PedersenOpening},
},
curve25519_dalek::traits::MultiscalarMul,
@ -62,8 +62,6 @@ impl ValidityProof {
let c = transcript.challenge_scalar(b"c");
transcript.challenge_scalar(b"w");
println!("prover: {:?}", t);
// aggregate lo and hi messages and openings
let x = Scalar::from(messages.0) + t * Scalar::from(messages.1);
let r = openings.0.get_scalar() + t * openings.1.get_scalar();
@ -104,8 +102,6 @@ impl ValidityProof {
let w = transcript.challenge_scalar(b"w");
let ww = w * w;
println!("verifier: {:?}", t);
// check the required algebraic conditions
let Y_0 = self.Y_0.decompress().ok_or(ProofError::VerificationError)?;
let Y_1 = self.Y_1.decompress().ok_or(ProofError::VerificationError)?;

View File

@ -23,6 +23,7 @@ mod target_arch {
equality_proof::EqualityProof,
errors::ProofError,
range_proof::RangeProof,
validity_proof::ValidityProof,
},
curve25519_dalek::{ristretto::CompressedRistretto, scalar::Scalar},
std::convert::TryFrom,
@ -155,6 +156,20 @@ mod target_arch {
}
}
impl From<ValidityProof> for pod::ValidityProof {
fn from(proof: ValidityProof) -> Self {
Self(proof.to_bytes())
}
}
impl TryFrom<pod::ValidityProof> for ValidityProof {
type Error = ProofError;
fn try_from(pod: pod::ValidityProof) -> Result<Self, Self::Error> {
Self::from_bytes(&pod.0)
}
}
impl TryFrom<RangeProof> for pod::RangeProof64 {
type Error = ProofError;

View File

@ -54,11 +54,22 @@ impl fmt::Debug for PedersenDecryptHandle {
#[repr(transparent)]
pub struct EqualityProof(pub [u8; 192]);
// `PodRangeProof64` is a Pod and Zeroable.
// `EqualityProof` is a Pod and Zeroable.
// Add the marker traits manually because `bytemuck` only adds them for some `u8` arrays
unsafe impl Zeroable for EqualityProof {}
unsafe impl Pod for EqualityProof {}
/// Serialization of validity proofs
#[derive(Clone, Copy)]
#[repr(transparent)]
pub struct ValidityProof(pub [u8; 160]);
// `ValidityProof` is a Pod and Zeroable.
// Add the marker traits manually because `bytemuck` only adds them for some `u8` arrays
unsafe impl Zeroable for ValidityProof {}
unsafe impl Pod for ValidityProof {}
/// Serialization of range proofs for 64-bit numbers (for `Withdraw` instruction)
#[derive(Clone, Copy)]
#[repr(transparent)]