From cac232bd0732817d2b357c1f25611fe0761b42a1 Mon Sep 17 00:00:00 2001 From: kevaundray Date: Fri, 8 Sep 2023 21:52:26 +0000 Subject: [PATCH 1/7] add a test which uses the high limb --- Cargo.lock | 2 + blackbox_solver/Cargo.toml | 12 +++--- blackbox_solver/src/barretenberg/wasm/mod.rs | 2 + .../src/barretenberg/wasm/scalar_mul.rs | 43 ++++++++++++++++++- 4 files changed, 52 insertions(+), 7 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 8bf7a0e8..814ecabd 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -56,8 +56,10 @@ dependencies = [ "blake2", "flate2", "getrandom", + "hex", "js-sys", "k256", + "num-bigint", "p256", "pkg-config", "reqwest", diff --git a/blackbox_solver/Cargo.toml b/blackbox_solver/Cargo.toml index 275c4dd9..5c93768a 100644 --- a/blackbox_solver/Cargo.toml +++ b/blackbox_solver/Cargo.toml @@ -31,17 +31,19 @@ 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", -] } - +] } # Barretenberg WASM dependencies [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" diff --git a/blackbox_solver/src/barretenberg/wasm/mod.rs b/blackbox_solver/src/barretenberg/wasm/mod.rs index 995ef673..75ca52de 100644 --- a/blackbox_solver/src/barretenberg/wasm/mod.rs +++ b/blackbox_solver/src/barretenberg/wasm/mod.rs @@ -34,6 +34,8 @@ pub(crate) enum FeatureError { NoValue, #[error("Value expected to be i32")] InvalidI32, + #[error("Value is not a valid grumpkin scalar")] + InvalidGrumpkinScalar { scalar_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")] diff --git a/blackbox_solver/src/barretenberg/wasm/scalar_mul.rs b/blackbox_solver/src/barretenberg/wasm/scalar_mul.rs index 008eaa1d..c7a30f7c 100644 --- a/blackbox_solver/src/barretenberg/wasm/scalar_mul.rs +++ b/blackbox_solver/src/barretenberg/wasm/scalar_mul.rs @@ -1,4 +1,7 @@ use acir::FieldElement; +use num_bigint::BigUint; + +use crate::barretenberg::wasm::FeatureError; use super::{Barretenberg, Error, FIELD_BYTES}; @@ -14,12 +17,34 @@ 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_bytes = low.to_be_bytes(); + let high_bytes = high.to_be_bytes(); + + let low_16_bytes = low_bytes[16..32].to_vec(); + let high_16_bytes = high_bytes[16..32].to_vec(); + + let mut bytes = high_16_bytes.to_vec(); + bytes.extend_from_slice(&low_16_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); @@ -46,6 +71,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(()) From 42c782a719f60b15fefe1b1e11d36b9b257f4be7 Mon Sep 17 00:00:00 2001 From: kevaundray Date: Fri, 8 Sep 2023 22:00:11 +0000 Subject: [PATCH 2/7] add check for limbs not being less than 2^128 --- blackbox_solver/src/barretenberg/wasm/mod.rs | 4 +++- blackbox_solver/src/barretenberg/wasm/scalar_mul.rs | 12 ++++++++++++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/blackbox_solver/src/barretenberg/wasm/mod.rs b/blackbox_solver/src/barretenberg/wasm/mod.rs index 75ca52de..03d9712d 100644 --- a/blackbox_solver/src/barretenberg/wasm/mod.rs +++ b/blackbox_solver/src/barretenberg/wasm/mod.rs @@ -34,8 +34,10 @@ pub(crate) enum FeatureError { NoValue, #[error("Value expected to be i32")] InvalidI32, - #[error("Value is not a valid grumpkin scalar")] + #[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")] diff --git a/blackbox_solver/src/barretenberg/wasm/scalar_mul.rs b/blackbox_solver/src/barretenberg/wasm/scalar_mul.rs index c7a30f7c..cabb189e 100644 --- a/blackbox_solver/src/barretenberg/wasm/scalar_mul.rs +++ b/blackbox_solver/src/barretenberg/wasm/scalar_mul.rs @@ -31,6 +31,18 @@ impl ScalarMul for Barretenberg { let mut bytes = high_16_bytes.to_vec(); bytes.extend_from_slice(&low_16_bytes); + let two_pow_128 = BigUint::from(2u128).pow(128); + if BigUint::from_bytes_be(&low_16_bytes) >= two_pow_128 { + return Err(Error::FromFeature(FeatureError::InvalidGrumpkinScalarLimb { + limb_as_hex: hex::encode(low_16_bytes), + })); + } + if BigUint::from_bytes_be(&high_16_bytes) >= two_pow_128 { + return Err(Error::FromFeature(FeatureError::InvalidGrumpkinScalarLimb { + limb_as_hex: hex::encode(high_16_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(&[ From f724ec362087e90a56fbff4c69aafb1e8d43e113 Mon Sep 17 00:00:00 2001 From: kevaundray Date: Tue, 12 Sep 2023 12:13:56 +0000 Subject: [PATCH 3/7] update fixed base mul code --- acir/tests/test_program_serialization.rs | 18 +++++++++--------- acvm_js/test/shared/fixed_base_scalar_mul.ts | 13 ++++++++----- 2 files changed, 17 insertions(+), 14 deletions(-) diff --git a/acir/tests/test_program_serialization.rs b/acir/tests/test_program_serialization.rs index e8bd066e..5aa51237 100644 --- a/acir/tests/test_program_serialization.rs +++ b/acir/tests/test_program_serialization.rs @@ -60,16 +60,16 @@ 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() }; @@ -77,9 +77,9 @@ fn fixed_base_scalar_mul_circuit() { circuit.write(&mut bytes).unwrap(); let expected_serialization: Vec = 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) diff --git a/acvm_js/test/shared/fixed_base_scalar_mul.ts b/acvm_js/test/shared/fixed_base_scalar_mul.ts index a1fd36d7..4240b424 100644 --- a/acvm_js/test/shared/fixed_base_scalar_mul.ts +++ b/acvm_js/test/shared/fixed_base_scalar_mul.ts @@ -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"], ]); From bbb307ffeb485e75da8f4530670a42dbcad59603 Mon Sep 17 00:00:00 2001 From: kevaundray Date: Tue, 12 Sep 2023 12:58:28 +0000 Subject: [PATCH 4/7] move 16 byte check to fields --- .../src/barretenberg/wasm/scalar_mul.rs | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/blackbox_solver/src/barretenberg/wasm/scalar_mul.rs b/blackbox_solver/src/barretenberg/wasm/scalar_mul.rs index cabb189e..152159b7 100644 --- a/blackbox_solver/src/barretenberg/wasm/scalar_mul.rs +++ b/blackbox_solver/src/barretenberg/wasm/scalar_mul.rs @@ -25,24 +25,24 @@ impl ScalarMul for Barretenberg { let low_bytes = low.to_be_bytes(); let high_bytes = high.to_be_bytes(); - let low_16_bytes = low_bytes[16..32].to_vec(); - let high_16_bytes = high_bytes[16..32].to_vec(); - - let mut bytes = high_16_bytes.to_vec(); - bytes.extend_from_slice(&low_16_bytes); - let two_pow_128 = BigUint::from(2u128).pow(128); - if BigUint::from_bytes_be(&low_16_bytes) >= two_pow_128 { + if BigUint::from_bytes_be(&low_bytes) >= two_pow_128 { return Err(Error::FromFeature(FeatureError::InvalidGrumpkinScalarLimb { - limb_as_hex: hex::encode(low_16_bytes), + limb_as_hex: hex::encode(low_bytes), })); } - if BigUint::from_bytes_be(&high_16_bytes) >= two_pow_128 { + if BigUint::from_bytes_be(&high_bytes) >= two_pow_128 { return Err(Error::FromFeature(FeatureError::InvalidGrumpkinScalarLimb { - limb_as_hex: hex::encode(high_16_bytes), + limb_as_hex: hex::encode(high_bytes), })); } + let low_16_bytes = low_bytes[16..32].to_vec(); + let high_16_bytes = high_bytes[16..32].to_vec(); + + let mut bytes = high_16_bytes.to_vec(); + bytes.extend_from_slice(&low_16_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(&[ From aa3148fb5ae822312aa9bc3587740dc42b05651f Mon Sep 17 00:00:00 2001 From: kevaundray Date: Tue, 12 Sep 2023 13:02:13 +0000 Subject: [PATCH 5/7] move comment up --- blackbox_solver/Cargo.toml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/blackbox_solver/Cargo.toml b/blackbox_solver/Cargo.toml index 5c93768a..631152d1 100644 --- a/blackbox_solver/Cargo.toml +++ b/blackbox_solver/Cargo.toml @@ -34,11 +34,12 @@ p256 = { version = "0.11.0", features = [ hex = "*" num-bigint.workspace = true +# Barretenberg WASM dependencies rust-embed = { version = "6.6.0", features = [ "debug-embed", "interpolate-folder-path", "include-exclude", -] } # Barretenberg WASM dependencies +] } [target.'cfg(target_arch = "wasm32")'.dependencies] wasmer = { version = "3.3", default-features = false, features = [ "js-default", From 3a20c9e06f6c33d36e4675ee809b54eb15c027a4 Mon Sep 17 00:00:00 2001 From: kevaundray Date: Tue, 12 Sep 2023 14:06:41 +0100 Subject: [PATCH 6/7] Update blackbox_solver/src/barretenberg/wasm/scalar_mul.rs Co-authored-by: Tom French <15848336+TomAFrench@users.noreply.github.com> --- blackbox_solver/src/barretenberg/wasm/scalar_mul.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/blackbox_solver/src/barretenberg/wasm/scalar_mul.rs b/blackbox_solver/src/barretenberg/wasm/scalar_mul.rs index 152159b7..25bb3ab0 100644 --- a/blackbox_solver/src/barretenberg/wasm/scalar_mul.rs +++ b/blackbox_solver/src/barretenberg/wasm/scalar_mul.rs @@ -37,11 +37,11 @@ impl ScalarMul for Barretenberg { })); } - let low_16_bytes = low_bytes[16..32].to_vec(); - let high_16_bytes = high_bytes[16..32].to_vec(); + let low_16_bytes = &low_bytes[16..32]; + let high_16_bytes = &high_bytes[16..32]; let mut bytes = high_16_bytes.to_vec(); - bytes.extend_from_slice(&low_16_bytes); + bytes.extend_from_slice(low_16_bytes); // Check if this is smaller than the grumpkin modulus let grumpkin_integer = BigUint::from_bytes_be(&bytes); From 7f65bd590f759c516cce4ced54af3c4371e34194 Mon Sep 17 00:00:00 2001 From: Tom French Date: Tue, 12 Sep 2023 14:23:39 +0100 Subject: [PATCH 7/7] chore: use `try_into_u128` in `fixed_base` --- .../src/barretenberg/wasm/scalar_mul.rs | 34 ++++++++----------- 1 file changed, 14 insertions(+), 20 deletions(-) diff --git a/blackbox_solver/src/barretenberg/wasm/scalar_mul.rs b/blackbox_solver/src/barretenberg/wasm/scalar_mul.rs index 25bb3ab0..aa333c31 100644 --- a/blackbox_solver/src/barretenberg/wasm/scalar_mul.rs +++ b/blackbox_solver/src/barretenberg/wasm/scalar_mul.rs @@ -22,26 +22,20 @@ impl ScalarMul for Barretenberg { let lhs_ptr: usize = 0; let result_ptr: usize = lhs_ptr + FIELD_BYTES; - let low_bytes = low.to_be_bytes(); - let high_bytes = high.to_be_bytes(); - - let two_pow_128 = BigUint::from(2u128).pow(128); - if BigUint::from_bytes_be(&low_bytes) >= two_pow_128 { - return Err(Error::FromFeature(FeatureError::InvalidGrumpkinScalarLimb { - limb_as_hex: hex::encode(low_bytes), - })); - } - if BigUint::from_bytes_be(&high_bytes) >= two_pow_128 { - return Err(Error::FromFeature(FeatureError::InvalidGrumpkinScalarLimb { - limb_as_hex: hex::encode(high_bytes), - })); - } - - let low_16_bytes = &low_bytes[16..32]; - let high_16_bytes = &high_bytes[16..32]; - - let mut bytes = high_16_bytes.to_vec(); - bytes.extend_from_slice(low_16_bytes); + 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);