mirror of
https://github.com/serai-dex/serai.git
synced 2025-03-21 06:38:56 +00:00
Add init function for BP statics
Considering they take 7 seconds to generate, thanks to #68, the ability to generate them at the start instead of on first BP is greatly appreciated. Also performs minor cleanups regarding BPs.
This commit is contained in:
parent
9221dbf048
commit
a30568ff57
9 changed files with 68 additions and 24 deletions
|
@ -34,7 +34,7 @@ pub enum Protocol {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Protocol {
|
impl Protocol {
|
||||||
pub(crate) fn ring_len(&self) -> usize {
|
pub fn ring_len(&self) -> usize {
|
||||||
match self {
|
match self {
|
||||||
Protocol::Unsupported => panic!("Unsupported protocol version"),
|
Protocol::Unsupported => panic!("Unsupported protocol version"),
|
||||||
Protocol::v14 => 11,
|
Protocol::v14 => 11,
|
||||||
|
@ -42,7 +42,7 @@ impl Protocol {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn bp_plus(&self) -> bool {
|
pub fn bp_plus(&self) -> bool {
|
||||||
match self {
|
match self {
|
||||||
Protocol::Unsupported => panic!("Unsupported protocol version"),
|
Protocol::Unsupported => panic!("Unsupported protocol version"),
|
||||||
Protocol::v14 => false,
|
Protocol::v14 => false,
|
||||||
|
|
|
@ -29,6 +29,7 @@ pub(crate) fn hash_to_scalar(data: &[u8]) -> Scalar {
|
||||||
|
|
||||||
// Components common between variants
|
// Components common between variants
|
||||||
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 N: usize = 64;
|
pub(crate) const N: usize = 64;
|
||||||
pub(crate) const MAX_MN: usize = MAX_M * N;
|
pub(crate) const MAX_MN: usize = MAX_M * N;
|
||||||
|
|
||||||
|
@ -77,9 +78,6 @@ pub(crate) fn hash_cache(cache: &mut Scalar, mash: &[[u8; 32]]) -> Scalar {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn MN(outputs: usize) -> (usize, usize, usize) {
|
pub(crate) fn MN(outputs: usize) -> (usize, usize, usize) {
|
||||||
let logN = 6;
|
|
||||||
debug_assert_eq!(N, 1 << logN);
|
|
||||||
|
|
||||||
let mut logM = 0;
|
let mut logM = 0;
|
||||||
let mut M;
|
let mut M;
|
||||||
while {
|
while {
|
||||||
|
@ -89,7 +87,7 @@ pub(crate) fn MN(outputs: usize) -> (usize, usize, usize) {
|
||||||
logM += 1;
|
logM += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
(logM + logN, M, M * N)
|
(logM + LOG_N, M, M * N)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn bit_decompose(commitments: &[Commitment]) -> (ScalarVector, ScalarVector) {
|
pub(crate) fn bit_decompose(commitments: &[Commitment]) -> (ScalarVector, ScalarVector) {
|
||||||
|
@ -152,6 +150,12 @@ 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];
|
||||||
|
|
|
@ -41,6 +41,14 @@ 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],
|
||||||
|
|
|
@ -32,6 +32,13 @@ 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],
|
||||||
|
@ -268,7 +275,7 @@ impl OriginalStruct {
|
||||||
rng: &mut R,
|
rng: &mut R,
|
||||||
commitments: &[DalekPoint],
|
commitments: &[DalekPoint],
|
||||||
) -> bool {
|
) -> bool {
|
||||||
let mut verifier = BatchVerifier::new(4 + commitments.len() + 4 + (2 * (MAX_MN + 10)));
|
let mut verifier = BatchVerifier::new(1);
|
||||||
if self.verify_core(rng, &mut verifier, (), commitments) {
|
if self.verify_core(rng, &mut verifier, (), commitments) {
|
||||||
verifier.verify_vartime()
|
verifier.verify_vartime()
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -17,6 +17,13 @@ lazy_static! {
|
||||||
static ref GENERATORS: Generators = generators_core(b"bulletproof_plus");
|
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();
|
||||||
|
static ref TWO_SIXTY_FOUR_MINUS_ONE: Scalar = {
|
||||||
|
let mut temp = Scalar::from(2u8);
|
||||||
|
for _ in 0 .. LOG_N {
|
||||||
|
temp *= temp;
|
||||||
|
}
|
||||||
|
temp - Scalar::one()
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
// TRANSCRIPT isn't a Scalar, so we need this alternative for the first hash
|
// TRANSCRIPT isn't a Scalar, so we need this alternative for the first hash
|
||||||
|
@ -50,6 +57,12 @@ 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],
|
||||||
|
@ -214,7 +227,6 @@ impl PlusStruct {
|
||||||
|
|
||||||
let (zpow, d) = d(z, M, MN);
|
let (zpow, d) = d(z, M, MN);
|
||||||
let zsq = zpow[0];
|
let zsq = zpow[0];
|
||||||
assert_eq!(zsq, z * z);
|
|
||||||
|
|
||||||
let esq = e * e;
|
let esq = e * e;
|
||||||
let minus_esq = -esq;
|
let minus_esq = -esq;
|
||||||
|
@ -223,19 +235,16 @@ impl PlusStruct {
|
||||||
proof.push((commitment_weight * zpow[i], commitment));
|
proof.push((commitment_weight * zpow[i], commitment));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Invert B, instead of the Scalar, as the latter is only 2x as expensive yet enables reduction
|
||||||
|
// to a single addition under vartime for the first BP verified in the batch, which is expected
|
||||||
|
// to be much more significant
|
||||||
proof.push((Scalar::one(), -B));
|
proof.push((Scalar::one(), -B));
|
||||||
proof.push((-e, A1));
|
proof.push((-e, A1));
|
||||||
proof.push((minus_esq, A));
|
proof.push((minus_esq, A));
|
||||||
proof.push((Scalar(self.d1), G));
|
proof.push((Scalar(self.d1), G));
|
||||||
|
|
||||||
let mut twoSixtyFourMinusOne = Scalar::from(2u8);
|
let d_sum = zpow.sum() * *TWO_SIXTY_FOUR_MINUS_ONE;
|
||||||
for _ in 0 .. 6 {
|
let y_sum = weighted_powers(y, MN).sum();
|
||||||
twoSixtyFourMinusOne *= twoSixtyFourMinusOne;
|
|
||||||
}
|
|
||||||
twoSixtyFourMinusOne -= Scalar::one();
|
|
||||||
let d_sum = zpow.sum() * twoSixtyFourMinusOne;
|
|
||||||
|
|
||||||
let y_sum = ScalarVector(ScalarVector::powers(y, MN + 1).0[1 ..].to_vec()).sum();
|
|
||||||
proof.push((
|
proof.push((
|
||||||
Scalar(self.r1 * y.0 * self.s1) + (esq * ((yMNy * z * d_sum) + ((zsq - z) * y_sum))),
|
Scalar(self.r1 * y.0 * self.s1) + (esq * ((yMNy * z * d_sum) + ((zsq - z) * y_sum))),
|
||||||
*H,
|
*H,
|
||||||
|
@ -275,7 +284,7 @@ impl PlusStruct {
|
||||||
rng: &mut R,
|
rng: &mut R,
|
||||||
commitments: &[DalekPoint],
|
commitments: &[DalekPoint],
|
||||||
) -> bool {
|
) -> bool {
|
||||||
let mut verifier = BatchVerifier::new(4 + commitments.len() + 4 + (2 * (MAX_MN + 10)));
|
let mut verifier = BatchVerifier::new(1);
|
||||||
if self.verify_core(rng, &mut verifier, (), commitments) {
|
if self.verify_core(rng, &mut verifier, (), commitments) {
|
||||||
verifier.verify_vartime()
|
verifier.verify_vartime()
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -103,9 +103,13 @@ pub(crate) fn inner_product(a: &ScalarVector, b: &ScalarVector) -> Scalar {
|
||||||
(a * b).sum()
|
(a * b).sum()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) fn weighted_powers(x: Scalar, len: usize) -> ScalarVector {
|
||||||
|
ScalarVector(ScalarVector::powers(x, len + 1).0[1 ..].to_vec())
|
||||||
|
}
|
||||||
|
|
||||||
pub(crate) fn weighted_inner_product(a: &ScalarVector, b: &ScalarVector, y: Scalar) -> Scalar {
|
pub(crate) fn weighted_inner_product(a: &ScalarVector, b: &ScalarVector, y: Scalar) -> Scalar {
|
||||||
// y ** 0 is not used as a power
|
// y ** 0 is not used as a power
|
||||||
(a * b * ScalarVector(ScalarVector::powers(y, a.len() + 1).0[1 ..].to_vec())).sum()
|
(a * b * weighted_powers(y, a.len())).sum()
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Mul<&[EdwardsPoint]> for &ScalarVector {
|
impl Mul<&[EdwardsPoint]> for &ScalarVector {
|
||||||
|
|
|
@ -57,7 +57,12 @@ fn bulletproofs_vector() {
|
||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! bulletproofs_tests {
|
macro_rules! bulletproofs_tests {
|
||||||
($name: ident, $max: ident, $plus: literal) => {
|
($init: ident, $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
|
||||||
|
@ -86,5 +91,5 @@ macro_rules! bulletproofs_tests {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
bulletproofs_tests!(bulletproofs, bulletproofs_max, false);
|
bulletproofs_tests!(bulletproofs_init, bulletproofs, bulletproofs_max, false);
|
||||||
bulletproofs_tests!(bulletproofs_plus, bulletproofs_plus_max, true);
|
bulletproofs_tests!(bulletproofs_plus_init, bulletproofs_plus, bulletproofs_plus_max, true);
|
||||||
|
|
|
@ -9,6 +9,7 @@ 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,9 +70,15 @@ pub struct Monero {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Monero {
|
impl Monero {
|
||||||
pub fn new(url: String) -> Monero {
|
pub async fn new(url: String) -> Monero {
|
||||||
let view = view_key::<Monero>(0).0;
|
let view = view_key::<Monero>(0).0;
|
||||||
Monero { rpc: Rpc::new(url), view }
|
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 {
|
||||||
|
|
|
@ -111,7 +111,7 @@ async fn test_send<C: Coin + Clone>(coin: C, fee: C::Fee) {
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn monero() {
|
async fn monero() {
|
||||||
let monero = Monero::new("http://127.0.0.1:18081".to_string());
|
let monero = Monero::new("http://127.0.0.1:18081".to_string()).await;
|
||||||
let fee = monero.rpc.get_fee().await.unwrap();
|
let fee = monero.rpc.get_fee().await.unwrap();
|
||||||
test_send(monero, fee).await;
|
test_send(monero, fee).await;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue