mirror of
https://github.com/Qortal/pirate-librustzcash.git
synced 2025-07-31 20:41:22 +00:00
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:
@@ -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"
|
||||
|
@@ -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
|
||||
|
56
ff/ff_derive/src/pow_fixed.rs
Normal file
56
ff/ff_derive/src/pow_fixed.rs
Normal 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
|
||||
}
|
Reference in New Issue
Block a user