Skip to content

Instantly share code, notes, and snippets.

@burdges
Last active November 11, 2025 15:30
Show Gist options
  • Select an option

  • Save burdges/079d24dba55e5033117d8a3b7f26ca4f to your computer and use it in GitHub Desktop.

Select an option

Save burdges/079d24dba55e5033117d8a3b7f26ca4f to your computer and use it in GitHub Desktop.
pub struct Plonkish<P: Pairing> {
pub lhs_size: usize,
pub rhs_size: usize,
/// We require exactly one of the g2 pooints be negated.
pub g2s: &'static [P::G2Affine; 2],
}
#[derive(Clone,CanonicalDeserialize,CanonicalSerialize)]
struct Side<C: CurveGroup> {
scalars: Vec<<C as CurveGroup>::ScalarField>,
points: Vec<<C as CurveGroup>::Affine>,
}
#[derive(Clone,CanonicalDeserialize,CanonicalSerialize)]
struct PlonkishInner<C: CurveGroup> {
lhs: Side<C>,
rhs: Side<C>,
}
pub struct PlonkishAcc<P: Pairing,const S: Plonkish>(Option<PlonkishInner<<P as Pairing>::G1,S>)
impl<P: Pairing,const S: Plonkish> PlonkishAcc<P::G1,S> {
pub const fn nonbatched() -> PlonkishAcc { PlonkishAcc(None) }
pub fn batched(size: usize) -> PlonkishAcc {
let lhs = Side {
scalars: Vec::with_capacity(size * S.lhs_size)
points: Vec::with_capacity(size * S.lhs_size)
};
let rhs = Side {
scalars: Vec::with_capacity(size * S.rhs_size)
points: Vec::with_capacity(size * S.rhs_size)
};
PlonkishAcc(Some(PlonkishInner { lhs, rhs })}
}
/// Add a debt to the batch accumulator or verify it now if not in batching mode
pub fn add_debt(
&mut self,
lhs_points: &[P::G1Affine, S.lhs_size],
lhs_scalars: &[P::ScalarField, S.lhs_size],
rhs_points: &[P::G1Affine, S.rhs_size],
rhs_scalars: &[P::ScalarField, S.rhs_size],
) {
if let Some(selfy) = self {
selfy.lhs.points.extend(lhs_points);
selfy.lhs.scalars.extend(lhs_scalars);
selfy.rhs.points.extend(rhs_points);
selfy.rhs.scalars.extend(rhs_scalars);
true
} else {
let l = P::G1::msm(lhs_points, lhs_scalars);
let r = P::G1::msm(rhs_points, rhs_scalars);
P::multi_pairing(&[l,r],S::g2s).is_one()
}
}
/// Consume the current batch accumulator and return it to nonbatched mode
pub fn verify_debts(&mut self) -> bool {
if self.0.is_none() { return true; }
let mut selfy = core::mem::take(self.0).unwrap();
let mut t = ark_transcript::new_labeled(b"Plonkish batch verifier");
t.append(selfy);
for (l,r) in selfy.lhs.scalars.chunks_mut(S.lhs_size)
.zip(selfy.rhs.scalars.chunks_mut(S.rhs_size))
{
let pos = t.challenge(b"r");
for s in l.iter_mut() { s *= pos; }
for s in r.iter_mut() { s *= neg; }
}
let l = P::G1::msm(selfy.lhs.points, selfy.lhs.scalars);
let r = P::G1::msm(selfy.rhs.points, selfy.rhs.scalars);
P::multi_pairing(&[l,r],S::g2s).is_one()
}
}
@burdges
Copy link
Author

burdges commented Oct 28, 2025

An actual substrate verifier would use this like

type Bls12_381 = ark_bls12_381::Bls12_381;

static LEFT_G2: Bls12_381::G2Affine = ..;
static RIGHT_G2: Bls12_381::G2Affine = ..;

const WEB3SUM_RVRF_PARAMS: Plonkish = Plonkish {
    lhs_size: 5,  // ??
    rhs_size: 5,  // ??
    g2s: [LEFT_G2,RIGHT_G2]
};
type Web3SumPlonkishAcc = PlonkishAcc<Bls12_381,WEB3SUM_RVRF_PARAMS>
 
static mut WEB3SUM_RVRF_DEBTS: Option<Web3SumPlonkishAcc> = PlonkishAcc::nonbatched();

@burdges
Copy link
Author

burdges commented Oct 28, 2025

Actually none of that would be visible to the end user though, because you'd do everything from the wraper crate that specilizes the curves etc. You'd jsut have the existing verifier fn, and a new fn for on_initialzie and on_finalize

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment