/*
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.
*/

const HASH384_H0: u64=0xcbbb9d5dc1059ed8;
const HASH384_H1: u64=0x629a292a367cd507;
const HASH384_H2: u64=0x9159015a3070dd17;
const HASH384_H3: u64=0x152fecd8f70e5939;
const HASH384_H4: u64=0x67332667ffc00b31;
const HASH384_H5: u64=0x8eb44a8768581511;
const HASH384_H6: u64=0xdb0c2e0d64f98fa7;
const HASH384_H7: u64=0x47b5481dbefa4fa4;

const HASH384_K : [u64;80]=[
	0x428a2f98d728ae22,0x7137449123ef65cd,0xb5c0fbcfec4d3b2f,0xe9b5dba58189dbbc,
	0x3956c25bf348b538,0x59f111f1b605d019,0x923f82a4af194f9b,0xab1c5ed5da6d8118,
	0xd807aa98a3030242,0x12835b0145706fbe,0x243185be4ee4b28c,0x550c7dc3d5ffb4e2,
	0x72be5d74f27b896f,0x80deb1fe3b1696b1,0x9bdc06a725c71235,0xc19bf174cf692694,
	0xe49b69c19ef14ad2,0xefbe4786384f25e3,0x0fc19dc68b8cd5b5,0x240ca1cc77ac9c65,
	0x2de92c6f592b0275,0x4a7484aa6ea6e483,0x5cb0a9dcbd41fbd4,0x76f988da831153b5,
	0x983e5152ee66dfab,0xa831c66d2db43210,0xb00327c898fb213f,0xbf597fc7beef0ee4,
	0xc6e00bf33da88fc2,0xd5a79147930aa725,0x06ca6351e003826f,0x142929670a0e6e70,
	0x27b70a8546d22ffc,0x2e1b21385c26c926,0x4d2c6dfc5ac42aed,0x53380d139d95b3df,
	0x650a73548baf63de,0x766a0abb3c77b2a8,0x81c2c92e47edaee6,0x92722c851482353b,
	0xa2bfe8a14cf10364,0xa81a664bbc423001,0xc24b8b70d0f89791,0xc76c51a30654be30,
	0xd192e819d6ef5218,0xd69906245565a910,0xf40e35855771202a,0x106aa07032bbd1b8,
	0x19a4c116b8d2d0c8,0x1e376c085141ab53,0x2748774cdf8eeb99,0x34b0bcb5e19b48a8,
	0x391c0cb3c5c95a63,0x4ed8aa4ae3418acb,0x5b9cca4f7763e373,0x682e6ff3d6b2b8a3,
	0x748f82ee5defb2fc,0x78a5636f43172f60,0x84c87814a1f0ab72,0x8cc702081a6439ec,
	0x90befffa23631e28,0xa4506cebde82bde9,0xbef9a3f7b2c67915,0xc67178f2e372532b,
	0xca273eceea26619c,0xd186b8c721c0c207,0xeada7dd6cde0eb1e,0xf57d4f7fee6ed178,
	0x06f067aa72176fba,0x0a637dc5a2c898a6,0x113f9804bef90dae,0x1b710b35131c471b,
	0x28db77f523047d84,0x32caab7b40c72493,0x3c9ebe0a15c9bebc,0x431d67c49c100d4c,
	0x4cc5d4becb3e42b6,0x597f299cfc657e2a,0x5fcb6fab3ad6faec,0x6c44198c4a475817];


pub struct HASH384 {
	length: [u64;2],
	h: [u64;8],
	w: [u64;80]
}

impl HASH384 {
	fn s(n: u64,x: u64) -> u64 {
		return ((x)>>n) | ((x)<<(64-n));
	}
	fn r(n: u64,x: u64) -> u64 {
		return (x)>>n;
	}

	fn ch(x: u64,y: u64,z: u64) -> u64 {
		return (x&y)^(!(x)&z);
	}

	fn maj(x: u64,y: u64,z: u64) -> u64 {
		return (x&y)^(x&z)^(y&z);
	}

	fn sig0(x: u64) -> u64 {
		return HASH384::s(28,x)^HASH384::s(34,x)^HASH384::s(39,x);
	}

