From e9c09e759bc7823ef62e9e936a3a18b864cf994f Mon Sep 17 00:00:00 2001 From: fnaticwang Date: Tue, 24 Sep 2019 14:37:46 +0800 Subject: [PATCH] implement the api for use.computeOTAPPKeys --- accounts/accounts.go | 3 +++ accounts/external/backend.go | 5 ++++ accounts/keystore/keystore.go | 20 ++++++++++++++ accounts/keystore/wallet.go | 13 +++++++++ accounts/scwallet/wallet.go | 5 ++++ accounts/usbwallet/wallet.go | 5 ++++ crypto/crypto.go | 45 +++++++++++++++++++++++++++++++ internal/ethapi/api.go | 51 +++++++++++++++++++++++++++++++++++ 8 files changed, 147 insertions(+) diff --git a/accounts/accounts.go b/accounts/accounts.go index 2af3a37fa5..3e9c3af62d 100644 --- a/accounts/accounts.go +++ b/accounts/accounts.go @@ -152,6 +152,9 @@ type Wallet interface { // GetUseAddress represents the wallet to retrieve corresponding wanchain public address for a specific ordinary account/address GetUseAddress(account Account) (common.UAddress, error) + + // ComputeOTAPPKeys returns one-time-address pair + ComputeOTAPPKeys(account Account, AX, AY, BX, BY string) ([]string, error) } // Backend is a "wallet provider" that may contain a batch of accounts they can diff --git a/accounts/external/backend.go b/accounts/external/backend.go index 185d87aee9..f75040c9d4 100644 --- a/accounts/external/backend.go +++ b/accounts/external/backend.go @@ -208,6 +208,11 @@ func (api *ExternalSigner) GetUseAddress(account accounts.Account) (common.UAddr return common.UAddress{}, nil } +// TODO: TBI +func (api *ExternalSigner) ComputeOTAPPKeys(account accounts.Account, AX, AY, BX, BY string) ([]string, error) { + return nil, nil +} + func (api *ExternalSigner) SignTextWithPassphrase(account accounts.Account, passphrase string, text []byte) ([]byte, error) { return []byte{}, fmt.Errorf("password-operations not supported on external signers") } diff --git a/accounts/keystore/keystore.go b/accounts/keystore/keystore.go index 64eeddaaa1..12cb501463 100644 --- a/accounts/keystore/keystore.go +++ b/accounts/keystore/keystore.go @@ -35,6 +35,7 @@ import ( "github.com/ethereum/go-ethereum/accounts" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/event" @@ -286,6 +287,25 @@ func (ks *KeyStore) SignTx(a accounts.Account, tx *types.Transaction, chainID *b return types.SignTx(tx, types.HomesteadSigner{}, unlockedKey.PrivateKey) } +func (ks *KeyStore) ComputeOTAPPKeys(a accounts.Account, AX, AY, BX, BY string) ([]string, error) { + ks.mu.RLock() + defer ks.mu.RUnlock() + + unlockedKey, found := ks.unlocked[a.Address] + if !found { + return nil, ErrLocked + } + + pub1, priv1, priv2, err := crypto.GenerteOTAPrivateKey(unlockedKey.PrivateKey, unlockedKey.PrivateKey2, AX, AY, BX, BY) + + pub1X := hexutil.Encode(common.LeftPadBytes(pub1.X.Bytes(), 32)) + pub1Y := hexutil.Encode(common.LeftPadBytes(pub1.Y.Bytes(), 32)) + priv1D := hexutil.Encode(common.LeftPadBytes(priv1.D.Bytes(), 32)) + priv2D := hexutil.Encode(common.LeftPadBytes(priv2.D.Bytes(), 32)) + + return []string{pub1X, pub1Y, priv1D, priv2D}, err +} + // SignHashWithPassphrase signs hash if the private key matching the given address // can be decrypted with the given passphrase. The produced signature is in the // [R || S || V] format where V is 0 or 1. diff --git a/accounts/keystore/wallet.go b/accounts/keystore/wallet.go index 5af66fe54b..b41f5e2beb 100644 --- a/accounts/keystore/wallet.go +++ b/accounts/keystore/wallet.go @@ -138,6 +138,19 @@ func (w *keystoreWallet) SignTx(account accounts.Account, tx *types.Transaction, return w.keystore.SignTx(account, tx, chainID) } +func (w *keystoreWallet) ComputeOTAPPKeys(account accounts.Account, AX, AY, BX, BY string) ([]string, error) { + // Make sure the requested account is contained within + if account.Address != w.account.Address { + return nil, accounts.ErrUnknownAccount + } + if account.URL != (accounts.URL{}) && account.URL != w.account.URL { + return nil, accounts.ErrUnknownAccount + } + + // Account seems valid, request the keystore to process + return w.keystore.ComputeOTAPPKeys(account, AX, AY, BX, BY) +} + // SignTxWithPassphrase implements accounts.Wallet, attempting to sign the given // transaction with the given account using passphrase as extra authentication. func (w *keystoreWallet) SignTxWithPassphrase(account accounts.Account, passphrase string, tx *types.Transaction, chainID *big.Int) (*types.Transaction, error) { diff --git a/accounts/scwallet/wallet.go b/accounts/scwallet/wallet.go index 27f301b7c9..d16f7e3101 100644 --- a/accounts/scwallet/wallet.go +++ b/accounts/scwallet/wallet.go @@ -793,6 +793,11 @@ func (w *Wallet) GetUseAddress(account accounts.Account) (common.UAddress, error return common.UAddress{}, nil } +// TODO: TBI +func (w *Wallet) ComputeOTAPPKeys(account accounts.Account, AX, AY, BX, BY string) ([]string, error) { + return nil, nil +} + // Session represents a secured communication session with the wallet. type Session struct { Wallet *Wallet // A handle to the wallet that opened the session diff --git a/accounts/usbwallet/wallet.go b/accounts/usbwallet/wallet.go index 31ae8fc80a..a740b426b0 100644 --- a/accounts/usbwallet/wallet.go +++ b/accounts/usbwallet/wallet.go @@ -598,3 +598,8 @@ func (w *wallet) SignTxWithPassphrase(account accounts.Account, passphrase strin func (w *wallet) GetUseAddress(account accounts.Account) (common.UAddress, error) { return common.UAddress{}, nil } + +// TODO: TBI +func (w *wallet) ComputeOTAPPKeys(account accounts.Account, AX, AY, BX, BY string) ([]string, error) { + return nil, nil +} diff --git a/crypto/crypto.go b/crypto/crypto.go index d2303d2ade..b97b8d9a02 100644 --- a/crypto/crypto.go +++ b/crypto/crypto.go @@ -295,3 +295,48 @@ func GenerateOneTimeKey(AX string, AY string, BX string, BY string) (ret []strin generatedA1, generatedR, err := generateOneTimeKey2528(pa, pb) return hexutil.PKPair2HexSlice(generatedA1, generatedR), nil } + +// 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 { + return + } + bytesAY, err := hexutil.Decode(AY) + if err != nil { + return + } + bytesBX, err := hexutil.Decode(BX) + if err != nil { + return + } + bytesBY, err := hexutil.Decode(BY) + if err != nil { + return + } + bnAX := new(big.Int).SetBytes(bytesAX) + bnAY := new(big.Int).SetBytes(bytesAY) + bnBX := new(big.Int).SetBytes(bytesBX) + bnBY := new(big.Int).SetBytes(bytesBY) + + retPub = &ecdsa.PublicKey{X: bnAX, Y: bnAY} + pb := &ecdsa.PublicKey{X: bnBX, Y: bnBY} + retPriv1, retPriv2, err = GenerateOneTimePrivateKey2528(privateKey, privateKey2, retPub, pb) + return +} + +func GenerateOneTimePrivateKey2528(privateKey *ecdsa.PrivateKey, privateKey2 *ecdsa.PrivateKey, destPubA *ecdsa.PublicKey, destPubB *ecdsa.PublicKey) (retPriv1 *ecdsa.PrivateKey, retPriv2 *ecdsa.PrivateKey, err error) { + pub := new(ecdsa.PublicKey) + pub.X, pub.Y = S256().ScalarMult(destPubB.X, destPubB.Y, privateKey2.D.Bytes()) //[b]R + k := new(big.Int).SetBytes(Keccak256(FromECDSAPub(pub))) //hash([b]R) + k.Add(k, privateKey.D) //hash([b]R)+a + k.Mod(k, S256().Params().N) //mod to feild N + + retPriv1 = new(ecdsa.PrivateKey) + retPriv2 = new(ecdsa.PrivateKey) + + retPriv1.D = k + retPriv2.D = new(big.Int).SetInt64(0) + return retPriv1, retPriv2, nil +} diff --git a/internal/ethapi/api.go b/internal/ethapi/api.go index 1aea97bf29..8d20dc3763 100644 --- a/internal/ethapi/api.go +++ b/internal/ethapi/api.go @@ -1531,6 +1531,57 @@ func (s *PublicTransactionPoolAPI) FillTransaction(ctx context.Context, args Sen return &SignTransactionResult{data, tx}, nil } +// ComputeOTAPPKeys compute ota private key, public key and short address +// from account address and ota full address. +func (s *PublicTransactionPoolAPI) ComputeOTAPPKeys(ctx context.Context, address common.Address, inOtaAddr string) (string, error) { + account := accounts.Account{Address: address} + wallet, err := s.b.AccountManager().Find(account) + if err != nil { + return "", err + } + + uanBytes, err := hexutil.Decode(inOtaAddr) + if err != nil { + return "", err + } + + otaBytes, err := keystore.UaddrToUncompressedRawBytes(uanBytes) + if err != nil { + return "", err + } + + otaAddr := hexutil.Encode(otaBytes) + + //AX string, AY string, BX string, BY string + otaAddr = strings.Replace(otaAddr, "0x", "", -1) + AX := "0x" + otaAddr[0:64] + AY := "0x" + otaAddr[64:128] + + BX := "0x" + otaAddr[128:192] + BY := "0x" + otaAddr[192:256] + + sS, err := wallet.ComputeOTAPPKeys(account, AX, AY, BX, BY) + if err != nil { + return "", err + } + + otaPub := sS[0] + sS[1][2:] + otaPriv := sS[2] + + privateKey, err := crypto.HexToECDSA(otaPriv[2:]) + if err != nil { + return "", err + } + + var addr common.Address + pubkey := crypto.FromECDSAPub(&privateKey.PublicKey) + //caculate the address for replaced pub + copy(addr[:], crypto.Keccak256(pubkey[1:])[12:]) + + return otaPriv + "+" + otaPub + "+" + hexutil.Encode(addr[:]), nil + +} + // SendRawTransaction will add the signed transaction to the transaction pool. // The sender is responsible for signing the transaction and using the correct nonce. func (s *PublicTransactionPoolAPI) SendRawTransaction(ctx context.Context, encodedTx hexutil.Bytes) (common.Hash, error) {