diff --git a/core/block_crypt.cpp b/core/block_crypt.cpp index da0ac8a0a..21eb9860e 100644 --- a/core/block_crypt.cpp +++ b/core/block_crypt.cpp @@ -491,7 +491,7 @@ namespace beam bool isPublic = (OpCode::Public == eOp) || m_Coinbase; ECC::Scalar::Native skSign = sk; - if (cid.m_AssetID || (!isPublic && Rules::get().IsEnabledCA(hScheme))) + if (cid.m_AssetID || (!isPublic && Asset::Proof::Params::get_AidMax(hScheme))) { ECC::Hash::Value hv; if (!bUseCoinKdf) @@ -1333,7 +1333,7 @@ namespace beam s.m_InputsShielded++; } - void TxKernelShieldedInput::Sign(Lelantus::Prover& p, Asset::ID aid, bool bHideAssetAlways /* = true */) + void TxKernelShieldedInput::Sign(Lelantus::Prover& p, Asset::ID aid) { ECC::Oracle oracle; oracle << m_Msg; @@ -1364,7 +1364,7 @@ namespace beam if (aid) Asset::Base(aid).get_Generator(hGen); - if (aid || bHideAssetAlways) + if (Asset::Proof::Params::IsNeeded(aid, m_Height.m_Min)) { m_pAsset = std::make_unique(); w.m_R_Adj = w.m_R_Output; @@ -3412,6 +3412,25 @@ namespace beam } } + Asset::ID Asset::Proof::Params::s_AidMax_Global = 1u; // by default demand AssetProof + + thread_local Asset::ID Asset::Proof::Params::s_AidMax_Override = 0; + + Asset::ID Asset::Proof::Params::get_AidMax(Height hScheme) + { + if (!Rules::get().IsEnabledCA(hScheme)) + return 0; + + return get_AidMax(); + } + + Asset::ID Asset::Proof::Params::get_AidMax() + { + auto ret = s_AidMax_Override; + return ret ? (ret - 1) : s_AidMax_Global; + } + + struct Asset::Proof::CmList :public Sigma::CmList { @@ -3430,9 +3449,7 @@ namespace beam return true; } - void SelectWindow(Asset::ID, Asset::ID aidMax, const Rules&, const ECC::Scalar::Native& skGen); - - static Asset::ID SelectWindowInternal(Asset::ID aid, Asset::ID aidMax, uint32_t N, uint32_t rnd); + void SelectWindow(Asset::ID, const Rules&, const ECC::Scalar::Native& skGen); }; void Asset::Proof::Create(Height hScheme, ECC::Point::Native& genBlinded, ECC::Scalar::Native& skInOut, Amount val, Asset::ID aid, const ECC::Hash::Value* phvSeed) @@ -3483,7 +3500,7 @@ namespace beam const Rules& r = Rules::get(); CmList lst(r, hScheme); - lst.SelectWindow(aid, 0, r, skGen); + lst.SelectWindow(aid, r, skGen); m_Begin = lst.m_Aid0; Sigma::Prover prover(lst, r.CA.m_ProofCfg, *this); @@ -3509,7 +3526,7 @@ namespace beam skInOut += k; } - void Asset::Proof::CmList::SelectWindow(Asset::ID aid, Asset::ID aidMax, const Rules& r, const ECC::Scalar::Native& skGen) + void Asset::Proof::CmList::SelectWindow(Asset::ID aid, const Rules& r, const ECC::Scalar::Native& skGen) { // Randomize m_Aid0 m_Aid0 = 0; @@ -3518,6 +3535,8 @@ namespace beam if (N <= 1) return; // should not happen + Asset::ID aidMax = Params::get_AidMax(); + if (aidMax < aid) aidMax = aid + N / 2; // guess @@ -3555,24 +3574,6 @@ namespace beam } } - Asset::ID Asset::Proof::CmList::SelectWindowInternal(Asset::ID aid, Asset::ID aidMax, uint32_t N, uint32_t rnd) - { - assert(aid <= aidMax); - assert(N); - assert(aidMax > (N - 1)); - - rnd %= N; // index of our element within the window - - if (aid < rnd) - return 0; - - Asset::ID ret = aid - rnd; - if (ret + (N - 1) <= aidMax) - return ret; - - return aidMax - (N - 1); - } - bool Asset::Proof::IsValidPrepare(ECC::Point::Native& hGen, ECC::InnerProduct::BatchContext& bc, ECC::Scalar::Native* pKs) const { ECC::Oracle oracle; diff --git a/core/block_crypt.h b/core/block_crypt.h index 15779156f..7fe4fe3e9 100644 --- a/core/block_crypt.h +++ b/core/block_crypt.h @@ -241,6 +241,41 @@ namespace beam { typedef std::unique_ptr Ptr; + struct Params + { + static Asset::ID s_AidMax_Global; + static thread_local Asset::ID s_AidMax_Override; + + static Asset::ID Make(Asset::ID aid, bool bHideAlways) { + return aid ? aid : bHideAlways ? 1 : 0; + } + + static Asset::ID get_AidMax(Height hScheme); // returns 0 if no need to hide + static Asset::ID get_AidMax(); + + static bool IsNeeded(Asset::ID aid, Height hScheme) { + return aid || get_AidMax(hScheme); + } + + struct Override; + }; + + struct Params::Override + { + Asset::ID m_Prev; + + Override(Asset::ID aid) + { + m_Prev = s_AidMax_Override; + s_AidMax_Override = aid + 1; + + } + ~Override() + { + s_AidMax_Override = m_Prev; + } + }; + Asset::ID m_Begin; // 1st element ECC::Point m_hGen; @@ -1184,7 +1219,7 @@ namespace beam ECC::Hash::Value m_hvShieldedState; } m_NotSerialized; - void Sign(Lelantus::Prover&, Asset::ID aid, bool bHideAssetAlways = true); + void Sign(Lelantus::Prover&, Asset::ID aids); virtual ~TxKernelShieldedInput() {} virtual Subtype::Enum get_Subtype() const override; diff --git a/core/fly_client.cpp b/core/fly_client.cpp index 5e84b4a6a..5ae899108 100644 --- a/core/fly_client.cpp +++ b/core/fly_client.cpp @@ -327,7 +327,7 @@ void FlyClient::NetworkStd::Connection::OnMsg(GetBlockFinalization&& msg) Block::Builder bb(iIdx, *pKdf, *pOwner, msg.m_Height); bb.AddCoinbaseAndKrn(); - bb.AddFees(msg.m_Fees); + bb.AddFees(msg.m_Fees); // TODO: aidMax proto::BlockFinalization msgOut; msgOut.m_Value.reset(new Transaction); diff --git a/core/shielded.cpp b/core/shielded.cpp index ea5aa1aaa..c3a1fa05d 100644 --- a/core/shielded.cpp +++ b/core/shielded.cpp @@ -377,7 +377,7 @@ namespace beam set_kG(hvShared, kTmp); } - void ShieldedTxo::Data::OutputParams::Generate(ShieldedTxo& txo, const ECC::Hash::Value& hvShared, Height hScheme, ECC::Oracle& oracle, bool bHideAssetAlways /* = false */) + void ShieldedTxo::Data::OutputParams::Generate(ShieldedTxo& txo, const ECC::Hash::Value& hvShared, Height hScheme, ECC::Oracle& oracle) { ECC::Scalar::Native pExtra[2]; @@ -404,7 +404,7 @@ namespace beam cp.m_Blob.n = sizeof(p); ECC::Scalar::Native skSign = m_k; - if (m_AssetID || bHideAssetAlways) + if (Asset::Proof::Params::IsNeeded(m_AssetID, hScheme)) { ECC::Scalar::Native skGen; get_skGen(skGen, hvShared); @@ -491,9 +491,9 @@ namespace beam ///////////// // Params (both) - void ShieldedTxo::Data::Params::GenerateOutp(ShieldedTxo& txo, Height hScheme, ECC::Oracle& oracle, bool bHideAssetAlways /* = false */) + void ShieldedTxo::Data::Params::GenerateOutp(ShieldedTxo& txo, Height hScheme, ECC::Oracle& oracle) { - m_Output.Generate(txo, m_Ticket.m_SharedSecret, hScheme, oracle, bHideAssetAlways); + m_Output.Generate(txo, m_Ticket.m_SharedSecret, hScheme, oracle); } bool ShieldedTxo::Data::Params::Recover(const ShieldedTxo& txo, Height hScheme, ECC::Oracle& oracle, const Viewer& v) { diff --git a/core/shielded.h b/core/shielded.h index 8ebb90770..94c6a5480 100644 --- a/core/shielded.h +++ b/core/shielded.h @@ -88,7 +88,7 @@ namespace beam ECC::Scalar::Native m_k; User m_User; - void Generate(ShieldedTxo&, const ECC::Hash::Value& hvShared, Height hScheme, ECC::Oracle&, bool bHideAssetAlways = false); + void Generate(ShieldedTxo&, const ECC::Hash::Value& hvShared, Height hScheme, ECC::Oracle&); bool Recover(const ShieldedTxo&, const ECC::Hash::Value& hvShared, Height hScheme, ECC::Oracle&); void Restore_kG(const ECC::Hash::Value& hvShared); // restores m_k, all other members must be set @@ -108,7 +108,7 @@ namespace beam TicketParams m_Ticket; OutputParams m_Output; - void GenerateOutp(ShieldedTxo&, Height hScheme, ECC::Oracle&, bool bHideAssetAlways = false); + void GenerateOutp(ShieldedTxo&, Height hScheme, ECC::Oracle&); bool Recover(const ShieldedTxo&, Height hScheme, ECC::Oracle&, const Viewer&); void ToID(ID&) const; diff --git a/core/unittest/ecc_test.cpp b/core/unittest/ecc_test.cpp index 8efd818d3..4bde090a0 100644 --- a/core/unittest/ecc_test.cpp +++ b/core/unittest/ecc_test.cpp @@ -3127,6 +3127,9 @@ int main() beam::Rules::get().CA.Enabled = true; for (uint32_t i = 0; i < _countof(beam::Rules::get().pForks); i++) beam::Rules::get().pForks[i].m_Height = g_hFork; + + beam::Asset::Proof::Params::s_AidMax_Global = 160; + ECC::TestAll(); ECC::RunBenchmark(); diff --git a/hw_crypto/unittest/hw_crypto_test.cpp b/hw_crypto/unittest/hw_crypto_test.cpp index 305a0eaf5..6dc882770 100644 --- a/hw_crypto/unittest/hw_crypto_test.cpp +++ b/hw_crypto/unittest/hw_crypto_test.cpp @@ -1565,7 +1565,7 @@ void TestShielded() verify_test(kkw.InvokeOnBoth(m) != KeyKeeperHwEmu::Status::Success); sig.m_k.m_Value.Inv(); - m.m_HideAssetAlways = !m.m_HideAssetAlways; + m.m_AidMax = !m.m_AidMax; } verify_test(kkw.InvokeOnBoth(m) == KeyKeeperHwEmu::Status::Success); diff --git a/keykeeper/local_private_key_keeper.cpp b/keykeeper/local_private_key_keeper.cpp index d4f8bf2c0..4308c48df 100644 --- a/keykeeper/local_private_key_keeper.cpp +++ b/keykeeper/local_private_key_keeper.cpp @@ -299,6 +299,8 @@ namespace beam::wallet x.m_pResult.reset(new Output); + Asset::Proof::Params::Override po(x.m_AidMax); + Scalar::Native sk; x.m_pResult->Create(x.m_hScheme, sk, *x.m_Cid.get_ChildKdf(m_pKdf), x.m_Cid, *m_pKdf, Output::OpCode::Standard, &x.m_User); @@ -309,6 +311,8 @@ namespace beam::wallet { assert(x.m_pKernel && x.m_pList); + Asset::Proof::Params::Override po(x.m_AidMax); + Lelantus::Prover prover(*x.m_pList, x.m_pKernel->m_SpendProof); ShieldedTxo::DataParams sdp; @@ -328,7 +332,7 @@ namespace beam::wallet ExecutorMT_R exec; Executor::Scope scope(exec); - x.m_pKernel->Sign(prover, x.m_AssetID, x.m_HideAssetAlways); + x.m_pKernel->Sign(prover, x.m_AssetID); return Status::Success; } @@ -634,6 +638,8 @@ namespace beam::wallet if (!aggr.Aggregate(x)) return Status::Unspecified; + Asset::Proof::Params::Override po(x.m_AidMax); + assert(x.m_pKernel); TxKernelStd& krn = *x.m_pKernel; @@ -707,7 +713,7 @@ namespace beam::wallet ECC::Oracle oracle; oracle << krn1.m_Msg; - pars.m_Output.Generate(krn1.m_Txo, pVoucher->m_SharedSecret, krn.m_Height.m_Min, oracle, x.m_HideAssetAlways); + pars.m_Output.Generate(krn1.m_Txo, pVoucher->m_SharedSecret, krn.m_Height.m_Min, oracle); krn1.MsgToID(); assert(krn.m_vNested.empty()); diff --git a/keykeeper/remote_key_keeper.cpp b/keykeeper/remote_key_keeper.cpp index e406d9e64..b4486190a 100644 --- a/keykeeper/remote_key_keeper.cpp +++ b/keykeeper/remote_key_keeper.cpp @@ -796,6 +796,8 @@ namespace beam::wallet { ECC::Scalar::Native skDummy; ECC::HKdf kdfDummy; + + Asset::Proof::Params::Override po(m_M.m_AidMax); m_pOutput->Create(m_M.m_hScheme, skDummy, kdfDummy, m_M.m_Cid, *m_GetKey.m_pPKdf, e, &m_M.m_User); // Phase 3 } @@ -1019,7 +1021,9 @@ namespace beam::wallet proof.m_Commitment = comm; proof.m_SpendPk = pars.m_Ticket.m_SpendPk; - if (m_M.m_HideAssetAlways || m.m_AssetID) + Asset::Proof::Params::Override po(m_M.m_AidMax); + + if (Asset::Proof::Params::IsNeeded(m.m_AssetID, krn.m_Height.m_Min)) { ECC::Hash::Processor() << "asset-blind.sh" @@ -1471,7 +1475,6 @@ namespace beam::wallet msg.m_Mut.m_Peer = Ecc2BC(m_M.m_Peer); msg.m_Mut.m_AddrID = m_M.m_iEndpoint; - msg.m_HideAssetAlways = m_M.m_HideAssetAlways; Import(msg.m_User, m_M.m_User); Import(msg.m_Tx.m_Krn, m_M); @@ -1538,6 +1541,8 @@ namespace beam::wallet op.m_User = m_M.m_User; op.Restore_kG(voucher.m_SharedSecret); + Asset::Proof::Params::Override po(m_M.m_AidMax); + m_pOutp = std::make_unique(); TxKernelShieldedOutput& krn1 = *m_pOutp; @@ -1548,9 +1553,11 @@ namespace beam::wallet ECC::Oracle oracle; oracle << krn1.m_Msg; - op.Generate(krn1.m_Txo, voucher.m_SharedSecret, m_M.m_pKernel->m_Height.m_Min, oracle, m_M.m_HideAssetAlways); + op.Generate(krn1.m_Txo, voucher.m_SharedSecret, m_M.m_pKernel->m_Height.m_Min, oracle); krn1.MsgToID(); + msg.m_HideAssetAlways = !!krn1.m_Txo.m_pAsset; + if (krn1.m_Txo.m_pAsset) msg.m_ptAssetGen = Ecc2BC(krn1.m_Txo.m_pAsset->m_hGen); diff --git a/node/node.cpp b/node/node.cpp index e39376a5e..04c2d0a09 100644 --- a/node/node.cpp +++ b/node/node.cpp @@ -2996,6 +2996,8 @@ void Node::AddDummyOutputs(Transaction& tx, TxPool::Stats& stats) bModified = true; + Asset::Proof::Params::Override po(m_Processor.get_AidMax()); + auto pOutput = std::make_unique(); ECC::Scalar::Native sk; pOutput->Create(m_Processor.m_Cursor.m_ID.m_Height + 1, sk, *m_Keys.m_pMiner, cid, *m_Keys.m_pOwner); diff --git a/node/processor.cpp b/node/processor.cpp index bdbd431e3..720a75541 100644 --- a/node/processor.cpp +++ b/node/processor.cpp @@ -6540,7 +6540,10 @@ size_t NodeProcessor::GenerateNewBlockInternal(BlockContext& bc, BlockInterpretC { if (bc.m_Fees) { - bb.AddFees(bc.m_Fees, pOutp); + { + Asset::Proof::Params::Override po(get_AidMax()); + bb.AddFees(bc.m_Fees, pOutp); + } if (!HandleBlockElement(*pOutp, bic)) return 0; diff --git a/node/unittests/node_test.cpp b/node/unittests/node_test.cpp index c19ba40a6..faf133a72 100644 --- a/node/unittests/node_test.cpp +++ b/node/unittests/node_test.cpp @@ -1983,7 +1983,7 @@ namespace beam sdp.m_Output.m_User.m_Sender = 165U; sdp.m_Output.m_User.m_pMessage[0] = 243U; sdp.m_Output.m_User.m_pMessage[1] = 2435U; - sdp.GenerateOutp(pKrn->m_Txo, h + 1, oracle, true); // generate asset proof, though it's not CA + sdp.GenerateOutp(pKrn->m_Txo, h + 1, oracle); pKrn->MsgToID(); @@ -2063,7 +2063,7 @@ namespace beam ECC::SetRandom(p.m_Witness.m_R_Output); pKrn->m_NotSerialized.m_hvShieldedState = msg.m_State1; - pKrn->Sign(p, 0, true); // hide asset, although it's beam + pKrn->Sign(p, 0); verify_test(m_Shielded.m_Params.m_Ticket.m_SpendPk == pKrn->m_SpendProof.m_SpendPk); diff --git a/node/utils/node_net_sim.cpp b/node/utils/node_net_sim.cpp index ed648df7f..409f27b2b 100644 --- a/node/utils/node_net_sim.cpp +++ b/node/utils/node_net_sim.cpp @@ -730,7 +730,7 @@ struct Context ECC::GenRandom(nonce); sdp.m_Ticket.Generate(pKrn->m_Txo.m_Ticket, v, nonce); - sdp.GenerateOutp(pKrn->m_Txo, hr.m_Min, oracle, true); + sdp.GenerateOutp(pKrn->m_Txo, hr.m_Min, oracle); pKrn->MsgToID(); //ECC::Point::Native pt; @@ -886,7 +886,7 @@ struct Context { beam::Executor::Scope scope(m_Exec); - pKrn->Sign(p, txo.m_AssetID, true); + pKrn->Sign(p, txo.m_AssetID); }; pTx->m_vKernels.push_back(std::move(pKrn)); diff --git a/wallet/core/private_key_keeper.h b/wallet/core/private_key_keeper.h index d23c99325..ca16da41f 100644 --- a/wallet/core/private_key_keeper.h +++ b/wallet/core/private_key_keeper.h @@ -96,6 +96,7 @@ namespace beam::wallet CoinID m_Cid; // weak schemes (V0, BB21) isn't supported for trustless wallet Output::User m_User; Output::Ptr m_pResult; + Asset::ID m_AidMax = 1u; CreateOutput() { ZeroObject(m_User); } }; @@ -105,7 +106,7 @@ namespace beam::wallet { Sigma::CmList* m_pList; uint32_t m_iIdx; - bool m_HideAssetAlways = true; + Asset::ID m_AidMax = 1u; TxKernelShieldedInput::Ptr m_pKernel; // before invocation the following must be set: @@ -186,7 +187,7 @@ namespace beam::wallet // sent value and asset are derived from the tx balance (ins - outs) ShieldedTxo::User m_User; - bool m_HideAssetAlways = true; + Asset::ID m_AidMax = 1u; }; struct DisplayEndpoint diff --git a/wallet/core/wallet_db.cpp b/wallet/core/wallet_db.cpp index f8e1fc80e..bb696c3f8 100644 --- a/wallet/core/wallet_db.cpp +++ b/wallet/core/wallet_db.cpp @@ -7093,7 +7093,13 @@ namespace beam::wallet outputParams.m_User.m_pMessage[0] = m_pMessage[0]; outputParams.m_User.m_pMessage[1] = m_pMessage[1]; outputParams.Restore_kG(m_VoucherSharedSecret); - outputParams.Generate(nestedKernel->m_Txo, m_VoucherSharedSecret, m_Height.m_Min, oracle, m_HideAssetAlways); + + { + Asset::Proof::Params::Override po(Asset::Proof::Params::Make(0, m_HideAssetAlways)); // KernelID should not depend on specific Asset::Proof structure, in particular the selected window. + // We should only know if it's present + + outputParams.Generate(nestedKernel->m_Txo, m_VoucherSharedSecret, m_Height.m_Min, oracle); + } nestedKernel->MsgToID(); kernel.m_vNested.push_back(std::move(nestedKernel));