diff --git a/ff/.gitignore b/ff/.gitignore new file mode 100644 index 000000000..4308d8220 --- /dev/null +++ b/ff/.gitignore @@ -0,0 +1,3 @@ +target/ +**/*.rs.bk +Cargo.lock diff --git a/ff/Cargo.toml b/ff/Cargo.toml new file mode 100644 index 000000000..22db67a8e --- /dev/null +++ b/ff/Cargo.toml @@ -0,0 +1,18 @@ +[package] +name = "ff" +version = "0.4.0" +authors = ["Sean Bowe "] +description = "Library for building and interfacing with finite fields" +documentation = "https://docs.rs/ff/" +homepage = "https://github.com/ebfull/ff" +license = "MIT/Apache-2.0" +repository = "https://github.com/ebfull/ff" + +[dependencies] +byteorder = "1" +rand = "0.4" +ff_derive = { version = "0.3.0", path = "ff_derive", optional = true } + +[features] +default = [] +derive = ["ff_derive"] diff --git a/ff/LICENSE-APACHE b/ff/LICENSE-APACHE new file mode 100644 index 000000000..1e5006dc1 --- /dev/null +++ b/ff/LICENSE-APACHE @@ -0,0 +1,202 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + diff --git a/ff/LICENSE-MIT b/ff/LICENSE-MIT new file mode 100644 index 000000000..ed3a13fdd --- /dev/null +++ b/ff/LICENSE-MIT @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2017 Sean Bowe + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/ff/README.md b/ff/README.md new file mode 100644 index 000000000..3efef941b --- /dev/null +++ b/ff/README.md @@ -0,0 +1,60 @@ +# ff + +`ff` is a finite field library written in pure Rust, with no `unsafe{}` code. + +## Disclaimers + +* This library does not provide constant-time guarantees. + +## Usage + +Add the `ff` crate to your `Cargo.toml`: + +```toml +[dependencies] +ff = "0.4" +``` + +The `ff` crate contains `Field`, `PrimeField`, `PrimeFieldRepr` and `SqrtField` traits. See the **[documentation](https://docs.rs/ff/0.4.0/ff/)** for more. + +### #![derive(PrimeField)] + +If you need an implementation of a prime field, this library also provides a procedural macro that will expand into an efficient implementation of a prime field when supplied with the modulus. `PrimeFieldGenerator` must be an element of Fp of p-1 order, that is also quadratic nonresidue. + +First, enable the `derive` crate feature: + +```toml +[dependencies] +ff = { version = "0.4", features = ["derive"] } +``` + +And then use the macro like so: + +```rust +extern crate rand; +#[macro_use] +extern crate ff; + +#[derive(PrimeField)] +#[PrimeFieldModulus = "52435875175126190479447740508185965837690552500527637822603658699938581184513"] +#[PrimeFieldGenerator = "7"] +struct Fp(FpRepr); +``` + +And that's it! `Fp` now implements `Field` and `PrimeField`. `Fp` will also implement `SqrtField` if supported. The library implements `FpRepr` itself and derives `PrimeFieldRepr` for it. + +## License + +Licensed under either of + + * Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0) + * MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT) + +at your option. + +### Contribution + +Unless you explicitly state otherwise, any contribution intentionally +submitted for inclusion in the work by you, as defined in the Apache-2.0 +license, shall be dual licensed as above, without any additional terms or +conditions. diff --git a/ff/ff_derive/Cargo.toml b/ff/ff_derive/Cargo.toml new file mode 100644 index 000000000..914e39258 --- /dev/null +++ b/ff/ff_derive/Cargo.toml @@ -0,0 +1,20 @@ +[package] +name = "ff_derive" +version = "0.3.0" +authors = ["Sean Bowe "] +description = "Procedural macro library used to build custom prime field implementations" +documentation = "https://docs.rs/ff/" +homepage = "https://github.com/ebfull/ff" +license = "MIT/Apache-2.0" +repository = "https://github.com/ebfull/ff" + +[lib] +proc-macro = true + +[dependencies] +num-bigint = "0.2" +num-traits = "0.2" +num-integer = "0.1" +proc-macro2 = "0.4" +quote = "0.6" +syn = "0.14" diff --git a/ff/ff_derive/src/lib.rs b/ff/ff_derive/src/lib.rs new file mode 100644 index 000000000..45d344537 --- /dev/null +++ b/ff/ff_derive/src/lib.rs @@ -0,0 +1,1065 @@ +#![recursion_limit = "1024"] + +extern crate proc_macro; +extern crate proc_macro2; +extern crate syn; +#[macro_use] +extern crate quote; + +extern crate num_bigint; +extern crate num_integer; +extern crate num_traits; + +use num_bigint::BigUint; +use num_integer::Integer; +use num_traits::{One, ToPrimitive, Zero}; +use quote::TokenStreamExt; +use std::str::FromStr; + +#[proc_macro_derive(PrimeField, attributes(PrimeFieldModulus, PrimeFieldGenerator))] +pub fn prime_field(input: proc_macro::TokenStream) -> proc_macro::TokenStream { + // Parse the type definition + let ast: syn::DeriveInput = syn::parse(input).unwrap(); + + // The struct we're deriving for is a wrapper around a "Repr" type we must construct. + let repr_ident = fetch_wrapped_ident(&ast.data) + .expect("PrimeField derive only operates over tuple structs of a single item"); + + // We're given the modulus p of the prime field + let modulus: BigUint = fetch_attr("PrimeFieldModulus", &ast.attrs) + .expect("Please supply a PrimeFieldModulus attribute") + .parse() + .expect("PrimeFieldModulus should be a number"); + + // We may be provided with a generator of p - 1 order. It is required that this generator be quadratic + // nonresidue. + let generator: BigUint = fetch_attr("PrimeFieldGenerator", &ast.attrs) + .expect("Please supply a PrimeFieldGenerator attribute") + .parse() + .expect("PrimeFieldGenerator should be a number"); + + // The arithmetic in this library only works if the modulus*2 is smaller than the backing + // representation. Compute the number of limbs we need. + let mut limbs = 1; + { + let mod2 = (&modulus) << 1; // modulus * 2 + let mut cur = BigUint::one() << 64; // always 64-bit limbs for now + while cur < mod2 { + limbs += 1; + cur = cur << 64; + } + } + + let mut gen = proc_macro2::TokenStream::new(); + + let (constants_impl, sqrt_impl) = prime_field_constants_and_sqrt( + &ast.ident, + &repr_ident, + modulus, + limbs, + generator, + ); + + gen.extend(constants_impl); + gen.extend(prime_field_repr_impl(&repr_ident, limbs)); + gen.extend(prime_field_impl(&ast.ident, &repr_ident, limbs)); + gen.extend(sqrt_impl); + + // Return the generated impl + gen.into() +} + +/// Fetches the ident being wrapped by the type we're deriving. +fn fetch_wrapped_ident(body: &syn::Data) -> Option { + match body { + &syn::Data::Struct(ref variant_data) => match variant_data.fields { + syn::Fields::Unnamed(ref fields) => { + if fields.unnamed.len() == 1 { + match fields.unnamed[0].ty { + syn::Type::Path(ref path) => { + if path.path.segments.len() == 1 { + return Some(path.path.segments[0].ident.clone()); + } + } + _ => {} + } + } + } + _ => {} + }, + _ => {} + }; + + None +} + +/// Fetch an attribute string from the derived struct. +fn fetch_attr(name: &str, attrs: &[syn::Attribute]) -> Option { + for attr in attrs { + if let Some(meta) = attr.interpret_meta() { + match meta { + syn::Meta::NameValue(nv) => { + if nv.ident.to_string() == name { + match nv.lit { + syn::Lit::Str(ref s) => return Some(s.value()), + _ => { + panic!("attribute {} should be a string", name); + } + } + } + } + _ => { + panic!("attribute {} should be a string", name); + } + } + } + } + + None +} + +// Implement PrimeFieldRepr for the wrapped ident `repr` with `limbs` limbs. +fn prime_field_repr_impl(repr: &syn::Ident, limbs: usize) -> proc_macro2::TokenStream { + quote! { + #[derive(Copy, Clone, PartialEq, Eq, Default)] + pub struct #repr(pub [u64; #limbs]); + + impl ::std::fmt::Debug for #repr + { + fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { + try!(write!(f, "0x")); + for i in self.0.iter().rev() { + try!(write!(f, "{:016x}", *i)); + } + + Ok(()) + } + } + + impl ::rand::Rand for #repr { + #[inline(always)] + fn rand(rng: &mut R) -> Self { + #repr(rng.gen()) + } + } + + impl ::std::fmt::Display for #repr { + fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { + try!(write!(f, "0x")); + for i in self.0.iter().rev() { + try!(write!(f, "{:016x}", *i)); + } + + Ok(()) + } + } + + impl AsRef<[u64]> for #repr { + #[inline(always)] + fn as_ref(&self) -> &[u64] { + &self.0 + } + } + + impl AsMut<[u64]> for #repr { + #[inline(always)] + fn as_mut(&mut self) -> &mut [u64] { + &mut self.0 + } + } + + impl From for #repr { + #[inline(always)] + fn from(val: u64) -> #repr { + use std::default::Default; + + let mut repr = Self::default(); + repr.0[0] = val; + repr + } + } + + impl Ord for #repr { + #[inline(always)] + fn cmp(&self, other: &#repr) -> ::std::cmp::Ordering { + for (a, b) in self.0.iter().rev().zip(other.0.iter().rev()) { + if a < b { + return ::std::cmp::Ordering::Less + } else if a > b { + return ::std::cmp::Ordering::Greater + } + } + + ::std::cmp::Ordering::Equal + } + } + + impl PartialOrd for #repr { + #[inline(always)] + fn partial_cmp(&self, other: &#repr) -> Option<::std::cmp::Ordering> { + Some(self.cmp(other)) + } + } + + impl ::ff::PrimeFieldRepr for #repr { + #[inline(always)] + fn is_odd(&self) -> bool { + self.0[0] & 1 == 1 + } + + #[inline(always)] + fn is_even(&self) -> bool { + !self.is_odd() + } + + #[inline(always)] + fn is_zero(&self) -> bool { + self.0.iter().all(|&e| e == 0) + } + + #[inline(always)] + fn shr(&mut self, mut n: u32) { + if n as usize >= 64 * #limbs { + *self = Self::from(0); + return; + } + + while n >= 64 { + let mut t = 0; + for i in self.0.iter_mut().rev() { + ::std::mem::swap(&mut t, i); + } + n -= 64; + } + + if n > 0 { + let mut t = 0; + for i in self.0.iter_mut().rev() { + let t2 = *i << (64 - n); + *i >>= n; + *i |= t; + t = t2; + } + } + } + + #[inline(always)] + fn div2(&mut self) { + let mut t = 0; + for i in self.0.iter_mut().rev() { + let t2 = *i << 63; + *i >>= 1; + *i |= t; + t = t2; + } + } + + #[inline(always)] + fn mul2(&mut self) { + let mut last = 0; + for i in &mut self.0 { + let tmp = *i >> 63; + *i <<= 1; + *i |= last; + last = tmp; + } + } + + #[inline(always)] + fn shl(&mut self, mut n: u32) { + if n as usize >= 64 * #limbs { + *self = Self::from(0); + return; + } + + while n >= 64 { + let mut t = 0; + for i in &mut self.0 { + ::std::mem::swap(&mut t, i); + } + n -= 64; + } + + if n > 0 { + let mut t = 0; + for i in &mut self.0 { + let t2 = *i >> (64 - n); + *i <<= n; + *i |= t; + t = t2; + } + } + } + + #[inline(always)] + fn num_bits(&self) -> u32 { + let mut ret = (#limbs as u32) * 64; + for i in self.0.iter().rev() { + let leading = i.leading_zeros(); + ret -= leading; + if leading != 64 { + break; + } + } + + ret + } + + #[inline(always)] + fn add_nocarry(&mut self, other: &#repr) { + let mut carry = 0; + + for (a, b) in self.0.iter_mut().zip(other.0.iter()) { + *a = ::ff::adc(*a, *b, &mut carry); + } + } + + #[inline(always)] + fn sub_noborrow(&mut self, other: &#repr) { + let mut borrow = 0; + + for (a, b) in self.0.iter_mut().zip(other.0.iter()) { + *a = ::ff::sbb(*a, *b, &mut borrow); + } + } + } + } +} + +/// Convert BigUint into a vector of 64-bit limbs. +fn biguint_to_real_u64_vec(mut v: BigUint, limbs: usize) -> Vec { + let m = BigUint::one() << 64; + let mut ret = vec![]; + + while v > BigUint::zero() { + ret.push((&v % &m).to_u64().unwrap()); + v = v >> 64; + } + + while ret.len() < limbs { + ret.push(0); + } + + assert!(ret.len() == limbs); + + ret +} + +/// Convert BigUint into a tokenized vector of 64-bit limbs. +fn biguint_to_u64_vec(v: BigUint, limbs: usize) -> proc_macro2::TokenStream { + let ret = biguint_to_real_u64_vec(v, limbs); + quote!([#(#ret,)*]) +} + +fn biguint_num_bits(mut v: BigUint) -> u32 { + let mut bits = 0; + + while v != BigUint::zero() { + v = v >> 1; + bits += 1; + } + + bits +} + +/// BigUint modular exponentiation by square-and-multiply. +fn exp(base: BigUint, exp: &BigUint, modulus: &BigUint) -> BigUint { + let mut ret = BigUint::one(); + + for i in exp.to_bytes_be() + .into_iter() + .flat_map(|x| (0..8).rev().map(move |i| (x >> i).is_odd())) + { + ret = (&ret * &ret) % modulus; + if i { + ret = (ret * &base) % modulus; + } + } + + ret +} + +#[test] +fn test_exp() { + assert_eq!( + exp( + BigUint::from_str("4398572349857239485729348572983472345").unwrap(), + &BigUint::from_str("5489673498567349856734895").unwrap(), + &BigUint::from_str( + "52435875175126190479447740508185965837690552500527637822603658699938581184513" + ).unwrap() + ), + BigUint::from_str( + "4371221214068404307866768905142520595925044802278091865033317963560480051536" + ).unwrap() + ); +} + +fn prime_field_constants_and_sqrt( + name: &syn::Ident, + repr: &syn::Ident, + modulus: BigUint, + limbs: usize, + generator: BigUint, +) -> (proc_macro2::TokenStream, proc_macro2::TokenStream) { + let modulus_num_bits = biguint_num_bits(modulus.clone()); + + // The number of bits we should "shave" from a randomly sampled reputation, i.e., + // if our modulus is 381 bits and our representation is 384 bits, we should shave + // 3 bits from the beginning of a randomly sampled 384 bit representation to + // reduce the cost of rejection sampling. + let repr_shave_bits = (64 * limbs as u32) - biguint_num_bits(modulus.clone()); + + // Compute R = 2**(64 * limbs) mod m + let r = (BigUint::one() << (limbs * 64)) % &modulus; + + // modulus - 1 = 2^s * t + let mut s: u32 = 0; + let mut t = &modulus - BigUint::from_str("1").unwrap(); + while t.is_even() { + t = t >> 1; + s += 1; + } + + // Compute 2^s root of unity given the generator + let root_of_unity = biguint_to_u64_vec( + (exp(generator.clone(), &t, &modulus) * &r) % &modulus, + limbs, + ); + let generator = biguint_to_u64_vec((generator.clone() * &r) % &modulus, limbs); + + let mod_minus_1_over_2 = + biguint_to_u64_vec((&modulus - BigUint::from_str("1").unwrap()) >> 1, limbs); + let legendre_impl = quote!{ + fn legendre(&self) -> ::ff::LegendreSymbol { + // s = self^((modulus - 1) // 2) + let s = self.pow(#mod_minus_1_over_2); + if s == Self::zero() { + ::ff::LegendreSymbol::Zero + } else if s == Self::one() { + ::ff::LegendreSymbol::QuadraticResidue + } else { + ::ff::LegendreSymbol::QuadraticNonResidue + } + } + }; + + let sqrt_impl = + if (&modulus % BigUint::from_str("4").unwrap()) == BigUint::from_str("3").unwrap() { + let mod_minus_3_over_4 = + biguint_to_u64_vec((&modulus - BigUint::from_str("3").unwrap()) >> 2, limbs); + + // Compute -R as (m - r) + let rneg = biguint_to_u64_vec(&modulus - &r, limbs); + + quote!{ + impl ::ff::SqrtField for #name { + #legendre_impl + + fn sqrt(&self) -> Option { + // Shank's algorithm for q mod 4 = 3 + // https://eprint.iacr.org/2012/685.pdf (page 9, algorithm 2) + + let mut a1 = self.pow(#mod_minus_3_over_4); + + let mut a0 = a1; + a0.square(); + a0.mul_assign(self); + + if a0.0 == #repr(#rneg) { + None + } else { + a1.mul_assign(self); + Some(a1) + } + } + } + } + } else if (&modulus % BigUint::from_str("16").unwrap()) == BigUint::from_str("1").unwrap() { + let t_plus_1_over_2 = biguint_to_u64_vec((&t + BigUint::one()) >> 1, limbs); + let t = biguint_to_u64_vec(t.clone(), limbs); + + quote!{ + impl ::ff::SqrtField for #name { + #legendre_impl + + fn sqrt(&self) -> Option { + // Tonelli-Shank's algorithm for q mod 16 = 1 + // https://eprint.iacr.org/2012/685.pdf (page 12, algorithm 5) + + match self.legendre() { + ::ff::LegendreSymbol::Zero => Some(*self), + ::ff::LegendreSymbol::QuadraticNonResidue => None, + ::ff::LegendreSymbol::QuadraticResidue => { + let mut c = #name(ROOT_OF_UNITY); + let mut r = self.pow(#t_plus_1_over_2); + let mut t = self.pow(#t); + let mut m = S; + + while t != Self::one() { + let mut i = 1; + { + let mut t2i = t; + t2i.square(); + loop { + if t2i == Self::one() { + break; + } + t2i.square(); + i += 1; + } + } + + for _ in 0..(m - i - 1) { + c.square(); + } + r.mul_assign(&c); + c.square(); + t.mul_assign(&c); + m = i; + } + + Some(r) + } + } + } + } + } + } else { + quote!{} + }; + + // Compute R^2 mod m + let r2 = biguint_to_u64_vec((&r * &r) % &modulus, limbs); + + let r = biguint_to_u64_vec(r, limbs); + let modulus = biguint_to_real_u64_vec(modulus, limbs); + + // Compute -m^-1 mod 2**64 by exponentiating by totient(2**64) - 1 + let mut inv = 1u64; + for _ in 0..63 { + inv = inv.wrapping_mul(inv); + inv = inv.wrapping_mul(modulus[0]); + } + inv = inv.wrapping_neg(); + + (quote! { + /// This is the modulus m of the prime field + const MODULUS: #repr = #repr([#(#modulus,)*]); + + /// The number of bits needed to represent the modulus. + const MODULUS_BITS: u32 = #modulus_num_bits; + + /// The number of bits that must be shaved from the beginning of + /// the representation when randomly sampling. + const REPR_SHAVE_BITS: u32 = #repr_shave_bits; + + /// 2^{limbs*64} mod m + const R: #repr = #repr(#r); + + /// 2^{limbs*64*2} mod m + const R2: #repr = #repr(#r2); + + /// -(m^{-1} mod m) mod m + const INV: u64 = #inv; + + /// Multiplicative generator of `MODULUS` - 1 order, also quadratic + /// nonresidue. + const GENERATOR: #repr = #repr(#generator); + + /// 2^s * t = MODULUS - 1 with t odd + const S: u32 = #s; + + /// 2^s root of unity computed by GENERATOR^t + const ROOT_OF_UNITY: #repr = #repr(#root_of_unity); + }, sqrt_impl) +} + +/// Implement PrimeField for the derived type. +fn prime_field_impl( + name: &syn::Ident, + repr: &syn::Ident, + limbs: usize, +) -> proc_macro2::TokenStream { + // Returns r{n} as an ident. + fn get_temp(n: usize) -> syn::Ident { + syn::Ident::new(&format!("r{}", n), proc_macro2::Span::call_site()) + } + + // The parameter list for the mont_reduce() internal method. + // r0: u64, mut r1: u64, mut r2: u64, ... + let mut mont_paramlist = proc_macro2::TokenStream::new(); + mont_paramlist.append_separated( + (0..(limbs * 2)).map(|i| (i, get_temp(i))).map(|(i, x)| { + if i != 0 { + quote!{mut #x: u64} + } else { + quote!{#x: u64} + } + }), + proc_macro2::Punct::new(',', proc_macro2::Spacing::Alone), + ); + + // Implement montgomery reduction for some number of limbs + fn mont_impl(limbs: usize) -> proc_macro2::TokenStream { + let mut gen = proc_macro2::TokenStream::new(); + + for i in 0..limbs { + { + let temp = get_temp(i); + gen.extend(quote!{ + let k = #temp.wrapping_mul(INV); + let mut carry = 0; + ::ff::mac_with_carry(#temp, k, MODULUS.0[0], &mut carry); + }); + } + + for j in 1..limbs { + let temp = get_temp(i + j); + gen.extend(quote!{ + #temp = ::ff::mac_with_carry(#temp, k, MODULUS.0[#j], &mut carry); + }); + } + + let temp = get_temp(i + limbs); + + if i == 0 { + gen.extend(quote!{ + #temp = ::ff::adc(#temp, 0, &mut carry); + }); + } else { + gen.extend(quote!{ + #temp = ::ff::adc(#temp, carry2, &mut carry); + }); + } + + if i != (limbs - 1) { + gen.extend(quote!{ + let carry2 = carry; + }); + } + } + + for i in 0..limbs { + let temp = get_temp(limbs + i); + + gen.extend(quote!{ + (self.0).0[#i] = #temp; + }); + } + + gen + } + + fn sqr_impl(a: proc_macro2::TokenStream, limbs: usize) -> proc_macro2::TokenStream { + let mut gen = proc_macro2::TokenStream::new(); + + for i in 0..(limbs - 1) { + gen.extend(quote!{ + let mut carry = 0; + }); + + for j in (i + 1)..limbs { + let temp = get_temp(i + j); + if i == 0 { + gen.extend(quote!{ + let #temp = ::ff::mac_with_carry(0, (#a.0).0[#i], (#a.0).0[#j], &mut carry); + }); + } else { + gen.extend(quote!{ + let #temp = ::ff::mac_with_carry(#temp, (#a.0).0[#i], (#a.0).0[#j], &mut carry); + }); + } + } + + let temp = get_temp(i + limbs); + + gen.extend(quote!{ + let #temp = carry; + }); + } + + for i in 1..(limbs * 2) { + let temp0 = get_temp(limbs * 2 - i); + let temp1 = get_temp(limbs * 2 - i - 1); + + if i == 1 { + gen.extend(quote!{ + let #temp0 = #temp1 >> 63; + }); + } else if i == (limbs * 2 - 1) { + gen.extend(quote!{ + let #temp0 = #temp0 << 1; + }); + } else { + gen.extend(quote!{ + let #temp0 = (#temp0 << 1) | (#temp1 >> 63); + }); + } + } + + gen.extend(quote!{ + let mut carry = 0; + }); + + for i in 0..limbs { + let temp0 = get_temp(i * 2); + let temp1 = get_temp(i * 2 + 1); + if i == 0 { + gen.extend(quote!{ + let #temp0 = ::ff::mac_with_carry(0, (#a.0).0[#i], (#a.0).0[#i], &mut carry); + }); + } else { + gen.extend(quote!{ + let #temp0 = ::ff::mac_with_carry(#temp0, (#a.0).0[#i], (#a.0).0[#i], &mut carry); + }); + } + + gen.extend(quote!{ + let #temp1 = ::ff::adc(#temp1, 0, &mut carry); + }); + } + + let mut mont_calling = proc_macro2::TokenStream::new(); + mont_calling.append_separated( + (0..(limbs * 2)).map(|i| get_temp(i)), + proc_macro2::Punct::new(',', proc_macro2::Spacing::Alone), + ); + + gen.extend(quote!{ + self.mont_reduce(#mont_calling); + }); + + gen + } + + fn mul_impl( + a: proc_macro2::TokenStream, + b: proc_macro2::TokenStream, + limbs: usize, + ) -> proc_macro2::TokenStream { + let mut gen = proc_macro2::TokenStream::new(); + + for i in 0..limbs { + gen.extend(quote!{ + let mut carry = 0; + }); + + for j in 0..limbs { + let temp = get_temp(i + j); + + if i == 0 { + gen.extend(quote!{ + let #temp = ::ff::mac_with_carry(0, (#a.0).0[#i], (#b.0).0[#j], &mut carry); + }); + } else { + gen.extend(quote!{ + let #temp = ::ff::mac_with_carry(#temp, (#a.0).0[#i], (#b.0).0[#j], &mut carry); + }); + } + } + + let temp = get_temp(i + limbs); + + gen.extend(quote!{ + let #temp = carry; + }); + } + + let mut mont_calling = proc_macro2::TokenStream::new(); + mont_calling.append_separated( + (0..(limbs * 2)).map(|i| get_temp(i)), + proc_macro2::Punct::new(',', proc_macro2::Spacing::Alone), + ); + + gen.extend(quote!{ + self.mont_reduce(#mont_calling); + }); + + gen + } + + let squaring_impl = sqr_impl(quote!{self}, limbs); + let multiply_impl = mul_impl(quote!{self}, quote!{other}, limbs); + let montgomery_impl = mont_impl(limbs); + + // (self.0).0[0], (self.0).0[1], ..., 0, 0, 0, 0, ... + let mut into_repr_params = proc_macro2::TokenStream::new(); + into_repr_params.append_separated( + (0..limbs) + .map(|i| quote!{ (self.0).0[#i] }) + .chain((0..limbs).map(|_| quote!{0})), + proc_macro2::Punct::new(',', proc_macro2::Spacing::Alone), + ); + + let top_limb_index = limbs - 1; + + quote!{ + impl ::std::marker::Copy for #name { } + + impl ::std::clone::Clone for #name { + fn clone(&self) -> #name { + *self + } + } + + impl ::std::cmp::PartialEq for #name { + fn eq(&self, other: &#name) -> bool { + self.0 == other.0 + } + } + + impl ::std::cmp::Eq for #name { } + + impl ::std::fmt::Debug for #name + { + fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { + write!(f, "{}({:?})", stringify!(#name), self.into_repr()) + } + } + + /// Elements are ordered lexicographically. + impl Ord for #name { + #[inline(always)] + fn cmp(&self, other: &#name) -> ::std::cmp::Ordering { + self.into_repr().cmp(&other.into_repr()) + } + } + + impl PartialOrd for #name { + #[inline(always)] + fn partial_cmp(&self, other: &#name) -> Option<::std::cmp::Ordering> { + Some(self.cmp(other)) + } + } + + impl ::std::fmt::Display for #name { + fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { + write!(f, "{}({})", stringify!(#name), self.into_repr()) + } + } + + impl ::rand::Rand for #name { + /// Computes a uniformly random element using rejection sampling. + fn rand(rng: &mut R) -> Self { + loop { + let mut tmp = #name(#repr::rand(rng)); + + // Mask away the unused bits at the beginning. + tmp.0.as_mut()[#top_limb_index] &= 0xffffffffffffffff >> REPR_SHAVE_BITS; + + if tmp.is_valid() { + return tmp + } + } + } + } + + impl From<#name> for #repr { + fn from(e: #name) -> #repr { + e.into_repr() + } + } + + impl ::ff::PrimeField for #name { + type Repr = #repr; + + fn from_repr(r: #repr) -> Result<#name, PrimeFieldDecodingError> { + let mut r = #name(r); + if r.is_valid() { + r.mul_assign(&#name(R2)); + + Ok(r) + } else { + Err(PrimeFieldDecodingError::NotInField(format!("{}", r.0))) + } + } + + fn into_repr(&self) -> #repr { + let mut r = *self; + r.mont_reduce( + #into_repr_params + ); + + r.0 + } + + fn char() -> #repr { + MODULUS + } + + const NUM_BITS: u32 = MODULUS_BITS; + + const CAPACITY: u32 = Self::NUM_BITS - 1; + + fn multiplicative_generator() -> Self { + #name(GENERATOR) + } + + const S: u32 = S; + + fn root_of_unity() -> Self { + #name(ROOT_OF_UNITY) + } + } + + impl ::ff::Field for #name { + #[inline] + fn zero() -> Self { + #name(#repr::from(0)) + } + + #[inline] + fn one() -> Self { + #name(R) + } + + #[inline] + fn is_zero(&self) -> bool { + self.0.is_zero() + } + + #[inline] + fn add_assign(&mut self, other: &#name) { + // This cannot exceed the backing capacity. + self.0.add_nocarry(&other.0); + + // However, it may need to be reduced. + self.reduce(); + } + + #[inline] + fn double(&mut self) { + // This cannot exceed the backing capacity. + self.0.mul2(); + + // However, it may need to be reduced. + self.reduce(); + } + + #[inline] + fn sub_assign(&mut self, other: &#name) { + // If `other` is larger than `self`, we'll need to add the modulus to self first. + if other.0 > self.0 { + self.0.add_nocarry(&MODULUS); + } + + self.0.sub_noborrow(&other.0); + } + + #[inline] + fn negate(&mut self) { + if !self.is_zero() { + let mut tmp = MODULUS; + tmp.sub_noborrow(&self.0); + self.0 = tmp; + } + } + + fn inverse(&self) -> Option { + if self.is_zero() { + None + } else { + // Guajardo Kumar Paar Pelzl + // Efficient Software-Implementation of Finite Fields with Applications to Cryptography + // Algorithm 16 (BEA for Inversion in Fp) + + let one = #repr::from(1); + + let mut u = self.0; + let mut v = MODULUS; + let mut b = #name(R2); // Avoids unnecessary reduction step. + let mut c = Self::zero(); + + while u != one && v != one { + while u.is_even() { + u.div2(); + + if b.0.is_even() { + b.0.div2(); + } else { + b.0.add_nocarry(&MODULUS); + b.0.div2(); + } + } + + while v.is_even() { + v.div2(); + + if c.0.is_even() { + c.0.div2(); + } else { + c.0.add_nocarry(&MODULUS); + c.0.div2(); + } + } + + if v < u { + u.sub_noborrow(&v); + b.sub_assign(&c); + } else { + v.sub_noborrow(&u); + c.sub_assign(&b); + } + } + + if u == one { + Some(b) + } else { + Some(c) + } + } + } + + #[inline(always)] + fn frobenius_map(&mut self, _: usize) { + // This has no effect in a prime field. + } + + #[inline] + fn mul_assign(&mut self, other: &#name) + { + #multiply_impl + } + + #[inline] + fn square(&mut self) + { + #squaring_impl + } + } + + impl #name { + /// Determines if the element is really in the field. This is only used + /// internally. + #[inline(always)] + fn is_valid(&self) -> bool { + self.0 < MODULUS + } + + /// Subtracts the modulus from this element if this element is not in the + /// field. Only used interally. + #[inline(always)] + fn reduce(&mut self) { + if !self.is_valid() { + self.0.sub_noborrow(&MODULUS); + } + } + + #[inline(always)] + fn mont_reduce( + &mut self, + #mont_paramlist + ) + { + // The Montgomery reduction here is based on Algorithm 14.32 in + // Handbook of Applied Cryptography + // . + + #montgomery_impl + + self.reduce(); + } + } + } +} diff --git a/ff/src/lib.rs b/ff/src/lib.rs new file mode 100644 index 000000000..a9d117f24 --- /dev/null +++ b/ff/src/lib.rs @@ -0,0 +1,393 @@ +#![allow(unused_imports)] + +extern crate byteorder; +extern crate rand; + +#[cfg(feature = "derive")] +#[macro_use] +extern crate ff_derive; + +#[cfg(feature = "derive")] +pub use ff_derive::*; + +use std::error::Error; +use std::fmt; +use std::io::{self, Read, Write}; + +/// This trait represents an element of a field. +pub trait Field: + Sized + Eq + Copy + Clone + Send + Sync + fmt::Debug + fmt::Display + 'static + rand::Rand +{ + /// Returns the zero element of the field, the additive identity. + fn zero() -> Self; + + /// Returns the one element of the field, the multiplicative identity. + fn one() -> Self; + + /// Returns true iff this element is zero. + fn is_zero(&self) -> bool; + + /// Squares this element. + fn square(&mut self); + + /// Doubles this element. + fn double(&mut self); + + /// Negates this element. + fn negate(&mut self); + + /// Adds another element to this element. + fn add_assign(&mut self, other: &Self); + + /// Subtracts another element from this element. + fn sub_assign(&mut self, other: &Self); + + /// Multiplies another element by this element. + fn mul_assign(&mut self, other: &Self); + + /// Computes the multiplicative inverse of this element, if nonzero. + fn inverse(&self) -> Option; + + /// Exponentiates this element by a power of the base prime modulus via + /// the Frobenius automorphism. + fn frobenius_map(&mut self, power: usize); + + /// Exponentiates this element by a number represented with `u64` limbs, + /// least significant digit first. + fn pow>(&self, exp: S) -> Self { + let mut res = Self::one(); + + let mut found_one = false; + + for i in BitIterator::new(exp) { + if found_one { + res.square(); + } else { + found_one = i; + } + + if i { + res.mul_assign(self); + } + } + + res + } +} + +/// This trait represents an element of a field that has a square root operation described for it. +pub trait SqrtField: Field { + /// Returns the Legendre symbol of the field element. + fn legendre(&self) -> LegendreSymbol; + + /// Returns the square root of the field element, if it is + /// quadratic residue. + fn sqrt(&self) -> Option; +} + +/// This trait represents a wrapper around a biginteger which can encode any element of a particular +/// prime field. It is a smart wrapper around a sequence of `u64` limbs, least-significant digit +/// first. +pub trait PrimeFieldRepr: + Sized + + Copy + + Clone + + Eq + + Ord + + Send + + Sync + + Default + + fmt::Debug + + fmt::Display + + 'static + + rand::Rand + + AsRef<[u64]> + + AsMut<[u64]> + + From +{ + /// Subtract another represetation from this one. + fn sub_noborrow(&mut self, other: &Self); + + /// Add another representation to this one. + fn add_nocarry(&mut self, other: &Self); + + /// Compute the number of bits needed to encode this number. Always a + /// multiple of 64. + fn num_bits(&self) -> u32; + + /// Returns true iff this number is zero. + fn is_zero(&self) -> bool; + + /// Returns true iff this number is odd. + fn is_odd(&self) -> bool; + + /// Returns true iff this number is even. + fn is_even(&self) -> bool; + + /// Performs a rightwise bitshift of this number, effectively dividing + /// it by 2. + fn div2(&mut self); + + /// Performs a rightwise bitshift of this number by some amount. + fn shr(&mut self, amt: u32); + + /// Performs a leftwise bitshift of this number, effectively multiplying + /// it by 2. Overflow is ignored. + fn mul2(&mut self); + + /// Performs a leftwise bitshift of this number by some amount. + fn shl(&mut self, amt: u32); + + /// Writes this `PrimeFieldRepr` as a big endian integer. + fn write_be(&self, mut writer: W) -> io::Result<()> { + use byteorder::{BigEndian, WriteBytesExt}; + + for digit in self.as_ref().iter().rev() { + writer.write_u64::(*digit)?; + } + + Ok(()) + } + + /// Reads a big endian integer into this representation. + fn read_be(&mut self, mut reader: R) -> io::Result<()> { + use byteorder::{BigEndian, ReadBytesExt}; + + for digit in self.as_mut().iter_mut().rev() { + *digit = reader.read_u64::()?; + } + + Ok(()) + } + + /// Writes this `PrimeFieldRepr` as a little endian integer. + fn write_le(&self, mut writer: W) -> io::Result<()> { + use byteorder::{LittleEndian, WriteBytesExt}; + + for digit in self.as_ref().iter() { + writer.write_u64::(*digit)?; + } + + Ok(()) + } + + /// Reads a little endian integer into this representation. + fn read_le(&mut self, mut reader: R) -> io::Result<()> { + use byteorder::{LittleEndian, ReadBytesExt}; + + for digit in self.as_mut().iter_mut() { + *digit = reader.read_u64::()?; + } + + Ok(()) + } +} + +#[derive(Debug, PartialEq)] +pub enum LegendreSymbol { + Zero = 0, + QuadraticResidue = 1, + QuadraticNonResidue = -1, +} + +/// An error that may occur when trying to interpret a `PrimeFieldRepr` as a +/// `PrimeField` element. +#[derive(Debug)] +pub enum PrimeFieldDecodingError { + /// The encoded value is not in the field + NotInField(String), +} + +impl Error for PrimeFieldDecodingError { + fn description(&self) -> &str { + match *self { + PrimeFieldDecodingError::NotInField(..) => "not an element of the field", + } + } +} + +impl fmt::Display for PrimeFieldDecodingError { + fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { + match *self { + PrimeFieldDecodingError::NotInField(ref repr) => { + write!(f, "{} is not an element of the field", repr) + } + } + } +} + +/// This represents an element of a prime field. +pub trait PrimeField: Field { + /// The prime field can be converted back and forth into this biginteger + /// representation. + type Repr: PrimeFieldRepr + From; + + /// Interpret a string of numbers as a (congruent) prime field element. + /// Does not accept unnecessary leading zeroes or a blank string. + fn from_str(s: &str) -> Option { + if s.is_empty() { + return None; + } + + if s == "0" { + return Some(Self::zero()); + } + + let mut res = Self::zero(); + + let ten = Self::from_repr(Self::Repr::from(10)).unwrap(); + + let mut first_digit = true; + + for c in s.chars() { + match c.to_digit(10) { + Some(c) => { + if first_digit { + if c == 0 { + return None; + } + + first_digit = false; + } + + res.mul_assign(&ten); + res.add_assign(&Self::from_repr(Self::Repr::from(u64::from(c))).unwrap()); + } + None => { + return None; + } + } + } + + Some(res) + } + + /// Convert this prime field element into a biginteger representation. + fn from_repr(Self::Repr) -> Result; + + /// Convert a biginteger representation into a prime field element, if + /// the number is an element of the field. + fn into_repr(&self) -> Self::Repr; + + /// Returns the field characteristic; the modulus. + fn char() -> Self::Repr; + + /// How many bits are needed to represent an element of this field. + const NUM_BITS: u32; + + /// How many bits of information can be reliably stored in the field element. + const CAPACITY: u32; + + /// Returns the multiplicative generator of `char()` - 1 order. This element + /// must also be quadratic nonresidue. + fn multiplicative_generator() -> Self; + + /// 2^s * t = `char()` - 1 with t odd. + const S: u32; + + /// Returns the 2^s root of unity computed by exponentiating the `multiplicative_generator()` + /// by t. + fn root_of_unity() -> Self; +} + +/// An "engine" is a collection of types (fields, elliptic curve groups, etc.) +/// with well-defined relationships. Specific relationships (for example, a +/// pairing-friendly curve) can be defined in a subtrait. +pub trait ScalarEngine: Sized + 'static + Clone { + /// This is the scalar field of the engine's groups. + type Fr: PrimeField + SqrtField; +} + +#[derive(Debug)] +pub struct BitIterator { + t: E, + n: usize, +} + +impl> BitIterator { + pub fn new(t: E) -> Self { + let n = t.as_ref().len() * 64; + + BitIterator { t, n } + } +} + +impl> Iterator for BitIterator { + type Item = bool; + + fn next(&mut self) -> Option { + if self.n == 0 { + None + } else { + self.n -= 1; + let part = self.n / 64; + let bit = self.n - (64 * part); + + Some(self.t.as_ref()[part] & (1 << bit) > 0) + } + } +} + +#[test] +fn test_bit_iterator() { + let mut a = BitIterator::new([0xa953d79b83f6ab59, 0x6dea2059e200bd39]); + let expected = "01101101111010100010000001011001111000100000000010111101001110011010100101010011110101111001101110000011111101101010101101011001"; + + for e in expected.chars() { + assert!(a.next().unwrap() == (e == '1')); + } + + assert!(a.next().is_none()); + + let expected = "1010010101111110101010000101101011101000011101110101001000011001100100100011011010001011011011010001011011101100110100111011010010110001000011110100110001100110011101101000101100011100100100100100001010011101010111110011101011000011101000111011011101011001"; + + let mut a = BitIterator::new([ + 0x429d5f3ac3a3b759, + 0xb10f4c66768b1c92, + 0x92368b6d16ecd3b4, + 0xa57ea85ae8775219, + ]); + + for e in expected.chars() { + assert!(a.next().unwrap() == (e == '1')); + } + + assert!(a.next().is_none()); +} + +pub use self::arith_impl::*; + +mod arith_impl { + /// Calculate a - b - borrow, returning the result and modifying + /// the borrow value. + #[inline(always)] + pub fn sbb(a: u64, b: u64, borrow: &mut u64) -> u64 { + let tmp = (1u128 << 64) + u128::from(a) - u128::from(b) - u128::from(*borrow); + + *borrow = if tmp >> 64 == 0 { 1 } else { 0 }; + + tmp as u64 + } + + /// Calculate a + b + carry, returning the sum and modifying the + /// carry value. + #[inline(always)] + pub fn adc(a: u64, b: u64, carry: &mut u64) -> u64 { + let tmp = u128::from(a) + u128::from(b) + u128::from(*carry); + + *carry = (tmp >> 64) as u64; + + tmp as u64 + } + + /// Calculate a + (b * c) + carry, returning the least significant digit + /// and setting carry to the most significant digit. + #[inline(always)] + pub fn mac_with_carry(a: u64, b: u64, c: u64, carry: &mut u64) -> u64 { + let tmp = (u128::from(a)) + u128::from(b) * u128::from(c) + u128::from(*carry); + + *carry = (tmp >> 64) as u64; + + tmp as u64 + } +}