Monero: add more legacy verify functions (#383)

* Add v1 ring sig verifying

* allow calculating signature hash for v1 txs

* add unreduced scalar type with recovery

I have added this type for borromen sigs, the ee field can be a normal
scalar as in the verify function the ee
field is checked against a reduced scalar mean for it to verify as
correct ee must be reduced

* change block major/ minor versions to u8

this matches Monero

I have also changed a couple varint functions to accept the `VarInt`
trait

* expose `serialize_hashable` on `Block`

* add back MLSAG verifying functions

I still need to revert the commit removing support for >1 input MLSAG FULL

This adds a new rct type to separate Full and simple rct

* add back support for multiple inputs for RCT FULL

* comment `non_adjacent_form` function

also added `#[allow(clippy::needless_range_loop)]` around a loop as without a re-write satisfying clippy without it will make the function worse.

* Improve Mlsag verifying API

* fix rebase errors

* revert the changes on `reserialize_chain`
plus other misc changes

* fix no-std

* Reduce the amount of rpc calls needed for `get_block_by_number`.
This function was causing me problems, every now and then a node would return a block with a different number than requested.

* change `serialize_hashable` to give the POW hashing blob.

Monero calculates the POW hash and the block hash using *slightly* different blobs :/

* make ring_signatures public and add length check when verifying.

* Misc improvements and bug fixes

---------

Co-authored-by: Luke Parker <lukeparker5132@gmail.com>
This commit is contained in:
Boog900
2023-11-12 15:18:18 +00:00
committed by GitHub
parent 54f1929078
commit 995734c960
19 changed files with 537 additions and 159 deletions

View File

@@ -1,73 +1,63 @@
use core::fmt::Debug;
use std_shims::io::{self, Read, Write};
use curve25519_dalek::edwards::EdwardsPoint;
#[cfg(feature = "experimental")]
use curve25519_dalek::{traits::Identity, scalar::Scalar};
use curve25519_dalek::{traits::Identity, Scalar, EdwardsPoint};
#[cfg(feature = "experimental")]
use monero_generators::H_pow_2;
#[cfg(feature = "experimental")]
use crate::hash_to_scalar;
use crate::serialize::*;
use crate::{hash_to_scalar, unreduced_scalar::UnreducedScalar, serialize::*};
/// 64 Borromean ring signatures.
///
/// This type keeps the data as raw bytes as Monero has some transactions with unreduced scalars in
/// this field. While we could use `from_bytes_mod_order`, we'd then not be able to encode this
/// back into it's original form.
///
/// Those scalars also have a custom reduction algorithm...
/// s0 and s1 are stored as `UnreducedScalar`s due to Monero not requiring they were reduced.
/// `UnreducedScalar` preserves their original byte encoding and implements a custom reduction
/// algorithm which was in use.
#[derive(Clone, PartialEq, Eq, Debug)]
pub struct BorromeanSignatures {
pub s0: [[u8; 32]; 64],
pub s1: [[u8; 32]; 64],
pub ee: [u8; 32],
pub s0: [UnreducedScalar; 64],
pub s1: [UnreducedScalar; 64],
pub ee: Scalar,
}
impl BorromeanSignatures {
pub fn read<R: Read>(r: &mut R) -> io::Result<BorromeanSignatures> {
Ok(BorromeanSignatures {
s0: read_array(read_bytes, r)?,
s1: read_array(read_bytes, r)?,
ee: read_bytes(r)?,
s0: read_array(UnreducedScalar::read, r)?,
s1: read_array(UnreducedScalar::read, r)?,
ee: read_scalar(r)?,
})
}
pub fn write<W: Write>(&self, w: &mut W) -> io::Result<()> {
for s0 in &self.s0 {
w.write_all(s0)?;
s0.write(w)?;
}
for s1 in &self.s1 {
w.write_all(s1)?;
s1.write(w)?;
}
w.write_all(&self.ee)
write_scalar(&self.ee, w)
}
#[cfg(feature = "experimental")]
fn verify(&self, keys_a: &[EdwardsPoint], keys_b: &[EdwardsPoint]) -> bool {
let mut transcript = [0; 2048];
for i in 0 .. 64 {
// TODO: These aren't the correct reduction
// TODO: Can either of these be tightened?
#[allow(non_snake_case)]
let LL = EdwardsPoint::vartime_double_scalar_mul_basepoint(
&Scalar::from_bytes_mod_order(self.ee),
&self.ee,
&keys_a[i],
&Scalar::from_bytes_mod_order(self.s0[i]),
&self.s0[i].recover_monero_slide_scalar(),
);
#[allow(non_snake_case)]
let LV = EdwardsPoint::vartime_double_scalar_mul_basepoint(
&hash_to_scalar(LL.compress().as_bytes()),
&keys_b[i],
&Scalar::from_bytes_mod_order(self.s1[i]),
&self.s1[i].recover_monero_slide_scalar(),
);
transcript[i .. ((i + 1) * 32)].copy_from_slice(LV.compress().as_bytes());
transcript[(i * 32) .. ((i + 1) * 32)].copy_from_slice(LV.compress().as_bytes());
}
// TODO: This isn't the correct reduction
// TODO: Can this be tightened to from_canonical_bytes?
hash_to_scalar(&transcript) == Scalar::from_bytes_mod_order(self.ee)
hash_to_scalar(&transcript) == self.ee
}
}
@@ -90,7 +80,6 @@ impl BorromeanRange {
write_raw_vec(write_point, &self.bit_commitments, w)
}
#[cfg(feature = "experimental")]
pub fn verify(&self, commitment: &EdwardsPoint) -> bool {
if &self.bit_commitments.iter().sum::<EdwardsPoint>() != commitment {
return false;