use super::{DoryProverPublicSetup, GT};
use crate::base::{
commitment::{Commitment, CommittableColumn},
impl_serde_for_ark_serde_checked,
scalar::{scalar_conversion_to_int, MontScalar, Scalar, ScalarConversionError},
};
use ark_ec::pairing::PairingOutput;
use ark_serialize::{CanonicalDeserialize, CanonicalSerialize};
use core::ops::Mul;
use derive_more::{AddAssign, Neg, Sub, SubAssign};
use num_bigint::BigInt;
use num_traits::One;
pub type DoryScalar = MontScalar<ark_bls12_381::FrConfig>;
scalar_conversion_to_int!(DoryScalar);
impl Scalar for DoryScalar {
const MAX_SIGNED: Self = Self(ark_ff::MontFp!(
"26217937587563095239723870254092982918845276250263818911301829349969290592256"
));
const ZERO: Self = Self(ark_ff::MontFp!("0"));
const ONE: Self = Self(ark_ff::MontFp!("1"));
const TWO: Self = Self(ark_ff::MontFp!("2"));
}
#[derive(
Debug,
Sub,
Eq,
PartialEq,
Neg,
Copy,
Clone,
AddAssign,
SubAssign,
CanonicalSerialize,
CanonicalDeserialize,
)]
pub struct DoryCommitment(pub(super) GT);
impl Default for DoryCommitment {
fn default() -> Self {
Self(PairingOutput(One::one()))
}
}
impl_serde_for_ark_serde_checked!(DoryCommitment);
impl Mul<DoryCommitment> for DoryScalar {
type Output = DoryCommitment;
fn mul(self, rhs: DoryCommitment) -> Self::Output {
DoryCommitment(rhs.0 * self.0)
}
}
impl<'a> Mul<&'a DoryCommitment> for DoryScalar {
type Output = DoryCommitment;
fn mul(self, rhs: &'a DoryCommitment) -> Self::Output {
DoryCommitment(rhs.0 * self.0)
}
}
impl Commitment for DoryCommitment {
type Scalar = DoryScalar;
type PublicSetup<'a> = DoryProverPublicSetup<'a>;
fn compute_commitments(
commitments: &mut [Self],
committable_columns: &[CommittableColumn],
offset: usize,
setup: &Self::PublicSetup<'_>,
) {
assert_eq!(commitments.len(), committable_columns.len());
let c = super::compute_dory_commitments(committable_columns, offset, setup);
commitments.copy_from_slice(&c);
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::{
base::{
commitment::{NumColumnsMismatch, VecCommitmentExt},
database::{Column, OwnedColumn},
},
proof_primitive::dory::{rand_util::test_rng, ProverSetup, PublicParameters},
};
use ark_ec::pairing::Pairing;
#[test]
fn we_can_convert_from_columns() {
let public_parameters = PublicParameters::rand(5, &mut test_rng());
let prover_setup = ProverSetup::from(&public_parameters);
let setup = DoryProverPublicSetup::new(&prover_setup, 2);
let Gamma_1 = &public_parameters.Gamma_1;
let Gamma_2 = &public_parameters.Gamma_2;
let commitments = Vec::<DoryCommitment>::from_columns_with_offset(
&Vec::<Column<DoryScalar>>::new(),
0,
&setup,
);
assert!(commitments.is_empty());
let column_a = [12i64, 34, 56];
let column_b = ["Lorem", "ipsum", "dolor"].map(String::from);
let columns = vec![
OwnedColumn::<DoryScalar>::BigInt(column_a.to_vec()),
OwnedColumn::VarChar(column_b.to_vec()),
];
let commitments = Vec::<DoryCommitment>::from_columns_with_offset(&columns, 0, &setup);
let mut expected_commitments = vec![DoryCommitment::default(); 2];
expected_commitments[0] = DoryCommitment(
Pairing::pairing(Gamma_1[0], Gamma_2[0]) * DoryScalar::from(column_a[0]).0
+ Pairing::pairing(Gamma_1[1], Gamma_2[0]) * DoryScalar::from(column_a[1]).0
+ Pairing::pairing(Gamma_1[2], Gamma_2[0]) * DoryScalar::from(column_a[2]).0,
);
expected_commitments[1] = DoryCommitment(
Pairing::pairing(Gamma_1[0], Gamma_2[0]) * DoryScalar::from(column_b[0].clone()).0
+ Pairing::pairing(Gamma_1[1], Gamma_2[0])
* DoryScalar::from(column_b[1].clone()).0
+ Pairing::pairing(Gamma_1[2], Gamma_2[0])
* DoryScalar::from(column_b[2].clone()).0,
);
assert_eq!(commitments, expected_commitments);
}
#[test]
fn we_can_append_rows() {
let public_parameters = PublicParameters::rand(5, &mut test_rng());
let prover_setup = ProverSetup::from(&public_parameters);
let setup = DoryProverPublicSetup::new(&prover_setup, 2);
let Gamma_1 = &public_parameters.Gamma_1;
let Gamma_2 = &public_parameters.Gamma_2;
let column_a = [12i64, 34, 56, 78, 90];
let column_b = ["Lorem", "ipsum", "dolor", "sit", "amet"].map(String::from);
let columns = vec![
OwnedColumn::<DoryScalar>::BigInt(column_a[..3].to_vec()),
OwnedColumn::VarChar(column_b[..3].to_vec()),
];
let mut commitments = Vec::<DoryCommitment>::from_columns_with_offset(&columns, 0, &setup);
let new_columns = vec![
OwnedColumn::<DoryScalar>::BigInt(column_a[3..].to_vec()),
OwnedColumn::VarChar(column_b[3..].to_vec()),
];
commitments
.try_append_rows_with_offset(&new_columns, 3, &setup)
.unwrap();
let mut expected_commitments = vec![DoryCommitment::default(); 2];
expected_commitments[0] = DoryCommitment(
Pairing::pairing(Gamma_1[0], Gamma_2[0]) * DoryScalar::from(column_a[0]).0
+ Pairing::pairing(Gamma_1[1], Gamma_2[0]) * DoryScalar::from(column_a[1]).0
+ Pairing::pairing(Gamma_1[2], Gamma_2[0]) * DoryScalar::from(column_a[2]).0
+ Pairing::pairing(Gamma_1[3], Gamma_2[0]) * DoryScalar::from(column_a[3]).0
+ Pairing::pairing(Gamma_1[0], Gamma_2[1]) * DoryScalar::from(column_a[4]).0,
);
expected_commitments[1] = DoryCommitment(
Pairing::pairing(Gamma_1[0], Gamma_2[0]) * DoryScalar::from(column_b[0].clone()).0
+ Pairing::pairing(Gamma_1[1], Gamma_2[0])
* DoryScalar::from(column_b[1].clone()).0
+ Pairing::pairing(Gamma_1[2], Gamma_2[0])
* DoryScalar::from(column_b[2].clone()).0
+ Pairing::pairing(Gamma_1[3], Gamma_2[0])
* DoryScalar::from(column_b[3].clone()).0
+ Pairing::pairing(Gamma_1[0], Gamma_2[1])
* DoryScalar::from(column_b[4].clone()).0,
);
assert_eq!(commitments, expected_commitments);
}
#[test]
fn we_cannot_append_rows_with_different_column_count() {
let public_parameters = PublicParameters::rand(5, &mut test_rng());
let prover_setup = ProverSetup::from(&public_parameters);
let setup = DoryProverPublicSetup::new(&prover_setup, 2);
let column_a = [12i64, 34, 56, 78, 90];
let column_b = ["Lorem", "ipsum", "dolor", "sit", "amet"].map(String::from);
let columns = vec![
OwnedColumn::<DoryScalar>::BigInt(column_a[..3].to_vec()),
OwnedColumn::VarChar(column_b[..3].to_vec()),
];
let mut commitments = Vec::<DoryCommitment>::from_columns_with_offset(&columns, 0, &setup);
let new_columns = Vec::<Column<DoryScalar>>::new();
assert!(matches!(
commitments.try_append_rows_with_offset(&new_columns, 3, &setup),
Err(NumColumnsMismatch)
));
let new_columns = vec![OwnedColumn::<DoryScalar>::BigInt(column_a[3..].to_vec())];
assert!(matches!(
commitments.try_append_rows_with_offset(&new_columns, 3, &setup),
Err(NumColumnsMismatch)
));
let new_columns = vec![
OwnedColumn::<DoryScalar>::BigInt(column_a[3..].to_vec()),
OwnedColumn::VarChar(column_b[3..].to_vec()),
OwnedColumn::BigInt(column_a[3..].to_vec()),
];
assert!(matches!(
commitments.try_append_rows_with_offset(&new_columns, 3, &setup),
Err(NumColumnsMismatch)
));
}
#[test]
fn we_can_extend_columns() {
let public_parameters = PublicParameters::rand(5, &mut test_rng());
let prover_setup = ProverSetup::from(&public_parameters);
let setup = DoryProverPublicSetup::new(&prover_setup, 2);
let Gamma_1 = &public_parameters.Gamma_1;
let Gamma_2 = &public_parameters.Gamma_2;
let column_a = [12i64, 34, 56];
let column_b = ["Lorem", "ipsum", "dolor"].map(String::from);
let column_c = ["sit", "amet", "consectetur"].map(String::from);
let column_d = [78i64, 90, 1112];
let columns = vec![
OwnedColumn::<DoryScalar>::BigInt(column_a.to_vec()),
OwnedColumn::VarChar(column_b.to_vec()),
];
let mut commitments = Vec::<DoryCommitment>::from_columns_with_offset(&columns, 0, &setup);
let new_columns = vec![
OwnedColumn::<DoryScalar>::VarChar(column_c.to_vec()),
OwnedColumn::BigInt(column_d.to_vec()),
];
commitments.extend_columns_with_offset(&new_columns, 0, &setup);
let mut expected_commitments = vec![DoryCommitment::default(); 4];
expected_commitments[0] = DoryCommitment(
Pairing::pairing(Gamma_1[0], Gamma_2[0]) * DoryScalar::from(column_a[0]).0
+ Pairing::pairing(Gamma_1[1], Gamma_2[0]) * DoryScalar::from(column_a[1]).0
+ Pairing::pairing(Gamma_1[2], Gamma_2[0]) * DoryScalar::from(column_a[2]).0,
);
expected_commitments[1] = DoryCommitment(
Pairing::pairing(Gamma_1[0], Gamma_2[0]) * DoryScalar::from(column_b[0].clone()).0
+ Pairing::pairing(Gamma_1[1], Gamma_2[0])
* DoryScalar::from(column_b[1].clone()).0
+ Pairing::pairing(Gamma_1[2], Gamma_2[0])
* DoryScalar::from(column_b[2].clone()).0,
);
expected_commitments[2] = DoryCommitment(
Pairing::pairing(Gamma_1[0], Gamma_2[0]) * DoryScalar::from(column_c[0].clone()).0
+ Pairing::pairing(Gamma_1[1], Gamma_2[0])
* DoryScalar::from(column_c[1].clone()).0
+ Pairing::pairing(Gamma_1[2], Gamma_2[0])
* DoryScalar::from(column_c[2].clone()).0,
);
expected_commitments[3] = DoryCommitment(
Pairing::pairing(Gamma_1[0], Gamma_2[0]) * DoryScalar::from(column_d[0]).0
+ Pairing::pairing(Gamma_1[1], Gamma_2[0]) * DoryScalar::from(column_d[1]).0
+ Pairing::pairing(Gamma_1[2], Gamma_2[0]) * DoryScalar::from(column_d[2]).0,
);
assert_eq!(commitments, expected_commitments);
}
#[test]
fn we_can_add_commitment_collections() {
let public_parameters = PublicParameters::rand(5, &mut test_rng());
let prover_setup = ProverSetup::from(&public_parameters);
let setup = DoryProverPublicSetup::new(&prover_setup, 2);
let Gamma_1 = &public_parameters.Gamma_1;
let Gamma_2 = &public_parameters.Gamma_2;
let column_a = [12i64, 34, 56, 78, 90];
let column_b = ["Lorem", "ipsum", "dolor", "sit", "amet"].map(String::from);
let columns = vec![
OwnedColumn::<DoryScalar>::BigInt(column_a[..3].to_vec()),
OwnedColumn::VarChar(column_b[..3].to_vec()),
];
let commitments_a = Vec::<DoryCommitment>::from_columns_with_offset(&columns, 0, &setup);
let new_columns = vec![
OwnedColumn::<DoryScalar>::BigInt(column_a[3..].to_vec()),
OwnedColumn::VarChar(column_b[3..].to_vec()),
];
let commitments_b =
Vec::<DoryCommitment>::from_columns_with_offset(&new_columns, 3, &setup);
let commitments = commitments_a.try_add(commitments_b).unwrap();
let mut expected_commitments = vec![DoryCommitment::default(); 2];
expected_commitments[0] = DoryCommitment(
Pairing::pairing(Gamma_1[0], Gamma_2[0]) * DoryScalar::from(column_a[0]).0
+ Pairing::pairing(Gamma_1[1], Gamma_2[0]) * DoryScalar::from(column_a[1]).0
+ Pairing::pairing(Gamma_1[2], Gamma_2[0]) * DoryScalar::from(column_a[2]).0
+ Pairing::pairing(Gamma_1[3], Gamma_2[0]) * DoryScalar::from(column_a[3]).0
+ Pairing::pairing(Gamma_1[0], Gamma_2[1]) * DoryScalar::from(column_a[4]).0,
);
expected_commitments[1] = DoryCommitment(
Pairing::pairing(Gamma_1[0], Gamma_2[0]) * DoryScalar::from(column_b[0].clone()).0
+ Pairing::pairing(Gamma_1[1], Gamma_2[0])
* DoryScalar::from(column_b[1].clone()).0
+ Pairing::pairing(Gamma_1[2], Gamma_2[0])
* DoryScalar::from(column_b[2].clone()).0
+ Pairing::pairing(Gamma_1[3], Gamma_2[0])
* DoryScalar::from(column_b[3].clone()).0
+ Pairing::pairing(Gamma_1[0], Gamma_2[1])
* DoryScalar::from(column_b[4].clone()).0,
);
assert_eq!(commitments, expected_commitments);
}
#[test]
fn we_cannot_add_commitment_collections_of_mixed_column_counts() {
let public_parameters = PublicParameters::rand(5, &mut test_rng());
let prover_setup = ProverSetup::from(&public_parameters);
let setup = DoryProverPublicSetup::new(&prover_setup, 2);
let column_a = [12i64, 34, 56, 78, 90];
let column_b = ["Lorem", "ipsum", "dolor", "sit", "amet"].map(String::from);
let columns = vec![
OwnedColumn::<DoryScalar>::BigInt(column_a[..3].to_vec()),
OwnedColumn::VarChar(column_b[..3].to_vec()),
];
let commitments = Vec::<DoryCommitment>::from_columns_with_offset(&columns, 0, &setup);
let new_columns = Vec::<Column<DoryScalar>>::new();
let new_commitments =
Vec::<DoryCommitment>::from_columns_with_offset(&new_columns, 3, &setup);
assert!(matches!(
commitments.clone().try_add(new_commitments),
Err(NumColumnsMismatch)
));
let new_columns = vec![OwnedColumn::<DoryScalar>::BigInt(column_a[3..].to_vec())];
let new_commitments =
Vec::<DoryCommitment>::from_columns_with_offset(&new_columns, 3, &setup);
assert!(matches!(
commitments.clone().try_add(new_commitments),
Err(NumColumnsMismatch)
));
let new_columns = vec![
OwnedColumn::<DoryScalar>::BigInt(column_a[3..].to_vec()),
OwnedColumn::VarChar(column_b[3..].to_vec()),
OwnedColumn::BigInt(column_a[3..].to_vec()),
];
let new_commitments =
Vec::<DoryCommitment>::from_columns_with_offset(&new_columns, 3, &setup);
assert!(matches!(
commitments.try_add(new_commitments),
Err(NumColumnsMismatch)
));
}
#[test]
fn we_can_sub_commitment_collections() {
let public_parameters = PublicParameters::rand(5, &mut test_rng());
let prover_setup = ProverSetup::from(&public_parameters);
let setup = DoryProverPublicSetup::new(&prover_setup, 2);
let Gamma_1 = &public_parameters.Gamma_1;
let Gamma_2 = &public_parameters.Gamma_2;
let column_a = [12i64, 34, 56, 78, 90];
let column_b = ["Lorem", "ipsum", "dolor", "sit", "amet"].map(String::from);
let columns = vec![
OwnedColumn::<DoryScalar>::BigInt(column_a[..3].to_vec()),
OwnedColumn::VarChar(column_b[..3].to_vec()),
];
let commitments_a = Vec::<DoryCommitment>::from_columns_with_offset(&columns, 0, &setup);
let full_columns = vec![
OwnedColumn::<DoryScalar>::BigInt(column_a.to_vec()),
OwnedColumn::VarChar(column_b.to_vec()),
];
let commitments_b =
Vec::<DoryCommitment>::from_columns_with_offset(&full_columns, 0, &setup);
let commitments = commitments_b.try_sub(commitments_a).unwrap();
let mut expected_commitments = vec![DoryCommitment::default(); 2];
expected_commitments[0] = DoryCommitment(
Pairing::pairing(Gamma_1[3], Gamma_2[0]) * DoryScalar::from(column_a[3]).0
+ Pairing::pairing(Gamma_1[0], Gamma_2[1]) * DoryScalar::from(column_a[4]).0,
);
expected_commitments[1] = DoryCommitment(
Pairing::pairing(Gamma_1[3], Gamma_2[0]) * DoryScalar::from(column_b[3].clone()).0
+ Pairing::pairing(Gamma_1[0], Gamma_2[1])
* DoryScalar::from(column_b[4].clone()).0,
);
assert_eq!(commitments, expected_commitments);
}
#[test]
fn we_cannot_sub_commitment_collections_of_mixed_column_counts() {
let public_parameters = PublicParameters::rand(5, &mut test_rng());
let prover_setup = ProverSetup::from(&public_parameters);
let setup = DoryProverPublicSetup::new(&prover_setup, 2);
let column_a = [12i64, 34, 56, 78, 90];
let column_b = ["Lorem", "ipsum", "dolor", "sit", "amet"].map(String::from);
let columns = vec![
OwnedColumn::<DoryScalar>::BigInt(column_a[..3].to_vec()),
OwnedColumn::VarChar(column_b[..3].to_vec()),
];
let commitments = Vec::<DoryCommitment>::from_columns_with_offset(&columns, 0, &setup);
let full_columns = Vec::<Column<DoryScalar>>::new();
let full_commitments =
Vec::<DoryCommitment>::from_columns_with_offset(&full_columns, 0, &setup);
assert!(matches!(
full_commitments.clone().try_sub(commitments.clone()),
Err(NumColumnsMismatch)
));
let full_columns = vec![OwnedColumn::<DoryScalar>::BigInt(column_a.to_vec())];
let full_commitments =
Vec::<DoryCommitment>::from_columns_with_offset(&full_columns, 0, &setup);
assert!(matches!(
full_commitments.try_sub(commitments.clone()),
Err(NumColumnsMismatch)
));
let full_columns = vec![
OwnedColumn::<DoryScalar>::BigInt(column_a.to_vec()),
OwnedColumn::VarChar(column_b.to_vec()),
OwnedColumn::BigInt(column_a.to_vec()),
];
let full_commitments =
Vec::<DoryCommitment>::from_columns_with_offset(&full_columns, 0, &setup);
assert!(matches!(
full_commitments.try_sub(commitments),
Err(NumColumnsMismatch)
));
}
}