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: solve fixed_base_scalar_mul black box functions in rust #3153

Merged
merged 11 commits into from
Oct 16, 2023
15 changes: 14 additions & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 4 additions & 0 deletions acvm-repo/acir_field/src/generic_ark.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
// Check if the negative version is smaller to represent
//
let minus_number = BigUint::from_bytes_be(&(self.neg()).to_be_bytes());
let (smaller_repr, is_negative) =

Check warning on line 22 in acvm-repo/acir_field/src/generic_ark.rs

View workflow job for this annotation

GitHub Actions / Spellcheck / Spellcheck

Unknown word (repr)
if minus_number.to_string().len() < number.to_string().len() {
(minus_number, true)
} else {
Expand All @@ -30,13 +30,13 @@
}

// Number of bits needed to represent the smaller representation
let num_bits = smaller_repr.bits();

Check warning on line 33 in acvm-repo/acir_field/src/generic_ark.rs

View workflow job for this annotation

GitHub Actions / Spellcheck / Spellcheck

Unknown word (repr)

// Check if the number represents a power of 2
if smaller_repr.count_ones() == 1 {

Check warning on line 36 in acvm-repo/acir_field/src/generic_ark.rs

View workflow job for this annotation

GitHub Actions / Spellcheck / Spellcheck

Unknown word (repr)
let mut bit_index = 0;
for i in 0..num_bits {
if smaller_repr.bit(i) {

Check warning on line 39 in acvm-repo/acir_field/src/generic_ark.rs

View workflow job for this annotation

GitHub Actions / Spellcheck / Spellcheck

Unknown word (repr)
bit_index = i;
break;
}
Expand All @@ -59,7 +59,7 @@
let mul_sign = "×";
for power in [64, 32, 16, 8, 4] {
let power_of_two = BigUint::from(2_u128).pow(power);
if &smaller_repr % &power_of_two == BigUint::zero() {

Check warning on line 62 in acvm-repo/acir_field/src/generic_ark.rs

View workflow job for this annotation

GitHub Actions / Spellcheck / Spellcheck

Unknown word (repr)
return write!(
f,
"2{}{}{}",
Expand Down Expand Up @@ -248,6 +248,10 @@
self.0.inverse_in_place().map(|f| FieldElement(*f))
}

pub fn from_repr(field: F) -> Self {
Self(field)
}

// XXX: This method is used while this field element
// implementation is not generic.
pub fn into_repr(self) -> F {
Expand Down
6 changes: 2 additions & 4 deletions acvm-repo/acvm/src/pwg/blackbox/fixed_base_scalar_mul.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,9 @@ use acir::{
circuit::opcodes::FunctionInput,
native_types::{Witness, WitnessMap},
};
use acvm_blackbox_solver::BlackBoxFunctionSolver;

use crate::{
pwg::{insert_value, witness_to_value, OpcodeResolutionError},
BlackBoxFunctionSolver,
};
use crate::pwg::{insert_value, witness_to_value, OpcodeResolutionError};

pub(super) fn fixed_base_scalar_mul(
backend: &impl BlackBoxFunctionSolver,
Expand Down
8 changes: 6 additions & 2 deletions acvm-repo/barretenberg_blackbox_solver/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,15 +16,19 @@ repository.workspace = true
acir.workspace = true
acvm_blackbox_solver.workspace = true
thiserror.workspace = true
hex.workspace = true
num-bigint.workspace = true

rust-embed = { version = "6.6.0", features = [
"debug-embed",
"interpolate-folder-path",
"include-exclude",
] }

# BN254 fixed base scalar multiplication solver
grumpkin = { git = "https://github.com/noir-lang/grumpkin", rev = "56d99799381f79e42148aaef0de2b0cf9a4b9a5d", features = ["std"] }
ark-ec = { version = "^0.4.0", default-features = false }
ark-ff = { version = "^0.4.0", default-features = false }
num-bigint.workspace = true

[target.'cfg(target_arch = "wasm32")'.dependencies]
wasmer = { version = "3.3", default-features = false, features = [
"js-default",
Expand Down
115 changes: 115 additions & 0 deletions acvm-repo/barretenberg_blackbox_solver/src/fixed_base_scalar_mul.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
use ark_ec::AffineRepr;

Check warning on line 1 in acvm-repo/barretenberg_blackbox_solver/src/fixed_base_scalar_mul.rs

View workflow job for this annotation

GitHub Actions / Spellcheck / Spellcheck

Unknown word (Repr)
use ark_ff::MontConfig;
use num_bigint::BigUint;

use acir::{BlackBoxFunc, FieldElement};

use crate::BlackBoxResolutionError;

pub fn fixed_base_scalar_mul(
low: &FieldElement,
high: &FieldElement,
) -> Result<(FieldElement, FieldElement), BlackBoxResolutionError> {
let low: u128 = low.try_into_u128().ok_or_else(|| {
BlackBoxResolutionError::Failed(
BlackBoxFunc::FixedBaseScalarMul,
format!("Limb {} is not less than 2^128", low.to_hex()),
)
})?;

let high: u128 = high.try_into_u128().ok_or_else(|| {
BlackBoxResolutionError::Failed(
BlackBoxFunc::FixedBaseScalarMul,
format!("Limb {} is not less than 2^128", high.to_hex()),
)
})?;

let mut bytes = high.to_be_bytes().to_vec();
bytes.extend_from_slice(&low.to_be_bytes());

// Check if this is smaller than the grumpkin modulus
let grumpkin_integer = BigUint::from_bytes_be(&bytes);

if grumpkin_integer >= grumpkin::FrConfig::MODULUS.into() {
return Err(BlackBoxResolutionError::Failed(
BlackBoxFunc::FixedBaseScalarMul,
format!("{} is not a valid grumpkin scalar", grumpkin_integer.to_str_radix(16)),
));
}

let result = grumpkin::SWAffine::from(
grumpkin::SWAffine::generator().mul_bigint(grumpkin_integer.to_u64_digits()),
);
if let Some((res_x, res_y)) = result.xy() {
Ok((FieldElement::from_repr(*res_x), FieldElement::from_repr(*res_y)))
} else {
Ok((FieldElement::zero(), FieldElement::zero()))
}
}

#[cfg(test)]
mod grumpkin_fixed_base_scalar_mul {
use ark_ff::BigInteger;

use super::*;
#[test]
fn smoke_test() -> Result<(), BlackBoxResolutionError> {
let input = FieldElement::one();

let res = fixed_base_scalar_mul(&input, &FieldElement::zero())?;
let x = "0000000000000000000000000000000000000000000000000000000000000001";
let y = "0000000000000002cf135e7506a45d632d270d45f1181294833fc48d823f272c";

assert_eq!(x, res.0.to_hex());
assert_eq!(y, res.1.to_hex());
Ok(())
}
#[test]
fn low_high_smoke_test() -> Result<(), BlackBoxResolutionError> {
let low = FieldElement::one();
let high = FieldElement::from(2u128);

let res = fixed_base_scalar_mul(&low, &high)?;
let x = "0702ab9c7038eeecc179b4f209991bcb68c7cb05bf4c532d804ccac36199c9a9";
let y = "23f10e9e43a3ae8d75d24154e796aae12ae7af546716e8f81a2564f1b5814130";

assert_eq!(x, res.0.to_hex());
assert_eq!(y, res.1.to_hex());
Ok(())
}

#[test]
fn rejects_invalid_limbs() {
let max_limb = FieldElement::from(u128::MAX);
let invalid_limb = max_limb + FieldElement::one();

let expected_error = Err(BlackBoxResolutionError::Failed(
BlackBoxFunc::FixedBaseScalarMul,
"Limb 0000000000000000000000000000000100000000000000000000000000000000 is not less than 2^128".into()
));

let res = fixed_base_scalar_mul(&invalid_limb, &FieldElement::zero());
assert_eq!(res, expected_error);

let res = fixed_base_scalar_mul(&FieldElement::zero(), &invalid_limb);
assert_eq!(res, expected_error);
}

#[test]
fn rejects_grumpkin_modulus() {
let x = grumpkin::FrConfig::MODULUS.to_bytes_be();

let high = FieldElement::from_be_bytes_reduce(&x[0..16]);
let low = FieldElement::from_be_bytes_reduce(&x[16..32]);

let res = fixed_base_scalar_mul(&low, &high);

assert_eq!(
res,
Err(BlackBoxResolutionError::Failed(
BlackBoxFunc::FixedBaseScalarMul,
"30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47 is not a valid grumpkin scalar".into()
))
);
}
}
9 changes: 4 additions & 5 deletions acvm-repo/barretenberg_blackbox_solver/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,13 @@
use acir::{BlackBoxFunc, FieldElement};
use acvm_blackbox_solver::{BlackBoxFunctionSolver, BlackBoxResolutionError};

mod fixed_base_scalar_mul;
mod wasm;

pub use fixed_base_scalar_mul::fixed_base_scalar_mul;
use wasm::Barretenberg;

use self::wasm::{Pedersen, ScalarMul, SchnorrSig};
use self::wasm::{Pedersen, SchnorrSig};

#[deprecated = "The `BarretenbergSolver` is a temporary solution and will be removed in future."]
pub struct BarretenbergSolver {
Expand Down Expand Up @@ -77,9 +79,6 @@ impl BlackBoxFunctionSolver for BarretenbergSolver {
low: &FieldElement,
high: &FieldElement,
) -> Result<(FieldElement, FieldElement), BlackBoxResolutionError> {
#[allow(deprecated)]
self.blackbox_vendor.fixed_base(low, high).map_err(|err| {
BlackBoxResolutionError::Failed(BlackBoxFunc::FixedBaseScalarMul, err.to_string())
})
fixed_base_scalar_mul(low, high)
}
}
6 changes: 0 additions & 6 deletions acvm-repo/barretenberg_blackbox_solver/src/wasm/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,11 @@

mod barretenberg_structures;
mod pedersen;
mod scalar_mul;
mod schnorr;

use barretenberg_structures::Assignments;

pub(crate) use pedersen::Pedersen;
pub(crate) use scalar_mul::ScalarMul;
pub(crate) use schnorr::SchnorrSig;

/// The number of bytes necessary to store a `FieldElement`.
Expand All @@ -34,10 +32,6 @@ pub(crate) enum FeatureError {
NoValue,
#[error("Value expected to be i32")]
InvalidI32,
#[error("Value {scalar_as_hex} is not a valid grumpkin scalar")]
InvalidGrumpkinScalar { scalar_as_hex: String },
#[error("Limb {limb_as_hex} is not less than 2^128")]
InvalidGrumpkinScalarLimb { limb_as_hex: String },
#[error("Could not convert value {value} from i32 to u32")]
InvalidU32 { value: i32, source: std::num::TryFromIntError },
#[error("Could not convert value {value} from i32 to usize")]
Expand Down
98 changes: 0 additions & 98 deletions acvm-repo/barretenberg_blackbox_solver/src/wasm/scalar_mul.rs

This file was deleted.

1 change: 1 addition & 0 deletions acvm-repo/blackbox_solver/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ p256 = { version = "0.11.0", features = [
"arithmetic",
] }


[features]
default = ["bn254"]
bn254 = ["acir/bn254"]
Expand Down
1 change: 1 addition & 0 deletions cspell.json
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@
"fxhash",
"getrandom",
"gloo",
"grumpkin",
"Guillaume",
"hasher",
"hexdigit",
Expand Down
5 changes: 4 additions & 1 deletion deny.toml
Original file line number Diff line number Diff line change
Expand Up @@ -99,4 +99,7 @@ unknown-registry = "warn"
# Lint level for what to happen when a crate from a git repository that is not
# in the allow list is encountered
unknown-git = "deny"
allow-git = ["https://github.com/jfecher/chumsky"]
allow-git = [
"https://github.com/noir-lang/grumpkin",
"https://github.com/jfecher/chumsky"
]
Loading