Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

50 changes: 41 additions & 9 deletions crates/jolt-crypto/src/ec/bn254/gt.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,14 @@
use std::fmt::Debug;
use std::fmt::{self, Debug};
use std::ops::{Add, AddAssign, Mul, MulAssign, Neg, Sub, SubAssign};

use ark_bn254::{Fq12, Fr};
use ark_ff::{AdditiveGroup, Field as ArkField, PrimeField};
use ark_serialize::{
CanonicalDeserialize, CanonicalSerialize, Compress, Read, SerializationError, Valid, Validate,
Write,
};
use jolt_field::Field;
use serde::{Deserialize, Deserializer, Serialize, Serializer};

use jolt_transcript::{AppendToTranscript, Transcript};

Expand Down Expand Up @@ -32,7 +37,7 @@ use super::field_to_fr;
pub struct Bn254GT(pub(crate) Fq12);

impl Debug for Bn254GT {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_tuple("Bn254GT").field(&self.0).finish()
}
}
Expand Down Expand Up @@ -131,7 +136,6 @@ impl MulAssign for Bn254GT {
#[expect(clippy::expect_used)]
impl AppendToTranscript for Bn254GT {
fn append_to_transcript<T: Transcript>(&self, transcript: &mut T) {
use ark_serialize::CanonicalSerialize;
let mut buf = Vec::with_capacity(self.0.uncompressed_size());
self.0
.serialize_uncompressed(&mut buf)
Expand Down Expand Up @@ -177,9 +181,8 @@ impl JoltGroup for Bn254GT {
}
}

impl serde::Serialize for Bn254GT {
fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
use ark_serialize::CanonicalSerialize;
impl Serialize for Bn254GT {
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
let mut buf = Vec::with_capacity(self.0.compressed_size());
self.0
.serialize_compressed(&mut buf)
Expand All @@ -188,9 +191,8 @@ impl serde::Serialize for Bn254GT {
}
}

impl<'de> serde::Deserialize<'de> for Bn254GT {
fn deserialize<D: serde::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
use ark_serialize::CanonicalDeserialize;
impl<'de> Deserialize<'de> for Bn254GT {
fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
let buf = <Vec<u8>>::deserialize(deserializer)?;
let inner = Fq12::deserialize_compressed(&buf[..]).map_err(serde::de::Error::custom)?;
// Reject Fq12::ZERO: not in any multiplicative subgroup, and later
Expand All @@ -209,3 +211,33 @@ impl<'de> serde::Deserialize<'de> for Bn254GT {
Ok(Self(inner))
}
}

impl CanonicalSerialize for Bn254GT {
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can we just #[derive(CanonicalSerialize, CanonicalDeserialize)] on Bn254GT instead of manually implementing these?

fn serialize_with_mode<W: Write>(
&self,
writer: W,
compress: Compress,
) -> Result<(), SerializationError> {
self.0.serialize_with_mode(writer, compress)
}

fn serialized_size(&self, compress: Compress) -> usize {
self.0.serialized_size(compress)
}
}

impl Valid for Bn254GT {
fn check(&self) -> Result<(), SerializationError> {
self.0.check()
}
}

impl CanonicalDeserialize for Bn254GT {
fn deserialize_with_mode<R: Read>(
reader: R,
compress: Compress,
validate: Validate,
) -> Result<Self, SerializationError> {
Fq12::deserialize_with_mode(reader, compress, validate).map(Self)
}
}
65 changes: 48 additions & 17 deletions crates/jolt-crypto/src/ec/bn254/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,36 @@ macro_rules! impl_jolt_group_wrapper {
}
}

impl ::ark_serialize::CanonicalSerialize for $wrapper {
fn serialize_with_mode<W: ::ark_serialize::Write>(
&self,
writer: W,
compress: ::ark_serialize::Compress,
) -> Result<(), ::ark_serialize::SerializationError> {
self.0.serialize_with_mode(writer, compress)
}

fn serialized_size(&self, compress: ::ark_serialize::Compress) -> usize {
self.0.serialized_size(compress)
}
}

impl ::ark_serialize::Valid for $wrapper {
fn check(&self) -> Result<(), ::ark_serialize::SerializationError> {
self.0.check()
}
}

impl ::ark_serialize::CanonicalDeserialize for $wrapper {
fn deserialize_with_mode<R: ::ark_serialize::Read>(
reader: R,
compress: ::ark_serialize::Compress,
validate: ::ark_serialize::Validate,
) -> Result<Self, ::ark_serialize::SerializationError> {
<$projective>::deserialize_with_mode(reader, compress, validate).map(Self)
}
}

impl ::jolt_transcript::AppendToTranscript for $wrapper {
fn append_to_transcript<T: ::jolt_transcript::Transcript>(&self, transcript: &mut T) {
use ::ark_serialize::CanonicalSerialize;
Expand Down Expand Up @@ -194,11 +224,13 @@ pub use g1::Bn254G1;
pub use g2::Bn254G2;
pub use gt::Bn254GT;

use ark_bn254::Bn254 as ArkBn254;
use ark_bn254::{Bn254 as ArkBn254, Fr as ArkFr, G1Affine, G1Projective, G2Affine, G2Projective};
use ark_ec::pairing::Pairing;
use ark_ec::AffineRepr;
use ark_ec::CurveGroup;
use ark_ff::PrimeField as _;
use jolt_field::Field;
use ark_std::UniformRand;
use jolt_field::{Field, Fr as JoltFr};

use crate::PairingGroup;

Expand All @@ -209,25 +241,22 @@ pub struct Bn254;
impl Bn254 {
/// Standard G1 generator. Useful for tests and PCS setup code.
pub fn g1_generator() -> Bn254G1 {
use ark_ec::AffineRepr;
Bn254G1(ark_bn254::G1Affine::generator().into())
Bn254G1(G1Affine::generator().into())
}

/// Standard G2 generator. Useful for tests and PCS setup code.
pub fn g2_generator() -> Bn254G2 {
use ark_ec::AffineRepr;
Bn254G2(ark_bn254::G2Affine::generator().into())
Bn254G2(G2Affine::generator().into())
}

/// Samples a uniformly random G1 element.
pub fn random_g1<R: rand_core::RngCore>(rng: &mut R) -> Bn254G1 {
use ark_std::UniformRand;
Bn254G1(ark_bn254::G1Projective::rand(rng))
Bn254G1(G1Projective::rand(rng))
}
}

impl PairingGroup for Bn254 {
type ScalarField = jolt_field::Fr;
type ScalarField = JoltFr;
type G1 = Bn254G1;
type G2 = Bn254G2;
type GT = Bn254GT;
Expand All @@ -241,10 +270,10 @@ impl PairingGroup for Bn254 {
// Batched projective → affine normalization (one inversion for all points)
// is 10-100× faster than per-point `into_affine` for typical Dory/KZG verifier
// sizes.
let g1_projs: Vec<ark_bn254::G1Projective> = g1s.iter().map(|g| g.0).collect();
let g2_projs: Vec<ark_bn254::G2Projective> = g2s.iter().map(|g| g.0).collect();
let g1_affines = ark_bn254::G1Projective::normalize_batch(&g1_projs);
let g2_affines = ark_bn254::G2Projective::normalize_batch(&g2_projs);
let g1_projs: Vec<G1Projective> = g1s.iter().map(|g| g.0).collect();
let g2_projs: Vec<G2Projective> = g2s.iter().map(|g| g.0).collect();
let g1_affines = G1Projective::normalize_batch(&g1_projs);
let g2_affines = G2Projective::normalize_batch(&g2_projs);
Bn254GT(ArkBn254::multi_pairing(&g1_affines, &g2_affines).0)
}
}
Expand All @@ -258,18 +287,20 @@ impl PairingGroup for Bn254 {
/// In debug builds, asserts that the source value fits in the BN254 Fr modulus —
/// catches silent modular reduction when `F` has a larger modulus than BN254 Fr.
#[inline]
pub(crate) fn field_to_fr<F: Field>(f: &F) -> ark_bn254::Fr {
pub(crate) fn field_to_fr<F: Field>(f: &F) -> ArkFr {
let mut bytes = vec![0u8; F::NUM_BYTES];
f.to_bytes_le(&mut bytes);
#[cfg(debug_assertions)]
{
use ark_ff::{BigInteger, PrimeField as _};
let value = num_bigint::BigUint::from_bytes_le(&bytes);
let modulus = num_bigint::BigUint::from_bytes_le(&ark_bn254::Fr::MODULUS.to_bytes_le());
use num_bigint::BigUint;

let value = BigUint::from_bytes_le(&bytes);
let modulus = BigUint::from_bytes_le(&ArkFr::MODULUS.to_bytes_le());
debug_assert!(
value < modulus,
"field_to_fr: source value >= BN254 Fr modulus (silent reduction)",
);
}
ark_bn254::Fr::from_le_bytes_mod_order(&bytes)
ArkFr::from_le_bytes_mod_order(&bytes)
}
7 changes: 5 additions & 2 deletions crates/jolt-dory/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,16 +9,19 @@ description = "Dory commitment scheme implementation for the Jolt zkVM"
workspace = true

[dependencies]
ark-bn254 = { workspace = true, features = ["curve"] }
ark-ec = { workspace = true }
ark-serialize = { workspace = true }
jolt-crypto = { workspace = true }
jolt-field = { workspace = true }
jolt-openings = { workspace = true }
jolt-optimizations = { workspace = true }
jolt-poly = { workspace = true }
jolt-transcript = { workspace = true }
dory = { workspace = true }
tracing.workspace = true
rayon = { workspace = true }
serde = { workspace = true, features = ["derive"] }
tracing.workspace = true
ark-serialize = { workspace = true }

[dev-dependencies]
criterion = { workspace = true }
Expand Down
Loading