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
No known key found for this signature in database
GPG key ID: F9F1386DB1E119B6
9 changed files with 209 additions and 113 deletions

66
Cargo.lock generated
View file

@ -406,15 +406,6 @@ version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6107fe1be6682a68940da878d9e9f5e90ca5745b3dec9fd1bb393c8777d4f581"
[[package]]
name = "base58-monero"
version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "935c90240f9b7749c80746bf88ad9cb346f34b01ee30ad4d566dfdecd6e3cc6a"
dependencies = [
"thiserror",
]
[[package]]
name = "base58-monero"
version = "1.0.0"
@ -907,7 +898,7 @@ version = "3.2.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "13547f7012c01ab4a0e8f8967730ada8f9fdf419e8b6c792788f39cf4e46eefa"
dependencies = [
"heck 0.4.0",
"heck",
"proc-macro-error",
"proc-macro2",
"quote",
@ -1699,7 +1690,7 @@ version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "21cdad81446a7f7dc43f6a77409efeb9733d2fa65553efef6018ef257c959b73"
dependencies = [
"heck 0.4.0",
"heck",
"proc-macro2",
"quote",
"syn",
@ -2856,15 +2847,6 @@ dependencies = [
"fxhash",
]
[[package]]
name = "heck"
version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6d621efb26863f0e9924c6ac577e8275e5e6b77455db64ffa6c65c904e9e132c"
dependencies = [
"unicode-segmentation",
]
[[package]]
name = "heck"
version = "0.4.0"
@ -3244,7 +3226,7 @@ dependencies = [
"blake2",
"derive_more",
"either",
"heck 0.4.0",
"heck",
"impl-serde",
"ink_lang_ir",
"itertools",
@ -4557,22 +4539,6 @@ dependencies = [
"zeroize",
]
[[package]]
name = "monero"
version = "0.16.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e3732061cea7e75dc68ef986e0d5a393b3606c258c996abb4a81b759613ea1a0"
dependencies = [
"base58-monero 0.3.2",
"curve25519-dalek 3.2.0",
"fixed-hash",
"hex",
"hex-literal",
"sealed",
"thiserror",
"tiny-keccak",
]
[[package]]
name = "monero-epee-bin-serde"
version = "1.0.1"
@ -4599,7 +4565,7 @@ dependencies = [
name = "monero-serai"
version = "0.1.0"
dependencies = [
"base58-monero 1.0.0",
"base58-monero",
"blake2",
"curve25519-dalek 3.2.0",
"dalek-ff-group",
@ -4610,7 +4576,6 @@ dependencies = [
"hex-literal",
"lazy_static",
"modular-frost",
"monero",
"monero-epee-bin-serde",
"monero-generators",
"multiexp",
@ -5840,7 +5805,7 @@ dependencies = [
"bytes",
"cfg-if",
"cmake",
"heck 0.4.0",
"heck",
"itertools",
"lazy_static",
"log",
@ -7334,18 +7299,6 @@ dependencies = [
"untrusted",
]
[[package]]
name = "sealed"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "636b9882a0f4cc2039488df89a10eb4b7976d4b6c1917fc0518f3f0f5e2c72ca"
dependencies = [
"heck 0.3.3",
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "sec1"
version = "0.3.0"
@ -7548,7 +7501,6 @@ dependencies = [
"hex",
"k256",
"modular-frost",
"monero",
"monero-serai",
"rand_core 0.6.3",
"serde",
@ -8587,7 +8539,7 @@ version = "0.24.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1e385be0d24f186b4ce2f9982191e7101bb737312ad61c1f2f984f34bcf85d59"
dependencies = [
"heck 0.4.0",
"heck",
"proc-macro2",
"quote",
"rustversion",
@ -9260,12 +9212,6 @@ dependencies = [
"tinyvec",
]
[[package]]
name = "unicode-segmentation"
version = "1.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7e8820f5d777f6224dc4be3632222971ac30164d4a258d595640799554ebfd99"
[[package]]
name = "unicode-width"
version = "0.1.9"

View file

@ -40,7 +40,6 @@ serde_json = "1.0"
base58-monero = "1"
monero-epee-bin-serde = "1.0"
monero = "0.16"
reqwest = { version = "0.11", features = ["json"] }

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());

View file

@ -4,13 +4,9 @@ use curve25519_dalek::constants::ED25519_BASEPOINT_TABLE;
use serde_json::json;
use monero::{
network::Network,
util::{key::PublicKey, address::Address},
};
use monero_serai::{
Protocol, random_scalar,
wallet::address::{Network, AddressType, AddressMeta, Address},
rpc::{EmptyResponse, RpcError, Rpc},
};
@ -22,11 +18,11 @@ pub async fn rpc() -> Rpc {
return rpc;
}
let addr = Address::standard(
Network::Mainnet,
PublicKey { point: (&random_scalar(&mut OsRng) * &ED25519_BASEPOINT_TABLE).compress() },
PublicKey { point: (&random_scalar(&mut OsRng) * &ED25519_BASEPOINT_TABLE).compress() },
)
let addr = Address {
meta: AddressMeta { network: Network::Mainnet, kind: AddressType::Standard, guaranteed: false },
spend: &random_scalar(&mut OsRng) * &ED25519_BASEPOINT_TABLE,
view: &random_scalar(&mut OsRng) * &ED25519_BASEPOINT_TABLE,
}
.to_string();
// Mine 20 blocks to ensure decoy availability

View file

@ -29,7 +29,6 @@ transcript = { package = "flexible-transcript", path = "../crypto/transcript", f
dalek-ff-group = { path = "../crypto/dalek-ff-group" }
frost = { package = "modular-frost", path = "../crypto/frost", features = ["secp256k1", "ed25519"] }
monero = { version = "0.16", features = ["experimental"] }
monero-serai = { path = "../coins/monero", features = ["multisig"] }
[dev-dependencies]