Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support for more backends #797

Open
wants to merge 7 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 6 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
67 changes: 66 additions & 1 deletion ff-macros/src/montgomery/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ use sum_of_products::sum_of_products_impl;
use crate::utils;

pub fn mont_config_helper(
// The modulus p of the field
modulus: BigUint,
generator: BigUint,
small_subgroup_base: Option<u32>,
Expand All @@ -37,12 +38,16 @@ pub fn mont_config_helper(
}
}

// modulus - 1 = 2^s * t
// Compute trace t and 2-adicity s such that p - 1 = 2^s * t
let mut trace = &modulus - BigUint::from_str("1").unwrap();
while !trace.bit(0) {
trace >>= 1u8;
}

let two_adicity = (&modulus - 1u8)
.trailing_zeros()
.expect("two_adicity should fit in u32") as u32;

// Compute 2^s root of unity given the generator
let remaining_subgroup_size = match (small_subgroup_base, small_subgroup_power) {
(Some(base), Some(power)) => Some(&trace / BigUint::from(base).pow(power)),
Expand All @@ -53,9 +58,37 @@ pub fn mont_config_helper(
let large_subgroup_generator = remaining_subgroup_size
.as_ref()
.map(|e| generator.modpow(e, &modulus).to_string());

// Compute R = 2**(64 * limbs) mod m
let r = (BigUint::one() << (limbs * 64)) % &modulus;
let r_squared = ((&r * &r) % &modulus).to_string();
let r = r.to_string();
let modulus_mod_4 = (&modulus % 4u64).try_into().unwrap();

let modulus_plus_one_div_four = ((&modulus + 1u8) / 4u8).to_u64_digits();
let trace_minus_one_div_two = ((&trace - 1u8) / 2u8).to_u64_digits();
let sqrt_precomp = match modulus_mod_4 {
3 => quote::quote!(Some(SqrtPrecomputation::Case3Mod4 {
modulus_plus_one_div_four: &[ #( #modulus_plus_one_div_four ),* ]
})),
1 => quote::quote!(Some(SqrtPrecomputation::TonelliShanks {
two_adicity: Self::TWO_ADICITY,
quadratic_nonresidue_to_trace: Self::TWO_ADIC_ROOT_OF_UNITY,
trace_of_modulus_minus_one_div_two: &[ #( #trace_minus_one_div_two ),* ]
})),
_ => panic!("Modulus must be odd"),
};

let modulus_plus_one_div_four = if modulus_mod_4 == 3u8 {
quote::quote! { Some(BigInt([ #( #modulus_plus_one_div_four ),* ])) }
} else {
quote::quote! { None }
};

let modulus = modulus.to_string();
let generator = generator.to_string();
let two_adic_root_of_unity = two_adic_root_of_unity.to_string();

let modulus_limbs = utils::str_to_limbs_u64(&modulus).1;
let modulus_has_spare_bit = modulus_limbs.last().unwrap() >> 63 == 0;
let can_use_no_carry_mul_opt = {
Expand All @@ -66,6 +99,14 @@ pub fn mont_config_helper(
first_limb_check
}
};

let mut inv = 1u64;
for _ in 0..63 {
inv = inv.wrapping_mul(inv);
inv = inv.wrapping_mul(modulus_limbs[0]);
}
inv = inv.wrapping_neg();

let modulus = quote::quote! { BigInt([ #( #modulus_limbs ),* ]) };

let add_with_carry = add_with_carry_impl(limbs);
Expand Down Expand Up @@ -111,8 +152,32 @@ pub fn mont_config_helper(

const GENERATOR: F = ark_ff::MontFp!(#generator);

const TWO_ADICITY: u32 = #two_adicity;

const TWO_ADIC_ROOT_OF_UNITY: F = ark_ff::MontFp!(#two_adic_root_of_unity);

const R: B = ark_ff::BigInt!(#r);

const R2: B = ark_ff::BigInt!(#r_squared);

const INV: u64 = #inv;

#[doc(hidden)]
const CAN_USE_NO_CARRY_MUL_OPT: bool = #can_use_no_carry_mul_opt;

#[doc(hidden)]
const CAN_USE_NO_CARRY_SQUARE_OPT: bool = #can_use_no_carry_mul_opt;

#[doc(hidden)]
const MODULUS_HAS_SPARE_BIT: bool = #modulus_has_spare_bit;


/// (MODULUS + 1) / 4 when MODULUS % 4 == 3. Used for square root precomputations.
#[doc(hidden)]
const MODULUS_PLUS_ONE_DIV_FOUR: Option<B> = #modulus_plus_one_div_four;

const SQRT_PRECOMP: Option<SqrtPrecomputation<F>> = #sqrt_precomp;

#mixed_radix

#[inline(always)]
Expand Down
38 changes: 38 additions & 0 deletions ff/src/biginteger/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -289,6 +289,44 @@ impl<const N: usize> BigInt<N> {
crate::const_helpers::R2Buffer::<N>([0u64; N], [0u64; N], 1);
const_modulo!(two_pow_n_times_64_square, self)
}

/// Compute `-self^{-1}` mod 2^64.
pub const fn montgomery_inv(&self) -> u64 {
// We compute this as follows.
// First, MODULUS mod 2^64 is just the lower 64 bits of MODULUS.
// Hence MODULUS mod 2^64 = MODULUS.0[0] mod 2^64.
//
Comment on lines +295 to +298
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As a follow-up to this PR, the next step would be to rename this existing BigInt to BigInt64, and then also add a BigInt32, correct?

// Next, computing the inverse mod 2^64 involves exponentiating by
// the multiplicative group order, which is euler_totient(2^64) - 1.
// Now, euler_totient(2^64) = 1 << 63, and so
// euler_totient(2^64) - 1 = (1 << 63) - 1 = 1111111... (63 digits).
// We compute this powering via standard square and multiply.
let mut inv = 1u64;
crate::const_for!((_i in 0..63) {
// Square
inv = inv.wrapping_mul(inv);
// Multiply
inv = inv.wrapping_mul(self.0[0]);
});
inv.wrapping_neg()
}

pub const fn msb(&self) -> bool {
self.0[N - 1] >> 63 == 1
}

pub const fn plus_one_div_four(&self) -> Option<Self> {
if self.mod_4() == 3 {
let (modulus_plus_one, carry) = self.const_add_with_carry(&BigInt::<N>::one());
let mut result = modulus_plus_one.divide_by_2_round_down();
// Since modulus_plus_one is even, dividing by 2 results in a MSB of 0.
// Thus we can set MSB to `carry` to get the correct result of (MODULUS + 1) // 2:
result.0[N - 1] |= (carry as u64) << 63;
Some(result.divide_by_2_round_down())
} else {
None
}
}
}

impl<const N: usize> BigInteger for BigInt<N> {
Expand Down
1 change: 1 addition & 0 deletions ff/src/const_helpers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ use ark_std::ops::{Index, IndexMut};
use crate::BigInt;

/// A helper macro for emulating `for` loops in a `const` context.
///
/// # Usage
/// ```rust
/// # use ark_ff::const_for;
Expand Down
4 changes: 2 additions & 2 deletions ff/src/fields/models/fp/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@ use ark_std::{
use core::iter;

#[macro_use]
mod montgomery_backend;
pub use montgomery_backend::*;
mod montgomery;
pub use montgomery::*;

/// A trait that specifies the configuration of a prime field.
/// Also specifies how to perform arithmetic on field elements.
Expand Down
Loading
Loading