2025-10-06 13:38:53 +07:00
|
|
|
package wallet
|
|
|
|
|
|
|
|
import (
|
2025-10-07 09:30:49 +07:00
|
|
|
"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"
|
|
|
|
)
|
|
|
|
|
|
|
|
var LastName = [5]uint64{9541855607561054508, 12383849149342406623, 11220017934615522559, 678840671137489369, 8985908938884028381}
|
|
|
|
|
|
|
|
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)
|
|
|
|
}
|
|
|
|
|
|
|
|
func HashSignature(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)
|
|
|
|
sigHash = crypto.Tip5RehashTenCell(sigHash, crypto.Tip5ZeroZero)
|
|
|
|
return crypto.Tip5RehashTenCell(crypto.Tip5Zero, sigHash), nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func HashOwner(pkPoint crypto.CheetahPoint) [5]uint64 {
|
|
|
|
pkHashedBelts := HashPubkey(pkPoint)
|
|
|
|
pkHashedZeroZero := crypto.Tip5RehashTenCell(pkHashedBelts, crypto.Tip5ZeroZero)
|
|
|
|
return crypto.Tip5RehashTenCell(crypto.Tip5One, pkHashedZeroZero)
|
|
|
|
}
|
|
|
|
|
|
|
|
func NockName(ownerHash [5]uint64) ([5]uint64, [5]uint64) {
|
|
|
|
firstName := first(ownerHash)
|
|
|
|
return firstName, LastName
|
|
|
|
}
|
|
|
|
|
|
|
|
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))
|
|
|
|
}
|
|
|
|
|
|
|
|
func HashNote(note *nockchain.NockchainNote) ([5]uint64, error) {
|
|
|
|
versionHash := crypto.Tip5HashBelts([]crypto.Belt{{Value: 1}, {Value: uint64(note.Version)}})
|
|
|
|
blockHash := crypto.Tip5HashBelts([]crypto.Belt{{Value: 1}, {Value: note.BlockHeight}})
|
|
|
|
timelockHash := HashTimelockIntent(note.Timelock)
|
|
|
|
hashBlockTimeLock := crypto.Tip5RehashTenCell(blockHash, timelockHash)
|
|
|
|
|
|
|
|
p := crypto.Tip5RehashTenCell(versionHash, hashBlockTimeLock)
|
|
|
|
nameHash := HashName(note.Name)
|
|
|
|
lockHash, err := HashLock(note.Lock)
|
|
|
|
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
|
|
|
|
}
|
|
|
|
|
|
|
|
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
|
|
|
|
}
|
|
|
|
func HashLock(lock *nockchain.NockchainLock) ([5]uint64, error) {
|
|
|
|
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
|
|
|
|
}
|
|
|
|
|
|
|
|
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
|
|
|
}
|
|
|
|
|
|
|
|
func HashSeedWithoutSource(seed *nockchain.NockchainSeed) ([5]uint64, error) {
|
|
|
|
lockHash, err := HashLock(seed.Recipient)
|
|
|
|
if err != nil {
|
|
|
|
return [5]uint64{}, nil
|
|
|
|
}
|
|
|
|
timelockIntentHash := HashTimelockIntent(seed.TimelockIntent)
|
|
|
|
assetHash := crypto.Tip5HashBelts([]crypto.Belt{{Value: 1}, {Value: seed.Gift}})
|
|
|
|
|
|
|
|
parentHash := crypto.Base58ToTip5Hash(seed.ParentHash)
|
|
|
|
assetHashparentHash := crypto.Tip5RehashTenCell(assetHash, parentHash)
|
|
|
|
|
|
|
|
timelockHashAssetParentHash := crypto.Tip5RehashTenCell(timelockIntentHash, assetHashparentHash)
|
|
|
|
|
|
|
|
seedHash := crypto.Tip5RehashTenCell(lockHash, timelockHashAssetParentHash)
|
|
|
|
return seedHash, nil
|
|
|
|
}
|
|
|
|
func HashSeed(seed *nockchain.NockchainSeed) ([5]uint64, error) {
|
|
|
|
seedHash, err := HashSeedWithoutSource(seed)
|
|
|
|
if err != nil {
|
|
|
|
return [5]uint64{}, nil
|
|
|
|
}
|
|
|
|
sourceHash := HashSource(seed.OutputSource)
|
|
|
|
return crypto.Tip5RehashTenCell(sourceHash, seedHash), nil
|
|
|
|
}
|
|
|
|
|
2025-10-15 08:00:31 +07:00
|
|
|
func HashSeedVarLen(seed *nockchain.NockchainSeed) ([5]uint64, error) {
|
|
|
|
belts := []crypto.Belt{{Value: 0}}
|
|
|
|
belts = append(belts, crypto.Belt{Value: seed.Recipient.KeysRequired})
|
|
|
|
for _, pk := range seed.Recipient.Pubkeys {
|
|
|
|
pkPoint, err := crypto.CheetaPointFromBytes(base58.Decode(pk))
|
|
|
|
if err != nil {
|
|
|
|
return [5]uint64{}, err
|
|
|
|
}
|
|
|
|
belts = append(belts, pkPoint.X[:]...)
|
|
|
|
belts = append(belts, pkPoint.Y[:]...)
|
|
|
|
}
|
|
|
|
belts = append(belts, []crypto.Belt{{Value: 1}, {Value: 0}, {Value: 0}, {Value: 0}, {Value: seed.Gift}}...)
|
|
|
|
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})
|
|
|
|
}
|
|
|
|
return crypto.Tip5HashBelts(belts), nil
|
|
|
|
}
|
2025-10-06 13:38:53 +07:00
|
|
|
func HashNonce(pkPoint crypto.CheetahPoint, message [5]uint64) ([]crypto.Belt, [5]uint64) {
|
|
|
|
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})
|
|
|
|
}
|
|
|
|
resBelts := make([]crypto.Belt, len(belts))
|
|
|
|
copy(resBelts, belts)
|
|
|
|
return resBelts, crypto.Tip5HashBelts(belts)
|
|
|
|
}
|
|
|
|
|
|
|
|
func HashSpend(spend *nockchain.NockchainSpend) ([5]uint64, error) {
|
|
|
|
// TODO: handle multiple sig
|
2025-10-07 09:30:49 +07:00
|
|
|
if len(spend.Signatures) == 0 {
|
|
|
|
return [5]uint64{}, fmt.Errorf("signatures can not be empty")
|
|
|
|
}
|
|
|
|
|
2025-10-06 13:38:53 +07:00
|
|
|
sigHash, err := HashSignature(spend.Signatures[0])
|
|
|
|
if err != nil {
|
|
|
|
return [5]uint64{}, err
|
|
|
|
}
|
|
|
|
seedsCount := len(spend.Seeds)
|
2025-10-15 08:00:31 +07:00
|
|
|
var finalSeedHash [5]uint64
|
|
|
|
if seedsCount == 1 {
|
|
|
|
seedHash, err := HashSeedWithoutSource(spend.Seeds[0])
|
|
|
|
if err != nil {
|
|
|
|
return [5]uint64{}, err
|
|
|
|
}
|
2025-10-06 13:38:53 +07:00
|
|
|
|
2025-10-15 08:00:31 +07:00
|
|
|
finalSeedHash = crypto.Tip5RehashTenCell(seedHash, crypto.Tip5ZeroZero)
|
|
|
|
} else {
|
|
|
|
seed1Hash, err := HashSeedWithoutSource(spend.Seeds[0])
|
|
|
|
if err != nil {
|
|
|
|
return [5]uint64{}, err
|
|
|
|
}
|
|
|
|
seed1HashVarLen, err := HashSeedVarLen(spend.Seeds[0])
|
|
|
|
if err != nil {
|
|
|
|
return [5]uint64{}, err
|
|
|
|
}
|
|
|
|
seed1DoubleHash := crypto.Tip5RehashTenCell(seed1HashVarLen, seed1HashVarLen)
|
|
|
|
seed2Hash, err := HashSeedWithoutSource(spend.Seeds[1])
|
|
|
|
if err != nil {
|
|
|
|
return [5]uint64{}, err
|
|
|
|
}
|
|
|
|
seed2HashVarLen, err := HashSeedVarLen(spend.Seeds[1])
|
|
|
|
if err != nil {
|
|
|
|
return [5]uint64{}, err
|
|
|
|
}
|
|
|
|
seed2DoubleHash := crypto.Tip5RehashTenCell(seed2HashVarLen, seed2HashVarLen)
|
|
|
|
|
|
|
|
seedHash1BigInt := new(big.Int).SetBytes(base58.Decode(crypto.Tip5HashToBase58(seed1HashVarLen)))
|
|
|
|
seed1DoubleHashBigInt := new(big.Int).SetBytes(base58.Decode(crypto.Tip5HashToBase58(seed1DoubleHash)))
|
|
|
|
seedHash2BigInt := new(big.Int).SetBytes(base58.Decode(crypto.Tip5HashToBase58(seed2HashVarLen)))
|
|
|
|
seed2DoubleHashBigInt := new(big.Int).SetBytes(base58.Decode(crypto.Tip5HashToBase58(seed2DoubleHash)))
|
|
|
|
if seedHash1BigInt.Cmp(seedHash2BigInt) == -1 {
|
|
|
|
// seed 1 < seed 2
|
|
|
|
|
|
|
|
if seed1DoubleHashBigInt.Cmp(seed2DoubleHashBigInt) == -1 {
|
|
|
|
// seed1
|
|
|
|
// / \
|
|
|
|
// ~ seed2
|
|
|
|
// / \
|
|
|
|
// ~ ~
|
|
|
|
finalSeedHash = crypto.Tip5RehashTenCell(seed2Hash, crypto.Tip5ZeroZero)
|
|
|
|
finalSeedHash = crypto.Tip5RehashTenCell(crypto.Tip5Zero, finalSeedHash)
|
|
|
|
finalSeedHash = crypto.Tip5RehashTenCell(seed1Hash, finalSeedHash)
|
|
|
|
} else {
|
|
|
|
// seed2
|
|
|
|
// / \
|
|
|
|
// seed1 ~
|
|
|
|
// / \
|
|
|
|
// ~ ~
|
|
|
|
finalSeedHash = crypto.Tip5RehashTenCell(seed1Hash, crypto.Tip5ZeroZero)
|
|
|
|
finalSeedHash = crypto.Tip5RehashTenCell(finalSeedHash, crypto.Tip5Zero)
|
|
|
|
finalSeedHash = crypto.Tip5RehashTenCell(seed2Hash, finalSeedHash)
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
// seed 1 > seed 2
|
|
|
|
|
|
|
|
if seed1DoubleHashBigInt.Cmp(seed2DoubleHashBigInt) == -1 {
|
|
|
|
// seed1
|
|
|
|
// / \
|
|
|
|
// seed2 ~
|
|
|
|
// / \
|
|
|
|
// ~ ~
|
|
|
|
finalSeedHash = crypto.Tip5RehashTenCell(seed2Hash, crypto.Tip5ZeroZero)
|
|
|
|
finalSeedHash = crypto.Tip5RehashTenCell(finalSeedHash, crypto.Tip5Zero)
|
|
|
|
finalSeedHash = crypto.Tip5RehashTenCell(seed1Hash, finalSeedHash)
|
|
|
|
} else {
|
|
|
|
// seed2
|
|
|
|
// / \
|
|
|
|
// ~ seed1
|
|
|
|
// / \
|
|
|
|
// ~ ~
|
|
|
|
finalSeedHash = crypto.Tip5RehashTenCell(seed1Hash, crypto.Tip5ZeroZero)
|
|
|
|
finalSeedHash = crypto.Tip5RehashTenCell(crypto.Tip5Zero, finalSeedHash)
|
|
|
|
finalSeedHash = crypto.Tip5RehashTenCell(seed2Hash, finalSeedHash)
|
2025-10-06 13:38:53 +07:00
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
feeHash := crypto.Tip5HashBelts([]crypto.Belt{{Value: 1}, {Value: spend.Fee}})
|
|
|
|
seedHashFee := crypto.Tip5RehashTenCell(finalSeedHash, feeHash)
|
|
|
|
return crypto.Tip5RehashTenCell(sigHash, seedHashFee), nil
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2025-10-06 18:18:19 +07:00
|
|
|
func HashMsg(spend *nockchain.NockchainSpend) ([5]uint64, error) {
|
|
|
|
seedsCount := len(spend.Seeds)
|
2025-10-15 08:00:31 +07:00
|
|
|
var finalSeedHash [5]uint64
|
|
|
|
if seedsCount == 1 {
|
|
|
|
seedHash, err := HashSeed(spend.Seeds[0])
|
|
|
|
if err != nil {
|
|
|
|
return [5]uint64{}, err
|
|
|
|
}
|
2025-10-06 18:18:19 +07:00
|
|
|
|
2025-10-15 08:00:31 +07:00
|
|
|
finalSeedHash = crypto.Tip5RehashTenCell(seedHash, crypto.Tip5ZeroZero)
|
|
|
|
} else {
|
|
|
|
seed1HashVarLen, err := HashSeedVarLen(spend.Seeds[0])
|
|
|
|
if err != nil {
|
|
|
|
return [5]uint64{}, err
|
|
|
|
}
|
|
|
|
seed1Hash, err := HashSeed(spend.Seeds[0])
|
|
|
|
if err != nil {
|
|
|
|
return [5]uint64{}, err
|
|
|
|
}
|
|
|
|
seed1DoubleHash := crypto.Tip5RehashTenCell(seed1HashVarLen, seed1HashVarLen)
|
|
|
|
seed2HashVarLen, err := HashSeedVarLen(spend.Seeds[1])
|
|
|
|
if err != nil {
|
|
|
|
return [5]uint64{}, err
|
|
|
|
}
|
|
|
|
seed2Hash, err := HashSeed(spend.Seeds[1])
|
|
|
|
if err != nil {
|
|
|
|
return [5]uint64{}, err
|
|
|
|
}
|
|
|
|
seed2DoubleHash := crypto.Tip5RehashTenCell(seed2HashVarLen, seed2HashVarLen)
|
|
|
|
|
|
|
|
seedHash1BigInt := new(big.Int).SetBytes(base58.Decode(crypto.Tip5HashToBase58(seed1HashVarLen)))
|
|
|
|
seed1DoubleHashBigInt := new(big.Int).SetBytes(base58.Decode(crypto.Tip5HashToBase58(seed1DoubleHash)))
|
|
|
|
seedHash2BigInt := new(big.Int).SetBytes(base58.Decode(crypto.Tip5HashToBase58(seed2HashVarLen)))
|
|
|
|
seed2DoubleHashBigInt := new(big.Int).SetBytes(base58.Decode(crypto.Tip5HashToBase58(seed2DoubleHash)))
|
|
|
|
if seedHash1BigInt.Cmp(seedHash2BigInt) == -1 {
|
|
|
|
// seed 1 < seed 2
|
|
|
|
|
|
|
|
if seed1DoubleHashBigInt.Cmp(seed2DoubleHashBigInt) == -1 {
|
|
|
|
// seed1
|
|
|
|
// / \
|
|
|
|
// ~ seed2
|
|
|
|
// / \
|
|
|
|
// ~ ~
|
|
|
|
finalSeedHash = crypto.Tip5RehashTenCell(seed2Hash, crypto.Tip5ZeroZero)
|
|
|
|
finalSeedHash = crypto.Tip5RehashTenCell(crypto.Tip5Zero, finalSeedHash)
|
|
|
|
finalSeedHash = crypto.Tip5RehashTenCell(seed1Hash, finalSeedHash)
|
|
|
|
} else {
|
|
|
|
// seed2
|
|
|
|
// / \
|
|
|
|
// seed1 ~
|
|
|
|
// / \
|
|
|
|
// ~ ~
|
|
|
|
finalSeedHash = crypto.Tip5RehashTenCell(seed1Hash, crypto.Tip5ZeroZero)
|
|
|
|
finalSeedHash = crypto.Tip5RehashTenCell(finalSeedHash, crypto.Tip5Zero)
|
|
|
|
finalSeedHash = crypto.Tip5RehashTenCell(seed2Hash, finalSeedHash)
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
// seed 1 > seed 2
|
|
|
|
|
|
|
|
if seed1DoubleHashBigInt.Cmp(seed2DoubleHashBigInt) == -1 {
|
|
|
|
// seed1
|
|
|
|
// / \
|
|
|
|
// seed2 ~
|
|
|
|
// / \
|
|
|
|
// ~ ~
|
|
|
|
finalSeedHash = crypto.Tip5RehashTenCell(seed2Hash, crypto.Tip5ZeroZero)
|
|
|
|
finalSeedHash = crypto.Tip5RehashTenCell(finalSeedHash, crypto.Tip5Zero)
|
|
|
|
finalSeedHash = crypto.Tip5RehashTenCell(seed1Hash, finalSeedHash)
|
|
|
|
} else {
|
|
|
|
// seed2
|
|
|
|
// / \
|
|
|
|
// ~ seed1
|
|
|
|
// / \
|
|
|
|
// ~ ~
|
|
|
|
finalSeedHash = crypto.Tip5RehashTenCell(seed1Hash, crypto.Tip5ZeroZero)
|
|
|
|
finalSeedHash = crypto.Tip5RehashTenCell(crypto.Tip5Zero, finalSeedHash)
|
|
|
|
finalSeedHash = crypto.Tip5RehashTenCell(seed2Hash, finalSeedHash)
|
2025-10-06 18:18:19 +07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
feeHash := crypto.Tip5HashBelts([]crypto.Belt{{Value: 1}, {Value: spend.Fee}})
|
|
|
|
return crypto.Tip5RehashTenCell(finalSeedHash, feeHash), nil
|
|
|
|
}
|
|
|
|
|
2025-10-06 13:38:53 +07:00
|
|
|
func HashInput(input *nockchain.NockchainInput) ([5]uint64, error) {
|
|
|
|
nameHash := HashName(input.Name)
|
|
|
|
|
|
|
|
noteHash, err := HashNote(input.Note)
|
|
|
|
if err != nil {
|
|
|
|
return [5]uint64{}, err
|
|
|
|
|
|
|
|
}
|
|
|
|
spendHash, err := HashSpend(input.Spend)
|
|
|
|
if err != nil {
|
|
|
|
return [5]uint64{}, err
|
|
|
|
|
|
|
|
}
|
|
|
|
hashNoteSpend := crypto.Tip5RehashTenCell(noteHash, spendHash)
|
2025-10-16 12:31:21 +07:00
|
|
|
return crypto.Tip5RehashTenCell(nameHash, hashNoteSpend), nil
|
2025-10-06 13:38:53 +07:00
|
|
|
}
|
|
|
|
|
|
|
|
func ComputeTxId(inputs []*nockchain.NockchainInput, timelockRange *nockchain.TimelockRange, totalFees uint64) ([5]uint64, error) {
|
2025-10-16 12:31:21 +07:00
|
|
|
|
|
|
|
inputTree := NewZTree(
|
|
|
|
func(i interface{}) [5]uint64 {
|
|
|
|
if name, ok := i.(*nockchain.NockchainName); ok {
|
|
|
|
return HashName(name)
|
|
|
|
} else {
|
|
|
|
return [5]uint64{}
|
|
|
|
}
|
|
|
|
},
|
|
|
|
func(i interface{}) ([5]uint64, error) {
|
|
|
|
if input, ok := i.(*nockchain.NockchainInput); ok {
|
|
|
|
hash, err := HashInput(input)
|
|
|
|
return hash, err
|
|
|
|
} else {
|
|
|
|
return [5]uint64{}, fmt.Errorf("invalid input type")
|
|
|
|
}
|
|
|
|
},
|
|
|
|
)
|
|
|
|
for _, input := range inputs {
|
|
|
|
inputTree.Insert(input.Name, input)
|
|
|
|
}
|
|
|
|
inputHash, err := inputTree.Hash()
|
2025-10-06 13:38:53 +07:00
|
|
|
if err != nil {
|
2025-10-16 12:31:21 +07:00
|
|
|
return [5]uint64{}, fmt.Errorf("error hashing inputs: %v", err)
|
2025-10-06 13:38:53 +07:00
|
|
|
}
|
|
|
|
|
|
|
|
timelockHash := HashTimelockRange(timelockRange)
|
|
|
|
|
|
|
|
totalFeesHash := crypto.Tip5HashBelts([]crypto.Belt{{Value: 1}, {Value: totalFees}})
|
|
|
|
|
|
|
|
q := crypto.Tip5RehashTenCell(timelockHash, totalFeesHash)
|
|
|
|
return crypto.Tip5RehashTenCell(inputHash, q), nil
|
|
|
|
}
|
|
|
|
|
|
|
|
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
|
|
|
|
}
|
|
|
|
belts, nonce := HashNonce(pkPoint, msg)
|
|
|
|
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
|
|
|
|
}
|
|
|
|
|
|
|
|
func first(ownerHash [5]uint64) [5]uint64 {
|
|
|
|
ownerHashZero := crypto.Tip5RehashTenCell(ownerHash, crypto.Tip5Zero)
|
|
|
|
ownerHashZeroOne := crypto.Tip5RehashTenCell(crypto.Tip5One, ownerHashZero)
|
|
|
|
return crypto.Tip5RehashTenCell(crypto.Tip5Zero, ownerHashZeroOne)
|
|
|
|
}
|