mirror of
https://github.com/serai-dex/serai.git
synced 2025-12-11 13:39:25 +00:00
Add Borromean range proof verifying functionality
This commit is contained in:
@@ -9,6 +9,7 @@ use lazy_static::lazy_static;
|
|||||||
use sha3::{Digest, Keccak256};
|
use sha3::{Digest, Keccak256};
|
||||||
|
|
||||||
use curve25519_dalek::edwards::{EdwardsPoint as DalekPoint, CompressedEdwardsY};
|
use curve25519_dalek::edwards::{EdwardsPoint as DalekPoint, CompressedEdwardsY};
|
||||||
|
use curve25519_dalek::scalar::Scalar;
|
||||||
|
|
||||||
use group::{Group, GroupEncoding};
|
use group::{Group, GroupEncoding};
|
||||||
use dalek_ff_group::EdwardsPoint;
|
use dalek_ff_group::EdwardsPoint;
|
||||||
@@ -30,6 +31,20 @@ lazy_static! {
|
|||||||
.decompress()
|
.decompress()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.mul_by_cofactor();
|
.mul_by_cofactor();
|
||||||
|
|
||||||
|
/// Monero's `H` generator multiplied 2^i for each index, i.e. H, 2H, 4H, 8H, ...
|
||||||
|
/// used in old range proofs.
|
||||||
|
/// https://github.com/monero-project/monero/blob/94e67bf96bbc010241f29ada6abc89f49a81759c/src/ringct/rctTypes.h#L628
|
||||||
|
pub static ref H2: [DalekPoint; 64] = generate_H2();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(non_snake_case)]
|
||||||
|
fn generate_H2() -> [DalekPoint; 64] {
|
||||||
|
let mut temp = Vec::with_capacity(64);
|
||||||
|
for i in 0..64 {
|
||||||
|
temp.push(Scalar::from(2_u128.pow(i)) * *H)
|
||||||
|
}
|
||||||
|
temp.try_into().unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
const MAX_M: usize = 16;
|
const MAX_M: usize = 16;
|
||||||
|
|||||||
@@ -3,18 +3,22 @@
|
|||||||
use std::fmt::Debug;
|
use std::fmt::Debug;
|
||||||
use std::io::{self, Read, Write};
|
use std::io::{self, Read, Write};
|
||||||
|
|
||||||
use curve25519_dalek::edwards::EdwardsPoint;
|
use curve25519_dalek::edwards::{CompressedEdwardsY, EdwardsPoint};
|
||||||
use curve25519_dalek::scalar::Scalar;
|
use curve25519_dalek::scalar::Scalar;
|
||||||
|
use curve25519_dalek::traits::Identity;
|
||||||
|
|
||||||
|
use monero_generators::H2;
|
||||||
|
|
||||||
|
use crate::hash_to_scalar;
|
||||||
use crate::serialize::*;
|
use crate::serialize::*;
|
||||||
|
|
||||||
fn read_64_array<R: Read, T: Debug, F: Fn(&mut R) -> io::Result<T>>(
|
/// A Borromean signature.
|
||||||
f: F,
|
///
|
||||||
r: &mut R,
|
/// Note: This type keeps the data as raw bytes as Monero has
|
||||||
) -> io::Result<[T; 64]> {
|
/// some transactions with unreduced scalars in this field, we
|
||||||
(0 .. 64).map(|_| f(r)).collect::<io::Result<Vec<T>>>().map(|vec| vec.try_into().unwrap())
|
/// could use `from_bytes_mod_order` but then we would not be able
|
||||||
}
|
/// to encode this back into it's original form.
|
||||||
|
///
|
||||||
#[derive(Clone, PartialEq, Eq, Debug)]
|
#[derive(Clone, PartialEq, Eq, Debug)]
|
||||||
pub struct BorroSig {
|
pub struct BorroSig {
|
||||||
pub s0: [[u8; 32]; 64],
|
pub s0: [[u8; 32]; 64],
|
||||||
@@ -55,4 +59,50 @@ impl RangeSig {
|
|||||||
self.asig.write(w)?;
|
self.asig.write(w)?;
|
||||||
write_raw_vec(write_point, &self.Ci, w)
|
write_raw_vec(write_point, &self.Ci, w)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn verify(&self, commitment: &EdwardsPoint) -> bool {
|
||||||
|
let mut P1 = Vec::with_capacity(64);
|
||||||
|
let mut P2 = Vec::with_capacity(64);
|
||||||
|
let mut bbs0 = Vec::with_capacity(64);
|
||||||
|
let mut bbs1 = Vec::with_capacity(64);
|
||||||
|
|
||||||
|
let bbee = Scalar::from_bytes_mod_order(self.asig.ee);
|
||||||
|
|
||||||
|
let mut C_temp = EdwardsPoint::identity();
|
||||||
|
|
||||||
|
for i in 0..64 {
|
||||||
|
bbs0.push(Scalar::from_bytes_mod_order(self.asig.s0[i]));
|
||||||
|
bbs1.push(Scalar::from_bytes_mod_order(self.asig.s1[i]));
|
||||||
|
|
||||||
|
P1.push(self.Ci[i]);
|
||||||
|
P2.push(P1[i] - H2[i]);
|
||||||
|
|
||||||
|
C_temp += P1[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
if &C_temp != commitment {
|
||||||
|
false
|
||||||
|
} else {
|
||||||
|
verify_borromean(P1, P2, bbee, bbs0, bbs1)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn verify_borromean(P1: Vec<EdwardsPoint>, P2: Vec<EdwardsPoint>, bbee: Scalar, bbs0: Vec<Scalar>, bbs1: Vec<Scalar>) -> bool {
|
||||||
|
let mut LV: Vec<u8> = Vec::with_capacity(2048);
|
||||||
|
for i in 0..64 {
|
||||||
|
let LL = EdwardsPoint::vartime_double_scalar_mul_basepoint(&bbee, &P1[i], &bbs0[i]);
|
||||||
|
let chash = hash_to_scalar(LL.compress().as_bytes());
|
||||||
|
let LV_temp = EdwardsPoint::vartime_double_scalar_mul_basepoint(&chash, &P2[i], &bbs1[i]);
|
||||||
|
LV.extend(LV_temp.compress().as_bytes());
|
||||||
|
}
|
||||||
|
let eecomp = hash_to_scalar(&LV);
|
||||||
|
|
||||||
|
if !(eecomp == bbee) {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
use std::fmt::Debug;
|
||||||
use std::io::{self, Read, Write};
|
use std::io::{self, Read, Write};
|
||||||
|
|
||||||
use curve25519_dalek::{
|
use curve25519_dalek::{
|
||||||
@@ -143,3 +144,10 @@ pub(crate) fn read_vec<R: Read, T, F: Fn(&mut R) -> io::Result<T>>(
|
|||||||
) -> io::Result<Vec<T>> {
|
) -> io::Result<Vec<T>> {
|
||||||
read_raw_vec(f, read_varint(r)?.try_into().unwrap(), r)
|
read_raw_vec(f, read_varint(r)?.try_into().unwrap(), r)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) fn read_64_array<R: Read, T: Debug, F: Fn(&mut R) -> io::Result<T>>(
|
||||||
|
f: F,
|
||||||
|
r: &mut R,
|
||||||
|
) -> io::Result<[T; 64]> {
|
||||||
|
(0 .. 64).map(|_| f(r)).collect::<io::Result<Vec<T>>>().map(|vec| vec.try_into().unwrap())
|
||||||
|
}
|
||||||
|
|||||||
@@ -201,6 +201,10 @@ impl TransactionPrefix {
|
|||||||
prefix.extra = read_vec(read_byte, r)?;
|
prefix.extra = read_vec(read_byte, r)?;
|
||||||
Ok(prefix)
|
Ok(prefix)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn hash(&self) -> [u8; 32] {
|
||||||
|
hash(&self.serialize())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Monero transaction. For version 1, rct_signatures still contains an accurate fee value.
|
/// Monero transaction. For version 1, rct_signatures still contains an accurate fee value.
|
||||||
@@ -254,18 +258,17 @@ impl Transaction {
|
|||||||
};
|
};
|
||||||
|
|
||||||
if prefix.version == 1 {
|
if prefix.version == 1 {
|
||||||
let read_sig =
|
|
||||||
|r: &mut R| -> io::Result<(Scalar, Scalar)> { Ok((read_scalar(r)?, read_scalar(r)?)) };
|
|
||||||
signatures = prefix
|
signatures = prefix
|
||||||
.inputs
|
.inputs
|
||||||
.iter()
|
.iter()
|
||||||
.filter_map(|input| match input {
|
.filter_map(|input| match input {
|
||||||
Input::ToKey { key_offsets, .. } => {
|
Input::ToKey { key_offsets, .. } => {
|
||||||
Some(key_offsets.iter().map(|_| (read_sig(r))).collect::<Result<Vec<(_, _)>, _>>())
|
Some(key_offsets.iter().map(|_| Ok((read_scalar(r)?, read_scalar(r)?))).collect::<Result<_, io::Error>>())
|
||||||
}
|
}
|
||||||
_ => None,
|
_ => None,
|
||||||
})
|
})
|
||||||
.collect::<Result<Vec<Vec<(Scalar, Scalar)>>, _>>()?;
|
.collect::<Result<_, _>>()?;
|
||||||
|
|
||||||
rct_signatures.base.fee = prefix
|
rct_signatures.base.fee = prefix
|
||||||
.inputs
|
.inputs
|
||||||
@@ -304,9 +307,7 @@ impl Transaction {
|
|||||||
} else {
|
} else {
|
||||||
let mut hashes = Vec::with_capacity(96);
|
let mut hashes = Vec::with_capacity(96);
|
||||||
|
|
||||||
self.prefix.write(&mut buf).unwrap();
|
hashes.extend(self.prefix.hash());
|
||||||
hashes.extend(hash(&buf));
|
|
||||||
buf.clear();
|
|
||||||
|
|
||||||
self.rct_signatures.base.write(&mut buf, self.rct_signatures.prunable.rct_type()).unwrap();
|
self.rct_signatures.base.write(&mut buf, self.rct_signatures.prunable.rct_type()).unwrap();
|
||||||
hashes.extend(hash(&buf));
|
hashes.extend(hash(&buf));
|
||||||
@@ -330,9 +331,7 @@ impl Transaction {
|
|||||||
let mut buf = Vec::with_capacity(2048);
|
let mut buf = Vec::with_capacity(2048);
|
||||||
let mut sig_hash = Vec::with_capacity(96);
|
let mut sig_hash = Vec::with_capacity(96);
|
||||||
|
|
||||||
self.prefix.write(&mut buf).unwrap();
|
sig_hash.extend(self.prefix.hash());
|
||||||
sig_hash.extend(hash(&buf));
|
|
||||||
buf.clear();
|
|
||||||
|
|
||||||
self.rct_signatures.base.write(&mut buf, self.rct_signatures.prunable.rct_type()).unwrap();
|
self.rct_signatures.base.write(&mut buf, self.rct_signatures.prunable.rct_type()).unwrap();
|
||||||
sig_hash.extend(hash(&buf));
|
sig_hash.extend(hash(&buf));
|
||||||
|
|||||||
Reference in New Issue
Block a user