mirror of
https://github.com/serai-dex/serai.git
synced 2025-12-12 14:09:25 +00:00
Bulletproofs+ (#70)
* Initial stab at Bulletproofs+ Does move around the existing Bulletproofs code, does still work as expected. * Make the Clsag RCTPrunable type work with BP and BP+ * Initial set of BP+ bug fixes * Further bug fixes * Remove RING_LEN as a constant * Monero v16 TX support Doesn't implement view tags, nor going back to v14, nor the updated BP clawback logic. * Support v14 and v16 at the same time
This commit is contained in:
@@ -7,12 +7,16 @@ use rand_core::{RngCore, CryptoRng};
|
||||
use curve25519_dalek::{scalar::Scalar as DalekScalar, edwards::EdwardsPoint as DalekPoint};
|
||||
|
||||
use group::{ff::Field, Group};
|
||||
use dalek_ff_group::{Scalar, EdwardsPoint};
|
||||
use dalek_ff_group::{ED25519_BASEPOINT_POINT, Scalar, EdwardsPoint};
|
||||
|
||||
use multiexp::multiexp;
|
||||
use multiexp::multiexp as const_multiexp;
|
||||
|
||||
fn prove_multiexp(pairs: &[(Scalar, EdwardsPoint)]) -> EdwardsPoint {
|
||||
const_multiexp(pairs) * *INV_EIGHT
|
||||
}
|
||||
|
||||
use crate::{
|
||||
H as DALEK_H, Commitment, random_scalar as dalek_random, hash, hash_to_scalar as dalek_hash,
|
||||
H as DALEK_H, Commitment, hash, hash_to_scalar as dalek_hash,
|
||||
ringct::{hash_to_point::raw_hash_to_point, bulletproofs::scalar_vector::*},
|
||||
serialize::write_varint,
|
||||
};
|
||||
@@ -23,10 +27,6 @@ lazy_static! {
|
||||
static ref H: EdwardsPoint = EdwardsPoint(*DALEK_H);
|
||||
}
|
||||
|
||||
fn random_scalar<R: RngCore + CryptoRng>(rng: &mut R) -> Scalar {
|
||||
Scalar(dalek_random(rng))
|
||||
}
|
||||
|
||||
fn hash_to_scalar(data: &[u8]) -> Scalar {
|
||||
Scalar(dalek_hash(data))
|
||||
}
|
||||
@@ -36,12 +36,6 @@ pub(crate) const MAX_M: usize = 16;
|
||||
const N: usize = 64;
|
||||
const MAX_MN: usize = MAX_M * N;
|
||||
|
||||
lazy_static! {
|
||||
static ref ONE_N: ScalarVector = ScalarVector(vec![Scalar::one(); N]);
|
||||
static ref TWO_N: ScalarVector = ScalarVector::powers(Scalar::from(2u8), N);
|
||||
static ref IP12: Scalar = inner_product(&ONE_N, &TWO_N);
|
||||
}
|
||||
|
||||
struct Generators {
|
||||
G: Vec<EdwardsPoint>,
|
||||
H: Vec<EdwardsPoint>,
|
||||
@@ -64,6 +58,7 @@ fn generators_core(prefix: &'static [u8]) -> Generators {
|
||||
res
|
||||
}
|
||||
|
||||
// TODO: Have this take in other, multiplied by G, and do a single multiexp
|
||||
fn vector_exponent(generators: &Generators, a: &ScalarVector, b: &ScalarVector) -> EdwardsPoint {
|
||||
debug_assert_eq!(a.len(), b.len());
|
||||
(a * &generators.G[.. a.len()]) + (b * &generators.H[.. b.len()])
|
||||
@@ -96,7 +91,7 @@ fn MN(outputs: usize) -> (usize, usize, usize) {
|
||||
fn bit_decompose(commitments: &[Commitment]) -> (ScalarVector, ScalarVector) {
|
||||
let (_, M, MN) = MN(commitments.len());
|
||||
|
||||
let sv = ScalarVector(commitments.iter().cloned().map(|c| Scalar::from(c.amount)).collect());
|
||||
let sv = commitments.iter().map(|c| Scalar::from(c.amount)).collect::<Vec<_>>();
|
||||
let mut aL = ScalarVector::new(MN);
|
||||
let mut aR = ScalarVector::new(MN);
|
||||
|
||||
@@ -118,46 +113,63 @@ fn hash_commitments(commitments: &[Commitment]) -> Scalar {
|
||||
hash_to_scalar(&V.iter().flat_map(|V| V.compress().to_bytes()).collect::<Vec<_>>())
|
||||
}
|
||||
|
||||
fn alpha<R: RngCore + CryptoRng>(
|
||||
fn alpha_rho<R: RngCore + CryptoRng>(
|
||||
rng: &mut R,
|
||||
generators: &Generators,
|
||||
aL: &ScalarVector,
|
||||
aR: &ScalarVector,
|
||||
) -> (Scalar, EdwardsPoint) {
|
||||
let alpha = random_scalar(&mut *rng);
|
||||
(alpha, (vector_exponent(generators, aL, aR) + (EdwardsPoint::generator() * alpha)) * *INV_EIGHT)
|
||||
let ar = Scalar::random(rng);
|
||||
(ar, (vector_exponent(generators, aL, aR) + (EdwardsPoint::generator() * ar)) * *INV_EIGHT)
|
||||
}
|
||||
|
||||
fn LR_statements(
|
||||
a: &ScalarVector,
|
||||
G_i: &[EdwardsPoint],
|
||||
b: &ScalarVector,
|
||||
H_i: &[EdwardsPoint],
|
||||
cL: Scalar,
|
||||
U: EdwardsPoint,
|
||||
) -> Vec<(Scalar, EdwardsPoint)> {
|
||||
let mut res = a
|
||||
.0
|
||||
.iter()
|
||||
.cloned()
|
||||
.zip(G_i.iter().cloned())
|
||||
.chain(b.0.iter().cloned().zip(H_i.iter().cloned()))
|
||||
.collect::<Vec<_>>();
|
||||
res.push((cL, U));
|
||||
res
|
||||
}
|
||||
|
||||
lazy_static! {
|
||||
static ref TWO_N: ScalarVector = ScalarVector::powers(Scalar::from(2u8), N);
|
||||
}
|
||||
|
||||
// Bulletproofs-specific
|
||||
lazy_static! {
|
||||
static ref GENERATORS: Generators = generators_core(b"bulletproof");
|
||||
static ref ONE_N: ScalarVector = ScalarVector(vec![Scalar::one(); N]);
|
||||
static ref IP12: Scalar = inner_product(&ONE_N, &TWO_N);
|
||||
}
|
||||
|
||||
// Bulletproofs+-specific
|
||||
lazy_static! {
|
||||
static ref GENERATORS_PLUS: Generators = generators_core(b"bulletproof_plus");
|
||||
static ref TRANSCRIPT_PLUS: EdwardsPoint =
|
||||
EdwardsPoint(raw_hash_to_point(hash(b"bulletproof_plus_transcript")));
|
||||
static ref TRANSCRIPT_PLUS: [u8; 32] =
|
||||
EdwardsPoint(raw_hash_to_point(hash(b"bulletproof_plus_transcript"))).compress().to_bytes();
|
||||
}
|
||||
|
||||
fn even_powers_sum(x: Scalar, pow: usize) -> Scalar {
|
||||
debug_assert!(pow != 0);
|
||||
// Verify pow is a power of two
|
||||
debug_assert_eq!(((pow - 1) & pow), 0);
|
||||
|
||||
let xsq = x * x;
|
||||
let mut res = xsq;
|
||||
|
||||
let mut prev = 2;
|
||||
while prev < pow {
|
||||
res += res * xsq;
|
||||
prev += 2;
|
||||
}
|
||||
|
||||
res
|
||||
// TRANSCRIPT_PLUS isn't a Scalar, so we need this alternative for the first hash
|
||||
fn hash_plus(mash: &[[u8; 32]]) -> Scalar {
|
||||
let slice =
|
||||
&[&*TRANSCRIPT_PLUS as &[u8], mash.iter().cloned().flatten().collect::<Vec<_>>().as_ref()]
|
||||
.concat();
|
||||
hash_to_scalar(slice)
|
||||
}
|
||||
|
||||
// Types for all Bulletproofs
|
||||
#[allow(clippy::large_enum_variant)]
|
||||
#[derive(Clone, PartialEq, Eq, Debug)]
|
||||
pub enum Bulletproofs {
|
||||
Original {
|
||||
@@ -173,6 +185,17 @@ pub enum Bulletproofs {
|
||||
b: DalekScalar,
|
||||
t: DalekScalar,
|
||||
},
|
||||
|
||||
Plus {
|
||||
A: DalekPoint,
|
||||
A1: DalekPoint,
|
||||
B: DalekPoint,
|
||||
r1: DalekScalar,
|
||||
s1: DalekScalar,
|
||||
d1: DalekScalar,
|
||||
L: Vec<DalekPoint>,
|
||||
R: Vec<DalekPoint>,
|
||||
},
|
||||
}
|
||||
|
||||
pub(crate) fn prove<R: RngCore + CryptoRng>(
|
||||
@@ -183,12 +206,11 @@ pub(crate) fn prove<R: RngCore + CryptoRng>(
|
||||
|
||||
let (aL, aR) = bit_decompose(commitments);
|
||||
let mut cache = hash_commitments(commitments);
|
||||
let (alpha, A) = alpha(rng, &GENERATORS, &aL, &aR);
|
||||
let (alpha, A) = alpha_rho(&mut *rng, &GENERATORS, &aL, &aR);
|
||||
|
||||
let (sL, sR) =
|
||||
ScalarVector((0 .. (MN * 2)).map(|_| random_scalar(&mut *rng)).collect::<Vec<_>>()).split();
|
||||
let rho = random_scalar(&mut *rng);
|
||||
let S = (vector_exponent(&GENERATORS, &sL, &sR) + (EdwardsPoint::generator() * rho)) * *INV_EIGHT;
|
||||
ScalarVector((0 .. (MN * 2)).map(|_| Scalar::random(&mut *rng)).collect::<Vec<_>>()).split();
|
||||
let (rho, S) = alpha_rho(&mut *rng, &GENERATORS, &sL, &sR);
|
||||
|
||||
let y = hash_cache(&mut cache, &[A.compress().to_bytes(), S.compress().to_bytes()]);
|
||||
let mut cache = hash_to_scalar(&y.to_bytes());
|
||||
@@ -212,19 +234,18 @@ pub(crate) fn prove<R: RngCore + CryptoRng>(
|
||||
let t1 = inner_product(&l0, &r1) + inner_product(&l1, &r0);
|
||||
let t2 = inner_product(&l1, &r1);
|
||||
|
||||
let tau1 = random_scalar(&mut *rng);
|
||||
let tau2 = random_scalar(&mut *rng);
|
||||
let tau1 = Scalar::random(&mut *rng);
|
||||
let tau2 = Scalar::random(rng);
|
||||
|
||||
let T1 = multiexp(&[(t1, *H), (tau1, EdwardsPoint::generator())]) * *INV_EIGHT;
|
||||
let T2 = multiexp(&[(t2, *H), (tau2, EdwardsPoint::generator())]) * *INV_EIGHT;
|
||||
let T1 = prove_multiexp(&[(t1, *H), (tau1, EdwardsPoint::generator())]);
|
||||
let T2 = prove_multiexp(&[(t2, *H), (tau2, EdwardsPoint::generator())]);
|
||||
|
||||
let x =
|
||||
hash_cache(&mut cache, &[z.to_bytes(), T1.compress().to_bytes(), T2.compress().to_bytes()]);
|
||||
|
||||
let gamma = ScalarVector(commitments.iter().cloned().map(|c| Scalar(c.mask)).collect());
|
||||
let mut taux = (tau2 * (x * x)) + (tau1 * x);
|
||||
for i in 1 ..= gamma.len() {
|
||||
taux += zpow[i + 1] * gamma[i - 1];
|
||||
for (i, gamma) in commitments.iter().map(|c| Scalar(c.mask)).enumerate() {
|
||||
taux += zpow[i + 2] * gamma;
|
||||
}
|
||||
let mu = (x * rho) + alpha;
|
||||
|
||||
@@ -259,26 +280,8 @@ pub(crate) fn prove<R: RngCore + CryptoRng>(
|
||||
let (G_L, G_R) = G_proof.split_at(aL.len());
|
||||
let (H_L, H_R) = H_proof.split_at(aL.len());
|
||||
|
||||
let mut L_i_s = aL
|
||||
.0
|
||||
.iter()
|
||||
.cloned()
|
||||
.zip(G_R.iter().cloned())
|
||||
.chain(bR.0.iter().cloned().zip(H_L.iter().cloned()))
|
||||
.collect::<Vec<_>>();
|
||||
L_i_s.push((cL, U));
|
||||
let L_i = multiexp(&L_i_s) * *INV_EIGHT;
|
||||
|
||||
let mut R_i_s = aR
|
||||
.0
|
||||
.iter()
|
||||
.cloned()
|
||||
.zip(G_L.iter().cloned())
|
||||
.chain(bL.0.iter().cloned().zip(H_R.iter().cloned()))
|
||||
.collect::<Vec<_>>();
|
||||
R_i_s.push((cR, U));
|
||||
let R_i = multiexp(&R_i_s) * *INV_EIGHT;
|
||||
|
||||
let L_i = prove_multiexp(&LR_statements(&aL, G_R, &bR, H_L, cL, U));
|
||||
let R_i = prove_multiexp(&LR_statements(&aR, G_L, &bL, H_R, cR, U));
|
||||
L.push(L_i);
|
||||
R.push(R_i);
|
||||
|
||||
@@ -308,3 +311,113 @@ pub(crate) fn prove<R: RngCore + CryptoRng>(
|
||||
t: *t,
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn prove_plus<R: RngCore + CryptoRng>(
|
||||
rng: &mut R,
|
||||
commitments: &[Commitment],
|
||||
) -> Bulletproofs {
|
||||
let (logMN, M, MN) = MN(commitments.len());
|
||||
|
||||
let (aL, aR) = bit_decompose(commitments);
|
||||
let mut cache = hash_plus(&[hash_commitments(commitments).to_bytes()]);
|
||||
let (mut alpha1, A) = alpha_rho(&mut *rng, &GENERATORS_PLUS, &aL, &aR);
|
||||
|
||||
let y = hash_cache(&mut cache, &[A.compress().to_bytes()]);
|
||||
let mut cache = hash_to_scalar(&y.to_bytes());
|
||||
let z = cache;
|
||||
|
||||
let zpow = ScalarVector::even_powers(z, 2 * M);
|
||||
// d[j*N+i] = z**(2*(j+1)) * 2**i
|
||||
let mut d = vec![Scalar::zero(); MN];
|
||||
for j in 0 .. M {
|
||||
for i in 0 .. N {
|
||||
d[(j * N) + i] = zpow[j] * TWO_N[i];
|
||||
}
|
||||
}
|
||||
|
||||
let aL1 = aL - z;
|
||||
|
||||
let ypow = ScalarVector::powers(y, MN + 2);
|
||||
let mut y_for_d = ScalarVector(ypow.0[1 ..= MN].to_vec());
|
||||
y_for_d.0.reverse();
|
||||
let aR1 = (aR + z) + (y_for_d * ScalarVector(d));
|
||||
|
||||
for (j, gamma) in commitments.iter().map(|c| Scalar(c.mask)).enumerate() {
|
||||
alpha1 += zpow[j] * ypow[MN + 1] * gamma;
|
||||
}
|
||||
|
||||
let mut a = aL1;
|
||||
let mut b = aR1;
|
||||
|
||||
let yinv = y.invert().unwrap();
|
||||
let yinvpow = ScalarVector::powers(yinv, MN);
|
||||
|
||||
let mut G_proof = GENERATORS_PLUS.G[.. a.len()].to_vec();
|
||||
let mut H_proof = GENERATORS_PLUS.H[.. a.len()].to_vec();
|
||||
|
||||
let mut L = Vec::with_capacity(logMN);
|
||||
let mut R = Vec::with_capacity(logMN);
|
||||
|
||||
while a.len() != 1 {
|
||||
let (aL, aR) = a.split();
|
||||
let (bL, bR) = b.split();
|
||||
|
||||
let cL = weighted_inner_product(&aL, &bR, y);
|
||||
let cR = weighted_inner_product(&(&aR * ypow[aR.len()]), &bL, y);
|
||||
|
||||
let (dL, dR) = (Scalar::random(&mut *rng), Scalar::random(&mut *rng));
|
||||
|
||||
let (G_L, G_R) = G_proof.split_at(aL.len());
|
||||
let (H_L, H_R) = H_proof.split_at(aL.len());
|
||||
|
||||
let mut L_i = LR_statements(&(&aL * yinvpow[aL.len()]), G_R, &bR, H_L, cL, *H);
|
||||
L_i.push((dL, ED25519_BASEPOINT_POINT));
|
||||
let L_i = prove_multiexp(&L_i);
|
||||
L.push(L_i);
|
||||
|
||||
let mut R_i = LR_statements(&(&aR * ypow[aR.len()]), G_L, &bL, H_R, cR, *H);
|
||||
R_i.push((dR, ED25519_BASEPOINT_POINT));
|
||||
let R_i = prove_multiexp(&R_i);
|
||||
R.push(R_i);
|
||||
|
||||
let w = hash_cache(&mut cache, &[L_i.compress().to_bytes(), R_i.compress().to_bytes()]);
|
||||
let winv = w.invert().unwrap();
|
||||
|
||||
G_proof = hadamard_fold(G_L, G_R, winv, w * yinvpow[aL.len()]);
|
||||
H_proof = hadamard_fold(H_L, H_R, w, winv);
|
||||
|
||||
a = (&aL * w) + (aR * (winv * ypow[aL.len()]));
|
||||
b = (bL * winv) + (bR * w);
|
||||
|
||||
alpha1 += (dL * (w * w)) + (dR * (winv * winv));
|
||||
}
|
||||
|
||||
let r = Scalar::random(&mut *rng);
|
||||
let s = Scalar::random(&mut *rng);
|
||||
let d = Scalar::random(&mut *rng);
|
||||
let eta = Scalar::random(rng);
|
||||
|
||||
let A1 = prove_multiexp(&[
|
||||
(r, G_proof[0]),
|
||||
(s, H_proof[0]),
|
||||
(d, ED25519_BASEPOINT_POINT),
|
||||
((r * y * b[0]) + (s * y * a[0]), *H),
|
||||
]);
|
||||
let B = prove_multiexp(&[(r * y * s, *H), (eta, ED25519_BASEPOINT_POINT)]);
|
||||
let e = hash_cache(&mut cache, &[A1.compress().to_bytes(), B.compress().to_bytes()]);
|
||||
|
||||
let r1 = (a[0] * e) + r;
|
||||
let s1 = (b[0] * e) + s;
|
||||
let d1 = ((d * e) + eta) + (alpha1 * (e * e));
|
||||
|
||||
Bulletproofs::Plus {
|
||||
A: *A,
|
||||
A1: *A1,
|
||||
B: *B,
|
||||
r1: *r1,
|
||||
s1: *s1,
|
||||
d1: *d1,
|
||||
L: L.drain(..).map(|L| *L).collect(),
|
||||
R: R.drain(..).map(|R| *R).collect(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,11 +10,12 @@ pub(crate) mod scalar_vector;
|
||||
|
||||
mod core;
|
||||
pub(crate) use self::core::Bulletproofs;
|
||||
use self::core::{MAX_M, prove};
|
||||
use self::core::{MAX_M, prove, prove_plus};
|
||||
|
||||
pub(crate) const MAX_OUTPUTS: usize = MAX_M;
|
||||
|
||||
impl Bulletproofs {
|
||||
// TODO
|
||||
pub(crate) fn fee_weight(outputs: usize) -> usize {
|
||||
let proofs = 6 + usize::try_from(usize::BITS - (outputs - 1).leading_zeros()).unwrap();
|
||||
let len = (9 + (2 * proofs)) * 32;
|
||||
@@ -32,11 +33,12 @@ impl Bulletproofs {
|
||||
pub fn prove<R: RngCore + CryptoRng>(
|
||||
rng: &mut R,
|
||||
outputs: &[Commitment],
|
||||
plus: bool,
|
||||
) -> Result<Bulletproofs, TransactionError> {
|
||||
if outputs.len() > MAX_OUTPUTS {
|
||||
return Err(TransactionError::TooManyOutputs)?;
|
||||
}
|
||||
Ok(prove(rng, outputs))
|
||||
Ok(if !plus { prove(rng, outputs) } else { prove_plus(rng, outputs) })
|
||||
}
|
||||
|
||||
fn serialize_core<W: std::io::Write, F: Fn(&[EdwardsPoint], &mut W) -> std::io::Result<()>>(
|
||||
@@ -58,6 +60,17 @@ impl Bulletproofs {
|
||||
write_scalar(b, w)?;
|
||||
write_scalar(t, w)
|
||||
}
|
||||
|
||||
Bulletproofs::Plus { A, A1, B, r1, s1, d1, L, R } => {
|
||||
write_point(A, w)?;
|
||||
write_point(A1, w)?;
|
||||
write_point(B, w)?;
|
||||
write_scalar(r1, w)?;
|
||||
write_scalar(s1, w)?;
|
||||
write_scalar(d1, w)?;
|
||||
specific_write_vec(L, w)?;
|
||||
specific_write_vec(R, w)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -84,4 +97,17 @@ impl Bulletproofs {
|
||||
t: read_scalar(r)?,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn deserialize_plus<R: std::io::Read>(r: &mut R) -> std::io::Result<Bulletproofs> {
|
||||
Ok(Bulletproofs::Plus {
|
||||
A: read_point(r)?,
|
||||
A1: read_point(r)?,
|
||||
B: read_point(r)?,
|
||||
r1: read_scalar(r)?,
|
||||
s1: read_scalar(r)?,
|
||||
d1: read_scalar(r)?,
|
||||
L: read_vec(read_point, r)?,
|
||||
R: read_vec(read_point, r)?,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -60,6 +60,24 @@ impl ScalarVector {
|
||||
ScalarVector(res)
|
||||
}
|
||||
|
||||
pub(crate) fn even_powers(x: Scalar, pow: usize) -> ScalarVector {
|
||||
debug_assert!(pow != 0);
|
||||
// Verify pow is a power of two
|
||||
debug_assert_eq!(((pow - 1) & pow), 0);
|
||||
|
||||
let xsq = x * x;
|
||||
let mut res = ScalarVector(Vec::with_capacity(pow / 2));
|
||||
res.0.push(xsq);
|
||||
|
||||
let mut prev = 2;
|
||||
while prev < pow {
|
||||
res.0.push(res[res.len() - 1] * xsq);
|
||||
prev += 2;
|
||||
}
|
||||
|
||||
res
|
||||
}
|
||||
|
||||
pub(crate) fn sum(mut self) -> Scalar {
|
||||
self.0.drain(..).sum()
|
||||
}
|
||||
@@ -86,7 +104,8 @@ pub(crate) fn inner_product(a: &ScalarVector, b: &ScalarVector) -> Scalar {
|
||||
}
|
||||
|
||||
pub(crate) fn weighted_inner_product(a: &ScalarVector, b: &ScalarVector, y: Scalar) -> Scalar {
|
||||
(a * b * ScalarVector::powers(y, a.len())).sum()
|
||||
// y ** 0 is not used as a power
|
||||
(a * b * ScalarVector(ScalarVector::powers(y, a.len() + 1).0[1 ..].to_vec())).sum()
|
||||
}
|
||||
|
||||
impl Mul<&[EdwardsPoint]> for &ScalarVector {
|
||||
|
||||
@@ -12,8 +12,8 @@ use curve25519_dalek::{
|
||||
};
|
||||
|
||||
use crate::{
|
||||
Commitment, random_scalar, hash_to_scalar, transaction::RING_LEN, wallet::decoys::Decoys,
|
||||
ringct::hash_to_point, serialize::*,
|
||||
Commitment, random_scalar, hash_to_scalar, wallet::decoys::Decoys, ringct::hash_to_point,
|
||||
serialize::*,
|
||||
};
|
||||
|
||||
#[cfg(feature = "multisig")]
|
||||
@@ -292,8 +292,8 @@ impl Clsag {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) fn fee_weight() -> usize {
|
||||
(RING_LEN * 32) + 32 + 32
|
||||
pub(crate) fn fee_weight(ring_len: usize) -> usize {
|
||||
(ring_len * 32) + 32 + 32
|
||||
}
|
||||
|
||||
pub fn serialize<W: std::io::Write>(&self, w: &mut W) -> std::io::Result<()> {
|
||||
|
||||
@@ -31,7 +31,7 @@ impl RctBase {
|
||||
w.write_all(&[rct_type])?;
|
||||
match rct_type {
|
||||
0 => Ok(()),
|
||||
5 => {
|
||||
5 | 6 => {
|
||||
write_varint(&self.fee, w)?;
|
||||
for ecdh in &self.ecdh_info {
|
||||
w.write_all(ecdh)?;
|
||||
@@ -78,18 +78,24 @@ impl RctPrunable {
|
||||
pub fn rct_type(&self) -> u8 {
|
||||
match self {
|
||||
RctPrunable::Null => 0,
|
||||
RctPrunable::Clsag { .. } => 5,
|
||||
RctPrunable::Clsag { bulletproofs, .. } => {
|
||||
if matches!(bulletproofs[0], Bulletproofs::Original { .. }) {
|
||||
5
|
||||
} else {
|
||||
6
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn fee_weight(inputs: usize, outputs: usize) -> usize {
|
||||
1 + Bulletproofs::fee_weight(outputs) + (inputs * (Clsag::fee_weight() + 32))
|
||||
pub(crate) fn fee_weight(ring_len: usize, inputs: usize, outputs: usize) -> usize {
|
||||
1 + Bulletproofs::fee_weight(outputs) + (inputs * (Clsag::fee_weight(ring_len) + 32))
|
||||
}
|
||||
|
||||
pub fn serialize<W: std::io::Write>(&self, w: &mut W) -> std::io::Result<()> {
|
||||
match self {
|
||||
RctPrunable::Null => Ok(()),
|
||||
RctPrunable::Clsag { bulletproofs, clsags, pseudo_outs } => {
|
||||
RctPrunable::Clsag { bulletproofs, clsags, pseudo_outs, .. } => {
|
||||
write_vec(Bulletproofs::serialize, bulletproofs, w)?;
|
||||
write_raw_vec(Clsag::serialize, clsags, w)?;
|
||||
write_raw_vec(write_point, pseudo_outs, w)
|
||||
@@ -104,8 +110,11 @@ impl RctPrunable {
|
||||
) -> std::io::Result<RctPrunable> {
|
||||
Ok(match rct_type {
|
||||
0 => RctPrunable::Null,
|
||||
5 => RctPrunable::Clsag {
|
||||
bulletproofs: read_vec(Bulletproofs::deserialize, r)?,
|
||||
5 | 6 => RctPrunable::Clsag {
|
||||
bulletproofs: read_vec(
|
||||
if rct_type == 5 { Bulletproofs::deserialize } else { Bulletproofs::deserialize_plus },
|
||||
r,
|
||||
)?,
|
||||
clsags: (0 .. decoys.len())
|
||||
.map(|o| Clsag::deserialize(decoys[o], r))
|
||||
.collect::<Result<_, _>>()?,
|
||||
@@ -135,8 +144,8 @@ pub struct RctSignatures {
|
||||
}
|
||||
|
||||
impl RctSignatures {
|
||||
pub(crate) fn fee_weight(inputs: usize, outputs: usize) -> usize {
|
||||
RctBase::fee_weight(outputs) + RctPrunable::fee_weight(inputs, outputs)
|
||||
pub(crate) fn fee_weight(ring_len: usize, inputs: usize, outputs: usize) -> usize {
|
||||
RctBase::fee_weight(outputs) + RctPrunable::fee_weight(ring_len, inputs, outputs)
|
||||
}
|
||||
|
||||
pub fn serialize<W: std::io::Write>(&self, w: &mut W) -> std::io::Result<()> {
|
||||
|
||||
Reference in New Issue
Block a user