Skip to content
This repository has been archived by the owner on Apr 9, 2024. It is now read-only.

fix: Implements handling of the high limb during fixed base scalar multiplication #535

Merged
merged 7 commits into from
Sep 12, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions Cargo.lock

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

18 changes: 9 additions & 9 deletions acir/tests/test_program_serialization.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,26 +60,26 @@ fn addition_circuit() {
#[test]
fn fixed_base_scalar_mul_circuit() {
let fixed_base_scalar_mul = Opcode::BlackBoxFuncCall(BlackBoxFuncCall::FixedBaseScalarMul {
low: FunctionInput { witness: Witness(1), num_bits: FieldElement::max_num_bits() },
high: FunctionInput { witness: Witness(1), num_bits: FieldElement::max_num_bits() },
outputs: (Witness(2), Witness(3)),
low: FunctionInput { witness: Witness(1), num_bits: 128 },
high: FunctionInput { witness: Witness(2), num_bits: 128 },
outputs: (Witness(3), Witness(4)),
});

let circuit = Circuit {
current_witness_index: 4,
current_witness_index: 5,
opcodes: vec![fixed_base_scalar_mul],
private_parameters: BTreeSet::from([Witness(1)]),
return_values: PublicInputs(BTreeSet::from_iter(vec![Witness(2), Witness(3)])),
private_parameters: BTreeSet::from([Witness(1), Witness(2)]),
return_values: PublicInputs(BTreeSet::from_iter(vec![Witness(3), Witness(4)])),
..Circuit::default()
};

let mut bytes = Vec::new();
circuit.write(&mut bytes).unwrap();

let expected_serialization: Vec<u8> = vec![
31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 93, 202, 65, 10, 0, 64, 8, 2, 64, 183, 246, 212, 255,
223, 27, 21, 21, 72, 130, 12, 136, 31, 192, 67, 167, 180, 209, 73, 201, 234, 249, 109, 132,
84, 218, 3, 23, 46, 165, 61, 88, 0, 0, 0,
31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 77, 138, 91, 10, 0, 48, 12, 194, 178, 215, 207, 78, 189,
163, 175, 165, 10, 21, 36, 10, 57, 192, 160, 146, 188, 226, 139, 78, 113, 69, 183, 190, 61,
111, 218, 182, 231, 124, 68, 185, 243, 207, 92, 0, 0, 0,
];

assert_eq!(bytes, expected_serialization)
Expand Down
13 changes: 8 additions & 5 deletions acvm_js/test/shared/fixed_base_scalar_mul.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,18 @@
// See `fixed_base_scalar_mul_circuit` integration test in `acir/tests/test_program_serialization.rs`.
export const bytecode = Uint8Array.from([
31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 93, 202, 65, 10, 0, 64, 8, 2, 64, 183, 246,
212, 255, 223, 27, 21, 21, 72, 130, 12, 136, 31, 192, 67, 167, 180, 209, 73,
201, 234, 249, 109, 132, 84, 218, 3, 23, 46, 165, 61, 88, 0, 0, 0,
31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 77, 138, 91, 10, 0, 48, 12, 194, 178, 215,
207, 78, 189, 163, 175, 165, 10, 21, 36, 10, 57, 192, 160, 146, 188, 226, 139,
78, 113, 69, 183, 190, 61, 111, 218, 182, 231, 124, 68, 185, 243, 207, 92, 0,
0, 0,
]);
export const initialWitnessMap = new Map([
[1, "0x0000000000000000000000000000000000000000000000000000000000000001"],
[2, "0x0000000000000000000000000000000000000000000000000000000000000000"],
]);

export const expectedWitnessMap = new Map([
[1, "0x0000000000000000000000000000000000000000000000000000000000000001"],
[2, "0x0000000000000000000000000000000000000000000000000000000000000001"],
[3, "0x0000000000000002cf135e7506a45d632d270d45f1181294833fc48d823f272c"],
[2, "0x0000000000000000000000000000000000000000000000000000000000000000"],
[3, "0x0000000000000000000000000000000000000000000000000000000000000001"],
[4, "0x0000000000000002cf135e7506a45d632d270d45f1181294833fc48d823f272c"],
]);
9 changes: 6 additions & 3 deletions blackbox_solver/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -31,17 +31,20 @@ p256 = { version = "0.11.0", features = [
"digest",
"arithmetic",
] }
hex = "*"
num-bigint.workspace = true

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

[target.'cfg(target_arch = "wasm32")'.dependencies]
wasmer = { version = "3.3", default-features = false, features = [ "js-default" ] }
getrandom = { version = "0.2", features = [ "js" ]}
wasmer = { version = "3.3", default-features = false, features = [
"js-default",
] }
getrandom = { version = "0.2", features = ["js"] }
wasm-bindgen-futures = "0.4.36"
js-sys = "0.3.62"

Expand Down
4 changes: 4 additions & 0 deletions blackbox_solver/src/barretenberg/wasm/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,10 @@ 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
49 changes: 47 additions & 2 deletions blackbox_solver/src/barretenberg/wasm/scalar_mul.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
use acir::FieldElement;
use num_bigint::BigUint;

use crate::barretenberg::wasm::FeatureError;

use super::{Barretenberg, Error, FIELD_BYTES};

Expand All @@ -14,12 +17,40 @@ impl ScalarMul for Barretenberg {
fn fixed_base(
&self,
low: &FieldElement,
_high: &FieldElement,
high: &FieldElement,
) -> Result<(FieldElement, FieldElement), Error> {
let lhs_ptr: usize = 0;
let result_ptr: usize = lhs_ptr + FIELD_BYTES;
self.transfer_to_heap(&low.to_be_bytes(), lhs_ptr);

let low: u128 = low.try_into_u128().ok_or_else(|| {
Error::FromFeature(FeatureError::InvalidGrumpkinScalarLimb {
limb_as_hex: low.to_hex(),
})
})?;

let high: u128 = high.try_into_u128().ok_or_else(|| {
Error::FromFeature(FeatureError::InvalidGrumpkinScalarLimb {
limb_as_hex: 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(Error::FromFeature(FeatureError::InvalidGrumpkinScalar {
scalar_as_hex: hex::encode(grumpkin_integer.to_bytes_be()),
}));
}

self.transfer_to_heap(&bytes, lhs_ptr);
self.call_multiple("compute_public_key", vec![&lhs_ptr.into(), &result_ptr.into()])?;

let result_bytes: [u8; 2 * FIELD_BYTES] = self.read_memory(result_ptr);
Expand All @@ -46,6 +77,20 @@ mod test {
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<(), Error> {
let barretenberg = Barretenberg::new();
let low = FieldElement::one();
let high = FieldElement::from(2u128);

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

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