mirror of
https://github.com/serai-dex/serai.git
synced 2024-12-22 19:49:22 +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 {
|
||||
pub(crate) fn ring_len(&self) -> usize {
|
||||
pub fn ring_len(&self) -> usize {
|
||||
match self {
|
||||
Protocol::Unsupported => panic!("Unsupported protocol version"),
|
||||
Protocol::v14 => 11,
|
||||
|
@ -42,7 +42,7 @@ impl Protocol {
|
|||
}
|
||||
}
|
||||
|
||||
pub(crate) fn bp_plus(&self) -> bool {
|
||||
pub fn bp_plus(&self) -> bool {
|
||||
match self {
|
||||
Protocol::Unsupported => panic!("Unsupported protocol version"),
|
||||
Protocol::v14 => false,
|
||||
|
|
|
@ -29,6 +29,7 @@ pub(crate) fn hash_to_scalar(data: &[u8]) -> Scalar {
|
|||
|
||||
// Components common between variants
|
||||
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 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) {
|
||||
let logN = 6;
|
||||
debug_assert_eq!(N, 1 << logN);
|
||||
|
||||
let mut logM = 0;
|
||||
let mut M;
|
||||
while {
|
||||
|
@ -89,7 +87,7 @@ pub(crate) fn MN(outputs: usize) -> (usize, usize, usize) {
|
|||
logM += 1;
|
||||
}
|
||||
|
||||
(logM + logN, M, M * N)
|
||||
(logM + LOG_N, M, M * N)
|
||||
}
|
||||
|
||||
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) fn init() {
|
||||
let _ = &*INV_EIGHT;
|
||||
let _ = &*H;
|
||||
let _ = &*TWO_N;
|
||||
}
|
||||
|
||||
pub(crate) fn challenge_products(w: &[Scalar], winv: &[Scalar]) -> Vec<Scalar> {
|
||||
let mut products = vec![Scalar::zero(); 1 << w.len()];
|
||||
products[0] = winv[0];
|
||||
|
|
|
@ -41,6 +41,14 @@ impl Bulletproofs {
|
|||
len + clawback
|
||||
}
|
||||
|
||||
pub fn init(plus: bool) {
|
||||
if !plus {
|
||||
OriginalStruct::init();
|
||||
} else {
|
||||
PlusStruct::init();
|
||||
}
|
||||
}
|
||||
|
||||
pub fn prove<R: RngCore + CryptoRng>(
|
||||
rng: &mut R,
|
||||
outputs: &[Commitment],
|
||||
|
|
|
@ -32,6 +32,13 @@ pub struct OriginalStruct {
|
|||
}
|
||||
|
||||
impl OriginalStruct {
|
||||
pub(crate) fn init() {
|
||||
init();
|
||||
let _ = &*GENERATORS;
|
||||
let _ = &*ONE_N;
|
||||
let _ = &*IP12;
|
||||
}
|
||||
|
||||
pub(crate) fn prove<R: RngCore + CryptoRng>(
|
||||
rng: &mut R,
|
||||
commitments: &[Commitment],
|
||||
|
@ -268,7 +275,7 @@ impl OriginalStruct {
|
|||
rng: &mut R,
|
||||
commitments: &[DalekPoint],
|
||||
) -> 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) {
|
||||
verifier.verify_vartime()
|
||||
} else {
|
||||
|
|
|
@ -17,6 +17,13 @@ lazy_static! {
|
|||
static ref GENERATORS: Generators = generators_core(b"bulletproof_plus");
|
||||
static ref TRANSCRIPT: [u8; 32] =
|
||||
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
|
||||
|
@ -50,6 +57,12 @@ pub struct PlusStruct {
|
|||
}
|
||||
|
||||
impl PlusStruct {
|
||||
pub(crate) fn init() {
|
||||
init();
|
||||
let _ = &*GENERATORS;
|
||||
let _ = &*TRANSCRIPT;
|
||||
}
|
||||
|
||||
pub(crate) fn prove<R: RngCore + CryptoRng>(
|
||||
rng: &mut R,
|
||||
commitments: &[Commitment],
|
||||
|
@ -214,7 +227,6 @@ impl PlusStruct {
|
|||
|
||||
let (zpow, d) = d(z, M, MN);
|
||||
let zsq = zpow[0];
|
||||
assert_eq!(zsq, z * z);
|
||||
|
||||
let esq = e * e;
|
||||
let minus_esq = -esq;
|
||||
|
@ -223,19 +235,16 @@ impl PlusStruct {
|
|||
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((-e, A1));
|
||||
proof.push((minus_esq, A));
|
||||
proof.push((Scalar(self.d1), G));
|
||||
|
||||
let mut twoSixtyFourMinusOne = Scalar::from(2u8);
|
||||
for _ in 0 .. 6 {
|
||||
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();
|
||||
let d_sum = zpow.sum() * *TWO_SIXTY_FOUR_MINUS_ONE;
|
||||
let y_sum = weighted_powers(y, MN).sum();
|
||||
proof.push((
|
||||
Scalar(self.r1 * y.0 * self.s1) + (esq * ((yMNy * z * d_sum) + ((zsq - z) * y_sum))),
|
||||
*H,
|
||||
|
@ -275,7 +284,7 @@ impl PlusStruct {
|
|||
rng: &mut R,
|
||||
commitments: &[DalekPoint],
|
||||
) -> 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) {
|
||||
verifier.verify_vartime()
|
||||
} else {
|
||||
|
|
|
@ -103,9 +103,13 @@ pub(crate) fn inner_product(a: &ScalarVector, b: &ScalarVector) -> Scalar {
|
|||
(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 {
|
||||
// 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 {
|
||||
|
|
|
@ -57,7 +57,12 @@ fn bulletproofs_vector() {
|
|||
}
|
||||
|
||||
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]
|
||||
fn $name() {
|
||||
// Create Bulletproofs for all possible output quantities
|
||||
|
@ -86,5 +91,5 @@ macro_rules! bulletproofs_tests {
|
|||
};
|
||||
}
|
||||
|
||||
bulletproofs_tests!(bulletproofs, bulletproofs_max, false);
|
||||
bulletproofs_tests!(bulletproofs_plus, bulletproofs_plus_max, true);
|
||||
bulletproofs_tests!(bulletproofs_init, bulletproofs, bulletproofs_max, false);
|
||||
bulletproofs_tests!(bulletproofs_plus_init, bulletproofs_plus, bulletproofs_plus_max, true);
|
||||
|
|
|
@ -9,6 +9,7 @@ use transcript::RecommendedTranscript;
|
|||
use frost::{curve::Ed25519, FrostKeys};
|
||||
|
||||
use monero_serai::{
|
||||
ringct::bulletproofs::Bulletproofs,
|
||||
transaction::Transaction,
|
||||
rpc::Rpc,
|
||||
wallet::{
|
||||
|
@ -69,9 +70,15 @@ pub struct Monero {
|
|||
}
|
||||
|
||||
impl Monero {
|
||||
pub 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 }
|
||||
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 {
|
||||
|
|
|
@ -111,7 +111,7 @@ async fn test_send<C: Coin + Clone>(coin: C, fee: C::Fee) {
|
|||
|
||||
#[tokio::test]
|
||||
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();
|
||||
test_send(monero, fee).await;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue