package sha1
import (
"crypto"
"encoding/binary"
"errors"
"hash"
)
func init () {
crypto .RegisterHash (crypto .SHA1 , New )
}
const Size = 20
const BlockSize = 64
const (
chunk = 64
init0 = 0x67452301
init1 = 0xEFCDAB89
init2 = 0x98BADCFE
init3 = 0x10325476
init4 = 0xC3D2E1F0
)
type digest struct {
h [5 ]uint32
x [chunk ]byte
nx int
len uint64
}
const (
magic = "sha\x01"
marshaledSize = len (magic ) + 5 *4 + chunk + 8
)
func (d *digest ) MarshalBinary () ([]byte , error ) {
b := make ([]byte , 0 , marshaledSize )
b = append (b , magic ...)
b = binary .BigEndian .AppendUint32 (b , d .h [0 ])
b = binary .BigEndian .AppendUint32 (b , d .h [1 ])
b = binary .BigEndian .AppendUint32 (b , d .h [2 ])
b = binary .BigEndian .AppendUint32 (b , d .h [3 ])
b = binary .BigEndian .AppendUint32 (b , d .h [4 ])
b = append (b , d .x [:d .nx ]...)
b = b [:len (b )+len (d .x )-d .nx ]
b = binary .BigEndian .AppendUint64 (b , d .len )
return b , nil
}
func (d *digest ) UnmarshalBinary (b []byte ) error {
if len (b ) < len (magic ) || string (b [:len (magic )]) != magic {
return errors .New ("crypto/sha1: invalid hash state identifier" )
}
if len (b ) != marshaledSize {
return errors .New ("crypto/sha1: invalid hash state size" )
}
b = b [len (magic ):]
b , d .h [0 ] = consumeUint32 (b )
b , d .h [1 ] = consumeUint32 (b )
b , d .h [2 ] = consumeUint32 (b )
b , d .h [3 ] = consumeUint32 (b )
b , d .h [4 ] = consumeUint32 (b )
b = b [copy (d .x [:], b ):]
b , d .len = consumeUint64 (b )
d .nx = int (d .len % chunk )
return nil
}
func consumeUint64 (b []byte ) ([]byte , uint64 ) {
_ = b [7 ]
x := uint64 (b [7 ]) | uint64 (b [6 ])<<8 | uint64 (b [5 ])<<16 | uint64 (b [4 ])<<24 |
uint64 (b [3 ])<<32 | uint64 (b [2 ])<<40 | uint64 (b [1 ])<<48 | uint64 (b [0 ])<<56
return b [8 :], x
}
func consumeUint32 (b []byte ) ([]byte , uint32 ) {
_ = b [3 ]
x := uint32 (b [3 ]) | uint32 (b [2 ])<<8 | uint32 (b [1 ])<<16 | uint32 (b [0 ])<<24
return b [4 :], x
}
func (d *digest ) Reset () {
d .h [0 ] = init0
d .h [1 ] = init1
d .h [2 ] = init2
d .h [3 ] = init3
d .h [4 ] = init4
d .nx = 0
d .len = 0
}
func New () hash .Hash {
if boringEnabled {
return boringNewSHA1 ()
}
d := new (digest )
d .Reset ()
return d
}
func (d *digest ) Size () int { return Size }
func (d *digest ) BlockSize () int { return BlockSize }
func (d *digest ) Write (p []byte ) (nn int , err error ) {
boringUnreachable ()
nn = len (p )
d .len += uint64 (nn )
if d .nx > 0 {
n := copy (d .x [d .nx :], p )
d .nx += n
if d .nx == chunk {
block (d , d .x [:])
d .nx = 0
}
p = p [n :]
}
if len (p ) >= chunk {
n := len (p ) &^ (chunk - 1 )
block (d , p [:n ])
p = p [n :]
}
if len (p ) > 0 {
d .nx = copy (d .x [:], p )
}
return
}
func (d *digest ) Sum (in []byte ) []byte {
boringUnreachable ()
d0 := *d
hash := d0 .checkSum ()
return append (in , hash [:]...)
}
func (d *digest ) checkSum () [Size ]byte {
len := d .len
var tmp [64 + 8 ]byte
tmp [0 ] = 0x80
var t uint64
if len %64 < 56 {
t = 56 - len %64
} else {
t = 64 + 56 - len %64
}
len <<= 3
padlen := tmp [:t +8 ]
binary .BigEndian .PutUint64 (padlen [t :], len )
d .Write (padlen )
if d .nx != 0 {
panic ("d.nx != 0" )
}
var digest [Size ]byte
binary .BigEndian .PutUint32 (digest [0 :], d .h [0 ])
binary .BigEndian .PutUint32 (digest [4 :], d .h [1 ])
binary .BigEndian .PutUint32 (digest [8 :], d .h [2 ])
binary .BigEndian .PutUint32 (digest [12 :], d .h [3 ])
binary .BigEndian .PutUint32 (digest [16 :], d .h [4 ])
return digest
}
func (d *digest ) ConstantTimeSum (in []byte ) []byte {
d0 := *d
hash := d0 .constSum ()
return append (in , hash [:]...)
}
func (d *digest ) constSum () [Size ]byte {
var length [8 ]byte
l := d .len << 3
for i := uint (0 ); i < 8 ; i ++ {
length [i ] = byte (l >> (56 - 8 *i ))
}
nx := byte (d .nx )
t := nx - 56
mask1b := byte (int8 (t ) >> 7 )
separator := byte (0x80 )
for i := byte (0 ); i < chunk ; i ++ {
mask := byte (int8 (i -nx ) >> 7 )
d .x [i ] = (^mask & separator ) | (mask & d .x [i ])
separator &= mask
if i >= 56 {
d .x [i ] |= mask1b & length [i -56 ]
}
}
block (d , d .x [:])
var digest [Size ]byte
for i , s := range d .h {
digest [i *4 ] = mask1b & byte (s >>24 )
digest [i *4 +1 ] = mask1b & byte (s >>16 )
digest [i *4 +2 ] = mask1b & byte (s >>8 )
digest [i *4 +3 ] = mask1b & byte (s )
}
for i := byte (0 ); i < chunk ; i ++ {
if i < 56 {
d .x [i ] = separator
separator = 0
} else {
d .x [i ] = length [i -56 ]
}
}
block (d , d .x [:])
for i , s := range d .h {
digest [i *4 ] |= ^mask1b & byte (s >>24 )
digest [i *4 +1 ] |= ^mask1b & byte (s >>16 )
digest [i *4 +2 ] |= ^mask1b & byte (s >>8 )
digest [i *4 +3 ] |= ^mask1b & byte (s )
}
return digest
}
func Sum (data []byte ) [Size ]byte {
if boringEnabled {
return boringSHA1 (data )
}
var d digest
d .Reset ()
d .Write (data )
return d .checkSum ()
}
The pages are generated with Golds v0.6.7 . (GOOS=linux GOARCH=amd64)
Golds is a Go 101 project developed by Tapir Liu .
PR and bug reports are welcome and can be submitted to the issue list .
Please follow @Go100and1 (reachable from the left QR code) to get the latest news of Golds .