@ -1,7 +1,7 @@
use super ::{
use super ::{
params ::{ get_params , OptimizationType } ,
params ::{ get_params , OptimizationType } ,
reduce ::{ bigint_to_basefield , limbs_to_bigint , Reducer } ,
reduce ::{ bigint_to_basefield , limbs_to_bigint , Reducer } ,
AllocatedNonNativeField MulResultVar ,
AllocatedMulResultVar ,
} ;
} ;
use crate ::{ fields ::fp ::FpVar , prelude ::* , ToConstraintFieldGadget } ;
use crate ::{ fields ::fp ::FpVar , prelude ::* , ToConstraintFieldGadget } ;
use ark_ff ::{ BigInteger , PrimeField } ;
use ark_ff ::{ BigInteger , PrimeField } ;
@ -19,58 +19,53 @@ use ark_std::{
vec ::Vec ,
vec ::Vec ,
} ;
} ;
/// The allocated version of `NonNativeField Var` (introduced below)
/// The allocated version of `EmulatedFp Var` (introduced below)
#[ derive(Debug) ]
#[ derive(Debug) ]
#[ must_use ]
#[ must_use ]
pub struct AllocatedNonNativeField Var < TargetField : PrimeField , BaseField : PrimeField > {
pub struct AllocatedEmulatedFp Var < TargetF : PrimeField , BaseF : PrimeField > {
/// Constraint system reference
/// Constraint system reference
pub cs : ConstraintSystemRef < BaseField > ,
/// The limbs, each of which is a BaseField gadget.
pub limbs : Vec < FpVar < BaseField > > ,
pub cs : ConstraintSystemRef < BaseF > ,
/// The limbs, each of which is a BaseF gadget.
pub limbs : Vec < FpVar < BaseF > > ,
/// Number of additions done over this gadget, using which the gadget
/// Number of additions done over this gadget, using which the gadget
/// decides when to reduce.
/// decides when to reduce.
pub num_of_additions_over_normal_form : BaseField ,
pub num_of_additions_over_normal_form : BaseF ,
/// Whether the limb representation is the normal form (using only the bits
/// Whether the limb representation is the normal form (using only the bits
/// specified in the parameters, and the representation is strictly within
/// specified in the parameters, and the representation is strictly within
/// the range of TargetField ).
/// the range of TargetF).
pub is_in_the_normal_form : bool ,
pub is_in_the_normal_form : bool ,
#[ doc(hidden) ]
#[ doc(hidden) ]
pub target_phantom : PhantomData < TargetField > ,
pub target_phantom : PhantomData < TargetF > ,
}
}
impl < TargetField : PrimeField , BaseField : PrimeField >
AllocatedNonNativeFieldVar < TargetField , BaseField >
{
impl < TargetF : PrimeField , BaseF : PrimeField > AllocatedEmulatedFpVar < TargetF , BaseF > {
/// Return cs
/// Return cs
pub fn cs ( & self ) -> ConstraintSystemRef < BaseField > {
pub fn cs ( & self ) -> ConstraintSystemRef < BaseF > {
self . cs . clone ( )
self . cs . clone ( )
}
}
/// Obtain the value of limbs
/// Obtain the value of limbs
pub fn limbs_to_value (
limbs : Vec < BaseField > ,
optimization_type : OptimizationType ,
) -> TargetField {
pub fn limbs_to_value ( limbs : Vec < BaseF > , optimization_type : OptimizationType ) -> TargetF {
let params = get_params (
let params = get_params (
TargetField ::MODULUS_BIT_SIZE as usize ,
BaseField ::MODULUS_BIT_SIZE as usize ,
TargetF ::MODULUS_BIT_SIZE as usize ,
BaseF ::MODULUS_BIT_SIZE as usize ,
optimization_type ,
optimization_type ,
) ;
) ;
// Convert 2^{(params.bits_per_limb - 1)} into the TargetField and then double
// Convert 2^{(params.bits_per_limb - 1)} into the TargetF and then double
// the base This is because 2^{(params.bits_per_limb)} might indeed be
// the base This is because 2^{(params.bits_per_limb)} might indeed be
// larger than the target field's prime.
// larger than the target field's prime.
let base_repr = TargetField ::ONE . into_bigint ( ) < < ( params . bits_per_limb - 1 ) as u32 ;
let base_repr = TargetF ::ONE . into_bigint ( ) < < ( params . bits_per_limb - 1 ) as u32 ;
let mut base = TargetField ::from_bigint ( base_repr ) . unwrap ( ) ;
let mut base = TargetF ::from_bigint ( base_repr ) . unwrap ( ) ;
base . double_in_place ( ) ;
base . double_in_place ( ) ;
let mut result = TargetField ::zero ( ) ;
let mut power = TargetField ::one ( ) ;
let mut result = TargetF ::zero ( ) ;
let mut power = TargetF ::one ( ) ;
for limb in limbs . iter ( ) . rev ( ) {
for limb in limbs . iter ( ) . rev ( ) {
let mut val = TargetField ::zero ( ) ;
let mut cur = TargetField ::one ( ) ;
let mut val = TargetF ::zero ( ) ;
let mut cur = TargetF ::one ( ) ;
for bit in limb . into_bigint ( ) . to_bits_be ( ) . iter ( ) . rev ( ) {
for bit in limb . into_bigint ( ) . to_bits_be ( ) . iter ( ) . rev ( ) {
if * bit {
if * bit {
@ -86,8 +81,8 @@ impl
result
result
}
}
/// Obtain the value of a nonnative field element
pub fn value ( & self ) -> R1CSResult < TargetField > {
/// Obtain the value of a emulated field element
pub fn value ( & self ) -> R1CSResult < TargetF > {
let mut limbs = Vec ::new ( ) ;
let mut limbs = Vec ::new ( ) ;
for limb in self . limbs . iter ( ) {
for limb in self . limbs . iter ( ) {
limbs . push ( limb . value ( ) ? ) ;
limbs . push ( limb . value ( ) ? ) ;
@ -96,8 +91,8 @@ impl
Ok ( Self ::limbs_to_value ( limbs , self . get_optimization_type ( ) ) )
Ok ( Self ::limbs_to_value ( limbs , self . get_optimization_type ( ) ) )
}
}
/// Obtain the nonnative field element of a constant value
pub fn constant ( cs : ConstraintSystemRef < BaseField > , value : TargetField ) -> R1CSResult < Self > {
/// Obtain the emulated field element of a constant value
pub fn constant ( cs : ConstraintSystemRef < BaseF > , value : TargetF ) -> R1CSResult < Self > {
let optimization_type = match cs . optimization_goal ( ) {
let optimization_type = match cs . optimization_goal ( ) {
OptimizationGoal ::None = > OptimizationType ::Constraints ,
OptimizationGoal ::None = > OptimizationType ::Constraints ,
OptimizationGoal ::Constraints = > OptimizationType ::Constraints ,
OptimizationGoal ::Constraints = > OptimizationType ::Constraints ,
@ -109,32 +104,29 @@ impl
let mut limbs = Vec ::new ( ) ;
let mut limbs = Vec ::new ( ) ;
for limb_value in limbs_value . iter ( ) {
for limb_value in limbs_value . iter ( ) {
limbs . push ( FpVar ::< BaseField > ::new_constant (
ns ! ( cs , "limb" ) ,
limb_value ,
) ? ) ;
limbs . push ( FpVar ::< BaseF > ::new_constant ( ns ! ( cs , "limb" ) , limb_value ) ? ) ;
}
}
Ok ( Self {
Ok ( Self {
cs ,
cs ,
limbs ,
limbs ,
num_of_additions_over_normal_form : BaseField ::zero ( ) ,
num_of_additions_over_normal_form : BaseF ::zero ( ) ,
is_in_the_normal_form : true ,
is_in_the_normal_form : true ,
target_phantom : PhantomData ,
target_phantom : PhantomData ,
} )
} )
}
}
/// Obtain the nonnative field element of one
pub fn one ( cs : ConstraintSystemRef < BaseField > ) -> R1CSResult < Self > {
Self ::constant ( cs , TargetField ::one ( ) )
/// Obtain the emulated field element of one
pub fn one ( cs : ConstraintSystemRef < BaseF > ) -> R1CSResult < Self > {
Self ::constant ( cs , TargetF ::one ( ) )
}
}
/// Obtain the nonnative field element of zero
pub fn zero ( cs : ConstraintSystemRef < BaseField > ) -> R1CSResult < Self > {
Self ::constant ( cs , TargetField ::zero ( ) )
/// Obtain the emulated field element of zero
pub fn zero ( cs : ConstraintSystemRef < BaseF > ) -> R1CSResult < Self > {
Self ::constant ( cs , TargetF ::zero ( ) )
}
}
/// Add a nonnative field element
/// Add a emulated field element
#[ tracing::instrument(target = " r1cs " ) ]
#[ tracing::instrument(target = " r1cs " ) ]
pub fn add ( & self , other : & Self ) -> R1CSResult < Self > {
pub fn add ( & self , other : & Self ) -> R1CSResult < Self > {
assert_eq ! ( self . get_optimization_type ( ) , other . get_optimization_type ( ) ) ;
assert_eq ! ( self . get_optimization_type ( ) , other . get_optimization_type ( ) ) ;
@ -150,18 +142,18 @@ impl
num_of_additions_over_normal_form : self
num_of_additions_over_normal_form : self
. num_of_additions_over_normal_form
. num_of_additions_over_normal_form
. add ( & other . num_of_additions_over_normal_form )
. add ( & other . num_of_additions_over_normal_form )
. add ( & BaseField ::one ( ) ) ,
. add ( & BaseF ::one ( ) ) ,
is_in_the_normal_form : false ,
is_in_the_normal_form : false ,
target_phantom : PhantomData ,
target_phantom : PhantomData ,
} ;
} ;
Reducer ::< TargetField , BaseField > ::post_add_reduce ( & mut res ) ? ;
Reducer ::< TargetF , BaseF > ::post_add_reduce ( & mut res ) ? ;
Ok ( res )
Ok ( res )
}
}
/// Add a constant
/// Add a constant
#[ tracing::instrument(target = " r1cs " ) ]
#[ tracing::instrument(target = " r1cs " ) ]
pub fn add_constant ( & self , other : & TargetField ) -> R1CSResult < Self > {
pub fn add_constant ( & self , other : & TargetF ) -> R1CSResult < Self > {
let other_limbs = Self ::get_limbs_representations ( other , self . get_optimization_type ( ) ) ? ;
let other_limbs = Self ::get_limbs_representations ( other , self . get_optimization_type ( ) ) ? ;
let mut limbs = Vec ::new ( ) ;
let mut limbs = Vec ::new ( ) ;
@ -174,50 +166,50 @@ impl
limbs ,
limbs ,
num_of_additions_over_normal_form : self
num_of_additions_over_normal_form : self
. num_of_additions_over_normal_form
. num_of_additions_over_normal_form
. add ( & BaseField ::one ( ) ) ,
. add ( & BaseF ::one ( ) ) ,
is_in_the_normal_form : false ,
is_in_the_normal_form : false ,
target_phantom : PhantomData ,
target_phantom : PhantomData ,
} ;
} ;
Reducer ::< TargetField , BaseField > ::post_add_reduce ( & mut res ) ? ;
Reducer ::< TargetF , BaseF > ::post_add_reduce ( & mut res ) ? ;
Ok ( res )
Ok ( res )
}
}
/// Subtract a nonnative field element, without the final reduction step
/// Subtract a emulated field element, without the final reduction step
#[ tracing::instrument(target = " r1cs " ) ]
#[ tracing::instrument(target = " r1cs " ) ]
pub fn sub_without_reduce ( & self , other : & Self ) -> R1CSResult < Self > {
pub fn sub_without_reduce ( & self , other : & Self ) -> R1CSResult < Self > {
assert_eq ! ( self . get_optimization_type ( ) , other . get_optimization_type ( ) ) ;
assert_eq ! ( self . get_optimization_type ( ) , other . get_optimization_type ( ) ) ;
let params = get_params (
let params = get_params (
TargetField ::MODULUS_BIT_SIZE as usize ,
BaseField ::MODULUS_BIT_SIZE as usize ,
TargetF ::MODULUS_BIT_SIZE as usize ,
BaseF ::MODULUS_BIT_SIZE as usize ,
self . get_optimization_type ( ) ,
self . get_optimization_type ( ) ,
) ;
) ;
// Step 1: reduce the `other` if needed
// Step 1: reduce the `other` if needed
let mut surfeit = overhead ! ( other . num_of_additions_over_normal_form + BaseField ::one ( ) ) + 1 ;
let mut surfeit = overhead ! ( other . num_of_additions_over_normal_form + BaseF ::one ( ) ) + 1 ;
let mut other = other . clone ( ) ;
let mut other = other . clone ( ) ;
if ( surfeit + params . bits_per_limb > BaseField ::MODULUS_BIT_SIZE as usize - 1 )
if ( surfeit + params . bits_per_limb > BaseF ::MODULUS_BIT_SIZE as usize - 1 )
| | ( surfeit
| | ( surfeit
+ ( TargetField ::MODULUS_BIT_SIZE as usize
+ ( TargetF ::MODULUS_BIT_SIZE as usize
- params . bits_per_limb * ( params . num_limbs - 1 ) )
- params . bits_per_limb * ( params . num_limbs - 1 ) )
> BaseField ::MODULUS_BIT_SIZE as usize - 1 )
> BaseF ::MODULUS_BIT_SIZE as usize - 1 )
{
{
Reducer ::reduce ( & mut other ) ? ;
Reducer ::reduce ( & mut other ) ? ;
surfeit = overhead ! ( other . num_of_additions_over_normal_form + BaseField ::ONE ) + 1 ;
surfeit = overhead ! ( other . num_of_additions_over_normal_form + BaseF ::ONE ) + 1 ;
}
}
// Step 2: construct the padding
// Step 2: construct the padding
let mut pad_non_top_limb = BaseField ::ONE . into_bigint ( ) ;
let mut pad_non_top_limb = BaseF ::ONE . into_bigint ( ) ;
let mut pad_top_limb = pad_non_top_limb ;
let mut pad_top_limb = pad_non_top_limb ;
pad_non_top_limb < < = ( surfeit + params . bits_per_limb ) as u32 ;
pad_non_top_limb < < = ( surfeit + params . bits_per_limb ) as u32 ;
let pad_non_top_limb = BaseField ::from_bigint ( pad_non_top_limb ) . unwrap ( ) ;
let pad_non_top_limb = BaseF ::from_bigint ( pad_non_top_limb ) . unwrap ( ) ;
pad_top_limb < < = ( surfeit + TargetField ::MODULUS_BIT_SIZE as usize
pad_top_limb < < = ( surfeit + TargetF ::MODULUS_BIT_SIZE as usize
- params . bits_per_limb * ( params . num_limbs - 1 ) ) as u32 ;
- params . bits_per_limb * ( params . num_limbs - 1 ) ) as u32 ;
let pad_top_limb = BaseField ::from_bigint ( pad_top_limb ) . unwrap ( ) ;
let pad_top_limb = BaseF ::from_bigint ( pad_top_limb ) . unwrap ( ) ;
let mut pad_limbs = Vec ::with_capacity ( self . limbs . len ( ) ) ;
let mut pad_limbs = Vec ::with_capacity ( self . limbs . len ( ) ) ;
pad_limbs . push ( pad_top_limb ) ;
pad_limbs . push ( pad_top_limb ) ;
@ -246,12 +238,12 @@ impl
}
}
}
}
let result = AllocatedNonNativeField Var ::< TargetField , BaseField > {
let result = AllocatedEmulatedFp Var ::< TargetF , BaseF > {
cs : self . cs ( ) ,
cs : self . cs ( ) ,
limbs ,
limbs ,
num_of_additions_over_normal_form : self . num_of_additions_over_normal_form
num_of_additions_over_normal_form : self . num_of_additions_over_normal_form
+ ( other . num_of_additions_over_normal_form + BaseField ::one ( ) )
+ ( other . num_of_additions_over_normal_form + BaseField ::one ( ) ) ,
+ ( other . num_of_additions_over_normal_form + BaseF ::one ( ) )
+ ( other . num_of_additions_over_normal_form + BaseF ::one ( ) ) ,
is_in_the_normal_form : false ,
is_in_the_normal_form : false ,
target_phantom : PhantomData ,
target_phantom : PhantomData ,
} ;
} ;
@ -259,23 +251,23 @@ impl
Ok ( result )
Ok ( result )
}
}
/// Subtract a nonnative field element
/// Subtract a emulated field element
#[ tracing::instrument(target = " r1cs " ) ]
#[ tracing::instrument(target = " r1cs " ) ]
pub fn sub ( & self , other : & Self ) -> R1CSResult < Self > {
pub fn sub ( & self , other : & Self ) -> R1CSResult < Self > {
assert_eq ! ( self . get_optimization_type ( ) , other . get_optimization_type ( ) ) ;
assert_eq ! ( self . get_optimization_type ( ) , other . get_optimization_type ( ) ) ;
let mut result = self . sub_without_reduce ( other ) ? ;
let mut result = self . sub_without_reduce ( other ) ? ;
Reducer ::< TargetField , BaseField > ::post_add_reduce ( & mut result ) ? ;
Reducer ::< TargetF , BaseF > ::post_add_reduce ( & mut result ) ? ;
Ok ( result )
Ok ( result )
}
}
/// Subtract a constant
/// Subtract a constant
#[ tracing::instrument(target = " r1cs " ) ]
#[ tracing::instrument(target = " r1cs " ) ]
pub fn sub_constant ( & self , other : & TargetField ) -> R1CSResult < Self > {
pub fn sub_constant ( & self , other : & TargetF ) -> R1CSResult < Self > {
self . sub ( & Self ::constant ( self . cs ( ) , * other ) ? )
self . sub ( & Self ::constant ( self . cs ( ) , * other ) ? )
}
}
/// Multiply a nonnative field element
/// Multiply a emulated field element
#[ tracing::instrument(target = " r1cs " ) ]
#[ tracing::instrument(target = " r1cs " ) ]
pub fn mul ( & self , other : & Self ) -> R1CSResult < Self > {
pub fn mul ( & self , other : & Self ) -> R1CSResult < Self > {
assert_eq ! ( self . get_optimization_type ( ) , other . get_optimization_type ( ) ) ;
assert_eq ! ( self . get_optimization_type ( ) , other . get_optimization_type ( ) ) ;
@ -284,21 +276,21 @@ impl
}
}
/// Multiply a constant
/// Multiply a constant
pub fn mul_constant ( & self , other : & TargetField ) -> R1CSResult < Self > {
pub fn mul_constant ( & self , other : & TargetF ) -> R1CSResult < Self > {
self . mul ( & Self ::constant ( self . cs ( ) , * other ) ? )
self . mul ( & Self ::constant ( self . cs ( ) , * other ) ? )
}
}
/// Compute the negate of a nonnative field element
/// Compute the negate of a emulated field element
#[ tracing::instrument(target = " r1cs " ) ]
#[ tracing::instrument(target = " r1cs " ) ]
pub fn negate ( & self ) -> R1CSResult < Self > {
pub fn negate ( & self ) -> R1CSResult < Self > {
Self ::zero ( self . cs ( ) ) ? . sub ( self )
Self ::zero ( self . cs ( ) ) ? . sub ( self )
}
}
/// Compute the inverse of a nonnative field element
/// Compute the inverse of a emulated field element
#[ tracing::instrument(target = " r1cs " ) ]
#[ tracing::instrument(target = " r1cs " ) ]
pub fn inverse ( & self ) -> R1CSResult < Self > {
pub fn inverse ( & self ) -> R1CSResult < Self > {
let inverse = Self ::new_witness ( self . cs ( ) , | | {
let inverse = Self ::new_witness ( self . cs ( ) , | | {
Ok ( self . value ( ) ? . inverse ( ) . unwrap_or_else ( TargetField ::zero ) )
Ok ( self . value ( ) ? . inverse ( ) . unwrap_or_else ( TargetF ::zero ) )
} ) ? ;
} ) ? ;
let actual_result = self . clone ( ) . mul ( & inverse ) ? ;
let actual_result = self . clone ( ) . mul ( & inverse ) ? ;
@ -306,36 +298,36 @@ impl
Ok ( inverse )
Ok ( inverse )
}
}
/// Convert a `TargetField ` element into limbs (not constraints)
/// Convert a `TargetF` element into limbs (not constraints)
/// This is an internal function that would be reused by a number of other
/// This is an internal function that would be reused by a number of other
/// functions
/// functions
pub fn get_limbs_representations (
pub fn get_limbs_representations (
elem : & TargetField ,
elem : & TargetF ,
optimization_type : OptimizationType ,
optimization_type : OptimizationType ,
) -> R1CSResult < Vec < BaseField > > {
) -> R1CSResult < Vec < BaseF > > {
Self ::get_limbs_representations_from_big_integer ( & elem . into_bigint ( ) , optimization_type )
Self ::get_limbs_representations_from_big_integer ( & elem . into_bigint ( ) , optimization_type )
}
}
/// Obtain the limbs directly from a big int
/// Obtain the limbs directly from a big int
pub fn get_limbs_representations_from_big_integer (
pub fn get_limbs_representations_from_big_integer (
elem : & < TargetField as PrimeField > ::BigInt ,
elem : & < TargetF as PrimeField > ::BigInt ,
optimization_type : OptimizationType ,
optimization_type : OptimizationType ,
) -> R1CSResult < Vec < BaseField > > {
) -> R1CSResult < Vec < BaseF > > {
let params = get_params (
let params = get_params (
TargetField ::MODULUS_BIT_SIZE as usize ,
BaseField ::MODULUS_BIT_SIZE as usize ,
TargetF ::MODULUS_BIT_SIZE as usize ,
BaseF ::MODULUS_BIT_SIZE as usize ,
optimization_type ,
optimization_type ,
) ;
) ;
// push the lower limbs first
// push the lower limbs first
let mut limbs : Vec < BaseField > = Vec ::new ( ) ;
let mut limbs : Vec < BaseF > = Vec ::new ( ) ;
let mut cur = * elem ;
let mut cur = * elem ;
for _ in 0 . . params . num_limbs {
for _ in 0 . . params . num_limbs {
let cur_bits = cur . to_bits_be ( ) ; // `to_bits` is big endian
let cur_bits = cur . to_bits_be ( ) ; // `to_bits` is big endian
let cur_mod_r = < BaseField as PrimeField > ::BigInt ::from_bits_be (
let cur_mod_r = < BaseF as PrimeField > ::BigInt ::from_bits_be (
& cur_bits [ cur_bits . len ( ) - params . bits_per_limb . . ] ,
& cur_bits [ cur_bits . len ( ) - params . bits_per_limb . . ] ,
) ; // therefore, the lowest `bits_per_non_top_limb` bits is what we want.
) ; // therefore, the lowest `bits_per_non_top_limb` bits is what we want.
limbs . push ( BaseField ::from_bigint ( cur_mod_r ) . unwrap ( ) ) ;
limbs . push ( BaseF ::from_bigint ( cur_mod_r ) . unwrap ( ) ) ;
cur > > = params . bits_per_limb as u32 ;
cur > > = params . bits_per_limb as u32 ;
}
}
@ -348,28 +340,28 @@ impl
/// for advanced use, multiply and output the intermediate representations
/// for advanced use, multiply and output the intermediate representations
/// (without reduction) This intermediate representations can be added
/// (without reduction) This intermediate representations can be added
/// with each other, and they can later be reduced back to the
/// with each other, and they can later be reduced back to the
/// `NonNativeField Var`.
/// `EmulatedFp Var`.
#[ tracing::instrument(target = " r1cs " ) ]
#[ tracing::instrument(target = " r1cs " ) ]
pub fn mul_without_reduce (
pub fn mul_without_reduce (
& self ,
& self ,
other : & Self ,
other : & Self ,
) -> R1CSResult < AllocatedNonNativeField MulResultVar < TargetField , BaseField > > {
) -> R1CSResult < AllocatedMulResultVar < TargetF , BaseF > > {
assert_eq ! ( self . get_optimization_type ( ) , other . get_optimization_type ( ) ) ;
assert_eq ! ( self . get_optimization_type ( ) , other . get_optimization_type ( ) ) ;
let params = get_params (
let params = get_params (
TargetField ::MODULUS_BIT_SIZE as usize ,
BaseField ::MODULUS_BIT_SIZE as usize ,
TargetF ::MODULUS_BIT_SIZE as usize ,
BaseF ::MODULUS_BIT_SIZE as usize ,
self . get_optimization_type ( ) ,
self . get_optimization_type ( ) ,
) ;
) ;
// Step 1: reduce `self` and `other` if neceessary
// Step 1: reduce `self` and `other` if neceessary
let mut self_reduced = self . clone ( ) ;
let mut self_reduced = self . clone ( ) ;
let mut other_reduced = other . clone ( ) ;
let mut other_reduced = other . clone ( ) ;
Reducer ::< TargetField , BaseField > ::pre_mul_reduce ( & mut self_reduced , & mut other_reduced ) ? ;
Reducer ::< TargetF , BaseF > ::pre_mul_reduce ( & mut self_reduced , & mut other_reduced ) ? ;
let mut prod_limbs = Vec ::new ( ) ;
let mut prod_limbs = Vec ::new ( ) ;
if self . get_optimization_type ( ) = = OptimizationType ::Weight {
if self . get_optimization_type ( ) = = OptimizationType ::Weight {
let zero = FpVar ::< BaseField > ::zero ( ) ;
let zero = FpVar ::< BaseF > ::zero ( ) ;
for _ in 0 . . 2 * params . num_limbs - 1 {
for _ in 0 . . 2 * params . num_limbs - 1 {
prod_limbs . push ( zero . clone ( ) ) ;
prod_limbs . push ( zero . clone ( ) ) ;
@ -386,7 +378,7 @@ impl
for z_index in 0 . . 2 * params . num_limbs - 1 {
for z_index in 0 . . 2 * params . num_limbs - 1 {
prod_limbs . push ( FpVar ::new_witness ( ns ! ( cs , "limb product" ) , | | {
prod_limbs . push ( FpVar ::new_witness ( ns ! ( cs , "limb product" ) , | | {
let mut z_i = BaseField ::zero ( ) ;
let mut z_i = BaseF ::zero ( ) ;
for i in 0 . . = min ( params . num_limbs - 1 , z_index ) {
for i in 0 . . = min ( params . num_limbs - 1 , z_index ) {
let j = z_index - i ;
let j = z_index - i ;
if j < params . num_limbs {
if j < params . num_limbs {
@ -402,7 +394,7 @@ impl
for c in 0 . . ( 2 * params . num_limbs - 1 ) {
for c in 0 . . ( 2 * params . num_limbs - 1 ) {
let c_pows : Vec < _ > = ( 0 . . ( 2 * params . num_limbs - 1 ) )
let c_pows : Vec < _ > = ( 0 . . ( 2 * params . num_limbs - 1 ) )
. map ( | i | BaseField ::from ( ( c + 1 ) as u128 ) . pow ( & vec ! [ i as u64 ] ) )
. map ( | i | BaseF ::from ( ( c + 1 ) as u128 ) . pow ( & vec ! [ i as u64 ] ) )
. collect ( ) ;
. collect ( ) ;
let x = self_reduced
let x = self_reduced
@ -429,12 +421,12 @@ impl
}
}
}
}
Ok ( AllocatedNonNativeField MulResultVar {
Ok ( AllocatedMulResultVar {
cs : self . cs ( ) ,
cs : self . cs ( ) ,
limbs : prod_limbs ,
limbs : prod_limbs ,
prod_of_num_of_additions : ( self_reduced . num_of_additions_over_normal_form
prod_of_num_of_additions : ( self_reduced . num_of_additions_over_normal_form
+ BaseField ::one ( ) )
* ( other_reduced . num_of_additions_over_normal_form + BaseField ::one ( ) ) ,
+ BaseF ::one ( ) )
* ( other_reduced . num_of_additions_over_normal_form + BaseF ::one ( ) ) ,
target_phantom : PhantomData ,
target_phantom : PhantomData ,
} )
} )
}
}
@ -446,32 +438,32 @@ impl
pub ( crate ) fn conditional_enforce_equal (
pub ( crate ) fn conditional_enforce_equal (
& self ,
& self ,
other : & Self ,
other : & Self ,
should_enforce : & Boolean < BaseField > ,
should_enforce : & Boolean < BaseF > ,
) -> R1CSResult < ( ) > {
) -> R1CSResult < ( ) > {
assert_eq ! ( self . get_optimization_type ( ) , other . get_optimization_type ( ) ) ;
assert_eq ! ( self . get_optimization_type ( ) , other . get_optimization_type ( ) ) ;
let params = get_params (
let params = get_params (
TargetField ::MODULUS_BIT_SIZE as usize ,
BaseField ::MODULUS_BIT_SIZE as usize ,
TargetF ::MODULUS_BIT_SIZE as usize ,
BaseF ::MODULUS_BIT_SIZE as usize ,
self . get_optimization_type ( ) ,
self . get_optimization_type ( ) ,
) ;
) ;
// Get p
// Get p
let p_representations =
let p_representations =
AllocatedNonNativeField Var ::< TargetField , BaseField > ::get_limbs_representations_from_big_integer (
& < TargetField as PrimeField > ::MODULUS ,
self . get_optimization_type ( )
AllocatedEmulatedFp Var ::< TargetF , BaseF > ::get_limbs_representations_from_big_integer (
& < TargetF as PrimeField > ::MODULUS ,
self . get_optimization_type ( ) ,
) ? ;
) ? ;
let p_bigint = limbs_to_bigint ( params . bits_per_limb , & p_representations ) ;
let p_bigint = limbs_to_bigint ( params . bits_per_limb , & p_representations ) ;
let mut p_gadget_limbs = Vec ::new ( ) ;
let mut p_gadget_limbs = Vec ::new ( ) ;
for limb in p_representations . iter ( ) {
for limb in p_representations . iter ( ) {
p_gadget_limbs . push ( FpVar ::< BaseField > ::Constant ( * limb ) ) ;
p_gadget_limbs . push ( FpVar ::< BaseF > ::Constant ( * limb ) ) ;
}
}
let p_gadget = AllocatedNonNativeField Var ::< TargetField , BaseField > {
let p_gadget = AllocatedEmulatedFp Var ::< TargetF , BaseF > {
cs : self . cs ( ) ,
cs : self . cs ( ) ,
limbs : p_gadget_limbs ,
limbs : p_gadget_limbs ,
num_of_additions_over_normal_form : BaseField ::one ( ) ,
num_of_additions_over_normal_form : BaseF ::one ( ) ,
is_in_the_normal_form : false ,
is_in_the_normal_form : false ,
target_phantom : PhantomData ,
target_phantom : PhantomData ,
} ;
} ;
@ -482,19 +474,19 @@ impl
delta = should_enforce . select ( & delta , & Self ::zero ( cs . clone ( ) ) ? ) ? ;
delta = should_enforce . select ( & delta , & Self ::zero ( cs . clone ( ) ) ? ) ? ;
// Allocate k = delta / p
// Allocate k = delta / p
let k_gadget = FpVar ::< BaseField > ::new_witness ( ns ! ( cs , "k" ) , | | {
let mut delta_limbs_values = Vec ::< BaseField > ::new ( ) ;
let k_gadget = FpVar ::< BaseF > ::new_witness ( ns ! ( cs , "k" ) , | | {
let mut delta_limbs_values = Vec ::< BaseF > ::new ( ) ;
for limb in delta . limbs . iter ( ) {
for limb in delta . limbs . iter ( ) {
delta_limbs_values . push ( limb . value ( ) ? ) ;
delta_limbs_values . push ( limb . value ( ) ? ) ;
}
}
let delta_bigint = limbs_to_bigint ( params . bits_per_limb , & delta_limbs_values ) ;
let delta_bigint = limbs_to_bigint ( params . bits_per_limb , & delta_limbs_values ) ;
Ok ( bigint_to_basefield ::< BaseField > ( & ( delta_bigint / p_bigint ) ) )
Ok ( bigint_to_basefield ::< BaseF > ( & ( delta_bigint / p_bigint ) ) )
} ) ? ;
} ) ? ;
let surfeit = overhead ! ( delta . num_of_additions_over_normal_form + BaseField ::one ( ) ) + 1 ;
Reducer ::< TargetField , BaseField > ::limb_to_bits ( & k_gadget , surfeit ) ? ;
let surfeit = overhead ! ( delta . num_of_additions_over_normal_form + BaseF ::one ( ) ) + 1 ;
Reducer ::< TargetF , BaseF > ::limb_to_bits ( & k_gadget , surfeit ) ? ;
// Compute k * p
// Compute k * p
let mut kp_gadget_limbs = Vec ::new ( ) ;
let mut kp_gadget_limbs = Vec ::new ( ) ;
@ -503,7 +495,7 @@ impl
}
}
// Enforce delta = kp
// Enforce delta = kp
Reducer ::< TargetField , BaseField > ::group_and_check_equality (
Reducer ::< TargetF , BaseF > ::group_and_check_equality (
surfeit ,
surfeit ,
params . bits_per_limb ,
params . bits_per_limb ,
params . bits_per_limb ,
params . bits_per_limb ,
@ -518,7 +510,7 @@ impl
pub ( crate ) fn conditional_enforce_not_equal (
pub ( crate ) fn conditional_enforce_not_equal (
& self ,
& self ,
other : & Self ,
other : & Self ,
should_enforce : & Boolean < BaseField > ,
should_enforce : & Boolean < BaseF > ,
) -> R1CSResult < ( ) > {
) -> R1CSResult < ( ) > {
assert_eq ! ( self . get_optimization_type ( ) , other . get_optimization_type ( ) ) ;
assert_eq ! ( self . get_optimization_type ( ) , other . get_optimization_type ( ) ) ;
@ -541,8 +533,8 @@ impl
/// Allocates a new variable, but does not check that the allocation's limbs
/// Allocates a new variable, but does not check that the allocation's limbs
/// are in-range.
/// are in-range.
fn new_variable_unchecked < T : Borrow < TargetField > > (
cs : impl Into < Namespace < BaseField > > ,
fn new_variable_unchecked < T : Borrow < TargetF > > (
cs : impl Into < Namespace < BaseF > > ,
f : impl FnOnce ( ) -> Result < T , SynthesisError > ,
f : impl FnOnce ( ) -> Result < T , SynthesisError > ,
mode : AllocationMode ,
mode : AllocationMode ,
) -> R1CSResult < Self > {
) -> R1CSResult < Self > {
@ -555,7 +547,7 @@ impl
OptimizationGoal ::Weight = > OptimizationType ::Weight ,
OptimizationGoal ::Weight = > OptimizationType ::Weight ,
} ;
} ;
let zero = TargetField ::zero ( ) ;
let zero = TargetF ::zero ( ) ;
let elem = match f ( ) {
let elem = match f ( ) {
Ok ( t ) = > * ( t . borrow ( ) ) ,
Ok ( t ) = > * ( t . borrow ( ) ) ,
@ -565,7 +557,7 @@ impl
let mut limbs = Vec ::new ( ) ;
let mut limbs = Vec ::new ( ) ;
for limb in elem_representations . iter ( ) {
for limb in elem_representations . iter ( ) {
limbs . push ( FpVar ::< BaseField > ::new_variable (
limbs . push ( FpVar ::< BaseF > ::new_variable (
ark_relations ::ns ! ( cs , "alloc" ) ,
ark_relations ::ns ! ( cs , "alloc" ) ,
| | Ok ( limb ) ,
| | Ok ( limb ) ,
mode ,
mode ,
@ -573,9 +565,9 @@ impl
}
}
let num_of_additions_over_normal_form = if mode ! = AllocationMode ::Witness {
let num_of_additions_over_normal_form = if mode ! = AllocationMode ::Witness {
BaseField ::zero ( )
BaseF ::zero ( )
} else {
} else {
BaseField ::one ( )
BaseF ::one ( )
} ;
} ;
Ok ( Self {
Ok ( Self {
@ -591,10 +583,7 @@ impl
/// the whole number is less than the modulus.
/// the whole number is less than the modulus.
///
///
/// Returns the bits of the element, in little-endian form
/// Returns the bits of the element, in little-endian form
fn enforce_in_range (
& self ,
cs : impl Into < Namespace < BaseField > > ,
) -> R1CSResult < Vec < Boolean < BaseField > > > {
fn enforce_in_range ( & self , cs : impl Into < Namespace < BaseF > > ) -> R1CSResult < Vec < Boolean < BaseF > > > {
let ns = cs . into ( ) ;
let ns = cs . into ( ) ;
let cs = ns . cs ( ) ;
let cs = ns . cs ( ) ;
let optimization_type = match cs . optimization_goal ( ) {
let optimization_type = match cs . optimization_goal ( ) {
@ -603,24 +592,23 @@ impl
OptimizationGoal ::Weight = > OptimizationType ::Weight ,
OptimizationGoal ::Weight = > OptimizationType ::Weight ,
} ;
} ;
let params = get_params (
let params = get_params (
TargetField ::MODULUS_BIT_SIZE as usize ,
BaseField ::MODULUS_BIT_SIZE as usize ,
TargetF ::MODULUS_BIT_SIZE as usize ,
BaseF ::MODULUS_BIT_SIZE as usize ,
optimization_type ,
optimization_type ,
) ;
) ;
let mut bits = Vec ::new ( ) ;
let mut bits = Vec ::new ( ) ;
for limb in self . limbs . iter ( ) . rev ( ) . take ( params . num_limbs - 1 ) {
for limb in self . limbs . iter ( ) . rev ( ) . take ( params . num_limbs - 1 ) {
bits . extend (
bits . extend (
Reducer ::< TargetField , BaseField > ::limb_to_bits ( limb , params . bits_per_limb ) ?
Reducer ::< TargetF , BaseF > ::limb_to_bits ( limb , params . bits_per_limb ) ?
. into_iter ( )
. into_iter ( )
. rev ( ) ,
. rev ( ) ,
) ;
) ;
}
}
bits . extend (
bits . extend (
Reducer ::< TargetField , BaseField > ::limb_to_bits (
Reducer ::< TargetF , BaseF > ::limb_to_bits (
& self . limbs [ 0 ] ,
& self . limbs [ 0 ] ,
TargetField ::MODULUS_BIT_SIZE as usize
- ( params . num_limbs - 1 ) * params . bits_per_limb ,
TargetF ::MODULUS_BIT_SIZE as usize - ( params . num_limbs - 1 ) * params . bits_per_limb ,
) ?
) ?
. into_iter ( )
. into_iter ( )
. rev ( ) ,
. rev ( ) ,
@ -633,10 +621,10 @@ impl
/// and returns the bits of its binary representation.
/// and returns the bits of its binary representation.
/// The bits are in little-endian (i.e., the bit at index 0 is the LSB) and the
/// The bits are in little-endian (i.e., the bit at index 0 is the LSB) and the
/// bit-vector is empty in non-witness allocation modes.
/// bit-vector is empty in non-witness allocation modes.
pub fn new_witness_with_le_bits < T : Borrow < TargetField > > (
cs : impl Into < Namespace < BaseField > > ,
pub fn new_witness_with_le_bits < T : Borrow < TargetF > > (
cs : impl Into < Namespace < BaseF > > ,
f : impl FnOnce ( ) -> Result < T , SynthesisError > ,
f : impl FnOnce ( ) -> Result < T , SynthesisError > ,
) -> R1CSResult < ( Self , Vec < Boolean < BaseField > > ) > {
) -> R1CSResult < ( Self , Vec < Boolean < BaseF > > ) > {
let ns = cs . into ( ) ;
let ns = cs . into ( ) ;
let cs = ns . cs ( ) ;
let cs = ns . cs ( ) ;
let this = Self ::new_variable_unchecked ( ns ! ( cs , "alloc" ) , f , AllocationMode ::Witness ) ? ;
let this = Self ::new_variable_unchecked ( ns ! ( cs , "alloc" ) , f , AllocationMode ::Witness ) ? ;
@ -645,36 +633,36 @@ impl
}
}
}
}
impl < TargetField : PrimeField , BaseField : PrimeField > ToBitsGadget < BaseField >
for AllocatedNonNativeField Var < TargetField , BaseField >
impl < TargetF : PrimeField , BaseF : PrimeField > ToBitsGadget < BaseF >
for AllocatedEmulatedFp Var < TargetF , BaseF >
{
{
#[ tracing::instrument(target = " r1cs " ) ]
#[ tracing::instrument(target = " r1cs " ) ]
fn to_bits_le ( & self ) -> R1CSResult < Vec < Boolean < BaseField > > > {
fn to_bits_le ( & self ) -> R1CSResult < Vec < Boolean < BaseF > > > {
let params = get_params (
let params = get_params (
TargetField ::MODULUS_BIT_SIZE as usize ,
BaseField ::MODULUS_BIT_SIZE as usize ,
TargetF ::MODULUS_BIT_SIZE as usize ,
BaseF ::MODULUS_BIT_SIZE as usize ,
self . get_optimization_type ( ) ,
self . get_optimization_type ( ) ,
) ;
) ;
// Reduce to the normal form
// Reduce to the normal form
// Though, a malicious prover can make it slightly larger than p
// Though, a malicious prover can make it slightly larger than p
let mut self_normal = self . clone ( ) ;
let mut self_normal = self . clone ( ) ;
Reducer ::< TargetField , BaseField > ::pre_eq_reduce ( & mut self_normal ) ? ;
Reducer ::< TargetF , BaseF > ::pre_eq_reduce ( & mut self_normal ) ? ;
// Therefore, we convert it to bits and enforce that it is in the field
// Therefore, we convert it to bits and enforce that it is in the field
let mut bits = Vec ::< Boolean < BaseField > > ::new ( ) ;
let mut bits = Vec ::< Boolean < BaseF > > ::new ( ) ;
for limb in self_normal . limbs . iter ( ) {
for limb in self_normal . limbs . iter ( ) {
bits . extend_from_slice ( & Reducer ::< TargetField , BaseField > ::limb_to_bits (
bits . extend_from_slice ( & Reducer ::< TargetF , BaseF > ::limb_to_bits (
& limb ,
& limb ,
params . bits_per_limb ,
params . bits_per_limb ,
) ? ) ;
) ? ) ;
}
}
bits . reverse ( ) ;
bits . reverse ( ) ;
let mut b = TargetField ::characteristic ( ) . to_vec ( ) ;
let mut b = TargetF ::characteristic ( ) . to_vec ( ) ;
assert_eq ! ( b [ 0 ] % 2 , 1 ) ;
assert_eq ! ( b [ 0 ] % 2 , 1 ) ;
b [ 0 ] - = 1 ; // This works, because the LSB is one, so there's no borrows.
b [ 0 ] - = 1 ; // This works, because the LSB is one, so there's no borrows.
let run = Boolean ::< BaseField > ::enforce_smaller_or_equal_than_le ( & bits , b ) ? ;
let run = Boolean ::< BaseF > ::enforce_smaller_or_equal_than_le ( & bits , b ) ? ;
// We should always end in a "run" of zeros, because
// We should always end in a "run" of zeros, because
// the characteristic is an odd prime. So, this should
// the characteristic is an odd prime. So, this should
@ -685,14 +673,14 @@ impl ToBitsGadget
}
}
}
}
impl < TargetField : PrimeField , BaseField : PrimeField > ToBytesGadget < BaseField >
for AllocatedNonNativeField Var < TargetField , BaseField >
impl < TargetF : PrimeField , BaseF : PrimeField > ToBytesGadget < BaseF >
for AllocatedEmulatedFp Var < TargetF , BaseF >
{
{
#[ tracing::instrument(target = " r1cs " ) ]
#[ tracing::instrument(target = " r1cs " ) ]
fn to_bytes ( & self ) -> R1CSResult < Vec < UInt8 < BaseField > > > {
fn to_bytes ( & self ) -> R1CSResult < Vec < UInt8 < BaseF > > > {
let mut bits = self . to_bits_le ( ) ? ;
let mut bits = self . to_bits_le ( ) ? ;
let num_bits = TargetField ::BigInt ::NUM_LIMBS * 64 ;
let num_bits = TargetF ::BigInt ::NUM_LIMBS * 64 ;
assert ! ( bits . len ( ) < = num_bits ) ;
assert ! ( bits . len ( ) < = num_bits ) ;
bits . resize_with ( num_bits , | | Boolean ::constant ( false ) ) ;
bits . resize_with ( num_bits , | | Boolean ::constant ( false ) ) ;
@ -701,12 +689,12 @@ impl ToBytesGadget
}
}
}
}
impl < TargetField : PrimeField , BaseField : PrimeField > CondSelectGadget < BaseField >
for AllocatedNonNativeField Var < TargetField , BaseField >
impl < TargetF : PrimeField , BaseF : PrimeField > CondSelectGadget < BaseF >
for AllocatedEmulatedFp Var < TargetF , BaseF >
{
{
#[ tracing::instrument(target = " r1cs " ) ]
#[ tracing::instrument(target = " r1cs " ) ]
fn conditionally_select (
fn conditionally_select (
cond : & Boolean < BaseField > ,
cond : & Boolean < BaseF > ,
true_value : & Self ,
true_value : & Self ,
false_value : & Self ,
false_value : & Self ,
) -> R1CSResult < Self > {
) -> R1CSResult < Self > {
@ -718,7 +706,7 @@ impl CondSelectGadget
let mut limbs_sel = Vec ::with_capacity ( true_value . limbs . len ( ) ) ;
let mut limbs_sel = Vec ::with_capacity ( true_value . limbs . len ( ) ) ;
for ( x , y ) in true_value . limbs . iter ( ) . zip ( & false_value . limbs ) {
for ( x , y ) in true_value . limbs . iter ( ) . zip ( & false_value . limbs ) {
limbs_sel . push ( FpVar ::< BaseField > ::conditionally_select ( cond , x , y ) ? ) ;
limbs_sel . push ( FpVar ::< BaseF > ::conditionally_select ( cond , x , y ) ? ) ;
}
}
Ok ( Self {
Ok ( Self {
@ -735,14 +723,14 @@ impl CondSelectGadget
}
}
}
}
impl < TargetField : PrimeField , BaseField : PrimeField > TwoBitLookupGadget < BaseField >
for AllocatedNonNativeField Var < TargetField , BaseField >
impl < TargetF : PrimeField , BaseF : PrimeField > TwoBitLookupGadget < BaseF >
for AllocatedEmulatedFp Var < TargetF , BaseF >
{
{
type TableConstant = TargetField ;
type TableConstant = TargetF ;
#[ tracing::instrument(target = " r1cs " ) ]
#[ tracing::instrument(target = " r1cs " ) ]
fn two_bit_lookup (
fn two_bit_lookup (
bits : & [ Boolean < BaseField > ] ,
bits : & [ Boolean < BaseF > ] ,
constants : & [ Self ::TableConstant ] ,
constants : & [ Self ::TableConstant ] ,
) -> R1CSResult < Self > {
) -> R1CSResult < Self > {
debug_assert ! ( bits . len ( ) = = 2 ) ;
debug_assert ! ( bits . len ( ) = = 2 ) ;
@ -757,8 +745,8 @@ impl TwoBitLookupGadget
} ;
} ;
let params = get_params (
let params = get_params (
TargetField ::MODULUS_BIT_SIZE as usize ,
BaseField ::MODULUS_BIT_SIZE as usize ,
TargetF ::MODULUS_BIT_SIZE as usize ,
BaseF ::MODULUS_BIT_SIZE as usize ,
optimization_type ,
optimization_type ,
) ;
) ;
let mut limbs_constants = Vec ::new ( ) ;
let mut limbs_constants = Vec ::new ( ) ;
@ -768,7 +756,7 @@ impl TwoBitLookupGadget
for constant in constants . iter ( ) {
for constant in constants . iter ( ) {
let representations =
let representations =
AllocatedNonNativeField Var ::< TargetField , BaseField > ::get_limbs_representations (
AllocatedEmulatedFp Var ::< TargetF , BaseF > ::get_limbs_representations (
constant ,
constant ,
optimization_type ,
optimization_type ,
) ? ;
) ? ;
@ -780,28 +768,28 @@ impl TwoBitLookupGadget
let mut limbs = Vec ::new ( ) ;
let mut limbs = Vec ::new ( ) ;
for limbs_constant in limbs_constants . iter ( ) {
for limbs_constant in limbs_constants . iter ( ) {
limbs . push ( FpVar ::< BaseField > ::two_bit_lookup ( bits , limbs_constant ) ? ) ;
limbs . push ( FpVar ::< BaseF > ::two_bit_lookup ( bits , limbs_constant ) ? ) ;
}
}
Ok ( AllocatedNonNativeField Var ::< TargetField , BaseField > {
Ok ( AllocatedEmulatedFp Var ::< TargetF , BaseF > {
cs ,
cs ,
limbs ,
limbs ,
num_of_additions_over_normal_form : BaseField ::zero ( ) ,
num_of_additions_over_normal_form : BaseF ::zero ( ) ,
is_in_the_normal_form : true ,
is_in_the_normal_form : true ,
target_phantom : PhantomData ,
target_phantom : PhantomData ,
} )
} )
}
}
}
}
impl < TargetField : PrimeField , BaseField : PrimeField > ThreeBitCondNegLookupGadget < BaseField >
for AllocatedNonNativeField Var < TargetField , BaseField >
impl < TargetF : PrimeField , BaseF : PrimeField > ThreeBitCondNegLookupGadget < BaseF >
for AllocatedEmulatedFp Var < TargetF , BaseF >
{
{
type TableConstant = TargetField ;
type TableConstant = TargetF ;
#[ tracing::instrument(target = " r1cs " ) ]
#[ tracing::instrument(target = " r1cs " ) ]
fn three_bit_cond_neg_lookup (
fn three_bit_cond_neg_lookup (
bits : & [ Boolean < BaseField > ] ,
b0b1 : & Boolean < BaseField > ,
bits : & [ Boolean < BaseF > ] ,
b0b1 : & Boolean < BaseF > ,
constants : & [ Self ::TableConstant ] ,
constants : & [ Self ::TableConstant ] ,
) -> R1CSResult < Self > {
) -> R1CSResult < Self > {
debug_assert ! ( bits . len ( ) = = 3 ) ;
debug_assert ! ( bits . len ( ) = = 3 ) ;
@ -816,8 +804,8 @@ impl ThreeBitCondNegLookupGadget
} ;
} ;
let params = get_params (
let params = get_params (
TargetField ::MODULUS_BIT_SIZE as usize ,
BaseField ::MODULUS_BIT_SIZE as usize ,
TargetF ::MODULUS_BIT_SIZE as usize ,
BaseF ::MODULUS_BIT_SIZE as usize ,
optimization_type ,
optimization_type ,
) ;
) ;
@ -828,7 +816,7 @@ impl ThreeBitCondNegLookupGadget
for constant in constants . iter ( ) {
for constant in constants . iter ( ) {
let representations =
let representations =
AllocatedNonNativeField Var ::< TargetField , BaseField > ::get_limbs_representations (
AllocatedEmulatedFp Var ::< TargetF , BaseF > ::get_limbs_representations (
constant ,
constant ,
optimization_type ,
optimization_type ,
) ? ;
) ? ;
@ -840,28 +828,28 @@ impl ThreeBitCondNegLookupGadget
let mut limbs = Vec ::new ( ) ;
let mut limbs = Vec ::new ( ) ;
for limbs_constant in limbs_constants . iter ( ) {
for limbs_constant in limbs_constants . iter ( ) {
limbs . push ( FpVar ::< BaseField > ::three_bit_cond_neg_lookup (
limbs . push ( FpVar ::< BaseF > ::three_bit_cond_neg_lookup (
bits ,
bits ,
b0b1 ,
b0b1 ,
limbs_constant ,
limbs_constant ,
) ? ) ;
) ? ) ;
}
}
Ok ( AllocatedNonNativeField Var ::< TargetField , BaseField > {
Ok ( AllocatedEmulatedFp Var ::< TargetF , BaseF > {
cs ,
cs ,
limbs ,
limbs ,
num_of_additions_over_normal_form : BaseField ::zero ( ) ,
num_of_additions_over_normal_form : BaseF ::zero ( ) ,
is_in_the_normal_form : true ,
is_in_the_normal_form : true ,
target_phantom : PhantomData ,
target_phantom : PhantomData ,
} )
} )
}
}
}
}
impl < TargetField : PrimeField , BaseField : PrimeField > AllocVar < TargetField , BaseField >
for AllocatedNonNativeField Var < TargetField , BaseField >
impl < TargetF : PrimeField , BaseF : PrimeField > AllocVar < TargetF , BaseF >
for AllocatedEmulatedFp Var < TargetF , BaseF >
{
{
fn new_variable < T : Borrow < TargetField > > (
cs : impl Into < Namespace < BaseField > > ,
fn new_variable < T : Borrow < TargetF > > (
cs : impl Into < Namespace < BaseF > > ,
f : impl FnOnce ( ) -> Result < T , SynthesisError > ,
f : impl FnOnce ( ) -> Result < T , SynthesisError > ,
mode : AllocationMode ,
mode : AllocationMode ,
) -> R1CSResult < Self > {
) -> R1CSResult < Self > {
@ -875,18 +863,18 @@ impl AllocVar
}
}
}
}
impl < TargetField : PrimeField , BaseField : PrimeField > ToConstraintFieldGadget < BaseField >
for AllocatedNonNativeField Var < TargetField , BaseField >
impl < TargetF : PrimeField , BaseF : PrimeField > ToConstraintFieldGadget < BaseF >
for AllocatedEmulatedFp Var < TargetF , BaseF >
{
{
fn to_constraint_field ( & self ) -> R1CSResult < Vec < FpVar < BaseField > > > {
// provide a unique representation of the nonnative variable
fn to_constraint_field ( & self ) -> R1CSResult < Vec < FpVar < BaseF > > > {
// provide a unique representation of the emulated variable
// step 1: convert it into a bit sequence
// step 1: convert it into a bit sequence
let bits = self . to_bits_le ( ) ? ;
let bits = self . to_bits_le ( ) ? ;
// step 2: obtain the parameters for weight-optimized (often, fewer limbs)
// step 2: obtain the parameters for weight-optimized (often, fewer limbs)
let params = get_params (
let params = get_params (
TargetField ::MODULUS_BIT_SIZE as usize ,
BaseField ::MODULUS_BIT_SIZE as usize ,
TargetF ::MODULUS_BIT_SIZE as usize ,
BaseF ::MODULUS_BIT_SIZE as usize ,
OptimizationType ::Weight ,
OptimizationType ::Weight ,
) ;
) ;
@ -894,15 +882,15 @@ impl ToConstraintFieldGadget
let mut limbs = bits
let mut limbs = bits
. chunks ( params . bits_per_limb )
. chunks ( params . bits_per_limb )
. map ( | chunk | {
. map ( | chunk | {
let mut limb = FpVar ::< BaseField > ::zero ( ) ;
let mut w = BaseField ::one ( ) ;
let mut limb = FpVar ::< BaseF > ::zero ( ) ;
let mut w = BaseF ::one ( ) ;
for b in chunk . iter ( ) {
for b in chunk . iter ( ) {
limb + = FpVar ::from ( b . clone ( ) ) * w ;
limb + = FpVar ::from ( b . clone ( ) ) * w ;
w . double_in_place ( ) ;
w . double_in_place ( ) ;
}
}
limb
limb
} )
} )
. collect ::< Vec < FpVar < BaseField > > > ( ) ;
. collect ::< Vec < FpVar < BaseF > > > ( ) ;
limbs . reverse ( ) ;
limbs . reverse ( ) ;
@ -913,11 +901,9 @@ impl ToConstraintFieldGadget
// Implementation of a few traits
// Implementation of a few traits
impl < TargetField : PrimeField , BaseField : PrimeField > Clone
for AllocatedNonNativeFieldVar < TargetField , BaseField >
{
impl < TargetF : PrimeField , BaseF : PrimeField > Clone for AllocatedEmulatedFpVar < TargetF , BaseF > {
fn clone ( & self ) -> Self {
fn clone ( & self ) -> Self {
AllocatedNonNativeField Var {
AllocatedEmulatedFpVar {
cs : self . cs ( ) ,
cs : self . cs ( ) ,
limbs : self . limbs . clone ( ) ,
limbs : self . limbs . clone ( ) ,
num_of_additions_over_normal_form : self . num_of_additions_over_normal_form ,
num_of_additions_over_normal_form : self . num_of_additions_over_normal_form ,