57 lines
1.4 KiB
Rust
57 lines
1.4 KiB
Rust
//! 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
|
|
}
|