Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Example of drand library in Move. This also includes a needed fix in translate.rs. #51

Open
wants to merge 5 commits into
base: solana
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,18 @@ impl From<&u256::U256> for Constant {
Constant::U256(U256::from(n))
}
}
impl From<&Vec<u8>> for Constant {
fn from(v: &Vec<u8>) -> Constant {
Constant::ByteArray(v.clone())
}
}

pub fn transform_bytearray_to_vec(val_vec: &[Constant]) -> Option<&Vec<u8>> {
if let Some(Constant::ByteArray(ref vec)) = val_vec.first() {
return Some(vec);
}
None
}

/// An operation -- target of a call. This contains user functions, builtin functions, and
/// operators.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
[package]
name = "Games"
version = "0.0.1"

[dependencies]
Sui = { local = "../../../../../../crates/sui-framework/packages/sui-framework" }

[addresses]
games = "0x0"
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
// Copyright (c) Mysten Labs, Inc.
// SPDX-License-Identifier: Apache-2.0

/// Helper module for working with drand outputs.
/// Currently works with chain 52db9ba70e0cc0f6eaf7803dd07447a1f5477735fd3f661792ba94600c84e971 (quicknet).
///
/// See examples of how to use this in drand_based_lottery.move and drand_based_scratch_card.move.
///
/// If you want to use this module with the default network which has a 30s period, you need to change the public key,
/// genesis time and include the previous signature in verify_drand_signature. See https://drand.love/developer/ or the
/// previous version of this file: https://github.com/MystenLabs/sui/blob/92df778310679626f00bc4226d7f7a281322cfdd/sui_programmability/examples/games/sources/drand_lib.move


// Copied from sui_programmability/examples/games/sources/drand_lib.move
// Run it from current directory as move-mv-llvm-compiler -c ./drand_lib.move -p ./Move.toml --test {-O|-S} -o <out_dir>

