proof_of_sql/proof_primitive/hyperkzg/
commitment.rs1use super::{BNScalar, HyperKZGPublicSetup};
2#[cfg(any(not(feature = "blitzar"), test))]
3use crate::base::if_rayon;
4use crate::base::{
5 commitment::{Commitment, CommittableColumn},
6 scalar::Scalar,
7 slice_ops,
8};
9use alloc::vec::Vec;
10use ark_bn254::{G1Affine, G1Projective};
11use ark_ec::AffineRepr;
12use ark_serialize::{CanonicalDeserialize, CanonicalSerialize};
13use core::ops::{AddAssign, Mul, Neg, Sub, SubAssign};
14#[cfg(all(feature = "rayon", any(not(feature = "blitzar"), test)))]
15use rayon::prelude::*;
16use serde::{Deserialize, Deserializer, Serialize, Serializer};
17
18#[derive(Clone, Copy, Debug, PartialEq, Eq, CanonicalSerialize, CanonicalDeserialize, Default)]
20pub struct HyperKZGCommitment {
21 pub commitment: G1Projective,
23}
24impl Serialize for HyperKZGCommitment {
25 fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
26 let affine: G1Affine = self.commitment.into();
27 match affine.xy() {
28 None => ([0u8; 32], [0u8; 32]).serialize(serializer),
29 Some((x, y)) => {
30 let mut x_bytes = [0u8; 32];
31 CanonicalSerialize::serialize_uncompressed(&x, &mut x_bytes[..])
32 .map_err(serde::ser::Error::custom)?;
33 x_bytes.reverse();
34 let mut y_bytes = [0u8; 32];
35 CanonicalSerialize::serialize_uncompressed(&y, &mut y_bytes[..])
36 .map_err(serde::ser::Error::custom)?;
37 y_bytes.reverse();
38 (x_bytes, y_bytes).serialize(serializer)
39 }
40 }
41 }
42}
43impl<'de> Deserialize<'de> for HyperKZGCommitment {
44 fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
45 let (mut x_bytes, mut y_bytes) = <([u8; 32], [u8; 32])>::deserialize(deserializer)?;
46 let affine: G1Affine = if (x_bytes, y_bytes) == ([0u8; 32], [0u8; 32]) {
47 G1Affine::identity()
48 } else {
49 x_bytes.reverse();
50 y_bytes.reverse();
51 let x = CanonicalDeserialize::deserialize_uncompressed(&x_bytes[..])
52 .map_err(serde::de::Error::custom)?;
53 let y = CanonicalDeserialize::deserialize_uncompressed(&y_bytes[..])
54 .map_err(serde::de::Error::custom)?;
55 G1Affine::new_unchecked(x, y)
56 };
57 Ok(Self {
58 commitment: affine.into(),
59 })
60 }
61}
62
63impl AddAssign for HyperKZGCommitment {
64 fn add_assign(&mut self, rhs: Self) {
65 self.commitment = self.commitment + rhs.commitment;
66 }
67}
68impl From<&G1Affine> for HyperKZGCommitment {
69 fn from(value: &G1Affine) -> Self {
70 Self {
71 commitment: (*value).into(),
72 }
73 }
74}
75
76impl Mul<&HyperKZGCommitment> for BNScalar {
77 type Output = HyperKZGCommitment;
78 fn mul(self, rhs: &HyperKZGCommitment) -> Self::Output {
79 Self::Output {
80 commitment: rhs.commitment * self.0,
81 }
82 }
83}
84
85impl Mul<HyperKZGCommitment> for BNScalar {
86 type Output = HyperKZGCommitment;
87 #[expect(clippy::op_ref)]
88 fn mul(self, rhs: HyperKZGCommitment) -> Self::Output {
89 self * &rhs
90 }
91}
92impl Neg for HyperKZGCommitment {
93 type Output = Self;
94 fn neg(self) -> Self::Output {
95 (-BNScalar::ONE) * self
96 }
97}
98impl SubAssign for HyperKZGCommitment {
99 fn sub_assign(&mut self, rhs: Self) {
100 *self += -rhs;
101 }
102}
103impl Sub for HyperKZGCommitment {
104 type Output = Self;
105 fn sub(mut self, rhs: Self) -> Self::Output {
106 self -= rhs;
107 self
108 }
109}
110
111#[cfg(any(not(feature = "blitzar"), test))]
112#[tracing::instrument(
113 name = "compute_commitment_generic_impl (cpu)",
114 level = "debug",
115 skip_all
116)]
117fn compute_commitment_generic_impl<T: Into<BNScalar> + Clone + Sync>(
118 setup: HyperKZGPublicSetup<'_>,
119 offset: usize,
120 scalars: &[T],
121) -> HyperKZGCommitment {
122 assert!(offset + scalars.len() <= setup.len());
123 let product: G1Projective = if_rayon!(scalars.par_iter(), scalars.iter())
124 .zip(&setup[offset..offset + scalars.len()])
125 .map(|(t, s)| *s * Into::<BNScalar>::into(t).0)
126 .sum();
127 HyperKZGCommitment {
128 commitment: G1Projective::from(product),
129 }
130}
131
132#[cfg(any(not(feature = "blitzar"), test))]
133#[tracing::instrument(name = "compute_commitments_impl (cpu)", level = "debug", skip_all)]
134fn compute_commitments_impl(
135 committable_columns: &[crate::base::commitment::CommittableColumn],
136 offset: usize,
137 setup: &<HyperKZGCommitment as Commitment>::PublicSetup<'_>,
138) -> Vec<HyperKZGCommitment> {
139 if_rayon!(committable_columns.par_iter(), committable_columns.iter())
140 .map(|column| match column {
141 CommittableColumn::Boolean(vals) => {
142 compute_commitment_generic_impl(setup, offset, vals)
143 }
144 CommittableColumn::Uint8(vals) => compute_commitment_generic_impl(setup, offset, vals),
145 CommittableColumn::TinyInt(vals) => {
146 compute_commitment_generic_impl(setup, offset, vals)
147 }
148 CommittableColumn::SmallInt(vals) => {
149 compute_commitment_generic_impl(setup, offset, vals)
150 }
151 CommittableColumn::Int(vals) => compute_commitment_generic_impl(setup, offset, vals),
152 CommittableColumn::BigInt(vals) | CommittableColumn::TimestampTZ(_, _, vals) => {
153 compute_commitment_generic_impl(setup, offset, vals)
154 }
155 CommittableColumn::Int128(vals) => compute_commitment_generic_impl(setup, offset, vals),
156 CommittableColumn::Decimal75(_, _, vals)
157 | CommittableColumn::Scalar(vals)
158 | CommittableColumn::VarChar(vals)
159 | CommittableColumn::VarBinary(vals) => {
160 compute_commitment_generic_impl(setup, offset, vals)
161 }
162 })
163 .collect()
164}
165
166impl Commitment for HyperKZGCommitment {
167 type Scalar = BNScalar;
168 type PublicSetup<'a> = HyperKZGPublicSetup<'a>;
169
170 #[cfg(not(feature = "blitzar"))]
171 #[tracing::instrument(name = "compute_commitments (cpu)", level = "debug", skip_all)]
172 fn compute_commitments(
173 committable_columns: &[crate::base::commitment::CommittableColumn],
174 offset: usize,
175 setup: &Self::PublicSetup<'_>,
176 ) -> Vec<Self> {
177 compute_commitments_impl(committable_columns, offset, setup)
178 }
179
180 #[cfg(feature = "blitzar")]
181 #[tracing::instrument(name = "compute_commitments (gpu)", level = "debug", skip_all)]
182 fn compute_commitments(
183 committable_columns: &[crate::base::commitment::CommittableColumn],
184 offset: usize,
185 setup: &Self::PublicSetup<'_>,
186 ) -> Vec<Self> {
187 if committable_columns.is_empty() {
188 return Vec::new();
189 }
190
191 let max_column_len = committable_columns
193 .iter()
194 .map(CommittableColumn::len)
195 .max()
196 .expect("You must have at least one column");
197
198 let mut blitzar_commitments = vec![G1Affine::default(); committable_columns.len()];
199
200 blitzar::compute::compute_bn254_g1_uncompressed_commitments_with_generators(
201 &mut blitzar_commitments,
202 &slice_ops::slice_cast(committable_columns),
203 &setup[offset..offset + max_column_len],
204 );
205
206 slice_ops::slice_cast(&blitzar_commitments)
207 }
208
209 fn to_transcript_bytes(&self) -> Vec<u8> {
210 let mut writer = Vec::with_capacity(self.commitment.compressed_size());
211 self.commitment.serialize_compressed(&mut writer).unwrap();
212 writer
213 }
214}
215
216#[cfg(test)]
217mod tests {
218 use super::*;
219 #[cfg(feature = "hyperkzg_proof")]
220 use crate::base::database::OwnedColumn;
221 use crate::base::{try_standard_binary_deserialization, try_standard_binary_serialization};
222 #[cfg(feature = "hyperkzg_proof")]
223 use crate::proof_primitive::hyperkzg::nova_commitment_key_to_hyperkzg_public_setup;
224 #[cfg(feature = "hyperkzg_proof")]
225 use crate::proof_primitive::hyperkzg::HyperKZGEngine;
226 use ark_ec::AffineRepr;
227 #[cfg(feature = "hyperkzg_proof")]
228 use nova_snark::provider::hyperkzg::{CommitmentEngine, CommitmentKey};
229 #[cfg(feature = "hyperkzg_proof")]
230 use nova_snark::traits::commitment::CommitmentEngineTrait;
231 #[cfg(feature = "hyperkzg_proof")]
232 use proptest::prelude::*;
233
234 #[test]
235 fn we_can_convert_default_point_to_a_hyperkzg_commitment_from_ark_bn254_g1_affine() {
236 let commitment: HyperKZGCommitment = HyperKZGCommitment::from(&G1Affine::default());
237 assert_eq!(commitment.commitment, G1Affine::default());
238 }
239
240 #[test]
241 fn we_can_convert_generator_to_a_hyperkzg_commitment_from_ark_bn254_g1_affine() {
242 let commitment: HyperKZGCommitment = (&G1Affine::generator()).into();
243 let expected: HyperKZGCommitment = HyperKZGCommitment::from(&G1Affine::generator());
244 assert_eq!(commitment.commitment, expected.commitment);
245 }
246
247 #[cfg(feature = "hyperkzg_proof")]
248 proptest! {
249 #[test]
250 fn blitzar_and_non_blitzar_commitments_are_equal(owned_column: OwnedColumn<BNScalar>) {
251 let ck: CommitmentKey<HyperKZGEngine> = CommitmentEngine::setup(b"test", owned_column.len());
252
253 let public_setup = nova_commitment_key_to_hyperkzg_public_setup(&ck);
254
255 let committable_columns = [CommittableColumn::from(&owned_column)];
256
257 let non_blitzar_commitments = compute_commitments_impl(&committable_columns, 0, &&public_setup[..]);
258 let blitzar_commitments = HyperKZGCommitment::compute_commitments(&committable_columns, 0, &&public_setup[..]);
259
260 prop_assert_eq!(non_blitzar_commitments, blitzar_commitments);
261 }
262 }
263
264 #[test]
265 fn we_can_serialize_and_deserialize_hyperkzg_commitment_generator() {
266 let commitment: HyperKZGCommitment = (&G1Affine::generator()).into();
267 let bytes = try_standard_binary_serialization(commitment).unwrap();
268 assert_eq!(bytes, [&[0u8; 31][..], &[1], &[0; 31], &[2]].concat());
269
270 let (deserialized_commitment, _): (HyperKZGCommitment, _) =
271 try_standard_binary_deserialization(&bytes[..]).unwrap();
272 assert_eq!(deserialized_commitment.commitment, G1Affine::generator());
273 }
274 #[test]
275 fn we_can_serialize_and_deserialize_hyperkzg_commitment_identity() {
276 let commitment: HyperKZGCommitment = (&G1Affine::identity()).into();
277 let bytes = try_standard_binary_serialization(commitment).unwrap();
278 assert_eq!(bytes, [&[0u8; 31][..], &[0], &[0; 31], &[0]].concat());
279
280 let (deserialized_commitment, _): (HyperKZGCommitment, _) =
281 try_standard_binary_deserialization(&bytes[..]).unwrap();
282 assert_eq!(deserialized_commitment.commitment, G1Affine::identity());
283 }
284 #[test]
285 fn we_can_round_trip_serialize_and_deserialize_random_hyperkzg_commitments() {
286 use ark_std::UniformRand;
287
288 let mut rng = ark_std::test_rng();
289
290 for _ in 0..100 {
291 let commitment: HyperKZGCommitment = (&G1Affine::rand(&mut rng)).into();
292 let bytes = try_standard_binary_serialization(commitment).unwrap();
293 let (deserialized_commitment, _): (HyperKZGCommitment, _) =
294 try_standard_binary_deserialization(&bytes[..]).unwrap();
295 assert_eq!(deserialized_commitment.commitment, commitment.commitment);
296 }
297 }
298}