Monero: support for legacy transactions (#308)
* add mlsag
* fix last commit
* fix miner v1 txs
* fix non-miner v1 txs
* add borromean + fix mlsag
* add block hash calculations
* fix for the jokester that added unreduced scalars
to the borromean signature of
2368d846e671bf79a1f84c6d3af9f0bfe296f043f50cf17ae5e485384a53707b
* Add Borromean range proof verifying functionality
* Add MLSAG verifying functionality
* fmt & clippy :)
* update MLSAG, ss2_elements will always be 2
* Add MgSig proving
* Tidy block.rs
* Tidy Borromean, fix bugs in last commit, replace todo! with unreachable!
* Mark legacy EcdhInfo amount decryption as experimental
* Correct comments
* Write a new impl of the merkle algorithm
This one tries to be understandable.
* Only pull in things only needed for experimental when experimental
* Stop caching the Monero block hash now in processor that we have Block::hash
* Corrections for recent processor commit
* Use a clearer algorithm for the merkle
Should also be more efficient due to not shifting as often.
* Tidy Mlsag
* Remove verify_rct_* from Mlsag
Both methods were ports from Monero, overtly specific without clear
documentation. They need to be added back in, with documentation, or included
in a node which provides the necessary further context for them to be naturally
understandable.
* Move mlsag/mod.rs to mlsag.rs
This should only be a folder if it has multiple files.
* Replace EcdhInfo terminology
The ECDH encrypted the amount, yet this struct contained the encrypted amount,
not some ECDH.
Also corrects the types on the original EcdhInfo struct.
* Correct handling of commitment masks when scanning
* Route read_array through read_raw_vec
* Misc lint
* Make a proper RctType enum
No longer caches RctType in the RctSignatures as well.
* Replace Vec<Bulletproofs> with Bulletproofs
Monero uses aggregated range proofs, so there's only ever one Bulletproof. This
is enforced with a consensus rule as well, making this safe.
As for why Monero uses a vec, it's probably due to the lack of variadic typing
used. Its effectively an Option for them, yet we don't need an Option since we
do have variadic typing (enums).
* Add necessary checks to Eventuality re: supported protocols
* Fix for block 202612 and fix merkel root calculations
* MLSAG (de)serialisation fix
ss_2_elements will not always be 2 as rct type 1 transactions are not enforced to have one input
* Revert "MLSAG (de)serialisation fix"
This reverts commit 5e710e0c96658092c6ecfe5e4ea5a9c3dbee3ab3.
here it checks number of MGs == number of inputs:
https://github.com/monero-project/monero/blob/0a1eaf26f9dd6b762c2582ee12603b2a4671c735/src/cryptonote_core/tx_verification_utils.cpp#L60-59
and here it checks for RctTypeFull number of MGs == 1:
https://github.com/monero-project/monero/blob/0a1eaf26f9dd6b762c2582ee12603b2a4671c735/src/ringct/rctSigs.cpp#L1325
so number of inputs == 1
so ss_2_elements == 2
* update `MlsagAggregate` comment
* cargo update
Resolves a yanked crate
* Move location of serai-client in Cargo.toml
---------
Co-authored-by: Luke Parker <lukeparker5132@gmail.com>
2023-07-04 21:18:05 +00:00
|
|
|
use std_shims::{
|
|
|
|
|
vec::Vec,
|
|
|
|
|
io::{self, Read, Write},
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
use curve25519_dalek::scalar::Scalar;
|
|
|
|
|
#[cfg(feature = "experimental")]
|
|
|
|
|
use curve25519_dalek::edwards::EdwardsPoint;
|
|
|
|
|
|
|
|
|
|
use crate::serialize::*;
|
|
|
|
|
#[cfg(feature = "experimental")]
|
|
|
|
|
use crate::{hash_to_scalar, ringct::hash_to_point};
|
|
|
|
|
|
|
|
|
|
#[derive(Clone, PartialEq, Eq, Debug)]
|
|
|
|
|
pub struct Mlsag {
|
|
|
|
|
pub ss: Vec<[Scalar; 2]>,
|
|
|
|
|
pub cc: Scalar,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl Mlsag {
|
|
|
|
|
pub fn write<W: Write>(&self, w: &mut W) -> io::Result<()> {
|
2023-07-08 11:29:05 -04:00
|
|
|
for ss in &self.ss {
|
Monero: support for legacy transactions (#308)
* add mlsag
* fix last commit
* fix miner v1 txs
* fix non-miner v1 txs
* add borromean + fix mlsag
* add block hash calculations
* fix for the jokester that added unreduced scalars
to the borromean signature of
2368d846e671bf79a1f84c6d3af9f0bfe296f043f50cf17ae5e485384a53707b
* Add Borromean range proof verifying functionality
* Add MLSAG verifying functionality
* fmt & clippy :)
* update MLSAG, ss2_elements will always be 2
* Add MgSig proving
* Tidy block.rs
* Tidy Borromean, fix bugs in last commit, replace todo! with unreachable!
* Mark legacy EcdhInfo amount decryption as experimental
* Correct comments
* Write a new impl of the merkle algorithm
This one tries to be understandable.
* Only pull in things only needed for experimental when experimental
* Stop caching the Monero block hash now in processor that we have Block::hash
* Corrections for recent processor commit
* Use a clearer algorithm for the merkle
Should also be more efficient due to not shifting as often.
* Tidy Mlsag
* Remove verify_rct_* from Mlsag
Both methods were ports from Monero, overtly specific without clear
documentation. They need to be added back in, with documentation, or included
in a node which provides the necessary further context for them to be naturally
understandable.
* Move mlsag/mod.rs to mlsag.rs
This should only be a folder if it has multiple files.
* Replace EcdhInfo terminology
The ECDH encrypted the amount, yet this struct contained the encrypted amount,
not some ECDH.
Also corrects the types on the original EcdhInfo struct.
* Correct handling of commitment masks when scanning
* Route read_array through read_raw_vec
* Misc lint
* Make a proper RctType enum
No longer caches RctType in the RctSignatures as well.
* Replace Vec<Bulletproofs> with Bulletproofs
Monero uses aggregated range proofs, so there's only ever one Bulletproof. This
is enforced with a consensus rule as well, making this safe.
As for why Monero uses a vec, it's probably due to the lack of variadic typing
used. Its effectively an Option for them, yet we don't need an Option since we
do have variadic typing (enums).
* Add necessary checks to Eventuality re: supported protocols
* Fix for block 202612 and fix merkel root calculations
* MLSAG (de)serialisation fix
ss_2_elements will not always be 2 as rct type 1 transactions are not enforced to have one input
* Revert "MLSAG (de)serialisation fix"
This reverts commit 5e710e0c96658092c6ecfe5e4ea5a9c3dbee3ab3.
here it checks number of MGs == number of inputs:
https://github.com/monero-project/monero/blob/0a1eaf26f9dd6b762c2582ee12603b2a4671c735/src/cryptonote_core/tx_verification_utils.cpp#L60-59
and here it checks for RctTypeFull number of MGs == 1:
https://github.com/monero-project/monero/blob/0a1eaf26f9dd6b762c2582ee12603b2a4671c735/src/ringct/rctSigs.cpp#L1325
so number of inputs == 1
so ss_2_elements == 2
* update `MlsagAggregate` comment
* cargo update
Resolves a yanked crate
* Move location of serai-client in Cargo.toml
---------
Co-authored-by: Luke Parker <lukeparker5132@gmail.com>
2023-07-04 21:18:05 +00:00
|
|
|
write_raw_vec(write_scalar, ss, w)?;
|
|
|
|
|
}
|
|
|
|
|
write_scalar(&self.cc, w)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn read<R: Read>(mixins: usize, r: &mut R) -> io::Result<Mlsag> {
|
|
|
|
|
Ok(Mlsag {
|
|
|
|
|
ss: (0 .. mixins).map(|_| read_array(read_scalar, r)).collect::<Result<_, _>>()?,
|
|
|
|
|
cc: read_scalar(r)?,
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[cfg(feature = "experimental")]
|
|
|
|
|
pub fn verify(
|
|
|
|
|
&self,
|
|
|
|
|
msg: &[u8; 32],
|
|
|
|
|
ring: &[[EdwardsPoint; 2]],
|
|
|
|
|
key_image: &EdwardsPoint,
|
|
|
|
|
) -> bool {
|
|
|
|
|
if ring.is_empty() {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
let mut buf = Vec::with_capacity(6 * 32);
|
|
|
|
|
let mut ci = self.cc;
|
|
|
|
|
for (i, ring_member) in ring.iter().enumerate() {
|
|
|
|
|
buf.extend_from_slice(msg);
|
|
|
|
|
|
|
|
|
|
#[allow(non_snake_case)]
|
|
|
|
|
let L =
|
|
|
|
|
|r| EdwardsPoint::vartime_double_scalar_mul_basepoint(&ci, &ring_member[r], &self.ss[i][r]);
|
|
|
|
|
|
|
|
|
|
buf.extend_from_slice(ring_member[0].compress().as_bytes());
|
|
|
|
|
buf.extend_from_slice(L(0).compress().as_bytes());
|
|
|
|
|
|
|
|
|
|
#[allow(non_snake_case)]
|
|
|
|
|
let R = (self.ss[i][0] * hash_to_point(ring_member[0])) + (ci * key_image);
|
|
|
|
|
buf.extend_from_slice(R.compress().as_bytes());
|
|
|
|
|
|
|
|
|
|
buf.extend_from_slice(ring_member[1].compress().as_bytes());
|
|
|
|
|
buf.extend_from_slice(L(1).compress().as_bytes());
|
|
|
|
|
|
|
|
|
|
ci = hash_to_scalar(&buf);
|
|
|
|
|
buf.clear();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ci == self.cc
|
|
|
|
|
}
|
|
|
|
|
}
|