diff --git a/accounts/keystore/key.go b/accounts/keystore/key.go index 99252b2c6b..a84bd743bf 100644 --- a/accounts/keystore/key.go +++ b/accounts/keystore/key.go @@ -51,7 +51,7 @@ type Key struct { PrivateKey *ecdsa.PrivateKey // add a second privkey for privary PrivateKey2 *ecdsa.PrivateKey - // compact wanchain address format + // compact usechain address format UAddress common.UAddress } diff --git a/core/vm/contracts.go b/core/vm/contracts.go index 8ed32ae205..e2e04efffa 100644 --- a/core/vm/contracts.go +++ b/core/vm/contracts.go @@ -893,8 +893,7 @@ func (c *useCoinSC) ValidRefundReq(stateDB StateDB, payload []byte, from []byte) func (c *useCoinSC) refund(all []byte, contract *Contract, evm *EVM) ([]byte, error) { kix, value, err := c.ValidRefundReq(evm.StateDB, all, contract.CallerAddress.Bytes()) if err != nil { - fmt.Println("failed refund") - fmt.Println(evm.BlockNumber) + fmt.Println("failed refund ", err) return nil, err } @@ -913,6 +912,7 @@ func (c *useCoinSC) refund(all []byte, contract *Contract, evm *EVM) ([]byte, er func (c *useCoinSC) buyCoin(in []byte, contract *Contract, evm *EVM) ([]byte, error) { otaAddr, err := c.ValidBuyCoinReq(evm.StateDB, in, contract.value) if err != nil { + fmt.Println("failed buyCoin ", err) return nil, err } diff --git a/crypto/crypto.go b/crypto/crypto.go index 4b9614cdab..f1904bd28a 100644 --- a/crypto/crypto.go +++ b/crypto/crypto.go @@ -245,6 +245,24 @@ func zeroBytes(bytes []byte) { } } +var one = new(big.Int).SetInt64(1) + +// randFieldElement2528 returns a random element of the field +func randFieldElement2528(rand io.Reader) (k *big.Int, err error) { + params := S256().Params() + b := make([]byte, params.BitSize/8+8) + _, err = io.ReadFull(rand, b) + if err != nil { + return + } + k = new(big.Int).SetBytes(b) + n := new(big.Int).Sub(params.N, one) + k.Mod(k, n) + k.Add(k, one) + + return +} + // calc [x]Hash(P) func xScalarHashP(x []byte, pub *ecdsa.PublicKey) (I *ecdsa.PublicKey) { KeyImg := new(ecdsa.PublicKey) @@ -255,8 +273,116 @@ func xScalarHashP(x []byte, pub *ecdsa.PublicKey) (I *ecdsa.PublicKey) { return } +var ( + ErrInvalidRingSignParams = errors.New("invalid ring sign params") + ErrRingSignFail = errors.New("ring sign fail") +) + +// RingSign is the function of ring signature +func RingSign(M []byte, x *big.Int, PublicKeys []*ecdsa.PublicKey) ([]*ecdsa.PublicKey, *ecdsa.PublicKey, []*big.Int, []*big.Int, error) { + if M == nil || x == nil || len(PublicKeys) == 0 { + return nil, nil, nil, nil, ErrInvalidRingSignParams + } + + for _, publicKey := range PublicKeys { + if publicKey == nil || publicKey.X == nil || publicKey.Y == nil { + return nil, nil, nil, nil, ErrInvalidRingSignParams + } + } + + n := len(PublicKeys) + I := xScalarHashP(x.Bytes(), PublicKeys[0]) //Key Image + if I == nil || I.X == nil || I.Y == nil { + return nil, nil, nil, nil, ErrRingSignFail + } + + rnd, rnderr := rand.Int(rand.Reader, big.NewInt(int64(n))) + if rnderr != nil { + return nil, nil, nil, nil, ErrRingSignFail + } + s := int(rnd.Int64()) //s is the random position for real key + + if s > 0 { + PublicKeys[0], PublicKeys[s] = PublicKeys[s], PublicKeys[0] //exchange position + } + + var ( + q = make([]*big.Int, n) + w = make([]*big.Int, n) + ) + + SumC := new(big.Int).SetInt64(0) + Lpub := new(ecdsa.PublicKey) + d := sha3.NewLegacyKeccak256() + d.Write(M) + + var err error + for i := 0; i < n; i++ { + q[i], err = randFieldElement2528(rand.Reader) + if err != nil { + return nil, nil, nil, nil, err + } + + w[i], err = randFieldElement2528(rand.Reader) + if err != nil { + return nil, nil, nil, nil, err + } + + Lpub.X, Lpub.Y = S256().ScalarBaseMult(q[i].Bytes()) //[qi]G + if Lpub.X == nil || Lpub.Y == nil { + return nil, nil, nil, nil, ErrRingSignFail + } + + if i != s { + Ppub := new(ecdsa.PublicKey) + Ppub.X, Ppub.Y = S256().ScalarMult(PublicKeys[i].X, PublicKeys[i].Y, w[i].Bytes()) //[wi]Pi + if Ppub.X == nil || Ppub.Y == nil { + return nil, nil, nil, nil, ErrRingSignFail + } + + Lpub.X, Lpub.Y = S256().Add(Lpub.X, Lpub.Y, Ppub.X, Ppub.Y) //[qi]G+[wi]Pi + + SumC.Add(SumC, w[i]) + SumC.Mod(SumC, secp256k1_N) + } + + d.Write(FromECDSAPub(Lpub)) + } + + Rpub := new(ecdsa.PublicKey) + for i := 0; i < n; i++ { + Rpub = xScalarHashP(q[i].Bytes(), PublicKeys[i]) //[qi]HashPi + if Rpub == nil || Rpub.X == nil || Rpub.Y == nil { + return nil, nil, nil, nil, ErrRingSignFail + } + + if i != s { + Ppub := new(ecdsa.PublicKey) + Ppub.X, Ppub.Y = S256().ScalarMult(I.X, I.Y, w[i].Bytes()) //[wi]I + if Ppub.X == nil || Ppub.Y == nil { + return nil, nil, nil, nil, ErrRingSignFail + } + + Rpub.X, Rpub.Y = S256().Add(Rpub.X, Rpub.Y, Ppub.X, Ppub.Y) //[qi]HashPi+[wi]I + } + + d.Write(FromECDSAPub(Rpub)) + } + + Cs := new(big.Int).SetBytes(d.Sum(nil)) //hash(m,Li,Ri) + Cs.Sub(Cs, SumC) + Cs.Mod(Cs, secp256k1_N) + + tmp := new(big.Int).Mul(Cs, x) + Rs := new(big.Int).Sub(q[s], tmp) + Rs.Mod(Rs, secp256k1_N) + w[s] = Cs + q[s] = Rs + + return PublicKeys, I, w, q, nil +} + // VerifyRingSign verifies the validity of ring signature -// Pengbo added, Shi,TeemoGuo revised func VerifyRingSign(M []byte, PublicKeys []*ecdsa.PublicKey, I *ecdsa.PublicKey, c []*big.Int, r []*big.Int) bool { if M == nil || PublicKeys == nil || I == nil || c == nil || r == nil { return false @@ -404,7 +530,6 @@ func GenerateOneTimeKey(AX string, AY string, BX string, BY string) (ret []strin } // GenerteOTAPrivateKey generates the privatekey for an OTA account using receiver's main account's privatekey -// Pengbo added, TeemoGuo revised func GenerteOTAPrivateKey(privateKey *ecdsa.PrivateKey, privateKey2 *ecdsa.PrivateKey, AX string, AY string, BX string, BY string) (retPub *ecdsa.PublicKey, retPriv1 *ecdsa.PrivateKey, retPriv2 *ecdsa.PrivateKey, err error) { bytesAX, err := hexutil.Decode(AX) if err != nil { diff --git a/internal/ethapi/api.go b/internal/ethapi/api.go index b910c9f187..6f58005b05 100644 --- a/internal/ethapi/api.go +++ b/internal/ethapi/api.go @@ -19,6 +19,7 @@ package ethapi import ( "bytes" "context" + "crypto/ecdsa" "encoding/hex" "errors" "fmt" @@ -1531,6 +1532,97 @@ func (s *PublicTransactionPoolAPI) FillTransaction(ctx context.Context, args Sen return &SignTransactionResult{data, tx}, nil } +// GenRingSignData generate ring sign data +func (s *PublicTransactionPoolAPI) GenRingSignData(ctx context.Context, hashMsg string, privateKey string, mixUseAdresses string) (string, error) { + if !hexutil.Has0xPrefix(privateKey) { + return "", ErrInvalidPrivateKey + } + + hmsg, err := hexutil.Decode(hashMsg) + if err != nil { + return "", err + } + + ecdsaPrivateKey, err := crypto.HexToECDSA(privateKey[2:]) + if err != nil { + return "", err + } + + privKey, err := hexutil.Decode(privateKey) + if err != nil { + return "", err + } + + if privKey == nil { + return "", ErrInvalidPrivateKey + } + + useAddresses := strings.Split(mixUseAdresses, "+") + if len(useAddresses) == 0 { + return "", ErrInvalidOTAMixSet + } + + return genRingSignData(hmsg, privKey, &ecdsaPrivateKey.PublicKey, useAddresses) +} + +func genRingSignData(hashMsg []byte, privateKey []byte, actualPub *ecdsa.PublicKey, mixUseAdress []string) (string, error) { + otaPrivD := new(big.Int).SetBytes(privateKey) + + publicKeys := make([]*ecdsa.PublicKey, 0) + publicKeys = append(publicKeys, actualPub) + + for _, strUseAddr := range mixUseAdress { + pubBytes, err := hexutil.Decode(strUseAddr) + if err != nil { + return "", errors.New("fail to decode use address!") + } + + if len(pubBytes) != common.UAddressLength { + return "", ErrInvalidUAddress + } + + publicKeyA, _, err := keystore.GeneratePKPairFromUAddress(pubBytes) + if err != nil { + + return "", errors.New("Fail to generate public key from use address!") + + } + + publicKeys = append(publicKeys, publicKeyA) + } + + retPublicKeys, keyImage, w_random, q_random, err := crypto.RingSign(hashMsg, otaPrivD, publicKeys) + if err != nil { + return "", err + } + + return encodeRingSignOut(retPublicKeys, keyImage, w_random, q_random) +} + +// encode all ring sign out data to a string +func encodeRingSignOut(publicKeys []*ecdsa.PublicKey, keyimage *ecdsa.PublicKey, Ws []*big.Int, Qs []*big.Int) (string, error) { + tmp := make([]string, 0) + for _, pk := range publicKeys { + tmp = append(tmp, common.ToHex(crypto.FromECDSAPub(pk))) + } + + pkStr := strings.Join(tmp, "&") + k := common.ToHex(crypto.FromECDSAPub(keyimage)) + wa := make([]string, 0) + for _, wi := range Ws { + wa = append(wa, hexutil.EncodeBig(wi)) + } + + wStr := strings.Join(wa, "&") + qa := make([]string, 0) + for _, qi := range Qs { + qa = append(qa, hexutil.EncodeBig(qi)) + } + qStr := strings.Join(qa, "&") + outs := strings.Join([]string{pkStr, k, wStr, qStr}, "+") + return outs, nil +} + func (s *PublicTransactionPoolAPI) GetOTAMixSet(ctx context.Context, otaAddr string, setLen int) ([]string, error) { if setLen <= 0 { return []string{}, ErrInvalidOTAMixNum