Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat/fixed base scalar multiplication using precomputed table #196

Merged
merged 16 commits into from
Aug 23, 2022
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
## [Unreleased]
### Added
- [\#172](https://github.com/Manta-Network/manta-rs/pull/172) Add abstract Phase 2 for Groth16 trusted setup
- [\#196](https://github.com/Manta-Network/manta-rs/pull/172) Add fixed base scalar multiplication using precomputed bases

### Changed
- [\#180](https://github.com/Manta-Network/manta-rs/pull/180) Start moving to new `arkworks` backend for `manta-crypto`
Expand Down
55 changes: 53 additions & 2 deletions manta-crypto/src/algebra.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,12 @@ use crate::{
key,
rand::{RngCore, Sample},
};
use core::marker::PhantomData;
use manta_util::codec::{Decode, DecodeError, Encode, Read, Write};
use alloc::vec::Vec;
use core::{borrow::Borrow, marker::PhantomData};
use manta_util::{
codec::{Decode, DecodeError, Encode, Read, Write},
into_array_unchecked,
};

#[cfg(feature = "serde")]
use manta_util::serde::{Deserialize, Serialize};
Expand All @@ -48,6 +52,53 @@ pub trait Group<COM = ()> {
fn mul(&self, scalar: &Self::Scalar, compiler: &mut COM) -> Self;
}

/// Fixed Base Scalar Multiplication using precomputed base points
pub trait FixedBaseScalarMul<COM = ()>: Group<COM> {
/// Fixed Base Point
type Base;

/// Multiply `precomputed_bases[0]` by `scalar` using precomputed base points,
/// where `precomputed_bases` are precomputed power-of-two multiples of the fixed base.
fn fixed_base_scalar_mul<I>(
precomputed_bases: I,
scalar: &Self::Scalar,
compiler: &mut COM,
) -> Self
where
I: IntoIterator,
I::Item: Borrow<Self::Base>;
}

/// Precomputed power-of-two Base for fixed-base scalar multiplication. Entry at index `i` is `base * 2^i`.
pub struct PrecomputedBaseTable<G, const N: usize> {
table: [G; N],
}

impl<G, const N: usize> IntoIterator for PrecomputedBaseTable<G, N> {
type Item = G;
type IntoIter = core::array::IntoIter<G, N>;

fn into_iter(self) -> Self::IntoIter {
self.table.into_iter()
}
}

impl<G, const N: usize> PrecomputedBaseTable<G, N> {
#[inline]
/// Builds a new [`PrecomputedBaseTable`] from a given `base`, such that `table[i] = base * 2^i`.
pub fn from_base<COM>(base: G, compiler: &mut COM) -> Self
where
G: Group<COM>,
{
let table = into_array_unchecked(
core::iter::successors(Some(base), |base| Some(base.add(base, compiler)))
.take(N)
.collect::<Vec<_>>(),
);
Self { table }
}
}

/// Diffie-Hellman Key Agreement Scheme
#[cfg_attr(
feature = "serde",
Expand Down
8 changes: 8 additions & 0 deletions manta-crypto/src/arkworks/algebra.rs
Original file line number Diff line number Diff line change
Expand Up @@ -104,3 +104,11 @@ where
Self(scalar, PhantomData)
}
}

/// Returns the modulus bits of scalar field of a given curve `C`.
pub const fn scalar_bits<C>() -> usize
where
C: ProjectiveCurve,
{
<<C as ProjectiveCurve>::ScalarField as PrimeField>::Params::MODULUS_BITS as usize
}
73 changes: 72 additions & 1 deletion manta-pay/src/crypto/ecc/arkworks.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@

use crate::crypto::constraint::arkworks::{self, empty, full, Boolean, Fp, FpVar, R1CS};
use alloc::vec::Vec;
use core::marker::PhantomData;
use core::{borrow::Borrow, marker::PhantomData};
use manta_crypto::{
algebra,
arkworks::{
Expand All @@ -41,6 +41,7 @@ use manta_crypto::{
};
use manta_util::codec;

use manta_crypto::algebra::FixedBaseScalarMul;
#[cfg(feature = "serde")]
use {
manta_crypto::arkworks::algebra::serialize_group_element,
Expand Down Expand Up @@ -516,3 +517,73 @@ where
)
}
}

impl<C, CV> FixedBaseScalarMul<Compiler<C>> for GroupVar<C, CV>
where
C: ProjectiveCurve,
CV: CurveVar<C, ConstraintField<C>>,
{
type Base = Group<C>;

fn fixed_base_scalar_mul<I>(
precomputed_bases: I,
scalar: &Self::Scalar,
compiler: &mut Compiler<C>,
) -> Self
where
I: IntoIterator,
I::Item: Borrow<Self::Base>,
{
let _ = compiler;
let mut result = CV::zero();
let scalar_bits = scalar
.0
.to_bits_le()
.expect("Bit decomposition is not allowed to fail.");
for (bit, base) in scalar_bits.into_iter().zip(precomputed_bases.into_iter()) {
result = bit
.select(&(result.clone() + base.borrow().0.into()), &result)
.expect("Conditional select is not allowed to fail. ");
}
Self::new(result)
}
}

#[cfg(test)]
mod test {
use super::*;
use crate::config::Bls12_381_Edwards;
use manta_crypto::{
algebra::{Group as _, PrecomputedBaseTable},
arkworks::{algebra::scalar_bits, r1cs_std::groups::curves::twisted_edwards::AffineVar},
constraint::measure::Measure,
eclair::bool::AssertEq,
rand::OsRng,
};

#[test]
fn fixed_base_mul() {
let mut cs = Compiler::<Bls12_381_Edwards>::for_proofs();
let scalar = Scalar::<Bls12_381_Edwards>::gen(&mut OsRng);
let base = Group::<Bls12_381_Edwards>::sample((), &mut OsRng);
const SCALAR_BITS: usize = scalar_bits::<Bls12_381_Edwards>();
let precomputed_table = PrecomputedBaseTable::<_, SCALAR_BITS>::from_base(base, &mut ());

let base_var =
base.as_known::<Secret, GroupVar<Bls12_381_Edwards, AffineVar<_, _>>>(&mut cs);
let scalar_var =
scalar.as_known::<Secret, ScalarVar<Bls12_381_Edwards, AffineVar<_, _>>>(&mut cs);

let ctr1 = cs.constraint_count();
let expected = base_var.mul(&scalar_var, &mut cs);
let ctr2 = cs.constraint_count();
let actual = GroupVar::fixed_base_scalar_mul(precomputed_table, &scalar_var, &mut cs);
let ctr3 = cs.constraint_count();

cs.assert_eq(&expected, &actual);
assert!(cs.is_satisfied());

println!("variable base mul constraint: {:?}", ctr2 - ctr1);
println!("fixed base mul constraint: {:?}", ctr3 - ctr2);
}
}
11 changes: 6 additions & 5 deletions workspace-hack/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,12 @@ publish = false

### BEGIN HAKARI SECTION
[dependencies]
aes-gcm = { version = "0.9.4", features = ["aes", "alloc"] }
anyhow = { version = "1.0.59", features = ["std"] }
ark-serialize = { version = "0.3.0", default-features = false, features = ["ark-serialize-derive", "derive"] }
bitflags = { version = "1.3.2" }
blake3 = { version = "1.3.1", default-features = false, features = ["digest", "std"] }
byteorder = { version = "1.4.3", features = ["std"] }
crypto-common = { version = "0.1.6", default-features = false, features = ["std"] }
crypto-common = { version = "0.1.6", default-features = false, features = ["getrandom", "rand_core", "std"] }
digest-93f6ce9d446188ac = { package = "digest", version = "0.10.3", features = ["alloc", "block-buffer", "core-api", "mac", "std", "subtle"] }
digest-274715c4dabd11b0 = { package = "digest", version = "0.9.0", default-features = false, features = ["alloc", "std"] }
futures = { version = "0.3.21", features = ["alloc", "async-await", "executor", "futures-executor", "std"] }
Expand All @@ -40,7 +39,7 @@ ppv-lite86 = { version = "0.2.16", default-features = false, features = ["simd",
rand = { version = "0.8.5", features = ["alloc", "getrandom", "libc", "rand_chacha", "std", "std_rng"] }
rand_chacha = { version = "0.3.1", default-features = false, features = ["std"] }
rand_core = { version = "0.6.3", default-features = false, features = ["alloc", "getrandom", "std"] }
serde = { version = "1.0.141", features = ["alloc", "derive", "serde_derive", "std"] }
serde = { version = "1.0.142", features = ["alloc", "derive", "serde_derive", "std"] }
serde_json = { version = "1.0.82", features = ["alloc", "std"] }
sha2 = { version = "0.9.9", features = ["std"] }
standback = { version = "0.2.17", default-features = false, features = ["std"] }
Expand All @@ -54,12 +53,14 @@ zeroize = { version = "1.5.7", default-features = false, features = ["alloc", "z
anyhow = { version = "1.0.59", features = ["std"] }
blake3 = { version = "1.3.1", default-features = false, features = ["digest", "std"] }
cc = { version = "1.0.73", default-features = false, features = ["jobserver", "parallel"] }
crypto-common = { version = "0.1.6", default-features = false, features = ["std"] }
crypto-common = { version = "0.1.6", default-features = false, features = ["getrandom", "rand_core", "std"] }
digest-93f6ce9d446188ac = { package = "digest", version = "0.10.3", features = ["alloc", "block-buffer", "core-api", "mac", "std", "subtle"] }
generic-array = { version = "0.14.6", default-features = false, features = ["more_lengths"] }
getrandom = { version = "0.2.7", default-features = false, features = ["js", "js-sys", "std", "wasm-bindgen"] }
log = { version = "0.4.17", default-features = false, features = ["kv_unstable", "kv_unstable_std", "std", "value-bag"] }
num-traits = { version = "0.2.15", features = ["i128", "libm", "std"] }
serde = { version = "1.0.141", features = ["alloc", "derive", "serde_derive", "std"] }
rand_core = { version = "0.6.3", default-features = false, features = ["alloc", "getrandom", "std"] }
serde = { version = "1.0.142", features = ["alloc", "derive", "serde_derive", "std"] }
standback = { version = "0.2.17", default-features = false, features = ["std"] }
subtle = { version = "2.4.1", default-features = false, features = ["i128"] }
syn = { version = "1.0.98", features = ["clone-impls", "derive", "extra-traits", "fold", "full", "parsing", "printing", "proc-macro", "quote", "visit", "visit-mut"] }
Expand Down