// TODO: Get index from an alternate syntax: rXYZ:<index> Json::Value parseAccountRaw (const Json::Value& jvParams, bool bPeer) { std::string strIdent = jvParams[0u].asString (); unsigned int iCursor = jvParams.size (); bool bStrict = false; std::string strPeer; if (!bPeer && iCursor >= 2 && jvParams[iCursor - 1] == "strict") { bStrict = true; --iCursor; } if (bPeer && iCursor >= 2) strPeer = jvParams[iCursor].asString (); int iIndex = 0; // int iIndex = jvParams.size() >= 2 ? lexicalCast <int>(jvParams[1u].asString()) : 0; RippleAddress raAddress; if (!raAddress.setAccountPublic (strIdent) && !raAddress.setAccountID (strIdent) && !raAddress.setSeedGeneric (strIdent)) return rpcError (rpcACT_MALFORMED); // Get info on account. Json::Value jvRequest (Json::objectValue); jvRequest["account"] = strIdent; if (bStrict) jvRequest["strict"] = 1; if (iIndex) jvRequest["account_index"] = iIndex; if (!strPeer.empty ()) { RippleAddress raPeer; if (!raPeer.setAccountPublic (strPeer) && !raPeer.setAccountID (strPeer) && !raPeer.setSeedGeneric (strPeer)) return rpcError (rpcACT_MALFORMED); jvRequest["peer"] = strPeer; } if (iCursor == (2 + bPeer) && !jvParseLedger (jvRequest, jvParams[1u + bPeer].asString ())) return rpcError (rpcLGR_IDX_MALFORMED); return jvRequest; }
// { // passphrase: <string> // } Json::Value doWalletPropose (RPC::Context& context) { context.lock_.unlock (); RippleAddress naSeed; RippleAddress naAccount; if (!context.params_.isMember ("passphrase")) naSeed.setSeedRandom (); else if (!naSeed.setSeedGeneric (context.params_["passphrase"].asString ())) return rpcError(rpcBAD_SEED); RippleAddress naGenerator = RippleAddress::createGeneratorPublic (naSeed); naAccount.setAccountPublic (naGenerator, 0); Json::Value obj (Json::objectValue); obj["master_seed"] = naSeed.humanSeed (); obj["master_seed_hex"] = to_string (naSeed.getSeed ()); obj["master_key"] = naSeed.humanSeed1751(); obj["account_id"] = naAccount.humanAccountID (); obj["public_key"] = naAccount.humanAccountPublic(); auto acct = naAccount.getAccountPublic(); obj["public_key_hex"] = strHex(acct.begin(), acct.size()); return obj; }
// --> strIdent: public key, account ID, or regular seed. // --> bStrict: Only allow account id or public key. // <-- bIndex: true if iIndex > 0 and used the index. Json::Value accountFromString (Ledger::ref lrLedger, RippleAddress& naAccount, bool& bIndex, const std::string& strIdent, const int iIndex, const bool bStrict, NetworkOPs& netOps) { RippleAddress naSeed; if (naAccount.setAccountPublic (strIdent) || naAccount.setAccountID (strIdent)) { // Got the account. bIndex = false; } else if (bStrict) { return naAccount.setAccountID (strIdent, Base58::getBitcoinAlphabet ()) ? rpcError (rpcACT_BITCOIN) : rpcError (rpcACT_MALFORMED); } // Must be a seed. else if (!naSeed.setSeedGeneric (strIdent)) { return rpcError (rpcBAD_SEED); } else { rpcError(rpcACT_MALFORMED); } return Json::Value (Json::objectValue); }
bool STTx::checkSingleSign () const { // We don't allow both a non-empty sfSigningPubKey and an sfSigners. // That would allow the transaction to be signed two ways. So if both // fields are present the signature is invalid. if (isFieldPresent (sfSigners)) return false; bool ret = false; try { ECDSA const fullyCanonical = (getFlags() & tfFullyCanonicalSig) ? ECDSA::strict : ECDSA::not_strict; RippleAddress n; n.setAccountPublic (getFieldVL (sfSigningPubKey)); ret = n.accountPublicVerify (getSigningData (*this), getFieldVL (sfTxnSignature), fullyCanonical); } catch (...) { // Assume it was a signature failure. ret = false; } return ret; }
bool STTx::checkSign () const { if (boost::indeterminate (sig_state_)) { try { ECDSA const fullyCanonical = (getFlags() & tfFullyCanonicalSig) ? ECDSA::strict : ECDSA::not_strict; RippleAddress n; n.setAccountPublic (getFieldVL (sfSigningPubKey)); sig_state_ = n.accountPublicVerify (getSigningData (*this), getFieldVL (sfTxnSignature), fullyCanonical); } catch (...) { sig_state_ = false; } } assert (!boost::indeterminate (sig_state_)); return static_cast<bool> (sig_state_); }
bool RippleAddress::setSeedGeneric (const std::string& strText) { RippleAddress naTemp; bool bResult = true; uint256 uSeed; if (strText.empty () || naTemp.setAccountID (strText) || naTemp.setAccountPublic (strText) || naTemp.setAccountPrivate (strText) || naTemp.setNodePublic (strText) || naTemp.setNodePrivate (strText)) { bResult = false; } else if (strText.length () == 32 && uSeed.SetHex (strText, true)) { setSeed (uSeed); } else if (setSeed (strText)) { // Log::out() << "Recognized seed."; nothing (); } else { // Log::out() << "Creating seed from pass phrase."; setSeed (EdKeyPair::passPhraseToKey (strText)); } return bResult; }
RippleAddress RippleAddress::createAccountPublic(const RippleAddress& naGenerator, int iSeq) { CKey ckPub(naGenerator, iSeq); RippleAddress naNew; naNew.setAccountPublic(ckPub.GetPubKey()); return naNew; }
RippleAddress RippleAddress::createAccountPublic ( RippleAddress const& generator, int iSeq) { RippleAddress naNew; naNew.setAccountPublic (generator, iSeq); return naNew; }
RippleAddress RippleAddress::createAccountPublic (const RippleAddress& seed) { EdKeyPair ckPub(seed.getSeed()); RippleAddress naNew; naNew.setAccountPublic (ckPub.getPubKey ()); return naNew; }
std::string rippleGetAddressFromSecret(const std::string& secretkey) { RippleAddress secret; if (!secret.SetString(secretkey, VER_FAMILY_SEED)) return ""; RippleAddress masterGenerator = createGeneratorPublic(secret); RippleAddress masterAccountPublic; masterAccountPublic.setAccountPublic(masterGenerator.getAccountPublic(), 0); return masterAccountPublic.humanAccountID(); }
void rippleGenerateAddress(std::string& address, std::string& secret) { RippleAddress naSeed; RippleAddress naAccount; uint128 key; getRand(key.begin(), key.size()); naSeed.setSeed(key); RippleAddress naGenerator = createGeneratorPublic(naSeed); naAccount.setAccountPublic(naGenerator.getAccountPublic(), 0); secret = naSeed.humanSeed(); address = naAccount.humanAccountID(); }
bool RippleAddress::setSeedGeneric(const std::string& strText) { RippleAddress naTemp; bool bResult = true; uint128 uSeed; if (strText.empty() || naTemp.setAccountID(strText) || naTemp.setAccountPublic(strText) || naTemp.setAccountPrivate(strText) || naTemp.setNodePublic(strText) || naTemp.setNodePrivate(strText)) { bResult = false; } else if (strText.length() == 32 && uSeed.SetHex(strText, true)) { setSeed(uSeed); } else if (setSeed(strText)) { // std::cerr << "Recognized seed." << std::endl; nothing(); } else if (1 == setSeed1751(strText)) { // std::cerr << "Recognized 1751 seed." << std::endl; nothing(); } else { // std::cerr << "Creating seed from pass phrase." << std::endl; setSeed(CKey::PassPhraseToKey(strText)); } return bResult; }
Json::Value accounts ( Ledger::ref lrLedger, RippleAddress const& naMasterGenerator, NetworkOPs& netOps) { Json::Value jsonAccounts (Json::arrayValue); // YYY Don't want to leak to thin server that these accounts are related. // YYY Would be best to alternate requests to servers and to cache results. unsigned int uIndex = 0; do { // VFALCO Should be PublicKey and Generator RippleAddress pk; pk.setAccountPublic (naMasterGenerator, uIndex++); auto const sle = cachedRead(*lrLedger, keylet::account(calcAccountID(pk)).key, ltACCOUNT_ROOT); if (sle) { Json::Value jsonAccount (Json::objectValue); injectSLE(jsonAccount, *sle); jsonAccounts.append (jsonAccount); } else { uIndex = 0; } } while (uIndex); return jsonAccounts; }
Json::Value accounts ( Ledger::ref lrLedger, RippleAddress const& naMasterGenerator, NetworkOPs& netOps) { Json::Value jsonAccounts (Json::arrayValue); // YYY Don't want to leak to thin server that these accounts are related. // YYY Would be best to alternate requests to servers and to cache results. unsigned int uIndex = 0; do { RippleAddress naAccount; naAccount.setAccountPublic (naMasterGenerator, uIndex++); AccountState::pointer as = netOps.getAccountState (lrLedger, naAccount); if (as) { Json::Value jsonAccount (Json::objectValue); as->addJson (jsonAccount); jsonAccounts.append (jsonAccount); } else { uIndex = 0; } } while (uIndex); return jsonAccounts; }
bool RippleAddress::setSeedGeneric (std::string const& strText) { RippleAddress naTemp; bool bResult = true; uint128 uSeed; if (parseBase58<AccountID>(strText)) return false; if (strText.empty () || naTemp.setAccountPublic (strText) || naTemp.setAccountPrivate (strText) || naTemp.setNodePublic (strText) || naTemp.setNodePrivate (strText)) { bResult = false; } else if (strText.length () == 32 && uSeed.SetHex (strText, true)) { setSeed (uSeed); } else if (setSeed (strText)) { // Log::out() << "Recognized seed."; } else if (1 == setSeed1751 (strText)) { // Log::out() << "Recognized 1751 seed."; } else { setSeed (PassPhraseToKey (strText)); } return bResult; }
Json::Value doGatewayBalances (RPC::Context& context) { auto& params = context.params; // Get the current ledger std::shared_ptr<ReadView const> ledger; auto result = RPC::lookupLedger (ledger, context); if (!ledger) return result; if (!(params.isMember (jss::account) || params.isMember (jss::ident))) return RPC::missing_field_error (jss::account); std::string const strIdent (params.isMember (jss::account) ? params[jss::account].asString () : params[jss::ident].asString ()); bool const bStrict = params.isMember (jss::strict) && params[jss::strict].asBool (); // Get info on account. AccountID accountID; auto jvAccepted = RPC::accountFromString (accountID, strIdent, bStrict); if (jvAccepted) return jvAccepted; context.loadType = Resource::feeHighBurdenRPC; result[jss::account] = getApp().accountIDCache().toBase58 (accountID); // Parse the specified hotwallet(s), if any std::set <AccountID> hotWallets; if (params.isMember ("hotwallet")) { Json::Value const& hw = params["hotwallet"]; bool valid = true; auto addHotWallet = [&valid, &hotWallets](Json::Value const& j) { if (j.isString()) { RippleAddress ra; if (ra.setAccountPublic (j.asString ())) { hotWallets.insert(calcAccountID(ra)); } else { auto const a =parseBase58<AccountID>(j.asString()); if (! a) valid = false; else hotWallets.insert(*a); } } else { valid = false; } }; if (hw.isArray()) { for (unsigned i = 0; i < hw.size(); ++i) addHotWallet (hw[i]); } else if (hw.isString()) { addHotWallet (hw); } else { valid = false; } if (! valid) { result[jss::error] = "invalidHotWallet"; return result; } } std::map <Currency, STAmount> sums; std::map <AccountID, std::vector <STAmount>> hotBalances; std::map <AccountID, std::vector <STAmount>> assets; // Traverse the cold wallet's trust lines { forEachItem(*ledger, accountID, [&](std::shared_ptr<SLE const> const& sle) { auto rs = RippleState::makeItem (accountID, sle); if (!rs) return; int balSign = rs->getBalance().signum(); if (balSign == 0) return; auto const& peer = rs->getAccountIDPeer(); // Here, a negative balance means the cold wallet owes (normal) // A positive balance means the cold wallet has an asset (unusual) if (hotWallets.count (peer) > 0) { // This is a specified hot wallt hotBalances[peer].push_back (-rs->getBalance ()); } else if (balSign > 0) { // This is a gateway asset assets[peer].push_back (rs->getBalance ()); } else { // normal negative balance, obligation to customer auto& bal = sums[rs->getBalance().getCurrency()]; if (bal == zero) { // This is needed to set the currency code correctly bal = -rs->getBalance(); } else bal -= rs->getBalance(); } }); } if (! sums.empty()) { Json::Value& j = (result [jss::obligations] = Json::objectValue); for (auto const& e : sums) { j[to_string (e.first)] = e.second.getText (); } } if (! hotBalances.empty()) { Json::Value& j = (result [jss::balances] = Json::objectValue); for (auto const& account : hotBalances) { Json::Value& balanceArray = (j[to_string (account.first)] = Json::arrayValue); for (auto const& balance : account.second) { Json::Value& entry = balanceArray.append (Json::objectValue); entry[jss::currency] = to_string (balance.issue ().currency); entry[jss::value] = balance.getText(); } } } if (! assets.empty()) { Json::Value& j = (result [jss::assets] = Json::objectValue); for (auto const& account : assets) { Json::Value& balanceArray = (j[to_string (account.first)] = Json::arrayValue); for (auto const& balance : account.second) { Json::Value& entry = balanceArray.append (Json::objectValue); entry[jss::currency] = to_string (balance.issue ().currency); entry[jss::value] = balance.getText(); } } } return result; }
void LoopThread(unsigned int n, uint64_t eta50, string* ppattern, string* pmaster_seed, string* pmaster_seed_hex, string* paccount_id) { RippleAddress naSeed; RippleAddress naAccount; string pattern = *ppattern; string account_id; uint128 key; getRand(key.begin(), key.size()); uint64_t count = 0; uint64_t last_count = 0; do { naSeed.setSeed(key); RippleAddress naGenerator = createGeneratorPublic(naSeed); naAccount.setAccountPublic(naGenerator.getAccountPublic(), 0); account_id = naAccount.humanAccountID(); count++; if (count % UPDATE_ITERATIONS == 0) { boost::unique_lock<boost::mutex> lock(mutex); total_searched += count - last_count; last_count = count; uint64_t nSecs = time(NULL) - start_time; double speed = (1.0 * total_searched)/nSecs; const char* unit = "seconds"; double eta50f = eta50/speed; if (eta50f > 100) { unit = "minutes"; eta50f /= 60; if (eta50f > 100) { unit = "hours"; eta50f /= 60; if (eta50f > 48) { unit = "days"; eta50f /= 24; } } } cout << "# Thread " << n << ": " << count << " seeds." << endl << "#" << endl << "# Total Speed: " << speed << " seeds/second" << endl << "# Total Searched: " << total_searched << endl << "# Total Time: " << nSecs << " seconds" << endl << "# ETA 50%: " << eta50f << " " << unit << endl << "# Last: " << account_id << endl << "# Pattern: " << pattern << endl << "#" << endl; } key++; boost::this_thread::yield(); } while ((account_id.substr(0, pattern.size()) != pattern) && !fDone); boost::unique_lock<boost::mutex> lock(mutex); if (fDone) return; fDone = true; cout << "# *** Found by thread " << n << ". ***" << endl << "#" << endl; *pmaster_seed = naSeed.humanSeed(); *pmaster_seed_hex = naSeed.getSeed().ToString(); *paccount_id = account_id; }
void run() { testBase58(RippleAddress::VER_NODE_PUBLIC, 'n'); testBase58(RippleAddress::VER_NODE_PRIVATE, 'h'); testBase58(RippleAddress::VER_ACCOUNT_PUBLIC, 'p'); testBase58(RippleAddress::VER_ACCOUNT_PRIVATE, 'h'); testBase58(RippleAddress::VER_SEED, 's'); // check pass phrase std::string strPass("paysharesmaster"); std::string strBase58Seed("s3q5ZGX2ScQK2rJ4JATp7rND6X5npG3De8jMbB7tuvm2HAVHcCN"); std::string strBase58NodePublic("nfbbWHgJqzqfH1cfRpMdPRkJ19cxTsdHkBtz1SLJJQfyf9Ax6vd"); std::string strBase58AccountPublic("pGreoXKYybde1keKZwDCv8m5V1kT6JH37pgnTUVzdMkdygTixG8"); AccountPrivateKey accountPrivateKey; NodePrivateKey nodePrivateKey; accountPrivateKey.fromPassPhrase(strPass); nodePrivateKey.fromPassPhrase(strPass); expect(accountPrivateKey.base58Seed() == "s3q5ZGX2ScQK2rJ4JATp7rND6X5npG3De8jMbB7tuvm2HAVHcCN", accountPrivateKey.base58Seed()); expect(accountPrivateKey.base58AccountID() == "ganVp9o5emfzpwrG5QVUXqMv8AgLcdvySb", accountPrivateKey.base58AccountID()); expect(accountPrivateKey.base58PublicKey() == strBase58AccountPublic, accountPrivateKey.base58PublicKey()); expect(nodePrivateKey.base58PublicKey() == strBase58NodePublic, nodePrivateKey.base58PublicKey()); Blob sig; uint256 message; accountPrivateKey.sign(message, sig); PaysharesPublicKey publicKey(accountPrivateKey.getPublicKey(), RippleAddress::VER_NODE_PUBLIC); expect(publicKey.verifySignature(message, sig), "Signature didn't verify"); expect(publicKey.getAccountID() == accountPrivateKey.getAccountID(), "Account Id's mis match"); expect(publicKey.base58AccountID() == accountPrivateKey.base58AccountID(), "Account Id's mis match"); Blob nonCanonicalSig(sig); add_l(nonCanonicalSig.data() + 32); expect(sig != nonCanonicalSig, "Non-canonical signature equal to canonical signature"); expect(crypto_sign_verify_detached(nonCanonicalSig.data(), message.data(), message.bytes, publicKey.vchData.data()) == 0, "Non-canonical signature didn't verify (ignoring canonical-ness)"); expect(!publicKey.verifySignature(message, nonCanonicalSig), "Non-canonical signature verified"); AccountPrivateKey privateKey2; privateKey2.fromString(strBase58Seed); // key from base58seed expect(privateKey2.base58Seed() == "s3q5ZGX2ScQK2rJ4JATp7rND6X5npG3De8jMbB7tuvm2HAVHcCN", privateKey2.base58Seed()); expect(privateKey2.base58AccountID() == "ganVp9o5emfzpwrG5QVUXqMv8AgLcdvySb", privateKey2.base58AccountID()); expect(privateKey2.base58PublicKey() == strBase58AccountPublic, privateKey2.base58PublicKey()); privateKey2.sign(message, sig); expect(publicKey.verifySignature(message, sig), "Signature didn't verify"); // check with the previous pubkey // check random /// ======= OLD ==== // Construct a seed. RippleAddress naSeed; expect(naSeed.setSeedGeneric("masterpassphrase")); expect(naSeed.humanSeed() == "s3q5ZGX2ScQK2rJ4JATp7rND6X5npG3De8jMbB7tuvm2HAVHcCN", naSeed.humanSeed()); // Create node public/private key pair RippleAddress naNodePublic = RippleAddress::createNodePublic(naSeed); expect(naNodePublic.verifySignature(message, sig), "Signature didn't verify"); expect(naNodePublic.humanNodePublic() == strBase58NodePublic, naNodePublic.humanNodePublic()); naNodePublic.setNodePublic(strBase58NodePublic); expect(naNodePublic.verifySignature(message, sig), "Signature didn't verify"); expect(naNodePublic.humanNodePublic() == strBase58NodePublic, naNodePublic.humanNodePublic()); RippleAddress naAccountPublic = RippleAddress::createAccountPublic(naSeed); expect(naAccountPublic.humanAccountID() == "ganVp9o5emfzpwrG5QVUXqMv8AgLcdvySb", naAccountPublic.humanAccountID()); expect(naAccountPublic.verifySignature(message, sig), "Signature didn't verify"); expect(naAccountPublic.humanAccountPublic() == strBase58AccountPublic, naAccountPublic.humanAccountPublic()); naAccountPublic.setAccountPublic(strBase58AccountPublic); expect(naAccountPublic.humanAccountID() == "ganVp9o5emfzpwrG5QVUXqMv8AgLcdvySb", naAccountPublic.humanAccountID()); expect(naAccountPublic.verifySignature(message, sig), "Signature didn't verify"); expect(naAccountPublic.humanAccountPublic() == strBase58AccountPublic, naAccountPublic.humanAccountPublic()); Blob rippleSig; RippleAddress naAccountPrivate = RippleAddress::createAccountPrivate(naSeed); naAccountPrivate.sign(message, rippleSig); expect(rippleSig==sig, "Signature don't match"); RippleAddress naNodePrivate = RippleAddress::createNodePrivate(naSeed); naNodePrivate.sign(message, rippleSig); expect(rippleSig == sig, "Signature don't match"); std::string strPrivateKey("ssQMHypYAPSPgniSyvJQccuL1dJUbXJWVgAPV5QcAuBVEWsZTVQwffsnwTY6Mivoy3NRSVR28ZaCW74F67VSq4VRC4zY1XR"); expect(naNodePrivate.humanNodePrivate() == strPrivateKey, naNodePrivate.humanNodePrivate()); expect(naNodePrivate.setNodePrivate(strPrivateKey),"couldn't create private node"); expect(naNodePrivate.humanNodePrivate() == strPrivateKey, naNodePrivate.humanNodePrivate()); naNodePrivate.sign(message, rippleSig); expect(rippleSig == sig, "Signature don't match"); /* RippleAddress naNodePrivate = RippleAddress::createNodePrivate(naSeed); expect(naNodePrivate.humanNodePrivate() == "pnen77YEeUd4fFKG7iycBWcwKpTaeFRkW2WFostaATy1DSupwXe", naNodePrivate.humanNodePrivate()); // Check node signing. Blob vucTextSrc = strCopy("Hello, nurse!"); uint256 uHash = Serializer::getSHA512Half(vucTextSrc); Blob vucTextSig; naNodePrivate.signNodePrivate(uHash, vucTextSig); expect(naNodePublic.verifyNodePublic(uHash, vucTextSig, ECDSA::strict), "Verify failed."); */ }
Json::Value walletPropose (Json::Value const& params) { RippleAddress naSeed; RippleAddress naAccount; KeyType type = KeyType::secp256k1; bool const has_key_type = params.isMember (jss::key_type); bool const has_passphrase = params.isMember (jss::passphrase); if (has_key_type) { // `key_type` must be valid if present. type = keyTypeFromString (params[jss::key_type].asString()); if (type == KeyType::invalid) { return rpcError (rpcBAD_SEED); } naSeed = getSeedFromRPC (params); } else if (has_passphrase) { naSeed.setSeedGeneric (params[jss::passphrase].asString()); } else { naSeed.setSeedRandom(); } if (!naSeed.isSet()) { return rpcError(rpcBAD_SEED); } if (type == KeyType::secp256k1) { RippleAddress naGenerator = RippleAddress::createGeneratorPublic (naSeed); naAccount.setAccountPublic (naGenerator, 0); } else if (type == KeyType::ed25519) { uint256 secretkey = keyFromSeed (naSeed.getSeed()); Blob publickey (33); publickey[0] = 0xED; ed25519_publickey (secretkey.data(), &publickey[1]); secretkey.zero(); // security erase naAccount.setAccountPublic (publickey); } else { assert (false); // not reached } Json::Value obj (Json::objectValue); obj[jss::master_seed] = naSeed.humanSeed (); obj[jss::master_seed_hex] = to_string (naSeed.getSeed ()); obj[jss::master_key] = naSeed.humanSeed1751(); obj[jss::account_id] = naAccount.humanAccountID (); obj[jss::public_key] = naAccount.humanAccountPublic(); obj[jss::key_type] = to_string (type); auto acct = naAccount.getAccountPublic(); obj[jss::public_key_hex] = strHex(acct.begin(), acct.size()); return obj; }
// --> strIdent: public key, account ID, or regular seed. // --> bStrict: Only allow account id or public key. // <-- bIndex: true if iIndex > 0 and used the index. Json::Value accountFromString (Ledger::ref lrLedger, RippleAddress& naAccount, bool& bIndex, const std::string& strIdent, const int iIndex, const bool bStrict, NetworkOPs& netOps) { RippleAddress naSeed; if (naAccount.setAccountPublic (strIdent) || naAccount.setAccountID (strIdent)) { // Got the account. bIndex = false; } else if (bStrict) { return naAccount.setAccountID (strIdent, Base58::getBitcoinAlphabet ()) ? rpcError (rpcACT_BITCOIN) : rpcError (rpcACT_MALFORMED); } // Must be a seed. else if (!naSeed.setSeedGeneric (strIdent)) { return rpcError (rpcBAD_SEED); } else { // We allow the use of the seeds to access #0. // This is poor practice and merely for debuging convenience. RippleAddress naRegular0Public; RippleAddress naRegular0Private; RippleAddress naGenerator = RippleAddress::createGeneratorPublic (naSeed); naRegular0Public.setAccountPublic (naGenerator, 0); naRegular0Private.setAccountPrivate (naGenerator, naSeed, 0); // Account uGeneratorID = naRegular0Public.getAccountID(); SLE::pointer sleGen = netOps.getGenerator (lrLedger, naRegular0Public.getAccountID ()); if (!sleGen) { // Didn't find a generator map, assume it is a master generator. } else { // Found master public key. Blob vucCipher = sleGen->getFieldVL (sfGenerator); Blob vucMasterGenerator = naRegular0Private.accountPrivateDecrypt (naRegular0Public, vucCipher); if (vucMasterGenerator.empty ()) { rpcError (rpcNO_GEN_DECRYPT); } naGenerator.setGenerator (vucMasterGenerator); } bIndex = !iIndex; naAccount.setAccountPublic (naGenerator, iIndex); } return Json::Value (Json::objectValue); }