Skip to content

Commit 6a2afa7

Browse files
author
SyntheticBird45
committed
Add common ammounts commitment lookup table
1 parent 978d72b commit 6a2afa7

File tree

6 files changed

+265
-19
lines changed

6 files changed

+265
-19
lines changed

constants/Cargo.toml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,11 @@ default = []
1313
block = []
1414
build = []
1515
rpc = []
16+
crypto = []
1617

1718
[dependencies]
1819

1920
[dev-dependencies]
2021

2122
[lints]
22-
workspace = true
23+
workspace = true

constants/src/crypto.rs

Lines changed: 184 additions & 0 deletions
Large diffs are not rendered by default.

constants/src/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,5 +8,7 @@ mod macros;
88
pub mod block;
99
#[cfg(feature = "build")]
1010
pub mod build;
11+
#[cfg(feature = "crypto")]
12+
pub mod crypto;
1113
#[cfg(feature = "rpc")]
1214
pub mod rpc;

storage/blockchain/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ redb-memory = ["cuprate-database/redb-memory"]
1818
service = ["dep:thread_local", "dep:rayon", "cuprate-helper/thread"]
1919

2020
[dependencies]
21+
cuprate-constants = { path = "../../constants", features = ["crypto"]}
2122
cuprate-database = { path = "../database" }
2223
cuprate-database-service = { path = "../service" }
2324
cuprate-helper = { path = "../../helper", features = ["fs", "map"] }
@@ -37,7 +38,6 @@ thread_local = { workspace = true, optional = true }
3738
rayon = { workspace = true, optional = true }
3839

3940
[dev-dependencies]
40-
cuprate-constants = { path = "../../constants" }
4141
cuprate-helper = { path = "../../helper", features = ["thread", "cast"] }
4242
cuprate-test-utils = { path = "../../test-utils" }
4343

storage/blockchain/src/ops/output.rs

Lines changed: 29 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,12 @@
11
//! Output functions.
22
33
//---------------------------------------------------------------------------------------------------- Import
4-
use curve25519_dalek::{constants::ED25519_BASEPOINT_POINT, edwards::CompressedEdwardsY, Scalar};
4+
use curve25519_dalek::{
5+
constants::ED25519_BASEPOINT_POINT, edwards::CompressedEdwardsY, EdwardsPoint, Scalar,
6+
};
57
use monero_serai::{generators::H, transaction::Timelock};
68

9+
use cuprate_constants::crypto::ZERO_COMMITMENT_LOOKUP_TABLE as ZC_LT;
710
use cuprate_database::{
811
RuntimeError, {DatabaseRo, DatabaseRw},
912
};
@@ -155,9 +158,31 @@ pub fn output_to_output_on_chain(
155158
amount: Amount,
156159
table_tx_unlock_time: &impl DatabaseRo<TxUnlockTime>,
157160
) -> Result<OutputOnChain, RuntimeError> {
158-
// FIXME: implement lookup table for common values:
159-
// <https://github.com/monero-project/monero/blob/c8214782fb2a769c57382a999eaf099691c836e7/src/ringct/rctOps.cpp#L322>
160-
let commitment = ED25519_BASEPOINT_POINT + *H * Scalar::from(amount);
161+
// Binary search in lookup table (O(log2(n)+2) instead of O(n+2))
162+
let commitment: EdwardsPoint = {
163+
let (mut start, mut end, mut c): (usize, usize, Option<EdwardsPoint>) =
164+
(0, (ZC_LT.len() - 1) / 2, None);
165+
while start <= end {
166+
let mid = (start + end) / 2;
167+
let lookup = ZC_LT[mid].0;
168+
match amount {
169+
a if a == lookup => {
170+
c = CompressedEdwardsY::from_slice(&ZC_LT[mid].1)
171+
.expect("The lookup table cannot contain invalid curve point data")
172+
.decompress();
173+
}
174+
a if a < lookup => {
175+
end = mid - 1;
176+
}
177+
_ => {
178+
start = mid + 1;
179+
}
180+
}
181+
}
182+
183+
// Compute the zero commitment if not found.
184+
c.unwrap_or_else(|| ED25519_BASEPOINT_POINT + *H * Scalar::from(amount))
185+
};
161186

162187
let time_lock = if output
163188
.output_flags

storage/blockchain/src/ops/tx.rs

Lines changed: 47 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,12 @@
22
33
//---------------------------------------------------------------------------------------------------- Import
44
use bytemuck::TransparentWrapper;
5-
use curve25519_dalek::{constants::ED25519_BASEPOINT_POINT, Scalar};
5+
use curve25519_dalek::{
6+
constants::ED25519_BASEPOINT_POINT, edwards::CompressedEdwardsY, EdwardsPoint, Scalar,
7+
};
68
use monero_serai::transaction::{Input, Timelock, Transaction};
79

10+
use cuprate_constants::crypto::ZERO_COMMITMENT_LOOKUP_TABLE as ZC_LT;
811
use cuprate_database::{DatabaseRo, DatabaseRw, RuntimeError, StorableVec};
912

1013
use crate::{
@@ -136,18 +139,49 @@ pub fn add_tx(
136139
.enumerate()
137140
.map(|(i, output)| {
138141
// Create commitment.
139-
// <https://github.com/Cuprate/cuprate/pull/102#discussion_r1559489302>
140-
// FIXME: implement lookup table for common values:
141-
// <https://github.com/monero-project/monero/blob/c8214782fb2a769c57382a999eaf099691c836e7/src/ringct/rctOps.cpp#L322>
142-
let commitment = if miner_tx {
143-
ED25519_BASEPOINT_POINT
144-
+ *monero_serai::generators::H * Scalar::from(output.amount.unwrap_or(0))
145-
} else {
146-
proofs
147-
.as_ref()
148-
.expect("A V2 transaction with no RCT proofs is a miner tx")
149-
.base
150-
.commitments[i]
142+
143+
// Binary search in lookup table (O(log2(n)+2) instead of O(n+2))
144+
let commitment: EdwardsPoint = {
145+
let (mut start, mut end, mut c, amount): (
146+
usize,
147+
usize,
148+
Option<EdwardsPoint>,
149+
u64,
150+
) = (0, (ZC_LT.len() - 1) / 2, None, output.amount.unwrap_or(0));
151+
while start <= end {
152+
let mid = (start + end) / 2;
153+
let lookup = ZC_LT[mid].0;
154+
match amount {
155+
a if a == lookup => {
156+
c = CompressedEdwardsY::from_slice(&ZC_LT[mid].1)
157+
.expect(
158+
"The lookup table cannot contain invalid curve point data",
159+
)
160+
.decompress();
161+
}
162+
a if a < lookup => {
163+
end = mid - 1;
164+
}
165+
_ => {
166+
start = mid + 1;
167+
}
168+
}
169+
}
170+
171+
// Compute commitment if not found.
172+
c.unwrap_or_else(|| {
173+
if miner_tx {
174+
ED25519_BASEPOINT_POINT
175+
+ *monero_serai::generators::H
176+
* Scalar::from(output.amount.unwrap_or(0))
177+
} else {
178+
proofs
179+
.as_ref()
180+
.expect("A V2 transaction with no RCT proofs is a miner tx")
181+
.base
182+
.commitments[i]
183+
}
184+
})
151185
};
152186

153187
// Add the RCT output.

0 commit comments

Comments
 (0)