Skip to content

Commit

Permalink
feat: expose Grumpkin commitment computation (PROOF-882) (#33)
Browse files Browse the repository at this point in the history
* feat: initial check in of Grumpkin API

* refactor: update grumpkin code to match latest arkworks crates
  • Loading branch information
jacobtrombetta authored Oct 31, 2024
1 parent 5980588 commit afc8e67
Show file tree
Hide file tree
Showing 10 changed files with 261 additions and 3 deletions.
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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" }
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
6 changes: 6 additions & 0 deletions docs/EXAMPLES.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
---------
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
95 changes: 95 additions & 0 deletions docs/commitments/compute_grumpkin_commitments_with_generators.md
Original file line number Diff line number Diff line change
@@ -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.
72 changes: 72 additions & 0 deletions examples/pass_grumpkin_generators_to_commitment.rs
Original file line number Diff line number Diff line change
@@ -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<u16> = 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<Affine> = (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<Fr> = 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());
}
39 changes: 39 additions & 0 deletions src/compute/commitments.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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")]
Expand Down Expand Up @@ -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<blitzar_sys::sxt_sequence_descriptor> = 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,
);
}
}
40 changes: 40 additions & 0 deletions src/compute/commitments_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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::{
Expand Down Expand Up @@ -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<u64> = 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<grumpkin_affine> = (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<grumpkin_fr> = 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
Expand Down
4 changes: 4 additions & 0 deletions src/compute/curve.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand Down
3 changes: 2 additions & 1 deletion src/compute/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)]
Expand Down

0 comments on commit afc8e67

Please sign in to comment.