Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
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