I have just jumped in Solana on-chain program.
I am going to make coin game which judge frontside or backside.
I tried to use std:: rand and get_random crate but they don't work.
If you have experience about it, please let me know.
I use anchor for Solana on-chain program.
unfortunately, The random generator doesn't work on-chain.
if you want some randoms, you should get it from outside the chain.
why?
assume you making randoms using block hash or something similar, so users can exploit that by inserting an instruction or values that checks for favorable outcomes and even worse, forcing it to roll back if it's not satisfactory.
so what should we do?
try to use oracles like chainlink vrf(verifiable random function)
simulate oracle vrf services:
make transaction on-chain that your server listens to it. if this transaction
happened, make random number off-chain and callback it from your server.
anchor use randoms like this
use rand::rngs::OsRng;
.
.
.
let dummy_a = Keypair::generate(&mut OsRng);
so, if you require randomness for UUID-like behavior you can use a mechanism like the above from the anchor code repository but if your case is game logic like a dice roll, you need oracles or simulate that.
UPDATE 11/10/2022
As we know, the Metaplex candy machine tool uses randoms to select the next item to mint.
see this code snippet:
// (2) selecting an item to mint
let recent_slothashes = &ctx.accounts.recent_slothashes;
let data = recent_slothashes.data.borrow();
let most_recent = array_ref![data, 12, 8];
let clock = Clock::get()?;
// seed for the random number is a combination of the slot_hash - timestamp
let seed = u64::from_le_bytes(*most_recent).saturating_sub(clock.unix_timestamp as u64);
let remainder: usize = seed
.checked_rem(candy_machine.data.items_available - candy_machine.items_redeemed)
.ok_or(CandyError::NumericalOverflowError)? as usize;
let config_line = get_config_line(candy_machine, remainder, candy_machine.items_redeemed)?;
candy_machine.items_redeemed = candy_machine
.items_redeemed
.checked_add(1)
.ok_or(CandyError::NumericalOverflowError)?;
The idea is you can get blockhash and clock from Solana network as random input seeds to create the next random number.
another code snippet which will be good point to start creating randoms:
//convert blockhash to random seed string
let recent_blockhash_data = recent_blockhashes.data.borrow();
let most_recent = array_ref![recent_blockhash_data, 0, 16];
let some_numbers = u128::from_le_bytes(*most_recent);
let blockhash_random_seed: String = (some_numbers).to_string();
in the above code, we use recent blockhash and convert it to hex(as string). you can select each part of this hexadecimal hash string and use it as random value.
In the end, this is important to know that blockhash is deprecated now and Metaplex use slothash but if you look closer you can see they still use blockhash and just use the name of the variable as slothash.
cheers
Related
ORIGINAL QUESTION:
I am currently trying to write a library in rust - to be compiled to WASM - for converting a bip39 mnemonic passphrase into an Arweave JWK. I am currently using tiny-bip39 and RSA.
When generating a private key using RSA as per the example given on RSA I want to seed the rng based on the mnemonic passphrase I have passed into the function. I tried achieving this by simply getting the seed from the mnemonic object generated by tiny-bip39, however this seems to generate a &[u8] with a length of 64. However, Seed is defined as [u8; 32], and without having to write my own rng, I cannot figure out how to use a len 64 seed.
#[wasm_bindgen]
pub fn get_key_from_mnemonic(phrase: &str) {
let mnemonic = Mnemonic::from_phrase(phrase, Language::English).unwrap();
assert_eq!(phrase, mnemonic.phrase());
let seed = Seed::new(&mnemonic, "");
let seed_bytes = seed.as_bytes();
let mut rng = ChaCha12Rng::from_seed(seed_bytes);
[...]
}
Is there a cryptographically secure rng that allows for len 64 seed?
I tried simply trying into, but that did not seem to work, which makes sense.
let seed_bytes: <ChaCha12Rng as SeedableRng>::Seed = seed.as_bytes().try_into().unwrap();
EDIT:
I came up with a solution that seem to work in every way except the random number generation.
let mnemonic = Mnemonic::from_phrase(phrase, Language::English).unwrap();
assert_eq!(phrase, mnemonic.phrase());
let seed = Seed::new(&mnemonic, "");
let seed_bytes = seed.as_bytes();
let mut seed_buf: [u8; 32] = Default::default();
let mut hmac_drgb = HmacDRBG::<Sha256>::new(&seed_bytes, &[], &[]);
hmac_drgb.generate_to_slice(&mut seed_buf, None);
let mut chacha = ChaCha20Rng::from_seed(seed_buf);
let modulus_length = 4098;
let rsa_private_key = RsaPrivateKey::new(&mut chacha, modulus_length).unwrap();
let der = rsa_private_key.to_pkcs1_der().unwrap();
let jwk = JWK {
modulus: der.private_key().modulus.as_bytes().to_vec(),
public_exponent: der.private_key().public_exponent.as_bytes().to_vec(),
private_exponent: der.private_key().private_exponent.as_bytes().to_vec(),
prime1: der.private_key().prime1.as_bytes().to_vec(),
prime2: der.private_key().prime2.as_bytes().to_vec(),
exponent1: der.private_key().exponent1.as_bytes().to_vec(),
exponent2: der.private_key().exponent2.as_bytes().to_vec(),
coefficient: der.private_key().coefficient.as_bytes().to_vec(),
};
As I am trying to rewrite some of the functionality provided by arweave-mnemonic-keys, I have tried to go through all of the dependencies, figuring out which rust modules I need, and think I have managed to figure out everything except how to generate the random numbers for the RSA algorithm.
I have tried looking through the node-forge/lib/rsa.js file, and found this snippet:
function generateRandom(bits, rng) {
var num = new BigInteger(bits, rng);
// force MSB set
var bits1 = bits - 1;
if(!num.testBit(bits1)) {
num.bitwiseTo(BigInteger.ONE.shiftLeft(bits1), op_or, num);
}
// align number on 30k+1 boundary
num.dAddOffset(31 - num.mod(THIRTY).byteValue(), 0);
return num;
}
However, I am not sure how to reproduce this in rust. So far I have tried to use ChaCha8Rng, ChaCha12Rng, ChaCha20Rng, and Pcg64, none of which produces the wanted result.
It depends on the CSPRNG. If you were seeding an HMAC DRBG using HMAC-SHA-512, then this would be a perfectly normal amount of input. However, in your case, the CSPRNG is ChaCha, which is configured to have a 256-bit key.
If this mnemonic has been generated from a CSPRNG and has sufficient entropy, then all you need is a simple, straightforward key derivation function like HKDF. You can use HKDF with SHA-256 or SHA-512, with the seed as the input keying material, no salt, and an output keying material which is 32 bytes in size. Then, you can use that to seed your CSPRNG.
You will also need an info string, which is usually some text string for the purpose. I like to use a version number to make things future proof, so you could use something like "v1 PRNG seed".
My recommendation here is that since you have a 64-byte input seed, that HKDF using SHA-512 is best, since it avoids losing entropy if you end up needing to seed other data. Also, while ChaCha12Rng is the default, ChaCha20Rng is more conservative and would probably be appropriate for generating a long term key.
I want to generate a different output of the same code every time I run it as it has random values assigned to some variables. Is there a way to do that, for example seeding using time as in C?
Sample code that has the randomization in it:
class ABC;
rand bit [4 : 0] arr []; // dynamic array
constraint arr_size{
arr.size() >= 2;
arr.size() <= 6;
}
endclass
module constraint_array_randomization();
ABC test_class;
initial begin
test_class = new();
test_class.randomize();
$display("The array has the value = %p ", test_class.arr);
end
endmodule
I this is probably dependent on the tool that is being used. For example xcelium from cadence supports xrun -seed some_seed(Questa has -sv_seed some_seed I think). I am certain all tools support something similar. Look for simulation tool reference/manual/guide/help it may support random seed for every simulation run.
Not sure if this is possible from inside of simulation.
As mentioned in the comments for Questa, -sv_seed random should do the trick.
Usually, having an uncontrolled random seeding at simulation creates repeatability issues. In other words, it would be very difficult to debug a failing case if you do not know the seed. But if you insist, then read the following.
You can mimic the 'c' way of randomizing with time. However, there is no good way in verilog to access system time. Therfore, there is no good way to do time based seeding from within the program.
However as always, there is a work-around available. For example, one can use the $system call to get the system time (is system-dependent). Then the srandom function can be used to set the seed. The following (linux-based) example might work for you (or you can tune it up for your system).
Here the time is provided as unix-time by the date +'%s' command. It writes it into a file and then reads from it as 'int' using $fopen/$fscan.
module constraint_array_randomization();
ABC test_class;
int today ;
initial begin
// get system time
$system("date +'%s' > date_file"); // write date into a file
fh = $fopen("date_file", "r");
void'($fscanf(fh, "%d", today)); // cast to void to avoid warnings
$fclose(fh);
$system("rm -f date_file"); // remove the file
$display("time = %d", today);
test_class = new();
test_class.srandom(today); // seed it
test_class.randomize();
$display("The array has the value = %p ", test_class.arr);
end
endmodule
I need a quick advice how-to. I mention that the following scenario is based on the use of c_api available already to my monetdblite compilation on 64bit, intention is to use it with some adhoc C written functions.
Short: how can I achieve or simulate the following scenario:
update aTable set a,b,c = func(x,y,z,…)
Long. Many algorithms are returning more than one variable as, for instance, multiple regression.
bool m_regression(IN const double **data, IN const int cols, IN const int rows, OUT double *fit_values, OUT double *residuals, OUT double *std_residuals, OUT double &p_value);
In order to minimize the transfer of data between monetdb and heavy computational function, all those results are generated in one step. Question is how can I transfer them back at once, minimizing computational time and memory traffic between monetdb and external C/C++(/R/Python) function?
My first thought to solve this is something like this:
1. update aTable set dummy = func_compute(x,y,z,…)
where dummy is a temporary __int64 field and func_compute will compute all the necessary outputs and store the result into a dummy pointer. To make sure is no issue with constant estimation, first returned value in the array will be the real dummy pointer, the rest just an incremented value of dummy + i;
2. update aTable set a = func_ret(dummy, 1), b= func_ret (dummy, 2), c= func_ret (dummy, 3) [, dummy=func_free(dummy)];
Assuming the func_ret will get the dummy in the same order that it was returned on first call, I would just copy the prepared result into provided storage; In case the order is not preserved, I will need an extra step to get the minimum (real dummy pointer), then to use the offset of current value to lookup in my array.
__int64 real_dummy = __inputs[0][0];
double *my_pointer_data = (double *) (real_dummy + __inputs[1][0] * sizeof(double)* row_count);
memcpy(__outputs[0], my_pointer_data, sizeof(double)* row_count);
// or ============================
__int64 real_dummy = minimum(__inputs[0]);
double *my_pointer_data = (double *) (real_dummy + __inputs[0][1] * sizeof(double)* row_count);
for (int i=0;i<row_count;i++)
__outputs[0][i] = my_pointer_data[__inputs[0][i] - real_dummy];
It is less relevant how am I going to free the temporary memory, can be in the last statement in update or in a new fake update statement using func_free.
Problem is that it doesn’t look to me that, even if I save some computational (big) time, the passing of the dummy is still done 3 times (any chance that memory is actually not copied?).
Is it any other better way of achieving this?
I am not aware of a good way of doing this, sorry. You could retrieve the table, add your columns as BATs in whichever way you like and write it back.
For fun, I am trying to write a simple simulation of the
Monty Hall problem
problem using F#.
I have created a function getShow which returns an array of three booleans (representing doors), one of which is randomly true (it has a car behind it) and the other two false.
let getShow =
let doorWithCar = System.Random().Next(3)+1
[|for door in 1..3 -> door = doorWithCar|]
Now when I try to get a sequence of shows using yield to call the getShow function, I keep getting the first random show repeated (I am guessing because of the way closures work in F#).
let shows =
seq { for i in 1 .. 10 do yield getShow} // Keeps generating the same show over and over
What is the correct way to call the getShow function using yield so that it actually calls the function and gets a new random array?
getShow is a value and not a function, so it's calculated once and you keep yielding the same value. To turn it into a function you have to add (). Also, you keep creating a new Random instance, which is probably initialized with the same time seed, not giving you what you want. Try this instead:
let random = System.Random()
let getShow() =
let doorWithCar = random.Next(3)+1
[|for door in 1..3 -> door = doorWithCar|]
let shows =
seq { for i in 1 .. 10 do yield getShow()}
So I'm trying to create a little something and I have looked all over the place looking for ways of generating a random number. However no matter where I test my code, it results in a non-random number. Here is an example I wrote up.
local lowdrops = {"Wooden Sword","Wooden Bow","Ion Thruster Machine Gun Blaster"}
local meddrops = {}
local highdrops = {}
function randomLoot(lootCategory)
if lootCategory == low then
print(lowdrops[math.random(3)])
end
if lootCategory == medium then
end
if lootCategory == high then
end
end
randomLoot(low)
Wherever I test my code I get the same result. For example when I test the code here http://www.lua.org/cgi-bin/demo it always ends up with the "Ion Thruster Machine Gun Blaster" and doesen't randomize. For that matter testing simply
random = math.random (10)
print(random)
gives me 9, is there something i'm missing?
You need to run math.randomseed() once before using math.random(), like this:
math.randomseed(os.time())
One possible problem is that the first number may not be so "randomized" in some platforms. So a better solution is to pop some random number before using them for real:
math.randomseed(os.time())
math.random(); math.random(); math.random()
Reference: Lua Math Library