Repository: nexus-xyz/nexus-zkvm
File: supernova/src/absorb.rs (Rust)

Code before:
/// The conversion to affine point must be consistent with in-circuit implementation.
impl<P: SWCurveConfig> AbsorbNonNative<P::ScalarField> for Projective<P>
where
    P::BaseField: PrimeField,
    P::ScalarField: Absorb,
{
    fn to_non_native_field_elements(&self, dest: &mut Vec<P::ScalarField>) {
        let affine = self.into_affine();

        let x = cast_field_element_unique::<P::BaseField, P::ScalarField>(&affine.x);
        let y = cast_field_element_unique::<P::BaseField, P::ScalarField>(&affine.y);
        let infinity = P::ScalarField::from(affine.infinity);
        Absorb::to_sponge_field_elements(&[&x[..], &y[..], &[infinity]].concat(), dest);
    }
}

/// Since r1cs instance contains both elements from F1 and F2, it's a matter of notion what to call
/// native absorb implementation: either it has to cast commitments coordinates or the input `X`.
///
/// Assume that native implementation is the one that doesn't have to cast public input.
impl<G, C> AbsorbNonNative<G::BaseField> for R1CSInstance<G, C>
where
    G: CurveGroup,
    G::BaseField: PrimeField + Absorb,
    G::Affine: Absorb,
    C: CommitmentScheme<G, Commitment = G>,
{
    fn to_non_native_field_elements(&self, dest: &mut Vec<G::BaseField>) {
        Absorb::to_sponge_field_elements(&self.commitment_W.into_affine(), dest);

        for x in &self.X[1..] {
            let x_base = cast_field_element_unique::<G::ScalarField, G::BaseField>(x);
            Absorb::to_sponge_field_elements(&x_base, dest);
        }
    }
}

/// See the above comment for [`R1CSInstance`] non-native absorb implementation.
impl<G, C> AbsorbNonNative<G::BaseField> for RelaxedR1CSInstance<G, C>
where
    G: CurveGroup,
    G::BaseField: PrimeField + Absorb,
    G::Affine: Absorb,
    C: CommitmentScheme<G, Commitment = G>,
{
    fn to_non_native_field_elements(&self, dest: &mut Vec<G::BaseField>) {
        Absorb::to_sponge_field_elements(&self.commitment_W.into_affine(), dest);
        Absorb::to_sponge_field_elements(&self.commitment_E.into_affine(), dest);

        for x in &self.X {
            let x_base = cast_field_element_unique::<G::ScalarField, G::BaseField>(x);

Review comment (suggestion):
good catch - i guess this impl is only used for the secondary circuit, so the compiler didn't catch this one. 

Code after:

/// Unique affine coordinates are non-native elements, boolean `infinity` is converted to `ZERO` or `ONE`.
///
/// The conversion to affine point must be consistent with in-circuit implementation.
impl<P: SWCurveConfig> AbsorbNonNative<P::ScalarField> for Projective<P>
where
    P::BaseField: PrimeField,
    P::ScalarField: Absorb,
{
    fn to_non_native_field_elements(&self, dest: &mut Vec<P::ScalarField>) {
        let affine = <Self as CurveGroup>::into_affine(*self);

        let x = cast_field_element_unique::<P::BaseField, P::ScalarField>(&affine.x);
        let y = cast_field_element_unique::<P::BaseField, P::ScalarField>(&affine.y);
        let infinity = P::ScalarField::from(affine.infinity);
        Absorb::to_sponge_field_elements(&[&x[..], &y[..], &[infinity]].concat(), dest);
    }
}

/// Since r1cs instance contains both elements from F1 and F2, it's a matter of notion what to call
/// native absorb implementation: either it has to cast commitments coordinates or the input `X`.
///
/// Assume that native implementation is the one that doesn't have to cast public input.
impl<G, C> AbsorbNonNative<G::BaseField> for R1CSInstance<G, C>
where
    G: CurveGroup,
    G::BaseField: PrimeField + Absorb,
    G::Affine: Absorb,
    C: CommitmentScheme<G>,
{
    fn to_non_native_field_elements(&self, dest: &mut Vec<G::BaseField>) {
        Absorb::to_sponge_field_elements(&self.commitment_W.into_affine(), dest);

        for x in &self.X[1..] {
            let x_base = cast_field_element_unique::<G::ScalarField, G::BaseField>(x);
            Absorb::to_sponge_field_elements(&x_base, dest);
        }
    }
}

/// See the above comment for [`R1CSInstance`] non-native absorb implementation.
impl<G, C> AbsorbNonNative<G::BaseField> for RelaxedR1CSInstance<G, C>
where
    G: CurveGroup,
    G::BaseField: PrimeField + Absorb,
    G::Affine: Absorb,
    C: CommitmentScheme<G>,
{
    fn to_non_native_field_elements(&self, dest: &mut Vec<G::BaseField>) {
        Absorb::to_sponge_field_elements(&self.commitment_W.into_affine(), dest);
        Absorb::to_sponge_field_elements(&self.commitment_E.into_affine(), dest);