From 696da8228ee79cc5c5a3f2a89574c391fa638939 Mon Sep 17 00:00:00 2001
From: Luke Parker <lukeparker5132@gmail.com>
Date: Tue, 26 Jul 2022 03:25:57 -0400
Subject: [PATCH] Remove Monero as a dependency

Introduces missing CLSAG checks. The only difference now should be the
additional rejection of torsioned points, which is relevant to
https://github.com/serai-dex/serai/issues/25. Considering this is only
currently used for FROST verification, this should be fine.

Closes https://github.com/serai-dex/serai/issues/19 by making it
irrelevant.

Increases priority of https://github.com/serai-dex/serai/issues/68, as
now it's used for the BP generators which are done at first-proof.

Also merges BP's stricter hash_to_point with the library's, since CLSAG
has the same bound.
---
 Cargo.lock                                   |   1 -
 coins/monero/Cargo.toml                      |   4 -
 coins/monero/build.rs                        |  52 -------
 coins/monero/c/monero                        |   1 -
 coins/monero/c/wrapper.cpp                   | 156 -------------------
 coins/monero/src/lib.rs                      |  32 +---
 coins/monero/src/ringct/bulletproofs/core.rs |   8 +-
 coins/monero/src/ringct/bulletproofs/mod.rs  |  38 -----
 coins/monero/src/ringct/clsag/mod.rs         |  86 +++-------
 coins/monero/src/ringct/hash_to_point.rs     |  17 +-
 coins/monero/src/tests/bulletproofs.rs       |  21 ---
 coins/monero/src/tests/clsag.rs              |   2 -
 coins/monero/src/tests/hash_to_point.rs      |  16 --
 coins/monero/src/tests/mod.rs                |   2 -
 14 files changed, 33 insertions(+), 403 deletions(-)
 delete mode 100644 coins/monero/build.rs
 delete mode 160000 coins/monero/c/monero
 delete mode 100644 coins/monero/c/wrapper.cpp
 delete mode 100644 coins/monero/src/tests/bulletproofs.rs
 delete mode 100644 coins/monero/src/tests/hash_to_point.rs

