Procedural macro for fixed-exponent variable-base modular exponentiation

Uses the addchain crate to obtain an addition chain for the exponent,
and then generates the corresponding constant-time square-and-multiply
algorithm.
This commit is contained in:
Jack Grigg 2019-12-19 22:10:10 -06:00
parent 2df2a2b2f2
commit 232fb4b7a3
4 changed files with 75 additions and 1 deletions

12
Cargo.lock generated
View File

@ -1,5 +1,15 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
[[package]]
name = "addchain"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"num-bigint 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
"num-integer 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)",
"num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "aes"
version = "0.3.2"
@ -467,6 +477,7 @@ dependencies = [
name = "ff_derive"
version = "0.6.0"
dependencies = [
"addchain 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"num-bigint 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
"num-integer 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)",
"num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
@ -1298,6 +1309,7 @@ dependencies = [
]
[metadata]
"checksum addchain 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1177222c93a7bb492002e9a3cd947c7fd869e085d6e81a9e415ff1be65b3489c"
"checksum aes 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "54eb1d8fe354e5fc611daf4f2ea97dd45a765f4f1e4512306ec183ae2e8f20c9"
"checksum aes-soft 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "cfd7e7ae3f9a1fb5c03b389fc6bb9a51400d0c13053f0dca698c832bfd893a0d"
"checksum aesni 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2f70a6b5f971e473091ab7cfb5ffac6cde81666c4556751d8d5620ead8abf100"

View File

@ -1,7 +1,10 @@
[package]
name = "ff_derive"
version = "0.6.0"
authors = ["Sean Bowe <ewillbefull@gmail.com>"]
authors = [
"Sean Bowe <ewillbefull@gmail.com>",
"Jack Grigg <thestr4d@gmail.com>",
]
description = "Procedural macro library used to build custom prime field implementations"
documentation = "https://docs.rs/ff/"
homepage = "https://github.com/ebfull/ff"
@ -13,6 +16,7 @@ edition = "2018"
proc-macro = true
[dependencies]
addchain = "0.1"
num-bigint = "0.2"
num-traits = "0.2"
num-integer = "0.1"

View File

@ -10,6 +10,8 @@ use quote::quote;
use quote::TokenStreamExt;
use std::str::FromStr;
mod pow_fixed;
#[proc_macro_derive(PrimeField, attributes(PrimeFieldModulus, PrimeFieldGenerator))]
pub fn prime_field(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
// Parse the type definition

View File

@ -0,0 +1,56 @@
//! Fixed-exponent variable-base exponentiation using addition chains.
use addchain::{build_addition_chain, Step};
use num_bigint::BigUint;
use quote::quote;
use syn::Ident;
/// Returns t{n} as an ident.
fn get_temp(n: usize) -> Ident {
Ident::new(&format!("t{}", n), proc_macro2::Span::call_site())
}
pub(crate) fn generate(
base: &proc_macro2::TokenStream,
exponent: BigUint,
) -> proc_macro2::TokenStream {
let steps = build_addition_chain(exponent);
let mut gen = proc_macro2::TokenStream::new();
// First entry in chain is one, i.e. the base.
let start = get_temp(0);
gen.extend(quote! {
let #start = #base;
});
let mut tmps = vec![start];
for (i, step) in steps.into_iter().enumerate() {
let out = get_temp(i + 1);
gen.extend(match step {
Step::Double { index } => {
let val = &tmps[index];
quote! {
let #out = #val.square();
}
}
Step::Add { left, right } => {
let left = &tmps[left];
let right = &tmps[right];
quote! {
let #out = #left * #right;
}
}
});
tmps.push(out.clone());
}
let end = tmps.last().expect("have last");
gen.extend(quote! {
#end
});
gen
}