mirror of
https://github.com/Cuprate/cuprate.git
synced 2025-03-31 03:19:06 +00:00
Update to experimental monero oxide api (#386)
* add specific method for context
* add new statemachine for tx verification
* fix consensus crates build
* working builds
* fix CI
* add docs
* fix CI
* fix docs
* fix clippy
* cleanup
* add docs to `blockchain_context`
* fix doc tests
* add output cache
* new monero-serai
* todo
* todo
* Revert "new monero-serai"
This reverts commit fe3f6acc67
.
* use indexmap to request outputs
* clean up
* fix typos
* fix CI
* fix cargo hack
* fix reorgs
* check if a block is already present before adding it to the alt block cache
* fmt
* update to new monero oxide API
* fmt & fix cache
* update config values
* fix tests
* fix no-std builds
This commit is contained in:
parent
2dc258e4c8
commit
5c2b56c78e
20 changed files with 113 additions and 114 deletions
30
Cargo.lock
generated
30
Cargo.lock
generated
|
@ -1152,7 +1152,7 @@ dependencies = [
|
|||
[[package]]
|
||||
name = "dalek-ff-group"
|
||||
version = "0.4.1"
|
||||
source = "git+https://github.com/Cuprate/serai.git?rev=e6fdef6#e6fdef6d0b4481932ac9647796eb3fa56197ed66"
|
||||
source = "git+https://github.com/Cuprate/serai.git?rev=e6ae8c2#e6ae8c2b1f9d791f35ea225032cc0a3f79dec99d"
|
||||
dependencies = [
|
||||
"crypto-bigint",
|
||||
"curve25519-dalek",
|
||||
|
@ -1317,7 +1317,7 @@ dependencies = [
|
|||
[[package]]
|
||||
name = "flexible-transcript"
|
||||
version = "0.3.2"
|
||||
source = "git+https://github.com/Cuprate/serai.git?rev=e6fdef6#e6fdef6d0b4481932ac9647796eb3fa56197ed66"
|
||||
source = "git+https://github.com/Cuprate/serai.git?rev=e6ae8c2#e6ae8c2b1f9d791f35ea225032cc0a3f79dec99d"
|
||||
dependencies = [
|
||||
"blake2",
|
||||
"digest",
|
||||
|
@ -2023,7 +2023,7 @@ dependencies = [
|
|||
[[package]]
|
||||
name = "monero-address"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/Cuprate/serai.git?rev=e6fdef6#e6fdef6d0b4481932ac9647796eb3fa56197ed66"
|
||||
source = "git+https://github.com/Cuprate/serai.git?rev=e6ae8c2#e6ae8c2b1f9d791f35ea225032cc0a3f79dec99d"
|
||||
dependencies = [
|
||||
"curve25519-dalek",
|
||||
"monero-io",
|
||||
|
@ -2036,7 +2036,7 @@ dependencies = [
|
|||
[[package]]
|
||||
name = "monero-borromean"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/Cuprate/serai.git?rev=e6fdef6#e6fdef6d0b4481932ac9647796eb3fa56197ed66"
|
||||
source = "git+https://github.com/Cuprate/serai.git?rev=e6ae8c2#e6ae8c2b1f9d791f35ea225032cc0a3f79dec99d"
|
||||
dependencies = [
|
||||
"curve25519-dalek",
|
||||
"monero-generators",
|
||||
|
@ -2049,7 +2049,7 @@ dependencies = [
|
|||
[[package]]
|
||||
name = "monero-bulletproofs"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/Cuprate/serai.git?rev=e6fdef6#e6fdef6d0b4481932ac9647796eb3fa56197ed66"
|
||||
source = "git+https://github.com/Cuprate/serai.git?rev=e6ae8c2#e6ae8c2b1f9d791f35ea225032cc0a3f79dec99d"
|
||||
dependencies = [
|
||||
"curve25519-dalek",
|
||||
"monero-generators",
|
||||
|
@ -2064,7 +2064,7 @@ dependencies = [
|
|||
[[package]]
|
||||
name = "monero-clsag"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/Cuprate/serai.git?rev=e6fdef6#e6fdef6d0b4481932ac9647796eb3fa56197ed66"
|
||||
source = "git+https://github.com/Cuprate/serai.git?rev=e6ae8c2#e6ae8c2b1f9d791f35ea225032cc0a3f79dec99d"
|
||||
dependencies = [
|
||||
"curve25519-dalek",
|
||||
"dalek-ff-group",
|
||||
|
@ -2084,7 +2084,7 @@ dependencies = [
|
|||
[[package]]
|
||||
name = "monero-generators"
|
||||
version = "0.4.0"
|
||||
source = "git+https://github.com/Cuprate/serai.git?rev=e6fdef6#e6fdef6d0b4481932ac9647796eb3fa56197ed66"
|
||||
source = "git+https://github.com/Cuprate/serai.git?rev=e6ae8c2#e6ae8c2b1f9d791f35ea225032cc0a3f79dec99d"
|
||||
dependencies = [
|
||||
"curve25519-dalek",
|
||||
"dalek-ff-group",
|
||||
|
@ -2098,7 +2098,7 @@ dependencies = [
|
|||
[[package]]
|
||||
name = "monero-io"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/Cuprate/serai.git?rev=e6fdef6#e6fdef6d0b4481932ac9647796eb3fa56197ed66"
|
||||
source = "git+https://github.com/Cuprate/serai.git?rev=e6ae8c2#e6ae8c2b1f9d791f35ea225032cc0a3f79dec99d"
|
||||
dependencies = [
|
||||
"curve25519-dalek",
|
||||
"std-shims",
|
||||
|
@ -2107,7 +2107,7 @@ dependencies = [
|
|||
[[package]]
|
||||
name = "monero-mlsag"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/Cuprate/serai.git?rev=e6fdef6#e6fdef6d0b4481932ac9647796eb3fa56197ed66"
|
||||
source = "git+https://github.com/Cuprate/serai.git?rev=e6ae8c2#e6ae8c2b1f9d791f35ea225032cc0a3f79dec99d"
|
||||
dependencies = [
|
||||
"curve25519-dalek",
|
||||
"monero-generators",
|
||||
|
@ -2121,7 +2121,7 @@ dependencies = [
|
|||
[[package]]
|
||||
name = "monero-primitives"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/Cuprate/serai.git?rev=e6fdef6#e6fdef6d0b4481932ac9647796eb3fa56197ed66"
|
||||
source = "git+https://github.com/Cuprate/serai.git?rev=e6ae8c2#e6ae8c2b1f9d791f35ea225032cc0a3f79dec99d"
|
||||
dependencies = [
|
||||
"curve25519-dalek",
|
||||
"monero-generators",
|
||||
|
@ -2134,7 +2134,7 @@ dependencies = [
|
|||
[[package]]
|
||||
name = "monero-rpc"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/Cuprate/serai.git?rev=e6fdef6#e6fdef6d0b4481932ac9647796eb3fa56197ed66"
|
||||
source = "git+https://github.com/Cuprate/serai.git?rev=e6ae8c2#e6ae8c2b1f9d791f35ea225032cc0a3f79dec99d"
|
||||
dependencies = [
|
||||
"curve25519-dalek",
|
||||
"hex",
|
||||
|
@ -2150,7 +2150,7 @@ dependencies = [
|
|||
[[package]]
|
||||
name = "monero-serai"
|
||||
version = "0.1.4-alpha"
|
||||
source = "git+https://github.com/Cuprate/serai.git?rev=e6fdef6#e6fdef6d0b4481932ac9647796eb3fa56197ed66"
|
||||
source = "git+https://github.com/Cuprate/serai.git?rev=e6ae8c2#e6ae8c2b1f9d791f35ea225032cc0a3f79dec99d"
|
||||
dependencies = [
|
||||
"curve25519-dalek",
|
||||
"hex-literal",
|
||||
|
@ -2168,7 +2168,7 @@ dependencies = [
|
|||
[[package]]
|
||||
name = "monero-simple-request-rpc"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/Cuprate/serai.git?rev=e6fdef6#e6fdef6d0b4481932ac9647796eb3fa56197ed66"
|
||||
source = "git+https://github.com/Cuprate/serai.git?rev=e6ae8c2#e6ae8c2b1f9d791f35ea225032cc0a3f79dec99d"
|
||||
dependencies = [
|
||||
"digest_auth",
|
||||
"hex",
|
||||
|
@ -2865,7 +2865,7 @@ dependencies = [
|
|||
[[package]]
|
||||
name = "simple-request"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/Cuprate/serai.git?rev=e6fdef6#e6fdef6d0b4481932ac9647796eb3fa56197ed66"
|
||||
source = "git+https://github.com/Cuprate/serai.git?rev=e6ae8c2#e6ae8c2b1f9d791f35ea225032cc0a3f79dec99d"
|
||||
dependencies = [
|
||||
"http-body-util",
|
||||
"hyper",
|
||||
|
@ -2931,7 +2931,7 @@ checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3"
|
|||
[[package]]
|
||||
name = "std-shims"
|
||||
version = "0.1.1"
|
||||
source = "git+https://github.com/Cuprate/serai.git?rev=e6fdef6#e6fdef6d0b4481932ac9647796eb3fa56197ed66"
|
||||
source = "git+https://github.com/Cuprate/serai.git?rev=e6ae8c2#e6ae8c2b1f9d791f35ea225032cc0a3f79dec99d"
|
||||
dependencies = [
|
||||
"hashbrown 0.14.5",
|
||||
"spin",
|
||||
|
|
|
@ -121,7 +121,7 @@ futures = { version = "0.3", default-features = false }
|
|||
hex = { version = "0.4", default-features = false }
|
||||
hex-literal = { version = "0.4", default-features = false }
|
||||
indexmap = { version = "2", default-features = false }
|
||||
monero-serai = { git = "https://github.com/Cuprate/serai.git", rev = "e6fdef6", default-features = false }
|
||||
monero-serai = { git = "https://github.com/Cuprate/serai.git", rev = "e6ae8c2", default-features = false }
|
||||
nu-ansi-term = { version = "0.46", default-features = false }
|
||||
paste = { version = "1", default-features = false }
|
||||
pin-project = { version = "1", default-features = false }
|
||||
|
@ -145,8 +145,8 @@ tracing-subscriber = { version = "0.3", default-features = false }
|
|||
tracing = { version = "0.1", default-features = false }
|
||||
|
||||
## workspace.dev-dependencies
|
||||
monero-rpc = { git = "https://github.com/Cuprate/serai.git", rev = "e6fdef6" }
|
||||
monero-simple-request-rpc = { git = "https://github.com/Cuprate/serai.git", rev = "e6fdef6" }
|
||||
monero-rpc = { git = "https://github.com/Cuprate/serai.git", rev = "e6ae8c2" }
|
||||
monero-simple-request-rpc = { git = "https://github.com/Cuprate/serai.git", rev = "e6ae8c2" }
|
||||
tempfile = { version = "3" }
|
||||
pretty_assertions = { version = "1" }
|
||||
proptest = { version = "1" }
|
||||
|
|
|
@ -43,9 +43,9 @@ peer_save_period = { secs = 90, nanos = 0 }
|
|||
## The block downloader config.
|
||||
[p2p.block_downloader]
|
||||
## The size of the buffer of sequential blocks waiting to be verified and added to the chain (bytes).
|
||||
buffer_bytes = 50_000_000
|
||||
buffer_bytes = 1_000_000_000
|
||||
## The size of the queue of blocks which are waiting for a parent block to be downloaded (bytes).
|
||||
in_progress_queue_bytes = 50_000_000
|
||||
in_progress_queue_bytes = 500_000_000
|
||||
## The target size of a batch of blocks (bytes), must not exceed 100MB.
|
||||
target_batch_bytes = 10_000_000
|
||||
## The amount of time between checking the pool of connected peers for free peers to download blocks.
|
||||
|
|
|
@ -452,7 +452,7 @@ impl super::BlockchainManager {
|
|||
.iter()
|
||||
.flat_map(|tx| {
|
||||
tx.tx.prefix().inputs.iter().map(|input| match input {
|
||||
Input::ToKey { key_image, .. } => key_image.compress().0,
|
||||
Input::ToKey { key_image, .. } => key_image.0,
|
||||
Input::Gen(_) => unreachable!(),
|
||||
})
|
||||
})
|
||||
|
|
|
@ -47,8 +47,8 @@ impl From<BlockDownloaderConfig> for cuprate_p2p::block_downloader::BlockDownloa
|
|||
impl Default for BlockDownloaderConfig {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
buffer_bytes: 50_000_000,
|
||||
in_progress_queue_bytes: 50_000_000,
|
||||
buffer_bytes: 1_000_000_000,
|
||||
in_progress_queue_bytes: 500_000_000,
|
||||
check_client_pool_interval: Duration::from_secs(30),
|
||||
target_batch_bytes: 10_000_000,
|
||||
}
|
||||
|
|
|
@ -1,17 +1,20 @@
|
|||
use std::cmp::Ordering;
|
||||
|
||||
use curve25519_dalek::EdwardsPoint;
|
||||
use monero_serai::{
|
||||
io::decompress_point,
|
||||
ringct::RctType,
|
||||
transaction::{Input, Output, Timelock, Transaction},
|
||||
};
|
||||
|
||||
pub use cuprate_types::TxVersion;
|
||||
|
||||
use crate::{
|
||||
batch_verifier::BatchVerifier, blocks::penalty_free_zone, check_point_canonically_encoded,
|
||||
is_decomposed_amount, HardFork,
|
||||
};
|
||||
|
||||
// re-export.
|
||||
pub use cuprate_types::TxVersion;
|
||||
|
||||
mod contextual_data;
|
||||
mod ring_ct;
|
||||
mod ring_signatures;
|
||||
|
@ -327,7 +330,10 @@ fn check_key_images(input: &Input) -> Result<(), TransactionError> {
|
|||
match input {
|
||||
Input::ToKey { key_image, .. } => {
|
||||
// this happens in monero-serai but we may as well duplicate the check.
|
||||
if !key_image.is_torsion_free() {
|
||||
if !decompress_point(*key_image)
|
||||
.as_ref()
|
||||
.is_some_and(EdwardsPoint::is_torsion_free)
|
||||
{
|
||||
return Err(TransactionError::KeyImageIsNotInPrimeSubGroup);
|
||||
}
|
||||
}
|
||||
|
@ -388,7 +394,7 @@ fn check_ring_members_unique(input: &Input, hf: HardFork) -> Result<(), Transact
|
|||
/// ref: <https://monero-book.cuprate.org/consensus_rules/transactions/inputs.html#sorted-inputs>
|
||||
fn check_inputs_sorted(inputs: &[Input], hf: HardFork) -> Result<(), TransactionError> {
|
||||
let get_ki = |inp: &Input| match inp {
|
||||
Input::ToKey { key_image, .. } => Ok(key_image.compress().to_bytes()),
|
||||
Input::ToKey { key_image, .. } => Ok(key_image.to_bytes()),
|
||||
Input::Gen(_) => Err(TransactionError::IncorrectInputType),
|
||||
};
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use std::cmp::{max, min};
|
||||
|
||||
use curve25519_dalek::EdwardsPoint;
|
||||
use curve25519_dalek::edwards::CompressedEdwardsY;
|
||||
use indexmap::{IndexMap, IndexSet};
|
||||
use monero_serai::transaction::{Input, Timelock};
|
||||
|
||||
|
@ -57,9 +57,9 @@ pub fn insert_ring_member_ids(
|
|||
#[derive(Debug)]
|
||||
pub enum Rings {
|
||||
/// Legacy, pre-ringCT, rings.
|
||||
Legacy(Vec<Vec<EdwardsPoint>>),
|
||||
Legacy(Vec<Vec<CompressedEdwardsY>>),
|
||||
/// `RingCT` rings, (outkey, amount commitment).
|
||||
RingCT(Vec<Vec<[EdwardsPoint; 2]>>),
|
||||
RingCT(Vec<Vec<[CompressedEdwardsY; 2]>>),
|
||||
}
|
||||
|
||||
/// Information on the outputs the transaction is referencing for inputs (ring members).
|
||||
|
|
|
@ -2,6 +2,7 @@ use curve25519_dalek::{EdwardsPoint, Scalar};
|
|||
use hex_literal::hex;
|
||||
use monero_serai::{
|
||||
generators::H,
|
||||
io::decompress_point,
|
||||
ringct::{
|
||||
clsag::ClsagError,
|
||||
mlsag::{AggregateRingMatrixBuilder, MlsagError, RingMatrix},
|
||||
|
@ -74,9 +75,21 @@ fn simple_type_balances(rct_sig: &RctProofs) -> Result<(), RingCTError> {
|
|||
}
|
||||
};
|
||||
|
||||
let sum_inputs = pseudo_outs.iter().sum::<EdwardsPoint>();
|
||||
let sum_outputs =
|
||||
rct_sig.base.commitments.iter().sum::<EdwardsPoint>() + Scalar::from(rct_sig.base.fee) * *H;
|
||||
let sum_inputs = pseudo_outs
|
||||
.iter()
|
||||
.copied()
|
||||
.map(decompress_point)
|
||||
.sum::<Option<EdwardsPoint>>()
|
||||
.ok_or(RingCTError::SimpleAmountDoNotBalance)?;
|
||||
let sum_outputs = rct_sig
|
||||
.base
|
||||
.commitments
|
||||
.iter()
|
||||
.copied()
|
||||
.map(decompress_point)
|
||||
.sum::<Option<EdwardsPoint>>()
|
||||
.ok_or(RingCTError::SimpleAmountDoNotBalance)?
|
||||
+ Scalar::from(rct_sig.base.fee) * *H;
|
||||
|
||||
if sum_inputs == sum_outputs {
|
||||
Ok(())
|
||||
|
@ -178,7 +191,7 @@ pub(crate) fn check_input_signatures(
|
|||
.collect::<Vec<_>>();
|
||||
|
||||
let mut matrix =
|
||||
AggregateRingMatrixBuilder::new(&proofs.base.commitments, proofs.base.fee);
|
||||
AggregateRingMatrixBuilder::new(&proofs.base.commitments, proofs.base.fee)?;
|
||||
|
||||
rings.iter().try_for_each(|ring| matrix.push_ring(ring))?;
|
||||
|
||||
|
@ -210,7 +223,7 @@ pub(crate) fn check_input_signatures(
|
|||
panic!("How did we build a ring with no decoys?");
|
||||
};
|
||||
|
||||
Ok(clsags.verify(ring, key_image, pseudo_out, msg)?)
|
||||
Ok(clsags.verify(ring.clone(), key_image, pseudo_out, msg)?)
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use std::ops::Range;
|
||||
|
||||
use curve25519_dalek::{
|
||||
constants::{ED25519_BASEPOINT_POINT, EIGHT_TORSION},
|
||||
constants::{ED25519_BASEPOINT_COMPRESSED, EIGHT_TORSION},
|
||||
edwards::CompressedEdwardsY,
|
||||
EdwardsPoint,
|
||||
};
|
||||
|
@ -92,7 +92,7 @@ fn test_decoy_info() {
|
|||
fn test_torsion_ki() {
|
||||
for &key_image in &EIGHT_TORSION[1..] {
|
||||
assert!(check_key_images(&Input::ToKey {
|
||||
key_image,
|
||||
key_image: key_image.compress(),
|
||||
amount: None,
|
||||
key_offsets: vec![],
|
||||
})
|
||||
|
@ -262,13 +262,13 @@ proptest! {
|
|||
#[test]
|
||||
fn test_check_input_has_decoys(key_offsets in vec(any::<u64>(), 1..10_000)) {
|
||||
assert!(check_input_has_decoys(&Input::ToKey {
|
||||
key_image: ED25519_BASEPOINT_POINT,
|
||||
key_image: ED25519_BASEPOINT_COMPRESSED,
|
||||
amount: None,
|
||||
key_offsets,
|
||||
}).is_ok());
|
||||
|
||||
assert!(check_input_has_decoys(&Input::ToKey {
|
||||
key_image: ED25519_BASEPOINT_POINT,
|
||||
key_image: ED25519_BASEPOINT_COMPRESSED,
|
||||
amount: None,
|
||||
key_offsets: vec![],
|
||||
}).is_err());
|
||||
|
|
|
@ -289,7 +289,7 @@ pub(crate) async fn check_kis_unique<D: Database>(
|
|||
txs.try_for_each(|tx| {
|
||||
tx.tx.prefix().inputs.iter().try_for_each(|input| {
|
||||
if let Input::ToKey { key_image, .. } = input {
|
||||
if !spent_kis.insert(key_image.compress().0) {
|
||||
if !spent_kis.insert(key_image.0) {
|
||||
tracing::debug!("Duplicate key image found in batch.");
|
||||
return Err(ConsensusError::Transaction(TransactionError::KeyImageSpent));
|
||||
}
|
||||
|
|
|
@ -96,27 +96,19 @@ pub fn new_ring_member_info(
|
|||
.collect::<Vec<_>>()
|
||||
})
|
||||
.collect(),
|
||||
rings: new_rings(used_outs, tx_version)?,
|
||||
rings: new_rings(used_outs, tx_version),
|
||||
decoy_info,
|
||||
})
|
||||
}
|
||||
|
||||
/// Builds the [`Rings`] for the transaction inputs, from the given outputs.
|
||||
fn new_rings(
|
||||
outputs: Vec<Vec<OutputOnChain>>,
|
||||
tx_version: TxVersion,
|
||||
) -> Result<Rings, TransactionError> {
|
||||
Ok(match tx_version {
|
||||
fn new_rings(outputs: Vec<Vec<OutputOnChain>>, tx_version: TxVersion) -> Rings {
|
||||
match tx_version {
|
||||
TxVersion::RingSignatures => Rings::Legacy(
|
||||
outputs
|
||||
.into_iter()
|
||||
.map(|inp_outs| {
|
||||
inp_outs
|
||||
.into_iter()
|
||||
.map(|out| out.key.ok_or(TransactionError::RingMemberNotFoundOrInvalid))
|
||||
.collect::<Result<Vec<_>, TransactionError>>()
|
||||
})
|
||||
.collect::<Result<Vec<_>, TransactionError>>()?,
|
||||
.map(|inp_outs| inp_outs.into_iter().map(|out| out.key).collect::<Vec<_>>())
|
||||
.collect::<Vec<_>>(),
|
||||
),
|
||||
TxVersion::RingCT => Rings::RingCT(
|
||||
outputs
|
||||
|
@ -124,18 +116,12 @@ fn new_rings(
|
|||
.map(|inp_outs| {
|
||||
inp_outs
|
||||
.into_iter()
|
||||
.map(|out| {
|
||||
Ok([
|
||||
out.key
|
||||
.ok_or(TransactionError::RingMemberNotFoundOrInvalid)?,
|
||||
out.commitment,
|
||||
])
|
||||
})
|
||||
.collect::<Result<_, TransactionError>>()
|
||||
.map(|out| [out.key, out.commitment])
|
||||
.collect::<_>()
|
||||
})
|
||||
.collect::<Result<_, _>>()?,
|
||||
.collect::<_>(),
|
||||
),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/// Retrieves an [`OutputCache`] for the list of transactions.
|
||||
|
@ -158,7 +144,7 @@ pub async fn get_output_cache<D: Database>(
|
|||
.call(BlockchainReadRequest::Outputs(output_ids))
|
||||
.await?
|
||||
else {
|
||||
panic!("Database sent incorrect response!")
|
||||
unreachable!();
|
||||
};
|
||||
|
||||
Ok(outputs)
|
||||
|
|
|
@ -7,7 +7,7 @@ use std::{
|
|||
sync::Arc,
|
||||
};
|
||||
|
||||
use curve25519_dalek::{constants::ED25519_BASEPOINT_POINT, edwards::CompressedEdwardsY};
|
||||
use curve25519_dalek::{constants::ED25519_BASEPOINT_COMPRESSED, edwards::CompressedEdwardsY};
|
||||
use indexmap::IndexMap;
|
||||
use monero_serai::transaction::{Timelock, Transaction};
|
||||
use tower::service_fn;
|
||||
|
@ -71,13 +71,8 @@ macro_rules! test_verify_valid_v2_tx {
|
|||
OutputOnChain {
|
||||
height: 0,
|
||||
time_lock: Timelock::None,
|
||||
commitment: CompressedEdwardsY::from_slice(&hex_literal::hex!($commitment))
|
||||
.unwrap()
|
||||
.decompress()
|
||||
.unwrap(),
|
||||
key: CompressedEdwardsY::from_slice(&hex_literal::hex!($ring_member))
|
||||
.unwrap()
|
||||
.decompress(),
|
||||
commitment: CompressedEdwardsY(hex_literal::hex!($commitment)),
|
||||
key: CompressedEdwardsY(hex_literal::hex!($ring_member)),
|
||||
}),)+)+
|
||||
];
|
||||
|
||||
|
@ -103,10 +98,8 @@ macro_rules! test_verify_valid_v2_tx {
|
|||
OutputOnChain {
|
||||
height: 0,
|
||||
time_lock: Timelock::None,
|
||||
commitment: ED25519_BASEPOINT_POINT,
|
||||
key: CompressedEdwardsY::from_slice(&hex_literal::hex!($ring_member))
|
||||
.unwrap()
|
||||
.decompress(),
|
||||
commitment: ED25519_BASEPOINT_COMPRESSED,
|
||||
key: CompressedEdwardsY(hex_literal::hex!($ring_member)),
|
||||
}),)+)+
|
||||
];
|
||||
|
||||
|
|
|
@ -4,8 +4,11 @@
|
|||
use std::sync::LazyLock;
|
||||
|
||||
use curve25519_dalek::{
|
||||
constants::ED25519_BASEPOINT_POINT, edwards::VartimeEdwardsPrecomputation,
|
||||
traits::VartimePrecomputedMultiscalarMul, EdwardsPoint, Scalar,
|
||||
constants::{ED25519_BASEPOINT_COMPRESSED, ED25519_BASEPOINT_POINT},
|
||||
edwards::CompressedEdwardsY,
|
||||
edwards::VartimeEdwardsPrecomputation,
|
||||
traits::VartimePrecomputedMultiscalarMul,
|
||||
Scalar,
|
||||
};
|
||||
use monero_serai::generators::H;
|
||||
|
||||
|
@ -49,15 +52,16 @@ static H_PRECOMP: LazyLock<VartimeEdwardsPrecomputation> =
|
|||
/// # Invariant
|
||||
/// This function assumes that the [`ZERO_COMMITMENT_DECOMPOSED_AMOUNT`]
|
||||
/// table is sorted.
|
||||
pub static ZERO_COMMITMENT_LOOKUP_TABLE: LazyLock<[EdwardsPoint; 172]> = LazyLock::new(|| {
|
||||
let mut lookup_table: [EdwardsPoint; 172] = [ED25519_BASEPOINT_POINT; 172];
|
||||
pub static ZERO_COMMITMENT_LOOKUP_TABLE: LazyLock<[CompressedEdwardsY; 172]> =
|
||||
LazyLock::new(|| {
|
||||
let mut lookup_table: [CompressedEdwardsY; 172] = [ED25519_BASEPOINT_COMPRESSED; 172];
|
||||
|
||||
for (i, amount) in ZERO_COMMITMENT_DECOMPOSED_AMOUNT.into_iter().enumerate() {
|
||||
lookup_table[i] = ED25519_BASEPOINT_POINT + *H * Scalar::from(amount);
|
||||
}
|
||||
for (i, amount) in ZERO_COMMITMENT_DECOMPOSED_AMOUNT.into_iter().enumerate() {
|
||||
lookup_table[i] = (ED25519_BASEPOINT_POINT + *H * Scalar::from(amount)).compress();
|
||||
}
|
||||
|
||||
lookup_table
|
||||
});
|
||||
lookup_table
|
||||
});
|
||||
|
||||
//---------------------------------------------------------------------------------------------------- Free functions
|
||||
|
||||
|
@ -66,7 +70,7 @@ pub static ZERO_COMMITMENT_LOOKUP_TABLE: LazyLock<[EdwardsPoint; 172]> = LazyLoc
|
|||
/// It will first attempt to lookup into the table of known Pre-RCT value.
|
||||
/// Compute it otherwise.
|
||||
#[expect(clippy::cast_possible_truncation)]
|
||||
pub fn compute_zero_commitment(amount: u64) -> EdwardsPoint {
|
||||
pub fn compute_zero_commitment(amount: u64) -> CompressedEdwardsY {
|
||||
// OPTIMIZATION: Unlike monerod which execute a linear search across its lookup
|
||||
// table (O(n)). Cuprate is making use of an arithmetic based constant time
|
||||
// version (O(1)). It has been benchmarked in both hit and miss scenarios against
|
||||
|
@ -78,7 +82,7 @@ pub fn compute_zero_commitment(amount: u64) -> EdwardsPoint {
|
|||
// the amount without its most significant digit.
|
||||
let Some(log) = amount.checked_ilog10() else {
|
||||
// amount = 0 so H component is 0.
|
||||
return ED25519_BASEPOINT_POINT;
|
||||
return ED25519_BASEPOINT_COMPRESSED;
|
||||
};
|
||||
let div = 10_u64.pow(log);
|
||||
|
||||
|
@ -89,7 +93,9 @@ pub fn compute_zero_commitment(amount: u64) -> EdwardsPoint {
|
|||
// there aren't only trailing zeroes behind the most significant digit.
|
||||
// The amount is not part of the table and can calculated apart.
|
||||
if most_significant_digit * div != amount {
|
||||
return H_PRECOMP.vartime_multiscalar_mul([Scalar::from(amount), Scalar::ONE]);
|
||||
return H_PRECOMP
|
||||
.vartime_multiscalar_mul([Scalar::from(amount), Scalar::ONE])
|
||||
.compress();
|
||||
}
|
||||
|
||||
// Calculating the index back by progressing within the powers of 10.
|
||||
|
@ -116,7 +122,10 @@ mod test {
|
|||
fn compare_lookup_with_computation() {
|
||||
for amount in ZERO_COMMITMENT_DECOMPOSED_AMOUNT {
|
||||
let commitment = H_PRECOMP.vartime_multiscalar_mul([Scalar::from(amount), Scalar::ONE]);
|
||||
assert!(commitment == compute_zero_commitment(amount));
|
||||
assert_eq!(
|
||||
commitment,
|
||||
compute_zero_commitment(amount).decompress().unwrap()
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -35,7 +35,7 @@ pub fn tx_fee(tx: &Transaction) -> u64 {
|
|||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use curve25519_dalek::{edwards::CompressedEdwardsY, EdwardsPoint};
|
||||
use curve25519_dalek::edwards::CompressedEdwardsY;
|
||||
use monero_serai::transaction::{NotPruned, Output, Timelock, TransactionPrefix};
|
||||
|
||||
use super::*;
|
||||
|
@ -46,7 +46,7 @@ mod test {
|
|||
let input = Input::ToKey {
|
||||
amount: Some(u64::MAX),
|
||||
key_offsets: vec![],
|
||||
key_image: EdwardsPoint::default(),
|
||||
key_image: CompressedEdwardsY::default(),
|
||||
};
|
||||
|
||||
let output = Output {
|
||||
|
|
|
@ -165,9 +165,7 @@ pub fn output_to_output_on_chain(
|
|||
Timelock::None
|
||||
};
|
||||
|
||||
let key = CompressedEdwardsY::from_slice(&output.key)
|
||||
.map(|y| y.decompress())
|
||||
.unwrap_or(None);
|
||||
let key = CompressedEdwardsY(output.key);
|
||||
|
||||
Ok(OutputOnChain {
|
||||
height: output.height as usize,
|
||||
|
@ -191,10 +189,7 @@ pub fn rct_output_to_output_on_chain(
|
|||
table_tx_unlock_time: &impl DatabaseRo<TxUnlockTime>,
|
||||
) -> DbResult<OutputOnChain> {
|
||||
// INVARIANT: Commitments stored are valid when stored by the database.
|
||||
let commitment = CompressedEdwardsY::from_slice(&rct_output.commitment)
|
||||
.unwrap()
|
||||
.decompress()
|
||||
.unwrap();
|
||||
let commitment = CompressedEdwardsY(rct_output.commitment);
|
||||
|
||||
let time_lock = if rct_output
|
||||
.output_flags
|
||||
|
@ -205,9 +200,7 @@ pub fn rct_output_to_output_on_chain(
|
|||
Timelock::None
|
||||
};
|
||||
|
||||
let key = CompressedEdwardsY::from_slice(&rct_output.key)
|
||||
.map(|y| y.decompress())
|
||||
.unwrap_or(None);
|
||||
let key = CompressedEdwardsY(rct_output.key);
|
||||
|
||||
Ok(OutputOnChain {
|
||||
height: rct_output.height as usize,
|
||||
|
|
|
@ -96,7 +96,7 @@ pub fn add_tx(
|
|||
match inputs {
|
||||
// Key images.
|
||||
Input::ToKey { key_image, .. } => {
|
||||
add_key_image(key_image.compress().as_bytes(), tables.key_images_mut())?;
|
||||
add_key_image(key_image.as_bytes(), tables.key_images_mut())?;
|
||||
}
|
||||
// This is a miner transaction, set it for later use.
|
||||
Input::Gen(_) => miner_tx = true,
|
||||
|
@ -154,7 +154,7 @@ pub fn add_tx(
|
|||
height,
|
||||
output_flags,
|
||||
tx_idx: tx_id,
|
||||
commitment: commitment.compress().0,
|
||||
commitment: commitment.0,
|
||||
},
|
||||
tables.rct_outputs_mut(),
|
||||
)
|
||||
|
@ -219,7 +219,7 @@ pub fn remove_tx(tx_hash: &TxHash, tables: &mut impl TablesMut) -> DbResult<(TxI
|
|||
match inputs {
|
||||
// Key images.
|
||||
Input::ToKey { key_image, .. } => {
|
||||
remove_key_image(key_image.compress().as_bytes(), tables.key_images_mut())?;
|
||||
remove_key_image(key_image.as_bytes(), tables.key_images_mut())?;
|
||||
}
|
||||
// This is a miner transaction, set it for later use.
|
||||
Input::Gen(_) => miner_tx = true,
|
||||
|
|
|
@ -48,7 +48,7 @@ pub(super) fn remove_tx_key_images(
|
|||
/// This function will panic if the [`Input`] is not [`Input::ToKey`]
|
||||
fn ki_from_input(input: &Input) -> [u8; 32] {
|
||||
match input {
|
||||
Input::ToKey { key_image, .. } => key_image.compress().0,
|
||||
Input::ToKey { key_image, .. } => key_image.0,
|
||||
Input::Gen(_) => panic!("miner tx cannot be added to the txpool"),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -71,7 +71,7 @@ impl From<transaction::Transaction> for Transaction {
|
|||
let key = Key {
|
||||
amount: amount.unwrap_or(0),
|
||||
key_offsets,
|
||||
k_image: HexBytes::<32>(key_image.compress().0),
|
||||
k_image: HexBytes::<32>(key_image.0),
|
||||
};
|
||||
|
||||
Some(Input { key })
|
||||
|
@ -169,7 +169,7 @@ impl From<transaction::Transaction> for Transaction {
|
|||
.base
|
||||
.commitments
|
||||
.into_iter()
|
||||
.map(|point| HexBytes::<32>(point.compress().0))
|
||||
.map(|point| HexBytes::<32>(point.0))
|
||||
.collect();
|
||||
|
||||
let rct_signatures = RctSignatures::NonCoinbase {
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use curve25519_dalek::EdwardsPoint;
|
||||
use curve25519_dalek::edwards::CompressedEdwardsY;
|
||||
use indexmap::{IndexMap, IndexSet};
|
||||
use monero_serai::transaction::Transaction;
|
||||
|
||||
|
@ -87,8 +87,7 @@ impl OutputCache {
|
|||
OutputOnChain {
|
||||
height,
|
||||
time_lock: tx.prefix().additional_timelock,
|
||||
// TODO: this needs to check the point is canonical.
|
||||
key: out.key.decompress(),
|
||||
key: out.key,
|
||||
commitment: get_output_commitment(tx, i),
|
||||
},
|
||||
);
|
||||
|
@ -111,7 +110,7 @@ impl OutputCache {
|
|||
}
|
||||
|
||||
/// Returns the amount commitment for the output at the given index `i` in the [`Transaction`]
|
||||
fn get_output_commitment(tx: &Transaction, i: usize) -> EdwardsPoint {
|
||||
fn get_output_commitment(tx: &Transaction, i: usize) -> CompressedEdwardsY {
|
||||
match tx {
|
||||
Transaction::V1 { prefix, .. } => {
|
||||
compute_zero_commitment(prefix.outputs[i].amount.unwrap_or_default())
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
use std::num::NonZero;
|
||||
|
||||
use curve25519_dalek::edwards::EdwardsPoint;
|
||||
use curve25519_dalek::edwards::CompressedEdwardsY;
|
||||
use monero_serai::{
|
||||
block::Block,
|
||||
transaction::{Timelock, Transaction},
|
||||
|
@ -142,9 +142,9 @@ pub struct OutputOnChain {
|
|||
/// The timelock of this output, if any.
|
||||
pub time_lock: Timelock,
|
||||
/// The public key of this output, if any.
|
||||
pub key: Option<EdwardsPoint>,
|
||||
pub key: CompressedEdwardsY,
|
||||
/// The output's commitment.
|
||||
pub commitment: EdwardsPoint,
|
||||
pub commitment: CompressedEdwardsY,
|
||||
}
|
||||
|
||||
/// Input required to generate an output histogram.
|
||||
|
|
Loading…
Reference in a new issue