diff --git a/Cargo.lock b/Cargo.lock
index 827469f6..7709b8e6 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -4569,7 +4569,6 @@ version = "0.1.0"
 dependencies = [
  "base58-monero 1.0.0",
  "blake2",
- "cc",
  "curve25519-dalek 3.2.0",
  "dalek-ff-group",
  "dleq-serai",
diff --git a/coins/monero/Cargo.toml b/coins/monero/Cargo.toml
index 04c7a82d..0f8268ca 100644
--- a/coins/monero/Cargo.toml
+++ b/coins/monero/Cargo.toml
@@ -6,9 +6,6 @@ license = "MIT"
 authors = ["Luke Parker <lukeparker5132@gmail.com>"]
 edition = "2021"
 
-[build-dependencies]
-cc = "1.0"
-
 [dependencies]
 hex-literal = "0.3"
 lazy_static = "1"
@@ -45,7 +42,6 @@ monero = "0.16"
 reqwest = { version = "0.11", features = ["json"] }
 
 [features]
-experimental = []
 multisig = ["rand_chacha", "blake2", "transcript", "frost", "dleq"]
 
 [dev-dependencies]
diff --git a/coins/monero/build.rs b/coins/monero/build.rs
deleted file mode 100644
index 98b25044..00000000
--- a/coins/monero/build.rs
+++ /dev/null
@@ -1,52 +0,0 @@
-use std::process::Command;
-
-fn main() {
-  if !Command::new("git")
-    .args(&["submodule", "update", "--init", "--recursive"])
-    .status()
-    .unwrap()
-    .success()
-  {
-    panic!("git failed to init submodules");
-  }
-
-  println!("cargo:rerun-if-changed=c/wrapper.cpp");
-  #[rustfmt::skip]
-  cc::Build::new()
-    .static_flag(true)
-    .warnings(false)
-    .extra_warnings(false)
-    .flag("-Wno-deprecated-declarations")
-
-    .include("c/monero/external/supercop/include")
-    .include("c/monero/contrib/epee/include")
-    .include("c/monero/src")
-    .include("c/monero/build/release/generated_include")
-
-    .define("AUTO_INITIALIZE_EASYLOGGINGPP", None)
-    .include("c/monero/external/easylogging++")
-    .file("c/monero/external/easylogging++/easylogging++.cc")
-
-    .file("c/monero/src/common/aligned.c")
-    .file("c/monero/src/common/perf_timer.cpp")
-
-    .include("c/monero/src/crypto")
-    .file("c/monero/src/crypto/crypto-ops-data.c")
-    .file("c/monero/src/crypto/crypto-ops.c")
-    .file("c/monero/src/crypto/keccak.c")
-    .file("c/monero/src/crypto/hash.c")
-
-    .include("c/monero/src/ringct")
-    .file("c/monero/src/ringct/rctCryptoOps.c")
-    .file("c/monero/src/ringct/rctTypes.cpp")
-    .file("c/monero/src/ringct/rctOps.cpp")
-    .file("c/monero/src/ringct/multiexp.cc")
-    .file("c/monero/src/ringct/bulletproofs.cc")
-    .file("c/monero/src/ringct/rctSigs.cpp")
-
-    .file("c/wrapper.cpp")
-    .compile("wrapper");
-
-  println!("cargo:rustc-link-lib=wrapper");
-  println!("cargo:rustc-link-lib=stdc++");
-}
diff --git a/coins/monero/c/monero b/coins/monero/c/monero
deleted file mode 160000
index 424e4de1..00000000
--- a/coins/monero/c/monero
+++ /dev/null
@@ -1 +0,0 @@
-Subproject commit 424e4de16b98506170db7b0d7d87a79ccf541744
diff --git a/coins/monero/c/wrapper.cpp b/coins/monero/c/wrapper.cpp
deleted file mode 100644
index d9436579..00000000
--- a/coins/monero/c/wrapper.cpp
+++ /dev/null
@@ -1,156 +0,0 @@
-#include <mutex>
-
-#include "ringct/bulletproofs.h"
-#include "ringct/rctSigs.h"
-
-typedef std::lock_guard<std::mutex> lock;
-
-std::mutex rng_mutex;
-uint8_t rng_entropy[64];
-
-extern "C" {
-  void rng(uint8_t* seed) {
-    // Set the first half to the seed
-    memcpy(rng_entropy, seed, 32);
-    // Set the second half to the hash of a DST to ensure a lack of collisions
-    crypto::cn_fast_hash("RNG_entropy_seed", 16, (char*) &rng_entropy[32]);
-  }
-}
-
-extern "C" void monero_wide_reduce(uint8_t* value);
-namespace crypto {
-  void generate_random_bytes_not_thread_safe(size_t n, void* value) {
-    size_t written = 0;
-    while (written != n) {
-      uint8_t hash[32];
-      crypto::cn_fast_hash(rng_entropy, 64, (char*) hash);
-      // Step the RNG by setting the latter half to the most recent result
-      // Does not leak the RNG, even if the values are leaked (which they are
-      // expected to be) due to the first half remaining constant and
-      // undisclosed
-      memcpy(&rng_entropy[32], hash, 32);
-
-      size_t next = n - written;
-      if (next > 32) {
-        next = 32;
-      }
-      memcpy(&((uint8_t*) value)[written], hash, next);
-      written += next;
-    }
-  }
-
-  void random32_unbiased(unsigned char *bytes) {
-    uint8_t value[64];
-    generate_random_bytes_not_thread_safe(64, value);
-    monero_wide_reduce(value);
-    memcpy(bytes, value, 32);
-  }
-}
-
-extern "C" {
-  void c_hash_to_point(uint8_t* point) {
-    rct::key key_point;
-    ge_p3 e_p3;
-    memcpy(key_point.bytes, point, 32);
-    rct::hash_to_p3(e_p3, key_point);
-    ge_p3_tobytes(point, &e_p3);
-  }
-
-  uint8_t* c_generate_bp(uint8_t* seed, uint8_t len, uint64_t* a, uint8_t* m) {
-    lock guard(rng_mutex);
-    rng(seed);
-
-    rct::keyV masks;
-    std::vector<uint64_t> amounts;
-    masks.resize(len);
-    amounts.resize(len);
-    for (uint8_t i = 0; i < len; i++) {
-      memcpy(masks[i].bytes, m + (i * 32), 32);
-      amounts[i] = a[i];
-    }
-
-    rct::Bulletproof bp = rct::bulletproof_PROVE(amounts, masks);
-
-    std::stringstream ss;
-    binary_archive<true> ba(ss);
-    ::serialization::serialize(ba, bp);
-    uint8_t* res = (uint8_t*) calloc(ss.str().size(), 1);
-    memcpy(res, ss.str().data(), ss.str().size());
-    return res;
-  }
-
-  bool c_verify_bp(
-    uint8_t* seed,
-    uint s_len,
-    uint8_t* s,
-    uint8_t c_len,
-    uint8_t* c
-  ) {
-    // BPs are batch verified which use RNG based weights to ensure individual
-    // integrity
-    // That's why this must also have control over RNG, to prevent interrupting
-    // multisig signing while not using known seeds. Considering this doesn't
-    // actually define a batch, and it's only verifying a single BP,
-    // it'd probably be fine, but...
-    lock guard(rng_mutex);
-    rng(seed);
-
-    rct::Bulletproof bp;
-    std::stringstream ss;
-    std::string str;
-    str.assign((char*) s, (size_t) s_len);
-    ss << str;
-    binary_archive<false> ba(ss);
-    ::serialization::serialize(ba, bp);
-    if (!ss.good()) {
-      return false;
-    }
-
-    bp.V.resize(c_len);
-    for (uint8_t i = 0; i < c_len; i++) {
-      memcpy(bp.V[i].bytes, &c[i * 32], 32);
-    }
-
-    try { return rct::bulletproof_VERIFY(bp); } catch(...) { return false; }
-  }
-
-  bool c_verify_clsag(
-    uint s_len,
-    uint8_t* s,
-    uint8_t k_len,
-    uint8_t* k,
-    uint8_t* I,
-    uint8_t* p,
-    uint8_t* m
-  ) {
-    rct::clsag clsag;
-    std::stringstream ss;
-    std::string str;
-    str.assign((char*) s, (size_t) s_len);
-    ss << str;
-    binary_archive<false> ba(ss);
-    ::serialization::serialize(ba, clsag);
-    if (!ss.good()) {
-      return false;
-    }
-
-    rct::ctkeyV keys;
-    keys.resize(k_len);
-    for (uint8_t i = 0; i < k_len; i++) {
-      memcpy(keys[i].dest.bytes, &k[(i * 2) * 32], 32);
-      memcpy(keys[i].mask.bytes, &k[((i * 2) + 1) * 32], 32);
-    }
-
-    memcpy(clsag.I.bytes, I, 32);
-
-    rct::key pseudo_out;
-    memcpy(pseudo_out.bytes, p, 32);
-
-    rct::key msg;
-    memcpy(msg.bytes, m, 32);
-
-    try {
-      return verRctCLSAGSimple(msg, clsag, keys, pseudo_out);
-    } catch(...) { return false; }
-  }
-}
diff --git a/coins/monero/src/lib.rs b/coins/monero/src/lib.rs
index 33601f0f..18990dad 100644
--- a/coins/monero/src/lib.rs
+++ b/coins/monero/src/lib.rs
@@ -1,10 +1,6 @@
-use std::slice;
-
 use lazy_static::lazy_static;
 use rand_core::{RngCore, CryptoRng};
 
-use subtle::ConstantTimeEq;
-
 use tiny_keccak::{Hasher, Keccak};
 
 use curve25519_dalek::{
@@ -38,26 +34,6 @@ lazy_static! {
   static ref H_TABLE: EdwardsBasepointTable = EdwardsBasepointTable::create(&H);
 }
 
-// Function from libsodium our subsection of Monero relies on. Implementing it here means we don't
-// need to link against libsodium
-#[no_mangle]
-unsafe extern "C" fn crypto_verify_32(a: *const u8, b: *const u8) -> isize {
-  isize::from(slice::from_raw_parts(a, 32).ct_eq(slice::from_raw_parts(b, 32)).unwrap_u8()) - 1
-}
-
-// Offer a wide reduction to C. Our seeded RNG prevented Monero from defining an unbiased scalar
-// generation function, and in order to not use Monero code (which would require propagating its
-// license), the function was rewritten. It was rewritten with wide reduction, instead of rejection
-// sampling however, hence the need for this function
-#[no_mangle]
-unsafe extern "C" fn monero_wide_reduce(value: *mut u8) {
-  let res =
-    Scalar::from_bytes_mod_order_wide(std::slice::from_raw_parts(value, 64).try_into().unwrap());
-  for (i, b) in res.to_bytes().iter().enumerate() {
-    value.add(i).write(*b);
-  }
-}
-
 #[allow(non_snake_case)]
 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
 pub struct Commitment {
@@ -95,5 +71,11 @@ pub fn hash(data: &[u8]) -> [u8; 32] {
 }
 
 pub fn hash_to_scalar(data: &[u8]) -> Scalar {
-  Scalar::from_bytes_mod_order(hash(data))
+  let scalar = Scalar::from_bytes_mod_order(hash(data));
+  // Monero will explicitly error in this case
+  // This library acknowledges its practical impossibility of it occurring, and doesn't bother to
+  // code in logic to handle it. That said, if it ever occurs, something must happen in order to
+  // not generate/verify a proof we believe to be valid when it isn't
+  assert!(scalar != Scalar::zero(), "ZERO HASH: {:?}", data);
+  scalar
 }
diff --git a/coins/monero/src/ringct/bulletproofs/core.rs b/coins/monero/src/ringct/bulletproofs/core.rs
index e083dda0..8988c595 100644
--- a/coins/monero/src/ringct/bulletproofs/core.rs
+++ b/coins/monero/src/ringct/bulletproofs/core.rs
@@ -28,13 +28,7 @@ fn random_scalar<R: RngCore + CryptoRng>(rng: &mut R) -> Scalar {
 }
 
 fn hash_to_scalar(data: &[u8]) -> Scalar {
-  let scalar = Scalar(dalek_hash(data));
-  // Monero will explicitly retry on these cases, as them occurring breaks the proof
-  // This library acknowledges their practical impossibility of them occurring, and doesn't bother
-  // to code in logic to handle it. That said, if they ever occur, something must happen in order
-  // to not generate a proof we believe to be valid when it isn't
-  assert!(!bool::from(scalar.is_zero()), "ZERO HASH: {:?}", data);
-  scalar
+  Scalar(dalek_hash(data))
 }
 
 fn generator(i: usize) -> EdwardsPoint {
diff --git a/coins/monero/src/ringct/bulletproofs/mod.rs b/coins/monero/src/ringct/bulletproofs/mod.rs
index 2599b2fc..388fdfd7 100644
--- a/coins/monero/src/ringct/bulletproofs/mod.rs
+++ b/coins/monero/src/ringct/bulletproofs/mod.rs
@@ -54,44 +54,6 @@ impl Bulletproofs {
     Ok(prove(rng, outputs))
   }
 
-  #[must_use]
-  pub fn verify<R: RngCore + CryptoRng>(&self, rng: &mut R, commitments: &[EdwardsPoint]) -> bool {
-    if commitments.len() > 16 {
-      return false;
-    }
-
-    let mut seed = [0; 32];
-    rng.fill_bytes(&mut seed);
-
-    let mut serialized = Vec::with_capacity((9 + (2 * self.L.len())) * 32);
-    self.serialize(&mut serialized).unwrap();
-    let commitments: Vec<[u8; 32]> = commitments
-      .iter()
-      .map(|commitment| (commitment * Scalar::from(8u8).invert()).compress().to_bytes())
-      .collect();
-
-    unsafe {
-      #[link(name = "wrapper")]
-      extern "C" {
-        fn c_verify_bp(
-          seed: *const u8,
-          serialized_len: usize,
-          serialized: *const u8,
-          commitments_len: u8,
-          commitments: *const [u8; 32],
-        ) -> bool;
-      }
-
-      c_verify_bp(
-        seed.as_ptr(),
-        serialized.len(),
-        serialized.as_ptr(),
-        u8::try_from(commitments.len()).unwrap(),
-        commitments.as_ptr(),
-      )
-    }
-  }
-
   fn serialize_core<W: std::io::Write, F: Fn(&[EdwardsPoint], &mut W) -> std::io::Result<()>>(
     &self,
     w: &mut W,
diff --git a/coins/monero/src/ringct/clsag/mod.rs b/coins/monero/src/ringct/clsag/mod.rs
index b9f480e1..755d09c2 100644
--- a/coins/monero/src/ringct/clsag/mod.rs
+++ b/coins/monero/src/ringct/clsag/mod.rs
@@ -7,7 +7,7 @@ use rand_core::{RngCore, CryptoRng};
 use curve25519_dalek::{
   constants::ED25519_BASEPOINT_TABLE,
   scalar::Scalar,
-  traits::VartimePrecomputedMultiscalarMul,
+  traits::{IsIdentity, VartimePrecomputedMultiscalarMul},
   edwards::{EdwardsPoint, VartimeEdwardsPrecomputation},
 };
 
@@ -29,10 +29,14 @@ lazy_static! {
 pub enum ClsagError {
   #[error("internal error ({0})")]
   InternalError(String),
+  #[error("invalid ring")]
+  InvalidRing,
   #[error("invalid ring member (member {0}, ring size {1})")]
   InvalidRingMember(u8, u8),
   #[error("invalid commitment")]
   InvalidCommitment,
+  #[error("invalid key image")]
+  InvalidImage,
   #[error("invalid D")]
   InvalidD,
   #[error("invalid s")]
@@ -72,7 +76,6 @@ impl ClsagInput {
 #[allow(clippy::large_enum_variant)]
 enum Mode {
   Sign(usize, EdwardsPoint, EdwardsPoint),
-  #[cfg(feature = "experimental")]
   Verify(Scalar),
 }
 
@@ -150,7 +153,6 @@ fn core(
       c = hash_to_scalar(&to_hash);
     }
 
-    #[cfg(feature = "experimental")]
     Mode::Verify(c1) => {
       start = 0;
       end = n;
@@ -259,17 +261,31 @@ impl Clsag {
     res
   }
 
-  // Not extensively tested nor guaranteed to have expected parity with Monero
-  #[cfg(feature = "experimental")]
-  pub fn rust_verify(
+  pub fn verify(
     &self,
     ring: &[[EdwardsPoint; 2]],
     I: &EdwardsPoint,
     pseudo_out: &EdwardsPoint,
     msg: &[u8; 32],
   ) -> Result<(), ClsagError> {
-    let (_, c1) =
-      core(ring, I, pseudo_out, msg, &self.D.mul_by_cofactor(), &self.s, Mode::Verify(self.c1));
+    // Preliminary checks. s, c1, and points must also be encoded canonically, which isn't checked
+    // here
+    if ring.len() == 0 {
+      Err(ClsagError::InvalidRing)?;
+    }
+    if ring.len() != self.s.len() {
+      Err(ClsagError::InvalidS)?;
+    }
+    if I.is_identity() {
+      Err(ClsagError::InvalidImage)?;
+    }
+
+    let D = self.D.mul_by_cofactor();
+    if D.is_identity() {
+      Err(ClsagError::InvalidD)?;
+    }
+
+    let (_, c1) = core(ring, I, pseudo_out, msg, &D, &self.s, Mode::Verify(self.c1));
     if c1 != self.c1 {
       Err(ClsagError::InvalidC1)?;
     }
@@ -289,58 +305,4 @@ impl Clsag {
   pub fn deserialize<R: std::io::Read>(decoys: usize, r: &mut R) -> std::io::Result<Clsag> {
     Ok(Clsag { s: read_raw_vec(read_scalar, decoys, r)?, c1: read_scalar(r)?, D: read_point(r)? })
   }
-
-  pub fn verify(
-    &self,
-    ring: &[[EdwardsPoint; 2]],
-    I: &EdwardsPoint,
-    pseudo_out: &EdwardsPoint,
-    msg: &[u8; 32],
-  ) -> Result<(), ClsagError> {
-    // Serialize it to pass the struct to Monero without extensive FFI
-    let mut serialized = Vec::with_capacity(1 + ((self.s.len() + 2) * 32));
-    write_varint(&self.s.len().try_into().unwrap(), &mut serialized).unwrap();
-    self.serialize(&mut serialized).unwrap();
-
-    let I_bytes = I.compress().to_bytes();
-
-    let mut ring_bytes = vec![];
-    for member in ring {
-      ring_bytes.extend(&member[0].compress().to_bytes());
-      ring_bytes.extend(&member[1].compress().to_bytes());
-    }
-
-    let pseudo_out_bytes = pseudo_out.compress().to_bytes();
-
-    unsafe {
-      // Uses Monero's C verification function to ensure compatibility with Monero
-      #[link(name = "wrapper")]
-      extern "C" {
-        pub(crate) fn c_verify_clsag(
-          serialized_len: usize,
-          serialized: *const u8,
-          ring_size: u8,
-          ring: *const u8,
-          I: *const u8,
-          pseudo_out: *const u8,
-          msg: *const u8,
-        ) -> bool;
-      }
-
-      if c_verify_clsag(
-        serialized.len(),
-        serialized.as_ptr(),
-        u8::try_from(ring.len())
-          .map_err(|_| ClsagError::InternalError("too large ring".to_string()))?,
-        ring_bytes.as_ptr(),
-        I_bytes.as_ptr(),
-        pseudo_out_bytes.as_ptr(),
-        msg.as_ptr(),
-      ) {
-        Ok(())
-      } else {
-        Err(ClsagError::InvalidC1)
-      }
-    }
-  }
 }
diff --git a/coins/monero/src/ringct/hash_to_point.rs b/coins/monero/src/ringct/hash_to_point.rs
index a28c8b95..779030de 100644
--- a/coins/monero/src/ringct/hash_to_point.rs
+++ b/coins/monero/src/ringct/hash_to_point.rs
@@ -7,23 +7,8 @@ use dalek_ff_group::field::FieldElement;
 
 use crate::hash;
 
-pub(crate) fn raw_hash_to_point(mut bytes: [u8; 32]) -> EdwardsPoint {
-  unsafe {
-    #[link(name = "wrapper")]
-    extern "C" {
-      fn c_hash_to_point(key: *const u8);
-    }
-
-    c_hash_to_point(bytes.as_mut_ptr());
-  }
-  CompressedEdwardsY::from_slice(&bytes).decompress().unwrap()
-}
-
-// This works without issue. It's also 140 times slower (@ 3.5ms), and despite checking it passes
-// for all branches, there still could be *some* discrepancy somewhere. There's no reason to use it
-// unless we're trying to purge that section of the C static library, which we aren't right now
 #[allow(dead_code)]
-pub(crate) fn rust_hash_to_point(bytes: [u8; 32]) -> EdwardsPoint {
+pub(crate) fn raw_hash_to_point(bytes: [u8; 32]) -> EdwardsPoint {
   #[allow(non_snake_case)]
   let A = FieldElement::from(486662u64);
 
diff --git a/coins/monero/src/tests/bulletproofs.rs b/coins/monero/src/tests/bulletproofs.rs
deleted file mode 100644
index 98ae1546..00000000
--- a/coins/monero/src/tests/bulletproofs.rs
+++ /dev/null
@@ -1,21 +0,0 @@
-use rand::rngs::OsRng;
-
-use crate::{Commitment, random_scalar, ringct::bulletproofs::Bulletproofs};
-
-#[test]
-fn bulletproofs() {
-  // Create Bulletproofs for all possible output quantities
-  for i in 1 .. 17 {
-    let commitments =
-      (1 ..= i).map(|i| Commitment::new(random_scalar(&mut OsRng), i)).collect::<Vec<_>>();
-
-    assert!(Bulletproofs::new(&mut OsRng, &commitments)
-      .unwrap()
-      .verify(&mut OsRng, &commitments.iter().map(Commitment::calculate).collect::<Vec<_>>()));
-  }
-
-  // Check it errors if we try to create too many
-  assert!(
-    Bulletproofs::new(&mut OsRng, &[Commitment::new(random_scalar(&mut OsRng), 1); 17]).is_err()
-  );
-}
diff --git a/coins/monero/src/tests/clsag.rs b/coins/monero/src/tests/clsag.rs
index 73f5b7cd..fe9ecc9b 100644
--- a/coins/monero/src/tests/clsag.rs
+++ b/coins/monero/src/tests/clsag.rs
@@ -74,8 +74,6 @@ fn clsag() {
     )
     .swap_remove(0);
     clsag.verify(&ring, &image, &pseudo_out, &msg).unwrap();
-    #[cfg(feature = "experimental")]
-    clsag.rust_verify(&ring, &image, &pseudo_out, &msg).unwrap();
   }
 }
 
diff --git a/coins/monero/src/tests/hash_to_point.rs b/coins/monero/src/tests/hash_to_point.rs
deleted file mode 100644
index 983539e5..00000000
--- a/coins/monero/src/tests/hash_to_point.rs
+++ /dev/null
@@ -1,16 +0,0 @@
-use rand::rngs::OsRng;
-
-use curve25519_dalek::constants::ED25519_BASEPOINT_TABLE;
-
-use crate::{
-  random_scalar,
-  ringct::hash_to_point::{hash_to_point as c_hash_to_point, rust_hash_to_point},
-};
-
-#[test]
-fn hash_to_point() {
-  for _ in 0 .. 50 {
-    let point = &random_scalar(&mut OsRng) * &ED25519_BASEPOINT_TABLE;
-    assert_eq!(rust_hash_to_point(point.compress().to_bytes()), c_hash_to_point(point));
-  }
-}
diff --git a/coins/monero/src/tests/mod.rs b/coins/monero/src/tests/mod.rs
index 5af30bad..d9b85f0c 100644
--- a/coins/monero/src/tests/mod.rs
+++ b/coins/monero/src/tests/mod.rs
@@ -1,4 +1,2 @@
-mod hash_to_point;
 mod clsag;
-mod bulletproofs;
 mod address;