diff --git a/Cargo.toml b/Cargo.toml index 997e45a..8bbac09 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -18,6 +18,7 @@ ark-bls12-381 = { version = "0.5.0" } ark-bn254 = { version = "0.5.0" } ark-ec = { version = "0.5.0" } ark-ff = { version = "0.5.0" } +ark-grumpkin = { version = "0.5.0" } ark-serialize = { version = "0.5.0" } ark-std = { version = "0.5.0" } rayon = { version = "1.5" } diff --git a/README.md b/README.md index e5b2118..37cd181 100644 --- a/README.md +++ b/README.md @@ -73,7 +73,7 @@ Blitzar-rs is a High-Level rust wrapper for the [blitzar-sys crate](https://gith The crate provides -* Functions for doing group operations on [Curve-25519](https://en.wikipedia.org/wiki/Curve25519), [Ristretto25519](https://ristretto.group/), [bls12-381 G1](https://electriccoin.co/blog/new-snark-curve/), and [bn254 G1](https://hackmd.io/@jpw/bn254) elements. +* Functions for doing group operations on [Curve-25519](https://en.wikipedia.org/wiki/Curve25519), [Ristretto25519](https://ristretto.group/), [bls12-381 G1](https://electriccoin.co/blog/new-snark-curve/), [bn254 G1](https://hackmd.io/@jpw/bn254) and [Grumpkin](https://hackmd.io/@aztec-network/B19AA8812#Curve-cycles) elements. * An implementation of [Inner Product Argument Protocol](https://eprint.iacr.org/2017/1066.pdf) for producing and verifying a compact proof of the inner product of two vectors. **WARNING**: This project has not undergone a security audit and is NOT ready diff --git a/docs/EXAMPLES.md b/docs/EXAMPLES.md index aa20861..8edd120 100644 --- a/docs/EXAMPLES.md +++ b/docs/EXAMPLES.md @@ -107,6 +107,12 @@ This example shows how to pass user-defined `bn254` `G1` point generators to the $ cargo run --features gpu --example pass_bn254_g1_generators_to_commitment ``` +This example shows how to pass user-defined `grumpkin` point generators to the commitment computation. + +``` +$ cargo run --features gpu --example pass_grumpkin_generators_to_commitment +``` + --------- #### Example 6 - Compute Commitments with Dalek Scalars --------- diff --git a/docs/commitments/compute_bn254_g1_commitments_with_generators.md b/docs/commitments/compute_bn254_g1_commitments_with_generators.md index 54d6be7..2eb31ea 100644 --- a/docs/commitments/compute_bn254_g1_commitments_with_generators.md +++ b/docs/commitments/compute_bn254_g1_commitments_with_generators.md @@ -68,7 +68,7 @@ Portions of this documentation were extracted from # Arguments -* `commitments` - A sliced view of a compressed `bn254` `G1` curve element memory area where the +* `commitments` - A sliced view of an uncompressed `bn254` `G1` curve element memory area where the 512-bit point results will be written to. Please, you need to guarantee that this slice captures exactly `data.len()` element positions. diff --git a/docs/commitments/compute_grumpkin_commitments_with_generators.md b/docs/commitments/compute_grumpkin_commitments_with_generators.md new file mode 100644 index 0000000..f245412 --- /dev/null +++ b/docs/commitments/compute_grumpkin_commitments_with_generators.md @@ -0,0 +1,95 @@ +Computes the Pedersen commitment for a given input data using `grumpkin` curve elements. + +In total, the function computes `data.len()` commitments, +which is related to the total number of columns in the data table. The commitment +results are stored as 512-bit `grumpkin` curve point in affine form in the `commitments` variable. + +The `j`-th Pedersen commitment is a 512-bit `grumpkin` curve point `C_j` over the +`grumpin` elliptic curve that is cryptographically binded to a data message vector `M_j`. This `M_j` vector is populated according to the type of the `data` given. + +For an input data table specified as a [crate::sequence::Sequence] slice view, we populate `M_j` as follows: + +```text +let el_size = data[j].element_size; // sizeof of each element in the current j-th column +let num_rows = data[j].data_slice.len() / el_size; // number of rows in the j-th column + +let M_j = [ + data[j].data_slice[0:el_size], + data[j].data_slice[el_size:2*el_size], + data[j].data_slice[2*el_size:3*el_size], + ., + ., + ., + data[j].data_slice[(num_rows-1)*el_size:num_rows*el_size] +]; +``` + +This message `M_j` cannot be decrypted from `C_j`. The curve point `C_j` +is generated in a unique way using `M_j` and a +set of 768-bit `grumpkin` curve elements in projective form `G_i`, called row generators. +Although our GPU code uses 768-bit generators during the scalar +multiplication, these generators are passed as 512-bit `grumpkin` curve elements in affine form +and only converted to 768-bit projective elements inside the GPU/CPU. + +The total number of generators used to compute `C_j` is equal to +the number of `num_rows` in the `data[j]` sequence. The following formula +is specified to obtain the `C_j` commitment when the input table is a +[crate::sequence::Sequence] view: + +```text +let C_j_temp = 0; // this is a 768-bit grumpkin curve element in projective form + +for j in 0..num_rows { + let G_i = generators[j].decompress(); // we decompress to convert 512-bit to 768-bit points + let curr_data_ji = data[j].data_slice[i*el_size:(i + 1)*el_size]; + C_j_temp = C_j_temp + curr_data_ji * G_i; +} + +let C_j = into_affine(C_j_temp); // this is a 512-bit grumpkin point +``` + +Ps: the above is only illustrative code. It will not compile. + +Here `curr_data_ji` are simply 256-bit scalars, `C_j_temp` and `G_i` are +768-bit `grumpkin` curve elements in projective form and `C_j` is a 512-bit `grumpkin` point in affine form. + +Given `M_j` and `G_i`, it is easy to verify that the Pedersen +commitment `C_j` is the correctly generated output. However, +the Pedersen commitment generated from `M_j` and `G_i` is cryptographically +binded to the message `M_j` because finding alternative inputs `M_j*` and +`G_i*` for which the Pedersen commitment generates the same point `C_j` +requires an infeasible amount of computation. + +To guarantee proper execution, so that the backend is correctly set, +this `compute_grumpkin_commitments_with_generators` always calls the `init_backend()` function. + +Portions of this documentation were extracted from +[here](findora.org/faq/crypto/pedersen-commitment-with-elliptic-curves/) + +# Arguments + +* `commitments` - A sliced view of an un compressed `grumpkin` curve element memory area where the + 512-bit point results will be written to. Please, + you need to guarantee that this slice captures exactly + `data.len()` element positions. + +* `data` - A generic sliced view `T` of a [crate::sequence::Sequence], + which captures the slices of contiguous `u8` memory elements. + You need to guarantee that the contiguous `u8` slice view + captures the correct amount of bytes that can reflect + your desired amount of `num_rows` in the sequence. After all, + we infer the `num_rows` from `data[i].data_slice.len() / data[i].element_size`. + +* `generators` - A sliced view of a `grumpkin` curve affine element memory area where the + 512-bit point generators used in the commitment computation are + stored. Bear in mind that the size of this slice must always be greater + or equal to the longest sequence, in terms of rows, in the table. + +# Asserts + +If the longest sequence in the input data is bigger than the generators length, or if +the `data.len()` value is different from the `commitments.len()` value. + +# Panics + +If the compute commitments execution in the GPU / CPU fails. diff --git a/examples/pass_grumpkin_generators_to_commitment.rs b/examples/pass_grumpkin_generators_to_commitment.rs new file mode 100644 index 0000000..dbda173 --- /dev/null +++ b/examples/pass_grumpkin_generators_to_commitment.rs @@ -0,0 +1,72 @@ +// Copyright 2023-present Space and Time Labs, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +use ark_ec::{CurveGroup, VariableBaseMSM}; +use ark_grumpkin::{Affine, Fr, Projective}; +use ark_std::UniformRand; + +extern crate blitzar; +use blitzar::compute::*; + +fn main() { + ///////////////////////////////////////////// + // For the following data, we have: + // commitment[0] = gs[0]*data[0] + gs[1]*data[1] + gs[2]*data[2] + gs[3]*data[3] + // + // Those generators `gs` are automatically generated by our CPU/GPU code. + // So we provide an interface to access them. We use the offset to get only + // a subset of the generators used in the gpu/cpu code. + // + // Alternatively, in this example, we provide a generator vector `gs`. + ///////////////////////////////////////////// + let data: Vec = vec![2, 3, 1, 5, 4, 7, 6, 8, 9, 10]; + + ///////////////////////////////////////////// + // randomly obtain the generator points + ///////////////////////////////////////////// + let mut rng = ark_std::test_rng(); + let generator_points: Vec = (0..data.len()).map(|_| Affine::rand(&mut rng)).collect(); + + ///////////////////////////////////////////// + // Do the actual commitment computation + ///////////////////////////////////////////// + let mut commitments = vec![Affine::default(); 1]; + compute_grumpkin_uncompressed_commitments_with_generators( + &mut commitments, + &[(&data).into()], + &generator_points, + ); + + ///////////////////////////////////////////// + // Then we use the above generators `gs`, + // as well as the data as scalars + // to verify that those generators `gs` + // are indeed the ones used during the + // commitment computation + ///////////////////////////////////////////// + let mut scalar_data: Vec = Vec::new(); + for d in &data { + scalar_data.push(Fr::from(*d)); + } + + ///////////////////////////////////////////// + // Compute the commitment using Arkworks + ///////////////////////////////////////////// + let ark_commitment = Projective::msm(&generator_points, &scalar_data).unwrap(); + + ///////////////////////////////////////////// + // Compare Arkworks and our CPU/GPU commitment + ///////////////////////////////////////////// + println!("Computed Commitment: {:?}\n", commitments[0]); + println!("Expected Commitment: {:?}\n", ark_commitment.into_affine()); +} diff --git a/src/compute/commitments.rs b/src/compute/commitments.rs index 83f4dae..c589482 100644 --- a/src/compute/commitments.rs +++ b/src/compute/commitments.rs @@ -16,6 +16,7 @@ use super::backend::init_backend; use crate::sequence::Sequence; use ark_bls12_381::G1Affine; use ark_bn254::G1Affine as bn254_g1_affine; +use ark_grumpkin::Affine as grumpkin_affine; use curve25519_dalek::ristretto::{CompressedRistretto, RistrettoPoint}; #[doc = include_str!("../../docs/commitments/compute_curve25519_commitments.md")] @@ -208,3 +209,41 @@ pub fn update_curve25519_commitments( .compress() }); } + +#[doc = include_str!("../../docs/commitments/compute_grumpkin_commitments_with_generators.md")] +/// +/// # Example - Pass generators to Commitment Computation +///```no_run +#[doc = include_str!("../../examples/pass_grumpkin_generators_to_commitment.rs")] +///``` +pub fn compute_grumpkin_uncompressed_commitments_with_generators( + commitments: &mut [grumpkin_affine], + data: &[Sequence], + generators: &[grumpkin_affine], +) { + init_backend(); + + let sxt_descriptors: Vec = data + .iter() + .map(|s| { + assert!( + s.len() <= generators.len(), + "generators has a length smaller than the longest sequence in the input data" + ); + s.into() + }) + .collect(); + + let sxt_grumpkin_generators = generators.as_ptr() as *const blitzar_sys::sxt_grumpkin; + + let sxt_grumpkin_uncompressed = commitments.as_mut_ptr() as *mut blitzar_sys::sxt_grumpkin; + + unsafe { + blitzar_sys::sxt_grumpkin_uncompressed_compute_pedersen_commitments_with_generators( + sxt_grumpkin_uncompressed, + sxt_descriptors.len() as u32, + sxt_descriptors.as_ptr(), + sxt_grumpkin_generators, + ); + } +} diff --git a/src/compute/commitments_tests.rs b/src/compute/commitments_tests.rs index 8ea453b..d481816 100644 --- a/src/compute/commitments_tests.rs +++ b/src/compute/commitments_tests.rs @@ -16,6 +16,9 @@ use super::*; use ark_bls12_381::{Fr, G1Affine, G1Projective}; use ark_bn254::{Fr as bn254_fr, G1Affine as bn254_g1_affine, G1Projective as bn254_g1_projective}; use ark_ec::{CurveGroup, VariableBaseMSM}; +use ark_grumpkin::{ + Affine as grumpkin_affine, Fr as grumpkin_fr, Projective as grumpkin_projective, +}; use ark_serialize::CanonicalSerialize; use ark_std::UniformRand; use curve25519_dalek::{ @@ -544,6 +547,43 @@ fn sending_generators_to_gpu_produces_correct_bn254_g1_commitment_results() { assert_ne!(bn254_g1_affine::default(), commitments[0]); } +#[test] +fn sending_generators_to_gpu_produces_correct_grumpkin_commitment_results() { + // generate input table + let data: Vec = vec![2, 3, 1, 5, 4, 7, 6, 8, 9, 10]; + + // randomly obtain the generator points + let mut rng = ark_std::test_rng(); + let generator_points: Vec = (0..data.len()) + .map(|_| grumpkin_affine::rand(&mut rng)) + .collect(); + + // initialize commitments + let mut commitments = vec![grumpkin_affine::default(); 1]; + + // compute commitment in Blitzar + compute_grumpkin_uncompressed_commitments_with_generators( + &mut commitments, + &[(&data).into()], + &generator_points, + ); + + // convert data to scalar + let mut scalar_data: Vec = Vec::new(); + for d in &data { + scalar_data.push(grumpkin_fr::from(*d)); + } + + // compute msm in Arkworks + let ark_commitment = grumpkin_projective::msm(&generator_points, &scalar_data) + .unwrap() + .into_affine(); + + // verify results + assert_eq!(commitments[0], ark_commitment); + assert_ne!(grumpkin_affine::default(), commitments[0]); +} + #[test] fn sending_generators_and_scalars_to_gpu_produces_correct_commitment_results() { // generate input table diff --git a/src/compute/curve.rs b/src/compute/curve.rs index 5a2afe9..7f51a5c 100644 --- a/src/compute/curve.rs +++ b/src/compute/curve.rs @@ -13,6 +13,10 @@ impl SwCurveConfig for ark_bn254::g1::Config { const CURVE_ID: u32 = blitzar_sys::SXT_CURVE_BN_254; } +impl SwCurveConfig for ark_grumpkin::GrumpkinConfig { + const CURVE_ID: u32 = blitzar_sys::SXT_CURVE_GRUMPKIN; +} + pub trait CurveId { const CURVE_ID: u32; } diff --git a/src/compute/mod.rs b/src/compute/mod.rs index 315c768..56d24da 100644 --- a/src/compute/mod.rs +++ b/src/compute/mod.rs @@ -24,7 +24,8 @@ mod commitments; pub use commitments::{ compute_bls12_381_g1_commitments_with_generators, compute_bn254_g1_uncompressed_commitments_with_generators, compute_curve25519_commitments, - compute_curve25519_commitments_with_generators, update_curve25519_commitments, + compute_curve25519_commitments_with_generators, + compute_grumpkin_uncompressed_commitments_with_generators, update_curve25519_commitments, }; #[cfg(test)]