302 lines
10 KiB
Go
Raw Permalink Normal View History

2025-10-06 13:38:53 +07:00
package crypto
import (
"encoding/binary"
"fmt"
"math/big"
"github.com/btcsuite/btcd/btcutil/base58"
)
const (
DIGEST_LENGTH = 5
STATE_SIZE = 16
NUM_SPLIT_AND_LOOKUP = 4
LOG2_STATE_SIZE = 4
CAPACITY = 6
RATE = 10
NUM_ROUNDS = 7
R_MOD_P uint64 = 4294967295
)
var (
R, _ = new(big.Int).SetString("18446744073709551616", 10)
LOOKUP_TABLE = [256]uint8{
0, 7, 26, 63, 124, 215, 85, 254, 214, 228, 45, 185, 140, 173, 33, 240, 29, 177, 176, 32, 8,
110, 87, 202, 204, 99, 150, 106, 230, 14, 235, 128, 213, 239, 212, 138, 23, 130, 208, 6, 44,
71, 93, 116, 146, 189, 251, 81, 199, 97, 38, 28, 73, 179, 95, 84, 152, 48, 35, 119, 49, 88,
242, 3, 148, 169, 72, 120, 62, 161, 166, 83, 175, 191, 137, 19, 100, 129, 112, 55, 221, 102,
218, 61, 151, 237, 68, 164, 17, 147, 46, 234, 203, 216, 22, 141, 65, 57, 123, 12, 244, 54, 219,
231, 96, 77, 180, 154, 5, 253, 133, 165, 98, 195, 205, 134, 245, 30, 9, 188, 59, 142, 186, 197,
181, 144, 92, 31, 224, 163, 111, 74, 58, 69, 113, 196, 67, 246, 225, 10, 121, 50, 60, 157, 90,
122, 2, 250, 101, 75, 178, 159, 24, 36, 201, 11, 243, 132, 198, 190, 114, 233, 39, 52, 21, 209,
108, 238, 91, 187, 18, 104, 194, 37, 153, 34, 200, 143, 126, 155, 236, 118, 64, 80, 172, 89,
94, 193, 135, 183, 86, 107, 252, 13, 167, 206, 136, 220, 207, 103, 171, 160, 76, 182, 227, 217,
158, 56, 174, 4, 66, 109, 139, 162, 184, 211, 249, 47, 125, 232, 117, 43, 16, 42, 127, 20, 241,
25, 149, 105, 156, 51, 53, 168, 145, 247, 223, 79, 78, 226, 15, 222, 82, 115, 70, 210, 27, 41,
1, 170, 40, 131, 192, 229, 248, 255,
}
ROUND_CONSTANTS = [NUM_ROUNDS * STATE_SIZE]uint64{
// 1st round constants
1332676891236936200, 16607633045354064669, 12746538998793080786, 15240351333789289931,
10333439796058208418, 986873372968378050, 153505017314310505, 703086547770691416,
8522628845961587962, 1727254290898686320, 199492491401196126, 2969174933639985366,
1607536590362293391, 16971515075282501568, 15401316942841283351, 14178982151025681389,
// 2nd round constants
2916963588744282587, 5474267501391258599, 5350367839445462659, 7436373192934779388,
12563531800071493891, 12265318129758141428, 6524649031155262053, 1388069597090660214,
3049665785814990091, 5225141380721656276, 10399487208361035835, 6576713996114457203,
12913805829885867278, 10299910245954679423, 12980779960345402499, 593670858850716490,
// 3rd round constants
12184128243723146967, 1315341360419235257, 9107195871057030023, 4354141752578294067,
8824457881527486794, 14811586928506712910, 7768837314956434138, 2807636171572954860,
9487703495117094125, 13452575580428891895, 14689488045617615844, 16144091782672017853,
15471922440568867245, 17295382518415944107, 15054306047726632486, 5708955503115886019,
// 4th round constants
9596017237020520842, 16520851172964236909, 8513472793890943175, 8503326067026609602,
9402483918549940854, 8614816312698982446, 7744830563717871780, 14419404818700162041,
8090742384565069824, 15547662568163517559, 17314710073626307254, 10008393716631058961,
14480243402290327574, 13569194973291808551, 10573516815088946209, 15120483436559336219,
// 5th round constants
3515151310595301563, 1095382462248757907, 5323307938514209350, 14204542692543834582,
12448773944668684656, 13967843398310696452, 14838288394107326806, 13718313940616442191,
15032565440414177483, 13769903572116157488, 17074377440395071208, 16931086385239297738,
8723550055169003617, 590842605971518043, 16642348030861036090, 10708719298241282592,
// 6th round constants
12766914315707517909, 11780889552403245587, 113183285481780712, 9019899125655375514,
3300264967390964820, 12802381622653377935, 891063765000023873, 15939045541699412539,
3240223189948727743, 4087221142360949772, 10980466041788253952, 18199914337033135244,
7168108392363190150, 16860278046098150740, 13088202265571714855, 4712275036097525581,
// 7th round constants
16338034078141228133, 1455012125527134274, 5024057780895012002, 9289161311673217186,
9401110072402537104, 11919498251456187748, 4173156070774045271, 15647643457869530627,
15642078237964257476, 1405048341078324037, 3059193199283698832, 1605012781983592984,
7134876918849821827, 5796994175286958720, 7251651436095127661, 4565856221886323991,
}
MDS_MATRIX = [STATE_SIZE][STATE_SIZE]uint64{
{
61402, 17845, 26798, 59689, 12021, 40901, 41351, 27521, 56951, 12034, 53865, 43244, 7454,
33823, 28750, 1108,
},
{
1108, 61402, 17845, 26798, 59689, 12021, 40901, 41351, 27521, 56951, 12034, 53865, 43244,
7454, 33823, 28750,
},
{
28750, 1108, 61402, 17845, 26798, 59689, 12021, 40901, 41351, 27521, 56951, 12034, 53865,
43244, 7454, 33823,
},
{
33823, 28750, 1108, 61402, 17845, 26798, 59689, 12021, 40901, 41351, 27521, 56951, 12034,
53865, 43244, 7454,
},
{
7454, 33823, 28750, 1108, 61402, 17845, 26798, 59689, 12021, 40901, 41351, 27521, 56951,
12034, 53865, 43244,
},
{
43244, 7454, 33823, 28750, 1108, 61402, 17845, 26798, 59689, 12021, 40901, 41351, 27521,
56951, 12034, 53865,
},
{
53865, 43244, 7454, 33823, 28750, 1108, 61402, 17845, 26798, 59689, 12021, 40901, 41351,
27521, 56951, 12034,
},
{
12034, 53865, 43244, 7454, 33823, 28750, 1108, 61402, 17845, 26798, 59689, 12021, 40901,
41351, 27521, 56951,
},
{
56951, 12034, 53865, 43244, 7454, 33823, 28750, 1108, 61402, 17845, 26798, 59689, 12021,
40901, 41351, 27521,
},
{
27521, 56951, 12034, 53865, 43244, 7454, 33823, 28750, 1108, 61402, 17845, 26798, 59689,
12021, 40901, 41351,
},
{
41351, 27521, 56951, 12034, 53865, 43244, 7454, 33823, 28750, 1108, 61402, 17845, 26798,
59689, 12021, 40901,
},
{
40901, 41351, 27521, 56951, 12034, 53865, 43244, 7454, 33823, 28750, 1108, 61402, 17845,
26798, 59689, 12021,
},
{
12021, 40901, 41351, 27521, 56951, 12034, 53865, 43244, 7454, 33823, 28750, 1108, 61402,
17845, 26798, 59689,
},
{
59689, 12021, 40901, 41351, 27521, 56951, 12034, 53865, 43244, 7454, 33823, 28750, 1108,
61402, 17845, 26798,
},
{
26798, 59689, 12021, 40901, 41351, 27521, 56951, 12034, 53865, 43244, 7454, 33823, 28750,
1108, 61402, 17845,
},
{
17845, 26798, 59689, 12021, 40901, 41351, 27521, 56951, 12034, 53865, 43244, 7454, 33823,
28750, 1108, 61402,
},
}
INIT_SPONGE = [16]uint64{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
INIT_SPONGE_FIX = [16]uint64{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4294967295, 4294967295, 4294967295, 4294967295, 4294967295, 4294967295}
)
func Tip5HashBelts(input []Belt) [5]uint64 {
inputLen := len(input)
q := inputLen / RATE
r := inputLen % RATE
for i := range input {
if !BaseCheck(input[i].Value) {
fmt.Printf("element %d must be inside the field\n", i)
}
input[i].Value = montify(input[i].Value)
}
input = append(input, Belt{Value: montify(1)})
for i := 0; i < (RATE-r)-1; i++ {
input = append(input, Belt{Value: montify(0)})
}
sponge := INIT_SPONGE
inputAbsorb := input
cntQ := q
for {
scagInput := inputAbsorb[:RATE]
slagInput := inputAbsorb[RATE:]
for i := 0; i < RATE; i++ {
sponge[i] = scagInput[i].Value
}
sponge = permute(sponge)
if cntQ == 0 {
break
}
cntQ--
inputAbsorb = slagInput
}
digest := [DIGEST_LENGTH]uint64{0, 0, 0, 0, 0}
for i := 0; i < DIGEST_LENGTH; i++ {
digest[i] = montReduction(new(big.Int).SetUint64(sponge[i]))
}
return digest
}
func Tip5HashTenCell(input []Belt) [5]uint64 {
inputLen := len(input)
q := inputLen / RATE
r := inputLen % RATE
if q != 1 || r != 0 {
panic("input is not 10 cell")
}
for i := range input {
if !BaseCheck(input[i].Value) {
fmt.Printf("element %d must be inside the field\n", i)
}
input[i].Value = montify(input[i].Value)
}
sponge := INIT_SPONGE_FIX
for i := 0; i < RATE; i++ {
sponge[i] = input[i].Value
}
sponge = permute(sponge)
digest := [DIGEST_LENGTH]uint64{0, 0, 0, 0, 0}
for i := 0; i < DIGEST_LENGTH; i++ {
digest[i] = montReduction(new(big.Int).SetUint64(sponge[i]))
}
return digest
}
func Tip5RehashTenCell(hash1 [5]uint64, hash2 [5]uint64) [5]uint64 {
belts := []Belt{}
for _, i := range hash1 {
belts = append(belts, Belt{Value: i})
}
for _, i := range hash2 {
belts = append(belts, Belt{Value: i})
}
return Tip5HashTenCell(belts)
}
func permute(sponge [16]uint64) [16]uint64 {
res := sponge
for i := 0; i < NUM_ROUNDS; i++ {
a := sboxLayer(res)
b := linearLayer(a)
for j := 0; j < STATE_SIZE; j++ {
roundConst := new(big.Int).SetUint64(ROUND_CONSTANTS[i*STATE_SIZE+j])
product := new(big.Int).Mul(roundConst, R)
roundConst = roundConst.Mod(product, PRIME_128)
res[j] = badd(roundConst.Uint64(), b[j])
}
}
return res
}
func Tip5HashToBase58(hash [5]uint64) string {
result := big.NewInt(0)
for i, value := range hash {
result.Add(result, new(big.Int).Mul(new(big.Int).SetUint64(value), new(big.Int).Exp(PRIME_128, big.NewInt(int64(i)), nil)))
}
return base58.Encode(result.Bytes())
}
func Base58ToTip5Hash(data string) [5]uint64 {
dataBigInt := new(big.Int).SetBytes(base58.Decode(data))
result := [5]uint64{}
for i := 0; i < 5; i++ {
resultBigInt := new(big.Int)
result[i] = resultBigInt.Mod(dataBigInt, PRIME_128).Uint64()
dataBigInt.Div(dataBigInt, PRIME_128)
}
return result
}
func TruncGOrder(a [5]uint64) *big.Int {
dataBigInt := new(big.Int).SetUint64(a[0])
dataBigInt.Add(dataBigInt, new(big.Int).Mul(P_BIG, new(big.Int).SetUint64(a[1])))
dataBigInt.Add(dataBigInt, new(big.Int).Mul(P_BIG_2, new(big.Int).SetUint64(a[2])))
dataBigInt.Add(dataBigInt, new(big.Int).Mul(P_BIG_3, new(big.Int).SetUint64(a[3])))
return dataBigInt.Mod(dataBigInt, G_ORDER)
}
func sboxLayer(state [16]uint64) [16]uint64 {
res := INIT_SPONGE
for i := 0; i < NUM_SPLIT_AND_LOOKUP; i++ {
bytes := make([]byte, 8)
binary.LittleEndian.PutUint64(bytes, state[i])
for j := 0; j < 8; j++ {
bytes[j] = LOOKUP_TABLE[bytes[j]]
}
res[i] = binary.LittleEndian.Uint64(bytes)
}
for i := NUM_SPLIT_AND_LOOKUP; i < STATE_SIZE; i++ {
res[i] = bpow(state[i], 7)
}
return res
}
func linearLayer(state [16]uint64) [16]uint64 {
res := INIT_SPONGE
for i := 0; i < 16; i++ {
for j := 0; j < 16; j++ {
matrixElement := MDS_MATRIX[i][j]
product := bmul(matrixElement, state[j])
res[i] = badd(res[i], product)
}
}
return res
}