mirror of
https://github.com/serai-dex/serai.git
synced 2025-03-22 15:19:06 +00:00
Generate Bulletproofs(+) generators at compile time
Creates a new monero-generators crate so the monero crate can run the code in question at build time. Saves several seconds from running the tests. Closes https://github.com/serai-dex/serai/issues/101.
This commit is contained in:
parent
577fe99a08
commit
603a3f8c9f
19 changed files with 274 additions and 133 deletions
14
Cargo.lock
generated
14
Cargo.lock
generated
|
@ -4583,6 +4583,18 @@ dependencies = [
|
||||||
"serde",
|
"serde",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "monero-generators"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"curve25519-dalek 3.2.0",
|
||||||
|
"dalek-ff-group",
|
||||||
|
"group",
|
||||||
|
"lazy_static",
|
||||||
|
"subtle",
|
||||||
|
"tiny-keccak",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "monero-serai"
|
name = "monero-serai"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
|
@ -4600,6 +4612,7 @@ dependencies = [
|
||||||
"modular-frost",
|
"modular-frost",
|
||||||
"monero",
|
"monero",
|
||||||
"monero-epee-bin-serde",
|
"monero-epee-bin-serde",
|
||||||
|
"monero-generators",
|
||||||
"multiexp",
|
"multiexp",
|
||||||
"rand 0.8.5",
|
"rand 0.8.5",
|
||||||
"rand_chacha 0.3.1",
|
"rand_chacha 0.3.1",
|
||||||
|
@ -4608,7 +4621,6 @@ dependencies = [
|
||||||
"reqwest",
|
"reqwest",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"sha2 0.10.2",
|
|
||||||
"subtle",
|
"subtle",
|
||||||
"thiserror",
|
"thiserror",
|
||||||
"tiny-keccak",
|
"tiny-keccak",
|
||||||
|
|
|
@ -9,6 +9,7 @@ members = [
|
||||||
"crypto/frost",
|
"crypto/frost",
|
||||||
|
|
||||||
"coins/ethereum",
|
"coins/ethereum",
|
||||||
|
"coins/monero/generators",
|
||||||
"coins/monero",
|
"coins/monero",
|
||||||
|
|
||||||
"processor",
|
"processor",
|
||||||
|
|
1
coins/monero/.gitignore
vendored
Normal file
1
coins/monero/.gitignore
vendored
Normal file
|
@ -0,0 +1 @@
|
||||||
|
.generators
|
|
@ -32,6 +32,8 @@ 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 }
|
||||||
|
|
||||||
|
monero-generators = { path = "generators" }
|
||||||
|
|
||||||
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"
|
||||||
|
@ -45,6 +47,9 @@ reqwest = { version = "0.11", features = ["json"] }
|
||||||
[features]
|
[features]
|
||||||
multisig = ["rand_chacha", "blake2", "transcript", "frost", "dleq"]
|
multisig = ["rand_chacha", "blake2", "transcript", "frost", "dleq"]
|
||||||
|
|
||||||
|
[build-dependencies]
|
||||||
|
dalek-ff-group = { path = "../../crypto/dalek-ff-group" }
|
||||||
|
monero-generators = { path = "generators" }
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
sha2 = "0.10"
|
|
||||||
tokio = { version = "1", features = ["full"] }
|
tokio = { version = "1", features = ["full"] }
|
||||||
|
|
67
coins/monero/build.rs
Normal file
67
coins/monero/build.rs
Normal file
|
@ -0,0 +1,67 @@
|
||||||
|
use std::{
|
||||||
|
io::Write,
|
||||||
|
path::Path,
|
||||||
|
fs::{File, remove_file},
|
||||||
|
};
|
||||||
|
|
||||||
|
use dalek_ff_group::EdwardsPoint;
|
||||||
|
|
||||||
|
use monero_generators::bulletproofs_generators;
|
||||||
|
|
||||||
|
fn serialize(generators_string: &mut String, points: &[EdwardsPoint]) {
|
||||||
|
for generator in points {
|
||||||
|
generators_string.extend(
|
||||||
|
format!(
|
||||||
|
"
|
||||||
|
dalek_ff_group::EdwardsPoint(
|
||||||
|
curve25519_dalek::edwards::CompressedEdwardsY({:?}).decompress().unwrap()
|
||||||
|
),
|
||||||
|
",
|
||||||
|
generator.compress().to_bytes()
|
||||||
|
)
|
||||||
|
.chars(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn generators(prefix: &'static str, path: &str) {
|
||||||
|
let generators = bulletproofs_generators(prefix.as_bytes());
|
||||||
|
#[allow(non_snake_case)]
|
||||||
|
let mut G_str = "".to_string();
|
||||||
|
serialize(&mut G_str, &generators.G);
|
||||||
|
#[allow(non_snake_case)]
|
||||||
|
let mut H_str = "".to_string();
|
||||||
|
serialize(&mut H_str, &generators.H);
|
||||||
|
|
||||||
|
let path = Path::new(".generators").join(path);
|
||||||
|
let _ = remove_file(&path);
|
||||||
|
File::create(&path)
|
||||||
|
.unwrap()
|
||||||
|
.write_all(
|
||||||
|
format!(
|
||||||
|
"
|
||||||
|
lazy_static! {{
|
||||||
|
static ref GENERATORS: Generators = Generators {{
|
||||||
|
G: [
|
||||||
|
{}
|
||||||
|
],
|
||||||
|
H: [
|
||||||
|
{}
|
||||||
|
],
|
||||||
|
}};
|
||||||
|
}}
|
||||||
|
",
|
||||||
|
G_str, H_str,
|
||||||
|
)
|
||||||
|
.as_bytes(),
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
// For some reason, filtering off .generators does not work. This prevents re-building overall
|
||||||
|
println!("cargo:rerun-if-changed=build.rs");
|
||||||
|
|
||||||
|
generators("bulletproof", "generators.rs");
|
||||||
|
generators("bulletproof_plus", "generators_plus.rs");
|
||||||
|
}
|
19
coins/monero/generators/Cargo.toml
Normal file
19
coins/monero/generators/Cargo.toml
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
[package]
|
||||||
|
name = "monero-generators"
|
||||||
|
version = "0.1.0"
|
||||||
|
description = "Monero's hash_to_point and generators"
|
||||||
|
license = "MIT"
|
||||||
|
authors = ["Luke Parker <lukeparker5132@gmail.com>"]
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
lazy_static = "1"
|
||||||
|
|
||||||
|
subtle = "2.4"
|
||||||
|
|
||||||
|
tiny-keccak = { version = "2", features = ["keccak"] }
|
||||||
|
|
||||||
|
curve25519-dalek = { version = "3", features = ["std"] }
|
||||||
|
|
||||||
|
group = { version = "0.12" }
|
||||||
|
dalek-ff-group = { path = "../../../crypto/dalek-ff-group" }
|
21
coins/monero/generators/LICENSE
Normal file
21
coins/monero/generators/LICENSE
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2022 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.
|
51
coins/monero/generators/src/hash_to_point.rs
Normal file
51
coins/monero/generators/src/hash_to_point.rs
Normal file
|
@ -0,0 +1,51 @@
|
||||||
|
use subtle::ConditionallySelectable;
|
||||||
|
|
||||||
|
use curve25519_dalek::edwards::{EdwardsPoint, CompressedEdwardsY};
|
||||||
|
|
||||||
|
use group::ff::{Field, PrimeField};
|
||||||
|
use dalek_ff_group::field::FieldElement;
|
||||||
|
|
||||||
|
use crate::hash;
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub fn hash_to_point(bytes: [u8; 32]) -> EdwardsPoint {
|
||||||
|
#[allow(non_snake_case)]
|
||||||
|
let A = FieldElement::from(486662u64);
|
||||||
|
|
||||||
|
let v = FieldElement::from_square(hash(&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;
|
||||||
|
|
||||||
|
CompressedEdwardsY(bytes).decompress().unwrap().mul_by_cofactor()
|
||||||
|
}
|
61
coins/monero/generators/src/lib.rs
Normal file
61
coins/monero/generators/src/lib.rs
Normal file
|
@ -0,0 +1,61 @@
|
||||||
|
use lazy_static::lazy_static;
|
||||||
|
|
||||||
|
use tiny_keccak::{Hasher, Keccak};
|
||||||
|
|
||||||
|
use curve25519_dalek::{
|
||||||
|
constants::ED25519_BASEPOINT_POINT,
|
||||||
|
edwards::{EdwardsPoint as DalekPoint, CompressedEdwardsY},
|
||||||
|
};
|
||||||
|
|
||||||
|
use group::Group;
|
||||||
|
use dalek_ff_group::EdwardsPoint;
|
||||||
|
|
||||||
|
mod varint;
|
||||||
|
use varint::write_varint;
|
||||||
|
|
||||||
|
mod hash_to_point;
|
||||||
|
pub use hash_to_point::hash_to_point;
|
||||||
|
|
||||||
|
fn hash(data: &[u8]) -> [u8; 32] {
|
||||||
|
let mut keccak = Keccak::v256();
|
||||||
|
keccak.update(data);
|
||||||
|
let mut res = [0; 32];
|
||||||
|
keccak.finalize(&mut res);
|
||||||
|
res
|
||||||
|
}
|
||||||
|
|
||||||
|
lazy_static! {
|
||||||
|
pub static ref H: DalekPoint =
|
||||||
|
CompressedEdwardsY(hash(&ED25519_BASEPOINT_POINT.compress().to_bytes()))
|
||||||
|
.decompress()
|
||||||
|
.unwrap()
|
||||||
|
.mul_by_cofactor();
|
||||||
|
}
|
||||||
|
|
||||||
|
const MAX_M: usize = 16;
|
||||||
|
const N: usize = 64;
|
||||||
|
const MAX_MN: usize = MAX_M * N;
|
||||||
|
|
||||||
|
#[allow(non_snake_case)]
|
||||||
|
pub struct Generators {
|
||||||
|
pub G: [EdwardsPoint; MAX_MN],
|
||||||
|
pub H: [EdwardsPoint; MAX_MN],
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn bulletproofs_generators(prefix: &'static [u8]) -> Generators {
|
||||||
|
let mut res =
|
||||||
|
Generators { G: [EdwardsPoint::identity(); MAX_MN], H: [EdwardsPoint::identity(); MAX_MN] };
|
||||||
|
for i in 0 .. MAX_MN {
|
||||||
|
let i = 2 * i;
|
||||||
|
|
||||||
|
let mut even = H.compress().to_bytes().to_vec();
|
||||||
|
even.extend(prefix);
|
||||||
|
let mut odd = even.clone();
|
||||||
|
|
||||||
|
write_varint(&i.try_into().unwrap(), &mut even).unwrap();
|
||||||
|
write_varint(&(i + 1).try_into().unwrap(), &mut odd).unwrap();
|
||||||
|
res.H[i / 2] = EdwardsPoint(hash_to_point(hash(&even)));
|
||||||
|
res.G[i / 2] = EdwardsPoint(hash_to_point(hash(&odd)));
|
||||||
|
}
|
||||||
|
res
|
||||||
|
}
|
16
coins/monero/generators/src/varint.rs
Normal file
16
coins/monero/generators/src/varint.rs
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
use std::io;
|
||||||
|
|
||||||
|
const VARINT_CONTINUATION_MASK: u8 = 0b1000_0000;
|
||||||
|
pub(crate) fn write_varint<W: io::Write>(varint: &u64, w: &mut W) -> io::Result<()> {
|
||||||
|
let mut varint = *varint;
|
||||||
|
while {
|
||||||
|
let mut b = u8::try_from(varint & u64::from(!VARINT_CONTINUATION_MASK)).unwrap();
|
||||||
|
varint >>= 7;
|
||||||
|
if varint != 0 {
|
||||||
|
b |= VARINT_CONTINUATION_MASK;
|
||||||
|
}
|
||||||
|
w.write_all(&[b])?;
|
||||||
|
varint != 0
|
||||||
|
} {}
|
||||||
|
Ok(())
|
||||||
|
}
|
|
@ -6,11 +6,13 @@ use zeroize::{Zeroize, ZeroizeOnDrop};
|
||||||
use tiny_keccak::{Hasher, Keccak};
|
use tiny_keccak::{Hasher, Keccak};
|
||||||
|
|
||||||
use curve25519_dalek::{
|
use curve25519_dalek::{
|
||||||
constants::{ED25519_BASEPOINT_POINT, ED25519_BASEPOINT_TABLE},
|
constants::ED25519_BASEPOINT_TABLE,
|
||||||
scalar::Scalar,
|
scalar::Scalar,
|
||||||
edwards::{EdwardsPoint, EdwardsBasepointTable, CompressedEdwardsY},
|
edwards::{EdwardsPoint, EdwardsBasepointTable},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
pub use monero_generators::H;
|
||||||
|
|
||||||
#[cfg(feature = "multisig")]
|
#[cfg(feature = "multisig")]
|
||||||
pub mod frost;
|
pub mod frost;
|
||||||
|
|
||||||
|
@ -54,11 +56,6 @@ impl Protocol {
|
||||||
}
|
}
|
||||||
|
|
||||||
lazy_static! {
|
lazy_static! {
|
||||||
static ref H: EdwardsPoint =
|
|
||||||
CompressedEdwardsY(hash(&ED25519_BASEPOINT_POINT.compress().to_bytes()))
|
|
||||||
.decompress()
|
|
||||||
.unwrap()
|
|
||||||
.mul_by_cofactor();
|
|
||||||
static ref H_TABLE: EdwardsBasepointTable = EdwardsBasepointTable::create(&H);
|
static ref H_TABLE: EdwardsBasepointTable = EdwardsBasepointTable::create(&H);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -13,10 +13,9 @@ use dalek_ff_group::{Scalar, EdwardsPoint};
|
||||||
|
|
||||||
use multiexp::multiexp as multiexp_const;
|
use multiexp::multiexp as multiexp_const;
|
||||||
|
|
||||||
use crate::{
|
pub(crate) use monero_generators::Generators;
|
||||||
H as DALEK_H, Commitment, hash, hash_to_scalar as dalek_hash,
|
|
||||||
ringct::hash_to_point::raw_hash_to_point, serialize::write_varint,
|
use crate::{H as DALEK_H, Commitment, hash_to_scalar as dalek_hash};
|
||||||
};
|
|
||||||
pub(crate) use crate::ringct::bulletproofs::scalar_vector::*;
|
pub(crate) use crate::ringct::bulletproofs::scalar_vector::*;
|
||||||
|
|
||||||
// Bring things into ff/group
|
// Bring things into ff/group
|
||||||
|
@ -33,29 +32,6 @@ pub(crate) fn hash_to_scalar(data: &[u8]) -> Scalar {
|
||||||
pub(crate) const MAX_M: usize = 16;
|
pub(crate) const MAX_M: usize = 16;
|
||||||
pub(crate) const LOG_N: usize = 6; // 2 << 6 == N
|
pub(crate) const LOG_N: usize = 6; // 2 << 6 == N
|
||||||
pub(crate) const N: usize = 64;
|
pub(crate) const N: usize = 64;
|
||||||
pub(crate) const MAX_MN: usize = MAX_M * N;
|
|
||||||
|
|
||||||
pub(crate) struct Generators {
|
|
||||||
pub(crate) G: Vec<EdwardsPoint>,
|
|
||||||
pub(crate) H: Vec<EdwardsPoint>,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn generators_core(prefix: &'static [u8]) -> Generators {
|
|
||||||
let mut res = Generators { G: Vec::with_capacity(MAX_MN), H: Vec::with_capacity(MAX_MN) };
|
|
||||||
for i in 0 .. MAX_MN {
|
|
||||||
let i = 2 * i;
|
|
||||||
|
|
||||||
let mut even = (*H).compress().to_bytes().to_vec();
|
|
||||||
even.extend(prefix);
|
|
||||||
let mut odd = even.clone();
|
|
||||||
|
|
||||||
write_varint(&i.try_into().unwrap(), &mut even).unwrap();
|
|
||||||
write_varint(&(i + 1).try_into().unwrap(), &mut odd).unwrap();
|
|
||||||
res.H.push(EdwardsPoint(raw_hash_to_point(hash(&even))));
|
|
||||||
res.G.push(EdwardsPoint(raw_hash_to_point(hash(&odd))));
|
|
||||||
}
|
|
||||||
res
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn prove_multiexp(pairs: &[(Scalar, EdwardsPoint)]) -> EdwardsPoint {
|
pub(crate) fn prove_multiexp(pairs: &[(Scalar, EdwardsPoint)]) -> EdwardsPoint {
|
||||||
multiexp_const(pairs) * *INV_EIGHT
|
multiexp_const(pairs) * *INV_EIGHT
|
||||||
|
@ -153,12 +129,6 @@ lazy_static! {
|
||||||
pub(crate) static ref TWO_N: ScalarVector = ScalarVector::powers(Scalar::from(2u8), N);
|
pub(crate) static ref TWO_N: ScalarVector = ScalarVector::powers(Scalar::from(2u8), N);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn init() {
|
|
||||||
let _ = &*INV_EIGHT;
|
|
||||||
let _ = &*H;
|
|
||||||
let _ = &*TWO_N;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn challenge_products(w: &[Scalar], winv: &[Scalar]) -> Vec<Scalar> {
|
pub(crate) fn challenge_products(w: &[Scalar], winv: &[Scalar]) -> Vec<Scalar> {
|
||||||
let mut products = vec![Scalar::zero(); 1 << w.len()];
|
let mut products = vec![Scalar::zero(); 1 << w.len()];
|
||||||
products[0] = winv[0];
|
products[0] = winv[0];
|
||||||
|
|
|
@ -43,14 +43,6 @@ impl Bulletproofs {
|
||||||
len + clawback
|
len + clawback
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn init(plus: bool) {
|
|
||||||
if !plus {
|
|
||||||
OriginalStruct::init();
|
|
||||||
} else {
|
|
||||||
PlusStruct::init();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn prove<R: RngCore + CryptoRng>(
|
pub fn prove<R: RngCore + CryptoRng>(
|
||||||
rng: &mut R,
|
rng: &mut R,
|
||||||
outputs: &[Commitment],
|
outputs: &[Commitment],
|
||||||
|
|
|
@ -12,8 +12,9 @@ use multiexp::BatchVerifier;
|
||||||
|
|
||||||
use crate::{Commitment, ringct::bulletproofs::core::*};
|
use crate::{Commitment, ringct::bulletproofs::core::*};
|
||||||
|
|
||||||
|
include!("../../../.generators/generators.rs");
|
||||||
|
|
||||||
lazy_static! {
|
lazy_static! {
|
||||||
static ref GENERATORS: Generators = generators_core(b"bulletproof");
|
|
||||||
static ref ONE_N: ScalarVector = ScalarVector(vec![Scalar::one(); N]);
|
static ref ONE_N: ScalarVector = ScalarVector(vec![Scalar::one(); N]);
|
||||||
static ref IP12: Scalar = inner_product(&ONE_N, &TWO_N);
|
static ref IP12: Scalar = inner_product(&ONE_N, &TWO_N);
|
||||||
}
|
}
|
||||||
|
@ -34,13 +35,6 @@ pub struct OriginalStruct {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl OriginalStruct {
|
impl OriginalStruct {
|
||||||
pub(crate) fn init() {
|
|
||||||
init();
|
|
||||||
let _ = &*GENERATORS;
|
|
||||||
let _ = &*ONE_N;
|
|
||||||
let _ = &*IP12;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn prove<R: RngCore + CryptoRng>(
|
pub(crate) fn prove<R: RngCore + CryptoRng>(
|
||||||
rng: &mut R,
|
rng: &mut R,
|
||||||
commitments: &[Commitment],
|
commitments: &[Commitment],
|
||||||
|
|
|
@ -15,8 +15,9 @@ use crate::{
|
||||||
ringct::{hash_to_point::raw_hash_to_point, bulletproofs::core::*},
|
ringct::{hash_to_point::raw_hash_to_point, bulletproofs::core::*},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
include!("../../../.generators/generators_plus.rs");
|
||||||
|
|
||||||
lazy_static! {
|
lazy_static! {
|
||||||
static ref GENERATORS: Generators = generators_core(b"bulletproof_plus");
|
|
||||||
static ref TRANSCRIPT: [u8; 32] =
|
static ref TRANSCRIPT: [u8; 32] =
|
||||||
EdwardsPoint(raw_hash_to_point(hash(b"bulletproof_plus_transcript"))).compress().to_bytes();
|
EdwardsPoint(raw_hash_to_point(hash(b"bulletproof_plus_transcript"))).compress().to_bytes();
|
||||||
}
|
}
|
||||||
|
@ -52,12 +53,6 @@ pub struct PlusStruct {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PlusStruct {
|
impl PlusStruct {
|
||||||
pub(crate) fn init() {
|
|
||||||
init();
|
|
||||||
let _ = &*GENERATORS;
|
|
||||||
let _ = &*TRANSCRIPT;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn prove<R: RngCore + CryptoRng>(
|
pub(crate) fn prove<R: RngCore + CryptoRng>(
|
||||||
rng: &mut R,
|
rng: &mut R,
|
||||||
commitments: &[Commitment],
|
commitments: &[Commitment],
|
||||||
|
|
|
@ -1,54 +1,6 @@
|
||||||
use subtle::ConditionallySelectable;
|
use curve25519_dalek::edwards::EdwardsPoint;
|
||||||
|
|
||||||
use curve25519_dalek::edwards::{CompressedEdwardsY, EdwardsPoint};
|
pub(crate) use monero_generators::{hash_to_point as raw_hash_to_point};
|
||||||
|
|
||||||
use group::ff::{Field, PrimeField};
|
|
||||||
use dalek_ff_group::field::FieldElement;
|
|
||||||
|
|
||||||
use crate::hash;
|
|
||||||
|
|
||||||
#[allow(dead_code)]
|
|
||||||
pub(crate) fn raw_hash_to_point(bytes: [u8; 32]) -> EdwardsPoint {
|
|
||||||
#[allow(non_snake_case)]
|
|
||||||
let A = FieldElement::from(486662u64);
|
|
||||||
|
|
||||||
let v = FieldElement::from_square(hash(&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;
|
|
||||||
|
|
||||||
CompressedEdwardsY(bytes).decompress().unwrap().mul_by_cofactor()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn hash_to_point(key: EdwardsPoint) -> EdwardsPoint {
|
pub fn hash_to_point(key: EdwardsPoint) -> EdwardsPoint {
|
||||||
raw_hash_to_point(key.compress().to_bytes())
|
raw_hash_to_point(key.compress().to_bytes())
|
||||||
|
|
|
@ -57,12 +57,7 @@ fn bulletproofs_vector() {
|
||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! bulletproofs_tests {
|
macro_rules! bulletproofs_tests {
|
||||||
($init: ident, $name: ident, $max: ident, $plus: literal) => {
|
($name: ident, $max: ident, $plus: literal) => {
|
||||||
#[test]
|
|
||||||
fn $init() {
|
|
||||||
Bulletproofs::init($plus);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn $name() {
|
fn $name() {
|
||||||
// Create Bulletproofs for all possible output quantities
|
// Create Bulletproofs for all possible output quantities
|
||||||
|
@ -93,5 +88,5 @@ macro_rules! bulletproofs_tests {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
bulletproofs_tests!(bulletproofs_init, bulletproofs, bulletproofs_max, false);
|
bulletproofs_tests!(bulletproofs, bulletproofs_max, false);
|
||||||
bulletproofs_tests!(bulletproofs_plus_init, bulletproofs_plus, bulletproofs_plus_max, true);
|
bulletproofs_tests!(bulletproofs_plus, bulletproofs_plus_max, true);
|
||||||
|
|
|
@ -7,7 +7,6 @@ use transcript::RecommendedTranscript;
|
||||||
use frost::{curve::Ed25519, FrostKeys};
|
use frost::{curve::Ed25519, FrostKeys};
|
||||||
|
|
||||||
use monero_serai::{
|
use monero_serai::{
|
||||||
ringct::bulletproofs::Bulletproofs,
|
|
||||||
transaction::Transaction,
|
transaction::Transaction,
|
||||||
rpc::Rpc,
|
rpc::Rpc,
|
||||||
wallet::{
|
wallet::{
|
||||||
|
@ -69,14 +68,7 @@ pub struct Monero {
|
||||||
|
|
||||||
impl Monero {
|
impl Monero {
|
||||||
pub async fn new(url: String) -> Monero {
|
pub async fn new(url: String) -> Monero {
|
||||||
let view = view_key::<Monero>(0).0;
|
Monero { rpc: Rpc::new(url), view: view_key::<Monero>(0).0 }
|
||||||
let res = Monero { rpc: Rpc::new(url), view };
|
|
||||||
|
|
||||||
// Initialize Bulletproofs now to prevent the first call from taking several seconds
|
|
||||||
// TODO: Do this for both, unless we're sure we're only working on a single protocol
|
|
||||||
Bulletproofs::init(res.rpc.get_protocol().await.unwrap().bp_plus());
|
|
||||||
|
|
||||||
res
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn view_pair(&self, spend: dfg::EdwardsPoint) -> ViewPair {
|
fn view_pair(&self, spend: dfg::EdwardsPoint) -> ViewPair {
|
||||||
|
|
|
@ -86,7 +86,7 @@ impl CoinDb for MemCoinDb {
|
||||||
fn add_output<O: Output>(&mut self, output: &O) -> bool {
|
fn add_output<O: Output>(&mut self, output: &O) -> bool {
|
||||||
// This would be insecure as we're indexing by ID and this will replace the output as a whole
|
// This would be insecure as we're indexing by ID and this will replace the output as a whole
|
||||||
// Multiple outputs may have the same ID in edge cases such as Monero, where outputs are ID'd
|
// Multiple outputs may have the same ID in edge cases such as Monero, where outputs are ID'd
|
||||||
// by key image, not by hash + index
|
// by output key, not by hash + index
|
||||||
// self.outputs.insert(output.id(), output).is_some()
|
// self.outputs.insert(output.id(), output).is_some()
|
||||||
let id = output.id().as_ref().to_vec();
|
let id = output.id().as_ref().to_vec();
|
||||||
if self.outputs.contains_key(&id) {
|
if self.outputs.contains_key(&id) {
|
||||||
|
|
Loading…
Reference in a new issue