module games::drand_lib {
use std::hash::sha2_256;
use std::vector;

use sui::bls12381;

/// Error codes
const EInvalidRndLength: u64 = 0;
const EInvalidProof: u64 = 1;

/// The genesis time of chain 52db9ba70e0cc0f6eaf7803dd07447a1f5477735fd3f661792ba94600c84e971.
const GENESIS: u64 = 1692803367;
/// The public key of chain 52db9ba70e0cc0f6eaf7803dd07447a1f5477735fd3f661792ba94600c84e971.
const DRAND_PK: vector<u8> =
x"83cf0f2896adee7eb8b5f01fcad3912212c437e0073e911fb90022d3e760183c8c4b450b6a0a6c3ac6a5776a2d1064510d1fec758c921cc22b0e17e63aaf4bcb5ed66304de9cf809bd274ca73bab4af5a6e9c76a4bc09e76eae8991ef5ece45a";

/// The time in seconds between randomness beacon rounds.
const PERIOD: u64 = 3;

/// Check that a given epoch time has passed by verifying a drand signature from a later time.
/// round must be at least (epoch_time - GENESIS)/PERIOD + 1).
public fun verify_time_has_passed(epoch_time: u64, sig: vector<u8>, round: u64) {
assert!(epoch_time <= GENESIS + PERIOD * (round - 1), EInvalidProof);
verify_drand_signature(sig, round);
}

/// Check a drand output.
public fun verify_drand_signature(sig: vector<u8>, round: u64) {
// Convert round to a byte array in big-endian order.
let round_bytes: vector<u8> = vector[0, 0, 0, 0, 0, 0, 0, 0];
let i = 7;

// Note that this loop never copies the last byte of round_bytes, though it is not expected to ever be non-zero.
while (i > 0) {
let curr_byte = round % 0x100;
let curr_element = vector::borrow_mut(&mut round_bytes, i);
*curr_element = (curr_byte as u8);
round = round >> 8;
i = i - 1;
};

// Compute sha256(prev_sig, round_bytes).
let digest = sha2_256(round_bytes);
// Verify the signature on the hash.
let drand_pk = DRAND_PK;
assert!(bls12381::bls12381_min_sig_verify(&sig, &drand_pk, &digest), EInvalidProof);
}

/// Derive a uniform vector from a drand signature.
public fun derive_randomness(drand_sig: vector<u8>): vector<u8> {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Make it an entry.

sha2_256(drand_sig)
}

// Converts the first 16 bytes of rnd to a u128 number and outputs its modulo with input n.
// Since n is u64, the output is at most 2^{-64} biased assuming rnd is uniformly random.
public fun safe_selection(n: u64, rnd: &vector<u8>): u64 {
assert!(vector::length(rnd) >= 16, EInvalidRndLength);
let m: u128 = 0;
let i = 0;
while (i < 16) {
m = m << 8;
let curr_byte = *vector::borrow(rnd, i);
m = m + (curr_byte as u128);
i = i + 1;
};
let n_128 = (n as u128);
let module_128 = m % n_128;
let res = (module_128 as u64);
res
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -353,9 +353,12 @@ impl<'mm, 'up> RttyContext<'mm, 'up> {
_ => unreachable!(),
};

debug!(target: "debug", "s_env {:#?}", &s_env);

// Look up the corresponding LLVM struct type constructed earlier in the translation.
// Use it to collect field offsets, struct size, and struct alignment as computed by LLVM.
let ll_struct_name = s_env.ll_struct_name_from_raw_name(s_tys);
debug!(target: "rtty", "ll_struct_name {:#?}", &ll_struct_name);
let ll_struct_ty = llcx
.named_struct_type(&ll_struct_name)
.expect("no struct type");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1285,11 +1285,22 @@ impl<'mm, 'up> FunctionContext<'mm, 'up> {
builder.field_ref_store(src_llval, dst_llval, stype, *offset);
}
Operation::Pack(mod_id, struct_id, types) => {
debug!(target:"debug", "Operation::Pack struct_id {:#?}", &struct_id);
let types = mty::Type::instantiate_vec(types.to_vec(), self.type_params);

let mod_env = self.get_global_env().get_module(*mod_id);
let mod_name = mod_env.get_name();
let all_structs = mod_env.get_structs();
debug!(target:"debug", "Module {:#?} all structures", mod_name);
for st in all_structs {
let st_name = st.get_full_name_str();
debug!(target:"debug", "Structure {:#?}", st_name);
}

let struct_env = self
.get_global_env()
.get_module(*mod_id)
.into_struct(*struct_id);
.into_struct(struct_id.clone());
assert_eq!(dst.len(), 1);
assert_eq!(src.len(), struct_env.get_field_count());
let struct_name = struct_env.ll_struct_name_from_raw_name(&types);
Expand Down Expand Up @@ -1328,7 +1339,7 @@ impl<'mm, 'up> FunctionContext<'mm, 'up> {
.env
.get_file_and_location(&loc)
.unwrap_or(("unknown".to_string(), Location::new(0, 0)));
debug!(target: "dwarf", "Op {:#?} {}:{:#?}", &op, filename, location.line.0);
debug!(target: "dwarf", "Op {:#?} {}:{:#?} {:#?}", &op, filename, location.line.0, &struct_name);
di_builder.create_struct(self, mod_id, struct_id, &struct_name, None);
}
Operation::Unpack(mod_id, struct_id, types) => {
Expand Down Expand Up @@ -1839,8 +1850,30 @@ impl<'mm, 'up> FunctionContext<'mm, 'up> {
}
Type::Vector(bt) if bt.is_number_u8() => {
// This is a Constant::ByteArray element type.
assert!(matches!(val_vec[0], Constant::ByteArray(_)));
todo!("{:?}", mc);

let val_vec_sz = val_vec.len();
debug!(target: "debug", "val_vec size {val_vec_sz}");
if !val_vec.is_empty() {
assert!(matches!(val_vec[0], Constant::ByteArray(_)));
}

let vec = match move_stackless_bytecode::stackless_bytecode::transform_bytearray_to_vec(&val_vec) {
Some(v) => v.clone(),
None => {
debug!(target: "constant", "No ByteArray found, using empty vector");
let v: Vec<u8> = vec![];
v
}
};
debug!(target: "constant", "ByteArray contents: {:#?}", vec);
let aval = llcx.const_int_array::<u8>(&vec);
let elt_mty = Type::Primitive(PrimitiveType::U8);
let (res_val_type, res_ptr) = self.make_global_array_and_copy_to_new_vec(aval, &elt_mty);
return builder
.build_load(res_val_type, res_ptr, "reload")
.as_constant();


}
_ => {
todo!("unexpected vec constant: {}: {:#?}", val_vec.len(), val_vec);
Expand Down
Loading