blob: d9247535abbbfcb22727d5b9148de16df38e2908 [file] [log] [blame]
/*
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
*/
use std::fmt;
#[derive(Copy, Clone)]
pub struct FP {
x:BIG
}
use big::BIG;
use dbig::DBIG;
use rom;
use rom::{Chunk, BIG_HEX_STRING_LEN};
impl fmt::Display for FP {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "FP: [ {} ]", self.x)
}
}
impl fmt::Debug for FP {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "FP: [ {} ]", self.x)
}
}
impl PartialEq for FP {
fn eq(&self, other: &FP) -> bool {
return self.x == other.x;
}
}
impl FP {
/* Constructors */
pub fn new() -> FP {
FP {
x: BIG::new()
}
}
pub fn new_int(a:isize) -> FP {
let mut f=FP::new();
f.x.inc(a);
f.nres();
return f;
}
pub fn new_copy(y:&FP) -> FP {
let mut f=FP::new();
f.x.copy(&(y.x));
return f;
}
pub fn new_big(y:&BIG) -> FP {
let mut f=FP::new();
f.x.copy(y);
f.nres();
return f;
}
pub fn nres(&mut self) {
if rom::MODTYPE != rom::PSEUDO_MERSENNE && rom::MODTYPE != rom::GENERALISED_MERSENNE {
let p = BIG::new_ints(&rom::MODULUS);
let mut d=DBIG::new_scopy(&(self.x));
d.shl(rom::NLEN*(rom::BASEBITS as usize));
self.x.copy(&d.dmod(&p));
}
}
/* convert back to regular form */
pub fn redc(&mut self) -> BIG {
if rom::MODTYPE != rom::PSEUDO_MERSENNE && rom::MODTYPE != rom::GENERALISED_MERSENNE {
let mut d=DBIG::new_scopy(&(self.x));
return BIG::modulo(&mut d);
} else {
let r=BIG::new_copy(&(self.x));
return r;
}
}
/* convert to string */
pub fn tostring(&mut self) -> String {
let s=self.redc().tostring();
return s;
}
pub fn to_hex(&self) -> String {
let mut ret: String = String::with_capacity(2 * BIG_HEX_STRING_LEN);
let mut x = self.x;
ret.push_str(&format!("{}", x.to_hex()));
return ret;
}
pub fn from_hex(val: String) -> FP {
return FP {
x: BIG::from_hex(val)
}
}
/* reduce this mod Modulus */
pub fn reduce(&mut self) {
let p = BIG::new_ints(&rom::MODULUS);
self.x.rmod(&p)
}
/* test this=0? */
pub fn iszilch(&mut self) -> bool {
self.reduce();
return self.x.iszilch();
}
/* copy from FP b */
pub fn copy(&mut self,b: &FP) {
self.x.copy(&(b.x));
}
/* copy from BIG b */
pub fn bcopy(&mut self,b: &BIG) {
self.x.copy(&b);
self.nres();
}
/* set this=0 */
pub fn zero(&mut self) {
self.x.zero();
}
/* set this=1 */
pub fn one(&mut self) {
self.x.one(); self.nres()
}
/* normalise this */
pub fn norm(&mut self) {
self.x.norm();
}
/* swap FPs depending on d */
pub fn cswap(&mut self,b: &mut FP,d: isize) {
self.x.cswap(&mut (b.x),d);
}
/* copy FPs depending on d */
pub fn cmove(&mut self,b: &FP,d: isize) {
self.x.cmove(&(b.x),d);
}
/* this*=b mod Modulus */
pub fn mul(&mut self,b: &mut FP)
{
self.norm();
b.norm();
if BIG::pexceed(&(self.x),&(b.x)) {self.reduce()}
let mut d=BIG::mul(&(self.x),&(b.x));
self.x.copy(&BIG::modulo(&mut d))
}
fn logb2(w: u32) -> usize {
let mut v=w;
v |= v >> 1;
v |= v >> 2;
v |= v >> 4;
v |= v >> 8;
v |= v >> 16;
v = v - ((v >> 1) & 0x55555555);
v = (v & 0x33333333) + ((v >> 2) & 0x33333333);
let r= (( ((v + (v >> 4)) & 0xF0F0F0F).wrapping_mul(0x1010101)) >> 24) as usize;
return r+1;
}
/* this = -this mod Modulus */
pub fn neg(&mut self) {
let mut p = BIG::new_ints(&rom::MODULUS);
self.norm();
let sb=FP::logb2(BIG::excess(&(self.x)) as u32);
// let mut ov=BIG::excess(&(self.x));
// let mut sb=1; while ov != 0 {sb += 1;ov>>=1}
p.fshl(sb);
self.x.rsub(&p);
if BIG::excess(&(self.x))>=rom::FEXCESS {self.reduce()}
}
/* this*=c mod Modulus, where c is a small int */
pub fn imul(&mut self,c: isize) {
let mut cc=c;
self.norm();
let mut s=false;
if cc<0 {
cc = -cc;
s=true;
}
let afx=(BIG::excess(&(self.x))+1)*((cc as Chunk)+1)+1;
if cc<rom::NEXCESS && afx<rom::FEXCESS {
self.x.imul(cc);
} else {
if afx<rom::FEXCESS {
self.x.pmul(cc);
} else {
let p = BIG::new_ints(&rom::MODULUS);
let mut d=self.x.pxmul(cc);
self.x.copy(&d.dmod(&p));
}
}
if s {self.neg()}
self.norm();
}
/* self*=self mod Modulus */
pub fn sqr(&mut self) {
self.norm();
if BIG::sexceed(&(self.x)) {self.reduce()}
let mut d=BIG::sqr(&(self.x));
self.x.copy(&BIG::modulo(&mut d))
}
/* self+=b */
pub fn add(&mut self,b: &FP) {
self.x.add(&(b.x));
if BIG::excess(&(self.x))+2>=rom::FEXCESS {self.reduce()}
}
/* self+=self */
pub fn dbl(&mut self) {
self.x.dbl();
if BIG::excess(&(self.x))+2>=rom::FEXCESS {self.reduce()}
}
/* self-=b */
pub fn sub(&mut self,b: &FP)
{
let mut n=FP::new_copy(b);
n.neg();
self.add(&n);
}
/* self/=2 mod Modulus */
pub fn div2(&mut self) {
self.x.norm();
if self.x.parity()==0 {
self.x.fshr(1);
} else {
let p = BIG::new_ints(&rom::MODULUS);
self.x.add(&p);
self.x.norm();
self.x.fshr(1);
}
}
/* self=1/self mod Modulus */
pub fn inverse(&mut self) {
let mut p = BIG::new_ints(&rom::MODULUS);
let mut r=self.redc();
r.invmodp(&mut p);
self.x.copy(&r);
self.nres();
}
/* return TRUE if self==a */
pub fn equals(&mut self,a: &mut FP) -> bool {
a.reduce();
self.reduce();
if BIG::comp(&(a.x),(&self.x))==0 {return true}
return false;
}
/* return self^e mod Modulus */
pub fn pow(&mut self,e: &mut BIG) -> FP {
let p = BIG::new_ints(&rom::MODULUS);
let mut r=FP::new_int(1);
e.norm();
self.x.norm();
let mut m=FP::new_copy(self);
loop {
let bt=e.parity();
e.fshr(1);
if bt==1 {r.mul(&mut m)}
if e.iszilch() {break}
m.sqr();
}
r.x.rmod(&p);
return r;
}
/* return sqrt(this) mod Modulus */
pub fn sqrt(&mut self) -> FP {
self.reduce();
let mut p = BIG::new_ints(&rom::MODULUS);
if rom::MOD8==5 {
p.dec(5); p.norm(); p.shr(3);
let mut i=FP::new_copy(self); i.x.shl(1);
let mut v=i.pow(&mut p);
i.mul(&mut v); i.mul(&mut v);
i.x.dec(1);
let mut r=FP::new_copy(self);
r.mul(&mut v); r.mul(&mut i);
r.reduce();
return r;
}
else
{
p.inc(1); p.norm(); p.shr(2);
return self.pow(&mut p);
}
}
/* return jacobi symbol (this/Modulus) */
pub fn jacobi(&mut self) -> isize
{
let mut p = BIG::new_ints(&rom::MODULUS);
let mut w=self.redc();
return w.jacobi(&mut p);
}
}
/*
fn main() {
let p = BIG::new_ints(&rom::MODULUS);
let mut e = BIG::new_copy(&p);
e.dec(1);
let mut x = FP::new_int(3);
let mut s=x.pow(&mut e);
println!("s= {}",s.tostring());
}
*/