Skip to main content

ff_derive_num/
lib.rs

1// Copyright 2021 Riad S. Wahby <rsw@cs.stanford.edu>
2//
3// This file is part of ff-derive-num
4//
5// Licensed under EITHER:
6//
7// - The Apache License, Version 2.0 (see LICENSE-apache or
8//   https://www.apache.org/licenses/LICENSE-2.0).
9//
10// - The MIT License (see LICENSE-mit or
11//   https://opensource.org/licenses/MIT).
12//
13// This file may not be copied, modified, or distributed
14// except according to the terms of ONE of these licenses,
15// at your discretion.
16#![deny(missing_docs)]
17
18/*! Derive ::num_traits::Num and associated traits for ::ff::Field types derived using ::ff_derive
19
20# example
21
22```rust
23use ff::PrimeField;         // ff should be used with the "derive" feature!
24use ff_derive_num::Num;
25
26#[derive(PrimeField,Num)]
27#[PrimeFieldModulus = "70386805592835581672624750593"]
28#[PrimeFieldGenerator = "17"]
29#[PrimeFieldReprEndianness = "little"]
30pub struct Ft([u64; 2]);
31```
32*/
33
34use quote::quote;
35use syn::DeriveInput;
36
37/// Proc macro for Num derivation
38#[proc_macro_derive(Num)]
39pub fn num_traits_num(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
40    let ast: DeriveInput = syn::parse(input).unwrap();
41
42    let ident = ast.ident;
43    let mut toks = proc_macro2::TokenStream::new();
44    toks.extend(quote! {
45        impl ::num_traits::Num for #ident {
46            type FromStrRadixErr = ::std::num::ParseIntError;
47
48            fn from_str_radix(s: &str, r: u32)-> Result<Self, Self::FromStrRadixErr> {
49                if s.is_empty() {
50                    // hack
51                    return Err(u32::from_str_radix(s, r).err().unwrap());
52                }
53
54                if s == "0" {
55                    return Ok(<Self as ::ff::Field>::zero());
56                }
57
58                let mut res = <Self as ::ff::Field>::zero();
59                let radix = Self::from(r as u64);
60                let mut first_digit = true;
61                for c in s.chars() {
62                    match c.to_digit(r) {
63                        Some(c) => {
64                            if first_digit {
65                                if c == 0 {
66                                    return Err(u32::from_str_radix("3", 2).err().unwrap());
67                                }
68                                first_digit = false;
69                            }
70
71                            res *= &radix;
72                            res += Self::from(c as u64);
73                        }
74                        None => {
75                            return Err(u32::from_str_radix("3", 2).err().unwrap());
76                        }
77                    }
78                }
79                Ok(res)
80            }
81        }
82
83        impl ::num_traits::Zero for #ident {
84            fn zero() -> Self {
85                <Self as ::ff::Field>::zero()
86            }
87
88            fn is_zero(&self) -> bool {
89                bool::from(<Self as ::ff::Field>::is_zero(self))
90            }
91        }
92
93        impl ::num_traits::One for #ident {
94            fn one() -> Self {
95                <Self as ::ff::Field>::one()
96            }
97
98            fn is_one(&self) -> bool {
99                self == &<Self as ::ff::Field>::one()
100            }
101        }
102
103        #[allow(clippy::suspicious_arithmetic_impl)]
104        impl ::std::ops::Div<#ident> for #ident {
105            type Output = Self;
106
107            #[must_use]
108            fn div(self, rhs: Self) -> Self {
109                use ::ff::Field;
110                self * <Self as ::ff::Field>::invert(&rhs).unwrap()
111            }
112        }
113
114        #[allow(clippy::suspicious_arithmetic_impl)]
115        impl ::std::ops::Div<&#ident> for #ident {
116            type Output = Self;
117
118            fn div(self, rhs: &Self) -> Self {
119                self * <Self as ::ff::Field>::invert(rhs).unwrap()
120            }
121        }
122
123        impl ::std::ops::Rem<#ident> for #ident {
124            type Output = Self;
125
126            #[must_use]
127            fn rem(self, rhs: Self) -> Self {
128                if bool::from(<Self as ::ff::Field>::is_zero(&self)) {
129                    panic!("divide by zero");
130                }
131
132                <Self as ::ff::Field>::zero()
133            }
134        }
135
136        impl ::std::ops::Rem<&#ident> for #ident {
137            type Output = Self;
138
139            #[must_use]
140            fn rem(self, rhs: &Self) -> Self {
141                if bool::from(<Self as ::ff::Field>::is_zero(&self)) {
142                    panic!("divide by zero");
143                }
144
145                <Self as ::ff::Field>::zero()
146            }
147        }
148
149        impl ::num_traits::ops::mul_add::MulAdd for #ident {
150            type Output = Self;
151
152            fn mul_add(mut self, a: Self, b: Self) -> Self {
153                self *= &a;
154                self += &b;
155                self
156            }
157        }
158
159        impl ::num_traits::ops::mul_add::MulAdd<&#ident, &#ident> for #ident {
160            type Output = Self;
161
162            fn mul_add(mut self, a: &Self, b: &Self) -> Self {
163                self *= a;
164                self += b;
165                self
166            }
167        }
168    });
169
170    toks.into()
171}