add decryption functionality to transfer data

This commit is contained in:
Sam Kim 2021-10-27 19:09:26 -04:00 committed by Michael Vines
parent 15aea0fe47
commit 973287ad66
1 changed files with 60 additions and 35 deletions

View File

@ -10,6 +10,7 @@ use {
pedersen::{ pedersen::{
Pedersen, PedersenBase, PedersenCommitment, PedersenDecryptHandle, PedersenOpening, Pedersen, PedersenBase, PedersenCommitment, PedersenDecryptHandle, PedersenOpening,
}, },
discrete_log::*,
}, },
errors::ProofError, errors::ProofError,
instruction::Verifiable, instruction::Verifiable,
@ -140,36 +141,49 @@ impl TransferData {
} }
} }
/// Extracts the lo and hi source ciphertexts associated with a transfer data and returns the /// Extracts the lo ciphertexts associated with a transfer data
/// *combined* ciphertext pub fn ciphertext_lo(&self, role: &TransferRole) -> Result<ElGamalCiphertext, ProofError> {
pub fn source_ciphertext(&self) -> Result<ElGamalCiphertext, ProofError> { let transfer_comm_lo: PedersenCommitment = self.amount_comms.lo.try_into()?;
let transfer_comms_lo: PedersenCommitment = self.amount_comms.lo.try_into()?;
let transfer_comms_hi: PedersenCommitment = self.amount_comms.hi.try_into()?;
let transfer_comm = combine_u32_comms(transfer_comms_lo, transfer_comms_hi);
let decryption_handle_lo: PedersenDecryptHandle = let decryption_handle_lo = match role {
self.decrypt_handles_lo.source.try_into()?; TransferRole::Source => self.decrypt_handles_lo.source,
let decryption_handle_hi: PedersenDecryptHandle = TransferRole::Dest => self.decrypt_handles_lo.dest,
self.decrypt_handles_hi.source.try_into()?; TransferRole::Auditor => self.decrypt_handles_lo.auditor,
let decryption_handle = combine_u32_handles(decryption_handle_lo, decryption_handle_hi); }.try_into()?;
Ok((transfer_comm, decryption_handle).into()) Ok((transfer_comm_lo, decryption_handle_lo).into())
} }
/// Extracts the lo and hi destination ciphertexts associated with a transfer data and returns /// Extracts the lo ciphertexts associated with a transfer data
/// the *combined* ciphertext pub fn ciphertext_hi(&self, role: &TransferRole) -> Result<ElGamalCiphertext, ProofError> {
pub fn dest_ciphertext(&self) -> Result<ElGamalCiphertext, ProofError> { let transfer_comm_hi: PedersenCommitment = self.amount_comms.hi.try_into()?;
let transfer_comms_lo: PedersenCommitment = self.amount_comms.lo.try_into()?;
let transfer_comms_hi: PedersenCommitment = self.amount_comms.hi.try_into()?;
let transfer_comm = combine_u32_comms(transfer_comms_lo, transfer_comms_hi);
let decryption_handle_lo: PedersenDecryptHandle = let decryption_handle_hi = match role {
self.decrypt_handles_lo.dest.try_into()?; TransferRole::Source => self.decrypt_handles_hi.source,
let decryption_handle_hi: PedersenDecryptHandle = TransferRole::Dest => self.decrypt_handles_hi.dest,
self.decrypt_handles_hi.dest.try_into()?; TransferRole::Auditor => self.decrypt_handles_hi.auditor,
let decryption_handle = combine_u32_handles(decryption_handle_lo, decryption_handle_hi); }.try_into()?;
Ok((transfer_comm, decryption_handle).into()) Ok((transfer_comm_hi, decryption_handle_hi).into())
}
/// Decrypts transfer amount from transfer data
///
/// TODO: This function should run in constant time. Use `subtle::Choice` for the if statement
/// and make sure that the function does not terminate prematurely due to errors
pub fn decrypt_amount(&self, role: &TransferRole, sk: &ElGamalSecretKey) -> Result<u64, ProofError> {
let ciphertext_lo = self.ciphertext_lo(role)?;
let ciphertext_hi = self.ciphertext_hi(role)?;
let amount_lo = ciphertext_lo.decrypt_u32_online(sk, &DECODE_U32_PRECOMPUTATION_FOR_G);
let amount_hi = ciphertext_hi.decrypt_u32_online(sk, &DECODE_U32_PRECOMPUTATION_FOR_G);
if amount_lo.is_some() && amount_hi.is_some() {
// Will panic if overflown
Ok((amount_lo.unwrap() as u64) + (TWO_32 * amount_hi.unwrap() as u64))
} else {
Err(ProofError::VerificationError)
}
} }
} }
@ -427,6 +441,13 @@ pub struct TransferDecryptHandles {
pub auditor: pod::PedersenDecryptHandle, // 32 bytes pub auditor: pod::PedersenDecryptHandle, // 32 bytes
} }
#[cfg(not(target_arch = "bpf"))]
pub enum TransferRole {
Source,
Dest,
Auditor,
}
/// Split u64 number into two u32 numbers /// Split u64 number into two u32 numbers
#[cfg(not(target_arch = "bpf"))] #[cfg(not(target_arch = "bpf"))]
pub fn split_u64_into_u32(amt: u64) -> (u32, u32) { pub fn split_u64_into_u32(amt: u64) -> (u32, u32) {
@ -504,11 +525,16 @@ mod test {
public: source_pk, public: source_pk,
secret: source_sk, secret: source_sk,
} = ElGamalKeypair::default(); } = ElGamalKeypair::default();
let ElGamalKeypair { let ElGamalKeypair {
public: dest_pk, public: dest_pk,
secret: dest_sk, secret: dest_sk,
} = ElGamalKeypair::default(); } = ElGamalKeypair::default();
let auditor_pk = ElGamalKeypair::default().public;
let ElGamalKeypair {
public: auditor_pk,
secret: auditor_sk,
} = ElGamalKeypair::default();
// create source account spendable ciphertext // create source account spendable ciphertext
let spendable_balance: u64 = 77; let spendable_balance: u64 = 77;
@ -528,20 +554,19 @@ mod test {
auditor_pk, auditor_pk,
); );
let source_ciphertext = transfer_data.source_ciphertext().unwrap();
assert_eq!( assert_eq!(
source_ciphertext transfer_data.decrypt_amount(&TransferRole::Source, &source_sk).unwrap(),
.decrypt_u32_online(&source_sk, &discrete_log::DECODE_U32_PRECOMPUTATION_FOR_G) 55_u64,
.unwrap(),
55_u32
); );
let dest_ciphertext = transfer_data.dest_ciphertext().unwrap();
assert_eq!( assert_eq!(
dest_ciphertext transfer_data.decrypt_amount(&TransferRole::Dest, &dest_sk).unwrap(),
.decrypt_u32_online(&dest_sk, &discrete_log::DECODE_U32_PRECOMPUTATION_FOR_G) 55_u64,
.unwrap(), );
55_u32
assert_eq!(
transfer_data.decrypt_amount(&TransferRole::Auditor, &auditor_sk).unwrap(),
55_u64,
); );
} }
} }