github.com/MangoDowner/go-gm@v0.0.0-20180818020936-8baa2bd4408c/src/crypto/sm3/sm3.go (about)

     1  /*
     2  Copyright Suzhou Tongji Fintech Research Institute 2017 All Rights Reserved.
     3  Licensed under the Apache License, Version 2.0 (the "License");
     4  you may not use this file except in compliance with the License.
     5  You may obtain a copy of the License at
     6  
     7                   http://www.apache.org/licenses/LICENSE-2.0
     8  
     9  Unless required by applicable law or agreed to in writing, software
    10  distributed under the License is distributed on an "AS IS" BASIS,
    11  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  See the License for the specific language governing permissions and
    13  limitations under the License.
    14  */
    15  
    16  package sm3
    17  
    18  import (
    19  	"encoding/binary"
    20  	"hash"
    21  )
    22  
    23  type SM3 struct {
    24  	digest      [8]uint32 // digest represents the partial evaluation of V
    25  	length      uint64    // length of the message
    26  	unhandleMsg []byte    // uint8  //
    27  }
    28  
    29  func (sm3 *SM3) ff0(x, y, z uint32) uint32 { return x ^ y ^ z }
    30  
    31  func (sm3 *SM3) ff1(x, y, z uint32) uint32 { return (x & y) | (x & z) | (y & z) }
    32  
    33  func (sm3 *SM3) gg0(x, y, z uint32) uint32 { return x ^ y ^ z }
    34  
    35  func (sm3 *SM3) gg1(x, y, z uint32) uint32 { return (x & y) | (^x & z) }
    36  
    37  func (sm3 *SM3) p0(x uint32) uint32 { return x ^ sm3.leftRotate(x, 9) ^ sm3.leftRotate(x, 17) }
    38  
    39  func (sm3 *SM3) p1(x uint32) uint32 { return x ^ sm3.leftRotate(x, 15) ^ sm3.leftRotate(x, 23) }
    40  
    41  func (sm3 *SM3) leftRotate(x uint32, i uint32) uint32 { return (x<<(i%32) | x>>(32-i%32)) }
    42  
    43  func (sm3 *SM3) pad() []byte {
    44  	msg := sm3.unhandleMsg
    45  	msg = append(msg, 0x80) // Append '1'
    46  	blockSize := 64         // Append until the resulting message length (in bits) is congruent to 448 (mod 512)
    47  	for len(msg)%blockSize != 56 {
    48  		msg = append(msg, 0x00)
    49  	}
    50  	// append message length
    51  	msg = append(msg, uint8(sm3.length>>56&0xff))
    52  	msg = append(msg, uint8(sm3.length>>48&0xff))
    53  	msg = append(msg, uint8(sm3.length>>40&0xff))
    54  	msg = append(msg, uint8(sm3.length>>32&0xff))
    55  	msg = append(msg, uint8(sm3.length>>24&0xff))
    56  	msg = append(msg, uint8(sm3.length>>16&0xff))
    57  	msg = append(msg, uint8(sm3.length>>8&0xff))
    58  	msg = append(msg, uint8(sm3.length>>0&0xff))
    59  
    60  	if len(msg)%64 != 0 {
    61  		panic("------SM3 Pad: error msgLen =")
    62  	}
    63  	return msg
    64  }
    65  
    66  func (sm3 *SM3) update(msg []byte, nblocks int) {
    67  	var w [68]uint32
    68  	var w1 [64]uint32
    69  
    70  	a, b, c, d, e, f, g, h := sm3.digest[0], sm3.digest[1], sm3.digest[2], sm3.digest[3], sm3.digest[4], sm3.digest[5], sm3.digest[6], sm3.digest[7]
    71  	for len(msg) >= 64 {
    72  		for i := 0; i < 16; i++ {
    73  			w[i] = binary.BigEndian.Uint32(msg[4*i : 4*(i+1)])
    74  		}
    75  		for i := 16; i < 68; i++ {
    76  			w[i] = sm3.p1(w[i-16]^w[i-9]^sm3.leftRotate(w[i-3], 15)) ^ sm3.leftRotate(w[i-13], 7) ^ w[i-6]
    77  		}
    78  		for i := 0; i < 64; i++ {
    79  			w1[i] = w[i] ^ w[i+4]
    80  		}
    81  		A, B, C, D, E, F, G, H := a, b, c, d, e, f, g, h
    82  		for i := 0; i < 16; i++ {
    83  			SS1 := sm3.leftRotate(sm3.leftRotate(A, 12)+E+sm3.leftRotate(0x79cc4519, uint32(i)), 7)
    84  			SS2 := SS1 ^ sm3.leftRotate(A, 12)
    85  			TT1 := sm3.ff0(A, B, C) + D + SS2 + w1[i]
    86  			TT2 := sm3.gg0(E, F, G) + H + SS1 + w[i]
    87  			D = C
    88  			C = sm3.leftRotate(B, 9)
    89  			B = A
    90  			A = TT1
    91  			H = G
    92  			G = sm3.leftRotate(F, 19)
    93  			F = E
    94  			E = sm3.p0(TT2)
    95  		}
    96  		for i := 16; i < 64; i++ {
    97  			SS1 := sm3.leftRotate(sm3.leftRotate(A, 12)+E+sm3.leftRotate(0x7a879d8a, uint32(i)), 7)
    98  			SS2 := SS1 ^ sm3.leftRotate(A, 12)
    99  			TT1 := sm3.ff1(A, B, C) + D + SS2 + w1[i]
   100  			TT2 := sm3.gg1(E, F, G) + H + SS1 + w[i]
   101  			D = C
   102  			C = sm3.leftRotate(B, 9)
   103  			B = A
   104  			A = TT1
   105  			H = G
   106  			G = sm3.leftRotate(F, 19)
   107  			F = E
   108  			E = sm3.p0(TT2)
   109  		}
   110  		a ^= A
   111  		b ^= B
   112  		c ^= C
   113  		d ^= D
   114  		e ^= E
   115  		f ^= F
   116  		g ^= G
   117  		h ^= H
   118  		msg = msg[64:]
   119  	}
   120  	sm3.digest[0], sm3.digest[1], sm3.digest[2], sm3.digest[3], sm3.digest[4], sm3.digest[5], sm3.digest[6], sm3.digest[7] = a, b, c, d, e, f, g, h
   121  }
   122  
   123  func New() hash.Hash {
   124  	var sm3 SM3
   125  
   126  	sm3.Reset()
   127  	return &sm3
   128  }
   129  
   130  // BlockSize, required by the hash.Hash interface.
   131  // BlockSize returns the hash's underlying block size.
   132  // The Write method must be able to accept any amount
   133  // of data, but it may operate more efficiently if all writes
   134  // are a multiple of the block size.
   135  func (sm3 *SM3) BlockSize() int { return 64 }
   136  
   137  // Size, required by the hash.Hash interface.
   138  // Size returns the number of bytes Sum will return.
   139  func (sm3 *SM3) Size() int { return 32 }
   140  
   141  // Reset clears the internal state by zeroing bytes in the state buffer.
   142  // This can be skipped for a newly-created hash state; the default zero-allocated state is correct.
   143  func (sm3 *SM3) Reset() {
   144  	// Reset digest
   145  	sm3.digest[0] = 0x7380166f
   146  	sm3.digest[1] = 0x4914b2b9
   147  	sm3.digest[2] = 0x172442d7
   148  	sm3.digest[3] = 0xda8a0600
   149  	sm3.digest[4] = 0xa96f30bc
   150  	sm3.digest[5] = 0x163138aa
   151  	sm3.digest[6] = 0xe38dee4d
   152  	sm3.digest[7] = 0xb0fb0e4e
   153  
   154  	sm3.length = 0 // Reset numberic states
   155  	sm3.unhandleMsg = []byte{}
   156  }
   157  
   158  // Write, required by the hash.Hash interface.
   159  // Write (via the embedded io.Writer interface) adds more data to the running hash.
   160  // It never returns an error.
   161  func (sm3 *SM3) Write(p []byte) (int, error) {
   162  	toWrite := len(p)
   163  	sm3.length += uint64(len(p) * 8)
   164  
   165  	msg := append(sm3.unhandleMsg, p...)
   166  	nblocks := len(msg) / sm3.BlockSize()
   167  	sm3.update(msg, nblocks)
   168  
   169  	// Update unhandleMsg
   170  	sm3.unhandleMsg = msg[nblocks*sm3.BlockSize():]
   171  
   172  	return toWrite, nil
   173  }
   174  
   175  // Sum, required by the hash.Hash interface.
   176  // Sum appends the current hash to b and returns the resulting slice.
   177  // It does not change the underlying hash state.
   178  func (sm3 *SM3) Sum(in []byte) []byte {
   179  	sm3.Write(in)
   180  	msg := sm3.pad()
   181  
   182  	// Finialize
   183  	sm3.update(msg, len(msg)/sm3.BlockSize())
   184  
   185  	// save hash to in
   186  	needed := sm3.Size()
   187  	if cap(in)-len(in) < needed {
   188  		newIn := make([]byte, len(in), len(in)+needed)
   189  		copy(newIn, in)
   190  		in = newIn
   191  	}
   192  	out := in[len(in) : len(in)+needed]
   193  
   194  	for i := 0; i < 8; i++ {
   195  		binary.BigEndian.PutUint32(out[i*4:], sm3.digest[i])
   196  	}
   197  	return out
   198  
   199  }
   200  
   201  func Sm3Sum(data []byte) []byte {
   202  	var sm3 SM3
   203  
   204  	sm3.Reset()
   205  	sm3.Write(data)
   206  	return sm3.Sum(nil)
   207  }