-
Notifications
You must be signed in to change notification settings - Fork 0
/
log2.go
132 lines (114 loc) · 3.15 KB
/
log2.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
package poc
import (
"math/big"
"github.com/shopspring/decimal"
)
const (
iterativeMPrecision = 256
iterativeDecimalPrecision = 256
)
var (
//bigDecimalZero = decimal.NewFromInt(0)
bigDecimalOne = decimal.NewFromInt(1)
bigDecimalTwo = decimal.NewFromInt(2)
power2Table [257]*big.Int
negPower2Table [257]decimal.Decimal
)
func init() {
// fill negPower2Table
negPower2Table[0] = decimal.NewFromInt(1)
for i := 1; i <= 256; i++ {
negPower2Table[i] = negPower2Table[i-1].DivRound(bigDecimalTwo, iterativeDecimalPrecision)
}
// fill power2Table
var bigTwo = big.NewInt(2)
power2Table[0] = big.NewInt(1)
for i := 1; i <= 256; i++ {
power2Table[i] = new(big.Int).Mul(power2Table[i-1], bigTwo)
}
}
func log2ByIterative(hi *big.Int) decimal.Decimal {
p, r := extractH(hi) // hi = 2^p + r
y := decimal.NewFromBigInt(r, 0)
y = y.DivRound(decimal.NewFromBigInt(power2Table[p], 0), iterativeDecimalPrecision)
y = y.Add(bigDecimalOne) // y = 1 + r / (2^p), 1 <= y < 2
log2Y := iterativeLog2(y)
pd := decimal.NewFromInt(int64(p))
return pd.Add(log2Y)
}
func iterativeLog2(y decimal.Decimal) decimal.Decimal {
if y.Equal(bigDecimalOne) {
return decimal.NewFromInt(0)
}
if y.Equal(bigDecimalTwo) {
return decimal.NewFromInt(1)
}
var result = decimal.NewFromInt(0)
var m, accumulatedM int
var z = y.Mul(bigDecimalTwo)
var ok bool
for {
m, z, ok = iterativeLog2GetM(z.DivRound(bigDecimalTwo, iterativeDecimalPrecision), accumulatedM)
if !ok {
break
}
accumulatedM += m
result = result.Add(negPower2Table[accumulatedM])
}
return result
}
func iterativeLog2GetM(y decimal.Decimal, accumulatedM int) (m int, z decimal.Decimal, ok bool) {
z = decimal.NewFromInt(0).Add(y)
for m+accumulatedM < iterativeMPrecision {
m++
z = z.Mul(z)
z = z.Round(iterativeDecimalPrecision)
if z.GreaterThanOrEqual(bigDecimalTwo) {
return m, z, true
}
}
return iterativeMPrecision + 1, z, false
}
func calcQualityByDecimal(bl int, h *big.Int, log2Func func(*big.Int) decimal.Decimal) *big.Int {
// Note: Q1 = SIZE * BL
Q1 := decimal.NewFromInt(int64(1 << uint(bl) * bl))
// Note: log2FH = log2(H)
log2FH := log2Func(h)
// Note: Q2 = 256 - log2(H)
Q2 := decimal.NewFromInt(256)
Q2 = Q2.Sub(log2FH)
if Q2.Cmp(decimal.NewFromInt(0)) <= 0 {
panic("Zero")
}
Quality := Q1.DivRound(Q2, iterativeDecimalPrecision).BigInt()
return Quality
}
// extractH takes hi ranges in (0, 2^257)
func extractH(hi *big.Int) (exp int, r *big.Int) {
for i := 256; i >= 0; i-- {
t := power2Table[i]
c := hi.Cmp(t)
if c < 0 {
continue
}
return i, new(big.Int).Sub(hi, t)
}
panic(hi.String())
}
func (proof *DefaultProof) GetQualityByIterative(slot, height uint64) *big.Int {
hashVal := proof.GetHashVal(slot, height)
// Note: Q1 = SIZE * BL
Q1 := decimal.NewFromInt(int64(1 << uint(proof.BL) * proof.BL))
// Note: BH = H in BigInt
BH := new(big.Int).SetBytes(hashVal[:])
// Note: log2FH = log2(H)
log2FH := log2ByIterative(BH)
// Note: Q2 = 256 - log2(H)
Q2 := decimal.NewFromInt(256)
Q2 = Q2.Sub(log2FH)
if Q2.Cmp(decimal.NewFromInt(0)) <= 0 {
panic("Zero")
}
Quality := Q1.DivRound(Q2, iterativeDecimalPrecision).BigInt()
return Quality
}