Home Manual Reference Source Test Repository

src/SHA512_Hasher.js

import { sha512_initial_state , sha512_call } from './sha512' ;

import { copy } from '@aureooms/js-array' ;
import { NotImplementedError } from '@aureooms/js-error' ;

export class SHA512_Hasher {

	constructor ( ) {

		this.state = sha512_initial_state() ;
		this.total_bits = 0 ;
		this.buffer = new ArrayBuffer(128) ;
		this.buffer_bits = 0 ;

	}

	update ( bytes , offset = 0 , length = bytes.length - offset ) {

		if ( this.buffer_bits & 0xFFF !== 0 ) {
			throw NotImplementedError('Cannot add bytes to bits (for now).') ;
		}

		this.total_bits += length << 3 ;

		const buffer_bytes = this.buffer_bits >> 3 ;

		if ( buffer_bytes > 0 ) {

			const buffer_complement = 128 - buffer_bytes ;

			if ( length < buffer_complement ) {
				// buffer is not full
				copy( bytes , offset , offset + length , this.buffer , buffer_bytes ) ;
				this.buffer_bits += length << 3 ;
				return ;
			}

			else {
				// pad buffer with head of bytes and process it
				copy( bytes , offset , offset + buffer_complement , this.buffer , buffer_bytes ) ;
				sha512_call(this.state, this.buffer, 0);
				this.buffer_bits = 0 ;
				offset += buffer_complement ;
				length -= buffer_complement ;
			}

		}

		const full_blocks = length >> 7 ;

		for ( let i = 0 ; i < full_blocks ; ++i ) {
			sha512_call(this.state, bytes, offset);
			offset += 128 ;
			length -= 128 ;
		}

		copy( bytes , offset , offset + length , this.buffer , 0 ) ;
		this.buffer_bits = length << 3 ;

	}

	digest ( ) {
		const digest = new ArrayBuffer(64);
		return sha512_finalize(this.buffer, this.total_bits, digest, this.buffer_bits >> 3, 0, this.buffer_bits, this.state);
	}

}