mirror of
https://github.com/serai-dex/serai.git
synced 2024-12-22 19:49:22 +00:00
Fix #48
Removes monero, yet we still use monero-rs's base58 and epee libraries.
This commit is contained in:
parent
d12507e612
commit
c5beee5648
9 changed files with 209 additions and 113 deletions
66
Cargo.lock
generated
66
Cargo.lock
generated
|
@ -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"
|
||||
|
|
|
@ -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"] }
|
||||
|
||||
|
|
|
@ -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(())
|
||||
|
|
165
coins/monero/src/wallet/extra.rs
Normal file
165
coins/monero/src/wallet/extra.rs
Normal 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)
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
|
|
|
@ -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,
|
||||
);
|
||||
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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]
|
||||
|
|
Loading…
Reference in a new issue