cl: simple_transfer integration test
This commit is contained in:
parent
6a45163014
commit
6b1d0c4172
|
@ -17,6 +17,15 @@ pub struct Balance(pub RistrettoPoint);
|
|||
pub struct BalanceWitness(pub Scalar);
|
||||
|
||||
impl Balance {
|
||||
/// A commitment to zero, blinded by the provided balance witness
|
||||
pub fn zero(blinding: BalanceWitness) -> Self {
|
||||
Self(balance(
|
||||
0,
|
||||
curve25519_dalek::constants::RISTRETTO_BASEPOINT_POINT,
|
||||
blinding.0,
|
||||
))
|
||||
}
|
||||
|
||||
pub fn to_bytes(&self) -> [u8; 32] {
|
||||
self.0.compress().to_bytes()
|
||||
}
|
||||
|
|
|
@ -1,8 +1,6 @@
|
|||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use curve25519_dalek::{constants::RISTRETTO_BASEPOINT_POINT, ristretto::RistrettoPoint};
|
||||
|
||||
use crate::{partial_tx::PartialTx, BalanceWitness};
|
||||
use crate::{partial_tx::PartialTx, Balance, BalanceWitness};
|
||||
|
||||
/// The transaction bundle is a collection of partial transactions.
|
||||
/// The goal in bundling transactions is to produce a set of partial transactions
|
||||
|
@ -19,20 +17,20 @@ pub struct BundleWitness {
|
|||
}
|
||||
|
||||
impl Bundle {
|
||||
pub fn balance(&self) -> RistrettoPoint {
|
||||
self.partials.iter().map(|ptx| ptx.balance()).sum()
|
||||
pub fn balance(&self) -> Balance {
|
||||
Balance(self.partials.iter().map(|ptx| ptx.balance().0).sum())
|
||||
}
|
||||
|
||||
pub fn is_balanced(&self, witness: BalanceWitness) -> bool {
|
||||
self.balance() == crate::balance::balance(0, RISTRETTO_BASEPOINT_POINT, witness.0)
|
||||
self.balance() == Balance::zero(witness)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use crate::{
|
||||
crypto::hash_to_curve, input::InputWitness, note::NoteWitness, nullifier::NullifierSecret,
|
||||
output::OutputWitness, partial_tx::PartialTxWitness,
|
||||
input::InputWitness, note::NoteWitness, nullifier::NullifierSecret, output::OutputWitness,
|
||||
partial_tx::PartialTxWitness,
|
||||
};
|
||||
|
||||
use super::*;
|
||||
|
@ -57,8 +55,8 @@ mod test {
|
|||
OutputWitness::random(NoteWitness::basic(4840, "CRV"), nf_c.commit(), &mut rng);
|
||||
|
||||
let ptx_unbalanced = PartialTxWitness {
|
||||
inputs: vec![nmo_10_in.clone(), eth_23_in.clone()],
|
||||
outputs: vec![crv_4840_out.clone()],
|
||||
inputs: vec![nmo_10_in, eth_23_in],
|
||||
outputs: vec![crv_4840_out],
|
||||
};
|
||||
|
||||
let bundle_witness = BundleWitness {
|
||||
|
@ -70,22 +68,14 @@ mod test {
|
|||
};
|
||||
|
||||
let mut bundle = Bundle {
|
||||
partials: vec![PartialTx::from_witness(ptx_unbalanced)],
|
||||
partials: vec![ptx_unbalanced.commit()],
|
||||
};
|
||||
|
||||
assert!(!bundle.is_balanced(bundle_witness.balance_blinding));
|
||||
assert_eq!(
|
||||
bundle.balance(),
|
||||
crate::balance::balance(4840, hash_to_curve(b"CRV"), crv_4840_out.balance_blinding.0)
|
||||
- (crate::balance::balance(
|
||||
10,
|
||||
hash_to_curve(b"NMO"),
|
||||
nmo_10_in.balance_blinding.0
|
||||
) + crate::balance::balance(
|
||||
23,
|
||||
hash_to_curve(b"ETH"),
|
||||
eth_23_in.balance_blinding.0
|
||||
))
|
||||
bundle.balance().0,
|
||||
crv_4840_out.commit().balance.0
|
||||
- (nmo_10_in.commit().balance.0 + eth_23_in.commit().balance.0)
|
||||
);
|
||||
|
||||
let crv_4840_in = InputWitness::random(crv_4840_out, nf_c, &mut rng);
|
||||
|
@ -100,12 +90,13 @@ mod test {
|
|||
&mut rng,
|
||||
);
|
||||
|
||||
bundle
|
||||
.partials
|
||||
.push(PartialTx::from_witness(PartialTxWitness {
|
||||
inputs: vec![crv_4840_in.clone()],
|
||||
outputs: vec![nmo_10_out.clone(), eth_23_out.clone()],
|
||||
}));
|
||||
bundle.partials.push(
|
||||
PartialTxWitness {
|
||||
inputs: vec![crv_4840_in],
|
||||
outputs: vec![nmo_10_out, eth_23_out],
|
||||
}
|
||||
.commit(),
|
||||
);
|
||||
|
||||
let witness = BundleWitness {
|
||||
balance_blinding: BalanceWitness::new(
|
||||
|
@ -117,15 +108,6 @@ mod test {
|
|||
),
|
||||
};
|
||||
|
||||
assert_eq!(
|
||||
bundle.balance(),
|
||||
crate::balance::balance(
|
||||
0,
|
||||
curve25519_dalek::constants::RISTRETTO_BASEPOINT_POINT,
|
||||
witness.balance_blinding.0
|
||||
)
|
||||
);
|
||||
|
||||
assert!(bundle.is_balanced(witness.balance_blinding));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -107,23 +107,23 @@ mod test {
|
|||
let wrong_witnesses = [
|
||||
OutputWitness {
|
||||
note: NoteWitness::basic(11, "NMO"),
|
||||
..witness.clone()
|
||||
..witness
|
||||
},
|
||||
OutputWitness {
|
||||
note: NoteWitness::basic(10, "ETH"),
|
||||
..witness.clone()
|
||||
..witness
|
||||
},
|
||||
OutputWitness {
|
||||
balance_blinding: BalanceWitness::random(&mut rng),
|
||||
..witness.clone()
|
||||
..witness
|
||||
},
|
||||
OutputWitness {
|
||||
nf_pk: NullifierSecret::random(&mut rng).commit(),
|
||||
..witness.clone()
|
||||
..witness
|
||||
},
|
||||
OutputWitness {
|
||||
nonce: NullifierNonce::random(&mut rng),
|
||||
..witness.clone()
|
||||
..witness
|
||||
},
|
||||
];
|
||||
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
use curve25519_dalek::ristretto::RistrettoPoint;
|
||||
use curve25519_dalek::Scalar;
|
||||
use rand_core::RngCore;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::balance::{Balance, BalanceWitness};
|
||||
use crate::input::{Input, InputWitness};
|
||||
use crate::merkle;
|
||||
use crate::output::{Output, OutputWitness};
|
||||
|
@ -44,14 +46,30 @@ pub struct PartialTxWitness {
|
|||
pub outputs: Vec<OutputWitness>,
|
||||
}
|
||||
|
||||
impl PartialTx {
|
||||
pub fn from_witness(w: PartialTxWitness) -> Self {
|
||||
Self {
|
||||
inputs: Vec::from_iter(w.inputs.iter().map(InputWitness::commit)),
|
||||
outputs: Vec::from_iter(w.outputs.iter().map(OutputWitness::commit)),
|
||||
impl PartialTxWitness {
|
||||
pub fn commit(&self) -> PartialTx {
|
||||
PartialTx {
|
||||
inputs: Vec::from_iter(self.inputs.iter().map(InputWitness::commit)),
|
||||
outputs: Vec::from_iter(self.outputs.iter().map(OutputWitness::commit)),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn balance_delta(&self) -> i128 {
|
||||
let in_sum: i128 = self.inputs.iter().map(|i| i.note.value as i128).sum();
|
||||
let out_sum: i128 = self.outputs.iter().map(|o| o.note.value as i128).sum();
|
||||
|
||||
out_sum - in_sum
|
||||
}
|
||||
|
||||
pub fn balance_blinding(&self) -> BalanceWitness {
|
||||
let in_sum: Scalar = self.inputs.iter().map(|i| i.balance_blinding.0).sum();
|
||||
let out_sum: Scalar = self.outputs.iter().map(|o| o.balance_blinding.0).sum();
|
||||
|
||||
BalanceWitness(out_sum - in_sum)
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialTx {
|
||||
pub fn input_root(&self) -> [u8; 32] {
|
||||
let input_bytes =
|
||||
Vec::from_iter(self.inputs.iter().map(Input::to_bytes).map(Vec::from_iter));
|
||||
|
@ -95,18 +113,18 @@ impl PartialTx {
|
|||
PtxRoot(root)
|
||||
}
|
||||
|
||||
pub fn balance(&self) -> RistrettoPoint {
|
||||
pub fn balance(&self) -> Balance {
|
||||
let in_sum: RistrettoPoint = self.inputs.iter().map(|i| i.balance.0).sum();
|
||||
let out_sum: RistrettoPoint = self.outputs.iter().map(|o| o.balance.0).sum();
|
||||
|
||||
out_sum - in_sum
|
||||
Balance(out_sum - in_sum)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
|
||||
use crate::{crypto::hash_to_curve, note::NoteWitness, nullifier::NullifierSecret};
|
||||
use crate::{note::NoteWitness, nullifier::NullifierSecret};
|
||||
|
||||
use super::*;
|
||||
|
||||
|
@ -130,21 +148,15 @@ mod test {
|
|||
OutputWitness::random(NoteWitness::basic(4840, "CRV"), nf_c.commit(), &mut rng);
|
||||
|
||||
let ptx_witness = PartialTxWitness {
|
||||
inputs: vec![nmo_10.clone(), eth_23.clone()],
|
||||
outputs: vec![crv_4840.clone()],
|
||||
inputs: vec![nmo_10, eth_23],
|
||||
outputs: vec![crv_4840],
|
||||
};
|
||||
|
||||
let ptx = PartialTx::from_witness(ptx_witness.clone());
|
||||
let ptx = ptx_witness.commit();
|
||||
|
||||
assert_eq!(
|
||||
ptx.balance(),
|
||||
crate::balance::balance(4840, hash_to_curve(b"CRV"), crv_4840.balance_blinding.0)
|
||||
- (crate::balance::balance(10, hash_to_curve(b"NMO"), nmo_10.balance_blinding.0)
|
||||
+ crate::balance::balance(
|
||||
23,
|
||||
hash_to_curve(b"ETH"),
|
||||
eth_23.balance_blinding.0
|
||||
))
|
||||
ptx.balance().0,
|
||||
crv_4840.commit().balance.0 - (nmo_10.commit().balance.0 + eth_23.commit().balance.0)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,41 @@
|
|||
use rand_core::CryptoRngCore;
|
||||
|
||||
fn receive_utxo(
|
||||
note: cl::NoteWitness,
|
||||
nf_pk: cl::NullifierCommitment,
|
||||
rng: impl CryptoRngCore,
|
||||
) -> cl::OutputWitness {
|
||||
cl::OutputWitness::random(note, nf_pk, rng)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_simple_transfer() {
|
||||
let mut rng = rand::thread_rng();
|
||||
|
||||
let sender_nf_sk = cl::NullifierSecret::random(&mut rng);
|
||||
let sender_nf_pk = sender_nf_sk.commit();
|
||||
|
||||
let recipient_nf_pk = cl::NullifierSecret::random(&mut rng).commit();
|
||||
|
||||
// Assume the sender has received an unspent output from somewhere
|
||||
let utxo = receive_utxo(cl::NoteWitness::basic(10, "NMO"), sender_nf_pk, &mut rng);
|
||||
|
||||
// and wants to send 8 NMO to some recipient and return 2 NMO to itself.
|
||||
let recipient_output =
|
||||
cl::OutputWitness::random(cl::NoteWitness::basic(8, "NMO"), recipient_nf_pk, &mut rng);
|
||||
let change_output =
|
||||
cl::OutputWitness::random(cl::NoteWitness::basic(2, "NMO"), sender_nf_pk, &mut rng);
|
||||
|
||||
let ptx_witness = cl::PartialTxWitness {
|
||||
inputs: vec![cl::InputWitness::random(utxo, sender_nf_sk, &mut rng)],
|
||||
outputs: vec![recipient_output, change_output],
|
||||
};
|
||||
|
||||
let ptx = ptx_witness.commit();
|
||||
|
||||
let bundle = cl::Bundle {
|
||||
partials: vec![ptx],
|
||||
};
|
||||
|
||||
assert!(bundle.is_balanced(ptx_witness.balance_blinding()))
|
||||
}
|
Loading…
Reference in New Issue