From 056a13b95f4b971a9ae2c6fbb5fbc9f1e4f4828e Mon Sep 17 00:00:00 2001 From: Alex Vlasov Date: Wed, 9 Jan 2019 20:32:39 +0200 Subject: [PATCH] add serde serialization/deserialization as de-facto rust standard --- Cargo.toml | 14 ++++++--- README.md | 2 +- ff_derive/Cargo.toml | 11 ++++--- ff_derive/src/lib.rs | 73 ++++++++++++++++++++++++++++++++++++++++++-- src/lib.rs | 3 ++ 5 files changed, 91 insertions(+), 12 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 22db67a..d9e8e45 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,18 +1,22 @@ [package] name = "ff" -version = "0.4.0" -authors = ["Sean Bowe "] +version = "0.5.0" +authors = ["Sean Bowe ", + "Alex Gluchowski ", + "Alex Vlasov "] description = "Library for building and interfacing with finite fields" documentation = "https://docs.rs/ff/" -homepage = "https://github.com/ebfull/ff" +homepage = "https://github.com/matterinc/ff" license = "MIT/Apache-2.0" -repository = "https://github.com/ebfull/ff" +repository = "https://github.com/matterinc/ff" [dependencies] byteorder = "1" rand = "0.4" -ff_derive = { version = "0.3.0", path = "ff_derive", optional = true } +ff_derive = { version = "0.4.0", path = "ff_derive", optional = true } +#ff_asm = { version = "0.0.1", path = "ff_asm", optional = true } [features] default = [] derive = ["ff_derive"] +#asm = ["ff_asm"] diff --git a/README.md b/README.md index 3efef94..da1b5ec 100644 --- a/README.md +++ b/README.md @@ -25,7 +25,7 @@ First, enable the `derive` crate feature: ```toml [dependencies] -ff = { version = "0.4", features = ["derive"] } +ff = { path = "../ff", features = ["derive"] } ``` And then use the macro like so: diff --git a/ff_derive/Cargo.toml b/ff_derive/Cargo.toml index 914e392..96ded76 100644 --- a/ff_derive/Cargo.toml +++ b/ff_derive/Cargo.toml @@ -1,12 +1,14 @@ [package] name = "ff_derive" -version = "0.3.0" -authors = ["Sean Bowe "] +version = "0.4.0" +authors = ["Sean Bowe ", + "Alex Gluchowski ", + "Alex Vlasov "] description = "Procedural macro library used to build custom prime field implementations" documentation = "https://docs.rs/ff/" -homepage = "https://github.com/ebfull/ff" +homepage = "https://github.com/matterinc/ff" license = "MIT/Apache-2.0" -repository = "https://github.com/ebfull/ff" +repository = "https://github.com/matterinc/ff" [lib] proc-macro = true @@ -18,3 +20,4 @@ num-integer = "0.1" proc-macro2 = "0.4" quote = "0.6" syn = "0.14" +serde_derive = "1.0.80" diff --git a/ff_derive/src/lib.rs b/ff_derive/src/lib.rs index 45d3445..5cad7c2 100644 --- a/ff_derive/src/lib.rs +++ b/ff_derive/src/lib.rs @@ -6,6 +6,8 @@ extern crate syn; #[macro_use] extern crate quote; +extern crate serde_derive; + extern crate num_bigint; extern crate num_integer; extern crate num_traits; @@ -121,8 +123,12 @@ fn fetch_attr(name: &str, attrs: &[syn::Attribute]) -> Option { // 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]); + + #[derive(Copy, Clone, PartialEq, Eq, Default, Serialize, Deserialize)] + pub struct #repr( + //#[serde(with = "SerHex::")] + pub [u64; #limbs] + ); impl ::std::fmt::Debug for #repr { @@ -901,6 +907,7 @@ fn prime_field_impl( fn root_of_unity() -> Self { #name(ROOT_OF_UNITY) } + } impl ::ff::Field for #name { @@ -1029,6 +1036,12 @@ fn prime_field_impl( } } + impl std::default::Default for #name { + fn default() -> Self { + Self::zero() + } + } + impl #name { /// Determines if the element is really in the field. This is only used /// internally. @@ -1060,6 +1073,62 @@ fn prime_field_impl( self.reduce(); } + + pub fn to_hex(&self) -> String { + let mut buf: Vec = vec![]; + self.into_repr().write_be(&mut buf).unwrap(); + hex::encode(&buf) + } + + pub fn from_hex(value: &str) -> Result<#name, String> { + let value = if value.starts_with("0x") { &value[2..] } else { value }; + if value.len() % 2 != 0 {return Err(format!("hex length must be even for full byte encoding: {}", value))} + let mut buf = hex::decode(&value).map_err(|_| format!("could not decode hex: {}", value))?; + buf.reverse(); + buf.resize(#limbs * 8, 0); + let mut repr = #repr::default(); + repr.read_le(&buf[..]).map_err(|e| format!("could not read {}: {}", value, &e))?; + #name::from_repr(repr).map_err(|e| format!("could not convert into prime field: {}: {}", value, &e)) + } + } + + impl serde::Serialize for #name { + fn serialize(&self, serializer: S) -> Result + where + S: serde::Serializer, + { + serializer.serialize_str(&format!("0x{}", &self.to_hex())) + } + } + + use std::fmt; + + use serde::de::{self, Visitor}; + + struct FrVisitor; + + impl<'de> Visitor<'de> for FrVisitor { + type Value = #name; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("a hex string with prefix: 0x012ab...") + } + + fn visit_str(self, value: &str) -> Result + where + E: de::Error, + { + #name::from_hex(&value[2..]).map_err(|e| E::custom(e)) + } + } + + impl<'de> serde::Deserialize<'de> for #name { + fn deserialize(deserializer: D) -> Result<#name, D::Error> + where + D: serde::Deserializer<'de>, + { + deserializer.deserialize_str(FrVisitor) + } } } } diff --git a/src/lib.rs b/src/lib.rs index a9d117f..35c5437 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -10,6 +10,9 @@ extern crate ff_derive; #[cfg(feature = "derive")] pub use ff_derive::*; +// #[cfg(feature = "asm")] +// pub use ff_asm::*; + use std::error::Error; use std::fmt; use std::io::{self, Read, Write};