| /* |
| 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 xxx::big; |
| use xxx::big::BIG; |
| use xxx::dbig::DBIG; |
| use xxx::rom; |
| use arch::Chunk; |
| use arch; |
| |
| //#[cfg(D32)] |
| //use arch::DChunk; |
| |
| #[derive(Copy, Clone)] |
| pub struct FP { |
| pub x:BIG, |
| pub xes:i32 |
| } |
| |
| pub const NOT_SPECIAL:usize =0; |
| pub const PSEUDO_MERSENNE:usize=1; |
| pub const MONTGOMERY_FRIENDLY:usize=2; |
| pub const GENERALISED_MERSENNE:usize=3; |
| |
| pub const MODBITS:usize = @NBT@; /* Number of bits in Modulus */ |
| pub const MOD8: usize = @M8@; /* Modulus mod 8 */ |
| pub const MODTYPE:usize=@MT@; |
| |
| pub const FEXCESS:i32 = (((1 as i32)<<@SH@)-1); |
| pub const OMASK:Chunk = (-1)<<(MODBITS%big::BASEBITS); |
| pub const TBITS:usize=MODBITS%big::BASEBITS; // Number of active bits in top word |
| pub const TMASK:Chunk=(1<<TBITS)-1; |
| |
| |
| impl FP { |
| |
| /* Constructors */ |
| pub fn new() -> FP { |
| FP { |
| x: BIG::new(), |
| xes:1 |
| } |
| } |
| |
| 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)); |
| f.xes=y.xes; |
| 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 MODTYPE != PSEUDO_MERSENNE && MODTYPE != GENERALISED_MERSENNE { |
| let r=BIG::new_ints(&rom::R2MODP); |
| let mut d=BIG::mul(&(self.x),&r); |
| self.x.copy(&FP::modulo(&mut d)); |
| self.xes=2; |
| } else { |
| self.xes=1; |
| } |
| |
| } |
| |
| /* convert back to regular form */ |
| pub fn redc(&mut self) -> BIG { |
| if MODTYPE != PSEUDO_MERSENNE && MODTYPE != GENERALISED_MERSENNE { |
| let mut d=DBIG::new_scopy(&(self.x)); |
| return FP::modulo(&mut d); |
| } else { |
| let r=BIG::new_copy(&(self.x)); |
| return r; |
| } |
| } |
| |
| |
| /* reduce a DBIG to a BIG using the appropriate form of the modulus */ |
| /* dd */ |
| pub fn modulo(d: &mut DBIG) -> BIG { |
| |
| if MODTYPE==PSEUDO_MERSENNE { |
| let mut b=BIG::new(); |
| let mut t=d.split(MODBITS); |
| b.dcopy(&d); |
| let v=t.pmul(rom::MCONST as isize); |
| |
| t.add(&b); |
| t.norm(); |
| |
| |
| let tw=t.w[big::NLEN-1]; |
| t.w[big::NLEN-1] &= TMASK; |
| t.w[0]+=rom::MCONST*((tw>>TBITS)+(v<<(big::BASEBITS-TBITS))); |
| t.norm(); |
| return t; |
| } |
| |
| if MODTYPE==MONTGOMERY_FRIENDLY |
| { |
| let mut b=BIG::new(); |
| for i in 0 ..big::NLEN { |
| let x=d.w[i]; |
| |
| let tuple=BIG::muladd(x,rom::MCONST-1,x,d.w[big::NLEN+i-1]); |
| d.w[big::NLEN+i]+=tuple.0; d.w[big::NLEN+i-1]=tuple.1; |
| } |
| |
| b.zero(); |
| |
| for i in 0 ..big::NLEN { |
| b.w[i]=d.w[big::NLEN+i]; |
| } |
| b.norm(); |
| return b; |
| } |
| |
| if MODTYPE==GENERALISED_MERSENNE |
| { // GoldiLocks Only |
| let mut b=BIG::new(); |
| let t=d.split(MODBITS); |
| let rm2=(MODBITS/2) as usize; |
| b.dcopy(&d); |
| b.add(&t); |
| let mut dd=DBIG::new_scopy(&t); |
| dd.shl(rm2); |
| |
| let mut tt=dd.split(MODBITS); |
| let lo=BIG::new_dcopy(&dd); |
| b.add(&tt); |
| b.add(&lo); |
| b.norm(); |
| tt.shl(rm2); |
| b.add(&tt); |
| |
| let carry=b.w[big::NLEN-1]>>TBITS; |
| b.w[big::NLEN-1]&=TMASK; |
| b.w[0]+=carry; |
| |
| b.w[(224/big::BASEBITS) as usize]+=carry<<(224%big::BASEBITS); |
| b.norm(); |
| return b; |
| } |
| |
| if MODTYPE==NOT_SPECIAL { |
| let m = BIG::new_ints(&rom::MODULUS); |
| return BIG::monty(&m,rom::MCONST,d); |
| } |
| return BIG::new(); |
| } |
| |
| /* convert to string */ |
| pub fn tostring(&mut self) -> String { |
| let s=self.redc().tostring(); |
| return s; |
| } |
| |
| /* reduce this mod Modulus */ |
| pub fn reduce(&mut self) { |
| let mut m = BIG::new_ints(&rom::MODULUS); |
| let mut r = BIG::new_copy(&m); |
| let mut sb : usize; |
| self.x.norm(); |
| if self.xes>16 { |
| let q=FP::quo(&self.x,&m); |
| let carry=r.pmul(q); |
| r.w[big::NLEN-1]+=carry<<big::BASEBITS; // correction - put any carry out back in again |
| self.x.sub(&r); |
| self.x.norm(); |
| sb=2; |
| } else { |
| sb=FP::logb2((self.xes-1) as u32); |
| } |
| m.fshl(sb); |
| |
| while sb>0 { |
| let sr=BIG::ssn(&mut r,&self.x,&mut m); |
| self.x.cmove(&r,1-sr); |
| sb=sb-1; |
| } |
| |
| self.xes=1; |
| } |
| |
| /* test this=0? */ |
| pub fn iszilch(&self) -> bool { |
| let mut a=FP::new_copy(self); |
| a.reduce(); |
| return a.x.iszilch(); |
| } |
| |
| /* copy from FP b */ |
| pub fn copy(&mut self,b: &FP) { |
| self.x.copy(&(b.x)); |
| self.xes=b.xes; |
| } |
| |
| /* 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(); |
| self.xes=1; |
| } |
| |
| /* 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); |
| let mut c=d as i32; |
| c=!(c-1); |
| let t=c&(self.xes^b.xes); |
| self.xes^=t; |
| b.xes^=t; |
| } |
| |
| /* copy FPs depending on d */ |
| pub fn cmove(&mut self,b: &FP,d: isize) { |
| self.x.cmove(&(b.x),d); |
| let c=d as i32; |
| self.xes^=(self.xes^b.xes)&(-c); |
| } |
| |
| /* this*=b mod Modulus */ |
| pub fn mul(&mut self,b: &FP) |
| { |
| if (self.xes as i64)*(b.xes as i64) > FEXCESS as i64 {self.reduce()} |
| |
| let mut d=BIG::mul(&(self.x),&(b.x)); |
| self.x.copy(&FP::modulo(&mut d)); |
| self.xes=2; |
| } |
| |
| 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; |
| } |
| |
| // find appoximation to quotient of a/m |
| // Out by at most 2. |
| // Note that MAXXES is bounded to be 2-bits less than half a word |
| fn quo(n: &BIG,m: &BIG) -> isize { |
| let hb=arch::CHUNK/2; |
| |
| if TBITS < hb { |
| let sh=hb-TBITS; |
| let num=((n.w[big::NLEN-1]<<sh))|(n.w[big::NLEN-2]>>(big::BASEBITS-sh)); |
| let den=((m.w[big::NLEN-1]<<sh))|(m.w[big::NLEN-2]>>(big::BASEBITS-sh)); |
| return (num/(den+1)) as isize; |
| } else { |
| let num=n.w[big::NLEN-1]; |
| let den=m.w[big::NLEN-1]; |
| return (num/(den+1)) as isize; |
| } |
| } |
| |
| /* this = -this mod Modulus */ |
| pub fn neg(&mut self) { |
| let mut p = BIG::new_ints(&rom::MODULUS); |
| let sb=FP::logb2((self.xes-1) as u32); |
| |
| p.fshl(sb); |
| self.x.rsub(&p); |
| self.xes=1<<(sb as i32)+1; |
| if self.xes>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; |
| } |
| |
| if MODTYPE==PSEUDO_MERSENNE || MODTYPE==GENERALISED_MERSENNE { |
| let mut d=self.x.pxmul(cc); |
| self.x.copy(&FP::modulo(&mut d)); |
| self.xes=2 |
| } else { |
| if self.xes*(cc as i32) <= FEXCESS { |
| self.x.pmul(cc); |
| self.xes*=cc as i32; |
| } else { |
| let n=FP::new_int(cc); |
| self.mul(&n); |
| } |
| |
| } |
| |
| if s {self.neg(); self.norm();} |
| } |
| |
| /* self*=self mod Modulus */ |
| pub fn sqr(&mut self) { |
| // self.norm(); |
| if (self.xes as i64)*(self.xes as i64) > FEXCESS as i64 {self.reduce()} |
| |
| |
| let mut d=BIG::sqr(&(self.x)); |
| self.x.copy(&FP::modulo(&mut d)); |
| self.xes=2 |
| } |
| |
| /* self+=b */ |
| pub fn add(&mut self,b: &FP) { |
| self.x.add(&(b.x)); |
| self.xes+=b.xes; |
| if self.xes>FEXCESS {self.reduce()} |
| } |
| |
| /* self+=self */ |
| pub fn dbl(&mut self) { |
| self.x.dbl(); |
| self.xes+=self.xes; |
| if self.xes>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=b-self */ |
| pub fn rsub(&mut self,b: &FP) |
| { |
| self.neg(); |
| self.add(&b); |
| } |
| |
| /* 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); |
| } |
| } |
| |
| // return this^(p-3)/4 or this^(p-5)/8 |
| pub fn fpow(&mut self) -> FP { |
| let ac:[isize;11]=[1,2,3,6,12,15,30,60,120,240,255]; |
| let mut xp:[FP;11]=[FP::new(),FP::new(),FP::new(),FP::new(),FP::new(),FP::new(),FP::new(),FP::new(),FP::new(),FP::new(),FP::new()]; |
| // phase 1 |
| let mut t=FP::new(); |
| xp[0].copy(&self); // 1 |
| xp[1].copy(&self); xp[1].sqr(); // 2 |
| t.copy(&xp[1]); xp[2].copy(&t); xp[2].mul(&self); // 3 |
| t.copy(&xp[2]); xp[3].copy(&t); xp[3].sqr(); // 6 |
| t.copy(&xp[3]); xp[4].copy(&t); xp[4].sqr(); // 12 |
| t.copy(&xp[4]); t.mul(&xp[2]); xp[5].copy(&t); // 15 |
| t.copy(&xp[5]); xp[6].copy(&t); xp[6].sqr(); // 30 |
| t.copy(&xp[6]); xp[7].copy(&t); xp[7].sqr(); // 60 |
| t.copy(&xp[7]); xp[8].copy(&t); xp[8].sqr(); // 120 |
| t.copy(&xp[8]); xp[9].copy(&t); xp[9].sqr(); // 240 |
| t.copy(&xp[9]); t.mul(&xp[5]); xp[10].copy(&t); // 255 |
| |
| let n : isize; |
| let c : isize; |
| |
| if MOD8==5 { |
| n=(MODBITS as isize)-3; |
| c=((rom::MCONST as isize)+5)/8; |
| } else { |
| n=(MODBITS as isize)-2; |
| c=((rom::MCONST as isize)+3)/4; |
| |
| } |
| let mut bw=0; let mut w=1; while w<c {w*=2; bw+=1;} |
| let mut k=w-c; |
| |
| let mut i=10; let mut key=FP::new(); |
| if k != 0 { |
| while ac[i]>k {i-=1;} |
| key.copy(&xp[i]); |
| k-=ac[i]; |
| } |
| while k != 0 { |
| i-=1; |
| if ac[i]>k {continue;} |
| key.mul(&xp[i]); |
| k-=ac[i]; |
| } |
| // phase 2 |
| t.copy(&xp[2]); xp[1].copy(&t); |
| t.copy(&xp[5]); xp[2].copy(&t); |
| t.copy(&xp[10]); xp[3].copy(&t); |
| |
| let mut j=3; let mut m=8; |
| let nw=n-bw; |
| let mut r=FP::new(); |
| |
| while 2*m<nw { |
| t.copy(&xp[j]); j+=1; |
| for _ in 0..m {t.sqr();} |
| r.copy(&xp[j-1]); |
| r.mul(&t); |
| xp[j].copy(&r); |
| m*=2; |
| } |
| let mut lo=nw-m; |
| r.copy(&xp[j]); |
| |
| while lo != 0 { |
| m/=2; j-=1; |
| if lo<m {continue;} |
| lo-=m; |
| t.copy(&r); |
| for _ in 0..m {t.sqr();} |
| r.copy(&t); |
| r.mul(&xp[j]); |
| } |
| // phase 3 |
| for _ in 0..bw {r.sqr();} |
| |
| if w-c != 0 { |
| r.mul(&key); |
| } |
| return r; |
| } |
| /* self=1/self mod Modulus */ |
| pub fn inverse(&mut self) { |
| if MODTYPE==PSEUDO_MERSENNE { |
| let mut y=self.fpow(); |
| if MOD8==5 { |
| let mut t=FP::new_copy(self); |
| t.sqr(); |
| self.mul(&t); |
| y.sqr(); |
| } |
| y.sqr(); |
| y.sqr(); |
| self.mul(&y); |
| |
| } else { |
| let mut m2 = BIG::new_ints(&rom::MODULUS); |
| m2.dec(2); m2.norm(); |
| let inv=self.pow(&mut m2); |
| self.copy(&inv); |
| } |
| } |
| |
| /* return TRUE if self==a */ |
| pub fn equals(&self,a: &FP) -> bool { |
| let mut f=FP::new_copy(self); |
| let mut s=FP::new_copy(a); |
| f.reduce(); |
| s.reduce(); |
| if BIG::comp(&(f.x),&(s.x))==0 {return true} |
| return false; |
| } |
| |
| |
| /* return self^e mod Modulus */ |
| pub fn pow(&mut self,e: &mut BIG) -> FP { |
| let mut tb:[FP;16]=[FP::new(),FP::new(),FP::new(),FP::new(),FP::new(),FP::new(),FP::new(),FP::new(),FP::new(),FP::new(),FP::new(),FP::new(),FP::new(),FP::new(),FP::new(),FP::new()]; |
| const CT:usize=1+(big::NLEN*(big::BASEBITS as usize)+3)/4; |
| let mut w:[i8;CT]=[0;CT]; |
| |
| self.norm(); |
| let mut t=BIG::new_copy(e); |
| t.norm(); |
| let nb=1+(t.nbits()+3)/4; |
| |
| for i in 0..nb { |
| let lsbs=t.lastbits(4); |
| t.dec(lsbs); |
| t.norm(); |
| w[i]=lsbs as i8; |
| t.fshr(4); |
| } |
| tb[0].one(); |
| tb[1].copy(&self); |
| |
| let mut c=FP::new(); |
| for i in 2..16 { |
| c.copy(&tb[i-1]); |
| tb[i].copy(&c); |
| tb[i].mul(&self); |
| } |
| let mut r=FP::new_copy(&tb[w[nb-1] as usize]); |
| for i in (0..nb-1).rev() { |
| r.sqr(); |
| r.sqr(); |
| r.sqr(); |
| r.sqr(); |
| r.mul(&tb[w[i] as usize]) |
| } |
| r.reduce(); |
| return r; |
| } |
| |
| /* 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(&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(); |
| |
| if MOD8==5 { |
| let v : FP; |
| let mut i=FP::new_copy(self); i.x.shl(1); |
| if MODTYPE==PSEUDO_MERSENNE { |
| v=i.fpow(); |
| } else { |
| let mut p = BIG::new_ints(&rom::MODULUS); |
| p.dec(5); p.norm(); p.shr(3); |
| v=i.pow(&mut p); |
| } |
| i.mul(&v); i.mul(&v); |
| i.x.dec(1); |
| let mut r=FP::new_copy(self); |
| r.mul(&v); r.mul(&i); |
| r.reduce(); |
| return r; |
| } |
| else |
| { |
| let mut r : FP; |
| if MODTYPE==PSEUDO_MERSENNE { |
| r=self.fpow(); |
| r.mul(self); |
| } else { |
| let mut p = BIG::new_ints(&rom::MODULUS); |
| p.inc(1); p.norm(); p.shr(2); |
| r=self.pow(&mut p); |
| } |
| return r; |
| } |
| } |
| /* 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()); |
| } |
| */ |