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
16 changes: 14 additions & 2 deletions 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
8 changes: 2 additions & 6 deletions acvm-repo/acvm/src/pwg/blackbox/fixed_base_scalar_mul.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,9 @@ use acir::{
native_types::{Witness, WitnessMap},
};

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,
initial_witness: &mut WitnessMap,
low: FunctionInput,
high: FunctionInput,
Expand All @@ -18,7 +14,7 @@ pub(super) fn fixed_base_scalar_mul(
let low = witness_to_value(initial_witness, low.witness)?;
let high = witness_to_value(initial_witness, high.witness)?;

let (pub_x, pub_y) = backend.fixed_base_scalar_mul(low, high)?;
let (pub_x, pub_y) = crate::blackbox_solver::fixed_base_scalar_mul(low, high)?;

insert_value(&outputs.0, pub_x, initial_witness)?;
insert_value(&outputs.1, pub_y, initial_witness)?;
Expand Down
2 changes: 1 addition & 1 deletion acvm-repo/acvm/src/pwg/blackbox/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
use pedersen::pedersen;
use range::solve_range_opcode;
use signature::{
ecdsa::{secp256k1_prehashed, secp256r1_prehashed},

Check warning on line 25 in acvm-repo/acvm/src/pwg/blackbox/mod.rs

View workflow job for this annotation

GitHub Actions / Spellcheck / Spellcheck

Unknown word (prehashed)

Check warning on line 25 in acvm-repo/acvm/src/pwg/blackbox/mod.rs

View workflow job for this annotation

GitHub Actions / Spellcheck / Spellcheck

Unknown word (prehashed)
schnorr::schnorr_verify,
};

Expand Down Expand Up @@ -126,7 +126,7 @@
signature,
hashed_message: message,
output,
} => secp256k1_prehashed(

Check warning on line 129 in acvm-repo/acvm/src/pwg/blackbox/mod.rs

View workflow job for this annotation

GitHub Actions / Spellcheck / Spellcheck

Unknown word (prehashed)
initial_witness,
public_key_x,
public_key_y,
Expand All @@ -140,7 +140,7 @@
signature,
hashed_message: message,
output,
} => secp256r1_prehashed(

Check warning on line 143 in acvm-repo/acvm/src/pwg/blackbox/mod.rs

View workflow job for this annotation

GitHub Actions / Spellcheck / Spellcheck

Unknown word (prehashed)
initial_witness,
public_key_x,
public_key_y,
Expand All @@ -149,7 +149,7 @@
*output,
),
BlackBoxFuncCall::FixedBaseScalarMul { low, high, outputs } => {
fixed_base_scalar_mul(backend, initial_witness, *low, *high, *outputs)
fixed_base_scalar_mul(initial_witness, *low, *high, *outputs)
}
BlackBoxFuncCall::RecursiveAggregation { output_aggregation_object, .. } => {
// Solve the output of the recursive aggregation to zero to prevent missing assignment errors
Expand Down
7 changes: 0 additions & 7 deletions acvm-repo/acvm/tests/solver.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,13 +36,6 @@ impl BlackBoxFunctionSolver for StubbedBackend {
) -> Result<(FieldElement, FieldElement), BlackBoxResolutionError> {
panic!("Path not trodden by this test")
}
fn fixed_base_scalar_mul(
&self,
_low: &FieldElement,
_high: &FieldElement,
) -> Result<(FieldElement, FieldElement), BlackBoxResolutionError> {
panic!("Path not trodden by this test")
}
}

// Reenable these test cases once we move the brillig implementation of inversion down into the acvm stdlib.
Expand Down
2 changes: 0 additions & 2 deletions acvm-repo/barretenberg_blackbox_solver/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,6 @@ 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",
Expand Down
13 changes: 1 addition & 12 deletions acvm-repo/barretenberg_blackbox_solver/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ mod wasm;

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 @@ -71,15 +71,4 @@ impl BlackBoxFunctionSolver for BarretenbergSolver {
.encrypt(inputs.to_vec(), domain_separator)
.map_err(|err| BlackBoxResolutionError::Failed(BlackBoxFunc::Pedersen, err.to_string()))
}

fn fixed_base_scalar_mul(
&self,
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())
})
}
}
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 @@ -27,17 +25,13 @@
#[derive(Debug, thiserror::Error)]
pub(crate) enum FeatureError {
#[error("Trying to call {name} resulted in an error")]
FunctionCallFailed { name: String, source: wasmer::RuntimeError },

Check warning on line 28 in acvm-repo/barretenberg_blackbox_solver/src/wasm/mod.rs

View workflow job for this annotation

GitHub Actions / Spellcheck / Spellcheck

Unknown word (wasmer)
#[error("Could not find function export named {name}")]
InvalidExport { name: String, source: wasmer::ExportError },
#[error("No value available when value was expected")]
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.

3 changes: 3 additions & 0 deletions acvm-repo/blackbox_solver/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ repository.workspace = true
[dependencies]
acir.workspace = true
thiserror.workspace = true
num-bigint.workspace = true

blake2 = "0.10.6"
sha2 = "0.10.6"
Expand All @@ -33,6 +34,8 @@ p256 = { version = "0.11.0", features = [
"digest",
"arithmetic",
] }
grumpkin = { git = "https://github.com/noir-lang/grumpkin", features = ["std"] }
TomAFrench marked this conversation as resolved.
Show resolved Hide resolved
ark-ec = { version = "^0.4.0", default-features = false }

[features]
default = ["bn254"]
Expand Down
89 changes: 84 additions & 5 deletions acvm-repo/blackbox_solver/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
use acir::{BlackBoxFunc, FieldElement};
use blake2::digest::generic_array::GenericArray;
use blake2::{Blake2s256, Digest};
use num_bigint::BigUint;
use sha2::Sha256;
use sha3::Keccak256;
use thiserror::Error;
Expand Down Expand Up @@ -39,11 +40,6 @@ pub trait BlackBoxFunctionSolver {
inputs: &[FieldElement],
domain_separator: u32,
) -> Result<(FieldElement, FieldElement), BlackBoxResolutionError>;
fn fixed_base_scalar_mul(
&self,
low: &FieldElement,
high: &FieldElement,
) -> Result<(FieldElement, FieldElement), BlackBoxResolutionError>;
}

pub fn sha256(inputs: &[u8]) -> Result<[u8; 32], BlackBoxResolutionError> {
Expand All @@ -66,6 +62,89 @@ pub fn hash_to_field_128_security(inputs: &[u8]) -> Result<FieldElement, BlackBo
.map_err(|err| BlackBoxResolutionError::Failed(BlackBoxFunc::HashToField128Security, err))
}

pub fn fixed_base_scalar_mul(
low: &FieldElement,
high: &FieldElement,
) -> Result<(FieldElement, FieldElement), BlackBoxResolutionError> {
#[cfg(not(feature = "bn254"))]
return BlackBoxResolutionError::Failed(
BlackBoxFunc::FixedBaseScalarMul,
"This solver is only defined over the bn254 curve currently".into(),
);

use ark_ec::AffineRepr;

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);
let grumpkin_modulus = BigUint::from_bytes_be(&[
48, 100, 78, 114, 225, 49, 160, 41, 184, 80, 69, 182, 129, 129, 88, 93, 151, 129, 106, 145,
104, 113, 202, 141, 60, 32, 140, 22, 216, 124, 253, 71,
]);

if grumpkin_integer >= grumpkin_modulus {
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 test {
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(())
}
}

pub fn ecdsa_secp256k1_verify(
hashed_msg: &[u8],
public_key_x: &[u8; 32],
Expand Down
Loading