mirror of
https://github.com/kaspanet/kaspad.git
synced 2025-06-02 20:26:43 +00:00

* Fix a bug in the matrix ranking algorithm * Add tests and benchmarks for matrix generation and ranking Co-authored-by: Ori Newman <orinewman1@gmail.com>
92 lines
1.9 KiB
Go
92 lines
1.9 KiB
Go
package pow
|
|
|
|
import (
|
|
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
|
|
"github.com/kaspanet/kaspad/domain/consensus/utils/hashes"
|
|
"math"
|
|
)
|
|
|
|
const eps float64 = 1e-9
|
|
|
|
type matrix [64][64]uint16
|
|
|
|
func generateMatrix(hash *externalapi.DomainHash) *matrix {
|
|
var mat matrix
|
|
generator := newxoShiRo256PlusPlus(hash)
|
|
for {
|
|
for i := range mat {
|
|
for j := 0; j < 64; j += 16 {
|
|
val := generator.Uint64()
|
|
for shift := 0; shift < 16; shift++ {
|
|
mat[i][j+shift] = uint16(val >> (4 * shift) & 0x0F)
|
|
}
|
|
}
|
|
}
|
|
if mat.computeRank() == 64 {
|
|
return &mat
|
|
}
|
|
}
|
|
}
|
|
|
|
func (mat *matrix) computeRank() int {
|
|
var B [64][64]float64
|
|
for i := range B {
|
|
for j := range B[0] {
|
|
B[i][j] = float64(mat[i][j])
|
|
}
|
|
}
|
|
var rank int
|
|
var rowSelected [64]bool
|
|
for i := 0; i < 64; i++ {
|
|
var j int
|
|
for j = 0; j < 64; j++ {
|
|
if !rowSelected[j] && math.Abs(B[j][i]) > eps {
|
|
break
|
|
}
|
|
}
|
|
if j != 64 {
|
|
rank++
|
|
rowSelected[j] = true
|
|
for p := i + 1; p < 64; p++ {
|
|
B[j][p] /= B[j][i]
|
|
}
|
|
for k := 0; k < 64; k++ {
|
|
if k != j && math.Abs(B[k][i]) > eps {
|
|
for p := i + 1; p < 64; p++ {
|
|
B[k][p] -= B[j][p] * B[k][i]
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return rank
|
|
}
|
|
|
|
func (mat *matrix) HeavyHash(hash *externalapi.DomainHash) *externalapi.DomainHash {
|
|
hashBytes := hash.ByteArray()
|
|
var vector [64]uint16
|
|
var product [64]uint16
|
|
for i := 0; i < 32; i++ {
|
|
vector[2*i] = uint16(hashBytes[i] >> 4)
|
|
vector[2*i+1] = uint16(hashBytes[i] & 0x0F)
|
|
}
|
|
// Matrix-vector multiplication, and convert to 4 bits.
|
|
for i := 0; i < 64; i++ {
|
|
var sum uint16
|
|
for j := 0; j < 64; j++ {
|
|
sum += mat[i][j] * vector[j]
|
|
}
|
|
product[i] = sum >> 10
|
|
}
|
|
|
|
// Concatenate 4 LSBs back to 8 bit xor with sum1
|
|
var res [32]byte
|
|
for i := range res {
|
|
res[i] = hashBytes[i] ^ (byte(product[2*i]<<4) | byte(product[2*i+1]))
|
|
}
|
|
// Hash again
|
|
writer := hashes.NewHeavyHashWriter()
|
|
writer.InfallibleWrite(res[:])
|
|
return writer.Finalize()
|
|
}
|