mirror of
https://github.com/serai-dex/serai.git
synced 2025-12-12 22:19:26 +00:00
* 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>
98 lines
2.8 KiB
Rust
98 lines
2.8 KiB
Rust
use core::fmt::Debug;
|
|
use std_shims::io::{self, Read, Write};
|
|
|
|
use curve25519_dalek::{traits::Identity, Scalar, EdwardsPoint};
|
|
|
|
use monero_generators::H_pow_2;
|
|
|
|
use crate::{hash_to_scalar, unreduced_scalar::UnreducedScalar, serialize::*};
|
|
|
|
/// 64 Borromean ring signatures.
|
|
///
|
|
/// 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: [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(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 {
|
|
s0.write(w)?;
|
|
}
|
|
for s1 in &self.s1 {
|
|
s1.write(w)?;
|
|
}
|
|
write_scalar(&self.ee, w)
|
|
}
|
|
|
|
fn verify(&self, keys_a: &[EdwardsPoint], keys_b: &[EdwardsPoint]) -> bool {
|
|
let mut transcript = [0; 2048];
|
|
|
|
for i in 0 .. 64 {
|
|
#[allow(non_snake_case)]
|
|
let LL = EdwardsPoint::vartime_double_scalar_mul_basepoint(
|
|
&self.ee,
|
|
&keys_a[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],
|
|
&self.s1[i].recover_monero_slide_scalar(),
|
|
);
|
|
transcript[(i * 32) .. ((i + 1) * 32)].copy_from_slice(LV.compress().as_bytes());
|
|
}
|
|
|
|
hash_to_scalar(&transcript) == self.ee
|
|
}
|
|
}
|
|
|
|
/// A range proof premised on Borromean ring signatures.
|
|
#[derive(Clone, PartialEq, Eq, Debug)]
|
|
pub struct BorromeanRange {
|
|
pub sigs: BorromeanSignatures,
|
|
pub bit_commitments: [EdwardsPoint; 64],
|
|
}
|
|
|
|
impl BorromeanRange {
|
|
pub fn read<R: Read>(r: &mut R) -> io::Result<BorromeanRange> {
|
|
Ok(BorromeanRange {
|
|
sigs: BorromeanSignatures::read(r)?,
|
|
bit_commitments: read_array(read_point, r)?,
|
|
})
|
|
}
|
|
pub fn write<W: Write>(&self, w: &mut W) -> io::Result<()> {
|
|
self.sigs.write(w)?;
|
|
write_raw_vec(write_point, &self.bit_commitments, w)
|
|
}
|
|
|
|
pub fn verify(&self, commitment: &EdwardsPoint) -> bool {
|
|
if &self.bit_commitments.iter().sum::<EdwardsPoint>() != commitment {
|
|
return false;
|
|
}
|
|
|
|
#[allow(non_snake_case)]
|
|
let H_pow_2 = H_pow_2();
|
|
let mut commitments_sub_one = [EdwardsPoint::identity(); 64];
|
|
for i in 0 .. 64 {
|
|
commitments_sub_one[i] = self.bit_commitments[i] - H_pow_2[i];
|
|
}
|
|
|
|
self.sigs.verify(&self.bit_commitments, &commitments_sub_one)
|
|
}
|
|
}
|