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 }