-
Notifications
You must be signed in to change notification settings - Fork 18
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* Add PoL crate * promote cl crate to nomos-node repo * add github action for risc0 proof * fix actions scrupt * add metal feature * fix risc0 install * remove check test
- Loading branch information
Showing
25 changed files
with
1,592 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
[package] | ||
name = "cl" | ||
version = "0.1.0" | ||
edition = "2021" | ||
|
||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html | ||
|
||
[dependencies] | ||
serde = {version="1.0", features = ["derive"]} | ||
rand = "0.8.5" | ||
rand_core = "0.6.0" | ||
hex = "0.4.3" | ||
sha2 = "0.10" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,149 @@ | ||
use rand_core::CryptoRngCore; | ||
use serde::{Deserialize, Serialize}; | ||
use sha2::{Digest, Sha256}; | ||
|
||
use crate::PartialTxWitness; | ||
|
||
pub type Value = u64; | ||
pub type Unit = [u8; 32]; | ||
|
||
#[derive(Debug, PartialEq, Eq, Clone, Copy, Serialize, Deserialize)] | ||
pub struct Balance([u8; 32]); | ||
|
||
impl Balance { | ||
pub fn to_bytes(&self) -> [u8; 32] { | ||
self.0 | ||
} | ||
} | ||
|
||
#[derive(Debug, PartialEq, Eq, Clone, Serialize, Deserialize)] | ||
pub struct UnitBalance { | ||
pub unit: Unit, | ||
pub pos: u64, | ||
pub neg: u64, | ||
} | ||
|
||
impl UnitBalance { | ||
pub fn is_zero(&self) -> bool { | ||
self.pos == self.neg | ||
} | ||
} | ||
|
||
#[derive(Debug, PartialEq, Eq, Clone, Serialize, Deserialize)] | ||
pub struct BalanceWitness { | ||
pub balances: Vec<UnitBalance>, | ||
pub blinding: [u8; 16], | ||
} | ||
|
||
impl BalanceWitness { | ||
pub fn random_blinding(mut rng: impl CryptoRngCore) -> [u8; 16] { | ||
let mut blinding = [0u8; 16]; | ||
rng.fill_bytes(&mut blinding); | ||
|
||
blinding | ||
} | ||
|
||
pub fn zero(blinding: [u8; 16]) -> Self { | ||
Self { | ||
balances: Default::default(), | ||
blinding, | ||
} | ||
} | ||
|
||
pub fn from_ptx(ptx: &PartialTxWitness, blinding: [u8; 16]) -> Self { | ||
let mut balance = Self::zero(blinding); | ||
|
||
for input in ptx.inputs.iter() { | ||
balance.insert_negative(input.note.unit, input.note.value); | ||
} | ||
|
||
for output in ptx.outputs.iter() { | ||
balance.insert_positive(output.note.unit, output.note.value); | ||
} | ||
|
||
balance.clear_zeros(); | ||
|
||
balance | ||
} | ||
|
||
pub fn insert_positive(&mut self, unit: Unit, value: Value) { | ||
for unit_bal in self.balances.iter_mut() { | ||
if unit_bal.unit == unit { | ||
unit_bal.pos += value; | ||
return; | ||
} | ||
} | ||
|
||
// Unit was not found, so we must create one. | ||
self.balances.push(UnitBalance { | ||
unit, | ||
pos: value, | ||
neg: 0, | ||
}); | ||
} | ||
|
||
pub fn insert_negative(&mut self, unit: Unit, value: Value) { | ||
for unit_bal in self.balances.iter_mut() { | ||
if unit_bal.unit == unit { | ||
unit_bal.neg += value; | ||
return; | ||
} | ||
} | ||
|
||
self.balances.push(UnitBalance { | ||
unit, | ||
pos: 0, | ||
neg: value, | ||
}); | ||
} | ||
|
||
pub fn clear_zeros(&mut self) { | ||
let mut i = 0usize; | ||
while i < self.balances.len() { | ||
if self.balances[i].is_zero() { | ||
self.balances.swap_remove(i); | ||
// don't increment `i` since the last element has been swapped into the | ||
// `i`'th place | ||
} else { | ||
i += 1; | ||
} | ||
} | ||
} | ||
|
||
pub fn combine(balances: impl IntoIterator<Item = Self>, blinding: [u8; 16]) -> Self { | ||
let mut combined = BalanceWitness::zero(blinding); | ||
|
||
for balance in balances { | ||
for unit_bal in balance.balances.iter() { | ||
if unit_bal.pos > unit_bal.neg { | ||
combined.insert_positive(unit_bal.unit, unit_bal.pos - unit_bal.neg); | ||
} else { | ||
combined.insert_negative(unit_bal.unit, unit_bal.neg - unit_bal.pos); | ||
} | ||
} | ||
} | ||
|
||
combined.clear_zeros(); | ||
|
||
combined | ||
} | ||
|
||
pub fn is_zero(&self) -> bool { | ||
self.balances.is_empty() | ||
} | ||
|
||
pub fn commit(&self) -> Balance { | ||
let mut hasher = Sha256::new(); | ||
hasher.update(b"NOMOS_CL_BAL_COMMIT"); | ||
|
||
for unit_balance in self.balances.iter() { | ||
hasher.update(unit_balance.unit); | ||
hasher.update(unit_balance.pos.to_le_bytes()); | ||
hasher.update(unit_balance.neg.to_le_bytes()); | ||
} | ||
hasher.update(self.blinding); | ||
|
||
let commit_bytes: [u8; 32] = hasher.finalize().into(); | ||
Balance(commit_bytes) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,117 @@ | ||
use serde::{Deserialize, Serialize}; | ||
|
||
use crate::{partial_tx::PartialTx, BalanceWitness, PartialTxWitness}; | ||
|
||
/// The transaction bundle is a collection of partial transactions. | ||
/// The goal in bundling transactions is to produce a set of partial transactions | ||
/// that balance each other. | ||
|
||
#[derive(Debug, Clone, Serialize, Deserialize)] | ||
pub struct Bundle { | ||
pub partials: Vec<PartialTx>, | ||
} | ||
|
||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] | ||
pub struct BundleWitness { | ||
pub partials: Vec<PartialTxWitness>, | ||
} | ||
|
||
impl BundleWitness { | ||
pub fn balance(&self) -> BalanceWitness { | ||
BalanceWitness::combine(self.partials.iter().map(|ptx| ptx.balance()), [0u8; 16]) | ||
} | ||
|
||
pub fn commit(&self) -> Bundle { | ||
Bundle { | ||
partials: Vec::from_iter(self.partials.iter().map(|ptx| ptx.commit())), | ||
} | ||
} | ||
} | ||
|
||
#[cfg(test)] | ||
mod test { | ||
use crate::{ | ||
balance::UnitBalance, | ||
input::InputWitness, | ||
note::{derive_unit, NoteWitness}, | ||
nullifier::NullifierSecret, | ||
output::OutputWitness, | ||
partial_tx::PartialTxWitness, | ||
}; | ||
|
||
use super::*; | ||
|
||
#[test] | ||
fn test_bundle_balance() { | ||
let mut rng = rand::thread_rng(); | ||
let (nmo, eth, crv) = (derive_unit("NMO"), derive_unit("ETH"), derive_unit("CRV")); | ||
|
||
let nf_a = NullifierSecret::random(&mut rng); | ||
let nf_b = NullifierSecret::random(&mut rng); | ||
let nf_c = NullifierSecret::random(&mut rng); | ||
|
||
let nmo_10_utxo = OutputWitness::new(NoteWitness::basic(10, nmo, &mut rng), nf_a.commit()); | ||
let nmo_10_in = InputWitness::from_output(nmo_10_utxo, nf_a); | ||
|
||
let eth_23_utxo = OutputWitness::new(NoteWitness::basic(23, eth, &mut rng), nf_b.commit()); | ||
let eth_23_in = InputWitness::from_output(eth_23_utxo, nf_b); | ||
|
||
let crv_4840_out = | ||
OutputWitness::new(NoteWitness::basic(4840, crv, &mut rng), nf_c.commit()); | ||
|
||
let ptx_unbalanced = PartialTxWitness { | ||
inputs: vec![nmo_10_in, eth_23_in], | ||
outputs: vec![crv_4840_out], | ||
balance_blinding: BalanceWitness::random_blinding(&mut rng), | ||
}; | ||
|
||
let bundle_witness = BundleWitness { | ||
partials: vec![ptx_unbalanced.clone()], | ||
}; | ||
|
||
assert!(!bundle_witness.balance().is_zero()); | ||
assert_eq!( | ||
bundle_witness.balance().balances, | ||
vec![ | ||
UnitBalance { | ||
unit: nmo, | ||
pos: 0, | ||
neg: 10 | ||
}, | ||
UnitBalance { | ||
unit: eth, | ||
pos: 0, | ||
neg: 23 | ||
}, | ||
UnitBalance { | ||
unit: crv, | ||
pos: 4840, | ||
neg: 0 | ||
}, | ||
] | ||
); | ||
|
||
let crv_4840_in = InputWitness::from_output(crv_4840_out, nf_c); | ||
let nmo_10_out = OutputWitness::new( | ||
NoteWitness::basic(10, nmo, &mut rng), | ||
NullifierSecret::random(&mut rng).commit(), // transferring to a random owner | ||
); | ||
let eth_23_out = OutputWitness::new( | ||
NoteWitness::basic(23, eth, &mut rng), | ||
NullifierSecret::random(&mut rng).commit(), // transferring to a random owner | ||
); | ||
|
||
let ptx_solved = PartialTxWitness { | ||
inputs: vec![crv_4840_in], | ||
outputs: vec![nmo_10_out, eth_23_out], | ||
balance_blinding: BalanceWitness::random_blinding(&mut rng), | ||
}; | ||
|
||
let witness = BundleWitness { | ||
partials: vec![ptx_unbalanced, ptx_solved], | ||
}; | ||
|
||
assert!(witness.balance().is_zero()); | ||
assert_eq!(witness.balance().balances, vec![]); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
#[derive(Debug)] | ||
pub enum Error { | ||
ProofFailed, | ||
} |
Oops, something went wrong.