	fn sig1(x: u64) -> u64 {
		return HASH384::s(14,x)^HASH384::s(18,x)^HASH384::s(41,x);
	}

	fn theta0(x: u64) -> u64 {
		return HASH384::s(1,x)^HASH384::s(8,x)^HASH384::r(7,x);
	}

	fn theta1(x: u64) -> u64 {
		return HASH384::s(19,x)^HASH384::s(61,x)^HASH384::r(6,x);
	}

	fn transform(&mut self) { /* basic transformation step */
		for j in 16..80 {
			self.w[j]=HASH384::theta1(self.w[j-2])+self.w[j-7]+HASH384::theta0(self.w[j-15])+self.w[j-16];
		}
		let mut a=self.h[0]; let mut b=self.h[1]; let mut c=self.h[2]; let mut d=self.h[3]; 
		let mut e=self.h[4]; let mut f=self.h[5]; let mut g=self.h[6]; let mut hh=self.h[7];
		for j in 0..80 { /* 64 times - mush it up */
			let t1=hh+HASH384::sig1(e)+HASH384::ch(e,f,g)+HASH384_K[j]+self.w[j];
			let t2=HASH384::sig0(a)+HASH384::maj(a,b,c);
			hh=g; g=f; f=e;
			e=d+t1;
			d=c;
			c=b;
			b=a;
			a=t1+t2 ; 
		}
		self.h[0]+=a; self.h[1]+=b; self.h[2]+=c; self.h[3]+=d;
		self.h[4]+=e; self.h[5]+=f; self.h[6]+=g; self.h[7]+=hh; 
	} 	

/* Initialise Hash function */
	pub fn init(&mut self) { /* initialise */
		for i in 0..64 {self.w[i]=0}
		self.length[0]=0; self.length[1]=0;
		self.h[0]=HASH384_H0;
		self.h[1]=HASH384_H1;
		self.h[2]=HASH384_H2;
		self.h[3]=HASH384_H3;
		self.h[4]=HASH384_H4;
		self.h[5]=HASH384_H5;
		self.h[6]=HASH384_H6;
		self.h[7]=HASH384_H7;
	}	

	pub fn new() -> HASH384 {
		let mut nh=HASH384 {
			length: [0;2],
			h: [0;8],
			w: [0;80]
		};
		nh.init();
		return nh;
	}

/* process a single byte */
	pub fn process(&mut self,byt: u8) { /* process the next message byte */
		let cnt=((self.length[0]/64)%16) as usize;
		self.w[cnt]<<=8;
		self.w[cnt]|=(byt&0xFF) as u64;
		self.length[0]+=8;
		if self.length[0]==0 {self.length[1]+=1; self.length[0]=0}
		if (self.length[0]%1024)==0 {self.transform()}
	}

/* process an array of bytes */	
	pub fn process_array(&mut self,b: &[u8]) {
		for i in 0..b.len() {self.process((b[i]))}
	}

/* process a 32-bit integer */
	pub fn process_num(&mut self,n: i32) {
		self.process(((n>>24)&0xff) as u8);
		self.process(((n>>16)&0xff) as u8);
		self.process(((n>>8)&0xff) as u8);
		self.process((n&0xff) as u8);
	}

/* Generate 32-byte Hash */
	pub fn hash(&mut self) -> [u8;48] { /* pad message and finish - supply digest */
		let mut digest:[u8;48]=[0;48];
		let len0=self.length[0];
		let len1=self.length[1];
		self.process(0x80);
		while (self.length[0]%1024)!=896 {self.process(0)}
		self.w[14]=len1;
		self.w[15]=len0;    
		self.transform();
		for i in 0..48 { /* convert to bytes */
			digest[i]=((self.h[i/8]>>(8*(7-i%8))) & 0xff) as u8;
		}
		self.init();
		return digest;
	}
}

//09330c33f71147e8 3d192fc782cd1b47 53111b173b3b05d2 2fa08086e3b0f712 fcc7c71a557e2db9 66c3e9fa91746039
/*
fn main() {
	let s = String::from("abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu");	
	let test = s.into_bytes();
	let mut sh=HASH384::new();

	for i in 0..test.len(){
		sh.process(test[i]);
	}
		
	let digest=sh.hash();    
	for i in 0..48 {print!("{:02x}",digest[i])}
} */
