mirror of
https://github.com/serai-dex/serai.git
synced 2025-12-08 20:29:23 +00:00
Respond to 1.1 A2 (also cited as 2 1)
`read_vec` was unbounded. It now accepts an optional bound. In some places, we are able to define and provide a bound (Bulletproofs(+)' `L` and `R` vectors). In others, we cannot (the amount of inputs within a transaction, which is not subject to any rule in the current consensus other than the total transaction size limit). Usage of `None` in those locations preserves the existing behavior.
This commit is contained in:
@@ -51,8 +51,6 @@ pub fn H_pow_2() -> &'static [EdwardsPoint; 64] {
|
|||||||
pub const MAX_COMMITMENTS: usize = 16;
|
pub const MAX_COMMITMENTS: usize = 16;
|
||||||
/// The amount of bits a value within a commitment may use.
|
/// The amount of bits a value within a commitment may use.
|
||||||
pub const COMMITMENT_BITS: usize = 64;
|
pub const COMMITMENT_BITS: usize = 64;
|
||||||
/// The logarithm (over 2) of the amount of bits a value within a commitment may use.
|
|
||||||
pub const LOG_COMMITMENT_BITS: usize = 6; // 2 ** 6 == N
|
|
||||||
|
|
||||||
/// Container struct for Bulletproofs(+) generators.
|
/// Container struct for Bulletproofs(+) generators.
|
||||||
#[allow(non_snake_case)]
|
#[allow(non_snake_case)]
|
||||||
|
|||||||
@@ -214,6 +214,20 @@ pub fn read_array<R: Read, T: Debug, F: Fn(&mut R) -> io::Result<T>, const N: us
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Read a length-prefixed variable-length list of elements.
|
/// Read a length-prefixed variable-length list of elements.
|
||||||
pub fn read_vec<R: Read, T, F: Fn(&mut R) -> io::Result<T>>(f: F, r: &mut R) -> io::Result<Vec<T>> {
|
///
|
||||||
read_raw_vec(f, read_varint(r)?, r)
|
/// An optional bound on the length of the result may be provided. If `None`, the returned `Vec`
|
||||||
|
/// will be of the length read off the reader, if successfully read. If `Some(_)`, an error will be
|
||||||
|
/// raised if the length read off the read is greater than the bound.
|
||||||
|
pub fn read_vec<R: Read, T, F: Fn(&mut R) -> io::Result<T>>(
|
||||||
|
f: F,
|
||||||
|
length_bound: Option<usize>,
|
||||||
|
r: &mut R,
|
||||||
|
) -> io::Result<Vec<T>> {
|
||||||
|
let declared_length: usize = read_varint(r)?;
|
||||||
|
if let Some(length_bound) = length_bound {
|
||||||
|
if declared_length > length_bound {
|
||||||
|
Err(io::Error::other("vector exceeds bound on length"))?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
read_raw_vec(f, declared_length, r)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -213,7 +213,7 @@ impl Decoys {
|
|||||||
pub fn write(&self, w: &mut impl io::Write) -> io::Result<()> {
|
pub fn write(&self, w: &mut impl io::Write) -> io::Result<()> {
|
||||||
write_vec(write_varint, &self.offsets, w)?;
|
write_vec(write_varint, &self.offsets, w)?;
|
||||||
w.write_all(&[self.signer_index])?;
|
w.write_all(&[self.signer_index])?;
|
||||||
write_vec(
|
write_raw_vec(
|
||||||
|pair, w| {
|
|pair, w| {
|
||||||
write_point(&pair[0], w)?;
|
write_point(&pair[0], w)?;
|
||||||
write_point(&pair[1], w)
|
write_point(&pair[1], w)
|
||||||
@@ -239,10 +239,12 @@ impl Decoys {
|
|||||||
/// This is not a Monero protocol defined struct, and this is accordingly not a Monero protocol
|
/// This is not a Monero protocol defined struct, and this is accordingly not a Monero protocol
|
||||||
/// defined serialization.
|
/// defined serialization.
|
||||||
pub fn read(r: &mut impl io::Read) -> io::Result<Decoys> {
|
pub fn read(r: &mut impl io::Read) -> io::Result<Decoys> {
|
||||||
|
let offsets = read_vec(read_varint, None, r)?;
|
||||||
|
let len = offsets.len();
|
||||||
Decoys::new(
|
Decoys::new(
|
||||||
read_vec(read_varint, r)?,
|
offsets,
|
||||||
read_byte(r)?,
|
read_byte(r)?,
|
||||||
read_vec(|r| Ok([read_point(r)?, read_point(r)?]), r)?,
|
read_raw_vec(|r| Ok([read_point(r)?, read_point(r)?]), len, r)?,
|
||||||
)
|
)
|
||||||
.ok_or_else(|| io::Error::other("invalid Decoys"))
|
.ok_or_else(|| io::Error::other("invalid Decoys"))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ use curve25519_dalek::{
|
|||||||
edwards::EdwardsPoint,
|
edwards::EdwardsPoint,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub(crate) use monero_generators::{MAX_COMMITMENTS, COMMITMENT_BITS, LOG_COMMITMENT_BITS};
|
pub(crate) use monero_generators::{MAX_COMMITMENTS, COMMITMENT_BITS};
|
||||||
|
|
||||||
pub(crate) fn multiexp(pairs: &[(Scalar, EdwardsPoint)]) -> EdwardsPoint {
|
pub(crate) fn multiexp(pairs: &[(Scalar, EdwardsPoint)]) -> EdwardsPoint {
|
||||||
let mut buf_scalars = Vec::with_capacity(pairs.len());
|
let mut buf_scalars = Vec::with_capacity(pairs.len());
|
||||||
|
|||||||
@@ -17,13 +17,13 @@ use curve25519_dalek::edwards::EdwardsPoint;
|
|||||||
|
|
||||||
use monero_io::*;
|
use monero_io::*;
|
||||||
pub use monero_generators::MAX_COMMITMENTS;
|
pub use monero_generators::MAX_COMMITMENTS;
|
||||||
|
use monero_generators::COMMITMENT_BITS;
|
||||||
use monero_primitives::Commitment;
|
use monero_primitives::Commitment;
|
||||||
|
|
||||||
pub(crate) mod scalar_vector;
|
pub(crate) mod scalar_vector;
|
||||||
pub(crate) mod point_vector;
|
pub(crate) mod point_vector;
|
||||||
|
|
||||||
pub(crate) mod core;
|
pub(crate) mod core;
|
||||||
use crate::core::LOG_COMMITMENT_BITS;
|
|
||||||
|
|
||||||
pub(crate) mod batch_verifier;
|
pub(crate) mod batch_verifier;
|
||||||
use batch_verifier::{BulletproofsBatchVerifier, BulletproofsPlusBatchVerifier};
|
use batch_verifier::{BulletproofsBatchVerifier, BulletproofsPlusBatchVerifier};
|
||||||
@@ -44,6 +44,11 @@ use crate::plus::{
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests;
|
mod tests;
|
||||||
|
|
||||||
|
// The logarithm (over 2) of the amount of bits a value within a commitment may use.
|
||||||
|
const LOG_COMMITMENT_BITS: usize = COMMITMENT_BITS.ilog2() as usize;
|
||||||
|
// The maximum length of L/R `Vec`s.
|
||||||
|
const MAX_LR: usize = (MAX_COMMITMENTS.ilog2() as usize) + LOG_COMMITMENT_BITS;
|
||||||
|
|
||||||
/// An error from proving/verifying Bulletproofs(+).
|
/// An error from proving/verifying Bulletproofs(+).
|
||||||
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
|
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
|
||||||
#[cfg_attr(feature = "std", derive(thiserror::Error))]
|
#[cfg_attr(feature = "std", derive(thiserror::Error))]
|
||||||
@@ -265,8 +270,8 @@ impl Bulletproof {
|
|||||||
tau_x: read_scalar(r)?,
|
tau_x: read_scalar(r)?,
|
||||||
mu: read_scalar(r)?,
|
mu: read_scalar(r)?,
|
||||||
ip: IpProof {
|
ip: IpProof {
|
||||||
L: read_vec(read_point, r)?,
|
L: read_vec(read_point, Some(MAX_LR), r)?,
|
||||||
R: read_vec(read_point, r)?,
|
R: read_vec(read_point, Some(MAX_LR), r)?,
|
||||||
a: read_scalar(r)?,
|
a: read_scalar(r)?,
|
||||||
b: read_scalar(r)?,
|
b: read_scalar(r)?,
|
||||||
},
|
},
|
||||||
@@ -284,8 +289,8 @@ impl Bulletproof {
|
|||||||
r_answer: read_scalar(r)?,
|
r_answer: read_scalar(r)?,
|
||||||
s_answer: read_scalar(r)?,
|
s_answer: read_scalar(r)?,
|
||||||
delta_answer: read_scalar(r)?,
|
delta_answer: read_scalar(r)?,
|
||||||
L: read_vec(read_point, r)?.into_iter().collect(),
|
L: read_vec(read_point, Some(MAX_LR), r)?.into_iter().collect(),
|
||||||
R: read_vec(read_point, r)?.into_iter().collect(),
|
R: read_vec(read_point, Some(MAX_LR), r)?.into_iter().collect(),
|
||||||
},
|
},
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -71,7 +71,7 @@ impl Input {
|
|||||||
let amount = if amount == 0 { None } else { Some(amount) };
|
let amount = if amount == 0 { None } else { Some(amount) };
|
||||||
Input::ToKey {
|
Input::ToKey {
|
||||||
amount,
|
amount,
|
||||||
key_offsets: read_vec(read_varint, r)?,
|
key_offsets: read_vec(read_varint, None, r)?,
|
||||||
key_image: read_torsion_free_point(r)?,
|
key_image: read_torsion_free_point(r)?,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -241,7 +241,7 @@ impl TransactionPrefix {
|
|||||||
pub fn read<R: Read>(r: &mut R, version: u64) -> io::Result<TransactionPrefix> {
|
pub fn read<R: Read>(r: &mut R, version: u64) -> io::Result<TransactionPrefix> {
|
||||||
let additional_timelock = Timelock::read(r)?;
|
let additional_timelock = Timelock::read(r)?;
|
||||||
|
|
||||||
let inputs = read_vec(|r| Input::read(r), r)?;
|
let inputs = read_vec(|r| Input::read(r), None, r)?;
|
||||||
if inputs.is_empty() {
|
if inputs.is_empty() {
|
||||||
Err(io::Error::other("transaction had no inputs"))?;
|
Err(io::Error::other("transaction had no inputs"))?;
|
||||||
}
|
}
|
||||||
@@ -250,10 +250,10 @@ impl TransactionPrefix {
|
|||||||
let mut prefix = TransactionPrefix {
|
let mut prefix = TransactionPrefix {
|
||||||
additional_timelock,
|
additional_timelock,
|
||||||
inputs,
|
inputs,
|
||||||
outputs: read_vec(|r| Output::read((!is_miner_tx) && (version == 2), r), r)?,
|
outputs: read_vec(|r| Output::read((!is_miner_tx) && (version == 2), r), None, r)?,
|
||||||
extra: vec![],
|
extra: vec![],
|
||||||
};
|
};
|
||||||
prefix.extra = read_vec(read_byte, r)?;
|
prefix.extra = read_vec(read_byte, None, r)?;
|
||||||
Ok(prefix)
|
Ok(prefix)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -181,16 +181,10 @@ impl ExtraField {
|
|||||||
size
|
size
|
||||||
}),
|
}),
|
||||||
1 => ExtraField::PublicKey(read_point(r)?),
|
1 => ExtraField::PublicKey(read_point(r)?),
|
||||||
2 => ExtraField::Nonce({
|
2 => ExtraField::Nonce(read_vec(read_byte, Some(MAX_TX_EXTRA_NONCE_SIZE), r)?),
|
||||||
let nonce = read_vec(read_byte, r)?;
|
|
||||||
if nonce.len() > MAX_TX_EXTRA_NONCE_SIZE {
|
|
||||||
Err(io::Error::other("too long nonce"))?;
|
|
||||||
}
|
|
||||||
nonce
|
|
||||||
}),
|
|
||||||
3 => ExtraField::MergeMining(read_varint(r)?, read_bytes(r)?),
|
3 => ExtraField::MergeMining(read_varint(r)?, read_bytes(r)?),
|
||||||
4 => ExtraField::PublicKeys(read_vec(read_point, r)?),
|
4 => ExtraField::PublicKeys(read_vec(read_point, None, r)?),
|
||||||
0xDE => ExtraField::MysteriousMinergate(read_vec(read_byte, r)?),
|
0xDE => ExtraField::MysteriousMinergate(read_vec(read_byte, None, r)?),
|
||||||
_ => Err(io::Error::other("unknown extra field"))?,
|
_ => Err(io::Error::other("unknown extra field"))?,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -456,7 +456,7 @@ impl SignableTransaction {
|
|||||||
/// defined serialization.
|
/// defined serialization.
|
||||||
pub fn read<R: io::Read>(r: &mut R) -> io::Result<SignableTransaction> {
|
pub fn read<R: io::Read>(r: &mut R) -> io::Result<SignableTransaction> {
|
||||||
fn read_address<R: io::Read>(r: &mut R) -> io::Result<MoneroAddress> {
|
fn read_address<R: io::Read>(r: &mut R) -> io::Result<MoneroAddress> {
|
||||||
String::from_utf8(read_vec(read_byte, r)?)
|
String::from_utf8(read_vec(read_byte, None, r)?)
|
||||||
.ok()
|
.ok()
|
||||||
.and_then(|str| MoneroAddress::from_str_with_unchecked_network(&str).ok())
|
.and_then(|str| MoneroAddress::from_str_with_unchecked_network(&str).ok())
|
||||||
.ok_or_else(|| io::Error::other("invalid address"))
|
.ok_or_else(|| io::Error::other("invalid address"))
|
||||||
@@ -484,9 +484,9 @@ impl SignableTransaction {
|
|||||||
rct_type: RctType::try_from(read_byte(r)?)
|
rct_type: RctType::try_from(read_byte(r)?)
|
||||||
.map_err(|()| io::Error::other("unsupported/invalid RctType"))?,
|
.map_err(|()| io::Error::other("unsupported/invalid RctType"))?,
|
||||||
outgoing_view_key: Zeroizing::new(read_bytes(r)?),
|
outgoing_view_key: Zeroizing::new(read_bytes(r)?),
|
||||||
inputs: read_vec(OutputWithDecoys::read, r)?,
|
inputs: read_vec(OutputWithDecoys::read, None, r)?,
|
||||||
payments: read_vec(read_payment, r)?,
|
payments: read_vec(read_payment, None, r)?,
|
||||||
data: read_vec(|r| read_vec(read_byte, r), r)?,
|
data: read_vec(|r| read_vec(read_byte, None, r), None, r)?,
|
||||||
fee_rate: FeeRate::read(r)?,
|
fee_rate: FeeRate::read(r)?,
|
||||||
};
|
};
|
||||||
match res.validate() {
|
match res.validate() {
|
||||||
|
|||||||
Reference in New Issue
Block a user