// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file // for details. All rights reserved. Use of this source code is governed by a // BSD-style license that can be found in the LICENSE file. import 'dart:convert'; import 'dart:typed_data'; import 'digest.dart'; import 'hash.dart'; import 'hash_sink.dart'; import 'utils.dart'; /// An implementation of the [SHA-1][rfc] hash function. /// /// [rfc]: http://tools.ietf.org/html/rfc3174 const Hash sha1 = _Sha1._(); /// An implementation of the [SHA-1][rfc] hash function. /// /// [rfc]: http://tools.ietf.org/html/rfc3174 class _Sha1 extends Hash { @override final int blockSize = 16 * bytesPerWord; const _Sha1._(); @override ByteConversionSink startChunkedConversion(Sink sink) => ByteConversionSink.from(_Sha1Sink(sink)); } /// The concrete implementation of `Sha1`. /// /// This is separate so that it can extend [HashSink] without leaking additional /// public members. class _Sha1Sink extends HashSink { @override final digest = Uint32List(5); /// The sixteen words from the original chunk, extended to 80 words. /// /// This is an instance variable to avoid re-allocating, but its data isn't /// used across invocations of [updateHash]. final Uint32List _extended; _Sha1Sink(Sink sink) : _extended = Uint32List(80), super(sink, 16) { digest[0] = 0x67452301; digest[1] = 0xEFCDAB89; digest[2] = 0x98BADCFE; digest[3] = 0x10325476; digest[4] = 0xC3D2E1F0; } @override void updateHash(Uint32List chunk) { assert(chunk.length == 16); var a = digest[0]; var b = digest[1]; var c = digest[2]; var d = digest[3]; var e = digest[4]; for (var i = 0; i < 80; i++) { if (i < 16) { _extended[i] = chunk[i]; } else { _extended[i] = rotl32( _extended[i - 3] ^ _extended[i - 8] ^ _extended[i - 14] ^ _extended[i - 16], 1, ); } var newA = add32(add32(rotl32(a, 5), e), _extended[i]); if (i < 20) { newA = add32(add32(newA, (b & c) | (~b & d)), 0x5A827999); } else if (i < 40) { newA = add32(add32(newA, b ^ c ^ d), 0x6ED9EBA1); } else if (i < 60) { newA = add32(add32(newA, (b & c) | (b & d) | (c & d)), 0x8F1BBCDC); } else { newA = add32(add32(newA, b ^ c ^ d), 0xCA62C1D6); } e = d; d = c; c = rotl32(b, 30); b = a; a = newA & mask32; } digest[0] = add32(a, digest[0]); digest[1] = add32(b, digest[1]); digest[2] = add32(c, digest[2]); digest[3] = add32(d, digest[3]); digest[4] = add32(e, digest[4]); } }