mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-08-20 02:42:27 +00:00
consensus/eccpow: add LDPCDecoder
This commit is contained in:
parent
4cbeacd254
commit
69983932fa
3 changed files with 491 additions and 0 deletions
210
consensus/eccpow/LDPCDecoder.go
Normal file
210
consensus/eccpow/LDPCDecoder.go
Normal file
|
|
@ -0,0 +1,210 @@
|
||||||
|
package eccpow
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/binary"
|
||||||
|
"math"
|
||||||
|
|
||||||
|
"github.com/cryptoecc/ETH-ECC/core/types"
|
||||||
|
"github.com/cryptoecc/ETH-ECC/crypto"
|
||||||
|
)
|
||||||
|
|
||||||
|
//OptimizedDecoding return hashVector, outputWord, LRrtl
|
||||||
|
func OptimizedDecoding(parameters Parameters, hashVector []int, H, rowInCol, colInRow [][]int) ([]int, []int, [][]float64) {
|
||||||
|
outputWord := make([]int, parameters.n)
|
||||||
|
LRqtl := make([][]float64, parameters.n)
|
||||||
|
LRrtl := make([][]float64, parameters.n)
|
||||||
|
LRft := make([]float64, parameters.n)
|
||||||
|
|
||||||
|
for i := 0; i < parameters.n; i++ {
|
||||||
|
LRqtl[i] = make([]float64, parameters.m)
|
||||||
|
LRrtl[i] = make([]float64, parameters.m)
|
||||||
|
LRft[i] = math.Log((1-crossErr)/crossErr) * float64((hashVector[i]*2 - 1))
|
||||||
|
}
|
||||||
|
LRpt := make([]float64, parameters.n)
|
||||||
|
|
||||||
|
for ind := 1; ind <= maxIter; ind++ {
|
||||||
|
for t := 0; t < parameters.n; t++ {
|
||||||
|
temp3 := 0.0
|
||||||
|
|
||||||
|
for mp := 0; mp < parameters.wc; mp++ {
|
||||||
|
temp3 = infinityTest(temp3 + LRrtl[t][rowInCol[mp][t]])
|
||||||
|
}
|
||||||
|
for m := 0; m < parameters.wc; m++ {
|
||||||
|
temp4 := temp3
|
||||||
|
temp4 = infinityTest(temp4 - LRrtl[t][rowInCol[m][t]])
|
||||||
|
LRqtl[t][rowInCol[m][t]] = infinityTest(LRft[t] + temp4)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for k := 0; k < parameters.wr; k++ {
|
||||||
|
for l := 0; l < parameters.wr; l++ {
|
||||||
|
temp3 := 0.0
|
||||||
|
sign := 1.0
|
||||||
|
tempSign := 0.0
|
||||||
|
for m := 0; m < parameters.wr; m++ {
|
||||||
|
if m != l {
|
||||||
|
temp3 = temp3 + funcF(math.Abs(LRqtl[colInRow[m][k]][k]))
|
||||||
|
if LRqtl[colInRow[m][k]][k] > 0.0 {
|
||||||
|
tempSign = 1.0
|
||||||
|
} else {
|
||||||
|
tempSign = -1.0
|
||||||
|
}
|
||||||
|
sign = sign * tempSign
|
||||||
|
}
|
||||||
|
}
|
||||||
|
magnitude := funcF(temp3)
|
||||||
|
LRrtl[colInRow[l][k]][k] = infinityTest(sign * magnitude)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for t := 0; t < parameters.n; t++ {
|
||||||
|
LRpt[t] = infinityTest(LRft[t])
|
||||||
|
for k := 0; k < parameters.wc; k++ {
|
||||||
|
LRpt[t] += LRrtl[t][rowInCol[k][t]]
|
||||||
|
LRpt[t] = infinityTest(LRpt[t])
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
if LRpt[t] >= 0 {
|
||||||
|
outputWord[t] = 1
|
||||||
|
} else {
|
||||||
|
outputWord[t] = 0
|
||||||
|
}*/
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for t := 0; t < parameters.n; t++ {
|
||||||
|
if LRpt[t] >= 0 {
|
||||||
|
outputWord[t] = 1
|
||||||
|
} else {
|
||||||
|
outputWord[t] = 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return hashVector, outputWord, LRrtl
|
||||||
|
}
|
||||||
|
|
||||||
|
//OptimizedDecoding return hashVector, outputWord, LRrtl
|
||||||
|
func OptimizedDecodingSeoul(parameters Parameters, hashVector []int, H, rowInCol, colInRow [][]int) ([]int, []int, [][]float64) {
|
||||||
|
outputWord := make([]int, parameters.n)
|
||||||
|
LRqtl := make([][]float64, parameters.n)
|
||||||
|
LRrtl := make([][]float64, parameters.n)
|
||||||
|
LRft := make([]float64, parameters.n)
|
||||||
|
|
||||||
|
for i := 0; i < parameters.n; i++ {
|
||||||
|
LRqtl[i] = make([]float64, parameters.m)
|
||||||
|
LRrtl[i] = make([]float64, parameters.m)
|
||||||
|
LRft[i] = math.Log((1-crossErr)/crossErr) * float64((hashVector[i]*2 - 1))
|
||||||
|
}
|
||||||
|
LRpt := make([]float64, parameters.n)
|
||||||
|
|
||||||
|
for ind := 1; ind <= maxIter; ind++ {
|
||||||
|
for t := 0; t < parameters.n; t++ {
|
||||||
|
temp3 := 0.0
|
||||||
|
|
||||||
|
for mp := 0; mp < parameters.wc; mp++ {
|
||||||
|
temp3 = infinityTest(temp3 + LRrtl[t][rowInCol[mp][t]])
|
||||||
|
}
|
||||||
|
for m := 0; m < parameters.wc; m++ {
|
||||||
|
temp4 := temp3
|
||||||
|
temp4 = infinityTest(temp4 - LRrtl[t][rowInCol[m][t]])
|
||||||
|
LRqtl[t][rowInCol[m][t]] = infinityTest(LRft[t] + temp4)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for k := 0; k < parameters.m; k++ {
|
||||||
|
for l := 0; l < parameters.wr; l++ {
|
||||||
|
temp3 := 0.0
|
||||||
|
sign := 1.0
|
||||||
|
tempSign := 0.0
|
||||||
|
for m := 0; m < parameters.wr; m++ {
|
||||||
|
if m != l {
|
||||||
|
temp3 = temp3 + funcF(math.Abs(LRqtl[colInRow[m][k]][k]))
|
||||||
|
if LRqtl[colInRow[m][k]][k] > 0.0 {
|
||||||
|
tempSign = 1.0
|
||||||
|
} else {
|
||||||
|
tempSign = -1.0
|
||||||
|
}
|
||||||
|
sign = sign * tempSign
|
||||||
|
}
|
||||||
|
}
|
||||||
|
magnitude := funcF(temp3)
|
||||||
|
LRrtl[colInRow[l][k]][k] = infinityTest(sign * magnitude)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for t := 0; t < parameters.n; t++ {
|
||||||
|
LRpt[t] = infinityTest(LRft[t])
|
||||||
|
for k := 0; k < parameters.wc; k++ {
|
||||||
|
LRpt[t] += LRrtl[t][rowInCol[k][t]]
|
||||||
|
LRpt[t] = infinityTest(LRpt[t])
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if LRpt[t] >= 0 {
|
||||||
|
outputWord[t] = 1
|
||||||
|
} else {
|
||||||
|
outputWord[t] = 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
for t := 0; t < parameters.n; t++ {
|
||||||
|
if LRpt[t] >= 0 {
|
||||||
|
outputWord[t] = 1
|
||||||
|
} else {
|
||||||
|
outputWord[t] = 0
|
||||||
|
}
|
||||||
|
}*/
|
||||||
|
|
||||||
|
return hashVector, outputWord, LRrtl
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//VerifyOptimizedDecoding return bool, hashVector, outputword, digest which are used for validation
|
||||||
|
func VerifyOptimizedDecoding(header *types.Header, hash []byte) (bool, []int, []int, []byte) {
|
||||||
|
parameters, _ := setParameters(header)
|
||||||
|
H := generateH(parameters)
|
||||||
|
colInRow, rowInCol := generateQ(parameters, H)
|
||||||
|
|
||||||
|
seed := make([]byte, 40)
|
||||||
|
copy(seed, hash)
|
||||||
|
binary.LittleEndian.PutUint64(seed[32:], header.Nonce.Uint64())
|
||||||
|
seed = crypto.Keccak512(seed)
|
||||||
|
|
||||||
|
hashVector := generateHv(parameters, seed)
|
||||||
|
hashVectorOfVerification, outputWordOfVerification, _ := OptimizedDecoding(parameters, hashVector, H, rowInCol, colInRow)
|
||||||
|
//hashVectorOfVerification, outputWordOfVerification, _ := OptimizedDecodingSeoul(parameters, hashVector, H, rowInCol, colInRow)
|
||||||
|
|
||||||
|
flag , _ := MakeDecision(header, colInRow, outputWordOfVerification)
|
||||||
|
|
||||||
|
if flag {
|
||||||
|
return true, hashVectorOfVerification, outputWordOfVerification, seed
|
||||||
|
}
|
||||||
|
|
||||||
|
return false, hashVectorOfVerification, outputWordOfVerification, seed
|
||||||
|
}
|
||||||
|
|
||||||
|
//VerifyOptimizedDecoding return bool, hashVector, outputword, digest which are used for validation
|
||||||
|
func VerifyOptimizedDecodingSeoul(header *types.Header, hash []byte) (bool, []int, []int, []byte) {
|
||||||
|
parameters, _ := setParameters_Seoul(header)
|
||||||
|
H := generateH(parameters)
|
||||||
|
colInRow, rowInCol := generateQ(parameters, H)
|
||||||
|
|
||||||
|
seed := make([]byte, 40)
|
||||||
|
copy(seed, hash)
|
||||||
|
binary.LittleEndian.PutUint64(seed[32:], header.Nonce.Uint64())
|
||||||
|
seed = crypto.Keccak512(seed)
|
||||||
|
|
||||||
|
hashVector := generateHv(parameters, seed)
|
||||||
|
//hashVectorOfVerification, outputWordOfVerification, _ := OptimizedDecoding(parameters, hashVector, H, rowInCol, colInRow)
|
||||||
|
hashVectorOfVerification, outputWordOfVerification, _ := OptimizedDecodingSeoul(parameters, hashVector, H, rowInCol, colInRow)
|
||||||
|
|
||||||
|
flag , _ := MakeDecision_Seoul(header, colInRow, outputWordOfVerification)
|
||||||
|
|
||||||
|
if flag {
|
||||||
|
return true, hashVectorOfVerification, outputWordOfVerification, seed
|
||||||
|
}
|
||||||
|
|
||||||
|
return false, hashVectorOfVerification, outputWordOfVerification, seed
|
||||||
|
}
|
||||||
79
consensus/eccpow/LDPCDecoder_test.go
Normal file
79
consensus/eccpow/LDPCDecoder_test.go
Normal file
|
|
@ -0,0 +1,79 @@
|
||||||
|
package eccpow
|
||||||
|
|
||||||
|
import (
|
||||||
|
"math/rand"
|
||||||
|
"reflect"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/cryptoecc/ETH-ECC/core/types"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestNonceDecoding(t *testing.T) {
|
||||||
|
LDPCNonce := generateRandomNonce()
|
||||||
|
EncodedNonce := types.EncodeNonce(LDPCNonce)
|
||||||
|
DecodedNonce := EncodedNonce.Uint64()
|
||||||
|
|
||||||
|
if LDPCNonce == DecodedNonce {
|
||||||
|
t.Logf("LDPCNonce : %v\n", LDPCNonce)
|
||||||
|
t.Logf("Decoded Nonce : %v\n", DecodedNonce)
|
||||||
|
} else {
|
||||||
|
t.Errorf("LDPCNonce : %v\n", LDPCNonce)
|
||||||
|
t.Errorf("Decoded Nonce : %v\n", DecodedNonce)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGenerateH(t *testing.T) {
|
||||||
|
for i := 0; i < 10; i++ {
|
||||||
|
header := new(types.Header)
|
||||||
|
header.Difficulty = ProbToDifficulty(Table[0].miningProb)
|
||||||
|
|
||||||
|
parameters, _ := setParameters(header)
|
||||||
|
|
||||||
|
H1 := generateH(parameters)
|
||||||
|
H2 := generateH(parameters)
|
||||||
|
|
||||||
|
if !reflect.DeepEqual(H1, H2) {
|
||||||
|
t.Error("Wrong")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestRandShuffle(t *testing.T) {
|
||||||
|
for attempt := 0; attempt < 100; attempt++ {
|
||||||
|
var hSeed int64
|
||||||
|
var colOrder []int
|
||||||
|
|
||||||
|
for i := 1; i < 4; i++ {
|
||||||
|
colOrder = nil
|
||||||
|
for j := 0; j < 32; j++ {
|
||||||
|
colOrder = append(colOrder, j)
|
||||||
|
}
|
||||||
|
|
||||||
|
rand.Seed(hSeed)
|
||||||
|
rand.Shuffle(len(colOrder), func(i, j int) {
|
||||||
|
colOrder[i], colOrder[j] = colOrder[j], colOrder[i]
|
||||||
|
})
|
||||||
|
hSeed--
|
||||||
|
}
|
||||||
|
|
||||||
|
var hSeed2 int64
|
||||||
|
var colOrder2 []int
|
||||||
|
|
||||||
|
for i := 1; i < 4; i++ {
|
||||||
|
colOrder2 = nil
|
||||||
|
for j := 0; j < 32; j++ {
|
||||||
|
colOrder2 = append(colOrder2, j)
|
||||||
|
}
|
||||||
|
|
||||||
|
rand.Seed(hSeed2)
|
||||||
|
rand.Shuffle(len(colOrder2), func(i, j int) {
|
||||||
|
colOrder2[i], colOrder2[j] = colOrder2[j], colOrder2[i]
|
||||||
|
})
|
||||||
|
hSeed2--
|
||||||
|
}
|
||||||
|
|
||||||
|
if !reflect.DeepEqual(colOrder, colOrder2) {
|
||||||
|
t.Error("Wrong")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
202
consensus/eccpow/LDPC_utils.go
Normal file
202
consensus/eccpow/LDPC_utils.go
Normal file
|
|
@ -0,0 +1,202 @@
|
||||||
|
package eccpow
|
||||||
|
|
||||||
|
import (
|
||||||
|
crand "crypto/rand"
|
||||||
|
"math"
|
||||||
|
"math/big"
|
||||||
|
"math/rand"
|
||||||
|
|
||||||
|
"github.com/cryptoecc/ETH-ECC/core/types"
|
||||||
|
)
|
||||||
|
|
||||||
|
//Parameters for matrix and seed
|
||||||
|
const (
|
||||||
|
BigInfinity = 1000000.0
|
||||||
|
Inf = 64.0
|
||||||
|
MaxNonce = 1<<32 - 1
|
||||||
|
|
||||||
|
// These parameters are only used for the decoding function.
|
||||||
|
maxIter = 20 // The maximum number of iteration in the decoder
|
||||||
|
crossErr = 0.01 // A transisient error probability. This is also fixed as a small value
|
||||||
|
)
|
||||||
|
|
||||||
|
type Parameters struct {
|
||||||
|
n int
|
||||||
|
m int
|
||||||
|
wc int
|
||||||
|
wr int
|
||||||
|
seed int
|
||||||
|
}
|
||||||
|
|
||||||
|
// setParameters sets n, wc, wr, m, seed return parameters and difficulty level
|
||||||
|
func setParameters(header *types.Header) (Parameters, int) {
|
||||||
|
//level := SearchLevel(header.Difficulty)
|
||||||
|
level := SearchLevel(header.Difficulty)
|
||||||
|
|
||||||
|
parameters := Parameters{
|
||||||
|
n: Table[level].n,
|
||||||
|
wc: Table[level].wc,
|
||||||
|
wr: Table[level].wr,
|
||||||
|
}
|
||||||
|
parameters.m = int(parameters.n * parameters.wc / parameters.wr)
|
||||||
|
parameters.seed = generateSeed(header.ParentHash)
|
||||||
|
|
||||||
|
return parameters, level
|
||||||
|
}
|
||||||
|
|
||||||
|
// setParameters sets n, wc, wr, m, seed return parameters and difficulty level
|
||||||
|
func setParameters_Seoul(header *types.Header) (Parameters, int) {
|
||||||
|
//level := SearchLevel(header.Difficulty)
|
||||||
|
level := SearchLevel_Seoul(header.Difficulty)
|
||||||
|
table := getTable(level)
|
||||||
|
parameters := Parameters{
|
||||||
|
n: table.n,
|
||||||
|
wc: table.wc,
|
||||||
|
wr: table.wr,
|
||||||
|
}
|
||||||
|
parameters.m = int(parameters.n * parameters.wc / parameters.wr)
|
||||||
|
parameters.seed = generateSeed(header.ParentHash)
|
||||||
|
|
||||||
|
return parameters, level
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//generateRandomNonce generate 64bit random nonce with similar way of ethereum block nonce
|
||||||
|
func generateRandomNonce() uint64 {
|
||||||
|
seed, _ := crand.Int(crand.Reader, big.NewInt(math.MaxInt64))
|
||||||
|
source := rand.New(rand.NewSource(seed.Int64()))
|
||||||
|
|
||||||
|
return uint64(source.Int63())
|
||||||
|
}
|
||||||
|
|
||||||
|
func funcF(x float64) float64 {
|
||||||
|
if x >= BigInfinity {
|
||||||
|
return 1.0 / BigInfinity
|
||||||
|
} else if x <= (1.0 / BigInfinity) {
|
||||||
|
return BigInfinity
|
||||||
|
} else {
|
||||||
|
return math.Log((math.Exp(x) + 1) / (math.Exp(x) - 1))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func infinityTest(x float64) float64 {
|
||||||
|
if x >= Inf {
|
||||||
|
return Inf
|
||||||
|
} else if x <= -Inf {
|
||||||
|
return -Inf
|
||||||
|
} else {
|
||||||
|
return x
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//generateSeed generate seed using previous hash vector
|
||||||
|
func generateSeed(phv [32]byte) int {
|
||||||
|
sum := 0
|
||||||
|
for i := 0; i < len(phv); i++ {
|
||||||
|
sum += int(phv[i])
|
||||||
|
}
|
||||||
|
return sum
|
||||||
|
}
|
||||||
|
|
||||||
|
//generateH generate H matrix using parameters
|
||||||
|
//generateH Cannot be sure rand is same with original implementation of C++
|
||||||
|
func generateH(parameters Parameters) [][]int {
|
||||||
|
var H [][]int
|
||||||
|
var hSeed int64
|
||||||
|
var colOrder []int
|
||||||
|
|
||||||
|
hSeed = int64(parameters.seed)
|
||||||
|
k := parameters.m / parameters.wc
|
||||||
|
|
||||||
|
H = make([][]int, parameters.m)
|
||||||
|
for i := range H {
|
||||||
|
H[i] = make([]int, parameters.n)
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := 0; i < k; i++ {
|
||||||
|
for j := i * parameters.wr; j < (i+1)*parameters.wr; j++ {
|
||||||
|
H[i][j] = 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := 1; i < parameters.wc; i++ {
|
||||||
|
colOrder = nil
|
||||||
|
for j := 0; j < parameters.n; j++ {
|
||||||
|
colOrder = append(colOrder, j)
|
||||||
|
}
|
||||||
|
|
||||||
|
src := rand.NewSource(hSeed)
|
||||||
|
rnd := rand.New(src)
|
||||||
|
rnd.Seed(hSeed)
|
||||||
|
rnd.Shuffle(len(colOrder), func(i, j int) {
|
||||||
|
colOrder[i],colOrder[j] = colOrder[j], colOrder[i]
|
||||||
|
})
|
||||||
|
hSeed--
|
||||||
|
|
||||||
|
for j := 0; j < parameters.n; j++ {
|
||||||
|
index := (colOrder[j]/parameters.wr + k*i)
|
||||||
|
H[index][j] = 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return H
|
||||||
|
}
|
||||||
|
|
||||||
|
//generateQ generate colInRow and rowInCol matrix using H matrix
|
||||||
|
func generateQ(parameters Parameters, H [][]int) ([][]int, [][]int) {
|
||||||
|
colInRow := make([][]int, parameters.wr)
|
||||||
|
for i := 0; i < parameters.wr; i++ {
|
||||||
|
colInRow[i] = make([]int, parameters.m)
|
||||||
|
}
|
||||||
|
|
||||||
|
rowInCol := make([][]int, parameters.wc)
|
||||||
|
for i := 0; i < parameters.wc; i++ {
|
||||||
|
rowInCol[i] = make([]int, parameters.n)
|
||||||
|
}
|
||||||
|
|
||||||
|
rowIndex := 0
|
||||||
|
colIndex := 0
|
||||||
|
|
||||||
|
for i := 0; i < parameters.m; i++ {
|
||||||
|
for j := 0; j < parameters.n; j++ {
|
||||||
|
if H[i][j] == 1 {
|
||||||
|
colInRow[colIndex%parameters.wr][i] = j
|
||||||
|
colIndex++
|
||||||
|
|
||||||
|
rowInCol[rowIndex/parameters.n][j] = i
|
||||||
|
rowIndex++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return colInRow, rowInCol
|
||||||
|
}
|
||||||
|
|
||||||
|
//generateHv generate hashvector
|
||||||
|
//It needs to compare with origin C++ implementation Especially when sha256 function is used
|
||||||
|
func generateHv(parameters Parameters, encryptedHeaderWithNonce []byte) []int {
|
||||||
|
hashVector := make([]int, parameters.n)
|
||||||
|
|
||||||
|
/*
|
||||||
|
if parameters.n <= 256 {
|
||||||
|
tmpHashVector = sha256.Sum256(headerWithNonce)
|
||||||
|
} else {
|
||||||
|
/*
|
||||||
|
This section is for a case in which the size of a hash vector is larger than 256.
|
||||||
|
This section will be implemented soon.
|
||||||
|
}
|
||||||
|
transform the constructed hexadecimal array into an binary array
|
||||||
|
ex) FE01 => 11111110000 0001
|
||||||
|
*/
|
||||||
|
|
||||||
|
for i := 0; i < parameters.n/8; i++ {
|
||||||
|
decimal := int(encryptedHeaderWithNonce[i])
|
||||||
|
for j := 7; j >= 0; j-- {
|
||||||
|
hashVector[j+8*(i)] = decimal % 2
|
||||||
|
decimal /= 2
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//outputWord := hashVector[:parameters.n]
|
||||||
|
return hashVector
|
||||||
|
}
|
||||||
Loading…
Reference in a new issue