proof_of_sql/proof_primitive/hyperkzg/
commitment.rs1use super::{BNScalar, HyperKZGPublicSetup};
2use crate::base::{
3 commitment::{Commitment, CommittableColumn},
4 impl_serde_for_ark_serde_checked,
5 scalar::Scalar,
6 slice_ops,
7};
8use alloc::vec::Vec;
9use ark_bn254::{G1Affine, G1Projective};
10use ark_serialize::{CanonicalDeserialize, CanonicalSerialize};
11use core::ops::{AddAssign, Mul, Neg, Sub, SubAssign};
12
13#[derive(Clone, Copy, Debug, PartialEq, Eq, CanonicalSerialize, CanonicalDeserialize, Default)]
15pub struct HyperKZGCommitment {
16 pub commitment: G1Projective,
18}
19impl_serde_for_ark_serde_checked!(HyperKZGCommitment);
20
21impl AddAssign for HyperKZGCommitment {
22 fn add_assign(&mut self, rhs: Self) {
23 self.commitment = self.commitment + rhs.commitment;
24 }
25}
26impl From<&G1Affine> for HyperKZGCommitment {
27 fn from(value: &G1Affine) -> Self {
28 Self {
29 commitment: (*value).into(),
30 }
31 }
32}
33
34impl Mul<&HyperKZGCommitment> for BNScalar {
35 type Output = HyperKZGCommitment;
36 fn mul(self, rhs: &HyperKZGCommitment) -> Self::Output {
37 Self::Output {
38 commitment: rhs.commitment * self.0,
39 }
40 }
41}
42
43impl Mul<HyperKZGCommitment> for BNScalar {
44 type Output = HyperKZGCommitment;
45 #[expect(clippy::op_ref)]
46 fn mul(self, rhs: HyperKZGCommitment) -> Self::Output {
47 self * &rhs
48 }
49}
50impl Neg for HyperKZGCommitment {
51 type Output = Self;
52 fn neg(self) -> Self::Output {
53 (-BNScalar::ONE) * self
54 }
55}
56impl SubAssign for HyperKZGCommitment {
57 fn sub_assign(&mut self, rhs: Self) {
58 *self += -rhs;
59 }
60}
61impl Sub for HyperKZGCommitment {
62 type Output = Self;
63 fn sub(mut self, rhs: Self) -> Self::Output {
64 self -= rhs;
65 self
66 }
67}
68
69#[cfg(any(not(feature = "blitzar"), test))]
70#[tracing::instrument(
71 name = "compute_commitment_generic_impl (cpu)",
72 level = "debug",
73 skip_all
74)]
75fn compute_commitment_generic_impl<T: Into<BNScalar> + Clone>(
76 setup: HyperKZGPublicSetup<'_>,
77 offset: usize,
78 scalars: &[T],
79) -> HyperKZGCommitment {
80 assert!(offset + scalars.len() <= setup.len());
81 let product: G1Projective = scalars
82 .iter()
83 .zip(&setup[offset..offset + scalars.len()])
84 .map(|(t, s)| *s * Into::<BNScalar>::into(t).0)
85 .sum();
86 HyperKZGCommitment {
87 commitment: G1Projective::from(product),
88 }
89}
90
91#[cfg(any(not(feature = "blitzar"), test))]
92#[tracing::instrument(name = "compute_commitments_impl (cpu)", level = "debug", skip_all)]
93fn compute_commitments_impl(
94 committable_columns: &[crate::base::commitment::CommittableColumn],
95 offset: usize,
96 setup: &<HyperKZGCommitment as Commitment>::PublicSetup<'_>,
97) -> Vec<HyperKZGCommitment> {
98 committable_columns
99 .iter()
100 .map(|column| match column {
101 CommittableColumn::Boolean(vals) => {
102 compute_commitment_generic_impl(setup, offset, vals)
103 }
104 CommittableColumn::Uint8(vals) => compute_commitment_generic_impl(setup, offset, vals),
105 CommittableColumn::TinyInt(vals) => {
106 compute_commitment_generic_impl(setup, offset, vals)
107 }
108 CommittableColumn::SmallInt(vals) => {
109 compute_commitment_generic_impl(setup, offset, vals)
110 }
111 CommittableColumn::Int(vals) => compute_commitment_generic_impl(setup, offset, vals),
112 CommittableColumn::BigInt(vals) | CommittableColumn::TimestampTZ(_, _, vals) => {
113 compute_commitment_generic_impl(setup, offset, vals)
114 }
115 CommittableColumn::Int128(vals) => compute_commitment_generic_impl(setup, offset, vals),
116 CommittableColumn::Decimal75(_, _, vals)
117 | CommittableColumn::Scalar(vals)
118 | CommittableColumn::VarChar(vals)
119 | CommittableColumn::VarBinary(vals) => {
120 compute_commitment_generic_impl(setup, offset, vals)
121 }
122 })
123 .collect()
124}
125
126impl Commitment for HyperKZGCommitment {
127 type Scalar = BNScalar;
128 type PublicSetup<'a> = HyperKZGPublicSetup<'a>;
129
130 #[cfg(not(feature = "blitzar"))]
131 #[tracing::instrument(name = "compute_commitments (cpu)", level = "debug", skip_all)]
132 fn compute_commitments(
133 committable_columns: &[crate::base::commitment::CommittableColumn],
134 offset: usize,
135 setup: &Self::PublicSetup<'_>,
136 ) -> Vec<Self> {
137 compute_commitments_impl(committable_columns, offset, setup)
138 }
139
140 #[cfg(feature = "blitzar")]
141 #[tracing::instrument(name = "compute_commitments (gpu)", level = "debug", skip_all)]
142 fn compute_commitments(
143 committable_columns: &[crate::base::commitment::CommittableColumn],
144 offset: usize,
145 setup: &Self::PublicSetup<'_>,
146 ) -> Vec<Self> {
147 if committable_columns.is_empty() {
148 return Vec::new();
149 }
150
151 let max_column_len = committable_columns
153 .iter()
154 .map(CommittableColumn::len)
155 .max()
156 .expect("You must have at least one column");
157
158 let mut blitzar_commitments = vec![G1Affine::default(); committable_columns.len()];
159
160 blitzar::compute::compute_bn254_g1_uncompressed_commitments_with_generators(
161 &mut blitzar_commitments,
162 &slice_ops::slice_cast(committable_columns),
163 &setup[offset..offset + max_column_len],
164 );
165
166 slice_ops::slice_cast(&blitzar_commitments)
167 }
168
169 fn to_transcript_bytes(&self) -> Vec<u8> {
170 let mut writer = Vec::with_capacity(self.commitment.compressed_size());
171 self.commitment.serialize_compressed(&mut writer).unwrap();
172 writer
173 }
174}
175
176#[cfg(test)]
177mod tests {
178 use super::*;
179 #[cfg(feature = "hyperkzg_proof")]
180 use crate::base::database::OwnedColumn;
181 #[cfg(feature = "hyperkzg_proof")]
182 use crate::proof_primitive::hyperkzg::nova_commitment_key_to_hyperkzg_public_setup;
183 #[cfg(feature = "hyperkzg_proof")]
184 use crate::proof_primitive::hyperkzg::HyperKZGEngine;
185 use ark_ec::AffineRepr;
186 #[cfg(feature = "hyperkzg_proof")]
187 use nova_snark::provider::hyperkzg::{CommitmentEngine, CommitmentKey};
188 #[cfg(feature = "hyperkzg_proof")]
189 use nova_snark::traits::commitment::CommitmentEngineTrait;
190 #[cfg(feature = "hyperkzg_proof")]
191 use proptest::prelude::*;
192
193 #[test]
194 fn we_can_convert_default_point_to_a_hyperkzg_commitment_from_ark_bn254_g1_affine() {
195 let commitment: HyperKZGCommitment = HyperKZGCommitment::from(&G1Affine::default());
196 assert_eq!(commitment.commitment, G1Affine::default());
197 }
198
199 #[test]
200 fn we_can_convert_generator_to_a_hyperkzg_commitment_from_ark_bn254_g1_affine() {
201 let commitment: HyperKZGCommitment = (&G1Affine::generator()).into();
202 let expected: HyperKZGCommitment = HyperKZGCommitment::from(&G1Affine::generator());
203 assert_eq!(commitment.commitment, expected.commitment);
204 }
205
206 #[cfg(feature = "hyperkzg_proof")]
207 proptest! {
208 #[test]
209 fn blitzar_and_non_blitzar_commitments_are_equal(owned_column: OwnedColumn<BNScalar>) {
210 let ck: CommitmentKey<HyperKZGEngine> = CommitmentEngine::setup(b"test", owned_column.len());
211
212 let public_setup = nova_commitment_key_to_hyperkzg_public_setup(&ck);
213
214 let committable_columns = [CommittableColumn::from(&owned_column)];
215
216 let non_blitzar_commitments = compute_commitments_impl(&committable_columns, 0, &&public_setup[..]);
217 let blitzar_commitments = HyperKZGCommitment::compute_commitments(&committable_columns, 0, &&public_setup[..]);
218
219 prop_assert_eq!(non_blitzar_commitments, blitzar_commitments);
220 }
221 }
222}