You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

shake.go 5.4KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172
  1. // Copyright 2014 The Go Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style
  3. // license that can be found in the LICENSE file.
  4. package sha3
  5. // This file defines the ShakeHash interface, and provides
  6. // functions for creating SHAKE and cSHAKE instances, as well as utility
  7. // functions for hashing bytes to arbitrary-length output.
  8. //
  9. //
  10. // SHAKE implementation is based on FIPS PUB 202 [1]
  11. // cSHAKE implementations is based on NIST SP 800-185 [2]
  12. //
  13. // [1] https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.202.pdf
  14. // [2] https://doi.org/10.6028/NIST.SP.800-185
  15. import (
  16. "encoding/binary"
  17. "hash"
  18. "io"
  19. )
  20. // ShakeHash defines the interface to hash functions that support
  21. // arbitrary-length output. When used as a plain [hash.Hash], it
  22. // produces minimum-length outputs that provide full-strength generic
  23. // security.
  24. type ShakeHash interface {
  25. hash.Hash
  26. // Read reads more output from the hash; reading affects the hash's
  27. // state. (ShakeHash.Read is thus very different from Hash.Sum)
  28. // It never returns an error, but subsequent calls to Write or Sum
  29. // will panic.
  30. io.Reader
  31. // Clone returns a copy of the ShakeHash in its current state.
  32. Clone() ShakeHash
  33. }
  34. // cSHAKE specific context
  35. type cshakeState struct {
  36. *state // SHA-3 state context and Read/Write operations
  37. // initBlock is the cSHAKE specific initialization set of bytes. It is initialized
  38. // by newCShake function and stores concatenation of N followed by S, encoded
  39. // by the method specified in 3.3 of [1].
  40. // It is stored here in order for Reset() to be able to put context into
  41. // initial state.
  42. initBlock []byte
  43. }
  44. // Consts for configuring initial SHA-3 state
  45. const (
  46. dsbyteShake = 0x1f
  47. dsbyteCShake = 0x04
  48. rate128 = 168
  49. rate256 = 136
  50. )
  51. func bytepad(input []byte, w int) []byte {
  52. // leftEncode always returns max 9 bytes
  53. buf := make([]byte, 0, 9+len(input)+w)
  54. buf = append(buf, leftEncode(uint64(w))...)
  55. buf = append(buf, input...)
  56. padlen := w - (len(buf) % w)
  57. return append(buf, make([]byte, padlen)...)
  58. }
  59. func leftEncode(value uint64) []byte {
  60. var b [9]byte
  61. binary.BigEndian.PutUint64(b[1:], value)
  62. // Trim all but last leading zero bytes
  63. i := byte(1)
  64. for i < 8 && b[i] == 0 {
  65. i++
  66. }
  67. // Prepend number of encoded bytes
  68. b[i-1] = 9 - i
  69. return b[i-1:]
  70. }
  71. func newCShake(N, S []byte, rate, outputLen int, dsbyte byte) ShakeHash {
  72. c := cshakeState{state: &state{rate: rate, outputLen: outputLen, dsbyte: dsbyte}}
  73. // leftEncode returns max 9 bytes
  74. c.initBlock = make([]byte, 0, 9*2+len(N)+len(S))
  75. c.initBlock = append(c.initBlock, leftEncode(uint64(len(N)*8))...)
  76. c.initBlock = append(c.initBlock, N...)
  77. c.initBlock = append(c.initBlock, leftEncode(uint64(len(S)*8))...)
  78. c.initBlock = append(c.initBlock, S...)
  79. c.Write(bytepad(c.initBlock, c.rate))
  80. return &c
  81. }
  82. // Reset resets the hash to initial state.
  83. func (c *cshakeState) Reset() {
  84. c.state.Reset()
  85. c.Write(bytepad(c.initBlock, c.rate))
  86. }
  87. // Clone returns copy of a cSHAKE context within its current state.
  88. func (c *cshakeState) Clone() ShakeHash {
  89. b := make([]byte, len(c.initBlock))
  90. copy(b, c.initBlock)
  91. return &cshakeState{state: c.clone(), initBlock: b}
  92. }
  93. // Clone returns copy of SHAKE context within its current state.
  94. func (c *state) Clone() ShakeHash {
  95. return c.clone()
  96. }
  97. // NewShake128 creates a new SHAKE128 variable-output-length ShakeHash.
  98. // Its generic security strength is 128 bits against all attacks if at
  99. // least 32 bytes of its output are used.
  100. func NewShake128() ShakeHash {
  101. if h := newShake128Asm(); h != nil {
  102. return h
  103. }
  104. return &state{rate: rate128, outputLen: 32, dsbyte: dsbyteShake}
  105. }
  106. // NewShake256 creates a new SHAKE256 variable-output-length ShakeHash.
  107. // Its generic security strength is 256 bits against all attacks if
  108. // at least 64 bytes of its output are used.
  109. func NewShake256() ShakeHash {
  110. if h := newShake256Asm(); h != nil {
  111. return h
  112. }
  113. return &state{rate: rate256, outputLen: 64, dsbyte: dsbyteShake}
  114. }
  115. // NewCShake128 creates a new instance of cSHAKE128 variable-output-length ShakeHash,
  116. // a customizable variant of SHAKE128.
  117. // N is used to define functions based on cSHAKE, it can be empty when plain cSHAKE is
  118. // desired. S is a customization byte string used for domain separation - two cSHAKE
  119. // computations on same input with different S yield unrelated outputs.
  120. // When N and S are both empty, this is equivalent to NewShake128.
  121. func NewCShake128(N, S []byte) ShakeHash {
  122. if len(N) == 0 && len(S) == 0 {
  123. return NewShake128()
  124. }
  125. return newCShake(N, S, rate128, 32, dsbyteCShake)
  126. }
  127. // NewCShake256 creates a new instance of cSHAKE256 variable-output-length ShakeHash,
  128. // a customizable variant of SHAKE256.
  129. // N is used to define functions based on cSHAKE, it can be empty when plain cSHAKE is
  130. // desired. S is a customization byte string used for domain separation - two cSHAKE
  131. // computations on same input with different S yield unrelated outputs.
  132. // When N and S are both empty, this is equivalent to NewShake256.
  133. func NewCShake256(N, S []byte) ShakeHash {
  134. if len(N) == 0 && len(S) == 0 {
  135. return NewShake256()
  136. }
  137. return newCShake(N, S, rate256, 64, dsbyteCShake)
  138. }
  139. // ShakeSum128 writes an arbitrary-length digest of data into hash.
  140. func ShakeSum128(hash, data []byte) {
  141. h := NewShake128()
  142. h.Write(data)
  143. h.Read(hash)
  144. }
  145. // ShakeSum256 writes an arbitrary-length digest of data into hash.
  146. func ShakeSum256(hash, data []byte) {
  147. h := NewShake256()
  148. h.Write(data)
  149. h.Read(hash)
  150. }