nockchain-grpc/wallet/nockhash.go

519 lines
17 KiB
Go
Raw Normal View History

2025-10-06 13:38:53 +07:00
package wallet
import (
"fmt"
2025-10-06 13:38:53 +07:00
"math/big"
"github.com/btcsuite/btcd/btcutil/base58"
"github.com/phamminh0811/private-grpc/crypto"
"github.com/phamminh0811/private-grpc/nockchain"
)
2025-11-07 11:16:19 +07:00
var (
MerkleHash = [5]uint64{7971649669803894685, 16663670492333541326, 11038715785817710450, 18178011379925321681, 17049062282971338707}
)
2025-10-06 13:38:53 +07:00
func HashPubkey(pkPoint crypto.CheetahPoint) [5]uint64 {
belts := []crypto.Belt{{Value: 13}}
belts = append(belts, pkPoint.X[:]...)
belts = append(belts, pkPoint.Y[:]...)
belts = append(belts, crypto.BELT_ONE)
for _, i := range crypto.MagicDyckForPoint {
belts = append(belts, crypto.Belt{Value: i})
}
return crypto.Tip5HashBelts(belts)
}
2025-11-07 11:16:19 +07:00
func HashSignatureV0(signature *nockchain.NockchainSignature) ([5]uint64, error) {
2025-10-06 13:38:53 +07:00
belts := []crypto.Belt{{Value: 16}}
for _, i := range signature.Chal {
belts = append(belts, crypto.Belt{Value: i})
}
for _, i := range signature.Sig {
belts = append(belts, crypto.Belt{Value: i})
}
for _, i := range crypto.MagicDyckForT8 {
belts = append(belts, crypto.Belt{Value: i})
}
sigHash := crypto.Tip5HashBelts(belts)
pkPoint, err := crypto.CheetaPointFromBytes(base58.Decode(signature.Pubkey))
if err != nil {
return [5]uint64{}, err
}
pkHash := HashPubkey(pkPoint)
sigHash = crypto.Tip5RehashTenCell(pkHash, sigHash)
2025-11-04 10:38:31 +07:00
return crypto.Tip5RehashTenCell(sigHash, crypto.Tip5ZeroZero), nil
2025-10-06 13:38:53 +07:00
}
2025-11-07 11:16:19 +07:00
func HashSignatureV1(signature *nockchain.NockchainSignature) ([5]uint64, error) {
belts := []crypto.Belt{{Value: 16}}
for _, i := range signature.Chal {
belts = append(belts, crypto.Belt{Value: i})
}
for _, i := range signature.Sig {
belts = append(belts, crypto.Belt{Value: i})
}
for _, i := range crypto.MagicDyckForT8 {
belts = append(belts, crypto.Belt{Value: i})
}
sigHash := crypto.Tip5HashBelts(belts)
pkPoint, err := crypto.CheetaPointFromBytes(base58.Decode(signature.Pubkey))
if err != nil {
return [5]uint64{}, err
}
pkHash := HashPubkey(pkPoint)
sigHash = crypto.Tip5RehashTenCell(pkHash, sigHash)
pkHashSig := crypto.Tip5RehashTenCell(pkHash, sigHash)
return crypto.Tip5RehashTenCell(pkHashSig, crypto.Tip5ZeroZero), nil
}
func HashWitness(witness *nockchain.NockchainWitness) ([5]uint64, error) {
spendConditionHash := HashLock(witness.Lmp.SpendCondition)
rootHash := crypto.Base58ToTip5Hash(witness.Lmp.MerkleRoot)
rootHashZero := crypto.Tip5RehashTenCell(rootHash, crypto.Tip5Zero)
axisHashRoot := crypto.Tip5RehashTenCell(MerkleHash, rootHashZero)
lmpHash := crypto.Tip5RehashTenCell(spendConditionHash, axisHashRoot)
sigHash, err := HashSignatureV1(witness.Pkh[0])
if err != nil {
return [5]uint64{}, err
}
sigHashZeroZero := crypto.Tip5RehashTenCell(sigHash, crypto.Tip5ZeroZero)
return crypto.Tip5RehashTenCell(lmpHash, sigHashZeroZero), nil
}
2025-11-04 10:38:31 +07:00
func HashNoteData(lock *nockchain.NockchainLock) [5]uint64 {
keysRequiredHash := crypto.Tip5HashLeaf(lock.KeysRequired)
// TODO: handle multisig
finalHash := crypto.Base58ToTip5Hash(lock.Pubkeys[lock.KeysRequired-1])
hash := crypto.Tip5RehashTenCell(crypto.Tip5HashLeaf(finalHash[3]), crypto.Tip5HashLeaf(finalHash[4]))
hash = crypto.Tip5RehashTenCell(crypto.Tip5HashLeaf(finalHash[2]), hash)
hash = crypto.Tip5RehashTenCell(crypto.Tip5HashLeaf(finalHash[1]), hash)
hash = crypto.Tip5RehashTenCell(crypto.Tip5HashLeaf(finalHash[0]), hash)
hash = crypto.Tip5RehashTenCell(hash, crypto.Tip5ZeroZero)
pkh := crypto.Tip5RehashTenCell(keysRequiredHash, hash)
pkhWithPkhTag := crypto.Tip5RehashTenCell(crypto.PkhTagTip5Hash, pkh)
pkhWithPkhTag = crypto.Tip5RehashTenCell(pkhWithPkhTag, crypto.Tip5Zero)
pkhWithPkhTag = crypto.Tip5RehashTenCell(crypto.Tip5Zero, pkhWithPkhTag)
pkhWithPkhLockTag := crypto.Tip5RehashTenCell(crypto.LockTagTip5Hash, pkhWithPkhTag)
return crypto.Tip5RehashTenCell(pkhWithPkhLockTag, crypto.Tip5ZeroZero)
}
2025-10-06 13:38:53 +07:00
func HashOwner(pkPoint crypto.CheetahPoint) [5]uint64 {
pkHashedBelts := HashPubkey(pkPoint)
pkHashedZeroZero := crypto.Tip5RehashTenCell(pkHashedBelts, crypto.Tip5ZeroZero)
return crypto.Tip5RehashTenCell(crypto.Tip5One, pkHashedZeroZero)
}
2025-11-07 11:16:19 +07:00
func NockFirstName(ownerHash [5]uint64) [5]uint64 {
ownerHashZero := crypto.Tip5RehashTenCell(ownerHash, crypto.Tip5Zero)
ownerHashZeroOne := crypto.Tip5RehashTenCell(crypto.Tip5One, ownerHashZero)
return crypto.Tip5RehashTenCell(crypto.Tip5Zero, ownerHashZeroOne)
2025-10-06 13:38:53 +07:00
}
func HashName(name *nockchain.NockchainName) [5]uint64 {
firstNameHash := crypto.Base58ToTip5Hash(name.First)
lastNameHash := crypto.Base58ToTip5Hash(name.Last)
return crypto.Tip5RehashTenCell(firstNameHash, crypto.Tip5RehashTenCell(lastNameHash, crypto.Tip5Zero))
}
2025-10-22 08:44:24 +07:00
func HashNameVarLen(name *nockchain.NockchainName) [5]uint64 {
belts := []crypto.Belt{}
for _, i := range crypto.Base58ToTip5Hash(name.First) {
belts = append(belts, crypto.Belt{Value: i})
}
for _, i := range crypto.Base58ToTip5Hash(name.Last) {
belts = append(belts, crypto.Belt{Value: i})
}
belts = append(belts, crypto.BELT_ZERO)
size := len(belts)
belts = append([]crypto.Belt{{Value: uint64(size)}}, belts...)
for _, i := range crypto.MagicDyckForName {
belts = append(belts, crypto.Belt{Value: i})
}
res := crypto.Tip5HashBelts(belts)
return res
}
2025-11-04 10:38:31 +07:00
func HashNoteV0(note *nockchain.NockchainNoteV0) ([5]uint64, error) {
2025-10-06 13:38:53 +07:00
versionHash := crypto.Tip5HashBelts([]crypto.Belt{{Value: 1}, {Value: uint64(note.Version)}})
2025-11-04 10:38:31 +07:00
blockHash := crypto.Tip5HashBelts([]crypto.Belt{{Value: 1}, {Value: note.OriginPage}})
hashBlockTimeLock := crypto.Tip5RehashTenCell(blockHash, crypto.Tip5Zero)
2025-10-06 13:38:53 +07:00
p := crypto.Tip5RehashTenCell(versionHash, hashBlockTimeLock)
nameHash := HashName(note.Name)
2025-11-04 10:38:31 +07:00
lockHash, err := HashLockV0(note.Lock)
2025-10-06 13:38:53 +07:00
if err != nil {
return [5]uint64{}, err
}
sourceHash := HashSource(note.Source)
assetHash := crypto.Tip5HashBelts([]crypto.Belt{{Value: 1}, {Value: uint64(note.Asset)}})
hashSourceAsset := crypto.Tip5RehashTenCell(sourceHash, assetHash)
q := crypto.Tip5RehashTenCell(nameHash, crypto.Tip5RehashTenCell(lockHash, hashSourceAsset))
return crypto.Tip5RehashTenCell(p, q), nil
}
2025-11-07 11:16:19 +07:00
func HashNoteV1(note *nockchain.NockchainNoteV1) [5]uint64 {
versionHash := crypto.Tip5HashBelts([]crypto.Belt{{Value: 1}, {Value: uint64(note.Version)}})
blockHash := crypto.Tip5HashBelts([]crypto.Belt{{Value: 1}, {Value: note.OriginPage}})
nameHash := HashName(note.Name)
noteDataHash := HashNoteData(note.NoteData)
assetHash := crypto.Tip5HashBelts([]crypto.Belt{{Value: 1}, {Value: uint64(note.Assets)}})
hashNoteDataAsset := crypto.Tip5RehashTenCell(noteDataHash, assetHash)
hashNameNoteDataAsset := crypto.Tip5RehashTenCell(nameHash, hashNoteDataAsset)
q := crypto.Tip5RehashTenCell(blockHash, hashNameNoteDataAsset)
return crypto.Tip5RehashTenCell(versionHash, q)
}
2025-10-06 13:38:53 +07:00
func HashTimelockIntent(timelock *nockchain.TimelockIntent) [5]uint64 {
if timelock == nil {
return crypto.Tip5Zero
}
if timelock.Absolute == nil && timelock.Relative == nil {
return crypto.Tip5ZeroZero
}
absoluteHash := HashTimelockRange(timelock.Absolute)
relativeHash := HashTimelockRange(timelock.Relative)
return crypto.Tip5RehashTenCell(absoluteHash, relativeHash)
}
func HashTimelockRange(timelockRange *nockchain.TimelockRange) [5]uint64 {
hash := crypto.Tip5Zero
if timelockRange != nil {
minHash := crypto.Tip5Zero
if timelockRange.Min != nil {
minHash = crypto.Tip5HashBelts([]crypto.Belt{{Value: 1}, {Value: timelockRange.Min.Value}})
}
maxHash := crypto.Tip5Zero
if timelockRange.Max != nil {
maxHash = crypto.Tip5HashBelts([]crypto.Belt{{Value: 1}, {Value: timelockRange.Max.Value}})
}
hash = crypto.Tip5RehashTenCell(minHash, maxHash)
}
return hash
}
2025-11-04 10:38:31 +07:00
func HashLockV0(lock *nockchain.NockchainLock) ([5]uint64, error) {
2025-10-06 13:38:53 +07:00
keysRequiredHash := crypto.Tip5HashBelts([]crypto.Belt{{Value: 1}, {Value: lock.KeysRequired}})
finalPk := base58.Decode(lock.Pubkeys[lock.KeysRequired-1])
finalPkPoint, err := crypto.CheetaPointFromBytes(finalPk)
if err != nil {
return [5]uint64{}, err
}
finalPkHash := HashPubkey(finalPkPoint)
finalHash := crypto.Tip5RehashTenCell(finalPkHash, crypto.Tip5ZeroZero)
if lock.KeysRequired != 1 {
for i := uint64(1); i < lock.KeysRequired; i++ {
pk := base58.Decode(lock.Pubkeys[lock.KeysRequired-1-i])
pkPoint, err := crypto.CheetaPointFromBytes(pk)
if err != nil {
return [5]uint64{}, err
}
pkHash := HashPubkey(pkPoint)
finalHash = crypto.Tip5RehashTenCell(pkHash, finalHash)
}
}
return crypto.Tip5RehashTenCell(keysRequiredHash, finalHash), nil
}
2025-11-04 10:38:31 +07:00
func HashLock(lock *nockchain.NockchainLock) [5]uint64 {
keysRequiredHash := crypto.Tip5HashBelts([]crypto.Belt{{Value: 1}, {Value: lock.KeysRequired}})
pkh := crypto.Base58ToTip5Hash(lock.Pubkeys[lock.KeysRequired-1])
finalHash := crypto.Tip5RehashTenCell(pkh, crypto.Tip5ZeroZero)
if lock.KeysRequired != 1 {
for i := uint64(1); i < lock.KeysRequired; i++ {
pkh := crypto.Base58ToTip5Hash(lock.Pubkeys[lock.KeysRequired-1-i])
finalHash = crypto.Tip5RehashTenCell(pkh, finalHash)
}
}
lockHash := crypto.Tip5RehashTenCell(keysRequiredHash, finalHash)
lockHashWithTag := crypto.Tip5RehashTenCell(crypto.PkhTagTip5Hash, lockHash)
return crypto.Tip5RehashTenCell(lockHashWithTag, crypto.Tip5Zero)
}
2025-10-06 13:38:53 +07:00
func HashSource(source *nockchain.NockchainSource) [5]uint64 {
if source == nil {
return crypto.Tip5Zero
}
sourceHash := crypto.Base58ToTip5Hash(source.Source)
2025-10-09 11:06:46 +07:00
return crypto.Tip5RehashTenCell(sourceHash, crypto.Tip5One)
2025-10-06 13:38:53 +07:00
}
2025-11-07 11:16:19 +07:00
func HashSeedWithoutSource(seed *nockchain.NockchainSeed) [5]uint64 {
2025-11-04 10:38:31 +07:00
lockRoot := crypto.Base58ToTip5Hash(seed.LockRoot)
2025-10-06 13:38:53 +07:00
assetHash := crypto.Tip5HashBelts([]crypto.Belt{{Value: 1}, {Value: seed.Gift}})
parentHash := crypto.Base58ToTip5Hash(seed.ParentHash)
assetHashparentHash := crypto.Tip5RehashTenCell(assetHash, parentHash)
2025-11-04 10:38:31 +07:00
noteDataHash := HashNoteData(seed.NoteData)
noteDataHashAssetParentHash := crypto.Tip5RehashTenCell(noteDataHash, assetHashparentHash)
2025-10-06 13:38:53 +07:00
2025-11-04 10:38:31 +07:00
seedHash := crypto.Tip5RehashTenCell(lockRoot, noteDataHashAssetParentHash)
return seedHash
2025-10-06 13:38:53 +07:00
}
2025-11-07 11:16:19 +07:00
func HashSeed(seed *nockchain.NockchainSeed) [5]uint64 {
2025-11-04 10:38:31 +07:00
seedHash := HashSeedWithoutSource(seed)
2025-10-06 13:38:53 +07:00
sourceHash := HashSource(seed.OutputSource)
2025-11-04 10:38:31 +07:00
return crypto.Tip5RehashTenCell(sourceHash, seedHash)
2025-10-06 13:38:53 +07:00
}
2025-11-07 11:16:19 +07:00
func HashSeedVarLen(seed *nockchain.NockchainSeed) [5]uint64 {
2025-10-15 08:00:31 +07:00
belts := []crypto.Belt{{Value: 0}}
2025-11-04 10:38:31 +07:00
lockRoot := crypto.Base58ToTip5Hash(seed.LockRoot)
for _, i := range lockRoot {
belts = append(belts, crypto.Belt{Value: i})
}
// %lock and %pkh tag
belts = append(belts, []crypto.Belt{{Value: 1801678700}, {Value: 0}, {Value: 6843248}}...)
belts = append(belts, crypto.Belt{Value: seed.NoteData.KeysRequired})
for _, pk := range seed.NoteData.Pubkeys {
pkHash := crypto.Base58ToTip5Hash(pk)
for _, i := range pkHash {
belts = append(belts, crypto.Belt{Value: i})
2025-10-15 08:00:31 +07:00
}
}
2025-11-04 10:38:31 +07:00
belts = append(belts, []crypto.Belt{{Value: 0}, {Value: 0}, {Value: 0}, {Value: 0}, {Value: 0}, {Value: seed.Gift}}...)
2025-10-15 08:00:31 +07:00
parentHash := crypto.Base58ToTip5Hash(seed.ParentHash)
for _, i := range parentHash {
belts = append(belts, crypto.Belt{Value: i})
}
size := len(belts)
belts = append([]crypto.Belt{{Value: uint64(size)}}, belts...)
for _, i := range crypto.MagicDyckForSeed {
belts = append(belts, crypto.Belt{Value: i})
}
2025-11-04 10:38:31 +07:00
return crypto.Tip5HashBelts(belts)
2025-10-15 08:00:31 +07:00
}
2025-11-04 10:38:31 +07:00
func HashNonce(pkPoint crypto.CheetahPoint, message [5]uint64, privKey []byte) ([]crypto.Belt, [5]uint64) {
privKeyBigInt := new(big.Int).SetBytes(privKey)
privKeyT8 := crypto.BigIntToT8(*privKeyBigInt)
2025-10-06 13:38:53 +07:00
belts := []crypto.Belt{}
for _, belt := range pkPoint.X {
belts = append(belts, belt)
}
for _, belt := range pkPoint.Y {
belts = append(belts, belt)
}
for _, belt := range message {
belts = append(belts, crypto.Belt{Value: belt})
}
2025-11-04 10:38:31 +07:00
2025-10-06 13:38:53 +07:00
resBelts := make([]crypto.Belt, len(belts))
copy(resBelts, belts)
2025-11-04 10:38:31 +07:00
for _, belt := range privKeyT8 {
belts = append(belts, crypto.Belt{Value: belt})
}
2025-10-06 13:38:53 +07:00
return resBelts, crypto.Tip5HashBelts(belts)
}
2025-11-04 10:38:31 +07:00
func HashSpendV0(spend *nockchain.NockchainSpendV0) ([5]uint64, error) {
2025-10-06 13:38:53 +07:00
// TODO: handle multiple sig
if len(spend.Signatures) == 0 {
return [5]uint64{}, fmt.Errorf("signatures can not be empty")
}
2025-11-07 11:16:19 +07:00
sigHash, err := HashSignatureV0(spend.Signatures[0])
if err != nil {
return [5]uint64{}, err
}
seedHashFee, err := HashSeedsAndFee(spend.Seeds, spend.Fee)
if err != nil {
return [5]uint64{}, err
}
return crypto.Tip5RehashTenCell(sigHash, seedHashFee), nil
}
func HashSpendV1(spend *nockchain.NockchainSpendV1) ([5]uint64, error) {
if len(spend.Witness) == 0 {
return [5]uint64{}, fmt.Errorf("witness can not be empty")
}
witnessHash, err := HashWitness(spend.Witness[0])
2025-10-06 13:38:53 +07:00
if err != nil {
return [5]uint64{}, err
}
2025-11-07 11:16:19 +07:00
seedHashFee, err := HashSeedsAndFee(spend.Seeds, spend.Fee)
if err != nil {
return [5]uint64{}, err
}
return crypto.Tip5RehashTenCell(witnessHash, seedHashFee), nil
}
func HashMsg(seeds []*nockchain.NockchainSeed, fee uint64) ([5]uint64, error) {
2025-10-22 08:44:24 +07:00
seedsTree := NewZTree(
func(i interface{}) [5]uint64 {
2025-11-07 11:16:19 +07:00
if seed, ok := i.(*nockchain.NockchainSeed); ok {
2025-11-04 10:38:31 +07:00
return HashSeedVarLen(seed)
2025-10-15 08:00:31 +07:00
} else {
2025-10-22 08:44:24 +07:00
return [5]uint64{}
2025-10-15 08:00:31 +07:00
}
2025-10-22 08:44:24 +07:00
},
func(i interface{}) ([5]uint64, error) {
2025-11-07 11:16:19 +07:00
if seed, ok := i.(*nockchain.NockchainSeed); ok {
return HashSeed(seed), nil
2025-10-15 08:00:31 +07:00
} else {
2025-10-22 08:44:24 +07:00
return [5]uint64{}, fmt.Errorf("invalid input type")
2025-10-06 13:38:53 +07:00
}
2025-10-22 08:44:24 +07:00
},
)
2025-11-07 11:16:19 +07:00
for _, seed := range seeds {
2025-10-22 08:44:24 +07:00
seedsTree.Insert(seed, seed)
}
finalSeedHash, err := seedsTree.Hash()
if err != nil {
return [5]uint64{}, err
2025-10-06 13:38:53 +07:00
}
2025-11-07 11:16:19 +07:00
feeHash := crypto.Tip5HashBelts([]crypto.Belt{{Value: 1}, {Value: fee}})
return crypto.Tip5RehashTenCell(finalSeedHash, feeHash), nil
2025-10-06 13:38:53 +07:00
}
2025-11-07 11:16:19 +07:00
func HashSeedsAndFee(seeds []*nockchain.NockchainSeed, fee uint64) ([5]uint64, error) {
2025-10-22 08:44:24 +07:00
seedsTree := NewZTree(
func(i interface{}) [5]uint64 {
2025-11-07 11:16:19 +07:00
if seed, ok := i.(*nockchain.NockchainSeed); ok {
2025-11-04 10:38:31 +07:00
return HashSeedVarLen(seed)
2025-10-15 08:00:31 +07:00
} else {
2025-10-22 08:44:24 +07:00
return [5]uint64{}
2025-10-15 08:00:31 +07:00
}
2025-10-22 08:44:24 +07:00
},
func(i interface{}) ([5]uint64, error) {
2025-11-07 11:16:19 +07:00
if seed, ok := i.(*nockchain.NockchainSeed); ok {
return HashSeedWithoutSource(seed), nil
2025-10-15 08:00:31 +07:00
} else {
2025-10-22 08:44:24 +07:00
return [5]uint64{}, fmt.Errorf("invalid input type")
2025-10-06 18:18:19 +07:00
}
2025-10-22 08:44:24 +07:00
},
)
2025-11-07 11:16:19 +07:00
for _, seed := range seeds {
2025-10-22 08:44:24 +07:00
seedsTree.Insert(seed, seed)
}
finalSeedHash, err := seedsTree.Hash()
if err != nil {
return [5]uint64{}, err
2025-10-06 18:18:19 +07:00
}
2025-11-07 11:16:19 +07:00
feeHash := crypto.Tip5HashBelts([]crypto.Belt{{Value: 1}, {Value: fee}})
2025-10-06 18:18:19 +07:00
return crypto.Tip5RehashTenCell(finalSeedHash, feeHash), nil
}
2025-11-04 10:38:31 +07:00
func ComputeTxId(spends []*nockchain.NockchainNamedSpend, version uint64) ([5]uint64, error) {
var spendHash [5]uint64
var err error
switch version {
case 0:
spendTree := NewZTree(
func(i interface{}) [5]uint64 {
if name, ok := i.(*nockchain.NockchainName); ok {
return HashNameVarLen(name)
} else {
return [5]uint64{}
}
},
func(i interface{}) ([5]uint64, error) {
if spendEntry, ok := i.(*nockchain.NockchainNamedSpend); ok {
nameHash := HashName(spendEntry.Name)
spendV0Hash, err := HashSpendV0(spendEntry.GetLegacy())
if err != nil {
return [5]uint64{}, fmt.Errorf("error hashing spend: %v", err)
}
zeroHashspend := crypto.Tip5RehashTenCell(crypto.Tip5Zero, spendV0Hash)
return crypto.Tip5RehashTenCell(nameHash, zeroHashspend), nil
} else {
return [5]uint64{}, fmt.Errorf("invalid input type")
}
},
)
for _, spend := range spends {
spendTree.Insert(spend.Name, spend)
}
spendHash, err = spendTree.Hash()
if err != nil {
return [5]uint64{}, fmt.Errorf("error hashing spends: %v", err)
}
2025-11-07 11:16:19 +07:00
case 1:
spendTree := NewZTree(
func(i interface{}) [5]uint64 {
if name, ok := i.(*nockchain.NockchainName); ok {
return HashNameVarLen(name)
} else {
return [5]uint64{}
}
},
func(i interface{}) ([5]uint64, error) {
if spendEntry, ok := i.(*nockchain.NockchainNamedSpend); ok {
nameHash := HashName(spendEntry.Name)
spendV1Hash, err := HashSpendV1(spendEntry.GetWitness())
if err != nil {
return [5]uint64{}, fmt.Errorf("error hashing spend: %v", err)
}
oneHashspend := crypto.Tip5RehashTenCell(crypto.Tip5One, spendV1Hash)
return crypto.Tip5RehashTenCell(nameHash, oneHashspend), nil
} else {
return [5]uint64{}, fmt.Errorf("invalid input type")
}
},
)
for _, spend := range spends {
spendTree.Insert(spend.Name, spend)
}
spendHash, err = spendTree.Hash()
if err != nil {
return [5]uint64{}, fmt.Errorf("error hashing spends: %v", err)
}
2025-11-04 10:38:31 +07:00
default:
return [5]uint64{}, fmt.Errorf("unsupported version %d", version)
2025-10-06 13:38:53 +07:00
}
2025-11-04 10:38:31 +07:00
return crypto.Tip5RehashTenCell(crypto.Tip5One, spendHash), nil
2025-10-06 13:38:53 +07:00
}
func ComputeSig(m crypto.MasterKey, msg [5]uint64) ([8]uint64, [8]uint64, error) {
pkPoint, err := crypto.CheetaPointFromBytes(m.PublicKey)
if err != nil {
return [8]uint64{}, [8]uint64{}, err
}
2025-11-04 10:38:31 +07:00
belts, nonce := HashNonce(pkPoint, msg, m.PrivateKey)
2025-10-06 13:38:53 +07:00
nonceBigInt := crypto.TruncGOrder(nonce)
scalar := crypto.CheetahScaleBig(crypto.A_GEN, *nonceBigInt)
scalarBelts := []crypto.Belt{}
scalarBelts = append(scalarBelts, scalar.X[:]...)
scalarBelts = append(scalarBelts, scalar.Y[:]...)
belts = append(scalarBelts, belts...)
chal := crypto.Tip5HashBelts(belts)
chalBigInt := crypto.TruncGOrder(chal)
skBigInt := new(big.Int).SetBytes(m.PrivateKey)
sig := new(big.Int).Mul(chalBigInt, skBigInt)
sig.Add(sig, nonceBigInt)
sig.Mod(sig, crypto.G_ORDER)
chalT8 := crypto.BigIntToT8(*chalBigInt)
sigT8 := crypto.BigIntToT8(*sig)
return chalT8, sigT8, nil
}