Runtime::generate_uuid() 在 Scrypto 中安全吗?
Is Runtime::generate_uuid() safe in Scrypto?
我想在 Scrypto 蓝图中制作一款游戏,用户可以在其中玩他们的 Gumball NFT。
我的蓝图有一个 pub fn attack(&self, my_gumball: Proof, other_gumball_key: NonFungibleId)
方法,通过给它分配 1 到 10 之间的随机伤害来攻击另一个 NFT。我应该为此使用 Runtime::generate_uuid()
吗?
好问题!我将在这里给你一个来自 Radix 的小例子,因为随机数的生成是所有 blockchains/DLTs/public 网络都在努力解决的问题,这是一个真正难以解决的问题。
首先,我假设你使用 UUID
s 作为你的 dApp 的随机数,所以整个回复都是基于此。在引擎盖下,当您调用 Uuid::generate
函数时,在发生的一长串调用的末尾,以下函数是处理 UUID
生成的函数:https://github.com/radixdlt/radixdlt-scrypto/blob/24168ae772215af5169549a7a2cc1adeb666baa6/radix-engine/src/engine/id_allocator.rs#L78
如果您查看此函数,您会发现此函数使用交易哈希 + 下一个可用 ID 为您生成 UUID
。下一个可用的 ID 没有什么特别的,它只是一个计数器,每次我们需要生成一个新的 ID 时它都会递增。此方法所做的只是在将 tx_hash + next_id
加载到 u128
之前对 tx_hash + next_id
进行两次哈希处理,这几乎就是 UUID
的生成方式。这意味着 UUID 是一个伪随机数,如果有人知道交易哈希是什么,那么他们将能够确定您将使用的“随机”数。
让我们暂且抛开所有的理论,用代码尝试一些事情。这是一些简单的 Scrypto 代码,向您展示 not-random UUID 的真实情况:
use radix_engine::engine::{IdAllocator, IdSpace};
use scrypto::prelude::*;
#[test]
fn test_randomness() {
// Creating the ID allocator
let mut id_allocator: IdAllocator = IdAllocator::new(IdSpace::Application);
// A fictional transaction hash
let tx_hash: H256 = H256::from_str("0e4c5812f00b3c821335c54b3bbc835a157df1149480f6469a4dc6b51489e989").unwrap();
// Generating four UUIDs
println!("Generated UUID: {:?}", id_allocator.new_uuid(tx_hash).unwrap());
println!("Generated UUID: {:?}", id_allocator.new_uuid(tx_hash).unwrap());
println!("Generated UUID: {:?}", id_allocator.new_uuid(tx_hash).unwrap());
println!("Generated UUID: {:?}", id_allocator.new_uuid(tx_hash).unwrap());
}
正如我们所说,IdAllocator.new_uuid
方法需要一个到 运行 的交易哈希,所以我为它提供了一个样本交易哈希。如果我们 运行 这段代码并查看输出,你和我都会在命令行终端中看到以下内容:
Generated UUID: 333873524275763974188597434119212610710
Generated UUID: 315396769568132504258157739854036837613
Generated UUID: 31497316649309892037047888539219683042
Generated UUID: 300332381675622117598720587595812830316
您可能会问,为什么我们都得到相同的输出,这不是随机的吗?
我们双方将获得的输出与 UUID
的随机性完全相同,依赖于交易哈希的变化和 next_id
。所以很容易看出这不是随机函数而是伪随机函数。
所以回答你的问题:
Someone would be able to guess the number 5-10 before the scrypto code can even generate it?
是的!内存池中的交易具有可见的哈希值,因此存在哈希部分。再加上了解你的蓝图和交易期间分配的 ID 数量的人将 100% 的时间能够在 scrypto 代码之前猜出随机数,上面的代码是如何做到这一点的一个例子。
结论:Uuid::generate
可以很好地生成 UUID,但不能很好地生成随机数,因为它不是真正的随机数函数。
我想在 Scrypto 蓝图中制作一款游戏,用户可以在其中玩他们的 Gumball NFT。
我的蓝图有一个 pub fn attack(&self, my_gumball: Proof, other_gumball_key: NonFungibleId)
方法,通过给它分配 1 到 10 之间的随机伤害来攻击另一个 NFT。我应该为此使用 Runtime::generate_uuid()
吗?
好问题!我将在这里给你一个来自 Radix 的小例子,因为随机数的生成是所有 blockchains/DLTs/public 网络都在努力解决的问题,这是一个真正难以解决的问题。
首先,我假设你使用 UUID
s 作为你的 dApp 的随机数,所以整个回复都是基于此。在引擎盖下,当您调用 Uuid::generate
函数时,在发生的一长串调用的末尾,以下函数是处理 UUID
生成的函数:https://github.com/radixdlt/radixdlt-scrypto/blob/24168ae772215af5169549a7a2cc1adeb666baa6/radix-engine/src/engine/id_allocator.rs#L78
如果您查看此函数,您会发现此函数使用交易哈希 + 下一个可用 ID 为您生成 UUID
。下一个可用的 ID 没有什么特别的,它只是一个计数器,每次我们需要生成一个新的 ID 时它都会递增。此方法所做的只是在将 tx_hash + next_id
加载到 u128
之前对 tx_hash + next_id
进行两次哈希处理,这几乎就是 UUID
的生成方式。这意味着 UUID 是一个伪随机数,如果有人知道交易哈希是什么,那么他们将能够确定您将使用的“随机”数。
让我们暂且抛开所有的理论,用代码尝试一些事情。这是一些简单的 Scrypto 代码,向您展示 not-random UUID 的真实情况:
use radix_engine::engine::{IdAllocator, IdSpace};
use scrypto::prelude::*;
#[test]
fn test_randomness() {
// Creating the ID allocator
let mut id_allocator: IdAllocator = IdAllocator::new(IdSpace::Application);
// A fictional transaction hash
let tx_hash: H256 = H256::from_str("0e4c5812f00b3c821335c54b3bbc835a157df1149480f6469a4dc6b51489e989").unwrap();
// Generating four UUIDs
println!("Generated UUID: {:?}", id_allocator.new_uuid(tx_hash).unwrap());
println!("Generated UUID: {:?}", id_allocator.new_uuid(tx_hash).unwrap());
println!("Generated UUID: {:?}", id_allocator.new_uuid(tx_hash).unwrap());
println!("Generated UUID: {:?}", id_allocator.new_uuid(tx_hash).unwrap());
}
正如我们所说,IdAllocator.new_uuid
方法需要一个到 运行 的交易哈希,所以我为它提供了一个样本交易哈希。如果我们 运行 这段代码并查看输出,你和我都会在命令行终端中看到以下内容:
Generated UUID: 333873524275763974188597434119212610710
Generated UUID: 315396769568132504258157739854036837613
Generated UUID: 31497316649309892037047888539219683042
Generated UUID: 300332381675622117598720587595812830316
您可能会问,为什么我们都得到相同的输出,这不是随机的吗?
我们双方将获得的输出与 UUID
的随机性完全相同,依赖于交易哈希的变化和 next_id
。所以很容易看出这不是随机函数而是伪随机函数。
所以回答你的问题:
Someone would be able to guess the number 5-10 before the scrypto code can even generate it?
是的!内存池中的交易具有可见的哈希值,因此存在哈希部分。再加上了解你的蓝图和交易期间分配的 ID 数量的人将 100% 的时间能够在 scrypto 代码之前猜出随机数,上面的代码是如何做到这一点的一个例子。
结论:Uuid::generate
可以很好地生成 UUID,但不能很好地生成随机数,因为它不是真正的随机数函数。