Skip to content

Commit

Permalink
Rename the coins folder to networks (serai-dex#583)
Browse files Browse the repository at this point in the history
* Rename the coins folder to networks

Ethereum isn't a coin. It's a network.

Resolves serai-dex#357.

* More renames of coins -> networks in orchestration

* Correct paths in tests/

* cargo fmt
  • Loading branch information
kayabaNerve authored Jul 18, 2024
0 parents commit 1a3719e
Show file tree
Hide file tree
Showing 150 changed files with 59,912 additions and 0 deletions.
57 changes: 57 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
[package]
name = "monero-serai"
version = "0.1.4-alpha"
description = "A modern Monero transaction library"
license = "MIT"
repository = "https://github.com/serai-dex/serai/tree/develop/networks/monero"
authors = ["Luke Parker <[email protected]>"]
edition = "2021"
rust-version = "1.79"

[package.metadata.docs.rs]
all-features = true
rustdoc-args = ["--cfg", "docsrs"]

[lints]
workspace = true

[dependencies]
std-shims = { path = "../../common/std-shims", version = "^0.1.1", default-features = false }

zeroize = { version = "^1.5", default-features = false, features = ["zeroize_derive"] }

curve25519-dalek = { version = "4", default-features = false, features = ["alloc", "zeroize"] }

monero-io = { path = "io", version = "0.1", default-features = false }
monero-generators = { path = "generators", version = "0.4", default-features = false }
monero-primitives = { path = "primitives", version = "0.1", default-features = false }
monero-mlsag = { path = "ringct/mlsag", version = "0.1", default-features = false }
monero-clsag = { path = "ringct/clsag", version = "0.1", default-features = false }
monero-borromean = { path = "ringct/borromean", version = "0.1", default-features = false }
monero-bulletproofs = { path = "ringct/bulletproofs", version = "0.1", default-features = false }

hex-literal = "0.4"

[dev-dependencies]
hex = { version = "0.4", default-features = false, features = ["std"] }
serde = { version = "1", default-features = false, features = ["std", "derive"] }
serde_json = { version = "1", default-features = false, features = ["std"] }

[features]
std = [
"std-shims/std",

"zeroize/std",

"monero-io/std",
"monero-generators/std",
"monero-primitives/std",
"monero-mlsag/std",
"monero-clsag/std",
"monero-borromean/std",
"monero-bulletproofs/std",
]

compile-time-generators = ["curve25519-dalek/precomputed-tables", "monero-bulletproofs/compile-time-generators"]
multisig = ["monero-clsag/multisig", "std"]
default = ["std", "compile-time-generators"]
21 changes: 21 additions & 0 deletions LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
MIT License

Copyright (c) 2022-2024 Luke Parker

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
28 changes: 28 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# monero-serai

A modern Monero transaction library. It provides a modern, Rust-friendly view of
the Monero protocol.

This library is usable under no-std when the `std` feature (on by default) is
disabled.

### Wallet Functionality

monero-serai originally included wallet functionality. That has been moved to
monero-wallet.

### Purpose and Support

monero-serai was written for Serai, a decentralized exchange aiming to support
Monero. Despite this, monero-serai is intended to be a widely usable library,
accurate to Monero. monero-serai guarantees the functionality needed for Serai,
yet does not include any functionality specific to Serai.

### Cargo Features

- `std` (on by default): Enables `std` (and with it, more efficient internal
implementations).
- `compile-time-generators` (on by default): Derives the generators at
compile-time so they don't need to be derived at runtime. This is recommended
if program size doesn't need to be kept minimal.
- `multisig`: Enables the `multisig` feature for all dependencies.
46 changes: 46 additions & 0 deletions generators/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
[package]
name = "monero-generators"
version = "0.4.0"
description = "Monero's hash to point function and generators"
license = "MIT"
repository = "https://github.com/serai-dex/serai/tree/develop/networks/monero/generators"
authors = ["Luke Parker <[email protected]>"]
edition = "2021"

[package.metadata.docs.rs]
all-features = true
rustdoc-args = ["--cfg", "docsrs"]

[lints]
workspace = true

[dependencies]
std-shims = { path = "../../../common/std-shims", version = "^0.1.1", default-features = false }

subtle = { version = "^2.4", default-features = false }

sha3 = { version = "0.10", default-features = false }
curve25519-dalek = { version = "4", default-features = false, features = ["alloc", "zeroize"] }

group = { version = "0.13", default-features = false }
dalek-ff-group = { path = "../../../crypto/dalek-ff-group", version = "0.4", default-features = false }

monero-io = { path = "../io", version = "0.1", default-features = false }

[dev-dependencies]
hex = "0.4"

[features]
std = [
"std-shims/std",

"subtle/std",

"sha3/std",

"group/alloc",
"dalek-ff-group/std",

"monero-io/std"
]
default = ["std"]
21 changes: 21 additions & 0 deletions generators/LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
MIT License

Copyright (c) 2022-2024 Luke Parker

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
13 changes: 13 additions & 0 deletions generators/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# Monero Generators

Generators used by Monero in both its Pedersen commitments and Bulletproofs(+).
An implementation of Monero's `hash_to_ec` is included, as needed to generate
the generators.

This library is usable under no-std when the `std` feature (on by default) is
disabled.

### Cargo Features

- `std` (on by default): Enables `std` (and with it, more efficient internal
implementations).
53 changes: 53 additions & 0 deletions generators/src/hash_to_point.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
use subtle::ConditionallySelectable;

use curve25519_dalek::edwards::EdwardsPoint;

use group::ff::{Field, PrimeField};
use dalek_ff_group::FieldElement;

use monero_io::decompress_point;

use crate::keccak256;

/// Monero's `hash_to_ec` function.
pub fn hash_to_point(bytes: [u8; 32]) -> EdwardsPoint {
#[allow(non_snake_case)]
let A = FieldElement::from(486662u64);

let v = FieldElement::from_square(keccak256(&bytes)).double();
let w = v + FieldElement::ONE;
let x = w.square() + (-A.square() * v);

// This isn't the complete X, yet its initial value
// We don't calculate the full X, and instead solely calculate Y, letting dalek reconstruct X
// While inefficient, it solves API boundaries and reduces the amount of work done here
#[allow(non_snake_case)]
let X = {
let u = w;
let v = x;
let v3 = v * v * v;
let uv3 = u * v3;
let v7 = v3 * v3 * v;
let uv7 = u * v7;
uv3 * uv7.pow((-FieldElement::from(5u8)) * FieldElement::from(8u8).invert().unwrap())
};
let x = X.square() * x;

let y = w - x;
let non_zero_0 = !y.is_zero();
let y_if_non_zero_0 = w + x;
let sign = non_zero_0 & (!y_if_non_zero_0.is_zero());

let mut z = -A;
z *= FieldElement::conditional_select(&v, &FieldElement::from(1u8), sign);
#[allow(non_snake_case)]
let Z = z + w;
#[allow(non_snake_case)]
let mut Y = z - w;

Y *= Z.invert().unwrap();
let mut bytes = Y.to_repr();
bytes[31] |= sign.unwrap_u8() << 7;

decompress_point(bytes).unwrap().mul_by_cofactor()
}
94 changes: 94 additions & 0 deletions generators/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
#![cfg_attr(docsrs, feature(doc_auto_cfg))]
#![doc = include_str!("../README.md")]
#![deny(missing_docs)]
#![cfg_attr(not(feature = "std"), no_std)]

use std_shims::{sync::OnceLock, vec::Vec};

use sha3::{Digest, Keccak256};

use curve25519_dalek::{constants::ED25519_BASEPOINT_POINT, edwards::EdwardsPoint};

use monero_io::{write_varint, decompress_point};

mod hash_to_point;
pub use hash_to_point::hash_to_point;

#[cfg(test)]
mod tests;

fn keccak256(data: &[u8]) -> [u8; 32] {
Keccak256::digest(data).into()
}

static H_CELL: OnceLock<EdwardsPoint> = OnceLock::new();
/// Monero's `H` generator.
///
/// Contrary to convention (`G` for values, `H` for randomness), `H` is used by Monero for amounts
/// within Pedersen commitments.
#[allow(non_snake_case)]
pub fn H() -> EdwardsPoint {
*H_CELL.get_or_init(|| {
decompress_point(keccak256(&ED25519_BASEPOINT_POINT.compress().to_bytes()))
.unwrap()
.mul_by_cofactor()
})
}

static H_POW_2_CELL: OnceLock<[EdwardsPoint; 64]> = OnceLock::new();
/// Monero's `H` generator, multiplied by 2**i for i in 1 ..= 64.
///
/// This table is useful when working with amounts, which are u64s.
#[allow(non_snake_case)]
pub fn H_pow_2() -> &'static [EdwardsPoint; 64] {
H_POW_2_CELL.get_or_init(|| {
let mut res = [H(); 64];
for i in 1 .. 64 {
res[i] = res[i - 1] + res[i - 1];
}
res
})
}

