From b11ea2db258b7e8a432866eba5f677e99fa4d747 Mon Sep 17 00:00:00 2001 From: Sean Bowe Date: Sun, 25 Jun 2017 23:09:43 -0600 Subject: [PATCH] Initial commit. --- .gitignore | 3 + Cargo.toml | 8 ++ LICENSE-APACHE | 202 +++++++++++++++++++++++++++++++++++++ LICENSE-MIT | 21 ++++ README.md | 51 ++++++++++ ff_derive/Cargo.toml | 13 +++ ff_derive/src/lib.rs | 111 ++++++++++++++++++++ src/lib.rs | 235 +++++++++++++++++++++++++++++++++++++++++++ 8 files changed, 644 insertions(+) create mode 100644 .gitignore create mode 100644 Cargo.toml create mode 100644 LICENSE-APACHE create mode 100644 LICENSE-MIT create mode 100644 README.md create mode 100644 ff_derive/Cargo.toml create mode 100644 ff_derive/src/lib.rs create mode 100644 src/lib.rs diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..4308d82 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +target/ +**/*.rs.bk +Cargo.lock diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..e687109 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,8 @@ +[package] +name = "ff" +version = "0.1.0" +authors = ["Sean Bowe "] + +[dependencies] +rand = "0.3" +ff_derive = { version = "0.1.0", path = "ff_derive" } diff --git a/LICENSE-APACHE b/LICENSE-APACHE new file mode 100644 index 0000000..1e5006d --- /dev/null +++ b/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/LICENSE-MIT b/LICENSE-MIT new file mode 100644 index 0000000..ed3a13f --- /dev/null +++ b/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/README.md b/README.md new file mode 100644 index 0000000..d9dfc76 --- /dev/null +++ b/README.md @@ -0,0 +1,51 @@ +# ff + +`ff` is a finite field library written in pure Rust, with no `unsafe{}` code. This library relies on Rust's `i128_type` feature, which is currently only available in the nightly compiler. + +## Disclaimers + +* This library does not provide constant-time guarantees. +* This library relies on Rust's `i128_type` feature, which is currently only available in the nightly compiler. + +## Usage + +Add the `ff` crate to your `Cargo.toml`: + +```toml +[dependencies] +ff = "0.1" +``` + +The `ff` crate contains `Field`, `PrimeField`, `PrimeFieldRepr` and `SqrtField` traits. See the **[documentation](http)** 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. It's very easy to use, after you've added it to your `Cargo.toml`. + +```rust +extern crate rand; +#[macro_use] +extern crate ff; + +#[derive(PrimeField)] +#[PrimeFieldModulus = "57896044618658097711785492504343953926634992332820282019728792003956564819949"] +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_derive/Cargo.toml b/ff_derive/Cargo.toml new file mode 100644 index 0000000..c61953a --- /dev/null +++ b/ff_derive/Cargo.toml @@ -0,0 +1,13 @@ +[package] +name = "ff_derive" +version = "0.1.0" +authors = ["Sean Bowe "] + +[lib] +proc-macro = true + +[dependencies] +syn = "0.11" +quote = "0.3" +num-bigint = "0.1" +num-traits = "0.1" diff --git a/ff_derive/src/lib.rs b/ff_derive/src/lib.rs new file mode 100644 index 0000000..740cda2 --- /dev/null +++ b/ff_derive/src/lib.rs @@ -0,0 +1,111 @@ +extern crate proc_macro; +//extern crate syn; +//#[macro_use] +extern crate quote; + +//extern crate num_bigint; +//extern crate num_traits; + +//use num_traits::{Zero, One, ToPrimitive}; +//use num_bigint::BigUint; + +#[proc_macro_derive(PrimeField, attributes(PrimeFieldModulus))] +pub fn prime_field( + _: proc_macro::TokenStream +) -> proc_macro::TokenStream +{ + /* + // Construct a string representation of the type definition + let s = input.to_string(); + + // Parse the string representation + let ast = syn::parse_derive_input(&s).unwrap(); + + // The struct we're deriving for is a wrapper around a "Repr" type we must construct. + let repr_ident = fetch_wrapped_ident(&ast.body) + .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"); + + // 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; + while cur < mod2 { + limbs += 1; + cur = cur << 64; + } + } + */ + + let gen = quote::Tokens::new(); + + //gen.append(prime_field_repr_impl(&repr_ident, limbs)); + //gen.append(prime_field_constants(&repr_ident, modulus, limbs)); + //gen.append(prime_field_impl(&ast.ident, &repr_ident)); + //gen.append(prime_field_arith_impl(&ast.ident, &repr_ident, limbs)); + + // Return the generated impl + gen.parse().unwrap() +} + +/* +fn fetch_wrapped_ident( + body: &syn::Body +) -> Option +{ + match body { + &syn::Body::Struct(ref variant_data) => { + let fields = variant_data.fields(); + if fields.len() == 1 { + match fields[0].ty { + syn::Ty::Path(_, ref path) => { + if path.segments.len() == 1 { + return Some(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 attr.name() == name { + match attr.value { + syn::MetaItem::NameValue(_, ref val) => { + match val { + &syn::Lit::Str(ref s, _) => { + return Some(s.clone()) + }, + _ => { + panic!("attribute {} should be a string", name); + } + } + }, + _ => { + panic!("attribute {} should be a string", name); + } + } + } + } + + None +} +*/ diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 0000000..bd76b93 --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,235 @@ +#![feature(i128_type)] + +extern crate rand; + +//#[macro_use] +//extern crate ff_derive; + +//pub use ff_derive::*; + +use std::fmt; + +/// This trait represents an element of a field. +pub trait Field: Sized + + Eq + + Copy + + Clone + + Send + + Sync + + fmt::Debug + + '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 modulus. + 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(); + + for i in BitIterator::new(exp) { + res.square(); + 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 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 + + fmt::Debug + + 'static + + rand::Rand + + AsRef<[u64]> + + From +{ + /// Subtract another reprensetation from this one. Underflow is ignored. + fn sub_noborrow(&mut self, other: &Self); + + /// Add another representation to this one. Overflow is ignored. + fn add_nocarry(&mut self, other: &Self); + + /// Compute the number of bits needed to encode this number. + fn num_bits(&self) -> usize; + + /// 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 leftwise bitshift of this number, effectively multiplying + /// it by 2. Overflow is ignored. + fn mul2(&mut self); +} + +/// This represents an element of a prime field. +pub trait PrimeField: SqrtField +{ + /// The prime field can be converted back and forth into this biginteger + /// representation. + type Repr: PrimeFieldRepr; + + /// Convert this prime field element into a biginteger representation. + fn from_repr(Self::Repr) -> Result; + + /// Convert a biginteger reprensentation 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; + + /// Returns how many bits are needed to represent an element of this + /// field. + fn num_bits() -> usize; + + /// Returns how many bits of information can be reliably stored in the + /// field element. + fn capacity() -> usize; +} + +pub struct BitIterator { + t: E, + n: usize +} + +impl> BitIterator { + fn new(t: E) -> Self { + let n = t.as_ref().len() * 64; + + BitIterator { + t: t, + n: 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()); +} + +/// 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) + (a as u128) - (b as u128) - (*borrow as u128); + + *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 = (a as u128) + (b as u128) + (*carry as u128); + + *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 = (a as u128) + (b as u128) * (c as u128) + (*carry as u128); + + *carry = (tmp >> 64) as u64; + + tmp as u64 +}