github.com/Bytom/bytom@v1.1.2-0.20210127130405-ae40204c0b09/mining/tensority/go_algorithm/matrix.go (about)

     1  package go_algorithm
     2  
     3  import (
     4  	"reflect"
     5  	"runtime"
     6  	"sync"
     7  	"unsafe"
     8  
     9  	"gonum.org/v1/gonum/mat"
    10  
    11  	"github.com/bytom/bytom/crypto/sha3pool"
    12  	"github.com/bytom/bytom/protocol/bc"
    13  )
    14  
    15  const (
    16  	matSize = 1 << 8 // Size of matrix
    17  	matNum  = 1 << 8 // Number of matrix
    18  )
    19  
    20  func mulMatrix(headerhash []byte, cache []uint32) []uint8 {
    21  	ui32data := make([]uint32, matNum*matSize*matSize/4)
    22  	for i := 0; i < 128; i++ {
    23  		start := i * 1024 * 32
    24  		for j := 0; j < 512; j++ {
    25  			copy(ui32data[start+j*32:start+j*32+32], cache[start+j*64:start+j*64+32])
    26  			copy(ui32data[start+512*32+j*32:start+512*32+j*32+32], cache[start+j*64+32:start+j*64+64])
    27  		}
    28  	}
    29  
    30  	// Convert our destination slice to a int8 buffer
    31  	header := *(*reflect.SliceHeader)(unsafe.Pointer(&ui32data))
    32  	header.Len *= 4
    33  	header.Cap *= 4
    34  	i8data := *(*[]int8)(unsafe.Pointer(&header))
    35  
    36  	f64data := make([]float64, matNum*matSize*matSize)
    37  	for i := 0; i < matNum*matSize*matSize; i++ {
    38  		f64data[i] = float64(i8data[i])
    39  	}
    40  
    41  	dataIdentity := make([]float64, matSize*matSize)
    42  	for i := 0; i < 256; i++ {
    43  		dataIdentity[i*257] = float64(1)
    44  	}
    45  
    46  	var tmp [matSize][matSize]float64
    47  	var maArr [4][matSize][matSize]float64
    48  
    49  	runtime.GOMAXPROCS(4)
    50  	var wg sync.WaitGroup
    51  	wg.Add(4)
    52  
    53  	for k := 0; k < 4; k++ {
    54  		go func(i int) {
    55  			defer wg.Done()
    56  
    57  			ma := mat.NewDense(matSize, matSize, dataIdentity)
    58  			mc := mat.NewDense(matSize, matSize, make([]float64, matSize*matSize))
    59  
    60  			var sequence [32]byte
    61  			sha3pool.Sum256(sequence[:], headerhash[i*8:(i+1)*8])
    62  
    63  			for j := 0; j < 2; j++ {
    64  				for k := 0; k < 32; k++ {
    65  					index := int(sequence[k])
    66  					mb := mat.NewDense(matSize, matSize, f64data[index*matSize*matSize:(index+1)*matSize*matSize])
    67  					mc.Mul(ma, mb.T())
    68  
    69  					for row := 0; row < matSize; row++ {
    70  						for col := 0; col < matSize; col++ {
    71  							i32v := int32(mc.At(row, col))
    72  							i8v := int8((i32v & 0xff) +
    73  								((i32v >> 8) & 0xff))
    74  							mc.Set(row, col, float64(i8v))
    75  						}
    76  					}
    77  					ma = mc
    78  				}
    79  			}
    80  
    81  			for row := 0; row < matSize; row++ {
    82  				for col := 0; col < matSize; col++ {
    83  					maArr[i][row][col] = ma.At(row, col)
    84  				}
    85  			}
    86  		}(k)
    87  	}
    88  	wg.Wait()
    89  
    90  	for i := 0; i < 4; i++ {
    91  		for row := 0; row < matSize; row++ {
    92  			for col := 0; col < matSize; col++ {
    93  				i32vtmp := int32(tmp[row][col])
    94  				i32vma := int32(maArr[i][row][col])
    95  				i8v := int8(int32(i32vtmp+i32vma) & 0xff)
    96  				tmp[row][col] = float64(i8v)
    97  			}
    98  		}
    99  	}
   100  
   101  	result := make([]uint8, 0)
   102  	for i := 0; i < matSize; i++ {
   103  		for j := 0; j < matSize; j++ {
   104  			result = append(result, uint8(tmp[i][j]))
   105  		}
   106  	}
   107  	return result
   108  }
   109  
   110  // hashMatrix hash result of mulMatrix
   111  func hashMatrix(result []uint8) *bc.Hash {
   112  	var mat8 [matSize][matSize]uint8
   113  	for i := 0; i < matSize; i++ {
   114  		for j := 0; j < matSize; j++ {
   115  			mat8[i][j] = result[i*matSize+j]
   116  		}
   117  	}
   118  
   119  	var mat32 [matSize][matSize / 4]uint32
   120  
   121  	for i := 0; i < matSize; i++ {
   122  		for j := 0; j < matSize/4; j++ {
   123  			mat32[i][j] = ((uint32(mat8[i][j+192])) << 24) |
   124  				((uint32(mat8[i][j+128])) << 16) |
   125  				((uint32(mat8[i][j+64])) << 8) |
   126  				((uint32(mat8[i][j])) << 0)
   127  		}
   128  	}
   129  
   130  	for k := matSize; k > 1; k = k / 2 {
   131  		for j := 0; j < k/2; j++ {
   132  			for i := 0; i < matSize/4; i++ {
   133  				mat32[j][i] = fnv(mat32[j][i], mat32[j+k/2][i])
   134  			}
   135  		}
   136  	}
   137  
   138  	ui32data := make([]uint32, 0)
   139  	for i := 0; i < matSize/4; i++ {
   140  		ui32data = append(ui32data, mat32[0][i])
   141  	}
   142  
   143  	// Convert our destination slice to a byte buffer
   144  	header := *(*reflect.SliceHeader)(unsafe.Pointer(&ui32data))
   145  	header.Len *= 4
   146  	header.Cap *= 4
   147  	dataBytes := *(*[]byte)(unsafe.Pointer(&header))
   148  
   149  	var h [32]byte
   150  	sha3pool.Sum256(h[:], dataBytes)
   151  	bcHash := bc.NewHash(h)
   152  	return &bcHash
   153  }
   154  
   155  func fnv(a, b uint32) uint32 {
   156  	return a*0x01000193 ^ b
   157  }