/// The maximum amount of commitments provable for within a single range proof.
pub const MAX_COMMITMENTS: usize = 16;
/// The amount of bits a value within a commitment may use.
pub const COMMITMENT_BITS: usize = 64;
/// The logarithm (over 2) of the amount of bits a value within a commitment may use.
pub const LOG_COMMITMENT_BITS: usize = 6; // 2 ** 6 == N

/// Container struct for Bulletproofs(+) generators.
#[allow(non_snake_case)]
pub struct Generators {
/// The G (bold) vector of generators.
pub G: Vec<EdwardsPoint>,
/// The H (bold) vector of generators.
pub H: Vec<EdwardsPoint>,
}

/// Generate generators as needed for Bulletproofs(+), as Monero does.
///
/// Consumers should not call this function ad-hoc, yet call it within a build script or use a
/// once-initialized static.
pub fn bulletproofs_generators(dst: &'static [u8]) -> Generators {
// The maximum amount of bits used within a single range proof.
const MAX_MN: usize = MAX_COMMITMENTS * COMMITMENT_BITS;

let mut preimage = H().compress().to_bytes().to_vec();
preimage.extend(dst);

let mut res = Generators { G: Vec::with_capacity(MAX_MN), H: Vec::with_capacity(MAX_MN) };
for i in 0 .. MAX_MN {
// We generate a pair of generators per iteration
let i = 2 * i;

let mut even = preimage.clone();
write_varint(&i, &mut even).unwrap();
res.H.push(hash_to_point(keccak256(&even)));

let mut odd = preimage.clone();
write_varint(&(i + 1), &mut odd).unwrap();
res.G.push(hash_to_point(keccak256(&odd)));
}
res
}
36 changes: 36 additions & 0 deletions generators/src/tests/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
use crate::{decompress_point, hash_to_point};

#[test]
fn test_vectors() {
// tests.txt file copied from monero repo
// https://github.com/monero-project/monero/
// blob/ac02af92867590ca80b2779a7bbeafa99ff94dcb/tests/crypto/tests.txt
let reader = include_str!("./tests.txt");

for line in reader.lines() {
let mut words = line.split_whitespace();
let command = words.next().unwrap();

match command {
"check_key" => {
let key = words.next().unwrap();
let expected = match words.next().unwrap() {
"true" => true,
"false" => false,
_ => unreachable!("invalid result"),
};

let actual = decompress_point(hex::decode(key).unwrap().try_into().unwrap());
assert_eq!(actual.is_some(), expected);
}
"hash_to_ec" => {
let bytes = words.next().unwrap();
let expected = words.next().unwrap();

let actual = hash_to_point(hex::decode(bytes).unwrap().try_into().unwrap());
assert_eq!(hex::encode(actual.compress().to_bytes()), expected);
}
_ => unreachable!("unknown command"),
}
}
}
Loading

0 comments on commit 1a3719e

Please sign in to comment.