|  | // Copyright 2010 The Go Authors. All rights reserved. | 
|  | // Use of this source code is governed by a BSD-style | 
|  | // license that can be found in the LICENSE file. | 
|  |  | 
|  | // Package ripemd160 implements the RIPEMD-160 hash algorithm. | 
|  | package ripemd160 // import "golang.org/x/crypto/ripemd160" | 
|  |  | 
|  | // RIPEMD-160 is designed by by Hans Dobbertin, Antoon Bosselaers, and Bart | 
|  | // Preneel with specifications available at: | 
|  | // http://homes.esat.kuleuven.be/~cosicart/pdf/AB-9601/AB-9601.pdf. | 
|  |  | 
|  | import ( | 
|  | "crypto" | 
|  | "hash" | 
|  | ) | 
|  |  | 
|  | func init() { | 
|  | crypto.RegisterHash(crypto.RIPEMD160, New) | 
|  | } | 
|  |  | 
|  | // The size of the checksum in bytes. | 
|  | const Size = 20 | 
|  |  | 
|  | // The block size of the hash algorithm in bytes. | 
|  | const BlockSize = 64 | 
|  |  | 
|  | const ( | 
|  | _s0 = 0x67452301 | 
|  | _s1 = 0xefcdab89 | 
|  | _s2 = 0x98badcfe | 
|  | _s3 = 0x10325476 | 
|  | _s4 = 0xc3d2e1f0 | 
|  | ) | 
|  |  | 
|  | // digest represents the partial evaluation of a checksum. | 
|  | type digest struct { | 
|  | s  [5]uint32       // running context | 
|  | x  [BlockSize]byte // temporary buffer | 
|  | nx int             // index into x | 
|  | tc uint64          // total count of bytes processed | 
|  | } | 
|  |  | 
|  | func (d *digest) Reset() { | 
|  | d.s[0], d.s[1], d.s[2], d.s[3], d.s[4] = _s0, _s1, _s2, _s3, _s4 | 
|  | d.nx = 0 | 
|  | d.tc = 0 | 
|  | } | 
|  |  | 
|  | // New returns a new hash.Hash computing the checksum. | 
|  | func New() hash.Hash { | 
|  | result := new(digest) | 
|  | result.Reset() | 
|  | return result | 
|  | } | 
|  |  | 
|  | func (d *digest) Size() int { return Size } | 
|  |  | 
|  | func (d *digest) BlockSize() int { return BlockSize } | 
|  |  | 
|  | func (d *digest) Write(p []byte) (nn int, err error) { | 
|  | nn = len(p) | 
|  | d.tc += uint64(nn) | 
|  | if d.nx > 0 { | 
|  | n := len(p) | 
|  | if n > BlockSize-d.nx { | 
|  | n = BlockSize - d.nx | 
|  | } | 
|  | for i := 0; i < n; i++ { | 
|  | d.x[d.nx+i] = p[i] | 
|  | } | 
|  | d.nx += n | 
|  | if d.nx == BlockSize { | 
|  | _Block(d, d.x[0:]) | 
|  | d.nx = 0 | 
|  | } | 
|  | p = p[n:] | 
|  | } | 
|  | n := _Block(d, p) | 
|  | p = p[n:] | 
|  | if len(p) > 0 { | 
|  | d.nx = copy(d.x[:], p) | 
|  | } | 
|  | return | 
|  | } | 
|  |  | 
|  | func (d0 *digest) Sum(in []byte) []byte { | 
|  | // Make a copy of d0 so that caller can keep writing and summing. | 
|  | d := *d0 | 
|  |  | 
|  | // Padding.  Add a 1 bit and 0 bits until 56 bytes mod 64. | 
|  | tc := d.tc | 
|  | var tmp [64]byte | 
|  | tmp[0] = 0x80 | 
|  | if tc%64 < 56 { | 
|  | d.Write(tmp[0 : 56-tc%64]) | 
|  | } else { | 
|  | d.Write(tmp[0 : 64+56-tc%64]) | 
|  | } | 
|  |  | 
|  | // Length in bits. | 
|  | tc <<= 3 | 
|  | for i := uint(0); i < 8; i++ { | 
|  | tmp[i] = byte(tc >> (8 * i)) | 
|  | } | 
|  | d.Write(tmp[0:8]) | 
|  |  | 
|  | if d.nx != 0 { | 
|  | panic("d.nx != 0") | 
|  | } | 
|  |  | 
|  | var digest [Size]byte | 
|  | for i, s := range d.s { | 
|  | digest[i*4] = byte(s) | 
|  | digest[i*4+1] = byte(s >> 8) | 
|  | digest[i*4+2] = byte(s >> 16) | 
|  | digest[i*4+3] = byte(s >> 24) | 
|  | } | 
|  |  | 
|  | return append(in, digest[:]...) | 
|  | } |