* Add a dedicated variant of `mat_vec_mul_sparse` for `NonNativeFieldVar` * Switch to a customized in-circuit nonnative implementation for efficiency * Comments and tests for `NonNativeUintVar` * Make `CycleFoldCircuit` a bit smaller * Faster trusted setup and proof generation by avoiding some nested LCs * Check the remaining limbs in a more safe way * Format * Disable the non-native checks in tests again * Clarify the group operation in `enforce_equal_unaligned` * Explain the rationale behind non-native mat-vec multiplication * Explain the difference with some other impls of `enforce_equal_unaligned` * Formatmain
@ -1,306 +0,0 @@ |
|||||
use ark_ec::{AffineRepr, CurveGroup};
|
|
||||
use ark_ff::{BigInteger, PrimeField};
|
|
||||
use ark_r1cs_std::{
|
|
||||
alloc::{AllocVar, AllocationMode},
|
|
||||
boolean::Boolean,
|
|
||||
fields::{
|
|
||||
fp::FpVar,
|
|
||||
nonnative::{
|
|
||||
params::{get_params, OptimizationType},
|
|
||||
AllocatedNonNativeFieldVar, NonNativeFieldVar,
|
|
||||
},
|
|
||||
FieldVar,
|
|
||||
},
|
|
||||
ToBitsGadget, ToConstraintFieldGadget,
|
|
||||
};
|
|
||||
use ark_relations::r1cs::{ConstraintSystemRef, Namespace, OptimizationGoal, SynthesisError};
|
|
||||
use ark_std::Zero;
|
|
||||
use core::borrow::Borrow;
|
|
||||
use std::marker::PhantomData;
|
|
||||
|
|
||||
/// Compose a vector boolean into a `NonNativeFieldVar`
|
|
||||
pub fn nonnative_field_var_from_le_bits<TargetField: PrimeField, BaseField: PrimeField>(
|
|
||||
cs: ConstraintSystemRef<BaseField>,
|
|
||||
bits: &[Boolean<BaseField>],
|
|
||||
) -> Result<NonNativeFieldVar<TargetField, BaseField>, SynthesisError> {
|
|
||||
let params = get_params(
|
|
||||
TargetField::MODULUS_BIT_SIZE as usize,
|
|
||||
BaseField::MODULUS_BIT_SIZE as usize,
|
|
||||
match cs.optimization_goal() {
|
|
||||
OptimizationGoal::None => OptimizationType::Constraints,
|
|
||||
OptimizationGoal::Constraints => OptimizationType::Constraints,
|
|
||||
OptimizationGoal::Weight => OptimizationType::Weight,
|
|
||||
},
|
|
||||
);
|
|
||||
|
|
||||
// push the lower limbs first
|
|
||||
let mut limbs = bits
|
|
||||
.chunks(params.bits_per_limb)
|
|
||||
.map(Boolean::le_bits_to_fp_var)
|
|
||||
.collect::<Result<Vec<_>, _>>()?;
|
|
||||
limbs.resize(params.num_limbs, FpVar::zero());
|
|
||||
limbs.reverse();
|
|
||||
|
|
||||
Ok(AllocatedNonNativeFieldVar {
|
|
||||
cs,
|
|
||||
limbs,
|
|
||||
num_of_additions_over_normal_form: BaseField::one(),
|
|
||||
is_in_the_normal_form: false,
|
|
||||
target_phantom: PhantomData,
|
|
||||
}
|
|
||||
.into())
|
|
||||
}
|
|
||||
|
|
||||
/// A more efficient version of `NonNativeFieldVar::to_constraint_field`
|
|
||||
pub fn nonnative_field_var_to_constraint_field<TargetField: PrimeField, BaseField: PrimeField>(
|
|
||||
f: &NonNativeFieldVar<TargetField, BaseField>,
|
|
||||
) -> Result<Vec<FpVar<BaseField>>, SynthesisError> {
|
|
||||
let bits = f.to_bits_le()?;
|
|
||||
|
|
||||
let bits_per_limb = BaseField::MODULUS_BIT_SIZE as usize - 1;
|
|
||||
let num_limbs = (TargetField::MODULUS_BIT_SIZE as usize).div_ceil(bits_per_limb);
|
|
||||
|
|
||||
let mut limbs = bits
|
|
||||
.chunks(bits_per_limb)
|
|
||||
.map(|chunk| {
|
|
||||
let mut limb = FpVar::<BaseField>::zero();
|
|
||||
let mut w = BaseField::one();
|
|
||||
for b in chunk.iter() {
|
|
||||
limb += FpVar::from(b.clone()) * w;
|
|
||||
w.double_in_place();
|
|
||||
}
|
|
||||
limb
|
|
||||
})
|
|
||||
.collect::<Vec<FpVar<BaseField>>>();
|
|
||||
limbs.resize(num_limbs, FpVar::zero());
|
|
||||
limbs.reverse();
|
|
||||
|
|
||||
Ok(limbs)
|
|
||||
}
|
|
||||
|
|
||||
/// The out-circuit counterpart of `nonnative_field_var_to_constraint_field`
|
|
||||
pub fn nonnative_field_to_field_elements<TargetField: PrimeField, BaseField: PrimeField>(
|
|
||||
f: &TargetField,
|
|
||||
) -> Vec<BaseField> {
|
|
||||
let bits = f.into_bigint().to_bits_le();
|
|
||||
|
|
||||
let bits_per_limb = BaseField::MODULUS_BIT_SIZE as usize - 1;
|
|
||||
let num_limbs = (TargetField::MODULUS_BIT_SIZE as usize).div_ceil(bits_per_limb);
|
|
||||
|
|
||||
let mut limbs = bits
|
|
||||
.chunks(bits_per_limb)
|
|
||||
.map(|chunk| {
|
|
||||
let mut limb = BaseField::zero();
|
|
||||
let mut w = BaseField::one();
|
|
||||
for &b in chunk.iter() {
|
|
||||
limb += BaseField::from(b) * w;
|
|
||||
w.double_in_place();
|
|
||||
}
|
|
||||
limb
|
|
||||
})
|
|
||||
.collect::<Vec<BaseField>>();
|
|
||||
limbs.resize(num_limbs, BaseField::zero());
|
|
||||
limbs.reverse();
|
|
||||
|
|
||||
limbs
|
|
||||
}
|
|
||||
|
|
||||
/// NonNativeAffineVar represents an elliptic curve point in Affine representation in the non-native
|
|
||||
/// field, over the constraint field. It is not intended to perform operations, but just to contain
|
|
||||
/// the affine coordinates in order to perform hash operations of the point.
|
|
||||
#[derive(Debug, Clone)]
|
|
||||
pub struct NonNativeAffineVar<C: CurveGroup>
|
|
||||
where
|
|
||||
<C as ark_ec::CurveGroup>::BaseField: ark_ff::PrimeField,
|
|
||||
{
|
|
||||
pub x: NonNativeFieldVar<C::BaseField, C::ScalarField>,
|
|
||||
pub y: NonNativeFieldVar<C::BaseField, C::ScalarField>,
|
|
||||
}
|
|
||||
|
|
||||
impl<C> AllocVar<C, C::ScalarField> for NonNativeAffineVar<C>
|
|
||||
where
|
|
||||
C: CurveGroup,
|
|
||||
<C as ark_ec::CurveGroup>::BaseField: ark_ff::PrimeField,
|
|
||||
{
|
|
||||
fn new_variable<T: Borrow<C>>(
|
|
||||
cs: impl Into<Namespace<C::ScalarField>>,
|
|
||||
f: impl FnOnce() -> Result<T, SynthesisError>,
|
|
||||
mode: AllocationMode,
|
|
||||
) -> Result<Self, SynthesisError> {
|
|
||||
f().and_then(|val| {
|
|
||||
let cs = cs.into();
|
|
||||
|
|
||||
let affine = val.borrow().into_affine();
|
|
||||
let zero_point = (&C::BaseField::zero(), &C::BaseField::zero());
|
|
||||
let xy = affine.xy().unwrap_or(zero_point);
|
|
||||
|
|
||||
let x = NonNativeFieldVar::<C::BaseField, C::ScalarField>::new_variable(
|
|
||||
cs.clone(),
|
|
||||
|| Ok(xy.0),
|
|
||||
mode,
|
|
||||
)?;
|
|
||||
let y = NonNativeFieldVar::<C::BaseField, C::ScalarField>::new_variable(
|
|
||||
cs.clone(),
|
|
||||
|| Ok(xy.1),
|
|
||||
mode,
|
|
||||
)?;
|
|
||||
|
|
||||
Ok(Self { x, y })
|
|
||||
})
|
|
||||
}
|
|
||||
}
|
|
||||
|
|
||||
impl<C: CurveGroup> ToConstraintFieldGadget<C::ScalarField> for NonNativeAffineVar<C>
|
|
||||
where
|
|
||||
<C as ark_ec::CurveGroup>::BaseField: ark_ff::PrimeField,
|
|
||||
{
|
|
||||
// A more efficient version of `point_to_nonnative_limbs_custom_opt`.
|
|
||||
// Used for converting `NonNativeAffineVar` to a vector of `FpVar` with minimum length in
|
|
||||
// the circuit.
|
|
||||
fn to_constraint_field(&self) -> Result<Vec<FpVar<C::ScalarField>>, SynthesisError> {
|
|
||||
let x = nonnative_field_var_to_constraint_field(&self.x)?;
|
|
||||
let y = nonnative_field_var_to_constraint_field(&self.y)?;
|
|
||||
Ok([x, y].concat())
|
|
||||
}
|
|
||||
}
|
|
||||
|
|
||||
/// The out-circuit counterpart of `NonNativeAffineVar::to_constraint_field`
|
|
||||
#[allow(clippy::type_complexity)]
|
|
||||
pub fn nonnative_affine_to_field_elements<C: CurveGroup>(
|
|
||||
p: C,
|
|
||||
) -> Result<(Vec<C::ScalarField>, Vec<C::ScalarField>), SynthesisError>
|
|
||||
where
|
|
||||
<C as ark_ec::CurveGroup>::BaseField: ark_ff::PrimeField,
|
|
||||
{
|
|
||||
let affine = p.into_affine();
|
|
||||
if affine.is_zero() {
|
|
||||
let x = nonnative_field_to_field_elements(&C::BaseField::zero());
|
|
||||
let y = nonnative_field_to_field_elements(&C::BaseField::zero());
|
|
||||
return Ok((x, y));
|
|
||||
}
|
|
||||
|
|
||||
let (x, y) = affine.xy().unwrap();
|
|
||||
let x = nonnative_field_to_field_elements(x);
|
|
||||
let y = nonnative_field_to_field_elements(y);
|
|
||||
Ok((x, y))
|
|
||||
}
|
|
||||
|
|
||||
impl<C: CurveGroup> NonNativeAffineVar<C>
|
|
||||
where
|
|
||||
<C as ark_ec::CurveGroup>::BaseField: ark_ff::PrimeField,
|
|
||||
{
|
|
||||
// A wrapper of `point_to_nonnative_limbs_custom_opt` with constraints-focused optimization
|
|
||||
// type (which is the default optimization type for arkworks' Groth16).
|
|
||||
// Used for extracting a list of field elements of type `C::ScalarField` from the public input
|
|
||||
// `p`, in exactly the same way as how `NonNativeAffineVar` is represented as limbs of type
|
|
||||
// `FpVar` in-circuit.
|
|
||||
#[allow(clippy::type_complexity)]
|
|
||||
pub fn inputize(p: C) -> Result<(Vec<C::ScalarField>, Vec<C::ScalarField>), SynthesisError> {
|
|
||||
point_to_nonnative_limbs_custom_opt(p, OptimizationType::Constraints)
|
|
||||
}
|
|
||||
}
|
|
||||
|
|
||||
// Used to compute (outside the circuit) the limbs representation of a point.
|
|
||||
// For `OptimizationType::Constraints`, the result matches the one used in-circuit.
|
|
||||
// For `OptimizationType::Weight`, the result vector is more dense and is suitable for hashing.
|
|
||||
// It is possible to further optimize the length of the result vector (see
|
|
||||
// `nonnative_affine_to_field_elements`)
|
|
||||
#[allow(clippy::type_complexity)]
|
|
||||
fn point_to_nonnative_limbs_custom_opt<C: CurveGroup>(
|
|
||||
p: C,
|
|
||||
optimization_type: OptimizationType,
|
|
||||
) -> Result<(Vec<C::ScalarField>, Vec<C::ScalarField>), SynthesisError>
|
|
||||
where
|
|
||||
<C as ark_ec::CurveGroup>::BaseField: ark_ff::PrimeField,
|
|
||||
{
|
|
||||
let affine = p.into_affine();
|
|
||||
if affine.is_zero() {
|
|
||||
let x =
|
|
||||
AllocatedNonNativeFieldVar::<C::BaseField, C::ScalarField>::get_limbs_representations(
|
|
||||
&C::BaseField::zero(),
|
|
||||
optimization_type,
|
|
||||
)?;
|
|
||||
let y =
|
|
||||
AllocatedNonNativeFieldVar::<C::BaseField, C::ScalarField>::get_limbs_representations(
|
|
||||
&C::BaseField::zero(),
|
|
||||
optimization_type,
|
|
||||
)?;
|
|
||||
return Ok((x, y));
|
|
||||
}
|
|
||||
|
|
||||
let (x, y) = affine.xy().unwrap();
|
|
||||
let x = AllocatedNonNativeFieldVar::<C::BaseField, C::ScalarField>::get_limbs_representations(
|
|
||||
x,
|
|
||||
optimization_type,
|
|
||||
)?;
|
|
||||
let y = AllocatedNonNativeFieldVar::<C::BaseField, C::ScalarField>::get_limbs_representations(
|
|
||||
y,
|
|
||||
optimization_type,
|
|
||||
)?;
|
|
||||
Ok((x, y))
|
|
||||
}
|
|
||||
|
|
||||
#[cfg(test)]
|
|
||||
mod tests {
|
|
||||
use super::*;
|
|
||||
use ark_pallas::{Fr, Projective};
|
|
||||
use ark_r1cs_std::R1CSVar;
|
|
||||
use ark_relations::r1cs::ConstraintSystem;
|
|
||||
use ark_std::UniformRand;
|
|
||||
|
|
||||
#[test]
|
|
||||
fn test_alloc_zero() {
|
|
||||
let cs = ConstraintSystem::<Fr>::new_ref();
|
|
||||
|
|
||||
// dealing with the 'zero' point should not panic when doing the unwrap
|
|
||||
let p = Projective::zero();
|
|
||||
assert!(NonNativeAffineVar::<Projective>::new_witness(cs.clone(), || Ok(p)).is_ok());
|
|
||||
}
|
|
||||
|
|
||||
#[test]
|
|
||||
fn test_arkworks_to_constraint_field() {
|
|
||||
let cs = ConstraintSystem::<Fr>::new_ref();
|
|
||||
|
|
||||
// check that point_to_nonnative_limbs returns the expected values
|
|
||||
let mut rng = ark_std::test_rng();
|
|
||||
let p = Projective::rand(&mut rng);
|
|
||||
let pVar = NonNativeAffineVar::<Projective>::new_witness(cs.clone(), || Ok(p)).unwrap();
|
|
||||
let (x, y) = point_to_nonnative_limbs_custom_opt(p, OptimizationType::Weight).unwrap();
|
|
||||
assert_eq!(pVar.x.to_constraint_field().unwrap().value().unwrap(), x);
|
|
||||
assert_eq!(pVar.y.to_constraint_field().unwrap().value().unwrap(), y);
|
|
||||
}
|
|
||||
|
|
||||
#[test]
|
|
||||
fn test_improved_to_constraint_field() {
|
|
||||
let cs = ConstraintSystem::<Fr>::new_ref();
|
|
||||
|
|
||||
// check that point_to_nonnative_limbs returns the expected values
|
|
||||
let mut rng = ark_std::test_rng();
|
|
||||
let p = Projective::rand(&mut rng);
|
|
||||
let pVar = NonNativeAffineVar::<Projective>::new_witness(cs.clone(), || Ok(p)).unwrap();
|
|
||||
let (x, y) = nonnative_affine_to_field_elements(p).unwrap();
|
|
||||
assert_eq!(
|
|
||||
pVar.to_constraint_field().unwrap().value().unwrap(),
|
|
||||
[x, y].concat()
|
|
||||
);
|
|
||||
}
|
|
||||
|
|
||||
#[test]
|
|
||||
fn test_inputize() {
|
|
||||
let cs = ConstraintSystem::<Fr>::new_ref();
|
|
||||
|
|
||||
// check that point_to_nonnative_limbs returns the expected values
|
|
||||
let mut rng = ark_std::test_rng();
|
|
||||
let p = Projective::rand(&mut rng);
|
|
||||
let pVar = NonNativeAffineVar::<Projective>::new_witness(cs.clone(), || Ok(p)).unwrap();
|
|
||||
let (x, y) = NonNativeAffineVar::inputize(p).unwrap();
|
|
||||
|
|
||||
match (pVar.x, pVar.y) {
|
|
||||
(NonNativeFieldVar::Var(p_x), NonNativeFieldVar::Var(p_y)) => {
|
|
||||
assert_eq!(p_x.limbs.value().unwrap(), x);
|
|
||||
assert_eq!(p_y.limbs.value().unwrap(), y);
|
|
||||
}
|
|
||||
_ => unreachable!(),
|
|
||||
}
|
|
||||
}
|
|
||||
}
|
|
@ -0,0 +1,161 @@ |
|||||
|
use ark_ec::{AffineRepr, CurveGroup};
|
||||
|
use ark_ff::PrimeField;
|
||||
|
use ark_r1cs_std::{
|
||||
|
alloc::{AllocVar, AllocationMode},
|
||||
|
fields::fp::FpVar,
|
||||
|
ToConstraintFieldGadget,
|
||||
|
};
|
||||
|
use ark_relations::r1cs::{Namespace, SynthesisError};
|
||||
|
use ark_std::Zero;
|
||||
|
use core::borrow::Borrow;
|
||||
|
|
||||
|
use super::uint::{nonnative_field_to_field_elements, NonNativeUintVar};
|
||||
|
|
||||
|
/// NonNativeAffineVar represents an elliptic curve point in Affine representation in the non-native
|
||||
|
/// field, over the constraint field. It is not intended to perform operations, but just to contain
|
||||
|
/// the affine coordinates in order to perform hash operations of the point.
|
||||
|
#[derive(Debug, Clone)]
|
||||
|
pub struct NonNativeAffineVar<C: CurveGroup>
|
||||
|
where
|
||||
|
<C as ark_ec::CurveGroup>::BaseField: ark_ff::PrimeField,
|
||||
|
{
|
||||
|
pub x: NonNativeUintVar<C::ScalarField>,
|
||||
|
pub y: NonNativeUintVar<C::ScalarField>,
|
||||
|
}
|
||||
|
|
||||
|
impl<C> AllocVar<C, C::ScalarField> for NonNativeAffineVar<C>
|
||||
|
where
|
||||
|
C: CurveGroup,
|
||||
|
<C as ark_ec::CurveGroup>::BaseField: ark_ff::PrimeField,
|
||||
|
{
|
||||
|
fn new_variable<T: Borrow<C>>(
|
||||
|
cs: impl Into<Namespace<C::ScalarField>>,
|
||||
|
f: impl FnOnce() -> Result<T, SynthesisError>,
|
||||
|
mode: AllocationMode,
|
||||
|
) -> Result<Self, SynthesisError> {
|
||||
|
f().and_then(|val| {
|
||||
|
let cs = cs.into();
|
||||
|
|
||||
|
let affine = val.borrow().into_affine();
|
||||
|
let zero_point = (&C::BaseField::zero(), &C::BaseField::zero());
|
||||
|
let xy = affine.xy().unwrap_or(zero_point);
|
||||
|
|
||||
|
let x = NonNativeUintVar::new_variable(cs.clone(), || Ok(*xy.0), mode)?;
|
||||
|
let y = NonNativeUintVar::new_variable(cs.clone(), || Ok(*xy.1), mode)?;
|
||||
|
|
||||
|
Ok(Self { x, y })
|
||||
|
})
|
||||
|
}
|
||||
|
}
|
||||
|
|
||||
|
impl<C: CurveGroup> ToConstraintFieldGadget<C::ScalarField> for NonNativeAffineVar<C>
|
||||
|
where
|
||||
|
<C as ark_ec::CurveGroup>::BaseField: ark_ff::PrimeField,
|
||||
|
{
|
||||
|
// Used for converting `NonNativeAffineVar` to a vector of `FpVar` with minimum length in
|
||||
|
// the circuit.
|
||||
|
fn to_constraint_field(&self) -> Result<Vec<FpVar<C::ScalarField>>, SynthesisError> {
|
||||
|
let x = self.x.to_constraint_field()?;
|
||||
|
let y = self.y.to_constraint_field()?;
|
||||
|
Ok([x, y].concat())
|
||||
|
}
|
||||
|
}
|
||||
|
|
||||
|
/// The out-circuit counterpart of `NonNativeAffineVar::to_constraint_field`
|
||||
|
#[allow(clippy::type_complexity)]
|
||||
|
pub fn nonnative_affine_to_field_elements<C: CurveGroup>(
|
||||
|
p: C,
|
||||
|
) -> Result<(Vec<C::ScalarField>, Vec<C::ScalarField>), SynthesisError>
|
||||
|
where
|
||||
|
<C as ark_ec::CurveGroup>::BaseField: ark_ff::PrimeField,
|
||||
|
{
|
||||
|
let affine = p.into_affine();
|
||||
|
if affine.is_zero() {
|
||||
|
let x = nonnative_field_to_field_elements(&C::BaseField::zero());
|
||||
|
let y = nonnative_field_to_field_elements(&C::BaseField::zero());
|
||||
|
return Ok((x, y));
|
||||
|
}
|
||||
|
|
||||
|
let (x, y) = affine.xy().unwrap();
|
||||
|
let x = nonnative_field_to_field_elements(x);
|
||||
|
let y = nonnative_field_to_field_elements(y);
|
||||
|
Ok((x, y))
|
||||
|
}
|
||||
|
|
||||
|
impl<C: CurveGroup> NonNativeAffineVar<C>
|
||||
|
where
|
||||
|
<C as ark_ec::CurveGroup>::BaseField: ark_ff::PrimeField,
|
||||
|
{
|
||||
|
// A wrapper of `point_to_nonnative_limbs_custom_opt` with constraints-focused optimization
|
||||
|
// type (which is the default optimization type for arkworks' Groth16).
|
||||
|
// Used for extracting a list of field elements of type `C::ScalarField` from the public input
|
||||
|
// `p`, in exactly the same way as how `NonNativeAffineVar` is represented as limbs of type
|
||||
|
// `FpVar` in-circuit.
|
||||
|
#[allow(clippy::type_complexity)]
|
||||
|
pub fn inputize(p: C) -> Result<(Vec<C::ScalarField>, Vec<C::ScalarField>), SynthesisError> {
|
||||
|
let affine = p.into_affine();
|
||||
|
if affine.is_zero() {
|
||||
|
let x = NonNativeUintVar::inputize(
|
||||
|
&(C::ScalarField::zero()).into(),
|
||||
|
C::ScalarField::MODULUS_BIT_SIZE as usize,
|
||||
|
);
|
||||
|
let y = NonNativeUintVar::inputize(
|
||||
|
&(C::ScalarField::zero()).into(),
|
||||
|
C::ScalarField::MODULUS_BIT_SIZE as usize,
|
||||
|
);
|
||||
|
return Ok((x, y));
|
||||
|
}
|
||||
|
|
||||
|
let (x, y) = affine.xy().unwrap();
|
||||
|
let x = NonNativeUintVar::inputize(&(*x).into(), C::ScalarField::MODULUS_BIT_SIZE as usize);
|
||||
|
let y = NonNativeUintVar::inputize(&(*y).into(), C::ScalarField::MODULUS_BIT_SIZE as usize);
|
||||
|
Ok((x, y))
|
||||
|
}
|
||||
|
}
|
||||
|
|
||||
|
#[cfg(test)]
|
||||
|
mod tests {
|
||||
|
use super::*;
|
||||
|
use ark_pallas::{Fr, Projective};
|
||||
|
use ark_r1cs_std::R1CSVar;
|
||||
|
use ark_relations::r1cs::ConstraintSystem;
|
||||
|
use ark_std::UniformRand;
|
||||
|
|
||||
|
#[test]
|
||||
|
fn test_alloc_zero() {
|
||||
|
let cs = ConstraintSystem::<Fr>::new_ref();
|
||||
|
|
||||
|
// dealing with the 'zero' point should not panic when doing the unwrap
|
||||
|
let p = Projective::zero();
|
||||
|
assert!(NonNativeAffineVar::<Projective>::new_witness(cs.clone(), || Ok(p)).is_ok());
|
||||
|
}
|
||||
|
|
||||
|
#[test]
|
||||
|
fn test_improved_to_constraint_field() {
|
||||
|
let cs = ConstraintSystem::<Fr>::new_ref();
|
||||
|
|
||||
|
// check that point_to_nonnative_limbs returns the expected values
|
||||
|
let mut rng = ark_std::test_rng();
|
||||
|
let p = Projective::rand(&mut rng);
|
||||
|
let pVar = NonNativeAffineVar::<Projective>::new_witness(cs.clone(), || Ok(p)).unwrap();
|
||||
|
let (x, y) = nonnative_affine_to_field_elements(p).unwrap();
|
||||
|
assert_eq!(
|
||||
|
pVar.to_constraint_field().unwrap().value().unwrap(),
|
||||
|
[x, y].concat()
|
||||
|
);
|
||||
|
}
|
||||
|
|
||||
|
#[test]
|
||||
|
fn test_inputize() {
|
||||
|
let cs = ConstraintSystem::<Fr>::new_ref();
|
||||
|
|
||||
|
// check that point_to_nonnative_limbs returns the expected values
|
||||
|
let mut rng = ark_std::test_rng();
|
||||
|
let p = Projective::rand(&mut rng);
|
||||
|
let pVar = NonNativeAffineVar::<Projective>::new_witness(cs.clone(), || Ok(p)).unwrap();
|
||||
|
let (x, y) = NonNativeAffineVar::inputize(p).unwrap();
|
||||
|
|
||||
|
assert_eq!(pVar.x.0.value().unwrap(), x);
|
||||
|
assert_eq!(pVar.y.0.value().unwrap(), y);
|
||||
|
}
|
||||
|
}
|
@ -0,0 +1,2 @@ |
|||||
|
pub mod affine;
|
||||
|
pub mod uint;
|