Removes monero, yet we still use monero-rs's base58 and epee libraries.
This commit is contained in:
Luke Parker
2022-08-21 08:41:19 -04:00
parent d12507e612
commit c5beee5648
9 changed files with 209 additions and 113 deletions

View File

@@ -11,6 +11,10 @@ pub fn varint_len(varint: usize) -> usize {
((usize::try_from(usize::BITS - varint.leading_zeros()).unwrap().saturating_sub(1)) / 7) + 1
}
pub fn write_byte<W: io::Write>(byte: &u8, w: &mut W) -> io::Result<()> {
w.write_all(&[*byte])
}
pub fn write_varint<W: io::Write>(varint: &u64, w: &mut W) -> io::Result<()> {
let mut varint = *varint;
while {
@@ -19,7 +23,7 @@ pub fn write_varint<W: io::Write>(varint: &u64, w: &mut W) -> io::Result<()> {
if varint != 0 {
b |= VARINT_CONTINUATION_MASK;
}
w.write_all(&[b])?;
write_byte(&b, w)?;
varint != 0
} {}
Ok(())

View File

@@ -0,0 +1,165 @@
use std::io::{self, Read, Write};
use zeroize::Zeroize;
use curve25519_dalek::edwards::EdwardsPoint;
use crate::serialize::{
read_byte, read_bytes, read_varint, read_point, read_vec, write_byte, write_varint, write_point,
write_vec,
};
#[derive(Clone, Copy, PartialEq, Eq, Debug, Zeroize)]
pub(crate) enum PaymentId {
Unencrypted([u8; 32]),
Encrypted([u8; 8]),
}
impl PaymentId {
fn serialize<W: Write>(&self, w: &mut W) -> io::Result<()> {
match self {
PaymentId::Unencrypted(id) => {
w.write_all(&[0])?;
w.write_all(id)?;
}
PaymentId::Encrypted(id) => {
w.write_all(&[1])?;
w.write_all(id)?;
}
}
Ok(())
}
fn deserialize<R: Read>(r: &mut R) -> io::Result<PaymentId> {
Ok(match read_byte(r)? {
0 => PaymentId::Unencrypted(read_bytes(r)?),
1 => PaymentId::Encrypted(read_bytes(r)?),
_ => Err(io::Error::new(io::ErrorKind::Other, "unknown payment ID type"))?,
})
}
}
#[derive(Clone, PartialEq, Eq, Debug, Zeroize)]
pub(crate) enum ExtraField {
Padding(Vec<u8>),
PublicKey(EdwardsPoint),
PaymentId(PaymentId), // Technically Nonce, an arbitrary data field, yet solely used as PaymentId
MergeMining(usize, [u8; 32]),
PublicKeys(Vec<EdwardsPoint>),
}
impl ExtraField {
fn serialize<W: Write>(&self, w: &mut W) -> io::Result<()> {
match self {
ExtraField::Padding(data) => {
w.write_all(&[0])?;
write_vec(write_byte, data, w)?;
}
ExtraField::PublicKey(key) => {
w.write_all(&[1])?;
w.write_all(&key.compress().to_bytes())?;
}
ExtraField::PaymentId(id) => {
w.write_all(&[2])?;
let mut buf = Vec::with_capacity(1 + 8);
id.serialize(&mut buf)?;
write_vec(write_byte, &buf, w)?;
}
ExtraField::MergeMining(height, merkle) => {
w.write_all(&[3])?;
write_varint(&u64::try_from(*height).unwrap(), w)?;
w.write_all(merkle)?;
}
ExtraField::PublicKeys(keys) => {
w.write_all(&[4])?;
write_vec(write_point, keys, w)?;
}
}
Ok(())
}
fn deserialize<R: Read>(r: &mut R) -> io::Result<ExtraField> {
Ok(match read_byte(r)? {
0 => {
let res = read_vec(read_byte, r)?;
if res.len() > 255 {
Err(io::Error::new(io::ErrorKind::Other, "too long padding"))?;
}
ExtraField::Padding(res)
}
1 => ExtraField::PublicKey(read_point(r)?),
2 => ExtraField::PaymentId(PaymentId::deserialize(r)?),
3 => ExtraField::MergeMining(
usize::try_from(read_varint(r)?)
.map_err(|_| io::Error::new(io::ErrorKind::Other, "varint for height exceeds usize"))?,
read_bytes(r)?,
),
4 => ExtraField::PublicKeys(read_vec(read_point, r)?),
_ => Err(io::Error::new(io::ErrorKind::Other, "unknown extra field"))?,
})
}
}
#[derive(Clone, PartialEq, Eq, Debug, Zeroize)]
pub(crate) struct Extra(Vec<ExtraField>);
impl Extra {
pub(crate) fn keys(&self) -> Vec<EdwardsPoint> {
let mut keys = Vec::with_capacity(2);
for field in &self.0 {
match field.clone() {
ExtraField::PublicKey(key) => keys.push(key),
ExtraField::PublicKeys(additional) => keys.extend(additional),
_ => (),
}
}
keys
}
pub(crate) fn data(&self) -> Option<Vec<u8>> {
for field in &self.0 {
if let ExtraField::Padding(data) = field {
return Some(data.clone());
}
}
None
}
pub(crate) fn new(mut keys: Vec<EdwardsPoint>) -> Extra {
let mut res = Extra(Vec::with_capacity(3));
if !keys.is_empty() {
res.push(ExtraField::PublicKey(keys[0]));
}
if keys.len() > 1 {
res.push(ExtraField::PublicKeys(keys.drain(1 ..).collect()));
}
res
}
pub(crate) fn push(&mut self, field: ExtraField) {
self.0.push(field);
}
pub(crate) fn fee_weight(outputs: usize) -> usize {
// PublicKey, key, PublicKeys, length, additional keys, PaymentId, length, encrypted, ID
33 + 2 + (outputs.saturating_sub(1) * 32) + 11
}
pub(crate) fn serialize<W: Write>(&self, w: &mut W) -> io::Result<()> {
for field in &self.0 {
field.serialize(w)?;
}
Ok(())
}
pub(crate) fn deserialize<R: Read>(r: &mut R) -> io::Result<Extra> {
let mut res = Extra(vec![]);
let mut field;
while {
field = ExtraField::deserialize(r);
field.is_ok()
} {
res.0.push(field.unwrap());
}
Ok(res)
}
}

View File

@@ -4,6 +4,9 @@ use curve25519_dalek::{scalar::Scalar, edwards::EdwardsPoint};
use crate::{hash, hash_to_scalar, serialize::write_varint, transaction::Input};
mod extra;
pub(crate) use extra::{PaymentId, ExtraField, Extra};
pub mod address;
mod scan;

View File

@@ -1,16 +1,14 @@
use std::convert::TryFrom;
use std::io::Cursor;
use zeroize::{Zeroize, ZeroizeOnDrop};
use curve25519_dalek::{constants::ED25519_BASEPOINT_TABLE, scalar::Scalar, edwards::EdwardsPoint};
use monero::{consensus::deserialize, blockdata::transaction::ExtraField};
use crate::{
Commitment,
serialize::{write_varint, read_byte, read_bytes, read_u64, read_scalar, read_point},
serialize::{read_byte, read_u64, read_bytes, read_scalar, read_point},
transaction::{Timelock, Transaction},
wallet::{ViewPair, uniqueness, shared_key, amount_decryption, commitment_mask},
wallet::{ViewPair, Extra, uniqueness, shared_key, amount_decryption, commitment_mask},
};
#[derive(Clone, PartialEq, Eq, Debug, Zeroize, ZeroizeOnDrop)]
@@ -72,34 +70,21 @@ impl SpendableOutput {
impl Transaction {
pub fn scan(&self, view: &ViewPair, guaranteed: bool) -> Timelocked {
let mut extra = vec![];
write_varint(&u64::try_from(self.prefix.extra.len()).unwrap(), &mut extra).unwrap();
extra.extend(&self.prefix.extra);
let extra = deserialize::<ExtraField>(&extra);
let pubkeys: Vec<EdwardsPoint>;
let extra = Extra::deserialize(&mut Cursor::new(&self.prefix.extra));
let keys;
if let Ok(extra) = extra {
let mut m_pubkeys = vec![];
if let Some(key) = extra.tx_pubkey() {
m_pubkeys.push(key);
}
if let Some(keys) = extra.tx_additional_pubkeys() {
m_pubkeys.extend(&keys);
}
pubkeys = m_pubkeys.iter().filter_map(|key| key.point.decompress()).collect();
keys = extra.keys();
} else {
return Timelocked(self.prefix.timelock, vec![]);
};
let mut res = vec![];
for (o, output) in self.prefix.outputs.iter().enumerate() {
// TODO: This may be replaceable by pubkeys[o]
for pubkey in &pubkeys {
for key in &keys {
let (view_tag, key_offset) = shared_key(
Some(uniqueness(&self.prefix.inputs)).filter(|_| guaranteed),
&view.view,
pubkey,
key,
o,
);

View File

@@ -7,8 +7,6 @@ use zeroize::{Zeroize, ZeroizeOnDrop};
use curve25519_dalek::{constants::ED25519_BASEPOINT_TABLE, scalar::Scalar, edwards::EdwardsPoint};
use monero::{consensus::Encodable, PublicKey, blockdata::transaction::SubField};
#[cfg(feature = "multisig")]
use frost::FrostError;
@@ -24,8 +22,8 @@ use crate::{
rpc::{Rpc, RpcError},
wallet::{
address::{AddressType, Address},
SpendableOutput, Decoys, key_image_sort, uniqueness, shared_key, commitment_mask,
amount_encryption,
SpendableOutput, Decoys, PaymentId, ExtraField, Extra, key_image_sort, uniqueness, shared_key,
commitment_mask, amount_encryption,
},
};
#[cfg(feature = "multisig")]
@@ -210,9 +208,8 @@ impl SignableTransaction {
}
let outputs = payments.len() + (if change { 1 } else { 0 });
// Calculate the extra length.
// Type, length, value, with 1 field for the first key and 1 field for the rest
let extra = (outputs * (2 + 32)) - (outputs.saturating_sub(2) * 2);
// Calculate the extra length
let extra = Extra::fee_weight(outputs);
// Calculate the fee.
let mut fee = fee_rate.calculate(Transaction::fee_weight(
@@ -279,16 +276,18 @@ impl SignableTransaction {
let bp = Bulletproofs::prove(rng, &commitments, self.protocol.bp_plus()).unwrap();
// Create the TX extra
// TODO: Review this for canonicity with Monero
let mut extra = vec![];
SubField::TxPublicKey(PublicKey { point: outputs[0].R.compress() })
.consensus_encode(&mut extra)
.unwrap();
SubField::AdditionalPublickKey(
outputs[1 ..].iter().map(|output| PublicKey { point: output.R.compress() }).collect(),
)
.consensus_encode(&mut extra)
.unwrap();
let extra = {
let mut extra = Extra::new(outputs.iter().map(|output| output.R).collect());
// Additionally include a random payment ID
let mut id = [0; 8];
rng.fill_bytes(&mut id);
extra.push(ExtraField::PaymentId(PaymentId::Encrypted(id)));
let mut serialized = Vec::with_capacity(Extra::fee_weight(outputs.len()));
extra.serialize(&mut serialized).unwrap();
serialized
};
let mut tx_outputs = Vec::with_capacity(outputs.len());
let mut ecdh_info = Vec::with_capacity(outputs.len());