mirror of
https://github.com/serai-dex/serai.git
synced 2024-11-17 01:17:36 +00:00
An extremely minimal subset of Monero is now all that's built, and I'm sufficiently happy with it.
This commit is contained in:
parent
53267a46c8
commit
854fca3806
5 changed files with 121 additions and 98 deletions
|
@ -19,6 +19,8 @@ rand_chacha = { version = "0.3", optional = true }
|
||||||
rand = "0.8"
|
rand = "0.8"
|
||||||
rand_distr = "0.4"
|
rand_distr = "0.4"
|
||||||
|
|
||||||
|
subtle = "2.4"
|
||||||
|
|
||||||
tiny-keccak = { version = "2", features = ["keccak"] }
|
tiny-keccak = { version = "2", features = ["keccak"] }
|
||||||
blake2 = { version = "0.10", optional = true }
|
blake2 = { version = "0.10", optional = true }
|
||||||
|
|
||||||
|
@ -31,13 +33,14 @@ transcript = { package = "flexible-transcript", path = "../../crypto/transcript"
|
||||||
frost = { package = "modular-frost", path = "../../crypto/frost", features = ["ed25519"], optional = true }
|
frost = { package = "modular-frost", path = "../../crypto/frost", features = ["ed25519"], optional = true }
|
||||||
dleq = { path = "../../crypto/dleq", features = ["serialize"], optional = true }
|
dleq = { path = "../../crypto/dleq", features = ["serialize"], optional = true }
|
||||||
|
|
||||||
base58-monero = "1"
|
|
||||||
monero = "0.16"
|
|
||||||
|
|
||||||
hex = "0.4"
|
hex = "0.4"
|
||||||
serde = { version = "1.0", features = ["derive"] }
|
serde = { version = "1.0", features = ["derive"] }
|
||||||
serde_json = "1.0"
|
serde_json = "1.0"
|
||||||
|
|
||||||
|
base58-monero = "1"
|
||||||
monero-epee-bin-serde = "1.0"
|
monero-epee-bin-serde = "1.0"
|
||||||
|
monero = "0.16"
|
||||||
|
|
||||||
reqwest = { version = "0.11", features = ["json"] }
|
reqwest = { version = "0.11", features = ["json"] }
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
|
|
|
@ -14,7 +14,6 @@ fn main() {
|
||||||
|
|
||||||
// Use a file to signal if Monero was already built, as that should never be rebuilt
|
// Use a file to signal if Monero was already built, as that should never be rebuilt
|
||||||
// If the signaling file was deleted, run this script again to rebuild Monero though
|
// If the signaling file was deleted, run this script again to rebuild Monero though
|
||||||
// TODO: Move this signaling file into OUT_DIR once Monero is built statically successfully
|
|
||||||
println!("cargo:rerun-if-changed=c/.build/monero");
|
println!("cargo:rerun-if-changed=c/.build/monero");
|
||||||
if !Path::new("c/.build/monero").exists() {
|
if !Path::new("c/.build/monero").exists() {
|
||||||
if !Command::new("make").arg(format!("-j{}", &env::var("THREADS").unwrap_or("2".to_string())))
|
if !Command::new("make").arg(format!("-j{}", &env::var("THREADS").unwrap_or("2".to_string())))
|
||||||
|
@ -28,81 +27,46 @@ fn main() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
println!("cargo:rerun-if-env-changed=OUT_DIR");
|
|
||||||
if !Path::new(
|
|
||||||
&format!(
|
|
||||||
"{}/{}cncrypto.{}",
|
|
||||||
out_dir,
|
|
||||||
&env::consts::DLL_PREFIX,
|
|
||||||
&env::consts::DLL_EXTENSION
|
|
||||||
)
|
|
||||||
).exists() {
|
|
||||||
let mut paths = vec![
|
|
||||||
"c/monero/build/release/contrib/epee/src/libepee.a".to_string(),
|
|
||||||
"c/monero/build/release/external/easylogging++/libeasylogging.a".to_string(),
|
|
||||||
"c/monero/build/release/external/randomx/librandomx.a".to_string()
|
|
||||||
];
|
|
||||||
|
|
||||||
for (folder, lib) in [
|
|
||||||
("common", "common"),
|
|
||||||
("crypto", "cncrypto"),
|
|
||||||
("crypto/wallet", "wallet-crypto"),
|
|
||||||
("cryptonote_basic", "cryptonote_basic"),
|
|
||||||
("cryptonote_basic", "cryptonote_format_utils_basic"),
|
|
||||||
("", "version"),
|
|
||||||
("device", "device"),
|
|
||||||
("ringct", "ringct_basic"),
|
|
||||||
("ringct", "ringct")
|
|
||||||
] {
|
|
||||||
paths.push(
|
|
||||||
format!(
|
|
||||||
"c/monero/build/release/src/{}/{}{}.a",
|
|
||||||
folder,
|
|
||||||
&env::consts::DLL_PREFIX,
|
|
||||||
lib
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
for path in paths {
|
|
||||||
if !Command::new("cp").args(&[&path, out_dir]).status().unwrap().success() {
|
|
||||||
panic!("Failed to cp {}", path);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
println!("cargo:rerun-if-changed=c/wrapper.cpp");
|
println!("cargo:rerun-if-changed=c/wrapper.cpp");
|
||||||
if !Path::new(&format!("{}/{}wrapper.a", out_dir, &env::consts::DLL_PREFIX)).exists() {
|
|
||||||
cc::Build::new()
|
cc::Build::new()
|
||||||
.file("c/wrapper.cpp")
|
.static_flag(true)
|
||||||
.cpp(true)
|
|
||||||
.warnings(false)
|
.warnings(false)
|
||||||
|
.extra_warnings(false)
|
||||||
|
.flag("-Wno-deprecated-declarations")
|
||||||
|
|
||||||
|
.include("c/monero/external/supercop/include")
|
||||||
.include("c/monero/contrib/epee/include")
|
.include("c/monero/contrib/epee/include")
|
||||||
.include("c/monero/src")
|
.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/device")
|
||||||
|
.file("c/monero/src/device/device_default.cpp")
|
||||||
|
|
||||||
|
.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");
|
.compile("wrapper");
|
||||||
}
|
|
||||||
|
|
||||||
println!("cargo:rustc-link-search={}", out_dir);
|
println!("cargo:rustc-link-search={}", out_dir);
|
||||||
println!("cargo:rustc-link-lib=wrapper");
|
println!("cargo:rustc-link-lib=wrapper");
|
||||||
println!("cargo:rustc-link-lib=ringct");
|
|
||||||
println!("cargo:rustc-link-lib=ringct_basic");
|
|
||||||
println!("cargo:rustc-link-lib=device");
|
|
||||||
println!("cargo:rustc-link-lib=cryptonote_basic");
|
|
||||||
println!("cargo:rustc-link-lib=cncrypto");
|
|
||||||
println!("cargo:rustc-link-lib=cryptonote_format_utils_basic");
|
|
||||||
println!("cargo:rustc-link-lib=version");
|
|
||||||
println!("cargo:rustc-link-lib=wallet-crypto");
|
|
||||||
println!("cargo:rustc-link-lib=easylogging");
|
|
||||||
println!("cargo:rustc-link-lib=epee");
|
|
||||||
println!("cargo:rustc-link-lib=common");
|
|
||||||
println!("cargo:rustc-link-lib=randomx");
|
|
||||||
println!("cargo:rustc-link-lib=unbound");
|
|
||||||
println!("cargo:rustc-link-lib=sodium");
|
|
||||||
println!("cargo:rustc-link-lib=boost_system");
|
|
||||||
println!("cargo:rustc-link-lib=boost_thread");
|
|
||||||
println!("cargo:rustc-link-lib=boost_filesystem");
|
|
||||||
println!("cargo:rustc-link-lib=hidapi-hidraw");
|
|
||||||
println!("cargo:rustc-link-lib=stdc++");
|
println!("cargo:rustc-link-lib=stdc++");
|
||||||
|
|
||||||
println!("cargo:rustc-link-arg=-zmuldefs");
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,36 +6,50 @@
|
||||||
#include "ringct/rctSigs.h"
|
#include "ringct/rctSigs.h"
|
||||||
|
|
||||||
typedef std::lock_guard<std::mutex> lock;
|
typedef std::lock_guard<std::mutex> lock;
|
||||||
std::mutex rng_mutex;
|
|
||||||
|
|
||||||
|
std::mutex rng_mutex;
|
||||||
uint8_t rng_entropy[64];
|
uint8_t rng_entropy[64];
|
||||||
void rng(uint8_t* seed) {
|
|
||||||
|
extern "C" {
|
||||||
|
void rng(uint8_t* seed) {
|
||||||
// Set the first half to the seed
|
// Set the first half to the seed
|
||||||
memcpy(rng_entropy, seed, 32);
|
memcpy(rng_entropy, seed, 32);
|
||||||
// Set the second half to the hash of a DST to ensure a lack of collisions
|
// 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]);
|
crypto::cn_fast_hash("RNG_entropy_seed", 16, (char*) &rng_entropy[32]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C" {
|
extern "C" void monero_wide_reduce(uint8_t* value);
|
||||||
void generate_random_bytes_not_thread_safe(size_t n, uint8_t* value) {
|
namespace crypto {
|
||||||
|
void generate_random_bytes_not_thread_safe(size_t n, void* value) {
|
||||||
size_t written = 0;
|
size_t written = 0;
|
||||||
while (written != n) {
|
while (written != n) {
|
||||||
uint8_t hash[32];
|
uint8_t hash[32];
|
||||||
crypto::cn_fast_hash(rng_entropy, 64, (char*) hash);
|
crypto::cn_fast_hash(rng_entropy, 64, (char*) hash);
|
||||||
// Step the RNG by setting the latter half to the most recent result
|
// 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
|
// Does not leak the RNG, even if the values are leaked (which they are
|
||||||
// the first half remaining constant and undisclosed
|
// expected to be) due to the first half remaining constant and
|
||||||
|
// undisclosed
|
||||||
memcpy(&rng_entropy[32], hash, 32);
|
memcpy(&rng_entropy[32], hash, 32);
|
||||||
|
|
||||||
size_t next = n - written;
|
size_t next = n - written;
|
||||||
if (next > 32) {
|
if (next > 32) {
|
||||||
next = 32;
|
next = 32;
|
||||||
}
|
}
|
||||||
memcpy(&value[written], hash, next);
|
memcpy(&((uint8_t*) value)[written], hash, next);
|
||||||
written += 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) {
|
void c_hash_to_point(uint8_t* point) {
|
||||||
rct::key key_point;
|
rct::key key_point;
|
||||||
ge_p3 e_p3;
|
ge_p3 e_p3;
|
||||||
|
@ -62,16 +76,24 @@ extern "C" {
|
||||||
std::stringstream ss;
|
std::stringstream ss;
|
||||||
binary_archive<true> ba(ss);
|
binary_archive<true> ba(ss);
|
||||||
::serialization::serialize(ba, bp);
|
::serialization::serialize(ba, bp);
|
||||||
uint8_t* res = (uint8_t*) calloc(ss.str().size(), 1); // malloc would also work
|
uint8_t* res = (uint8_t*) calloc(ss.str().size(), 1);
|
||||||
memcpy(res, ss.str().data(), ss.str().size());
|
memcpy(res, ss.str().data(), ss.str().size());
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool c_verify_bp(uint8_t* seed, uint s_len, uint8_t* s, uint8_t c_len, uint8_t* c) {
|
bool c_verify_bp(
|
||||||
// BPs are batch verified which use RNG based challenges to ensure individual integrity
|
uint8_t* seed,
|
||||||
// That's why this must also have control over RNG, to prevent interrupting multisig signing
|
uint s_len,
|
||||||
// while not using known seeds. Considering this doesn't actually define a batch,
|
uint8_t* s,
|
||||||
// and it's only verifying a single BP, it'd probably be fine, but...
|
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);
|
lock guard(rng_mutex);
|
||||||
rng(seed);
|
rng(seed);
|
||||||
|
|
||||||
|
@ -94,7 +116,15 @@ extern "C" {
|
||||||
try { return rct::bulletproof_VERIFY(bp); } catch(...) { return false; }
|
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) {
|
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;
|
rct::clsag clsag;
|
||||||
std::stringstream ss;
|
std::stringstream ss;
|
||||||
std::string str;
|
std::string str;
|
||||||
|
@ -121,6 +151,8 @@ extern "C" {
|
||||||
rct::key msg;
|
rct::key msg;
|
||||||
memcpy(msg.bytes, m, 32);
|
memcpy(msg.bytes, m, 32);
|
||||||
|
|
||||||
try { return verRctCLSAGSimple(msg, clsag, keys, pseudo_out); } catch(...) { return false; }
|
try {
|
||||||
|
return verRctCLSAGSimple(msg, clsag, keys, pseudo_out);
|
||||||
|
} catch(...) { return false; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,10 @@
|
||||||
|
use std::slice;
|
||||||
|
|
||||||
use lazy_static::lazy_static;
|
use lazy_static::lazy_static;
|
||||||
use rand_core::{RngCore, CryptoRng};
|
use rand_core::{RngCore, CryptoRng};
|
||||||
|
|
||||||
|
use subtle::ConstantTimeEq;
|
||||||
|
|
||||||
use tiny_keccak::{Hasher, Keccak};
|
use tiny_keccak::{Hasher, Keccak};
|
||||||
|
|
||||||
use curve25519_dalek::{
|
use curve25519_dalek::{
|
||||||
|
@ -32,6 +36,29 @@ lazy_static! {
|
||||||
static ref H_TABLE: EdwardsBasepointTable = EdwardsBasepointTable::create(&*H);
|
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)]
|
#[allow(non_snake_case)]
|
||||||
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
|
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
|
||||||
pub struct Commitment {
|
pub struct Commitment {
|
||||||
|
|
|
@ -1,3 +0,0 @@
|
||||||
fn main() {
|
|
||||||
println!("cargo:rustc-link-arg=-zmuldefs");
|
|
||||||
}
|
|
Loading…
Reference in a new issue