From 232fb4b7a330ce07ce3783ced032420c745a0ab3 Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Thu, 19 Dec 2019 22:10:10 -0600 Subject: [PATCH] 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. --- Cargo.lock | 12 ++++++++ ff/ff_derive/Cargo.toml | 6 +++- ff/ff_derive/src/lib.rs | 2 ++ ff/ff_derive/src/pow_fixed.rs | 56 +++++++++++++++++++++++++++++++++++ 4 files changed, 75 insertions(+), 1 deletion(-) create mode 100644 ff/ff_derive/src/pow_fixed.rs diff --git a/Cargo.lock b/Cargo.lock index dcbed1f..4bfd9b3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -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" diff --git a/ff/ff_derive/Cargo.toml b/ff/ff_derive/Cargo.toml index 8c28a13..4adf28b 100644 --- a/ff/ff_derive/Cargo.toml +++ b/ff/ff_derive/Cargo.toml @@ -1,7 +1,10 @@ [package] name = "ff_derive" version = "0.6.0" -authors = ["Sean Bowe "] +authors = [ + "Sean Bowe ", + "Jack Grigg ", +] 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" diff --git a/ff/ff_derive/src/lib.rs b/ff/ff_derive/src/lib.rs index a69a2c0..af1ac58 100644 --- a/ff/ff_derive/src/lib.rs +++ b/ff/ff_derive/src/lib.rs @@ -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 diff --git a/ff/ff_derive/src/pow_fixed.rs b/ff/ff_derive/src/pow_fixed.rs new file mode 100644 index 0000000..1d2b37a --- /dev/null +++ b/ff/ff_derive/src/pow_fixed.rs @@ -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 +}